diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..a581cee4f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ + +# default +* text=auto + +# leave unmodified +*.ico binary +*.bmp binary + +# Visual Studio +*.dsp text eol=crlf +*.dsw text eol=crlf +*.manifest text eol=crlf + +# Windows +*.bat text eol=crlf +*.cmd text eol=crlf +*.hhp text eol=crlf +*.inf text eol=crlf +*.nsi text eol=crlf +*.wxs text eol=crlf diff --git a/Asm/arm/7zCrcOpt.asm b/Asm/arm/7zCrcOpt.asm index f008d658c..6001d8e36 100644 --- a/Asm/arm/7zCrcOpt.asm +++ b/Asm/arm/7zCrcOpt.asm @@ -1,100 +1,100 @@ - CODE32 - - EXPORT |CrcUpdateT4@16| - - AREA |.text|, CODE, ARM - - MACRO - CRC32_STEP_1 - - ldrb r4, [r1], #1 - subs r2, r2, #1 - eor r4, r4, r0 - and r4, r4, #0xFF - ldr r4, [r3, +r4, lsl #2] - eor r0, r4, r0, lsr #8 - - MEND - - - MACRO - CRC32_STEP_4 $STREAM_WORD - - eor r7, r7, r8 - eor r7, r7, r9 - eor r0, r0, r7 - eor r0, r0, $STREAM_WORD - ldr $STREAM_WORD, [r1], #4 - - and r7, r0, #0xFF - and r8, r0, #0xFF00 - and r9, r0, #0xFF0000 - and r0, r0, #0xFF000000 - - ldr r7, [r6, +r7, lsl #2] - ldr r8, [r5, +r8, lsr #6] - ldr r9, [r4, +r9, lsr #14] - ldr r0, [r3, +r0, lsr #22] - - MEND - - -|CrcUpdateT4@16| PROC - - stmdb sp!, {r4-r11, lr} - cmp r2, #0 - beq |$fin| - -|$v1| - tst r1, #7 - beq |$v2| - CRC32_STEP_1 - bne |$v1| - -|$v2| - cmp r2, #16 - blo |$v3| - - ldr r10, [r1], #4 - ldr r11, [r1], #4 - - add r4, r3, #0x400 - add r5, r3, #0x800 - add r6, r3, #0xC00 - - mov r7, #0 - mov r8, #0 - mov r9, #0 - - sub r2, r2, #16 - -|$loop| - ; pld [r1, #0x40] - - CRC32_STEP_4 r10 - CRC32_STEP_4 r11 - - subs r2, r2, #8 - bhs |$loop| - - sub r1, r1, #8 - add r2, r2, #16 - - eor r7, r7, r8 - eor r7, r7, r9 - eor r0, r0, r7 - -|$v3| - cmp r2, #0 - beq |$fin| - -|$v4| - CRC32_STEP_1 - bne |$v4| - -|$fin| - ldmia sp!, {r4-r11, pc} - -|CrcUpdateT4@16| ENDP - - END + CODE32 + + EXPORT |CrcUpdateT4@16| + + AREA |.text|, CODE, ARM + + MACRO + CRC32_STEP_1 + + ldrb r4, [r1], #1 + subs r2, r2, #1 + eor r4, r4, r0 + and r4, r4, #0xFF + ldr r4, [r3, +r4, lsl #2] + eor r0, r4, r0, lsr #8 + + MEND + + + MACRO + CRC32_STEP_4 $STREAM_WORD + + eor r7, r7, r8 + eor r7, r7, r9 + eor r0, r0, r7 + eor r0, r0, $STREAM_WORD + ldr $STREAM_WORD, [r1], #4 + + and r7, r0, #0xFF + and r8, r0, #0xFF00 + and r9, r0, #0xFF0000 + and r0, r0, #0xFF000000 + + ldr r7, [r6, +r7, lsl #2] + ldr r8, [r5, +r8, lsr #6] + ldr r9, [r4, +r9, lsr #14] + ldr r0, [r3, +r0, lsr #22] + + MEND + + +|CrcUpdateT4@16| PROC + + stmdb sp!, {r4-r11, lr} + cmp r2, #0 + beq |$fin| + +|$v1| + tst r1, #7 + beq |$v2| + CRC32_STEP_1 + bne |$v1| + +|$v2| + cmp r2, #16 + blo |$v3| + + ldr r10, [r1], #4 + ldr r11, [r1], #4 + + add r4, r3, #0x400 + add r5, r3, #0x800 + add r6, r3, #0xC00 + + mov r7, #0 + mov r8, #0 + mov r9, #0 + + sub r2, r2, #16 + +|$loop| + ; pld [r1, #0x40] + + CRC32_STEP_4 r10 + CRC32_STEP_4 r11 + + subs r2, r2, #8 + bhs |$loop| + + sub r1, r1, #8 + add r2, r2, #16 + + eor r7, r7, r8 + eor r7, r7, r9 + eor r0, r0, r7 + +|$v3| + cmp r2, #0 + beq |$fin| + +|$v4| + CRC32_STEP_1 + bne |$v4| + +|$fin| + ldmia sp!, {r4-r11, pc} + +|CrcUpdateT4@16| ENDP + + END diff --git a/Asm/arm64/7zAsm.S b/Asm/arm64/7zAsm.S index 67d650d9a..12e950b4c 100644 --- a/Asm/arm64/7zAsm.S +++ b/Asm/arm64/7zAsm.S @@ -1,181 +1,181 @@ -// 7zAsm.S -- ASM macros for arm64 -// 2021-04-25 : Igor Pavlov : Public domain - -#define r0 x0 -#define r1 x1 -#define r2 x2 -#define r3 x3 -#define r4 x4 -#define r5 x5 -#define r6 x6 -#define r7 x7 -#define r8 x8 -#define r9 x9 -#define r10 x10 -#define r11 x11 -#define r12 x12 -#define r13 x13 -#define r14 x14 -#define r15 x15 -#define r16 x16 -#define r17 x17 -#define r18 x18 -#define r19 x19 -#define r20 x20 -#define r21 x21 -#define r22 x22 -#define r23 x23 -#define r24 x24 -#define r25 x25 -#define r26 x26 -#define r27 x27 -#define r28 x28 -#define r29 x29 -#define r30 x30 - -#define REG_ABI_PARAM_0 r0 -#define REG_ABI_PARAM_1 r1 -#define REG_ABI_PARAM_2 r2 - - -.macro p2_add reg:req, param:req - add \reg, \reg, \param -.endm - -.macro p2_sub reg:req, param:req - sub \reg, \reg, \param -.endm - -.macro p2_sub_s reg:req, param:req - subs \reg, \reg, \param -.endm - -.macro p2_and reg:req, param:req - and \reg, \reg, \param -.endm - -.macro xor reg:req, param:req - eor \reg, \reg, \param -.endm - -.macro or reg:req, param:req - orr \reg, \reg, \param -.endm - -.macro shl reg:req, param:req - lsl \reg, \reg, \param -.endm - -.macro shr reg:req, param:req - lsr \reg, \reg, \param -.endm - -.macro sar reg:req, param:req - asr \reg, \reg, \param -.endm - -.macro p1_neg reg:req - neg \reg, \reg -.endm - -.macro dec reg:req - sub \reg, \reg, 1 -.endm - -.macro dec_s reg:req - subs \reg, \reg, 1 -.endm - -.macro inc reg:req - add \reg, \reg, 1 -.endm - -.macro inc_s reg:req - adds \reg, \reg, 1 -.endm - - -.macro imul reg:req, param:req - mul \reg, \reg, \param -.endm - -/* -arm64 and arm use reverted c flag after subs/cmp instructions: - arm64-arm : x86 - b.lo / b.cc : jb / jc - b.hs / b.cs : jae / jnc -*/ - -.macro jmp lab:req - b \lab -.endm - -.macro je lab:req - b.eq \lab -.endm - -.macro jz lab:req - b.eq \lab -.endm - -.macro jnz lab:req - b.ne \lab -.endm - -.macro jne lab:req - b.ne \lab -.endm - -.macro jb lab:req - b.lo \lab -.endm - -.macro jbe lab:req - b.ls \lab -.endm - -.macro ja lab:req - b.hi \lab -.endm - -.macro jae lab:req - b.hs \lab -.endm - - -.macro cmove dest:req, srcTrue:req - csel \dest, \srcTrue, \dest, eq -.endm - -.macro cmovne dest:req, srcTrue:req - csel \dest, \srcTrue, \dest, ne -.endm - -.macro cmovs dest:req, srcTrue:req - csel \dest, \srcTrue, \dest, mi -.endm - -.macro cmovns dest:req, srcTrue:req - csel \dest, \srcTrue, \dest, pl -.endm - -.macro cmovb dest:req, srcTrue:req - csel \dest, \srcTrue, \dest, lo -.endm - -.macro cmovae dest:req, srcTrue:req - csel \dest, \srcTrue, \dest, hs -.endm - - -.macro MY_ALIGN_16 macro - .p2align 4,, (1 << 4) - 1 -.endm - -.macro MY_ALIGN_32 macro - .p2align 5,, (1 << 5) - 1 -.endm - -.macro MY_ALIGN_64 macro - .p2align 6,, (1 << 6) - 1 -.endm +// 7zAsm.S -- ASM macros for arm64 +// 2021-04-25 : Igor Pavlov : Public domain + +#define r0 x0 +#define r1 x1 +#define r2 x2 +#define r3 x3 +#define r4 x4 +#define r5 x5 +#define r6 x6 +#define r7 x7 +#define r8 x8 +#define r9 x9 +#define r10 x10 +#define r11 x11 +#define r12 x12 +#define r13 x13 +#define r14 x14 +#define r15 x15 +#define r16 x16 +#define r17 x17 +#define r18 x18 +#define r19 x19 +#define r20 x20 +#define r21 x21 +#define r22 x22 +#define r23 x23 +#define r24 x24 +#define r25 x25 +#define r26 x26 +#define r27 x27 +#define r28 x28 +#define r29 x29 +#define r30 x30 + +#define REG_ABI_PARAM_0 r0 +#define REG_ABI_PARAM_1 r1 +#define REG_ABI_PARAM_2 r2 + + +.macro p2_add reg:req, param:req + add \reg, \reg, \param +.endm + +.macro p2_sub reg:req, param:req + sub \reg, \reg, \param +.endm + +.macro p2_sub_s reg:req, param:req + subs \reg, \reg, \param +.endm + +.macro p2_and reg:req, param:req + and \reg, \reg, \param +.endm + +.macro xor reg:req, param:req + eor \reg, \reg, \param +.endm + +.macro or reg:req, param:req + orr \reg, \reg, \param +.endm + +.macro shl reg:req, param:req + lsl \reg, \reg, \param +.endm + +.macro shr reg:req, param:req + lsr \reg, \reg, \param +.endm + +.macro sar reg:req, param:req + asr \reg, \reg, \param +.endm + +.macro p1_neg reg:req + neg \reg, \reg +.endm + +.macro dec reg:req + sub \reg, \reg, 1 +.endm + +.macro dec_s reg:req + subs \reg, \reg, 1 +.endm + +.macro inc reg:req + add \reg, \reg, 1 +.endm + +.macro inc_s reg:req + adds \reg, \reg, 1 +.endm + + +.macro imul reg:req, param:req + mul \reg, \reg, \param +.endm + +/* +arm64 and arm use reverted c flag after subs/cmp instructions: + arm64-arm : x86 + b.lo / b.cc : jb / jc + b.hs / b.cs : jae / jnc +*/ + +.macro jmp lab:req + b \lab +.endm + +.macro je lab:req + b.eq \lab +.endm + +.macro jz lab:req + b.eq \lab +.endm + +.macro jnz lab:req + b.ne \lab +.endm + +.macro jne lab:req + b.ne \lab +.endm + +.macro jb lab:req + b.lo \lab +.endm + +.macro jbe lab:req + b.ls \lab +.endm + +.macro ja lab:req + b.hi \lab +.endm + +.macro jae lab:req + b.hs \lab +.endm + + +.macro cmove dest:req, srcTrue:req + csel \dest, \srcTrue, \dest, eq +.endm + +.macro cmovne dest:req, srcTrue:req + csel \dest, \srcTrue, \dest, ne +.endm + +.macro cmovs dest:req, srcTrue:req + csel \dest, \srcTrue, \dest, mi +.endm + +.macro cmovns dest:req, srcTrue:req + csel \dest, \srcTrue, \dest, pl +.endm + +.macro cmovb dest:req, srcTrue:req + csel \dest, \srcTrue, \dest, lo +.endm + +.macro cmovae dest:req, srcTrue:req + csel \dest, \srcTrue, \dest, hs +.endm + + +.macro MY_ALIGN_16 macro + .p2align 4,, (1 << 4) - 1 +.endm + +.macro MY_ALIGN_32 macro + .p2align 5,, (1 << 5) - 1 +.endm + +.macro MY_ALIGN_64 macro + .p2align 6,, (1 << 6) - 1 +.endm diff --git a/Asm/x86/7zAsm.asm b/Asm/x86/7zAsm.asm index 8b994a5e1..8910d16c6 100644 --- a/Asm/x86/7zAsm.asm +++ b/Asm/x86/7zAsm.asm @@ -1,341 +1,341 @@ -; 7zAsm.asm -- ASM macros -; 2023-12-08 : Igor Pavlov : Public domain - - -; UASM can require these changes -; OPTION FRAMEPRESERVEFLAGS:ON -; OPTION PROLOGUE:NONE -; OPTION EPILOGUE:NONE - -ifdef @wordsize -; @wordsize is defined only in JWASM and ASMC and is not defined in MASM -; @wordsize eq 8 for 64-bit x64 -; @wordsize eq 2 for 32-bit x86 -if @wordsize eq 8 - x64 equ 1 -endif -else -ifdef RAX - x64 equ 1 -endif -endif - - -ifdef x64 - IS_X64 equ 1 -else - IS_X64 equ 0 -endif - -ifdef ABI_LINUX - IS_LINUX equ 1 -else - IS_LINUX equ 0 -endif - -ifndef x64 -; Use ABI_CDECL for x86 (32-bit) only -; if ABI_CDECL is not defined, we use fastcall abi -ifdef ABI_CDECL - IS_CDECL equ 1 -else - IS_CDECL equ 0 -endif -endif - -OPTION PROLOGUE:NONE -OPTION EPILOGUE:NONE - -MY_ASM_START macro - ifdef x64 - .code - else - .386 - .model flat - _TEXT$00 SEGMENT PARA PUBLIC 'CODE' - endif -endm - -MY_PROC macro name:req, numParams:req - align 16 - proc_numParams = numParams - if (IS_X64 gt 0) - proc_name equ name - elseif (IS_LINUX gt 0) - proc_name equ name - elseif (IS_CDECL gt 0) - proc_name equ @CatStr(_,name) - else - proc_name equ @CatStr(@,name,@, %numParams * 4) - endif - proc_name PROC -endm - -MY_ENDP macro - if (IS_X64 gt 0) - ret - elseif (IS_CDECL gt 0) - ret - elseif (proc_numParams LT 3) - ret - else - ret (proc_numParams - 2) * 4 - endif - proc_name ENDP -endm - - -ifdef x64 - REG_SIZE equ 8 - REG_LOGAR_SIZE equ 3 -else - REG_SIZE equ 4 - REG_LOGAR_SIZE equ 2 -endif - - x0 equ EAX - x1 equ ECX - x2 equ EDX - x3 equ EBX - x4 equ ESP - x5 equ EBP - x6 equ ESI - x7 equ EDI - - x0_W equ AX - x1_W equ CX - x2_W equ DX - x3_W equ BX - - x5_W equ BP - x6_W equ SI - x7_W equ DI - - x0_L equ AL - x1_L equ CL - x2_L equ DL - x3_L equ BL - - x0_H equ AH - x1_H equ CH - x2_H equ DH - x3_H equ BH - -; r0_L equ AL -; r1_L equ CL -; r2_L equ DL -; r3_L equ BL - -; r0_H equ AH -; r1_H equ CH -; r2_H equ DH -; r3_H equ BH - - -ifdef x64 - x5_L equ BPL - x6_L equ SIL - x7_L equ DIL - x8_L equ r8b - x9_L equ r9b - x10_L equ r10b - x11_L equ r11b - x12_L equ r12b - x13_L equ r13b - x14_L equ r14b - x15_L equ r15b - - r0 equ RAX - r1 equ RCX - r2 equ RDX - r3 equ RBX - r4 equ RSP - r5 equ RBP - r6 equ RSI - r7 equ RDI - x8 equ r8d - x9 equ r9d - x10 equ r10d - x11 equ r11d - x12 equ r12d - x13 equ r13d - x14 equ r14d - x15 equ r15d -else - r0 equ x0 - r1 equ x1 - r2 equ x2 - r3 equ x3 - r4 equ x4 - r5 equ x5 - r6 equ x6 - r7 equ x7 -endif - - x0_R equ r0 - x1_R equ r1 - x2_R equ r2 - x3_R equ r3 - x4_R equ r4 - x5_R equ r5 - x6_R equ r6 - x7_R equ r7 - x8_R equ r8 - x9_R equ r9 - x10_R equ r10 - x11_R equ r11 - x12_R equ r12 - x13_R equ r13 - x14_R equ r14 - x15_R equ r15 - -ifdef x64 -ifdef ABI_LINUX - -MY_PUSH_2_REGS macro - push r3 - push r5 -endm - -MY_POP_2_REGS macro - pop r5 - pop r3 -endm - -endif -endif - - -MY_PUSH_4_REGS macro - push r3 - push r5 - push r6 - push r7 -endm - -MY_POP_4_REGS macro - pop r7 - pop r6 - pop r5 - pop r3 -endm - - -; for fastcall and for WIN-x64 -REG_PARAM_0_x equ x1 -REG_PARAM_0 equ r1 -REG_PARAM_1_x equ x2 -REG_PARAM_1 equ r2 - -ifndef x64 -; for x86-fastcall - -REG_ABI_PARAM_0_x equ REG_PARAM_0_x -REG_ABI_PARAM_0 equ REG_PARAM_0 -REG_ABI_PARAM_1_x equ REG_PARAM_1_x -REG_ABI_PARAM_1 equ REG_PARAM_1 - -MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro - MY_PUSH_4_REGS -endm - -MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro - MY_POP_4_REGS -endm - -else -; x64 - -if (IS_LINUX eq 0) - -; for WIN-x64: -REG_PARAM_2_x equ x8 -REG_PARAM_2 equ r8 -REG_PARAM_3 equ r9 - -REG_ABI_PARAM_0_x equ REG_PARAM_0_x -REG_ABI_PARAM_0 equ REG_PARAM_0 -REG_ABI_PARAM_1_x equ REG_PARAM_1_x -REG_ABI_PARAM_1 equ REG_PARAM_1 -REG_ABI_PARAM_2_x equ REG_PARAM_2_x -REG_ABI_PARAM_2 equ REG_PARAM_2 -REG_ABI_PARAM_3 equ REG_PARAM_3 - -else -; for LINUX-x64: -REG_LINUX_PARAM_0_x equ x7 -REG_LINUX_PARAM_0 equ r7 -REG_LINUX_PARAM_1_x equ x6 -REG_LINUX_PARAM_1 equ r6 -REG_LINUX_PARAM_2 equ r2 -REG_LINUX_PARAM_3 equ r1 -REG_LINUX_PARAM_4_x equ x8 -REG_LINUX_PARAM_4 equ r8 -REG_LINUX_PARAM_5 equ r9 - -REG_ABI_PARAM_0_x equ REG_LINUX_PARAM_0_x -REG_ABI_PARAM_0 equ REG_LINUX_PARAM_0 -REG_ABI_PARAM_1_x equ REG_LINUX_PARAM_1_x -REG_ABI_PARAM_1 equ REG_LINUX_PARAM_1 -REG_ABI_PARAM_2 equ REG_LINUX_PARAM_2 -REG_ABI_PARAM_3 equ REG_LINUX_PARAM_3 -REG_ABI_PARAM_4_x equ REG_LINUX_PARAM_4_x -REG_ABI_PARAM_4 equ REG_LINUX_PARAM_4 -REG_ABI_PARAM_5 equ REG_LINUX_PARAM_5 - -MY_ABI_LINUX_TO_WIN_2 macro - mov r2, r6 - mov r1, r7 -endm - -MY_ABI_LINUX_TO_WIN_3 macro - mov r8, r2 - mov r2, r6 - mov r1, r7 -endm - -MY_ABI_LINUX_TO_WIN_4 macro - mov r9, r1 - mov r8, r2 - mov r2, r6 - mov r1, r7 -endm - -endif ; IS_LINUX - - -MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro - if (IS_LINUX gt 0) - MY_PUSH_2_REGS - else - MY_PUSH_4_REGS - endif -endm - -MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro - if (IS_LINUX gt 0) - MY_POP_2_REGS - else - MY_POP_4_REGS - endif -endm - - -MY_PUSH_PRESERVED_ABI_REGS macro - MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 - push r12 - push r13 - push r14 - push r15 -endm - - -MY_POP_PRESERVED_ABI_REGS macro - pop r15 - pop r14 - pop r13 - pop r12 - MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 -endm - -endif ; x64 +; 7zAsm.asm -- ASM macros +; 2023-12-08 : Igor Pavlov : Public domain + + +; UASM can require these changes +; OPTION FRAMEPRESERVEFLAGS:ON +; OPTION PROLOGUE:NONE +; OPTION EPILOGUE:NONE + +ifdef @wordsize +; @wordsize is defined only in JWASM and ASMC and is not defined in MASM +; @wordsize eq 8 for 64-bit x64 +; @wordsize eq 2 for 32-bit x86 +if @wordsize eq 8 + x64 equ 1 +endif +else +ifdef RAX + x64 equ 1 +endif +endif + + +ifdef x64 + IS_X64 equ 1 +else + IS_X64 equ 0 +endif + +ifdef ABI_LINUX + IS_LINUX equ 1 +else + IS_LINUX equ 0 +endif + +ifndef x64 +; Use ABI_CDECL for x86 (32-bit) only +; if ABI_CDECL is not defined, we use fastcall abi +ifdef ABI_CDECL + IS_CDECL equ 1 +else + IS_CDECL equ 0 +endif +endif + +OPTION PROLOGUE:NONE +OPTION EPILOGUE:NONE + +MY_ASM_START macro + ifdef x64 + .code + else + .386 + .model flat + _TEXT$00 SEGMENT PARA PUBLIC 'CODE' + endif +endm + +MY_PROC macro name:req, numParams:req + align 16 + proc_numParams = numParams + if (IS_X64 gt 0) + proc_name equ name + elseif (IS_LINUX gt 0) + proc_name equ name + elseif (IS_CDECL gt 0) + proc_name equ @CatStr(_,name) + else + proc_name equ @CatStr(@,name,@, %numParams * 4) + endif + proc_name PROC +endm + +MY_ENDP macro + if (IS_X64 gt 0) + ret + elseif (IS_CDECL gt 0) + ret + elseif (proc_numParams LT 3) + ret + else + ret (proc_numParams - 2) * 4 + endif + proc_name ENDP +endm + + +ifdef x64 + REG_SIZE equ 8 + REG_LOGAR_SIZE equ 3 +else + REG_SIZE equ 4 + REG_LOGAR_SIZE equ 2 +endif + + x0 equ EAX + x1 equ ECX + x2 equ EDX + x3 equ EBX + x4 equ ESP + x5 equ EBP + x6 equ ESI + x7 equ EDI + + x0_W equ AX + x1_W equ CX + x2_W equ DX + x3_W equ BX + + x5_W equ BP + x6_W equ SI + x7_W equ DI + + x0_L equ AL + x1_L equ CL + x2_L equ DL + x3_L equ BL + + x0_H equ AH + x1_H equ CH + x2_H equ DH + x3_H equ BH + +; r0_L equ AL +; r1_L equ CL +; r2_L equ DL +; r3_L equ BL + +; r0_H equ AH +; r1_H equ CH +; r2_H equ DH +; r3_H equ BH + + +ifdef x64 + x5_L equ BPL + x6_L equ SIL + x7_L equ DIL + x8_L equ r8b + x9_L equ r9b + x10_L equ r10b + x11_L equ r11b + x12_L equ r12b + x13_L equ r13b + x14_L equ r14b + x15_L equ r15b + + r0 equ RAX + r1 equ RCX + r2 equ RDX + r3 equ RBX + r4 equ RSP + r5 equ RBP + r6 equ RSI + r7 equ RDI + x8 equ r8d + x9 equ r9d + x10 equ r10d + x11 equ r11d + x12 equ r12d + x13 equ r13d + x14 equ r14d + x15 equ r15d +else + r0 equ x0 + r1 equ x1 + r2 equ x2 + r3 equ x3 + r4 equ x4 + r5 equ x5 + r6 equ x6 + r7 equ x7 +endif + + x0_R equ r0 + x1_R equ r1 + x2_R equ r2 + x3_R equ r3 + x4_R equ r4 + x5_R equ r5 + x6_R equ r6 + x7_R equ r7 + x8_R equ r8 + x9_R equ r9 + x10_R equ r10 + x11_R equ r11 + x12_R equ r12 + x13_R equ r13 + x14_R equ r14 + x15_R equ r15 + +ifdef x64 +ifdef ABI_LINUX + +MY_PUSH_2_REGS macro + push r3 + push r5 +endm + +MY_POP_2_REGS macro + pop r5 + pop r3 +endm + +endif +endif + + +MY_PUSH_4_REGS macro + push r3 + push r5 + push r6 + push r7 +endm + +MY_POP_4_REGS macro + pop r7 + pop r6 + pop r5 + pop r3 +endm + + +; for fastcall and for WIN-x64 +REG_PARAM_0_x equ x1 +REG_PARAM_0 equ r1 +REG_PARAM_1_x equ x2 +REG_PARAM_1 equ r2 + +ifndef x64 +; for x86-fastcall + +REG_ABI_PARAM_0_x equ REG_PARAM_0_x +REG_ABI_PARAM_0 equ REG_PARAM_0 +REG_ABI_PARAM_1_x equ REG_PARAM_1_x +REG_ABI_PARAM_1 equ REG_PARAM_1 + +MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro + MY_PUSH_4_REGS +endm + +MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro + MY_POP_4_REGS +endm + +else +; x64 + +if (IS_LINUX eq 0) + +; for WIN-x64: +REG_PARAM_2_x equ x8 +REG_PARAM_2 equ r8 +REG_PARAM_3 equ r9 + +REG_ABI_PARAM_0_x equ REG_PARAM_0_x +REG_ABI_PARAM_0 equ REG_PARAM_0 +REG_ABI_PARAM_1_x equ REG_PARAM_1_x +REG_ABI_PARAM_1 equ REG_PARAM_1 +REG_ABI_PARAM_2_x equ REG_PARAM_2_x +REG_ABI_PARAM_2 equ REG_PARAM_2 +REG_ABI_PARAM_3 equ REG_PARAM_3 + +else +; for LINUX-x64: +REG_LINUX_PARAM_0_x equ x7 +REG_LINUX_PARAM_0 equ r7 +REG_LINUX_PARAM_1_x equ x6 +REG_LINUX_PARAM_1 equ r6 +REG_LINUX_PARAM_2 equ r2 +REG_LINUX_PARAM_3 equ r1 +REG_LINUX_PARAM_4_x equ x8 +REG_LINUX_PARAM_4 equ r8 +REG_LINUX_PARAM_5 equ r9 + +REG_ABI_PARAM_0_x equ REG_LINUX_PARAM_0_x +REG_ABI_PARAM_0 equ REG_LINUX_PARAM_0 +REG_ABI_PARAM_1_x equ REG_LINUX_PARAM_1_x +REG_ABI_PARAM_1 equ REG_LINUX_PARAM_1 +REG_ABI_PARAM_2 equ REG_LINUX_PARAM_2 +REG_ABI_PARAM_3 equ REG_LINUX_PARAM_3 +REG_ABI_PARAM_4_x equ REG_LINUX_PARAM_4_x +REG_ABI_PARAM_4 equ REG_LINUX_PARAM_4 +REG_ABI_PARAM_5 equ REG_LINUX_PARAM_5 + +MY_ABI_LINUX_TO_WIN_2 macro + mov r2, r6 + mov r1, r7 +endm + +MY_ABI_LINUX_TO_WIN_3 macro + mov r8, r2 + mov r2, r6 + mov r1, r7 +endm + +MY_ABI_LINUX_TO_WIN_4 macro + mov r9, r1 + mov r8, r2 + mov r2, r6 + mov r1, r7 +endm + +endif ; IS_LINUX + + +MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro + if (IS_LINUX gt 0) + MY_PUSH_2_REGS + else + MY_PUSH_4_REGS + endif +endm + +MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 macro + if (IS_LINUX gt 0) + MY_POP_2_REGS + else + MY_POP_4_REGS + endif +endm + + +MY_PUSH_PRESERVED_ABI_REGS macro + MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 + push r12 + push r13 + push r14 + push r15 +endm + + +MY_POP_PRESERVED_ABI_REGS macro + pop r15 + pop r14 + pop r13 + pop r12 + MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 +endm + +endif ; x64 diff --git a/Asm/x86/7zCrcOpt.asm b/Asm/x86/7zCrcOpt.asm index 1c0513b98..c5de80883 100644 --- a/Asm/x86/7zCrcOpt.asm +++ b/Asm/x86/7zCrcOpt.asm @@ -1,258 +1,258 @@ -; 7zCrcOpt.asm -- CRC32 calculation : optimized version -; 2023-12-08 : Igor Pavlov : Public domain - -include 7zAsm.asm - -MY_ASM_START - -NUM_WORDS equ 3 -UNROLL_CNT equ 2 - -if (NUM_WORDS lt 1) or (NUM_WORDS gt 64) -.err -endif -if (UNROLL_CNT lt 1) -.err -endif - -rD equ r2 -rD_x equ x2 -rN equ r7 -rT equ r5 - -ifndef x64 - if (IS_CDECL gt 0) - crc_OFFS equ (REG_SIZE * 5) - data_OFFS equ (REG_SIZE + crc_OFFS) - size_OFFS equ (REG_SIZE + data_OFFS) - else - size_OFFS equ (REG_SIZE * 5) - endif - table_OFFS equ (REG_SIZE + size_OFFS) -endif - -; rN + rD is same speed as rD, but we reduce one instruction in loop -SRCDAT_1 equ rN + rD * 1 + 1 * -SRCDAT_4 equ rN + rD * 1 + 4 * - -CRC macro op:req, dest:req, src:req, t:req - op dest, dword ptr [rT + @CatStr(src, _R) * 4 + 0400h * (t)] -endm - -CRC_XOR macro dest:req, src:req, t:req - CRC xor, dest, src, t -endm - -CRC_MOV macro dest:req, src:req, t:req - CRC mov, dest, src, t -endm - -MOVZXLO macro dest:req, src:req - movzx dest, @CatStr(src, _L) -endm - -MOVZXHI macro dest:req, src:req - movzx dest, @CatStr(src, _H) -endm - -; movzx x0, x0_L - is slow in some cpus (ivb), if same register for src and dest -; movzx x3, x0_L sometimes is 0 cycles latency (not always) -; movzx x3, x0_L sometimes is 0.5 cycles latency -; movzx x3, x0_H is 2 cycles latency in some cpus - -CRC1b macro - movzx x6, byte ptr [rD] - MOVZXLO x3, x0 - inc rD - shr x0, 8 - xor x6, x3 - CRC_XOR x0, x6, 0 - dec rN -endm - -LOAD_1 macro dest:req, t:req, iter:req, index:req - movzx dest, byte ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + index)] -endm - -LOAD_2 macro dest:req, t:req, iter:req, index:req - movzx dest, word ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + index)] -endm - -CRC_QUAD macro nn, t:req, iter:req -ifdef x64 - ; paired memory loads give 1-3% speed gain, but it uses more registers - LOAD_2 x3, t, iter, 0 - LOAD_2 x9, t, iter, 2 - MOVZXLO x6, x3 - shr x3, 8 - CRC_XOR nn, x6, t * 4 + 3 - MOVZXLO x6, x9 - shr x9, 8 - CRC_XOR nn, x3, t * 4 + 2 - CRC_XOR nn, x6, t * 4 + 1 - CRC_XOR nn, x9, t * 4 + 0 -elseif 0 - LOAD_2 x3, t, iter, 0 - MOVZXLO x6, x3 - shr x3, 8 - CRC_XOR nn, x6, t * 4 + 3 - CRC_XOR nn, x3, t * 4 + 2 - LOAD_2 x3, t, iter, 2 - MOVZXLO x6, x3 - shr x3, 8 - CRC_XOR nn, x6, t * 4 + 1 - CRC_XOR nn, x3, t * 4 + 0 -elseif 0 - LOAD_1 x3, t, iter, 0 - LOAD_1 x6, t, iter, 1 - CRC_XOR nn, x3, t * 4 + 3 - CRC_XOR nn, x6, t * 4 + 2 - LOAD_1 x3, t, iter, 2 - LOAD_1 x6, t, iter, 3 - CRC_XOR nn, x3, t * 4 + 1 - CRC_XOR nn, x6, t * 4 + 0 -else - ; 32-bit load is better if there is only one read port (core2) - ; but that code can be slower if there are 2 read ports (snb) - mov x3, dword ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + 0)] - MOVZXLO x6, x3 - CRC_XOR nn, x6, t * 4 + 3 - MOVZXHI x6, x3 - shr x3, 16 - CRC_XOR nn, x6, t * 4 + 2 - MOVZXLO x6, x3 - shr x3, 8 - CRC_XOR nn, x6, t * 4 + 1 - CRC_XOR nn, x3, t * 4 + 0 -endif -endm - - -LAST equ (4 * (NUM_WORDS - 1)) - -CRC_ITER macro qq, nn, iter - mov nn, [SRCDAT_4 (NUM_WORDS * (1 + iter))] - - i = 0 - rept NUM_WORDS - 1 - CRC_QUAD nn, i, iter - i = i + 1 - endm - - MOVZXLO x6, qq - mov x3, qq - shr x3, 24 - CRC_XOR nn, x6, LAST + 3 - CRC_XOR nn, x3, LAST + 0 - ror qq, 16 - MOVZXLO x6, qq - shr qq, 24 - CRC_XOR nn, x6, LAST + 1 -if ((UNROLL_CNT and 1) eq 1) and (iter eq (UNROLL_CNT - 1)) - CRC_MOV qq, qq, LAST + 2 - xor qq, nn -else - CRC_XOR nn, qq, LAST + 2 -endif -endm - - -; + 4 for prefetching next 4-bytes after current iteration -NUM_BYTES_LIMIT equ (NUM_WORDS * 4 * UNROLL_CNT + 4) -ALIGN_MASK equ 3 - - -; MY_PROC @CatStr(CrcUpdateT, 12), 4 -MY_PROC @CatStr(CrcUpdateT, %(NUM_WORDS * 4)), 4 - MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 - ifdef x64 - mov x0, REG_ABI_PARAM_0_x ; x0 = x1(win) / x7(linux) - mov rT, REG_ABI_PARAM_3 ; r5 = r9(win) / x1(linux) - mov rN, REG_ABI_PARAM_2 ; r7 = r8(win) / r2(linux) - ; mov rD, REG_ABI_PARAM_1 ; r2 = r2(win) - if (IS_LINUX gt 0) - mov rD, REG_ABI_PARAM_1 ; r2 = r6 - endif - else - if (IS_CDECL gt 0) - mov x0, [r4 + crc_OFFS] - mov rD, [r4 + data_OFFS] - else - mov x0, REG_ABI_PARAM_0_x - endif - mov rN, [r4 + size_OFFS] - mov rT, [r4 + table_OFFS] - endif - - cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK - jb crc_end -@@: - test rD_x, ALIGN_MASK ; test rD, ALIGN_MASK - jz @F - CRC1b - jmp @B -@@: - xor x0, dword ptr [rD] - lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)] - sub rD, rN - -align 16 -@@: -unr_index = 0 -while unr_index lt UNROLL_CNT - if (unr_index and 1) eq 0 - CRC_ITER x0, x1, unr_index - else - CRC_ITER x1, x0, unr_index - endif - unr_index = unr_index + 1 -endm - - add rD, NUM_WORDS * 4 * UNROLL_CNT - jnc @B - -if 0 - ; byte verson - add rD, rN - xor x0, dword ptr [rD] - add rN, NUM_BYTES_LIMIT - 1 -else - ; 4-byte version - add rN, 4 * NUM_WORDS * UNROLL_CNT - sub rD, 4 * NUM_WORDS * UNROLL_CNT -@@: - MOVZXLO x3, x0 - MOVZXHI x1, x0 - shr x0, 16 - MOVZXLO x6, x0 - shr x0, 8 - CRC_MOV x0, x0, 0 - CRC_XOR x0, x3, 3 - CRC_XOR x0, x1, 2 - CRC_XOR x0, x6, 1 - - add rD, 4 -if (NUM_WORDS * UNROLL_CNT) ne 1 - jc @F - xor x0, [SRCDAT_4 0] - jmp @B -@@: -endif - add rD, rN - add rN, 4 - 1 - -endif - - sub rN, rD -crc_end: - test rN, rN - jz func_end -@@: - CRC1b - jnz @B - -func_end: - MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 -MY_ENDP - -end +; 7zCrcOpt.asm -- CRC32 calculation : optimized version +; 2023-12-08 : Igor Pavlov : Public domain + +include 7zAsm.asm + +MY_ASM_START + +NUM_WORDS equ 3 +UNROLL_CNT equ 2 + +if (NUM_WORDS lt 1) or (NUM_WORDS gt 64) +.err +endif +if (UNROLL_CNT lt 1) +.err +endif + +rD equ r2 +rD_x equ x2 +rN equ r7 +rT equ r5 + +ifndef x64 + if (IS_CDECL gt 0) + crc_OFFS equ (REG_SIZE * 5) + data_OFFS equ (REG_SIZE + crc_OFFS) + size_OFFS equ (REG_SIZE + data_OFFS) + else + size_OFFS equ (REG_SIZE * 5) + endif + table_OFFS equ (REG_SIZE + size_OFFS) +endif + +; rN + rD is same speed as rD, but we reduce one instruction in loop +SRCDAT_1 equ rN + rD * 1 + 1 * +SRCDAT_4 equ rN + rD * 1 + 4 * + +CRC macro op:req, dest:req, src:req, t:req + op dest, dword ptr [rT + @CatStr(src, _R) * 4 + 0400h * (t)] +endm + +CRC_XOR macro dest:req, src:req, t:req + CRC xor, dest, src, t +endm + +CRC_MOV macro dest:req, src:req, t:req + CRC mov, dest, src, t +endm + +MOVZXLO macro dest:req, src:req + movzx dest, @CatStr(src, _L) +endm + +MOVZXHI macro dest:req, src:req + movzx dest, @CatStr(src, _H) +endm + +; movzx x0, x0_L - is slow in some cpus (ivb), if same register for src and dest +; movzx x3, x0_L sometimes is 0 cycles latency (not always) +; movzx x3, x0_L sometimes is 0.5 cycles latency +; movzx x3, x0_H is 2 cycles latency in some cpus + +CRC1b macro + movzx x6, byte ptr [rD] + MOVZXLO x3, x0 + inc rD + shr x0, 8 + xor x6, x3 + CRC_XOR x0, x6, 0 + dec rN +endm + +LOAD_1 macro dest:req, t:req, iter:req, index:req + movzx dest, byte ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + index)] +endm + +LOAD_2 macro dest:req, t:req, iter:req, index:req + movzx dest, word ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + index)] +endm + +CRC_QUAD macro nn, t:req, iter:req +ifdef x64 + ; paired memory loads give 1-3% speed gain, but it uses more registers + LOAD_2 x3, t, iter, 0 + LOAD_2 x9, t, iter, 2 + MOVZXLO x6, x3 + shr x3, 8 + CRC_XOR nn, x6, t * 4 + 3 + MOVZXLO x6, x9 + shr x9, 8 + CRC_XOR nn, x3, t * 4 + 2 + CRC_XOR nn, x6, t * 4 + 1 + CRC_XOR nn, x9, t * 4 + 0 +elseif 0 + LOAD_2 x3, t, iter, 0 + MOVZXLO x6, x3 + shr x3, 8 + CRC_XOR nn, x6, t * 4 + 3 + CRC_XOR nn, x3, t * 4 + 2 + LOAD_2 x3, t, iter, 2 + MOVZXLO x6, x3 + shr x3, 8 + CRC_XOR nn, x6, t * 4 + 1 + CRC_XOR nn, x3, t * 4 + 0 +elseif 0 + LOAD_1 x3, t, iter, 0 + LOAD_1 x6, t, iter, 1 + CRC_XOR nn, x3, t * 4 + 3 + CRC_XOR nn, x6, t * 4 + 2 + LOAD_1 x3, t, iter, 2 + LOAD_1 x6, t, iter, 3 + CRC_XOR nn, x3, t * 4 + 1 + CRC_XOR nn, x6, t * 4 + 0 +else + ; 32-bit load is better if there is only one read port (core2) + ; but that code can be slower if there are 2 read ports (snb) + mov x3, dword ptr [SRCDAT_1 (4 * (NUM_WORDS - 1 - t + iter * NUM_WORDS) + 0)] + MOVZXLO x6, x3 + CRC_XOR nn, x6, t * 4 + 3 + MOVZXHI x6, x3 + shr x3, 16 + CRC_XOR nn, x6, t * 4 + 2 + MOVZXLO x6, x3 + shr x3, 8 + CRC_XOR nn, x6, t * 4 + 1 + CRC_XOR nn, x3, t * 4 + 0 +endif +endm + + +LAST equ (4 * (NUM_WORDS - 1)) + +CRC_ITER macro qq, nn, iter + mov nn, [SRCDAT_4 (NUM_WORDS * (1 + iter))] + + i = 0 + rept NUM_WORDS - 1 + CRC_QUAD nn, i, iter + i = i + 1 + endm + + MOVZXLO x6, qq + mov x3, qq + shr x3, 24 + CRC_XOR nn, x6, LAST + 3 + CRC_XOR nn, x3, LAST + 0 + ror qq, 16 + MOVZXLO x6, qq + shr qq, 24 + CRC_XOR nn, x6, LAST + 1 +if ((UNROLL_CNT and 1) eq 1) and (iter eq (UNROLL_CNT - 1)) + CRC_MOV qq, qq, LAST + 2 + xor qq, nn +else + CRC_XOR nn, qq, LAST + 2 +endif +endm + + +; + 4 for prefetching next 4-bytes after current iteration +NUM_BYTES_LIMIT equ (NUM_WORDS * 4 * UNROLL_CNT + 4) +ALIGN_MASK equ 3 + + +; MY_PROC @CatStr(CrcUpdateT, 12), 4 +MY_PROC @CatStr(CrcUpdateT, %(NUM_WORDS * 4)), 4 + MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 + ifdef x64 + mov x0, REG_ABI_PARAM_0_x ; x0 = x1(win) / x7(linux) + mov rT, REG_ABI_PARAM_3 ; r5 = r9(win) / x1(linux) + mov rN, REG_ABI_PARAM_2 ; r7 = r8(win) / r2(linux) + ; mov rD, REG_ABI_PARAM_1 ; r2 = r2(win) + if (IS_LINUX gt 0) + mov rD, REG_ABI_PARAM_1 ; r2 = r6 + endif + else + if (IS_CDECL gt 0) + mov x0, [r4 + crc_OFFS] + mov rD, [r4 + data_OFFS] + else + mov x0, REG_ABI_PARAM_0_x + endif + mov rN, [r4 + size_OFFS] + mov rT, [r4 + table_OFFS] + endif + + cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK + jb crc_end +@@: + test rD_x, ALIGN_MASK ; test rD, ALIGN_MASK + jz @F + CRC1b + jmp @B +@@: + xor x0, dword ptr [rD] + lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)] + sub rD, rN + +align 16 +@@: +unr_index = 0 +while unr_index lt UNROLL_CNT + if (unr_index and 1) eq 0 + CRC_ITER x0, x1, unr_index + else + CRC_ITER x1, x0, unr_index + endif + unr_index = unr_index + 1 +endm + + add rD, NUM_WORDS * 4 * UNROLL_CNT + jnc @B + +if 0 + ; byte verson + add rD, rN + xor x0, dword ptr [rD] + add rN, NUM_BYTES_LIMIT - 1 +else + ; 4-byte version + add rN, 4 * NUM_WORDS * UNROLL_CNT + sub rD, 4 * NUM_WORDS * UNROLL_CNT +@@: + MOVZXLO x3, x0 + MOVZXHI x1, x0 + shr x0, 16 + MOVZXLO x6, x0 + shr x0, 8 + CRC_MOV x0, x0, 0 + CRC_XOR x0, x3, 3 + CRC_XOR x0, x1, 2 + CRC_XOR x0, x6, 1 + + add rD, 4 +if (NUM_WORDS * UNROLL_CNT) ne 1 + jc @F + xor x0, [SRCDAT_4 0] + jmp @B +@@: +endif + add rD, rN + add rN, 4 - 1 + +endif + + sub rN, rD +crc_end: + test rN, rN + jz func_end +@@: + CRC1b + jnz @B + +func_end: + MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 +MY_ENDP + +end diff --git a/Asm/x86/AesOpt.asm b/Asm/x86/AesOpt.asm index 1b7b5d450..84bf8977f 100644 --- a/Asm/x86/AesOpt.asm +++ b/Asm/x86/AesOpt.asm @@ -1,742 +1,742 @@ -; AesOpt.asm -- AES optimized code for x86 AES hardware instructions -; 2021-12-25 : Igor Pavlov : Public domain - -include 7zAsm.asm - -ifdef __ASMC__ - use_vaes_256 equ 1 -else -ifdef ymm0 - use_vaes_256 equ 1 -endif -endif - - -ifdef use_vaes_256 - ECHO "++ VAES 256" -else - ECHO "-- NO VAES 256" -endif - -ifdef x64 - ECHO "x86-64" -else - ECHO "x86" -if (IS_CDECL gt 0) - ECHO "ABI : CDECL" -else - ECHO "ABI : no CDECL : FASTCALL" -endif -endif - -if (IS_LINUX gt 0) - ECHO "ABI : LINUX" -else - ECHO "ABI : WINDOWS" -endif - -MY_ASM_START - -ifndef x64 - .686 - .xmm -endif - - -; MY_ALIGN EQU ALIGN(64) -MY_ALIGN EQU - -SEG_ALIGN EQU MY_ALIGN - -MY_SEG_PROC macro name:req, numParams:req - ; seg_name equ @CatStr(_TEXT$, name) - ; seg_name SEGMENT SEG_ALIGN 'CODE' - MY_PROC name, numParams -endm - -MY_SEG_ENDP macro - ; seg_name ENDS -endm - - -NUM_AES_KEYS_MAX equ 15 - -; the number of push operators in function PROLOG -if (IS_LINUX eq 0) or (IS_X64 eq 0) -num_regs_push equ 2 -stack_param_offset equ (REG_SIZE * (1 + num_regs_push)) -endif - -ifdef x64 - num_param equ REG_ABI_PARAM_2 -else - if (IS_CDECL gt 0) - ; size_t size - ; void * data - ; UInt32 * aes - ; ret-ip <- (r4) - aes_OFFS equ (stack_param_offset) - data_OFFS equ (REG_SIZE + aes_OFFS) - size_OFFS equ (REG_SIZE + data_OFFS) - num_param equ [r4 + size_OFFS] - else - num_param equ [r4 + stack_param_offset] - endif -endif - -keys equ REG_PARAM_0 ; r1 -rD equ REG_PARAM_1 ; r2 -rN equ r0 - -koffs_x equ x7 -koffs_r equ r7 - -ksize_x equ x6 -ksize_r equ r6 - -keys2 equ r3 - -state equ xmm0 -key equ xmm0 -key_ymm equ ymm0 -key_ymm_n equ 0 - -ifdef x64 - ways = 11 -else - ways = 4 -endif - -ways_start_reg equ 1 - -iv equ @CatStr(xmm, %(ways_start_reg + ways)) -iv_ymm equ @CatStr(ymm, %(ways_start_reg + ways)) - - -WOP macro op, op2 - i = 0 - rept ways - op @CatStr(xmm, %(ways_start_reg + i)), op2 - i = i + 1 - endm -endm - - -ifndef ABI_LINUX -ifdef x64 - -; we use 32 bytes of home space in stack in WIN64-x64 -NUM_HOME_MM_REGS equ (32 / 16) -; we preserve xmm registers starting from xmm6 in WIN64-x64 -MM_START_SAVE_REG equ 6 - -SAVE_XMM macro num_used_mm_regs:req - num_save_mm_regs = num_used_mm_regs - MM_START_SAVE_REG - if num_save_mm_regs GT 0 - num_save_mm_regs2 = num_save_mm_regs - NUM_HOME_MM_REGS - ; RSP is (16*x + 8) after entering the function in WIN64-x64 - stack_offset = 16 * num_save_mm_regs2 + (stack_param_offset mod 16) - - i = 0 - rept num_save_mm_regs - - if i eq NUM_HOME_MM_REGS - sub r4, stack_offset - endif - - if i lt NUM_HOME_MM_REGS - movdqa [r4 + stack_param_offset + i * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i)) - else - movdqa [r4 + (i - NUM_HOME_MM_REGS) * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i)) - endif - - i = i + 1 - endm - endif -endm - -RESTORE_XMM macro num_used_mm_regs:req - if num_save_mm_regs GT 0 - i = 0 - if num_save_mm_regs2 GT 0 - rept num_save_mm_regs2 - movdqa @CatStr(xmm, %(MM_START_SAVE_REG + NUM_HOME_MM_REGS + i)), [r4 + i * 16] - i = i + 1 - endm - add r4, stack_offset - endif - - num_low_regs = num_save_mm_regs - i - i = 0 - rept num_low_regs - movdqa @CatStr(xmm, %(MM_START_SAVE_REG + i)), [r4 + stack_param_offset + i * 16] - i = i + 1 - endm - endif -endm - -endif ; x64 -endif ; ABI_LINUX - - -MY_PROLOG macro num_used_mm_regs:req - ; num_regs_push: must be equal to the number of push operators - ; push r3 - ; push r5 - if (IS_LINUX eq 0) or (IS_X64 eq 0) - push r6 - push r7 - endif - - mov rN, num_param ; don't move it; num_param can use stack pointer (r4) - - if (IS_X64 eq 0) - if (IS_CDECL gt 0) - mov rD, [r4 + data_OFFS] - mov keys, [r4 + aes_OFFS] - endif - elseif (IS_LINUX gt 0) - MY_ABI_LINUX_TO_WIN_2 - endif - - - ifndef ABI_LINUX - ifdef x64 - SAVE_XMM num_used_mm_regs - endif - endif - - mov ksize_x, [keys + 16] - shl ksize_x, 5 -endm - - -MY_EPILOG macro - ifndef ABI_LINUX - ifdef x64 - RESTORE_XMM num_save_mm_regs - endif - endif - - if (IS_LINUX eq 0) or (IS_X64 eq 0) - pop r7 - pop r6 - endif - ; pop r5 - ; pop r3 - MY_ENDP -endm - - -OP_KEY macro op:req, offs:req - op state, [keys + offs] -endm - - -WOP_KEY macro op:req, offs:req - movdqa key, [keys + offs] - WOP op, key -endm - - -; ---------- AES-CBC Decode ---------- - - -XOR_WITH_DATA macro reg, _ppp_ - pxor reg, [rD + i * 16] -endm - -WRITE_TO_DATA macro reg, _ppp_ - movdqa [rD + i * 16], reg -endm - - -; state0 equ @CatStr(xmm, %(ways_start_reg)) - -key0 equ @CatStr(xmm, %(ways_start_reg + ways + 1)) -key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1)) - -key_last equ @CatStr(xmm, %(ways_start_reg + ways + 2)) -key_last_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2)) -key_last_ymm_n equ (ways_start_reg + ways + 2) - -NUM_CBC_REGS equ (ways_start_reg + ways + 3) - - -MY_SEG_PROC AesCbc_Decode_HW, 3 - - AesCbc_Decode_HW_start:: - MY_PROLOG NUM_CBC_REGS - - AesCbc_Decode_HW_start_2:: - movdqa iv, [keys] - add keys, 32 - - movdqa key0, [keys + 1 * ksize_r] - movdqa key_last, [keys] - sub ksize_x, 16 - - jmp check2 - align 16 - nextBlocks2: - WOP movdqa, [rD + i * 16] - mov koffs_x, ksize_x - ; WOP_KEY pxor, ksize_r + 16 - WOP pxor, key0 - ; align 16 - @@: - WOP_KEY aesdec, 1 * koffs_r - sub koffs_r, 16 - jnz @B - ; WOP_KEY aesdeclast, 0 - WOP aesdeclast, key_last - - pxor @CatStr(xmm, %(ways_start_reg)), iv - i = 1 - rept ways - 1 - pxor @CatStr(xmm, %(ways_start_reg + i)), [rD + i * 16 - 16] - i = i + 1 - endm - movdqa iv, [rD + ways * 16 - 16] - WOP WRITE_TO_DATA - - add rD, ways * 16 - AesCbc_Decode_HW_start_3:: - check2: - sub rN, ways - jnc nextBlocks2 - add rN, ways - - sub ksize_x, 16 - - jmp check - nextBlock: - movdqa state, [rD] - mov koffs_x, ksize_x - ; OP_KEY pxor, 1 * ksize_r + 32 - pxor state, key0 - ; movdqa state0, [rD] - ; movdqa state, key0 - ; pxor state, state0 - @@: - OP_KEY aesdec, 1 * koffs_r + 16 - OP_KEY aesdec, 1 * koffs_r - sub koffs_r, 32 - jnz @B - OP_KEY aesdec, 16 - ; OP_KEY aesdeclast, 0 - aesdeclast state, key_last - - pxor state, iv - movdqa iv, [rD] - ; movdqa iv, state0 - movdqa [rD], state - - add rD, 16 - check: - sub rN, 1 - jnc nextBlock - - movdqa [keys - 32], iv -MY_EPILOG - - - - -; ---------- AVX ---------- - - -AVX__WOP_n macro op - i = 0 - rept ways - op (ways_start_reg + i) - i = i + 1 - endm -endm - -AVX__WOP macro op - i = 0 - rept ways - op @CatStr(ymm, %(ways_start_reg + i)) - i = i + 1 - endm -endm - - -AVX__WOP_KEY macro op:req, offs:req - vmovdqa key_ymm, ymmword ptr [keys2 + offs] - AVX__WOP_n op -endm - - -AVX__CBC_START macro reg - ; vpxor reg, key_ymm, ymmword ptr [rD + 32 * i] - vpxor reg, key0_ymm, ymmword ptr [rD + 32 * i] -endm - -AVX__CBC_END macro reg - if i eq 0 - vpxor reg, reg, iv_ymm - else - vpxor reg, reg, ymmword ptr [rD + i * 32 - 16] - endif -endm - - -AVX__WRITE_TO_DATA macro reg - vmovdqu ymmword ptr [rD + 32 * i], reg -endm - -AVX__XOR_WITH_DATA macro reg - vpxor reg, reg, ymmword ptr [rD + 32 * i] -endm - -AVX__CTR_START macro reg - vpaddq iv_ymm, iv_ymm, one_ymm - ; vpxor reg, iv_ymm, key_ymm - vpxor reg, iv_ymm, key0_ymm -endm - - -MY_VAES_INSTR_2 macro cmd, dest, a1, a2 - db 0c4H - db 2 + 040H + 020h * (1 - (a2) / 8) + 080h * (1 - (dest) / 8) - db 5 + 8 * ((not (a1)) and 15) - db cmd - db 0c0H + 8 * ((dest) and 7) + ((a2) and 7) -endm - -MY_VAES_INSTR macro cmd, dest, a - MY_VAES_INSTR_2 cmd, dest, dest, a -endm - -MY_vaesenc macro dest, a - MY_VAES_INSTR 0dcH, dest, a -endm -MY_vaesenclast macro dest, a - MY_VAES_INSTR 0ddH, dest, a -endm -MY_vaesdec macro dest, a - MY_VAES_INSTR 0deH, dest, a -endm -MY_vaesdeclast macro dest, a - MY_VAES_INSTR 0dfH, dest, a -endm - - -AVX__VAES_DEC macro reg - MY_vaesdec reg, key_ymm_n -endm - -AVX__VAES_DEC_LAST_key_last macro reg - ; MY_vaesdeclast reg, key_ymm_n - MY_vaesdeclast reg, key_last_ymm_n -endm - -AVX__VAES_ENC macro reg - MY_vaesenc reg, key_ymm_n -endm - -AVX__VAES_ENC_LAST macro reg - MY_vaesenclast reg, key_ymm_n -endm - -AVX__vinserti128_TO_HIGH macro dest, src - vinserti128 dest, dest, src, 1 -endm - - -MY_PROC AesCbc_Decode_HW_256, 3 - ifdef use_vaes_256 - MY_PROLOG NUM_CBC_REGS - - cmp rN, ways * 2 - jb AesCbc_Decode_HW_start_2 - - vmovdqa iv, xmmword ptr [keys] - add keys, 32 - - vbroadcasti128 key0_ymm, xmmword ptr [keys + 1 * ksize_r] - vbroadcasti128 key_last_ymm, xmmword ptr [keys] - sub ksize_x, 16 - mov koffs_x, ksize_x - add ksize_x, ksize_x - - AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 2) * 32) - push keys2 - sub r4, AVX_STACK_SUB - ; sub r4, 32 - ; sub r4, ksize_r - ; lea keys2, [r4 + 32] - mov keys2, r4 - and keys2, -32 - broad: - vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r] - vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm - sub koffs_r, 16 - ; jnc broad - jnz broad - - sub rN, ways * 2 - - align 16 - avx_cbcdec_nextBlock2: - mov koffs_x, ksize_x - ; AVX__WOP_KEY AVX__CBC_START, 1 * koffs_r + 32 - AVX__WOP AVX__CBC_START - @@: - AVX__WOP_KEY AVX__VAES_DEC, 1 * koffs_r - sub koffs_r, 32 - jnz @B - ; AVX__WOP_KEY AVX__VAES_DEC_LAST, 0 - AVX__WOP_n AVX__VAES_DEC_LAST_key_last - - AVX__vinserti128_TO_HIGH iv_ymm, xmmword ptr [rD] - AVX__WOP AVX__CBC_END - - vmovdqa iv, xmmword ptr [rD + ways * 32 - 16] - AVX__WOP AVX__WRITE_TO_DATA - - add rD, ways * 32 - sub rN, ways * 2 - jnc avx_cbcdec_nextBlock2 - add rN, ways * 2 - - shr ksize_x, 1 - - ; lea r4, [r4 + 1 * ksize_r + 32] - add r4, AVX_STACK_SUB - pop keys2 - - vzeroupper - jmp AesCbc_Decode_HW_start_3 - else - jmp AesCbc_Decode_HW_start - endif -MY_ENDP -MY_SEG_ENDP - - - - -; ---------- AES-CBC Encode ---------- - -e0 equ xmm1 - -CENC_START_KEY equ 2 -CENC_NUM_REG_KEYS equ (3 * 2) -; last_key equ @CatStr(xmm, %(CENC_START_KEY + CENC_NUM_REG_KEYS)) - -MY_SEG_PROC AesCbc_Encode_HW, 3 - MY_PROLOG (CENC_START_KEY + CENC_NUM_REG_KEYS + 0) - - movdqa state, [keys] - add keys, 32 - - i = 0 - rept CENC_NUM_REG_KEYS - movdqa @CatStr(xmm, %(CENC_START_KEY + i)), [keys + i * 16] - i = i + 1 - endm - - add keys, ksize_r - neg ksize_r - add ksize_r, (16 * CENC_NUM_REG_KEYS) - ; movdqa last_key, [keys] - jmp check_e - - align 16 - nextBlock_e: - movdqa e0, [rD] - mov koffs_r, ksize_r - pxor e0, @CatStr(xmm, %(CENC_START_KEY)) - pxor state, e0 - - i = 1 - rept (CENC_NUM_REG_KEYS - 1) - aesenc state, @CatStr(xmm, %(CENC_START_KEY + i)) - i = i + 1 - endm - - @@: - OP_KEY aesenc, 1 * koffs_r - OP_KEY aesenc, 1 * koffs_r + 16 - add koffs_r, 32 - jnz @B - OP_KEY aesenclast, 0 - ; aesenclast state, last_key - - movdqa [rD], state - add rD, 16 - check_e: - sub rN, 1 - jnc nextBlock_e - - ; movdqa [keys - 32], state - movdqa [keys + 1 * ksize_r - (16 * CENC_NUM_REG_KEYS) - 32], state -MY_EPILOG -MY_SEG_ENDP - - - -; ---------- AES-CTR ---------- - -ifdef x64 - ; ways = 11 -endif - - -one equ @CatStr(xmm, %(ways_start_reg + ways + 1)) -one_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1)) -key0 equ @CatStr(xmm, %(ways_start_reg + ways + 2)) -key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2)) -NUM_CTR_REGS equ (ways_start_reg + ways + 3) - -INIT_CTR macro reg, _ppp_ - paddq iv, one - movdqa reg, iv -endm - - -MY_SEG_PROC AesCtr_Code_HW, 3 - Ctr_start:: - MY_PROLOG NUM_CTR_REGS - - Ctr_start_2:: - movdqa iv, [keys] - add keys, 32 - movdqa key0, [keys] - - add keys, ksize_r - neg ksize_r - add ksize_r, 16 - - Ctr_start_3:: - mov koffs_x, 1 - movd one, koffs_x - jmp check2_c - - align 16 - nextBlocks2_c: - WOP INIT_CTR, 0 - mov koffs_r, ksize_r - ; WOP_KEY pxor, 1 * koffs_r -16 - WOP pxor, key0 - @@: - WOP_KEY aesenc, 1 * koffs_r - add koffs_r, 16 - jnz @B - WOP_KEY aesenclast, 0 - - WOP XOR_WITH_DATA - WOP WRITE_TO_DATA - add rD, ways * 16 - check2_c: - sub rN, ways - jnc nextBlocks2_c - add rN, ways - - sub keys, 16 - add ksize_r, 16 - - jmp check_c - - ; align 16 - nextBlock_c: - paddq iv, one - ; movdqa state, [keys + 1 * koffs_r - 16] - movdqa state, key0 - mov koffs_r, ksize_r - pxor state, iv - - @@: - OP_KEY aesenc, 1 * koffs_r - OP_KEY aesenc, 1 * koffs_r + 16 - add koffs_r, 32 - jnz @B - OP_KEY aesenc, 0 - OP_KEY aesenclast, 16 - - pxor state, [rD] - movdqa [rD], state - add rD, 16 - check_c: - sub rN, 1 - jnc nextBlock_c - - ; movdqa [keys - 32], iv - movdqa [keys + 1 * ksize_r - 16 - 32], iv -MY_EPILOG - - -MY_PROC AesCtr_Code_HW_256, 3 - ifdef use_vaes_256 - MY_PROLOG NUM_CTR_REGS - - cmp rN, ways * 2 - jb Ctr_start_2 - - vbroadcasti128 iv_ymm, xmmword ptr [keys] - add keys, 32 - vbroadcasti128 key0_ymm, xmmword ptr [keys] - mov koffs_x, 1 - vmovd one, koffs_x - vpsubq iv_ymm, iv_ymm, one_ymm - vpaddq one, one, one - AVX__vinserti128_TO_HIGH one_ymm, one - - add keys, ksize_r - sub ksize_x, 16 - neg ksize_r - mov koffs_r, ksize_r - add ksize_r, ksize_r - - AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 1) * 32) - push keys2 - lea keys2, [r4 - 32] - sub r4, AVX_STACK_SUB - and keys2, -32 - vbroadcasti128 key_ymm, xmmword ptr [keys] - vmovdqa ymmword ptr [keys2], key_ymm - @@: - vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r] - vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm - add koffs_r, 16 - jnz @B - - sub rN, ways * 2 - - align 16 - avx_ctr_nextBlock2: - mov koffs_r, ksize_r - AVX__WOP AVX__CTR_START - ; AVX__WOP_KEY AVX__CTR_START, 1 * koffs_r - 32 - @@: - AVX__WOP_KEY AVX__VAES_ENC, 1 * koffs_r - add koffs_r, 32 - jnz @B - AVX__WOP_KEY AVX__VAES_ENC_LAST, 0 - - AVX__WOP AVX__XOR_WITH_DATA - AVX__WOP AVX__WRITE_TO_DATA - - add rD, ways * 32 - sub rN, ways * 2 - jnc avx_ctr_nextBlock2 - add rN, ways * 2 - - vextracti128 iv, iv_ymm, 1 - sar ksize_r, 1 - - add r4, AVX_STACK_SUB - pop keys2 - - vzeroupper - jmp Ctr_start_3 - else - jmp Ctr_start - endif -MY_ENDP -MY_SEG_ENDP - -end +; AesOpt.asm -- AES optimized code for x86 AES hardware instructions +; 2021-12-25 : Igor Pavlov : Public domain + +include 7zAsm.asm + +ifdef __ASMC__ + use_vaes_256 equ 1 +else +ifdef ymm0 + use_vaes_256 equ 1 +endif +endif + + +ifdef use_vaes_256 + ECHO "++ VAES 256" +else + ECHO "-- NO VAES 256" +endif + +ifdef x64 + ECHO "x86-64" +else + ECHO "x86" +if (IS_CDECL gt 0) + ECHO "ABI : CDECL" +else + ECHO "ABI : no CDECL : FASTCALL" +endif +endif + +if (IS_LINUX gt 0) + ECHO "ABI : LINUX" +else + ECHO "ABI : WINDOWS" +endif + +MY_ASM_START + +ifndef x64 + .686 + .xmm +endif + + +; MY_ALIGN EQU ALIGN(64) +MY_ALIGN EQU + +SEG_ALIGN EQU MY_ALIGN + +MY_SEG_PROC macro name:req, numParams:req + ; seg_name equ @CatStr(_TEXT$, name) + ; seg_name SEGMENT SEG_ALIGN 'CODE' + MY_PROC name, numParams +endm + +MY_SEG_ENDP macro + ; seg_name ENDS +endm + + +NUM_AES_KEYS_MAX equ 15 + +; the number of push operators in function PROLOG +if (IS_LINUX eq 0) or (IS_X64 eq 0) +num_regs_push equ 2 +stack_param_offset equ (REG_SIZE * (1 + num_regs_push)) +endif + +ifdef x64 + num_param equ REG_ABI_PARAM_2 +else + if (IS_CDECL gt 0) + ; size_t size + ; void * data + ; UInt32 * aes + ; ret-ip <- (r4) + aes_OFFS equ (stack_param_offset) + data_OFFS equ (REG_SIZE + aes_OFFS) + size_OFFS equ (REG_SIZE + data_OFFS) + num_param equ [r4 + size_OFFS] + else + num_param equ [r4 + stack_param_offset] + endif +endif + +keys equ REG_PARAM_0 ; r1 +rD equ REG_PARAM_1 ; r2 +rN equ r0 + +koffs_x equ x7 +koffs_r equ r7 + +ksize_x equ x6 +ksize_r equ r6 + +keys2 equ r3 + +state equ xmm0 +key equ xmm0 +key_ymm equ ymm0 +key_ymm_n equ 0 + +ifdef x64 + ways = 11 +else + ways = 4 +endif + +ways_start_reg equ 1 + +iv equ @CatStr(xmm, %(ways_start_reg + ways)) +iv_ymm equ @CatStr(ymm, %(ways_start_reg + ways)) + + +WOP macro op, op2 + i = 0 + rept ways + op @CatStr(xmm, %(ways_start_reg + i)), op2 + i = i + 1 + endm +endm + + +ifndef ABI_LINUX +ifdef x64 + +; we use 32 bytes of home space in stack in WIN64-x64 +NUM_HOME_MM_REGS equ (32 / 16) +; we preserve xmm registers starting from xmm6 in WIN64-x64 +MM_START_SAVE_REG equ 6 + +SAVE_XMM macro num_used_mm_regs:req + num_save_mm_regs = num_used_mm_regs - MM_START_SAVE_REG + if num_save_mm_regs GT 0 + num_save_mm_regs2 = num_save_mm_regs - NUM_HOME_MM_REGS + ; RSP is (16*x + 8) after entering the function in WIN64-x64 + stack_offset = 16 * num_save_mm_regs2 + (stack_param_offset mod 16) + + i = 0 + rept num_save_mm_regs + + if i eq NUM_HOME_MM_REGS + sub r4, stack_offset + endif + + if i lt NUM_HOME_MM_REGS + movdqa [r4 + stack_param_offset + i * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i)) + else + movdqa [r4 + (i - NUM_HOME_MM_REGS) * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i)) + endif + + i = i + 1 + endm + endif +endm + +RESTORE_XMM macro num_used_mm_regs:req + if num_save_mm_regs GT 0 + i = 0 + if num_save_mm_regs2 GT 0 + rept num_save_mm_regs2 + movdqa @CatStr(xmm, %(MM_START_SAVE_REG + NUM_HOME_MM_REGS + i)), [r4 + i * 16] + i = i + 1 + endm + add r4, stack_offset + endif + + num_low_regs = num_save_mm_regs - i + i = 0 + rept num_low_regs + movdqa @CatStr(xmm, %(MM_START_SAVE_REG + i)), [r4 + stack_param_offset + i * 16] + i = i + 1 + endm + endif +endm + +endif ; x64 +endif ; ABI_LINUX + + +MY_PROLOG macro num_used_mm_regs:req + ; num_regs_push: must be equal to the number of push operators + ; push r3 + ; push r5 + if (IS_LINUX eq 0) or (IS_X64 eq 0) + push r6 + push r7 + endif + + mov rN, num_param ; don't move it; num_param can use stack pointer (r4) + + if (IS_X64 eq 0) + if (IS_CDECL gt 0) + mov rD, [r4 + data_OFFS] + mov keys, [r4 + aes_OFFS] + endif + elseif (IS_LINUX gt 0) + MY_ABI_LINUX_TO_WIN_2 + endif + + + ifndef ABI_LINUX + ifdef x64 + SAVE_XMM num_used_mm_regs + endif + endif + + mov ksize_x, [keys + 16] + shl ksize_x, 5 +endm + + +MY_EPILOG macro + ifndef ABI_LINUX + ifdef x64 + RESTORE_XMM num_save_mm_regs + endif + endif + + if (IS_LINUX eq 0) or (IS_X64 eq 0) + pop r7 + pop r6 + endif + ; pop r5 + ; pop r3 + MY_ENDP +endm + + +OP_KEY macro op:req, offs:req + op state, [keys + offs] +endm + + +WOP_KEY macro op:req, offs:req + movdqa key, [keys + offs] + WOP op, key +endm + + +; ---------- AES-CBC Decode ---------- + + +XOR_WITH_DATA macro reg, _ppp_ + pxor reg, [rD + i * 16] +endm + +WRITE_TO_DATA macro reg, _ppp_ + movdqa [rD + i * 16], reg +endm + + +; state0 equ @CatStr(xmm, %(ways_start_reg)) + +key0 equ @CatStr(xmm, %(ways_start_reg + ways + 1)) +key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1)) + +key_last equ @CatStr(xmm, %(ways_start_reg + ways + 2)) +key_last_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2)) +key_last_ymm_n equ (ways_start_reg + ways + 2) + +NUM_CBC_REGS equ (ways_start_reg + ways + 3) + + +MY_SEG_PROC AesCbc_Decode_HW, 3 + + AesCbc_Decode_HW_start:: + MY_PROLOG NUM_CBC_REGS + + AesCbc_Decode_HW_start_2:: + movdqa iv, [keys] + add keys, 32 + + movdqa key0, [keys + 1 * ksize_r] + movdqa key_last, [keys] + sub ksize_x, 16 + + jmp check2 + align 16 + nextBlocks2: + WOP movdqa, [rD + i * 16] + mov koffs_x, ksize_x + ; WOP_KEY pxor, ksize_r + 16 + WOP pxor, key0 + ; align 16 + @@: + WOP_KEY aesdec, 1 * koffs_r + sub koffs_r, 16 + jnz @B + ; WOP_KEY aesdeclast, 0 + WOP aesdeclast, key_last + + pxor @CatStr(xmm, %(ways_start_reg)), iv + i = 1 + rept ways - 1 + pxor @CatStr(xmm, %(ways_start_reg + i)), [rD + i * 16 - 16] + i = i + 1 + endm + movdqa iv, [rD + ways * 16 - 16] + WOP WRITE_TO_DATA + + add rD, ways * 16 + AesCbc_Decode_HW_start_3:: + check2: + sub rN, ways + jnc nextBlocks2 + add rN, ways + + sub ksize_x, 16 + + jmp check + nextBlock: + movdqa state, [rD] + mov koffs_x, ksize_x + ; OP_KEY pxor, 1 * ksize_r + 32 + pxor state, key0 + ; movdqa state0, [rD] + ; movdqa state, key0 + ; pxor state, state0 + @@: + OP_KEY aesdec, 1 * koffs_r + 16 + OP_KEY aesdec, 1 * koffs_r + sub koffs_r, 32 + jnz @B + OP_KEY aesdec, 16 + ; OP_KEY aesdeclast, 0 + aesdeclast state, key_last + + pxor state, iv + movdqa iv, [rD] + ; movdqa iv, state0 + movdqa [rD], state + + add rD, 16 + check: + sub rN, 1 + jnc nextBlock + + movdqa [keys - 32], iv +MY_EPILOG + + + + +; ---------- AVX ---------- + + +AVX__WOP_n macro op + i = 0 + rept ways + op (ways_start_reg + i) + i = i + 1 + endm +endm + +AVX__WOP macro op + i = 0 + rept ways + op @CatStr(ymm, %(ways_start_reg + i)) + i = i + 1 + endm +endm + + +AVX__WOP_KEY macro op:req, offs:req + vmovdqa key_ymm, ymmword ptr [keys2 + offs] + AVX__WOP_n op +endm + + +AVX__CBC_START macro reg + ; vpxor reg, key_ymm, ymmword ptr [rD + 32 * i] + vpxor reg, key0_ymm, ymmword ptr [rD + 32 * i] +endm + +AVX__CBC_END macro reg + if i eq 0 + vpxor reg, reg, iv_ymm + else + vpxor reg, reg, ymmword ptr [rD + i * 32 - 16] + endif +endm + + +AVX__WRITE_TO_DATA macro reg + vmovdqu ymmword ptr [rD + 32 * i], reg +endm + +AVX__XOR_WITH_DATA macro reg + vpxor reg, reg, ymmword ptr [rD + 32 * i] +endm + +AVX__CTR_START macro reg + vpaddq iv_ymm, iv_ymm, one_ymm + ; vpxor reg, iv_ymm, key_ymm + vpxor reg, iv_ymm, key0_ymm +endm + + +MY_VAES_INSTR_2 macro cmd, dest, a1, a2 + db 0c4H + db 2 + 040H + 020h * (1 - (a2) / 8) + 080h * (1 - (dest) / 8) + db 5 + 8 * ((not (a1)) and 15) + db cmd + db 0c0H + 8 * ((dest) and 7) + ((a2) and 7) +endm + +MY_VAES_INSTR macro cmd, dest, a + MY_VAES_INSTR_2 cmd, dest, dest, a +endm + +MY_vaesenc macro dest, a + MY_VAES_INSTR 0dcH, dest, a +endm +MY_vaesenclast macro dest, a + MY_VAES_INSTR 0ddH, dest, a +endm +MY_vaesdec macro dest, a + MY_VAES_INSTR 0deH, dest, a +endm +MY_vaesdeclast macro dest, a + MY_VAES_INSTR 0dfH, dest, a +endm + + +AVX__VAES_DEC macro reg + MY_vaesdec reg, key_ymm_n +endm + +AVX__VAES_DEC_LAST_key_last macro reg + ; MY_vaesdeclast reg, key_ymm_n + MY_vaesdeclast reg, key_last_ymm_n +endm + +AVX__VAES_ENC macro reg + MY_vaesenc reg, key_ymm_n +endm + +AVX__VAES_ENC_LAST macro reg + MY_vaesenclast reg, key_ymm_n +endm + +AVX__vinserti128_TO_HIGH macro dest, src + vinserti128 dest, dest, src, 1 +endm + + +MY_PROC AesCbc_Decode_HW_256, 3 + ifdef use_vaes_256 + MY_PROLOG NUM_CBC_REGS + + cmp rN, ways * 2 + jb AesCbc_Decode_HW_start_2 + + vmovdqa iv, xmmword ptr [keys] + add keys, 32 + + vbroadcasti128 key0_ymm, xmmword ptr [keys + 1 * ksize_r] + vbroadcasti128 key_last_ymm, xmmword ptr [keys] + sub ksize_x, 16 + mov koffs_x, ksize_x + add ksize_x, ksize_x + + AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 2) * 32) + push keys2 + sub r4, AVX_STACK_SUB + ; sub r4, 32 + ; sub r4, ksize_r + ; lea keys2, [r4 + 32] + mov keys2, r4 + and keys2, -32 + broad: + vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r] + vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm + sub koffs_r, 16 + ; jnc broad + jnz broad + + sub rN, ways * 2 + + align 16 + avx_cbcdec_nextBlock2: + mov koffs_x, ksize_x + ; AVX__WOP_KEY AVX__CBC_START, 1 * koffs_r + 32 + AVX__WOP AVX__CBC_START + @@: + AVX__WOP_KEY AVX__VAES_DEC, 1 * koffs_r + sub koffs_r, 32 + jnz @B + ; AVX__WOP_KEY AVX__VAES_DEC_LAST, 0 + AVX__WOP_n AVX__VAES_DEC_LAST_key_last + + AVX__vinserti128_TO_HIGH iv_ymm, xmmword ptr [rD] + AVX__WOP AVX__CBC_END + + vmovdqa iv, xmmword ptr [rD + ways * 32 - 16] + AVX__WOP AVX__WRITE_TO_DATA + + add rD, ways * 32 + sub rN, ways * 2 + jnc avx_cbcdec_nextBlock2 + add rN, ways * 2 + + shr ksize_x, 1 + + ; lea r4, [r4 + 1 * ksize_r + 32] + add r4, AVX_STACK_SUB + pop keys2 + + vzeroupper + jmp AesCbc_Decode_HW_start_3 + else + jmp AesCbc_Decode_HW_start + endif +MY_ENDP +MY_SEG_ENDP + + + + +; ---------- AES-CBC Encode ---------- + +e0 equ xmm1 + +CENC_START_KEY equ 2 +CENC_NUM_REG_KEYS equ (3 * 2) +; last_key equ @CatStr(xmm, %(CENC_START_KEY + CENC_NUM_REG_KEYS)) + +MY_SEG_PROC AesCbc_Encode_HW, 3 + MY_PROLOG (CENC_START_KEY + CENC_NUM_REG_KEYS + 0) + + movdqa state, [keys] + add keys, 32 + + i = 0 + rept CENC_NUM_REG_KEYS + movdqa @CatStr(xmm, %(CENC_START_KEY + i)), [keys + i * 16] + i = i + 1 + endm + + add keys, ksize_r + neg ksize_r + add ksize_r, (16 * CENC_NUM_REG_KEYS) + ; movdqa last_key, [keys] + jmp check_e + + align 16 + nextBlock_e: + movdqa e0, [rD] + mov koffs_r, ksize_r + pxor e0, @CatStr(xmm, %(CENC_START_KEY)) + pxor state, e0 + + i = 1 + rept (CENC_NUM_REG_KEYS - 1) + aesenc state, @CatStr(xmm, %(CENC_START_KEY + i)) + i = i + 1 + endm + + @@: + OP_KEY aesenc, 1 * koffs_r + OP_KEY aesenc, 1 * koffs_r + 16 + add koffs_r, 32 + jnz @B + OP_KEY aesenclast, 0 + ; aesenclast state, last_key + + movdqa [rD], state + add rD, 16 + check_e: + sub rN, 1 + jnc nextBlock_e + + ; movdqa [keys - 32], state + movdqa [keys + 1 * ksize_r - (16 * CENC_NUM_REG_KEYS) - 32], state +MY_EPILOG +MY_SEG_ENDP + + + +; ---------- AES-CTR ---------- + +ifdef x64 + ; ways = 11 +endif + + +one equ @CatStr(xmm, %(ways_start_reg + ways + 1)) +one_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1)) +key0 equ @CatStr(xmm, %(ways_start_reg + ways + 2)) +key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2)) +NUM_CTR_REGS equ (ways_start_reg + ways + 3) + +INIT_CTR macro reg, _ppp_ + paddq iv, one + movdqa reg, iv +endm + + +MY_SEG_PROC AesCtr_Code_HW, 3 + Ctr_start:: + MY_PROLOG NUM_CTR_REGS + + Ctr_start_2:: + movdqa iv, [keys] + add keys, 32 + movdqa key0, [keys] + + add keys, ksize_r + neg ksize_r + add ksize_r, 16 + + Ctr_start_3:: + mov koffs_x, 1 + movd one, koffs_x + jmp check2_c + + align 16 + nextBlocks2_c: + WOP INIT_CTR, 0 + mov koffs_r, ksize_r + ; WOP_KEY pxor, 1 * koffs_r -16 + WOP pxor, key0 + @@: + WOP_KEY aesenc, 1 * koffs_r + add koffs_r, 16 + jnz @B + WOP_KEY aesenclast, 0 + + WOP XOR_WITH_DATA + WOP WRITE_TO_DATA + add rD, ways * 16 + check2_c: + sub rN, ways + jnc nextBlocks2_c + add rN, ways + + sub keys, 16 + add ksize_r, 16 + + jmp check_c + + ; align 16 + nextBlock_c: + paddq iv, one + ; movdqa state, [keys + 1 * koffs_r - 16] + movdqa state, key0 + mov koffs_r, ksize_r + pxor state, iv + + @@: + OP_KEY aesenc, 1 * koffs_r + OP_KEY aesenc, 1 * koffs_r + 16 + add koffs_r, 32 + jnz @B + OP_KEY aesenc, 0 + OP_KEY aesenclast, 16 + + pxor state, [rD] + movdqa [rD], state + add rD, 16 + check_c: + sub rN, 1 + jnc nextBlock_c + + ; movdqa [keys - 32], iv + movdqa [keys + 1 * ksize_r - 16 - 32], iv +MY_EPILOG + + +MY_PROC AesCtr_Code_HW_256, 3 + ifdef use_vaes_256 + MY_PROLOG NUM_CTR_REGS + + cmp rN, ways * 2 + jb Ctr_start_2 + + vbroadcasti128 iv_ymm, xmmword ptr [keys] + add keys, 32 + vbroadcasti128 key0_ymm, xmmword ptr [keys] + mov koffs_x, 1 + vmovd one, koffs_x + vpsubq iv_ymm, iv_ymm, one_ymm + vpaddq one, one, one + AVX__vinserti128_TO_HIGH one_ymm, one + + add keys, ksize_r + sub ksize_x, 16 + neg ksize_r + mov koffs_r, ksize_r + add ksize_r, ksize_r + + AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 1) * 32) + push keys2 + lea keys2, [r4 - 32] + sub r4, AVX_STACK_SUB + and keys2, -32 + vbroadcasti128 key_ymm, xmmword ptr [keys] + vmovdqa ymmword ptr [keys2], key_ymm + @@: + vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r] + vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm + add koffs_r, 16 + jnz @B + + sub rN, ways * 2 + + align 16 + avx_ctr_nextBlock2: + mov koffs_r, ksize_r + AVX__WOP AVX__CTR_START + ; AVX__WOP_KEY AVX__CTR_START, 1 * koffs_r - 32 + @@: + AVX__WOP_KEY AVX__VAES_ENC, 1 * koffs_r + add koffs_r, 32 + jnz @B + AVX__WOP_KEY AVX__VAES_ENC_LAST, 0 + + AVX__WOP AVX__XOR_WITH_DATA + AVX__WOP AVX__WRITE_TO_DATA + + add rD, ways * 32 + sub rN, ways * 2 + jnc avx_ctr_nextBlock2 + add rN, ways * 2 + + vextracti128 iv, iv_ymm, 1 + sar ksize_r, 1 + + add r4, AVX_STACK_SUB + pop keys2 + + vzeroupper + jmp Ctr_start_3 + else + jmp Ctr_start + endif +MY_ENDP +MY_SEG_ENDP + +end diff --git a/Asm/x86/LzFindOpt.asm b/Asm/x86/LzFindOpt.asm index b149ae12b..94c5c768c 100644 --- a/Asm/x86/LzFindOpt.asm +++ b/Asm/x86/LzFindOpt.asm @@ -1,540 +1,540 @@ -; LzFindOpt.asm -- ASM version of GetMatchesSpecN_2() function -; 2024-06-18: Igor Pavlov : Public domain -; - -ifndef x64 -; x64=1 -; .err -endif - -include 7zAsm.asm - -MY_ASM_START - -ifndef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT -if (IS_LINUX gt 0) - Z7_LZ_FIND_OPT_ASM_USE_SEGMENT equ 1 -else - Z7_LZ_FIND_OPT_ASM_USE_SEGMENT equ 1 -endif -endif - -ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT -_TEXT$LZFINDOPT SEGMENT ALIGN(64) 'CODE' -MY_ALIGN macro num:req - align num - ; align 16 -endm -else -MY_ALIGN macro num:req - ; We expect that ".text" is aligned for 16-bytes. - ; So we don't need large alignment inside our function. - align 16 -endm -endif - - -MY_ALIGN_16 macro - MY_ALIGN 16 -endm - -MY_ALIGN_32 macro - MY_ALIGN 32 -endm - -MY_ALIGN_64 macro - MY_ALIGN 64 -endm - - -t0_L equ x0_L -t0_x equ x0 -t0 equ r0 -t1_x equ x3 -t1 equ r3 - -cp_x equ t1_x -cp_r equ t1 -m equ x5 -m_r equ r5 -len_x equ x6 -len equ r6 -diff_x equ x7 -diff equ r7 -len0 equ r10 -len1_x equ x11 -len1 equ r11 -maxLen_x equ x12 -maxLen equ r12 -d equ r13 -ptr0 equ r14 -ptr1 equ r15 - -d_lim equ m_r -cycSize equ len_x -hash_lim equ len0 -delta1_x equ len1_x -delta1_r equ len1 -delta_x equ maxLen_x -delta_r equ maxLen -hash equ ptr0 -src equ ptr1 - - - -if (IS_LINUX gt 0) - -; r1 r2 r8 r9 : win32 -; r7 r6 r2 r1 r8 r9 : linux - -lenLimit equ r8 -lenLimit_x equ x8 -; pos_r equ r2 -pos equ x2 -cur equ r1 -son equ r9 - -else - -lenLimit equ REG_ABI_PARAM_2 -lenLimit_x equ REG_ABI_PARAM_2_x -pos equ REG_ABI_PARAM_1_x -cur equ REG_ABI_PARAM_0 -son equ REG_ABI_PARAM_3 - -endif - - -if (IS_LINUX gt 0) - maxLen_OFFS equ (REG_SIZE * (6 + 1)) -else - cutValue_OFFS equ (REG_SIZE * (8 + 1 + 4)) - d_OFFS equ (REG_SIZE + cutValue_OFFS) - maxLen_OFFS equ (REG_SIZE + d_OFFS) -endif - hash_OFFS equ (REG_SIZE + maxLen_OFFS) - limit_OFFS equ (REG_SIZE + hash_OFFS) - size_OFFS equ (REG_SIZE + limit_OFFS) - cycPos_OFFS equ (REG_SIZE + size_OFFS) - cycSize_OFFS equ (REG_SIZE + cycPos_OFFS) - posRes_OFFS equ (REG_SIZE + cycSize_OFFS) - -if (IS_LINUX gt 0) -else - cutValue_PAR equ [r0 + cutValue_OFFS] - d_PAR equ [r0 + d_OFFS] -endif - maxLen_PAR equ [r0 + maxLen_OFFS] - hash_PAR equ [r0 + hash_OFFS] - limit_PAR equ [r0 + limit_OFFS] - size_PAR equ [r0 + size_OFFS] - cycPos_PAR equ [r0 + cycPos_OFFS] - cycSize_PAR equ [r0 + cycSize_OFFS] - posRes_PAR equ [r0 + posRes_OFFS] - - - cutValue_VAR equ DWORD PTR [r4 + 8 * 0] - cutValueCur_VAR equ DWORD PTR [r4 + 8 * 0 + 4] - cycPos_VAR equ DWORD PTR [r4 + 8 * 1 + 0] - cycSize_VAR equ DWORD PTR [r4 + 8 * 1 + 4] - hash_VAR equ QWORD PTR [r4 + 8 * 2] - limit_VAR equ QWORD PTR [r4 + 8 * 3] - size_VAR equ QWORD PTR [r4 + 8 * 4] - distances equ QWORD PTR [r4 + 8 * 5] - maxLen_VAR equ QWORD PTR [r4 + 8 * 6] - - Old_RSP equ QWORD PTR [r4 + 8 * 7] - LOCAL_SIZE equ 8 * 8 - -COPY_VAR_32 macro dest_var, src_var - mov x3, src_var - mov dest_var, x3 -endm - -COPY_VAR_64 macro dest_var, src_var - mov r3, src_var - mov dest_var, r3 -endm - - -ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT -; MY_ALIGN_64 -else - MY_ALIGN_16 -endif -MY_PROC GetMatchesSpecN_2, 13 -MY_PUSH_PRESERVED_ABI_REGS - mov r0, RSP - lea r3, [r0 - LOCAL_SIZE] - and r3, -64 - mov RSP, r3 - mov Old_RSP, r0 - -if (IS_LINUX gt 0) - mov d, REG_ABI_PARAM_5 ; r13 = r9 - mov cutValue_VAR, REG_ABI_PARAM_4_x ; = r8 - mov son, REG_ABI_PARAM_3 ; r9 = r1 - mov r8, REG_ABI_PARAM_2 ; r8 = r2 - mov pos, REG_ABI_PARAM_1_x ; r2 = x6 - mov r1, REG_ABI_PARAM_0 ; r1 = r7 -else - COPY_VAR_32 cutValue_VAR, cutValue_PAR - mov d, d_PAR -endif - - COPY_VAR_64 limit_VAR, limit_PAR - - mov hash_lim, size_PAR - mov size_VAR, hash_lim - - mov cp_x, cycPos_PAR - mov hash, hash_PAR - - mov cycSize, cycSize_PAR - mov cycSize_VAR, cycSize - - ; we want cur in (rcx). So we change the cur and lenLimit variables - sub lenLimit, cur - neg lenLimit_x - inc lenLimit_x - - mov t0_x, maxLen_PAR - sub t0, lenLimit - mov maxLen_VAR, t0 - - jmp main_loop - -MY_ALIGN_64 -fill_empty: - ; ptr0 = *ptr1 = kEmptyHashValue; - mov QWORD PTR [ptr1], 0 - inc pos - inc cp_x - mov DWORD PTR [d - 4], 0 - cmp d, limit_VAR - jae fin - cmp hash, hash_lim - je fin - -; MY_ALIGN_64 -main_loop: - ; UInt32 delta = *hash++; - mov diff_x, [hash] ; delta - add hash, 4 - ; mov cycPos_VAR, cp_x - - inc cur - add d, 4 - mov m, pos - sub m, diff_x; ; matchPos - - ; CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; - lea ptr1, [son + 8 * cp_r] - ; mov cycSize, cycSize_VAR - cmp pos, cycSize - jb directMode ; if (pos < cycSize_VAR) - - ; CYC MODE - - cmp diff_x, cycSize - jae fill_empty ; if (delta >= cycSize_VAR) - - xor t0_x, t0_x - mov cycPos_VAR, cp_x - sub cp_x, diff_x - ; jae prepare_for_tree_loop - ; add cp_x, cycSize - cmovb t0_x, cycSize - add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0) - jmp prepare_for_tree_loop - - -directMode: - cmp diff_x, pos - je fill_empty ; if (delta == pos) - jae fin_error ; if (delta >= pos) - - mov cycPos_VAR, cp_x - mov cp_x, m - -prepare_for_tree_loop: - mov len0, lenLimit - mov hash_VAR, hash - ; CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1; - lea ptr0, [ptr1 + 4] - ; UInt32 *_distances = ++d; - mov distances, d - - neg len0 - mov len1, len0 - - mov t0_x, cutValue_VAR - mov maxLen, maxLen_VAR - mov cutValueCur_VAR, t0_x - -MY_ALIGN_32 -tree_loop: - neg diff - mov len, len0 - cmp len1, len0 - cmovb len, len1 ; len = (len1 < len0 ? len1 : len0); - add diff, cur - - mov t0_x, [son + cp_r * 8] ; prefetch - movzx t0_x, BYTE PTR [diff + 1 * len] - lea cp_r, [son + cp_r * 8] - cmp [cur + 1 * len], t0_L - je matched_1 - - jb left_0 - - mov [ptr1], m - mov m, [cp_r + 4] - lea ptr1, [cp_r + 4] - sub diff, cur ; FIX32 - jmp next_node - -MY_ALIGN_32 -left_0: - mov [ptr0], m - mov m, [cp_r] - mov ptr0, cp_r - sub diff, cur ; FIX32 - ; jmp next_node - -; ------------ NEXT NODE ------------ -; MY_ALIGN_32 -next_node: - mov cycSize, cycSize_VAR - dec cutValueCur_VAR - je finish_tree - - add diff_x, pos ; prev_match = pos + diff - cmp m, diff_x - jae fin_error ; if (new_match >= prev_match) - - mov diff_x, pos - sub diff_x, m ; delta = pos - new_match - cmp pos, cycSize - jae cyc_mode_2 ; if (pos >= cycSize) - - mov cp_x, m - test m, m - jne tree_loop ; if (m != 0) - -finish_tree: - ; ptr0 = *ptr1 = kEmptyHashValue; - mov DWORD PTR [ptr0], 0 - mov DWORD PTR [ptr1], 0 - - inc pos - - ; _distances[-1] = (UInt32)(d - _distances); - mov t0, distances - mov t1, d - sub t1, t0 - shr t1_x, 2 - mov [t0 - 4], t1_x - - cmp d, limit_VAR - jae fin ; if (d >= limit) - - mov cp_x, cycPos_VAR - mov hash, hash_VAR - mov hash_lim, size_VAR - inc cp_x - cmp hash, hash_lim - jne main_loop ; if (hash != size) - jmp fin - - -MY_ALIGN_32 -cyc_mode_2: - cmp diff_x, cycSize - jae finish_tree ; if (delta >= cycSize) - - mov cp_x, cycPos_VAR - xor t0_x, t0_x - sub cp_x, diff_x ; cp_x = cycPos - delta - cmovb t0_x, cycSize - add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0) - jmp tree_loop - - -MY_ALIGN_32 -matched_1: - - inc len - ; cmp len_x, lenLimit_x - je short lenLimit_reach - movzx t0_x, BYTE PTR [diff + 1 * len] - cmp [cur + 1 * len], t0_L - jne mismatch - - -MY_ALIGN_32 -match_loop: - ; while (++len != lenLimit) (len[diff] != len[0]) ; - - inc len - ; cmp len_x, lenLimit_x - je short lenLimit_reach - movzx t0_x, BYTE PTR [diff + 1 * len] - cmp BYTE PTR [cur + 1 * len], t0_L - je match_loop - -mismatch: - jb left_2 - - mov [ptr1], m - mov m, [cp_r + 4] - lea ptr1, [cp_r + 4] - mov len1, len - - jmp max_update - -MY_ALIGN_32 -left_2: - mov [ptr0], m - mov m, [cp_r] - mov ptr0, cp_r - mov len0, len - -max_update: - sub diff, cur ; restore diff - - cmp maxLen, len - jae next_node - - mov maxLen, len - add len, lenLimit - mov [d], len_x - mov t0_x, diff_x - not t0_x - mov [d + 4], t0_x - add d, 8 - - jmp next_node - - - -MY_ALIGN_32 -lenLimit_reach: - - mov delta_r, cur - sub delta_r, diff - lea delta1_r, [delta_r - 1] - - mov t0_x, [cp_r] - mov [ptr1], t0_x - mov t0_x, [cp_r + 4] - mov [ptr0], t0_x - - mov [d], lenLimit_x - mov [d + 4], delta1_x - add d, 8 - - ; _distances[-1] = (UInt32)(d - _distances); - mov t0, distances - mov t1, d - sub t1, t0 - shr t1_x, 2 - mov [t0 - 4], t1_x - - mov hash, hash_VAR - mov hash_lim, size_VAR - - inc pos - mov cp_x, cycPos_VAR - inc cp_x - - mov d_lim, limit_VAR - mov cycSize, cycSize_VAR - ; if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) - ; break; - cmp hash, hash_lim - je fin - cmp d, d_lim - jae fin - cmp delta_x, [hash] - jne main_loop - movzx t0_x, BYTE PTR [diff] - cmp [cur], t0_L - jne main_loop - - ; jmp main_loop ; bypass for debug - - mov cycPos_VAR, cp_x - shl len, 3 ; cycSize * 8 - sub diff, cur ; restore diff - xor t0_x, t0_x - cmp cp_x, delta_x ; cmp (cycPos_VAR, delta) - lea cp_r, [son + 8 * cp_r] ; dest - lea src, [cp_r + 8 * diff] - cmovb t0, len ; t0 = (cycPos_VAR < delta ? cycSize * 8 : 0) - add src, t0 - add len, son ; len = son + cycSize * 8 - - -MY_ALIGN_32 -long_loop: - add hash, 4 - - ; *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff]; - - mov t0, [src] - add src, 8 - mov [cp_r], t0 - add cp_r, 8 - cmp src, len - cmove src, son ; if end of (son) buffer is reached, we wrap to begin - - mov DWORD PTR [d], 2 - mov [d + 4], lenLimit_x - mov [d + 8], delta1_x - add d, 12 - - inc cur - - cmp hash, hash_lim - je long_footer - cmp delta_x, [hash] - jne long_footer - movzx t0_x, BYTE PTR [diff + 1 * cur] - cmp [cur], t0_L - jne long_footer - cmp d, d_lim - jb long_loop - -long_footer: - sub cp_r, son - shr cp_r, 3 - add pos, cp_x - sub pos, cycPos_VAR - mov cycSize, cycSize_VAR - - cmp d, d_lim - jae fin - cmp hash, hash_lim - jne main_loop - jmp fin - - - -fin_error: - xor d, d - -fin: - mov RSP, Old_RSP - mov t0, [r4 + posRes_OFFS] - mov [t0], pos - mov r0, d - -MY_POP_PRESERVED_ABI_REGS -MY_ENDP - -ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT -_TEXT$LZFINDOPT ENDS -endif - -end +; LzFindOpt.asm -- ASM version of GetMatchesSpecN_2() function +; 2024-06-18: Igor Pavlov : Public domain +; + +ifndef x64 +; x64=1 +; .err +endif + +include 7zAsm.asm + +MY_ASM_START + +ifndef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT +if (IS_LINUX gt 0) + Z7_LZ_FIND_OPT_ASM_USE_SEGMENT equ 1 +else + Z7_LZ_FIND_OPT_ASM_USE_SEGMENT equ 1 +endif +endif + +ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT +_TEXT$LZFINDOPT SEGMENT ALIGN(64) 'CODE' +MY_ALIGN macro num:req + align num + ; align 16 +endm +else +MY_ALIGN macro num:req + ; We expect that ".text" is aligned for 16-bytes. + ; So we don't need large alignment inside our function. + align 16 +endm +endif + + +MY_ALIGN_16 macro + MY_ALIGN 16 +endm + +MY_ALIGN_32 macro + MY_ALIGN 32 +endm + +MY_ALIGN_64 macro + MY_ALIGN 64 +endm + + +t0_L equ x0_L +t0_x equ x0 +t0 equ r0 +t1_x equ x3 +t1 equ r3 + +cp_x equ t1_x +cp_r equ t1 +m equ x5 +m_r equ r5 +len_x equ x6 +len equ r6 +diff_x equ x7 +diff equ r7 +len0 equ r10 +len1_x equ x11 +len1 equ r11 +maxLen_x equ x12 +maxLen equ r12 +d equ r13 +ptr0 equ r14 +ptr1 equ r15 + +d_lim equ m_r +cycSize equ len_x +hash_lim equ len0 +delta1_x equ len1_x +delta1_r equ len1 +delta_x equ maxLen_x +delta_r equ maxLen +hash equ ptr0 +src equ ptr1 + + + +if (IS_LINUX gt 0) + +; r1 r2 r8 r9 : win32 +; r7 r6 r2 r1 r8 r9 : linux + +lenLimit equ r8 +lenLimit_x equ x8 +; pos_r equ r2 +pos equ x2 +cur equ r1 +son equ r9 + +else + +lenLimit equ REG_ABI_PARAM_2 +lenLimit_x equ REG_ABI_PARAM_2_x +pos equ REG_ABI_PARAM_1_x +cur equ REG_ABI_PARAM_0 +son equ REG_ABI_PARAM_3 + +endif + + +if (IS_LINUX gt 0) + maxLen_OFFS equ (REG_SIZE * (6 + 1)) +else + cutValue_OFFS equ (REG_SIZE * (8 + 1 + 4)) + d_OFFS equ (REG_SIZE + cutValue_OFFS) + maxLen_OFFS equ (REG_SIZE + d_OFFS) +endif + hash_OFFS equ (REG_SIZE + maxLen_OFFS) + limit_OFFS equ (REG_SIZE + hash_OFFS) + size_OFFS equ (REG_SIZE + limit_OFFS) + cycPos_OFFS equ (REG_SIZE + size_OFFS) + cycSize_OFFS equ (REG_SIZE + cycPos_OFFS) + posRes_OFFS equ (REG_SIZE + cycSize_OFFS) + +if (IS_LINUX gt 0) +else + cutValue_PAR equ [r0 + cutValue_OFFS] + d_PAR equ [r0 + d_OFFS] +endif + maxLen_PAR equ [r0 + maxLen_OFFS] + hash_PAR equ [r0 + hash_OFFS] + limit_PAR equ [r0 + limit_OFFS] + size_PAR equ [r0 + size_OFFS] + cycPos_PAR equ [r0 + cycPos_OFFS] + cycSize_PAR equ [r0 + cycSize_OFFS] + posRes_PAR equ [r0 + posRes_OFFS] + + + cutValue_VAR equ DWORD PTR [r4 + 8 * 0] + cutValueCur_VAR equ DWORD PTR [r4 + 8 * 0 + 4] + cycPos_VAR equ DWORD PTR [r4 + 8 * 1 + 0] + cycSize_VAR equ DWORD PTR [r4 + 8 * 1 + 4] + hash_VAR equ QWORD PTR [r4 + 8 * 2] + limit_VAR equ QWORD PTR [r4 + 8 * 3] + size_VAR equ QWORD PTR [r4 + 8 * 4] + distances equ QWORD PTR [r4 + 8 * 5] + maxLen_VAR equ QWORD PTR [r4 + 8 * 6] + + Old_RSP equ QWORD PTR [r4 + 8 * 7] + LOCAL_SIZE equ 8 * 8 + +COPY_VAR_32 macro dest_var, src_var + mov x3, src_var + mov dest_var, x3 +endm + +COPY_VAR_64 macro dest_var, src_var + mov r3, src_var + mov dest_var, r3 +endm + + +ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT +; MY_ALIGN_64 +else + MY_ALIGN_16 +endif +MY_PROC GetMatchesSpecN_2, 13 +MY_PUSH_PRESERVED_ABI_REGS + mov r0, RSP + lea r3, [r0 - LOCAL_SIZE] + and r3, -64 + mov RSP, r3 + mov Old_RSP, r0 + +if (IS_LINUX gt 0) + mov d, REG_ABI_PARAM_5 ; r13 = r9 + mov cutValue_VAR, REG_ABI_PARAM_4_x ; = r8 + mov son, REG_ABI_PARAM_3 ; r9 = r1 + mov r8, REG_ABI_PARAM_2 ; r8 = r2 + mov pos, REG_ABI_PARAM_1_x ; r2 = x6 + mov r1, REG_ABI_PARAM_0 ; r1 = r7 +else + COPY_VAR_32 cutValue_VAR, cutValue_PAR + mov d, d_PAR +endif + + COPY_VAR_64 limit_VAR, limit_PAR + + mov hash_lim, size_PAR + mov size_VAR, hash_lim + + mov cp_x, cycPos_PAR + mov hash, hash_PAR + + mov cycSize, cycSize_PAR + mov cycSize_VAR, cycSize + + ; we want cur in (rcx). So we change the cur and lenLimit variables + sub lenLimit, cur + neg lenLimit_x + inc lenLimit_x + + mov t0_x, maxLen_PAR + sub t0, lenLimit + mov maxLen_VAR, t0 + + jmp main_loop + +MY_ALIGN_64 +fill_empty: + ; ptr0 = *ptr1 = kEmptyHashValue; + mov QWORD PTR [ptr1], 0 + inc pos + inc cp_x + mov DWORD PTR [d - 4], 0 + cmp d, limit_VAR + jae fin + cmp hash, hash_lim + je fin + +; MY_ALIGN_64 +main_loop: + ; UInt32 delta = *hash++; + mov diff_x, [hash] ; delta + add hash, 4 + ; mov cycPos_VAR, cp_x + + inc cur + add d, 4 + mov m, pos + sub m, diff_x; ; matchPos + + ; CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + lea ptr1, [son + 8 * cp_r] + ; mov cycSize, cycSize_VAR + cmp pos, cycSize + jb directMode ; if (pos < cycSize_VAR) + + ; CYC MODE + + cmp diff_x, cycSize + jae fill_empty ; if (delta >= cycSize_VAR) + + xor t0_x, t0_x + mov cycPos_VAR, cp_x + sub cp_x, diff_x + ; jae prepare_for_tree_loop + ; add cp_x, cycSize + cmovb t0_x, cycSize + add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0) + jmp prepare_for_tree_loop + + +directMode: + cmp diff_x, pos + je fill_empty ; if (delta == pos) + jae fin_error ; if (delta >= pos) + + mov cycPos_VAR, cp_x + mov cp_x, m + +prepare_for_tree_loop: + mov len0, lenLimit + mov hash_VAR, hash + ; CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1; + lea ptr0, [ptr1 + 4] + ; UInt32 *_distances = ++d; + mov distances, d + + neg len0 + mov len1, len0 + + mov t0_x, cutValue_VAR + mov maxLen, maxLen_VAR + mov cutValueCur_VAR, t0_x + +MY_ALIGN_32 +tree_loop: + neg diff + mov len, len0 + cmp len1, len0 + cmovb len, len1 ; len = (len1 < len0 ? len1 : len0); + add diff, cur + + mov t0_x, [son + cp_r * 8] ; prefetch + movzx t0_x, BYTE PTR [diff + 1 * len] + lea cp_r, [son + cp_r * 8] + cmp [cur + 1 * len], t0_L + je matched_1 + + jb left_0 + + mov [ptr1], m + mov m, [cp_r + 4] + lea ptr1, [cp_r + 4] + sub diff, cur ; FIX32 + jmp next_node + +MY_ALIGN_32 +left_0: + mov [ptr0], m + mov m, [cp_r] + mov ptr0, cp_r + sub diff, cur ; FIX32 + ; jmp next_node + +; ------------ NEXT NODE ------------ +; MY_ALIGN_32 +next_node: + mov cycSize, cycSize_VAR + dec cutValueCur_VAR + je finish_tree + + add diff_x, pos ; prev_match = pos + diff + cmp m, diff_x + jae fin_error ; if (new_match >= prev_match) + + mov diff_x, pos + sub diff_x, m ; delta = pos - new_match + cmp pos, cycSize + jae cyc_mode_2 ; if (pos >= cycSize) + + mov cp_x, m + test m, m + jne tree_loop ; if (m != 0) + +finish_tree: + ; ptr0 = *ptr1 = kEmptyHashValue; + mov DWORD PTR [ptr0], 0 + mov DWORD PTR [ptr1], 0 + + inc pos + + ; _distances[-1] = (UInt32)(d - _distances); + mov t0, distances + mov t1, d + sub t1, t0 + shr t1_x, 2 + mov [t0 - 4], t1_x + + cmp d, limit_VAR + jae fin ; if (d >= limit) + + mov cp_x, cycPos_VAR + mov hash, hash_VAR + mov hash_lim, size_VAR + inc cp_x + cmp hash, hash_lim + jne main_loop ; if (hash != size) + jmp fin + + +MY_ALIGN_32 +cyc_mode_2: + cmp diff_x, cycSize + jae finish_tree ; if (delta >= cycSize) + + mov cp_x, cycPos_VAR + xor t0_x, t0_x + sub cp_x, diff_x ; cp_x = cycPos - delta + cmovb t0_x, cycSize + add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0) + jmp tree_loop + + +MY_ALIGN_32 +matched_1: + + inc len + ; cmp len_x, lenLimit_x + je short lenLimit_reach + movzx t0_x, BYTE PTR [diff + 1 * len] + cmp [cur + 1 * len], t0_L + jne mismatch + + +MY_ALIGN_32 +match_loop: + ; while (++len != lenLimit) (len[diff] != len[0]) ; + + inc len + ; cmp len_x, lenLimit_x + je short lenLimit_reach + movzx t0_x, BYTE PTR [diff + 1 * len] + cmp BYTE PTR [cur + 1 * len], t0_L + je match_loop + +mismatch: + jb left_2 + + mov [ptr1], m + mov m, [cp_r + 4] + lea ptr1, [cp_r + 4] + mov len1, len + + jmp max_update + +MY_ALIGN_32 +left_2: + mov [ptr0], m + mov m, [cp_r] + mov ptr0, cp_r + mov len0, len + +max_update: + sub diff, cur ; restore diff + + cmp maxLen, len + jae next_node + + mov maxLen, len + add len, lenLimit + mov [d], len_x + mov t0_x, diff_x + not t0_x + mov [d + 4], t0_x + add d, 8 + + jmp next_node + + + +MY_ALIGN_32 +lenLimit_reach: + + mov delta_r, cur + sub delta_r, diff + lea delta1_r, [delta_r - 1] + + mov t0_x, [cp_r] + mov [ptr1], t0_x + mov t0_x, [cp_r + 4] + mov [ptr0], t0_x + + mov [d], lenLimit_x + mov [d + 4], delta1_x + add d, 8 + + ; _distances[-1] = (UInt32)(d - _distances); + mov t0, distances + mov t1, d + sub t1, t0 + shr t1_x, 2 + mov [t0 - 4], t1_x + + mov hash, hash_VAR + mov hash_lim, size_VAR + + inc pos + mov cp_x, cycPos_VAR + inc cp_x + + mov d_lim, limit_VAR + mov cycSize, cycSize_VAR + ; if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + ; break; + cmp hash, hash_lim + je fin + cmp d, d_lim + jae fin + cmp delta_x, [hash] + jne main_loop + movzx t0_x, BYTE PTR [diff] + cmp [cur], t0_L + jne main_loop + + ; jmp main_loop ; bypass for debug + + mov cycPos_VAR, cp_x + shl len, 3 ; cycSize * 8 + sub diff, cur ; restore diff + xor t0_x, t0_x + cmp cp_x, delta_x ; cmp (cycPos_VAR, delta) + lea cp_r, [son + 8 * cp_r] ; dest + lea src, [cp_r + 8 * diff] + cmovb t0, len ; t0 = (cycPos_VAR < delta ? cycSize * 8 : 0) + add src, t0 + add len, son ; len = son + cycSize * 8 + + +MY_ALIGN_32 +long_loop: + add hash, 4 + + ; *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff]; + + mov t0, [src] + add src, 8 + mov [cp_r], t0 + add cp_r, 8 + cmp src, len + cmove src, son ; if end of (son) buffer is reached, we wrap to begin + + mov DWORD PTR [d], 2 + mov [d + 4], lenLimit_x + mov [d + 8], delta1_x + add d, 12 + + inc cur + + cmp hash, hash_lim + je long_footer + cmp delta_x, [hash] + jne long_footer + movzx t0_x, BYTE PTR [diff + 1 * cur] + cmp [cur], t0_L + jne long_footer + cmp d, d_lim + jb long_loop + +long_footer: + sub cp_r, son + shr cp_r, 3 + add pos, cp_x + sub pos, cycPos_VAR + mov cycSize, cycSize_VAR + + cmp d, d_lim + jae fin + cmp hash, hash_lim + jne main_loop + jmp fin + + + +fin_error: + xor d, d + +fin: + mov RSP, Old_RSP + mov t0, [r4 + posRes_OFFS] + mov [t0], pos + mov r0, d + +MY_POP_PRESERVED_ABI_REGS +MY_ENDP + +ifdef Z7_LZ_FIND_OPT_ASM_USE_SEGMENT +_TEXT$LZFINDOPT ENDS +endif + +end diff --git a/Asm/x86/LzmaDecOpt.asm b/Asm/x86/LzmaDecOpt.asm index 7a3fdfd3f..7c568df1d 100644 --- a/Asm/x86/LzmaDecOpt.asm +++ b/Asm/x86/LzmaDecOpt.asm @@ -1,1339 +1,1339 @@ -; LzmaDecOpt.asm -- ASM version of LzmaDec_DecodeReal_3() function -; 2024-06-18: Igor Pavlov : Public domain -; -; 3 - is the code compatibility version of LzmaDec_DecodeReal_*() -; function for check at link time. -; That code is tightly coupled with LzmaDec_TryDummy() -; and with another functions in LzmaDec.c file. -; CLzmaDec structure, (probs) array layout, input and output of -; LzmaDec_DecodeReal_*() must be equal in both versions (C / ASM). - -ifndef x64 -; x64=1 -; .err -endif - -include 7zAsm.asm - -MY_ASM_START - -; if Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT is defined, we use additional SEGMENT with 64-byte alignment. -; if Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT is not defined, we use default SEGMENT (where default 16-byte alignment of segment is expected). -; The performance is almost identical in our tests. -; But the performance can depend from position of lzmadec code inside instruction cache -; or micro-op cache line (depending from low address bits in 32-byte/64-byte cache lines). -; And 64-byte alignment provides a more consistent speed regardless -; of the code's position in the executable. -; But also it's possible that code without Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT can be -; slightly faster than 64-bytes aligned code in some cases, if offset of lzmadec -; code in 64-byte block after compilation provides better speed by some reason. -; Note that Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT adds an extra section to the ELF file. -; If you don't want to get that extra section, do not define Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT. - -ifndef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT -if (IS_LINUX gt 0) - Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT equ 1 -else - Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT equ 1 -endif -endif - -ifdef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT -_TEXT$LZMADECOPT SEGMENT ALIGN(64) 'CODE' -MY_ALIGN macro num:req - align num - ; align 16 -endm -else -MY_ALIGN macro num:req - ; We expect that ".text" is aligned for 16-bytes. - ; So we don't need large alignment inside out function. - align 16 -endm -endif - - -MY_ALIGN_16 macro - MY_ALIGN 16 -endm - -MY_ALIGN_32 macro - MY_ALIGN 32 -endm - -MY_ALIGN_64 macro - MY_ALIGN 64 -endm - - -; _LZMA_SIZE_OPT equ 1 - -; _LZMA_PROB32 equ 1 - -ifdef _LZMA_PROB32 - PSHIFT equ 2 - PLOAD macro dest, mem - mov dest, dword ptr [mem] - endm - PSTORE macro src, mem - mov dword ptr [mem], src - endm -else - PSHIFT equ 1 - PLOAD macro dest, mem - movzx dest, word ptr [mem] - endm - PSTORE macro src, mem - mov word ptr [mem], @CatStr(src, _W) - endm -endif - -PMULT equ (1 SHL PSHIFT) -PMULT_HALF equ (1 SHL (PSHIFT - 1)) -PMULT_2 equ (1 SHL (PSHIFT + 1)) - -kMatchSpecLen_Error_Data equ (1 SHL 9) - -; x0 range -; x1 pbPos / (prob) TREE -; x2 probBranch / prm (MATCHED) / pbPos / cnt -; x3 sym -;====== r4 === RSP -; x5 cod -; x6 t1 NORM_CALC / probs_state / dist -; x7 t0 NORM_CALC / prob2 IF_BIT_1 -; x8 state -; x9 match (MATCHED) / sym2 / dist2 / lpMask_reg -; x10 kBitModelTotal_reg -; r11 probs -; x12 offs (MATCHED) / dic / len_temp -; x13 processedPos -; x14 bit (MATCHED) / dicPos -; r15 buf - - -cod equ x5 -cod_L equ x5_L -range equ x0 -state equ x8 -state_R equ r8 -buf equ r15 -processedPos equ x13 -kBitModelTotal_reg equ x10 - -probBranch equ x2 -probBranch_R equ r2 -probBranch_W equ x2_W - -pbPos equ x1 -pbPos_R equ r1 - -cnt equ x2 -cnt_R equ r2 - -lpMask_reg equ x9 -dicPos equ r14 - -sym equ x3 -sym_R equ r3 -sym_L equ x3_L - -probs equ r11 -dic equ r12 - -t0 equ x7 -t0_W equ x7_W -t0_R equ r7 - -prob2 equ t0 -prob2_W equ t0_W - -t1 equ x6 -t1_R equ r6 - -probs_state equ t1 -probs_state_R equ t1_R - -prm equ r2 -match equ x9 -match_R equ r9 -offs equ x12 -offs_R equ r12 -bit equ x14 -bit_R equ r14 - -sym2 equ x9 -sym2_R equ r9 - -len_temp equ x12 - -dist equ sym -dist2 equ x9 - - - -kNumBitModelTotalBits equ 11 -kBitModelTotal equ (1 SHL kNumBitModelTotalBits) -kNumMoveBits equ 5 -kBitModelOffset equ ((1 SHL kNumMoveBits) - 1) -kTopValue equ (1 SHL 24) - -NORM_2 macro - ; movzx t0, BYTE PTR [buf] - shl cod, 8 - mov cod_L, BYTE PTR [buf] - shl range, 8 - ; or cod, t0 - inc buf -endm - - -NORM macro - cmp range, kTopValue - jae SHORT @F - NORM_2 -@@: -endm - - -; ---------- Branch MACROS ---------- - -UPDATE_0 macro probsArray:req, probOffset:req, probDisp:req - mov prob2, kBitModelTotal_reg - sub prob2, probBranch - shr prob2, kNumMoveBits - add probBranch, prob2 - PSTORE probBranch, probOffset * 1 + probsArray + probDisp * PMULT -endm - - -UPDATE_1 macro probsArray:req, probOffset:req, probDisp:req - sub prob2, range - sub cod, range - mov range, prob2 - mov prob2, probBranch - shr probBranch, kNumMoveBits - sub prob2, probBranch - PSTORE prob2, probOffset * 1 + probsArray + probDisp * PMULT -endm - - -CMP_COD macro probsArray:req, probOffset:req, probDisp:req - PLOAD probBranch, probOffset * 1 + probsArray + probDisp * PMULT - NORM - mov prob2, range - shr range, kNumBitModelTotalBits - imul range, probBranch - cmp cod, range -endm - - -IF_BIT_1_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req - CMP_COD probsArray, probOffset, probDisp - jae toLabel -endm - - -IF_BIT_1 macro probsArray:req, probOffset:req, probDisp:req, toLabel:req - IF_BIT_1_NOUP probsArray, probOffset, probDisp, toLabel - UPDATE_0 probsArray, probOffset, probDisp -endm - - -IF_BIT_0_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req - CMP_COD probsArray, probOffset, probDisp - jb toLabel -endm - - -; ---------- CMOV MACROS ---------- - -NORM_CALC macro prob:req - NORM - mov t0, range - shr range, kNumBitModelTotalBits - imul range, prob - sub t0, range - mov t1, cod - sub cod, range -endm - - -PUP macro prob:req, probPtr:req - sub t0, prob - ; only sar works for both 16/32 bit prob modes - sar t0, kNumMoveBits - add t0, prob - PSTORE t0, probPtr -endm - - -PUP_SUB macro prob:req, probPtr:req, symSub:req - sbb sym, symSub - PUP prob, probPtr -endm - - -PUP_COD macro prob:req, probPtr:req, symSub:req - mov t0, kBitModelOffset - cmovb cod, t1 - mov t1, sym - cmovb t0, kBitModelTotal_reg - PUP_SUB prob, probPtr, symSub -endm - - -BIT_0 macro prob:req, probNext:req - PLOAD prob, probs + 1 * PMULT - PLOAD probNext, probs + 1 * PMULT_2 - - NORM_CALC prob - - cmovae range, t0 - PLOAD t0, probs + 1 * PMULT_2 + PMULT - cmovae probNext, t0 - mov t0, kBitModelOffset - cmovb cod, t1 - cmovb t0, kBitModelTotal_reg - mov sym, 2 - PUP_SUB prob, probs + 1 * PMULT, 0 - 1 -endm - - -BIT_1 macro prob:req, probNext:req - PLOAD probNext, probs + sym_R * PMULT_2 - add sym, sym - - NORM_CALC prob - - cmovae range, t0 - PLOAD t0, probs + sym_R * PMULT + PMULT - cmovae probNext, t0 - PUP_COD prob, probs + t1_R * PMULT_HALF, 0 - 1 -endm - - -BIT_2 macro prob:req, symSub:req - add sym, sym - - NORM_CALC prob - - cmovae range, t0 - PUP_COD prob, probs + t1_R * PMULT_HALF, symSub -endm - - -; ---------- MATCHED LITERAL ---------- - -LITM_0 macro - mov offs, 256 * PMULT - shl match, (PSHIFT + 1) - mov bit, offs - and bit, match - PLOAD x1, probs + 256 * PMULT + bit_R * 1 + 1 * PMULT - lea prm, [probs + 256 * PMULT + bit_R * 1 + 1 * PMULT] - ; lea prm, [probs + 256 * PMULT + 1 * PMULT] - ; add prm, bit_R - xor offs, bit - add match, match - - NORM_CALC x1 - - cmovae offs, bit - mov bit, match - cmovae range, t0 - mov t0, kBitModelOffset - cmovb cod, t1 - cmovb t0, kBitModelTotal_reg - mov sym, 0 - PUP_SUB x1, prm, -2-1 -endm - - -LITM macro - and bit, offs - lea prm, [probs + offs_R * 1] - add prm, bit_R - PLOAD x1, prm + sym_R * PMULT - xor offs, bit - add sym, sym - add match, match - - NORM_CALC x1 - - cmovae offs, bit - mov bit, match - cmovae range, t0 - PUP_COD x1, prm + t1_R * PMULT_HALF, - 1 -endm - - -LITM_2 macro - and bit, offs - lea prm, [probs + offs_R * 1] - add prm, bit_R - PLOAD x1, prm + sym_R * PMULT - add sym, sym - - NORM_CALC x1 - - cmovae range, t0 - PUP_COD x1, prm + t1_R * PMULT_HALF, 256 - 1 -endm - - -; ---------- REVERSE BITS ---------- - -REV_0 macro prob:req, probNext:req - ; PLOAD prob, probs + 1 * PMULT - ; lea sym2_R, [probs + 2 * PMULT] - ; PLOAD probNext, probs + 2 * PMULT - PLOAD probNext, sym2_R - - NORM_CALC prob - - cmovae range, t0 - PLOAD t0, probs + 3 * PMULT - cmovae probNext, t0 - cmovb cod, t1 - mov t0, kBitModelOffset - cmovb t0, kBitModelTotal_reg - lea t1_R, [probs + 3 * PMULT] - cmovae sym2_R, t1_R - PUP prob, probs + 1 * PMULT -endm - - -REV_1 macro prob:req, probNext:req, step:req - add sym2_R, step * PMULT - PLOAD probNext, sym2_R - - NORM_CALC prob - - cmovae range, t0 - PLOAD t0, sym2_R + step * PMULT - cmovae probNext, t0 - cmovb cod, t1 - mov t0, kBitModelOffset - cmovb t0, kBitModelTotal_reg - lea t1_R, [sym2_R + step * PMULT] - cmovae sym2_R, t1_R - PUP prob, t1_R - step * PMULT_2 -endm - - -REV_2 macro prob:req, step:req - sub sym2_R, probs - shr sym2, PSHIFT - or sym, sym2 - - NORM_CALC prob - - cmovae range, t0 - lea t0, [sym - step] - cmovb sym, t0 - cmovb cod, t1 - mov t0, kBitModelOffset - cmovb t0, kBitModelTotal_reg - PUP prob, probs + sym2_R * PMULT -endm - - -REV_1_VAR macro prob:req - PLOAD prob, sym_R - mov probs, sym_R - add sym_R, sym2_R - - NORM_CALC prob - - cmovae range, t0 - lea t0_R, [sym_R + 1 * sym2_R] - cmovae sym_R, t0_R - mov t0, kBitModelOffset - cmovb cod, t1 - ; mov t1, kBitModelTotal - ; cmovb t0, t1 - cmovb t0, kBitModelTotal_reg - add sym2, sym2 - PUP prob, probs -endm - - - - -LIT_PROBS macro lpMaskParam:req - ; prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); - mov t0, processedPos - shl t0, 8 - add sym, t0 - and sym, lpMaskParam - add probs_state_R, pbPos_R - mov x1, LOC lc2 - lea sym, dword ptr[sym_R + 2 * sym_R] - add probs, Literal * PMULT - shl sym, x1_L - add probs, sym_R - UPDATE_0 probs_state_R, 0, IsMatch - inc processedPos -endm - - - -kNumPosBitsMax equ 4 -kNumPosStatesMax equ (1 SHL kNumPosBitsMax) - -kLenNumLowBits equ 3 -kLenNumLowSymbols equ (1 SHL kLenNumLowBits) -kLenNumHighBits equ 8 -kLenNumHighSymbols equ (1 SHL kLenNumHighBits) -kNumLenProbs equ (2 * kLenNumLowSymbols * kNumPosStatesMax + kLenNumHighSymbols) - -LenLow equ 0 -LenChoice equ LenLow -LenChoice2 equ (LenLow + kLenNumLowSymbols) -LenHigh equ (LenLow + 2 * kLenNumLowSymbols * kNumPosStatesMax) - -kNumStates equ 12 -kNumStates2 equ 16 -kNumLitStates equ 7 - -kStartPosModelIndex equ 4 -kEndPosModelIndex equ 14 -kNumFullDistances equ (1 SHL (kEndPosModelIndex SHR 1)) - -kNumPosSlotBits equ 6 -kNumLenToPosStates equ 4 - -kNumAlignBits equ 4 -kAlignTableSize equ (1 SHL kNumAlignBits) - -kMatchMinLen equ 2 -kMatchSpecLenStart equ (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) - -kStartOffset equ 1664 -SpecPos equ (-kStartOffset) -IsRep0Long equ (SpecPos + kNumFullDistances) -RepLenCoder equ (IsRep0Long + (kNumStates2 SHL kNumPosBitsMax)) -LenCoder equ (RepLenCoder + kNumLenProbs) -IsMatch equ (LenCoder + kNumLenProbs) -kAlign equ (IsMatch + (kNumStates2 SHL kNumPosBitsMax)) -IsRep equ (kAlign + kAlignTableSize) -IsRepG0 equ (IsRep + kNumStates) -IsRepG1 equ (IsRepG0 + kNumStates) -IsRepG2 equ (IsRepG1 + kNumStates) -PosSlot equ (IsRepG2 + kNumStates) -Literal equ (PosSlot + (kNumLenToPosStates SHL kNumPosSlotBits)) -NUM_BASE_PROBS equ (Literal + kStartOffset) - -if kAlign ne 0 - .err -endif - -if NUM_BASE_PROBS ne 1984 - .err -endif - - -PTR_FIELD equ dq ? - -CLzmaDec_Asm struct - lc db ? - lp db ? - pb db ? - _pad_ db ? - dicSize dd ? - - probs_Spec PTR_FIELD - probs_1664 PTR_FIELD - dic_Spec PTR_FIELD - dicBufSize PTR_FIELD - dicPos_Spec PTR_FIELD - buf_Spec PTR_FIELD - - range_Spec dd ? - code_Spec dd ? - processedPos_Spec dd ? - checkDicSize dd ? - rep0 dd ? - rep1 dd ? - rep2 dd ? - rep3 dd ? - state_Spec dd ? - remainLen dd ? -CLzmaDec_Asm ends - - -CLzmaDec_Asm_Loc struct - OLD_RSP PTR_FIELD - lzmaPtr PTR_FIELD - _pad0_ PTR_FIELD - _pad1_ PTR_FIELD - _pad2_ PTR_FIELD - dicBufSize PTR_FIELD - probs_Spec PTR_FIELD - dic_Spec PTR_FIELD - - limit PTR_FIELD - bufLimit PTR_FIELD - lc2 dd ? - lpMask dd ? - pbMask dd ? - checkDicSize dd ? - - _pad_ dd ? - remainLen dd ? - dicPos_Spec PTR_FIELD - rep0 dd ? - rep1 dd ? - rep2 dd ? - rep3 dd ? -CLzmaDec_Asm_Loc ends - - -GLOB_2 equ [sym_R].CLzmaDec_Asm. -GLOB equ [r1].CLzmaDec_Asm. -LOC_0 equ [r0].CLzmaDec_Asm_Loc. -LOC equ [RSP].CLzmaDec_Asm_Loc. - - -COPY_VAR macro name - mov t0, GLOB_2 name - mov LOC_0 name, t0 -endm - - -RESTORE_VAR macro name - mov t0, LOC name - mov GLOB name, t0 -endm - - - -IsMatchBranch_Pre macro reg - ; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; - mov pbPos, LOC pbMask - and pbPos, processedPos - shl pbPos, (kLenNumLowBits + 1 + PSHIFT) - lea probs_state_R, [probs + 1 * state_R] -endm - - -IsMatchBranch macro reg - IsMatchBranch_Pre - IF_BIT_1 probs_state_R, pbPos_R, IsMatch, IsMatch_label -endm - - -CheckLimits macro reg - cmp buf, LOC bufLimit - jae fin_OK - cmp dicPos, LOC limit - jae fin_OK -endm - - - -; RSP is (16x + 8) bytes aligned in WIN64-x64 -; LocalSize equ ((((SIZEOF CLzmaDec_Asm_Loc) + 7) / 16 * 16) + 8) - -PARAM_lzma equ REG_ABI_PARAM_0 -PARAM_limit equ REG_ABI_PARAM_1 -PARAM_bufLimit equ REG_ABI_PARAM_2 - -ifdef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT -; MY_ALIGN_64 -else - MY_ALIGN_16 -endif -MY_PROC LzmaDec_DecodeReal_3, 3 -MY_PUSH_PRESERVED_ABI_REGS - - lea r0, [RSP - (SIZEOF CLzmaDec_Asm_Loc)] - and r0, -128 - mov r5, RSP - mov RSP, r0 - mov LOC_0 Old_RSP, r5 - mov LOC_0 lzmaPtr, PARAM_lzma - - mov LOC_0 remainLen, 0 ; remainLen must be ZERO - - mov LOC_0 bufLimit, PARAM_bufLimit - mov sym_R, PARAM_lzma ; CLzmaDec_Asm_Loc pointer for GLOB_2 - mov dic, GLOB_2 dic_Spec - add PARAM_limit, dic - mov LOC_0 limit, PARAM_limit - - COPY_VAR(rep0) - COPY_VAR(rep1) - COPY_VAR(rep2) - COPY_VAR(rep3) - - mov dicPos, GLOB_2 dicPos_Spec - add dicPos, dic - mov LOC_0 dicPos_Spec, dicPos - mov LOC_0 dic_Spec, dic - - mov x1_L, GLOB_2 pb - mov t0, 1 - shl t0, x1_L - dec t0 - mov LOC_0 pbMask, t0 - - ; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; - ; unsigned lc = p->prop.lc; - ; unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); - - mov x1_L, GLOB_2 lc - mov x2, 100h - mov t0, x2 - shr x2, x1_L - ; inc x1 - add x1_L, PSHIFT - mov LOC_0 lc2, x1 - mov x1_L, GLOB_2 lp - shl t0, x1_L - sub t0, x2 - mov LOC_0 lpMask, t0 - mov lpMask_reg, t0 - - ; mov probs, GLOB_2 probs_Spec - ; add probs, kStartOffset SHL PSHIFT - mov probs, GLOB_2 probs_1664 - mov LOC_0 probs_Spec, probs - - mov t0_R, GLOB_2 dicBufSize - mov LOC_0 dicBufSize, t0_R - - mov x1, GLOB_2 checkDicSize - mov LOC_0 checkDicSize, x1 - - mov processedPos, GLOB_2 processedPos_Spec - - mov state, GLOB_2 state_Spec - shl state, PSHIFT - - mov buf, GLOB_2 buf_Spec - mov range, GLOB_2 range_Spec - mov cod, GLOB_2 code_Spec - mov kBitModelTotal_reg, kBitModelTotal - xor sym, sym - - ; if (processedPos != 0 || checkDicSize != 0) - or x1, processedPos - jz @f - - add t0_R, dic - cmp dicPos, dic - cmovnz t0_R, dicPos - movzx sym, byte ptr[t0_R - 1] - -@@: - IsMatchBranch_Pre - cmp state, 4 * PMULT - jb lit_end - cmp state, kNumLitStates * PMULT - jb lit_matched_end - jmp lz_end - - - - -; ---------- LITERAL ---------- -MY_ALIGN_64 -lit_start: - xor state, state -lit_start_2: - LIT_PROBS lpMask_reg - - ifdef _LZMA_SIZE_OPT - - PLOAD x1, probs + 1 * PMULT - mov sym, 1 -MY_ALIGN_16 -lit_loop: - BIT_1 x1, x2 - mov x1, x2 - cmp sym, 127 - jbe lit_loop - - else - - BIT_0 x1, x2 - BIT_1 x2, x1 - BIT_1 x1, x2 - BIT_1 x2, x1 - BIT_1 x1, x2 - BIT_1 x2, x1 - BIT_1 x1, x2 - - endif - - BIT_2 x2, 256 - 1 - - ; mov dic, LOC dic_Spec - mov probs, LOC probs_Spec - IsMatchBranch_Pre - mov byte ptr[dicPos], sym_L - inc dicPos - - CheckLimits -lit_end: - IF_BIT_0_NOUP probs_state_R, pbPos_R, IsMatch, lit_start - - ; jmp IsMatch_label - -; ---------- MATCHES ---------- -; MY_ALIGN_32 -IsMatch_label: - UPDATE_1 probs_state_R, pbPos_R, IsMatch - IF_BIT_1 probs_state_R, 0, IsRep, IsRep_label - - add probs, LenCoder * PMULT - add state, kNumStates * PMULT - -; ---------- LEN DECODE ---------- -len_decode: - mov len_temp, 8 - 1 - kMatchMinLen - IF_BIT_0_NOUP probs, 0, 0, len_mid_0 - UPDATE_1 probs, 0, 0 - add probs, (1 SHL (kLenNumLowBits + PSHIFT)) - mov len_temp, -1 - kMatchMinLen - IF_BIT_0_NOUP probs, 0, 0, len_mid_0 - UPDATE_1 probs, 0, 0 - add probs, LenHigh * PMULT - (1 SHL (kLenNumLowBits + PSHIFT)) - mov sym, 1 - PLOAD x1, probs + 1 * PMULT - -MY_ALIGN_32 -len8_loop: - BIT_1 x1, x2 - mov x1, x2 - cmp sym, 64 - jb len8_loop - - mov len_temp, (kLenNumHighSymbols - kLenNumLowSymbols * 2) - 1 - kMatchMinLen - jmp short len_mid_2 ; we use short here for MASM that doesn't optimize that code as another assembler programs - -MY_ALIGN_32 -len_mid_0: - UPDATE_0 probs, 0, 0 - add probs, pbPos_R - BIT_0 x2, x1 -len_mid_2: - BIT_1 x1, x2 - BIT_2 x2, len_temp - mov probs, LOC probs_Spec - cmp state, kNumStates * PMULT - jb copy_match - - -; ---------- DECODE DISTANCE ---------- - ; probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - - mov t0, 3 + kMatchMinLen - cmp sym, 3 + kMatchMinLen - cmovb t0, sym - add probs, PosSlot * PMULT - (kMatchMinLen SHL (kNumPosSlotBits + PSHIFT)) - shl t0, (kNumPosSlotBits + PSHIFT) - add probs, t0_R - - ; sym = Len - ; mov LOC remainLen, sym - mov len_temp, sym - - ifdef _LZMA_SIZE_OPT - - PLOAD x1, probs + 1 * PMULT - mov sym, 1 -MY_ALIGN_16 -slot_loop: - BIT_1 x1, x2 - mov x1, x2 - cmp sym, 32 - jb slot_loop - - else - - BIT_0 x1, x2 - BIT_1 x2, x1 - BIT_1 x1, x2 - BIT_1 x2, x1 - BIT_1 x1, x2 - - endif - - mov x1, sym - BIT_2 x2, 64-1 - - and sym, 3 - mov probs, LOC probs_Spec - cmp x1, 32 + kEndPosModelIndex / 2 - jb short_dist - - ; unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); - sub x1, (32 + 1 + kNumAlignBits) - ; distance = (2 | (distance & 1)); - or sym, 2 - PLOAD x2, probs + 1 * PMULT - shl sym, kNumAlignBits + 1 - lea sym2_R, [probs + 2 * PMULT] - - jmp direct_norm - ; lea t1, [sym_R + (1 SHL kNumAlignBits)] - ; cmp range, kTopValue - ; jb direct_norm - -; ---------- DIRECT DISTANCE ---------- -MY_ALIGN_32 -direct_loop: - shr range, 1 - mov t0, cod - sub cod, range - cmovs cod, t0 - cmovns sym, t1 - - comment ~ - sub cod, range - mov x2, cod - sar x2, 31 - lea sym, dword ptr [r2 + sym_R * 2 + 1] - and x2, range - add cod, x2 - ~ - dec x1 - je direct_end - - add sym, sym -direct_norm: - lea t1, [sym_R + (1 SHL kNumAlignBits)] - cmp range, kTopValue - jae near ptr direct_loop - ; we align for 32 here with "near ptr" command above - NORM_2 - jmp direct_loop - -MY_ALIGN_32 -direct_end: - ; prob = + kAlign; - ; distance <<= kNumAlignBits; - REV_0 x2, x1 - REV_1 x1, x2, 2 - REV_1 x2, x1, 4 - REV_2 x1, 8 - -decode_dist_end: - - ; if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) - - mov t1, LOC rep0 - mov x1, LOC rep1 - mov x2, LOC rep2 - - mov t0, LOC checkDicSize - test t0, t0 - cmove t0, processedPos - cmp sym, t0 - jae end_of_payload - ; jmp end_of_payload ; for debug - - ; rep3 = rep2; - ; rep2 = rep1; - ; rep1 = rep0; - ; rep0 = distance + 1; - - inc sym - mov LOC rep0, sym - ; mov sym, LOC remainLen - mov sym, len_temp - mov LOC rep1, t1 - mov LOC rep2, x1 - mov LOC rep3, x2 - - ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - cmp state, (kNumStates + kNumLitStates) * PMULT - mov state, kNumLitStates * PMULT - mov t0, (kNumLitStates + 3) * PMULT - cmovae state, t0 - - -; ---------- COPY MATCH ---------- -copy_match: - - ; len += kMatchMinLen; - ; add sym, kMatchMinLen - - ; if ((rem = limit - dicPos) == 0) - ; { - ; p->dicPos = dicPos; - ; return SZ_ERROR_DATA; - ; } - mov cnt_R, LOC limit - sub cnt_R, dicPos - jz fin_dicPos_LIMIT - - ; curLen = ((rem < len) ? (unsigned)rem : len); - cmp cnt_R, sym_R - ; cmovae cnt_R, sym_R ; 64-bit - cmovae cnt, sym ; 32-bit - - mov dic, LOC dic_Spec - mov x1, LOC rep0 - - mov t0_R, dicPos - add dicPos, cnt_R - ; processedPos += curLen; - add processedPos, cnt - ; len -= curLen; - sub sym, cnt - mov LOC remainLen, sym - - sub t0_R, dic - - ; pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); - sub t0_R, r1 - jae @f - - mov r1, LOC dicBufSize - add t0_R, r1 - sub r1, t0_R - cmp cnt_R, r1 - ja copy_match_cross -@@: - ; if (curLen <= dicBufSize - pos) - -; ---------- COPY MATCH FAST ---------- - ; Byte *dest = dic + dicPos; - ; mov r1, dic - ; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; - ; sub t0_R, dicPos - ; dicPos += curLen; - - ; const Byte *lim = dest + curLen; - add t0_R, dic - movzx sym, byte ptr[t0_R] - add t0_R, cnt_R - neg cnt_R - ; lea r1, [dicPos - 1] -copy_common: - dec dicPos - ; cmp LOC rep0, 1 - ; je rep0Label - - ; t0_R - src_lim - ; r1 - dest_lim - 1 - ; cnt_R - (-cnt) - - IsMatchBranch_Pre - inc cnt_R - jz copy_end -MY_ALIGN_16 -@@: - mov byte ptr[cnt_R * 1 + dicPos], sym_L - movzx sym, byte ptr[cnt_R * 1 + t0_R] - inc cnt_R - jnz @b - -copy_end: -lz_end_match: - mov byte ptr[dicPos], sym_L - inc dicPos - - ; IsMatchBranch_Pre - CheckLimits -lz_end: - IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label - - - -; ---------- LITERAL MATCHED ---------- - - LIT_PROBS LOC lpMask - - ; matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - mov x1, LOC rep0 - ; mov dic, LOC dic_Spec - mov LOC dicPos_Spec, dicPos - - ; state -= (state < 10) ? 3 : 6; - lea t0, [state_R - 6 * PMULT] - sub state, 3 * PMULT - cmp state, 7 * PMULT - cmovae state, t0 - - sub dicPos, dic - sub dicPos, r1 - jae @f - add dicPos, LOC dicBufSize -@@: - comment ~ - xor t0, t0 - sub dicPos, r1 - cmovb t0_R, LOC dicBufSize - ~ - - movzx match, byte ptr[dic + dicPos * 1] - - ifdef _LZMA_SIZE_OPT - - mov offs, 256 * PMULT - shl match, (PSHIFT + 1) - mov bit, match - mov sym, 1 -MY_ALIGN_16 -litm_loop: - LITM - cmp sym, 256 - jb litm_loop - sub sym, 256 - - else - - LITM_0 - LITM - LITM - LITM - LITM - LITM - LITM - LITM_2 - - endif - - mov probs, LOC probs_Spec - IsMatchBranch_Pre - ; mov dic, LOC dic_Spec - mov dicPos, LOC dicPos_Spec - mov byte ptr[dicPos], sym_L - inc dicPos - - CheckLimits -lit_matched_end: - IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label - ; IsMatchBranch - mov lpMask_reg, LOC lpMask - sub state, 3 * PMULT - jmp lit_start_2 - - - -; ---------- REP 0 LITERAL ---------- -MY_ALIGN_32 -IsRep0Short_label: - UPDATE_0 probs_state_R, pbPos_R, IsRep0Long - - ; dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - mov dic, LOC dic_Spec - mov t0_R, dicPos - mov probBranch, LOC rep0 - sub t0_R, dic - - sub probs, RepLenCoder * PMULT - - ; state = state < kNumLitStates ? 9 : 11; - or state, 1 * PMULT - - ; the caller doesn't allow (dicPos >= limit) case for REP_SHORT - ; so we don't need the following (dicPos == limit) check here: - ; cmp dicPos, LOC limit - ; jae fin_dicPos_LIMIT_REP_SHORT - - inc processedPos - - IsMatchBranch_Pre - -; xor sym, sym -; sub t0_R, probBranch_R -; cmovb sym_R, LOC dicBufSize -; add t0_R, sym_R - sub t0_R, probBranch_R - jae @f - add t0_R, LOC dicBufSize -@@: - movzx sym, byte ptr[dic + t0_R * 1] - jmp lz_end_match - - -MY_ALIGN_32 -IsRep_label: - UPDATE_1 probs_state_R, 0, IsRep - - ; The (checkDicSize == 0 && processedPos == 0) case was checked before in LzmaDec.c with kBadRepCode. - ; So we don't check it here. - - ; mov t0, processedPos - ; or t0, LOC checkDicSize - ; jz fin_ERROR_2 - - ; state = state < kNumLitStates ? 8 : 11; - cmp state, kNumLitStates * PMULT - mov state, 8 * PMULT - mov probBranch, 11 * PMULT - cmovae state, probBranch - - ; prob = probs + RepLenCoder; - add probs, RepLenCoder * PMULT - - IF_BIT_1 probs_state_R, 0, IsRepG0, IsRepG0_label - IF_BIT_0_NOUP probs_state_R, pbPos_R, IsRep0Long, IsRep0Short_label - UPDATE_1 probs_state_R, pbPos_R, IsRep0Long - jmp len_decode - -MY_ALIGN_32 -IsRepG0_label: - UPDATE_1 probs_state_R, 0, IsRepG0 - mov dist2, LOC rep0 - mov dist, LOC rep1 - mov LOC rep1, dist2 - - IF_BIT_1 probs_state_R, 0, IsRepG1, IsRepG1_label - mov LOC rep0, dist - jmp len_decode - -; MY_ALIGN_32 -IsRepG1_label: - UPDATE_1 probs_state_R, 0, IsRepG1 - mov dist2, LOC rep2 - mov LOC rep2, dist - - IF_BIT_1 probs_state_R, 0, IsRepG2, IsRepG2_label - mov LOC rep0, dist2 - jmp len_decode - -; MY_ALIGN_32 -IsRepG2_label: - UPDATE_1 probs_state_R, 0, IsRepG2 - mov dist, LOC rep3 - mov LOC rep3, dist2 - mov LOC rep0, dist - jmp len_decode - - - -; ---------- SPEC SHORT DISTANCE ---------- - -MY_ALIGN_32 -short_dist: - sub x1, 32 + 1 - jbe decode_dist_end - or sym, 2 - shl sym, x1_L - lea sym_R, [probs + sym_R * PMULT + SpecPos * PMULT + 1 * PMULT] - mov sym2, PMULT ; step -MY_ALIGN_32 -spec_loop: - REV_1_VAR x2 - dec x1 - jnz spec_loop - - mov probs, LOC probs_Spec - sub sym, sym2 - sub sym, SpecPos * PMULT - sub sym_R, probs - shr sym, PSHIFT - - jmp decode_dist_end - - -; ---------- COPY MATCH CROSS ---------- -copy_match_cross: - ; t0_R - src pos - ; r1 - len to dicBufSize - ; cnt_R - total copy len - - mov t1_R, t0_R ; srcPos - mov t0_R, dic - mov r1, LOC dicBufSize ; - neg cnt_R -@@: - movzx sym, byte ptr[t1_R * 1 + t0_R] - inc t1_R - mov byte ptr[cnt_R * 1 + dicPos], sym_L - inc cnt_R - cmp t1_R, r1 - jne @b - - movzx sym, byte ptr[t0_R] - sub t0_R, cnt_R - jmp copy_common - - - - -; fin_dicPos_LIMIT_REP_SHORT: - ; mov sym, 1 - -fin_dicPos_LIMIT: - mov LOC remainLen, sym - jmp fin_OK - ; For more strict mode we can stop decoding with error - ; mov sym, 1 - ; jmp fin - - -fin_ERROR_MATCH_DIST: - - ; rep3 = rep2; - ; rep2 = rep1; - ; rep1 = rep0; - ; rep0 = distance + 1; - - add len_temp, kMatchSpecLen_Error_Data - mov LOC remainLen, len_temp - - mov LOC rep0, sym - mov LOC rep1, t1 - mov LOC rep2, x1 - mov LOC rep3, x2 - - ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - cmp state, (kNumStates + kNumLitStates) * PMULT - mov state, kNumLitStates * PMULT - mov t0, (kNumLitStates + 3) * PMULT - cmovae state, t0 - - ; jmp fin_OK - mov sym, 1 - jmp fin - -end_of_payload: - inc sym - jnz fin_ERROR_MATCH_DIST - - mov LOC remainLen, kMatchSpecLenStart - sub state, kNumStates * PMULT - -fin_OK: - xor sym, sym - -fin: - NORM - - mov r1, LOC lzmaPtr - - sub dicPos, LOC dic_Spec - mov GLOB dicPos_Spec, dicPos - mov GLOB buf_Spec, buf - mov GLOB range_Spec, range - mov GLOB code_Spec, cod - shr state, PSHIFT - mov GLOB state_Spec, state - mov GLOB processedPos_Spec, processedPos - - RESTORE_VAR(remainLen) - RESTORE_VAR(rep0) - RESTORE_VAR(rep1) - RESTORE_VAR(rep2) - RESTORE_VAR(rep3) - - mov x0, sym - - mov RSP, LOC Old_RSP - -MY_POP_PRESERVED_ABI_REGS -MY_ENDP - -ifdef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT -_TEXT$LZMADECOPT ENDS -endif - -end +; LzmaDecOpt.asm -- ASM version of LzmaDec_DecodeReal_3() function +; 2024-06-18: Igor Pavlov : Public domain +; +; 3 - is the code compatibility version of LzmaDec_DecodeReal_*() +; function for check at link time. +; That code is tightly coupled with LzmaDec_TryDummy() +; and with another functions in LzmaDec.c file. +; CLzmaDec structure, (probs) array layout, input and output of +; LzmaDec_DecodeReal_*() must be equal in both versions (C / ASM). + +ifndef x64 +; x64=1 +; .err +endif + +include 7zAsm.asm + +MY_ASM_START + +; if Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT is defined, we use additional SEGMENT with 64-byte alignment. +; if Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT is not defined, we use default SEGMENT (where default 16-byte alignment of segment is expected). +; The performance is almost identical in our tests. +; But the performance can depend from position of lzmadec code inside instruction cache +; or micro-op cache line (depending from low address bits in 32-byte/64-byte cache lines). +; And 64-byte alignment provides a more consistent speed regardless +; of the code's position in the executable. +; But also it's possible that code without Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT can be +; slightly faster than 64-bytes aligned code in some cases, if offset of lzmadec +; code in 64-byte block after compilation provides better speed by some reason. +; Note that Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT adds an extra section to the ELF file. +; If you don't want to get that extra section, do not define Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT. + +ifndef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT +if (IS_LINUX gt 0) + Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT equ 1 +else + Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT equ 1 +endif +endif + +ifdef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT +_TEXT$LZMADECOPT SEGMENT ALIGN(64) 'CODE' +MY_ALIGN macro num:req + align num + ; align 16 +endm +else +MY_ALIGN macro num:req + ; We expect that ".text" is aligned for 16-bytes. + ; So we don't need large alignment inside out function. + align 16 +endm +endif + + +MY_ALIGN_16 macro + MY_ALIGN 16 +endm + +MY_ALIGN_32 macro + MY_ALIGN 32 +endm + +MY_ALIGN_64 macro + MY_ALIGN 64 +endm + + +; _LZMA_SIZE_OPT equ 1 + +; _LZMA_PROB32 equ 1 + +ifdef _LZMA_PROB32 + PSHIFT equ 2 + PLOAD macro dest, mem + mov dest, dword ptr [mem] + endm + PSTORE macro src, mem + mov dword ptr [mem], src + endm +else + PSHIFT equ 1 + PLOAD macro dest, mem + movzx dest, word ptr [mem] + endm + PSTORE macro src, mem + mov word ptr [mem], @CatStr(src, _W) + endm +endif + +PMULT equ (1 SHL PSHIFT) +PMULT_HALF equ (1 SHL (PSHIFT - 1)) +PMULT_2 equ (1 SHL (PSHIFT + 1)) + +kMatchSpecLen_Error_Data equ (1 SHL 9) + +; x0 range +; x1 pbPos / (prob) TREE +; x2 probBranch / prm (MATCHED) / pbPos / cnt +; x3 sym +;====== r4 === RSP +; x5 cod +; x6 t1 NORM_CALC / probs_state / dist +; x7 t0 NORM_CALC / prob2 IF_BIT_1 +; x8 state +; x9 match (MATCHED) / sym2 / dist2 / lpMask_reg +; x10 kBitModelTotal_reg +; r11 probs +; x12 offs (MATCHED) / dic / len_temp +; x13 processedPos +; x14 bit (MATCHED) / dicPos +; r15 buf + + +cod equ x5 +cod_L equ x5_L +range equ x0 +state equ x8 +state_R equ r8 +buf equ r15 +processedPos equ x13 +kBitModelTotal_reg equ x10 + +probBranch equ x2 +probBranch_R equ r2 +probBranch_W equ x2_W + +pbPos equ x1 +pbPos_R equ r1 + +cnt equ x2 +cnt_R equ r2 + +lpMask_reg equ x9 +dicPos equ r14 + +sym equ x3 +sym_R equ r3 +sym_L equ x3_L + +probs equ r11 +dic equ r12 + +t0 equ x7 +t0_W equ x7_W +t0_R equ r7 + +prob2 equ t0 +prob2_W equ t0_W + +t1 equ x6 +t1_R equ r6 + +probs_state equ t1 +probs_state_R equ t1_R + +prm equ r2 +match equ x9 +match_R equ r9 +offs equ x12 +offs_R equ r12 +bit equ x14 +bit_R equ r14 + +sym2 equ x9 +sym2_R equ r9 + +len_temp equ x12 + +dist equ sym +dist2 equ x9 + + + +kNumBitModelTotalBits equ 11 +kBitModelTotal equ (1 SHL kNumBitModelTotalBits) +kNumMoveBits equ 5 +kBitModelOffset equ ((1 SHL kNumMoveBits) - 1) +kTopValue equ (1 SHL 24) + +NORM_2 macro + ; movzx t0, BYTE PTR [buf] + shl cod, 8 + mov cod_L, BYTE PTR [buf] + shl range, 8 + ; or cod, t0 + inc buf +endm + + +NORM macro + cmp range, kTopValue + jae SHORT @F + NORM_2 +@@: +endm + + +; ---------- Branch MACROS ---------- + +UPDATE_0 macro probsArray:req, probOffset:req, probDisp:req + mov prob2, kBitModelTotal_reg + sub prob2, probBranch + shr prob2, kNumMoveBits + add probBranch, prob2 + PSTORE probBranch, probOffset * 1 + probsArray + probDisp * PMULT +endm + + +UPDATE_1 macro probsArray:req, probOffset:req, probDisp:req + sub prob2, range + sub cod, range + mov range, prob2 + mov prob2, probBranch + shr probBranch, kNumMoveBits + sub prob2, probBranch + PSTORE prob2, probOffset * 1 + probsArray + probDisp * PMULT +endm + + +CMP_COD macro probsArray:req, probOffset:req, probDisp:req + PLOAD probBranch, probOffset * 1 + probsArray + probDisp * PMULT + NORM + mov prob2, range + shr range, kNumBitModelTotalBits + imul range, probBranch + cmp cod, range +endm + + +IF_BIT_1_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req + CMP_COD probsArray, probOffset, probDisp + jae toLabel +endm + + +IF_BIT_1 macro probsArray:req, probOffset:req, probDisp:req, toLabel:req + IF_BIT_1_NOUP probsArray, probOffset, probDisp, toLabel + UPDATE_0 probsArray, probOffset, probDisp +endm + + +IF_BIT_0_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req + CMP_COD probsArray, probOffset, probDisp + jb toLabel +endm + + +; ---------- CMOV MACROS ---------- + +NORM_CALC macro prob:req + NORM + mov t0, range + shr range, kNumBitModelTotalBits + imul range, prob + sub t0, range + mov t1, cod + sub cod, range +endm + + +PUP macro prob:req, probPtr:req + sub t0, prob + ; only sar works for both 16/32 bit prob modes + sar t0, kNumMoveBits + add t0, prob + PSTORE t0, probPtr +endm + + +PUP_SUB macro prob:req, probPtr:req, symSub:req + sbb sym, symSub + PUP prob, probPtr +endm + + +PUP_COD macro prob:req, probPtr:req, symSub:req + mov t0, kBitModelOffset + cmovb cod, t1 + mov t1, sym + cmovb t0, kBitModelTotal_reg + PUP_SUB prob, probPtr, symSub +endm + + +BIT_0 macro prob:req, probNext:req + PLOAD prob, probs + 1 * PMULT + PLOAD probNext, probs + 1 * PMULT_2 + + NORM_CALC prob + + cmovae range, t0 + PLOAD t0, probs + 1 * PMULT_2 + PMULT + cmovae probNext, t0 + mov t0, kBitModelOffset + cmovb cod, t1 + cmovb t0, kBitModelTotal_reg + mov sym, 2 + PUP_SUB prob, probs + 1 * PMULT, 0 - 1 +endm + + +BIT_1 macro prob:req, probNext:req + PLOAD probNext, probs + sym_R * PMULT_2 + add sym, sym + + NORM_CALC prob + + cmovae range, t0 + PLOAD t0, probs + sym_R * PMULT + PMULT + cmovae probNext, t0 + PUP_COD prob, probs + t1_R * PMULT_HALF, 0 - 1 +endm + + +BIT_2 macro prob:req, symSub:req + add sym, sym + + NORM_CALC prob + + cmovae range, t0 + PUP_COD prob, probs + t1_R * PMULT_HALF, symSub +endm + + +; ---------- MATCHED LITERAL ---------- + +LITM_0 macro + mov offs, 256 * PMULT + shl match, (PSHIFT + 1) + mov bit, offs + and bit, match + PLOAD x1, probs + 256 * PMULT + bit_R * 1 + 1 * PMULT + lea prm, [probs + 256 * PMULT + bit_R * 1 + 1 * PMULT] + ; lea prm, [probs + 256 * PMULT + 1 * PMULT] + ; add prm, bit_R + xor offs, bit + add match, match + + NORM_CALC x1 + + cmovae offs, bit + mov bit, match + cmovae range, t0 + mov t0, kBitModelOffset + cmovb cod, t1 + cmovb t0, kBitModelTotal_reg + mov sym, 0 + PUP_SUB x1, prm, -2-1 +endm + + +LITM macro + and bit, offs + lea prm, [probs + offs_R * 1] + add prm, bit_R + PLOAD x1, prm + sym_R * PMULT + xor offs, bit + add sym, sym + add match, match + + NORM_CALC x1 + + cmovae offs, bit + mov bit, match + cmovae range, t0 + PUP_COD x1, prm + t1_R * PMULT_HALF, - 1 +endm + + +LITM_2 macro + and bit, offs + lea prm, [probs + offs_R * 1] + add prm, bit_R + PLOAD x1, prm + sym_R * PMULT + add sym, sym + + NORM_CALC x1 + + cmovae range, t0 + PUP_COD x1, prm + t1_R * PMULT_HALF, 256 - 1 +endm + + +; ---------- REVERSE BITS ---------- + +REV_0 macro prob:req, probNext:req + ; PLOAD prob, probs + 1 * PMULT + ; lea sym2_R, [probs + 2 * PMULT] + ; PLOAD probNext, probs + 2 * PMULT + PLOAD probNext, sym2_R + + NORM_CALC prob + + cmovae range, t0 + PLOAD t0, probs + 3 * PMULT + cmovae probNext, t0 + cmovb cod, t1 + mov t0, kBitModelOffset + cmovb t0, kBitModelTotal_reg + lea t1_R, [probs + 3 * PMULT] + cmovae sym2_R, t1_R + PUP prob, probs + 1 * PMULT +endm + + +REV_1 macro prob:req, probNext:req, step:req + add sym2_R, step * PMULT + PLOAD probNext, sym2_R + + NORM_CALC prob + + cmovae range, t0 + PLOAD t0, sym2_R + step * PMULT + cmovae probNext, t0 + cmovb cod, t1 + mov t0, kBitModelOffset + cmovb t0, kBitModelTotal_reg + lea t1_R, [sym2_R + step * PMULT] + cmovae sym2_R, t1_R + PUP prob, t1_R - step * PMULT_2 +endm + + +REV_2 macro prob:req, step:req + sub sym2_R, probs + shr sym2, PSHIFT + or sym, sym2 + + NORM_CALC prob + + cmovae range, t0 + lea t0, [sym - step] + cmovb sym, t0 + cmovb cod, t1 + mov t0, kBitModelOffset + cmovb t0, kBitModelTotal_reg + PUP prob, probs + sym2_R * PMULT +endm + + +REV_1_VAR macro prob:req + PLOAD prob, sym_R + mov probs, sym_R + add sym_R, sym2_R + + NORM_CALC prob + + cmovae range, t0 + lea t0_R, [sym_R + 1 * sym2_R] + cmovae sym_R, t0_R + mov t0, kBitModelOffset + cmovb cod, t1 + ; mov t1, kBitModelTotal + ; cmovb t0, t1 + cmovb t0, kBitModelTotal_reg + add sym2, sym2 + PUP prob, probs +endm + + + + +LIT_PROBS macro lpMaskParam:req + ; prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); + mov t0, processedPos + shl t0, 8 + add sym, t0 + and sym, lpMaskParam + add probs_state_R, pbPos_R + mov x1, LOC lc2 + lea sym, dword ptr[sym_R + 2 * sym_R] + add probs, Literal * PMULT + shl sym, x1_L + add probs, sym_R + UPDATE_0 probs_state_R, 0, IsMatch + inc processedPos +endm + + + +kNumPosBitsMax equ 4 +kNumPosStatesMax equ (1 SHL kNumPosBitsMax) + +kLenNumLowBits equ 3 +kLenNumLowSymbols equ (1 SHL kLenNumLowBits) +kLenNumHighBits equ 8 +kLenNumHighSymbols equ (1 SHL kLenNumHighBits) +kNumLenProbs equ (2 * kLenNumLowSymbols * kNumPosStatesMax + kLenNumHighSymbols) + +LenLow equ 0 +LenChoice equ LenLow +LenChoice2 equ (LenLow + kLenNumLowSymbols) +LenHigh equ (LenLow + 2 * kLenNumLowSymbols * kNumPosStatesMax) + +kNumStates equ 12 +kNumStates2 equ 16 +kNumLitStates equ 7 + +kStartPosModelIndex equ 4 +kEndPosModelIndex equ 14 +kNumFullDistances equ (1 SHL (kEndPosModelIndex SHR 1)) + +kNumPosSlotBits equ 6 +kNumLenToPosStates equ 4 + +kNumAlignBits equ 4 +kAlignTableSize equ (1 SHL kNumAlignBits) + +kMatchMinLen equ 2 +kMatchSpecLenStart equ (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +kStartOffset equ 1664 +SpecPos equ (-kStartOffset) +IsRep0Long equ (SpecPos + kNumFullDistances) +RepLenCoder equ (IsRep0Long + (kNumStates2 SHL kNumPosBitsMax)) +LenCoder equ (RepLenCoder + kNumLenProbs) +IsMatch equ (LenCoder + kNumLenProbs) +kAlign equ (IsMatch + (kNumStates2 SHL kNumPosBitsMax)) +IsRep equ (kAlign + kAlignTableSize) +IsRepG0 equ (IsRep + kNumStates) +IsRepG1 equ (IsRepG0 + kNumStates) +IsRepG2 equ (IsRepG1 + kNumStates) +PosSlot equ (IsRepG2 + kNumStates) +Literal equ (PosSlot + (kNumLenToPosStates SHL kNumPosSlotBits)) +NUM_BASE_PROBS equ (Literal + kStartOffset) + +if kAlign ne 0 + .err +endif + +if NUM_BASE_PROBS ne 1984 + .err +endif + + +PTR_FIELD equ dq ? + +CLzmaDec_Asm struct + lc db ? + lp db ? + pb db ? + _pad_ db ? + dicSize dd ? + + probs_Spec PTR_FIELD + probs_1664 PTR_FIELD + dic_Spec PTR_FIELD + dicBufSize PTR_FIELD + dicPos_Spec PTR_FIELD + buf_Spec PTR_FIELD + + range_Spec dd ? + code_Spec dd ? + processedPos_Spec dd ? + checkDicSize dd ? + rep0 dd ? + rep1 dd ? + rep2 dd ? + rep3 dd ? + state_Spec dd ? + remainLen dd ? +CLzmaDec_Asm ends + + +CLzmaDec_Asm_Loc struct + OLD_RSP PTR_FIELD + lzmaPtr PTR_FIELD + _pad0_ PTR_FIELD + _pad1_ PTR_FIELD + _pad2_ PTR_FIELD + dicBufSize PTR_FIELD + probs_Spec PTR_FIELD + dic_Spec PTR_FIELD + + limit PTR_FIELD + bufLimit PTR_FIELD + lc2 dd ? + lpMask dd ? + pbMask dd ? + checkDicSize dd ? + + _pad_ dd ? + remainLen dd ? + dicPos_Spec PTR_FIELD + rep0 dd ? + rep1 dd ? + rep2 dd ? + rep3 dd ? +CLzmaDec_Asm_Loc ends + + +GLOB_2 equ [sym_R].CLzmaDec_Asm. +GLOB equ [r1].CLzmaDec_Asm. +LOC_0 equ [r0].CLzmaDec_Asm_Loc. +LOC equ [RSP].CLzmaDec_Asm_Loc. + + +COPY_VAR macro name + mov t0, GLOB_2 name + mov LOC_0 name, t0 +endm + + +RESTORE_VAR macro name + mov t0, LOC name + mov GLOB name, t0 +endm + + + +IsMatchBranch_Pre macro reg + ; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + mov pbPos, LOC pbMask + and pbPos, processedPos + shl pbPos, (kLenNumLowBits + 1 + PSHIFT) + lea probs_state_R, [probs + 1 * state_R] +endm + + +IsMatchBranch macro reg + IsMatchBranch_Pre + IF_BIT_1 probs_state_R, pbPos_R, IsMatch, IsMatch_label +endm + + +CheckLimits macro reg + cmp buf, LOC bufLimit + jae fin_OK + cmp dicPos, LOC limit + jae fin_OK +endm + + + +; RSP is (16x + 8) bytes aligned in WIN64-x64 +; LocalSize equ ((((SIZEOF CLzmaDec_Asm_Loc) + 7) / 16 * 16) + 8) + +PARAM_lzma equ REG_ABI_PARAM_0 +PARAM_limit equ REG_ABI_PARAM_1 +PARAM_bufLimit equ REG_ABI_PARAM_2 + +ifdef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT +; MY_ALIGN_64 +else + MY_ALIGN_16 +endif +MY_PROC LzmaDec_DecodeReal_3, 3 +MY_PUSH_PRESERVED_ABI_REGS + + lea r0, [RSP - (SIZEOF CLzmaDec_Asm_Loc)] + and r0, -128 + mov r5, RSP + mov RSP, r0 + mov LOC_0 Old_RSP, r5 + mov LOC_0 lzmaPtr, PARAM_lzma + + mov LOC_0 remainLen, 0 ; remainLen must be ZERO + + mov LOC_0 bufLimit, PARAM_bufLimit + mov sym_R, PARAM_lzma ; CLzmaDec_Asm_Loc pointer for GLOB_2 + mov dic, GLOB_2 dic_Spec + add PARAM_limit, dic + mov LOC_0 limit, PARAM_limit + + COPY_VAR(rep0) + COPY_VAR(rep1) + COPY_VAR(rep2) + COPY_VAR(rep3) + + mov dicPos, GLOB_2 dicPos_Spec + add dicPos, dic + mov LOC_0 dicPos_Spec, dicPos + mov LOC_0 dic_Spec, dic + + mov x1_L, GLOB_2 pb + mov t0, 1 + shl t0, x1_L + dec t0 + mov LOC_0 pbMask, t0 + + ; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + ; unsigned lc = p->prop.lc; + ; unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); + + mov x1_L, GLOB_2 lc + mov x2, 100h + mov t0, x2 + shr x2, x1_L + ; inc x1 + add x1_L, PSHIFT + mov LOC_0 lc2, x1 + mov x1_L, GLOB_2 lp + shl t0, x1_L + sub t0, x2 + mov LOC_0 lpMask, t0 + mov lpMask_reg, t0 + + ; mov probs, GLOB_2 probs_Spec + ; add probs, kStartOffset SHL PSHIFT + mov probs, GLOB_2 probs_1664 + mov LOC_0 probs_Spec, probs + + mov t0_R, GLOB_2 dicBufSize + mov LOC_0 dicBufSize, t0_R + + mov x1, GLOB_2 checkDicSize + mov LOC_0 checkDicSize, x1 + + mov processedPos, GLOB_2 processedPos_Spec + + mov state, GLOB_2 state_Spec + shl state, PSHIFT + + mov buf, GLOB_2 buf_Spec + mov range, GLOB_2 range_Spec + mov cod, GLOB_2 code_Spec + mov kBitModelTotal_reg, kBitModelTotal + xor sym, sym + + ; if (processedPos != 0 || checkDicSize != 0) + or x1, processedPos + jz @f + + add t0_R, dic + cmp dicPos, dic + cmovnz t0_R, dicPos + movzx sym, byte ptr[t0_R - 1] + +@@: + IsMatchBranch_Pre + cmp state, 4 * PMULT + jb lit_end + cmp state, kNumLitStates * PMULT + jb lit_matched_end + jmp lz_end + + + + +; ---------- LITERAL ---------- +MY_ALIGN_64 +lit_start: + xor state, state +lit_start_2: + LIT_PROBS lpMask_reg + + ifdef _LZMA_SIZE_OPT + + PLOAD x1, probs + 1 * PMULT + mov sym, 1 +MY_ALIGN_16 +lit_loop: + BIT_1 x1, x2 + mov x1, x2 + cmp sym, 127 + jbe lit_loop + + else + + BIT_0 x1, x2 + BIT_1 x2, x1 + BIT_1 x1, x2 + BIT_1 x2, x1 + BIT_1 x1, x2 + BIT_1 x2, x1 + BIT_1 x1, x2 + + endif + + BIT_2 x2, 256 - 1 + + ; mov dic, LOC dic_Spec + mov probs, LOC probs_Spec + IsMatchBranch_Pre + mov byte ptr[dicPos], sym_L + inc dicPos + + CheckLimits +lit_end: + IF_BIT_0_NOUP probs_state_R, pbPos_R, IsMatch, lit_start + + ; jmp IsMatch_label + +; ---------- MATCHES ---------- +; MY_ALIGN_32 +IsMatch_label: + UPDATE_1 probs_state_R, pbPos_R, IsMatch + IF_BIT_1 probs_state_R, 0, IsRep, IsRep_label + + add probs, LenCoder * PMULT + add state, kNumStates * PMULT + +; ---------- LEN DECODE ---------- +len_decode: + mov len_temp, 8 - 1 - kMatchMinLen + IF_BIT_0_NOUP probs, 0, 0, len_mid_0 + UPDATE_1 probs, 0, 0 + add probs, (1 SHL (kLenNumLowBits + PSHIFT)) + mov len_temp, -1 - kMatchMinLen + IF_BIT_0_NOUP probs, 0, 0, len_mid_0 + UPDATE_1 probs, 0, 0 + add probs, LenHigh * PMULT - (1 SHL (kLenNumLowBits + PSHIFT)) + mov sym, 1 + PLOAD x1, probs + 1 * PMULT + +MY_ALIGN_32 +len8_loop: + BIT_1 x1, x2 + mov x1, x2 + cmp sym, 64 + jb len8_loop + + mov len_temp, (kLenNumHighSymbols - kLenNumLowSymbols * 2) - 1 - kMatchMinLen + jmp short len_mid_2 ; we use short here for MASM that doesn't optimize that code as another assembler programs + +MY_ALIGN_32 +len_mid_0: + UPDATE_0 probs, 0, 0 + add probs, pbPos_R + BIT_0 x2, x1 +len_mid_2: + BIT_1 x1, x2 + BIT_2 x2, len_temp + mov probs, LOC probs_Spec + cmp state, kNumStates * PMULT + jb copy_match + + +; ---------- DECODE DISTANCE ---------- + ; probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + + mov t0, 3 + kMatchMinLen + cmp sym, 3 + kMatchMinLen + cmovb t0, sym + add probs, PosSlot * PMULT - (kMatchMinLen SHL (kNumPosSlotBits + PSHIFT)) + shl t0, (kNumPosSlotBits + PSHIFT) + add probs, t0_R + + ; sym = Len + ; mov LOC remainLen, sym + mov len_temp, sym + + ifdef _LZMA_SIZE_OPT + + PLOAD x1, probs + 1 * PMULT + mov sym, 1 +MY_ALIGN_16 +slot_loop: + BIT_1 x1, x2 + mov x1, x2 + cmp sym, 32 + jb slot_loop + + else + + BIT_0 x1, x2 + BIT_1 x2, x1 + BIT_1 x1, x2 + BIT_1 x2, x1 + BIT_1 x1, x2 + + endif + + mov x1, sym + BIT_2 x2, 64-1 + + and sym, 3 + mov probs, LOC probs_Spec + cmp x1, 32 + kEndPosModelIndex / 2 + jb short_dist + + ; unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); + sub x1, (32 + 1 + kNumAlignBits) + ; distance = (2 | (distance & 1)); + or sym, 2 + PLOAD x2, probs + 1 * PMULT + shl sym, kNumAlignBits + 1 + lea sym2_R, [probs + 2 * PMULT] + + jmp direct_norm + ; lea t1, [sym_R + (1 SHL kNumAlignBits)] + ; cmp range, kTopValue + ; jb direct_norm + +; ---------- DIRECT DISTANCE ---------- +MY_ALIGN_32 +direct_loop: + shr range, 1 + mov t0, cod + sub cod, range + cmovs cod, t0 + cmovns sym, t1 + + comment ~ + sub cod, range + mov x2, cod + sar x2, 31 + lea sym, dword ptr [r2 + sym_R * 2 + 1] + and x2, range + add cod, x2 + ~ + dec x1 + je direct_end + + add sym, sym +direct_norm: + lea t1, [sym_R + (1 SHL kNumAlignBits)] + cmp range, kTopValue + jae near ptr direct_loop + ; we align for 32 here with "near ptr" command above + NORM_2 + jmp direct_loop + +MY_ALIGN_32 +direct_end: + ; prob = + kAlign; + ; distance <<= kNumAlignBits; + REV_0 x2, x1 + REV_1 x1, x2, 2 + REV_1 x2, x1, 4 + REV_2 x1, 8 + +decode_dist_end: + + ; if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) + + mov t1, LOC rep0 + mov x1, LOC rep1 + mov x2, LOC rep2 + + mov t0, LOC checkDicSize + test t0, t0 + cmove t0, processedPos + cmp sym, t0 + jae end_of_payload + ; jmp end_of_payload ; for debug + + ; rep3 = rep2; + ; rep2 = rep1; + ; rep1 = rep0; + ; rep0 = distance + 1; + + inc sym + mov LOC rep0, sym + ; mov sym, LOC remainLen + mov sym, len_temp + mov LOC rep1, t1 + mov LOC rep2, x1 + mov LOC rep3, x2 + + ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + cmp state, (kNumStates + kNumLitStates) * PMULT + mov state, kNumLitStates * PMULT + mov t0, (kNumLitStates + 3) * PMULT + cmovae state, t0 + + +; ---------- COPY MATCH ---------- +copy_match: + + ; len += kMatchMinLen; + ; add sym, kMatchMinLen + + ; if ((rem = limit - dicPos) == 0) + ; { + ; p->dicPos = dicPos; + ; return SZ_ERROR_DATA; + ; } + mov cnt_R, LOC limit + sub cnt_R, dicPos + jz fin_dicPos_LIMIT + + ; curLen = ((rem < len) ? (unsigned)rem : len); + cmp cnt_R, sym_R + ; cmovae cnt_R, sym_R ; 64-bit + cmovae cnt, sym ; 32-bit + + mov dic, LOC dic_Spec + mov x1, LOC rep0 + + mov t0_R, dicPos + add dicPos, cnt_R + ; processedPos += curLen; + add processedPos, cnt + ; len -= curLen; + sub sym, cnt + mov LOC remainLen, sym + + sub t0_R, dic + + ; pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); + sub t0_R, r1 + jae @f + + mov r1, LOC dicBufSize + add t0_R, r1 + sub r1, t0_R + cmp cnt_R, r1 + ja copy_match_cross +@@: + ; if (curLen <= dicBufSize - pos) + +; ---------- COPY MATCH FAST ---------- + ; Byte *dest = dic + dicPos; + ; mov r1, dic + ; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + ; sub t0_R, dicPos + ; dicPos += curLen; + + ; const Byte *lim = dest + curLen; + add t0_R, dic + movzx sym, byte ptr[t0_R] + add t0_R, cnt_R + neg cnt_R + ; lea r1, [dicPos - 1] +copy_common: + dec dicPos + ; cmp LOC rep0, 1 + ; je rep0Label + + ; t0_R - src_lim + ; r1 - dest_lim - 1 + ; cnt_R - (-cnt) + + IsMatchBranch_Pre + inc cnt_R + jz copy_end +MY_ALIGN_16 +@@: + mov byte ptr[cnt_R * 1 + dicPos], sym_L + movzx sym, byte ptr[cnt_R * 1 + t0_R] + inc cnt_R + jnz @b + +copy_end: +lz_end_match: + mov byte ptr[dicPos], sym_L + inc dicPos + + ; IsMatchBranch_Pre + CheckLimits +lz_end: + IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label + + + +; ---------- LITERAL MATCHED ---------- + + LIT_PROBS LOC lpMask + + ; matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + mov x1, LOC rep0 + ; mov dic, LOC dic_Spec + mov LOC dicPos_Spec, dicPos + + ; state -= (state < 10) ? 3 : 6; + lea t0, [state_R - 6 * PMULT] + sub state, 3 * PMULT + cmp state, 7 * PMULT + cmovae state, t0 + + sub dicPos, dic + sub dicPos, r1 + jae @f + add dicPos, LOC dicBufSize +@@: + comment ~ + xor t0, t0 + sub dicPos, r1 + cmovb t0_R, LOC dicBufSize + ~ + + movzx match, byte ptr[dic + dicPos * 1] + + ifdef _LZMA_SIZE_OPT + + mov offs, 256 * PMULT + shl match, (PSHIFT + 1) + mov bit, match + mov sym, 1 +MY_ALIGN_16 +litm_loop: + LITM + cmp sym, 256 + jb litm_loop + sub sym, 256 + + else + + LITM_0 + LITM + LITM + LITM + LITM + LITM + LITM + LITM_2 + + endif + + mov probs, LOC probs_Spec + IsMatchBranch_Pre + ; mov dic, LOC dic_Spec + mov dicPos, LOC dicPos_Spec + mov byte ptr[dicPos], sym_L + inc dicPos + + CheckLimits +lit_matched_end: + IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label + ; IsMatchBranch + mov lpMask_reg, LOC lpMask + sub state, 3 * PMULT + jmp lit_start_2 + + + +; ---------- REP 0 LITERAL ---------- +MY_ALIGN_32 +IsRep0Short_label: + UPDATE_0 probs_state_R, pbPos_R, IsRep0Long + + ; dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + mov dic, LOC dic_Spec + mov t0_R, dicPos + mov probBranch, LOC rep0 + sub t0_R, dic + + sub probs, RepLenCoder * PMULT + + ; state = state < kNumLitStates ? 9 : 11; + or state, 1 * PMULT + + ; the caller doesn't allow (dicPos >= limit) case for REP_SHORT + ; so we don't need the following (dicPos == limit) check here: + ; cmp dicPos, LOC limit + ; jae fin_dicPos_LIMIT_REP_SHORT + + inc processedPos + + IsMatchBranch_Pre + +; xor sym, sym +; sub t0_R, probBranch_R +; cmovb sym_R, LOC dicBufSize +; add t0_R, sym_R + sub t0_R, probBranch_R + jae @f + add t0_R, LOC dicBufSize +@@: + movzx sym, byte ptr[dic + t0_R * 1] + jmp lz_end_match + + +MY_ALIGN_32 +IsRep_label: + UPDATE_1 probs_state_R, 0, IsRep + + ; The (checkDicSize == 0 && processedPos == 0) case was checked before in LzmaDec.c with kBadRepCode. + ; So we don't check it here. + + ; mov t0, processedPos + ; or t0, LOC checkDicSize + ; jz fin_ERROR_2 + + ; state = state < kNumLitStates ? 8 : 11; + cmp state, kNumLitStates * PMULT + mov state, 8 * PMULT + mov probBranch, 11 * PMULT + cmovae state, probBranch + + ; prob = probs + RepLenCoder; + add probs, RepLenCoder * PMULT + + IF_BIT_1 probs_state_R, 0, IsRepG0, IsRepG0_label + IF_BIT_0_NOUP probs_state_R, pbPos_R, IsRep0Long, IsRep0Short_label + UPDATE_1 probs_state_R, pbPos_R, IsRep0Long + jmp len_decode + +MY_ALIGN_32 +IsRepG0_label: + UPDATE_1 probs_state_R, 0, IsRepG0 + mov dist2, LOC rep0 + mov dist, LOC rep1 + mov LOC rep1, dist2 + + IF_BIT_1 probs_state_R, 0, IsRepG1, IsRepG1_label + mov LOC rep0, dist + jmp len_decode + +; MY_ALIGN_32 +IsRepG1_label: + UPDATE_1 probs_state_R, 0, IsRepG1 + mov dist2, LOC rep2 + mov LOC rep2, dist + + IF_BIT_1 probs_state_R, 0, IsRepG2, IsRepG2_label + mov LOC rep0, dist2 + jmp len_decode + +; MY_ALIGN_32 +IsRepG2_label: + UPDATE_1 probs_state_R, 0, IsRepG2 + mov dist, LOC rep3 + mov LOC rep3, dist2 + mov LOC rep0, dist + jmp len_decode + + + +; ---------- SPEC SHORT DISTANCE ---------- + +MY_ALIGN_32 +short_dist: + sub x1, 32 + 1 + jbe decode_dist_end + or sym, 2 + shl sym, x1_L + lea sym_R, [probs + sym_R * PMULT + SpecPos * PMULT + 1 * PMULT] + mov sym2, PMULT ; step +MY_ALIGN_32 +spec_loop: + REV_1_VAR x2 + dec x1 + jnz spec_loop + + mov probs, LOC probs_Spec + sub sym, sym2 + sub sym, SpecPos * PMULT + sub sym_R, probs + shr sym, PSHIFT + + jmp decode_dist_end + + +; ---------- COPY MATCH CROSS ---------- +copy_match_cross: + ; t0_R - src pos + ; r1 - len to dicBufSize + ; cnt_R - total copy len + + mov t1_R, t0_R ; srcPos + mov t0_R, dic + mov r1, LOC dicBufSize ; + neg cnt_R +@@: + movzx sym, byte ptr[t1_R * 1 + t0_R] + inc t1_R + mov byte ptr[cnt_R * 1 + dicPos], sym_L + inc cnt_R + cmp t1_R, r1 + jne @b + + movzx sym, byte ptr[t0_R] + sub t0_R, cnt_R + jmp copy_common + + + + +; fin_dicPos_LIMIT_REP_SHORT: + ; mov sym, 1 + +fin_dicPos_LIMIT: + mov LOC remainLen, sym + jmp fin_OK + ; For more strict mode we can stop decoding with error + ; mov sym, 1 + ; jmp fin + + +fin_ERROR_MATCH_DIST: + + ; rep3 = rep2; + ; rep2 = rep1; + ; rep1 = rep0; + ; rep0 = distance + 1; + + add len_temp, kMatchSpecLen_Error_Data + mov LOC remainLen, len_temp + + mov LOC rep0, sym + mov LOC rep1, t1 + mov LOC rep2, x1 + mov LOC rep3, x2 + + ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + cmp state, (kNumStates + kNumLitStates) * PMULT + mov state, kNumLitStates * PMULT + mov t0, (kNumLitStates + 3) * PMULT + cmovae state, t0 + + ; jmp fin_OK + mov sym, 1 + jmp fin + +end_of_payload: + inc sym + jnz fin_ERROR_MATCH_DIST + + mov LOC remainLen, kMatchSpecLenStart + sub state, kNumStates * PMULT + +fin_OK: + xor sym, sym + +fin: + NORM + + mov r1, LOC lzmaPtr + + sub dicPos, LOC dic_Spec + mov GLOB dicPos_Spec, dicPos + mov GLOB buf_Spec, buf + mov GLOB range_Spec, range + mov GLOB code_Spec, cod + shr state, PSHIFT + mov GLOB state_Spec, state + mov GLOB processedPos_Spec, processedPos + + RESTORE_VAR(remainLen) + RESTORE_VAR(rep0) + RESTORE_VAR(rep1) + RESTORE_VAR(rep2) + RESTORE_VAR(rep3) + + mov x0, sym + + mov RSP, LOC Old_RSP + +MY_POP_PRESERVED_ABI_REGS +MY_ENDP + +ifdef Z7_LZMA_DEC_OPT_ASM_USE_SEGMENT +_TEXT$LZMADECOPT ENDS +endif + +end diff --git a/Asm/x86/Sha1Opt.asm b/Asm/x86/Sha1Opt.asm index 578c9677f..0b63aeb85 100644 --- a/Asm/x86/Sha1Opt.asm +++ b/Asm/x86/Sha1Opt.asm @@ -1,263 +1,263 @@ -; Sha1Opt.asm -- SHA-1 optimized code for SHA-1 x86 hardware instructions -; 2024-06-16 : Igor Pavlov : Public domain - -include 7zAsm.asm - -MY_ASM_START - - - - - - - - - - - - - - - - -CONST SEGMENT READONLY - -align 16 -Reverse_Endian_Mask db 15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0 - - - - - - - - - - - - - - - - - - - - - - -CONST ENDS - -; _TEXT$SHA1OPT SEGMENT 'CODE' - -ifndef x64 - .686 - .xmm -endif - -ifdef x64 - rNum equ REG_ABI_PARAM_2 - if (IS_LINUX eq 0) - LOCAL_SIZE equ (16 * 2) - endif -else - rNum equ r0 - LOCAL_SIZE equ (16 * 1) -endif - -rState equ REG_ABI_PARAM_0 -rData equ REG_ABI_PARAM_1 - - -MY_sha1rnds4 macro a1, a2, imm - db 0fH, 03aH, 0ccH, (0c0H + a1 * 8 + a2), imm -endm - -MY_SHA_INSTR macro cmd, a1, a2 - db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2) -endm - -cmd_sha1nexte equ 0c8H -cmd_sha1msg1 equ 0c9H -cmd_sha1msg2 equ 0caH - -MY_sha1nexte macro a1, a2 - MY_SHA_INSTR cmd_sha1nexte, a1, a2 -endm - -MY_sha1msg1 macro a1, a2 - MY_SHA_INSTR cmd_sha1msg1, a1, a2 -endm - -MY_sha1msg2 macro a1, a2 - MY_SHA_INSTR cmd_sha1msg2, a1, a2 -endm - -MY_PROLOG macro - ifdef x64 - if (IS_LINUX eq 0) - movdqa [r4 + 8], xmm6 - movdqa [r4 + 8 + 16], xmm7 - sub r4, LOCAL_SIZE + 8 - movdqa [r4 ], xmm8 - movdqa [r4 + 16], xmm9 - endif - else ; x86 - if (IS_CDECL gt 0) - mov rState, [r4 + REG_SIZE * 1] - mov rData, [r4 + REG_SIZE * 2] - mov rNum, [r4 + REG_SIZE * 3] - else ; fastcall - mov rNum, [r4 + REG_SIZE * 1] - endif - push r5 - mov r5, r4 - and r4, -16 - sub r4, LOCAL_SIZE - endif -endm - -MY_EPILOG macro - ifdef x64 - if (IS_LINUX eq 0) - movdqa xmm8, [r4] - movdqa xmm9, [r4 + 16] - add r4, LOCAL_SIZE + 8 - movdqa xmm6, [r4 + 8] - movdqa xmm7, [r4 + 8 + 16] - endif - else ; x86 - mov r4, r5 - pop r5 - endif - MY_ENDP -endm - - -e0_N equ 0 -e1_N equ 1 -abcd_N equ 2 -e0_save_N equ 3 -w_regs equ 4 - -e0 equ @CatStr(xmm, %e0_N) -e1 equ @CatStr(xmm, %e1_N) -abcd equ @CatStr(xmm, %abcd_N) -e0_save equ @CatStr(xmm, %e0_save_N) - - -ifdef x64 - abcd_save equ xmm8 - mask2 equ xmm9 -else - abcd_save equ [r4] - mask2 equ e1 -endif - -LOAD_MASK macro - movdqa mask2, XMMWORD PTR Reverse_Endian_Mask -endm - -LOAD_W macro k:req - movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))] - pshufb @CatStr(xmm, %(w_regs + k)), mask2 -endm - - -; pre2 can be 2 or 3 (recommended) -pre2 equ 3 -pre1 equ (pre2 + 1) - -NUM_ROUNDS4 equ 20 - -RND4 macro k - movdqa @CatStr(xmm, %(e0_N + ((k + 1) mod 2))), abcd - MY_sha1rnds4 abcd_N, (e0_N + (k mod 2)), k / 5 - - nextM = (w_regs + ((k + 1) mod 4)) - - if (k EQ NUM_ROUNDS4 - 1) - nextM = e0_save_N - endif - - MY_sha1nexte (e0_N + ((k + 1) mod 2)), nextM - - if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2)) - pxor @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4))) - endif - - if (k GE (4 - pre1)) AND (k LT (NUM_ROUNDS4 - pre1)) - MY_sha1msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4)) - endif - - if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2)) - MY_sha1msg2 (w_regs + ((k + pre2) mod 4)), (w_regs + ((k + pre2 - 1) mod 4)) - endif -endm - - -REVERSE_STATE macro - ; abcd ; dcba - ; e0 ; 000e - pshufd abcd, abcd, 01bH ; abcd - pshufd e0, e0, 01bH ; e000 -endm - - - - - -MY_PROC Sha1_UpdateBlocks_HW, 3 - MY_PROLOG - - cmp rNum, 0 - je end_c - - movdqu abcd, [rState] ; dcba - movd e0, dword ptr [rState + 16] ; 000e - - REVERSE_STATE - - ifdef x64 - LOAD_MASK - endif - - align 16 - nextBlock: - movdqa abcd_save, abcd - movdqa e0_save, e0 - - ifndef x64 - LOAD_MASK - endif - - LOAD_W 0 - LOAD_W 1 - LOAD_W 2 - LOAD_W 3 - - paddd e0, @CatStr(xmm, %(w_regs)) - k = 0 - rept NUM_ROUNDS4 - RND4 k - k = k + 1 - endm - - paddd abcd, abcd_save - - - add rData, 64 - sub rNum, 1 - jnz nextBlock - - REVERSE_STATE - - movdqu [rState], abcd - movd dword ptr [rState + 16], e0 - - end_c: -MY_EPILOG - -; _TEXT$SHA1OPT ENDS - -end +; Sha1Opt.asm -- SHA-1 optimized code for SHA-1 x86 hardware instructions +; 2024-06-16 : Igor Pavlov : Public domain + +include 7zAsm.asm + +MY_ASM_START + + + + + + + + + + + + + + + + +CONST SEGMENT READONLY + +align 16 +Reverse_Endian_Mask db 15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0 + + + + + + + + + + + + + + + + + + + + + + +CONST ENDS + +; _TEXT$SHA1OPT SEGMENT 'CODE' + +ifndef x64 + .686 + .xmm +endif + +ifdef x64 + rNum equ REG_ABI_PARAM_2 + if (IS_LINUX eq 0) + LOCAL_SIZE equ (16 * 2) + endif +else + rNum equ r0 + LOCAL_SIZE equ (16 * 1) +endif + +rState equ REG_ABI_PARAM_0 +rData equ REG_ABI_PARAM_1 + + +MY_sha1rnds4 macro a1, a2, imm + db 0fH, 03aH, 0ccH, (0c0H + a1 * 8 + a2), imm +endm + +MY_SHA_INSTR macro cmd, a1, a2 + db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2) +endm + +cmd_sha1nexte equ 0c8H +cmd_sha1msg1 equ 0c9H +cmd_sha1msg2 equ 0caH + +MY_sha1nexte macro a1, a2 + MY_SHA_INSTR cmd_sha1nexte, a1, a2 +endm + +MY_sha1msg1 macro a1, a2 + MY_SHA_INSTR cmd_sha1msg1, a1, a2 +endm + +MY_sha1msg2 macro a1, a2 + MY_SHA_INSTR cmd_sha1msg2, a1, a2 +endm + +MY_PROLOG macro + ifdef x64 + if (IS_LINUX eq 0) + movdqa [r4 + 8], xmm6 + movdqa [r4 + 8 + 16], xmm7 + sub r4, LOCAL_SIZE + 8 + movdqa [r4 ], xmm8 + movdqa [r4 + 16], xmm9 + endif + else ; x86 + if (IS_CDECL gt 0) + mov rState, [r4 + REG_SIZE * 1] + mov rData, [r4 + REG_SIZE * 2] + mov rNum, [r4 + REG_SIZE * 3] + else ; fastcall + mov rNum, [r4 + REG_SIZE * 1] + endif + push r5 + mov r5, r4 + and r4, -16 + sub r4, LOCAL_SIZE + endif +endm + +MY_EPILOG macro + ifdef x64 + if (IS_LINUX eq 0) + movdqa xmm8, [r4] + movdqa xmm9, [r4 + 16] + add r4, LOCAL_SIZE + 8 + movdqa xmm6, [r4 + 8] + movdqa xmm7, [r4 + 8 + 16] + endif + else ; x86 + mov r4, r5 + pop r5 + endif + MY_ENDP +endm + + +e0_N equ 0 +e1_N equ 1 +abcd_N equ 2 +e0_save_N equ 3 +w_regs equ 4 + +e0 equ @CatStr(xmm, %e0_N) +e1 equ @CatStr(xmm, %e1_N) +abcd equ @CatStr(xmm, %abcd_N) +e0_save equ @CatStr(xmm, %e0_save_N) + + +ifdef x64 + abcd_save equ xmm8 + mask2 equ xmm9 +else + abcd_save equ [r4] + mask2 equ e1 +endif + +LOAD_MASK macro + movdqa mask2, XMMWORD PTR Reverse_Endian_Mask +endm + +LOAD_W macro k:req + movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))] + pshufb @CatStr(xmm, %(w_regs + k)), mask2 +endm + + +; pre2 can be 2 or 3 (recommended) +pre2 equ 3 +pre1 equ (pre2 + 1) + +NUM_ROUNDS4 equ 20 + +RND4 macro k + movdqa @CatStr(xmm, %(e0_N + ((k + 1) mod 2))), abcd + MY_sha1rnds4 abcd_N, (e0_N + (k mod 2)), k / 5 + + nextM = (w_regs + ((k + 1) mod 4)) + + if (k EQ NUM_ROUNDS4 - 1) + nextM = e0_save_N + endif + + MY_sha1nexte (e0_N + ((k + 1) mod 2)), nextM + + if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2)) + pxor @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4))) + endif + + if (k GE (4 - pre1)) AND (k LT (NUM_ROUNDS4 - pre1)) + MY_sha1msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4)) + endif + + if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2)) + MY_sha1msg2 (w_regs + ((k + pre2) mod 4)), (w_regs + ((k + pre2 - 1) mod 4)) + endif +endm + + +REVERSE_STATE macro + ; abcd ; dcba + ; e0 ; 000e + pshufd abcd, abcd, 01bH ; abcd + pshufd e0, e0, 01bH ; e000 +endm + + + + + +MY_PROC Sha1_UpdateBlocks_HW, 3 + MY_PROLOG + + cmp rNum, 0 + je end_c + + movdqu abcd, [rState] ; dcba + movd e0, dword ptr [rState + 16] ; 000e + + REVERSE_STATE + + ifdef x64 + LOAD_MASK + endif + + align 16 + nextBlock: + movdqa abcd_save, abcd + movdqa e0_save, e0 + + ifndef x64 + LOAD_MASK + endif + + LOAD_W 0 + LOAD_W 1 + LOAD_W 2 + LOAD_W 3 + + paddd e0, @CatStr(xmm, %(w_regs)) + k = 0 + rept NUM_ROUNDS4 + RND4 k + k = k + 1 + endm + + paddd abcd, abcd_save + + + add rData, 64 + sub rNum, 1 + jnz nextBlock + + REVERSE_STATE + + movdqu [rState], abcd + movd dword ptr [rState + 16], e0 + + end_c: +MY_EPILOG + +; _TEXT$SHA1OPT ENDS + +end diff --git a/Asm/x86/Sha256Opt.asm b/Asm/x86/Sha256Opt.asm index a07930287..bc2f9da24 100644 --- a/Asm/x86/Sha256Opt.asm +++ b/Asm/x86/Sha256Opt.asm @@ -1,275 +1,275 @@ -; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions -; 2024-06-16 : Igor Pavlov : Public domain - -include 7zAsm.asm - -MY_ASM_START - -; .data -; public K - -; we can use external SHA256_K_ARRAY defined in Sha256.c -; but we must guarantee that SHA256_K_ARRAY is aligned for 16-bytes - -COMMENT @ -ifdef x64 -K_CONST equ SHA256_K_ARRAY -else -K_CONST equ _SHA256_K_ARRAY -endif -EXTRN K_CONST:xmmword -@ - -CONST SEGMENT READONLY - -align 16 -Reverse_Endian_Mask db 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12 - -; COMMENT @ -align 16 -K_CONST \ -DD 0428a2f98H, 071374491H, 0b5c0fbcfH, 0e9b5dba5H -DD 03956c25bH, 059f111f1H, 0923f82a4H, 0ab1c5ed5H -DD 0d807aa98H, 012835b01H, 0243185beH, 0550c7dc3H -DD 072be5d74H, 080deb1feH, 09bdc06a7H, 0c19bf174H -DD 0e49b69c1H, 0efbe4786H, 00fc19dc6H, 0240ca1ccH -DD 02de92c6fH, 04a7484aaH, 05cb0a9dcH, 076f988daH -DD 0983e5152H, 0a831c66dH, 0b00327c8H, 0bf597fc7H -DD 0c6e00bf3H, 0d5a79147H, 006ca6351H, 014292967H -DD 027b70a85H, 02e1b2138H, 04d2c6dfcH, 053380d13H -DD 0650a7354H, 0766a0abbH, 081c2c92eH, 092722c85H -DD 0a2bfe8a1H, 0a81a664bH, 0c24b8b70H, 0c76c51a3H -DD 0d192e819H, 0d6990624H, 0f40e3585H, 0106aa070H -DD 019a4c116H, 01e376c08H, 02748774cH, 034b0bcb5H -DD 0391c0cb3H, 04ed8aa4aH, 05b9cca4fH, 0682e6ff3H -DD 0748f82eeH, 078a5636fH, 084c87814H, 08cc70208H -DD 090befffaH, 0a4506cebH, 0bef9a3f7H, 0c67178f2H -; @ - -CONST ENDS - -; _TEXT$SHA256OPT SEGMENT 'CODE' - -ifndef x64 - .686 - .xmm -endif - -; jwasm-based assemblers for linux and linker from new versions of binutils -; can generate incorrect code for load [ARRAY + offset] instructions. -; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem - rTable equ r0 - ; rTable equ K_CONST - -ifdef x64 - rNum equ REG_ABI_PARAM_2 - if (IS_LINUX eq 0) - LOCAL_SIZE equ (16 * 2) - endif -else - rNum equ r3 - LOCAL_SIZE equ (16 * 1) -endif - -rState equ REG_ABI_PARAM_0 -rData equ REG_ABI_PARAM_1 - - - - - - -MY_SHA_INSTR macro cmd, a1, a2 - db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2) -endm - -cmd_sha256rnds2 equ 0cbH -cmd_sha256msg1 equ 0ccH -cmd_sha256msg2 equ 0cdH - -MY_sha256rnds2 macro a1, a2 - MY_SHA_INSTR cmd_sha256rnds2, a1, a2 -endm - -MY_sha256msg1 macro a1, a2 - MY_SHA_INSTR cmd_sha256msg1, a1, a2 -endm - -MY_sha256msg2 macro a1, a2 - MY_SHA_INSTR cmd_sha256msg2, a1, a2 -endm - -MY_PROLOG macro - ifdef x64 - if (IS_LINUX eq 0) - movdqa [r4 + 8], xmm6 - movdqa [r4 + 8 + 16], xmm7 - sub r4, LOCAL_SIZE + 8 - movdqa [r4 ], xmm8 - movdqa [r4 + 16], xmm9 - endif - else ; x86 - push r3 - push r5 - mov r5, r4 - NUM_PUSH_REGS equ 2 - PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS)) - if (IS_CDECL gt 0) - mov rState, [r4 + PARAM_OFFSET] - mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1] - mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2] - else ; fastcall - mov rNum, [r4 + PARAM_OFFSET] - endif - and r4, -16 - sub r4, LOCAL_SIZE - endif -endm - -MY_EPILOG macro - ifdef x64 - if (IS_LINUX eq 0) - movdqa xmm8, [r4] - movdqa xmm9, [r4 + 16] - add r4, LOCAL_SIZE + 8 - movdqa xmm6, [r4 + 8] - movdqa xmm7, [r4 + 8 + 16] - endif - else ; x86 - mov r4, r5 - pop r5 - pop r3 - endif - MY_ENDP -endm - - -msg equ xmm0 -tmp equ xmm0 -state0_N equ 2 -state1_N equ 3 -w_regs equ 4 - - -state1_save equ xmm1 -state0 equ @CatStr(xmm, %state0_N) -state1 equ @CatStr(xmm, %state1_N) - - -ifdef x64 - state0_save equ xmm8 - mask2 equ xmm9 -else - state0_save equ [r4] - mask2 equ xmm0 -endif - -LOAD_MASK macro - movdqa mask2, XMMWORD PTR Reverse_Endian_Mask -endm - -LOAD_W macro k:req - movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))] - pshufb @CatStr(xmm, %(w_regs + k)), mask2 -endm - - -; pre1 <= 4 && pre2 >= 1 && pre1 > pre2 && (pre1 - pre2) <= 1 -pre1 equ 3 -pre2 equ 2 - - - -RND4 macro k - movdqa msg, xmmword ptr [rTable + (k) * 16] - paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4))) - MY_sha256rnds2 state0_N, state1_N - pshufd msg, msg, 0eH - - if (k GE (4 - pre1)) AND (k LT (16 - pre1)) - ; w4[0] = msg1(w4[-4], w4[-3]) - MY_sha256msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4)) - endif - - MY_sha256rnds2 state1_N, state0_N - - if (k GE (4 - pre2)) AND (k LT (16 - pre2)) - movdqa tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 1) mod 4))) - palignr tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4))), 4 - paddd @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), tmp - ; w4[0] = msg2(w4[0], w4[-1]) - MY_sha256msg2 %(w_regs + ((k + pre2) mod 4)), %(w_regs + ((k + pre2 - 1) mod 4)) - endif -endm - - - - - -REVERSE_STATE macro - ; state0 ; dcba - ; state1 ; hgfe - pshufd tmp, state0, 01bH ; abcd - pshufd state0, state1, 01bH ; efgh - movdqa state1, state0 ; efgh - punpcklqdq state0, tmp ; cdgh - punpckhqdq state1, tmp ; abef -endm - - -MY_PROC Sha256_UpdateBlocks_HW, 3 - MY_PROLOG - - lea rTable, [K_CONST] - - cmp rNum, 0 - je end_c - - movdqu state0, [rState] ; dcba - movdqu state1, [rState + 16] ; hgfe - - REVERSE_STATE - - ifdef x64 - LOAD_MASK - endif - - align 16 - nextBlock: - movdqa state0_save, state0 - movdqa state1_save, state1 - - ifndef x64 - LOAD_MASK - endif - - LOAD_W 0 - LOAD_W 1 - LOAD_W 2 - LOAD_W 3 - - - k = 0 - rept 16 - RND4 k - k = k + 1 - endm - - paddd state0, state0_save - paddd state1, state1_save - - add rData, 64 - sub rNum, 1 - jnz nextBlock - - REVERSE_STATE - - movdqu [rState], state0 - movdqu [rState + 16], state1 - - end_c: -MY_EPILOG - -; _TEXT$SHA256OPT ENDS - -end +; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions +; 2024-06-16 : Igor Pavlov : Public domain + +include 7zAsm.asm + +MY_ASM_START + +; .data +; public K + +; we can use external SHA256_K_ARRAY defined in Sha256.c +; but we must guarantee that SHA256_K_ARRAY is aligned for 16-bytes + +COMMENT @ +ifdef x64 +K_CONST equ SHA256_K_ARRAY +else +K_CONST equ _SHA256_K_ARRAY +endif +EXTRN K_CONST:xmmword +@ + +CONST SEGMENT READONLY + +align 16 +Reverse_Endian_Mask db 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12 + +; COMMENT @ +align 16 +K_CONST \ +DD 0428a2f98H, 071374491H, 0b5c0fbcfH, 0e9b5dba5H +DD 03956c25bH, 059f111f1H, 0923f82a4H, 0ab1c5ed5H +DD 0d807aa98H, 012835b01H, 0243185beH, 0550c7dc3H +DD 072be5d74H, 080deb1feH, 09bdc06a7H, 0c19bf174H +DD 0e49b69c1H, 0efbe4786H, 00fc19dc6H, 0240ca1ccH +DD 02de92c6fH, 04a7484aaH, 05cb0a9dcH, 076f988daH +DD 0983e5152H, 0a831c66dH, 0b00327c8H, 0bf597fc7H +DD 0c6e00bf3H, 0d5a79147H, 006ca6351H, 014292967H +DD 027b70a85H, 02e1b2138H, 04d2c6dfcH, 053380d13H +DD 0650a7354H, 0766a0abbH, 081c2c92eH, 092722c85H +DD 0a2bfe8a1H, 0a81a664bH, 0c24b8b70H, 0c76c51a3H +DD 0d192e819H, 0d6990624H, 0f40e3585H, 0106aa070H +DD 019a4c116H, 01e376c08H, 02748774cH, 034b0bcb5H +DD 0391c0cb3H, 04ed8aa4aH, 05b9cca4fH, 0682e6ff3H +DD 0748f82eeH, 078a5636fH, 084c87814H, 08cc70208H +DD 090befffaH, 0a4506cebH, 0bef9a3f7H, 0c67178f2H +; @ + +CONST ENDS + +; _TEXT$SHA256OPT SEGMENT 'CODE' + +ifndef x64 + .686 + .xmm +endif + +; jwasm-based assemblers for linux and linker from new versions of binutils +; can generate incorrect code for load [ARRAY + offset] instructions. +; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem + rTable equ r0 + ; rTable equ K_CONST + +ifdef x64 + rNum equ REG_ABI_PARAM_2 + if (IS_LINUX eq 0) + LOCAL_SIZE equ (16 * 2) + endif +else + rNum equ r3 + LOCAL_SIZE equ (16 * 1) +endif + +rState equ REG_ABI_PARAM_0 +rData equ REG_ABI_PARAM_1 + + + + + + +MY_SHA_INSTR macro cmd, a1, a2 + db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2) +endm + +cmd_sha256rnds2 equ 0cbH +cmd_sha256msg1 equ 0ccH +cmd_sha256msg2 equ 0cdH + +MY_sha256rnds2 macro a1, a2 + MY_SHA_INSTR cmd_sha256rnds2, a1, a2 +endm + +MY_sha256msg1 macro a1, a2 + MY_SHA_INSTR cmd_sha256msg1, a1, a2 +endm + +MY_sha256msg2 macro a1, a2 + MY_SHA_INSTR cmd_sha256msg2, a1, a2 +endm + +MY_PROLOG macro + ifdef x64 + if (IS_LINUX eq 0) + movdqa [r4 + 8], xmm6 + movdqa [r4 + 8 + 16], xmm7 + sub r4, LOCAL_SIZE + 8 + movdqa [r4 ], xmm8 + movdqa [r4 + 16], xmm9 + endif + else ; x86 + push r3 + push r5 + mov r5, r4 + NUM_PUSH_REGS equ 2 + PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS)) + if (IS_CDECL gt 0) + mov rState, [r4 + PARAM_OFFSET] + mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1] + mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2] + else ; fastcall + mov rNum, [r4 + PARAM_OFFSET] + endif + and r4, -16 + sub r4, LOCAL_SIZE + endif +endm + +MY_EPILOG macro + ifdef x64 + if (IS_LINUX eq 0) + movdqa xmm8, [r4] + movdqa xmm9, [r4 + 16] + add r4, LOCAL_SIZE + 8 + movdqa xmm6, [r4 + 8] + movdqa xmm7, [r4 + 8 + 16] + endif + else ; x86 + mov r4, r5 + pop r5 + pop r3 + endif + MY_ENDP +endm + + +msg equ xmm0 +tmp equ xmm0 +state0_N equ 2 +state1_N equ 3 +w_regs equ 4 + + +state1_save equ xmm1 +state0 equ @CatStr(xmm, %state0_N) +state1 equ @CatStr(xmm, %state1_N) + + +ifdef x64 + state0_save equ xmm8 + mask2 equ xmm9 +else + state0_save equ [r4] + mask2 equ xmm0 +endif + +LOAD_MASK macro + movdqa mask2, XMMWORD PTR Reverse_Endian_Mask +endm + +LOAD_W macro k:req + movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))] + pshufb @CatStr(xmm, %(w_regs + k)), mask2 +endm + + +; pre1 <= 4 && pre2 >= 1 && pre1 > pre2 && (pre1 - pre2) <= 1 +pre1 equ 3 +pre2 equ 2 + + + +RND4 macro k + movdqa msg, xmmword ptr [rTable + (k) * 16] + paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4))) + MY_sha256rnds2 state0_N, state1_N + pshufd msg, msg, 0eH + + if (k GE (4 - pre1)) AND (k LT (16 - pre1)) + ; w4[0] = msg1(w4[-4], w4[-3]) + MY_sha256msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4)) + endif + + MY_sha256rnds2 state1_N, state0_N + + if (k GE (4 - pre2)) AND (k LT (16 - pre2)) + movdqa tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 1) mod 4))) + palignr tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4))), 4 + paddd @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), tmp + ; w4[0] = msg2(w4[0], w4[-1]) + MY_sha256msg2 %(w_regs + ((k + pre2) mod 4)), %(w_regs + ((k + pre2 - 1) mod 4)) + endif +endm + + + + + +REVERSE_STATE macro + ; state0 ; dcba + ; state1 ; hgfe + pshufd tmp, state0, 01bH ; abcd + pshufd state0, state1, 01bH ; efgh + movdqa state1, state0 ; efgh + punpcklqdq state0, tmp ; cdgh + punpckhqdq state1, tmp ; abef +endm + + +MY_PROC Sha256_UpdateBlocks_HW, 3 + MY_PROLOG + + lea rTable, [K_CONST] + + cmp rNum, 0 + je end_c + + movdqu state0, [rState] ; dcba + movdqu state1, [rState + 16] ; hgfe + + REVERSE_STATE + + ifdef x64 + LOAD_MASK + endif + + align 16 + nextBlock: + movdqa state0_save, state0 + movdqa state1_save, state1 + + ifndef x64 + LOAD_MASK + endif + + LOAD_W 0 + LOAD_W 1 + LOAD_W 2 + LOAD_W 3 + + + k = 0 + rept 16 + RND4 k + k = k + 1 + endm + + paddd state0, state0_save + paddd state1, state1_save + + add rData, 64 + sub rNum, 1 + jnz nextBlock + + REVERSE_STATE + + movdqu [rState], state0 + movdqu [rState + 16], state1 + + end_c: +MY_EPILOG + +; _TEXT$SHA256OPT ENDS + +end diff --git a/Asm/x86/XzCrc64Opt.asm b/Asm/x86/XzCrc64Opt.asm index de023f9f4..283424c62 100644 --- a/Asm/x86/XzCrc64Opt.asm +++ b/Asm/x86/XzCrc64Opt.asm @@ -1,523 +1,523 @@ -; XzCrc64Opt.asm -- CRC64 calculation : optimized version -; 2023-12-08 : Igor Pavlov : Public domain - -include 7zAsm.asm - -MY_ASM_START - -NUM_WORDS equ 3 - -if (NUM_WORDS lt 1) or (NUM_WORDS gt 64) -.err -endif - -NUM_SKIP_BYTES equ ((NUM_WORDS - 2) * 4) - - -MOVZXLO macro dest:req, src:req - movzx dest, @CatStr(src, _L) -endm - -MOVZXHI macro dest:req, src:req - movzx dest, @CatStr(src, _H) -endm - - -ifdef x64 - -rD equ r11 -rN equ r10 -rT equ r9 - -CRC_OP macro op:req, dest:req, src:req, t:req - op dest, QWORD PTR [rT + @CatStr(src, _R) * 8 + 0800h * (t)] -endm - -CRC_XOR macro dest:req, src:req, t:req - CRC_OP xor, dest, src, t -endm - -CRC_MOV macro dest:req, src:req, t:req - CRC_OP mov, dest, src, t -endm - -CRC1b macro - movzx x6, BYTE PTR [rD] - inc rD - MOVZXLO x3, x0 - xor x6, x3 - shr r0, 8 - CRC_XOR r0, x6, 0 - dec rN -endm - - -; ALIGN_MASK is 3 or 7 bytes alignment: -ALIGN_MASK equ (7 - (NUM_WORDS and 1) * 4) - -if NUM_WORDS eq 1 - -src_rN_offset equ 4 -; + 4 for prefetching next 4-bytes after current iteration -NUM_BYTES_LIMIT equ (NUM_WORDS * 4 + 4) -SRCDAT4 equ DWORD PTR [rN + rD * 1] - -XOR_NEXT macro - mov x1, [rD] - xor r0, r1 -endm - -else ; NUM_WORDS > 1 - -src_rN_offset equ 8 -; + 8 for prefetching next 8-bytes after current iteration -NUM_BYTES_LIMIT equ (NUM_WORDS * 4 + 8) - -XOR_NEXT macro - xor r0, QWORD PTR [rD] ; 64-bit read, can be unaligned -endm - -; 32-bit or 64-bit -LOAD_SRC_MULT4 macro dest:req, word_index:req - mov dest, [rN + rD * 1 + 4 * (word_index) - src_rN_offset]; -endm - -endif - - - -MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 4 - MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 - - mov r0, REG_ABI_PARAM_0 ; r0 <- r1 / r7 - mov rD, REG_ABI_PARAM_1 ; r11 <- r2 / r6 - mov rN, REG_ABI_PARAM_2 ; r10 <- r8 / r2 -if (IS_LINUX gt 0) - mov rT, REG_ABI_PARAM_3 ; r9 <- r9 / r1 -endif - - cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK - jb crc_end -@@: - test rD, ALIGN_MASK - jz @F - CRC1b - jmp @B -@@: - XOR_NEXT - lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)] - sub rD, rN - add rN, src_rN_offset - -align 16 -@@: - -if NUM_WORDS eq 1 - - mov x1, x0 - shr x1, 8 - MOVZXLO x3, x1 - MOVZXLO x2, x0 - shr x1, 8 - shr r0, 32 - xor x0, SRCDAT4 - CRC_XOR r0, x2, 3 - CRC_XOR r0, x3, 2 - MOVZXLO x2, x1 - shr x1, 8 - CRC_XOR r0, x2, 1 - CRC_XOR r0, x1, 0 - -else ; NUM_WORDS > 1 - -if NUM_WORDS ne 2 - k = 2 - while k lt NUM_WORDS - - LOAD_SRC_MULT4 x1, k - crc_op1 textequ - - if k eq 2 - if (NUM_WORDS and 1) - LOAD_SRC_MULT4 x7, NUM_WORDS ; aligned 32-bit - LOAD_SRC_MULT4 x6, NUM_WORDS + 1 ; aligned 32-bit - shl r6, 32 - else - LOAD_SRC_MULT4 r6, NUM_WORDS ; aligned 64-bit - crc_op1 textequ - endif - endif - table = 4 * (NUM_WORDS - 1 - k) - MOVZXLO x3, x1 - CRC_OP crc_op1, r7, x3, 3 + table - MOVZXHI x3, x1 - shr x1, 16 - CRC_XOR r6, x3, 2 + table - MOVZXLO x3, x1 - shr x1, 8 - CRC_XOR r7, x3, 1 + table - CRC_XOR r6, x1, 0 + table - k = k + 1 - endm - crc_op2 textequ - -else ; NUM_WORDS == 2 - LOAD_SRC_MULT4 r6, NUM_WORDS ; aligned 64-bit - crc_op2 textequ -endif ; NUM_WORDS == 2 - - MOVZXHI x3, x0 - MOVZXLO x2, x0 - mov r1, r0 - shr r1, 32 - shr x0, 16 - CRC_XOR r6, x2, NUM_SKIP_BYTES + 7 - CRC_OP crc_op2, r7, x3, NUM_SKIP_BYTES + 6 - MOVZXLO x2, x0 - MOVZXHI x5, x1 - MOVZXLO x3, x1 - shr x0, 8 - shr x1, 16 - CRC_XOR r7, x2, NUM_SKIP_BYTES + 5 - CRC_XOR r6, x3, NUM_SKIP_BYTES + 3 - CRC_XOR r7, x0, NUM_SKIP_BYTES + 4 - CRC_XOR r6, x5, NUM_SKIP_BYTES + 2 - MOVZXLO x2, x1 - shr x1, 8 - CRC_XOR r7, x2, NUM_SKIP_BYTES + 1 - CRC_MOV r0, x1, NUM_SKIP_BYTES + 0 - xor r0, r6 - xor r0, r7 - -endif ; NUM_WORDS > 1 - add rD, NUM_WORDS * 4 - jnc @B - - sub rN, src_rN_offset - add rD, rN - XOR_NEXT - add rN, NUM_BYTES_LIMIT - 1 - sub rN, rD - -crc_end: - test rN, rN - jz func_end -@@: - CRC1b - jnz @B -func_end: - MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 -MY_ENDP - - - -else -; ================================================================== -; x86 (32-bit) - -rD equ r7 -rN equ r1 -rT equ r5 - -xA equ x6 -xA_R equ r6 - -ifdef x64 - num_VAR equ r8 -else - -crc_OFFS equ (REG_SIZE * 5) - -if (IS_CDECL gt 0) or (IS_LINUX gt 0) - ; cdecl or (GNU fastcall) stack: - ; (UInt32 *) table - ; size_t size - ; void * data - ; (UInt64) crc - ; ret-ip <-(r4) - data_OFFS equ (8 + crc_OFFS) - size_OFFS equ (REG_SIZE + data_OFFS) - table_OFFS equ (REG_SIZE + size_OFFS) - num_VAR equ [r4 + size_OFFS] - table_VAR equ [r4 + table_OFFS] -else - ; Windows fastcall: - ; r1 = data, r2 = size - ; stack: - ; (UInt32 *) table - ; (UInt64) crc - ; ret-ip <-(r4) - table_OFFS equ (8 + crc_OFFS) - table_VAR equ [r4 + table_OFFS] - num_VAR equ table_VAR -endif -endif ; x64 - -SRCDAT4 equ DWORD PTR [rN + rD * 1] - -CRC_1 macro op:req, dest:req, src:req, t:req, word_index:req - op dest, DWORD PTR [rT + @CatStr(src, _R) * 8 + 0800h * (t) + (word_index) * 4] -endm - -CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req - CRC_1 op0, dest0, src, t, 0 - CRC_1 op1, dest1, src, t, 1 -endm - -CRC_XOR macro dest0:req, dest1:req, src:req, t:req - CRC xor, xor, dest0, dest1, src, t -endm - - -CRC1b macro - movzx xA, BYTE PTR [rD] - inc rD - MOVZXLO x3, x0 - xor xA, x3 - shrd x0, x2, 8 - shr x2, 8 - CRC_XOR x0, x2, xA, 0 - dec rN -endm - - -MY_PROLOG_BASE macro - MY_PUSH_4_REGS -ifdef x64 - mov r0, REG_ABI_PARAM_0 ; r0 <- r1 / r7 - mov rT, REG_ABI_PARAM_3 ; r5 <- r9 / r1 - mov rN, REG_ABI_PARAM_2 ; r1 <- r8 / r2 - mov rD, REG_ABI_PARAM_1 ; r7 <- r2 / r6 - mov r2, r0 - shr r2, 32 - mov x0, x0 -else - if (IS_CDECL gt 0) or (IS_LINUX gt 0) - proc_numParams = proc_numParams + 2 ; for ABI_LINUX - mov rN, [r4 + size_OFFS] - mov rD, [r4 + data_OFFS] - else - mov rD, REG_ABI_PARAM_0 ; r7 <- r1 : (data) - mov rN, REG_ABI_PARAM_1 ; r1 <- r2 : (size) - endif - mov x0, [r4 + crc_OFFS] - mov x2, [r4 + crc_OFFS + 4] - mov rT, table_VAR -endif -endm - - -MY_EPILOG_BASE macro crc_end:req, func_end:req -crc_end: - test rN, rN - jz func_end -@@: - CRC1b - jnz @B -func_end: -ifdef x64 - shl r2, 32 - xor r0, r2 -endif - MY_POP_4_REGS -endm - - -; ALIGN_MASK is 3 or 7 bytes alignment: -ALIGN_MASK equ (7 - (NUM_WORDS and 1) * 4) - -if (NUM_WORDS eq 1) - -NUM_BYTES_LIMIT_T4 equ (NUM_WORDS * 4 + 4) - -MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 5 - MY_PROLOG_BASE - - cmp rN, NUM_BYTES_LIMIT_T4 + ALIGN_MASK - jb crc_end_4 -@@: - test rD, ALIGN_MASK - jz @F - CRC1b - jmp @B -@@: - xor x0, [rD] - lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT_T4 - 1)] - sub rD, rN - add rN, 4 - - MOVZXLO xA, x0 -align 16 -@@: - mov x3, SRCDAT4 - xor x3, x2 - shr x0, 8 - CRC xor, mov, x3, x2, xA, 3 - MOVZXLO xA, x0 - shr x0, 8 - ; MOVZXHI xA, x0 - ; shr x0, 16 - CRC_XOR x3, x2, xA, 2 - - MOVZXLO xA, x0 - shr x0, 8 - CRC_XOR x3, x2, xA, 1 - CRC_XOR x3, x2, x0, 0 - MOVZXLO xA, x3 - mov x0, x3 - - add rD, 4 - jnc @B - - sub rN, 4 - add rD, rN - xor x0, [rD] - add rN, NUM_BYTES_LIMIT_T4 - 1 - sub rN, rD - MY_EPILOG_BASE crc_end_4, func_end_4 -MY_ENDP - -else ; NUM_WORDS > 1 - -SHR_X macro x, imm - shr x, imm -endm - - -ITER_1 macro v0, v1, a, off - MOVZXLO xA, a - SHR_X a, 8 - CRC_XOR v0, v1, xA, off -endm - - -ITER_4 macro v0, v1, a, off -if 0 eq 0 - ITER_1 v0, v1, a, off + 3 - ITER_1 v0, v1, a, off + 2 - ITER_1 v0, v1, a, off + 1 - CRC_XOR v0, v1, a, off -elseif 0 eq 0 - MOVZXLO xA, a - CRC_XOR v0, v1, xA, off + 3 - mov xA, a - ror a, 16 ; 32-bit ror - shr xA, 24 - CRC_XOR v0, v1, xA, off - MOVZXLO xA, a - SHR_X a, 24 - CRC_XOR v0, v1, xA, off + 1 - CRC_XOR v0, v1, a, off + 2 -else - ; MOVZXHI provides smaller code, but MOVZX_HI_BYTE is not fast instruction - MOVZXLO xA, a - CRC_XOR v0, v1, xA, off + 3 - MOVZXHI xA, a - SHR_X a, 16 - CRC_XOR v0, v1, xA, off + 2 - MOVZXLO xA, a - SHR_X a, 8 - CRC_XOR v0, v1, xA, off + 1 - CRC_XOR v0, v1, a, off -endif -endm - - - -ITER_1_PAIR macro v0, v1, a0, a1, off - ITER_1 v0, v1, a0, off + 4 - ITER_1 v0, v1, a1, off -endm - -src_rD_offset equ 8 -STEP_SIZE equ (NUM_WORDS * 4) - -ITER_12_NEXT macro op, index, v0, v1 - op v0, DWORD PTR [rD + (index + 1) * STEP_SIZE - src_rD_offset] - op v1, DWORD PTR [rD + (index + 1) * STEP_SIZE + 4 - src_rD_offset] -endm - -ITER_12 macro index, a0, a1, v0, v1 - - if NUM_SKIP_BYTES eq 0 - ITER_12_NEXT mov, index, v0, v1 - else - k = 0 - while k lt NUM_SKIP_BYTES - movzx xA, BYTE PTR [rD + (index) * STEP_SIZE + k + 8 - src_rD_offset] - if k eq 0 - CRC mov, mov, v0, v1, xA, NUM_SKIP_BYTES - 1 - k - else - CRC_XOR v0, v1, xA, NUM_SKIP_BYTES - 1 - k - endif - k = k + 1 - endm - ITER_12_NEXT xor, index, v0, v1 - endif - -if 0 eq 0 - ITER_4 v0, v1, a0, NUM_SKIP_BYTES + 4 - ITER_4 v0, v1, a1, NUM_SKIP_BYTES -else ; interleave version is faster/slower for different processors - ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 3 - ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 2 - ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 1 - CRC_XOR v0, v1, a0, NUM_SKIP_BYTES + 4 - CRC_XOR v0, v1, a1, NUM_SKIP_BYTES -endif -endm - -; we use (UNROLL_CNT > 1) to reduce read ports pressure (num_VAR reads) -UNROLL_CNT equ (2 * 1) -NUM_BYTES_LIMIT equ (STEP_SIZE * UNROLL_CNT + 8) - -MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 5 - MY_PROLOG_BASE - - cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK - jb crc_end_12 -@@: - test rD, ALIGN_MASK - jz @F - CRC1b - jmp @B -@@: - xor x0, [rD] - xor x2, [rD + 4] - add rD, src_rD_offset - lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)] - mov num_VAR, rN - -align 16 -@@: - i = 0 - rept UNROLL_CNT - if (i and 1) eq 0 - ITER_12 i, x0, x2, x1, x3 - else - ITER_12 i, x1, x3, x0, x2 - endif - i = i + 1 - endm - - if (UNROLL_CNT and 1) - mov x0, x1 - mov x2, x3 - endif - add rD, STEP_SIZE * UNROLL_CNT - cmp rD, num_VAR - jb @B - - mov rN, num_VAR - add rN, NUM_BYTES_LIMIT - 1 - sub rN, rD - sub rD, src_rD_offset - xor x0, [rD] - xor x2, [rD + 4] - - MY_EPILOG_BASE crc_end_12, func_end_12 -MY_ENDP - -endif ; (NUM_WORDS > 1) -endif ; ! x64 -end +; XzCrc64Opt.asm -- CRC64 calculation : optimized version +; 2023-12-08 : Igor Pavlov : Public domain + +include 7zAsm.asm + +MY_ASM_START + +NUM_WORDS equ 3 + +if (NUM_WORDS lt 1) or (NUM_WORDS gt 64) +.err +endif + +NUM_SKIP_BYTES equ ((NUM_WORDS - 2) * 4) + + +MOVZXLO macro dest:req, src:req + movzx dest, @CatStr(src, _L) +endm + +MOVZXHI macro dest:req, src:req + movzx dest, @CatStr(src, _H) +endm + + +ifdef x64 + +rD equ r11 +rN equ r10 +rT equ r9 + +CRC_OP macro op:req, dest:req, src:req, t:req + op dest, QWORD PTR [rT + @CatStr(src, _R) * 8 + 0800h * (t)] +endm + +CRC_XOR macro dest:req, src:req, t:req + CRC_OP xor, dest, src, t +endm + +CRC_MOV macro dest:req, src:req, t:req + CRC_OP mov, dest, src, t +endm + +CRC1b macro + movzx x6, BYTE PTR [rD] + inc rD + MOVZXLO x3, x0 + xor x6, x3 + shr r0, 8 + CRC_XOR r0, x6, 0 + dec rN +endm + + +; ALIGN_MASK is 3 or 7 bytes alignment: +ALIGN_MASK equ (7 - (NUM_WORDS and 1) * 4) + +if NUM_WORDS eq 1 + +src_rN_offset equ 4 +; + 4 for prefetching next 4-bytes after current iteration +NUM_BYTES_LIMIT equ (NUM_WORDS * 4 + 4) +SRCDAT4 equ DWORD PTR [rN + rD * 1] + +XOR_NEXT macro + mov x1, [rD] + xor r0, r1 +endm + +else ; NUM_WORDS > 1 + +src_rN_offset equ 8 +; + 8 for prefetching next 8-bytes after current iteration +NUM_BYTES_LIMIT equ (NUM_WORDS * 4 + 8) + +XOR_NEXT macro + xor r0, QWORD PTR [rD] ; 64-bit read, can be unaligned +endm + +; 32-bit or 64-bit +LOAD_SRC_MULT4 macro dest:req, word_index:req + mov dest, [rN + rD * 1 + 4 * (word_index) - src_rN_offset]; +endm + +endif + + + +MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 4 + MY_PUSH_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 + + mov r0, REG_ABI_PARAM_0 ; r0 <- r1 / r7 + mov rD, REG_ABI_PARAM_1 ; r11 <- r2 / r6 + mov rN, REG_ABI_PARAM_2 ; r10 <- r8 / r2 +if (IS_LINUX gt 0) + mov rT, REG_ABI_PARAM_3 ; r9 <- r9 / r1 +endif + + cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK + jb crc_end +@@: + test rD, ALIGN_MASK + jz @F + CRC1b + jmp @B +@@: + XOR_NEXT + lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)] + sub rD, rN + add rN, src_rN_offset + +align 16 +@@: + +if NUM_WORDS eq 1 + + mov x1, x0 + shr x1, 8 + MOVZXLO x3, x1 + MOVZXLO x2, x0 + shr x1, 8 + shr r0, 32 + xor x0, SRCDAT4 + CRC_XOR r0, x2, 3 + CRC_XOR r0, x3, 2 + MOVZXLO x2, x1 + shr x1, 8 + CRC_XOR r0, x2, 1 + CRC_XOR r0, x1, 0 + +else ; NUM_WORDS > 1 + +if NUM_WORDS ne 2 + k = 2 + while k lt NUM_WORDS + + LOAD_SRC_MULT4 x1, k + crc_op1 textequ + + if k eq 2 + if (NUM_WORDS and 1) + LOAD_SRC_MULT4 x7, NUM_WORDS ; aligned 32-bit + LOAD_SRC_MULT4 x6, NUM_WORDS + 1 ; aligned 32-bit + shl r6, 32 + else + LOAD_SRC_MULT4 r6, NUM_WORDS ; aligned 64-bit + crc_op1 textequ + endif + endif + table = 4 * (NUM_WORDS - 1 - k) + MOVZXLO x3, x1 + CRC_OP crc_op1, r7, x3, 3 + table + MOVZXHI x3, x1 + shr x1, 16 + CRC_XOR r6, x3, 2 + table + MOVZXLO x3, x1 + shr x1, 8 + CRC_XOR r7, x3, 1 + table + CRC_XOR r6, x1, 0 + table + k = k + 1 + endm + crc_op2 textequ + +else ; NUM_WORDS == 2 + LOAD_SRC_MULT4 r6, NUM_WORDS ; aligned 64-bit + crc_op2 textequ +endif ; NUM_WORDS == 2 + + MOVZXHI x3, x0 + MOVZXLO x2, x0 + mov r1, r0 + shr r1, 32 + shr x0, 16 + CRC_XOR r6, x2, NUM_SKIP_BYTES + 7 + CRC_OP crc_op2, r7, x3, NUM_SKIP_BYTES + 6 + MOVZXLO x2, x0 + MOVZXHI x5, x1 + MOVZXLO x3, x1 + shr x0, 8 + shr x1, 16 + CRC_XOR r7, x2, NUM_SKIP_BYTES + 5 + CRC_XOR r6, x3, NUM_SKIP_BYTES + 3 + CRC_XOR r7, x0, NUM_SKIP_BYTES + 4 + CRC_XOR r6, x5, NUM_SKIP_BYTES + 2 + MOVZXLO x2, x1 + shr x1, 8 + CRC_XOR r7, x2, NUM_SKIP_BYTES + 1 + CRC_MOV r0, x1, NUM_SKIP_BYTES + 0 + xor r0, r6 + xor r0, r7 + +endif ; NUM_WORDS > 1 + add rD, NUM_WORDS * 4 + jnc @B + + sub rN, src_rN_offset + add rD, rN + XOR_NEXT + add rN, NUM_BYTES_LIMIT - 1 + sub rN, rD + +crc_end: + test rN, rN + jz func_end +@@: + CRC1b + jnz @B +func_end: + MY_POP_PRESERVED_ABI_REGS_UP_TO_INCLUDING_R11 +MY_ENDP + + + +else +; ================================================================== +; x86 (32-bit) + +rD equ r7 +rN equ r1 +rT equ r5 + +xA equ x6 +xA_R equ r6 + +ifdef x64 + num_VAR equ r8 +else + +crc_OFFS equ (REG_SIZE * 5) + +if (IS_CDECL gt 0) or (IS_LINUX gt 0) + ; cdecl or (GNU fastcall) stack: + ; (UInt32 *) table + ; size_t size + ; void * data + ; (UInt64) crc + ; ret-ip <-(r4) + data_OFFS equ (8 + crc_OFFS) + size_OFFS equ (REG_SIZE + data_OFFS) + table_OFFS equ (REG_SIZE + size_OFFS) + num_VAR equ [r4 + size_OFFS] + table_VAR equ [r4 + table_OFFS] +else + ; Windows fastcall: + ; r1 = data, r2 = size + ; stack: + ; (UInt32 *) table + ; (UInt64) crc + ; ret-ip <-(r4) + table_OFFS equ (8 + crc_OFFS) + table_VAR equ [r4 + table_OFFS] + num_VAR equ table_VAR +endif +endif ; x64 + +SRCDAT4 equ DWORD PTR [rN + rD * 1] + +CRC_1 macro op:req, dest:req, src:req, t:req, word_index:req + op dest, DWORD PTR [rT + @CatStr(src, _R) * 8 + 0800h * (t) + (word_index) * 4] +endm + +CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req + CRC_1 op0, dest0, src, t, 0 + CRC_1 op1, dest1, src, t, 1 +endm + +CRC_XOR macro dest0:req, dest1:req, src:req, t:req + CRC xor, xor, dest0, dest1, src, t +endm + + +CRC1b macro + movzx xA, BYTE PTR [rD] + inc rD + MOVZXLO x3, x0 + xor xA, x3 + shrd x0, x2, 8 + shr x2, 8 + CRC_XOR x0, x2, xA, 0 + dec rN +endm + + +MY_PROLOG_BASE macro + MY_PUSH_4_REGS +ifdef x64 + mov r0, REG_ABI_PARAM_0 ; r0 <- r1 / r7 + mov rT, REG_ABI_PARAM_3 ; r5 <- r9 / r1 + mov rN, REG_ABI_PARAM_2 ; r1 <- r8 / r2 + mov rD, REG_ABI_PARAM_1 ; r7 <- r2 / r6 + mov r2, r0 + shr r2, 32 + mov x0, x0 +else + if (IS_CDECL gt 0) or (IS_LINUX gt 0) + proc_numParams = proc_numParams + 2 ; for ABI_LINUX + mov rN, [r4 + size_OFFS] + mov rD, [r4 + data_OFFS] + else + mov rD, REG_ABI_PARAM_0 ; r7 <- r1 : (data) + mov rN, REG_ABI_PARAM_1 ; r1 <- r2 : (size) + endif + mov x0, [r4 + crc_OFFS] + mov x2, [r4 + crc_OFFS + 4] + mov rT, table_VAR +endif +endm + + +MY_EPILOG_BASE macro crc_end:req, func_end:req +crc_end: + test rN, rN + jz func_end +@@: + CRC1b + jnz @B +func_end: +ifdef x64 + shl r2, 32 + xor r0, r2 +endif + MY_POP_4_REGS +endm + + +; ALIGN_MASK is 3 or 7 bytes alignment: +ALIGN_MASK equ (7 - (NUM_WORDS and 1) * 4) + +if (NUM_WORDS eq 1) + +NUM_BYTES_LIMIT_T4 equ (NUM_WORDS * 4 + 4) + +MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 5 + MY_PROLOG_BASE + + cmp rN, NUM_BYTES_LIMIT_T4 + ALIGN_MASK + jb crc_end_4 +@@: + test rD, ALIGN_MASK + jz @F + CRC1b + jmp @B +@@: + xor x0, [rD] + lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT_T4 - 1)] + sub rD, rN + add rN, 4 + + MOVZXLO xA, x0 +align 16 +@@: + mov x3, SRCDAT4 + xor x3, x2 + shr x0, 8 + CRC xor, mov, x3, x2, xA, 3 + MOVZXLO xA, x0 + shr x0, 8 + ; MOVZXHI xA, x0 + ; shr x0, 16 + CRC_XOR x3, x2, xA, 2 + + MOVZXLO xA, x0 + shr x0, 8 + CRC_XOR x3, x2, xA, 1 + CRC_XOR x3, x2, x0, 0 + MOVZXLO xA, x3 + mov x0, x3 + + add rD, 4 + jnc @B + + sub rN, 4 + add rD, rN + xor x0, [rD] + add rN, NUM_BYTES_LIMIT_T4 - 1 + sub rN, rD + MY_EPILOG_BASE crc_end_4, func_end_4 +MY_ENDP + +else ; NUM_WORDS > 1 + +SHR_X macro x, imm + shr x, imm +endm + + +ITER_1 macro v0, v1, a, off + MOVZXLO xA, a + SHR_X a, 8 + CRC_XOR v0, v1, xA, off +endm + + +ITER_4 macro v0, v1, a, off +if 0 eq 0 + ITER_1 v0, v1, a, off + 3 + ITER_1 v0, v1, a, off + 2 + ITER_1 v0, v1, a, off + 1 + CRC_XOR v0, v1, a, off +elseif 0 eq 0 + MOVZXLO xA, a + CRC_XOR v0, v1, xA, off + 3 + mov xA, a + ror a, 16 ; 32-bit ror + shr xA, 24 + CRC_XOR v0, v1, xA, off + MOVZXLO xA, a + SHR_X a, 24 + CRC_XOR v0, v1, xA, off + 1 + CRC_XOR v0, v1, a, off + 2 +else + ; MOVZXHI provides smaller code, but MOVZX_HI_BYTE is not fast instruction + MOVZXLO xA, a + CRC_XOR v0, v1, xA, off + 3 + MOVZXHI xA, a + SHR_X a, 16 + CRC_XOR v0, v1, xA, off + 2 + MOVZXLO xA, a + SHR_X a, 8 + CRC_XOR v0, v1, xA, off + 1 + CRC_XOR v0, v1, a, off +endif +endm + + + +ITER_1_PAIR macro v0, v1, a0, a1, off + ITER_1 v0, v1, a0, off + 4 + ITER_1 v0, v1, a1, off +endm + +src_rD_offset equ 8 +STEP_SIZE equ (NUM_WORDS * 4) + +ITER_12_NEXT macro op, index, v0, v1 + op v0, DWORD PTR [rD + (index + 1) * STEP_SIZE - src_rD_offset] + op v1, DWORD PTR [rD + (index + 1) * STEP_SIZE + 4 - src_rD_offset] +endm + +ITER_12 macro index, a0, a1, v0, v1 + + if NUM_SKIP_BYTES eq 0 + ITER_12_NEXT mov, index, v0, v1 + else + k = 0 + while k lt NUM_SKIP_BYTES + movzx xA, BYTE PTR [rD + (index) * STEP_SIZE + k + 8 - src_rD_offset] + if k eq 0 + CRC mov, mov, v0, v1, xA, NUM_SKIP_BYTES - 1 - k + else + CRC_XOR v0, v1, xA, NUM_SKIP_BYTES - 1 - k + endif + k = k + 1 + endm + ITER_12_NEXT xor, index, v0, v1 + endif + +if 0 eq 0 + ITER_4 v0, v1, a0, NUM_SKIP_BYTES + 4 + ITER_4 v0, v1, a1, NUM_SKIP_BYTES +else ; interleave version is faster/slower for different processors + ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 3 + ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 2 + ITER_1_PAIR v0, v1, a0, a1, NUM_SKIP_BYTES + 1 + CRC_XOR v0, v1, a0, NUM_SKIP_BYTES + 4 + CRC_XOR v0, v1, a1, NUM_SKIP_BYTES +endif +endm + +; we use (UNROLL_CNT > 1) to reduce read ports pressure (num_VAR reads) +UNROLL_CNT equ (2 * 1) +NUM_BYTES_LIMIT equ (STEP_SIZE * UNROLL_CNT + 8) + +MY_PROC @CatStr(XzCrc64UpdateT, %(NUM_WORDS * 4)), 5 + MY_PROLOG_BASE + + cmp rN, NUM_BYTES_LIMIT + ALIGN_MASK + jb crc_end_12 +@@: + test rD, ALIGN_MASK + jz @F + CRC1b + jmp @B +@@: + xor x0, [rD] + xor x2, [rD + 4] + add rD, src_rD_offset + lea rN, [rD + rN * 1 - (NUM_BYTES_LIMIT - 1)] + mov num_VAR, rN + +align 16 +@@: + i = 0 + rept UNROLL_CNT + if (i and 1) eq 0 + ITER_12 i, x0, x2, x1, x3 + else + ITER_12 i, x1, x3, x0, x2 + endif + i = i + 1 + endm + + if (UNROLL_CNT and 1) + mov x0, x1 + mov x2, x3 + endif + add rD, STEP_SIZE * UNROLL_CNT + cmp rD, num_VAR + jb @B + + mov rN, num_VAR + add rN, NUM_BYTES_LIMIT - 1 + sub rN, rD + sub rD, src_rD_offset + xor x0, [rD] + xor x2, [rD + 4] + + MY_EPILOG_BASE crc_end_12, func_end_12 +MY_ENDP + +endif ; (NUM_WORDS > 1) +endif ; ! x64 +end diff --git a/C/7z.h b/C/7z.h index b42405cc2..9e27c0152 100644 --- a/C/7z.h +++ b/C/7z.h @@ -1,204 +1,204 @@ -/* 7z.h -- 7z interface -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_7Z_H -#define ZIP7_INC_7Z_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define k7zStartHeaderSize 0x20 -#define k7zSignatureSize 6 - -extern const Byte k7zSignature[k7zSignatureSize]; - -typedef struct -{ - const Byte *Data; - size_t Size; -} CSzData; - -/* CSzCoderInfo & CSzFolder support only default methods */ - -typedef struct -{ - size_t PropsOffset; - UInt32 MethodID; - Byte NumStreams; - Byte PropsSize; -} CSzCoderInfo; - -typedef struct -{ - UInt32 InIndex; - UInt32 OutIndex; -} CSzBond; - -#define SZ_NUM_CODERS_IN_FOLDER_MAX 4 -#define SZ_NUM_BONDS_IN_FOLDER_MAX 3 -#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 - -typedef struct -{ - UInt32 NumCoders; - UInt32 NumBonds; - UInt32 NumPackStreams; - UInt32 UnpackStream; - UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; - CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; - CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; -} CSzFolder; - - -SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); - -typedef struct -{ - UInt32 Low; - UInt32 High; -} CNtfsFileTime; - -typedef struct -{ - Byte *Defs; /* MSB 0 bit numbering */ - UInt32 *Vals; -} CSzBitUi32s; - -typedef struct -{ - Byte *Defs; /* MSB 0 bit numbering */ - // UInt64 *Vals; - CNtfsFileTime *Vals; -} CSzBitUi64s; - -#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) - -#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) - -typedef struct -{ - UInt32 NumPackStreams; - UInt32 NumFolders; - - UInt64 *PackPositions; // NumPackStreams + 1 - CSzBitUi32s FolderCRCs; // NumFolders - - size_t *FoCodersOffsets; // NumFolders + 1 - UInt32 *FoStartPackStreamIndex; // NumFolders + 1 - UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 - Byte *FoToMainUnpackSizeIndex; // NumFolders - UInt64 *CoderUnpackSizes; // for all coders in all folders - - Byte *CodersData; - - UInt64 RangeLimit; -} CSzAr; - -UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); - -SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, - ILookInStreamPtr stream, UInt64 startPos, - Byte *outBuffer, size_t outSize, - ISzAllocPtr allocMain); - -typedef struct -{ - CSzAr db; - - UInt64 startPosAfterHeader; - UInt64 dataPos; - - UInt32 NumFiles; - - UInt64 *UnpackPositions; // NumFiles + 1 - // Byte *IsEmptyFiles; - Byte *IsDirs; - CSzBitUi32s CRCs; - - CSzBitUi32s Attribs; - // CSzBitUi32s Parents; - CSzBitUi64s MTime; - CSzBitUi64s CTime; - - UInt32 *FolderToFile; // NumFolders + 1 - UInt32 *FileToFolder; // NumFiles - - size_t *FileNameOffsets; /* in 2-byte steps */ - Byte *FileNames; /* UTF-16-LE */ -} CSzArEx; - -#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) - -#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) - -void SzArEx_Init(CSzArEx *p); -void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc); -UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); -int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); - -/* -if dest == NULL, the return value specifies the required size of the buffer, - in 16-bit characters, including the null-terminating character. -if dest != NULL, the return value specifies the number of 16-bit characters that - are written to the dest, including the null-terminating character. */ - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); - -/* -size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); -UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); -*/ - - - -/* - SzArEx_Extract extracts file from archive - - *outBuffer must be 0 before first call for each new archive. - - Extracting cache: - If you need to decompress more than one file, you can send - these values from previous call: - *blockIndex, - *outBuffer, - *outBufferSize - You can consider "*outBuffer" as cache of solid block. If your archive is solid, - it will increase decompression speed. - - If you use external function, you can declare these 3 cache variables - (blockIndex, outBuffer, outBufferSize) as static in that external function. - - Free *outBuffer and set *outBuffer to 0, if you want to flush cache. -*/ - -SRes SzArEx_Extract( - const CSzArEx *db, - ILookInStreamPtr inStream, - UInt32 fileIndex, /* index of file */ - UInt32 *blockIndex, /* index of solid block */ - Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ - size_t *outBufferSize, /* buffer size for output buffer */ - size_t *offset, /* offset of stream for required file in *outBuffer */ - size_t *outSizeProcessed, /* size of file in *outBuffer */ - ISzAllocPtr allocMain, - ISzAllocPtr allocTemp); - - -/* -SzArEx_Open Errors: -SZ_ERROR_NO_ARCHIVE -SZ_ERROR_ARCHIVE -SZ_ERROR_UNSUPPORTED -SZ_ERROR_MEM -SZ_ERROR_CRC -SZ_ERROR_INPUT_EOF -SZ_ERROR_FAIL -*/ - -SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream, - ISzAllocPtr allocMain, ISzAllocPtr allocTemp); - -EXTERN_C_END - -#endif +/* 7z.h -- 7z interface +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_H +#define ZIP7_INC_7Z_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define k7zStartHeaderSize 0x20 +#define k7zSignatureSize 6 + +extern const Byte k7zSignature[k7zSignatureSize]; + +typedef struct +{ + const Byte *Data; + size_t Size; +} CSzData; + +/* CSzCoderInfo & CSzFolder support only default methods */ + +typedef struct +{ + size_t PropsOffset; + UInt32 MethodID; + Byte NumStreams; + Byte PropsSize; +} CSzCoderInfo; + +typedef struct +{ + UInt32 InIndex; + UInt32 OutIndex; +} CSzBond; + +#define SZ_NUM_CODERS_IN_FOLDER_MAX 4 +#define SZ_NUM_BONDS_IN_FOLDER_MAX 3 +#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 + +typedef struct +{ + UInt32 NumCoders; + UInt32 NumBonds; + UInt32 NumPackStreams; + UInt32 UnpackStream; + UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; + CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; + CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; +} CSzFolder; + + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); + +typedef struct +{ + UInt32 Low; + UInt32 High; +} CNtfsFileTime; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + UInt32 *Vals; +} CSzBitUi32s; + +typedef struct +{ + Byte *Defs; /* MSB 0 bit numbering */ + // UInt64 *Vals; + CNtfsFileTime *Vals; +} CSzBitUi64s; + +#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0) + +typedef struct +{ + UInt32 NumPackStreams; + UInt32 NumFolders; + + UInt64 *PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders + + size_t *FoCodersOffsets; // NumFolders + 1 + UInt32 *FoStartPackStreamIndex; // NumFolders + 1 + UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 + Byte *FoToMainUnpackSizeIndex; // NumFolders + UInt64 *CoderUnpackSizes; // for all coders in all folders + + Byte *CodersData; + + UInt64 RangeLimit; +} CSzAr; + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStreamPtr stream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAllocPtr allocMain); + +typedef struct +{ + CSzAr db; + + UInt64 startPosAfterHeader; + UInt64 dataPos; + + UInt32 NumFiles; + + UInt64 *UnpackPositions; // NumFiles + 1 + // Byte *IsEmptyFiles; + Byte *IsDirs; + CSzBitUi32s CRCs; + + CSzBitUi32s Attribs; + // CSzBitUi32s Parents; + CSzBitUi64s MTime; + CSzBitUi64s CTime; + + UInt32 *FolderToFile; // NumFolders + 1 + UInt32 *FileToFolder; // NumFiles + + size_t *FileNameOffsets; /* in 2-byte steps */ + Byte *FileNames; /* UTF-16-LE */ +} CSzArEx; + +#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i)) + +#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i]) + +void SzArEx_Init(CSzArEx *p); +void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc); +UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder); +int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize); + +/* +if dest == NULL, the return value specifies the required size of the buffer, + in 16-bit characters, including the null-terminating character. +if dest != NULL, the return value specifies the number of 16-bit characters that + are written to the dest, including the null-terminating character. */ + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest); + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +*/ + + + +/* + SzArEx_Extract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. +*/ + +SRes SzArEx_Extract( + const CSzArEx *db, + ILookInStreamPtr inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp); + + +/* +SzArEx_Open Errors: +SZ_ERROR_NO_ARCHIVE +SZ_ERROR_ARCHIVE +SZ_ERROR_UNSUPPORTED +SZ_ERROR_MEM +SZ_ERROR_CRC +SZ_ERROR_INPUT_EOF +SZ_ERROR_FAIL +*/ + +SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream, + ISzAllocPtr allocMain, ISzAllocPtr allocTemp); + +EXTERN_C_END + +#endif diff --git a/C/7zAlloc.c b/C/7zAlloc.c index 3a8e2cbf4..2f0659af6 100644 --- a/C/7zAlloc.c +++ b/C/7zAlloc.c @@ -1,89 +1,89 @@ -/* 7zAlloc.c -- Allocation functions for 7z processing -2023-03-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "7zAlloc.h" - -/* #define SZ_ALLOC_DEBUG */ -/* use SZ_ALLOC_DEBUG to debug alloc/free operations */ - -#ifdef SZ_ALLOC_DEBUG - -/* -#ifdef _WIN32 -#include "7zWindows.h" -#endif -*/ - -#include -static int g_allocCount = 0; -static int g_allocCountTemp = 0; - -static void Print_Alloc(const char *s, size_t size, int *counter) -{ - const unsigned size2 = (unsigned)size; - fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2); - (*counter)++; -} -static void Print_Free(const char *s, int *counter) -{ - (*counter)--; - fprintf(stderr, "\n%s count = %10d", s, *counter); -} -#endif - -void *SzAlloc(ISzAllocPtr p, size_t size) -{ - UNUSED_VAR(p) - if (size == 0) - return 0; - #ifdef SZ_ALLOC_DEBUG - Print_Alloc("Alloc", size, &g_allocCount); - #endif - return malloc(size); -} - -void SzFree(ISzAllocPtr p, void *address) -{ - UNUSED_VAR(p) - #ifdef SZ_ALLOC_DEBUG - if (address) - Print_Free("Free ", &g_allocCount); - #endif - free(address); -} - -void *SzAllocTemp(ISzAllocPtr p, size_t size) -{ - UNUSED_VAR(p) - if (size == 0) - return 0; - #ifdef SZ_ALLOC_DEBUG - Print_Alloc("Alloc_temp", size, &g_allocCountTemp); - /* - #ifdef _WIN32 - return HeapAlloc(GetProcessHeap(), 0, size); - #endif - */ - #endif - return malloc(size); -} - -void SzFreeTemp(ISzAllocPtr p, void *address) -{ - UNUSED_VAR(p) - #ifdef SZ_ALLOC_DEBUG - if (address) - Print_Free("Free_temp ", &g_allocCountTemp); - /* - #ifdef _WIN32 - HeapFree(GetProcessHeap(), 0, address); - return; - #endif - */ - #endif - free(address); -} +/* 7zAlloc.c -- Allocation functions for 7z processing +2023-03-04 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zAlloc.h" + +/* #define SZ_ALLOC_DEBUG */ +/* use SZ_ALLOC_DEBUG to debug alloc/free operations */ + +#ifdef SZ_ALLOC_DEBUG + +/* +#ifdef _WIN32 +#include "7zWindows.h" +#endif +*/ + +#include +static int g_allocCount = 0; +static int g_allocCountTemp = 0; + +static void Print_Alloc(const char *s, size_t size, int *counter) +{ + const unsigned size2 = (unsigned)size; + fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2); + (*counter)++; +} +static void Print_Free(const char *s, int *counter) +{ + (*counter)--; + fprintf(stderr, "\n%s count = %10d", s, *counter); +} +#endif + +void *SzAlloc(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p) + if (size == 0) + return 0; + #ifdef SZ_ALLOC_DEBUG + Print_Alloc("Alloc", size, &g_allocCount); + #endif + return malloc(size); +} + +void SzFree(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p) + #ifdef SZ_ALLOC_DEBUG + if (address) + Print_Free("Free ", &g_allocCount); + #endif + free(address); +} + +void *SzAllocTemp(ISzAllocPtr p, size_t size) +{ + UNUSED_VAR(p) + if (size == 0) + return 0; + #ifdef SZ_ALLOC_DEBUG + Print_Alloc("Alloc_temp", size, &g_allocCountTemp); + /* + #ifdef _WIN32 + return HeapAlloc(GetProcessHeap(), 0, size); + #endif + */ + #endif + return malloc(size); +} + +void SzFreeTemp(ISzAllocPtr p, void *address) +{ + UNUSED_VAR(p) + #ifdef SZ_ALLOC_DEBUG + if (address) + Print_Free("Free_temp ", &g_allocCountTemp); + /* + #ifdef _WIN32 + HeapFree(GetProcessHeap(), 0, address); + return; + #endif + */ + #endif + free(address); +} diff --git a/C/7zAlloc.h b/C/7zAlloc.h index bedd125c0..b2b8b0cdd 100644 --- a/C/7zAlloc.h +++ b/C/7zAlloc.h @@ -1,19 +1,19 @@ -/* 7zAlloc.h -- Allocation functions -2023-03-04 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_7Z_ALLOC_H -#define ZIP7_INC_7Z_ALLOC_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -void *SzAlloc(ISzAllocPtr p, size_t size); -void SzFree(ISzAllocPtr p, void *address); - -void *SzAllocTemp(ISzAllocPtr p, size_t size); -void SzFreeTemp(ISzAllocPtr p, void *address); - -EXTERN_C_END - -#endif +/* 7zAlloc.h -- Allocation functions +2023-03-04 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_ALLOC_H +#define ZIP7_INC_7Z_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void *SzAlloc(ISzAllocPtr p, size_t size); +void SzFree(ISzAllocPtr p, void *address); + +void *SzAllocTemp(ISzAllocPtr p, size_t size); +void SzFreeTemp(ISzAllocPtr p, void *address); + +EXTERN_C_END + +#endif diff --git a/C/7zArcIn.c b/C/7zArcIn.c index 84a1c08d1..23f294992 100644 --- a/C/7zArcIn.c +++ b/C/7zArcIn.c @@ -1,1786 +1,1786 @@ -/* 7zArcIn.c -- 7z Input functions -2023-09-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "7z.h" -#include "7zBuf.h" -#include "7zCrc.h" -#include "CpuArch.h" - -#define MY_ALLOC(T, p, size, alloc) \ - { if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } - -#define MY_ALLOC_ZE(T, p, size, alloc) \ - { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } - -#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ - { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } - -#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ - { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } - -#define k7zMajorVersion 0 - -enum EIdEnum -{ - k7zIdEnd, - k7zIdHeader, - k7zIdArchiveProperties, - k7zIdAdditionalStreamsInfo, - k7zIdMainStreamsInfo, - k7zIdFilesInfo, - k7zIdPackInfo, - k7zIdUnpackInfo, - k7zIdSubStreamsInfo, - k7zIdSize, - k7zIdCRC, - k7zIdFolder, - k7zIdCodersUnpackSize, - k7zIdNumUnpackStream, - k7zIdEmptyStream, - k7zIdEmptyFile, - k7zIdAnti, - k7zIdName, - k7zIdCTime, - k7zIdATime, - k7zIdMTime, - k7zIdWinAttrib, - k7zIdComment, - k7zIdEncodedHeader, - k7zIdStartPos, - k7zIdDummy - // k7zNtSecure, - // k7zParent, - // k7zIsReal -}; - -const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - -#define SzBitUi32s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; } - -static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) -{ - if (num == 0) - { - p->Defs = NULL; - p->Vals = NULL; - } - else - { - MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc) - MY_ALLOC(UInt32, p->Vals, num, alloc) - } - return SZ_OK; -} - -static void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; - ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; -} - -#define SzBitUi64s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; } - -static void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; - ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; -} - - -static void SzAr_Init(CSzAr *p) -{ - p->NumPackStreams = 0; - p->NumFolders = 0; - - p->PackPositions = NULL; - SzBitUi32s_INIT(&p->FolderCRCs) - - p->FoCodersOffsets = NULL; - p->FoStartPackStreamIndex = NULL; - p->FoToCoderUnpackSizes = NULL; - p->FoToMainUnpackSizeIndex = NULL; - p->CoderUnpackSizes = NULL; - - p->CodersData = NULL; - - p->RangeLimit = 0; -} - -static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->PackPositions); - SzBitUi32s_Free(&p->FolderCRCs, alloc); - - ISzAlloc_Free(alloc, p->FoCodersOffsets); - ISzAlloc_Free(alloc, p->FoStartPackStreamIndex); - ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes); - ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); - ISzAlloc_Free(alloc, p->CoderUnpackSizes); - - ISzAlloc_Free(alloc, p->CodersData); - - SzAr_Init(p); -} - - -void SzArEx_Init(CSzArEx *p) -{ - SzAr_Init(&p->db); - - p->NumFiles = 0; - p->dataPos = 0; - - p->UnpackPositions = NULL; - p->IsDirs = NULL; - - p->FolderToFile = NULL; - p->FileToFolder = NULL; - - p->FileNameOffsets = NULL; - p->FileNames = NULL; - - SzBitUi32s_INIT(&p->CRCs) - SzBitUi32s_INIT(&p->Attribs) - // SzBitUi32s_INIT(&p->Parents) - SzBitUi64s_INIT(&p->MTime) - SzBitUi64s_INIT(&p->CTime) -} - -void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->UnpackPositions); - ISzAlloc_Free(alloc, p->IsDirs); - - ISzAlloc_Free(alloc, p->FolderToFile); - ISzAlloc_Free(alloc, p->FileToFolder); - - ISzAlloc_Free(alloc, p->FileNameOffsets); - ISzAlloc_Free(alloc, p->FileNames); - - SzBitUi32s_Free(&p->CRCs, alloc); - SzBitUi32s_Free(&p->Attribs, alloc); - // SzBitUi32s_Free(&p->Parents, alloc); - SzBitUi64s_Free(&p->MTime, alloc); - SzBitUi64s_Free(&p->CTime, alloc); - - SzAr_Free(&p->db, alloc); - SzArEx_Init(p); -} - - -static int TestSignatureCandidate(const Byte *testBytes) -{ - unsigned i; - for (i = 0; i < k7zSignatureSize; i++) - if (testBytes[i] != k7zSignature[i]) - return 0; - return 1; -} - -#define SzData_CLEAR(p) { (p)->Data = NULL; (p)->Size = 0; } - -#define SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) \ - (_sd_)->Size--; dest = *(_sd_)->Data++; - -#define SZ_READ_BYTE_SD(_sd_, dest) \ - if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; \ - SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) - -#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) - -#define SZ_READ_BYTE_2(dest) \ - if (sd.Size == 0) return SZ_ERROR_ARCHIVE; \ - sd.Size--; dest = *sd.Data++; - -#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } -#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } - -#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ - dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); - -static Z7_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) -{ - Byte firstByte, mask; - unsigned i; - UInt32 v; - - SZ_READ_BYTE(firstByte) - if ((firstByte & 0x80) == 0) - { - *value = firstByte; - return SZ_OK; - } - SZ_READ_BYTE(v) - if ((firstByte & 0x40) == 0) - { - *value = (((UInt32)firstByte & 0x3F) << 8) | v; - return SZ_OK; - } - SZ_READ_BYTE(mask) - *value = v | ((UInt32)mask << 8); - mask = 0x20; - for (i = 2; i < 8; i++) - { - Byte b; - if ((firstByte & mask) == 0) - { - const UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); - *value |= (highPart << (8 * i)); - return SZ_OK; - } - SZ_READ_BYTE(b) - *value |= ((UInt64)b << (8 * i)); - mask >>= 1; - } - return SZ_OK; -} - - -static Z7_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) -{ - Byte firstByte; - UInt64 value64; - if (sd->Size == 0) - return SZ_ERROR_ARCHIVE; - firstByte = *sd->Data; - if ((firstByte & 0x80) == 0) - { - *value = firstByte; - sd->Data++; - sd->Size--; - return SZ_OK; - } - RINOK(ReadNumber(sd, &value64)) - if (value64 >= (UInt32)0x80000000 - 1) - return SZ_ERROR_UNSUPPORTED; - if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) - return SZ_ERROR_UNSUPPORTED; - *value = (UInt32)value64; - return SZ_OK; -} - -#define ReadID(sd, value) ReadNumber(sd, value) - -static SRes SkipData(CSzData *sd) -{ - UInt64 size; - RINOK(ReadNumber(sd, &size)) - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA(sd, size) - return SZ_OK; -} - -static SRes WaitId(CSzData *sd, UInt32 id) -{ - for (;;) - { - UInt64 type; - RINOK(ReadID(sd, &type)) - if (type == id) - return SZ_OK; - if (type == k7zIdEnd) - return SZ_ERROR_ARCHIVE; - RINOK(SkipData(sd)) - } -} - -static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) -{ - const UInt32 numBytes = (numItems + 7) >> 3; - if (numBytes > sd->Size) - return SZ_ERROR_ARCHIVE; - *v = sd->Data; - SKIP_DATA(sd, numBytes) - return SZ_OK; -} - -static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) -{ - unsigned b = 0; - unsigned m = 0; - UInt32 sum = 0; - for (; numItems != 0; numItems--) - { - if (m == 0) - { - b = *bits++; - m = 8; - } - m--; - sum += (UInt32)((b >> m) & 1); - } - return sum; -} - -static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) -{ - Byte allAreDefined; - Byte *v2; - const UInt32 numBytes = (numItems + 7) >> 3; - *v = NULL; - SZ_READ_BYTE(allAreDefined) - if (numBytes == 0) - return SZ_OK; - if (allAreDefined == 0) - { - if (numBytes > sd->Size) - return SZ_ERROR_ARCHIVE; - MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc) - SKIP_DATA(sd, numBytes) - return SZ_OK; - } - MY_ALLOC(Byte, *v, numBytes, alloc) - v2 = *v; - memset(v2, 0xFF, (size_t)numBytes); - { - const unsigned numBits = (unsigned)numItems & 7; - if (numBits != 0) - v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); - } - return SZ_OK; -} - -static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) -{ - UInt32 i; - CSzData sd; - UInt32 *vals; - const Byte *defs; - MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc) - sd = *sd2; - defs = crcs->Defs; - vals = crcs->Vals; - for (i = 0; i < numItems; i++) - if (SzBitArray_Check(defs, i)) - { - SZ_READ_32(vals[i]) - } - else - vals[i] = 0; - *sd2 = sd; - return SZ_OK; -} - -static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) -{ - SzBitUi32s_Free(crcs, alloc); - RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)) - return ReadUi32s(sd, numItems, crcs, alloc); -} - -static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) -{ - Byte allAreDefined; - UInt32 numDefined = numItems; - SZ_READ_BYTE(allAreDefined) - if (!allAreDefined) - { - const size_t numBytes = (numItems + 7) >> 3; - if (numBytes > sd->Size) - return SZ_ERROR_ARCHIVE; - numDefined = CountDefinedBits(sd->Data, numItems); - SKIP_DATA(sd, numBytes) - } - if (numDefined > (sd->Size >> 2)) - return SZ_ERROR_ARCHIVE; - SKIP_DATA(sd, (size_t)numDefined * 4) - return SZ_OK; -} - -static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) -{ - RINOK(SzReadNumber32(sd, &p->NumPackStreams)) - - RINOK(WaitId(sd, k7zIdSize)) - MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc) - { - UInt64 sum = 0; - UInt32 i; - const UInt32 numPackStreams = p->NumPackStreams; - for (i = 0; i < numPackStreams; i++) - { - UInt64 packSize; - p->PackPositions[i] = sum; - RINOK(ReadNumber(sd, &packSize)) - sum += packSize; - if (sum < packSize) - return SZ_ERROR_ARCHIVE; - } - p->PackPositions[i] = sum; - } - - for (;;) - { - UInt64 type; - RINOK(ReadID(sd, &type)) - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - /* CRC of packed streams is unused now */ - RINOK(SkipBitUi32s(sd, p->NumPackStreams)) - continue; - } - RINOK(SkipData(sd)) - } -} - -/* -static SRes SzReadSwitch(CSzData *sd) -{ - Byte external; - RINOK(SzReadByte(sd, &external)); - return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; -} -*/ - -#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) - -SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) -{ - UInt32 numCoders, i; - UInt32 numInStreams = 0; - const Byte *dataStart = sd->Data; - - f->NumCoders = 0; - f->NumBonds = 0; - f->NumPackStreams = 0; - f->UnpackStream = 0; - - RINOK(SzReadNumber32(sd, &numCoders)) - if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - - for (i = 0; i < numCoders; i++) - { - Byte mainByte; - CSzCoderInfo *coder = f->Coders + i; - unsigned idSize, j; - UInt64 id; - - SZ_READ_BYTE(mainByte) - if ((mainByte & 0xC0) != 0) - return SZ_ERROR_UNSUPPORTED; - - idSize = (unsigned)(mainByte & 0xF); - if (idSize > sizeof(id)) - return SZ_ERROR_UNSUPPORTED; - if (idSize > sd->Size) - return SZ_ERROR_ARCHIVE; - id = 0; - for (j = 0; j < idSize; j++) - { - id = ((id << 8) | *sd->Data); - sd->Data++; - sd->Size--; - } - if (id > (UInt32)0xFFFFFFFF) - return SZ_ERROR_UNSUPPORTED; - coder->MethodID = (UInt32)id; - - coder->NumStreams = 1; - coder->PropsOffset = 0; - coder->PropsSize = 0; - - if ((mainByte & 0x10) != 0) - { - UInt32 numStreams; - - RINOK(SzReadNumber32(sd, &numStreams)) - if (numStreams > k_NumCodersStreams_in_Folder_MAX) - return SZ_ERROR_UNSUPPORTED; - coder->NumStreams = (Byte)numStreams; - - RINOK(SzReadNumber32(sd, &numStreams)) - if (numStreams != 1) - return SZ_ERROR_UNSUPPORTED; - } - - numInStreams += coder->NumStreams; - - if (numInStreams > k_NumCodersStreams_in_Folder_MAX) - return SZ_ERROR_UNSUPPORTED; - - if ((mainByte & 0x20) != 0) - { - UInt32 propsSize = 0; - RINOK(SzReadNumber32(sd, &propsSize)) - if (propsSize > sd->Size) - return SZ_ERROR_ARCHIVE; - if (propsSize >= 0x80) - return SZ_ERROR_UNSUPPORTED; - coder->PropsOffset = (size_t)(sd->Data - dataStart); - coder->PropsSize = (Byte)propsSize; - sd->Data += (size_t)propsSize; - sd->Size -= (size_t)propsSize; - } - } - - /* - if (numInStreams == 1 && numCoders == 1) - { - f->NumPackStreams = 1; - f->PackStreams[0] = 0; - } - else - */ - { - Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; - UInt32 numBonds, numPackStreams; - - numBonds = numCoders - 1; - if (numInStreams < numBonds) - return SZ_ERROR_ARCHIVE; - if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - f->NumBonds = numBonds; - - numPackStreams = numInStreams - numBonds; - if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - f->NumPackStreams = numPackStreams; - - for (i = 0; i < numInStreams; i++) - streamUsed[i] = False; - - if (numBonds != 0) - { - Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; - - for (i = 0; i < numCoders; i++) - coderUsed[i] = False; - - for (i = 0; i < numBonds; i++) - { - CSzBond *bp = f->Bonds + i; - - RINOK(SzReadNumber32(sd, &bp->InIndex)) - if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) - return SZ_ERROR_ARCHIVE; - streamUsed[bp->InIndex] = True; - - RINOK(SzReadNumber32(sd, &bp->OutIndex)) - if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) - return SZ_ERROR_ARCHIVE; - coderUsed[bp->OutIndex] = True; - } - - for (i = 0; i < numCoders; i++) - if (!coderUsed[i]) - { - f->UnpackStream = i; - break; - } - - if (i == numCoders) - return SZ_ERROR_ARCHIVE; - } - - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams; i++) - if (!streamUsed[i]) - break; - if (i == numInStreams) - return SZ_ERROR_ARCHIVE; - f->PackStreams[0] = i; - } - else - for (i = 0; i < numPackStreams; i++) - { - UInt32 index; - RINOK(SzReadNumber32(sd, &index)) - if (index >= numInStreams || streamUsed[index]) - return SZ_ERROR_ARCHIVE; - streamUsed[index] = True; - f->PackStreams[i] = index; - } - } - - f->NumCoders = numCoders; - - return SZ_OK; -} - - -static Z7_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) -{ - CSzData sd; - sd = *sd2; - for (; num != 0; num--) - { - Byte firstByte, mask; - unsigned i; - SZ_READ_BYTE_2(firstByte) - if ((firstByte & 0x80) == 0) - continue; - if ((firstByte & 0x40) == 0) - { - if (sd.Size == 0) - return SZ_ERROR_ARCHIVE; - sd.Size--; - sd.Data++; - continue; - } - mask = 0x20; - for (i = 2; i < 8 && (firstByte & mask) != 0; i++) - mask >>= 1; - if (i > sd.Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, i) - } - *sd2 = sd; - return SZ_OK; -} - - -#define k_Scan_NumCoders_MAX 64 -#define k_Scan_NumCodersStreams_in_Folder_MAX 64 - - -static SRes ReadUnpackInfo(CSzAr *p, - CSzData *sd2, - UInt32 numFoldersMax, - const CBuf *tempBufs, UInt32 numTempBufs, - ISzAllocPtr alloc) -{ - CSzData sd; - - UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; - const Byte *startBufPtr; - Byte external; - - RINOK(WaitId(sd2, k7zIdFolder)) - - RINOK(SzReadNumber32(sd2, &numFolders)) - if (numFolders > numFoldersMax) - return SZ_ERROR_UNSUPPORTED; - p->NumFolders = numFolders; - - SZ_READ_BYTE_SD(sd2, external) - if (external == 0) - sd = *sd2; - else - { - UInt32 index; - RINOK(SzReadNumber32(sd2, &index)) - if (index >= numTempBufs) - return SZ_ERROR_ARCHIVE; - sd.Data = tempBufs[index].data; - sd.Size = tempBufs[index].size; - } - - MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc) - MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc) - MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc) - MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc) - - startBufPtr = sd.Data; - - packStreamIndex = 0; - numCodersOutStreams = 0; - - for (fo = 0; fo < numFolders; fo++) - { - UInt32 numCoders, ci, numInStreams = 0; - - p->FoCodersOffsets[fo] = (size_t)(sd.Data - startBufPtr); - - RINOK(SzReadNumber32(&sd, &numCoders)) - if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) - return SZ_ERROR_UNSUPPORTED; - - for (ci = 0; ci < numCoders; ci++) - { - Byte mainByte; - unsigned idSize; - UInt32 coderInStreams; - - SZ_READ_BYTE_2(mainByte) - if ((mainByte & 0xC0) != 0) - return SZ_ERROR_UNSUPPORTED; - idSize = (mainByte & 0xF); - if (idSize > 8) - return SZ_ERROR_UNSUPPORTED; - if (idSize > sd.Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, idSize) - - coderInStreams = 1; - - if ((mainByte & 0x10) != 0) - { - UInt32 coderOutStreams; - RINOK(SzReadNumber32(&sd, &coderInStreams)) - RINOK(SzReadNumber32(&sd, &coderOutStreams)) - if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) - return SZ_ERROR_UNSUPPORTED; - } - - numInStreams += coderInStreams; - - if ((mainByte & 0x20) != 0) - { - UInt32 propsSize; - RINOK(SzReadNumber32(&sd, &propsSize)) - if (propsSize > sd.Size) - return SZ_ERROR_ARCHIVE; - SKIP_DATA2(sd, propsSize) - } - } - - { - UInt32 indexOfMainStream = 0; - UInt32 numPackStreams = 1; - - if (numCoders != 1 || numInStreams != 1) - { - Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; - Byte coderUsed[k_Scan_NumCoders_MAX]; - - UInt32 i; - const UInt32 numBonds = numCoders - 1; - if (numInStreams < numBonds) - return SZ_ERROR_ARCHIVE; - - if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) - return SZ_ERROR_UNSUPPORTED; - - for (i = 0; i < numInStreams; i++) - streamUsed[i] = False; - for (i = 0; i < numCoders; i++) - coderUsed[i] = False; - - for (i = 0; i < numBonds; i++) - { - UInt32 index; - - RINOK(SzReadNumber32(&sd, &index)) - if (index >= numInStreams || streamUsed[index]) - return SZ_ERROR_ARCHIVE; - streamUsed[index] = True; - - RINOK(SzReadNumber32(&sd, &index)) - if (index >= numCoders || coderUsed[index]) - return SZ_ERROR_ARCHIVE; - coderUsed[index] = True; - } - - numPackStreams = numInStreams - numBonds; - - if (numPackStreams != 1) - for (i = 0; i < numPackStreams; i++) - { - UInt32 index; - RINOK(SzReadNumber32(&sd, &index)) - if (index >= numInStreams || streamUsed[index]) - return SZ_ERROR_ARCHIVE; - streamUsed[index] = True; - } - - for (i = 0; i < numCoders; i++) - if (!coderUsed[i]) - { - indexOfMainStream = i; - break; - } - - if (i == numCoders) - return SZ_ERROR_ARCHIVE; - } - - p->FoStartPackStreamIndex[fo] = packStreamIndex; - p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; - p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; - numCodersOutStreams += numCoders; - if (numCodersOutStreams < numCoders) - return SZ_ERROR_UNSUPPORTED; - if (numPackStreams > p->NumPackStreams - packStreamIndex) - return SZ_ERROR_ARCHIVE; - packStreamIndex += numPackStreams; - } - } - - p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; - - { - const size_t dataSize = (size_t)(sd.Data - startBufPtr); - p->FoStartPackStreamIndex[fo] = packStreamIndex; - p->FoCodersOffsets[fo] = dataSize; - MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc) - } - - if (external != 0) - { - if (sd.Size != 0) - return SZ_ERROR_ARCHIVE; - sd = *sd2; - } - - RINOK(WaitId(&sd, k7zIdCodersUnpackSize)) - - MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc) - { - UInt32 i; - for (i = 0; i < numCodersOutStreams; i++) - { - RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)) - } - } - - for (;;) - { - UInt64 type; - RINOK(ReadID(&sd, &type)) - if (type == k7zIdEnd) - { - *sd2 = sd; - return SZ_OK; - } - if (type == k7zIdCRC) - { - RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)) - continue; - } - RINOK(SkipData(&sd)) - } -} - - -UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) -{ - return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; -} - - -typedef struct -{ - UInt32 NumTotalSubStreams; - UInt32 NumSubDigests; - CSzData sdNumSubStreams; - CSzData sdSizes; - CSzData sdCRCs; -} CSubStreamInfo; - - -static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) -{ - UInt64 type = 0; - UInt32 numSubDigests = 0; - const UInt32 numFolders = p->NumFolders; - UInt32 numUnpackStreams = numFolders; - UInt32 numUnpackSizesInData = 0; - - for (;;) - { - RINOK(ReadID(sd, &type)) - if (type == k7zIdNumUnpackStream) - { - UInt32 i; - ssi->sdNumSubStreams.Data = sd->Data; - numUnpackStreams = 0; - numSubDigests = 0; - for (i = 0; i < numFolders; i++) - { - UInt32 numStreams; - RINOK(SzReadNumber32(sd, &numStreams)) - if (numUnpackStreams > numUnpackStreams + numStreams) - return SZ_ERROR_UNSUPPORTED; - numUnpackStreams += numStreams; - if (numStreams != 0) - numUnpackSizesInData += (numStreams - 1); - if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) - numSubDigests += numStreams; - } - ssi->sdNumSubStreams.Size = (size_t)(sd->Data - ssi->sdNumSubStreams.Data); - continue; - } - if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) - break; - RINOK(SkipData(sd)) - } - - if (!ssi->sdNumSubStreams.Data) - { - numSubDigests = numFolders; - if (p->FolderCRCs.Defs) - numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); - } - - ssi->NumTotalSubStreams = numUnpackStreams; - ssi->NumSubDigests = numSubDigests; - - if (type == k7zIdSize) - { - ssi->sdSizes.Data = sd->Data; - RINOK(SkipNumbers(sd, numUnpackSizesInData)) - ssi->sdSizes.Size = (size_t)(sd->Data - ssi->sdSizes.Data); - RINOK(ReadID(sd, &type)) - } - - for (;;) - { - if (type == k7zIdEnd) - return SZ_OK; - if (type == k7zIdCRC) - { - ssi->sdCRCs.Data = sd->Data; - RINOK(SkipBitUi32s(sd, numSubDigests)) - ssi->sdCRCs.Size = (size_t)(sd->Data - ssi->sdCRCs.Data); - } - else - { - RINOK(SkipData(sd)) - } - RINOK(ReadID(sd, &type)) - } -} - -static SRes SzReadStreamsInfo(CSzAr *p, - CSzData *sd, - UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, - UInt64 *dataOffset, - CSubStreamInfo *ssi, - ISzAllocPtr alloc) -{ - UInt64 type; - - SzData_CLEAR(&ssi->sdSizes) - SzData_CLEAR(&ssi->sdCRCs) - SzData_CLEAR(&ssi->sdNumSubStreams) - - *dataOffset = 0; - RINOK(ReadID(sd, &type)) - if (type == k7zIdPackInfo) - { - RINOK(ReadNumber(sd, dataOffset)) - if (*dataOffset > p->RangeLimit) - return SZ_ERROR_ARCHIVE; - RINOK(ReadPackInfo(p, sd, alloc)) - if (p->PackPositions[p->NumPackStreams] > p->RangeLimit - *dataOffset) - return SZ_ERROR_ARCHIVE; - RINOK(ReadID(sd, &type)) - } - if (type == k7zIdUnpackInfo) - { - RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)) - RINOK(ReadID(sd, &type)) - } - if (type == k7zIdSubStreamsInfo) - { - RINOK(ReadSubStreamsInfo(p, sd, ssi)) - RINOK(ReadID(sd, &type)) - } - else - { - ssi->NumTotalSubStreams = p->NumFolders; - // ssi->NumSubDigests = 0; - } - - return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); -} - -static SRes SzReadAndDecodePackedStreams( - ILookInStreamPtr inStream, - CSzData *sd, - CBuf *tempBufs, - UInt32 numFoldersMax, - UInt64 baseOffset, - CSzAr *p, - ISzAllocPtr allocTemp) -{ - UInt64 dataStartPos; - UInt32 fo; - CSubStreamInfo ssi; - - RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)) - - dataStartPos += baseOffset; - if (p->NumFolders == 0) - return SZ_ERROR_ARCHIVE; - - for (fo = 0; fo < p->NumFolders; fo++) - Buf_Init(tempBufs + fo); - - for (fo = 0; fo < p->NumFolders; fo++) - { - CBuf *tempBuf = tempBufs + fo; - const UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); - if ((size_t)unpackSize != unpackSize) - return SZ_ERROR_MEM; - if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) - return SZ_ERROR_MEM; - } - - for (fo = 0; fo < p->NumFolders; fo++) - { - const CBuf *tempBuf = tempBufs + fo; - RINOK(LookInStream_SeekTo(inStream, dataStartPos)) - RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)) - } - - return SZ_OK; -} - -static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) -{ - size_t pos = 0; - *offsets++ = 0; - if (numFiles == 0) - return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; - if (size < 2) - return SZ_ERROR_ARCHIVE; - if (data[size - 2] != 0 || data[size - 1] != 0) - return SZ_ERROR_ARCHIVE; - do - { - const Byte *p; - if (pos == size) - return SZ_ERROR_ARCHIVE; - for (p = data + pos; - #ifdef _WIN32 - *(const UInt16 *)(const void *)p != 0 - #else - p[0] != 0 || p[1] != 0 - #endif - ; p += 2); - pos = (size_t)(p - data) + 2; - *offsets++ = (pos >> 1); - } - while (--numFiles); - return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; -} - -static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, - CSzData *sd2, - const CBuf *tempBufs, UInt32 numTempBufs, - ISzAllocPtr alloc) -{ - CSzData sd; - UInt32 i; - CNtfsFileTime *vals; - Byte *defs; - Byte external; - - RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)) - - SZ_READ_BYTE_SD(sd2, external) - if (external == 0) - sd = *sd2; - else - { - UInt32 index; - RINOK(SzReadNumber32(sd2, &index)) - if (index >= numTempBufs) - return SZ_ERROR_ARCHIVE; - sd.Data = tempBufs[index].data; - sd.Size = tempBufs[index].size; - } - - MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc) - vals = p->Vals; - defs = p->Defs; - for (i = 0; i < num; i++) - if (SzBitArray_Check(defs, i)) - { - if (sd.Size < 8) - return SZ_ERROR_ARCHIVE; - vals[i].Low = GetUi32(sd.Data); - vals[i].High = GetUi32(sd.Data + 4); - SKIP_DATA2(sd, 8) - } - else - vals[i].High = vals[i].Low = 0; - - if (external == 0) - *sd2 = sd; - - return SZ_OK; -} - - -#define NUM_ADDITIONAL_STREAMS_MAX 8 - - -static SRes SzReadHeader2( - CSzArEx *p, /* allocMain */ - CSzData *sd, - ILookInStreamPtr inStream, - CBuf *tempBufs, UInt32 *numTempBufs, - ISzAllocPtr allocMain, - ISzAllocPtr allocTemp - ) -{ - CSubStreamInfo ssi; - -{ - UInt64 type; - - SzData_CLEAR(&ssi.sdSizes) - SzData_CLEAR(&ssi.sdCRCs) - SzData_CLEAR(&ssi.sdNumSubStreams) - - ssi.NumSubDigests = 0; - ssi.NumTotalSubStreams = 0; - - RINOK(ReadID(sd, &type)) - - if (type == k7zIdArchiveProperties) - { - for (;;) - { - UInt64 type2; - RINOK(ReadID(sd, &type2)) - if (type2 == k7zIdEnd) - break; - RINOK(SkipData(sd)) - } - RINOK(ReadID(sd, &type)) - } - - if (type == k7zIdAdditionalStreamsInfo) - { - CSzAr tempAr; - SRes res; - - SzAr_Init(&tempAr); - tempAr.RangeLimit = p->db.RangeLimit; - - res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, - p->startPosAfterHeader, &tempAr, allocTemp); - *numTempBufs = tempAr.NumFolders; - SzAr_Free(&tempAr, allocTemp); - - if (res != SZ_OK) - return res; - RINOK(ReadID(sd, &type)) - } - - if (type == k7zIdMainStreamsInfo) - { - RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, - &p->dataPos, &ssi, allocMain)) - p->dataPos += p->startPosAfterHeader; - RINOK(ReadID(sd, &type)) - } - - if (type == k7zIdEnd) - { - return SZ_OK; - } - - if (type != k7zIdFilesInfo) - return SZ_ERROR_ARCHIVE; -} - -{ - UInt32 numFiles = 0; - UInt32 numEmptyStreams = 0; - const Byte *emptyStreams = NULL; - const Byte *emptyFiles = NULL; - - RINOK(SzReadNumber32(sd, &numFiles)) - p->NumFiles = numFiles; - - for (;;) - { - UInt64 type; - UInt64 size; - RINOK(ReadID(sd, &type)) - if (type == k7zIdEnd) - break; - RINOK(ReadNumber(sd, &size)) - if (size > sd->Size) - return SZ_ERROR_ARCHIVE; - - if (type >= ((UInt32)1 << 8)) - { - SKIP_DATA(sd, size) - } - else switch ((unsigned)type) - { - case k7zIdName: - { - size_t namesSize; - const Byte *namesData; - Byte external; - - SZ_READ_BYTE(external) - if (external == 0) - { - namesSize = (size_t)size - 1; - namesData = sd->Data; - } - else - { - UInt32 index; - RINOK(SzReadNumber32(sd, &index)) - if (index >= *numTempBufs) - return SZ_ERROR_ARCHIVE; - namesData = (tempBufs)[index].data; - namesSize = (tempBufs)[index].size; - } - - if ((namesSize & 1) != 0) - return SZ_ERROR_ARCHIVE; - MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain) - MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain) - RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) - if (external == 0) - { - SKIP_DATA(sd, namesSize) - } - break; - } - case k7zIdEmptyStream: - { - RINOK(RememberBitVector(sd, numFiles, &emptyStreams)) - numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); - emptyFiles = NULL; - break; - } - case k7zIdEmptyFile: - { - RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)) - break; - } - case k7zIdWinAttrib: - { - Byte external; - CSzData sdSwitch; - CSzData *sdPtr; - SzBitUi32s_Free(&p->Attribs, allocMain); - RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)) - - SZ_READ_BYTE(external) - if (external == 0) - sdPtr = sd; - else - { - UInt32 index; - RINOK(SzReadNumber32(sd, &index)) - if (index >= *numTempBufs) - return SZ_ERROR_ARCHIVE; - sdSwitch.Data = (tempBufs)[index].data; - sdSwitch.Size = (tempBufs)[index].size; - sdPtr = &sdSwitch; - } - RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)) - break; - } - /* - case k7zParent: - { - SzBitUi32s_Free(&p->Parents, allocMain); - RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); - RINOK(SzReadSwitch(sd)); - RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); - break; - } - */ - case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break; - case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break; - default: - { - SKIP_DATA(sd, size) - } - } - } - - if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) - return SZ_ERROR_ARCHIVE; - - for (;;) - { - UInt64 type; - RINOK(ReadID(sd, &type)) - if (type == k7zIdEnd) - break; - RINOK(SkipData(sd)) - } - - { - UInt32 i; - UInt32 emptyFileIndex = 0; - UInt32 folderIndex = 0; - UInt32 remSubStreams = 0; - UInt32 numSubStreams = 0; - UInt64 unpackPos = 0; - const Byte *digestsDefs = NULL; - const Byte *digestsVals = NULL; - UInt32 digestIndex = 0; - Byte isDirMask = 0; - Byte crcMask = 0; - Byte mask = 0x80; - - MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain) - MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain) - MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain) - MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain) - - RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)) - - if (ssi.sdCRCs.Size != 0) - { - Byte allDigestsDefined = 0; - SZ_READ_BYTE_SD_NOCHECK(&ssi.sdCRCs, allDigestsDefined) - if (allDigestsDefined) - digestsVals = ssi.sdCRCs.Data; - else - { - const size_t numBytes = (ssi.NumSubDigests + 7) >> 3; - digestsDefs = ssi.sdCRCs.Data; - digestsVals = digestsDefs + numBytes; - } - } - - for (i = 0; i < numFiles; i++, mask >>= 1) - { - if (mask == 0) - { - const UInt32 byteIndex = (i - 1) >> 3; - p->IsDirs[byteIndex] = isDirMask; - p->CRCs.Defs[byteIndex] = crcMask; - isDirMask = 0; - crcMask = 0; - mask = 0x80; - } - - p->UnpackPositions[i] = unpackPos; - p->CRCs.Vals[i] = 0; - - if (emptyStreams && SzBitArray_Check(emptyStreams, i)) - { - if (emptyFiles) - { - if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) - isDirMask |= mask; - emptyFileIndex++; - } - else - isDirMask |= mask; - if (remSubStreams == 0) - { - p->FileToFolder[i] = (UInt32)-1; - continue; - } - } - - if (remSubStreams == 0) - { - for (;;) - { - if (folderIndex >= p->db.NumFolders) - return SZ_ERROR_ARCHIVE; - p->FolderToFile[folderIndex] = i; - numSubStreams = 1; - if (ssi.sdNumSubStreams.Data) - { - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)) - } - remSubStreams = numSubStreams; - if (numSubStreams != 0) - break; - { - const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - unpackPos += folderUnpackSize; - if (unpackPos < folderUnpackSize) - return SZ_ERROR_ARCHIVE; - } - folderIndex++; - } - } - - p->FileToFolder[i] = folderIndex; - - if (emptyStreams && SzBitArray_Check(emptyStreams, i)) - continue; - - if (--remSubStreams == 0) - { - const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - const UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; - if (folderUnpackSize < unpackPos - startFolderUnpackPos) - return SZ_ERROR_ARCHIVE; - unpackPos = startFolderUnpackPos + folderUnpackSize; - if (unpackPos < folderUnpackSize) - return SZ_ERROR_ARCHIVE; - - if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex)) - { - p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; - crcMask |= mask; - } - folderIndex++; - } - else - { - UInt64 v; - RINOK(ReadNumber(&ssi.sdSizes, &v)) - unpackPos += v; - if (unpackPos < v) - return SZ_ERROR_ARCHIVE; - } - if ((crcMask & mask) == 0 && digestsVals) - { - if (!digestsDefs || SzBitArray_Check(digestsDefs, digestIndex)) - { - p->CRCs.Vals[i] = GetUi32(digestsVals); - digestsVals += 4; - crcMask |= mask; - } - digestIndex++; - } - } - - if (mask != 0x80) - { - const UInt32 byteIndex = (i - 1) >> 3; - p->IsDirs[byteIndex] = isDirMask; - p->CRCs.Defs[byteIndex] = crcMask; - } - - p->UnpackPositions[i] = unpackPos; - - if (remSubStreams != 0) - return SZ_ERROR_ARCHIVE; - - for (;;) - { - p->FolderToFile[folderIndex] = i; - if (folderIndex >= p->db.NumFolders) - break; - if (!ssi.sdNumSubStreams.Data) - return SZ_ERROR_ARCHIVE; - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)) - if (numSubStreams != 0) - return SZ_ERROR_ARCHIVE; - /* - { - UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - unpackPos += folderUnpackSize; - if (unpackPos < folderUnpackSize) - return SZ_ERROR_ARCHIVE; - } - */ - folderIndex++; - } - - if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) - return SZ_ERROR_ARCHIVE; - } -} - return SZ_OK; -} - - -static SRes SzReadHeader( - CSzArEx *p, - CSzData *sd, - ILookInStreamPtr inStream, - ISzAllocPtr allocMain, - ISzAllocPtr allocTemp) -{ - UInt32 i; - UInt32 numTempBufs = 0; - SRes res; - CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; - - for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) - Buf_Init(tempBufs + i); - - res = SzReadHeader2(p, sd, inStream, - tempBufs, &numTempBufs, - allocMain, allocTemp); - - for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) - Buf_Free(tempBufs + i, allocTemp); - - RINOK(res) - - if (sd->Size != 0) - return SZ_ERROR_FAIL; - - return res; -} - -static SRes SzArEx_Open2( - CSzArEx *p, - ILookInStreamPtr inStream, - ISzAllocPtr allocMain, - ISzAllocPtr allocTemp) -{ - Byte header[k7zStartHeaderSize]; - Int64 startArcPos; - UInt64 nextHeaderOffset, nextHeaderSize; - size_t nextHeaderSizeT; - UInt32 nextHeaderCRC; - CBuf buf; - SRes res; - - startArcPos = 0; - RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)) - - RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)) - - if (!TestSignatureCandidate(header)) - return SZ_ERROR_NO_ARCHIVE; - if (header[6] != k7zMajorVersion) - return SZ_ERROR_UNSUPPORTED; - - nextHeaderOffset = GetUi64(header + 12); - nextHeaderSize = GetUi64(header + 20); - nextHeaderCRC = GetUi32(header + 28); - - p->startPosAfterHeader = (UInt64)startArcPos + k7zStartHeaderSize; - - if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) - return SZ_ERROR_CRC; - - p->db.RangeLimit = nextHeaderOffset; - - nextHeaderSizeT = (size_t)nextHeaderSize; - if (nextHeaderSizeT != nextHeaderSize) - return SZ_ERROR_MEM; - if (nextHeaderSizeT == 0) - return SZ_OK; - if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || - nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) - return SZ_ERROR_NO_ARCHIVE; - - { - Int64 pos = 0; - RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)) - if ((UInt64)pos < (UInt64)startArcPos + nextHeaderOffset || - (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset || - (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) - return SZ_ERROR_INPUT_EOF; - } - - RINOK(LookInStream_SeekTo(inStream, (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset)) - - if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) - return SZ_ERROR_MEM; - - res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); - - if (res == SZ_OK) - { - res = SZ_ERROR_ARCHIVE; - if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) - { - CSzData sd; - UInt64 type; - sd.Data = buf.data; - sd.Size = buf.size; - - res = ReadID(&sd, &type); - - if (res == SZ_OK && type == k7zIdEncodedHeader) - { - CSzAr tempAr; - CBuf tempBuf; - Buf_Init(&tempBuf); - - SzAr_Init(&tempAr); - tempAr.RangeLimit = p->db.RangeLimit; - - res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); - SzAr_Free(&tempAr, allocTemp); - - if (res != SZ_OK) - { - Buf_Free(&tempBuf, allocTemp); - } - else - { - Buf_Free(&buf, allocTemp); - buf.data = tempBuf.data; - buf.size = tempBuf.size; - sd.Data = buf.data; - sd.Size = buf.size; - res = ReadID(&sd, &type); - } - } - - if (res == SZ_OK) - { - if (type == k7zIdHeader) - { - /* - CSzData sd2; - unsigned ttt; - for (ttt = 0; ttt < 40000; ttt++) - { - SzArEx_Free(p, allocMain); - sd2 = sd; - res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); - if (res != SZ_OK) - break; - } - */ - res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); - } - else - res = SZ_ERROR_UNSUPPORTED; - } - } - } - - Buf_Free(&buf, allocTemp); - return res; -} - - -SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream, - ISzAllocPtr allocMain, ISzAllocPtr allocTemp) -{ - const SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); - if (res != SZ_OK) - SzArEx_Free(p, allocMain); - return res; -} - - -SRes SzArEx_Extract( - const CSzArEx *p, - ILookInStreamPtr inStream, - UInt32 fileIndex, - UInt32 *blockIndex, - Byte **tempBuf, - size_t *outBufferSize, - size_t *offset, - size_t *outSizeProcessed, - ISzAllocPtr allocMain, - ISzAllocPtr allocTemp) -{ - const UInt32 folderIndex = p->FileToFolder[fileIndex]; - SRes res = SZ_OK; - - *offset = 0; - *outSizeProcessed = 0; - - if (folderIndex == (UInt32)-1) - { - ISzAlloc_Free(allocMain, *tempBuf); - *blockIndex = folderIndex; - *tempBuf = NULL; - *outBufferSize = 0; - return SZ_OK; - } - - if (*tempBuf == NULL || *blockIndex != folderIndex) - { - const UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - /* - UInt64 unpackSizeSpec = - p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] - - p->UnpackPositions[p->FolderToFile[folderIndex]]; - */ - const size_t unpackSize = (size_t)unpackSizeSpec; - - if (unpackSize != unpackSizeSpec) - return SZ_ERROR_MEM; - *blockIndex = folderIndex; - ISzAlloc_Free(allocMain, *tempBuf); - *tempBuf = NULL; - - if (res == SZ_OK) - { - *outBufferSize = unpackSize; - if (unpackSize != 0) - { - *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize); - if (*tempBuf == NULL) - res = SZ_ERROR_MEM; - } - - if (res == SZ_OK) - { - res = SzAr_DecodeFolder(&p->db, folderIndex, - inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); - } - } - } - - if (res == SZ_OK) - { - const UInt64 unpackPos = p->UnpackPositions[fileIndex]; - *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); - *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos); - if (*offset + *outSizeProcessed > *outBufferSize) - return SZ_ERROR_FAIL; - if (SzBitWithVals_Check(&p->CRCs, fileIndex)) - if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) - res = SZ_ERROR_CRC; - } - - return res; -} - - -size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) -{ - const size_t offs = p->FileNameOffsets[fileIndex]; - const size_t len = p->FileNameOffsets[fileIndex + 1] - offs; - if (dest != 0) - { - size_t i; - const Byte *src = p->FileNames + offs * 2; - for (i = 0; i < len; i++) - dest[i] = GetUi16(src + i * 2); - } - return len; -} - -/* -size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) -{ - size_t len; - if (!p->FileNameOffsets) - return 1; - len = 0; - for (;;) - { - UInt32 parent = (UInt32)(Int32)-1; - len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; - if SzBitWithVals_Check(&p->Parents, fileIndex) - parent = p->Parents.Vals[fileIndex]; - if (parent == (UInt32)(Int32)-1) - return len; - fileIndex = parent; - } -} - -UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) -{ - BoolInt needSlash; - if (!p->FileNameOffsets) - { - *(--dest) = 0; - return dest; - } - needSlash = False; - for (;;) - { - UInt32 parent = (UInt32)(Int32)-1; - size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; - SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); - if (needSlash) - *(dest - 1) = '/'; - needSlash = True; - dest -= curLen; - - if SzBitWithVals_Check(&p->Parents, fileIndex) - parent = p->Parents.Vals[fileIndex]; - if (parent == (UInt32)(Int32)-1) - return dest; - fileIndex = parent; - } -} -*/ +/* 7zArcIn.c -- 7z Input functions +2023-09-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7z.h" +#include "7zBuf.h" +#include "7zCrc.h" +#include "CpuArch.h" + +#define MY_ALLOC(T, p, size, alloc) \ + { if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } + +#define MY_ALLOC_ZE(T, p, size, alloc) \ + { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } + +#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ + { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } + +#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ + { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } + +#define k7zMajorVersion 0 + +enum EIdEnum +{ + k7zIdEnd, + k7zIdHeader, + k7zIdArchiveProperties, + k7zIdAdditionalStreamsInfo, + k7zIdMainStreamsInfo, + k7zIdFilesInfo, + k7zIdPackInfo, + k7zIdUnpackInfo, + k7zIdSubStreamsInfo, + k7zIdSize, + k7zIdCRC, + k7zIdFolder, + k7zIdCodersUnpackSize, + k7zIdNumUnpackStream, + k7zIdEmptyStream, + k7zIdEmptyFile, + k7zIdAnti, + k7zIdName, + k7zIdCTime, + k7zIdATime, + k7zIdMTime, + k7zIdWinAttrib, + k7zIdComment, + k7zIdEncodedHeader, + k7zIdStartPos, + k7zIdDummy + // k7zNtSecure, + // k7zParent, + // k7zIsReal +}; + +const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +#define SzBitUi32s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc) +{ + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc) + MY_ALLOC(UInt32, p->Vals, num, alloc) + } + return SZ_OK; +} + +static void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; + ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + +#define SzBitUi64s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; } + +static void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL; + ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL; +} + + +static void SzAr_Init(CSzAr *p) +{ + p->NumPackStreams = 0; + p->NumFolders = 0; + + p->PackPositions = NULL; + SzBitUi32s_INIT(&p->FolderCRCs) + + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; + + p->CodersData = NULL; + + p->RangeLimit = 0; +} + +static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); + + ISzAlloc_Free(alloc, p->FoCodersOffsets); + ISzAlloc_Free(alloc, p->FoStartPackStreamIndex); + ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes); + ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + ISzAlloc_Free(alloc, p->CoderUnpackSizes); + + ISzAlloc_Free(alloc, p->CodersData); + + SzAr_Init(p); +} + + +void SzArEx_Init(CSzArEx *p) +{ + SzAr_Init(&p->db); + + p->NumFiles = 0; + p->dataPos = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + + SzBitUi32s_INIT(&p->CRCs) + SzBitUi32s_INIT(&p->Attribs) + // SzBitUi32s_INIT(&p->Parents) + SzBitUi64s_INIT(&p->MTime) + SzBitUi64s_INIT(&p->CTime) +} + +void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->UnpackPositions); + ISzAlloc_Free(alloc, p->IsDirs); + + ISzAlloc_Free(alloc, p->FolderToFile); + ISzAlloc_Free(alloc, p->FileToFolder); + + ISzAlloc_Free(alloc, p->FileNameOffsets); + ISzAlloc_Free(alloc, p->FileNames); + + SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); + // SzBitUi32s_Free(&p->Parents, alloc); + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + + SzAr_Free(&p->db, alloc); + SzArEx_Init(p); +} + + +static int TestSignatureCandidate(const Byte *testBytes) +{ + unsigned i; + for (i = 0; i < k7zSignatureSize; i++) + if (testBytes[i] != k7zSignature[i]) + return 0; + return 1; +} + +#define SzData_CLEAR(p) { (p)->Data = NULL; (p)->Size = 0; } + +#define SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) \ + (_sd_)->Size--; dest = *(_sd_)->Data++; + +#define SZ_READ_BYTE_SD(_sd_, dest) \ + if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; \ + SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) + +#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest) + +#define SZ_READ_BYTE_2(dest) \ + if (sd.Size == 0) return SZ_ERROR_ARCHIVE; \ + sd.Size--; dest = *sd.Data++; + +#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); } +#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); } + +#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \ + dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4); + +static Z7_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value) +{ + Byte firstByte, mask; + unsigned i; + UInt32 v; + + SZ_READ_BYTE(firstByte) + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + return SZ_OK; + } + SZ_READ_BYTE(v) + if ((firstByte & 0x40) == 0) + { + *value = (((UInt32)firstByte & 0x3F) << 8) | v; + return SZ_OK; + } + SZ_READ_BYTE(mask) + *value = v | ((UInt32)mask << 8); + mask = 0x20; + for (i = 2; i < 8; i++) + { + Byte b; + if ((firstByte & mask) == 0) + { + const UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); + *value |= (highPart << (8 * i)); + return SZ_OK; + } + SZ_READ_BYTE(b) + *value |= ((UInt64)b << (8 * i)); + mask >>= 1; + } + return SZ_OK; +} + + +static Z7_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) +{ + Byte firstByte; + UInt64 value64; + if (sd->Size == 0) + return SZ_ERROR_ARCHIVE; + firstByte = *sd->Data; + if ((firstByte & 0x80) == 0) + { + *value = firstByte; + sd->Data++; + sd->Size--; + return SZ_OK; + } + RINOK(ReadNumber(sd, &value64)) + if (value64 >= (UInt32)0x80000000 - 1) + return SZ_ERROR_UNSUPPORTED; + if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4))) + return SZ_ERROR_UNSUPPORTED; + *value = (UInt32)value64; + return SZ_OK; +} + +#define ReadID(sd, value) ReadNumber(sd, value) + +static SRes SkipData(CSzData *sd) +{ + UInt64 size; + RINOK(ReadNumber(sd, &size)) + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, size) + return SZ_OK; +} + +static SRes WaitId(CSzData *sd, UInt32 id) +{ + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)) + if (type == id) + return SZ_OK; + if (type == k7zIdEnd) + return SZ_ERROR_ARCHIVE; + RINOK(SkipData(sd)) + } +} + +static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v) +{ + const UInt32 numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + *v = sd->Data; + SKIP_DATA(sd, numBytes) + return SZ_OK; +} + +static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems) +{ + unsigned b = 0; + unsigned m = 0; + UInt32 sum = 0; + for (; numItems != 0; numItems--) + { + if (m == 0) + { + b = *bits++; + m = 8; + } + m--; + sum += (UInt32)((b >> m) & 1); + } + return sum; +} + +static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc) +{ + Byte allAreDefined; + Byte *v2; + const UInt32 numBytes = (numItems + 7) >> 3; + *v = NULL; + SZ_READ_BYTE(allAreDefined) + if (numBytes == 0) + return SZ_OK; + if (allAreDefined == 0) + { + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc) + SKIP_DATA(sd, numBytes) + return SZ_OK; + } + MY_ALLOC(Byte, *v, numBytes, alloc) + v2 = *v; + memset(v2, 0xFF, (size_t)numBytes); + { + const unsigned numBits = (unsigned)numItems & 7; + if (numBits != 0) + v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits)); + } + return SZ_OK; +} + +static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +{ + UInt32 i; + CSzData sd; + UInt32 *vals; + const Byte *defs; + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc) + sd = *sd2; + defs = crcs->Defs; + vals = crcs->Vals; + for (i = 0; i < numItems; i++) + if (SzBitArray_Check(defs, i)) + { + SZ_READ_32(vals[i]) + } + else + vals[i] = 0; + *sd2 = sd; + return SZ_OK; +} + +static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc) +{ + SzBitUi32s_Free(crcs, alloc); + RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc)) + return ReadUi32s(sd, numItems, crcs, alloc); +} + +static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems) +{ + Byte allAreDefined; + UInt32 numDefined = numItems; + SZ_READ_BYTE(allAreDefined) + if (!allAreDefined) + { + const size_t numBytes = (numItems + 7) >> 3; + if (numBytes > sd->Size) + return SZ_ERROR_ARCHIVE; + numDefined = CountDefinedBits(sd->Data, numItems); + SKIP_DATA(sd, numBytes) + } + if (numDefined > (sd->Size >> 2)) + return SZ_ERROR_ARCHIVE; + SKIP_DATA(sd, (size_t)numDefined * 4) + return SZ_OK; +} + +static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc) +{ + RINOK(SzReadNumber32(sd, &p->NumPackStreams)) + + RINOK(WaitId(sd, k7zIdSize)) + MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc) + { + UInt64 sum = 0; + UInt32 i; + const UInt32 numPackStreams = p->NumPackStreams; + for (i = 0; i < numPackStreams; i++) + { + UInt64 packSize; + p->PackPositions[i] = sum; + RINOK(ReadNumber(sd, &packSize)) + sum += packSize; + if (sum < packSize) + return SZ_ERROR_ARCHIVE; + } + p->PackPositions[i] = sum; + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)) + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + /* CRC of packed streams is unused now */ + RINOK(SkipBitUi32s(sd, p->NumPackStreams)) + continue; + } + RINOK(SkipData(sd)) + } +} + +/* +static SRes SzReadSwitch(CSzData *sd) +{ + Byte external; + RINOK(SzReadByte(sd, &external)); + return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; +} +*/ + +#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) +{ + UInt32 numCoders, i; + UInt32 numInStreams = 0; + const Byte *dataStart = sd->Data; + + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; + + RINOK(SzReadNumber32(sd, &numCoders)) + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numCoders; i++) + { + Byte mainByte; + CSzCoderInfo *coder = f->Coders + i; + unsigned idSize, j; + UInt64 id; + + SZ_READ_BYTE(mainByte) + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + + idSize = (unsigned)(mainByte & 0xF); + if (idSize > sizeof(id)) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd->Size) + return SZ_ERROR_ARCHIVE; + id = 0; + for (j = 0; j < idSize; j++) + { + id = ((id << 8) | *sd->Data); + sd->Data++; + sd->Size--; + } + if (id > (UInt32)0xFFFFFFFF) + return SZ_ERROR_UNSUPPORTED; + coder->MethodID = (UInt32)id; + + coder->NumStreams = 1; + coder->PropsOffset = 0; + coder->PropsSize = 0; + + if ((mainByte & 0x10) != 0) + { + UInt32 numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)) + if (numStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + coder->NumStreams = (Byte)numStreams; + + RINOK(SzReadNumber32(sd, &numStreams)) + if (numStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize = 0; + RINOK(SzReadNumber32(sd, &propsSize)) + if (propsSize > sd->Size) + return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; + coder->PropsOffset = (size_t)(sd->Data - dataStart); + coder->PropsSize = (Byte)propsSize; + sd->Data += (size_t)propsSize; + sd->Size -= (size_t)propsSize; + } + } + + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ + { + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; + + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond *bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)) + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)) + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) + return SZ_ERROR_ARCHIVE; + f->PackStreams[0] = i; + } + else + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)) + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; + } + } + + f->NumCoders = numCoders; + + return SZ_OK; +} + + +static Z7_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) +{ + CSzData sd; + sd = *sd2; + for (; num != 0; num--) + { + Byte firstByte, mask; + unsigned i; + SZ_READ_BYTE_2(firstByte) + if ((firstByte & 0x80) == 0) + continue; + if ((firstByte & 0x40) == 0) + { + if (sd.Size == 0) + return SZ_ERROR_ARCHIVE; + sd.Size--; + sd.Data++; + continue; + } + mask = 0x20; + for (i = 2; i < 8 && (firstByte & mask) != 0; i++) + mask >>= 1; + if (i > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, i) + } + *sd2 = sd; + return SZ_OK; +} + + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + + +static SRes ReadUnpackInfo(CSzAr *p, + CSzData *sd2, + UInt32 numFoldersMax, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAllocPtr alloc) +{ + CSzData sd; + + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; + const Byte *startBufPtr; + Byte external; + + RINOK(WaitId(sd2, k7zIdFolder)) + + RINOK(SzReadNumber32(sd2, &numFolders)) + if (numFolders > numFoldersMax) + return SZ_ERROR_UNSUPPORTED; + p->NumFolders = numFolders; + + SZ_READ_BYTE_SD(sd2, external) + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)) + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc) + MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc) + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc) + MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc) + + startBufPtr = sd.Data; + + packStreamIndex = 0; + numCodersOutStreams = 0; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 numCoders, ci, numInStreams = 0; + + p->FoCodersOffsets[fo] = (size_t)(sd.Data - startBufPtr); + + RINOK(SzReadNumber32(&sd, &numCoders)) + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (ci = 0; ci < numCoders; ci++) + { + Byte mainByte; + unsigned idSize; + UInt32 coderInStreams; + + SZ_READ_BYTE_2(mainByte) + if ((mainByte & 0xC0) != 0) + return SZ_ERROR_UNSUPPORTED; + idSize = (mainByte & 0xF); + if (idSize > 8) + return SZ_ERROR_UNSUPPORTED; + if (idSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, idSize) + + coderInStreams = 1; + + if ((mainByte & 0x10) != 0) + { + UInt32 coderOutStreams; + RINOK(SzReadNumber32(&sd, &coderInStreams)) + RINOK(SzReadNumber32(&sd, &coderOutStreams)) + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) + return SZ_ERROR_UNSUPPORTED; + } + + numInStreams += coderInStreams; + + if ((mainByte & 0x20) != 0) + { + UInt32 propsSize; + RINOK(SzReadNumber32(&sd, &propsSize)) + if (propsSize > sd.Size) + return SZ_ERROR_ARCHIVE; + SKIP_DATA2(sd, propsSize) + } + } + + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 1; + + if (numCoders != 1 || numInStreams != 1) + { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + + UInt32 i; + const UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + UInt32 index; + + RINOK(SzReadNumber32(&sd, &index)) + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + + RINOK(SzReadNumber32(&sd, &index)) + if (index >= numCoders || coderUsed[index]) + return SZ_ERROR_ARCHIVE; + coderUsed[index] = True; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)) + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) + return SZ_ERROR_UNSUPPORTED; + if (numPackStreams > p->NumPackStreams - packStreamIndex) + return SZ_ERROR_ARCHIVE; + packStreamIndex += numPackStreams; + } + } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + + { + const size_t dataSize = (size_t)(sd.Data - startBufPtr); + p->FoStartPackStreamIndex[fo] = packStreamIndex; + p->FoCodersOffsets[fo] = dataSize; + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc) + } + + if (external != 0) + { + if (sd.Size != 0) + return SZ_ERROR_ARCHIVE; + sd = *sd2; + } + + RINOK(WaitId(&sd, k7zIdCodersUnpackSize)) + + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc) + { + UInt32 i; + for (i = 0; i < numCodersOutStreams; i++) + { + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)) + } + } + + for (;;) + { + UInt64 type; + RINOK(ReadID(&sd, &type)) + if (type == k7zIdEnd) + { + *sd2 = sd; + return SZ_OK; + } + if (type == k7zIdCRC) + { + RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc)) + continue; + } + RINOK(SkipData(&sd)) + } +} + + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +{ + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; +} + + +typedef struct +{ + UInt32 NumTotalSubStreams; + UInt32 NumSubDigests; + CSzData sdNumSubStreams; + CSzData sdSizes; + CSzData sdCRCs; +} CSubStreamInfo; + + +static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) +{ + UInt64 type = 0; + UInt32 numSubDigests = 0; + const UInt32 numFolders = p->NumFolders; + UInt32 numUnpackStreams = numFolders; + UInt32 numUnpackSizesInData = 0; + + for (;;) + { + RINOK(ReadID(sd, &type)) + if (type == k7zIdNumUnpackStream) + { + UInt32 i; + ssi->sdNumSubStreams.Data = sd->Data; + numUnpackStreams = 0; + numSubDigests = 0; + for (i = 0; i < numFolders; i++) + { + UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)) + if (numUnpackStreams > numUnpackStreams + numStreams) + return SZ_ERROR_UNSUPPORTED; + numUnpackStreams += numStreams; + if (numStreams != 0) + numUnpackSizesInData += (numStreams - 1); + if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i)) + numSubDigests += numStreams; + } + ssi->sdNumSubStreams.Size = (size_t)(sd->Data - ssi->sdNumSubStreams.Data); + continue; + } + if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd) + break; + RINOK(SkipData(sd)) + } + + if (!ssi->sdNumSubStreams.Data) + { + numSubDigests = numFolders; + if (p->FolderCRCs.Defs) + numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders); + } + + ssi->NumTotalSubStreams = numUnpackStreams; + ssi->NumSubDigests = numSubDigests; + + if (type == k7zIdSize) + { + ssi->sdSizes.Data = sd->Data; + RINOK(SkipNumbers(sd, numUnpackSizesInData)) + ssi->sdSizes.Size = (size_t)(sd->Data - ssi->sdSizes.Data); + RINOK(ReadID(sd, &type)) + } + + for (;;) + { + if (type == k7zIdEnd) + return SZ_OK; + if (type == k7zIdCRC) + { + ssi->sdCRCs.Data = sd->Data; + RINOK(SkipBitUi32s(sd, numSubDigests)) + ssi->sdCRCs.Size = (size_t)(sd->Data - ssi->sdCRCs.Data); + } + else + { + RINOK(SkipData(sd)) + } + RINOK(ReadID(sd, &type)) + } +} + +static SRes SzReadStreamsInfo(CSzAr *p, + CSzData *sd, + UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, + UInt64 *dataOffset, + CSubStreamInfo *ssi, + ISzAllocPtr alloc) +{ + UInt64 type; + + SzData_CLEAR(&ssi->sdSizes) + SzData_CLEAR(&ssi->sdCRCs) + SzData_CLEAR(&ssi->sdNumSubStreams) + + *dataOffset = 0; + RINOK(ReadID(sd, &type)) + if (type == k7zIdPackInfo) + { + RINOK(ReadNumber(sd, dataOffset)) + if (*dataOffset > p->RangeLimit) + return SZ_ERROR_ARCHIVE; + RINOK(ReadPackInfo(p, sd, alloc)) + if (p->PackPositions[p->NumPackStreams] > p->RangeLimit - *dataOffset) + return SZ_ERROR_ARCHIVE; + RINOK(ReadID(sd, &type)) + } + if (type == k7zIdUnpackInfo) + { + RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc)) + RINOK(ReadID(sd, &type)) + } + if (type == k7zIdSubStreamsInfo) + { + RINOK(ReadSubStreamsInfo(p, sd, ssi)) + RINOK(ReadID(sd, &type)) + } + else + { + ssi->NumTotalSubStreams = p->NumFolders; + // ssi->NumSubDigests = 0; + } + + return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED); +} + +static SRes SzReadAndDecodePackedStreams( + ILookInStreamPtr inStream, + CSzData *sd, + CBuf *tempBufs, + UInt32 numFoldersMax, + UInt64 baseOffset, + CSzAr *p, + ISzAllocPtr allocTemp) +{ + UInt64 dataStartPos; + UInt32 fo; + CSubStreamInfo ssi; + + RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp)) + + dataStartPos += baseOffset; + if (p->NumFolders == 0) + return SZ_ERROR_ARCHIVE; + + for (fo = 0; fo < p->NumFolders; fo++) + Buf_Init(tempBufs + fo); + + for (fo = 0; fo < p->NumFolders; fo++) + { + CBuf *tempBuf = tempBufs + fo; + const UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); + if ((size_t)unpackSize != unpackSize) + return SZ_ERROR_MEM; + if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) + return SZ_ERROR_MEM; + } + + for (fo = 0; fo < p->NumFolders; fo++) + { + const CBuf *tempBuf = tempBufs + fo; + RINOK(LookInStream_SeekTo(inStream, dataStartPos)) + RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)) + } + + return SZ_OK; +} + +static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets) +{ + size_t pos = 0; + *offsets++ = 0; + if (numFiles == 0) + return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; + if (data[size - 2] != 0 || data[size - 1] != 0) + return SZ_ERROR_ARCHIVE; + do + { + const Byte *p; + if (pos == size) + return SZ_ERROR_ARCHIVE; + for (p = data + pos; + #ifdef _WIN32 + *(const UInt16 *)(const void *)p != 0 + #else + p[0] != 0 || p[1] != 0 + #endif + ; p += 2); + pos = (size_t)(p - data) + 2; + *offsets++ = (pos >> 1); + } + while (--numFiles); + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num, + CSzData *sd2, + const CBuf *tempBufs, UInt32 numTempBufs, + ISzAllocPtr alloc) +{ + CSzData sd; + UInt32 i; + CNtfsFileTime *vals; + Byte *defs; + Byte external; + + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)) + + SZ_READ_BYTE_SD(sd2, external) + if (external == 0) + sd = *sd2; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd2, &index)) + if (index >= numTempBufs) + return SZ_ERROR_ARCHIVE; + sd.Data = tempBufs[index].data; + sd.Size = tempBufs[index].size; + } + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc) + vals = p->Vals; + defs = p->Defs; + for (i = 0; i < num; i++) + if (SzBitArray_Check(defs, i)) + { + if (sd.Size < 8) + return SZ_ERROR_ARCHIVE; + vals[i].Low = GetUi32(sd.Data); + vals[i].High = GetUi32(sd.Data + 4); + SKIP_DATA2(sd, 8) + } + else + vals[i].High = vals[i].Low = 0; + + if (external == 0) + *sd2 = sd; + + return SZ_OK; +} + + +#define NUM_ADDITIONAL_STREAMS_MAX 8 + + +static SRes SzReadHeader2( + CSzArEx *p, /* allocMain */ + CSzData *sd, + ILookInStreamPtr inStream, + CBuf *tempBufs, UInt32 *numTempBufs, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp + ) +{ + CSubStreamInfo ssi; + +{ + UInt64 type; + + SzData_CLEAR(&ssi.sdSizes) + SzData_CLEAR(&ssi.sdCRCs) + SzData_CLEAR(&ssi.sdNumSubStreams) + + ssi.NumSubDigests = 0; + ssi.NumTotalSubStreams = 0; + + RINOK(ReadID(sd, &type)) + + if (type == k7zIdArchiveProperties) + { + for (;;) + { + UInt64 type2; + RINOK(ReadID(sd, &type2)) + if (type2 == k7zIdEnd) + break; + RINOK(SkipData(sd)) + } + RINOK(ReadID(sd, &type)) + } + + if (type == k7zIdAdditionalStreamsInfo) + { + CSzAr tempAr; + SRes res; + + SzAr_Init(&tempAr); + tempAr.RangeLimit = p->db.RangeLimit; + + res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, + p->startPosAfterHeader, &tempAr, allocTemp); + *numTempBufs = tempAr.NumFolders; + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + return res; + RINOK(ReadID(sd, &type)) + } + + if (type == k7zIdMainStreamsInfo) + { + RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs, + &p->dataPos, &ssi, allocMain)) + p->dataPos += p->startPosAfterHeader; + RINOK(ReadID(sd, &type)) + } + + if (type == k7zIdEnd) + { + return SZ_OK; + } + + if (type != k7zIdFilesInfo) + return SZ_ERROR_ARCHIVE; +} + +{ + UInt32 numFiles = 0; + UInt32 numEmptyStreams = 0; + const Byte *emptyStreams = NULL; + const Byte *emptyFiles = NULL; + + RINOK(SzReadNumber32(sd, &numFiles)) + p->NumFiles = numFiles; + + for (;;) + { + UInt64 type; + UInt64 size; + RINOK(ReadID(sd, &type)) + if (type == k7zIdEnd) + break; + RINOK(ReadNumber(sd, &size)) + if (size > sd->Size) + return SZ_ERROR_ARCHIVE; + + if (type >= ((UInt32)1 << 8)) + { + SKIP_DATA(sd, size) + } + else switch ((unsigned)type) + { + case k7zIdName: + { + size_t namesSize; + const Byte *namesData; + Byte external; + + SZ_READ_BYTE(external) + if (external == 0) + { + namesSize = (size_t)size - 1; + namesData = sd->Data; + } + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)) + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + namesData = (tempBufs)[index].data; + namesSize = (tempBufs)[index].size; + } + + if ((namesSize & 1) != 0) + return SZ_ERROR_ARCHIVE; + MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain) + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain) + RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) + if (external == 0) + { + SKIP_DATA(sd, namesSize) + } + break; + } + case k7zIdEmptyStream: + { + RINOK(RememberBitVector(sd, numFiles, &emptyStreams)) + numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; + break; + } + case k7zIdEmptyFile: + { + RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles)) + break; + } + case k7zIdWinAttrib: + { + Byte external; + CSzData sdSwitch; + CSzData *sdPtr; + SzBitUi32s_Free(&p->Attribs, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain)) + + SZ_READ_BYTE(external) + if (external == 0) + sdPtr = sd; + else + { + UInt32 index; + RINOK(SzReadNumber32(sd, &index)) + if (index >= *numTempBufs) + return SZ_ERROR_ARCHIVE; + sdSwitch.Data = (tempBufs)[index].data; + sdSwitch.Size = (tempBufs)[index].size; + sdPtr = &sdSwitch; + } + RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain)) + break; + } + /* + case k7zParent: + { + SzBitUi32s_Free(&p->Parents, allocMain); + RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain)); + RINOK(SzReadSwitch(sd)); + RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain)); + break; + } + */ + case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break; + case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break; + default: + { + SKIP_DATA(sd, size) + } + } + } + + if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + UInt64 type; + RINOK(ReadID(sd, &type)) + if (type == k7zIdEnd) + break; + RINOK(SkipData(sd)) + } + + { + UInt32 i; + UInt32 emptyFileIndex = 0; + UInt32 folderIndex = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; + UInt64 unpackPos = 0; + const Byte *digestsDefs = NULL; + const Byte *digestsVals = NULL; + UInt32 digestIndex = 0; + Byte isDirMask = 0; + Byte crcMask = 0; + Byte mask = 0x80; + + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain) + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain) + MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain) + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain) + + RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)) + + if (ssi.sdCRCs.Size != 0) + { + Byte allDigestsDefined = 0; + SZ_READ_BYTE_SD_NOCHECK(&ssi.sdCRCs, allDigestsDefined) + if (allDigestsDefined) + digestsVals = ssi.sdCRCs.Data; + else + { + const size_t numBytes = (ssi.NumSubDigests + 7) >> 3; + digestsDefs = ssi.sdCRCs.Data; + digestsVals = digestsDefs + numBytes; + } + } + + for (i = 0; i < numFiles; i++, mask >>= 1) + { + if (mask == 0) + { + const UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + isDirMask = 0; + crcMask = 0; + mask = 0x80; + } + + p->UnpackPositions[i] = unpackPos; + p->CRCs.Vals[i] = 0; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + { + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else + isDirMask |= mask; + if (remSubStreams == 0) + { + p->FileToFolder[i] = (UInt32)-1; + continue; + } + } + + if (remSubStreams == 0) + { + for (;;) + { + if (folderIndex >= p->db.NumFolders) + return SZ_ERROR_ARCHIVE; + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) + { + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)) + } + remSubStreams = numSubStreams; + if (numSubStreams != 0) + break; + { + const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + folderIndex++; + } + } + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) + continue; + + if (--remSubStreams == 0) + { + const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + const UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; + if (folderUnpackSize < unpackPos - startFolderUnpackPos) + return SZ_ERROR_ARCHIVE; + unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex)) + { + p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; + crcMask |= mask; + } + folderIndex++; + } + else + { + UInt64 v; + RINOK(ReadNumber(&ssi.sdSizes, &v)) + unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; + } + if ((crcMask & mask) == 0 && digestsVals) + { + if (!digestsDefs || SzBitArray_Check(digestsDefs, digestIndex)) + { + p->CRCs.Vals[i] = GetUi32(digestsVals); + digestsVals += 4; + crcMask |= mask; + } + digestIndex++; + } + } + + if (mask != 0x80) + { + const UInt32 byteIndex = (i - 1) >> 3; + p->IsDirs[byteIndex] = isDirMask; + p->CRCs.Defs[byteIndex] = crcMask; + } + + p->UnpackPositions[i] = unpackPos; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)) + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; + } +} + return SZ_OK; +} + + +static SRes SzReadHeader( + CSzArEx *p, + CSzData *sd, + ILookInStreamPtr inStream, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + UInt32 i; + UInt32 numTempBufs = 0; + SRes res; + CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX]; + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Init(tempBufs + i); + + res = SzReadHeader2(p, sd, inStream, + tempBufs, &numTempBufs, + allocMain, allocTemp); + + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) + Buf_Free(tempBufs + i, allocTemp); + + RINOK(res) + + if (sd->Size != 0) + return SZ_ERROR_FAIL; + + return res; +} + +static SRes SzArEx_Open2( + CSzArEx *p, + ILookInStreamPtr inStream, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + Byte header[k7zStartHeaderSize]; + Int64 startArcPos; + UInt64 nextHeaderOffset, nextHeaderSize; + size_t nextHeaderSizeT; + UInt32 nextHeaderCRC; + CBuf buf; + SRes res; + + startArcPos = 0; + RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR)) + + RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)) + + if (!TestSignatureCandidate(header)) + return SZ_ERROR_NO_ARCHIVE; + if (header[6] != k7zMajorVersion) + return SZ_ERROR_UNSUPPORTED; + + nextHeaderOffset = GetUi64(header + 12); + nextHeaderSize = GetUi64(header + 20); + nextHeaderCRC = GetUi32(header + 28); + + p->startPosAfterHeader = (UInt64)startArcPos + k7zStartHeaderSize; + + if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) + return SZ_ERROR_CRC; + + p->db.RangeLimit = nextHeaderOffset; + + nextHeaderSizeT = (size_t)nextHeaderSize; + if (nextHeaderSizeT != nextHeaderSize) + return SZ_ERROR_MEM; + if (nextHeaderSizeT == 0) + return SZ_OK; + if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || + nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) + return SZ_ERROR_NO_ARCHIVE; + + { + Int64 pos = 0; + RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END)) + if ((UInt64)pos < (UInt64)startArcPos + nextHeaderOffset || + (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset || + (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) + return SZ_ERROR_INPUT_EOF; + } + + RINOK(LookInStream_SeekTo(inStream, (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset)) + + if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp)) + return SZ_ERROR_MEM; + + res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + + if (res == SZ_OK) + { + res = SZ_ERROR_ARCHIVE; + if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC) + { + CSzData sd; + UInt64 type; + sd.Data = buf.data; + sd.Size = buf.size; + + res = ReadID(&sd, &type); + + if (res == SZ_OK && type == k7zIdEncodedHeader) + { + CSzAr tempAr; + CBuf tempBuf; + Buf_Init(&tempBuf); + + SzAr_Init(&tempAr); + tempAr.RangeLimit = p->db.RangeLimit; + + res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp); + SzAr_Free(&tempAr, allocTemp); + + if (res != SZ_OK) + { + Buf_Free(&tempBuf, allocTemp); + } + else + { + Buf_Free(&buf, allocTemp); + buf.data = tempBuf.data; + buf.size = tempBuf.size; + sd.Data = buf.data; + sd.Size = buf.size; + res = ReadID(&sd, &type); + } + } + + if (res == SZ_OK) + { + if (type == k7zIdHeader) + { + /* + CSzData sd2; + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) + { + SzArEx_Free(p, allocMain); + sd2 = sd; + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); + if (res != SZ_OK) + break; + } + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); + } + else + res = SZ_ERROR_UNSUPPORTED; + } + } + } + + Buf_Free(&buf, allocTemp); + return res; +} + + +SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream, + ISzAllocPtr allocMain, ISzAllocPtr allocTemp) +{ + const SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); + if (res != SZ_OK) + SzArEx_Free(p, allocMain); + return res; +} + + +SRes SzArEx_Extract( + const CSzArEx *p, + ILookInStreamPtr inStream, + UInt32 fileIndex, + UInt32 *blockIndex, + Byte **tempBuf, + size_t *outBufferSize, + size_t *offset, + size_t *outSizeProcessed, + ISzAllocPtr allocMain, + ISzAllocPtr allocTemp) +{ + const UInt32 folderIndex = p->FileToFolder[fileIndex]; + SRes res = SZ_OK; + + *offset = 0; + *outSizeProcessed = 0; + + if (folderIndex == (UInt32)-1) + { + ISzAlloc_Free(allocMain, *tempBuf); + *blockIndex = folderIndex; + *tempBuf = NULL; + *outBufferSize = 0; + return SZ_OK; + } + + if (*tempBuf == NULL || *blockIndex != folderIndex) + { + const UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* + UInt64 unpackSizeSpec = + p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ + const size_t unpackSize = (size_t)unpackSizeSpec; + + if (unpackSize != unpackSizeSpec) + return SZ_ERROR_MEM; + *blockIndex = folderIndex; + ISzAlloc_Free(allocMain, *tempBuf); + *tempBuf = NULL; + + if (res == SZ_OK) + { + *outBufferSize = unpackSize; + if (unpackSize != 0) + { + *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize); + if (*tempBuf == NULL) + res = SZ_ERROR_MEM; + } + + if (res == SZ_OK) + { + res = SzAr_DecodeFolder(&p->db, folderIndex, + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); + } + } + } + + if (res == SZ_OK) + { + const UInt64 unpackPos = p->UnpackPositions[fileIndex]; + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); + *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos); + if (*offset + *outSizeProcessed > *outBufferSize) + return SZ_ERROR_FAIL; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; + } + + return res; +} + + +size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + const size_t offs = p->FileNameOffsets[fileIndex]; + const size_t len = p->FileNameOffsets[fileIndex + 1] - offs; + if (dest != 0) + { + size_t i; + const Byte *src = p->FileNames + offs * 2; + for (i = 0; i < len; i++) + dest[i] = GetUi16(src + i * 2); + } + return len; +} + +/* +size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex) +{ + size_t len; + if (!p->FileNameOffsets) + return 1; + len = 0; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return len; + fileIndex = parent; + } +} + +UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest) +{ + BoolInt needSlash; + if (!p->FileNameOffsets) + { + *(--dest) = 0; + return dest; + } + needSlash = False; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; + SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen); + if (needSlash) + *(dest - 1) = '/'; + needSlash = True; + dest -= curLen; + + if SzBitWithVals_Check(&p->Parents, fileIndex) + parent = p->Parents.Vals[fileIndex]; + if (parent == (UInt32)(Int32)-1) + return dest; + fileIndex = parent; + } +} +*/ diff --git a/C/7zBuf.c b/C/7zBuf.c index 438bba68b..8865c32a8 100644 --- a/C/7zBuf.c +++ b/C/7zBuf.c @@ -1,36 +1,36 @@ -/* 7zBuf.c -- Byte Buffer -2017-04-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "7zBuf.h" - -void Buf_Init(CBuf *p) -{ - p->data = 0; - p->size = 0; -} - -int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc) -{ - p->size = 0; - if (size == 0) - { - p->data = 0; - return 1; - } - p->data = (Byte *)ISzAlloc_Alloc(alloc, size); - if (p->data) - { - p->size = size; - return 1; - } - return 0; -} - -void Buf_Free(CBuf *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->data); - p->data = 0; - p->size = 0; -} +/* 7zBuf.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zBuf.h" + +void Buf_Init(CBuf *p) +{ + p->data = 0; + p->size = 0; +} + +int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc) +{ + p->size = 0; + if (size == 0) + { + p->data = 0; + return 1; + } + p->data = (Byte *)ISzAlloc_Alloc(alloc, size); + if (p->data) + { + p->size = size; + return 1; + } + return 0; +} + +void Buf_Free(CBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; +} diff --git a/C/7zBuf.h b/C/7zBuf.h index ca34c1909..c0ba8a7b6 100644 --- a/C/7zBuf.h +++ b/C/7zBuf.h @@ -1,35 +1,35 @@ -/* 7zBuf.h -- Byte Buffer -2023-03-04 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_7Z_BUF_H -#define ZIP7_INC_7Z_BUF_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -typedef struct -{ - Byte *data; - size_t size; -} CBuf; - -void Buf_Init(CBuf *p); -int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc); -void Buf_Free(CBuf *p, ISzAllocPtr alloc); - -typedef struct -{ - Byte *data; - size_t size; - size_t pos; -} CDynBuf; - -void DynBuf_Construct(CDynBuf *p); -void DynBuf_SeekToBeg(CDynBuf *p); -int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc); -void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc); - -EXTERN_C_END - -#endif +/* 7zBuf.h -- Byte Buffer +2023-03-04 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_BUF_H +#define ZIP7_INC_7Z_BUF_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + Byte *data; + size_t size; +} CBuf; + +void Buf_Init(CBuf *p); +int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc); +void Buf_Free(CBuf *p, ISzAllocPtr alloc); + +typedef struct +{ + Byte *data; + size_t size; + size_t pos; +} CDynBuf; + +void DynBuf_Construct(CDynBuf *p); +void DynBuf_SeekToBeg(CDynBuf *p); +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc); +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/C/7zBuf2.c b/C/7zBuf2.c index 49b4343b6..208347416 100644 --- a/C/7zBuf2.c +++ b/C/7zBuf2.c @@ -1,52 +1,52 @@ -/* 7zBuf2.c -- Byte Buffer -2017-04-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "7zBuf.h" - -void DynBuf_Construct(CDynBuf *p) -{ - p->data = 0; - p->size = 0; - p->pos = 0; -} - -void DynBuf_SeekToBeg(CDynBuf *p) -{ - p->pos = 0; -} - -int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc) -{ - if (size > p->size - p->pos) - { - size_t newSize = p->pos + size; - Byte *data; - newSize += newSize / 4; - data = (Byte *)ISzAlloc_Alloc(alloc, newSize); - if (!data) - return 0; - p->size = newSize; - if (p->pos != 0) - memcpy(data, p->data, p->pos); - ISzAlloc_Free(alloc, p->data); - p->data = data; - } - if (size != 0) - { - memcpy(p->data + p->pos, buf, size); - p->pos += size; - } - return 1; -} - -void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->data); - p->data = 0; - p->size = 0; - p->pos = 0; -} +/* 7zBuf2.c -- Byte Buffer +2017-04-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zBuf.h" + +void DynBuf_Construct(CDynBuf *p) +{ + p->data = 0; + p->size = 0; + p->pos = 0; +} + +void DynBuf_SeekToBeg(CDynBuf *p) +{ + p->pos = 0; +} + +int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + if (size > p->size - p->pos) + { + size_t newSize = p->pos + size; + Byte *data; + newSize += newSize / 4; + data = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!data) + return 0; + p->size = newSize; + if (p->pos != 0) + memcpy(data, p->data, p->pos); + ISzAlloc_Free(alloc, p->data); + p->data = data; + } + if (size != 0) + { + memcpy(p->data + p->pos, buf, size); + p->pos += size; + } + return 1; +} + +void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->data); + p->data = 0; + p->size = 0; + p->pos = 0; +} diff --git a/C/7zCrc.c b/C/7zCrc.c index 9be9a75ac..6e2db9eab 100644 --- a/C/7zCrc.c +++ b/C/7zCrc.c @@ -1,420 +1,420 @@ -/* 7zCrc.c -- CRC32 calculation and init -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "7zCrc.h" -#include "CpuArch.h" - -// for debug: -// #define __ARM_FEATURE_CRC32 1 - -#ifdef __ARM_FEATURE_CRC32 -// #pragma message("__ARM_FEATURE_CRC32") -#define Z7_CRC_HW_FORCE -#endif - -// #define Z7_CRC_DEBUG_BE -#ifdef Z7_CRC_DEBUG_BE -#undef MY_CPU_LE -#define MY_CPU_BE -#endif - -#ifdef Z7_CRC_HW_FORCE - #define Z7_CRC_NUM_TABLES_USE 1 -#else -#ifdef Z7_CRC_NUM_TABLES - #define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES -#else - #define Z7_CRC_NUM_TABLES_USE 12 -#endif -#endif - -#if Z7_CRC_NUM_TABLES_USE < 1 - #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES -#endif - -#if defined(MY_CPU_LE) || (Z7_CRC_NUM_TABLES_USE == 1) - #define Z7_CRC_NUM_TABLES_TOTAL Z7_CRC_NUM_TABLES_USE -#else - #define Z7_CRC_NUM_TABLES_TOTAL (Z7_CRC_NUM_TABLES_USE + 1) -#endif - -#ifndef Z7_CRC_HW_FORCE - -#if Z7_CRC_NUM_TABLES_USE == 1 \ - || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -#define Z7_CRC_UPDATE_T1_FUNC_NAME CrcUpdateGT1 -static UInt32 Z7_FASTCALL Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v, const void *data, size_t size) -{ - const UInt32 *table = g_CrcTable; - const Byte *p = (const Byte *)data; - const Byte *lim = p + size; - for (; p != lim; p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; -} -#endif - - -#if Z7_CRC_NUM_TABLES_USE != 1 -#ifndef MY_CPU_BE - #define FUNC_NAME_LE_2(s) CrcUpdateT ## s - #define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s) - #define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC_NUM_TABLES_USE) - UInt32 Z7_FASTCALL FUNC_NAME_LE (UInt32 v, const void *data, size_t size, const UInt32 *table); -#endif -#ifndef MY_CPU_LE - #define FUNC_NAME_BE_2(s) CrcUpdateT1_BeT ## s - #define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s) - #define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC_NUM_TABLES_USE) - UInt32 Z7_FASTCALL FUNC_NAME_BE (UInt32 v, const void *data, size_t size, const UInt32 *table); -#endif -#endif - -#endif // Z7_CRC_HW_FORCE - -/* ---------- hardware CRC ---------- */ - -#ifdef MY_CPU_LE - -#if defined(MY_CPU_ARM_OR_ARM64) -// #pragma message("ARM*") - - #if (defined(__clang__) && (__clang_major__ >= 3)) \ - || defined(__GNUC__) && (__GNUC__ >= 6) && defined(MY_CPU_ARM64) \ - || defined(__GNUC__) && (__GNUC__ >= 8) - #if !defined(__ARM_FEATURE_CRC32) -// #pragma message("!defined(__ARM_FEATURE_CRC32)") -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #define __ARM_FEATURE_CRC32 1 -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER - #define Z7_ARM_FEATURE_CRC32_WAS_SET - #if defined(__clang__) - #if defined(MY_CPU_ARM64) - #define ATTRIB_CRC __attribute__((__target__("crc"))) - #else - #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc"))) - #endif - #else - #if defined(MY_CPU_ARM64) -#if !defined(Z7_GCC_VERSION) || (Z7_GCC_VERSION >= 60000) - #define ATTRIB_CRC __attribute__((__target__("+crc"))) -#endif - #else -#if !defined(Z7_GCC_VERSION) || (__GNUC__ >= 8) -#if defined(__ARM_FP) && __GNUC__ >= 8 -// for -mfloat-abi=hard: similar to - #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc+simd"))) -#else - #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc"))) -#endif -#endif - #endif - #endif - #endif - #if defined(__ARM_FEATURE_CRC32) - // #pragma message("") -/* -arm_acle.h (GGC): - before Nov 17, 2017: -#ifdef __ARM_FEATURE_CRC32 - - Nov 17, 2017: gcc10.0 (gcc 9.2.0) checked" -#if __ARM_ARCH >= 8 -#pragma GCC target ("arch=armv8-a+crc") - - Aug 22, 2019: GCC 8.4?, 9.2.1, 10.1: -#ifdef __ARM_FEATURE_CRC32 -#ifdef __ARM_FP -#pragma GCC target ("arch=armv8-a+crc+simd") -#else -#pragma GCC target ("arch=armv8-a+crc") -#endif -*/ -#if defined(__ARM_ARCH) && __ARM_ARCH < 8 -#if defined(Z7_GCC_VERSION) && (__GNUC__ == 8) && (Z7_GCC_VERSION < 80400) \ - || defined(Z7_GCC_VERSION) && (__GNUC__ == 9) && (Z7_GCC_VERSION < 90201) \ - || defined(Z7_GCC_VERSION) && (__GNUC__ == 10) && (Z7_GCC_VERSION < 100100) -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -// #pragma message("#define __ARM_ARCH 8") -#undef __ARM_ARCH -#define __ARM_ARCH 8 -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif -#endif - #define Z7_CRC_HW_USE - #include - #endif - #elif defined(_MSC_VER) - #if defined(MY_CPU_ARM64) - #if (_MSC_VER >= 1910) - #ifdef __clang__ - // #define Z7_CRC_HW_USE - // #include - #else - #define Z7_CRC_HW_USE - #include - #endif - #endif - #endif - #endif - -#else // non-ARM* - -// #define Z7_CRC_HW_USE // for debug : we can test HW-branch of code -#ifdef Z7_CRC_HW_USE -#include "7zCrcEmu.h" -#endif - -#endif // non-ARM* - - - -#if defined(Z7_CRC_HW_USE) - -// #pragma message("USE ARM HW CRC") - -#ifdef MY_CPU_64BIT - #define CRC_HW_WORD_TYPE UInt64 - #define CRC_HW_WORD_FUNC __crc32d -#else - #define CRC_HW_WORD_TYPE UInt32 - #define CRC_HW_WORD_FUNC __crc32w -#endif - -#define CRC_HW_UNROLL_BYTES (sizeof(CRC_HW_WORD_TYPE) * 4) - -#ifdef ATTRIB_CRC - ATTRIB_CRC -#endif -Z7_NO_INLINE -#ifdef Z7_CRC_HW_FORCE - UInt32 Z7_FASTCALL CrcUpdate -#else - static UInt32 Z7_FASTCALL CrcUpdate_HW -#endif - (UInt32 v, const void *data, size_t size) -{ - const Byte *p = (const Byte *)data; - for (; size != 0 && ((unsigned)(ptrdiff_t)p & (CRC_HW_UNROLL_BYTES - 1)) != 0; size--) - v = __crc32b(v, *p++); - if (size >= CRC_HW_UNROLL_BYTES) - { - const Byte *lim = p + size; - size &= CRC_HW_UNROLL_BYTES - 1; - lim -= size; - do - { - v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p)); - v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE))); - p += 2 * sizeof(CRC_HW_WORD_TYPE); - v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p)); - v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE))); - p += 2 * sizeof(CRC_HW_WORD_TYPE); - } - while (p != lim); - } - - for (; size != 0; size--) - v = __crc32b(v, *p++); - - return v; -} - -#ifdef Z7_ARM_FEATURE_CRC32_WAS_SET -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -#undef __ARM_FEATURE_CRC32 -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#undef Z7_ARM_FEATURE_CRC32_WAS_SET -#endif - -#endif // defined(Z7_CRC_HW_USE) -#endif // MY_CPU_LE - - - -#ifndef Z7_CRC_HW_FORCE - -#if defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) -/* -typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_WITH_TABLE_FUNC) - (UInt32 v, const void *data, size_t size, const UInt32 *table); -Z7_CRC_UPDATE_WITH_TABLE_FUNC g_CrcUpdate; -*/ -static unsigned g_Crc_Algo; -#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) -static unsigned g_Crc_Be; -#endif -#endif // defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) - - - -Z7_NO_INLINE -#ifdef Z7_CRC_HW_USE - static UInt32 Z7_FASTCALL CrcUpdate_Base -#else - UInt32 Z7_FASTCALL CrcUpdate -#endif - (UInt32 crc, const void *data, size_t size) -{ -#if Z7_CRC_NUM_TABLES_USE == 1 - return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size); -#else // Z7_CRC_NUM_TABLES_USE != 1 -#ifdef Z7_CRC_UPDATE_T1_FUNC_NAME - if (g_Crc_Algo == 1) - return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size); -#endif - -#ifdef MY_CPU_LE - return FUNC_NAME_LE(crc, data, size, g_CrcTable); -#elif defined(MY_CPU_BE) - return FUNC_NAME_BE(crc, data, size, g_CrcTable); -#else - if (g_Crc_Be) - return FUNC_NAME_BE(crc, data, size, g_CrcTable); - else - return FUNC_NAME_LE(crc, data, size, g_CrcTable); -#endif -#endif // Z7_CRC_NUM_TABLES_USE != 1 -} - - -#ifdef Z7_CRC_HW_USE -Z7_NO_INLINE -UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size) -{ - if (g_Crc_Algo == 0) - return CrcUpdate_HW(crc, data, size); - return CrcUpdate_Base(crc, data, size); -} -#endif - -#endif // !defined(Z7_CRC_HW_FORCE) - - - -UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size) -{ - return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL; -} - - -MY_ALIGN(64) -UInt32 g_CrcTable[256 * Z7_CRC_NUM_TABLES_TOTAL]; - - -void Z7_FASTCALL CrcGenerateTable(void) -{ - UInt32 i; - for (i = 0; i < 256; i++) - { -#if defined(Z7_CRC_HW_FORCE) - g_CrcTable[i] = __crc32b(i, 0); -#else - #define kCrcPoly 0xEDB88320 - UInt32 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); - g_CrcTable[i] = r; -#endif - } - for (i = 256; i < 256 * Z7_CRC_NUM_TABLES_USE; i++) - { - const UInt32 r = g_CrcTable[(size_t)i - 256]; - g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); - } - -#if !defined(Z7_CRC_HW_FORCE) && \ - (defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) || defined(MY_CPU_BE)) - -#if Z7_CRC_NUM_TABLES_USE <= 1 - g_Crc_Algo = 1; -#else // Z7_CRC_NUM_TABLES_USE <= 1 - -#if defined(MY_CPU_LE) - g_Crc_Algo = Z7_CRC_NUM_TABLES_USE; -#else // !defined(MY_CPU_LE) - { -#ifndef MY_CPU_BE - UInt32 k = 0x01020304; - const Byte *p = (const Byte *)&k; - if (p[0] == 4 && p[1] == 3) - g_Crc_Algo = Z7_CRC_NUM_TABLES_USE; - else if (p[0] != 1 || p[1] != 2) - g_Crc_Algo = 1; - else -#endif // MY_CPU_BE - { - for (i = 256 * Z7_CRC_NUM_TABLES_TOTAL - 1; i >= 256; i--) - { - const UInt32 x = g_CrcTable[(size_t)i - 256]; - g_CrcTable[i] = Z7_BSWAP32(x); - } -#if defined(Z7_CRC_UPDATE_T1_FUNC_NAME) - g_Crc_Algo = Z7_CRC_NUM_TABLES_USE; -#endif -#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) - g_Crc_Be = 1; -#endif - } - } -#endif // !defined(MY_CPU_LE) - -#ifdef MY_CPU_LE -#ifdef Z7_CRC_HW_USE - if (CPU_IsSupported_CRC32()) - g_Crc_Algo = 0; -#endif // Z7_CRC_HW_USE -#endif // MY_CPU_LE - -#endif // Z7_CRC_NUM_TABLES_USE <= 1 -#endif // g_Crc_Algo was declared -} - -Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo) -{ - if (algo == 0) - return &CrcUpdate; - -#if defined(Z7_CRC_HW_USE) - if (algo == sizeof(CRC_HW_WORD_TYPE) * 8) - { -#ifdef Z7_CRC_HW_FORCE - return &CrcUpdate; -#else - if (g_Crc_Algo == 0) - return &CrcUpdate_HW; -#endif - } -#endif - -#ifndef Z7_CRC_HW_FORCE - if (algo == Z7_CRC_NUM_TABLES_USE) - return - #ifdef Z7_CRC_HW_USE - &CrcUpdate_Base; - #else - &CrcUpdate; - #endif -#endif - - return NULL; -} - -#undef kCrcPoly -#undef Z7_CRC_NUM_TABLES_USE -#undef Z7_CRC_NUM_TABLES_TOTAL -#undef CRC_UPDATE_BYTE_2 -#undef FUNC_NAME_LE_2 -#undef FUNC_NAME_LE_1 -#undef FUNC_NAME_LE -#undef FUNC_NAME_BE_2 -#undef FUNC_NAME_BE_1 -#undef FUNC_NAME_BE - -#undef CRC_HW_UNROLL_BYTES -#undef CRC_HW_WORD_FUNC -#undef CRC_HW_WORD_TYPE +/* 7zCrc.c -- CRC32 calculation and init +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" + +// for debug: +// #define __ARM_FEATURE_CRC32 1 + +#ifdef __ARM_FEATURE_CRC32 +// #pragma message("__ARM_FEATURE_CRC32") +#define Z7_CRC_HW_FORCE +#endif + +// #define Z7_CRC_DEBUG_BE +#ifdef Z7_CRC_DEBUG_BE +#undef MY_CPU_LE +#define MY_CPU_BE +#endif + +#ifdef Z7_CRC_HW_FORCE + #define Z7_CRC_NUM_TABLES_USE 1 +#else +#ifdef Z7_CRC_NUM_TABLES + #define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES +#else + #define Z7_CRC_NUM_TABLES_USE 12 +#endif +#endif + +#if Z7_CRC_NUM_TABLES_USE < 1 + #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES +#endif + +#if defined(MY_CPU_LE) || (Z7_CRC_NUM_TABLES_USE == 1) + #define Z7_CRC_NUM_TABLES_TOTAL Z7_CRC_NUM_TABLES_USE +#else + #define Z7_CRC_NUM_TABLES_TOTAL (Z7_CRC_NUM_TABLES_USE + 1) +#endif + +#ifndef Z7_CRC_HW_FORCE + +#if Z7_CRC_NUM_TABLES_USE == 1 \ + || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) +#define Z7_CRC_UPDATE_T1_FUNC_NAME CrcUpdateGT1 +static UInt32 Z7_FASTCALL Z7_CRC_UPDATE_T1_FUNC_NAME(UInt32 v, const void *data, size_t size) +{ + const UInt32 *table = g_CrcTable; + const Byte *p = (const Byte *)data; + const Byte *lim = p + size; + for (; p != lim; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} +#endif + + +#if Z7_CRC_NUM_TABLES_USE != 1 +#ifndef MY_CPU_BE + #define FUNC_NAME_LE_2(s) CrcUpdateT ## s + #define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s) + #define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC_NUM_TABLES_USE) + UInt32 Z7_FASTCALL FUNC_NAME_LE (UInt32 v, const void *data, size_t size, const UInt32 *table); +#endif +#ifndef MY_CPU_LE + #define FUNC_NAME_BE_2(s) CrcUpdateT1_BeT ## s + #define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s) + #define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC_NUM_TABLES_USE) + UInt32 Z7_FASTCALL FUNC_NAME_BE (UInt32 v, const void *data, size_t size, const UInt32 *table); +#endif +#endif + +#endif // Z7_CRC_HW_FORCE + +/* ---------- hardware CRC ---------- */ + +#ifdef MY_CPU_LE + +#if defined(MY_CPU_ARM_OR_ARM64) +// #pragma message("ARM*") + + #if (defined(__clang__) && (__clang_major__ >= 3)) \ + || defined(__GNUC__) && (__GNUC__ >= 6) && defined(MY_CPU_ARM64) \ + || defined(__GNUC__) && (__GNUC__ >= 8) + #if !defined(__ARM_FEATURE_CRC32) +// #pragma message("!defined(__ARM_FEATURE_CRC32)") +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define __ARM_FEATURE_CRC32 1 +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER + #define Z7_ARM_FEATURE_CRC32_WAS_SET + #if defined(__clang__) + #if defined(MY_CPU_ARM64) + #define ATTRIB_CRC __attribute__((__target__("crc"))) + #else + #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc"))) + #endif + #else + #if defined(MY_CPU_ARM64) +#if !defined(Z7_GCC_VERSION) || (Z7_GCC_VERSION >= 60000) + #define ATTRIB_CRC __attribute__((__target__("+crc"))) +#endif + #else +#if !defined(Z7_GCC_VERSION) || (__GNUC__ >= 8) +#if defined(__ARM_FP) && __GNUC__ >= 8 +// for -mfloat-abi=hard: similar to + #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc+simd"))) +#else + #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc"))) +#endif +#endif + #endif + #endif + #endif + #if defined(__ARM_FEATURE_CRC32) + // #pragma message("") +/* +arm_acle.h (GGC): + before Nov 17, 2017: +#ifdef __ARM_FEATURE_CRC32 + + Nov 17, 2017: gcc10.0 (gcc 9.2.0) checked" +#if __ARM_ARCH >= 8 +#pragma GCC target ("arch=armv8-a+crc") + + Aug 22, 2019: GCC 8.4?, 9.2.1, 10.1: +#ifdef __ARM_FEATURE_CRC32 +#ifdef __ARM_FP +#pragma GCC target ("arch=armv8-a+crc+simd") +#else +#pragma GCC target ("arch=armv8-a+crc") +#endif +*/ +#if defined(__ARM_ARCH) && __ARM_ARCH < 8 +#if defined(Z7_GCC_VERSION) && (__GNUC__ == 8) && (Z7_GCC_VERSION < 80400) \ + || defined(Z7_GCC_VERSION) && (__GNUC__ == 9) && (Z7_GCC_VERSION < 90201) \ + || defined(Z7_GCC_VERSION) && (__GNUC__ == 10) && (Z7_GCC_VERSION < 100100) +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +// #pragma message("#define __ARM_ARCH 8") +#undef __ARM_ARCH +#define __ARM_ARCH 8 +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif + #define Z7_CRC_HW_USE + #include + #endif + #elif defined(_MSC_VER) + #if defined(MY_CPU_ARM64) + #if (_MSC_VER >= 1910) + #ifdef __clang__ + // #define Z7_CRC_HW_USE + // #include + #else + #define Z7_CRC_HW_USE + #include + #endif + #endif + #endif + #endif + +#else // non-ARM* + +// #define Z7_CRC_HW_USE // for debug : we can test HW-branch of code +#ifdef Z7_CRC_HW_USE +#include "7zCrcEmu.h" +#endif + +#endif // non-ARM* + + + +#if defined(Z7_CRC_HW_USE) + +// #pragma message("USE ARM HW CRC") + +#ifdef MY_CPU_64BIT + #define CRC_HW_WORD_TYPE UInt64 + #define CRC_HW_WORD_FUNC __crc32d +#else + #define CRC_HW_WORD_TYPE UInt32 + #define CRC_HW_WORD_FUNC __crc32w +#endif + +#define CRC_HW_UNROLL_BYTES (sizeof(CRC_HW_WORD_TYPE) * 4) + +#ifdef ATTRIB_CRC + ATTRIB_CRC +#endif +Z7_NO_INLINE +#ifdef Z7_CRC_HW_FORCE + UInt32 Z7_FASTCALL CrcUpdate +#else + static UInt32 Z7_FASTCALL CrcUpdate_HW +#endif + (UInt32 v, const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + for (; size != 0 && ((unsigned)(ptrdiff_t)p & (CRC_HW_UNROLL_BYTES - 1)) != 0; size--) + v = __crc32b(v, *p++); + if (size >= CRC_HW_UNROLL_BYTES) + { + const Byte *lim = p + size; + size &= CRC_HW_UNROLL_BYTES - 1; + lim -= size; + do + { + v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p)); + v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE))); + p += 2 * sizeof(CRC_HW_WORD_TYPE); + v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p)); + v = CRC_HW_WORD_FUNC(v, *(const CRC_HW_WORD_TYPE *)(const void *)(p + sizeof(CRC_HW_WORD_TYPE))); + p += 2 * sizeof(CRC_HW_WORD_TYPE); + } + while (p != lim); + } + + for (; size != 0; size--) + v = __crc32b(v, *p++); + + return v; +} + +#ifdef Z7_ARM_FEATURE_CRC32_WAS_SET +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#undef __ARM_FEATURE_CRC32 +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#undef Z7_ARM_FEATURE_CRC32_WAS_SET +#endif + +#endif // defined(Z7_CRC_HW_USE) +#endif // MY_CPU_LE + + + +#ifndef Z7_CRC_HW_FORCE + +#if defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) +/* +typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_WITH_TABLE_FUNC) + (UInt32 v, const void *data, size_t size, const UInt32 *table); +Z7_CRC_UPDATE_WITH_TABLE_FUNC g_CrcUpdate; +*/ +static unsigned g_Crc_Algo; +#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) +static unsigned g_Crc_Be; +#endif +#endif // defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) + + + +Z7_NO_INLINE +#ifdef Z7_CRC_HW_USE + static UInt32 Z7_FASTCALL CrcUpdate_Base +#else + UInt32 Z7_FASTCALL CrcUpdate +#endif + (UInt32 crc, const void *data, size_t size) +{ +#if Z7_CRC_NUM_TABLES_USE == 1 + return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size); +#else // Z7_CRC_NUM_TABLES_USE != 1 +#ifdef Z7_CRC_UPDATE_T1_FUNC_NAME + if (g_Crc_Algo == 1) + return Z7_CRC_UPDATE_T1_FUNC_NAME(crc, data, size); +#endif + +#ifdef MY_CPU_LE + return FUNC_NAME_LE(crc, data, size, g_CrcTable); +#elif defined(MY_CPU_BE) + return FUNC_NAME_BE(crc, data, size, g_CrcTable); +#else + if (g_Crc_Be) + return FUNC_NAME_BE(crc, data, size, g_CrcTable); + else + return FUNC_NAME_LE(crc, data, size, g_CrcTable); +#endif +#endif // Z7_CRC_NUM_TABLES_USE != 1 +} + + +#ifdef Z7_CRC_HW_USE +Z7_NO_INLINE +UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size) +{ + if (g_Crc_Algo == 0) + return CrcUpdate_HW(crc, data, size); + return CrcUpdate_Base(crc, data, size); +} +#endif + +#endif // !defined(Z7_CRC_HW_FORCE) + + + +UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size) +{ + return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL; +} + + +MY_ALIGN(64) +UInt32 g_CrcTable[256 * Z7_CRC_NUM_TABLES_TOTAL]; + + +void Z7_FASTCALL CrcGenerateTable(void) +{ + UInt32 i; + for (i = 0; i < 256; i++) + { +#if defined(Z7_CRC_HW_FORCE) + g_CrcTable[i] = __crc32b(i, 0); +#else + #define kCrcPoly 0xEDB88320 + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + g_CrcTable[i] = r; +#endif + } + for (i = 256; i < 256 * Z7_CRC_NUM_TABLES_USE; i++) + { + const UInt32 r = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); + } + +#if !defined(Z7_CRC_HW_FORCE) && \ + (defined(Z7_CRC_HW_USE) || defined(Z7_CRC_UPDATE_T1_FUNC_NAME) || defined(MY_CPU_BE)) + +#if Z7_CRC_NUM_TABLES_USE <= 1 + g_Crc_Algo = 1; +#else // Z7_CRC_NUM_TABLES_USE <= 1 + +#if defined(MY_CPU_LE) + g_Crc_Algo = Z7_CRC_NUM_TABLES_USE; +#else // !defined(MY_CPU_LE) + { +#ifndef MY_CPU_BE + UInt32 k = 0x01020304; + const Byte *p = (const Byte *)&k; + if (p[0] == 4 && p[1] == 3) + g_Crc_Algo = Z7_CRC_NUM_TABLES_USE; + else if (p[0] != 1 || p[1] != 2) + g_Crc_Algo = 1; + else +#endif // MY_CPU_BE + { + for (i = 256 * Z7_CRC_NUM_TABLES_TOTAL - 1; i >= 256; i--) + { + const UInt32 x = g_CrcTable[(size_t)i - 256]; + g_CrcTable[i] = Z7_BSWAP32(x); + } +#if defined(Z7_CRC_UPDATE_T1_FUNC_NAME) + g_Crc_Algo = Z7_CRC_NUM_TABLES_USE; +#endif +#if (!defined(MY_CPU_LE) && !defined(MY_CPU_BE)) + g_Crc_Be = 1; +#endif + } + } +#endif // !defined(MY_CPU_LE) + +#ifdef MY_CPU_LE +#ifdef Z7_CRC_HW_USE + if (CPU_IsSupported_CRC32()) + g_Crc_Algo = 0; +#endif // Z7_CRC_HW_USE +#endif // MY_CPU_LE + +#endif // Z7_CRC_NUM_TABLES_USE <= 1 +#endif // g_Crc_Algo was declared +} + +Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo) +{ + if (algo == 0) + return &CrcUpdate; + +#if defined(Z7_CRC_HW_USE) + if (algo == sizeof(CRC_HW_WORD_TYPE) * 8) + { +#ifdef Z7_CRC_HW_FORCE + return &CrcUpdate; +#else + if (g_Crc_Algo == 0) + return &CrcUpdate_HW; +#endif + } +#endif + +#ifndef Z7_CRC_HW_FORCE + if (algo == Z7_CRC_NUM_TABLES_USE) + return + #ifdef Z7_CRC_HW_USE + &CrcUpdate_Base; + #else + &CrcUpdate; + #endif +#endif + + return NULL; +} + +#undef kCrcPoly +#undef Z7_CRC_NUM_TABLES_USE +#undef Z7_CRC_NUM_TABLES_TOTAL +#undef CRC_UPDATE_BYTE_2 +#undef FUNC_NAME_LE_2 +#undef FUNC_NAME_LE_1 +#undef FUNC_NAME_LE +#undef FUNC_NAME_BE_2 +#undef FUNC_NAME_BE_1 +#undef FUNC_NAME_BE + +#undef CRC_HW_UNROLL_BYTES +#undef CRC_HW_WORD_FUNC +#undef CRC_HW_WORD_TYPE diff --git a/C/7zCrc.h b/C/7zCrc.h index ed0423580..3e6d408b9 100644 --- a/C/7zCrc.h +++ b/C/7zCrc.h @@ -1,28 +1,28 @@ -/* 7zCrc.h -- CRC32 calculation -2024-01-22 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_7Z_CRC_H -#define ZIP7_INC_7Z_CRC_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -extern UInt32 g_CrcTable[]; - -/* Call CrcGenerateTable one time before other CRC functions */ -void Z7_FASTCALL CrcGenerateTable(void); - -#define CRC_INIT_VAL 0xFFFFFFFF -#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) -#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size); -UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size); - -typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_FUNC)(UInt32 v, const void *data, size_t size); -Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo); - -EXTERN_C_END - -#endif +/* 7zCrc.h -- CRC32 calculation +2024-01-22 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_CRC_H +#define ZIP7_INC_7Z_CRC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +extern UInt32 g_CrcTable[]; + +/* Call CrcGenerateTable one time before other CRC functions */ +void Z7_FASTCALL CrcGenerateTable(void); + +#define CRC_INIT_VAL 0xFFFFFFFF +#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) +#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size); +UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size); + +typedef UInt32 (Z7_FASTCALL *Z7_CRC_UPDATE_FUNC)(UInt32 v, const void *data, size_t size); +Z7_CRC_UPDATE_FUNC z7_GetFunc_CrcUpdate(unsigned algo); + +EXTERN_C_END + +#endif diff --git a/C/7zCrcOpt.c b/C/7zCrcOpt.c index bbb61f547..9408017ed 100644 --- a/C/7zCrcOpt.c +++ b/C/7zCrcOpt.c @@ -1,199 +1,199 @@ -/* 7zCrcOpt.c -- CRC32 calculation (optimized functions) -2023-12-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "CpuArch.h" - -#if !defined(Z7_CRC_NUM_TABLES) || Z7_CRC_NUM_TABLES > 1 - -// for debug only : define Z7_CRC_DEBUG_BE to test big-endian code in little-endian cpu -// #define Z7_CRC_DEBUG_BE -#ifdef Z7_CRC_DEBUG_BE -#undef MY_CPU_LE -#define MY_CPU_BE -#endif - -// the value Z7_CRC_NUM_TABLES_USE must be defined to same value as in 7zCrc.c -#ifdef Z7_CRC_NUM_TABLES -#define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES -#else -#define Z7_CRC_NUM_TABLES_USE 12 -#endif - -#if Z7_CRC_NUM_TABLES_USE % 4 || \ - Z7_CRC_NUM_TABLES_USE < 4 * 1 || \ - Z7_CRC_NUM_TABLES_USE > 4 * 6 - #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES -#endif - - -#ifndef MY_CPU_BE - -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -#define Q(n, d) \ - ( (table + ((n) * 4 + 3) * 0x100)[(Byte)(d)] \ - ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] ) - -#define R(a) *((const UInt32 *)(const void *)p + (a)) - -#define CRC_FUNC_PRE_LE2(step) \ -UInt32 Z7_FASTCALL CrcUpdateT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table) - -#define CRC_FUNC_PRE_LE(step) \ - CRC_FUNC_PRE_LE2(step); \ - CRC_FUNC_PRE_LE2(step) - -CRC_FUNC_PRE_LE(Z7_CRC_NUM_TABLES_USE) -{ - const Byte *p = (const Byte *)data; - const Byte *lim; - for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - lim = p + size; - if (size >= Z7_CRC_NUM_TABLES_USE) - { - lim -= Z7_CRC_NUM_TABLES_USE; - do - { - v ^= R(0); - { -#if Z7_CRC_NUM_TABLES_USE == 1 * 4 - v = Q(0, v); -#else -#define U2(r, op) \ - { d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); } - UInt32 d, x; - U2(1, =) -#if Z7_CRC_NUM_TABLES_USE >= 3 * 4 -#define U(r) U2(r, ^=) - U(2) -#if Z7_CRC_NUM_TABLES_USE >= 4 * 4 - U(3) -#if Z7_CRC_NUM_TABLES_USE >= 5 * 4 - U(4) -#if Z7_CRC_NUM_TABLES_USE >= 6 * 4 - U(5) -#if Z7_CRC_NUM_TABLES_USE >= 7 * 4 -#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES -#endif -#endif -#endif -#endif -#endif -#undef U -#undef U2 - v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v); -#endif - } - p += Z7_CRC_NUM_TABLES_USE; - } - while (p <= lim); - lim += Z7_CRC_NUM_TABLES_USE; - } - for (; p < lim; p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; -} - -#undef CRC_UPDATE_BYTE_2 -#undef R -#undef Q -#undef CRC_FUNC_PRE_LE -#undef CRC_FUNC_PRE_LE2 - -#endif - - - - -#ifndef MY_CPU_LE - -#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[((crc) >> 24) ^ (b)] ^ ((crc) << 8)) - -#define Q(n, d) \ - ( (table + ((n) * 4 + 0) * 0x100)[((d)) & 0xFF] \ - ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] ) - -#ifdef Z7_CRC_DEBUG_BE - #define R(a) GetBe32a((const UInt32 *)(const void *)p + (a)) -#else - #define R(a) *((const UInt32 *)(const void *)p + (a)) -#endif - - -#define CRC_FUNC_PRE_BE2(step) \ -UInt32 Z7_FASTCALL CrcUpdateT1_BeT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table) - -#define CRC_FUNC_PRE_BE(step) \ - CRC_FUNC_PRE_BE2(step); \ - CRC_FUNC_PRE_BE2(step) - -CRC_FUNC_PRE_BE(Z7_CRC_NUM_TABLES_USE) -{ - const Byte *p = (const Byte *)data; - const Byte *lim; - table += 0x100; - v = Z7_BSWAP32(v); - for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2_BE(v, *p); - lim = p + size; - if (size >= Z7_CRC_NUM_TABLES_USE) - { - lim -= Z7_CRC_NUM_TABLES_USE; - do - { - v ^= R(0); - { -#if Z7_CRC_NUM_TABLES_USE == 1 * 4 - v = Q(0, v); -#else -#define U2(r, op) \ - { d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); } - UInt32 d, x; - U2(1, =) -#if Z7_CRC_NUM_TABLES_USE >= 3 * 4 -#define U(r) U2(r, ^=) - U(2) -#if Z7_CRC_NUM_TABLES_USE >= 4 * 4 - U(3) -#if Z7_CRC_NUM_TABLES_USE >= 5 * 4 - U(4) -#if Z7_CRC_NUM_TABLES_USE >= 6 * 4 - U(5) -#if Z7_CRC_NUM_TABLES_USE >= 7 * 4 -#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES -#endif -#endif -#endif -#endif -#endif -#undef U -#undef U2 - v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v); -#endif - } - p += Z7_CRC_NUM_TABLES_USE; - } - while (p <= lim); - lim += Z7_CRC_NUM_TABLES_USE; - } - for (; p < lim; p++) - v = CRC_UPDATE_BYTE_2_BE(v, *p); - return Z7_BSWAP32(v); -} - -#undef CRC_UPDATE_BYTE_2_BE -#undef R -#undef Q -#undef CRC_FUNC_PRE_BE -#undef CRC_FUNC_PRE_BE2 - -#endif -#undef Z7_CRC_NUM_TABLES_USE -#endif +/* 7zCrcOpt.c -- CRC32 calculation (optimized functions) +2023-12-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#if !defined(Z7_CRC_NUM_TABLES) || Z7_CRC_NUM_TABLES > 1 + +// for debug only : define Z7_CRC_DEBUG_BE to test big-endian code in little-endian cpu +// #define Z7_CRC_DEBUG_BE +#ifdef Z7_CRC_DEBUG_BE +#undef MY_CPU_LE +#define MY_CPU_BE +#endif + +// the value Z7_CRC_NUM_TABLES_USE must be defined to same value as in 7zCrc.c +#ifdef Z7_CRC_NUM_TABLES +#define Z7_CRC_NUM_TABLES_USE Z7_CRC_NUM_TABLES +#else +#define Z7_CRC_NUM_TABLES_USE 12 +#endif + +#if Z7_CRC_NUM_TABLES_USE % 4 || \ + Z7_CRC_NUM_TABLES_USE < 4 * 1 || \ + Z7_CRC_NUM_TABLES_USE > 4 * 6 + #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES +#endif + + +#ifndef MY_CPU_BE + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +#define Q(n, d) \ + ( (table + ((n) * 4 + 3) * 0x100)[(Byte)(d)] \ + ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] ) + +#define R(a) *((const UInt32 *)(const void *)p + (a)) + +#define CRC_FUNC_PRE_LE2(step) \ +UInt32 Z7_FASTCALL CrcUpdateT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table) + +#define CRC_FUNC_PRE_LE(step) \ + CRC_FUNC_PRE_LE2(step); \ + CRC_FUNC_PRE_LE2(step) + +CRC_FUNC_PRE_LE(Z7_CRC_NUM_TABLES_USE) +{ + const Byte *p = (const Byte *)data; + const Byte *lim; + for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + lim = p + size; + if (size >= Z7_CRC_NUM_TABLES_USE) + { + lim -= Z7_CRC_NUM_TABLES_USE; + do + { + v ^= R(0); + { +#if Z7_CRC_NUM_TABLES_USE == 1 * 4 + v = Q(0, v); +#else +#define U2(r, op) \ + { d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); } + UInt32 d, x; + U2(1, =) +#if Z7_CRC_NUM_TABLES_USE >= 3 * 4 +#define U(r) U2(r, ^=) + U(2) +#if Z7_CRC_NUM_TABLES_USE >= 4 * 4 + U(3) +#if Z7_CRC_NUM_TABLES_USE >= 5 * 4 + U(4) +#if Z7_CRC_NUM_TABLES_USE >= 6 * 4 + U(5) +#if Z7_CRC_NUM_TABLES_USE >= 7 * 4 +#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES +#endif +#endif +#endif +#endif +#endif +#undef U +#undef U2 + v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v); +#endif + } + p += Z7_CRC_NUM_TABLES_USE; + } + while (p <= lim); + lim += Z7_CRC_NUM_TABLES_USE; + } + for (; p < lim; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +#undef CRC_UPDATE_BYTE_2 +#undef R +#undef Q +#undef CRC_FUNC_PRE_LE +#undef CRC_FUNC_PRE_LE2 + +#endif + + + + +#ifndef MY_CPU_LE + +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[((crc) >> 24) ^ (b)] ^ ((crc) << 8)) + +#define Q(n, d) \ + ( (table + ((n) * 4 + 0) * 0x100)[((d)) & 0xFF] \ + ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] ) + +#ifdef Z7_CRC_DEBUG_BE + #define R(a) GetBe32a((const UInt32 *)(const void *)p + (a)) +#else + #define R(a) *((const UInt32 *)(const void *)p + (a)) +#endif + + +#define CRC_FUNC_PRE_BE2(step) \ +UInt32 Z7_FASTCALL CrcUpdateT1_BeT ## step (UInt32 v, const void *data, size_t size, const UInt32 *table) + +#define CRC_FUNC_PRE_BE(step) \ + CRC_FUNC_PRE_BE2(step); \ + CRC_FUNC_PRE_BE2(step) + +CRC_FUNC_PRE_BE(Z7_CRC_NUM_TABLES_USE) +{ + const Byte *p = (const Byte *)data; + const Byte *lim; + table += 0x100; + v = Z7_BSWAP32(v); + for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC_NUM_TABLES_USE & 4))) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + lim = p + size; + if (size >= Z7_CRC_NUM_TABLES_USE) + { + lim -= Z7_CRC_NUM_TABLES_USE; + do + { + v ^= R(0); + { +#if Z7_CRC_NUM_TABLES_USE == 1 * 4 + v = Q(0, v); +#else +#define U2(r, op) \ + { d = R(r); x op Q(Z7_CRC_NUM_TABLES_USE / 4 - 1 - (r), d); } + UInt32 d, x; + U2(1, =) +#if Z7_CRC_NUM_TABLES_USE >= 3 * 4 +#define U(r) U2(r, ^=) + U(2) +#if Z7_CRC_NUM_TABLES_USE >= 4 * 4 + U(3) +#if Z7_CRC_NUM_TABLES_USE >= 5 * 4 + U(4) +#if Z7_CRC_NUM_TABLES_USE >= 6 * 4 + U(5) +#if Z7_CRC_NUM_TABLES_USE >= 7 * 4 +#error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES +#endif +#endif +#endif +#endif +#endif +#undef U +#undef U2 + v = x ^ Q(Z7_CRC_NUM_TABLES_USE / 4 - 1, v); +#endif + } + p += Z7_CRC_NUM_TABLES_USE; + } + while (p <= lim); + lim += Z7_CRC_NUM_TABLES_USE; + } + for (; p < lim; p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return Z7_BSWAP32(v); +} + +#undef CRC_UPDATE_BYTE_2_BE +#undef R +#undef Q +#undef CRC_FUNC_PRE_BE +#undef CRC_FUNC_PRE_BE2 + +#endif +#undef Z7_CRC_NUM_TABLES_USE +#endif diff --git a/C/7zDec.c b/C/7zDec.c index 35aab4bd2..520cbfd83 100644 --- a/C/7zDec.c +++ b/C/7zDec.c @@ -1,672 +1,673 @@ -/* 7zDec.c -- Decoding from 7z folder -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #define Z7_PPMD_SUPPORT */ - -#include "7z.h" -#include "7zCrc.h" - -#include "Bcj2.h" -#include "Bra.h" -#include "CpuArch.h" -#include "Delta.h" -#include "LzmaDec.h" -#include "Lzma2Dec.h" -#ifdef Z7_PPMD_SUPPORT -#include "Ppmd7.h" -#endif - -#define k_Copy 0 -#ifndef Z7_NO_METHOD_LZMA2 -#define k_LZMA2 0x21 -#endif -#define k_LZMA 0x30101 -#define k_BCJ2 0x303011B - -#if !defined(Z7_NO_METHODS_FILTERS) -#define Z7_USE_BRANCH_FILTER -#endif - -#if !defined(Z7_NO_METHODS_FILTERS) || \ - defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64) -#define Z7_USE_FILTER_ARM64 -#ifndef Z7_USE_BRANCH_FILTER -#define Z7_USE_BRANCH_FILTER -#endif -#define k_ARM64 0xa -#endif - -#if !defined(Z7_NO_METHODS_FILTERS) || \ - defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT) -#define Z7_USE_FILTER_ARMT -#ifndef Z7_USE_BRANCH_FILTER -#define Z7_USE_BRANCH_FILTER -#endif -#define k_ARMT 0x3030701 -#endif - -#ifndef Z7_NO_METHODS_FILTERS -#define k_Delta 3 -#define k_RISCV 0xb -#define k_BCJ 0x3030103 -#define k_PPC 0x3030205 -#define k_IA64 0x3030401 -#define k_ARM 0x3030501 -#define k_SPARC 0x3030805 -#endif - -#ifdef Z7_PPMD_SUPPORT - -#define k_PPMD 0x30401 - -typedef struct -{ - IByteIn vt; - const Byte *cur; - const Byte *end; - const Byte *begin; - UInt64 processed; - BoolInt extra; - SRes res; - ILookInStreamPtr inStream; -} CByteInToLook; - -static Byte ReadByte(IByteInPtr pp) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook) - if (p->cur != p->end) - return *p->cur++; - if (p->res == SZ_OK) - { - size_t size = (size_t)(p->cur - p->begin); - p->processed += size; - p->res = ILookInStream_Skip(p->inStream, size); - size = (1 << 25); - p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size); - p->cur = p->begin; - p->end = p->begin + size; - if (size != 0) - return *p->cur++; - } - p->extra = True; - return 0; -} - -static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, - Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) -{ - CPpmd7 ppmd; - CByteInToLook s; - SRes res = SZ_OK; - - s.vt.Read = ReadByte; - s.inStream = inStream; - s.begin = s.end = s.cur = NULL; - s.extra = False; - s.res = SZ_OK; - s.processed = 0; - - if (propsSize != 5) - return SZ_ERROR_UNSUPPORTED; - - { - unsigned order = props[0]; - UInt32 memSize = GetUi32(props + 1); - if (order < PPMD7_MIN_ORDER || - order > PPMD7_MAX_ORDER || - memSize < PPMD7_MIN_MEM_SIZE || - memSize > PPMD7_MAX_MEM_SIZE) - return SZ_ERROR_UNSUPPORTED; - Ppmd7_Construct(&ppmd); - if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) - return SZ_ERROR_MEM; - Ppmd7_Init(&ppmd, order); - } - { - ppmd.rc.dec.Stream = &s.vt; - if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec)) - res = SZ_ERROR_DATA; - else if (!s.extra) - { - Byte *buf = outBuffer; - const Byte *lim = buf + outSize; - for (; buf != lim; buf++) - { - int sym = Ppmd7z_DecodeSymbol(&ppmd); - if (s.extra || sym < 0) - break; - *buf = (Byte)sym; - } - if (buf != lim) - res = SZ_ERROR_DATA; - else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) - { - /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */ - res = SZ_ERROR_DATA; - } - } - if (s.extra) - res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); - else if (s.processed + (size_t)(s.cur - s.begin) != inSize) - res = SZ_ERROR_DATA; - } - Ppmd7_Free(&ppmd, allocMain); - return res; -} - -#endif - - -static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, - Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) -{ - CLzmaDec state; - SRes res = SZ_OK; - - LzmaDec_CONSTRUCT(&state) - RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)) - state.dic = outBuffer; - state.dicBufSize = outSize; - LzmaDec_Init(&state); - - for (;;) - { - const void *inBuf = NULL; - size_t lookahead = (1 << 18); - if (lookahead > inSize) - lookahead = (size_t)inSize; - res = ILookInStream_Look(inStream, &inBuf, &lookahead); - if (res != SZ_OK) - break; - - { - SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; - ELzmaStatus status; - res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); - lookahead -= inProcessed; - inSize -= inProcessed; - if (res != SZ_OK) - break; - - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - { - if (outSize != state.dicPos || inSize != 0) - res = SZ_ERROR_DATA; - break; - } - - if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - break; - - if (inProcessed == 0 && dicPos == state.dicPos) - { - res = SZ_ERROR_DATA; - break; - } - - res = ILookInStream_Skip(inStream, inProcessed); - if (res != SZ_OK) - break; - } - } - - LzmaDec_FreeProbs(&state, allocMain); - return res; -} - - -#ifndef Z7_NO_METHOD_LZMA2 - -static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, - Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) -{ - CLzma2Dec state; - SRes res = SZ_OK; - - Lzma2Dec_CONSTRUCT(&state) - if (propsSize != 1) - return SZ_ERROR_DATA; - RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)) - state.decoder.dic = outBuffer; - state.decoder.dicBufSize = outSize; - Lzma2Dec_Init(&state); - - for (;;) - { - const void *inBuf = NULL; - size_t lookahead = (1 << 18); - if (lookahead > inSize) - lookahead = (size_t)inSize; - res = ILookInStream_Look(inStream, &inBuf, &lookahead); - if (res != SZ_OK) - break; - - { - SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; - ELzmaStatus status; - res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); - lookahead -= inProcessed; - inSize -= inProcessed; - if (res != SZ_OK) - break; - - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - { - if (outSize != state.decoder.dicPos || inSize != 0) - res = SZ_ERROR_DATA; - break; - } - - if (inProcessed == 0 && dicPos == state.decoder.dicPos) - { - res = SZ_ERROR_DATA; - break; - } - - res = ILookInStream_Skip(inStream, inProcessed); - if (res != SZ_OK) - break; - } - } - - Lzma2Dec_FreeProbs(&state, allocMain); - return res; -} - -#endif - - -static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer) -{ - while (inSize > 0) - { - const void *inBuf; - size_t curSize = (1 << 18); - if (curSize > inSize) - curSize = (size_t)inSize; - RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)) - if (curSize == 0) - return SZ_ERROR_INPUT_EOF; - memcpy(outBuffer, inBuf, curSize); - outBuffer += curSize; - inSize -= curSize; - RINOK(ILookInStream_Skip(inStream, curSize)) - } - return SZ_OK; -} - -static BoolInt IS_MAIN_METHOD(UInt32 m) -{ - switch (m) - { - case k_Copy: - case k_LZMA: - #ifndef Z7_NO_METHOD_LZMA2 - case k_LZMA2: - #endif - #ifdef Z7_PPMD_SUPPORT - case k_PPMD: - #endif - return True; - } - return False; -} - -static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c) -{ - return - c->NumStreams == 1 - /* && c->MethodID <= (UInt32)0xFFFFFFFF */ - && IS_MAIN_METHOD((UInt32)c->MethodID); -} - -#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) - -static SRes CheckSupportedFolder(const CSzFolder *f) -{ - if (f->NumCoders < 1 || f->NumCoders > 4) - return SZ_ERROR_UNSUPPORTED; - if (!IS_SUPPORTED_CODER(&f->Coders[0])) - return SZ_ERROR_UNSUPPORTED; - if (f->NumCoders == 1) - { - if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) - return SZ_ERROR_UNSUPPORTED; - return SZ_OK; - } - - - #if defined(Z7_USE_BRANCH_FILTER) - - if (f->NumCoders == 2) - { - const CSzCoderInfo *c = &f->Coders[1]; - if ( - /* c->MethodID > (UInt32)0xFFFFFFFF || */ - c->NumStreams != 1 - || f->NumPackStreams != 1 - || f->PackStreams[0] != 0 - || f->NumBonds != 1 - || f->Bonds[0].InIndex != 1 - || f->Bonds[0].OutIndex != 0) - return SZ_ERROR_UNSUPPORTED; - switch ((UInt32)c->MethodID) - { - #if !defined(Z7_NO_METHODS_FILTERS) - case k_Delta: - case k_BCJ: - case k_PPC: - case k_IA64: - case k_SPARC: - case k_ARM: - case k_RISCV: - #endif - #ifdef Z7_USE_FILTER_ARM64 - case k_ARM64: - #endif - #ifdef Z7_USE_FILTER_ARMT - case k_ARMT: - #endif - break; - default: - return SZ_ERROR_UNSUPPORTED; - } - return SZ_OK; - } - - #endif - - - if (f->NumCoders == 4) - { - if (!IS_SUPPORTED_CODER(&f->Coders[1]) - || !IS_SUPPORTED_CODER(&f->Coders[2]) - || !IS_BCJ2(&f->Coders[3])) - return SZ_ERROR_UNSUPPORTED; - if (f->NumPackStreams != 4 - || f->PackStreams[0] != 2 - || f->PackStreams[1] != 6 - || f->PackStreams[2] != 1 - || f->PackStreams[3] != 0 - || f->NumBonds != 3 - || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 - || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 - || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) - return SZ_ERROR_UNSUPPORTED; - return SZ_OK; - } - - return SZ_ERROR_UNSUPPORTED; -} - - - - - - -static SRes SzFolder_Decode2(const CSzFolder *folder, - const Byte *propsData, - const UInt64 *unpackSizes, - const UInt64 *packPositions, - ILookInStreamPtr inStream, UInt64 startPos, - Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain, - Byte *tempBuf[]) -{ - UInt32 ci; - SizeT tempSizes[3] = { 0, 0, 0}; - SizeT tempSize3 = 0; - Byte *tempBuf3 = 0; - - RINOK(CheckSupportedFolder(folder)) - - for (ci = 0; ci < folder->NumCoders; ci++) - { - const CSzCoderInfo *coder = &folder->Coders[ci]; - - if (IS_MAIN_METHOD((UInt32)coder->MethodID)) - { - UInt32 si = 0; - UInt64 offset; - UInt64 inSize; - Byte *outBufCur = outBuffer; - SizeT outSizeCur = outSize; - if (folder->NumCoders == 4) - { - const UInt32 indices[] = { 3, 2, 0 }; - const UInt64 unpackSize = unpackSizes[ci]; - si = indices[ci]; - if (ci < 2) - { - Byte *temp; - outSizeCur = (SizeT)unpackSize; - if (outSizeCur != unpackSize) - return SZ_ERROR_MEM; - temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur); - if (!temp && outSizeCur != 0) - return SZ_ERROR_MEM; - outBufCur = tempBuf[1 - ci] = temp; - tempSizes[1 - ci] = outSizeCur; - } - else if (ci == 2) - { - if (unpackSize > outSize) /* check it */ - return SZ_ERROR_PARAM; - tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); - tempSize3 = outSizeCur = (SizeT)unpackSize; - } - else - return SZ_ERROR_UNSUPPORTED; - } - offset = packPositions[si]; - inSize = packPositions[(size_t)si + 1] - offset; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)) - - if (coder->MethodID == k_Copy) - { - if (inSize != outSizeCur) /* check it */ - return SZ_ERROR_DATA; - RINOK(SzDecodeCopy(inSize, inStream, outBufCur)) - } - else if (coder->MethodID == k_LZMA) - { - RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) - } - #ifndef Z7_NO_METHOD_LZMA2 - else if (coder->MethodID == k_LZMA2) - { - RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) - } - #endif - #ifdef Z7_PPMD_SUPPORT - else if (coder->MethodID == k_PPMD) - { - RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) - } - #endif - else - return SZ_ERROR_UNSUPPORTED; - } - else if (coder->MethodID == k_BCJ2) - { - const UInt64 offset = packPositions[1]; - const UInt64 s3Size = packPositions[2] - offset; - - if (ci != 3) - return SZ_ERROR_UNSUPPORTED; - - tempSizes[2] = (SizeT)s3Size; - if (tempSizes[2] != s3Size) - return SZ_ERROR_MEM; - tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]); - if (!tempBuf[2] && tempSizes[2] != 0) - return SZ_ERROR_MEM; - - RINOK(LookInStream_SeekTo(inStream, startPos + offset)) - RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])) - - if ((tempSizes[0] & 3) != 0 || - (tempSizes[1] & 3) != 0 || - tempSize3 + tempSizes[0] + tempSizes[1] != outSize) - return SZ_ERROR_DATA; - - { - CBcj2Dec p; - - p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; - p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; - p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; - p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; - - p.dest = outBuffer; - p.destLim = outBuffer + outSize; - - Bcj2Dec_Init(&p); - RINOK(Bcj2Dec_Decode(&p)) - - { - unsigned i; - for (i = 0; i < 4; i++) - if (p.bufs[i] != p.lims[i]) - return SZ_ERROR_DATA; - if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p)) - return SZ_ERROR_DATA; - } - } - } -#if defined(Z7_USE_BRANCH_FILTER) - else if (ci == 1) - { -#if !defined(Z7_NO_METHODS_FILTERS) - if (coder->MethodID == k_Delta) - { - if (coder->PropsSize != 1) - return SZ_ERROR_UNSUPPORTED; - { - Byte state[DELTA_STATE_SIZE]; - Delta_Init(state); - Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); - } - continue; - } -#endif - -#ifdef Z7_USE_FILTER_ARM64 - if (coder->MethodID == k_ARM64) - { - UInt32 pc = 0; - if (coder->PropsSize == 4) - { - pc = GetUi32(propsData + coder->PropsOffset); - if (pc & 3) - return SZ_ERROR_UNSUPPORTED; - } - else if (coder->PropsSize != 0) - return SZ_ERROR_UNSUPPORTED; - z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc); - continue; - } -#endif - -#if !defined(Z7_NO_METHODS_FILTERS) - if (coder->MethodID == k_RISCV) - { - UInt32 pc = 0; - if (coder->PropsSize == 4) - { - pc = GetUi32(propsData + coder->PropsOffset); - if (pc & 1) - return SZ_ERROR_UNSUPPORTED; - } - else if (coder->PropsSize != 0) - return SZ_ERROR_UNSUPPORTED; - z7_BranchConv_RISCV_Dec(outBuffer, outSize, pc); - continue; - } -#endif - -#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT) - { - if (coder->PropsSize != 0) - return SZ_ERROR_UNSUPPORTED; - #define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0; - switch (coder->MethodID) - { - #if !defined(Z7_NO_METHODS_FILTERS) - case k_BCJ: - { - UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; - z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0 - break; - } - case k_PPC: Z7_BRANCH_CONV_DEC_2(BranchConv_PPC)(outBuffer, outSize, 0); break; // pc = 0; - // CASE_BRA_CONV(PPC) - CASE_BRA_CONV(IA64) - CASE_BRA_CONV(SPARC) - CASE_BRA_CONV(ARM) - #endif - #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT) - CASE_BRA_CONV(ARMT) - #endif - default: - return SZ_ERROR_UNSUPPORTED; - } - continue; - } -#endif - } // (c == 1) -#endif // Z7_USE_BRANCH_FILTER - else - return SZ_ERROR_UNSUPPORTED; - } - - return SZ_OK; -} - - -SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, - ILookInStreamPtr inStream, UInt64 startPos, - Byte *outBuffer, size_t outSize, - ISzAllocPtr allocMain) -{ - SRes res; - CSzFolder folder; - CSzData sd; - - const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; - sd.Data = data; - sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex]; - - res = SzGetNextFolderItem(&folder, &sd); - - if (res != SZ_OK) - return res; - - if (sd.Size != 0 - || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] - || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) - return SZ_ERROR_FAIL; - { - unsigned i; - Byte *tempBuf[3] = { 0, 0, 0}; - - res = SzFolder_Decode2(&folder, data, - &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], - p->PackPositions + p->FoStartPackStreamIndex[folderIndex], - inStream, startPos, - outBuffer, (SizeT)outSize, allocMain, tempBuf); - - for (i = 0; i < 3; i++) - ISzAlloc_Free(allocMain, tempBuf[i]); - - if (res == SZ_OK) - if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) - if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) - res = SZ_ERROR_CRC; - - return res; - } -} +/* 7zDec.c -- Decoding from 7z folder +: Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define Z7_PPMD_SUPPORT */ + +#include "7z.h" +#include "7zCrc.h" + +#include "Bcj2.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "LzmaDec.h" +#include "Lzma2Dec.h" +#ifdef Z7_PPMD_SUPPORT +#include "Ppmd7.h" +#endif + +#define k_Copy 0 +#ifndef Z7_NO_METHOD_LZMA2 +#define k_LZMA2 0x21 +#endif +#define k_LZMA 0x30101 +#define k_BCJ2 0x303011B + +#if !defined(Z7_NO_METHODS_FILTERS) +#define Z7_USE_BRANCH_FILTER +#endif + +#if !defined(Z7_NO_METHODS_FILTERS) || \ + defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64) +#define Z7_USE_FILTER_ARM64 +#ifndef Z7_USE_BRANCH_FILTER +#define Z7_USE_BRANCH_FILTER +#endif +#define k_ARM64 0xa +#endif + +#if !defined(Z7_NO_METHODS_FILTERS) || \ + defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT) +#define Z7_USE_FILTER_ARMT +#ifndef Z7_USE_BRANCH_FILTER +#define Z7_USE_BRANCH_FILTER +#endif +#define k_ARMT 0x3030701 +#endif + +#ifndef Z7_NO_METHODS_FILTERS +#define k_Delta 3 +#define k_RISCV 0xb +#define k_BCJ 0x3030103 +#define k_PPC 0x3030205 +#define k_IA64 0x3030401 +#define k_ARM 0x3030501 +#define k_SPARC 0x3030805 +#endif + +#ifdef Z7_PPMD_SUPPORT + +#define k_PPMD 0x30401 + +typedef struct +{ + IByteIn vt; + const Byte *cur; + const Byte *end; + const Byte *begin; + UInt64 processed; + BoolInt extra; + SRes res; + ILookInStreamPtr inStream; +} CByteInToLook; + +static Byte ReadByte(IByteInPtr pp) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook) + if (p->cur != p->end) + return *p->cur++; + if (p->res == SZ_OK) + { + size_t size = (size_t)(p->cur - p->begin); + p->processed += size; + p->res = ILookInStream_Skip(p->inStream, size); + size = (1 << 25); + p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size); + p->cur = p->begin; + p->end = p->begin + size; + if (size != 0) + return *p->cur++; + } + p->extra = True; + return 0; +} + +static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CPpmd7 ppmd; + CByteInToLook s; + SRes res = SZ_OK; + + s.vt.Read = ReadByte; + s.inStream = inStream; + s.begin = s.end = s.cur = NULL; + s.extra = False; + s.res = SZ_OK; + s.processed = 0; + + if (propsSize != 5) + return SZ_ERROR_UNSUPPORTED; + + { + unsigned order = props[0]; + UInt32 memSize = GetUi32(props + 1); + if (order < PPMD7_MIN_ORDER || + order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return SZ_ERROR_UNSUPPORTED; + Ppmd7_Construct(&ppmd); + if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) + return SZ_ERROR_MEM; + Ppmd7_Init(&ppmd, order); + } + { + ppmd.rc.dec.Stream = &s.vt; + if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec)) + res = SZ_ERROR_DATA; + else if (!s.extra) + { + Byte *buf = outBuffer; + const Byte *lim = buf + outSize; + for (; buf != lim; buf++) + { + int sym = Ppmd7z_DecodeSymbol(&ppmd); + if (s.extra || sym < 0) + break; + *buf = (Byte)sym; + } + if (buf != lim) + res = SZ_ERROR_DATA; + else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) + { + /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */ + res = SZ_ERROR_DATA; + } + } + if (s.extra) + res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); + else if (s.processed + (size_t)(s.cur - s.begin) != inSize) + res = SZ_ERROR_DATA; + } + Ppmd7_Free(&ppmd, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CLzmaDec state; + SRes res = SZ_OK; + + LzmaDec_CONSTRUCT(&state) + RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)) + state.dic = outBuffer; + state.dicBufSize = outSize; + LzmaDec_Init(&state); + + for (;;) + { + const void *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = ILookInStream_Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; + ELzmaStatus status; + res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } + + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; + + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + + res = ILookInStream_Skip(inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + LzmaDec_FreeProbs(&state, allocMain); + return res; +} + + +#ifndef Z7_NO_METHOD_LZMA2 + +static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) +{ + CLzma2Dec state; + SRes res = SZ_OK; + + Lzma2Dec_CONSTRUCT(&state) + if (propsSize != 1) + return SZ_ERROR_DATA; + RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)) + state.decoder.dic = outBuffer; + state.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&state); + + for (;;) + { + const void *inBuf = NULL; + size_t lookahead = (1 << 18); + if (lookahead > inSize) + lookahead = (size_t)inSize; + res = ILookInStream_Look(inStream, &inBuf, &lookahead); + if (res != SZ_OK) + break; + + { + SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; + ELzmaStatus status; + res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status); + lookahead -= inProcessed; + inSize -= inProcessed; + if (res != SZ_OK) + break; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (outSize != state.decoder.dicPos || inSize != 0) + res = SZ_ERROR_DATA; + break; + } + + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + + res = ILookInStream_Skip(inStream, inProcessed); + if (res != SZ_OK) + break; + } + } + + Lzma2Dec_FreeProbs(&state, allocMain); + return res; +} + +#endif + + +static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer) +{ + while (inSize > 0) + { + const void *inBuf; + size_t curSize = (1 << 18); + if (curSize > inSize) + curSize = (size_t)inSize; + RINOK(ILookInStream_Look(inStream, &inBuf, &curSize)) + if (curSize == 0) + return SZ_ERROR_INPUT_EOF; + memcpy(outBuffer, inBuf, curSize); + outBuffer += curSize; + inSize -= curSize; + RINOK(ILookInStream_Skip(inStream, curSize)) + } + return SZ_OK; +} + +static BoolInt IS_MAIN_METHOD(UInt32 m) +{ + switch (m) + { + case k_Copy: + case k_LZMA: + #ifndef Z7_NO_METHOD_LZMA2 + case k_LZMA2: + #endif + #ifdef Z7_PPMD_SUPPORT + case k_PPMD: + #endif + return True; + default: + return False; + } +} + +static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c) +{ + return + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); +} + +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) + +static SRes CheckSupportedFolder(const CSzFolder *f) +{ + if (f->NumCoders < 1 || f->NumCoders > 4) + return SZ_ERROR_UNSUPPORTED; + if (!IS_SUPPORTED_CODER(&f->Coders[0])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumCoders == 1) + { + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + + #if defined(Z7_USE_BRANCH_FILTER) + + if (f->NumCoders == 2) + { + const CSzCoderInfo *c = &f->Coders[1]; + if ( + /* c->MethodID > (UInt32)0xFFFFFFFF || */ + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) + return SZ_ERROR_UNSUPPORTED; + switch ((UInt32)c->MethodID) + { + #if !defined(Z7_NO_METHODS_FILTERS) + case k_Delta: + case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: + case k_ARM: + case k_RISCV: + #endif + #ifdef Z7_USE_FILTER_ARM64 + case k_ARM64: + #endif + #ifdef Z7_USE_FILTER_ARMT + case k_ARMT: + #endif + break; + default: + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; + } + + #endif + + + if (f->NumCoders == 4) + { + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) + return SZ_ERROR_UNSUPPORTED; + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) + return SZ_ERROR_UNSUPPORTED; + return SZ_OK; + } + + return SZ_ERROR_UNSUPPORTED; +} + + + + + + +static SRes SzFolder_Decode2(const CSzFolder *folder, + const Byte *propsData, + const UInt64 *unpackSizes, + const UInt64 *packPositions, + ILookInStreamPtr inStream, UInt64 startPos, + Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain, + Byte *tempBuf[]) +{ + UInt32 ci; + SizeT tempSizes[3] = { 0, 0, 0}; + SizeT tempSize3 = 0; + Byte *tempBuf3 = 0; + + RINOK(CheckSupportedFolder(folder)) + + for (ci = 0; ci < folder->NumCoders; ci++) + { + const CSzCoderInfo *coder = &folder->Coders[ci]; + + if (IS_MAIN_METHOD((UInt32)coder->MethodID)) + { + UInt32 si = 0; + UInt64 offset; + UInt64 inSize; + Byte *outBufCur = outBuffer; + SizeT outSizeCur = outSize; + if (folder->NumCoders == 4) + { + const UInt32 indices[] = { 3, 2, 0 }; + const UInt64 unpackSize = unpackSizes[ci]; + si = indices[ci]; + if (ci < 2) + { + Byte *temp; + outSizeCur = (SizeT)unpackSize; + if (outSizeCur != unpackSize) + return SZ_ERROR_MEM; + temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur); + if (!temp && outSizeCur != 0) + return SZ_ERROR_MEM; + outBufCur = tempBuf[1 - ci] = temp; + tempSizes[1 - ci] = outSizeCur; + } + else if (ci == 2) + { + if (unpackSize > outSize) /* check it */ + return SZ_ERROR_PARAM; + tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); + tempSize3 = outSizeCur = (SizeT)unpackSize; + } + else + return SZ_ERROR_UNSUPPORTED; + } + offset = packPositions[si]; + inSize = packPositions[(size_t)si + 1] - offset; + RINOK(LookInStream_SeekTo(inStream, startPos + offset)) + + if (coder->MethodID == k_Copy) + { + if (inSize != outSizeCur) /* check it */ + return SZ_ERROR_DATA; + RINOK(SzDecodeCopy(inSize, inStream, outBufCur)) + } + else if (coder->MethodID == k_LZMA) + { + RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) + } + #ifndef Z7_NO_METHOD_LZMA2 + else if (coder->MethodID == k_LZMA2) + { + RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) + } + #endif + #ifdef Z7_PPMD_SUPPORT + else if (coder->MethodID == k_PPMD) + { + RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)) + } + #endif + else + return SZ_ERROR_UNSUPPORTED; + } + else if (coder->MethodID == k_BCJ2) + { + const UInt64 offset = packPositions[1]; + const UInt64 s3Size = packPositions[2] - offset; + + if (ci != 3) + return SZ_ERROR_UNSUPPORTED; + + tempSizes[2] = (SizeT)s3Size; + if (tempSizes[2] != s3Size) + return SZ_ERROR_MEM; + tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]); + if (!tempBuf[2] && tempSizes[2] != 0) + return SZ_ERROR_MEM; + + RINOK(LookInStream_SeekTo(inStream, startPos + offset)) + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])) + + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; + + { + CBcj2Dec p; + + p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)) + + { + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p)) + return SZ_ERROR_DATA; + } + } + } +#if defined(Z7_USE_BRANCH_FILTER) + else if (ci == 1) + { +#if !defined(Z7_NO_METHODS_FILTERS) + if (coder->MethodID == k_Delta) + { + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); + } + continue; + } +#endif + +#ifdef Z7_USE_FILTER_ARM64 + if (coder->MethodID == k_ARM64) + { + UInt32 pc = 0; + if (coder->PropsSize == 4) + { + pc = GetUi32(propsData + coder->PropsOffset); + if (pc & 3) + return SZ_ERROR_UNSUPPORTED; + } + else if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc); + continue; + } +#endif + +#if !defined(Z7_NO_METHODS_FILTERS) + if (coder->MethodID == k_RISCV) + { + UInt32 pc = 0; + if (coder->PropsSize == 4) + { + pc = GetUi32(propsData + coder->PropsOffset); + if (pc & 1) + return SZ_ERROR_UNSUPPORTED; + } + else if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + z7_BranchConv_RISCV_Dec(outBuffer, outSize, pc); + continue; + } +#endif + +#if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT) + { + if (coder->PropsSize != 0) + return SZ_ERROR_UNSUPPORTED; + #define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0; + switch (coder->MethodID) + { + #if !defined(Z7_NO_METHODS_FILTERS) + case k_BCJ: + { + UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0 + break; + } + case k_PPC: Z7_BRANCH_CONV_DEC_2(BranchConv_PPC)(outBuffer, outSize, 0); break; // pc = 0; + // CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + #endif + #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT) + CASE_BRA_CONV(ARMT) + #endif + default: + return SZ_ERROR_UNSUPPORTED; + } + continue; + } +#endif + } // (c == 1) +#endif // Z7_USE_BRANCH_FILTER + else + return SZ_ERROR_UNSUPPORTED; + } + + return SZ_OK; +} + + +SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, + ILookInStreamPtr inStream, UInt64 startPos, + Byte *outBuffer, size_t outSize, + ISzAllocPtr allocMain) +{ + SRes res; + CSzFolder folder; + CSzData sd; + + const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; + sd.Data = data; + sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex]; + + res = SzGetNextFolderItem(&folder, &sd); + + if (res != SZ_OK) + return res; + + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) + return SZ_ERROR_FAIL; + { + unsigned i; + Byte *tempBuf[3] = { 0, 0, 0}; + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], + p->PackPositions + p->FoStartPackStreamIndex[folderIndex], + inStream, startPos, + outBuffer, (SizeT)outSize, allocMain, tempBuf); + + for (i = 0; i < 3; i++) + ISzAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + + return res; + } +} diff --git a/C/7zFile.c b/C/7zFile.c index 96d4edd20..ba5daa133 100644 --- a/C/7zFile.c +++ b/C/7zFile.c @@ -1,443 +1,443 @@ -/* 7zFile.c -- File IO -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "7zFile.h" - -#ifndef USE_WINDOWS_FILE - - #include - - #ifndef USE_FOPEN - #include - #include - #ifdef _WIN32 - #include - typedef int ssize_t; - typedef int off_t; - #else - #include - #endif - #endif - -#else - -/* - ReadFile and WriteFile functions in Windows have BUG: - If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) - from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES - (Insufficient system resources exist to complete the requested service). - Probably in some version of Windows there are problems with other sizes: - for 32 MB (maybe also for 16 MB). - And message can be "Network connection was lost" -*/ - -#endif - -#define kChunkSizeMax (1 << 22) - -void File_Construct(CSzFile *p) -{ - #ifdef USE_WINDOWS_FILE - p->handle = INVALID_HANDLE_VALUE; - #elif defined(USE_FOPEN) - p->file = NULL; - #else - p->fd = -1; - #endif -} - -#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) - -static WRes File_Open(CSzFile *p, const char *name, int writeMode) -{ - #ifdef USE_WINDOWS_FILE - - p->handle = CreateFileA(name, - writeMode ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, NULL, - writeMode ? CREATE_ALWAYS : OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); - - #elif defined(USE_FOPEN) - - p->file = fopen(name, writeMode ? "wb+" : "rb"); - return (p->file != 0) ? 0 : - #ifdef UNDER_CE - 2; /* ENOENT */ - #else - errno; - #endif - - #else - - int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY); - #ifdef O_BINARY - flags |= O_BINARY; - #endif - p->fd = open(name, flags, 0666); - return (p->fd != -1) ? 0 : errno; - - #endif -} - -WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } - -WRes OutFile_Open(CSzFile *p, const char *name) -{ - #if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN) - return File_Open(p, name, 1); - #else - p->fd = creat(name, 0666); - return (p->fd != -1) ? 0 : errno; - #endif -} - -#endif - - -#ifdef USE_WINDOWS_FILE -static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) -{ - p->handle = CreateFileW(name, - writeMode ? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ, NULL, - writeMode ? CREATE_ALWAYS : OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); -} -WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } -WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } -#endif - -WRes File_Close(CSzFile *p) -{ - #ifdef USE_WINDOWS_FILE - - if (p->handle != INVALID_HANDLE_VALUE) - { - if (!CloseHandle(p->handle)) - return GetLastError(); - p->handle = INVALID_HANDLE_VALUE; - } - - #elif defined(USE_FOPEN) - - if (p->file != NULL) - { - int res = fclose(p->file); - if (res != 0) - { - if (res == EOF) - return errno; - return res; - } - p->file = NULL; - } - - #else - - if (p->fd != -1) - { - if (close(p->fd) != 0) - return errno; - p->fd = -1; - } - - #endif - - return 0; -} - - -WRes File_Read(CSzFile *p, void *data, size_t *size) -{ - size_t originalSize = *size; - *size = 0; - if (originalSize == 0) - return 0; - - #ifdef USE_WINDOWS_FILE - - do - { - const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; - DWORD processed = 0; - const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); - data = (void *)((Byte *)data + processed); - originalSize -= processed; - *size += processed; - if (!res) - return GetLastError(); - // debug : we can break here for partial reading mode - if (processed == 0) - break; - } - while (originalSize > 0); - - #elif defined(USE_FOPEN) - - do - { - const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; - const size_t processed = fread(data, 1, curSize, p->file); - data = (void *)((Byte *)data + (size_t)processed); - originalSize -= processed; - *size += processed; - if (processed != curSize) - return ferror(p->file); - // debug : we can break here for partial reading mode - if (processed == 0) - break; - } - while (originalSize > 0); - - #else - - do - { - const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; - const ssize_t processed = read(p->fd, data, curSize); - if (processed == -1) - return errno; - if (processed == 0) - break; - data = (void *)((Byte *)data + (size_t)processed); - originalSize -= (size_t)processed; - *size += (size_t)processed; - // debug : we can break here for partial reading mode - // break; - } - while (originalSize > 0); - - #endif - - return 0; -} - - -WRes File_Write(CSzFile *p, const void *data, size_t *size) -{ - size_t originalSize = *size; - *size = 0; - if (originalSize == 0) - return 0; - - #ifdef USE_WINDOWS_FILE - - do - { - const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; - DWORD processed = 0; - const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); - data = (const void *)((const Byte *)data + processed); - originalSize -= processed; - *size += processed; - if (!res) - return GetLastError(); - if (processed == 0) - break; - } - while (originalSize > 0); - - #elif defined(USE_FOPEN) - - do - { - const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; - const size_t processed = fwrite(data, 1, curSize, p->file); - data = (void *)((Byte *)data + (size_t)processed); - originalSize -= processed; - *size += processed; - if (processed != curSize) - return ferror(p->file); - if (processed == 0) - break; - } - while (originalSize > 0); - - #else - - do - { - const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; - const ssize_t processed = write(p->fd, data, curSize); - if (processed == -1) - return errno; - if (processed == 0) - break; - data = (const void *)((const Byte *)data + (size_t)processed); - originalSize -= (size_t)processed; - *size += (size_t)processed; - } - while (originalSize > 0); - - #endif - - return 0; -} - - -WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) -{ - #ifdef USE_WINDOWS_FILE - - DWORD moveMethod; - UInt32 low = (UInt32)*pos; - LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ - // (int) to eliminate clang warning - switch ((int)origin) - { - case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; - case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; - case SZ_SEEK_END: moveMethod = FILE_END; break; - default: return ERROR_INVALID_PARAMETER; - } - low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod); - if (low == (UInt32)0xFFFFFFFF) - { - WRes res = GetLastError(); - if (res != NO_ERROR) - return res; - } - *pos = ((Int64)high << 32) | low; - return 0; - - #else - - int moveMethod; // = origin; - - switch ((int)origin) - { - case SZ_SEEK_SET: moveMethod = SEEK_SET; break; - case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; - case SZ_SEEK_END: moveMethod = SEEK_END; break; - default: return EINVAL; - } - - #if defined(USE_FOPEN) - { - int res = fseek(p->file, (long)*pos, moveMethod); - if (res == -1) - return errno; - *pos = ftell(p->file); - if (*pos == -1) - return errno; - return 0; - } - #else - { - off_t res = lseek(p->fd, (off_t)*pos, moveMethod); - if (res == -1) - return errno; - *pos = res; - return 0; - } - - #endif // USE_FOPEN - #endif // USE_WINDOWS_FILE -} - - -WRes File_GetLength(CSzFile *p, UInt64 *length) -{ - #ifdef USE_WINDOWS_FILE - - DWORD sizeHigh; - DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); - if (sizeLow == 0xFFFFFFFF) - { - DWORD res = GetLastError(); - if (res != NO_ERROR) - return res; - } - *length = (((UInt64)sizeHigh) << 32) + sizeLow; - return 0; - - #elif defined(USE_FOPEN) - - long pos = ftell(p->file); - int res = fseek(p->file, 0, SEEK_END); - *length = ftell(p->file); - fseek(p->file, pos, SEEK_SET); - return res; - - #else - - off_t pos; - *length = 0; - pos = lseek(p->fd, 0, SEEK_CUR); - if (pos != -1) - { - const off_t len2 = lseek(p->fd, 0, SEEK_END); - const off_t res2 = lseek(p->fd, pos, SEEK_SET); - if (len2 != -1) - { - *length = (UInt64)len2; - if (res2 != -1) - return 0; - } - } - return errno; - - #endif -} - - -/* ---------- FileSeqInStream ---------- */ - -static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream) - const WRes wres = File_Read(&p->file, buf, size); - p->wres = wres; - return (wres == 0) ? SZ_OK : SZ_ERROR_READ; -} - -void FileSeqInStream_CreateVTable(CFileSeqInStream *p) -{ - p->vt.Read = FileSeqInStream_Read; -} - - -/* ---------- FileInStream ---------- */ - -static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream) - const WRes wres = File_Read(&p->file, buf, size); - p->wres = wres; - return (wres == 0) ? SZ_OK : SZ_ERROR_READ; -} - -static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream) - const WRes wres = File_Seek(&p->file, pos, origin); - p->wres = wres; - return (wres == 0) ? SZ_OK : SZ_ERROR_READ; -} - -void FileInStream_CreateVTable(CFileInStream *p) -{ - p->vt.Read = FileInStream_Read; - p->vt.Seek = FileInStream_Seek; -} - - -/* ---------- FileOutStream ---------- */ - -static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream) - const WRes wres = File_Write(&p->file, data, &size); - p->wres = wres; - return size; -} - -void FileOutStream_CreateVTable(CFileOutStream *p) -{ - p->vt.Write = FileOutStream_Write; -} +/* 7zFile.c -- File IO +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zFile.h" + +#ifndef USE_WINDOWS_FILE + + #include + + #ifndef USE_FOPEN + #include + #include + #ifdef _WIN32 + #include + typedef int ssize_t; + typedef int off_t; + #else + #include + #endif + #endif + +#else + +/* + ReadFile and WriteFile functions in Windows have BUG: + If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) + from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES + (Insufficient system resources exist to complete the requested service). + Probably in some version of Windows there are problems with other sizes: + for 32 MB (maybe also for 16 MB). + And message can be "Network connection was lost" +*/ + +#endif + +#define kChunkSizeMax (1 << 22) + +void File_Construct(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + p->handle = INVALID_HANDLE_VALUE; + #elif defined(USE_FOPEN) + p->file = NULL; + #else + p->fd = -1; + #endif +} + +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) + +static WRes File_Open(CSzFile *p, const char *name, int writeMode) +{ + #ifdef USE_WINDOWS_FILE + + p->handle = CreateFileA(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); + + #elif defined(USE_FOPEN) + + p->file = fopen(name, writeMode ? "wb+" : "rb"); + return (p->file != 0) ? 0 : + #ifdef UNDER_CE + 2; /* ENOENT */ + #else + errno; + #endif + + #else + + int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY); + #ifdef O_BINARY + flags |= O_BINARY; + #endif + p->fd = open(name, flags, 0666); + return (p->fd != -1) ? 0 : errno; + + #endif +} + +WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } + +WRes OutFile_Open(CSzFile *p, const char *name) +{ + #if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN) + return File_Open(p, name, 1); + #else + p->fd = creat(name, 0666); + return (p->fd != -1) ? 0 : errno; + #endif +} + +#endif + + +#ifdef USE_WINDOWS_FILE +static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) +{ + p->handle = CreateFileW(name, + writeMode ? GENERIC_WRITE : GENERIC_READ, + FILE_SHARE_READ, NULL, + writeMode ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); +} +WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } +#endif + +WRes File_Close(CSzFile *p) +{ + #ifdef USE_WINDOWS_FILE + + if (p->handle != INVALID_HANDLE_VALUE) + { + if (!CloseHandle(p->handle)) + return GetLastError(); + p->handle = INVALID_HANDLE_VALUE; + } + + #elif defined(USE_FOPEN) + + if (p->file != NULL) + { + int res = fclose(p->file); + if (res != 0) + { + if (res == EOF) + return errno; + return res; + } + p->file = NULL; + } + + #else + + if (p->fd != -1) + { + if (close(p->fd) != 0) + return errno; + p->fd = -1; + } + + #endif + + return 0; +} + + +WRes File_Read(CSzFile *p, void *data, size_t *size) +{ + size_t originalSize = *size; + *size = 0; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + do + { + const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); + data = (void *)((Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + // debug : we can break here for partial reading mode + if (processed == 0) + break; + } + while (originalSize > 0); + + #elif defined(USE_FOPEN) + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const size_t processed = fread(data, 1, curSize, p->file); + data = (void *)((Byte *)data + (size_t)processed); + originalSize -= processed; + *size += processed; + if (processed != curSize) + return ferror(p->file); + // debug : we can break here for partial reading mode + if (processed == 0) + break; + } + while (originalSize > 0); + + #else + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const ssize_t processed = read(p->fd, data, curSize); + if (processed == -1) + return errno; + if (processed == 0) + break; + data = (void *)((Byte *)data + (size_t)processed); + originalSize -= (size_t)processed; + *size += (size_t)processed; + // debug : we can break here for partial reading mode + // break; + } + while (originalSize > 0); + + #endif + + return 0; +} + + +WRes File_Write(CSzFile *p, const void *data, size_t *size) +{ + size_t originalSize = *size; + *size = 0; + if (originalSize == 0) + return 0; + + #ifdef USE_WINDOWS_FILE + + do + { + const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; + DWORD processed = 0; + const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); + data = (const void *)((const Byte *)data + processed); + originalSize -= processed; + *size += processed; + if (!res) + return GetLastError(); + if (processed == 0) + break; + } + while (originalSize > 0); + + #elif defined(USE_FOPEN) + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const size_t processed = fwrite(data, 1, curSize, p->file); + data = (void *)((Byte *)data + (size_t)processed); + originalSize -= processed; + *size += processed; + if (processed != curSize) + return ferror(p->file); + if (processed == 0) + break; + } + while (originalSize > 0); + + #else + + do + { + const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize; + const ssize_t processed = write(p->fd, data, curSize); + if (processed == -1) + return errno; + if (processed == 0) + break; + data = (const void *)((const Byte *)data + (size_t)processed); + originalSize -= (size_t)processed; + *size += (size_t)processed; + } + while (originalSize > 0); + + #endif + + return 0; +} + + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) +{ + #ifdef USE_WINDOWS_FILE + + DWORD moveMethod; + UInt32 low = (UInt32)*pos; + LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ + // (int) to eliminate clang warning + switch ((int)origin) + { + case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; + case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; + case SZ_SEEK_END: moveMethod = FILE_END; break; + default: return ERROR_INVALID_PARAMETER; + } + low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod); + if (low == (UInt32)0xFFFFFFFF) + { + WRes res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *pos = ((Int64)high << 32) | low; + return 0; + + #else + + int moveMethod; // = origin; + + switch ((int)origin) + { + case SZ_SEEK_SET: moveMethod = SEEK_SET; break; + case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; + case SZ_SEEK_END: moveMethod = SEEK_END; break; + default: return EINVAL; + } + + #if defined(USE_FOPEN) + { + int res = fseek(p->file, (long)*pos, moveMethod); + if (res == -1) + return errno; + *pos = ftell(p->file); + if (*pos == -1) + return errno; + return 0; + } + #else + { + off_t res = lseek(p->fd, (off_t)*pos, moveMethod); + if (res == -1) + return errno; + *pos = res; + return 0; + } + + #endif // USE_FOPEN + #endif // USE_WINDOWS_FILE +} + + +WRes File_GetLength(CSzFile *p, UInt64 *length) +{ + #ifdef USE_WINDOWS_FILE + + DWORD sizeHigh; + DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + { + DWORD res = GetLastError(); + if (res != NO_ERROR) + return res; + } + *length = (((UInt64)sizeHigh) << 32) + sizeLow; + return 0; + + #elif defined(USE_FOPEN) + + long pos = ftell(p->file); + int res = fseek(p->file, 0, SEEK_END); + *length = ftell(p->file); + fseek(p->file, pos, SEEK_SET); + return res; + + #else + + off_t pos; + *length = 0; + pos = lseek(p->fd, 0, SEEK_CUR); + if (pos != -1) + { + const off_t len2 = lseek(p->fd, 0, SEEK_END); + const off_t res2 = lseek(p->fd, pos, SEEK_SET); + if (len2 != -1) + { + *length = (UInt64)len2; + if (res2 != -1) + return 0; + } + } + return errno; + + #endif +} + + +/* ---------- FileSeqInStream ---------- */ + +static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream) + const WRes wres = File_Read(&p->file, buf, size); + p->wres = wres; + return (wres == 0) ? SZ_OK : SZ_ERROR_READ; +} + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p) +{ + p->vt.Read = FileSeqInStream_Read; +} + + +/* ---------- FileInStream ---------- */ + +static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream) + const WRes wres = File_Read(&p->file, buf, size); + p->wres = wres; + return (wres == 0) ? SZ_OK : SZ_ERROR_READ; +} + +static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream) + const WRes wres = File_Seek(&p->file, pos, origin); + p->wres = wres; + return (wres == 0) ? SZ_OK : SZ_ERROR_READ; +} + +void FileInStream_CreateVTable(CFileInStream *p) +{ + p->vt.Read = FileInStream_Read; + p->vt.Seek = FileInStream_Seek; +} + + +/* ---------- FileOutStream ---------- */ + +static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream) + const WRes wres = File_Write(&p->file, data, &size); + p->wres = wres; + return size; +} + +void FileOutStream_CreateVTable(CFileOutStream *p) +{ + p->vt.Write = FileOutStream_Write; +} diff --git a/C/7zFile.h b/C/7zFile.h index d7c871a73..f5069cd9e 100644 --- a/C/7zFile.h +++ b/C/7zFile.h @@ -1,92 +1,92 @@ -/* 7zFile.h -- File IO -2023-03-05 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_FILE_H -#define ZIP7_INC_FILE_H - -#ifdef _WIN32 -#define USE_WINDOWS_FILE -// #include -#endif - -#ifdef USE_WINDOWS_FILE -#include "7zWindows.h" - -#else -// note: USE_FOPEN mode is limited to 32-bit file size -// #define USE_FOPEN -// #include -#endif - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* ---------- File ---------- */ - -typedef struct -{ - #ifdef USE_WINDOWS_FILE - HANDLE handle; - #elif defined(USE_FOPEN) - FILE *file; - #else - int fd; - #endif -} CSzFile; - -void File_Construct(CSzFile *p); -#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) -WRes InFile_Open(CSzFile *p, const char *name); -WRes OutFile_Open(CSzFile *p, const char *name); -#endif -#ifdef USE_WINDOWS_FILE -WRes InFile_OpenW(CSzFile *p, const WCHAR *name); -WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); -#endif -WRes File_Close(CSzFile *p); - -/* reads max(*size, remain file's size) bytes */ -WRes File_Read(CSzFile *p, void *data, size_t *size); - -/* writes *size bytes */ -WRes File_Write(CSzFile *p, const void *data, size_t *size); - -WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); -WRes File_GetLength(CSzFile *p, UInt64 *length); - - -/* ---------- FileInStream ---------- */ - -typedef struct -{ - ISeqInStream vt; - CSzFile file; - WRes wres; -} CFileSeqInStream; - -void FileSeqInStream_CreateVTable(CFileSeqInStream *p); - - -typedef struct -{ - ISeekInStream vt; - CSzFile file; - WRes wres; -} CFileInStream; - -void FileInStream_CreateVTable(CFileInStream *p); - - -typedef struct -{ - ISeqOutStream vt; - CSzFile file; - WRes wres; -} CFileOutStream; - -void FileOutStream_CreateVTable(CFileOutStream *p); - -EXTERN_C_END - -#endif +/* 7zFile.h -- File IO +2023-03-05 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_FILE_H +#define ZIP7_INC_FILE_H + +#ifdef _WIN32 +#define USE_WINDOWS_FILE +// #include +#endif + +#ifdef USE_WINDOWS_FILE +#include "7zWindows.h" + +#else +// note: USE_FOPEN mode is limited to 32-bit file size +// #define USE_FOPEN +// #include +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* ---------- File ---------- */ + +typedef struct +{ + #ifdef USE_WINDOWS_FILE + HANDLE handle; + #elif defined(USE_FOPEN) + FILE *file; + #else + int fd; + #endif +} CSzFile; + +void File_Construct(CSzFile *p); +#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) +WRes InFile_Open(CSzFile *p, const char *name); +WRes OutFile_Open(CSzFile *p, const char *name); +#endif +#ifdef USE_WINDOWS_FILE +WRes InFile_OpenW(CSzFile *p, const WCHAR *name); +WRes OutFile_OpenW(CSzFile *p, const WCHAR *name); +#endif +WRes File_Close(CSzFile *p); + +/* reads max(*size, remain file's size) bytes */ +WRes File_Read(CSzFile *p, void *data, size_t *size); + +/* writes *size bytes */ +WRes File_Write(CSzFile *p, const void *data, size_t *size); + +WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin); +WRes File_GetLength(CSzFile *p, UInt64 *length); + + +/* ---------- FileInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + CSzFile file; + WRes wres; +} CFileSeqInStream; + +void FileSeqInStream_CreateVTable(CFileSeqInStream *p); + + +typedef struct +{ + ISeekInStream vt; + CSzFile file; + WRes wres; +} CFileInStream; + +void FileInStream_CreateVTable(CFileInStream *p); + + +typedef struct +{ + ISeqOutStream vt; + CSzFile file; + WRes wres; +} CFileOutStream; + +void FileOutStream_CreateVTable(CFileOutStream *p); + +EXTERN_C_END + +#endif diff --git a/C/7zStream.c b/C/7zStream.c index 92f821e2c..74e75b65a 100644 --- a/C/7zStream.c +++ b/C/7zStream.c @@ -1,199 +1,199 @@ -/* 7zStream.c -- 7z Stream functions -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "7zTypes.h" - - -SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize) -{ - size_t size = *processedSize; - *processedSize = 0; - while (size != 0) - { - size_t cur = size; - const SRes res = ISeqInStream_Read(stream, buf, &cur); - *processedSize += cur; - buf = (void *)((Byte *)buf + cur); - size -= cur; - if (res != SZ_OK) - return res; - if (cur == 0) - return SZ_OK; - } - return SZ_OK; -} - -/* -SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType) -{ - while (size != 0) - { - size_t processed = size; - RINOK(ISeqInStream_Read(stream, buf, &processed)) - if (processed == 0) - return errorType; - buf = (void *)((Byte *)buf + processed); - size -= processed; - } - return SZ_OK; -} - -SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size) -{ - return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); -} -*/ - - -SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf) -{ - size_t processed = 1; - RINOK(ISeqInStream_Read(stream, buf, &processed)) - return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; -} - - - -SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset) -{ - Int64 t = (Int64)offset; - return ILookInStream_Seek(stream, &t, SZ_SEEK_SET); -} - -SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size) -{ - const void *lookBuf; - if (*size == 0) - return SZ_OK; - RINOK(ILookInStream_Look(stream, &lookBuf, size)) - memcpy(buf, lookBuf, *size); - return ILookInStream_Skip(stream, *size); -} - -SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType) -{ - while (size != 0) - { - size_t processed = size; - RINOK(ILookInStream_Read(stream, buf, &processed)) - if (processed == 0) - return errorType; - buf = (void *)((Byte *)buf + processed); - size -= processed; - } - return SZ_OK; -} - -SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size) -{ - return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); -} - - - -#define GET_LookToRead2 Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLookToRead2) - -static SRes LookToRead2_Look_Lookahead(ILookInStreamPtr pp, const void **buf, size_t *size) -{ - SRes res = SZ_OK; - GET_LookToRead2 - size_t size2 = p->size - p->pos; - if (size2 == 0 && *size != 0) - { - p->pos = 0; - p->size = 0; - size2 = p->bufSize; - res = ISeekInStream_Read(p->realStream, p->buf, &size2); - p->size = size2; - } - if (*size > size2) - *size = size2; - *buf = p->buf + p->pos; - return res; -} - -static SRes LookToRead2_Look_Exact(ILookInStreamPtr pp, const void **buf, size_t *size) -{ - SRes res = SZ_OK; - GET_LookToRead2 - size_t size2 = p->size - p->pos; - if (size2 == 0 && *size != 0) - { - p->pos = 0; - p->size = 0; - if (*size > p->bufSize) - *size = p->bufSize; - res = ISeekInStream_Read(p->realStream, p->buf, size); - size2 = p->size = *size; - } - if (*size > size2) - *size = size2; - *buf = p->buf + p->pos; - return res; -} - -static SRes LookToRead2_Skip(ILookInStreamPtr pp, size_t offset) -{ - GET_LookToRead2 - p->pos += offset; - return SZ_OK; -} - -static SRes LookToRead2_Read(ILookInStreamPtr pp, void *buf, size_t *size) -{ - GET_LookToRead2 - size_t rem = p->size - p->pos; - if (rem == 0) - return ISeekInStream_Read(p->realStream, buf, size); - if (rem > *size) - rem = *size; - memcpy(buf, p->buf + p->pos, rem); - p->pos += rem; - *size = rem; - return SZ_OK; -} - -static SRes LookToRead2_Seek(ILookInStreamPtr pp, Int64 *pos, ESzSeek origin) -{ - GET_LookToRead2 - p->pos = p->size = 0; - return ISeekInStream_Seek(p->realStream, pos, origin); -} - -void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead) -{ - p->vt.Look = lookahead ? - LookToRead2_Look_Lookahead : - LookToRead2_Look_Exact; - p->vt.Skip = LookToRead2_Skip; - p->vt.Read = LookToRead2_Read; - p->vt.Seek = LookToRead2_Seek; -} - - - -static SRes SecToLook_Read(ISeqInStreamPtr pp, void *buf, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToLook) - return LookInStream_LookRead(p->realStream, buf, size); -} - -void SecToLook_CreateVTable(CSecToLook *p) -{ - p->vt.Read = SecToLook_Read; -} - -static SRes SecToRead_Read(ISeqInStreamPtr pp, void *buf, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToRead) - return ILookInStream_Read(p->realStream, buf, size); -} - -void SecToRead_CreateVTable(CSecToRead *p) -{ - p->vt.Read = SecToRead_Read; -} +/* 7zStream.c -- 7z Stream functions +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zTypes.h" + + +SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize) +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + size_t cur = size; + const SRes res = ISeqInStream_Read(stream, buf, &cur); + *processedSize += cur; + buf = (void *)((Byte *)buf + cur); + size -= cur; + if (res != SZ_OK) + return res; + if (cur == 0) + return SZ_OK; + } + return SZ_OK; +} + +/* +SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(ISeqInStream_Read(stream, buf, &processed)) + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size) +{ + return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} +*/ + + +SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf) +{ + size_t processed = 1; + RINOK(ISeqInStream_Read(stream, buf, &processed)) + return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF; +} + + + +SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset) +{ + Int64 t = (Int64)offset; + return ILookInStream_Seek(stream, &t, SZ_SEEK_SET); +} + +SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size) +{ + const void *lookBuf; + if (*size == 0) + return SZ_OK; + RINOK(ILookInStream_Look(stream, &lookBuf, size)) + memcpy(buf, lookBuf, *size); + return ILookInStream_Skip(stream, *size); +} + +SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType) +{ + while (size != 0) + { + size_t processed = size; + RINOK(ILookInStream_Read(stream, buf, &processed)) + if (processed == 0) + return errorType; + buf = (void *)((Byte *)buf + processed); + size -= processed; + } + return SZ_OK; +} + +SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size) +{ + return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF); +} + + + +#define GET_LookToRead2 Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLookToRead2) + +static SRes LookToRead2_Look_Lookahead(ILookInStreamPtr pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + GET_LookToRead2 + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size != 0) + { + p->pos = 0; + p->size = 0; + size2 = p->bufSize; + res = ISeekInStream_Read(p->realStream, p->buf, &size2); + p->size = size2; + } + if (*size > size2) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead2_Look_Exact(ILookInStreamPtr pp, const void **buf, size_t *size) +{ + SRes res = SZ_OK; + GET_LookToRead2 + size_t size2 = p->size - p->pos; + if (size2 == 0 && *size != 0) + { + p->pos = 0; + p->size = 0; + if (*size > p->bufSize) + *size = p->bufSize; + res = ISeekInStream_Read(p->realStream, p->buf, size); + size2 = p->size = *size; + } + if (*size > size2) + *size = size2; + *buf = p->buf + p->pos; + return res; +} + +static SRes LookToRead2_Skip(ILookInStreamPtr pp, size_t offset) +{ + GET_LookToRead2 + p->pos += offset; + return SZ_OK; +} + +static SRes LookToRead2_Read(ILookInStreamPtr pp, void *buf, size_t *size) +{ + GET_LookToRead2 + size_t rem = p->size - p->pos; + if (rem == 0) + return ISeekInStream_Read(p->realStream, buf, size); + if (rem > *size) + rem = *size; + memcpy(buf, p->buf + p->pos, rem); + p->pos += rem; + *size = rem; + return SZ_OK; +} + +static SRes LookToRead2_Seek(ILookInStreamPtr pp, Int64 *pos, ESzSeek origin) +{ + GET_LookToRead2 + p->pos = p->size = 0; + return ISeekInStream_Seek(p->realStream, pos, origin); +} + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead) +{ + p->vt.Look = lookahead ? + LookToRead2_Look_Lookahead : + LookToRead2_Look_Exact; + p->vt.Skip = LookToRead2_Skip; + p->vt.Read = LookToRead2_Read; + p->vt.Seek = LookToRead2_Seek; +} + + + +static SRes SecToLook_Read(ISeqInStreamPtr pp, void *buf, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToLook) + return LookInStream_LookRead(p->realStream, buf, size); +} + +void SecToLook_CreateVTable(CSecToLook *p) +{ + p->vt.Read = SecToLook_Read; +} + +static SRes SecToRead_Read(ISeqInStreamPtr pp, void *buf, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToRead) + return ILookInStream_Read(p->realStream, buf, size); +} + +void SecToRead_CreateVTable(CSecToRead *p) +{ + p->vt.Read = SecToRead_Read; +} diff --git a/C/7zTypes.h b/C/7zTypes.h index 5d3c74834..5b77420a3 100644 --- a/C/7zTypes.h +++ b/C/7zTypes.h @@ -1,597 +1,597 @@ -/* 7zTypes.h -- Basic types -2024-01-24 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_7Z_TYPES_H -#define ZIP7_7Z_TYPES_H - -#ifdef _WIN32 -/* #include */ -#else -#include -#endif - -#include - -#ifndef EXTERN_C_BEGIN -#ifdef __cplusplus -#define EXTERN_C_BEGIN extern "C" { -#define EXTERN_C_END } -#else -#define EXTERN_C_BEGIN -#define EXTERN_C_END -#endif -#endif - -EXTERN_C_BEGIN - -#define SZ_OK 0 - -#define SZ_ERROR_DATA 1 -#define SZ_ERROR_MEM 2 -#define SZ_ERROR_CRC 3 -#define SZ_ERROR_UNSUPPORTED 4 -#define SZ_ERROR_PARAM 5 -#define SZ_ERROR_INPUT_EOF 6 -#define SZ_ERROR_OUTPUT_EOF 7 -#define SZ_ERROR_READ 8 -#define SZ_ERROR_WRITE 9 -#define SZ_ERROR_PROGRESS 10 -#define SZ_ERROR_FAIL 11 -#define SZ_ERROR_THREAD 12 - -#define SZ_ERROR_ARCHIVE 16 -#define SZ_ERROR_NO_ARCHIVE 17 - -typedef int SRes; - - -#ifdef _MSC_VER - #if _MSC_VER > 1200 - #define MY_ALIGN(n) __declspec(align(n)) - #else - #define MY_ALIGN(n) - #endif -#else - /* - // C11/C++11: - #include - #define MY_ALIGN(n) alignas(n) - */ - #define MY_ALIGN(n) __attribute__ ((aligned(n))) -#endif - - -#ifdef _WIN32 - -/* typedef DWORD WRes; */ -typedef unsigned WRes; -#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) - -// #define MY_HRES_ERROR_INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR) - -#else // _WIN32 - -// #define ENV_HAVE_LSTAT -typedef int WRes; - -// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT -#define MY_FACILITY_ERRNO 0x800 -#define MY_FACILITY_WIN32 7 -#define MY_FACILITY_WRes MY_FACILITY_ERRNO - -#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \ - ( (HRESULT)(x) & 0x0000FFFF) \ - | (MY_FACILITY_WRes << 16) \ - | (HRESULT)0x80000000 )) - -#define MY_SRes_HRESULT_FROM_WRes(x) \ - ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x)) - -// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno) -#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x) - -/* -#define ERROR_FILE_NOT_FOUND 2L -#define ERROR_ACCESS_DENIED 5L -#define ERROR_NO_MORE_FILES 18L -#define ERROR_LOCK_VIOLATION 33L -#define ERROR_FILE_EXISTS 80L -#define ERROR_DISK_FULL 112L -#define ERROR_NEGATIVE_SEEK 131L -#define ERROR_ALREADY_EXISTS 183L -#define ERROR_DIRECTORY 267L -#define ERROR_TOO_MANY_POSTS 298L - -#define ERROR_INTERNAL_ERROR 1359L -#define ERROR_INVALID_REPARSE_DATA 4392L -#define ERROR_REPARSE_TAG_INVALID 4393L -#define ERROR_REPARSE_TAG_MISMATCH 4394L -*/ - -// we use errno equivalents for some WIN32 errors: - -#define ERROR_INVALID_PARAMETER EINVAL -#define ERROR_INVALID_FUNCTION EINVAL -#define ERROR_ALREADY_EXISTS EEXIST -#define ERROR_FILE_EXISTS EEXIST -#define ERROR_PATH_NOT_FOUND ENOENT -#define ERROR_FILE_NOT_FOUND ENOENT -#define ERROR_DISK_FULL ENOSPC -// #define ERROR_INVALID_HANDLE EBADF - -// we use FACILITY_WIN32 for errors that has no errno equivalent -// Too many posts were made to a semaphore. -#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL) -#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L) -#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L) - -// if (MY_FACILITY_WRes != FACILITY_WIN32), -// we use FACILITY_WIN32 for COM errors: -#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) -#define E_INVALIDARG ((HRESULT)0x80070057L) -#define MY_E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L) - -/* -// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents: -#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM) -#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) -#define MY_E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) -*/ - -#define TEXT(quote) quote - -#define FILE_ATTRIBUTE_READONLY 0x0001 -#define FILE_ATTRIBUTE_HIDDEN 0x0002 -#define FILE_ATTRIBUTE_SYSTEM 0x0004 -#define FILE_ATTRIBUTE_DIRECTORY 0x0010 -#define FILE_ATTRIBUTE_ARCHIVE 0x0020 -#define FILE_ATTRIBUTE_DEVICE 0x0040 -#define FILE_ATTRIBUTE_NORMAL 0x0080 -#define FILE_ATTRIBUTE_TEMPORARY 0x0100 -#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200 -#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400 -#define FILE_ATTRIBUTE_COMPRESSED 0x0800 -#define FILE_ATTRIBUTE_OFFLINE 0x1000 -#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000 -#define FILE_ATTRIBUTE_ENCRYPTED 0x4000 - -#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ - -#endif - - -#ifndef RINOK -#define RINOK(x) { const int _result_ = (x); if (_result_ != 0) return _result_; } -#endif - -#ifndef RINOK_WRes -#define RINOK_WRes(x) { const WRes _result_ = (x); if (_result_ != 0) return _result_; } -#endif - -typedef unsigned char Byte; -typedef short Int16; -typedef unsigned short UInt16; - -#ifdef Z7_DECL_Int32_AS_long -typedef long Int32; -typedef unsigned long UInt32; -#else -typedef int Int32; -typedef unsigned int UInt32; -#endif - - -#ifndef _WIN32 - -typedef int INT; -typedef Int32 INT32; -typedef unsigned int UINT; -typedef UInt32 UINT32; -typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility -typedef UINT32 ULONG; - -#undef DWORD -typedef UINT32 DWORD; - -#define VOID void - -#define HRESULT LONG - -typedef void *LPVOID; -// typedef void VOID; -// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; -// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits) -typedef long INT_PTR; -typedef unsigned long UINT_PTR; -typedef long LONG_PTR; -typedef unsigned long DWORD_PTR; - -typedef size_t SIZE_T; - -#endif // _WIN32 - - -#define MY_HRES_ERROR_INTERNAL_ERROR ((HRESULT)0x8007054FL) - - -#ifdef Z7_DECL_Int64_AS_long - -typedef long Int64; -typedef unsigned long UInt64; - -#else - -#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__clang__) -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#else -#if defined(__clang__) || defined(__GNUC__) -#include -typedef int64_t Int64; -typedef uint64_t UInt64; -#else -typedef long long int Int64; -typedef unsigned long long int UInt64; -// #define UINT64_CONST(n) n ## ULL -#endif -#endif - -#endif - -#define UINT64_CONST(n) n - - -#ifdef Z7_DECL_SizeT_AS_unsigned_int -typedef unsigned int SizeT; -#else -typedef size_t SizeT; -#endif - -/* -#if (defined(_MSC_VER) && _MSC_VER <= 1200) -typedef size_t MY_uintptr_t; -#else -#include -typedef uintptr_t MY_uintptr_t; -#endif -*/ - -typedef int BoolInt; -/* typedef BoolInt Bool; */ -#define True 1 -#define False 0 - - -#ifdef _WIN32 -#define Z7_STDCALL __stdcall -#else -#define Z7_STDCALL -#endif - -#ifdef _MSC_VER - -#if _MSC_VER >= 1300 -#define Z7_NO_INLINE __declspec(noinline) -#else -#define Z7_NO_INLINE -#endif - -#define Z7_FORCE_INLINE __forceinline - -#define Z7_CDECL __cdecl -#define Z7_FASTCALL __fastcall - -#else // _MSC_VER - -#if (defined(__GNUC__) && (__GNUC__ >= 4)) \ - || (defined(__clang__) && (__clang_major__ >= 4)) \ - || defined(__INTEL_COMPILER) \ - || defined(__xlC__) -#define Z7_NO_INLINE __attribute__((noinline)) -#define Z7_FORCE_INLINE __attribute__((always_inline)) inline -#else -#define Z7_NO_INLINE -#define Z7_FORCE_INLINE -#endif - -#define Z7_CDECL - -#if defined(_M_IX86) \ - || defined(__i386__) -// #define Z7_FASTCALL __attribute__((fastcall)) -// #define Z7_FASTCALL __attribute__((cdecl)) -#define Z7_FASTCALL -#elif defined(MY_CPU_AMD64) -// #define Z7_FASTCALL __attribute__((ms_abi)) -#define Z7_FASTCALL -#else -#define Z7_FASTCALL -#endif - -#endif // _MSC_VER - - -/* The following interfaces use first parameter as pointer to structure */ - -// #define Z7_C_IFACE_CONST_QUAL -#define Z7_C_IFACE_CONST_QUAL const - -#define Z7_C_IFACE_DECL(a) \ - struct a ## _; \ - typedef Z7_C_IFACE_CONST_QUAL struct a ## _ * a ## Ptr; \ - typedef struct a ## _ a; \ - struct a ## _ - - -Z7_C_IFACE_DECL (IByteIn) -{ - Byte (*Read)(IByteInPtr p); /* reads one byte, returns 0 in case of EOF or error */ -}; -#define IByteIn_Read(p) (p)->Read(p) - - -Z7_C_IFACE_DECL (IByteOut) -{ - void (*Write)(IByteOutPtr p, Byte b); -}; -#define IByteOut_Write(p, b) (p)->Write(p, b) - - -Z7_C_IFACE_DECL (ISeqInStream) -{ - SRes (*Read)(ISeqInStreamPtr p, void *buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) < input(*size)) is allowed */ -}; -#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) - -/* try to read as much as avail in stream and limited by (*processedSize) */ -SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize); -/* it can return SZ_ERROR_INPUT_EOF */ -// SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size); -// SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType); -SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf); - - -Z7_C_IFACE_DECL (ISeqOutStream) -{ - size_t (*Write)(ISeqOutStreamPtr p, const void *buf, size_t size); - /* Returns: result - the number of actually written bytes. - (result < size) means error */ -}; -#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) - -typedef enum -{ - SZ_SEEK_SET = 0, - SZ_SEEK_CUR = 1, - SZ_SEEK_END = 2 -} ESzSeek; - - -Z7_C_IFACE_DECL (ISeekInStream) -{ - SRes (*Read)(ISeekInStreamPtr p, void *buf, size_t *size); /* same as ISeqInStream::Read */ - SRes (*Seek)(ISeekInStreamPtr p, Int64 *pos, ESzSeek origin); -}; -#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) -#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) - - -Z7_C_IFACE_DECL (ILookInStream) -{ - SRes (*Look)(ILookInStreamPtr p, const void **buf, size_t *size); - /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. - (output(*size) > input(*size)) is not allowed - (output(*size) < input(*size)) is allowed */ - SRes (*Skip)(ILookInStreamPtr p, size_t offset); - /* offset must be <= output(*size) of Look */ - SRes (*Read)(ILookInStreamPtr p, void *buf, size_t *size); - /* reads directly (without buffer). It's same as ISeqInStream::Read */ - SRes (*Seek)(ILookInStreamPtr p, Int64 *pos, ESzSeek origin); -}; - -#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) -#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) -#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) -#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) - - -SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size); -SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset); - -/* reads via ILookInStream::Read */ -SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType); -SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size); - - -typedef struct -{ - ILookInStream vt; - ISeekInStreamPtr realStream; - - size_t pos; - size_t size; /* it's data size */ - - /* the following variables must be set outside */ - Byte *buf; - size_t bufSize; -} CLookToRead2; - -void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); - -#define LookToRead2_INIT(p) { (p)->pos = (p)->size = 0; } - - -typedef struct -{ - ISeqInStream vt; - ILookInStreamPtr realStream; -} CSecToLook; - -void SecToLook_CreateVTable(CSecToLook *p); - - - -typedef struct -{ - ISeqInStream vt; - ILookInStreamPtr realStream; -} CSecToRead; - -void SecToRead_CreateVTable(CSecToRead *p); - - -Z7_C_IFACE_DECL (ICompressProgress) -{ - SRes (*Progress)(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize); - /* Returns: result. (result != SZ_OK) means break. - Value (UInt64)(Int64)-1 for size means unknown value. */ -}; - -#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) - - - -typedef struct ISzAlloc ISzAlloc; -typedef const ISzAlloc * ISzAllocPtr; - -struct ISzAlloc -{ - void *(*Alloc)(ISzAllocPtr p, size_t size); - void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ -}; - -#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) -#define ISzAlloc_Free(p, a) (p)->Free(p, a) - -/* deprecated */ -#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) -#define IAlloc_Free(p, a) ISzAlloc_Free(p, a) - - - - - -#ifndef MY_offsetof - #ifdef offsetof - #define MY_offsetof(type, m) offsetof(type, m) - /* - #define MY_offsetof(type, m) FIELD_OFFSET(type, m) - */ - #else - #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) - #endif -#endif - - - -#ifndef Z7_container_of - -/* -#define Z7_container_of(ptr, type, m) container_of(ptr, type, m) -#define Z7_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) -#define Z7_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) -#define Z7_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) -*/ - -/* - GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" - GCC 3.4.4 : classes with constructor - GCC 4.8.1 : classes with non-public variable members" -*/ - -#define Z7_container_of(ptr, type, m) \ - ((type *)(void *)((char *)(void *) \ - (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) - -#define Z7_container_of_CONST(ptr, type, m) \ - ((const type *)(const void *)((const char *)(const void *) \ - (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) - -/* -#define Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) \ - ((type *)(void *)(const void *)((const char *)(const void *) \ - (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) -*/ - -#endif - -#define Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr)) - -// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) -#define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of(ptr, type, m) -// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) - -#define Z7_CONTAINER_FROM_VTBL_CONST(ptr, type, m) Z7_container_of_CONST(ptr, type, m) - -#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) -/* -#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL(ptr, type, m) -*/ -#if defined (__clang__) || defined(__GNUC__) -#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") -#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL \ - _Pragma("GCC diagnostic pop") -#else -#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL -#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL -#endif - -#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \ - Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \ - type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \ - Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL - -#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(type) \ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(pp, type, vt, p) - - -// #define ZIP7_DECLARE_HANDLE(name) typedef void *name; -#define Z7_DECLARE_HANDLE(name) struct name##_dummy{int unused;}; typedef struct name##_dummy *name; - - -#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) - -#ifndef Z7_ARRAY_SIZE -#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - - -#ifdef _WIN32 - -#define CHAR_PATH_SEPARATOR '\\' -#define WCHAR_PATH_SEPARATOR L'\\' -#define STRING_PATH_SEPARATOR "\\" -#define WSTRING_PATH_SEPARATOR L"\\" - -#else - -#define CHAR_PATH_SEPARATOR '/' -#define WCHAR_PATH_SEPARATOR L'/' -#define STRING_PATH_SEPARATOR "/" -#define WSTRING_PATH_SEPARATOR L"/" - -#endif - -#define k_PropVar_TimePrec_0 0 -#define k_PropVar_TimePrec_Unix 1 -#define k_PropVar_TimePrec_DOS 2 -#define k_PropVar_TimePrec_HighPrec 3 -#define k_PropVar_TimePrec_Base 16 -#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7) -#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9) - -EXTERN_C_END - -#endif - -/* -#ifndef Z7_ST -#ifdef _7ZIP_ST -#define Z7_ST -#endif -#endif -*/ +/* 7zTypes.h -- Basic types +2024-01-24 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_7Z_TYPES_H +#define ZIP7_7Z_TYPES_H + +#ifdef _WIN32 +/* #include */ +#else +#include +#endif + +#include + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + + +#ifdef _MSC_VER + #if _MSC_VER > 1200 + #define MY_ALIGN(n) __declspec(align(n)) + #else + #define MY_ALIGN(n) + #endif +#else + /* + // C11/C++11: + #include + #define MY_ALIGN(n) alignas(n) + */ + #define MY_ALIGN(n) __attribute__ ((aligned(n))) +#endif + + +#ifdef _WIN32 + +/* typedef DWORD WRes; */ +typedef unsigned WRes; +#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) + +// #define MY_HRES_ERROR_INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR) + +#else // _WIN32 + +// #define ENV_HAVE_LSTAT +typedef int WRes; + +// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT +#define MY_FACILITY_ERRNO 0x800 +#define MY_FACILITY_WIN32 7 +#define MY_FACILITY_WRes MY_FACILITY_ERRNO + +#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \ + ( (HRESULT)(x) & 0x0000FFFF) \ + | (MY_FACILITY_WRes << 16) \ + | (HRESULT)0x80000000 )) + +#define MY_SRes_HRESULT_FROM_WRes(x) \ + ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x)) + +// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno) +#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x) + +/* +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_LOCK_VIOLATION 33L +#define ERROR_FILE_EXISTS 80L +#define ERROR_DISK_FULL 112L +#define ERROR_NEGATIVE_SEEK 131L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_DIRECTORY 267L +#define ERROR_TOO_MANY_POSTS 298L + +#define ERROR_INTERNAL_ERROR 1359L +#define ERROR_INVALID_REPARSE_DATA 4392L +#define ERROR_REPARSE_TAG_INVALID 4393L +#define ERROR_REPARSE_TAG_MISMATCH 4394L +*/ + +// we use errno equivalents for some WIN32 errors: + +#define ERROR_INVALID_PARAMETER EINVAL +#define ERROR_INVALID_FUNCTION EINVAL +#define ERROR_ALREADY_EXISTS EEXIST +#define ERROR_FILE_EXISTS EEXIST +#define ERROR_PATH_NOT_FOUND ENOENT +#define ERROR_FILE_NOT_FOUND ENOENT +#define ERROR_DISK_FULL ENOSPC +// #define ERROR_INVALID_HANDLE EBADF + +// we use FACILITY_WIN32 for errors that has no errno equivalent +// Too many posts were made to a semaphore. +#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL) +#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L) +#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L) + +// if (MY_FACILITY_WRes != FACILITY_WIN32), +// we use FACILITY_WIN32 for COM errors: +#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) +#define E_INVALIDARG ((HRESULT)0x80070057L) +#define MY_E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L) + +/* +// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents: +#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM) +#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) +#define MY_E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) +*/ + +#define TEXT(quote) quote + +#define FILE_ATTRIBUTE_READONLY 0x0001 +#define FILE_ATTRIBUTE_HIDDEN 0x0002 +#define FILE_ATTRIBUTE_SYSTEM 0x0004 +#define FILE_ATTRIBUTE_DIRECTORY 0x0010 +#define FILE_ATTRIBUTE_ARCHIVE 0x0020 +#define FILE_ATTRIBUTE_DEVICE 0x0040 +#define FILE_ATTRIBUTE_NORMAL 0x0080 +#define FILE_ATTRIBUTE_TEMPORARY 0x0100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400 +#define FILE_ATTRIBUTE_COMPRESSED 0x0800 +#define FILE_ATTRIBUTE_OFFLINE 0x1000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x4000 + +#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ + +#endif + + +#ifndef RINOK +#define RINOK(x) { const int _result_ = (x); if (_result_ != 0) return _result_; } +#endif + +#ifndef RINOK_WRes +#define RINOK_WRes(x) { const WRes _result_ = (x); if (_result_ != 0) return _result_; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef Z7_DECL_Int32_AS_long +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + + +#ifndef _WIN32 + +typedef int INT; +typedef Int32 INT32; +typedef unsigned int UINT; +typedef UInt32 UINT32; +typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility +typedef UINT32 ULONG; + +#undef DWORD +typedef UINT32 DWORD; + +#define VOID void + +#define HRESULT LONG + +typedef void *LPVOID; +// typedef void VOID; +// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; +// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits) +typedef long INT_PTR; +typedef unsigned long UINT_PTR; +typedef long LONG_PTR; +typedef unsigned long DWORD_PTR; + +typedef size_t SIZE_T; + +#endif // _WIN32 + + +#define MY_HRES_ERROR_INTERNAL_ERROR ((HRESULT)0x8007054FL) + + +#ifdef Z7_DECL_Int64_AS_long + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__clang__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +#if defined(__clang__) || defined(__GNUC__) +#include +typedef int64_t Int64; +typedef uint64_t UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +// #define UINT64_CONST(n) n ## ULL +#endif +#endif + +#endif + +#define UINT64_CONST(n) n + + +#ifdef Z7_DECL_SizeT_AS_unsigned_int +typedef unsigned int SizeT; +#else +typedef size_t SizeT; +#endif + +/* +#if (defined(_MSC_VER) && _MSC_VER <= 1200) +typedef size_t MY_uintptr_t; +#else +#include +typedef uintptr_t MY_uintptr_t; +#endif +*/ + +typedef int BoolInt; +/* typedef BoolInt Bool; */ +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define Z7_STDCALL __stdcall +#else +#define Z7_STDCALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define Z7_NO_INLINE __declspec(noinline) +#else +#define Z7_NO_INLINE +#endif + +#define Z7_FORCE_INLINE __forceinline + +#define Z7_CDECL __cdecl +#define Z7_FASTCALL __fastcall + +#else // _MSC_VER + +#if (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4)) \ + || defined(__INTEL_COMPILER) \ + || defined(__xlC__) +#define Z7_NO_INLINE __attribute__((noinline)) +#define Z7_FORCE_INLINE __attribute__((always_inline)) inline +#else +#define Z7_NO_INLINE +#define Z7_FORCE_INLINE +#endif + +#define Z7_CDECL + +#if defined(_M_IX86) \ + || defined(__i386__) +// #define Z7_FASTCALL __attribute__((fastcall)) +// #define Z7_FASTCALL __attribute__((cdecl)) +#define Z7_FASTCALL +#elif defined(MY_CPU_AMD64) +// #define Z7_FASTCALL __attribute__((ms_abi)) +#define Z7_FASTCALL +#else +#define Z7_FASTCALL +#endif + +#endif // _MSC_VER + + +/* The following interfaces use first parameter as pointer to structure */ + +// #define Z7_C_IFACE_CONST_QUAL +#define Z7_C_IFACE_CONST_QUAL const + +#define Z7_C_IFACE_DECL(a) \ + struct a ## _; \ + typedef Z7_C_IFACE_CONST_QUAL struct a ## _ * a ## Ptr; \ + typedef struct a ## _ a; \ + struct a ## _ + + +Z7_C_IFACE_DECL (IByteIn) +{ + Byte (*Read)(IByteInPtr p); /* reads one byte, returns 0 in case of EOF or error */ +}; +#define IByteIn_Read(p) (p)->Read(p) + + +Z7_C_IFACE_DECL (IByteOut) +{ + void (*Write)(IByteOutPtr p, Byte b); +}; +#define IByteOut_Write(p, b) (p)->Write(p, b) + + +Z7_C_IFACE_DECL (ISeqInStream) +{ + SRes (*Read)(ISeqInStreamPtr p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +}; +#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) + +/* try to read as much as avail in stream and limited by (*processedSize) */ +SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize); +/* it can return SZ_ERROR_INPUT_EOF */ +// SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size); +// SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf); + + +Z7_C_IFACE_DECL (ISeqOutStream) +{ + size_t (*Write)(ISeqOutStreamPtr p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +}; +#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + + +Z7_C_IFACE_DECL (ISeekInStream) +{ + SRes (*Read)(ISeekInStreamPtr p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(ISeekInStreamPtr p, Int64 *pos, ESzSeek origin); +}; +#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +Z7_C_IFACE_DECL (ILookInStream) +{ + SRes (*Look)(ILookInStreamPtr p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(ILookInStreamPtr p, size_t offset); + /* offset must be <= output(*size) of Look */ + SRes (*Read)(ILookInStreamPtr p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(ILookInStreamPtr p, Int64 *pos, ESzSeek origin); +}; + +#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) +#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) +#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size); + + +typedef struct +{ + ILookInStream vt; + ISeekInStreamPtr realStream; + + size_t pos; + size_t size; /* it's data size */ + + /* the following variables must be set outside */ + Byte *buf; + size_t bufSize; +} CLookToRead2; + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); + +#define LookToRead2_INIT(p) { (p)->pos = (p)->size = 0; } + + +typedef struct +{ + ISeqInStream vt; + ILookInStreamPtr realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + + + +typedef struct +{ + ISeqInStream vt; + ILookInStreamPtr realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + + +Z7_C_IFACE_DECL (ICompressProgress) +{ + SRes (*Progress)(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +}; + +#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) + + + +typedef struct ISzAlloc ISzAlloc; +typedef const ISzAlloc * ISzAllocPtr; + +struct ISzAlloc +{ + void *(*Alloc)(ISzAllocPtr p, size_t size); + void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ +}; + +#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) +#define ISzAlloc_Free(p, a) (p)->Free(p, a) + +/* deprecated */ +#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) +#define IAlloc_Free(p, a) ISzAlloc_Free(p, a) + + + + + +#ifndef MY_offsetof + #ifdef offsetof + #define MY_offsetof(type, m) offsetof(type, m) + /* + #define MY_offsetof(type, m) FIELD_OFFSET(type, m) + */ + #else + #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) + #endif +#endif + + + +#ifndef Z7_container_of + +/* +#define Z7_container_of(ptr, type, m) container_of(ptr, type, m) +#define Z7_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) +#define Z7_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) +#define Z7_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) +*/ + +/* + GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" + GCC 3.4.4 : classes with constructor + GCC 4.8.1 : classes with non-public variable members" +*/ + +#define Z7_container_of(ptr, type, m) \ + ((type *)(void *)((char *)(void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) + +#define Z7_container_of_CONST(ptr, type, m) \ + ((const type *)(const void *)((const char *)(const void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) + +/* +#define Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) \ + ((type *)(void *)(const void *)((const char *)(const void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) +*/ + +#endif + +#define Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr)) + +// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +#define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of(ptr, type, m) +// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) + +#define Z7_CONTAINER_FROM_VTBL_CONST(ptr, type, m) Z7_container_of_CONST(ptr, type, m) + +#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +/* +#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL(ptr, type, m) +*/ +#if defined (__clang__) || defined(__GNUC__) +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL \ + _Pragma("GCC diagnostic pop") +#else +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL +#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL +#endif + +#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \ + Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \ + type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \ + Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL + +#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(type) \ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(pp, type, vt, p) + + +// #define ZIP7_DECLARE_HANDLE(name) typedef void *name; +#define Z7_DECLARE_HANDLE(name) struct name##_dummy{int unused;}; typedef struct name##_dummy *name; + + +#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) + +#ifndef Z7_ARRAY_SIZE +#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +#define k_PropVar_TimePrec_0 0 +#define k_PropVar_TimePrec_Unix 1 +#define k_PropVar_TimePrec_DOS 2 +#define k_PropVar_TimePrec_HighPrec 3 +#define k_PropVar_TimePrec_Base 16 +#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7) +#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9) + +EXTERN_C_END + +#endif + +/* +#ifndef Z7_ST +#ifdef _7ZIP_ST +#define Z7_ST +#endif +#endif +*/ diff --git a/C/7zVersion.h b/C/7zVersion.h index a489caa34..e82ba0bbe 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h @@ -1,27 +1,27 @@ -#define MY_VER_MAJOR 24 -#define MY_VER_MINOR 8 -#define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "24.08" -#define MY_VERSION MY_VERSION_NUMBERS - -#ifdef MY_CPU_NAME - #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")" -#else - #define MY_VERSION_CPU MY_VERSION -#endif - -#define MY_DATE "2024-08-11" -#undef MY_COPYRIGHT -#undef MY_VERSION_COPYRIGHT_DATE -#define MY_AUTHOR_NAME "Igor Pavlov" -#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" -#define MY_COPYRIGHT_CR "Copyright (c) 1999-2024 Igor Pavlov" - -#ifdef USE_COPYRIGHT_CR - #define MY_COPYRIGHT MY_COPYRIGHT_CR -#else - #define MY_COPYRIGHT MY_COPYRIGHT_PD -#endif - -#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE -#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE +#define MY_VER_MAJOR 24 +#define MY_VER_MINOR 9 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "24.09" +#define MY_VERSION MY_VERSION_NUMBERS + +#ifdef MY_CPU_NAME + #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")" +#else + #define MY_VERSION_CPU MY_VERSION +#endif + +#define MY_DATE "2024-11-29" +#undef MY_COPYRIGHT +#undef MY_VERSION_COPYRIGHT_DATE +#define MY_AUTHOR_NAME "Igor Pavlov" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2024 Igor Pavlov" + +#ifdef USE_COPYRIGHT_CR + #define MY_COPYRIGHT MY_COPYRIGHT_CR +#else + #define MY_COPYRIGHT MY_COPYRIGHT_PD +#endif + +#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE diff --git a/C/7zVersion.rc b/C/7zVersion.rc index 6ed26de74..e520995dd 100644 --- a/C/7zVersion.rc +++ b/C/7zVersion.rc @@ -1,55 +1,55 @@ -#define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL -#define MY_VOS_NT_WINDOWS32 0x00040004L -#define MY_VOS_CE_WINDOWS32 0x00050004L - -#define MY_VFT_APP 0x00000001L -#define MY_VFT_DLL 0x00000002L - -// #include - -#ifndef MY_VERSION -#include "7zVersion.h" -#endif - -#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0 - -#ifdef DEBUG -#define DBG_FL VS_FF_DEBUG -#else -#define DBG_FL 0 -#endif - -#define MY_VERSION_INFO(fileType, descr, intName, origName) \ -LANGUAGE 9, 1 \ -1 VERSIONINFO \ - FILEVERSION MY_VER \ - PRODUCTVERSION MY_VER \ - FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \ - FILEFLAGS DBG_FL \ - FILEOS MY_VOS_NT_WINDOWS32 \ - FILETYPE fileType \ - FILESUBTYPE 0x0L \ -BEGIN \ - BLOCK "StringFileInfo" \ - BEGIN \ - BLOCK "040904b0" \ - BEGIN \ - VALUE "CompanyName", "Igor Pavlov" \ - VALUE "FileDescription", descr \ - VALUE "FileVersion", MY_VERSION \ - VALUE "InternalName", intName \ - VALUE "LegalCopyright", MY_COPYRIGHT \ - VALUE "OriginalFilename", origName \ - VALUE "ProductName", "7-Zip" \ - VALUE "ProductVersion", MY_VERSION \ - END \ - END \ - BLOCK "VarFileInfo" \ - BEGIN \ - VALUE "Translation", 0x409, 1200 \ - END \ -END - -#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe") - -#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll") +#define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL +#define MY_VOS_NT_WINDOWS32 0x00040004L +#define MY_VOS_CE_WINDOWS32 0x00050004L + +#define MY_VFT_APP 0x00000001L +#define MY_VFT_DLL 0x00000002L + +// #include + +#ifndef MY_VERSION +#include "7zVersion.h" +#endif + +#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0 + +#ifdef DEBUG +#define DBG_FL VS_FF_DEBUG +#else +#define DBG_FL 0 +#endif + +#define MY_VERSION_INFO(fileType, descr, intName, origName) \ +LANGUAGE 9, 1 \ +1 VERSIONINFO \ + FILEVERSION MY_VER \ + PRODUCTVERSION MY_VER \ + FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \ + FILEFLAGS DBG_FL \ + FILEOS MY_VOS_NT_WINDOWS32 \ + FILETYPE fileType \ + FILESUBTYPE 0x0L \ +BEGIN \ + BLOCK "StringFileInfo" \ + BEGIN \ + BLOCK "040904b0" \ + BEGIN \ + VALUE "CompanyName", "Igor Pavlov" \ + VALUE "FileDescription", descr \ + VALUE "FileVersion", MY_VERSION \ + VALUE "InternalName", intName \ + VALUE "LegalCopyright", MY_COPYRIGHT \ + VALUE "OriginalFilename", origName \ + VALUE "ProductName", "7-Zip" \ + VALUE "ProductVersion", MY_VERSION \ + END \ + END \ + BLOCK "VarFileInfo" \ + BEGIN \ + VALUE "Translation", 0x409, 1200 \ + END \ +END + +#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe") + +#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll") diff --git a/C/7zWindows.h b/C/7zWindows.h index 0967a7992..42c6db8bf 100644 --- a/C/7zWindows.h +++ b/C/7zWindows.h @@ -1,101 +1,101 @@ -/* 7zWindows.h -- StdAfx -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_7Z_WINDOWS_H -#define ZIP7_INC_7Z_WINDOWS_H - -#ifdef _WIN32 - -#if defined(__clang__) -# pragma clang diagnostic push -#endif - -#if defined(_MSC_VER) - -#pragma warning(push) -#pragma warning(disable : 4668) // '_WIN32_WINNT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' - -#if _MSC_VER == 1900 -// for old kit10 versions -// #pragma warning(disable : 4255) // winuser.h(13979): warning C4255: 'GetThreadDpiAwarenessContext': -#endif -// win10 Windows Kit: -#endif // _MSC_VER - -#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) -// for msvc6 without sdk2003 -#define RPC_NO_WINDOWS_H -#endif - -#if defined(__MINGW32__) || defined(__MINGW64__) -// #if defined(__GNUC__) && !defined(__clang__) -#include -#else -#include -#endif -// #include -// #include - -// but if precompiled with clang-cl then we need -// #include -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) -#ifndef _W64 - -typedef long LONG_PTR, *PLONG_PTR; -typedef unsigned long ULONG_PTR, *PULONG_PTR; -typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; - -#define Z7_OLD_WIN_SDK -#endif // _W64 -#endif // _MSC_VER == 1200 - -#ifdef Z7_OLD_WIN_SDK - -#ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif -#ifndef INVALID_SET_FILE_POINTER -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif -#ifndef FILE_SPECIAL_ACCESS -#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) -#endif - -// ShlObj.h: -// #define BIF_NEWDIALOGSTYLE 0x0040 - -#pragma warning(disable : 4201) -// #pragma warning(disable : 4115) - -#undef VARIANT_TRUE -#define VARIANT_TRUE ((VARIANT_BOOL)-1) -#endif - -#endif // Z7_OLD_WIN_SDK - -#ifdef UNDER_CE -#undef VARIANT_TRUE -#define VARIANT_TRUE ((VARIANT_BOOL)-1) -#endif - - -#if defined(_MSC_VER) -#if _MSC_VER >= 1400 && _MSC_VER <= 1600 - // BaseTsd.h(148) : 'HandleToULong' : unreferenced inline function has been removed - // string.h - // #pragma warning(disable : 4514) -#endif -#endif - - -/* #include "7zTypes.h" */ - -#endif +/* 7zWindows.h -- StdAfx +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_WINDOWS_H +#define ZIP7_INC_7Z_WINDOWS_H + +#ifdef _WIN32 + +#if defined(__clang__) +# pragma clang diagnostic push +#endif + +#if defined(_MSC_VER) + +#pragma warning(push) +#pragma warning(disable : 4668) // '_WIN32_WINNT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + +#if _MSC_VER == 1900 +// for old kit10 versions +// #pragma warning(disable : 4255) // winuser.h(13979): warning C4255: 'GetThreadDpiAwarenessContext': +#endif +// win10 Windows Kit: +#endif // _MSC_VER + +#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) +// for msvc6 without sdk2003 +#define RPC_NO_WINDOWS_H +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +// #if defined(__GNUC__) && !defined(__clang__) +#include +#else +#include +#endif +// #include +// #include + +// but if precompiled with clang-cl then we need +// #include +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) +#ifndef _W64 + +typedef long LONG_PTR, *PLONG_PTR; +typedef unsigned long ULONG_PTR, *PULONG_PTR; +typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; + +#define Z7_OLD_WIN_SDK +#endif // _W64 +#endif // _MSC_VER == 1200 + +#ifdef Z7_OLD_WIN_SDK + +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif +#ifndef FILE_SPECIAL_ACCESS +#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#endif + +// ShlObj.h: +// #define BIF_NEWDIALOGSTYLE 0x0040 + +#pragma warning(disable : 4201) +// #pragma warning(disable : 4115) + +#undef VARIANT_TRUE +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + +#endif // Z7_OLD_WIN_SDK + +#ifdef UNDER_CE +#undef VARIANT_TRUE +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + + +#if defined(_MSC_VER) +#if _MSC_VER >= 1400 && _MSC_VER <= 1600 + // BaseTsd.h(148) : 'HandleToULong' : unreferenced inline function has been removed + // string.h + // #pragma warning(disable : 4514) +#endif +#endif + + +/* #include "7zTypes.h" */ + +#endif diff --git a/C/7zip_gcc_c.mak b/C/7zip_gcc_c.mak index bba911613..195d23d86 100644 --- a/C/7zip_gcc_c.mak +++ b/C/7zip_gcc_c.mak @@ -1,360 +1,360 @@ - -MY_ARCH_2 = $(MY_ARCH) - -MY_ASM = jwasm -MY_ASM = asmc - -ifndef RC -#RC=windres.exe --target=pe-x86-64 -#RC=windres.exe -F pe-i386 -RC=windres.exe -endif - -PROGPATH = $(O)/$(PROG) -PROGPATH_STATIC = $(O)/$(PROG)s - -ifneq ($(CC), xlc) -CFLAGS_WARN_WALL = -Wall -Werror -Wextra -endif - -# for object file -CFLAGS_BASE_LIST = -c -# for ASM file -# CFLAGS_BASE_LIST = -S - -FLAGS_FLTO = -flto -FLAGS_FLTO = - -CFLAGS_BASE = $(MY_ARCH_2) -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \ - -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE - - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -ifdef IS_MINGW -LDFLAGS_STATIC_2 = -static -else -ifndef DEF_FILE -ifndef IS_NOT_STANDALONE -ifndef MY_DYNAMIC_LINK -ifneq ($(CC), clang) -LDFLAGS_STATIC_2 = -# -static -# -static-libstdc++ -static-libgcc -endif -endif -endif -endif -endif - -LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2) - -ifdef DEF_FILE - - -ifdef IS_MINGW -SHARED_EXT=.dll -LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC) -else -SHARED_EXT=.so -LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC) -CC_SHARED=-fPIC -endif - - -else - -LDFLAGS = $(LDFLAGS_STATIC) -# -s is not required for clang, do we need it for GGC ??? -# -s - -#-static -static-libgcc -static-libstdc++ - -ifdef IS_MINGW -SHARED_EXT=.exe -else -SHARED_EXT= -endif - -endif - - -PROGPATH = $(O)/$(PROG)$(SHARED_EXT) -PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT) - -ifndef O -O=_o -endif - -ifdef IS_MINGW - -ifdef MSYSTEM -RM = rm -f -MY_MKDIR=mkdir -p -DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) -else -RM = del -MY_MKDIR=mkdir -DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll -endif - - -LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32 -lShell32 - -CFLAGS_EXTRA = -DUNICODE -D_UNICODE -# -Wno-delete-non-virtual-dtor - - -else - -RM = rm -f -MY_MKDIR=mkdir -p -# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST -# CFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE - -# LOCAL_LIBS=-lpthread -# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl -LIB2 = -lpthread -ldl - -DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) - -endif - - -ifdef IS_X64 -AFLAGS_ABI = -elf64 -DABI_LINUX -else -AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL -# -DABI_CDECL -# -DABI_LINUX -# -DABI_CDECL -endif -AFLAGS = $(AFLAGS_ABI) -Fo$(O)/ - -C_WARN_FLAGS = - -CFLAGS = $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CFLAGS_EXTRA) $(C_WARN_FLAGS) $(FLAGS_FLTO) $(CC_SHARED) -o $@ - -STATIC_TARGET= -ifdef COMPL_STATIC -STATIC_TARGET=$(PROGPATH_STATIC) -endif - - -all: $(O) $(PROGPATH) $(STATIC_TARGET) - -$(O): - $(MY_MKDIR) $(O) - -ifneq ($(CC), $(CROSS_COMPILE)clang) -LFLAGS_STRIP = -s -endif - -LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(OBJS) $(MY_LIBS) $(LIB2) -$(PROGPATH): $(OBJS) - $(CC) -o $(PROGPATH) $(LFLAGS_ALL) - -$(PROGPATH_STATIC): $(OBJS) - $(CC) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL) - - -ifndef NO_DEFAULT_RES -# old mingw without -FO -# windres.exe $(RFLAGS) resource.rc $O/resource.o -$O/resource.o: resource.rc - $(RC) $(RFLAGS) resource.rc $(O)/resource.o -endif -# windres.exe $(RFLAGS) resource.rc $(O)\resource.o -# windres.exe $(RFLAGS) resource.rc -FO $(O)/resource.o -# $(RC) $(RFLAGS) resource.rc -FO $(O)/resource.o - - - -$O/7zAlloc.o: ../../../C/7zAlloc.c - $(CC) $(CFLAGS) $< -$O/7zArcIn.o: ../../../C/7zArcIn.c - $(CC) $(CFLAGS) $< -$O/7zBuf.o: ../../../C/7zBuf.c - $(CC) $(CFLAGS) $< -$O/7zBuf2.o: ../../../C/7zBuf2.c - $(CC) $(CFLAGS) $< -$O/7zCrc.o: ../../../C/7zCrc.c - $(CC) $(CFLAGS) $< -$O/7zDec.o: ../../../C/7zDec.c - $(CC) $(CFLAGS) $< -$O/7zFile.o: ../../../C/7zFile.c - $(CC) $(CFLAGS) $< -$O/7zStream.o: ../../../C/7zStream.c - $(CC) $(CFLAGS) $< -$O/Aes.o: ../../../C/Aes.c - $(CC) $(CFLAGS) $< -$O/Alloc.o: ../../../C/Alloc.c - $(CC) $(CFLAGS) $< -$O/Bcj2.o: ../../../C/Bcj2.c - $(CC) $(CFLAGS) $< -$O/Bcj2Enc.o: ../../../C/Bcj2Enc.c - $(CC) $(CFLAGS) $< -$O/Blake2s.o: ../../../C/Blake2s.c - $(CC) $(CFLAGS) $< -$O/Bra.o: ../../../C/Bra.c - $(CC) $(CFLAGS) $< -$O/Bra86.o: ../../../C/Bra86.c - $(CC) $(CFLAGS) $< -$O/BraIA64.o: ../../../C/BraIA64.c - $(CC) $(CFLAGS) $< -$O/BwtSort.o: ../../../C/BwtSort.c - $(CC) $(CFLAGS) $< - -$O/CpuArch.o: ../../../C/CpuArch.c - $(CC) $(CFLAGS) $< -$O/Delta.o: ../../../C/Delta.c - $(CC) $(CFLAGS) $< -$O/DllSecur.o: ../../../C/DllSecur.c - $(CC) $(CFLAGS) $< -$O/HuffEnc.o: ../../../C/HuffEnc.c - $(CC) $(CFLAGS) $< -$O/LzFind.o: ../../../C/LzFind.c - $(CC) $(CFLAGS) $< - -# ifdef MT_FILES -$O/LzFindMt.o: ../../../C/LzFindMt.c - $(CC) $(CFLAGS) $< -$O/LzFindOpt.o: ../../../C/LzFindOpt.c - $(CC) $(CFLAGS) $< - -$O/Threads.o: ../../../C/Threads.c - $(CC) $(CFLAGS) $< -# endif - -$O/LzmaEnc.o: ../../../C/LzmaEnc.c - $(CC) $(CFLAGS) $< -$O/Lzma86Dec.o: ../../../C/Lzma86Dec.c - $(CC) $(CFLAGS) $< -$O/Lzma86Enc.o: ../../../C/Lzma86Enc.c - $(CC) $(CFLAGS) $< -$O/Lzma2Dec.o: ../../../C/Lzma2Dec.c - $(CC) $(CFLAGS) $< -$O/Lzma2DecMt.o: ../../../C/Lzma2DecMt.c - $(CC) $(CFLAGS) $< -$O/Lzma2Enc.o: ../../../C/Lzma2Enc.c - $(CC) $(CFLAGS) $< -$O/LzmaLib.o: ../../../C/LzmaLib.c - $(CC) $(CFLAGS) $< -$O/MtCoder.o: ../../../C/MtCoder.c - $(CC) $(CFLAGS) $< -$O/MtDec.o: ../../../C/MtDec.c - $(CC) $(CFLAGS) $< -$O/Ppmd7.o: ../../../C/Ppmd7.c - $(CC) $(CFLAGS) $< -$O/Ppmd7aDec.o: ../../../C/Ppmd7aDec.c - $(CC) $(CFLAGS) $< -$O/Ppmd7Dec.o: ../../../C/Ppmd7Dec.c - $(CC) $(CFLAGS) $< -$O/Ppmd7Enc.o: ../../../C/Ppmd7Enc.c - $(CC) $(CFLAGS) $< -$O/Ppmd8.o: ../../../C/Ppmd8.c - $(CC) $(CFLAGS) $< -$O/Ppmd8Dec.o: ../../../C/Ppmd8Dec.c - $(CC) $(CFLAGS) $< -$O/Ppmd8Enc.o: ../../../C/Ppmd8Enc.c - $(CC) $(CFLAGS) $< -$O/Sha1.o: ../../../C/Sha1.c - $(CC) $(CFLAGS) $< -$O/Sha256.o: ../../../C/Sha256.c - $(CC) $(CFLAGS) $< -$O/Sort.o: ../../../C/Sort.c - $(CC) $(CFLAGS) $< -$O/SwapBytes.o: ../../../C/SwapBytes.c - $(CC) $(CFLAGS) $< -$O/Xz.o: ../../../C/Xz.c - $(CC) $(CFLAGS) $< -$O/XzCrc64.o: ../../../C/XzCrc64.c - $(CC) $(CFLAGS) $< -$O/XzDec.o: ../../../C/XzDec.c - $(CC) $(CFLAGS) $< -$O/XzEnc.o: ../../../C/XzEnc.c - $(CC) $(CFLAGS) $< -$O/XzIn.o: ../../../C/XzIn.c - $(CC) $(CFLAGS) $< - - -ifdef USE_ASM -ifdef IS_X64 -USE_X86_ASM=1 -else -ifdef IS_X86 -USE_X86_ASM=1 -endif -endif -endif - -ifdef USE_X86_ASM -$O/7zCrcOpt.o: ../../../Asm/x86/7zCrcOpt.asm - $(MY_ASM) $(AFLAGS) $< -$O/XzCrc64Opt.o: ../../../Asm/x86/XzCrc64Opt.asm - $(MY_ASM) $(AFLAGS) $< -$O/AesOpt.o: ../../../Asm/x86/AesOpt.asm - $(MY_ASM) $(AFLAGS) $< -$O/Sha1Opt.o: ../../../Asm/x86/Sha1Opt.asm - $(MY_ASM) $(AFLAGS) $< -$O/Sha256Opt.o: ../../../Asm/x86/Sha256Opt.asm - $(MY_ASM) $(AFLAGS) $< -else -$O/7zCrcOpt.o: ../../7zCrcOpt.c - $(CC) $(CFLAGS) $< -$O/XzCrc64Opt.o: ../../XzCrc64Opt.c - $(CC) $(CFLAGS) $< -$O/Sha1Opt.o: ../../Sha1Opt.c - $(CC) $(CFLAGS) $< -$O/Sha256Opt.o: ../../Sha256Opt.c - $(CC) $(CFLAGS) $< -$O/AesOpt.o: ../../AesOpt.c - $(CC) $(CFLAGS) $< -endif - - -ifdef USE_LZMA_DEC_ASM - -ifdef IS_X64 -$O/LzmaDecOpt.o: ../../../Asm/x86/LzmaDecOpt.asm - $(MY_ASM) $(AFLAGS) $< -endif - -ifdef IS_ARM64 -$O/LzmaDecOpt.o: ../../../Asm/arm64/LzmaDecOpt.S ../../../Asm/arm64/7zAsm.S - $(CC) $(CFLAGS) $(ASM_FLAGS) $< -endif - -$O/LzmaDec.o: ../../LzmaDec.c - $(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $< - -else - -$O/LzmaDec.o: ../../LzmaDec.c - $(CC) $(CFLAGS) $< - -endif - - - -$O/7zMain.o: ../../../C/Util/7z/7zMain.c - $(CC) $(CFLAGS) $< -$O/7zipInstall.o: ../../../C/Util/7zipInstall/7zipInstall.c - $(CC) $(CFLAGS) $< -$O/7zipUninstall.o: ../../../C/Util/7zipUninstall/7zipUninstall.c - $(CC) $(CFLAGS) $< -$O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c - $(CC) $(CFLAGS) $< -$O/XzUtil.o: ../../../C/Util/Xz/XzUtil.c - $(CC) $(CFLAGS) $< - - -clean: - -$(DEL_OBJ_EXE) + +MY_ARCH_2 = $(MY_ARCH) + +MY_ASM = jwasm +MY_ASM = asmc + +ifndef RC +#RC=windres.exe --target=pe-x86-64 +#RC=windres.exe -F pe-i386 +RC=windres.exe +endif + +PROGPATH = $(O)/$(PROG) +PROGPATH_STATIC = $(O)/$(PROG)s + +ifneq ($(CC), xlc) +CFLAGS_WARN_WALL = -Wall -Werror -Wextra +endif + +# for object file +CFLAGS_BASE_LIST = -c +# for ASM file +# CFLAGS_BASE_LIST = -S + +FLAGS_FLTO = -flto +FLAGS_FLTO = + +CFLAGS_BASE = $(MY_ARCH_2) -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \ + -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef IS_MINGW +LDFLAGS_STATIC_2 = -static +else +ifndef DEF_FILE +ifndef IS_NOT_STANDALONE +ifndef MY_DYNAMIC_LINK +ifneq ($(CC), clang) +LDFLAGS_STATIC_2 = +# -static +# -static-libstdc++ -static-libgcc +endif +endif +endif +endif +endif + +LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2) + +ifdef DEF_FILE + + +ifdef IS_MINGW +SHARED_EXT=.dll +LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC) +else +SHARED_EXT=.so +LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC) +CC_SHARED=-fPIC +endif + + +else + +LDFLAGS = $(LDFLAGS_STATIC) +# -s is not required for clang, do we need it for GGC ??? +# -s + +#-static -static-libgcc -static-libstdc++ + +ifdef IS_MINGW +SHARED_EXT=.exe +else +SHARED_EXT= +endif + +endif + + +PROGPATH = $(O)/$(PROG)$(SHARED_EXT) +PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT) + +ifndef O +O=_o +endif + +ifdef IS_MINGW + +ifdef MSYSTEM +RM = rm -f +MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) +else +RM = del +MY_MKDIR=mkdir +DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll +endif + + +LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32 -lShell32 + +CFLAGS_EXTRA = -DUNICODE -D_UNICODE +# -Wno-delete-non-virtual-dtor + + +else + +RM = rm -f +MY_MKDIR=mkdir -p +# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST +# CFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + +# LOCAL_LIBS=-lpthread +# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl +LIB2 = -lpthread -ldl + +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) + +endif + + +ifdef IS_X64 +AFLAGS_ABI = -elf64 -DABI_LINUX +else +AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL +# -DABI_CDECL +# -DABI_LINUX +# -DABI_CDECL +endif +AFLAGS = $(AFLAGS_ABI) -Fo$(O)/ + +C_WARN_FLAGS = + +CFLAGS = $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CFLAGS_EXTRA) $(C_WARN_FLAGS) $(FLAGS_FLTO) $(CC_SHARED) -o $@ + +STATIC_TARGET= +ifdef COMPL_STATIC +STATIC_TARGET=$(PROGPATH_STATIC) +endif + + +all: $(O) $(PROGPATH) $(STATIC_TARGET) + +$(O): + $(MY_MKDIR) $(O) + +ifneq ($(CC), $(CROSS_COMPILE)clang) +LFLAGS_STRIP = -s +endif + +LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(OBJS) $(MY_LIBS) $(LIB2) +$(PROGPATH): $(OBJS) + $(CC) -o $(PROGPATH) $(LFLAGS_ALL) + +$(PROGPATH_STATIC): $(OBJS) + $(CC) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL) + + +ifndef NO_DEFAULT_RES +# old mingw without -FO +# windres.exe $(RFLAGS) resource.rc $O/resource.o +$O/resource.o: resource.rc + $(RC) $(RFLAGS) resource.rc $(O)/resource.o +endif +# windres.exe $(RFLAGS) resource.rc $(O)\resource.o +# windres.exe $(RFLAGS) resource.rc -FO $(O)/resource.o +# $(RC) $(RFLAGS) resource.rc -FO $(O)/resource.o + + + +$O/7zAlloc.o: ../../../C/7zAlloc.c + $(CC) $(CFLAGS) $< +$O/7zArcIn.o: ../../../C/7zArcIn.c + $(CC) $(CFLAGS) $< +$O/7zBuf.o: ../../../C/7zBuf.c + $(CC) $(CFLAGS) $< +$O/7zBuf2.o: ../../../C/7zBuf2.c + $(CC) $(CFLAGS) $< +$O/7zCrc.o: ../../../C/7zCrc.c + $(CC) $(CFLAGS) $< +$O/7zDec.o: ../../../C/7zDec.c + $(CC) $(CFLAGS) $< +$O/7zFile.o: ../../../C/7zFile.c + $(CC) $(CFLAGS) $< +$O/7zStream.o: ../../../C/7zStream.c + $(CC) $(CFLAGS) $< +$O/Aes.o: ../../../C/Aes.c + $(CC) $(CFLAGS) $< +$O/Alloc.o: ../../../C/Alloc.c + $(CC) $(CFLAGS) $< +$O/Bcj2.o: ../../../C/Bcj2.c + $(CC) $(CFLAGS) $< +$O/Bcj2Enc.o: ../../../C/Bcj2Enc.c + $(CC) $(CFLAGS) $< +$O/Blake2s.o: ../../../C/Blake2s.c + $(CC) $(CFLAGS) $< +$O/Bra.o: ../../../C/Bra.c + $(CC) $(CFLAGS) $< +$O/Bra86.o: ../../../C/Bra86.c + $(CC) $(CFLAGS) $< +$O/BraIA64.o: ../../../C/BraIA64.c + $(CC) $(CFLAGS) $< +$O/BwtSort.o: ../../../C/BwtSort.c + $(CC) $(CFLAGS) $< + +$O/CpuArch.o: ../../../C/CpuArch.c + $(CC) $(CFLAGS) $< +$O/Delta.o: ../../../C/Delta.c + $(CC) $(CFLAGS) $< +$O/DllSecur.o: ../../../C/DllSecur.c + $(CC) $(CFLAGS) $< +$O/HuffEnc.o: ../../../C/HuffEnc.c + $(CC) $(CFLAGS) $< +$O/LzFind.o: ../../../C/LzFind.c + $(CC) $(CFLAGS) $< + +# ifdef MT_FILES +$O/LzFindMt.o: ../../../C/LzFindMt.c + $(CC) $(CFLAGS) $< +$O/LzFindOpt.o: ../../../C/LzFindOpt.c + $(CC) $(CFLAGS) $< + +$O/Threads.o: ../../../C/Threads.c + $(CC) $(CFLAGS) $< +# endif + +$O/LzmaEnc.o: ../../../C/LzmaEnc.c + $(CC) $(CFLAGS) $< +$O/Lzma86Dec.o: ../../../C/Lzma86Dec.c + $(CC) $(CFLAGS) $< +$O/Lzma86Enc.o: ../../../C/Lzma86Enc.c + $(CC) $(CFLAGS) $< +$O/Lzma2Dec.o: ../../../C/Lzma2Dec.c + $(CC) $(CFLAGS) $< +$O/Lzma2DecMt.o: ../../../C/Lzma2DecMt.c + $(CC) $(CFLAGS) $< +$O/Lzma2Enc.o: ../../../C/Lzma2Enc.c + $(CC) $(CFLAGS) $< +$O/LzmaLib.o: ../../../C/LzmaLib.c + $(CC) $(CFLAGS) $< +$O/MtCoder.o: ../../../C/MtCoder.c + $(CC) $(CFLAGS) $< +$O/MtDec.o: ../../../C/MtDec.c + $(CC) $(CFLAGS) $< +$O/Ppmd7.o: ../../../C/Ppmd7.c + $(CC) $(CFLAGS) $< +$O/Ppmd7aDec.o: ../../../C/Ppmd7aDec.c + $(CC) $(CFLAGS) $< +$O/Ppmd7Dec.o: ../../../C/Ppmd7Dec.c + $(CC) $(CFLAGS) $< +$O/Ppmd7Enc.o: ../../../C/Ppmd7Enc.c + $(CC) $(CFLAGS) $< +$O/Ppmd8.o: ../../../C/Ppmd8.c + $(CC) $(CFLAGS) $< +$O/Ppmd8Dec.o: ../../../C/Ppmd8Dec.c + $(CC) $(CFLAGS) $< +$O/Ppmd8Enc.o: ../../../C/Ppmd8Enc.c + $(CC) $(CFLAGS) $< +$O/Sha1.o: ../../../C/Sha1.c + $(CC) $(CFLAGS) $< +$O/Sha256.o: ../../../C/Sha256.c + $(CC) $(CFLAGS) $< +$O/Sort.o: ../../../C/Sort.c + $(CC) $(CFLAGS) $< +$O/SwapBytes.o: ../../../C/SwapBytes.c + $(CC) $(CFLAGS) $< +$O/Xz.o: ../../../C/Xz.c + $(CC) $(CFLAGS) $< +$O/XzCrc64.o: ../../../C/XzCrc64.c + $(CC) $(CFLAGS) $< +$O/XzDec.o: ../../../C/XzDec.c + $(CC) $(CFLAGS) $< +$O/XzEnc.o: ../../../C/XzEnc.c + $(CC) $(CFLAGS) $< +$O/XzIn.o: ../../../C/XzIn.c + $(CC) $(CFLAGS) $< + + +ifdef USE_ASM +ifdef IS_X64 +USE_X86_ASM=1 +else +ifdef IS_X86 +USE_X86_ASM=1 +endif +endif +endif + +ifdef USE_X86_ASM +$O/7zCrcOpt.o: ../../../Asm/x86/7zCrcOpt.asm + $(MY_ASM) $(AFLAGS) $< +$O/XzCrc64Opt.o: ../../../Asm/x86/XzCrc64Opt.asm + $(MY_ASM) $(AFLAGS) $< +$O/AesOpt.o: ../../../Asm/x86/AesOpt.asm + $(MY_ASM) $(AFLAGS) $< +$O/Sha1Opt.o: ../../../Asm/x86/Sha1Opt.asm + $(MY_ASM) $(AFLAGS) $< +$O/Sha256Opt.o: ../../../Asm/x86/Sha256Opt.asm + $(MY_ASM) $(AFLAGS) $< +else +$O/7zCrcOpt.o: ../../7zCrcOpt.c + $(CC) $(CFLAGS) $< +$O/XzCrc64Opt.o: ../../XzCrc64Opt.c + $(CC) $(CFLAGS) $< +$O/Sha1Opt.o: ../../Sha1Opt.c + $(CC) $(CFLAGS) $< +$O/Sha256Opt.o: ../../Sha256Opt.c + $(CC) $(CFLAGS) $< +$O/AesOpt.o: ../../AesOpt.c + $(CC) $(CFLAGS) $< +endif + + +ifdef USE_LZMA_DEC_ASM + +ifdef IS_X64 +$O/LzmaDecOpt.o: ../../../Asm/x86/LzmaDecOpt.asm + $(MY_ASM) $(AFLAGS) $< +endif + +ifdef IS_ARM64 +$O/LzmaDecOpt.o: ../../../Asm/arm64/LzmaDecOpt.S ../../../Asm/arm64/7zAsm.S + $(CC) $(CFLAGS) $(ASM_FLAGS) $< +endif + +$O/LzmaDec.o: ../../LzmaDec.c + $(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $< + +else + +$O/LzmaDec.o: ../../LzmaDec.c + $(CC) $(CFLAGS) $< + +endif + + + +$O/7zMain.o: ../../../C/Util/7z/7zMain.c + $(CC) $(CFLAGS) $< +$O/7zipInstall.o: ../../../C/Util/7zipInstall/7zipInstall.c + $(CC) $(CFLAGS) $< +$O/7zipUninstall.o: ../../../C/Util/7zipUninstall/7zipUninstall.c + $(CC) $(CFLAGS) $< +$O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c + $(CC) $(CFLAGS) $< +$O/XzUtil.o: ../../../C/Util/Xz/XzUtil.c + $(CC) $(CFLAGS) $< + + +clean: + -$(DEL_OBJ_EXE) diff --git a/C/Aes.c b/C/Aes.c index fc2c492d3..abc5d24b4 100644 --- a/C/Aes.c +++ b/C/Aes.c @@ -1,429 +1,429 @@ -/* Aes.c -- AES encryption / decryption -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "CpuArch.h" -#include "Aes.h" - -AES_CODE_FUNC g_AesCbc_Decode; -#ifndef Z7_SFX -AES_CODE_FUNC g_AesCbc_Encode; -AES_CODE_FUNC g_AesCtr_Code; -UInt32 g_Aes_SupportedFunctions_Flags; -#endif - -MY_ALIGN(64) -static UInt32 T[256 * 4]; -MY_ALIGN(64) -static const Byte Sbox[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; - - -MY_ALIGN(64) -static UInt32 D[256 * 4]; -MY_ALIGN(64) -static Byte InvS[256]; - -#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF) - -#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24)) - -#define gb0(x) ( (x) & 0xFF) -#define gb1(x) (((x) >> ( 8)) & 0xFF) -#define gb2(x) (((x) >> (16)) & 0xFF) -#define gb3(x) (((x) >> (24))) - -#define gb(n, x) gb ## n(x) - -#define TT(x) (T + (x << 8)) -#define DD(x) (D + (x << 8)) - - -// #define Z7_SHOW_AES_STATUS - -#ifdef MY_CPU_X86_OR_AMD64 - - #if defined(__INTEL_COMPILER) - #if (__INTEL_COMPILER >= 1110) - #define USE_HW_AES - #if (__INTEL_COMPILER >= 1900) - #define USE_HW_VAES - #endif - #endif - #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) - #define USE_HW_AES - #if defined(__clang__) && (__clang_major__ >= 8) \ - || defined(__GNUC__) && (__GNUC__ >= 8) - #define USE_HW_VAES - #endif - #elif defined(_MSC_VER) - #define USE_HW_AES - #define USE_HW_VAES - #endif - -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) - - #if defined(__ARM_FEATURE_AES) \ - || defined(__ARM_FEATURE_CRYPTO) - #define USE_HW_AES - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define USE_HW_AES - #endif - #endif - #endif - #endif -#endif - -#ifdef USE_HW_AES -// #pragma message("=== Aes.c USE_HW_AES === ") -#ifdef Z7_SHOW_AES_STATUS -#include -#define PRF(x) x -#else -#define PRF(x) -#endif -#endif - - -void AesGenTables(void) -{ - unsigned i; - for (i = 0; i < 256; i++) - InvS[Sbox[i]] = (Byte)i; - - for (i = 0; i < 256; i++) - { - { - const UInt32 a1 = Sbox[i]; - const UInt32 a2 = xtime(a1); - const UInt32 a3 = a2 ^ a1; - TT(0)[i] = Ui32(a2, a1, a1, a3); - TT(1)[i] = Ui32(a3, a2, a1, a1); - TT(2)[i] = Ui32(a1, a3, a2, a1); - TT(3)[i] = Ui32(a1, a1, a3, a2); - } - { - const UInt32 a1 = InvS[i]; - const UInt32 a2 = xtime(a1); - const UInt32 a4 = xtime(a2); - const UInt32 a8 = xtime(a4); - const UInt32 a9 = a8 ^ a1; - const UInt32 aB = a8 ^ a2 ^ a1; - const UInt32 aD = a8 ^ a4 ^ a1; - const UInt32 aE = a8 ^ a4 ^ a2; - DD(0)[i] = Ui32(aE, a9, aD, aB); - DD(1)[i] = Ui32(aB, aE, a9, aD); - DD(2)[i] = Ui32(aD, aB, aE, a9); - DD(3)[i] = Ui32(a9, aD, aB, aE); - } - } - - { - AES_CODE_FUNC d = AesCbc_Decode; - #ifndef Z7_SFX - AES_CODE_FUNC e = AesCbc_Encode; - AES_CODE_FUNC c = AesCtr_Code; - UInt32 flags = 0; - #endif - - #ifdef USE_HW_AES - if (CPU_IsSupported_AES()) - { - // #pragma message ("AES HW") - PRF(printf("\n===AES HW\n")); - d = AesCbc_Decode_HW; - - #ifndef Z7_SFX - e = AesCbc_Encode_HW; - c = AesCtr_Code_HW; - flags = k_Aes_SupportedFunctions_HW; - #endif - - #ifdef MY_CPU_X86_OR_AMD64 - #ifdef USE_HW_VAES - if (CPU_IsSupported_VAES_AVX2()) - { - PRF(printf("\n===vaes avx2\n")); - d = AesCbc_Decode_HW_256; - #ifndef Z7_SFX - c = AesCtr_Code_HW_256; - flags |= k_Aes_SupportedFunctions_HW_256; - #endif - } - #endif - #endif - } - #endif - - g_AesCbc_Decode = d; - #ifndef Z7_SFX - g_AesCbc_Encode = e; - g_AesCtr_Code = c; - g_Aes_SupportedFunctions_Flags = flags; - #endif - } -} - - -#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])] - -#define HT4(m, i, s, p) m[i] = \ - HT(i, 0, s) ^ \ - HT(i, 1, s) ^ \ - HT(i, 2, s) ^ \ - HT(i, 3, s) ^ w[p + i] - -#define HT16(m, s, p) \ - HT4(m, 0, s, p); \ - HT4(m, 1, s, p); \ - HT4(m, 2, s, p); \ - HT4(m, 3, s, p); \ - -#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])] -#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i]; - - -#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])] - -#define HD4(m, i, s, p) m[i] = \ - HD(i, 0, s) ^ \ - HD(i, 1, s) ^ \ - HD(i, 2, s) ^ \ - HD(i, 3, s) ^ w[p + i]; - -#define HD16(m, s, p) \ - HD4(m, 0, s, p); \ - HD4(m, 1, s, p); \ - HD4(m, 2, s, p); \ - HD4(m, 3, s, p); \ - -#define FD(i, x) InvS[gb(x, m[(i - x) & 3])] -#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i]; - -void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize) -{ - unsigned i, m; - const UInt32 *wLim; - UInt32 t; - UInt32 rcon = 1; - - keySize /= 4; - w[0] = ((UInt32)keySize / 2) + 3; - w += 4; - - for (i = 0; i < keySize; i++, key += 4) - w[i] = GetUi32(key); - - t = w[(size_t)keySize - 1]; - wLim = w + (size_t)keySize * 3 + 28; - m = 0; - do - { - if (m == 0) - { - t = Ui32(Sbox[gb1(t)] ^ rcon, Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]); - rcon <<= 1; - if (rcon & 0x100) - rcon = 0x1b; - m = keySize; - } - else if (m == 4 && keySize > 6) - t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]); - m--; - t ^= w[0]; - w[keySize] = t; - } - while (++w != wLim); -} - -void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize) -{ - unsigned i, num; - Aes_SetKey_Enc(w, key, keySize); - num = keySize + 20; - w += 8; - for (i = 0; i < num; i++) - { - UInt32 r = w[i]; - w[i] = - DD(0)[Sbox[gb0(r)]] ^ - DD(1)[Sbox[gb1(r)]] ^ - DD(2)[Sbox[gb2(r)]] ^ - DD(3)[Sbox[gb3(r)]]; - } -} - -/* Aes_Encode and Aes_Decode functions work with little-endian words. - src and dest are pointers to 4 UInt32 words. - src and dest can point to same block */ - -// Z7_FORCE_INLINE -static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src) -{ - UInt32 s[4]; - UInt32 m[4]; - UInt32 numRounds2 = w[0]; - w += 4; - s[0] = src[0] ^ w[0]; - s[1] = src[1] ^ w[1]; - s[2] = src[2] ^ w[2]; - s[3] = src[3] ^ w[3]; - w += 4; - for (;;) - { - HT16(m, s, 0) - if (--numRounds2 == 0) - break; - HT16(s, m, 4) - w += 8; - } - w += 4; - FT4(0) - FT4(1) - FT4(2) - FT4(3) -} - -Z7_FORCE_INLINE -static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src) -{ - UInt32 s[4]; - UInt32 m[4]; - UInt32 numRounds2 = w[0]; - w += 4 + numRounds2 * 8; - s[0] = src[0] ^ w[0]; - s[1] = src[1] ^ w[1]; - s[2] = src[2] ^ w[2]; - s[3] = src[3] ^ w[3]; - for (;;) - { - w -= 8; - HD16(m, s, 4) - if (--numRounds2 == 0) - break; - HD16(s, m, 0) - } - FD4(0) - FD4(1) - FD4(2) - FD4(3) -} - -void AesCbc_Init(UInt32 *p, const Byte *iv) -{ - unsigned i; - for (i = 0; i < 4; i++) - p[i] = GetUi32(iv + i * 4); -} - -void Z7_FASTCALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks) -{ - for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) - { - p[0] ^= GetUi32(data); - p[1] ^= GetUi32(data + 4); - p[2] ^= GetUi32(data + 8); - p[3] ^= GetUi32(data + 12); - - Aes_Encode(p + 4, p, p); - - SetUi32(data, p[0]) - SetUi32(data + 4, p[1]) - SetUi32(data + 8, p[2]) - SetUi32(data + 12, p[3]) - } -} - -void Z7_FASTCALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks) -{ - UInt32 in[4], out[4]; - for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) - { - in[0] = GetUi32(data); - in[1] = GetUi32(data + 4); - in[2] = GetUi32(data + 8); - in[3] = GetUi32(data + 12); - - Aes_Decode(p + 4, out, in); - - SetUi32(data, p[0] ^ out[0]) - SetUi32(data + 4, p[1] ^ out[1]) - SetUi32(data + 8, p[2] ^ out[2]) - SetUi32(data + 12, p[3] ^ out[3]) - - p[0] = in[0]; - p[1] = in[1]; - p[2] = in[2]; - p[3] = in[3]; - } -} - -void Z7_FASTCALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks) -{ - for (; numBlocks != 0; numBlocks--) - { - UInt32 temp[4]; - unsigned i; - - if (++p[0] == 0) - p[1]++; - - Aes_Encode(p + 4, temp, p); - - for (i = 0; i < 4; i++, data += 4) - { - const UInt32 t = temp[i]; - - #ifdef MY_CPU_LE_UNALIGN - *((UInt32 *)(void *)data) ^= t; - #else - data[0] = (Byte)(data[0] ^ (t & 0xFF)); - data[1] = (Byte)(data[1] ^ ((t >> 8) & 0xFF)); - data[2] = (Byte)(data[2] ^ ((t >> 16) & 0xFF)); - data[3] = (Byte)(data[3] ^ ((t >> 24))); - #endif - } - } -} - -#undef xtime -#undef Ui32 -#undef gb0 -#undef gb1 -#undef gb2 -#undef gb3 -#undef gb -#undef TT -#undef DD -#undef USE_HW_AES -#undef PRF +/* Aes.c -- AES encryption / decryption +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "Aes.h" + +AES_CODE_FUNC g_AesCbc_Decode; +#ifndef Z7_SFX +AES_CODE_FUNC g_AesCbc_Encode; +AES_CODE_FUNC g_AesCtr_Code; +UInt32 g_Aes_SupportedFunctions_Flags; +#endif + +MY_ALIGN(64) +static UInt32 T[256 * 4]; +MY_ALIGN(64) +static const Byte Sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + + +MY_ALIGN(64) +static UInt32 D[256 * 4]; +MY_ALIGN(64) +static Byte InvS[256]; + +#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF) + +#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24)) + +#define gb0(x) ( (x) & 0xFF) +#define gb1(x) (((x) >> ( 8)) & 0xFF) +#define gb2(x) (((x) >> (16)) & 0xFF) +#define gb3(x) (((x) >> (24))) + +#define gb(n, x) gb ## n(x) + +#define TT(x) (T + (x << 8)) +#define DD(x) (D + (x << 8)) + + +// #define Z7_SHOW_AES_STATUS + +#ifdef MY_CPU_X86_OR_AMD64 + + #if defined(__INTEL_COMPILER) + #if (__INTEL_COMPILER >= 1110) + #define USE_HW_AES + #if (__INTEL_COMPILER >= 1900) + #define USE_HW_VAES + #endif + #endif + #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) + #define USE_HW_AES + #if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 8) + #define USE_HW_VAES + #endif + #elif defined(_MSC_VER) + #define USE_HW_AES + #define USE_HW_VAES + #endif + +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) + + #if defined(__ARM_FEATURE_AES) \ + || defined(__ARM_FEATURE_CRYPTO) + #define USE_HW_AES + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define USE_HW_AES + #endif + #endif + #endif + #endif +#endif + +#ifdef USE_HW_AES +// #pragma message("=== Aes.c USE_HW_AES === ") +#ifdef Z7_SHOW_AES_STATUS +#include +#define PRF(x) x +#else +#define PRF(x) +#endif +#endif + + +void AesGenTables(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + InvS[Sbox[i]] = (Byte)i; + + for (i = 0; i < 256; i++) + { + { + const UInt32 a1 = Sbox[i]; + const UInt32 a2 = xtime(a1); + const UInt32 a3 = a2 ^ a1; + TT(0)[i] = Ui32(a2, a1, a1, a3); + TT(1)[i] = Ui32(a3, a2, a1, a1); + TT(2)[i] = Ui32(a1, a3, a2, a1); + TT(3)[i] = Ui32(a1, a1, a3, a2); + } + { + const UInt32 a1 = InvS[i]; + const UInt32 a2 = xtime(a1); + const UInt32 a4 = xtime(a2); + const UInt32 a8 = xtime(a4); + const UInt32 a9 = a8 ^ a1; + const UInt32 aB = a8 ^ a2 ^ a1; + const UInt32 aD = a8 ^ a4 ^ a1; + const UInt32 aE = a8 ^ a4 ^ a2; + DD(0)[i] = Ui32(aE, a9, aD, aB); + DD(1)[i] = Ui32(aB, aE, a9, aD); + DD(2)[i] = Ui32(aD, aB, aE, a9); + DD(3)[i] = Ui32(a9, aD, aB, aE); + } + } + + { + AES_CODE_FUNC d = AesCbc_Decode; + #ifndef Z7_SFX + AES_CODE_FUNC e = AesCbc_Encode; + AES_CODE_FUNC c = AesCtr_Code; + UInt32 flags = 0; + #endif + + #ifdef USE_HW_AES + if (CPU_IsSupported_AES()) + { + // #pragma message ("AES HW") + PRF(printf("\n===AES HW\n")); + d = AesCbc_Decode_HW; + + #ifndef Z7_SFX + e = AesCbc_Encode_HW; + c = AesCtr_Code_HW; + flags = k_Aes_SupportedFunctions_HW; + #endif + + #ifdef MY_CPU_X86_OR_AMD64 + #ifdef USE_HW_VAES + if (CPU_IsSupported_VAES_AVX2()) + { + PRF(printf("\n===vaes avx2\n")); + d = AesCbc_Decode_HW_256; + #ifndef Z7_SFX + c = AesCtr_Code_HW_256; + flags |= k_Aes_SupportedFunctions_HW_256; + #endif + } + #endif + #endif + } + #endif + + g_AesCbc_Decode = d; + #ifndef Z7_SFX + g_AesCbc_Encode = e; + g_AesCtr_Code = c; + g_Aes_SupportedFunctions_Flags = flags; + #endif + } +} + + +#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])] + +#define HT4(m, i, s, p) m[i] = \ + HT(i, 0, s) ^ \ + HT(i, 1, s) ^ \ + HT(i, 2, s) ^ \ + HT(i, 3, s) ^ w[p + i] + +#define HT16(m, s, p) \ + HT4(m, 0, s, p); \ + HT4(m, 1, s, p); \ + HT4(m, 2, s, p); \ + HT4(m, 3, s, p); \ + +#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])] +#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i]; + + +#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])] + +#define HD4(m, i, s, p) m[i] = \ + HD(i, 0, s) ^ \ + HD(i, 1, s) ^ \ + HD(i, 2, s) ^ \ + HD(i, 3, s) ^ w[p + i]; + +#define HD16(m, s, p) \ + HD4(m, 0, s, p); \ + HD4(m, 1, s, p); \ + HD4(m, 2, s, p); \ + HD4(m, 3, s, p); \ + +#define FD(i, x) InvS[gb(x, m[(i - x) & 3])] +#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i]; + +void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize) +{ + unsigned i, m; + const UInt32 *wLim; + UInt32 t; + UInt32 rcon = 1; + + keySize /= 4; + w[0] = ((UInt32)keySize / 2) + 3; + w += 4; + + for (i = 0; i < keySize; i++, key += 4) + w[i] = GetUi32(key); + + t = w[(size_t)keySize - 1]; + wLim = w + (size_t)keySize * 3 + 28; + m = 0; + do + { + if (m == 0) + { + t = Ui32(Sbox[gb1(t)] ^ rcon, Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]); + rcon <<= 1; + if (rcon & 0x100) + rcon = 0x1b; + m = keySize; + } + else if (m == 4 && keySize > 6) + t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]); + m--; + t ^= w[0]; + w[keySize] = t; + } + while (++w != wLim); +} + +void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize) +{ + unsigned i, num; + Aes_SetKey_Enc(w, key, keySize); + num = keySize + 20; + w += 8; + for (i = 0; i < num; i++) + { + UInt32 r = w[i]; + w[i] = + DD(0)[Sbox[gb0(r)]] ^ + DD(1)[Sbox[gb1(r)]] ^ + DD(2)[Sbox[gb2(r)]] ^ + DD(3)[Sbox[gb3(r)]]; + } +} + +/* Aes_Encode and Aes_Decode functions work with little-endian words. + src and dest are pointers to 4 UInt32 words. + src and dest can point to same block */ + +// Z7_FORCE_INLINE +static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src) +{ + UInt32 s[4]; + UInt32 m[4]; + UInt32 numRounds2 = w[0]; + w += 4; + s[0] = src[0] ^ w[0]; + s[1] = src[1] ^ w[1]; + s[2] = src[2] ^ w[2]; + s[3] = src[3] ^ w[3]; + w += 4; + for (;;) + { + HT16(m, s, 0) + if (--numRounds2 == 0) + break; + HT16(s, m, 4) + w += 8; + } + w += 4; + FT4(0) + FT4(1) + FT4(2) + FT4(3) +} + +Z7_FORCE_INLINE +static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src) +{ + UInt32 s[4]; + UInt32 m[4]; + UInt32 numRounds2 = w[0]; + w += 4 + numRounds2 * 8; + s[0] = src[0] ^ w[0]; + s[1] = src[1] ^ w[1]; + s[2] = src[2] ^ w[2]; + s[3] = src[3] ^ w[3]; + for (;;) + { + w -= 8; + HD16(m, s, 4) + if (--numRounds2 == 0) + break; + HD16(s, m, 0) + } + FD4(0) + FD4(1) + FD4(2) + FD4(3) +} + +void AesCbc_Init(UInt32 *p, const Byte *iv) +{ + unsigned i; + for (i = 0; i < 4; i++) + p[i] = GetUi32(iv + i * 4); +} + +void Z7_FASTCALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks) +{ + for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) + { + p[0] ^= GetUi32(data); + p[1] ^= GetUi32(data + 4); + p[2] ^= GetUi32(data + 8); + p[3] ^= GetUi32(data + 12); + + Aes_Encode(p + 4, p, p); + + SetUi32(data, p[0]) + SetUi32(data + 4, p[1]) + SetUi32(data + 8, p[2]) + SetUi32(data + 12, p[3]) + } +} + +void Z7_FASTCALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks) +{ + UInt32 in[4], out[4]; + for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE) + { + in[0] = GetUi32(data); + in[1] = GetUi32(data + 4); + in[2] = GetUi32(data + 8); + in[3] = GetUi32(data + 12); + + Aes_Decode(p + 4, out, in); + + SetUi32(data, p[0] ^ out[0]) + SetUi32(data + 4, p[1] ^ out[1]) + SetUi32(data + 8, p[2] ^ out[2]) + SetUi32(data + 12, p[3] ^ out[3]) + + p[0] = in[0]; + p[1] = in[1]; + p[2] = in[2]; + p[3] = in[3]; + } +} + +void Z7_FASTCALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks) +{ + for (; numBlocks != 0; numBlocks--) + { + UInt32 temp[4]; + unsigned i; + + if (++p[0] == 0) + p[1]++; + + Aes_Encode(p + 4, temp, p); + + for (i = 0; i < 4; i++, data += 4) + { + const UInt32 t = temp[i]; + + #ifdef MY_CPU_LE_UNALIGN + *((UInt32 *)(void *)data) ^= t; + #else + data[0] = (Byte)(data[0] ^ (t & 0xFF)); + data[1] = (Byte)(data[1] ^ ((t >> 8) & 0xFF)); + data[2] = (Byte)(data[2] ^ ((t >> 16) & 0xFF)); + data[3] = (Byte)(data[3] ^ ((t >> 24))); + #endif + } + } +} + +#undef xtime +#undef Ui32 +#undef gb0 +#undef gb1 +#undef gb2 +#undef gb3 +#undef gb +#undef TT +#undef DD +#undef USE_HW_AES +#undef PRF diff --git a/C/Aes.h b/C/Aes.h index 2373afb97..7f0182ac0 100644 --- a/C/Aes.h +++ b/C/Aes.h @@ -1,60 +1,60 @@ -/* Aes.h -- AES encryption / decryption -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_AES_H -#define ZIP7_INC_AES_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define AES_BLOCK_SIZE 16 - -/* Call AesGenTables one time before other AES functions */ -void AesGenTables(void); - -/* UInt32 pointers must be 16-byte aligned */ - -/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */ -#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4) - -/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */ -/* keySize = 16 or 24 or 32 (bytes) */ -typedef void (Z7_FASTCALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize); -void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize); -void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize); - -/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */ -void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */ - -/* data - 16-byte aligned pointer to data */ -/* numBlocks - the number of 16-byte blocks in data array */ -typedef void (Z7_FASTCALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks); - -extern AES_CODE_FUNC g_AesCbc_Decode; -#ifndef Z7_SFX -extern AES_CODE_FUNC g_AesCbc_Encode; -extern AES_CODE_FUNC g_AesCtr_Code; -#define k_Aes_SupportedFunctions_HW (1 << 2) -#define k_Aes_SupportedFunctions_HW_256 (1 << 3) -extern UInt32 g_Aes_SupportedFunctions_Flags; -#endif - - -#define Z7_DECLARE_AES_CODE_FUNC(funcName) \ - void Z7_FASTCALL funcName(UInt32 *ivAes, Byte *data, size_t numBlocks); - -Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode) -Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode) -Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code) - -Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode_HW) -Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW) -Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW) - -Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW_256) -Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW_256) - -EXTERN_C_END - -#endif +/* Aes.h -- AES encryption / decryption +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_AES_H +#define ZIP7_INC_AES_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define AES_BLOCK_SIZE 16 + +/* Call AesGenTables one time before other AES functions */ +void AesGenTables(void); + +/* UInt32 pointers must be 16-byte aligned */ + +/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */ +#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4) + +/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */ +/* keySize = 16 or 24 or 32 (bytes) */ +typedef void (Z7_FASTCALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize); +void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize); +void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize); + +/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */ +void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */ + +/* data - 16-byte aligned pointer to data */ +/* numBlocks - the number of 16-byte blocks in data array */ +typedef void (Z7_FASTCALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks); + +extern AES_CODE_FUNC g_AesCbc_Decode; +#ifndef Z7_SFX +extern AES_CODE_FUNC g_AesCbc_Encode; +extern AES_CODE_FUNC g_AesCtr_Code; +#define k_Aes_SupportedFunctions_HW (1 << 2) +#define k_Aes_SupportedFunctions_HW_256 (1 << 3) +extern UInt32 g_Aes_SupportedFunctions_Flags; +#endif + + +#define Z7_DECLARE_AES_CODE_FUNC(funcName) \ + void Z7_FASTCALL funcName(UInt32 *ivAes, Byte *data, size_t numBlocks); + +Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode) +Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode) +Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code) + +Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode_HW) +Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW) +Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW) + +Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW_256) +Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW_256) + +EXTERN_C_END + +#endif diff --git a/C/AesOpt.c b/C/AesOpt.c index 00b6c06ba..b28180739 100644 --- a/C/AesOpt.c +++ b/C/AesOpt.c @@ -1,957 +1,1002 @@ -/* AesOpt.c -- AES optimized code for x86 AES hardware instructions -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Aes.h" -#include "CpuArch.h" - -#ifdef MY_CPU_X86_OR_AMD64 - - #if defined(__INTEL_COMPILER) - #if (__INTEL_COMPILER >= 1110) - #define USE_INTEL_AES - #if (__INTEL_COMPILER >= 1900) - #define USE_INTEL_VAES - #endif - #endif - #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) - #define USE_INTEL_AES - #if !defined(__AES__) - #define ATTRIB_AES __attribute__((__target__("aes"))) - #endif - #if defined(__clang__) && (__clang_major__ >= 8) \ - || defined(__GNUC__) && (__GNUC__ >= 8) - #define USE_INTEL_VAES - #if !defined(__AES__) || !defined(__VAES__) || !defined(__AVX__) || !defined(__AVX2__) - #define ATTRIB_VAES __attribute__((__target__("aes,vaes,avx,avx2"))) - #endif - #endif - #elif defined(_MSC_VER) - #if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729) - #define USE_INTEL_AES - #if (_MSC_VER >= 1910) - #define USE_INTEL_VAES - #endif - #endif - #ifndef USE_INTEL_AES - #define Z7_USE_AES_HW_STUB - #endif - #ifndef USE_INTEL_VAES - #define Z7_USE_VAES_HW_STUB - #endif - #endif - - #ifndef USE_INTEL_AES - // #define Z7_USE_AES_HW_STUB // for debug - #endif - #ifndef USE_INTEL_VAES - // #define Z7_USE_VAES_HW_STUB // for debug - #endif - - -#ifdef USE_INTEL_AES - -#include - -#if !defined(USE_INTEL_VAES) && defined(Z7_USE_VAES_HW_STUB) -#define AES_TYPE_keys UInt32 -#define AES_TYPE_data Byte -// #define AES_TYPE_keys __m128i -// #define AES_TYPE_data __m128i -#endif - -#ifndef ATTRIB_AES - #define ATTRIB_AES -#endif - -#define AES_FUNC_START(name) \ - void Z7_FASTCALL name(UInt32 *ivAes, Byte *data8, size_t numBlocks) - // void Z7_FASTCALL name(__m128i *p, __m128i *data, size_t numBlocks) - -#define AES_FUNC_START2(name) \ -AES_FUNC_START (name); \ -ATTRIB_AES \ -AES_FUNC_START (name) - -#define MM_OP(op, dest, src) dest = op(dest, src); -#define MM_OP_m(op, src) MM_OP(op, m, src) - -#define MM_XOR( dest, src) MM_OP(_mm_xor_si128, dest, src) - -AES_FUNC_START2 (AesCbc_Encode_HW) -{ - __m128i *p = (__m128i *)(void *)ivAes; - __m128i *data = (__m128i *)(void *)data8; - __m128i m = *p; - const __m128i k0 = p[2]; - const __m128i k1 = p[3]; - const UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; - for (; numBlocks != 0; numBlocks--, data++) - { - UInt32 r = numRounds2; - const __m128i *w = p + 4; - __m128i temp = *data; - MM_XOR (temp, k0) - MM_XOR (m, temp) - MM_OP_m (_mm_aesenc_si128, k1) - do - { - MM_OP_m (_mm_aesenc_si128, w[0]) - MM_OP_m (_mm_aesenc_si128, w[1]) - w += 2; - } - while (--r); - MM_OP_m (_mm_aesenclast_si128, w[0]) - *data = m; - } - *p = m; -} - - -#define WOP_1(op) -#define WOP_2(op) WOP_1 (op) op (m1, 1) -#define WOP_3(op) WOP_2 (op) op (m2, 2) -#define WOP_4(op) WOP_3 (op) op (m3, 3) -#ifdef MY_CPU_AMD64 -#define WOP_5(op) WOP_4 (op) op (m4, 4) -#define WOP_6(op) WOP_5 (op) op (m5, 5) -#define WOP_7(op) WOP_6 (op) op (m6, 6) -#define WOP_8(op) WOP_7 (op) op (m7, 7) -#endif -/* -#define WOP_9(op) WOP_8 (op) op (m8, 8); -#define WOP_10(op) WOP_9 (op) op (m9, 9); -#define WOP_11(op) WOP_10(op) op (m10, 10); -#define WOP_12(op) WOP_11(op) op (m11, 11); -#define WOP_13(op) WOP_12(op) op (m12, 12); -#define WOP_14(op) WOP_13(op) op (m13, 13); -*/ - -#ifdef MY_CPU_AMD64 - #define NUM_WAYS 8 - #define WOP_M1 WOP_8 -#else - #define NUM_WAYS 4 - #define WOP_M1 WOP_4 -#endif - -#define WOP(op) op (m0, 0) WOP_M1(op) - - -#define DECLARE_VAR(reg, ii) __m128i reg; -#define LOAD_data( reg, ii) reg = data[ii]; -#define STORE_data( reg, ii) data[ii] = reg; -#if (NUM_WAYS > 1) -#define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1]) -#endif - -#define MM_OP_key(op, reg) MM_OP(op, reg, key); - -#define AES_DEC( reg, ii) MM_OP_key (_mm_aesdec_si128, reg) -#define AES_DEC_LAST( reg, ii) MM_OP_key (_mm_aesdeclast_si128, reg) -#define AES_ENC( reg, ii) MM_OP_key (_mm_aesenc_si128, reg) -#define AES_ENC_LAST( reg, ii) MM_OP_key (_mm_aesenclast_si128, reg) -#define AES_XOR( reg, ii) MM_OP_key (_mm_xor_si128, reg) - -#define CTR_START(reg, ii) MM_OP (_mm_add_epi64, ctr, one) reg = ctr; -#define CTR_END( reg, ii) MM_XOR (data[ii], reg) - -#define WOP_KEY(op, n) { \ - const __m128i key = w[n]; \ - WOP(op); } - - -#define WIDE_LOOP_START \ - dataEnd = data + numBlocks; \ - if (numBlocks >= NUM_WAYS) \ - { dataEnd -= NUM_WAYS; do { \ - - -#define WIDE_LOOP_END \ - data += NUM_WAYS; \ - } while (data <= dataEnd); \ - dataEnd += NUM_WAYS; } \ - - -#define SINGLE_LOOP \ - for (; data < dataEnd; data++) - - - -#ifdef USE_INTEL_VAES - -#define AVX_XOR(dest, src) MM_OP(_mm256_xor_si256, dest, src) -#define AVX_DECLARE_VAR(reg, ii) __m256i reg; -#define AVX_LOAD_data( reg, ii) reg = ((const __m256i *)(const void *)data)[ii]; -#define AVX_STORE_data( reg, ii) ((__m256i *)(void *)data)[ii] = reg; -/* -AVX_XOR_data_M1() needs unaligned memory load -if (we don't use _mm256_loadu_si256() here) -{ - Most compilers with enabled optimizations generate fused AVX (LOAD + OP) - instruction that can load unaligned data. - But GCC and CLANG without -O2 or -O1 optimizations can generate separated - LOAD-ALIGNED (vmovdqa) instruction that will fail on execution. -} -Note: some compilers generate more instructions, if we use _mm256_loadu_si256() here. -v23.02: we use _mm256_loadu_si256() here, because we need compatibility with any compiler. -*/ -#define AVX_XOR_data_M1(reg, ii) AVX_XOR (reg, _mm256_loadu_si256(&(((const __m256i *)(const void *)(data - 1))[ii]))) -// for debug only: the following code will fail on execution, if compiled by some compilers: -// #define AVX_XOR_data_M1(reg, ii) AVX_XOR (reg, (((const __m256i *)(const void *)(data - 1))[ii])) - -#define AVX_AES_DEC( reg, ii) MM_OP_key (_mm256_aesdec_epi128, reg) -#define AVX_AES_DEC_LAST( reg, ii) MM_OP_key (_mm256_aesdeclast_epi128, reg) -#define AVX_AES_ENC( reg, ii) MM_OP_key (_mm256_aesenc_epi128, reg) -#define AVX_AES_ENC_LAST( reg, ii) MM_OP_key (_mm256_aesenclast_epi128, reg) -#define AVX_AES_XOR( reg, ii) MM_OP_key (_mm256_xor_si256, reg) -#define AVX_CTR_START(reg, ii) MM_OP (_mm256_add_epi64, ctr2, two) reg = _mm256_xor_si256(ctr2, key); -#define AVX_CTR_END( reg, ii) AVX_XOR (((__m256i *)(void *)data)[ii], reg) -#define AVX_WOP_KEY(op, n) { \ - const __m256i key = w[n]; \ - WOP(op); } - -#define NUM_AES_KEYS_MAX 15 - -#define WIDE_LOOP_START_AVX(OP) \ - dataEnd = data + numBlocks; \ - if (numBlocks >= NUM_WAYS * 2) \ - { __m256i keys[NUM_AES_KEYS_MAX]; \ - UInt32 ii; \ - OP \ - for (ii = 0; ii < numRounds; ii++) \ - keys[ii] = _mm256_broadcastsi128_si256(p[ii]); \ - dataEnd -= NUM_WAYS * 2; do { \ - - -#define WIDE_LOOP_END_AVX(OP) \ - data += NUM_WAYS * 2; \ - } while (data <= dataEnd); \ - dataEnd += NUM_WAYS * 2; \ - OP \ - _mm256_zeroupper(); \ - } \ - -/* MSVC for x86: If we don't call _mm256_zeroupper(), and -arch:IA32 is not specified, - MSVC still can insert vzeroupper instruction. */ - -#endif - - - -AES_FUNC_START2 (AesCbc_Decode_HW) -{ - __m128i *p = (__m128i *)(void *)ivAes; - __m128i *data = (__m128i *)(void *)data8; - __m128i iv = *p; - const __m128i *wStart = p + *(const UInt32 *)(p + 1) * 2 + 2 - 1; - const __m128i *dataEnd; - p += 2; - - WIDE_LOOP_START - { - const __m128i *w = wStart; - - WOP (DECLARE_VAR) - WOP (LOAD_data) - WOP_KEY (AES_XOR, 1) - - do - { - WOP_KEY (AES_DEC, 0) - w--; - } - while (w != p); - WOP_KEY (AES_DEC_LAST, 0) - - MM_XOR (m0, iv) - WOP_M1 (XOR_data_M1) - iv = data[NUM_WAYS - 1]; - WOP (STORE_data) - } - WIDE_LOOP_END - - SINGLE_LOOP - { - const __m128i *w = wStart - 1; - __m128i m = _mm_xor_si128 (w[2], *data); - do - { - MM_OP_m (_mm_aesdec_si128, w[1]) - MM_OP_m (_mm_aesdec_si128, w[0]) - w -= 2; - } - while (w != p); - MM_OP_m (_mm_aesdec_si128, w[1]) - MM_OP_m (_mm_aesdeclast_si128, w[0]) - - MM_XOR (m, iv) - iv = *data; - *data = m; - } - - p[-2] = iv; -} - - -AES_FUNC_START2 (AesCtr_Code_HW) -{ - __m128i *p = (__m128i *)(void *)ivAes; - __m128i *data = (__m128i *)(void *)data8; - __m128i ctr = *p; - UInt32 numRoundsMinus2 = *(const UInt32 *)(p + 1) * 2 - 1; - const __m128i *dataEnd; - __m128i one = _mm_cvtsi32_si128(1); - - p += 2; - - WIDE_LOOP_START - { - const __m128i *w = p; - UInt32 r = numRoundsMinus2; - WOP (DECLARE_VAR) - WOP (CTR_START) - WOP_KEY (AES_XOR, 0) - w += 1; - do - { - WOP_KEY (AES_ENC, 0) - w += 1; - } - while (--r); - WOP_KEY (AES_ENC_LAST, 0) - - WOP (CTR_END) - } - WIDE_LOOP_END - - SINGLE_LOOP - { - UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1; - const __m128i *w = p; - __m128i m; - MM_OP (_mm_add_epi64, ctr, one) - m = _mm_xor_si128 (ctr, p[0]); - w += 1; - do - { - MM_OP_m (_mm_aesenc_si128, w[0]) - MM_OP_m (_mm_aesenc_si128, w[1]) - w += 2; - } - while (--numRounds2); - MM_OP_m (_mm_aesenc_si128, w[0]) - MM_OP_m (_mm_aesenclast_si128, w[1]) - MM_XOR (*data, m) - } - - p[-2] = ctr; -} - - - -#ifdef USE_INTEL_VAES - -/* -GCC before 2013-Jun: - : - #ifdef __AVX__ - #include - #endif -GCC after 2013-Jun: - : - #include -CLANG 3.8+: -{ - : - #if !defined(_MSC_VER) || defined(__AVX__) - #include - #endif - - if (the compiler is clang for Windows and if global arch is not set for __AVX__) - [ if (defined(_MSC_VER) && !defined(__AVX__)) ] - { - doesn't include - and we have 2 ways to fix it: - 1) we can define required __AVX__ before - or - 2) we can include after - } -} - -If we include manually for GCC/CLANG, it's -required that must be included before . -*/ - -/* -#if defined(__clang__) && defined(_MSC_VER) -#define __AVX__ -#define __AVX2__ -#define __VAES__ -#endif -*/ - -#include -#if defined(__clang__) && defined(_MSC_VER) - #if !defined(__AVX__) - #include - #endif - #if !defined(__AVX2__) - #include - #endif - #if !defined(__VAES__) - #include - #endif -#endif // __clang__ && _MSC_VER - -#ifndef ATTRIB_VAES - #define ATTRIB_VAES -#endif - -#define VAES_FUNC_START2(name) \ -AES_FUNC_START (name); \ -ATTRIB_VAES \ -AES_FUNC_START (name) - -VAES_FUNC_START2 (AesCbc_Decode_HW_256) -{ - __m128i *p = (__m128i *)(void *)ivAes; - __m128i *data = (__m128i *)(void *)data8; - __m128i iv = *p; - const __m128i *dataEnd; - UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; - p += 2; - - WIDE_LOOP_START_AVX(;) - { - const __m256i *w = keys + numRounds - 2; - - WOP (AVX_DECLARE_VAR) - WOP (AVX_LOAD_data) - AVX_WOP_KEY (AVX_AES_XOR, 1) - - do - { - AVX_WOP_KEY (AVX_AES_DEC, 0) - w--; - } - while (w != keys); - AVX_WOP_KEY (AVX_AES_DEC_LAST, 0) - - AVX_XOR (m0, _mm256_setr_m128i(iv, data[0])) - WOP_M1 (AVX_XOR_data_M1) - iv = data[NUM_WAYS * 2 - 1]; - WOP (AVX_STORE_data) - } - WIDE_LOOP_END_AVX(;) - - SINGLE_LOOP - { - const __m128i *w = p + *(const UInt32 *)(p + 1 - 2) * 2 + 1 - 3; - __m128i m = _mm_xor_si128 (w[2], *data); - do - { - MM_OP_m (_mm_aesdec_si128, w[1]) - MM_OP_m (_mm_aesdec_si128, w[0]) - w -= 2; - } - while (w != p); - MM_OP_m (_mm_aesdec_si128, w[1]) - MM_OP_m (_mm_aesdeclast_si128, w[0]) - - MM_XOR (m, iv) - iv = *data; - *data = m; - } - - p[-2] = iv; -} - - -/* -SSE2: _mm_cvtsi32_si128 : movd -AVX: _mm256_setr_m128i : vinsertf128 -AVX2: _mm256_add_epi64 : vpaddq ymm, ymm, ymm - _mm256_extracti128_si256 : vextracti128 - _mm256_broadcastsi128_si256 : vbroadcasti128 -*/ - -#define AVX_CTR_LOOP_START \ - ctr2 = _mm256_setr_m128i(_mm_sub_epi64(ctr, one), ctr); \ - two = _mm256_setr_m128i(one, one); \ - two = _mm256_add_epi64(two, two); \ - -// two = _mm256_setr_epi64x(2, 0, 2, 0); - -#define AVX_CTR_LOOP_ENC \ - ctr = _mm256_extracti128_si256 (ctr2, 1); \ - -VAES_FUNC_START2 (AesCtr_Code_HW_256) -{ - __m128i *p = (__m128i *)(void *)ivAes; - __m128i *data = (__m128i *)(void *)data8; - __m128i ctr = *p; - UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; - const __m128i *dataEnd; - __m128i one = _mm_cvtsi32_si128(1); - __m256i ctr2, two; - p += 2; - - WIDE_LOOP_START_AVX (AVX_CTR_LOOP_START) - { - const __m256i *w = keys; - UInt32 r = numRounds - 2; - WOP (AVX_DECLARE_VAR) - AVX_WOP_KEY (AVX_CTR_START, 0) - - w += 1; - do - { - AVX_WOP_KEY (AVX_AES_ENC, 0) - w += 1; - } - while (--r); - AVX_WOP_KEY (AVX_AES_ENC_LAST, 0) - - WOP (AVX_CTR_END) - } - WIDE_LOOP_END_AVX (AVX_CTR_LOOP_ENC) - - SINGLE_LOOP - { - UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1; - const __m128i *w = p; - __m128i m; - MM_OP (_mm_add_epi64, ctr, one) - m = _mm_xor_si128 (ctr, p[0]); - w += 1; - do - { - MM_OP_m (_mm_aesenc_si128, w[0]) - MM_OP_m (_mm_aesenc_si128, w[1]) - w += 2; - } - while (--numRounds2); - MM_OP_m (_mm_aesenc_si128, w[0]) - MM_OP_m (_mm_aesenclast_si128, w[1]) - MM_XOR (*data, m) - } - - p[-2] = ctr; -} - -#endif // USE_INTEL_VAES - -#else // USE_INTEL_AES - -/* no USE_INTEL_AES */ - -#if defined(Z7_USE_AES_HW_STUB) -// We can compile this file with another C compiler, -// or we can compile asm version. -// So we can generate real code instead of this stub function. -// #if defined(_MSC_VER) -#pragma message("AES HW_SW stub was used") -// #endif - -#if !defined(USE_INTEL_VAES) && defined(Z7_USE_VAES_HW_STUB) -#define AES_TYPE_keys UInt32 -#define AES_TYPE_data Byte -#endif - -#define AES_FUNC_START(name) \ - void Z7_FASTCALL name(UInt32 *p, Byte *data, size_t numBlocks) \ - -#define AES_COMPAT_STUB(name) \ - AES_FUNC_START(name); \ - AES_FUNC_START(name ## _HW) \ - { name(p, data, numBlocks); } - -AES_COMPAT_STUB (AesCbc_Encode) -AES_COMPAT_STUB (AesCbc_Decode) -AES_COMPAT_STUB (AesCtr_Code) -#endif // Z7_USE_AES_HW_STUB - -#endif // USE_INTEL_AES - - -#ifndef USE_INTEL_VAES -#if defined(Z7_USE_VAES_HW_STUB) -// #if defined(_MSC_VER) -#pragma message("VAES HW_SW stub was used") -// #endif - -#define VAES_COMPAT_STUB(name) \ - void Z7_FASTCALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks); \ - void Z7_FASTCALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks) \ - { name((AES_TYPE_keys *)(void *)p, (AES_TYPE_data *)(void *)data, numBlocks); } - -VAES_COMPAT_STUB (AesCbc_Decode_HW) -VAES_COMPAT_STUB (AesCtr_Code_HW) -#endif -#endif // ! USE_INTEL_VAES - - - - -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) - - #if defined(__ARM_FEATURE_AES) \ - || defined(__ARM_FEATURE_CRYPTO) - #define USE_HW_AES - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define USE_HW_AES - #endif - #endif - #endif - #endif - -#ifdef USE_HW_AES - -// #pragma message("=== AES HW === ") -// __ARM_FEATURE_CRYPTO macro is deprecated in favor of the finer grained feature macro __ARM_FEATURE_AES - -#if defined(__clang__) || defined(__GNUC__) -#if !defined(__ARM_FEATURE_AES) && \ - !defined(__ARM_FEATURE_CRYPTO) - #ifdef MY_CPU_ARM64 -#if defined(__clang__) - #define ATTRIB_AES __attribute__((__target__("crypto"))) -#else - #define ATTRIB_AES __attribute__((__target__("+crypto"))) -#endif - #else -#if defined(__clang__) - #define ATTRIB_AES __attribute__((__target__("armv8-a,aes"))) -#else - #define ATTRIB_AES __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) -#endif - #endif -#endif -#else - // _MSC_VER - // for arm32 - #define _ARM_USE_NEW_NEON_INTRINSICS -#endif - -#ifndef ATTRIB_AES - #define ATTRIB_AES -#endif - -#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) -#include -#else -/* - clang-17.0.1: error : Cannot select: intrinsic %llvm.arm.neon.aese - clang - 3.8.1 : __ARM_NEON : defined(__ARM_FEATURE_CRYPTO) - 7.0.1 : __ARM_NEON : __ARM_ARCH >= 8 && defined(__ARM_FEATURE_CRYPTO) - 11.?.0 : __ARM_NEON && __ARM_FP : __ARM_ARCH >= 8 && defined(__ARM_FEATURE_CRYPTO) - 13.0.1 : __ARM_NEON && __ARM_FP : __ARM_ARCH >= 8 && defined(__ARM_FEATURE_AES) - 16 : __ARM_NEON && __ARM_FP : __ARM_ARCH >= 8 -*/ -#if defined(__clang__) && __clang_major__ < 16 -#if !defined(__ARM_FEATURE_AES) && \ - !defined(__ARM_FEATURE_CRYPTO) -// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ") - Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1 -// #if defined(__clang__) && __clang_major__ < 13 - #define __ARM_FEATURE_CRYPTO 1 -// #else - #define __ARM_FEATURE_AES 1 -// #endif - Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif -#endif // clang - -#if defined(__clang__) - -#if defined(__ARM_ARCH) && __ARM_ARCH < 8 - Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -// #pragma message("#define __ARM_ARCH 8") - #undef __ARM_ARCH - #define __ARM_ARCH 8 - Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif - -#endif // clang - -#include - -#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \ - defined(__ARM_FEATURE_CRYPTO) && \ - defined(__ARM_FEATURE_AES) -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #undef __ARM_FEATURE_CRYPTO - #undef __ARM_FEATURE_AES - #undef Z7_ARM_FEATURE_CRYPTO_WAS_SET -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") -#endif - -#endif // Z7_MSC_VER_ORIGINAL - -typedef uint8x16_t v128; - -#define AES_FUNC_START(name) \ - void Z7_FASTCALL name(UInt32 *ivAes, Byte *data8, size_t numBlocks) - // void Z7_FASTCALL name(v128 *p, v128 *data, size_t numBlocks) - -#define AES_FUNC_START2(name) \ -AES_FUNC_START (name); \ -ATTRIB_AES \ -AES_FUNC_START (name) - -#define MM_OP(op, dest, src) dest = op(dest, src); -#define MM_OP_m(op, src) MM_OP(op, m, src) -#define MM_OP1_m(op) m = op(m); - -#define MM_XOR( dest, src) MM_OP(veorq_u8, dest, src) -#define MM_XOR_m( src) MM_XOR(m, src) - -#define AES_E_m(k) MM_OP_m (vaeseq_u8, k) -#define AES_E_MC_m(k) AES_E_m (k) MM_OP1_m(vaesmcq_u8) - - -AES_FUNC_START2 (AesCbc_Encode_HW) -{ - v128 * const p = (v128*)(void*)ivAes; - v128 *data = (v128*)(void*)data8; - v128 m = *p; - const v128 k0 = p[2]; - const v128 k1 = p[3]; - const v128 k2 = p[4]; - const v128 k3 = p[5]; - const v128 k4 = p[6]; - const v128 k5 = p[7]; - const v128 k6 = p[8]; - const v128 k7 = p[9]; - const v128 k8 = p[10]; - const v128 k9 = p[11]; - const UInt32 numRounds2 = *(const UInt32 *)(p + 1); - const v128 *w = p + ((size_t)numRounds2 * 2); - const v128 k_z1 = w[1]; - const v128 k_z0 = w[2]; - for (; numBlocks != 0; numBlocks--, data++) - { - MM_XOR_m (*data) - AES_E_MC_m (k0) - AES_E_MC_m (k1) - AES_E_MC_m (k2) - AES_E_MC_m (k3) - AES_E_MC_m (k4) - AES_E_MC_m (k5) - AES_E_MC_m (k6) - AES_E_MC_m (k7) - AES_E_MC_m (k8) - if (numRounds2 >= 6) - { - AES_E_MC_m (k9) - AES_E_MC_m (p[12]) - if (numRounds2 != 6) - { - AES_E_MC_m (p[13]) - AES_E_MC_m (p[14]) - } - } - AES_E_m (k_z1) - MM_XOR_m (k_z0) - *data = m; - } - *p = m; -} - - -#define WOP_1(op) -#define WOP_2(op) WOP_1 (op) op (m1, 1) -#define WOP_3(op) WOP_2 (op) op (m2, 2) -#define WOP_4(op) WOP_3 (op) op (m3, 3) -#define WOP_5(op) WOP_4 (op) op (m4, 4) -#define WOP_6(op) WOP_5 (op) op (m5, 5) -#define WOP_7(op) WOP_6 (op) op (m6, 6) -#define WOP_8(op) WOP_7 (op) op (m7, 7) - - #define NUM_WAYS 8 - #define WOP_M1 WOP_8 - -#define WOP(op) op (m0, 0) WOP_M1(op) - -#define DECLARE_VAR(reg, ii) v128 reg; -#define LOAD_data( reg, ii) reg = data[ii]; -#define STORE_data( reg, ii) data[ii] = reg; -#if (NUM_WAYS > 1) -#define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1]) -#endif - -#define MM_OP_key(op, reg) MM_OP (op, reg, key) - -#define AES_D_m(k) MM_OP_m (vaesdq_u8, k) -#define AES_D_IMC_m(k) AES_D_m (k) MM_OP1_m (vaesimcq_u8) - -#define AES_XOR( reg, ii) MM_OP_key (veorq_u8, reg) -#define AES_D( reg, ii) MM_OP_key (vaesdq_u8, reg) -#define AES_E( reg, ii) MM_OP_key (vaeseq_u8, reg) - -#define AES_D_IMC( reg, ii) AES_D (reg, ii) reg = vaesimcq_u8(reg); -#define AES_E_MC( reg, ii) AES_E (reg, ii) reg = vaesmcq_u8(reg); - -#define CTR_START(reg, ii) MM_OP (vaddq_u64, ctr, one) reg = vreinterpretq_u8_u64(ctr); -#define CTR_END( reg, ii) MM_XOR (data[ii], reg) - -#define WOP_KEY(op, n) { \ - const v128 key = w[n]; \ - WOP(op) } - -#define WIDE_LOOP_START \ - dataEnd = data + numBlocks; \ - if (numBlocks >= NUM_WAYS) \ - { dataEnd -= NUM_WAYS; do { \ - -#define WIDE_LOOP_END \ - data += NUM_WAYS; \ - } while (data <= dataEnd); \ - dataEnd += NUM_WAYS; } \ - -#define SINGLE_LOOP \ - for (; data < dataEnd; data++) - - -AES_FUNC_START2 (AesCbc_Decode_HW) -{ - v128 *p = (v128*)(void*)ivAes; - v128 *data = (v128*)(void*)data8; - v128 iv = *p; - const v128 *wStart = p + ((size_t)*(const UInt32 *)(p + 1)) * 2; - const v128 *dataEnd; - p += 2; - - WIDE_LOOP_START - { - const v128 *w = wStart; - WOP (DECLARE_VAR) - WOP (LOAD_data) - WOP_KEY (AES_D_IMC, 2) - do - { - WOP_KEY (AES_D_IMC, 1) - WOP_KEY (AES_D_IMC, 0) - w -= 2; - } - while (w != p); - WOP_KEY (AES_D, 1) - WOP_KEY (AES_XOR, 0) - MM_XOR (m0, iv) - WOP_M1 (XOR_data_M1) - iv = data[NUM_WAYS - 1]; - WOP (STORE_data) - } - WIDE_LOOP_END - - SINGLE_LOOP - { - const v128 *w = wStart; - v128 m = *data; - AES_D_IMC_m (w[2]) - do - { - AES_D_IMC_m (w[1]) - AES_D_IMC_m (w[0]) - w -= 2; - } - while (w != p); - AES_D_m (w[1]) - MM_XOR_m (w[0]) - MM_XOR_m (iv) - iv = *data; - *data = m; - } - - p[-2] = iv; -} - - -AES_FUNC_START2 (AesCtr_Code_HW) -{ - v128 *p = (v128*)(void*)ivAes; - v128 *data = (v128*)(void*)data8; - uint64x2_t ctr = vreinterpretq_u64_u8(*p); - const v128 *wEnd = p + ((size_t)*(const UInt32 *)(p + 1)) * 2; - const v128 *dataEnd; - uint64x2_t one = vdupq_n_u64(0); - -// the bug in clang: -// __builtin_neon_vsetq_lane_i64(__s0, (int8x16_t)__s1, __p2); -#if defined(__clang__) && (__clang_major__ <= 9) -#pragma GCC diagnostic ignored "-Wvector-conversion" -#endif - one = vsetq_lane_u64(1, one, 0); - p += 2; - - WIDE_LOOP_START - { - const v128 *w = p; - WOP (DECLARE_VAR) - WOP (CTR_START) - do - { - WOP_KEY (AES_E_MC, 0) - WOP_KEY (AES_E_MC, 1) - w += 2; - } - while (w != wEnd); - WOP_KEY (AES_E_MC, 0) - WOP_KEY (AES_E, 1) - WOP_KEY (AES_XOR, 2) - WOP (CTR_END) - } - WIDE_LOOP_END - - SINGLE_LOOP - { - const v128 *w = p; - v128 m; - CTR_START (m, 0) - do - { - AES_E_MC_m (w[0]) - AES_E_MC_m (w[1]) - w += 2; - } - while (w != wEnd); - AES_E_MC_m (w[0]) - AES_E_m (w[1]) - MM_XOR_m (w[2]) - CTR_END (m, 0) - } - - p[-2] = vreinterpretq_u8_u64(ctr); -} - -#endif // USE_HW_AES - -#endif // MY_CPU_ARM_OR_ARM64 - -#undef NUM_WAYS -#undef WOP_M1 -#undef WOP -#undef DECLARE_VAR -#undef LOAD_data -#undef STORE_data -#undef USE_INTEL_AES -#undef USE_HW_AES +/* AesOpt.c -- AES optimized code for x86 AES hardware instructions +Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Aes.h" +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + + #if defined(__INTEL_COMPILER) + #if (__INTEL_COMPILER >= 1110) + #define USE_INTEL_AES + #if (__INTEL_COMPILER >= 1900) + #define USE_INTEL_VAES + #endif + #endif + #elif defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) + #define USE_INTEL_AES + #if !defined(__AES__) + #define ATTRIB_AES __attribute__((__target__("aes"))) + #endif + #if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 8) + #define USE_INTEL_VAES + #if !defined(__AES__) || !defined(__VAES__) || !defined(__AVX__) || !defined(__AVX2__) + #define ATTRIB_VAES __attribute__((__target__("aes,vaes,avx,avx2"))) + #endif + #endif + #elif defined(_MSC_VER) + #if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729) + #define USE_INTEL_AES + #if (_MSC_VER >= 1910) + #define USE_INTEL_VAES + #endif + #endif + #ifndef USE_INTEL_AES + #define Z7_USE_AES_HW_STUB + #endif + #ifndef USE_INTEL_VAES + #define Z7_USE_VAES_HW_STUB + #endif + #endif + + #ifndef USE_INTEL_AES + // #define Z7_USE_AES_HW_STUB // for debug + #endif + #ifndef USE_INTEL_VAES + // #define Z7_USE_VAES_HW_STUB // for debug + #endif + + +#ifdef USE_INTEL_AES + +#include + +#if !defined(USE_INTEL_VAES) && defined(Z7_USE_VAES_HW_STUB) +#define AES_TYPE_keys UInt32 +#define AES_TYPE_data Byte +// #define AES_TYPE_keys __m128i +// #define AES_TYPE_data __m128i +#endif + +#ifndef ATTRIB_AES + #define ATTRIB_AES +#endif + +#define AES_FUNC_START(name) \ + void Z7_FASTCALL name(UInt32 *ivAes, Byte *data8, size_t numBlocks) + // void Z7_FASTCALL name(__m128i *p, __m128i *data, size_t numBlocks) + +#define AES_FUNC_START2(name) \ +AES_FUNC_START (name); \ +ATTRIB_AES \ +AES_FUNC_START (name) + +#define MM_OP(op, dest, src) dest = op(dest, src); +#define MM_OP_m(op, src) MM_OP(op, m, src) + +#define MM_XOR( dest, src) MM_OP(_mm_xor_si128, dest, src) + +#if 1 +// use aligned SSE load/store for data. +// It is required for our Aes functions, that data is aligned for 16-bytes. +// So we can use this branch of code. +// and compiler can use fused load-op SSE instructions: +// xorps xmm0, XMMWORD PTR [rdx] +#define LOAD_128(pp) (*(__m128i *)(void *)(pp)) +#define STORE_128(pp, _v) *(__m128i *)(void *)(pp) = _v +// use aligned SSE load/store for data. Alternative code with direct access +// #define LOAD_128(pp) _mm_load_si128(pp) +// #define STORE_128(pp, _v) _mm_store_si128(pp, _v) +#else +// use unaligned load/store for data: movdqu XMMWORD PTR [rdx] +#define LOAD_128(pp) _mm_loadu_si128(pp) +#define STORE_128(pp, _v) _mm_storeu_si128(pp, _v) +#endif + +AES_FUNC_START2 (AesCbc_Encode_HW) +{ + if (numBlocks == 0) + return; + { + __m128i *p = (__m128i *)(void *)ivAes; + __m128i *data = (__m128i *)(void *)data8; + __m128i m = *p; + const __m128i k0 = p[2]; + const __m128i k1 = p[3]; + const UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1; + do + { + UInt32 r = numRounds2; + const __m128i *w = p + 4; + __m128i temp = LOAD_128(data); + MM_XOR (temp, k0) + MM_XOR (m, temp) + MM_OP_m (_mm_aesenc_si128, k1) + do + { + MM_OP_m (_mm_aesenc_si128, w[0]) + MM_OP_m (_mm_aesenc_si128, w[1]) + w += 2; + } + while (--r); + MM_OP_m (_mm_aesenclast_si128, w[0]) + STORE_128(data, m); + data++; + } + while (--numBlocks); + *p = m; + } +} + + +#define WOP_1(op) +#define WOP_2(op) WOP_1 (op) op (m1, 1) +#define WOP_3(op) WOP_2 (op) op (m2, 2) +#define WOP_4(op) WOP_3 (op) op (m3, 3) +#ifdef MY_CPU_AMD64 +#define WOP_5(op) WOP_4 (op) op (m4, 4) +#define WOP_6(op) WOP_5 (op) op (m5, 5) +#define WOP_7(op) WOP_6 (op) op (m6, 6) +#define WOP_8(op) WOP_7 (op) op (m7, 7) +#endif +/* +#define WOP_9(op) WOP_8 (op) op (m8, 8); +#define WOP_10(op) WOP_9 (op) op (m9, 9); +#define WOP_11(op) WOP_10(op) op (m10, 10); +#define WOP_12(op) WOP_11(op) op (m11, 11); +#define WOP_13(op) WOP_12(op) op (m12, 12); +#define WOP_14(op) WOP_13(op) op (m13, 13); +*/ + +#ifdef MY_CPU_AMD64 + #define NUM_WAYS 8 + #define WOP_M1 WOP_8 +#else + #define NUM_WAYS 4 + #define WOP_M1 WOP_4 +#endif + +#define WOP(op) op (m0, 0) WOP_M1(op) + +#define DECLARE_VAR(reg, ii) __m128i reg; +#define LOAD_data_ii(ii) LOAD_128(data + (ii)) +#define LOAD_data( reg, ii) reg = LOAD_data_ii(ii); +#define STORE_data( reg, ii) STORE_128(data + (ii), reg); +#if (NUM_WAYS > 1) +#define XOR_data_M1(reg, ii) MM_XOR (reg, LOAD_128(data + (ii- 1))) +#endif + +#define MM_OP_key(op, reg) MM_OP(op, reg, key); + +#define AES_DEC( reg, ii) MM_OP_key (_mm_aesdec_si128, reg) +#define AES_DEC_LAST( reg, ii) MM_OP_key (_mm_aesdeclast_si128, reg) +#define AES_ENC( reg, ii) MM_OP_key (_mm_aesenc_si128, reg) +#define AES_ENC_LAST( reg, ii) MM_OP_key (_mm_aesenclast_si128, reg) +#define AES_XOR( reg, ii) MM_OP_key (_mm_xor_si128, reg) + +#define CTR_START(reg, ii) MM_OP (_mm_add_epi64, ctr, one) reg = ctr; +#define CTR_END( reg, ii) STORE_128(data + (ii), _mm_xor_si128(reg, \ + LOAD_128 (data + (ii)))); +#define WOP_KEY(op, n) { \ + const __m128i key = w[n]; \ + WOP(op) } + +#define WIDE_LOOP_START \ + dataEnd = data + numBlocks; \ + if (numBlocks >= NUM_WAYS) \ + { dataEnd -= NUM_WAYS; do { \ + +#define WIDE_LOOP_END \ + data += NUM_WAYS; \ + } while (data <= dataEnd); \ + dataEnd += NUM_WAYS; } \ + +#define SINGLE_LOOP \ + for (; data < dataEnd; data++) + + + +#ifdef USE_INTEL_VAES + +#define AVX_XOR(dest, src) MM_OP(_mm256_xor_si256, dest, src) +#define AVX_DECLARE_VAR(reg, ii) __m256i reg; + +#if 1 +// use unaligned AVX load/store for data. +// It is required for our Aes functions, that data is aligned for 16-bytes. +// But we need 32-bytes reading. +// So we use intrinsics for unaligned AVX load/store. +// notes for _mm256_storeu_si256: +// msvc2022: uses vmovdqu and keeps the order of instruction sequence. +// new gcc11 uses vmovdqu +// old gcc9 could use pair of instructions: +// vmovups %xmm7, -224(%rax) +// vextracti128 $0x1, %ymm7, -208(%rax) +#define AVX_LOAD(p) _mm256_loadu_si256((const __m256i *)(const void *)(p)) +#define AVX_STORE(p, _v) _mm256_storeu_si256((__m256i *)(void *)(p), _v); +#else +// use aligned AVX load/store for data. +// for debug: we can use this branch, if we are sure that data is aligned for 32-bytes. +// msvc2022 uses vmovdqu still +// gcc uses vmovdqa (that requires 32-bytes alignment) +#define AVX_LOAD(p) (*(const __m256i *)(const void *)(p)) +#define AVX_STORE(p, _v) (*(__m256i *)(void *)(p)) = _v; +#endif + +#define AVX_LOAD_data( reg, ii) reg = AVX_LOAD((const __m256i *)(const void *)data + (ii)); +#define AVX_STORE_data( reg, ii) AVX_STORE((__m256i *)(void *)data + (ii), reg) +/* +AVX_XOR_data_M1() needs unaligned memory load, even if (data) +is aligned for 256-bits, because we read 32-bytes chunk that +crosses (data) position: from (data - 16bytes) to (data + 16bytes). +*/ +#define AVX_XOR_data_M1(reg, ii) AVX_XOR (reg, _mm256_loadu_si256((const __m256i *)(const void *)(data - 1) + (ii))) + +#define AVX_AES_DEC( reg, ii) MM_OP_key (_mm256_aesdec_epi128, reg) +#define AVX_AES_DEC_LAST( reg, ii) MM_OP_key (_mm256_aesdeclast_epi128, reg) +#define AVX_AES_ENC( reg, ii) MM_OP_key (_mm256_aesenc_epi128, reg) +#define AVX_AES_ENC_LAST( reg, ii) MM_OP_key (_mm256_aesenclast_epi128, reg) +#define AVX_AES_XOR( reg, ii) MM_OP_key (_mm256_xor_si256, reg) +#define AVX_CTR_START(reg, ii) \ + MM_OP (_mm256_add_epi64, ctr2, two) \ + reg = _mm256_xor_si256(ctr2, key); + +#define AVX_CTR_END(reg, ii) \ + AVX_STORE((__m256i *)(void *)data + (ii), _mm256_xor_si256(reg, \ + AVX_LOAD ((__m256i *)(void *)data + (ii)))); + +#define AVX_WOP_KEY(op, n) { \ + const __m256i key = w[n]; \ + WOP(op) } + +#define NUM_AES_KEYS_MAX 15 + +#define WIDE_LOOP_START_AVX(OP) \ + dataEnd = data + numBlocks; \ + if (numBlocks >= NUM_WAYS * 2) \ + { __m256i keys[NUM_AES_KEYS_MAX]; \ + OP \ + { UInt32 ii; for (ii = 0; ii < numRounds; ii++) \ + keys[ii] = _mm256_broadcastsi128_si256(p[ii]); } \ + dataEnd -= NUM_WAYS * 2; \ + do { \ + +#define WIDE_LOOP_END_AVX(OP) \ + data += NUM_WAYS * 2; \ + } while (data <= dataEnd); \ + dataEnd += NUM_WAYS * 2; \ + OP \ + _mm256_zeroupper(); \ + } \ + +/* MSVC for x86: If we don't call _mm256_zeroupper(), and -arch:IA32 is not specified, + MSVC still can insert vzeroupper instruction. */ + +#endif + + + +AES_FUNC_START2 (AesCbc_Decode_HW) +{ + __m128i *p = (__m128i *)(void *)ivAes; + __m128i *data = (__m128i *)(void *)data8; + __m128i iv = *p; + const __m128i * const wStart = p + (size_t)*(const UInt32 *)(p + 1) * 2 + 2 - 1; + const __m128i *dataEnd; + p += 2; + + WIDE_LOOP_START + { + const __m128i *w = wStart; + WOP (DECLARE_VAR) + WOP (LOAD_data) + WOP_KEY (AES_XOR, 1) + do + { + WOP_KEY (AES_DEC, 0) + + w--; + } + while (w != p); + WOP_KEY (AES_DEC_LAST, 0) + + MM_XOR (m0, iv) + WOP_M1 (XOR_data_M1) + LOAD_data(iv, NUM_WAYS - 1) + WOP (STORE_data) + } + WIDE_LOOP_END + + SINGLE_LOOP + { + const __m128i *w = wStart - 1; + __m128i m = _mm_xor_si128 (w[2], LOAD_data_ii(0)); + + do + { + MM_OP_m (_mm_aesdec_si128, w[1]) + MM_OP_m (_mm_aesdec_si128, w[0]) + w -= 2; + } + while (w != p); + MM_OP_m (_mm_aesdec_si128, w[1]) + MM_OP_m (_mm_aesdeclast_si128, w[0]) + MM_XOR (m, iv) + LOAD_data(iv, 0) + STORE_data(m, 0) + } + + p[-2] = iv; +} + + +AES_FUNC_START2 (AesCtr_Code_HW) +{ + __m128i *p = (__m128i *)(void *)ivAes; + __m128i *data = (__m128i *)(void *)data8; + __m128i ctr = *p; + const UInt32 numRoundsMinus2 = *(const UInt32 *)(p + 1) * 2 - 1; + const __m128i *dataEnd; + const __m128i one = _mm_cvtsi32_si128(1); + + p += 2; + + WIDE_LOOP_START + { + const __m128i *w = p; + UInt32 r = numRoundsMinus2; + WOP (DECLARE_VAR) + WOP (CTR_START) + WOP_KEY (AES_XOR, 0) + w += 1; + do + { + WOP_KEY (AES_ENC, 0) + w += 1; + } + while (--r); + WOP_KEY (AES_ENC_LAST, 0) + WOP (CTR_END) + } + WIDE_LOOP_END + + SINGLE_LOOP + { + UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1; + const __m128i *w = p; + __m128i m; + MM_OP (_mm_add_epi64, ctr, one) + m = _mm_xor_si128 (ctr, p[0]); + w += 1; + do + { + MM_OP_m (_mm_aesenc_si128, w[0]) + MM_OP_m (_mm_aesenc_si128, w[1]) + w += 2; + } + while (--numRounds2); + MM_OP_m (_mm_aesenc_si128, w[0]) + MM_OP_m (_mm_aesenclast_si128, w[1]) + CTR_END (m, 0) + } + + p[-2] = ctr; +} + + + +#ifdef USE_INTEL_VAES + +/* +GCC before 2013-Jun: + : + #ifdef __AVX__ + #include + #endif +GCC after 2013-Jun: + : + #include +CLANG 3.8+: +{ + : + #if !defined(_MSC_VER) || defined(__AVX__) + #include + #endif + + if (the compiler is clang for Windows and if global arch is not set for __AVX__) + [ if (defined(_MSC_VER) && !defined(__AVX__)) ] + { + doesn't include + and we have 2 ways to fix it: + 1) we can define required __AVX__ before + or + 2) we can include after + } +} + +If we include manually for GCC/CLANG, it's +required that must be included before . +*/ + +/* +#if defined(__clang__) && defined(_MSC_VER) +#define __AVX__ +#define __AVX2__ +#define __VAES__ +#endif +*/ + +#include +#if defined(__clang__) && defined(_MSC_VER) + #if !defined(__AVX__) + #include + #endif + #if !defined(__AVX2__) + #include + #endif + #if !defined(__VAES__) + #include + #endif +#endif // __clang__ && _MSC_VER + +#ifndef ATTRIB_VAES + #define ATTRIB_VAES +#endif + +#define VAES_FUNC_START2(name) \ +AES_FUNC_START (name); \ +ATTRIB_VAES \ +AES_FUNC_START (name) + +VAES_FUNC_START2 (AesCbc_Decode_HW_256) +{ + __m128i *p = (__m128i *)(void *)ivAes; + __m128i *data = (__m128i *)(void *)data8; + __m128i iv = *p; + const __m128i *dataEnd; + const UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; + p += 2; + + WIDE_LOOP_START_AVX(;) + { + const __m256i *w = keys + numRounds - 2; + + WOP (AVX_DECLARE_VAR) + WOP (AVX_LOAD_data) + AVX_WOP_KEY (AVX_AES_XOR, 1) + + do + { + AVX_WOP_KEY (AVX_AES_DEC, 0) + w--; + } + while (w != keys); + AVX_WOP_KEY (AVX_AES_DEC_LAST, 0) + + AVX_XOR (m0, _mm256_setr_m128i(iv, LOAD_data_ii(0))) + WOP_M1 (AVX_XOR_data_M1) + LOAD_data (iv, NUM_WAYS * 2 - 1) + WOP (AVX_STORE_data) + } + WIDE_LOOP_END_AVX(;) + + SINGLE_LOOP + { + const __m128i *w = p - 2 + (size_t)*(const UInt32 *)(p + 1 - 2) * 2; + __m128i m = _mm_xor_si128 (w[2], LOAD_data_ii(0)); + do + { + MM_OP_m (_mm_aesdec_si128, w[1]) + MM_OP_m (_mm_aesdec_si128, w[0]) + w -= 2; + } + while (w != p); + MM_OP_m (_mm_aesdec_si128, w[1]) + MM_OP_m (_mm_aesdeclast_si128, w[0]) + + MM_XOR (m, iv) + LOAD_data(iv, 0) + STORE_data(m, 0) + } + + p[-2] = iv; +} + + +/* +SSE2: _mm_cvtsi32_si128 : movd +AVX: _mm256_setr_m128i : vinsertf128 +AVX2: _mm256_add_epi64 : vpaddq ymm, ymm, ymm + _mm256_extracti128_si256 : vextracti128 + _mm256_broadcastsi128_si256 : vbroadcasti128 +*/ + +#define AVX_CTR_LOOP_START \ + ctr2 = _mm256_setr_m128i(_mm_sub_epi64(ctr, one), ctr); \ + two = _mm256_setr_m128i(one, one); \ + two = _mm256_add_epi64(two, two); \ + +// two = _mm256_setr_epi64x(2, 0, 2, 0); + +#define AVX_CTR_LOOP_ENC \ + ctr = _mm256_extracti128_si256 (ctr2, 1); \ + +VAES_FUNC_START2 (AesCtr_Code_HW_256) +{ + __m128i *p = (__m128i *)(void *)ivAes; + __m128i *data = (__m128i *)(void *)data8; + __m128i ctr = *p; + const UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; + const __m128i *dataEnd; + const __m128i one = _mm_cvtsi32_si128(1); + __m256i ctr2, two; + p += 2; + + WIDE_LOOP_START_AVX (AVX_CTR_LOOP_START) + { + const __m256i *w = keys; + UInt32 r = numRounds - 2; + WOP (AVX_DECLARE_VAR) + AVX_WOP_KEY (AVX_CTR_START, 0) + + w += 1; + do + { + AVX_WOP_KEY (AVX_AES_ENC, 0) + w += 1; + } + while (--r); + AVX_WOP_KEY (AVX_AES_ENC_LAST, 0) + + WOP (AVX_CTR_END) + } + WIDE_LOOP_END_AVX (AVX_CTR_LOOP_ENC) + + SINGLE_LOOP + { + UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1; + const __m128i *w = p; + __m128i m; + MM_OP (_mm_add_epi64, ctr, one) + m = _mm_xor_si128 (ctr, p[0]); + w += 1; + do + { + MM_OP_m (_mm_aesenc_si128, w[0]) + MM_OP_m (_mm_aesenc_si128, w[1]) + w += 2; + } + while (--numRounds2); + MM_OP_m (_mm_aesenc_si128, w[0]) + MM_OP_m (_mm_aesenclast_si128, w[1]) + CTR_END (m, 0) + } + + p[-2] = ctr; +} + +#endif // USE_INTEL_VAES + +#else // USE_INTEL_AES + +/* no USE_INTEL_AES */ + +#if defined(Z7_USE_AES_HW_STUB) +// We can compile this file with another C compiler, +// or we can compile asm version. +// So we can generate real code instead of this stub function. +// #if defined(_MSC_VER) +#pragma message("AES HW_SW stub was used") +// #endif + +#if !defined(USE_INTEL_VAES) && defined(Z7_USE_VAES_HW_STUB) +#define AES_TYPE_keys UInt32 +#define AES_TYPE_data Byte +#endif + +#define AES_FUNC_START(name) \ + void Z7_FASTCALL name(UInt32 *p, Byte *data, size_t numBlocks) \ + +#define AES_COMPAT_STUB(name) \ + AES_FUNC_START(name); \ + AES_FUNC_START(name ## _HW) \ + { name(p, data, numBlocks); } + +AES_COMPAT_STUB (AesCbc_Encode) +AES_COMPAT_STUB (AesCbc_Decode) +AES_COMPAT_STUB (AesCtr_Code) +#endif // Z7_USE_AES_HW_STUB + +#endif // USE_INTEL_AES + + +#ifndef USE_INTEL_VAES +#if defined(Z7_USE_VAES_HW_STUB) +// #if defined(_MSC_VER) +#pragma message("VAES HW_SW stub was used") +// #endif + +#define VAES_COMPAT_STUB(name) \ + void Z7_FASTCALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks); \ + void Z7_FASTCALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks) \ + { name((AES_TYPE_keys *)(void *)p, (AES_TYPE_data *)(void *)data, numBlocks); } + +VAES_COMPAT_STUB (AesCbc_Decode_HW) +VAES_COMPAT_STUB (AesCtr_Code_HW) +#endif +#endif // ! USE_INTEL_VAES + + + + +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) + + #if defined(__ARM_FEATURE_AES) \ + || defined(__ARM_FEATURE_CRYPTO) + #define USE_HW_AES + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define USE_HW_AES + #endif + #endif + #endif + #endif + +#ifdef USE_HW_AES + +// #pragma message("=== AES HW === ") +// __ARM_FEATURE_CRYPTO macro is deprecated in favor of the finer grained feature macro __ARM_FEATURE_AES + +#if defined(__clang__) || defined(__GNUC__) +#if !defined(__ARM_FEATURE_AES) && \ + !defined(__ARM_FEATURE_CRYPTO) + #ifdef MY_CPU_ARM64 +#if defined(__clang__) + #define ATTRIB_AES __attribute__((__target__("crypto"))) +#else + #define ATTRIB_AES __attribute__((__target__("+crypto"))) +#endif + #else +#if defined(__clang__) + #define ATTRIB_AES __attribute__((__target__("armv8-a,aes"))) +#else + #define ATTRIB_AES __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) +#endif + #endif +#endif +#else + // _MSC_VER + // for arm32 + #define _ARM_USE_NEW_NEON_INTRINSICS +#endif + +#ifndef ATTRIB_AES + #define ATTRIB_AES +#endif + +#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) +#include +#else +/* + clang-17.0.1: error : Cannot select: intrinsic %llvm.arm.neon.aese + clang + 3.8.1 : __ARM_NEON : defined(__ARM_FEATURE_CRYPTO) + 7.0.1 : __ARM_NEON : __ARM_ARCH >= 8 && defined(__ARM_FEATURE_CRYPTO) + 11.?.0 : __ARM_NEON && __ARM_FP : __ARM_ARCH >= 8 && defined(__ARM_FEATURE_CRYPTO) + 13.0.1 : __ARM_NEON && __ARM_FP : __ARM_ARCH >= 8 && defined(__ARM_FEATURE_AES) + 16 : __ARM_NEON && __ARM_FP : __ARM_ARCH >= 8 +*/ +#if defined(__clang__) && __clang_major__ < 16 +#if !defined(__ARM_FEATURE_AES) && \ + !defined(__ARM_FEATURE_CRYPTO) +// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ") + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1 +// #if defined(__clang__) && __clang_major__ < 13 + #define __ARM_FEATURE_CRYPTO 1 +// #else + #define __ARM_FEATURE_AES 1 +// #endif + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif // clang + +#if defined(__clang__) + +#if defined(__ARM_ARCH) && __ARM_ARCH < 8 + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +// #pragma message("#define __ARM_ARCH 8") + #undef __ARM_ARCH + #define __ARM_ARCH 8 + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#endif // clang + +#include + +#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \ + defined(__ARM_FEATURE_CRYPTO) && \ + defined(__ARM_FEATURE_AES) +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #undef __ARM_FEATURE_CRYPTO + #undef __ARM_FEATURE_AES + #undef Z7_ARM_FEATURE_CRYPTO_WAS_SET +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") +#endif + +#endif // Z7_MSC_VER_ORIGINAL + +typedef uint8x16_t v128; + +#define AES_FUNC_START(name) \ + void Z7_FASTCALL name(UInt32 *ivAes, Byte *data8, size_t numBlocks) + // void Z7_FASTCALL name(v128 *p, v128 *data, size_t numBlocks) + +#define AES_FUNC_START2(name) \ +AES_FUNC_START (name); \ +ATTRIB_AES \ +AES_FUNC_START (name) + +#define MM_OP(op, dest, src) dest = op(dest, src); +#define MM_OP_m(op, src) MM_OP(op, m, src) +#define MM_OP1_m(op) m = op(m); + +#define MM_XOR( dest, src) MM_OP(veorq_u8, dest, src) +#define MM_XOR_m( src) MM_XOR(m, src) + +#define AES_E_m(k) MM_OP_m (vaeseq_u8, k) +#define AES_E_MC_m(k) AES_E_m (k) MM_OP1_m(vaesmcq_u8) + + +AES_FUNC_START2 (AesCbc_Encode_HW) +{ + if (numBlocks == 0) + return; + { + v128 * const p = (v128 *)(void *)ivAes; + v128 *data = (v128 *)(void *)data8; + v128 m = *p; + const UInt32 numRounds2 = *(const UInt32 *)(p + 1); + const v128 *w = p + (size_t)numRounds2 * 2; + const v128 k0 = p[2]; + const v128 k1 = p[3]; + const v128 k2 = p[4]; + const v128 k3 = p[5]; + const v128 k4 = p[6]; + const v128 k5 = p[7]; + const v128 k6 = p[8]; + const v128 k7 = p[9]; + const v128 k8 = p[10]; + const v128 k9 = p[11]; + const v128 k_z4 = w[-2]; + const v128 k_z3 = w[-1]; + const v128 k_z2 = w[0]; + const v128 k_z1 = w[1]; + const v128 k_z0 = w[2]; + // we don't use optimization veorq_u8(*data, k_z0) that can reduce one cycle, + // because gcc/clang compilers are not good for that optimization. + do + { + MM_XOR_m (*data) + AES_E_MC_m (k0) + AES_E_MC_m (k1) + AES_E_MC_m (k2) + AES_E_MC_m (k3) + AES_E_MC_m (k4) + AES_E_MC_m (k5) + if (numRounds2 >= 6) + { + AES_E_MC_m (k6) + AES_E_MC_m (k7) + if (numRounds2 != 6) + { + AES_E_MC_m (k8) + AES_E_MC_m (k9) + } + } + AES_E_MC_m (k_z4) + AES_E_MC_m (k_z3) + AES_E_MC_m (k_z2) + AES_E_m (k_z1) + MM_XOR_m (k_z0) + *data++ = m; + } + while (--numBlocks); + *p = m; + } +} + + +#define WOP_1(op) +#define WOP_2(op) WOP_1 (op) op (m1, 1) +#define WOP_3(op) WOP_2 (op) op (m2, 2) +#define WOP_4(op) WOP_3 (op) op (m3, 3) +#define WOP_5(op) WOP_4 (op) op (m4, 4) +#define WOP_6(op) WOP_5 (op) op (m5, 5) +#define WOP_7(op) WOP_6 (op) op (m6, 6) +#define WOP_8(op) WOP_7 (op) op (m7, 7) + + #define NUM_WAYS 8 + #define WOP_M1 WOP_8 + +#define WOP(op) op (m0, 0) WOP_M1(op) + +#define DECLARE_VAR(reg, ii) v128 reg; +#define LOAD_data( reg, ii) reg = data[ii]; +#define STORE_data( reg, ii) data[ii] = reg; +#if (NUM_WAYS > 1) +#define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1]) +#endif + +#define MM_OP_key(op, reg) MM_OP (op, reg, key) + +#define AES_D_m(k) MM_OP_m (vaesdq_u8, k) +#define AES_D_IMC_m(k) AES_D_m (k) MM_OP1_m (vaesimcq_u8) + +#define AES_XOR( reg, ii) MM_OP_key (veorq_u8, reg) +#define AES_D( reg, ii) MM_OP_key (vaesdq_u8, reg) +#define AES_E( reg, ii) MM_OP_key (vaeseq_u8, reg) + +#define AES_D_IMC( reg, ii) AES_D (reg, ii) reg = vaesimcq_u8(reg); +#define AES_E_MC( reg, ii) AES_E (reg, ii) reg = vaesmcq_u8(reg); + +#define CTR_START(reg, ii) MM_OP (vaddq_u64, ctr, one) reg = vreinterpretq_u8_u64(ctr); +#define CTR_END( reg, ii) MM_XOR (data[ii], reg) + +#define WOP_KEY(op, n) { \ + const v128 key = w[n]; \ + WOP(op) } + +#define WIDE_LOOP_START \ + dataEnd = data + numBlocks; \ + if (numBlocks >= NUM_WAYS) \ + { dataEnd -= NUM_WAYS; do { \ + +#define WIDE_LOOP_END \ + data += NUM_WAYS; \ + } while (data <= dataEnd); \ + dataEnd += NUM_WAYS; } \ + +#define SINGLE_LOOP \ + for (; data < dataEnd; data++) + + +AES_FUNC_START2 (AesCbc_Decode_HW) +{ + v128 *p = (v128 *)(void *)ivAes; + v128 *data = (v128 *)(void *)data8; + v128 iv = *p; + const v128 * const wStart = p + (size_t)*(const UInt32 *)(p + 1) * 2; + const v128 *dataEnd; + p += 2; + + WIDE_LOOP_START + { + const v128 *w = wStart; + WOP (DECLARE_VAR) + WOP (LOAD_data) + WOP_KEY (AES_D_IMC, 2) + do + { + WOP_KEY (AES_D_IMC, 1) + WOP_KEY (AES_D_IMC, 0) + w -= 2; + } + while (w != p); + WOP_KEY (AES_D, 1) + WOP_KEY (AES_XOR, 0) + MM_XOR (m0, iv) + WOP_M1 (XOR_data_M1) + LOAD_data(iv, NUM_WAYS - 1) + WOP (STORE_data) + } + WIDE_LOOP_END + + SINGLE_LOOP + { + const v128 *w = wStart; + v128 m; LOAD_data(m, 0) + AES_D_IMC_m (w[2]) + do + { + AES_D_IMC_m (w[1]) + AES_D_IMC_m (w[0]) + w -= 2; + } + while (w != p); + AES_D_m (w[1]) + MM_XOR_m (w[0]) + MM_XOR_m (iv) + LOAD_data(iv, 0) + STORE_data(m, 0) + } + + p[-2] = iv; +} + + +AES_FUNC_START2 (AesCtr_Code_HW) +{ + v128 *p = (v128 *)(void *)ivAes; + v128 *data = (v128 *)(void *)data8; + uint64x2_t ctr = vreinterpretq_u64_u8(*p); + const v128 * const wEnd = p + (size_t)*(const UInt32 *)(p + 1) * 2; + const v128 *dataEnd; +// the bug in clang: +// __builtin_neon_vsetq_lane_i64(__s0, (int8x16_t)__s1, __p2); +#if defined(__clang__) && (__clang_major__ <= 9) +#pragma GCC diagnostic ignored "-Wvector-conversion" +#endif + const uint64x2_t one = vsetq_lane_u64(1, vdupq_n_u64(0), 0); + p += 2; + + WIDE_LOOP_START + { + const v128 *w = p; + WOP (DECLARE_VAR) + WOP (CTR_START) + do + { + WOP_KEY (AES_E_MC, 0) + WOP_KEY (AES_E_MC, 1) + w += 2; + } + while (w != wEnd); + WOP_KEY (AES_E_MC, 0) + WOP_KEY (AES_E, 1) + WOP_KEY (AES_XOR, 2) + WOP (CTR_END) + } + WIDE_LOOP_END + + SINGLE_LOOP + { + const v128 *w = p; + v128 m; + CTR_START (m, 0) + do + { + AES_E_MC_m (w[0]) + AES_E_MC_m (w[1]) + w += 2; + } + while (w != wEnd); + AES_E_MC_m (w[0]) + AES_E_m (w[1]) + MM_XOR_m (w[2]) + CTR_END (m, 0) + } + + p[-2] = vreinterpretq_u8_u64(ctr); +} + +#endif // USE_HW_AES + +#endif // MY_CPU_ARM_OR_ARM64 + +#undef NUM_WAYS +#undef WOP_M1 +#undef WOP +#undef DECLARE_VAR +#undef LOAD_data +#undef STORE_data +#undef USE_INTEL_AES +#undef USE_HW_AES diff --git a/C/Alloc.c b/C/Alloc.c index 552515031..63e1a121e 100644 --- a/C/Alloc.c +++ b/C/Alloc.c @@ -1,605 +1,605 @@ -/* Alloc.c -- Memory allocation functions -2024-02-18 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#ifdef _WIN32 -#include "7zWindows.h" -#endif -#include - -#include "Alloc.h" - -#if defined(Z7_LARGE_PAGES) && defined(_WIN32) && \ - (!defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502) // < Win2003 (xp-64) - #define Z7_USE_DYN_GetLargePageMinimum -#endif - -// for debug: -#if 0 -#if defined(__CHERI__) && defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) -// #pragma message("=== Z7_ALLOC_NO_OFFSET_ALLOCATOR === ") -#define Z7_ALLOC_NO_OFFSET_ALLOCATOR -#endif -#endif - -// #define SZ_ALLOC_DEBUG -/* #define SZ_ALLOC_DEBUG */ - -/* use SZ_ALLOC_DEBUG to debug alloc/free operations */ -#ifdef SZ_ALLOC_DEBUG - -#include -#include -static int g_allocCount = 0; -#ifdef _WIN32 -static int g_allocCountMid = 0; -static int g_allocCountBig = 0; -#endif - - -#define CONVERT_INT_TO_STR(charType, tempSize) \ - char temp[tempSize]; unsigned i = 0; \ - while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \ - *s++ = (charType)('0' + (unsigned)val); \ - while (i != 0) { i--; *s++ = temp[i]; } \ - *s = 0; - -static void ConvertUInt64ToString(UInt64 val, char *s) -{ - CONVERT_INT_TO_STR(char, 24) -} - -#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) - -static void ConvertUInt64ToHex(UInt64 val, char *s) -{ - UInt64 v = val; - unsigned i; - for (i = 1;; i++) - { - v >>= 4; - if (v == 0) - break; - } - s[i] = 0; - do - { - unsigned t = (unsigned)(val & 0xF); - val >>= 4; - s[--i] = GET_HEX_CHAR(t); - } - while (i); -} - -#define DEBUG_OUT_STREAM stderr - -static void Print(const char *s) -{ - fputs(s, DEBUG_OUT_STREAM); -} - -static void PrintAligned(const char *s, size_t align) -{ - size_t len = strlen(s); - for(;;) - { - fputc(' ', DEBUG_OUT_STREAM); - if (len >= align) - break; - ++len; - } - Print(s); -} - -static void PrintLn(void) -{ - Print("\n"); -} - -static void PrintHex(UInt64 v, size_t align) -{ - char s[32]; - ConvertUInt64ToHex(v, s); - PrintAligned(s, align); -} - -static void PrintDec(int v, size_t align) -{ - char s[32]; - ConvertUInt64ToString((unsigned)v, s); - PrintAligned(s, align); -} - -static void PrintAddr(void *p) -{ - PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12); -} - - -#define PRINT_REALLOC(name, cnt, size, ptr) { \ - Print(name " "); \ - if (!ptr) PrintDec(cnt++, 10); \ - PrintHex(size, 10); \ - PrintAddr(ptr); \ - PrintLn(); } - -#define PRINT_ALLOC(name, cnt, size, ptr) { \ - Print(name " "); \ - PrintDec(cnt++, 10); \ - PrintHex(size, 10); \ - PrintAddr(ptr); \ - PrintLn(); } - -#define PRINT_FREE(name, cnt, ptr) if (ptr) { \ - Print(name " "); \ - PrintDec(--cnt, 10); \ - PrintAddr(ptr); \ - PrintLn(); } - -#else - -#ifdef _WIN32 -#define PRINT_ALLOC(name, cnt, size, ptr) -#endif -#define PRINT_FREE(name, cnt, ptr) -#define Print(s) -#define PrintLn() -#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR -#define PrintHex(v, align) -#endif -#define PrintAddr(p) - -#endif - - -/* -by specification: - malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free() - realloc(NULL, size) : the call is equivalent to malloc(size) - realloc(non_NULL, 0) : the call is equivalent to free(ptr) - -in main compilers: - malloc(0) : returns non_NULL - realloc(NULL, 0) : returns non_NULL - realloc(non_NULL, 0) : returns NULL -*/ - - -void *MyAlloc(size_t size) -{ - if (size == 0) - return NULL; - // PRINT_ALLOC("Alloc ", g_allocCount, size, NULL) - #ifdef SZ_ALLOC_DEBUG - { - void *p = malloc(size); - if (p) - { - PRINT_ALLOC("Alloc ", g_allocCount, size, p) - } - return p; - } - #else - return malloc(size); - #endif -} - -void MyFree(void *address) -{ - PRINT_FREE("Free ", g_allocCount, address) - - free(address); -} - -void *MyRealloc(void *address, size_t size) -{ - if (size == 0) - { - MyFree(address); - return NULL; - } - // PRINT_REALLOC("Realloc ", g_allocCount, size, address) - #ifdef SZ_ALLOC_DEBUG - { - void *p = realloc(address, size); - if (p) - { - PRINT_REALLOC("Realloc ", g_allocCount, size, address) - } - return p; - } - #else - return realloc(address, size); - #endif -} - - -#ifdef _WIN32 - -void *MidAlloc(size_t size) -{ - if (size == 0) - return NULL; - #ifdef SZ_ALLOC_DEBUG - { - void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); - if (p) - { - PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p) - } - return p; - } - #else - return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); - #endif -} - -void MidFree(void *address) -{ - PRINT_FREE("Free-Mid", g_allocCountMid, address) - - if (!address) - return; - VirtualFree(address, 0, MEM_RELEASE); -} - -#ifdef Z7_LARGE_PAGES - -#ifdef MEM_LARGE_PAGES - #define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES -#else - #define MY_MEM_LARGE_PAGES 0x20000000 -#endif - -extern -SIZE_T g_LargePageSize; -SIZE_T g_LargePageSize = 0; -typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID); - -void SetLargePageSize(void) -{ - SIZE_T size; -#ifdef Z7_USE_DYN_GetLargePageMinimum -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - - const - Func_GetLargePageMinimum fn = - (Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), - "GetLargePageMinimum"); - if (!fn) - return; - size = fn(); -#else - size = GetLargePageMinimum(); -#endif - if (size == 0 || (size & (size - 1)) != 0) - return; - g_LargePageSize = size; -} - -#endif // Z7_LARGE_PAGES - -void *BigAlloc(size_t size) -{ - if (size == 0) - return NULL; - - PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL) - - #ifdef Z7_LARGE_PAGES - { - SIZE_T ps = g_LargePageSize; - if (ps != 0 && ps <= (1 << 30) && size > (ps / 2)) - { - size_t size2; - ps--; - size2 = (size + ps) & ~ps; - if (size2 >= size) - { - void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE); - if (p) - { - PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p) - return p; - } - } - } - } - #endif - - return MidAlloc(size); -} - -void BigFree(void *address) -{ - PRINT_FREE("Free-Big", g_allocCountBig, address) - MidFree(address); -} - -#endif // _WIN32 - - -static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); } -static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); } -const ISzAlloc g_Alloc = { SzAlloc, SzFree }; - -#ifdef _WIN32 -static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); } -static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); } -static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); } -static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); } -const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree }; -const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; -#endif - -#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR - -#define ADJUST_ALLOC_SIZE 0 -/* -#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1) -*/ -/* - Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if - MyAlloc() can return address that is NOT multiple of sizeof(void *). -*/ - -/* - uintptr_t : C99 (optional) - : unsupported in VS6 -*/ -typedef - #ifdef _WIN32 - UINT_PTR - #elif 1 - uintptr_t - #else - ptrdiff_t - #endif - MY_uintptr_t; - -#if 0 \ - || (defined(__CHERI__) \ - || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ > 8)) -// for 128-bit pointers (cheri): -#define MY_ALIGN_PTR_DOWN(p, align) \ - ((void *)((char *)(p) - ((size_t)(MY_uintptr_t)(p) & ((align) - 1)))) -#else -#define MY_ALIGN_PTR_DOWN(p, align) \ - ((void *)((((MY_uintptr_t)(p)) & ~((MY_uintptr_t)(align) - 1)))) -#endif - -#endif - -#if !defined(_WIN32) \ - && (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \ - || defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) - #define USE_posix_memalign -#endif - -#ifndef USE_posix_memalign -#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align) -#endif - -/* - This posix_memalign() is for test purposes only. - We also need special Free() function instead of free(), - if this posix_memalign() is used. -*/ - -/* -static int posix_memalign(void **ptr, size_t align, size_t size) -{ - size_t newSize = size + align; - void *p; - void *pAligned; - *ptr = NULL; - if (newSize < size) - return 12; // ENOMEM - p = MyAlloc(newSize); - if (!p) - return 12; // ENOMEM - pAligned = MY_ALIGN_PTR_UP_PLUS(p, align); - ((void **)pAligned)[-1] = p; - *ptr = pAligned; - return 0; -} -*/ - -/* - ALLOC_ALIGN_SIZE >= sizeof(void *) - ALLOC_ALIGN_SIZE >= cache_line_size -*/ - -#define ALLOC_ALIGN_SIZE ((size_t)1 << 7) - -void *z7_AlignedAlloc(size_t size) -{ -#ifndef USE_posix_memalign - - void *p; - void *pAligned; - size_t newSize; - - /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned - block to prevent cache line sharing with another allocated blocks */ - - newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE; - if (newSize < size) - return NULL; - - p = MyAlloc(newSize); - - if (!p) - return NULL; - pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE); - - Print(" size="); PrintHex(size, 8); - Print(" a_size="); PrintHex(newSize, 8); - Print(" ptr="); PrintAddr(p); - Print(" a_ptr="); PrintAddr(pAligned); - PrintLn(); - - ((void **)pAligned)[-1] = p; - - return pAligned; - -#else - - void *p; - if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size)) - return NULL; - - Print(" posix_memalign="); PrintAddr(p); - PrintLn(); - - return p; - -#endif -} - - -void z7_AlignedFree(void *address) -{ -#ifndef USE_posix_memalign - if (address) - MyFree(((void **)address)[-1]); -#else - free(address); -#endif -} - - -static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size) -{ - UNUSED_VAR(pp) - return z7_AlignedAlloc(size); -} - - -static void SzAlignedFree(ISzAllocPtr pp, void *address) -{ - UNUSED_VAR(pp) -#ifndef USE_posix_memalign - if (address) - MyFree(((void **)address)[-1]); -#else - free(address); -#endif -} - - -const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree }; - - - -/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */ -#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR -#if 1 - #define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *)) - #define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1] -#else - // we can use this simplified code, - // if (CAlignOffsetAlloc::offset == (k * sizeof(void *)) - #define REAL_BLOCK_PTR_VAR(p) (((void **)(p))[-1]) -#endif -#endif - - -#if 0 -#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR -#include -static void PrintPtr(const char *s, const void *p) -{ - const Byte *p2 = (const Byte *)&p; - unsigned i; - printf("%s %p ", s, p); - for (i = sizeof(p); i != 0;) - { - i--; - printf("%02x", p2[i]); - } - printf("\n"); -} -#endif -#endif - - -static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size) -{ -#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) - UNUSED_VAR(pp) - return z7_AlignedAlloc(size); -#else - const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt); - void *adr; - void *pAligned; - size_t newSize; - size_t extra; - size_t alignSize = (size_t)1 << p->numAlignBits; - - if (alignSize < sizeof(void *)) - alignSize = sizeof(void *); - - if (p->offset >= alignSize) - return NULL; - - /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned - block to prevent cache line sharing with another allocated blocks */ - extra = p->offset & (sizeof(void *) - 1); - newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE; - if (newSize < size) - return NULL; - - adr = ISzAlloc_Alloc(p->baseAlloc, newSize); - - if (!adr) - return NULL; - - pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr + - alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset; - -#if 0 - printf("\nalignSize = %6x, offset=%6x, size=%8x \n", (unsigned)alignSize, (unsigned)p->offset, (unsigned)size); - PrintPtr("base", adr); - PrintPtr("alig", pAligned); -#endif - - PrintLn(); - Print("- Aligned: "); - Print(" size="); PrintHex(size, 8); - Print(" a_size="); PrintHex(newSize, 8); - Print(" ptr="); PrintAddr(adr); - Print(" a_ptr="); PrintAddr(pAligned); - PrintLn(); - - REAL_BLOCK_PTR_VAR(pAligned) = adr; - - return pAligned; -#endif -} - - -static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address) -{ -#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) - UNUSED_VAR(pp) - z7_AlignedFree(address); -#else - if (address) - { - const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt); - PrintLn(); - Print("- Aligned Free: "); - PrintLn(); - ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address)); - } -#endif -} - - -void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p) -{ - p->vt.Alloc = AlignOffsetAlloc_Alloc; - p->vt.Free = AlignOffsetAlloc_Free; -} +/* Alloc.c -- Memory allocation functions +2024-02-18 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 +#include "7zWindows.h" +#endif +#include + +#include "Alloc.h" + +#if defined(Z7_LARGE_PAGES) && defined(_WIN32) && \ + (!defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502) // < Win2003 (xp-64) + #define Z7_USE_DYN_GetLargePageMinimum +#endif + +// for debug: +#if 0 +#if defined(__CHERI__) && defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) +// #pragma message("=== Z7_ALLOC_NO_OFFSET_ALLOCATOR === ") +#define Z7_ALLOC_NO_OFFSET_ALLOCATOR +#endif +#endif + +// #define SZ_ALLOC_DEBUG +/* #define SZ_ALLOC_DEBUG */ + +/* use SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef SZ_ALLOC_DEBUG + +#include +#include +static int g_allocCount = 0; +#ifdef _WIN32 +static int g_allocCountMid = 0; +static int g_allocCountBig = 0; +#endif + + +#define CONVERT_INT_TO_STR(charType, tempSize) \ + char temp[tempSize]; unsigned i = 0; \ + while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \ + *s++ = (charType)('0' + (unsigned)val); \ + while (i != 0) { i--; *s++ = temp[i]; } \ + *s = 0; + +static void ConvertUInt64ToString(UInt64 val, char *s) +{ + CONVERT_INT_TO_STR(char, 24) +} + +#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) + +static void ConvertUInt64ToHex(UInt64 val, char *s) +{ + UInt64 v = val; + unsigned i; + for (i = 1;; i++) + { + v >>= 4; + if (v == 0) + break; + } + s[i] = 0; + do + { + unsigned t = (unsigned)(val & 0xF); + val >>= 4; + s[--i] = GET_HEX_CHAR(t); + } + while (i); +} + +#define DEBUG_OUT_STREAM stderr + +static void Print(const char *s) +{ + fputs(s, DEBUG_OUT_STREAM); +} + +static void PrintAligned(const char *s, size_t align) +{ + size_t len = strlen(s); + for(;;) + { + fputc(' ', DEBUG_OUT_STREAM); + if (len >= align) + break; + ++len; + } + Print(s); +} + +static void PrintLn(void) +{ + Print("\n"); +} + +static void PrintHex(UInt64 v, size_t align) +{ + char s[32]; + ConvertUInt64ToHex(v, s); + PrintAligned(s, align); +} + +static void PrintDec(int v, size_t align) +{ + char s[32]; + ConvertUInt64ToString((unsigned)v, s); + PrintAligned(s, align); +} + +static void PrintAddr(void *p) +{ + PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12); +} + + +#define PRINT_REALLOC(name, cnt, size, ptr) { \ + Print(name " "); \ + if (!ptr) PrintDec(cnt++, 10); \ + PrintHex(size, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#define PRINT_ALLOC(name, cnt, size, ptr) { \ + Print(name " "); \ + PrintDec(cnt++, 10); \ + PrintHex(size, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#define PRINT_FREE(name, cnt, ptr) if (ptr) { \ + Print(name " "); \ + PrintDec(--cnt, 10); \ + PrintAddr(ptr); \ + PrintLn(); } + +#else + +#ifdef _WIN32 +#define PRINT_ALLOC(name, cnt, size, ptr) +#endif +#define PRINT_FREE(name, cnt, ptr) +#define Print(s) +#define PrintLn() +#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR +#define PrintHex(v, align) +#endif +#define PrintAddr(p) + +#endif + + +/* +by specification: + malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free() + realloc(NULL, size) : the call is equivalent to malloc(size) + realloc(non_NULL, 0) : the call is equivalent to free(ptr) + +in main compilers: + malloc(0) : returns non_NULL + realloc(NULL, 0) : returns non_NULL + realloc(non_NULL, 0) : returns NULL +*/ + + +void *MyAlloc(size_t size) +{ + if (size == 0) + return NULL; + // PRINT_ALLOC("Alloc ", g_allocCount, size, NULL) + #ifdef SZ_ALLOC_DEBUG + { + void *p = malloc(size); + if (p) + { + PRINT_ALLOC("Alloc ", g_allocCount, size, p) + } + return p; + } + #else + return malloc(size); + #endif +} + +void MyFree(void *address) +{ + PRINT_FREE("Free ", g_allocCount, address) + + free(address); +} + +void *MyRealloc(void *address, size_t size) +{ + if (size == 0) + { + MyFree(address); + return NULL; + } + // PRINT_REALLOC("Realloc ", g_allocCount, size, address) + #ifdef SZ_ALLOC_DEBUG + { + void *p = realloc(address, size); + if (p) + { + PRINT_REALLOC("Realloc ", g_allocCount, size, address) + } + return p; + } + #else + return realloc(address, size); + #endif +} + + +#ifdef _WIN32 + +void *MidAlloc(size_t size) +{ + if (size == 0) + return NULL; + #ifdef SZ_ALLOC_DEBUG + { + void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + if (p) + { + PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p) + } + return p; + } + #else + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + #endif +} + +void MidFree(void *address) +{ + PRINT_FREE("Free-Mid", g_allocCountMid, address) + + if (!address) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#ifdef Z7_LARGE_PAGES + +#ifdef MEM_LARGE_PAGES + #define MY_MEM_LARGE_PAGES MEM_LARGE_PAGES +#else + #define MY_MEM_LARGE_PAGES 0x20000000 +#endif + +extern +SIZE_T g_LargePageSize; +SIZE_T g_LargePageSize = 0; +typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID); + +void SetLargePageSize(void) +{ + SIZE_T size; +#ifdef Z7_USE_DYN_GetLargePageMinimum +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + + const + Func_GetLargePageMinimum fn = + (Func_GetLargePageMinimum) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), + "GetLargePageMinimum"); + if (!fn) + return; + size = fn(); +#else + size = GetLargePageMinimum(); +#endif + if (size == 0 || (size & (size - 1)) != 0) + return; + g_LargePageSize = size; +} + +#endif // Z7_LARGE_PAGES + +void *BigAlloc(size_t size) +{ + if (size == 0) + return NULL; + + PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL) + + #ifdef Z7_LARGE_PAGES + { + SIZE_T ps = g_LargePageSize; + if (ps != 0 && ps <= (1 << 30) && size > (ps / 2)) + { + size_t size2; + ps--; + size2 = (size + ps) & ~ps; + if (size2 >= size) + { + void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY_MEM_LARGE_PAGES, PAGE_READWRITE); + if (p) + { + PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p) + return p; + } + } + } + } + #endif + + return MidAlloc(size); +} + +void BigFree(void *address) +{ + PRINT_FREE("Free-Big", g_allocCountBig, address) + MidFree(address); +} + +#endif // _WIN32 + + +static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); } +static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); } +const ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +#ifdef _WIN32 +static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); } +static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); } +static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); } +static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); } +const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree }; +const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; +#endif + +#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR + +#define ADJUST_ALLOC_SIZE 0 +/* +#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1) +*/ +/* + Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if + MyAlloc() can return address that is NOT multiple of sizeof(void *). +*/ + +/* + uintptr_t : C99 (optional) + : unsupported in VS6 +*/ +typedef + #ifdef _WIN32 + UINT_PTR + #elif 1 + uintptr_t + #else + ptrdiff_t + #endif + MY_uintptr_t; + +#if 0 \ + || (defined(__CHERI__) \ + || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ > 8)) +// for 128-bit pointers (cheri): +#define MY_ALIGN_PTR_DOWN(p, align) \ + ((void *)((char *)(p) - ((size_t)(MY_uintptr_t)(p) & ((align) - 1)))) +#else +#define MY_ALIGN_PTR_DOWN(p, align) \ + ((void *)((((MY_uintptr_t)(p)) & ~((MY_uintptr_t)(align) - 1)))) +#endif + +#endif + +#if !defined(_WIN32) \ + && (defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) \ + || defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) + #define USE_posix_memalign +#endif + +#ifndef USE_posix_memalign +#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align) +#endif + +/* + This posix_memalign() is for test purposes only. + We also need special Free() function instead of free(), + if this posix_memalign() is used. +*/ + +/* +static int posix_memalign(void **ptr, size_t align, size_t size) +{ + size_t newSize = size + align; + void *p; + void *pAligned; + *ptr = NULL; + if (newSize < size) + return 12; // ENOMEM + p = MyAlloc(newSize); + if (!p) + return 12; // ENOMEM + pAligned = MY_ALIGN_PTR_UP_PLUS(p, align); + ((void **)pAligned)[-1] = p; + *ptr = pAligned; + return 0; +} +*/ + +/* + ALLOC_ALIGN_SIZE >= sizeof(void *) + ALLOC_ALIGN_SIZE >= cache_line_size +*/ + +#define ALLOC_ALIGN_SIZE ((size_t)1 << 7) + +void *z7_AlignedAlloc(size_t size) +{ +#ifndef USE_posix_memalign + + void *p; + void *pAligned; + size_t newSize; + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + + newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + p = MyAlloc(newSize); + + if (!p) + return NULL; + pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE); + + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(p); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + ((void **)pAligned)[-1] = p; + + return pAligned; + +#else + + void *p; + if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size)) + return NULL; + + Print(" posix_memalign="); PrintAddr(p); + PrintLn(); + + return p; + +#endif +} + + +void z7_AlignedFree(void *address) +{ +#ifndef USE_posix_memalign + if (address) + MyFree(((void **)address)[-1]); +#else + free(address); +#endif +} + + +static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size) +{ + UNUSED_VAR(pp) + return z7_AlignedAlloc(size); +} + + +static void SzAlignedFree(ISzAllocPtr pp, void *address) +{ + UNUSED_VAR(pp) +#ifndef USE_posix_memalign + if (address) + MyFree(((void **)address)[-1]); +#else + free(address); +#endif +} + + +const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree }; + + + +/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */ +#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR +#if 1 + #define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *)) + #define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1] +#else + // we can use this simplified code, + // if (CAlignOffsetAlloc::offset == (k * sizeof(void *)) + #define REAL_BLOCK_PTR_VAR(p) (((void **)(p))[-1]) +#endif +#endif + + +#if 0 +#ifndef Z7_ALLOC_NO_OFFSET_ALLOCATOR +#include +static void PrintPtr(const char *s, const void *p) +{ + const Byte *p2 = (const Byte *)&p; + unsigned i; + printf("%s %p ", s, p); + for (i = sizeof(p); i != 0;) + { + i--; + printf("%02x", p2[i]); + } + printf("\n"); +} +#endif +#endif + + +static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size) +{ +#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) + UNUSED_VAR(pp) + return z7_AlignedAlloc(size); +#else + const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt); + void *adr; + void *pAligned; + size_t newSize; + size_t extra; + size_t alignSize = (size_t)1 << p->numAlignBits; + + if (alignSize < sizeof(void *)) + alignSize = sizeof(void *); + + if (p->offset >= alignSize) + return NULL; + + /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned + block to prevent cache line sharing with another allocated blocks */ + extra = p->offset & (sizeof(void *) - 1); + newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE; + if (newSize < size) + return NULL; + + adr = ISzAlloc_Alloc(p->baseAlloc, newSize); + + if (!adr) + return NULL; + + pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr + + alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset; + +#if 0 + printf("\nalignSize = %6x, offset=%6x, size=%8x \n", (unsigned)alignSize, (unsigned)p->offset, (unsigned)size); + PrintPtr("base", adr); + PrintPtr("alig", pAligned); +#endif + + PrintLn(); + Print("- Aligned: "); + Print(" size="); PrintHex(size, 8); + Print(" a_size="); PrintHex(newSize, 8); + Print(" ptr="); PrintAddr(adr); + Print(" a_ptr="); PrintAddr(pAligned); + PrintLn(); + + REAL_BLOCK_PTR_VAR(pAligned) = adr; + + return pAligned; +#endif +} + + +static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address) +{ +#if defined(Z7_ALLOC_NO_OFFSET_ALLOCATOR) + UNUSED_VAR(pp) + z7_AlignedFree(address); +#else + if (address) + { + const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt); + PrintLn(); + Print("- Aligned Free: "); + PrintLn(); + ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address)); + } +#endif +} + + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p) +{ + p->vt.Alloc = AlignOffsetAlloc_Alloc; + p->vt.Free = AlignOffsetAlloc_Free; +} diff --git a/C/Alloc.h b/C/Alloc.h index 4c684613c..01bf6b7dd 100644 --- a/C/Alloc.h +++ b/C/Alloc.h @@ -1,76 +1,76 @@ -/* Alloc.h -- Memory allocation functions -2024-01-22 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_ALLOC_H -#define ZIP7_INC_ALLOC_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* - MyFree(NULL) : is allowed, as free(NULL) - MyAlloc(0) : returns NULL : but malloc(0) is allowed to return NULL or non_NULL - MyRealloc(NULL, 0) : returns NULL : but realloc(NULL, 0) is allowed to return NULL or non_NULL -MyRealloc() is similar to realloc() for the following cases: - MyRealloc(non_NULL, 0) : returns NULL and always calls MyFree(ptr) - MyRealloc(NULL, non_ZERO) : returns NULL, if allocation failed - MyRealloc(non_NULL, non_ZERO) : returns NULL, if reallocation failed -*/ - -void *MyAlloc(size_t size); -void MyFree(void *address); -void *MyRealloc(void *address, size_t size); - -void *z7_AlignedAlloc(size_t size); -void z7_AlignedFree(void *p); - -#ifdef _WIN32 - -#ifdef Z7_LARGE_PAGES -void SetLargePageSize(void); -#endif - -void *MidAlloc(size_t size); -void MidFree(void *address); -void *BigAlloc(size_t size); -void BigFree(void *address); - -/* #define Z7_BIG_ALLOC_IS_ZERO_FILLED */ - -#else - -#define MidAlloc(size) z7_AlignedAlloc(size) -#define MidFree(address) z7_AlignedFree(address) -#define BigAlloc(size) z7_AlignedAlloc(size) -#define BigFree(address) z7_AlignedFree(address) - -#endif - -extern const ISzAlloc g_Alloc; - -#ifdef _WIN32 -extern const ISzAlloc g_BigAlloc; -extern const ISzAlloc g_MidAlloc; -#else -#define g_BigAlloc g_AlignedAlloc -#define g_MidAlloc g_AlignedAlloc -#endif - -extern const ISzAlloc g_AlignedAlloc; - - -typedef struct -{ - ISzAlloc vt; - ISzAllocPtr baseAlloc; - unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */ - size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */ -} CAlignOffsetAlloc; - -void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p); - - -EXTERN_C_END - -#endif +/* Alloc.h -- Memory allocation functions +2024-01-22 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_ALLOC_H +#define ZIP7_INC_ALLOC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* + MyFree(NULL) : is allowed, as free(NULL) + MyAlloc(0) : returns NULL : but malloc(0) is allowed to return NULL or non_NULL + MyRealloc(NULL, 0) : returns NULL : but realloc(NULL, 0) is allowed to return NULL or non_NULL +MyRealloc() is similar to realloc() for the following cases: + MyRealloc(non_NULL, 0) : returns NULL and always calls MyFree(ptr) + MyRealloc(NULL, non_ZERO) : returns NULL, if allocation failed + MyRealloc(non_NULL, non_ZERO) : returns NULL, if reallocation failed +*/ + +void *MyAlloc(size_t size); +void MyFree(void *address); +void *MyRealloc(void *address, size_t size); + +void *z7_AlignedAlloc(size_t size); +void z7_AlignedFree(void *p); + +#ifdef _WIN32 + +#ifdef Z7_LARGE_PAGES +void SetLargePageSize(void); +#endif + +void *MidAlloc(size_t size); +void MidFree(void *address); +void *BigAlloc(size_t size); +void BigFree(void *address); + +/* #define Z7_BIG_ALLOC_IS_ZERO_FILLED */ + +#else + +#define MidAlloc(size) z7_AlignedAlloc(size) +#define MidFree(address) z7_AlignedFree(address) +#define BigAlloc(size) z7_AlignedAlloc(size) +#define BigFree(address) z7_AlignedFree(address) + +#endif + +extern const ISzAlloc g_Alloc; + +#ifdef _WIN32 +extern const ISzAlloc g_BigAlloc; +extern const ISzAlloc g_MidAlloc; +#else +#define g_BigAlloc g_AlignedAlloc +#define g_MidAlloc g_AlignedAlloc +#endif + +extern const ISzAlloc g_AlignedAlloc; + + +typedef struct +{ + ISzAlloc vt; + ISzAllocPtr baseAlloc; + unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */ + size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */ +} CAlignOffsetAlloc; + +void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p); + + +EXTERN_C_END + +#endif diff --git a/C/Asm_c.mak b/C/Asm_c.mak index 2007d74db..94318163b 100644 --- a/C/Asm_c.mak +++ b/C/Asm_c.mak @@ -1,12 +1,12 @@ -!IFDEF ASM_OBJS -!IF "$(PLATFORM)" == "arm64" -$(ASM_OBJS): ../../../Asm/arm64/$(*B).S - $(COMPL_ASM_CLANG) -!ELSEIF "$(PLATFORM)" == "arm" -$(ASM_OBJS): ../../../Asm/arm/$(*B).asm - $(COMPL_ASM) -!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" -$(ASM_OBJS): ../../../Asm/x86/$(*B).asm - $(COMPL_ASM) -!ENDIF -!ENDIF +!IFDEF ASM_OBJS +!IF "$(PLATFORM)" == "arm64" +$(ASM_OBJS): ../../../Asm/arm64/$(*B).S + $(COMPL_ASM_CLANG) +!ELSEIF "$(PLATFORM)" == "arm" +$(ASM_OBJS): ../../../Asm/arm/$(*B).asm + $(COMPL_ASM) +!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" +$(ASM_OBJS): ../../../Asm/x86/$(*B).asm + $(COMPL_ASM) +!ENDIF +!ENDIF diff --git a/C/Bcj2.c b/C/Bcj2.c index c562e47ce..7cb57ad62 100644 --- a/C/Bcj2.c +++ b/C/Bcj2.c @@ -1,290 +1,290 @@ -/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) -2023-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Bcj2.h" -#include "CpuArch.h" - -#define kTopValue ((UInt32)1 << 24) -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 - -// UInt32 bcj2_stats[256 + 2][2]; - -void Bcj2Dec_Init(CBcj2Dec *p) -{ - unsigned i; - p->state = BCJ2_STREAM_RC; // BCJ2_DEC_STATE_OK; - p->ip = 0; - p->temp = 0; - p->range = 0; - p->code = 0; - for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) - p->probs[i] = kBitModelTotal >> 1; -} - -SRes Bcj2Dec_Decode(CBcj2Dec *p) -{ - UInt32 v = p->temp; - // const Byte *src; - if (p->range <= 5) - { - UInt32 code = p->code; - p->state = BCJ2_DEC_STATE_ERROR; /* for case if we return SZ_ERROR_DATA; */ - for (; p->range != 5; p->range++) - { - if (p->range == 1 && code != 0) - return SZ_ERROR_DATA; - if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) - { - p->state = BCJ2_STREAM_RC; - return SZ_OK; - } - code = (code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; - p->code = code; - } - if (code == 0xffffffff) - return SZ_ERROR_DATA; - p->range = 0xffffffff; - } - // else - { - unsigned state = p->state; - // we check BCJ2_IS_32BIT_STREAM() here instead of check in the main loop - if (BCJ2_IS_32BIT_STREAM(state)) - { - const Byte *cur = p->bufs[state]; - if (cur == p->lims[state]) - return SZ_OK; - p->bufs[state] = cur + 4; - { - const UInt32 ip = p->ip + 4; - v = GetBe32a(cur) - ip; - p->ip = ip; - } - state = BCJ2_DEC_STATE_ORIG_0; - } - if ((unsigned)(state - BCJ2_DEC_STATE_ORIG_0) < 4) - { - Byte *dest = p->dest; - for (;;) - { - if (dest == p->destLim) - { - p->state = state; - p->temp = v; - return SZ_OK; - } - *dest++ = (Byte)v; - p->dest = dest; - if (++state == BCJ2_DEC_STATE_ORIG_3 + 1) - break; - v >>= 8; - } - } - } - - // src = p->bufs[BCJ2_STREAM_MAIN]; - for (;;) - { - /* - if (BCJ2_IS_32BIT_STREAM(p->state)) - p->state = BCJ2_DEC_STATE_OK; - else - */ - { - if (p->range < kTopValue) - { - if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) - { - p->state = BCJ2_STREAM_RC; - p->temp = v; - return SZ_OK; - } - p->range <<= 8; - p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; - } - { - const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; - const Byte *srcLim; - Byte *dest = p->dest; - { - const SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src); - SizeT num = (SizeT)(p->destLim - dest); - if (num >= rem) - num = rem; - #define NUM_ITERS 4 - #if (NUM_ITERS & (NUM_ITERS - 1)) == 0 - num &= ~((SizeT)NUM_ITERS - 1); // if (NUM_ITERS == (1 << x)) - #else - num -= num % NUM_ITERS; // if (NUM_ITERS != (1 << x)) - #endif - srcLim = src + num; - } - - #define NUM_SHIFT_BITS 24 - #define ONE_ITER(indx) { \ - const unsigned b = src[indx]; \ - *dest++ = (Byte)b; \ - v = (v << NUM_SHIFT_BITS) | b; \ - if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \ - if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \ - ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \ - /* ++dest */; /* v = b; */ } - - if (src != srcLim) - for (;;) - { - /* The dependency chain of 2-cycle for (v) calculation is not big problem here. - But we can remove dependency chain with v = b in the end of loop. */ - ONE_ITER(0) - #if (NUM_ITERS > 1) - ONE_ITER(1) - #if (NUM_ITERS > 2) - ONE_ITER(2) - #if (NUM_ITERS > 3) - ONE_ITER(3) - #if (NUM_ITERS > 4) - ONE_ITER(4) - #if (NUM_ITERS > 5) - ONE_ITER(5) - #if (NUM_ITERS > 6) - ONE_ITER(6) - #if (NUM_ITERS > 7) - ONE_ITER(7) - #endif - #endif - #endif - #endif - #endif - #endif - #endif - - src += NUM_ITERS; - if (src == srcLim) - break; - } - - if (src == srcLim) - #if (NUM_ITERS > 1) - for (;;) - #endif - { - #if (NUM_ITERS > 1) - if (src == p->lims[BCJ2_STREAM_MAIN] || dest == p->destLim) - #endif - { - const SizeT num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]); - p->bufs[BCJ2_STREAM_MAIN] = src; - p->dest = dest; - p->ip += (UInt32)num; - /* state BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ - p->state = - src == p->lims[BCJ2_STREAM_MAIN] ? - (unsigned)BCJ2_STREAM_MAIN : - (unsigned)BCJ2_DEC_STATE_ORIG; - p->temp = v; - return SZ_OK; - } - #if (NUM_ITERS > 1) - ONE_ITER(0) - src++; - #endif - } - - { - const SizeT num = (SizeT)(dest - p->dest); - p->dest = dest; // p->dest += num; - p->bufs[BCJ2_STREAM_MAIN] += num; // = src; - p->ip += (UInt32)num; - } - { - UInt32 bound, ttt; - CBcj2Prob *prob; // unsigned index; - /* - prob = p->probs + (unsigned)((Byte)v == 0xe8 ? - 2 + (Byte)(v >> 8) : - ((v >> 5) & 1)); // ((Byte)v < 0xe8 ? 0 : 1)); - */ - { - const unsigned c = ((v + 0x17) >> 6) & 1; - prob = p->probs + (unsigned) - (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1)); - // (Byte) - // 8x->0 : e9->1 : xxe8->xx+2 - // 8x->0x100 : e9->0x101 : xxe8->xx - // (((0x100 - (e & ~v)) & (0x100 | (v >> 8))) + (e & v)); - // (((0x101 + (~e | v)) & (0x100 | (v >> 8))) + (e & v)); - } - ttt = *prob; - bound = (p->range >> kNumBitModelTotalBits) * ttt; - if (p->code < bound) - { - // bcj2_stats[prob - p->probs][0]++; - p->range = bound; - *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); - continue; - } - { - // bcj2_stats[prob - p->probs][1]++; - p->range -= bound; - p->code -= bound; - *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits)); - } - } - } - } - { - /* (v == 0xe8 ? 0 : 1) uses setcc instruction with additional zero register usage in x64 MSVC. */ - // const unsigned cj = ((Byte)v == 0xe8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; - const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL; - const Byte *cur = p->bufs[cj]; - Byte *dest; - SizeT rem; - if (cur == p->lims[cj]) - { - p->state = cj; - break; - } - v = GetBe32a(cur); - p->bufs[cj] = cur + 4; - { - const UInt32 ip = p->ip + 4; - v -= ip; - p->ip = ip; - } - dest = p->dest; - rem = (SizeT)(p->destLim - dest); - if (rem < 4) - { - if ((unsigned)rem > 0) { dest[0] = (Byte)v; v >>= 8; - if ((unsigned)rem > 1) { dest[1] = (Byte)v; v >>= 8; - if ((unsigned)rem > 2) { dest[2] = (Byte)v; v >>= 8; }}} - p->temp = v; - p->dest = dest + rem; - p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; - break; - } - SetUi32(dest, v) - v >>= 24; - p->dest = dest + 4; - } - } - - if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) - { - p->range <<= 8; - p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; - } - return SZ_OK; -} - -#undef NUM_ITERS -#undef ONE_ITER -#undef NUM_SHIFT_BITS -#undef kTopValue -#undef kNumBitModelTotalBits -#undef kBitModelTotal -#undef kNumMoveBits +/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) +2023-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bcj2.h" +#include "CpuArch.h" + +#define kTopValue ((UInt32)1 << 24) +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +// UInt32 bcj2_stats[256 + 2][2]; + +void Bcj2Dec_Init(CBcj2Dec *p) +{ + unsigned i; + p->state = BCJ2_STREAM_RC; // BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +SRes Bcj2Dec_Decode(CBcj2Dec *p) +{ + UInt32 v = p->temp; + // const Byte *src; + if (p->range <= 5) + { + UInt32 code = p->code; + p->state = BCJ2_DEC_STATE_ERROR; /* for case if we return SZ_ERROR_DATA; */ + for (; p->range != 5; p->range++) + { + if (p->range == 1 && code != 0) + return SZ_ERROR_DATA; + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + code = (code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + p->code = code; + } + if (code == 0xffffffff) + return SZ_ERROR_DATA; + p->range = 0xffffffff; + } + // else + { + unsigned state = p->state; + // we check BCJ2_IS_32BIT_STREAM() here instead of check in the main loop + if (BCJ2_IS_32BIT_STREAM(state)) + { + const Byte *cur = p->bufs[state]; + if (cur == p->lims[state]) + return SZ_OK; + p->bufs[state] = cur + 4; + { + const UInt32 ip = p->ip + 4; + v = GetBe32a(cur) - ip; + p->ip = ip; + } + state = BCJ2_DEC_STATE_ORIG_0; + } + if ((unsigned)(state - BCJ2_DEC_STATE_ORIG_0) < 4) + { + Byte *dest = p->dest; + for (;;) + { + if (dest == p->destLim) + { + p->state = state; + p->temp = v; + return SZ_OK; + } + *dest++ = (Byte)v; + p->dest = dest; + if (++state == BCJ2_DEC_STATE_ORIG_3 + 1) + break; + v >>= 8; + } + } + } + + // src = p->bufs[BCJ2_STREAM_MAIN]; + for (;;) + { + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; + else + */ + { + if (p->range < kTopValue) + { + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + p->temp = v; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + { + const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte *srcLim; + Byte *dest = p->dest; + { + const SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src); + SizeT num = (SizeT)(p->destLim - dest); + if (num >= rem) + num = rem; + #define NUM_ITERS 4 + #if (NUM_ITERS & (NUM_ITERS - 1)) == 0 + num &= ~((SizeT)NUM_ITERS - 1); // if (NUM_ITERS == (1 << x)) + #else + num -= num % NUM_ITERS; // if (NUM_ITERS != (1 << x)) + #endif + srcLim = src + num; + } + + #define NUM_SHIFT_BITS 24 + #define ONE_ITER(indx) { \ + const unsigned b = src[indx]; \ + *dest++ = (Byte)b; \ + v = (v << NUM_SHIFT_BITS) | b; \ + if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \ + if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \ + ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \ + /* ++dest */; /* v = b; */ } + + if (src != srcLim) + for (;;) + { + /* The dependency chain of 2-cycle for (v) calculation is not big problem here. + But we can remove dependency chain with v = b in the end of loop. */ + ONE_ITER(0) + #if (NUM_ITERS > 1) + ONE_ITER(1) + #if (NUM_ITERS > 2) + ONE_ITER(2) + #if (NUM_ITERS > 3) + ONE_ITER(3) + #if (NUM_ITERS > 4) + ONE_ITER(4) + #if (NUM_ITERS > 5) + ONE_ITER(5) + #if (NUM_ITERS > 6) + ONE_ITER(6) + #if (NUM_ITERS > 7) + ONE_ITER(7) + #endif + #endif + #endif + #endif + #endif + #endif + #endif + + src += NUM_ITERS; + if (src == srcLim) + break; + } + + if (src == srcLim) + #if (NUM_ITERS > 1) + for (;;) + #endif + { + #if (NUM_ITERS > 1) + if (src == p->lims[BCJ2_STREAM_MAIN] || dest == p->destLim) + #endif + { + const SizeT num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]); + p->bufs[BCJ2_STREAM_MAIN] = src; + p->dest = dest; + p->ip += (UInt32)num; + /* state BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + p->state = + src == p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + p->temp = v; + return SZ_OK; + } + #if (NUM_ITERS > 1) + ONE_ITER(0) + src++; + #endif + } + + { + const SizeT num = (SizeT)(dest - p->dest); + p->dest = dest; // p->dest += num; + p->bufs[BCJ2_STREAM_MAIN] += num; // = src; + p->ip += (UInt32)num; + } + { + UInt32 bound, ttt; + CBcj2Prob *prob; // unsigned index; + /* + prob = p->probs + (unsigned)((Byte)v == 0xe8 ? + 2 + (Byte)(v >> 8) : + ((v >> 5) & 1)); // ((Byte)v < 0xe8 ? 0 : 1)); + */ + { + const unsigned c = ((v + 0x17) >> 6) & 1; + prob = p->probs + (unsigned) + (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1)); + // (Byte) + // 8x->0 : e9->1 : xxe8->xx+2 + // 8x->0x100 : e9->0x101 : xxe8->xx + // (((0x100 - (e & ~v)) & (0x100 | (v >> 8))) + (e & v)); + // (((0x101 + (~e | v)) & (0x100 | (v >> 8))) + (e & v)); + } + ttt = *prob; + bound = (p->range >> kNumBitModelTotalBits) * ttt; + if (p->code < bound) + { + // bcj2_stats[prob - p->probs][0]++; + p->range = bound; + *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + continue; + } + { + // bcj2_stats[prob - p->probs][1]++; + p->range -= bound; + p->code -= bound; + *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits)); + } + } + } + } + { + /* (v == 0xe8 ? 0 : 1) uses setcc instruction with additional zero register usage in x64 MSVC. */ + // const unsigned cj = ((Byte)v == 0xe8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL; + const Byte *cur = p->bufs[cj]; + Byte *dest; + SizeT rem; + if (cur == p->lims[cj]) + { + p->state = cj; + break; + } + v = GetBe32a(cur); + p->bufs[cj] = cur + 4; + { + const UInt32 ip = p->ip + 4; + v -= ip; + p->ip = ip; + } + dest = p->dest; + rem = (SizeT)(p->destLim - dest); + if (rem < 4) + { + if ((unsigned)rem > 0) { dest[0] = (Byte)v; v >>= 8; + if ((unsigned)rem > 1) { dest[1] = (Byte)v; v >>= 8; + if ((unsigned)rem > 2) { dest[2] = (Byte)v; v >>= 8; }}} + p->temp = v; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + break; + } + SetUi32(dest, v) + v >>= 24; + p->dest = dest + 4; + } + } + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + return SZ_OK; +} + +#undef NUM_ITERS +#undef ONE_ITER +#undef NUM_SHIFT_BITS +#undef kTopValue +#undef kNumBitModelTotalBits +#undef kBitModelTotal +#undef kNumMoveBits diff --git a/C/Bcj2.h b/C/Bcj2.h index 2eda0c820..4575545b6 100644 --- a/C/Bcj2.h +++ b/C/Bcj2.h @@ -1,332 +1,332 @@ -/* Bcj2.h -- BCJ2 converter for x86 code (Branch CALL/JUMP variant2) -2023-03-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_BCJ2_H -#define ZIP7_INC_BCJ2_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define BCJ2_NUM_STREAMS 4 - -enum -{ - BCJ2_STREAM_MAIN, - BCJ2_STREAM_CALL, - BCJ2_STREAM_JUMP, - BCJ2_STREAM_RC -}; - -enum -{ - BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, - BCJ2_DEC_STATE_ORIG_1, - BCJ2_DEC_STATE_ORIG_2, - BCJ2_DEC_STATE_ORIG_3, - - BCJ2_DEC_STATE_ORIG, - BCJ2_DEC_STATE_ERROR /* after detected data error */ -}; - -enum -{ - BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, - BCJ2_ENC_STATE_FINISHED /* it's state after fully encoded stream */ -}; - - -/* #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) */ -#define BCJ2_IS_32BIT_STREAM(s) ((unsigned)((unsigned)(s) - (unsigned)BCJ2_STREAM_CALL) < 2) - -/* -CBcj2Dec / CBcj2Enc -bufs sizes: - BUF_SIZE(n) = lims[n] - bufs[n] -bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be multiply of 4: - (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 - (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 -*/ - -// typedef UInt32 CBcj2Prob; -typedef UInt16 CBcj2Prob; - -/* -BCJ2 encoder / decoder internal requirements: - - If last bytes of stream contain marker (e8/e8/0f8x), then - there is also encoded symbol (0 : no conversion) in RC stream. - - One case of overlapped instructions is supported, - if last byte of converted instruction is (0f) and next byte is (8x): - marker [xx xx xx 0f] 8x - then the pair (0f 8x) is treated as marker. -*/ - -/* ---------- BCJ2 Decoder ---------- */ - -/* -CBcj2Dec: -(dest) is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: - bufs[BCJ2_STREAM_MAIN] >= dest && - bufs[BCJ2_STREAM_MAIN] - dest >= - BUF_SIZE(BCJ2_STREAM_CALL) + - BUF_SIZE(BCJ2_STREAM_JUMP) - reserve = bufs[BCJ2_STREAM_MAIN] - dest - - ( BUF_SIZE(BCJ2_STREAM_CALL) + - BUF_SIZE(BCJ2_STREAM_JUMP) ) - and additional conditions: - if (it's first call of Bcj2Dec_Decode() after Bcj2Dec_Init()) - { - (reserve != 1) : if (ver < v23.00) - } - else // if there are more than one calls of Bcj2Dec_Decode() after Bcj2Dec_Init()) - { - (reserve >= 6) : if (ver < v23.00) - (reserve >= 4) : if (ver >= v23.00) - We need that (reserve) because after first call of Bcj2Dec_Decode(), - CBcj2Dec::temp can contain up to 4 bytes for writing to (dest). - } - (reserve == 0) is allowed, if we decode full stream via single call of Bcj2Dec_Decode(). - (reserve == 0) also is allowed in case of multi-call, if we use fixed buffers, - and (reserve) is calculated from full (final) sizes of all streams before first call. -*/ - -typedef struct -{ - const Byte *bufs[BCJ2_NUM_STREAMS]; - const Byte *lims[BCJ2_NUM_STREAMS]; - Byte *dest; - const Byte *destLim; - - unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ - - UInt32 ip; /* property of starting base for decoding */ - UInt32 temp; /* Byte temp[4]; */ - UInt32 range; - UInt32 code; - CBcj2Prob probs[2 + 256]; -} CBcj2Dec; - - -/* Note: - Bcj2Dec_Init() sets (CBcj2Dec::ip = 0) - if (ip != 0) property is required, the caller must set CBcj2Dec::ip after Bcj2Dec_Init() -*/ -void Bcj2Dec_Init(CBcj2Dec *p); - - -/* Bcj2Dec_Decode(): - returns: - SZ_OK - SZ_ERROR_DATA : if data in 5 starting bytes of BCJ2_STREAM_RC stream are not correct -*/ -SRes Bcj2Dec_Decode(CBcj2Dec *p); - -/* To check that decoding was finished you can compare - sizes of processed streams with sizes known from another sources. - You must do at least one mandatory check from the two following options: - - the check for size of processed output (ORIG) stream. - - the check for size of processed input (MAIN) stream. - additional optional checks: - - the checks for processed sizes of all input streams (MAIN, CALL, JUMP, RC) - - the checks Bcj2Dec_IsMaybeFinished*() - also before actual decoding you can check that the - following condition is met for stream sizes: - ( size(ORIG) == size(MAIN) + size(CALL) + size(JUMP) ) -*/ - -/* (state == BCJ2_STREAM_MAIN) means that decoder is ready for - additional input data in BCJ2_STREAM_MAIN stream. - Note that (state == BCJ2_STREAM_MAIN) is allowed for non-finished decoding. -*/ -#define Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) ((_p_)->state == BCJ2_STREAM_MAIN) - -/* if the stream decoding was finished correctly, then range decoder - part of CBcj2Dec also was finished, and then (CBcj2Dec::code == 0). - Note that (CBcj2Dec::code == 0) is allowed for non-finished decoding. -*/ -#define Bcj2Dec_IsMaybeFinished_code(_p_) ((_p_)->code == 0) - -/* use Bcj2Dec_IsMaybeFinished() only as additional check - after at least one mandatory check from the two following options: - - the check for size of processed output (ORIG) stream. - - the check for size of processed input (MAIN) stream. -*/ -#define Bcj2Dec_IsMaybeFinished(_p_) ( \ - Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) && \ - Bcj2Dec_IsMaybeFinished_code(_p_)) - - - -/* ---------- BCJ2 Encoder ---------- */ - -typedef enum -{ - BCJ2_ENC_FINISH_MODE_CONTINUE, - BCJ2_ENC_FINISH_MODE_END_BLOCK, - BCJ2_ENC_FINISH_MODE_END_STREAM -} EBcj2Enc_FinishMode; - -/* - BCJ2_ENC_FINISH_MODE_CONTINUE: - process non finished encoding. - It notifies the encoder that additional further calls - can provide more input data (src) than provided by current call. - In that case the CBcj2Enc encoder still can move (src) pointer - up to (srcLim), but CBcj2Enc encoder can store some of the last - processed bytes (up to 4 bytes) from src to internal CBcj2Enc::temp[] buffer. - at return: - (CBcj2Enc::src will point to position that includes - processed data and data copied to (temp[]) buffer) - That data from (temp[]) buffer will be used in further calls. - - BCJ2_ENC_FINISH_MODE_END_BLOCK: - finish encoding of current block (ended at srcLim) without RC flushing. - at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_ORIG) && - CBcj2Enc::src == CBcj2Enc::srcLim) - : it shows that block encoding was finished. And the encoder is - ready for new (src) data or for stream finish operation. - finished block means - { - CBcj2Enc has completed block encoding up to (srcLim). - (1 + 4 bytes) or (2 + 4 bytes) CALL/JUMP cortages will - not cross block boundary at (srcLim). - temporary CBcj2Enc buffer for (ORIG) src data is empty. - 3 output uncompressed streams (MAIN, CALL, JUMP) were flushed. - RC stream was not flushed. And RC stream will cross block boundary. - } - Note: some possible implementation of BCJ2 encoder could - write branch marker (e8/e8/0f8x) in one call of Bcj2Enc_Encode(), - and it could calculate symbol for RC in another call of Bcj2Enc_Encode(). - BCJ2 encoder uses ip/fileIp/fileSize/relatLimit values to calculate RC symbol. - And these CBcj2Enc variables can have different values in different Bcj2Enc_Encode() calls. - So caller must finish each block with BCJ2_ENC_FINISH_MODE_END_BLOCK - to ensure that RC symbol is calculated and written in proper block. - - BCJ2_ENC_FINISH_MODE_END_STREAM - finish encoding of stream (ended at srcLim) fully including RC flushing. - at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_FINISHED) - : it shows that stream encoding was finished fully, - and all output streams were flushed fully. - also Bcj2Enc_IsFinished() can be called. -*/ - - -/* - 32-bit relative offset in JUMP/CALL commands is - - (mod 4 GiB) for 32-bit x86 code - - signed Int32 for 64-bit x86-64 code - BCJ2 encoder also does internal relative to absolute address conversions. - And there are 2 possible ways to do it: - before v23: we used 32-bit variables and (mod 4 GiB) conversion - since v23: we use 64-bit variables and (signed Int32 offset) conversion. - The absolute address condition for conversion in v23: - ((UInt64)((Int64)ip64 - (Int64)fileIp64 + 5 + (Int32)offset) < (UInt64)fileSize64) - note that if (fileSize64 > 2 GiB). there is difference between - old (mod 4 GiB) way (v22) and new (signed Int32 offset) way (v23). - And new (v23) way is more suitable to encode 64-bit x86-64 code for (fileSize64 > 2 GiB) cases. -*/ - -/* -// for old (v22) way for conversion: -typedef UInt32 CBcj2Enc_ip_unsigned; -typedef Int32 CBcj2Enc_ip_signed; -#define BCJ2_ENC_FileSize_MAX ((UInt32)1 << 31) -*/ -typedef UInt64 CBcj2Enc_ip_unsigned; -typedef Int64 CBcj2Enc_ip_signed; - -/* maximum size of file that can be used for conversion condition */ -#define BCJ2_ENC_FileSize_MAX ((CBcj2Enc_ip_unsigned)0 - 2) - -/* default value of fileSize64_minus1 variable that means - that absolute address limitation will not be used */ -#define BCJ2_ENC_FileSizeField_UNLIMITED ((CBcj2Enc_ip_unsigned)0 - 1) - -/* calculate value that later can be set to CBcj2Enc::fileSize64_minus1 */ -#define BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize) \ - ((CBcj2Enc_ip_unsigned)(fileSize) - 1) - -/* set CBcj2Enc::fileSize64_minus1 variable from size of file */ -#define Bcj2Enc_SET_FileSize(p, fileSize) \ - (p)->fileSize64_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize); - - -typedef struct -{ - Byte *bufs[BCJ2_NUM_STREAMS]; - const Byte *lims[BCJ2_NUM_STREAMS]; - const Byte *src; - const Byte *srcLim; - - unsigned state; - EBcj2Enc_FinishMode finishMode; - - Byte context; - Byte flushRem; - Byte isFlushState; - - Byte cache; - UInt32 range; - UInt64 low; - UInt64 cacheSize; - - // UInt32 context; // for marker version, it can include marker flag. - - /* (ip64) and (fileIp64) correspond to virtual source stream position - that doesn't include data in temp[] */ - CBcj2Enc_ip_unsigned ip64; /* current (ip) position */ - CBcj2Enc_ip_unsigned fileIp64; /* start (ip) position of current file */ - CBcj2Enc_ip_unsigned fileSize64_minus1; /* size of current file (for conversion limitation) */ - UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)) : 0 means disable_conversion */ - // UInt32 relatExcludeBits; - - UInt32 tempTarget; - unsigned tempPos; /* the number of bytes that were copied to temp[] buffer - (tempPos <= 4) outside of Bcj2Enc_Encode() */ - // Byte temp[4]; // for marker version - Byte temp[8]; - CBcj2Prob probs[2 + 256]; -} CBcj2Enc; - -void Bcj2Enc_Init(CBcj2Enc *p); - - -/* -Bcj2Enc_Encode(): at exit: - p->State < BCJ2_NUM_STREAMS : we need more buffer space for output stream - (bufs[p->State] == lims[p->State]) - p->State == BCJ2_ENC_STATE_ORIG : we need more data in input src stream - (src == srcLim) - p->State == BCJ2_ENC_STATE_FINISHED : after fully encoded stream -*/ -void Bcj2Enc_Encode(CBcj2Enc *p); - -/* Bcj2Enc encoder can look ahead for up 4 bytes of source stream. - CBcj2Enc::tempPos : is the number of bytes that were copied from input stream to temp[] buffer. - (CBcj2Enc::src) after Bcj2Enc_Encode() is starting position after - fully processed data and after data copied to temp buffer. - So if the caller needs to get real number of fully processed input - bytes (without look ahead data in temp buffer), - the caller must subtruct (CBcj2Enc::tempPos) value from processed size - value that is calculated based on current (CBcj2Enc::src): - cur_processed_pos = Calc_Big_Processed_Pos(enc.src)) - - Bcj2Enc_Get_AvailInputSize_in_Temp(&enc); -*/ -/* get the size of input data that was stored in temp[] buffer: */ -#define Bcj2Enc_Get_AvailInputSize_in_Temp(p) ((p)->tempPos) - -#define Bcj2Enc_IsFinished(p) ((p)->flushRem == 0) - -/* Note : the decoder supports overlapping of marker (0f 80). - But we can eliminate such overlapping cases by setting - the limit for relative offset conversion as - CBcj2Enc::relatLimit <= (0x0f << 24) == (240 MiB) -*/ -/* default value for CBcj2Enc::relatLimit */ -#define BCJ2_ENC_RELAT_LIMIT_DEFAULT ((UInt32)0x0f << 24) -#define BCJ2_ENC_RELAT_LIMIT_MAX ((UInt32)1 << 31) -// #define BCJ2_RELAT_EXCLUDE_NUM_BITS 5 - -EXTERN_C_END - -#endif +/* Bcj2.h -- BCJ2 converter for x86 code (Branch CALL/JUMP variant2) +2023-03-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_BCJ2_H +#define ZIP7_INC_BCJ2_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define BCJ2_NUM_STREAMS 4 + +enum +{ + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC +}; + +enum +{ + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_ERROR /* after detected data error */ +}; + +enum +{ + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_FINISHED /* it's state after fully encoded stream */ +}; + + +/* #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) */ +#define BCJ2_IS_32BIT_STREAM(s) ((unsigned)((unsigned)(s) - (unsigned)BCJ2_STREAM_CALL) < 2) + +/* +CBcj2Dec / CBcj2Enc +bufs sizes: + BUF_SIZE(n) = lims[n] - bufs[n] +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be multiply of 4: + (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 + (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 +*/ + +// typedef UInt32 CBcj2Prob; +typedef UInt16 CBcj2Prob; + +/* +BCJ2 encoder / decoder internal requirements: + - If last bytes of stream contain marker (e8/e8/0f8x), then + there is also encoded symbol (0 : no conversion) in RC stream. + - One case of overlapped instructions is supported, + if last byte of converted instruction is (0f) and next byte is (8x): + marker [xx xx xx 0f] 8x + then the pair (0f 8x) is treated as marker. +*/ + +/* ---------- BCJ2 Decoder ---------- */ + +/* +CBcj2Dec: +(dest) is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: + bufs[BCJ2_STREAM_MAIN] >= dest && + bufs[BCJ2_STREAM_MAIN] - dest >= + BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) + reserve = bufs[BCJ2_STREAM_MAIN] - dest - + ( BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) ) + and additional conditions: + if (it's first call of Bcj2Dec_Decode() after Bcj2Dec_Init()) + { + (reserve != 1) : if (ver < v23.00) + } + else // if there are more than one calls of Bcj2Dec_Decode() after Bcj2Dec_Init()) + { + (reserve >= 6) : if (ver < v23.00) + (reserve >= 4) : if (ver >= v23.00) + We need that (reserve) because after first call of Bcj2Dec_Decode(), + CBcj2Dec::temp can contain up to 4 bytes for writing to (dest). + } + (reserve == 0) is allowed, if we decode full stream via single call of Bcj2Dec_Decode(). + (reserve == 0) also is allowed in case of multi-call, if we use fixed buffers, + and (reserve) is calculated from full (final) sizes of all streams before first call. +*/ + +typedef struct +{ + const Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + Byte *dest; + const Byte *destLim; + + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + + UInt32 ip; /* property of starting base for decoding */ + UInt32 temp; /* Byte temp[4]; */ + UInt32 range; + UInt32 code; + CBcj2Prob probs[2 + 256]; +} CBcj2Dec; + + +/* Note: + Bcj2Dec_Init() sets (CBcj2Dec::ip = 0) + if (ip != 0) property is required, the caller must set CBcj2Dec::ip after Bcj2Dec_Init() +*/ +void Bcj2Dec_Init(CBcj2Dec *p); + + +/* Bcj2Dec_Decode(): + returns: + SZ_OK + SZ_ERROR_DATA : if data in 5 starting bytes of BCJ2_STREAM_RC stream are not correct +*/ +SRes Bcj2Dec_Decode(CBcj2Dec *p); + +/* To check that decoding was finished you can compare + sizes of processed streams with sizes known from another sources. + You must do at least one mandatory check from the two following options: + - the check for size of processed output (ORIG) stream. + - the check for size of processed input (MAIN) stream. + additional optional checks: + - the checks for processed sizes of all input streams (MAIN, CALL, JUMP, RC) + - the checks Bcj2Dec_IsMaybeFinished*() + also before actual decoding you can check that the + following condition is met for stream sizes: + ( size(ORIG) == size(MAIN) + size(CALL) + size(JUMP) ) +*/ + +/* (state == BCJ2_STREAM_MAIN) means that decoder is ready for + additional input data in BCJ2_STREAM_MAIN stream. + Note that (state == BCJ2_STREAM_MAIN) is allowed for non-finished decoding. +*/ +#define Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) ((_p_)->state == BCJ2_STREAM_MAIN) + +/* if the stream decoding was finished correctly, then range decoder + part of CBcj2Dec also was finished, and then (CBcj2Dec::code == 0). + Note that (CBcj2Dec::code == 0) is allowed for non-finished decoding. +*/ +#define Bcj2Dec_IsMaybeFinished_code(_p_) ((_p_)->code == 0) + +/* use Bcj2Dec_IsMaybeFinished() only as additional check + after at least one mandatory check from the two following options: + - the check for size of processed output (ORIG) stream. + - the check for size of processed input (MAIN) stream. +*/ +#define Bcj2Dec_IsMaybeFinished(_p_) ( \ + Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) && \ + Bcj2Dec_IsMaybeFinished_code(_p_)) + + + +/* ---------- BCJ2 Encoder ---------- */ + +typedef enum +{ + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM +} EBcj2Enc_FinishMode; + +/* + BCJ2_ENC_FINISH_MODE_CONTINUE: + process non finished encoding. + It notifies the encoder that additional further calls + can provide more input data (src) than provided by current call. + In that case the CBcj2Enc encoder still can move (src) pointer + up to (srcLim), but CBcj2Enc encoder can store some of the last + processed bytes (up to 4 bytes) from src to internal CBcj2Enc::temp[] buffer. + at return: + (CBcj2Enc::src will point to position that includes + processed data and data copied to (temp[]) buffer) + That data from (temp[]) buffer will be used in further calls. + + BCJ2_ENC_FINISH_MODE_END_BLOCK: + finish encoding of current block (ended at srcLim) without RC flushing. + at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_ORIG) && + CBcj2Enc::src == CBcj2Enc::srcLim) + : it shows that block encoding was finished. And the encoder is + ready for new (src) data or for stream finish operation. + finished block means + { + CBcj2Enc has completed block encoding up to (srcLim). + (1 + 4 bytes) or (2 + 4 bytes) CALL/JUMP cortages will + not cross block boundary at (srcLim). + temporary CBcj2Enc buffer for (ORIG) src data is empty. + 3 output uncompressed streams (MAIN, CALL, JUMP) were flushed. + RC stream was not flushed. And RC stream will cross block boundary. + } + Note: some possible implementation of BCJ2 encoder could + write branch marker (e8/e8/0f8x) in one call of Bcj2Enc_Encode(), + and it could calculate symbol for RC in another call of Bcj2Enc_Encode(). + BCJ2 encoder uses ip/fileIp/fileSize/relatLimit values to calculate RC symbol. + And these CBcj2Enc variables can have different values in different Bcj2Enc_Encode() calls. + So caller must finish each block with BCJ2_ENC_FINISH_MODE_END_BLOCK + to ensure that RC symbol is calculated and written in proper block. + + BCJ2_ENC_FINISH_MODE_END_STREAM + finish encoding of stream (ended at srcLim) fully including RC flushing. + at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_FINISHED) + : it shows that stream encoding was finished fully, + and all output streams were flushed fully. + also Bcj2Enc_IsFinished() can be called. +*/ + + +/* + 32-bit relative offset in JUMP/CALL commands is + - (mod 4 GiB) for 32-bit x86 code + - signed Int32 for 64-bit x86-64 code + BCJ2 encoder also does internal relative to absolute address conversions. + And there are 2 possible ways to do it: + before v23: we used 32-bit variables and (mod 4 GiB) conversion + since v23: we use 64-bit variables and (signed Int32 offset) conversion. + The absolute address condition for conversion in v23: + ((UInt64)((Int64)ip64 - (Int64)fileIp64 + 5 + (Int32)offset) < (UInt64)fileSize64) + note that if (fileSize64 > 2 GiB). there is difference between + old (mod 4 GiB) way (v22) and new (signed Int32 offset) way (v23). + And new (v23) way is more suitable to encode 64-bit x86-64 code for (fileSize64 > 2 GiB) cases. +*/ + +/* +// for old (v22) way for conversion: +typedef UInt32 CBcj2Enc_ip_unsigned; +typedef Int32 CBcj2Enc_ip_signed; +#define BCJ2_ENC_FileSize_MAX ((UInt32)1 << 31) +*/ +typedef UInt64 CBcj2Enc_ip_unsigned; +typedef Int64 CBcj2Enc_ip_signed; + +/* maximum size of file that can be used for conversion condition */ +#define BCJ2_ENC_FileSize_MAX ((CBcj2Enc_ip_unsigned)0 - 2) + +/* default value of fileSize64_minus1 variable that means + that absolute address limitation will not be used */ +#define BCJ2_ENC_FileSizeField_UNLIMITED ((CBcj2Enc_ip_unsigned)0 - 1) + +/* calculate value that later can be set to CBcj2Enc::fileSize64_minus1 */ +#define BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize) \ + ((CBcj2Enc_ip_unsigned)(fileSize) - 1) + +/* set CBcj2Enc::fileSize64_minus1 variable from size of file */ +#define Bcj2Enc_SET_FileSize(p, fileSize) \ + (p)->fileSize64_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize); + + +typedef struct +{ + Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + const Byte *src; + const Byte *srcLim; + + unsigned state; + EBcj2Enc_FinishMode finishMode; + + Byte context; + Byte flushRem; + Byte isFlushState; + + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; + + // UInt32 context; // for marker version, it can include marker flag. + + /* (ip64) and (fileIp64) correspond to virtual source stream position + that doesn't include data in temp[] */ + CBcj2Enc_ip_unsigned ip64; /* current (ip) position */ + CBcj2Enc_ip_unsigned fileIp64; /* start (ip) position of current file */ + CBcj2Enc_ip_unsigned fileSize64_minus1; /* size of current file (for conversion limitation) */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)) : 0 means disable_conversion */ + // UInt32 relatExcludeBits; + + UInt32 tempTarget; + unsigned tempPos; /* the number of bytes that were copied to temp[] buffer + (tempPos <= 4) outside of Bcj2Enc_Encode() */ + // Byte temp[4]; // for marker version + Byte temp[8]; + CBcj2Prob probs[2 + 256]; +} CBcj2Enc; + +void Bcj2Enc_Init(CBcj2Enc *p); + + +/* +Bcj2Enc_Encode(): at exit: + p->State < BCJ2_NUM_STREAMS : we need more buffer space for output stream + (bufs[p->State] == lims[p->State]) + p->State == BCJ2_ENC_STATE_ORIG : we need more data in input src stream + (src == srcLim) + p->State == BCJ2_ENC_STATE_FINISHED : after fully encoded stream +*/ +void Bcj2Enc_Encode(CBcj2Enc *p); + +/* Bcj2Enc encoder can look ahead for up 4 bytes of source stream. + CBcj2Enc::tempPos : is the number of bytes that were copied from input stream to temp[] buffer. + (CBcj2Enc::src) after Bcj2Enc_Encode() is starting position after + fully processed data and after data copied to temp buffer. + So if the caller needs to get real number of fully processed input + bytes (without look ahead data in temp buffer), + the caller must subtruct (CBcj2Enc::tempPos) value from processed size + value that is calculated based on current (CBcj2Enc::src): + cur_processed_pos = Calc_Big_Processed_Pos(enc.src)) - + Bcj2Enc_Get_AvailInputSize_in_Temp(&enc); +*/ +/* get the size of input data that was stored in temp[] buffer: */ +#define Bcj2Enc_Get_AvailInputSize_in_Temp(p) ((p)->tempPos) + +#define Bcj2Enc_IsFinished(p) ((p)->flushRem == 0) + +/* Note : the decoder supports overlapping of marker (0f 80). + But we can eliminate such overlapping cases by setting + the limit for relative offset conversion as + CBcj2Enc::relatLimit <= (0x0f << 24) == (240 MiB) +*/ +/* default value for CBcj2Enc::relatLimit */ +#define BCJ2_ENC_RELAT_LIMIT_DEFAULT ((UInt32)0x0f << 24) +#define BCJ2_ENC_RELAT_LIMIT_MAX ((UInt32)1 << 31) +// #define BCJ2_RELAT_EXCLUDE_NUM_BITS 5 + +EXTERN_C_END + +#endif diff --git a/C/Bcj2Enc.c b/C/Bcj2Enc.c index 53da59035..79460bb15 100644 --- a/C/Bcj2Enc.c +++ b/C/Bcj2Enc.c @@ -1,506 +1,506 @@ -/* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2) -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -/* #define SHOW_STAT */ -#ifdef SHOW_STAT -#include -#define PRF2(s) printf("%s ip=%8x tempPos=%d src= %8x\n", s, (unsigned)p->ip64, p->tempPos, (unsigned)(p->srcLim - p->src)); -#else -#define PRF2(s) -#endif - -#include "Bcj2.h" -#include "CpuArch.h" - -#define kTopValue ((UInt32)1 << 24) -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 - -void Bcj2Enc_Init(CBcj2Enc *p) -{ - unsigned i; - p->state = BCJ2_ENC_STATE_ORIG; - p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - p->context = 0; - p->flushRem = 5; - p->isFlushState = 0; - p->cache = 0; - p->range = 0xffffffff; - p->low = 0; - p->cacheSize = 1; - p->ip64 = 0; - p->fileIp64 = 0; - p->fileSize64_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED; - p->relatLimit = BCJ2_ENC_RELAT_LIMIT_DEFAULT; - // p->relatExcludeBits = 0; - p->tempPos = 0; - for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) - p->probs[i] = kBitModelTotal >> 1; -} - -// Z7_NO_INLINE -Z7_FORCE_INLINE -static BoolInt Bcj2_RangeEnc_ShiftLow(CBcj2Enc *p) -{ - const UInt32 low = (UInt32)p->low; - const unsigned high = (unsigned) - #if defined(Z7_MSC_VER_ORIGINAL) \ - && defined(MY_CPU_X86) \ - && defined(MY_CPU_LE) \ - && !defined(MY_CPU_64BIT) - // we try to rid of __aullshr() call in MSVS-x86 - (((const UInt32 *)&p->low)[1]); // [1] : for little-endian only - #else - (p->low >> 32); - #endif - if (low < (UInt32)0xff000000 || high != 0) - { - Byte *buf = p->bufs[BCJ2_STREAM_RC]; - do - { - if (buf == p->lims[BCJ2_STREAM_RC]) - { - p->state = BCJ2_STREAM_RC; - p->bufs[BCJ2_STREAM_RC] = buf; - return True; - } - *buf++ = (Byte)(p->cache + high); - p->cache = 0xff; - } - while (--p->cacheSize); - p->bufs[BCJ2_STREAM_RC] = buf; - p->cache = (Byte)(low >> 24); - } - p->cacheSize++; - p->low = low << 8; - return False; -} - - -/* -We can use 2 alternative versions of code: -1) non-marker version: - Byte CBcj2Enc::context - Byte temp[8]; - Last byte of marker (e8/e9/[0f]8x) can be written to temp[] buffer. - Encoder writes last byte of marker (e8/e9/[0f]8x) to dest, only in conjunction - with writing branch symbol to range coder in same Bcj2Enc_Encode_2() call. - -2) marker version: - UInt32 CBcj2Enc::context - Byte CBcj2Enc::temp[4]; - MARKER_FLAG in CBcj2Enc::context shows that CBcj2Enc::context contains finded marker. - it's allowed that - one call of Bcj2Enc_Encode_2() writes last byte of marker (e8/e9/[0f]8x) to dest, - and another call of Bcj2Enc_Encode_2() does offset conversion. - So different values of (fileIp) and (fileSize) are possible - in these different Bcj2Enc_Encode_2() calls. - -Also marker version requires additional if((v & MARKER_FLAG) == 0) check in main loop. -So we use non-marker version. -*/ - -/* - Corner cases with overlap in multi-block. - before v23: there was one corner case, where converted instruction - could start in one sub-stream and finish in next sub-stream. - If multi-block (solid) encoding is used, - and BCJ2_ENC_FINISH_MODE_END_BLOCK is used for each sub-stream. - and (0f) is last byte of previous sub-stream - and (8x) is first byte of current sub-stream - then (0f 8x) pair is treated as marker by BCJ2 encoder and decoder. - BCJ2 encoder can converts 32-bit offset for that (0f 8x) cortage, - if that offset meets limit requirements. - If encoder allows 32-bit offset conversion for such overlap case, - then the data in 3 uncompressed BCJ2 streams for some sub-stream - can depend from data of previous sub-stream. - That corner case is not big problem, and it's rare case. - Since v23.00 we do additional check to prevent conversions in such overlap cases. -*/ - -/* - Bcj2Enc_Encode_2() output variables at exit: - { - if (Bcj2Enc_Encode_2() exits with (p->state == BCJ2_ENC_STATE_ORIG)) - { - it means that encoder needs more input data. - if (p->srcLim == p->src) at exit, then - { - (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) - all input data were read and processed, and we are ready for - new input data. - } - else - { - (p->srcLim != p->src) - (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) - The encoder have found e8/e9/0f_8x marker, - and p->src points to last byte of that marker, - Bcj2Enc_Encode_2() needs more input data to get totally - 5 bytes (last byte of marker and 32-bit branch offset) - as continuous array starting from p->src. - (p->srcLim - p->src < 5) requirement is met after exit. - So non-processed resedue from p->src to p->srcLim is always less than 5 bytes. - } - } - } -*/ - -Z7_NO_INLINE -static void Bcj2Enc_Encode_2(CBcj2Enc *p) -{ - if (!p->isFlushState) - { - const Byte *src; - UInt32 v; - { - const unsigned state = p->state; - if (BCJ2_IS_32BIT_STREAM(state)) - { - Byte *cur = p->bufs[state]; - if (cur == p->lims[state]) - return; - SetBe32a(cur, p->tempTarget) - p->bufs[state] = cur + 4; - } - } - p->state = BCJ2_ENC_STATE_ORIG; // for main reason of exit - src = p->src; - v = p->context; - - // #define WRITE_CONTEXT p->context = v; // for marker version - #define WRITE_CONTEXT p->context = (Byte)v; - #define WRITE_CONTEXT_AND_SRC p->src = src; WRITE_CONTEXT - - for (;;) - { - // const Byte *src; - // UInt32 v; - CBcj2Enc_ip_unsigned ip; - if (p->range < kTopValue) - { - // to reduce register pressure and code size: we save and restore local variables. - WRITE_CONTEXT_AND_SRC - if (Bcj2_RangeEnc_ShiftLow(p)) - return; - p->range <<= 8; - src = p->src; - v = p->context; - } - // src = p->src; - // #define MARKER_FLAG ((UInt32)1 << 17) - // if ((v & MARKER_FLAG) == 0) // for marker version - { - const Byte *srcLim; - Byte *dest = p->bufs[BCJ2_STREAM_MAIN]; - { - const SizeT remSrc = (SizeT)(p->srcLim - src); - SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest); - if (rem >= remSrc) - rem = remSrc; - srcLim = src + rem; - } - /* p->context contains context of previous byte: - bits [0 : 7] : src[-1], if (src) was changed in this call - bits [8 : 31] : are undefined for non-marker version - */ - // v = p->context; - #define NUM_SHIFT_BITS 24 - #define CONV_FLAG ((UInt32)1 << 16) - #define ONE_ITER { \ - b = src[0]; \ - *dest++ = (Byte)b; \ - v = (v << NUM_SHIFT_BITS) | b; \ - if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \ - if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \ - ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \ - src++; if (src == srcLim) { break; } } - - if (src != srcLim) - for (;;) - { - /* clang can generate ineffective code with setne instead of two jcc instructions. - we can use 2 iterations and external (unsigned b) to avoid that ineffective code genaration. */ - unsigned b; - ONE_ITER - ONE_ITER - } - - ip = p->ip64 + (CBcj2Enc_ip_unsigned)(SizeT)(dest - p->bufs[BCJ2_STREAM_MAIN]); - p->bufs[BCJ2_STREAM_MAIN] = dest; - p->ip64 = ip; - - if (src == srcLim) - { - WRITE_CONTEXT_AND_SRC - if (src != p->srcLim) - { - p->state = BCJ2_STREAM_MAIN; - return; - } - /* (p->src == p->srcLim) - (p->state == BCJ2_ENC_STATE_ORIG) */ - if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) - return; - /* (p->finishMode == BCJ2_ENC_FINISH_MODE_END_STREAM */ - // (p->flushRem == 5); - p->isFlushState = 1; - break; - } - src++; - // p->src = src; - } - // ip = p->ip; // for marker version - /* marker was found */ - /* (v) contains marker that was found: - bits [NUM_SHIFT_BITS : NUM_SHIFT_BITS + 7] - : value of src[-2] : xx/xx/0f - bits [0 : 7] : value of src[-1] : e8/e9/8x - */ - { - { - #if NUM_SHIFT_BITS != 24 - v &= ~(UInt32)CONV_FLAG; - #endif - // UInt32 relat = 0; - if ((SizeT)(p->srcLim - src) >= 4) - { - /* - if (relat != 0 || (Byte)v != 0xe8) - BoolInt isBigOffset = True; - */ - const UInt32 relat = GetUi32(src); - /* - #define EXCLUDE_FLAG ((UInt32)1 << 4) - #define NEED_CONVERT(rel) ((((rel) + EXCLUDE_FLAG) & (0 - EXCLUDE_FLAG * 2)) != 0) - if (p->relatExcludeBits != 0) - { - const UInt32 flag = (UInt32)1 << (p->relatExcludeBits - 1); - isBigOffset = (((relat + flag) & (0 - flag * 2)) != 0); - } - // isBigOffset = False; // for debug - */ - ip -= p->fileIp64; - // Use the following if check, if (ip) is 64-bit: - if (ip > (((v + 0x20) >> 5) & 1)) // 23.00 : we eliminate milti-block overlap for (Of 80) and (e8/e9) - if ((CBcj2Enc_ip_unsigned)((CBcj2Enc_ip_signed)ip + 4 + (Int32)relat) <= p->fileSize64_minus1) - if (((UInt32)(relat + p->relatLimit) >> 1) < p->relatLimit) - v |= CONV_FLAG; - } - else if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) - { - // (p->srcLim - src < 4) - // /* - // for non-marker version - p->ip64--; // p->ip = ip - 1; - p->bufs[BCJ2_STREAM_MAIN]--; - src--; - v >>= NUM_SHIFT_BITS; - // (0 < p->srcLim - p->src <= 4) - // */ - // v |= MARKER_FLAG; // for marker version - /* (p->state == BCJ2_ENC_STATE_ORIG) */ - WRITE_CONTEXT_AND_SRC - return; - } - { - const unsigned c = ((v + 0x17) >> 6) & 1; - CBcj2Prob *prob = p->probs + (unsigned) - (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1)); - /* - ((Byte)v == 0xe8 ? 2 + ((Byte)(v >> 8)) : - ((Byte)v < 0xe8 ? 0 : 1)); // ((v >> 5) & 1)); - */ - const unsigned ttt = *prob; - const UInt32 bound = (p->range >> kNumBitModelTotalBits) * ttt; - if ((v & CONV_FLAG) == 0) - { - // static int yyy = 0; yyy++; printf("\n!needConvert = %d\n", yyy); - // v = (Byte)v; // for marker version - p->range = bound; - *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); - // WRITE_CONTEXT_AND_SRC - continue; - } - p->low += bound; - p->range -= bound; - *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits)); - } - // p->context = src[3]; - { - // const unsigned cj = ((Byte)v == 0xe8 ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP); - const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL; - ip = p->ip64; - v = GetUi32(src); // relat - ip += 4; - p->ip64 = ip; - src += 4; - // p->src = src; - { - const UInt32 absol = (UInt32)ip + v; - Byte *cur = p->bufs[cj]; - v >>= 24; - // WRITE_CONTEXT - if (cur == p->lims[cj]) - { - p->state = cj; - p->tempTarget = absol; - WRITE_CONTEXT_AND_SRC - return; - } - SetBe32a(cur, absol) - p->bufs[cj] = cur + 4; - } - } - } - } - } // end of loop - } - - for (; p->flushRem != 0; p->flushRem--) - if (Bcj2_RangeEnc_ShiftLow(p)) - return; - p->state = BCJ2_ENC_STATE_FINISHED; -} - - -/* -BCJ2 encoder needs look ahead for up to 4 bytes in (src) buffer. -So base function Bcj2Enc_Encode_2() - in BCJ2_ENC_FINISH_MODE_CONTINUE mode can return with - (p->state == BCJ2_ENC_STATE_ORIG && p->src < p->srcLim) -Bcj2Enc_Encode() solves that look ahead problem by using p->temp[] buffer. - so if (p->state == BCJ2_ENC_STATE_ORIG) after Bcj2Enc_Encode(), - then (p->src == p->srcLim). - And the caller's code is simpler with Bcj2Enc_Encode(). -*/ - -Z7_NO_INLINE -void Bcj2Enc_Encode(CBcj2Enc *p) -{ - PRF2("\n----") - if (p->tempPos != 0) - { - /* extra: number of bytes that were copied from (src) to (temp) buffer in this call */ - unsigned extra = 0; - /* We will touch only minimal required number of bytes in input (src) stream. - So we will add input bytes from (src) stream to temp[] with step of 1 byte. - We don't add new bytes to temp[] before Bcj2Enc_Encode_2() call - in first loop iteration because - - previous call of Bcj2Enc_Encode() could use another (finishMode), - - previous call could finish with (p->state != BCJ2_ENC_STATE_ORIG). - the case with full temp[] buffer (p->tempPos == 4) is possible here. - */ - for (;;) - { - // (0 < p->tempPos <= 5) // in non-marker version - /* p->src : the current src data position including extra bytes - that were copied to temp[] buffer in this call */ - const Byte *src = p->src; - const Byte *srcLim = p->srcLim; - const EBcj2Enc_FinishMode finishMode = p->finishMode; - if (src != srcLim) - { - /* if there are some src data after the data copied to temp[], - then we use MODE_CONTINUE for temp data */ - p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - } - p->src = p->temp; - p->srcLim = p->temp + p->tempPos; - PRF2(" ") - Bcj2Enc_Encode_2(p); - { - const unsigned num = (unsigned)(p->src - p->temp); - const unsigned tempPos = p->tempPos - num; - unsigned i; - p->tempPos = tempPos; - for (i = 0; i < tempPos; i++) - p->temp[i] = p->temp[(SizeT)i + num]; - // tempPos : number of bytes in temp buffer - p->src = src; - p->srcLim = srcLim; - p->finishMode = finishMode; - if (p->state != BCJ2_ENC_STATE_ORIG) - { - // (p->tempPos <= 4) // in non-marker version - /* if (the reason of exit from Bcj2Enc_Encode_2() - is not BCJ2_ENC_STATE_ORIG), - then we exit from Bcj2Enc_Encode() with same reason */ - // optional code begin : we rollback (src) and tempPos, if it's possible: - if (extra >= tempPos) - extra = tempPos; - p->src = src - extra; - p->tempPos = tempPos - extra; - // optional code end : rollback of (src) and tempPos - return; - } - /* (p->tempPos <= 4) - (p->state == BCJ2_ENC_STATE_ORIG) - so encoder needs more data than in temp[] */ - if (src == srcLim) - return; // src buffer has no more input data. - /* (src != srcLim) - so we can provide more input data from src for Bcj2Enc_Encode_2() */ - if (extra >= tempPos) - { - /* (extra >= tempPos) means that temp buffer contains - only data from src buffer of this call. - So now we can encode without temp buffer */ - p->src = src - tempPos; // rollback (src) - p->tempPos = 0; - break; - } - // we append one additional extra byte from (src) to temp[] buffer: - p->temp[tempPos] = *src; - p->tempPos = tempPos + 1; - // (0 < p->tempPos <= 5) // in non-marker version - p->src = src + 1; - extra++; - } - } - } - - PRF2("++++") - // (p->tempPos == 0) - Bcj2Enc_Encode_2(p); - PRF2("====") - - if (p->state == BCJ2_ENC_STATE_ORIG) - { - const Byte *src = p->src; - const Byte *srcLim = p->srcLim; - const unsigned rem = (unsigned)(srcLim - src); - /* (rem <= 4) here. - if (p->src != p->srcLim), then - - we copy non-processed bytes from (p->src) to temp[] buffer, - - we set p->src equal to p->srcLim. - */ - if (rem) - { - unsigned i = 0; - p->src = srcLim; - p->tempPos = rem; - // (0 < p->tempPos <= 4) - do - p->temp[i] = src[i]; - while (++i != rem); - } - // (p->tempPos <= 4) - // (p->src == p->srcLim) - } -} - -#undef PRF2 -#undef CONV_FLAG -#undef MARKER_FLAG -#undef WRITE_CONTEXT -#undef WRITE_CONTEXT_AND_SRC -#undef ONE_ITER -#undef NUM_SHIFT_BITS -#undef kTopValue -#undef kNumBitModelTotalBits -#undef kBitModelTotal -#undef kNumMoveBits +/* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2) +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +/* #define SHOW_STAT */ +#ifdef SHOW_STAT +#include +#define PRF2(s) printf("%s ip=%8x tempPos=%d src= %8x\n", s, (unsigned)p->ip64, p->tempPos, (unsigned)(p->srcLim - p->src)); +#else +#define PRF2(s) +#endif + +#include "Bcj2.h" +#include "CpuArch.h" + +#define kTopValue ((UInt32)1 << 24) +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +void Bcj2Enc_Init(CBcj2Enc *p) +{ + unsigned i; + p->state = BCJ2_ENC_STATE_ORIG; + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + p->context = 0; + p->flushRem = 5; + p->isFlushState = 0; + p->cache = 0; + p->range = 0xffffffff; + p->low = 0; + p->cacheSize = 1; + p->ip64 = 0; + p->fileIp64 = 0; + p->fileSize64_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED; + p->relatLimit = BCJ2_ENC_RELAT_LIMIT_DEFAULT; + // p->relatExcludeBits = 0; + p->tempPos = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +// Z7_NO_INLINE +Z7_FORCE_INLINE +static BoolInt Bcj2_RangeEnc_ShiftLow(CBcj2Enc *p) +{ + const UInt32 low = (UInt32)p->low; + const unsigned high = (unsigned) + #if defined(Z7_MSC_VER_ORIGINAL) \ + && defined(MY_CPU_X86) \ + && defined(MY_CPU_LE) \ + && !defined(MY_CPU_64BIT) + // we try to rid of __aullshr() call in MSVS-x86 + (((const UInt32 *)&p->low)[1]); // [1] : for little-endian only + #else + (p->low >> 32); + #endif + if (low < (UInt32)0xff000000 || high != 0) + { + Byte *buf = p->bufs[BCJ2_STREAM_RC]; + do + { + if (buf == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + p->bufs[BCJ2_STREAM_RC] = buf; + return True; + } + *buf++ = (Byte)(p->cache + high); + p->cache = 0xff; + } + while (--p->cacheSize); + p->bufs[BCJ2_STREAM_RC] = buf; + p->cache = (Byte)(low >> 24); + } + p->cacheSize++; + p->low = low << 8; + return False; +} + + +/* +We can use 2 alternative versions of code: +1) non-marker version: + Byte CBcj2Enc::context + Byte temp[8]; + Last byte of marker (e8/e9/[0f]8x) can be written to temp[] buffer. + Encoder writes last byte of marker (e8/e9/[0f]8x) to dest, only in conjunction + with writing branch symbol to range coder in same Bcj2Enc_Encode_2() call. + +2) marker version: + UInt32 CBcj2Enc::context + Byte CBcj2Enc::temp[4]; + MARKER_FLAG in CBcj2Enc::context shows that CBcj2Enc::context contains finded marker. + it's allowed that + one call of Bcj2Enc_Encode_2() writes last byte of marker (e8/e9/[0f]8x) to dest, + and another call of Bcj2Enc_Encode_2() does offset conversion. + So different values of (fileIp) and (fileSize) are possible + in these different Bcj2Enc_Encode_2() calls. + +Also marker version requires additional if((v & MARKER_FLAG) == 0) check in main loop. +So we use non-marker version. +*/ + +/* + Corner cases with overlap in multi-block. + before v23: there was one corner case, where converted instruction + could start in one sub-stream and finish in next sub-stream. + If multi-block (solid) encoding is used, + and BCJ2_ENC_FINISH_MODE_END_BLOCK is used for each sub-stream. + and (0f) is last byte of previous sub-stream + and (8x) is first byte of current sub-stream + then (0f 8x) pair is treated as marker by BCJ2 encoder and decoder. + BCJ2 encoder can converts 32-bit offset for that (0f 8x) cortage, + if that offset meets limit requirements. + If encoder allows 32-bit offset conversion for such overlap case, + then the data in 3 uncompressed BCJ2 streams for some sub-stream + can depend from data of previous sub-stream. + That corner case is not big problem, and it's rare case. + Since v23.00 we do additional check to prevent conversions in such overlap cases. +*/ + +/* + Bcj2Enc_Encode_2() output variables at exit: + { + if (Bcj2Enc_Encode_2() exits with (p->state == BCJ2_ENC_STATE_ORIG)) + { + it means that encoder needs more input data. + if (p->srcLim == p->src) at exit, then + { + (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + all input data were read and processed, and we are ready for + new input data. + } + else + { + (p->srcLim != p->src) + (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + The encoder have found e8/e9/0f_8x marker, + and p->src points to last byte of that marker, + Bcj2Enc_Encode_2() needs more input data to get totally + 5 bytes (last byte of marker and 32-bit branch offset) + as continuous array starting from p->src. + (p->srcLim - p->src < 5) requirement is met after exit. + So non-processed resedue from p->src to p->srcLim is always less than 5 bytes. + } + } + } +*/ + +Z7_NO_INLINE +static void Bcj2Enc_Encode_2(CBcj2Enc *p) +{ + if (!p->isFlushState) + { + const Byte *src; + UInt32 v; + { + const unsigned state = p->state; + if (BCJ2_IS_32BIT_STREAM(state)) + { + Byte *cur = p->bufs[state]; + if (cur == p->lims[state]) + return; + SetBe32a(cur, p->tempTarget) + p->bufs[state] = cur + 4; + } + } + p->state = BCJ2_ENC_STATE_ORIG; // for main reason of exit + src = p->src; + v = p->context; + + // #define WRITE_CONTEXT p->context = v; // for marker version + #define WRITE_CONTEXT p->context = (Byte)v; + #define WRITE_CONTEXT_AND_SRC p->src = src; WRITE_CONTEXT + + for (;;) + { + // const Byte *src; + // UInt32 v; + CBcj2Enc_ip_unsigned ip; + if (p->range < kTopValue) + { + // to reduce register pressure and code size: we save and restore local variables. + WRITE_CONTEXT_AND_SRC + if (Bcj2_RangeEnc_ShiftLow(p)) + return; + p->range <<= 8; + src = p->src; + v = p->context; + } + // src = p->src; + // #define MARKER_FLAG ((UInt32)1 << 17) + // if ((v & MARKER_FLAG) == 0) // for marker version + { + const Byte *srcLim; + Byte *dest = p->bufs[BCJ2_STREAM_MAIN]; + { + const SizeT remSrc = (SizeT)(p->srcLim - src); + SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest); + if (rem >= remSrc) + rem = remSrc; + srcLim = src + rem; + } + /* p->context contains context of previous byte: + bits [0 : 7] : src[-1], if (src) was changed in this call + bits [8 : 31] : are undefined for non-marker version + */ + // v = p->context; + #define NUM_SHIFT_BITS 24 + #define CONV_FLAG ((UInt32)1 << 16) + #define ONE_ITER { \ + b = src[0]; \ + *dest++ = (Byte)b; \ + v = (v << NUM_SHIFT_BITS) | b; \ + if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \ + if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \ + ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \ + src++; if (src == srcLim) { break; } } + + if (src != srcLim) + for (;;) + { + /* clang can generate ineffective code with setne instead of two jcc instructions. + we can use 2 iterations and external (unsigned b) to avoid that ineffective code genaration. */ + unsigned b; + ONE_ITER + ONE_ITER + } + + ip = p->ip64 + (CBcj2Enc_ip_unsigned)(SizeT)(dest - p->bufs[BCJ2_STREAM_MAIN]); + p->bufs[BCJ2_STREAM_MAIN] = dest; + p->ip64 = ip; + + if (src == srcLim) + { + WRITE_CONTEXT_AND_SRC + if (src != p->srcLim) + { + p->state = BCJ2_STREAM_MAIN; + return; + } + /* (p->src == p->srcLim) + (p->state == BCJ2_ENC_STATE_ORIG) */ + if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + return; + /* (p->finishMode == BCJ2_ENC_FINISH_MODE_END_STREAM */ + // (p->flushRem == 5); + p->isFlushState = 1; + break; + } + src++; + // p->src = src; + } + // ip = p->ip; // for marker version + /* marker was found */ + /* (v) contains marker that was found: + bits [NUM_SHIFT_BITS : NUM_SHIFT_BITS + 7] + : value of src[-2] : xx/xx/0f + bits [0 : 7] : value of src[-1] : e8/e9/8x + */ + { + { + #if NUM_SHIFT_BITS != 24 + v &= ~(UInt32)CONV_FLAG; + #endif + // UInt32 relat = 0; + if ((SizeT)(p->srcLim - src) >= 4) + { + /* + if (relat != 0 || (Byte)v != 0xe8) + BoolInt isBigOffset = True; + */ + const UInt32 relat = GetUi32(src); + /* + #define EXCLUDE_FLAG ((UInt32)1 << 4) + #define NEED_CONVERT(rel) ((((rel) + EXCLUDE_FLAG) & (0 - EXCLUDE_FLAG * 2)) != 0) + if (p->relatExcludeBits != 0) + { + const UInt32 flag = (UInt32)1 << (p->relatExcludeBits - 1); + isBigOffset = (((relat + flag) & (0 - flag * 2)) != 0); + } + // isBigOffset = False; // for debug + */ + ip -= p->fileIp64; + // Use the following if check, if (ip) is 64-bit: + if (ip > (((v + 0x20) >> 5) & 1)) // 23.00 : we eliminate milti-block overlap for (Of 80) and (e8/e9) + if ((CBcj2Enc_ip_unsigned)((CBcj2Enc_ip_signed)ip + 4 + (Int32)relat) <= p->fileSize64_minus1) + if (((UInt32)(relat + p->relatLimit) >> 1) < p->relatLimit) + v |= CONV_FLAG; + } + else if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + { + // (p->srcLim - src < 4) + // /* + // for non-marker version + p->ip64--; // p->ip = ip - 1; + p->bufs[BCJ2_STREAM_MAIN]--; + src--; + v >>= NUM_SHIFT_BITS; + // (0 < p->srcLim - p->src <= 4) + // */ + // v |= MARKER_FLAG; // for marker version + /* (p->state == BCJ2_ENC_STATE_ORIG) */ + WRITE_CONTEXT_AND_SRC + return; + } + { + const unsigned c = ((v + 0x17) >> 6) & 1; + CBcj2Prob *prob = p->probs + (unsigned) + (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1)); + /* + ((Byte)v == 0xe8 ? 2 + ((Byte)(v >> 8)) : + ((Byte)v < 0xe8 ? 0 : 1)); // ((v >> 5) & 1)); + */ + const unsigned ttt = *prob; + const UInt32 bound = (p->range >> kNumBitModelTotalBits) * ttt; + if ((v & CONV_FLAG) == 0) + { + // static int yyy = 0; yyy++; printf("\n!needConvert = %d\n", yyy); + // v = (Byte)v; // for marker version + p->range = bound; + *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + // WRITE_CONTEXT_AND_SRC + continue; + } + p->low += bound; + p->range -= bound; + *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits)); + } + // p->context = src[3]; + { + // const unsigned cj = ((Byte)v == 0xe8 ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP); + const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL; + ip = p->ip64; + v = GetUi32(src); // relat + ip += 4; + p->ip64 = ip; + src += 4; + // p->src = src; + { + const UInt32 absol = (UInt32)ip + v; + Byte *cur = p->bufs[cj]; + v >>= 24; + // WRITE_CONTEXT + if (cur == p->lims[cj]) + { + p->state = cj; + p->tempTarget = absol; + WRITE_CONTEXT_AND_SRC + return; + } + SetBe32a(cur, absol) + p->bufs[cj] = cur + 4; + } + } + } + } + } // end of loop + } + + for (; p->flushRem != 0; p->flushRem--) + if (Bcj2_RangeEnc_ShiftLow(p)) + return; + p->state = BCJ2_ENC_STATE_FINISHED; +} + + +/* +BCJ2 encoder needs look ahead for up to 4 bytes in (src) buffer. +So base function Bcj2Enc_Encode_2() + in BCJ2_ENC_FINISH_MODE_CONTINUE mode can return with + (p->state == BCJ2_ENC_STATE_ORIG && p->src < p->srcLim) +Bcj2Enc_Encode() solves that look ahead problem by using p->temp[] buffer. + so if (p->state == BCJ2_ENC_STATE_ORIG) after Bcj2Enc_Encode(), + then (p->src == p->srcLim). + And the caller's code is simpler with Bcj2Enc_Encode(). +*/ + +Z7_NO_INLINE +void Bcj2Enc_Encode(CBcj2Enc *p) +{ + PRF2("\n----") + if (p->tempPos != 0) + { + /* extra: number of bytes that were copied from (src) to (temp) buffer in this call */ + unsigned extra = 0; + /* We will touch only minimal required number of bytes in input (src) stream. + So we will add input bytes from (src) stream to temp[] with step of 1 byte. + We don't add new bytes to temp[] before Bcj2Enc_Encode_2() call + in first loop iteration because + - previous call of Bcj2Enc_Encode() could use another (finishMode), + - previous call could finish with (p->state != BCJ2_ENC_STATE_ORIG). + the case with full temp[] buffer (p->tempPos == 4) is possible here. + */ + for (;;) + { + // (0 < p->tempPos <= 5) // in non-marker version + /* p->src : the current src data position including extra bytes + that were copied to temp[] buffer in this call */ + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + const EBcj2Enc_FinishMode finishMode = p->finishMode; + if (src != srcLim) + { + /* if there are some src data after the data copied to temp[], + then we use MODE_CONTINUE for temp data */ + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + } + p->src = p->temp; + p->srcLim = p->temp + p->tempPos; + PRF2(" ") + Bcj2Enc_Encode_2(p); + { + const unsigned num = (unsigned)(p->src - p->temp); + const unsigned tempPos = p->tempPos - num; + unsigned i; + p->tempPos = tempPos; + for (i = 0; i < tempPos; i++) + p->temp[i] = p->temp[(SizeT)i + num]; + // tempPos : number of bytes in temp buffer + p->src = src; + p->srcLim = srcLim; + p->finishMode = finishMode; + if (p->state != BCJ2_ENC_STATE_ORIG) + { + // (p->tempPos <= 4) // in non-marker version + /* if (the reason of exit from Bcj2Enc_Encode_2() + is not BCJ2_ENC_STATE_ORIG), + then we exit from Bcj2Enc_Encode() with same reason */ + // optional code begin : we rollback (src) and tempPos, if it's possible: + if (extra >= tempPos) + extra = tempPos; + p->src = src - extra; + p->tempPos = tempPos - extra; + // optional code end : rollback of (src) and tempPos + return; + } + /* (p->tempPos <= 4) + (p->state == BCJ2_ENC_STATE_ORIG) + so encoder needs more data than in temp[] */ + if (src == srcLim) + return; // src buffer has no more input data. + /* (src != srcLim) + so we can provide more input data from src for Bcj2Enc_Encode_2() */ + if (extra >= tempPos) + { + /* (extra >= tempPos) means that temp buffer contains + only data from src buffer of this call. + So now we can encode without temp buffer */ + p->src = src - tempPos; // rollback (src) + p->tempPos = 0; + break; + } + // we append one additional extra byte from (src) to temp[] buffer: + p->temp[tempPos] = *src; + p->tempPos = tempPos + 1; + // (0 < p->tempPos <= 5) // in non-marker version + p->src = src + 1; + extra++; + } + } + } + + PRF2("++++") + // (p->tempPos == 0) + Bcj2Enc_Encode_2(p); + PRF2("====") + + if (p->state == BCJ2_ENC_STATE_ORIG) + { + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + const unsigned rem = (unsigned)(srcLim - src); + /* (rem <= 4) here. + if (p->src != p->srcLim), then + - we copy non-processed bytes from (p->src) to temp[] buffer, + - we set p->src equal to p->srcLim. + */ + if (rem) + { + unsigned i = 0; + p->src = srcLim; + p->tempPos = rem; + // (0 < p->tempPos <= 4) + do + p->temp[i] = src[i]; + while (++i != rem); + } + // (p->tempPos <= 4) + // (p->src == p->srcLim) + } +} + +#undef PRF2 +#undef CONV_FLAG +#undef MARKER_FLAG +#undef WRITE_CONTEXT +#undef WRITE_CONTEXT_AND_SRC +#undef ONE_ITER +#undef NUM_SHIFT_BITS +#undef kTopValue +#undef kNumBitModelTotalBits +#undef kBitModelTotal +#undef kNumMoveBits diff --git a/C/Blake2.h b/C/Blake2.h index da2416f0c..801ea7ac5 100644 --- a/C/Blake2.h +++ b/C/Blake2.h @@ -1,105 +1,105 @@ -/* Blake2.h -- BLAKE2sp Hash -2024-01-17 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_BLAKE2_H -#define ZIP7_INC_BLAKE2_H - -#include "7zTypes.h" - -#if 0 -#include "Compiler.h" -#include "CpuArch.h" -#if defined(MY_CPU_X86_OR_AMD64) -#if defined(__SSE2__) \ - || defined(_MSC_VER) && _MSC_VER > 1200 \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 30300) \ - || defined(__clang__) \ - || defined(__INTEL_COMPILER) -#include // SSE2 -#endif - -#if defined(__AVX2__) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ - || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ - || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) -#include -#if defined(__clang__) -#include -#include -#endif -#endif // avx2 -#endif // MY_CPU_X86_OR_AMD64 -#endif // 0 - -EXTERN_C_BEGIN - -#define Z7_BLAKE2S_BLOCK_SIZE 64 -#define Z7_BLAKE2S_DIGEST_SIZE 32 -#define Z7_BLAKE2SP_PARALLEL_DEGREE 8 -#define Z7_BLAKE2SP_NUM_STRUCT_WORDS 16 - -#if 1 || defined(Z7_BLAKE2SP_USE_FUNCTIONS) -typedef void (Z7_FASTCALL *Z7_BLAKE2SP_FUNC_COMPRESS)(UInt32 *states, const Byte *data, const Byte *end); -typedef void (Z7_FASTCALL *Z7_BLAKE2SP_FUNC_INIT)(UInt32 *states); -#endif - -// it's required that CBlake2sp is aligned for 32-bytes, -// because the code can use unaligned access with sse and avx256. -// but 64-bytes alignment can be better. -MY_ALIGN(64) -typedef struct -{ - union - { -#if 0 -#if defined(MY_CPU_X86_OR_AMD64) -#if defined(__SSE2__) \ - || defined(_MSC_VER) && _MSC_VER > 1200 \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 30300) \ - || defined(__clang__) \ - || defined(__INTEL_COMPILER) - __m128i _pad_align_128bit[4]; -#endif // sse2 -#if defined(__AVX2__) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ - || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ - || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) - __m256i _pad_align_256bit[2]; -#endif // avx2 -#endif // x86 -#endif // 0 - - void * _pad_align_ptr[8]; - UInt32 _pad_align_32bit[16]; - struct - { - unsigned cycPos; - unsigned _pad_unused; -#if 1 || defined(Z7_BLAKE2SP_USE_FUNCTIONS) - Z7_BLAKE2SP_FUNC_COMPRESS func_Compress_Fast; - Z7_BLAKE2SP_FUNC_COMPRESS func_Compress_Single; - Z7_BLAKE2SP_FUNC_INIT func_Init; - Z7_BLAKE2SP_FUNC_INIT func_Final; -#endif - } header; - } u; - // MY_ALIGN(64) - UInt32 states[Z7_BLAKE2SP_PARALLEL_DEGREE * Z7_BLAKE2SP_NUM_STRUCT_WORDS]; - // MY_ALIGN(64) - UInt32 buf32[Z7_BLAKE2SP_PARALLEL_DEGREE * Z7_BLAKE2SP_NUM_STRUCT_WORDS * 2]; -} CBlake2sp; - -BoolInt Blake2sp_SetFunction(CBlake2sp *p, unsigned algo); -void Blake2sp_Init(CBlake2sp *p); -void Blake2sp_InitState(CBlake2sp *p); -void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size); -void Blake2sp_Final(CBlake2sp *p, Byte *digest); -void z7_Black2sp_Prepare(void); - -EXTERN_C_END - -#endif +/* Blake2.h -- BLAKE2sp Hash +2024-01-17 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_BLAKE2_H +#define ZIP7_INC_BLAKE2_H + +#include "7zTypes.h" + +#if 0 +#include "Compiler.h" +#include "CpuArch.h" +#if defined(MY_CPU_X86_OR_AMD64) +#if defined(__SSE2__) \ + || defined(_MSC_VER) && _MSC_VER > 1200 \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 30300) \ + || defined(__clang__) \ + || defined(__INTEL_COMPILER) +#include // SSE2 +#endif + +#if defined(__AVX2__) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ + || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) +#include +#if defined(__clang__) +#include +#include +#endif +#endif // avx2 +#endif // MY_CPU_X86_OR_AMD64 +#endif // 0 + +EXTERN_C_BEGIN + +#define Z7_BLAKE2S_BLOCK_SIZE 64 +#define Z7_BLAKE2S_DIGEST_SIZE 32 +#define Z7_BLAKE2SP_PARALLEL_DEGREE 8 +#define Z7_BLAKE2SP_NUM_STRUCT_WORDS 16 + +#if 1 || defined(Z7_BLAKE2SP_USE_FUNCTIONS) +typedef void (Z7_FASTCALL *Z7_BLAKE2SP_FUNC_COMPRESS)(UInt32 *states, const Byte *data, const Byte *end); +typedef void (Z7_FASTCALL *Z7_BLAKE2SP_FUNC_INIT)(UInt32 *states); +#endif + +// it's required that CBlake2sp is aligned for 32-bytes, +// because the code can use unaligned access with sse and avx256. +// but 64-bytes alignment can be better. +MY_ALIGN(64) +typedef struct +{ + union + { +#if 0 +#if defined(MY_CPU_X86_OR_AMD64) +#if defined(__SSE2__) \ + || defined(_MSC_VER) && _MSC_VER > 1200 \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 30300) \ + || defined(__clang__) \ + || defined(__INTEL_COMPILER) + __m128i _pad_align_128bit[4]; +#endif // sse2 +#if defined(__AVX2__) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ + || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) + __m256i _pad_align_256bit[2]; +#endif // avx2 +#endif // x86 +#endif // 0 + + void * _pad_align_ptr[8]; + UInt32 _pad_align_32bit[16]; + struct + { + unsigned cycPos; + unsigned _pad_unused; +#if 1 || defined(Z7_BLAKE2SP_USE_FUNCTIONS) + Z7_BLAKE2SP_FUNC_COMPRESS func_Compress_Fast; + Z7_BLAKE2SP_FUNC_COMPRESS func_Compress_Single; + Z7_BLAKE2SP_FUNC_INIT func_Init; + Z7_BLAKE2SP_FUNC_INIT func_Final; +#endif + } header; + } u; + // MY_ALIGN(64) + UInt32 states[Z7_BLAKE2SP_PARALLEL_DEGREE * Z7_BLAKE2SP_NUM_STRUCT_WORDS]; + // MY_ALIGN(64) + UInt32 buf32[Z7_BLAKE2SP_PARALLEL_DEGREE * Z7_BLAKE2SP_NUM_STRUCT_WORDS * 2]; +} CBlake2sp; + +BoolInt Blake2sp_SetFunction(CBlake2sp *p, unsigned algo); +void Blake2sp_Init(CBlake2sp *p); +void Blake2sp_InitState(CBlake2sp *p); +void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size); +void Blake2sp_Final(CBlake2sp *p, Byte *digest); +void z7_Black2sp_Prepare(void); + +EXTERN_C_END + +#endif diff --git a/C/Blake2s.c b/C/Blake2s.c index 95c7d958f..abb907d76 100644 --- a/C/Blake2s.c +++ b/C/Blake2s.c @@ -1,2672 +1,2672 @@ -/* Blake2s.c -- BLAKE2sp Hash -2024-05-18 : Igor Pavlov : Public domain -2015-2019 : Samuel Neves : original code : CC0 1.0 Universal (CC0 1.0). */ - -#include "Precomp.h" - -// #include -#include - -#include "Blake2.h" -#include "RotateDefs.h" -#include "Compiler.h" -#include "CpuArch.h" - -/* - if defined(__AVX512F__) && defined(__AVX512VL__) - { - we define Z7_BLAKE2S_USE_AVX512_ALWAYS, - but the compiler can use avx512 for any code. - } - else if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) - { we use avx512 only for sse* and avx* branches of code. } -*/ -// #define Z7_BLAKE2S_USE_AVX512_ALWAYS // for debug - -#if defined(__SSE2__) - #define Z7_BLAKE2S_USE_VECTORS -#elif defined(MY_CPU_X86_OR_AMD64) - #if defined(_MSC_VER) && _MSC_VER > 1200 \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 30300) \ - || defined(__clang__) \ - || defined(__INTEL_COMPILER) - #define Z7_BLAKE2S_USE_VECTORS - #endif -#endif - -#ifdef Z7_BLAKE2S_USE_VECTORS - -#define Z7_BLAKE2SP_USE_FUNCTIONS - -// define Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED, if CBlake2sp can be non aligned for 32-bytes. -// #define Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED - -// SSSE3 : for _mm_shuffle_epi8 (pshufb) that improves the performance for 5-15%. -#if defined(__SSSE3__) - #define Z7_BLAKE2S_USE_SSSE3 -#elif defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1500) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40300) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40000) \ - || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 20300) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1000) - #define Z7_BLAKE2S_USE_SSSE3 -#endif - -#ifdef Z7_BLAKE2S_USE_SSSE3 -/* SSE41 : for _mm_insert_epi32 (pinsrd) - it can slightly reduce code size and improves the performance in some cases. - it's used only for last 512-1024 bytes, if FAST versions (2 or 3) of vector algos are used. - it can be used for all blocks in another algos (4+). -*/ -#if defined(__SSE4_1__) - #define Z7_BLAKE2S_USE_SSE41 -#elif defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1500) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40300) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40000) \ - || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 20300) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1000) - #define Z7_BLAKE2S_USE_SSE41 -#endif -#endif // SSSE3 - -#if defined(__GNUC__) || defined(__clang__) -#if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) && !(defined(__AVX512F__) && defined(__AVX512VL__)) - #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("avx512vl,avx512f"))) -#else - #if defined(Z7_BLAKE2S_USE_SSE41) - #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("sse4.1"))) - #elif defined(Z7_BLAKE2S_USE_SSSE3) - #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("ssse3"))) - #else - #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("sse2"))) - #endif -#endif -#endif - - -#if defined(__AVX2__) - #define Z7_BLAKE2S_USE_AVX2 -#else - #if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ - || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) - #define Z7_BLAKE2S_USE_AVX2 - #ifdef Z7_BLAKE2S_USE_AVX2 -#if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) && !(defined(__AVX512F__) && defined(__AVX512VL__)) - #define BLAKE2S_ATTRIB_AVX2 __attribute__((__target__("avx512vl,avx512f"))) -#else - #define BLAKE2S_ATTRIB_AVX2 __attribute__((__target__("avx2"))) -#endif - #endif - #elif defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) - #if (Z7_MSC_VER_ORIGINAL == 1900) - #pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX - #endif - #define Z7_BLAKE2S_USE_AVX2 - #endif -#endif - -#ifdef Z7_BLAKE2S_USE_SSE41 -#include // SSE4.1 -#elif defined(Z7_BLAKE2S_USE_SSSE3) -#include // SSSE3 -#else -#include // SSE2 -#endif - -#ifdef Z7_BLAKE2S_USE_AVX2 -#include -#if defined(__clang__) -#include -#include -#endif -#endif // avx2 - - -#if defined(__AVX512F__) && defined(__AVX512VL__) - // && defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL > 1930) - #ifndef Z7_BLAKE2S_USE_AVX512_ALWAYS - #define Z7_BLAKE2S_USE_AVX512_ALWAYS - #endif - // #pragma message ("=== Blake2s AVX512") -#endif - - -#define Z7_BLAKE2S_USE_V128_FAST -// for speed optimization for small messages: -// #define Z7_BLAKE2S_USE_V128_WAY2 - -#ifdef Z7_BLAKE2S_USE_AVX2 - -// for debug: -// gather is slow -// #define Z7_BLAKE2S_USE_GATHER - - #define Z7_BLAKE2S_USE_AVX2_FAST -// for speed optimization for small messages: -// #define Z7_BLAKE2S_USE_AVX2_WAY2 -// #define Z7_BLAKE2S_USE_AVX2_WAY4 -#if defined(Z7_BLAKE2S_USE_AVX2_WAY2) || \ - defined(Z7_BLAKE2S_USE_AVX2_WAY4) - #define Z7_BLAKE2S_USE_AVX2_WAY_SLOW -#endif -#endif - - #define Z7_BLAKE2SP_ALGO_DEFAULT 0 - #define Z7_BLAKE2SP_ALGO_SCALAR 1 -#ifdef Z7_BLAKE2S_USE_V128_FAST - #define Z7_BLAKE2SP_ALGO_V128_FAST 2 -#endif -#ifdef Z7_BLAKE2S_USE_AVX2_FAST - #define Z7_BLAKE2SP_ALGO_V256_FAST 3 -#endif - #define Z7_BLAKE2SP_ALGO_V128_WAY1 4 -#ifdef Z7_BLAKE2S_USE_V128_WAY2 - #define Z7_BLAKE2SP_ALGO_V128_WAY2 5 -#endif -#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 - #define Z7_BLAKE2SP_ALGO_V256_WAY2 6 -#endif -#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 - #define Z7_BLAKE2SP_ALGO_V256_WAY4 7 -#endif - -#endif // Z7_BLAKE2S_USE_VECTORS - - - - -#define BLAKE2S_FINAL_FLAG (~(UInt32)0) -#define NSW Z7_BLAKE2SP_NUM_STRUCT_WORDS -#define SUPER_BLOCK_SIZE (Z7_BLAKE2S_BLOCK_SIZE * Z7_BLAKE2SP_PARALLEL_DEGREE) -#define SUPER_BLOCK_MASK (SUPER_BLOCK_SIZE - 1) - -#define V_INDEX_0_0 0 -#define V_INDEX_1_0 1 -#define V_INDEX_2_0 2 -#define V_INDEX_3_0 3 -#define V_INDEX_0_1 4 -#define V_INDEX_1_1 5 -#define V_INDEX_2_1 6 -#define V_INDEX_3_1 7 -#define V_INDEX_0_2 8 -#define V_INDEX_1_2 9 -#define V_INDEX_2_2 10 -#define V_INDEX_3_2 11 -#define V_INDEX_0_3 12 -#define V_INDEX_1_3 13 -#define V_INDEX_2_3 14 -#define V_INDEX_3_3 15 -#define V_INDEX_4_0 0 -#define V_INDEX_5_0 1 -#define V_INDEX_6_0 2 -#define V_INDEX_7_0 3 -#define V_INDEX_7_1 4 -#define V_INDEX_4_1 5 -#define V_INDEX_5_1 6 -#define V_INDEX_6_1 7 -#define V_INDEX_6_2 8 -#define V_INDEX_7_2 9 -#define V_INDEX_4_2 10 -#define V_INDEX_5_2 11 -#define V_INDEX_5_3 12 -#define V_INDEX_6_3 13 -#define V_INDEX_7_3 14 -#define V_INDEX_4_3 15 - -#define V(row, col) v[V_INDEX_ ## row ## _ ## col] - -#define k_Blake2s_IV_0 0x6A09E667UL -#define k_Blake2s_IV_1 0xBB67AE85UL -#define k_Blake2s_IV_2 0x3C6EF372UL -#define k_Blake2s_IV_3 0xA54FF53AUL -#define k_Blake2s_IV_4 0x510E527FUL -#define k_Blake2s_IV_5 0x9B05688CUL -#define k_Blake2s_IV_6 0x1F83D9ABUL -#define k_Blake2s_IV_7 0x5BE0CD19UL - -#define KIV(n) (k_Blake2s_IV_## n) - -#ifdef Z7_BLAKE2S_USE_VECTORS -MY_ALIGN(16) -static const UInt32 k_Blake2s_IV[8] = -{ - KIV(0), KIV(1), KIV(2), KIV(3), KIV(4), KIV(5), KIV(6), KIV(7) -}; -#endif - -#define STATE_T(s) ((s) + 8) -#define STATE_F(s) ((s) + 10) - -#ifdef Z7_BLAKE2S_USE_VECTORS - -#define LOAD_128(p) _mm_load_si128 ((const __m128i *)(const void *)(p)) -#define LOADU_128(p) _mm_loadu_si128((const __m128i *)(const void *)(p)) -#ifdef Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED - // here we use unaligned load and stores - // use this branch if CBlake2sp can be unaligned for 16 bytes - #define STOREU_128(p, r) _mm_storeu_si128((__m128i *)(void *)(p), r) - #define LOAD_128_FROM_STRUCT(p) LOADU_128(p) - #define STORE_128_TO_STRUCT(p, r) STOREU_128(p, r) -#else - // here we use aligned load and stores - // use this branch if CBlake2sp is aligned for 16 bytes - #define STORE_128(p, r) _mm_store_si128((__m128i *)(void *)(p), r) - #define LOAD_128_FROM_STRUCT(p) LOAD_128(p) - #define STORE_128_TO_STRUCT(p, r) STORE_128(p, r) -#endif - -#endif // Z7_BLAKE2S_USE_VECTORS - - -#if 0 -static void PrintState(const UInt32 *s, unsigned num) -{ - unsigned i; - printf("\n"); - for (i = 0; i < num; i++) - printf(" %08x", (unsigned)s[i]); -} -static void PrintStates2(const UInt32 *s, unsigned x, unsigned y) -{ - unsigned i; - for (i = 0; i < y; i++) - PrintState(s + i * x, x); - printf("\n"); -} -#endif - - -#define REP8_MACRO(m) { m(0) m(1) m(2) m(3) m(4) m(5) m(6) m(7) } - -#define BLAKE2S_NUM_ROUNDS 10 - -#if defined(Z7_BLAKE2S_USE_VECTORS) -#define ROUNDS_LOOP(mac) \ - { unsigned r; for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++) mac(r) } -#endif -/* -#define ROUNDS_LOOP_2(mac) \ - { unsigned r; for (r = 0; r < BLAKE2S_NUM_ROUNDS; r += 2) { mac(r) mac(r + 1) } } -*/ -#if 0 || 1 && !defined(Z7_BLAKE2S_USE_VECTORS) -#define ROUNDS_LOOP_UNROLLED(m) \ - { m(0) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) } -#endif - -#define SIGMA_TABLE(M) \ - M( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ), \ - M( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ), \ - M( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ), \ - M( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ), \ - M( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ), \ - M( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ), \ - M( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ), \ - M( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ), \ - M( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ), \ - M( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ) - -#define SIGMA_TABLE_MULT(m, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ - { a0*m,a1*m,a2*m,a3*m,a4*m,a5*m,a6*m,a7*m,a8*m,a9*m,a10*m,a11*m,a12*m,a13*m,a14*m,a15*m } -#define SIGMA_TABLE_MULT_4( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ - SIGMA_TABLE_MULT(4, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) - -// MY_ALIGN(32) -MY_ALIGN(16) -static const Byte k_Blake2s_Sigma_4[BLAKE2S_NUM_ROUNDS][16] = - { SIGMA_TABLE(SIGMA_TABLE_MULT_4) }; - -#define GET_SIGMA_PTR(p, index) \ - ((const void *)((const Byte *)(const void *)(p) + (index))) - -#define GET_STATE_TABLE_PTR_FROM_BYTE_POS(s, pos) \ - ((UInt32 *)(void *)((Byte *)(void *)(s) + (pos))) - - -#ifdef Z7_BLAKE2S_USE_VECTORS - - -#if 0 - // use loading constants from memory - // is faster for some compilers. - #define KK4(n) KIV(n), KIV(n), KIV(n), KIV(n) -MY_ALIGN(64) -static const UInt32 k_Blake2s_IV_WAY4[]= -{ - KK4(0), KK4(1), KK4(2), KK4(3), KK4(4), KK4(5), KK4(6), KK4(7) -}; - #define GET_128_IV_WAY4(i) LOAD_128(k_Blake2s_IV_WAY4 + 4 * (i)) -#else - // use constant generation: - #define GET_128_IV_WAY4(i) _mm_set1_epi32((Int32)KIV(i)) -#endif - - -#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW -#define GET_CONST_128_FROM_ARRAY32(k) \ - _mm_set_epi32((Int32)(k)[3], (Int32)(k)[2], (Int32)(k)[1], (Int32)(k)[0]) -#endif - - -#if 0 -#define k_r8 _mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1) -#define k_r16 _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2) -#define k_inc _mm_set_epi32(0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE) -#define k_iv0_128 GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 0) -#define k_iv4_128 GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 4) -#else -#if defined(Z7_BLAKE2S_USE_SSSE3) && \ - !defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) -MY_ALIGN(16) static const Byte k_r8_arr [16] = { 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8 ,13, 14, 15, 12 }; -MY_ALIGN(16) static const Byte k_r16_arr[16] = { 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 }; -#define k_r8 LOAD_128(k_r8_arr) -#define k_r16 LOAD_128(k_r16_arr) -#endif -MY_ALIGN(16) static const UInt32 k_inc_arr[4] = { Z7_BLAKE2S_BLOCK_SIZE, 0, 0, 0 }; -#define k_inc LOAD_128(k_inc_arr) -#define k_iv0_128 LOAD_128(k_Blake2s_IV + 0) -#define k_iv4_128 LOAD_128(k_Blake2s_IV + 4) -#endif - - -#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW - -#ifdef Z7_BLAKE2S_USE_AVX2 -#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 80000) - #define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1) -#else - #define MY_mm256_set_m128i _mm256_set_m128i -#endif - -#define SET_FROM_128(a) MY_mm256_set_m128i(a, a) - -#ifndef Z7_BLAKE2S_USE_AVX512_ALWAYS -MY_ALIGN(32) static const Byte k_r8_arr_256 [32] = -{ - 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8 ,13, 14, 15, 12, - 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8 ,13, 14, 15, 12 -}; -MY_ALIGN(32) static const Byte k_r16_arr_256[32] = -{ - 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13, - 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 -}; -#define k_r8_256 LOAD_256(k_r8_arr_256) -#define k_r16_256 LOAD_256(k_r16_arr_256) -#endif - -// #define k_r8_256 SET_FROM_128(_mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)) -// #define k_r16_256 SET_FROM_128(_mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2)) -// #define k_inc_256 SET_FROM_128(_mm_set_epi32(0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE)) -// #define k_iv0_256 SET_FROM_128(GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 0)) -#define k_iv4_256 SET_FROM_128(GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 4)) -#endif // Z7_BLAKE2S_USE_AVX2_WAY_SLOW -#endif - - -/* -IPC(TP) ports: -1 p__5 : skl- : SSE : shufps : _mm_shuffle_ps -2 p_15 : icl+ -1 p__5 : nhm-bdw : SSE : xorps : _mm_xor_ps -3 p015 : skl+ - -3 p015 : SSE2 : pxor : _mm_xor_si128 -2 p_15: snb-bdw : SSE2 : padd : _mm_add_epi32 -2 p0_5: mrm-wsm : -3 p015 : skl+ - -2 p_15 : ivb-,icl+ : SSE2 : punpcklqdq, punpckhqdq, punpckldq, punpckhdq -2 p_15 : : SSE2 : pshufd : _mm_shuffle_epi32 -2 p_15 : : SSE2 : pshuflw : _mm_shufflelo_epi16 -2 p_15 : : SSE2 : psrldq : -2 p_15 : : SSE3 : pshufb : _mm_shuffle_epi8 -2 p_15 : : SSE4 : pblendw : _mm_blend_epi16 -1 p__5 : hsw-skl : * - -1 p0 : SSE2 : pslld (i8) : _mm_slli_si128 -2 p01 : skl+ : - -2 p_15 : ivb- : SSE3 : palignr -1 p__5 : hsw+ - -2 p_15 + p23 : ivb-, icl+ : SSE4 : pinsrd : _mm_insert_epi32(xmm, m32, i8) -1 p__5 + p23 : hsw-skl -1 p_15 + p5 : ivb-, ice+ : SSE4 : pinsrd : _mm_insert_epi32(xmm, r32, i8) -0.5 2*p5 : hsw-skl - -2 p23 : SSE2 : movd (m32) -3 p23A : adl : -1 p5: : SSE2 : movd (r32) -*/ - -#if 0 && defined(__XOP__) -// we must debug and test __XOP__ instruction -#include -#include - #define LOAD_ROTATE_CONSTS - #define MM_ROR_EPI32(r, c) _mm_roti_epi32(r, -(c)) - #define Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED -#elif 1 && defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) - #define LOAD_ROTATE_CONSTS - #define MM_ROR_EPI32(r, c) _mm_ror_epi32(r, c) - #define Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED -#else - -// MSVC_1937+ uses "orps" instruction for _mm_or_si128(). -// But "orps" has low throughput: TP=1 for bdw-nhm. -// So it can be better to use _mm_add_epi32()/"paddd" (TP=2 for bdw-nhm) instead of "xorps". -// But "orps" is fast for modern cpus (skl+). -// So we are default with "or" version: -#if 0 || 0 && defined(Z7_MSC_VER_ORIGINAL) && Z7_MSC_VER_ORIGINAL > 1937 - // minor optimization for some old cpus, if "xorps" is slow. - #define MM128_EPI32_OR_or_ADD _mm_add_epi32 -#else - #define MM128_EPI32_OR_or_ADD _mm_or_si128 -#endif - - #define MM_ROR_EPI32_VIA_SHIFT(r, c)( \ - MM128_EPI32_OR_or_ADD( \ - _mm_srli_epi32((r), (c)), \ - _mm_slli_epi32((r), 32-(c)))) - #if defined(Z7_BLAKE2S_USE_SSSE3) || defined(Z7_BLAKE2S_USE_SSE41) - #define LOAD_ROTATE_CONSTS \ - const __m128i r8 = k_r8; \ - const __m128i r16 = k_r16; - #define MM_ROR_EPI32(r, c) ( \ - ( 8==(c)) ? _mm_shuffle_epi8(r,r8) \ - : (16==(c)) ? _mm_shuffle_epi8(r,r16) \ - : MM_ROR_EPI32_VIA_SHIFT(r, c)) - #else - #define LOAD_ROTATE_CONSTS - #define MM_ROR_EPI32(r, c) ( \ - (16==(c)) ? _mm_shufflehi_epi16(_mm_shufflelo_epi16(r, 0xb1), 0xb1) \ - : MM_ROR_EPI32_VIA_SHIFT(r, c)) - #endif -#endif - -/* -we have 3 main ways to load 4 32-bit integers to __m128i: - 1) SSE2: _mm_set_epi32() - 2) SSE2: _mm_unpacklo_epi64() / _mm_unpacklo_epi32 / _mm_cvtsi32_si128() - 3) SSE41: _mm_insert_epi32() and _mm_cvtsi32_si128() -good compiler for _mm_set_epi32() generates these instructions: -{ - movd xmm, [m32]; vpunpckldq; vpunpckldq; vpunpcklqdq; -} -good new compiler generates one instruction -{ - for _mm_insert_epi32() : { pinsrd xmm, [m32], i } - for _mm_cvtsi32_si128() : { movd xmm, [m32] } -} -but vc2010 generates slow pair of instructions: -{ - for _mm_insert_epi32() : { mov r32, [m32]; pinsrd xmm, r32, i } - for _mm_cvtsi32_si128() : { mov r32, [m32]; movd xmm, r32 } -} -_mm_insert_epi32() (pinsrd) code reduces xmm register pressure -in comparison with _mm_set_epi32() (movd + vpunpckld) code. -Note that variant with "movd xmm, r32" can be more slow, -but register pressure can be more important. -So we can force to "pinsrd" always. -*/ -// #if !defined(Z7_MSC_VER_ORIGINAL) || Z7_MSC_VER_ORIGINAL > 1600 || defined(MY_CPU_X86) -#ifdef Z7_BLAKE2S_USE_SSE41 - /* _mm_set_epi32() can be more effective for GCC and CLANG - _mm_insert_epi32() is more effective for MSVC */ - #if 0 || 1 && defined(Z7_MSC_VER_ORIGINAL) - #define Z7_BLAKE2S_USE_INSERT_INSTRUCTION - #endif -#endif // USE_SSE41 -// #endif - -#ifdef Z7_BLAKE2S_USE_INSERT_INSTRUCTION - // for SSE4.1 -#define MM_LOAD_EPI32_FROM_4_POINTERS(p0, p1, p2, p3) \ - _mm_insert_epi32( \ - _mm_insert_epi32( \ - _mm_insert_epi32( \ - _mm_cvtsi32_si128( \ - *(const Int32 *)p0), \ - *(const Int32 *)p1, 1), \ - *(const Int32 *)p2, 2), \ - *(const Int32 *)p3, 3) -#elif 0 || 1 && defined(Z7_MSC_VER_ORIGINAL) -/* MSVC 1400 implements _mm_set_epi32() via slow memory write/read. - Also _mm_unpacklo_epi32 is more effective for another MSVC compilers. - But _mm_set_epi32() is more effective for GCC and CLANG. - So we use _mm_unpacklo_epi32 for MSVC only */ -#define MM_LOAD_EPI32_FROM_4_POINTERS(p0, p1, p2, p3) \ - _mm_unpacklo_epi64( \ - _mm_unpacklo_epi32( _mm_cvtsi32_si128(*(const Int32 *)p0), \ - _mm_cvtsi32_si128(*(const Int32 *)p1)), \ - _mm_unpacklo_epi32( _mm_cvtsi32_si128(*(const Int32 *)p2), \ - _mm_cvtsi32_si128(*(const Int32 *)p3))) -#else -#define MM_LOAD_EPI32_FROM_4_POINTERS(p0, p1, p2, p3) \ - _mm_set_epi32( \ - *(const Int32 *)p3, \ - *(const Int32 *)p2, \ - *(const Int32 *)p1, \ - *(const Int32 *)p0) -#endif - -#define SET_ROW_FROM_SIGMA_BASE(input, i0, i1, i2, i3) \ - MM_LOAD_EPI32_FROM_4_POINTERS( \ - GET_SIGMA_PTR(input, i0), \ - GET_SIGMA_PTR(input, i1), \ - GET_SIGMA_PTR(input, i2), \ - GET_SIGMA_PTR(input, i3)) - -#define SET_ROW_FROM_SIGMA(input, sigma_index) \ - SET_ROW_FROM_SIGMA_BASE(input, \ - sigma[(sigma_index) ], \ - sigma[(sigma_index) + 2 * 1], \ - sigma[(sigma_index) + 2 * 2], \ - sigma[(sigma_index) + 2 * 3]) \ - - -#define ADD_128(a, b) _mm_add_epi32(a, b) -#define XOR_128(a, b) _mm_xor_si128(a, b) - -#define D_ADD_128(dest, src) dest = ADD_128(dest, src) -#define D_XOR_128(dest, src) dest = XOR_128(dest, src) -#define D_ROR_128(dest, shift) dest = MM_ROR_EPI32(dest, shift) -#define D_ADD_EPI64_128(dest, src) dest = _mm_add_epi64(dest, src) - - -#define AXR(a, b, d, shift) \ - D_ADD_128(a, b); \ - D_XOR_128(d, a); \ - D_ROR_128(d, shift); - -#define AXR2(a, b, c, d, input, sigma_index, shift1, shift2) \ - a = _mm_add_epi32 (a, SET_ROW_FROM_SIGMA(input, sigma_index)); \ - AXR(a, b, d, shift1) \ - AXR(c, d, b, shift2) - -#define ROTATE_WORDS_TO_RIGHT(a, n) \ - a = _mm_shuffle_epi32(a, _MM_SHUFFLE((3+n)&3, (2+n)&3, (1+n)&3, (0+n)&3)); - -#define AXR4(a, b, c, d, input, sigma_index) \ - AXR2(a, b, c, d, input, sigma_index, 16, 12) \ - AXR2(a, b, c, d, input, sigma_index + 1, 8, 7) \ - -#define RR2(a, b, c, d, input) \ - { \ - AXR4(a, b, c, d, input, 0) \ - ROTATE_WORDS_TO_RIGHT(b, 1) \ - ROTATE_WORDS_TO_RIGHT(c, 2) \ - ROTATE_WORDS_TO_RIGHT(d, 3) \ - AXR4(a, b, c, d, input, 8) \ - ROTATE_WORDS_TO_RIGHT(b, 3) \ - ROTATE_WORDS_TO_RIGHT(c, 2) \ - ROTATE_WORDS_TO_RIGHT(d, 1) \ - } - - -/* -Way1: -per 64 bytes block: -10 rounds * 4 iters * (7 + 2) = 360 cycles = if pslld TP=1 - * (7 + 1) = 320 cycles = if pslld TP=2 (skl+) -additional operations per 7_op_iter : -4 movzx byte mem -1 movd mem -3 pinsrd mem -1.5 pshufd -*/ - -static -#if 0 || 0 && (defined(Z7_BLAKE2S_USE_V128_WAY2) || \ - defined(Z7_BLAKE2S_USE_V256_WAY2)) - Z7_NO_INLINE -#else - Z7_FORCE_INLINE -#endif -#ifdef BLAKE2S_ATTRIB_128BIT - BLAKE2S_ATTRIB_128BIT -#endif -void -Z7_FASTCALL -Blake2s_Compress_V128_Way1(UInt32 * const s, const Byte * const input) -{ - __m128i a, b, c, d; - __m128i f0, f1; - - LOAD_ROTATE_CONSTS - d = LOAD_128_FROM_STRUCT(STATE_T(s)); - c = k_iv0_128; - a = f0 = LOAD_128_FROM_STRUCT(s); - b = f1 = LOAD_128_FROM_STRUCT(s + 4); - D_ADD_EPI64_128(d, k_inc); - STORE_128_TO_STRUCT (STATE_T(s), d); - D_XOR_128(d, k_iv4_128); - -#define RR(r) { const Byte * const sigma = k_Blake2s_Sigma_4[r]; \ - RR2(a, b, c, d, input) } - - ROUNDS_LOOP(RR) -#undef RR - - STORE_128_TO_STRUCT(s , XOR_128(f0, XOR_128(a, c))); - STORE_128_TO_STRUCT(s + 4, XOR_128(f1, XOR_128(b, d))); -} - - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_128BIT - BLAKE2S_ATTRIB_128BIT -#endif -void -Z7_FASTCALL -Blake2sp_Compress2_V128_Way1(UInt32 *s_items, const Byte *data, const Byte *end) -{ - size_t pos = 0; - do - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - Blake2s_Compress_V128_Way1(s, data); - data += Z7_BLAKE2S_BLOCK_SIZE; - pos += Z7_BLAKE2S_BLOCK_SIZE; - pos &= SUPER_BLOCK_MASK; - } - while (data != end); -} - - -#if defined(Z7_BLAKE2S_USE_V128_WAY2) || \ - defined(Z7_BLAKE2S_USE_AVX2_WAY2) -#if 1 - #define Z7_BLAKE2S_CompressSingleBlock(s, data) \ - Blake2sp_Compress2_V128_Way1(s, data, \ - (const Byte *)(const void *)(data) + Z7_BLAKE2S_BLOCK_SIZE) -#else - #define Z7_BLAKE2S_CompressSingleBlock Blake2s_Compress_V128_Way1 -#endif -#endif - - -#if (defined(Z7_BLAKE2S_USE_AVX2_WAY_SLOW) || \ - defined(Z7_BLAKE2S_USE_V128_WAY2)) && \ - !defined(Z7_BLAKE2S_USE_GATHER) -#define AXR2_LOAD_INDEXES(sigma_index) \ - const unsigned i0 = sigma[(sigma_index)]; \ - const unsigned i1 = sigma[(sigma_index) + 2 * 1]; \ - const unsigned i2 = sigma[(sigma_index) + 2 * 2]; \ - const unsigned i3 = sigma[(sigma_index) + 2 * 3]; \ - -#define SET_ROW_FROM_SIGMA_W(input) \ - SET_ROW_FROM_SIGMA_BASE(input, i0, i1, i2, i3) -#endif - - -#ifdef Z7_BLAKE2S_USE_V128_WAY2 - -#if 1 || !defined(Z7_BLAKE2S_USE_SSE41) -/* we use SET_ROW_FROM_SIGMA_BASE, that uses - (SSE4) _mm_insert_epi32(), if Z7_BLAKE2S_USE_INSERT_INSTRUCTION is defined - (SSE2) _mm_set_epi32() - MSVC can be faster for this branch: -*/ -#define AXR2_W(sigma_index, shift1, shift2) \ - { \ - AXR2_LOAD_INDEXES(sigma_index) \ - a0 = _mm_add_epi32(a0, SET_ROW_FROM_SIGMA_W(data)); \ - a1 = _mm_add_epi32(a1, SET_ROW_FROM_SIGMA_W(data + Z7_BLAKE2S_BLOCK_SIZE)); \ - AXR(a0, b0, d0, shift1) \ - AXR(a1, b1, d1, shift1) \ - AXR(c0, d0, b0, shift2) \ - AXR(c1, d1, b1, shift2) \ - } -#else -/* we use interleaved _mm_insert_epi32(): - GCC can be faster for this branch: -*/ -#define AXR2_W_PRE_INSERT(sigma_index, i) \ - { const unsigned ii = sigma[(sigma_index) + i * 2]; \ - t0 = _mm_insert_epi32(t0, *(const Int32 *)GET_SIGMA_PTR(data, ii), i); \ - t1 = _mm_insert_epi32(t1, *(const Int32 *)GET_SIGMA_PTR(data, Z7_BLAKE2S_BLOCK_SIZE + ii), i); \ - } -#define AXR2_W(sigma_index, shift1, shift2) \ - { __m128i t0, t1; \ - { const unsigned ii = sigma[sigma_index]; \ - t0 = _mm_cvtsi32_si128(*(const Int32 *)GET_SIGMA_PTR(data, ii)); \ - t1 = _mm_cvtsi32_si128(*(const Int32 *)GET_SIGMA_PTR(data, Z7_BLAKE2S_BLOCK_SIZE + ii)); \ - } \ - AXR2_W_PRE_INSERT(sigma_index, 1) \ - AXR2_W_PRE_INSERT(sigma_index, 2) \ - AXR2_W_PRE_INSERT(sigma_index, 3) \ - a0 = _mm_add_epi32(a0, t0); \ - a1 = _mm_add_epi32(a1, t1); \ - AXR(a0, b0, d0, shift1) \ - AXR(a1, b1, d1, shift1) \ - AXR(c0, d0, b0, shift2) \ - AXR(c1, d1, b1, shift2) \ - } -#endif - - -#define AXR4_W(sigma_index) \ - AXR2_W(sigma_index, 16, 12) \ - AXR2_W(sigma_index + 1, 8, 7) \ - -#define WW(r) \ - { const Byte * const sigma = k_Blake2s_Sigma_4[r]; \ - AXR4_W(0) \ - ROTATE_WORDS_TO_RIGHT(b0, 1) \ - ROTATE_WORDS_TO_RIGHT(b1, 1) \ - ROTATE_WORDS_TO_RIGHT(c0, 2) \ - ROTATE_WORDS_TO_RIGHT(c1, 2) \ - ROTATE_WORDS_TO_RIGHT(d0, 3) \ - ROTATE_WORDS_TO_RIGHT(d1, 3) \ - AXR4_W(8) \ - ROTATE_WORDS_TO_RIGHT(b0, 3) \ - ROTATE_WORDS_TO_RIGHT(b1, 3) \ - ROTATE_WORDS_TO_RIGHT(c0, 2) \ - ROTATE_WORDS_TO_RIGHT(c1, 2) \ - ROTATE_WORDS_TO_RIGHT(d0, 1) \ - ROTATE_WORDS_TO_RIGHT(d1, 1) \ - } - - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_128BIT - BLAKE2S_ATTRIB_128BIT -#endif -void -Z7_FASTCALL -Blake2sp_Compress2_V128_Way2(UInt32 *s_items, const Byte *data, const Byte *end) -{ - size_t pos = 0; - end -= Z7_BLAKE2S_BLOCK_SIZE; - - if (data != end) - { - LOAD_ROTATE_CONSTS - do - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - __m128i a0, b0, c0, d0; - __m128i a1, b1, c1, d1; - { - const __m128i inc = k_inc; - const __m128i temp = k_iv4_128; - d0 = LOAD_128_FROM_STRUCT (STATE_T(s)); - d1 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW)); - D_ADD_EPI64_128(d0, inc); - D_ADD_EPI64_128(d1, inc); - STORE_128_TO_STRUCT (STATE_T(s ), d0); - STORE_128_TO_STRUCT (STATE_T(s + NSW), d1); - D_XOR_128(d0, temp); - D_XOR_128(d1, temp); - } - c1 = c0 = k_iv0_128; - a0 = LOAD_128_FROM_STRUCT(s); - b0 = LOAD_128_FROM_STRUCT(s + 4); - a1 = LOAD_128_FROM_STRUCT(s + NSW); - b1 = LOAD_128_FROM_STRUCT(s + NSW + 4); - - ROUNDS_LOOP (WW) - -#undef WW - - D_XOR_128(a0, c0); - D_XOR_128(b0, d0); - D_XOR_128(a1, c1); - D_XOR_128(b1, d1); - - D_XOR_128(a0, LOAD_128_FROM_STRUCT(s)); - D_XOR_128(b0, LOAD_128_FROM_STRUCT(s + 4)); - D_XOR_128(a1, LOAD_128_FROM_STRUCT(s + NSW)); - D_XOR_128(b1, LOAD_128_FROM_STRUCT(s + NSW + 4)); - - STORE_128_TO_STRUCT(s, a0); - STORE_128_TO_STRUCT(s + 4, b0); - STORE_128_TO_STRUCT(s + NSW, a1); - STORE_128_TO_STRUCT(s + NSW + 4, b1); - - data += Z7_BLAKE2S_BLOCK_SIZE * 2; - pos += Z7_BLAKE2S_BLOCK_SIZE * 2; - pos &= SUPER_BLOCK_MASK; - } - while (data < end); - if (data != end) - return; - } - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - Z7_BLAKE2S_CompressSingleBlock(s, data); - } -} -#endif // Z7_BLAKE2S_USE_V128_WAY2 - - -#ifdef Z7_BLAKE2S_USE_V128_WAY2 - #define Z7_BLAKE2S_Compress2_V128 Blake2sp_Compress2_V128_Way2 -#else - #define Z7_BLAKE2S_Compress2_V128 Blake2sp_Compress2_V128_Way1 -#endif - - - -#ifdef Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED - #define ROT_128_8(x) MM_ROR_EPI32(x, 8) - #define ROT_128_16(x) MM_ROR_EPI32(x, 16) - #define ROT_128_7(x) MM_ROR_EPI32(x, 7) - #define ROT_128_12(x) MM_ROR_EPI32(x, 12) -#else -#if defined(Z7_BLAKE2S_USE_SSSE3) || defined(Z7_BLAKE2S_USE_SSE41) - #define ROT_128_8(x) _mm_shuffle_epi8(x, r8) // k_r8 - #define ROT_128_16(x) _mm_shuffle_epi8(x, r16) // k_r16 -#else - #define ROT_128_8(x) MM_ROR_EPI32_VIA_SHIFT(x, 8) - #define ROT_128_16(x) MM_ROR_EPI32_VIA_SHIFT(x, 16) -#endif - #define ROT_128_7(x) MM_ROR_EPI32_VIA_SHIFT(x, 7) - #define ROT_128_12(x) MM_ROR_EPI32_VIA_SHIFT(x, 12) -#endif - - -#if 1 -// this branch can provide similar speed on x86* in most cases, -// because [base + index*4] provides same speed as [base + index]. -// but some compilers can generate different code with this branch, that can be faster sometimes. -// this branch uses additional table of 10*16=160 bytes. -#define SIGMA_TABLE_MULT_16( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ - SIGMA_TABLE_MULT(16, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) -MY_ALIGN(16) -static const Byte k_Blake2s_Sigma_16[BLAKE2S_NUM_ROUNDS][16] = - { SIGMA_TABLE(SIGMA_TABLE_MULT_16) }; -#define GET_SIGMA_PTR_128(r) const Byte * const sigma = k_Blake2s_Sigma_16[r]; -#define GET_SIGMA_VAL_128(n) (sigma[n]) -#else -#define GET_SIGMA_PTR_128(r) const Byte * const sigma = k_Blake2s_Sigma_4[r]; -#define GET_SIGMA_VAL_128(n) (4 * (size_t)sigma[n]) -#endif - - -#ifdef Z7_BLAKE2S_USE_AVX2_FAST -#if 1 -#define SIGMA_TABLE_MULT_32( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ - SIGMA_TABLE_MULT(32, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) -MY_ALIGN(64) -static const UInt16 k_Blake2s_Sigma_32[BLAKE2S_NUM_ROUNDS][16] = - { SIGMA_TABLE(SIGMA_TABLE_MULT_32) }; -#define GET_SIGMA_PTR_256(r) const UInt16 * const sigma = k_Blake2s_Sigma_32[r]; -#define GET_SIGMA_VAL_256(n) (sigma[n]) -#else -#define GET_SIGMA_PTR_256(r) const Byte * const sigma = k_Blake2s_Sigma_4[r]; -#define GET_SIGMA_VAL_256(n) (8 * (size_t)sigma[n]) -#endif -#endif // Z7_BLAKE2S_USE_AVX2_FAST - - -#define D_ROT_128_7(dest) dest = ROT_128_7(dest) -#define D_ROT_128_8(dest) dest = ROT_128_8(dest) -#define D_ROT_128_12(dest) dest = ROT_128_12(dest) -#define D_ROT_128_16(dest) dest = ROT_128_16(dest) - -#define OP_L(a, i) D_ADD_128 (V(a, 0), \ - LOAD_128((const Byte *)(w) + GET_SIGMA_VAL_128(2*(a)+(i)))); - -#define OP_0(a) OP_L(a, 0) -#define OP_7(a) OP_L(a, 1) - -#define OP_1(a) D_ADD_128 (V(a, 0), V(a, 1)); -#define OP_2(a) D_XOR_128 (V(a, 3), V(a, 0)); -#define OP_4(a) D_ADD_128 (V(a, 2), V(a, 3)); -#define OP_5(a) D_XOR_128 (V(a, 1), V(a, 2)); - -#define OP_3(a) D_ROT_128_16 (V(a, 3)); -#define OP_6(a) D_ROT_128_12 (V(a, 1)); -#define OP_8(a) D_ROT_128_8 (V(a, 3)); -#define OP_9(a) D_ROT_128_7 (V(a, 1)); - - -// for 32-bit x86 : interleave mode works slower, because of register pressure. - -#if 0 || 1 && (defined(MY_CPU_X86) \ - || defined(__GNUC__) && !defined(__clang__)) -// non-inteleaved version: -// is fast for x86 32-bit. -// is fast for GCC x86-64. - -#define V4G(a) \ - OP_0 (a) \ - OP_1 (a) \ - OP_2 (a) \ - OP_3 (a) \ - OP_4 (a) \ - OP_5 (a) \ - OP_6 (a) \ - OP_7 (a) \ - OP_1 (a) \ - OP_2 (a) \ - OP_8 (a) \ - OP_4 (a) \ - OP_5 (a) \ - OP_9 (a) \ - -#define V4R \ -{ \ - V4G (0) \ - V4G (1) \ - V4G (2) \ - V4G (3) \ - V4G (4) \ - V4G (5) \ - V4G (6) \ - V4G (7) \ -} - -#elif 0 || 1 && defined(MY_CPU_X86) - -#define OP_INTER_2(op, a,b) \ - op (a) \ - op (b) \ - -#define V4G(a,b) \ - OP_INTER_2 (OP_0, a,b) \ - OP_INTER_2 (OP_1, a,b) \ - OP_INTER_2 (OP_2, a,b) \ - OP_INTER_2 (OP_3, a,b) \ - OP_INTER_2 (OP_4, a,b) \ - OP_INTER_2 (OP_5, a,b) \ - OP_INTER_2 (OP_6, a,b) \ - OP_INTER_2 (OP_7, a,b) \ - OP_INTER_2 (OP_1, a,b) \ - OP_INTER_2 (OP_2, a,b) \ - OP_INTER_2 (OP_8, a,b) \ - OP_INTER_2 (OP_4, a,b) \ - OP_INTER_2 (OP_5, a,b) \ - OP_INTER_2 (OP_9, a,b) \ - -#define V4R \ -{ \ - V4G (0, 1) \ - V4G (2, 3) \ - V4G (4, 5) \ - V4G (6, 7) \ -} - -#else -// iterleave-4 version is fast for x64 (MSVC/CLANG) - -#define OP_INTER_4(op, a,b,c,d) \ - op (a) \ - op (b) \ - op (c) \ - op (d) \ - -#define V4G(a,b,c,d) \ - OP_INTER_4 (OP_0, a,b,c,d) \ - OP_INTER_4 (OP_1, a,b,c,d) \ - OP_INTER_4 (OP_2, a,b,c,d) \ - OP_INTER_4 (OP_3, a,b,c,d) \ - OP_INTER_4 (OP_4, a,b,c,d) \ - OP_INTER_4 (OP_5, a,b,c,d) \ - OP_INTER_4 (OP_6, a,b,c,d) \ - OP_INTER_4 (OP_7, a,b,c,d) \ - OP_INTER_4 (OP_1, a,b,c,d) \ - OP_INTER_4 (OP_2, a,b,c,d) \ - OP_INTER_4 (OP_8, a,b,c,d) \ - OP_INTER_4 (OP_4, a,b,c,d) \ - OP_INTER_4 (OP_5, a,b,c,d) \ - OP_INTER_4 (OP_9, a,b,c,d) \ - -#define V4R \ -{ \ - V4G (0, 1, 2, 3) \ - V4G (4, 5, 6, 7) \ -} - -#endif - -#define V4_ROUND(r) { GET_SIGMA_PTR_128(r); V4R } - - -#define V4_LOAD_MSG_1(w, m, i) \ -{ \ - __m128i m0, m1, m2, m3; \ - __m128i t0, t1, t2, t3; \ - m0 = LOADU_128((m) + ((i) + 0 * 4) * 16); \ - m1 = LOADU_128((m) + ((i) + 1 * 4) * 16); \ - m2 = LOADU_128((m) + ((i) + 2 * 4) * 16); \ - m3 = LOADU_128((m) + ((i) + 3 * 4) * 16); \ - t0 = _mm_unpacklo_epi32(m0, m1); \ - t1 = _mm_unpackhi_epi32(m0, m1); \ - t2 = _mm_unpacklo_epi32(m2, m3); \ - t3 = _mm_unpackhi_epi32(m2, m3); \ - w[(i) * 4 + 0] = _mm_unpacklo_epi64(t0, t2); \ - w[(i) * 4 + 1] = _mm_unpackhi_epi64(t0, t2); \ - w[(i) * 4 + 2] = _mm_unpacklo_epi64(t1, t3); \ - w[(i) * 4 + 3] = _mm_unpackhi_epi64(t1, t3); \ -} - -#define V4_LOAD_MSG(w, m) \ -{ \ - V4_LOAD_MSG_1 (w, m, 0) \ - V4_LOAD_MSG_1 (w, m, 1) \ - V4_LOAD_MSG_1 (w, m, 2) \ - V4_LOAD_MSG_1 (w, m, 3) \ -} - -#define V4_LOAD_UNPACK_PAIR_128(src32, i, d0, d1) \ -{ \ - const __m128i v0 = LOAD_128_FROM_STRUCT((src32) + (i ) * 4); \ - const __m128i v1 = LOAD_128_FROM_STRUCT((src32) + (i + 1) * 4); \ - d0 = _mm_unpacklo_epi32(v0, v1); \ - d1 = _mm_unpackhi_epi32(v0, v1); \ -} - -#define V4_UNPACK_PAIR_128(dest32, i, s0, s1) \ -{ \ - STORE_128_TO_STRUCT((dest32) + i * 4 , _mm_unpacklo_epi64(s0, s1)); \ - STORE_128_TO_STRUCT((dest32) + i * 4 + 16, _mm_unpackhi_epi64(s0, s1)); \ -} - -#define V4_UNPACK_STATE(dest32, src32) \ -{ \ - __m128i t0, t1, t2, t3, t4, t5, t6, t7; \ - V4_LOAD_UNPACK_PAIR_128(src32, 0, t0, t1) \ - V4_LOAD_UNPACK_PAIR_128(src32, 2, t2, t3) \ - V4_LOAD_UNPACK_PAIR_128(src32, 4, t4, t5) \ - V4_LOAD_UNPACK_PAIR_128(src32, 6, t6, t7) \ - V4_UNPACK_PAIR_128(dest32, 0, t0, t2) \ - V4_UNPACK_PAIR_128(dest32, 8, t1, t3) \ - V4_UNPACK_PAIR_128(dest32, 1, t4, t6) \ - V4_UNPACK_PAIR_128(dest32, 9, t5, t7) \ -} - - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_128BIT - BLAKE2S_ATTRIB_128BIT -#endif -void -Z7_FASTCALL -Blake2sp_Compress2_V128_Fast(UInt32 *s_items, const Byte *data, const Byte *end) -{ - // PrintStates2(s_items, 8, 16); - size_t pos = 0; - pos /= 2; - do - { -#if defined(Z7_BLAKE2S_USE_SSSE3) && \ - !defined(Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED) - const __m128i r8 = k_r8; - const __m128i r16 = k_r16; -#endif - __m128i w[16]; - __m128i v[16]; - UInt32 *s; - V4_LOAD_MSG(w, data) - s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - { - __m128i ctr = LOAD_128_FROM_STRUCT(s + 64); - D_ADD_EPI64_128 (ctr, k_inc); - STORE_128_TO_STRUCT(s + 64, ctr); - v[12] = XOR_128 (GET_128_IV_WAY4(4), _mm_shuffle_epi32(ctr, _MM_SHUFFLE(0, 0, 0, 0))); - v[13] = XOR_128 (GET_128_IV_WAY4(5), _mm_shuffle_epi32(ctr, _MM_SHUFFLE(1, 1, 1, 1))); - } - v[ 8] = GET_128_IV_WAY4(0); - v[ 9] = GET_128_IV_WAY4(1); - v[10] = GET_128_IV_WAY4(2); - v[11] = GET_128_IV_WAY4(3); - v[14] = GET_128_IV_WAY4(6); - v[15] = GET_128_IV_WAY4(7); - -#define LOAD_STATE_128_FROM_STRUCT(i) \ - v[i] = LOAD_128_FROM_STRUCT(s + (i) * 4); - -#define UPDATE_STATE_128_IN_STRUCT(i) \ - STORE_128_TO_STRUCT(s + (i) * 4, XOR_128( \ - XOR_128(v[i], v[(i) + 8]), \ - LOAD_128_FROM_STRUCT(s + (i) * 4))); - - REP8_MACRO (LOAD_STATE_128_FROM_STRUCT) - ROUNDS_LOOP (V4_ROUND) - REP8_MACRO (UPDATE_STATE_128_IN_STRUCT) - - data += Z7_BLAKE2S_BLOCK_SIZE * 4; - pos += Z7_BLAKE2S_BLOCK_SIZE * 4 / 2; - pos &= SUPER_BLOCK_SIZE / 2 - 1; - } - while (data != end); -} - - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_128BIT - BLAKE2S_ATTRIB_128BIT -#endif -void -Z7_FASTCALL -Blake2sp_Final_V128_Fast(UInt32 *states) -{ - const __m128i ctr = LOAD_128_FROM_STRUCT(states + 64); - // printf("\nBlake2sp_Compress2_V128_Fast_Final4\n"); - // PrintStates2(states, 8, 16); - { - ptrdiff_t pos = 8 * 4; - do - { - UInt32 *src32 = states + (size_t)(pos * 1); - UInt32 *dest32 = states + (size_t)(pos * 2); - V4_UNPACK_STATE(dest32, src32) - pos -= 8 * 4; - } - while (pos >= 0); - } - { - unsigned k; - for (k = 0; k < 8; k++) - { - UInt32 *s = states + (size_t)k * 16; - STORE_128_TO_STRUCT (STATE_T(s), ctr); - } - } - // PrintStates2(states, 8, 16); -} - - - -#ifdef Z7_BLAKE2S_USE_AVX2 - -#define ADD_256(a, b) _mm256_add_epi32(a, b) -#define XOR_256(a, b) _mm256_xor_si256(a, b) - -#if 1 && defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) - #define MM256_ROR_EPI32 _mm256_ror_epi32 - #define Z7_MM256_ROR_EPI32_IS_SUPPORTED -#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 - #define LOAD_ROTATE_CONSTS_256 -#endif -#else -#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW -#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 - #define LOAD_ROTATE_CONSTS_256 \ - const __m256i r8 = k_r8_256; \ - const __m256i r16 = k_r16_256; -#endif // AVX2_WAY2 - - #define MM256_ROR_EPI32(r, c) ( \ - ( 8==(c)) ? _mm256_shuffle_epi8(r,r8) \ - : (16==(c)) ? _mm256_shuffle_epi8(r,r16) \ - : _mm256_or_si256( \ - _mm256_srli_epi32((r), (c)), \ - _mm256_slli_epi32((r), 32-(c)))) -#endif // WAY_SLOW -#endif - - -#define D_ADD_256(dest, src) dest = ADD_256(dest, src) -#define D_XOR_256(dest, src) dest = XOR_256(dest, src) - -#define LOADU_256(p) _mm256_loadu_si256((const __m256i *)(const void *)(p)) - -#ifdef Z7_BLAKE2S_USE_AVX2_FAST - -#ifdef Z7_MM256_ROR_EPI32_IS_SUPPORTED -#define ROT_256_16(x) MM256_ROR_EPI32((x), 16) -#define ROT_256_12(x) MM256_ROR_EPI32((x), 12) -#define ROT_256_8(x) MM256_ROR_EPI32((x), 8) -#define ROT_256_7(x) MM256_ROR_EPI32((x), 7) -#else -#define ROTATE8 _mm256_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1, \ - 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1) -#define ROTATE16 _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, \ - 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2) -#define ROT_256_16(x) _mm256_shuffle_epi8((x), ROTATE16) -#define ROT_256_12(x) _mm256_or_si256(_mm256_srli_epi32((x), 12), _mm256_slli_epi32((x), 20)) -#define ROT_256_8(x) _mm256_shuffle_epi8((x), ROTATE8) -#define ROT_256_7(x) _mm256_or_si256(_mm256_srli_epi32((x), 7), _mm256_slli_epi32((x), 25)) -#endif - -#define D_ROT_256_7(dest) dest = ROT_256_7(dest) -#define D_ROT_256_8(dest) dest = ROT_256_8(dest) -#define D_ROT_256_12(dest) dest = ROT_256_12(dest) -#define D_ROT_256_16(dest) dest = ROT_256_16(dest) - -#define LOAD_256(p) _mm256_load_si256((const __m256i *)(const void *)(p)) -#ifdef Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED - #define STOREU_256(p, r) _mm256_storeu_si256((__m256i *)(void *)(p), r) - #define LOAD_256_FROM_STRUCT(p) LOADU_256(p) - #define STORE_256_TO_STRUCT(p, r) STOREU_256(p, r) -#else - // if struct is aligned for 32-bytes - #define STORE_256(p, r) _mm256_store_si256((__m256i *)(void *)(p), r) - #define LOAD_256_FROM_STRUCT(p) LOAD_256(p) - #define STORE_256_TO_STRUCT(p, r) STORE_256(p, r) -#endif - -#endif // Z7_BLAKE2S_USE_AVX2_FAST - - - -#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW - -#if 0 - #define DIAG_PERM2(s) \ - { \ - const __m256i a = LOAD_256_FROM_STRUCT((s) ); \ - const __m256i b = LOAD_256_FROM_STRUCT((s) + NSW); \ - STORE_256_TO_STRUCT((s ), _mm256_permute2x128_si256(a, b, 0x20)); \ - STORE_256_TO_STRUCT((s + NSW), _mm256_permute2x128_si256(a, b, 0x31)); \ - } -#else - #define DIAG_PERM2(s) \ - { \ - const __m128i a = LOAD_128_FROM_STRUCT((s) + 4); \ - const __m128i b = LOAD_128_FROM_STRUCT((s) + NSW); \ - STORE_128_TO_STRUCT((s) + NSW, a); \ - STORE_128_TO_STRUCT((s) + 4 , b); \ - } -#endif - #define DIAG_PERM8(s_items) \ - { \ - DIAG_PERM2(s_items) \ - DIAG_PERM2(s_items + NSW * 2) \ - DIAG_PERM2(s_items + NSW * 4) \ - DIAG_PERM2(s_items + NSW * 6) \ - } - - -#define AXR256(a, b, d, shift) \ - D_ADD_256(a, b); \ - D_XOR_256(d, a); \ - d = MM256_ROR_EPI32(d, shift); \ - - - -#ifdef Z7_BLAKE2S_USE_GATHER - - #define TABLE_GATHER_256_4(a0,a1,a2,a3) \ - a0,a1,a2,a3, a0+16,a1+16,a2+16,a3+16 - #define TABLE_GATHER_256( \ - a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ - { TABLE_GATHER_256_4(a0,a2,a4,a6), \ - TABLE_GATHER_256_4(a1,a3,a5,a7), \ - TABLE_GATHER_256_4(a8,a10,a12,a14), \ - TABLE_GATHER_256_4(a9,a11,a13,a15) } -MY_ALIGN(64) -static const UInt32 k_Blake2s_Sigma_gather256[BLAKE2S_NUM_ROUNDS][16 * 2] = - { SIGMA_TABLE(TABLE_GATHER_256) }; - #define GET_SIGMA(r) \ - const UInt32 * const sigma = k_Blake2s_Sigma_gather256[r]; - #define AXR2_LOAD_INDEXES_AVX(sigma_index) \ - const __m256i i01234567 = LOAD_256(sigma + (sigma_index)); - #define SET_ROW_FROM_SIGMA_AVX(in) \ - _mm256_i32gather_epi32((const void *)(in), i01234567, 4) - #define SIGMA_INTERLEAVE 8 - #define SIGMA_HALF_ROW_SIZE 16 - -#else // !Z7_BLAKE2S_USE_GATHER - - #define GET_SIGMA(r) \ - const Byte * const sigma = k_Blake2s_Sigma_4[r]; - #define AXR2_LOAD_INDEXES_AVX(sigma_index) \ - AXR2_LOAD_INDEXES(sigma_index) - #define SET_ROW_FROM_SIGMA_AVX(in) \ - MY_mm256_set_m128i( \ - SET_ROW_FROM_SIGMA_W((in) + Z7_BLAKE2S_BLOCK_SIZE), \ - SET_ROW_FROM_SIGMA_W(in)) - #define SIGMA_INTERLEAVE 1 - #define SIGMA_HALF_ROW_SIZE 8 -#endif // !Z7_BLAKE2S_USE_GATHER - - -#define ROTATE_WORDS_TO_RIGHT_256(a, n) \ - a = _mm256_shuffle_epi32(a, _MM_SHUFFLE((3+n)&3, (2+n)&3, (1+n)&3, (0+n)&3)); - - - -#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 - -#define AXR2_A(sigma_index, shift1, shift2) \ - AXR2_LOAD_INDEXES_AVX(sigma_index) \ - D_ADD_256( a0, SET_ROW_FROM_SIGMA_AVX(data)); \ - AXR256(a0, b0, d0, shift1) \ - AXR256(c0, d0, b0, shift2) \ - -#define AXR4_A(sigma_index) \ - { AXR2_A(sigma_index, 16, 12) } \ - { AXR2_A(sigma_index + SIGMA_INTERLEAVE, 8, 7) } - -#define EE1(r) \ - { GET_SIGMA(r) \ - AXR4_A(0) \ - ROTATE_WORDS_TO_RIGHT_256(b0, 1) \ - ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ - ROTATE_WORDS_TO_RIGHT_256(d0, 3) \ - AXR4_A(SIGMA_HALF_ROW_SIZE) \ - ROTATE_WORDS_TO_RIGHT_256(b0, 3) \ - ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ - ROTATE_WORDS_TO_RIGHT_256(d0, 1) \ - } - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_AVX2 - BLAKE2S_ATTRIB_AVX2 -#endif -void -Z7_FASTCALL -Blake2sp_Compress2_AVX2_Way2(UInt32 *s_items, const Byte *data, const Byte *end) -{ - size_t pos = 0; - end -= Z7_BLAKE2S_BLOCK_SIZE; - - if (data != end) - { - LOAD_ROTATE_CONSTS_256 - DIAG_PERM8(s_items) - do - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - __m256i a0, b0, c0, d0; - { - const __m128i inc = k_inc; - __m128i d0_128 = LOAD_128_FROM_STRUCT (STATE_T(s)); - __m128i d1_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW)); - D_ADD_EPI64_128(d0_128, inc); - D_ADD_EPI64_128(d1_128, inc); - STORE_128_TO_STRUCT (STATE_T(s ), d0_128); - STORE_128_TO_STRUCT (STATE_T(s + NSW), d1_128); - d0 = MY_mm256_set_m128i(d1_128, d0_128); - D_XOR_256(d0, k_iv4_256); - } - c0 = SET_FROM_128(k_iv0_128); - a0 = LOAD_256_FROM_STRUCT(s + NSW * 0); - b0 = LOAD_256_FROM_STRUCT(s + NSW * 1); - - ROUNDS_LOOP (EE1) - - D_XOR_256(a0, c0); - D_XOR_256(b0, d0); - - D_XOR_256(a0, LOAD_256_FROM_STRUCT(s + NSW * 0)); - D_XOR_256(b0, LOAD_256_FROM_STRUCT(s + NSW * 1)); - - STORE_256_TO_STRUCT(s + NSW * 0, a0); - STORE_256_TO_STRUCT(s + NSW * 1, b0); - - data += Z7_BLAKE2S_BLOCK_SIZE * 2; - pos += Z7_BLAKE2S_BLOCK_SIZE * 2; - pos &= SUPER_BLOCK_MASK; - } - while (data < end); - DIAG_PERM8(s_items) - if (data != end) - return; - } - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - Z7_BLAKE2S_CompressSingleBlock(s, data); - } -} - -#endif // Z7_BLAKE2S_USE_AVX2_WAY2 - - - -#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 - -#define AXR2_X(sigma_index, shift1, shift2) \ - AXR2_LOAD_INDEXES_AVX(sigma_index) \ - D_ADD_256( a0, SET_ROW_FROM_SIGMA_AVX(data)); \ - D_ADD_256( a1, SET_ROW_FROM_SIGMA_AVX((data) + Z7_BLAKE2S_BLOCK_SIZE * 2)); \ - AXR256(a0, b0, d0, shift1) \ - AXR256(a1, b1, d1, shift1) \ - AXR256(c0, d0, b0, shift2) \ - AXR256(c1, d1, b1, shift2) \ - -#define AXR4_X(sigma_index) \ - { AXR2_X(sigma_index, 16, 12) } \ - { AXR2_X(sigma_index + SIGMA_INTERLEAVE, 8, 7) } - -#define EE2(r) \ - { GET_SIGMA(r) \ - AXR4_X(0) \ - ROTATE_WORDS_TO_RIGHT_256(b0, 1) \ - ROTATE_WORDS_TO_RIGHT_256(b1, 1) \ - ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ - ROTATE_WORDS_TO_RIGHT_256(c1, 2) \ - ROTATE_WORDS_TO_RIGHT_256(d0, 3) \ - ROTATE_WORDS_TO_RIGHT_256(d1, 3) \ - AXR4_X(SIGMA_HALF_ROW_SIZE) \ - ROTATE_WORDS_TO_RIGHT_256(b0, 3) \ - ROTATE_WORDS_TO_RIGHT_256(b1, 3) \ - ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ - ROTATE_WORDS_TO_RIGHT_256(c1, 2) \ - ROTATE_WORDS_TO_RIGHT_256(d0, 1) \ - ROTATE_WORDS_TO_RIGHT_256(d1, 1) \ - } - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_AVX2 - BLAKE2S_ATTRIB_AVX2 -#endif -void -Z7_FASTCALL -Blake2sp_Compress2_AVX2_Way4(UInt32 *s_items, const Byte *data, const Byte *end) -{ - size_t pos = 0; - - if ((size_t)(end - data) >= Z7_BLAKE2S_BLOCK_SIZE * 4) - { -#ifndef Z7_MM256_ROR_EPI32_IS_SUPPORTED - const __m256i r8 = k_r8_256; - const __m256i r16 = k_r16_256; -#endif - end -= Z7_BLAKE2S_BLOCK_SIZE * 3; - DIAG_PERM8(s_items) - do - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - __m256i a0, b0, c0, d0; - __m256i a1, b1, c1, d1; - { - const __m128i inc = k_inc; - __m128i d0_128 = LOAD_128_FROM_STRUCT (STATE_T(s)); - __m128i d1_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW)); - __m128i d2_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW * 2)); - __m128i d3_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW * 3)); - D_ADD_EPI64_128(d0_128, inc); - D_ADD_EPI64_128(d1_128, inc); - D_ADD_EPI64_128(d2_128, inc); - D_ADD_EPI64_128(d3_128, inc); - STORE_128_TO_STRUCT (STATE_T(s ), d0_128); - STORE_128_TO_STRUCT (STATE_T(s + NSW * 1), d1_128); - STORE_128_TO_STRUCT (STATE_T(s + NSW * 2), d2_128); - STORE_128_TO_STRUCT (STATE_T(s + NSW * 3), d3_128); - d0 = MY_mm256_set_m128i(d1_128, d0_128); - d1 = MY_mm256_set_m128i(d3_128, d2_128); - D_XOR_256(d0, k_iv4_256); - D_XOR_256(d1, k_iv4_256); - } - c1 = c0 = SET_FROM_128(k_iv0_128); - a0 = LOAD_256_FROM_STRUCT(s + NSW * 0); - b0 = LOAD_256_FROM_STRUCT(s + NSW * 1); - a1 = LOAD_256_FROM_STRUCT(s + NSW * 2); - b1 = LOAD_256_FROM_STRUCT(s + NSW * 3); - - ROUNDS_LOOP (EE2) - - D_XOR_256(a0, c0); - D_XOR_256(b0, d0); - D_XOR_256(a1, c1); - D_XOR_256(b1, d1); - - D_XOR_256(a0, LOAD_256_FROM_STRUCT(s + NSW * 0)); - D_XOR_256(b0, LOAD_256_FROM_STRUCT(s + NSW * 1)); - D_XOR_256(a1, LOAD_256_FROM_STRUCT(s + NSW * 2)); - D_XOR_256(b1, LOAD_256_FROM_STRUCT(s + NSW * 3)); - - STORE_256_TO_STRUCT(s + NSW * 0, a0); - STORE_256_TO_STRUCT(s + NSW * 1, b0); - STORE_256_TO_STRUCT(s + NSW * 2, a1); - STORE_256_TO_STRUCT(s + NSW * 3, b1); - - data += Z7_BLAKE2S_BLOCK_SIZE * 4; - pos += Z7_BLAKE2S_BLOCK_SIZE * 4; - pos &= SUPER_BLOCK_MASK; - } - while (data < end); - DIAG_PERM8(s_items) - end += Z7_BLAKE2S_BLOCK_SIZE * 3; - } - if (data == end) - return; - // Z7_BLAKE2S_Compress2_V128(s_items, data, end, pos); - do - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - Z7_BLAKE2S_CompressSingleBlock(s, data); - data += Z7_BLAKE2S_BLOCK_SIZE; - pos += Z7_BLAKE2S_BLOCK_SIZE; - pos &= SUPER_BLOCK_MASK; - } - while (data != end); -} - -#endif // Z7_BLAKE2S_USE_AVX2_WAY4 -#endif // Z7_BLAKE2S_USE_AVX2_WAY_SLOW - - -// --------------------------------------------------------- - -#ifdef Z7_BLAKE2S_USE_AVX2_FAST - -#define OP256_L(a, i) D_ADD_256 (V(a, 0), \ - LOAD_256((const Byte *)(w) + GET_SIGMA_VAL_256(2*(a)+(i)))); - -#define OP256_0(a) OP256_L(a, 0) -#define OP256_7(a) OP256_L(a, 1) - -#define OP256_1(a) D_ADD_256 (V(a, 0), V(a, 1)); -#define OP256_2(a) D_XOR_256 (V(a, 3), V(a, 0)); -#define OP256_4(a) D_ADD_256 (V(a, 2), V(a, 3)); -#define OP256_5(a) D_XOR_256 (V(a, 1), V(a, 2)); - -#define OP256_3(a) D_ROT_256_16 (V(a, 3)); -#define OP256_6(a) D_ROT_256_12 (V(a, 1)); -#define OP256_8(a) D_ROT_256_8 (V(a, 3)); -#define OP256_9(a) D_ROT_256_7 (V(a, 1)); - - -#if 0 || 1 && defined(MY_CPU_X86) - -#define V8_G(a) \ - OP256_0 (a) \ - OP256_1 (a) \ - OP256_2 (a) \ - OP256_3 (a) \ - OP256_4 (a) \ - OP256_5 (a) \ - OP256_6 (a) \ - OP256_7 (a) \ - OP256_1 (a) \ - OP256_2 (a) \ - OP256_8 (a) \ - OP256_4 (a) \ - OP256_5 (a) \ - OP256_9 (a) \ - -#define V8R { \ - V8_G (0); \ - V8_G (1); \ - V8_G (2); \ - V8_G (3); \ - V8_G (4); \ - V8_G (5); \ - V8_G (6); \ - V8_G (7); \ -} - -#else - -#define OP256_INTER_4(op, a,b,c,d) \ - op (a) \ - op (b) \ - op (c) \ - op (d) \ - -#define V8_G(a,b,c,d) \ - OP256_INTER_4 (OP256_0, a,b,c,d) \ - OP256_INTER_4 (OP256_1, a,b,c,d) \ - OP256_INTER_4 (OP256_2, a,b,c,d) \ - OP256_INTER_4 (OP256_3, a,b,c,d) \ - OP256_INTER_4 (OP256_4, a,b,c,d) \ - OP256_INTER_4 (OP256_5, a,b,c,d) \ - OP256_INTER_4 (OP256_6, a,b,c,d) \ - OP256_INTER_4 (OP256_7, a,b,c,d) \ - OP256_INTER_4 (OP256_1, a,b,c,d) \ - OP256_INTER_4 (OP256_2, a,b,c,d) \ - OP256_INTER_4 (OP256_8, a,b,c,d) \ - OP256_INTER_4 (OP256_4, a,b,c,d) \ - OP256_INTER_4 (OP256_5, a,b,c,d) \ - OP256_INTER_4 (OP256_9, a,b,c,d) \ - -#define V8R { \ - V8_G (0, 1, 2, 3) \ - V8_G (4, 5, 6, 7) \ -} -#endif - -#define V8_ROUND(r) { GET_SIGMA_PTR_256(r); V8R } - - -// for debug: -// #define Z7_BLAKE2S_PERMUTE_WITH_GATHER -#if defined(Z7_BLAKE2S_PERMUTE_WITH_GATHER) -// gather instruction is slow. -#define V8_LOAD_MSG(w, m) \ -{ \ - unsigned i; \ - for (i = 0; i < 16; ++i) { \ - w[i] = _mm256_i32gather_epi32( \ - (const void *)((m) + i * sizeof(UInt32)),\ - _mm256_set_epi32(0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00), \ - sizeof(UInt32)); \ - } \ -} -#else // !Z7_BLAKE2S_PERMUTE_WITH_GATHER - -#define V8_LOAD_MSG_2(w, a0, a1) \ -{ \ - (w)[0] = _mm256_permute2x128_si256(a0, a1, 0x20); \ - (w)[4] = _mm256_permute2x128_si256(a0, a1, 0x31); \ -} - -#define V8_LOAD_MSG_4(w, z0, z1, z2, z3) \ -{ \ - __m256i s0, s1, s2, s3; \ - s0 = _mm256_unpacklo_epi64(z0, z1); \ - s1 = _mm256_unpackhi_epi64(z0, z1); \ - s2 = _mm256_unpacklo_epi64(z2, z3); \ - s3 = _mm256_unpackhi_epi64(z2, z3); \ - V8_LOAD_MSG_2((w) + 0, s0, s2) \ - V8_LOAD_MSG_2((w) + 1, s1, s3) \ -} - -#define V8_LOAD_MSG_0(t0, t1, m) \ -{ \ - __m256i m0, m1; \ - m0 = LOADU_256(m); \ - m1 = LOADU_256((m) + 2 * 32); \ - t0 = _mm256_unpacklo_epi32(m0, m1); \ - t1 = _mm256_unpackhi_epi32(m0, m1); \ -} - -#define V8_LOAD_MSG_8(w, m) \ -{ \ - __m256i t0, t1, t2, t3, t4, t5, t6, t7; \ - V8_LOAD_MSG_0(t0, t4, (m) + 0 * 4 * 32) \ - V8_LOAD_MSG_0(t1, t5, (m) + 1 * 4 * 32) \ - V8_LOAD_MSG_0(t2, t6, (m) + 2 * 4 * 32) \ - V8_LOAD_MSG_0(t3, t7, (m) + 3 * 4 * 32) \ - V8_LOAD_MSG_4((w) , t0, t1, t2, t3) \ - V8_LOAD_MSG_4((w) + 2, t4, t5, t6, t7) \ -} - -#define V8_LOAD_MSG(w, m) \ -{ \ - V8_LOAD_MSG_8(w, m) \ - V8_LOAD_MSG_8((w) + 8, (m) + 32) \ -} - -#endif // !Z7_BLAKE2S_PERMUTE_WITH_GATHER - - -#define V8_PERM_PAIR_STORE(u, a0, a2) \ -{ \ - STORE_256_TO_STRUCT((u), _mm256_permute2x128_si256(a0, a2, 0x20)); \ - STORE_256_TO_STRUCT((u) + 8, _mm256_permute2x128_si256(a0, a2, 0x31)); \ -} - -#define V8_UNPACK_STORE_4(u, z0, z1, z2, z3) \ -{ \ - __m256i s0, s1, s2, s3; \ - s0 = _mm256_unpacklo_epi64(z0, z1); \ - s1 = _mm256_unpackhi_epi64(z0, z1); \ - s2 = _mm256_unpacklo_epi64(z2, z3); \ - s3 = _mm256_unpackhi_epi64(z2, z3); \ - V8_PERM_PAIR_STORE(u + 0, s0, s2) \ - V8_PERM_PAIR_STORE(u + 2, s1, s3) \ -} - -#define V8_UNPACK_STORE_0(src32, d0, d1) \ -{ \ - const __m256i v0 = LOAD_256_FROM_STRUCT ((src32) ); \ - const __m256i v1 = LOAD_256_FROM_STRUCT ((src32) + 8); \ - d0 = _mm256_unpacklo_epi32(v0, v1); \ - d1 = _mm256_unpackhi_epi32(v0, v1); \ -} - -#define V8_UNPACK_STATE(dest32, src32) \ -{ \ - __m256i t0, t1, t2, t3, t4, t5, t6, t7; \ - V8_UNPACK_STORE_0 ((src32) + 16 * 0, t0, t4) \ - V8_UNPACK_STORE_0 ((src32) + 16 * 1, t1, t5) \ - V8_UNPACK_STORE_0 ((src32) + 16 * 2, t2, t6) \ - V8_UNPACK_STORE_0 ((src32) + 16 * 3, t3, t7) \ - V8_UNPACK_STORE_4 ((__m256i *)(void *)(dest32) , t0, t1, t2, t3) \ - V8_UNPACK_STORE_4 ((__m256i *)(void *)(dest32) + 4, t4, t5, t6, t7) \ -} - - - -#define V8_LOAD_STATE_256_FROM_STRUCT(i) \ - v[i] = LOAD_256_FROM_STRUCT(s_items + (i) * 8); - -#if 0 || 0 && defined(MY_CPU_X86) -#define Z7_BLAKE2S_AVX2_FAST_USE_STRUCT -#endif - -#ifdef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT -// this branch doesn't use (iv) array -// so register pressure can be lower. -// it can be faster sometimes -#define V8_LOAD_STATE_256(i) V8_LOAD_STATE_256_FROM_STRUCT(i) -#define V8_UPDATE_STATE_256(i) \ -{ \ - STORE_256_TO_STRUCT(s_items + (i) * 8, XOR_256( \ - XOR_256(v[i], v[(i) + 8]), \ - LOAD_256_FROM_STRUCT(s_items + (i) * 8))); \ -} -#else -// it uses more variables (iv) registers -// it's better for gcc -// maybe that branch is better, if register pressure will be lower (avx512) -#define V8_LOAD_STATE_256(i) { iv[i] = v[i]; } -#define V8_UPDATE_STATE_256(i) { v[i] = XOR_256(XOR_256(v[i], v[i + 8]), iv[i]); } -#define V8_STORE_STATE_256(i) { STORE_256_TO_STRUCT(s_items + (i) * 8, v[i]); } -#endif - - -#if 0 - // use loading constants from memory - #define KK8(n) KIV(n), KIV(n), KIV(n), KIV(n), KIV(n), KIV(n), KIV(n), KIV(n) -MY_ALIGN(64) -static const UInt32 k_Blake2s_IV_WAY8[]= -{ - KK8(0), KK8(1), KK8(2), KK8(3), KK8(4), KK8(5), KK8(6), KK8(7) -}; - #define GET_256_IV_WAY8(i) LOAD_256(k_Blake2s_IV_WAY8 + 8 * (i)) -#else - // use constant generation: - #define GET_256_IV_WAY8(i) _mm256_set1_epi32((Int32)KIV(i)) -#endif - - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_AVX2 - BLAKE2S_ATTRIB_AVX2 -#endif -void -Z7_FASTCALL -Blake2sp_Compress2_AVX2_Fast(UInt32 *s_items, const Byte *data, const Byte *end) -{ -#ifndef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT - __m256i v[16]; -#endif - - // PrintStates2(s_items, 8, 16); - -#ifndef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT - REP8_MACRO (V8_LOAD_STATE_256_FROM_STRUCT) -#endif - - do - { - __m256i w[16]; -#ifdef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT - __m256i v[16]; -#else - __m256i iv[8]; -#endif - V8_LOAD_MSG(w, data) - { - // we use load/store ctr inside loop to reduce register pressure: -#if 1 || 1 && defined(MY_CPU_X86) - const __m256i ctr = _mm256_add_epi64( - LOAD_256_FROM_STRUCT(s_items + 64), - _mm256_set_epi32( - 0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE, - 0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE)); - STORE_256_TO_STRUCT(s_items + 64, ctr); -#else - const UInt64 ctr64 = *(const UInt64 *)(const void *)(s_items + 64) - + Z7_BLAKE2S_BLOCK_SIZE; - const __m256i ctr = _mm256_set_epi64x(0, (Int64)ctr64, 0, (Int64)ctr64); - *(UInt64 *)(void *)(s_items + 64) = ctr64; -#endif - v[12] = XOR_256 (GET_256_IV_WAY8(4), _mm256_shuffle_epi32(ctr, _MM_SHUFFLE(0, 0, 0, 0))); - v[13] = XOR_256 (GET_256_IV_WAY8(5), _mm256_shuffle_epi32(ctr, _MM_SHUFFLE(1, 1, 1, 1))); - } - v[ 8] = GET_256_IV_WAY8(0); - v[ 9] = GET_256_IV_WAY8(1); - v[10] = GET_256_IV_WAY8(2); - v[11] = GET_256_IV_WAY8(3); - v[14] = GET_256_IV_WAY8(6); - v[15] = GET_256_IV_WAY8(7); - - REP8_MACRO (V8_LOAD_STATE_256) - ROUNDS_LOOP (V8_ROUND) - REP8_MACRO (V8_UPDATE_STATE_256) - data += SUPER_BLOCK_SIZE; - } - while (data != end); - -#ifndef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT - REP8_MACRO (V8_STORE_STATE_256) -#endif -} - - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_AVX2 - BLAKE2S_ATTRIB_AVX2 -#endif -void -Z7_FASTCALL -Blake2sp_Final_AVX2_Fast(UInt32 *states) -{ - const __m128i ctr = LOAD_128_FROM_STRUCT(states + 64); - // PrintStates2(states, 8, 16); - V8_UNPACK_STATE(states, states) - // PrintStates2(states, 8, 16); - { - unsigned k; - for (k = 0; k < 8; k++) - { - UInt32 *s = states + (size_t)k * 16; - STORE_128_TO_STRUCT (STATE_T(s), ctr); - } - } - // PrintStates2(states, 8, 16); - // printf("\nafter V8_UNPACK_STATE \n"); -} - -#endif // Z7_BLAKE2S_USE_AVX2_FAST -#endif // avx2 -#endif // vector - - -/* -#define Blake2s_Increment_Counter(s, inc) \ - { STATE_T(s)[0] += (inc); STATE_T(s)[1] += (STATE_T(s)[0] < (inc)); } -#define Blake2s_Increment_Counter_Small(s, inc) \ - { STATE_T(s)[0] += (inc); } -*/ - -#define Blake2s_Set_LastBlock(s) \ - { STATE_F(s)[0] = BLAKE2S_FINAL_FLAG; /* STATE_F(s)[1] = p->u.header.lastNode_f1; */ } - - -#if 0 || 1 && defined(Z7_MSC_VER_ORIGINAL) && Z7_MSC_VER_ORIGINAL >= 1600 - // good for vs2022 - #define LOOP_8(mac) { unsigned kkk; for (kkk = 0; kkk < 8; kkk++) mac(kkk) } -#else - // good for Z7_BLAKE2S_UNROLL for GCC9 (arm*/x86*) and MSC_VER_1400-x64. - #define LOOP_8(mac) { REP8_MACRO(mac) } -#endif - - -static -Z7_FORCE_INLINE -// Z7_NO_INLINE -void -Z7_FASTCALL -Blake2s_Compress(UInt32 *s, const Byte *input) -{ - UInt32 m[16]; - UInt32 v[16]; - { - unsigned i; - for (i = 0; i < 16; i++) - m[i] = GetUi32(input + i * 4); - } - -#define INIT_v_FROM_s(i) v[i] = s[i]; - - LOOP_8(INIT_v_FROM_s) - - // Blake2s_Increment_Counter(s, Z7_BLAKE2S_BLOCK_SIZE) - { - const UInt32 t0 = STATE_T(s)[0] + Z7_BLAKE2S_BLOCK_SIZE; - const UInt32 t1 = STATE_T(s)[1] + (t0 < Z7_BLAKE2S_BLOCK_SIZE); - STATE_T(s)[0] = t0; - STATE_T(s)[1] = t1; - v[12] = t0 ^ KIV(4); - v[13] = t1 ^ KIV(5); - } - // v[12] = STATE_T(s)[0] ^ KIV(4); - // v[13] = STATE_T(s)[1] ^ KIV(5); - v[14] = STATE_F(s)[0] ^ KIV(6); - v[15] = STATE_F(s)[1] ^ KIV(7); - - v[ 8] = KIV(0); - v[ 9] = KIV(1); - v[10] = KIV(2); - v[11] = KIV(3); - // PrintStates2((const UInt32 *)v, 1, 16); - - #define ADD_SIGMA(a, index) V(a, 0) += *(const UInt32 *)GET_SIGMA_PTR(m, sigma[index]); - #define ADD32M(dest, src, a) V(a, dest) += V(a, src); - #define XOR32M(dest, src, a) V(a, dest) ^= V(a, src); - #define RTR32M(dest, shift, a) V(a, dest) = rotrFixed(V(a, dest), shift); - -// big interleaving can provides big performance gain, if scheduler queues are small. -#if 0 || 1 && defined(MY_CPU_X86) - // interleave-1: for small register number (x86-32bit) - #define G2(index, a, x, y) \ - ADD_SIGMA (a, (index) + 2 * 0) \ - ADD32M (0, 1, a) \ - XOR32M (3, 0, a) \ - RTR32M (3, x, a) \ - ADD32M (2, 3, a) \ - XOR32M (1, 2, a) \ - RTR32M (1, y, a) \ - - #define G(a) \ - G2(a * 2 , a, 16, 12) \ - G2(a * 2 + 1, a, 8, 7) \ - - #define R2 \ - G(0) \ - G(1) \ - G(2) \ - G(3) \ - G(4) \ - G(5) \ - G(6) \ - G(7) \ - -#elif 0 || 1 && defined(MY_CPU_X86_OR_AMD64) - // interleave-2: is good if the number of registers is not big (x86-64). - - #define REP2(mac, dest, src, a, b) \ - mac(dest, src, a) \ - mac(dest, src, b) - - #define G2(index, a, b, x, y) \ - ADD_SIGMA (a, (index) + 2 * 0) \ - ADD_SIGMA (b, (index) + 2 * 1) \ - REP2 (ADD32M, 0, 1, a, b) \ - REP2 (XOR32M, 3, 0, a, b) \ - REP2 (RTR32M, 3, x, a, b) \ - REP2 (ADD32M, 2, 3, a, b) \ - REP2 (XOR32M, 1, 2, a, b) \ - REP2 (RTR32M, 1, y, a, b) \ - - #define G(a, b) \ - G2(a * 2 , a, b, 16, 12) \ - G2(a * 2 + 1, a, b, 8, 7) \ - - #define R2 \ - G(0, 1) \ - G(2, 3) \ - G(4, 5) \ - G(6, 7) \ - -#else - // interleave-4: - // it has big register pressure for x86/x64. - // and MSVC compilers for x86/x64 are slow for this branch. - // but if we have big number of registers, this branch can be faster. - - #define REP4(mac, dest, src, a, b, c, d) \ - mac(dest, src, a) \ - mac(dest, src, b) \ - mac(dest, src, c) \ - mac(dest, src, d) - - #define G2(index, a, b, c, d, x, y) \ - ADD_SIGMA (a, (index) + 2 * 0) \ - ADD_SIGMA (b, (index) + 2 * 1) \ - ADD_SIGMA (c, (index) + 2 * 2) \ - ADD_SIGMA (d, (index) + 2 * 3) \ - REP4 (ADD32M, 0, 1, a, b, c, d) \ - REP4 (XOR32M, 3, 0, a, b, c, d) \ - REP4 (RTR32M, 3, x, a, b, c, d) \ - REP4 (ADD32M, 2, 3, a, b, c, d) \ - REP4 (XOR32M, 1, 2, a, b, c, d) \ - REP4 (RTR32M, 1, y, a, b, c, d) \ - - #define G(a, b, c, d) \ - G2(a * 2 , a, b, c, d, 16, 12) \ - G2(a * 2 + 1, a, b, c, d, 8, 7) \ - - #define R2 \ - G(0, 1, 2, 3) \ - G(4, 5, 6, 7) \ - -#endif - - #define R(r) { const Byte *sigma = k_Blake2s_Sigma_4[r]; R2 } - - // Z7_BLAKE2S_UNROLL gives 5-6 KB larger code, but faster: - // 20-40% faster for (x86/x64) VC2010+/GCC/CLANG. - // 30-60% faster for (arm64-arm32) GCC. - // 5-11% faster for (arm64) CLANG-MAC. - // so Z7_BLAKE2S_UNROLL is good optimization, if there is no vector branch. - // But if there is vectors branch (for x86*), this scalar code will be unused mostly. - // So we want smaller code (without unrolling) in that case (x86*). -#if 0 || 1 && !defined(Z7_BLAKE2S_USE_VECTORS) - #define Z7_BLAKE2S_UNROLL -#endif - -#ifdef Z7_BLAKE2S_UNROLL - ROUNDS_LOOP_UNROLLED (R) -#else - ROUNDS_LOOP (R) -#endif - - #undef G - #undef G2 - #undef R - #undef R2 - - // printf("\n v after: \n"); - // PrintStates2((const UInt32 *)v, 1, 16); -#define XOR_s_PAIR_v(i) s[i] ^= v[i] ^ v[i + 8]; - - LOOP_8(XOR_s_PAIR_v) - // printf("\n s after:\n"); - // PrintStates2((const UInt32 *)s, 1, 16); -} - - -static -Z7_NO_INLINE -void -Z7_FASTCALL -Blake2sp_Compress2(UInt32 *s_items, const Byte *data, const Byte *end) -{ - size_t pos = 0; - // PrintStates2(s_items, 8, 16); - do - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); - Blake2s_Compress(s, data); - data += Z7_BLAKE2S_BLOCK_SIZE; - pos += Z7_BLAKE2S_BLOCK_SIZE; - pos &= SUPER_BLOCK_MASK; - } - while (data != end); -} - - -#ifdef Z7_BLAKE2S_USE_VECTORS - -static Z7_BLAKE2SP_FUNC_COMPRESS g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast = Blake2sp_Compress2; -static Z7_BLAKE2SP_FUNC_COMPRESS g_Z7_BLAKE2SP_FUNC_COMPRESS_Single = Blake2sp_Compress2; -static Z7_BLAKE2SP_FUNC_INIT g_Z7_BLAKE2SP_FUNC_INIT_Init; -static Z7_BLAKE2SP_FUNC_INIT g_Z7_BLAKE2SP_FUNC_INIT_Final; -static unsigned g_z7_Blake2sp_SupportedFlags; - - #define Z7_BLAKE2SP_Compress_Fast(p) (p)->u.header.func_Compress_Fast - #define Z7_BLAKE2SP_Compress_Single(p) (p)->u.header.func_Compress_Single -#else - #define Z7_BLAKE2SP_Compress_Fast(p) Blake2sp_Compress2 - #define Z7_BLAKE2SP_Compress_Single(p) Blake2sp_Compress2 -#endif // Z7_BLAKE2S_USE_VECTORS - - -#if 1 && defined(MY_CPU_LE) - #define GET_DIGEST(_s, _digest) \ - { memcpy(_digest, _s, Z7_BLAKE2S_DIGEST_SIZE); } -#else - #define GET_DIGEST(_s, _digest) \ - { unsigned _i; for (_i = 0; _i < 8; _i++) \ - { SetUi32((_digest) + 4 * _i, (_s)[_i]) } \ - } -#endif - - -/* ---------- BLAKE2s ---------- */ -/* -// we need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() -typedef struct -{ - Byte digest_length; - Byte key_length; - Byte fanout; // = 1 : in sequential mode - Byte depth; // = 1 : in sequential mode - UInt32 leaf_length; - Byte node_offset[6]; // 0 for the first, leftmost, leaf, or in sequential mode - Byte node_depth; // 0 for the leaves, or in sequential mode - Byte inner_length; // [0, 32], 0 in sequential mode - Byte salt[BLAKE2S_SALTBYTES]; - Byte personal[BLAKE2S_PERSONALBYTES]; -} CBlake2sParam; -*/ - -#define k_Blake2sp_IV_0 \ - (KIV(0) ^ (Z7_BLAKE2S_DIGEST_SIZE | ((UInt32)Z7_BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24))) -#define k_Blake2sp_IV_3_FROM_NODE_DEPTH(node_depth) \ - (KIV(3) ^ ((UInt32)(node_depth) << 16) ^ ((UInt32)Z7_BLAKE2S_DIGEST_SIZE << 24)) - -Z7_FORCE_INLINE -static void Blake2sp_Init_Spec(UInt32 *s, unsigned node_offset, unsigned node_depth) -{ - s[0] = k_Blake2sp_IV_0; - s[1] = KIV(1); - s[2] = KIV(2) ^ (UInt32)node_offset; - s[3] = k_Blake2sp_IV_3_FROM_NODE_DEPTH(node_depth); - s[4] = KIV(4); - s[5] = KIV(5); - s[6] = KIV(6); - s[7] = KIV(7); - - STATE_T(s)[0] = 0; - STATE_T(s)[1] = 0; - STATE_F(s)[0] = 0; - STATE_F(s)[1] = 0; -} - - -#ifdef Z7_BLAKE2S_USE_V128_FAST - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_128BIT - BLAKE2S_ATTRIB_128BIT -#endif -void -Z7_FASTCALL -Blake2sp_InitState_V128_Fast(UInt32 *states) -{ -#define STORE_128_PAIR_INIT_STATES_2(i, t0, t1) \ - { STORE_128_TO_STRUCT(states + 0 + 4 * (i), (t0)); \ - STORE_128_TO_STRUCT(states + 32 + 4 * (i), (t1)); \ - } -#define STORE_128_PAIR_INIT_STATES_1(i, mac) \ - { const __m128i t = mac; \ - STORE_128_PAIR_INIT_STATES_2(i, t, t) \ - } -#define STORE_128_PAIR_INIT_STATES_IV(i) \ - STORE_128_PAIR_INIT_STATES_1(i, GET_128_IV_WAY4(i)) - - STORE_128_PAIR_INIT_STATES_1 (0, _mm_set1_epi32((Int32)k_Blake2sp_IV_0)) - STORE_128_PAIR_INIT_STATES_IV (1) - { - const __m128i t = GET_128_IV_WAY4(2); - STORE_128_PAIR_INIT_STATES_2 (2, - XOR_128(t, _mm_set_epi32(3, 2, 1, 0)), - XOR_128(t, _mm_set_epi32(7, 6, 5, 4))) - } - STORE_128_PAIR_INIT_STATES_1 (3, _mm_set1_epi32((Int32)k_Blake2sp_IV_3_FROM_NODE_DEPTH(0))) - STORE_128_PAIR_INIT_STATES_IV (4) - STORE_128_PAIR_INIT_STATES_IV (5) - STORE_128_PAIR_INIT_STATES_IV (6) - STORE_128_PAIR_INIT_STATES_IV (7) - STORE_128_PAIR_INIT_STATES_1 (16, _mm_set_epi32(0, 0, 0, 0)) - // printf("\n== exit Blake2sp_InitState_V128_Fast ctr=%d\n", states[64]); -} - -#endif // Z7_BLAKE2S_USE_V128_FAST - - -#ifdef Z7_BLAKE2S_USE_AVX2_FAST - -static -Z7_NO_INLINE -#ifdef BLAKE2S_ATTRIB_AVX2 - BLAKE2S_ATTRIB_AVX2 -#endif -void -Z7_FASTCALL -Blake2sp_InitState_AVX2_Fast(UInt32 *states) -{ -#define STORE_256_INIT_STATES(i, t) \ - STORE_256_TO_STRUCT(states + 8 * (i), t); -#define STORE_256_INIT_STATES_IV(i) \ - STORE_256_INIT_STATES(i, GET_256_IV_WAY8(i)) - - STORE_256_INIT_STATES (0, _mm256_set1_epi32((Int32)k_Blake2sp_IV_0)) - STORE_256_INIT_STATES_IV (1) - STORE_256_INIT_STATES (2, XOR_256( GET_256_IV_WAY8(2), - _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0))) - STORE_256_INIT_STATES (3, _mm256_set1_epi32((Int32)k_Blake2sp_IV_3_FROM_NODE_DEPTH(0))) - STORE_256_INIT_STATES_IV (4) - STORE_256_INIT_STATES_IV (5) - STORE_256_INIT_STATES_IV (6) - STORE_256_INIT_STATES_IV (7) - STORE_256_INIT_STATES (8, _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0)) - // printf("\n== exit Blake2sp_InitState_AVX2_Fast\n"); -} - -#endif // Z7_BLAKE2S_USE_AVX2_FAST - - - -Z7_NO_INLINE -void Blake2sp_InitState(CBlake2sp *p) -{ - size_t i; - // memset(p->states, 0, sizeof(p->states)); // for debug - p->u.header.cycPos = 0; -#ifdef Z7_BLAKE2SP_USE_FUNCTIONS - if (p->u.header.func_Init) - { - p->u.header.func_Init(p->states); - return; - } -#endif - for (i = 0; i < Z7_BLAKE2SP_PARALLEL_DEGREE; i++) - Blake2sp_Init_Spec(p->states + i * NSW, (unsigned)i, 0); -} - -void Blake2sp_Init(CBlake2sp *p) -{ -#ifdef Z7_BLAKE2SP_USE_FUNCTIONS - p->u.header.func_Compress_Fast = -#ifdef Z7_BLAKE2S_USE_VECTORS - g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast; -#else - NULL; -#endif - - p->u.header.func_Compress_Single = -#ifdef Z7_BLAKE2S_USE_VECTORS - g_Z7_BLAKE2SP_FUNC_COMPRESS_Single; -#else - NULL; -#endif - - p->u.header.func_Init = -#ifdef Z7_BLAKE2S_USE_VECTORS - g_Z7_BLAKE2SP_FUNC_INIT_Init; -#else - NULL; -#endif - - p->u.header.func_Final = -#ifdef Z7_BLAKE2S_USE_VECTORS - g_Z7_BLAKE2SP_FUNC_INIT_Final; -#else - NULL; -#endif -#endif - - Blake2sp_InitState(p); -} - - -void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size) -{ - size_t pos; - // printf("\nsize = 0x%6x, cycPos = %5u data = %p\n", (unsigned)size, (unsigned)p->u.header.cycPos, data); - if (size == 0) - return; - pos = p->u.header.cycPos; - // pos < SUPER_BLOCK_SIZE * 2 : is expected - // pos == SUPER_BLOCK_SIZE * 2 : is not expected, but is supported also - { - const size_t pos2 = pos & SUPER_BLOCK_MASK; - if (pos2) - { - const size_t rem = SUPER_BLOCK_SIZE - pos2; - if (rem > size) - { - p->u.header.cycPos = (unsigned)(pos + size); - // cycPos < SUPER_BLOCK_SIZE * 2 - memcpy((Byte *)(void *)p->buf32 + pos, data, size); - /* to simpilify the code here we don't try to process first superblock, - if (cycPos > SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE) */ - return; - } - // (rem <= size) - memcpy((Byte *)(void *)p->buf32 + pos, data, rem); - pos += rem; - data += rem; - size -= rem; - } - } - - // pos <= SUPER_BLOCK_SIZE * 2 - // pos % SUPER_BLOCK_SIZE == 0 - if (pos) - { - /* pos == SUPER_BLOCK_SIZE || - pos == SUPER_BLOCK_SIZE * 2 */ - size_t end = pos; - if (size > SUPER_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE - || (end -= SUPER_BLOCK_SIZE)) - { - Z7_BLAKE2SP_Compress_Fast(p)(p->states, - (const Byte *)(const void *)p->buf32, - (const Byte *)(const void *)p->buf32 + end); - if (pos -= end) - memcpy(p->buf32, (const Byte *)(const void *)p->buf32 - + SUPER_BLOCK_SIZE, SUPER_BLOCK_SIZE); - } - } - - // pos == 0 || (pos == SUPER_BLOCK_SIZE && size <= SUPER_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE) - if (size > SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE) - { - // pos == 0 - const Byte *end; - const size_t size2 = (size - (SUPER_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE + 1)) - & ~(size_t)SUPER_BLOCK_MASK; - size -= size2; - // size < SUPER_BLOCK_SIZE * 2 - end = data + size2; - Z7_BLAKE2SP_Compress_Fast(p)(p->states, data, end); - data = end; - } - - if (size != 0) - { - memcpy((Byte *)(void *)p->buf32 + pos, data, size); - pos += size; - } - p->u.header.cycPos = (unsigned)pos; - // cycPos < SUPER_BLOCK_SIZE * 2 -} - - -void Blake2sp_Final(CBlake2sp *p, Byte *digest) -{ - // UInt32 * const R_states = p->states; - // printf("\nBlake2sp_Final \n"); -#ifdef Z7_BLAKE2SP_USE_FUNCTIONS - if (p->u.header.func_Final) - p->u.header.func_Final(p->states); -#endif - // printf("\n=====\nBlake2sp_Final \n"); - // PrintStates(p->states, 32); - - // (p->u.header.cycPos == SUPER_BLOCK_SIZE) can be processed in any branch: - if (p->u.header.cycPos <= SUPER_BLOCK_SIZE) - { - unsigned pos; - memset((Byte *)(void *)p->buf32 + p->u.header.cycPos, - 0, SUPER_BLOCK_SIZE - p->u.header.cycPos); - STATE_F(&p->states[(Z7_BLAKE2SP_PARALLEL_DEGREE - 1) * NSW])[1] = BLAKE2S_FINAL_FLAG; - for (pos = 0; pos < SUPER_BLOCK_SIZE; pos += Z7_BLAKE2S_BLOCK_SIZE) - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, pos); - Blake2s_Set_LastBlock(s) - if (pos + Z7_BLAKE2S_BLOCK_SIZE > p->u.header.cycPos) - { - UInt32 delta = Z7_BLAKE2S_BLOCK_SIZE; - if (pos < p->u.header.cycPos) - delta -= p->u.header.cycPos & (Z7_BLAKE2S_BLOCK_SIZE - 1); - // 0 < delta <= Z7_BLAKE2S_BLOCK_SIZE - { - const UInt32 v = STATE_T(s)[0]; - STATE_T(s)[1] -= v < delta; // (v < delta) is same condition here as (v == 0) - STATE_T(s)[0] = v - delta; - } - } - } - // PrintStates(p->states, 16); - Z7_BLAKE2SP_Compress_Single(p)(p->states, - (Byte *)(void *)p->buf32, - (Byte *)(void *)p->buf32 + SUPER_BLOCK_SIZE); - // PrintStates(p->states, 16); - } - else - { - // (p->u.header.cycPos > SUPER_BLOCK_SIZE) - unsigned pos; - for (pos = 0; pos < SUPER_BLOCK_SIZE; pos += Z7_BLAKE2S_BLOCK_SIZE) - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, pos); - if (pos + SUPER_BLOCK_SIZE >= p->u.header.cycPos) - Blake2s_Set_LastBlock(s) - } - if (p->u.header.cycPos <= SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE) - STATE_F(&p->states[(Z7_BLAKE2SP_PARALLEL_DEGREE - 1) * NSW])[1] = BLAKE2S_FINAL_FLAG; - - Z7_BLAKE2SP_Compress_Single(p)(p->states, - (Byte *)(void *)p->buf32, - (Byte *)(void *)p->buf32 + SUPER_BLOCK_SIZE); - - // if (p->u.header.cycPos > SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE; - STATE_F(&p->states[(Z7_BLAKE2SP_PARALLEL_DEGREE - 1) * NSW])[1] = BLAKE2S_FINAL_FLAG; - - // if (p->u.header.cycPos != SUPER_BLOCK_SIZE) - { - pos = SUPER_BLOCK_SIZE; - for (;;) - { - UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, pos & SUPER_BLOCK_MASK); - Blake2s_Set_LastBlock(s) - pos += Z7_BLAKE2S_BLOCK_SIZE; - if (pos >= p->u.header.cycPos) - { - if (pos != p->u.header.cycPos) - { - const UInt32 delta = pos - p->u.header.cycPos; - const UInt32 v = STATE_T(s)[0]; - STATE_T(s)[1] -= v < delta; - STATE_T(s)[0] = v - delta; - memset((Byte *)(void *)p->buf32 + p->u.header.cycPos, 0, delta); - } - break; - } - } - Z7_BLAKE2SP_Compress_Single(p)(p->states, - (Byte *)(void *)p->buf32 + SUPER_BLOCK_SIZE, - (Byte *)(void *)p->buf32 + pos); - } - } - - { - size_t pos; - for (pos = 0; pos < SUPER_BLOCK_SIZE / 2; pos += Z7_BLAKE2S_BLOCK_SIZE / 2) - { - const UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, (pos * 2)); - Byte *dest = (Byte *)(void *)p->buf32 + pos; - GET_DIGEST(s, dest) - } - } - Blake2sp_Init_Spec(p->states, 0, 1); - { - size_t pos; - for (pos = 0; pos < (Z7_BLAKE2SP_PARALLEL_DEGREE * Z7_BLAKE2S_DIGEST_SIZE) - - Z7_BLAKE2S_BLOCK_SIZE; pos += Z7_BLAKE2S_BLOCK_SIZE) - { - Z7_BLAKE2SP_Compress_Single(p)(p->states, - (const Byte *)(const void *)p->buf32 + pos, - (const Byte *)(const void *)p->buf32 + pos + Z7_BLAKE2S_BLOCK_SIZE); - } - } - // Blake2s_Final(p->states, 0, digest, p, (Byte *)(void *)p->buf32 + i); - Blake2s_Set_LastBlock(p->states) - STATE_F(p->states)[1] = BLAKE2S_FINAL_FLAG; - { - Z7_BLAKE2SP_Compress_Single(p)(p->states, - (const Byte *)(const void *)p->buf32 + Z7_BLAKE2SP_PARALLEL_DEGREE / 2 * Z7_BLAKE2S_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE, - (const Byte *)(const void *)p->buf32 + Z7_BLAKE2SP_PARALLEL_DEGREE / 2 * Z7_BLAKE2S_BLOCK_SIZE); - } - GET_DIGEST(p->states, digest) - // printf("\n Blake2sp_Final 555 numDataInBufs = %5u\n", (unsigned)p->u.header.numDataInBufs); -} - - -BoolInt Blake2sp_SetFunction(CBlake2sp *p, unsigned algo) -{ - // printf("\n========== setfunction = %d ======== \n", algo); -#ifdef Z7_BLAKE2SP_USE_FUNCTIONS - Z7_BLAKE2SP_FUNC_COMPRESS func = NULL; - Z7_BLAKE2SP_FUNC_COMPRESS func_Single = NULL; - Z7_BLAKE2SP_FUNC_INIT func_Final = NULL; - Z7_BLAKE2SP_FUNC_INIT func_Init = NULL; -#else - UNUSED_VAR(p) -#endif - -#ifdef Z7_BLAKE2S_USE_VECTORS - - func = func_Single = Blake2sp_Compress2; - - if (algo != Z7_BLAKE2SP_ALGO_SCALAR) - { - // printf("\n========== setfunction NON-SCALER ======== \n"); - if (algo == Z7_BLAKE2SP_ALGO_DEFAULT) - { - func = g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast; - func_Single = g_Z7_BLAKE2SP_FUNC_COMPRESS_Single; - func_Init = g_Z7_BLAKE2SP_FUNC_INIT_Init; - func_Final = g_Z7_BLAKE2SP_FUNC_INIT_Final; - } - else - { - if ((g_z7_Blake2sp_SupportedFlags & (1u << algo)) == 0) - return False; - -#ifdef Z7_BLAKE2S_USE_AVX2 - - func_Single = -#if defined(Z7_BLAKE2S_USE_AVX2_WAY2) - Blake2sp_Compress2_AVX2_Way2; -#else - Z7_BLAKE2S_Compress2_V128; -#endif - -#ifdef Z7_BLAKE2S_USE_AVX2_FAST - if (algo == Z7_BLAKE2SP_ALGO_V256_FAST) - { - func = Blake2sp_Compress2_AVX2_Fast; - func_Final = Blake2sp_Final_AVX2_Fast; - func_Init = Blake2sp_InitState_AVX2_Fast; - } - else -#endif -#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 - if (algo == Z7_BLAKE2SP_ALGO_V256_WAY2) - func = Blake2sp_Compress2_AVX2_Way2; - else -#endif -#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 - if (algo == Z7_BLAKE2SP_ALGO_V256_WAY4) - { - func_Single = func = Blake2sp_Compress2_AVX2_Way4; - } - else -#endif -#endif // avx2 - { - if (algo == Z7_BLAKE2SP_ALGO_V128_FAST) - { - func = Blake2sp_Compress2_V128_Fast; - func_Final = Blake2sp_Final_V128_Fast; - func_Init = Blake2sp_InitState_V128_Fast; - func_Single = Z7_BLAKE2S_Compress2_V128; - } - else -#ifdef Z7_BLAKE2S_USE_V128_WAY2 - if (algo == Z7_BLAKE2SP_ALGO_V128_WAY2) - func = func_Single = Blake2sp_Compress2_V128_Way2; - else -#endif - { - if (algo != Z7_BLAKE2SP_ALGO_V128_WAY1) - return False; - func = func_Single = Blake2sp_Compress2_V128_Way1; - } - } - } - } -#else // !VECTORS - if (algo > 1) // Z7_BLAKE2SP_ALGO_SCALAR - return False; -#endif // !VECTORS - -#ifdef Z7_BLAKE2SP_USE_FUNCTIONS - p->u.header.func_Compress_Fast = func; - p->u.header.func_Compress_Single = func_Single; - p->u.header.func_Final = func_Final; - p->u.header.func_Init = func_Init; -#endif - // printf("\n p->u.header.func_Compress = %p", p->u.header.func_Compress); - return True; -} - - -void z7_Black2sp_Prepare(void) -{ -#ifdef Z7_BLAKE2S_USE_VECTORS - unsigned flags = 0; // (1u << Z7_BLAKE2SP_ALGO_V128_SCALAR); - - Z7_BLAKE2SP_FUNC_COMPRESS func_Fast = Blake2sp_Compress2; - Z7_BLAKE2SP_FUNC_COMPRESS func_Single = Blake2sp_Compress2; - Z7_BLAKE2SP_FUNC_INIT func_Init = NULL; - Z7_BLAKE2SP_FUNC_INIT func_Final = NULL; - -#if defined(MY_CPU_X86_OR_AMD64) - #if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) - // optional check - #if 0 || !(defined(__AVX512F__) && defined(__AVX512VL__)) - if (CPU_IsSupported_AVX512F_AVX512VL()) - #endif - #elif defined(Z7_BLAKE2S_USE_SSE41) - if (CPU_IsSupported_SSE41()) - #elif defined(Z7_BLAKE2S_USE_SSSE3) - if (CPU_IsSupported_SSSE3()) - #elif !defined(MY_CPU_AMD64) - if (CPU_IsSupported_SSE2()) - #endif -#endif - { - #if defined(Z7_BLAKE2S_USE_SSE41) - // printf("\n========== Blake2s SSE41 128-bit\n"); - #elif defined(Z7_BLAKE2S_USE_SSSE3) - // printf("\n========== Blake2s SSSE3 128-bit\n"); - #else - // printf("\n========== Blake2s SSE2 128-bit\n"); - #endif - // func_Fast = f_vector = Blake2sp_Compress2_V128_Way2; - // printf("\n========== Blake2sp_Compress2_V128_Way2\n"); - func_Fast = - func_Single = Z7_BLAKE2S_Compress2_V128; - flags |= (1u << Z7_BLAKE2SP_ALGO_V128_WAY1); -#ifdef Z7_BLAKE2S_USE_V128_WAY2 - flags |= (1u << Z7_BLAKE2SP_ALGO_V128_WAY2); -#endif -#ifdef Z7_BLAKE2S_USE_V128_FAST - flags |= (1u << Z7_BLAKE2SP_ALGO_V128_FAST); - func_Fast = Blake2sp_Compress2_V128_Fast; - func_Init = Blake2sp_InitState_V128_Fast; - func_Final = Blake2sp_Final_V128_Fast; -#endif - -#ifdef Z7_BLAKE2S_USE_AVX2 -#if defined(MY_CPU_X86_OR_AMD64) - - #if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) - #if 0 - if (CPU_IsSupported_AVX512F_AVX512VL()) - #endif - #else - if (CPU_IsSupported_AVX2()) - #endif -#endif - { - // #pragma message ("=== Blake2s AVX2") - // printf("\n========== Blake2s AVX2\n"); - -#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 - func_Single = Blake2sp_Compress2_AVX2_Way2; - flags |= (1u << Z7_BLAKE2SP_ALGO_V256_WAY2); -#endif -#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 - flags |= (1u << Z7_BLAKE2SP_ALGO_V256_WAY4); -#endif - -#ifdef Z7_BLAKE2S_USE_AVX2_FAST - flags |= (1u << Z7_BLAKE2SP_ALGO_V256_FAST); - func_Fast = Blake2sp_Compress2_AVX2_Fast; - func_Init = Blake2sp_InitState_AVX2_Fast; - func_Final = Blake2sp_Final_AVX2_Fast; -#elif defined(Z7_BLAKE2S_USE_AVX2_WAY4) - func_Fast = Blake2sp_Compress2_AVX2_Way4; -#elif defined(Z7_BLAKE2S_USE_AVX2_WAY2) - func_Fast = Blake2sp_Compress2_AVX2_Way2; -#endif - } // avx2 -#endif // avx2 - } // sse* - g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast = func_Fast; - g_Z7_BLAKE2SP_FUNC_COMPRESS_Single = func_Single; - g_Z7_BLAKE2SP_FUNC_INIT_Init = func_Init; - g_Z7_BLAKE2SP_FUNC_INIT_Final = func_Final; - g_z7_Blake2sp_SupportedFlags = flags; - // printf("\nflags=%x\n", flags); -#endif // vectors -} - -/* -#ifdef Z7_BLAKE2S_USE_VECTORS -void align_test2(CBlake2sp *sp); -void align_test2(CBlake2sp *sp) -{ - __m128i a = LOAD_128(sp->states); - D_XOR_128(a, LOAD_128(sp->states + 4)); - STORE_128(sp->states, a); -} -void align_test2(void); -void align_test2(void) -{ - CBlake2sp sp; - Blake2sp_Init(&sp); - Blake2sp_Update(&sp, NULL, 0); -} -#endif -*/ +/* Blake2s.c -- BLAKE2sp Hash +2024-05-18 : Igor Pavlov : Public domain +2015-2019 : Samuel Neves : original code : CC0 1.0 Universal (CC0 1.0). */ + +#include "Precomp.h" + +// #include +#include + +#include "Blake2.h" +#include "RotateDefs.h" +#include "Compiler.h" +#include "CpuArch.h" + +/* + if defined(__AVX512F__) && defined(__AVX512VL__) + { + we define Z7_BLAKE2S_USE_AVX512_ALWAYS, + but the compiler can use avx512 for any code. + } + else if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) + { we use avx512 only for sse* and avx* branches of code. } +*/ +// #define Z7_BLAKE2S_USE_AVX512_ALWAYS // for debug + +#if defined(__SSE2__) + #define Z7_BLAKE2S_USE_VECTORS +#elif defined(MY_CPU_X86_OR_AMD64) + #if defined(_MSC_VER) && _MSC_VER > 1200 \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 30300) \ + || defined(__clang__) \ + || defined(__INTEL_COMPILER) + #define Z7_BLAKE2S_USE_VECTORS + #endif +#endif + +#ifdef Z7_BLAKE2S_USE_VECTORS + +#define Z7_BLAKE2SP_USE_FUNCTIONS + +// define Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED, if CBlake2sp can be non aligned for 32-bytes. +// #define Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED + +// SSSE3 : for _mm_shuffle_epi8 (pshufb) that improves the performance for 5-15%. +#if defined(__SSSE3__) + #define Z7_BLAKE2S_USE_SSSE3 +#elif defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1500) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40300) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40000) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 20300) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1000) + #define Z7_BLAKE2S_USE_SSSE3 +#endif + +#ifdef Z7_BLAKE2S_USE_SSSE3 +/* SSE41 : for _mm_insert_epi32 (pinsrd) + it can slightly reduce code size and improves the performance in some cases. + it's used only for last 512-1024 bytes, if FAST versions (2 or 3) of vector algos are used. + it can be used for all blocks in another algos (4+). +*/ +#if defined(__SSE4_1__) + #define Z7_BLAKE2S_USE_SSE41 +#elif defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1500) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40300) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40000) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 20300) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1000) + #define Z7_BLAKE2S_USE_SSE41 +#endif +#endif // SSSE3 + +#if defined(__GNUC__) || defined(__clang__) +#if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) && !(defined(__AVX512F__) && defined(__AVX512VL__)) + #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("avx512vl,avx512f"))) +#else + #if defined(Z7_BLAKE2S_USE_SSE41) + #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("sse4.1"))) + #elif defined(Z7_BLAKE2S_USE_SSSE3) + #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("ssse3"))) + #else + #define BLAKE2S_ATTRIB_128BIT __attribute__((__target__("sse2"))) + #endif +#endif +#endif + + +#if defined(__AVX2__) + #define Z7_BLAKE2S_USE_AVX2 +#else + #if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) + #define Z7_BLAKE2S_USE_AVX2 + #ifdef Z7_BLAKE2S_USE_AVX2 +#if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) && !(defined(__AVX512F__) && defined(__AVX512VL__)) + #define BLAKE2S_ATTRIB_AVX2 __attribute__((__target__("avx512vl,avx512f"))) +#else + #define BLAKE2S_ATTRIB_AVX2 __attribute__((__target__("avx2"))) +#endif + #endif + #elif defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) + #if (Z7_MSC_VER_ORIGINAL == 1900) + #pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX + #endif + #define Z7_BLAKE2S_USE_AVX2 + #endif +#endif + +#ifdef Z7_BLAKE2S_USE_SSE41 +#include // SSE4.1 +#elif defined(Z7_BLAKE2S_USE_SSSE3) +#include // SSSE3 +#else +#include // SSE2 +#endif + +#ifdef Z7_BLAKE2S_USE_AVX2 +#include +#if defined(__clang__) +#include +#include +#endif +#endif // avx2 + + +#if defined(__AVX512F__) && defined(__AVX512VL__) + // && defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL > 1930) + #ifndef Z7_BLAKE2S_USE_AVX512_ALWAYS + #define Z7_BLAKE2S_USE_AVX512_ALWAYS + #endif + // #pragma message ("=== Blake2s AVX512") +#endif + + +#define Z7_BLAKE2S_USE_V128_FAST +// for speed optimization for small messages: +// #define Z7_BLAKE2S_USE_V128_WAY2 + +#ifdef Z7_BLAKE2S_USE_AVX2 + +// for debug: +// gather is slow +// #define Z7_BLAKE2S_USE_GATHER + + #define Z7_BLAKE2S_USE_AVX2_FAST +// for speed optimization for small messages: +// #define Z7_BLAKE2S_USE_AVX2_WAY2 +// #define Z7_BLAKE2S_USE_AVX2_WAY4 +#if defined(Z7_BLAKE2S_USE_AVX2_WAY2) || \ + defined(Z7_BLAKE2S_USE_AVX2_WAY4) + #define Z7_BLAKE2S_USE_AVX2_WAY_SLOW +#endif +#endif + + #define Z7_BLAKE2SP_ALGO_DEFAULT 0 + #define Z7_BLAKE2SP_ALGO_SCALAR 1 +#ifdef Z7_BLAKE2S_USE_V128_FAST + #define Z7_BLAKE2SP_ALGO_V128_FAST 2 +#endif +#ifdef Z7_BLAKE2S_USE_AVX2_FAST + #define Z7_BLAKE2SP_ALGO_V256_FAST 3 +#endif + #define Z7_BLAKE2SP_ALGO_V128_WAY1 4 +#ifdef Z7_BLAKE2S_USE_V128_WAY2 + #define Z7_BLAKE2SP_ALGO_V128_WAY2 5 +#endif +#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 + #define Z7_BLAKE2SP_ALGO_V256_WAY2 6 +#endif +#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 + #define Z7_BLAKE2SP_ALGO_V256_WAY4 7 +#endif + +#endif // Z7_BLAKE2S_USE_VECTORS + + + + +#define BLAKE2S_FINAL_FLAG (~(UInt32)0) +#define NSW Z7_BLAKE2SP_NUM_STRUCT_WORDS +#define SUPER_BLOCK_SIZE (Z7_BLAKE2S_BLOCK_SIZE * Z7_BLAKE2SP_PARALLEL_DEGREE) +#define SUPER_BLOCK_MASK (SUPER_BLOCK_SIZE - 1) + +#define V_INDEX_0_0 0 +#define V_INDEX_1_0 1 +#define V_INDEX_2_0 2 +#define V_INDEX_3_0 3 +#define V_INDEX_0_1 4 +#define V_INDEX_1_1 5 +#define V_INDEX_2_1 6 +#define V_INDEX_3_1 7 +#define V_INDEX_0_2 8 +#define V_INDEX_1_2 9 +#define V_INDEX_2_2 10 +#define V_INDEX_3_2 11 +#define V_INDEX_0_3 12 +#define V_INDEX_1_3 13 +#define V_INDEX_2_3 14 +#define V_INDEX_3_3 15 +#define V_INDEX_4_0 0 +#define V_INDEX_5_0 1 +#define V_INDEX_6_0 2 +#define V_INDEX_7_0 3 +#define V_INDEX_7_1 4 +#define V_INDEX_4_1 5 +#define V_INDEX_5_1 6 +#define V_INDEX_6_1 7 +#define V_INDEX_6_2 8 +#define V_INDEX_7_2 9 +#define V_INDEX_4_2 10 +#define V_INDEX_5_2 11 +#define V_INDEX_5_3 12 +#define V_INDEX_6_3 13 +#define V_INDEX_7_3 14 +#define V_INDEX_4_3 15 + +#define V(row, col) v[V_INDEX_ ## row ## _ ## col] + +#define k_Blake2s_IV_0 0x6A09E667UL +#define k_Blake2s_IV_1 0xBB67AE85UL +#define k_Blake2s_IV_2 0x3C6EF372UL +#define k_Blake2s_IV_3 0xA54FF53AUL +#define k_Blake2s_IV_4 0x510E527FUL +#define k_Blake2s_IV_5 0x9B05688CUL +#define k_Blake2s_IV_6 0x1F83D9ABUL +#define k_Blake2s_IV_7 0x5BE0CD19UL + +#define KIV(n) (k_Blake2s_IV_## n) + +#ifdef Z7_BLAKE2S_USE_VECTORS +MY_ALIGN(16) +static const UInt32 k_Blake2s_IV[8] = +{ + KIV(0), KIV(1), KIV(2), KIV(3), KIV(4), KIV(5), KIV(6), KIV(7) +}; +#endif + +#define STATE_T(s) ((s) + 8) +#define STATE_F(s) ((s) + 10) + +#ifdef Z7_BLAKE2S_USE_VECTORS + +#define LOAD_128(p) _mm_load_si128 ((const __m128i *)(const void *)(p)) +#define LOADU_128(p) _mm_loadu_si128((const __m128i *)(const void *)(p)) +#ifdef Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED + // here we use unaligned load and stores + // use this branch if CBlake2sp can be unaligned for 16 bytes + #define STOREU_128(p, r) _mm_storeu_si128((__m128i *)(void *)(p), r) + #define LOAD_128_FROM_STRUCT(p) LOADU_128(p) + #define STORE_128_TO_STRUCT(p, r) STOREU_128(p, r) +#else + // here we use aligned load and stores + // use this branch if CBlake2sp is aligned for 16 bytes + #define STORE_128(p, r) _mm_store_si128((__m128i *)(void *)(p), r) + #define LOAD_128_FROM_STRUCT(p) LOAD_128(p) + #define STORE_128_TO_STRUCT(p, r) STORE_128(p, r) +#endif + +#endif // Z7_BLAKE2S_USE_VECTORS + + +#if 0 +static void PrintState(const UInt32 *s, unsigned num) +{ + unsigned i; + printf("\n"); + for (i = 0; i < num; i++) + printf(" %08x", (unsigned)s[i]); +} +static void PrintStates2(const UInt32 *s, unsigned x, unsigned y) +{ + unsigned i; + for (i = 0; i < y; i++) + PrintState(s + i * x, x); + printf("\n"); +} +#endif + + +#define REP8_MACRO(m) { m(0) m(1) m(2) m(3) m(4) m(5) m(6) m(7) } + +#define BLAKE2S_NUM_ROUNDS 10 + +#if defined(Z7_BLAKE2S_USE_VECTORS) +#define ROUNDS_LOOP(mac) \ + { unsigned r; for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++) mac(r) } +#endif +/* +#define ROUNDS_LOOP_2(mac) \ + { unsigned r; for (r = 0; r < BLAKE2S_NUM_ROUNDS; r += 2) { mac(r) mac(r + 1) } } +*/ +#if 0 || 1 && !defined(Z7_BLAKE2S_USE_VECTORS) +#define ROUNDS_LOOP_UNROLLED(m) \ + { m(0) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) } +#endif + +#define SIGMA_TABLE(M) \ + M( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ), \ + M( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ), \ + M( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ), \ + M( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ), \ + M( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ), \ + M( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ), \ + M( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ), \ + M( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ), \ + M( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ), \ + M( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ) + +#define SIGMA_TABLE_MULT(m, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ + { a0*m,a1*m,a2*m,a3*m,a4*m,a5*m,a6*m,a7*m,a8*m,a9*m,a10*m,a11*m,a12*m,a13*m,a14*m,a15*m } +#define SIGMA_TABLE_MULT_4( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ + SIGMA_TABLE_MULT(4, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) + +// MY_ALIGN(32) +MY_ALIGN(16) +static const Byte k_Blake2s_Sigma_4[BLAKE2S_NUM_ROUNDS][16] = + { SIGMA_TABLE(SIGMA_TABLE_MULT_4) }; + +#define GET_SIGMA_PTR(p, index) \ + ((const void *)((const Byte *)(const void *)(p) + (index))) + +#define GET_STATE_TABLE_PTR_FROM_BYTE_POS(s, pos) \ + ((UInt32 *)(void *)((Byte *)(void *)(s) + (pos))) + + +#ifdef Z7_BLAKE2S_USE_VECTORS + + +#if 0 + // use loading constants from memory + // is faster for some compilers. + #define KK4(n) KIV(n), KIV(n), KIV(n), KIV(n) +MY_ALIGN(64) +static const UInt32 k_Blake2s_IV_WAY4[]= +{ + KK4(0), KK4(1), KK4(2), KK4(3), KK4(4), KK4(5), KK4(6), KK4(7) +}; + #define GET_128_IV_WAY4(i) LOAD_128(k_Blake2s_IV_WAY4 + 4 * (i)) +#else + // use constant generation: + #define GET_128_IV_WAY4(i) _mm_set1_epi32((Int32)KIV(i)) +#endif + + +#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW +#define GET_CONST_128_FROM_ARRAY32(k) \ + _mm_set_epi32((Int32)(k)[3], (Int32)(k)[2], (Int32)(k)[1], (Int32)(k)[0]) +#endif + + +#if 0 +#define k_r8 _mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1) +#define k_r16 _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2) +#define k_inc _mm_set_epi32(0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE) +#define k_iv0_128 GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 0) +#define k_iv4_128 GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 4) +#else +#if defined(Z7_BLAKE2S_USE_SSSE3) && \ + !defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) +MY_ALIGN(16) static const Byte k_r8_arr [16] = { 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8 ,13, 14, 15, 12 }; +MY_ALIGN(16) static const Byte k_r16_arr[16] = { 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 }; +#define k_r8 LOAD_128(k_r8_arr) +#define k_r16 LOAD_128(k_r16_arr) +#endif +MY_ALIGN(16) static const UInt32 k_inc_arr[4] = { Z7_BLAKE2S_BLOCK_SIZE, 0, 0, 0 }; +#define k_inc LOAD_128(k_inc_arr) +#define k_iv0_128 LOAD_128(k_Blake2s_IV + 0) +#define k_iv4_128 LOAD_128(k_Blake2s_IV + 4) +#endif + + +#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW + +#ifdef Z7_BLAKE2S_USE_AVX2 +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 80000) + #define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1) +#else + #define MY_mm256_set_m128i _mm256_set_m128i +#endif + +#define SET_FROM_128(a) MY_mm256_set_m128i(a, a) + +#ifndef Z7_BLAKE2S_USE_AVX512_ALWAYS +MY_ALIGN(32) static const Byte k_r8_arr_256 [32] = +{ + 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8 ,13, 14, 15, 12, + 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8 ,13, 14, 15, 12 +}; +MY_ALIGN(32) static const Byte k_r16_arr_256[32] = +{ + 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13, + 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 +}; +#define k_r8_256 LOAD_256(k_r8_arr_256) +#define k_r16_256 LOAD_256(k_r16_arr_256) +#endif + +// #define k_r8_256 SET_FROM_128(_mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)) +// #define k_r16_256 SET_FROM_128(_mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2)) +// #define k_inc_256 SET_FROM_128(_mm_set_epi32(0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE)) +// #define k_iv0_256 SET_FROM_128(GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 0)) +#define k_iv4_256 SET_FROM_128(GET_CONST_128_FROM_ARRAY32(k_Blake2s_IV + 4)) +#endif // Z7_BLAKE2S_USE_AVX2_WAY_SLOW +#endif + + +/* +IPC(TP) ports: +1 p__5 : skl- : SSE : shufps : _mm_shuffle_ps +2 p_15 : icl+ +1 p__5 : nhm-bdw : SSE : xorps : _mm_xor_ps +3 p015 : skl+ + +3 p015 : SSE2 : pxor : _mm_xor_si128 +2 p_15: snb-bdw : SSE2 : padd : _mm_add_epi32 +2 p0_5: mrm-wsm : +3 p015 : skl+ + +2 p_15 : ivb-,icl+ : SSE2 : punpcklqdq, punpckhqdq, punpckldq, punpckhdq +2 p_15 : : SSE2 : pshufd : _mm_shuffle_epi32 +2 p_15 : : SSE2 : pshuflw : _mm_shufflelo_epi16 +2 p_15 : : SSE2 : psrldq : +2 p_15 : : SSE3 : pshufb : _mm_shuffle_epi8 +2 p_15 : : SSE4 : pblendw : _mm_blend_epi16 +1 p__5 : hsw-skl : * + +1 p0 : SSE2 : pslld (i8) : _mm_slli_si128 +2 p01 : skl+ : + +2 p_15 : ivb- : SSE3 : palignr +1 p__5 : hsw+ + +2 p_15 + p23 : ivb-, icl+ : SSE4 : pinsrd : _mm_insert_epi32(xmm, m32, i8) +1 p__5 + p23 : hsw-skl +1 p_15 + p5 : ivb-, ice+ : SSE4 : pinsrd : _mm_insert_epi32(xmm, r32, i8) +0.5 2*p5 : hsw-skl + +2 p23 : SSE2 : movd (m32) +3 p23A : adl : +1 p5: : SSE2 : movd (r32) +*/ + +#if 0 && defined(__XOP__) +// we must debug and test __XOP__ instruction +#include +#include + #define LOAD_ROTATE_CONSTS + #define MM_ROR_EPI32(r, c) _mm_roti_epi32(r, -(c)) + #define Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED +#elif 1 && defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) + #define LOAD_ROTATE_CONSTS + #define MM_ROR_EPI32(r, c) _mm_ror_epi32(r, c) + #define Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED +#else + +// MSVC_1937+ uses "orps" instruction for _mm_or_si128(). +// But "orps" has low throughput: TP=1 for bdw-nhm. +// So it can be better to use _mm_add_epi32()/"paddd" (TP=2 for bdw-nhm) instead of "xorps". +// But "orps" is fast for modern cpus (skl+). +// So we are default with "or" version: +#if 0 || 0 && defined(Z7_MSC_VER_ORIGINAL) && Z7_MSC_VER_ORIGINAL > 1937 + // minor optimization for some old cpus, if "xorps" is slow. + #define MM128_EPI32_OR_or_ADD _mm_add_epi32 +#else + #define MM128_EPI32_OR_or_ADD _mm_or_si128 +#endif + + #define MM_ROR_EPI32_VIA_SHIFT(r, c)( \ + MM128_EPI32_OR_or_ADD( \ + _mm_srli_epi32((r), (c)), \ + _mm_slli_epi32((r), 32-(c)))) + #if defined(Z7_BLAKE2S_USE_SSSE3) || defined(Z7_BLAKE2S_USE_SSE41) + #define LOAD_ROTATE_CONSTS \ + const __m128i r8 = k_r8; \ + const __m128i r16 = k_r16; + #define MM_ROR_EPI32(r, c) ( \ + ( 8==(c)) ? _mm_shuffle_epi8(r,r8) \ + : (16==(c)) ? _mm_shuffle_epi8(r,r16) \ + : MM_ROR_EPI32_VIA_SHIFT(r, c)) + #else + #define LOAD_ROTATE_CONSTS + #define MM_ROR_EPI32(r, c) ( \ + (16==(c)) ? _mm_shufflehi_epi16(_mm_shufflelo_epi16(r, 0xb1), 0xb1) \ + : MM_ROR_EPI32_VIA_SHIFT(r, c)) + #endif +#endif + +/* +we have 3 main ways to load 4 32-bit integers to __m128i: + 1) SSE2: _mm_set_epi32() + 2) SSE2: _mm_unpacklo_epi64() / _mm_unpacklo_epi32 / _mm_cvtsi32_si128() + 3) SSE41: _mm_insert_epi32() and _mm_cvtsi32_si128() +good compiler for _mm_set_epi32() generates these instructions: +{ + movd xmm, [m32]; vpunpckldq; vpunpckldq; vpunpcklqdq; +} +good new compiler generates one instruction +{ + for _mm_insert_epi32() : { pinsrd xmm, [m32], i } + for _mm_cvtsi32_si128() : { movd xmm, [m32] } +} +but vc2010 generates slow pair of instructions: +{ + for _mm_insert_epi32() : { mov r32, [m32]; pinsrd xmm, r32, i } + for _mm_cvtsi32_si128() : { mov r32, [m32]; movd xmm, r32 } +} +_mm_insert_epi32() (pinsrd) code reduces xmm register pressure +in comparison with _mm_set_epi32() (movd + vpunpckld) code. +Note that variant with "movd xmm, r32" can be more slow, +but register pressure can be more important. +So we can force to "pinsrd" always. +*/ +// #if !defined(Z7_MSC_VER_ORIGINAL) || Z7_MSC_VER_ORIGINAL > 1600 || defined(MY_CPU_X86) +#ifdef Z7_BLAKE2S_USE_SSE41 + /* _mm_set_epi32() can be more effective for GCC and CLANG + _mm_insert_epi32() is more effective for MSVC */ + #if 0 || 1 && defined(Z7_MSC_VER_ORIGINAL) + #define Z7_BLAKE2S_USE_INSERT_INSTRUCTION + #endif +#endif // USE_SSE41 +// #endif + +#ifdef Z7_BLAKE2S_USE_INSERT_INSTRUCTION + // for SSE4.1 +#define MM_LOAD_EPI32_FROM_4_POINTERS(p0, p1, p2, p3) \ + _mm_insert_epi32( \ + _mm_insert_epi32( \ + _mm_insert_epi32( \ + _mm_cvtsi32_si128( \ + *(const Int32 *)p0), \ + *(const Int32 *)p1, 1), \ + *(const Int32 *)p2, 2), \ + *(const Int32 *)p3, 3) +#elif 0 || 1 && defined(Z7_MSC_VER_ORIGINAL) +/* MSVC 1400 implements _mm_set_epi32() via slow memory write/read. + Also _mm_unpacklo_epi32 is more effective for another MSVC compilers. + But _mm_set_epi32() is more effective for GCC and CLANG. + So we use _mm_unpacklo_epi32 for MSVC only */ +#define MM_LOAD_EPI32_FROM_4_POINTERS(p0, p1, p2, p3) \ + _mm_unpacklo_epi64( \ + _mm_unpacklo_epi32( _mm_cvtsi32_si128(*(const Int32 *)p0), \ + _mm_cvtsi32_si128(*(const Int32 *)p1)), \ + _mm_unpacklo_epi32( _mm_cvtsi32_si128(*(const Int32 *)p2), \ + _mm_cvtsi32_si128(*(const Int32 *)p3))) +#else +#define MM_LOAD_EPI32_FROM_4_POINTERS(p0, p1, p2, p3) \ + _mm_set_epi32( \ + *(const Int32 *)p3, \ + *(const Int32 *)p2, \ + *(const Int32 *)p1, \ + *(const Int32 *)p0) +#endif + +#define SET_ROW_FROM_SIGMA_BASE(input, i0, i1, i2, i3) \ + MM_LOAD_EPI32_FROM_4_POINTERS( \ + GET_SIGMA_PTR(input, i0), \ + GET_SIGMA_PTR(input, i1), \ + GET_SIGMA_PTR(input, i2), \ + GET_SIGMA_PTR(input, i3)) + +#define SET_ROW_FROM_SIGMA(input, sigma_index) \ + SET_ROW_FROM_SIGMA_BASE(input, \ + sigma[(sigma_index) ], \ + sigma[(sigma_index) + 2 * 1], \ + sigma[(sigma_index) + 2 * 2], \ + sigma[(sigma_index) + 2 * 3]) \ + + +#define ADD_128(a, b) _mm_add_epi32(a, b) +#define XOR_128(a, b) _mm_xor_si128(a, b) + +#define D_ADD_128(dest, src) dest = ADD_128(dest, src) +#define D_XOR_128(dest, src) dest = XOR_128(dest, src) +#define D_ROR_128(dest, shift) dest = MM_ROR_EPI32(dest, shift) +#define D_ADD_EPI64_128(dest, src) dest = _mm_add_epi64(dest, src) + + +#define AXR(a, b, d, shift) \ + D_ADD_128(a, b); \ + D_XOR_128(d, a); \ + D_ROR_128(d, shift); + +#define AXR2(a, b, c, d, input, sigma_index, shift1, shift2) \ + a = _mm_add_epi32 (a, SET_ROW_FROM_SIGMA(input, sigma_index)); \ + AXR(a, b, d, shift1) \ + AXR(c, d, b, shift2) + +#define ROTATE_WORDS_TO_RIGHT(a, n) \ + a = _mm_shuffle_epi32(a, _MM_SHUFFLE((3+n)&3, (2+n)&3, (1+n)&3, (0+n)&3)); + +#define AXR4(a, b, c, d, input, sigma_index) \ + AXR2(a, b, c, d, input, sigma_index, 16, 12) \ + AXR2(a, b, c, d, input, sigma_index + 1, 8, 7) \ + +#define RR2(a, b, c, d, input) \ + { \ + AXR4(a, b, c, d, input, 0) \ + ROTATE_WORDS_TO_RIGHT(b, 1) \ + ROTATE_WORDS_TO_RIGHT(c, 2) \ + ROTATE_WORDS_TO_RIGHT(d, 3) \ + AXR4(a, b, c, d, input, 8) \ + ROTATE_WORDS_TO_RIGHT(b, 3) \ + ROTATE_WORDS_TO_RIGHT(c, 2) \ + ROTATE_WORDS_TO_RIGHT(d, 1) \ + } + + +/* +Way1: +per 64 bytes block: +10 rounds * 4 iters * (7 + 2) = 360 cycles = if pslld TP=1 + * (7 + 1) = 320 cycles = if pslld TP=2 (skl+) +additional operations per 7_op_iter : +4 movzx byte mem +1 movd mem +3 pinsrd mem +1.5 pshufd +*/ + +static +#if 0 || 0 && (defined(Z7_BLAKE2S_USE_V128_WAY2) || \ + defined(Z7_BLAKE2S_USE_V256_WAY2)) + Z7_NO_INLINE +#else + Z7_FORCE_INLINE +#endif +#ifdef BLAKE2S_ATTRIB_128BIT + BLAKE2S_ATTRIB_128BIT +#endif +void +Z7_FASTCALL +Blake2s_Compress_V128_Way1(UInt32 * const s, const Byte * const input) +{ + __m128i a, b, c, d; + __m128i f0, f1; + + LOAD_ROTATE_CONSTS + d = LOAD_128_FROM_STRUCT(STATE_T(s)); + c = k_iv0_128; + a = f0 = LOAD_128_FROM_STRUCT(s); + b = f1 = LOAD_128_FROM_STRUCT(s + 4); + D_ADD_EPI64_128(d, k_inc); + STORE_128_TO_STRUCT (STATE_T(s), d); + D_XOR_128(d, k_iv4_128); + +#define RR(r) { const Byte * const sigma = k_Blake2s_Sigma_4[r]; \ + RR2(a, b, c, d, input) } + + ROUNDS_LOOP(RR) +#undef RR + + STORE_128_TO_STRUCT(s , XOR_128(f0, XOR_128(a, c))); + STORE_128_TO_STRUCT(s + 4, XOR_128(f1, XOR_128(b, d))); +} + + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_128BIT + BLAKE2S_ATTRIB_128BIT +#endif +void +Z7_FASTCALL +Blake2sp_Compress2_V128_Way1(UInt32 *s_items, const Byte *data, const Byte *end) +{ + size_t pos = 0; + do + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + Blake2s_Compress_V128_Way1(s, data); + data += Z7_BLAKE2S_BLOCK_SIZE; + pos += Z7_BLAKE2S_BLOCK_SIZE; + pos &= SUPER_BLOCK_MASK; + } + while (data != end); +} + + +#if defined(Z7_BLAKE2S_USE_V128_WAY2) || \ + defined(Z7_BLAKE2S_USE_AVX2_WAY2) +#if 1 + #define Z7_BLAKE2S_CompressSingleBlock(s, data) \ + Blake2sp_Compress2_V128_Way1(s, data, \ + (const Byte *)(const void *)(data) + Z7_BLAKE2S_BLOCK_SIZE) +#else + #define Z7_BLAKE2S_CompressSingleBlock Blake2s_Compress_V128_Way1 +#endif +#endif + + +#if (defined(Z7_BLAKE2S_USE_AVX2_WAY_SLOW) || \ + defined(Z7_BLAKE2S_USE_V128_WAY2)) && \ + !defined(Z7_BLAKE2S_USE_GATHER) +#define AXR2_LOAD_INDEXES(sigma_index) \ + const unsigned i0 = sigma[(sigma_index)]; \ + const unsigned i1 = sigma[(sigma_index) + 2 * 1]; \ + const unsigned i2 = sigma[(sigma_index) + 2 * 2]; \ + const unsigned i3 = sigma[(sigma_index) + 2 * 3]; \ + +#define SET_ROW_FROM_SIGMA_W(input) \ + SET_ROW_FROM_SIGMA_BASE(input, i0, i1, i2, i3) +#endif + + +#ifdef Z7_BLAKE2S_USE_V128_WAY2 + +#if 1 || !defined(Z7_BLAKE2S_USE_SSE41) +/* we use SET_ROW_FROM_SIGMA_BASE, that uses + (SSE4) _mm_insert_epi32(), if Z7_BLAKE2S_USE_INSERT_INSTRUCTION is defined + (SSE2) _mm_set_epi32() + MSVC can be faster for this branch: +*/ +#define AXR2_W(sigma_index, shift1, shift2) \ + { \ + AXR2_LOAD_INDEXES(sigma_index) \ + a0 = _mm_add_epi32(a0, SET_ROW_FROM_SIGMA_W(data)); \ + a1 = _mm_add_epi32(a1, SET_ROW_FROM_SIGMA_W(data + Z7_BLAKE2S_BLOCK_SIZE)); \ + AXR(a0, b0, d0, shift1) \ + AXR(a1, b1, d1, shift1) \ + AXR(c0, d0, b0, shift2) \ + AXR(c1, d1, b1, shift2) \ + } +#else +/* we use interleaved _mm_insert_epi32(): + GCC can be faster for this branch: +*/ +#define AXR2_W_PRE_INSERT(sigma_index, i) \ + { const unsigned ii = sigma[(sigma_index) + i * 2]; \ + t0 = _mm_insert_epi32(t0, *(const Int32 *)GET_SIGMA_PTR(data, ii), i); \ + t1 = _mm_insert_epi32(t1, *(const Int32 *)GET_SIGMA_PTR(data, Z7_BLAKE2S_BLOCK_SIZE + ii), i); \ + } +#define AXR2_W(sigma_index, shift1, shift2) \ + { __m128i t0, t1; \ + { const unsigned ii = sigma[sigma_index]; \ + t0 = _mm_cvtsi32_si128(*(const Int32 *)GET_SIGMA_PTR(data, ii)); \ + t1 = _mm_cvtsi32_si128(*(const Int32 *)GET_SIGMA_PTR(data, Z7_BLAKE2S_BLOCK_SIZE + ii)); \ + } \ + AXR2_W_PRE_INSERT(sigma_index, 1) \ + AXR2_W_PRE_INSERT(sigma_index, 2) \ + AXR2_W_PRE_INSERT(sigma_index, 3) \ + a0 = _mm_add_epi32(a0, t0); \ + a1 = _mm_add_epi32(a1, t1); \ + AXR(a0, b0, d0, shift1) \ + AXR(a1, b1, d1, shift1) \ + AXR(c0, d0, b0, shift2) \ + AXR(c1, d1, b1, shift2) \ + } +#endif + + +#define AXR4_W(sigma_index) \ + AXR2_W(sigma_index, 16, 12) \ + AXR2_W(sigma_index + 1, 8, 7) \ + +#define WW(r) \ + { const Byte * const sigma = k_Blake2s_Sigma_4[r]; \ + AXR4_W(0) \ + ROTATE_WORDS_TO_RIGHT(b0, 1) \ + ROTATE_WORDS_TO_RIGHT(b1, 1) \ + ROTATE_WORDS_TO_RIGHT(c0, 2) \ + ROTATE_WORDS_TO_RIGHT(c1, 2) \ + ROTATE_WORDS_TO_RIGHT(d0, 3) \ + ROTATE_WORDS_TO_RIGHT(d1, 3) \ + AXR4_W(8) \ + ROTATE_WORDS_TO_RIGHT(b0, 3) \ + ROTATE_WORDS_TO_RIGHT(b1, 3) \ + ROTATE_WORDS_TO_RIGHT(c0, 2) \ + ROTATE_WORDS_TO_RIGHT(c1, 2) \ + ROTATE_WORDS_TO_RIGHT(d0, 1) \ + ROTATE_WORDS_TO_RIGHT(d1, 1) \ + } + + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_128BIT + BLAKE2S_ATTRIB_128BIT +#endif +void +Z7_FASTCALL +Blake2sp_Compress2_V128_Way2(UInt32 *s_items, const Byte *data, const Byte *end) +{ + size_t pos = 0; + end -= Z7_BLAKE2S_BLOCK_SIZE; + + if (data != end) + { + LOAD_ROTATE_CONSTS + do + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + __m128i a0, b0, c0, d0; + __m128i a1, b1, c1, d1; + { + const __m128i inc = k_inc; + const __m128i temp = k_iv4_128; + d0 = LOAD_128_FROM_STRUCT (STATE_T(s)); + d1 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW)); + D_ADD_EPI64_128(d0, inc); + D_ADD_EPI64_128(d1, inc); + STORE_128_TO_STRUCT (STATE_T(s ), d0); + STORE_128_TO_STRUCT (STATE_T(s + NSW), d1); + D_XOR_128(d0, temp); + D_XOR_128(d1, temp); + } + c1 = c0 = k_iv0_128; + a0 = LOAD_128_FROM_STRUCT(s); + b0 = LOAD_128_FROM_STRUCT(s + 4); + a1 = LOAD_128_FROM_STRUCT(s + NSW); + b1 = LOAD_128_FROM_STRUCT(s + NSW + 4); + + ROUNDS_LOOP (WW) + +#undef WW + + D_XOR_128(a0, c0); + D_XOR_128(b0, d0); + D_XOR_128(a1, c1); + D_XOR_128(b1, d1); + + D_XOR_128(a0, LOAD_128_FROM_STRUCT(s)); + D_XOR_128(b0, LOAD_128_FROM_STRUCT(s + 4)); + D_XOR_128(a1, LOAD_128_FROM_STRUCT(s + NSW)); + D_XOR_128(b1, LOAD_128_FROM_STRUCT(s + NSW + 4)); + + STORE_128_TO_STRUCT(s, a0); + STORE_128_TO_STRUCT(s + 4, b0); + STORE_128_TO_STRUCT(s + NSW, a1); + STORE_128_TO_STRUCT(s + NSW + 4, b1); + + data += Z7_BLAKE2S_BLOCK_SIZE * 2; + pos += Z7_BLAKE2S_BLOCK_SIZE * 2; + pos &= SUPER_BLOCK_MASK; + } + while (data < end); + if (data != end) + return; + } + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + Z7_BLAKE2S_CompressSingleBlock(s, data); + } +} +#endif // Z7_BLAKE2S_USE_V128_WAY2 + + +#ifdef Z7_BLAKE2S_USE_V128_WAY2 + #define Z7_BLAKE2S_Compress2_V128 Blake2sp_Compress2_V128_Way2 +#else + #define Z7_BLAKE2S_Compress2_V128 Blake2sp_Compress2_V128_Way1 +#endif + + + +#ifdef Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED + #define ROT_128_8(x) MM_ROR_EPI32(x, 8) + #define ROT_128_16(x) MM_ROR_EPI32(x, 16) + #define ROT_128_7(x) MM_ROR_EPI32(x, 7) + #define ROT_128_12(x) MM_ROR_EPI32(x, 12) +#else +#if defined(Z7_BLAKE2S_USE_SSSE3) || defined(Z7_BLAKE2S_USE_SSE41) + #define ROT_128_8(x) _mm_shuffle_epi8(x, r8) // k_r8 + #define ROT_128_16(x) _mm_shuffle_epi8(x, r16) // k_r16 +#else + #define ROT_128_8(x) MM_ROR_EPI32_VIA_SHIFT(x, 8) + #define ROT_128_16(x) MM_ROR_EPI32_VIA_SHIFT(x, 16) +#endif + #define ROT_128_7(x) MM_ROR_EPI32_VIA_SHIFT(x, 7) + #define ROT_128_12(x) MM_ROR_EPI32_VIA_SHIFT(x, 12) +#endif + + +#if 1 +// this branch can provide similar speed on x86* in most cases, +// because [base + index*4] provides same speed as [base + index]. +// but some compilers can generate different code with this branch, that can be faster sometimes. +// this branch uses additional table of 10*16=160 bytes. +#define SIGMA_TABLE_MULT_16( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ + SIGMA_TABLE_MULT(16, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) +MY_ALIGN(16) +static const Byte k_Blake2s_Sigma_16[BLAKE2S_NUM_ROUNDS][16] = + { SIGMA_TABLE(SIGMA_TABLE_MULT_16) }; +#define GET_SIGMA_PTR_128(r) const Byte * const sigma = k_Blake2s_Sigma_16[r]; +#define GET_SIGMA_VAL_128(n) (sigma[n]) +#else +#define GET_SIGMA_PTR_128(r) const Byte * const sigma = k_Blake2s_Sigma_4[r]; +#define GET_SIGMA_VAL_128(n) (4 * (size_t)sigma[n]) +#endif + + +#ifdef Z7_BLAKE2S_USE_AVX2_FAST +#if 1 +#define SIGMA_TABLE_MULT_32( a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ + SIGMA_TABLE_MULT(32, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) +MY_ALIGN(64) +static const UInt16 k_Blake2s_Sigma_32[BLAKE2S_NUM_ROUNDS][16] = + { SIGMA_TABLE(SIGMA_TABLE_MULT_32) }; +#define GET_SIGMA_PTR_256(r) const UInt16 * const sigma = k_Blake2s_Sigma_32[r]; +#define GET_SIGMA_VAL_256(n) (sigma[n]) +#else +#define GET_SIGMA_PTR_256(r) const Byte * const sigma = k_Blake2s_Sigma_4[r]; +#define GET_SIGMA_VAL_256(n) (8 * (size_t)sigma[n]) +#endif +#endif // Z7_BLAKE2S_USE_AVX2_FAST + + +#define D_ROT_128_7(dest) dest = ROT_128_7(dest) +#define D_ROT_128_8(dest) dest = ROT_128_8(dest) +#define D_ROT_128_12(dest) dest = ROT_128_12(dest) +#define D_ROT_128_16(dest) dest = ROT_128_16(dest) + +#define OP_L(a, i) D_ADD_128 (V(a, 0), \ + LOAD_128((const Byte *)(w) + GET_SIGMA_VAL_128(2*(a)+(i)))); + +#define OP_0(a) OP_L(a, 0) +#define OP_7(a) OP_L(a, 1) + +#define OP_1(a) D_ADD_128 (V(a, 0), V(a, 1)); +#define OP_2(a) D_XOR_128 (V(a, 3), V(a, 0)); +#define OP_4(a) D_ADD_128 (V(a, 2), V(a, 3)); +#define OP_5(a) D_XOR_128 (V(a, 1), V(a, 2)); + +#define OP_3(a) D_ROT_128_16 (V(a, 3)); +#define OP_6(a) D_ROT_128_12 (V(a, 1)); +#define OP_8(a) D_ROT_128_8 (V(a, 3)); +#define OP_9(a) D_ROT_128_7 (V(a, 1)); + + +// for 32-bit x86 : interleave mode works slower, because of register pressure. + +#if 0 || 1 && (defined(MY_CPU_X86) \ + || defined(__GNUC__) && !defined(__clang__)) +// non-inteleaved version: +// is fast for x86 32-bit. +// is fast for GCC x86-64. + +#define V4G(a) \ + OP_0 (a) \ + OP_1 (a) \ + OP_2 (a) \ + OP_3 (a) \ + OP_4 (a) \ + OP_5 (a) \ + OP_6 (a) \ + OP_7 (a) \ + OP_1 (a) \ + OP_2 (a) \ + OP_8 (a) \ + OP_4 (a) \ + OP_5 (a) \ + OP_9 (a) \ + +#define V4R \ +{ \ + V4G (0) \ + V4G (1) \ + V4G (2) \ + V4G (3) \ + V4G (4) \ + V4G (5) \ + V4G (6) \ + V4G (7) \ +} + +#elif 0 || 1 && defined(MY_CPU_X86) + +#define OP_INTER_2(op, a,b) \ + op (a) \ + op (b) \ + +#define V4G(a,b) \ + OP_INTER_2 (OP_0, a,b) \ + OP_INTER_2 (OP_1, a,b) \ + OP_INTER_2 (OP_2, a,b) \ + OP_INTER_2 (OP_3, a,b) \ + OP_INTER_2 (OP_4, a,b) \ + OP_INTER_2 (OP_5, a,b) \ + OP_INTER_2 (OP_6, a,b) \ + OP_INTER_2 (OP_7, a,b) \ + OP_INTER_2 (OP_1, a,b) \ + OP_INTER_2 (OP_2, a,b) \ + OP_INTER_2 (OP_8, a,b) \ + OP_INTER_2 (OP_4, a,b) \ + OP_INTER_2 (OP_5, a,b) \ + OP_INTER_2 (OP_9, a,b) \ + +#define V4R \ +{ \ + V4G (0, 1) \ + V4G (2, 3) \ + V4G (4, 5) \ + V4G (6, 7) \ +} + +#else +// iterleave-4 version is fast for x64 (MSVC/CLANG) + +#define OP_INTER_4(op, a,b,c,d) \ + op (a) \ + op (b) \ + op (c) \ + op (d) \ + +#define V4G(a,b,c,d) \ + OP_INTER_4 (OP_0, a,b,c,d) \ + OP_INTER_4 (OP_1, a,b,c,d) \ + OP_INTER_4 (OP_2, a,b,c,d) \ + OP_INTER_4 (OP_3, a,b,c,d) \ + OP_INTER_4 (OP_4, a,b,c,d) \ + OP_INTER_4 (OP_5, a,b,c,d) \ + OP_INTER_4 (OP_6, a,b,c,d) \ + OP_INTER_4 (OP_7, a,b,c,d) \ + OP_INTER_4 (OP_1, a,b,c,d) \ + OP_INTER_4 (OP_2, a,b,c,d) \ + OP_INTER_4 (OP_8, a,b,c,d) \ + OP_INTER_4 (OP_4, a,b,c,d) \ + OP_INTER_4 (OP_5, a,b,c,d) \ + OP_INTER_4 (OP_9, a,b,c,d) \ + +#define V4R \ +{ \ + V4G (0, 1, 2, 3) \ + V4G (4, 5, 6, 7) \ +} + +#endif + +#define V4_ROUND(r) { GET_SIGMA_PTR_128(r); V4R } + + +#define V4_LOAD_MSG_1(w, m, i) \ +{ \ + __m128i m0, m1, m2, m3; \ + __m128i t0, t1, t2, t3; \ + m0 = LOADU_128((m) + ((i) + 0 * 4) * 16); \ + m1 = LOADU_128((m) + ((i) + 1 * 4) * 16); \ + m2 = LOADU_128((m) + ((i) + 2 * 4) * 16); \ + m3 = LOADU_128((m) + ((i) + 3 * 4) * 16); \ + t0 = _mm_unpacklo_epi32(m0, m1); \ + t1 = _mm_unpackhi_epi32(m0, m1); \ + t2 = _mm_unpacklo_epi32(m2, m3); \ + t3 = _mm_unpackhi_epi32(m2, m3); \ + w[(i) * 4 + 0] = _mm_unpacklo_epi64(t0, t2); \ + w[(i) * 4 + 1] = _mm_unpackhi_epi64(t0, t2); \ + w[(i) * 4 + 2] = _mm_unpacklo_epi64(t1, t3); \ + w[(i) * 4 + 3] = _mm_unpackhi_epi64(t1, t3); \ +} + +#define V4_LOAD_MSG(w, m) \ +{ \ + V4_LOAD_MSG_1 (w, m, 0) \ + V4_LOAD_MSG_1 (w, m, 1) \ + V4_LOAD_MSG_1 (w, m, 2) \ + V4_LOAD_MSG_1 (w, m, 3) \ +} + +#define V4_LOAD_UNPACK_PAIR_128(src32, i, d0, d1) \ +{ \ + const __m128i v0 = LOAD_128_FROM_STRUCT((src32) + (i ) * 4); \ + const __m128i v1 = LOAD_128_FROM_STRUCT((src32) + (i + 1) * 4); \ + d0 = _mm_unpacklo_epi32(v0, v1); \ + d1 = _mm_unpackhi_epi32(v0, v1); \ +} + +#define V4_UNPACK_PAIR_128(dest32, i, s0, s1) \ +{ \ + STORE_128_TO_STRUCT((dest32) + i * 4 , _mm_unpacklo_epi64(s0, s1)); \ + STORE_128_TO_STRUCT((dest32) + i * 4 + 16, _mm_unpackhi_epi64(s0, s1)); \ +} + +#define V4_UNPACK_STATE(dest32, src32) \ +{ \ + __m128i t0, t1, t2, t3, t4, t5, t6, t7; \ + V4_LOAD_UNPACK_PAIR_128(src32, 0, t0, t1) \ + V4_LOAD_UNPACK_PAIR_128(src32, 2, t2, t3) \ + V4_LOAD_UNPACK_PAIR_128(src32, 4, t4, t5) \ + V4_LOAD_UNPACK_PAIR_128(src32, 6, t6, t7) \ + V4_UNPACK_PAIR_128(dest32, 0, t0, t2) \ + V4_UNPACK_PAIR_128(dest32, 8, t1, t3) \ + V4_UNPACK_PAIR_128(dest32, 1, t4, t6) \ + V4_UNPACK_PAIR_128(dest32, 9, t5, t7) \ +} + + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_128BIT + BLAKE2S_ATTRIB_128BIT +#endif +void +Z7_FASTCALL +Blake2sp_Compress2_V128_Fast(UInt32 *s_items, const Byte *data, const Byte *end) +{ + // PrintStates2(s_items, 8, 16); + size_t pos = 0; + pos /= 2; + do + { +#if defined(Z7_BLAKE2S_USE_SSSE3) && \ + !defined(Z7_BLAKE2S_MM_ROR_EPI32_IS_SUPPORTED) + const __m128i r8 = k_r8; + const __m128i r16 = k_r16; +#endif + __m128i w[16]; + __m128i v[16]; + UInt32 *s; + V4_LOAD_MSG(w, data) + s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + { + __m128i ctr = LOAD_128_FROM_STRUCT(s + 64); + D_ADD_EPI64_128 (ctr, k_inc); + STORE_128_TO_STRUCT(s + 64, ctr); + v[12] = XOR_128 (GET_128_IV_WAY4(4), _mm_shuffle_epi32(ctr, _MM_SHUFFLE(0, 0, 0, 0))); + v[13] = XOR_128 (GET_128_IV_WAY4(5), _mm_shuffle_epi32(ctr, _MM_SHUFFLE(1, 1, 1, 1))); + } + v[ 8] = GET_128_IV_WAY4(0); + v[ 9] = GET_128_IV_WAY4(1); + v[10] = GET_128_IV_WAY4(2); + v[11] = GET_128_IV_WAY4(3); + v[14] = GET_128_IV_WAY4(6); + v[15] = GET_128_IV_WAY4(7); + +#define LOAD_STATE_128_FROM_STRUCT(i) \ + v[i] = LOAD_128_FROM_STRUCT(s + (i) * 4); + +#define UPDATE_STATE_128_IN_STRUCT(i) \ + STORE_128_TO_STRUCT(s + (i) * 4, XOR_128( \ + XOR_128(v[i], v[(i) + 8]), \ + LOAD_128_FROM_STRUCT(s + (i) * 4))); + + REP8_MACRO (LOAD_STATE_128_FROM_STRUCT) + ROUNDS_LOOP (V4_ROUND) + REP8_MACRO (UPDATE_STATE_128_IN_STRUCT) + + data += Z7_BLAKE2S_BLOCK_SIZE * 4; + pos += Z7_BLAKE2S_BLOCK_SIZE * 4 / 2; + pos &= SUPER_BLOCK_SIZE / 2 - 1; + } + while (data != end); +} + + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_128BIT + BLAKE2S_ATTRIB_128BIT +#endif +void +Z7_FASTCALL +Blake2sp_Final_V128_Fast(UInt32 *states) +{ + const __m128i ctr = LOAD_128_FROM_STRUCT(states + 64); + // printf("\nBlake2sp_Compress2_V128_Fast_Final4\n"); + // PrintStates2(states, 8, 16); + { + ptrdiff_t pos = 8 * 4; + do + { + UInt32 *src32 = states + (size_t)(pos * 1); + UInt32 *dest32 = states + (size_t)(pos * 2); + V4_UNPACK_STATE(dest32, src32) + pos -= 8 * 4; + } + while (pos >= 0); + } + { + unsigned k; + for (k = 0; k < 8; k++) + { + UInt32 *s = states + (size_t)k * 16; + STORE_128_TO_STRUCT (STATE_T(s), ctr); + } + } + // PrintStates2(states, 8, 16); +} + + + +#ifdef Z7_BLAKE2S_USE_AVX2 + +#define ADD_256(a, b) _mm256_add_epi32(a, b) +#define XOR_256(a, b) _mm256_xor_si256(a, b) + +#if 1 && defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) + #define MM256_ROR_EPI32 _mm256_ror_epi32 + #define Z7_MM256_ROR_EPI32_IS_SUPPORTED +#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 + #define LOAD_ROTATE_CONSTS_256 +#endif +#else +#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW +#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 + #define LOAD_ROTATE_CONSTS_256 \ + const __m256i r8 = k_r8_256; \ + const __m256i r16 = k_r16_256; +#endif // AVX2_WAY2 + + #define MM256_ROR_EPI32(r, c) ( \ + ( 8==(c)) ? _mm256_shuffle_epi8(r,r8) \ + : (16==(c)) ? _mm256_shuffle_epi8(r,r16) \ + : _mm256_or_si256( \ + _mm256_srli_epi32((r), (c)), \ + _mm256_slli_epi32((r), 32-(c)))) +#endif // WAY_SLOW +#endif + + +#define D_ADD_256(dest, src) dest = ADD_256(dest, src) +#define D_XOR_256(dest, src) dest = XOR_256(dest, src) + +#define LOADU_256(p) _mm256_loadu_si256((const __m256i *)(const void *)(p)) + +#ifdef Z7_BLAKE2S_USE_AVX2_FAST + +#ifdef Z7_MM256_ROR_EPI32_IS_SUPPORTED +#define ROT_256_16(x) MM256_ROR_EPI32((x), 16) +#define ROT_256_12(x) MM256_ROR_EPI32((x), 12) +#define ROT_256_8(x) MM256_ROR_EPI32((x), 8) +#define ROT_256_7(x) MM256_ROR_EPI32((x), 7) +#else +#define ROTATE8 _mm256_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1, \ + 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1) +#define ROTATE16 _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, \ + 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2) +#define ROT_256_16(x) _mm256_shuffle_epi8((x), ROTATE16) +#define ROT_256_12(x) _mm256_or_si256(_mm256_srli_epi32((x), 12), _mm256_slli_epi32((x), 20)) +#define ROT_256_8(x) _mm256_shuffle_epi8((x), ROTATE8) +#define ROT_256_7(x) _mm256_or_si256(_mm256_srli_epi32((x), 7), _mm256_slli_epi32((x), 25)) +#endif + +#define D_ROT_256_7(dest) dest = ROT_256_7(dest) +#define D_ROT_256_8(dest) dest = ROT_256_8(dest) +#define D_ROT_256_12(dest) dest = ROT_256_12(dest) +#define D_ROT_256_16(dest) dest = ROT_256_16(dest) + +#define LOAD_256(p) _mm256_load_si256((const __m256i *)(const void *)(p)) +#ifdef Z7_BLAKE2SP_STRUCT_IS_NOT_ALIGNED + #define STOREU_256(p, r) _mm256_storeu_si256((__m256i *)(void *)(p), r) + #define LOAD_256_FROM_STRUCT(p) LOADU_256(p) + #define STORE_256_TO_STRUCT(p, r) STOREU_256(p, r) +#else + // if struct is aligned for 32-bytes + #define STORE_256(p, r) _mm256_store_si256((__m256i *)(void *)(p), r) + #define LOAD_256_FROM_STRUCT(p) LOAD_256(p) + #define STORE_256_TO_STRUCT(p, r) STORE_256(p, r) +#endif + +#endif // Z7_BLAKE2S_USE_AVX2_FAST + + + +#ifdef Z7_BLAKE2S_USE_AVX2_WAY_SLOW + +#if 0 + #define DIAG_PERM2(s) \ + { \ + const __m256i a = LOAD_256_FROM_STRUCT((s) ); \ + const __m256i b = LOAD_256_FROM_STRUCT((s) + NSW); \ + STORE_256_TO_STRUCT((s ), _mm256_permute2x128_si256(a, b, 0x20)); \ + STORE_256_TO_STRUCT((s + NSW), _mm256_permute2x128_si256(a, b, 0x31)); \ + } +#else + #define DIAG_PERM2(s) \ + { \ + const __m128i a = LOAD_128_FROM_STRUCT((s) + 4); \ + const __m128i b = LOAD_128_FROM_STRUCT((s) + NSW); \ + STORE_128_TO_STRUCT((s) + NSW, a); \ + STORE_128_TO_STRUCT((s) + 4 , b); \ + } +#endif + #define DIAG_PERM8(s_items) \ + { \ + DIAG_PERM2(s_items) \ + DIAG_PERM2(s_items + NSW * 2) \ + DIAG_PERM2(s_items + NSW * 4) \ + DIAG_PERM2(s_items + NSW * 6) \ + } + + +#define AXR256(a, b, d, shift) \ + D_ADD_256(a, b); \ + D_XOR_256(d, a); \ + d = MM256_ROR_EPI32(d, shift); \ + + + +#ifdef Z7_BLAKE2S_USE_GATHER + + #define TABLE_GATHER_256_4(a0,a1,a2,a3) \ + a0,a1,a2,a3, a0+16,a1+16,a2+16,a3+16 + #define TABLE_GATHER_256( \ + a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15) \ + { TABLE_GATHER_256_4(a0,a2,a4,a6), \ + TABLE_GATHER_256_4(a1,a3,a5,a7), \ + TABLE_GATHER_256_4(a8,a10,a12,a14), \ + TABLE_GATHER_256_4(a9,a11,a13,a15) } +MY_ALIGN(64) +static const UInt32 k_Blake2s_Sigma_gather256[BLAKE2S_NUM_ROUNDS][16 * 2] = + { SIGMA_TABLE(TABLE_GATHER_256) }; + #define GET_SIGMA(r) \ + const UInt32 * const sigma = k_Blake2s_Sigma_gather256[r]; + #define AXR2_LOAD_INDEXES_AVX(sigma_index) \ + const __m256i i01234567 = LOAD_256(sigma + (sigma_index)); + #define SET_ROW_FROM_SIGMA_AVX(in) \ + _mm256_i32gather_epi32((const void *)(in), i01234567, 4) + #define SIGMA_INTERLEAVE 8 + #define SIGMA_HALF_ROW_SIZE 16 + +#else // !Z7_BLAKE2S_USE_GATHER + + #define GET_SIGMA(r) \ + const Byte * const sigma = k_Blake2s_Sigma_4[r]; + #define AXR2_LOAD_INDEXES_AVX(sigma_index) \ + AXR2_LOAD_INDEXES(sigma_index) + #define SET_ROW_FROM_SIGMA_AVX(in) \ + MY_mm256_set_m128i( \ + SET_ROW_FROM_SIGMA_W((in) + Z7_BLAKE2S_BLOCK_SIZE), \ + SET_ROW_FROM_SIGMA_W(in)) + #define SIGMA_INTERLEAVE 1 + #define SIGMA_HALF_ROW_SIZE 8 +#endif // !Z7_BLAKE2S_USE_GATHER + + +#define ROTATE_WORDS_TO_RIGHT_256(a, n) \ + a = _mm256_shuffle_epi32(a, _MM_SHUFFLE((3+n)&3, (2+n)&3, (1+n)&3, (0+n)&3)); + + + +#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 + +#define AXR2_A(sigma_index, shift1, shift2) \ + AXR2_LOAD_INDEXES_AVX(sigma_index) \ + D_ADD_256( a0, SET_ROW_FROM_SIGMA_AVX(data)); \ + AXR256(a0, b0, d0, shift1) \ + AXR256(c0, d0, b0, shift2) \ + +#define AXR4_A(sigma_index) \ + { AXR2_A(sigma_index, 16, 12) } \ + { AXR2_A(sigma_index + SIGMA_INTERLEAVE, 8, 7) } + +#define EE1(r) \ + { GET_SIGMA(r) \ + AXR4_A(0) \ + ROTATE_WORDS_TO_RIGHT_256(b0, 1) \ + ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ + ROTATE_WORDS_TO_RIGHT_256(d0, 3) \ + AXR4_A(SIGMA_HALF_ROW_SIZE) \ + ROTATE_WORDS_TO_RIGHT_256(b0, 3) \ + ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ + ROTATE_WORDS_TO_RIGHT_256(d0, 1) \ + } + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_AVX2 + BLAKE2S_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +Blake2sp_Compress2_AVX2_Way2(UInt32 *s_items, const Byte *data, const Byte *end) +{ + size_t pos = 0; + end -= Z7_BLAKE2S_BLOCK_SIZE; + + if (data != end) + { + LOAD_ROTATE_CONSTS_256 + DIAG_PERM8(s_items) + do + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + __m256i a0, b0, c0, d0; + { + const __m128i inc = k_inc; + __m128i d0_128 = LOAD_128_FROM_STRUCT (STATE_T(s)); + __m128i d1_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW)); + D_ADD_EPI64_128(d0_128, inc); + D_ADD_EPI64_128(d1_128, inc); + STORE_128_TO_STRUCT (STATE_T(s ), d0_128); + STORE_128_TO_STRUCT (STATE_T(s + NSW), d1_128); + d0 = MY_mm256_set_m128i(d1_128, d0_128); + D_XOR_256(d0, k_iv4_256); + } + c0 = SET_FROM_128(k_iv0_128); + a0 = LOAD_256_FROM_STRUCT(s + NSW * 0); + b0 = LOAD_256_FROM_STRUCT(s + NSW * 1); + + ROUNDS_LOOP (EE1) + + D_XOR_256(a0, c0); + D_XOR_256(b0, d0); + + D_XOR_256(a0, LOAD_256_FROM_STRUCT(s + NSW * 0)); + D_XOR_256(b0, LOAD_256_FROM_STRUCT(s + NSW * 1)); + + STORE_256_TO_STRUCT(s + NSW * 0, a0); + STORE_256_TO_STRUCT(s + NSW * 1, b0); + + data += Z7_BLAKE2S_BLOCK_SIZE * 2; + pos += Z7_BLAKE2S_BLOCK_SIZE * 2; + pos &= SUPER_BLOCK_MASK; + } + while (data < end); + DIAG_PERM8(s_items) + if (data != end) + return; + } + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + Z7_BLAKE2S_CompressSingleBlock(s, data); + } +} + +#endif // Z7_BLAKE2S_USE_AVX2_WAY2 + + + +#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 + +#define AXR2_X(sigma_index, shift1, shift2) \ + AXR2_LOAD_INDEXES_AVX(sigma_index) \ + D_ADD_256( a0, SET_ROW_FROM_SIGMA_AVX(data)); \ + D_ADD_256( a1, SET_ROW_FROM_SIGMA_AVX((data) + Z7_BLAKE2S_BLOCK_SIZE * 2)); \ + AXR256(a0, b0, d0, shift1) \ + AXR256(a1, b1, d1, shift1) \ + AXR256(c0, d0, b0, shift2) \ + AXR256(c1, d1, b1, shift2) \ + +#define AXR4_X(sigma_index) \ + { AXR2_X(sigma_index, 16, 12) } \ + { AXR2_X(sigma_index + SIGMA_INTERLEAVE, 8, 7) } + +#define EE2(r) \ + { GET_SIGMA(r) \ + AXR4_X(0) \ + ROTATE_WORDS_TO_RIGHT_256(b0, 1) \ + ROTATE_WORDS_TO_RIGHT_256(b1, 1) \ + ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ + ROTATE_WORDS_TO_RIGHT_256(c1, 2) \ + ROTATE_WORDS_TO_RIGHT_256(d0, 3) \ + ROTATE_WORDS_TO_RIGHT_256(d1, 3) \ + AXR4_X(SIGMA_HALF_ROW_SIZE) \ + ROTATE_WORDS_TO_RIGHT_256(b0, 3) \ + ROTATE_WORDS_TO_RIGHT_256(b1, 3) \ + ROTATE_WORDS_TO_RIGHT_256(c0, 2) \ + ROTATE_WORDS_TO_RIGHT_256(c1, 2) \ + ROTATE_WORDS_TO_RIGHT_256(d0, 1) \ + ROTATE_WORDS_TO_RIGHT_256(d1, 1) \ + } + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_AVX2 + BLAKE2S_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +Blake2sp_Compress2_AVX2_Way4(UInt32 *s_items, const Byte *data, const Byte *end) +{ + size_t pos = 0; + + if ((size_t)(end - data) >= Z7_BLAKE2S_BLOCK_SIZE * 4) + { +#ifndef Z7_MM256_ROR_EPI32_IS_SUPPORTED + const __m256i r8 = k_r8_256; + const __m256i r16 = k_r16_256; +#endif + end -= Z7_BLAKE2S_BLOCK_SIZE * 3; + DIAG_PERM8(s_items) + do + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + __m256i a0, b0, c0, d0; + __m256i a1, b1, c1, d1; + { + const __m128i inc = k_inc; + __m128i d0_128 = LOAD_128_FROM_STRUCT (STATE_T(s)); + __m128i d1_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW)); + __m128i d2_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW * 2)); + __m128i d3_128 = LOAD_128_FROM_STRUCT (STATE_T(s + NSW * 3)); + D_ADD_EPI64_128(d0_128, inc); + D_ADD_EPI64_128(d1_128, inc); + D_ADD_EPI64_128(d2_128, inc); + D_ADD_EPI64_128(d3_128, inc); + STORE_128_TO_STRUCT (STATE_T(s ), d0_128); + STORE_128_TO_STRUCT (STATE_T(s + NSW * 1), d1_128); + STORE_128_TO_STRUCT (STATE_T(s + NSW * 2), d2_128); + STORE_128_TO_STRUCT (STATE_T(s + NSW * 3), d3_128); + d0 = MY_mm256_set_m128i(d1_128, d0_128); + d1 = MY_mm256_set_m128i(d3_128, d2_128); + D_XOR_256(d0, k_iv4_256); + D_XOR_256(d1, k_iv4_256); + } + c1 = c0 = SET_FROM_128(k_iv0_128); + a0 = LOAD_256_FROM_STRUCT(s + NSW * 0); + b0 = LOAD_256_FROM_STRUCT(s + NSW * 1); + a1 = LOAD_256_FROM_STRUCT(s + NSW * 2); + b1 = LOAD_256_FROM_STRUCT(s + NSW * 3); + + ROUNDS_LOOP (EE2) + + D_XOR_256(a0, c0); + D_XOR_256(b0, d0); + D_XOR_256(a1, c1); + D_XOR_256(b1, d1); + + D_XOR_256(a0, LOAD_256_FROM_STRUCT(s + NSW * 0)); + D_XOR_256(b0, LOAD_256_FROM_STRUCT(s + NSW * 1)); + D_XOR_256(a1, LOAD_256_FROM_STRUCT(s + NSW * 2)); + D_XOR_256(b1, LOAD_256_FROM_STRUCT(s + NSW * 3)); + + STORE_256_TO_STRUCT(s + NSW * 0, a0); + STORE_256_TO_STRUCT(s + NSW * 1, b0); + STORE_256_TO_STRUCT(s + NSW * 2, a1); + STORE_256_TO_STRUCT(s + NSW * 3, b1); + + data += Z7_BLAKE2S_BLOCK_SIZE * 4; + pos += Z7_BLAKE2S_BLOCK_SIZE * 4; + pos &= SUPER_BLOCK_MASK; + } + while (data < end); + DIAG_PERM8(s_items) + end += Z7_BLAKE2S_BLOCK_SIZE * 3; + } + if (data == end) + return; + // Z7_BLAKE2S_Compress2_V128(s_items, data, end, pos); + do + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + Z7_BLAKE2S_CompressSingleBlock(s, data); + data += Z7_BLAKE2S_BLOCK_SIZE; + pos += Z7_BLAKE2S_BLOCK_SIZE; + pos &= SUPER_BLOCK_MASK; + } + while (data != end); +} + +#endif // Z7_BLAKE2S_USE_AVX2_WAY4 +#endif // Z7_BLAKE2S_USE_AVX2_WAY_SLOW + + +// --------------------------------------------------------- + +#ifdef Z7_BLAKE2S_USE_AVX2_FAST + +#define OP256_L(a, i) D_ADD_256 (V(a, 0), \ + LOAD_256((const Byte *)(w) + GET_SIGMA_VAL_256(2*(a)+(i)))); + +#define OP256_0(a) OP256_L(a, 0) +#define OP256_7(a) OP256_L(a, 1) + +#define OP256_1(a) D_ADD_256 (V(a, 0), V(a, 1)); +#define OP256_2(a) D_XOR_256 (V(a, 3), V(a, 0)); +#define OP256_4(a) D_ADD_256 (V(a, 2), V(a, 3)); +#define OP256_5(a) D_XOR_256 (V(a, 1), V(a, 2)); + +#define OP256_3(a) D_ROT_256_16 (V(a, 3)); +#define OP256_6(a) D_ROT_256_12 (V(a, 1)); +#define OP256_8(a) D_ROT_256_8 (V(a, 3)); +#define OP256_9(a) D_ROT_256_7 (V(a, 1)); + + +#if 0 || 1 && defined(MY_CPU_X86) + +#define V8_G(a) \ + OP256_0 (a) \ + OP256_1 (a) \ + OP256_2 (a) \ + OP256_3 (a) \ + OP256_4 (a) \ + OP256_5 (a) \ + OP256_6 (a) \ + OP256_7 (a) \ + OP256_1 (a) \ + OP256_2 (a) \ + OP256_8 (a) \ + OP256_4 (a) \ + OP256_5 (a) \ + OP256_9 (a) \ + +#define V8R { \ + V8_G (0); \ + V8_G (1); \ + V8_G (2); \ + V8_G (3); \ + V8_G (4); \ + V8_G (5); \ + V8_G (6); \ + V8_G (7); \ +} + +#else + +#define OP256_INTER_4(op, a,b,c,d) \ + op (a) \ + op (b) \ + op (c) \ + op (d) \ + +#define V8_G(a,b,c,d) \ + OP256_INTER_4 (OP256_0, a,b,c,d) \ + OP256_INTER_4 (OP256_1, a,b,c,d) \ + OP256_INTER_4 (OP256_2, a,b,c,d) \ + OP256_INTER_4 (OP256_3, a,b,c,d) \ + OP256_INTER_4 (OP256_4, a,b,c,d) \ + OP256_INTER_4 (OP256_5, a,b,c,d) \ + OP256_INTER_4 (OP256_6, a,b,c,d) \ + OP256_INTER_4 (OP256_7, a,b,c,d) \ + OP256_INTER_4 (OP256_1, a,b,c,d) \ + OP256_INTER_4 (OP256_2, a,b,c,d) \ + OP256_INTER_4 (OP256_8, a,b,c,d) \ + OP256_INTER_4 (OP256_4, a,b,c,d) \ + OP256_INTER_4 (OP256_5, a,b,c,d) \ + OP256_INTER_4 (OP256_9, a,b,c,d) \ + +#define V8R { \ + V8_G (0, 1, 2, 3) \ + V8_G (4, 5, 6, 7) \ +} +#endif + +#define V8_ROUND(r) { GET_SIGMA_PTR_256(r); V8R } + + +// for debug: +// #define Z7_BLAKE2S_PERMUTE_WITH_GATHER +#if defined(Z7_BLAKE2S_PERMUTE_WITH_GATHER) +// gather instruction is slow. +#define V8_LOAD_MSG(w, m) \ +{ \ + unsigned i; \ + for (i = 0; i < 16; ++i) { \ + w[i] = _mm256_i32gather_epi32( \ + (const void *)((m) + i * sizeof(UInt32)),\ + _mm256_set_epi32(0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00), \ + sizeof(UInt32)); \ + } \ +} +#else // !Z7_BLAKE2S_PERMUTE_WITH_GATHER + +#define V8_LOAD_MSG_2(w, a0, a1) \ +{ \ + (w)[0] = _mm256_permute2x128_si256(a0, a1, 0x20); \ + (w)[4] = _mm256_permute2x128_si256(a0, a1, 0x31); \ +} + +#define V8_LOAD_MSG_4(w, z0, z1, z2, z3) \ +{ \ + __m256i s0, s1, s2, s3; \ + s0 = _mm256_unpacklo_epi64(z0, z1); \ + s1 = _mm256_unpackhi_epi64(z0, z1); \ + s2 = _mm256_unpacklo_epi64(z2, z3); \ + s3 = _mm256_unpackhi_epi64(z2, z3); \ + V8_LOAD_MSG_2((w) + 0, s0, s2) \ + V8_LOAD_MSG_2((w) + 1, s1, s3) \ +} + +#define V8_LOAD_MSG_0(t0, t1, m) \ +{ \ + __m256i m0, m1; \ + m0 = LOADU_256(m); \ + m1 = LOADU_256((m) + 2 * 32); \ + t0 = _mm256_unpacklo_epi32(m0, m1); \ + t1 = _mm256_unpackhi_epi32(m0, m1); \ +} + +#define V8_LOAD_MSG_8(w, m) \ +{ \ + __m256i t0, t1, t2, t3, t4, t5, t6, t7; \ + V8_LOAD_MSG_0(t0, t4, (m) + 0 * 4 * 32) \ + V8_LOAD_MSG_0(t1, t5, (m) + 1 * 4 * 32) \ + V8_LOAD_MSG_0(t2, t6, (m) + 2 * 4 * 32) \ + V8_LOAD_MSG_0(t3, t7, (m) + 3 * 4 * 32) \ + V8_LOAD_MSG_4((w) , t0, t1, t2, t3) \ + V8_LOAD_MSG_4((w) + 2, t4, t5, t6, t7) \ +} + +#define V8_LOAD_MSG(w, m) \ +{ \ + V8_LOAD_MSG_8(w, m) \ + V8_LOAD_MSG_8((w) + 8, (m) + 32) \ +} + +#endif // !Z7_BLAKE2S_PERMUTE_WITH_GATHER + + +#define V8_PERM_PAIR_STORE(u, a0, a2) \ +{ \ + STORE_256_TO_STRUCT((u), _mm256_permute2x128_si256(a0, a2, 0x20)); \ + STORE_256_TO_STRUCT((u) + 8, _mm256_permute2x128_si256(a0, a2, 0x31)); \ +} + +#define V8_UNPACK_STORE_4(u, z0, z1, z2, z3) \ +{ \ + __m256i s0, s1, s2, s3; \ + s0 = _mm256_unpacklo_epi64(z0, z1); \ + s1 = _mm256_unpackhi_epi64(z0, z1); \ + s2 = _mm256_unpacklo_epi64(z2, z3); \ + s3 = _mm256_unpackhi_epi64(z2, z3); \ + V8_PERM_PAIR_STORE(u + 0, s0, s2) \ + V8_PERM_PAIR_STORE(u + 2, s1, s3) \ +} + +#define V8_UNPACK_STORE_0(src32, d0, d1) \ +{ \ + const __m256i v0 = LOAD_256_FROM_STRUCT ((src32) ); \ + const __m256i v1 = LOAD_256_FROM_STRUCT ((src32) + 8); \ + d0 = _mm256_unpacklo_epi32(v0, v1); \ + d1 = _mm256_unpackhi_epi32(v0, v1); \ +} + +#define V8_UNPACK_STATE(dest32, src32) \ +{ \ + __m256i t0, t1, t2, t3, t4, t5, t6, t7; \ + V8_UNPACK_STORE_0 ((src32) + 16 * 0, t0, t4) \ + V8_UNPACK_STORE_0 ((src32) + 16 * 1, t1, t5) \ + V8_UNPACK_STORE_0 ((src32) + 16 * 2, t2, t6) \ + V8_UNPACK_STORE_0 ((src32) + 16 * 3, t3, t7) \ + V8_UNPACK_STORE_4 ((__m256i *)(void *)(dest32) , t0, t1, t2, t3) \ + V8_UNPACK_STORE_4 ((__m256i *)(void *)(dest32) + 4, t4, t5, t6, t7) \ +} + + + +#define V8_LOAD_STATE_256_FROM_STRUCT(i) \ + v[i] = LOAD_256_FROM_STRUCT(s_items + (i) * 8); + +#if 0 || 0 && defined(MY_CPU_X86) +#define Z7_BLAKE2S_AVX2_FAST_USE_STRUCT +#endif + +#ifdef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT +// this branch doesn't use (iv) array +// so register pressure can be lower. +// it can be faster sometimes +#define V8_LOAD_STATE_256(i) V8_LOAD_STATE_256_FROM_STRUCT(i) +#define V8_UPDATE_STATE_256(i) \ +{ \ + STORE_256_TO_STRUCT(s_items + (i) * 8, XOR_256( \ + XOR_256(v[i], v[(i) + 8]), \ + LOAD_256_FROM_STRUCT(s_items + (i) * 8))); \ +} +#else +// it uses more variables (iv) registers +// it's better for gcc +// maybe that branch is better, if register pressure will be lower (avx512) +#define V8_LOAD_STATE_256(i) { iv[i] = v[i]; } +#define V8_UPDATE_STATE_256(i) { v[i] = XOR_256(XOR_256(v[i], v[i + 8]), iv[i]); } +#define V8_STORE_STATE_256(i) { STORE_256_TO_STRUCT(s_items + (i) * 8, v[i]); } +#endif + + +#if 0 + // use loading constants from memory + #define KK8(n) KIV(n), KIV(n), KIV(n), KIV(n), KIV(n), KIV(n), KIV(n), KIV(n) +MY_ALIGN(64) +static const UInt32 k_Blake2s_IV_WAY8[]= +{ + KK8(0), KK8(1), KK8(2), KK8(3), KK8(4), KK8(5), KK8(6), KK8(7) +}; + #define GET_256_IV_WAY8(i) LOAD_256(k_Blake2s_IV_WAY8 + 8 * (i)) +#else + // use constant generation: + #define GET_256_IV_WAY8(i) _mm256_set1_epi32((Int32)KIV(i)) +#endif + + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_AVX2 + BLAKE2S_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +Blake2sp_Compress2_AVX2_Fast(UInt32 *s_items, const Byte *data, const Byte *end) +{ +#ifndef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT + __m256i v[16]; +#endif + + // PrintStates2(s_items, 8, 16); + +#ifndef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT + REP8_MACRO (V8_LOAD_STATE_256_FROM_STRUCT) +#endif + + do + { + __m256i w[16]; +#ifdef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT + __m256i v[16]; +#else + __m256i iv[8]; +#endif + V8_LOAD_MSG(w, data) + { + // we use load/store ctr inside loop to reduce register pressure: +#if 1 || 1 && defined(MY_CPU_X86) + const __m256i ctr = _mm256_add_epi64( + LOAD_256_FROM_STRUCT(s_items + 64), + _mm256_set_epi32( + 0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE, + 0, 0, 0, Z7_BLAKE2S_BLOCK_SIZE)); + STORE_256_TO_STRUCT(s_items + 64, ctr); +#else + const UInt64 ctr64 = *(const UInt64 *)(const void *)(s_items + 64) + + Z7_BLAKE2S_BLOCK_SIZE; + const __m256i ctr = _mm256_set_epi64x(0, (Int64)ctr64, 0, (Int64)ctr64); + *(UInt64 *)(void *)(s_items + 64) = ctr64; +#endif + v[12] = XOR_256 (GET_256_IV_WAY8(4), _mm256_shuffle_epi32(ctr, _MM_SHUFFLE(0, 0, 0, 0))); + v[13] = XOR_256 (GET_256_IV_WAY8(5), _mm256_shuffle_epi32(ctr, _MM_SHUFFLE(1, 1, 1, 1))); + } + v[ 8] = GET_256_IV_WAY8(0); + v[ 9] = GET_256_IV_WAY8(1); + v[10] = GET_256_IV_WAY8(2); + v[11] = GET_256_IV_WAY8(3); + v[14] = GET_256_IV_WAY8(6); + v[15] = GET_256_IV_WAY8(7); + + REP8_MACRO (V8_LOAD_STATE_256) + ROUNDS_LOOP (V8_ROUND) + REP8_MACRO (V8_UPDATE_STATE_256) + data += SUPER_BLOCK_SIZE; + } + while (data != end); + +#ifndef Z7_BLAKE2S_AVX2_FAST_USE_STRUCT + REP8_MACRO (V8_STORE_STATE_256) +#endif +} + + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_AVX2 + BLAKE2S_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +Blake2sp_Final_AVX2_Fast(UInt32 *states) +{ + const __m128i ctr = LOAD_128_FROM_STRUCT(states + 64); + // PrintStates2(states, 8, 16); + V8_UNPACK_STATE(states, states) + // PrintStates2(states, 8, 16); + { + unsigned k; + for (k = 0; k < 8; k++) + { + UInt32 *s = states + (size_t)k * 16; + STORE_128_TO_STRUCT (STATE_T(s), ctr); + } + } + // PrintStates2(states, 8, 16); + // printf("\nafter V8_UNPACK_STATE \n"); +} + +#endif // Z7_BLAKE2S_USE_AVX2_FAST +#endif // avx2 +#endif // vector + + +/* +#define Blake2s_Increment_Counter(s, inc) \ + { STATE_T(s)[0] += (inc); STATE_T(s)[1] += (STATE_T(s)[0] < (inc)); } +#define Blake2s_Increment_Counter_Small(s, inc) \ + { STATE_T(s)[0] += (inc); } +*/ + +#define Blake2s_Set_LastBlock(s) \ + { STATE_F(s)[0] = BLAKE2S_FINAL_FLAG; /* STATE_F(s)[1] = p->u.header.lastNode_f1; */ } + + +#if 0 || 1 && defined(Z7_MSC_VER_ORIGINAL) && Z7_MSC_VER_ORIGINAL >= 1600 + // good for vs2022 + #define LOOP_8(mac) { unsigned kkk; for (kkk = 0; kkk < 8; kkk++) mac(kkk) } +#else + // good for Z7_BLAKE2S_UNROLL for GCC9 (arm*/x86*) and MSC_VER_1400-x64. + #define LOOP_8(mac) { REP8_MACRO(mac) } +#endif + + +static +Z7_FORCE_INLINE +// Z7_NO_INLINE +void +Z7_FASTCALL +Blake2s_Compress(UInt32 *s, const Byte *input) +{ + UInt32 m[16]; + UInt32 v[16]; + { + unsigned i; + for (i = 0; i < 16; i++) + m[i] = GetUi32(input + i * 4); + } + +#define INIT_v_FROM_s(i) v[i] = s[i]; + + LOOP_8(INIT_v_FROM_s) + + // Blake2s_Increment_Counter(s, Z7_BLAKE2S_BLOCK_SIZE) + { + const UInt32 t0 = STATE_T(s)[0] + Z7_BLAKE2S_BLOCK_SIZE; + const UInt32 t1 = STATE_T(s)[1] + (t0 < Z7_BLAKE2S_BLOCK_SIZE); + STATE_T(s)[0] = t0; + STATE_T(s)[1] = t1; + v[12] = t0 ^ KIV(4); + v[13] = t1 ^ KIV(5); + } + // v[12] = STATE_T(s)[0] ^ KIV(4); + // v[13] = STATE_T(s)[1] ^ KIV(5); + v[14] = STATE_F(s)[0] ^ KIV(6); + v[15] = STATE_F(s)[1] ^ KIV(7); + + v[ 8] = KIV(0); + v[ 9] = KIV(1); + v[10] = KIV(2); + v[11] = KIV(3); + // PrintStates2((const UInt32 *)v, 1, 16); + + #define ADD_SIGMA(a, index) V(a, 0) += *(const UInt32 *)GET_SIGMA_PTR(m, sigma[index]); + #define ADD32M(dest, src, a) V(a, dest) += V(a, src); + #define XOR32M(dest, src, a) V(a, dest) ^= V(a, src); + #define RTR32M(dest, shift, a) V(a, dest) = rotrFixed(V(a, dest), shift); + +// big interleaving can provides big performance gain, if scheduler queues are small. +#if 0 || 1 && defined(MY_CPU_X86) + // interleave-1: for small register number (x86-32bit) + #define G2(index, a, x, y) \ + ADD_SIGMA (a, (index) + 2 * 0) \ + ADD32M (0, 1, a) \ + XOR32M (3, 0, a) \ + RTR32M (3, x, a) \ + ADD32M (2, 3, a) \ + XOR32M (1, 2, a) \ + RTR32M (1, y, a) \ + + #define G(a) \ + G2(a * 2 , a, 16, 12) \ + G2(a * 2 + 1, a, 8, 7) \ + + #define R2 \ + G(0) \ + G(1) \ + G(2) \ + G(3) \ + G(4) \ + G(5) \ + G(6) \ + G(7) \ + +#elif 0 || 1 && defined(MY_CPU_X86_OR_AMD64) + // interleave-2: is good if the number of registers is not big (x86-64). + + #define REP2(mac, dest, src, a, b) \ + mac(dest, src, a) \ + mac(dest, src, b) + + #define G2(index, a, b, x, y) \ + ADD_SIGMA (a, (index) + 2 * 0) \ + ADD_SIGMA (b, (index) + 2 * 1) \ + REP2 (ADD32M, 0, 1, a, b) \ + REP2 (XOR32M, 3, 0, a, b) \ + REP2 (RTR32M, 3, x, a, b) \ + REP2 (ADD32M, 2, 3, a, b) \ + REP2 (XOR32M, 1, 2, a, b) \ + REP2 (RTR32M, 1, y, a, b) \ + + #define G(a, b) \ + G2(a * 2 , a, b, 16, 12) \ + G2(a * 2 + 1, a, b, 8, 7) \ + + #define R2 \ + G(0, 1) \ + G(2, 3) \ + G(4, 5) \ + G(6, 7) \ + +#else + // interleave-4: + // it has big register pressure for x86/x64. + // and MSVC compilers for x86/x64 are slow for this branch. + // but if we have big number of registers, this branch can be faster. + + #define REP4(mac, dest, src, a, b, c, d) \ + mac(dest, src, a) \ + mac(dest, src, b) \ + mac(dest, src, c) \ + mac(dest, src, d) + + #define G2(index, a, b, c, d, x, y) \ + ADD_SIGMA (a, (index) + 2 * 0) \ + ADD_SIGMA (b, (index) + 2 * 1) \ + ADD_SIGMA (c, (index) + 2 * 2) \ + ADD_SIGMA (d, (index) + 2 * 3) \ + REP4 (ADD32M, 0, 1, a, b, c, d) \ + REP4 (XOR32M, 3, 0, a, b, c, d) \ + REP4 (RTR32M, 3, x, a, b, c, d) \ + REP4 (ADD32M, 2, 3, a, b, c, d) \ + REP4 (XOR32M, 1, 2, a, b, c, d) \ + REP4 (RTR32M, 1, y, a, b, c, d) \ + + #define G(a, b, c, d) \ + G2(a * 2 , a, b, c, d, 16, 12) \ + G2(a * 2 + 1, a, b, c, d, 8, 7) \ + + #define R2 \ + G(0, 1, 2, 3) \ + G(4, 5, 6, 7) \ + +#endif + + #define R(r) { const Byte *sigma = k_Blake2s_Sigma_4[r]; R2 } + + // Z7_BLAKE2S_UNROLL gives 5-6 KB larger code, but faster: + // 20-40% faster for (x86/x64) VC2010+/GCC/CLANG. + // 30-60% faster for (arm64-arm32) GCC. + // 5-11% faster for (arm64) CLANG-MAC. + // so Z7_BLAKE2S_UNROLL is good optimization, if there is no vector branch. + // But if there is vectors branch (for x86*), this scalar code will be unused mostly. + // So we want smaller code (without unrolling) in that case (x86*). +#if 0 || 1 && !defined(Z7_BLAKE2S_USE_VECTORS) + #define Z7_BLAKE2S_UNROLL +#endif + +#ifdef Z7_BLAKE2S_UNROLL + ROUNDS_LOOP_UNROLLED (R) +#else + ROUNDS_LOOP (R) +#endif + + #undef G + #undef G2 + #undef R + #undef R2 + + // printf("\n v after: \n"); + // PrintStates2((const UInt32 *)v, 1, 16); +#define XOR_s_PAIR_v(i) s[i] ^= v[i] ^ v[i + 8]; + + LOOP_8(XOR_s_PAIR_v) + // printf("\n s after:\n"); + // PrintStates2((const UInt32 *)s, 1, 16); +} + + +static +Z7_NO_INLINE +void +Z7_FASTCALL +Blake2sp_Compress2(UInt32 *s_items, const Byte *data, const Byte *end) +{ + size_t pos = 0; + // PrintStates2(s_items, 8, 16); + do + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(s_items, pos); + Blake2s_Compress(s, data); + data += Z7_BLAKE2S_BLOCK_SIZE; + pos += Z7_BLAKE2S_BLOCK_SIZE; + pos &= SUPER_BLOCK_MASK; + } + while (data != end); +} + + +#ifdef Z7_BLAKE2S_USE_VECTORS + +static Z7_BLAKE2SP_FUNC_COMPRESS g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast = Blake2sp_Compress2; +static Z7_BLAKE2SP_FUNC_COMPRESS g_Z7_BLAKE2SP_FUNC_COMPRESS_Single = Blake2sp_Compress2; +static Z7_BLAKE2SP_FUNC_INIT g_Z7_BLAKE2SP_FUNC_INIT_Init; +static Z7_BLAKE2SP_FUNC_INIT g_Z7_BLAKE2SP_FUNC_INIT_Final; +static unsigned g_z7_Blake2sp_SupportedFlags; + + #define Z7_BLAKE2SP_Compress_Fast(p) (p)->u.header.func_Compress_Fast + #define Z7_BLAKE2SP_Compress_Single(p) (p)->u.header.func_Compress_Single +#else + #define Z7_BLAKE2SP_Compress_Fast(p) Blake2sp_Compress2 + #define Z7_BLAKE2SP_Compress_Single(p) Blake2sp_Compress2 +#endif // Z7_BLAKE2S_USE_VECTORS + + +#if 1 && defined(MY_CPU_LE) + #define GET_DIGEST(_s, _digest) \ + { memcpy(_digest, _s, Z7_BLAKE2S_DIGEST_SIZE); } +#else + #define GET_DIGEST(_s, _digest) \ + { unsigned _i; for (_i = 0; _i < 8; _i++) \ + { SetUi32((_digest) + 4 * _i, (_s)[_i]) } \ + } +#endif + + +/* ---------- BLAKE2s ---------- */ +/* +// we need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() +typedef struct +{ + Byte digest_length; + Byte key_length; + Byte fanout; // = 1 : in sequential mode + Byte depth; // = 1 : in sequential mode + UInt32 leaf_length; + Byte node_offset[6]; // 0 for the first, leftmost, leaf, or in sequential mode + Byte node_depth; // 0 for the leaves, or in sequential mode + Byte inner_length; // [0, 32], 0 in sequential mode + Byte salt[BLAKE2S_SALTBYTES]; + Byte personal[BLAKE2S_PERSONALBYTES]; +} CBlake2sParam; +*/ + +#define k_Blake2sp_IV_0 \ + (KIV(0) ^ (Z7_BLAKE2S_DIGEST_SIZE | ((UInt32)Z7_BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24))) +#define k_Blake2sp_IV_3_FROM_NODE_DEPTH(node_depth) \ + (KIV(3) ^ ((UInt32)(node_depth) << 16) ^ ((UInt32)Z7_BLAKE2S_DIGEST_SIZE << 24)) + +Z7_FORCE_INLINE +static void Blake2sp_Init_Spec(UInt32 *s, unsigned node_offset, unsigned node_depth) +{ + s[0] = k_Blake2sp_IV_0; + s[1] = KIV(1); + s[2] = KIV(2) ^ (UInt32)node_offset; + s[3] = k_Blake2sp_IV_3_FROM_NODE_DEPTH(node_depth); + s[4] = KIV(4); + s[5] = KIV(5); + s[6] = KIV(6); + s[7] = KIV(7); + + STATE_T(s)[0] = 0; + STATE_T(s)[1] = 0; + STATE_F(s)[0] = 0; + STATE_F(s)[1] = 0; +} + + +#ifdef Z7_BLAKE2S_USE_V128_FAST + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_128BIT + BLAKE2S_ATTRIB_128BIT +#endif +void +Z7_FASTCALL +Blake2sp_InitState_V128_Fast(UInt32 *states) +{ +#define STORE_128_PAIR_INIT_STATES_2(i, t0, t1) \ + { STORE_128_TO_STRUCT(states + 0 + 4 * (i), (t0)); \ + STORE_128_TO_STRUCT(states + 32 + 4 * (i), (t1)); \ + } +#define STORE_128_PAIR_INIT_STATES_1(i, mac) \ + { const __m128i t = mac; \ + STORE_128_PAIR_INIT_STATES_2(i, t, t) \ + } +#define STORE_128_PAIR_INIT_STATES_IV(i) \ + STORE_128_PAIR_INIT_STATES_1(i, GET_128_IV_WAY4(i)) + + STORE_128_PAIR_INIT_STATES_1 (0, _mm_set1_epi32((Int32)k_Blake2sp_IV_0)) + STORE_128_PAIR_INIT_STATES_IV (1) + { + const __m128i t = GET_128_IV_WAY4(2); + STORE_128_PAIR_INIT_STATES_2 (2, + XOR_128(t, _mm_set_epi32(3, 2, 1, 0)), + XOR_128(t, _mm_set_epi32(7, 6, 5, 4))) + } + STORE_128_PAIR_INIT_STATES_1 (3, _mm_set1_epi32((Int32)k_Blake2sp_IV_3_FROM_NODE_DEPTH(0))) + STORE_128_PAIR_INIT_STATES_IV (4) + STORE_128_PAIR_INIT_STATES_IV (5) + STORE_128_PAIR_INIT_STATES_IV (6) + STORE_128_PAIR_INIT_STATES_IV (7) + STORE_128_PAIR_INIT_STATES_1 (16, _mm_set_epi32(0, 0, 0, 0)) + // printf("\n== exit Blake2sp_InitState_V128_Fast ctr=%d\n", states[64]); +} + +#endif // Z7_BLAKE2S_USE_V128_FAST + + +#ifdef Z7_BLAKE2S_USE_AVX2_FAST + +static +Z7_NO_INLINE +#ifdef BLAKE2S_ATTRIB_AVX2 + BLAKE2S_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +Blake2sp_InitState_AVX2_Fast(UInt32 *states) +{ +#define STORE_256_INIT_STATES(i, t) \ + STORE_256_TO_STRUCT(states + 8 * (i), t); +#define STORE_256_INIT_STATES_IV(i) \ + STORE_256_INIT_STATES(i, GET_256_IV_WAY8(i)) + + STORE_256_INIT_STATES (0, _mm256_set1_epi32((Int32)k_Blake2sp_IV_0)) + STORE_256_INIT_STATES_IV (1) + STORE_256_INIT_STATES (2, XOR_256( GET_256_IV_WAY8(2), + _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0))) + STORE_256_INIT_STATES (3, _mm256_set1_epi32((Int32)k_Blake2sp_IV_3_FROM_NODE_DEPTH(0))) + STORE_256_INIT_STATES_IV (4) + STORE_256_INIT_STATES_IV (5) + STORE_256_INIT_STATES_IV (6) + STORE_256_INIT_STATES_IV (7) + STORE_256_INIT_STATES (8, _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0)) + // printf("\n== exit Blake2sp_InitState_AVX2_Fast\n"); +} + +#endif // Z7_BLAKE2S_USE_AVX2_FAST + + + +Z7_NO_INLINE +void Blake2sp_InitState(CBlake2sp *p) +{ + size_t i; + // memset(p->states, 0, sizeof(p->states)); // for debug + p->u.header.cycPos = 0; +#ifdef Z7_BLAKE2SP_USE_FUNCTIONS + if (p->u.header.func_Init) + { + p->u.header.func_Init(p->states); + return; + } +#endif + for (i = 0; i < Z7_BLAKE2SP_PARALLEL_DEGREE; i++) + Blake2sp_Init_Spec(p->states + i * NSW, (unsigned)i, 0); +} + +void Blake2sp_Init(CBlake2sp *p) +{ +#ifdef Z7_BLAKE2SP_USE_FUNCTIONS + p->u.header.func_Compress_Fast = +#ifdef Z7_BLAKE2S_USE_VECTORS + g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast; +#else + NULL; +#endif + + p->u.header.func_Compress_Single = +#ifdef Z7_BLAKE2S_USE_VECTORS + g_Z7_BLAKE2SP_FUNC_COMPRESS_Single; +#else + NULL; +#endif + + p->u.header.func_Init = +#ifdef Z7_BLAKE2S_USE_VECTORS + g_Z7_BLAKE2SP_FUNC_INIT_Init; +#else + NULL; +#endif + + p->u.header.func_Final = +#ifdef Z7_BLAKE2S_USE_VECTORS + g_Z7_BLAKE2SP_FUNC_INIT_Final; +#else + NULL; +#endif +#endif + + Blake2sp_InitState(p); +} + + +void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size) +{ + size_t pos; + // printf("\nsize = 0x%6x, cycPos = %5u data = %p\n", (unsigned)size, (unsigned)p->u.header.cycPos, data); + if (size == 0) + return; + pos = p->u.header.cycPos; + // pos < SUPER_BLOCK_SIZE * 2 : is expected + // pos == SUPER_BLOCK_SIZE * 2 : is not expected, but is supported also + { + const size_t pos2 = pos & SUPER_BLOCK_MASK; + if (pos2) + { + const size_t rem = SUPER_BLOCK_SIZE - pos2; + if (rem > size) + { + p->u.header.cycPos = (unsigned)(pos + size); + // cycPos < SUPER_BLOCK_SIZE * 2 + memcpy((Byte *)(void *)p->buf32 + pos, data, size); + /* to simpilify the code here we don't try to process first superblock, + if (cycPos > SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE) */ + return; + } + // (rem <= size) + memcpy((Byte *)(void *)p->buf32 + pos, data, rem); + pos += rem; + data += rem; + size -= rem; + } + } + + // pos <= SUPER_BLOCK_SIZE * 2 + // pos % SUPER_BLOCK_SIZE == 0 + if (pos) + { + /* pos == SUPER_BLOCK_SIZE || + pos == SUPER_BLOCK_SIZE * 2 */ + size_t end = pos; + if (size > SUPER_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE + || (end -= SUPER_BLOCK_SIZE)) + { + Z7_BLAKE2SP_Compress_Fast(p)(p->states, + (const Byte *)(const void *)p->buf32, + (const Byte *)(const void *)p->buf32 + end); + if (pos -= end) + memcpy(p->buf32, (const Byte *)(const void *)p->buf32 + + SUPER_BLOCK_SIZE, SUPER_BLOCK_SIZE); + } + } + + // pos == 0 || (pos == SUPER_BLOCK_SIZE && size <= SUPER_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE) + if (size > SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE) + { + // pos == 0 + const Byte *end; + const size_t size2 = (size - (SUPER_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE + 1)) + & ~(size_t)SUPER_BLOCK_MASK; + size -= size2; + // size < SUPER_BLOCK_SIZE * 2 + end = data + size2; + Z7_BLAKE2SP_Compress_Fast(p)(p->states, data, end); + data = end; + } + + if (size != 0) + { + memcpy((Byte *)(void *)p->buf32 + pos, data, size); + pos += size; + } + p->u.header.cycPos = (unsigned)pos; + // cycPos < SUPER_BLOCK_SIZE * 2 +} + + +void Blake2sp_Final(CBlake2sp *p, Byte *digest) +{ + // UInt32 * const R_states = p->states; + // printf("\nBlake2sp_Final \n"); +#ifdef Z7_BLAKE2SP_USE_FUNCTIONS + if (p->u.header.func_Final) + p->u.header.func_Final(p->states); +#endif + // printf("\n=====\nBlake2sp_Final \n"); + // PrintStates(p->states, 32); + + // (p->u.header.cycPos == SUPER_BLOCK_SIZE) can be processed in any branch: + if (p->u.header.cycPos <= SUPER_BLOCK_SIZE) + { + unsigned pos; + memset((Byte *)(void *)p->buf32 + p->u.header.cycPos, + 0, SUPER_BLOCK_SIZE - p->u.header.cycPos); + STATE_F(&p->states[(Z7_BLAKE2SP_PARALLEL_DEGREE - 1) * NSW])[1] = BLAKE2S_FINAL_FLAG; + for (pos = 0; pos < SUPER_BLOCK_SIZE; pos += Z7_BLAKE2S_BLOCK_SIZE) + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, pos); + Blake2s_Set_LastBlock(s) + if (pos + Z7_BLAKE2S_BLOCK_SIZE > p->u.header.cycPos) + { + UInt32 delta = Z7_BLAKE2S_BLOCK_SIZE; + if (pos < p->u.header.cycPos) + delta -= p->u.header.cycPos & (Z7_BLAKE2S_BLOCK_SIZE - 1); + // 0 < delta <= Z7_BLAKE2S_BLOCK_SIZE + { + const UInt32 v = STATE_T(s)[0]; + STATE_T(s)[1] -= v < delta; // (v < delta) is same condition here as (v == 0) + STATE_T(s)[0] = v - delta; + } + } + } + // PrintStates(p->states, 16); + Z7_BLAKE2SP_Compress_Single(p)(p->states, + (Byte *)(void *)p->buf32, + (Byte *)(void *)p->buf32 + SUPER_BLOCK_SIZE); + // PrintStates(p->states, 16); + } + else + { + // (p->u.header.cycPos > SUPER_BLOCK_SIZE) + unsigned pos; + for (pos = 0; pos < SUPER_BLOCK_SIZE; pos += Z7_BLAKE2S_BLOCK_SIZE) + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, pos); + if (pos + SUPER_BLOCK_SIZE >= p->u.header.cycPos) + Blake2s_Set_LastBlock(s) + } + if (p->u.header.cycPos <= SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE) + STATE_F(&p->states[(Z7_BLAKE2SP_PARALLEL_DEGREE - 1) * NSW])[1] = BLAKE2S_FINAL_FLAG; + + Z7_BLAKE2SP_Compress_Single(p)(p->states, + (Byte *)(void *)p->buf32, + (Byte *)(void *)p->buf32 + SUPER_BLOCK_SIZE); + + // if (p->u.header.cycPos > SUPER_BLOCK_SIZE * 2 - Z7_BLAKE2S_BLOCK_SIZE; + STATE_F(&p->states[(Z7_BLAKE2SP_PARALLEL_DEGREE - 1) * NSW])[1] = BLAKE2S_FINAL_FLAG; + + // if (p->u.header.cycPos != SUPER_BLOCK_SIZE) + { + pos = SUPER_BLOCK_SIZE; + for (;;) + { + UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, pos & SUPER_BLOCK_MASK); + Blake2s_Set_LastBlock(s) + pos += Z7_BLAKE2S_BLOCK_SIZE; + if (pos >= p->u.header.cycPos) + { + if (pos != p->u.header.cycPos) + { + const UInt32 delta = pos - p->u.header.cycPos; + const UInt32 v = STATE_T(s)[0]; + STATE_T(s)[1] -= v < delta; + STATE_T(s)[0] = v - delta; + memset((Byte *)(void *)p->buf32 + p->u.header.cycPos, 0, delta); + } + break; + } + } + Z7_BLAKE2SP_Compress_Single(p)(p->states, + (Byte *)(void *)p->buf32 + SUPER_BLOCK_SIZE, + (Byte *)(void *)p->buf32 + pos); + } + } + + { + size_t pos; + for (pos = 0; pos < SUPER_BLOCK_SIZE / 2; pos += Z7_BLAKE2S_BLOCK_SIZE / 2) + { + const UInt32 * const s = GET_STATE_TABLE_PTR_FROM_BYTE_POS(p->states, (pos * 2)); + Byte *dest = (Byte *)(void *)p->buf32 + pos; + GET_DIGEST(s, dest) + } + } + Blake2sp_Init_Spec(p->states, 0, 1); + { + size_t pos; + for (pos = 0; pos < (Z7_BLAKE2SP_PARALLEL_DEGREE * Z7_BLAKE2S_DIGEST_SIZE) + - Z7_BLAKE2S_BLOCK_SIZE; pos += Z7_BLAKE2S_BLOCK_SIZE) + { + Z7_BLAKE2SP_Compress_Single(p)(p->states, + (const Byte *)(const void *)p->buf32 + pos, + (const Byte *)(const void *)p->buf32 + pos + Z7_BLAKE2S_BLOCK_SIZE); + } + } + // Blake2s_Final(p->states, 0, digest, p, (Byte *)(void *)p->buf32 + i); + Blake2s_Set_LastBlock(p->states) + STATE_F(p->states)[1] = BLAKE2S_FINAL_FLAG; + { + Z7_BLAKE2SP_Compress_Single(p)(p->states, + (const Byte *)(const void *)p->buf32 + Z7_BLAKE2SP_PARALLEL_DEGREE / 2 * Z7_BLAKE2S_BLOCK_SIZE - Z7_BLAKE2S_BLOCK_SIZE, + (const Byte *)(const void *)p->buf32 + Z7_BLAKE2SP_PARALLEL_DEGREE / 2 * Z7_BLAKE2S_BLOCK_SIZE); + } + GET_DIGEST(p->states, digest) + // printf("\n Blake2sp_Final 555 numDataInBufs = %5u\n", (unsigned)p->u.header.numDataInBufs); +} + + +BoolInt Blake2sp_SetFunction(CBlake2sp *p, unsigned algo) +{ + // printf("\n========== setfunction = %d ======== \n", algo); +#ifdef Z7_BLAKE2SP_USE_FUNCTIONS + Z7_BLAKE2SP_FUNC_COMPRESS func = NULL; + Z7_BLAKE2SP_FUNC_COMPRESS func_Single = NULL; + Z7_BLAKE2SP_FUNC_INIT func_Final = NULL; + Z7_BLAKE2SP_FUNC_INIT func_Init = NULL; +#else + UNUSED_VAR(p) +#endif + +#ifdef Z7_BLAKE2S_USE_VECTORS + + func = func_Single = Blake2sp_Compress2; + + if (algo != Z7_BLAKE2SP_ALGO_SCALAR) + { + // printf("\n========== setfunction NON-SCALER ======== \n"); + if (algo == Z7_BLAKE2SP_ALGO_DEFAULT) + { + func = g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast; + func_Single = g_Z7_BLAKE2SP_FUNC_COMPRESS_Single; + func_Init = g_Z7_BLAKE2SP_FUNC_INIT_Init; + func_Final = g_Z7_BLAKE2SP_FUNC_INIT_Final; + } + else + { + if ((g_z7_Blake2sp_SupportedFlags & (1u << algo)) == 0) + return False; + +#ifdef Z7_BLAKE2S_USE_AVX2 + + func_Single = +#if defined(Z7_BLAKE2S_USE_AVX2_WAY2) + Blake2sp_Compress2_AVX2_Way2; +#else + Z7_BLAKE2S_Compress2_V128; +#endif + +#ifdef Z7_BLAKE2S_USE_AVX2_FAST + if (algo == Z7_BLAKE2SP_ALGO_V256_FAST) + { + func = Blake2sp_Compress2_AVX2_Fast; + func_Final = Blake2sp_Final_AVX2_Fast; + func_Init = Blake2sp_InitState_AVX2_Fast; + } + else +#endif +#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 + if (algo == Z7_BLAKE2SP_ALGO_V256_WAY2) + func = Blake2sp_Compress2_AVX2_Way2; + else +#endif +#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 + if (algo == Z7_BLAKE2SP_ALGO_V256_WAY4) + { + func_Single = func = Blake2sp_Compress2_AVX2_Way4; + } + else +#endif +#endif // avx2 + { + if (algo == Z7_BLAKE2SP_ALGO_V128_FAST) + { + func = Blake2sp_Compress2_V128_Fast; + func_Final = Blake2sp_Final_V128_Fast; + func_Init = Blake2sp_InitState_V128_Fast; + func_Single = Z7_BLAKE2S_Compress2_V128; + } + else +#ifdef Z7_BLAKE2S_USE_V128_WAY2 + if (algo == Z7_BLAKE2SP_ALGO_V128_WAY2) + func = func_Single = Blake2sp_Compress2_V128_Way2; + else +#endif + { + if (algo != Z7_BLAKE2SP_ALGO_V128_WAY1) + return False; + func = func_Single = Blake2sp_Compress2_V128_Way1; + } + } + } + } +#else // !VECTORS + if (algo > 1) // Z7_BLAKE2SP_ALGO_SCALAR + return False; +#endif // !VECTORS + +#ifdef Z7_BLAKE2SP_USE_FUNCTIONS + p->u.header.func_Compress_Fast = func; + p->u.header.func_Compress_Single = func_Single; + p->u.header.func_Final = func_Final; + p->u.header.func_Init = func_Init; +#endif + // printf("\n p->u.header.func_Compress = %p", p->u.header.func_Compress); + return True; +} + + +void z7_Black2sp_Prepare(void) +{ +#ifdef Z7_BLAKE2S_USE_VECTORS + unsigned flags = 0; // (1u << Z7_BLAKE2SP_ALGO_V128_SCALAR); + + Z7_BLAKE2SP_FUNC_COMPRESS func_Fast = Blake2sp_Compress2; + Z7_BLAKE2SP_FUNC_COMPRESS func_Single = Blake2sp_Compress2; + Z7_BLAKE2SP_FUNC_INIT func_Init = NULL; + Z7_BLAKE2SP_FUNC_INIT func_Final = NULL; + +#if defined(MY_CPU_X86_OR_AMD64) + #if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) + // optional check + #if 0 || !(defined(__AVX512F__) && defined(__AVX512VL__)) + if (CPU_IsSupported_AVX512F_AVX512VL()) + #endif + #elif defined(Z7_BLAKE2S_USE_SSE41) + if (CPU_IsSupported_SSE41()) + #elif defined(Z7_BLAKE2S_USE_SSSE3) + if (CPU_IsSupported_SSSE3()) + #elif !defined(MY_CPU_AMD64) + if (CPU_IsSupported_SSE2()) + #endif +#endif + { + #if defined(Z7_BLAKE2S_USE_SSE41) + // printf("\n========== Blake2s SSE41 128-bit\n"); + #elif defined(Z7_BLAKE2S_USE_SSSE3) + // printf("\n========== Blake2s SSSE3 128-bit\n"); + #else + // printf("\n========== Blake2s SSE2 128-bit\n"); + #endif + // func_Fast = f_vector = Blake2sp_Compress2_V128_Way2; + // printf("\n========== Blake2sp_Compress2_V128_Way2\n"); + func_Fast = + func_Single = Z7_BLAKE2S_Compress2_V128; + flags |= (1u << Z7_BLAKE2SP_ALGO_V128_WAY1); +#ifdef Z7_BLAKE2S_USE_V128_WAY2 + flags |= (1u << Z7_BLAKE2SP_ALGO_V128_WAY2); +#endif +#ifdef Z7_BLAKE2S_USE_V128_FAST + flags |= (1u << Z7_BLAKE2SP_ALGO_V128_FAST); + func_Fast = Blake2sp_Compress2_V128_Fast; + func_Init = Blake2sp_InitState_V128_Fast; + func_Final = Blake2sp_Final_V128_Fast; +#endif + +#ifdef Z7_BLAKE2S_USE_AVX2 +#if defined(MY_CPU_X86_OR_AMD64) + + #if defined(Z7_BLAKE2S_USE_AVX512_ALWAYS) + #if 0 + if (CPU_IsSupported_AVX512F_AVX512VL()) + #endif + #else + if (CPU_IsSupported_AVX2()) + #endif +#endif + { + // #pragma message ("=== Blake2s AVX2") + // printf("\n========== Blake2s AVX2\n"); + +#ifdef Z7_BLAKE2S_USE_AVX2_WAY2 + func_Single = Blake2sp_Compress2_AVX2_Way2; + flags |= (1u << Z7_BLAKE2SP_ALGO_V256_WAY2); +#endif +#ifdef Z7_BLAKE2S_USE_AVX2_WAY4 + flags |= (1u << Z7_BLAKE2SP_ALGO_V256_WAY4); +#endif + +#ifdef Z7_BLAKE2S_USE_AVX2_FAST + flags |= (1u << Z7_BLAKE2SP_ALGO_V256_FAST); + func_Fast = Blake2sp_Compress2_AVX2_Fast; + func_Init = Blake2sp_InitState_AVX2_Fast; + func_Final = Blake2sp_Final_AVX2_Fast; +#elif defined(Z7_BLAKE2S_USE_AVX2_WAY4) + func_Fast = Blake2sp_Compress2_AVX2_Way4; +#elif defined(Z7_BLAKE2S_USE_AVX2_WAY2) + func_Fast = Blake2sp_Compress2_AVX2_Way2; +#endif + } // avx2 +#endif // avx2 + } // sse* + g_Z7_BLAKE2SP_FUNC_COMPRESS_Fast = func_Fast; + g_Z7_BLAKE2SP_FUNC_COMPRESS_Single = func_Single; + g_Z7_BLAKE2SP_FUNC_INIT_Init = func_Init; + g_Z7_BLAKE2SP_FUNC_INIT_Final = func_Final; + g_z7_Blake2sp_SupportedFlags = flags; + // printf("\nflags=%x\n", flags); +#endif // vectors +} + +/* +#ifdef Z7_BLAKE2S_USE_VECTORS +void align_test2(CBlake2sp *sp); +void align_test2(CBlake2sp *sp) +{ + __m128i a = LOAD_128(sp->states); + D_XOR_128(a, LOAD_128(sp->states + 4)); + STORE_128(sp->states, a); +} +void align_test2(void); +void align_test2(void) +{ + CBlake2sp sp; + Blake2sp_Init(&sp); + Blake2sp_Update(&sp, NULL, 0); +} +#endif +*/ diff --git a/C/Bra.c b/C/Bra.c index 818cc78ba..e61edf8f1 100644 --- a/C/Bra.c +++ b/C/Bra.c @@ -1,709 +1,709 @@ -/* Bra.c -- Branch converters for RISC code -2024-01-20 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Bra.h" -#include "RotateDefs.h" -#include "CpuArch.h" - -#if defined(MY_CPU_SIZEOF_POINTER) \ - && ( MY_CPU_SIZEOF_POINTER == 4 \ - || MY_CPU_SIZEOF_POINTER == 8) - #define BR_CONV_USE_OPT_PC_PTR -#endif - -#ifdef BR_CONV_USE_OPT_PC_PTR -#define BR_PC_INIT pc -= (UInt32)(SizeT)p; -#define BR_PC_GET (pc + (UInt32)(SizeT)p) -#else -#define BR_PC_INIT pc += (UInt32)size; -#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p)) -// #define BR_PC_INIT -// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data)) -#endif - -#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c; -// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c; - -#define Z7_BRANCH_CONV(name) z7_ ## name - -#define Z7_BRANCH_FUNC_MAIN(name) \ -static \ -Z7_FORCE_INLINE \ -Z7_ATTRIB_NO_VECTOR \ -Byte *Z7_BRANCH_CONV(name)(Byte *p, SizeT size, UInt32 pc, int encoding) - -#define Z7_BRANCH_FUNC_IMP(name, m, encoding) \ -Z7_NO_INLINE \ -Z7_ATTRIB_NO_VECTOR \ -Byte *m(name)(Byte *data, SizeT size, UInt32 pc) \ - { return Z7_BRANCH_CONV(name)(data, size, pc, encoding); } \ - -#ifdef Z7_EXTRACT_ONLY -#define Z7_BRANCH_FUNCS_IMP(name) \ - Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0) -#else -#define Z7_BRANCH_FUNCS_IMP(name) \ - Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0) \ - Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC_2, 1) -#endif - -#if defined(__clang__) -#define BR_EXTERNAL_FOR -#define BR_NEXT_ITERATION continue; -#else -#define BR_EXTERNAL_FOR for (;;) -#define BR_NEXT_ITERATION break; -#endif - -#if defined(__clang__) && (__clang_major__ >= 8) \ - || defined(__GNUC__) && (__GNUC__ >= 1000) \ - // GCC is not good for __builtin_expect() here - /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ - // #define Z7_unlikely [[unlikely]] - // #define Z7_LIKELY(x) (__builtin_expect((x), 1)) - #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) - // #define Z7_likely [[likely]] -#else - // #define Z7_LIKELY(x) (x) - #define Z7_UNLIKELY(x) (x) - // #define Z7_likely -#endif - - -Z7_BRANCH_FUNC_MAIN(BranchConv_ARM64) -{ - // Byte *p = data; - const Byte *lim; - const UInt32 flag = (UInt32)1 << (24 - 4); - const UInt32 mask = ((UInt32)1 << 24) - (flag << 1); - size &= ~(SizeT)3; - // if (size == 0) return p; - lim = p + size; - BR_PC_INIT - pc -= 4; // because (p) will point to next instruction - - BR_EXTERNAL_FOR - { - // Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (;;) - { - UInt32 v; - if Z7_UNLIKELY(p == lim) - return p; - v = GetUi32a(p); - p += 4; - if Z7_UNLIKELY(((v - 0x94000000) & 0xfc000000) == 0) - { - UInt32 c = BR_PC_GET >> 2; - BR_CONVERT_VAL(v, c) - v &= 0x03ffffff; - v |= 0x94000000; - SetUi32a(p - 4, v) - BR_NEXT_ITERATION - } - // v = rotlFixed(v, 8); v += (flag << 8) - 0x90; if Z7_UNLIKELY((v & ((mask << 8) + 0x9f)) == 0) - v -= 0x90000000; if Z7_UNLIKELY((v & 0x9f000000) == 0) - { - UInt32 z, c; - // v = rotrFixed(v, 8); - v += flag; if Z7_UNLIKELY(v & mask) continue; - z = (v & 0xffffffe0) | (v >> 26); - c = (BR_PC_GET >> (12 - 3)) & ~(UInt32)7; - BR_CONVERT_VAL(z, c) - v &= 0x1f; - v |= 0x90000000; - v |= z << 26; - v |= 0x00ffffe0 & ((z & (((flag << 1) - 1))) - flag); - SetUi32a(p - 4, v) - } - } - } -} -Z7_BRANCH_FUNCS_IMP(BranchConv_ARM64) - - -Z7_BRANCH_FUNC_MAIN(BranchConv_ARM) -{ - // Byte *p = data; - const Byte *lim; - size &= ~(SizeT)3; - lim = p + size; - BR_PC_INIT - /* in ARM: branch offset is relative to the +2 instructions from current instruction. - (p) will point to next instruction */ - pc += 8 - 4; - - for (;;) - { - for (;;) - { - if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break; - if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break; - } - { - UInt32 v = GetUi32a(p - 4); - UInt32 c = BR_PC_GET >> 2; - BR_CONVERT_VAL(v, c) - v &= 0x00ffffff; - v |= 0xeb000000; - SetUi32a(p - 4, v) - } - } -} -Z7_BRANCH_FUNCS_IMP(BranchConv_ARM) - - -Z7_BRANCH_FUNC_MAIN(BranchConv_PPC) -{ - // Byte *p = data; - const Byte *lim; - size &= ~(SizeT)3; - lim = p + size; - BR_PC_INIT - pc -= 4; // because (p) will point to next instruction - - for (;;) - { - UInt32 v; - for (;;) - { - if Z7_UNLIKELY(p == lim) - return p; - // v = GetBe32a(p); - v = *(UInt32 *)(void *)p; - p += 4; - // if ((v & 0xfc000003) == 0x48000001) break; - // if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) break; - if Z7_UNLIKELY( - ((v - Z7_CONV_BE_TO_NATIVE_CONST32(0x48000001)) - & Z7_CONV_BE_TO_NATIVE_CONST32(0xfc000003)) == 0) break; - } - { - v = Z7_CONV_NATIVE_TO_BE_32(v); - { - UInt32 c = BR_PC_GET; - BR_CONVERT_VAL(v, c) - } - v &= 0x03ffffff; - v |= 0x48000000; - SetBe32a(p - 4, v) - } - } -} -Z7_BRANCH_FUNCS_IMP(BranchConv_PPC) - - -#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED -#define BR_SPARC_USE_ROTATE -#endif - -Z7_BRANCH_FUNC_MAIN(BranchConv_SPARC) -{ - // Byte *p = data; - const Byte *lim; - const UInt32 flag = (UInt32)1 << 22; - size &= ~(SizeT)3; - lim = p + size; - BR_PC_INIT - pc -= 4; // because (p) will point to next instruction - for (;;) - { - UInt32 v; - for (;;) - { - if Z7_UNLIKELY(p == lim) - return p; - /* // the code without GetBe32a(): - { const UInt32 v = GetUi16a(p) & 0xc0ff; p += 4; if (v == 0x40 || v == 0xc07f) break; } - */ - v = GetBe32a(p); - p += 4; - #ifdef BR_SPARC_USE_ROTATE - v = rotlFixed(v, 2); - v += (flag << 2) - 1; - if Z7_UNLIKELY((v & (3 - (flag << 3))) == 0) - #else - v += (UInt32)5 << 29; - v ^= (UInt32)7 << 29; - v += flag; - if Z7_UNLIKELY((v & (0 - (flag << 1))) == 0) - #endif - break; - } - { - // UInt32 v = GetBe32a(p - 4); - #ifndef BR_SPARC_USE_ROTATE - v <<= 2; - #endif - { - UInt32 c = BR_PC_GET; - BR_CONVERT_VAL(v, c) - } - v &= (flag << 3) - 1; - #ifdef BR_SPARC_USE_ROTATE - v -= (flag << 2) - 1; - v = rotrFixed(v, 2); - #else - v -= (flag << 2); - v >>= 2; - v |= (UInt32)1 << 30; - #endif - SetBe32a(p - 4, v) - } - } -} -Z7_BRANCH_FUNCS_IMP(BranchConv_SPARC) - - -Z7_BRANCH_FUNC_MAIN(BranchConv_ARMT) -{ - // Byte *p = data; - Byte *lim; - size &= ~(SizeT)1; - // if (size == 0) return p; - if (size <= 2) return p; - size -= 2; - lim = p + size; - BR_PC_INIT - /* in ARM: branch offset is relative to the +2 instructions from current instruction. - (p) will point to the +2 instructions from current instruction */ - // pc += 4 - 4; - // if (encoding) pc -= 0xf800 << 1; else pc += 0xf800 << 1; - // #define ARMT_TAIL_PROC { goto armt_tail; } - #define ARMT_TAIL_PROC { return p; } - - do - { - /* in MSVC 32-bit x86 compilers: - UInt32 version : it loads value from memory with movzx - Byte version : it loads value to 8-bit register (AL/CL) - movzx version is slightly faster in some cpus - */ - unsigned b1; - // Byte / unsigned - b1 = p[1]; - // optimized version to reduce one (p >= lim) check: - // unsigned a1 = p[1]; b1 = p[3]; p += 2; if Z7_LIKELY((b1 & (a1 ^ 8)) < 0xf8) - for (;;) - { - unsigned b3; // Byte / UInt32 - /* (Byte)(b3) normalization can use low byte computations in MSVC. - It gives smaller code, and no loss of speed in some compilers/cpus. - But new MSVC 32-bit x86 compilers use more slow load - from memory to low byte register in that case. - So we try to use full 32-bit computations for faster code. - */ - // if (p >= lim) { ARMT_TAIL_PROC } b3 = b1 + 8; b1 = p[3]; p += 2; if ((b3 & b1) >= 0xf8) break; - if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b3 = p[3]; p += 2; if Z7_UNLIKELY((b3 & (b1 ^ 8)) >= 0xf8) break; - if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b1 = p[3]; p += 2; if Z7_UNLIKELY((b1 & (b3 ^ 8)) >= 0xf8) break; - } - { - /* we can adjust pc for (0xf800) to rid of (& 0x7FF) operation. - But gcc/clang for arm64 can use bfi instruction for full code here */ - UInt32 v = - ((UInt32)GetUi16a(p - 2) << 11) | - ((UInt32)GetUi16a(p) & 0x7FF); - /* - UInt32 v = - ((UInt32)p[1 - 2] << 19) - + (((UInt32)p[1] & 0x7) << 8) - + (((UInt32)p[-2] << 11)) - + (p[0]); - */ - p += 2; - { - UInt32 c = BR_PC_GET >> 1; - BR_CONVERT_VAL(v, c) - } - SetUi16a(p - 4, (UInt16)(((v >> 11) & 0x7ff) | 0xf000)) - SetUi16a(p - 2, (UInt16)(v | 0xf800)) - /* - p[-4] = (Byte)(v >> 11); - p[-3] = (Byte)(0xf0 | ((v >> 19) & 0x7)); - p[-2] = (Byte)v; - p[-1] = (Byte)(0xf8 | (v >> 8)); - */ - } - } - while (p < lim); - return p; - // armt_tail: - // if ((Byte)((lim[1] & 0xf8)) != 0xf0) { lim += 2; } return lim; - // return (Byte *)(lim + ((Byte)((lim[1] ^ 0xf0) & 0xf8) == 0 ? 0 : 2)); - // return (Byte *)(lim + (((lim[1] ^ ~0xfu) & ~7u) == 0 ? 0 : 2)); - // return (Byte *)(lim + 2 - (((((unsigned)lim[1] ^ 8) + 8) >> 7) & 2)); -} -Z7_BRANCH_FUNCS_IMP(BranchConv_ARMT) - - -// #define BR_IA64_NO_INLINE - -Z7_BRANCH_FUNC_MAIN(BranchConv_IA64) -{ - // Byte *p = data; - const Byte *lim; - size &= ~(SizeT)15; - lim = p + size; - pc -= 1 << 4; - pc >>= 4 - 1; - // pc -= 1 << 1; - - for (;;) - { - unsigned m; - for (;;) - { - if Z7_UNLIKELY(p == lim) - return p; - m = (unsigned)((UInt32)0x334b0000 >> (*p & 0x1e)); - p += 16; - pc += 1 << 1; - if (m &= 3) - break; - } - { - p += (ptrdiff_t)m * 5 - 20; // negative value is expected here. - do - { - const UInt32 t = - #if defined(MY_CPU_X86_OR_AMD64) - // we use 32-bit load here to reduce code size on x86: - GetUi32(p); - #else - GetUi16(p); - #endif - UInt32 z = GetUi32(p + 1) >> m; - p += 5; - if (((t >> m) & (0x70 << 1)) == 0 - && ((z - (0x5000000 << 1)) & (0xf000000 << 1)) == 0) - { - UInt32 v = (UInt32)((0x8fffff << 1) | 1) & z; - z ^= v; - #ifdef BR_IA64_NO_INLINE - v |= (v & ((UInt32)1 << (23 + 1))) >> 3; - { - UInt32 c = pc; - BR_CONVERT_VAL(v, c) - } - v &= (0x1fffff << 1) | 1; - #else - { - if (encoding) - { - // pc &= ~(0xc00000 << 1); // we just need to clear at least 2 bits - pc &= (0x1fffff << 1) | 1; - v += pc; - } - else - { - // pc |= 0xc00000 << 1; // we need to set at least 2 bits - pc |= ~(UInt32)((0x1fffff << 1) | 1); - v -= pc; - } - } - v &= ~(UInt32)(0x600000 << 1); - #endif - v += (0x700000 << 1); - v &= (0x8fffff << 1) | 1; - z |= v; - z <<= m; - SetUi32(p + 1 - 5, z) - } - m++; - } - while (m &= 3); // while (m < 4); - } - } -} -Z7_BRANCH_FUNCS_IMP(BranchConv_IA64) - - -#define BR_CONVERT_VAL_ENC(v) v += BR_PC_GET; -#define BR_CONVERT_VAL_DEC(v) v -= BR_PC_GET; - -#if 1 && defined(MY_CPU_LE_UNALIGN) - #define RISCV_USE_UNALIGNED_LOAD -#endif - -#ifdef RISCV_USE_UNALIGNED_LOAD - #define RISCV_GET_UI32(p) GetUi32(p) - #define RISCV_SET_UI32(p, v) { SetUi32(p, v) } -#else - #define RISCV_GET_UI32(p) \ - ((UInt32)GetUi16a(p) + \ - ((UInt32)GetUi16a((p) + 2) << 16)) - #define RISCV_SET_UI32(p, v) { \ - SetUi16a(p, (UInt16)(v)) \ - SetUi16a((p) + 2, (UInt16)(v >> 16)) } -#endif - -#if 1 && defined(MY_CPU_LE) - #define RISCV_USE_16BIT_LOAD -#endif - -#ifdef RISCV_USE_16BIT_LOAD - #define RISCV_LOAD_VAL(p) GetUi16a(p) -#else - #define RISCV_LOAD_VAL(p) (*(p)) -#endif - -#define RISCV_INSTR_SIZE 2 -#define RISCV_STEP_1 (4 + RISCV_INSTR_SIZE) -#define RISCV_STEP_2 4 -#define RISCV_REG_VAL (2 << 7) -#define RISCV_CMD_VAL 3 -#if 1 - // for code size optimization: - #define RISCV_DELTA_7F 0x7f -#else - #define RISCV_DELTA_7F 0 -#endif - -#define RISCV_CHECK_1(v, b) \ - (((((b) - RISCV_CMD_VAL) ^ ((v) << 8)) & (0xf8000 + RISCV_CMD_VAL)) == 0) - -#if 1 - #define RISCV_CHECK_2(v, r) \ - ((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL | 8)) \ - << 18) \ - < ((r) & 0x1d)) -#else - // this branch gives larger code, because - // compilers generate larger code for big constants. - #define RISCV_CHECK_2(v, r) \ - ((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \ - & ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \ - < ((r) & 0x1d)) -#endif - - -#define RISCV_SCAN_LOOP \ - Byte *lim; \ - size &= ~(SizeT)(RISCV_INSTR_SIZE - 1); \ - if (size <= 6) return p; \ - size -= 6; \ - lim = p + size; \ - BR_PC_INIT \ - for (;;) \ - { \ - UInt32 a, v; \ - /* Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE */ \ - for (;;) \ - { \ - if Z7_UNLIKELY(p >= lim) { return p; } \ - a = (RISCV_LOAD_VAL(p) ^ 0x10u) + 1; \ - if ((a & 0x77) == 0) break; \ - a = (RISCV_LOAD_VAL(p + RISCV_INSTR_SIZE) ^ 0x10u) + 1; \ - p += RISCV_INSTR_SIZE * 2; \ - if ((a & 0x77) == 0) \ - { \ - p -= RISCV_INSTR_SIZE; \ - if Z7_UNLIKELY(p >= lim) { return p; } \ - break; \ - } \ - } -// (xx6f ^ 10) + 1 = xx7f + 1 = xx80 : JAL -// (xxef ^ 10) + 1 = xxff + 1 = xx00 + 100 : JAL -// (xx17 ^ 10) + 1 = xx07 + 1 = xx08 : AUIPC -// (xx97 ^ 10) + 1 = xx87 + 1 = xx88 : AUIPC - -Byte * Z7_BRANCH_CONV_ENC(RISCV)(Byte *p, SizeT size, UInt32 pc) -{ - RISCV_SCAN_LOOP - v = a; - a = RISCV_GET_UI32(p); -#ifndef RISCV_USE_16BIT_LOAD - v += (UInt32)p[1] << 8; -#endif - - if ((v & 8) == 0) // JAL - { - if ((v - (0x100 /* - RISCV_DELTA_7F */)) & 0xd80) - { - p += RISCV_INSTR_SIZE; - continue; - } - { - v = ((a & 1u << 31) >> 11) - | ((a & 0x3ff << 21) >> 20) - | ((a & 1 << 20) >> 9) - | (a & 0xff << 12); - BR_CONVERT_VAL_ENC(v) - // ((v & 1) == 0) - // v: bits [1 : 20] contain offset bits -#if 0 && defined(RISCV_USE_UNALIGNED_LOAD) - a &= 0xfff; - a |= ((UInt32)(v << 23)) - | ((UInt32)(v << 7) & ((UInt32)0xff << 16)) - | ((UInt32)(v >> 5) & ((UInt32)0xf0 << 8)); - RISCV_SET_UI32(p, a) -#else // aligned -#if 0 - SetUi16a(p, (UInt16)(((v >> 5) & 0xf000) | (a & 0xfff))) -#else - p[1] = (Byte)(((v >> 13) & 0xf0) | ((a >> 8) & 0xf)); -#endif - -#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) - v <<= 15; - v = Z7_BSWAP32(v); - SetUi16a(p + 2, (UInt16)v) -#else - p[2] = (Byte)(v >> 9); - p[3] = (Byte)(v >> 1); -#endif -#endif // aligned - } - p += 4; - continue; - } // JAL - - { - // AUIPC - if (v & 0xe80) // (not x0) and (not x2) - { - const UInt32 b = RISCV_GET_UI32(p + 4); - if (RISCV_CHECK_1(v, b)) - { - { - const UInt32 temp = (b << 12) | (0x17 + RISCV_REG_VAL); - RISCV_SET_UI32(p, temp) - } - a &= 0xfffff000; - { -#if 1 - const int t = -1 >> 1; - if (t != -1) - a += (b >> 20) - ((b >> 19) & 0x1000); // arithmetic right shift emulation - else -#endif - a += (UInt32)((Int32)b >> 20); // arithmetic right shift (sign-extension). - } - BR_CONVERT_VAL_ENC(a) -#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) - a = Z7_BSWAP32(a); - RISCV_SET_UI32(p + 4, a) -#else - SetBe32(p + 4, a) -#endif - p += 8; - } - else - p += RISCV_STEP_1; - } - else - { - UInt32 r = a >> 27; - if (RISCV_CHECK_2(v, r)) - { - v = RISCV_GET_UI32(p + 4); - r = (r << 7) + 0x17 + (v & 0xfffff000); - a = (a >> 12) | (v << 20); - RISCV_SET_UI32(p, r) - RISCV_SET_UI32(p + 4, a) - p += 8; - } - else - p += RISCV_STEP_2; - } - } - } // for -} - - -Byte * Z7_BRANCH_CONV_DEC(RISCV)(Byte *p, SizeT size, UInt32 pc) -{ - RISCV_SCAN_LOOP -#ifdef RISCV_USE_16BIT_LOAD - if ((a & 8) == 0) - { -#else - v = a; - a += (UInt32)p[1] << 8; - if ((v & 8) == 0) - { -#endif - // JAL - a -= 0x100 - RISCV_DELTA_7F; - if (a & 0xd80) - { - p += RISCV_INSTR_SIZE; - continue; - } - { - const UInt32 a_old = (a + (0xef - RISCV_DELTA_7F)) & 0xfff; -#if 0 // unaligned - a = GetUi32(p); - v = (UInt32)(a >> 23) & ((UInt32)0xff << 1) - | (UInt32)(a >> 7) & ((UInt32)0xff << 9) -#elif 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) - v = GetUi16a(p + 2); - v = Z7_BSWAP32(v) >> 15 -#else - v = (UInt32)p[3] << 1 - | (UInt32)p[2] << 9 -#endif - | (UInt32)((a & 0xf000) << 5); - BR_CONVERT_VAL_DEC(v) - a = a_old - | (v << 11 & 1u << 31) - | (v << 20 & 0x3ff << 21) - | (v << 9 & 1 << 20) - | (v & 0xff << 12); - RISCV_SET_UI32(p, a) - } - p += 4; - continue; - } // JAL - - { - // AUIPC - v = a; -#if 1 && defined(RISCV_USE_UNALIGNED_LOAD) - a = GetUi32(p); -#else - a |= (UInt32)GetUi16a(p + 2) << 16; -#endif - if ((v & 0xe80) == 0) // x0/x2 - { - const UInt32 r = a >> 27; - if (RISCV_CHECK_2(v, r)) - { - UInt32 b; -#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) - b = RISCV_GET_UI32(p + 4); - b = Z7_BSWAP32(b); -#else - b = GetBe32(p + 4); -#endif - v = a >> 12; - BR_CONVERT_VAL_DEC(b) - a = (r << 7) + 0x17; - a += (b + 0x800) & 0xfffff000; - v |= b << 20; - RISCV_SET_UI32(p, a) - RISCV_SET_UI32(p + 4, v) - p += 8; - } - else - p += RISCV_STEP_2; - } - else - { - const UInt32 b = RISCV_GET_UI32(p + 4); - if (!RISCV_CHECK_1(v, b)) - p += RISCV_STEP_1; - else - { - v = (a & 0xfffff000) | (b >> 20); - a = (b << 12) | (0x17 + RISCV_REG_VAL); - RISCV_SET_UI32(p, a) - RISCV_SET_UI32(p + 4, v) - p += 8; - } - } - } - } // for -} +/* Bra.c -- Branch converters for RISC code +2024-01-20 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bra.h" +#include "RotateDefs.h" +#include "CpuArch.h" + +#if defined(MY_CPU_SIZEOF_POINTER) \ + && ( MY_CPU_SIZEOF_POINTER == 4 \ + || MY_CPU_SIZEOF_POINTER == 8) + #define BR_CONV_USE_OPT_PC_PTR +#endif + +#ifdef BR_CONV_USE_OPT_PC_PTR +#define BR_PC_INIT pc -= (UInt32)(SizeT)p; +#define BR_PC_GET (pc + (UInt32)(SizeT)p) +#else +#define BR_PC_INIT pc += (UInt32)size; +#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p)) +// #define BR_PC_INIT +// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data)) +#endif + +#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c; +// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c; + +#define Z7_BRANCH_CONV(name) z7_ ## name + +#define Z7_BRANCH_FUNC_MAIN(name) \ +static \ +Z7_FORCE_INLINE \ +Z7_ATTRIB_NO_VECTOR \ +Byte *Z7_BRANCH_CONV(name)(Byte *p, SizeT size, UInt32 pc, int encoding) + +#define Z7_BRANCH_FUNC_IMP(name, m, encoding) \ +Z7_NO_INLINE \ +Z7_ATTRIB_NO_VECTOR \ +Byte *m(name)(Byte *data, SizeT size, UInt32 pc) \ + { return Z7_BRANCH_CONV(name)(data, size, pc, encoding); } \ + +#ifdef Z7_EXTRACT_ONLY +#define Z7_BRANCH_FUNCS_IMP(name) \ + Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0) +#else +#define Z7_BRANCH_FUNCS_IMP(name) \ + Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC_2, 0) \ + Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC_2, 1) +#endif + +#if defined(__clang__) +#define BR_EXTERNAL_FOR +#define BR_NEXT_ITERATION continue; +#else +#define BR_EXTERNAL_FOR for (;;) +#define BR_NEXT_ITERATION break; +#endif + +#if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 1000) \ + // GCC is not good for __builtin_expect() here + /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ + // #define Z7_unlikely [[unlikely]] + // #define Z7_LIKELY(x) (__builtin_expect((x), 1)) + #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) + // #define Z7_likely [[likely]] +#else + // #define Z7_LIKELY(x) (x) + #define Z7_UNLIKELY(x) (x) + // #define Z7_likely +#endif + + +Z7_BRANCH_FUNC_MAIN(BranchConv_ARM64) +{ + // Byte *p = data; + const Byte *lim; + const UInt32 flag = (UInt32)1 << (24 - 4); + const UInt32 mask = ((UInt32)1 << 24) - (flag << 1); + size &= ~(SizeT)3; + // if (size == 0) return p; + lim = p + size; + BR_PC_INIT + pc -= 4; // because (p) will point to next instruction + + BR_EXTERNAL_FOR + { + // Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (;;) + { + UInt32 v; + if Z7_UNLIKELY(p == lim) + return p; + v = GetUi32a(p); + p += 4; + if Z7_UNLIKELY(((v - 0x94000000) & 0xfc000000) == 0) + { + UInt32 c = BR_PC_GET >> 2; + BR_CONVERT_VAL(v, c) + v &= 0x03ffffff; + v |= 0x94000000; + SetUi32a(p - 4, v) + BR_NEXT_ITERATION + } + // v = rotlFixed(v, 8); v += (flag << 8) - 0x90; if Z7_UNLIKELY((v & ((mask << 8) + 0x9f)) == 0) + v -= 0x90000000; if Z7_UNLIKELY((v & 0x9f000000) == 0) + { + UInt32 z, c; + // v = rotrFixed(v, 8); + v += flag; if Z7_UNLIKELY(v & mask) continue; + z = (v & 0xffffffe0) | (v >> 26); + c = (BR_PC_GET >> (12 - 3)) & ~(UInt32)7; + BR_CONVERT_VAL(z, c) + v &= 0x1f; + v |= 0x90000000; + v |= z << 26; + v |= 0x00ffffe0 & ((z & (((flag << 1) - 1))) - flag); + SetUi32a(p - 4, v) + } + } + } +} +Z7_BRANCH_FUNCS_IMP(BranchConv_ARM64) + + +Z7_BRANCH_FUNC_MAIN(BranchConv_ARM) +{ + // Byte *p = data; + const Byte *lim; + size &= ~(SizeT)3; + lim = p + size; + BR_PC_INIT + /* in ARM: branch offset is relative to the +2 instructions from current instruction. + (p) will point to next instruction */ + pc += 8 - 4; + + for (;;) + { + for (;;) + { + if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break; + if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break; + } + { + UInt32 v = GetUi32a(p - 4); + UInt32 c = BR_PC_GET >> 2; + BR_CONVERT_VAL(v, c) + v &= 0x00ffffff; + v |= 0xeb000000; + SetUi32a(p - 4, v) + } + } +} +Z7_BRANCH_FUNCS_IMP(BranchConv_ARM) + + +Z7_BRANCH_FUNC_MAIN(BranchConv_PPC) +{ + // Byte *p = data; + const Byte *lim; + size &= ~(SizeT)3; + lim = p + size; + BR_PC_INIT + pc -= 4; // because (p) will point to next instruction + + for (;;) + { + UInt32 v; + for (;;) + { + if Z7_UNLIKELY(p == lim) + return p; + // v = GetBe32a(p); + v = *(UInt32 *)(void *)p; + p += 4; + // if ((v & 0xfc000003) == 0x48000001) break; + // if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) break; + if Z7_UNLIKELY( + ((v - Z7_CONV_BE_TO_NATIVE_CONST32(0x48000001)) + & Z7_CONV_BE_TO_NATIVE_CONST32(0xfc000003)) == 0) break; + } + { + v = Z7_CONV_NATIVE_TO_BE_32(v); + { + UInt32 c = BR_PC_GET; + BR_CONVERT_VAL(v, c) + } + v &= 0x03ffffff; + v |= 0x48000000; + SetBe32a(p - 4, v) + } + } +} +Z7_BRANCH_FUNCS_IMP(BranchConv_PPC) + + +#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED +#define BR_SPARC_USE_ROTATE +#endif + +Z7_BRANCH_FUNC_MAIN(BranchConv_SPARC) +{ + // Byte *p = data; + const Byte *lim; + const UInt32 flag = (UInt32)1 << 22; + size &= ~(SizeT)3; + lim = p + size; + BR_PC_INIT + pc -= 4; // because (p) will point to next instruction + for (;;) + { + UInt32 v; + for (;;) + { + if Z7_UNLIKELY(p == lim) + return p; + /* // the code without GetBe32a(): + { const UInt32 v = GetUi16a(p) & 0xc0ff; p += 4; if (v == 0x40 || v == 0xc07f) break; } + */ + v = GetBe32a(p); + p += 4; + #ifdef BR_SPARC_USE_ROTATE + v = rotlFixed(v, 2); + v += (flag << 2) - 1; + if Z7_UNLIKELY((v & (3 - (flag << 3))) == 0) + #else + v += (UInt32)5 << 29; + v ^= (UInt32)7 << 29; + v += flag; + if Z7_UNLIKELY((v & (0 - (flag << 1))) == 0) + #endif + break; + } + { + // UInt32 v = GetBe32a(p - 4); + #ifndef BR_SPARC_USE_ROTATE + v <<= 2; + #endif + { + UInt32 c = BR_PC_GET; + BR_CONVERT_VAL(v, c) + } + v &= (flag << 3) - 1; + #ifdef BR_SPARC_USE_ROTATE + v -= (flag << 2) - 1; + v = rotrFixed(v, 2); + #else + v -= (flag << 2); + v >>= 2; + v |= (UInt32)1 << 30; + #endif + SetBe32a(p - 4, v) + } + } +} +Z7_BRANCH_FUNCS_IMP(BranchConv_SPARC) + + +Z7_BRANCH_FUNC_MAIN(BranchConv_ARMT) +{ + // Byte *p = data; + Byte *lim; + size &= ~(SizeT)1; + // if (size == 0) return p; + if (size <= 2) return p; + size -= 2; + lim = p + size; + BR_PC_INIT + /* in ARM: branch offset is relative to the +2 instructions from current instruction. + (p) will point to the +2 instructions from current instruction */ + // pc += 4 - 4; + // if (encoding) pc -= 0xf800 << 1; else pc += 0xf800 << 1; + // #define ARMT_TAIL_PROC { goto armt_tail; } + #define ARMT_TAIL_PROC { return p; } + + do + { + /* in MSVC 32-bit x86 compilers: + UInt32 version : it loads value from memory with movzx + Byte version : it loads value to 8-bit register (AL/CL) + movzx version is slightly faster in some cpus + */ + unsigned b1; + // Byte / unsigned + b1 = p[1]; + // optimized version to reduce one (p >= lim) check: + // unsigned a1 = p[1]; b1 = p[3]; p += 2; if Z7_LIKELY((b1 & (a1 ^ 8)) < 0xf8) + for (;;) + { + unsigned b3; // Byte / UInt32 + /* (Byte)(b3) normalization can use low byte computations in MSVC. + It gives smaller code, and no loss of speed in some compilers/cpus. + But new MSVC 32-bit x86 compilers use more slow load + from memory to low byte register in that case. + So we try to use full 32-bit computations for faster code. + */ + // if (p >= lim) { ARMT_TAIL_PROC } b3 = b1 + 8; b1 = p[3]; p += 2; if ((b3 & b1) >= 0xf8) break; + if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b3 = p[3]; p += 2; if Z7_UNLIKELY((b3 & (b1 ^ 8)) >= 0xf8) break; + if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b1 = p[3]; p += 2; if Z7_UNLIKELY((b1 & (b3 ^ 8)) >= 0xf8) break; + } + { + /* we can adjust pc for (0xf800) to rid of (& 0x7FF) operation. + But gcc/clang for arm64 can use bfi instruction for full code here */ + UInt32 v = + ((UInt32)GetUi16a(p - 2) << 11) | + ((UInt32)GetUi16a(p) & 0x7FF); + /* + UInt32 v = + ((UInt32)p[1 - 2] << 19) + + (((UInt32)p[1] & 0x7) << 8) + + (((UInt32)p[-2] << 11)) + + (p[0]); + */ + p += 2; + { + UInt32 c = BR_PC_GET >> 1; + BR_CONVERT_VAL(v, c) + } + SetUi16a(p - 4, (UInt16)(((v >> 11) & 0x7ff) | 0xf000)) + SetUi16a(p - 2, (UInt16)(v | 0xf800)) + /* + p[-4] = (Byte)(v >> 11); + p[-3] = (Byte)(0xf0 | ((v >> 19) & 0x7)); + p[-2] = (Byte)v; + p[-1] = (Byte)(0xf8 | (v >> 8)); + */ + } + } + while (p < lim); + return p; + // armt_tail: + // if ((Byte)((lim[1] & 0xf8)) != 0xf0) { lim += 2; } return lim; + // return (Byte *)(lim + ((Byte)((lim[1] ^ 0xf0) & 0xf8) == 0 ? 0 : 2)); + // return (Byte *)(lim + (((lim[1] ^ ~0xfu) & ~7u) == 0 ? 0 : 2)); + // return (Byte *)(lim + 2 - (((((unsigned)lim[1] ^ 8) + 8) >> 7) & 2)); +} +Z7_BRANCH_FUNCS_IMP(BranchConv_ARMT) + + +// #define BR_IA64_NO_INLINE + +Z7_BRANCH_FUNC_MAIN(BranchConv_IA64) +{ + // Byte *p = data; + const Byte *lim; + size &= ~(SizeT)15; + lim = p + size; + pc -= 1 << 4; + pc >>= 4 - 1; + // pc -= 1 << 1; + + for (;;) + { + unsigned m; + for (;;) + { + if Z7_UNLIKELY(p == lim) + return p; + m = (unsigned)((UInt32)0x334b0000 >> (*p & 0x1e)); + p += 16; + pc += 1 << 1; + if (m &= 3) + break; + } + { + p += (ptrdiff_t)m * 5 - 20; // negative value is expected here. + do + { + const UInt32 t = + #if defined(MY_CPU_X86_OR_AMD64) + // we use 32-bit load here to reduce code size on x86: + GetUi32(p); + #else + GetUi16(p); + #endif + UInt32 z = GetUi32(p + 1) >> m; + p += 5; + if (((t >> m) & (0x70 << 1)) == 0 + && ((z - (0x5000000 << 1)) & (0xf000000 << 1)) == 0) + { + UInt32 v = (UInt32)((0x8fffff << 1) | 1) & z; + z ^= v; + #ifdef BR_IA64_NO_INLINE + v |= (v & ((UInt32)1 << (23 + 1))) >> 3; + { + UInt32 c = pc; + BR_CONVERT_VAL(v, c) + } + v &= (0x1fffff << 1) | 1; + #else + { + if (encoding) + { + // pc &= ~(0xc00000 << 1); // we just need to clear at least 2 bits + pc &= (0x1fffff << 1) | 1; + v += pc; + } + else + { + // pc |= 0xc00000 << 1; // we need to set at least 2 bits + pc |= ~(UInt32)((0x1fffff << 1) | 1); + v -= pc; + } + } + v &= ~(UInt32)(0x600000 << 1); + #endif + v += (0x700000 << 1); + v &= (0x8fffff << 1) | 1; + z |= v; + z <<= m; + SetUi32(p + 1 - 5, z) + } + m++; + } + while (m &= 3); // while (m < 4); + } + } +} +Z7_BRANCH_FUNCS_IMP(BranchConv_IA64) + + +#define BR_CONVERT_VAL_ENC(v) v += BR_PC_GET; +#define BR_CONVERT_VAL_DEC(v) v -= BR_PC_GET; + +#if 1 && defined(MY_CPU_LE_UNALIGN) + #define RISCV_USE_UNALIGNED_LOAD +#endif + +#ifdef RISCV_USE_UNALIGNED_LOAD + #define RISCV_GET_UI32(p) GetUi32(p) + #define RISCV_SET_UI32(p, v) { SetUi32(p, v) } +#else + #define RISCV_GET_UI32(p) \ + ((UInt32)GetUi16a(p) + \ + ((UInt32)GetUi16a((p) + 2) << 16)) + #define RISCV_SET_UI32(p, v) { \ + SetUi16a(p, (UInt16)(v)) \ + SetUi16a((p) + 2, (UInt16)(v >> 16)) } +#endif + +#if 1 && defined(MY_CPU_LE) + #define RISCV_USE_16BIT_LOAD +#endif + +#ifdef RISCV_USE_16BIT_LOAD + #define RISCV_LOAD_VAL(p) GetUi16a(p) +#else + #define RISCV_LOAD_VAL(p) (*(p)) +#endif + +#define RISCV_INSTR_SIZE 2 +#define RISCV_STEP_1 (4 + RISCV_INSTR_SIZE) +#define RISCV_STEP_2 4 +#define RISCV_REG_VAL (2 << 7) +#define RISCV_CMD_VAL 3 +#if 1 + // for code size optimization: + #define RISCV_DELTA_7F 0x7f +#else + #define RISCV_DELTA_7F 0 +#endif + +#define RISCV_CHECK_1(v, b) \ + (((((b) - RISCV_CMD_VAL) ^ ((v) << 8)) & (0xf8000 + RISCV_CMD_VAL)) == 0) + +#if 1 + #define RISCV_CHECK_2(v, r) \ + ((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL | 8)) \ + << 18) \ + < ((r) & 0x1d)) +#else + // this branch gives larger code, because + // compilers generate larger code for big constants. + #define RISCV_CHECK_2(v, r) \ + ((((v) - ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \ + & ((RISCV_CMD_VAL << 12) | RISCV_REG_VAL)) \ + < ((r) & 0x1d)) +#endif + + +#define RISCV_SCAN_LOOP \ + Byte *lim; \ + size &= ~(SizeT)(RISCV_INSTR_SIZE - 1); \ + if (size <= 6) return p; \ + size -= 6; \ + lim = p + size; \ + BR_PC_INIT \ + for (;;) \ + { \ + UInt32 a, v; \ + /* Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE */ \ + for (;;) \ + { \ + if Z7_UNLIKELY(p >= lim) { return p; } \ + a = (RISCV_LOAD_VAL(p) ^ 0x10u) + 1; \ + if ((a & 0x77) == 0) break; \ + a = (RISCV_LOAD_VAL(p + RISCV_INSTR_SIZE) ^ 0x10u) + 1; \ + p += RISCV_INSTR_SIZE * 2; \ + if ((a & 0x77) == 0) \ + { \ + p -= RISCV_INSTR_SIZE; \ + if Z7_UNLIKELY(p >= lim) { return p; } \ + break; \ + } \ + } +// (xx6f ^ 10) + 1 = xx7f + 1 = xx80 : JAL +// (xxef ^ 10) + 1 = xxff + 1 = xx00 + 100 : JAL +// (xx17 ^ 10) + 1 = xx07 + 1 = xx08 : AUIPC +// (xx97 ^ 10) + 1 = xx87 + 1 = xx88 : AUIPC + +Byte * Z7_BRANCH_CONV_ENC(RISCV)(Byte *p, SizeT size, UInt32 pc) +{ + RISCV_SCAN_LOOP + v = a; + a = RISCV_GET_UI32(p); +#ifndef RISCV_USE_16BIT_LOAD + v += (UInt32)p[1] << 8; +#endif + + if ((v & 8) == 0) // JAL + { + if ((v - (0x100 /* - RISCV_DELTA_7F */)) & 0xd80) + { + p += RISCV_INSTR_SIZE; + continue; + } + { + v = ((a & 1u << 31) >> 11) + | ((a & 0x3ff << 21) >> 20) + | ((a & 1 << 20) >> 9) + | (a & 0xff << 12); + BR_CONVERT_VAL_ENC(v) + // ((v & 1) == 0) + // v: bits [1 : 20] contain offset bits +#if 0 && defined(RISCV_USE_UNALIGNED_LOAD) + a &= 0xfff; + a |= ((UInt32)(v << 23)) + | ((UInt32)(v << 7) & ((UInt32)0xff << 16)) + | ((UInt32)(v >> 5) & ((UInt32)0xf0 << 8)); + RISCV_SET_UI32(p, a) +#else // aligned +#if 0 + SetUi16a(p, (UInt16)(((v >> 5) & 0xf000) | (a & 0xfff))) +#else + p[1] = (Byte)(((v >> 13) & 0xf0) | ((a >> 8) & 0xf)); +#endif + +#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) + v <<= 15; + v = Z7_BSWAP32(v); + SetUi16a(p + 2, (UInt16)v) +#else + p[2] = (Byte)(v >> 9); + p[3] = (Byte)(v >> 1); +#endif +#endif // aligned + } + p += 4; + continue; + } // JAL + + { + // AUIPC + if (v & 0xe80) // (not x0) and (not x2) + { + const UInt32 b = RISCV_GET_UI32(p + 4); + if (RISCV_CHECK_1(v, b)) + { + { + const UInt32 temp = (b << 12) | (0x17 + RISCV_REG_VAL); + RISCV_SET_UI32(p, temp) + } + a &= 0xfffff000; + { +#if 1 + const int t = -1 >> 1; + if (t != -1) + a += (b >> 20) - ((b >> 19) & 0x1000); // arithmetic right shift emulation + else +#endif + a += (UInt32)((Int32)b >> 20); // arithmetic right shift (sign-extension). + } + BR_CONVERT_VAL_ENC(a) +#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) + a = Z7_BSWAP32(a); + RISCV_SET_UI32(p + 4, a) +#else + SetBe32(p + 4, a) +#endif + p += 8; + } + else + p += RISCV_STEP_1; + } + else + { + UInt32 r = a >> 27; + if (RISCV_CHECK_2(v, r)) + { + v = RISCV_GET_UI32(p + 4); + r = (r << 7) + 0x17 + (v & 0xfffff000); + a = (a >> 12) | (v << 20); + RISCV_SET_UI32(p, r) + RISCV_SET_UI32(p + 4, a) + p += 8; + } + else + p += RISCV_STEP_2; + } + } + } // for +} + + +Byte * Z7_BRANCH_CONV_DEC(RISCV)(Byte *p, SizeT size, UInt32 pc) +{ + RISCV_SCAN_LOOP +#ifdef RISCV_USE_16BIT_LOAD + if ((a & 8) == 0) + { +#else + v = a; + a += (UInt32)p[1] << 8; + if ((v & 8) == 0) + { +#endif + // JAL + a -= 0x100 - RISCV_DELTA_7F; + if (a & 0xd80) + { + p += RISCV_INSTR_SIZE; + continue; + } + { + const UInt32 a_old = (a + (0xef - RISCV_DELTA_7F)) & 0xfff; +#if 0 // unaligned + a = GetUi32(p); + v = (UInt32)(a >> 23) & ((UInt32)0xff << 1) + | (UInt32)(a >> 7) & ((UInt32)0xff << 9) +#elif 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) + v = GetUi16a(p + 2); + v = Z7_BSWAP32(v) >> 15 +#else + v = (UInt32)p[3] << 1 + | (UInt32)p[2] << 9 +#endif + | (UInt32)((a & 0xf000) << 5); + BR_CONVERT_VAL_DEC(v) + a = a_old + | (v << 11 & 1u << 31) + | (v << 20 & 0x3ff << 21) + | (v << 9 & 1 << 20) + | (v & 0xff << 12); + RISCV_SET_UI32(p, a) + } + p += 4; + continue; + } // JAL + + { + // AUIPC + v = a; +#if 1 && defined(RISCV_USE_UNALIGNED_LOAD) + a = GetUi32(p); +#else + a |= (UInt32)GetUi16a(p + 2) << 16; +#endif + if ((v & 0xe80) == 0) // x0/x2 + { + const UInt32 r = a >> 27; + if (RISCV_CHECK_2(v, r)) + { + UInt32 b; +#if 1 && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE) + b = RISCV_GET_UI32(p + 4); + b = Z7_BSWAP32(b); +#else + b = GetBe32(p + 4); +#endif + v = a >> 12; + BR_CONVERT_VAL_DEC(b) + a = (r << 7) + 0x17; + a += (b + 0x800) & 0xfffff000; + v |= b << 20; + RISCV_SET_UI32(p, a) + RISCV_SET_UI32(p + 4, v) + p += 8; + } + else + p += RISCV_STEP_2; + } + else + { + const UInt32 b = RISCV_GET_UI32(p + 4); + if (!RISCV_CHECK_1(v, b)) + p += RISCV_STEP_1; + else + { + v = (a & 0xfffff000) | (b >> 20); + a = (b << 12) | (0x17 + RISCV_REG_VAL); + RISCV_SET_UI32(p, a) + RISCV_SET_UI32(p + 4, v) + p += 8; + } + } + } + } // for +} diff --git a/C/Bra.h b/C/Bra.h index 060ee1707..b47112ced 100644 --- a/C/Bra.h +++ b/C/Bra.h @@ -1,105 +1,105 @@ -/* Bra.h -- Branch converters for executables -2024-01-20 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_BRA_H -#define ZIP7_INC_BRA_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* #define PPC BAD_PPC_11 // for debug */ - -#define Z7_BRANCH_CONV_DEC_2(name) z7_ ## name ## _Dec -#define Z7_BRANCH_CONV_ENC_2(name) z7_ ## name ## _Enc -#define Z7_BRANCH_CONV_DEC(name) Z7_BRANCH_CONV_DEC_2(BranchConv_ ## name) -#define Z7_BRANCH_CONV_ENC(name) Z7_BRANCH_CONV_ENC_2(BranchConv_ ## name) -#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec -#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc - -#define Z7_BRANCH_CONV_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc) -#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state) - -typedef Z7_BRANCH_CONV_DECL( (*z7_Func_BranchConv)); -typedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt)); - -#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0 -Z7_BRANCH_CONV_ST_DECL (Z7_BRANCH_CONV_ST_DEC(X86)); -Z7_BRANCH_CONV_ST_DECL (Z7_BRANCH_CONV_ST_ENC(X86)); - -#define Z7_BRANCH_FUNCS_DECL(name) \ -Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_DEC_2(name)); \ -Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_ENC_2(name)); - -Z7_BRANCH_FUNCS_DECL (BranchConv_ARM64) -Z7_BRANCH_FUNCS_DECL (BranchConv_ARM) -Z7_BRANCH_FUNCS_DECL (BranchConv_ARMT) -Z7_BRANCH_FUNCS_DECL (BranchConv_PPC) -Z7_BRANCH_FUNCS_DECL (BranchConv_SPARC) -Z7_BRANCH_FUNCS_DECL (BranchConv_IA64) -Z7_BRANCH_FUNCS_DECL (BranchConv_RISCV) - -/* -These functions convert data that contain CPU instructions. -Each such function converts relative addresses to absolute addresses in some -branch instructions: CALL (in all converters) and JUMP (X86 converter only). -Such conversion allows to increase compression ratio, if we compress that data. - -There are 2 types of converters: - Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc); - Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state); -Each Converter supports 2 versions: one for encoding -and one for decoding (_Enc/_Dec postfixes in function name). - -In params: - data : data buffer - size : size of data - pc : current virtual Program Counter (Instruction Pointer) value -In/Out param: - state : pointer to state variable (for X86 converter only) - -Return: - The pointer to position in (data) buffer after last byte that was processed. - If the caller calls converter again, it must call it starting with that position. - But the caller is allowed to move data in buffer. So pointer to - current processed position also will be changed for next call. - Also the caller must increase internal (pc) value for next call. - -Each converter has some characteristics: Endian, Alignment, LookAhead. - Type Endian Alignment LookAhead - - X86 little 1 4 - ARMT little 2 2 - RISCV little 2 6 - ARM little 4 0 - ARM64 little 4 0 - PPC big 4 0 - SPARC big 4 0 - IA64 little 16 0 - - (data) must be aligned for (Alignment). - processed size can be calculated as: - SizeT processed = Conv(data, size, pc) - data; - if (processed == 0) - it means that converter needs more data for processing. - If (size < Alignment + LookAhead) - then (processed == 0) is allowed. - -Example code for conversion in loop: - UInt32 pc = 0; - size = 0; - for (;;) - { - size += Load_more_input_data(data + size); - SizeT processed = Conv(data, size, pc) - data; - if (processed == 0 && no_more_input_data_after_size) - break; // we stop convert loop - data += processed; - size -= processed; - pc += processed; - } -*/ - -EXTERN_C_END - -#endif +/* Bra.h -- Branch converters for executables +2024-01-20 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_BRA_H +#define ZIP7_INC_BRA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* #define PPC BAD_PPC_11 // for debug */ + +#define Z7_BRANCH_CONV_DEC_2(name) z7_ ## name ## _Dec +#define Z7_BRANCH_CONV_ENC_2(name) z7_ ## name ## _Enc +#define Z7_BRANCH_CONV_DEC(name) Z7_BRANCH_CONV_DEC_2(BranchConv_ ## name) +#define Z7_BRANCH_CONV_ENC(name) Z7_BRANCH_CONV_ENC_2(BranchConv_ ## name) +#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec +#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc + +#define Z7_BRANCH_CONV_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc) +#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state) + +typedef Z7_BRANCH_CONV_DECL( (*z7_Func_BranchConv)); +typedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt)); + +#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0 +Z7_BRANCH_CONV_ST_DECL (Z7_BRANCH_CONV_ST_DEC(X86)); +Z7_BRANCH_CONV_ST_DECL (Z7_BRANCH_CONV_ST_ENC(X86)); + +#define Z7_BRANCH_FUNCS_DECL(name) \ +Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_DEC_2(name)); \ +Z7_BRANCH_CONV_DECL (Z7_BRANCH_CONV_ENC_2(name)); + +Z7_BRANCH_FUNCS_DECL (BranchConv_ARM64) +Z7_BRANCH_FUNCS_DECL (BranchConv_ARM) +Z7_BRANCH_FUNCS_DECL (BranchConv_ARMT) +Z7_BRANCH_FUNCS_DECL (BranchConv_PPC) +Z7_BRANCH_FUNCS_DECL (BranchConv_SPARC) +Z7_BRANCH_FUNCS_DECL (BranchConv_IA64) +Z7_BRANCH_FUNCS_DECL (BranchConv_RISCV) + +/* +These functions convert data that contain CPU instructions. +Each such function converts relative addresses to absolute addresses in some +branch instructions: CALL (in all converters) and JUMP (X86 converter only). +Such conversion allows to increase compression ratio, if we compress that data. + +There are 2 types of converters: + Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc); + Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state); +Each Converter supports 2 versions: one for encoding +and one for decoding (_Enc/_Dec postfixes in function name). + +In params: + data : data buffer + size : size of data + pc : current virtual Program Counter (Instruction Pointer) value +In/Out param: + state : pointer to state variable (for X86 converter only) + +Return: + The pointer to position in (data) buffer after last byte that was processed. + If the caller calls converter again, it must call it starting with that position. + But the caller is allowed to move data in buffer. So pointer to + current processed position also will be changed for next call. + Also the caller must increase internal (pc) value for next call. + +Each converter has some characteristics: Endian, Alignment, LookAhead. + Type Endian Alignment LookAhead + + X86 little 1 4 + ARMT little 2 2 + RISCV little 2 6 + ARM little 4 0 + ARM64 little 4 0 + PPC big 4 0 + SPARC big 4 0 + IA64 little 16 0 + + (data) must be aligned for (Alignment). + processed size can be calculated as: + SizeT processed = Conv(data, size, pc) - data; + if (processed == 0) + it means that converter needs more data for processing. + If (size < Alignment + LookAhead) + then (processed == 0) is allowed. + +Example code for conversion in loop: + UInt32 pc = 0; + size = 0; + for (;;) + { + size += Load_more_input_data(data + size); + SizeT processed = Conv(data, size, pc) - data; + if (processed == 0 && no_more_input_data_after_size) + break; // we stop convert loop + data += processed; + size -= processed; + pc += processed; + } +*/ + +EXTERN_C_END + +#endif diff --git a/C/Bra86.c b/C/Bra86.c index 9c468ba74..d81f392ae 100644 --- a/C/Bra86.c +++ b/C/Bra86.c @@ -1,187 +1,187 @@ -/* Bra86.c -- Branch converter for X86 code (BCJ) -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Bra.h" -#include "CpuArch.h" - - -#if defined(MY_CPU_SIZEOF_POINTER) \ - && ( MY_CPU_SIZEOF_POINTER == 4 \ - || MY_CPU_SIZEOF_POINTER == 8) - #define BR_CONV_USE_OPT_PC_PTR -#endif - -#ifdef BR_CONV_USE_OPT_PC_PTR -#define BR_PC_INIT pc -= (UInt32)(SizeT)p; // (MY_uintptr_t) -#define BR_PC_GET (pc + (UInt32)(SizeT)p) -#else -#define BR_PC_INIT pc += (UInt32)size; -#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p)) -// #define BR_PC_INIT -// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data)) -#endif - -#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c; -// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c; - -#define Z7_BRANCH_CONV_ST(name) z7_BranchConvSt_ ## name - -#define BR86_NEED_CONV_FOR_MS_BYTE(b) ((((b) + 1) & 0xfe) == 0) - -#ifdef MY_CPU_LE_UNALIGN - #define BR86_PREPARE_BCJ_SCAN const UInt32 v = GetUi32(p) ^ 0xe8e8e8e8; - #define BR86_IS_BCJ_BYTE(n) ((v & ((UInt32)0xfe << (n) * 8)) == 0) -#else - #define BR86_PREPARE_BCJ_SCAN - // bad for MSVC X86 (partial write to byte reg): - #define BR86_IS_BCJ_BYTE(n) ((p[n - 4] & 0xfe) == 0xe8) - // bad for old MSVC (partial write to byte reg): - // #define BR86_IS_BCJ_BYTE(n) (((*p ^ 0xe8) & 0xfe) == 0) -#endif - -static -Z7_FORCE_INLINE -Z7_ATTRIB_NO_VECTOR -Byte *Z7_BRANCH_CONV_ST(X86)(Byte *p, SizeT size, UInt32 pc, UInt32 *state, int encoding) -{ - if (size < 5) - return p; - { - // Byte *p = data; - const Byte *lim = p + size - 4; - unsigned mask = (unsigned)*state; // & 7; -#ifdef BR_CONV_USE_OPT_PC_PTR - /* if BR_CONV_USE_OPT_PC_PTR is defined: we need to adjust (pc) for (+4), - because call/jump offset is relative to the next instruction. - if BR_CONV_USE_OPT_PC_PTR is not defined : we don't need to adjust (pc) for (+4), - because BR_PC_GET uses (pc - (lim - p)), and lim was adjusted for (-4) before. - */ - pc += 4; -#endif - BR_PC_INIT - goto start; - - for (;; mask |= 4) - { - // cont: mask |= 4; - start: - if (p >= lim) - goto fin; - { - BR86_PREPARE_BCJ_SCAN - p += 4; - if (BR86_IS_BCJ_BYTE(0)) { goto m0; } mask >>= 1; - if (BR86_IS_BCJ_BYTE(1)) { goto m1; } mask >>= 1; - if (BR86_IS_BCJ_BYTE(2)) { goto m2; } mask = 0; - if (BR86_IS_BCJ_BYTE(3)) { goto a3; } - } - goto main_loop; - - m0: p--; - m1: p--; - m2: p--; - if (mask == 0) - goto a3; - if (p > lim) - goto fin_p; - - // if (((0x17u >> mask) & 1) == 0) - if (mask > 4 || mask == 3) - { - mask >>= 1; - continue; // goto cont; - } - mask >>= 1; - if (BR86_NEED_CONV_FOR_MS_BYTE(p[mask])) - continue; // goto cont; - // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont; - { - UInt32 v = GetUi32(p); - UInt32 c; - v += (1 << 24); if (v & 0xfe000000) continue; // goto cont; - c = BR_PC_GET; - BR_CONVERT_VAL(v, c) - { - mask <<= 3; - if (BR86_NEED_CONV_FOR_MS_BYTE(v >> mask)) - { - v ^= (((UInt32)0x100 << mask) - 1); - #ifdef MY_CPU_X86 - // for X86 : we can recalculate (c) to reduce register pressure - c = BR_PC_GET; - #endif - BR_CONVERT_VAL(v, c) - } - mask = 0; - } - // v = (v & ((1 << 24) - 1)) - (v & (1 << 24)); - v &= (1 << 25) - 1; v -= (1 << 24); - SetUi32(p, v) - p += 4; - goto main_loop; - } - - main_loop: - if (p >= lim) - goto fin; - for (;;) - { - BR86_PREPARE_BCJ_SCAN - p += 4; - if (BR86_IS_BCJ_BYTE(0)) { goto a0; } - if (BR86_IS_BCJ_BYTE(1)) { goto a1; } - if (BR86_IS_BCJ_BYTE(2)) { goto a2; } - if (BR86_IS_BCJ_BYTE(3)) { goto a3; } - if (p >= lim) - goto fin; - } - - a0: p--; - a1: p--; - a2: p--; - a3: - if (p > lim) - goto fin_p; - // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont; - { - UInt32 v = GetUi32(p); - UInt32 c; - v += (1 << 24); if (v & 0xfe000000) continue; // goto cont; - c = BR_PC_GET; - BR_CONVERT_VAL(v, c) - // v = (v & ((1 << 24) - 1)) - (v & (1 << 24)); - v &= (1 << 25) - 1; v -= (1 << 24); - SetUi32(p, v) - p += 4; - goto main_loop; - } - } - -fin_p: - p--; -fin: - // the following processing for tail is optional and can be commented - /* - lim += 4; - for (; p < lim; p++, mask >>= 1) - if ((*p & 0xfe) == 0xe8) - break; - */ - *state = (UInt32)mask; - return p; - } -} - - -#define Z7_BRANCH_CONV_ST_FUNC_IMP(name, m, encoding) \ -Z7_NO_INLINE \ -Z7_ATTRIB_NO_VECTOR \ -Byte *m(name)(Byte *data, SizeT size, UInt32 pc, UInt32 *state) \ - { return Z7_BRANCH_CONV_ST(name)(data, size, pc, state, encoding); } - -Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_DEC, 0) -#ifndef Z7_EXTRACT_ONLY -Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_ENC, 1) -#endif +/* Bra86.c -- Branch converter for X86 code (BCJ) +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Bra.h" +#include "CpuArch.h" + + +#if defined(MY_CPU_SIZEOF_POINTER) \ + && ( MY_CPU_SIZEOF_POINTER == 4 \ + || MY_CPU_SIZEOF_POINTER == 8) + #define BR_CONV_USE_OPT_PC_PTR +#endif + +#ifdef BR_CONV_USE_OPT_PC_PTR +#define BR_PC_INIT pc -= (UInt32)(SizeT)p; // (MY_uintptr_t) +#define BR_PC_GET (pc + (UInt32)(SizeT)p) +#else +#define BR_PC_INIT pc += (UInt32)size; +#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p)) +// #define BR_PC_INIT +// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data)) +#endif + +#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c; +// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c; + +#define Z7_BRANCH_CONV_ST(name) z7_BranchConvSt_ ## name + +#define BR86_NEED_CONV_FOR_MS_BYTE(b) ((((b) + 1) & 0xfe) == 0) + +#ifdef MY_CPU_LE_UNALIGN + #define BR86_PREPARE_BCJ_SCAN const UInt32 v = GetUi32(p) ^ 0xe8e8e8e8; + #define BR86_IS_BCJ_BYTE(n) ((v & ((UInt32)0xfe << (n) * 8)) == 0) +#else + #define BR86_PREPARE_BCJ_SCAN + // bad for MSVC X86 (partial write to byte reg): + #define BR86_IS_BCJ_BYTE(n) ((p[n - 4] & 0xfe) == 0xe8) + // bad for old MSVC (partial write to byte reg): + // #define BR86_IS_BCJ_BYTE(n) (((*p ^ 0xe8) & 0xfe) == 0) +#endif + +static +Z7_FORCE_INLINE +Z7_ATTRIB_NO_VECTOR +Byte *Z7_BRANCH_CONV_ST(X86)(Byte *p, SizeT size, UInt32 pc, UInt32 *state, int encoding) +{ + if (size < 5) + return p; + { + // Byte *p = data; + const Byte *lim = p + size - 4; + unsigned mask = (unsigned)*state; // & 7; +#ifdef BR_CONV_USE_OPT_PC_PTR + /* if BR_CONV_USE_OPT_PC_PTR is defined: we need to adjust (pc) for (+4), + because call/jump offset is relative to the next instruction. + if BR_CONV_USE_OPT_PC_PTR is not defined : we don't need to adjust (pc) for (+4), + because BR_PC_GET uses (pc - (lim - p)), and lim was adjusted for (-4) before. + */ + pc += 4; +#endif + BR_PC_INIT + goto start; + + for (;; mask |= 4) + { + // cont: mask |= 4; + start: + if (p >= lim) + goto fin; + { + BR86_PREPARE_BCJ_SCAN + p += 4; + if (BR86_IS_BCJ_BYTE(0)) { goto m0; } mask >>= 1; + if (BR86_IS_BCJ_BYTE(1)) { goto m1; } mask >>= 1; + if (BR86_IS_BCJ_BYTE(2)) { goto m2; } mask = 0; + if (BR86_IS_BCJ_BYTE(3)) { goto a3; } + } + goto main_loop; + + m0: p--; + m1: p--; + m2: p--; + if (mask == 0) + goto a3; + if (p > lim) + goto fin_p; + + // if (((0x17u >> mask) & 1) == 0) + if (mask > 4 || mask == 3) + { + mask >>= 1; + continue; // goto cont; + } + mask >>= 1; + if (BR86_NEED_CONV_FOR_MS_BYTE(p[mask])) + continue; // goto cont; + // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont; + { + UInt32 v = GetUi32(p); + UInt32 c; + v += (1 << 24); if (v & 0xfe000000) continue; // goto cont; + c = BR_PC_GET; + BR_CONVERT_VAL(v, c) + { + mask <<= 3; + if (BR86_NEED_CONV_FOR_MS_BYTE(v >> mask)) + { + v ^= (((UInt32)0x100 << mask) - 1); + #ifdef MY_CPU_X86 + // for X86 : we can recalculate (c) to reduce register pressure + c = BR_PC_GET; + #endif + BR_CONVERT_VAL(v, c) + } + mask = 0; + } + // v = (v & ((1 << 24) - 1)) - (v & (1 << 24)); + v &= (1 << 25) - 1; v -= (1 << 24); + SetUi32(p, v) + p += 4; + goto main_loop; + } + + main_loop: + if (p >= lim) + goto fin; + for (;;) + { + BR86_PREPARE_BCJ_SCAN + p += 4; + if (BR86_IS_BCJ_BYTE(0)) { goto a0; } + if (BR86_IS_BCJ_BYTE(1)) { goto a1; } + if (BR86_IS_BCJ_BYTE(2)) { goto a2; } + if (BR86_IS_BCJ_BYTE(3)) { goto a3; } + if (p >= lim) + goto fin; + } + + a0: p--; + a1: p--; + a2: p--; + a3: + if (p > lim) + goto fin_p; + // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont; + { + UInt32 v = GetUi32(p); + UInt32 c; + v += (1 << 24); if (v & 0xfe000000) continue; // goto cont; + c = BR_PC_GET; + BR_CONVERT_VAL(v, c) + // v = (v & ((1 << 24) - 1)) - (v & (1 << 24)); + v &= (1 << 25) - 1; v -= (1 << 24); + SetUi32(p, v) + p += 4; + goto main_loop; + } + } + +fin_p: + p--; +fin: + // the following processing for tail is optional and can be commented + /* + lim += 4; + for (; p < lim; p++, mask >>= 1) + if ((*p & 0xfe) == 0xe8) + break; + */ + *state = (UInt32)mask; + return p; + } +} + + +#define Z7_BRANCH_CONV_ST_FUNC_IMP(name, m, encoding) \ +Z7_NO_INLINE \ +Z7_ATTRIB_NO_VECTOR \ +Byte *m(name)(Byte *data, SizeT size, UInt32 pc, UInt32 *state) \ + { return Z7_BRANCH_CONV_ST(name)(data, size, pc, state, encoding); } + +Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_DEC, 0) +#ifndef Z7_EXTRACT_ONLY +Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_ENC, 1) +#endif diff --git a/C/BraIA64.c b/C/BraIA64.c index 1b61927cc..9dfe3e289 100644 --- a/C/BraIA64.c +++ b/C/BraIA64.c @@ -1,14 +1,14 @@ -/* BraIA64.c -- Converter for IA-64 code -2023-02-20 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// the code was moved to Bra.c - -#ifdef _MSC_VER -#pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty -#endif - -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Wempty-translation-unit" -#endif +/* BraIA64.c -- Converter for IA-64 code +2023-02-20 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// the code was moved to Bra.c + +#ifdef _MSC_VER +#pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty +#endif + +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wempty-translation-unit" +#endif diff --git a/C/BwtSort.c b/C/BwtSort.c index a6bf08e89..05ad6de8b 100644 --- a/C/BwtSort.c +++ b/C/BwtSort.c @@ -1,516 +1,516 @@ -/* BwtSort.c -- BWT block sorting -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "BwtSort.h" -#include "Sort.h" - -/* #define BLOCK_SORT_USE_HEAP_SORT */ - -/* Don't change it !!! */ -#define kNumHashBytes 2 -#define kNumHashValues (1 << (kNumHashBytes * 8)) - -/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */ -#define kNumRefBitsMax 12 - -#define BS_TEMP_SIZE kNumHashValues - -#ifdef BLOCK_SORT_EXTERNAL_FLAGS - -/* 32 Flags in UInt32 word */ -#define kNumFlagsBits 5 -#define kNumFlagsInWord (1 << kNumFlagsBits) -#define kFlagsMask (kNumFlagsInWord - 1) -#define kAllFlags 0xFFFFFFFF - -#else - -#define kNumBitsMax 20 -#define kIndexMask ((1 << kNumBitsMax) - 1) -#define kNumExtraBits (32 - kNumBitsMax) -#define kNumExtra0Bits (kNumExtraBits - 2) -#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) - -#define SetFinishedGroupSize(p, size) \ - { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ - if ((size) > (1 << kNumExtra0Bits)) { \ - *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \ - -static void SetGroupSize(UInt32 *p, UInt32 size) -{ - if (--size == 0) - return; - *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax); - if (size >= (1 << kNumExtra0Bits)) - { - *p |= 0x40000000; - p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax); - } -} - -#endif - -/* -SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks - "range" is not real range. It's only for optimization. -returns: 1 - if there are groups, 0 - no more groups -*/ - -static -UInt32 -Z7_FASTCALL -SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices - #ifndef BLOCK_SORT_USE_HEAP_SORT - , UInt32 left, UInt32 range - #endif - ) -{ - UInt32 *ind2 = Indices + groupOffset; - UInt32 *Groups; - if (groupSize <= 1) - { - /* - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetFinishedGroupSize(ind2, 1) - #endif - */ - return 0; - } - Groups = Indices + BlockSize + BS_TEMP_SIZE; - if (groupSize <= ((UInt32)1 << NumRefBits) - #ifndef BLOCK_SORT_USE_HEAP_SORT - && groupSize <= range - #endif - ) - { - UInt32 *temp = Indices + BlockSize; - UInt32 j; - UInt32 mask, thereAreGroups, group, cg; - { - UInt32 gPrev; - UInt32 gRes = 0; - { - UInt32 sp = ind2[0] + NumSortedBytes; - if (sp >= BlockSize) sp -= BlockSize; - gPrev = Groups[sp]; - temp[0] = (gPrev << NumRefBits); - } - - for (j = 1; j < groupSize; j++) - { - UInt32 sp = ind2[j] + NumSortedBytes; - UInt32 g; - if (sp >= BlockSize) sp -= BlockSize; - g = Groups[sp]; - temp[j] = (g << NumRefBits) | j; - gRes |= (gPrev ^ g); - } - if (gRes == 0) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2, groupSize); - #endif - return 1; - } - } - - HeapSort(temp, groupSize); - mask = (((UInt32)1 << NumRefBits) - 1); - thereAreGroups = 0; - - group = groupOffset; - cg = (temp[0] >> NumRefBits); - temp[0] = ind2[temp[0] & mask]; - - { - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 *Flags = Groups + BlockSize; - #else - UInt32 prevGroupStart = 0; - #endif - - for (j = 1; j < groupSize; j++) - { - UInt32 val = temp[j]; - UInt32 cgCur = (val >> NumRefBits); - - if (cgCur != cg) - { - cg = cgCur; - group = groupOffset + j; - - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 t = group - 1; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - } - #else - SetGroupSize(temp + prevGroupStart, j - prevGroupStart); - prevGroupStart = j; - #endif - } - else - thereAreGroups = 1; - { - UInt32 ind = ind2[val & mask]; - temp[j] = ind; - Groups[ind] = group; - } - } - - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(temp + prevGroupStart, j - prevGroupStart); - #endif - } - - for (j = 0; j < groupSize; j++) - ind2[j] = temp[j]; - return thereAreGroups; - } - - /* Check that all strings are in one group (cannot sort) */ - { - UInt32 group, j; - UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - group = Groups[sp]; - for (j = 1; j < groupSize; j++) - { - sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - if (Groups[sp] != group) - break; - } - if (j == groupSize) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2, groupSize); - #endif - return 1; - } - } - - #ifndef BLOCK_SORT_USE_HEAP_SORT - { - /* ---------- Range Sort ---------- */ - UInt32 i; - UInt32 mid; - for (;;) - { - UInt32 j; - if (range <= 1) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2, groupSize); - #endif - return 1; - } - mid = left + ((range + 1) >> 1); - j = groupSize; - i = 0; - do - { - UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - if (Groups[sp] >= mid) - { - for (j--; j > i; j--) - { - sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - if (Groups[sp] < mid) - { - UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp; - break; - } - } - if (i >= j) - break; - } - } - while (++i < j); - if (i == 0) - { - range = range - (mid - left); - left = mid; - } - else if (i == groupSize) - range = (mid - left); - else - break; - } - - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 t = (groupOffset + i - 1); - UInt32 *Flags = Groups + BlockSize; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - } - #endif - - { - UInt32 j; - for (j = i; j < groupSize; j++) - Groups[ind2[j]] = groupOffset + i; - } - - { - UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); - return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); - } - - } - - #else - - /* ---------- Heap Sort ---------- */ - - { - UInt32 j; - for (j = 0; j < groupSize; j++) - { - UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; - ind2[j] = sp; - } - - HeapSortRef(ind2, Groups, groupSize); - - /* Write Flags */ - { - UInt32 sp = ind2[0]; - UInt32 group = Groups[sp]; - - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 *Flags = Groups + BlockSize; - #else - UInt32 prevGroupStart = 0; - #endif - - for (j = 1; j < groupSize; j++) - { - sp = ind2[j]; - if (Groups[sp] != group) - { - group = Groups[sp]; - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 t = groupOffset + j - 1; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - } - #else - SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); - prevGroupStart = j; - #endif - } - } - - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); - #endif - } - { - /* Write new Groups values and Check that there are groups */ - UInt32 thereAreGroups = 0; - for (j = 0; j < groupSize; j++) - { - UInt32 group = groupOffset + j; - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); - if ((ind2[j] & 0x40000000) != 0) - subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits); - subGroupSize++; - for (;;) - { - UInt32 original = ind2[j]; - UInt32 sp = original & kIndexMask; - if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; - ind2[j] = sp | (original & ~kIndexMask); - Groups[sp] = group; - if (--subGroupSize == 0) - break; - j++; - thereAreGroups = 1; - } - #else - UInt32 *Flags = Groups + BlockSize; - for (;;) - { - UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; - ind2[j] = sp; - Groups[sp] = group; - if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0) - break; - j++; - thereAreGroups = 1; - } - #endif - } - return thereAreGroups; - } - } - #endif -} - -/* conditions: blockSize > 0 */ -UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize) -{ - UInt32 *counters = Indices + blockSize; - UInt32 i; - UInt32 *Groups; - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 *Flags; - #endif - - /* Radix-Sort for 2 bytes */ - for (i = 0; i < kNumHashValues; i++) - counters[i] = 0; - for (i = 0; i < blockSize - 1; i++) - counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++; - counters[((UInt32)data[i] << 8) | data[0]]++; - - Groups = counters + BS_TEMP_SIZE; - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - Flags = Groups + blockSize; - { - UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits; - for (i = 0; i < numWords; i++) - Flags[i] = kAllFlags; - } - #endif - - { - UInt32 sum = 0; - for (i = 0; i < kNumHashValues; i++) - { - UInt32 groupSize = counters[i]; - if (groupSize > 0) - { - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 t = sum + groupSize - 1; - Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); - #endif - sum += groupSize; - } - counters[i] = sum - groupSize; - } - - for (i = 0; i < blockSize - 1; i++) - Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]; - Groups[i] = counters[((UInt32)data[i] << 8) | data[0]]; - - for (i = 0; i < blockSize - 1; i++) - Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i; - Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i; - - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - { - UInt32 prev = 0; - for (i = 0; i < kNumHashValues; i++) - { - UInt32 prevGroupSize = counters[i] - prev; - if (prevGroupSize == 0) - continue; - SetGroupSize(Indices + prev, prevGroupSize); - prev = counters[i]; - } - } - #endif - } - - { - int NumRefBits; - UInt32 NumSortedBytes; - for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++); - NumRefBits = 32 - NumRefBits; - if (NumRefBits > kNumRefBitsMax) - NumRefBits = kNumRefBitsMax; - - for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1) - { - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - UInt32 finishedGroupSize = 0; - #endif - UInt32 newLimit = 0; - for (i = 0; i < blockSize;) - { - UInt32 groupSize; - #ifdef BLOCK_SORT_EXTERNAL_FLAGS - - if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0) - { - i++; - continue; - } - for (groupSize = 1; - (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0; - groupSize++); - - groupSize++; - - #else - - groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); - { - BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); - if ((Indices[i] & 0x40000000) != 0) - { - groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); - Indices[(size_t)i + 1] &= kIndexMask; - } - Indices[i] &= kIndexMask; - groupSize++; - if (finishedGroup || groupSize == 1) - { - Indices[i - finishedGroupSize] &= kIndexMask; - if (finishedGroupSize > 1) - Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask; - { - UInt32 newGroupSize = groupSize + finishedGroupSize; - SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize) - finishedGroupSize = newGroupSize; - } - i += groupSize; - continue; - } - finishedGroupSize = 0; - } - - #endif - - if (NumSortedBytes >= blockSize) - { - UInt32 j; - for (j = 0; j < groupSize; j++) - { - UInt32 t = (i + j); - /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */ - Groups[Indices[t]] = t; - } - } - else - if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices - #ifndef BLOCK_SORT_USE_HEAP_SORT - , 0, blockSize - #endif - ) != 0) - newLimit = i + groupSize; - i += groupSize; - } - if (newLimit == 0) - break; - } - } - #ifndef BLOCK_SORT_EXTERNAL_FLAGS - for (i = 0; i < blockSize;) - { - UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); - if ((Indices[i] & 0x40000000) != 0) - { - groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); - Indices[(size_t)i + 1] &= kIndexMask; - } - Indices[i] &= kIndexMask; - groupSize++; - i += groupSize; - } - #endif - return Groups[0]; -} +/* BwtSort.c -- BWT block sorting +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "BwtSort.h" +#include "Sort.h" + +/* #define BLOCK_SORT_USE_HEAP_SORT */ + +/* Don't change it !!! */ +#define kNumHashBytes 2 +#define kNumHashValues (1 << (kNumHashBytes * 8)) + +/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */ +#define kNumRefBitsMax 12 + +#define BS_TEMP_SIZE kNumHashValues + +#ifdef BLOCK_SORT_EXTERNAL_FLAGS + +/* 32 Flags in UInt32 word */ +#define kNumFlagsBits 5 +#define kNumFlagsInWord (1 << kNumFlagsBits) +#define kFlagsMask (kNumFlagsInWord - 1) +#define kAllFlags 0xFFFFFFFF + +#else + +#define kNumBitsMax 20 +#define kIndexMask ((1 << kNumBitsMax) - 1) +#define kNumExtraBits (32 - kNumBitsMax) +#define kNumExtra0Bits (kNumExtraBits - 2) +#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1) + +#define SetFinishedGroupSize(p, size) \ + { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \ + if ((size) > (1 << kNumExtra0Bits)) { \ + *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \ + +static void SetGroupSize(UInt32 *p, UInt32 size) +{ + if (--size == 0) + return; + *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax); + if (size >= (1 << kNumExtra0Bits)) + { + *p |= 0x40000000; + p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax); + } +} + +#endif + +/* +SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks + "range" is not real range. It's only for optimization. +returns: 1 - if there are groups, 0 - no more groups +*/ + +static +UInt32 +Z7_FASTCALL +SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices + #ifndef BLOCK_SORT_USE_HEAP_SORT + , UInt32 left, UInt32 range + #endif + ) +{ + UInt32 *ind2 = Indices + groupOffset; + UInt32 *Groups; + if (groupSize <= 1) + { + /* + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetFinishedGroupSize(ind2, 1) + #endif + */ + return 0; + } + Groups = Indices + BlockSize + BS_TEMP_SIZE; + if (groupSize <= ((UInt32)1 << NumRefBits) + #ifndef BLOCK_SORT_USE_HEAP_SORT + && groupSize <= range + #endif + ) + { + UInt32 *temp = Indices + BlockSize; + UInt32 j; + UInt32 mask, thereAreGroups, group, cg; + { + UInt32 gPrev; + UInt32 gRes = 0; + { + UInt32 sp = ind2[0] + NumSortedBytes; + if (sp >= BlockSize) sp -= BlockSize; + gPrev = Groups[sp]; + temp[0] = (gPrev << NumRefBits); + } + + for (j = 1; j < groupSize; j++) + { + UInt32 sp = ind2[j] + NumSortedBytes; + UInt32 g; + if (sp >= BlockSize) sp -= BlockSize; + g = Groups[sp]; + temp[j] = (g << NumRefBits) | j; + gRes |= (gPrev ^ g); + } + if (gRes == 0) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2, groupSize); + #endif + return 1; + } + } + + HeapSort(temp, groupSize); + mask = (((UInt32)1 << NumRefBits) - 1); + thereAreGroups = 0; + + group = groupOffset; + cg = (temp[0] >> NumRefBits); + temp[0] = ind2[temp[0] & mask]; + + { + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 *Flags = Groups + BlockSize; + #else + UInt32 prevGroupStart = 0; + #endif + + for (j = 1; j < groupSize; j++) + { + UInt32 val = temp[j]; + UInt32 cgCur = (val >> NumRefBits); + + if (cgCur != cg) + { + cg = cgCur; + group = groupOffset + j; + + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 t = group - 1; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + } + #else + SetGroupSize(temp + prevGroupStart, j - prevGroupStart); + prevGroupStart = j; + #endif + } + else + thereAreGroups = 1; + { + UInt32 ind = ind2[val & mask]; + temp[j] = ind; + Groups[ind] = group; + } + } + + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(temp + prevGroupStart, j - prevGroupStart); + #endif + } + + for (j = 0; j < groupSize; j++) + ind2[j] = temp[j]; + return thereAreGroups; + } + + /* Check that all strings are in one group (cannot sort) */ + { + UInt32 group, j; + UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + group = Groups[sp]; + for (j = 1; j < groupSize; j++) + { + sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + if (Groups[sp] != group) + break; + } + if (j == groupSize) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2, groupSize); + #endif + return 1; + } + } + + #ifndef BLOCK_SORT_USE_HEAP_SORT + { + /* ---------- Range Sort ---------- */ + UInt32 i; + UInt32 mid; + for (;;) + { + UInt32 j; + if (range <= 1) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2, groupSize); + #endif + return 1; + } + mid = left + ((range + 1) >> 1); + j = groupSize; + i = 0; + do + { + UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + if (Groups[sp] >= mid) + { + for (j--; j > i; j--) + { + sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + if (Groups[sp] < mid) + { + UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp; + break; + } + } + if (i >= j) + break; + } + } + while (++i < j); + if (i == 0) + { + range = range - (mid - left); + left = mid; + } + else if (i == groupSize) + range = (mid - left); + else + break; + } + + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 t = (groupOffset + i - 1); + UInt32 *Flags = Groups + BlockSize; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + } + #endif + + { + UInt32 j; + for (j = i; j < groupSize; j++) + Groups[ind2[j]] = groupOffset + i; + } + + { + UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left); + return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left)); + } + + } + + #else + + /* ---------- Heap Sort ---------- */ + + { + UInt32 j; + for (j = 0; j < groupSize; j++) + { + UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize; + ind2[j] = sp; + } + + HeapSortRef(ind2, Groups, groupSize); + + /* Write Flags */ + { + UInt32 sp = ind2[0]; + UInt32 group = Groups[sp]; + + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 *Flags = Groups + BlockSize; + #else + UInt32 prevGroupStart = 0; + #endif + + for (j = 1; j < groupSize; j++) + { + sp = ind2[j]; + if (Groups[sp] != group) + { + group = Groups[sp]; + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 t = groupOffset + j - 1; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + } + #else + SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); + prevGroupStart = j; + #endif + } + } + + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart); + #endif + } + { + /* Write new Groups values and Check that there are groups */ + UInt32 thereAreGroups = 0; + for (j = 0; j < groupSize; j++) + { + UInt32 group = groupOffset + j; + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax); + if ((ind2[j] & 0x40000000) != 0) + subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits); + subGroupSize++; + for (;;) + { + UInt32 original = ind2[j]; + UInt32 sp = original & kIndexMask; + if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; + ind2[j] = sp | (original & ~kIndexMask); + Groups[sp] = group; + if (--subGroupSize == 0) + break; + j++; + thereAreGroups = 1; + } + #else + UInt32 *Flags = Groups + BlockSize; + for (;;) + { + UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes; + ind2[j] = sp; + Groups[sp] = group; + if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0) + break; + j++; + thereAreGroups = 1; + } + #endif + } + return thereAreGroups; + } + } + #endif +} + +/* conditions: blockSize > 0 */ +UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize) +{ + UInt32 *counters = Indices + blockSize; + UInt32 i; + UInt32 *Groups; + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 *Flags; + #endif + + /* Radix-Sort for 2 bytes */ + for (i = 0; i < kNumHashValues; i++) + counters[i] = 0; + for (i = 0; i < blockSize - 1; i++) + counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++; + counters[((UInt32)data[i] << 8) | data[0]]++; + + Groups = counters + BS_TEMP_SIZE; + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + Flags = Groups + blockSize; + { + UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits; + for (i = 0; i < numWords; i++) + Flags[i] = kAllFlags; + } + #endif + + { + UInt32 sum = 0; + for (i = 0; i < kNumHashValues; i++) + { + UInt32 groupSize = counters[i]; + if (groupSize > 0) + { + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 t = sum + groupSize - 1; + Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); + #endif + sum += groupSize; + } + counters[i] = sum - groupSize; + } + + for (i = 0; i < blockSize - 1; i++) + Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]; + Groups[i] = counters[((UInt32)data[i] << 8) | data[0]]; + + for (i = 0; i < blockSize - 1; i++) + Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i; + Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i; + + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + { + UInt32 prev = 0; + for (i = 0; i < kNumHashValues; i++) + { + UInt32 prevGroupSize = counters[i] - prev; + if (prevGroupSize == 0) + continue; + SetGroupSize(Indices + prev, prevGroupSize); + prev = counters[i]; + } + } + #endif + } + + { + int NumRefBits; + UInt32 NumSortedBytes; + for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++); + NumRefBits = 32 - NumRefBits; + if (NumRefBits > kNumRefBitsMax) + NumRefBits = kNumRefBitsMax; + + for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1) + { + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + UInt32 finishedGroupSize = 0; + #endif + UInt32 newLimit = 0; + for (i = 0; i < blockSize;) + { + UInt32 groupSize; + #ifdef BLOCK_SORT_EXTERNAL_FLAGS + + if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0) + { + i++; + continue; + } + for (groupSize = 1; + (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0; + groupSize++); + + groupSize++; + + #else + + groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); + { + BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); + if ((Indices[i] & 0x40000000) != 0) + { + groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); + Indices[(size_t)i + 1] &= kIndexMask; + } + Indices[i] &= kIndexMask; + groupSize++; + if (finishedGroup || groupSize == 1) + { + Indices[i - finishedGroupSize] &= kIndexMask; + if (finishedGroupSize > 1) + Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask; + { + UInt32 newGroupSize = groupSize + finishedGroupSize; + SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize) + finishedGroupSize = newGroupSize; + } + i += groupSize; + continue; + } + finishedGroupSize = 0; + } + + #endif + + if (NumSortedBytes >= blockSize) + { + UInt32 j; + for (j = 0; j < groupSize; j++) + { + UInt32 t = (i + j); + /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */ + Groups[Indices[t]] = t; + } + } + else + if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices + #ifndef BLOCK_SORT_USE_HEAP_SORT + , 0, blockSize + #endif + ) != 0) + newLimit = i + groupSize; + i += groupSize; + } + if (newLimit == 0) + break; + } + } + #ifndef BLOCK_SORT_EXTERNAL_FLAGS + for (i = 0; i < blockSize;) + { + UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax); + if ((Indices[i] & 0x40000000) != 0) + { + groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); + Indices[(size_t)i + 1] &= kIndexMask; + } + Indices[i] &= kIndexMask; + groupSize++; + i += groupSize; + } + #endif + return Groups[0]; +} diff --git a/C/BwtSort.h b/C/BwtSort.h index 3a57f6794..a34b243a3 100644 --- a/C/BwtSort.h +++ b/C/BwtSort.h @@ -1,26 +1,26 @@ -/* BwtSort.h -- BWT block sorting -2023-03-03 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_BWT_SORT_H -#define ZIP7_INC_BWT_SORT_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */ -/* #define BLOCK_SORT_EXTERNAL_FLAGS */ - -#ifdef BLOCK_SORT_EXTERNAL_FLAGS -#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5)) -#else -#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0 -#endif - -#define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16)) - -UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize); - -EXTERN_C_END - -#endif +/* BwtSort.h -- BWT block sorting +2023-03-03 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_BWT_SORT_H +#define ZIP7_INC_BWT_SORT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */ +/* #define BLOCK_SORT_EXTERNAL_FLAGS */ + +#ifdef BLOCK_SORT_EXTERNAL_FLAGS +#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5)) +#else +#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0 +#endif + +#define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16)) + +UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize); + +EXTERN_C_END + +#endif diff --git a/C/Compiler.h b/C/Compiler.h index 6f8db4ca2..2a9c2b7a0 100644 --- a/C/Compiler.h +++ b/C/Compiler.h @@ -1,236 +1,236 @@ -/* Compiler.h : Compiler specific defines and pragmas -2024-01-22 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_COMPILER_H -#define ZIP7_INC_COMPILER_H - -#if defined(__clang__) -# define Z7_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) -#endif -#if defined(__clang__) && defined(__apple_build_version__) -# define Z7_APPLE_CLANG_VERSION Z7_CLANG_VERSION -#elif defined(__clang__) -# define Z7_LLVM_CLANG_VERSION Z7_CLANG_VERSION -#elif defined(__GNUC__) -# define Z7_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#endif - -#ifdef _MSC_VER -#if !defined(__clang__) && !defined(__GNUC__) -#define Z7_MSC_VER_ORIGINAL _MSC_VER -#endif -#endif - -#if defined(__MINGW32__) || defined(__MINGW64__) -#define Z7_MINGW -#endif - -#if defined(__LCC__) && (defined(__MCST__) || defined(__e2k__)) -#define Z7_MCST_LCC -#define Z7_MCST_LCC_VERSION (__LCC__ * 100 + __LCC_MINOR__) -#endif - -/* -#if defined(__AVX2__) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ - || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ - || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) - #define Z7_COMPILER_AVX2_SUPPORTED - #endif -#endif -*/ - -// #pragma GCC diagnostic ignored "-Wunknown-pragmas" - -#ifdef __clang__ -// padding size of '' with 4 bytes to alignment boundary -#pragma GCC diagnostic ignored "-Wpadded" - -#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \ - && defined(__FreeBSD__) -// freebsd: -#pragma GCC diagnostic ignored "-Wexcess-padding" -#endif - -#if __clang_major__ >= 16 -#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" -#endif - -#if __clang_major__ == 13 -#if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) -// cheri -#pragma GCC diagnostic ignored "-Wcapability-to-integer-cast" -#endif -#endif - -#if __clang_major__ == 13 - // for - #pragma GCC diagnostic ignored "-Wreserved-identifier" -#endif - -#endif // __clang__ - -#if defined(_WIN32) && defined(__clang__) && __clang_major__ >= 16 -// #pragma GCC diagnostic ignored "-Wcast-function-type-strict" -#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION \ - _Pragma("GCC diagnostic ignored \"-Wcast-function-type-strict\"") -#else -#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -#endif - -typedef void (*Z7_void_Function)(void); -#if defined(__clang__) || defined(__GNUC__) -#define Z7_CAST_FUNC_C (Z7_void_Function) -#elif defined(_MSC_VER) && _MSC_VER > 1920 -#define Z7_CAST_FUNC_C (void *) -// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()' -#else -#define Z7_CAST_FUNC_C -#endif -/* -#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__) - // #pragma GCC diagnostic ignored "-Wcast-function-type" -#endif -*/ -#ifdef __GNUC__ -#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40000) && (Z7_GCC_VERSION < 70000) -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif -#endif - - -#ifdef _MSC_VER - - #ifdef UNDER_CE - #define RPC_NO_WINDOWS_H - /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ - #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union - #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int - #endif - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -// == 1200 : -O1 : for __forceinline -// >= 1900 : -O1 : for printf -#pragma warning(disable : 4710) // function not inlined - -#if _MSC_VER < 1900 -// winnt.h: 'Int64ShllMod32' -#pragma warning(disable : 4514) // unreferenced inline function has been removed -#endif - -#if _MSC_VER < 1300 -// #pragma warning(disable : 4702) // unreachable code -// Bra.c : -O1: -#pragma warning(disable : 4714) // function marked as __forceinline not inlined -#endif - -/* -#if _MSC_VER > 1400 && _MSC_VER <= 1900 -// strcat: This function or variable may be unsafe -// sysinfoapi.h: kit10: GetVersion was declared deprecated -#pragma warning(disable : 4996) -#endif -*/ - -#if _MSC_VER > 1200 -// -Wall warnings - -#pragma warning(disable : 4711) // function selected for automatic inline expansion -#pragma warning(disable : 4820) // '2' bytes padding added after data member - -#if _MSC_VER >= 1400 && _MSC_VER < 1920 -// 1400: string.h: _DBG_MEMCPY_INLINE_ -// 1600 - 191x : smmintrin.h __cplusplus' -// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' -#pragma warning(disable : 4668) - -// 1400 - 1600 : WinDef.h : 'FARPROC' : -// 1900 - 191x : immintrin.h: _readfsbase_u32 -// no function prototype given : converting '()' to '(void)' -#pragma warning(disable : 4255) -#endif - -#if _MSC_VER >= 1914 -// Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified -#pragma warning(disable : 5045) -#endif - -#endif // _MSC_VER > 1200 -#endif // _MSC_VER - - -#if defined(__clang__) && (__clang_major__ >= 4) - #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ - _Pragma("clang loop unroll(disable)") \ - _Pragma("clang loop vectorize(disable)") - #define Z7_ATTRIB_NO_VECTORIZE -#elif defined(__GNUC__) && (__GNUC__ >= 5) \ - && (!defined(Z7_MCST_LCC_VERSION) || (Z7_MCST_LCC_VERSION >= 12610)) - #define Z7_ATTRIB_NO_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) - // __attribute__((optimize("no-unroll-loops"))); - #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE -#elif defined(_MSC_VER) && (_MSC_VER >= 1920) - #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ - _Pragma("loop( no_vector )") - #define Z7_ATTRIB_NO_VECTORIZE -#else - #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - #define Z7_ATTRIB_NO_VECTORIZE -#endif - -#if defined(MY_CPU_X86_OR_AMD64) && ( \ - defined(__clang__) && (__clang_major__ >= 4) \ - || defined(__GNUC__) && (__GNUC__ >= 5)) - #define Z7_ATTRIB_NO_SSE __attribute__((__target__("no-sse"))) -#else - #define Z7_ATTRIB_NO_SSE -#endif - -#define Z7_ATTRIB_NO_VECTOR \ - Z7_ATTRIB_NO_VECTORIZE \ - Z7_ATTRIB_NO_SSE - - -#if defined(__clang__) && (__clang_major__ >= 8) \ - || defined(__GNUC__) && (__GNUC__ >= 1000) \ - /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ - // GCC is not good for __builtin_expect() - #define Z7_LIKELY(x) (__builtin_expect((x), 1)) - #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) - // #define Z7_unlikely [[unlikely]] - // #define Z7_likely [[likely]] -#else - #define Z7_LIKELY(x) (x) - #define Z7_UNLIKELY(x) (x) - // #define Z7_likely -#endif - - -#if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30600)) - -#if (Z7_CLANG_VERSION < 130000) -#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wreserved-id-macro\"") -#else -#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"") -#endif - -#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \ - _Pragma("GCC diagnostic pop") -#else -#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif - -#define UNUSED_VAR(x) (void)x; -/* #define UNUSED_VAR(x) x=x; */ - -#endif +/* Compiler.h : Compiler specific defines and pragmas +2024-01-22 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_COMPILER_H +#define ZIP7_INC_COMPILER_H + +#if defined(__clang__) +# define Z7_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif +#if defined(__clang__) && defined(__apple_build_version__) +# define Z7_APPLE_CLANG_VERSION Z7_CLANG_VERSION +#elif defined(__clang__) +# define Z7_LLVM_CLANG_VERSION Z7_CLANG_VERSION +#elif defined(__GNUC__) +# define Z7_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#ifdef _MSC_VER +#if !defined(__clang__) && !defined(__GNUC__) +#define Z7_MSC_VER_ORIGINAL _MSC_VER +#endif +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +#define Z7_MINGW +#endif + +#if defined(__LCC__) && (defined(__MCST__) || defined(__e2k__)) +#define Z7_MCST_LCC +#define Z7_MCST_LCC_VERSION (__LCC__ * 100 + __LCC_MINOR__) +#endif + +/* +#if defined(__AVX2__) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ + || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) + #define Z7_COMPILER_AVX2_SUPPORTED + #endif +#endif +*/ + +// #pragma GCC diagnostic ignored "-Wunknown-pragmas" + +#ifdef __clang__ +// padding size of '' with 4 bytes to alignment boundary +#pragma GCC diagnostic ignored "-Wpadded" + +#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \ + && defined(__FreeBSD__) +// freebsd: +#pragma GCC diagnostic ignored "-Wexcess-padding" +#endif + +#if __clang_major__ >= 16 +#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" +#endif + +#if __clang_major__ == 13 +#if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) +// cheri +#pragma GCC diagnostic ignored "-Wcapability-to-integer-cast" +#endif +#endif + +#if __clang_major__ == 13 + // for + #pragma GCC diagnostic ignored "-Wreserved-identifier" +#endif + +#endif // __clang__ + +#if defined(_WIN32) && defined(__clang__) && __clang_major__ >= 16 +// #pragma GCC diagnostic ignored "-Wcast-function-type-strict" +#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION \ + _Pragma("GCC diagnostic ignored \"-Wcast-function-type-strict\"") +#else +#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +#endif + +typedef void (*Z7_void_Function)(void); +#if defined(__clang__) || defined(__GNUC__) +#define Z7_CAST_FUNC_C (Z7_void_Function) +#elif defined(_MSC_VER) && _MSC_VER > 1920 +#define Z7_CAST_FUNC_C (void *) +// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()' +#else +#define Z7_CAST_FUNC_C +#endif +/* +#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__) + // #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif +*/ +#ifdef __GNUC__ +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40000) && (Z7_GCC_VERSION < 70000) +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif +#endif + + +#ifdef _MSC_VER + + #ifdef UNDER_CE + #define RPC_NO_WINDOWS_H + /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ + #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int + #endif + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +// == 1200 : -O1 : for __forceinline +// >= 1900 : -O1 : for printf +#pragma warning(disable : 4710) // function not inlined + +#if _MSC_VER < 1900 +// winnt.h: 'Int64ShllMod32' +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif + +#if _MSC_VER < 1300 +// #pragma warning(disable : 4702) // unreachable code +// Bra.c : -O1: +#pragma warning(disable : 4714) // function marked as __forceinline not inlined +#endif + +/* +#if _MSC_VER > 1400 && _MSC_VER <= 1900 +// strcat: This function or variable may be unsafe +// sysinfoapi.h: kit10: GetVersion was declared deprecated +#pragma warning(disable : 4996) +#endif +*/ + +#if _MSC_VER > 1200 +// -Wall warnings + +#pragma warning(disable : 4711) // function selected for automatic inline expansion +#pragma warning(disable : 4820) // '2' bytes padding added after data member + +#if _MSC_VER >= 1400 && _MSC_VER < 1920 +// 1400: string.h: _DBG_MEMCPY_INLINE_ +// 1600 - 191x : smmintrin.h __cplusplus' +// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +#pragma warning(disable : 4668) + +// 1400 - 1600 : WinDef.h : 'FARPROC' : +// 1900 - 191x : immintrin.h: _readfsbase_u32 +// no function prototype given : converting '()' to '(void)' +#pragma warning(disable : 4255) +#endif + +#if _MSC_VER >= 1914 +// Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#pragma warning(disable : 5045) +#endif + +#endif // _MSC_VER > 1200 +#endif // _MSC_VER + + +#if defined(__clang__) && (__clang_major__ >= 4) + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + _Pragma("clang loop unroll(disable)") \ + _Pragma("clang loop vectorize(disable)") + #define Z7_ATTRIB_NO_VECTORIZE +#elif defined(__GNUC__) && (__GNUC__ >= 5) \ + && (!defined(Z7_MCST_LCC_VERSION) || (Z7_MCST_LCC_VERSION >= 12610)) + #define Z7_ATTRIB_NO_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) + // __attribute__((optimize("no-unroll-loops"))); + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE +#elif defined(_MSC_VER) && (_MSC_VER >= 1920) + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + _Pragma("loop( no_vector )") + #define Z7_ATTRIB_NO_VECTORIZE +#else + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + #define Z7_ATTRIB_NO_VECTORIZE +#endif + +#if defined(MY_CPU_X86_OR_AMD64) && ( \ + defined(__clang__) && (__clang_major__ >= 4) \ + || defined(__GNUC__) && (__GNUC__ >= 5)) + #define Z7_ATTRIB_NO_SSE __attribute__((__target__("no-sse"))) +#else + #define Z7_ATTRIB_NO_SSE +#endif + +#define Z7_ATTRIB_NO_VECTOR \ + Z7_ATTRIB_NO_VECTORIZE \ + Z7_ATTRIB_NO_SSE + + +#if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 1000) \ + /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ + // GCC is not good for __builtin_expect() + #define Z7_LIKELY(x) (__builtin_expect((x), 1)) + #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) + // #define Z7_unlikely [[unlikely]] + // #define Z7_likely [[likely]] +#else + #define Z7_LIKELY(x) (x) + #define Z7_UNLIKELY(x) (x) + // #define Z7_likely +#endif + + +#if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30600)) + +#if (Z7_CLANG_VERSION < 130000) +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wreserved-id-macro\"") +#else +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"") +#endif + +#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic pop") +#else +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ + +#endif diff --git a/C/CpuArch.c b/C/CpuArch.c index 1ddbd33b7..6e02551e2 100644 --- a/C/CpuArch.c +++ b/C/CpuArch.c @@ -1,889 +1,970 @@ -/* CpuArch.c -- CPU specific code -2024-07-04 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #include - -#include "CpuArch.h" - -#ifdef MY_CPU_X86_OR_AMD64 - -#undef NEED_CHECK_FOR_CPUID -#if !defined(MY_CPU_AMD64) -#define NEED_CHECK_FOR_CPUID -#endif - -/* - cpuid instruction supports (subFunction) parameter in ECX, - that is used only with some specific (function) parameter values. - But we always use only (subFunction==0). -*/ -/* - __cpuid(): MSVC and GCC/CLANG use same function/macro name - but parameters are different. - We use MSVC __cpuid() parameters style for our z7_x86_cpuid() function. -*/ - -#if defined(__GNUC__) /* && (__GNUC__ >= 10) */ \ - || defined(__clang__) /* && (__clang_major__ >= 10) */ - -/* there was some CLANG/GCC compilers that have issues with - rbx(ebx) handling in asm blocks in -fPIC mode (__PIC__ is defined). - compiler's contains the macro __cpuid() that is similar to our code. - The history of __cpuid() changes in CLANG/GCC: - GCC: - 2007: it preserved ebx for (__PIC__ && __i386__) - 2013: it preserved rbx and ebx for __PIC__ - 2014: it doesn't preserves rbx and ebx anymore - we suppose that (__GNUC__ >= 5) fixed that __PIC__ ebx/rbx problem. - CLANG: - 2014+: it preserves rbx, but only for 64-bit code. No __PIC__ check. - Why CLANG cares about 64-bit mode only, and doesn't care about ebx (in 32-bit)? - Do we need __PIC__ test for CLANG or we must care about rbx even if - __PIC__ is not defined? -*/ - -#define ASM_LN "\n" - -#if defined(MY_CPU_AMD64) && defined(__PIC__) \ - && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__)) - -#define x86_cpuid_MACRO(p, func) { \ - __asm__ __volatile__ ( \ - ASM_LN "mov %%rbx, %q1" \ - ASM_LN "cpuid" \ - ASM_LN "xchg %%rbx, %q1" \ - : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); } - - /* "=&r" selects free register. It can select even rbx, if that register is free. - "=&D" for (RDI) also works, but the code can be larger with "=&D" - "2"(0) means (subFunction = 0), - 2 is (zero-based) index in the output constraint list "=c" (ECX). */ - -#elif defined(MY_CPU_X86) && defined(__PIC__) \ - && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__)) - -#define x86_cpuid_MACRO(p, func) { \ - __asm__ __volatile__ ( \ - ASM_LN "mov %%ebx, %k1" \ - ASM_LN "cpuid" \ - ASM_LN "xchg %%ebx, %k1" \ - : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); } - -#else - -#define x86_cpuid_MACRO(p, func) { \ - __asm__ __volatile__ ( \ - ASM_LN "cpuid" \ - : "=a" ((p)[0]), "=b" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); } - -#endif - - -void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) -{ - x86_cpuid_MACRO(p, func) -} - - -Z7_NO_INLINE -UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) -{ - #if defined(NEED_CHECK_FOR_CPUID) - #define EFALGS_CPUID_BIT 21 - UInt32 a; - __asm__ __volatile__ ( - ASM_LN "pushf" - ASM_LN "pushf" - ASM_LN "pop %0" - // ASM_LN "movl %0, %1" - // ASM_LN "xorl $0x200000, %0" - ASM_LN "btc %1, %0" - ASM_LN "push %0" - ASM_LN "popf" - ASM_LN "pushf" - ASM_LN "pop %0" - ASM_LN "xorl (%%esp), %0" - - ASM_LN "popf" - ASM_LN - : "=&r" (a) // "=a" - : "i" (EFALGS_CPUID_BIT) - ); - if ((a & (1 << EFALGS_CPUID_BIT)) == 0) - return 0; - #endif - { - UInt32 p[4]; - x86_cpuid_MACRO(p, 0) - return p[0]; - } -} - -#undef ASM_LN - -#elif !defined(_MSC_VER) - -/* -// for gcc/clang and other: we can try to use __cpuid macro: -#include -void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) -{ - __cpuid(func, p[0], p[1], p[2], p[3]); -} -UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) -{ - return (UInt32)__get_cpuid_max(0, NULL); -} -*/ -// for unsupported cpuid: -void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) -{ - UNUSED_VAR(func) - p[0] = p[1] = p[2] = p[3] = 0; -} -UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) -{ - return 0; -} - -#else // _MSC_VER - -#if !defined(MY_CPU_AMD64) - -UInt32 __declspec(naked) Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) -{ - #if defined(NEED_CHECK_FOR_CPUID) - #define EFALGS_CPUID_BIT 21 - __asm pushfd - __asm pushfd - /* - __asm pop eax - // __asm mov edx, eax - __asm btc eax, EFALGS_CPUID_BIT - __asm push eax - */ - __asm btc dword ptr [esp], EFALGS_CPUID_BIT - __asm popfd - __asm pushfd - __asm pop eax - // __asm xor eax, edx - __asm xor eax, [esp] - // __asm push edx - __asm popfd - __asm and eax, (1 shl EFALGS_CPUID_BIT) - __asm jz end_func - #endif - __asm push ebx - __asm xor eax, eax // func - __asm xor ecx, ecx // subFunction (optional) for (func == 0) - __asm cpuid - __asm pop ebx - #if defined(NEED_CHECK_FOR_CPUID) - end_func: - #endif - __asm ret 0 -} - -void __declspec(naked) Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) -{ - UNUSED_VAR(p) - UNUSED_VAR(func) - __asm push ebx - __asm push edi - __asm mov edi, ecx // p - __asm mov eax, edx // func - __asm xor ecx, ecx // subfunction (optional) for (func == 0) - __asm cpuid - __asm mov [edi ], eax - __asm mov [edi + 4], ebx - __asm mov [edi + 8], ecx - __asm mov [edi + 12], edx - __asm pop edi - __asm pop ebx - __asm ret 0 -} - -#else // MY_CPU_AMD64 - - #if _MSC_VER >= 1600 - #include - #define MY_cpuidex __cpuidex - #else -/* - __cpuid (func == (0 or 7)) requires subfunction number in ECX. - MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction. - __cpuid() in new MSVC clears ECX. - __cpuid() in old MSVC (14.00) x64 doesn't clear ECX - We still can use __cpuid for low (func) values that don't require ECX, - but __cpuid() in old MSVC will be incorrect for some func values: (func == 7). - So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction, - where ECX value is first parameter for FASTCALL / NO_INLINE func, - So the caller of MY_cpuidex_HACK() sets ECX as subFunction, and - old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value. - -DON'T remove Z7_NO_INLINE and Z7_FASTCALL for MY_cpuidex_HACK(): !!! -*/ -static -Z7_NO_INLINE void Z7_FASTCALL MY_cpuidex_HACK(Int32 subFunction, Int32 func, Int32 *CPUInfo) -{ - UNUSED_VAR(subFunction) - __cpuid(CPUInfo, func); -} - #define MY_cpuidex(info, func, func2) MY_cpuidex_HACK(func2, func, info) - #pragma message("======== MY_cpuidex_HACK WAS USED ========") - #endif // _MSC_VER >= 1600 - -#if !defined(MY_CPU_AMD64) -/* inlining for __cpuid() in MSVC x86 (32-bit) produces big ineffective code, - so we disable inlining here */ -Z7_NO_INLINE -#endif -void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) -{ - MY_cpuidex((Int32 *)p, (Int32)func, 0); -} - -Z7_NO_INLINE -UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) -{ - Int32 a[4]; - MY_cpuidex(a, 0, 0); - return a[0]; -} - -#endif // MY_CPU_AMD64 -#endif // _MSC_VER - -#if defined(NEED_CHECK_FOR_CPUID) -#define CHECK_CPUID_IS_SUPPORTED { if (z7_x86_cpuid_GetMaxFunc() == 0) return 0; } -#else -#define CHECK_CPUID_IS_SUPPORTED -#endif -#undef NEED_CHECK_FOR_CPUID - - -static -BoolInt x86cpuid_Func_1(UInt32 *p) -{ - CHECK_CPUID_IS_SUPPORTED - z7_x86_cpuid(p, 1); - return True; -} - -/* -static const UInt32 kVendors[][1] = -{ - { 0x756E6547 }, // , 0x49656E69, 0x6C65746E }, - { 0x68747541 }, // , 0x69746E65, 0x444D4163 }, - { 0x746E6543 } // , 0x48727561, 0x736C7561 } -}; -*/ - -/* -typedef struct -{ - UInt32 maxFunc; - UInt32 vendor[3]; - UInt32 ver; - UInt32 b; - UInt32 c; - UInt32 d; -} Cx86cpuid; - -enum -{ - CPU_FIRM_INTEL, - CPU_FIRM_AMD, - CPU_FIRM_VIA -}; -int x86cpuid_GetFirm(const Cx86cpuid *p); -#define x86cpuid_ver_GetFamily(ver) (((ver >> 16) & 0xff0) | ((ver >> 8) & 0xf)) -#define x86cpuid_ver_GetModel(ver) (((ver >> 12) & 0xf0) | ((ver >> 4) & 0xf)) -#define x86cpuid_ver_GetStepping(ver) (ver & 0xf) - -int x86cpuid_GetFirm(const Cx86cpuid *p) -{ - unsigned i; - for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[0]); i++) - { - const UInt32 *v = kVendors[i]; - if (v[0] == p->vendor[0] - // && v[1] == p->vendor[1] - // && v[2] == p->vendor[2] - ) - return (int)i; - } - return -1; -} - -BoolInt CPU_Is_InOrder() -{ - Cx86cpuid p; - UInt32 family, model; - if (!x86cpuid_CheckAndRead(&p)) - return True; - - family = x86cpuid_ver_GetFamily(p.ver); - model = x86cpuid_ver_GetModel(p.ver); - - switch (x86cpuid_GetFirm(&p)) - { - case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( - // In-Order Atom CPU - model == 0x1C // 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 - || model == 0x26 // 45 nm, Z6xx - || model == 0x27 // 32 nm, Z2460 - || model == 0x35 // 32 nm, Z2760 - || model == 0x36 // 32 nm, N2xxx, D2xxx - ))); - case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); - case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); - } - return False; // v23 : unknown processors are not In-Order -} -*/ - -#ifdef _WIN32 -#include "7zWindows.h" -#endif - -#if !defined(MY_CPU_AMD64) && defined(_WIN32) - -/* for legacy SSE ia32: there is no user-space cpu instruction to check - that OS supports SSE register storing/restoring on context switches. - So we need some OS-specific function to check that it's safe to use SSE registers. -*/ - -Z7_FORCE_INLINE -static BoolInt CPU_Sys_Is_SSE_Supported(void) -{ -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable : 4996) // `GetVersion': was declared deprecated -#endif - /* low byte is major version of Windows - We suppose that any Windows version since - Windows2000 (major == 5) supports SSE registers */ - return (Byte)GetVersion() >= 5; -#if defined(_MSC_VER) - #pragma warning(pop) -#endif -} -#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; -#else -#define CHECK_SYS_SSE_SUPPORT -#endif - - -#if !defined(MY_CPU_AMD64) - -BoolInt CPU_IsSupported_CMOV(void) -{ - UInt32 a[4]; - if (!x86cpuid_Func_1(&a[0])) - return 0; - return (BoolInt)(a[3] >> 15) & 1; -} - -BoolInt CPU_IsSupported_SSE(void) -{ - UInt32 a[4]; - CHECK_SYS_SSE_SUPPORT - if (!x86cpuid_Func_1(&a[0])) - return 0; - return (BoolInt)(a[3] >> 25) & 1; -} - -BoolInt CPU_IsSupported_SSE2(void) -{ - UInt32 a[4]; - CHECK_SYS_SSE_SUPPORT - if (!x86cpuid_Func_1(&a[0])) - return 0; - return (BoolInt)(a[3] >> 26) & 1; -} - -#endif - - -static UInt32 x86cpuid_Func_1_ECX(void) -{ - UInt32 a[4]; - CHECK_SYS_SSE_SUPPORT - if (!x86cpuid_Func_1(&a[0])) - return 0; - return a[2]; -} - -BoolInt CPU_IsSupported_AES(void) -{ - return (BoolInt)(x86cpuid_Func_1_ECX() >> 25) & 1; -} - -BoolInt CPU_IsSupported_SSSE3(void) -{ - return (BoolInt)(x86cpuid_Func_1_ECX() >> 9) & 1; -} - -BoolInt CPU_IsSupported_SSE41(void) -{ - return (BoolInt)(x86cpuid_Func_1_ECX() >> 19) & 1; -} - -BoolInt CPU_IsSupported_SHA(void) -{ - CHECK_SYS_SSE_SUPPORT - - if (z7_x86_cpuid_GetMaxFunc() < 7) - return False; - { - UInt32 d[4]; - z7_x86_cpuid(d, 7); - return (BoolInt)(d[1] >> 29) & 1; - } -} - -/* -MSVC: _xgetbv() intrinsic is available since VS2010SP1. - MSVC also defines (_XCR_XFEATURE_ENABLED_MASK) macro in - that we can use or check. - For any 32-bit x86 we can use asm code in MSVC, - but MSVC asm code is huge after compilation. - So _xgetbv() is better - -ICC: _xgetbv() intrinsic is available (in what version of ICC?) - ICC defines (__GNUC___) and it supports gnu assembler - also ICC supports MASM style code with -use-msasm switch. - but ICC doesn't support __attribute__((__target__)) - -GCC/CLANG 9: - _xgetbv() is macro that works via __builtin_ia32_xgetbv() - and we need __attribute__((__target__("xsave")). - But with __target__("xsave") the function will be not - inlined to function that has no __target__("xsave") attribute. - If we want _xgetbv() call inlining, then we should use asm version - instead of calling _xgetbv(). - Note:intrinsic is broke before GCC 8.2: - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684 -*/ - -#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) \ - || defined(_MSC_VER) && (_MSC_VER >= 1600) && (_MSC_FULL_VER >= 160040219) \ - || defined(__GNUC__) && (__GNUC__ >= 9) \ - || defined(__clang__) && (__clang_major__ >= 9) -// we define ATTRIB_XGETBV, if we want to use predefined _xgetbv() from compiler -#if defined(__INTEL_COMPILER) -#define ATTRIB_XGETBV -#elif defined(__GNUC__) || defined(__clang__) -// we don't define ATTRIB_XGETBV here, because asm version is better for inlining. -// #define ATTRIB_XGETBV __attribute__((__target__("xsave"))) -#else -#define ATTRIB_XGETBV -#endif -#endif - -#if defined(ATTRIB_XGETBV) -#include -#endif - - -// XFEATURE_ENABLED_MASK/XCR0 -#define MY_XCR_XFEATURE_ENABLED_MASK 0 - -#if defined(ATTRIB_XGETBV) -ATTRIB_XGETBV -#endif -static UInt64 x86_xgetbv_0(UInt32 num) -{ -#if defined(ATTRIB_XGETBV) - { - return - #if (defined(_MSC_VER)) - _xgetbv(num); - #else - __builtin_ia32_xgetbv( - #if !defined(__clang__) - (int) - #endif - num); - #endif - } - -#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC) - - UInt32 a, d; - #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) - __asm__ - ( - "xgetbv" - : "=a"(a), "=d"(d) : "c"(num) : "cc" - ); - #else // is old gcc - __asm__ - ( - ".byte 0x0f, 0x01, 0xd0" "\n\t" - : "=a"(a), "=d"(d) : "c"(num) : "cc" - ); - #endif - return ((UInt64)d << 32) | a; - // return a; - -#elif defined(_MSC_VER) && !defined(MY_CPU_AMD64) - - UInt32 a, d; - __asm { - push eax - push edx - push ecx - mov ecx, num; - // xor ecx, ecx // = MY_XCR_XFEATURE_ENABLED_MASK - _emit 0x0f - _emit 0x01 - _emit 0xd0 - mov a, eax - mov d, edx - pop ecx - pop edx - pop eax - } - return ((UInt64)d << 32) | a; - // return a; - -#else // it's unknown compiler - // #error "Need xgetbv function" - UNUSED_VAR(num) - // for MSVC-X64 we could call external function from external file. - /* Actually we had checked OSXSAVE/AVX in cpuid before. - So it's expected that OS supports at least AVX and below. */ - // if (num != MY_XCR_XFEATURE_ENABLED_MASK) return 0; // if not XCR0 - return - // (1 << 0) | // x87 - (1 << 1) // SSE - | (1 << 2); // AVX - -#endif -} - -#ifdef _WIN32 -/* - Windows versions do not know about new ISA extensions that - can be introduced. But we still can use new extensions, - even if Windows doesn't report about supporting them, - But we can use new extensions, only if Windows knows about new ISA extension - that changes the number or size of registers: SSE, AVX/XSAVE, AVX512 - So it's enough to check - MY_PF_AVX_INSTRUCTIONS_AVAILABLE - instead of - MY_PF_AVX2_INSTRUCTIONS_AVAILABLE -*/ -#define MY_PF_XSAVE_ENABLED 17 -// #define MY_PF_SSSE3_INSTRUCTIONS_AVAILABLE 36 -// #define MY_PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37 -// #define MY_PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38 -// #define MY_PF_AVX_INSTRUCTIONS_AVAILABLE 39 -// #define MY_PF_AVX2_INSTRUCTIONS_AVAILABLE 40 -// #define MY_PF_AVX512F_INSTRUCTIONS_AVAILABLE 41 -#endif - -BoolInt CPU_IsSupported_AVX(void) -{ - #ifdef _WIN32 - if (!IsProcessorFeaturePresent(MY_PF_XSAVE_ENABLED)) - return False; - /* PF_AVX_INSTRUCTIONS_AVAILABLE probably is supported starting from - some latest Win10 revisions. But we need AVX in older Windows also. - So we don't use the following check: */ - /* - if (!IsProcessorFeaturePresent(MY_PF_AVX_INSTRUCTIONS_AVAILABLE)) - return False; - */ - #endif - - /* - OS must use new special XSAVE/XRSTOR instructions to save - AVX registers when it required for context switching. - At OS statring: - OS sets CR4.OSXSAVE flag to signal the processor that OS supports the XSAVE extensions. - Also OS sets bitmask in XCR0 register that defines what - registers will be processed by XSAVE instruction: - XCR0.SSE[bit 0] - x87 registers and state - XCR0.SSE[bit 1] - SSE registers and state - XCR0.AVX[bit 2] - AVX registers and state - CR4.OSXSAVE is reflected to CPUID.1:ECX.OSXSAVE[bit 27]. - So we can read that bit in user-space. - XCR0 is available for reading in user-space by new XGETBV instruction. - */ - { - const UInt32 c = x86cpuid_Func_1_ECX(); - if (0 == (1 - & (c >> 28) // AVX instructions are supported by hardware - & (c >> 27))) // OSXSAVE bit: XSAVE and related instructions are enabled by OS. - return False; - } - - /* also we can check - CPUID.1:ECX.XSAVE [bit 26] : that shows that - XSAVE, XRESTOR, XSETBV, XGETBV instructions are supported by hardware. - But that check is redundant, because if OSXSAVE bit is set, then XSAVE is also set */ - - /* If OS have enabled XSAVE extension instructions (OSXSAVE == 1), - in most cases we expect that OS also will support storing/restoring - for AVX and SSE states at least. - But to be ensure for that we call user-space instruction - XGETBV(0) to get XCR0 value that contains bitmask that defines - what exact states(registers) OS have enabled for storing/restoring. - */ - - { - const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK); - // printf("\n=== XGetBV=0x%x\n", bm); - return 1 - & (BoolInt)(bm >> 1) // SSE state is supported (set by OS) for storing/restoring - & (BoolInt)(bm >> 2); // AVX state is supported (set by OS) for storing/restoring - } - // since Win7SP1: we can use GetEnabledXStateFeatures(); -} - - -BoolInt CPU_IsSupported_AVX2(void) -{ - if (!CPU_IsSupported_AVX()) - return False; - if (z7_x86_cpuid_GetMaxFunc() < 7) - return False; - { - UInt32 d[4]; - z7_x86_cpuid(d, 7); - // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); - return 1 - & (BoolInt)(d[1] >> 5); // avx2 - } -} - -#if 0 -BoolInt CPU_IsSupported_AVX512F_AVX512VL(void) -{ - if (!CPU_IsSupported_AVX()) - return False; - if (z7_x86_cpuid_GetMaxFunc() < 7) - return False; - { - UInt32 d[4]; - BoolInt v; - z7_x86_cpuid(d, 7); - // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); - v = 1 - & (BoolInt)(d[1] >> 16) // avx512f - & (BoolInt)(d[1] >> 31); // avx512vl - if (!v) - return False; - } - { - const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK); - // printf("\n=== XGetBV=0x%x\n", bm); - return 1 - & (BoolInt)(bm >> 5) // OPMASK - & (BoolInt)(bm >> 6) // ZMM upper 256-bit - & (BoolInt)(bm >> 7); // ZMM16 ... ZMM31 - } -} -#endif - -BoolInt CPU_IsSupported_VAES_AVX2(void) -{ - if (!CPU_IsSupported_AVX()) - return False; - if (z7_x86_cpuid_GetMaxFunc() < 7) - return False; - { - UInt32 d[4]; - z7_x86_cpuid(d, 7); - // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); - return 1 - & (BoolInt)(d[1] >> 5) // avx2 - // & (d[1] >> 31) // avx512vl - & (BoolInt)(d[2] >> 9); // vaes // VEX-256/EVEX - } -} - -BoolInt CPU_IsSupported_PageGB(void) -{ - CHECK_CPUID_IS_SUPPORTED - { - UInt32 d[4]; - z7_x86_cpuid(d, 0x80000000); - if (d[0] < 0x80000001) - return False; - z7_x86_cpuid(d, 0x80000001); - return (BoolInt)(d[3] >> 26) & 1; - } -} - - -#elif defined(MY_CPU_ARM_OR_ARM64) - -#ifdef _WIN32 - -#include "7zWindows.h" - -BoolInt CPU_IsSupported_CRC32(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } -BoolInt CPU_IsSupported_CRYPTO(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } -BoolInt CPU_IsSupported_NEON(void) { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } - -#else - -#if defined(__APPLE__) - -/* -#include -#include -static void Print_sysctlbyname(const char *name) -{ - size_t bufSize = 256; - char buf[256]; - int res = sysctlbyname(name, &buf, &bufSize, NULL, 0); - { - int i; - printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize); - for (i = 0; i < 20; i++) - printf(" %2x", (unsigned)(Byte)buf[i]); - - } -} -*/ -/* - Print_sysctlbyname("hw.pagesize"); - Print_sysctlbyname("machdep.cpu.brand_string"); -*/ - -static BoolInt z7_sysctlbyname_Get_BoolInt(const char *name) -{ - UInt32 val = 0; - if (z7_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1) - return 1; - return 0; -} - -BoolInt CPU_IsSupported_CRC32(void) -{ - return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32"); -} - -BoolInt CPU_IsSupported_NEON(void) -{ - return z7_sysctlbyname_Get_BoolInt("hw.optional.neon"); -} - -#ifdef MY_CPU_ARM64 -#define APPLE_CRYPTO_SUPPORT_VAL 1 -#else -#define APPLE_CRYPTO_SUPPORT_VAL 0 -#endif - -BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; } -BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; } -BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; } - - -#else // __APPLE__ - -#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216) - #define Z7_GETAUXV_AVAILABLE -#else -// #pragma message("=== is not NEW GLIBC === ") - #if defined __has_include - #if __has_include () -// #pragma message("=== sys/auxv.h is avail=== ") - #define Z7_GETAUXV_AVAILABLE - #endif - #endif -#endif - -#ifdef Z7_GETAUXV_AVAILABLE -// #pragma message("=== Z7_GETAUXV_AVAILABLE === ") -#include -#define USE_HWCAP -#endif - -#ifdef USE_HWCAP - -#if defined(__FreeBSD__) -static unsigned long MY_getauxval(int aux) -{ - unsigned long val; - if (elf_aux_info(aux, &val, sizeof(val))) - return 0; - return val; -} -#else -#define MY_getauxval getauxval - #if defined __has_include - #if __has_include () -#include - #endif - #endif -#endif - - #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \ - BoolInt CPU_IsSupported_ ## name1(void) { return (MY_getauxval(AT_HWCAP) & (HWCAP_ ## name2)); } - -#ifdef MY_CPU_ARM64 - #define MY_HWCAP_CHECK_FUNC(name) \ - MY_HWCAP_CHECK_FUNC_2(name, name) -#if 1 || defined(__ARM_NEON) - BoolInt CPU_IsSupported_NEON(void) { return True; } -#else - MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD) -#endif -// MY_HWCAP_CHECK_FUNC (ASIMD) -#elif defined(MY_CPU_ARM) - #define MY_HWCAP_CHECK_FUNC(name) \ - BoolInt CPU_IsSupported_ ## name(void) { return (MY_getauxval(AT_HWCAP2) & (HWCAP2_ ## name)); } - MY_HWCAP_CHECK_FUNC_2(NEON, NEON) -#endif - -#else // USE_HWCAP - - #define MY_HWCAP_CHECK_FUNC(name) \ - BoolInt CPU_IsSupported_ ## name(void) { return 0; } -#if defined(__ARM_NEON) - BoolInt CPU_IsSupported_NEON(void) { return True; } -#else - MY_HWCAP_CHECK_FUNC(NEON) -#endif - -#endif // USE_HWCAP - -MY_HWCAP_CHECK_FUNC (CRC32) -MY_HWCAP_CHECK_FUNC (SHA1) -MY_HWCAP_CHECK_FUNC (SHA2) -MY_HWCAP_CHECK_FUNC (AES) - -#endif // __APPLE__ -#endif // _WIN32 - -#endif // MY_CPU_ARM_OR_ARM64 - - - -#ifdef __APPLE__ - -#include - -int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize) -{ - return sysctlbyname(name, buf, bufSize, NULL, 0); -} - -int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val) -{ - size_t bufSize = sizeof(*val); - const int res = z7_sysctlbyname_Get(name, val, &bufSize); - if (res == 0 && bufSize != sizeof(*val)) - return EFAULT; - return res; -} - -#endif +/* CpuArch.c -- CPU specific code +Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + +#undef NEED_CHECK_FOR_CPUID +#if !defined(MY_CPU_AMD64) +#define NEED_CHECK_FOR_CPUID +#endif + +/* + cpuid instruction supports (subFunction) parameter in ECX, + that is used only with some specific (function) parameter values. + most functions use only (subFunction==0). +*/ +/* + __cpuid(): MSVC and GCC/CLANG use same function/macro name + but parameters are different. + We use MSVC __cpuid() parameters style for our z7_x86_cpuid() function. +*/ + +#if defined(__GNUC__) /* && (__GNUC__ >= 10) */ \ + || defined(__clang__) /* && (__clang_major__ >= 10) */ + +/* there was some CLANG/GCC compilers that have issues with + rbx(ebx) handling in asm blocks in -fPIC mode (__PIC__ is defined). + compiler's contains the macro __cpuid() that is similar to our code. + The history of __cpuid() changes in CLANG/GCC: + GCC: + 2007: it preserved ebx for (__PIC__ && __i386__) + 2013: it preserved rbx and ebx for __PIC__ + 2014: it doesn't preserves rbx and ebx anymore + we suppose that (__GNUC__ >= 5) fixed that __PIC__ ebx/rbx problem. + CLANG: + 2014+: it preserves rbx, but only for 64-bit code. No __PIC__ check. + Why CLANG cares about 64-bit mode only, and doesn't care about ebx (in 32-bit)? + Do we need __PIC__ test for CLANG or we must care about rbx even if + __PIC__ is not defined? +*/ + +#define ASM_LN "\n" + +#if defined(MY_CPU_AMD64) && defined(__PIC__) \ + && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__)) + + /* "=&r" selects free register. It can select even rbx, if that register is free. + "=&D" for (RDI) also works, but the code can be larger with "=&D" + "2"(subFun) : 2 is (zero-based) index in the output constraint list "=c" (ECX). */ + +#define x86_cpuid_MACRO_2(p, func, subFunc) { \ + __asm__ __volatile__ ( \ + ASM_LN "mov %%rbx, %q1" \ + ASM_LN "cpuid" \ + ASM_LN "xchg %%rbx, %q1" \ + : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(subFunc)); } + +#elif defined(MY_CPU_X86) && defined(__PIC__) \ + && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__)) + +#define x86_cpuid_MACRO_2(p, func, subFunc) { \ + __asm__ __volatile__ ( \ + ASM_LN "mov %%ebx, %k1" \ + ASM_LN "cpuid" \ + ASM_LN "xchg %%ebx, %k1" \ + : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(subFunc)); } + +#else + +#define x86_cpuid_MACRO_2(p, func, subFunc) { \ + __asm__ __volatile__ ( \ + ASM_LN "cpuid" \ + : "=a" ((p)[0]), "=b" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(subFunc)); } + +#endif + +#define x86_cpuid_MACRO(p, func) x86_cpuid_MACRO_2(p, func, 0) + +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + x86_cpuid_MACRO(p, func) +} + +static +void Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc) +{ + x86_cpuid_MACRO_2(p, func, subFunc) +} + + +Z7_NO_INLINE +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + #if defined(NEED_CHECK_FOR_CPUID) + #define EFALGS_CPUID_BIT 21 + UInt32 a; + __asm__ __volatile__ ( + ASM_LN "pushf" + ASM_LN "pushf" + ASM_LN "pop %0" + // ASM_LN "movl %0, %1" + // ASM_LN "xorl $0x200000, %0" + ASM_LN "btc %1, %0" + ASM_LN "push %0" + ASM_LN "popf" + ASM_LN "pushf" + ASM_LN "pop %0" + ASM_LN "xorl (%%esp), %0" + + ASM_LN "popf" + ASM_LN + : "=&r" (a) // "=a" + : "i" (EFALGS_CPUID_BIT) + ); + if ((a & (1 << EFALGS_CPUID_BIT)) == 0) + return 0; + #endif + { + UInt32 p[4]; + x86_cpuid_MACRO(p, 0) + return p[0]; + } +} + +#undef ASM_LN + +#elif !defined(_MSC_VER) + +/* +// for gcc/clang and other: we can try to use __cpuid macro: +#include +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + __cpuid(func, p[0], p[1], p[2], p[3]); +} +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + return (UInt32)__get_cpuid_max(0, NULL); +} +*/ +// for unsupported cpuid: +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + UNUSED_VAR(func) + p[0] = p[1] = p[2] = p[3] = 0; +} +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + return 0; +} + +#else // _MSC_VER + +#if !defined(MY_CPU_AMD64) + +UInt32 __declspec(naked) Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + #if defined(NEED_CHECK_FOR_CPUID) + #define EFALGS_CPUID_BIT 21 + __asm pushfd + __asm pushfd + /* + __asm pop eax + // __asm mov edx, eax + __asm btc eax, EFALGS_CPUID_BIT + __asm push eax + */ + __asm btc dword ptr [esp], EFALGS_CPUID_BIT + __asm popfd + __asm pushfd + __asm pop eax + // __asm xor eax, edx + __asm xor eax, [esp] + // __asm push edx + __asm popfd + __asm and eax, (1 shl EFALGS_CPUID_BIT) + __asm jz end_func + #endif + __asm push ebx + __asm xor eax, eax // func + __asm xor ecx, ecx // subFunction (optional) for (func == 0) + __asm cpuid + __asm pop ebx + #if defined(NEED_CHECK_FOR_CPUID) + end_func: + #endif + __asm ret 0 +} + +void __declspec(naked) Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + UNUSED_VAR(p) + UNUSED_VAR(func) + __asm push ebx + __asm push edi + __asm mov edi, ecx // p + __asm mov eax, edx // func + __asm xor ecx, ecx // subfunction (optional) for (func == 0) + __asm cpuid + __asm mov [edi ], eax + __asm mov [edi + 4], ebx + __asm mov [edi + 8], ecx + __asm mov [edi + 12], edx + __asm pop edi + __asm pop ebx + __asm ret 0 +} + +static +void __declspec(naked) Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc) +{ + UNUSED_VAR(p) + UNUSED_VAR(func) + UNUSED_VAR(subFunc) + __asm push ebx + __asm push edi + __asm mov edi, ecx // p + __asm mov eax, edx // func + __asm mov ecx, [esp + 12] // subFunc + __asm cpuid + __asm mov [edi ], eax + __asm mov [edi + 4], ebx + __asm mov [edi + 8], ecx + __asm mov [edi + 12], edx + __asm pop edi + __asm pop ebx + __asm ret 4 +} + +#else // MY_CPU_AMD64 + + #if _MSC_VER >= 1600 + #include + #define MY_cpuidex __cpuidex + +static +void Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc) +{ + __cpuidex((int *)p, func, subFunc); +} + + #else +/* + __cpuid (func == (0 or 7)) requires subfunction number in ECX. + MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction. + __cpuid() in new MSVC clears ECX. + __cpuid() in old MSVC (14.00) x64 doesn't clear ECX + We still can use __cpuid for low (func) values that don't require ECX, + but __cpuid() in old MSVC will be incorrect for some func values: (func == 7). + So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction, + where ECX value is first parameter for FASTCALL / NO_INLINE func. + So the caller of MY_cpuidex_HACK() sets ECX as subFunction, and + old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value. + +DON'T remove Z7_NO_INLINE and Z7_FASTCALL for MY_cpuidex_HACK(): !!! +*/ +static +Z7_NO_INLINE void Z7_FASTCALL MY_cpuidex_HACK(Int32 subFunction, Int32 func, Int32 *CPUInfo) +{ + UNUSED_VAR(subFunction) + __cpuid(CPUInfo, func); +} + #define MY_cpuidex(info, func, func2) MY_cpuidex_HACK(func2, func, info) + #pragma message("======== MY_cpuidex_HACK WAS USED ========") +static +void Z7_FASTCALL z7_x86_cpuid_subFunc(UInt32 p[4], UInt32 func, UInt32 subFunc) +{ + MY_cpuidex_HACK(subFunc, func, (Int32 *)p); +} + #endif // _MSC_VER >= 1600 + +#if !defined(MY_CPU_AMD64) +/* inlining for __cpuid() in MSVC x86 (32-bit) produces big ineffective code, + so we disable inlining here */ +Z7_NO_INLINE +#endif +void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func) +{ + MY_cpuidex((Int32 *)p, (Int32)func, 0); +} + +Z7_NO_INLINE +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void) +{ + Int32 a[4]; + MY_cpuidex(a, 0, 0); + return a[0]; +} + +#endif // MY_CPU_AMD64 +#endif // _MSC_VER + +#if defined(NEED_CHECK_FOR_CPUID) +#define CHECK_CPUID_IS_SUPPORTED { if (z7_x86_cpuid_GetMaxFunc() == 0) return 0; } +#else +#define CHECK_CPUID_IS_SUPPORTED +#endif +#undef NEED_CHECK_FOR_CPUID + + +static +BoolInt x86cpuid_Func_1(UInt32 *p) +{ + CHECK_CPUID_IS_SUPPORTED + z7_x86_cpuid(p, 1); + return True; +} + +/* +static const UInt32 kVendors[][1] = +{ + { 0x756E6547 }, // , 0x49656E69, 0x6C65746E }, + { 0x68747541 }, // , 0x69746E65, 0x444D4163 }, + { 0x746E6543 } // , 0x48727561, 0x736C7561 } +}; +*/ + +/* +typedef struct +{ + UInt32 maxFunc; + UInt32 vendor[3]; + UInt32 ver; + UInt32 b; + UInt32 c; + UInt32 d; +} Cx86cpuid; + +enum +{ + CPU_FIRM_INTEL, + CPU_FIRM_AMD, + CPU_FIRM_VIA +}; +int x86cpuid_GetFirm(const Cx86cpuid *p); +#define x86cpuid_ver_GetFamily(ver) (((ver >> 16) & 0xff0) | ((ver >> 8) & 0xf)) +#define x86cpuid_ver_GetModel(ver) (((ver >> 12) & 0xf0) | ((ver >> 4) & 0xf)) +#define x86cpuid_ver_GetStepping(ver) (ver & 0xf) + +int x86cpuid_GetFirm(const Cx86cpuid *p) +{ + unsigned i; + for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[0]); i++) + { + const UInt32 *v = kVendors[i]; + if (v[0] == p->vendor[0] + // && v[1] == p->vendor[1] + // && v[2] == p->vendor[2] + ) + return (int)i; + } + return -1; +} + +BoolInt CPU_Is_InOrder() +{ + Cx86cpuid p; + UInt32 family, model; + if (!x86cpuid_CheckAndRead(&p)) + return True; + + family = x86cpuid_ver_GetFamily(p.ver); + model = x86cpuid_ver_GetModel(p.ver); + + switch (x86cpuid_GetFirm(&p)) + { + case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( + // In-Order Atom CPU + model == 0x1C // 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 + || model == 0x26 // 45 nm, Z6xx + || model == 0x27 // 32 nm, Z2460 + || model == 0x35 // 32 nm, Z2760 + || model == 0x36 // 32 nm, N2xxx, D2xxx + ))); + case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); + case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); + } + return False; // v23 : unknown processors are not In-Order +} +*/ + +#ifdef _WIN32 +#include "7zWindows.h" +#endif + +#if !defined(MY_CPU_AMD64) && defined(_WIN32) + +/* for legacy SSE ia32: there is no user-space cpu instruction to check + that OS supports SSE register storing/restoring on context switches. + So we need some OS-specific function to check that it's safe to use SSE registers. +*/ + +Z7_FORCE_INLINE +static BoolInt CPU_Sys_Is_SSE_Supported(void) +{ +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4996) // `GetVersion': was declared deprecated +#endif + /* low byte is major version of Windows + We suppose that any Windows version since + Windows2000 (major == 5) supports SSE registers */ + return (Byte)GetVersion() >= 5; +#if defined(_MSC_VER) + #pragma warning(pop) +#endif +} +#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; +#else +#define CHECK_SYS_SSE_SUPPORT +#endif + + +#if !defined(MY_CPU_AMD64) + +BoolInt CPU_IsSupported_CMOV(void) +{ + UInt32 a[4]; + if (!x86cpuid_Func_1(&a[0])) + return 0; + return (BoolInt)(a[3] >> 15) & 1; +} + +BoolInt CPU_IsSupported_SSE(void) +{ + UInt32 a[4]; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_Func_1(&a[0])) + return 0; + return (BoolInt)(a[3] >> 25) & 1; +} + +BoolInt CPU_IsSupported_SSE2(void) +{ + UInt32 a[4]; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_Func_1(&a[0])) + return 0; + return (BoolInt)(a[3] >> 26) & 1; +} + +#endif + + +static UInt32 x86cpuid_Func_1_ECX(void) +{ + UInt32 a[4]; + CHECK_SYS_SSE_SUPPORT + if (!x86cpuid_Func_1(&a[0])) + return 0; + return a[2]; +} + +BoolInt CPU_IsSupported_AES(void) +{ + return (BoolInt)(x86cpuid_Func_1_ECX() >> 25) & 1; +} + +BoolInt CPU_IsSupported_SSSE3(void) +{ + return (BoolInt)(x86cpuid_Func_1_ECX() >> 9) & 1; +} + +BoolInt CPU_IsSupported_SSE41(void) +{ + return (BoolInt)(x86cpuid_Func_1_ECX() >> 19) & 1; +} + +BoolInt CPU_IsSupported_SHA(void) +{ + CHECK_SYS_SSE_SUPPORT + + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; + { + UInt32 d[4]; + z7_x86_cpuid(d, 7); + return (BoolInt)(d[1] >> 29) & 1; + } +} + + +BoolInt CPU_IsSupported_SHA512(void) +{ + if (!CPU_IsSupported_AVX2()) return False; // maybe CPU_IsSupported_AVX() is enough here + + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; + { + UInt32 d[4]; + z7_x86_cpuid_subFunc(d, 7, 0); + if (d[0] < 1) // d[0] - is max supported subleaf value + return False; + z7_x86_cpuid_subFunc(d, 7, 1); + return (BoolInt)(d[0]) & 1; + } +} + +/* +MSVC: _xgetbv() intrinsic is available since VS2010SP1. + MSVC also defines (_XCR_XFEATURE_ENABLED_MASK) macro in + that we can use or check. + For any 32-bit x86 we can use asm code in MSVC, + but MSVC asm code is huge after compilation. + So _xgetbv() is better + +ICC: _xgetbv() intrinsic is available (in what version of ICC?) + ICC defines (__GNUC___) and it supports gnu assembler + also ICC supports MASM style code with -use-msasm switch. + but ICC doesn't support __attribute__((__target__)) + +GCC/CLANG 9: + _xgetbv() is macro that works via __builtin_ia32_xgetbv() + and we need __attribute__((__target__("xsave")). + But with __target__("xsave") the function will be not + inlined to function that has no __target__("xsave") attribute. + If we want _xgetbv() call inlining, then we should use asm version + instead of calling _xgetbv(). + Note:intrinsic is broke before GCC 8.2: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684 +*/ + +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) \ + || defined(_MSC_VER) && (_MSC_VER >= 1600) && (_MSC_FULL_VER >= 160040219) \ + || defined(__GNUC__) && (__GNUC__ >= 9) \ + || defined(__clang__) && (__clang_major__ >= 9) +// we define ATTRIB_XGETBV, if we want to use predefined _xgetbv() from compiler +#if defined(__INTEL_COMPILER) +#define ATTRIB_XGETBV +#elif defined(__GNUC__) || defined(__clang__) +// we don't define ATTRIB_XGETBV here, because asm version is better for inlining. +// #define ATTRIB_XGETBV __attribute__((__target__("xsave"))) +#else +#define ATTRIB_XGETBV +#endif +#endif + +#if defined(ATTRIB_XGETBV) +#include +#endif + + +// XFEATURE_ENABLED_MASK/XCR0 +#define MY_XCR_XFEATURE_ENABLED_MASK 0 + +#if defined(ATTRIB_XGETBV) +ATTRIB_XGETBV +#endif +static UInt64 x86_xgetbv_0(UInt32 num) +{ +#if defined(ATTRIB_XGETBV) + { + return + #if (defined(_MSC_VER)) + _xgetbv(num); + #else + __builtin_ia32_xgetbv( + #if !defined(__clang__) + (int) + #endif + num); + #endif + } + +#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC) + + UInt32 a, d; + #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) + __asm__ + ( + "xgetbv" + : "=a"(a), "=d"(d) : "c"(num) : "cc" + ); + #else // is old gcc + __asm__ + ( + ".byte 0x0f, 0x01, 0xd0" "\n\t" + : "=a"(a), "=d"(d) : "c"(num) : "cc" + ); + #endif + return ((UInt64)d << 32) | a; + // return a; + +#elif defined(_MSC_VER) && !defined(MY_CPU_AMD64) + + UInt32 a, d; + __asm { + push eax + push edx + push ecx + mov ecx, num; + // xor ecx, ecx // = MY_XCR_XFEATURE_ENABLED_MASK + _emit 0x0f + _emit 0x01 + _emit 0xd0 + mov a, eax + mov d, edx + pop ecx + pop edx + pop eax + } + return ((UInt64)d << 32) | a; + // return a; + +#else // it's unknown compiler + // #error "Need xgetbv function" + UNUSED_VAR(num) + // for MSVC-X64 we could call external function from external file. + /* Actually we had checked OSXSAVE/AVX in cpuid before. + So it's expected that OS supports at least AVX and below. */ + // if (num != MY_XCR_XFEATURE_ENABLED_MASK) return 0; // if not XCR0 + return + // (1 << 0) | // x87 + (1 << 1) // SSE + | (1 << 2); // AVX + +#endif +} + +#ifdef _WIN32 +/* + Windows versions do not know about new ISA extensions that + can be introduced. But we still can use new extensions, + even if Windows doesn't report about supporting them, + But we can use new extensions, only if Windows knows about new ISA extension + that changes the number or size of registers: SSE, AVX/XSAVE, AVX512 + So it's enough to check + MY_PF_AVX_INSTRUCTIONS_AVAILABLE + instead of + MY_PF_AVX2_INSTRUCTIONS_AVAILABLE +*/ +#define MY_PF_XSAVE_ENABLED 17 +// #define MY_PF_SSSE3_INSTRUCTIONS_AVAILABLE 36 +// #define MY_PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37 +// #define MY_PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38 +// #define MY_PF_AVX_INSTRUCTIONS_AVAILABLE 39 +// #define MY_PF_AVX2_INSTRUCTIONS_AVAILABLE 40 +// #define MY_PF_AVX512F_INSTRUCTIONS_AVAILABLE 41 +#endif + +BoolInt CPU_IsSupported_AVX(void) +{ + #ifdef _WIN32 + if (!IsProcessorFeaturePresent(MY_PF_XSAVE_ENABLED)) + return False; + /* PF_AVX_INSTRUCTIONS_AVAILABLE probably is supported starting from + some latest Win10 revisions. But we need AVX in older Windows also. + So we don't use the following check: */ + /* + if (!IsProcessorFeaturePresent(MY_PF_AVX_INSTRUCTIONS_AVAILABLE)) + return False; + */ + #endif + + /* + OS must use new special XSAVE/XRSTOR instructions to save + AVX registers when it required for context switching. + At OS statring: + OS sets CR4.OSXSAVE flag to signal the processor that OS supports the XSAVE extensions. + Also OS sets bitmask in XCR0 register that defines what + registers will be processed by XSAVE instruction: + XCR0.SSE[bit 0] - x87 registers and state + XCR0.SSE[bit 1] - SSE registers and state + XCR0.AVX[bit 2] - AVX registers and state + CR4.OSXSAVE is reflected to CPUID.1:ECX.OSXSAVE[bit 27]. + So we can read that bit in user-space. + XCR0 is available for reading in user-space by new XGETBV instruction. + */ + { + const UInt32 c = x86cpuid_Func_1_ECX(); + if (0 == (1 + & (c >> 28) // AVX instructions are supported by hardware + & (c >> 27))) // OSXSAVE bit: XSAVE and related instructions are enabled by OS. + return False; + } + + /* also we can check + CPUID.1:ECX.XSAVE [bit 26] : that shows that + XSAVE, XRESTOR, XSETBV, XGETBV instructions are supported by hardware. + But that check is redundant, because if OSXSAVE bit is set, then XSAVE is also set */ + + /* If OS have enabled XSAVE extension instructions (OSXSAVE == 1), + in most cases we expect that OS also will support storing/restoring + for AVX and SSE states at least. + But to be ensure for that we call user-space instruction + XGETBV(0) to get XCR0 value that contains bitmask that defines + what exact states(registers) OS have enabled for storing/restoring. + */ + + { + const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK); + // printf("\n=== XGetBV=0x%x\n", bm); + return 1 + & (BoolInt)(bm >> 1) // SSE state is supported (set by OS) for storing/restoring + & (BoolInt)(bm >> 2); // AVX state is supported (set by OS) for storing/restoring + } + // since Win7SP1: we can use GetEnabledXStateFeatures(); +} + + +BoolInt CPU_IsSupported_AVX2(void) +{ + if (!CPU_IsSupported_AVX()) + return False; + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; + { + UInt32 d[4]; + z7_x86_cpuid(d, 7); + // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); + return 1 + & (BoolInt)(d[1] >> 5); // avx2 + } +} + +#if 0 +BoolInt CPU_IsSupported_AVX512F_AVX512VL(void) +{ + if (!CPU_IsSupported_AVX()) + return False; + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; + { + UInt32 d[4]; + BoolInt v; + z7_x86_cpuid(d, 7); + // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); + v = 1 + & (BoolInt)(d[1] >> 16) // avx512f + & (BoolInt)(d[1] >> 31); // avx512vl + if (!v) + return False; + } + { + const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK); + // printf("\n=== XGetBV=0x%x\n", bm); + return 1 + & (BoolInt)(bm >> 5) // OPMASK + & (BoolInt)(bm >> 6) // ZMM upper 256-bit + & (BoolInt)(bm >> 7); // ZMM16 ... ZMM31 + } +} +#endif + +BoolInt CPU_IsSupported_VAES_AVX2(void) +{ + if (!CPU_IsSupported_AVX()) + return False; + if (z7_x86_cpuid_GetMaxFunc() < 7) + return False; + { + UInt32 d[4]; + z7_x86_cpuid(d, 7); + // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]); + return 1 + & (BoolInt)(d[1] >> 5) // avx2 + // & (d[1] >> 31) // avx512vl + & (BoolInt)(d[2] >> 9); // vaes // VEX-256/EVEX + } +} + +BoolInt CPU_IsSupported_PageGB(void) +{ + CHECK_CPUID_IS_SUPPORTED + { + UInt32 d[4]; + z7_x86_cpuid(d, 0x80000000); + if (d[0] < 0x80000001) + return False; + z7_x86_cpuid(d, 0x80000001); + return (BoolInt)(d[3] >> 26) & 1; + } +} + + +#elif defined(MY_CPU_ARM_OR_ARM64) + +#ifdef _WIN32 + +#include "7zWindows.h" + +BoolInt CPU_IsSupported_CRC32(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } +BoolInt CPU_IsSupported_CRYPTO(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } +BoolInt CPU_IsSupported_NEON(void) { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; } + +#else + +#if defined(__APPLE__) + +/* +#include +#include +static void Print_sysctlbyname(const char *name) +{ + size_t bufSize = 256; + char buf[256]; + int res = sysctlbyname(name, &buf, &bufSize, NULL, 0); + { + int i; + printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize); + for (i = 0; i < 20; i++) + printf(" %2x", (unsigned)(Byte)buf[i]); + + } +} +*/ +/* + Print_sysctlbyname("hw.pagesize"); + Print_sysctlbyname("machdep.cpu.brand_string"); +*/ + +static BoolInt z7_sysctlbyname_Get_BoolInt(const char *name) +{ + UInt32 val = 0; + if (z7_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1) + return 1; + return 0; +} + +BoolInt CPU_IsSupported_CRC32(void) +{ + return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32"); +} + +BoolInt CPU_IsSupported_NEON(void) +{ + return z7_sysctlbyname_Get_BoolInt("hw.optional.neon"); +} + +BoolInt CPU_IsSupported_SHA512(void) +{ + return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_2_sha512"); +} + +/* +BoolInt CPU_IsSupported_SHA3(void) +{ + return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_2_sha3"); +} +*/ + +#ifdef MY_CPU_ARM64 +#define APPLE_CRYPTO_SUPPORT_VAL 1 +#else +#define APPLE_CRYPTO_SUPPORT_VAL 0 +#endif + +BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; } +BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; } +BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; } + + +#else // __APPLE__ + +#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216) + #define Z7_GETAUXV_AVAILABLE +#else +// #pragma message("=== is not NEW GLIBC === ") + #if defined __has_include + #if __has_include () +// #pragma message("=== sys/auxv.h is avail=== ") + #define Z7_GETAUXV_AVAILABLE + #endif + #endif +#endif + +#ifdef Z7_GETAUXV_AVAILABLE +// #pragma message("=== Z7_GETAUXV_AVAILABLE === ") +#include +#define USE_HWCAP +#endif + +#ifdef USE_HWCAP + +#if defined(__FreeBSD__) +static unsigned long MY_getauxval(int aux) +{ + unsigned long val; + if (elf_aux_info(aux, &val, sizeof(val))) + return 0; + return val; +} +#else +#define MY_getauxval getauxval + #if defined __has_include + #if __has_include () +#include + #endif + #endif +#endif + + #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \ + BoolInt CPU_IsSupported_ ## name1(void) { return (MY_getauxval(AT_HWCAP) & (HWCAP_ ## name2)); } + +#ifdef MY_CPU_ARM64 + #define MY_HWCAP_CHECK_FUNC(name) \ + MY_HWCAP_CHECK_FUNC_2(name, name) +#if 1 || defined(__ARM_NEON) + BoolInt CPU_IsSupported_NEON(void) { return True; } +#else + MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD) +#endif +// MY_HWCAP_CHECK_FUNC (ASIMD) +#elif defined(MY_CPU_ARM) + #define MY_HWCAP_CHECK_FUNC(name) \ + BoolInt CPU_IsSupported_ ## name(void) { return (MY_getauxval(AT_HWCAP2) & (HWCAP2_ ## name)); } + MY_HWCAP_CHECK_FUNC_2(NEON, NEON) +#endif + +#else // USE_HWCAP + + #define MY_HWCAP_CHECK_FUNC(name) \ + BoolInt CPU_IsSupported_ ## name(void) { return 0; } +#if defined(__ARM_NEON) + BoolInt CPU_IsSupported_NEON(void) { return True; } +#else + MY_HWCAP_CHECK_FUNC(NEON) +#endif + +#endif // USE_HWCAP + +MY_HWCAP_CHECK_FUNC (CRC32) +MY_HWCAP_CHECK_FUNC (SHA1) +MY_HWCAP_CHECK_FUNC (SHA2) +MY_HWCAP_CHECK_FUNC (AES) +#ifdef MY_CPU_ARM64 +// supports HWCAP_SHA512 and HWCAP_SHA3 since 2017. +// we define them here, if they are not defined +#ifndef HWCAP_SHA3 +// #define HWCAP_SHA3 (1 << 17) +#endif +#ifndef HWCAP_SHA512 +// #pragma message("=== HWCAP_SHA512 define === ") +#define HWCAP_SHA512 (1 << 21) +#endif +MY_HWCAP_CHECK_FUNC (SHA512) +// MY_HWCAP_CHECK_FUNC (SHA3) +#endif + +#endif // __APPLE__ +#endif // _WIN32 + +#endif // MY_CPU_ARM_OR_ARM64 + + + +#ifdef __APPLE__ + +#include + +int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize) +{ + return sysctlbyname(name, buf, bufSize, NULL, 0); +} + +int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val) +{ + size_t bufSize = sizeof(*val); + const int res = z7_sysctlbyname_Get(name, val, &bufSize); + if (res == 0 && bufSize != sizeof(*val)) + return EFAULT; + return res; +} + +#endif diff --git a/C/CpuArch.h b/C/CpuArch.h index bdba5dfd6..a6297ea43 100644 --- a/C/CpuArch.h +++ b/C/CpuArch.h @@ -1,647 +1,678 @@ -/* CpuArch.h -- CPU specific code -2024-06-17 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_CPU_ARCH_H -#define ZIP7_INC_CPU_ARCH_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* -MY_CPU_LE means that CPU is LITTLE ENDIAN. -MY_CPU_BE means that CPU is BIG ENDIAN. -If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. - -MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. - -MY_CPU_64BIT means that processor can work with 64-bit registers. - MY_CPU_64BIT can be used to select fast code branch - MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8) -*/ - -#if !defined(_M_ARM64EC) -#if defined(_M_X64) \ - || defined(_M_AMD64) \ - || defined(__x86_64__) \ - || defined(__AMD64__) \ - || defined(__amd64__) - #define MY_CPU_AMD64 - #ifdef __ILP32__ - #define MY_CPU_NAME "x32" - #define MY_CPU_SIZEOF_POINTER 4 - #else - #define MY_CPU_NAME "x64" - #define MY_CPU_SIZEOF_POINTER 8 - #endif - #define MY_CPU_64BIT -#endif -#endif - - -#if defined(_M_IX86) \ - || defined(__i386__) - #define MY_CPU_X86 - #define MY_CPU_NAME "x86" - /* #define MY_CPU_32BIT */ - #define MY_CPU_SIZEOF_POINTER 4 -#endif - - -#if defined(_M_ARM64) \ - || defined(_M_ARM64EC) \ - || defined(__AARCH64EL__) \ - || defined(__AARCH64EB__) \ - || defined(__aarch64__) - #define MY_CPU_ARM64 -#if defined(__ILP32__) \ - || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4) - #define MY_CPU_NAME "arm64-32" - #define MY_CPU_SIZEOF_POINTER 4 -#elif defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) - #define MY_CPU_NAME "arm64-128" - #define MY_CPU_SIZEOF_POINTER 16 -#else -#if defined(_M_ARM64EC) - #define MY_CPU_NAME "arm64ec" -#else - #define MY_CPU_NAME "arm64" -#endif - #define MY_CPU_SIZEOF_POINTER 8 -#endif - #define MY_CPU_64BIT -#endif - - -#if defined(_M_ARM) \ - || defined(_M_ARM_NT) \ - || defined(_M_ARMT) \ - || defined(__arm__) \ - || defined(__thumb__) \ - || defined(__ARMEL__) \ - || defined(__ARMEB__) \ - || defined(__THUMBEL__) \ - || defined(__THUMBEB__) - #define MY_CPU_ARM - - #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT) - #define MY_CPU_ARMT - #define MY_CPU_NAME "armt" - #else - #define MY_CPU_ARM32 - #define MY_CPU_NAME "arm" - #endif - /* #define MY_CPU_32BIT */ - #define MY_CPU_SIZEOF_POINTER 4 -#endif - - -#if defined(_M_IA64) \ - || defined(__ia64__) - #define MY_CPU_IA64 - #define MY_CPU_NAME "ia64" - #define MY_CPU_64BIT -#endif - - -#if defined(__mips64) \ - || defined(__mips64__) \ - || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3)) - #define MY_CPU_NAME "mips64" - #define MY_CPU_64BIT -#elif defined(__mips__) - #define MY_CPU_NAME "mips" - /* #define MY_CPU_32BIT */ -#endif - - -#if defined(__ppc64__) \ - || defined(__powerpc64__) \ - || defined(__ppc__) \ - || defined(__powerpc__) \ - || defined(__PPC__) \ - || defined(_POWER) - -#define MY_CPU_PPC_OR_PPC64 - -#if defined(__ppc64__) \ - || defined(__powerpc64__) \ - || defined(_LP64) \ - || defined(__64BIT__) - #ifdef __ILP32__ - #define MY_CPU_NAME "ppc64-32" - #define MY_CPU_SIZEOF_POINTER 4 - #else - #define MY_CPU_NAME "ppc64" - #define MY_CPU_SIZEOF_POINTER 8 - #endif - #define MY_CPU_64BIT -#else - #define MY_CPU_NAME "ppc" - #define MY_CPU_SIZEOF_POINTER 4 - /* #define MY_CPU_32BIT */ -#endif -#endif - - -#if defined(__sparc__) \ - || defined(__sparc) - #define MY_CPU_SPARC - #if defined(__LP64__) \ - || defined(_LP64) \ - || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8) - #define MY_CPU_NAME "sparcv9" - #define MY_CPU_SIZEOF_POINTER 8 - #define MY_CPU_64BIT - #elif defined(__sparc_v9__) \ - || defined(__sparcv9) - #define MY_CPU_64BIT - #if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4) - #define MY_CPU_NAME "sparcv9-32" - #else - #define MY_CPU_NAME "sparcv9m" - #endif - #elif defined(__sparc_v8__) \ - || defined(__sparcv8) - #define MY_CPU_NAME "sparcv8" - #define MY_CPU_SIZEOF_POINTER 4 - #else - #define MY_CPU_NAME "sparc" - #endif -#endif - - -#if defined(__riscv) \ - || defined(__riscv__) - #define MY_CPU_RISCV - #if __riscv_xlen == 32 - #define MY_CPU_NAME "riscv32" - #elif __riscv_xlen == 64 - #define MY_CPU_NAME "riscv64" - #else - #define MY_CPU_NAME "riscv" - #endif -#endif - - -#if defined(__loongarch__) - #define MY_CPU_LOONGARCH - #if defined(__loongarch64) || defined(__loongarch_grlen) && (__loongarch_grlen == 64) - #define MY_CPU_64BIT - #endif - #if defined(__loongarch64) - #define MY_CPU_NAME "loongarch64" - #define MY_CPU_LOONGARCH64 - #else - #define MY_CPU_NAME "loongarch" - #endif -#endif - - -// #undef MY_CPU_NAME -// #undef MY_CPU_SIZEOF_POINTER -// #define __e2k__ -// #define __SIZEOF_POINTER__ 4 -#if defined(__e2k__) - #define MY_CPU_E2K - #if defined(__ILP32__) || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4) - #define MY_CPU_NAME "e2k-32" - #define MY_CPU_SIZEOF_POINTER 4 - #else - #define MY_CPU_NAME "e2k" - #if defined(__LP64__) || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8) - #define MY_CPU_SIZEOF_POINTER 8 - #endif - #endif - #define MY_CPU_64BIT -#endif - - -#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) -#define MY_CPU_X86_OR_AMD64 -#endif - -#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64) -#define MY_CPU_ARM_OR_ARM64 -#endif - - -#ifdef _WIN32 - - #ifdef MY_CPU_ARM - #define MY_CPU_ARM_LE - #endif - - #ifdef MY_CPU_ARM64 - #define MY_CPU_ARM64_LE - #endif - - #ifdef _M_IA64 - #define MY_CPU_IA64_LE - #endif - -#endif - - -#if defined(MY_CPU_X86_OR_AMD64) \ - || defined(MY_CPU_ARM_LE) \ - || defined(MY_CPU_ARM64_LE) \ - || defined(MY_CPU_IA64_LE) \ - || defined(_LITTLE_ENDIAN) \ - || defined(__LITTLE_ENDIAN__) \ - || defined(__ARMEL__) \ - || defined(__THUMBEL__) \ - || defined(__AARCH64EL__) \ - || defined(__MIPSEL__) \ - || defined(__MIPSEL) \ - || defined(_MIPSEL) \ - || defined(__BFIN__) \ - || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - #define MY_CPU_LE -#endif - -#if defined(__BIG_ENDIAN__) \ - || defined(__ARMEB__) \ - || defined(__THUMBEB__) \ - || defined(__AARCH64EB__) \ - || defined(__MIPSEB__) \ - || defined(__MIPSEB) \ - || defined(_MIPSEB) \ - || defined(__m68k__) \ - || defined(__s390__) \ - || defined(__s390x__) \ - || defined(__zarch__) \ - || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - #define MY_CPU_BE -#endif - - -#if defined(MY_CPU_LE) && defined(MY_CPU_BE) - #error Stop_Compiling_Bad_Endian -#endif - -#if !defined(MY_CPU_LE) && !defined(MY_CPU_BE) - #error Stop_Compiling_CPU_ENDIAN_must_be_detected_at_compile_time -#endif - -#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT) - #error Stop_Compiling_Bad_32_64_BIT -#endif - -#ifdef __SIZEOF_POINTER__ - #ifdef MY_CPU_SIZEOF_POINTER - #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__ - #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE - #endif - #else - #define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__ - #endif -#endif - -#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) -#if defined (_LP64) - #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE -#endif -#endif - -#ifdef _MSC_VER - #if _MSC_VER >= 1300 - #define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1)) - #define MY_CPU_pragma_pop __pragma(pack(pop)) - #else - #define MY_CPU_pragma_pack_push_1 - #define MY_CPU_pragma_pop - #endif -#else - #ifdef __xlC__ - #define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)") - #define MY_CPU_pragma_pop _Pragma("pack()") - #else - #define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)") - #define MY_CPU_pragma_pop _Pragma("pack(pop)") - #endif -#endif - - -#ifndef MY_CPU_NAME - // #define MY_CPU_IS_UNKNOWN - #ifdef MY_CPU_LE - #define MY_CPU_NAME "LE" - #elif defined(MY_CPU_BE) - #define MY_CPU_NAME "BE" - #else - /* - #define MY_CPU_NAME "" - */ - #endif -#endif - - - - - -#ifdef __has_builtin - #define Z7_has_builtin(x) __has_builtin(x) -#else - #define Z7_has_builtin(x) 0 -#endif - - -#define Z7_BSWAP32_CONST(v) \ - ( (((UInt32)(v) << 24) ) \ - | (((UInt32)(v) << 8) & (UInt32)0xff0000) \ - | (((UInt32)(v) >> 8) & (UInt32)0xff00 ) \ - | (((UInt32)(v) >> 24) )) - - -#if defined(_MSC_VER) && (_MSC_VER >= 1300) - -#include - -/* Note: these macros will use bswap instruction (486), that is unsupported in 386 cpu */ - -#pragma intrinsic(_byteswap_ushort) -#pragma intrinsic(_byteswap_ulong) -#pragma intrinsic(_byteswap_uint64) - -#define Z7_BSWAP16(v) _byteswap_ushort(v) -#define Z7_BSWAP32(v) _byteswap_ulong (v) -#define Z7_BSWAP64(v) _byteswap_uint64(v) -#define Z7_CPU_FAST_BSWAP_SUPPORTED - -/* GCC can generate slow code that calls function for __builtin_bswap32() for: - - GCC for RISCV, if Zbb/XTHeadBb extension is not used. - - GCC for SPARC. - The code from CLANG for SPARC also is not fastest. - So we don't define Z7_CPU_FAST_BSWAP_SUPPORTED in some cases. -*/ -#elif (!defined(MY_CPU_RISCV) || defined (__riscv_zbb) || defined(__riscv_xtheadbb)) \ - && !defined(MY_CPU_SPARC) \ - && ( \ - (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ - || (defined(__clang__) && Z7_has_builtin(__builtin_bswap16)) \ - ) - -#define Z7_BSWAP16(v) __builtin_bswap16(v) -#define Z7_BSWAP32(v) __builtin_bswap32(v) -#define Z7_BSWAP64(v) __builtin_bswap64(v) -#define Z7_CPU_FAST_BSWAP_SUPPORTED - -#else - -#define Z7_BSWAP16(v) ((UInt16) \ - ( ((UInt32)(v) << 8) \ - | ((UInt32)(v) >> 8) \ - )) - -#define Z7_BSWAP32(v) Z7_BSWAP32_CONST(v) - -#define Z7_BSWAP64(v) \ - ( ( ( (UInt64)(v) ) << 8 * 7 ) \ - | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 1) ) << 8 * 5 ) \ - | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 2) ) << 8 * 3 ) \ - | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 3) ) << 8 * 1 ) \ - | ( ( (UInt64)(v) >> 8 * 1 ) & ((UInt32)0xff << 8 * 3) ) \ - | ( ( (UInt64)(v) >> 8 * 3 ) & ((UInt32)0xff << 8 * 2) ) \ - | ( ( (UInt64)(v) >> 8 * 5 ) & ((UInt32)0xff << 8 * 1) ) \ - | ( ( (UInt64)(v) >> 8 * 7 ) ) \ - ) - -#endif - - - -#ifdef MY_CPU_LE - #if defined(MY_CPU_X86_OR_AMD64) \ - || defined(MY_CPU_ARM64) \ - || defined(MY_CPU_RISCV) && defined(__riscv_misaligned_fast) \ - || defined(MY_CPU_E2K) && defined(__iset__) && (__iset__ >= 6) - #define MY_CPU_LE_UNALIGN - #define MY_CPU_LE_UNALIGN_64 - #elif defined(__ARM_FEATURE_UNALIGNED) -/* === ALIGNMENT on 32-bit arm and LDRD/STRD/LDM/STM instructions. - Description of problems: -problem-1 : 32-bit ARM architecture: - multi-access (pair of 32-bit accesses) instructions (LDRD/STRD/LDM/STM) - require 32-bit (WORD) alignment (by 32-bit ARM architecture). - So there is "Alignment fault exception", if data is not aligned for 32-bit. - -problem-2 : 32-bit kernels and arm64 kernels: - 32-bit linux kernels provide fixup for these "paired" instruction "Alignment fault exception". - So unaligned paired-access instructions work via exception handler in kernel in 32-bit linux. - - But some arm64 kernels do not handle these faults in 32-bit programs. - So we have unhandled exception for such instructions. - Probably some new arm64 kernels have fixed it, and unaligned - paired-access instructions work in new kernels? - -problem-3 : compiler for 32-bit arm: - Compilers use LDRD/STRD/LDM/STM for UInt64 accesses - and for another cases where two 32-bit accesses are fused - to one multi-access instruction. - So UInt64 variables must be aligned for 32-bit, and each - 32-bit access must be aligned for 32-bit, if we want to - avoid "Alignment fault" exception (handled or unhandled). - -problem-4 : performace: - Even if unaligned access is handled by kernel, it will be slow. - So if we allow unaligned access, we can get fast unaligned - single-access, and slow unaligned paired-access. - - We don't allow unaligned access on 32-bit arm, because compiler - genarates paired-access instructions that require 32-bit alignment, - and some arm64 kernels have no handler for these instructions. - Also unaligned paired-access instructions will be slow, if kernel handles them. -*/ - // it must be disabled: - // #define MY_CPU_LE_UNALIGN - #endif -#endif - - -#ifdef MY_CPU_LE_UNALIGN - -#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) -#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) -#ifdef MY_CPU_LE_UNALIGN_64 -#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) -#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); } -#endif - -#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); } -#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); } - -#else - -#define GetUi16(p) ( (UInt16) ( \ - ((const Byte *)(p))[0] | \ - ((UInt16)((const Byte *)(p))[1] << 8) )) - -#define GetUi32(p) ( \ - ((const Byte *)(p))[0] | \ - ((UInt32)((const Byte *)(p))[1] << 8) | \ - ((UInt32)((const Byte *)(p))[2] << 16) | \ - ((UInt32)((const Byte *)(p))[3] << 24)) - -#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ - _ppp_[0] = (Byte)_vvv_; \ - _ppp_[1] = (Byte)(_vvv_ >> 8); } - -#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ - _ppp_[0] = (Byte)_vvv_; \ - _ppp_[1] = (Byte)(_vvv_ >> 8); \ - _ppp_[2] = (Byte)(_vvv_ >> 16); \ - _ppp_[3] = (Byte)(_vvv_ >> 24); } - -#endif - - -#ifndef GetUi64 -#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) -#endif - -#ifndef SetUi64 -#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ - SetUi32(_ppp2_ , (UInt32)_vvv2_) \ - SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)) } -#endif - - -#if defined(MY_CPU_LE_UNALIGN) && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) - -#define GetBe32(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p)) -#define SetBe32(p, v) { (*(UInt32 *)(void *)(p)) = Z7_BSWAP32(v); } - -#if defined(MY_CPU_LE_UNALIGN_64) -#define GetBe64(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p)) -#endif - -#else - -#define GetBe32(p) ( \ - ((UInt32)((const Byte *)(p))[0] << 24) | \ - ((UInt32)((const Byte *)(p))[1] << 16) | \ - ((UInt32)((const Byte *)(p))[2] << 8) | \ - ((const Byte *)(p))[3] ) - -#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ - _ppp_[0] = (Byte)(_vvv_ >> 24); \ - _ppp_[1] = (Byte)(_vvv_ >> 16); \ - _ppp_[2] = (Byte)(_vvv_ >> 8); \ - _ppp_[3] = (Byte)_vvv_; } - -#endif - -#ifndef GetBe64 -#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) -#endif - -#ifndef GetBe16 -#define GetBe16(p) ( (UInt16) ( \ - ((UInt16)((const Byte *)(p))[0] << 8) | \ - ((const Byte *)(p))[1] )) -#endif - - -#if defined(MY_CPU_BE) -#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v) -#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) -#define Z7_CONV_NATIVE_TO_BE_32(v) (v) -#elif defined(MY_CPU_LE) -#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) -#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v) -#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v) -#else -#error Stop_Compiling_Unknown_Endian_CONV -#endif - - -#if defined(MY_CPU_BE) - -#define GetBe64a(p) (*(const UInt64 *)(const void *)(p)) -#define GetBe32a(p) (*(const UInt32 *)(const void *)(p)) -#define GetBe16a(p) (*(const UInt16 *)(const void *)(p)) -#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); } -#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); } - -#define GetUi64a(p) GetUi64(p) -#define GetUi32a(p) GetUi32(p) -#define GetUi16a(p) GetUi16(p) -#define SetUi32a(p, v) SetUi32(p, v) -#define SetUi16a(p, v) SetUi16(p, v) - -#elif defined(MY_CPU_LE) - -#define GetUi64a(p) (*(const UInt64 *)(const void *)(p)) -#define GetUi32a(p) (*(const UInt32 *)(const void *)(p)) -#define GetUi16a(p) (*(const UInt16 *)(const void *)(p)) -#define SetUi32a(p, v) { *(UInt32 *)(void *)(p) = (v); } -#define SetUi16a(p, v) { *(UInt16 *)(void *)(p) = (v); } - -#define GetBe64a(p) GetBe64(p) -#define GetBe32a(p) GetBe32(p) -#define GetBe16a(p) GetBe16(p) -#define SetBe32a(p, v) SetBe32(p, v) -#define SetBe16a(p, v) SetBe16(p, v) - -#else -#error Stop_Compiling_Unknown_Endian_CPU_a -#endif - - -#if defined(MY_CPU_X86_OR_AMD64) \ - || defined(MY_CPU_ARM_OR_ARM64) \ - || defined(MY_CPU_PPC_OR_PPC64) - #define Z7_CPU_FAST_ROTATE_SUPPORTED -#endif - - -#ifdef MY_CPU_X86_OR_AMD64 - -void Z7_FASTCALL z7_x86_cpuid(UInt32 a[4], UInt32 function); -UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void); -#if defined(MY_CPU_AMD64) -#define Z7_IF_X86_CPUID_SUPPORTED -#else -#define Z7_IF_X86_CPUID_SUPPORTED if (z7_x86_cpuid_GetMaxFunc()) -#endif - -BoolInt CPU_IsSupported_AES(void); -BoolInt CPU_IsSupported_AVX(void); -BoolInt CPU_IsSupported_AVX2(void); -BoolInt CPU_IsSupported_AVX512F_AVX512VL(void); -BoolInt CPU_IsSupported_VAES_AVX2(void); -BoolInt CPU_IsSupported_CMOV(void); -BoolInt CPU_IsSupported_SSE(void); -BoolInt CPU_IsSupported_SSE2(void); -BoolInt CPU_IsSupported_SSSE3(void); -BoolInt CPU_IsSupported_SSE41(void); -BoolInt CPU_IsSupported_SHA(void); -BoolInt CPU_IsSupported_PageGB(void); - -#elif defined(MY_CPU_ARM_OR_ARM64) - -BoolInt CPU_IsSupported_CRC32(void); -BoolInt CPU_IsSupported_NEON(void); - -#if defined(_WIN32) -BoolInt CPU_IsSupported_CRYPTO(void); -#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO -#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO -#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO -#else -BoolInt CPU_IsSupported_SHA1(void); -BoolInt CPU_IsSupported_SHA2(void); -BoolInt CPU_IsSupported_AES(void); -#endif - -#endif - -#if defined(__APPLE__) -int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize); -int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val); -#endif - -EXTERN_C_END - -#endif +/* CpuArch.h -- CPU specific code +Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_CPU_ARCH_H +#define ZIP7_INC_CPU_ARCH_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +MY_CPU_LE means that CPU is LITTLE ENDIAN. +MY_CPU_BE means that CPU is BIG ENDIAN. +If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. + +MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. + +MY_CPU_64BIT means that processor can work with 64-bit registers. + MY_CPU_64BIT can be used to select fast code branch + MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8) +*/ + +#if !defined(_M_ARM64EC) +#if defined(_M_X64) \ + || defined(_M_AMD64) \ + || defined(__x86_64__) \ + || defined(__AMD64__) \ + || defined(__amd64__) + #define MY_CPU_AMD64 + #ifdef __ILP32__ + #define MY_CPU_NAME "x32" + #define MY_CPU_SIZEOF_POINTER 4 + #else + #define MY_CPU_NAME "x64" + #define MY_CPU_SIZEOF_POINTER 8 + #endif + #define MY_CPU_64BIT +#endif +#endif + + +#if defined(_M_IX86) \ + || defined(__i386__) + #define MY_CPU_X86 + #define MY_CPU_NAME "x86" + /* #define MY_CPU_32BIT */ + #define MY_CPU_SIZEOF_POINTER 4 +#endif + + +#if defined(_M_ARM64) \ + || defined(_M_ARM64EC) \ + || defined(__AARCH64EL__) \ + || defined(__AARCH64EB__) \ + || defined(__aarch64__) + #define MY_CPU_ARM64 +#if defined(__ILP32__) \ + || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4) + #define MY_CPU_NAME "arm64-32" + #define MY_CPU_SIZEOF_POINTER 4 +#elif defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) + #define MY_CPU_NAME "arm64-128" + #define MY_CPU_SIZEOF_POINTER 16 +#else +#if defined(_M_ARM64EC) + #define MY_CPU_NAME "arm64ec" +#else + #define MY_CPU_NAME "arm64" +#endif + #define MY_CPU_SIZEOF_POINTER 8 +#endif + #define MY_CPU_64BIT +#endif + + +#if defined(_M_ARM) \ + || defined(_M_ARM_NT) \ + || defined(_M_ARMT) \ + || defined(__arm__) \ + || defined(__thumb__) \ + || defined(__ARMEL__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEL__) \ + || defined(__THUMBEB__) + #define MY_CPU_ARM + + #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT) + #define MY_CPU_ARMT + #define MY_CPU_NAME "armt" + #else + #define MY_CPU_ARM32 + #define MY_CPU_NAME "arm" + #endif + /* #define MY_CPU_32BIT */ + #define MY_CPU_SIZEOF_POINTER 4 +#endif + + +#if defined(_M_IA64) \ + || defined(__ia64__) + #define MY_CPU_IA64 + #define MY_CPU_NAME "ia64" + #define MY_CPU_64BIT +#endif + + +#if defined(__mips64) \ + || defined(__mips64__) \ + || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3)) + #define MY_CPU_NAME "mips64" + #define MY_CPU_64BIT +#elif defined(__mips__) + #define MY_CPU_NAME "mips" + /* #define MY_CPU_32BIT */ +#endif + + +#if defined(__ppc64__) \ + || defined(__powerpc64__) \ + || defined(__ppc__) \ + || defined(__powerpc__) \ + || defined(__PPC__) \ + || defined(_POWER) + +#define MY_CPU_PPC_OR_PPC64 + +#if defined(__ppc64__) \ + || defined(__powerpc64__) \ + || defined(_LP64) \ + || defined(__64BIT__) + #ifdef __ILP32__ + #define MY_CPU_NAME "ppc64-32" + #define MY_CPU_SIZEOF_POINTER 4 + #else + #define MY_CPU_NAME "ppc64" + #define MY_CPU_SIZEOF_POINTER 8 + #endif + #define MY_CPU_64BIT +#else + #define MY_CPU_NAME "ppc" + #define MY_CPU_SIZEOF_POINTER 4 + /* #define MY_CPU_32BIT */ +#endif +#endif + + +#if defined(__sparc__) \ + || defined(__sparc) + #define MY_CPU_SPARC + #if defined(__LP64__) \ + || defined(_LP64) \ + || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8) + #define MY_CPU_NAME "sparcv9" + #define MY_CPU_SIZEOF_POINTER 8 + #define MY_CPU_64BIT + #elif defined(__sparc_v9__) \ + || defined(__sparcv9) + #define MY_CPU_64BIT + #if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4) + #define MY_CPU_NAME "sparcv9-32" + #else + #define MY_CPU_NAME "sparcv9m" + #endif + #elif defined(__sparc_v8__) \ + || defined(__sparcv8) + #define MY_CPU_NAME "sparcv8" + #define MY_CPU_SIZEOF_POINTER 4 + #else + #define MY_CPU_NAME "sparc" + #endif +#endif + + +#if defined(__riscv) \ + || defined(__riscv__) + #define MY_CPU_RISCV + #if __riscv_xlen == 32 + #define MY_CPU_NAME "riscv32" + #elif __riscv_xlen == 64 + #define MY_CPU_NAME "riscv64" + #else + #define MY_CPU_NAME "riscv" + #endif +#endif + + +#if defined(__loongarch__) + #define MY_CPU_LOONGARCH + #if defined(__loongarch64) || defined(__loongarch_grlen) && (__loongarch_grlen == 64) + #define MY_CPU_64BIT + #endif + #if defined(__loongarch64) + #define MY_CPU_NAME "loongarch64" + #define MY_CPU_LOONGARCH64 + #else + #define MY_CPU_NAME "loongarch" + #endif +#endif + + +// #undef MY_CPU_NAME +// #undef MY_CPU_SIZEOF_POINTER +// #define __e2k__ +// #define __SIZEOF_POINTER__ 4 +#if defined(__e2k__) + #define MY_CPU_E2K + #if defined(__ILP32__) || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4) + #define MY_CPU_NAME "e2k-32" + #define MY_CPU_SIZEOF_POINTER 4 + #else + #define MY_CPU_NAME "e2k" + #if defined(__LP64__) || defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8) + #define MY_CPU_SIZEOF_POINTER 8 + #endif + #endif + #define MY_CPU_64BIT +#endif + + +#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) +#define MY_CPU_X86_OR_AMD64 +#endif + +#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64) +#define MY_CPU_ARM_OR_ARM64 +#endif + + +#ifdef _WIN32 + + #ifdef MY_CPU_ARM + #define MY_CPU_ARM_LE + #endif + + #ifdef MY_CPU_ARM64 + #define MY_CPU_ARM64_LE + #endif + + #ifdef _M_IA64 + #define MY_CPU_IA64_LE + #endif + +#endif + + +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_LE) \ + || defined(MY_CPU_ARM64_LE) \ + || defined(MY_CPU_IA64_LE) \ + || defined(_LITTLE_ENDIAN) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__AARCH64EL__) \ + || defined(__MIPSEL__) \ + || defined(__MIPSEL) \ + || defined(_MIPSEL) \ + || defined(__BFIN__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + #define MY_CPU_LE +#endif + +#if defined(__BIG_ENDIAN__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) \ + || defined(__AARCH64EB__) \ + || defined(__MIPSEB__) \ + || defined(__MIPSEB) \ + || defined(_MIPSEB) \ + || defined(__m68k__) \ + || defined(__s390__) \ + || defined(__s390x__) \ + || defined(__zarch__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define MY_CPU_BE +#endif + + +#if defined(MY_CPU_LE) && defined(MY_CPU_BE) + #error Stop_Compiling_Bad_Endian +#endif + +#if !defined(MY_CPU_LE) && !defined(MY_CPU_BE) + #error Stop_Compiling_CPU_ENDIAN_must_be_detected_at_compile_time +#endif + +#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT) + #error Stop_Compiling_Bad_32_64_BIT +#endif + +#ifdef __SIZEOF_POINTER__ + #ifdef MY_CPU_SIZEOF_POINTER + #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__ + #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE + #endif + #else + #define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__ + #endif +#endif + +#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) +#if defined (_LP64) + #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE +#endif +#endif + +#ifdef _MSC_VER + #if _MSC_VER >= 1300 + #define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1)) + #define MY_CPU_pragma_pop __pragma(pack(pop)) + #else + #define MY_CPU_pragma_pack_push_1 + #define MY_CPU_pragma_pop + #endif +#else + #ifdef __xlC__ + #define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)") + #define MY_CPU_pragma_pop _Pragma("pack()") + #else + #define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)") + #define MY_CPU_pragma_pop _Pragma("pack(pop)") + #endif +#endif + + +#ifndef MY_CPU_NAME + // #define MY_CPU_IS_UNKNOWN + #ifdef MY_CPU_LE + #define MY_CPU_NAME "LE" + #elif defined(MY_CPU_BE) + #define MY_CPU_NAME "BE" + #else + /* + #define MY_CPU_NAME "" + */ + #endif +#endif + + + + + +#ifdef __has_builtin + #define Z7_has_builtin(x) __has_builtin(x) +#else + #define Z7_has_builtin(x) 0 +#endif + + +#define Z7_BSWAP32_CONST(v) \ + ( (((UInt32)(v) << 24) ) \ + | (((UInt32)(v) << 8) & (UInt32)0xff0000) \ + | (((UInt32)(v) >> 8) & (UInt32)0xff00 ) \ + | (((UInt32)(v) >> 24) )) + + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) + +#include + +/* Note: these macros will use bswap instruction (486), that is unsupported in 386 cpu */ + +#pragma intrinsic(_byteswap_ushort) +#pragma intrinsic(_byteswap_ulong) +#pragma intrinsic(_byteswap_uint64) + +#define Z7_BSWAP16(v) _byteswap_ushort(v) +#define Z7_BSWAP32(v) _byteswap_ulong (v) +#define Z7_BSWAP64(v) _byteswap_uint64(v) +#define Z7_CPU_FAST_BSWAP_SUPPORTED + +/* GCC can generate slow code that calls function for __builtin_bswap32() for: + - GCC for RISCV, if Zbb/XTHeadBb extension is not used. + - GCC for SPARC. + The code from CLANG for SPARC also is not fastest. + So we don't define Z7_CPU_FAST_BSWAP_SUPPORTED in some cases. +*/ +#elif (!defined(MY_CPU_RISCV) || defined (__riscv_zbb) || defined(__riscv_xtheadbb)) \ + && !defined(MY_CPU_SPARC) \ + && ( \ + (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ + || (defined(__clang__) && Z7_has_builtin(__builtin_bswap16)) \ + ) + +#define Z7_BSWAP16(v) __builtin_bswap16(v) +#define Z7_BSWAP32(v) __builtin_bswap32(v) +#define Z7_BSWAP64(v) __builtin_bswap64(v) +#define Z7_CPU_FAST_BSWAP_SUPPORTED + +#else + +#define Z7_BSWAP16(v) ((UInt16) \ + ( ((UInt32)(v) << 8) \ + | ((UInt32)(v) >> 8) \ + )) + +#define Z7_BSWAP32(v) Z7_BSWAP32_CONST(v) + +#define Z7_BSWAP64(v) \ + ( ( ( (UInt64)(v) ) << 8 * 7 ) \ + | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 1) ) << 8 * 5 ) \ + | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 2) ) << 8 * 3 ) \ + | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 3) ) << 8 * 1 ) \ + | ( ( (UInt64)(v) >> 8 * 1 ) & ((UInt32)0xff << 8 * 3) ) \ + | ( ( (UInt64)(v) >> 8 * 3 ) & ((UInt32)0xff << 8 * 2) ) \ + | ( ( (UInt64)(v) >> 8 * 5 ) & ((UInt32)0xff << 8 * 1) ) \ + | ( ( (UInt64)(v) >> 8 * 7 ) ) \ + ) + +#endif + + + +#ifdef MY_CPU_LE + #if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM64) \ + || defined(MY_CPU_RISCV) && defined(__riscv_misaligned_fast) \ + || defined(MY_CPU_E2K) && defined(__iset__) && (__iset__ >= 6) + #define MY_CPU_LE_UNALIGN + #define MY_CPU_LE_UNALIGN_64 + #elif defined(__ARM_FEATURE_UNALIGNED) +/* === ALIGNMENT on 32-bit arm and LDRD/STRD/LDM/STM instructions. + Description of problems: +problem-1 : 32-bit ARM architecture: + multi-access (pair of 32-bit accesses) instructions (LDRD/STRD/LDM/STM) + require 32-bit (WORD) alignment (by 32-bit ARM architecture). + So there is "Alignment fault exception", if data is not aligned for 32-bit. + +problem-2 : 32-bit kernels and arm64 kernels: + 32-bit linux kernels provide fixup for these "paired" instruction "Alignment fault exception". + So unaligned paired-access instructions work via exception handler in kernel in 32-bit linux. + + But some arm64 kernels do not handle these faults in 32-bit programs. + So we have unhandled exception for such instructions. + Probably some new arm64 kernels have fixed it, and unaligned + paired-access instructions work in new kernels? + +problem-3 : compiler for 32-bit arm: + Compilers use LDRD/STRD/LDM/STM for UInt64 accesses + and for another cases where two 32-bit accesses are fused + to one multi-access instruction. + So UInt64 variables must be aligned for 32-bit, and each + 32-bit access must be aligned for 32-bit, if we want to + avoid "Alignment fault" exception (handled or unhandled). + +problem-4 : performace: + Even if unaligned access is handled by kernel, it will be slow. + So if we allow unaligned access, we can get fast unaligned + single-access, and slow unaligned paired-access. + + We don't allow unaligned access on 32-bit arm, because compiler + genarates paired-access instructions that require 32-bit alignment, + and some arm64 kernels have no handler for these instructions. + Also unaligned paired-access instructions will be slow, if kernel handles them. +*/ + // it must be disabled: + // #define MY_CPU_LE_UNALIGN + #endif +#endif + + +#ifdef MY_CPU_LE_UNALIGN + +#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) +#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) +#ifdef MY_CPU_LE_UNALIGN_64 +#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) +#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); } +#endif + +#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); } + +#else + +#define GetUi16(p) ( (UInt16) ( \ + ((const Byte *)(p))[0] | \ + ((UInt16)((const Byte *)(p))[1] << 8) )) + +#define GetUi32(p) ( \ + ((const Byte *)(p))[0] | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((UInt32)((const Byte *)(p))[2] << 16) | \ + ((UInt32)((const Byte *)(p))[3] << 24)) + +#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); } + +#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); \ + _ppp_[2] = (Byte)(_vvv_ >> 16); \ + _ppp_[3] = (Byte)(_vvv_ >> 24); } + +#endif + + +#ifndef GetUi64 +#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) +#endif + +#ifndef SetUi64 +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_) \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)) } +#endif + + +#if defined(MY_CPU_LE_UNALIGN) && defined(Z7_CPU_FAST_BSWAP_SUPPORTED) + +#if 0 +// Z7_BSWAP16 can be slow for x86-msvc +#define GetBe16_to32(p) (Z7_BSWAP16 (*(const UInt16 *)(const void *)(p))) +#else +#define GetBe16_to32(p) (Z7_BSWAP32 (*(const UInt16 *)(const void *)(p)) >> 16) +#endif + +#define GetBe32(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p)) +#define SetBe32(p, v) { (*(UInt32 *)(void *)(p)) = Z7_BSWAP32(v); } + +#if defined(MY_CPU_LE_UNALIGN_64) +#define GetBe64(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p)) +#define SetBe64(p, v) { (*(UInt64 *)(void *)(p)) = Z7_BSWAP64(v); } +#endif + +#else + +#define GetBe32(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 24) | \ + ((UInt32)((const Byte *)(p))[1] << 16) | \ + ((UInt32)((const Byte *)(p))[2] << 8) | \ + ((const Byte *)(p))[3] ) + +#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 24); \ + _ppp_[1] = (Byte)(_vvv_ >> 16); \ + _ppp_[2] = (Byte)(_vvv_ >> 8); \ + _ppp_[3] = (Byte)_vvv_; } + +#endif + +#ifndef GetBe64 +#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) +#endif + +#ifndef SetBe64 +#define SetBe64(p, v) { Byte *_ppp_ = (Byte *)(p); UInt64 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 56); \ + _ppp_[1] = (Byte)(_vvv_ >> 48); \ + _ppp_[2] = (Byte)(_vvv_ >> 40); \ + _ppp_[3] = (Byte)(_vvv_ >> 32); \ + _ppp_[4] = (Byte)(_vvv_ >> 24); \ + _ppp_[5] = (Byte)(_vvv_ >> 16); \ + _ppp_[6] = (Byte)(_vvv_ >> 8); \ + _ppp_[7] = (Byte)_vvv_; } +#endif + +#ifndef GetBe16 +#ifdef GetBe16_to32 +#define GetBe16(p) ( (UInt16) GetBe16_to32(p)) +#else +#define GetBe16(p) ( (UInt16) ( \ + ((UInt16)((const Byte *)(p))[0] << 8) | \ + ((const Byte *)(p))[1] )) +#endif +#endif + + +#if defined(MY_CPU_BE) +#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v) +#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) +#define Z7_CONV_NATIVE_TO_BE_32(v) (v) +#elif defined(MY_CPU_LE) +#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v) +#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v) +#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v) +#else +#error Stop_Compiling_Unknown_Endian_CONV +#endif + + +#if defined(MY_CPU_BE) + +#define GetBe64a(p) (*(const UInt64 *)(const void *)(p)) +#define GetBe32a(p) (*(const UInt32 *)(const void *)(p)) +#define GetBe16a(p) (*(const UInt16 *)(const void *)(p)) +#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); } +#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); } + +#define GetUi64a(p) GetUi64(p) +#define GetUi32a(p) GetUi32(p) +#define GetUi16a(p) GetUi16(p) +#define SetUi32a(p, v) SetUi32(p, v) +#define SetUi16a(p, v) SetUi16(p, v) + +#elif defined(MY_CPU_LE) + +#define GetUi64a(p) (*(const UInt64 *)(const void *)(p)) +#define GetUi32a(p) (*(const UInt32 *)(const void *)(p)) +#define GetUi16a(p) (*(const UInt16 *)(const void *)(p)) +#define SetUi32a(p, v) { *(UInt32 *)(void *)(p) = (v); } +#define SetUi16a(p, v) { *(UInt16 *)(void *)(p) = (v); } + +#define GetBe64a(p) GetBe64(p) +#define GetBe32a(p) GetBe32(p) +#define GetBe16a(p) GetBe16(p) +#define SetBe32a(p, v) SetBe32(p, v) +#define SetBe16a(p, v) SetBe16(p, v) + +#else +#error Stop_Compiling_Unknown_Endian_CPU_a +#endif + + +#ifndef GetBe16_to32 +#define GetBe16_to32(p) GetBe16(p) +#endif + + +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_OR_ARM64) \ + || defined(MY_CPU_PPC_OR_PPC64) + #define Z7_CPU_FAST_ROTATE_SUPPORTED +#endif + + +#ifdef MY_CPU_X86_OR_AMD64 + +void Z7_FASTCALL z7_x86_cpuid(UInt32 a[4], UInt32 function); +UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void); +#if defined(MY_CPU_AMD64) +#define Z7_IF_X86_CPUID_SUPPORTED +#else +#define Z7_IF_X86_CPUID_SUPPORTED if (z7_x86_cpuid_GetMaxFunc()) +#endif + +BoolInt CPU_IsSupported_AES(void); +BoolInt CPU_IsSupported_AVX(void); +BoolInt CPU_IsSupported_AVX2(void); +BoolInt CPU_IsSupported_AVX512F_AVX512VL(void); +BoolInt CPU_IsSupported_VAES_AVX2(void); +BoolInt CPU_IsSupported_CMOV(void); +BoolInt CPU_IsSupported_SSE(void); +BoolInt CPU_IsSupported_SSE2(void); +BoolInt CPU_IsSupported_SSSE3(void); +BoolInt CPU_IsSupported_SSE41(void); +BoolInt CPU_IsSupported_SHA(void); +BoolInt CPU_IsSupported_SHA512(void); +BoolInt CPU_IsSupported_PageGB(void); + +#elif defined(MY_CPU_ARM_OR_ARM64) + +BoolInt CPU_IsSupported_CRC32(void); +BoolInt CPU_IsSupported_NEON(void); + +#if defined(_WIN32) +BoolInt CPU_IsSupported_CRYPTO(void); +#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO +#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO +#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO +#else +BoolInt CPU_IsSupported_SHA1(void); +BoolInt CPU_IsSupported_SHA2(void); +BoolInt CPU_IsSupported_AES(void); +#endif +BoolInt CPU_IsSupported_SHA512(void); + +#endif + +#if defined(__APPLE__) +int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize); +int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val); +#endif + +EXTERN_C_END + +#endif diff --git a/C/Delta.c b/C/Delta.c index fc7e9fe96..c4a4499fe 100644 --- a/C/Delta.c +++ b/C/Delta.c @@ -1,169 +1,169 @@ -/* Delta.c -- Delta converter -2021-02-09 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Delta.h" - -void Delta_Init(Byte *state) -{ - unsigned i; - for (i = 0; i < DELTA_STATE_SIZE; i++) - state[i] = 0; -} - - -void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) -{ - Byte temp[DELTA_STATE_SIZE]; - - if (size == 0) - return; - - { - unsigned i = 0; - do - temp[i] = state[i]; - while (++i != delta); - } - - if (size <= delta) - { - unsigned i = 0, k; - do - { - Byte b = *data; - *data++ = (Byte)(b - temp[i]); - temp[i] = b; - } - while (++i != size); - - k = 0; - - do - { - if (i == delta) - i = 0; - state[k] = temp[i++]; - } - while (++k != delta); - - return; - } - - { - Byte *p = data + size - delta; - { - unsigned i = 0; - do - state[i] = *p++; - while (++i != delta); - } - { - const Byte *lim = data + delta; - ptrdiff_t dif = -(ptrdiff_t)delta; - - if (((ptrdiff_t)size + dif) & 1) - { - --p; *p = (Byte)(*p - p[dif]); - } - - while (p != lim) - { - --p; *p = (Byte)(*p - p[dif]); - --p; *p = (Byte)(*p - p[dif]); - } - - dif = -dif; - - do - { - --p; *p = (Byte)(*p - temp[--dif]); - } - while (dif != 0); - } - } -} - - -void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) -{ - unsigned i; - const Byte *lim; - - if (size == 0) - return; - - i = 0; - lim = data + size; - - if (size <= delta) - { - do - *data = (Byte)(*data + state[i++]); - while (++data != lim); - - for (; delta != i; state++, delta--) - *state = state[i]; - data -= i; - } - else - { - /* - #define B(n) b ## n - #define I(n) Byte B(n) = state[n]; - #define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); } - #define F(n) if (data != lim) { U(n) } - - if (delta == 1) - { - I(0) - if ((lim - data) & 1) { U(0) } - while (data != lim) { U(0) U(0) } - data -= 1; - } - else if (delta == 2) - { - I(0) I(1) - lim -= 1; while (data < lim) { U(0) U(1) } - lim += 1; F(0) - data -= 2; - } - else if (delta == 3) - { - I(0) I(1) I(2) - lim -= 2; while (data < lim) { U(0) U(1) U(2) } - lim += 2; F(0) F(1) - data -= 3; - } - else if (delta == 4) - { - I(0) I(1) I(2) I(3) - lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) } - lim += 3; F(0) F(1) F(2) - data -= 4; - } - else - */ - { - do - { - *data = (Byte)(*data + state[i++]); - data++; - } - while (i != delta); - - { - ptrdiff_t dif = -(ptrdiff_t)delta; - do - *data = (Byte)(*data + data[dif]); - while (++data != lim); - data += dif; - } - } - } - - do - *state++ = *data; - while (++data != lim); -} +/* Delta.c -- Delta converter +2021-02-09 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Delta.h" + +void Delta_Init(Byte *state) +{ + unsigned i; + for (i = 0; i < DELTA_STATE_SIZE; i++) + state[i] = 0; +} + + +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + Byte temp[DELTA_STATE_SIZE]; + + if (size == 0) + return; + + { + unsigned i = 0; + do + temp[i] = state[i]; + while (++i != delta); + } + + if (size <= delta) + { + unsigned i = 0, k; + do + { + Byte b = *data; + *data++ = (Byte)(b - temp[i]); + temp[i] = b; + } + while (++i != size); + + k = 0; + + do + { + if (i == delta) + i = 0; + state[k] = temp[i++]; + } + while (++k != delta); + + return; + } + + { + Byte *p = data + size - delta; + { + unsigned i = 0; + do + state[i] = *p++; + while (++i != delta); + } + { + const Byte *lim = data + delta; + ptrdiff_t dif = -(ptrdiff_t)delta; + + if (((ptrdiff_t)size + dif) & 1) + { + --p; *p = (Byte)(*p - p[dif]); + } + + while (p != lim) + { + --p; *p = (Byte)(*p - p[dif]); + --p; *p = (Byte)(*p - p[dif]); + } + + dif = -dif; + + do + { + --p; *p = (Byte)(*p - temp[--dif]); + } + while (dif != 0); + } + } +} + + +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size) +{ + unsigned i; + const Byte *lim; + + if (size == 0) + return; + + i = 0; + lim = data + size; + + if (size <= delta) + { + do + *data = (Byte)(*data + state[i++]); + while (++data != lim); + + for (; delta != i; state++, delta--) + *state = state[i]; + data -= i; + } + else + { + /* + #define B(n) b ## n + #define I(n) Byte B(n) = state[n]; + #define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); } + #define F(n) if (data != lim) { U(n) } + + if (delta == 1) + { + I(0) + if ((lim - data) & 1) { U(0) } + while (data != lim) { U(0) U(0) } + data -= 1; + } + else if (delta == 2) + { + I(0) I(1) + lim -= 1; while (data < lim) { U(0) U(1) } + lim += 1; F(0) + data -= 2; + } + else if (delta == 3) + { + I(0) I(1) I(2) + lim -= 2; while (data < lim) { U(0) U(1) U(2) } + lim += 2; F(0) F(1) + data -= 3; + } + else if (delta == 4) + { + I(0) I(1) I(2) I(3) + lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) } + lim += 3; F(0) F(1) F(2) + data -= 4; + } + else + */ + { + do + { + *data = (Byte)(*data + state[i++]); + data++; + } + while (i != delta); + + { + ptrdiff_t dif = -(ptrdiff_t)delta; + do + *data = (Byte)(*data + data[dif]); + while (++data != lim); + data += dif; + } + } + } + + do + *state++ = *data; + while (++data != lim); +} diff --git a/C/Delta.h b/C/Delta.h index be77c6c6c..706095417 100644 --- a/C/Delta.h +++ b/C/Delta.h @@ -1,19 +1,19 @@ -/* Delta.h -- Delta converter -2023-03-03 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_DELTA_H -#define ZIP7_INC_DELTA_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define DELTA_STATE_SIZE 256 - -void Delta_Init(Byte *state); -void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); -void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); - -EXTERN_C_END - -#endif +/* Delta.h -- Delta converter +2023-03-03 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_DELTA_H +#define ZIP7_INC_DELTA_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define DELTA_STATE_SIZE 256 + +void Delta_Init(Byte *state); +void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size); +void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size); + +EXTERN_C_END + +#endif diff --git a/C/DllSecur.c b/C/DllSecur.c index d65f7edc9..bbbfc0a76 100644 --- a/C/DllSecur.c +++ b/C/DllSecur.c @@ -1,99 +1,99 @@ -/* DllSecur.c -- DLL loading security -2023-12-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#ifdef _WIN32 - -#include "7zWindows.h" - -#include "DllSecur.h" - -#ifndef UNDER_CE - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); - -#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 -#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 - -#define DELIM "\0" - -static const char * const g_Dlls = - "userenv" - DELIM "setupapi" - DELIM "apphelp" - DELIM "propsys" - DELIM "dwmapi" - DELIM "cryptbase" - DELIM "oleacc" - DELIM "clbcatq" - DELIM "version" - #ifndef _CONSOLE - DELIM "uxtheme" - #endif - DELIM; - -#endif - -#ifdef __clang__ - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif -#if defined (_MSC_VER) && _MSC_VER >= 1900 -// sysinfoapi.h: kit10: GetVersion was declared deprecated -#pragma warning(disable : 4996) -#endif - -#define IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN \ - if ((UInt16)GetVersion() != 6) { \ - const \ - Func_SetDefaultDllDirectories setDllDirs = \ - (Func_SetDefaultDllDirectories) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), \ - "SetDefaultDllDirectories"); \ - if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; } - -void My_SetDefaultDllDirectories(void) -{ - #ifndef UNDER_CE - IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN - #endif -} - - -void LoadSecurityDlls(void) -{ - #ifndef UNDER_CE - // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ??? - IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN - { - wchar_t buf[MAX_PATH + 100]; - const char *dll; - unsigned pos = GetSystemDirectoryW(buf, MAX_PATH + 2); - if (pos == 0 || pos > MAX_PATH) - return; - if (buf[pos - 1] != '\\') - buf[pos++] = '\\'; - for (dll = g_Dlls; *dll != 0;) - { - wchar_t *dest = &buf[pos]; - for (;;) - { - const char c = *dll++; - if (c == 0) - break; - *dest++ = (Byte)c; - } - dest[0] = '.'; - dest[1] = 'd'; - dest[2] = 'l'; - dest[3] = 'l'; - dest[4] = 0; - // lstrcatW(buf, L".dll"); - LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - } - } - #endif -} - -#endif // _WIN32 +/* DllSecur.c -- DLL loading security +2023-12-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 + +#include "7zWindows.h" + +#include "DllSecur.h" + +#ifndef UNDER_CE + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); + +#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 +#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800 + +#define DELIM "\0" + +static const char * const g_Dlls = + "userenv" + DELIM "setupapi" + DELIM "apphelp" + DELIM "propsys" + DELIM "dwmapi" + DELIM "cryptbase" + DELIM "oleacc" + DELIM "clbcatq" + DELIM "version" + #ifndef _CONSOLE + DELIM "uxtheme" + #endif + DELIM; + +#endif + +#ifdef __clang__ + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +#if defined (_MSC_VER) && _MSC_VER >= 1900 +// sysinfoapi.h: kit10: GetVersion was declared deprecated +#pragma warning(disable : 4996) +#endif + +#define IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN \ + if ((UInt16)GetVersion() != 6) { \ + const \ + Func_SetDefaultDllDirectories setDllDirs = \ + (Func_SetDefaultDllDirectories) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), \ + "SetDefaultDllDirectories"); \ + if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; } + +void My_SetDefaultDllDirectories(void) +{ + #ifndef UNDER_CE + IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN + #endif +} + + +void LoadSecurityDlls(void) +{ + #ifndef UNDER_CE + // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ??? + IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN + { + wchar_t buf[MAX_PATH + 100]; + const char *dll; + unsigned pos = GetSystemDirectoryW(buf, MAX_PATH + 2); + if (pos == 0 || pos > MAX_PATH) + return; + if (buf[pos - 1] != '\\') + buf[pos++] = '\\'; + for (dll = g_Dlls; *dll != 0;) + { + wchar_t *dest = &buf[pos]; + for (;;) + { + const char c = *dll++; + if (c == 0) + break; + *dest++ = (Byte)c; + } + dest[0] = '.'; + dest[1] = 'd'; + dest[2] = 'l'; + dest[3] = 'l'; + dest[4] = 0; + // lstrcatW(buf, L".dll"); + LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + } + } + #endif +} + +#endif // _WIN32 diff --git a/C/DllSecur.h b/C/DllSecur.h index 87bacc637..9fa415382 100644 --- a/C/DllSecur.h +++ b/C/DllSecur.h @@ -1,20 +1,20 @@ -/* DllSecur.h -- DLL loading for security -2023-03-03 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_DLL_SECUR_H -#define ZIP7_INC_DLL_SECUR_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#ifdef _WIN32 - -void My_SetDefaultDllDirectories(void); -void LoadSecurityDlls(void); - -#endif - -EXTERN_C_END - -#endif +/* DllSecur.h -- DLL loading for security +2023-03-03 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_DLL_SECUR_H +#define ZIP7_INC_DLL_SECUR_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#ifdef _WIN32 + +void My_SetDefaultDllDirectories(void); +void LoadSecurityDlls(void); + +#endif + +EXTERN_C_END + +#endif diff --git a/C/HuffEnc.c b/C/HuffEnc.c index 98e68b490..996da302c 100644 --- a/C/HuffEnc.c +++ b/C/HuffEnc.c @@ -1,154 +1,154 @@ -/* HuffEnc.c -- functions for Huffman encoding -2023-09-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "HuffEnc.h" -#include "Sort.h" - -#define kMaxLen 16 -#define NUM_BITS 10 -#define MASK ((1u << NUM_BITS) - 1) - -#define NUM_COUNTERS 64 - -#define HUFFMAN_SPEED_OPT - -void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen) -{ - UInt32 num = 0; - /* if (maxLen > 10) maxLen = 10; */ - { - UInt32 i; - - #ifdef HUFFMAN_SPEED_OPT - - UInt32 counters[NUM_COUNTERS]; - for (i = 0; i < NUM_COUNTERS; i++) - counters[i] = 0; - for (i = 0; i < numSymbols; i++) - { - UInt32 freq = freqs[i]; - counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++; - } - - for (i = 1; i < NUM_COUNTERS; i++) - { - UInt32 temp = counters[i]; - counters[i] = num; - num += temp; - } - - for (i = 0; i < numSymbols; i++) - { - UInt32 freq = freqs[i]; - if (freq == 0) - lens[i] = 0; - else - p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS); - } - counters[0] = 0; - HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); - - #else - - for (i = 0; i < numSymbols; i++) - { - UInt32 freq = freqs[i]; - if (freq == 0) - lens[i] = 0; - else - p[num++] = i | (freq << NUM_BITS); - } - HeapSort(p, num); - - #endif - } - - if (num < 2) - { - unsigned minCode = 0; - unsigned maxCode = 1; - if (num == 1) - { - maxCode = (unsigned)p[0] & MASK; - if (maxCode == 0) - maxCode++; - } - p[minCode] = 0; - p[maxCode] = 1; - lens[minCode] = lens[maxCode] = 1; - return; - } - - { - UInt32 b, e, i; - - i = b = e = 0; - do - { - UInt32 n, m, freq; - n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; - freq = (p[n] & ~MASK); - p[n] = (p[n] & MASK) | (e << NUM_BITS); - m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; - freq += (p[m] & ~MASK); - p[m] = (p[m] & MASK) | (e << NUM_BITS); - p[e] = (p[e] & MASK) | freq; - e++; - } - while (num - e > 1); - - { - UInt32 lenCounters[kMaxLen + 1]; - for (i = 0; i <= kMaxLen; i++) - lenCounters[i] = 0; - - p[--e] &= MASK; - lenCounters[1] = 2; - while (e != 0) - { - UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1; - p[e] = (p[e] & MASK) | (len << NUM_BITS); - if (len >= maxLen) - for (len = maxLen - 1; lenCounters[len] == 0; len--); - lenCounters[len]--; - lenCounters[(size_t)len + 1] += 2; - } - - { - UInt32 len; - i = 0; - for (len = maxLen; len != 0; len--) - { - UInt32 k; - for (k = lenCounters[len]; k != 0; k--) - lens[p[i++] & MASK] = (Byte)len; - } - } - - { - UInt32 nextCodes[kMaxLen + 1]; - { - UInt32 code = 0; - UInt32 len; - for (len = 1; len <= kMaxLen; len++) - nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1; - } - /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */ - - { - UInt32 k; - for (k = 0; k < numSymbols; k++) - p[k] = nextCodes[lens[k]]++; - } - } - } - } -} - -#undef kMaxLen -#undef NUM_BITS -#undef MASK -#undef NUM_COUNTERS -#undef HUFFMAN_SPEED_OPT +/* HuffEnc.c -- functions for Huffman encoding +2023-09-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "HuffEnc.h" +#include "Sort.h" + +#define kMaxLen 16 +#define NUM_BITS 10 +#define MASK ((1u << NUM_BITS) - 1) + +#define NUM_COUNTERS 64 + +#define HUFFMAN_SPEED_OPT + +void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen) +{ + UInt32 num = 0; + /* if (maxLen > 10) maxLen = 10; */ + { + UInt32 i; + + #ifdef HUFFMAN_SPEED_OPT + + UInt32 counters[NUM_COUNTERS]; + for (i = 0; i < NUM_COUNTERS; i++) + counters[i] = 0; + for (i = 0; i < numSymbols; i++) + { + UInt32 freq = freqs[i]; + counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++; + } + + for (i = 1; i < NUM_COUNTERS; i++) + { + UInt32 temp = counters[i]; + counters[i] = num; + num += temp; + } + + for (i = 0; i < numSymbols; i++) + { + UInt32 freq = freqs[i]; + if (freq == 0) + lens[i] = 0; + else + p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS); + } + counters[0] = 0; + HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]); + + #else + + for (i = 0; i < numSymbols; i++) + { + UInt32 freq = freqs[i]; + if (freq == 0) + lens[i] = 0; + else + p[num++] = i | (freq << NUM_BITS); + } + HeapSort(p, num); + + #endif + } + + if (num < 2) + { + unsigned minCode = 0; + unsigned maxCode = 1; + if (num == 1) + { + maxCode = (unsigned)p[0] & MASK; + if (maxCode == 0) + maxCode++; + } + p[minCode] = 0; + p[maxCode] = 1; + lens[minCode] = lens[maxCode] = 1; + return; + } + + { + UInt32 b, e, i; + + i = b = e = 0; + do + { + UInt32 n, m, freq; + n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; + freq = (p[n] & ~MASK); + p[n] = (p[n] & MASK) | (e << NUM_BITS); + m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++; + freq += (p[m] & ~MASK); + p[m] = (p[m] & MASK) | (e << NUM_BITS); + p[e] = (p[e] & MASK) | freq; + e++; + } + while (num - e > 1); + + { + UInt32 lenCounters[kMaxLen + 1]; + for (i = 0; i <= kMaxLen; i++) + lenCounters[i] = 0; + + p[--e] &= MASK; + lenCounters[1] = 2; + while (e != 0) + { + UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1; + p[e] = (p[e] & MASK) | (len << NUM_BITS); + if (len >= maxLen) + for (len = maxLen - 1; lenCounters[len] == 0; len--); + lenCounters[len]--; + lenCounters[(size_t)len + 1] += 2; + } + + { + UInt32 len; + i = 0; + for (len = maxLen; len != 0; len--) + { + UInt32 k; + for (k = lenCounters[len]; k != 0; k--) + lens[p[i++] & MASK] = (Byte)len; + } + } + + { + UInt32 nextCodes[kMaxLen + 1]; + { + UInt32 code = 0; + UInt32 len; + for (len = 1; len <= kMaxLen; len++) + nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1; + } + /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */ + + { + UInt32 k; + for (k = 0; k < numSymbols; k++) + p[k] = nextCodes[lens[k]]++; + } + } + } + } +} + +#undef kMaxLen +#undef NUM_BITS +#undef MASK +#undef NUM_COUNTERS +#undef HUFFMAN_SPEED_OPT diff --git a/C/HuffEnc.h b/C/HuffEnc.h index 8dc394437..cbc5d11f9 100644 --- a/C/HuffEnc.h +++ b/C/HuffEnc.h @@ -1,23 +1,23 @@ -/* HuffEnc.h -- Huffman encoding -2023-03-05 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_HUFF_ENC_H -#define ZIP7_INC_HUFF_ENC_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* -Conditions: - num <= 1024 = 2 ^ NUM_BITS - Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS) - maxLen <= 16 = kMaxLen - Num_Items(p) >= HUFFMAN_TEMP_SIZE(num) -*/ - -void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen); - -EXTERN_C_END - -#endif +/* HuffEnc.h -- Huffman encoding +2023-03-05 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_HUFF_ENC_H +#define ZIP7_INC_HUFF_ENC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* +Conditions: + num <= 1024 = 2 ^ NUM_BITS + Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS) + maxLen <= 16 = kMaxLen + Num_Items(p) >= HUFFMAN_TEMP_SIZE(num) +*/ + +void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen); + +EXTERN_C_END + +#endif diff --git a/C/LzFind.c b/C/LzFind.c index 8975fc200..1ce404648 100644 --- a/C/LzFind.c +++ b/C/LzFind.c @@ -1,1746 +1,1746 @@ -/* LzFind.c -- Match finder for LZ algorithms -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include -// #include - -#include "CpuArch.h" -#include "LzFind.h" -#include "LzHash.h" - -#define kBlockMoveAlign (1 << 7) // alignment for memmove() -#define kBlockSizeAlign (1 << 16) // alignment for block allocation -#define kBlockSizeReserveMin (1 << 24) // it's 1/256 from 4 GB dictinary - -#define kEmptyHashValue 0 - -#define kMaxValForNormalize ((UInt32)0) -// #define kMaxValForNormalize ((UInt32)(1 << 20) + 0xfff) // for debug - -// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses - -#define GET_AVAIL_BYTES(p) \ - Inline_MatchFinder_GetNumAvailableBytes(p) - - -// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) -#define kFix5HashSize kFix4HashSize - -/* - HASH2_CALC: - if (hv) match, then cur[0] and cur[1] also match -*/ -#define HASH2_CALC hv = GetUi16(cur); - -// (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255] - -/* - HASH3_CALC: - if (cur[0]) and (h2) match, then cur[1] also match - if (cur[0]) and (hv) match, then cur[1] and cur[2] also match -*/ -#define HASH3_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } - -#define HASH4_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - temp ^= ((UInt32)cur[2] << 8); \ - h3 = temp & (kHash3Size - 1); \ - hv = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hashMask; } - -#define HASH5_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - temp ^= ((UInt32)cur[2] << 8); \ - h3 = temp & (kHash3Size - 1); \ - temp ^= (p->crc[cur[3]] << kLzHash_CrcShift_1); \ - /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */ \ - hv = (temp ^ (p->crc[cur[4]] << kLzHash_CrcShift_2)) & p->hashMask; } - -#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; - - -static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) -{ - // if (!p->directInput) - { - ISzAlloc_Free(alloc, p->bufBase); - p->bufBase = NULL; - } -} - - -static int LzInWindow_Create2(CMatchFinder *p, UInt32 blockSize, ISzAllocPtr alloc) -{ - if (blockSize == 0) - return 0; - if (!p->bufBase || p->blockSize != blockSize) - { - // size_t blockSizeT; - LzInWindow_Free(p, alloc); - p->blockSize = blockSize; - // blockSizeT = blockSize; - - // printf("\nblockSize = 0x%x\n", blockSize); - /* - #if defined _WIN64 - // we can allocate 4GiB, but still use UInt32 for (p->blockSize) - // we use UInt32 type for (p->blockSize), because - // we don't want to wrap over 4 GiB, - // when we use (p->streamPos - p->pos) that is UInt32. - if (blockSize >= (UInt32)0 - (UInt32)kBlockSizeAlign) - { - blockSizeT = ((size_t)1 << 32); - printf("\nchanged to blockSizeT = 4GiB\n"); - } - #endif - */ - - p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, blockSize); - // printf("\nbufferBase = %p\n", p->bufBase); - // return 0; // for debug - } - return (p->bufBase != NULL); -} - -static const Byte *MatchFinder_GetPointerToCurrentPos(void *p) -{ - return ((CMatchFinder *)p)->buffer; -} - -static UInt32 MatchFinder_GetNumAvailableBytes(void *p) -{ - return GET_AVAIL_BYTES((CMatchFinder *)p); -} - - -Z7_NO_INLINE -static void MatchFinder_ReadBlock(CMatchFinder *p) -{ - if (p->streamEndWasReached || p->result != SZ_OK) - return; - - /* We use (p->streamPos - p->pos) value. - (p->streamPos < p->pos) is allowed. */ - - if (p->directInput) - { - UInt32 curSize = 0xFFFFFFFF - GET_AVAIL_BYTES(p); - if (curSize > p->directInputRem) - curSize = (UInt32)p->directInputRem; - p->streamPos += curSize; - p->directInputRem -= curSize; - if (p->directInputRem == 0) - p->streamEndWasReached = 1; - return; - } - - for (;;) - { - const Byte *dest = p->buffer + GET_AVAIL_BYTES(p); - size_t size = (size_t)(p->bufBase + p->blockSize - dest); - if (size == 0) - { - /* we call ReadBlock() after NeedMove() and MoveBlock(). - NeedMove() and MoveBlock() povide more than (keepSizeAfter) - to the end of (blockSize). - So we don't execute this branch in normal code flow. - We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock(). - */ - // p->result = SZ_ERROR_FAIL; // we can show error here - return; - } - - // #define kRead 3 - // if (size > kRead) size = kRead; // for debug - - /* - // we need cast (Byte *)dest. - #ifdef __clang__ - #pragma GCC diagnostic ignored "-Wcast-qual" - #endif - */ - p->result = ISeqInStream_Read(p->stream, - p->bufBase + (dest - p->bufBase), &size); - if (p->result != SZ_OK) - return; - if (size == 0) - { - p->streamEndWasReached = 1; - return; - } - p->streamPos += (UInt32)size; - if (GET_AVAIL_BYTES(p) > p->keepSizeAfter) - return; - /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function - (GET_AVAIL_BYTES(p) >= p->keepSizeAfter) - minimal required size */ - } - - // on exit: (p->result != SZ_OK || p->streamEndWasReached || GET_AVAIL_BYTES(p) > p->keepSizeAfter) -} - - - -Z7_NO_INLINE -void MatchFinder_MoveBlock(CMatchFinder *p) -{ - const size_t offset = (size_t)(p->buffer - p->bufBase) - p->keepSizeBefore; - const size_t keepBefore = (offset & (kBlockMoveAlign - 1)) + p->keepSizeBefore; - p->buffer = p->bufBase + keepBefore; - memmove(p->bufBase, - p->bufBase + (offset & ~((size_t)kBlockMoveAlign - 1)), - keepBefore + (size_t)GET_AVAIL_BYTES(p)); -} - -/* We call MoveBlock() before ReadBlock(). - So MoveBlock() can be wasteful operation, if the whole input data - can fit in current block even without calling MoveBlock(). - in important case where (dataSize <= historySize) - condition (p->blockSize > dataSize + p->keepSizeAfter) is met - So there is no MoveBlock() in that case case. -*/ - -int MatchFinder_NeedMove(CMatchFinder *p) -{ - if (p->directInput) - return 0; - if (p->streamEndWasReached || p->result != SZ_OK) - return 0; - return ((size_t)(p->bufBase + p->blockSize - p->buffer) <= p->keepSizeAfter); -} - -void MatchFinder_ReadIfRequired(CMatchFinder *p) -{ - if (p->keepSizeAfter >= GET_AVAIL_BYTES(p)) - MatchFinder_ReadBlock(p); -} - - - -static void MatchFinder_SetDefaultSettings(CMatchFinder *p) -{ - p->cutValue = 32; - p->btMode = 1; - p->numHashBytes = 4; - p->numHashBytes_Min = 2; - p->numHashOutBits = 0; - p->bigHash = 0; -} - -#define kCrcPoly 0xEDB88320 - -void MatchFinder_Construct(CMatchFinder *p) -{ - unsigned i; - p->buffer = NULL; - p->bufBase = NULL; - p->directInput = 0; - p->stream = NULL; - p->hash = NULL; - p->expectedDataSize = (UInt64)(Int64)-1; - MatchFinder_SetDefaultSettings(p); - - for (i = 0; i < 256; i++) - { - UInt32 r = (UInt32)i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); - p->crc[i] = r; - } -} - -#undef kCrcPoly - -static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->hash); - p->hash = NULL; -} - -void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) -{ - MatchFinder_FreeThisClassMemory(p, alloc); - LzInWindow_Free(p, alloc); -} - -static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) -{ - const size_t sizeInBytes = (size_t)num * sizeof(CLzRef); - if (sizeInBytes / sizeof(CLzRef) != num) - return NULL; - return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes); -} - -#if (kBlockSizeReserveMin < kBlockSizeAlign * 2) - #error Stop_Compiling_Bad_Reserve -#endif - - - -static UInt32 GetBlockSize(CMatchFinder *p, UInt32 historySize) -{ - UInt32 blockSize = (p->keepSizeBefore + p->keepSizeAfter); - /* - if (historySize > kMaxHistorySize) - return 0; - */ - // printf("\nhistorySize == 0x%x\n", historySize); - - if (p->keepSizeBefore < historySize || blockSize < p->keepSizeBefore) // if 32-bit overflow - return 0; - - { - const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)kBlockSizeAlign; - const UInt32 rem = kBlockSizeMax - blockSize; - const UInt32 reserve = (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)) - + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here - if (blockSize >= kBlockSizeMax - || rem < kBlockSizeReserveMin) // we reject settings that will be slow - return 0; - if (reserve >= rem) - blockSize = kBlockSizeMax; - else - { - blockSize += reserve; - blockSize &= ~(UInt32)(kBlockSizeAlign - 1); - } - } - // printf("\n LzFind_blockSize = %x\n", blockSize); - // printf("\n LzFind_blockSize = %d\n", blockSize >> 20); - return blockSize; -} - - -// input is historySize -static UInt32 MatchFinder_GetHashMask2(CMatchFinder *p, UInt32 hs) -{ - if (p->numHashBytes == 2) - return (1 << 16) - 1; - if (hs != 0) - hs--; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - // we propagated 16 bits in (hs). Low 16 bits must be set later - if (hs >= (1 << 24)) - { - if (p->numHashBytes == 3) - hs = (1 << 24) - 1; - /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ - } - // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) - hs |= (1 << 16) - 1; /* don't change it! */ - // bt5: we adjust the size with recommended minimum size - if (p->numHashBytes >= 5) - hs |= (256 << kLzHash_CrcShift_2) - 1; - return hs; -} - -// input is historySize -static UInt32 MatchFinder_GetHashMask(CMatchFinder *p, UInt32 hs) -{ - if (p->numHashBytes == 2) - return (1 << 16) - 1; - if (hs != 0) - hs--; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - // we propagated 16 bits in (hs). Low 16 bits must be set later - hs >>= 1; - if (hs >= (1 << 24)) - { - if (p->numHashBytes == 3) - hs = (1 << 24) - 1; - else - hs >>= 1; - /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ - } - // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) - hs |= (1 << 16) - 1; /* don't change it! */ - // bt5: we adjust the size with recommended minimum size - if (p->numHashBytes >= 5) - hs |= (256 << kLzHash_CrcShift_2) - 1; - return hs; -} - - -int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, - UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, - ISzAllocPtr alloc) -{ - /* we need one additional byte in (p->keepSizeBefore), - since we use MoveBlock() after (p->pos++) and before dictionary using */ - // keepAddBufferBefore = (UInt32)0xFFFFFFFF - (1 << 22); // for debug - p->keepSizeBefore = historySize + keepAddBufferBefore + 1; - - keepAddBufferAfter += matchMaxLen; - /* we need (p->keepSizeAfter >= p->numHashBytes) */ - if (keepAddBufferAfter < p->numHashBytes) - keepAddBufferAfter = p->numHashBytes; - // keepAddBufferAfter -= 2; // for debug - p->keepSizeAfter = keepAddBufferAfter; - - if (p->directInput) - p->blockSize = 0; - if (p->directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc)) - { - size_t hashSizeSum; - { - UInt32 hs; - UInt32 hsCur; - - if (p->numHashOutBits != 0) - { - unsigned numBits = p->numHashOutBits; - const unsigned nbMax = - (p->numHashBytes == 2 ? 16 : - (p->numHashBytes == 3 ? 24 : 32)); - if (numBits > nbMax) - numBits = nbMax; - if (numBits >= 32) - hs = (UInt32)0 - 1; - else - hs = ((UInt32)1 << numBits) - 1; - // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) - hs |= (1 << 16) - 1; /* don't change it! */ - if (p->numHashBytes >= 5) - hs |= (256 << kLzHash_CrcShift_2) - 1; - { - const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize); - if (hs > hs2) - hs = hs2; - } - hsCur = hs; - if (p->expectedDataSize < historySize) - { - const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize); - if (hsCur > hs2) - hsCur = hs2; - } - } - else - { - hs = MatchFinder_GetHashMask(p, historySize); - hsCur = hs; - if (p->expectedDataSize < historySize) - { - hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize); - if (hsCur > hs) // is it possible? - hsCur = hs; - } - } - - p->hashMask = hsCur; - - hashSizeSum = hs; - hashSizeSum++; - if (hashSizeSum < hs) - return 0; - { - UInt32 fixedHashSize = 0; - if (p->numHashBytes > 2 && p->numHashBytes_Min <= 2) fixedHashSize += kHash2Size; - if (p->numHashBytes > 3 && p->numHashBytes_Min <= 3) fixedHashSize += kHash3Size; - // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size; - hashSizeSum += fixedHashSize; - p->fixedHashSize = fixedHashSize; - } - } - - p->matchMaxLen = matchMaxLen; - - { - size_t newSize; - size_t numSons; - const UInt32 newCyclicBufferSize = historySize + 1; // do not change it - p->historySize = historySize; - p->cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1) - - numSons = newCyclicBufferSize; - if (p->btMode) - numSons <<= 1; - newSize = hashSizeSum + numSons; - - if (numSons < newCyclicBufferSize || newSize < numSons) - return 0; - - // aligned size is not required here, but it can be better for some loops - #define NUM_REFS_ALIGN_MASK 0xF - newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~(size_t)NUM_REFS_ALIGN_MASK; - - // 22.02: we don't reallocate buffer, if old size is enough - if (p->hash && p->numRefs >= newSize) - return 1; - - MatchFinder_FreeThisClassMemory(p, alloc); - p->numRefs = newSize; - p->hash = AllocRefs(newSize, alloc); - - if (p->hash) - { - p->son = p->hash + hashSizeSum; - return 1; - } - } - } - - MatchFinder_Free(p, alloc); - return 0; -} - - -static void MatchFinder_SetLimits(CMatchFinder *p) -{ - UInt32 k; - UInt32 n = kMaxValForNormalize - p->pos; - if (n == 0) - n = (UInt32)(Int32)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0) - - k = p->cyclicBufferSize - p->cyclicBufferPos; - if (k < n) - n = k; - - k = GET_AVAIL_BYTES(p); - { - const UInt32 ksa = p->keepSizeAfter; - UInt32 mm = p->matchMaxLen; - if (k > ksa) - k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock - else if (k >= mm) - { - // the limitation for (p->lenLimit) update - k -= mm; // optimization : to reduce the number of checks - k++; - // k = 1; // non-optimized version : for debug - } - else - { - mm = k; - if (k != 0) - k = 1; - } - p->lenLimit = mm; - } - if (k < n) - n = k; - - p->posLimit = p->pos + n; -} - - -void MatchFinder_Init_LowHash(CMatchFinder *p) -{ - size_t i; - CLzRef *items = p->hash; - const size_t numItems = p->fixedHashSize; - for (i = 0; i < numItems; i++) - items[i] = kEmptyHashValue; -} - - -void MatchFinder_Init_HighHash(CMatchFinder *p) -{ - size_t i; - CLzRef *items = p->hash + p->fixedHashSize; - const size_t numItems = (size_t)p->hashMask + 1; - for (i = 0; i < numItems; i++) - items[i] = kEmptyHashValue; -} - - -void MatchFinder_Init_4(CMatchFinder *p) -{ - if (!p->directInput) - p->buffer = p->bufBase; - { - /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker. - the code in CMatchFinderMt expects (pos = 1) */ - p->pos = - p->streamPos = - 1; // it's smallest optimal value. do not change it - // 0; // for debug - } - p->result = SZ_OK; - p->streamEndWasReached = 0; -} - - -// (CYC_TO_POS_OFFSET == 0) is expected by some optimized code -#define CYC_TO_POS_OFFSET 0 -// #define CYC_TO_POS_OFFSET 1 // for debug - -void MatchFinder_Init(void *_p) -{ - CMatchFinder *p = (CMatchFinder *)_p; - MatchFinder_Init_HighHash(p); - MatchFinder_Init_LowHash(p); - MatchFinder_Init_4(p); - // if (readData) - MatchFinder_ReadBlock(p); - - /* if we init (cyclicBufferPos = pos), then we can use one variable - instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */ - p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); // init with relation to (pos) - // p->cyclicBufferPos = 0; // smallest value - // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses. - MatchFinder_SetLimits(p); -} - - - -#ifdef MY_CPU_X86_OR_AMD64 - #if defined(__clang__) && (__clang_major__ >= 4) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) - // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) - - #define USE_LZFIND_SATUR_SUB_128 - #define USE_LZFIND_SATUR_SUB_256 - #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("sse4.1"))) - #define LZFIND_ATTRIB_AVX2 __attribute__((__target__("avx2"))) - #elif defined(_MSC_VER) - #if (_MSC_VER >= 1600) - #define USE_LZFIND_SATUR_SUB_128 - #endif - #if (_MSC_VER >= 1900) - #define USE_LZFIND_SATUR_SUB_256 - #endif - #endif - -#elif defined(MY_CPU_ARM64) \ - /* || (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) */ - - #if defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) - #define USE_LZFIND_SATUR_SUB_128 - #ifdef MY_CPU_ARM64 - // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__(""))) - #else - #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("fpu=neon"))) - #endif - - #elif defined(_MSC_VER) - #if (_MSC_VER >= 1910) - #define USE_LZFIND_SATUR_SUB_128 - #endif - #endif - - #if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) - #include - #else - #include - #endif - -#endif - - -#ifdef USE_LZFIND_SATUR_SUB_128 - -// #define Z7_SHOW_HW_STATUS - -#ifdef Z7_SHOW_HW_STATUS -#include -#define PRF(x) x -PRF(;) -#else -#define PRF(x) -#endif - - -#ifdef MY_CPU_ARM_OR_ARM64 - -#ifdef MY_CPU_ARM64 -// #define FORCE_LZFIND_SATUR_SUB_128 -#endif -typedef uint32x4_t LzFind_v128; -#define SASUB_128_V(v, s) \ - vsubq_u32(vmaxq_u32(v, s), s) - -#else // MY_CPU_ARM_OR_ARM64 - -#include // sse4.1 - -typedef __m128i LzFind_v128; -// SSE 4.1 -#define SASUB_128_V(v, s) \ - _mm_sub_epi32(_mm_max_epu32(v, s), s) - -#endif // MY_CPU_ARM_OR_ARM64 - - -#define SASUB_128(i) \ - *( LzFind_v128 *)( void *)(items + (i) * 4) = SASUB_128_V( \ - *(const LzFind_v128 *)(const void *)(items + (i) * 4), sub2); - - -Z7_NO_INLINE -static -#ifdef LZFIND_ATTRIB_SSE41 -LZFIND_ATTRIB_SSE41 -#endif -void -Z7_FASTCALL -LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim) -{ - const LzFind_v128 sub2 = - #ifdef MY_CPU_ARM_OR_ARM64 - vdupq_n_u32(subValue); - #else - _mm_set_epi32((Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); - #endif - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SASUB_128(0) SASUB_128(1) items += 2 * 4; - SASUB_128(0) SASUB_128(1) items += 2 * 4; - } - while (items != lim); -} - - - -#ifdef USE_LZFIND_SATUR_SUB_256 - -#include // avx -/* -clang :immintrin.h uses -#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \ - defined(__AVX2__) -#include -#endif -so we need for clang-cl */ - -#if defined(__clang__) -#include -#include -#endif - -// AVX2: -#define SASUB_256(i) \ - *( __m256i *)( void *)(items + (i) * 8) = \ - _mm256_sub_epi32(_mm256_max_epu32( \ - *(const __m256i *)(const void *)(items + (i) * 8), sub2), sub2); - -Z7_NO_INLINE -static -#ifdef LZFIND_ATTRIB_AVX2 -LZFIND_ATTRIB_AVX2 -#endif -void -Z7_FASTCALL -LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim) -{ - const __m256i sub2 = _mm256_set_epi32( - (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue, - (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SASUB_256(0) SASUB_256(1) items += 2 * 8; - SASUB_256(0) SASUB_256(1) items += 2 * 8; - } - while (items != lim); -} -#endif // USE_LZFIND_SATUR_SUB_256 - -#ifndef FORCE_LZFIND_SATUR_SUB_128 -typedef void (Z7_FASTCALL *LZFIND_SATUR_SUB_CODE_FUNC)( - UInt32 subValue, CLzRef *items, const CLzRef *lim); -static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub; -#endif // FORCE_LZFIND_SATUR_SUB_128 - -#endif // USE_LZFIND_SATUR_SUB_128 - - -// kEmptyHashValue must be zero -// #define SASUB_32(i) { UInt32 v = items[i]; UInt32 m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m; } -#define SASUB_32(i) { UInt32 v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue; } - -#ifdef FORCE_LZFIND_SATUR_SUB_128 - -#define DEFAULT_SaturSub LzFind_SaturSub_128 - -#else - -#define DEFAULT_SaturSub LzFind_SaturSub_32 - -Z7_NO_INLINE -static -void -Z7_FASTCALL -LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SASUB_32(0) SASUB_32(1) items += 2; - SASUB_32(0) SASUB_32(1) items += 2; - SASUB_32(0) SASUB_32(1) items += 2; - SASUB_32(0) SASUB_32(1) items += 2; - } - while (items != lim); -} - -#endif - - -Z7_NO_INLINE -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) -{ - #define LZFIND_NORM_ALIGN_BLOCK_SIZE (1 << 7) - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (LZFIND_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--) - { - SASUB_32(0) - items++; - } - { - const size_t k_Align_Mask = (LZFIND_NORM_ALIGN_BLOCK_SIZE / 4 - 1); - CLzRef *lim = items + (numItems & ~(size_t)k_Align_Mask); - numItems &= k_Align_Mask; - if (items != lim) - { - #if defined(USE_LZFIND_SATUR_SUB_128) && !defined(FORCE_LZFIND_SATUR_SUB_128) - if (g_LzFind_SaturSub) - g_LzFind_SaturSub(subValue, items, lim); - else - #endif - DEFAULT_SaturSub(subValue, items, lim); - } - items = lim; - } - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (; numItems != 0; numItems--) - { - SASUB_32(0) - items++; - } -} - - - -// call MatchFinder_CheckLimits() only after (p->pos++) update - -Z7_NO_INLINE -static void MatchFinder_CheckLimits(CMatchFinder *p) -{ - if (// !p->streamEndWasReached && p->result == SZ_OK && - p->keepSizeAfter == GET_AVAIL_BYTES(p)) - { - // we try to read only in exact state (p->keepSizeAfter == GET_AVAIL_BYTES(p)) - if (MatchFinder_NeedMove(p)) - MatchFinder_MoveBlock(p); - MatchFinder_ReadBlock(p); - } - - if (p->pos == kMaxValForNormalize) - if (GET_AVAIL_BYTES(p) >= p->numHashBytes) // optional optimization for last bytes of data. - /* - if we disable normalization for last bytes of data, and - if (data_size == 4 GiB), we don't call wastfull normalization, - but (pos) will be wrapped over Zero (0) in that case. - And we cannot resume later to normal operation - */ - { - // MatchFinder_Normalize(p); - /* after normalization we need (p->pos >= p->historySize + 1); */ - /* we can reduce subValue to aligned value, if want to keep alignment - of (p->pos) and (p->buffer) for speculated accesses. */ - const UInt32 subValue = (p->pos - p->historySize - 1) /* & ~(UInt32)(kNormalizeAlign - 1) */; - // const UInt32 subValue = (1 << 15); // for debug - // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue); - MatchFinder_REDUCE_OFFSETS(p, subValue) - MatchFinder_Normalize3(subValue, p->hash, (size_t)p->hashMask + 1 + p->fixedHashSize); - { - size_t numSonRefs = p->cyclicBufferSize; - if (p->btMode) - numSonRefs <<= 1; - MatchFinder_Normalize3(subValue, p->son, numSonRefs); - } - } - - if (p->cyclicBufferPos == p->cyclicBufferSize) - p->cyclicBufferPos = 0; - - MatchFinder_SetLimits(p); -} - - -/* - (lenLimit > maxLen) -*/ -Z7_FORCE_INLINE -static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, - UInt32 *d, unsigned maxLen) -{ - /* - son[_cyclicBufferPos] = curMatch; - for (;;) - { - UInt32 delta = pos - curMatch; - if (cutValue-- == 0 || delta >= _cyclicBufferSize) - return d; - { - const Byte *pb = cur - delta; - curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; - if (pb[maxLen] == cur[maxLen] && *pb == *cur) - { - UInt32 len = 0; - while (++len != lenLimit) - if (pb[len] != cur[len]) - break; - if (maxLen < len) - { - maxLen = len; - *d++ = len; - *d++ = delta - 1; - if (len == lenLimit) - return d; - } - } - } - } - */ - - const Byte *lim = cur + lenLimit; - son[_cyclicBufferPos] = curMatch; - - do - { - UInt32 delta; - - if (curMatch == 0) - break; - // if (curMatch2 >= curMatch) return NULL; - delta = pos - curMatch; - if (delta >= _cyclicBufferSize) - break; - { - ptrdiff_t diff; - curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; - diff = (ptrdiff_t)0 - (ptrdiff_t)delta; - if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff]) - { - const Byte *c = cur; - while (*c == c[diff]) - { - if (++c == lim) - { - d[0] = (UInt32)(lim - cur); - d[1] = delta - 1; - return d + 2; - } - } - { - const unsigned len = (unsigned)(c - cur); - if (maxLen < len) - { - maxLen = len; - d[0] = (UInt32)len; - d[1] = delta - 1; - d += 2; - } - } - } - } - } - while (--cutValue); - - return d; -} - - -Z7_FORCE_INLINE -UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, - UInt32 *d, UInt32 maxLen) -{ - CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - unsigned len0 = 0, len1 = 0; - - UInt32 cmCheck; - - // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } - - cmCheck = (UInt32)(pos - _cyclicBufferSize); - if ((UInt32)pos <= _cyclicBufferSize) - cmCheck = 0; - - if (cmCheck < curMatch) - do - { - const UInt32 delta = pos - curMatch; - { - CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); - const Byte *pb = cur - delta; - unsigned len = (len0 < len1 ? len0 : len1); - const UInt32 pair0 = pair[0]; - if (pb[len] == cur[len]) - { - if (++len != lenLimit && pb[len] == cur[len]) - while (++len != lenLimit) - if (pb[len] != cur[len]) - break; - if (maxLen < len) - { - maxLen = (UInt32)len; - *d++ = (UInt32)len; - *d++ = delta - 1; - if (len == lenLimit) - { - *ptr1 = pair0; - *ptr0 = pair[1]; - return d; - } - } - } - if (pb[len] < cur[len]) - { - *ptr1 = curMatch; - // const UInt32 curMatch2 = pair[1]; - // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } - // curMatch = curMatch2; - curMatch = pair[1]; - ptr1 = pair + 1; - len1 = len; - } - else - { - *ptr0 = curMatch; - curMatch = pair[0]; - ptr0 = pair; - len0 = len; - } - } - } - while(--cutValue && cmCheck < curMatch); - - *ptr0 = *ptr1 = kEmptyHashValue; - return d; -} - - -static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) -{ - CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - unsigned len0 = 0, len1 = 0; - - UInt32 cmCheck; - - cmCheck = (UInt32)(pos - _cyclicBufferSize); - if ((UInt32)pos <= _cyclicBufferSize) - cmCheck = 0; - - if (// curMatch >= pos || // failure - cmCheck < curMatch) - do - { - const UInt32 delta = pos - curMatch; - { - CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); - const Byte *pb = cur - delta; - unsigned len = (len0 < len1 ? len0 : len1); - if (pb[len] == cur[len]) - { - while (++len != lenLimit) - if (pb[len] != cur[len]) - break; - { - if (len == lenLimit) - { - *ptr1 = pair[0]; - *ptr0 = pair[1]; - return; - } - } - } - if (pb[len] < cur[len]) - { - *ptr1 = curMatch; - curMatch = pair[1]; - ptr1 = pair + 1; - len1 = len; - } - else - { - *ptr0 = curMatch; - curMatch = pair[0]; - ptr0 = pair; - len0 = len; - } - } - } - while(--cutValue && cmCheck < curMatch); - - *ptr0 = *ptr1 = kEmptyHashValue; - return; -} - - -#define MOVE_POS \ - p->cyclicBufferPos++; \ - p->buffer++; \ - { const UInt32 pos1 = p->pos + 1; \ - p->pos = pos1; \ - if (pos1 == p->posLimit) MatchFinder_CheckLimits(p); } - -#define MOVE_POS_RET MOVE_POS return distances; - -Z7_NO_INLINE -static void MatchFinder_MovePos(CMatchFinder *p) -{ - /* we go here at the end of stream data, when (avail < num_hash_bytes) - We don't update sons[cyclicBufferPos << btMode]. - So (sons) record will contain junk. And we cannot resume match searching - to normal operation, even if we will provide more input data in buffer. - p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue - if (p->btMode) - p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue - */ - MOVE_POS -} - -#define GET_MATCHES_HEADER2(minLen, ret_op) \ - UInt32 hv; const Byte *cur; UInt32 curMatch; \ - UInt32 lenLimit = p->lenLimit; \ - if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; } \ - cur = p->buffer; - -#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return distances) -#define SKIP_HEADER(minLen) \ - do { GET_MATCHES_HEADER2(minLen, continue) - -#define MF_PARAMS(p) lenLimit, curMatch, p->pos, p->buffer, p->son, \ - p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue - -#define SKIP_FOOTER \ - SkipMatchesSpec(MF_PARAMS(p)); \ - MOVE_POS \ - } while (--num); - -#define GET_MATCHES_FOOTER_BASE(_maxLen_, func) \ - distances = func(MF_PARAMS(p), distances, (UInt32)_maxLen_); \ - MOVE_POS_RET - -#define GET_MATCHES_FOOTER_BT(_maxLen_) \ - GET_MATCHES_FOOTER_BASE(_maxLen_, GetMatchesSpec1) - -#define GET_MATCHES_FOOTER_HC(_maxLen_) \ - GET_MATCHES_FOOTER_BASE(_maxLen_, Hc_GetMatchesSpec) - - - -#define UPDATE_maxLen { \ - const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)d2; \ - const Byte *c = cur + maxLen; \ - const Byte *lim = cur + lenLimit; \ - for (; c != lim; c++) if (*(c + diff) != *c) break; \ - maxLen = (unsigned)(c - cur); } - -static UInt32* Bt2_MatchFinder_GetMatches(void *_p, UInt32 *distances) -{ - CMatchFinder *p = (CMatchFinder *)_p; - GET_MATCHES_HEADER(2) - HASH2_CALC - curMatch = p->hash[hv]; - p->hash[hv] = p->pos; - GET_MATCHES_FOOTER_BT(1) -} - -UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) -{ - GET_MATCHES_HEADER(3) - HASH_ZIP_CALC - curMatch = p->hash[hv]; - p->hash[hv] = p->pos; - GET_MATCHES_FOOTER_BT(2) -} - - -#define SET_mmm \ - mmm = p->cyclicBufferSize; \ - if (pos < mmm) \ - mmm = pos; - - -static UInt32* Bt3_MatchFinder_GetMatches(void *_p, UInt32 *distances) -{ - CMatchFinder *p = (CMatchFinder *)_p; - UInt32 mmm; - UInt32 h2, d2, pos; - unsigned maxLen; - UInt32 *hash; - GET_MATCHES_HEADER(3) - - HASH3_CALC - - hash = p->hash; - pos = p->pos; - - d2 = pos - hash[h2]; - - curMatch = (hash + kFix3HashSize)[hv]; - - hash[h2] = pos; - (hash + kFix3HashSize)[hv] = pos; - - SET_mmm - - maxLen = 2; - - if (d2 < mmm && *(cur - d2) == *cur) - { - UPDATE_maxLen - distances[0] = (UInt32)maxLen; - distances[1] = d2 - 1; - distances += 2; - if (maxLen == lenLimit) - { - SkipMatchesSpec(MF_PARAMS(p)); - MOVE_POS_RET - } - } - - GET_MATCHES_FOOTER_BT(maxLen) -} - - -static UInt32* Bt4_MatchFinder_GetMatches(void *_p, UInt32 *distances) -{ - CMatchFinder *p = (CMatchFinder *)_p; - UInt32 mmm; - UInt32 h2, h3, d2, d3, pos; - unsigned maxLen; - UInt32 *hash; - GET_MATCHES_HEADER(4) - - HASH4_CALC - - hash = p->hash; - pos = p->pos; - - d2 = pos - hash [h2]; - d3 = pos - (hash + kFix3HashSize)[h3]; - curMatch = (hash + kFix4HashSize)[hv]; - - hash [h2] = pos; - (hash + kFix3HashSize)[h3] = pos; - (hash + kFix4HashSize)[hv] = pos; - - SET_mmm - - maxLen = 3; - - for (;;) - { - if (d2 < mmm && *(cur - d2) == *cur) - { - distances[0] = 2; - distances[1] = d2 - 1; - distances += 2; - if (*(cur - d2 + 2) == cur[2]) - { - // distances[-2] = 3; - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - d2 = d3; - distances[1] = d3 - 1; - distances += 2; - } - else - break; - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - d2 = d3; - distances[1] = d3 - 1; - distances += 2; - } - else - break; - - UPDATE_maxLen - distances[-2] = (UInt32)maxLen; - if (maxLen == lenLimit) - { - SkipMatchesSpec(MF_PARAMS(p)); - MOVE_POS_RET - } - break; - } - - GET_MATCHES_FOOTER_BT(maxLen) -} - - -static UInt32* Bt5_MatchFinder_GetMatches(void *_p, UInt32 *distances) -{ - CMatchFinder *p = (CMatchFinder *)_p; - UInt32 mmm; - UInt32 h2, h3, d2, d3, pos; - unsigned maxLen; - UInt32 *hash; - GET_MATCHES_HEADER(5) - - HASH5_CALC - - hash = p->hash; - pos = p->pos; - - d2 = pos - hash [h2]; - d3 = pos - (hash + kFix3HashSize)[h3]; - // d4 = pos - (hash + kFix4HashSize)[h4]; - - curMatch = (hash + kFix5HashSize)[hv]; - - hash [h2] = pos; - (hash + kFix3HashSize)[h3] = pos; - // (hash + kFix4HashSize)[h4] = pos; - (hash + kFix5HashSize)[hv] = pos; - - SET_mmm - - maxLen = 4; - - for (;;) - { - if (d2 < mmm && *(cur - d2) == *cur) - { - distances[0] = 2; - distances[1] = d2 - 1; - distances += 2; - if (*(cur - d2 + 2) == cur[2]) - { - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - distances[1] = d3 - 1; - distances += 2; - d2 = d3; - } - else - break; - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - distances[1] = d3 - 1; - distances += 2; - d2 = d3; - } - else - break; - - distances[-2] = 3; - if (*(cur - d2 + 3) != cur[3]) - break; - UPDATE_maxLen - distances[-2] = (UInt32)maxLen; - if (maxLen == lenLimit) - { - SkipMatchesSpec(MF_PARAMS(p)); - MOVE_POS_RET - } - break; - } - - GET_MATCHES_FOOTER_BT(maxLen) -} - - -static UInt32* Hc4_MatchFinder_GetMatches(void *_p, UInt32 *distances) -{ - CMatchFinder *p = (CMatchFinder *)_p; - UInt32 mmm; - UInt32 h2, h3, d2, d3, pos; - unsigned maxLen; - UInt32 *hash; - GET_MATCHES_HEADER(4) - - HASH4_CALC - - hash = p->hash; - pos = p->pos; - - d2 = pos - hash [h2]; - d3 = pos - (hash + kFix3HashSize)[h3]; - curMatch = (hash + kFix4HashSize)[hv]; - - hash [h2] = pos; - (hash + kFix3HashSize)[h3] = pos; - (hash + kFix4HashSize)[hv] = pos; - - SET_mmm - - maxLen = 3; - - for (;;) - { - if (d2 < mmm && *(cur - d2) == *cur) - { - distances[0] = 2; - distances[1] = d2 - 1; - distances += 2; - if (*(cur - d2 + 2) == cur[2]) - { - // distances[-2] = 3; - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - d2 = d3; - distances[1] = d3 - 1; - distances += 2; - } - else - break; - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - d2 = d3; - distances[1] = d3 - 1; - distances += 2; - } - else - break; - - UPDATE_maxLen - distances[-2] = (UInt32)maxLen; - if (maxLen == lenLimit) - { - p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS_RET - } - break; - } - - GET_MATCHES_FOOTER_HC(maxLen) -} - - -static UInt32 * Hc5_MatchFinder_GetMatches(void *_p, UInt32 *distances) -{ - CMatchFinder *p = (CMatchFinder *)_p; - UInt32 mmm; - UInt32 h2, h3, d2, d3, pos; - unsigned maxLen; - UInt32 *hash; - GET_MATCHES_HEADER(5) - - HASH5_CALC - - hash = p->hash; - pos = p->pos; - - d2 = pos - hash [h2]; - d3 = pos - (hash + kFix3HashSize)[h3]; - // d4 = pos - (hash + kFix4HashSize)[h4]; - - curMatch = (hash + kFix5HashSize)[hv]; - - hash [h2] = pos; - (hash + kFix3HashSize)[h3] = pos; - // (hash + kFix4HashSize)[h4] = pos; - (hash + kFix5HashSize)[hv] = pos; - - SET_mmm - - maxLen = 4; - - for (;;) - { - if (d2 < mmm && *(cur - d2) == *cur) - { - distances[0] = 2; - distances[1] = d2 - 1; - distances += 2; - if (*(cur - d2 + 2) == cur[2]) - { - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - distances[1] = d3 - 1; - distances += 2; - d2 = d3; - } - else - break; - } - else if (d3 < mmm && *(cur - d3) == *cur) - { - distances[1] = d3 - 1; - distances += 2; - d2 = d3; - } - else - break; - - distances[-2] = 3; - if (*(cur - d2 + 3) != cur[3]) - break; - UPDATE_maxLen - distances[-2] = (UInt32)maxLen; - if (maxLen == lenLimit) - { - p->son[p->cyclicBufferPos] = curMatch; - MOVE_POS_RET - } - break; - } - - GET_MATCHES_FOOTER_HC(maxLen) -} - - -UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) -{ - GET_MATCHES_HEADER(3) - HASH_ZIP_CALC - curMatch = p->hash[hv]; - p->hash[hv] = p->pos; - GET_MATCHES_FOOTER_HC(2) -} - - -static void Bt2_MatchFinder_Skip(void *_p, UInt32 num) -{ - CMatchFinder *p = (CMatchFinder *)_p; - SKIP_HEADER(2) - { - HASH2_CALC - curMatch = p->hash[hv]; - p->hash[hv] = p->pos; - } - SKIP_FOOTER -} - -void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) -{ - SKIP_HEADER(3) - { - HASH_ZIP_CALC - curMatch = p->hash[hv]; - p->hash[hv] = p->pos; - } - SKIP_FOOTER -} - -static void Bt3_MatchFinder_Skip(void *_p, UInt32 num) -{ - CMatchFinder *p = (CMatchFinder *)_p; - SKIP_HEADER(3) - { - UInt32 h2; - UInt32 *hash; - HASH3_CALC - hash = p->hash; - curMatch = (hash + kFix3HashSize)[hv]; - hash[h2] = - (hash + kFix3HashSize)[hv] = p->pos; - } - SKIP_FOOTER -} - -static void Bt4_MatchFinder_Skip(void *_p, UInt32 num) -{ - CMatchFinder *p = (CMatchFinder *)_p; - SKIP_HEADER(4) - { - UInt32 h2, h3; - UInt32 *hash; - HASH4_CALC - hash = p->hash; - curMatch = (hash + kFix4HashSize)[hv]; - hash [h2] = - (hash + kFix3HashSize)[h3] = - (hash + kFix4HashSize)[hv] = p->pos; - } - SKIP_FOOTER -} - -static void Bt5_MatchFinder_Skip(void *_p, UInt32 num) -{ - CMatchFinder *p = (CMatchFinder *)_p; - SKIP_HEADER(5) - { - UInt32 h2, h3; - UInt32 *hash; - HASH5_CALC - hash = p->hash; - curMatch = (hash + kFix5HashSize)[hv]; - hash [h2] = - (hash + kFix3HashSize)[h3] = - // (hash + kFix4HashSize)[h4] = - (hash + kFix5HashSize)[hv] = p->pos; - } - SKIP_FOOTER -} - - -#define HC_SKIP_HEADER(minLen) \ - do { if (p->lenLimit < minLen) { MatchFinder_MovePos(p); num--; continue; } { \ - const Byte *cur; \ - UInt32 *hash; \ - UInt32 *son; \ - UInt32 pos = p->pos; \ - UInt32 num2 = num; \ - /* (p->pos == p->posLimit) is not allowed here !!! */ \ - { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \ - num -= num2; \ - { const UInt32 cycPos = p->cyclicBufferPos; \ - son = p->son + cycPos; \ - p->cyclicBufferPos = cycPos + num2; } \ - cur = p->buffer; \ - hash = p->hash; \ - do { \ - UInt32 curMatch; \ - UInt32 hv; - - -#define HC_SKIP_FOOTER \ - cur++; pos++; *son++ = curMatch; \ - } while (--num2); \ - p->buffer = cur; \ - p->pos = pos; \ - if (pos == p->posLimit) MatchFinder_CheckLimits(p); \ - }} while(num); \ - - -static void Hc4_MatchFinder_Skip(void *_p, UInt32 num) -{ - CMatchFinder *p = (CMatchFinder *)_p; - HC_SKIP_HEADER(4) - - UInt32 h2, h3; - HASH4_CALC - curMatch = (hash + kFix4HashSize)[hv]; - hash [h2] = - (hash + kFix3HashSize)[h3] = - (hash + kFix4HashSize)[hv] = pos; - - HC_SKIP_FOOTER -} - - -static void Hc5_MatchFinder_Skip(void *_p, UInt32 num) -{ - CMatchFinder *p = (CMatchFinder *)_p; - HC_SKIP_HEADER(5) - - UInt32 h2, h3; - HASH5_CALC - curMatch = (hash + kFix5HashSize)[hv]; - hash [h2] = - (hash + kFix3HashSize)[h3] = - // (hash + kFix4HashSize)[h4] = - (hash + kFix5HashSize)[hv] = pos; - - HC_SKIP_FOOTER -} - - -void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) -{ - HC_SKIP_HEADER(3) - - HASH_ZIP_CALC - curMatch = hash[hv]; - hash[hv] = pos; - - HC_SKIP_FOOTER -} - - -void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable) -{ - vTable->Init = MatchFinder_Init; - vTable->GetNumAvailableBytes = MatchFinder_GetNumAvailableBytes; - vTable->GetPointerToCurrentPos = MatchFinder_GetPointerToCurrentPos; - if (!p->btMode) - { - if (p->numHashBytes <= 4) - { - vTable->GetMatches = Hc4_MatchFinder_GetMatches; - vTable->Skip = Hc4_MatchFinder_Skip; - } - else - { - vTable->GetMatches = Hc5_MatchFinder_GetMatches; - vTable->Skip = Hc5_MatchFinder_Skip; - } - } - else if (p->numHashBytes == 2) - { - vTable->GetMatches = Bt2_MatchFinder_GetMatches; - vTable->Skip = Bt2_MatchFinder_Skip; - } - else if (p->numHashBytes == 3) - { - vTable->GetMatches = Bt3_MatchFinder_GetMatches; - vTable->Skip = Bt3_MatchFinder_Skip; - } - else if (p->numHashBytes == 4) - { - vTable->GetMatches = Bt4_MatchFinder_GetMatches; - vTable->Skip = Bt4_MatchFinder_Skip; - } - else - { - vTable->GetMatches = Bt5_MatchFinder_GetMatches; - vTable->Skip = Bt5_MatchFinder_Skip; - } -} - - - -void LzFindPrepare(void) -{ - #ifndef FORCE_LZFIND_SATUR_SUB_128 - #ifdef USE_LZFIND_SATUR_SUB_128 - LZFIND_SATUR_SUB_CODE_FUNC f = NULL; - #ifdef MY_CPU_ARM_OR_ARM64 - { - if (CPU_IsSupported_NEON()) - { - // #pragma message ("=== LzFind NEON") - PRF(printf("\n=== LzFind NEON\n")); - f = LzFind_SaturSub_128; - } - // f = 0; // for debug - } - #else // MY_CPU_ARM_OR_ARM64 - if (CPU_IsSupported_SSE41()) - { - // #pragma message ("=== LzFind SSE41") - PRF(printf("\n=== LzFind SSE41\n")); - f = LzFind_SaturSub_128; - - #ifdef USE_LZFIND_SATUR_SUB_256 - if (CPU_IsSupported_AVX2()) - { - // #pragma message ("=== LzFind AVX2") - PRF(printf("\n=== LzFind AVX2\n")); - f = LzFind_SaturSub_256; - } - #endif - } - #endif // MY_CPU_ARM_OR_ARM64 - g_LzFind_SaturSub = f; - #endif // USE_LZFIND_SATUR_SUB_128 - #endif // FORCE_LZFIND_SATUR_SUB_128 -} - - -#undef MOVE_POS -#undef MOVE_POS_RET -#undef PRF +/* LzFind.c -- Match finder for LZ algorithms +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +// #include + +#include "CpuArch.h" +#include "LzFind.h" +#include "LzHash.h" + +#define kBlockMoveAlign (1 << 7) // alignment for memmove() +#define kBlockSizeAlign (1 << 16) // alignment for block allocation +#define kBlockSizeReserveMin (1 << 24) // it's 1/256 from 4 GB dictinary + +#define kEmptyHashValue 0 + +#define kMaxValForNormalize ((UInt32)0) +// #define kMaxValForNormalize ((UInt32)(1 << 20) + 0xfff) // for debug + +// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses + +#define GET_AVAIL_BYTES(p) \ + Inline_MatchFinder_GetNumAvailableBytes(p) + + +// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) +#define kFix5HashSize kFix4HashSize + +/* + HASH2_CALC: + if (hv) match, then cur[0] and cur[1] also match +*/ +#define HASH2_CALC hv = GetUi16(cur); + +// (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255] + +/* + HASH3_CALC: + if (cur[0]) and (h2) match, then cur[1] also match + if (cur[0]) and (hv) match, then cur[1] and cur[2] also match +*/ +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << kLzHash_CrcShift_1); \ + /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */ \ + hv = (temp ^ (p->crc[cur[4]] << kLzHash_CrcShift_2)) & p->hashMask; } + +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc) +{ + // if (!p->directInput) + { + ISzAlloc_Free(alloc, p->bufBase); + p->bufBase = NULL; + } +} + + +static int LzInWindow_Create2(CMatchFinder *p, UInt32 blockSize, ISzAllocPtr alloc) +{ + if (blockSize == 0) + return 0; + if (!p->bufBase || p->blockSize != blockSize) + { + // size_t blockSizeT; + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + // blockSizeT = blockSize; + + // printf("\nblockSize = 0x%x\n", blockSize); + /* + #if defined _WIN64 + // we can allocate 4GiB, but still use UInt32 for (p->blockSize) + // we use UInt32 type for (p->blockSize), because + // we don't want to wrap over 4 GiB, + // when we use (p->streamPos - p->pos) that is UInt32. + if (blockSize >= (UInt32)0 - (UInt32)kBlockSizeAlign) + { + blockSizeT = ((size_t)1 << 32); + printf("\nchanged to blockSizeT = 4GiB\n"); + } + #endif + */ + + p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, blockSize); + // printf("\nbufferBase = %p\n", p->bufBase); + // return 0; // for debug + } + return (p->bufBase != NULL); +} + +static const Byte *MatchFinder_GetPointerToCurrentPos(void *p) +{ + return ((CMatchFinder *)p)->buffer; +} + +static UInt32 MatchFinder_GetNumAvailableBytes(void *p) +{ + return GET_AVAIL_BYTES((CMatchFinder *)p); +} + + +Z7_NO_INLINE +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + + /* We use (p->streamPos - p->pos) value. + (p->streamPos < p->pos) is allowed. */ + + if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - GET_AVAIL_BYTES(p); + if (curSize > p->directInputRem) + curSize = (UInt32)p->directInputRem; + p->streamPos += curSize; + p->directInputRem -= curSize; + if (p->directInputRem == 0) + p->streamEndWasReached = 1; + return; + } + + for (;;) + { + const Byte *dest = p->buffer + GET_AVAIL_BYTES(p); + size_t size = (size_t)(p->bufBase + p->blockSize - dest); + if (size == 0) + { + /* we call ReadBlock() after NeedMove() and MoveBlock(). + NeedMove() and MoveBlock() povide more than (keepSizeAfter) + to the end of (blockSize). + So we don't execute this branch in normal code flow. + We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock(). + */ + // p->result = SZ_ERROR_FAIL; // we can show error here + return; + } + + // #define kRead 3 + // if (size > kRead) size = kRead; // for debug + + /* + // we need cast (Byte *)dest. + #ifdef __clang__ + #pragma GCC diagnostic ignored "-Wcast-qual" + #endif + */ + p->result = ISeqInStream_Read(p->stream, + p->bufBase + (dest - p->bufBase), &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (GET_AVAIL_BYTES(p) > p->keepSizeAfter) + return; + /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function + (GET_AVAIL_BYTES(p) >= p->keepSizeAfter) - minimal required size */ + } + + // on exit: (p->result != SZ_OK || p->streamEndWasReached || GET_AVAIL_BYTES(p) > p->keepSizeAfter) +} + + + +Z7_NO_INLINE +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + const size_t offset = (size_t)(p->buffer - p->bufBase) - p->keepSizeBefore; + const size_t keepBefore = (offset & (kBlockMoveAlign - 1)) + p->keepSizeBefore; + p->buffer = p->bufBase + keepBefore; + memmove(p->bufBase, + p->bufBase + (offset & ~((size_t)kBlockMoveAlign - 1)), + keepBefore + (size_t)GET_AVAIL_BYTES(p)); +} + +/* We call MoveBlock() before ReadBlock(). + So MoveBlock() can be wasteful operation, if the whole input data + can fit in current block even without calling MoveBlock(). + in important case where (dataSize <= historySize) + condition (p->blockSize > dataSize + p->keepSizeAfter) is met + So there is no MoveBlock() in that case case. +*/ + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + if (p->directInput) + return 0; + if (p->streamEndWasReached || p->result != SZ_OK) + return 0; + return ((size_t)(p->bufBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->keepSizeAfter >= GET_AVAIL_BYTES(p)) + MatchFinder_ReadBlock(p); +} + + + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + p->numHashBytes_Min = 2; + p->numHashOutBits = 0; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + unsigned i; + p->buffer = NULL; + p->bufBase = NULL; + p->directInput = 0; + p->stream = NULL; + p->hash = NULL; + p->expectedDataSize = (UInt64)(Int64)-1; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = (UInt32)i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + p->crc[i] = r; + } +} + +#undef kCrcPoly + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->hash); + p->hash = NULL; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc) +{ + const size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return NULL; + return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes); +} + +#if (kBlockSizeReserveMin < kBlockSizeAlign * 2) + #error Stop_Compiling_Bad_Reserve +#endif + + + +static UInt32 GetBlockSize(CMatchFinder *p, UInt32 historySize) +{ + UInt32 blockSize = (p->keepSizeBefore + p->keepSizeAfter); + /* + if (historySize > kMaxHistorySize) + return 0; + */ + // printf("\nhistorySize == 0x%x\n", historySize); + + if (p->keepSizeBefore < historySize || blockSize < p->keepSizeBefore) // if 32-bit overflow + return 0; + + { + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)kBlockSizeAlign; + const UInt32 rem = kBlockSizeMax - blockSize; + const UInt32 reserve = (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)) + + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here + if (blockSize >= kBlockSizeMax + || rem < kBlockSizeReserveMin) // we reject settings that will be slow + return 0; + if (reserve >= rem) + blockSize = kBlockSizeMax; + else + { + blockSize += reserve; + blockSize &= ~(UInt32)(kBlockSizeAlign - 1); + } + } + // printf("\n LzFind_blockSize = %x\n", blockSize); + // printf("\n LzFind_blockSize = %d\n", blockSize >> 20); + return blockSize; +} + + +// input is historySize +static UInt32 MatchFinder_GetHashMask2(CMatchFinder *p, UInt32 hs) +{ + if (p->numHashBytes == 2) + return (1 << 16) - 1; + if (hs != 0) + hs--; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + // we propagated 16 bits in (hs). Low 16 bits must be set later + if (hs >= (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + } + // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) + hs |= (1 << 16) - 1; /* don't change it! */ + // bt5: we adjust the size with recommended minimum size + if (p->numHashBytes >= 5) + hs |= (256 << kLzHash_CrcShift_2) - 1; + return hs; +} + +// input is historySize +static UInt32 MatchFinder_GetHashMask(CMatchFinder *p, UInt32 hs) +{ + if (p->numHashBytes == 2) + return (1 << 16) - 1; + if (hs != 0) + hs--; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + // we propagated 16 bits in (hs). Low 16 bits must be set later + hs >>= 1; + if (hs >= (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ + } + // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) + hs |= (1 << 16) - 1; /* don't change it! */ + // bt5: we adjust the size with recommended minimum size + if (p->numHashBytes >= 5) + hs |= (256 << kLzHash_CrcShift_2) - 1; + return hs; +} + + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc) +{ + /* we need one additional byte in (p->keepSizeBefore), + since we use MoveBlock() after (p->pos++) and before dictionary using */ + // keepAddBufferBefore = (UInt32)0xFFFFFFFF - (1 << 22); // for debug + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + + keepAddBufferAfter += matchMaxLen; + /* we need (p->keepSizeAfter >= p->numHashBytes) */ + if (keepAddBufferAfter < p->numHashBytes) + keepAddBufferAfter = p->numHashBytes; + // keepAddBufferAfter -= 2; // for debug + p->keepSizeAfter = keepAddBufferAfter; + + if (p->directInput) + p->blockSize = 0; + if (p->directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc)) + { + size_t hashSizeSum; + { + UInt32 hs; + UInt32 hsCur; + + if (p->numHashOutBits != 0) + { + unsigned numBits = p->numHashOutBits; + const unsigned nbMax = + (p->numHashBytes == 2 ? 16 : + (p->numHashBytes == 3 ? 24 : 32)); + if (numBits > nbMax) + numBits = nbMax; + if (numBits >= 32) + hs = (UInt32)0 - 1; + else + hs = ((UInt32)1 << numBits) - 1; + // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2) + hs |= (1 << 16) - 1; /* don't change it! */ + if (p->numHashBytes >= 5) + hs |= (256 << kLzHash_CrcShift_2) - 1; + { + const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize); + if (hs > hs2) + hs = hs2; + } + hsCur = hs; + if (p->expectedDataSize < historySize) + { + const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize); + if (hsCur > hs2) + hsCur = hs2; + } + } + else + { + hs = MatchFinder_GetHashMask(p, historySize); + hsCur = hs; + if (p->expectedDataSize < historySize) + { + hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize); + if (hsCur > hs) // is it possible? + hsCur = hs; + } + } + + p->hashMask = hsCur; + + hashSizeSum = hs; + hashSizeSum++; + if (hashSizeSum < hs) + return 0; + { + UInt32 fixedHashSize = 0; + if (p->numHashBytes > 2 && p->numHashBytes_Min <= 2) fixedHashSize += kHash2Size; + if (p->numHashBytes > 3 && p->numHashBytes_Min <= 3) fixedHashSize += kHash3Size; + // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size; + hashSizeSum += fixedHashSize; + p->fixedHashSize = fixedHashSize; + } + } + + p->matchMaxLen = matchMaxLen; + + { + size_t newSize; + size_t numSons; + const UInt32 newCyclicBufferSize = historySize + 1; // do not change it + p->historySize = historySize; + p->cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1) + + numSons = newCyclicBufferSize; + if (p->btMode) + numSons <<= 1; + newSize = hashSizeSum + numSons; + + if (numSons < newCyclicBufferSize || newSize < numSons) + return 0; + + // aligned size is not required here, but it can be better for some loops + #define NUM_REFS_ALIGN_MASK 0xF + newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~(size_t)NUM_REFS_ALIGN_MASK; + + // 22.02: we don't reallocate buffer, if old size is enough + if (p->hash && p->numRefs >= newSize) + return 1; + + MatchFinder_FreeThisClassMemory(p, alloc); + p->numRefs = newSize; + p->hash = AllocRefs(newSize, alloc); + + if (p->hash) + { + p->son = p->hash + hashSizeSum; + return 1; + } + } + } + + MatchFinder_Free(p, alloc); + return 0; +} + + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 k; + UInt32 n = kMaxValForNormalize - p->pos; + if (n == 0) + n = (UInt32)(Int32)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0) + + k = p->cyclicBufferSize - p->cyclicBufferPos; + if (k < n) + n = k; + + k = GET_AVAIL_BYTES(p); + { + const UInt32 ksa = p->keepSizeAfter; + UInt32 mm = p->matchMaxLen; + if (k > ksa) + k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock + else if (k >= mm) + { + // the limitation for (p->lenLimit) update + k -= mm; // optimization : to reduce the number of checks + k++; + // k = 1; // non-optimized version : for debug + } + else + { + mm = k; + if (k != 0) + k = 1; + } + p->lenLimit = mm; + } + if (k < n) + n = k; + + p->posLimit = p->pos + n; +} + + +void MatchFinder_Init_LowHash(CMatchFinder *p) +{ + size_t i; + CLzRef *items = p->hash; + const size_t numItems = p->fixedHashSize; + for (i = 0; i < numItems; i++) + items[i] = kEmptyHashValue; +} + + +void MatchFinder_Init_HighHash(CMatchFinder *p) +{ + size_t i; + CLzRef *items = p->hash + p->fixedHashSize; + const size_t numItems = (size_t)p->hashMask + 1; + for (i = 0; i < numItems; i++) + items[i] = kEmptyHashValue; +} + + +void MatchFinder_Init_4(CMatchFinder *p) +{ + if (!p->directInput) + p->buffer = p->bufBase; + { + /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker. + the code in CMatchFinderMt expects (pos = 1) */ + p->pos = + p->streamPos = + 1; // it's smallest optimal value. do not change it + // 0; // for debug + } + p->result = SZ_OK; + p->streamEndWasReached = 0; +} + + +// (CYC_TO_POS_OFFSET == 0) is expected by some optimized code +#define CYC_TO_POS_OFFSET 0 +// #define CYC_TO_POS_OFFSET 1 // for debug + +void MatchFinder_Init(void *_p) +{ + CMatchFinder *p = (CMatchFinder *)_p; + MatchFinder_Init_HighHash(p); + MatchFinder_Init_LowHash(p); + MatchFinder_Init_4(p); + // if (readData) + MatchFinder_ReadBlock(p); + + /* if we init (cyclicBufferPos = pos), then we can use one variable + instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */ + p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); // init with relation to (pos) + // p->cyclicBufferPos = 0; // smallest value + // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses. + MatchFinder_SetLimits(p); +} + + + +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(__clang__) && (__clang_major__ >= 4) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) + // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) + + #define USE_LZFIND_SATUR_SUB_128 + #define USE_LZFIND_SATUR_SUB_256 + #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("sse4.1"))) + #define LZFIND_ATTRIB_AVX2 __attribute__((__target__("avx2"))) + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1600) + #define USE_LZFIND_SATUR_SUB_128 + #endif + #if (_MSC_VER >= 1900) + #define USE_LZFIND_SATUR_SUB_256 + #endif + #endif + +#elif defined(MY_CPU_ARM64) \ + /* || (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) */ + + #if defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) + #define USE_LZFIND_SATUR_SUB_128 + #ifdef MY_CPU_ARM64 + // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__(""))) + #else + #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("fpu=neon"))) + #endif + + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1910) + #define USE_LZFIND_SATUR_SUB_128 + #endif + #endif + + #if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) + #include + #else + #include + #endif + +#endif + + +#ifdef USE_LZFIND_SATUR_SUB_128 + +// #define Z7_SHOW_HW_STATUS + +#ifdef Z7_SHOW_HW_STATUS +#include +#define PRF(x) x +PRF(;) +#else +#define PRF(x) +#endif + + +#ifdef MY_CPU_ARM_OR_ARM64 + +#ifdef MY_CPU_ARM64 +// #define FORCE_LZFIND_SATUR_SUB_128 +#endif +typedef uint32x4_t LzFind_v128; +#define SASUB_128_V(v, s) \ + vsubq_u32(vmaxq_u32(v, s), s) + +#else // MY_CPU_ARM_OR_ARM64 + +#include // sse4.1 + +typedef __m128i LzFind_v128; +// SSE 4.1 +#define SASUB_128_V(v, s) \ + _mm_sub_epi32(_mm_max_epu32(v, s), s) + +#endif // MY_CPU_ARM_OR_ARM64 + + +#define SASUB_128(i) \ + *( LzFind_v128 *)( void *)(items + (i) * 4) = SASUB_128_V( \ + *(const LzFind_v128 *)(const void *)(items + (i) * 4), sub2); + + +Z7_NO_INLINE +static +#ifdef LZFIND_ATTRIB_SSE41 +LZFIND_ATTRIB_SSE41 +#endif +void +Z7_FASTCALL +LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim) +{ + const LzFind_v128 sub2 = + #ifdef MY_CPU_ARM_OR_ARM64 + vdupq_n_u32(subValue); + #else + _mm_set_epi32((Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); + #endif + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SASUB_128(0) SASUB_128(1) items += 2 * 4; + SASUB_128(0) SASUB_128(1) items += 2 * 4; + } + while (items != lim); +} + + + +#ifdef USE_LZFIND_SATUR_SUB_256 + +#include // avx +/* +clang :immintrin.h uses +#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \ + defined(__AVX2__) +#include +#endif +so we need for clang-cl */ + +#if defined(__clang__) +#include +#include +#endif + +// AVX2: +#define SASUB_256(i) \ + *( __m256i *)( void *)(items + (i) * 8) = \ + _mm256_sub_epi32(_mm256_max_epu32( \ + *(const __m256i *)(const void *)(items + (i) * 8), sub2), sub2); + +Z7_NO_INLINE +static +#ifdef LZFIND_ATTRIB_AVX2 +LZFIND_ATTRIB_AVX2 +#endif +void +Z7_FASTCALL +LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim) +{ + const __m256i sub2 = _mm256_set_epi32( + (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue, + (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue); + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SASUB_256(0) SASUB_256(1) items += 2 * 8; + SASUB_256(0) SASUB_256(1) items += 2 * 8; + } + while (items != lim); +} +#endif // USE_LZFIND_SATUR_SUB_256 + +#ifndef FORCE_LZFIND_SATUR_SUB_128 +typedef void (Z7_FASTCALL *LZFIND_SATUR_SUB_CODE_FUNC)( + UInt32 subValue, CLzRef *items, const CLzRef *lim); +static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub; +#endif // FORCE_LZFIND_SATUR_SUB_128 + +#endif // USE_LZFIND_SATUR_SUB_128 + + +// kEmptyHashValue must be zero +// #define SASUB_32(i) { UInt32 v = items[i]; UInt32 m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m; } +#define SASUB_32(i) { UInt32 v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue; } + +#ifdef FORCE_LZFIND_SATUR_SUB_128 + +#define DEFAULT_SaturSub LzFind_SaturSub_128 + +#else + +#define DEFAULT_SaturSub LzFind_SaturSub_32 + +Z7_NO_INLINE +static +void +Z7_FASTCALL +LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SASUB_32(0) SASUB_32(1) items += 2; + SASUB_32(0) SASUB_32(1) items += 2; + SASUB_32(0) SASUB_32(1) items += 2; + SASUB_32(0) SASUB_32(1) items += 2; + } + while (items != lim); +} + +#endif + + +Z7_NO_INLINE +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) +{ + #define LZFIND_NORM_ALIGN_BLOCK_SIZE (1 << 7) + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (LZFIND_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--) + { + SASUB_32(0) + items++; + } + { + const size_t k_Align_Mask = (LZFIND_NORM_ALIGN_BLOCK_SIZE / 4 - 1); + CLzRef *lim = items + (numItems & ~(size_t)k_Align_Mask); + numItems &= k_Align_Mask; + if (items != lim) + { + #if defined(USE_LZFIND_SATUR_SUB_128) && !defined(FORCE_LZFIND_SATUR_SUB_128) + if (g_LzFind_SaturSub) + g_LzFind_SaturSub(subValue, items, lim); + else + #endif + DEFAULT_SaturSub(subValue, items, lim); + } + items = lim; + } + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0; numItems--) + { + SASUB_32(0) + items++; + } +} + + + +// call MatchFinder_CheckLimits() only after (p->pos++) update + +Z7_NO_INLINE +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (// !p->streamEndWasReached && p->result == SZ_OK && + p->keepSizeAfter == GET_AVAIL_BYTES(p)) + { + // we try to read only in exact state (p->keepSizeAfter == GET_AVAIL_BYTES(p)) + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); + } + + if (p->pos == kMaxValForNormalize) + if (GET_AVAIL_BYTES(p) >= p->numHashBytes) // optional optimization for last bytes of data. + /* + if we disable normalization for last bytes of data, and + if (data_size == 4 GiB), we don't call wastfull normalization, + but (pos) will be wrapped over Zero (0) in that case. + And we cannot resume later to normal operation + */ + { + // MatchFinder_Normalize(p); + /* after normalization we need (p->pos >= p->historySize + 1); */ + /* we can reduce subValue to aligned value, if want to keep alignment + of (p->pos) and (p->buffer) for speculated accesses. */ + const UInt32 subValue = (p->pos - p->historySize - 1) /* & ~(UInt32)(kNormalizeAlign - 1) */; + // const UInt32 subValue = (1 << 15); // for debug + // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue); + MatchFinder_REDUCE_OFFSETS(p, subValue) + MatchFinder_Normalize3(subValue, p->hash, (size_t)p->hashMask + 1 + p->fixedHashSize); + { + size_t numSonRefs = p->cyclicBufferSize; + if (p->btMode) + numSonRefs <<= 1; + MatchFinder_Normalize3(subValue, p->son, numSonRefs); + } + } + + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + + MatchFinder_SetLimits(p); +} + + +/* + (lenLimit > maxLen) +*/ +Z7_FORCE_INLINE +static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *d, unsigned maxLen) +{ + /* + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return d; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *d++ = len; + *d++ = delta - 1; + if (len == lenLimit) + return d; + } + } + } + } + */ + + const Byte *lim = cur + lenLimit; + son[_cyclicBufferPos] = curMatch; + + do + { + UInt32 delta; + + if (curMatch == 0) + break; + // if (curMatch2 >= curMatch) return NULL; + delta = pos - curMatch; + if (delta >= _cyclicBufferSize) + break; + { + ptrdiff_t diff; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff]) + { + const Byte *c = cur; + while (*c == c[diff]) + { + if (++c == lim) + { + d[0] = (UInt32)(lim - cur); + d[1] = delta - 1; + return d + 2; + } + } + { + const unsigned len = (unsigned)(c - cur); + if (maxLen < len) + { + maxLen = len; + d[0] = (UInt32)len; + d[1] = delta - 1; + d += 2; + } + } + } + } + } + while (--cutValue); + + return d; +} + + +Z7_FORCE_INLINE +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *d, UInt32 maxLen) +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + + UInt32 cmCheck; + + // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } + + cmCheck = (UInt32)(pos - _cyclicBufferSize); + if ((UInt32)pos <= _cyclicBufferSize) + cmCheck = 0; + + if (cmCheck < curMatch) + do + { + const UInt32 delta = pos - curMatch; + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + const UInt32 pair0 = pair[0]; + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = (UInt32)len; + *d++ = (UInt32)len; + *d++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair0; + *ptr0 = pair[1]; + return d; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + // const UInt32 curMatch2 = pair[1]; + // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; } + // curMatch = curMatch2; + curMatch = pair[1]; + ptr1 = pair + 1; + len1 = len; + } + else + { + *ptr0 = curMatch; + curMatch = pair[0]; + ptr0 = pair; + len0 = len; + } + } + } + while(--cutValue && cmCheck < curMatch); + + *ptr0 = *ptr1 = kEmptyHashValue; + return d; +} + + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + unsigned len0 = 0, len1 = 0; + + UInt32 cmCheck; + + cmCheck = (UInt32)(pos - _cyclicBufferSize); + if ((UInt32)pos <= _cyclicBufferSize) + cmCheck = 0; + + if (// curMatch >= pos || // failure + cmCheck < curMatch) + do + { + const UInt32 delta = pos - curMatch; + { + CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + unsigned len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + curMatch = pair[1]; + ptr1 = pair + 1; + len1 = len; + } + else + { + *ptr0 = curMatch; + curMatch = pair[0]; + ptr0 = pair; + len0 = len; + } + } + } + while(--cutValue && cmCheck < curMatch); + + *ptr0 = *ptr1 = kEmptyHashValue; + return; +} + + +#define MOVE_POS \ + p->cyclicBufferPos++; \ + p->buffer++; \ + { const UInt32 pos1 = p->pos + 1; \ + p->pos = pos1; \ + if (pos1 == p->posLimit) MatchFinder_CheckLimits(p); } + +#define MOVE_POS_RET MOVE_POS return distances; + +Z7_NO_INLINE +static void MatchFinder_MovePos(CMatchFinder *p) +{ + /* we go here at the end of stream data, when (avail < num_hash_bytes) + We don't update sons[cyclicBufferPos << btMode]. + So (sons) record will contain junk. And we cannot resume match searching + to normal operation, even if we will provide more input data in buffer. + p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue + if (p->btMode) + p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue + */ + MOVE_POS +} + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 hv; const Byte *cur; UInt32 curMatch; \ + UInt32 lenLimit = p->lenLimit; \ + if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; } \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return distances) +#define SKIP_HEADER(minLen) \ + do { GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) lenLimit, curMatch, p->pos, p->buffer, p->son, \ + p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define SKIP_FOOTER \ + SkipMatchesSpec(MF_PARAMS(p)); \ + MOVE_POS \ + } while (--num); + +#define GET_MATCHES_FOOTER_BASE(_maxLen_, func) \ + distances = func(MF_PARAMS(p), distances, (UInt32)_maxLen_); \ + MOVE_POS_RET + +#define GET_MATCHES_FOOTER_BT(_maxLen_) \ + GET_MATCHES_FOOTER_BASE(_maxLen_, GetMatchesSpec1) + +#define GET_MATCHES_FOOTER_HC(_maxLen_) \ + GET_MATCHES_FOOTER_BASE(_maxLen_, Hc_GetMatchesSpec) + + + +#define UPDATE_maxLen { \ + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)d2; \ + const Byte *c = cur + maxLen; \ + const Byte *lim = cur + lenLimit; \ + for (; c != lim; c++) if (*(c + diff) != *c) break; \ + maxLen = (unsigned)(c - cur); } + +static UInt32* Bt2_MatchFinder_GetMatches(void *_p, UInt32 *distances) +{ + CMatchFinder *p = (CMatchFinder *)_p; + GET_MATCHES_HEADER(2) + HASH2_CALC + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + GET_MATCHES_FOOTER_BT(1) +} + +UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + GET_MATCHES_FOOTER_BT(2) +} + + +#define SET_mmm \ + mmm = p->cyclicBufferSize; \ + if (pos < mmm) \ + mmm = pos; + + +static UInt32* Bt3_MatchFinder_GetMatches(void *_p, UInt32 *distances) +{ + CMatchFinder *p = (CMatchFinder *)_p; + UInt32 mmm; + UInt32 h2, d2, pos; + unsigned maxLen; + UInt32 *hash; + GET_MATCHES_HEADER(3) + + HASH3_CALC + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[h2]; + + curMatch = (hash + kFix3HashSize)[hv]; + + hash[h2] = pos; + (hash + kFix3HashSize)[hv] = pos; + + SET_mmm + + maxLen = 2; + + if (d2 < mmm && *(cur - d2) == *cur) + { + UPDATE_maxLen + distances[0] = (UInt32)maxLen; + distances[1] = d2 - 1; + distances += 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec(MF_PARAMS(p)); + MOVE_POS_RET + } + } + + GET_MATCHES_FOOTER_BT(maxLen) +} + + +static UInt32* Bt4_MatchFinder_GetMatches(void *_p, UInt32 *distances) +{ + CMatchFinder *p = (CMatchFinder *)_p; + UInt32 mmm; + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen; + UInt32 *hash; + GET_MATCHES_HEADER(4) + + HASH4_CALC + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + curMatch = (hash + kFix4HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[hv] = pos; + + SET_mmm + + maxLen = 3; + + for (;;) + { + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + // distances[-2] = 3; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + + UPDATE_maxLen + distances[-2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(MF_PARAMS(p)); + MOVE_POS_RET + } + break; + } + + GET_MATCHES_FOOTER_BT(maxLen) +} + + +static UInt32* Bt5_MatchFinder_GetMatches(void *_p, UInt32 *distances) +{ + CMatchFinder *p = (CMatchFinder *)_p; + UInt32 mmm; + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + // d4 = pos - (hash + kFix4HashSize)[h4]; + + curMatch = (hash + kFix5HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + // (hash + kFix4HashSize)[h4] = pos; + (hash + kFix5HashSize)[hv] = pos; + + SET_mmm + + maxLen = 4; + + for (;;) + { + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + distances[1] = d3 - 1; + distances += 2; + d2 = d3; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + distances[1] = d3 - 1; + distances += 2; + d2 = d3; + } + else + break; + + distances[-2] = 3; + if (*(cur - d2 + 3) != cur[3]) + break; + UPDATE_maxLen + distances[-2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(MF_PARAMS(p)); + MOVE_POS_RET + } + break; + } + + GET_MATCHES_FOOTER_BT(maxLen) +} + + +static UInt32* Hc4_MatchFinder_GetMatches(void *_p, UInt32 *distances) +{ + CMatchFinder *p = (CMatchFinder *)_p; + UInt32 mmm; + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen; + UInt32 *hash; + GET_MATCHES_HEADER(4) + + HASH4_CALC + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + curMatch = (hash + kFix4HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + (hash + kFix4HashSize)[hv] = pos; + + SET_mmm + + maxLen = 3; + + for (;;) + { + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + // distances[-2] = 3; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + d2 = d3; + distances[1] = d3 - 1; + distances += 2; + } + else + break; + + UPDATE_maxLen + distances[-2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET + } + break; + } + + GET_MATCHES_FOOTER_HC(maxLen) +} + + +static UInt32 * Hc5_MatchFinder_GetMatches(void *_p, UInt32 *distances) +{ + CMatchFinder *p = (CMatchFinder *)_p; + UInt32 mmm; + UInt32 h2, h3, d2, d3, pos; + unsigned maxLen; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash [h2]; + d3 = pos - (hash + kFix3HashSize)[h3]; + // d4 = pos - (hash + kFix4HashSize)[h4]; + + curMatch = (hash + kFix5HashSize)[hv]; + + hash [h2] = pos; + (hash + kFix3HashSize)[h3] = pos; + // (hash + kFix4HashSize)[h4] = pos; + (hash + kFix5HashSize)[hv] = pos; + + SET_mmm + + maxLen = 4; + + for (;;) + { + if (d2 < mmm && *(cur - d2) == *cur) + { + distances[0] = 2; + distances[1] = d2 - 1; + distances += 2; + if (*(cur - d2 + 2) == cur[2]) + { + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + distances[1] = d3 - 1; + distances += 2; + d2 = d3; + } + else + break; + } + else if (d3 < mmm && *(cur - d3) == *cur) + { + distances[1] = d3 - 1; + distances += 2; + d2 = d3; + } + else + break; + + distances[-2] = 3; + if (*(cur - d2 + 3) != cur[3]) + break; + UPDATE_maxLen + distances[-2] = (UInt32)maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET + } + break; + } + + GET_MATCHES_FOOTER_HC(maxLen) +} + + +UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + GET_MATCHES_FOOTER_HC(2) +} + + +static void Bt2_MatchFinder_Skip(void *_p, UInt32 num) +{ + CMatchFinder *p = (CMatchFinder *)_p; + SKIP_HEADER(2) + { + HASH2_CALC + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + } + SKIP_FOOTER +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + SKIP_HEADER(3) + { + HASH_ZIP_CALC + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; + } + SKIP_FOOTER +} + +static void Bt3_MatchFinder_Skip(void *_p, UInt32 num) +{ + CMatchFinder *p = (CMatchFinder *)_p; + SKIP_HEADER(3) + { + UInt32 h2; + UInt32 *hash; + HASH3_CALC + hash = p->hash; + curMatch = (hash + kFix3HashSize)[hv]; + hash[h2] = + (hash + kFix3HashSize)[hv] = p->pos; + } + SKIP_FOOTER +} + +static void Bt4_MatchFinder_Skip(void *_p, UInt32 num) +{ + CMatchFinder *p = (CMatchFinder *)_p; + SKIP_HEADER(4) + { + UInt32 h2, h3; + UInt32 *hash; + HASH4_CALC + hash = p->hash; + curMatch = (hash + kFix4HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[hv] = p->pos; + } + SKIP_FOOTER +} + +static void Bt5_MatchFinder_Skip(void *_p, UInt32 num) +{ + CMatchFinder *p = (CMatchFinder *)_p; + SKIP_HEADER(5) + { + UInt32 h2, h3; + UInt32 *hash; + HASH5_CALC + hash = p->hash; + curMatch = (hash + kFix5HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + // (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = p->pos; + } + SKIP_FOOTER +} + + +#define HC_SKIP_HEADER(minLen) \ + do { if (p->lenLimit < minLen) { MatchFinder_MovePos(p); num--; continue; } { \ + const Byte *cur; \ + UInt32 *hash; \ + UInt32 *son; \ + UInt32 pos = p->pos; \ + UInt32 num2 = num; \ + /* (p->pos == p->posLimit) is not allowed here !!! */ \ + { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \ + num -= num2; \ + { const UInt32 cycPos = p->cyclicBufferPos; \ + son = p->son + cycPos; \ + p->cyclicBufferPos = cycPos + num2; } \ + cur = p->buffer; \ + hash = p->hash; \ + do { \ + UInt32 curMatch; \ + UInt32 hv; + + +#define HC_SKIP_FOOTER \ + cur++; pos++; *son++ = curMatch; \ + } while (--num2); \ + p->buffer = cur; \ + p->pos = pos; \ + if (pos == p->posLimit) MatchFinder_CheckLimits(p); \ + }} while(num); \ + + +static void Hc4_MatchFinder_Skip(void *_p, UInt32 num) +{ + CMatchFinder *p = (CMatchFinder *)_p; + HC_SKIP_HEADER(4) + + UInt32 h2, h3; + HASH4_CALC + curMatch = (hash + kFix4HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + (hash + kFix4HashSize)[hv] = pos; + + HC_SKIP_FOOTER +} + + +static void Hc5_MatchFinder_Skip(void *_p, UInt32 num) +{ + CMatchFinder *p = (CMatchFinder *)_p; + HC_SKIP_HEADER(5) + + UInt32 h2, h3; + HASH5_CALC + curMatch = (hash + kFix5HashSize)[hv]; + hash [h2] = + (hash + kFix3HashSize)[h3] = + // (hash + kFix4HashSize)[h4] = + (hash + kFix5HashSize)[hv] = pos; + + HC_SKIP_FOOTER +} + + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + HC_SKIP_HEADER(3) + + HASH_ZIP_CALC + curMatch = hash[hv]; + hash[hv] = pos; + + HC_SKIP_FOOTER +} + + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable) +{ + vTable->Init = MatchFinder_Init; + vTable->GetNumAvailableBytes = MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + if (p->numHashBytes <= 4) + { + vTable->GetMatches = Hc4_MatchFinder_GetMatches; + vTable->Skip = Hc4_MatchFinder_Skip; + } + else + { + vTable->GetMatches = Hc5_MatchFinder_GetMatches; + vTable->Skip = Hc5_MatchFinder_Skip; + } + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = Bt2_MatchFinder_GetMatches; + vTable->Skip = Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = Bt3_MatchFinder_GetMatches; + vTable->Skip = Bt3_MatchFinder_Skip; + } + else if (p->numHashBytes == 4) + { + vTable->GetMatches = Bt4_MatchFinder_GetMatches; + vTable->Skip = Bt4_MatchFinder_Skip; + } + else + { + vTable->GetMatches = Bt5_MatchFinder_GetMatches; + vTable->Skip = Bt5_MatchFinder_Skip; + } +} + + + +void LzFindPrepare(void) +{ + #ifndef FORCE_LZFIND_SATUR_SUB_128 + #ifdef USE_LZFIND_SATUR_SUB_128 + LZFIND_SATUR_SUB_CODE_FUNC f = NULL; + #ifdef MY_CPU_ARM_OR_ARM64 + { + if (CPU_IsSupported_NEON()) + { + // #pragma message ("=== LzFind NEON") + PRF(printf("\n=== LzFind NEON\n")); + f = LzFind_SaturSub_128; + } + // f = 0; // for debug + } + #else // MY_CPU_ARM_OR_ARM64 + if (CPU_IsSupported_SSE41()) + { + // #pragma message ("=== LzFind SSE41") + PRF(printf("\n=== LzFind SSE41\n")); + f = LzFind_SaturSub_128; + + #ifdef USE_LZFIND_SATUR_SUB_256 + if (CPU_IsSupported_AVX2()) + { + // #pragma message ("=== LzFind AVX2") + PRF(printf("\n=== LzFind AVX2\n")); + f = LzFind_SaturSub_256; + } + #endif + } + #endif // MY_CPU_ARM_OR_ARM64 + g_LzFind_SaturSub = f; + #endif // USE_LZFIND_SATUR_SUB_128 + #endif // FORCE_LZFIND_SATUR_SUB_128 +} + + +#undef MOVE_POS +#undef MOVE_POS_RET +#undef PRF diff --git a/C/LzFind.h b/C/LzFind.h index fd778747d..67e8a6e02 100644 --- a/C/LzFind.h +++ b/C/LzFind.h @@ -1,160 +1,160 @@ -/* LzFind.h -- Match finder for LZ algorithms -2024-01-22 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZ_FIND_H -#define ZIP7_INC_LZ_FIND_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -typedef UInt32 CLzRef; - -typedef struct -{ - const Byte *buffer; - UInt32 pos; - UInt32 posLimit; - UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */ - UInt32 lenLimit; - - UInt32 cyclicBufferPos; - UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ - - Byte streamEndWasReached; - Byte btMode; - Byte bigHash; - Byte directInput; - - UInt32 matchMaxLen; - CLzRef *hash; - CLzRef *son; - UInt32 hashMask; - UInt32 cutValue; - - Byte *bufBase; - ISeqInStreamPtr stream; - - UInt32 blockSize; - UInt32 keepSizeBefore; - UInt32 keepSizeAfter; - - UInt32 numHashBytes; - size_t directInputRem; - UInt32 historySize; - UInt32 fixedHashSize; - Byte numHashBytes_Min; - Byte numHashOutBits; - Byte _pad2_[2]; - SRes result; - UInt32 crc[256]; - size_t numRefs; - - UInt64 expectedDataSize; -} CMatchFinder; - -#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer) - -#define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos)) - -/* -#define Inline_MatchFinder_IsFinishedOK(p) \ - ((p)->streamEndWasReached \ - && (p)->streamPos == (p)->pos \ - && (!(p)->directInput || (p)->directInputRem == 0)) -*/ - -int MatchFinder_NeedMove(CMatchFinder *p); -/* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */ -void MatchFinder_MoveBlock(CMatchFinder *p); -void MatchFinder_ReadIfRequired(CMatchFinder *p); - -void MatchFinder_Construct(CMatchFinder *p); - -/* (directInput = 0) is default value. - It's required to provide correct (directInput) value - before calling MatchFinder_Create(). - You can set (directInput) by any of the following calls: - - MatchFinder_SET_DIRECT_INPUT_BUF() - - MatchFinder_SET_STREAM() - - MatchFinder_SET_STREAM_MODE() -*/ - -#define MatchFinder_SET_DIRECT_INPUT_BUF(p, _src_, _srcLen_) { \ - (p)->stream = NULL; \ - (p)->directInput = 1; \ - (p)->buffer = (_src_); \ - (p)->directInputRem = (_srcLen_); } - -/* -#define MatchFinder_SET_STREAM_MODE(p) { \ - (p)->directInput = 0; } -*/ - -#define MatchFinder_SET_STREAM(p, _stream_) { \ - (p)->stream = _stream_; \ - (p)->directInput = 0; } - - -int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, - UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, - ISzAllocPtr alloc); -void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); - -/* -#define MatchFinder_INIT_POS(p, val) \ - (p)->pos = (val); \ - (p)->streamPos = (val); -*/ - -// void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); -#define MatchFinder_REDUCE_OFFSETS(p, subValue) \ - (p)->pos -= (subValue); \ - (p)->streamPos -= (subValue); - - -UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, - UInt32 *distances, UInt32 maxLen); - -/* -Conditions: - Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. - Mf_GetPointerToCurrentPos_Func's result must be used only before any other function -*/ - -typedef void (*Mf_Init_Func)(void *object); -typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); -typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); -typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances); -typedef void (*Mf_Skip_Func)(void *object, UInt32); - -typedef struct -{ - Mf_Init_Func Init; - Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; - Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; - Mf_GetMatches_Func GetMatches; - Mf_Skip_Func Skip; -} IMatchFinder2; - -void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable); - -void MatchFinder_Init_LowHash(CMatchFinder *p); -void MatchFinder_Init_HighHash(CMatchFinder *p); -void MatchFinder_Init_4(CMatchFinder *p); -// void MatchFinder_Init(CMatchFinder *p); -void MatchFinder_Init(void *p); - -UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); -UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); - -void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); -void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); - -void LzFindPrepare(void); - -EXTERN_C_END - -#endif +/* LzFind.h -- Match finder for LZ algorithms +2024-01-22 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZ_FIND_H +#define ZIP7_INC_LZ_FIND_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef UInt32 CLzRef; + +typedef struct +{ + const Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */ + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + Byte streamEndWasReached; + Byte btMode; + Byte bigHash; + Byte directInput; + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufBase; + ISeqInStreamPtr stream; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + size_t directInputRem; + UInt32 historySize; + UInt32 fixedHashSize; + Byte numHashBytes_Min; + Byte numHashOutBits; + Byte _pad2_[2]; + SRes result; + UInt32 crc[256]; + size_t numRefs; + + UInt64 expectedDataSize; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos)) + +/* +#define Inline_MatchFinder_IsFinishedOK(p) \ + ((p)->streamEndWasReached \ + && (p)->streamPos == (p)->pos \ + && (!(p)->directInput || (p)->directInputRem == 0)) +*/ + +int MatchFinder_NeedMove(CMatchFinder *p); +/* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */ +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* (directInput = 0) is default value. + It's required to provide correct (directInput) value + before calling MatchFinder_Create(). + You can set (directInput) by any of the following calls: + - MatchFinder_SET_DIRECT_INPUT_BUF() + - MatchFinder_SET_STREAM() + - MatchFinder_SET_STREAM_MODE() +*/ + +#define MatchFinder_SET_DIRECT_INPUT_BUF(p, _src_, _srcLen_) { \ + (p)->stream = NULL; \ + (p)->directInput = 1; \ + (p)->buffer = (_src_); \ + (p)->directInputRem = (_srcLen_); } + +/* +#define MatchFinder_SET_STREAM_MODE(p) { \ + (p)->directInput = 0; } +*/ + +#define MatchFinder_SET_STREAM(p, _stream_) { \ + (p)->stream = _stream_; \ + (p)->directInput = 0; } + + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAllocPtr alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); + +/* +#define MatchFinder_INIT_POS(p, val) \ + (p)->pos = (val); \ + (p)->streamPos = (val); +*/ + +// void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); +#define MatchFinder_REDUCE_OFFSETS(p, subValue) \ + (p)->pos -= (subValue); \ + (p)->streamPos -= (subValue); + + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct +{ + Mf_Init_Func Init; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder2; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable); + +void MatchFinder_Init_LowHash(CMatchFinder *p); +void MatchFinder_Init_HighHash(CMatchFinder *p); +void MatchFinder_Init_4(CMatchFinder *p); +// void MatchFinder_Init(CMatchFinder *p); +void MatchFinder_Init(void *p); + +UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +void LzFindPrepare(void); + +EXTERN_C_END + +#endif diff --git a/C/LzFindMt.c b/C/LzFindMt.c index 260e3210b..ac9d59d0f 100644 --- a/C/LzFindMt.c +++ b/C/LzFindMt.c @@ -1,1414 +1,1414 @@ -/* LzFindMt.c -- multithreaded Match finder for LZ algorithms -2024-01-22 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #include - -#include "CpuArch.h" - -#include "LzHash.h" -#include "LzFindMt.h" - -// #define LOG_ITERS - -// #define LOG_THREAD - -#ifdef LOG_THREAD -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - -#ifdef LOG_ITERS -#include -extern UInt64 g_NumIters_Tree; -extern UInt64 g_NumIters_Loop; -extern UInt64 g_NumIters_Bytes; -#define LOG_ITER(x) x -#else -#define LOG_ITER(x) -#endif - -#define kMtHashBlockSize ((UInt32)1 << 17) -#define kMtHashNumBlocks (1 << 1) - -#define GET_HASH_BLOCK_OFFSET(i) (((i) & (kMtHashNumBlocks - 1)) * kMtHashBlockSize) - -#define kMtBtBlockSize ((UInt32)1 << 16) -#define kMtBtNumBlocks (1 << 4) - -#define GET_BT_BLOCK_OFFSET(i) (((i) & (kMtBtNumBlocks - 1)) * (size_t)kMtBtBlockSize) - -/* - HASH functions: - We use raw 8/16 bits from a[1] and a[2], - xored with crc(a[0]) and crc(a[3]). - We check a[0], a[3] only. We don't need to compare a[1] and a[2] in matches. - our crc() function provides one-to-one correspondence for low 8-bit values: - (crc[0...0xFF] & 0xFF) <-> [0...0xFF] -*/ - -#define MF(mt) ((mt)->MatchFinder) -#define MF_CRC (p->crc) - -// #define MF(mt) (&(mt)->MatchFinder) -// #define MF_CRC (p->MatchFinder.crc) - -#define MT_HASH2_CALC \ - h2 = (MF_CRC[cur[0]] ^ cur[1]) & (kHash2Size - 1); - -#define MT_HASH3_CALC { \ - UInt32 temp = MF_CRC[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } - -/* -#define MT_HASH3_CALC__NO_2 { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } - -#define MT_HASH4_CALC { \ - UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - h2 = temp & (kHash2Size - 1); \ - temp ^= ((UInt32)cur[2] << 8); \ - h3 = temp & (kHash3Size - 1); \ - h4 = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hash4Mask; } - // (kHash4Size - 1); -*/ - - -Z7_NO_INLINE -static void MtSync_Construct(CMtSync *p) -{ - p->affinity = 0; - p->wasCreated = False; - p->csWasInitialized = False; - p->csWasEntered = False; - Thread_CONSTRUCT(&p->thread) - Event_Construct(&p->canStart); - Event_Construct(&p->wasStopped); - Semaphore_Construct(&p->freeSemaphore); - Semaphore_Construct(&p->filledSemaphore); -} - - -// #define DEBUG_BUFFER_LOCK // define it to debug lock state - -#ifdef DEBUG_BUFFER_LOCK -#include -#define BUFFER_MUST_BE_LOCKED(p) if (!(p)->csWasEntered) exit(1); -#define BUFFER_MUST_BE_UNLOCKED(p) if ( (p)->csWasEntered) exit(1); -#else -#define BUFFER_MUST_BE_LOCKED(p) -#define BUFFER_MUST_BE_UNLOCKED(p) -#endif - -#define LOCK_BUFFER(p) { \ - BUFFER_MUST_BE_UNLOCKED(p); \ - CriticalSection_Enter(&(p)->cs); \ - (p)->csWasEntered = True; } - -#define UNLOCK_BUFFER(p) { \ - BUFFER_MUST_BE_LOCKED(p); \ - CriticalSection_Leave(&(p)->cs); \ - (p)->csWasEntered = False; } - - -Z7_NO_INLINE -static UInt32 MtSync_GetNextBlock(CMtSync *p) -{ - UInt32 numBlocks = 0; - if (p->needStart) - { - BUFFER_MUST_BE_UNLOCKED(p) - p->numProcessedBlocks = 1; - p->needStart = False; - p->stopWriting = False; - p->exit = False; - Event_Reset(&p->wasStopped); - Event_Set(&p->canStart); - } - else - { - UNLOCK_BUFFER(p) - // we free current block - numBlocks = p->numProcessedBlocks++; - Semaphore_Release1(&p->freeSemaphore); - } - - // buffer is UNLOCKED here - Semaphore_Wait(&p->filledSemaphore); - LOCK_BUFFER(p) - return numBlocks; -} - - -/* if Writing (Processing) thread was started, we must call MtSync_StopWriting() */ - -Z7_NO_INLINE -static void MtSync_StopWriting(CMtSync *p) -{ - if (!Thread_WasCreated(&p->thread) || p->needStart) - return; - - PRF(printf("\nMtSync_StopWriting %p\n", p)); - - if (p->csWasEntered) - { - /* we don't use buffer in this thread after StopWriting(). - So we UNLOCK buffer. - And we restore default UNLOCKED state for stopped thread */ - UNLOCK_BUFFER(p) - } - - /* We send (p->stopWriting) message and release freeSemaphore - to free current block. - So the thread will see (p->stopWriting) at some - iteration after Wait(freeSemaphore). - The thread doesn't need to fill all avail free blocks, - so we can get fast thread stop. - */ - - p->stopWriting = True; - Semaphore_Release1(&p->freeSemaphore); // check semaphore count !!! - - PRF(printf("\nMtSync_StopWriting %p : Event_Wait(&p->wasStopped)\n", p)); - Event_Wait(&p->wasStopped); - PRF(printf("\nMtSync_StopWriting %p : Event_Wait() finsihed\n", p)); - - /* 21.03 : we don't restore samaphore counters here. - We will recreate and reinit samaphores in next start */ - - p->needStart = True; -} - - -Z7_NO_INLINE -static void MtSync_Destruct(CMtSync *p) -{ - PRF(printf("\nMtSync_Destruct %p\n", p)); - - if (Thread_WasCreated(&p->thread)) - { - /* we want thread to be in Stopped state before sending EXIT command. - note: stop(btSync) will stop (htSync) also */ - MtSync_StopWriting(p); - /* thread in Stopped state here : (p->needStart == true) */ - p->exit = True; - // if (p->needStart) // it's (true) - Event_Set(&p->canStart); // we send EXIT command to thread - Thread_Wait_Close(&p->thread); // we wait thread finishing - } - - if (p->csWasInitialized) - { - CriticalSection_Delete(&p->cs); - p->csWasInitialized = False; - } - p->csWasEntered = False; - - Event_Close(&p->canStart); - Event_Close(&p->wasStopped); - Semaphore_Close(&p->freeSemaphore); - Semaphore_Close(&p->filledSemaphore); - - p->wasCreated = False; -} - - -// #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } -// we want to get real system error codes here instead of SZ_ERROR_THREAD -#define RINOK_THREAD(x) RINOK_WRes(x) - - -// call it before each new file (when new starting is required): -Z7_NO_INLINE -static SRes MtSync_Init(CMtSync *p, UInt32 numBlocks) -{ - WRes wres; - // BUFFER_MUST_BE_UNLOCKED(p) - if (!p->needStart || p->csWasEntered) - return SZ_ERROR_FAIL; - wres = Semaphore_OptCreateInit(&p->freeSemaphore, numBlocks, numBlocks); - if (wres == 0) - wres = Semaphore_OptCreateInit(&p->filledSemaphore, 0, numBlocks); - return MY_SRes_HRESULT_FROM_WRes(wres); -} - - -static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) -{ - WRes wres; - - if (p->wasCreated) - return SZ_OK; - - RINOK_THREAD(CriticalSection_Init(&p->cs)) - p->csWasInitialized = True; - p->csWasEntered = False; - - RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)) - RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)) - - p->needStart = True; - p->exit = True; /* p->exit is unused before (canStart) Event. - But in case of some unexpected code failure we will get fast exit from thread */ - - // return ERROR_TOO_MANY_POSTS; // for debug - // return EINVAL; // for debug - - if (p->affinity != 0) - wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity); - else - wres = Thread_Create(&p->thread, startAddress, obj); - - RINOK_THREAD(wres) - p->wasCreated = True; - return SZ_OK; -} - - -Z7_NO_INLINE -static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) -{ - const WRes wres = MtSync_Create_WRes(p, startAddress, obj); - if (wres == 0) - return 0; - MtSync_Destruct(p); - return MY_SRes_HRESULT_FROM_WRes(wres); -} - - -// ---------- HASH THREAD ---------- - -#define kMtMaxValForNormalize 0xFFFFFFFF -// #define kMtMaxValForNormalize ((1 << 21)) // for debug -// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses - -#ifdef MY_CPU_LE_UNALIGN - #define GetUi24hi_from32(p) ((UInt32)GetUi32(p) >> 8) -#else - #define GetUi24hi_from32(p) ((p)[1] ^ ((UInt32)(p)[2] << 8) ^ ((UInt32)(p)[3] << 16)) -#endif - -#define GetHeads_DECL(name) \ - static void GetHeads ## name(const Byte *p, UInt32 pos, \ - UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) - -#define GetHeads_LOOP(v) \ - for (; numHeads != 0; numHeads--) { \ - const UInt32 value = (v); \ - p++; \ - *heads++ = pos - hash[value]; \ - hash[value] = pos++; } - -#define DEF_GetHeads2(name, v, action) \ - GetHeads_DECL(name) { action \ - GetHeads_LOOP(v) } - -#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) - -DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) -DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask) -DEF_GetHeads2(3b, GetUi16(p) ^ ((UInt32)(p)[2] << 16), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) -// BT3 is not good for crc collisions for big hashMask values. - -/* -GetHeads_DECL(3b) -{ - UNUSED_VAR(hashMask); - UNUSED_VAR(crc); - { - const Byte *pLim = p + numHeads; - if (numHeads == 0) - return; - pLim--; - while (p < pLim) - { - UInt32 v1 = GetUi32(p); - UInt32 v0 = v1 & 0xFFFFFF; - UInt32 h0, h1; - p += 2; - v1 >>= 8; - h0 = hash[v0]; hash[v0] = pos; heads[0] = pos - h0; pos++; - h1 = hash[v1]; hash[v1] = pos; heads[1] = pos - h1; pos++; - heads += 2; - } - if (p == pLim) - { - UInt32 v0 = GetUi16(p) ^ ((UInt32)(p)[2] << 16); - *heads = pos - hash[v0]; - hash[v0] = pos; - } - } -} -*/ - -/* -GetHeads_DECL(4) -{ - unsigned sh = 0; - UNUSED_VAR(crc) - while ((hashMask & 0x80000000) == 0) - { - hashMask <<= 1; - sh++; - } - GetHeads_LOOP((GetUi32(p) * 0xa54a1) >> sh) -} -#define GetHeads4b GetHeads4 -*/ - -#define USE_GetHeads_LOCAL_CRC - -#ifdef USE_GetHeads_LOCAL_CRC - -GetHeads_DECL(4) -{ - UInt32 crc0[256]; - UInt32 crc1[256]; - { - unsigned i; - for (i = 0; i < 256; i++) - { - UInt32 v = crc[i]; - crc0[i] = v & hashMask; - crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; - // crc1[i] = rotlFixed(v, 8) & hashMask; - } - } - GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ (UInt32)GetUi16(p+1)) -} - -GetHeads_DECL(4b) -{ - UInt32 crc0[256]; - { - unsigned i; - for (i = 0; i < 256; i++) - crc0[i] = crc[i] & hashMask; - } - GetHeads_LOOP(crc0[p[0]] ^ GetUi24hi_from32(p)) -} - -GetHeads_DECL(5) -{ - UInt32 crc0[256]; - UInt32 crc1[256]; - UInt32 crc2[256]; - { - unsigned i; - for (i = 0; i < 256; i++) - { - UInt32 v = crc[i]; - crc0[i] = v & hashMask; - crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; - crc2[i] = (v << kLzHash_CrcShift_2) & hashMask; - } - } - GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ crc2[p[4]] ^ (UInt32)GetUi16(p+1)) -} - -GetHeads_DECL(5b) -{ - UInt32 crc0[256]; - UInt32 crc1[256]; - { - unsigned i; - for (i = 0; i < 256; i++) - { - UInt32 v = crc[i]; - crc0[i] = v & hashMask; - crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; - } - } - GetHeads_LOOP(crc0[p[0]] ^ crc1[p[4]] ^ GetUi24hi_from32(p)) -} - -#else - -DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask) -DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask) -DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask) -DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask) - -#endif - - -static void HashThreadFunc(CMatchFinderMt *mt) -{ - CMtSync *p = &mt->hashSync; - PRF(printf("\nHashThreadFunc\n")); - - for (;;) - { - UInt32 blockIndex = 0; - PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart)\n")); - Event_Wait(&p->canStart); - PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart) : after \n")); - if (p->exit) - { - PRF(printf("\nHashThreadFunc : exit \n")); - return; - } - - MatchFinder_Init_HighHash(MF(mt)); - - for (;;) - { - PRF(printf("Hash thread block = %d pos = %d\n", (unsigned)blockIndex, mt->MatchFinder->pos)); - - { - CMatchFinder *mf = MF(mt); - if (MatchFinder_NeedMove(mf)) - { - CriticalSection_Enter(&mt->btSync.cs); - CriticalSection_Enter(&mt->hashSync.cs); - { - const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); - ptrdiff_t offset; - MatchFinder_MoveBlock(mf); - offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); - mt->pointerToCurPos -= offset; - mt->buffer -= offset; - } - CriticalSection_Leave(&mt->hashSync.cs); - CriticalSection_Leave(&mt->btSync.cs); - continue; - } - - Semaphore_Wait(&p->freeSemaphore); - - if (p->exit) // exit is unexpected here. But we check it here for some failure case - return; - - // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) - if (p->stopWriting) - break; - - MatchFinder_ReadIfRequired(mf); - { - UInt32 *heads = mt->hashBuf + GET_HASH_BLOCK_OFFSET(blockIndex++); - UInt32 num = Inline_MatchFinder_GetNumAvailableBytes(mf); - heads[0] = 2; - heads[1] = num; - - /* heads[1] contains the number of avail bytes: - if (avail < mf->numHashBytes) : - { - it means that stream was finished - HASH_THREAD and BT_TREAD must move position for heads[1] (avail) bytes. - HASH_THREAD doesn't stop, - HASH_THREAD fills only the header (2 numbers) for all next blocks: - {2, NumHashBytes - 1}, {2,0}, {2,0}, ... , {2,0} - } - else - { - HASH_THREAD and BT_TREAD must move position for (heads[0] - 2) bytes; - } - */ - - if (num >= mf->numHashBytes) - { - num = num - mf->numHashBytes + 1; - if (num > kMtHashBlockSize - 2) - num = kMtHashBlockSize - 2; - - if (mf->pos > (UInt32)kMtMaxValForNormalize - num) - { - const UInt32 subValue = (mf->pos - mf->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); - MatchFinder_REDUCE_OFFSETS(mf, subValue) - MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); - } - - heads[0] = 2 + num; - mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); - } - - mf->pos += num; // wrap over zero is allowed at the end of stream - mf->buffer += num; - } - } - - Semaphore_Release1(&p->filledSemaphore); - } // for() processing end - - // p->numBlocks_Sent = blockIndex; - Event_Set(&p->wasStopped); - } // for() thread end -} - - - - -// ---------- BT THREAD ---------- - -/* we use one variable instead of two (cyclicBufferPos == pos) before CyclicBuf wrap. - here we define fixed offset of (p->pos) from (p->cyclicBufferPos) */ -#define CYC_TO_POS_OFFSET 0 -// #define CYC_TO_POS_OFFSET 1 // for debug - -#define MFMT_GM_INLINE - -#ifdef MFMT_GM_INLINE - -/* - we use size_t for (pos) instead of UInt32 - to eliminate "movsx" BUG in old MSVC x64 compiler. -*/ - - -UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, - UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, - UInt32 *posRes); - -#endif - - -static void BtGetMatches(CMatchFinderMt *p, UInt32 *d) -{ - UInt32 numProcessed = 0; - UInt32 curPos = 2; - - /* GetMatchesSpec() functions don't create (len = 1) - in [len, dist] match pairs, if (p->numHashBytes >= 2) - Also we suppose here that (matchMaxLen >= 2). - So the following code for (reserve) is not required - UInt32 reserve = (p->matchMaxLen * 2); - const UInt32 kNumHashBytes_Max = 5; // BT_HASH_BYTES_MAX - if (reserve < kNumHashBytes_Max - 1) - reserve = kNumHashBytes_Max - 1; - const UInt32 limit = kMtBtBlockSize - (reserve); - */ - - const UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); - - d[1] = p->hashNumAvail; - - if (p->failure_BT) - { - // printf("\n == 1 BtGetMatches() p->failure_BT\n"); - d[0] = 0; - // d[1] = 0; - return; - } - - while (curPos < limit) - { - if (p->hashBufPos == p->hashBufPosLimit) - { - // MatchFinderMt_GetNextBlock_Hash(p); - UInt32 avail; - { - const UInt32 bi = MtSync_GetNextBlock(&p->hashSync); - const UInt32 k = GET_HASH_BLOCK_OFFSET(bi); - const UInt32 *h = p->hashBuf + k; - avail = h[1]; - p->hashBufPosLimit = k + h[0]; - p->hashNumAvail = avail; - p->hashBufPos = k + 2; - } - - { - /* we must prevent UInt32 overflow for avail total value, - if avail was increased with new hash block */ - UInt32 availSum = numProcessed + avail; - if (availSum < numProcessed) - availSum = (UInt32)(Int32)-1; - d[1] = availSum; - } - - if (avail >= p->numHashBytes) - continue; - - // if (p->hashBufPos != p->hashBufPosLimit) exit(1); - - /* (avail < p->numHashBytes) - It means that stream was finished. - And (avail) - is a number of remaining bytes, - we fill (d) for (avail) bytes for LZ_THREAD (receiver). - but we don't update (p->pos) and (p->cyclicBufferPos) here in BT_THREAD */ - - /* here we suppose that we have space enough: - (kMtBtBlockSize - curPos >= p->hashNumAvail) */ - p->hashNumAvail = 0; - d[0] = curPos + avail; - d += curPos; - for (; avail != 0; avail--) - *d++ = 0; - return; - } - { - UInt32 size = p->hashBufPosLimit - p->hashBufPos; - UInt32 pos = p->pos; - UInt32 cyclicBufferPos = p->cyclicBufferPos; - UInt32 lenLimit = p->matchMaxLen; - if (lenLimit >= p->hashNumAvail) - lenLimit = p->hashNumAvail; - { - UInt32 size2 = p->hashNumAvail - lenLimit + 1; - if (size2 < size) - size = size2; - size2 = p->cyclicBufferSize - cyclicBufferPos; - if (size2 < size) - size = size2; - } - - if (pos > (UInt32)kMtMaxValForNormalize - size) - { - const UInt32 subValue = (pos - p->cyclicBufferSize); // & ~(UInt32)(kNormalizeAlign - 1); - pos -= subValue; - p->pos = pos; - MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); - } - - #ifndef MFMT_GM_INLINE - while (curPos < limit && size-- != 0) - { - UInt32 *startDistances = d + curPos; - UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], - pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - startDistances + 1, p->numHashBytes - 1) - startDistances); - *startDistances = num - 1; - curPos += num; - cyclicBufferPos++; - pos++; - p->buffer++; - } - #else - { - UInt32 posRes = pos; - const UInt32 *d_end; - { - d_end = GetMatchesSpecN_2( - p->buffer + lenLimit - 1, - pos, p->buffer, p->son, p->cutValue, d + curPos, - p->numHashBytes - 1, p->hashBuf + p->hashBufPos, - d + limit, p->hashBuf + p->hashBufPos + size, - cyclicBufferPos, p->cyclicBufferSize, - &posRes); - } - { - if (!d_end) - { - // printf("\n == 2 BtGetMatches() p->failure_BT\n"); - // internal data failure - p->failure_BT = True; - d[0] = 0; - // d[1] = 0; - return; - } - } - curPos = (UInt32)(d_end - d); - { - const UInt32 processed = posRes - pos; - pos = posRes; - p->hashBufPos += processed; - cyclicBufferPos += processed; - p->buffer += processed; - } - } - #endif - - { - const UInt32 processed = pos - p->pos; - numProcessed += processed; - p->hashNumAvail -= processed; - p->pos = pos; - } - if (cyclicBufferPos == p->cyclicBufferSize) - cyclicBufferPos = 0; - p->cyclicBufferPos = cyclicBufferPos; - } - } - - d[0] = curPos; -} - - -static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) -{ - CMtSync *sync = &p->hashSync; - - BUFFER_MUST_BE_UNLOCKED(sync) - - if (!sync->needStart) - { - LOCK_BUFFER(sync) - } - - BtGetMatches(p, p->btBuf + GET_BT_BLOCK_OFFSET(globalBlockIndex)); - - /* We suppose that we have called GetNextBlock() from start. - So buffer is LOCKED */ - - UNLOCK_BUFFER(sync) -} - - -Z7_NO_INLINE -static void BtThreadFunc(CMatchFinderMt *mt) -{ - CMtSync *p = &mt->btSync; - for (;;) - { - UInt32 blockIndex = 0; - Event_Wait(&p->canStart); - - for (;;) - { - PRF(printf(" BT thread block = %d pos = %d\n", (unsigned)blockIndex, mt->pos)); - /* (p->exit == true) is possible after (p->canStart) at first loop iteration - and is unexpected after more Wait(freeSemaphore) iterations */ - if (p->exit) - return; - - Semaphore_Wait(&p->freeSemaphore); - - // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) - if (p->stopWriting) - break; - - BtFillBlock(mt, blockIndex++); - - Semaphore_Release1(&p->filledSemaphore); - } - - // we stop HASH_THREAD here - MtSync_StopWriting(&mt->hashSync); - - // p->numBlocks_Sent = blockIndex; - Event_Set(&p->wasStopped); - } -} - - -void MatchFinderMt_Construct(CMatchFinderMt *p) -{ - p->hashBuf = NULL; - MtSync_Construct(&p->hashSync); - MtSync_Construct(&p->btSync); -} - -static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->hashBuf); - p->hashBuf = NULL; -} - -void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) -{ - /* - HASH_THREAD can use CriticalSection(s) btSync.cs and hashSync.cs. - So we must be sure that HASH_THREAD will not use CriticalSection(s) - after deleting CriticalSection here. - - we call ReleaseStream(p) - that calls StopWriting(btSync) - that calls StopWriting(hashSync), if it's required to stop HASH_THREAD. - after StopWriting() it's safe to destruct MtSync(s) in any order */ - - MatchFinderMt_ReleaseStream(p); - - MtSync_Destruct(&p->btSync); - MtSync_Destruct(&p->hashSync); - - LOG_ITER( - printf("\nTree %9d * %7d iter = %9d = sum : bytes = %9d\n", - (UInt32)(g_NumIters_Tree / 1000), - (UInt32)(((UInt64)g_NumIters_Loop * 1000) / (g_NumIters_Tree + 1)), - (UInt32)(g_NumIters_Loop / 1000), - (UInt32)(g_NumIters_Bytes / 1000) - )); - - MatchFinderMt_FreeMem(p, alloc); -} - - -#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) -#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) - - -static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } -static THREAD_FUNC_DECL BtThreadFunc2(void *p) -{ - Byte allocaDummy[0x180]; - unsigned i = 0; - for (i = 0; i < 16; i++) - allocaDummy[i] = (Byte)0; - if (allocaDummy[0] == 0) - BtThreadFunc((CMatchFinderMt *)p); - return 0; -} - - -SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, - UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc) -{ - CMatchFinder *mf = MF(p); - p->historySize = historySize; - if (kMtBtBlockSize <= matchMaxLen * 4) - return SZ_ERROR_PARAM; - if (!p->hashBuf) - { - p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, ((size_t)kHashBufferSize + (size_t)kBtBufferSize) * sizeof(UInt32)); - if (!p->hashBuf) - return SZ_ERROR_MEM; - p->btBuf = p->hashBuf + kHashBufferSize; - } - keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); - keepAddBufferAfter += kMtHashBlockSize; - if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) - return SZ_ERROR_MEM; - - RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p)) - RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p)) - return SZ_OK; -} - - -SRes MatchFinderMt_InitMt(CMatchFinderMt *p) -{ - RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks)) - return MtSync_Init(&p->btSync, kMtBtNumBlocks); -} - - -static void MatchFinderMt_Init(void *_p) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - CMatchFinder *mf = MF(p); - - p->btBufPos = - p->btBufPosLimit = NULL; - p->hashBufPos = - p->hashBufPosLimit = 0; - p->hashNumAvail = 0; // 21.03 - - p->failure_BT = False; - - /* Init without data reading. We don't want to read data in this thread */ - MatchFinder_Init_4(mf); - - MatchFinder_Init_LowHash(mf); - - p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); - p->btNumAvailBytes = 0; - p->failure_LZ_BT = False; - // p->failure_LZ_LZ = False; - - p->lzPos = - 1; // optimal smallest value - // 0; // for debug: ignores match to start - // kNormalizeAlign; // for debug - - p->hash = mf->hash; - p->fixedHashSize = mf->fixedHashSize; - // p->hash4Mask = mf->hash4Mask; - p->crc = mf->crc; - // memcpy(p->crc, mf->crc, sizeof(mf->crc)); - - p->son = mf->son; - p->matchMaxLen = mf->matchMaxLen; - p->numHashBytes = mf->numHashBytes; - - /* (mf->pos) and (mf->streamPos) were already initialized to 1 in MatchFinder_Init_4() */ - // mf->streamPos = mf->pos = 1; // optimal smallest value - // 0; // for debug: ignores match to start - // kNormalizeAlign; // for debug - - /* we must init (p->pos = mf->pos) for BT, because - BT code needs (p->pos == delta_value_for_empty_hash_record == mf->pos) */ - p->pos = mf->pos; // do not change it - - p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); - p->cyclicBufferSize = mf->cyclicBufferSize; - p->buffer = mf->buffer; - p->cutValue = mf->cutValue; - // p->son[0] = p->son[1] = 0; // unused: to init skipped record for speculated accesses. -} - - -/* ReleaseStream is required to finish multithreading */ -void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) -{ - // Sleep(1); // for debug - MtSync_StopWriting(&p->btSync); - // Sleep(200); // for debug - /* p->MatchFinder->ReleaseStream(); */ -} - - -Z7_NO_INLINE -static UInt32 MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) -{ - if (p->failure_LZ_BT) - p->btBufPos = p->failureBuf; - else - { - const UInt32 bi = MtSync_GetNextBlock(&p->btSync); - const UInt32 *bt = p->btBuf + GET_BT_BLOCK_OFFSET(bi); - { - const UInt32 numItems = bt[0]; - p->btBufPosLimit = bt + numItems; - p->btNumAvailBytes = bt[1]; - p->btBufPos = bt + 2; - if (numItems < 2 || numItems > kMtBtBlockSize) - { - p->failureBuf[0] = 0; - p->btBufPos = p->failureBuf; - p->btBufPosLimit = p->failureBuf + 1; - p->failure_LZ_BT = True; - // p->btNumAvailBytes = 0; - /* we don't want to decrease AvailBytes, that was load before. - that can be unxepected for the code that have loaded anopther value before */ - } - } - - if (p->lzPos >= (UInt32)kMtMaxValForNormalize - (UInt32)kMtBtBlockSize) - { - /* we don't check (lzPos) over exact avail bytes in (btBuf). - (fixedHashSize) is small, so normalization is fast */ - const UInt32 subValue = (p->lzPos - p->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); - p->lzPos -= subValue; - MatchFinder_Normalize3(subValue, p->hash, p->fixedHashSize); - } - } - return p->btNumAvailBytes; -} - - - -static const Byte * MatchFinderMt_GetPointerToCurrentPos(void *_p) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - return p->pointerToCurPos; -} - - -#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); - - -static UInt32 MatchFinderMt_GetNumAvailableBytes(void *_p) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - if (p->btBufPos != p->btBufPosLimit) - return p->btNumAvailBytes; - return MatchFinderMt_GetNextBlock_Bt(p); -} - - -// #define CHECK_FAILURE_LZ(_match_, _pos_) if (_match_ >= _pos_) { p->failure_LZ_LZ = True; return d; } -#define CHECK_FAILURE_LZ(_match_, _pos_) - -static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) -{ - UInt32 h2, c2; - UInt32 *hash = p->hash; - const Byte *cur = p->pointerToCurPos; - const UInt32 m = p->lzPos; - MT_HASH2_CALC - - c2 = hash[h2]; - hash[h2] = m; - - if (c2 >= matchMinPos) - { - CHECK_FAILURE_LZ(c2, m) - if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) - { - *d++ = 2; - *d++ = m - c2 - 1; - } - } - - return d; -} - -static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) -{ - UInt32 h2, h3, c2, c3; - UInt32 *hash = p->hash; - const Byte *cur = p->pointerToCurPos; - const UInt32 m = p->lzPos; - MT_HASH3_CALC - - c2 = hash[h2]; - c3 = (hash + kFix3HashSize)[h3]; - - hash[h2] = m; - (hash + kFix3HashSize)[h3] = m; - - if (c2 >= matchMinPos) - { - CHECK_FAILURE_LZ(c2, m) - if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) - { - d[1] = m - c2 - 1; - if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) - { - d[0] = 3; - return d + 2; - } - d[0] = 2; - d += 2; - } - } - - if (c3 >= matchMinPos) - { - CHECK_FAILURE_LZ(c3, m) - if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) - { - *d++ = 3; - *d++ = m - c3 - 1; - } - } - - return d; -} - - -#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; - -/* -static -UInt32* MatchFinderMt_GetMatches_Bt4(CMatchFinderMt *p, UInt32 *d) -{ - const UInt32 *bt = p->btBufPos; - const UInt32 len = *bt++; - const UInt32 *btLim = bt + len; - UInt32 matchMinPos; - UInt32 avail = p->btNumAvailBytes - 1; - p->btBufPos = btLim; - - { - p->btNumAvailBytes = avail; - - #define BT_HASH_BYTES_MAX 5 - - matchMinPos = p->lzPos; - - if (len != 0) - matchMinPos -= bt[1]; - else if (avail < (BT_HASH_BYTES_MAX - 1) - 1) - { - INCREASE_LZ_POS - return d; - } - else - { - const UInt32 hs = p->historySize; - if (matchMinPos > hs) - matchMinPos -= hs; - else - matchMinPos = 1; - } - } - - for (;;) - { - - UInt32 h2, h3, c2, c3; - UInt32 *hash = p->hash; - const Byte *cur = p->pointerToCurPos; - UInt32 m = p->lzPos; - MT_HASH3_CALC - - c2 = hash[h2]; - c3 = (hash + kFix3HashSize)[h3]; - - hash[h2] = m; - (hash + kFix3HashSize)[h3] = m; - - if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) - { - d[1] = m - c2 - 1; - if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) - { - d[0] = 3; - d += 2; - break; - } - // else - { - d[0] = 2; - d += 2; - } - } - if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) - { - *d++ = 3; - *d++ = m - c3 - 1; - } - break; - } - - if (len != 0) - { - do - { - const UInt32 v0 = bt[0]; - const UInt32 v1 = bt[1]; - bt += 2; - d[0] = v0; - d[1] = v1; - d += 2; - } - while (bt != btLim); - } - INCREASE_LZ_POS - return d; -} -*/ - - -static UInt32 * MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) -{ - UInt32 h2, h3, /* h4, */ c2, c3 /* , c4 */; - UInt32 *hash = p->hash; - const Byte *cur = p->pointerToCurPos; - const UInt32 m = p->lzPos; - MT_HASH3_CALC - // MT_HASH4_CALC - c2 = hash[h2]; - c3 = (hash + kFix3HashSize)[h3]; - // c4 = (hash + kFix4HashSize)[h4]; - - hash[h2] = m; - (hash + kFix3HashSize)[h3] = m; - // (hash + kFix4HashSize)[h4] = m; - - // #define BT5_USE_H2 - // #ifdef BT5_USE_H2 - if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) - { - d[1] = m - c2 - 1; - if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) - { - // d[0] = (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) ? 4 : 3; - // return d + 2; - - if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) - { - d[0] = 4; - return d + 2; - } - d[0] = 3; - d += 2; - - #ifdef BT5_USE_H4 - if (c4 >= matchMinPos) - if ( - cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && - cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] - ) - { - *d++ = 4; - *d++ = m - c4 - 1; - } - #endif - return d; - } - d[0] = 2; - d += 2; - } - // #endif - - if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) - { - d[1] = m - c3 - 1; - if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m + 3] == cur[3]) - { - d[0] = 4; - return d + 2; - } - d[0] = 3; - d += 2; - } - - #ifdef BT5_USE_H4 - if (c4 >= matchMinPos) - if ( - cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && - cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] - ) - { - *d++ = 4; - *d++ = m - c4 - 1; - } - #endif - - return d; -} - - -static UInt32 * MatchFinderMt2_GetMatches(void *_p, UInt32 *d) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - const UInt32 *bt = p->btBufPos; - const UInt32 len = *bt++; - const UInt32 *btLim = bt + len; - p->btBufPos = btLim; - p->btNumAvailBytes--; - INCREASE_LZ_POS - { - while (bt != btLim) - { - const UInt32 v0 = bt[0]; - const UInt32 v1 = bt[1]; - bt += 2; - d[0] = v0; - d[1] = v1; - d += 2; - } - } - return d; -} - - - -static UInt32 * MatchFinderMt_GetMatches(void *_p, UInt32 *d) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - const UInt32 *bt = p->btBufPos; - UInt32 len = *bt++; - const UInt32 avail = p->btNumAvailBytes - 1; - p->btNumAvailBytes = avail; - p->btBufPos = bt + len; - if (len == 0) - { - #define BT_HASH_BYTES_MAX 5 - if (avail >= (BT_HASH_BYTES_MAX - 1) - 1) - { - UInt32 m = p->lzPos; - if (m > p->historySize) - m -= p->historySize; - else - m = 1; - d = p->MixMatchesFunc(p, m, d); - } - } - else - { - /* - first match pair from BinTree: (match_len, match_dist), - (match_len >= numHashBytes). - MixMatchesFunc() inserts only hash matches that are nearer than (match_dist) - */ - d = p->MixMatchesFunc(p, p->lzPos - bt[1], d); - // if (d) // check for failure - do - { - const UInt32 v0 = bt[0]; - const UInt32 v1 = bt[1]; - bt += 2; - d[0] = v0; - d[1] = v1; - d += 2; - } - while (len -= 2); - } - INCREASE_LZ_POS - return d; -} - -#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED -#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; -#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += (size_t)*p->btBufPos + 1; } while (--num != 0); - -static void MatchFinderMt0_Skip(void *_p, UInt32 num) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - SKIP_HEADER2_MT { p->btNumAvailBytes--; - SKIP_FOOTER_MT -} - -static void MatchFinderMt2_Skip(void *_p, UInt32 num) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - SKIP_HEADER_MT(2) - UInt32 h2; - MT_HASH2_CALC - hash[h2] = p->lzPos; - SKIP_FOOTER_MT -} - -static void MatchFinderMt3_Skip(void *_p, UInt32 num) -{ - CMatchFinderMt *p = (CMatchFinderMt *)_p; - SKIP_HEADER_MT(3) - UInt32 h2, h3; - MT_HASH3_CALC - (hash + kFix3HashSize)[h3] = - hash[ h2] = - p->lzPos; - SKIP_FOOTER_MT -} - -/* -// MatchFinderMt4_Skip() is similar to MatchFinderMt3_Skip(). -// The difference is that MatchFinderMt3_Skip() updates hash for last 3 bytes of stream. - -static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) -{ - SKIP_HEADER_MT(4) - UInt32 h2, h3; // h4 - MT_HASH3_CALC - // MT_HASH4_CALC - // (hash + kFix4HashSize)[h4] = - (hash + kFix3HashSize)[h3] = - hash[ h2] = - p->lzPos; - SKIP_FOOTER_MT -} -*/ - -void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable) -{ - vTable->Init = MatchFinderMt_Init; - vTable->GetNumAvailableBytes = MatchFinderMt_GetNumAvailableBytes; - vTable->GetPointerToCurrentPos = MatchFinderMt_GetPointerToCurrentPos; - vTable->GetMatches = MatchFinderMt_GetMatches; - - switch (MF(p)->numHashBytes) - { - case 2: - p->GetHeadsFunc = GetHeads2; - p->MixMatchesFunc = NULL; - vTable->Skip = MatchFinderMt0_Skip; - vTable->GetMatches = MatchFinderMt2_GetMatches; - break; - case 3: - p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3; - p->MixMatchesFunc = MixMatches2; - vTable->Skip = MatchFinderMt2_Skip; - break; - case 4: - p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4; - - // it's fast inline version of GetMatches() - // vTable->GetMatches = MatchFinderMt_GetMatches_Bt4; - - p->MixMatchesFunc = MixMatches3; - vTable->Skip = MatchFinderMt3_Skip; - break; - default: - p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5; - p->MixMatchesFunc = MixMatches4; - vTable->Skip = - MatchFinderMt3_Skip; - // MatchFinderMt4_Skip; - break; - } -} - -#undef RINOK_THREAD -#undef PRF -#undef MF -#undef GetUi24hi_from32 -#undef LOCK_BUFFER -#undef UNLOCK_BUFFER +/* LzFindMt.c -- multithreaded Match finder for LZ algorithms +2024-01-22 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +#include "CpuArch.h" + +#include "LzHash.h" +#include "LzFindMt.h" + +// #define LOG_ITERS + +// #define LOG_THREAD + +#ifdef LOG_THREAD +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#ifdef LOG_ITERS +#include +extern UInt64 g_NumIters_Tree; +extern UInt64 g_NumIters_Loop; +extern UInt64 g_NumIters_Bytes; +#define LOG_ITER(x) x +#else +#define LOG_ITER(x) +#endif + +#define kMtHashBlockSize ((UInt32)1 << 17) +#define kMtHashNumBlocks (1 << 1) + +#define GET_HASH_BLOCK_OFFSET(i) (((i) & (kMtHashNumBlocks - 1)) * kMtHashBlockSize) + +#define kMtBtBlockSize ((UInt32)1 << 16) +#define kMtBtNumBlocks (1 << 4) + +#define GET_BT_BLOCK_OFFSET(i) (((i) & (kMtBtNumBlocks - 1)) * (size_t)kMtBtBlockSize) + +/* + HASH functions: + We use raw 8/16 bits from a[1] and a[2], + xored with crc(a[0]) and crc(a[3]). + We check a[0], a[3] only. We don't need to compare a[1] and a[2] in matches. + our crc() function provides one-to-one correspondence for low 8-bit values: + (crc[0...0xFF] & 0xFF) <-> [0...0xFF] +*/ + +#define MF(mt) ((mt)->MatchFinder) +#define MF_CRC (p->crc) + +// #define MF(mt) (&(mt)->MatchFinder) +// #define MF_CRC (p->MatchFinder.crc) + +#define MT_HASH2_CALC \ + h2 = (MF_CRC[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = MF_CRC[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +/* +#define MT_HASH3_CALC__NO_2 { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hash4Mask; } + // (kHash4Size - 1); +*/ + + +Z7_NO_INLINE +static void MtSync_Construct(CMtSync *p) +{ + p->affinity = 0; + p->wasCreated = False; + p->csWasInitialized = False; + p->csWasEntered = False; + Thread_CONSTRUCT(&p->thread) + Event_Construct(&p->canStart); + Event_Construct(&p->wasStopped); + Semaphore_Construct(&p->freeSemaphore); + Semaphore_Construct(&p->filledSemaphore); +} + + +// #define DEBUG_BUFFER_LOCK // define it to debug lock state + +#ifdef DEBUG_BUFFER_LOCK +#include +#define BUFFER_MUST_BE_LOCKED(p) if (!(p)->csWasEntered) exit(1); +#define BUFFER_MUST_BE_UNLOCKED(p) if ( (p)->csWasEntered) exit(1); +#else +#define BUFFER_MUST_BE_LOCKED(p) +#define BUFFER_MUST_BE_UNLOCKED(p) +#endif + +#define LOCK_BUFFER(p) { \ + BUFFER_MUST_BE_UNLOCKED(p); \ + CriticalSection_Enter(&(p)->cs); \ + (p)->csWasEntered = True; } + +#define UNLOCK_BUFFER(p) { \ + BUFFER_MUST_BE_LOCKED(p); \ + CriticalSection_Leave(&(p)->cs); \ + (p)->csWasEntered = False; } + + +Z7_NO_INLINE +static UInt32 MtSync_GetNextBlock(CMtSync *p) +{ + UInt32 numBlocks = 0; + if (p->needStart) + { + BUFFER_MUST_BE_UNLOCKED(p) + p->numProcessedBlocks = 1; + p->needStart = False; + p->stopWriting = False; + p->exit = False; + Event_Reset(&p->wasStopped); + Event_Set(&p->canStart); + } + else + { + UNLOCK_BUFFER(p) + // we free current block + numBlocks = p->numProcessedBlocks++; + Semaphore_Release1(&p->freeSemaphore); + } + + // buffer is UNLOCKED here + Semaphore_Wait(&p->filledSemaphore); + LOCK_BUFFER(p) + return numBlocks; +} + + +/* if Writing (Processing) thread was started, we must call MtSync_StopWriting() */ + +Z7_NO_INLINE +static void MtSync_StopWriting(CMtSync *p) +{ + if (!Thread_WasCreated(&p->thread) || p->needStart) + return; + + PRF(printf("\nMtSync_StopWriting %p\n", p)); + + if (p->csWasEntered) + { + /* we don't use buffer in this thread after StopWriting(). + So we UNLOCK buffer. + And we restore default UNLOCKED state for stopped thread */ + UNLOCK_BUFFER(p) + } + + /* We send (p->stopWriting) message and release freeSemaphore + to free current block. + So the thread will see (p->stopWriting) at some + iteration after Wait(freeSemaphore). + The thread doesn't need to fill all avail free blocks, + so we can get fast thread stop. + */ + + p->stopWriting = True; + Semaphore_Release1(&p->freeSemaphore); // check semaphore count !!! + + PRF(printf("\nMtSync_StopWriting %p : Event_Wait(&p->wasStopped)\n", p)); + Event_Wait(&p->wasStopped); + PRF(printf("\nMtSync_StopWriting %p : Event_Wait() finsihed\n", p)); + + /* 21.03 : we don't restore samaphore counters here. + We will recreate and reinit samaphores in next start */ + + p->needStart = True; +} + + +Z7_NO_INLINE +static void MtSync_Destruct(CMtSync *p) +{ + PRF(printf("\nMtSync_Destruct %p\n", p)); + + if (Thread_WasCreated(&p->thread)) + { + /* we want thread to be in Stopped state before sending EXIT command. + note: stop(btSync) will stop (htSync) also */ + MtSync_StopWriting(p); + /* thread in Stopped state here : (p->needStart == true) */ + p->exit = True; + // if (p->needStart) // it's (true) + Event_Set(&p->canStart); // we send EXIT command to thread + Thread_Wait_Close(&p->thread); // we wait thread finishing + } + + if (p->csWasInitialized) + { + CriticalSection_Delete(&p->cs); + p->csWasInitialized = False; + } + p->csWasEntered = False; + + Event_Close(&p->canStart); + Event_Close(&p->wasStopped); + Semaphore_Close(&p->freeSemaphore); + Semaphore_Close(&p->filledSemaphore); + + p->wasCreated = False; +} + + +// #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } +// we want to get real system error codes here instead of SZ_ERROR_THREAD +#define RINOK_THREAD(x) RINOK_WRes(x) + + +// call it before each new file (when new starting is required): +Z7_NO_INLINE +static SRes MtSync_Init(CMtSync *p, UInt32 numBlocks) +{ + WRes wres; + // BUFFER_MUST_BE_UNLOCKED(p) + if (!p->needStart || p->csWasEntered) + return SZ_ERROR_FAIL; + wres = Semaphore_OptCreateInit(&p->freeSemaphore, numBlocks, numBlocks); + if (wres == 0) + wres = Semaphore_OptCreateInit(&p->filledSemaphore, 0, numBlocks); + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) +{ + WRes wres; + + if (p->wasCreated) + return SZ_OK; + + RINOK_THREAD(CriticalSection_Init(&p->cs)) + p->csWasInitialized = True; + p->csWasEntered = False; + + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)) + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)) + + p->needStart = True; + p->exit = True; /* p->exit is unused before (canStart) Event. + But in case of some unexpected code failure we will get fast exit from thread */ + + // return ERROR_TOO_MANY_POSTS; // for debug + // return EINVAL; // for debug + + if (p->affinity != 0) + wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity); + else + wres = Thread_Create(&p->thread, startAddress, obj); + + RINOK_THREAD(wres) + p->wasCreated = True; + return SZ_OK; +} + + +Z7_NO_INLINE +static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj) +{ + const WRes wres = MtSync_Create_WRes(p, startAddress, obj); + if (wres == 0) + return 0; + MtSync_Destruct(p); + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +// ---------- HASH THREAD ---------- + +#define kMtMaxValForNormalize 0xFFFFFFFF +// #define kMtMaxValForNormalize ((1 << 21)) // for debug +// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses + +#ifdef MY_CPU_LE_UNALIGN + #define GetUi24hi_from32(p) ((UInt32)GetUi32(p) >> 8) +#else + #define GetUi24hi_from32(p) ((p)[1] ^ ((UInt32)(p)[2] << 8) ^ ((UInt32)(p)[3] << 16)) +#endif + +#define GetHeads_DECL(name) \ + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) + +#define GetHeads_LOOP(v) \ + for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); \ + p++; \ + *heads++ = pos - hash[value]; \ + hash[value] = pos++; } + +#define DEF_GetHeads2(name, v, action) \ + GetHeads_DECL(name) { action \ + GetHeads_LOOP(v) } + +#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) + +DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) +DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask) +DEF_GetHeads2(3b, GetUi16(p) ^ ((UInt32)(p)[2] << 16), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) +// BT3 is not good for crc collisions for big hashMask values. + +/* +GetHeads_DECL(3b) +{ + UNUSED_VAR(hashMask); + UNUSED_VAR(crc); + { + const Byte *pLim = p + numHeads; + if (numHeads == 0) + return; + pLim--; + while (p < pLim) + { + UInt32 v1 = GetUi32(p); + UInt32 v0 = v1 & 0xFFFFFF; + UInt32 h0, h1; + p += 2; + v1 >>= 8; + h0 = hash[v0]; hash[v0] = pos; heads[0] = pos - h0; pos++; + h1 = hash[v1]; hash[v1] = pos; heads[1] = pos - h1; pos++; + heads += 2; + } + if (p == pLim) + { + UInt32 v0 = GetUi16(p) ^ ((UInt32)(p)[2] << 16); + *heads = pos - hash[v0]; + hash[v0] = pos; + } + } +} +*/ + +/* +GetHeads_DECL(4) +{ + unsigned sh = 0; + UNUSED_VAR(crc) + while ((hashMask & 0x80000000) == 0) + { + hashMask <<= 1; + sh++; + } + GetHeads_LOOP((GetUi32(p) * 0xa54a1) >> sh) +} +#define GetHeads4b GetHeads4 +*/ + +#define USE_GetHeads_LOCAL_CRC + +#ifdef USE_GetHeads_LOCAL_CRC + +GetHeads_DECL(4) +{ + UInt32 crc0[256]; + UInt32 crc1[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + { + UInt32 v = crc[i]; + crc0[i] = v & hashMask; + crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; + // crc1[i] = rotlFixed(v, 8) & hashMask; + } + } + GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ (UInt32)GetUi16(p+1)) +} + +GetHeads_DECL(4b) +{ + UInt32 crc0[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + crc0[i] = crc[i] & hashMask; + } + GetHeads_LOOP(crc0[p[0]] ^ GetUi24hi_from32(p)) +} + +GetHeads_DECL(5) +{ + UInt32 crc0[256]; + UInt32 crc1[256]; + UInt32 crc2[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + { + UInt32 v = crc[i]; + crc0[i] = v & hashMask; + crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; + crc2[i] = (v << kLzHash_CrcShift_2) & hashMask; + } + } + GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ crc2[p[4]] ^ (UInt32)GetUi16(p+1)) +} + +GetHeads_DECL(5b) +{ + UInt32 crc0[256]; + UInt32 crc1[256]; + { + unsigned i; + for (i = 0; i < 256; i++) + { + UInt32 v = crc[i]; + crc0[i] = v & hashMask; + crc1[i] = (v << kLzHash_CrcShift_1) & hashMask; + } + } + GetHeads_LOOP(crc0[p[0]] ^ crc1[p[4]] ^ GetUi24hi_from32(p)) +} + +#else + +DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask) +DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask) +DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask) +DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask) + +#endif + + +static void HashThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->hashSync; + PRF(printf("\nHashThreadFunc\n")); + + for (;;) + { + UInt32 blockIndex = 0; + PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart)\n")); + Event_Wait(&p->canStart); + PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart) : after \n")); + if (p->exit) + { + PRF(printf("\nHashThreadFunc : exit \n")); + return; + } + + MatchFinder_Init_HighHash(MF(mt)); + + for (;;) + { + PRF(printf("Hash thread block = %d pos = %d\n", (unsigned)blockIndex, mt->MatchFinder->pos)); + + { + CMatchFinder *mf = MF(mt); + if (MatchFinder_NeedMove(mf)) + { + CriticalSection_Enter(&mt->btSync.cs); + CriticalSection_Enter(&mt->hashSync.cs); + { + const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); + ptrdiff_t offset; + MatchFinder_MoveBlock(mf); + offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= offset; + mt->buffer -= offset; + } + CriticalSection_Leave(&mt->hashSync.cs); + CriticalSection_Leave(&mt->btSync.cs); + continue; + } + + Semaphore_Wait(&p->freeSemaphore); + + if (p->exit) // exit is unexpected here. But we check it here for some failure case + return; + + // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) + if (p->stopWriting) + break; + + MatchFinder_ReadIfRequired(mf); + { + UInt32 *heads = mt->hashBuf + GET_HASH_BLOCK_OFFSET(blockIndex++); + UInt32 num = Inline_MatchFinder_GetNumAvailableBytes(mf); + heads[0] = 2; + heads[1] = num; + + /* heads[1] contains the number of avail bytes: + if (avail < mf->numHashBytes) : + { + it means that stream was finished + HASH_THREAD and BT_TREAD must move position for heads[1] (avail) bytes. + HASH_THREAD doesn't stop, + HASH_THREAD fills only the header (2 numbers) for all next blocks: + {2, NumHashBytes - 1}, {2,0}, {2,0}, ... , {2,0} + } + else + { + HASH_THREAD and BT_TREAD must move position for (heads[0] - 2) bytes; + } + */ + + if (num >= mf->numHashBytes) + { + num = num - mf->numHashBytes + 1; + if (num > kMtHashBlockSize - 2) + num = kMtHashBlockSize - 2; + + if (mf->pos > (UInt32)kMtMaxValForNormalize - num) + { + const UInt32 subValue = (mf->pos - mf->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); + MatchFinder_REDUCE_OFFSETS(mf, subValue) + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); + } + + heads[0] = 2 + num; + mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); + } + + mf->pos += num; // wrap over zero is allowed at the end of stream + mf->buffer += num; + } + } + + Semaphore_Release1(&p->filledSemaphore); + } // for() processing end + + // p->numBlocks_Sent = blockIndex; + Event_Set(&p->wasStopped); + } // for() thread end +} + + + + +// ---------- BT THREAD ---------- + +/* we use one variable instead of two (cyclicBufferPos == pos) before CyclicBuf wrap. + here we define fixed offset of (p->pos) from (p->cyclicBufferPos) */ +#define CYC_TO_POS_OFFSET 0 +// #define CYC_TO_POS_OFFSET 1 // for debug + +#define MFMT_GM_INLINE + +#ifdef MFMT_GM_INLINE + +/* + we use size_t for (pos) instead of UInt32 + to eliminate "movsx" BUG in old MSVC x64 compiler. +*/ + + +UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes); + +#endif + + +static void BtGetMatches(CMatchFinderMt *p, UInt32 *d) +{ + UInt32 numProcessed = 0; + UInt32 curPos = 2; + + /* GetMatchesSpec() functions don't create (len = 1) + in [len, dist] match pairs, if (p->numHashBytes >= 2) + Also we suppose here that (matchMaxLen >= 2). + So the following code for (reserve) is not required + UInt32 reserve = (p->matchMaxLen * 2); + const UInt32 kNumHashBytes_Max = 5; // BT_HASH_BYTES_MAX + if (reserve < kNumHashBytes_Max - 1) + reserve = kNumHashBytes_Max - 1; + const UInt32 limit = kMtBtBlockSize - (reserve); + */ + + const UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + + d[1] = p->hashNumAvail; + + if (p->failure_BT) + { + // printf("\n == 1 BtGetMatches() p->failure_BT\n"); + d[0] = 0; + // d[1] = 0; + return; + } + + while (curPos < limit) + { + if (p->hashBufPos == p->hashBufPosLimit) + { + // MatchFinderMt_GetNextBlock_Hash(p); + UInt32 avail; + { + const UInt32 bi = MtSync_GetNextBlock(&p->hashSync); + const UInt32 k = GET_HASH_BLOCK_OFFSET(bi); + const UInt32 *h = p->hashBuf + k; + avail = h[1]; + p->hashBufPosLimit = k + h[0]; + p->hashNumAvail = avail; + p->hashBufPos = k + 2; + } + + { + /* we must prevent UInt32 overflow for avail total value, + if avail was increased with new hash block */ + UInt32 availSum = numProcessed + avail; + if (availSum < numProcessed) + availSum = (UInt32)(Int32)-1; + d[1] = availSum; + } + + if (avail >= p->numHashBytes) + continue; + + // if (p->hashBufPos != p->hashBufPosLimit) exit(1); + + /* (avail < p->numHashBytes) + It means that stream was finished. + And (avail) - is a number of remaining bytes, + we fill (d) for (avail) bytes for LZ_THREAD (receiver). + but we don't update (p->pos) and (p->cyclicBufferPos) here in BT_THREAD */ + + /* here we suppose that we have space enough: + (kMtBtBlockSize - curPos >= p->hashNumAvail) */ + p->hashNumAvail = 0; + d[0] = curPos + avail; + d += curPos; + for (; avail != 0; avail--) + *d++ = 0; + return; + } + { + UInt32 size = p->hashBufPosLimit - p->hashBufPos; + UInt32 pos = p->pos; + UInt32 cyclicBufferPos = p->cyclicBufferPos; + UInt32 lenLimit = p->matchMaxLen; + if (lenLimit >= p->hashNumAvail) + lenLimit = p->hashNumAvail; + { + UInt32 size2 = p->hashNumAvail - lenLimit + 1; + if (size2 < size) + size = size2; + size2 = p->cyclicBufferSize - cyclicBufferPos; + if (size2 < size) + size = size2; + } + + if (pos > (UInt32)kMtMaxValForNormalize - size) + { + const UInt32 subValue = (pos - p->cyclicBufferSize); // & ~(UInt32)(kNormalizeAlign - 1); + pos -= subValue; + p->pos = pos; + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); + } + + #ifndef MFMT_GM_INLINE + while (curPos < limit && size-- != 0) + { + UInt32 *startDistances = d + curPos; + UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); + *startDistances = num - 1; + curPos += num; + cyclicBufferPos++; + pos++; + p->buffer++; + } + #else + { + UInt32 posRes = pos; + const UInt32 *d_end; + { + d_end = GetMatchesSpecN_2( + p->buffer + lenLimit - 1, + pos, p->buffer, p->son, p->cutValue, d + curPos, + p->numHashBytes - 1, p->hashBuf + p->hashBufPos, + d + limit, p->hashBuf + p->hashBufPos + size, + cyclicBufferPos, p->cyclicBufferSize, + &posRes); + } + { + if (!d_end) + { + // printf("\n == 2 BtGetMatches() p->failure_BT\n"); + // internal data failure + p->failure_BT = True; + d[0] = 0; + // d[1] = 0; + return; + } + } + curPos = (UInt32)(d_end - d); + { + const UInt32 processed = posRes - pos; + pos = posRes; + p->hashBufPos += processed; + cyclicBufferPos += processed; + p->buffer += processed; + } + } + #endif + + { + const UInt32 processed = pos - p->pos; + numProcessed += processed; + p->hashNumAvail -= processed; + p->pos = pos; + } + if (cyclicBufferPos == p->cyclicBufferSize) + cyclicBufferPos = 0; + p->cyclicBufferPos = cyclicBufferPos; + } + } + + d[0] = curPos; +} + + +static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +{ + CMtSync *sync = &p->hashSync; + + BUFFER_MUST_BE_UNLOCKED(sync) + + if (!sync->needStart) + { + LOCK_BUFFER(sync) + } + + BtGetMatches(p, p->btBuf + GET_BT_BLOCK_OFFSET(globalBlockIndex)); + + /* We suppose that we have called GetNextBlock() from start. + So buffer is LOCKED */ + + UNLOCK_BUFFER(sync) +} + + +Z7_NO_INLINE +static void BtThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->btSync; + for (;;) + { + UInt32 blockIndex = 0; + Event_Wait(&p->canStart); + + for (;;) + { + PRF(printf(" BT thread block = %d pos = %d\n", (unsigned)blockIndex, mt->pos)); + /* (p->exit == true) is possible after (p->canStart) at first loop iteration + and is unexpected after more Wait(freeSemaphore) iterations */ + if (p->exit) + return; + + Semaphore_Wait(&p->freeSemaphore); + + // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore) + if (p->stopWriting) + break; + + BtFillBlock(mt, blockIndex++); + + Semaphore_Release1(&p->filledSemaphore); + } + + // we stop HASH_THREAD here + MtSync_StopWriting(&mt->hashSync); + + // p->numBlocks_Sent = blockIndex; + Event_Set(&p->wasStopped); + } +} + + +void MatchFinderMt_Construct(CMatchFinderMt *p) +{ + p->hashBuf = NULL; + MtSync_Construct(&p->hashSync); + MtSync_Construct(&p->btSync); +} + +static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->hashBuf); + p->hashBuf = NULL; +} + +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc) +{ + /* + HASH_THREAD can use CriticalSection(s) btSync.cs and hashSync.cs. + So we must be sure that HASH_THREAD will not use CriticalSection(s) + after deleting CriticalSection here. + + we call ReleaseStream(p) + that calls StopWriting(btSync) + that calls StopWriting(hashSync), if it's required to stop HASH_THREAD. + after StopWriting() it's safe to destruct MtSync(s) in any order */ + + MatchFinderMt_ReleaseStream(p); + + MtSync_Destruct(&p->btSync); + MtSync_Destruct(&p->hashSync); + + LOG_ITER( + printf("\nTree %9d * %7d iter = %9d = sum : bytes = %9d\n", + (UInt32)(g_NumIters_Tree / 1000), + (UInt32)(((UInt64)g_NumIters_Loop * 1000) / (g_NumIters_Tree + 1)), + (UInt32)(g_NumIters_Loop / 1000), + (UInt32)(g_NumIters_Bytes / 1000) + )); + + MatchFinderMt_FreeMem(p, alloc); +} + + +#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) +#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) + + +static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static THREAD_FUNC_DECL BtThreadFunc2(void *p) +{ + Byte allocaDummy[0x180]; + unsigned i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)0; + if (allocaDummy[0] == 0) + BtThreadFunc((CMatchFinderMt *)p); + return 0; +} + + +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc) +{ + CMatchFinder *mf = MF(p); + p->historySize = historySize; + if (kMtBtBlockSize <= matchMaxLen * 4) + return SZ_ERROR_PARAM; + if (!p->hashBuf) + { + p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, ((size_t)kHashBufferSize + (size_t)kBtBufferSize) * sizeof(UInt32)); + if (!p->hashBuf) + return SZ_ERROR_MEM; + p->btBuf = p->hashBuf + kHashBufferSize; + } + keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); + keepAddBufferAfter += kMtHashBlockSize; + if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) + return SZ_ERROR_MEM; + + RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p)) + RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p)) + return SZ_OK; +} + + +SRes MatchFinderMt_InitMt(CMatchFinderMt *p) +{ + RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks)) + return MtSync_Init(&p->btSync, kMtBtNumBlocks); +} + + +static void MatchFinderMt_Init(void *_p) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + CMatchFinder *mf = MF(p); + + p->btBufPos = + p->btBufPosLimit = NULL; + p->hashBufPos = + p->hashBufPosLimit = 0; + p->hashNumAvail = 0; // 21.03 + + p->failure_BT = False; + + /* Init without data reading. We don't want to read data in this thread */ + MatchFinder_Init_4(mf); + + MatchFinder_Init_LowHash(mf); + + p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); + p->btNumAvailBytes = 0; + p->failure_LZ_BT = False; + // p->failure_LZ_LZ = False; + + p->lzPos = + 1; // optimal smallest value + // 0; // for debug: ignores match to start + // kNormalizeAlign; // for debug + + p->hash = mf->hash; + p->fixedHashSize = mf->fixedHashSize; + // p->hash4Mask = mf->hash4Mask; + p->crc = mf->crc; + // memcpy(p->crc, mf->crc, sizeof(mf->crc)); + + p->son = mf->son; + p->matchMaxLen = mf->matchMaxLen; + p->numHashBytes = mf->numHashBytes; + + /* (mf->pos) and (mf->streamPos) were already initialized to 1 in MatchFinder_Init_4() */ + // mf->streamPos = mf->pos = 1; // optimal smallest value + // 0; // for debug: ignores match to start + // kNormalizeAlign; // for debug + + /* we must init (p->pos = mf->pos) for BT, because + BT code needs (p->pos == delta_value_for_empty_hash_record == mf->pos) */ + p->pos = mf->pos; // do not change it + + p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); + p->cyclicBufferSize = mf->cyclicBufferSize; + p->buffer = mf->buffer; + p->cutValue = mf->cutValue; + // p->son[0] = p->son[1] = 0; // unused: to init skipped record for speculated accesses. +} + + +/* ReleaseStream is required to finish multithreading */ +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) +{ + // Sleep(1); // for debug + MtSync_StopWriting(&p->btSync); + // Sleep(200); // for debug + /* p->MatchFinder->ReleaseStream(); */ +} + + +Z7_NO_INLINE +static UInt32 MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +{ + if (p->failure_LZ_BT) + p->btBufPos = p->failureBuf; + else + { + const UInt32 bi = MtSync_GetNextBlock(&p->btSync); + const UInt32 *bt = p->btBuf + GET_BT_BLOCK_OFFSET(bi); + { + const UInt32 numItems = bt[0]; + p->btBufPosLimit = bt + numItems; + p->btNumAvailBytes = bt[1]; + p->btBufPos = bt + 2; + if (numItems < 2 || numItems > kMtBtBlockSize) + { + p->failureBuf[0] = 0; + p->btBufPos = p->failureBuf; + p->btBufPosLimit = p->failureBuf + 1; + p->failure_LZ_BT = True; + // p->btNumAvailBytes = 0; + /* we don't want to decrease AvailBytes, that was load before. + that can be unxepected for the code that have loaded anopther value before */ + } + } + + if (p->lzPos >= (UInt32)kMtMaxValForNormalize - (UInt32)kMtBtBlockSize) + { + /* we don't check (lzPos) over exact avail bytes in (btBuf). + (fixedHashSize) is small, so normalization is fast */ + const UInt32 subValue = (p->lzPos - p->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1); + p->lzPos -= subValue; + MatchFinder_Normalize3(subValue, p->hash, p->fixedHashSize); + } + } + return p->btNumAvailBytes; +} + + + +static const Byte * MatchFinderMt_GetPointerToCurrentPos(void *_p) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + return p->pointerToCurPos; +} + + +#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); + + +static UInt32 MatchFinderMt_GetNumAvailableBytes(void *_p) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + if (p->btBufPos != p->btBufPosLimit) + return p->btNumAvailBytes; + return MatchFinderMt_GetNextBlock_Bt(p); +} + + +// #define CHECK_FAILURE_LZ(_match_, _pos_) if (_match_ >= _pos_) { p->failure_LZ_LZ = True; return d; } +#define CHECK_FAILURE_LZ(_match_, _pos_) + +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) +{ + UInt32 h2, c2; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + const UInt32 m = p->lzPos; + MT_HASH2_CALC + + c2 = hash[h2]; + hash[h2] = m; + + if (c2 >= matchMinPos) + { + CHECK_FAILURE_LZ(c2, m) + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) + { + *d++ = 2; + *d++ = m - c2 - 1; + } + } + + return d; +} + +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) +{ + UInt32 h2, h3, c2, c3; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + const UInt32 m = p->lzPos; + MT_HASH3_CALC + + c2 = hash[h2]; + c3 = (hash + kFix3HashSize)[h3]; + + hash[h2] = m; + (hash + kFix3HashSize)[h3] = m; + + if (c2 >= matchMinPos) + { + CHECK_FAILURE_LZ(c2, m) + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) + { + d[1] = m - c2 - 1; + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) + { + d[0] = 3; + return d + 2; + } + d[0] = 2; + d += 2; + } + } + + if (c3 >= matchMinPos) + { + CHECK_FAILURE_LZ(c3, m) + if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) + { + *d++ = 3; + *d++ = m - c3 - 1; + } + } + + return d; +} + + +#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; + +/* +static +UInt32* MatchFinderMt_GetMatches_Bt4(CMatchFinderMt *p, UInt32 *d) +{ + const UInt32 *bt = p->btBufPos; + const UInt32 len = *bt++; + const UInt32 *btLim = bt + len; + UInt32 matchMinPos; + UInt32 avail = p->btNumAvailBytes - 1; + p->btBufPos = btLim; + + { + p->btNumAvailBytes = avail; + + #define BT_HASH_BYTES_MAX 5 + + matchMinPos = p->lzPos; + + if (len != 0) + matchMinPos -= bt[1]; + else if (avail < (BT_HASH_BYTES_MAX - 1) - 1) + { + INCREASE_LZ_POS + return d; + } + else + { + const UInt32 hs = p->historySize; + if (matchMinPos > hs) + matchMinPos -= hs; + else + matchMinPos = 1; + } + } + + for (;;) + { + + UInt32 h2, h3, c2, c3; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 m = p->lzPos; + MT_HASH3_CALC + + c2 = hash[h2]; + c3 = (hash + kFix3HashSize)[h3]; + + hash[h2] = m; + (hash + kFix3HashSize)[h3] = m; + + if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) + { + d[1] = m - c2 - 1; + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) + { + d[0] = 3; + d += 2; + break; + } + // else + { + d[0] = 2; + d += 2; + } + } + if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) + { + *d++ = 3; + *d++ = m - c3 - 1; + } + break; + } + + if (len != 0) + { + do + { + const UInt32 v0 = bt[0]; + const UInt32 v1 = bt[1]; + bt += 2; + d[0] = v0; + d[1] = v1; + d += 2; + } + while (bt != btLim); + } + INCREASE_LZ_POS + return d; +} +*/ + + +static UInt32 * MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d) +{ + UInt32 h2, h3, /* h4, */ c2, c3 /* , c4 */; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + const UInt32 m = p->lzPos; + MT_HASH3_CALC + // MT_HASH4_CALC + c2 = hash[h2]; + c3 = (hash + kFix3HashSize)[h3]; + // c4 = (hash + kFix4HashSize)[h4]; + + hash[h2] = m; + (hash + kFix3HashSize)[h3] = m; + // (hash + kFix4HashSize)[h4] = m; + + // #define BT5_USE_H2 + // #ifdef BT5_USE_H2 + if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0]) + { + d[1] = m - c2 - 1; + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2]) + { + // d[0] = (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) ? 4 : 3; + // return d + 2; + + if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) + { + d[0] = 4; + return d + 2; + } + d[0] = 3; + d += 2; + + #ifdef BT5_USE_H4 + if (c4 >= matchMinPos) + if ( + cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && + cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] + ) + { + *d++ = 4; + *d++ = m - c4 - 1; + } + #endif + return d; + } + d[0] = 2; + d += 2; + } + // #endif + + if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0]) + { + d[1] = m - c3 - 1; + if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m + 3] == cur[3]) + { + d[0] = 4; + return d + 2; + } + d[0] = 3; + d += 2; + } + + #ifdef BT5_USE_H4 + if (c4 >= matchMinPos) + if ( + cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] && + cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3] + ) + { + *d++ = 4; + *d++ = m - c4 - 1; + } + #endif + + return d; +} + + +static UInt32 * MatchFinderMt2_GetMatches(void *_p, UInt32 *d) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + const UInt32 *bt = p->btBufPos; + const UInt32 len = *bt++; + const UInt32 *btLim = bt + len; + p->btBufPos = btLim; + p->btNumAvailBytes--; + INCREASE_LZ_POS + { + while (bt != btLim) + { + const UInt32 v0 = bt[0]; + const UInt32 v1 = bt[1]; + bt += 2; + d[0] = v0; + d[1] = v1; + d += 2; + } + } + return d; +} + + + +static UInt32 * MatchFinderMt_GetMatches(void *_p, UInt32 *d) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + const UInt32 *bt = p->btBufPos; + UInt32 len = *bt++; + const UInt32 avail = p->btNumAvailBytes - 1; + p->btNumAvailBytes = avail; + p->btBufPos = bt + len; + if (len == 0) + { + #define BT_HASH_BYTES_MAX 5 + if (avail >= (BT_HASH_BYTES_MAX - 1) - 1) + { + UInt32 m = p->lzPos; + if (m > p->historySize) + m -= p->historySize; + else + m = 1; + d = p->MixMatchesFunc(p, m, d); + } + } + else + { + /* + first match pair from BinTree: (match_len, match_dist), + (match_len >= numHashBytes). + MixMatchesFunc() inserts only hash matches that are nearer than (match_dist) + */ + d = p->MixMatchesFunc(p, p->lzPos - bt[1], d); + // if (d) // check for failure + do + { + const UInt32 v0 = bt[0]; + const UInt32 v1 = bt[1]; + bt += 2; + d[0] = v0; + d[1] = v1; + d += 2; + } + while (len -= 2); + } + INCREASE_LZ_POS + return d; +} + +#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED +#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; +#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += (size_t)*p->btBufPos + 1; } while (--num != 0); + +static void MatchFinderMt0_Skip(void *_p, UInt32 num) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + SKIP_HEADER2_MT { p->btNumAvailBytes--; + SKIP_FOOTER_MT +} + +static void MatchFinderMt2_Skip(void *_p, UInt32 num) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + SKIP_HEADER_MT(2) + UInt32 h2; + MT_HASH2_CALC + hash[h2] = p->lzPos; + SKIP_FOOTER_MT +} + +static void MatchFinderMt3_Skip(void *_p, UInt32 num) +{ + CMatchFinderMt *p = (CMatchFinderMt *)_p; + SKIP_HEADER_MT(3) + UInt32 h2, h3; + MT_HASH3_CALC + (hash + kFix3HashSize)[h3] = + hash[ h2] = + p->lzPos; + SKIP_FOOTER_MT +} + +/* +// MatchFinderMt4_Skip() is similar to MatchFinderMt3_Skip(). +// The difference is that MatchFinderMt3_Skip() updates hash for last 3 bytes of stream. + +static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(4) + UInt32 h2, h3; // h4 + MT_HASH3_CALC + // MT_HASH4_CALC + // (hash + kFix4HashSize)[h4] = + (hash + kFix3HashSize)[h3] = + hash[ h2] = + p->lzPos; + SKIP_FOOTER_MT +} +*/ + +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable) +{ + vTable->Init = MatchFinderMt_Init; + vTable->GetNumAvailableBytes = MatchFinderMt_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = MatchFinderMt_GetPointerToCurrentPos; + vTable->GetMatches = MatchFinderMt_GetMatches; + + switch (MF(p)->numHashBytes) + { + case 2: + p->GetHeadsFunc = GetHeads2; + p->MixMatchesFunc = NULL; + vTable->Skip = MatchFinderMt0_Skip; + vTable->GetMatches = MatchFinderMt2_GetMatches; + break; + case 3: + p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3; + p->MixMatchesFunc = MixMatches2; + vTable->Skip = MatchFinderMt2_Skip; + break; + case 4: + p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4; + + // it's fast inline version of GetMatches() + // vTable->GetMatches = MatchFinderMt_GetMatches_Bt4; + + p->MixMatchesFunc = MixMatches3; + vTable->Skip = MatchFinderMt3_Skip; + break; + default: + p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5; + p->MixMatchesFunc = MixMatches4; + vTable->Skip = + MatchFinderMt3_Skip; + // MatchFinderMt4_Skip; + break; + } +} + +#undef RINOK_THREAD +#undef PRF +#undef MF +#undef GetUi24hi_from32 +#undef LOCK_BUFFER +#undef UNLOCK_BUFFER diff --git a/C/LzFindMt.h b/C/LzFindMt.h index 0eb2a4301..fcb479da9 100644 --- a/C/LzFindMt.h +++ b/C/LzFindMt.h @@ -1,112 +1,112 @@ -/* LzFindMt.h -- multithreaded Match finder for LZ algorithms -2024-01-22 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZ_FIND_MT_H -#define ZIP7_INC_LZ_FIND_MT_H - -#include "LzFind.h" -#include "Threads.h" - -EXTERN_C_BEGIN - -typedef struct -{ - UInt32 numProcessedBlocks; - CThread thread; - UInt64 affinity; - - BoolInt wasCreated; - BoolInt needStart; - BoolInt csWasInitialized; - BoolInt csWasEntered; - - BoolInt exit; - BoolInt stopWriting; - - CAutoResetEvent canStart; - CAutoResetEvent wasStopped; - CSemaphore freeSemaphore; - CSemaphore filledSemaphore; - CCriticalSection cs; - // UInt32 numBlocks_Sent; -} CMtSync; - - -struct CMatchFinderMt_; - -typedef UInt32 * (*Mf_Mix_Matches)(struct CMatchFinderMt_ *p, UInt32 matchMinPos, UInt32 *distances); - -/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ -#define kMtCacheLineDummy 128 - -typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, - UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); - -typedef struct CMatchFinderMt_ -{ - /* LZ */ - const Byte *pointerToCurPos; - UInt32 *btBuf; - const UInt32 *btBufPos; - const UInt32 *btBufPosLimit; - UInt32 lzPos; - UInt32 btNumAvailBytes; - - UInt32 *hash; - UInt32 fixedHashSize; - // UInt32 hash4Mask; - UInt32 historySize; - const UInt32 *crc; - - Mf_Mix_Matches MixMatchesFunc; - UInt32 failure_LZ_BT; // failure in BT transfered to LZ - // UInt32 failure_LZ_LZ; // failure in LZ tables - UInt32 failureBuf[1]; - // UInt32 crc[256]; - - /* LZ + BT */ - CMtSync btSync; - Byte btDummy[kMtCacheLineDummy]; - - /* BT */ - UInt32 *hashBuf; - UInt32 hashBufPos; - UInt32 hashBufPosLimit; - UInt32 hashNumAvail; - UInt32 failure_BT; - - - CLzRef *son; - UInt32 matchMaxLen; - UInt32 numHashBytes; - UInt32 pos; - const Byte *buffer; - UInt32 cyclicBufferPos; - UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ - UInt32 cutValue; - - /* BT + Hash */ - CMtSync hashSync; - /* Byte hashDummy[kMtCacheLineDummy]; */ - - /* Hash */ - Mf_GetHeads GetHeadsFunc; - CMatchFinder *MatchFinder; - // CMatchFinder MatchFinder; -} CMatchFinderMt; - -// only for Mt part -void MatchFinderMt_Construct(CMatchFinderMt *p); -void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc); - -SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, - UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); -void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable); - -/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */ -SRes MatchFinderMt_InitMt(CMatchFinderMt *p); -void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); - -EXTERN_C_END - -#endif +/* LzFindMt.h -- multithreaded Match finder for LZ algorithms +2024-01-22 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZ_FIND_MT_H +#define ZIP7_INC_LZ_FIND_MT_H + +#include "LzFind.h" +#include "Threads.h" + +EXTERN_C_BEGIN + +typedef struct +{ + UInt32 numProcessedBlocks; + CThread thread; + UInt64 affinity; + + BoolInt wasCreated; + BoolInt needStart; + BoolInt csWasInitialized; + BoolInt csWasEntered; + + BoolInt exit; + BoolInt stopWriting; + + CAutoResetEvent canStart; + CAutoResetEvent wasStopped; + CSemaphore freeSemaphore; + CSemaphore filledSemaphore; + CCriticalSection cs; + // UInt32 numBlocks_Sent; +} CMtSync; + + +struct CMatchFinderMt_; + +typedef UInt32 * (*Mf_Mix_Matches)(struct CMatchFinderMt_ *p, UInt32 matchMinPos, UInt32 *distances); + +/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ +#define kMtCacheLineDummy 128 + +typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); + +typedef struct CMatchFinderMt_ +{ + /* LZ */ + const Byte *pointerToCurPos; + UInt32 *btBuf; + const UInt32 *btBufPos; + const UInt32 *btBufPosLimit; + UInt32 lzPos; + UInt32 btNumAvailBytes; + + UInt32 *hash; + UInt32 fixedHashSize; + // UInt32 hash4Mask; + UInt32 historySize; + const UInt32 *crc; + + Mf_Mix_Matches MixMatchesFunc; + UInt32 failure_LZ_BT; // failure in BT transfered to LZ + // UInt32 failure_LZ_LZ; // failure in LZ tables + UInt32 failureBuf[1]; + // UInt32 crc[256]; + + /* LZ + BT */ + CMtSync btSync; + Byte btDummy[kMtCacheLineDummy]; + + /* BT */ + UInt32 *hashBuf; + UInt32 hashBufPos; + UInt32 hashBufPosLimit; + UInt32 hashNumAvail; + UInt32 failure_BT; + + + CLzRef *son; + UInt32 matchMaxLen; + UInt32 numHashBytes; + UInt32 pos; + const Byte *buffer; + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + UInt32 cutValue; + + /* BT + Hash */ + CMtSync hashSync; + /* Byte hashDummy[kMtCacheLineDummy]; */ + + /* Hash */ + Mf_GetHeads GetHeadsFunc; + CMatchFinder *MatchFinder; + // CMatchFinder MatchFinder; +} CMatchFinderMt; + +// only for Mt part +void MatchFinderMt_Construct(CMatchFinderMt *p); +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc); + +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc); +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable); + +/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */ +SRes MatchFinderMt_InitMt(CMatchFinderMt *p); +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); + +EXTERN_C_END + +#endif diff --git a/C/LzFindOpt.c b/C/LzFindOpt.c index e590aac1e..85bdc136d 100644 --- a/C/LzFindOpt.c +++ b/C/LzFindOpt.c @@ -1,578 +1,578 @@ -/* LzFindOpt.c -- multithreaded Match finder for LZ algorithms -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "CpuArch.h" -#include "LzFind.h" - -// #include "LzFindMt.h" - -// #define LOG_ITERS - -// #define LOG_THREAD - -#ifdef LOG_THREAD -#include -#define PRF(x) x -#else -// #define PRF(x) -#endif - -#ifdef LOG_ITERS -#include -UInt64 g_NumIters_Tree; -UInt64 g_NumIters_Loop; -UInt64 g_NumIters_Bytes; -#define LOG_ITER(x) x -#else -#define LOG_ITER(x) -#endif - -// ---------- BT THREAD ---------- - -#define USE_SON_PREFETCH -#define USE_LONG_MATCH_OPT - -#define kEmptyHashValue 0 - -// #define CYC_TO_POS_OFFSET 0 - -// #define CYC_TO_POS_OFFSET 1 // for debug - -/* -Z7_NO_INLINE -UInt32 * Z7_FASTCALL GetMatchesSpecN_1(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, - UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, UInt32 *posRes) -{ - do - { - UInt32 delta; - if (hash == size) - break; - delta = *hash++; - - if (delta == 0 || delta > (UInt32)pos) - return NULL; - - lenLimit++; - - if (delta == (UInt32)pos) - { - CLzRef *ptr1 = son + ((size_t)pos << 1) - CYC_TO_POS_OFFSET * 2; - *d++ = 0; - ptr1[0] = kEmptyHashValue; - ptr1[1] = kEmptyHashValue; - } -else -{ - UInt32 *_distances = ++d; - - CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1; - CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; - - const Byte *len0 = cur, *len1 = cur; - UInt32 cutValue = _cutValue; - const Byte *maxLen = cur + _maxLen; - - for (LOG_ITER(g_NumIters_Tree++);;) - { - LOG_ITER(g_NumIters_Loop++); - { - const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; - CLzRef *pair = son + ((size_t)(((ptrdiff_t)pos - CYC_TO_POS_OFFSET) + diff) << 1); - const Byte *len = (len0 < len1 ? len0 : len1); - - #ifdef USE_SON_PREFETCH - const UInt32 pair0 = *pair; - #endif - - if (len[diff] == len[0]) - { - if (++len != lenLimit && len[diff] == len[0]) - while (++len != lenLimit) - { - LOG_ITER(g_NumIters_Bytes++); - if (len[diff] != len[0]) - break; - } - if (maxLen < len) - { - maxLen = len; - *d++ = (UInt32)(len - cur); - *d++ = delta - 1; - - if (len == lenLimit) - { - const UInt32 pair1 = pair[1]; - *ptr1 = - #ifdef USE_SON_PREFETCH - pair0; - #else - pair[0]; - #endif - *ptr0 = pair1; - - _distances[-1] = (UInt32)(d - _distances); - - #ifdef USE_LONG_MATCH_OPT - - if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) - break; - - { - for (;;) - { - hash++; - pos++; - cur++; - lenLimit++; - { - CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; - #if 0 - *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff]; - #else - const UInt32 p0 = ptr[0 + (diff * 2)]; - const UInt32 p1 = ptr[1 + (diff * 2)]; - ptr[0] = p0; - ptr[1] = p1; - // ptr[0] = ptr[0 + (diff * 2)]; - // ptr[1] = ptr[1 + (diff * 2)]; - #endif - } - // PrintSon(son + 2, pos - 1); - // printf("\npos = %x delta = %x\n", pos, delta); - len++; - *d++ = 2; - *d++ = (UInt32)(len - cur); - *d++ = delta - 1; - if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) - break; - } - } - #endif - - break; - } - } - } - - { - const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); - if (len[diff] < len[0]) - { - delta = pair[1]; - if (delta >= curMatch) - return NULL; - *ptr1 = curMatch; - ptr1 = pair + 1; - len1 = len; - } - else - { - delta = *pair; - if (delta >= curMatch) - return NULL; - *ptr0 = curMatch; - ptr0 = pair; - len0 = len; - } - - delta = (UInt32)pos - delta; - - if (--cutValue == 0 || delta >= pos) - { - *ptr0 = *ptr1 = kEmptyHashValue; - _distances[-1] = (UInt32)(d - _distances); - break; - } - } - } - } // for (tree iterations) -} - pos++; - cur++; - } - while (d < limit); - *posRes = (UInt32)pos; - return d; -} -*/ - -/* define cbs if you use 2 functions. - GetMatchesSpecN_1() : (pos < _cyclicBufferSize) - GetMatchesSpecN_2() : (pos >= _cyclicBufferSize) - - do not define cbs if you use 1 function: - GetMatchesSpecN_2() -*/ - -// #define cbs _cyclicBufferSize - -/* - we use size_t for (pos) and (_cyclicBufferPos_ instead of UInt32 - to eliminate "movsx" BUG in old MSVC x64 compiler. -*/ - -UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, - UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, - UInt32 *posRes); - -Z7_NO_INLINE -UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, - UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, - UInt32 *posRes) -{ - do // while (hash != size) - { - UInt32 delta; - - #ifndef cbs - UInt32 cbs; - #endif - - if (hash == size) - break; - - delta = *hash++; - - if (delta == 0) - return NULL; - - lenLimit++; - - #ifndef cbs - cbs = _cyclicBufferSize; - if ((UInt32)pos < cbs) - { - if (delta > (UInt32)pos) - return NULL; - cbs = (UInt32)pos; - } - #endif - - if (delta >= cbs) - { - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - *d++ = 0; - ptr1[0] = kEmptyHashValue; - ptr1[1] = kEmptyHashValue; - } -else -{ - UInt32 *_distances = ++d; - - CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - - UInt32 cutValue = _cutValue; - const Byte *len0 = cur, *len1 = cur; - const Byte *maxLen = cur + _maxLen; - - // if (cutValue == 0) { *ptr0 = *ptr1 = kEmptyHashValue; } else - for (LOG_ITER(g_NumIters_Tree++);;) - { - LOG_ITER(g_NumIters_Loop++); - { - // SPEC code - CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - (ptrdiff_t)delta - + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) - ) << 1); - - const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; - const Byte *len = (len0 < len1 ? len0 : len1); - - #ifdef USE_SON_PREFETCH - const UInt32 pair0 = *pair; - #endif - - if (len[diff] == len[0]) - { - if (++len != lenLimit && len[diff] == len[0]) - while (++len != lenLimit) - { - LOG_ITER(g_NumIters_Bytes++); - if (len[diff] != len[0]) - break; - } - if (maxLen < len) - { - maxLen = len; - *d++ = (UInt32)(len - cur); - *d++ = delta - 1; - - if (len == lenLimit) - { - const UInt32 pair1 = pair[1]; - *ptr1 = - #ifdef USE_SON_PREFETCH - pair0; - #else - pair[0]; - #endif - *ptr0 = pair1; - - _distances[-1] = (UInt32)(d - _distances); - - #ifdef USE_LONG_MATCH_OPT - - if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) - break; - - { - for (;;) - { - *d++ = 2; - *d++ = (UInt32)(lenLimit - cur); - *d++ = delta - 1; - cur++; - lenLimit++; - // SPEC - _cyclicBufferPos++; - { - // SPEC code - CLzRef *dest = son + ((size_t)(_cyclicBufferPos) << 1); - const CLzRef *src = dest + ((diff - + (ptrdiff_t)(UInt32)((_cyclicBufferPos < delta) ? cbs : 0)) << 1); - // CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; - #if 0 - *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); - #else - const UInt32 p0 = src[0]; - const UInt32 p1 = src[1]; - dest[0] = p0; - dest[1] = p1; - #endif - } - pos++; - hash++; - if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) - break; - } // for() end for long matches - } - #endif - - break; // break from TREE iterations - } - } - } - { - const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); - if (len[diff] < len[0]) - { - delta = pair[1]; - *ptr1 = curMatch; - ptr1 = pair + 1; - len1 = len; - if (delta >= curMatch) - return NULL; - } - else - { - delta = *pair; - *ptr0 = curMatch; - ptr0 = pair; - len0 = len; - if (delta >= curMatch) - return NULL; - } - delta = (UInt32)pos - delta; - - if (--cutValue == 0 || delta >= cbs) - { - *ptr0 = *ptr1 = kEmptyHashValue; - _distances[-1] = (UInt32)(d - _distances); - break; - } - } - } - } // for (tree iterations) -} - pos++; - _cyclicBufferPos++; - cur++; - } - while (d < limit); - *posRes = (UInt32)pos; - return d; -} - - - -/* -typedef UInt32 uint32plus; // size_t - -UInt32 * Z7_FASTCALL GetMatchesSpecN_3(uint32plus lenLimit, size_t pos, const Byte *cur, CLzRef *son, - UInt32 _cutValue, UInt32 *d, uint32plus _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, - size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, - UInt32 *posRes) -{ - do // while (hash != size) - { - UInt32 delta; - - #ifndef cbs - UInt32 cbs; - #endif - - if (hash == size) - break; - - delta = *hash++; - - if (delta == 0) - return NULL; - - #ifndef cbs - cbs = _cyclicBufferSize; - if ((UInt32)pos < cbs) - { - if (delta > (UInt32)pos) - return NULL; - cbs = (UInt32)pos; - } - #endif - - if (delta >= cbs) - { - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - *d++ = 0; - ptr1[0] = kEmptyHashValue; - ptr1[1] = kEmptyHashValue; - } -else -{ - CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; - CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); - UInt32 *_distances = ++d; - uint32plus len0 = 0, len1 = 0; - UInt32 cutValue = _cutValue; - uint32plus maxLen = _maxLen; - // lenLimit++; // const Byte *lenLimit = cur + _lenLimit; - - for (LOG_ITER(g_NumIters_Tree++);;) - { - LOG_ITER(g_NumIters_Loop++); - { - // const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; - CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - delta - + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) - ) << 1); - const Byte *pb = cur - delta; - uint32plus len = (len0 < len1 ? len0 : len1); - - #ifdef USE_SON_PREFETCH - const UInt32 pair0 = *pair; - #endif - - if (pb[len] == cur[len]) - { - if (++len != lenLimit && pb[len] == cur[len]) - while (++len != lenLimit) - if (pb[len] != cur[len]) - break; - if (maxLen < len) - { - maxLen = len; - *d++ = (UInt32)len; - *d++ = delta - 1; - if (len == lenLimit) - { - { - const UInt32 pair1 = pair[1]; - *ptr0 = pair1; - *ptr1 = - #ifdef USE_SON_PREFETCH - pair0; - #else - pair[0]; - #endif - } - - _distances[-1] = (UInt32)(d - _distances); - - #ifdef USE_LONG_MATCH_OPT - - if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) - break; - - { - const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; - for (;;) - { - *d++ = 2; - *d++ = (UInt32)lenLimit; - *d++ = delta - 1; - _cyclicBufferPos++; - { - CLzRef *dest = son + ((size_t)_cyclicBufferPos << 1); - const CLzRef *src = dest + ((diff + - (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)) << 1); - #if 0 - *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); - #else - const UInt32 p0 = src[0]; - const UInt32 p1 = src[1]; - dest[0] = p0; - dest[1] = p1; - #endif - } - hash++; - pos++; - cur++; - pb++; - if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) - break; - } - } - #endif - - break; - } - } - } - { - const UInt32 curMatch = (UInt32)pos - delta; - if (pb[len] < cur[len]) - { - delta = pair[1]; - *ptr1 = curMatch; - ptr1 = pair + 1; - len1 = len; - } - else - { - delta = *pair; - *ptr0 = curMatch; - ptr0 = pair; - len0 = len; - } - - { - if (delta >= curMatch) - return NULL; - delta = (UInt32)pos - delta; - if (delta >= cbs - // delta >= _cyclicBufferSize || delta >= pos - || --cutValue == 0) - { - *ptr0 = *ptr1 = kEmptyHashValue; - _distances[-1] = (UInt32)(d - _distances); - break; - } - } - } - } - } // for (tree iterations) -} - pos++; - _cyclicBufferPos++; - cur++; - } - while (d < limit); - *posRes = (UInt32)pos; - return d; -} -*/ +/* LzFindOpt.c -- multithreaded Match finder for LZ algorithms +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "LzFind.h" + +// #include "LzFindMt.h" + +// #define LOG_ITERS + +// #define LOG_THREAD + +#ifdef LOG_THREAD +#include +#define PRF(x) x +#else +// #define PRF(x) +#endif + +#ifdef LOG_ITERS +#include +UInt64 g_NumIters_Tree; +UInt64 g_NumIters_Loop; +UInt64 g_NumIters_Bytes; +#define LOG_ITER(x) x +#else +#define LOG_ITER(x) +#endif + +// ---------- BT THREAD ---------- + +#define USE_SON_PREFETCH +#define USE_LONG_MATCH_OPT + +#define kEmptyHashValue 0 + +// #define CYC_TO_POS_OFFSET 0 + +// #define CYC_TO_POS_OFFSET 1 // for debug + +/* +Z7_NO_INLINE +UInt32 * Z7_FASTCALL GetMatchesSpecN_1(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, UInt32 *posRes) +{ + do + { + UInt32 delta; + if (hash == size) + break; + delta = *hash++; + + if (delta == 0 || delta > (UInt32)pos) + return NULL; + + lenLimit++; + + if (delta == (UInt32)pos) + { + CLzRef *ptr1 = son + ((size_t)pos << 1) - CYC_TO_POS_OFFSET * 2; + *d++ = 0; + ptr1[0] = kEmptyHashValue; + ptr1[1] = kEmptyHashValue; + } +else +{ + UInt32 *_distances = ++d; + + CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1; + CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + + const Byte *len0 = cur, *len1 = cur; + UInt32 cutValue = _cutValue; + const Byte *maxLen = cur + _maxLen; + + for (LOG_ITER(g_NumIters_Tree++);;) + { + LOG_ITER(g_NumIters_Loop++); + { + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + CLzRef *pair = son + ((size_t)(((ptrdiff_t)pos - CYC_TO_POS_OFFSET) + diff) << 1); + const Byte *len = (len0 < len1 ? len0 : len1); + + #ifdef USE_SON_PREFETCH + const UInt32 pair0 = *pair; + #endif + + if (len[diff] == len[0]) + { + if (++len != lenLimit && len[diff] == len[0]) + while (++len != lenLimit) + { + LOG_ITER(g_NumIters_Bytes++); + if (len[diff] != len[0]) + break; + } + if (maxLen < len) + { + maxLen = len; + *d++ = (UInt32)(len - cur); + *d++ = delta - 1; + + if (len == lenLimit) + { + const UInt32 pair1 = pair[1]; + *ptr1 = + #ifdef USE_SON_PREFETCH + pair0; + #else + pair[0]; + #endif + *ptr0 = pair1; + + _distances[-1] = (UInt32)(d - _distances); + + #ifdef USE_LONG_MATCH_OPT + + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + + { + for (;;) + { + hash++; + pos++; + cur++; + lenLimit++; + { + CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + #if 0 + *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff]; + #else + const UInt32 p0 = ptr[0 + (diff * 2)]; + const UInt32 p1 = ptr[1 + (diff * 2)]; + ptr[0] = p0; + ptr[1] = p1; + // ptr[0] = ptr[0 + (diff * 2)]; + // ptr[1] = ptr[1 + (diff * 2)]; + #endif + } + // PrintSon(son + 2, pos - 1); + // printf("\npos = %x delta = %x\n", pos, delta); + len++; + *d++ = 2; + *d++ = (UInt32)(len - cur); + *d++ = delta - 1; + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + } + } + #endif + + break; + } + } + } + + { + const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); + if (len[diff] < len[0]) + { + delta = pair[1]; + if (delta >= curMatch) + return NULL; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + } + else + { + delta = *pair; + if (delta >= curMatch) + return NULL; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + } + + delta = (UInt32)pos - delta; + + if (--cutValue == 0 || delta >= pos) + { + *ptr0 = *ptr1 = kEmptyHashValue; + _distances[-1] = (UInt32)(d - _distances); + break; + } + } + } + } // for (tree iterations) +} + pos++; + cur++; + } + while (d < limit); + *posRes = (UInt32)pos; + return d; +} +*/ + +/* define cbs if you use 2 functions. + GetMatchesSpecN_1() : (pos < _cyclicBufferSize) + GetMatchesSpecN_2() : (pos >= _cyclicBufferSize) + + do not define cbs if you use 1 function: + GetMatchesSpecN_2() +*/ + +// #define cbs _cyclicBufferSize + +/* + we use size_t for (pos) and (_cyclicBufferPos_ instead of UInt32 + to eliminate "movsx" BUG in old MSVC x64 compiler. +*/ + +UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes); + +Z7_NO_INLINE +UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes) +{ + do // while (hash != size) + { + UInt32 delta; + + #ifndef cbs + UInt32 cbs; + #endif + + if (hash == size) + break; + + delta = *hash++; + + if (delta == 0) + return NULL; + + lenLimit++; + + #ifndef cbs + cbs = _cyclicBufferSize; + if ((UInt32)pos < cbs) + { + if (delta > (UInt32)pos) + return NULL; + cbs = (UInt32)pos; + } + #endif + + if (delta >= cbs) + { + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + *d++ = 0; + ptr1[0] = kEmptyHashValue; + ptr1[1] = kEmptyHashValue; + } +else +{ + UInt32 *_distances = ++d; + + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + + UInt32 cutValue = _cutValue; + const Byte *len0 = cur, *len1 = cur; + const Byte *maxLen = cur + _maxLen; + + // if (cutValue == 0) { *ptr0 = *ptr1 = kEmptyHashValue; } else + for (LOG_ITER(g_NumIters_Tree++);;) + { + LOG_ITER(g_NumIters_Loop++); + { + // SPEC code + CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - (ptrdiff_t)delta + + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) + ) << 1); + + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + const Byte *len = (len0 < len1 ? len0 : len1); + + #ifdef USE_SON_PREFETCH + const UInt32 pair0 = *pair; + #endif + + if (len[diff] == len[0]) + { + if (++len != lenLimit && len[diff] == len[0]) + while (++len != lenLimit) + { + LOG_ITER(g_NumIters_Bytes++); + if (len[diff] != len[0]) + break; + } + if (maxLen < len) + { + maxLen = len; + *d++ = (UInt32)(len - cur); + *d++ = delta - 1; + + if (len == lenLimit) + { + const UInt32 pair1 = pair[1]; + *ptr1 = + #ifdef USE_SON_PREFETCH + pair0; + #else + pair[0]; + #endif + *ptr0 = pair1; + + _distances[-1] = (UInt32)(d - _distances); + + #ifdef USE_LONG_MATCH_OPT + + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + + { + for (;;) + { + *d++ = 2; + *d++ = (UInt32)(lenLimit - cur); + *d++ = delta - 1; + cur++; + lenLimit++; + // SPEC + _cyclicBufferPos++; + { + // SPEC code + CLzRef *dest = son + ((size_t)(_cyclicBufferPos) << 1); + const CLzRef *src = dest + ((diff + + (ptrdiff_t)(UInt32)((_cyclicBufferPos < delta) ? cbs : 0)) << 1); + // CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2; + #if 0 + *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); + #else + const UInt32 p0 = src[0]; + const UInt32 p1 = src[1]; + dest[0] = p0; + dest[1] = p1; + #endif + } + pos++; + hash++; + if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit) + break; + } // for() end for long matches + } + #endif + + break; // break from TREE iterations + } + } + } + { + const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff); + if (len[diff] < len[0]) + { + delta = pair[1]; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + if (delta >= curMatch) + return NULL; + } + else + { + delta = *pair; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + if (delta >= curMatch) + return NULL; + } + delta = (UInt32)pos - delta; + + if (--cutValue == 0 || delta >= cbs) + { + *ptr0 = *ptr1 = kEmptyHashValue; + _distances[-1] = (UInt32)(d - _distances); + break; + } + } + } + } // for (tree iterations) +} + pos++; + _cyclicBufferPos++; + cur++; + } + while (d < limit); + *posRes = (UInt32)pos; + return d; +} + + + +/* +typedef UInt32 uint32plus; // size_t + +UInt32 * Z7_FASTCALL GetMatchesSpecN_3(uint32plus lenLimit, size_t pos, const Byte *cur, CLzRef *son, + UInt32 _cutValue, UInt32 *d, uint32plus _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, + size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, + UInt32 *posRes) +{ + do // while (hash != size) + { + UInt32 delta; + + #ifndef cbs + UInt32 cbs; + #endif + + if (hash == size) + break; + + delta = *hash++; + + if (delta == 0) + return NULL; + + #ifndef cbs + cbs = _cyclicBufferSize; + if ((UInt32)pos < cbs) + { + if (delta > (UInt32)pos) + return NULL; + cbs = (UInt32)pos; + } + #endif + + if (delta >= cbs) + { + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + *d++ = 0; + ptr1[0] = kEmptyHashValue; + ptr1[1] = kEmptyHashValue; + } +else +{ + CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1); + UInt32 *_distances = ++d; + uint32plus len0 = 0, len1 = 0; + UInt32 cutValue = _cutValue; + uint32plus maxLen = _maxLen; + // lenLimit++; // const Byte *lenLimit = cur + _lenLimit; + + for (LOG_ITER(g_NumIters_Tree++);;) + { + LOG_ITER(g_NumIters_Loop++); + { + // const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - delta + + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0) + ) << 1); + const Byte *pb = cur - delta; + uint32plus len = (len0 < len1 ? len0 : len1); + + #ifdef USE_SON_PREFETCH + const UInt32 pair0 = *pair; + #endif + + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + maxLen = len; + *d++ = (UInt32)len; + *d++ = delta - 1; + if (len == lenLimit) + { + { + const UInt32 pair1 = pair[1]; + *ptr0 = pair1; + *ptr1 = + #ifdef USE_SON_PREFETCH + pair0; + #else + pair[0]; + #endif + } + + _distances[-1] = (UInt32)(d - _distances); + + #ifdef USE_LONG_MATCH_OPT + + if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) + break; + + { + const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta; + for (;;) + { + *d++ = 2; + *d++ = (UInt32)lenLimit; + *d++ = delta - 1; + _cyclicBufferPos++; + { + CLzRef *dest = son + ((size_t)_cyclicBufferPos << 1); + const CLzRef *src = dest + ((diff + + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)) << 1); + #if 0 + *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src); + #else + const UInt32 p0 = src[0]; + const UInt32 p1 = src[1]; + dest[0] = p0; + dest[1] = p1; + #endif + } + hash++; + pos++; + cur++; + pb++; + if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit) + break; + } + } + #endif + + break; + } + } + } + { + const UInt32 curMatch = (UInt32)pos - delta; + if (pb[len] < cur[len]) + { + delta = pair[1]; + *ptr1 = curMatch; + ptr1 = pair + 1; + len1 = len; + } + else + { + delta = *pair; + *ptr0 = curMatch; + ptr0 = pair; + len0 = len; + } + + { + if (delta >= curMatch) + return NULL; + delta = (UInt32)pos - delta; + if (delta >= cbs + // delta >= _cyclicBufferSize || delta >= pos + || --cutValue == 0) + { + *ptr0 = *ptr1 = kEmptyHashValue; + _distances[-1] = (UInt32)(d - _distances); + break; + } + } + } + } + } // for (tree iterations) +} + pos++; + _cyclicBufferPos++; + cur++; + } + while (d < limit); + *posRes = (UInt32)pos; + return d; +} +*/ diff --git a/C/LzHash.h b/C/LzHash.h index 3b172ebc6..2b6290b64 100644 --- a/C/LzHash.h +++ b/C/LzHash.h @@ -1,34 +1,34 @@ -/* LzHash.h -- HASH constants for LZ algorithms -2023-03-05 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZ_HASH_H -#define ZIP7_INC_LZ_HASH_H - -/* - (kHash2Size >= (1 << 8)) : Required - (kHash3Size >= (1 << 16)) : Required -*/ - -#define kHash2Size (1 << 10) -#define kHash3Size (1 << 16) -// #define kHash4Size (1 << 20) - -#define kFix3HashSize (kHash2Size) -#define kFix4HashSize (kHash2Size + kHash3Size) -// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) - -/* - We use up to 3 crc values for hash: - crc0 - crc1 << Shift_1 - crc2 << Shift_2 - (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff. - Small values for Shift are not good for collision rate. - Big value for Shift_2 increases the minimum size - of hash table, that will be slow for small files. -*/ - -#define kLzHash_CrcShift_1 5 -#define kLzHash_CrcShift_2 10 - -#endif +/* LzHash.h -- HASH constants for LZ algorithms +2023-03-05 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZ_HASH_H +#define ZIP7_INC_LZ_HASH_H + +/* + (kHash2Size >= (1 << 8)) : Required + (kHash3Size >= (1 << 16)) : Required +*/ + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +// #define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +/* + We use up to 3 crc values for hash: + crc0 + crc1 << Shift_1 + crc2 << Shift_2 + (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff. + Small values for Shift are not good for collision rate. + Big value for Shift_2 increases the minimum size + of hash table, that will be slow for small files. +*/ + +#define kLzHash_CrcShift_1 5 +#define kLzHash_CrcShift_2 10 + +#endif diff --git a/C/Lzma2Dec.c b/C/Lzma2Dec.c index 64420ef06..8bf54e499 100644 --- a/C/Lzma2Dec.c +++ b/C/Lzma2Dec.c @@ -1,493 +1,493 @@ -/* Lzma2Dec.c -- LZMA2 Decoder -2024-03-01 : Igor Pavlov : Public domain */ - -/* #define SHOW_DEBUG_INFO */ - -#include "Precomp.h" - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include - -#include "Lzma2Dec.h" - -/* -00000000 - End of data -00000001 U U - Uncompressed, reset dic, need reset state and set new prop -00000010 U U - Uncompressed, no reset -100uuuuu U U P P - LZMA, no reset -101uuuuu U U P P - LZMA, reset state -110uuuuu U U P P S - LZMA, reset state + set new prop -111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic - - u, U - Unpack Size - P - Pack Size - S - Props -*/ - -#define LZMA2_CONTROL_COPY_RESET_DIC 1 - -#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0) - -#define LZMA2_LCLP_MAX 4 -#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -typedef enum -{ - LZMA2_STATE_CONTROL, - LZMA2_STATE_UNPACK0, - LZMA2_STATE_UNPACK1, - LZMA2_STATE_PACK0, - LZMA2_STATE_PACK1, - LZMA2_STATE_PROP, - LZMA2_STATE_DATA, - LZMA2_STATE_DATA_CONT, - LZMA2_STATE_FINISHED, - LZMA2_STATE_ERROR -} ELzma2State; - -static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) -{ - UInt32 dicSize; - if (prop > 40) - return SZ_ERROR_UNSUPPORTED; - dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); - props[0] = (Byte)LZMA2_LCLP_MAX; - props[1] = (Byte)(dicSize); - props[2] = (Byte)(dicSize >> 8); - props[3] = (Byte)(dicSize >> 16); - props[4] = (Byte)(dicSize >> 24); - return SZ_OK; -} - -SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) -{ - Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)) - return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); -} - -SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) -{ - Byte props[LZMA_PROPS_SIZE]; - RINOK(Lzma2Dec_GetOldProps(prop, props)) - return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); -} - -void Lzma2Dec_Init(CLzma2Dec *p) -{ - p->state = LZMA2_STATE_CONTROL; - p->needInitLevel = 0xE0; - p->isExtraMode = False; - p->unpackSize = 0; - - // p->decoder.dicPos = 0; // we can use it instead of full init - LzmaDec_Init(&p->decoder); -} - -// ELzma2State -static unsigned Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) -{ - switch (p->state) - { - case LZMA2_STATE_CONTROL: - p->isExtraMode = False; - p->control = b; - PRF(printf("\n %8X", (unsigned)p->decoder.dicPos)); - PRF(printf(" %02X", (unsigned)b)); - if (b == 0) - return LZMA2_STATE_FINISHED; - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if (b == LZMA2_CONTROL_COPY_RESET_DIC) - p->needInitLevel = 0xC0; - else if (b > 2 || p->needInitLevel == 0xE0) - return LZMA2_STATE_ERROR; - } - else - { - if (b < p->needInitLevel) - return LZMA2_STATE_ERROR; - p->needInitLevel = 0; - p->unpackSize = (UInt32)(b & 0x1F) << 16; - } - return LZMA2_STATE_UNPACK0; - - case LZMA2_STATE_UNPACK0: - p->unpackSize |= (UInt32)b << 8; - return LZMA2_STATE_UNPACK1; - - case LZMA2_STATE_UNPACK1: - p->unpackSize |= (UInt32)b; - p->unpackSize++; - PRF(printf(" %7u", (unsigned)p->unpackSize)); - return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; - - case LZMA2_STATE_PACK0: - p->packSize = (UInt32)b << 8; - return LZMA2_STATE_PACK1; - - case LZMA2_STATE_PACK1: - p->packSize |= (UInt32)b; - p->packSize++; - // if (p->packSize < 5) return LZMA2_STATE_ERROR; - PRF(printf(" %5u", (unsigned)p->packSize)); - return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA; - - case LZMA2_STATE_PROP: - { - unsigned lc, lp; - if (b >= (9 * 5 * 5)) - return LZMA2_STATE_ERROR; - lc = b % 9; - b /= 9; - p->decoder.prop.pb = (Byte)(b / 5); - lp = b % 5; - if (lc + lp > LZMA2_LCLP_MAX) - return LZMA2_STATE_ERROR; - p->decoder.prop.lc = (Byte)lc; - p->decoder.prop.lp = (Byte)lp; - return LZMA2_STATE_DATA; - } - - default: - return LZMA2_STATE_ERROR; - } -} - -static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) -{ - memcpy(p->dic + p->dicPos, src, size); - p->dicPos += size; - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) - p->checkDicSize = p->prop.dicSize; - p->processedPos += (UInt32)size; -} - -void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); - - -SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT inSize = *srcLen; - *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - - while (p->state != LZMA2_STATE_ERROR) - { - SizeT dicPos; - - if (p->state == LZMA2_STATE_FINISHED) - { - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return SZ_OK; - } - - dicPos = p->decoder.dicPos; - - if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } - - if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) - { - if (*srcLen == inSize) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - (*srcLen)++; - p->state = Lzma2Dec_UpdateState(p, *src++); - if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) - break; - continue; - } - - { - SizeT inCur = inSize - *srcLen; - SizeT outCur = dicLimit - dicPos; - ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; - - if (outCur >= p->unpackSize) - { - outCur = (SizeT)p->unpackSize; - curFinishMode = LZMA_FINISH_END; - } - - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if (inCur == 0) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - if (p->state == LZMA2_STATE_DATA) - { - BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); - LzmaDec_InitDicAndState(&p->decoder, initDic, False); - } - - if (inCur > outCur) - inCur = outCur; - if (inCur == 0) - break; - - LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur); - - src += inCur; - *srcLen += inCur; - p->unpackSize -= (UInt32)inCur; - p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; - } - else - { - SRes res; - - if (p->state == LZMA2_STATE_DATA) - { - BoolInt initDic = (p->control >= 0xE0); - BoolInt initState = (p->control >= 0xA0); - LzmaDec_InitDicAndState(&p->decoder, initDic, initState); - p->state = LZMA2_STATE_DATA_CONT; - } - - if (inCur > p->packSize) - inCur = (SizeT)p->packSize; - - res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status); - - src += inCur; - *srcLen += inCur; - p->packSize -= (UInt32)inCur; - outCur = p->decoder.dicPos - dicPos; - p->unpackSize -= (UInt32)outCur; - - if (res != 0) - break; - - if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) - { - if (p->packSize == 0) - break; - return SZ_OK; - } - - if (inCur == 0 && outCur == 0) - { - if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - || p->unpackSize != 0 - || p->packSize != 0) - break; - p->state = LZMA2_STATE_CONTROL; - } - - *status = LZMA_STATUS_NOT_SPECIFIED; - } - } - } - - *status = LZMA_STATUS_NOT_SPECIFIED; - p->state = LZMA2_STATE_ERROR; - return SZ_ERROR_DATA; -} - - - - -ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, - SizeT outSize, - const Byte *src, SizeT *srcLen, - int checkFinishBlock) -{ - SizeT inSize = *srcLen; - *srcLen = 0; - - while (p->state != LZMA2_STATE_ERROR) - { - if (p->state == LZMA2_STATE_FINISHED) - return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK; - - if (outSize == 0 && !checkFinishBlock) - return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; - - if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) - { - if (*srcLen == inSize) - return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; - (*srcLen)++; - - p->state = Lzma2Dec_UpdateState(p, *src++); - - if (p->state == LZMA2_STATE_UNPACK0) - { - // if (p->decoder.dicPos != 0) - if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0) - return LZMA2_PARSE_STATUS_NEW_BLOCK; - // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED; - } - - // The following code can be commented. - // It's not big problem, if we read additional input bytes. - // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state. - - if (outSize == 0 && p->state != LZMA2_STATE_FINISHED) - { - // checkFinishBlock is true. So we expect that block must be finished, - // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here - // break; - return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; - } - - if (p->state == LZMA2_STATE_DATA) - return LZMA2_PARSE_STATUS_NEW_CHUNK; - - continue; - } - - if (outSize == 0) - return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; - - { - SizeT inCur = inSize - *srcLen; - - if (LZMA2_IS_UNCOMPRESSED_STATE(p)) - { - if (inCur == 0) - return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; - if (inCur > p->unpackSize) - inCur = p->unpackSize; - if (inCur > outSize) - inCur = outSize; - p->decoder.dicPos += inCur; - src += inCur; - *srcLen += inCur; - outSize -= inCur; - p->unpackSize -= (UInt32)inCur; - p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; - } - else - { - p->isExtraMode = True; - - if (inCur == 0) - { - if (p->packSize != 0) - return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; - } - else if (p->state == LZMA2_STATE_DATA) - { - p->state = LZMA2_STATE_DATA_CONT; - if (*src != 0) - { - // first byte of lzma chunk must be Zero - *srcLen += 1; - p->packSize--; - break; - } - } - - if (inCur > p->packSize) - inCur = (SizeT)p->packSize; - - src += inCur; - *srcLen += inCur; - p->packSize -= (UInt32)inCur; - - if (p->packSize == 0) - { - SizeT rem = outSize; - if (rem > p->unpackSize) - rem = p->unpackSize; - p->decoder.dicPos += rem; - p->unpackSize -= (UInt32)rem; - outSize -= rem; - if (p->unpackSize == 0) - p->state = LZMA2_STATE_CONTROL; - } - } - } - } - - p->state = LZMA2_STATE_ERROR; - return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; -} - - - - -SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT outSize = *destLen, inSize = *srcLen; - *srcLen = *destLen = 0; - - for (;;) - { - SizeT inCur = inSize, outCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - - if (p->decoder.dicPos == p->decoder.dicBufSize) - p->decoder.dicPos = 0; - dicPos = p->decoder.dicPos; - curFinishMode = LZMA_FINISH_ANY; - outCur = p->decoder.dicBufSize - dicPos; - - if (outCur >= outSize) - { - outCur = outSize; - curFinishMode = finishMode; - } - - res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status); - - src += inCur; - inSize -= inCur; - *srcLen += inCur; - outCur = p->decoder.dicPos - dicPos; - memcpy(dest, p->decoder.dic + dicPos, outCur); - dest += outCur; - outSize -= outCur; - *destLen += outCur; - if (res != 0) - return res; - if (outCur == 0 || outSize == 0) - return SZ_OK; - } -} - - -SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc) -{ - CLzma2Dec p; - SRes res; - SizeT outSize = *destLen, inSize = *srcLen; - *destLen = *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - Lzma2Dec_CONSTRUCT(&p) - RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)) - p.decoder.dic = dest; - p.decoder.dicBufSize = outSize; - Lzma2Dec_Init(&p); - *srcLen = inSize; - res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); - *destLen = p.decoder.dicPos; - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - Lzma2Dec_FreeProbs(&p, alloc); - return res; -} - -#undef PRF +/* Lzma2Dec.c -- LZMA2 Decoder +2024-03-01 : Igor Pavlov : Public domain */ + +/* #define SHOW_DEBUG_INFO */ + +#include "Precomp.h" + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include + +#include "Lzma2Dec.h" + +/* +00000000 - End of data +00000001 U U - Uncompressed, reset dic, need reset state and set new prop +00000010 U U - Uncompressed, no reset +100uuuuu U U P P - LZMA, no reset +101uuuuu U U P P - LZMA, reset state +110uuuuu U U P P S - LZMA, reset state + set new prop +111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic + + u, U - Unpack Size + P - Pack Size + S - Props +*/ + +#define LZMA2_CONTROL_COPY_RESET_DIC 1 + +#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0) + +#define LZMA2_LCLP_MAX 4 +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +typedef enum +{ + LZMA2_STATE_CONTROL, + LZMA2_STATE_UNPACK0, + LZMA2_STATE_UNPACK1, + LZMA2_STATE_PACK0, + LZMA2_STATE_PACK1, + LZMA2_STATE_PROP, + LZMA2_STATE_DATA, + LZMA2_STATE_DATA_CONT, + LZMA2_STATE_FINISHED, + LZMA2_STATE_ERROR +} ELzma2State; + +static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props) +{ + UInt32 dicSize; + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop); + props[0] = (Byte)LZMA2_LCLP_MAX; + props[1] = (Byte)(dicSize); + props[2] = (Byte)(dicSize >> 8); + props[3] = (Byte)(dicSize >> 16); + props[4] = (Byte)(dicSize >> 24); + return SZ_OK; +} + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)) + return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc) +{ + Byte props[LZMA_PROPS_SIZE]; + RINOK(Lzma2Dec_GetOldProps(prop, props)) + return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc); +} + +void Lzma2Dec_Init(CLzma2Dec *p) +{ + p->state = LZMA2_STATE_CONTROL; + p->needInitLevel = 0xE0; + p->isExtraMode = False; + p->unpackSize = 0; + + // p->decoder.dicPos = 0; // we can use it instead of full init + LzmaDec_Init(&p->decoder); +} + +// ELzma2State +static unsigned Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) +{ + switch (p->state) + { + case LZMA2_STATE_CONTROL: + p->isExtraMode = False; + p->control = b; + PRF(printf("\n %8X", (unsigned)p->decoder.dicPos)); + PRF(printf(" %02X", (unsigned)b)); + if (b == 0) + return LZMA2_STATE_FINISHED; + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (b == LZMA2_CONTROL_COPY_RESET_DIC) + p->needInitLevel = 0xC0; + else if (b > 2 || p->needInitLevel == 0xE0) + return LZMA2_STATE_ERROR; + } + else + { + if (b < p->needInitLevel) + return LZMA2_STATE_ERROR; + p->needInitLevel = 0; + p->unpackSize = (UInt32)(b & 0x1F) << 16; + } + return LZMA2_STATE_UNPACK0; + + case LZMA2_STATE_UNPACK0: + p->unpackSize |= (UInt32)b << 8; + return LZMA2_STATE_UNPACK1; + + case LZMA2_STATE_UNPACK1: + p->unpackSize |= (UInt32)b; + p->unpackSize++; + PRF(printf(" %7u", (unsigned)p->unpackSize)); + return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; + + case LZMA2_STATE_PACK0: + p->packSize = (UInt32)b << 8; + return LZMA2_STATE_PACK1; + + case LZMA2_STATE_PACK1: + p->packSize |= (UInt32)b; + p->packSize++; + // if (p->packSize < 5) return LZMA2_STATE_ERROR; + PRF(printf(" %5u", (unsigned)p->packSize)); + return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA; + + case LZMA2_STATE_PROP: + { + unsigned lc, lp; + if (b >= (9 * 5 * 5)) + return LZMA2_STATE_ERROR; + lc = b % 9; + b /= 9; + p->decoder.prop.pb = (Byte)(b / 5); + lp = b % 5; + if (lc + lp > LZMA2_LCLP_MAX) + return LZMA2_STATE_ERROR; + p->decoder.prop.lc = (Byte)lc; + p->decoder.prop.lp = (Byte)lp; + return LZMA2_STATE_DATA; + } + + default: + return LZMA2_STATE_ERROR; + } +} + +static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size) +{ + memcpy(p->dic + p->dicPos, src, size); + p->dicPos += size; + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size) + p->checkDicSize = p->prop.dicSize; + p->processedPos += (UInt32)size; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); + + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->state != LZMA2_STATE_ERROR) + { + SizeT dicPos; + + if (p->state == LZMA2_STATE_FINISHED) + { + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + + dicPos = p->decoder.dicPos; + + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->state = Lzma2Dec_UpdateState(p, *src++); + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + break; + continue; + } + + { + SizeT inCur = inSize - *srcLen; + SizeT outCur = dicLimit - dicPos; + ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY; + + if (outCur >= p->unpackSize) + { + outCur = (SizeT)p->unpackSize; + curFinishMode = LZMA_FINISH_END; + } + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (inCur == 0) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + if (p->state == LZMA2_STATE_DATA) + { + BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC); + LzmaDec_InitDicAndState(&p->decoder, initDic, False); + } + + if (inCur > outCur) + inCur = outCur; + if (inCur == 0) + break; + + LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur); + + src += inCur; + *srcLen += inCur; + p->unpackSize -= (UInt32)inCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + SRes res; + + if (p->state == LZMA2_STATE_DATA) + { + BoolInt initDic = (p->control >= 0xE0); + BoolInt initState = (p->control >= 0xA0); + LzmaDec_InitDicAndState(&p->decoder, initDic, initState); + p->state = LZMA2_STATE_DATA_CONT; + } + + if (inCur > p->packSize) + inCur = (SizeT)p->packSize; + + res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status); + + src += inCur; + *srcLen += inCur; + p->packSize -= (UInt32)inCur; + outCur = p->decoder.dicPos - dicPos; + p->unpackSize -= (UInt32)outCur; + + if (res != 0) + break; + + if (*status == LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->packSize == 0) + break; + return SZ_OK; + } + + if (inCur == 0 && outCur == 0) + { + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + break; + p->state = LZMA2_STATE_CONTROL; + } + + *status = LZMA_STATUS_NOT_SPECIFIED; + } + } + } + + *status = LZMA_STATUS_NOT_SPECIFIED; + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; +} + + + + +ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, + SizeT outSize, + const Byte *src, SizeT *srcLen, + int checkFinishBlock) +{ + SizeT inSize = *srcLen; + *srcLen = 0; + + while (p->state != LZMA2_STATE_ERROR) + { + if (p->state == LZMA2_STATE_FINISHED) + return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK; + + if (outSize == 0 && !checkFinishBlock) + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) + { + if (*srcLen == inSize) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + (*srcLen)++; + + p->state = Lzma2Dec_UpdateState(p, *src++); + + if (p->state == LZMA2_STATE_UNPACK0) + { + // if (p->decoder.dicPos != 0) + if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0) + return LZMA2_PARSE_STATUS_NEW_BLOCK; + // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED; + } + + // The following code can be commented. + // It's not big problem, if we read additional input bytes. + // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state. + + if (outSize == 0 && p->state != LZMA2_STATE_FINISHED) + { + // checkFinishBlock is true. So we expect that block must be finished, + // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here + // break; + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + } + + if (p->state == LZMA2_STATE_DATA) + return LZMA2_PARSE_STATUS_NEW_CHUNK; + + continue; + } + + if (outSize == 0) + return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED; + + { + SizeT inCur = inSize - *srcLen; + + if (LZMA2_IS_UNCOMPRESSED_STATE(p)) + { + if (inCur == 0) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + if (inCur > p->unpackSize) + inCur = p->unpackSize; + if (inCur > outSize) + inCur = outSize; + p->decoder.dicPos += inCur; + src += inCur; + *srcLen += inCur; + outSize -= inCur; + p->unpackSize -= (UInt32)inCur; + p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT; + } + else + { + p->isExtraMode = True; + + if (inCur == 0) + { + if (p->packSize != 0) + return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT; + } + else if (p->state == LZMA2_STATE_DATA) + { + p->state = LZMA2_STATE_DATA_CONT; + if (*src != 0) + { + // first byte of lzma chunk must be Zero + *srcLen += 1; + p->packSize--; + break; + } + } + + if (inCur > p->packSize) + inCur = (SizeT)p->packSize; + + src += inCur; + *srcLen += inCur; + p->packSize -= (UInt32)inCur; + + if (p->packSize == 0) + { + SizeT rem = outSize; + if (rem > p->unpackSize) + rem = p->unpackSize; + p->decoder.dicPos += rem; + p->unpackSize -= (UInt32)rem; + outSize -= rem; + if (p->unpackSize == 0) + p->state = LZMA2_STATE_CONTROL; + } + } + } + } + + p->state = LZMA2_STATE_ERROR; + return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; +} + + + + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen, inSize = *srcLen; + *srcLen = *destLen = 0; + + for (;;) + { + SizeT inCur = inSize, outCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + + if (p->decoder.dicPos == p->decoder.dicBufSize) + p->decoder.dicPos = 0; + dicPos = p->decoder.dicPos; + curFinishMode = LZMA_FINISH_ANY; + outCur = p->decoder.dicBufSize - dicPos; + + if (outCur >= outSize) + { + outCur = outSize; + curFinishMode = finishMode; + } + + res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status); + + src += inCur; + inSize -= inCur; + *srcLen += inCur; + outCur = p->decoder.dicPos - dicPos; + memcpy(dest, p->decoder.dic + dicPos, outCur); + dest += outCur; + outSize -= outCur; + *destLen += outCur; + if (res != 0) + return res; + if (outCur == 0 || outSize == 0) + return SZ_OK; + } +} + + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc) +{ + CLzma2Dec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + Lzma2Dec_CONSTRUCT(&p) + RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc)) + p.decoder.dic = dest; + p.decoder.dicBufSize = outSize; + Lzma2Dec_Init(&p); + *srcLen = inSize; + res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.decoder.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + Lzma2Dec_FreeProbs(&p, alloc); + return res; +} + +#undef PRF diff --git a/C/Lzma2Dec.h b/C/Lzma2Dec.h index 9b15ab04a..1f5233a72 100644 --- a/C/Lzma2Dec.h +++ b/C/Lzma2Dec.h @@ -1,121 +1,121 @@ -/* Lzma2Dec.h -- LZMA2 Decoder -2023-03-03 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA2_DEC_H -#define ZIP7_INC_LZMA2_DEC_H - -#include "LzmaDec.h" - -EXTERN_C_BEGIN - -/* ---------- State Interface ---------- */ - -typedef struct -{ - unsigned state; - Byte control; - Byte needInitLevel; - Byte isExtraMode; - Byte _pad_; - UInt32 packSize; - UInt32 unpackSize; - CLzmaDec decoder; -} CLzma2Dec; - -#define Lzma2Dec_CONSTRUCT(p) LzmaDec_CONSTRUCT(&(p)->decoder) -#define Lzma2Dec_Construct(p) Lzma2Dec_CONSTRUCT(p) -#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) -#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) - -SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); -SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); -void Lzma2Dec_Init(CLzma2Dec *p); - -/* -finishMode: - It has meaning only if the decoding reaches output limit (*destLen or dicLimit). - LZMA_FINISH_ANY - use smallest number of input bytes - LZMA_FINISH_END - read EndOfStream marker after decoding - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_NEEDS_MORE_INPUT - SZ_ERROR_DATA - Data error -*/ - -SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - -SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- LZMA2 block and chunk parsing ---------- */ - -/* -Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data. -It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code: - - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input. - - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read. - CLzma2Dec::unpackSize contains unpack size of that chunk -*/ - -typedef enum -{ -/* - LZMA_STATUS_NOT_SPECIFIED // data error - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED // - LZMA_STATUS_NEEDS_MORE_INPUT - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused -*/ - LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1, - LZMA2_PARSE_STATUS_NEW_CHUNK -} ELzma2ParseStatus; - -ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, - SizeT outSize, // output size - const Byte *src, SizeT *srcLen, - int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position. - ); - -/* -LZMA2 parser doesn't decode LZMA chunks, so we must read - full input LZMA chunk to decode some part of LZMA chunk. - -Lzma2Dec_GetUnpackExtra() returns the value that shows - max possible number of output bytes that can be output by decoder - at current input positon. -*/ - -#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0) - - -/* ---------- One Call Interface ---------- */ - -/* -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - use smallest number of input bytes - LZMA_FINISH_END - read EndOfStream marker after decoding - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). -*/ - -SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc); - -EXTERN_C_END - -#endif +/* Lzma2Dec.h -- LZMA2 Decoder +2023-03-03 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA2_DEC_H +#define ZIP7_INC_LZMA2_DEC_H + +#include "LzmaDec.h" + +EXTERN_C_BEGIN + +/* ---------- State Interface ---------- */ + +typedef struct +{ + unsigned state; + Byte control; + Byte needInitLevel; + Byte isExtraMode; + Byte _pad_; + UInt32 packSize; + UInt32 unpackSize; + CLzmaDec decoder; +} CLzma2Dec; + +#define Lzma2Dec_CONSTRUCT(p) LzmaDec_CONSTRUCT(&(p)->decoder) +#define Lzma2Dec_Construct(p) Lzma2Dec_CONSTRUCT(p) +#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc) +#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc) + +SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); +SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc); +void Lzma2Dec_Init(CLzma2Dec *p); + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen or dicLimit). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + SZ_ERROR_DATA - Data error +*/ + +SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + +SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- LZMA2 block and chunk parsing ---------- */ + +/* +Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data. +It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code: + - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input. + - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read. + CLzma2Dec::unpackSize contains unpack size of that chunk +*/ + +typedef enum +{ +/* + LZMA_STATUS_NOT_SPECIFIED // data error + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED // + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused +*/ + LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1, + LZMA2_PARSE_STATUS_NEW_CHUNK +} ELzma2ParseStatus; + +ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p, + SizeT outSize, // output size + const Byte *src, SizeT *srcLen, + int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position. + ); + +/* +LZMA2 parser doesn't decode LZMA chunks, so we must read + full input LZMA chunk to decode some part of LZMA chunk. + +Lzma2Dec_GetUnpackExtra() returns the value that shows + max possible number of output bytes that can be output by decoder + at current input positon. +*/ + +#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0) + + +/* ---------- One Call Interface ---------- */ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - use smallest number of input bytes + LZMA_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/C/Lzma2DecMt.c b/C/Lzma2DecMt.c index e1038a125..4bc4ddeb5 100644 --- a/C/Lzma2DecMt.c +++ b/C/Lzma2DecMt.c @@ -1,1095 +1,1095 @@ -/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread -2023-04-13 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #define SHOW_DEBUG_INFO -// #define Z7_ST - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "Alloc.h" - -#include "Lzma2Dec.h" -#include "Lzma2DecMt.h" - -#ifndef Z7_ST -#include "MtDec.h" - -#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) -#endif - - -#ifndef Z7_ST -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif -#define PRF_STR(s) PRF(printf("\n" s "\n");) -#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2);) -#endif - - -void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) -{ - p->inBufSize_ST = 1 << 20; - p->outStep_ST = 1 << 20; - - #ifndef Z7_ST - p->numThreads = 1; - p->inBufSize_MT = 1 << 18; - p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; - p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; - #endif -} - - - -#ifndef Z7_ST - -/* ---------- CLzma2DecMtThread ---------- */ - -typedef struct -{ - CLzma2Dec dec; - Byte dec_created; - Byte needInit; - - Byte *outBuf; - size_t outBufSize; - - EMtDecParseState state; - ELzma2ParseStatus parseStatus; - - size_t inPreSize; - size_t outPreSize; - - size_t inCodeSize; - size_t outCodeSize; - SRes codeRes; - - CAlignOffsetAlloc alloc; - - Byte mtPad[1 << 7]; -} CLzma2DecMtThread; - -#endif - - -/* ---------- CLzma2DecMt ---------- */ - -struct CLzma2DecMt -{ - // ISzAllocPtr alloc; - ISzAllocPtr allocMid; - - CAlignOffsetAlloc alignOffsetAlloc; - CLzma2DecMtProps props; - Byte prop; - - ISeqInStreamPtr inStream; - ISeqOutStreamPtr outStream; - ICompressProgressPtr progress; - - BoolInt finishMode; - BoolInt outSize_Defined; - UInt64 outSize; - - UInt64 outProcessed; - UInt64 inProcessed; - BoolInt readWasFinished; - SRes readRes; - - Byte *inBuf; - size_t inBufSize; - Byte dec_created; - CLzma2Dec dec; - - size_t inPos; - size_t inLim; - - #ifndef Z7_ST - UInt64 outProcessed_Parse; - BoolInt mtc_WasConstructed; - CMtDec mtc; - CLzma2DecMtThread coders[MTDEC_THREADS_MAX]; - #endif -}; - - - -CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) -{ - CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); - if (!p) - return NULL; - - // p->alloc = alloc; - p->allocMid = allocMid; - - AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); - p->alignOffsetAlloc.numAlignBits = 7; - p->alignOffsetAlloc.offset = 0; - p->alignOffsetAlloc.baseAlloc = alloc; - - p->inBuf = NULL; - p->inBufSize = 0; - p->dec_created = False; - - // Lzma2DecMtProps_Init(&p->props); - - #ifndef Z7_ST - p->mtc_WasConstructed = False; - { - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CLzma2DecMtThread *t = &p->coders[i]; - t->dec_created = False; - t->outBuf = NULL; - t->outBufSize = 0; - } - } - #endif - - return (CLzma2DecMtHandle)(void *)p; -} - - -#ifndef Z7_ST - -static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) -{ - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CLzma2DecMtThread *t = &p->coders[i]; - if (t->outBuf) - { - ISzAlloc_Free(p->allocMid, t->outBuf); - t->outBuf = NULL; - t->outBufSize = 0; - } - } -} - -#endif - - -static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) -{ - if (p->dec_created) - { - Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); - p->dec_created = False; - } - if (p->inBuf) - { - ISzAlloc_Free(p->allocMid, p->inBuf); - p->inBuf = NULL; - } - p->inBufSize = 0; -} - - -// #define GET_CLzma2DecMt_p CLzma2DecMt *p = (CLzma2DecMt *)(void *)pp; - -void Lzma2DecMt_Destroy(CLzma2DecMtHandle p) -{ - // GET_CLzma2DecMt_p - - Lzma2DecMt_FreeSt(p); - - #ifndef Z7_ST - - if (p->mtc_WasConstructed) - { - MtDec_Destruct(&p->mtc); - p->mtc_WasConstructed = False; - } - { - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CLzma2DecMtThread *t = &p->coders[i]; - if (t->dec_created) - { - // we don't need to free dict here - Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! - t->dec_created = False; - } - } - } - Lzma2DecMt_FreeOutBufs(p); - - #endif - - ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p); -} - - - -#ifndef Z7_ST - -static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) -{ - CLzma2DecMt *me = (CLzma2DecMt *)obj; - CLzma2DecMtThread *t = &me->coders[coderIndex]; - - PRF_STR_INT_2("Parse", coderIndex, cc->srcSize) - - cc->state = MTDEC_PARSE_CONTINUE; - - if (cc->startCall) - { - if (!t->dec_created) - { - Lzma2Dec_CONSTRUCT(&t->dec) - t->dec_created = True; - AlignOffsetAlloc_CreateVTable(&t->alloc); - { - /* (1 << 12) is expected size of one way in data cache. - We optimize alignment for cache line size of 128 bytes and smaller */ - const unsigned kNumAlignBits = 12; - const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ - t->alloc.numAlignBits = kNumAlignBits; - t->alloc.offset = ((UInt32)coderIndex * (((unsigned)1 << 11) + (1 << 8) + (1 << 6))) & (((unsigned)1 << kNumAlignBits) - ((unsigned)1 << kNumCacheLineBits)); - t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; - } - } - Lzma2Dec_Init(&t->dec); - - t->inPreSize = 0; - t->outPreSize = 0; - // t->blockWasFinished = False; - // t->finishedWithMark = False; - t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; - t->state = MTDEC_PARSE_CONTINUE; - - t->inCodeSize = 0; - t->outCodeSize = 0; - t->codeRes = SZ_OK; - - // (cc->srcSize == 0) is allowed - } - - { - ELzma2ParseStatus status; - BoolInt overflow; - UInt32 unpackRem = 0; - - int checkFinishBlock = True; - size_t limit = me->props.outBlockMax; - if (me->outSize_Defined) - { - UInt64 rem = me->outSize - me->outProcessed_Parse; - if (limit >= rem) - { - limit = (size_t)rem; - if (!me->finishMode) - checkFinishBlock = False; - } - } - - // checkFinishBlock = False, if we want to decode partial data - // that must be finished at position <= outBlockMax. - - { - const size_t srcOrig = cc->srcSize; - SizeT srcSize_Point = 0; - SizeT dicPos_Point = 0; - - cc->srcSize = 0; - overflow = False; - - for (;;) - { - SizeT srcCur = (SizeT)(srcOrig - cc->srcSize); - - status = Lzma2Dec_Parse(&t->dec, - (SizeT)limit - t->dec.decoder.dicPos, - cc->src + cc->srcSize, &srcCur, - checkFinishBlock); - - cc->srcSize += srcCur; - - if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) - { - if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) - { - overflow = True; - break; - } - continue; - } - - if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) - { - if (t->dec.decoder.dicPos == 0) - continue; - // we decode small blocks in one thread - if (t->dec.decoder.dicPos >= (1 << 14)) - break; - dicPos_Point = t->dec.decoder.dicPos; - srcSize_Point = (SizeT)cc->srcSize; - continue; - } - - if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock - // && limit == t->dec.decoder.dicPos - // && limit == me->props.outBlockMax - ) - { - overflow = True; - break; - } - - unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); - break; - } - - if (dicPos_Point != 0 - && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK - && (int)status != LZMA_STATUS_FINISHED_WITH_MARK - && (int)status != LZMA_STATUS_NOT_SPECIFIED) - { - // we revert to latest newBlock state - status = LZMA2_PARSE_STATUS_NEW_BLOCK; - unpackRem = 0; - t->dec.decoder.dicPos = dicPos_Point; - cc->srcSize = srcSize_Point; - overflow = False; - } - } - - t->inPreSize += cc->srcSize; - t->parseStatus = status; - - if (overflow) - cc->state = MTDEC_PARSE_OVERFLOW; - else - { - size_t dicPos = t->dec.decoder.dicPos; - - if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) - { - if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) - { - cc->state = MTDEC_PARSE_NEW; - cc->srcSize--; // we don't need control byte of next block - t->inPreSize--; - } - else - { - cc->state = MTDEC_PARSE_END; - if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) - { - // (status == LZMA_STATUS_NOT_SPECIFIED) - // (status == LZMA_STATUS_NOT_FINISHED) - if (unpackRem != 0) - { - /* we also reserve space for max possible number of output bytes of current LZMA chunk */ - size_t rem = limit - dicPos; - if (rem > unpackRem) - rem = unpackRem; - dicPos += rem; - } - } - } - - me->outProcessed_Parse += dicPos; - } - - cc->outPos = dicPos; - t->outPreSize = (size_t)dicPos; - } - - t->state = cc->state; - return; - } -} - - -static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) -{ - CLzma2DecMt *me = (CLzma2DecMt *)pp; - CLzma2DecMtThread *t = &me->coders[coderIndex]; - Byte *dest = t->outBuf; - - if (t->inPreSize == 0) - { - t->codeRes = SZ_ERROR_DATA; - return t->codeRes; - } - - if (!dest || t->outBufSize < t->outPreSize) - { - if (dest) - { - ISzAlloc_Free(me->allocMid, dest); - t->outBuf = NULL; - t->outBufSize = 0; - } - - dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize - // + (1 << 28) - ); - // Sleep(200); - if (!dest) - return SZ_ERROR_MEM; - t->outBuf = dest; - t->outBufSize = t->outPreSize; - } - - t->dec.decoder.dic = dest; - t->dec.decoder.dicBufSize = (SizeT)t->outPreSize; - - t->needInit = True; - - return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt -} - - -static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, - const Byte *src, size_t srcSize, int srcFinished, - // int finished, int blockFinished, - UInt64 *inCodePos, UInt64 *outCodePos, int *stop) -{ - CLzma2DecMt *me = (CLzma2DecMt *)pp; - CLzma2DecMtThread *t = &me->coders[coderIndex]; - - UNUSED_VAR(srcFinished) - - PRF_STR_INT_2("Code", coderIndex, srcSize) - - *inCodePos = t->inCodeSize; - *outCodePos = 0; - *stop = True; - - if (t->needInit) - { - Lzma2Dec_Init(&t->dec); - t->needInit = False; - } - - { - ELzmaStatus status; - SizeT srcProcessed = (SizeT)srcSize; - BoolInt blockWasFinished = - ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK - || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); - - SRes res = Lzma2Dec_DecodeToDic(&t->dec, - (SizeT)t->outPreSize, - src, &srcProcessed, - blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, - &status); - - t->codeRes = res; - - t->inCodeSize += srcProcessed; - *inCodePos = t->inCodeSize; - t->outCodeSize = t->dec.decoder.dicPos; - *outCodePos = t->dec.decoder.dicPos; - - if (res != SZ_OK) - return res; - - if (srcProcessed == srcSize) - *stop = False; - - if (blockWasFinished) - { - if (srcSize != srcProcessed) - return SZ_ERROR_FAIL; - - if (t->inPreSize == t->inCodeSize) - { - if (t->outPreSize != t->outCodeSize) - return SZ_ERROR_FAIL; - *stop = True; - } - } - else - { - if (t->outPreSize == t->outCodeSize) - *stop = True; - } - - return SZ_OK; - } -} - - -#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) - -static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, - BoolInt needWriteToStream, - const Byte *src, size_t srcSize, BoolInt isCross, - BoolInt *needContinue, BoolInt *canRecode) -{ - CLzma2DecMt *me = (CLzma2DecMt *)pp; - const CLzma2DecMtThread *t = &me->coders[coderIndex]; - size_t size = t->outCodeSize; - const Byte *data = t->outBuf; - BoolInt needContinue2 = True; - - UNUSED_VAR(src) - UNUSED_VAR(srcSize) - UNUSED_VAR(isCross) - - PRF_STR_INT_2("Write", coderIndex, srcSize) - - *needContinue = False; - *canRecode = True; - - if ( - // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK - t->state == MTDEC_PARSE_OVERFLOW - || t->state == MTDEC_PARSE_END) - needContinue2 = False; - - - if (!needWriteToStream) - return SZ_OK; - - me->mtc.inProcessed += t->inCodeSize; - - if (t->codeRes == SZ_OK) - if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK - || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) - if (t->outPreSize != t->outCodeSize - || t->inPreSize != t->inCodeSize) - return SZ_ERROR_FAIL; - - *canRecode = False; - - if (me->outStream) - { - for (;;) - { - size_t cur = size; - size_t written; - if (cur > LZMA2DECMT_STREAM_WRITE_STEP) - cur = LZMA2DECMT_STREAM_WRITE_STEP; - - written = ISeqOutStream_Write(me->outStream, data, cur); - - me->outProcessed += written; - // me->mtc.writtenTotal += written; - if (written != cur) - return SZ_ERROR_WRITE; - data += cur; - size -= cur; - if (size == 0) - { - *needContinue = needContinue2; - return SZ_OK; - } - RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)) - } - } - - return SZ_ERROR_FAIL; - /* - if (size > me->outBufSize) - return SZ_ERROR_OUTPUT_EOF; - memcpy(me->outBuf, data, size); - me->outBufSize -= size; - me->outBuf += size; - *needContinue = needContinue2; - return SZ_OK; - */ -} - -#endif - - -static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) -{ - if (!p->dec_created) - { - Lzma2Dec_CONSTRUCT(&p->dec) - p->dec_created = True; - } - - RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)) - - if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) - { - ISzAlloc_Free(p->allocMid, p->inBuf); - p->inBufSize = 0; - p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); - if (!p->inBuf) - return SZ_ERROR_MEM; - p->inBufSize = p->props.inBufSize_ST; - } - - Lzma2Dec_Init(&p->dec); - - return SZ_OK; -} - - -static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p - #ifndef Z7_ST - , BoolInt tMode - #endif - ) -{ - SizeT wrPos; - size_t inPos, inLim; - const Byte *inData; - UInt64 inPrev, outPrev; - - CLzma2Dec *dec; - - #ifndef Z7_ST - if (tMode) - { - Lzma2DecMt_FreeOutBufs(p); - tMode = MtDec_PrepareRead(&p->mtc); - } - #endif - - RINOK(Lzma2Dec_Prepare_ST(p)) - - dec = &p->dec; - - inPrev = p->inProcessed; - outPrev = p->outProcessed; - - inPos = 0; - inLim = 0; - inData = NULL; - wrPos = dec->decoder.dicPos; - - for (;;) - { - SizeT dicPos; - SizeT size; - ELzmaFinishMode finishMode; - SizeT inProcessed; - ELzmaStatus status; - SRes res; - - SizeT outProcessed; - BoolInt outFinished; - BoolInt needStop; - - if (inPos == inLim) - { - #ifndef Z7_ST - if (tMode) - { - inData = MtDec_Read(&p->mtc, &inLim); - inPos = 0; - if (inData) - continue; - tMode = False; - inLim = 0; - } - #endif - - if (!p->readWasFinished) - { - inPos = 0; - inLim = p->inBufSize; - inData = p->inBuf; - p->readRes = ISeqInStream_Read(p->inStream, (void *)(p->inBuf), &inLim); - // p->readProcessed += inLim; - // inLim -= 5; p->readWasFinished = True; // for test - if (inLim == 0 || p->readRes != SZ_OK) - p->readWasFinished = True; - } - } - - dicPos = dec->decoder.dicPos; - { - SizeT next = dec->decoder.dicBufSize; - if (next - wrPos > p->props.outStep_ST) - next = wrPos + (SizeT)p->props.outStep_ST; - size = next - dicPos; - } - - finishMode = LZMA_FINISH_ANY; - if (p->outSize_Defined) - { - const UInt64 rem = p->outSize - p->outProcessed; - if (size >= rem) - { - size = (SizeT)rem; - if (p->finishMode) - finishMode = LZMA_FINISH_END; - } - } - - inProcessed = (SizeT)(inLim - inPos); - - res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); - - inPos += inProcessed; - p->inProcessed += inProcessed; - outProcessed = dec->decoder.dicPos - dicPos; - p->outProcessed += outProcessed; - - outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); - - needStop = (res != SZ_OK - || (inProcessed == 0 && outProcessed == 0) - || status == LZMA_STATUS_FINISHED_WITH_MARK - || (!p->finishMode && outFinished)); - - if (needStop || outProcessed >= size) - { - SRes res2; - { - size_t writeSize = dec->decoder.dicPos - wrPos; - size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); - res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; - } - - if (dec->decoder.dicPos == dec->decoder.dicBufSize) - dec->decoder.dicPos = 0; - wrPos = dec->decoder.dicPos; - - RINOK(res2) - - if (needStop) - { - if (res != SZ_OK) - return res; - - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - { - if (p->finishMode) - { - if (p->outSize_Defined && p->outSize != p->outProcessed) - return SZ_ERROR_DATA; - } - return SZ_OK; - } - - if (!p->finishMode && outFinished) - return SZ_OK; - - if (status == LZMA_STATUS_NEEDS_MORE_INPUT) - return SZ_ERROR_INPUT_EOF; - - return SZ_ERROR_DATA; - } - } - - if (p->progress) - { - UInt64 inDelta = p->inProcessed - inPrev; - UInt64 outDelta = p->outProcessed - outPrev; - if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) - { - RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)) - inPrev = p->inProcessed; - outPrev = p->outProcessed; - } - } - } -} - - - -SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, - Byte prop, - const CLzma2DecMtProps *props, - ISeqOutStreamPtr outStream, const UInt64 *outDataSize, int finishMode, - // Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - // const Byte *inData, size_t inDataSize, - UInt64 *inProcessed, - // UInt64 *outProcessed, - int *isMT, - ICompressProgressPtr progress) -{ - // GET_CLzma2DecMt_p - #ifndef Z7_ST - BoolInt tMode; - #endif - - *inProcessed = 0; - - if (prop > 40) - return SZ_ERROR_UNSUPPORTED; - - p->prop = prop; - p->props = *props; - - p->inStream = inStream; - p->outStream = outStream; - p->progress = progress; - - p->outSize = 0; - p->outSize_Defined = False; - if (outDataSize) - { - p->outSize_Defined = True; - p->outSize = *outDataSize; - } - p->finishMode = finishMode; - - p->outProcessed = 0; - p->inProcessed = 0; - - p->readWasFinished = False; - p->readRes = SZ_OK; - - *isMT = False; - - - #ifndef Z7_ST - - tMode = False; - - // p->mtc.parseRes = SZ_OK; - - // p->mtc.numFilledThreads = 0; - // p->mtc.crossStart = 0; - // p->mtc.crossEnd = 0; - // p->mtc.allocError_for_Read_BlockIndex = 0; - // p->mtc.isAllocError = False; - - if (p->props.numThreads > 1) - { - IMtDecCallback2 vt; - - Lzma2DecMt_FreeSt(p); - - p->outProcessed_Parse = 0; - - if (!p->mtc_WasConstructed) - { - p->mtc_WasConstructed = True; - MtDec_Construct(&p->mtc); - } - - p->mtc.progress = progress; - p->mtc.inStream = inStream; - - // p->outBuf = NULL; - // p->outBufSize = 0; - /* - if (!outStream) - { - // p->outBuf = outBuf; - // p->outBufSize = *outBufSize; - // *outBufSize = 0; - return SZ_ERROR_PARAM; - } - */ - - // p->mtc.inBlockMax = p->props.inBlockMax; - p->mtc.alloc = &p->alignOffsetAlloc.vt; - // p->alignOffsetAlloc.baseAlloc; - // p->mtc.inData = inData; - // p->mtc.inDataSize = inDataSize; - p->mtc.mtCallback = &vt; - p->mtc.mtCallbackObject = p; - - p->mtc.inBufSize = p->props.inBufSize_MT; - - p->mtc.numThreadsMax = p->props.numThreads; - - *isMT = True; - - vt.Parse = Lzma2DecMt_MtCallback_Parse; - vt.PreCode = Lzma2DecMt_MtCallback_PreCode; - vt.Code = Lzma2DecMt_MtCallback_Code; - vt.Write = Lzma2DecMt_MtCallback_Write; - - { - BoolInt needContinue = False; - - SRes res = MtDec_Code(&p->mtc); - - /* - if (!outStream) - *outBufSize = p->outBuf - outBuf; - */ - - *inProcessed = p->mtc.inProcessed; - - needContinue = False; - - if (res == SZ_OK) - { - if (p->mtc.mtProgress.res != SZ_OK) - res = p->mtc.mtProgress.res; - else - needContinue = p->mtc.needContinue; - } - - if (!needContinue) - { - if (res == SZ_OK) - return p->mtc.readRes; - return res; - } - - tMode = True; - p->readRes = p->mtc.readRes; - p->readWasFinished = p->mtc.readWasFinished; - p->inProcessed = p->mtc.inProcessed; - - PRF_STR("----- decoding ST -----") - } - } - - #endif - - - *isMT = False; - - { - SRes res = Lzma2Dec_Decode_ST(p - #ifndef Z7_ST - , tMode - #endif - ); - - *inProcessed = p->inProcessed; - - // res = SZ_OK; // for test - if (res == SZ_ERROR_INPUT_EOF) - { - if (p->readRes != SZ_OK) - res = p->readRes; - } - else if (res == SZ_OK && p->readRes != SZ_OK) - res = p->readRes; - - /* - #ifndef Z7_ST - if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) - res = p->mtc.parseRes; - #endif - */ - - return res; - } -} - - -/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ - -SRes Lzma2DecMt_Init(CLzma2DecMtHandle p, - Byte prop, - const CLzma2DecMtProps *props, - const UInt64 *outDataSize, int finishMode, - ISeqInStreamPtr inStream) -{ - // GET_CLzma2DecMt_p - - if (prop > 40) - return SZ_ERROR_UNSUPPORTED; - - p->prop = prop; - p->props = *props; - - p->inStream = inStream; - - p->outSize = 0; - p->outSize_Defined = False; - if (outDataSize) - { - p->outSize_Defined = True; - p->outSize = *outDataSize; - } - p->finishMode = finishMode; - - p->outProcessed = 0; - p->inProcessed = 0; - - p->inPos = 0; - p->inLim = 0; - - return Lzma2Dec_Prepare_ST(p); -} - - -SRes Lzma2DecMt_Read(CLzma2DecMtHandle p, - Byte *data, size_t *outSize, - UInt64 *inStreamProcessed) -{ - // GET_CLzma2DecMt_p - ELzmaFinishMode finishMode; - SRes readRes; - size_t size = *outSize; - - *outSize = 0; - *inStreamProcessed = 0; - - finishMode = LZMA_FINISH_ANY; - if (p->outSize_Defined) - { - const UInt64 rem = p->outSize - p->outProcessed; - if (size >= rem) - { - size = (size_t)rem; - if (p->finishMode) - finishMode = LZMA_FINISH_END; - } - } - - readRes = SZ_OK; - - for (;;) - { - SizeT inCur; - SizeT outCur; - ELzmaStatus status; - SRes res; - - if (p->inPos == p->inLim && readRes == SZ_OK) - { - p->inPos = 0; - p->inLim = p->props.inBufSize_ST; - readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); - } - - inCur = (SizeT)(p->inLim - p->inPos); - outCur = (SizeT)size; - - res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, - p->inBuf + p->inPos, &inCur, finishMode, &status); - - p->inPos += inCur; - p->inProcessed += inCur; - *inStreamProcessed += inCur; - p->outProcessed += outCur; - *outSize += outCur; - size -= outCur; - data += outCur; - - if (res != 0) - return res; - - /* - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - return readRes; - - if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) - { - if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) - return SZ_ERROR_DATA; - return readRes; - } - */ - - if (inCur == 0 && outCur == 0) - return readRes; - } -} - -#undef PRF -#undef PRF_STR -#undef PRF_STR_INT_2 +/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO +// #define Z7_ST + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "Alloc.h" + +#include "Lzma2Dec.h" +#include "Lzma2DecMt.h" + +#ifndef Z7_ST +#include "MtDec.h" + +#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28) +#endif + + +#ifndef Z7_ST +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif +#define PRF_STR(s) PRF(printf("\n" s "\n");) +#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2);) +#endif + + +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p) +{ + p->inBufSize_ST = 1 << 20; + p->outStep_ST = 1 << 20; + + #ifndef Z7_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT; + p->inBlockMax = p->outBlockMax + p->outBlockMax / 16; + #endif +} + + + +#ifndef Z7_ST + +/* ---------- CLzma2DecMtThread ---------- */ + +typedef struct +{ + CLzma2Dec dec; + Byte dec_created; + Byte needInit; + + Byte *outBuf; + size_t outBufSize; + + EMtDecParseState state; + ELzma2ParseStatus parseStatus; + + size_t inPreSize; + size_t outPreSize; + + size_t inCodeSize; + size_t outCodeSize; + SRes codeRes; + + CAlignOffsetAlloc alloc; + + Byte mtPad[1 << 7]; +} CLzma2DecMtThread; + +#endif + + +/* ---------- CLzma2DecMt ---------- */ + +struct CLzma2DecMt +{ + // ISzAllocPtr alloc; + ISzAllocPtr allocMid; + + CAlignOffsetAlloc alignOffsetAlloc; + CLzma2DecMtProps props; + Byte prop; + + ISeqInStreamPtr inStream; + ISeqOutStreamPtr outStream; + ICompressProgressPtr progress; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + BoolInt readWasFinished; + SRes readRes; + + Byte *inBuf; + size_t inBufSize; + Byte dec_created; + CLzma2Dec dec; + + size_t inPos; + size_t inLim; + + #ifndef Z7_ST + UInt64 outProcessed_Parse; + BoolInt mtc_WasConstructed; + CMtDec mtc; + CLzma2DecMtThread coders[MTDEC_THREADS_MAX]; + #endif +}; + + + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt)); + if (!p) + return NULL; + + // p->alloc = alloc; + p->allocMid = allocMid; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + p->alignOffsetAlloc.baseAlloc = alloc; + + p->inBuf = NULL; + p->inBufSize = 0; + p->dec_created = False; + + // Lzma2DecMtProps_Init(&p->props); + + #ifndef Z7_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + t->dec_created = False; + t->outBuf = NULL; + t->outBufSize = 0; + } + } + #endif + + return (CLzma2DecMtHandle)(void *)p; +} + + +#ifndef Z7_ST + +static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->outBuf) + { + ISzAlloc_Free(p->allocMid, t->outBuf); + t->outBuf = NULL; + t->outBufSize = 0; + } + } +} + +#endif + + +static void Lzma2DecMt_FreeSt(CLzma2DecMt *p) +{ + if (p->dec_created) + { + Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt); + p->dec_created = False; + } + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +// #define GET_CLzma2DecMt_p CLzma2DecMt *p = (CLzma2DecMt *)(void *)pp; + +void Lzma2DecMt_Destroy(CLzma2DecMtHandle p) +{ + // GET_CLzma2DecMt_p + + Lzma2DecMt_FreeSt(p); + + #ifndef Z7_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CLzma2DecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!! + t->dec_created = False; + } + } + } + Lzma2DecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p); +} + + + +#ifndef Z7_ST + +static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CLzma2DecMt *me = (CLzma2DecMt *)obj; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + PRF_STR_INT_2("Parse", coderIndex, cc->srcSize) + + cc->state = MTDEC_PARSE_CONTINUE; + + if (cc->startCall) + { + if (!t->dec_created) + { + Lzma2Dec_CONSTRUCT(&t->dec) + t->dec_created = True; + AlignOffsetAlloc_CreateVTable(&t->alloc); + { + /* (1 << 12) is expected size of one way in data cache. + We optimize alignment for cache line size of 128 bytes and smaller */ + const unsigned kNumAlignBits = 12; + const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */ + t->alloc.numAlignBits = kNumAlignBits; + t->alloc.offset = ((UInt32)coderIndex * (((unsigned)1 << 11) + (1 << 8) + (1 << 6))) & (((unsigned)1 << kNumAlignBits) - ((unsigned)1 << kNumCacheLineBits)); + t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc; + } + } + Lzma2Dec_Init(&t->dec); + + t->inPreSize = 0; + t->outPreSize = 0; + // t->blockWasFinished = False; + // t->finishedWithMark = False; + t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED; + t->state = MTDEC_PARSE_CONTINUE; + + t->inCodeSize = 0; + t->outCodeSize = 0; + t->codeRes = SZ_OK; + + // (cc->srcSize == 0) is allowed + } + + { + ELzma2ParseStatus status; + BoolInt overflow; + UInt32 unpackRem = 0; + + int checkFinishBlock = True; + size_t limit = me->props.outBlockMax; + if (me->outSize_Defined) + { + UInt64 rem = me->outSize - me->outProcessed_Parse; + if (limit >= rem) + { + limit = (size_t)rem; + if (!me->finishMode) + checkFinishBlock = False; + } + } + + // checkFinishBlock = False, if we want to decode partial data + // that must be finished at position <= outBlockMax. + + { + const size_t srcOrig = cc->srcSize; + SizeT srcSize_Point = 0; + SizeT dicPos_Point = 0; + + cc->srcSize = 0; + overflow = False; + + for (;;) + { + SizeT srcCur = (SizeT)(srcOrig - cc->srcSize); + + status = Lzma2Dec_Parse(&t->dec, + (SizeT)limit - t->dec.decoder.dicPos, + cc->src + cc->srcSize, &srcCur, + checkFinishBlock); + + cc->srcSize += srcCur; + + if (status == LZMA2_PARSE_STATUS_NEW_CHUNK) + { + if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos) + { + overflow = True; + break; + } + continue; + } + + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + if (t->dec.decoder.dicPos == 0) + continue; + // we decode small blocks in one thread + if (t->dec.decoder.dicPos >= (1 << 14)) + break; + dicPos_Point = t->dec.decoder.dicPos; + srcSize_Point = (SizeT)cc->srcSize; + continue; + } + + if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock + // && limit == t->dec.decoder.dicPos + // && limit == me->props.outBlockMax + ) + { + overflow = True; + break; + } + + unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec); + break; + } + + if (dicPos_Point != 0 + && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK + && (int)status != LZMA_STATUS_FINISHED_WITH_MARK + && (int)status != LZMA_STATUS_NOT_SPECIFIED) + { + // we revert to latest newBlock state + status = LZMA2_PARSE_STATUS_NEW_BLOCK; + unpackRem = 0; + t->dec.decoder.dicPos = dicPos_Point; + cc->srcSize = srcSize_Point; + overflow = False; + } + } + + t->inPreSize += cc->srcSize; + t->parseStatus = status; + + if (overflow) + cc->state = MTDEC_PARSE_OVERFLOW; + else + { + size_t dicPos = t->dec.decoder.dicPos; + + if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (status == LZMA2_PARSE_STATUS_NEW_BLOCK) + { + cc->state = MTDEC_PARSE_NEW; + cc->srcSize--; // we don't need control byte of next block + t->inPreSize--; + } + else + { + cc->state = MTDEC_PARSE_END; + if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK) + { + // (status == LZMA_STATUS_NOT_SPECIFIED) + // (status == LZMA_STATUS_NOT_FINISHED) + if (unpackRem != 0) + { + /* we also reserve space for max possible number of output bytes of current LZMA chunk */ + size_t rem = limit - dicPos; + if (rem > unpackRem) + rem = unpackRem; + dicPos += rem; + } + } + } + + me->outProcessed_Parse += dicPos; + } + + cc->outPos = dicPos; + t->outPreSize = (size_t)dicPos; + } + + t->state = cc->state; + return; + } +} + + +static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + Byte *dest = t->outBuf; + + if (t->inPreSize == 0) + { + t->codeRes = SZ_ERROR_DATA; + return t->codeRes; + } + + if (!dest || t->outBufSize < t->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + t->outBuf = NULL; + t->outBufSize = 0; + } + + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize + // + (1 << 28) + ); + // Sleep(200); + if (!dest) + return SZ_ERROR_MEM; + t->outBuf = dest; + t->outBufSize = t->outPreSize; + } + + t->dec.decoder.dic = dest; + t->dec.decoder.dicBufSize = (SizeT)t->outPreSize; + + t->needInit = True; + + return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt +} + + +static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + CLzma2DecMtThread *t = &me->coders[coderIndex]; + + UNUSED_VAR(srcFinished) + + PRF_STR_INT_2("Code", coderIndex, srcSize) + + *inCodePos = t->inCodeSize; + *outCodePos = 0; + *stop = True; + + if (t->needInit) + { + Lzma2Dec_Init(&t->dec); + t->needInit = False; + } + + { + ELzmaStatus status; + SizeT srcProcessed = (SizeT)srcSize; + BoolInt blockWasFinished = + ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK); + + SRes res = Lzma2Dec_DecodeToDic(&t->dec, + (SizeT)t->outPreSize, + src, &srcProcessed, + blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY, + &status); + + t->codeRes = res; + + t->inCodeSize += srcProcessed; + *inCodePos = t->inCodeSize; + t->outCodeSize = t->dec.decoder.dicPos; + *outCodePos = t->dec.decoder.dicPos; + + if (res != SZ_OK) + return res; + + if (srcProcessed == srcSize) + *stop = False; + + if (blockWasFinished) + { + if (srcSize != srcProcessed) + return SZ_ERROR_FAIL; + + if (t->inPreSize == t->inCodeSize) + { + if (t->outPreSize != t->outCodeSize) + return SZ_ERROR_FAIL; + *stop = True; + } + } + else + { + if (t->outPreSize == t->outCodeSize) + *stop = True; + } + + return SZ_OK; + } +} + + +#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, BoolInt isCross, + BoolInt *needContinue, BoolInt *canRecode) +{ + CLzma2DecMt *me = (CLzma2DecMt *)pp; + const CLzma2DecMtThread *t = &me->coders[coderIndex]; + size_t size = t->outCodeSize; + const Byte *data = t->outBuf; + BoolInt needContinue2 = True; + + UNUSED_VAR(src) + UNUSED_VAR(srcSize) + UNUSED_VAR(isCross) + + PRF_STR_INT_2("Write", coderIndex, srcSize) + + *needContinue = False; + *canRecode = True; + + if ( + // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + t->state == MTDEC_PARSE_OVERFLOW + || t->state == MTDEC_PARSE_END) + needContinue2 = False; + + + if (!needWriteToStream) + return SZ_OK; + + me->mtc.inProcessed += t->inCodeSize; + + if (t->codeRes == SZ_OK) + if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK + || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK) + if (t->outPreSize != t->outCodeSize + || t->inPreSize != t->inCodeSize) + return SZ_ERROR_FAIL; + + *canRecode = False; + + if (me->outStream) + { + for (;;) + { + size_t cur = size; + size_t written; + if (cur > LZMA2DECMT_STREAM_WRITE_STEP) + cur = LZMA2DECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + me->outProcessed += written; + // me->mtc.writtenTotal += written; + if (written != cur) + return SZ_ERROR_WRITE; + data += cur; + size -= cur; + if (size == 0) + { + *needContinue = needContinue2; + return SZ_OK; + } + RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0)) + } + } + + return SZ_ERROR_FAIL; + /* + if (size > me->outBufSize) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBufSize -= size; + me->outBuf += size; + *needContinue = needContinue2; + return SZ_OK; + */ +} + +#endif + + +static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p) +{ + if (!p->dec_created) + { + Lzma2Dec_CONSTRUCT(&p->dec) + p->dec_created = True; + } + + RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt)) + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + Lzma2Dec_Init(&p->dec); + + return SZ_OK; +} + + +static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p + #ifndef Z7_ST + , BoolInt tMode + #endif + ) +{ + SizeT wrPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CLzma2Dec *dec; + + #ifndef Z7_ST + if (tMode) + { + Lzma2DecMt_FreeOutBufs(p); + tMode = MtDec_PrepareRead(&p->mtc); + } + #endif + + RINOK(Lzma2Dec_Prepare_ST(p)) + + dec = &p->dec; + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + wrPos = dec->decoder.dicPos; + + for (;;) + { + SizeT dicPos; + SizeT size; + ELzmaFinishMode finishMode; + SizeT inProcessed; + ELzmaStatus status; + SRes res; + + SizeT outProcessed; + BoolInt outFinished; + BoolInt needStop; + + if (inPos == inLim) + { + #ifndef Z7_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)(p->inBuf), &inLim); + // p->readProcessed += inLim; + // inLim -= 5; p->readWasFinished = True; // for test + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + dicPos = dec->decoder.dicPos; + { + SizeT next = dec->decoder.dicBufSize; + if (next - wrPos > p->props.outStep_ST) + next = wrPos + (SizeT)p->props.outStep_ST; + size = next - dicPos; + } + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (SizeT)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + inProcessed = (SizeT)(inLim - inPos); + + res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status); + + inPos += inProcessed; + p->inProcessed += inProcessed; + outProcessed = dec->decoder.dicPos - dicPos; + p->outProcessed += outProcessed; + + outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed); + + needStop = (res != SZ_OK + || (inProcessed == 0 && outProcessed == 0) + || status == LZMA_STATUS_FINISHED_WITH_MARK + || (!p->finishMode && outFinished)); + + if (needStop || outProcessed >= size) + { + SRes res2; + { + size_t writeSize = dec->decoder.dicPos - wrPos; + size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize); + res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE; + } + + if (dec->decoder.dicPos == dec->decoder.dicBufSize) + dec->decoder.dicPos = 0; + wrPos = dec->decoder.dicPos; + + RINOK(res2) + + if (needStop) + { + if (res != SZ_OK) + return res; + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (p->finishMode) + { + if (p->outSize_Defined && p->outSize != p->outProcessed) + return SZ_ERROR_DATA; + } + return SZ_OK; + } + + if (!p->finishMode && outFinished) + return SZ_OK; + + if (status == LZMA_STATUS_NEEDS_MORE_INPUT) + return SZ_ERROR_INPUT_EOF; + + return SZ_ERROR_DATA; + } + } + + if (p->progress) + { + UInt64 inDelta = p->inProcessed - inPrev; + UInt64 outDelta = p->outProcessed - outPrev; + if (inDelta >= (1 << 22) || outDelta >= (1 << 22)) + { + RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed)) + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + } +} + + + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStreamPtr outStream, const UInt64 *outDataSize, int finishMode, + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + UInt64 *inProcessed, + // UInt64 *outProcessed, + int *isMT, + ICompressProgressPtr progress) +{ + // GET_CLzma2DecMt_p + #ifndef Z7_ST + BoolInt tMode; + #endif + + *inProcessed = 0; + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->readWasFinished = False; + p->readRes = SZ_OK; + + *isMT = False; + + + #ifndef Z7_ST + + tMode = False; + + // p->mtc.parseRes = SZ_OK; + + // p->mtc.numFilledThreads = 0; + // p->mtc.crossStart = 0; + // p->mtc.crossEnd = 0; + // p->mtc.allocError_for_Read_BlockIndex = 0; + // p->mtc.isAllocError = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback2 vt; + + Lzma2DecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + + // p->outBuf = NULL; + // p->outBufSize = 0; + /* + if (!outStream) + { + // p->outBuf = outBuf; + // p->outBufSize = *outBufSize; + // *outBufSize = 0; + return SZ_ERROR_PARAM; + } + */ + + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->alignOffsetAlloc.baseAlloc; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.inBufSize = p->props.inBufSize_MT; + + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = Lzma2DecMt_MtCallback_Parse; + vt.PreCode = Lzma2DecMt_MtCallback_PreCode; + vt.Code = Lzma2DecMt_MtCallback_Code; + vt.Write = Lzma2DecMt_MtCallback_Write; + + { + BoolInt needContinue = False; + + SRes res = MtDec_Code(&p->mtc); + + /* + if (!outStream) + *outBufSize = p->outBuf - outBuf; + */ + + *inProcessed = p->mtc.inProcessed; + + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + res = p->mtc.mtProgress.res; + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + if (res == SZ_OK) + return p->mtc.readRes; + return res; + } + + tMode = True; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->inProcessed = p->mtc.inProcessed; + + PRF_STR("----- decoding ST -----") + } + } + + #endif + + + *isMT = False; + + { + SRes res = Lzma2Dec_Decode_ST(p + #ifndef Z7_ST + , tMode + #endif + ); + + *inProcessed = p->inProcessed; + + // res = SZ_OK; // for test + if (res == SZ_ERROR_INPUT_EOF) + { + if (p->readRes != SZ_OK) + res = p->readRes; + } + else if (res == SZ_OK && p->readRes != SZ_OK) + res = p->readRes; + + /* + #ifndef Z7_ST + if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK) + res = p->mtc.parseRes; + #endif + */ + + return res; + } +} + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStreamPtr inStream) +{ + // GET_CLzma2DecMt_p + + if (prop > 40) + return SZ_ERROR_UNSUPPORTED; + + p->prop = prop; + p->props = *props; + + p->inStream = inStream; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + p->finishMode = finishMode; + + p->outProcessed = 0; + p->inProcessed = 0; + + p->inPos = 0; + p->inLim = 0; + + return Lzma2Dec_Prepare_ST(p); +} + + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle p, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed) +{ + // GET_CLzma2DecMt_p + ELzmaFinishMode finishMode; + SRes readRes; + size_t size = *outSize; + + *outSize = 0; + *inStreamProcessed = 0; + + finishMode = LZMA_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (size >= rem) + { + size = (size_t)rem; + if (p->finishMode) + finishMode = LZMA_FINISH_END; + } + } + + readRes = SZ_OK; + + for (;;) + { + SizeT inCur; + SizeT outCur; + ELzmaStatus status; + SRes res; + + if (p->inPos == p->inLim && readRes == SZ_OK) + { + p->inPos = 0; + p->inLim = p->props.inBufSize_ST; + readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim); + } + + inCur = (SizeT)(p->inLim - p->inPos); + outCur = (SizeT)size; + + res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur, + p->inBuf + p->inPos, &inCur, finishMode, &status); + + p->inPos += inCur; + p->inProcessed += inCur; + *inStreamProcessed += inCur; + p->outProcessed += outCur; + *outSize += outCur; + size -= outCur; + data += outCur; + + if (res != 0) + return res; + + /* + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + return readRes; + + if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize) + return SZ_ERROR_DATA; + return readRes; + } + */ + + if (inCur == 0 && outCur == 0) + return readRes; + } +} + +#undef PRF +#undef PRF_STR +#undef PRF_STR_INT_2 diff --git a/C/Lzma2DecMt.h b/C/Lzma2DecMt.h index cb7c8f1e5..93a5cd59e 100644 --- a/C/Lzma2DecMt.h +++ b/C/Lzma2DecMt.h @@ -1,81 +1,81 @@ -/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread -2023-04-13 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA2_DEC_MT_H -#define ZIP7_INC_LZMA2_DEC_MT_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -typedef struct -{ - size_t inBufSize_ST; - size_t outStep_ST; - - #ifndef Z7_ST - unsigned numThreads; - size_t inBufSize_MT; - size_t outBlockMax; - size_t inBlockMax; - #endif -} CLzma2DecMtProps; - -/* init to single-thread mode */ -void Lzma2DecMtProps_Init(CLzma2DecMtProps *p); - - -/* ---------- CLzma2DecMtHandle Interface ---------- */ - -/* Lzma2DecMt_ * functions can return the following exit codes: -SRes: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater in props - SZ_ERROR_WRITE - ISeqOutStream write callback error - // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output - SZ_ERROR_PROGRESS - some break from progress callback - SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) -*/ - -typedef struct CLzma2DecMt CLzma2DecMt; -typedef CLzma2DecMt * CLzma2DecMtHandle; -// Z7_DECLARE_HANDLE(CLzma2DecMtHandle) - -CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); -void Lzma2DecMt_Destroy(CLzma2DecMtHandle p); - -SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, - Byte prop, - const CLzma2DecMtProps *props, - ISeqOutStreamPtr outStream, - const UInt64 *outDataSize, // NULL means undefined - int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished - // Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - // const Byte *inData, size_t inDataSize, - - // out variables: - UInt64 *inProcessed, - int *isMT, /* out: (*isMT == 0), if single thread decoding was used */ - - // UInt64 *outProcessed, - ICompressProgressPtr progress); - - -/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ - -SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, - Byte prop, - const CLzma2DecMtProps *props, - const UInt64 *outDataSize, int finishMode, - ISeqInStreamPtr inStream); - -SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, - Byte *data, size_t *outSize, - UInt64 *inStreamProcessed); - - -EXTERN_C_END - -#endif +/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA2_DEC_MT_H +#define ZIP7_INC_LZMA2_DEC_MT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +typedef struct +{ + size_t inBufSize_ST; + size_t outStep_ST; + + #ifndef Z7_ST + unsigned numThreads; + size_t inBufSize_MT; + size_t outBlockMax; + size_t inBlockMax; + #endif +} CLzma2DecMtProps; + +/* init to single-thread mode */ +void Lzma2DecMtProps_Init(CLzma2DecMtProps *p); + + +/* ---------- CLzma2DecMtHandle Interface ---------- */ + +/* Lzma2DecMt_ * functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef struct CLzma2DecMt CLzma2DecMt; +typedef CLzma2DecMt * CLzma2DecMtHandle; +// Z7_DECLARE_HANDLE(CLzma2DecMtHandle) + +CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void Lzma2DecMt_Destroy(CLzma2DecMtHandle p); + +SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p, + Byte prop, + const CLzma2DecMtProps *props, + ISeqOutStreamPtr outStream, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + + // out variables: + UInt64 *inProcessed, + int *isMT, /* out: (*isMT == 0), if single thread decoding was used */ + + // UInt64 *outProcessed, + ICompressProgressPtr progress); + + +/* ---------- Read from CLzma2DecMtHandle Interface ---------- */ + +SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp, + Byte prop, + const CLzma2DecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqInStreamPtr inStream); + +SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp, + Byte *data, size_t *outSize, + UInt64 *inStreamProcessed); + + +EXTERN_C_END + +#endif diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c index 85aa80d77..703e146b5 100644 --- a/C/Lzma2Enc.c +++ b/C/Lzma2Enc.c @@ -1,805 +1,805 @@ -/* Lzma2Enc.c -- LZMA2 Encoder -2023-04-13 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #define Z7_ST */ - -#include "Lzma2Enc.h" - -#ifndef Z7_ST -#include "MtCoder.h" -#else -#define MTCODER_THREADS_MAX 1 -#endif - -#define LZMA2_CONTROL_LZMA (1 << 7) -#define LZMA2_CONTROL_COPY_NO_RESET 2 -#define LZMA2_CONTROL_COPY_RESET_DIC 1 -#define LZMA2_CONTROL_EOF 0 - -#define LZMA2_LCLP_MAX 4 - -#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) - -#define LZMA2_PACK_SIZE_MAX (1 << 16) -#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX -#define LZMA2_UNPACK_SIZE_MAX (1 << 21) -#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX - -#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) - - -#define PRF(x) /* x */ - - -/* ---------- CLimitedSeqInStream ---------- */ - -typedef struct -{ - ISeqInStream vt; - ISeqInStreamPtr realStream; - UInt64 limit; - UInt64 processed; - int finished; -} CLimitedSeqInStream; - -static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) -{ - p->limit = (UInt64)(Int64)-1; - p->processed = 0; - p->finished = 0; -} - -static SRes LimitedSeqInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLimitedSeqInStream) - size_t size2 = *size; - SRes res = SZ_OK; - - if (p->limit != (UInt64)(Int64)-1) - { - const UInt64 rem = p->limit - p->processed; - if (size2 > rem) - size2 = (size_t)rem; - } - if (size2 != 0) - { - res = ISeqInStream_Read(p->realStream, data, &size2); - p->finished = (size2 == 0 ? 1 : 0); - p->processed += size2; - } - *size = size2; - return res; -} - - -/* ---------- CLzma2EncInt ---------- */ - -typedef struct -{ - CLzmaEncHandle enc; - Byte propsAreSet; - Byte propsByte; - Byte needInitState; - Byte needInitProp; - UInt64 srcPos; -} CLzma2EncInt; - - -static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) -{ - if (!p->propsAreSet) - { - SizeT propsSize = LZMA_PROPS_SIZE; - Byte propsEncoded[LZMA_PROPS_SIZE]; - RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)) - RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)) - p->propsByte = propsEncoded[0]; - p->propsAreSet = True; - } - return SZ_OK; -} - -static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) -{ - p->srcPos = 0; - p->needInitState = True; - p->needInitProp = True; -} - - -SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize, - ISzAllocPtr alloc, ISzAllocPtr allocBig); -SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen, - UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); -SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, - Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); -const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p); -void LzmaEnc_Finish(CLzmaEncHandle p); -void LzmaEnc_SaveState(CLzmaEncHandle p); -void LzmaEnc_RestoreState(CLzmaEncHandle p); - -/* -UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p); -*/ - -static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, - size_t *packSizeRes, ISeqOutStreamPtr outStream) -{ - size_t packSizeLimit = *packSizeRes; - size_t packSize = packSizeLimit; - UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; - unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); - BoolInt useCopyBlock; - SRes res; - - *packSizeRes = 0; - if (packSize < lzHeaderSize) - return SZ_ERROR_OUTPUT_EOF; - packSize -= lzHeaderSize; - - LzmaEnc_SaveState(p->enc); - res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, - outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); - - PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); - - if (unpackSize == 0) - return res; - - if (res == SZ_OK) - useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); - else - { - if (res != SZ_ERROR_OUTPUT_EOF) - return res; - res = SZ_OK; - useCopyBlock = True; - } - - if (useCopyBlock) - { - size_t destPos = 0; - PRF(printf("################# COPY ")); - - while (unpackSize > 0) - { - const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; - if (packSizeLimit - destPos < u + 3) - return SZ_ERROR_OUTPUT_EOF; - outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); - outBuf[destPos++] = (Byte)((u - 1) >> 8); - outBuf[destPos++] = (Byte)(u - 1); - memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); - unpackSize -= u; - destPos += u; - p->srcPos += u; - - if (outStream) - { - *packSizeRes += destPos; - if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) - return SZ_ERROR_WRITE; - destPos = 0; - } - else - *packSizeRes = destPos; - /* needInitState = True; */ - } - - LzmaEnc_RestoreState(p->enc); - return SZ_OK; - } - - { - size_t destPos = 0; - const UInt32 u = unpackSize - 1; - const UInt32 pm = (UInt32)(packSize - 1); - const unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); - - PRF(printf(" ")); - - outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); - outBuf[destPos++] = (Byte)(u >> 8); - outBuf[destPos++] = (Byte)u; - outBuf[destPos++] = (Byte)(pm >> 8); - outBuf[destPos++] = (Byte)pm; - - if (p->needInitProp) - outBuf[destPos++] = p->propsByte; - - p->needInitProp = False; - p->needInitState = False; - destPos += packSize; - p->srcPos += unpackSize; - - if (outStream) - if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) - return SZ_ERROR_WRITE; - - *packSizeRes = destPos; - return SZ_OK; - } -} - - -/* ---------- Lzma2 Props ---------- */ - -void Lzma2EncProps_Init(CLzma2EncProps *p) -{ - LzmaEncProps_Init(&p->lzmaProps); - p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO; - p->numBlockThreads_Reduced = -1; - p->numBlockThreads_Max = -1; - p->numTotalThreads = -1; -} - -void Lzma2EncProps_Normalize(CLzma2EncProps *p) -{ - UInt64 fileSize; - int t1, t1n, t2, t2r, t3; - { - CLzmaEncProps lzmaProps = p->lzmaProps; - LzmaEncProps_Normalize(&lzmaProps); - t1n = lzmaProps.numThreads; - } - - t1 = p->lzmaProps.numThreads; - t2 = p->numBlockThreads_Max; - t3 = p->numTotalThreads; - - if (t2 > MTCODER_THREADS_MAX) - t2 = MTCODER_THREADS_MAX; - - if (t3 <= 0) - { - if (t2 <= 0) - t2 = 1; - t3 = t1n * t2; - } - else if (t2 <= 0) - { - t2 = t3 / t1n; - if (t2 == 0) - { - t1 = 1; - t2 = t3; - } - if (t2 > MTCODER_THREADS_MAX) - t2 = MTCODER_THREADS_MAX; - } - else if (t1 <= 0) - { - t1 = t3 / t2; - if (t1 == 0) - t1 = 1; - } - else - t3 = t1n * t2; - - p->lzmaProps.numThreads = t1; - - t2r = t2; - - fileSize = p->lzmaProps.reduceSize; - - if ( p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID - && p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO - && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) - p->lzmaProps.reduceSize = p->blockSize; - - LzmaEncProps_Normalize(&p->lzmaProps); - - p->lzmaProps.reduceSize = fileSize; - - t1 = p->lzmaProps.numThreads; - - if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) - { - t2r = t2 = 1; - t3 = t1; - } - else if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO && t2 <= 1) - { - /* if there is no block multi-threading, we use SOLID block */ - p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; - } - else - { - if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) - { - const UInt32 kMinSize = (UInt32)1 << 20; - const UInt32 kMaxSize = (UInt32)1 << 28; - const UInt32 dictSize = p->lzmaProps.dictSize; - UInt64 blockSize = (UInt64)dictSize << 2; - if (blockSize < kMinSize) blockSize = kMinSize; - if (blockSize > kMaxSize) blockSize = kMaxSize; - if (blockSize < dictSize) blockSize = dictSize; - blockSize += (kMinSize - 1); - blockSize &= ~(UInt64)(kMinSize - 1); - p->blockSize = blockSize; - } - - if (t2 > 1 && fileSize != (UInt64)(Int64)-1) - { - UInt64 numBlocks = fileSize / p->blockSize; - if (numBlocks * p->blockSize != fileSize) - numBlocks++; - if (numBlocks < (unsigned)t2) - { - t2r = (int)numBlocks; - if (t2r == 0) - t2r = 1; - t3 = t1 * t2r; - } - } - } - - p->numBlockThreads_Max = t2; - p->numBlockThreads_Reduced = t2r; - p->numTotalThreads = t3; -} - - -static SRes Progress(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize) -{ - return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; -} - - -/* ---------- Lzma2 ---------- */ - -struct CLzma2Enc -{ - Byte propEncoded; - CLzma2EncProps props; - UInt64 expectedDataSize; - - Byte *tempBufLzma; - - ISzAllocPtr alloc; - ISzAllocPtr allocBig; - - CLzma2EncInt coders[MTCODER_THREADS_MAX]; - - #ifndef Z7_ST - - ISeqOutStreamPtr outStream; - Byte *outBuf; - size_t outBuf_Rem; /* remainder in outBuf */ - - size_t outBufSize; /* size of allocated outBufs[i] */ - size_t outBufsDataSizes[MTCODER_BLOCKS_MAX]; - BoolInt mtCoder_WasConstructed; - CMtCoder mtCoder; - Byte *outBufs[MTCODER_BLOCKS_MAX]; - - #endif -}; - - - -CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); - if (!p) - return NULL; - Lzma2EncProps_Init(&p->props); - Lzma2EncProps_Normalize(&p->props); - p->expectedDataSize = (UInt64)(Int64)-1; - p->tempBufLzma = NULL; - p->alloc = alloc; - p->allocBig = allocBig; - { - unsigned i; - for (i = 0; i < MTCODER_THREADS_MAX; i++) - p->coders[i].enc = NULL; - } - - #ifndef Z7_ST - p->mtCoder_WasConstructed = False; - { - unsigned i; - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - p->outBufs[i] = NULL; - p->outBufSize = 0; - } - #endif - - return (CLzma2EncHandle)p; -} - - -#ifndef Z7_ST - -static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) -{ - unsigned i; - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - if (p->outBufs[i]) - { - ISzAlloc_Free(p->alloc, p->outBufs[i]); - p->outBufs[i] = NULL; - } - p->outBufSize = 0; -} - -#endif - -// #define GET_CLzma2Enc_p CLzma2Enc *p = (CLzma2Enc *)(void *)p; - -void Lzma2Enc_Destroy(CLzma2EncHandle p) -{ - // GET_CLzma2Enc_p - unsigned i; - for (i = 0; i < MTCODER_THREADS_MAX; i++) - { - CLzma2EncInt *t = &p->coders[i]; - if (t->enc) - { - LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); - t->enc = NULL; - } - } - - - #ifndef Z7_ST - if (p->mtCoder_WasConstructed) - { - MtCoder_Destruct(&p->mtCoder); - p->mtCoder_WasConstructed = False; - } - Lzma2Enc_FreeOutBufs(p); - #endif - - ISzAlloc_Free(p->alloc, p->tempBufLzma); - p->tempBufLzma = NULL; - - ISzAlloc_Free(p->alloc, p); -} - - -SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props) -{ - // GET_CLzma2Enc_p - CLzmaEncProps lzmaProps = props->lzmaProps; - LzmaEncProps_Normalize(&lzmaProps); - if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) - return SZ_ERROR_PARAM; - p->props = *props; - Lzma2EncProps_Normalize(&p->props); - return SZ_OK; -} - - -void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize) -{ - // GET_CLzma2Enc_p - p->expectedDataSize = expectedDataSiize; -} - - -Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p) -{ - // GET_CLzma2Enc_p - unsigned i; - UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); - for (i = 0; i < 40; i++) - if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) - break; - return (Byte)i; -} - - -static SRes Lzma2Enc_EncodeMt1( - CLzma2Enc *me, - CLzma2EncInt *p, - ISeqOutStreamPtr outStream, - Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - const Byte *inData, size_t inDataSize, - int finished, - ICompressProgressPtr progress) -{ - UInt64 unpackTotal = 0; - UInt64 packTotal = 0; - size_t outLim = 0; - CLimitedSeqInStream limitedInStream; - - if (outBuf) - { - outLim = *outBufSize; - *outBufSize = 0; - } - - if (!p->enc) - { - p->propsAreSet = False; - p->enc = LzmaEnc_Create(me->alloc); - if (!p->enc) - return SZ_ERROR_MEM; - } - - limitedInStream.realStream = inStream; - if (inStream) - { - limitedInStream.vt.Read = LimitedSeqInStream_Read; - } - - if (!outBuf) - { - // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma - if (!me->tempBufLzma) - { - me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); - if (!me->tempBufLzma) - return SZ_ERROR_MEM; - } - } - - RINOK(Lzma2EncInt_InitStream(p, &me->props)) - - for (;;) - { - SRes res = SZ_OK; - SizeT inSizeCur = 0; - - Lzma2EncInt_InitBlock(p); - - LimitedSeqInStream_Init(&limitedInStream); - limitedInStream.limit = me->props.blockSize; - - if (inStream) - { - UInt64 expected = (UInt64)(Int64)-1; - // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize - if (me->expectedDataSize != (UInt64)(Int64)-1 - && me->expectedDataSize >= unpackTotal) - expected = me->expectedDataSize - unpackTotal; - if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID - && expected > me->props.blockSize) - expected = (size_t)me->props.blockSize; - - LzmaEnc_SetDataSize(p->enc, expected); - - RINOK(LzmaEnc_PrepareForLzma2(p->enc, - &limitedInStream.vt, - LZMA2_KEEP_WINDOW_SIZE, - me->alloc, - me->allocBig)) - } - else - { - inSizeCur = (SizeT)(inDataSize - (size_t)unpackTotal); - if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID - && inSizeCur > me->props.blockSize) - inSizeCur = (SizeT)(size_t)me->props.blockSize; - - // LzmaEnc_SetDataSize(p->enc, inSizeCur); - - RINOK(LzmaEnc_MemPrepare(p->enc, - inData + (size_t)unpackTotal, inSizeCur, - LZMA2_KEEP_WINDOW_SIZE, - me->alloc, - me->allocBig)) - } - - for (;;) - { - size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; - if (outBuf) - packSize = outLim - (size_t)packTotal; - - res = Lzma2EncInt_EncodeSubblock(p, - outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, - outBuf ? NULL : outStream); - - if (res != SZ_OK) - break; - - packTotal += packSize; - if (outBuf) - *outBufSize = (size_t)packTotal; - - res = Progress(progress, unpackTotal + p->srcPos, packTotal); - if (res != SZ_OK) - break; - - /* - if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) - break; - */ - - if (packSize == 0) - break; - } - - LzmaEnc_Finish(p->enc); - - unpackTotal += p->srcPos; - - RINOK(res) - - if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) - return SZ_ERROR_FAIL; - - if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) - { - if (finished) - { - if (outBuf) - { - const size_t destPos = *outBufSize; - if (destPos >= outLim) - return SZ_ERROR_OUTPUT_EOF; - outBuf[destPos] = LZMA2_CONTROL_EOF; // 0 - *outBufSize = destPos + 1; - } - else - { - const Byte b = LZMA2_CONTROL_EOF; // 0; - if (ISeqOutStream_Write(outStream, &b, 1) != 1) - return SZ_ERROR_WRITE; - } - } - return SZ_OK; - } - } -} - - - -#ifndef Z7_ST - -static SRes Lzma2Enc_MtCallback_Code(void *p, unsigned coderIndex, unsigned outBufIndex, - const Byte *src, size_t srcSize, int finished) -{ - CLzma2Enc *me = (CLzma2Enc *)p; - size_t destSize = me->outBufSize; - SRes res; - CMtProgressThunk progressThunk; - - Byte *dest = me->outBufs[outBufIndex]; - - me->outBufsDataSizes[outBufIndex] = 0; - - if (!dest) - { - dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); - if (!dest) - return SZ_ERROR_MEM; - me->outBufs[outBufIndex] = dest; - } - - MtProgressThunk_CreateVTable(&progressThunk); - progressThunk.mtProgress = &me->mtCoder.mtProgress; - progressThunk.inSize = 0; - progressThunk.outSize = 0; - - res = Lzma2Enc_EncodeMt1(me, - &me->coders[coderIndex], - NULL, dest, &destSize, - NULL, src, srcSize, - finished, - &progressThunk.vt); - - me->outBufsDataSizes[outBufIndex] = destSize; - - return res; -} - - -static SRes Lzma2Enc_MtCallback_Write(void *p, unsigned outBufIndex) -{ - CLzma2Enc *me = (CLzma2Enc *)p; - size_t size = me->outBufsDataSizes[outBufIndex]; - const Byte *data = me->outBufs[outBufIndex]; - - if (me->outStream) - return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; - - if (size > me->outBuf_Rem) - return SZ_ERROR_OUTPUT_EOF; - memcpy(me->outBuf, data, size); - me->outBuf_Rem -= size; - me->outBuf += size; - return SZ_OK; -} - -#endif - - - -SRes Lzma2Enc_Encode2(CLzma2EncHandle p, - ISeqOutStreamPtr outStream, - Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - const Byte *inData, size_t inDataSize, - ICompressProgressPtr progress) -{ - // GET_CLzma2Enc_p - - if (inStream && inData) - return SZ_ERROR_PARAM; - - if (outStream && outBuf) - return SZ_ERROR_PARAM; - - { - unsigned i; - for (i = 0; i < MTCODER_THREADS_MAX; i++) - p->coders[i].propsAreSet = False; - } - - #ifndef Z7_ST - - if (p->props.numBlockThreads_Reduced > 1) - { - IMtCoderCallback2 vt; - - if (!p->mtCoder_WasConstructed) - { - p->mtCoder_WasConstructed = True; - MtCoder_Construct(&p->mtCoder); - } - - vt.Code = Lzma2Enc_MtCallback_Code; - vt.Write = Lzma2Enc_MtCallback_Write; - - p->outStream = outStream; - p->outBuf = NULL; - p->outBuf_Rem = 0; - if (!outStream) - { - p->outBuf = outBuf; - p->outBuf_Rem = *outBufSize; - *outBufSize = 0; - } - - p->mtCoder.allocBig = p->allocBig; - p->mtCoder.progress = progress; - p->mtCoder.inStream = inStream; - p->mtCoder.inData = inData; - p->mtCoder.inDataSize = inDataSize; - p->mtCoder.mtCallback = &vt; - p->mtCoder.mtCallbackObject = p; - - p->mtCoder.blockSize = (size_t)p->props.blockSize; - if (p->mtCoder.blockSize != p->props.blockSize) - return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ - - { - const size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; - if (destBlockSize < p->mtCoder.blockSize) - return SZ_ERROR_PARAM; - if (p->outBufSize != destBlockSize) - Lzma2Enc_FreeOutBufs(p); - p->outBufSize = destBlockSize; - } - - p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; - p->mtCoder.expectedDataSize = p->expectedDataSize; - - { - const SRes res = MtCoder_Code(&p->mtCoder); - if (!outStream) - *outBufSize = (size_t)(p->outBuf - outBuf); - return res; - } - } - - #endif - - - return Lzma2Enc_EncodeMt1(p, - &p->coders[0], - outStream, outBuf, outBufSize, - inStream, inData, inDataSize, - True, /* finished */ - progress); -} - -#undef PRF +/* Lzma2Enc.c -- LZMA2 Encoder +2023-04-13 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define Z7_ST */ + +#include "Lzma2Enc.h" + +#ifndef Z7_ST +#include "MtCoder.h" +#else +#define MTCODER_THREADS_MAX 1 +#endif + +#define LZMA2_CONTROL_LZMA (1 << 7) +#define LZMA2_CONTROL_COPY_NO_RESET 2 +#define LZMA2_CONTROL_COPY_RESET_DIC 1 +#define LZMA2_CONTROL_EOF 0 + +#define LZMA2_LCLP_MAX 4 + +#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) + +#define LZMA2_PACK_SIZE_MAX (1 << 16) +#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX +#define LZMA2_UNPACK_SIZE_MAX (1 << 21) +#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX + +#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) + + +#define PRF(x) /* x */ + + +/* ---------- CLimitedSeqInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr realStream; + UInt64 limit; + UInt64 processed; + int finished; +} CLimitedSeqInStream; + +static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->finished = 0; +} + +static SRes LimitedSeqInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLimitedSeqInStream) + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + const UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->finished = (size2 == 0 ? 1 : 0); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CLzma2EncInt ---------- */ + +typedef struct +{ + CLzmaEncHandle enc; + Byte propsAreSet; + Byte propsByte; + Byte needInitState; + Byte needInitProp; + UInt64 srcPos; +} CLzma2EncInt; + + +static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) +{ + if (!p->propsAreSet) + { + SizeT propsSize = LZMA_PROPS_SIZE; + Byte propsEncoded[LZMA_PROPS_SIZE]; + RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)) + RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)) + p->propsByte = propsEncoded[0]; + p->propsAreSet = True; + } + return SZ_OK; +} + +static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) +{ + p->srcPos = 0; + p->needInitState = True; + p->needInitProp = True; +} + + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p); +void LzmaEnc_Finish(CLzmaEncHandle p); +void LzmaEnc_SaveState(CLzmaEncHandle p); +void LzmaEnc_RestoreState(CLzmaEncHandle p); + +/* +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p); +*/ + +static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, + size_t *packSizeRes, ISeqOutStreamPtr outStream) +{ + size_t packSizeLimit = *packSizeRes; + size_t packSize = packSizeLimit; + UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; + unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); + BoolInt useCopyBlock; + SRes res; + + *packSizeRes = 0; + if (packSize < lzHeaderSize) + return SZ_ERROR_OUTPUT_EOF; + packSize -= lzHeaderSize; + + LzmaEnc_SaveState(p->enc); + res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, + outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); + + PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); + + if (unpackSize == 0) + return res; + + if (res == SZ_OK) + useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); + else + { + if (res != SZ_ERROR_OUTPUT_EOF) + return res; + res = SZ_OK; + useCopyBlock = True; + } + + if (useCopyBlock) + { + size_t destPos = 0; + PRF(printf("################# COPY ")); + + while (unpackSize > 0) + { + const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; + if (packSizeLimit - destPos < u + 3) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); + outBuf[destPos++] = (Byte)((u - 1) >> 8); + outBuf[destPos++] = (Byte)(u - 1); + memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); + unpackSize -= u; + destPos += u; + p->srcPos += u; + + if (outStream) + { + *packSizeRes += destPos; + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + destPos = 0; + } + else + *packSizeRes = destPos; + /* needInitState = True; */ + } + + LzmaEnc_RestoreState(p->enc); + return SZ_OK; + } + + { + size_t destPos = 0; + const UInt32 u = unpackSize - 1; + const UInt32 pm = (UInt32)(packSize - 1); + const unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); + + PRF(printf(" ")); + + outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); + outBuf[destPos++] = (Byte)(u >> 8); + outBuf[destPos++] = (Byte)u; + outBuf[destPos++] = (Byte)(pm >> 8); + outBuf[destPos++] = (Byte)pm; + + if (p->needInitProp) + outBuf[destPos++] = p->propsByte; + + p->needInitProp = False; + p->needInitState = False; + destPos += packSize; + p->srcPos += unpackSize; + + if (outStream) + if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) + return SZ_ERROR_WRITE; + + *packSizeRes = destPos; + return SZ_OK; + } +} + + +/* ---------- Lzma2 Props ---------- */ + +void Lzma2EncProps_Init(CLzma2EncProps *p) +{ + LzmaEncProps_Init(&p->lzmaProps); + p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; +} + +void Lzma2EncProps_Normalize(CLzma2EncProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzmaEncProps lzmaProps = p->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + t1n = lzmaProps.numThreads; + } + + t1 = p->lzmaProps.numThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzmaProps.numThreads = t1; + + t2r = t2; + + fileSize = p->lzmaProps.reduceSize; + + if ( p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + && p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO + && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzmaProps.reduceSize = p->blockSize; + + LzmaEncProps_Normalize(&p->lzmaProps); + + p->lzmaProps.reduceSize = fileSize; + + t1 = p->lzmaProps.numThreads; + + if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + { + t2r = t2 = 1; + t3 = t1; + } + else if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO && t2 <= 1) + { + /* if there is no block multi-threading, we use SOLID block */ + p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; + } + else + { + if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + { + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + const UInt32 dictSize = p->lzmaProps.dictSize; + UInt64 blockSize = (UInt64)dictSize << 2; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + blockSize += (kMinSize - 1); + blockSize &= ~(UInt64)(kMinSize - 1); + p->blockSize = blockSize; + } + + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (int)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static SRes Progress(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize) +{ + return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; +} + + +/* ---------- Lzma2 ---------- */ + +struct CLzma2Enc +{ + Byte propEncoded; + CLzma2EncProps props; + UInt64 expectedDataSize; + + Byte *tempBufLzma; + + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CLzma2EncInt coders[MTCODER_THREADS_MAX]; + + #ifndef Z7_ST + + ISeqOutStreamPtr outStream; + Byte *outBuf; + size_t outBuf_Rem; /* remainder in outBuf */ + + size_t outBufSize; /* size of allocated outBufs[i] */ + size_t outBufsDataSizes[MTCODER_BLOCKS_MAX]; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + Byte *outBufs[MTCODER_BLOCKS_MAX]; + + #endif +}; + + + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); + if (!p) + return NULL; + Lzma2EncProps_Init(&p->props); + Lzma2EncProps_Normalize(&p->props); + p->expectedDataSize = (UInt64)(Int64)-1; + p->tempBufLzma = NULL; + p->alloc = alloc; + p->allocBig = allocBig; + { + unsigned i; + for (i = 0; i < MTCODER_THREADS_MAX; i++) + p->coders[i].enc = NULL; + } + + #ifndef Z7_ST + p->mtCoder_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif + + return (CLzma2EncHandle)p; +} + + +#ifndef Z7_ST + +static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) +{ + unsigned i; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + +#endif + +// #define GET_CLzma2Enc_p CLzma2Enc *p = (CLzma2Enc *)(void *)p; + +void Lzma2Enc_Destroy(CLzma2EncHandle p) +{ + // GET_CLzma2Enc_p + unsigned i; + for (i = 0; i < MTCODER_THREADS_MAX; i++) + { + CLzma2EncInt *t = &p->coders[i]; + if (t->enc) + { + LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); + t->enc = NULL; + } + } + + + #ifndef Z7_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + Lzma2Enc_FreeOutBufs(p); + #endif + + ISzAlloc_Free(p->alloc, p->tempBufLzma); + p->tempBufLzma = NULL; + + ISzAlloc_Free(p->alloc, p); +} + + +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props) +{ + // GET_CLzma2Enc_p + CLzmaEncProps lzmaProps = props->lzmaProps; + LzmaEncProps_Normalize(&lzmaProps); + if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) + return SZ_ERROR_PARAM; + p->props = *props; + Lzma2EncProps_Normalize(&p->props); + return SZ_OK; +} + + +void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize) +{ + // GET_CLzma2Enc_p + p->expectedDataSize = expectedDataSiize; +} + + +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p) +{ + // GET_CLzma2Enc_p + unsigned i; + UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); + for (i = 0; i < 40; i++) + if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) + break; + return (Byte)i; +} + + +static SRes Lzma2Enc_EncodeMt1( + CLzma2Enc *me, + CLzma2EncInt *p, + ISeqOutStreamPtr outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + const Byte *inData, size_t inDataSize, + int finished, + ICompressProgressPtr progress) +{ + UInt64 unpackTotal = 0; + UInt64 packTotal = 0; + size_t outLim = 0; + CLimitedSeqInStream limitedInStream; + + if (outBuf) + { + outLim = *outBufSize; + *outBufSize = 0; + } + + if (!p->enc) + { + p->propsAreSet = False; + p->enc = LzmaEnc_Create(me->alloc); + if (!p->enc) + return SZ_ERROR_MEM; + } + + limitedInStream.realStream = inStream; + if (inStream) + { + limitedInStream.vt.Read = LimitedSeqInStream_Read; + } + + if (!outBuf) + { + // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma + if (!me->tempBufLzma) + { + me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); + if (!me->tempBufLzma) + return SZ_ERROR_MEM; + } + } + + RINOK(Lzma2EncInt_InitStream(p, &me->props)) + + for (;;) + { + SRes res = SZ_OK; + SizeT inSizeCur = 0; + + Lzma2EncInt_InitBlock(p); + + LimitedSeqInStream_Init(&limitedInStream); + limitedInStream.limit = me->props.blockSize; + + if (inStream) + { + UInt64 expected = (UInt64)(Int64)-1; + // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize + if (me->expectedDataSize != (UInt64)(Int64)-1 + && me->expectedDataSize >= unpackTotal) + expected = me->expectedDataSize - unpackTotal; + if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + && expected > me->props.blockSize) + expected = (size_t)me->props.blockSize; + + LzmaEnc_SetDataSize(p->enc, expected); + + RINOK(LzmaEnc_PrepareForLzma2(p->enc, + &limitedInStream.vt, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)) + } + else + { + inSizeCur = (SizeT)(inDataSize - (size_t)unpackTotal); + if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + && inSizeCur > me->props.blockSize) + inSizeCur = (SizeT)(size_t)me->props.blockSize; + + // LzmaEnc_SetDataSize(p->enc, inSizeCur); + + RINOK(LzmaEnc_MemPrepare(p->enc, + inData + (size_t)unpackTotal, inSizeCur, + LZMA2_KEEP_WINDOW_SIZE, + me->alloc, + me->allocBig)) + } + + for (;;) + { + size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; + if (outBuf) + packSize = outLim - (size_t)packTotal; + + res = Lzma2EncInt_EncodeSubblock(p, + outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, + outBuf ? NULL : outStream); + + if (res != SZ_OK) + break; + + packTotal += packSize; + if (outBuf) + *outBufSize = (size_t)packTotal; + + res = Progress(progress, unpackTotal + p->srcPos, packTotal); + if (res != SZ_OK) + break; + + /* + if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) + break; + */ + + if (packSize == 0) + break; + } + + LzmaEnc_Finish(p->enc); + + unpackTotal += p->srcPos; + + RINOK(res) + + if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) + return SZ_ERROR_FAIL; + + if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) + { + if (finished) + { + if (outBuf) + { + const size_t destPos = *outBufSize; + if (destPos >= outLim) + return SZ_ERROR_OUTPUT_EOF; + outBuf[destPos] = LZMA2_CONTROL_EOF; // 0 + *outBufSize = destPos + 1; + } + else + { + const Byte b = LZMA2_CONTROL_EOF; // 0; + if (ISeqOutStream_Write(outStream, &b, 1) != 1) + return SZ_ERROR_WRITE; + } + } + return SZ_OK; + } + } +} + + + +#ifndef Z7_ST + +static SRes Lzma2Enc_MtCallback_Code(void *p, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CLzma2Enc *me = (CLzma2Enc *)p; + size_t destSize = me->outBufSize; + SRes res; + CMtProgressThunk progressThunk; + + Byte *dest = me->outBufs[outBufIndex]; + + me->outBufsDataSizes[outBufIndex] = 0; + + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + progressThunk.inSize = 0; + progressThunk.outSize = 0; + + res = Lzma2Enc_EncodeMt1(me, + &me->coders[coderIndex], + NULL, dest, &destSize, + NULL, src, srcSize, + finished, + &progressThunk.vt); + + me->outBufsDataSizes[outBufIndex] = destSize; + + return res; +} + + +static SRes Lzma2Enc_MtCallback_Write(void *p, unsigned outBufIndex) +{ + CLzma2Enc *me = (CLzma2Enc *)p; + size_t size = me->outBufsDataSizes[outBufIndex]; + const Byte *data = me->outBufs[outBufIndex]; + + if (me->outStream) + return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; + + if (size > me->outBuf_Rem) + return SZ_ERROR_OUTPUT_EOF; + memcpy(me->outBuf, data, size); + me->outBuf_Rem -= size; + me->outBuf += size; + return SZ_OK; +} + +#endif + + + +SRes Lzma2Enc_Encode2(CLzma2EncHandle p, + ISeqOutStreamPtr outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + const Byte *inData, size_t inDataSize, + ICompressProgressPtr progress) +{ + // GET_CLzma2Enc_p + + if (inStream && inData) + return SZ_ERROR_PARAM; + + if (outStream && outBuf) + return SZ_ERROR_PARAM; + + { + unsigned i; + for (i = 0; i < MTCODER_THREADS_MAX; i++) + p->coders[i].propsAreSet = False; + } + + #ifndef Z7_ST + + if (p->props.numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = Lzma2Enc_MtCallback_Code; + vt.Write = Lzma2Enc_MtCallback_Write; + + p->outStream = outStream; + p->outBuf = NULL; + p->outBuf_Rem = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBuf_Rem = *outBufSize; + *outBufSize = 0; + } + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = inData; + p->mtCoder.inDataSize = inDataSize; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + p->mtCoder.blockSize = (size_t)p->props.blockSize; + if (p->mtCoder.blockSize != p->props.blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + const size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + Lzma2Enc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + { + const SRes res = MtCoder_Code(&p->mtCoder); + if (!outStream) + *outBufSize = (size_t)(p->outBuf - outBuf); + return res; + } + } + + #endif + + + return Lzma2Enc_EncodeMt1(p, + &p->coders[0], + outStream, outBuf, outBufSize, + inStream, inData, inDataSize, + True, /* finished */ + progress); +} + +#undef PRF diff --git a/C/Lzma2Enc.h b/C/Lzma2Enc.h index bead0fc52..cb25275c6 100644 --- a/C/Lzma2Enc.h +++ b/C/Lzma2Enc.h @@ -1,57 +1,57 @@ -/* Lzma2Enc.h -- LZMA2 Encoder -2023-04-13 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA2_ENC_H -#define ZIP7_INC_LZMA2_ENC_H - -#include "LzmaEnc.h" - -EXTERN_C_BEGIN - -#define LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO 0 -#define LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID ((UInt64)(Int64)-1) - -typedef struct -{ - CLzmaEncProps lzmaProps; - UInt64 blockSize; - int numBlockThreads_Reduced; - int numBlockThreads_Max; - int numTotalThreads; -} CLzma2EncProps; - -void Lzma2EncProps_Init(CLzma2EncProps *p); -void Lzma2EncProps_Normalize(CLzma2EncProps *p); - -/* ---------- CLzmaEnc2Handle Interface ---------- */ - -/* Lzma2Enc_* functions can return the following exit codes: -SRes: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater in props - SZ_ERROR_WRITE - ISeqOutStream write callback error - SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output - SZ_ERROR_PROGRESS - some break from progress callback - SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) -*/ - -typedef struct CLzma2Enc CLzma2Enc; -typedef CLzma2Enc * CLzma2EncHandle; -// Z7_DECLARE_HANDLE(CLzma2EncHandle) - -CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); -void Lzma2Enc_Destroy(CLzma2EncHandle p); -SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); -void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize); -Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); -SRes Lzma2Enc_Encode2(CLzma2EncHandle p, - ISeqOutStreamPtr outStream, - Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - const Byte *inData, size_t inDataSize, - ICompressProgressPtr progress); - -EXTERN_C_END - -#endif +/* Lzma2Enc.h -- LZMA2 Encoder +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA2_ENC_H +#define ZIP7_INC_LZMA2_ENC_H + +#include "LzmaEnc.h" + +EXTERN_C_BEGIN + +#define LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO 0 +#define LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID ((UInt64)(Int64)-1) + +typedef struct +{ + CLzmaEncProps lzmaProps; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; +} CLzma2EncProps; + +void Lzma2EncProps_Init(CLzma2EncProps *p); +void Lzma2EncProps_Normalize(CLzma2EncProps *p); + +/* ---------- CLzmaEnc2Handle Interface ---------- */ + +/* Lzma2Enc_* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef struct CLzma2Enc CLzma2Enc; +typedef CLzma2Enc * CLzma2EncHandle; +// Z7_DECLARE_HANDLE(CLzma2EncHandle) + +CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void Lzma2Enc_Destroy(CLzma2EncHandle p); +SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props); +void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize); +Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p); +SRes Lzma2Enc_Encode2(CLzma2EncHandle p, + ISeqOutStreamPtr outStream, + Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + const Byte *inData, size_t inDataSize, + ICompressProgressPtr progress); + +EXTERN_C_END + +#endif diff --git a/C/Lzma86.h b/C/Lzma86.h index 9127d73b7..e7707e2c4 100644 --- a/C/Lzma86.h +++ b/C/Lzma86.h @@ -1,111 +1,111 @@ -/* Lzma86.h -- LZMA + x86 (BCJ) Filter -2023-03-03 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA86_H -#define ZIP7_INC_LZMA86_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define LZMA86_SIZE_OFFSET (1 + 5) -#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8) - -/* -It's an example for LZMA + x86 Filter use. -You can use .lzma86 extension, if you write that stream to file. -.lzma86 header adds one additional byte to standard .lzma header. -.lzma86 header (14 bytes): - Offset Size Description - 0 1 = 0 - no filter, pure LZMA - = 1 - x86 filter + LZMA - 1 1 lc, lp and pb in encoded form - 2 4 dictSize (little endian) - 6 8 uncompressed size (little endian) - - -Lzma86_Encode -------------- -level - compression level: 0 <= level <= 9, the default value for "level" is 5. - -dictSize - The dictionary size in bytes. The maximum value is - 128 MB = (1 << 27) bytes for 32-bit version - 1 GB = (1 << 30) bytes for 64-bit version - The default value is 16 MB = (1 << 24) bytes, for level = 5. - It's recommended to use the dictionary that is larger than 4 KB and - that can be calculated as (1 << N) or (3 << N) sizes. - For better compression ratio dictSize must be >= inSize. - -filterMode: - SZ_FILTER_NO - no Filter - SZ_FILTER_YES - x86 Filter - SZ_FILTER_AUTO - it tries both alternatives to select best. - Encoder will use 2 or 3 passes: - 2 passes when FILTER_NO provides better compression. - 3 passes when FILTER_YES provides better compression. - -Lzma86Encode allocates Data with MyAlloc functions. -RAM Requirements for compressing: - RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize - filterMode FilterBlockSize - SZ_FILTER_NO 0 - SZ_FILTER_YES inSize - SZ_FILTER_AUTO inSize - - -Return code: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater - SZ_ERROR_OUTPUT_EOF - output buffer overflow - SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) -*/ - -enum ESzFilterMode -{ - SZ_FILTER_NO, - SZ_FILTER_YES, - SZ_FILTER_AUTO -}; - -SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, - int level, UInt32 dictSize, int filterMode); - - -/* -Lzma86_GetUnpackSize: - In: - src - input data - srcLen - input data size - Out: - unpackSize - size of uncompressed stream - Return code: - SZ_OK - OK - SZ_ERROR_INPUT_EOF - Error in headers -*/ - -SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize); - -/* -Lzma86_Decode: - In: - dest - output data - destLen - output data size - src - input data - srcLen - input data size - Out: - destLen - processed output size - srcLen - processed input size - Return code: - SZ_OK - OK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - unsupported file - SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer -*/ - -SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen); - -EXTERN_C_END - -#endif +/* Lzma86.h -- LZMA + x86 (BCJ) Filter +2023-03-03 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA86_H +#define ZIP7_INC_LZMA86_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define LZMA86_SIZE_OFFSET (1 + 5) +#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8) + +/* +It's an example for LZMA + x86 Filter use. +You can use .lzma86 extension, if you write that stream to file. +.lzma86 header adds one additional byte to standard .lzma header. +.lzma86 header (14 bytes): + Offset Size Description + 0 1 = 0 - no filter, pure LZMA + = 1 - x86 filter + LZMA + 1 1 lc, lp and pb in encoded form + 2 4 dictSize (little endian) + 6 8 uncompressed size (little endian) + + +Lzma86_Encode +------------- +level - compression level: 0 <= level <= 9, the default value for "level" is 5. + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes, for level = 5. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + For better compression ratio dictSize must be >= inSize. + +filterMode: + SZ_FILTER_NO - no Filter + SZ_FILTER_YES - x86 Filter + SZ_FILTER_AUTO - it tries both alternatives to select best. + Encoder will use 2 or 3 passes: + 2 passes when FILTER_NO provides better compression. + 3 passes when FILTER_YES provides better compression. + +Lzma86Encode allocates Data with MyAlloc functions. +RAM Requirements for compressing: + RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize + filterMode FilterBlockSize + SZ_FILTER_NO 0 + SZ_FILTER_YES inSize + SZ_FILTER_AUTO inSize + + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +enum ESzFilterMode +{ + SZ_FILTER_NO, + SZ_FILTER_YES, + SZ_FILTER_AUTO +}; + +SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode); + + +/* +Lzma86_GetUnpackSize: + In: + src - input data + srcLen - input data size + Out: + unpackSize - size of uncompressed stream + Return code: + SZ_OK - OK + SZ_ERROR_INPUT_EOF - Error in headers +*/ + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize); + +/* +Lzma86_Decode: + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + Out: + destLen - processed output size + srcLen - processed input size + Return code: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - unsupported file + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer +*/ + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen); + +EXTERN_C_END + +#endif diff --git a/C/Lzma86Dec.c b/C/Lzma86Dec.c index 9b15f3630..f094d4c35 100644 --- a/C/Lzma86Dec.c +++ b/C/Lzma86Dec.c @@ -1,53 +1,53 @@ -/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder -2023-03-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Lzma86.h" - -#include "Alloc.h" -#include "Bra.h" -#include "LzmaDec.h" - -SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) -{ - unsigned i; - if (srcLen < LZMA86_HEADER_SIZE) - return SZ_ERROR_INPUT_EOF; - *unpackSize = 0; - for (i = 0; i < sizeof(UInt64); i++) - *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i); - return SZ_OK; -} - -SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) -{ - SRes res; - int useFilter; - SizeT inSizePure; - ELzmaStatus status; - - if (*srcLen < LZMA86_HEADER_SIZE) - return SZ_ERROR_INPUT_EOF; - - useFilter = src[0]; - - if (useFilter > 1) - { - *destLen = 0; - return SZ_ERROR_UNSUPPORTED; - } - - inSizePure = *srcLen - LZMA86_HEADER_SIZE; - res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure, - src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc); - *srcLen = inSizePure + LZMA86_HEADER_SIZE; - if (res != SZ_OK) - return res; - if (useFilter == 1) - { - UInt32 x86State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; - z7_BranchConvSt_X86_Dec(dest, *destLen, 0, &x86State); - } - return SZ_OK; -} +/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder +2023-03-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaDec.h" + +SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) +{ + unsigned i; + if (srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + *unpackSize = 0; + for (i = 0; i < sizeof(UInt64); i++) + *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i); + return SZ_OK; +} + +SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + SRes res; + int useFilter; + SizeT inSizePure; + ELzmaStatus status; + + if (*srcLen < LZMA86_HEADER_SIZE) + return SZ_ERROR_INPUT_EOF; + + useFilter = src[0]; + + if (useFilter > 1) + { + *destLen = 0; + return SZ_ERROR_UNSUPPORTED; + } + + inSizePure = *srcLen - LZMA86_HEADER_SIZE; + res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure, + src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc); + *srcLen = inSizePure + LZMA86_HEADER_SIZE; + if (res != SZ_OK) + return res; + if (useFilter == 1) + { + UInt32 x86State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + z7_BranchConvSt_X86_Dec(dest, *destLen, 0, &x86State); + } + return SZ_OK; +} diff --git a/C/Lzma86Enc.c b/C/Lzma86Enc.c index 1c034a74c..0cdde1c9a 100644 --- a/C/Lzma86Enc.c +++ b/C/Lzma86Enc.c @@ -1,103 +1,103 @@ -/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder -2023-03-03 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "Lzma86.h" - -#include "Alloc.h" -#include "Bra.h" -#include "LzmaEnc.h" - -int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, - int level, UInt32 dictSize, int filterMode) -{ - size_t outSize2 = *destLen; - Byte *filteredStream; - BoolInt useFilter; - int mainResult = SZ_ERROR_OUTPUT_EOF; - CLzmaEncProps props; - LzmaEncProps_Init(&props); - props.level = level; - props.dictSize = dictSize; - - *destLen = 0; - if (outSize2 < LZMA86_HEADER_SIZE) - return SZ_ERROR_OUTPUT_EOF; - - { - int i; - UInt64 t = srcLen; - for (i = 0; i < 8; i++, t >>= 8) - dest[LZMA86_SIZE_OFFSET + i] = (Byte)t; - } - - filteredStream = 0; - useFilter = (filterMode != SZ_FILTER_NO); - if (useFilter) - { - if (srcLen != 0) - { - filteredStream = (Byte *)MyAlloc(srcLen); - if (filteredStream == 0) - return SZ_ERROR_MEM; - memcpy(filteredStream, src, srcLen); - } - { - UInt32 x86State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; - z7_BranchConvSt_X86_Enc(filteredStream, srcLen, 0, &x86State); - } - } - - { - size_t minSize = 0; - BoolInt bestIsFiltered = False; - - /* passes for SZ_FILTER_AUTO: - 0 - BCJ + LZMA - 1 - LZMA - 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better. - */ - int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; - - int i; - for (i = 0; i < numPasses; i++) - { - size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE; - size_t outPropsSize = 5; - SRes curRes; - BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1); - if (curModeIsFiltered && !bestIsFiltered) - break; - if (useFilter && i == 0) - curModeIsFiltered = True; - - curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed, - curModeIsFiltered ? filteredStream : src, srcLen, - &props, dest + 1, &outPropsSize, 0, - NULL, &g_Alloc, &g_Alloc); - - if (curRes != SZ_ERROR_OUTPUT_EOF) - { - if (curRes != SZ_OK) - { - mainResult = curRes; - break; - } - if (outSizeProcessed <= minSize || mainResult != SZ_OK) - { - minSize = outSizeProcessed; - bestIsFiltered = curModeIsFiltered; - mainResult = SZ_OK; - } - } - } - dest[0] = (Byte)(bestIsFiltered ? 1 : 0); - *destLen = LZMA86_HEADER_SIZE + minSize; - } - if (useFilter) - MyFree(filteredStream); - return mainResult; -} +/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder +2023-03-03 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "Lzma86.h" + +#include "Alloc.h" +#include "Bra.h" +#include "LzmaEnc.h" + +int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, + int level, UInt32 dictSize, int filterMode) +{ + size_t outSize2 = *destLen; + Byte *filteredStream; + BoolInt useFilter; + int mainResult = SZ_ERROR_OUTPUT_EOF; + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + + *destLen = 0; + if (outSize2 < LZMA86_HEADER_SIZE) + return SZ_ERROR_OUTPUT_EOF; + + { + int i; + UInt64 t = srcLen; + for (i = 0; i < 8; i++, t >>= 8) + dest[LZMA86_SIZE_OFFSET + i] = (Byte)t; + } + + filteredStream = 0; + useFilter = (filterMode != SZ_FILTER_NO); + if (useFilter) + { + if (srcLen != 0) + { + filteredStream = (Byte *)MyAlloc(srcLen); + if (filteredStream == 0) + return SZ_ERROR_MEM; + memcpy(filteredStream, src, srcLen); + } + { + UInt32 x86State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + z7_BranchConvSt_X86_Enc(filteredStream, srcLen, 0, &x86State); + } + } + + { + size_t minSize = 0; + BoolInt bestIsFiltered = False; + + /* passes for SZ_FILTER_AUTO: + 0 - BCJ + LZMA + 1 - LZMA + 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better. + */ + int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1; + + int i; + for (i = 0; i < numPasses; i++) + { + size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE; + size_t outPropsSize = 5; + SRes curRes; + BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1); + if (curModeIsFiltered && !bestIsFiltered) + break; + if (useFilter && i == 0) + curModeIsFiltered = True; + + curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed, + curModeIsFiltered ? filteredStream : src, srcLen, + &props, dest + 1, &outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); + + if (curRes != SZ_ERROR_OUTPUT_EOF) + { + if (curRes != SZ_OK) + { + mainResult = curRes; + break; + } + if (outSizeProcessed <= minSize || mainResult != SZ_OK) + { + minSize = outSizeProcessed; + bestIsFiltered = curModeIsFiltered; + mainResult = SZ_OK; + } + } + } + dest[0] = (Byte)(bestIsFiltered ? 1 : 0); + *destLen = LZMA86_HEADER_SIZE + minSize; + } + if (useFilter) + MyFree(filteredStream); + return mainResult; +} diff --git a/C/LzmaDec.c b/C/LzmaDec.c index b6bcd5099..69bb8bba9 100644 --- a/C/LzmaDec.c +++ b/C/LzmaDec.c @@ -1,1363 +1,1363 @@ -/* LzmaDec.c -- LZMA Decoder -2023-04-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #include "CpuArch.h" */ -#include "LzmaDec.h" - -// #define kNumTopBits 24 -#define kTopValue ((UInt32)1 << 24) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) - -#define RC_INIT_SIZE 5 - -#ifndef Z7_LZMA_DEC_OPT - -#define kNumMoveBits 5 -#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } - -#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); -#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ - { UPDATE_0(p) i = (i + i); A0; } else \ - { UPDATE_1(p) i = (i + i) + 1; A1; } - -#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } - -#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ - { UPDATE_0(p + i) A0; } else \ - { UPDATE_1(p + i) A1; } -#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) -#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) -#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) - -#define TREE_DECODE(probs, limit, i) \ - { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } - -/* #define Z7_LZMA_SIZE_OPT */ - -#ifdef Z7_LZMA_SIZE_OPT -#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) -#else -#define TREE_6_DECODE(probs, i) \ - { i = 1; \ - TREE_GET_BIT(probs, i) \ - TREE_GET_BIT(probs, i) \ - TREE_GET_BIT(probs, i) \ - TREE_GET_BIT(probs, i) \ - TREE_GET_BIT(probs, i) \ - TREE_GET_BIT(probs, i) \ - i -= 0x40; } -#endif - -#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol) -#define MATCHED_LITER_DEC \ - matchByte += matchByte; \ - bit = offs; \ - offs &= matchByte; \ - probLit = prob + (offs + bit + symbol); \ - GET_BIT2(probLit, symbol, offs ^= bit; , ;) - -#endif // Z7_LZMA_DEC_OPT - - -#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_INPUT_EOF; range <<= 8; code = (code << 8) | (*buf++); } - -#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) -#define UPDATE_0_CHECK range = bound; -#define UPDATE_1_CHECK range -= bound; code -= bound; -#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ - { UPDATE_0_CHECK i = (i + i); A0; } else \ - { UPDATE_1_CHECK i = (i + i) + 1; A1; } -#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) -#define TREE_DECODE_CHECK(probs, limit, i) \ - { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } - - -#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ - { UPDATE_0_CHECK i += m; m += m; } else \ - { UPDATE_1_CHECK m += m; i += m; } - - -#define kNumPosBitsMax 4 -#define kNumPosStatesMax (1 << kNumPosBitsMax) - -#define kLenNumLowBits 3 -#define kLenNumLowSymbols (1 << kLenNumLowBits) -#define kLenNumHighBits 8 -#define kLenNumHighSymbols (1 << kLenNumHighBits) - -#define LenLow 0 -#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits)) -#define kNumLenProbs (LenHigh + kLenNumHighSymbols) - -#define LenChoice LenLow -#define LenChoice2 (LenLow + (1 << kLenNumLowBits)) - -#define kNumStates 12 -#define kNumStates2 16 -#define kNumLitStates 7 - -#define kStartPosModelIndex 4 -#define kEndPosModelIndex 14 -#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) - -#define kNumPosSlotBits 6 -#define kNumLenToPosStates 4 - -#define kNumAlignBits 4 -#define kAlignTableSize (1 << kNumAlignBits) - -#define kMatchMinLen 2 -#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) - -#define kMatchSpecLen_Error_Data (1 << 9) -#define kMatchSpecLen_Error_Fail (kMatchSpecLen_Error_Data - 1) - -/* External ASM code needs same CLzmaProb array layout. So don't change it. */ - -/* (probs_1664) is faster and better for code size at some platforms */ -/* -#ifdef MY_CPU_X86_OR_AMD64 -*/ -#define kStartOffset 1664 -#define GET_PROBS p->probs_1664 -/* -#define GET_PROBS p->probs + kStartOffset -#else -#define kStartOffset 0 -#define GET_PROBS p->probs -#endif -*/ - -#define SpecPos (-kStartOffset) -#define IsRep0Long (SpecPos + kNumFullDistances) -#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax)) -#define LenCoder (RepLenCoder + kNumLenProbs) -#define IsMatch (LenCoder + kNumLenProbs) -#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax)) -#define IsRep (Align + kAlignTableSize) -#define IsRepG0 (IsRep + kNumStates) -#define IsRepG1 (IsRepG0 + kNumStates) -#define IsRepG2 (IsRepG1 + kNumStates) -#define PosSlot (IsRepG2 + kNumStates) -#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) -#define NUM_BASE_PROBS (Literal + kStartOffset) - -#if Align != 0 && kStartOffset != 0 - #error Stop_Compiling_Bad_LZMA_kAlign -#endif - -#if NUM_BASE_PROBS != 1984 - #error Stop_Compiling_Bad_LZMA_PROBS -#endif - - -#define LZMA_LIT_SIZE 0x300 - -#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) - - -#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4) -#define COMBINED_PS_STATE (posState + state) -#define GET_LEN_STATE (posState) - -#define LZMA_DIC_MIN (1 << 12) - -/* -p->remainLen : shows status of LZMA decoder: - < kMatchSpecLenStart : the number of bytes to be copied with (p->rep0) offset - = kMatchSpecLenStart : the LZMA stream was finished with end mark - = kMatchSpecLenStart + 1 : need init range coder - = kMatchSpecLenStart + 2 : need init range coder and state - = kMatchSpecLen_Error_Fail : Internal Code Failure - = kMatchSpecLen_Error_Data + [0 ... 273] : LZMA Data Error -*/ - -/* ---------- LZMA_DECODE_REAL ---------- */ -/* -LzmaDec_DecodeReal_3() can be implemented in external ASM file. -3 - is the code compatibility version of that function for check at link time. -*/ - -#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3 - -/* -LZMA_DECODE_REAL() -In: - RangeCoder is normalized - if (p->dicPos == limit) - { - LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. - So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol - is not END_OF_PAYALOAD_MARKER, then the function doesn't write any byte to dictionary, - the function returns SZ_OK, and the caller can use (p->remainLen) and (p->reps[0]) later. - } - -Processing: - The first LZMA symbol will be decoded in any case. - All main checks for limits are at the end of main loop, - It decodes additional LZMA-symbols while (p->buf < bufLimit && dicPos < limit), - RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. - But if (p->buf < bufLimit), the caller provided at least (LZMA_REQUIRED_INPUT_MAX + 1) bytes for - next iteration before limit (bufLimit + LZMA_REQUIRED_INPUT_MAX), - that is enough for worst case LZMA symbol with one additional RangeCoder normalization for one bit. - So that function never reads bufLimit [LZMA_REQUIRED_INPUT_MAX] byte. - -Out: - RangeCoder is normalized - Result: - SZ_OK - OK - p->remainLen: - < kMatchSpecLenStart : the number of bytes to be copied with (p->reps[0]) offset - = kMatchSpecLenStart : the LZMA stream was finished with end mark - - SZ_ERROR_DATA - error, when the MATCH-Symbol refers out of dictionary - p->remainLen : undefined - p->reps[*] : undefined -*/ - - -#ifdef Z7_LZMA_DEC_OPT - -int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); - -#else - -static -int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - CLzmaProb *probs = GET_PROBS; - unsigned state = (unsigned)p->state; - UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; - unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; - unsigned lc = p->prop.lc; - unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); - - Byte *dic = p->dic; - SizeT dicBufSize = p->dicBufSize; - SizeT dicPos = p->dicPos; - - UInt32 processedPos = p->processedPos; - UInt32 checkDicSize = p->checkDicSize; - unsigned len = 0; - - const Byte *buf = p->buf; - UInt32 range = p->range; - UInt32 code = p->code; - - do - { - CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = CALC_POS_STATE(processedPos, pbMask); - - prob = probs + IsMatch + COMBINED_PS_STATE; - IF_BIT_0(prob) - { - unsigned symbol; - UPDATE_0(prob) - prob = probs + Literal; - if (processedPos != 0 || checkDicSize != 0) - prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); - processedPos++; - - if (state < kNumLitStates) - { - state -= (state < 4) ? state : 3; - symbol = 1; - #ifdef Z7_LZMA_SIZE_OPT - do { NORMAL_LITER_DEC } while (symbol < 0x100); - #else - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - NORMAL_LITER_DEC - #endif - } - else - { - unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - unsigned offs = 0x100; - state -= (state < 10) ? 3 : 6; - symbol = 1; - #ifdef Z7_LZMA_SIZE_OPT - do - { - unsigned bit; - CLzmaProb *probLit; - MATCHED_LITER_DEC - } - while (symbol < 0x100); - #else - { - unsigned bit; - CLzmaProb *probLit; - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - MATCHED_LITER_DEC - } - #endif - } - - dic[dicPos++] = (Byte)symbol; - continue; - } - - { - UPDATE_1(prob) - prob = probs + IsRep + state; - IF_BIT_0(prob) - { - UPDATE_0(prob) - state += kNumStates; - prob = probs + LenCoder; - } - else - { - UPDATE_1(prob) - prob = probs + IsRepG0 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob) - prob = probs + IsRep0Long + COMBINED_PS_STATE; - IF_BIT_0(prob) - { - UPDATE_0(prob) - - // that case was checked before with kBadRepCode - // if (checkDicSize == 0 && processedPos == 0) { len = kMatchSpecLen_Error_Data + 1; break; } - // The caller doesn't allow (dicPos == limit) case here - // so we don't need the following check: - // if (dicPos == limit) { state = state < kNumLitStates ? 9 : 11; len = 1; break; } - - dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - dicPos++; - processedPos++; - state = state < kNumLitStates ? 9 : 11; - continue; - } - UPDATE_1(prob) - } - else - { - UInt32 distance; - UPDATE_1(prob) - prob = probs + IsRepG1 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob) - distance = rep1; - } - else - { - UPDATE_1(prob) - prob = probs + IsRepG2 + state; - IF_BIT_0(prob) - { - UPDATE_0(prob) - distance = rep2; - } - else - { - UPDATE_1(prob) - distance = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = distance; - } - state = state < kNumLitStates ? 8 : 11; - prob = probs + RepLenCoder; - } - - #ifdef Z7_LZMA_SIZE_OPT - { - unsigned lim, offset; - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0(probLen) - { - UPDATE_0(probLen) - probLen = prob + LenLow + GET_LEN_STATE; - offset = 0; - lim = (1 << kLenNumLowBits); - } - else - { - UPDATE_1(probLen) - probLen = prob + LenChoice2; - IF_BIT_0(probLen) - { - UPDATE_0(probLen) - probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); - offset = kLenNumLowSymbols; - lim = (1 << kLenNumLowBits); - } - else - { - UPDATE_1(probLen) - probLen = prob + LenHigh; - offset = kLenNumLowSymbols * 2; - lim = (1 << kLenNumHighBits); - } - } - TREE_DECODE(probLen, lim, len) - len += offset; - } - #else - { - CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0(probLen) - { - UPDATE_0(probLen) - probLen = prob + LenLow + GET_LEN_STATE; - len = 1; - TREE_GET_BIT(probLen, len) - TREE_GET_BIT(probLen, len) - TREE_GET_BIT(probLen, len) - len -= 8; - } - else - { - UPDATE_1(probLen) - probLen = prob + LenChoice2; - IF_BIT_0(probLen) - { - UPDATE_0(probLen) - probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); - len = 1; - TREE_GET_BIT(probLen, len) - TREE_GET_BIT(probLen, len) - TREE_GET_BIT(probLen, len) - } - else - { - UPDATE_1(probLen) - probLen = prob + LenHigh; - TREE_DECODE(probLen, (1 << kLenNumHighBits), len) - len += kLenNumLowSymbols * 2; - } - } - } - #endif - - if (state >= kNumStates) - { - UInt32 distance; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); - TREE_6_DECODE(prob, distance) - if (distance >= kStartPosModelIndex) - { - unsigned posSlot = (unsigned)distance; - unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); - distance = (2 | (distance & 1)); - if (posSlot < kEndPosModelIndex) - { - distance <<= numDirectBits; - prob = probs + SpecPos; - { - UInt32 m = 1; - distance++; - do - { - REV_BIT_VAR(prob, distance, m) - } - while (--numDirectBits); - distance -= m; - } - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE - range >>= 1; - - { - UInt32 t; - code -= range; - t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ - distance = (distance << 1) + (t + 1); - code += range & t; - } - /* - distance <<= 1; - if (code >= range) - { - code -= range; - distance |= 1; - } - */ - } - while (--numDirectBits); - prob = probs + Align; - distance <<= kNumAlignBits; - { - unsigned i = 1; - REV_BIT_CONST(prob, i, 1) - REV_BIT_CONST(prob, i, 2) - REV_BIT_CONST(prob, i, 4) - REV_BIT_LAST (prob, i, 8) - distance |= i; - } - if (distance == (UInt32)0xFFFFFFFF) - { - len = kMatchSpecLenStart; - state -= kNumStates; - break; - } - } - } - - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - rep0 = distance + 1; - state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) - { - len += kMatchSpecLen_Error_Data + kMatchMinLen; - // len = kMatchSpecLen_Error_Data; - // len += kMatchMinLen; - break; - } - } - - len += kMatchMinLen; - - { - SizeT rem; - unsigned curLen; - SizeT pos; - - if ((rem = limit - dicPos) == 0) - { - /* - We stop decoding and return SZ_OK, and we can resume decoding later. - Any error conditions can be tested later in caller code. - For more strict mode we can stop decoding with error - // len += kMatchSpecLen_Error_Data; - */ - break; - } - - curLen = ((rem < len) ? (unsigned)rem : len); - pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); - - processedPos += (UInt32)curLen; - - len -= curLen; - if (curLen <= dicBufSize - pos) - { - Byte *dest = dic + dicPos; - ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; - const Byte *lim = dest + curLen; - dicPos += (SizeT)curLen; - do - *(dest) = (Byte)*(dest + src); - while (++dest != lim); - } - else - { - do - { - dic[dicPos++] = dic[pos]; - if (++pos == dicBufSize) - pos = 0; - } - while (--curLen != 0); - } - } - } - } - while (dicPos < limit && buf < bufLimit); - - NORMALIZE - - p->buf = buf; - p->range = range; - p->code = code; - p->remainLen = (UInt32)len; // & (kMatchSpecLen_Error_Data - 1); // we can write real length for error matches too. - p->dicPos = dicPos; - p->processedPos = processedPos; - p->reps[0] = rep0; - p->reps[1] = rep1; - p->reps[2] = rep2; - p->reps[3] = rep3; - p->state = (UInt32)state; - if (len >= kMatchSpecLen_Error_Data) - return SZ_ERROR_DATA; - return SZ_OK; -} -#endif - - - -static void Z7_FASTCALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) -{ - unsigned len = (unsigned)p->remainLen; - if (len == 0 /* || len >= kMatchSpecLenStart */) - return; - { - SizeT dicPos = p->dicPos; - Byte *dic; - SizeT dicBufSize; - SizeT rep0; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ - { - SizeT rem = limit - dicPos; - if (rem < len) - { - len = (unsigned)(rem); - if (len == 0) - return; - } - } - - if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) - p->checkDicSize = p->prop.dicSize; - - p->processedPos += (UInt32)len; - p->remainLen -= (UInt32)len; - dic = p->dic; - rep0 = p->reps[0]; - dicBufSize = p->dicBufSize; - do - { - dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; - dicPos++; - } - while (--len); - p->dicPos = dicPos; - } -} - - -/* -At staring of new stream we have one of the following symbols: - - Literal - is allowed - - Non-Rep-Match - is allowed only if it's end marker symbol - - Rep-Match - is not allowed -We use early check of (RangeCoder:Code) over kBadRepCode to simplify main decoding code -*/ - -#define kRange0 0xFFFFFFFF -#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) -#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) -#if kBadRepCode != (0xC0000000 - 0x400) - #error Stop_Compiling_Bad_LZMA_Check -#endif - - -/* -LzmaDec_DecodeReal2(): - It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize). - -We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(), -and we support the following state of (p->checkDicSize): - if (total_processed < p->prop.dicSize) then - { - (total_processed == p->processedPos) - (p->checkDicSize == 0) - } - else - (p->checkDicSize == p->prop.dicSize) -*/ - -static int Z7_FASTCALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -{ - if (p->checkDicSize == 0) - { - UInt32 rem = p->prop.dicSize - p->processedPos; - if (limit - p->dicPos > rem) - limit = p->dicPos + rem; - } - { - int res = LZMA_DECODE_REAL(p, limit, bufLimit); - if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) - p->checkDicSize = p->prop.dicSize; - return res; - } -} - - - -typedef enum -{ - DUMMY_INPUT_EOF, /* need more input data */ - DUMMY_LIT, - DUMMY_MATCH, - DUMMY_REP -} ELzmaDummy; - - -#define IS_DUMMY_END_MARKER_POSSIBLE(dummyRes) ((dummyRes) == DUMMY_MATCH) - -static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byte **bufOut) -{ - UInt32 range = p->range; - UInt32 code = p->code; - const Byte *bufLimit = *bufOut; - const CLzmaProb *probs = GET_PROBS; - unsigned state = (unsigned)p->state; - ELzmaDummy res; - - for (;;) - { - const CLzmaProb *prob; - UInt32 bound; - unsigned ttt; - unsigned posState = CALC_POS_STATE(p->processedPos, ((unsigned)1 << p->prop.pb) - 1); - - prob = probs + IsMatch + COMBINED_PS_STATE; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - - prob = probs + Literal; - if (p->checkDicSize != 0 || p->processedPos != 0) - prob += ((UInt32)LZMA_LIT_SIZE * - ((((p->processedPos) & (((unsigned)1 << (p->prop.lp)) - 1)) << p->prop.lc) + - ((unsigned)p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); - - if (state < kNumLitStates) - { - unsigned symbol = 1; - do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); - } - else - { - unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; - unsigned offs = 0x100; - unsigned symbol = 1; - do - { - unsigned bit; - const CLzmaProb *probLit; - matchByte += matchByte; - bit = offs; - offs &= matchByte; - probLit = prob + (offs + bit + symbol); - GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; ) - } - while (symbol < 0x100); - } - res = DUMMY_LIT; - } - else - { - unsigned len; - UPDATE_1_CHECK - - prob = probs + IsRep + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - state = 0; - prob = probs + LenCoder; - res = DUMMY_MATCH; - } - else - { - UPDATE_1_CHECK - res = DUMMY_REP; - prob = probs + IsRepG0 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - prob = probs + IsRep0Long + COMBINED_PS_STATE; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - break; - } - else - { - UPDATE_1_CHECK - } - } - else - { - UPDATE_1_CHECK - prob = probs + IsRepG1 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - } - else - { - UPDATE_1_CHECK - prob = probs + IsRepG2 + state; - IF_BIT_0_CHECK(prob) - { - UPDATE_0_CHECK - } - else - { - UPDATE_1_CHECK - } - } - } - state = kNumStates; - prob = probs + RepLenCoder; - } - { - unsigned limit, offset; - const CLzmaProb *probLen = prob + LenChoice; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK - probLen = prob + LenLow + GET_LEN_STATE; - offset = 0; - limit = 1 << kLenNumLowBits; - } - else - { - UPDATE_1_CHECK - probLen = prob + LenChoice2; - IF_BIT_0_CHECK(probLen) - { - UPDATE_0_CHECK - probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); - offset = kLenNumLowSymbols; - limit = 1 << kLenNumLowBits; - } - else - { - UPDATE_1_CHECK - probLen = prob + LenHigh; - offset = kLenNumLowSymbols * 2; - limit = 1 << kLenNumHighBits; - } - } - TREE_DECODE_CHECK(probLen, limit, len) - len += offset; - } - - if (state < 4) - { - unsigned posSlot; - prob = probs + PosSlot + - ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << - kNumPosSlotBits); - TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot) - if (posSlot >= kStartPosModelIndex) - { - unsigned numDirectBits = ((posSlot >> 1) - 1); - - if (posSlot < kEndPosModelIndex) - { - prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); - } - else - { - numDirectBits -= kNumAlignBits; - do - { - NORMALIZE_CHECK - range >>= 1; - code -= range & (((code - range) >> 31) - 1); - /* if (code >= range) code -= range; */ - } - while (--numDirectBits); - prob = probs + Align; - numDirectBits = kNumAlignBits; - } - { - unsigned i = 1; - unsigned m = 1; - do - { - REV_BIT_CHECK(prob, i, m) - } - while (--numDirectBits); - } - } - } - } - break; - } - NORMALIZE_CHECK - - *bufOut = buf; - return res; -} - -void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); -void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) -{ - p->remainLen = kMatchSpecLenStart + 1; - p->tempBufSize = 0; - - if (initDic) - { - p->processedPos = 0; - p->checkDicSize = 0; - p->remainLen = kMatchSpecLenStart + 2; - } - if (initState) - p->remainLen = kMatchSpecLenStart + 2; -} - -void LzmaDec_Init(CLzmaDec *p) -{ - p->dicPos = 0; - LzmaDec_InitDicAndState(p, True, True); -} - - -/* -LZMA supports optional end_marker. -So the decoder can lookahead for one additional LZMA-Symbol to check end_marker. -That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream. -When the decoder reaches dicLimit, it looks (finishMode) parameter: - if (finishMode == LZMA_FINISH_ANY), the decoder doesn't lookahead - if (finishMode != LZMA_FINISH_ANY), the decoder lookahead, if end_marker is possible for current position - -When the decoder lookahead, and the lookahead symbol is not end_marker, we have two ways: - 1) Strict mode (default) : the decoder returns SZ_ERROR_DATA. - 2) The relaxed mode (alternative mode) : we could return SZ_OK, and the caller - must check (status) value. The caller can show the error, - if the end of stream is expected, and the (status) is noit - LZMA_STATUS_FINISHED_WITH_MARK or LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK. -*/ - - -#define RETURN_NOT_FINISHED_FOR_FINISH \ - *status = LZMA_STATUS_NOT_FINISHED; \ - return SZ_ERROR_DATA; // for strict mode - // return SZ_OK; // for relaxed mode - - -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, - ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT inSize = *srcLen; - (*srcLen) = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - - if (p->remainLen > kMatchSpecLenStart) - { - if (p->remainLen > kMatchSpecLenStart + 2) - return p->remainLen == kMatchSpecLen_Error_Fail ? SZ_ERROR_FAIL : SZ_ERROR_DATA; - - for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) - p->tempBuf[p->tempBufSize++] = *src++; - if (p->tempBufSize != 0 && p->tempBuf[0] != 0) - return SZ_ERROR_DATA; - if (p->tempBufSize < RC_INIT_SIZE) - { - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - p->code = - ((UInt32)p->tempBuf[1] << 24) - | ((UInt32)p->tempBuf[2] << 16) - | ((UInt32)p->tempBuf[3] << 8) - | ((UInt32)p->tempBuf[4]); - - if (p->checkDicSize == 0 - && p->processedPos == 0 - && p->code >= kBadRepCode) - return SZ_ERROR_DATA; - - p->range = 0xFFFFFFFF; - p->tempBufSize = 0; - - if (p->remainLen > kMatchSpecLenStart + 1) - { - SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); - SizeT i; - CLzmaProb *probs = p->probs; - for (i = 0; i < numProbs; i++) - probs[i] = kBitModelTotal >> 1; - p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; - p->state = 0; - } - - p->remainLen = 0; - } - - for (;;) - { - if (p->remainLen == kMatchSpecLenStart) - { - if (p->code != 0) - return SZ_ERROR_DATA; - *status = LZMA_STATUS_FINISHED_WITH_MARK; - return SZ_OK; - } - - LzmaDec_WriteRem(p, dicLimit); - - { - // (p->remainLen == 0 || p->dicPos == dicLimit) - - int checkEndMarkNow = 0; - - if (p->dicPos >= dicLimit) - { - if (p->remainLen == 0 && p->code == 0) - { - *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; - return SZ_OK; - } - if (finishMode == LZMA_FINISH_ANY) - { - *status = LZMA_STATUS_NOT_FINISHED; - return SZ_OK; - } - if (p->remainLen != 0) - { - RETURN_NOT_FINISHED_FOR_FINISH - } - checkEndMarkNow = 1; - } - - // (p->remainLen == 0) - - if (p->tempBufSize == 0) - { - const Byte *bufLimit; - int dummyProcessed = -1; - - if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - const Byte *bufOut = src + inSize; - - ELzmaDummy dummyRes = LzmaDec_TryDummy(p, src, &bufOut); - - if (dummyRes == DUMMY_INPUT_EOF) - { - size_t i; - if (inSize >= LZMA_REQUIRED_INPUT_MAX) - break; - (*srcLen) += inSize; - p->tempBufSize = (unsigned)inSize; - for (i = 0; i < inSize; i++) - p->tempBuf[i] = src[i]; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - dummyProcessed = (int)(bufOut - src); - if ((unsigned)dummyProcessed > LZMA_REQUIRED_INPUT_MAX) - break; - - if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) - { - unsigned i; - (*srcLen) += (unsigned)dummyProcessed; - p->tempBufSize = (unsigned)dummyProcessed; - for (i = 0; i < (unsigned)dummyProcessed; i++) - p->tempBuf[i] = src[i]; - // p->remainLen = kMatchSpecLen_Error_Data; - RETURN_NOT_FINISHED_FOR_FINISH - } - - bufLimit = src; - // we will decode only one iteration - } - else - bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; - - p->buf = src; - - { - int res = LzmaDec_DecodeReal2(p, dicLimit, bufLimit); - - SizeT processed = (SizeT)(p->buf - src); - - if (dummyProcessed < 0) - { - if (processed > inSize) - break; - } - else if ((unsigned)dummyProcessed != processed) - break; - - src += processed; - inSize -= processed; - (*srcLen) += processed; - - if (res != SZ_OK) - { - p->remainLen = kMatchSpecLen_Error_Data; - return SZ_ERROR_DATA; - } - } - continue; - } - - { - // we have some data in (p->tempBuf) - // in strict mode: tempBufSize is not enough for one Symbol decoding. - // in relaxed mode: tempBufSize not larger than required for one Symbol decoding. - - unsigned rem = p->tempBufSize; - unsigned ahead = 0; - int dummyProcessed = -1; - - while (rem < LZMA_REQUIRED_INPUT_MAX && ahead < inSize) - p->tempBuf[rem++] = src[ahead++]; - - // ahead - the size of new data copied from (src) to (p->tempBuf) - // rem - the size of temp buffer including new data from (src) - - if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) - { - const Byte *bufOut = p->tempBuf + rem; - - ELzmaDummy dummyRes = LzmaDec_TryDummy(p, p->tempBuf, &bufOut); - - if (dummyRes == DUMMY_INPUT_EOF) - { - if (rem >= LZMA_REQUIRED_INPUT_MAX) - break; - p->tempBufSize = rem; - (*srcLen) += (SizeT)ahead; - *status = LZMA_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - dummyProcessed = (int)(bufOut - p->tempBuf); - - if ((unsigned)dummyProcessed < p->tempBufSize) - break; - - if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) - { - (*srcLen) += (unsigned)dummyProcessed - p->tempBufSize; - p->tempBufSize = (unsigned)dummyProcessed; - // p->remainLen = kMatchSpecLen_Error_Data; - RETURN_NOT_FINISHED_FOR_FINISH - } - } - - p->buf = p->tempBuf; - - { - // we decode one symbol from (p->tempBuf) here, so the (bufLimit) is equal to (p->buf) - int res = LzmaDec_DecodeReal2(p, dicLimit, p->buf); - - SizeT processed = (SizeT)(p->buf - p->tempBuf); - rem = p->tempBufSize; - - if (dummyProcessed < 0) - { - if (processed > LZMA_REQUIRED_INPUT_MAX) - break; - if (processed < rem) - break; - } - else if ((unsigned)dummyProcessed != processed) - break; - - processed -= rem; - - src += processed; - inSize -= processed; - (*srcLen) += processed; - p->tempBufSize = 0; - - if (res != SZ_OK) - { - p->remainLen = kMatchSpecLen_Error_Data; - return SZ_ERROR_DATA; - } - } - } - } - } - - /* Some unexpected error: internal error of code, memory corruption or hardware failure */ - p->remainLen = kMatchSpecLen_Error_Fail; - return SZ_ERROR_FAIL; -} - - - -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -{ - SizeT outSize = *destLen; - SizeT inSize = *srcLen; - *srcLen = *destLen = 0; - for (;;) - { - SizeT inSizeCur = inSize, outSizeCur, dicPos; - ELzmaFinishMode curFinishMode; - SRes res; - if (p->dicPos == p->dicBufSize) - p->dicPos = 0; - dicPos = p->dicPos; - if (outSize > p->dicBufSize - dicPos) - { - outSizeCur = p->dicBufSize; - curFinishMode = LZMA_FINISH_ANY; - } - else - { - outSizeCur = dicPos + outSize; - curFinishMode = finishMode; - } - - res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); - src += inSizeCur; - inSize -= inSizeCur; - *srcLen += inSizeCur; - outSizeCur = p->dicPos - dicPos; - memcpy(dest, p->dic + dicPos, outSizeCur); - dest += outSizeCur; - outSize -= outSizeCur; - *destLen += outSizeCur; - if (res != 0) - return res; - if (outSizeCur == 0 || outSize == 0) - return SZ_OK; - } -} - -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->probs); - p->probs = NULL; -} - -static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->dic); - p->dic = NULL; -} - -void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc) -{ - LzmaDec_FreeProbs(p, alloc); - LzmaDec_FreeDict(p, alloc); -} - -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) -{ - UInt32 dicSize; - Byte d; - - if (size < LZMA_PROPS_SIZE) - return SZ_ERROR_UNSUPPORTED; - else - dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); - - if (dicSize < LZMA_DIC_MIN) - dicSize = LZMA_DIC_MIN; - p->dicSize = dicSize; - - d = data[0]; - if (d >= (9 * 5 * 5)) - return SZ_ERROR_UNSUPPORTED; - - p->lc = (Byte)(d % 9); - d /= 9; - p->pb = (Byte)(d / 5); - p->lp = (Byte)(d % 5); - - return SZ_OK; -} - -static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc) -{ - UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (!p->probs || numProbs != p->numProbs) - { - LzmaDec_FreeProbs(p, alloc); - p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb)); - if (!p->probs) - return SZ_ERROR_MEM; - p->probs_1664 = p->probs + 1664; - p->numProbs = numProbs; - } - return SZ_OK; -} - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) -{ - CLzmaProps propNew; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)) - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)) - p->prop = propNew; - return SZ_OK; -} - -SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) -{ - CLzmaProps propNew; - SizeT dicBufSize; - RINOK(LzmaProps_Decode(&propNew, props, propsSize)) - RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)) - - { - UInt32 dictSize = propNew.dicSize; - SizeT mask = ((UInt32)1 << 12) - 1; - if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; - else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1; - dicBufSize = ((SizeT)dictSize + mask) & ~mask; - if (dicBufSize < dictSize) - dicBufSize = dictSize; - } - - if (!p->dic || dicBufSize != p->dicBufSize) - { - LzmaDec_FreeDict(p, alloc); - p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize); - if (!p->dic) - { - LzmaDec_FreeProbs(p, alloc); - return SZ_ERROR_MEM; - } - } - p->dicBufSize = dicBufSize; - p->prop = propNew; - return SZ_OK; -} - -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAllocPtr alloc) -{ - CLzmaDec p; - SRes res; - SizeT outSize = *destLen, inSize = *srcLen; - *destLen = *srcLen = 0; - *status = LZMA_STATUS_NOT_SPECIFIED; - if (inSize < RC_INIT_SIZE) - return SZ_ERROR_INPUT_EOF; - LzmaDec_CONSTRUCT(&p) - RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)) - p.dic = dest; - p.dicBufSize = outSize; - LzmaDec_Init(&p); - *srcLen = inSize; - res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); - *destLen = p.dicPos; - if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - LzmaDec_FreeProbs(&p, alloc); - return res; -} +/* LzmaDec.c -- LZMA Decoder +2023-04-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #include "CpuArch.h" */ +#include "LzmaDec.h" + +// #define kNumTopBits 24 +#define kTopValue ((UInt32)1 << 24) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) + +#define RC_INIT_SIZE 5 + +#ifndef Z7_LZMA_DEC_OPT + +#define kNumMoveBits 5 +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p) i = (i + i); A0; } else \ + { UPDATE_1(p) i = (i + i) + 1; A1; } + +#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); } + +#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \ + { UPDATE_0(p + i) A0; } else \ + { UPDATE_1(p + i) A1; } +#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; ) +#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; ) +#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; ) + +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define Z7_LZMA_SIZE_OPT */ + +#ifdef Z7_LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + TREE_GET_BIT(probs, i) \ + i -= 0x40; } +#endif + +#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol) +#define MATCHED_LITER_DEC \ + matchByte += matchByte; \ + bit = offs; \ + offs &= matchByte; \ + probLit = prob + (offs + bit + symbol); \ + GET_BIT2(probLit, symbol, offs ^= bit; , ;) + +#endif // Z7_LZMA_DEC_OPT + + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_INPUT_EOF; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK i = (i + i); A0; } else \ + { UPDATE_1_CHECK i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \ + { UPDATE_0_CHECK i += m; m += m; } else \ + { UPDATE_1_CHECK m += m; i += m; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenLow 0 +#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + +#define LenChoice LenLow +#define LenChoice2 (LenLow + (1 << kLenNumLowBits)) + +#define kNumStates 12 +#define kNumStates2 16 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +#define kMatchSpecLen_Error_Data (1 << 9) +#define kMatchSpecLen_Error_Fail (kMatchSpecLen_Error_Data - 1) + +/* External ASM code needs same CLzmaProb array layout. So don't change it. */ + +/* (probs_1664) is faster and better for code size at some platforms */ +/* +#ifdef MY_CPU_X86_OR_AMD64 +*/ +#define kStartOffset 1664 +#define GET_PROBS p->probs_1664 +/* +#define GET_PROBS p->probs + kStartOffset +#else +#define kStartOffset 0 +#define GET_PROBS p->probs +#endif +*/ + +#define SpecPos (-kStartOffset) +#define IsRep0Long (SpecPos + kNumFullDistances) +#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax)) +#define LenCoder (RepLenCoder + kNumLenProbs) +#define IsMatch (LenCoder + kNumLenProbs) +#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax)) +#define IsRep (Align + kAlignTableSize) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define PosSlot (IsRepG2 + kNumStates) +#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define NUM_BASE_PROBS (Literal + kStartOffset) + +#if Align != 0 && kStartOffset != 0 + #error Stop_Compiling_Bad_LZMA_kAlign +#endif + +#if NUM_BASE_PROBS != 1984 + #error Stop_Compiling_Bad_LZMA_PROBS +#endif + + +#define LZMA_LIT_SIZE 0x300 + +#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + + +#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4) +#define COMBINED_PS_STATE (posState + state) +#define GET_LEN_STATE (posState) + +#define LZMA_DIC_MIN (1 << 12) + +/* +p->remainLen : shows status of LZMA decoder: + < kMatchSpecLenStart : the number of bytes to be copied with (p->rep0) offset + = kMatchSpecLenStart : the LZMA stream was finished with end mark + = kMatchSpecLenStart + 1 : need init range coder + = kMatchSpecLenStart + 2 : need init range coder and state + = kMatchSpecLen_Error_Fail : Internal Code Failure + = kMatchSpecLen_Error_Data + [0 ... 273] : LZMA Data Error +*/ + +/* ---------- LZMA_DECODE_REAL ---------- */ +/* +LzmaDec_DecodeReal_3() can be implemented in external ASM file. +3 - is the code compatibility version of that function for check at link time. +*/ + +#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3 + +/* +LZMA_DECODE_REAL() +In: + RangeCoder is normalized + if (p->dicPos == limit) + { + LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases. + So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol + is not END_OF_PAYALOAD_MARKER, then the function doesn't write any byte to dictionary, + the function returns SZ_OK, and the caller can use (p->remainLen) and (p->reps[0]) later. + } + +Processing: + The first LZMA symbol will be decoded in any case. + All main checks for limits are at the end of main loop, + It decodes additional LZMA-symbols while (p->buf < bufLimit && dicPos < limit), + RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked. + But if (p->buf < bufLimit), the caller provided at least (LZMA_REQUIRED_INPUT_MAX + 1) bytes for + next iteration before limit (bufLimit + LZMA_REQUIRED_INPUT_MAX), + that is enough for worst case LZMA symbol with one additional RangeCoder normalization for one bit. + So that function never reads bufLimit [LZMA_REQUIRED_INPUT_MAX] byte. + +Out: + RangeCoder is normalized + Result: + SZ_OK - OK + p->remainLen: + < kMatchSpecLenStart : the number of bytes to be copied with (p->reps[0]) offset + = kMatchSpecLenStart : the LZMA stream was finished with end mark + + SZ_ERROR_DATA - error, when the MATCH-Symbol refers out of dictionary + p->remainLen : undefined + p->reps[*] : undefined +*/ + + +#ifdef Z7_LZMA_DEC_OPT + +int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit); + +#else + +static +int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = GET_PROBS; + unsigned state = (unsigned)p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lc = p->prop.lc; + unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc); + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = CALC_POS_STATE(processedPos, pbMask); + + prob = probs + IsMatch + COMBINED_PS_STATE; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob) + prob = probs + Literal; + if (processedPos != 0 || checkDicSize != 0) + prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc); + processedPos++; + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + #ifdef Z7_LZMA_SIZE_OPT + do { NORMAL_LITER_DEC } while (symbol < 0x100); + #else + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + NORMAL_LITER_DEC + #endif + } + else + { + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + #ifdef Z7_LZMA_SIZE_OPT + do + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + } + while (symbol < 0x100); + #else + { + unsigned bit; + CLzmaProb *probLit; + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + MATCHED_LITER_DEC + } + #endif + } + + dic[dicPos++] = (Byte)symbol; + continue; + } + + { + UPDATE_1(prob) + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob) + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob) + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob) + prob = probs + IsRep0Long + COMBINED_PS_STATE; + IF_BIT_0(prob) + { + UPDATE_0(prob) + + // that case was checked before with kBadRepCode + // if (checkDicSize == 0 && processedPos == 0) { len = kMatchSpecLen_Error_Data + 1; break; } + // The caller doesn't allow (dicPos == limit) case here + // so we don't need the following check: + // if (dicPos == limit) { state = state < kNumLitStates ? 9 : 11; len = 1; break; } + + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob) + } + else + { + UInt32 distance; + UPDATE_1(prob) + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob) + distance = rep1; + } + else + { + UPDATE_1(prob) + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob) + distance = rep2; + } + else + { + UPDATE_1(prob) + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + + #ifdef Z7_LZMA_SIZE_OPT + { + unsigned lim, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen) + probLen = prob + LenLow + GET_LEN_STATE; + offset = 0; + lim = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen) + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen) + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + offset = kLenNumLowSymbols; + lim = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen) + probLen = prob + LenHigh; + offset = kLenNumLowSymbols * 2; + lim = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, lim, len) + len += offset; + } + #else + { + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen) + probLen = prob + LenLow + GET_LEN_STATE; + len = 1; + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) + len -= 8; + } + else + { + UPDATE_1(probLen) + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen) + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) + TREE_GET_BIT(probLen, len) + } + else + { + UPDATE_1(probLen) + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len) + len += kLenNumLowSymbols * 2; + } + } + } + #endif + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance) + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos; + { + UInt32 m = 1; + distance++; + do + { + REV_BIT_VAR(prob, distance, m) + } + while (--numDirectBits); + distance -= m; + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + REV_BIT_CONST(prob, i, 1) + REV_BIT_CONST(prob, i, 2) + REV_BIT_CONST(prob, i, 4) + REV_BIT_LAST (prob, i, 8) + distance |= i; + } + if (distance == (UInt32)0xFFFFFFFF) + { + len = kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize)) + { + len += kMatchSpecLen_Error_Data + kMatchMinLen; + // len = kMatchSpecLen_Error_Data; + // len += kMatchMinLen; + break; + } + } + + len += kMatchMinLen; + + { + SizeT rem; + unsigned curLen; + SizeT pos; + + if ((rem = limit - dicPos) == 0) + { + /* + We stop decoding and return SZ_OK, and we can resume decoding later. + Any error conditions can be tested later in caller code. + For more strict mode we can stop decoding with error + // len += kMatchSpecLen_Error_Data; + */ + break; + } + + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); + + processedPos += (UInt32)curLen; + + len -= curLen; + if (curLen <= dicBufSize - pos) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += (SizeT)curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + + NORMALIZE + + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = (UInt32)len; // & (kMatchSpecLen_Error_Data - 1); // we can write real length for error matches too. + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = (UInt32)state; + if (len >= kMatchSpecLen_Error_Data) + return SZ_ERROR_DATA; + return SZ_OK; +} +#endif + + + +static void Z7_FASTCALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + unsigned len = (unsigned)p->remainLen; + if (len == 0 /* || len >= kMatchSpecLenStart */) + return; + { + SizeT dicPos = p->dicPos; + Byte *dic; + SizeT dicBufSize; + SizeT rep0; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + { + SizeT rem = limit - dicPos; + if (rem < len) + { + len = (unsigned)(rem); + if (len == 0) + return; + } + } + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += (UInt32)len; + p->remainLen -= (UInt32)len; + dic = p->dic; + rep0 = p->reps[0]; + dicBufSize = p->dicBufSize; + do + { + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; + dicPos++; + } + while (--len); + p->dicPos = dicPos; + } +} + + +/* +At staring of new stream we have one of the following symbols: + - Literal - is allowed + - Non-Rep-Match - is allowed only if it's end marker symbol + - Rep-Match - is not allowed +We use early check of (RangeCoder:Code) over kBadRepCode to simplify main decoding code +*/ + +#define kRange0 0xFFFFFFFF +#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)) +#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))) +#if kBadRepCode != (0xC0000000 - 0x400) + #error Stop_Compiling_Bad_LZMA_Check +#endif + + +/* +LzmaDec_DecodeReal2(): + It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize). + +We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(), +and we support the following state of (p->checkDicSize): + if (total_processed < p->prop.dicSize) then + { + (total_processed == p->processedPos) + (p->checkDicSize == 0) + } + else + (p->checkDicSize == p->prop.dicSize) +*/ + +static int Z7_FASTCALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit = p->dicPos + rem; + } + { + int res = LZMA_DECODE_REAL(p, limit, bufLimit); + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + return res; + } +} + + + +typedef enum +{ + DUMMY_INPUT_EOF, /* need more input data */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + + +#define IS_DUMMY_END_MARKER_POSSIBLE(dummyRes) ((dummyRes) == DUMMY_MATCH) + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byte **bufOut) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = *bufOut; + const CLzmaProb *probs = GET_PROBS; + unsigned state = (unsigned)p->state; + ELzmaDummy res; + + for (;;) + { + const CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = CALC_POS_STATE(p->processedPos, ((unsigned)1 << p->prop.pb) - 1); + + prob = probs + IsMatch + COMBINED_PS_STATE; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & (((unsigned)1 << (p->prop.lp)) - 1)) << p->prop.lc) + + ((unsigned)p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + const CLzmaProb *probLit; + matchByte += matchByte; + bit = offs; + offs &= matchByte; + probLit = prob + (offs + bit + symbol); + GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; ) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + prob = probs + IsRep0Long + COMBINED_PS_STATE; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + break; + } + else + { + UPDATE_1_CHECK + } + } + else + { + UPDATE_1_CHECK + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + } + else + { + UPDATE_1_CHECK + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + } + else + { + UPDATE_1_CHECK + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + const CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK + probLen = prob + LenLow + GET_LEN_STATE; + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK + probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK + probLen = prob + LenHigh; + offset = kLenNumLowSymbols * 2; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len) + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot) + if (posSlot >= kStartPosModelIndex) + { + unsigned numDirectBits = ((posSlot >> 1) - 1); + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + unsigned m = 1; + do + { + REV_BIT_CHECK(prob, i, m) + } + while (--numDirectBits); + } + } + } + } + break; + } + NORMALIZE_CHECK + + *bufOut = buf; + return res; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState); +void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState) +{ + p->remainLen = kMatchSpecLenStart + 1; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->remainLen = kMatchSpecLenStart + 2; + } + if (initState) + p->remainLen = kMatchSpecLenStart + 2; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + + +/* +LZMA supports optional end_marker. +So the decoder can lookahead for one additional LZMA-Symbol to check end_marker. +That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream. +When the decoder reaches dicLimit, it looks (finishMode) parameter: + if (finishMode == LZMA_FINISH_ANY), the decoder doesn't lookahead + if (finishMode != LZMA_FINISH_ANY), the decoder lookahead, if end_marker is possible for current position + +When the decoder lookahead, and the lookahead symbol is not end_marker, we have two ways: + 1) Strict mode (default) : the decoder returns SZ_ERROR_DATA. + 2) The relaxed mode (alternative mode) : we could return SZ_OK, and the caller + must check (status) value. The caller can show the error, + if the end of stream is expected, and the (status) is noit + LZMA_STATUS_FINISHED_WITH_MARK or LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK. +*/ + + +#define RETURN_NOT_FINISHED_FOR_FINISH \ + *status = LZMA_STATUS_NOT_FINISHED; \ + return SZ_ERROR_DATA; // for strict mode + // return SZ_OK; // for relaxed mode + + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + + if (p->remainLen > kMatchSpecLenStart) + { + if (p->remainLen > kMatchSpecLenStart + 2) + return p->remainLen == kMatchSpecLen_Error_Fail ? SZ_ERROR_FAIL : SZ_ERROR_DATA; + + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize != 0 && p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + + if (p->checkDicSize == 0 + && p->processedPos == 0 + && p->code >= kBadRepCode) + return SZ_ERROR_DATA; + + p->range = 0xFFFFFFFF; + p->tempBufSize = 0; + + if (p->remainLen > kMatchSpecLenStart + 1) + { + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + } + + p->remainLen = 0; + } + + for (;;) + { + if (p->remainLen == kMatchSpecLenStart) + { + if (p->code != 0) + return SZ_ERROR_DATA; + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + + LzmaDec_WriteRem(p, dicLimit); + + { + // (p->remainLen == 0 || p->dicPos == dicLimit) + + int checkEndMarkNow = 0; + + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + RETURN_NOT_FINISHED_FOR_FINISH + } + checkEndMarkNow = 1; + } + + // (p->remainLen == 0) + + if (p->tempBufSize == 0) + { + const Byte *bufLimit; + int dummyProcessed = -1; + + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + const Byte *bufOut = src + inSize; + + ELzmaDummy dummyRes = LzmaDec_TryDummy(p, src, &bufOut); + + if (dummyRes == DUMMY_INPUT_EOF) + { + size_t i; + if (inSize >= LZMA_REQUIRED_INPUT_MAX) + break; + (*srcLen) += inSize; + p->tempBufSize = (unsigned)inSize; + for (i = 0; i < inSize; i++) + p->tempBuf[i] = src[i]; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + dummyProcessed = (int)(bufOut - src); + if ((unsigned)dummyProcessed > LZMA_REQUIRED_INPUT_MAX) + break; + + if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) + { + unsigned i; + (*srcLen) += (unsigned)dummyProcessed; + p->tempBufSize = (unsigned)dummyProcessed; + for (i = 0; i < (unsigned)dummyProcessed; i++) + p->tempBuf[i] = src[i]; + // p->remainLen = kMatchSpecLen_Error_Data; + RETURN_NOT_FINISHED_FOR_FINISH + } + + bufLimit = src; + // we will decode only one iteration + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + + p->buf = src; + + { + int res = LzmaDec_DecodeReal2(p, dicLimit, bufLimit); + + SizeT processed = (SizeT)(p->buf - src); + + if (dummyProcessed < 0) + { + if (processed > inSize) + break; + } + else if ((unsigned)dummyProcessed != processed) + break; + + src += processed; + inSize -= processed; + (*srcLen) += processed; + + if (res != SZ_OK) + { + p->remainLen = kMatchSpecLen_Error_Data; + return SZ_ERROR_DATA; + } + } + continue; + } + + { + // we have some data in (p->tempBuf) + // in strict mode: tempBufSize is not enough for one Symbol decoding. + // in relaxed mode: tempBufSize not larger than required for one Symbol decoding. + + unsigned rem = p->tempBufSize; + unsigned ahead = 0; + int dummyProcessed = -1; + + while (rem < LZMA_REQUIRED_INPUT_MAX && ahead < inSize) + p->tempBuf[rem++] = src[ahead++]; + + // ahead - the size of new data copied from (src) to (p->tempBuf) + // rem - the size of temp buffer including new data from (src) + + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + const Byte *bufOut = p->tempBuf + rem; + + ELzmaDummy dummyRes = LzmaDec_TryDummy(p, p->tempBuf, &bufOut); + + if (dummyRes == DUMMY_INPUT_EOF) + { + if (rem >= LZMA_REQUIRED_INPUT_MAX) + break; + p->tempBufSize = rem; + (*srcLen) += (SizeT)ahead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + dummyProcessed = (int)(bufOut - p->tempBuf); + + if ((unsigned)dummyProcessed < p->tempBufSize) + break; + + if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes)) + { + (*srcLen) += (unsigned)dummyProcessed - p->tempBufSize; + p->tempBufSize = (unsigned)dummyProcessed; + // p->remainLen = kMatchSpecLen_Error_Data; + RETURN_NOT_FINISHED_FOR_FINISH + } + } + + p->buf = p->tempBuf; + + { + // we decode one symbol from (p->tempBuf) here, so the (bufLimit) is equal to (p->buf) + int res = LzmaDec_DecodeReal2(p, dicLimit, p->buf); + + SizeT processed = (SizeT)(p->buf - p->tempBuf); + rem = p->tempBufSize; + + if (dummyProcessed < 0) + { + if (processed > LZMA_REQUIRED_INPUT_MAX) + break; + if (processed < rem) + break; + } + else if ((unsigned)dummyProcessed != processed) + break; + + processed -= rem; + + src += processed; + inSize -= processed; + (*srcLen) += processed; + p->tempBufSize = 0; + + if (res != SZ_OK) + { + p->remainLen = kMatchSpecLen_Error_Data; + return SZ_ERROR_DATA; + } + } + } + } + } + + /* Some unexpected error: internal error of code, memory corruption or hardware failure */ + p->remainLen = kMatchSpecLen_Error_Fail; + return SZ_ERROR_FAIL; +} + + + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->probs); + p->probs = NULL; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->dic); + p->dic = NULL; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = (Byte)(d % 9); + d /= 9; + p->pb = (Byte)(d / 5); + p->lp = (Byte)(d % 5); + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (!p->probs || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb)); + if (!p->probs) + return SZ_ERROR_MEM; + p->probs_1664 = p->probs + 1664; + p->numProbs = numProbs; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)) + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)) + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)) + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)) + + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } + + if (!p->dic || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize); + if (!p->dic) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAllocPtr alloc) +{ + CLzmaDec p; + SRes res; + SizeT outSize = *destLen, inSize = *srcLen; + *destLen = *srcLen = 0; + *status = LZMA_STATUS_NOT_SPECIFIED; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + LzmaDec_CONSTRUCT(&p) + RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)) + p.dic = dest; + p.dicBufSize = outSize; + LzmaDec_Init(&p); + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + *destLen = p.dicPos; + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/C/LzmaDec.h b/C/LzmaDec.h index 6432f6085..b0ce28fa0 100644 --- a/C/LzmaDec.h +++ b/C/LzmaDec.h @@ -1,237 +1,237 @@ -/* LzmaDec.h -- LZMA Decoder -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA_DEC_H -#define ZIP7_INC_LZMA_DEC_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -/* #define Z7_LZMA_PROB32 */ -/* Z7_LZMA_PROB32 can increase the speed on some CPUs, - but memory usage for CLzmaDec::probs will be doubled in that case */ - -typedef -#ifdef Z7_LZMA_PROB32 - UInt32 -#else - UInt16 -#endif - CLzmaProb; - - -/* ---------- LZMA Properties ---------- */ - -#define LZMA_PROPS_SIZE 5 - -typedef struct -{ - Byte lc; - Byte lp; - Byte pb; - Byte _pad_; - UInt32 dicSize; -} CLzmaProps; - -/* LzmaProps_Decode - decodes properties -Returns: - SZ_OK - SZ_ERROR_UNSUPPORTED - Unsupported properties -*/ - -SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); - - -/* ---------- LZMA Decoder state ---------- */ - -/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. - Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ - -#define LZMA_REQUIRED_INPUT_MAX 20 - -typedef struct -{ - /* Don't change this structure. ASM code can use it. */ - CLzmaProps prop; - CLzmaProb *probs; - CLzmaProb *probs_1664; - Byte *dic; - SizeT dicBufSize; - SizeT dicPos; - const Byte *buf; - UInt32 range; - UInt32 code; - UInt32 processedPos; - UInt32 checkDicSize; - UInt32 reps[4]; - UInt32 state; - UInt32 remainLen; - - UInt32 numProbs; - unsigned tempBufSize; - Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; -} CLzmaDec; - -#define LzmaDec_CONSTRUCT(p) { (p)->dic = NULL; (p)->probs = NULL; } -#define LzmaDec_Construct(p) LzmaDec_CONSTRUCT(p) - -void LzmaDec_Init(CLzmaDec *p); - -/* There are two types of LZMA streams: - - Stream with end mark. That end mark adds about 6 bytes to compressed size. - - Stream without end mark. You must know exact uncompressed size to decompress such stream. */ - -typedef enum -{ - LZMA_FINISH_ANY, /* finish at any point */ - LZMA_FINISH_END /* block must be finished at the end */ -} ELzmaFinishMode; - -/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! - - You must use LZMA_FINISH_END, when you know that current output buffer - covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. - - If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, - and output value of destLen will be less than output buffer size limit. - You can check status result also. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - -typedef enum -{ - LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ - LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ - LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ -} ELzmaStatus; - -/* ELzmaStatus is used only as output value for function call */ - - -/* ---------- Interfaces ---------- */ - -/* There are 3 levels of interfaces: - 1) Dictionary Interface - 2) Buffer Interface - 3) One Call Interface - You can select any of these interfaces, but don't mix functions from different - groups for same object. */ - - -/* There are two variants to allocate state for Dictionary Interface: - 1) LzmaDec_Allocate / LzmaDec_Free - 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs - You can use variant 2, if you set dictionary buffer manually. - For Buffer Interface you must always use variant 1. - -LzmaDec_Allocate* can return: - SZ_OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties -*/ - -SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); -void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc); - -SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); -void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); - -/* ---------- Dictionary Interface ---------- */ - -/* You can use it, if you want to eliminate the overhead for data copying from - dictionary to some other external buffer. - You must work with CLzmaDec variables directly in this interface. - - STEPS: - LzmaDec_Construct() - LzmaDec_Allocate() - for (each new stream) - { - LzmaDec_Init() - while (it needs more decompression) - { - LzmaDec_DecodeToDic() - use data from CLzmaDec::dic and update CLzmaDec::dicPos - } - } - LzmaDec_Free() -*/ - -/* LzmaDec_DecodeToDic - - The decoding to internal dictionary buffer (CLzmaDec::dic). - You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! - -finishMode: - It has meaning only if the decoding reaches output limit (dicLimit). - LZMA_FINISH_ANY - Decode just dicLimit bytes. - LZMA_FINISH_END - Stream must be finished after dicLimit. - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_NEEDS_MORE_INPUT - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure -*/ - -SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- Buffer Interface ---------- */ - -/* It's zlib-like interface. - See LzmaDec_DecodeToDic description for information about STEPS and return results, - but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need - to work with CLzmaDec variables manually. - -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). -*/ - -SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); - - -/* ---------- One Call Interface ---------- */ - -/* LzmaDecode - -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - -Returns: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). - SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure -*/ - -SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAllocPtr alloc); - -EXTERN_C_END - -#endif +/* LzmaDec.h -- LZMA Decoder +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA_DEC_H +#define ZIP7_INC_LZMA_DEC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +/* #define Z7_LZMA_PROB32 */ +/* Z7_LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +typedef +#ifdef Z7_LZMA_PROB32 + UInt32 +#else + UInt16 +#endif + CLzmaProb; + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct +{ + Byte lc; + Byte lp; + Byte pb; + Byte _pad_; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + /* Don't change this structure. ASM code can use it. */ + CLzmaProps prop; + CLzmaProb *probs; + CLzmaProb *probs_1664; + Byte *dic; + SizeT dicBufSize; + SizeT dicPos; + const Byte *buf; + UInt32 range; + UInt32 code; + UInt32 processedPos; + UInt32 checkDicSize; + UInt32 reps[4]; + UInt32 state; + UInt32 remainLen; + + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_CONSTRUCT(p) { (p)->dic = NULL; (p)->probs = NULL; } +#define LzmaDec_Construct(p) LzmaDec_CONSTRUCT(p) + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + - Stream with end mark. That end mark adds about 6 bytes to compressed size. + - Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc); + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc); +void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Construct() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAllocPtr alloc); + +EXTERN_C_END + +#endif diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c index 5f79d54b8..088b78f8b 100644 --- a/C/LzmaEnc.c +++ b/C/LzmaEnc.c @@ -1,3144 +1,3144 @@ -/* LzmaEnc.c -- LZMA Encoder -2024-01-24: Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -/* #define SHOW_STAT */ -/* #define SHOW_STAT2 */ - -#if defined(SHOW_STAT) || defined(SHOW_STAT2) -#include -#endif - -#include "CpuArch.h" -#include "LzmaEnc.h" - -#include "LzFind.h" -#ifndef Z7_ST -#include "LzFindMt.h" -#endif - -/* the following LzmaEnc_* declarations is internal LZMA interface for LZMA2 encoder */ - -SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize, - ISzAllocPtr alloc, ISzAllocPtr allocBig); -SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen, - UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); -SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, - Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); -const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p); -void LzmaEnc_Finish(CLzmaEncHandle p); -void LzmaEnc_SaveState(CLzmaEncHandle p); -void LzmaEnc_RestoreState(CLzmaEncHandle p); - -#ifdef SHOW_STAT -static unsigned g_STAT_OFFSET = 0; -#endif - -/* for good normalization speed we still reserve 256 MB before 4 GB range */ -#define kLzmaMaxHistorySize ((UInt32)15 << 28) - -// #define kNumTopBits 24 -#define kTopValue ((UInt32)1 << 24) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) -#define kNumMoveBits 5 -#define kProbInitValue (kBitModelTotal >> 1) - -#define kNumMoveReducingBits 4 -#define kNumBitPriceShiftBits 4 -// #define kBitPrice (1 << kNumBitPriceShiftBits) - -#define REP_LEN_COUNT 64 - -void LzmaEncProps_Init(CLzmaEncProps *p) -{ - p->level = 5; - p->dictSize = p->mc = 0; - p->reduceSize = (UInt64)(Int64)-1; - p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; - p->numHashOutBits = 0; - p->writeEndMark = 0; - p->affinity = 0; -} - -void LzmaEncProps_Normalize(CLzmaEncProps *p) -{ - int level = p->level; - if (level < 0) level = 5; - p->level = level; - - if (p->dictSize == 0) - p->dictSize = - ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : - ( level <= 6 ? ((UInt32)1 << (level + 19)) : - ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) - ))); - - if (p->dictSize > p->reduceSize) - { - UInt32 v = (UInt32)p->reduceSize; - const UInt32 kReduceMin = ((UInt32)1 << 12); - if (v < kReduceMin) - v = kReduceMin; - if (p->dictSize > v) - p->dictSize = v; - } - - if (p->lc < 0) p->lc = 3; - if (p->lp < 0) p->lp = 0; - if (p->pb < 0) p->pb = 2; - - if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); - if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); - if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); - if (p->numHashBytes < 0) p->numHashBytes = (p->btMode ? 4 : 5); - if (p->mc == 0) p->mc = (16 + ((unsigned)p->fb >> 1)) >> (p->btMode ? 0 : 1); - - if (p->numThreads < 0) - p->numThreads = - #ifndef Z7_ST - ((p->btMode && p->algo) ? 2 : 1); - #else - 1; - #endif -} - -UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) -{ - CLzmaEncProps props = *props2; - LzmaEncProps_Normalize(&props); - return props.dictSize; -} - - -/* -x86/x64: - -BSR: - IF (SRC == 0) ZF = 1, DEST is undefined; - AMD : DEST is unchanged; - IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit - BSR is slow in some processors - -LZCNT: - IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64) - IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits - IF (DEST == 0) ZF = 1; - -LZCNT works only in new processors starting from Haswell. -if LZCNT is not supported by processor, then it's executed as BSR. -LZCNT can be faster than BSR, if supported. -*/ - -// #define LZMA_LOG_BSR - -#if defined(MY_CPU_ARM_OR_ARM64) /* || defined(MY_CPU_X86_OR_AMD64) */ - - #if (defined(__clang__) && (__clang_major__ >= 6)) \ - || (defined(__GNUC__) && (__GNUC__ >= 6)) - #define LZMA_LOG_BSR - #elif defined(_MSC_VER) && (_MSC_VER >= 1300) - // #if defined(MY_CPU_ARM_OR_ARM64) - #define LZMA_LOG_BSR - // #endif - #endif -#endif - -// #include - -#ifdef LZMA_LOG_BSR - -#if defined(__clang__) \ - || defined(__GNUC__) - -/* - C code: : (30 - __builtin_clz(x)) - gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31) - clang10 for x64 : 31 + (bsr(x) xor -32) -*/ - - #define MY_clz(x) ((unsigned)__builtin_clz(x)) - // __lzcnt32 - // __builtin_ia32_lzcnt_u32 - -#else // #if defined(_MSC_VER) - - #ifdef MY_CPU_ARM_OR_ARM64 - - #define MY_clz _CountLeadingZeros - - #else // if defined(MY_CPU_X86_OR_AMD64) - - // #define MY_clz __lzcnt // we can use lzcnt (unsupported by old CPU) - // _BitScanReverse code is not optimal for some MSVC compilers - #define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); zz--; \ - res = (zz + zz) + (pos >> zz); } - - #endif // MY_CPU_X86_OR_AMD64 - -#endif // _MSC_VER - - -#ifndef BSR2_RET - - #define BSR2_RET(pos, res) { unsigned zz = 30 - MY_clz(pos); \ - res = (zz + zz) + (pos >> zz); } - -#endif - - -unsigned GetPosSlot1(UInt32 pos); -unsigned GetPosSlot1(UInt32 pos) -{ - unsigned res; - BSR2_RET(pos, res) - return res; -} -#define GetPosSlot2(pos, res) { BSR2_RET(pos, res) } -#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res) } - - -#else // ! LZMA_LOG_BSR - -#define kNumLogBits (11 + sizeof(size_t) / 8 * 3) - -#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) - -static void LzmaEnc_FastPosInit(Byte *g_FastPos) -{ - unsigned slot; - g_FastPos[0] = 0; - g_FastPos[1] = 1; - g_FastPos += 2; - - for (slot = 2; slot < kNumLogBits * 2; slot++) - { - size_t k = ((size_t)1 << ((slot >> 1) - 1)); - size_t j; - for (j = 0; j < k; j++) - g_FastPos[j] = (Byte)slot; - g_FastPos += k; - } -} - -/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ -/* -#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ - (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ - res = p->g_FastPos[pos >> zz] + (zz * 2); } -*/ - -/* -#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ - (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ - res = p->g_FastPos[pos >> zz] + (zz * 2); } -*/ - -#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ - res = p->g_FastPos[pos >> zz] + (zz * 2); } - -/* -#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ - p->g_FastPos[pos >> 6] + 12 : \ - p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } -*/ - -#define GetPosSlot1(pos) p->g_FastPos[pos] -#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } -#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); } - -#endif // LZMA_LOG_BSR - - -#define LZMA_NUM_REPS 4 - -typedef UInt16 CState; -typedef UInt16 CExtra; - -typedef struct -{ - UInt32 price; - CState state; - CExtra extra; - // 0 : normal - // 1 : LIT : MATCH - // > 1 : MATCH (extra-1) : LIT : REP0 (len) - UInt32 len; - UInt32 dist; - UInt32 reps[LZMA_NUM_REPS]; -} COptimal; - - -// 18.06 -#define kNumOpts (1 << 11) -#define kPackReserve (kNumOpts * 8) -// #define kNumOpts (1 << 12) -// #define kPackReserve (1 + kNumOpts * 2) - -#define kNumLenToPosStates 4 -#define kNumPosSlotBits 6 -// #define kDicLogSizeMin 0 -#define kDicLogSizeMax 32 -#define kDistTableSizeMax (kDicLogSizeMax * 2) - -#define kNumAlignBits 4 -#define kAlignTableSize (1 << kNumAlignBits) -#define kAlignMask (kAlignTableSize - 1) - -#define kStartPosModelIndex 4 -#define kEndPosModelIndex 14 -#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) - -typedef -#ifdef Z7_LZMA_PROB32 - UInt32 -#else - UInt16 -#endif - CLzmaProb; - -#define LZMA_PB_MAX 4 -#define LZMA_LC_MAX 8 -#define LZMA_LP_MAX 4 - -#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) - -#define kLenNumLowBits 3 -#define kLenNumLowSymbols (1 << kLenNumLowBits) -#define kLenNumHighBits 8 -#define kLenNumHighSymbols (1 << kLenNumHighBits) -#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols) - -#define LZMA_MATCH_LEN_MIN 2 -#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) - -#define kNumStates 12 - - -typedef struct -{ - CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)]; - CLzmaProb high[kLenNumHighSymbols]; -} CLenEnc; - - -typedef struct -{ - unsigned tableSize; - UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; - // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2]; - // UInt32 prices2[kLenNumSymbolsTotal]; -} CLenPriceEnc; - -#define GET_PRICE_LEN(p, posState, len) \ - ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN]) - -/* -#define GET_PRICE_LEN(p, posState, len) \ - ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9))) -*/ - -typedef struct -{ - UInt32 range; - unsigned cache; - UInt64 low; - UInt64 cacheSize; - Byte *buf; - Byte *bufLim; - Byte *bufBase; - ISeqOutStreamPtr outStream; - UInt64 processed; - SRes res; -} CRangeEnc; - - -typedef struct -{ - CLzmaProb *litProbs; - - unsigned state; - UInt32 reps[LZMA_NUM_REPS]; - - CLzmaProb posAlignEncoder[1 << kNumAlignBits]; - CLzmaProb isRep[kNumStates]; - CLzmaProb isRepG0[kNumStates]; - CLzmaProb isRepG1[kNumStates]; - CLzmaProb isRepG2[kNumStates]; - CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; - CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; - - CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; - CLzmaProb posEncoders[kNumFullDistances]; - - CLenEnc lenProbs; - CLenEnc repLenProbs; - -} CSaveState; - - -typedef UInt32 CProbPrice; - - -struct CLzmaEnc -{ - void *matchFinderObj; - IMatchFinder2 matchFinder; - - unsigned optCur; - unsigned optEnd; - - unsigned longestMatchLen; - unsigned numPairs; - UInt32 numAvail; - - unsigned state; - unsigned numFastBytes; - unsigned additionalOffset; - UInt32 reps[LZMA_NUM_REPS]; - unsigned lpMask, pbMask; - CLzmaProb *litProbs; - CRangeEnc rc; - - UInt32 backRes; - - unsigned lc, lp, pb; - unsigned lclp; - - BoolInt fastMode; - BoolInt writeEndMark; - BoolInt finished; - BoolInt multiThread; - BoolInt needInit; - // BoolInt _maxMode; - - UInt64 nowPos64; - - unsigned matchPriceCount; - // unsigned alignPriceCount; - int repLenEncCounter; - - unsigned distTableSize; - - UInt32 dictSize; - SRes result; - - #ifndef Z7_ST - BoolInt mtMode; - // begin of CMatchFinderMt is used in LZ thread - CMatchFinderMt matchFinderMt; - // end of CMatchFinderMt is used in BT and HASH threads - // #else - // CMatchFinder matchFinderBase; - #endif - CMatchFinder matchFinderBase; - - - // we suppose that we have 8-bytes alignment after CMatchFinder - - #ifndef Z7_ST - Byte pad[128]; - #endif - - // LZ thread - CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; - - // we want {len , dist} pairs to be 8-bytes aligned in matches array - UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2]; - - // we want 8-bytes alignment here - UInt32 alignPrices[kAlignTableSize]; - UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; - UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; - - CLzmaProb posAlignEncoder[1 << kNumAlignBits]; - CLzmaProb isRep[kNumStates]; - CLzmaProb isRepG0[kNumStates]; - CLzmaProb isRepG1[kNumStates]; - CLzmaProb isRepG2[kNumStates]; - CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; - CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; - CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; - CLzmaProb posEncoders[kNumFullDistances]; - - CLenEnc lenProbs; - CLenEnc repLenProbs; - - #ifndef LZMA_LOG_BSR - Byte g_FastPos[1 << kNumLogBits]; - #endif - - CLenPriceEnc lenEnc; - CLenPriceEnc repLenEnc; - - COptimal opt[kNumOpts]; - - CSaveState saveState; - - // BoolInt mf_Failure; - #ifndef Z7_ST - Byte pad2[128]; - #endif -}; - - -#define MFB (p->matchFinderBase) -/* -#ifndef Z7_ST -#define MFB (p->matchFinderMt.MatchFinder) -#endif -*/ - -// #define GET_CLzmaEnc_p CLzmaEnc *p = (CLzmaEnc*)(void *)p; -// #define GET_const_CLzmaEnc_p const CLzmaEnc *p = (const CLzmaEnc*)(const void *)p; - -#define COPY_ARR(dest, src, arr) memcpy((dest)->arr, (src)->arr, sizeof((src)->arr)); - -#define COPY_LZMA_ENC_STATE(d, s, p) \ - (d)->state = (s)->state; \ - COPY_ARR(d, s, reps) \ - COPY_ARR(d, s, posAlignEncoder) \ - COPY_ARR(d, s, isRep) \ - COPY_ARR(d, s, isRepG0) \ - COPY_ARR(d, s, isRepG1) \ - COPY_ARR(d, s, isRepG2) \ - COPY_ARR(d, s, isMatch) \ - COPY_ARR(d, s, isRep0Long) \ - COPY_ARR(d, s, posSlotEncoder) \ - COPY_ARR(d, s, posEncoders) \ - (d)->lenProbs = (s)->lenProbs; \ - (d)->repLenProbs = (s)->repLenProbs; \ - memcpy((d)->litProbs, (s)->litProbs, ((size_t)0x300 * sizeof(CLzmaProb)) << (p)->lclp); - -void LzmaEnc_SaveState(CLzmaEncHandle p) -{ - // GET_CLzmaEnc_p - CSaveState *v = &p->saveState; - COPY_LZMA_ENC_STATE(v, p, p) -} - -void LzmaEnc_RestoreState(CLzmaEncHandle p) -{ - // GET_CLzmaEnc_p - const CSaveState *v = &p->saveState; - COPY_LZMA_ENC_STATE(p, v, p) -} - - -Z7_NO_INLINE -SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props2) -{ - // GET_CLzmaEnc_p - CLzmaEncProps props = *props2; - LzmaEncProps_Normalize(&props); - - if (props.lc > LZMA_LC_MAX - || props.lp > LZMA_LP_MAX - || props.pb > LZMA_PB_MAX) - return SZ_ERROR_PARAM; - - - if (props.dictSize > kLzmaMaxHistorySize) - props.dictSize = kLzmaMaxHistorySize; - - #ifndef LZMA_LOG_BSR - { - const UInt64 dict64 = props.dictSize; - if (dict64 > ((UInt64)1 << kDicLogSizeMaxCompress)) - return SZ_ERROR_PARAM; - } - #endif - - p->dictSize = props.dictSize; - { - unsigned fb = (unsigned)props.fb; - if (fb < 5) - fb = 5; - if (fb > LZMA_MATCH_LEN_MAX) - fb = LZMA_MATCH_LEN_MAX; - p->numFastBytes = fb; - } - p->lc = (unsigned)props.lc; - p->lp = (unsigned)props.lp; - p->pb = (unsigned)props.pb; - p->fastMode = (props.algo == 0); - // p->_maxMode = True; - MFB.btMode = (Byte)(props.btMode ? 1 : 0); - // MFB.btMode = (Byte)(props.btMode); - { - unsigned numHashBytes = 4; - if (props.btMode) - { - if (props.numHashBytes < 2) numHashBytes = 2; - else if (props.numHashBytes < 4) numHashBytes = (unsigned)props.numHashBytes; - } - if (props.numHashBytes >= 5) numHashBytes = 5; - - MFB.numHashBytes = numHashBytes; - // MFB.numHashBytes_Min = 2; - MFB.numHashOutBits = (Byte)props.numHashOutBits; - } - - MFB.cutValue = props.mc; - - p->writeEndMark = (BoolInt)props.writeEndMark; - - #ifndef Z7_ST - /* - if (newMultiThread != _multiThread) - { - ReleaseMatchFinder(); - _multiThread = newMultiThread; - } - */ - p->multiThread = (props.numThreads > 1); - p->matchFinderMt.btSync.affinity = - p->matchFinderMt.hashSync.affinity = props.affinity; - #endif - - return SZ_OK; -} - - -void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize) -{ - // GET_CLzmaEnc_p - MFB.expectedDataSize = expectedDataSiize; -} - - -#define kState_Start 0 -#define kState_LitAfterMatch 4 -#define kState_LitAfterRep 5 -#define kState_MatchAfterLit 7 -#define kState_RepAfterLit 8 - -static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; -static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; -static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; -static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; - -#define IsLitState(s) ((s) < 7) -#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1) -#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) - -#define kInfinityPrice (1 << 30) - -static void RangeEnc_Construct(CRangeEnc *p) -{ - p->outStream = NULL; - p->bufBase = NULL; -} - -#define RangeEnc_GetProcessed(p) ( (p)->processed + (size_t)((p)->buf - (p)->bufBase) + (p)->cacheSize) -#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + (size_t)((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) - -#define RC_BUF_SIZE (1 << 16) - -static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc) -{ - if (!p->bufBase) - { - p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE); - if (!p->bufBase) - return 0; - p->bufLim = p->bufBase + RC_BUF_SIZE; - } - return 1; -} - -static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->bufBase); - p->bufBase = NULL; -} - -static void RangeEnc_Init(CRangeEnc *p) -{ - p->range = 0xFFFFFFFF; - p->cache = 0; - p->low = 0; - p->cacheSize = 0; - - p->buf = p->bufBase; - - p->processed = 0; - p->res = SZ_OK; -} - -Z7_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) -{ - const size_t num = (size_t)(p->buf - p->bufBase); - if (p->res == SZ_OK) - { - if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) - p->res = SZ_ERROR_WRITE; - } - p->processed += num; - p->buf = p->bufBase; -} - -Z7_NO_INLINE static void Z7_FASTCALL RangeEnc_ShiftLow(CRangeEnc *p) -{ - UInt32 low = (UInt32)p->low; - unsigned high = (unsigned)(p->low >> 32); - p->low = (UInt32)(low << 8); - if (low < (UInt32)0xFF000000 || high != 0) - { - { - Byte *buf = p->buf; - *buf++ = (Byte)(p->cache + high); - p->cache = (unsigned)(low >> 24); - p->buf = buf; - if (buf == p->bufLim) - RangeEnc_FlushStream(p); - if (p->cacheSize == 0) - return; - } - high += 0xFF; - for (;;) - { - Byte *buf = p->buf; - *buf++ = (Byte)(high); - p->buf = buf; - if (buf == p->bufLim) - RangeEnc_FlushStream(p); - if (--p->cacheSize == 0) - return; - } - } - p->cacheSize++; -} - -static void RangeEnc_FlushData(CRangeEnc *p) -{ - int i; - for (i = 0; i < 5; i++) - RangeEnc_ShiftLow(p); -} - -#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); } - -#define RC_BIT_PRE(p, prob) \ - ttt = *(prob); \ - newBound = (range >> kNumBitModelTotalBits) * ttt; - -// #define Z7_LZMA_ENC_USE_BRANCH - -#ifdef Z7_LZMA_ENC_USE_BRANCH - -#define RC_BIT(p, prob, bit) { \ - RC_BIT_PRE(p, prob) \ - if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \ - else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \ - *(prob) = (CLzmaProb)ttt; \ - RC_NORM(p) \ - } - -#else - -#define RC_BIT(p, prob, bit) { \ - UInt32 mask; \ - RC_BIT_PRE(p, prob) \ - mask = 0 - (UInt32)bit; \ - range &= mask; \ - mask &= newBound; \ - range -= mask; \ - (p)->low += mask; \ - mask = (UInt32)bit - 1; \ - range += newBound & mask; \ - mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \ - mask += ((1 << kNumMoveBits) - 1); \ - ttt += (UInt32)((Int32)(mask - ttt) >> kNumMoveBits); \ - *(prob) = (CLzmaProb)ttt; \ - RC_NORM(p) \ - } - -#endif - - - - -#define RC_BIT_0_BASE(p, prob) \ - range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); - -#define RC_BIT_1_BASE(p, prob) \ - range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \ - -#define RC_BIT_0(p, prob) \ - RC_BIT_0_BASE(p, prob) \ - RC_NORM(p) - -#define RC_BIT_1(p, prob) \ - RC_BIT_1_BASE(p, prob) \ - RC_NORM(p) - -static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob) -{ - UInt32 range, ttt, newBound; - range = p->range; - RC_BIT_PRE(p, prob) - RC_BIT_0(p, prob) - p->range = range; -} - -static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym) -{ - UInt32 range = p->range; - sym |= 0x100; - do - { - UInt32 ttt, newBound; - // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1); - CLzmaProb *prob = probs + (sym >> 8); - UInt32 bit = (sym >> 7) & 1; - sym <<= 1; - RC_BIT(p, prob, bit) - } - while (sym < 0x10000); - p->range = range; -} - -static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte) -{ - UInt32 range = p->range; - UInt32 offs = 0x100; - sym |= 0x100; - do - { - UInt32 ttt, newBound; - CLzmaProb *prob; - UInt32 bit; - matchByte <<= 1; - // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1); - prob = probs + (offs + (matchByte & offs) + (sym >> 8)); - bit = (sym >> 7) & 1; - sym <<= 1; - offs &= ~(matchByte ^ sym); - RC_BIT(p, prob, bit) - } - while (sym < 0x10000); - p->range = range; -} - - - -static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices) -{ - UInt32 i; - for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++) - { - const unsigned kCyclesBits = kNumBitPriceShiftBits; - UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1)); - unsigned bitCount = 0; - unsigned j; - for (j = 0; j < kCyclesBits; j++) - { - w = w * w; - bitCount <<= 1; - while (w >= ((UInt32)1 << 16)) - { - w >>= 1; - bitCount++; - } - } - ProbPrices[i] = (CProbPrice)(((unsigned)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); - // printf("\n%3d: %5d", i, ProbPrices[i]); - } -} - - -#define GET_PRICE(prob, bit) \ - p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits] - -#define GET_PRICEa(prob, bit) \ - ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits] - -#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] -#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] - -#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits] -#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] - - -static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices) -{ - UInt32 price = 0; - sym |= 0x100; - do - { - unsigned bit = sym & 1; - sym >>= 1; - price += GET_PRICEa(probs[sym], bit); - } - while (sym >= 2); - return price; -} - - -static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices) -{ - UInt32 price = 0; - UInt32 offs = 0x100; - sym |= 0x100; - do - { - matchByte <<= 1; - price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1); - sym <<= 1; - offs &= ~(matchByte ^ sym); - } - while (sym < 0x10000); - return price; -} - - -static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym) -{ - UInt32 range = rc->range; - unsigned m = 1; - do - { - UInt32 ttt, newBound; - unsigned bit = sym & 1; - // RangeEnc_EncodeBit(rc, probs + m, bit); - sym >>= 1; - RC_BIT(rc, probs + m, bit) - m = (m << 1) | bit; - } - while (--numBits); - rc->range = range; -} - - - -static void LenEnc_Init(CLenEnc *p) -{ - unsigned i; - for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++) - p->low[i] = kProbInitValue; - for (i = 0; i < kLenNumHighSymbols; i++) - p->high[i] = kProbInitValue; -} - -static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState) -{ - UInt32 range, ttt, newBound; - CLzmaProb *probs = p->low; - range = rc->range; - RC_BIT_PRE(rc, probs) - if (sym >= kLenNumLowSymbols) - { - RC_BIT_1(rc, probs) - probs += kLenNumLowSymbols; - RC_BIT_PRE(rc, probs) - if (sym >= kLenNumLowSymbols * 2) - { - RC_BIT_1(rc, probs) - rc->range = range; - // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2); - LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2); - return; - } - sym -= kLenNumLowSymbols; - } - - // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym); - { - unsigned m; - unsigned bit; - RC_BIT_0(rc, probs) - probs += (posState << (1 + kLenNumLowBits)); - bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit; - bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit; - bit = sym & 1; RC_BIT(rc, probs + m, bit) - rc->range = range; - } -} - -static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices) -{ - unsigned i; - for (i = 0; i < 8; i += 2) - { - UInt32 price = startPrice; - UInt32 prob; - price += GET_PRICEa(probs[1 ], (i >> 2)); - price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1); - prob = probs[4 + (i >> 1)]; - prices[i ] = price + GET_PRICEa_0(prob); - prices[i + 1] = price + GET_PRICEa_1(prob); - } -} - - -Z7_NO_INLINE static void Z7_FASTCALL LenPriceEnc_UpdateTables( - CLenPriceEnc *p, - unsigned numPosStates, - const CLenEnc *enc, - const CProbPrice *ProbPrices) -{ - UInt32 b; - - { - unsigned prob = enc->low[0]; - UInt32 a, c; - unsigned posState; - b = GET_PRICEa_1(prob); - a = GET_PRICEa_0(prob); - c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); - for (posState = 0; posState < numPosStates; posState++) - { - UInt32 *prices = p->prices[posState]; - const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); - SetPrices_3(probs, a, prices, ProbPrices); - SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); - } - } - - /* - { - unsigned i; - UInt32 b; - a = GET_PRICEa_0(enc->low[0]); - for (i = 0; i < kLenNumLowSymbols; i++) - p->prices2[i] = a; - a = GET_PRICEa_1(enc->low[0]); - b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); - for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++) - p->prices2[i] = b; - a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); - } - */ - - // p->counter = numSymbols; - // p->counter = 64; - - { - unsigned i = p->tableSize; - - if (i > kLenNumLowSymbols * 2) - { - const CLzmaProb *probs = enc->high; - UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2; - i -= kLenNumLowSymbols * 2 - 1; - i >>= 1; - b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); - do - { - /* - p->prices2[i] = a + - // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices); - LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices); - */ - // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices); - unsigned sym = --i + (1 << (kLenNumHighBits - 1)); - UInt32 price = b; - do - { - const unsigned bit = sym & 1; - sym >>= 1; - price += GET_PRICEa(probs[sym], bit); - } - while (sym >= 2); - - { - const unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))]; - prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob); - prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob); - } - } - while (i); - - { - unsigned posState; - const size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]); - for (posState = 1; posState < numPosStates; posState++) - memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num); - } - } - } -} - -/* - #ifdef SHOW_STAT - g_STAT_OFFSET += num; - printf("\n MovePos %u", num); - #endif -*/ - -#define MOVE_POS(p, num) { \ - p->additionalOffset += (num); \ - p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); } - - -static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) -{ - unsigned numPairs; - - p->additionalOffset++; - p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); - { - const UInt32 *d = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); - // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; } - numPairs = (unsigned)(d - p->matches); - } - *numPairsRes = numPairs; - - #ifdef SHOW_STAT - printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); - g_STAT_OFFSET++; - { - unsigned i; - for (i = 0; i < numPairs; i += 2) - printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); - } - #endif - - if (numPairs == 0) - return 0; - { - const unsigned len = p->matches[(size_t)numPairs - 2]; - if (len != p->numFastBytes) - return len; - { - UInt32 numAvail = p->numAvail; - if (numAvail > LZMA_MATCH_LEN_MAX) - numAvail = LZMA_MATCH_LEN_MAX; - { - const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - const Byte *p2 = p1 + len; - const ptrdiff_t dif = (ptrdiff_t)-1 - (ptrdiff_t)p->matches[(size_t)numPairs - 1]; - const Byte *lim = p1 + numAvail; - for (; p2 != lim && *p2 == p2[dif]; p2++) - {} - return (unsigned)(p2 - p1); - } - } - } -} - -#define MARK_LIT ((UInt32)(Int32)-1) - -#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; } -#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; } -#define IsShortRep(p) ((p)->dist == 0) - - -#define GetPrice_ShortRep(p, state, posState) \ - ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState])) - -#define GetPrice_Rep_0(p, state, posState) ( \ - GET_PRICE_1(p->isMatch[state][posState]) \ - + GET_PRICE_1(p->isRep0Long[state][posState])) \ - + GET_PRICE_1(p->isRep[state]) \ - + GET_PRICE_0(p->isRepG0[state]) - -Z7_FORCE_INLINE -static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState) -{ - UInt32 price; - UInt32 prob = p->isRepG0[state]; - if (repIndex == 0) - { - price = GET_PRICE_0(prob); - price += GET_PRICE_1(p->isRep0Long[state][posState]); - } - else - { - price = GET_PRICE_1(prob); - prob = p->isRepG1[state]; - if (repIndex == 1) - price += GET_PRICE_0(prob); - else - { - price += GET_PRICE_1(prob); - price += GET_PRICE(p->isRepG2[state], repIndex - 2); - } - } - return price; -} - - -static unsigned Backward(CLzmaEnc *p, unsigned cur) -{ - unsigned wr = cur + 1; - p->optEnd = wr; - - for (;;) - { - UInt32 dist = p->opt[cur].dist; - unsigned len = (unsigned)p->opt[cur].len; - unsigned extra = (unsigned)p->opt[cur].extra; - cur -= len; - - if (extra) - { - wr--; - p->opt[wr].len = (UInt32)len; - cur -= extra; - len = extra; - if (extra == 1) - { - p->opt[wr].dist = dist; - dist = MARK_LIT; - } - else - { - p->opt[wr].dist = 0; - len--; - wr--; - p->opt[wr].dist = MARK_LIT; - p->opt[wr].len = 1; - } - } - - if (cur == 0) - { - p->backRes = dist; - p->optCur = wr; - return len; - } - - wr--; - p->opt[wr].dist = dist; - p->opt[wr].len = (UInt32)len; - } -} - - - -#define LIT_PROBS(pos, prevByte) \ - (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc)) - - -static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) -{ - unsigned last, cur; - UInt32 reps[LZMA_NUM_REPS]; - unsigned repLens[LZMA_NUM_REPS]; - UInt32 *matches; - - { - UInt32 numAvail; - unsigned numPairs, mainLen, repMaxIndex, i, posState; - UInt32 matchPrice, repMatchPrice; - const Byte *data; - Byte curByte, matchByte; - - p->optCur = p->optEnd = 0; - - if (p->additionalOffset == 0) - mainLen = ReadMatchDistances(p, &numPairs); - else - { - mainLen = p->longestMatchLen; - numPairs = p->numPairs; - } - - numAvail = p->numAvail; - if (numAvail < 2) - { - p->backRes = MARK_LIT; - return 1; - } - if (numAvail > LZMA_MATCH_LEN_MAX) - numAvail = LZMA_MATCH_LEN_MAX; - - data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - repMaxIndex = 0; - - for (i = 0; i < LZMA_NUM_REPS; i++) - { - unsigned len; - const Byte *data2; - reps[i] = p->reps[i]; - data2 = data - reps[i]; - if (data[0] != data2[0] || data[1] != data2[1]) - { - repLens[i] = 0; - continue; - } - for (len = 2; len < numAvail && data[len] == data2[len]; len++) - {} - repLens[i] = len; - if (len > repLens[repMaxIndex]) - repMaxIndex = i; - if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization - break; - } - - if (repLens[repMaxIndex] >= p->numFastBytes) - { - unsigned len; - p->backRes = (UInt32)repMaxIndex; - len = repLens[repMaxIndex]; - MOVE_POS(p, len - 1) - return len; - } - - matches = p->matches; - #define MATCHES matches - // #define MATCHES p->matches - - if (mainLen >= p->numFastBytes) - { - p->backRes = MATCHES[(size_t)numPairs - 1] + LZMA_NUM_REPS; - MOVE_POS(p, mainLen - 1) - return mainLen; - } - - curByte = *data; - matchByte = *(data - reps[0]); - - last = repLens[repMaxIndex]; - if (last <= mainLen) - last = mainLen; - - if (last < 2 && curByte != matchByte) - { - p->backRes = MARK_LIT; - return 1; - } - - p->opt[0].state = (CState)p->state; - - posState = (position & p->pbMask); - - { - const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); - p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + - (!IsLitState(p->state) ? - LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : - LitEnc_GetPrice(probs, curByte, p->ProbPrices)); - } - - MakeAs_Lit(&p->opt[1]) - - matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); - repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); - - // 18.06 - if (matchByte == curByte && repLens[0] == 0) - { - UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState); - if (shortRepPrice < p->opt[1].price) - { - p->opt[1].price = shortRepPrice; - MakeAs_ShortRep(&p->opt[1]) - } - if (last < 2) - { - p->backRes = p->opt[1].dist; - return 1; - } - } - - p->opt[1].len = 1; - - p->opt[0].reps[0] = reps[0]; - p->opt[0].reps[1] = reps[1]; - p->opt[0].reps[2] = reps[2]; - p->opt[0].reps[3] = reps[3]; - - // ---------- REP ---------- - - for (i = 0; i < LZMA_NUM_REPS; i++) - { - unsigned repLen = repLens[i]; - UInt32 price; - if (repLen < 2) - continue; - price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState); - do - { - UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen); - COptimal *opt = &p->opt[repLen]; - if (price2 < opt->price) - { - opt->price = price2; - opt->len = (UInt32)repLen; - opt->dist = (UInt32)i; - opt->extra = 0; - } - } - while (--repLen >= 2); - } - - - // ---------- MATCH ---------- - { - unsigned len = repLens[0] + 1; - if (len <= mainLen) - { - unsigned offs = 0; - UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); - - if (len < 2) - len = 2; - else - while (len > MATCHES[offs]) - offs += 2; - - for (; ; len++) - { - COptimal *opt; - UInt32 dist = MATCHES[(size_t)offs + 1]; - UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); - unsigned lenToPosState = GetLenToPosState(len); - - if (dist < kNumFullDistances) - price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)]; - else - { - unsigned slot; - GetPosSlot2(dist, slot) - price += p->alignPrices[dist & kAlignMask]; - price += p->posSlotPrices[lenToPosState][slot]; - } - - opt = &p->opt[len]; - - if (price < opt->price) - { - opt->price = price; - opt->len = (UInt32)len; - opt->dist = dist + LZMA_NUM_REPS; - opt->extra = 0; - } - - if (len == MATCHES[offs]) - { - offs += 2; - if (offs == numPairs) - break; - } - } - } - } - - - cur = 0; - - #ifdef SHOW_STAT2 - /* if (position >= 0) */ - { - unsigned i; - printf("\n pos = %4X", position); - for (i = cur; i <= last; i++) - printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); - } - #endif - } - - - - // ---------- Optimal Parsing ---------- - - for (;;) - { - unsigned numAvail; - UInt32 numAvailFull; - unsigned newLen, numPairs, prev, state, posState, startLen; - UInt32 litPrice, matchPrice, repMatchPrice; - BoolInt nextIsLit; - Byte curByte, matchByte; - const Byte *data; - COptimal *curOpt, *nextOpt; - - if (++cur == last) - break; - - // 18.06 - if (cur >= kNumOpts - 64) - { - unsigned j, best; - UInt32 price = p->opt[cur].price; - best = cur; - for (j = cur + 1; j <= last; j++) - { - UInt32 price2 = p->opt[j].price; - if (price >= price2) - { - price = price2; - best = j; - } - } - { - unsigned delta = best - cur; - if (delta != 0) - { - MOVE_POS(p, delta) - } - } - cur = best; - break; - } - - newLen = ReadMatchDistances(p, &numPairs); - - if (newLen >= p->numFastBytes) - { - p->numPairs = numPairs; - p->longestMatchLen = newLen; - break; - } - - curOpt = &p->opt[cur]; - - position++; - - // we need that check here, if skip_items in p->opt are possible - /* - if (curOpt->price >= kInfinityPrice) - continue; - */ - - prev = cur - curOpt->len; - - if (curOpt->len == 1) - { - state = (unsigned)p->opt[prev].state; - if (IsShortRep(curOpt)) - state = kShortRepNextStates[state]; - else - state = kLiteralNextStates[state]; - } - else - { - const COptimal *prevOpt; - UInt32 b0; - UInt32 dist = curOpt->dist; - - if (curOpt->extra) - { - prev -= (unsigned)curOpt->extra; - state = kState_RepAfterLit; - if (curOpt->extra == 1) - state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit); - } - else - { - state = (unsigned)p->opt[prev].state; - if (dist < LZMA_NUM_REPS) - state = kRepNextStates[state]; - else - state = kMatchNextStates[state]; - } - - prevOpt = &p->opt[prev]; - b0 = prevOpt->reps[0]; - - if (dist < LZMA_NUM_REPS) - { - if (dist == 0) - { - reps[0] = b0; - reps[1] = prevOpt->reps[1]; - reps[2] = prevOpt->reps[2]; - reps[3] = prevOpt->reps[3]; - } - else - { - reps[1] = b0; - b0 = prevOpt->reps[1]; - if (dist == 1) - { - reps[0] = b0; - reps[2] = prevOpt->reps[2]; - reps[3] = prevOpt->reps[3]; - } - else - { - reps[2] = b0; - reps[0] = prevOpt->reps[dist]; - reps[3] = prevOpt->reps[dist ^ 1]; - } - } - } - else - { - reps[0] = (dist - LZMA_NUM_REPS + 1); - reps[1] = b0; - reps[2] = prevOpt->reps[1]; - reps[3] = prevOpt->reps[2]; - } - } - - curOpt->state = (CState)state; - curOpt->reps[0] = reps[0]; - curOpt->reps[1] = reps[1]; - curOpt->reps[2] = reps[2]; - curOpt->reps[3] = reps[3]; - - data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - curByte = *data; - matchByte = *(data - reps[0]); - - posState = (position & p->pbMask); - - /* - The order of Price checks: - < LIT - <= SHORT_REP - < LIT : REP_0 - < REP [ : LIT : REP_0 ] - < MATCH [ : LIT : REP_0 ] - */ - - { - UInt32 curPrice = curOpt->price; - unsigned prob = p->isMatch[state][posState]; - matchPrice = curPrice + GET_PRICE_1(prob); - litPrice = curPrice + GET_PRICE_0(prob); - } - - nextOpt = &p->opt[(size_t)cur + 1]; - nextIsLit = False; - - // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice) - // 18.new.06 - if ((nextOpt->price < kInfinityPrice - // && !IsLitState(state) - && matchByte == curByte) - || litPrice > nextOpt->price - ) - litPrice = 0; - else - { - const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); - litPrice += (!IsLitState(state) ? - LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : - LitEnc_GetPrice(probs, curByte, p->ProbPrices)); - - if (litPrice < nextOpt->price) - { - nextOpt->price = litPrice; - nextOpt->len = 1; - MakeAs_Lit(nextOpt) - nextIsLit = True; - } - } - - repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); - - numAvailFull = p->numAvail; - { - unsigned temp = kNumOpts - 1 - cur; - if (numAvailFull > temp) - numAvailFull = (UInt32)temp; - } - - // 18.06 - // ---------- SHORT_REP ---------- - if (IsLitState(state)) // 18.new - if (matchByte == curByte) - if (repMatchPrice < nextOpt->price) // 18.new - // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1)) - if ( - // nextOpt->price >= kInfinityPrice || - nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt - || (nextOpt->dist != 0 - // && nextOpt->extra <= 1 // 17.old - ) - ) - { - UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState); - // if (shortRepPrice <= nextOpt->price) // 17.old - if (shortRepPrice < nextOpt->price) // 18.new - { - nextOpt->price = shortRepPrice; - nextOpt->len = 1; - MakeAs_ShortRep(nextOpt) - nextIsLit = False; - } - } - - if (numAvailFull < 2) - continue; - numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); - - // numAvail <= p->numFastBytes - - // ---------- LIT : REP_0 ---------- - - if (!nextIsLit - && litPrice != 0 // 18.new - && matchByte != curByte - && numAvailFull > 2) - { - const Byte *data2 = data - reps[0]; - if (data[1] == data2[1] && data[2] == data2[2]) - { - unsigned len; - unsigned limit = p->numFastBytes + 1; - if (limit > numAvailFull) - limit = numAvailFull; - for (len = 3; len < limit && data[len] == data2[len]; len++) - {} - - { - unsigned state2 = kLiteralNextStates[state]; - unsigned posState2 = (position + 1) & p->pbMask; - UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2); - { - unsigned offset = cur + len; - - if (last < offset) - last = offset; - - // do - { - UInt32 price2; - COptimal *opt; - len--; - // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2); - price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len); - - opt = &p->opt[offset]; - // offset--; - if (price2 < opt->price) - { - opt->price = price2; - opt->len = (UInt32)len; - opt->dist = 0; - opt->extra = 1; - } - } - // while (len >= 3); - } - } - } - } - - startLen = 2; /* speed optimization */ - - { - // ---------- REP ---------- - unsigned repIndex = 0; // 17.old - // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused - for (; repIndex < LZMA_NUM_REPS; repIndex++) - { - unsigned len; - UInt32 price; - const Byte *data2 = data - reps[repIndex]; - if (data[0] != data2[0] || data[1] != data2[1]) - continue; - - for (len = 2; len < numAvail && data[len] == data2[len]; len++) - {} - - // if (len < startLen) continue; // 18.new: speed optimization - - { - unsigned offset = cur + len; - if (last < offset) - last = offset; - } - { - unsigned len2 = len; - price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState); - do - { - UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2); - COptimal *opt = &p->opt[cur + len2]; - if (price2 < opt->price) - { - opt->price = price2; - opt->len = (UInt32)len2; - opt->dist = (UInt32)repIndex; - opt->extra = 0; - } - } - while (--len2 >= 2); - } - - if (repIndex == 0) startLen = len + 1; // 17.old - // startLen = len + 1; // 18.new - - /* if (_maxMode) */ - { - // ---------- REP : LIT : REP_0 ---------- - // numFastBytes + 1 + numFastBytes - - unsigned len2 = len + 1; - unsigned limit = len2 + p->numFastBytes; - if (limit > numAvailFull) - limit = numAvailFull; - - len2 += 2; - if (len2 <= limit) - if (data[len2 - 2] == data2[len2 - 2]) - if (data[len2 - 1] == data2[len2 - 1]) - { - unsigned state2 = kRepNextStates[state]; - unsigned posState2 = (position + len) & p->pbMask; - price += GET_PRICE_LEN(&p->repLenEnc, posState, len) - + GET_PRICE_0(p->isMatch[state2][posState2]) - + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), - data[len], data2[len], p->ProbPrices); - - // state2 = kLiteralNextStates[state2]; - state2 = kState_LitAfterRep; - posState2 = (posState2 + 1) & p->pbMask; - - - price += GetPrice_Rep_0(p, state2, posState2); - - for (; len2 < limit && data[len2] == data2[len2]; len2++) - {} - - len2 -= len; - // if (len2 >= 3) - { - { - unsigned offset = cur + len + len2; - - if (last < offset) - last = offset; - // do - { - UInt32 price2; - COptimal *opt; - len2--; - // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); - price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); - - opt = &p->opt[offset]; - // offset--; - if (price2 < opt->price) - { - opt->price = price2; - opt->len = (UInt32)len2; - opt->extra = (CExtra)(len + 1); - opt->dist = (UInt32)repIndex; - } - } - // while (len2 >= 3); - } - } - } - } - } - } - - - // ---------- MATCH ---------- - /* for (unsigned len = 2; len <= newLen; len++) */ - if (newLen > numAvail) - { - newLen = numAvail; - for (numPairs = 0; newLen > MATCHES[numPairs]; numPairs += 2); - MATCHES[numPairs] = (UInt32)newLen; - numPairs += 2; - } - - // startLen = 2; /* speed optimization */ - - if (newLen >= startLen) - { - UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); - UInt32 dist; - unsigned offs, posSlot, len; - - { - unsigned offset = cur + newLen; - if (last < offset) - last = offset; - } - - offs = 0; - while (startLen > MATCHES[offs]) - offs += 2; - dist = MATCHES[(size_t)offs + 1]; - - // if (dist >= kNumFullDistances) - GetPosSlot2(dist, posSlot) - - for (len = /*2*/ startLen; ; len++) - { - UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); - { - COptimal *opt; - unsigned lenNorm = len - 2; - lenNorm = GetLenToPosState2(lenNorm); - if (dist < kNumFullDistances) - price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)]; - else - price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask]; - - opt = &p->opt[cur + len]; - if (price < opt->price) - { - opt->price = price; - opt->len = (UInt32)len; - opt->dist = dist + LZMA_NUM_REPS; - opt->extra = 0; - } - } - - if (len == MATCHES[offs]) - { - // if (p->_maxMode) { - // MATCH : LIT : REP_0 - - const Byte *data2 = data - dist - 1; - unsigned len2 = len + 1; - unsigned limit = len2 + p->numFastBytes; - if (limit > numAvailFull) - limit = numAvailFull; - - len2 += 2; - if (len2 <= limit) - if (data[len2 - 2] == data2[len2 - 2]) - if (data[len2 - 1] == data2[len2 - 1]) - { - for (; len2 < limit && data[len2] == data2[len2]; len2++) - {} - - len2 -= len; - - // if (len2 >= 3) - { - unsigned state2 = kMatchNextStates[state]; - unsigned posState2 = (position + len) & p->pbMask; - unsigned offset; - price += GET_PRICE_0(p->isMatch[state2][posState2]); - price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), - data[len], data2[len], p->ProbPrices); - - // state2 = kLiteralNextStates[state2]; - state2 = kState_LitAfterMatch; - - posState2 = (posState2 + 1) & p->pbMask; - price += GetPrice_Rep_0(p, state2, posState2); - - offset = cur + len + len2; - - if (last < offset) - last = offset; - // do - { - UInt32 price2; - COptimal *opt; - len2--; - // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); - price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); - opt = &p->opt[offset]; - // offset--; - if (price2 < opt->price) - { - opt->price = price2; - opt->len = (UInt32)len2; - opt->extra = (CExtra)(len + 1); - opt->dist = dist + LZMA_NUM_REPS; - } - } - // while (len2 >= 3); - } - - } - - offs += 2; - if (offs == numPairs) - break; - dist = MATCHES[(size_t)offs + 1]; - // if (dist >= kNumFullDistances) - GetPosSlot2(dist, posSlot) - } - } - } - } - - do - p->opt[last].price = kInfinityPrice; - while (--last); - - return Backward(p, cur); -} - - - -#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) - - - -static unsigned GetOptimumFast(CLzmaEnc *p) -{ - UInt32 numAvail, mainDist; - unsigned mainLen, numPairs, repIndex, repLen, i; - const Byte *data; - - if (p->additionalOffset == 0) - mainLen = ReadMatchDistances(p, &numPairs); - else - { - mainLen = p->longestMatchLen; - numPairs = p->numPairs; - } - - numAvail = p->numAvail; - p->backRes = MARK_LIT; - if (numAvail < 2) - return 1; - // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused - if (numAvail > LZMA_MATCH_LEN_MAX) - numAvail = LZMA_MATCH_LEN_MAX; - data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - repLen = repIndex = 0; - - for (i = 0; i < LZMA_NUM_REPS; i++) - { - unsigned len; - const Byte *data2 = data - p->reps[i]; - if (data[0] != data2[0] || data[1] != data2[1]) - continue; - for (len = 2; len < numAvail && data[len] == data2[len]; len++) - {} - if (len >= p->numFastBytes) - { - p->backRes = (UInt32)i; - MOVE_POS(p, len - 1) - return len; - } - if (len > repLen) - { - repIndex = i; - repLen = len; - } - } - - if (mainLen >= p->numFastBytes) - { - p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; - MOVE_POS(p, mainLen - 1) - return mainLen; - } - - mainDist = 0; /* for GCC */ - - if (mainLen >= 2) - { - mainDist = p->matches[(size_t)numPairs - 1]; - while (numPairs > 2) - { - UInt32 dist2; - if (mainLen != p->matches[(size_t)numPairs - 4] + 1) - break; - dist2 = p->matches[(size_t)numPairs - 3]; - if (!ChangePair(dist2, mainDist)) - break; - numPairs -= 2; - mainLen--; - mainDist = dist2; - } - if (mainLen == 2 && mainDist >= 0x80) - mainLen = 1; - } - - if (repLen >= 2) - if ( repLen + 1 >= mainLen - || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) - || (repLen + 3 >= mainLen && mainDist >= (1 << 15))) - { - p->backRes = (UInt32)repIndex; - MOVE_POS(p, repLen - 1) - return repLen; - } - - if (mainLen < 2 || numAvail <= 2) - return 1; - - { - unsigned len1 = ReadMatchDistances(p, &p->numPairs); - p->longestMatchLen = len1; - - if (len1 >= 2) - { - UInt32 newDist = p->matches[(size_t)p->numPairs - 1]; - if ( (len1 >= mainLen && newDist < mainDist) - || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist)) - || (len1 > mainLen + 1) - || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist))) - return 1; - } - } - - data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - - for (i = 0; i < LZMA_NUM_REPS; i++) - { - unsigned len, limit; - const Byte *data2 = data - p->reps[i]; - if (data[0] != data2[0] || data[1] != data2[1]) - continue; - limit = mainLen - 1; - for (len = 2;; len++) - { - if (len >= limit) - return 1; - if (data[len] != data2[len]) - break; - } - } - - p->backRes = mainDist + LZMA_NUM_REPS; - if (mainLen != 2) - { - MOVE_POS(p, mainLen - 2) - } - return mainLen; -} - - - - -static void WriteEndMarker(CLzmaEnc *p, unsigned posState) -{ - UInt32 range; - range = p->rc.range; - { - UInt32 ttt, newBound; - CLzmaProb *prob = &p->isMatch[p->state][posState]; - RC_BIT_PRE(&p->rc, prob) - RC_BIT_1(&p->rc, prob) - prob = &p->isRep[p->state]; - RC_BIT_PRE(&p->rc, prob) - RC_BIT_0(&p->rc, prob) - } - p->state = kMatchNextStates[p->state]; - - p->rc.range = range; - LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState); - range = p->rc.range; - - { - // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1); - CLzmaProb *probs = p->posSlotEncoder[0]; - unsigned m = 1; - do - { - UInt32 ttt, newBound; - RC_BIT_PRE(p, probs + m) - RC_BIT_1(&p->rc, probs + m) - m = (m << 1) + 1; - } - while (m < (1 << kNumPosSlotBits)); - } - { - // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range; - unsigned numBits = 30 - kNumAlignBits; - do - { - range >>= 1; - p->rc.low += range; - RC_NORM(&p->rc) - } - while (--numBits); - } - - { - // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); - CLzmaProb *probs = p->posAlignEncoder; - unsigned m = 1; - do - { - UInt32 ttt, newBound; - RC_BIT_PRE(p, probs + m) - RC_BIT_1(&p->rc, probs + m) - m = (m << 1) + 1; - } - while (m < kAlignTableSize); - } - p->rc.range = range; -} - - -static SRes CheckErrors(CLzmaEnc *p) -{ - if (p->result != SZ_OK) - return p->result; - if (p->rc.res != SZ_OK) - p->result = SZ_ERROR_WRITE; - - #ifndef Z7_ST - if ( - // p->mf_Failure || - (p->mtMode && - ( // p->matchFinderMt.failure_LZ_LZ || - p->matchFinderMt.failure_LZ_BT)) - ) - { - p->result = MY_HRES_ERROR_INTERNAL_ERROR; - // printf("\nCheckErrors p->matchFinderMt.failureLZ\n"); - } - #endif - - if (MFB.result != SZ_OK) - p->result = SZ_ERROR_READ; - - if (p->result != SZ_OK) - p->finished = True; - return p->result; -} - - -Z7_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) -{ - /* ReleaseMFStream(); */ - p->finished = True; - if (p->writeEndMark) - WriteEndMarker(p, nowPos & p->pbMask); - RangeEnc_FlushData(&p->rc); - RangeEnc_FlushStream(&p->rc); - return CheckErrors(p); -} - - -Z7_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) -{ - unsigned i; - const CProbPrice *ProbPrices = p->ProbPrices; - const CLzmaProb *probs = p->posAlignEncoder; - // p->alignPriceCount = 0; - for (i = 0; i < kAlignTableSize / 2; i++) - { - UInt32 price = 0; - unsigned sym = i; - unsigned m = 1; - unsigned bit; - UInt32 prob; - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; - prob = probs[m]; - p->alignPrices[i ] = price + GET_PRICEa_0(prob); - p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); - // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); - } -} - - -Z7_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) -{ - // int y; for (y = 0; y < 100; y++) { - - UInt32 tempPrices[kNumFullDistances]; - unsigned i, lps; - - const CProbPrice *ProbPrices = p->ProbPrices; - p->matchPriceCount = 0; - - for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++) - { - unsigned posSlot = GetPosSlot1(i); - unsigned footerBits = (posSlot >> 1) - 1; - unsigned base = ((2 | (posSlot & 1)) << footerBits); - const CLzmaProb *probs = p->posEncoders + (size_t)base * 2; - // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices); - UInt32 price = 0; - unsigned m = 1; - unsigned sym = i; - unsigned offset = (unsigned)1 << footerBits; - base += i; - - if (footerBits) - do - { - unsigned bit = sym & 1; - sym >>= 1; - price += GET_PRICEa(probs[m], bit); - m = (m << 1) + bit; - } - while (--footerBits); - - { - unsigned prob = probs[m]; - tempPrices[base ] = price + GET_PRICEa_0(prob); - tempPrices[base + offset] = price + GET_PRICEa_1(prob); - } - } - - for (lps = 0; lps < kNumLenToPosStates; lps++) - { - unsigned slot; - unsigned distTableSize2 = (p->distTableSize + 1) >> 1; - UInt32 *posSlotPrices = p->posSlotPrices[lps]; - const CLzmaProb *probs = p->posSlotEncoder[lps]; - - for (slot = 0; slot < distTableSize2; slot++) - { - // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices); - UInt32 price; - unsigned bit; - unsigned sym = slot + (1 << (kNumPosSlotBits - 1)); - unsigned prob; - bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit); - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); - prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))]; - posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob); - posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob); - } - - { - UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits); - for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++) - { - posSlotPrices[(size_t)slot * 2 ] += delta; - posSlotPrices[(size_t)slot * 2 + 1] += delta; - delta += ((UInt32)1 << kNumBitPriceShiftBits); - } - } - - { - UInt32 *dp = p->distancesPrices[lps]; - - dp[0] = posSlotPrices[0]; - dp[1] = posSlotPrices[1]; - dp[2] = posSlotPrices[2]; - dp[3] = posSlotPrices[3]; - - for (i = 4; i < kNumFullDistances; i += 2) - { - UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)]; - dp[i ] = slotPrice + tempPrices[i]; - dp[i + 1] = slotPrice + tempPrices[i + 1]; - } - } - } - // } -} - - - -static void LzmaEnc_Construct(CLzmaEnc *p) -{ - RangeEnc_Construct(&p->rc); - MatchFinder_Construct(&MFB); - - #ifndef Z7_ST - p->matchFinderMt.MatchFinder = &MFB; - MatchFinderMt_Construct(&p->matchFinderMt); - #endif - - { - CLzmaEncProps props; - LzmaEncProps_Init(&props); - LzmaEnc_SetProps((CLzmaEncHandle)(void *)p, &props); - } - - #ifndef LZMA_LOG_BSR - LzmaEnc_FastPosInit(p->g_FastPos); - #endif - - LzmaEnc_InitPriceTables(p->ProbPrices); - p->litProbs = NULL; - p->saveState.litProbs = NULL; -} - -CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) -{ - void *p; - p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc)); - if (p) - LzmaEnc_Construct((CLzmaEnc *)p); - return p; -} - -static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->litProbs); - ISzAlloc_Free(alloc, p->saveState.litProbs); - p->litProbs = NULL; - p->saveState.litProbs = NULL; -} - -static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - #ifndef Z7_ST - MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); - #endif - - MatchFinder_Free(&MFB, allocBig); - LzmaEnc_FreeLits(p, alloc); - RangeEnc_Free(&p->rc, alloc); -} - -void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - // GET_CLzmaEnc_p - LzmaEnc_Destruct(p, alloc, allocBig); - ISzAlloc_Free(alloc, p); -} - - -Z7_NO_INLINE -static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize) -{ - UInt32 nowPos32, startPos32; - if (p->needInit) - { - #ifndef Z7_ST - if (p->mtMode) - { - RINOK(MatchFinderMt_InitMt(&p->matchFinderMt)) - } - #endif - p->matchFinder.Init(p->matchFinderObj); - p->needInit = 0; - } - - if (p->finished) - return p->result; - RINOK(CheckErrors(p)) - - nowPos32 = (UInt32)p->nowPos64; - startPos32 = nowPos32; - - if (p->nowPos64 == 0) - { - unsigned numPairs; - Byte curByte; - if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) - return Flush(p, nowPos32); - ReadMatchDistances(p, &numPairs); - RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]); - // p->state = kLiteralNextStates[p->state]; - curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); - LitEnc_Encode(&p->rc, p->litProbs, curByte); - p->additionalOffset--; - nowPos32++; - } - - if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) - - for (;;) - { - UInt32 dist; - unsigned len, posState; - UInt32 range, ttt, newBound; - CLzmaProb *probs; - - if (p->fastMode) - len = GetOptimumFast(p); - else - { - unsigned oci = p->optCur; - if (p->optEnd == oci) - len = GetOptimum(p, nowPos32); - else - { - const COptimal *opt = &p->opt[oci]; - len = opt->len; - p->backRes = opt->dist; - p->optCur = oci + 1; - } - } - - posState = (unsigned)nowPos32 & p->pbMask; - range = p->rc.range; - probs = &p->isMatch[p->state][posState]; - - RC_BIT_PRE(&p->rc, probs) - - dist = p->backRes; - - #ifdef SHOW_STAT2 - printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist); - #endif - - if (dist == MARK_LIT) - { - Byte curByte; - const Byte *data; - unsigned state; - - RC_BIT_0(&p->rc, probs) - p->rc.range = range; - data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; - probs = LIT_PROBS(nowPos32, *(data - 1)); - curByte = *data; - state = p->state; - p->state = kLiteralNextStates[state]; - if (IsLitState(state)) - LitEnc_Encode(&p->rc, probs, curByte); - else - LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0])); - } - else - { - RC_BIT_1(&p->rc, probs) - probs = &p->isRep[p->state]; - RC_BIT_PRE(&p->rc, probs) - - if (dist < LZMA_NUM_REPS) - { - RC_BIT_1(&p->rc, probs) - probs = &p->isRepG0[p->state]; - RC_BIT_PRE(&p->rc, probs) - if (dist == 0) - { - RC_BIT_0(&p->rc, probs) - probs = &p->isRep0Long[p->state][posState]; - RC_BIT_PRE(&p->rc, probs) - if (len != 1) - { - RC_BIT_1_BASE(&p->rc, probs) - } - else - { - RC_BIT_0_BASE(&p->rc, probs) - p->state = kShortRepNextStates[p->state]; - } - } - else - { - RC_BIT_1(&p->rc, probs) - probs = &p->isRepG1[p->state]; - RC_BIT_PRE(&p->rc, probs) - if (dist == 1) - { - RC_BIT_0_BASE(&p->rc, probs) - dist = p->reps[1]; - } - else - { - RC_BIT_1(&p->rc, probs) - probs = &p->isRepG2[p->state]; - RC_BIT_PRE(&p->rc, probs) - if (dist == 2) - { - RC_BIT_0_BASE(&p->rc, probs) - dist = p->reps[2]; - } - else - { - RC_BIT_1_BASE(&p->rc, probs) - dist = p->reps[3]; - p->reps[3] = p->reps[2]; - } - p->reps[2] = p->reps[1]; - } - p->reps[1] = p->reps[0]; - p->reps[0] = dist; - } - - RC_NORM(&p->rc) - - p->rc.range = range; - - if (len != 1) - { - LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); - --p->repLenEncCounter; - p->state = kRepNextStates[p->state]; - } - } - else - { - unsigned posSlot; - RC_BIT_0(&p->rc, probs) - p->rc.range = range; - p->state = kMatchNextStates[p->state]; - - LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); - // --p->lenEnc.counter; - - dist -= LZMA_NUM_REPS; - p->reps[3] = p->reps[2]; - p->reps[2] = p->reps[1]; - p->reps[1] = p->reps[0]; - p->reps[0] = dist + 1; - - p->matchPriceCount++; - GetPosSlot(dist, posSlot) - // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot); - { - UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits); - range = p->rc.range; - probs = p->posSlotEncoder[GetLenToPosState(len)]; - do - { - CLzmaProb *prob = probs + (sym >> kNumPosSlotBits); - UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1; - sym <<= 1; - RC_BIT(&p->rc, prob, bit) - } - while (sym < (1 << kNumPosSlotBits * 2)); - p->rc.range = range; - } - - if (dist >= kStartPosModelIndex) - { - unsigned footerBits = ((posSlot >> 1) - 1); - - if (dist < kNumFullDistances) - { - unsigned base = ((2 | (posSlot & 1)) << footerBits); - RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */)); - } - else - { - UInt32 pos2 = (dist | 0xF) << (32 - footerBits); - range = p->rc.range; - // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); - /* - do - { - range >>= 1; - p->rc.low += range & (0 - ((dist >> --footerBits) & 1)); - RC_NORM(&p->rc) - } - while (footerBits > kNumAlignBits); - */ - do - { - range >>= 1; - p->rc.low += range & (0 - (pos2 >> 31)); - pos2 += pos2; - RC_NORM(&p->rc) - } - while (pos2 != 0xF0000000); - - - // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); - - { - unsigned m = 1; - unsigned bit; - bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; - bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; - bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; - bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) - p->rc.range = range; - // p->alignPriceCount++; - } - } - } - } - } - - nowPos32 += (UInt32)len; - p->additionalOffset -= len; - - if (p->additionalOffset == 0) - { - UInt32 processed; - - if (!p->fastMode) - { - /* - if (p->alignPriceCount >= 16) // kAlignTableSize - FillAlignPrices(p); - if (p->matchPriceCount >= 128) - FillDistancesPrices(p); - if (p->lenEnc.counter <= 0) - LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); - */ - if (p->matchPriceCount >= 64) - { - FillAlignPrices(p); - // { int y; for (y = 0; y < 100; y++) { - FillDistancesPrices(p); - // }} - LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); - } - if (p->repLenEncCounter <= 0) - { - p->repLenEncCounter = REP_LEN_COUNT; - LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); - } - } - - if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) - break; - processed = nowPos32 - startPos32; - - if (maxPackSize) - { - if (processed + kNumOpts + 300 >= maxUnpackSize - || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize) - break; - } - else if (processed >= (1 << 17)) - { - p->nowPos64 += nowPos32 - startPos32; - return CheckErrors(p); - } - } - } - - p->nowPos64 += nowPos32 - startPos32; - return Flush(p, nowPos32); -} - - - -#define kBigHashDicLimit ((UInt32)1 << 24) - -static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - UInt32 beforeSize = kNumOpts; - UInt32 dictSize; - - if (!RangeEnc_Alloc(&p->rc, alloc)) - return SZ_ERROR_MEM; - - #ifndef Z7_ST - p->mtMode = (p->multiThread && !p->fastMode && (MFB.btMode != 0)); - #endif - - { - const unsigned lclp = p->lc + p->lp; - if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) - { - LzmaEnc_FreeLits(p, alloc); - p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((size_t)0x300 * sizeof(CLzmaProb)) << lclp); - p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((size_t)0x300 * sizeof(CLzmaProb)) << lclp); - if (!p->litProbs || !p->saveState.litProbs) - { - LzmaEnc_FreeLits(p, alloc); - return SZ_ERROR_MEM; - } - p->lclp = lclp; - } - } - - MFB.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); - - - dictSize = p->dictSize; - if (dictSize == ((UInt32)2 << 30) || - dictSize == ((UInt32)3 << 30)) - { - /* 21.03 : here we reduce the dictionary for 2 reasons: - 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary. - 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases, - where data size is aligned for 1 GB: 5/6/8 GB. - That reducing must be >= 1 for such corner cases. */ - dictSize -= 1; - } - - if (beforeSize + dictSize < keepWindowSize) - beforeSize = keepWindowSize - dictSize; - - /* in worst case we can look ahead for - max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes. - we send larger value for (keepAfter) to MantchFinder_Create(): - (numFastBytes + LZMA_MATCH_LEN_MAX + 1) - */ - - #ifndef Z7_ST - if (p->mtMode) - { - RINOK(MatchFinderMt_Create(&p->matchFinderMt, dictSize, beforeSize, - p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 18.04 */ - , allocBig)) - p->matchFinderObj = &p->matchFinderMt; - MFB.bigHash = (Byte)(MFB.hashMask >= 0xFFFFFF ? 1 : 0); - MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); - } - else - #endif - { - if (!MatchFinder_Create(&MFB, dictSize, beforeSize, - p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */ - , allocBig)) - return SZ_ERROR_MEM; - p->matchFinderObj = &MFB; - MatchFinder_CreateVTable(&MFB, &p->matchFinder); - } - - return SZ_OK; -} - -static void LzmaEnc_Init(CLzmaEnc *p) -{ - unsigned i; - p->state = 0; - p->reps[0] = - p->reps[1] = - p->reps[2] = - p->reps[3] = 1; - - RangeEnc_Init(&p->rc); - - for (i = 0; i < (1 << kNumAlignBits); i++) - p->posAlignEncoder[i] = kProbInitValue; - - for (i = 0; i < kNumStates; i++) - { - unsigned j; - for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) - { - p->isMatch[i][j] = kProbInitValue; - p->isRep0Long[i][j] = kProbInitValue; - } - p->isRep[i] = kProbInitValue; - p->isRepG0[i] = kProbInitValue; - p->isRepG1[i] = kProbInitValue; - p->isRepG2[i] = kProbInitValue; - } - - { - for (i = 0; i < kNumLenToPosStates; i++) - { - CLzmaProb *probs = p->posSlotEncoder[i]; - unsigned j; - for (j = 0; j < (1 << kNumPosSlotBits); j++) - probs[j] = kProbInitValue; - } - } - { - for (i = 0; i < kNumFullDistances; i++) - p->posEncoders[i] = kProbInitValue; - } - - { - const size_t num = (size_t)0x300 << (p->lp + p->lc); - size_t k; - CLzmaProb *probs = p->litProbs; - for (k = 0; k < num; k++) - probs[k] = kProbInitValue; - } - - - LenEnc_Init(&p->lenProbs); - LenEnc_Init(&p->repLenProbs); - - p->optEnd = 0; - p->optCur = 0; - - { - for (i = 0; i < kNumOpts; i++) - p->opt[i].price = kInfinityPrice; - } - - p->additionalOffset = 0; - - p->pbMask = ((unsigned)1 << p->pb) - 1; - p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc); - - // p->mf_Failure = False; -} - - -static void LzmaEnc_InitPrices(CLzmaEnc *p) -{ - if (!p->fastMode) - { - FillDistancesPrices(p); - FillAlignPrices(p); - } - - p->lenEnc.tableSize = - p->repLenEnc.tableSize = - p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; - - p->repLenEncCounter = REP_LEN_COUNT; - - LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); - LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); -} - -static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - unsigned i; - for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++) - if (p->dictSize <= ((UInt32)1 << i)) - break; - p->distTableSize = i * 2; - - p->finished = False; - p->result = SZ_OK; - p->nowPos64 = 0; - p->needInit = 1; - RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)) - LzmaEnc_Init(p); - LzmaEnc_InitPrices(p); - return SZ_OK; -} - -static SRes LzmaEnc_Prepare(CLzmaEncHandle p, - ISeqOutStreamPtr outStream, - ISeqInStreamPtr inStream, - ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - // GET_CLzmaEnc_p - MatchFinder_SET_STREAM(&MFB, inStream) - p->rc.outStream = outStream; - return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); -} - -SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, - ISeqInStreamPtr inStream, UInt32 keepWindowSize, - ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - // GET_CLzmaEnc_p - MatchFinder_SET_STREAM(&MFB, inStream) - return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); -} - -SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, - const Byte *src, SizeT srcLen, - UInt32 keepWindowSize, - ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - // GET_CLzmaEnc_p - MatchFinder_SET_DIRECT_INPUT_BUF(&MFB, src, srcLen) - LzmaEnc_SetDataSize(p, srcLen); - return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); -} - -void LzmaEnc_Finish(CLzmaEncHandle p) -{ - #ifndef Z7_ST - // GET_CLzmaEnc_p - if (p->mtMode) - MatchFinderMt_ReleaseStream(&p->matchFinderMt); - #else - UNUSED_VAR(p) - #endif -} - - -typedef struct -{ - ISeqOutStream vt; - Byte *data; - size_t rem; - BoolInt overflow; -} CLzmaEnc_SeqOutStreamBuf; - -static size_t SeqOutStreamBuf_Write(ISeqOutStreamPtr pp, const void *data, size_t size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLzmaEnc_SeqOutStreamBuf) - if (p->rem < size) - { - size = p->rem; - p->overflow = True; - } - if (size != 0) - { - memcpy(p->data, data, size); - p->rem -= size; - p->data += size; - } - return size; -} - - -/* -UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p) -{ - GET_const_CLzmaEnc_p - return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); -} -*/ - -const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p) -{ - // GET_const_CLzmaEnc_p - return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; -} - - -// (desiredPackSize == 0) is not allowed -SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, - Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) -{ - // GET_CLzmaEnc_p - UInt64 nowPos64; - SRes res; - CLzmaEnc_SeqOutStreamBuf outStream; - - outStream.vt.Write = SeqOutStreamBuf_Write; - outStream.data = dest; - outStream.rem = *destLen; - outStream.overflow = False; - - p->writeEndMark = False; - p->finished = False; - p->result = SZ_OK; - - if (reInit) - LzmaEnc_Init(p); - LzmaEnc_InitPrices(p); - RangeEnc_Init(&p->rc); - p->rc.outStream = &outStream.vt; - nowPos64 = p->nowPos64; - - res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); - - *unpackSize = (UInt32)(p->nowPos64 - nowPos64); - *destLen -= outStream.rem; - if (outStream.overflow) - return SZ_ERROR_OUTPUT_EOF; - - return res; -} - - -Z7_NO_INLINE -static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgressPtr progress) -{ - SRes res = SZ_OK; - - #ifndef Z7_ST - Byte allocaDummy[0x300]; - allocaDummy[0] = 0; - allocaDummy[1] = allocaDummy[0]; - #endif - - for (;;) - { - res = LzmaEnc_CodeOneBlock(p, 0, 0); - if (res != SZ_OK || p->finished) - break; - if (progress) - { - res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); - if (res != SZ_OK) - { - res = SZ_ERROR_PROGRESS; - break; - } - } - } - - LzmaEnc_Finish((CLzmaEncHandle)(void *)p); - - /* - if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&MFB)) - res = SZ_ERROR_FAIL; - } - */ - - return res; -} - - -SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress, - ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - // GET_CLzmaEnc_p - RINOK(LzmaEnc_Prepare(p, outStream, inStream, alloc, allocBig)) - return LzmaEnc_Encode2(p, progress); -} - - -SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *props, SizeT *size) -{ - if (*size < LZMA_PROPS_SIZE) - return SZ_ERROR_PARAM; - *size = LZMA_PROPS_SIZE; - { - // GET_CLzmaEnc_p - const UInt32 dictSize = p->dictSize; - UInt32 v; - props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); - - // we write aligned dictionary value to properties for lzma decoder - if (dictSize >= ((UInt32)1 << 21)) - { - const UInt32 kDictMask = ((UInt32)1 << 20) - 1; - v = (dictSize + kDictMask) & ~kDictMask; - if (v < dictSize) - v = dictSize; - } - else - { - unsigned i = 11 * 2; - do - { - v = (UInt32)(2 + (i & 1)) << (i >> 1); - i++; - } - while (v < dictSize); - } - - SetUi32(props + 1, v) - return SZ_OK; - } -} - - -unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p) -{ - // GET_CLzmaEnc_p - return (unsigned)p->writeEndMark; -} - - -SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - SRes res; - // GET_CLzmaEnc_p - - CLzmaEnc_SeqOutStreamBuf outStream; - - outStream.vt.Write = SeqOutStreamBuf_Write; - outStream.data = dest; - outStream.rem = *destLen; - outStream.overflow = False; - - p->writeEndMark = writeEndMark; - p->rc.outStream = &outStream.vt; - - res = LzmaEnc_MemPrepare(p, src, srcLen, 0, alloc, allocBig); - - if (res == SZ_OK) - { - res = LzmaEnc_Encode2(p, progress); - if (res == SZ_OK && p->nowPos64 != srcLen) - res = SZ_ERROR_FAIL; - } - - *destLen -= (SizeT)outStream.rem; - if (outStream.overflow) - return SZ_ERROR_OUTPUT_EOF; - return res; -} - - -SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - CLzmaEncHandle p = LzmaEnc_Create(alloc); - SRes res; - if (!p) - return SZ_ERROR_MEM; - - res = LzmaEnc_SetProps(p, props); - if (res == SZ_OK) - { - res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); - if (res == SZ_OK) - res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, - writeEndMark, progress, alloc, allocBig); - } - - LzmaEnc_Destroy(p, alloc, allocBig); - return res; -} - - -/* -#ifndef Z7_ST -void LzmaEnc_GetLzThreads(CLzmaEncHandle p, HANDLE lz_threads[2]) -{ - GET_const_CLzmaEnc_p - lz_threads[0] = p->matchFinderMt.hashSync.thread; - lz_threads[1] = p->matchFinderMt.btSync.thread; -} -#endif -*/ +/* LzmaEnc.c -- LZMA Encoder +Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "CpuArch.h" +#include "LzmaEnc.h" + +#include "LzFind.h" +#ifndef Z7_ST +#include "LzFindMt.h" +#endif + +/* the following LzmaEnc_* declarations is internal LZMA interface for LZMA2 encoder */ + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p); +void LzmaEnc_Finish(CLzmaEncHandle p); +void LzmaEnc_SaveState(CLzmaEncHandle p); +void LzmaEnc_RestoreState(CLzmaEncHandle p); + +#ifdef SHOW_STAT +static unsigned g_STAT_OFFSET = 0; +#endif + +/* for good normalization speed we still reserve 256 MB before 4 GB range */ +#define kLzmaMaxHistorySize ((UInt32)15 << 28) + +// #define kNumTopBits 24 +#define kTopValue ((UInt32)1 << 24) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +// #define kBitPrice (1 << kNumBitPriceShiftBits) + +#define REP_LEN_COUNT 64 + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->reduceSize = (UInt64)(Int64)-1; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->numHashOutBits = 0; + p->writeEndMark = 0; + p->affinity = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + + if (p->dictSize == 0) + p->dictSize = (unsigned)level <= 4 ? + (UInt32)1 << (level * 2 + 16) : + (unsigned)level <= sizeof(size_t) / 2 + 4 ? + (UInt32)1 << (level + 20) : + (UInt32)1 << (sizeof(size_t) / 2 + 24); + + if (p->dictSize > p->reduceSize) + { + UInt32 v = (UInt32)p->reduceSize; + const UInt32 kReduceMin = ((UInt32)1 << 12); + if (v < kReduceMin) + v = kReduceMin; + if (p->dictSize > v) + p->dictSize = v; + } + + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + + if (p->algo < 0) p->algo = (unsigned)level < 5 ? 0 : 1; + if (p->fb < 0) p->fb = (unsigned)level < 7 ? 32 : 64; + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = (p->btMode ? 4 : 5); + if (p->mc == 0) p->mc = (16 + ((unsigned)p->fb >> 1)) >> (p->btMode ? 0 : 1); + + if (p->numThreads < 0) + p->numThreads = + #ifndef Z7_ST + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + + +/* +x86/x64: + +BSR: + IF (SRC == 0) ZF = 1, DEST is undefined; + AMD : DEST is unchanged; + IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit + BSR is slow in some processors + +LZCNT: + IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64) + IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits + IF (DEST == 0) ZF = 1; + +LZCNT works only in new processors starting from Haswell. +if LZCNT is not supported by processor, then it's executed as BSR. +LZCNT can be faster than BSR, if supported. +*/ + +// #define LZMA_LOG_BSR + +#if defined(MY_CPU_ARM_OR_ARM64) /* || defined(MY_CPU_X86_OR_AMD64) */ + + #if (defined(__clang__) && (__clang_major__ >= 6)) \ + || (defined(__GNUC__) && (__GNUC__ >= 6)) + #define LZMA_LOG_BSR + #elif defined(_MSC_VER) && (_MSC_VER >= 1300) + // #if defined(MY_CPU_ARM_OR_ARM64) + #define LZMA_LOG_BSR + // #endif + #endif +#endif + +// #include + +#ifdef LZMA_LOG_BSR + +#if defined(__clang__) \ + || defined(__GNUC__) + +/* + C code: : (30 - __builtin_clz(x)) + gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31) + clang10 for x64 : 31 + (bsr(x) xor -32) +*/ + + #define MY_clz(x) ((unsigned)__builtin_clz(x)) + // __lzcnt32 + // __builtin_ia32_lzcnt_u32 + +#else // #if defined(_MSC_VER) + + #ifdef MY_CPU_ARM_OR_ARM64 + + #define MY_clz _CountLeadingZeros + + #else // if defined(MY_CPU_X86_OR_AMD64) + + // #define MY_clz __lzcnt // we can use lzcnt (unsupported by old CPU) + // _BitScanReverse code is not optimal for some MSVC compilers + #define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); zz--; \ + res = (zz + zz) + (pos >> zz); } + + #endif // MY_CPU_X86_OR_AMD64 + +#endif // _MSC_VER + + +#ifndef BSR2_RET + + #define BSR2_RET(pos, res) { unsigned zz = 30 - MY_clz(pos); \ + res = (zz + zz) + (pos >> zz); } + +#endif + + +unsigned GetPosSlot1(UInt32 pos); +unsigned GetPosSlot1(UInt32 pos) +{ + unsigned res; + BSR2_RET(pos, res) + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res) } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res) } + + +#else // ! LZMA_LOG_BSR + +#define kNumLogBits (11 + sizeof(size_t) / 8 * 3) + +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +static void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + unsigned slot; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + g_FastPos += 2; + + for (slot = 2; slot < kNumLogBits * 2; slot++) + { + size_t k = ((size_t)1 << ((slot >> 1) - 1)); + size_t j; + for (j = 0; j < k; j++) + g_FastPos[j] = (Byte)slot; + g_FastPos += k; + } +} + +/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ +/* +#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } +*/ + +/* +#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } +*/ + +#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ + res = p->g_FastPos[pos >> zz] + (zz * 2); } + +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); } + +#endif // LZMA_LOG_BSR + + +#define LZMA_NUM_REPS 4 + +typedef UInt16 CState; +typedef UInt16 CExtra; + +typedef struct +{ + UInt32 price; + CState state; + CExtra extra; + // 0 : normal + // 1 : LIT : MATCH + // > 1 : MATCH (extra-1) : LIT : REP0 (len) + UInt32 len; + UInt32 dist; + UInt32 reps[LZMA_NUM_REPS]; +} COptimal; + + +// 18.06 +#define kNumOpts (1 << 11) +#define kPackReserve (kNumOpts * 8) +// #define kNumOpts (1 << 12) +// #define kPackReserve (1 + kNumOpts * 2) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +// #define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +typedef +#ifdef Z7_LZMA_PROB32 + UInt32 +#else + UInt16 +#endif + CLzmaProb; + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) +#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + + +typedef struct +{ + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + + +typedef struct +{ + unsigned tableSize; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2]; + // UInt32 prices2[kLenNumSymbolsTotal]; +} CLenPriceEnc; + +#define GET_PRICE_LEN(p, posState, len) \ + ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN]) + +/* +#define GET_PRICE_LEN(p, posState, len) \ + ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9))) +*/ + +typedef struct +{ + UInt32 range; + unsigned cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStreamPtr outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + + +typedef struct +{ + CLzmaProb *litProbs; + + unsigned state; + UInt32 reps[LZMA_NUM_REPS]; + + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances]; + + CLenEnc lenProbs; + CLenEnc repLenProbs; + +} CSaveState; + + +typedef UInt32 CProbPrice; + + +struct CLzmaEnc +{ + void *matchFinderObj; + IMatchFinder2 matchFinder; + + unsigned optCur; + unsigned optEnd; + + unsigned longestMatchLen; + unsigned numPairs; + UInt32 numAvail; + + unsigned state; + unsigned numFastBytes; + unsigned additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + unsigned lpMask, pbMask; + CLzmaProb *litProbs; + CRangeEnc rc; + + UInt32 backRes; + + unsigned lc, lp, pb; + unsigned lclp; + + BoolInt fastMode; + BoolInt writeEndMark; + BoolInt finished; + BoolInt multiThread; + BoolInt needInit; + // BoolInt _maxMode; + + UInt64 nowPos64; + + unsigned matchPriceCount; + // unsigned alignPriceCount; + int repLenEncCounter; + + unsigned distTableSize; + + UInt32 dictSize; + SRes result; + + #ifndef Z7_ST + BoolInt mtMode; + // begin of CMatchFinderMt is used in LZ thread + CMatchFinderMt matchFinderMt; + // end of CMatchFinderMt is used in BT and HASH threads + // #else + // CMatchFinder matchFinderBase; + #endif + CMatchFinder matchFinderBase; + + + // we suppose that we have 8-bytes alignment after CMatchFinder + + #ifndef Z7_ST + Byte pad[128]; + #endif + + // LZ thread + CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + + // we want {len , dist} pairs to be 8-bytes aligned in matches array + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2]; + + // we want 8-bytes alignment here + UInt32 alignPrices[kAlignTableSize]; + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances]; + + CLenEnc lenProbs; + CLenEnc repLenProbs; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + COptimal opt[kNumOpts]; + + CSaveState saveState; + + // BoolInt mf_Failure; + #ifndef Z7_ST + Byte pad2[128]; + #endif +}; + + +#define MFB (p->matchFinderBase) +/* +#ifndef Z7_ST +#define MFB (p->matchFinderMt.MatchFinder) +#endif +*/ + +// #define GET_CLzmaEnc_p CLzmaEnc *p = (CLzmaEnc*)(void *)p; +// #define GET_const_CLzmaEnc_p const CLzmaEnc *p = (const CLzmaEnc*)(const void *)p; + +#define COPY_ARR(dest, src, arr) memcpy((dest)->arr, (src)->arr, sizeof((src)->arr)); + +#define COPY_LZMA_ENC_STATE(d, s, p) \ + (d)->state = (s)->state; \ + COPY_ARR(d, s, reps) \ + COPY_ARR(d, s, posAlignEncoder) \ + COPY_ARR(d, s, isRep) \ + COPY_ARR(d, s, isRepG0) \ + COPY_ARR(d, s, isRepG1) \ + COPY_ARR(d, s, isRepG2) \ + COPY_ARR(d, s, isMatch) \ + COPY_ARR(d, s, isRep0Long) \ + COPY_ARR(d, s, posSlotEncoder) \ + COPY_ARR(d, s, posEncoders) \ + (d)->lenProbs = (s)->lenProbs; \ + (d)->repLenProbs = (s)->repLenProbs; \ + memcpy((d)->litProbs, (s)->litProbs, ((size_t)0x300 * sizeof(CLzmaProb)) << (p)->lclp); + +void LzmaEnc_SaveState(CLzmaEncHandle p) +{ + // GET_CLzmaEnc_p + CSaveState *v = &p->saveState; + COPY_LZMA_ENC_STATE(v, p, p) +} + +void LzmaEnc_RestoreState(CLzmaEncHandle p) +{ + // GET_CLzmaEnc_p + const CSaveState *v = &p->saveState; + COPY_LZMA_ENC_STATE(p, v, p) +} + + +Z7_NO_INLINE +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props2) +{ + // GET_CLzmaEnc_p + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX + || props.lp > LZMA_LP_MAX + || props.pb > LZMA_PB_MAX) + return SZ_ERROR_PARAM; + + + if (props.dictSize > kLzmaMaxHistorySize) + props.dictSize = kLzmaMaxHistorySize; + + #ifndef LZMA_LOG_BSR + { + const UInt64 dict64 = props.dictSize; + if (dict64 > ((UInt64)1 << kDicLogSizeMaxCompress)) + return SZ_ERROR_PARAM; + } + #endif + + p->dictSize = props.dictSize; + { + unsigned fb = (unsigned)props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = (unsigned)props.lc; + p->lp = (unsigned)props.lp; + p->pb = (unsigned)props.pb; + p->fastMode = (props.algo == 0); + // p->_maxMode = True; + MFB.btMode = (Byte)(props.btMode ? 1 : 0); + // MFB.btMode = (Byte)(props.btMode); + { + unsigned numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) numHashBytes = 2; + else if (props.numHashBytes < 4) numHashBytes = (unsigned)props.numHashBytes; + } + if (props.numHashBytes >= 5) numHashBytes = 5; + + MFB.numHashBytes = numHashBytes; + // MFB.numHashBytes_Min = 2; + MFB.numHashOutBits = (Byte)props.numHashOutBits; + } + + MFB.cutValue = props.mc; + + p->writeEndMark = (BoolInt)props.writeEndMark; + + #ifndef Z7_ST + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + p->matchFinderMt.btSync.affinity = + p->matchFinderMt.hashSync.affinity = props.affinity; + #endif + + return SZ_OK; +} + + +void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize) +{ + // GET_CLzmaEnc_p + MFB.expectedDataSize = expectedDataSiize; +} + + +#define kState_Start 0 +#define kState_LitAfterMatch 4 +#define kState_LitAfterRep 5 +#define kState_MatchAfterLit 7 +#define kState_RepAfterLit 8 + +static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsLitState(s) ((s) < 7) +#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1) +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = NULL; + p->bufBase = NULL; +} + +#define RangeEnc_GetProcessed(p) ( (p)->processed + (size_t)((p)->buf - (p)->bufBase) + (p)->cacheSize) +#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + (size_t)((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) + +static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc) +{ + if (!p->bufBase) + { + p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE); + if (!p->bufBase) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->bufBase); + p->bufBase = NULL; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + p->range = 0xFFFFFFFF; + p->cache = 0; + p->low = 0; + p->cacheSize = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +Z7_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p) +{ + const size_t num = (size_t)(p->buf - p->bufBase); + if (p->res == SZ_OK) + { + if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + } + p->processed += num; + p->buf = p->bufBase; +} + +Z7_NO_INLINE static void Z7_FASTCALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + UInt32 low = (UInt32)p->low; + unsigned high = (unsigned)(p->low >> 32); + p->low = (UInt32)(low << 8); + if (low < (UInt32)0xFF000000 || high != 0) + { + { + Byte *buf = p->buf; + *buf++ = (Byte)(p->cache + high); + p->cache = (unsigned)(low >> 24); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + if (p->cacheSize == 0) + return; + } + high += 0xFF; + for (;;) + { + Byte *buf = p->buf; + *buf++ = (Byte)(high); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + if (--p->cacheSize == 0) + return; + } + } + p->cacheSize++; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); } + +#define RC_BIT_PRE(p, prob) \ + ttt = *(prob); \ + newBound = (range >> kNumBitModelTotalBits) * ttt; + +// #define Z7_LZMA_ENC_USE_BRANCH + +#ifdef Z7_LZMA_ENC_USE_BRANCH + +#define RC_BIT(p, prob, bit) { \ + RC_BIT_PRE(p, prob) \ + if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \ + else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \ + *(prob) = (CLzmaProb)ttt; \ + RC_NORM(p) \ + } + +#else + +#define RC_BIT(p, prob, bit) { \ + UInt32 mask; \ + RC_BIT_PRE(p, prob) \ + mask = 0 - (UInt32)bit; \ + range &= mask; \ + mask &= newBound; \ + range -= mask; \ + (p)->low += mask; \ + mask = (UInt32)bit - 1; \ + range += newBound & mask; \ + mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \ + mask += ((1 << kNumMoveBits) - 1); \ + ttt += (UInt32)((Int32)(mask - ttt) >> kNumMoveBits); \ + *(prob) = (CLzmaProb)ttt; \ + RC_NORM(p) \ + } + +#endif + + + + +#define RC_BIT_0_BASE(p, prob) \ + range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + +#define RC_BIT_1_BASE(p, prob) \ + range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \ + +#define RC_BIT_0(p, prob) \ + RC_BIT_0_BASE(p, prob) \ + RC_NORM(p) + +#define RC_BIT_1(p, prob) \ + RC_BIT_1_BASE(p, prob) \ + RC_NORM(p) + +static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob) +{ + UInt32 range, ttt, newBound; + range = p->range; + RC_BIT_PRE(p, prob) + RC_BIT_0(p, prob) + p->range = range; +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym) +{ + UInt32 range = p->range; + sym |= 0x100; + do + { + UInt32 ttt, newBound; + // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1); + CLzmaProb *prob = probs + (sym >> 8); + UInt32 bit = (sym >> 7) & 1; + sym <<= 1; + RC_BIT(p, prob, bit) + } + while (sym < 0x10000); + p->range = range; +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte) +{ + UInt32 range = p->range; + UInt32 offs = 0x100; + sym |= 0x100; + do + { + UInt32 ttt, newBound; + CLzmaProb *prob; + UInt32 bit; + matchByte <<= 1; + // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1); + prob = probs + (offs + (matchByte & offs) + (sym >> 8)); + bit = (sym >> 7) & 1; + sym <<= 1; + offs &= ~(matchByte ^ sym); + RC_BIT(p, prob, bit) + } + while (sym < 0x10000); + p->range = range; +} + + + +static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices) +{ + UInt32 i; + for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++) + { + const unsigned kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1)); + unsigned bitCount = 0; + unsigned j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i] = (CProbPrice)(((unsigned)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + // printf("\n%3d: %5d", i, ProbPrices[i]); + } +} + + +#define GET_PRICE(prob, bit) \ + p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits] + +#define GET_PRICEa(prob, bit) \ + ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits] + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices) +{ + UInt32 price = 0; + sym |= 0x100; + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[sym], bit); + } + while (sym >= 2); + return price; +} + + +static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + sym |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1); + sym <<= 1; + offs &= ~(matchByte ^ sym); + } + while (sym < 0x10000); + return price; +} + + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym) +{ + UInt32 range = rc->range; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + unsigned bit = sym & 1; + // RangeEnc_EncodeBit(rc, probs + m, bit); + sym >>= 1; + RC_BIT(rc, probs + m, bit) + m = (m << 1) | bit; + } + while (--numBits); + rc->range = range; +} + + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState) +{ + UInt32 range, ttt, newBound; + CLzmaProb *probs = p->low; + range = rc->range; + RC_BIT_PRE(rc, probs) + if (sym >= kLenNumLowSymbols) + { + RC_BIT_1(rc, probs) + probs += kLenNumLowSymbols; + RC_BIT_PRE(rc, probs) + if (sym >= kLenNumLowSymbols * 2) + { + RC_BIT_1(rc, probs) + rc->range = range; + // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2); + LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2); + return; + } + sym -= kLenNumLowSymbols; + } + + // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym); + { + unsigned m; + unsigned bit; + RC_BIT_0(rc, probs) + probs += (posState << (1 + kLenNumLowBits)); + bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit; + bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit; + bit = sym & 1; RC_BIT(rc, probs + m, bit) + rc->range = range; + } +} + +static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices) +{ + unsigned i; + for (i = 0; i < 8; i += 2) + { + UInt32 price = startPrice; + UInt32 prob; + price += GET_PRICEa(probs[1 ], (i >> 2)); + price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1); + prob = probs[4 + (i >> 1)]; + prices[i ] = price + GET_PRICEa_0(prob); + prices[i + 1] = price + GET_PRICEa_1(prob); + } +} + + +Z7_NO_INLINE static void Z7_FASTCALL LenPriceEnc_UpdateTables( + CLenPriceEnc *p, + unsigned numPosStates, + const CLenEnc *enc, + const CProbPrice *ProbPrices) +{ + UInt32 b; + + { + unsigned prob = enc->low[0]; + UInt32 a, c; + unsigned posState; + b = GET_PRICEa_1(prob); + a = GET_PRICEa_0(prob); + c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); + for (posState = 0; posState < numPosStates; posState++) + { + UInt32 *prices = p->prices[posState]; + const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); + SetPrices_3(probs, a, prices, ProbPrices); + SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); + } + } + + /* + { + unsigned i; + UInt32 b; + a = GET_PRICEa_0(enc->low[0]); + for (i = 0; i < kLenNumLowSymbols; i++) + p->prices2[i] = a; + a = GET_PRICEa_1(enc->low[0]); + b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]); + for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++) + p->prices2[i] = b; + a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); + } + */ + + // p->counter = numSymbols; + // p->counter = 64; + + { + unsigned i = p->tableSize; + + if (i > kLenNumLowSymbols * 2) + { + const CLzmaProb *probs = enc->high; + UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2; + i -= kLenNumLowSymbols * 2 - 1; + i >>= 1; + b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]); + do + { + /* + p->prices2[i] = a + + // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices); + LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices); + */ + // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices); + unsigned sym = --i + (1 << (kLenNumHighBits - 1)); + UInt32 price = b; + do + { + const unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[sym], bit); + } + while (sym >= 2); + + { + const unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))]; + prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob); + prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob); + } + } + while (i); + + { + unsigned posState; + const size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]); + for (posState = 1; posState < numPosStates; posState++) + memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num); + } + } + } +} + +/* + #ifdef SHOW_STAT + g_STAT_OFFSET += num; + printf("\n MovePos %u", num); + #endif +*/ + +#define MOVE_POS(p, num) { \ + p->additionalOffset += (num); \ + p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); } + + +static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes) +{ + unsigned numPairs; + + p->additionalOffset++; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + { + const UInt32 *d = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; } + numPairs = (unsigned)(d - p->matches); + } + *numPairsRes = numPairs; + + #ifdef SHOW_STAT + printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); + g_STAT_OFFSET++; + { + unsigned i; + for (i = 0; i < numPairs; i += 2) + printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); + } + #endif + + if (numPairs == 0) + return 0; + { + const unsigned len = p->matches[(size_t)numPairs - 2]; + if (len != p->numFastBytes) + return len; + { + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + const Byte *p2 = p1 + len; + const ptrdiff_t dif = (ptrdiff_t)-1 - (ptrdiff_t)p->matches[(size_t)numPairs - 1]; + const Byte *lim = p1 + numAvail; + for (; p2 != lim && *p2 == p2[dif]; p2++) + {} + return (unsigned)(p2 - p1); + } + } + } +} + +#define MARK_LIT ((UInt32)(Int32)-1) + +#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; } +#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; } +#define IsShortRep(p) ((p)->dist == 0) + + +#define GetPrice_ShortRep(p, state, posState) \ + ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState])) + +#define GetPrice_Rep_0(p, state, posState) ( \ + GET_PRICE_1(p->isMatch[state][posState]) \ + + GET_PRICE_1(p->isRep0Long[state][posState])) \ + + GET_PRICE_1(p->isRep[state]) \ + + GET_PRICE_0(p->isRepG0[state]) + +Z7_FORCE_INLINE +static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState) +{ + UInt32 price; + UInt32 prob = p->isRepG0[state]; + if (repIndex == 0) + { + price = GET_PRICE_0(prob); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(prob); + prob = p->isRepG1[state]; + if (repIndex == 1) + price += GET_PRICE_0(prob); + else + { + price += GET_PRICE_1(prob); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + + +static unsigned Backward(CLzmaEnc *p, unsigned cur) +{ + unsigned wr = cur + 1; + p->optEnd = wr; + + for (;;) + { + UInt32 dist = p->opt[cur].dist; + unsigned len = (unsigned)p->opt[cur].len; + unsigned extra = (unsigned)p->opt[cur].extra; + cur -= len; + + if (extra) + { + wr--; + p->opt[wr].len = (UInt32)len; + cur -= extra; + len = extra; + if (extra == 1) + { + p->opt[wr].dist = dist; + dist = MARK_LIT; + } + else + { + p->opt[wr].dist = 0; + len--; + wr--; + p->opt[wr].dist = MARK_LIT; + p->opt[wr].len = 1; + } + } + + if (cur == 0) + { + p->backRes = dist; + p->optCur = wr; + return len; + } + + wr--; + p->opt[wr].dist = dist; + p->opt[wr].len = (UInt32)len; + } +} + + + +#define LIT_PROBS(pos, prevByte) \ + (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc)) + + +static unsigned GetOptimum(CLzmaEnc *p, UInt32 position) +{ + unsigned last, cur; + UInt32 reps[LZMA_NUM_REPS]; + unsigned repLens[LZMA_NUM_REPS]; + UInt32 *matches; + + { + UInt32 numAvail; + unsigned numPairs, mainLen, repMaxIndex, i, posState; + UInt32 matchPrice, repMatchPrice; + const Byte *data; + Byte curByte, matchByte; + + p->optCur = p->optEnd = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLen; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + p->backRes = MARK_LIT; + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + repLens[i] = len; + if (len > repLens[repMaxIndex]) + repMaxIndex = i; + if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization + break; + } + + if (repLens[repMaxIndex] >= p->numFastBytes) + { + unsigned len; + p->backRes = (UInt32)repMaxIndex; + len = repLens[repMaxIndex]; + MOVE_POS(p, len - 1) + return len; + } + + matches = p->matches; + #define MATCHES matches + // #define MATCHES p->matches + + if (mainLen >= p->numFastBytes) + { + p->backRes = MATCHES[(size_t)numPairs - 1] + LZMA_NUM_REPS; + MOVE_POS(p, mainLen - 1) + return mainLen; + } + + curByte = *data; + matchByte = *(data - reps[0]); + + last = repLens[repMaxIndex]; + if (last <= mainLen) + last = mainLen; + + if (last < 2 && curByte != matchByte) + { + p->backRes = MARK_LIT; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsLitState(p->state) ? + LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAs_Lit(&p->opt[1]) + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + // 18.06 + if (matchByte == curByte && repLens[0] == 0) + { + UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAs_ShortRep(&p->opt[1]) + } + if (last < 2) + { + p->backRes = p->opt[1].dist; + return 1; + } + } + + p->opt[1].len = 1; + + p->opt[0].reps[0] = reps[0]; + p->opt[0].reps[1] = reps[1]; + p->opt[0].reps[2] = reps[2]; + p->opt[0].reps[3] = reps[3]; + + // ---------- REP ---------- + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState); + do + { + UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen); + COptimal *opt = &p->opt[repLen]; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)repLen; + opt->dist = (UInt32)i; + opt->extra = 0; + } + } + while (--repLen >= 2); + } + + + // ---------- MATCH ---------- + { + unsigned len = repLens[0] + 1; + if (len <= mainLen) + { + unsigned offs = 0; + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + if (len < 2) + len = 2; + else + while (len > MATCHES[offs]) + offs += 2; + + for (; ; len++) + { + COptimal *opt; + UInt32 dist = MATCHES[(size_t)offs + 1]; + UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); + unsigned lenToPosState = GetLenToPosState(len); + + if (dist < kNumFullDistances) + price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)]; + else + { + unsigned slot; + GetPosSlot2(dist, slot) + price += p->alignPrices[dist & kAlignMask]; + price += p->posSlotPrices[lenToPosState][slot]; + } + + opt = &p->opt[len]; + + if (price < opt->price) + { + opt->price = price; + opt->len = (UInt32)len; + opt->dist = dist + LZMA_NUM_REPS; + opt->extra = 0; + } + + if (len == MATCHES[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + } + + + cur = 0; + + #ifdef SHOW_STAT2 + /* if (position >= 0) */ + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= last; i++) + printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); + } + #endif + } + + + + // ---------- Optimal Parsing ---------- + + for (;;) + { + unsigned numAvail; + UInt32 numAvailFull; + unsigned newLen, numPairs, prev, state, posState, startLen; + UInt32 litPrice, matchPrice, repMatchPrice; + BoolInt nextIsLit; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt, *nextOpt; + + if (++cur == last) + break; + + // 18.06 + if (cur >= kNumOpts - 64) + { + unsigned j, best; + UInt32 price = p->opt[cur].price; + best = cur; + for (j = cur + 1; j <= last; j++) + { + UInt32 price2 = p->opt[j].price; + if (price >= price2) + { + price = price2; + best = j; + } + } + { + unsigned delta = best - cur; + if (delta != 0) + { + MOVE_POS(p, delta) + } + } + cur = best; + break; + } + + newLen = ReadMatchDistances(p, &numPairs); + + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLen = newLen; + break; + } + + curOpt = &p->opt[cur]; + + position++; + + // we need that check here, if skip_items in p->opt are possible + /* + if (curOpt->price >= kInfinityPrice) + continue; + */ + + prev = cur - curOpt->len; + + if (curOpt->len == 1) + { + state = (unsigned)p->opt[prev].state; + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + const COptimal *prevOpt; + UInt32 b0; + UInt32 dist = curOpt->dist; + + if (curOpt->extra) + { + prev -= (unsigned)curOpt->extra; + state = kState_RepAfterLit; + if (curOpt->extra == 1) + state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit); + } + else + { + state = (unsigned)p->opt[prev].state; + if (dist < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + + prevOpt = &p->opt[prev]; + b0 = prevOpt->reps[0]; + + if (dist < LZMA_NUM_REPS) + { + if (dist == 0) + { + reps[0] = b0; + reps[1] = prevOpt->reps[1]; + reps[2] = prevOpt->reps[2]; + reps[3] = prevOpt->reps[3]; + } + else + { + reps[1] = b0; + b0 = prevOpt->reps[1]; + if (dist == 1) + { + reps[0] = b0; + reps[2] = prevOpt->reps[2]; + reps[3] = prevOpt->reps[3]; + } + else + { + reps[2] = b0; + reps[0] = prevOpt->reps[dist]; + reps[3] = prevOpt->reps[dist ^ 1]; + } + } + } + else + { + reps[0] = (dist - LZMA_NUM_REPS + 1); + reps[1] = b0; + reps[2] = prevOpt->reps[1]; + reps[3] = prevOpt->reps[2]; + } + } + + curOpt->state = (CState)state; + curOpt->reps[0] = reps[0]; + curOpt->reps[1] = reps[1]; + curOpt->reps[2] = reps[2]; + curOpt->reps[3] = reps[3]; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - reps[0]); + + posState = (position & p->pbMask); + + /* + The order of Price checks: + < LIT + <= SHORT_REP + < LIT : REP_0 + < REP [ : LIT : REP_0 ] + < MATCH [ : LIT : REP_0 ] + */ + + { + UInt32 curPrice = curOpt->price; + unsigned prob = p->isMatch[state][posState]; + matchPrice = curPrice + GET_PRICE_1(prob); + litPrice = curPrice + GET_PRICE_0(prob); + } + + nextOpt = &p->opt[(size_t)cur + 1]; + nextIsLit = False; + + // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice) + // 18.new.06 + if ((nextOpt->price < kInfinityPrice + // && !IsLitState(state) + && matchByte == curByte) + || litPrice > nextOpt->price + ) + litPrice = 0; + else + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + litPrice += (!IsLitState(state) ? + LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + + if (litPrice < nextOpt->price) + { + nextOpt->price = litPrice; + nextOpt->len = 1; + MakeAs_Lit(nextOpt) + nextIsLit = True; + } + } + + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + numAvailFull = p->numAvail; + { + unsigned temp = kNumOpts - 1 - cur; + if (numAvailFull > temp) + numAvailFull = (UInt32)temp; + } + + // 18.06 + // ---------- SHORT_REP ---------- + if (IsLitState(state)) // 18.new + if (matchByte == curByte) + if (repMatchPrice < nextOpt->price) // 18.new + // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1)) + if ( + // nextOpt->price >= kInfinityPrice || + nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt + || (nextOpt->dist != 0 + // && nextOpt->extra <= 1 // 17.old + ) + ) + { + UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState); + // if (shortRepPrice <= nextOpt->price) // 17.old + if (shortRepPrice < nextOpt->price) // 18.new + { + nextOpt->price = shortRepPrice; + nextOpt->len = 1; + MakeAs_ShortRep(nextOpt) + nextIsLit = False; + } + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + // numAvail <= p->numFastBytes + + // ---------- LIT : REP_0 ---------- + + if (!nextIsLit + && litPrice != 0 // 18.new + && matchByte != curByte + && numAvailFull > 2) + { + const Byte *data2 = data - reps[0]; + if (data[1] == data2[1] && data[2] == data2[2]) + { + unsigned len; + unsigned limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + for (len = 3; len < limit && data[len] == data2[len]; len++) + {} + + { + unsigned state2 = kLiteralNextStates[state]; + unsigned posState2 = (position + 1) & p->pbMask; + UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2); + { + unsigned offset = cur + len; + + if (last < offset) + last = offset; + + // do + { + UInt32 price2; + COptimal *opt; + len--; + // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len); + + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len; + opt->dist = 0; + opt->extra = 1; + } + } + // while (len >= 3); + } + } + } + } + + startLen = 2; /* speed optimization */ + + { + // ---------- REP ---------- + unsigned repIndex = 0; // 17.old + // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused + for (; repIndex < LZMA_NUM_REPS; repIndex++) + { + unsigned len; + UInt32 price; + const Byte *data2 = data - reps[repIndex]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + + // if (len < startLen) continue; // 18.new: speed optimization + + { + unsigned offset = cur + len; + if (last < offset) + last = offset; + } + { + unsigned len2 = len; + price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState); + do + { + UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2); + COptimal *opt = &p->opt[cur + len2]; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->dist = (UInt32)repIndex; + opt->extra = 0; + } + } + while (--len2 >= 2); + } + + if (repIndex == 0) startLen = len + 1; // 17.old + // startLen = len + 1; // 18.new + + /* if (_maxMode) */ + { + // ---------- REP : LIT : REP_0 ---------- + // numFastBytes + 1 + numFastBytes + + unsigned len2 = len + 1; + unsigned limit = len2 + p->numFastBytes; + if (limit > numAvailFull) + limit = numAvailFull; + + len2 += 2; + if (len2 <= limit) + if (data[len2 - 2] == data2[len2 - 2]) + if (data[len2 - 1] == data2[len2 - 1]) + { + unsigned state2 = kRepNextStates[state]; + unsigned posState2 = (position + len) & p->pbMask; + price += GET_PRICE_LEN(&p->repLenEnc, posState, len) + + GET_PRICE_0(p->isMatch[state2][posState2]) + + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), + data[len], data2[len], p->ProbPrices); + + // state2 = kLiteralNextStates[state2]; + state2 = kState_LitAfterRep; + posState2 = (posState2 + 1) & p->pbMask; + + + price += GetPrice_Rep_0(p, state2, posState2); + + for (; len2 < limit && data[len2] == data2[len2]; len2++) + {} + + len2 -= len; + // if (len2 >= 3) + { + { + unsigned offset = cur + len + len2; + + if (last < offset) + last = offset; + // do + { + UInt32 price2; + COptimal *opt; + len2--; + // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); + + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->extra = (CExtra)(len + 1); + opt->dist = (UInt32)repIndex; + } + } + // while (len2 >= 3); + } + } + } + } + } + } + + + // ---------- MATCH ---------- + /* for (unsigned len = 2; len <= newLen; len++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > MATCHES[numPairs]; numPairs += 2); + MATCHES[numPairs] = (UInt32)newLen; + numPairs += 2; + } + + // startLen = 2; /* speed optimization */ + + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 dist; + unsigned offs, posSlot, len; + + { + unsigned offset = cur + newLen; + if (last < offset) + last = offset; + } + + offs = 0; + while (startLen > MATCHES[offs]) + offs += 2; + dist = MATCHES[(size_t)offs + 1]; + + // if (dist >= kNumFullDistances) + GetPosSlot2(dist, posSlot) + + for (len = /*2*/ startLen; ; len++) + { + UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len); + { + COptimal *opt; + unsigned lenNorm = len - 2; + lenNorm = GetLenToPosState2(lenNorm); + if (dist < kNumFullDistances) + price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)]; + else + price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask]; + + opt = &p->opt[cur + len]; + if (price < opt->price) + { + opt->price = price; + opt->len = (UInt32)len; + opt->dist = dist + LZMA_NUM_REPS; + opt->extra = 0; + } + } + + if (len == MATCHES[offs]) + { + // if (p->_maxMode) { + // MATCH : LIT : REP_0 + + const Byte *data2 = data - dist - 1; + unsigned len2 = len + 1; + unsigned limit = len2 + p->numFastBytes; + if (limit > numAvailFull) + limit = numAvailFull; + + len2 += 2; + if (len2 <= limit) + if (data[len2 - 2] == data2[len2 - 2]) + if (data[len2 - 1] == data2[len2 - 1]) + { + for (; len2 < limit && data[len2] == data2[len2]; len2++) + {} + + len2 -= len; + + // if (len2 >= 3) + { + unsigned state2 = kMatchNextStates[state]; + unsigned posState2 = (position + len) & p->pbMask; + unsigned offset; + price += GET_PRICE_0(p->isMatch[state2][posState2]); + price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]), + data[len], data2[len], p->ProbPrices); + + // state2 = kLiteralNextStates[state2]; + state2 = kState_LitAfterMatch; + + posState2 = (posState2 + 1) & p->pbMask; + price += GetPrice_Rep_0(p, state2, posState2); + + offset = cur + len + len2; + + if (last < offset) + last = offset; + // do + { + UInt32 price2; + COptimal *opt; + len2--; + // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2); + price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2); + opt = &p->opt[offset]; + // offset--; + if (price2 < opt->price) + { + opt->price = price2; + opt->len = (UInt32)len2; + opt->extra = (CExtra)(len + 1); + opt->dist = dist + LZMA_NUM_REPS; + } + } + // while (len2 >= 3); + } + + } + + offs += 2; + if (offs == numPairs) + break; + dist = MATCHES[(size_t)offs + 1]; + // if (dist >= kNumFullDistances) + GetPosSlot2(dist, posSlot) + } + } + } + } + + do + p->opt[last].price = kInfinityPrice; + while (--last); + + return Backward(p, cur); +} + + + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + + + +static unsigned GetOptimumFast(CLzmaEnc *p) +{ + UInt32 numAvail, mainDist; + unsigned mainLen, numPairs, repIndex, repLen, i; + const Byte *data; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLen; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + p->backRes = MARK_LIT; + if (numAvail < 2) + return 1; + // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repLen = repIndex = 0; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len; + const Byte *data2 = data - p->reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++) + {} + if (len >= p->numFastBytes) + { + p->backRes = (UInt32)i; + MOVE_POS(p, len - 1) + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + if (mainLen >= p->numFastBytes) + { + p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS; + MOVE_POS(p, mainLen - 1) + return mainLen; + } + + mainDist = 0; /* for GCC */ + + if (mainLen >= 2) + { + mainDist = p->matches[(size_t)numPairs - 1]; + while (numPairs > 2) + { + UInt32 dist2; + if (mainLen != p->matches[(size_t)numPairs - 4] + 1) + break; + dist2 = p->matches[(size_t)numPairs - 3]; + if (!ChangePair(dist2, mainDist)) + break; + numPairs -= 2; + mainLen--; + mainDist = dist2; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2) + if ( repLen + 1 >= mainLen + || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) + || (repLen + 3 >= mainLen && mainDist >= (1 << 15))) + { + p->backRes = (UInt32)repIndex; + MOVE_POS(p, repLen - 1) + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + { + unsigned len1 = ReadMatchDistances(p, &p->numPairs); + p->longestMatchLen = len1; + + if (len1 >= 2) + { + UInt32 newDist = p->matches[(size_t)p->numPairs - 1]; + if ( (len1 >= mainLen && newDist < mainDist) + || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist)) + || (len1 > mainLen + 1) + || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist))) + return 1; + } + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + unsigned len, limit; + const Byte *data2 = data - p->reps[i]; + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2;; len++) + { + if (len >= limit) + return 1; + if (data[len] != data2[len]) + break; + } + } + + p->backRes = mainDist + LZMA_NUM_REPS; + if (mainLen != 2) + { + MOVE_POS(p, mainLen - 2) + } + return mainLen; +} + + + + +static void WriteEndMarker(CLzmaEnc *p, unsigned posState) +{ + UInt32 range; + range = p->rc.range; + { + UInt32 ttt, newBound; + CLzmaProb *prob = &p->isMatch[p->state][posState]; + RC_BIT_PRE(&p->rc, prob) + RC_BIT_1(&p->rc, prob) + prob = &p->isRep[p->state]; + RC_BIT_PRE(&p->rc, prob) + RC_BIT_0(&p->rc, prob) + } + p->state = kMatchNextStates[p->state]; + + p->rc.range = range; + LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState); + range = p->rc.range; + + { + // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1); + CLzmaProb *probs = p->posSlotEncoder[0]; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + RC_BIT_PRE(p, probs + m) + RC_BIT_1(&p->rc, probs + m) + m = (m << 1) + 1; + } + while (m < (1 << kNumPosSlotBits)); + } + { + // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range; + unsigned numBits = 30 - kNumAlignBits; + do + { + range >>= 1; + p->rc.low += range; + RC_NORM(&p->rc) + } + while (--numBits); + } + + { + // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); + CLzmaProb *probs = p->posAlignEncoder; + unsigned m = 1; + do + { + UInt32 ttt, newBound; + RC_BIT_PRE(p, probs + m) + RC_BIT_1(&p->rc, probs + m) + m = (m << 1) + 1; + } + while (m < kAlignTableSize); + } + p->rc.range = range; +} + + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + + #ifndef Z7_ST + if ( + // p->mf_Failure || + (p->mtMode && + ( // p->matchFinderMt.failure_LZ_LZ || + p->matchFinderMt.failure_LZ_BT)) + ) + { + p->result = MY_HRES_ERROR_INTERNAL_ERROR; + // printf("\nCheckErrors p->matchFinderMt.failureLZ\n"); + } + #endif + + if (MFB.result != SZ_OK) + p->result = SZ_ERROR_READ; + + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + + +Z7_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + + +Z7_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) +{ + unsigned i; + const CProbPrice *ProbPrices = p->ProbPrices; + const CLzmaProb *probs = p->posAlignEncoder; + // p->alignPriceCount = 0; + for (i = 0; i < kAlignTableSize / 2; i++) + { + UInt32 price = 0; + unsigned sym = i; + unsigned m = 1; + unsigned bit; + UInt32 prob; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + prob = probs[m]; + p->alignPrices[i ] = price + GET_PRICEa_0(prob); + p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); + // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + } +} + + +Z7_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p) +{ + // int y; for (y = 0; y < 100; y++) { + + UInt32 tempPrices[kNumFullDistances]; + unsigned i, lps; + + const CProbPrice *ProbPrices = p->ProbPrices; + p->matchPriceCount = 0; + + for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++) + { + unsigned posSlot = GetPosSlot1(i); + unsigned footerBits = (posSlot >> 1) - 1; + unsigned base = ((2 | (posSlot & 1)) << footerBits); + const CLzmaProb *probs = p->posEncoders + (size_t)base * 2; + // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices); + UInt32 price = 0; + unsigned m = 1; + unsigned sym = i; + unsigned offset = (unsigned)1 << footerBits; + base += i; + + if (footerBits) + do + { + unsigned bit = sym & 1; + sym >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) + bit; + } + while (--footerBits); + + { + unsigned prob = probs[m]; + tempPrices[base ] = price + GET_PRICEa_0(prob); + tempPrices[base + offset] = price + GET_PRICEa_1(prob); + } + } + + for (lps = 0; lps < kNumLenToPosStates; lps++) + { + unsigned slot; + unsigned distTableSize2 = (p->distTableSize + 1) >> 1; + UInt32 *posSlotPrices = p->posSlotPrices[lps]; + const CLzmaProb *probs = p->posSlotEncoder[lps]; + + for (slot = 0; slot < distTableSize2; slot++) + { + // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices); + UInt32 price; + unsigned bit; + unsigned sym = slot + (1 << (kNumPosSlotBits - 1)); + unsigned prob; + bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit); + prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))]; + posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob); + posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob); + } + + { + UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++) + { + posSlotPrices[(size_t)slot * 2 ] += delta; + posSlotPrices[(size_t)slot * 2 + 1] += delta; + delta += ((UInt32)1 << kNumBitPriceShiftBits); + } + } + + { + UInt32 *dp = p->distancesPrices[lps]; + + dp[0] = posSlotPrices[0]; + dp[1] = posSlotPrices[1]; + dp[2] = posSlotPrices[2]; + dp[3] = posSlotPrices[3]; + + for (i = 4; i < kNumFullDistances; i += 2) + { + UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)]; + dp[i ] = slotPrice + tempPrices[i]; + dp[i + 1] = slotPrice + tempPrices[i + 1]; + } + } + } + // } +} + + + +static void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&MFB); + + #ifndef Z7_ST + p->matchFinderMt.MatchFinder = &MFB; + MatchFinderMt_Construct(&p->matchFinderMt); + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps((CLzmaEncHandle)(void *)p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = NULL; + p->saveState.litProbs = NULL; +} + +CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc) +{ + void *p; + p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc)); + if (p) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->litProbs); + ISzAlloc_Free(alloc, p->saveState.litProbs); + p->litProbs = NULL; + p->saveState.litProbs = NULL; +} + +static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + #ifndef Z7_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + + MatchFinder_Free(&MFB, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + // GET_CLzmaEnc_p + LzmaEnc_Destruct(p, alloc, allocBig); + ISzAlloc_Free(alloc, p); +} + + +Z7_NO_INLINE +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->needInit) + { + #ifndef Z7_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_InitMt(&p->matchFinderMt)) + } + #endif + p->matchFinder.Init(p->matchFinderObj); + p->needInit = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)) + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + unsigned numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]); + // p->state = kLiteralNextStates[p->state]; + curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + + for (;;) + { + UInt32 dist; + unsigned len, posState; + UInt32 range, ttt, newBound; + CLzmaProb *probs; + + if (p->fastMode) + len = GetOptimumFast(p); + else + { + unsigned oci = p->optCur; + if (p->optEnd == oci) + len = GetOptimum(p, nowPos32); + else + { + const COptimal *opt = &p->opt[oci]; + len = opt->len; + p->backRes = opt->dist; + p->optCur = oci + 1; + } + } + + posState = (unsigned)nowPos32 & p->pbMask; + range = p->rc.range; + probs = &p->isMatch[p->state][posState]; + + RC_BIT_PRE(&p->rc, probs) + + dist = p->backRes; + + #ifdef SHOW_STAT2 + printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist); + #endif + + if (dist == MARK_LIT) + { + Byte curByte; + const Byte *data; + unsigned state; + + RC_BIT_0(&p->rc, probs) + p->rc.range = range; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + probs = LIT_PROBS(nowPos32, *(data - 1)); + curByte = *data; + state = p->state; + p->state = kLiteralNextStates[state]; + if (IsLitState(state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0])); + } + else + { + RC_BIT_1(&p->rc, probs) + probs = &p->isRep[p->state]; + RC_BIT_PRE(&p->rc, probs) + + if (dist < LZMA_NUM_REPS) + { + RC_BIT_1(&p->rc, probs) + probs = &p->isRepG0[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 0) + { + RC_BIT_0(&p->rc, probs) + probs = &p->isRep0Long[p->state][posState]; + RC_BIT_PRE(&p->rc, probs) + if (len != 1) + { + RC_BIT_1_BASE(&p->rc, probs) + } + else + { + RC_BIT_0_BASE(&p->rc, probs) + p->state = kShortRepNextStates[p->state]; + } + } + else + { + RC_BIT_1(&p->rc, probs) + probs = &p->isRepG1[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 1) + { + RC_BIT_0_BASE(&p->rc, probs) + dist = p->reps[1]; + } + else + { + RC_BIT_1(&p->rc, probs) + probs = &p->isRepG2[p->state]; + RC_BIT_PRE(&p->rc, probs) + if (dist == 2) + { + RC_BIT_0_BASE(&p->rc, probs) + dist = p->reps[2]; + } + else + { + RC_BIT_1_BASE(&p->rc, probs) + dist = p->reps[3]; + p->reps[3] = p->reps[2]; + } + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = dist; + } + + RC_NORM(&p->rc) + + p->rc.range = range; + + if (len != 1) + { + LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); + --p->repLenEncCounter; + p->state = kRepNextStates[p->state]; + } + } + else + { + unsigned posSlot; + RC_BIT_0(&p->rc, probs) + p->rc.range = range; + p->state = kMatchNextStates[p->state]; + + LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState); + // --p->lenEnc.counter; + + dist -= LZMA_NUM_REPS; + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = dist + 1; + + p->matchPriceCount++; + GetPosSlot(dist, posSlot) + // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot); + { + UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits); + range = p->rc.range; + probs = p->posSlotEncoder[GetLenToPosState(len)]; + do + { + CLzmaProb *prob = probs + (sym >> kNumPosSlotBits); + UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1; + sym <<= 1; + RC_BIT(&p->rc, prob, bit) + } + while (sym < (1 << kNumPosSlotBits * 2)); + p->rc.range = range; + } + + if (dist >= kStartPosModelIndex) + { + unsigned footerBits = ((posSlot >> 1) - 1); + + if (dist < kNumFullDistances) + { + unsigned base = ((2 | (posSlot & 1)) << footerBits); + RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */)); + } + else + { + UInt32 pos2 = (dist | 0xF) << (32 - footerBits); + range = p->rc.range; + // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + /* + do + { + range >>= 1; + p->rc.low += range & (0 - ((dist >> --footerBits) & 1)); + RC_NORM(&p->rc) + } + while (footerBits > kNumAlignBits); + */ + do + { + range >>= 1; + p->rc.low += range & (0 - (pos2 >> 31)); + pos2 += pos2; + RC_NORM(&p->rc) + } + while (pos2 != 0xF0000000); + + + // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + + { + unsigned m = 1; + unsigned bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; + bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit; + bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) + p->rc.range = range; + // p->alignPriceCount++; + } + } + } + } + } + + nowPos32 += (UInt32)len; + p->additionalOffset -= len; + + if (p->additionalOffset == 0) + { + UInt32 processed; + + if (!p->fastMode) + { + /* + if (p->alignPriceCount >= 16) // kAlignTableSize + FillAlignPrices(p); + if (p->matchPriceCount >= 128) + FillDistancesPrices(p); + if (p->lenEnc.counter <= 0) + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices); + */ + if (p->matchPriceCount >= 64) + { + FillAlignPrices(p); + // { int y; for (y = 0; y < 100; y++) { + FillDistancesPrices(p); + // }} + LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); + } + if (p->repLenEncCounter <= 0) + { + p->repLenEncCounter = REP_LEN_COUNT; + LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); + } + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + + if (maxPackSize) + { + if (processed + kNumOpts + 300 >= maxUnpackSize + || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize) + break; + } + else if (processed >= (1 << 17)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + + + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + UInt32 beforeSize = kNumOpts; + UInt32 dictSize; + + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + + #ifndef Z7_ST + p->mtMode = (p->multiThread && !p->fastMode && (MFB.btMode != 0)); + #endif + + { + const unsigned lclp = p->lc + p->lp; + if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((size_t)0x300 * sizeof(CLzmaProb)) << lclp); + p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((size_t)0x300 * sizeof(CLzmaProb)) << lclp); + if (!p->litProbs || !p->saveState.litProbs) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + MFB.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); + + + dictSize = p->dictSize; + if (dictSize == ((UInt32)2 << 30) || + dictSize == ((UInt32)3 << 30)) + { + /* 21.03 : here we reduce the dictionary for 2 reasons: + 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary. + 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases, + where data size is aligned for 1 GB: 5/6/8 GB. + That reducing must be >= 1 for such corner cases. */ + dictSize -= 1; + } + + if (beforeSize + dictSize < keepWindowSize) + beforeSize = keepWindowSize - dictSize; + + /* in worst case we can look ahead for + max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes. + we send larger value for (keepAfter) to MantchFinder_Create(): + (numFastBytes + LZMA_MATCH_LEN_MAX + 1) + */ + + #ifndef Z7_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, dictSize, beforeSize, + p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 18.04 */ + , allocBig)) + p->matchFinderObj = &p->matchFinderMt; + MFB.bigHash = (Byte)(MFB.hashMask >= 0xFFFFFF ? 1 : 0); + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&MFB, dictSize, beforeSize, + p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */ + , allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &MFB; + MatchFinder_CreateVTable(&MFB, &p->matchFinder); + } + + return SZ_OK; +} + +static void LzmaEnc_Init(CLzmaEnc *p) +{ + unsigned i; + p->state = 0; + p->reps[0] = + p->reps[1] = + p->reps[2] = + p->reps[3] = 1; + + RangeEnc_Init(&p->rc); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + for (i = 0; i < kNumStates; i++) + { + unsigned j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + unsigned j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances; i++) + p->posEncoders[i] = kProbInitValue; + } + + { + const size_t num = (size_t)0x300 << (p->lp + p->lc); + size_t k; + CLzmaProb *probs = p->litProbs; + for (k = 0; k < num; k++) + probs[k] = kProbInitValue; + } + + + LenEnc_Init(&p->lenProbs); + LenEnc_Init(&p->repLenProbs); + + p->optEnd = 0; + p->optCur = 0; + + { + for (i = 0; i < kNumOpts; i++) + p->opt[i].price = kInfinityPrice; + } + + p->additionalOffset = 0; + + p->pbMask = ((unsigned)1 << p->pb) - 1; + p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc); + + // p->mf_Failure = False; +} + + +static void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + + p->repLenEncCounter = REP_LEN_COUNT; + + LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + unsigned i; + for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + p->nowPos64 = 0; + p->needInit = 1; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle p, + ISeqOutStreamPtr outStream, + ISeqInStreamPtr inStream, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + // GET_CLzmaEnc_p + MatchFinder_SET_STREAM(&MFB, inStream) + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, + ISeqInStreamPtr inStream, UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + // GET_CLzmaEnc_p + MatchFinder_SET_STREAM(&MFB, inStream) + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, + const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + // GET_CLzmaEnc_p + MatchFinder_SET_DIRECT_INPUT_BUF(&MFB, src, srcLen) + LzmaEnc_SetDataSize(p, srcLen); + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +void LzmaEnc_Finish(CLzmaEncHandle p) +{ + #ifndef Z7_ST + // GET_CLzmaEnc_p + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + UNUSED_VAR(p) + #endif +} + + +typedef struct +{ + ISeqOutStream vt; + Byte *data; + size_t rem; + BoolInt overflow; +} CLzmaEnc_SeqOutStreamBuf; + +static size_t SeqOutStreamBuf_Write(ISeqOutStreamPtr pp, const void *data, size_t size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLzmaEnc_SeqOutStreamBuf) + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + if (size != 0) + { + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + } + return size; +} + + +/* +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p) +{ + GET_const_CLzmaEnc_p + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +} +*/ + +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p) +{ + // GET_const_CLzmaEnc_p + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +} + + +// (desiredPackSize == 0) is not allowed +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + // GET_CLzmaEnc_p + UInt64 nowPos64; + SRes res; + CLzmaEnc_SeqOutStreamBuf outStream; + + outStream.vt.Write = SeqOutStreamBuf_Write; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.vt; + nowPos64 = p->nowPos64; + + res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +} + + +Z7_NO_INLINE +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgressPtr progress) +{ + SRes res = SZ_OK; + + #ifndef Z7_ST + Byte allocaDummy[0x300]; + allocaDummy[0] = 0; + allocaDummy[1] = allocaDummy[0]; + #endif + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, 0, 0); + if (res != SZ_OK || p->finished) + break; + if (progress) + { + res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + + LzmaEnc_Finish((CLzmaEncHandle)(void *)p); + + /* + if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&MFB)) + res = SZ_ERROR_FAIL; + } + */ + + return res; +} + + +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress, + ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + // GET_CLzmaEnc_p + RINOK(LzmaEnc_Prepare(p, outStream, inStream, alloc, allocBig)) + return LzmaEnc_Encode2(p, progress); +} + + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *props, SizeT *size) +{ + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + { + // GET_CLzmaEnc_p + const UInt32 dictSize = p->dictSize; + UInt32 v; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + // we write aligned dictionary value to properties for lzma decoder + if (dictSize >= ((UInt32)1 << 21)) + { + const UInt32 kDictMask = ((UInt32)1 << 20) - 1; + v = (dictSize + kDictMask) & ~kDictMask; + if (v < dictSize) + v = dictSize; + } + else + { + unsigned i = 11 * 2; + do + { + v = (UInt32)(2 + (i & 1)) << (i >> 1); + i++; + } + while (v < dictSize); + } + + SetUi32(props + 1, v) + return SZ_OK; + } +} + + +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p) +{ + // GET_CLzmaEnc_p + return (unsigned)p->writeEndMark; +} + + +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + SRes res; + // GET_CLzmaEnc_p + + CLzmaEnc_SeqOutStreamBuf outStream; + + outStream.vt.Write = SeqOutStreamBuf_Write; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + p->rc.outStream = &outStream.vt; + + res = LzmaEnc_MemPrepare(p, src, srcLen, 0, alloc, allocBig); + + if (res == SZ_OK) + { + res = LzmaEnc_Encode2(p, progress); + if (res == SZ_OK && p->nowPos64 != srcLen) + res = SZ_ERROR_FAIL; + } + + *destLen -= (SizeT)outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CLzmaEncHandle p = LzmaEnc_Create(alloc); + SRes res; + if (!p) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} + + +/* +#ifndef Z7_ST +void LzmaEnc_GetLzThreads(CLzmaEncHandle p, HANDLE lz_threads[2]) +{ + GET_const_CLzmaEnc_p + lz_threads[0] = p->matchFinderMt.hashSync.thread; + lz_threads[1] = p->matchFinderMt.btSync.thread; +} +#endif +*/ diff --git a/C/LzmaEnc.h b/C/LzmaEnc.h index 08711cbac..9f8039a10 100644 --- a/C/LzmaEnc.h +++ b/C/LzmaEnc.h @@ -1,83 +1,83 @@ -/* LzmaEnc.h -- LZMA Encoder -2023-04-13 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA_ENC_H -#define ZIP7_INC_LZMA_ENC_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define LZMA_PROPS_SIZE 5 - -typedef struct -{ - int level; /* 0 <= level <= 9 */ - UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version - (1 << 12) <= dictSize <= (3 << 29) for 64-bit version - default = (1 << 24) */ - int lc; /* 0 <= lc <= 8, default = 3 */ - int lp; /* 0 <= lp <= 4, default = 0 */ - int pb; /* 0 <= pb <= 4, default = 2 */ - int algo; /* 0 - fast, 1 - normal, default = 1 */ - int fb; /* 5 <= fb <= 273, default = 32 */ - int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ - int numHashBytes; /* 2, 3 or 4, default = 4 */ - unsigned numHashOutBits; /* default = ? */ - UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ - unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ - int numThreads; /* 1 or 2, default = 2 */ - - // int _pad; - - UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. - Encoder uses this value to reduce dictionary size */ - - UInt64 affinity; -} CLzmaEncProps; - -void LzmaEncProps_Init(CLzmaEncProps *p); -void LzmaEncProps_Normalize(CLzmaEncProps *p); -UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); - - -/* ---------- CLzmaEncHandle Interface ---------- */ - -/* LzmaEnc* functions can return the following exit codes: -SRes: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater in props - SZ_ERROR_WRITE - ISeqOutStream write callback error - SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output - SZ_ERROR_PROGRESS - some break from progress callback - SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) -*/ - -typedef struct CLzmaEnc CLzmaEnc; -typedef CLzmaEnc * CLzmaEncHandle; -// Z7_DECLARE_HANDLE(CLzmaEncHandle) - -CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); -void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); - -SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); -void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); -SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); -unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); - -SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, - ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); -SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); - - -/* ---------- One Call Interface ---------- */ - -SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); - -EXTERN_C_END - -#endif +/* LzmaEnc.h -- LZMA Encoder +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA_ENC_H +#define ZIP7_INC_LZMA_ENC_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define LZMA_PROPS_SIZE 5 + +typedef struct +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (3 << 29) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + unsigned numHashOutBits; /* default = ? */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ + + // int _pad; + + UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1. + Encoder uses this value to reduce dictionary size */ + + UInt64 affinity; +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc* functions can return the following exit codes: +SRes: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - ISeqOutStream write callback error + SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - error in multithreading functions (only for Mt version) +*/ + +typedef struct CLzmaEnc CLzmaEnc; +typedef CLzmaEnc * CLzmaEncHandle; +// Z7_DECLARE_HANDLE(CLzmaEncHandle) + +CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig); + +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p); + +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + + +/* ---------- One Call Interface ---------- */ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig); + +EXTERN_C_END + +#endif diff --git a/C/LzmaLib.c b/C/LzmaLib.c index 350c1953d..785e88487 100644 --- a/C/LzmaLib.c +++ b/C/LzmaLib.c @@ -1,42 +1,42 @@ -/* LzmaLib.c -- LZMA library wrapper -2023-04-02 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Alloc.h" -#include "LzmaDec.h" -#include "LzmaEnc.h" -#include "LzmaLib.h" - -Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, - unsigned char *outProps, size_t *outPropsSize, - int level, /* 0 <= level <= 9, default = 5 */ - unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ - int lc, /* 0 <= lc <= 8, default = 3 */ - int lp, /* 0 <= lp <= 4, default = 0 */ - int pb, /* 0 <= pb <= 4, default = 2 */ - int fb, /* 5 <= fb <= 273, default = 32 */ - int numThreads /* 1 or 2, default = 2 */ -) -{ - CLzmaEncProps props; - LzmaEncProps_Init(&props); - props.level = level; - props.dictSize = dictSize; - props.lc = lc; - props.lp = lp; - props.pb = pb; - props.fb = fb; - props.numThreads = numThreads; - - return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, - NULL, &g_Alloc, &g_Alloc); -} - - -Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, - const unsigned char *props, size_t propsSize) -{ - ELzmaStatus status; - return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); -} +/* LzmaLib.c -- LZMA library wrapper +2023-04-02 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Alloc.h" +#include "LzmaDec.h" +#include "LzmaEnc.h" +#include "LzmaLib.h" + +Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ +) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + props.lc = lc; + props.lp = lp; + props.pb = pb; + props.fb = fb; + props.numThreads = numThreads; + + return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); +} + + +Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, + const unsigned char *props, size_t propsSize) +{ + ELzmaStatus status; + return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); +} diff --git a/C/LzmaLib.h b/C/LzmaLib.h index 79612a42e..d7c0724de 100644 --- a/C/LzmaLib.h +++ b/C/LzmaLib.h @@ -1,138 +1,138 @@ -/* LzmaLib.h -- LZMA library interface -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_LZMA_LIB_H -#define ZIP7_INC_LZMA_LIB_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define Z7_STDAPI int Z7_STDCALL - -#define LZMA_PROPS_SIZE 5 - -/* -RAM requirements for LZMA: - for compression: (dictSize * 11.5 + 6 MB) + state_size - for decompression: dictSize + state_size - state_size = (4 + (1.5 << (lc + lp))) KB - by default (lc=3, lp=0), state_size = 16 KB. - -LZMA properties (5 bytes) format - Offset Size Description - 0 1 lc, lp and pb in encoded form. - 1 4 dictSize (little endian). -*/ - -/* -LzmaCompress ------------- - -outPropsSize - - In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. - Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. - - LZMA Encoder will use defult values for any parameter, if it is - -1 for any from: level, loc, lp, pb, fb, numThreads - 0 for dictSize - -level - compression level: 0 <= level <= 9; - - level dictSize algo fb - 0: 64 KB 0 32 - 1: 256 KB 0 32 - 2: 1 MB 0 32 - 3: 4 MB 0 32 - 4: 16 MB 0 32 - 5: 16 MB 1 32 - 6: 32 MB 1 32 - 7: 32 MB 1 64 - 8: 64 MB 1 64 - 9: 64 MB 1 64 - - The default value for "level" is 5. - - algo = 0 means fast method - algo = 1 means normal method - -dictSize - The dictionary size in bytes. The maximum value is - 128 MB = (1 << 27) bytes for 32-bit version - 1 GB = (1 << 30) bytes for 64-bit version - The default value is 16 MB = (1 << 24) bytes. - It's recommended to use the dictionary that is larger than 4 KB and - that can be calculated as (1 << N) or (3 << N) sizes. - -lc - The number of literal context bits (high bits of previous literal). - It can be in the range from 0 to 8. The default value is 3. - Sometimes lc=4 gives the gain for big files. - -lp - The number of literal pos bits (low bits of current position for literals). - It can be in the range from 0 to 4. The default value is 0. - The lp switch is intended for periodical data when the period is equal to 2^lp. - For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's - better to set lc=0, if you change lp switch. - -pb - The number of pos bits (low bits of current position). - It can be in the range from 0 to 4. The default value is 2. - The pb switch is intended for periodical data when the period is equal 2^pb. - -fb - Word size (the number of fast bytes). - It can be in the range from 5 to 273. The default value is 32. - Usually, a big number gives a little bit better compression ratio and - slower compression process. - -numThreads - The number of thereads. 1 or 2. The default value is 2. - Fast mode (algo = 0) can use only 1 thread. - -In: - dest - output data buffer - destLen - output data buffer size - src - input data - srcLen - input data size -Out: - destLen - processed output size -Returns: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater - SZ_ERROR_OUTPUT_EOF - output buffer overflow - SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) -*/ - -Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, - unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ - int level, /* 0 <= level <= 9, default = 5 */ - unsigned dictSize, /* default = (1 << 24) */ - int lc, /* 0 <= lc <= 8, default = 3 */ - int lp, /* 0 <= lp <= 4, default = 0 */ - int pb, /* 0 <= pb <= 4, default = 2 */ - int fb, /* 5 <= fb <= 273, default = 32 */ - int numThreads /* 1 or 2, default = 2 */ - ); - -/* -LzmaUncompress --------------- -In: - dest - output data buffer - destLen - output data buffer size - src - input data - srcLen - input data size -Out: - destLen - processed output size - srcLen - processed input size -Returns: - SZ_OK - OK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation arror - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) -*/ - -Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, - const unsigned char *props, size_t propsSize); - -EXTERN_C_END - -#endif +/* LzmaLib.h -- LZMA library interface +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_LZMA_LIB_H +#define ZIP7_INC_LZMA_LIB_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define Z7_STDAPI int Z7_STDCALL + +#define LZMA_PROPS_SIZE 5 + +/* +RAM requirements for LZMA: + for compression: (dictSize * 11.5 + 6 MB) + state_size + for decompression: dictSize + state_size + state_size = (4 + (1.5 << (lc + lp))) KB + by default (lc=3, lp=0), state_size = 16 KB. + +LZMA properties (5 bytes) format + Offset Size Description + 0 1 lc, lp and pb in encoded form. + 1 4 dictSize (little endian). +*/ + +/* +LzmaCompress +------------ + +outPropsSize - + In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + + LZMA Encoder will use defult values for any parameter, if it is + -1 for any from: level, loc, lp, pb, fb, numThreads + 0 for dictSize + +level - compression level: 0 <= level <= 9; + + level dictSize algo fb + 0: 64 KB 0 32 + 1: 256 KB 0 32 + 2: 1 MB 0 32 + 3: 4 MB 0 32 + 4: 16 MB 0 32 + 5: 16 MB 1 32 + 6: 32 MB 1 32 + 7: 32 MB 1 64 + 8: 64 MB 1 64 + 9: 64 MB 1 64 + + The default value for "level" is 5. + + algo = 0 means fast method + algo = 1 means normal method + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + +lc - The number of literal context bits (high bits of previous literal). + It can be in the range from 0 to 8. The default value is 3. + Sometimes lc=4 gives the gain for big files. + +lp - The number of literal pos bits (low bits of current position for literals). + It can be in the range from 0 to 4. The default value is 0. + The lp switch is intended for periodical data when the period is equal to 2^lp. + For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's + better to set lc=0, if you change lp switch. + +pb - The number of pos bits (low bits of current position). + It can be in the range from 0 to 4. The default value is 2. + The pb switch is intended for periodical data when the period is equal 2^pb. + +fb - Word size (the number of fast bytes). + It can be in the range from 5 to 273. The default value is 32. + Usually, a big number gives a little bit better compression ratio and + slower compression process. + +numThreads - The number of thereads. 1 or 2. The default value is 2. + Fast mode (algo = 0) can use only 1 thread. + +In: + dest - output data buffer + destLen - output data buffer size + src - input data + srcLen - input data size +Out: + destLen - processed output size +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* default = (1 << 24) */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads /* 1 or 2, default = 2 */ + ); + +/* +LzmaUncompress +-------------- +In: + dest - output data buffer + destLen - output data buffer size + src - input data + srcLen - input data size +Out: + destLen - processed output size + srcLen - processed input size +Returns: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation arror + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) +*/ + +Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, + const unsigned char *props, size_t propsSize); + +EXTERN_C_END + +#endif diff --git a/C/Md5.c b/C/Md5.c new file mode 100644 index 000000000..1b745d705 --- /dev/null +++ b/C/Md5.c @@ -0,0 +1,206 @@ +/* Md5.c -- MD5 Hash +: Igor Pavlov : Public domain +This code is based on Colin Plumb's public domain md5.c code */ + +#include "Precomp.h" + +#include + +#include "Md5.h" +#include "RotateDefs.h" +#include "CpuArch.h" + +#define MD5_UPDATE_BLOCKS(p) Md5_UpdateBlocks + +Z7_NO_INLINE +void Md5_Init(CMd5 *p) +{ + p->count = 0; + p->state[0] = 0x67452301; + p->state[1] = 0xefcdab89; + p->state[2] = 0x98badcfe; + p->state[3] = 0x10325476; +} + +#if 0 && !defined(MY_CPU_LE_UNALIGN) +// optional optimization for Big-endian processors or processors without unaligned access: +// it is intended to reduce the number of complex LE32 memory reading from 64 to 16. +// But some compilers (sparc, armt) are better without this optimization. +#define Z7_MD5_USE_DATA32_ARRAY +#endif + +#define LOAD_DATA(i) GetUi32((const UInt32 *)(const void *)data + (i)) + +#ifdef Z7_MD5_USE_DATA32_ARRAY +#define D(i) data32[i] +#else +#define D(i) LOAD_DATA(i) +#endif + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define R1(i, f, start, step, w, x, y, z, s, k) \ + w += D((start + step * (i)) % 16) + k; \ + w += f(x, y, z); \ + w = rotlFixed(w, s) + x; \ + +#define R4(i4, f, start, step, s0,s1,s2,s3, k0,k1,k2,k3) \ + R1 (i4*4+0, f, start, step, a,b,c,d, s0, k0) \ + R1 (i4*4+1, f, start, step, d,a,b,c, s1, k1) \ + R1 (i4*4+2, f, start, step, c,d,a,b, s2, k2) \ + R1 (i4*4+3, f, start, step, b,c,d,a, s3, k3) \ + +#define R16(f, start, step, s0,s1,s2,s3, k00,k01,k02,k03, k10,k11,k12,k13, k20,k21,k22,k23, k30,k31,k32,k33) \ + R4 (0, f, start, step, s0,s1,s2,s3, k00,k01,k02,k03) \ + R4 (1, f, start, step, s0,s1,s2,s3, k10,k11,k12,k13) \ + R4 (2, f, start, step, s0,s1,s2,s3, k20,k21,k22,k23) \ + R4 (3, f, start, step, s0,s1,s2,s3, k30,k31,k32,k33) \ + +static +Z7_NO_INLINE +void Z7_FASTCALL Md5_UpdateBlocks(UInt32 state[4], const Byte *data, size_t numBlocks) +{ + UInt32 a, b, c, d; + // if (numBlocks == 0) return; + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + do + { +#ifdef Z7_MD5_USE_DATA32_ARRAY + UInt32 data32[MD5_NUM_BLOCK_WORDS]; + { +#define LOAD_data32_x4(i) { \ + data32[i ] = LOAD_DATA(i ); \ + data32[i + 1] = LOAD_DATA(i + 1); \ + data32[i + 2] = LOAD_DATA(i + 2); \ + data32[i + 3] = LOAD_DATA(i + 3); } +#if 1 + LOAD_data32_x4 (0 * 4) + LOAD_data32_x4 (1 * 4) + LOAD_data32_x4 (2 * 4) + LOAD_data32_x4 (3 * 4) +#else + unsigned i; + for (i = 0; i < MD5_NUM_BLOCK_WORDS; i += 4) + { + LOAD_data32_x4(i) + } +#endif + } +#endif + + R16 (F1, 0, 1, 7,12,17,22, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821) + R16 (F2, 1, 5, 5, 9,14,20, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a) + R16 (F3, 5, 3, 4,11,16,23, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665) + R16 (F4, 0, 7, 6,10,15,21, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391) + + a += state[0]; + b += state[1]; + c += state[2]; + d += state[3]; + + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + + data += MD5_BLOCK_SIZE; + } + while (--numBlocks); +} + + +#define Md5_UpdateBlock(p) MD5_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) + +void Md5_Update(CMd5 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + { + const unsigned pos = (unsigned)p->count & (MD5_BLOCK_SIZE - 1); + const unsigned num = MD5_BLOCK_SIZE - pos; + p->count += size; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + if (pos != 0) + { + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + Md5_UpdateBlock(p); + } + } + { + const size_t numBlocks = size >> 6; + if (numBlocks) + MD5_UPDATE_BLOCKS(p)(p->state, data, numBlocks); + size &= MD5_BLOCK_SIZE - 1; + if (size == 0) + return; + data += (numBlocks << 6); + memcpy(p->buffer, data, size); + } +} + + +void Md5_Final(CMd5 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->count & (MD5_BLOCK_SIZE - 1); + p->buffer[pos++] = 0x80; + if (pos > (MD5_BLOCK_SIZE - 4 * 2)) + { + while (pos != MD5_BLOCK_SIZE) { p->buffer[pos++] = 0; } + // memset(&p->buf.buffer[pos], 0, MD5_BLOCK_SIZE - pos); + Md5_UpdateBlock(p); + pos = 0; + } + memset(&p->buffer[pos], 0, (MD5_BLOCK_SIZE - 4 * 2) - pos); + { + const UInt64 numBits = p->count << 3; +#if defined(MY_CPU_LE_UNALIGN) + SetUi64 (p->buffer + MD5_BLOCK_SIZE - 4 * 2, numBits) +#else + SetUi32a(p->buffer + MD5_BLOCK_SIZE - 4 * 2, (UInt32)(numBits)) + SetUi32a(p->buffer + MD5_BLOCK_SIZE - 4 * 1, (UInt32)(numBits >> 32)) +#endif + } + Md5_UpdateBlock(p); + + SetUi32(digest, p->state[0]) + SetUi32(digest + 4, p->state[1]) + SetUi32(digest + 8, p->state[2]) + SetUi32(digest + 12, p->state[3]) + + Md5_Init(p); +} + +#undef R1 +#undef R4 +#undef R16 +#undef D +#undef LOAD_DATA +#undef LOAD_data32_x4 +#undef F1 +#undef F2 +#undef F3 +#undef F4 diff --git a/C/Md5.h b/C/Md5.h new file mode 100644 index 000000000..49c0741f1 --- /dev/null +++ b/C/Md5.h @@ -0,0 +1,34 @@ +/* Md5.h -- MD5 Hash +: Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_MD5_H +#define ZIP7_INC_MD5_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define MD5_NUM_BLOCK_WORDS 16 +#define MD5_NUM_DIGEST_WORDS 4 + +#define MD5_BLOCK_SIZE (MD5_NUM_BLOCK_WORDS * 4) +#define MD5_DIGEST_SIZE (MD5_NUM_DIGEST_WORDS * 4) + +typedef struct +{ + UInt64 count; + UInt64 _pad_1; + // we want 16-bytes alignment here + UInt32 state[MD5_NUM_DIGEST_WORDS]; + UInt64 _pad_2[4]; + // we want 64-bytes alignment here + Byte buffer[MD5_BLOCK_SIZE]; +} CMd5; + +void Md5_Init(CMd5 *p); +void Md5_Update(CMd5 *p, const Byte *data, size_t size); +void Md5_Final(CMd5 *p, Byte *digest); + +EXTERN_C_END + +#endif diff --git a/C/MtCoder.c b/C/MtCoder.c index 10ad5822a..03959b6ca 100644 --- a/C/MtCoder.c +++ b/C/MtCoder.c @@ -1,571 +1,571 @@ -/* MtCoder.c -- Multi-thread Coder -2023-09-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "MtCoder.h" - -#ifndef Z7_ST - -static SRes MtProgressThunk_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CMtProgressThunk) - UInt64 inSize2 = 0; - UInt64 outSize2 = 0; - if (inSize != (UInt64)(Int64)-1) - { - inSize2 = inSize - p->inSize; - p->inSize = inSize; - } - if (outSize != (UInt64)(Int64)-1) - { - outSize2 = outSize - p->outSize; - p->outSize = outSize; - } - return MtProgress_ProgressAdd(p->mtProgress, inSize2, outSize2); -} - - -void MtProgressThunk_CreateVTable(CMtProgressThunk *p) -{ - p->vt.Progress = MtProgressThunk_Progress; -} - - - -#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } - - -static THREAD_FUNC_DECL ThreadFunc(void *pp); - - -static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) -{ - WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent); - if (wres == 0) - { - t->stop = False; - if (!Thread_WasCreated(&t->thread)) - wres = Thread_Create(&t->thread, ThreadFunc, t); - if (wres == 0) - wres = Event_Set(&t->startEvent); - } - if (wres == 0) - return SZ_OK; - return MY_SRes_HRESULT_FROM_WRes(wres); -} - - -static void MtCoderThread_Destruct(CMtCoderThread *t) -{ - if (Thread_WasCreated(&t->thread)) - { - t->stop = 1; - Event_Set(&t->startEvent); - Thread_Wait_Close(&t->thread); - } - - Event_Close(&t->startEvent); - - if (t->inBuf) - { - ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf); - t->inBuf = NULL; - } -} - - - - -/* - ThreadFunc2() returns: - SZ_OK - in all normal cases (even for stream error or memory allocation error) - SZ_ERROR_THREAD - in case of failure in system synch function -*/ - -static SRes ThreadFunc2(CMtCoderThread *t) -{ - CMtCoder *mtc = t->mtCoder; - - for (;;) - { - unsigned bi; - SRes res; - SRes res2; - BoolInt finished; - unsigned bufIndex; - size_t size; - const Byte *inData; - UInt64 readProcessed = 0; - - RINOK_THREAD(Event_Wait(&mtc->readEvent)) - - /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */ - - if (mtc->stopReading) - { - return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD; - } - - res = MtProgress_GetError(&mtc->mtProgress); - - size = 0; - inData = NULL; - finished = True; - - if (res == SZ_OK) - { - size = mtc->blockSize; - if (mtc->inStream) - { - if (!t->inBuf) - { - t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize); - if (!t->inBuf) - res = SZ_ERROR_MEM; - } - if (res == SZ_OK) - { - res = SeqInStream_ReadMax(mtc->inStream, t->inBuf, &size); - readProcessed = mtc->readProcessed + size; - mtc->readProcessed = readProcessed; - } - if (res != SZ_OK) - { - mtc->readRes = res; - /* after reading error - we can stop encoding of previous blocks */ - MtProgress_SetError(&mtc->mtProgress, res); - } - else - finished = (size != mtc->blockSize); - } - else - { - size_t rem; - readProcessed = mtc->readProcessed; - rem = mtc->inDataSize - (size_t)readProcessed; - if (size > rem) - size = rem; - inData = mtc->inData + (size_t)readProcessed; - readProcessed += size; - mtc->readProcessed = readProcessed; - finished = (mtc->inDataSize == (size_t)readProcessed); - } - } - - /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */ - - res2 = SZ_OK; - - if (Semaphore_Wait(&mtc->blocksSemaphore) != 0) - { - res2 = SZ_ERROR_THREAD; - if (res == SZ_OK) - { - res = res2; - // MtProgress_SetError(&mtc->mtProgress, res); - } - } - - bi = mtc->blockIndex; - - if (++mtc->blockIndex >= mtc->numBlocksMax) - mtc->blockIndex = 0; - - bufIndex = (unsigned)(int)-1; - - if (res == SZ_OK) - res = MtProgress_GetError(&mtc->mtProgress); - - if (res != SZ_OK) - finished = True; - - if (!finished) - { - if (mtc->numStartedThreads < mtc->numStartedThreadsLimit - && mtc->expectedDataSize != readProcessed) - { - res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); - if (res == SZ_OK) - mtc->numStartedThreads++; - else - { - MtProgress_SetError(&mtc->mtProgress, res); - finished = True; - } - } - } - - if (finished) - mtc->stopReading = True; - - RINOK_THREAD(Event_Set(&mtc->readEvent)) - - if (res2 != SZ_OK) - return res2; - - if (res == SZ_OK) - { - CriticalSection_Enter(&mtc->cs); - bufIndex = mtc->freeBlockHead; - mtc->freeBlockHead = mtc->freeBlockList[bufIndex]; - CriticalSection_Leave(&mtc->cs); - - res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex, - mtc->inStream ? t->inBuf : inData, size, finished); - - // MtProgress_Reinit(&mtc->mtProgress, t->index); - - if (res != SZ_OK) - MtProgress_SetError(&mtc->mtProgress, res); - } - - { - CMtCoderBlock *block = &mtc->blocks[bi]; - block->res = res; - block->bufIndex = bufIndex; - block->finished = finished; - } - - #ifdef MTCODER_USE_WRITE_THREAD - RINOK_THREAD(Event_Set(&mtc->writeEvents[bi])) - #else - { - unsigned wi; - { - CriticalSection_Enter(&mtc->cs); - wi = mtc->writeIndex; - if (wi == bi) - mtc->writeIndex = (unsigned)(int)-1; - else - mtc->ReadyBlocks[bi] = True; - CriticalSection_Leave(&mtc->cs); - } - - if (wi != bi) - { - if (res != SZ_OK || finished) - return 0; - continue; - } - - if (mtc->writeRes != SZ_OK) - res = mtc->writeRes; - - for (;;) - { - if (res == SZ_OK && bufIndex != (unsigned)(int)-1) - { - res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex); - if (res != SZ_OK) - { - mtc->writeRes = res; - MtProgress_SetError(&mtc->mtProgress, res); - } - } - - if (++wi >= mtc->numBlocksMax) - wi = 0; - { - BoolInt isReady; - - CriticalSection_Enter(&mtc->cs); - - if (bufIndex != (unsigned)(int)-1) - { - mtc->freeBlockList[bufIndex] = mtc->freeBlockHead; - mtc->freeBlockHead = bufIndex; - } - - isReady = mtc->ReadyBlocks[wi]; - - if (isReady) - mtc->ReadyBlocks[wi] = False; - else - mtc->writeIndex = wi; - - CriticalSection_Leave(&mtc->cs); - - RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore)) - - if (!isReady) - break; - } - - { - CMtCoderBlock *block = &mtc->blocks[wi]; - if (res == SZ_OK && block->res != SZ_OK) - res = block->res; - bufIndex = block->bufIndex; - finished = block->finished; - } - } - } - #endif - - if (finished || res != SZ_OK) - return 0; - } -} - - -static THREAD_FUNC_DECL ThreadFunc(void *pp) -{ - CMtCoderThread *t = (CMtCoderThread *)pp; - for (;;) - { - if (Event_Wait(&t->startEvent) != 0) - return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; - if (t->stop) - return 0; - { - SRes res = ThreadFunc2(t); - CMtCoder *mtc = t->mtCoder; - if (res != SZ_OK) - { - MtProgress_SetError(&mtc->mtProgress, res); - } - - #ifndef MTCODER_USE_WRITE_THREAD - { - unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); - if (numFinished == mtc->numStartedThreads) - if (Event_Set(&mtc->finishedEvent) != 0) - return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; - } - #endif - } - } -} - - - -void MtCoder_Construct(CMtCoder *p) -{ - unsigned i; - - p->blockSize = 0; - p->numThreadsMax = 0; - p->expectedDataSize = (UInt64)(Int64)-1; - - p->inStream = NULL; - p->inData = NULL; - p->inDataSize = 0; - - p->progress = NULL; - p->allocBig = NULL; - - p->mtCallback = NULL; - p->mtCallbackObject = NULL; - - p->allocatedBufsSize = 0; - - Event_Construct(&p->readEvent); - Semaphore_Construct(&p->blocksSemaphore); - - for (i = 0; i < MTCODER_THREADS_MAX; i++) - { - CMtCoderThread *t = &p->threads[i]; - t->mtCoder = p; - t->index = i; - t->inBuf = NULL; - t->stop = False; - Event_Construct(&t->startEvent); - Thread_CONSTRUCT(&t->thread) - } - - #ifdef MTCODER_USE_WRITE_THREAD - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - Event_Construct(&p->writeEvents[i]); - #else - Event_Construct(&p->finishedEvent); - #endif - - CriticalSection_Init(&p->cs); - CriticalSection_Init(&p->mtProgress.cs); -} - - - - -static void MtCoder_Free(CMtCoder *p) -{ - unsigned i; - - /* - p->stopReading = True; - if (Event_IsCreated(&p->readEvent)) - Event_Set(&p->readEvent); - */ - - for (i = 0; i < MTCODER_THREADS_MAX; i++) - MtCoderThread_Destruct(&p->threads[i]); - - Event_Close(&p->readEvent); - Semaphore_Close(&p->blocksSemaphore); - - #ifdef MTCODER_USE_WRITE_THREAD - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - Event_Close(&p->writeEvents[i]); - #else - Event_Close(&p->finishedEvent); - #endif -} - - -void MtCoder_Destruct(CMtCoder *p) -{ - MtCoder_Free(p); - - CriticalSection_Delete(&p->cs); - CriticalSection_Delete(&p->mtProgress.cs); -} - - -SRes MtCoder_Code(CMtCoder *p) -{ - unsigned numThreads = p->numThreadsMax; - unsigned numBlocksMax; - unsigned i; - SRes res = SZ_OK; - - if (numThreads > MTCODER_THREADS_MAX) - numThreads = MTCODER_THREADS_MAX; - numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads); - - if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++; - if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++; - if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++; - - if (numBlocksMax > MTCODER_BLOCKS_MAX) - numBlocksMax = MTCODER_BLOCKS_MAX; - - if (p->blockSize != p->allocatedBufsSize) - { - for (i = 0; i < MTCODER_THREADS_MAX; i++) - { - CMtCoderThread *t = &p->threads[i]; - if (t->inBuf) - { - ISzAlloc_Free(p->allocBig, t->inBuf); - t->inBuf = NULL; - } - } - p->allocatedBufsSize = p->blockSize; - } - - p->readRes = SZ_OK; - - MtProgress_Init(&p->mtProgress, p->progress); - - #ifdef MTCODER_USE_WRITE_THREAD - for (i = 0; i < numBlocksMax; i++) - { - RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->writeEvents[i])) - } - #else - RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent)) - #endif - - { - RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->readEvent)) - RINOK_THREAD(Semaphore_OptCreateInit(&p->blocksSemaphore, (UInt32)numBlocksMax, (UInt32)numBlocksMax)) - } - - for (i = 0; i < MTCODER_BLOCKS_MAX - 1; i++) - p->freeBlockList[i] = i + 1; - p->freeBlockList[MTCODER_BLOCKS_MAX - 1] = (unsigned)(int)-1; - p->freeBlockHead = 0; - - p->readProcessed = 0; - p->blockIndex = 0; - p->numBlocksMax = numBlocksMax; - p->stopReading = False; - - #ifndef MTCODER_USE_WRITE_THREAD - p->writeIndex = 0; - p->writeRes = SZ_OK; - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - p->ReadyBlocks[i] = False; - p->numFinishedThreads = 0; - #endif - - p->numStartedThreadsLimit = numThreads; - p->numStartedThreads = 0; - - // for (i = 0; i < numThreads; i++) - { - CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; - RINOK(MtCoderThread_CreateAndStart(nextThread)) - } - - RINOK_THREAD(Event_Set(&p->readEvent)) - - #ifdef MTCODER_USE_WRITE_THREAD - { - unsigned bi = 0; - - for (;; bi++) - { - if (bi >= numBlocksMax) - bi = 0; - - RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) - - { - const CMtCoderBlock *block = &p->blocks[bi]; - unsigned bufIndex = block->bufIndex; - BoolInt finished = block->finished; - if (res == SZ_OK && block->res != SZ_OK) - res = block->res; - - if (bufIndex != (unsigned)(int)-1) - { - if (res == SZ_OK) - { - res = p->mtCallback->Write(p->mtCallbackObject, bufIndex); - if (res != SZ_OK) - MtProgress_SetError(&p->mtProgress, res); - } - - CriticalSection_Enter(&p->cs); - { - p->freeBlockList[bufIndex] = p->freeBlockHead; - p->freeBlockHead = bufIndex; - } - CriticalSection_Leave(&p->cs); - } - - RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore)) - - if (finished) - break; - } - } - } - #else - { - WRes wres = Event_Wait(&p->finishedEvent); - res = MY_SRes_HRESULT_FROM_WRes(wres); - } - #endif - - if (res == SZ_OK) - res = p->readRes; - - if (res == SZ_OK) - res = p->mtProgress.res; - - #ifndef MTCODER_USE_WRITE_THREAD - if (res == SZ_OK) - res = p->writeRes; - #endif - - if (res != SZ_OK) - MtCoder_Free(p); - return res; -} - -#endif - -#undef RINOK_THREAD +/* MtCoder.c -- Multi-thread Coder +2023-09-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "MtCoder.h" + +#ifndef Z7_ST + +static SRes MtProgressThunk_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CMtProgressThunk) + UInt64 inSize2 = 0; + UInt64 outSize2 = 0; + if (inSize != (UInt64)(Int64)-1) + { + inSize2 = inSize - p->inSize; + p->inSize = inSize; + } + if (outSize != (UInt64)(Int64)-1) + { + outSize2 = outSize - p->outSize; + p->outSize = outSize; + } + return MtProgress_ProgressAdd(p->mtProgress, inSize2, outSize2); +} + + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p) +{ + p->vt.Progress = MtProgressThunk_Progress; +} + + + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + + +static THREAD_FUNC_DECL ThreadFunc(void *pp); + + +static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t) +{ + WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent); + if (wres == 0) + { + t->stop = False; + if (!Thread_WasCreated(&t->thread)) + wres = Thread_Create(&t->thread, ThreadFunc, t); + if (wres == 0) + wres = Event_Set(&t->startEvent); + } + if (wres == 0) + return SZ_OK; + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +static void MtCoderThread_Destruct(CMtCoderThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + t->stop = 1; + Event_Set(&t->startEvent); + Thread_Wait_Close(&t->thread); + } + + Event_Close(&t->startEvent); + + if (t->inBuf) + { + ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf); + t->inBuf = NULL; + } +} + + + + +/* + ThreadFunc2() returns: + SZ_OK - in all normal cases (even for stream error or memory allocation error) + SZ_ERROR_THREAD - in case of failure in system synch function +*/ + +static SRes ThreadFunc2(CMtCoderThread *t) +{ + CMtCoder *mtc = t->mtCoder; + + for (;;) + { + unsigned bi; + SRes res; + SRes res2; + BoolInt finished; + unsigned bufIndex; + size_t size; + const Byte *inData; + UInt64 readProcessed = 0; + + RINOK_THREAD(Event_Wait(&mtc->readEvent)) + + /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */ + + if (mtc->stopReading) + { + return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD; + } + + res = MtProgress_GetError(&mtc->mtProgress); + + size = 0; + inData = NULL; + finished = True; + + if (res == SZ_OK) + { + size = mtc->blockSize; + if (mtc->inStream) + { + if (!t->inBuf) + { + t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize); + if (!t->inBuf) + res = SZ_ERROR_MEM; + } + if (res == SZ_OK) + { + res = SeqInStream_ReadMax(mtc->inStream, t->inBuf, &size); + readProcessed = mtc->readProcessed + size; + mtc->readProcessed = readProcessed; + } + if (res != SZ_OK) + { + mtc->readRes = res; + /* after reading error - we can stop encoding of previous blocks */ + MtProgress_SetError(&mtc->mtProgress, res); + } + else + finished = (size != mtc->blockSize); + } + else + { + size_t rem; + readProcessed = mtc->readProcessed; + rem = mtc->inDataSize - (size_t)readProcessed; + if (size > rem) + size = rem; + inData = mtc->inData + (size_t)readProcessed; + readProcessed += size; + mtc->readProcessed = readProcessed; + finished = (mtc->inDataSize == (size_t)readProcessed); + } + } + + /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */ + + res2 = SZ_OK; + + if (Semaphore_Wait(&mtc->blocksSemaphore) != 0) + { + res2 = SZ_ERROR_THREAD; + if (res == SZ_OK) + { + res = res2; + // MtProgress_SetError(&mtc->mtProgress, res); + } + } + + bi = mtc->blockIndex; + + if (++mtc->blockIndex >= mtc->numBlocksMax) + mtc->blockIndex = 0; + + bufIndex = (unsigned)(int)-1; + + if (res == SZ_OK) + res = MtProgress_GetError(&mtc->mtProgress); + + if (res != SZ_OK) + finished = True; + + if (!finished) + { + if (mtc->numStartedThreads < mtc->numStartedThreadsLimit + && mtc->expectedDataSize != readProcessed) + { + res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]); + if (res == SZ_OK) + mtc->numStartedThreads++; + else + { + MtProgress_SetError(&mtc->mtProgress, res); + finished = True; + } + } + } + + if (finished) + mtc->stopReading = True; + + RINOK_THREAD(Event_Set(&mtc->readEvent)) + + if (res2 != SZ_OK) + return res2; + + if (res == SZ_OK) + { + CriticalSection_Enter(&mtc->cs); + bufIndex = mtc->freeBlockHead; + mtc->freeBlockHead = mtc->freeBlockList[bufIndex]; + CriticalSection_Leave(&mtc->cs); + + res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex, + mtc->inStream ? t->inBuf : inData, size, finished); + + // MtProgress_Reinit(&mtc->mtProgress, t->index); + + if (res != SZ_OK) + MtProgress_SetError(&mtc->mtProgress, res); + } + + { + CMtCoderBlock *block = &mtc->blocks[bi]; + block->res = res; + block->bufIndex = bufIndex; + block->finished = finished; + } + + #ifdef MTCODER_USE_WRITE_THREAD + RINOK_THREAD(Event_Set(&mtc->writeEvents[bi])) + #else + { + unsigned wi; + { + CriticalSection_Enter(&mtc->cs); + wi = mtc->writeIndex; + if (wi == bi) + mtc->writeIndex = (unsigned)(int)-1; + else + mtc->ReadyBlocks[bi] = True; + CriticalSection_Leave(&mtc->cs); + } + + if (wi != bi) + { + if (res != SZ_OK || finished) + return 0; + continue; + } + + if (mtc->writeRes != SZ_OK) + res = mtc->writeRes; + + for (;;) + { + if (res == SZ_OK && bufIndex != (unsigned)(int)-1) + { + res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex); + if (res != SZ_OK) + { + mtc->writeRes = res; + MtProgress_SetError(&mtc->mtProgress, res); + } + } + + if (++wi >= mtc->numBlocksMax) + wi = 0; + { + BoolInt isReady; + + CriticalSection_Enter(&mtc->cs); + + if (bufIndex != (unsigned)(int)-1) + { + mtc->freeBlockList[bufIndex] = mtc->freeBlockHead; + mtc->freeBlockHead = bufIndex; + } + + isReady = mtc->ReadyBlocks[wi]; + + if (isReady) + mtc->ReadyBlocks[wi] = False; + else + mtc->writeIndex = wi; + + CriticalSection_Leave(&mtc->cs); + + RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore)) + + if (!isReady) + break; + } + + { + CMtCoderBlock *block = &mtc->blocks[wi]; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + bufIndex = block->bufIndex; + finished = block->finished; + } + } + } + #endif + + if (finished || res != SZ_OK) + return 0; + } +} + + +static THREAD_FUNC_DECL ThreadFunc(void *pp) +{ + CMtCoderThread *t = (CMtCoderThread *)pp; + for (;;) + { + if (Event_Wait(&t->startEvent) != 0) + return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; + if (t->stop) + return 0; + { + SRes res = ThreadFunc2(t); + CMtCoder *mtc = t->mtCoder; + if (res != SZ_OK) + { + MtProgress_SetError(&mtc->mtProgress, res); + } + + #ifndef MTCODER_USE_WRITE_THREAD + { + unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads); + if (numFinished == mtc->numStartedThreads) + if (Event_Set(&mtc->finishedEvent) != 0) + return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD; + } + #endif + } + } +} + + + +void MtCoder_Construct(CMtCoder *p) +{ + unsigned i; + + p->blockSize = 0; + p->numThreadsMax = 0; + p->expectedDataSize = (UInt64)(Int64)-1; + + p->inStream = NULL; + p->inData = NULL; + p->inDataSize = 0; + + p->progress = NULL; + p->allocBig = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + Event_Construct(&p->readEvent); + Semaphore_Construct(&p->blocksSemaphore); + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + t->mtCoder = p; + t->index = i; + t->inBuf = NULL; + t->stop = False; + Event_Construct(&t->startEvent); + Thread_CONSTRUCT(&t->thread) + } + + #ifdef MTCODER_USE_WRITE_THREAD + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + Event_Construct(&p->writeEvents[i]); + #else + Event_Construct(&p->finishedEvent); + #endif + + CriticalSection_Init(&p->cs); + CriticalSection_Init(&p->mtProgress.cs); +} + + + + +static void MtCoder_Free(CMtCoder *p) +{ + unsigned i; + + /* + p->stopReading = True; + if (Event_IsCreated(&p->readEvent)) + Event_Set(&p->readEvent); + */ + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + MtCoderThread_Destruct(&p->threads[i]); + + Event_Close(&p->readEvent); + Semaphore_Close(&p->blocksSemaphore); + + #ifdef MTCODER_USE_WRITE_THREAD + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + Event_Close(&p->writeEvents[i]); + #else + Event_Close(&p->finishedEvent); + #endif +} + + +void MtCoder_Destruct(CMtCoder *p) +{ + MtCoder_Free(p); + + CriticalSection_Delete(&p->cs); + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtCoder_Code(CMtCoder *p) +{ + unsigned numThreads = p->numThreadsMax; + unsigned numBlocksMax; + unsigned i; + SRes res = SZ_OK; + + if (numThreads > MTCODER_THREADS_MAX) + numThreads = MTCODER_THREADS_MAX; + numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads); + + if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++; + if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++; + + if (numBlocksMax > MTCODER_BLOCKS_MAX) + numBlocksMax = MTCODER_BLOCKS_MAX; + + if (p->blockSize != p->allocatedBufsSize) + { + for (i = 0; i < MTCODER_THREADS_MAX; i++) + { + CMtCoderThread *t = &p->threads[i]; + if (t->inBuf) + { + ISzAlloc_Free(p->allocBig, t->inBuf); + t->inBuf = NULL; + } + } + p->allocatedBufsSize = p->blockSize; + } + + p->readRes = SZ_OK; + + MtProgress_Init(&p->mtProgress, p->progress); + + #ifdef MTCODER_USE_WRITE_THREAD + for (i = 0; i < numBlocksMax; i++) + { + RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->writeEvents[i])) + } + #else + RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent)) + #endif + + { + RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->readEvent)) + RINOK_THREAD(Semaphore_OptCreateInit(&p->blocksSemaphore, (UInt32)numBlocksMax, (UInt32)numBlocksMax)) + } + + for (i = 0; i < MTCODER_BLOCKS_MAX - 1; i++) + p->freeBlockList[i] = i + 1; + p->freeBlockList[MTCODER_BLOCKS_MAX - 1] = (unsigned)(int)-1; + p->freeBlockHead = 0; + + p->readProcessed = 0; + p->blockIndex = 0; + p->numBlocksMax = numBlocksMax; + p->stopReading = False; + + #ifndef MTCODER_USE_WRITE_THREAD + p->writeIndex = 0; + p->writeRes = SZ_OK; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + p->ReadyBlocks[i] = False; + p->numFinishedThreads = 0; + #endif + + p->numStartedThreadsLimit = numThreads; + p->numStartedThreads = 0; + + // for (i = 0; i < numThreads; i++) + { + CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++]; + RINOK(MtCoderThread_CreateAndStart(nextThread)) + } + + RINOK_THREAD(Event_Set(&p->readEvent)) + + #ifdef MTCODER_USE_WRITE_THREAD + { + unsigned bi = 0; + + for (;; bi++) + { + if (bi >= numBlocksMax) + bi = 0; + + RINOK_THREAD(Event_Wait(&p->writeEvents[bi])) + + { + const CMtCoderBlock *block = &p->blocks[bi]; + unsigned bufIndex = block->bufIndex; + BoolInt finished = block->finished; + if (res == SZ_OK && block->res != SZ_OK) + res = block->res; + + if (bufIndex != (unsigned)(int)-1) + { + if (res == SZ_OK) + { + res = p->mtCallback->Write(p->mtCallbackObject, bufIndex); + if (res != SZ_OK) + MtProgress_SetError(&p->mtProgress, res); + } + + CriticalSection_Enter(&p->cs); + { + p->freeBlockList[bufIndex] = p->freeBlockHead; + p->freeBlockHead = bufIndex; + } + CriticalSection_Leave(&p->cs); + } + + RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore)) + + if (finished) + break; + } + } + } + #else + { + WRes wres = Event_Wait(&p->finishedEvent); + res = MY_SRes_HRESULT_FROM_WRes(wres); + } + #endif + + if (res == SZ_OK) + res = p->readRes; + + if (res == SZ_OK) + res = p->mtProgress.res; + + #ifndef MTCODER_USE_WRITE_THREAD + if (res == SZ_OK) + res = p->writeRes; + #endif + + if (res != SZ_OK) + MtCoder_Free(p); + return res; +} + +#endif + +#undef RINOK_THREAD diff --git a/C/MtCoder.h b/C/MtCoder.h index c031fe0f7..1231d3c2a 100644 --- a/C/MtCoder.h +++ b/C/MtCoder.h @@ -1,141 +1,141 @@ -/* MtCoder.h -- Multi-thread Coder -2023-04-13 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_MT_CODER_H -#define ZIP7_INC_MT_CODER_H - -#include "MtDec.h" - -EXTERN_C_BEGIN - -/* - if ( defined MTCODER_USE_WRITE_THREAD) : main thread writes all data blocks to output stream - if (not defined MTCODER_USE_WRITE_THREAD) : any coder thread can write data blocks to output stream -*/ -/* #define MTCODER_USE_WRITE_THREAD */ - -#ifndef Z7_ST - #define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) - #define MTCODER_THREADS_MAX 64 - #define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3) -#else - #define MTCODER_THREADS_MAX 1 - #define MTCODER_BLOCKS_MAX 1 -#endif - - -#ifndef Z7_ST - - -typedef struct -{ - ICompressProgress vt; - CMtProgress *mtProgress; - UInt64 inSize; - UInt64 outSize; -} CMtProgressThunk; - -void MtProgressThunk_CreateVTable(CMtProgressThunk *p); - -#define MtProgressThunk_INIT(p) { (p)->inSize = 0; (p)->outSize = 0; } - - -struct CMtCoder_; - - -typedef struct -{ - struct CMtCoder_ *mtCoder; - unsigned index; - int stop; - Byte *inBuf; - - CAutoResetEvent startEvent; - CThread thread; -} CMtCoderThread; - - -typedef struct -{ - SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex, - const Byte *src, size_t srcSize, int finished); - SRes (*Write)(void *p, unsigned outBufIndex); -} IMtCoderCallback2; - - -typedef struct -{ - SRes res; - unsigned bufIndex; - BoolInt finished; -} CMtCoderBlock; - - -typedef struct CMtCoder_ -{ - /* input variables */ - - size_t blockSize; /* size of input block */ - unsigned numThreadsMax; - UInt64 expectedDataSize; - - ISeqInStreamPtr inStream; - const Byte *inData; - size_t inDataSize; - - ICompressProgressPtr progress; - ISzAllocPtr allocBig; - - IMtCoderCallback2 *mtCallback; - void *mtCallbackObject; - - - /* internal variables */ - - size_t allocatedBufsSize; - - CAutoResetEvent readEvent; - CSemaphore blocksSemaphore; - - BoolInt stopReading; - SRes readRes; - - #ifdef MTCODER_USE_WRITE_THREAD - CAutoResetEvent writeEvents[MTCODER_BLOCKS_MAX]; - #else - CAutoResetEvent finishedEvent; - SRes writeRes; - unsigned writeIndex; - Byte ReadyBlocks[MTCODER_BLOCKS_MAX]; - LONG numFinishedThreads; - #endif - - unsigned numStartedThreadsLimit; - unsigned numStartedThreads; - - unsigned numBlocksMax; - unsigned blockIndex; - UInt64 readProcessed; - - CCriticalSection cs; - - unsigned freeBlockHead; - unsigned freeBlockList[MTCODER_BLOCKS_MAX]; - - CMtProgress mtProgress; - CMtCoderBlock blocks[MTCODER_BLOCKS_MAX]; - CMtCoderThread threads[MTCODER_THREADS_MAX]; -} CMtCoder; - - -void MtCoder_Construct(CMtCoder *p); -void MtCoder_Destruct(CMtCoder *p); -SRes MtCoder_Code(CMtCoder *p); - - -#endif - - -EXTERN_C_END - -#endif +/* MtCoder.h -- Multi-thread Coder +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_MT_CODER_H +#define ZIP7_INC_MT_CODER_H + +#include "MtDec.h" + +EXTERN_C_BEGIN + +/* + if ( defined MTCODER_USE_WRITE_THREAD) : main thread writes all data blocks to output stream + if (not defined MTCODER_USE_WRITE_THREAD) : any coder thread can write data blocks to output stream +*/ +/* #define MTCODER_USE_WRITE_THREAD */ + +#ifndef Z7_ST + #define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1) + #define MTCODER_THREADS_MAX 64 + #define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3) +#else + #define MTCODER_THREADS_MAX 1 + #define MTCODER_BLOCKS_MAX 1 +#endif + + +#ifndef Z7_ST + + +typedef struct +{ + ICompressProgress vt; + CMtProgress *mtProgress; + UInt64 inSize; + UInt64 outSize; +} CMtProgressThunk; + +void MtProgressThunk_CreateVTable(CMtProgressThunk *p); + +#define MtProgressThunk_INIT(p) { (p)->inSize = 0; (p)->outSize = 0; } + + +struct CMtCoder_; + + +typedef struct +{ + struct CMtCoder_ *mtCoder; + unsigned index; + int stop; + Byte *inBuf; + + CAutoResetEvent startEvent; + CThread thread; +} CMtCoderThread; + + +typedef struct +{ + SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished); + SRes (*Write)(void *p, unsigned outBufIndex); +} IMtCoderCallback2; + + +typedef struct +{ + SRes res; + unsigned bufIndex; + BoolInt finished; +} CMtCoderBlock; + + +typedef struct CMtCoder_ +{ + /* input variables */ + + size_t blockSize; /* size of input block */ + unsigned numThreadsMax; + UInt64 expectedDataSize; + + ISeqInStreamPtr inStream; + const Byte *inData; + size_t inDataSize; + + ICompressProgressPtr progress; + ISzAllocPtr allocBig; + + IMtCoderCallback2 *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + CAutoResetEvent readEvent; + CSemaphore blocksSemaphore; + + BoolInt stopReading; + SRes readRes; + + #ifdef MTCODER_USE_WRITE_THREAD + CAutoResetEvent writeEvents[MTCODER_BLOCKS_MAX]; + #else + CAutoResetEvent finishedEvent; + SRes writeRes; + unsigned writeIndex; + Byte ReadyBlocks[MTCODER_BLOCKS_MAX]; + LONG numFinishedThreads; + #endif + + unsigned numStartedThreadsLimit; + unsigned numStartedThreads; + + unsigned numBlocksMax; + unsigned blockIndex; + UInt64 readProcessed; + + CCriticalSection cs; + + unsigned freeBlockHead; + unsigned freeBlockList[MTCODER_BLOCKS_MAX]; + + CMtProgress mtProgress; + CMtCoderBlock blocks[MTCODER_BLOCKS_MAX]; + CMtCoderThread threads[MTCODER_THREADS_MAX]; +} CMtCoder; + + +void MtCoder_Construct(CMtCoder *p); +void MtCoder_Destruct(CMtCoder *p); +SRes MtCoder_Code(CMtCoder *p); + + +#endif + + +EXTERN_C_END + +#endif diff --git a/C/MtDec.c b/C/MtDec.c index c79520425..96274b6f3 100644 --- a/C/MtDec.c +++ b/C/MtDec.c @@ -1,1124 +1,1124 @@ -/* MtDec.c -- Multi-thread Decoder -2024-02-20 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #define SHOW_DEBUG_INFO - -// #include -#include - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "MtDec.h" - -#ifndef Z7_ST - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) - -void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress) -{ - p->progress = progress; - p->res = SZ_OK; - p->totalInSize = 0; - p->totalOutSize = 0; -} - - -SRes MtProgress_Progress_ST(CMtProgress *p) -{ - if (p->res == SZ_OK && p->progress) - if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) - p->res = SZ_ERROR_PROGRESS; - return p->res; -} - - -SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize) -{ - SRes res; - CriticalSection_Enter(&p->cs); - - p->totalInSize += inSize; - p->totalOutSize += outSize; - if (p->res == SZ_OK && p->progress) - if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) - p->res = SZ_ERROR_PROGRESS; - res = p->res; - - CriticalSection_Leave(&p->cs); - return res; -} - - -SRes MtProgress_GetError(CMtProgress *p) -{ - SRes res; - CriticalSection_Enter(&p->cs); - res = p->res; - CriticalSection_Leave(&p->cs); - return res; -} - - -void MtProgress_SetError(CMtProgress *p, SRes res) -{ - CriticalSection_Enter(&p->cs); - if (p->res == SZ_OK) - p->res = res; - CriticalSection_Leave(&p->cs); -} - - -#define RINOK_THREAD(x) RINOK_WRes(x) - - -struct CMtDecBufLink_ -{ - struct CMtDecBufLink_ *next; - void *pad[3]; -}; - -typedef struct CMtDecBufLink_ CMtDecBufLink; - -#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink) -#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET) - - - -static THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp); - - -static WRes MtDecThread_CreateEvents(CMtDecThread *t) -{ - WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->canWrite); - if (wres == 0) - { - wres = AutoResetEvent_OptCreate_And_Reset(&t->canRead); - if (wres == 0) - return SZ_OK; - } - return wres; -} - - -static SRes MtDecThread_CreateAndStart(CMtDecThread *t) -{ - WRes wres = MtDecThread_CreateEvents(t); - // wres = 17; // for test - if (wres == 0) - { - if (Thread_WasCreated(&t->thread)) - return SZ_OK; - wres = Thread_Create(&t->thread, MtDec_ThreadFunc, t); - if (wres == 0) - return SZ_OK; - } - return MY_SRes_HRESULT_FROM_WRes(wres); -} - - -void MtDecThread_FreeInBufs(CMtDecThread *t) -{ - if (t->inBuf) - { - void *link = t->inBuf; - t->inBuf = NULL; - do - { - void *next = ((CMtDecBufLink *)link)->next; - ISzAlloc_Free(t->mtDec->alloc, link); - link = next; - } - while (link); - } -} - - -static void MtDecThread_CloseThread(CMtDecThread *t) -{ - if (Thread_WasCreated(&t->thread)) - { - Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */ - Event_Set(&t->canRead); - Thread_Wait_Close(&t->thread); - } - - Event_Close(&t->canRead); - Event_Close(&t->canWrite); -} - -static void MtDec_CloseThreads(CMtDec *p) -{ - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - MtDecThread_CloseThread(&p->threads[i]); -} - -static void MtDecThread_Destruct(CMtDecThread *t) -{ - MtDecThread_CloseThread(t); - MtDecThread_FreeInBufs(t); -} - - - -static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted) -{ - SRes res; - CriticalSection_Enter(&p->mtProgress.cs); - *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); - res = p->mtProgress.res; - CriticalSection_Leave(&p->mtProgress.cs); - return res; -} - -static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted) -{ - SRes res; - CriticalSection_Enter(&p->mtProgress.cs); - - p->mtProgress.totalInSize += inSize; - p->mtProgress.totalOutSize += outSize; - if (p->mtProgress.res == SZ_OK && p->mtProgress.progress) - if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK) - p->mtProgress.res = SZ_ERROR_PROGRESS; - - *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); - res = p->mtProgress.res; - - CriticalSection_Leave(&p->mtProgress.cs); - - return res; -} - -static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex) -{ - CriticalSection_Enter(&p->mtProgress.cs); - if (!p->needInterrupt || interruptIndex < p->interruptIndex) - { - p->interruptIndex = interruptIndex; - p->needInterrupt = True; - } - CriticalSection_Leave(&p->mtProgress.cs); -} - -Byte *MtDec_GetCrossBuff(CMtDec *p) -{ - Byte *cr = p->crossBlock; - if (!cr) - { - cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); - if (!cr) - return NULL; - p->crossBlock = cr; - } - return MTDEC__DATA_PTR_FROM_LINK(cr); -} - - -/* - MtDec_ThreadFunc2() returns: - 0 - in all normal cases (even for stream error or memory allocation error) - (!= 0) - WRes error return by system threading function -*/ - -// #define MTDEC_ProgessStep (1 << 22) -#define MTDEC_ProgessStep (1 << 0) - -static WRes MtDec_ThreadFunc2(CMtDecThread *t) -{ - CMtDec *p = t->mtDec; - - PRF_STR_INT("MtDec_ThreadFunc2", t->index) - - // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index); - - for (;;) - { - SRes res, codeRes; - BoolInt wasInterrupted, isAllocError, overflow, finish; - SRes threadingErrorSRes; - BoolInt needCode, needWrite, needContinue; - - size_t inDataSize_Start; - UInt64 inDataSize; - // UInt64 inDataSize_Full; - - UInt64 blockIndex; - - UInt64 inPrev = 0; - UInt64 outPrev = 0; - UInt64 inCodePos; - UInt64 outCodePos; - - Byte *afterEndData = NULL; - size_t afterEndData_Size = 0; - BoolInt afterEndData_IsCross = False; - - BoolInt canCreateNewThread = False; - // CMtDecCallbackInfo parse; - CMtDecThread *nextThread; - - PRF_STR_INT("=============== Event_Wait(&t->canRead)", t->index) - - RINOK_THREAD(Event_Wait(&t->canRead)) - if (p->exitThread) - return 0; - - PRF_STR_INT("after Event_Wait(&t->canRead)", t->index) - - // if (t->index == 3) return 19; // for test - - blockIndex = p->blockIndex++; - - // PRF(printf("\ncanRead\n")) - - res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); - - finish = p->readWasFinished; - needCode = False; - needWrite = False; - isAllocError = False; - overflow = False; - - inDataSize_Start = 0; - inDataSize = 0; - // inDataSize_Full = 0; - - if (res == SZ_OK && !wasInterrupted) - { - // if (p->inStream) - { - CMtDecBufLink *prev = NULL; - CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; - size_t crossSize = p->crossEnd - p->crossStart; - - PRF(printf("\ncrossSize = %d\n", crossSize)); - - for (;;) - { - if (!link) - { - link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); - if (!link) - { - finish = True; - // p->allocError_for_Read_BlockIndex = blockIndex; - isAllocError = True; - break; - } - link->next = NULL; - if (prev) - { - // static unsigned g_num = 0; - // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev)); - prev->next = link; - } - else - t->inBuf = (void *)link; - } - - { - Byte *data = MTDEC__DATA_PTR_FROM_LINK(link); - Byte *parseData = data; - size_t size; - - if (crossSize != 0) - { - inDataSize = crossSize; - // inDataSize_Full = inDataSize; - inDataSize_Start = crossSize; - size = crossSize; - parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; - PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d", - (int)p->crossStart, (int)p->crossEnd, (int)finish)); - } - else - { - size = p->inBufSize; - - res = SeqInStream_ReadMax(p->inStream, data, &size); - - // size = 10; // test - - inDataSize += size; - // inDataSize_Full = inDataSize; - if (!prev) - inDataSize_Start = size; - - p->readProcessed += size; - finish = (size != p->inBufSize); - if (finish) - p->readWasFinished = True; - - // res = E_INVALIDARG; // test - - if (res != SZ_OK) - { - // PRF(printf("\nRead error = %d\n", res)) - // we want to decode all data before error - p->readRes = res; - // p->readError_BlockIndex = blockIndex; - p->readWasFinished = True; - finish = True; - res = SZ_OK; - // break; - } - - if (inDataSize - inPrev >= MTDEC_ProgessStep) - { - res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); - if (res != SZ_OK || wasInterrupted) - break; - inPrev = inDataSize; - } - } - - { - CMtDecCallbackInfo parse; - - parse.startCall = (prev == NULL); - parse.src = parseData; - parse.srcSize = size; - parse.srcFinished = finish; - parse.canCreateNewThread = True; - - PRF(printf("\nParse size = %d\n", (unsigned)size)); - - p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse); - - PRF(printf(" Parse processed = %d, state = %d \n", (unsigned)parse.srcSize, (unsigned)parse.state)); - - needWrite = True; - canCreateNewThread = parse.canCreateNewThread; - - // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize); - - if ( - // parseRes != SZ_OK || - // inDataSize - (size - parse.srcSize) > p->inBlockMax - // || - parse.state == MTDEC_PARSE_OVERFLOW - // || wasInterrupted - ) - { - // Overflow or Parse error - switch from MT decoding to ST decoding - finish = True; - overflow = True; - - { - PRF(printf("\n Overflow")); - // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished)); - PRF(printf("\n inDataSize = %d", (unsigned)inDataSize)); - } - - if (crossSize != 0) - memcpy(data, parseData, size); - p->crossStart = 0; - p->crossEnd = 0; - break; - } - - if (crossSize != 0) - { - memcpy(data, parseData, parse.srcSize); - p->crossStart += parse.srcSize; - } - - if (parse.state != MTDEC_PARSE_CONTINUE || finish) - { - // we don't need to parse in current thread anymore - - if (parse.state == MTDEC_PARSE_END) - finish = True; - - needCode = True; - // p->crossFinished = finish; - - if (parse.srcSize == size) - { - // full parsed - no cross transfer - p->crossStart = 0; - p->crossEnd = 0; - break; - } - - if (parse.state == MTDEC_PARSE_END) - { - afterEndData = parseData + parse.srcSize; - afterEndData_Size = size - parse.srcSize; - if (crossSize != 0) - afterEndData_IsCross = True; - // we reduce data size to required bytes (parsed only) - inDataSize -= afterEndData_Size; - if (!prev) - inDataSize_Start = parse.srcSize; - break; - } - - { - // partial parsed - need cross transfer - if (crossSize != 0) - inDataSize = parse.srcSize; // it's only parsed now - else - { - // partial parsed - is not in initial cross block - we need to copy new data to cross block - Byte *cr = MtDec_GetCrossBuff(p); - if (!cr) - { - { - PRF(printf("\ncross alloc error error\n")); - // res = SZ_ERROR_MEM; - finish = True; - // p->allocError_for_Read_BlockIndex = blockIndex; - isAllocError = True; - break; - } - } - - { - size_t crSize = size - parse.srcSize; - inDataSize -= crSize; - p->crossEnd = crSize; - p->crossStart = 0; - memcpy(cr, parseData + parse.srcSize, crSize); - } - } - - // inDataSize_Full = inDataSize; - if (!prev) - inDataSize_Start = parse.srcSize; // it's partial size (parsed only) - - finish = False; - break; - } - } - - if (parse.srcSize != size) - { - res = SZ_ERROR_FAIL; - PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res)); - break; - } - } - } - - prev = link; - link = link->next; - - if (crossSize != 0) - { - crossSize = 0; - p->crossStart = 0; - p->crossEnd = 0; - } - } - } - - if (res == SZ_OK) - res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted); - } - - codeRes = SZ_OK; - - if (res == SZ_OK && needCode && !wasInterrupted) - { - codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index); - if (codeRes != SZ_OK) - { - needCode = False; - finish = True; - // SZ_ERROR_MEM is expected error here. - // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later. - // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding. - } - } - - if (res != SZ_OK || wasInterrupted) - finish = True; - - nextThread = NULL; - threadingErrorSRes = SZ_OK; - - if (!finish) - { - if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread) - { - SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]); - if (res2 == SZ_OK) - { - // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads)); - p->numStartedThreads++; - } - else - { - PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads)); - if (p->numStartedThreads == 1) - { - // if only one thread is possible, we leave muti-threading code - finish = True; - needCode = False; - threadingErrorSRes = res2; - } - else - p->numStartedThreads_Limit = p->numStartedThreads; - } - } - - if (!finish) - { - unsigned nextIndex = t->index + 1; - nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex]; - RINOK_THREAD(Event_Set(&nextThread->canRead)) - // We have started executing for new iteration (with next thread) - // And that next thread now is responsible for possible exit from decoding (threading_code) - } - } - - // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite) - // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case - // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block): - // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration - // - otherwise we stop decoding and exit from MtDec_ThreadFunc2() - - // Don't change (finish) variable in the further code - - - // ---------- CODE ---------- - - inPrev = 0; - outPrev = 0; - inCodePos = 0; - outCodePos = 0; - - if (res == SZ_OK && needCode && codeRes == SZ_OK) - { - BoolInt isStartBlock = True; - CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; - - for (;;) - { - size_t inSize; - int stop; - - if (isStartBlock) - inSize = inDataSize_Start; - else - { - UInt64 rem = inDataSize - inCodePos; - inSize = p->inBufSize; - if (inSize > rem) - inSize = (size_t)rem; - } - - inCodePos += inSize; - stop = True; - - codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index, - (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize, - (inCodePos == inDataSize), // srcFinished - &inCodePos, &outCodePos, &stop); - - if (codeRes != SZ_OK) - { - PRF(printf("\nCode Interrupt error = %x\n", codeRes)); - // we interrupt only later blocks - MtDec_Interrupt(p, blockIndex); - break; - } - - if (stop || inCodePos == inDataSize) - break; - - { - const UInt64 inDelta = inCodePos - inPrev; - const UInt64 outDelta = outCodePos - outPrev; - if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep) - { - // Sleep(1); - res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted); - if (res != SZ_OK || wasInterrupted) - break; - inPrev = inCodePos; - outPrev = outCodePos; - } - } - - link = link->next; - isStartBlock = False; - } - } - - - // ---------- WRITE ---------- - - RINOK_THREAD(Event_Wait(&t->canWrite)) - - { - BoolInt isErrorMode = False; - BoolInt canRecode = True; - BoolInt needWriteToStream = needWrite; - - if (p->exitThread) return 0; // it's never executed in normal cases - - if (p->wasInterrupted) - wasInterrupted = True; - else - { - if (codeRes != SZ_OK) // || !needCode // check it !!! - { - p->wasInterrupted = True; - p->codeRes = codeRes; - if (codeRes == SZ_ERROR_MEM) - isAllocError = True; - } - - if (threadingErrorSRes) - { - p->wasInterrupted = True; - p->threadingErrorSRes = threadingErrorSRes; - needWriteToStream = False; - } - if (isAllocError) - { - p->wasInterrupted = True; - p->isAllocError = True; - needWriteToStream = False; - } - if (overflow) - { - p->wasInterrupted = True; - p->overflow = True; - needWriteToStream = False; - } - } - - if (needCode) - { - if (wasInterrupted) - { - inCodePos = 0; - outCodePos = 0; - } - { - const UInt64 inDelta = inCodePos - inPrev; - const UInt64 outDelta = outCodePos - outPrev; - // if (inDelta != 0 || outDelta != 0) - res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta); - } - } - - needContinue = (!finish); - - // if (res == SZ_OK && needWrite && !wasInterrupted) - if (needWrite) - { - // p->inProcessed += inCodePos; - - PRF(printf("\n--Write afterSize = %d\n", (unsigned)afterEndData_Size)); - - res = p->mtCallback->Write(p->mtCallbackObject, t->index, - res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite - afterEndData, afterEndData_Size, afterEndData_IsCross, - &needContinue, - &canRecode); - - // res = SZ_ERROR_FAIL; // for test - - PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue)); - PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed)); - - if (res != SZ_OK) - { - PRF(printf("\nWrite error = %d\n", res)); - isErrorMode = True; - p->wasInterrupted = True; - } - if (res != SZ_OK - || (!needContinue && !finish)) - { - PRF(printf("\nWrite Interrupt error = %x\n", res)); - MtDec_Interrupt(p, blockIndex); - } - } - - if (canRecode) - if (!needCode - || res != SZ_OK - || p->wasInterrupted - || codeRes != SZ_OK - || wasInterrupted - || p->numFilledThreads != 0 - || isErrorMode) - { - if (p->numFilledThreads == 0) - p->filledThreadStart = t->index; - if (inDataSize != 0 || !finish) - { - t->inDataSize_Start = inDataSize_Start; - t->inDataSize = inDataSize; - p->numFilledThreads++; - } - PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads)); - PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart)); - } - - if (!finish) - { - RINOK_THREAD(Event_Set(&nextThread->canWrite)) - } - else - { - if (needContinue) - { - // we restore decoding with new iteration - RINOK_THREAD(Event_Set(&p->threads[0].canWrite)) - } - else - { - // we exit from decoding - if (t->index == 0) - return SZ_OK; - p->exitThread = True; - } - RINOK_THREAD(Event_Set(&p->threads[0].canRead)) - } - } - } -} - -#ifdef _WIN32 -#define USE_ALLOCA -#endif - -#ifdef USE_ALLOCA -#ifdef _WIN32 -#include -#else -#include -#endif -#endif - - -typedef - #ifdef _WIN32 - UINT_PTR - #elif 1 - uintptr_t - #else - ptrdiff_t - #endif - MY_uintptr_t; - -static THREAD_FUNC_DECL MtDec_ThreadFunc1(void *pp) -{ - WRes res; - - CMtDecThread *t = (CMtDecThread *)pp; - CMtDec *p; - - // fprintf(stdout, "\n%d = %p\n", t->index, &t); - - res = MtDec_ThreadFunc2(t); - p = t->mtDec; - if (res == 0) - return (THREAD_FUNC_RET_TYPE)(MY_uintptr_t)p->exitThreadWRes; - { - // it's unexpected situation for some threading function error - if (p->exitThreadWRes == 0) - p->exitThreadWRes = res; - PRF(printf("\nthread exit error = %d\n", res)); - p->exitThread = True; - Event_Set(&p->threads[0].canRead); - Event_Set(&p->threads[0].canWrite); - MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res)); - } - return (THREAD_FUNC_RET_TYPE)(MY_uintptr_t)res; -} - -static Z7_NO_INLINE THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp) -{ - #ifdef USE_ALLOCA - CMtDecThread *t = (CMtDecThread *)pp; - // fprintf(stderr, "\n%d = %p - before", t->index, &t); - t->allocaPtr = alloca(t->index * 128); - #endif - return MtDec_ThreadFunc1(pp); -} - - -int MtDec_PrepareRead(CMtDec *p) -{ - if (p->crossBlock && p->crossStart == p->crossEnd) - { - ISzAlloc_Free(p->alloc, p->crossBlock); - p->crossBlock = NULL; - } - - { - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - if (i > p->numStartedThreads - || p->numFilledThreads <= - (i >= p->filledThreadStart ? - i - p->filledThreadStart : - i + p->numStartedThreads - p->filledThreadStart)) - MtDecThread_FreeInBufs(&p->threads[i]); - } - - return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd); -} - - -const Byte *MtDec_Read(CMtDec *p, size_t *inLim) -{ - while (p->numFilledThreads != 0) - { - CMtDecThread *t = &p->threads[p->filledThreadStart]; - - if (*inLim != 0) - { - { - void *link = t->inBuf; - void *next = ((CMtDecBufLink *)link)->next; - ISzAlloc_Free(p->alloc, link); - t->inBuf = next; - } - - if (t->inDataSize == 0) - { - MtDecThread_FreeInBufs(t); - if (--p->numFilledThreads == 0) - break; - if (++p->filledThreadStart == p->numStartedThreads) - p->filledThreadStart = 0; - t = &p->threads[p->filledThreadStart]; - } - } - - { - size_t lim = t->inDataSize_Start; - if (lim != 0) - t->inDataSize_Start = 0; - else - { - UInt64 rem = t->inDataSize; - lim = p->inBufSize; - if (lim > rem) - lim = (size_t)rem; - } - t->inDataSize -= lim; - *inLim = lim; - return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf); - } - } - - { - size_t crossSize = p->crossEnd - p->crossStart; - if (crossSize != 0) - { - const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; - *inLim = crossSize; - p->crossStart = 0; - p->crossEnd = 0; - return data; - } - *inLim = 0; - if (p->crossBlock) - { - ISzAlloc_Free(p->alloc, p->crossBlock); - p->crossBlock = NULL; - } - return NULL; - } -} - - -void MtDec_Construct(CMtDec *p) -{ - unsigned i; - - p->inBufSize = (size_t)1 << 18; - - p->numThreadsMax = 0; - - p->inStream = NULL; - - // p->inData = NULL; - // p->inDataSize = 0; - - p->crossBlock = NULL; - p->crossStart = 0; - p->crossEnd = 0; - - p->numFilledThreads = 0; - - p->progress = NULL; - p->alloc = NULL; - - p->mtCallback = NULL; - p->mtCallbackObject = NULL; - - p->allocatedBufsSize = 0; - - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CMtDecThread *t = &p->threads[i]; - t->mtDec = p; - t->index = i; - t->inBuf = NULL; - Event_Construct(&t->canRead); - Event_Construct(&t->canWrite); - Thread_CONSTRUCT(&t->thread) - } - - // Event_Construct(&p->finishedEvent); - - CriticalSection_Init(&p->mtProgress.cs); -} - - -static void MtDec_Free(CMtDec *p) -{ - unsigned i; - - p->exitThread = True; - - for (i = 0; i < MTDEC_THREADS_MAX; i++) - MtDecThread_Destruct(&p->threads[i]); - - // Event_Close(&p->finishedEvent); - - if (p->crossBlock) - { - ISzAlloc_Free(p->alloc, p->crossBlock); - p->crossBlock = NULL; - } -} - - -void MtDec_Destruct(CMtDec *p) -{ - MtDec_Free(p); - - CriticalSection_Delete(&p->mtProgress.cs); -} - - -SRes MtDec_Code(CMtDec *p) -{ - unsigned i; - - p->inProcessed = 0; - - p->blockIndex = 1; // it must be larger than not_defined index (0) - p->isAllocError = False; - p->overflow = False; - p->threadingErrorSRes = SZ_OK; - - p->needContinue = True; - - p->readWasFinished = False; - p->needInterrupt = False; - p->interruptIndex = (UInt64)(Int64)-1; - - p->readProcessed = 0; - p->readRes = SZ_OK; - p->codeRes = SZ_OK; - p->wasInterrupted = False; - - p->crossStart = 0; - p->crossEnd = 0; - - p->filledThreadStart = 0; - p->numFilledThreads = 0; - - { - unsigned numThreads = p->numThreadsMax; - if (numThreads > MTDEC_THREADS_MAX) - numThreads = MTDEC_THREADS_MAX; - p->numStartedThreads_Limit = numThreads; - p->numStartedThreads = 0; - } - - if (p->inBufSize != p->allocatedBufsSize) - { - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CMtDecThread *t = &p->threads[i]; - if (t->inBuf) - MtDecThread_FreeInBufs(t); - } - if (p->crossBlock) - { - ISzAlloc_Free(p->alloc, p->crossBlock); - p->crossBlock = NULL; - } - - p->allocatedBufsSize = p->inBufSize; - } - - MtProgress_Init(&p->mtProgress, p->progress); - - // RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent)) - p->exitThread = False; - p->exitThreadWRes = 0; - - { - WRes wres; - SRes sres; - CMtDecThread *nextThread = &p->threads[p->numStartedThreads++]; - // wres = MtDecThread_CreateAndStart(nextThread); - wres = MtDecThread_CreateEvents(nextThread); - if (wres == 0) { wres = Event_Set(&nextThread->canWrite); - if (wres == 0) { wres = Event_Set(&nextThread->canRead); - if (wres == 0) { THREAD_FUNC_RET_TYPE res = MtDec_ThreadFunc(nextThread); - wres = (WRes)(MY_uintptr_t)res; - if (wres != 0) - { - p->needContinue = False; - MtDec_CloseThreads(p); - }}}} - - // wres = 17; // for test - // wres = Event_Wait(&p->finishedEvent); - - sres = MY_SRes_HRESULT_FROM_WRes(wres); - - if (sres != 0) - p->threadingErrorSRes = sres; - - if ( - // wres == 0 - // wres != 0 - // || p->mtc.codeRes == SZ_ERROR_MEM - p->isAllocError - || p->threadingErrorSRes != SZ_OK - || p->overflow) - { - // p->needContinue = True; - } - else - p->needContinue = False; - - if (p->needContinue) - return SZ_OK; - - // if (sres != SZ_OK) - return sres; - // return SZ_ERROR_FAIL; - } -} - -#endif - -#undef PRF +/* MtDec.c -- Multi-thread Decoder +2024-02-20 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SHOW_DEBUG_INFO + +// #include +#include + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "MtDec.h" + +#ifndef Z7_ST + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress) +{ + p->progress = progress; + p->res = SZ_OK; + p->totalInSize = 0; + p->totalOutSize = 0; +} + + +SRes MtProgress_Progress_ST(CMtProgress *p) +{ + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + return p->res; +} + + +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize) +{ + SRes res; + CriticalSection_Enter(&p->cs); + + p->totalInSize += inSize; + p->totalOutSize += outSize; + if (p->res == SZ_OK && p->progress) + if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK) + p->res = SZ_ERROR_PROGRESS; + res = p->res; + + CriticalSection_Leave(&p->cs); + return res; +} + + +SRes MtProgress_GetError(CMtProgress *p) +{ + SRes res; + CriticalSection_Enter(&p->cs); + res = p->res; + CriticalSection_Leave(&p->cs); + return res; +} + + +void MtProgress_SetError(CMtProgress *p, SRes res) +{ + CriticalSection_Enter(&p->cs); + if (p->res == SZ_OK) + p->res = res; + CriticalSection_Leave(&p->cs); +} + + +#define RINOK_THREAD(x) RINOK_WRes(x) + + +struct CMtDecBufLink_ +{ + struct CMtDecBufLink_ *next; + void *pad[3]; +}; + +typedef struct CMtDecBufLink_ CMtDecBufLink; + +#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink) +#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET) + + + +static THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp); + + +static WRes MtDecThread_CreateEvents(CMtDecThread *t) +{ + WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->canWrite); + if (wres == 0) + { + wres = AutoResetEvent_OptCreate_And_Reset(&t->canRead); + if (wres == 0) + return SZ_OK; + } + return wres; +} + + +static SRes MtDecThread_CreateAndStart(CMtDecThread *t) +{ + WRes wres = MtDecThread_CreateEvents(t); + // wres = 17; // for test + if (wres == 0) + { + if (Thread_WasCreated(&t->thread)) + return SZ_OK; + wres = Thread_Create(&t->thread, MtDec_ThreadFunc, t); + if (wres == 0) + return SZ_OK; + } + return MY_SRes_HRESULT_FROM_WRes(wres); +} + + +void MtDecThread_FreeInBufs(CMtDecThread *t) +{ + if (t->inBuf) + { + void *link = t->inBuf; + t->inBuf = NULL; + do + { + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(t->mtDec->alloc, link); + link = next; + } + while (link); + } +} + + +static void MtDecThread_CloseThread(CMtDecThread *t) +{ + if (Thread_WasCreated(&t->thread)) + { + Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */ + Event_Set(&t->canRead); + Thread_Wait_Close(&t->thread); + } + + Event_Close(&t->canRead); + Event_Close(&t->canWrite); +} + +static void MtDec_CloseThreads(CMtDec *p) +{ + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + MtDecThread_CloseThread(&p->threads[i]); +} + +static void MtDecThread_Destruct(CMtDecThread *t) +{ + MtDecThread_CloseThread(t); + MtDecThread_FreeInBufs(t); +} + + + +static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + CriticalSection_Leave(&p->mtProgress.cs); + return res; +} + +static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted) +{ + SRes res; + CriticalSection_Enter(&p->mtProgress.cs); + + p->mtProgress.totalInSize += inSize; + p->mtProgress.totalOutSize += outSize; + if (p->mtProgress.res == SZ_OK && p->mtProgress.progress) + if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK) + p->mtProgress.res = SZ_ERROR_PROGRESS; + + *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex); + res = p->mtProgress.res; + + CriticalSection_Leave(&p->mtProgress.cs); + + return res; +} + +static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex) +{ + CriticalSection_Enter(&p->mtProgress.cs); + if (!p->needInterrupt || interruptIndex < p->interruptIndex) + { + p->interruptIndex = interruptIndex; + p->needInterrupt = True; + } + CriticalSection_Leave(&p->mtProgress.cs); +} + +Byte *MtDec_GetCrossBuff(CMtDec *p) +{ + Byte *cr = p->crossBlock; + if (!cr) + { + cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!cr) + return NULL; + p->crossBlock = cr; + } + return MTDEC__DATA_PTR_FROM_LINK(cr); +} + + +/* + MtDec_ThreadFunc2() returns: + 0 - in all normal cases (even for stream error or memory allocation error) + (!= 0) - WRes error return by system threading function +*/ + +// #define MTDEC_ProgessStep (1 << 22) +#define MTDEC_ProgessStep (1 << 0) + +static WRes MtDec_ThreadFunc2(CMtDecThread *t) +{ + CMtDec *p = t->mtDec; + + PRF_STR_INT("MtDec_ThreadFunc2", t->index) + + // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index); + + for (;;) + { + SRes res, codeRes; + BoolInt wasInterrupted, isAllocError, overflow, finish; + SRes threadingErrorSRes; + BoolInt needCode, needWrite, needContinue; + + size_t inDataSize_Start; + UInt64 inDataSize; + // UInt64 inDataSize_Full; + + UInt64 blockIndex; + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + UInt64 inCodePos; + UInt64 outCodePos; + + Byte *afterEndData = NULL; + size_t afterEndData_Size = 0; + BoolInt afterEndData_IsCross = False; + + BoolInt canCreateNewThread = False; + // CMtDecCallbackInfo parse; + CMtDecThread *nextThread; + + PRF_STR_INT("=============== Event_Wait(&t->canRead)", t->index) + + RINOK_THREAD(Event_Wait(&t->canRead)) + if (p->exitThread) + return 0; + + PRF_STR_INT("after Event_Wait(&t->canRead)", t->index) + + // if (t->index == 3) return 19; // for test + + blockIndex = p->blockIndex++; + + // PRF(printf("\ncanRead\n")) + + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + + finish = p->readWasFinished; + needCode = False; + needWrite = False; + isAllocError = False; + overflow = False; + + inDataSize_Start = 0; + inDataSize = 0; + // inDataSize_Full = 0; + + if (res == SZ_OK && !wasInterrupted) + { + // if (p->inStream) + { + CMtDecBufLink *prev = NULL; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + size_t crossSize = p->crossEnd - p->crossStart; + + PRF(printf("\ncrossSize = %d\n", crossSize)); + + for (;;) + { + if (!link) + { + link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize); + if (!link) + { + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + link->next = NULL; + if (prev) + { + // static unsigned g_num = 0; + // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev)); + prev->next = link; + } + else + t->inBuf = (void *)link; + } + + { + Byte *data = MTDEC__DATA_PTR_FROM_LINK(link); + Byte *parseData = data; + size_t size; + + if (crossSize != 0) + { + inDataSize = crossSize; + // inDataSize_Full = inDataSize; + inDataSize_Start = crossSize; + size = crossSize; + parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d", + (int)p->crossStart, (int)p->crossEnd, (int)finish)); + } + else + { + size = p->inBufSize; + + res = SeqInStream_ReadMax(p->inStream, data, &size); + + // size = 10; // test + + inDataSize += size; + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = size; + + p->readProcessed += size; + finish = (size != p->inBufSize); + if (finish) + p->readWasFinished = True; + + // res = E_INVALIDARG; // test + + if (res != SZ_OK) + { + // PRF(printf("\nRead error = %d\n", res)) + // we want to decode all data before error + p->readRes = res; + // p->readError_BlockIndex = blockIndex; + p->readWasFinished = True; + finish = True; + res = SZ_OK; + // break; + } + + if (inDataSize - inPrev >= MTDEC_ProgessStep) + { + res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inDataSize; + } + } + + { + CMtDecCallbackInfo parse; + + parse.startCall = (prev == NULL); + parse.src = parseData; + parse.srcSize = size; + parse.srcFinished = finish; + parse.canCreateNewThread = True; + + PRF(printf("\nParse size = %d\n", (unsigned)size)); + + p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse); + + PRF(printf(" Parse processed = %d, state = %d \n", (unsigned)parse.srcSize, (unsigned)parse.state)); + + needWrite = True; + canCreateNewThread = parse.canCreateNewThread; + + // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize); + + if ( + // parseRes != SZ_OK || + // inDataSize - (size - parse.srcSize) > p->inBlockMax + // || + parse.state == MTDEC_PARSE_OVERFLOW + // || wasInterrupted + ) + { + // Overflow or Parse error - switch from MT decoding to ST decoding + finish = True; + overflow = True; + + { + PRF(printf("\n Overflow")); + // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished)); + PRF(printf("\n inDataSize = %d", (unsigned)inDataSize)); + } + + if (crossSize != 0) + memcpy(data, parseData, size); + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (crossSize != 0) + { + memcpy(data, parseData, parse.srcSize); + p->crossStart += parse.srcSize; + } + + if (parse.state != MTDEC_PARSE_CONTINUE || finish) + { + // we don't need to parse in current thread anymore + + if (parse.state == MTDEC_PARSE_END) + finish = True; + + needCode = True; + // p->crossFinished = finish; + + if (parse.srcSize == size) + { + // full parsed - no cross transfer + p->crossStart = 0; + p->crossEnd = 0; + break; + } + + if (parse.state == MTDEC_PARSE_END) + { + afterEndData = parseData + parse.srcSize; + afterEndData_Size = size - parse.srcSize; + if (crossSize != 0) + afterEndData_IsCross = True; + // we reduce data size to required bytes (parsed only) + inDataSize -= afterEndData_Size; + if (!prev) + inDataSize_Start = parse.srcSize; + break; + } + + { + // partial parsed - need cross transfer + if (crossSize != 0) + inDataSize = parse.srcSize; // it's only parsed now + else + { + // partial parsed - is not in initial cross block - we need to copy new data to cross block + Byte *cr = MtDec_GetCrossBuff(p); + if (!cr) + { + { + PRF(printf("\ncross alloc error error\n")); + // res = SZ_ERROR_MEM; + finish = True; + // p->allocError_for_Read_BlockIndex = blockIndex; + isAllocError = True; + break; + } + } + + { + size_t crSize = size - parse.srcSize; + inDataSize -= crSize; + p->crossEnd = crSize; + p->crossStart = 0; + memcpy(cr, parseData + parse.srcSize, crSize); + } + } + + // inDataSize_Full = inDataSize; + if (!prev) + inDataSize_Start = parse.srcSize; // it's partial size (parsed only) + + finish = False; + break; + } + } + + if (parse.srcSize != size) + { + res = SZ_ERROR_FAIL; + PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res)); + break; + } + } + } + + prev = link; + link = link->next; + + if (crossSize != 0) + { + crossSize = 0; + p->crossStart = 0; + p->crossEnd = 0; + } + } + } + + if (res == SZ_OK) + res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted); + } + + codeRes = SZ_OK; + + if (res == SZ_OK && needCode && !wasInterrupted) + { + codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index); + if (codeRes != SZ_OK) + { + needCode = False; + finish = True; + // SZ_ERROR_MEM is expected error here. + // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later. + // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding. + } + } + + if (res != SZ_OK || wasInterrupted) + finish = True; + + nextThread = NULL; + threadingErrorSRes = SZ_OK; + + if (!finish) + { + if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread) + { + SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]); + if (res2 == SZ_OK) + { + // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads)); + p->numStartedThreads++; + } + else + { + PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads)); + if (p->numStartedThreads == 1) + { + // if only one thread is possible, we leave muti-threading code + finish = True; + needCode = False; + threadingErrorSRes = res2; + } + else + p->numStartedThreads_Limit = p->numStartedThreads; + } + } + + if (!finish) + { + unsigned nextIndex = t->index + 1; + nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex]; + RINOK_THREAD(Event_Set(&nextThread->canRead)) + // We have started executing for new iteration (with next thread) + // And that next thread now is responsible for possible exit from decoding (threading_code) + } + } + + // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite) + // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case + // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block): + // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration + // - otherwise we stop decoding and exit from MtDec_ThreadFunc2() + + // Don't change (finish) variable in the further code + + + // ---------- CODE ---------- + + inPrev = 0; + outPrev = 0; + inCodePos = 0; + outCodePos = 0; + + if (res == SZ_OK && needCode && codeRes == SZ_OK) + { + BoolInt isStartBlock = True; + CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf; + + for (;;) + { + size_t inSize; + int stop; + + if (isStartBlock) + inSize = inDataSize_Start; + else + { + UInt64 rem = inDataSize - inCodePos; + inSize = p->inBufSize; + if (inSize > rem) + inSize = (size_t)rem; + } + + inCodePos += inSize; + stop = True; + + codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index, + (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize, + (inCodePos == inDataSize), // srcFinished + &inCodePos, &outCodePos, &stop); + + if (codeRes != SZ_OK) + { + PRF(printf("\nCode Interrupt error = %x\n", codeRes)); + // we interrupt only later blocks + MtDec_Interrupt(p, blockIndex); + break; + } + + if (stop || inCodePos == inDataSize) + break; + + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep) + { + // Sleep(1); + res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted); + if (res != SZ_OK || wasInterrupted) + break; + inPrev = inCodePos; + outPrev = outCodePos; + } + } + + link = link->next; + isStartBlock = False; + } + } + + + // ---------- WRITE ---------- + + RINOK_THREAD(Event_Wait(&t->canWrite)) + + { + BoolInt isErrorMode = False; + BoolInt canRecode = True; + BoolInt needWriteToStream = needWrite; + + if (p->exitThread) return 0; // it's never executed in normal cases + + if (p->wasInterrupted) + wasInterrupted = True; + else + { + if (codeRes != SZ_OK) // || !needCode // check it !!! + { + p->wasInterrupted = True; + p->codeRes = codeRes; + if (codeRes == SZ_ERROR_MEM) + isAllocError = True; + } + + if (threadingErrorSRes) + { + p->wasInterrupted = True; + p->threadingErrorSRes = threadingErrorSRes; + needWriteToStream = False; + } + if (isAllocError) + { + p->wasInterrupted = True; + p->isAllocError = True; + needWriteToStream = False; + } + if (overflow) + { + p->wasInterrupted = True; + p->overflow = True; + needWriteToStream = False; + } + } + + if (needCode) + { + if (wasInterrupted) + { + inCodePos = 0; + outCodePos = 0; + } + { + const UInt64 inDelta = inCodePos - inPrev; + const UInt64 outDelta = outCodePos - outPrev; + // if (inDelta != 0 || outDelta != 0) + res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta); + } + } + + needContinue = (!finish); + + // if (res == SZ_OK && needWrite && !wasInterrupted) + if (needWrite) + { + // p->inProcessed += inCodePos; + + PRF(printf("\n--Write afterSize = %d\n", (unsigned)afterEndData_Size)); + + res = p->mtCallback->Write(p->mtCallbackObject, t->index, + res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite + afterEndData, afterEndData_Size, afterEndData_IsCross, + &needContinue, + &canRecode); + + // res = SZ_ERROR_FAIL; // for test + + PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue)); + PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed)); + + if (res != SZ_OK) + { + PRF(printf("\nWrite error = %d\n", res)); + isErrorMode = True; + p->wasInterrupted = True; + } + if (res != SZ_OK + || (!needContinue && !finish)) + { + PRF(printf("\nWrite Interrupt error = %x\n", res)); + MtDec_Interrupt(p, blockIndex); + } + } + + if (canRecode) + if (!needCode + || res != SZ_OK + || p->wasInterrupted + || codeRes != SZ_OK + || wasInterrupted + || p->numFilledThreads != 0 + || isErrorMode) + { + if (p->numFilledThreads == 0) + p->filledThreadStart = t->index; + if (inDataSize != 0 || !finish) + { + t->inDataSize_Start = inDataSize_Start; + t->inDataSize = inDataSize; + p->numFilledThreads++; + } + PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads)); + PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart)); + } + + if (!finish) + { + RINOK_THREAD(Event_Set(&nextThread->canWrite)) + } + else + { + if (needContinue) + { + // we restore decoding with new iteration + RINOK_THREAD(Event_Set(&p->threads[0].canWrite)) + } + else + { + // we exit from decoding + if (t->index == 0) + return SZ_OK; + p->exitThread = True; + } + RINOK_THREAD(Event_Set(&p->threads[0].canRead)) + } + } + } +} + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#endif +#endif + + +typedef + #ifdef _WIN32 + UINT_PTR + #elif 1 + uintptr_t + #else + ptrdiff_t + #endif + MY_uintptr_t; + +static THREAD_FUNC_DECL MtDec_ThreadFunc1(void *pp) +{ + WRes res; + + CMtDecThread *t = (CMtDecThread *)pp; + CMtDec *p; + + // fprintf(stdout, "\n%d = %p\n", t->index, &t); + + res = MtDec_ThreadFunc2(t); + p = t->mtDec; + if (res == 0) + return (THREAD_FUNC_RET_TYPE)(MY_uintptr_t)p->exitThreadWRes; + { + // it's unexpected situation for some threading function error + if (p->exitThreadWRes == 0) + p->exitThreadWRes = res; + PRF(printf("\nthread exit error = %d\n", res)); + p->exitThread = True; + Event_Set(&p->threads[0].canRead); + Event_Set(&p->threads[0].canWrite); + MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res)); + } + return (THREAD_FUNC_RET_TYPE)(MY_uintptr_t)res; +} + +static Z7_NO_INLINE THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp) +{ + #ifdef USE_ALLOCA + CMtDecThread *t = (CMtDecThread *)pp; + // fprintf(stderr, "\n%d = %p - before", t->index, &t); + t->allocaPtr = alloca(t->index * 128); + #endif + return MtDec_ThreadFunc1(pp); +} + + +int MtDec_PrepareRead(CMtDec *p) +{ + if (p->crossBlock && p->crossStart == p->crossEnd) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + if (i > p->numStartedThreads + || p->numFilledThreads <= + (i >= p->filledThreadStart ? + i - p->filledThreadStart : + i + p->numStartedThreads - p->filledThreadStart)) + MtDecThread_FreeInBufs(&p->threads[i]); + } + + return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd); +} + + +const Byte *MtDec_Read(CMtDec *p, size_t *inLim) +{ + while (p->numFilledThreads != 0) + { + CMtDecThread *t = &p->threads[p->filledThreadStart]; + + if (*inLim != 0) + { + { + void *link = t->inBuf; + void *next = ((CMtDecBufLink *)link)->next; + ISzAlloc_Free(p->alloc, link); + t->inBuf = next; + } + + if (t->inDataSize == 0) + { + MtDecThread_FreeInBufs(t); + if (--p->numFilledThreads == 0) + break; + if (++p->filledThreadStart == p->numStartedThreads) + p->filledThreadStart = 0; + t = &p->threads[p->filledThreadStart]; + } + } + + { + size_t lim = t->inDataSize_Start; + if (lim != 0) + t->inDataSize_Start = 0; + else + { + UInt64 rem = t->inDataSize; + lim = p->inBufSize; + if (lim > rem) + lim = (size_t)rem; + } + t->inDataSize -= lim; + *inLim = lim; + return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf); + } + } + + { + size_t crossSize = p->crossEnd - p->crossStart; + if (crossSize != 0) + { + const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart; + *inLim = crossSize; + p->crossStart = 0; + p->crossEnd = 0; + return data; + } + *inLim = 0; + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + return NULL; + } +} + + +void MtDec_Construct(CMtDec *p) +{ + unsigned i; + + p->inBufSize = (size_t)1 << 18; + + p->numThreadsMax = 0; + + p->inStream = NULL; + + // p->inData = NULL; + // p->inDataSize = 0; + + p->crossBlock = NULL; + p->crossStart = 0; + p->crossEnd = 0; + + p->numFilledThreads = 0; + + p->progress = NULL; + p->alloc = NULL; + + p->mtCallback = NULL; + p->mtCallbackObject = NULL; + + p->allocatedBufsSize = 0; + + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + t->mtDec = p; + t->index = i; + t->inBuf = NULL; + Event_Construct(&t->canRead); + Event_Construct(&t->canWrite); + Thread_CONSTRUCT(&t->thread) + } + + // Event_Construct(&p->finishedEvent); + + CriticalSection_Init(&p->mtProgress.cs); +} + + +static void MtDec_Free(CMtDec *p) +{ + unsigned i; + + p->exitThread = True; + + for (i = 0; i < MTDEC_THREADS_MAX; i++) + MtDecThread_Destruct(&p->threads[i]); + + // Event_Close(&p->finishedEvent); + + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } +} + + +void MtDec_Destruct(CMtDec *p) +{ + MtDec_Free(p); + + CriticalSection_Delete(&p->mtProgress.cs); +} + + +SRes MtDec_Code(CMtDec *p) +{ + unsigned i; + + p->inProcessed = 0; + + p->blockIndex = 1; // it must be larger than not_defined index (0) + p->isAllocError = False; + p->overflow = False; + p->threadingErrorSRes = SZ_OK; + + p->needContinue = True; + + p->readWasFinished = False; + p->needInterrupt = False; + p->interruptIndex = (UInt64)(Int64)-1; + + p->readProcessed = 0; + p->readRes = SZ_OK; + p->codeRes = SZ_OK; + p->wasInterrupted = False; + + p->crossStart = 0; + p->crossEnd = 0; + + p->filledThreadStart = 0; + p->numFilledThreads = 0; + + { + unsigned numThreads = p->numThreadsMax; + if (numThreads > MTDEC_THREADS_MAX) + numThreads = MTDEC_THREADS_MAX; + p->numStartedThreads_Limit = numThreads; + p->numStartedThreads = 0; + } + + if (p->inBufSize != p->allocatedBufsSize) + { + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CMtDecThread *t = &p->threads[i]; + if (t->inBuf) + MtDecThread_FreeInBufs(t); + } + if (p->crossBlock) + { + ISzAlloc_Free(p->alloc, p->crossBlock); + p->crossBlock = NULL; + } + + p->allocatedBufsSize = p->inBufSize; + } + + MtProgress_Init(&p->mtProgress, p->progress); + + // RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent)) + p->exitThread = False; + p->exitThreadWRes = 0; + + { + WRes wres; + SRes sres; + CMtDecThread *nextThread = &p->threads[p->numStartedThreads++]; + // wres = MtDecThread_CreateAndStart(nextThread); + wres = MtDecThread_CreateEvents(nextThread); + if (wres == 0) { wres = Event_Set(&nextThread->canWrite); + if (wres == 0) { wres = Event_Set(&nextThread->canRead); + if (wres == 0) { THREAD_FUNC_RET_TYPE res = MtDec_ThreadFunc(nextThread); + wres = (WRes)(MY_uintptr_t)res; + if (wres != 0) + { + p->needContinue = False; + MtDec_CloseThreads(p); + }}}} + + // wres = 17; // for test + // wres = Event_Wait(&p->finishedEvent); + + sres = MY_SRes_HRESULT_FROM_WRes(wres); + + if (sres != 0) + p->threadingErrorSRes = sres; + + if ( + // wres == 0 + // wres != 0 + // || p->mtc.codeRes == SZ_ERROR_MEM + p->isAllocError + || p->threadingErrorSRes != SZ_OK + || p->overflow) + { + // p->needContinue = True; + } + else + p->needContinue = False; + + if (p->needContinue) + return SZ_OK; + + // if (sres != SZ_OK) + return sres; + // return SZ_ERROR_FAIL; + } +} + +#endif + +#undef PRF diff --git a/C/MtDec.h b/C/MtDec.h index f214b3ab4..c28e8d9ac 100644 --- a/C/MtDec.h +++ b/C/MtDec.h @@ -1,202 +1,202 @@ -/* MtDec.h -- Multi-thread Decoder -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_MT_DEC_H -#define ZIP7_INC_MT_DEC_H - -#include "7zTypes.h" - -#ifndef Z7_ST -#include "Threads.h" -#endif - -EXTERN_C_BEGIN - -#ifndef Z7_ST - -#ifndef Z7_ST - #define MTDEC_THREADS_MAX 32 -#else - #define MTDEC_THREADS_MAX 1 -#endif - - -typedef struct -{ - ICompressProgressPtr progress; - SRes res; - UInt64 totalInSize; - UInt64 totalOutSize; - CCriticalSection cs; -} CMtProgress; - -void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress); -SRes MtProgress_Progress_ST(CMtProgress *p); -SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize); -SRes MtProgress_GetError(CMtProgress *p); -void MtProgress_SetError(CMtProgress *p, SRes res); - -struct CMtDec; - -typedef struct -{ - struct CMtDec_ *mtDec; - unsigned index; - void *inBuf; - - size_t inDataSize_Start; // size of input data in start block - UInt64 inDataSize; // total size of input data in all blocks - - CThread thread; - CAutoResetEvent canRead; - CAutoResetEvent canWrite; - void *allocaPtr; -} CMtDecThread; - -void MtDecThread_FreeInBufs(CMtDecThread *t); - - -typedef enum -{ - MTDEC_PARSE_CONTINUE, // continue this block with more input data - MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread - MTDEC_PARSE_NEW, // new block - MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue) -} EMtDecParseState; - -typedef struct -{ - // in - int startCall; - const Byte *src; - size_t srcSize; - // in : (srcSize == 0) is allowed - // out : it's allowed to return less that actually was used ? - int srcFinished; - - // out - EMtDecParseState state; - BoolInt canCreateNewThread; - UInt64 outPos; // check it (size_t) -} CMtDecCallbackInfo; - - -typedef struct -{ - void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci); - - // PreCode() and Code(): - // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks - SRes (*PreCode)(void *p, unsigned coderIndex); - SRes (*Code)(void *p, unsigned coderIndex, - const Byte *src, size_t srcSize, int srcFinished, - UInt64 *inCodePos, UInt64 *outCodePos, int *stop); - // stop - means stop another Code calls - - - /* Write() must be called, if Parse() was called - set (needWrite) if - { - && (was not interrupted by progress) - && (was not interrupted in previous block) - } - - out: - if (*needContinue), decoder still need to continue decoding with new iteration, - even after MTDEC_PARSE_END - if (*canRecode), we didn't flush current block data, so we still can decode current block later. - */ - SRes (*Write)(void *p, unsigned coderIndex, - BoolInt needWriteToStream, - const Byte *src, size_t srcSize, BoolInt isCross, - // int srcFinished, - BoolInt *needContinue, - BoolInt *canRecode); - -} IMtDecCallback2; - - - -typedef struct CMtDec_ -{ - /* input variables */ - - size_t inBufSize; /* size of input block */ - unsigned numThreadsMax; - // size_t inBlockMax; - unsigned numThreadsMax_2; - - ISeqInStreamPtr inStream; - // const Byte *inData; - // size_t inDataSize; - - ICompressProgressPtr progress; - ISzAllocPtr alloc; - - IMtDecCallback2 *mtCallback; - void *mtCallbackObject; - - - /* internal variables */ - - size_t allocatedBufsSize; - - BoolInt exitThread; - WRes exitThreadWRes; - - UInt64 blockIndex; - BoolInt isAllocError; - BoolInt overflow; - SRes threadingErrorSRes; - - BoolInt needContinue; - - // CAutoResetEvent finishedEvent; - - SRes readRes; - SRes codeRes; - - BoolInt wasInterrupted; - - unsigned numStartedThreads_Limit; - unsigned numStartedThreads; - - Byte *crossBlock; - size_t crossStart; - size_t crossEnd; - UInt64 readProcessed; - BoolInt readWasFinished; - UInt64 inProcessed; - - unsigned filledThreadStart; - unsigned numFilledThreads; - - #ifndef Z7_ST - BoolInt needInterrupt; - UInt64 interruptIndex; - CMtProgress mtProgress; - CMtDecThread threads[MTDEC_THREADS_MAX]; - #endif -} CMtDec; - - -void MtDec_Construct(CMtDec *p); -void MtDec_Destruct(CMtDec *p); - -/* -MtDec_Code() returns: - SZ_OK - in most cases - MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function -*/ - -SRes MtDec_Code(CMtDec *p); -Byte *MtDec_GetCrossBuff(CMtDec *p); - -int MtDec_PrepareRead(CMtDec *p); -const Byte *MtDec_Read(CMtDec *p, size_t *inLim); - -#endif - -EXTERN_C_END - -#endif +/* MtDec.h -- Multi-thread Decoder +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_MT_DEC_H +#define ZIP7_INC_MT_DEC_H + +#include "7zTypes.h" + +#ifndef Z7_ST +#include "Threads.h" +#endif + +EXTERN_C_BEGIN + +#ifndef Z7_ST + +#ifndef Z7_ST + #define MTDEC_THREADS_MAX 32 +#else + #define MTDEC_THREADS_MAX 1 +#endif + + +typedef struct +{ + ICompressProgressPtr progress; + SRes res; + UInt64 totalInSize; + UInt64 totalOutSize; + CCriticalSection cs; +} CMtProgress; + +void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress); +SRes MtProgress_Progress_ST(CMtProgress *p); +SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize); +SRes MtProgress_GetError(CMtProgress *p); +void MtProgress_SetError(CMtProgress *p, SRes res); + +struct CMtDec; + +typedef struct +{ + struct CMtDec_ *mtDec; + unsigned index; + void *inBuf; + + size_t inDataSize_Start; // size of input data in start block + UInt64 inDataSize; // total size of input data in all blocks + + CThread thread; + CAutoResetEvent canRead; + CAutoResetEvent canWrite; + void *allocaPtr; +} CMtDecThread; + +void MtDecThread_FreeInBufs(CMtDecThread *t); + + +typedef enum +{ + MTDEC_PARSE_CONTINUE, // continue this block with more input data + MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread + MTDEC_PARSE_NEW, // new block + MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue) +} EMtDecParseState; + +typedef struct +{ + // in + int startCall; + const Byte *src; + size_t srcSize; + // in : (srcSize == 0) is allowed + // out : it's allowed to return less that actually was used ? + int srcFinished; + + // out + EMtDecParseState state; + BoolInt canCreateNewThread; + UInt64 outPos; // check it (size_t) +} CMtDecCallbackInfo; + + +typedef struct +{ + void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci); + + // PreCode() and Code(): + // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks + SRes (*PreCode)(void *p, unsigned coderIndex); + SRes (*Code)(void *p, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop); + // stop - means stop another Code calls + + + /* Write() must be called, if Parse() was called + set (needWrite) if + { + && (was not interrupted by progress) + && (was not interrupted in previous block) + } + + out: + if (*needContinue), decoder still need to continue decoding with new iteration, + even after MTDEC_PARSE_END + if (*canRecode), we didn't flush current block data, so we still can decode current block later. + */ + SRes (*Write)(void *p, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, BoolInt isCross, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode); + +} IMtDecCallback2; + + + +typedef struct CMtDec_ +{ + /* input variables */ + + size_t inBufSize; /* size of input block */ + unsigned numThreadsMax; + // size_t inBlockMax; + unsigned numThreadsMax_2; + + ISeqInStreamPtr inStream; + // const Byte *inData; + // size_t inDataSize; + + ICompressProgressPtr progress; + ISzAllocPtr alloc; + + IMtDecCallback2 *mtCallback; + void *mtCallbackObject; + + + /* internal variables */ + + size_t allocatedBufsSize; + + BoolInt exitThread; + WRes exitThreadWRes; + + UInt64 blockIndex; + BoolInt isAllocError; + BoolInt overflow; + SRes threadingErrorSRes; + + BoolInt needContinue; + + // CAutoResetEvent finishedEvent; + + SRes readRes; + SRes codeRes; + + BoolInt wasInterrupted; + + unsigned numStartedThreads_Limit; + unsigned numStartedThreads; + + Byte *crossBlock; + size_t crossStart; + size_t crossEnd; + UInt64 readProcessed; + BoolInt readWasFinished; + UInt64 inProcessed; + + unsigned filledThreadStart; + unsigned numFilledThreads; + + #ifndef Z7_ST + BoolInt needInterrupt; + UInt64 interruptIndex; + CMtProgress mtProgress; + CMtDecThread threads[MTDEC_THREADS_MAX]; + #endif +} CMtDec; + + +void MtDec_Construct(CMtDec *p); +void MtDec_Destruct(CMtDec *p); + +/* +MtDec_Code() returns: + SZ_OK - in most cases + MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function +*/ + +SRes MtDec_Code(CMtDec *p); +Byte *MtDec_GetCrossBuff(CMtDec *p); + +int MtDec_PrepareRead(CMtDec *p); +const Byte *MtDec_Read(CMtDec *p, size_t *inLim); + +#endif + +EXTERN_C_END + +#endif diff --git a/C/Ppmd.h b/C/Ppmd.h index da1ed375e..66b26266f 100644 --- a/C/Ppmd.h +++ b/C/Ppmd.h @@ -1,169 +1,169 @@ -/* Ppmd.h -- PPMD codec common code -2023-03-05 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ - -#ifndef ZIP7_INC_PPMD_H -#define ZIP7_INC_PPMD_H - -#include "CpuArch.h" - -EXTERN_C_BEGIN - -#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) -/* - PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block. - if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields. - if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields. - if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed, - if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional, - and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit. - PPMD code works slightly faster in (PPMD_32BIT) mode. -*/ - #define PPMD_32BIT -#endif - -#define PPMD_INT_BITS 7 -#define PPMD_PERIOD_BITS 7 -#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) - -#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) -#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) -#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) -#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) - -#define PPMD_N1 4 -#define PPMD_N2 4 -#define PPMD_N3 4 -#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) -#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) - -MY_CPU_pragma_pack_push_1 -/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ - -/* SEE-contexts for PPM-contexts with masked symbols */ -typedef struct -{ - UInt16 Summ; /* Freq */ - Byte Shift; /* Speed of Freq change; low Shift is for fast change */ - Byte Count; /* Count to next change of Shift */ -} CPpmd_See; - -#define Ppmd_See_UPDATE(p) \ - { if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ - { (p)->Summ = (UInt16)((p)->Summ << 1); \ - (p)->Count = (Byte)(3 << (p)->Shift++); }} - - -typedef struct -{ - Byte Symbol; - Byte Freq; - UInt16 Successor_0; - UInt16 Successor_1; -} CPpmd_State; - -typedef struct CPpmd_State2_ -{ - Byte Symbol; - Byte Freq; -} CPpmd_State2; - -typedef struct CPpmd_State4_ -{ - UInt16 Successor_0; - UInt16 Successor_1; -} CPpmd_State4; - -MY_CPU_pragma_pop - -/* - PPMD code can write full CPpmd_State structure data to CPpmd*_Context - at (byte offset = 2) instead of some fields of original CPpmd*_Context structure. - - If we use pointers to different types, but that point to shared - memory space, we can have aliasing problem (strict aliasing). - - XLC compiler in -O2 mode can change the order of memory write instructions - in relation to read instructions, if we have use pointers to different types. - - To solve that aliasing problem we use combined CPpmd*_Context structure - with unions that contain the fields from both structures: - the original CPpmd*_Context and CPpmd_State. - So we can access the fields from both structures via one pointer, - and the compiler doesn't change the order of write instructions - in relation to read instructions. - - If we don't use memory write instructions to shared memory in - some local code, and we use only reading instructions (read only), - then probably it's safe to use pointers to different types for reading. -*/ - - - -#ifdef PPMD_32BIT - - #define Ppmd_Ref_Type(type) type * - #define Ppmd_GetRef(p, ptr) (ptr) - #define Ppmd_GetPtr(p, ptr) (ptr) - #define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr) - -#else - - #define Ppmd_Ref_Type(type) UInt32 - #define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) - #define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs))) - #define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs)) - -#endif // PPMD_32BIT - - -typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref; -typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref; -typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref; - - -/* -#ifdef MY_CPU_LE_UNALIGN -// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache. -#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0) -#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v) - -#else -*/ - -/* - We can write 16-bit halves to 32-bit (Successor) field in any selected order. - But the native order is more consistent way. - So we use the native order, if LE/BE order can be detected here at compile time. -*/ - -#ifdef MY_CPU_BE - - #define Ppmd_GET_SUCCESSOR(p) \ - ( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) ) - - #define Ppmd_SET_SUCCESSOR(p, v) { \ - (p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \ - (p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); } - -#else - - #define Ppmd_GET_SUCCESSOR(p) \ - ( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) ) - - #define Ppmd_SET_SUCCESSOR(p, v) { \ - (p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \ - (p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); } - -#endif - -// #endif - - -#define PPMD_SetAllBitsIn256Bytes(p) \ - { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ - p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }} - -EXTERN_C_END - -#endif +/* Ppmd.h -- PPMD codec common code +2023-03-05 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#ifndef ZIP7_INC_PPMD_H +#define ZIP7_INC_PPMD_H + +#include "CpuArch.h" + +EXTERN_C_BEGIN + +#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) +/* + PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block. + if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields. + if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields. + if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed, + if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional, + and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit. + PPMD code works slightly faster in (PPMD_32BIT) mode. +*/ + #define PPMD_32BIT +#endif + +#define PPMD_INT_BITS 7 +#define PPMD_PERIOD_BITS 7 +#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) + +#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) +#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) +#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) +#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) + +#define PPMD_N1 4 +#define PPMD_N2 4 +#define PPMD_N3 4 +#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) +#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) + +MY_CPU_pragma_pack_push_1 +/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ + +/* SEE-contexts for PPM-contexts with masked symbols */ +typedef struct +{ + UInt16 Summ; /* Freq */ + Byte Shift; /* Speed of Freq change; low Shift is for fast change */ + Byte Count; /* Count to next change of Shift */ +} CPpmd_See; + +#define Ppmd_See_UPDATE(p) \ + { if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ + { (p)->Summ = (UInt16)((p)->Summ << 1); \ + (p)->Count = (Byte)(3 << (p)->Shift++); }} + + +typedef struct +{ + Byte Symbol; + Byte Freq; + UInt16 Successor_0; + UInt16 Successor_1; +} CPpmd_State; + +typedef struct CPpmd_State2_ +{ + Byte Symbol; + Byte Freq; +} CPpmd_State2; + +typedef struct CPpmd_State4_ +{ + UInt16 Successor_0; + UInt16 Successor_1; +} CPpmd_State4; + +MY_CPU_pragma_pop + +/* + PPMD code can write full CPpmd_State structure data to CPpmd*_Context + at (byte offset = 2) instead of some fields of original CPpmd*_Context structure. + + If we use pointers to different types, but that point to shared + memory space, we can have aliasing problem (strict aliasing). + + XLC compiler in -O2 mode can change the order of memory write instructions + in relation to read instructions, if we have use pointers to different types. + + To solve that aliasing problem we use combined CPpmd*_Context structure + with unions that contain the fields from both structures: + the original CPpmd*_Context and CPpmd_State. + So we can access the fields from both structures via one pointer, + and the compiler doesn't change the order of write instructions + in relation to read instructions. + + If we don't use memory write instructions to shared memory in + some local code, and we use only reading instructions (read only), + then probably it's safe to use pointers to different types for reading. +*/ + + + +#ifdef PPMD_32BIT + + #define Ppmd_Ref_Type(type) type * + #define Ppmd_GetRef(p, ptr) (ptr) + #define Ppmd_GetPtr(p, ptr) (ptr) + #define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr) + +#else + + #define Ppmd_Ref_Type(type) UInt32 + #define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) + #define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs))) + #define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs)) + +#endif // PPMD_32BIT + + +typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref; +typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref; +typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref; + + +/* +#ifdef MY_CPU_LE_UNALIGN +// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache. +#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0) +#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v) + +#else +*/ + +/* + We can write 16-bit halves to 32-bit (Successor) field in any selected order. + But the native order is more consistent way. + So we use the native order, if LE/BE order can be detected here at compile time. +*/ + +#ifdef MY_CPU_BE + + #define Ppmd_GET_SUCCESSOR(p) \ + ( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) ) + + #define Ppmd_SET_SUCCESSOR(p, v) { \ + (p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \ + (p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); } + +#else + + #define Ppmd_GET_SUCCESSOR(p) \ + ( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) ) + + #define Ppmd_SET_SUCCESSOR(p, v) { \ + (p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \ + (p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); } + +#endif + +// #endif + + +#define PPMD_SetAllBitsIn256Bytes(p) \ + { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \ + p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }} + +EXTERN_C_END + +#endif diff --git a/C/Ppmd7.c b/C/Ppmd7.c index 29ff621cd..efcc5d86e 100644 --- a/C/Ppmd7.c +++ b/C/Ppmd7.c @@ -1,1131 +1,1131 @@ -/* Ppmd7.c -- PPMdH codec -2023-09-07 : Igor Pavlov : Public domain -This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ - -#include "Precomp.h" - -#include - -#include "Ppmd7.h" - -/* define PPMD7_ORDER_0_SUPPPORT to suport order-0 mode, unsupported by orignal PPMd var.H. code */ -// #define PPMD7_ORDER_0_SUPPPORT - -MY_ALIGN(16) -static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -MY_ALIGN(16) -static const UInt16 PPMD7_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; - -#define MAX_FREQ 124 -#define UNIT_SIZE 12 - -#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) -#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) -#define I2U(indx) ((unsigned)p->Indx2Units[indx]) -#define I2U_UInt16(indx) ((UInt16)p->Indx2Units[indx]) - -#define REF(ptr) Ppmd_GetRef(p, ptr) - -#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) - -#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) -#define STATS(ctx) Ppmd7_GetStats(p, ctx) -#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) -#define SUFFIX(ctx) CTX((ctx)->Suffix) - -typedef CPpmd7_Context * PPMD7_CTX_PTR; - -struct CPpmd7_Node_; - -typedef Ppmd_Ref_Type(struct CPpmd7_Node_) CPpmd7_Node_Ref; - -typedef struct CPpmd7_Node_ -{ - UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ - UInt16 NU; - CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ - CPpmd7_Node_Ref Prev; -} CPpmd7_Node; - -#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd7_Node) - -void Ppmd7_Construct(CPpmd7 *p) -{ - unsigned i, k, m; - - p->Base = NULL; - - for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) - { - unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); - do { p->Units2Indx[k++] = (Byte)i; } while (--step); - p->Indx2Units[i] = (Byte)k; - } - - p->NS2BSIndx[0] = (0 << 1); - p->NS2BSIndx[1] = (1 << 1); - memset(p->NS2BSIndx + 2, (2 << 1), 9); - memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); - - for (i = 0; i < 3; i++) - p->NS2Indx[i] = (Byte)i; - - for (m = i, k = 1; i < 256; i++) - { - p->NS2Indx[i] = (Byte)m; - if (--k == 0) - k = (++m) - 2; - } - - memcpy(p->ExpEscape, PPMD7_kExpEscape, 16); -} - - -void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->Base); - p->Size = 0; - p->Base = NULL; -} - - -BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc) -{ - if (!p->Base || p->Size != size) - { - Ppmd7_Free(p, alloc); - p->AlignOffset = (4 - size) & 3; - if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) - return False; - p->Size = size; - } - return True; -} - - - -// ---------- Internal Memory Allocator ---------- - -/* We can use CPpmd7_Node in list of free units (as in Ppmd8) - But we still need one additional list walk pass in Ppmd7_GlueFreeBlocks(). - So we use simple CPpmd_Void_Ref instead of CPpmd7_Node in Ppmd7_InsertNode() / Ppmd7_RemoveNode() -*/ - -#define EMPTY_NODE 0 - - -static void Ppmd7_InsertNode(CPpmd7 *p, void *node, unsigned indx) -{ - *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; - // ((CPpmd7_Node *)node)->Next = (CPpmd7_Node_Ref)p->FreeList[indx]; - - p->FreeList[indx] = REF(node); - -} - - -static void *Ppmd7_RemoveNode(CPpmd7 *p, unsigned indx) -{ - CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); - p->FreeList[indx] = *node; - // CPpmd7_Node *node = NODE((CPpmd7_Node_Ref)p->FreeList[indx]); - // p->FreeList[indx] = node->Next; - return node; -} - - -static void Ppmd7_SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) -{ - unsigned i, nu = I2U(oldIndx) - I2U(newIndx); - ptr = (Byte *)ptr + U2B(I2U(newIndx)); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - Ppmd7_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); - } - Ppmd7_InsertNode(p, ptr, i); -} - - -/* we use CPpmd7_Node_Union union to solve XLC -O2 strict pointer aliasing problem */ - -typedef union -{ - CPpmd7_Node Node; - CPpmd7_Node_Ref NextRef; -} CPpmd7_Node_Union; - -/* Original PPmdH (Ppmd7) code uses doubly linked list in Ppmd7_GlueFreeBlocks() - we use single linked list similar to Ppmd8 code */ - - -static void Ppmd7_GlueFreeBlocks(CPpmd7 *p) -{ - /* - we use first UInt16 field of 12-bytes UNITs as record type stamp - CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0 - CPpmd7_Context { UInt16 NumStats; : NumStats != 0 - CPpmd7_Node { UInt16 Stamp : Stamp == 0 for free record - : Stamp == 1 for head record and guard - Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd7_Context record. - */ - CPpmd7_Node_Ref head, n = 0; - - p->GlueCount = 255; - - - /* we set guard NODE at LoUnit */ - if (p->LoUnit != p->HiUnit) - ((CPpmd7_Node *)(void *)p->LoUnit)->Stamp = 1; - - { - /* Create list of free blocks. - We still need one additional list walk pass before Glue. */ - unsigned i; - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - const UInt16 nu = I2U_UInt16(i); - CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; - p->FreeList[i] = 0; - while (next != 0) - { - /* Don't change the order of the following commands: */ - CPpmd7_Node_Union *un = (CPpmd7_Node_Union *)NODE(next); - const CPpmd7_Node_Ref tmp = next; - next = un->NextRef; - un->Node.Stamp = EMPTY_NODE; - un->Node.NU = nu; - un->Node.Next = n; - n = tmp; - } - } - } - - head = n; - /* Glue and Fill must walk the list in same direction */ - { - /* Glue free blocks */ - CPpmd7_Node_Ref *prev = &head; - while (n) - { - CPpmd7_Node *node = NODE(n); - UInt32 nu = node->NU; - n = node->Next; - if (nu == 0) - { - *prev = n; - continue; - } - prev = &node->Next; - for (;;) - { - CPpmd7_Node *node2 = node + nu; - nu += node2->NU; - if (node2->Stamp != EMPTY_NODE || nu >= 0x10000) - break; - node->NU = (UInt16)nu; - node2->NU = 0; - } - } - } - - /* Fill lists of free blocks */ - for (n = head; n != 0;) - { - CPpmd7_Node *node = NODE(n); - UInt32 nu = node->NU; - unsigned i; - n = node->Next; - if (nu == 0) - continue; - for (; nu > 128; nu -= 128, node += 128) - Ppmd7_InsertNode(p, node, PPMD_NUM_INDEXES - 1); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - Ppmd7_InsertNode(p, node + k, (unsigned)nu - k - 1); - } - Ppmd7_InsertNode(p, node, i); - } -} - - -Z7_NO_INLINE -static void *Ppmd7_AllocUnitsRare(CPpmd7 *p, unsigned indx) -{ - unsigned i; - - if (p->GlueCount == 0) - { - Ppmd7_GlueFreeBlocks(p); - if (p->FreeList[indx] != 0) - return Ppmd7_RemoveNode(p, indx); - } - - i = indx; - - do - { - if (++i == PPMD_NUM_INDEXES) - { - UInt32 numBytes = U2B(I2U(indx)); - Byte *us = p->UnitsStart; - p->GlueCount--; - return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : NULL; - } - } - while (p->FreeList[i] == 0); - - { - void *block = Ppmd7_RemoveNode(p, i); - Ppmd7_SplitBlock(p, block, i, indx); - return block; - } -} - - -static void *Ppmd7_AllocUnits(CPpmd7 *p, unsigned indx) -{ - if (p->FreeList[indx] != 0) - return Ppmd7_RemoveNode(p, indx); - { - UInt32 numBytes = U2B(I2U(indx)); - Byte *lo = p->LoUnit; - if ((UInt32)(p->HiUnit - lo) >= numBytes) - { - p->LoUnit = lo + numBytes; - return lo; - } - } - return Ppmd7_AllocUnitsRare(p, indx); -} - - -#define MEM_12_CPY(dest, src, num) \ - { UInt32 *d = (UInt32 *)(dest); \ - const UInt32 *z = (const UInt32 *)(src); \ - unsigned n = (num); \ - do { \ - d[0] = z[0]; \ - d[1] = z[1]; \ - d[2] = z[2]; \ - z += 3; \ - d += 3; \ - } while (--n); \ - } - - -/* -static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) -{ - unsigned i0 = U2I(oldNU); - unsigned i1 = U2I(newNU); - if (i0 == i1) - return oldPtr; - if (p->FreeList[i1] != 0) - { - void *ptr = Ppmd7_RemoveNode(p, i1); - MEM_12_CPY(ptr, oldPtr, newNU) - Ppmd7_InsertNode(p, oldPtr, i0); - return ptr; - } - Ppmd7_SplitBlock(p, oldPtr, i0, i1); - return oldPtr; -} -*/ - - -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) -static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) -{ - Ppmd_SET_SUCCESSOR(p, v) -} - - - -Z7_NO_INLINE -static -void Ppmd7_RestartModel(CPpmd7 *p) -{ - unsigned i, k; - - memset(p->FreeList, 0, sizeof(p->FreeList)); - - p->Text = p->Base + p->AlignOffset; - p->HiUnit = p->Text + p->Size; - p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; - p->GlueCount = 0; - - p->OrderFall = p->MaxOrder; - p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; - p->PrevSuccess = 0; - - { - CPpmd7_Context *mc = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ - CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd7_AllocUnits(p, PPMD_NUM_INDEXES - 1); */ - - p->LoUnit += U2B(256 / 2); - p->MaxContext = p->MinContext = mc; - p->FoundState = s; - - mc->NumStats = 256; - mc->Union2.SummFreq = 256 + 1; - mc->Union4.Stats = REF(s); - mc->Suffix = 0; - - for (i = 0; i < 256; i++, s++) - { - s->Symbol = (Byte)i; - s->Freq = 1; - SetSuccessor(s, 0); - } - - #ifdef PPMD7_ORDER_0_SUPPPORT - if (p->MaxOrder == 0) - { - CPpmd_Void_Ref r = REF(mc); - s = p->FoundState; - for (i = 0; i < 256; i++, s++) - SetSuccessor(s, r); - return; - } - #endif - } - - for (i = 0; i < 128; i++) - - - - for (k = 0; k < 8; k++) - { - unsigned m; - UInt16 *dest = p->BinSumm[i] + k; - const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD7_kInitBinEsc[k] / (i + 2)); - for (m = 0; m < 64; m += 8) - dest[m] = val; - } - - - for (i = 0; i < 25; i++) - { - - CPpmd_See *s = p->See[i]; - - - - unsigned summ = ((5 * i + 10) << (PPMD_PERIOD_BITS - 4)); - for (k = 0; k < 16; k++, s++) - { - s->Summ = (UInt16)summ; - s->Shift = (PPMD_PERIOD_BITS - 4); - s->Count = 4; - } - } - - p->DummySee.Summ = 0; /* unused */ - p->DummySee.Shift = PPMD_PERIOD_BITS; - p->DummySee.Count = 64; /* unused */ -} - - -void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) -{ - p->MaxOrder = maxOrder; - - Ppmd7_RestartModel(p); -} - - - -/* - Ppmd7_CreateSuccessors() - It's called when (FoundState->Successor) is RAW-Successor, - that is the link to position in Raw text. - So we create Context records and write the links to - FoundState->Successor and to identical RAW-Successors in suffix - contexts of MinContex. - - The function returns: - if (OrderFall == 0) then MinContext is already at MAX order, - { return pointer to new or existing context of same MAX order } - else - { return pointer to new real context that will be (Order+1) in comparison with MinContext - - also it can return pointer to real context of same order, -*/ - -Z7_NO_INLINE -static PPMD7_CTX_PTR Ppmd7_CreateSuccessors(CPpmd7 *p) -{ - PPMD7_CTX_PTR c = p->MinContext; - CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); - Byte newSym, newFreq; - unsigned numPs = 0; - CPpmd_State *ps[PPMD7_MAX_ORDER]; - - if (p->OrderFall != 0) - ps[numPs++] = p->FoundState; - - while (c->Suffix) - { - CPpmd_Void_Ref successor; - CPpmd_State *s; - c = SUFFIX(c); - - - if (c->NumStats != 1) - { - Byte sym = p->FoundState->Symbol; - for (s = STATS(c); s->Symbol != sym; s++); - - } - else - { - s = ONE_STATE(c); - - } - successor = SUCCESSOR(s); - if (successor != upBranch) - { - // (c) is real record Context here, - c = CTX(successor); - if (numPs == 0) - { - // (c) is real record MAX Order Context here, - // So we don't need to create any new contexts. - return c; - } - break; - } - ps[numPs++] = s; - } - - // All created contexts will have single-symbol with new RAW-Successor - // All new RAW-Successors will point to next position in RAW text - // after FoundState->Successor - - newSym = *(const Byte *)Ppmd7_GetPtr(p, upBranch); - upBranch++; - - - if (c->NumStats == 1) - newFreq = ONE_STATE(c)->Freq; - else - { - UInt32 cf, s0; - CPpmd_State *s; - for (s = STATS(c); s->Symbol != newSym; s++); - cf = (UInt32)s->Freq - 1; - s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; - /* - cf - is frequency of symbol that will be Successor in new context records. - s0 - is commulative frequency sum of another symbols from parent context. - max(newFreq)= (s->Freq + 1), when (s0 == 1) - we have requirement (Ppmd7Context_OneState()->Freq <= 128) in BinSumm[] - so (s->Freq < 128) - is requirement for multi-symbol contexts - */ - newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : (2 * cf + s0 - 1) / (2 * s0) + 1)); - } - - // Create new single-symbol contexts from low order to high order in loop - - do - { - PPMD7_CTX_PTR c1; - /* = AllocContext(p); */ - if (p->HiUnit != p->LoUnit) - c1 = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); - else if (p->FreeList[0] != 0) - c1 = (PPMD7_CTX_PTR)Ppmd7_RemoveNode(p, 0); - else - { - c1 = (PPMD7_CTX_PTR)Ppmd7_AllocUnitsRare(p, 0); - if (!c1) - return NULL; - } - - c1->NumStats = 1; - ONE_STATE(c1)->Symbol = newSym; - ONE_STATE(c1)->Freq = newFreq; - SetSuccessor(ONE_STATE(c1), upBranch); - c1->Suffix = REF(c); - SetSuccessor(ps[--numPs], REF(c1)); - c = c1; - } - while (numPs != 0); - - return c; -} - - - -#define SWAP_STATES(s) \ - { CPpmd_State tmp = s[0]; s[0] = s[-1]; s[-1] = tmp; } - - -void Ppmd7_UpdateModel(CPpmd7 *p); -Z7_NO_INLINE -void Ppmd7_UpdateModel(CPpmd7 *p) -{ - CPpmd_Void_Ref maxSuccessor, minSuccessor; - PPMD7_CTX_PTR c, mc; - unsigned s0, ns; - - - - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) - { - /* Update Freqs in Suffix Context */ - - c = SUFFIX(p->MinContext); - - if (c->NumStats == 1) - { - CPpmd_State *s = ONE_STATE(c); - if (s->Freq < 32) - s->Freq++; - } - else - { - CPpmd_State *s = STATS(c); - Byte sym = p->FoundState->Symbol; - - if (s->Symbol != sym) - { - do - { - // s++; if (s->Symbol == sym) break; - s++; - } - while (s->Symbol != sym); - - if (s[0].Freq >= s[-1].Freq) - { - SWAP_STATES(s) - s--; - } - } - - if (s->Freq < MAX_FREQ - 9) - { - s->Freq = (Byte)(s->Freq + 2); - c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); - } - } - } - - - if (p->OrderFall == 0) - { - /* MAX ORDER context */ - /* (FoundState->Successor) is RAW-Successor. */ - p->MaxContext = p->MinContext = Ppmd7_CreateSuccessors(p); - if (!p->MinContext) - { - Ppmd7_RestartModel(p); - return; - } - SetSuccessor(p->FoundState, REF(p->MinContext)); - return; - } - - - /* NON-MAX ORDER context */ - - { - Byte *text = p->Text; - *text++ = p->FoundState->Symbol; - p->Text = text; - if (text >= p->UnitsStart) - { - Ppmd7_RestartModel(p); - return; - } - maxSuccessor = REF(text); - } - - minSuccessor = SUCCESSOR(p->FoundState); - - if (minSuccessor) - { - // there is Successor for FoundState in MinContext. - // So the next context will be one order higher than MinContext. - - if (minSuccessor <= maxSuccessor) - { - // minSuccessor is RAW-Successor. So we will create real contexts records: - PPMD7_CTX_PTR cs = Ppmd7_CreateSuccessors(p); - if (!cs) - { - Ppmd7_RestartModel(p); - return; - } - minSuccessor = REF(cs); - } - - // minSuccessor now is real Context pointer that points to existing (Order+1) context - - if (--p->OrderFall == 0) - { - /* - if we move to MaxOrder context, then minSuccessor will be common Succesor for both: - MinContext that is (MaxOrder - 1) - MaxContext that is (MaxOrder) - so we don't need new RAW-Successor, and we can use real minSuccessor - as succssors for both MinContext and MaxContext. - */ - maxSuccessor = minSuccessor; - - /* - if (MaxContext != MinContext) - { - there was order fall from MaxOrder and we don't need current symbol - to transfer some RAW-Succesors to real contexts. - So we roll back pointer in raw data for one position. - } - */ - p->Text -= (p->MaxContext != p->MinContext); - } - } - else - { - /* - FoundState has NULL-Successor here. - And only root 0-order context can contain NULL-Successors. - We change Successor in FoundState to RAW-Successor, - And next context will be same 0-order root Context. - */ - SetSuccessor(p->FoundState, maxSuccessor); - minSuccessor = REF(p->MinContext); - } - - mc = p->MinContext; - c = p->MaxContext; - - p->MaxContext = p->MinContext = CTX(minSuccessor); - - if (c == mc) - return; - - // s0 : is pure Escape Freq - s0 = mc->Union2.SummFreq - (ns = mc->NumStats) - ((unsigned)p->FoundState->Freq - 1); - - do - { - unsigned ns1; - UInt32 sum; - - if ((ns1 = c->NumStats) != 1) - { - if ((ns1 & 1) == 0) - { - /* Expand for one UNIT */ - const unsigned oldNU = ns1 >> 1; - const unsigned i = U2I(oldNU); - if (i != U2I((size_t)oldNU + 1)) - { - void *ptr = Ppmd7_AllocUnits(p, i + 1); - void *oldPtr; - if (!ptr) - { - Ppmd7_RestartModel(p); - return; - } - oldPtr = STATS(c); - MEM_12_CPY(ptr, oldPtr, oldNU) - Ppmd7_InsertNode(p, oldPtr, i); - c->Union4.Stats = STATS_REF(ptr); - } - } - sum = c->Union2.SummFreq; - /* max increase of Escape_Freq is 3 here. - total increase of Union2.SummFreq for all symbols is less than 256 here */ - sum += (UInt32)(unsigned)((2 * ns1 < ns) + 2 * ((unsigned)(4 * ns1 <= ns) & (sum <= 8 * ns1))); - /* original PPMdH uses 16-bit variable for (sum) here. - But (sum < 0x9000). So we don't truncate (sum) to 16-bit */ - // sum = (UInt16)sum; - } - else - { - // instead of One-symbol context we create 2-symbol context - CPpmd_State *s = (CPpmd_State*)Ppmd7_AllocUnits(p, 0); - if (!s) - { - Ppmd7_RestartModel(p); - return; - } - { - unsigned freq = c->Union2.State2.Freq; - // s = *ONE_STATE(c); - s->Symbol = c->Union2.State2.Symbol; - s->Successor_0 = c->Union4.State4.Successor_0; - s->Successor_1 = c->Union4.State4.Successor_1; - // SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of - // (Successor_0 and Successor_1) in LE/BE. - c->Union4.Stats = REF(s); - if (freq < MAX_FREQ / 4 - 1) - freq <<= 1; - else - freq = MAX_FREQ - 4; - // (max(s->freq) == 120), when we convert from 1-symbol into 2-symbol context - s->Freq = (Byte)freq; - // max(InitEsc = PPMD7_kExpEscape[*]) is 25. So the max(escapeFreq) is 26 here - sum = (UInt32)(freq + p->InitEsc + (ns > 3)); - } - } - - { - CPpmd_State *s = STATS(c) + ns1; - UInt32 cf = 2 * (sum + 6) * (UInt32)p->FoundState->Freq; - UInt32 sf = (UInt32)s0 + sum; - s->Symbol = p->FoundState->Symbol; - c->NumStats = (UInt16)(ns1 + 1); - SetSuccessor(s, maxSuccessor); - - if (cf < 6 * sf) - { - cf = (UInt32)1 + (cf > sf) + (cf >= 4 * sf); - sum += 3; - /* It can add (0, 1, 2) to Escape_Freq */ - } - else - { - cf = (UInt32)4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); - sum += cf; - } - - c->Union2.SummFreq = (UInt16)sum; - s->Freq = (Byte)cf; - } - c = SUFFIX(c); - } - while (c != mc); -} - - - -Z7_NO_INLINE -static void Ppmd7_Rescale(CPpmd7 *p) -{ - unsigned i, adder, sumFreq, escFreq; - CPpmd_State *stats = STATS(p->MinContext); - CPpmd_State *s = p->FoundState; - - /* Sort the list by Freq */ - if (s != stats) - { - CPpmd_State tmp = *s; - do - s[0] = s[-1]; - while (--s != stats); - *s = tmp; - } - - sumFreq = s->Freq; - escFreq = p->MinContext->Union2.SummFreq - sumFreq; - - /* - if (p->OrderFall == 0), adder = 0 : it's allowed to remove symbol from MAX Order context - if (p->OrderFall != 0), adder = 1 : it's NOT allowed to remove symbol from NON-MAX Order context - */ - - adder = (p->OrderFall != 0); - - #ifdef PPMD7_ORDER_0_SUPPPORT - adder |= (p->MaxOrder == 0); // we don't remove symbols from order-0 context - #endif - - sumFreq = (sumFreq + 4 + adder) >> 1; - i = (unsigned)p->MinContext->NumStats - 1; - s->Freq = (Byte)sumFreq; - - do - { - unsigned freq = (++s)->Freq; - escFreq -= freq; - freq = (freq + adder) >> 1; - sumFreq += freq; - s->Freq = (Byte)freq; - if (freq > s[-1].Freq) - { - CPpmd_State tmp = *s; - CPpmd_State *s1 = s; - do - { - s1[0] = s1[-1]; - } - while (--s1 != stats && freq > s1[-1].Freq); - *s1 = tmp; - } - } - while (--i); - - if (s->Freq == 0) - { - /* Remove all items with Freq == 0 */ - CPpmd7_Context *mc; - unsigned numStats, numStatsNew, n0, n1; - - i = 0; do { i++; } while ((--s)->Freq == 0); - - /* We increase (escFreq) for the number of removed symbols. - So we will have (0.5) increase for Escape_Freq in avarage per - removed symbol after Escape_Freq halving */ - escFreq += i; - mc = p->MinContext; - numStats = mc->NumStats; - numStatsNew = numStats - i; - mc->NumStats = (UInt16)(numStatsNew); - n0 = (numStats + 1) >> 1; - - if (numStatsNew == 1) - { - /* Create Single-Symbol context */ - unsigned freq = stats->Freq; - - do - { - escFreq >>= 1; - freq = (freq + 1) >> 1; - } - while (escFreq > 1); - - s = ONE_STATE(mc); - *s = *stats; - s->Freq = (Byte)freq; // (freq <= 260 / 4) - p->FoundState = s; - Ppmd7_InsertNode(p, stats, U2I(n0)); - return; - } - - n1 = (numStatsNew + 1) >> 1; - if (n0 != n1) - { - // p->MinContext->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); - unsigned i0 = U2I(n0); - unsigned i1 = U2I(n1); - if (i0 != i1) - { - if (p->FreeList[i1] != 0) - { - void *ptr = Ppmd7_RemoveNode(p, i1); - p->MinContext->Union4.Stats = STATS_REF(ptr); - MEM_12_CPY(ptr, (const void *)stats, n1) - Ppmd7_InsertNode(p, stats, i0); - } - else - Ppmd7_SplitBlock(p, stats, i0, i1); - } - } - } - { - CPpmd7_Context *mc = p->MinContext; - mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); - // Escape_Freq halving here - p->FoundState = STATS(mc); - } -} - - -CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) -{ - CPpmd_See *see; - const CPpmd7_Context *mc = p->MinContext; - unsigned numStats = mc->NumStats; - if (numStats != 256) - { - unsigned nonMasked = numStats - numMasked; - see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] - + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - numStats) - + 2 * (unsigned)(mc->Union2.SummFreq < 11 * numStats) - + 4 * (unsigned)(numMasked > nonMasked) + - p->HiBitsFlag; - { - // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ - const unsigned summ = (UInt16)see->Summ; // & 0xFFFF - const unsigned r = (summ >> see->Shift); - see->Summ = (UInt16)(summ - r); - *escFreq = (UInt32)(r + (r == 0)); - } - } - else - { - see = &p->DummySee; - *escFreq = 1; - } - return see; -} - - -static void Ppmd7_NextContext(CPpmd7 *p) -{ - PPMD7_CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); - if (p->OrderFall == 0 && (const Byte *)c > p->Text) - p->MaxContext = p->MinContext = c; - else - Ppmd7_UpdateModel(p); -} - - -void Ppmd7_Update1(CPpmd7 *p) -{ - CPpmd_State *s = p->FoundState; - unsigned freq = s->Freq; - freq += 4; - p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); - s->Freq = (Byte)freq; - if (freq > s[-1].Freq) - { - SWAP_STATES(s) - p->FoundState = --s; - if (freq > MAX_FREQ) - Ppmd7_Rescale(p); - } - Ppmd7_NextContext(p); -} - - -void Ppmd7_Update1_0(CPpmd7 *p) -{ - CPpmd_State *s = p->FoundState; - CPpmd7_Context *mc = p->MinContext; - unsigned freq = s->Freq; - const unsigned summFreq = mc->Union2.SummFreq; - p->PrevSuccess = (2 * freq > summFreq); - p->RunLength += (Int32)p->PrevSuccess; - mc->Union2.SummFreq = (UInt16)(summFreq + 4); - freq += 4; - s->Freq = (Byte)freq; - if (freq > MAX_FREQ) - Ppmd7_Rescale(p); - Ppmd7_NextContext(p); -} - - -/* -void Ppmd7_UpdateBin(CPpmd7 *p) -{ - unsigned freq = p->FoundState->Freq; - p->FoundState->Freq = (Byte)(freq + (freq < 128)); - p->PrevSuccess = 1; - p->RunLength++; - Ppmd7_NextContext(p); -} -*/ - -void Ppmd7_Update2(CPpmd7 *p) -{ - CPpmd_State *s = p->FoundState; - unsigned freq = s->Freq; - freq += 4; - p->RunLength = p->InitRL; - p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); - s->Freq = (Byte)freq; - if (freq > MAX_FREQ) - Ppmd7_Rescale(p); - Ppmd7_UpdateModel(p); -} - - - -/* -PPMd Memory Map: -{ - [ 0 ] contains subset of original raw text, that is required to create context - records, Some symbols are not written, when max order context was reached - [ Text ] free area - [ UnitsStart ] CPpmd_State vectors and CPpmd7_Context records - [ LoUnit ] free area for CPpmd_State and CPpmd7_Context items -[ HiUnit ] CPpmd7_Context records - [ Size ] end of array -} - -These addresses don't cross at any time. -And the following condtions is true for addresses: - (0 <= Text < UnitsStart <= LoUnit <= HiUnit <= Size) - -Raw text is BYTE--aligned. -the data in block [ UnitsStart ... Size ] contains 12-bytes aligned UNITs. - -Last UNIT of array at offset (Size - 12) is root order-0 CPpmd7_Context record. -The code can free UNITs memory blocks that were allocated to store CPpmd_State vectors. -The code doesn't free UNITs allocated for CPpmd7_Context records. - -The code calls Ppmd7_RestartModel(), when there is no free memory for allocation. -And Ppmd7_RestartModel() changes the state to orignal start state, with full free block. - - -The code allocates UNITs with the following order: - -Allocation of 1 UNIT for Context record - - from free space (HiUnit) down to (LoUnit) - - from FreeList[0] - - Ppmd7_AllocUnitsRare() - -Ppmd7_AllocUnits() for CPpmd_State vectors: - - from FreeList[i] - - from free space (LoUnit) up to (HiUnit) - - Ppmd7_AllocUnitsRare() - -Ppmd7_AllocUnitsRare() - - if (GlueCount == 0) - { Glue lists, GlueCount = 255, allocate from FreeList[i]] } - - loop for all higher sized FreeList[...] lists - - from (UnitsStart - Text), GlueCount-- - - ERROR - - -Each Record with Context contains the CPpmd_State vector, where each -CPpmd_State contains the link to Successor. -There are 3 types of Successor: - 1) NULL-Successor - NULL pointer. NULL-Successor links can be stored - only in 0-order Root Context Record. - We use 0 value as NULL-Successor - 2) RAW-Successor - the link to position in raw text, - that "RAW-Successor" is being created after first - occurrence of new symbol for some existing context record. - (RAW-Successor > 0). - 3) RECORD-Successor - the link to CPpmd7_Context record of (Order+1), - that record is being created when we go via RAW-Successor again. - -For any successors at any time: the following condtions are true for Successor links: -(NULL-Successor < RAW-Successor < UnitsStart <= RECORD-Successor) - - ----------- Symbol Frequency, SummFreq and Range in Range_Coder ---------- - -CPpmd7_Context::SummFreq = Sum(Stats[].Freq) + Escape_Freq - -The PPMd code tries to fulfill the condition: - (SummFreq <= (256 * 128 = RC::kBot)) - -We have (Sum(Stats[].Freq) <= 256 * 124), because of (MAX_FREQ = 124) -So (4 = 128 - 124) is average reserve for Escape_Freq for each symbol. -If (CPpmd_State::Freq) is not aligned for 4, the reserve can be 5, 6 or 7. -SummFreq and Escape_Freq can be changed in Ppmd7_Rescale() and *Update*() functions. -Ppmd7_Rescale() can remove symbols only from max-order contexts. So Escape_Freq can increase after multiple calls of Ppmd7_Rescale() for -max-order context. - -When the PPMd code still break (Total <= RC::Range) condition in range coder, -we have two ways to resolve that problem: - 1) we can report error, if we want to keep compatibility with original PPMd code that has no fix for such cases. - 2) we can reduce (Total) value to (RC::Range) by reducing (Escape_Freq) part of (Total) value. -*/ - -#undef MAX_FREQ -#undef UNIT_SIZE -#undef U2B -#undef U2I -#undef I2U -#undef I2U_UInt16 -#undef REF -#undef STATS_REF -#undef CTX -#undef STATS -#undef ONE_STATE -#undef SUFFIX -#undef NODE -#undef EMPTY_NODE -#undef MEM_12_CPY -#undef SUCCESSOR -#undef SWAP_STATES +/* Ppmd7.c -- PPMdH codec +2023-09-07 : Igor Pavlov : Public domain +This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd7.h" + +/* define PPMD7_ORDER_0_SUPPPORT to suport order-0 mode, unsupported by orignal PPMd var.H. code */ +// #define PPMD7_ORDER_0_SUPPPORT + +MY_ALIGN(16) +static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +MY_ALIGN(16) +static const UInt16 PPMD7_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) +#define I2U(indx) ((unsigned)p->Indx2Units[indx]) +#define I2U_UInt16(indx) ((UInt16)p->Indx2Units[indx]) + +#define REF(ptr) Ppmd_GetRef(p, ptr) + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define STATS(ctx) Ppmd7_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd7_Context * PPMD7_CTX_PTR; + +struct CPpmd7_Node_; + +typedef Ppmd_Ref_Type(struct CPpmd7_Node_) CPpmd7_Node_Ref; + +typedef struct CPpmd7_Node_ +{ + UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ + UInt16 NU; + CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ + CPpmd7_Node_Ref Prev; +} CPpmd7_Node; + +#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd7_Node) + +void Ppmd7_Construct(CPpmd7 *p) +{ + unsigned i, k, m; + + p->Base = NULL; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 3; i++) + p->NS2Indx[i] = (Byte)i; + + for (m = i, k = 1; i < 256; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 2; + } + + memcpy(p->ExpEscape, PPMD7_kExpEscape, 16); +} + + +void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Base); + p->Size = 0; + p->Base = NULL; +} + + +BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc) +{ + if (!p->Base || p->Size != size) + { + Ppmd7_Free(p, alloc); + p->AlignOffset = (4 - size) & 3; + if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) + return False; + p->Size = size; + } + return True; +} + + + +// ---------- Internal Memory Allocator ---------- + +/* We can use CPpmd7_Node in list of free units (as in Ppmd8) + But we still need one additional list walk pass in Ppmd7_GlueFreeBlocks(). + So we use simple CPpmd_Void_Ref instead of CPpmd7_Node in Ppmd7_InsertNode() / Ppmd7_RemoveNode() +*/ + +#define EMPTY_NODE 0 + + +static void Ppmd7_InsertNode(CPpmd7 *p, void *node, unsigned indx) +{ + *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; + // ((CPpmd7_Node *)node)->Next = (CPpmd7_Node_Ref)p->FreeList[indx]; + + p->FreeList[indx] = REF(node); + +} + + +static void *Ppmd7_RemoveNode(CPpmd7 *p, unsigned indx) +{ + CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); + p->FreeList[indx] = *node; + // CPpmd7_Node *node = NODE((CPpmd7_Node_Ref)p->FreeList[indx]); + // p->FreeList[indx] = node->Next; + return node; +} + + +static void Ppmd7_SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + Ppmd7_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + Ppmd7_InsertNode(p, ptr, i); +} + + +/* we use CPpmd7_Node_Union union to solve XLC -O2 strict pointer aliasing problem */ + +typedef union +{ + CPpmd7_Node Node; + CPpmd7_Node_Ref NextRef; +} CPpmd7_Node_Union; + +/* Original PPmdH (Ppmd7) code uses doubly linked list in Ppmd7_GlueFreeBlocks() + we use single linked list similar to Ppmd8 code */ + + +static void Ppmd7_GlueFreeBlocks(CPpmd7 *p) +{ + /* + we use first UInt16 field of 12-bytes UNITs as record type stamp + CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0 + CPpmd7_Context { UInt16 NumStats; : NumStats != 0 + CPpmd7_Node { UInt16 Stamp : Stamp == 0 for free record + : Stamp == 1 for head record and guard + Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd7_Context record. + */ + CPpmd7_Node_Ref head, n = 0; + + p->GlueCount = 255; + + + /* we set guard NODE at LoUnit */ + if (p->LoUnit != p->HiUnit) + ((CPpmd7_Node *)(void *)p->LoUnit)->Stamp = 1; + + { + /* Create list of free blocks. + We still need one additional list walk pass before Glue. */ + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + const UInt16 nu = I2U_UInt16(i); + CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + /* Don't change the order of the following commands: */ + CPpmd7_Node_Union *un = (CPpmd7_Node_Union *)NODE(next); + const CPpmd7_Node_Ref tmp = next; + next = un->NextRef; + un->Node.Stamp = EMPTY_NODE; + un->Node.NU = nu; + un->Node.Next = n; + n = tmp; + } + } + } + + head = n; + /* Glue and Fill must walk the list in same direction */ + { + /* Glue free blocks */ + CPpmd7_Node_Ref *prev = &head; + while (n) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = node->NU; + n = node->Next; + if (nu == 0) + { + *prev = n; + continue; + } + prev = &node->Next; + for (;;) + { + CPpmd7_Node *node2 = node + nu; + nu += node2->NU; + if (node2->Stamp != EMPTY_NODE || nu >= 0x10000) + break; + node->NU = (UInt16)nu; + node2->NU = 0; + } + } + } + + /* Fill lists of free blocks */ + for (n = head; n != 0;) + { + CPpmd7_Node *node = NODE(n); + UInt32 nu = node->NU; + unsigned i; + n = node->Next; + if (nu == 0) + continue; + for (; nu > 128; nu -= 128, node += 128) + Ppmd7_InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + Ppmd7_InsertNode(p, node + k, (unsigned)nu - k - 1); + } + Ppmd7_InsertNode(p, node, i); + } +} + + +Z7_NO_INLINE +static void *Ppmd7_AllocUnitsRare(CPpmd7 *p, unsigned indx) +{ + unsigned i; + + if (p->GlueCount == 0) + { + Ppmd7_GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return Ppmd7_RemoveNode(p, indx); + } + + i = indx; + + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + Byte *us = p->UnitsStart; + p->GlueCount--; + return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : NULL; + } + } + while (p->FreeList[i] == 0); + + { + void *block = Ppmd7_RemoveNode(p, i); + Ppmd7_SplitBlock(p, block, i, indx); + return block; + } +} + + +static void *Ppmd7_AllocUnits(CPpmd7 *p, unsigned indx) +{ + if (p->FreeList[indx] != 0) + return Ppmd7_RemoveNode(p, indx); + { + UInt32 numBytes = U2B(I2U(indx)); + Byte *lo = p->LoUnit; + if ((UInt32)(p->HiUnit - lo) >= numBytes) + { + p->LoUnit = lo + numBytes; + return lo; + } + } + return Ppmd7_AllocUnitsRare(p, indx); +} + + +#define MEM_12_CPY(dest, src, num) \ + { UInt32 *d = (UInt32 *)(dest); \ + const UInt32 *z = (const UInt32 *)(src); \ + unsigned n = (num); \ + do { \ + d[0] = z[0]; \ + d[1] = z[1]; \ + d[2] = z[2]; \ + z += 3; \ + d += 3; \ + } while (--n); \ + } + + +/* +static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = Ppmd7_RemoveNode(p, i1); + MEM_12_CPY(ptr, oldPtr, newNU) + Ppmd7_InsertNode(p, oldPtr, i0); + return ptr; + } + Ppmd7_SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} +*/ + + +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) +static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + Ppmd_SET_SUCCESSOR(p, v) +} + + + +Z7_NO_INLINE +static +void Ppmd7_RestartModel(CPpmd7 *p) +{ + unsigned i, k; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + + p->Text = p->Base + p->AlignOffset; + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + { + CPpmd7_Context *mc = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd7_AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + + p->LoUnit += U2B(256 / 2); + p->MaxContext = p->MinContext = mc; + p->FoundState = s; + + mc->NumStats = 256; + mc->Union2.SummFreq = 256 + 1; + mc->Union4.Stats = REF(s); + mc->Suffix = 0; + + for (i = 0; i < 256; i++, s++) + { + s->Symbol = (Byte)i; + s->Freq = 1; + SetSuccessor(s, 0); + } + + #ifdef PPMD7_ORDER_0_SUPPPORT + if (p->MaxOrder == 0) + { + CPpmd_Void_Ref r = REF(mc); + s = p->FoundState; + for (i = 0; i < 256; i++, s++) + SetSuccessor(s, r); + return; + } + #endif + } + + for (i = 0; i < 128; i++) + + + + for (k = 0; k < 8; k++) + { + unsigned m; + UInt16 *dest = p->BinSumm[i] + k; + const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD7_kInitBinEsc[k] / (i + 2)); + for (m = 0; m < 64; m += 8) + dest[m] = val; + } + + + for (i = 0; i < 25; i++) + { + + CPpmd_See *s = p->See[i]; + + + + unsigned summ = ((5 * i + 10) << (PPMD_PERIOD_BITS - 4)); + for (k = 0; k < 16; k++, s++) + { + s->Summ = (UInt16)summ; + s->Shift = (PPMD_PERIOD_BITS - 4); + s->Count = 4; + } + } + + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Count = 64; /* unused */ +} + + +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) +{ + p->MaxOrder = maxOrder; + + Ppmd7_RestartModel(p); +} + + + +/* + Ppmd7_CreateSuccessors() + It's called when (FoundState->Successor) is RAW-Successor, + that is the link to position in Raw text. + So we create Context records and write the links to + FoundState->Successor and to identical RAW-Successors in suffix + contexts of MinContex. + + The function returns: + if (OrderFall == 0) then MinContext is already at MAX order, + { return pointer to new or existing context of same MAX order } + else + { return pointer to new real context that will be (Order+1) in comparison with MinContext + + also it can return pointer to real context of same order, +*/ + +Z7_NO_INLINE +static PPMD7_CTX_PTR Ppmd7_CreateSuccessors(CPpmd7 *p) +{ + PPMD7_CTX_PTR c = p->MinContext; + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + Byte newSym, newFreq; + unsigned numPs = 0; + CPpmd_State *ps[PPMD7_MAX_ORDER]; + + if (p->OrderFall != 0) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + + + if (c->NumStats != 1) + { + Byte sym = p->FoundState->Symbol; + for (s = STATS(c); s->Symbol != sym; s++); + + } + else + { + s = ONE_STATE(c); + + } + successor = SUCCESSOR(s); + if (successor != upBranch) + { + // (c) is real record Context here, + c = CTX(successor); + if (numPs == 0) + { + // (c) is real record MAX Order Context here, + // So we don't need to create any new contexts. + return c; + } + break; + } + ps[numPs++] = s; + } + + // All created contexts will have single-symbol with new RAW-Successor + // All new RAW-Successors will point to next position in RAW text + // after FoundState->Successor + + newSym = *(const Byte *)Ppmd7_GetPtr(p, upBranch); + upBranch++; + + + if (c->NumStats == 1) + newFreq = ONE_STATE(c)->Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != newSym; s++); + cf = (UInt32)s->Freq - 1; + s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; + /* + cf - is frequency of symbol that will be Successor in new context records. + s0 - is commulative frequency sum of another symbols from parent context. + max(newFreq)= (s->Freq + 1), when (s0 == 1) + we have requirement (Ppmd7Context_OneState()->Freq <= 128) in BinSumm[] + so (s->Freq < 128) - is requirement for multi-symbol contexts + */ + newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : (2 * cf + s0 - 1) / (2 * s0) + 1)); + } + + // Create new single-symbol contexts from low order to high order in loop + + do + { + PPMD7_CTX_PTR c1; + /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (PPMD7_CTX_PTR)Ppmd7_RemoveNode(p, 0); + else + { + c1 = (PPMD7_CTX_PTR)Ppmd7_AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + + c1->NumStats = 1; + ONE_STATE(c1)->Symbol = newSym; + ONE_STATE(c1)->Freq = newFreq; + SetSuccessor(ONE_STATE(c1), upBranch); + c1->Suffix = REF(c); + SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + + + +#define SWAP_STATES(s) \ + { CPpmd_State tmp = s[0]; s[0] = s[-1]; s[-1] = tmp; } + + +void Ppmd7_UpdateModel(CPpmd7 *p); +Z7_NO_INLINE +void Ppmd7_UpdateModel(CPpmd7 *p) +{ + CPpmd_Void_Ref maxSuccessor, minSuccessor; + PPMD7_CTX_PTR c, mc; + unsigned s0, ns; + + + + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + /* Update Freqs in Suffix Context */ + + c = SUFFIX(p->MinContext); + + if (c->NumStats == 1) + { + CPpmd_State *s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + CPpmd_State *s = STATS(c); + Byte sym = p->FoundState->Symbol; + + if (s->Symbol != sym) + { + do + { + // s++; if (s->Symbol == sym) break; + s++; + } + while (s->Symbol != sym); + + if (s[0].Freq >= s[-1].Freq) + { + SWAP_STATES(s) + s--; + } + } + + if (s->Freq < MAX_FREQ - 9) + { + s->Freq = (Byte)(s->Freq + 2); + c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); + } + } + } + + + if (p->OrderFall == 0) + { + /* MAX ORDER context */ + /* (FoundState->Successor) is RAW-Successor. */ + p->MaxContext = p->MinContext = Ppmd7_CreateSuccessors(p); + if (!p->MinContext) + { + Ppmd7_RestartModel(p); + return; + } + SetSuccessor(p->FoundState, REF(p->MinContext)); + return; + } + + + /* NON-MAX ORDER context */ + + { + Byte *text = p->Text; + *text++ = p->FoundState->Symbol; + p->Text = text; + if (text >= p->UnitsStart) + { + Ppmd7_RestartModel(p); + return; + } + maxSuccessor = REF(text); + } + + minSuccessor = SUCCESSOR(p->FoundState); + + if (minSuccessor) + { + // there is Successor for FoundState in MinContext. + // So the next context will be one order higher than MinContext. + + if (minSuccessor <= maxSuccessor) + { + // minSuccessor is RAW-Successor. So we will create real contexts records: + PPMD7_CTX_PTR cs = Ppmd7_CreateSuccessors(p); + if (!cs) + { + Ppmd7_RestartModel(p); + return; + } + minSuccessor = REF(cs); + } + + // minSuccessor now is real Context pointer that points to existing (Order+1) context + + if (--p->OrderFall == 0) + { + /* + if we move to MaxOrder context, then minSuccessor will be common Succesor for both: + MinContext that is (MaxOrder - 1) + MaxContext that is (MaxOrder) + so we don't need new RAW-Successor, and we can use real minSuccessor + as succssors for both MinContext and MaxContext. + */ + maxSuccessor = minSuccessor; + + /* + if (MaxContext != MinContext) + { + there was order fall from MaxOrder and we don't need current symbol + to transfer some RAW-Succesors to real contexts. + So we roll back pointer in raw data for one position. + } + */ + p->Text -= (p->MaxContext != p->MinContext); + } + } + else + { + /* + FoundState has NULL-Successor here. + And only root 0-order context can contain NULL-Successors. + We change Successor in FoundState to RAW-Successor, + And next context will be same 0-order root Context. + */ + SetSuccessor(p->FoundState, maxSuccessor); + minSuccessor = REF(p->MinContext); + } + + mc = p->MinContext; + c = p->MaxContext; + + p->MaxContext = p->MinContext = CTX(minSuccessor); + + if (c == mc) + return; + + // s0 : is pure Escape Freq + s0 = mc->Union2.SummFreq - (ns = mc->NumStats) - ((unsigned)p->FoundState->Freq - 1); + + do + { + unsigned ns1; + UInt32 sum; + + if ((ns1 = c->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + /* Expand for one UNIT */ + const unsigned oldNU = ns1 >> 1; + const unsigned i = U2I(oldNU); + if (i != U2I((size_t)oldNU + 1)) + { + void *ptr = Ppmd7_AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + Ppmd7_RestartModel(p); + return; + } + oldPtr = STATS(c); + MEM_12_CPY(ptr, oldPtr, oldNU) + Ppmd7_InsertNode(p, oldPtr, i); + c->Union4.Stats = STATS_REF(ptr); + } + } + sum = c->Union2.SummFreq; + /* max increase of Escape_Freq is 3 here. + total increase of Union2.SummFreq for all symbols is less than 256 here */ + sum += (UInt32)(unsigned)((2 * ns1 < ns) + 2 * ((unsigned)(4 * ns1 <= ns) & (sum <= 8 * ns1))); + /* original PPMdH uses 16-bit variable for (sum) here. + But (sum < 0x9000). So we don't truncate (sum) to 16-bit */ + // sum = (UInt16)sum; + } + else + { + // instead of One-symbol context we create 2-symbol context + CPpmd_State *s = (CPpmd_State*)Ppmd7_AllocUnits(p, 0); + if (!s) + { + Ppmd7_RestartModel(p); + return; + } + { + unsigned freq = c->Union2.State2.Freq; + // s = *ONE_STATE(c); + s->Symbol = c->Union2.State2.Symbol; + s->Successor_0 = c->Union4.State4.Successor_0; + s->Successor_1 = c->Union4.State4.Successor_1; + // SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of + // (Successor_0 and Successor_1) in LE/BE. + c->Union4.Stats = REF(s); + if (freq < MAX_FREQ / 4 - 1) + freq <<= 1; + else + freq = MAX_FREQ - 4; + // (max(s->freq) == 120), when we convert from 1-symbol into 2-symbol context + s->Freq = (Byte)freq; + // max(InitEsc = PPMD7_kExpEscape[*]) is 25. So the max(escapeFreq) is 26 here + sum = (UInt32)(freq + p->InitEsc + (ns > 3)); + } + } + + { + CPpmd_State *s = STATS(c) + ns1; + UInt32 cf = 2 * (sum + 6) * (UInt32)p->FoundState->Freq; + UInt32 sf = (UInt32)s0 + sum; + s->Symbol = p->FoundState->Symbol; + c->NumStats = (UInt16)(ns1 + 1); + SetSuccessor(s, maxSuccessor); + + if (cf < 6 * sf) + { + cf = (UInt32)1 + (cf > sf) + (cf >= 4 * sf); + sum += 3; + /* It can add (0, 1, 2) to Escape_Freq */ + } + else + { + cf = (UInt32)4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); + sum += cf; + } + + c->Union2.SummFreq = (UInt16)sum; + s->Freq = (Byte)cf; + } + c = SUFFIX(c); + } + while (c != mc); +} + + + +Z7_NO_INLINE +static void Ppmd7_Rescale(CPpmd7 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + + /* Sort the list by Freq */ + if (s != stats) + { + CPpmd_State tmp = *s; + do + s[0] = s[-1]; + while (--s != stats); + *s = tmp; + } + + sumFreq = s->Freq; + escFreq = p->MinContext->Union2.SummFreq - sumFreq; + + /* + if (p->OrderFall == 0), adder = 0 : it's allowed to remove symbol from MAX Order context + if (p->OrderFall != 0), adder = 1 : it's NOT allowed to remove symbol from NON-MAX Order context + */ + + adder = (p->OrderFall != 0); + + #ifdef PPMD7_ORDER_0_SUPPPORT + adder |= (p->MaxOrder == 0); // we don't remove symbols from order-0 context + #endif + + sumFreq = (sumFreq + 4 + adder) >> 1; + i = (unsigned)p->MinContext->NumStats - 1; + s->Freq = (Byte)sumFreq; + + do + { + unsigned freq = (++s)->Freq; + escFreq -= freq; + freq = (freq + adder) >> 1; + sumFreq += freq; + s->Freq = (Byte)freq; + if (freq > s[-1].Freq) + { + CPpmd_State tmp = *s; + CPpmd_State *s1 = s; + do + { + s1[0] = s1[-1]; + } + while (--s1 != stats && freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + /* Remove all items with Freq == 0 */ + CPpmd7_Context *mc; + unsigned numStats, numStatsNew, n0, n1; + + i = 0; do { i++; } while ((--s)->Freq == 0); + + /* We increase (escFreq) for the number of removed symbols. + So we will have (0.5) increase for Escape_Freq in avarage per + removed symbol after Escape_Freq halving */ + escFreq += i; + mc = p->MinContext; + numStats = mc->NumStats; + numStatsNew = numStats - i; + mc->NumStats = (UInt16)(numStatsNew); + n0 = (numStats + 1) >> 1; + + if (numStatsNew == 1) + { + /* Create Single-Symbol context */ + unsigned freq = stats->Freq; + + do + { + escFreq >>= 1; + freq = (freq + 1) >> 1; + } + while (escFreq > 1); + + s = ONE_STATE(mc); + *s = *stats; + s->Freq = (Byte)freq; // (freq <= 260 / 4) + p->FoundState = s; + Ppmd7_InsertNode(p, stats, U2I(n0)); + return; + } + + n1 = (numStatsNew + 1) >> 1; + if (n0 != n1) + { + // p->MinContext->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + unsigned i0 = U2I(n0); + unsigned i1 = U2I(n1); + if (i0 != i1) + { + if (p->FreeList[i1] != 0) + { + void *ptr = Ppmd7_RemoveNode(p, i1); + p->MinContext->Union4.Stats = STATS_REF(ptr); + MEM_12_CPY(ptr, (const void *)stats, n1) + Ppmd7_InsertNode(p, stats, i0); + } + else + Ppmd7_SplitBlock(p, stats, i0, i1); + } + } + } + { + CPpmd7_Context *mc = p->MinContext; + mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + // Escape_Freq halving here + p->FoundState = STATS(mc); + } +} + + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) +{ + CPpmd_See *see; + const CPpmd7_Context *mc = p->MinContext; + unsigned numStats = mc->NumStats; + if (numStats != 256) + { + unsigned nonMasked = numStats - numMasked; + see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - numStats) + + 2 * (unsigned)(mc->Union2.SummFreq < 11 * numStats) + + 4 * (unsigned)(numMasked > nonMasked) + + p->HiBitsFlag; + { + // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ + const unsigned summ = (UInt16)see->Summ; // & 0xFFFF + const unsigned r = (summ >> see->Shift); + see->Summ = (UInt16)(summ - r); + *escFreq = (UInt32)(r + (r == 0)); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + + +static void Ppmd7_NextContext(CPpmd7 *p) +{ + PPMD7_CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; + else + Ppmd7_UpdateModel(p); +} + + +void Ppmd7_Update1(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + unsigned freq = s->Freq; + freq += 4; + p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); + s->Freq = (Byte)freq; + if (freq > s[-1].Freq) + { + SWAP_STATES(s) + p->FoundState = --s; + if (freq > MAX_FREQ) + Ppmd7_Rescale(p); + } + Ppmd7_NextContext(p); +} + + +void Ppmd7_Update1_0(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + CPpmd7_Context *mc = p->MinContext; + unsigned freq = s->Freq; + const unsigned summFreq = mc->Union2.SummFreq; + p->PrevSuccess = (2 * freq > summFreq); + p->RunLength += (Int32)p->PrevSuccess; + mc->Union2.SummFreq = (UInt16)(summFreq + 4); + freq += 4; + s->Freq = (Byte)freq; + if (freq > MAX_FREQ) + Ppmd7_Rescale(p); + Ppmd7_NextContext(p); +} + + +/* +void Ppmd7_UpdateBin(CPpmd7 *p) +{ + unsigned freq = p->FoundState->Freq; + p->FoundState->Freq = (Byte)(freq + (freq < 128)); + p->PrevSuccess = 1; + p->RunLength++; + Ppmd7_NextContext(p); +} +*/ + +void Ppmd7_Update2(CPpmd7 *p) +{ + CPpmd_State *s = p->FoundState; + unsigned freq = s->Freq; + freq += 4; + p->RunLength = p->InitRL; + p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); + s->Freq = (Byte)freq; + if (freq > MAX_FREQ) + Ppmd7_Rescale(p); + Ppmd7_UpdateModel(p); +} + + + +/* +PPMd Memory Map: +{ + [ 0 ] contains subset of original raw text, that is required to create context + records, Some symbols are not written, when max order context was reached + [ Text ] free area + [ UnitsStart ] CPpmd_State vectors and CPpmd7_Context records + [ LoUnit ] free area for CPpmd_State and CPpmd7_Context items +[ HiUnit ] CPpmd7_Context records + [ Size ] end of array +} + +These addresses don't cross at any time. +And the following condtions is true for addresses: + (0 <= Text < UnitsStart <= LoUnit <= HiUnit <= Size) + +Raw text is BYTE--aligned. +the data in block [ UnitsStart ... Size ] contains 12-bytes aligned UNITs. + +Last UNIT of array at offset (Size - 12) is root order-0 CPpmd7_Context record. +The code can free UNITs memory blocks that were allocated to store CPpmd_State vectors. +The code doesn't free UNITs allocated for CPpmd7_Context records. + +The code calls Ppmd7_RestartModel(), when there is no free memory for allocation. +And Ppmd7_RestartModel() changes the state to orignal start state, with full free block. + + +The code allocates UNITs with the following order: + +Allocation of 1 UNIT for Context record + - from free space (HiUnit) down to (LoUnit) + - from FreeList[0] + - Ppmd7_AllocUnitsRare() + +Ppmd7_AllocUnits() for CPpmd_State vectors: + - from FreeList[i] + - from free space (LoUnit) up to (HiUnit) + - Ppmd7_AllocUnitsRare() + +Ppmd7_AllocUnitsRare() + - if (GlueCount == 0) + { Glue lists, GlueCount = 255, allocate from FreeList[i]] } + - loop for all higher sized FreeList[...] lists + - from (UnitsStart - Text), GlueCount-- + - ERROR + + +Each Record with Context contains the CPpmd_State vector, where each +CPpmd_State contains the link to Successor. +There are 3 types of Successor: + 1) NULL-Successor - NULL pointer. NULL-Successor links can be stored + only in 0-order Root Context Record. + We use 0 value as NULL-Successor + 2) RAW-Successor - the link to position in raw text, + that "RAW-Successor" is being created after first + occurrence of new symbol for some existing context record. + (RAW-Successor > 0). + 3) RECORD-Successor - the link to CPpmd7_Context record of (Order+1), + that record is being created when we go via RAW-Successor again. + +For any successors at any time: the following condtions are true for Successor links: +(NULL-Successor < RAW-Successor < UnitsStart <= RECORD-Successor) + + +---------- Symbol Frequency, SummFreq and Range in Range_Coder ---------- + +CPpmd7_Context::SummFreq = Sum(Stats[].Freq) + Escape_Freq + +The PPMd code tries to fulfill the condition: + (SummFreq <= (256 * 128 = RC::kBot)) + +We have (Sum(Stats[].Freq) <= 256 * 124), because of (MAX_FREQ = 124) +So (4 = 128 - 124) is average reserve for Escape_Freq for each symbol. +If (CPpmd_State::Freq) is not aligned for 4, the reserve can be 5, 6 or 7. +SummFreq and Escape_Freq can be changed in Ppmd7_Rescale() and *Update*() functions. +Ppmd7_Rescale() can remove symbols only from max-order contexts. So Escape_Freq can increase after multiple calls of Ppmd7_Rescale() for +max-order context. + +When the PPMd code still break (Total <= RC::Range) condition in range coder, +we have two ways to resolve that problem: + 1) we can report error, if we want to keep compatibility with original PPMd code that has no fix for such cases. + 2) we can reduce (Total) value to (RC::Range) by reducing (Escape_Freq) part of (Total) value. +*/ + +#undef MAX_FREQ +#undef UNIT_SIZE +#undef U2B +#undef U2I +#undef I2U +#undef I2U_UInt16 +#undef REF +#undef STATS_REF +#undef CTX +#undef STATS +#undef ONE_STATE +#undef SUFFIX +#undef NODE +#undef EMPTY_NODE +#undef MEM_12_CPY +#undef SUCCESSOR +#undef SWAP_STATES diff --git a/C/Ppmd7.h b/C/Ppmd7.h index 65c22ae9a..d9eb326d6 100644 --- a/C/Ppmd7.h +++ b/C/Ppmd7.h @@ -1,181 +1,181 @@ -/* Ppmd7.h -- Ppmd7 (PPMdH) compression codec -2023-04-02 : Igor Pavlov : Public domain -This code is based on: - PPMd var.H (2001): Dmitry Shkarin : Public domain */ - - -#ifndef ZIP7_INC_PPMD7_H -#define ZIP7_INC_PPMD7_H - -#include "Ppmd.h" - -EXTERN_C_BEGIN - -#define PPMD7_MIN_ORDER 2 -#define PPMD7_MAX_ORDER 64 - -#define PPMD7_MIN_MEM_SIZE (1 << 11) -#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) - -struct CPpmd7_Context_; - -typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref; - -// MY_CPU_pragma_pack_push_1 - -typedef struct CPpmd7_Context_ -{ - UInt16 NumStats; - - - union - { - UInt16 SummFreq; - CPpmd_State2 State2; - } Union2; - - union - { - CPpmd_State_Ref Stats; - CPpmd_State4 State4; - } Union4; - - CPpmd7_Context_Ref Suffix; -} CPpmd7_Context; - -// MY_CPU_pragma_pop - -#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2) - - - - -typedef struct -{ - UInt32 Range; - UInt32 Code; - UInt32 Low; - IByteInPtr Stream; -} CPpmd7_RangeDec; - - -typedef struct -{ - UInt32 Range; - Byte Cache; - // Byte _dummy_[3]; - UInt64 Low; - UInt64 CacheSize; - IByteOutPtr Stream; -} CPpmd7z_RangeEnc; - - -typedef struct -{ - CPpmd7_Context *MinContext, *MaxContext; - CPpmd_State *FoundState; - unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; - Int32 RunLength, InitRL; /* must be 32-bit at least */ - - UInt32 Size; - UInt32 GlueCount; - UInt32 AlignOffset; - Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; - - - - - union - { - CPpmd7_RangeDec dec; - CPpmd7z_RangeEnc enc; - } rc; - - Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment - Byte Units2Indx[128]; - CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; - - Byte NS2BSIndx[256], NS2Indx[256]; - Byte ExpEscape[16]; - CPpmd_See DummySee, See[25][16]; - UInt16 BinSumm[128][64]; - // int LastSymbol; -} CPpmd7; - - -void Ppmd7_Construct(CPpmd7 *p); -BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc); -void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc); -void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); -#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) - - -/* ---------- Internal Functions ---------- */ - -#define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) -#define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context) -#define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) - -void Ppmd7_Update1(CPpmd7 *p); -void Ppmd7_Update1_0(CPpmd7 *p); -void Ppmd7_Update2(CPpmd7 *p); - -#define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3)) -#define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4)) -// #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3)) -// #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4)) - -#define Ppmd7_GetBinSumm(p) \ - &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \ - [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ - + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \ - + PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \ - + (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ] - -CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); - - -/* -We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure: - 1) Ppmd7a_*: original PPMdH - 2) Ppmd7z_*: modified PPMdH with 7z Range Coder -Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH) -*/ - -/* ---------- Decode ---------- */ - -#define PPMD7_SYM_END (-1) -#define PPMD7_SYM_ERROR (-2) - -/* -You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init() - -Ppmd7*_DecodeSymbol() -out: - >= 0 : decoded byte - -1 : PPMD7_SYM_END : End of payload marker - -2 : PPMD7_SYM_ERROR : Data error -*/ - -/* Ppmd7a_* : original PPMdH */ -BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p); -#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -int Ppmd7a_DecodeSymbol(CPpmd7 *p); - -/* Ppmd7z_* : modified PPMdH with 7z Range Coder */ -BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p); -#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -int Ppmd7z_DecodeSymbol(CPpmd7 *p); -// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim); - - -/* ---------- Encode ---------- */ - -void Ppmd7z_Init_RangeEnc(CPpmd7 *p); -void Ppmd7z_Flush_RangeEnc(CPpmd7 *p); -// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol); -void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim); - -EXTERN_C_END - -#endif +/* Ppmd7.h -- Ppmd7 (PPMdH) compression codec +2023-04-02 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain */ + + +#ifndef ZIP7_INC_PPMD7_H +#define ZIP7_INC_PPMD7_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD7_MIN_ORDER 2 +#define PPMD7_MAX_ORDER 64 + +#define PPMD7_MIN_MEM_SIZE (1 << 11) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) + +struct CPpmd7_Context_; + +typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref; + +// MY_CPU_pragma_pack_push_1 + +typedef struct CPpmd7_Context_ +{ + UInt16 NumStats; + + + union + { + UInt16 SummFreq; + CPpmd_State2 State2; + } Union2; + + union + { + CPpmd_State_Ref Stats; + CPpmd_State4 State4; + } Union4; + + CPpmd7_Context_Ref Suffix; +} CPpmd7_Context; + +// MY_CPU_pragma_pop + +#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2) + + + + +typedef struct +{ + UInt32 Range; + UInt32 Code; + UInt32 Low; + IByteInPtr Stream; +} CPpmd7_RangeDec; + + +typedef struct +{ + UInt32 Range; + Byte Cache; + // Byte _dummy_[3]; + UInt64 Low; + UInt64 CacheSize; + IByteOutPtr Stream; +} CPpmd7z_RangeEnc; + + +typedef struct +{ + CPpmd7_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + UInt32 AlignOffset; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + + + + + union + { + CPpmd7_RangeDec dec; + CPpmd7z_RangeEnc enc; + } rc; + + Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + + Byte NS2BSIndx[256], NS2Indx[256]; + Byte ExpEscape[16]; + CPpmd_See DummySee, See[25][16]; + UInt16 BinSumm[128][64]; + // int LastSymbol; +} CPpmd7; + + +void Ppmd7_Construct(CPpmd7 *p); +BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc); +void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc); +void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); +#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +#define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) +#define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context) +#define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) + +void Ppmd7_Update1(CPpmd7 *p); +void Ppmd7_Update1_0(CPpmd7 *p); +void Ppmd7_Update2(CPpmd7 *p); + +#define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3)) +#define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4)) +// #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3)) +// #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4)) + +#define Ppmd7_GetBinSumm(p) \ + &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \ + [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ + + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \ + + PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \ + + (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ] + +CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); + + +/* +We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure: + 1) Ppmd7a_*: original PPMdH + 2) Ppmd7z_*: modified PPMdH with 7z Range Coder +Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH) +*/ + +/* ---------- Decode ---------- */ + +#define PPMD7_SYM_END (-1) +#define PPMD7_SYM_ERROR (-2) + +/* +You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init() + +Ppmd7*_DecodeSymbol() +out: + >= 0 : decoded byte + -1 : PPMD7_SYM_END : End of payload marker + -2 : PPMD7_SYM_ERROR : Data error +*/ + +/* Ppmd7a_* : original PPMdH */ +BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p); +#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd7a_DecodeSymbol(CPpmd7 *p); + +/* Ppmd7z_* : modified PPMdH with 7z Range Coder */ +BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p); +#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd7z_DecodeSymbol(CPpmd7 *p); +// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim); + + +/* ---------- Encode ---------- */ + +void Ppmd7z_Init_RangeEnc(CPpmd7 *p); +void Ppmd7z_Flush_RangeEnc(CPpmd7 *p); +// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol); +void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim); + +EXTERN_C_END + +#endif diff --git a/C/Ppmd7Dec.c b/C/Ppmd7Dec.c index e601feb19..081ab8955 100644 --- a/C/Ppmd7Dec.c +++ b/C/Ppmd7Dec.c @@ -1,312 +1,312 @@ -/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder -2023-09-07 : Igor Pavlov : Public domain -This code is based on: - PPMd var.H (2001): Dmitry Shkarin : Public domain */ - - -#include "Precomp.h" - -#include "Ppmd7.h" - -#define kTopValue ((UInt32)1 << 24) - - -#define READ_BYTE(p) IByteIn_Read((p)->Stream) - -BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p) -{ - unsigned i; - p->Code = 0; - p->Range = 0xFFFFFFFF; - if (READ_BYTE(p) != 0) - return False; - for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | READ_BYTE(p); - return (p->Code < 0xFFFFFFFF); -} - -#define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \ - { (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8; - -#define RC_NORM_1(p) RC_NORM_BASE(p) } -#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} - -// we must use only one type of Normalization from two: LOCAL or REMOTE -#define RC_NORM_LOCAL(p) // RC_NORM(p) -#define RC_NORM_REMOTE(p) RC_NORM(p) - -#define R (&p->rc.dec) - -Z7_FORCE_INLINE -// Z7_NO_INLINE -static void Ppmd7z_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size) -{ - - - R->Code -= start * R->Range; - R->Range *= size; - RC_NORM_LOCAL(R) -} - -#define RC_Decode(start, size) Ppmd7z_RD_Decode(p, start, size); -#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) -#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) - - -#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) -// typedef CPpmd7_Context * CTX_PTR; -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) -void Ppmd7_UpdateModel(CPpmd7 *p); - -#define MASK(sym) ((Byte *)charMask)[sym] -// Z7_FORCE_INLINE -// static -int Ppmd7z_DecodeSymbol(CPpmd7 *p) -{ - size_t charMask[256 / sizeof(size_t)]; - - if (p->MinContext->NumStats != 1) - { - CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); - unsigned i; - UInt32 count, hiCnt; - const UInt32 summFreq = p->MinContext->Union2.SummFreq; - - - - - count = RC_GetThreshold(summFreq); - hiCnt = count; - - if ((Int32)(count -= s->Freq) < 0) - { - Byte sym; - RC_DecodeFinal(0, s->Freq) - p->FoundState = s; - sym = s->Symbol; - Ppmd7_Update1_0(p); - return sym; - } - - p->PrevSuccess = 0; - i = (unsigned)p->MinContext->NumStats - 1; - - do - { - if ((Int32)(count -= (++s)->Freq) < 0) - { - Byte sym; - RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) - p->FoundState = s; - sym = s->Symbol; - Ppmd7_Update1(p); - return sym; - } - } - while (--i); - - if (hiCnt >= summFreq) - return PPMD7_SYM_ERROR; - - hiCnt -= count; - RC_Decode(hiCnt, summFreq - hiCnt) - - p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); - PPMD_SetAllBitsIn256Bytes(charMask) - // i = p->MinContext->NumStats - 1; - // do { MASK((--s)->Symbol) = 0; } while (--i); - { - CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } - else - { - CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); - UInt16 *prob = Ppmd7_GetBinSumm(p); - UInt32 pr = *prob; - UInt32 size0 = (R->Range >> 14) * pr; - pr = PPMD_UPDATE_PROB_1(pr); - - if (R->Code < size0) - { - Byte sym; - *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); - - // RangeDec_DecodeBit0(size0); - R->Range = size0; - RC_NORM_1(R) - /* we can use single byte normalization here because of - (min(BinSumm[][]) = 95) > (1 << (14 - 8)) */ - - // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; - // Ppmd7_UpdateBin(p); - { - unsigned freq = s->Freq; - CPpmd7_Context *c = CTX(SUCCESSOR(s)); - sym = s->Symbol; - p->FoundState = s; - p->PrevSuccess = 1; - p->RunLength++; - s->Freq = (Byte)(freq + (freq < 128)); - // NextContext(p); - if (p->OrderFall == 0 && (const Byte *)c > p->Text) - p->MaxContext = p->MinContext = c; - else - Ppmd7_UpdateModel(p); - } - return sym; - } - - *prob = (UInt16)pr; - p->InitEsc = p->ExpEscape[pr >> 10]; - - // RangeDec_DecodeBit1(size0); - - R->Code -= size0; - R->Range -= size0; - RC_NORM_LOCAL(R) - - PPMD_SetAllBitsIn256Bytes(charMask) - MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; - p->PrevSuccess = 0; - } - - for (;;) - { - CPpmd_State *s, *s2; - UInt32 freqSum, count, hiCnt; - - CPpmd_See *see; - CPpmd7_Context *mc; - unsigned numMasked; - RC_NORM_REMOTE(R) - mc = p->MinContext; - numMasked = mc->NumStats; - - do - { - p->OrderFall++; - if (!mc->Suffix) - return PPMD7_SYM_END; - mc = Ppmd7_GetContext(p, mc->Suffix); - } - while (mc->NumStats == numMasked); - - s = Ppmd7_GetStats(p, mc); - - { - unsigned num = mc->NumStats; - unsigned num2 = num / 2; - - num &= 1; - hiCnt = (s->Freq & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num); - s += num; - p->MinContext = mc; - - do - { - const unsigned sym0 = s[0].Symbol; - const unsigned sym1 = s[1].Symbol; - s += 2; - hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0))); - hiCnt += (s[-1].Freq & (UInt32)(MASK(sym1))); - } - while (--num2); - } - - see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); - freqSum += hiCnt; - - - - - count = RC_GetThreshold(freqSum); - - if (count < hiCnt) - { - Byte sym; - - s = Ppmd7_GetStats(p, p->MinContext); - hiCnt = count; - // count -= s->Freq & (UInt32)(MASK(s->Symbol)); - // if ((Int32)count >= 0) - { - for (;;) - { - count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; - // count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; - } - } - s--; - RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) - - // new (see->Summ) value can overflow over 16-bits in some rare cases - Ppmd_See_UPDATE(see) - p->FoundState = s; - sym = s->Symbol; - Ppmd7_Update2(p); - return sym; - } - - if (count >= freqSum) - return PPMD7_SYM_ERROR; - - RC_Decode(hiCnt, freqSum - hiCnt) - - // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. - // new (see->Summ) value can overflow over 16-bits in some rare cases - see->Summ = (UInt16)(see->Summ + freqSum); - - s = Ppmd7_GetStats(p, p->MinContext); - s2 = s + p->MinContext->NumStats; - do - { - MASK(s->Symbol) = 0; - s++; - } - while (s != s2); - } -} - -/* -Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim) -{ - int sym = 0; - if (buf != lim) - do - { - sym = Ppmd7z_DecodeSymbol(p); - if (sym < 0) - break; - *buf = (Byte)sym; - } - while (++buf < lim); - p->LastSymbol = sym; - return buf; -} -*/ - -#undef kTopValue -#undef READ_BYTE -#undef RC_NORM_BASE -#undef RC_NORM_1 -#undef RC_NORM -#undef RC_NORM_LOCAL -#undef RC_NORM_REMOTE -#undef R -#undef RC_Decode -#undef RC_DecodeFinal -#undef RC_GetThreshold -#undef CTX -#undef SUCCESSOR -#undef MASK +/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder +2023-09-07 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain */ + + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue ((UInt32)1 << 24) + + +#define READ_BYTE(p) IByteIn_Read((p)->Stream) + +BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + if (READ_BYTE(p) != 0) + return False; + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | READ_BYTE(p); + return (p->Code < 0xFFFFFFFF); +} + +#define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \ + { (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8; + +#define RC_NORM_1(p) RC_NORM_BASE(p) } +#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} + +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) + +#define R (&p->rc.dec) + +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd7z_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size) +{ + + + R->Code -= start * R->Range; + R->Range *= size; + RC_NORM_LOCAL(R) +} + +#define RC_Decode(start, size) Ppmd7z_RD_Decode(p, start, size); +#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) +#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) + + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +// typedef CPpmd7_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) +void Ppmd7_UpdateModel(CPpmd7 *p); + +#define MASK(sym) ((Byte *)charMask)[sym] +// Z7_FORCE_INLINE +// static +int Ppmd7z_DecodeSymbol(CPpmd7 *p) +{ + size_t charMask[256 / sizeof(size_t)]; + + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + const UInt32 summFreq = p->MinContext->Union2.SummFreq; + + + + + count = RC_GetThreshold(summFreq); + hiCnt = count; + + if ((Int32)(count -= s->Freq) < 0) + { + Byte sym; + RC_DecodeFinal(0, s->Freq) + p->FoundState = s; + sym = s->Symbol; + Ppmd7_Update1_0(p); + return sym; + } + + p->PrevSuccess = 0; + i = (unsigned)p->MinContext->NumStats - 1; + + do + { + if ((Int32)(count -= (++s)->Freq) < 0) + { + Byte sym; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + p->FoundState = s; + sym = s->Symbol; + Ppmd7_Update1(p); + return sym; + } + } + while (--i); + + if (hiCnt >= summFreq) + return PPMD7_SYM_ERROR; + + hiCnt -= count; + RC_Decode(hiCnt, summFreq - hiCnt) + + p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); + PPMD_SetAllBitsIn256Bytes(charMask) + // i = p->MinContext->NumStats - 1; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } + else + { + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + UInt16 *prob = Ppmd7_GetBinSumm(p); + UInt32 pr = *prob; + UInt32 size0 = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + + if (R->Code < size0) + { + Byte sym; + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + + // RangeDec_DecodeBit0(size0); + R->Range = size0; + RC_NORM_1(R) + /* we can use single byte normalization here because of + (min(BinSumm[][]) = 95) > (1 << (14 - 8)) */ + + // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + // Ppmd7_UpdateBin(p); + { + unsigned freq = s->Freq; + CPpmd7_Context *c = CTX(SUCCESSOR(s)); + sym = s->Symbol; + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 128)); + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; + else + Ppmd7_UpdateModel(p); + } + return sym; + } + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + + // RangeDec_DecodeBit1(size0); + + R->Code -= size0; + R->Range -= size0; + RC_NORM_LOCAL(R) + + PPMD_SetAllBitsIn256Bytes(charMask) + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + + for (;;) + { + CPpmd_State *s, *s2; + UInt32 freqSum, count, hiCnt; + + CPpmd_See *see; + CPpmd7_Context *mc; + unsigned numMasked; + RC_NORM_REMOTE(R) + mc = p->MinContext; + numMasked = mc->NumStats; + + do + { + p->OrderFall++; + if (!mc->Suffix) + return PPMD7_SYM_END; + mc = Ppmd7_GetContext(p, mc->Suffix); + } + while (mc->NumStats == numMasked); + + s = Ppmd7_GetStats(p, mc); + + { + unsigned num = mc->NumStats; + unsigned num2 = num / 2; + + num &= 1; + hiCnt = (s->Freq & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num); + s += num; + p->MinContext = mc; + + do + { + const unsigned sym0 = s[0].Symbol; + const unsigned sym1 = s[1].Symbol; + s += 2; + hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0))); + hiCnt += (s[-1].Freq & (UInt32)(MASK(sym1))); + } + while (--num2); + } + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + + + + + count = RC_GetThreshold(freqSum); + + if (count < hiCnt) + { + Byte sym; + + s = Ppmd7_GetStats(p, p->MinContext); + hiCnt = count; + // count -= s->Freq & (UInt32)(MASK(s->Symbol)); + // if ((Int32)count >= 0) + { + for (;;) + { + count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + // count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + } + } + s--; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + + // new (see->Summ) value can overflow over 16-bits in some rare cases + Ppmd_See_UPDATE(see) + p->FoundState = s; + sym = s->Symbol; + Ppmd7_Update2(p); + return sym; + } + + if (count >= freqSum) + return PPMD7_SYM_ERROR; + + RC_Decode(hiCnt, freqSum - hiCnt) + + // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. + // new (see->Summ) value can overflow over 16-bits in some rare cases + see->Summ = (UInt16)(see->Summ + freqSum); + + s = Ppmd7_GetStats(p, p->MinContext); + s2 = s + p->MinContext->NumStats; + do + { + MASK(s->Symbol) = 0; + s++; + } + while (s != s2); + } +} + +/* +Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim) +{ + int sym = 0; + if (buf != lim) + do + { + sym = Ppmd7z_DecodeSymbol(p); + if (sym < 0) + break; + *buf = (Byte)sym; + } + while (++buf < lim); + p->LastSymbol = sym; + return buf; +} +*/ + +#undef kTopValue +#undef READ_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Decode +#undef RC_DecodeFinal +#undef RC_GetThreshold +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/C/Ppmd7Enc.c b/C/Ppmd7Enc.c index 961b1a96b..49cbbe649 100644 --- a/C/Ppmd7Enc.c +++ b/C/Ppmd7Enc.c @@ -1,337 +1,337 @@ -/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder -2023-09-07 : Igor Pavlov : Public domain -This code is based on: - PPMd var.H (2001): Dmitry Shkarin : Public domain */ - - -#include "Precomp.h" - -#include "Ppmd7.h" - -#define kTopValue ((UInt32)1 << 24) - -#define R (&p->rc.enc) - -void Ppmd7z_Init_RangeEnc(CPpmd7 *p) -{ - R->Low = 0; - R->Range = 0xFFFFFFFF; - R->Cache = 0; - R->CacheSize = 1; -} - -Z7_NO_INLINE -static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p) -{ - if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0) - { - Byte temp = R->Cache; - do - { - IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32))); - temp = 0xFF; - } - while (--R->CacheSize != 0); - R->Cache = (Byte)((UInt32)R->Low >> 24); - } - R->CacheSize++; - R->Low = (UInt32)((UInt32)R->Low << 8); -} - -#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p); -#define RC_NORM_1(p) RC_NORM_BASE(p) } -#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} - -// we must use only one type of Normalization from two: LOCAL or REMOTE -#define RC_NORM_LOCAL(p) // RC_NORM(p) -#define RC_NORM_REMOTE(p) RC_NORM(p) - -/* -#define Ppmd7z_RangeEnc_Encode(p, start, _size_) \ - { UInt32 size = _size_; \ - R->Low += start * R->Range; \ - R->Range *= size; \ - RC_NORM_LOCAL(p); } -*/ - -Z7_FORCE_INLINE -// Z7_NO_INLINE -static void Ppmd7z_RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size) -{ - R->Low += start * R->Range; - R->Range *= size; - RC_NORM_LOCAL(p) -} - -void Ppmd7z_Flush_RangeEnc(CPpmd7 *p) -{ - unsigned i; - for (i = 0; i < 5; i++) - Ppmd7z_RangeEnc_ShiftLow(p); -} - - - -#define RC_Encode(start, size) Ppmd7z_RangeEnc_Encode(p, start, size); -#define RC_EncodeFinal(start, size) RC_Encode(start, size) RC_NORM_REMOTE(p) - -#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) -#define SUFFIX(ctx) CTX((ctx)->Suffix) -// typedef CPpmd7_Context * CTX_PTR; -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) - -void Ppmd7_UpdateModel(CPpmd7 *p); - -#define MASK(sym) ((Byte *)charMask)[sym] - -Z7_FORCE_INLINE -static -void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol) -{ - size_t charMask[256 / sizeof(size_t)]; - - if (p->MinContext->NumStats != 1) - { - CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); - UInt32 sum; - unsigned i; - - - - - R->Range /= p->MinContext->Union2.SummFreq; - - if (s->Symbol == symbol) - { - // R->Range /= p->MinContext->Union2.SummFreq; - RC_EncodeFinal(0, s->Freq) - p->FoundState = s; - Ppmd7_Update1_0(p); - return; - } - p->PrevSuccess = 0; - sum = s->Freq; - i = (unsigned)p->MinContext->NumStats - 1; - do - { - if ((++s)->Symbol == symbol) - { - // R->Range /= p->MinContext->Union2.SummFreq; - RC_EncodeFinal(sum, s->Freq) - p->FoundState = s; - Ppmd7_Update1(p); - return; - } - sum += s->Freq; - } - while (--i); - - // R->Range /= p->MinContext->Union2.SummFreq; - RC_Encode(sum, p->MinContext->Union2.SummFreq - sum) - - p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); - PPMD_SetAllBitsIn256Bytes(charMask) - // MASK(s->Symbol) = 0; - // i = p->MinContext->NumStats - 1; - // do { MASK((--s)->Symbol) = 0; } while (--i); - { - CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } - else - { - UInt16 *prob = Ppmd7_GetBinSumm(p); - CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); - UInt32 pr = *prob; - const UInt32 bound = (R->Range >> 14) * pr; - pr = PPMD_UPDATE_PROB_1(pr); - if (s->Symbol == symbol) - { - *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); - // RangeEnc_EncodeBit_0(p, bound); - R->Range = bound; - RC_NORM_1(p) - - // p->FoundState = s; - // Ppmd7_UpdateBin(p); - { - const unsigned freq = s->Freq; - CPpmd7_Context *c = CTX(SUCCESSOR(s)); - p->FoundState = s; - p->PrevSuccess = 1; - p->RunLength++; - s->Freq = (Byte)(freq + (freq < 128)); - // NextContext(p); - if (p->OrderFall == 0 && (const Byte *)c > p->Text) - p->MaxContext = p->MinContext = c; - else - Ppmd7_UpdateModel(p); - } - return; - } - - *prob = (UInt16)pr; - p->InitEsc = p->ExpEscape[pr >> 10]; - // RangeEnc_EncodeBit_1(p, bound); - R->Low += bound; - R->Range -= bound; - RC_NORM_LOCAL(p) - - PPMD_SetAllBitsIn256Bytes(charMask) - MASK(s->Symbol) = 0; - p->PrevSuccess = 0; - } - - for (;;) - { - CPpmd_See *see; - CPpmd_State *s; - UInt32 sum, escFreq; - CPpmd7_Context *mc; - unsigned i, numMasked; - - RC_NORM_REMOTE(p) - - mc = p->MinContext; - numMasked = mc->NumStats; - - do - { - p->OrderFall++; - if (!mc->Suffix) - return; /* EndMarker (symbol = -1) */ - mc = Ppmd7_GetContext(p, mc->Suffix); - i = mc->NumStats; - } - while (i == numMasked); - - p->MinContext = mc; - - // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); - { - if (i != 256) - { - unsigned nonMasked = i - numMasked; - see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] - + p->HiBitsFlag - + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i) - + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i) - + 4 * (unsigned)(numMasked > nonMasked); - { - // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ - unsigned summ = (UInt16)see->Summ; // & 0xFFFF - unsigned r = (summ >> see->Shift); - see->Summ = (UInt16)(summ - r); - escFreq = r + (r == 0); - } - } - else - { - see = &p->DummySee; - escFreq = 1; - } - } - - s = Ppmd7_GetStats(p, mc); - sum = 0; - // i = mc->NumStats; - - do - { - const unsigned cur = s->Symbol; - if ((int)cur == symbol) - { - const UInt32 low = sum; - const UInt32 freq = s->Freq; - unsigned num2; - - Ppmd_See_UPDATE(see) - p->FoundState = s; - sum += escFreq; - - num2 = i / 2; - i &= 1; - sum += freq & (0 - (UInt32)i); - if (num2 != 0) - { - s += i; - do - { - const unsigned sym0 = s[0].Symbol; - const unsigned sym1 = s[1].Symbol; - s += 2; - sum += (s[-2].Freq & (unsigned)(MASK(sym0))); - sum += (s[-1].Freq & (unsigned)(MASK(sym1))); - } - while (--num2); - } - - - R->Range /= sum; - RC_EncodeFinal(low, freq) - Ppmd7_Update2(p); - return; - } - sum += (s->Freq & (unsigned)(MASK(cur))); - s++; - } - while (--i); - - { - const UInt32 total = sum + escFreq; - see->Summ = (UInt16)(see->Summ + total); - - R->Range /= total; - RC_Encode(sum, escFreq) - } - - { - const CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); - s--; - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } -} - - -void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim) -{ - for (; buf < lim; buf++) - { - Ppmd7z_EncodeSymbol(p, *buf); - } -} - -#undef kTopValue -#undef WRITE_BYTE -#undef RC_NORM_BASE -#undef RC_NORM_1 -#undef RC_NORM -#undef RC_NORM_LOCAL -#undef RC_NORM_REMOTE -#undef R -#undef RC_Encode -#undef RC_EncodeFinal -#undef SUFFIX -#undef CTX -#undef SUCCESSOR -#undef MASK +/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder +2023-09-07 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain */ + + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTopValue ((UInt32)1 << 24) + +#define R (&p->rc.enc) + +void Ppmd7z_Init_RangeEnc(CPpmd7 *p) +{ + R->Low = 0; + R->Range = 0xFFFFFFFF; + R->Cache = 0; + R->CacheSize = 1; +} + +Z7_NO_INLINE +static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p) +{ + if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0) + { + Byte temp = R->Cache; + do + { + IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32))); + temp = 0xFF; + } + while (--R->CacheSize != 0); + R->Cache = (Byte)((UInt32)R->Low >> 24); + } + R->CacheSize++; + R->Low = (UInt32)((UInt32)R->Low << 8); +} + +#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p); +#define RC_NORM_1(p) RC_NORM_BASE(p) } +#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }} + +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) + +/* +#define Ppmd7z_RangeEnc_Encode(p, start, _size_) \ + { UInt32 size = _size_; \ + R->Low += start * R->Range; \ + R->Range *= size; \ + RC_NORM_LOCAL(p); } +*/ + +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd7z_RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size) +{ + R->Low += start * R->Range; + R->Range *= size; + RC_NORM_LOCAL(p) +} + +void Ppmd7z_Flush_RangeEnc(CPpmd7 *p) +{ + unsigned i; + for (i = 0; i < 5; i++) + Ppmd7z_RangeEnc_ShiftLow(p); +} + + + +#define RC_Encode(start, size) Ppmd7z_RangeEnc_Encode(p, start, size); +#define RC_EncodeFinal(start, size) RC_Encode(start, size) RC_NORM_REMOTE(p) + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +#define SUFFIX(ctx) CTX((ctx)->Suffix) +// typedef CPpmd7_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) + +void Ppmd7_UpdateModel(CPpmd7 *p); + +#define MASK(sym) ((Byte *)charMask)[sym] + +Z7_FORCE_INLINE +static +void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + + + + + R->Range /= p->MinContext->Union2.SummFreq; + + if (s->Symbol == symbol) + { + // R->Range /= p->MinContext->Union2.SummFreq; + RC_EncodeFinal(0, s->Freq) + p->FoundState = s; + Ppmd7_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = (unsigned)p->MinContext->NumStats - 1; + do + { + if ((++s)->Symbol == symbol) + { + // R->Range /= p->MinContext->Union2.SummFreq; + RC_EncodeFinal(sum, s->Freq) + p->FoundState = s; + Ppmd7_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + // R->Range /= p->MinContext->Union2.SummFreq; + RC_Encode(sum, p->MinContext->Union2.SummFreq - sum) + + p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); + PPMD_SetAllBitsIn256Bytes(charMask) + // MASK(s->Symbol) = 0; + // i = p->MinContext->NumStats - 1; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } + else + { + UInt16 *prob = Ppmd7_GetBinSumm(p); + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + UInt32 pr = *prob; + const UInt32 bound = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + if (s->Symbol == symbol) + { + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + // RangeEnc_EncodeBit_0(p, bound); + R->Range = bound; + RC_NORM_1(p) + + // p->FoundState = s; + // Ppmd7_UpdateBin(p); + { + const unsigned freq = s->Freq; + CPpmd7_Context *c = CTX(SUCCESSOR(s)); + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 128)); + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; + else + Ppmd7_UpdateModel(p); + } + return; + } + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + // RangeEnc_EncodeBit_1(p, bound); + R->Low += bound; + R->Range -= bound; + RC_NORM_LOCAL(p) + + PPMD_SetAllBitsIn256Bytes(charMask) + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + + for (;;) + { + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum, escFreq; + CPpmd7_Context *mc; + unsigned i, numMasked; + + RC_NORM_REMOTE(p) + + mc = p->MinContext; + numMasked = mc->NumStats; + + do + { + p->OrderFall++; + if (!mc->Suffix) + return; /* EndMarker (symbol = -1) */ + mc = Ppmd7_GetContext(p, mc->Suffix); + i = mc->NumStats; + } + while (i == numMasked); + + p->MinContext = mc; + + // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); + { + if (i != 256) + { + unsigned nonMasked = i - numMasked; + see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] + + p->HiBitsFlag + + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i) + + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i) + + 4 * (unsigned)(numMasked > nonMasked); + { + // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ + unsigned summ = (UInt16)see->Summ; // & 0xFFFF + unsigned r = (summ >> see->Shift); + see->Summ = (UInt16)(summ - r); + escFreq = r + (r == 0); + } + } + else + { + see = &p->DummySee; + escFreq = 1; + } + } + + s = Ppmd7_GetStats(p, mc); + sum = 0; + // i = mc->NumStats; + + do + { + const unsigned cur = s->Symbol; + if ((int)cur == symbol) + { + const UInt32 low = sum; + const UInt32 freq = s->Freq; + unsigned num2; + + Ppmd_See_UPDATE(see) + p->FoundState = s; + sum += escFreq; + + num2 = i / 2; + i &= 1; + sum += freq & (0 - (UInt32)i); + if (num2 != 0) + { + s += i; + do + { + const unsigned sym0 = s[0].Symbol; + const unsigned sym1 = s[1].Symbol; + s += 2; + sum += (s[-2].Freq & (unsigned)(MASK(sym0))); + sum += (s[-1].Freq & (unsigned)(MASK(sym1))); + } + while (--num2); + } + + + R->Range /= sum; + RC_EncodeFinal(low, freq) + Ppmd7_Update2(p); + return; + } + sum += (s->Freq & (unsigned)(MASK(cur))); + s++; + } + while (--i); + + { + const UInt32 total = sum + escFreq; + see->Summ = (UInt16)(see->Summ + total); + + R->Range /= total; + RC_Encode(sum, escFreq) + } + + { + const CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + s--; + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } +} + + +void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim) +{ + for (; buf < lim; buf++) + { + Ppmd7z_EncodeSymbol(p, *buf); + } +} + +#undef kTopValue +#undef WRITE_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Encode +#undef RC_EncodeFinal +#undef SUFFIX +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/C/Ppmd7aDec.c b/C/Ppmd7aDec.c index 7f3d1e567..ef86dde79 100644 --- a/C/Ppmd7aDec.c +++ b/C/Ppmd7aDec.c @@ -1,295 +1,295 @@ -/* Ppmd7aDec.c -- PPMd7a (PPMdH) Decoder -2023-09-07 : Igor Pavlov : Public domain -This code is based on: - PPMd var.H (2001): Dmitry Shkarin : Public domain - Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#include "Precomp.h" - -#include "Ppmd7.h" - -#define kTop ((UInt32)1 << 24) -#define kBot ((UInt32)1 << 15) - -#define READ_BYTE(p) IByteIn_Read((p)->Stream) - -BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p) -{ - unsigned i; - p->Code = 0; - p->Range = 0xFFFFFFFF; - p->Low = 0; - - for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | READ_BYTE(p); - return (p->Code < 0xFFFFFFFF); -} - -#define RC_NORM(p) \ - while ((p->Low ^ (p->Low + p->Range)) < kTop \ - || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \ - p->Code = (p->Code << 8) | READ_BYTE(p); \ - p->Range <<= 8; p->Low <<= 8; } - -// we must use only one type of Normalization from two: LOCAL or REMOTE -#define RC_NORM_LOCAL(p) // RC_NORM(p) -#define RC_NORM_REMOTE(p) RC_NORM(p) - -#define R (&p->rc.dec) - -Z7_FORCE_INLINE -// Z7_NO_INLINE -static void Ppmd7a_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size) -{ - start *= R->Range; - R->Low += start; - R->Code -= start; - R->Range *= size; - RC_NORM_LOCAL(R) -} - -#define RC_Decode(start, size) Ppmd7a_RD_Decode(p, start, size); -#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) -#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) - - -#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) -typedef CPpmd7_Context * CTX_PTR; -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) -void Ppmd7_UpdateModel(CPpmd7 *p); - -#define MASK(sym) ((Byte *)charMask)[sym] - - -int Ppmd7a_DecodeSymbol(CPpmd7 *p) -{ - size_t charMask[256 / sizeof(size_t)]; - - if (p->MinContext->NumStats != 1) - { - CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); - unsigned i; - UInt32 count, hiCnt; - const UInt32 summFreq = p->MinContext->Union2.SummFreq; - - if (summFreq > R->Range) - return PPMD7_SYM_ERROR; - - count = RC_GetThreshold(summFreq); - hiCnt = count; - - if ((Int32)(count -= s->Freq) < 0) - { - Byte sym; - RC_DecodeFinal(0, s->Freq) - p->FoundState = s; - sym = s->Symbol; - Ppmd7_Update1_0(p); - return sym; - } - - p->PrevSuccess = 0; - i = (unsigned)p->MinContext->NumStats - 1; - - do - { - if ((Int32)(count -= (++s)->Freq) < 0) - { - Byte sym; - RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) - p->FoundState = s; - sym = s->Symbol; - Ppmd7_Update1(p); - return sym; - } - } - while (--i); - - if (hiCnt >= summFreq) - return PPMD7_SYM_ERROR; - - hiCnt -= count; - RC_Decode(hiCnt, summFreq - hiCnt) - - p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); - PPMD_SetAllBitsIn256Bytes(charMask) - // i = p->MinContext->NumStats - 1; - // do { MASK((--s)->Symbol) = 0; } while (--i); - { - CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } - else - { - CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); - UInt16 *prob = Ppmd7_GetBinSumm(p); - UInt32 pr = *prob; - UInt32 size0 = (R->Range >> 14) * pr; - pr = PPMD_UPDATE_PROB_1(pr); - - if (R->Code < size0) - { - Byte sym; - *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); - - // RangeDec_DecodeBit0(size0); - R->Range = size0; - RC_NORM(R) - - - - // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; - // Ppmd7_UpdateBin(p); - { - unsigned freq = s->Freq; - CTX_PTR c = CTX(SUCCESSOR(s)); - sym = s->Symbol; - p->FoundState = s; - p->PrevSuccess = 1; - p->RunLength++; - s->Freq = (Byte)(freq + (freq < 128)); - // NextContext(p); - if (p->OrderFall == 0 && (const Byte *)c > p->Text) - p->MaxContext = p->MinContext = c; - else - Ppmd7_UpdateModel(p); - } - return sym; - } - - *prob = (UInt16)pr; - p->InitEsc = p->ExpEscape[pr >> 10]; - - // RangeDec_DecodeBit1(size0); - R->Low += size0; - R->Code -= size0; - R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0; - RC_NORM_LOCAL(R) - - PPMD_SetAllBitsIn256Bytes(charMask) - MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; - p->PrevSuccess = 0; - } - - for (;;) - { - CPpmd_State *s, *s2; - UInt32 freqSum, count, hiCnt; - - CPpmd_See *see; - CPpmd7_Context *mc; - unsigned numMasked; - RC_NORM_REMOTE(R) - mc = p->MinContext; - numMasked = mc->NumStats; - - do - { - p->OrderFall++; - if (!mc->Suffix) - return PPMD7_SYM_END; - mc = Ppmd7_GetContext(p, mc->Suffix); - } - while (mc->NumStats == numMasked); - - s = Ppmd7_GetStats(p, mc); - - { - unsigned num = mc->NumStats; - unsigned num2 = num / 2; - - num &= 1; - hiCnt = (s->Freq & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num); - s += num; - p->MinContext = mc; - - do - { - const unsigned sym0 = s[0].Symbol; - const unsigned sym1 = s[1].Symbol; - s += 2; - hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0))); - hiCnt += (s[-1].Freq & (UInt32)(MASK(sym1))); - } - while (--num2); - } - - see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); - freqSum += hiCnt; - - if (freqSum > R->Range) - return PPMD7_SYM_ERROR; - - count = RC_GetThreshold(freqSum); - - if (count < hiCnt) - { - Byte sym; - - s = Ppmd7_GetStats(p, p->MinContext); - hiCnt = count; - // count -= s->Freq & (UInt32)(MASK(s->Symbol)); - // if ((Int32)count >= 0) - { - for (;;) - { - count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; - // count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; - } - } - s--; - RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) - - // new (see->Summ) value can overflow over 16-bits in some rare cases - Ppmd_See_UPDATE(see) - p->FoundState = s; - sym = s->Symbol; - Ppmd7_Update2(p); - return sym; - } - - if (count >= freqSum) - return PPMD7_SYM_ERROR; - - RC_Decode(hiCnt, freqSum - hiCnt) - - // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. - // new (see->Summ) value can overflow over 16-bits in some rare cases - see->Summ = (UInt16)(see->Summ + freqSum); - - s = Ppmd7_GetStats(p, p->MinContext); - s2 = s + p->MinContext->NumStats; - do - { - MASK(s->Symbol) = 0; - s++; - } - while (s != s2); - } -} - -#undef kTop -#undef kBot -#undef READ_BYTE -#undef RC_NORM_BASE -#undef RC_NORM_1 -#undef RC_NORM -#undef RC_NORM_LOCAL -#undef RC_NORM_REMOTE -#undef R -#undef RC_Decode -#undef RC_DecodeFinal -#undef RC_GetThreshold -#undef CTX -#undef SUCCESSOR -#undef MASK +/* Ppmd7aDec.c -- PPMd7a (PPMdH) Decoder +2023-09-07 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd7.h" + +#define kTop ((UInt32)1 << 24) +#define kBot ((UInt32)1 << 15) + +#define READ_BYTE(p) IByteIn_Read((p)->Stream) + +BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + p->Low = 0; + + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | READ_BYTE(p); + return (p->Code < 0xFFFFFFFF); +} + +#define RC_NORM(p) \ + while ((p->Low ^ (p->Low + p->Range)) < kTop \ + || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \ + p->Code = (p->Code << 8) | READ_BYTE(p); \ + p->Range <<= 8; p->Low <<= 8; } + +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) + +#define R (&p->rc.dec) + +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd7a_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size) +{ + start *= R->Range; + R->Low += start; + R->Code -= start; + R->Range *= size; + RC_NORM_LOCAL(R) +} + +#define RC_Decode(start, size) Ppmd7a_RD_Decode(p, start, size); +#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) +#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) + + +#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) +typedef CPpmd7_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) +void Ppmd7_UpdateModel(CPpmd7 *p); + +#define MASK(sym) ((Byte *)charMask)[sym] + + +int Ppmd7a_DecodeSymbol(CPpmd7 *p) +{ + size_t charMask[256 / sizeof(size_t)]; + + if (p->MinContext->NumStats != 1) + { + CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + const UInt32 summFreq = p->MinContext->Union2.SummFreq; + + if (summFreq > R->Range) + return PPMD7_SYM_ERROR; + + count = RC_GetThreshold(summFreq); + hiCnt = count; + + if ((Int32)(count -= s->Freq) < 0) + { + Byte sym; + RC_DecodeFinal(0, s->Freq) + p->FoundState = s; + sym = s->Symbol; + Ppmd7_Update1_0(p); + return sym; + } + + p->PrevSuccess = 0; + i = (unsigned)p->MinContext->NumStats - 1; + + do + { + if ((Int32)(count -= (++s)->Freq) < 0) + { + Byte sym; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + p->FoundState = s; + sym = s->Symbol; + Ppmd7_Update1(p); + return sym; + } + } + while (--i); + + if (hiCnt >= summFreq) + return PPMD7_SYM_ERROR; + + hiCnt -= count; + RC_Decode(hiCnt, summFreq - hiCnt) + + p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol); + PPMD_SetAllBitsIn256Bytes(charMask) + // i = p->MinContext->NumStats - 1; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } + else + { + CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); + UInt16 *prob = Ppmd7_GetBinSumm(p); + UInt32 pr = *prob; + UInt32 size0 = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + + if (R->Code < size0) + { + Byte sym; + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + + // RangeDec_DecodeBit0(size0); + R->Range = size0; + RC_NORM(R) + + + + // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; + // Ppmd7_UpdateBin(p); + { + unsigned freq = s->Freq; + CTX_PTR c = CTX(SUCCESSOR(s)); + sym = s->Symbol; + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 128)); + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c > p->Text) + p->MaxContext = p->MinContext = c; + else + Ppmd7_UpdateModel(p); + } + return sym; + } + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + + // RangeDec_DecodeBit1(size0); + R->Low += size0; + R->Code -= size0; + R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0; + RC_NORM_LOCAL(R) + + PPMD_SetAllBitsIn256Bytes(charMask) + MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + + for (;;) + { + CPpmd_State *s, *s2; + UInt32 freqSum, count, hiCnt; + + CPpmd_See *see; + CPpmd7_Context *mc; + unsigned numMasked; + RC_NORM_REMOTE(R) + mc = p->MinContext; + numMasked = mc->NumStats; + + do + { + p->OrderFall++; + if (!mc->Suffix) + return PPMD7_SYM_END; + mc = Ppmd7_GetContext(p, mc->Suffix); + } + while (mc->NumStats == numMasked); + + s = Ppmd7_GetStats(p, mc); + + { + unsigned num = mc->NumStats; + unsigned num2 = num / 2; + + num &= 1; + hiCnt = (s->Freq & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num); + s += num; + p->MinContext = mc; + + do + { + const unsigned sym0 = s[0].Symbol; + const unsigned sym1 = s[1].Symbol; + s += 2; + hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0))); + hiCnt += (s[-1].Freq & (UInt32)(MASK(sym1))); + } + while (--num2); + } + + see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + + if (freqSum > R->Range) + return PPMD7_SYM_ERROR; + + count = RC_GetThreshold(freqSum); + + if (count < hiCnt) + { + Byte sym; + + s = Ppmd7_GetStats(p, p->MinContext); + hiCnt = count; + // count -= s->Freq & (UInt32)(MASK(s->Symbol)); + // if ((Int32)count >= 0) + { + for (;;) + { + count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + // count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + } + } + s--; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + + // new (see->Summ) value can overflow over 16-bits in some rare cases + Ppmd_See_UPDATE(see) + p->FoundState = s; + sym = s->Symbol; + Ppmd7_Update2(p); + return sym; + } + + if (count >= freqSum) + return PPMD7_SYM_ERROR; + + RC_Decode(hiCnt, freqSum - hiCnt) + + // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. + // new (see->Summ) value can overflow over 16-bits in some rare cases + see->Summ = (UInt16)(see->Summ + freqSum); + + s = Ppmd7_GetStats(p, p->MinContext); + s2 = s + p->MinContext->NumStats; + do + { + MASK(s->Symbol) = 0; + s++; + } + while (s != s2); + } +} + +#undef kTop +#undef kBot +#undef READ_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Decode +#undef RC_DecodeFinal +#undef RC_GetThreshold +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/C/Ppmd8.c b/C/Ppmd8.c index 2ac115808..c6bdd8673 100644 --- a/C/Ppmd8.c +++ b/C/Ppmd8.c @@ -1,1574 +1,1574 @@ -/* Ppmd8.c -- PPMdI codec -2023-09-07 : Igor Pavlov : Public domain -This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ - -#include "Precomp.h" - -#include - -#include "Ppmd8.h" - - - - -MY_ALIGN(16) -static const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -MY_ALIGN(16) -static const UInt16 PPMD8_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; - -#define MAX_FREQ 124 -#define UNIT_SIZE 12 - -#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) -#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) -#define I2U(indx) ((unsigned)p->Indx2Units[indx]) - - -#define REF(ptr) Ppmd_GetRef(p, ptr) - -#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) - -#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) -#define STATS(ctx) Ppmd8_GetStats(p, ctx) -#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) -#define SUFFIX(ctx) CTX((ctx)->Suffix) - -typedef CPpmd8_Context * PPMD8_CTX_PTR; - -struct CPpmd8_Node_; - -typedef Ppmd_Ref_Type(struct CPpmd8_Node_) CPpmd8_Node_Ref; - -typedef struct CPpmd8_Node_ -{ - UInt32 Stamp; - - CPpmd8_Node_Ref Next; - UInt32 NU; -} CPpmd8_Node; - -#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd8_Node) - -void Ppmd8_Construct(CPpmd8 *p) -{ - unsigned i, k, m; - - p->Base = NULL; - - for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) - { - unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); - do { p->Units2Indx[k++] = (Byte)i; } while (--step); - p->Indx2Units[i] = (Byte)k; - } - - p->NS2BSIndx[0] = (0 << 1); - p->NS2BSIndx[1] = (1 << 1); - memset(p->NS2BSIndx + 2, (2 << 1), 9); - memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); - - for (i = 0; i < 5; i++) - p->NS2Indx[i] = (Byte)i; - - for (m = i, k = 1; i < 260; i++) - { - p->NS2Indx[i] = (Byte)m; - if (--k == 0) - k = (++m) - 4; - } - - memcpy(p->ExpEscape, PPMD8_kExpEscape, 16); -} - - -void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->Base); - p->Size = 0; - p->Base = NULL; -} - - -BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc) -{ - if (!p->Base || p->Size != size) - { - Ppmd8_Free(p, alloc); - p->AlignOffset = (4 - size) & 3; - if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) - return False; - p->Size = size; - } - return True; -} - - - -// ---------- Internal Memory Allocator ---------- - - - - - - -#define EMPTY_NODE 0xFFFFFFFF - - -static void Ppmd8_InsertNode(CPpmd8 *p, void *node, unsigned indx) -{ - ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; - ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; - ((CPpmd8_Node *)node)->NU = I2U(indx); - p->FreeList[indx] = REF(node); - p->Stamps[indx]++; -} - - -static void *Ppmd8_RemoveNode(CPpmd8 *p, unsigned indx) -{ - CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); - p->FreeList[indx] = node->Next; - p->Stamps[indx]--; - - return node; -} - - -static void Ppmd8_SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) -{ - unsigned i, nu = I2U(oldIndx) - I2U(newIndx); - ptr = (Byte *)ptr + U2B(I2U(newIndx)); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - Ppmd8_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); - } - Ppmd8_InsertNode(p, ptr, i); -} - - - - - - - - - - - - - - -static void Ppmd8_GlueFreeBlocks(CPpmd8 *p) -{ - /* - we use first UInt32 field of 12-bytes UNITs as record type stamp - CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0xFF - CPpmd8_Context { Byte NumStats; Byte Flags; UInt16 SummFreq; : Flags != 0xFF ??? - CPpmd8_Node { UInt32 Stamp : Stamp == 0xFFFFFFFF for free record - : Stamp == 0 for guard - Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd8_Context record - */ - CPpmd8_Node_Ref n; - - p->GlueCount = 1 << 13; - memset(p->Stamps, 0, sizeof(p->Stamps)); - - /* we set guard NODE at LoUnit */ - if (p->LoUnit != p->HiUnit) - ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0; - - { - /* Glue free blocks */ - CPpmd8_Node_Ref *prev = &n; - unsigned i; - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - - CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; - p->FreeList[i] = 0; - while (next != 0) - { - CPpmd8_Node *node = NODE(next); - UInt32 nu = node->NU; - *prev = next; - next = node->Next; - if (nu != 0) - { - CPpmd8_Node *node2; - prev = &(node->Next); - while ((node2 = node + nu)->Stamp == EMPTY_NODE) - { - nu += node2->NU; - node2->NU = 0; - node->NU = nu; - } - } - } - } - - *prev = 0; - } - - - - - - - - - - - - - - - - - - - - - /* Fill lists of free blocks */ - while (n != 0) - { - CPpmd8_Node *node = NODE(n); - UInt32 nu = node->NU; - unsigned i; - n = node->Next; - if (nu == 0) - continue; - for (; nu > 128; nu -= 128, node += 128) - Ppmd8_InsertNode(p, node, PPMD_NUM_INDEXES - 1); - if (I2U(i = U2I(nu)) != nu) - { - unsigned k = I2U(--i); - Ppmd8_InsertNode(p, node + k, (unsigned)nu - k - 1); - } - Ppmd8_InsertNode(p, node, i); - } -} - - -Z7_NO_INLINE -static void *Ppmd8_AllocUnitsRare(CPpmd8 *p, unsigned indx) -{ - unsigned i; - - if (p->GlueCount == 0) - { - Ppmd8_GlueFreeBlocks(p); - if (p->FreeList[indx] != 0) - return Ppmd8_RemoveNode(p, indx); - } - - i = indx; - - do - { - if (++i == PPMD_NUM_INDEXES) - { - UInt32 numBytes = U2B(I2U(indx)); - Byte *us = p->UnitsStart; - p->GlueCount--; - return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : (NULL); - } - } - while (p->FreeList[i] == 0); - - { - void *block = Ppmd8_RemoveNode(p, i); - Ppmd8_SplitBlock(p, block, i, indx); - return block; - } -} - - -static void *Ppmd8_AllocUnits(CPpmd8 *p, unsigned indx) -{ - if (p->FreeList[indx] != 0) - return Ppmd8_RemoveNode(p, indx); - { - UInt32 numBytes = U2B(I2U(indx)); - Byte *lo = p->LoUnit; - if ((UInt32)(p->HiUnit - lo) >= numBytes) - { - p->LoUnit = lo + numBytes; - return lo; - } - } - return Ppmd8_AllocUnitsRare(p, indx); -} - - -#define MEM_12_CPY(dest, src, num) \ - { UInt32 *d = (UInt32 *)(dest); \ - const UInt32 *z = (const UInt32 *)(src); \ - unsigned n = (num); \ - do { \ - d[0] = z[0]; \ - d[1] = z[1]; \ - d[2] = z[2]; \ - z += 3; \ - d += 3; \ - } while (--n); \ - } - - - -static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) -{ - unsigned i0 = U2I(oldNU); - unsigned i1 = U2I(newNU); - if (i0 == i1) - return oldPtr; - if (p->FreeList[i1] != 0) - { - void *ptr = Ppmd8_RemoveNode(p, i1); - MEM_12_CPY(ptr, oldPtr, newNU) - Ppmd8_InsertNode(p, oldPtr, i0); - return ptr; - } - Ppmd8_SplitBlock(p, oldPtr, i0, i1); - return oldPtr; -} - - -static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) -{ - Ppmd8_InsertNode(p, ptr, U2I(nu)); -} - - -static void SpecialFreeUnit(CPpmd8 *p, void *ptr) -{ - if ((Byte *)ptr != p->UnitsStart) - Ppmd8_InsertNode(p, ptr, 0); - else - { - #ifdef PPMD8_FREEZE_SUPPORT - *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts() */ - #endif - p->UnitsStart += UNIT_SIZE; - } -} - - -/* -static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) -{ - unsigned indx = U2I(nu); - void *ptr; - if ((Byte *)oldPtr > p->UnitsStart + (1 << 14) || REF(oldPtr) > p->FreeList[indx]) - return oldPtr; - ptr = Ppmd8_RemoveNode(p, indx); - MEM_12_CPY(ptr, oldPtr, nu) - if ((Byte *)oldPtr != p->UnitsStart) - Ppmd8_InsertNode(p, oldPtr, indx); - else - p->UnitsStart += U2B(I2U(indx)); - return ptr; -} -*/ - -static void ExpandTextArea(CPpmd8 *p) -{ - UInt32 count[PPMD_NUM_INDEXES]; - unsigned i; - - memset(count, 0, sizeof(count)); - if (p->LoUnit != p->HiUnit) - ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0; - - { - CPpmd8_Node *node = (CPpmd8_Node *)(void *)p->UnitsStart; - while (node->Stamp == EMPTY_NODE) - { - UInt32 nu = node->NU; - node->Stamp = 0; - count[U2I(nu)]++; - node += nu; - } - p->UnitsStart = (Byte *)node; - } - - for (i = 0; i < PPMD_NUM_INDEXES; i++) - { - UInt32 cnt = count[i]; - if (cnt == 0) - continue; - { - CPpmd8_Node_Ref *prev = (CPpmd8_Node_Ref *)&p->FreeList[i]; - CPpmd8_Node_Ref n = *prev; - p->Stamps[i] -= cnt; - for (;;) - { - CPpmd8_Node *node = NODE(n); - n = node->Next; - if (node->Stamp != 0) - { - prev = &node->Next; - continue; - } - *prev = n; - if (--cnt == 0) - break; - } - } - } -} - - -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) -static void Ppmd8State_SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) -{ - Ppmd_SET_SUCCESSOR(p, v) -} - -#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } - -Z7_NO_INLINE -static -void Ppmd8_RestartModel(CPpmd8 *p) -{ - unsigned i, k, m; - - memset(p->FreeList, 0, sizeof(p->FreeList)); - memset(p->Stamps, 0, sizeof(p->Stamps)); - RESET_TEXT(0) - p->HiUnit = p->Text + p->Size; - p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; - p->GlueCount = 0; - - p->OrderFall = p->MaxOrder; - p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; - p->PrevSuccess = 0; - - { - CPpmd8_Context *mc = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ - CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd8_AllocUnits(p, PPMD_NUM_INDEXES - 1); */ - - p->LoUnit += U2B(256 / 2); - p->MaxContext = p->MinContext = mc; - p->FoundState = s; - mc->Flags = 0; - mc->NumStats = 256 - 1; - mc->Union2.SummFreq = 256 + 1; - mc->Union4.Stats = REF(s); - mc->Suffix = 0; - - for (i = 0; i < 256; i++, s++) - { - s->Symbol = (Byte)i; - s->Freq = 1; - Ppmd8State_SetSuccessor(s, 0); - } - } - - - - - - - - - - - - - for (i = m = 0; m < 25; m++) - { - while (p->NS2Indx[i] == m) - i++; - for (k = 0; k < 8; k++) - { - unsigned r; - UInt16 *dest = p->BinSumm[m] + k; - const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD8_kInitBinEsc[k] / (i + 1)); - for (r = 0; r < 64; r += 8) - dest[r] = val; - } - } - - for (i = m = 0; m < 24; m++) - { - unsigned summ; - CPpmd_See *s; - while (p->NS2Indx[(size_t)i + 3] == m + 3) - i++; - s = p->See[m]; - summ = ((2 * i + 5) << (PPMD_PERIOD_BITS - 4)); - for (k = 0; k < 32; k++, s++) - { - s->Summ = (UInt16)summ; - s->Shift = (PPMD_PERIOD_BITS - 4); - s->Count = 7; - } - } - - p->DummySee.Summ = 0; /* unused */ - p->DummySee.Shift = PPMD_PERIOD_BITS; - p->DummySee.Count = 64; /* unused */ -} - - -void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) -{ - p->MaxOrder = maxOrder; - p->RestoreMethod = restoreMethod; - Ppmd8_RestartModel(p); -} - - -#define FLAG_RESCALED (1 << 2) -// #define FLAG_SYM_HIGH (1 << 3) -#define FLAG_PREV_HIGH (1 << 4) - -#define HiBits_Prepare(sym) ((unsigned)(sym) + 0xC0) - -#define HiBits_Convert_3(flags) (((flags) >> (8 - 3)) & (1 << 3)) -#define HiBits_Convert_4(flags) (((flags) >> (8 - 4)) & (1 << 4)) - -#define PPMD8_HiBitsFlag_3(sym) HiBits_Convert_3(HiBits_Prepare(sym)) -#define PPMD8_HiBitsFlag_4(sym) HiBits_Convert_4(HiBits_Prepare(sym)) - -// #define PPMD8_HiBitsFlag_3(sym) (0x08 * ((sym) >= 0x40)) -// #define PPMD8_HiBitsFlag_4(sym) (0x10 * ((sym) >= 0x40)) - -/* -Refresh() is called when we remove some symbols (successors) in context. -It increases Escape_Freq for sum of all removed symbols. -*/ - -static void Refresh(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned oldNU, unsigned scale) -{ - unsigned i = ctx->NumStats, escFreq, sumFreq, flags; - CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); - ctx->Union4.Stats = REF(s); - - // #ifdef PPMD8_FREEZE_SUPPORT - /* - (ctx->Union2.SummFreq >= ((UInt32)1 << 15)) can be in FREEZE mode for some files. - It's not good for range coder. So new versions of support fix: - - original PPMdI code rev.1 - + original PPMdI code rev.2 - - 7-Zip default ((PPMD8_FREEZE_SUPPORT is not defined) - + 7-Zip (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE) - if we use that fixed line, we can lose compatibility with some files created before fix - if we don't use that fixed line, the program can work incorrectly in FREEZE mode in rare case. - */ - // if (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE) - { - scale |= (ctx->Union2.SummFreq >= ((UInt32)1 << 15)); - } - // #endif - - - - flags = HiBits_Prepare(s->Symbol); - { - unsigned freq = s->Freq; - escFreq = ctx->Union2.SummFreq - freq; - freq = (freq + scale) >> scale; - sumFreq = freq; - s->Freq = (Byte)freq; - } - - do - { - unsigned freq = (++s)->Freq; - escFreq -= freq; - freq = (freq + scale) >> scale; - sumFreq += freq; - s->Freq = (Byte)freq; - flags |= HiBits_Prepare(s->Symbol); - } - while (--i); - - ctx->Union2.SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); - ctx->Flags = (Byte)((ctx->Flags & (FLAG_PREV_HIGH + FLAG_RESCALED * scale)) + HiBits_Convert_3(flags)); -} - - -static void SWAP_STATES(CPpmd_State *t1, CPpmd_State *t2) -{ - CPpmd_State tmp = *t1; - *t1 = *t2; - *t2 = tmp; -} - - -/* -CutOff() reduces contexts: - It conversts Successors at MaxOrder to another Contexts to NULL-Successors - It removes RAW-Successors and NULL-Successors that are not Order-0 - and it removes contexts when it has no Successors. - if the (Union4.Stats) is close to (UnitsStart), it moves it up. -*/ - -static CPpmd_Void_Ref CutOff(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order) -{ - int ns = ctx->NumStats; - unsigned nu; - CPpmd_State *stats; - - if (ns == 0) - { - CPpmd_State *s = ONE_STATE(ctx); - CPpmd_Void_Ref successor = SUCCESSOR(s); - if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart) - { - if (order < p->MaxOrder) - successor = CutOff(p, CTX(successor), order + 1); - else - successor = 0; - Ppmd8State_SetSuccessor(s, successor); - if (successor || order <= 9) /* O_BOUND */ - return REF(ctx); - } - SpecialFreeUnit(p, ctx); - return 0; - } - - nu = ((unsigned)ns + 2) >> 1; - // ctx->Union4.Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), nu)); - { - unsigned indx = U2I(nu); - stats = STATS(ctx); - - if ((UInt32)((Byte *)stats - p->UnitsStart) <= (1 << 14) - && (CPpmd_Void_Ref)ctx->Union4.Stats <= p->FreeList[indx]) - { - void *ptr = Ppmd8_RemoveNode(p, indx); - ctx->Union4.Stats = STATS_REF(ptr); - MEM_12_CPY(ptr, (const void *)stats, nu) - if ((Byte *)stats != p->UnitsStart) - Ppmd8_InsertNode(p, stats, indx); - else - p->UnitsStart += U2B(I2U(indx)); - stats = ptr; - } - } - - { - CPpmd_State *s = stats + (unsigned)ns; - do - { - CPpmd_Void_Ref successor = SUCCESSOR(s); - if ((Byte *)Ppmd8_GetPtr(p, successor) < p->UnitsStart) - { - CPpmd_State *s2 = stats + (unsigned)(ns--); - if (order) - { - if (s != s2) - *s = *s2; - } - else - { - SWAP_STATES(s, s2); - Ppmd8State_SetSuccessor(s2, 0); - } - } - else - { - if (order < p->MaxOrder) - Ppmd8State_SetSuccessor(s, CutOff(p, CTX(successor), order + 1)); - else - Ppmd8State_SetSuccessor(s, 0); - } - } - while (--s >= stats); - } - - if (ns != ctx->NumStats && order) - { - if (ns < 0) - { - FreeUnits(p, stats, nu); - SpecialFreeUnit(p, ctx); - return 0; - } - ctx->NumStats = (Byte)ns; - if (ns == 0) - { - const Byte sym = stats->Symbol; - ctx->Flags = (Byte)((ctx->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(sym)); - // *ONE_STATE(ctx) = *stats; - ctx->Union2.State2.Symbol = sym; - ctx->Union2.State2.Freq = (Byte)(((unsigned)stats->Freq + 11) >> 3); - ctx->Union4.State4.Successor_0 = stats->Successor_0; - ctx->Union4.State4.Successor_1 = stats->Successor_1; - FreeUnits(p, stats, nu); - } - else - { - Refresh(p, ctx, nu, ctx->Union2.SummFreq > 16 * (unsigned)ns); - } - } - - return REF(ctx); -} - - - -#ifdef PPMD8_FREEZE_SUPPORT - -/* -RemoveBinContexts() - It conversts Successors at MaxOrder to another Contexts to NULL-Successors - It changes RAW-Successors to NULL-Successors - removes Bin Context without Successor, if suffix of that context is also binary. -*/ - -static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order) -{ - if (!ctx->NumStats) - { - CPpmd_State *s = ONE_STATE(ctx); - CPpmd_Void_Ref successor = SUCCESSOR(s); - if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder) - successor = RemoveBinContexts(p, CTX(successor), order + 1); - else - successor = 0; - Ppmd8State_SetSuccessor(s, successor); - /* Suffix context can be removed already, since different (high-order) - Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ - if (!successor && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) - { - FreeUnits(p, ctx, 1); - return 0; - } - } - else - { - CPpmd_State *s = STATS(ctx) + ctx->NumStats; - do - { - CPpmd_Void_Ref successor = SUCCESSOR(s); - if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder) - Ppmd8State_SetSuccessor(s, RemoveBinContexts(p, CTX(successor), order + 1)); - else - Ppmd8State_SetSuccessor(s, 0); - } - while (--s >= STATS(ctx)); - } - - return REF(ctx); -} - -#endif - - - -static UInt32 GetUsedMemory(const CPpmd8 *p) -{ - UInt32 v = 0; - unsigned i; - for (i = 0; i < PPMD_NUM_INDEXES; i++) - v += p->Stamps[i] * I2U(i); - return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); -} - -#ifdef PPMD8_FREEZE_SUPPORT - #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) -#else - #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) -#endif - - -static void RestoreModel(CPpmd8 *p, PPMD8_CTX_PTR ctxError - #ifdef PPMD8_FREEZE_SUPPORT - , PPMD8_CTX_PTR fSuccessor - #endif - ) -{ - PPMD8_CTX_PTR c; - CPpmd_State *s; - RESET_TEXT(0) - - // we go here in cases of error of allocation for context (c1) - // Order(MinContext) < Order(ctxError) <= Order(MaxContext) - - // We remove last symbol from each of contexts [p->MaxContext ... ctxError) contexts - // So we rollback all created (symbols) before error. - for (c = p->MaxContext; c != ctxError; c = SUFFIX(c)) - if (--(c->NumStats) == 0) - { - s = STATS(c); - c->Flags = (Byte)((c->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(s->Symbol)); - // *ONE_STATE(c) = *s; - c->Union2.State2.Symbol = s->Symbol; - c->Union2.State2.Freq = (Byte)(((unsigned)s->Freq + 11) >> 3); - c->Union4.State4.Successor_0 = s->Successor_0; - c->Union4.State4.Successor_1 = s->Successor_1; - - SpecialFreeUnit(p, s); - } - else - { - /* Refresh() can increase Escape_Freq on value of Freq of last symbol, that was added before error. - so the largest possible increase for Escape_Freq is (8) from value before ModelUpoadet() */ - Refresh(p, c, ((unsigned)c->NumStats + 3) >> 1, 0); - } - - // increase Escape Freq for context [ctxError ... p->MinContext) - for (; c != p->MinContext; c = SUFFIX(c)) - if (c->NumStats == 0) - { - // ONE_STATE(c) - c->Union2.State2.Freq = (Byte)(((unsigned)c->Union2.State2.Freq + 1) >> 1); - } - else if ((c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 4)) > 128 + 4 * c->NumStats) - Refresh(p, c, ((unsigned)c->NumStats + 2) >> 1, 1); - - #ifdef PPMD8_FREEZE_SUPPORT - if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - p->MaxContext = fSuccessor; - p->GlueCount += !(p->Stamps[1] & 1); // why? - } - else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) - { - while (p->MaxContext->Suffix) - p->MaxContext = SUFFIX(p->MaxContext); - RemoveBinContexts(p, p->MaxContext, 0); - // we change the current mode to (PPMD8_RESTORE_METHOD_FREEZE + 1) - p->RestoreMethod = PPMD8_RESTORE_METHOD_FREEZE + 1; - p->GlueCount = 0; - p->OrderFall = p->MaxOrder; - } - else - #endif - if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) - Ppmd8_RestartModel(p); - else - { - while (p->MaxContext->Suffix) - p->MaxContext = SUFFIX(p->MaxContext); - do - { - CutOff(p, p->MaxContext, 0); - ExpandTextArea(p); - } - while (GetUsedMemory(p) > 3 * (p->Size >> 2)); - p->GlueCount = 0; - p->OrderFall = p->MaxOrder; - } - p->MinContext = p->MaxContext; -} - - - -Z7_NO_INLINE -static PPMD8_CTX_PTR Ppmd8_CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, PPMD8_CTX_PTR c) -{ - - CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); - Byte newSym, newFreq, flags; - unsigned numPs = 0; - CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ - - if (!skip) - ps[numPs++] = p->FoundState; - - while (c->Suffix) - { - CPpmd_Void_Ref successor; - CPpmd_State *s; - c = SUFFIX(c); - - if (s1) { s = s1; s1 = NULL; } - else if (c->NumStats != 0) - { - Byte sym = p->FoundState->Symbol; - for (s = STATS(c); s->Symbol != sym; s++); - if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; } - } - else - { - s = ONE_STATE(c); - s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); - } - successor = SUCCESSOR(s); - if (successor != upBranch) - { - - c = CTX(successor); - if (numPs == 0) - { - - - return c; - } - break; - } - ps[numPs++] = s; - } - - - - - - newSym = *(const Byte *)Ppmd8_GetPtr(p, upBranch); - upBranch++; - flags = (Byte)(PPMD8_HiBitsFlag_4(p->FoundState->Symbol) + PPMD8_HiBitsFlag_3(newSym)); - - if (c->NumStats == 0) - newFreq = c->Union2.State2.Freq; - else - { - UInt32 cf, s0; - CPpmd_State *s; - for (s = STATS(c); s->Symbol != newSym; s++); - cf = (UInt32)s->Freq - 1; - s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; - /* - - - max(newFreq)= (s->Freq - 1), when (s0 == 1) - - - */ - newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); - } - - - - do - { - PPMD8_CTX_PTR c1; - /* = AllocContext(p); */ - if (p->HiUnit != p->LoUnit) - c1 = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); - else if (p->FreeList[0] != 0) - c1 = (PPMD8_CTX_PTR)Ppmd8_RemoveNode(p, 0); - else - { - c1 = (PPMD8_CTX_PTR)Ppmd8_AllocUnitsRare(p, 0); - if (!c1) - return NULL; - } - c1->Flags = flags; - c1->NumStats = 0; - c1->Union2.State2.Symbol = newSym; - c1->Union2.State2.Freq = newFreq; - Ppmd8State_SetSuccessor(ONE_STATE(c1), upBranch); - c1->Suffix = REF(c); - Ppmd8State_SetSuccessor(ps[--numPs], REF(c1)); - c = c1; - } - while (numPs != 0); - - return c; -} - - -static PPMD8_CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, PPMD8_CTX_PTR c) -{ - CPpmd_State *s = NULL; - PPMD8_CTX_PTR c1 = c; - CPpmd_Void_Ref upBranch = REF(p->Text); - - #ifdef PPMD8_FREEZE_SUPPORT - /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ - CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; - unsigned numPs = 0; - ps[numPs++] = p->FoundState; - #endif - - Ppmd8State_SetSuccessor(p->FoundState, upBranch); - p->OrderFall++; - - for (;;) - { - if (s1) - { - c = SUFFIX(c); - s = s1; - s1 = NULL; - } - else - { - if (!c->Suffix) - { - #ifdef PPMD8_FREEZE_SUPPORT - if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs); - RESET_TEXT(1) - p->OrderFall = 1; - } - #endif - return c; - } - c = SUFFIX(c); - if (c->NumStats) - { - if ((s = STATS(c))->Symbol != p->FoundState->Symbol) - do { s++; } while (s->Symbol != p->FoundState->Symbol); - if (s->Freq < MAX_FREQ - 9) - { - s->Freq = (Byte)(s->Freq + 2); - c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); - } - } - else - { - s = ONE_STATE(c); - s->Freq = (Byte)(s->Freq + (s->Freq < 32)); - } - } - if (SUCCESSOR(s)) - break; - #ifdef PPMD8_FREEZE_SUPPORT - ps[numPs++] = s; - #endif - Ppmd8State_SetSuccessor(s, upBranch); - p->OrderFall++; - } - - #ifdef PPMD8_FREEZE_SUPPORT - if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - c = CTX(SUCCESSOR(s)); - do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs); - RESET_TEXT(1) - p->OrderFall = 1; - return c; - } - else - #endif - if (SUCCESSOR(s) <= upBranch) - { - PPMD8_CTX_PTR successor; - CPpmd_State *s2 = p->FoundState; - p->FoundState = s; - - successor = Ppmd8_CreateSuccessors(p, False, NULL, c); - if (!successor) - Ppmd8State_SetSuccessor(s, 0); - else - Ppmd8State_SetSuccessor(s, REF(successor)); - p->FoundState = s2; - } - - { - CPpmd_Void_Ref successor = SUCCESSOR(s); - if (p->OrderFall == 1 && c1 == p->MaxContext) - { - Ppmd8State_SetSuccessor(p->FoundState, successor); - p->Text--; - } - if (successor == 0) - return NULL; - return CTX(successor); - } -} - - - -void Ppmd8_UpdateModel(CPpmd8 *p); -Z7_NO_INLINE -void Ppmd8_UpdateModel(CPpmd8 *p) -{ - CPpmd_Void_Ref maxSuccessor, minSuccessor = SUCCESSOR(p->FoundState); - PPMD8_CTX_PTR c; - unsigned s0, ns, fFreq = p->FoundState->Freq; - Byte flag, fSymbol = p->FoundState->Symbol; - { - CPpmd_State *s = NULL; - if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) - { - /* Update Freqs in Suffix Context */ - - c = SUFFIX(p->MinContext); - - if (c->NumStats == 0) - { - s = ONE_STATE(c); - if (s->Freq < 32) - s->Freq++; - } - else - { - Byte sym = p->FoundState->Symbol; - s = STATS(c); - - if (s->Symbol != sym) - { - do - { - - s++; - } - while (s->Symbol != sym); - - if (s[0].Freq >= s[-1].Freq) - { - SWAP_STATES(&s[0], &s[-1]); - s--; - } - } - - if (s->Freq < MAX_FREQ - 9) - { - s->Freq = (Byte)(s->Freq + 2); - c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); - } - } - } - - c = p->MaxContext; - if (p->OrderFall == 0 && minSuccessor) - { - PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, True, s, p->MinContext); - if (!cs) - { - Ppmd8State_SetSuccessor(p->FoundState, 0); - RESTORE_MODEL(c, CTX(minSuccessor)); - return; - } - Ppmd8State_SetSuccessor(p->FoundState, REF(cs)); - p->MinContext = p->MaxContext = cs; - return; - } - - - - - { - Byte *text = p->Text; - *text++ = p->FoundState->Symbol; - p->Text = text; - if (text >= p->UnitsStart) - { - RESTORE_MODEL(c, CTX(minSuccessor)); /* check it */ - return; - } - maxSuccessor = REF(text); - } - - if (!minSuccessor) - { - PPMD8_CTX_PTR cs = ReduceOrder(p, s, p->MinContext); - if (!cs) - { - RESTORE_MODEL(c, NULL); - return; - } - minSuccessor = REF(cs); - } - else if ((Byte *)Ppmd8_GetPtr(p, minSuccessor) < p->UnitsStart) - { - PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, False, s, p->MinContext); - if (!cs) - { - RESTORE_MODEL(c, NULL); - return; - } - minSuccessor = REF(cs); - } - - if (--p->OrderFall == 0) - { - maxSuccessor = minSuccessor; - p->Text -= (p->MaxContext != p->MinContext); - } - #ifdef PPMD8_FREEZE_SUPPORT - else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) - { - maxSuccessor = minSuccessor; - RESET_TEXT(0) - p->OrderFall = 0; - } - #endif - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - flag = (Byte)(PPMD8_HiBitsFlag_3(fSymbol)); - s0 = p->MinContext->Union2.SummFreq - (ns = p->MinContext->NumStats) - fFreq; - - for (; c != p->MinContext; c = SUFFIX(c)) - { - unsigned ns1; - UInt32 sum; - - if ((ns1 = c->NumStats) != 0) - { - if ((ns1 & 1) != 0) - { - /* Expand for one UNIT */ - const unsigned oldNU = (ns1 + 1) >> 1; - const unsigned i = U2I(oldNU); - if (i != U2I((size_t)oldNU + 1)) - { - void *ptr = Ppmd8_AllocUnits(p, i + 1); - void *oldPtr; - if (!ptr) - { - RESTORE_MODEL(c, CTX(minSuccessor)); - return; - } - oldPtr = STATS(c); - MEM_12_CPY(ptr, oldPtr, oldNU) - Ppmd8_InsertNode(p, oldPtr, i); - c->Union4.Stats = STATS_REF(ptr); - } - } - sum = c->Union2.SummFreq; - /* max increase of Escape_Freq is 1 here. - an average increase is 1/3 per symbol */ - sum += (UInt32)(unsigned)(3 * ns1 + 1 < ns); - /* original PPMdH uses 16-bit variable for (sum) here. - But (sum < ???). Do we need to truncate (sum) to 16-bit */ - // sum = (UInt16)sum; - } - else - { - - CPpmd_State *s = (CPpmd_State*)Ppmd8_AllocUnits(p, 0); - if (!s) - { - RESTORE_MODEL(c, CTX(minSuccessor)); - return; - } - { - unsigned freq = c->Union2.State2.Freq; - // s = *ONE_STATE(c); - s->Symbol = c->Union2.State2.Symbol; - s->Successor_0 = c->Union4.State4.Successor_0; - s->Successor_1 = c->Union4.State4.Successor_1; - // Ppmd8State_SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of - // (Successor_0 and Successor_1) in LE/BE. - c->Union4.Stats = REF(s); - if (freq < MAX_FREQ / 4 - 1) - freq <<= 1; - else - freq = MAX_FREQ - 4; - - s->Freq = (Byte)freq; - - sum = (UInt32)(freq + p->InitEsc + (ns > 2)); // Ppmd8 (> 2) - } - } - - { - CPpmd_State *s = STATS(c) + ns1 + 1; - UInt32 cf = 2 * (sum + 6) * (UInt32)fFreq; - UInt32 sf = (UInt32)s0 + sum; - s->Symbol = fSymbol; - c->NumStats = (Byte)(ns1 + 1); - Ppmd8State_SetSuccessor(s, maxSuccessor); - c->Flags |= flag; - if (cf < 6 * sf) - { - cf = (unsigned)1 + (cf > sf) + (cf >= 4 * sf); - sum += 4; - /* It can add (1, 2, 3) to Escape_Freq */ - } - else - { - cf = (unsigned)4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); - sum += cf; - } - - c->Union2.SummFreq = (UInt16)sum; - s->Freq = (Byte)cf; - } - - } - p->MaxContext = p->MinContext = CTX(minSuccessor); -} - - - -Z7_NO_INLINE -static void Ppmd8_Rescale(CPpmd8 *p) -{ - unsigned i, adder, sumFreq, escFreq; - CPpmd_State *stats = STATS(p->MinContext); - CPpmd_State *s = p->FoundState; - - /* Sort the list by Freq */ - if (s != stats) - { - CPpmd_State tmp = *s; - do - s[0] = s[-1]; - while (--s != stats); - *s = tmp; - } - - sumFreq = s->Freq; - escFreq = p->MinContext->Union2.SummFreq - sumFreq; - - - - - - - adder = (p->OrderFall != 0); - - #ifdef PPMD8_FREEZE_SUPPORT - adder |= (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE); - #endif - - sumFreq = (sumFreq + 4 + adder) >> 1; - i = p->MinContext->NumStats; - s->Freq = (Byte)sumFreq; - - do - { - unsigned freq = (++s)->Freq; - escFreq -= freq; - freq = (freq + adder) >> 1; - sumFreq += freq; - s->Freq = (Byte)freq; - if (freq > s[-1].Freq) - { - CPpmd_State tmp = *s; - CPpmd_State *s1 = s; - do - { - s1[0] = s1[-1]; - } - while (--s1 != stats && freq > s1[-1].Freq); - *s1 = tmp; - } - } - while (--i); - - if (s->Freq == 0) - { - /* Remove all items with Freq == 0 */ - CPpmd8_Context *mc; - unsigned numStats, numStatsNew, n0, n1; - - i = 0; do { i++; } while ((--s)->Freq == 0); - - - - - escFreq += i; - mc = p->MinContext; - numStats = mc->NumStats; - numStatsNew = numStats - i; - mc->NumStats = (Byte)(numStatsNew); - n0 = (numStats + 2) >> 1; - - if (numStatsNew == 0) - { - - unsigned freq = (2 * (unsigned)stats->Freq + escFreq - 1) / escFreq; - if (freq > MAX_FREQ / 3) - freq = MAX_FREQ / 3; - mc->Flags = (Byte)((mc->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(stats->Symbol)); - - - - - - s = ONE_STATE(mc); - *s = *stats; - s->Freq = (Byte)freq; - p->FoundState = s; - Ppmd8_InsertNode(p, stats, U2I(n0)); - return; - } - - n1 = (numStatsNew + 2) >> 1; - if (n0 != n1) - mc->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); - { - // here we are for max order only. So Ppmd8_MakeEscFreq() doesn't use mc->Flags - // but we still need current (Flags & FLAG_PREV_HIGH), if we will convert context to 1-symbol context later. - /* - unsigned flags = HiBits_Prepare((s = STATS(mc))->Symbol); - i = mc->NumStats; - do { flags |= HiBits_Prepare((++s)->Symbol); } while (--i); - mc->Flags = (Byte)((mc->Flags & ~FLAG_SYM_HIGH) + HiBits_Convert_3(flags)); - */ - } - } - - - - - - - { - CPpmd8_Context *mc = p->MinContext; - mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); - mc->Flags |= FLAG_RESCALED; - p->FoundState = STATS(mc); - } -} - - -CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) -{ - CPpmd_See *see; - const CPpmd8_Context *mc = p->MinContext; - unsigned numStats = mc->NumStats; - if (numStats != 0xFF) - { - // (3 <= numStats + 2 <= 256) (3 <= NS2Indx[3] and NS2Indx[256] === 26) - see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)numStats + 2] - 3] - + (mc->Union2.SummFreq > 11 * (numStats + 1)) - + 2 * (unsigned)(2 * numStats < ((unsigned)SUFFIX(mc)->NumStats + numMasked1)) - + mc->Flags; - - { - // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ - const unsigned summ = (UInt16)see->Summ; // & 0xFFFF - const unsigned r = (summ >> see->Shift); - see->Summ = (UInt16)(summ - r); - *escFreq = (UInt32)(r + (r == 0)); - } - } - else - { - see = &p->DummySee; - *escFreq = 1; - } - return see; -} - - -static void Ppmd8_NextContext(CPpmd8 *p) -{ - PPMD8_CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); - if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) - p->MaxContext = p->MinContext = c; - else - Ppmd8_UpdateModel(p); -} - - -void Ppmd8_Update1(CPpmd8 *p) -{ - CPpmd_State *s = p->FoundState; - unsigned freq = s->Freq; - freq += 4; - p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); - s->Freq = (Byte)freq; - if (freq > s[-1].Freq) - { - SWAP_STATES(s, &s[-1]); - p->FoundState = --s; - if (freq > MAX_FREQ) - Ppmd8_Rescale(p); - } - Ppmd8_NextContext(p); -} - - -void Ppmd8_Update1_0(CPpmd8 *p) -{ - CPpmd_State *s = p->FoundState; - CPpmd8_Context *mc = p->MinContext; - unsigned freq = s->Freq; - const unsigned summFreq = mc->Union2.SummFreq; - p->PrevSuccess = (2 * freq >= summFreq); // Ppmd8 (>=) - p->RunLength += (Int32)p->PrevSuccess; - mc->Union2.SummFreq = (UInt16)(summFreq + 4); - freq += 4; - s->Freq = (Byte)freq; - if (freq > MAX_FREQ) - Ppmd8_Rescale(p); - Ppmd8_NextContext(p); -} - - -/* -void Ppmd8_UpdateBin(CPpmd8 *p) -{ - unsigned freq = p->FoundState->Freq; - p->FoundState->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) - p->PrevSuccess = 1; - p->RunLength++; - Ppmd8_NextContext(p); -} -*/ - -void Ppmd8_Update2(CPpmd8 *p) -{ - CPpmd_State *s = p->FoundState; - unsigned freq = s->Freq; - freq += 4; - p->RunLength = p->InitRL; - p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); - s->Freq = (Byte)freq; - if (freq > MAX_FREQ) - Ppmd8_Rescale(p); - Ppmd8_UpdateModel(p); -} - -/* H->I changes: - NS2Indx - GlueCount, and Glue method - BinSum - See / EscFreq - Ppmd8_CreateSuccessors updates more suffix contexts - Ppmd8_UpdateModel consts. - PrevSuccess Update - -Flags: - (1 << 2) - the Context was Rescaled - (1 << 3) - there is symbol in Stats with (sym >= 0x40) in - (1 << 4) - main symbol of context is (sym >= 0x40) -*/ - -#undef RESET_TEXT -#undef FLAG_RESCALED -#undef FLAG_PREV_HIGH -#undef HiBits_Prepare -#undef HiBits_Convert_3 -#undef HiBits_Convert_4 -#undef PPMD8_HiBitsFlag_3 -#undef PPMD8_HiBitsFlag_4 -#undef RESTORE_MODEL - -#undef MAX_FREQ -#undef UNIT_SIZE -#undef U2B -#undef U2I -#undef I2U - -#undef REF -#undef STATS_REF -#undef CTX -#undef STATS -#undef ONE_STATE -#undef SUFFIX -#undef NODE -#undef EMPTY_NODE -#undef MEM_12_CPY -#undef SUCCESSOR -#undef SWAP_STATES +/* Ppmd8.c -- PPMdI codec +2023-09-07 : Igor Pavlov : Public domain +This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ + +#include "Precomp.h" + +#include + +#include "Ppmd8.h" + + + + +MY_ALIGN(16) +static const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +MY_ALIGN(16) +static const UInt16 PPMD8_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; + +#define MAX_FREQ 124 +#define UNIT_SIZE 12 + +#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) +#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1]) +#define I2U(indx) ((unsigned)p->Indx2Units[indx]) + + +#define REF(ptr) Ppmd_GetRef(p, ptr) + +#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) + +#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) +#define STATS(ctx) Ppmd8_GetStats(p, ctx) +#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) +#define SUFFIX(ctx) CTX((ctx)->Suffix) + +typedef CPpmd8_Context * PPMD8_CTX_PTR; + +struct CPpmd8_Node_; + +typedef Ppmd_Ref_Type(struct CPpmd8_Node_) CPpmd8_Node_Ref; + +typedef struct CPpmd8_Node_ +{ + UInt32 Stamp; + + CPpmd8_Node_Ref Next; + UInt32 NU; +} CPpmd8_Node; + +#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd8_Node) + +void Ppmd8_Construct(CPpmd8 *p) +{ + unsigned i, k, m; + + p->Base = NULL; + + for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) + { + unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); + p->Indx2Units[i] = (Byte)k; + } + + p->NS2BSIndx[0] = (0 << 1); + p->NS2BSIndx[1] = (1 << 1); + memset(p->NS2BSIndx + 2, (2 << 1), 9); + memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); + + for (i = 0; i < 5; i++) + p->NS2Indx[i] = (Byte)i; + + for (m = i, k = 1; i < 260; i++) + { + p->NS2Indx[i] = (Byte)m; + if (--k == 0) + k = (++m) - 4; + } + + memcpy(p->ExpEscape, PPMD8_kExpEscape, 16); +} + + +void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->Base); + p->Size = 0; + p->Base = NULL; +} + + +BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc) +{ + if (!p->Base || p->Size != size) + { + Ppmd8_Free(p, alloc); + p->AlignOffset = (4 - size) & 3; + if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL) + return False; + p->Size = size; + } + return True; +} + + + +// ---------- Internal Memory Allocator ---------- + + + + + + +#define EMPTY_NODE 0xFFFFFFFF + + +static void Ppmd8_InsertNode(CPpmd8 *p, void *node, unsigned indx) +{ + ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; + ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; + ((CPpmd8_Node *)node)->NU = I2U(indx); + p->FreeList[indx] = REF(node); + p->Stamps[indx]++; +} + + +static void *Ppmd8_RemoveNode(CPpmd8 *p, unsigned indx) +{ + CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); + p->FreeList[indx] = node->Next; + p->Stamps[indx]--; + + return node; +} + + +static void Ppmd8_SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) +{ + unsigned i, nu = I2U(oldIndx) - I2U(newIndx); + ptr = (Byte *)ptr + U2B(I2U(newIndx)); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + Ppmd8_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); + } + Ppmd8_InsertNode(p, ptr, i); +} + + + + + + + + + + + + + + +static void Ppmd8_GlueFreeBlocks(CPpmd8 *p) +{ + /* + we use first UInt32 field of 12-bytes UNITs as record type stamp + CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0xFF + CPpmd8_Context { Byte NumStats; Byte Flags; UInt16 SummFreq; : Flags != 0xFF ??? + CPpmd8_Node { UInt32 Stamp : Stamp == 0xFFFFFFFF for free record + : Stamp == 0 for guard + Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd8_Context record + */ + CPpmd8_Node_Ref n; + + p->GlueCount = 1 << 13; + memset(p->Stamps, 0, sizeof(p->Stamps)); + + /* we set guard NODE at LoUnit */ + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0; + + { + /* Glue free blocks */ + CPpmd8_Node_Ref *prev = &n; + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + + CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; + p->FreeList[i] = 0; + while (next != 0) + { + CPpmd8_Node *node = NODE(next); + UInt32 nu = node->NU; + *prev = next; + next = node->Next; + if (nu != 0) + { + CPpmd8_Node *node2; + prev = &(node->Next); + while ((node2 = node + nu)->Stamp == EMPTY_NODE) + { + nu += node2->NU; + node2->NU = 0; + node->NU = nu; + } + } + } + } + + *prev = 0; + } + + + + + + + + + + + + + + + + + + + + + /* Fill lists of free blocks */ + while (n != 0) + { + CPpmd8_Node *node = NODE(n); + UInt32 nu = node->NU; + unsigned i; + n = node->Next; + if (nu == 0) + continue; + for (; nu > 128; nu -= 128, node += 128) + Ppmd8_InsertNode(p, node, PPMD_NUM_INDEXES - 1); + if (I2U(i = U2I(nu)) != nu) + { + unsigned k = I2U(--i); + Ppmd8_InsertNode(p, node + k, (unsigned)nu - k - 1); + } + Ppmd8_InsertNode(p, node, i); + } +} + + +Z7_NO_INLINE +static void *Ppmd8_AllocUnitsRare(CPpmd8 *p, unsigned indx) +{ + unsigned i; + + if (p->GlueCount == 0) + { + Ppmd8_GlueFreeBlocks(p); + if (p->FreeList[indx] != 0) + return Ppmd8_RemoveNode(p, indx); + } + + i = indx; + + do + { + if (++i == PPMD_NUM_INDEXES) + { + UInt32 numBytes = U2B(I2U(indx)); + Byte *us = p->UnitsStart; + p->GlueCount--; + return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : (NULL); + } + } + while (p->FreeList[i] == 0); + + { + void *block = Ppmd8_RemoveNode(p, i); + Ppmd8_SplitBlock(p, block, i, indx); + return block; + } +} + + +static void *Ppmd8_AllocUnits(CPpmd8 *p, unsigned indx) +{ + if (p->FreeList[indx] != 0) + return Ppmd8_RemoveNode(p, indx); + { + UInt32 numBytes = U2B(I2U(indx)); + Byte *lo = p->LoUnit; + if ((UInt32)(p->HiUnit - lo) >= numBytes) + { + p->LoUnit = lo + numBytes; + return lo; + } + } + return Ppmd8_AllocUnitsRare(p, indx); +} + + +#define MEM_12_CPY(dest, src, num) \ + { UInt32 *d = (UInt32 *)(dest); \ + const UInt32 *z = (const UInt32 *)(src); \ + unsigned n = (num); \ + do { \ + d[0] = z[0]; \ + d[1] = z[1]; \ + d[2] = z[2]; \ + z += 3; \ + d += 3; \ + } while (--n); \ + } + + + +static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) +{ + unsigned i0 = U2I(oldNU); + unsigned i1 = U2I(newNU); + if (i0 == i1) + return oldPtr; + if (p->FreeList[i1] != 0) + { + void *ptr = Ppmd8_RemoveNode(p, i1); + MEM_12_CPY(ptr, oldPtr, newNU) + Ppmd8_InsertNode(p, oldPtr, i0); + return ptr; + } + Ppmd8_SplitBlock(p, oldPtr, i0, i1); + return oldPtr; +} + + +static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) +{ + Ppmd8_InsertNode(p, ptr, U2I(nu)); +} + + +static void SpecialFreeUnit(CPpmd8 *p, void *ptr) +{ + if ((Byte *)ptr != p->UnitsStart) + Ppmd8_InsertNode(p, ptr, 0); + else + { + #ifdef PPMD8_FREEZE_SUPPORT + *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts() */ + #endif + p->UnitsStart += UNIT_SIZE; + } +} + + +/* +static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) +{ + unsigned indx = U2I(nu); + void *ptr; + if ((Byte *)oldPtr > p->UnitsStart + (1 << 14) || REF(oldPtr) > p->FreeList[indx]) + return oldPtr; + ptr = Ppmd8_RemoveNode(p, indx); + MEM_12_CPY(ptr, oldPtr, nu) + if ((Byte *)oldPtr != p->UnitsStart) + Ppmd8_InsertNode(p, oldPtr, indx); + else + p->UnitsStart += U2B(I2U(indx)); + return ptr; +} +*/ + +static void ExpandTextArea(CPpmd8 *p) +{ + UInt32 count[PPMD_NUM_INDEXES]; + unsigned i; + + memset(count, 0, sizeof(count)); + if (p->LoUnit != p->HiUnit) + ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0; + + { + CPpmd8_Node *node = (CPpmd8_Node *)(void *)p->UnitsStart; + while (node->Stamp == EMPTY_NODE) + { + UInt32 nu = node->NU; + node->Stamp = 0; + count[U2I(nu)]++; + node += nu; + } + p->UnitsStart = (Byte *)node; + } + + for (i = 0; i < PPMD_NUM_INDEXES; i++) + { + UInt32 cnt = count[i]; + if (cnt == 0) + continue; + { + CPpmd8_Node_Ref *prev = (CPpmd8_Node_Ref *)&p->FreeList[i]; + CPpmd8_Node_Ref n = *prev; + p->Stamps[i] -= cnt; + for (;;) + { + CPpmd8_Node *node = NODE(n); + n = node->Next; + if (node->Stamp != 0) + { + prev = &node->Next; + continue; + } + *prev = n; + if (--cnt == 0) + break; + } + } + } +} + + +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) +static void Ppmd8State_SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) +{ + Ppmd_SET_SUCCESSOR(p, v) +} + +#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } + +Z7_NO_INLINE +static +void Ppmd8_RestartModel(CPpmd8 *p) +{ + unsigned i, k, m; + + memset(p->FreeList, 0, sizeof(p->FreeList)); + memset(p->Stamps, 0, sizeof(p->Stamps)); + RESET_TEXT(0) + p->HiUnit = p->Text + p->Size; + p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; + p->GlueCount = 0; + + p->OrderFall = p->MaxOrder; + p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; + p->PrevSuccess = 0; + + { + CPpmd8_Context *mc = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ + CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd8_AllocUnits(p, PPMD_NUM_INDEXES - 1); */ + + p->LoUnit += U2B(256 / 2); + p->MaxContext = p->MinContext = mc; + p->FoundState = s; + mc->Flags = 0; + mc->NumStats = 256 - 1; + mc->Union2.SummFreq = 256 + 1; + mc->Union4.Stats = REF(s); + mc->Suffix = 0; + + for (i = 0; i < 256; i++, s++) + { + s->Symbol = (Byte)i; + s->Freq = 1; + Ppmd8State_SetSuccessor(s, 0); + } + } + + + + + + + + + + + + + for (i = m = 0; m < 25; m++) + { + while (p->NS2Indx[i] == m) + i++; + for (k = 0; k < 8; k++) + { + unsigned r; + UInt16 *dest = p->BinSumm[m] + k; + const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD8_kInitBinEsc[k] / (i + 1)); + for (r = 0; r < 64; r += 8) + dest[r] = val; + } + } + + for (i = m = 0; m < 24; m++) + { + unsigned summ; + CPpmd_See *s; + while (p->NS2Indx[(size_t)i + 3] == m + 3) + i++; + s = p->See[m]; + summ = ((2 * i + 5) << (PPMD_PERIOD_BITS - 4)); + for (k = 0; k < 32; k++, s++) + { + s->Summ = (UInt16)summ; + s->Shift = (PPMD_PERIOD_BITS - 4); + s->Count = 7; + } + } + + p->DummySee.Summ = 0; /* unused */ + p->DummySee.Shift = PPMD_PERIOD_BITS; + p->DummySee.Count = 64; /* unused */ +} + + +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) +{ + p->MaxOrder = maxOrder; + p->RestoreMethod = restoreMethod; + Ppmd8_RestartModel(p); +} + + +#define FLAG_RESCALED (1 << 2) +// #define FLAG_SYM_HIGH (1 << 3) +#define FLAG_PREV_HIGH (1 << 4) + +#define HiBits_Prepare(sym) ((unsigned)(sym) + 0xC0) + +#define HiBits_Convert_3(flags) (((flags) >> (8 - 3)) & (1 << 3)) +#define HiBits_Convert_4(flags) (((flags) >> (8 - 4)) & (1 << 4)) + +#define PPMD8_HiBitsFlag_3(sym) HiBits_Convert_3(HiBits_Prepare(sym)) +#define PPMD8_HiBitsFlag_4(sym) HiBits_Convert_4(HiBits_Prepare(sym)) + +// #define PPMD8_HiBitsFlag_3(sym) (0x08 * ((sym) >= 0x40)) +// #define PPMD8_HiBitsFlag_4(sym) (0x10 * ((sym) >= 0x40)) + +/* +Refresh() is called when we remove some symbols (successors) in context. +It increases Escape_Freq for sum of all removed symbols. +*/ + +static void Refresh(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned oldNU, unsigned scale) +{ + unsigned i = ctx->NumStats, escFreq, sumFreq, flags; + CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); + ctx->Union4.Stats = REF(s); + + // #ifdef PPMD8_FREEZE_SUPPORT + /* + (ctx->Union2.SummFreq >= ((UInt32)1 << 15)) can be in FREEZE mode for some files. + It's not good for range coder. So new versions of support fix: + - original PPMdI code rev.1 + + original PPMdI code rev.2 + - 7-Zip default ((PPMD8_FREEZE_SUPPORT is not defined) + + 7-Zip (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE) + if we use that fixed line, we can lose compatibility with some files created before fix + if we don't use that fixed line, the program can work incorrectly in FREEZE mode in rare case. + */ + // if (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE) + { + scale |= (ctx->Union2.SummFreq >= ((UInt32)1 << 15)); + } + // #endif + + + + flags = HiBits_Prepare(s->Symbol); + { + unsigned freq = s->Freq; + escFreq = ctx->Union2.SummFreq - freq; + freq = (freq + scale) >> scale; + sumFreq = freq; + s->Freq = (Byte)freq; + } + + do + { + unsigned freq = (++s)->Freq; + escFreq -= freq; + freq = (freq + scale) >> scale; + sumFreq += freq; + s->Freq = (Byte)freq; + flags |= HiBits_Prepare(s->Symbol); + } + while (--i); + + ctx->Union2.SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); + ctx->Flags = (Byte)((ctx->Flags & (FLAG_PREV_HIGH + FLAG_RESCALED * scale)) + HiBits_Convert_3(flags)); +} + + +static void SWAP_STATES(CPpmd_State *t1, CPpmd_State *t2) +{ + CPpmd_State tmp = *t1; + *t1 = *t2; + *t2 = tmp; +} + + +/* +CutOff() reduces contexts: + It conversts Successors at MaxOrder to another Contexts to NULL-Successors + It removes RAW-Successors and NULL-Successors that are not Order-0 + and it removes contexts when it has no Successors. + if the (Union4.Stats) is close to (UnitsStart), it moves it up. +*/ + +static CPpmd_Void_Ref CutOff(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order) +{ + int ns = ctx->NumStats; + unsigned nu; + CPpmd_State *stats; + + if (ns == 0) + { + CPpmd_State *s = ONE_STATE(ctx); + CPpmd_Void_Ref successor = SUCCESSOR(s); + if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart) + { + if (order < p->MaxOrder) + successor = CutOff(p, CTX(successor), order + 1); + else + successor = 0; + Ppmd8State_SetSuccessor(s, successor); + if (successor || order <= 9) /* O_BOUND */ + return REF(ctx); + } + SpecialFreeUnit(p, ctx); + return 0; + } + + nu = ((unsigned)ns + 2) >> 1; + // ctx->Union4.Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), nu)); + { + unsigned indx = U2I(nu); + stats = STATS(ctx); + + if ((UInt32)((Byte *)stats - p->UnitsStart) <= (1 << 14) + && (CPpmd_Void_Ref)ctx->Union4.Stats <= p->FreeList[indx]) + { + void *ptr = Ppmd8_RemoveNode(p, indx); + ctx->Union4.Stats = STATS_REF(ptr); + MEM_12_CPY(ptr, (const void *)stats, nu) + if ((Byte *)stats != p->UnitsStart) + Ppmd8_InsertNode(p, stats, indx); + else + p->UnitsStart += U2B(I2U(indx)); + stats = ptr; + } + } + + { + CPpmd_State *s = stats + (unsigned)ns; + do + { + CPpmd_Void_Ref successor = SUCCESSOR(s); + if ((Byte *)Ppmd8_GetPtr(p, successor) < p->UnitsStart) + { + CPpmd_State *s2 = stats + (unsigned)(ns--); + if (order) + { + if (s != s2) + *s = *s2; + } + else + { + SWAP_STATES(s, s2); + Ppmd8State_SetSuccessor(s2, 0); + } + } + else + { + if (order < p->MaxOrder) + Ppmd8State_SetSuccessor(s, CutOff(p, CTX(successor), order + 1)); + else + Ppmd8State_SetSuccessor(s, 0); + } + } + while (--s >= stats); + } + + if (ns != ctx->NumStats && order) + { + if (ns < 0) + { + FreeUnits(p, stats, nu); + SpecialFreeUnit(p, ctx); + return 0; + } + ctx->NumStats = (Byte)ns; + if (ns == 0) + { + const Byte sym = stats->Symbol; + ctx->Flags = (Byte)((ctx->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(sym)); + // *ONE_STATE(ctx) = *stats; + ctx->Union2.State2.Symbol = sym; + ctx->Union2.State2.Freq = (Byte)(((unsigned)stats->Freq + 11) >> 3); + ctx->Union4.State4.Successor_0 = stats->Successor_0; + ctx->Union4.State4.Successor_1 = stats->Successor_1; + FreeUnits(p, stats, nu); + } + else + { + Refresh(p, ctx, nu, ctx->Union2.SummFreq > 16 * (unsigned)ns); + } + } + + return REF(ctx); +} + + + +#ifdef PPMD8_FREEZE_SUPPORT + +/* +RemoveBinContexts() + It conversts Successors at MaxOrder to another Contexts to NULL-Successors + It changes RAW-Successors to NULL-Successors + removes Bin Context without Successor, if suffix of that context is also binary. +*/ + +static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order) +{ + if (!ctx->NumStats) + { + CPpmd_State *s = ONE_STATE(ctx); + CPpmd_Void_Ref successor = SUCCESSOR(s); + if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder) + successor = RemoveBinContexts(p, CTX(successor), order + 1); + else + successor = 0; + Ppmd8State_SetSuccessor(s, successor); + /* Suffix context can be removed already, since different (high-order) + Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ + if (!successor && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) + { + FreeUnits(p, ctx, 1); + return 0; + } + } + else + { + CPpmd_State *s = STATS(ctx) + ctx->NumStats; + do + { + CPpmd_Void_Ref successor = SUCCESSOR(s); + if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder) + Ppmd8State_SetSuccessor(s, RemoveBinContexts(p, CTX(successor), order + 1)); + else + Ppmd8State_SetSuccessor(s, 0); + } + while (--s >= STATS(ctx)); + } + + return REF(ctx); +} + +#endif + + + +static UInt32 GetUsedMemory(const CPpmd8 *p) +{ + UInt32 v = 0; + unsigned i; + for (i = 0; i < PPMD_NUM_INDEXES; i++) + v += p->Stamps[i] * I2U(i); + return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); +} + +#ifdef PPMD8_FREEZE_SUPPORT + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) +#else + #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) +#endif + + +static void RestoreModel(CPpmd8 *p, PPMD8_CTX_PTR ctxError + #ifdef PPMD8_FREEZE_SUPPORT + , PPMD8_CTX_PTR fSuccessor + #endif + ) +{ + PPMD8_CTX_PTR c; + CPpmd_State *s; + RESET_TEXT(0) + + // we go here in cases of error of allocation for context (c1) + // Order(MinContext) < Order(ctxError) <= Order(MaxContext) + + // We remove last symbol from each of contexts [p->MaxContext ... ctxError) contexts + // So we rollback all created (symbols) before error. + for (c = p->MaxContext; c != ctxError; c = SUFFIX(c)) + if (--(c->NumStats) == 0) + { + s = STATS(c); + c->Flags = (Byte)((c->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(s->Symbol)); + // *ONE_STATE(c) = *s; + c->Union2.State2.Symbol = s->Symbol; + c->Union2.State2.Freq = (Byte)(((unsigned)s->Freq + 11) >> 3); + c->Union4.State4.Successor_0 = s->Successor_0; + c->Union4.State4.Successor_1 = s->Successor_1; + + SpecialFreeUnit(p, s); + } + else + { + /* Refresh() can increase Escape_Freq on value of Freq of last symbol, that was added before error. + so the largest possible increase for Escape_Freq is (8) from value before ModelUpoadet() */ + Refresh(p, c, ((unsigned)c->NumStats + 3) >> 1, 0); + } + + // increase Escape Freq for context [ctxError ... p->MinContext) + for (; c != p->MinContext; c = SUFFIX(c)) + if (c->NumStats == 0) + { + // ONE_STATE(c) + c->Union2.State2.Freq = (Byte)(((unsigned)c->Union2.State2.Freq + 1) >> 1); + } + else if ((c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 4)) > 128 + 4 * c->NumStats) + Refresh(p, c, ((unsigned)c->NumStats + 2) >> 1, 1); + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + p->MaxContext = fSuccessor; + p->GlueCount += !(p->Stamps[1] & 1); // why? + } + else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + RemoveBinContexts(p, p->MaxContext, 0); + // we change the current mode to (PPMD8_RESTORE_METHOD_FREEZE + 1) + p->RestoreMethod = PPMD8_RESTORE_METHOD_FREEZE + 1; + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } + else + #endif + if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) + Ppmd8_RestartModel(p); + else + { + while (p->MaxContext->Suffix) + p->MaxContext = SUFFIX(p->MaxContext); + do + { + CutOff(p, p->MaxContext, 0); + ExpandTextArea(p); + } + while (GetUsedMemory(p) > 3 * (p->Size >> 2)); + p->GlueCount = 0; + p->OrderFall = p->MaxOrder; + } + p->MinContext = p->MaxContext; +} + + + +Z7_NO_INLINE +static PPMD8_CTX_PTR Ppmd8_CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, PPMD8_CTX_PTR c) +{ + + CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); + Byte newSym, newFreq, flags; + unsigned numPs = 0; + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ + + if (!skip) + ps[numPs++] = p->FoundState; + + while (c->Suffix) + { + CPpmd_Void_Ref successor; + CPpmd_State *s; + c = SUFFIX(c); + + if (s1) { s = s1; s1 = NULL; } + else if (c->NumStats != 0) + { + Byte sym = p->FoundState->Symbol; + for (s = STATS(c); s->Symbol != sym; s++); + if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; } + } + else + { + s = ONE_STATE(c); + s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); + } + successor = SUCCESSOR(s); + if (successor != upBranch) + { + + c = CTX(successor); + if (numPs == 0) + { + + + return c; + } + break; + } + ps[numPs++] = s; + } + + + + + + newSym = *(const Byte *)Ppmd8_GetPtr(p, upBranch); + upBranch++; + flags = (Byte)(PPMD8_HiBitsFlag_4(p->FoundState->Symbol) + PPMD8_HiBitsFlag_3(newSym)); + + if (c->NumStats == 0) + newFreq = c->Union2.State2.Freq; + else + { + UInt32 cf, s0; + CPpmd_State *s; + for (s = STATS(c); s->Symbol != newSym; s++); + cf = (UInt32)s->Freq - 1; + s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf; + /* + + + max(newFreq)= (s->Freq - 1), when (s0 == 1) + + + */ + newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); + } + + + + do + { + PPMD8_CTX_PTR c1; + /* = AllocContext(p); */ + if (p->HiUnit != p->LoUnit) + c1 = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); + else if (p->FreeList[0] != 0) + c1 = (PPMD8_CTX_PTR)Ppmd8_RemoveNode(p, 0); + else + { + c1 = (PPMD8_CTX_PTR)Ppmd8_AllocUnitsRare(p, 0); + if (!c1) + return NULL; + } + c1->Flags = flags; + c1->NumStats = 0; + c1->Union2.State2.Symbol = newSym; + c1->Union2.State2.Freq = newFreq; + Ppmd8State_SetSuccessor(ONE_STATE(c1), upBranch); + c1->Suffix = REF(c); + Ppmd8State_SetSuccessor(ps[--numPs], REF(c1)); + c = c1; + } + while (numPs != 0); + + return c; +} + + +static PPMD8_CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, PPMD8_CTX_PTR c) +{ + CPpmd_State *s = NULL; + PPMD8_CTX_PTR c1 = c; + CPpmd_Void_Ref upBranch = REF(p->Text); + + #ifdef PPMD8_FREEZE_SUPPORT + /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ + CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; + unsigned numPs = 0; + ps[numPs++] = p->FoundState; + #endif + + Ppmd8State_SetSuccessor(p->FoundState, upBranch); + p->OrderFall++; + + for (;;) + { + if (s1) + { + c = SUFFIX(c); + s = s1; + s1 = NULL; + } + else + { + if (!c->Suffix) + { + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1) + p->OrderFall = 1; + } + #endif + return c; + } + c = SUFFIX(c); + if (c->NumStats) + { + if ((s = STATS(c))->Symbol != p->FoundState->Symbol) + do { s++; } while (s->Symbol != p->FoundState->Symbol); + if (s->Freq < MAX_FREQ - 9) + { + s->Freq = (Byte)(s->Freq + 2); + c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); + } + } + else + { + s = ONE_STATE(c); + s->Freq = (Byte)(s->Freq + (s->Freq < 32)); + } + } + if (SUCCESSOR(s)) + break; + #ifdef PPMD8_FREEZE_SUPPORT + ps[numPs++] = s; + #endif + Ppmd8State_SetSuccessor(s, upBranch); + p->OrderFall++; + } + + #ifdef PPMD8_FREEZE_SUPPORT + if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + c = CTX(SUCCESSOR(s)); + do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs); + RESET_TEXT(1) + p->OrderFall = 1; + return c; + } + else + #endif + if (SUCCESSOR(s) <= upBranch) + { + PPMD8_CTX_PTR successor; + CPpmd_State *s2 = p->FoundState; + p->FoundState = s; + + successor = Ppmd8_CreateSuccessors(p, False, NULL, c); + if (!successor) + Ppmd8State_SetSuccessor(s, 0); + else + Ppmd8State_SetSuccessor(s, REF(successor)); + p->FoundState = s2; + } + + { + CPpmd_Void_Ref successor = SUCCESSOR(s); + if (p->OrderFall == 1 && c1 == p->MaxContext) + { + Ppmd8State_SetSuccessor(p->FoundState, successor); + p->Text--; + } + if (successor == 0) + return NULL; + return CTX(successor); + } +} + + + +void Ppmd8_UpdateModel(CPpmd8 *p); +Z7_NO_INLINE +void Ppmd8_UpdateModel(CPpmd8 *p) +{ + CPpmd_Void_Ref maxSuccessor, minSuccessor = SUCCESSOR(p->FoundState); + PPMD8_CTX_PTR c; + unsigned s0, ns, fFreq = p->FoundState->Freq; + Byte flag, fSymbol = p->FoundState->Symbol; + { + CPpmd_State *s = NULL; + if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) + { + /* Update Freqs in Suffix Context */ + + c = SUFFIX(p->MinContext); + + if (c->NumStats == 0) + { + s = ONE_STATE(c); + if (s->Freq < 32) + s->Freq++; + } + else + { + Byte sym = p->FoundState->Symbol; + s = STATS(c); + + if (s->Symbol != sym) + { + do + { + + s++; + } + while (s->Symbol != sym); + + if (s[0].Freq >= s[-1].Freq) + { + SWAP_STATES(&s[0], &s[-1]); + s--; + } + } + + if (s->Freq < MAX_FREQ - 9) + { + s->Freq = (Byte)(s->Freq + 2); + c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2); + } + } + } + + c = p->MaxContext; + if (p->OrderFall == 0 && minSuccessor) + { + PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, True, s, p->MinContext); + if (!cs) + { + Ppmd8State_SetSuccessor(p->FoundState, 0); + RESTORE_MODEL(c, CTX(minSuccessor)); + return; + } + Ppmd8State_SetSuccessor(p->FoundState, REF(cs)); + p->MinContext = p->MaxContext = cs; + return; + } + + + + + { + Byte *text = p->Text; + *text++ = p->FoundState->Symbol; + p->Text = text; + if (text >= p->UnitsStart) + { + RESTORE_MODEL(c, CTX(minSuccessor)); /* check it */ + return; + } + maxSuccessor = REF(text); + } + + if (!minSuccessor) + { + PPMD8_CTX_PTR cs = ReduceOrder(p, s, p->MinContext); + if (!cs) + { + RESTORE_MODEL(c, NULL); + return; + } + minSuccessor = REF(cs); + } + else if ((Byte *)Ppmd8_GetPtr(p, minSuccessor) < p->UnitsStart) + { + PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, False, s, p->MinContext); + if (!cs) + { + RESTORE_MODEL(c, NULL); + return; + } + minSuccessor = REF(cs); + } + + if (--p->OrderFall == 0) + { + maxSuccessor = minSuccessor; + p->Text -= (p->MaxContext != p->MinContext); + } + #ifdef PPMD8_FREEZE_SUPPORT + else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) + { + maxSuccessor = minSuccessor; + RESET_TEXT(0) + p->OrderFall = 0; + } + #endif + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flag = (Byte)(PPMD8_HiBitsFlag_3(fSymbol)); + s0 = p->MinContext->Union2.SummFreq - (ns = p->MinContext->NumStats) - fFreq; + + for (; c != p->MinContext; c = SUFFIX(c)) + { + unsigned ns1; + UInt32 sum; + + if ((ns1 = c->NumStats) != 0) + { + if ((ns1 & 1) != 0) + { + /* Expand for one UNIT */ + const unsigned oldNU = (ns1 + 1) >> 1; + const unsigned i = U2I(oldNU); + if (i != U2I((size_t)oldNU + 1)) + { + void *ptr = Ppmd8_AllocUnits(p, i + 1); + void *oldPtr; + if (!ptr) + { + RESTORE_MODEL(c, CTX(minSuccessor)); + return; + } + oldPtr = STATS(c); + MEM_12_CPY(ptr, oldPtr, oldNU) + Ppmd8_InsertNode(p, oldPtr, i); + c->Union4.Stats = STATS_REF(ptr); + } + } + sum = c->Union2.SummFreq; + /* max increase of Escape_Freq is 1 here. + an average increase is 1/3 per symbol */ + sum += (UInt32)(unsigned)(3 * ns1 + 1 < ns); + /* original PPMdH uses 16-bit variable for (sum) here. + But (sum < ???). Do we need to truncate (sum) to 16-bit */ + // sum = (UInt16)sum; + } + else + { + + CPpmd_State *s = (CPpmd_State*)Ppmd8_AllocUnits(p, 0); + if (!s) + { + RESTORE_MODEL(c, CTX(minSuccessor)); + return; + } + { + unsigned freq = c->Union2.State2.Freq; + // s = *ONE_STATE(c); + s->Symbol = c->Union2.State2.Symbol; + s->Successor_0 = c->Union4.State4.Successor_0; + s->Successor_1 = c->Union4.State4.Successor_1; + // Ppmd8State_SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of + // (Successor_0 and Successor_1) in LE/BE. + c->Union4.Stats = REF(s); + if (freq < MAX_FREQ / 4 - 1) + freq <<= 1; + else + freq = MAX_FREQ - 4; + + s->Freq = (Byte)freq; + + sum = (UInt32)(freq + p->InitEsc + (ns > 2)); // Ppmd8 (> 2) + } + } + + { + CPpmd_State *s = STATS(c) + ns1 + 1; + UInt32 cf = 2 * (sum + 6) * (UInt32)fFreq; + UInt32 sf = (UInt32)s0 + sum; + s->Symbol = fSymbol; + c->NumStats = (Byte)(ns1 + 1); + Ppmd8State_SetSuccessor(s, maxSuccessor); + c->Flags |= flag; + if (cf < 6 * sf) + { + cf = (unsigned)1 + (cf > sf) + (cf >= 4 * sf); + sum += 4; + /* It can add (1, 2, 3) to Escape_Freq */ + } + else + { + cf = (unsigned)4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); + sum += cf; + } + + c->Union2.SummFreq = (UInt16)sum; + s->Freq = (Byte)cf; + } + + } + p->MaxContext = p->MinContext = CTX(minSuccessor); +} + + + +Z7_NO_INLINE +static void Ppmd8_Rescale(CPpmd8 *p) +{ + unsigned i, adder, sumFreq, escFreq; + CPpmd_State *stats = STATS(p->MinContext); + CPpmd_State *s = p->FoundState; + + /* Sort the list by Freq */ + if (s != stats) + { + CPpmd_State tmp = *s; + do + s[0] = s[-1]; + while (--s != stats); + *s = tmp; + } + + sumFreq = s->Freq; + escFreq = p->MinContext->Union2.SummFreq - sumFreq; + + + + + + + adder = (p->OrderFall != 0); + + #ifdef PPMD8_FREEZE_SUPPORT + adder |= (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE); + #endif + + sumFreq = (sumFreq + 4 + adder) >> 1; + i = p->MinContext->NumStats; + s->Freq = (Byte)sumFreq; + + do + { + unsigned freq = (++s)->Freq; + escFreq -= freq; + freq = (freq + adder) >> 1; + sumFreq += freq; + s->Freq = (Byte)freq; + if (freq > s[-1].Freq) + { + CPpmd_State tmp = *s; + CPpmd_State *s1 = s; + do + { + s1[0] = s1[-1]; + } + while (--s1 != stats && freq > s1[-1].Freq); + *s1 = tmp; + } + } + while (--i); + + if (s->Freq == 0) + { + /* Remove all items with Freq == 0 */ + CPpmd8_Context *mc; + unsigned numStats, numStatsNew, n0, n1; + + i = 0; do { i++; } while ((--s)->Freq == 0); + + + + + escFreq += i; + mc = p->MinContext; + numStats = mc->NumStats; + numStatsNew = numStats - i; + mc->NumStats = (Byte)(numStatsNew); + n0 = (numStats + 2) >> 1; + + if (numStatsNew == 0) + { + + unsigned freq = (2 * (unsigned)stats->Freq + escFreq - 1) / escFreq; + if (freq > MAX_FREQ / 3) + freq = MAX_FREQ / 3; + mc->Flags = (Byte)((mc->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(stats->Symbol)); + + + + + + s = ONE_STATE(mc); + *s = *stats; + s->Freq = (Byte)freq; + p->FoundState = s; + Ppmd8_InsertNode(p, stats, U2I(n0)); + return; + } + + n1 = (numStatsNew + 2) >> 1; + if (n0 != n1) + mc->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); + { + // here we are for max order only. So Ppmd8_MakeEscFreq() doesn't use mc->Flags + // but we still need current (Flags & FLAG_PREV_HIGH), if we will convert context to 1-symbol context later. + /* + unsigned flags = HiBits_Prepare((s = STATS(mc))->Symbol); + i = mc->NumStats; + do { flags |= HiBits_Prepare((++s)->Symbol); } while (--i); + mc->Flags = (Byte)((mc->Flags & ~FLAG_SYM_HIGH) + HiBits_Convert_3(flags)); + */ + } + } + + + + + + + { + CPpmd8_Context *mc = p->MinContext; + mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); + mc->Flags |= FLAG_RESCALED; + p->FoundState = STATS(mc); + } +} + + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) +{ + CPpmd_See *see; + const CPpmd8_Context *mc = p->MinContext; + unsigned numStats = mc->NumStats; + if (numStats != 0xFF) + { + // (3 <= numStats + 2 <= 256) (3 <= NS2Indx[3] and NS2Indx[256] === 26) + see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)numStats + 2] - 3] + + (mc->Union2.SummFreq > 11 * (numStats + 1)) + + 2 * (unsigned)(2 * numStats < ((unsigned)SUFFIX(mc)->NumStats + numMasked1)) + + mc->Flags; + + { + // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ + const unsigned summ = (UInt16)see->Summ; // & 0xFFFF + const unsigned r = (summ >> see->Shift); + see->Summ = (UInt16)(summ - r); + *escFreq = (UInt32)(r + (r == 0)); + } + } + else + { + see = &p->DummySee; + *escFreq = 1; + } + return see; +} + + +static void Ppmd8_NextContext(CPpmd8 *p) +{ + PPMD8_CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); + if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) + p->MaxContext = p->MinContext = c; + else + Ppmd8_UpdateModel(p); +} + + +void Ppmd8_Update1(CPpmd8 *p) +{ + CPpmd_State *s = p->FoundState; + unsigned freq = s->Freq; + freq += 4; + p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); + s->Freq = (Byte)freq; + if (freq > s[-1].Freq) + { + SWAP_STATES(s, &s[-1]); + p->FoundState = --s; + if (freq > MAX_FREQ) + Ppmd8_Rescale(p); + } + Ppmd8_NextContext(p); +} + + +void Ppmd8_Update1_0(CPpmd8 *p) +{ + CPpmd_State *s = p->FoundState; + CPpmd8_Context *mc = p->MinContext; + unsigned freq = s->Freq; + const unsigned summFreq = mc->Union2.SummFreq; + p->PrevSuccess = (2 * freq >= summFreq); // Ppmd8 (>=) + p->RunLength += (Int32)p->PrevSuccess; + mc->Union2.SummFreq = (UInt16)(summFreq + 4); + freq += 4; + s->Freq = (Byte)freq; + if (freq > MAX_FREQ) + Ppmd8_Rescale(p); + Ppmd8_NextContext(p); +} + + +/* +void Ppmd8_UpdateBin(CPpmd8 *p) +{ + unsigned freq = p->FoundState->Freq; + p->FoundState->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) + p->PrevSuccess = 1; + p->RunLength++; + Ppmd8_NextContext(p); +} +*/ + +void Ppmd8_Update2(CPpmd8 *p) +{ + CPpmd_State *s = p->FoundState; + unsigned freq = s->Freq; + freq += 4; + p->RunLength = p->InitRL; + p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4); + s->Freq = (Byte)freq; + if (freq > MAX_FREQ) + Ppmd8_Rescale(p); + Ppmd8_UpdateModel(p); +} + +/* H->I changes: + NS2Indx + GlueCount, and Glue method + BinSum + See / EscFreq + Ppmd8_CreateSuccessors updates more suffix contexts + Ppmd8_UpdateModel consts. + PrevSuccess Update + +Flags: + (1 << 2) - the Context was Rescaled + (1 << 3) - there is symbol in Stats with (sym >= 0x40) in + (1 << 4) - main symbol of context is (sym >= 0x40) +*/ + +#undef RESET_TEXT +#undef FLAG_RESCALED +#undef FLAG_PREV_HIGH +#undef HiBits_Prepare +#undef HiBits_Convert_3 +#undef HiBits_Convert_4 +#undef PPMD8_HiBitsFlag_3 +#undef PPMD8_HiBitsFlag_4 +#undef RESTORE_MODEL + +#undef MAX_FREQ +#undef UNIT_SIZE +#undef U2B +#undef U2I +#undef I2U + +#undef REF +#undef STATS_REF +#undef CTX +#undef STATS +#undef ONE_STATE +#undef SUFFIX +#undef NODE +#undef EMPTY_NODE +#undef MEM_12_CPY +#undef SUCCESSOR +#undef SWAP_STATES diff --git a/C/Ppmd8.h b/C/Ppmd8.h index 44943b857..d5bb57e15 100644 --- a/C/Ppmd8.h +++ b/C/Ppmd8.h @@ -1,181 +1,181 @@ -/* Ppmd8.h -- Ppmd8 (PPMdI) compression codec -2023-04-02 : Igor Pavlov : Public domain -This code is based on: - PPMd var.I (2002): Dmitry Shkarin : Public domain - Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#ifndef ZIP7_INC_PPMD8_H -#define ZIP7_INC_PPMD8_H - -#include "Ppmd.h" - -EXTERN_C_BEGIN - -#define PPMD8_MIN_ORDER 2 -#define PPMD8_MAX_ORDER 16 - - - - -struct CPpmd8_Context_; - -typedef Ppmd_Ref_Type(struct CPpmd8_Context_) CPpmd8_Context_Ref; - -// MY_CPU_pragma_pack_push_1 - -typedef struct CPpmd8_Context_ -{ - Byte NumStats; - Byte Flags; - - union - { - UInt16 SummFreq; - CPpmd_State2 State2; - } Union2; - - union - { - CPpmd_State_Ref Stats; - CPpmd_State4 State4; - } Union4; - - CPpmd8_Context_Ref Suffix; -} CPpmd8_Context; - -// MY_CPU_pragma_pop - -#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->Union2) - -/* PPMdI code rev.2 contains the fix over PPMdI code rev.1. - But the code PPMdI.2 is not compatible with PPMdI.1 for some files compressed - in FREEZE mode. So we disable FREEZE mode support. */ - -// #define PPMD8_FREEZE_SUPPORT - -enum -{ - PPMD8_RESTORE_METHOD_RESTART, - PPMD8_RESTORE_METHOD_CUT_OFF - #ifdef PPMD8_FREEZE_SUPPORT - , PPMD8_RESTORE_METHOD_FREEZE - #endif - , PPMD8_RESTORE_METHOD_UNSUPPPORTED -}; - - - - - - - - -typedef struct -{ - CPpmd8_Context *MinContext, *MaxContext; - CPpmd_State *FoundState; - unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, RestoreMethod; - Int32 RunLength, InitRL; /* must be 32-bit at least */ - - UInt32 Size; - UInt32 GlueCount; - UInt32 AlignOffset; - Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; - - UInt32 Range; - UInt32 Code; - UInt32 Low; - union - { - IByteInPtr In; - IByteOutPtr Out; - } Stream; - - Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment - Byte Units2Indx[128]; - CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; - UInt32 Stamps[PPMD_NUM_INDEXES]; - Byte NS2BSIndx[256], NS2Indx[260]; - Byte ExpEscape[16]; - CPpmd_See DummySee, See[24][32]; - UInt16 BinSumm[25][64]; - -} CPpmd8; - - -void Ppmd8_Construct(CPpmd8 *p); -BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc); -void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc); -void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); -#define Ppmd8_WasAllocated(p) ((p)->Base != NULL) - - -/* ---------- Internal Functions ---------- */ - -#define Ppmd8_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) -#define Ppmd8_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd8_Context) -#define Ppmd8_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) - -void Ppmd8_Update1(CPpmd8 *p); -void Ppmd8_Update1_0(CPpmd8 *p); -void Ppmd8_Update2(CPpmd8 *p); - - - - - - -#define Ppmd8_GetBinSumm(p) \ - &p->BinSumm[p->NS2Indx[(size_t)Ppmd8Context_OneState(p->MinContext)->Freq - 1]] \ - [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ - + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ - + p->MinContext->Flags ] - - -CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); - - -/* 20.01: the original PPMdI encoder and decoder probably could work incorrectly in some rare cases, - where the original PPMdI code can give "Divide by Zero" operation. - We use the following fix to allow correct working of encoder and decoder in any cases. - We correct (Escape_Freq) and (_sum_), if (_sum_) is larger than p->Range) */ -#define PPMD8_CORRECT_SUM_RANGE(p, _sum_) if (_sum_ > p->Range /* /1 */) _sum_ = p->Range; - - -/* ---------- Decode ---------- */ - -#define PPMD8_SYM_END (-1) -#define PPMD8_SYM_ERROR (-2) - -/* -You must set (CPpmd8::Stream.In) before Ppmd8_RangeDec_Init() - -Ppmd8_DecodeSymbol() -out: - >= 0 : decoded byte - -1 : PPMD8_SYM_END : End of payload marker - -2 : PPMD8_SYM_ERROR : Data error -*/ - - -BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p); -#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -int Ppmd8_DecodeSymbol(CPpmd8 *p); - - - - - - - - -/* ---------- Encode ---------- */ - -#define Ppmd8_Init_RangeEnc(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } -void Ppmd8_Flush_RangeEnc(CPpmd8 *p); -void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); - - -EXTERN_C_END - -#endif +/* Ppmd8.h -- Ppmd8 (PPMdI) compression codec +2023-04-02 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef ZIP7_INC_PPMD8_H +#define ZIP7_INC_PPMD8_H + +#include "Ppmd.h" + +EXTERN_C_BEGIN + +#define PPMD8_MIN_ORDER 2 +#define PPMD8_MAX_ORDER 16 + + + + +struct CPpmd8_Context_; + +typedef Ppmd_Ref_Type(struct CPpmd8_Context_) CPpmd8_Context_Ref; + +// MY_CPU_pragma_pack_push_1 + +typedef struct CPpmd8_Context_ +{ + Byte NumStats; + Byte Flags; + + union + { + UInt16 SummFreq; + CPpmd_State2 State2; + } Union2; + + union + { + CPpmd_State_Ref Stats; + CPpmd_State4 State4; + } Union4; + + CPpmd8_Context_Ref Suffix; +} CPpmd8_Context; + +// MY_CPU_pragma_pop + +#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->Union2) + +/* PPMdI code rev.2 contains the fix over PPMdI code rev.1. + But the code PPMdI.2 is not compatible with PPMdI.1 for some files compressed + in FREEZE mode. So we disable FREEZE mode support. */ + +// #define PPMD8_FREEZE_SUPPORT + +enum +{ + PPMD8_RESTORE_METHOD_RESTART, + PPMD8_RESTORE_METHOD_CUT_OFF + #ifdef PPMD8_FREEZE_SUPPORT + , PPMD8_RESTORE_METHOD_FREEZE + #endif + , PPMD8_RESTORE_METHOD_UNSUPPPORTED +}; + + + + + + + + +typedef struct +{ + CPpmd8_Context *MinContext, *MaxContext; + CPpmd_State *FoundState; + unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, RestoreMethod; + Int32 RunLength, InitRL; /* must be 32-bit at least */ + + UInt32 Size; + UInt32 GlueCount; + UInt32 AlignOffset; + Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; + + UInt32 Range; + UInt32 Code; + UInt32 Low; + union + { + IByteInPtr In; + IByteOutPtr Out; + } Stream; + + Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment + Byte Units2Indx[128]; + CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; + UInt32 Stamps[PPMD_NUM_INDEXES]; + Byte NS2BSIndx[256], NS2Indx[260]; + Byte ExpEscape[16]; + CPpmd_See DummySee, See[24][32]; + UInt16 BinSumm[25][64]; + +} CPpmd8; + + +void Ppmd8_Construct(CPpmd8 *p); +BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc); +void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc); +void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); +#define Ppmd8_WasAllocated(p) ((p)->Base != NULL) + + +/* ---------- Internal Functions ---------- */ + +#define Ppmd8_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr) +#define Ppmd8_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd8_Context) +#define Ppmd8_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State) + +void Ppmd8_Update1(CPpmd8 *p); +void Ppmd8_Update1_0(CPpmd8 *p); +void Ppmd8_Update2(CPpmd8 *p); + + + + + + +#define Ppmd8_GetBinSumm(p) \ + &p->BinSumm[p->NS2Indx[(size_t)Ppmd8Context_OneState(p->MinContext)->Freq - 1]] \ + [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \ + + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ + + p->MinContext->Flags ] + + +CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); + + +/* 20.01: the original PPMdI encoder and decoder probably could work incorrectly in some rare cases, + where the original PPMdI code can give "Divide by Zero" operation. + We use the following fix to allow correct working of encoder and decoder in any cases. + We correct (Escape_Freq) and (_sum_), if (_sum_) is larger than p->Range) */ +#define PPMD8_CORRECT_SUM_RANGE(p, _sum_) if (_sum_ > p->Range /* /1 */) _sum_ = p->Range; + + +/* ---------- Decode ---------- */ + +#define PPMD8_SYM_END (-1) +#define PPMD8_SYM_ERROR (-2) + +/* +You must set (CPpmd8::Stream.In) before Ppmd8_RangeDec_Init() + +Ppmd8_DecodeSymbol() +out: + >= 0 : decoded byte + -1 : PPMD8_SYM_END : End of payload marker + -2 : PPMD8_SYM_ERROR : Data error +*/ + + +BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p); +#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) +int Ppmd8_DecodeSymbol(CPpmd8 *p); + + + + + + + + +/* ---------- Encode ---------- */ + +#define Ppmd8_Init_RangeEnc(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } +void Ppmd8_Flush_RangeEnc(CPpmd8 *p); +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); + + +EXTERN_C_END + +#endif diff --git a/C/Ppmd8Dec.c b/C/Ppmd8Dec.c index 944d7d894..ff911674a 100644 --- a/C/Ppmd8Dec.c +++ b/C/Ppmd8Dec.c @@ -1,295 +1,295 @@ -/* Ppmd8Dec.c -- Ppmd8 (PPMdI) Decoder -2023-09-07 : Igor Pavlov : Public domain -This code is based on: - PPMd var.I (2002): Dmitry Shkarin : Public domain - Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#include "Precomp.h" - -#include "Ppmd8.h" - -#define kTop ((UInt32)1 << 24) -#define kBot ((UInt32)1 << 15) - -#define READ_BYTE(p) IByteIn_Read((p)->Stream.In) - -BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p) -{ - unsigned i; - p->Code = 0; - p->Range = 0xFFFFFFFF; - p->Low = 0; - - for (i = 0; i < 4; i++) - p->Code = (p->Code << 8) | READ_BYTE(p); - return (p->Code < 0xFFFFFFFF); -} - -#define RC_NORM(p) \ - while ((p->Low ^ (p->Low + p->Range)) < kTop \ - || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \ - p->Code = (p->Code << 8) | READ_BYTE(p); \ - p->Range <<= 8; p->Low <<= 8; } - -// we must use only one type of Normalization from two: LOCAL or REMOTE -#define RC_NORM_LOCAL(p) // RC_NORM(p) -#define RC_NORM_REMOTE(p) RC_NORM(p) - -#define R p - -Z7_FORCE_INLINE -// Z7_NO_INLINE -static void Ppmd8_RD_Decode(CPpmd8 *p, UInt32 start, UInt32 size) -{ - start *= R->Range; - R->Low += start; - R->Code -= start; - R->Range *= size; - RC_NORM_LOCAL(R) -} - -#define RC_Decode(start, size) Ppmd8_RD_Decode(p, start, size); -#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) -#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) - - -#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) -// typedef CPpmd8_Context * CTX_PTR; -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) -void Ppmd8_UpdateModel(CPpmd8 *p); - -#define MASK(sym) ((Byte *)charMask)[sym] - - -int Ppmd8_DecodeSymbol(CPpmd8 *p) -{ - size_t charMask[256 / sizeof(size_t)]; - - if (p->MinContext->NumStats != 0) - { - CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); - unsigned i; - UInt32 count, hiCnt; - UInt32 summFreq = p->MinContext->Union2.SummFreq; - - PPMD8_CORRECT_SUM_RANGE(p, summFreq) - - - count = RC_GetThreshold(summFreq); - hiCnt = count; - - if ((Int32)(count -= s->Freq) < 0) - { - Byte sym; - RC_DecodeFinal(0, s->Freq) - p->FoundState = s; - sym = s->Symbol; - Ppmd8_Update1_0(p); - return sym; - } - - p->PrevSuccess = 0; - i = p->MinContext->NumStats; - - do - { - if ((Int32)(count -= (++s)->Freq) < 0) - { - Byte sym; - RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) - p->FoundState = s; - sym = s->Symbol; - Ppmd8_Update1(p); - return sym; - } - } - while (--i); - - if (hiCnt >= summFreq) - return PPMD8_SYM_ERROR; - - hiCnt -= count; - RC_Decode(hiCnt, summFreq - hiCnt) - - - PPMD_SetAllBitsIn256Bytes(charMask) - // i = p->MinContext->NumStats - 1; - // do { MASK((--s)->Symbol) = 0; } while (--i); - { - CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } - else - { - CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); - UInt16 *prob = Ppmd8_GetBinSumm(p); - UInt32 pr = *prob; - UInt32 size0 = (R->Range >> 14) * pr; - pr = PPMD_UPDATE_PROB_1(pr); - - if (R->Code < size0) - { - Byte sym; - *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); - - // RangeDec_DecodeBit0(size0); - R->Range = size0; - RC_NORM(R) - - - - // sym = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; - // Ppmd8_UpdateBin(p); - { - unsigned freq = s->Freq; - CPpmd8_Context *c = CTX(SUCCESSOR(s)); - sym = s->Symbol; - p->FoundState = s; - p->PrevSuccess = 1; - p->RunLength++; - s->Freq = (Byte)(freq + (freq < 196)); - // NextContext(p); - if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) - p->MaxContext = p->MinContext = c; - else - Ppmd8_UpdateModel(p); - } - return sym; - } - - *prob = (UInt16)pr; - p->InitEsc = p->ExpEscape[pr >> 10]; - - // RangeDec_DecodeBit1(rc2, size0); - R->Low += size0; - R->Code -= size0; - R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0; - RC_NORM_LOCAL(R) - - PPMD_SetAllBitsIn256Bytes(charMask) - MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; - p->PrevSuccess = 0; - } - - for (;;) - { - CPpmd_State *s, *s2; - UInt32 freqSum, count, hiCnt; - UInt32 freqSum2; - CPpmd_See *see; - CPpmd8_Context *mc; - unsigned numMasked; - RC_NORM_REMOTE(R) - mc = p->MinContext; - numMasked = mc->NumStats; - - do - { - p->OrderFall++; - if (!mc->Suffix) - return PPMD8_SYM_END; - mc = Ppmd8_GetContext(p, mc->Suffix); - } - while (mc->NumStats == numMasked); - - s = Ppmd8_GetStats(p, mc); - - { - unsigned num = (unsigned)mc->NumStats + 1; - unsigned num2 = num / 2; - - num &= 1; - hiCnt = (s->Freq & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num); - s += num; - p->MinContext = mc; - - do - { - const unsigned sym0 = s[0].Symbol; - const unsigned sym1 = s[1].Symbol; - s += 2; - hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0))); - hiCnt += (s[-1].Freq & (UInt32)(MASK(sym1))); - } - while (--num2); - } - - see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); - freqSum += hiCnt; - freqSum2 = freqSum; - PPMD8_CORRECT_SUM_RANGE(R, freqSum2) - - - count = RC_GetThreshold(freqSum2); - - if (count < hiCnt) - { - Byte sym; - // Ppmd_See_UPDATE(see) // new (see->Summ) value can overflow over 16-bits in some rare cases - s = Ppmd8_GetStats(p, p->MinContext); - hiCnt = count; - - - { - for (;;) - { - count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; - // count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; - } - } - s--; - RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) - - // new (see->Summ) value can overflow over 16-bits in some rare cases - Ppmd_See_UPDATE(see) - p->FoundState = s; - sym = s->Symbol; - Ppmd8_Update2(p); - return sym; - } - - if (count >= freqSum2) - return PPMD8_SYM_ERROR; - - RC_Decode(hiCnt, freqSum2 - hiCnt) - - // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. - // new (see->Summ) value can overflow over 16-bits in some rare cases - see->Summ = (UInt16)(see->Summ + freqSum); - - s = Ppmd8_GetStats(p, p->MinContext); - s2 = s + p->MinContext->NumStats + 1; - do - { - MASK(s->Symbol) = 0; - s++; - } - while (s != s2); - } -} - -#undef kTop -#undef kBot -#undef READ_BYTE -#undef RC_NORM_BASE -#undef RC_NORM_1 -#undef RC_NORM -#undef RC_NORM_LOCAL -#undef RC_NORM_REMOTE -#undef R -#undef RC_Decode -#undef RC_DecodeFinal -#undef RC_GetThreshold -#undef CTX -#undef SUCCESSOR -#undef MASK +/* Ppmd8Dec.c -- Ppmd8 (PPMdI) Decoder +2023-09-07 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd8.h" + +#define kTop ((UInt32)1 << 24) +#define kBot ((UInt32)1 << 15) + +#define READ_BYTE(p) IByteIn_Read((p)->Stream.In) + +BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p) +{ + unsigned i; + p->Code = 0; + p->Range = 0xFFFFFFFF; + p->Low = 0; + + for (i = 0; i < 4; i++) + p->Code = (p->Code << 8) | READ_BYTE(p); + return (p->Code < 0xFFFFFFFF); +} + +#define RC_NORM(p) \ + while ((p->Low ^ (p->Low + p->Range)) < kTop \ + || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \ + p->Code = (p->Code << 8) | READ_BYTE(p); \ + p->Range <<= 8; p->Low <<= 8; } + +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) + +#define R p + +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd8_RD_Decode(CPpmd8 *p, UInt32 start, UInt32 size) +{ + start *= R->Range; + R->Low += start; + R->Code -= start; + R->Range *= size; + RC_NORM_LOCAL(R) +} + +#define RC_Decode(start, size) Ppmd8_RD_Decode(p, start, size); +#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R) +#define RC_GetThreshold(total) (R->Code / (R->Range /= (total))) + + +#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) +// typedef CPpmd8_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) +void Ppmd8_UpdateModel(CPpmd8 *p); + +#define MASK(sym) ((Byte *)charMask)[sym] + + +int Ppmd8_DecodeSymbol(CPpmd8 *p) +{ + size_t charMask[256 / sizeof(size_t)]; + + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + unsigned i; + UInt32 count, hiCnt; + UInt32 summFreq = p->MinContext->Union2.SummFreq; + + PPMD8_CORRECT_SUM_RANGE(p, summFreq) + + + count = RC_GetThreshold(summFreq); + hiCnt = count; + + if ((Int32)(count -= s->Freq) < 0) + { + Byte sym; + RC_DecodeFinal(0, s->Freq) + p->FoundState = s; + sym = s->Symbol; + Ppmd8_Update1_0(p); + return sym; + } + + p->PrevSuccess = 0; + i = p->MinContext->NumStats; + + do + { + if ((Int32)(count -= (++s)->Freq) < 0) + { + Byte sym; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + p->FoundState = s; + sym = s->Symbol; + Ppmd8_Update1(p); + return sym; + } + } + while (--i); + + if (hiCnt >= summFreq) + return PPMD8_SYM_ERROR; + + hiCnt -= count; + RC_Decode(hiCnt, summFreq - hiCnt) + + + PPMD_SetAllBitsIn256Bytes(charMask) + // i = p->MinContext->NumStats - 1; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } + else + { + CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); + UInt16 *prob = Ppmd8_GetBinSumm(p); + UInt32 pr = *prob; + UInt32 size0 = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + + if (R->Code < size0) + { + Byte sym; + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + + // RangeDec_DecodeBit0(size0); + R->Range = size0; + RC_NORM(R) + + + + // sym = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; + // Ppmd8_UpdateBin(p); + { + unsigned freq = s->Freq; + CPpmd8_Context *c = CTX(SUCCESSOR(s)); + sym = s->Symbol; + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 196)); + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) + p->MaxContext = p->MinContext = c; + else + Ppmd8_UpdateModel(p); + } + return sym; + } + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + + // RangeDec_DecodeBit1(rc2, size0); + R->Low += size0; + R->Code -= size0; + R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0; + RC_NORM_LOCAL(R) + + PPMD_SetAllBitsIn256Bytes(charMask) + MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; + p->PrevSuccess = 0; + } + + for (;;) + { + CPpmd_State *s, *s2; + UInt32 freqSum, count, hiCnt; + UInt32 freqSum2; + CPpmd_See *see; + CPpmd8_Context *mc; + unsigned numMasked; + RC_NORM_REMOTE(R) + mc = p->MinContext; + numMasked = mc->NumStats; + + do + { + p->OrderFall++; + if (!mc->Suffix) + return PPMD8_SYM_END; + mc = Ppmd8_GetContext(p, mc->Suffix); + } + while (mc->NumStats == numMasked); + + s = Ppmd8_GetStats(p, mc); + + { + unsigned num = (unsigned)mc->NumStats + 1; + unsigned num2 = num / 2; + + num &= 1; + hiCnt = (s->Freq & (UInt32)(MASK(s->Symbol))) & (0 - (UInt32)num); + s += num; + p->MinContext = mc; + + do + { + const unsigned sym0 = s[0].Symbol; + const unsigned sym1 = s[1].Symbol; + s += 2; + hiCnt += (s[-2].Freq & (UInt32)(MASK(sym0))); + hiCnt += (s[-1].Freq & (UInt32)(MASK(sym1))); + } + while (--num2); + } + + see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); + freqSum += hiCnt; + freqSum2 = freqSum; + PPMD8_CORRECT_SUM_RANGE(R, freqSum2) + + + count = RC_GetThreshold(freqSum2); + + if (count < hiCnt) + { + Byte sym; + // Ppmd_See_UPDATE(see) // new (see->Summ) value can overflow over 16-bits in some rare cases + s = Ppmd8_GetStats(p, p->MinContext); + hiCnt = count; + + + { + for (;;) + { + count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + // count -= s->Freq & (UInt32)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break; + } + } + s--; + RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq) + + // new (see->Summ) value can overflow over 16-bits in some rare cases + Ppmd_See_UPDATE(see) + p->FoundState = s; + sym = s->Symbol; + Ppmd8_Update2(p); + return sym; + } + + if (count >= freqSum2) + return PPMD8_SYM_ERROR; + + RC_Decode(hiCnt, freqSum2 - hiCnt) + + // We increase (see->Summ) for sum of Freqs of all non_Masked symbols. + // new (see->Summ) value can overflow over 16-bits in some rare cases + see->Summ = (UInt16)(see->Summ + freqSum); + + s = Ppmd8_GetStats(p, p->MinContext); + s2 = s + p->MinContext->NumStats + 1; + do + { + MASK(s->Symbol) = 0; + s++; + } + while (s != s2); + } +} + +#undef kTop +#undef kBot +#undef READ_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Decode +#undef RC_DecodeFinal +#undef RC_GetThreshold +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/C/Ppmd8Enc.c b/C/Ppmd8Enc.c index 6756d247a..b0e34c45e 100644 --- a/C/Ppmd8Enc.c +++ b/C/Ppmd8Enc.c @@ -1,337 +1,337 @@ -/* Ppmd8Enc.c -- Ppmd8 (PPMdI) Encoder -2023-09-07 : Igor Pavlov : Public domain -This code is based on: - PPMd var.I (2002): Dmitry Shkarin : Public domain - Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#include "Precomp.h" - -#include "Ppmd8.h" - -#define kTop ((UInt32)1 << 24) -#define kBot ((UInt32)1 << 15) - -#define WRITE_BYTE(p) IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)) - -void Ppmd8_Flush_RangeEnc(CPpmd8 *p) -{ - unsigned i; - for (i = 0; i < 4; i++, p->Low <<= 8 ) - WRITE_BYTE(p); -} - - - - - - -#define RC_NORM(p) \ - while ((p->Low ^ (p->Low + p->Range)) < kTop \ - || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) \ - { WRITE_BYTE(p); p->Range <<= 8; p->Low <<= 8; } - - - - - - - - - - - - - -// we must use only one type of Normalization from two: LOCAL or REMOTE -#define RC_NORM_LOCAL(p) // RC_NORM(p) -#define RC_NORM_REMOTE(p) RC_NORM(p) - -// #define RC_PRE(total) p->Range /= total; -// #define RC_PRE(total) - -#define R p - - - - -Z7_FORCE_INLINE -// Z7_NO_INLINE -static void Ppmd8_RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) -{ - R->Low += start * (R->Range /= total); - R->Range *= size; - RC_NORM_LOCAL(R) -} - - - - - - - - - - -#define RC_Encode(start, size, total) Ppmd8_RangeEnc_Encode(p, start, size, total); -#define RC_EncodeFinal(start, size, total) RC_Encode(start, size, total) RC_NORM_REMOTE(p) - -#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) - -// typedef CPpmd8_Context * CTX_PTR; -#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) - -void Ppmd8_UpdateModel(CPpmd8 *p); - -#define MASK(sym) ((Byte *)charMask)[sym] - -// Z7_FORCE_INLINE -// static -void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) -{ - size_t charMask[256 / sizeof(size_t)]; - - if (p->MinContext->NumStats != 0) - { - CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); - UInt32 sum; - unsigned i; - UInt32 summFreq = p->MinContext->Union2.SummFreq; - - PPMD8_CORRECT_SUM_RANGE(p, summFreq) - - // RC_PRE(summFreq); - - if (s->Symbol == symbol) - { - - RC_EncodeFinal(0, s->Freq, summFreq) - p->FoundState = s; - Ppmd8_Update1_0(p); - return; - } - p->PrevSuccess = 0; - sum = s->Freq; - i = p->MinContext->NumStats; - do - { - if ((++s)->Symbol == symbol) - { - - RC_EncodeFinal(sum, s->Freq, summFreq) - p->FoundState = s; - Ppmd8_Update1(p); - return; - } - sum += s->Freq; - } - while (--i); - - - RC_Encode(sum, summFreq - sum, summFreq) - - - PPMD_SetAllBitsIn256Bytes(charMask) - // MASK(s->Symbol) = 0; - // i = p->MinContext->NumStats; - // do { MASK((--s)->Symbol) = 0; } while (--i); - { - CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } - else - { - UInt16 *prob = Ppmd8_GetBinSumm(p); - CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); - UInt32 pr = *prob; - const UInt32 bound = (R->Range >> 14) * pr; - pr = PPMD_UPDATE_PROB_1(pr); - if (s->Symbol == symbol) - { - *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); - // RangeEnc_EncodeBit_0(p, bound); - R->Range = bound; - RC_NORM(R) - - // p->FoundState = s; - // Ppmd8_UpdateBin(p); - { - const unsigned freq = s->Freq; - CPpmd8_Context *c = CTX(SUCCESSOR(s)); - p->FoundState = s; - p->PrevSuccess = 1; - p->RunLength++; - s->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) - // NextContext(p); - if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) - p->MaxContext = p->MinContext = c; - else - Ppmd8_UpdateModel(p); - } - return; - } - - *prob = (UInt16)pr; - p->InitEsc = p->ExpEscape[pr >> 10]; - // RangeEnc_EncodeBit_1(p, bound); - R->Low += bound; - R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - bound; - RC_NORM_LOCAL(R) - - PPMD_SetAllBitsIn256Bytes(charMask) - MASK(s->Symbol) = 0; - p->PrevSuccess = 0; - } - - for (;;) - { - CPpmd_See *see; - CPpmd_State *s; - UInt32 sum, escFreq; - CPpmd8_Context *mc; - unsigned i, numMasked; - - RC_NORM_REMOTE(p) - - mc = p->MinContext; - numMasked = mc->NumStats; - - do - { - p->OrderFall++; - if (!mc->Suffix) - return; /* EndMarker (symbol = -1) */ - mc = Ppmd8_GetContext(p, mc->Suffix); - - } - while (mc->NumStats == numMasked); - - p->MinContext = mc; - - see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); - - - - - - - - - - - - - - - - - - - - - - - - - s = Ppmd8_GetStats(p, p->MinContext); - sum = 0; - i = (unsigned)p->MinContext->NumStats + 1; - - do - { - const unsigned cur = s->Symbol; - if ((int)cur == symbol) - { - const UInt32 low = sum; - const UInt32 freq = s->Freq; - unsigned num2; - - Ppmd_See_UPDATE(see) - p->FoundState = s; - sum += escFreq; - - num2 = i / 2; - i &= 1; - sum += freq & (0 - (UInt32)i); - if (num2 != 0) - { - s += i; - do - { - const unsigned sym0 = s[0].Symbol; - const unsigned sym1 = s[1].Symbol; - s += 2; - sum += (s[-2].Freq & (unsigned)(MASK(sym0))); - sum += (s[-1].Freq & (unsigned)(MASK(sym1))); - } - while (--num2); - } - - PPMD8_CORRECT_SUM_RANGE(p, sum) - - RC_EncodeFinal(low, freq, sum) - Ppmd8_Update2(p); - return; - } - sum += (s->Freq & (unsigned)(MASK(cur))); - s++; - } - while (--i); - - { - UInt32 total = sum + escFreq; - see->Summ = (UInt16)(see->Summ + total); - PPMD8_CORRECT_SUM_RANGE(p, total) - - RC_Encode(sum, total - sum, total) - } - - { - const CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); - s--; - MASK(s->Symbol) = 0; - do - { - const unsigned sym0 = s2[0].Symbol; - const unsigned sym1 = s2[1].Symbol; - s2 += 2; - MASK(sym0) = 0; - MASK(sym1) = 0; - } - while (s2 < s); - } - } -} - - - - - - - - - -#undef kTop -#undef kBot -#undef WRITE_BYTE -#undef RC_NORM_BASE -#undef RC_NORM_1 -#undef RC_NORM -#undef RC_NORM_LOCAL -#undef RC_NORM_REMOTE -#undef R -#undef RC_Encode -#undef RC_EncodeFinal - -#undef CTX -#undef SUCCESSOR -#undef MASK +/* Ppmd8Enc.c -- Ppmd8 (PPMdI) Encoder +2023-09-07 : Igor Pavlov : Public domain +This code is based on: + PPMd var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "Precomp.h" + +#include "Ppmd8.h" + +#define kTop ((UInt32)1 << 24) +#define kBot ((UInt32)1 << 15) + +#define WRITE_BYTE(p) IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)) + +void Ppmd8_Flush_RangeEnc(CPpmd8 *p) +{ + unsigned i; + for (i = 0; i < 4; i++, p->Low <<= 8 ) + WRITE_BYTE(p); +} + + + + + + +#define RC_NORM(p) \ + while ((p->Low ^ (p->Low + p->Range)) < kTop \ + || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) \ + { WRITE_BYTE(p); p->Range <<= 8; p->Low <<= 8; } + + + + + + + + + + + + + +// we must use only one type of Normalization from two: LOCAL or REMOTE +#define RC_NORM_LOCAL(p) // RC_NORM(p) +#define RC_NORM_REMOTE(p) RC_NORM(p) + +// #define RC_PRE(total) p->Range /= total; +// #define RC_PRE(total) + +#define R p + + + + +Z7_FORCE_INLINE +// Z7_NO_INLINE +static void Ppmd8_RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) +{ + R->Low += start * (R->Range /= total); + R->Range *= size; + RC_NORM_LOCAL(R) +} + + + + + + + + + + +#define RC_Encode(start, size, total) Ppmd8_RangeEnc_Encode(p, start, size, total); +#define RC_EncodeFinal(start, size, total) RC_Encode(start, size, total) RC_NORM_REMOTE(p) + +#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) + +// typedef CPpmd8_Context * CTX_PTR; +#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) + +void Ppmd8_UpdateModel(CPpmd8 *p); + +#define MASK(sym) ((Byte *)charMask)[sym] + +// Z7_FORCE_INLINE +// static +void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) +{ + size_t charMask[256 / sizeof(size_t)]; + + if (p->MinContext->NumStats != 0) + { + CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); + UInt32 sum; + unsigned i; + UInt32 summFreq = p->MinContext->Union2.SummFreq; + + PPMD8_CORRECT_SUM_RANGE(p, summFreq) + + // RC_PRE(summFreq); + + if (s->Symbol == symbol) + { + + RC_EncodeFinal(0, s->Freq, summFreq) + p->FoundState = s; + Ppmd8_Update1_0(p); + return; + } + p->PrevSuccess = 0; + sum = s->Freq; + i = p->MinContext->NumStats; + do + { + if ((++s)->Symbol == symbol) + { + + RC_EncodeFinal(sum, s->Freq, summFreq) + p->FoundState = s; + Ppmd8_Update1(p); + return; + } + sum += s->Freq; + } + while (--i); + + + RC_Encode(sum, summFreq - sum, summFreq) + + + PPMD_SetAllBitsIn256Bytes(charMask) + // MASK(s->Symbol) = 0; + // i = p->MinContext->NumStats; + // do { MASK((--s)->Symbol) = 0; } while (--i); + { + CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } + else + { + UInt16 *prob = Ppmd8_GetBinSumm(p); + CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); + UInt32 pr = *prob; + const UInt32 bound = (R->Range >> 14) * pr; + pr = PPMD_UPDATE_PROB_1(pr); + if (s->Symbol == symbol) + { + *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); + // RangeEnc_EncodeBit_0(p, bound); + R->Range = bound; + RC_NORM(R) + + // p->FoundState = s; + // Ppmd8_UpdateBin(p); + { + const unsigned freq = s->Freq; + CPpmd8_Context *c = CTX(SUCCESSOR(s)); + p->FoundState = s; + p->PrevSuccess = 1; + p->RunLength++; + s->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) + // NextContext(p); + if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) + p->MaxContext = p->MinContext = c; + else + Ppmd8_UpdateModel(p); + } + return; + } + + *prob = (UInt16)pr; + p->InitEsc = p->ExpEscape[pr >> 10]; + // RangeEnc_EncodeBit_1(p, bound); + R->Low += bound; + R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - bound; + RC_NORM_LOCAL(R) + + PPMD_SetAllBitsIn256Bytes(charMask) + MASK(s->Symbol) = 0; + p->PrevSuccess = 0; + } + + for (;;) + { + CPpmd_See *see; + CPpmd_State *s; + UInt32 sum, escFreq; + CPpmd8_Context *mc; + unsigned i, numMasked; + + RC_NORM_REMOTE(p) + + mc = p->MinContext; + numMasked = mc->NumStats; + + do + { + p->OrderFall++; + if (!mc->Suffix) + return; /* EndMarker (symbol = -1) */ + mc = Ppmd8_GetContext(p, mc->Suffix); + + } + while (mc->NumStats == numMasked); + + p->MinContext = mc; + + see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); + + + + + + + + + + + + + + + + + + + + + + + + + s = Ppmd8_GetStats(p, p->MinContext); + sum = 0; + i = (unsigned)p->MinContext->NumStats + 1; + + do + { + const unsigned cur = s->Symbol; + if ((int)cur == symbol) + { + const UInt32 low = sum; + const UInt32 freq = s->Freq; + unsigned num2; + + Ppmd_See_UPDATE(see) + p->FoundState = s; + sum += escFreq; + + num2 = i / 2; + i &= 1; + sum += freq & (0 - (UInt32)i); + if (num2 != 0) + { + s += i; + do + { + const unsigned sym0 = s[0].Symbol; + const unsigned sym1 = s[1].Symbol; + s += 2; + sum += (s[-2].Freq & (unsigned)(MASK(sym0))); + sum += (s[-1].Freq & (unsigned)(MASK(sym1))); + } + while (--num2); + } + + PPMD8_CORRECT_SUM_RANGE(p, sum) + + RC_EncodeFinal(low, freq, sum) + Ppmd8_Update2(p); + return; + } + sum += (s->Freq & (unsigned)(MASK(cur))); + s++; + } + while (--i); + + { + UInt32 total = sum + escFreq; + see->Summ = (UInt16)(see->Summ + total); + PPMD8_CORRECT_SUM_RANGE(p, total) + + RC_Encode(sum, total - sum, total) + } + + { + const CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); + s--; + MASK(s->Symbol) = 0; + do + { + const unsigned sym0 = s2[0].Symbol; + const unsigned sym1 = s2[1].Symbol; + s2 += 2; + MASK(sym0) = 0; + MASK(sym1) = 0; + } + while (s2 < s); + } + } +} + + + + + + + + + +#undef kTop +#undef kBot +#undef WRITE_BYTE +#undef RC_NORM_BASE +#undef RC_NORM_1 +#undef RC_NORM +#undef RC_NORM_LOCAL +#undef RC_NORM_REMOTE +#undef R +#undef RC_Encode +#undef RC_EncodeFinal + +#undef CTX +#undef SUCCESSOR +#undef MASK diff --git a/C/Precomp.h b/C/Precomp.h index 976522817..7747fdd74 100644 --- a/C/Precomp.h +++ b/C/Precomp.h @@ -1,127 +1,127 @@ -/* Precomp.h -- precompilation file -2024-01-25 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_PRECOMP_H -#define ZIP7_INC_PRECOMP_H - -/* - this file must be included before another *.h files and before . - this file is included from the following files: - C\*.c - C\Util\*\Precomp.h <- C\Util\*\*.c - CPP\Common\Common.h <- *\StdAfx.h <- *\*.cpp - - this file can set the following macros: - Z7_LARGE_PAGES 1 - Z7_LONG_PATH 1 - Z7_WIN32_WINNT_MIN 0x0500 (or higher) : we require at least win2000+ for 7-Zip - _WIN32_WINNT 0x0500 (or higher) - WINVER _WIN32_WINNT - UNICODE 1 - _UNICODE 1 -*/ - -#include "Compiler.h" - -#ifdef _MSC_VER -// #pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty -#if _MSC_VER >= 1912 -// #pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception. -#endif -#endif - -/* -// for debug: -#define UNICODE 1 -#define _UNICODE 1 -#define _WIN32_WINNT 0x0500 // win2000 -#ifndef WINVER - #define WINVER _WIN32_WINNT -#endif -*/ - -#ifdef _WIN32 -/* - this "Precomp.h" file must be included before , - if we want to define _WIN32_WINNT before . -*/ - -#ifndef Z7_LARGE_PAGES -#ifndef Z7_NO_LARGE_PAGES -#define Z7_LARGE_PAGES 1 -#endif -#endif - -#ifndef Z7_LONG_PATH -#ifndef Z7_NO_LONG_PATH -#define Z7_LONG_PATH 1 -#endif -#endif - -#ifndef Z7_DEVICE_FILE -#ifndef Z7_NO_DEVICE_FILE -// #define Z7_DEVICE_FILE 1 -#endif -#endif - -// we don't change macros if included after -#ifndef _WINDOWS_ - -#ifndef Z7_WIN32_WINNT_MIN - #if defined(_M_ARM64) || defined(__aarch64__) - // #define Z7_WIN32_WINNT_MIN 0x0a00 // win10 - #define Z7_WIN32_WINNT_MIN 0x0600 // vista - #elif defined(_M_ARM) && defined(_M_ARMT) && defined(_M_ARM_NT) - // #define Z7_WIN32_WINNT_MIN 0x0602 // win8 - #define Z7_WIN32_WINNT_MIN 0x0600 // vista - #elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IA64) - #define Z7_WIN32_WINNT_MIN 0x0503 // win2003 - // #elif defined(_M_IX86) || defined(__i386__) - // #define Z7_WIN32_WINNT_MIN 0x0500 // win2000 - #else // x86 and another(old) systems - #define Z7_WIN32_WINNT_MIN 0x0500 // win2000 - // #define Z7_WIN32_WINNT_MIN 0x0502 // win2003 // for debug - #endif -#endif // Z7_WIN32_WINNT_MIN - - -#ifndef Z7_DO_NOT_DEFINE_WIN32_WINNT -#ifdef _WIN32_WINNT - // #error Stop_Compiling_Bad_WIN32_WINNT -#else - #ifndef Z7_NO_DEFINE_WIN32_WINNT -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #define _WIN32_WINNT Z7_WIN32_WINNT_MIN -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER - #endif -#endif // _WIN32_WINNT - -#ifndef WINVER - #define WINVER _WIN32_WINNT -#endif -#endif // Z7_DO_NOT_DEFINE_WIN32_WINNT - - -#ifndef _MBCS -#ifndef Z7_NO_UNICODE -// UNICODE and _UNICODE are used by and by 7-zip code. - -#ifndef UNICODE -#define UNICODE 1 -#endif - -#ifndef _UNICODE -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -#define _UNICODE 1 -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif - -#endif // Z7_NO_UNICODE -#endif // _MBCS -#endif // _WINDOWS_ - -// #include "7zWindows.h" - -#endif // _WIN32 - -#endif +/* Precomp.h -- precompilation file +2024-01-25 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_PRECOMP_H +#define ZIP7_INC_PRECOMP_H + +/* + this file must be included before another *.h files and before . + this file is included from the following files: + C\*.c + C\Util\*\Precomp.h <- C\Util\*\*.c + CPP\Common\Common.h <- *\StdAfx.h <- *\*.cpp + + this file can set the following macros: + Z7_LARGE_PAGES 1 + Z7_LONG_PATH 1 + Z7_WIN32_WINNT_MIN 0x0500 (or higher) : we require at least win2000+ for 7-Zip + _WIN32_WINNT 0x0500 (or higher) + WINVER _WIN32_WINNT + UNICODE 1 + _UNICODE 1 +*/ + +#include "Compiler.h" + +#ifdef _MSC_VER +// #pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty +#if _MSC_VER >= 1912 +// #pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception. +#endif +#endif + +/* +// for debug: +#define UNICODE 1 +#define _UNICODE 1 +#define _WIN32_WINNT 0x0500 // win2000 +#ifndef WINVER + #define WINVER _WIN32_WINNT +#endif +*/ + +#ifdef _WIN32 +/* + this "Precomp.h" file must be included before , + if we want to define _WIN32_WINNT before . +*/ + +#ifndef Z7_LARGE_PAGES +#ifndef Z7_NO_LARGE_PAGES +#define Z7_LARGE_PAGES 1 +#endif +#endif + +#ifndef Z7_LONG_PATH +#ifndef Z7_NO_LONG_PATH +#define Z7_LONG_PATH 1 +#endif +#endif + +#ifndef Z7_DEVICE_FILE +#ifndef Z7_NO_DEVICE_FILE +// #define Z7_DEVICE_FILE 1 +#endif +#endif + +// we don't change macros if included after +#ifndef _WINDOWS_ + +#ifndef Z7_WIN32_WINNT_MIN + #if defined(_M_ARM64) || defined(__aarch64__) + // #define Z7_WIN32_WINNT_MIN 0x0a00 // win10 + #define Z7_WIN32_WINNT_MIN 0x0600 // vista + #elif defined(_M_ARM) && defined(_M_ARMT) && defined(_M_ARM_NT) + // #define Z7_WIN32_WINNT_MIN 0x0602 // win8 + #define Z7_WIN32_WINNT_MIN 0x0600 // vista + #elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IA64) + #define Z7_WIN32_WINNT_MIN 0x0503 // win2003 + // #elif defined(_M_IX86) || defined(__i386__) + // #define Z7_WIN32_WINNT_MIN 0x0500 // win2000 + #else // x86 and another(old) systems + #define Z7_WIN32_WINNT_MIN 0x0500 // win2000 + // #define Z7_WIN32_WINNT_MIN 0x0502 // win2003 // for debug + #endif +#endif // Z7_WIN32_WINNT_MIN + + +#ifndef Z7_DO_NOT_DEFINE_WIN32_WINNT +#ifdef _WIN32_WINNT + // #error Stop_Compiling_Bad_WIN32_WINNT +#else + #ifndef Z7_NO_DEFINE_WIN32_WINNT +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define _WIN32_WINNT Z7_WIN32_WINNT_MIN +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER + #endif +#endif // _WIN32_WINNT + +#ifndef WINVER + #define WINVER _WIN32_WINNT +#endif +#endif // Z7_DO_NOT_DEFINE_WIN32_WINNT + + +#ifndef _MBCS +#ifndef Z7_NO_UNICODE +// UNICODE and _UNICODE are used by and by 7-zip code. + +#ifndef UNICODE +#define UNICODE 1 +#endif + +#ifndef _UNICODE +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#define _UNICODE 1 +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#endif // Z7_NO_UNICODE +#endif // _MBCS +#endif // _WINDOWS_ + +// #include "7zWindows.h" + +#endif // _WIN32 + +#endif diff --git a/C/RotateDefs.h b/C/RotateDefs.h index 8026cd106..c16b4f8e6 100644 --- a/C/RotateDefs.h +++ b/C/RotateDefs.h @@ -1,50 +1,50 @@ -/* RotateDefs.h -- Rotate functions -2023-06-18 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_ROTATE_DEFS_H -#define ZIP7_INC_ROTATE_DEFS_H - -#ifdef _MSC_VER - -#include - -/* don't use _rotl with old MINGW. It can insert slow call to function. */ - -/* #if (_MSC_VER >= 1200) */ -#pragma intrinsic(_rotl) -#pragma intrinsic(_rotr) -/* #endif */ - -#define rotlFixed(x, n) _rotl((x), (n)) -#define rotrFixed(x, n) _rotr((x), (n)) - -#if (_MSC_VER >= 1300) -#define Z7_ROTL64(x, n) _rotl64((x), (n)) -#define Z7_ROTR64(x, n) _rotr64((x), (n)) -#else -#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) -#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) -#endif - -#else - -/* new compilers can translate these macros to fast commands. */ - -#if defined(__clang__) && (__clang_major__ >= 4) \ - || defined(__GNUC__) && (__GNUC__ >= 5) -/* GCC 4.9.0 and clang 3.5 can recognize more correct version: */ -#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (-(n) & 31))) -#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (-(n) & 31))) -#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (-(n) & 63))) -#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (-(n) & 63))) -#else -/* for old GCC / clang: */ -#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) -#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) -#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) -#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) -#endif - -#endif - -#endif +/* RotateDefs.h -- Rotate functions +2023-06-18 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_ROTATE_DEFS_H +#define ZIP7_INC_ROTATE_DEFS_H + +#ifdef _MSC_VER + +#include + +/* don't use _rotl with old MINGW. It can insert slow call to function. */ + +/* #if (_MSC_VER >= 1200) */ +#pragma intrinsic(_rotl) +#pragma intrinsic(_rotr) +/* #endif */ + +#define rotlFixed(x, n) _rotl((x), (n)) +#define rotrFixed(x, n) _rotr((x), (n)) + +#if (_MSC_VER >= 1300) +#define Z7_ROTL64(x, n) _rotl64((x), (n)) +#define Z7_ROTR64(x, n) _rotr64((x), (n)) +#else +#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) +#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) +#endif + +#else + +/* new compilers can translate these macros to fast commands. */ + +#if defined(__clang__) && (__clang_major__ >= 4) \ + || defined(__GNUC__) && (__GNUC__ >= 5) +/* GCC 4.9.0 and clang 3.5 can recognize more correct version: */ +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (-(n) & 31))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (-(n) & 31))) +#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (-(n) & 63))) +#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (-(n) & 63))) +#else +/* for old GCC / clang: */ +#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) +#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) +#endif + +#endif + +#endif diff --git a/C/Sha1.c b/C/Sha1.c index fcc515cee..4ca21d7d9 100644 --- a/C/Sha1.c +++ b/C/Sha1.c @@ -1,498 +1,441 @@ -/* Sha1.c -- SHA-1 Hash -2024-03-01 : Igor Pavlov : Public domain -This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ library. */ - -#include "Precomp.h" - -#include - -#include "CpuArch.h" -#include "RotateDefs.h" -#include "Sha1.h" - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -// #define USE_MY_MM -#endif - -#ifdef MY_CPU_X86_OR_AMD64 - #if defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) \ - || defined(_MSC_VER) && (_MSC_VER >= 1200) - #define Z7_COMPILER_SHA1_SUPPORTED - #endif -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) \ - && (!defined(Z7_MSC_VER_ORIGINAL) || (_MSC_VER >= 1929) && (_MSC_FULL_VER >= 192930037)) - #if defined(__ARM_FEATURE_SHA2) \ - || defined(__ARM_FEATURE_CRYPTO) - #define Z7_COMPILER_SHA1_SUPPORTED - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define Z7_COMPILER_SHA1_SUPPORTED - #endif - #endif - #endif - #endif -#endif - -void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); - -#ifdef Z7_COMPILER_SHA1_SUPPORTED - void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); - - static SHA1_FUNC_UPDATE_BLOCKS g_SHA1_FUNC_UPDATE_BLOCKS = Sha1_UpdateBlocks; - static SHA1_FUNC_UPDATE_BLOCKS g_SHA1_FUNC_UPDATE_BLOCKS_HW; - - #define SHA1_UPDATE_BLOCKS(p) p->func_UpdateBlocks -#else - #define SHA1_UPDATE_BLOCKS(p) Sha1_UpdateBlocks -#endif - - -BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo) -{ - SHA1_FUNC_UPDATE_BLOCKS func = Sha1_UpdateBlocks; - - #ifdef Z7_COMPILER_SHA1_SUPPORTED - if (algo != SHA1_ALGO_SW) - { - if (algo == SHA1_ALGO_DEFAULT) - func = g_SHA1_FUNC_UPDATE_BLOCKS; - else - { - if (algo != SHA1_ALGO_HW) - return False; - func = g_SHA1_FUNC_UPDATE_BLOCKS_HW; - if (!func) - return False; - } - } - #else - if (algo > 1) - return False; - #endif - - p->func_UpdateBlocks = func; - return True; -} - - -/* define it for speed optimization */ -// #define Z7_SHA1_UNROLL - -// allowed unroll steps: (1, 2, 4, 5, 20) - -#undef Z7_SHA1_BIG_W -#ifdef Z7_SHA1_UNROLL - #define STEP_PRE 20 - #define STEP_MAIN 20 -#else - #define Z7_SHA1_BIG_W - #define STEP_PRE 5 - #define STEP_MAIN 5 -#endif - - -#ifdef Z7_SHA1_BIG_W - #define kNumW 80 - #define w(i) W[i] -#else - #define kNumW 16 - #define w(i) W[(i)&15] -#endif - -#define w0(i) (W[i] = GetBe32(data + (size_t)(i) * 4)) -#define w1(i) (w(i) = rotlFixed(w((size_t)(i)-3) ^ w((size_t)(i)-8) ^ w((size_t)(i)-14) ^ w((size_t)(i)-16), 1)) - -#define f0(x,y,z) ( 0x5a827999 + (z^(x&(y^z))) ) -#define f1(x,y,z) ( 0x6ed9eba1 + (x^y^z) ) -#define f2(x,y,z) ( 0x8f1bbcdc + ((x&y)|(z&(x|y))) ) -#define f3(x,y,z) ( 0xca62c1d6 + (x^y^z) ) - -/* -#define T1(fx, ww) \ - tmp = e + fx(b,c,d) + ww + rotlFixed(a, 5); \ - e = d; \ - d = c; \ - c = rotlFixed(b, 30); \ - b = a; \ - a = tmp; \ -*/ - -#define T5(a,b,c,d,e, fx, ww) \ - e += fx(b,c,d) + ww + rotlFixed(a, 5); \ - b = rotlFixed(b, 30); \ - - -/* -#define R1(i, fx, wx) \ - T1 ( fx, wx(i)); \ - -#define R2(i, fx, wx) \ - R1 ( (i) , fx, wx); \ - R1 ( (i) + 1, fx, wx); \ - -#define R4(i, fx, wx) \ - R2 ( (i) , fx, wx); \ - R2 ( (i) + 2, fx, wx); \ -*/ - -#define M5(i, fx, wx0, wx1) \ - T5 ( a,b,c,d,e, fx, wx0((i) ) ) \ - T5 ( e,a,b,c,d, fx, wx1((i)+1) ) \ - T5 ( d,e,a,b,c, fx, wx1((i)+2) ) \ - T5 ( c,d,e,a,b, fx, wx1((i)+3) ) \ - T5 ( b,c,d,e,a, fx, wx1((i)+4) ) \ - -#define R5(i, fx, wx) \ - M5 ( i, fx, wx, wx) \ - - -#if STEP_PRE > 5 - - #define R20_START \ - R5 ( 0, f0, w0) \ - R5 ( 5, f0, w0) \ - R5 ( 10, f0, w0) \ - M5 ( 15, f0, w0, w1) \ - - #elif STEP_PRE == 5 - - #define R20_START \ - { size_t i; for (i = 0; i < 15; i += STEP_PRE) \ - { R5(i, f0, w0) } } \ - M5 ( 15, f0, w0, w1) \ - -#else - - #if STEP_PRE == 1 - #define R_PRE R1 - #elif STEP_PRE == 2 - #define R_PRE R2 - #elif STEP_PRE == 4 - #define R_PRE R4 - #endif - - #define R20_START \ - { size_t i; for (i = 0; i < 16; i += STEP_PRE) \ - { R_PRE(i, f0, w0) } } \ - R4 ( 16, f0, w1) \ - -#endif - - - -#if STEP_MAIN > 5 - - #define R20(ii, fx) \ - R5 ( (ii) , fx, w1) \ - R5 ( (ii) + 5 , fx, w1) \ - R5 ( (ii) + 10, fx, w1) \ - R5 ( (ii) + 15, fx, w1) \ - -#else - - #if STEP_MAIN == 1 - #define R_MAIN R1 - #elif STEP_MAIN == 2 - #define R_MAIN R2 - #elif STEP_MAIN == 4 - #define R_MAIN R4 - #elif STEP_MAIN == 5 - #define R_MAIN R5 - #endif - - #define R20(ii, fx) \ - { size_t i; for (i = (ii); i < (ii) + 20; i += STEP_MAIN) \ - { R_MAIN(i, fx, w1) } } \ - -#endif - - - -void Sha1_InitState(CSha1 *p) -{ - p->count = 0; - p->state[0] = 0x67452301; - p->state[1] = 0xEFCDAB89; - p->state[2] = 0x98BADCFE; - p->state[3] = 0x10325476; - p->state[4] = 0xC3D2E1F0; -} - -void Sha1_Init(CSha1 *p) -{ - p->func_UpdateBlocks = - #ifdef Z7_COMPILER_SHA1_SUPPORTED - g_SHA1_FUNC_UPDATE_BLOCKS; - #else - NULL; - #endif - Sha1_InitState(p); -} - - -Z7_NO_INLINE -void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks) -{ - UInt32 a, b, c, d, e; - UInt32 W[kNumW]; - // if (numBlocks != 0x1264378347) return; - if (numBlocks == 0) - return; - - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - - do - { - #if STEP_PRE < 5 || STEP_MAIN < 5 - UInt32 tmp; - #endif - - R20_START - R20(20, f1) - R20(40, f2) - R20(60, f3) - - a += state[0]; - b += state[1]; - c += state[2]; - d += state[3]; - e += state[4]; - - state[0] = a; - state[1] = b; - state[2] = c; - state[3] = d; - state[4] = e; - - data += 64; - } - while (--numBlocks); -} - - -#define Sha1_UpdateBlock(p) SHA1_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) - -void Sha1_Update(CSha1 *p, const Byte *data, size_t size) -{ - if (size == 0) - return; - - { - unsigned pos = (unsigned)p->count & 0x3F; - unsigned num; - - p->count += size; - - num = 64 - pos; - if (num > size) - { - memcpy(p->buffer + pos, data, size); - return; - } - - if (pos != 0) - { - size -= num; - memcpy(p->buffer + pos, data, num); - data += num; - Sha1_UpdateBlock(p); - } - } - { - size_t numBlocks = size >> 6; - SHA1_UPDATE_BLOCKS(p)(p->state, data, numBlocks); - size &= 0x3F; - if (size == 0) - return; - data += (numBlocks << 6); - memcpy(p->buffer, data, size); - } -} - - -void Sha1_Final(CSha1 *p, Byte *digest) -{ - unsigned pos = (unsigned)p->count & 0x3F; - - - p->buffer[pos++] = 0x80; - - if (pos > (64 - 8)) - { - while (pos != 64) { p->buffer[pos++] = 0; } - // memset(&p->buf.buffer[pos], 0, 64 - pos); - Sha1_UpdateBlock(p); - pos = 0; - } - - /* - if (pos & 3) - { - p->buffer[pos] = 0; - p->buffer[pos + 1] = 0; - p->buffer[pos + 2] = 0; - pos += 3; - pos &= ~3; - } - { - for (; pos < 64 - 8; pos += 4) - *(UInt32 *)(&p->buffer[pos]) = 0; - } - */ - - memset(&p->buffer[pos], 0, (64 - 8) - pos); - - { - const UInt64 numBits = (p->count << 3); - SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)) - SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)) - } - - Sha1_UpdateBlock(p); - - SetBe32(digest, p->state[0]) - SetBe32(digest + 4, p->state[1]) - SetBe32(digest + 8, p->state[2]) - SetBe32(digest + 12, p->state[3]) - SetBe32(digest + 16, p->state[4]) - - - - - Sha1_InitState(p); -} - - -void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size) -{ - const UInt64 numBits = (p->count + size) << 3; - SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 2], (UInt32)(numBits >> 32)) - SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 1], (UInt32)(numBits)) - // SetBe32((UInt32 *)(block + size), 0x80000000); - SetUi32((UInt32 *)(void *)(block + size), 0x80) - size += 4; - while (size != (SHA1_NUM_BLOCK_WORDS - 2) * 4) - { - *((UInt32 *)(void *)(block + size)) = 0; - size += 4; - } -} - -void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest) -{ - MY_ALIGN (16) - UInt32 st[SHA1_NUM_DIGEST_WORDS]; - - st[0] = p->state[0]; - st[1] = p->state[1]; - st[2] = p->state[2]; - st[3] = p->state[3]; - st[4] = p->state[4]; - - SHA1_UPDATE_BLOCKS(p)(st, data, 1); - - SetBe32(destDigest + 0 , st[0]) - SetBe32(destDigest + 1 * 4, st[1]) - SetBe32(destDigest + 2 * 4, st[2]) - SetBe32(destDigest + 3 * 4, st[3]) - SetBe32(destDigest + 4 * 4, st[4]) -} - - -void Sha1Prepare(void) -{ - #ifdef Z7_COMPILER_SHA1_SUPPORTED - SHA1_FUNC_UPDATE_BLOCKS f, f_hw; - f = Sha1_UpdateBlocks; - f_hw = NULL; - #ifdef MY_CPU_X86_OR_AMD64 - #ifndef USE_MY_MM - if (CPU_IsSupported_SHA() - && CPU_IsSupported_SSSE3() - // && CPU_IsSupported_SSE41() - ) - #endif - #else - if (CPU_IsSupported_SHA1()) - #endif - { - // printf("\n========== HW SHA1 ======== \n"); - #if 0 && defined(MY_CPU_ARM_OR_ARM64) && defined(_MSC_VER) - /* there was bug in MSVC compiler for ARM64 -O2 before version VS2019 16.10 (19.29.30037). - It generated incorrect SHA-1 code. - 21.03 : we test sha1-hardware code at runtime initialization */ - - #pragma message("== SHA1 code: MSC compiler : failure-check code was inserted") - - UInt32 state[5] = { 0, 1, 2, 3, 4 } ; - Byte data[64]; - unsigned i; - for (i = 0; i < sizeof(data); i += 2) - { - data[i ] = (Byte)(i); - data[i + 1] = (Byte)(i + 1); - } - - Sha1_UpdateBlocks_HW(state, data, sizeof(data) / 64); - - if ( state[0] != 0x9acd7297 - || state[1] != 0x4624d898 - || state[2] != 0x0bf079f0 - || state[3] != 0x031e61b3 - || state[4] != 0x8323fe20) - { - // printf("\n========== SHA-1 hardware version failure ======== \n"); - } - else - #endif - { - f = f_hw = Sha1_UpdateBlocks_HW; - } - } - g_SHA1_FUNC_UPDATE_BLOCKS = f; - g_SHA1_FUNC_UPDATE_BLOCKS_HW = f_hw; - #endif -} - -#undef kNumW -#undef w -#undef w0 -#undef w1 -#undef f0 -#undef f1 -#undef f2 -#undef f3 -#undef T1 -#undef T5 -#undef M5 -#undef R1 -#undef R2 -#undef R4 -#undef R5 -#undef R20_START -#undef R_PRE -#undef R_MAIN -#undef STEP_PRE -#undef STEP_MAIN -#undef Z7_SHA1_BIG_W -#undef Z7_SHA1_UNROLL -#undef Z7_COMPILER_SHA1_SUPPORTED +/* Sha1.c -- SHA-1 Hash +: Igor Pavlov : Public domain +This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "Sha1.h" +#include "RotateDefs.h" +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) \ + || defined(_MSC_VER) && (_MSC_VER >= 1200) + #define Z7_COMPILER_SHA1_SUPPORTED + #endif +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) \ + && (!defined(Z7_MSC_VER_ORIGINAL) || (_MSC_VER >= 1929) && (_MSC_FULL_VER >= 192930037)) + #if defined(__ARM_FEATURE_SHA2) \ + || defined(__ARM_FEATURE_CRYPTO) + #define Z7_COMPILER_SHA1_SUPPORTED + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define Z7_COMPILER_SHA1_SUPPORTED + #endif + #endif + #endif + #endif +#endif + +void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); + +#ifdef Z7_COMPILER_SHA1_SUPPORTED + void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); + + static SHA1_FUNC_UPDATE_BLOCKS g_SHA1_FUNC_UPDATE_BLOCKS = Sha1_UpdateBlocks; + static SHA1_FUNC_UPDATE_BLOCKS g_SHA1_FUNC_UPDATE_BLOCKS_HW; + + #define SHA1_UPDATE_BLOCKS(p) p->v.vars.func_UpdateBlocks +#else + #define SHA1_UPDATE_BLOCKS(p) Sha1_UpdateBlocks +#endif + + +BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo) +{ + SHA1_FUNC_UPDATE_BLOCKS func = Sha1_UpdateBlocks; + + #ifdef Z7_COMPILER_SHA1_SUPPORTED + if (algo != SHA1_ALGO_SW) + { + if (algo == SHA1_ALGO_DEFAULT) + func = g_SHA1_FUNC_UPDATE_BLOCKS; + else + { + if (algo != SHA1_ALGO_HW) + return False; + func = g_SHA1_FUNC_UPDATE_BLOCKS_HW; + if (!func) + return False; + } + } + #else + if (algo > 1) + return False; + #endif + + p->v.vars.func_UpdateBlocks = func; + return True; +} + + +/* define it for speed optimization */ +// #define Z7_SHA1_UNROLL + +// allowed unroll steps: (1, 2, 4, 5, 20) + +#undef Z7_SHA1_BIG_W +#ifdef Z7_SHA1_UNROLL + #define STEP_PRE 20 + #define STEP_MAIN 20 +#else + #define Z7_SHA1_BIG_W + #define STEP_PRE 5 + #define STEP_MAIN 5 +#endif + + +#ifdef Z7_SHA1_BIG_W + #define kNumW 80 + #define w(i) W[i] +#else + #define kNumW 16 + #define w(i) W[(i)&15] +#endif + +#define w0(i) (W[i] = GetBe32(data + (size_t)(i) * 4)) +#define w1(i) (w(i) = rotlFixed(w((size_t)(i)-3) ^ w((size_t)(i)-8) ^ w((size_t)(i)-14) ^ w((size_t)(i)-16), 1)) + +#define f0(x,y,z) ( 0x5a827999 + (z^(x&(y^z))) ) +#define f1(x,y,z) ( 0x6ed9eba1 + (x^y^z) ) +#define f2(x,y,z) ( 0x8f1bbcdc + ((x&y)|(z&(x|y))) ) +#define f3(x,y,z) ( 0xca62c1d6 + (x^y^z) ) + +/* +#define T1(fx, ww) \ + tmp = e + fx(b,c,d) + ww + rotlFixed(a, 5); \ + e = d; \ + d = c; \ + c = rotlFixed(b, 30); \ + b = a; \ + a = tmp; \ +*/ + +#define T5(a,b,c,d,e, fx, ww) \ + e += fx(b,c,d) + ww + rotlFixed(a, 5); \ + b = rotlFixed(b, 30); \ + + +/* +#define R1(i, fx, wx) \ + T1 ( fx, wx(i)); \ + +#define R2(i, fx, wx) \ + R1 ( (i) , fx, wx); \ + R1 ( (i) + 1, fx, wx); \ + +#define R4(i, fx, wx) \ + R2 ( (i) , fx, wx); \ + R2 ( (i) + 2, fx, wx); \ +*/ + +#define M5(i, fx, wx0, wx1) \ + T5 ( a,b,c,d,e, fx, wx0((i) ) ) \ + T5 ( e,a,b,c,d, fx, wx1((i)+1) ) \ + T5 ( d,e,a,b,c, fx, wx1((i)+2) ) \ + T5 ( c,d,e,a,b, fx, wx1((i)+3) ) \ + T5 ( b,c,d,e,a, fx, wx1((i)+4) ) \ + +#define R5(i, fx, wx) \ + M5 ( i, fx, wx, wx) \ + + +#if STEP_PRE > 5 + + #define R20_START \ + R5 ( 0, f0, w0) \ + R5 ( 5, f0, w0) \ + R5 ( 10, f0, w0) \ + M5 ( 15, f0, w0, w1) \ + + #elif STEP_PRE == 5 + + #define R20_START \ + { size_t i; for (i = 0; i < 15; i += STEP_PRE) \ + { R5(i, f0, w0) } } \ + M5 ( 15, f0, w0, w1) \ + +#else + + #if STEP_PRE == 1 + #define R_PRE R1 + #elif STEP_PRE == 2 + #define R_PRE R2 + #elif STEP_PRE == 4 + #define R_PRE R4 + #endif + + #define R20_START \ + { size_t i; for (i = 0; i < 16; i += STEP_PRE) \ + { R_PRE(i, f0, w0) } } \ + R4 ( 16, f0, w1) \ + +#endif + + + +#if STEP_MAIN > 5 + + #define R20(ii, fx) \ + R5 ( (ii) , fx, w1) \ + R5 ( (ii) + 5 , fx, w1) \ + R5 ( (ii) + 10, fx, w1) \ + R5 ( (ii) + 15, fx, w1) \ + +#else + + #if STEP_MAIN == 1 + #define R_MAIN R1 + #elif STEP_MAIN == 2 + #define R_MAIN R2 + #elif STEP_MAIN == 4 + #define R_MAIN R4 + #elif STEP_MAIN == 5 + #define R_MAIN R5 + #endif + + #define R20(ii, fx) \ + { size_t i; for (i = (ii); i < (ii) + 20; i += STEP_MAIN) \ + { R_MAIN(i, fx, w1) } } \ + +#endif + + + +void Sha1_InitState(CSha1 *p) +{ + p->v.vars.count = 0; + p->state[0] = 0x67452301; + p->state[1] = 0xEFCDAB89; + p->state[2] = 0x98BADCFE; + p->state[3] = 0x10325476; + p->state[4] = 0xC3D2E1F0; +} + +void Sha1_Init(CSha1 *p) +{ + p->v.vars.func_UpdateBlocks = + #ifdef Z7_COMPILER_SHA1_SUPPORTED + g_SHA1_FUNC_UPDATE_BLOCKS; + #else + NULL; + #endif + Sha1_InitState(p); +} + + +Z7_NO_INLINE +void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks) +{ + UInt32 a, b, c, d, e; + UInt32 W[kNumW]; + + if (numBlocks == 0) + return; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + do + { + #if STEP_PRE < 5 || STEP_MAIN < 5 + UInt32 tmp; + #endif + + R20_START + R20(20, f1) + R20(40, f2) + R20(60, f3) + + a += state[0]; + b += state[1]; + c += state[2]; + d += state[3]; + e += state[4]; + + state[0] = a; + state[1] = b; + state[2] = c; + state[3] = d; + state[4] = e; + + data += SHA1_BLOCK_SIZE; + } + while (--numBlocks); +} + + +#define Sha1_UpdateBlock(p) SHA1_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) + +void Sha1_Update(CSha1 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + { + const unsigned pos = (unsigned)p->v.vars.count & (SHA1_BLOCK_SIZE - 1); + const unsigned num = SHA1_BLOCK_SIZE - pos; + p->v.vars.count += size; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + if (pos != 0) + { + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + Sha1_UpdateBlock(p); + } + } + { + const size_t numBlocks = size >> 6; + // if (numBlocks) + SHA1_UPDATE_BLOCKS(p)(p->state, data, numBlocks); + size &= SHA1_BLOCK_SIZE - 1; + if (size == 0) + return; + data += (numBlocks << 6); + memcpy(p->buffer, data, size); + } +} + + +void Sha1_Final(CSha1 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->v.vars.count & (SHA1_BLOCK_SIZE - 1); + p->buffer[pos++] = 0x80; + if (pos > (SHA1_BLOCK_SIZE - 4 * 2)) + { + while (pos != SHA1_BLOCK_SIZE) { p->buffer[pos++] = 0; } + // memset(&p->buf.buffer[pos], 0, SHA1_BLOCK_SIZE - pos); + Sha1_UpdateBlock(p); + pos = 0; + } + memset(&p->buffer[pos], 0, (SHA1_BLOCK_SIZE - 4 * 2) - pos); + { + const UInt64 numBits = p->v.vars.count << 3; + SetBe32(p->buffer + SHA1_BLOCK_SIZE - 4 * 2, (UInt32)(numBits >> 32)) + SetBe32(p->buffer + SHA1_BLOCK_SIZE - 4 * 1, (UInt32)(numBits)) + } + Sha1_UpdateBlock(p); + + SetBe32(digest, p->state[0]) + SetBe32(digest + 4, p->state[1]) + SetBe32(digest + 8, p->state[2]) + SetBe32(digest + 12, p->state[3]) + SetBe32(digest + 16, p->state[4]) + + Sha1_InitState(p); +} + + +void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size) +{ + const UInt64 numBits = (p->v.vars.count + size) << 3; + SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 2], (UInt32)(numBits >> 32)) + SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 1], (UInt32)(numBits)) + // SetBe32((UInt32 *)(block + size), 0x80000000); + SetUi32((UInt32 *)(void *)(block + size), 0x80) + size += 4; + while (size != (SHA1_NUM_BLOCK_WORDS - 2) * 4) + { + *((UInt32 *)(void *)(block + size)) = 0; + size += 4; + } +} + +void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest) +{ + MY_ALIGN (16) + UInt32 st[SHA1_NUM_DIGEST_WORDS]; + + st[0] = p->state[0]; + st[1] = p->state[1]; + st[2] = p->state[2]; + st[3] = p->state[3]; + st[4] = p->state[4]; + + SHA1_UPDATE_BLOCKS(p)(st, data, 1); + + SetBe32(destDigest + 0 , st[0]) + SetBe32(destDigest + 1 * 4, st[1]) + SetBe32(destDigest + 2 * 4, st[2]) + SetBe32(destDigest + 3 * 4, st[3]) + SetBe32(destDigest + 4 * 4, st[4]) +} + + +void Sha1Prepare(void) +{ +#ifdef Z7_COMPILER_SHA1_SUPPORTED + SHA1_FUNC_UPDATE_BLOCKS f, f_hw; + f = Sha1_UpdateBlocks; + f_hw = NULL; +#ifdef MY_CPU_X86_OR_AMD64 + if (CPU_IsSupported_SHA() + && CPU_IsSupported_SSSE3() + ) +#else + if (CPU_IsSupported_SHA1()) +#endif + { + // printf("\n========== HW SHA1 ======== \n"); +#if 1 && defined(MY_CPU_ARM_OR_ARM64) && defined(Z7_MSC_VER_ORIGINAL) && (_MSC_FULL_VER < 192930037) + /* there was bug in MSVC compiler for ARM64 -O2 before version VS2019 16.10 (19.29.30037). + It generated incorrect SHA-1 code. */ + #pragma message("== SHA1 code can work incorrectly with this compiler") + #error Stop_Compiling_MSC_Compiler_BUG_SHA1 +#endif + { + f = f_hw = Sha1_UpdateBlocks_HW; + } + } + g_SHA1_FUNC_UPDATE_BLOCKS = f; + g_SHA1_FUNC_UPDATE_BLOCKS_HW = f_hw; +#endif +} + +#undef kNumW +#undef w +#undef w0 +#undef w1 +#undef f0 +#undef f1 +#undef f2 +#undef f3 +#undef T1 +#undef T5 +#undef M5 +#undef R1 +#undef R2 +#undef R4 +#undef R5 +#undef R20_START +#undef R_PRE +#undef R_MAIN +#undef STEP_PRE +#undef STEP_MAIN +#undef Z7_SHA1_BIG_W +#undef Z7_SHA1_UNROLL +#undef Z7_COMPILER_SHA1_SUPPORTED diff --git a/C/Sha1.h b/C/Sha1.h index 0a297ede2..529be4d8d 100644 --- a/C/Sha1.h +++ b/C/Sha1.h @@ -1,76 +1,86 @@ -/* Sha1.h -- SHA-1 Hash -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_SHA1_H -#define ZIP7_INC_SHA1_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define SHA1_NUM_BLOCK_WORDS 16 -#define SHA1_NUM_DIGEST_WORDS 5 - -#define SHA1_BLOCK_SIZE (SHA1_NUM_BLOCK_WORDS * 4) -#define SHA1_DIGEST_SIZE (SHA1_NUM_DIGEST_WORDS * 4) - -typedef void (Z7_FASTCALL *SHA1_FUNC_UPDATE_BLOCKS)(UInt32 state[5], const Byte *data, size_t numBlocks); - -/* - if (the system supports different SHA1 code implementations) - { - (CSha1::func_UpdateBlocks) will be used - (CSha1::func_UpdateBlocks) can be set by - Sha1_Init() - to default (fastest) - Sha1_SetFunction() - to any algo - } - else - { - (CSha1::func_UpdateBlocks) is ignored. - } -*/ - -typedef struct -{ - SHA1_FUNC_UPDATE_BLOCKS func_UpdateBlocks; - UInt64 count; - UInt64 _pad_2[2]; - UInt32 state[SHA1_NUM_DIGEST_WORDS]; - UInt32 _pad_3[3]; - Byte buffer[SHA1_BLOCK_SIZE]; -} CSha1; - - -#define SHA1_ALGO_DEFAULT 0 -#define SHA1_ALGO_SW 1 -#define SHA1_ALGO_HW 2 - -/* -Sha1_SetFunction() -return: - 0 - (algo) value is not supported, and func_UpdateBlocks was not changed - 1 - func_UpdateBlocks was set according (algo) value. -*/ - -BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo); - -void Sha1_InitState(CSha1 *p); -void Sha1_Init(CSha1 *p); -void Sha1_Update(CSha1 *p, const Byte *data, size_t size); -void Sha1_Final(CSha1 *p, Byte *digest); - -void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size); -void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest); - -// void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); - -/* -call Sha1Prepare() once at program start. -It prepares all supported implementations, and detects the fastest implementation. -*/ - -void Sha1Prepare(void); - -EXTERN_C_END - -#endif +/* Sha1.h -- SHA-1 Hash +: Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SHA1_H +#define ZIP7_INC_SHA1_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA1_NUM_BLOCK_WORDS 16 +#define SHA1_NUM_DIGEST_WORDS 5 + +#define SHA1_BLOCK_SIZE (SHA1_NUM_BLOCK_WORDS * 4) +#define SHA1_DIGEST_SIZE (SHA1_NUM_DIGEST_WORDS * 4) + + + + +typedef void (Z7_FASTCALL *SHA1_FUNC_UPDATE_BLOCKS)(UInt32 state[5], const Byte *data, size_t numBlocks); + +/* + if (the system supports different SHA1 code implementations) + { + (CSha1::func_UpdateBlocks) will be used + (CSha1::func_UpdateBlocks) can be set by + Sha1_Init() - to default (fastest) + Sha1_SetFunction() - to any algo + } + else + { + (CSha1::func_UpdateBlocks) is ignored. + } +*/ + +typedef struct +{ + union + { + struct + { + SHA1_FUNC_UPDATE_BLOCKS func_UpdateBlocks; + UInt64 count; + } vars; + UInt64 _pad_64bit[4]; + void *_pad_align_ptr[2]; + } v; + UInt32 state[SHA1_NUM_DIGEST_WORDS]; + UInt32 _pad_3[3]; + Byte buffer[SHA1_BLOCK_SIZE]; +} CSha1; + + +#define SHA1_ALGO_DEFAULT 0 +#define SHA1_ALGO_SW 1 +#define SHA1_ALGO_HW 2 + +/* +Sha1_SetFunction() +return: + 0 - (algo) value is not supported, and func_UpdateBlocks was not changed + 1 - func_UpdateBlocks was set according (algo) value. +*/ + +BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo); + +void Sha1_InitState(CSha1 *p); +void Sha1_Init(CSha1 *p); +void Sha1_Update(CSha1 *p, const Byte *data, size_t size); +void Sha1_Final(CSha1 *p, Byte *digest); + +void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size); +void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest); + +// void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); + +/* +call Sha1Prepare() once at program start. +It prepares all supported implementations, and detects the fastest implementation. +*/ + +void Sha1Prepare(void); + +EXTERN_C_END + +#endif diff --git a/C/Sha1Opt.c b/C/Sha1Opt.c index d06c34588..8738b94fb 100644 --- a/C/Sha1Opt.c +++ b/C/Sha1Opt.c @@ -1,472 +1,424 @@ -/* Sha1Opt.c -- SHA-1 optimized code for SHA-1 hardware instructions -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" -#include "Compiler.h" -#include "CpuArch.h" - -#if defined(_MSC_VER) -#if (_MSC_VER < 1900) && (_MSC_VER >= 1200) -// #define USE_MY_MM -#endif -#endif - -// #define Z7_USE_HW_SHA_STUB // for debug - -#ifdef MY_CPU_X86_OR_AMD64 - #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check - #define USE_HW_SHA - #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) - #define USE_HW_SHA - #if !defined(_INTEL_COMPILER) - // icc defines __GNUC__, but icc doesn't support __attribute__(__target__) - #if !defined(__SHA__) || !defined(__SSSE3__) - #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) - #endif - #endif - #elif defined(_MSC_VER) - #ifdef USE_MY_MM - #define USE_VER_MIN 1300 - #else - #define USE_VER_MIN 1900 - #endif - #if (_MSC_VER >= USE_VER_MIN) - #define USE_HW_SHA - #else - #define Z7_USE_HW_SHA_STUB - #endif - #endif -// #endif // MY_CPU_X86_OR_AMD64 -#ifndef USE_HW_SHA - // #define Z7_USE_HW_SHA_STUB // for debug -#endif - -#ifdef USE_HW_SHA - -// #pragma message("Sha1 HW") - -// sse/sse2/ssse3: -#include -// sha*: -#include - -#if defined (__clang__) && defined(_MSC_VER) - // #if !defined(__SSSE3__) - // #endif - #if !defined(__SHA__) - #include - #endif -#else - -#ifdef USE_MY_MM -#include "My_mm.h" -#endif - -#endif - -/* -SHA1 uses: -SSE2: - _mm_loadu_si128 - _mm_storeu_si128 - _mm_set_epi32 - _mm_add_epi32 - _mm_shuffle_epi32 / pshufd - _mm_xor_si128 - _mm_cvtsi128_si32 - _mm_cvtsi32_si128 -SSSE3: - _mm_shuffle_epi8 / pshufb - -SHA: - _mm_sha1* -*/ - - -#define XOR_SI128(dest, src) dest = _mm_xor_si128(dest, src); -#define SHUFFLE_EPI8(dest, mask) dest = _mm_shuffle_epi8(dest, mask); -#define SHUFFLE_EPI32(dest, mask) dest = _mm_shuffle_epi32(dest, mask); -#ifdef __clang__ -#define SHA1_RNDS4_RET_TYPE_CAST (__m128i) -#else -#define SHA1_RNDS4_RET_TYPE_CAST -#endif -#define SHA1_RND4(abcd, e0, f) abcd = SHA1_RNDS4_RET_TYPE_CAST _mm_sha1rnds4_epu32(abcd, e0, f); -#define SHA1_NEXTE(e, m) e = _mm_sha1nexte_epu32(e, m); -#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); -#define SHA1_MSG1(dest, src) dest = _mm_sha1msg1_epu32(dest, src); -#define SHA1_MSG2(dest, src) dest = _mm_sha1msg2_epu32(dest, src); - - -#define LOAD_SHUFFLE(m, k) \ - m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ - SHUFFLE_EPI8(m, mask) \ - -#define SM1(m0, m1, m2, m3) \ - SHA1_MSG1(m0, m1) \ - -#define SM2(m0, m1, m2, m3) \ - XOR_SI128(m3, m1) \ - SHA1_MSG2(m3, m2) \ - -#define SM3(m0, m1, m2, m3) \ - XOR_SI128(m3, m1) \ - SM1(m0, m1, m2, m3) \ - SHA1_MSG2(m3, m2) \ - -#define NNN(m0, m1, m2, m3) - - - - - - - - - - - - - - - - - -#define R4(k, e0, e1, m0, m1, m2, m3, OP) \ - e1 = abcd; \ - SHA1_RND4(abcd, e0, (k) / 5) \ - SHA1_NEXTE(e1, m1) \ - OP(m0, m1, m2, m3) \ - -#define R16(k, mx, OP0, OP1, OP2, OP3) \ - R4 ( (k)*4+0, e0,e1, m0,m1,m2,m3, OP0 ) \ - R4 ( (k)*4+1, e1,e0, m1,m2,m3,m0, OP1 ) \ - R4 ( (k)*4+2, e0,e1, m2,m3,m0,m1, OP2 ) \ - R4 ( (k)*4+3, e1,e0, m3,mx,m1,m2, OP3 ) \ - -#define PREPARE_STATE \ - SHUFFLE_EPI32 (abcd, 0x1B) \ - SHUFFLE_EPI32 (e0, 0x1B) \ - - - - - -void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); -#ifdef ATTRIB_SHA -ATTRIB_SHA -#endif -void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks) -{ - const __m128i mask = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f); - - __m128i abcd, e0; - - if (numBlocks == 0) - return; - - abcd = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); // dbca - e0 = _mm_cvtsi32_si128((int)state[4]); // 000e - - PREPARE_STATE - - do - { - __m128i abcd_save, e2; - __m128i m0, m1, m2, m3; - __m128i e1; - - - abcd_save = abcd; - e2 = e0; - - LOAD_SHUFFLE (m0, 0) - LOAD_SHUFFLE (m1, 1) - LOAD_SHUFFLE (m2, 2) - LOAD_SHUFFLE (m3, 3) - - ADD_EPI32(e0, m0) - - R16 ( 0, m0, SM1, SM3, SM3, SM3 ) - R16 ( 1, m0, SM3, SM3, SM3, SM3 ) - R16 ( 2, m0, SM3, SM3, SM3, SM3 ) - R16 ( 3, m0, SM3, SM3, SM3, SM3 ) - R16 ( 4, e2, SM2, NNN, NNN, NNN ) - - ADD_EPI32(abcd, abcd_save) - - data += 64; - } - while (--numBlocks); - - PREPARE_STATE - - _mm_storeu_si128((__m128i *) (void *) state, abcd); - *(state+4) = (UInt32)_mm_cvtsi128_si32(e0); -} - -#endif // USE_HW_SHA - -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) \ - && (!defined(Z7_MSC_VER_ORIGINAL) || (_MSC_VER >= 1929) && (_MSC_FULL_VER >= 192930037)) - #if defined(__ARM_FEATURE_SHA2) \ - || defined(__ARM_FEATURE_CRYPTO) - #define USE_HW_SHA - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define USE_HW_SHA - #endif - #endif - #endif - #endif - -#ifdef USE_HW_SHA - -// #pragma message("=== Sha1 HW === ") -// __ARM_FEATURE_CRYPTO macro is deprecated in favor of the finer grained feature macro __ARM_FEATURE_SHA2 - -#if defined(__clang__) || defined(__GNUC__) -#if !defined(__ARM_FEATURE_SHA2) && \ - !defined(__ARM_FEATURE_CRYPTO) - #ifdef MY_CPU_ARM64 -#if defined(__clang__) - #define ATTRIB_SHA __attribute__((__target__("crypto"))) -#else - #define ATTRIB_SHA __attribute__((__target__("+crypto"))) -#endif - #else -#if defined(__clang__) && (__clang_major__ >= 1) - #define ATTRIB_SHA __attribute__((__target__("armv8-a,sha2"))) -#else - #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) -#endif - #endif -#endif -#else - // _MSC_VER - // for arm32 - #define _ARM_USE_NEW_NEON_INTRINSICS -#endif - - - - - -#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) -#include -#else - - - - - - - - - -#if defined(__clang__) && __clang_major__ < 16 -#if !defined(__ARM_FEATURE_SHA2) && \ - !defined(__ARM_FEATURE_CRYPTO) -// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ") - Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1 -// #if defined(__clang__) && __clang_major__ < 13 - #define __ARM_FEATURE_CRYPTO 1 -// #else - #define __ARM_FEATURE_SHA2 1 -// #endif - Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif -#endif // clang - -#if defined(__clang__) - -#if defined(__ARM_ARCH) && __ARM_ARCH < 8 - Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -// #pragma message("#define __ARM_ARCH 8") - #undef __ARM_ARCH - #define __ARM_ARCH 8 - Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif - -#endif // clang - -#include - -#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \ - defined(__ARM_FEATURE_CRYPTO) && \ - defined(__ARM_FEATURE_SHA2) -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #undef __ARM_FEATURE_CRYPTO - #undef __ARM_FEATURE_SHA2 - #undef Z7_ARM_FEATURE_CRYPTO_WAS_SET -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") -#endif - -#endif // Z7_MSC_VER_ORIGINAL - -typedef uint32x4_t v128; -// typedef __n128 v128; // MSVC -// the bug in clang 3.8.1: -// __builtin_neon_vgetq_lane_i32((int8x16_t)__s0, __p1); -#if defined(__clang__) && (__clang_major__ <= 9) -#pragma GCC diagnostic ignored "-Wvector-conversion" -#endif - -#ifdef MY_CPU_BE - #define MY_rev32_for_LE(x) -#else - #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x))) -#endif - -#define LOAD_128(_p) (*(const v128 *)(const void *)(_p)) -#define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v) - -#define LOAD_SHUFFLE(m, k) \ - m = LOAD_128((data + (k) * 16)); \ - MY_rev32_for_LE(m); \ - -#define SU0(dest, src2, src3) dest = vsha1su0q_u32(dest, src2, src3) -#define SU1(dest, src) dest = vsha1su1q_u32(dest, src) -#define C(e) abcd = vsha1cq_u32(abcd, e, t) -#define P(e) abcd = vsha1pq_u32(abcd, e, t) -#define M(e) abcd = vsha1mq_u32(abcd, e, t) -#define H(e) e = vsha1h_u32(vgetq_lane_u32(abcd, 0)) -#define T(m, c) t = vaddq_u32(m, c) - -void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); -#ifdef ATTRIB_SHA -ATTRIB_SHA -#endif -void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) -{ - v128 abcd; - v128 c0, c1, c2, c3; - uint32_t e0; - - if (numBlocks == 0) - return; - - c0 = vdupq_n_u32(0x5a827999); - c1 = vdupq_n_u32(0x6ed9eba1); - c2 = vdupq_n_u32(0x8f1bbcdc); - c3 = vdupq_n_u32(0xca62c1d6); - - abcd = LOAD_128(&state[0]); - e0 = state[4]; - - do - { - v128 abcd_save; - v128 m0, m1, m2, m3; - v128 t; - uint32_t e0_save, e1; - - abcd_save = abcd; - e0_save = e0; - - LOAD_SHUFFLE (m0, 0) - LOAD_SHUFFLE (m1, 1) - LOAD_SHUFFLE (m2, 2) - LOAD_SHUFFLE (m3, 3) - - T(m0, c0); H(e1); C(e0); - T(m1, c0); SU0(m0, m1, m2); H(e0); C(e1); - T(m2, c0); SU0(m1, m2, m3); SU1(m0, m3); H(e1); C(e0); - T(m3, c0); SU0(m2, m3, m0); SU1(m1, m0); H(e0); C(e1); - T(m0, c0); SU0(m3, m0, m1); SU1(m2, m1); H(e1); C(e0); - T(m1, c1); SU0(m0, m1, m2); SU1(m3, m2); H(e0); P(e1); - T(m2, c1); SU0(m1, m2, m3); SU1(m0, m3); H(e1); P(e0); - T(m3, c1); SU0(m2, m3, m0); SU1(m1, m0); H(e0); P(e1); - T(m0, c1); SU0(m3, m0, m1); SU1(m2, m1); H(e1); P(e0); - T(m1, c1); SU0(m0, m1, m2); SU1(m3, m2); H(e0); P(e1); - T(m2, c2); SU0(m1, m2, m3); SU1(m0, m3); H(e1); M(e0); - T(m3, c2); SU0(m2, m3, m0); SU1(m1, m0); H(e0); M(e1); - T(m0, c2); SU0(m3, m0, m1); SU1(m2, m1); H(e1); M(e0); - T(m1, c2); SU0(m0, m1, m2); SU1(m3, m2); H(e0); M(e1); - T(m2, c2); SU0(m1, m2, m3); SU1(m0, m3); H(e1); M(e0); - T(m3, c3); SU0(m2, m3, m0); SU1(m1, m0); H(e0); P(e1); - T(m0, c3); SU0(m3, m0, m1); SU1(m2, m1); H(e1); P(e0); - T(m1, c3); SU1(m3, m2); H(e0); P(e1); - T(m2, c3); H(e1); P(e0); - T(m3, c3); H(e0); P(e1); - - abcd = vaddq_u32(abcd, abcd_save); - e0 += e0_save; - - data += 64; - } - while (--numBlocks); - - STORE_128(&state[0], abcd); - state[4] = e0; -} - -#endif // USE_HW_SHA - -#endif // MY_CPU_ARM_OR_ARM64 - - -#if !defined(USE_HW_SHA) && defined(Z7_USE_HW_SHA_STUB) -// #error Stop_Compiling_UNSUPPORTED_SHA -// #include - - - -// #include "Sha1.h" -// #if defined(_MSC_VER) -#pragma message("Sha1 HW-SW stub was used") -// #endif -void Z7_FASTCALL Sha1_UpdateBlocks (UInt32 state[5], const Byte *data, size_t numBlocks); -void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); -void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks) -{ - Sha1_UpdateBlocks(state, data, numBlocks); - /* - UNUSED_VAR(state); - UNUSED_VAR(data); - UNUSED_VAR(numBlocks); - exit(1); - return; - */ -} -#endif - -#undef SU0 -#undef SU1 -#undef C -#undef P -#undef M -#undef H -#undef T -#undef MY_rev32_for_LE -#undef NNN -#undef LOAD_128 -#undef STORE_128 -#undef LOAD_SHUFFLE -#undef SM1 -#undef SM2 -#undef SM3 -#undef NNN -#undef R4 -#undef R16 -#undef PREPARE_STATE -#undef USE_HW_SHA -#undef ATTRIB_SHA -#undef USE_VER_MIN -#undef Z7_USE_HW_SHA_STUB +/* Sha1Opt.c -- SHA-1 optimized code for SHA-1 hardware instructions +: Igor Pavlov : Public domain */ + +#include "Precomp.h" +#include "Compiler.h" +#include "CpuArch.h" + +// #define Z7_USE_HW_SHA_STUB // for debug +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check + #define USE_HW_SHA + #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) + #define USE_HW_SHA + #if !defined(__INTEL_COMPILER) + // icc defines __GNUC__, but icc doesn't support __attribute__(__target__) + #if !defined(__SHA__) || !defined(__SSSE3__) + #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) + #endif + #endif + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1900) + #define USE_HW_SHA + #else + #define Z7_USE_HW_SHA_STUB + #endif + #endif +// #endif // MY_CPU_X86_OR_AMD64 +#ifndef USE_HW_SHA + // #define Z7_USE_HW_SHA_STUB // for debug +#endif + +#ifdef USE_HW_SHA + +// #pragma message("Sha1 HW") + + + + +// sse/sse2/ssse3: +#include +// sha*: +#include + +#if defined (__clang__) && defined(_MSC_VER) + #if !defined(__SHA__) + #include + #endif +#else + +#endif + +/* +SHA1 uses: +SSE2: + _mm_loadu_si128 + _mm_storeu_si128 + _mm_set_epi32 + _mm_add_epi32 + _mm_shuffle_epi32 / pshufd + _mm_xor_si128 + _mm_cvtsi128_si32 + _mm_cvtsi32_si128 +SSSE3: + _mm_shuffle_epi8 / pshufb + +SHA: + _mm_sha1* +*/ + +#define XOR_SI128(dest, src) dest = _mm_xor_si128(dest, src); +#define SHUFFLE_EPI8(dest, mask) dest = _mm_shuffle_epi8(dest, mask); +#define SHUFFLE_EPI32(dest, mask) dest = _mm_shuffle_epi32(dest, mask); +#ifdef __clang__ +#define SHA1_RNDS4_RET_TYPE_CAST (__m128i) +#else +#define SHA1_RNDS4_RET_TYPE_CAST +#endif +#define SHA1_RND4(abcd, e0, f) abcd = SHA1_RNDS4_RET_TYPE_CAST _mm_sha1rnds4_epu32(abcd, e0, f); +#define SHA1_NEXTE(e, m) e = _mm_sha1nexte_epu32(e, m); +#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); +#define SHA1_MSG1(dest, src) dest = _mm_sha1msg1_epu32(dest, src); +#define SHA1_MSG2(dest, src) dest = _mm_sha1msg2_epu32(dest, src); + +#define LOAD_SHUFFLE(m, k) \ + m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ + SHUFFLE_EPI8(m, mask) \ + +#define NNN(m0, m1, m2, m3) + +#define SM1(m0, m1, m2, m3) \ + SHA1_MSG1(m0, m1) \ + +#define SM2(m0, m1, m2, m3) \ + XOR_SI128(m3, m1) \ + SHA1_MSG2(m3, m2) \ + +#define SM3(m0, m1, m2, m3) \ + XOR_SI128(m3, m1) \ + SM1(m0, m1, m2, m3) \ + SHA1_MSG2(m3, m2) \ + +#define R4(k, m0, m1, m2, m3, e0, e1, OP) \ + e1 = abcd; \ + SHA1_RND4(abcd, e0, (k) / 5) \ + SHA1_NEXTE(e1, m1) \ + OP(m0, m1, m2, m3) \ + + + +#define R16(k, mx, OP0, OP1, OP2, OP3) \ + R4 ( (k)*4+0, m0,m1,m2,m3, e0,e1, OP0 ) \ + R4 ( (k)*4+1, m1,m2,m3,m0, e1,e0, OP1 ) \ + R4 ( (k)*4+2, m2,m3,m0,m1, e0,e1, OP2 ) \ + R4 ( (k)*4+3, m3,mx,m1,m2, e1,e0, OP3 ) \ + +#define PREPARE_STATE \ + SHUFFLE_EPI32 (abcd, 0x1B) \ + SHUFFLE_EPI32 (e0, 0x1B) \ + + + + + +void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA +ATTRIB_SHA +#endif +void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks) +{ + const __m128i mask = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f); + + + __m128i abcd, e0; + + if (numBlocks == 0) + return; + + abcd = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); // dbca + e0 = _mm_cvtsi32_si128((int)state[4]); // 000e + + PREPARE_STATE + + do + { + __m128i abcd_save, e2; + __m128i m0, m1, m2, m3; + __m128i e1; + + + abcd_save = abcd; + e2 = e0; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + ADD_EPI32(e0, m0) + + R16 ( 0, m0, SM1, SM3, SM3, SM3 ) + R16 ( 1, m0, SM3, SM3, SM3, SM3 ) + R16 ( 2, m0, SM3, SM3, SM3, SM3 ) + R16 ( 3, m0, SM3, SM3, SM3, SM3 ) + R16 ( 4, e2, SM2, NNN, NNN, NNN ) + + ADD_EPI32(abcd, abcd_save) + + data += 64; + } + while (--numBlocks); + + PREPARE_STATE + + _mm_storeu_si128((__m128i *) (void *) state, abcd); + *(state + 4) = (UInt32)_mm_cvtsi128_si32(e0); +} + +#endif // USE_HW_SHA + +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) \ + && (!defined(Z7_MSC_VER_ORIGINAL) || (_MSC_VER >= 1929) && (_MSC_FULL_VER >= 192930037)) + #if defined(__ARM_FEATURE_SHA2) \ + || defined(__ARM_FEATURE_CRYPTO) + #define USE_HW_SHA + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define USE_HW_SHA + #endif + #endif + #endif + #endif + +#ifdef USE_HW_SHA + +// #pragma message("=== Sha1 HW === ") +// __ARM_FEATURE_CRYPTO macro is deprecated in favor of the finer grained feature macro __ARM_FEATURE_SHA2 + +#if defined(__clang__) || defined(__GNUC__) +#if !defined(__ARM_FEATURE_SHA2) && \ + !defined(__ARM_FEATURE_CRYPTO) + #ifdef MY_CPU_ARM64 +#if defined(__clang__) + #define ATTRIB_SHA __attribute__((__target__("crypto"))) +#else + #define ATTRIB_SHA __attribute__((__target__("+crypto"))) +#endif + #else +#if defined(__clang__) && (__clang_major__ >= 1) + #define ATTRIB_SHA __attribute__((__target__("armv8-a,sha2"))) +#else + #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) +#endif + #endif +#endif +#else + // _MSC_VER + // for arm32 + #define _ARM_USE_NEW_NEON_INTRINSICS +#endif + +#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) +#include +#else + +#if defined(__clang__) && __clang_major__ < 16 +#if !defined(__ARM_FEATURE_SHA2) && \ + !defined(__ARM_FEATURE_CRYPTO) +// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ") + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1 +// #if defined(__clang__) && __clang_major__ < 13 + #define __ARM_FEATURE_CRYPTO 1 +// #else + #define __ARM_FEATURE_SHA2 1 +// #endif + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif // clang + +#if defined(__clang__) + +#if defined(__ARM_ARCH) && __ARM_ARCH < 8 + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +// #pragma message("#define __ARM_ARCH 8") + #undef __ARM_ARCH + #define __ARM_ARCH 8 + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#endif // clang + +#include + +#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \ + defined(__ARM_FEATURE_CRYPTO) && \ + defined(__ARM_FEATURE_SHA2) +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #undef __ARM_FEATURE_CRYPTO + #undef __ARM_FEATURE_SHA2 + #undef Z7_ARM_FEATURE_CRYPTO_WAS_SET +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") +#endif + +#endif // Z7_MSC_VER_ORIGINAL + +typedef uint32x4_t v128; +// typedef __n128 v128; // MSVC +// the bug in clang 3.8.1: +// __builtin_neon_vgetq_lane_i32((int8x16_t)__s0, __p1); +#if defined(__clang__) && (__clang_major__ <= 9) +#pragma GCC diagnostic ignored "-Wvector-conversion" +#endif + +#ifdef MY_CPU_BE + #define MY_rev32_for_LE(x) x +#else + #define MY_rev32_for_LE(x) vrev32q_u8(x) +#endif + +#define LOAD_128_32(_p) vld1q_u32(_p) +#define LOAD_128_8(_p) vld1q_u8 (_p) +#define STORE_128_32(_p, _v) vst1q_u32(_p, _v) + +#define LOAD_SHUFFLE(m, k) \ + m = vreinterpretq_u32_u8( \ + MY_rev32_for_LE( \ + LOAD_128_8(data + (k) * 16))); \ + +#define N0(dest, src2, src3) +#define N1(dest, src) +#define U0(dest, src2, src3) dest = vsha1su0q_u32(dest, src2, src3); +#define U1(dest, src) dest = vsha1su1q_u32(dest, src); +#define C(e) abcd = vsha1cq_u32(abcd, e, t) +#define P(e) abcd = vsha1pq_u32(abcd, e, t) +#define M(e) abcd = vsha1mq_u32(abcd, e, t) +#define H(e) e = vsha1h_u32(vgetq_lane_u32(abcd, 0)) +#define T(m, c) t = vaddq_u32(m, c) + +#define R16(d0,d1,d2,d3, f0,z0, f1,z1, f2,z2, f3,z3, w0,w1,w2,w3) \ + T(m0, d0); f0(m3, m0, m1) z0(m2, m1) H(e1); w0(e0); \ + T(m1, d1); f1(m0, m1, m2) z1(m3, m2) H(e0); w1(e1); \ + T(m2, d2); f2(m1, m2, m3) z2(m0, m3) H(e1); w2(e0); \ + T(m3, d3); f3(m2, m3, m0) z3(m1, m0) H(e0); w3(e1); \ + + +void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA +ATTRIB_SHA +#endif +void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + v128 abcd; + v128 c0, c1, c2, c3; + uint32_t e0; + + if (numBlocks == 0) + return; + + c0 = vdupq_n_u32(0x5a827999); + c1 = vdupq_n_u32(0x6ed9eba1); + c2 = vdupq_n_u32(0x8f1bbcdc); + c3 = vdupq_n_u32(0xca62c1d6); + + abcd = LOAD_128_32(&state[0]); + e0 = state[4]; + + do + { + v128 abcd_save; + v128 m0, m1, m2, m3; + v128 t; + uint32_t e0_save, e1; + + abcd_save = abcd; + e0_save = e0; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + R16 ( c0,c0,c0,c0, N0,N1, U0,N1, U0,U1, U0,U1, C,C,C,C ) + R16 ( c0,c1,c1,c1, U0,U1, U0,U1, U0,U1, U0,U1, C,P,P,P ) + R16 ( c1,c1,c2,c2, U0,U1, U0,U1, U0,U1, U0,U1, P,P,M,M ) + R16 ( c2,c2,c2,c3, U0,U1, U0,U1, U0,U1, U0,U1, M,M,M,P ) + R16 ( c3,c3,c3,c3, U0,U1, N0,U1, N0,N1, N0,N1, P,P,P,P ) + + abcd = vaddq_u32(abcd, abcd_save); + e0 += e0_save; + + data += 64; + } + while (--numBlocks); + + STORE_128_32(&state[0], abcd); + state[4] = e0; +} + +#endif // USE_HW_SHA + +#endif // MY_CPU_ARM_OR_ARM64 + +#if !defined(USE_HW_SHA) && defined(Z7_USE_HW_SHA_STUB) +// #error Stop_Compiling_UNSUPPORTED_SHA +// #include +// #include "Sha1.h" +// #if defined(_MSC_VER) +#pragma message("Sha1 HW-SW stub was used") +// #endif +void Z7_FASTCALL Sha1_UpdateBlocks (UInt32 state[5], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks) +{ + Sha1_UpdateBlocks(state, data, numBlocks); + /* + UNUSED_VAR(state); + UNUSED_VAR(data); + UNUSED_VAR(numBlocks); + exit(1); + return; + */ +} +#endif + +#undef U0 +#undef U1 +#undef N0 +#undef N1 +#undef C +#undef P +#undef M +#undef H +#undef T +#undef MY_rev32_for_LE +#undef NNN +#undef LOAD_128 +#undef STORE_128 +#undef LOAD_SHUFFLE +#undef SM1 +#undef SM2 +#undef SM3 +#undef NNN +#undef R4 +#undef R16 +#undef PREPARE_STATE +#undef USE_HW_SHA +#undef ATTRIB_SHA +#undef USE_VER_MIN +#undef Z7_USE_HW_SHA_STUB diff --git a/C/Sha256.c b/C/Sha256.c index e877b6105..ea7ed8e75 100644 --- a/C/Sha256.c +++ b/C/Sha256.c @@ -1,514 +1,492 @@ -/* Sha256.c -- SHA-256 Hash -2024-03-01 : Igor Pavlov : Public domain -This code is based on public domain code from Wei Dai's Crypto++ library. */ - -#include "Precomp.h" - -#include - -#include "CpuArch.h" -#include "RotateDefs.h" -#include "Sha256.h" - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -// #define USE_MY_MM -#endif - -#ifdef MY_CPU_X86_OR_AMD64 - #if defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ - || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) \ - || defined(_MSC_VER) && (_MSC_VER >= 1200) - #define Z7_COMPILER_SHA256_SUPPORTED - #endif -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) - - #if defined(__ARM_FEATURE_SHA2) \ - || defined(__ARM_FEATURE_CRYPTO) - #define Z7_COMPILER_SHA256_SUPPORTED - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define Z7_COMPILER_SHA256_SUPPORTED - #endif - #endif - #endif - #endif -#endif - -void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); - -#ifdef Z7_COMPILER_SHA256_SUPPORTED - void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); - - static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS = Sha256_UpdateBlocks; - static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS_HW; - - #define SHA256_UPDATE_BLOCKS(p) p->func_UpdateBlocks -#else - #define SHA256_UPDATE_BLOCKS(p) Sha256_UpdateBlocks -#endif - - -BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo) -{ - SHA256_FUNC_UPDATE_BLOCKS func = Sha256_UpdateBlocks; - - #ifdef Z7_COMPILER_SHA256_SUPPORTED - if (algo != SHA256_ALGO_SW) - { - if (algo == SHA256_ALGO_DEFAULT) - func = g_SHA256_FUNC_UPDATE_BLOCKS; - else - { - if (algo != SHA256_ALGO_HW) - return False; - func = g_SHA256_FUNC_UPDATE_BLOCKS_HW; - if (!func) - return False; - } - } - #else - if (algo > 1) - return False; - #endif - - p->func_UpdateBlocks = func; - return True; -} - - -/* define it for speed optimization */ - -#ifdef Z7_SFX - #define STEP_PRE 1 - #define STEP_MAIN 1 -#else - #define STEP_PRE 2 - #define STEP_MAIN 4 - // #define Z7_SHA256_UNROLL -#endif - -#undef Z7_SHA256_BIG_W -#if STEP_MAIN != 16 - #define Z7_SHA256_BIG_W -#endif - - - - -void Sha256_InitState(CSha256 *p) -{ - p->count = 0; - p->state[0] = 0x6a09e667; - p->state[1] = 0xbb67ae85; - p->state[2] = 0x3c6ef372; - p->state[3] = 0xa54ff53a; - p->state[4] = 0x510e527f; - p->state[5] = 0x9b05688c; - p->state[6] = 0x1f83d9ab; - p->state[7] = 0x5be0cd19; -} - -void Sha256_Init(CSha256 *p) -{ - p->func_UpdateBlocks = - #ifdef Z7_COMPILER_SHA256_SUPPORTED - g_SHA256_FUNC_UPDATE_BLOCKS; - #else - NULL; - #endif - Sha256_InitState(p); -} - -#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22)) -#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25)) -#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) -#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) - -#define Ch(x,y,z) (z^(x&(y^z))) -#define Maj(x,y,z) ((x&y)|(z&(x|y))) - - -#define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe32(data + ((size_t)(j) + i) * 4)) - -#define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15)) - -#ifdef Z7_SHA256_BIG_W - // we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned. - #define w(j, i) W[(size_t)(j) + i] - #define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i)) -#else - #if STEP_MAIN == 16 - #define w(j, i) W[(i) & 15] - #else - #define w(j, i) W[((size_t)(j) + (i)) & 15] - #endif - #define blk2(j, i) (w(j, i) += blk2_main(j, i)) -#endif - -#define W_MAIN(i) blk2(j, i) - - -#define T1(wx, i) \ - tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ - h = g; \ - g = f; \ - f = e; \ - e = d + tmp; \ - tmp += S0(a) + Maj(a, b, c); \ - d = c; \ - c = b; \ - b = a; \ - a = tmp; \ - -#define R1_PRE(i) T1( W_PRE, i) -#define R1_MAIN(i) T1( W_MAIN, i) - -#if (!defined(Z7_SHA256_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4) -#define R2_MAIN(i) \ - R1_MAIN(i) \ - R1_MAIN(i + 1) \ - -#endif - - - -#if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8 - -#define T4( a,b,c,d,e,f,g,h, wx, i) \ - h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ - tmp = h; \ - h += d; \ - d = tmp + S0(a) + Maj(a, b, c); \ - -#define R4( wx, i) \ - T4 ( a,b,c,d,e,f,g,h, wx, (i )); \ - T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \ - T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \ - T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \ - -#define R4_PRE(i) R4( W_PRE, i) -#define R4_MAIN(i) R4( W_MAIN, i) - - -#define T8( a,b,c,d,e,f,g,h, wx, i) \ - h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ - d += h; \ - h += S0(a) + Maj(a, b, c); \ - -#define R8( wx, i) \ - T8 ( a,b,c,d,e,f,g,h, wx, i ); \ - T8 ( h,a,b,c,d,e,f,g, wx, i+1); \ - T8 ( g,h,a,b,c,d,e,f, wx, i+2); \ - T8 ( f,g,h,a,b,c,d,e, wx, i+3); \ - T8 ( e,f,g,h,a,b,c,d, wx, i+4); \ - T8 ( d,e,f,g,h,a,b,c, wx, i+5); \ - T8 ( c,d,e,f,g,h,a,b, wx, i+6); \ - T8 ( b,c,d,e,f,g,h,a, wx, i+7); \ - -#define R8_PRE(i) R8( W_PRE, i) -#define R8_MAIN(i) R8( W_MAIN, i) - -#endif - -// static -extern MY_ALIGN(64) -const UInt32 SHA256_K_ARRAY[64]; - -MY_ALIGN(64) -const UInt32 SHA256_K_ARRAY[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -#define K SHA256_K_ARRAY - - -Z7_NO_INLINE -void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks) -{ - UInt32 W - #ifdef Z7_SHA256_BIG_W - [64]; - #else - [16]; - #endif - - unsigned j; - - UInt32 a,b,c,d,e,f,g,h; - - #if !defined(Z7_SHA256_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4) - UInt32 tmp; - #endif - - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - f = state[5]; - g = state[6]; - h = state[7]; - - while (numBlocks) - { - - for (j = 0; j < 16; j += STEP_PRE) - { - #if STEP_PRE > 4 - - #if STEP_PRE < 8 - R4_PRE(0); - #else - R8_PRE(0); - #if STEP_PRE == 16 - R8_PRE(8); - #endif - #endif - - #else - - R1_PRE(0) - #if STEP_PRE >= 2 - R1_PRE(1) - #if STEP_PRE >= 4 - R1_PRE(2) - R1_PRE(3) - #endif - #endif - - #endif - } - - for (j = 16; j < 64; j += STEP_MAIN) - { - #if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8 - - #if STEP_MAIN < 8 - R4_MAIN(0) - #else - R8_MAIN(0) - #if STEP_MAIN == 16 - R8_MAIN(8) - #endif - #endif - - #else - - R1_MAIN(0) - #if STEP_MAIN >= 2 - R1_MAIN(1) - #if STEP_MAIN >= 4 - R2_MAIN(2) - #if STEP_MAIN >= 8 - R2_MAIN(4) - R2_MAIN(6) - #if STEP_MAIN >= 16 - R2_MAIN(8) - R2_MAIN(10) - R2_MAIN(12) - R2_MAIN(14) - #endif - #endif - #endif - #endif - #endif - } - - a += state[0]; state[0] = a; - b += state[1]; state[1] = b; - c += state[2]; state[2] = c; - d += state[3]; state[3] = d; - e += state[4]; state[4] = e; - f += state[5]; state[5] = f; - g += state[6]; state[6] = g; - h += state[7]; state[7] = h; - - data += 64; - numBlocks--; - } - - /* Wipe variables */ - /* memset(W, 0, sizeof(W)); */ -} - -#undef S0 -#undef S1 -#undef s0 -#undef s1 -#undef K - -#define Sha256_UpdateBlock(p) SHA256_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) - -void Sha256_Update(CSha256 *p, const Byte *data, size_t size) -{ - if (size == 0) - return; - - { - unsigned pos = (unsigned)p->count & 0x3F; - unsigned num; - - p->count += size; - - num = 64 - pos; - if (num > size) - { - memcpy(p->buffer + pos, data, size); - return; - } - - if (pos != 0) - { - size -= num; - memcpy(p->buffer + pos, data, num); - data += num; - Sha256_UpdateBlock(p); - } - } - { - size_t numBlocks = size >> 6; - SHA256_UPDATE_BLOCKS(p)(p->state, data, numBlocks); - size &= 0x3F; - if (size == 0) - return; - data += (numBlocks << 6); - memcpy(p->buffer, data, size); - } -} - - -void Sha256_Final(CSha256 *p, Byte *digest) -{ - unsigned pos = (unsigned)p->count & 0x3F; - unsigned i; - - p->buffer[pos++] = 0x80; - - if (pos > (64 - 8)) - { - while (pos != 64) { p->buffer[pos++] = 0; } - // memset(&p->buf.buffer[pos], 0, 64 - pos); - Sha256_UpdateBlock(p); - pos = 0; - } - - /* - if (pos & 3) - { - p->buffer[pos] = 0; - p->buffer[pos + 1] = 0; - p->buffer[pos + 2] = 0; - pos += 3; - pos &= ~3; - } - { - for (; pos < 64 - 8; pos += 4) - *(UInt32 *)(&p->buffer[pos]) = 0; - } - */ - - memset(&p->buffer[pos], 0, (64 - 8) - pos); - - { - UInt64 numBits = (p->count << 3); - SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)) - SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)) - } - - Sha256_UpdateBlock(p); - - for (i = 0; i < 8; i += 2) - { - UInt32 v0 = p->state[i]; - UInt32 v1 = p->state[(size_t)i + 1]; - SetBe32(digest , v0) - SetBe32(digest + 4, v1) - digest += 8; - } - - Sha256_InitState(p); -} - - -void Sha256Prepare(void) -{ - #ifdef Z7_COMPILER_SHA256_SUPPORTED - SHA256_FUNC_UPDATE_BLOCKS f, f_hw; - f = Sha256_UpdateBlocks; - f_hw = NULL; - #ifdef MY_CPU_X86_OR_AMD64 - #ifndef USE_MY_MM - if (CPU_IsSupported_SHA() - && CPU_IsSupported_SSSE3() - // && CPU_IsSupported_SSE41() - ) - #endif - #else - if (CPU_IsSupported_SHA2()) - #endif - { - // printf("\n========== HW SHA256 ======== \n"); - f = f_hw = Sha256_UpdateBlocks_HW; - } - g_SHA256_FUNC_UPDATE_BLOCKS = f; - g_SHA256_FUNC_UPDATE_BLOCKS_HW = f_hw; - #endif -} - -#undef S0 -#undef S1 -#undef s0 -#undef s1 -#undef Ch -#undef Maj -#undef W_MAIN -#undef W_PRE -#undef w -#undef blk2_main -#undef blk2 -#undef T1 -#undef T4 -#undef T8 -#undef R1_PRE -#undef R1_MAIN -#undef R2_MAIN -#undef R4 -#undef R4_PRE -#undef R4_MAIN -#undef R8 -#undef R8_PRE -#undef R8_MAIN -#undef STEP_PRE -#undef STEP_MAIN -#undef Z7_SHA256_BIG_W -#undef Z7_SHA256_UNROLL -#undef Z7_COMPILER_SHA256_SUPPORTED +/* Sha256.c -- SHA-256 Hash +: Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "Sha256.h" +#include "RotateDefs.h" +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) \ + || defined(_MSC_VER) && (_MSC_VER >= 1200) + #define Z7_COMPILER_SHA256_SUPPORTED + #endif +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) + + #if defined(__ARM_FEATURE_SHA2) \ + || defined(__ARM_FEATURE_CRYPTO) + #define Z7_COMPILER_SHA256_SUPPORTED + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define Z7_COMPILER_SHA256_SUPPORTED + #endif + #endif + #endif + #endif +#endif + +void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); + +#ifdef Z7_COMPILER_SHA256_SUPPORTED + void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); + + static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS = Sha256_UpdateBlocks; + static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS_HW; + + #define SHA256_UPDATE_BLOCKS(p) p->v.vars.func_UpdateBlocks +#else + #define SHA256_UPDATE_BLOCKS(p) Sha256_UpdateBlocks +#endif + + +BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo) +{ + SHA256_FUNC_UPDATE_BLOCKS func = Sha256_UpdateBlocks; + + #ifdef Z7_COMPILER_SHA256_SUPPORTED + if (algo != SHA256_ALGO_SW) + { + if (algo == SHA256_ALGO_DEFAULT) + func = g_SHA256_FUNC_UPDATE_BLOCKS; + else + { + if (algo != SHA256_ALGO_HW) + return False; + func = g_SHA256_FUNC_UPDATE_BLOCKS_HW; + if (!func) + return False; + } + } + #else + if (algo > 1) + return False; + #endif + + p->v.vars.func_UpdateBlocks = func; + return True; +} + + +/* define it for speed optimization */ + +#ifdef Z7_SFX + #define STEP_PRE 1 + #define STEP_MAIN 1 +#else + #define STEP_PRE 2 + #define STEP_MAIN 4 + // #define Z7_SHA256_UNROLL +#endif + +#undef Z7_SHA256_BIG_W +#if STEP_MAIN != 16 + #define Z7_SHA256_BIG_W +#endif + + + + +void Sha256_InitState(CSha256 *p) +{ + p->v.vars.count = 0; + p->state[0] = 0x6a09e667; + p->state[1] = 0xbb67ae85; + p->state[2] = 0x3c6ef372; + p->state[3] = 0xa54ff53a; + p->state[4] = 0x510e527f; + p->state[5] = 0x9b05688c; + p->state[6] = 0x1f83d9ab; + p->state[7] = 0x5be0cd19; +} + + + + + + + + +void Sha256_Init(CSha256 *p) +{ + p->v.vars.func_UpdateBlocks = + #ifdef Z7_COMPILER_SHA256_SUPPORTED + g_SHA256_FUNC_UPDATE_BLOCKS; + #else + NULL; + #endif + Sha256_InitState(p); +} + +#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x,22)) +#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x,25)) +#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) +#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >>10)) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + + +#define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe32(data + ((size_t)(j) + i) * 4)) + +#define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15)) + +#ifdef Z7_SHA256_BIG_W + // we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned. + #define w(j, i) W[(size_t)(j) + i] + #define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i)) +#else + #if STEP_MAIN == 16 + #define w(j, i) W[(i) & 15] + #else + #define w(j, i) W[((size_t)(j) + (i)) & 15] + #endif + #define blk2(j, i) (w(j, i) += blk2_main(j, i)) +#endif + +#define W_MAIN(i) blk2(j, i) + + +#define T1(wx, i) \ + tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + h = g; \ + g = f; \ + f = e; \ + e = d + tmp; \ + tmp += S0(a) + Maj(a, b, c); \ + d = c; \ + c = b; \ + b = a; \ + a = tmp; \ + +#define R1_PRE(i) T1( W_PRE, i) +#define R1_MAIN(i) T1( W_MAIN, i) + +#if (!defined(Z7_SHA256_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4) +#define R2_MAIN(i) \ + R1_MAIN(i) \ + R1_MAIN(i + 1) \ + +#endif + + + +#if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8 + +#define T4( a,b,c,d,e,f,g,h, wx, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + tmp = h; \ + h += d; \ + d = tmp + S0(a) + Maj(a, b, c); \ + +#define R4( wx, i) \ + T4 ( a,b,c,d,e,f,g,h, wx, (i )); \ + T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \ + T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \ + T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \ + +#define R4_PRE(i) R4( W_PRE, i) +#define R4_MAIN(i) R4( W_MAIN, i) + + +#define T8( a,b,c,d,e,f,g,h, wx, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + d += h; \ + h += S0(a) + Maj(a, b, c); \ + +#define R8( wx, i) \ + T8 ( a,b,c,d,e,f,g,h, wx, i ); \ + T8 ( h,a,b,c,d,e,f,g, wx, i+1); \ + T8 ( g,h,a,b,c,d,e,f, wx, i+2); \ + T8 ( f,g,h,a,b,c,d,e, wx, i+3); \ + T8 ( e,f,g,h,a,b,c,d, wx, i+4); \ + T8 ( d,e,f,g,h,a,b,c, wx, i+5); \ + T8 ( c,d,e,f,g,h,a,b, wx, i+6); \ + T8 ( b,c,d,e,f,g,h,a, wx, i+7); \ + +#define R8_PRE(i) R8( W_PRE, i) +#define R8_MAIN(i) R8( W_MAIN, i) + +#endif + + +extern +MY_ALIGN(64) const UInt32 SHA256_K_ARRAY[64]; +MY_ALIGN(64) const UInt32 SHA256_K_ARRAY[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + + + + +#define K SHA256_K_ARRAY + +Z7_NO_INLINE +void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + UInt32 W +#ifdef Z7_SHA256_BIG_W + [64]; +#else + [16]; +#endif + unsigned j; + UInt32 a,b,c,d,e,f,g,h; +#if !defined(Z7_SHA256_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4) + UInt32 tmp; +#endif + + if (numBlocks == 0) return; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + + do + { + + for (j = 0; j < 16; j += STEP_PRE) + { + #if STEP_PRE > 4 + + #if STEP_PRE < 8 + R4_PRE(0); + #else + R8_PRE(0); + #if STEP_PRE == 16 + R8_PRE(8); + #endif + #endif + + #else + + R1_PRE(0) + #if STEP_PRE >= 2 + R1_PRE(1) + #if STEP_PRE >= 4 + R1_PRE(2) + R1_PRE(3) + #endif + #endif + + #endif + } + + for (j = 16; j < 64; j += STEP_MAIN) + { + #if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8 + + #if STEP_MAIN < 8 + R4_MAIN(0) + #else + R8_MAIN(0) + #if STEP_MAIN == 16 + R8_MAIN(8) + #endif + #endif + + #else + + R1_MAIN(0) + #if STEP_MAIN >= 2 + R1_MAIN(1) + #if STEP_MAIN >= 4 + R2_MAIN(2) + #if STEP_MAIN >= 8 + R2_MAIN(4) + R2_MAIN(6) + #if STEP_MAIN >= 16 + R2_MAIN(8) + R2_MAIN(10) + R2_MAIN(12) + R2_MAIN(14) + #endif + #endif + #endif + #endif + #endif + } + + a += state[0]; state[0] = a; + b += state[1]; state[1] = b; + c += state[2]; state[2] = c; + d += state[3]; state[3] = d; + e += state[4]; state[4] = e; + f += state[5]; state[5] = f; + g += state[6]; state[6] = g; + h += state[7]; state[7] = h; + + data += SHA256_BLOCK_SIZE; + } + while (--numBlocks); +} + + +#define Sha256_UpdateBlock(p) SHA256_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) + +void Sha256_Update(CSha256 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + { + const unsigned pos = (unsigned)p->v.vars.count & (SHA256_BLOCK_SIZE - 1); + const unsigned num = SHA256_BLOCK_SIZE - pos; + p->v.vars.count += size; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + if (pos != 0) + { + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + Sha256_UpdateBlock(p); + } + } + { + const size_t numBlocks = size >> 6; + // if (numBlocks) + SHA256_UPDATE_BLOCKS(p)(p->state, data, numBlocks); + size &= SHA256_BLOCK_SIZE - 1; + if (size == 0) + return; + data += (numBlocks << 6); + memcpy(p->buffer, data, size); + } +} + + +void Sha256_Final(CSha256 *p, Byte *digest) +{ + unsigned pos = (unsigned)p->v.vars.count & (SHA256_BLOCK_SIZE - 1); + p->buffer[pos++] = 0x80; + if (pos > (SHA256_BLOCK_SIZE - 4 * 2)) + { + while (pos != SHA256_BLOCK_SIZE) { p->buffer[pos++] = 0; } + // memset(&p->buf.buffer[pos], 0, SHA256_BLOCK_SIZE - pos); + Sha256_UpdateBlock(p); + pos = 0; + } + memset(&p->buffer[pos], 0, (SHA256_BLOCK_SIZE - 4 * 2) - pos); + { + const UInt64 numBits = p->v.vars.count << 3; + SetBe32(p->buffer + SHA256_BLOCK_SIZE - 4 * 2, (UInt32)(numBits >> 32)) + SetBe32(p->buffer + SHA256_BLOCK_SIZE - 4 * 1, (UInt32)(numBits)) + } + Sha256_UpdateBlock(p); +#if 1 && defined(MY_CPU_BE) + memcpy(digest, p->state, SHA256_DIGEST_SIZE); +#else + { + unsigned i; + for (i = 0; i < 8; i += 2) + { + const UInt32 v0 = p->state[i]; + const UInt32 v1 = p->state[(size_t)i + 1]; + SetBe32(digest , v0) + SetBe32(digest + 4, v1) + digest += 4 * 2; + } + } + + + + +#endif + Sha256_InitState(p); +} + + +void Sha256Prepare(void) +{ +#ifdef Z7_COMPILER_SHA256_SUPPORTED + SHA256_FUNC_UPDATE_BLOCKS f, f_hw; + f = Sha256_UpdateBlocks; + f_hw = NULL; +#ifdef MY_CPU_X86_OR_AMD64 + if (CPU_IsSupported_SHA() + && CPU_IsSupported_SSSE3() + ) +#else + if (CPU_IsSupported_SHA2()) +#endif + { + // printf("\n========== HW SHA256 ======== \n"); + f = f_hw = Sha256_UpdateBlocks_HW; + } + g_SHA256_FUNC_UPDATE_BLOCKS = f; + g_SHA256_FUNC_UPDATE_BLOCKS_HW = f_hw; +#endif +} + +#undef U64C +#undef K +#undef S0 +#undef S1 +#undef s0 +#undef s1 +#undef Ch +#undef Maj +#undef W_MAIN +#undef W_PRE +#undef w +#undef blk2_main +#undef blk2 +#undef T1 +#undef T4 +#undef T8 +#undef R1_PRE +#undef R1_MAIN +#undef R2_MAIN +#undef R4 +#undef R4_PRE +#undef R4_MAIN +#undef R8 +#undef R8_PRE +#undef R8_MAIN +#undef STEP_PRE +#undef STEP_MAIN +#undef Z7_SHA256_BIG_W +#undef Z7_SHA256_UNROLL +#undef Z7_COMPILER_SHA256_SUPPORTED diff --git a/C/Sha256.h b/C/Sha256.h index af8c9bc8a..75329cdf0 100644 --- a/C/Sha256.h +++ b/C/Sha256.h @@ -1,76 +1,86 @@ -/* Sha256.h -- SHA-256 Hash -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_SHA256_H -#define ZIP7_INC_SHA256_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define SHA256_NUM_BLOCK_WORDS 16 -#define SHA256_NUM_DIGEST_WORDS 8 - -#define SHA256_BLOCK_SIZE (SHA256_NUM_BLOCK_WORDS * 4) -#define SHA256_DIGEST_SIZE (SHA256_NUM_DIGEST_WORDS * 4) - -typedef void (Z7_FASTCALL *SHA256_FUNC_UPDATE_BLOCKS)(UInt32 state[8], const Byte *data, size_t numBlocks); - -/* - if (the system supports different SHA256 code implementations) - { - (CSha256::func_UpdateBlocks) will be used - (CSha256::func_UpdateBlocks) can be set by - Sha256_Init() - to default (fastest) - Sha256_SetFunction() - to any algo - } - else - { - (CSha256::func_UpdateBlocks) is ignored. - } -*/ - -typedef struct -{ - SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks; - UInt64 count; - UInt64 _pad_2[2]; - UInt32 state[SHA256_NUM_DIGEST_WORDS]; - - Byte buffer[SHA256_BLOCK_SIZE]; -} CSha256; - - -#define SHA256_ALGO_DEFAULT 0 -#define SHA256_ALGO_SW 1 -#define SHA256_ALGO_HW 2 - -/* -Sha256_SetFunction() -return: - 0 - (algo) value is not supported, and func_UpdateBlocks was not changed - 1 - func_UpdateBlocks was set according (algo) value. -*/ - -BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo); - -void Sha256_InitState(CSha256 *p); -void Sha256_Init(CSha256 *p); -void Sha256_Update(CSha256 *p, const Byte *data, size_t size); -void Sha256_Final(CSha256 *p, Byte *digest); - - - - -// void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); - -/* -call Sha256Prepare() once at program start. -It prepares all supported implementations, and detects the fastest implementation. -*/ - -void Sha256Prepare(void); - -EXTERN_C_END - -#endif +/* Sha256.h -- SHA-256 Hash +: Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SHA256_H +#define ZIP7_INC_SHA256_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA256_NUM_BLOCK_WORDS 16 +#define SHA256_NUM_DIGEST_WORDS 8 + +#define SHA256_BLOCK_SIZE (SHA256_NUM_BLOCK_WORDS * 4) +#define SHA256_DIGEST_SIZE (SHA256_NUM_DIGEST_WORDS * 4) + + + + +typedef void (Z7_FASTCALL *SHA256_FUNC_UPDATE_BLOCKS)(UInt32 state[8], const Byte *data, size_t numBlocks); + +/* + if (the system supports different SHA256 code implementations) + { + (CSha256::func_UpdateBlocks) will be used + (CSha256::func_UpdateBlocks) can be set by + Sha256_Init() - to default (fastest) + Sha256_SetFunction() - to any algo + } + else + { + (CSha256::func_UpdateBlocks) is ignored. + } +*/ + +typedef struct +{ + union + { + struct + { + SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks; + UInt64 count; + } vars; + UInt64 _pad_64bit[4]; + void *_pad_align_ptr[2]; + } v; + UInt32 state[SHA256_NUM_DIGEST_WORDS]; + + Byte buffer[SHA256_BLOCK_SIZE]; +} CSha256; + + +#define SHA256_ALGO_DEFAULT 0 +#define SHA256_ALGO_SW 1 +#define SHA256_ALGO_HW 2 + +/* +Sha256_SetFunction() +return: + 0 - (algo) value is not supported, and func_UpdateBlocks was not changed + 1 - func_UpdateBlocks was set according (algo) value. +*/ + +BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo); + +void Sha256_InitState(CSha256 *p); +void Sha256_Init(CSha256 *p); +void Sha256_Update(CSha256 *p, const Byte *data, size_t size); +void Sha256_Final(CSha256 *p, Byte *digest); + + + + +// void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); + +/* +call Sha256Prepare() once at program start. +It prepares all supported implementations, and detects the fastest implementation. +*/ + +void Sha256Prepare(void); + +EXTERN_C_END + +#endif diff --git a/C/Sha256Opt.c b/C/Sha256Opt.c index 9bbfb5ab5..1c6b50f8d 100644 --- a/C/Sha256Opt.c +++ b/C/Sha256Opt.c @@ -1,467 +1,451 @@ -/* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" -#include "Compiler.h" -#include "CpuArch.h" - -#if defined(_MSC_VER) -#if (_MSC_VER < 1900) && (_MSC_VER >= 1200) -// #define USE_MY_MM -#endif -#endif - -// #define Z7_USE_HW_SHA_STUB // for debug - -#ifdef MY_CPU_X86_OR_AMD64 - #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check - #define USE_HW_SHA - #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ - || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) - #define USE_HW_SHA - #if !defined(_INTEL_COMPILER) - // icc defines __GNUC__, but icc doesn't support __attribute__(__target__) - #if !defined(__SHA__) || !defined(__SSSE3__) - #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) - #endif - #endif - #elif defined(_MSC_VER) - #ifdef USE_MY_MM - #define USE_VER_MIN 1300 - #else - #define USE_VER_MIN 1900 - #endif - #if (_MSC_VER >= USE_VER_MIN) - #define USE_HW_SHA - #else - #define Z7_USE_HW_SHA_STUB - #endif - #endif -// #endif // MY_CPU_X86_OR_AMD64 -#ifndef USE_HW_SHA - // #define Z7_USE_HW_SHA_STUB // for debug -#endif - -#ifdef USE_HW_SHA - -// #pragma message("Sha256 HW") - -// sse/sse2/ssse3: -#include -// sha*: -#include - -#if defined (__clang__) && defined(_MSC_VER) - // #if !defined(__SSSE3__) - // #endif - #if !defined(__SHA__) - #include - #endif -#else - -#ifdef USE_MY_MM -#include "My_mm.h" -#endif - -#endif - -/* -SHA256 uses: -SSE2: - _mm_loadu_si128 - _mm_storeu_si128 - _mm_set_epi32 - _mm_add_epi32 - _mm_shuffle_epi32 / pshufd - - - -SSSE3: - _mm_shuffle_epi8 / pshufb - _mm_alignr_epi8 -SHA: - _mm_sha256* -*/ - -// K array must be aligned for 16-bytes at least. -// The compiler can look align attribute and selects -// movdqu - for code without align attribute -// movdqa - for code with align attribute -extern -MY_ALIGN(64) -const UInt32 SHA256_K_ARRAY[64]; - -#define K SHA256_K_ARRAY - - -#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); -#define SHA256_MSG1(dest, src) dest = _mm_sha256msg1_epu32(dest, src); -#define SHA25G_MSG2(dest, src) dest = _mm_sha256msg2_epu32(dest, src); - - -#define LOAD_SHUFFLE(m, k) \ - m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ - m = _mm_shuffle_epi8(m, mask); \ - -#define SM1(g0, g1, g2, g3) \ - SHA256_MSG1(g3, g0); \ - -#define SM2(g0, g1, g2, g3) \ - tmp = _mm_alignr_epi8(g1, g0, 4); \ - ADD_EPI32(g2, tmp) \ - SHA25G_MSG2(g2, g1); \ - -// #define LS0(k, g0, g1, g2, g3) LOAD_SHUFFLE(g0, k) -// #define LS1(k, g0, g1, g2, g3) LOAD_SHUFFLE(g1, k+1) - - -#define NNN(g0, g1, g2, g3) - - -#define RND2(t0, t1) \ - t0 = _mm_sha256rnds2_epu32(t0, t1, msg); - -#define RND2_0(m, k) \ - msg = _mm_add_epi32(m, *(const __m128i *) (const void *) &K[(k) * 4]); \ - RND2(state0, state1); \ - msg = _mm_shuffle_epi32(msg, 0x0E); \ - - -#define RND2_1 \ - RND2(state1, state0); \ - - -// We use scheme with 3 rounds ahead for SHA256_MSG1 / 2 rounds ahead for SHA256_MSG2 - -#define R4(k, g0, g1, g2, g3, OP0, OP1) \ - RND2_0(g0, k) \ - OP0(g0, g1, g2, g3) \ - RND2_1 \ - OP1(g0, g1, g2, g3) \ - -#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ - R4 ( (k)*4+0, m0,m1,m2,m3, OP0, OP1 ) \ - R4 ( (k)*4+1, m1,m2,m3,m0, OP2, OP3 ) \ - R4 ( (k)*4+2, m2,m3,m0,m1, OP4, OP5 ) \ - R4 ( (k)*4+3, m3,m0,m1,m2, OP6, OP7 ) \ - -#define PREPARE_STATE \ - tmp = _mm_shuffle_epi32(state0, 0x1B); /* abcd */ \ - state0 = _mm_shuffle_epi32(state1, 0x1B); /* efgh */ \ - state1 = state0; \ - state0 = _mm_unpacklo_epi64(state0, tmp); /* cdgh */ \ - state1 = _mm_unpackhi_epi64(state1, tmp); /* abef */ \ - - -void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); -#ifdef ATTRIB_SHA -ATTRIB_SHA -#endif -void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) -{ - const __m128i mask = _mm_set_epi32(0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203); - __m128i tmp; - __m128i state0, state1; - - if (numBlocks == 0) - return; - - state0 = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); - state1 = _mm_loadu_si128((const __m128i *) (const void *) &state[4]); - - PREPARE_STATE - - do - { - __m128i state0_save, state1_save; - __m128i m0, m1, m2, m3; - __m128i msg; - // #define msg tmp - - state0_save = state0; - state1_save = state1; - - LOAD_SHUFFLE (m0, 0) - LOAD_SHUFFLE (m1, 1) - LOAD_SHUFFLE (m2, 2) - LOAD_SHUFFLE (m3, 3) - - - - R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ) - R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) - R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) - R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ) - - ADD_EPI32(state0, state0_save) - ADD_EPI32(state1, state1_save) - - data += 64; - } - while (--numBlocks); - - PREPARE_STATE - - _mm_storeu_si128((__m128i *) (void *) &state[0], state0); - _mm_storeu_si128((__m128i *) (void *) &state[4], state1); -} - -#endif // USE_HW_SHA - -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) - - #if defined(__ARM_FEATURE_SHA2) \ - || defined(__ARM_FEATURE_CRYPTO) - #define USE_HW_SHA - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define USE_HW_SHA - #endif - #endif - #endif - #endif - -#ifdef USE_HW_SHA - -// #pragma message("=== Sha256 HW === ") - - -#if defined(__clang__) || defined(__GNUC__) -#if !defined(__ARM_FEATURE_SHA2) && \ - !defined(__ARM_FEATURE_CRYPTO) - #ifdef MY_CPU_ARM64 -#if defined(__clang__) - #define ATTRIB_SHA __attribute__((__target__("crypto"))) -#else - #define ATTRIB_SHA __attribute__((__target__("+crypto"))) -#endif - #else -#if defined(__clang__) && (__clang_major__ >= 1) - #define ATTRIB_SHA __attribute__((__target__("armv8-a,sha2"))) -#else - #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) -#endif - #endif -#endif -#else - // _MSC_VER - // for arm32 - #define _ARM_USE_NEW_NEON_INTRINSICS -#endif - - - - - -#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) -#include -#else - - - - - - - - - -#if defined(__clang__) && __clang_major__ < 16 -#if !defined(__ARM_FEATURE_SHA2) && \ - !defined(__ARM_FEATURE_CRYPTO) -// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ") - Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1 -// #if defined(__clang__) && __clang_major__ < 13 - #define __ARM_FEATURE_CRYPTO 1 -// #else - #define __ARM_FEATURE_SHA2 1 -// #endif - Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif -#endif // clang - -#if defined(__clang__) - -#if defined(__ARM_ARCH) && __ARM_ARCH < 8 - Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -// #pragma message("#define __ARM_ARCH 8") - #undef __ARM_ARCH - #define __ARM_ARCH 8 - Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif - -#endif // clang - -#include - -#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \ - defined(__ARM_FEATURE_CRYPTO) && \ - defined(__ARM_FEATURE_SHA2) -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER - #undef __ARM_FEATURE_CRYPTO - #undef __ARM_FEATURE_SHA2 - #undef Z7_ARM_FEATURE_CRYPTO_WAS_SET -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") -#endif - -#endif // Z7_MSC_VER_ORIGINAL - -typedef uint32x4_t v128; -// typedef __n128 v128; // MSVC - -#ifdef MY_CPU_BE - #define MY_rev32_for_LE(x) -#else - #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x))) -#endif - -#define LOAD_128(_p) (*(const v128 *)(const void *)(_p)) -#define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v) - -#define LOAD_SHUFFLE(m, k) \ - m = LOAD_128((data + (k) * 16)); \ - MY_rev32_for_LE(m); \ - -// K array must be aligned for 16-bytes at least. -extern -MY_ALIGN(64) -const UInt32 SHA256_K_ARRAY[64]; - -#define K SHA256_K_ARRAY - - -#define SHA256_SU0(dest, src) dest = vsha256su0q_u32(dest, src); -#define SHA25G_SU1(dest, src2, src3) dest = vsha256su1q_u32(dest, src2, src3); - -#define SM1(g0, g1, g2, g3) SHA256_SU0(g3, g0) -#define SM2(g0, g1, g2, g3) SHA25G_SU1(g2, g0, g1) -#define NNN(g0, g1, g2, g3) - - -#define R4(k, g0, g1, g2, g3, OP0, OP1) \ - msg = vaddq_u32(g0, *(const v128 *) (const void *) &K[(k) * 4]); \ - tmp = state0; \ - state0 = vsha256hq_u32( state0, state1, msg ); \ - state1 = vsha256h2q_u32( state1, tmp, msg ); \ - OP0(g0, g1, g2, g3); \ - OP1(g0, g1, g2, g3); \ - - -#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ - R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \ - R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \ - R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \ - R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \ - - -void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); -#ifdef ATTRIB_SHA -ATTRIB_SHA -#endif -void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) -{ - v128 state0, state1; - - if (numBlocks == 0) - return; - - state0 = LOAD_128(&state[0]); - state1 = LOAD_128(&state[4]); - - do - { - v128 state0_save, state1_save; - v128 m0, m1, m2, m3; - v128 msg, tmp; - - state0_save = state0; - state1_save = state1; - - LOAD_SHUFFLE (m0, 0) - LOAD_SHUFFLE (m1, 1) - LOAD_SHUFFLE (m2, 2) - LOAD_SHUFFLE (m3, 3) - - R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ) - R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) - R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) - R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ) - - state0 = vaddq_u32(state0, state0_save); - state1 = vaddq_u32(state1, state1_save); - - data += 64; - } - while (--numBlocks); - - STORE_128(&state[0], state0); - STORE_128(&state[4], state1); -} - -#endif // USE_HW_SHA - -#endif // MY_CPU_ARM_OR_ARM64 - - -#if !defined(USE_HW_SHA) && defined(Z7_USE_HW_SHA_STUB) -// #error Stop_Compiling_UNSUPPORTED_SHA -// #include -// We can compile this file with another C compiler, -// or we can compile asm version. -// So we can generate real code instead of this stub function. -// #include "Sha256.h" -// #if defined(_MSC_VER) -#pragma message("Sha256 HW-SW stub was used") -// #endif -void Z7_FASTCALL Sha256_UpdateBlocks (UInt32 state[8], const Byte *data, size_t numBlocks); -void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); -void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) -{ - Sha256_UpdateBlocks(state, data, numBlocks); - /* - UNUSED_VAR(state); - UNUSED_VAR(data); - UNUSED_VAR(numBlocks); - exit(1); - return; - */ -} -#endif - - - -#undef K -#undef RND2 -#undef RND2_0 -#undef RND2_1 - -#undef MY_rev32_for_LE -#undef NNN -#undef LOAD_128 -#undef STORE_128 -#undef LOAD_SHUFFLE -#undef SM1 -#undef SM2 - -#undef NNN -#undef R4 -#undef R16 -#undef PREPARE_STATE -#undef USE_HW_SHA -#undef ATTRIB_SHA -#undef USE_VER_MIN -#undef Z7_USE_HW_SHA_STUB +/* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions +: Igor Pavlov : Public domain */ + +#include "Precomp.h" +#include "Compiler.h" +#include "CpuArch.h" + +// #define Z7_USE_HW_SHA_STUB // for debug +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check + #define USE_HW_SHA + #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) + #define USE_HW_SHA + #if !defined(__INTEL_COMPILER) + // icc defines __GNUC__, but icc doesn't support __attribute__(__target__) + #if !defined(__SHA__) || !defined(__SSSE3__) + #define ATTRIB_SHA __attribute__((__target__("sha,ssse3"))) + #endif + #endif + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1900) + #define USE_HW_SHA + #else + #define Z7_USE_HW_SHA_STUB + #endif + #endif +// #endif // MY_CPU_X86_OR_AMD64 +#ifndef USE_HW_SHA + // #define Z7_USE_HW_SHA_STUB // for debug +#endif + +#ifdef USE_HW_SHA + +// #pragma message("Sha256 HW") + + + + +// sse/sse2/ssse3: +#include +// sha*: +#include + +#if defined (__clang__) && defined(_MSC_VER) + #if !defined(__SHA__) + #include + #endif +#else + +#endif + +/* +SHA256 uses: +SSE2: + _mm_loadu_si128 + _mm_storeu_si128 + _mm_set_epi32 + _mm_add_epi32 + _mm_shuffle_epi32 / pshufd + + + +SSSE3: + _mm_shuffle_epi8 / pshufb + _mm_alignr_epi8 +SHA: + _mm_sha256* +*/ + +// K array must be aligned for 16-bytes at least. +// The compiler can look align attribute and selects +// movdqu - for code without align attribute +// movdqa - for code with align attribute +extern +MY_ALIGN(64) +const UInt32 SHA256_K_ARRAY[64]; +#define K SHA256_K_ARRAY + + +#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src); +#define SHA256_MSG1(dest, src) dest = _mm_sha256msg1_epu32(dest, src); +#define SHA256_MSG2(dest, src) dest = _mm_sha256msg2_epu32(dest, src); + +#define LOAD_SHUFFLE(m, k) \ + m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \ + m = _mm_shuffle_epi8(m, mask); \ + +#define NNN(m0, m1, m2, m3) + +#define SM1(m1, m2, m3, m0) \ + SHA256_MSG1(m0, m1); \ + +#define SM2(m2, m3, m0, m1) \ + ADD_EPI32(m0, _mm_alignr_epi8(m3, m2, 4)) \ + SHA256_MSG2(m0, m3); \ + +#define RND2(t0, t1) \ + t0 = _mm_sha256rnds2_epu32(t0, t1, msg); + + + +#define R4(k, m0, m1, m2, m3, OP0, OP1) \ + msg = _mm_add_epi32(m0, *(const __m128i *) (const void *) &K[(k) * 4]); \ + RND2(state0, state1); \ + msg = _mm_shuffle_epi32(msg, 0x0E); \ + OP0(m0, m1, m2, m3) \ + RND2(state1, state0); \ + OP1(m0, m1, m2, m3) \ + +#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ + R4 ( (k)*4+0, m0,m1,m2,m3, OP0, OP1 ) \ + R4 ( (k)*4+1, m1,m2,m3,m0, OP2, OP3 ) \ + R4 ( (k)*4+2, m2,m3,m0,m1, OP4, OP5 ) \ + R4 ( (k)*4+3, m3,m0,m1,m2, OP6, OP7 ) \ + +#define PREPARE_STATE \ + tmp = _mm_shuffle_epi32(state0, 0x1B); /* abcd */ \ + state0 = _mm_shuffle_epi32(state1, 0x1B); /* efgh */ \ + state1 = state0; \ + state0 = _mm_unpacklo_epi64(state0, tmp); /* cdgh */ \ + state1 = _mm_unpackhi_epi64(state1, tmp); /* abef */ \ + + +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA +ATTRIB_SHA +#endif +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + const __m128i mask = _mm_set_epi32(0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203); + + + __m128i tmp, state0, state1; + + if (numBlocks == 0) + return; + + state0 = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); + state1 = _mm_loadu_si128((const __m128i *) (const void *) &state[4]); + + PREPARE_STATE + + do + { + __m128i state0_save, state1_save; + __m128i m0, m1, m2, m3; + __m128i msg; + // #define msg tmp + + state0_save = state0; + state1_save = state1; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + + + R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ) + R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ) + + ADD_EPI32(state0, state0_save) + ADD_EPI32(state1, state1_save) + + data += 64; + } + while (--numBlocks); + + PREPARE_STATE + + _mm_storeu_si128((__m128i *) (void *) &state[0], state0); + _mm_storeu_si128((__m128i *) (void *) &state[4], state1); +} + +#endif // USE_HW_SHA + +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) + + #if defined(__ARM_FEATURE_SHA2) \ + || defined(__ARM_FEATURE_CRYPTO) + #define USE_HW_SHA + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define USE_HW_SHA + #endif + #endif + #endif + #endif + +#ifdef USE_HW_SHA + +// #pragma message("=== Sha256 HW === ") + + +#if defined(__clang__) || defined(__GNUC__) +#if !defined(__ARM_FEATURE_SHA2) && \ + !defined(__ARM_FEATURE_CRYPTO) + #ifdef MY_CPU_ARM64 +#if defined(__clang__) + #define ATTRIB_SHA __attribute__((__target__("crypto"))) +#else + #define ATTRIB_SHA __attribute__((__target__("+crypto"))) +#endif + #else +#if defined(__clang__) && (__clang_major__ >= 1) + #define ATTRIB_SHA __attribute__((__target__("armv8-a,sha2"))) +#else + #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8"))) +#endif + #endif +#endif +#else + // _MSC_VER + // for arm32 + #define _ARM_USE_NEW_NEON_INTRINSICS +#endif + +#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) +#include +#else + +#if defined(__clang__) && __clang_major__ < 16 +#if !defined(__ARM_FEATURE_SHA2) && \ + !defined(__ARM_FEATURE_CRYPTO) +// #pragma message("=== we set __ARM_FEATURE_CRYPTO 1 === ") + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define Z7_ARM_FEATURE_CRYPTO_WAS_SET 1 +// #if defined(__clang__) && __clang_major__ < 13 + #define __ARM_FEATURE_CRYPTO 1 +// #else + #define __ARM_FEATURE_SHA2 1 +// #endif + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif // clang + +#if defined(__clang__) + +#if defined(__ARM_ARCH) && __ARM_ARCH < 8 + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +// #pragma message("#define __ARM_ARCH 8") + #undef __ARM_ARCH + #define __ARM_ARCH 8 + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#endif // clang + +#include + +#if defined(Z7_ARM_FEATURE_CRYPTO_WAS_SET) && \ + defined(__ARM_FEATURE_CRYPTO) && \ + defined(__ARM_FEATURE_SHA2) +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #undef __ARM_FEATURE_CRYPTO + #undef __ARM_FEATURE_SHA2 + #undef Z7_ARM_FEATURE_CRYPTO_WAS_SET +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") +#endif + +#endif // Z7_MSC_VER_ORIGINAL + +typedef uint32x4_t v128; +// typedef __n128 v128; // MSVC + +#ifdef MY_CPU_BE + #define MY_rev32_for_LE(x) x +#else + #define MY_rev32_for_LE(x) vrev32q_u8(x) +#endif + +#if 1 // 0 for debug +// for arm32: it works slower by some reason than direct code +/* +for arm32 it generates: +MSVC-2022, GCC-9: + vld1.32 {d18,d19}, [r10] + vst1.32 {d4,d5}, [r3] + vld1.8 {d20-d21}, [r4] +there is no align hint (like [r10:128]). So instruction allows unaligned access +*/ +#define LOAD_128_32(_p) vld1q_u32(_p) +#define LOAD_128_8(_p) vld1q_u8 (_p) +#define STORE_128_32(_p, _v) vst1q_u32(_p, _v) +#else +/* +for arm32: +MSVC-2022: + vldm r10,{d18,d19} + vstm r3,{d4,d5} + does it require strict alignment? +GCC-9: + vld1.64 {d30-d31}, [r0:64] + vldr d28, [r0, #16] + vldr d29, [r0, #24] + vst1.64 {d30-d31}, [r0:64] + vstr d28, [r0, #16] + vstr d29, [r0, #24] +there is hint [r0:64], so does it requires 64-bit alignment. +*/ +#define LOAD_128_32(_p) (*(const v128 *)(const void *)(_p)) +#define LOAD_128_8(_p) vreinterpretq_u8_u32(*(const v128 *)(const void *)(_p)) +#define STORE_128_32(_p, _v) *(v128 *)(void *)(_p) = (_v) +#endif + +#define LOAD_SHUFFLE(m, k) \ + m = vreinterpretq_u32_u8( \ + MY_rev32_for_LE( \ + LOAD_128_8(data + (k) * 16))); \ + +// K array must be aligned for 16-bytes at least. +extern +MY_ALIGN(64) +const UInt32 SHA256_K_ARRAY[64]; +#define K SHA256_K_ARRAY + +#define SHA256_SU0(dest, src) dest = vsha256su0q_u32(dest, src); +#define SHA256_SU1(dest, src2, src3) dest = vsha256su1q_u32(dest, src2, src3); + +#define SM1(m0, m1, m2, m3) SHA256_SU0(m3, m0) +#define SM2(m0, m1, m2, m3) SHA256_SU1(m2, m0, m1) +#define NNN(m0, m1, m2, m3) + +#define R4(k, m0, m1, m2, m3, OP0, OP1) \ + msg = vaddq_u32(m0, *(const v128 *) (const void *) &K[(k) * 4]); \ + tmp = state0; \ + state0 = vsha256hq_u32( state0, state1, msg ); \ + state1 = vsha256h2q_u32( state1, tmp, msg ); \ + OP0(m0, m1, m2, m3); \ + OP1(m0, m1, m2, m3); \ + + +#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ + R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \ + R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \ + R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \ + R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \ + + +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA +ATTRIB_SHA +#endif +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + v128 state0, state1; + + if (numBlocks == 0) + return; + + state0 = LOAD_128_32(&state[0]); + state1 = LOAD_128_32(&state[4]); + + do + { + v128 state0_save, state1_save; + v128 m0, m1, m2, m3; + v128 msg, tmp; + + state0_save = state0; + state1_save = state1; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ) + R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ) + + state0 = vaddq_u32(state0, state0_save); + state1 = vaddq_u32(state1, state1_save); + + data += 64; + } + while (--numBlocks); + + STORE_128_32(&state[0], state0); + STORE_128_32(&state[4], state1); +} + +#endif // USE_HW_SHA + +#endif // MY_CPU_ARM_OR_ARM64 + + +#if !defined(USE_HW_SHA) && defined(Z7_USE_HW_SHA_STUB) +// #error Stop_Compiling_UNSUPPORTED_SHA +// #include +// We can compile this file with another C compiler, +// or we can compile asm version. +// So we can generate real code instead of this stub function. +// #include "Sha256.h" +// #if defined(_MSC_VER) +#pragma message("Sha256 HW-SW stub was used") +// #endif +void Z7_FASTCALL Sha256_UpdateBlocks (UInt32 state[8], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks) +{ + Sha256_UpdateBlocks(state, data, numBlocks); + /* + UNUSED_VAR(state); + UNUSED_VAR(data); + UNUSED_VAR(numBlocks); + exit(1); + return; + */ +} +#endif + + +#undef K +#undef RND2 +#undef MY_rev32_for_LE + +#undef NNN +#undef LOAD_128 +#undef STORE_128 +#undef LOAD_SHUFFLE +#undef SM1 +#undef SM2 + + +#undef R4 +#undef R16 +#undef PREPARE_STATE +#undef USE_HW_SHA +#undef ATTRIB_SHA +#undef USE_VER_MIN +#undef Z7_USE_HW_SHA_STUB diff --git a/C/Sha3.c b/C/Sha3.c new file mode 100644 index 000000000..be972d614 --- /dev/null +++ b/C/Sha3.c @@ -0,0 +1,359 @@ +/* Sha3.c -- SHA-3 Hash +: Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "Sha3.h" +#include "RotateDefs.h" +#include "CpuArch.h" + +#define U64C(x) UINT64_CONST(x) + +static +MY_ALIGN(64) +const UInt64 SHA3_K_ARRAY[24] = +{ + U64C(0x0000000000000001), U64C(0x0000000000008082), + U64C(0x800000000000808a), U64C(0x8000000080008000), + U64C(0x000000000000808b), U64C(0x0000000080000001), + U64C(0x8000000080008081), U64C(0x8000000000008009), + U64C(0x000000000000008a), U64C(0x0000000000000088), + U64C(0x0000000080008009), U64C(0x000000008000000a), + U64C(0x000000008000808b), U64C(0x800000000000008b), + U64C(0x8000000000008089), U64C(0x8000000000008003), + U64C(0x8000000000008002), U64C(0x8000000000000080), + U64C(0x000000000000800a), U64C(0x800000008000000a), + U64C(0x8000000080008081), U64C(0x8000000000008080), + U64C(0x0000000080000001), U64C(0x8000000080008008) +}; + +void Sha3_Init(CSha3 *p) +{ + p->count = 0; + memset(p->state, 0, sizeof(p->state)); +} + +#define GET_state(i, a) UInt64 a = state[i]; +#define SET_state(i, a) state[i] = a; + +#define LS_5(M, i, a0,a1,a2,a3,a4) \ + M ((i) * 5 , a0) \ + M ((i) * 5 + 1, a1) \ + M ((i) * 5 + 2, a2) \ + M ((i) * 5 + 3, a3) \ + M ((i) * 5 + 4, a4) \ + +#define LS_25(M) \ + LS_5 (M, 0, a50, a51, a52, a53, a54) \ + LS_5 (M, 1, a60, a61, a62, a63, a64) \ + LS_5 (M, 2, a70, a71, a72, a73, a74) \ + LS_5 (M, 3, a80, a81, a82, a83, a84) \ + LS_5 (M, 4, a90, a91, a92, a93, a94) \ + + +#define XOR_1(i, a0) \ + a0 ^= GetUi64(data + (i) * 8); \ + +#define XOR_4(i, a0,a1,a2,a3) \ + XOR_1 ((i) , a0); \ + XOR_1 ((i) + 1, a1); \ + XOR_1 ((i) + 2, a2); \ + XOR_1 ((i) + 3, a3); \ + +#define D(d,b1,b2) \ + d = b1 ^ Z7_ROTL64(b2, 1); + +#define D5 \ + D (d0, c4, c1) \ + D (d1, c0, c2) \ + D (d2, c1, c3) \ + D (d3, c2, c4) \ + D (d4, c3, c0) \ + +#define C0(c,a,d) \ + c = a ^ d; \ + +#define C(c,a,d,k) \ + c = a ^ d; \ + c = Z7_ROTL64(c, k); \ + +#define E4(e1,e2,e3,e4) \ + e1 = c1 ^ (~c2 & c3); \ + e2 = c2 ^ (~c3 & c4); \ + e3 = c3 ^ (~c4 & c0); \ + e4 = c4 ^ (~c0 & c1); \ + +#define CK( v0,w0, \ + v1,w1,k1, \ + v2,w2,k2, \ + v3,w3,k3, \ + v4,w4,k4, e0,e1,e2,e3,e4, keccak_c) \ + C0(c0,v0,w0) \ + C (c1,v1,w1,k1) \ + C (c2,v2,w2,k2) \ + C (c3,v3,w3,k3) \ + C (c4,v4,w4,k4) \ + e0 = c0 ^ (~c1 & c2) ^ keccak_c; \ + E4(e1,e2,e3,e4) \ + +#define CE( v0,w0,k0, \ + v1,w1,k1, \ + v2,w2,k2, \ + v3,w3,k3, \ + v4,w4,k4, e0,e1,e2,e3,e4) \ + C (c0,v0,w0,k0) \ + C (c1,v1,w1,k1) \ + C (c2,v2,w2,k2) \ + C (c3,v3,w3,k3) \ + C (c4,v4,w4,k4) \ + e0 = c0 ^ (~c1 & c2); \ + E4(e1,e2,e3,e4) \ + +// numBlocks != 0 +static +Z7_NO_INLINE +void Z7_FASTCALL Sha3_UpdateBlocks(UInt64 state[SHA3_NUM_STATE_WORDS], + const Byte *data, size_t numBlocks, size_t blockSize) +{ + LS_25 (GET_state) + + do + { + unsigned round; + XOR_4 ( 0, a50, a51, a52, a53) + XOR_4 ( 4, a54, a60, a61, a62) + XOR_1 ( 8, a63) + if (blockSize > 8 * 9) { XOR_4 ( 9, a64, a70, a71, a72) // sha3-384 + if (blockSize > 8 * 13) { XOR_4 (13, a73, a74, a80, a81) // sha3-256 + if (blockSize > 8 * 17) { XOR_1 (17, a82) // sha3-224 + if (blockSize > 8 * 18) { XOR_1 (18, a83) // shake128 + XOR_1 (19, a84) + XOR_1 (20, a90) }}}} + data += blockSize; + + for (round = 0; round < 24; round += 2) + { + UInt64 c0, c1, c2, c3, c4; + UInt64 d0, d1, d2, d3, d4; + UInt64 e50, e51, e52, e53, e54; + UInt64 e60, e61, e62, e63, e64; + UInt64 e70, e71, e72, e73, e74; + UInt64 e80, e81, e82, e83, e84; + UInt64 e90, e91, e92, e93, e94; + + c0 = a50^a60^a70^a80^a90; + c1 = a51^a61^a71^a81^a91; + c2 = a52^a62^a72^a82^a92; + c3 = a53^a63^a73^a83^a93; + c4 = a54^a64^a74^a84^a94; + D5 + CK( a50, d0, + a61, d1, 44, + a72, d2, 43, + a83, d3, 21, + a94, d4, 14, e50, e51, e52, e53, e54, SHA3_K_ARRAY[round]) + CE( a53, d3, 28, + a64, d4, 20, + a70, d0, 3, + a81, d1, 45, + a92, d2, 61, e60, e61, e62, e63, e64) + CE( a51, d1, 1, + a62, d2, 6, + a73, d3, 25, + a84, d4, 8, + a90, d0, 18, e70, e71, e72, e73, e74) + CE( a54, d4, 27, + a60, d0, 36, + a71, d1, 10, + a82, d2, 15, + a93, d3, 56, e80, e81, e82, e83, e84) + CE( a52, d2, 62, + a63, d3, 55, + a74, d4, 39, + a80, d0, 41, + a91, d1, 2, e90, e91, e92, e93, e94) + + // ---------- ROUND + 1 ---------- + + c0 = e50^e60^e70^e80^e90; + c1 = e51^e61^e71^e81^e91; + c2 = e52^e62^e72^e82^e92; + c3 = e53^e63^e73^e83^e93; + c4 = e54^e64^e74^e84^e94; + D5 + CK( e50, d0, + e61, d1, 44, + e72, d2, 43, + e83, d3, 21, + e94, d4, 14, a50, a51, a52, a53, a54, SHA3_K_ARRAY[(size_t)round + 1]) + CE( e53, d3, 28, + e64, d4, 20, + e70, d0, 3, + e81, d1, 45, + e92, d2, 61, a60, a61, a62, a63, a64) + CE( e51, d1, 1, + e62, d2, 6, + e73, d3, 25, + e84, d4, 8, + e90, d0, 18, a70, a71, a72, a73, a74) + CE (e54, d4, 27, + e60, d0, 36, + e71, d1, 10, + e82, d2, 15, + e93, d3, 56, a80, a81, a82, a83, a84) + CE (e52, d2, 62, + e63, d3, 55, + e74, d4, 39, + e80, d0, 41, + e91, d1, 2, a90, a91, a92, a93, a94) + } + } + while (--numBlocks); + + LS_25 (SET_state) +} + + +#define Sha3_UpdateBlock(p) \ + Sha3_UpdateBlocks(p->state, p->buffer, 1, p->blockSize) + +void Sha3_Update(CSha3 *p, const Byte *data, size_t size) +{ +/* + for (;;) + { + if (size == 0) + return; + unsigned cur = p->blockSize - p->count; + if (cur > size) + cur = (unsigned)size; + size -= cur; + unsigned pos = p->count; + p->count = pos + cur; + while (pos & 7) + { + if (cur == 0) + return; + Byte *pb = &(((Byte *)p->state)[pos]); + *pb = (Byte)(*pb ^ *data++); + cur--; + pos++; + } + if (cur >= 8) + { + do + { + *(UInt64 *)(void *)&(((Byte *)p->state)[pos]) ^= GetUi64(data); + data += 8; + pos += 8; + cur -= 8; + } + while (cur >= 8); + } + if (pos != p->blockSize) + { + if (cur) + { + Byte *pb = &(((Byte *)p->state)[pos]); + do + { + *pb = (Byte)(*pb ^ *data++); + pb++; + } + while (--cur); + } + return; + } + Sha3_UpdateBlock(p->state); + p->count = 0; + } +*/ + if (size == 0) + return; + { + const unsigned pos = p->count; + const unsigned num = p->blockSize - pos; + if (num > size) + { + p->count = pos + (unsigned)size; + memcpy(p->buffer + pos, data, size); + return; + } + if (pos != 0) + { + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + Sha3_UpdateBlock(p); + } + } + if (size >= p->blockSize) + { + const size_t numBlocks = size / p->blockSize; + const Byte *dataOld = data; + data += numBlocks * p->blockSize; + size = (size_t)(dataOld + size - data); + Sha3_UpdateBlocks(p->state, dataOld, numBlocks, p->blockSize); + } + p->count = (unsigned)size; + if (size) + memcpy(p->buffer, data, size); +} + + +// we support only (digestSize % 4 == 0) cases +void Sha3_Final(CSha3 *p, Byte *digest, unsigned digestSize, unsigned shake) +{ + memset(p->buffer + p->count, 0, p->blockSize - p->count); + // we write bits markers from low to higher in current byte: + // - if sha-3 : 2 bits : 0,1 + // - if shake : 4 bits : 1111 + // then we write bit 1 to same byte. + // And we write bit 1 to highest bit of last byte of block. + p->buffer[p->count] = (Byte)(shake ? 0x1f : 0x06); + // we need xor operation (^= 0x80) here because we must write 0x80 bit + // to same byte as (0x1f : 0x06), if (p->count == p->blockSize - 1) !!! + p->buffer[p->blockSize - 1] ^= 0x80; +/* + ((Byte *)p->state)[p->count] ^= (Byte)(shake ? 0x1f : 0x06); + ((Byte *)p->state)[p->blockSize - 1] ^= 0x80; +*/ + Sha3_UpdateBlock(p); +#if 1 && defined(MY_CPU_LE) + memcpy(digest, p->state, digestSize); +#else + { + const unsigned numWords = digestSize >> 3; + unsigned i; + for (i = 0; i < numWords; i++) + { + const UInt64 v = p->state[i]; + SetUi64(digest, v) + digest += 8; + } + if (digestSize & 4) // for SHA3-224 + { + const UInt32 v = (UInt32)p->state[numWords]; + SetUi32(digest, v) + } + } +#endif + Sha3_Init(p); +} + +#undef GET_state +#undef SET_state +#undef LS_5 +#undef LS_25 +#undef XOR_1 +#undef XOR_4 +#undef D +#undef D5 +#undef C0 +#undef C +#undef E4 +#undef CK +#undef CE diff --git a/C/Sha3.h b/C/Sha3.h new file mode 100644 index 000000000..c5909c946 --- /dev/null +++ b/C/Sha3.h @@ -0,0 +1,36 @@ +/* Sha3.h -- SHA-3 Hash +: Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_MD5_H +#define ZIP7_INC_MD5_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA3_NUM_STATE_WORDS 25 + +#define SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize) \ + (SHA3_NUM_STATE_WORDS * 8 - (digestSize) * 2) + +typedef struct +{ + UInt32 count; // < blockSize + UInt32 blockSize; // <= SHA3_NUM_STATE_WORDS * 8 + UInt64 _pad1[3]; + // we want 32-bytes alignment here + UInt64 state[SHA3_NUM_STATE_WORDS]; + UInt64 _pad2[3]; + // we want 64-bytes alignment here + Byte buffer[SHA3_NUM_STATE_WORDS * 8]; // last bytes will be unused with predefined blockSize values +} CSha3; + +#define Sha3_SET_blockSize(p, blockSize) { (p)->blockSize = (blockSize); } + +void Sha3_Init(CSha3 *p); +void Sha3_Update(CSha3 *p, const Byte *data, size_t size); +void Sha3_Final(CSha3 *p, Byte *digest, unsigned digestSize, unsigned shake); + +EXTERN_C_END + +#endif diff --git a/C/Sha512.c b/C/Sha512.c new file mode 100644 index 000000000..04827d669 --- /dev/null +++ b/C/Sha512.c @@ -0,0 +1,618 @@ +/* Sha512.c -- SHA-512 Hash +: Igor Pavlov : Public domain +This code is based on public domain code from Wei Dai's Crypto++ library. */ + +#include "Precomp.h" + +#include + +#include "Sha512.h" +#include "RotateDefs.h" +#include "CpuArch.h" + +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 170001) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 170001) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 140000) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 2400) && (__INTEL_COMPILER <= 9900) \ + || defined(_MSC_VER) && (_MSC_VER >= 1940) + #define Z7_COMPILER_SHA512_SUPPORTED + #endif +#elif defined(MY_CPU_ARM64) && defined(MY_CPU_LE) + #if defined(__ARM_FEATURE_SHA512) + #define Z7_COMPILER_SHA512_SUPPORTED + #else + #if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 130000) \ + || defined(__GNUC__) && (__GNUC__ >= 9) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1940) // fix it + #define Z7_COMPILER_SHA512_SUPPORTED + #endif + #endif +#endif + + + + + + + + + + + + + + +void Z7_FASTCALL Sha512_UpdateBlocks(UInt64 state[8], const Byte *data, size_t numBlocks); + +#ifdef Z7_COMPILER_SHA512_SUPPORTED + void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks); + + static SHA512_FUNC_UPDATE_BLOCKS g_SHA512_FUNC_UPDATE_BLOCKS = Sha512_UpdateBlocks; + static SHA512_FUNC_UPDATE_BLOCKS g_SHA512_FUNC_UPDATE_BLOCKS_HW; + + #define SHA512_UPDATE_BLOCKS(p) p->v.vars.func_UpdateBlocks +#else + #define SHA512_UPDATE_BLOCKS(p) Sha512_UpdateBlocks +#endif + + +BoolInt Sha512_SetFunction(CSha512 *p, unsigned algo) +{ + SHA512_FUNC_UPDATE_BLOCKS func = Sha512_UpdateBlocks; + + #ifdef Z7_COMPILER_SHA512_SUPPORTED + if (algo != SHA512_ALGO_SW) + { + if (algo == SHA512_ALGO_DEFAULT) + func = g_SHA512_FUNC_UPDATE_BLOCKS; + else + { + if (algo != SHA512_ALGO_HW) + return False; + func = g_SHA512_FUNC_UPDATE_BLOCKS_HW; + if (!func) + return False; + } + } + #else + if (algo > 1) + return False; + #endif + + p->v.vars.func_UpdateBlocks = func; + return True; +} + + +/* define it for speed optimization */ + +#if 0 // 1 for size optimization + #define STEP_PRE 1 + #define STEP_MAIN 1 +#else + #define STEP_PRE 2 + #define STEP_MAIN 4 + // #define Z7_SHA512_UNROLL +#endif + +#undef Z7_SHA512_BIG_W +#if STEP_MAIN != 16 + #define Z7_SHA512_BIG_W +#endif + + +#define U64C(x) UINT64_CONST(x) + +static MY_ALIGN(64) const UInt64 SHA512_INIT_ARRAYS[4][8] = { +{ U64C(0x8c3d37c819544da2), U64C(0x73e1996689dcd4d6), U64C(0x1dfab7ae32ff9c82), U64C(0x679dd514582f9fcf), + U64C(0x0f6d2b697bd44da8), U64C(0x77e36f7304c48942), U64C(0x3f9d85a86a1d36c8), U64C(0x1112e6ad91d692a1) +}, +{ U64C(0x22312194fc2bf72c), U64C(0x9f555fa3c84c64c2), U64C(0x2393b86b6f53b151), U64C(0x963877195940eabd), + U64C(0x96283ee2a88effe3), U64C(0xbe5e1e2553863992), U64C(0x2b0199fc2c85b8aa), U64C(0x0eb72ddc81c52ca2) +}, +{ U64C(0xcbbb9d5dc1059ed8), U64C(0x629a292a367cd507), U64C(0x9159015a3070dd17), U64C(0x152fecd8f70e5939), + U64C(0x67332667ffc00b31), U64C(0x8eb44a8768581511), U64C(0xdb0c2e0d64f98fa7), U64C(0x47b5481dbefa4fa4) +}, +{ U64C(0x6a09e667f3bcc908), U64C(0xbb67ae8584caa73b), U64C(0x3c6ef372fe94f82b), U64C(0xa54ff53a5f1d36f1), + U64C(0x510e527fade682d1), U64C(0x9b05688c2b3e6c1f), U64C(0x1f83d9abfb41bd6b), U64C(0x5be0cd19137e2179) +}}; + +void Sha512_InitState(CSha512 *p, unsigned digestSize) +{ + p->v.vars.count = 0; + memcpy(p->state, SHA512_INIT_ARRAYS[(size_t)(digestSize >> 4) - 1], sizeof(p->state)); +} + +void Sha512_Init(CSha512 *p, unsigned digestSize) +{ + p->v.vars.func_UpdateBlocks = + #ifdef Z7_COMPILER_SHA512_SUPPORTED + g_SHA512_FUNC_UPDATE_BLOCKS; + #else + NULL; + #endif + Sha512_InitState(p, digestSize); +} + +#define S0(x) (Z7_ROTR64(x,28) ^ Z7_ROTR64(x,34) ^ Z7_ROTR64(x,39)) +#define S1(x) (Z7_ROTR64(x,14) ^ Z7_ROTR64(x,18) ^ Z7_ROTR64(x,41)) +#define s0(x) (Z7_ROTR64(x, 1) ^ Z7_ROTR64(x, 8) ^ (x >> 7)) +#define s1(x) (Z7_ROTR64(x,19) ^ Z7_ROTR64(x,61) ^ (x >> 6)) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + + +#define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe64(data + ((size_t)(j) + i) * 8)) + +#define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15)) + +#ifdef Z7_SHA512_BIG_W + // we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned. + #define w(j, i) W[(size_t)(j) + i] + #define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i)) +#else + #if STEP_MAIN == 16 + #define w(j, i) W[(i) & 15] + #else + #define w(j, i) W[((size_t)(j) + (i)) & 15] + #endif + #define blk2(j, i) (w(j, i) += blk2_main(j, i)) +#endif + +#define W_MAIN(i) blk2(j, i) + + +#define T1(wx, i) \ + tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + h = g; \ + g = f; \ + f = e; \ + e = d + tmp; \ + tmp += S0(a) + Maj(a, b, c); \ + d = c; \ + c = b; \ + b = a; \ + a = tmp; \ + +#define R1_PRE(i) T1( W_PRE, i) +#define R1_MAIN(i) T1( W_MAIN, i) + +#if (!defined(Z7_SHA512_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4) +#define R2_MAIN(i) \ + R1_MAIN(i) \ + R1_MAIN(i + 1) \ + +#endif + + + +#if defined(Z7_SHA512_UNROLL) && STEP_MAIN >= 8 + +#define T4( a,b,c,d,e,f,g,h, wx, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + tmp = h; \ + h += d; \ + d = tmp + S0(a) + Maj(a, b, c); \ + +#define R4( wx, i) \ + T4 ( a,b,c,d,e,f,g,h, wx, (i )); \ + T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \ + T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \ + T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \ + +#define R4_PRE(i) R4( W_PRE, i) +#define R4_MAIN(i) R4( W_MAIN, i) + + +#define T8( a,b,c,d,e,f,g,h, wx, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \ + d += h; \ + h += S0(a) + Maj(a, b, c); \ + +#define R8( wx, i) \ + T8 ( a,b,c,d,e,f,g,h, wx, i ); \ + T8 ( h,a,b,c,d,e,f,g, wx, i+1); \ + T8 ( g,h,a,b,c,d,e,f, wx, i+2); \ + T8 ( f,g,h,a,b,c,d,e, wx, i+3); \ + T8 ( e,f,g,h,a,b,c,d, wx, i+4); \ + T8 ( d,e,f,g,h,a,b,c, wx, i+5); \ + T8 ( c,d,e,f,g,h,a,b, wx, i+6); \ + T8 ( b,c,d,e,f,g,h,a, wx, i+7); \ + +#define R8_PRE(i) R8( W_PRE, i) +#define R8_MAIN(i) R8( W_MAIN, i) + +#endif + + +extern +MY_ALIGN(64) const UInt64 SHA512_K_ARRAY[80]; +MY_ALIGN(64) const UInt64 SHA512_K_ARRAY[80] = { + U64C(0x428a2f98d728ae22), U64C(0x7137449123ef65cd), U64C(0xb5c0fbcfec4d3b2f), U64C(0xe9b5dba58189dbbc), + U64C(0x3956c25bf348b538), U64C(0x59f111f1b605d019), U64C(0x923f82a4af194f9b), U64C(0xab1c5ed5da6d8118), + U64C(0xd807aa98a3030242), U64C(0x12835b0145706fbe), U64C(0x243185be4ee4b28c), U64C(0x550c7dc3d5ffb4e2), + U64C(0x72be5d74f27b896f), U64C(0x80deb1fe3b1696b1), U64C(0x9bdc06a725c71235), U64C(0xc19bf174cf692694), + U64C(0xe49b69c19ef14ad2), U64C(0xefbe4786384f25e3), U64C(0x0fc19dc68b8cd5b5), U64C(0x240ca1cc77ac9c65), + U64C(0x2de92c6f592b0275), U64C(0x4a7484aa6ea6e483), U64C(0x5cb0a9dcbd41fbd4), U64C(0x76f988da831153b5), + U64C(0x983e5152ee66dfab), U64C(0xa831c66d2db43210), U64C(0xb00327c898fb213f), U64C(0xbf597fc7beef0ee4), + U64C(0xc6e00bf33da88fc2), U64C(0xd5a79147930aa725), U64C(0x06ca6351e003826f), U64C(0x142929670a0e6e70), + U64C(0x27b70a8546d22ffc), U64C(0x2e1b21385c26c926), U64C(0x4d2c6dfc5ac42aed), U64C(0x53380d139d95b3df), + U64C(0x650a73548baf63de), U64C(0x766a0abb3c77b2a8), U64C(0x81c2c92e47edaee6), U64C(0x92722c851482353b), + U64C(0xa2bfe8a14cf10364), U64C(0xa81a664bbc423001), U64C(0xc24b8b70d0f89791), U64C(0xc76c51a30654be30), + U64C(0xd192e819d6ef5218), U64C(0xd69906245565a910), U64C(0xf40e35855771202a), U64C(0x106aa07032bbd1b8), + U64C(0x19a4c116b8d2d0c8), U64C(0x1e376c085141ab53), U64C(0x2748774cdf8eeb99), U64C(0x34b0bcb5e19b48a8), + U64C(0x391c0cb3c5c95a63), U64C(0x4ed8aa4ae3418acb), U64C(0x5b9cca4f7763e373), U64C(0x682e6ff3d6b2b8a3), + U64C(0x748f82ee5defb2fc), U64C(0x78a5636f43172f60), U64C(0x84c87814a1f0ab72), U64C(0x8cc702081a6439ec), + U64C(0x90befffa23631e28), U64C(0xa4506cebde82bde9), U64C(0xbef9a3f7b2c67915), U64C(0xc67178f2e372532b), + U64C(0xca273eceea26619c), U64C(0xd186b8c721c0c207), U64C(0xeada7dd6cde0eb1e), U64C(0xf57d4f7fee6ed178), + U64C(0x06f067aa72176fba), U64C(0x0a637dc5a2c898a6), U64C(0x113f9804bef90dae), U64C(0x1b710b35131c471b), + U64C(0x28db77f523047d84), U64C(0x32caab7b40c72493), U64C(0x3c9ebe0a15c9bebc), U64C(0x431d67c49c100d4c), + U64C(0x4cc5d4becb3e42b6), U64C(0x597f299cfc657e2a), U64C(0x5fcb6fab3ad6faec), U64C(0x6c44198c4a475817) +}; + +#define K SHA512_K_ARRAY + +Z7_NO_INLINE +void Z7_FASTCALL Sha512_UpdateBlocks(UInt64 state[8], const Byte *data, size_t numBlocks) +{ + UInt64 W +#ifdef Z7_SHA512_BIG_W + [80]; +#else + [16]; +#endif + unsigned j; + UInt64 a,b,c,d,e,f,g,h; +#if !defined(Z7_SHA512_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4) + UInt64 tmp; +#endif + + if (numBlocks == 0) return; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; + + do + { + + for (j = 0; j < 16; j += STEP_PRE) + { + #if STEP_PRE > 4 + + #if STEP_PRE < 8 + R4_PRE(0); + #else + R8_PRE(0); + #if STEP_PRE == 16 + R8_PRE(8); + #endif + #endif + + #else + + R1_PRE(0) + #if STEP_PRE >= 2 + R1_PRE(1) + #if STEP_PRE >= 4 + R1_PRE(2) + R1_PRE(3) + #endif + #endif + + #endif + } + + for (j = 16; j < 80; j += STEP_MAIN) + { + #if defined(Z7_SHA512_UNROLL) && STEP_MAIN >= 8 + + #if STEP_MAIN < 8 + R4_MAIN(0) + #else + R8_MAIN(0) + #if STEP_MAIN == 16 + R8_MAIN(8) + #endif + #endif + + #else + + R1_MAIN(0) + #if STEP_MAIN >= 2 + R1_MAIN(1) + #if STEP_MAIN >= 4 + R2_MAIN(2) + #if STEP_MAIN >= 8 + R2_MAIN(4) + R2_MAIN(6) + #if STEP_MAIN >= 16 + R2_MAIN(8) + R2_MAIN(10) + R2_MAIN(12) + R2_MAIN(14) + #endif + #endif + #endif + #endif + #endif + } + + a += state[0]; state[0] = a; + b += state[1]; state[1] = b; + c += state[2]; state[2] = c; + d += state[3]; state[3] = d; + e += state[4]; state[4] = e; + f += state[5]; state[5] = f; + g += state[6]; state[6] = g; + h += state[7]; state[7] = h; + + data += SHA512_BLOCK_SIZE; + } + while (--numBlocks); +} + + +#define Sha512_UpdateBlock(p) SHA512_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) + +void Sha512_Update(CSha512 *p, const Byte *data, size_t size) +{ + if (size == 0) + return; + { + const unsigned pos = (unsigned)p->v.vars.count & (SHA512_BLOCK_SIZE - 1); + const unsigned num = SHA512_BLOCK_SIZE - pos; + p->v.vars.count += size; + if (num > size) + { + memcpy(p->buffer + pos, data, size); + return; + } + if (pos != 0) + { + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; + Sha512_UpdateBlock(p); + } + } + { + const size_t numBlocks = size >> 7; + // if (numBlocks) + SHA512_UPDATE_BLOCKS(p)(p->state, data, numBlocks); + size &= SHA512_BLOCK_SIZE - 1; + if (size == 0) + return; + data += (numBlocks << 7); + memcpy(p->buffer, data, size); + } +} + + +void Sha512_Final(CSha512 *p, Byte *digest, unsigned digestSize) +{ + unsigned pos = (unsigned)p->v.vars.count & (SHA512_BLOCK_SIZE - 1); + p->buffer[pos++] = 0x80; + if (pos > (SHA512_BLOCK_SIZE - 8 * 2)) + { + while (pos != SHA512_BLOCK_SIZE) { p->buffer[pos++] = 0; } + // memset(&p->buf.buffer[pos], 0, SHA512_BLOCK_SIZE - pos); + Sha512_UpdateBlock(p); + pos = 0; + } + memset(&p->buffer[pos], 0, (SHA512_BLOCK_SIZE - 8 * 2) - pos); + { + const UInt64 numBits = p->v.vars.count << 3; + SetBe64(p->buffer + SHA512_BLOCK_SIZE - 8 * 2, 0) // = (p->v.vars.count >> (64 - 3)); (high 64-bits) + SetBe64(p->buffer + SHA512_BLOCK_SIZE - 8 * 1, numBits) + } + Sha512_UpdateBlock(p); +#if 1 && defined(MY_CPU_BE) + memcpy(digest, p->state, digestSize); +#else + { + const unsigned numWords = digestSize >> 3; + unsigned i; + for (i = 0; i < numWords; i++) + { + const UInt64 v = p->state[i]; + SetBe64(digest, v) + digest += 8; + } + if (digestSize & 4) // digestSize == SHA512_224_DIGEST_SIZE + { + const UInt32 v = (UInt32)((p->state[numWords]) >> 32); + SetBe32(digest, v) + } + } +#endif + Sha512_InitState(p, digestSize); +} + + + + +#if defined(_WIN32) && defined(Z7_COMPILER_SHA512_SUPPORTED) \ + && defined(MY_CPU_ARM64) // we can disable this check to debug in x64 + +#if 1 // 0 for debug + +#include "7zWindows.h" +// #include +#if 0 && defined(MY_CPU_X86_OR_AMD64) +#include // for debug : for __ud2() +#endif + +BoolInt CPU_IsSupported_SHA512(void) +{ +#if defined(MY_CPU_ARM64) + // we have no SHA512 flag for IsProcessorFeaturePresent() still. + if (!CPU_IsSupported_CRYPTO()) + return False; +#endif + // printf("\nCPU_IsSupported_SHA512\n"); + { + // we can't read ID_AA64ISAR0_EL1 register from application. + // but ID_AA64ISAR0_EL1 register is mapped to "CP 4030" registry value. + HKEY key = NULL; + LONG res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), + 0, KEY_READ, &key); + if (res != ERROR_SUCCESS) + return False; + { + DWORD type = 0; + DWORD count = sizeof(UInt64); + UInt64 val = 0; + res = RegQueryValueEx(key, TEXT("CP 4030"), NULL, + &type, (LPBYTE)&val, &count); + RegCloseKey(key); + if (res != ERROR_SUCCESS + || type != REG_QWORD + || count != sizeof(UInt64) + || ((unsigned)(val >> 12) & 0xf) != 2) + return False; + // we parse SHA2 field of ID_AA64ISAR0_EL1 register: + // 0 : No SHA2 instructions implemented + // 1 : SHA256 implemented + // 2 : SHA256 and SHA512 implemented + } + } + + +#if 1 // 0 for debug to disable SHA512 PROBE code + +/* +----- SHA512 PROBE ----- + +We suppose that "CP 4030" registry reading is enough. +But we use additional SHA512 PROBE code, because +we can catch exception here, and we don't catch exceptions, +if we call Sha512 functions from main code. + +NOTE: arm64 PROBE code doesn't work, if we call it via Wine in linux-arm64. +The program just stops. +Also x64 version of PROBE code doesn't work, if we run it via Intel SDE emulator +without SHA512 support (-skl switch), +The program stops, and we have message from SDE: + TID 0 SDE-ERROR: Executed instruction not valid for specified chip (SKYLAKE): vsha512msg1 +But we still want to catch that exception instead of process stopping. +Does this PROBE code work in native Windows-arm64 (with/without sha512 hw instructions)? +Are there any ways to fix the problems with arm64-wine and x64-SDE cases? +*/ + + // printf("\n========== CPU_IsSupported_SHA512 PROBE ========\n"); + { +#ifdef __clang_major__ + #pragma GCC diagnostic ignored "-Wlanguage-extension-token" +#endif + __try + { +#if 0 // 1 : for debug (reduced version to detect sha512) + const uint64x2_t a = vdupq_n_u64(1); + const uint64x2_t b = vsha512hq_u64(a, a, a); + if ((UInt32)vgetq_lane_u64(b, 0) == 0x11800002) + return True; +#else + MY_ALIGN(16) + UInt64 temp[SHA512_NUM_DIGEST_WORDS + SHA512_NUM_BLOCK_WORDS]; + memset(temp, 0x5a, sizeof(temp)); +#if 0 && defined(MY_CPU_X86_OR_AMD64) + __ud2(); // for debug : that exception is not problem for SDE +#endif +#if 1 + Sha512_UpdateBlocks_HW(temp, + (const Byte *)(const void *)(temp + SHA512_NUM_DIGEST_WORDS), 1); + // printf("\n==== t = %x\n", (UInt32)temp[0]); + if ((UInt32)temp[0] == 0xa33cfdf7) + { + // printf("\n=== PROBE SHA512: SHA512 supported\n"); + return True; + } +#endif +#endif + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // printf("\n==== CPU_IsSupported_SHA512 EXCEPTION_EXECUTE_HANDLER\n"); + } + } + return False; +#else + // without SHA512 PROBE code + return True; +#endif + +} + +#else + +BoolInt CPU_IsSupported_SHA512(void) +{ + return False; +} + +#endif +#endif // WIN32 arm64 + + +void Sha512Prepare(void) +{ +#ifdef Z7_COMPILER_SHA512_SUPPORTED + SHA512_FUNC_UPDATE_BLOCKS f, f_hw; + f = Sha512_UpdateBlocks; + f_hw = NULL; +#ifdef MY_CPU_X86_OR_AMD64 + if (CPU_IsSupported_SHA512() + && CPU_IsSupported_AVX2() + ) +#else + if (CPU_IsSupported_SHA512()) +#endif + { + // printf("\n========== HW SHA512 ======== \n"); + f = f_hw = Sha512_UpdateBlocks_HW; + } + g_SHA512_FUNC_UPDATE_BLOCKS = f; + g_SHA512_FUNC_UPDATE_BLOCKS_HW = f_hw; +#endif +} + + +#undef K +#undef S0 +#undef S1 +#undef s0 +#undef s1 +#undef Ch +#undef Maj +#undef W_MAIN +#undef W_PRE +#undef w +#undef blk2_main +#undef blk2 +#undef T1 +#undef T4 +#undef T8 +#undef R1_PRE +#undef R1_MAIN +#undef R2_MAIN +#undef R4 +#undef R4_PRE +#undef R4_MAIN +#undef R8 +#undef R8_PRE +#undef R8_MAIN +#undef STEP_PRE +#undef STEP_MAIN +#undef Z7_SHA512_BIG_W +#undef Z7_SHA512_UNROLL +#undef Z7_COMPILER_SHA512_SUPPORTED diff --git a/C/Sha512.h b/C/Sha512.h new file mode 100644 index 000000000..1f3a4d1e4 --- /dev/null +++ b/C/Sha512.h @@ -0,0 +1,86 @@ +/* Sha512.h -- SHA-512 Hash +: Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SHA512_H +#define ZIP7_INC_SHA512_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define SHA512_NUM_BLOCK_WORDS 16 +#define SHA512_NUM_DIGEST_WORDS 8 + +#define SHA512_BLOCK_SIZE (SHA512_NUM_BLOCK_WORDS * 8) +#define SHA512_DIGEST_SIZE (SHA512_NUM_DIGEST_WORDS * 8) +#define SHA512_224_DIGEST_SIZE (224 / 8) +#define SHA512_256_DIGEST_SIZE (256 / 8) +#define SHA512_384_DIGEST_SIZE (384 / 8) + +typedef void (Z7_FASTCALL *SHA512_FUNC_UPDATE_BLOCKS)(UInt64 state[8], const Byte *data, size_t numBlocks); + +/* + if (the system supports different SHA512 code implementations) + { + (CSha512::func_UpdateBlocks) will be used + (CSha512::func_UpdateBlocks) can be set by + Sha512_Init() - to default (fastest) + Sha512_SetFunction() - to any algo + } + else + { + (CSha512::func_UpdateBlocks) is ignored. + } +*/ + +typedef struct +{ + union + { + struct + { + SHA512_FUNC_UPDATE_BLOCKS func_UpdateBlocks; + UInt64 count; + } vars; + UInt64 _pad_64bit[8]; + void *_pad_align_ptr[2]; + } v; + UInt64 state[SHA512_NUM_DIGEST_WORDS]; + + Byte buffer[SHA512_BLOCK_SIZE]; +} CSha512; + + +#define SHA512_ALGO_DEFAULT 0 +#define SHA512_ALGO_SW 1 +#define SHA512_ALGO_HW 2 + +/* +Sha512_SetFunction() +return: + 0 - (algo) value is not supported, and func_UpdateBlocks was not changed + 1 - func_UpdateBlocks was set according (algo) value. +*/ + +BoolInt Sha512_SetFunction(CSha512 *p, unsigned algo); +// we support only these (digestSize) values: 224/8, 256/8, 384/8, 512/8 +void Sha512_InitState(CSha512 *p, unsigned digestSize); +void Sha512_Init(CSha512 *p, unsigned digestSize); +void Sha512_Update(CSha512 *p, const Byte *data, size_t size); +void Sha512_Final(CSha512 *p, Byte *digest, unsigned digestSize); + + + + +// void Z7_FASTCALL Sha512_UpdateBlocks(UInt64 state[8], const Byte *data, size_t numBlocks); + +/* +call Sha512Prepare() once at program start. +It prepares all supported implementations, and detects the fastest implementation. +*/ + +void Sha512Prepare(void); + +EXTERN_C_END + +#endif diff --git a/C/Sha512Opt.c b/C/Sha512Opt.c new file mode 100644 index 000000000..3a1386840 --- /dev/null +++ b/C/Sha512Opt.c @@ -0,0 +1,395 @@ +/* Sha512Opt.c -- SHA-512 optimized code for SHA-512 hardware instructions +: Igor Pavlov : Public domain */ + +#include "Precomp.h" +#include "Compiler.h" +#include "CpuArch.h" + +// #define Z7_USE_HW_SHA_STUB // for debug +#ifdef MY_CPU_X86_OR_AMD64 + #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 2400) && (__INTEL_COMPILER <= 9900) // fix it + #define USE_HW_SHA + #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 170001) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 170001) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 140000) + #define USE_HW_SHA + #if !defined(__INTEL_COMPILER) + // icc defines __GNUC__, but icc doesn't support __attribute__(__target__) + #if !defined(__SHA512__) || !defined(__AVX2__) + #define ATTRIB_SHA512 __attribute__((__target__("sha512,avx2"))) + #endif + #endif + #elif defined(Z7_MSC_VER_ORIGINAL) + #if (_MSC_VER >= 1940) + #define USE_HW_SHA + #else + // #define Z7_USE_HW_SHA_STUB + #endif + #endif +// #endif // MY_CPU_X86_OR_AMD64 +#ifndef USE_HW_SHA + // #define Z7_USE_HW_SHA_STUB // for debug +#endif + +#ifdef USE_HW_SHA + +// #pragma message("Sha512 HW") + +#include + +#if defined (__clang__) && defined(_MSC_VER) + #if !defined(__AVX__) + #include + #endif + #if !defined(__AVX2__) + #include + #endif + #if !defined(__SHA512__) + #include + #endif +#else + +#endif + +/* +SHA512 uses: +AVX: + _mm256_loadu_si256 (vmovdqu) + _mm256_storeu_si256 + _mm256_set_epi32 (unused) +AVX2: + _mm256_add_epi64 : vpaddq + _mm256_shuffle_epi8 : vpshufb + _mm256_shuffle_epi32 : pshufd + _mm256_blend_epi32 : vpblendd + _mm256_permute4x64_epi64 : vpermq : 3c + _mm256_permute2x128_si256: vperm2i128 : 3c + _mm256_extracti128_si256 : vextracti128 : 3c +SHA512: + _mm256_sha512* +*/ + +// K array must be aligned for 32-bytes at least. +// The compiler can look align attribute and selects +// vmovdqu - for code without align attribute +// vmovdqa - for code with align attribute +extern +MY_ALIGN(64) +const UInt64 SHA512_K_ARRAY[80]; +#define K SHA512_K_ARRAY + + +#define ADD_EPI64(dest, src) dest = _mm256_add_epi64(dest, src); +#define SHA512_MSG1(dest, src) dest = _mm256_sha512msg1_epi64(dest, _mm256_extracti128_si256(src, 0)); +#define SHA512_MSG2(dest, src) dest = _mm256_sha512msg2_epi64(dest, src); + +#define LOAD_SHUFFLE(m, k) \ + m = _mm256_loadu_si256((const __m256i *)(const void *)(data + (k) * 32)); \ + m = _mm256_shuffle_epi8(m, mask); \ + +#define NNN(m0, m1, m2, m3) + +#define SM1(m1, m2, m3, m0) \ + SHA512_MSG1(m0, m1); \ + +#define SM2(m2, m3, m0, m1) \ + ADD_EPI64(m0, _mm256_permute4x64_epi64(_mm256_blend_epi32(m2, m3, 3), 0x39)); \ + SHA512_MSG2(m0, m3); \ + +#define RND2(t0, t1, lane) \ + t0 = _mm256_sha512rnds2_epi64(t0, t1, _mm256_extracti128_si256(msg, lane)); + + + +#define R4(k, m0, m1, m2, m3, OP0, OP1) \ + msg = _mm256_add_epi64(m0, *(const __m256i *) (const void *) &K[(k) * 4]); \ + RND2(state0, state1, 0); OP0(m0, m1, m2, m3) \ + RND2(state1, state0, 1); OP1(m0, m1, m2, m3) \ + + + + +#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \ + R4 ( (k)*4+0, m0,m1,m2,m3, OP0, OP1 ) \ + R4 ( (k)*4+1, m1,m2,m3,m0, OP2, OP3 ) \ + R4 ( (k)*4+2, m2,m3,m0,m1, OP4, OP5 ) \ + R4 ( (k)*4+3, m3,m0,m1,m2, OP6, OP7 ) \ + +#define PREPARE_STATE \ + state0 = _mm256_shuffle_epi32(state0, 0x4e); /* cdab */ \ + state1 = _mm256_shuffle_epi32(state1, 0x4e); /* ghef */ \ + tmp = state0; \ + state0 = _mm256_permute2x128_si256(state0, state1, 0x13); /* cdgh */ \ + state1 = _mm256_permute2x128_si256(tmp, state1, 2); /* abef */ \ + + +void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA512 +ATTRIB_SHA512 +#endif +void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks) +{ + const __m256i mask = _mm256_set_epi32( + 0x08090a0b,0x0c0d0e0f, 0x00010203,0x04050607, + 0x08090a0b,0x0c0d0e0f, 0x00010203,0x04050607); + __m256i tmp, state0, state1; + + if (numBlocks == 0) + return; + + state0 = _mm256_loadu_si256((const __m256i *) (const void *) &state[0]); + state1 = _mm256_loadu_si256((const __m256i *) (const void *) &state[4]); + + PREPARE_STATE + + do + { + __m256i state0_save, state1_save; + __m256i m0, m1, m2, m3; + __m256i msg; + // #define msg tmp + + state0_save = state0; + state1_save = state1; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + + + + R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 ) + R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 3, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 ) + R16 ( 4, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN ) + ADD_EPI64(state0, state0_save) + ADD_EPI64(state1, state1_save) + + data += 128; + } + while (--numBlocks); + + PREPARE_STATE + + _mm256_storeu_si256((__m256i *) (void *) &state[0], state0); + _mm256_storeu_si256((__m256i *) (void *) &state[4], state1); +} + +#endif // USE_HW_SHA + +// gcc 8.5 also supports sha512, but we need also support in assembler that is called by gcc +#elif defined(MY_CPU_ARM64) && defined(MY_CPU_LE) + + #if defined(__ARM_FEATURE_SHA512) + #define USE_HW_SHA + #else + #if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 130000) \ + || defined(__GNUC__) && (__GNUC__ >= 9) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1940) // fix it + #define USE_HW_SHA + #endif + #endif + +#ifdef USE_HW_SHA + +// #pragma message("=== Sha512 HW === ") + + +#if defined(__clang__) || defined(__GNUC__) +#if !defined(__ARM_FEATURE_SHA512) +// #pragma message("=== we define SHA3 ATTRIB_SHA512 === ") +#if defined(__clang__) + #define ATTRIB_SHA512 __attribute__((__target__("sha3"))) // "armv8.2-a,sha3" +#else + #define ATTRIB_SHA512 __attribute__((__target__("arch=armv8.2-a+sha3"))) +#endif +#endif +#endif + + +#if defined(Z7_MSC_VER_ORIGINAL) +#include +#else + +#if defined(__clang__) && __clang_major__ < 16 +#if !defined(__ARM_FEATURE_SHA512) +// #pragma message("=== we set __ARM_FEATURE_SHA512 1 === ") + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define Z7_ARM_FEATURE_SHA512_WAS_SET 1 + #define __ARM_FEATURE_SHA512 1 + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif // clang + +#include + +#if defined(Z7_ARM_FEATURE_SHA512_WAS_SET) && \ + defined(__ARM_FEATURE_SHA512) + Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #undef __ARM_FEATURE_SHA512 + #undef Z7_ARM_FEATURE_SHA512_WAS_SET + Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +// #pragma message("=== we undefine __ARM_FEATURE_CRYPTO === ") +#endif + +#endif // Z7_MSC_VER_ORIGINAL + +typedef uint64x2_t v128_64; +// typedef __n128 v128_64; // MSVC + +#ifdef MY_CPU_BE + #define MY_rev64_for_LE(x) x +#else + #define MY_rev64_for_LE(x) vrev64q_u8(x) +#endif + +#define LOAD_128_64(_p) vld1q_u64(_p) +#define LOAD_128_8(_p) vld1q_u8 (_p) +#define STORE_128_64(_p, _v) vst1q_u64(_p, _v) + +#define LOAD_SHUFFLE(m, k) \ + m = vreinterpretq_u64_u8( \ + MY_rev64_for_LE( \ + LOAD_128_8(data + (k) * 16))); \ + +// K array must be aligned for 16-bytes at least. +extern +MY_ALIGN(64) +const UInt64 SHA512_K_ARRAY[80]; +#define K SHA512_K_ARRAY + +#define NN(m0, m1, m4, m5, m7) +#define SM(m0, m1, m4, m5, m7) \ + m0 = vsha512su1q_u64(vsha512su0q_u64(m0, m1), m7, vextq_u64(m4, m5, 1)); + +#define R2(k, m0,m1,m2,m3,m4,m5,m6,m7, a0,a1,a2,a3, OP) \ + OP(m0, m1, m4, m5, m7) \ + t = vaddq_u64(m0, vld1q_u64(k)); \ + t = vaddq_u64(vextq_u64(t, t, 1), a3); \ + t = vsha512hq_u64(t, vextq_u64(a2, a3, 1), vextq_u64(a1, a2, 1)); \ + a3 = vsha512h2q_u64(t, a1, a0); \ + a1 = vaddq_u64(a1, t); \ + +#define R8(k, m0,m1,m2,m3,m4,m5,m6,m7, OP) \ + R2 ( (k)+0*2, m0,m1,m2,m3,m4,m5,m6,m7, a0,a1,a2,a3, OP ) \ + R2 ( (k)+1*2, m1,m2,m3,m4,m5,m6,m7,m0, a3,a0,a1,a2, OP ) \ + R2 ( (k)+2*2, m2,m3,m4,m5,m6,m7,m0,m1, a2,a3,a0,a1, OP ) \ + R2 ( (k)+3*2, m3,m4,m5,m6,m7,m0,m1,m2, a1,a2,a3,a0, OP ) \ + +#define R16(k, OP) \ + R8 ( (k)+0*2, m0,m1,m2,m3,m4,m5,m6,m7, OP ) \ + R8 ( (k)+4*2, m4,m5,m6,m7,m0,m1,m2,m3, OP ) \ + + +void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks); +#ifdef ATTRIB_SHA512 +ATTRIB_SHA512 +#endif +void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks) +{ + v128_64 a0, a1, a2, a3; + + if (numBlocks == 0) + return; + a0 = LOAD_128_64(&state[0]); + a1 = LOAD_128_64(&state[2]); + a2 = LOAD_128_64(&state[4]); + a3 = LOAD_128_64(&state[6]); + do + { + v128_64 a0_save, a1_save, a2_save, a3_save; + v128_64 m0, m1, m2, m3, m4, m5, m6, m7; + v128_64 t; + unsigned i; + const UInt64 *k_ptr; + + LOAD_SHUFFLE (m0, 0) + LOAD_SHUFFLE (m1, 1) + LOAD_SHUFFLE (m2, 2) + LOAD_SHUFFLE (m3, 3) + LOAD_SHUFFLE (m4, 4) + LOAD_SHUFFLE (m5, 5) + LOAD_SHUFFLE (m6, 6) + LOAD_SHUFFLE (m7, 7) + + a0_save = a0; + a1_save = a1; + a2_save = a2; + a3_save = a3; + + R16 ( K, NN ) + k_ptr = K + 16; + for (i = 0; i < 4; i++) + { + R16 ( k_ptr, SM ) + k_ptr += 16; + } + + a0 = vaddq_u64(a0, a0_save); + a1 = vaddq_u64(a1, a1_save); + a2 = vaddq_u64(a2, a2_save); + a3 = vaddq_u64(a3, a3_save); + + data += 128; + } + while (--numBlocks); + + STORE_128_64(&state[0], a0); + STORE_128_64(&state[2], a1); + STORE_128_64(&state[4], a2); + STORE_128_64(&state[6], a3); +} + +#endif // USE_HW_SHA + +#endif // MY_CPU_ARM_OR_ARM64 + + +#if !defined(USE_HW_SHA) && defined(Z7_USE_HW_SHA_STUB) +// #error Stop_Compiling_UNSUPPORTED_SHA +// #include +// We can compile this file with another C compiler, +// or we can compile asm version. +// So we can generate real code instead of this stub function. +// #include "Sha512.h" +// #if defined(_MSC_VER) +#pragma message("Sha512 HW-SW stub was used") +// #endif +void Z7_FASTCALL Sha512_UpdateBlocks (UInt64 state[8], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks); +void Z7_FASTCALL Sha512_UpdateBlocks_HW(UInt64 state[8], const Byte *data, size_t numBlocks) +{ + Sha512_UpdateBlocks(state, data, numBlocks); + /* + UNUSED_VAR(state); + UNUSED_VAR(data); + UNUSED_VAR(numBlocks); + exit(1); + return; + */ +} +#endif + + +#undef K +#undef RND2 +#undef MY_rev64_for_LE +#undef NN +#undef NNN +#undef LOAD_128 +#undef STORE_128 +#undef LOAD_SHUFFLE +#undef SM1 +#undef SM2 +#undef SM +#undef R2 +#undef R4 +#undef R16 +#undef PREPARE_STATE +#undef USE_HW_SHA +#undef ATTRIB_SHA512 +#undef USE_VER_MIN +#undef Z7_USE_HW_SHA_STUB diff --git a/C/Sort.c b/C/Sort.c index 73dcbf059..e1097e380 100644 --- a/C/Sort.c +++ b/C/Sort.c @@ -1,141 +1,141 @@ -/* Sort.c -- Sort functions -2014-04-05 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Sort.h" - -#define HeapSortDown(p, k, size, temp) \ - { for (;;) { \ - size_t s = (k << 1); \ - if (s > size) break; \ - if (s < size && p[s + 1] > p[s]) s++; \ - if (temp >= p[s]) break; \ - p[k] = p[s]; k = s; \ - } p[k] = temp; } - -void HeapSort(UInt32 *p, size_t size) -{ - if (size <= 1) - return; - p--; - { - size_t i = size / 2; - do - { - UInt32 temp = p[i]; - size_t k = i; - HeapSortDown(p, k, size, temp) - } - while (--i != 0); - } - /* - do - { - size_t k = 1; - UInt32 temp = p[size]; - p[size--] = p[1]; - HeapSortDown(p, k, size, temp) - } - while (size > 1); - */ - while (size > 3) - { - UInt32 temp = p[size]; - size_t k = (p[3] > p[2]) ? 3 : 2; - p[size--] = p[1]; - p[1] = p[k]; - HeapSortDown(p, k, size, temp) - } - { - UInt32 temp = p[size]; - p[size] = p[1]; - if (size > 2 && p[2] < temp) - { - p[1] = p[2]; - p[2] = temp; - } - else - p[1] = temp; - } -} - -void HeapSort64(UInt64 *p, size_t size) -{ - if (size <= 1) - return; - p--; - { - size_t i = size / 2; - do - { - UInt64 temp = p[i]; - size_t k = i; - HeapSortDown(p, k, size, temp) - } - while (--i != 0); - } - /* - do - { - size_t k = 1; - UInt64 temp = p[size]; - p[size--] = p[1]; - HeapSortDown(p, k, size, temp) - } - while (size > 1); - */ - while (size > 3) - { - UInt64 temp = p[size]; - size_t k = (p[3] > p[2]) ? 3 : 2; - p[size--] = p[1]; - p[1] = p[k]; - HeapSortDown(p, k, size, temp) - } - { - UInt64 temp = p[size]; - p[size] = p[1]; - if (size > 2 && p[2] < temp) - { - p[1] = p[2]; - p[2] = temp; - } - else - p[1] = temp; - } -} - -/* -#define HeapSortRefDown(p, vals, n, size, temp) \ - { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ - size_t s = (k << 1); \ - if (s > size) break; \ - if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ - if (val >= vals[p[s]]) break; \ - p[k] = p[s]; k = s; \ - } p[k] = temp; } - -void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) -{ - if (size <= 1) - return; - p--; - { - size_t i = size / 2; - do - { - UInt32 temp = p[i]; - HeapSortRefDown(p, vals, i, size, temp); - } - while (--i != 0); - } - do - { - UInt32 temp = p[size]; - p[size--] = p[1]; - HeapSortRefDown(p, vals, 1, size, temp); - } - while (size > 1); -} -*/ +/* Sort.c -- Sort functions +2014-04-05 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Sort.h" + +#define HeapSortDown(p, k, size, temp) \ + { for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && p[s + 1] > p[s]) s++; \ + if (temp >= p[s]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSort(UInt32 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt32 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt32 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +void HeapSort64(UInt64 *p, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt64 temp = p[i]; + size_t k = i; + HeapSortDown(p, k, size, temp) + } + while (--i != 0); + } + /* + do + { + size_t k = 1; + UInt64 temp = p[size]; + p[size--] = p[1]; + HeapSortDown(p, k, size, temp) + } + while (size > 1); + */ + while (size > 3) + { + UInt64 temp = p[size]; + size_t k = (p[3] > p[2]) ? 3 : 2; + p[size--] = p[1]; + p[1] = p[k]; + HeapSortDown(p, k, size, temp) + } + { + UInt64 temp = p[size]; + p[size] = p[1]; + if (size > 2 && p[2] < temp) + { + p[1] = p[2]; + p[2] = temp; + } + else + p[1] = temp; + } +} + +/* +#define HeapSortRefDown(p, vals, n, size, temp) \ + { size_t k = n; UInt32 val = vals[temp]; for (;;) { \ + size_t s = (k << 1); \ + if (s > size) break; \ + if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \ + if (val >= vals[p[s]]) break; \ + p[k] = p[s]; k = s; \ + } p[k] = temp; } + +void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size) +{ + if (size <= 1) + return; + p--; + { + size_t i = size / 2; + do + { + UInt32 temp = p[i]; + HeapSortRefDown(p, vals, i, size, temp); + } + while (--i != 0); + } + do + { + UInt32 temp = p[size]; + p[size--] = p[1]; + HeapSortRefDown(p, vals, 1, size, temp); + } + while (size > 1); +} +*/ diff --git a/C/Sort.h b/C/Sort.h index 1bb2b1e7e..1817b652f 100644 --- a/C/Sort.h +++ b/C/Sort.h @@ -1,18 +1,18 @@ -/* Sort.h -- Sort functions -2023-03-05 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_SORT_H -#define ZIP7_INC_SORT_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -void HeapSort(UInt32 *p, size_t size); -void HeapSort64(UInt64 *p, size_t size); - -/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ - -EXTERN_C_END - -#endif +/* Sort.h -- Sort functions +2023-03-05 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SORT_H +#define ZIP7_INC_SORT_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void HeapSort(UInt32 *p, size_t size); +void HeapSort64(UInt64 *p, size_t size); + +/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */ + +EXTERN_C_END + +#endif diff --git a/C/SwapBytes.c b/C/SwapBytes.c index d382c327a..9290592b7 100644 --- a/C/SwapBytes.c +++ b/C/SwapBytes.c @@ -1,835 +1,835 @@ -/* SwapBytes.c -- Byte Swap conversion filter -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "Compiler.h" -#include "CpuArch.h" -#include "RotateDefs.h" -#include "SwapBytes.h" - -typedef UInt16 CSwapUInt16; -typedef UInt32 CSwapUInt32; - -// #define k_SwapBytes_Mode_BASE 0 - -#ifdef MY_CPU_X86_OR_AMD64 - -#define k_SwapBytes_Mode_SSE2 1 -#define k_SwapBytes_Mode_SSSE3 2 -#define k_SwapBytes_Mode_AVX2 3 - - // #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) - #if defined(__clang__) && (__clang_major__ >= 4) \ - || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) - #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2 - #define SWAP_ATTRIB_SSE2 __attribute__((__target__("sse2"))) - #define SWAP_ATTRIB_SSSE3 __attribute__((__target__("ssse3"))) - #define SWAP_ATTRIB_AVX2 __attribute__((__target__("avx2"))) - #elif defined(_MSC_VER) - #if (_MSC_VER == 1900) - #pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX - #endif - #if (_MSC_VER >= 1900) - #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2 - #elif (_MSC_VER >= 1500) // (VS2008) - #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSSE3 - #elif (_MSC_VER >= 1310) // (VS2003) - #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSE2 - #endif - #endif // _MSC_VER - -/* -// for debug -#ifdef k_SwapBytes_Mode_MAX -#undef k_SwapBytes_Mode_MAX -#endif -*/ - -#ifndef k_SwapBytes_Mode_MAX -#define k_SwapBytes_Mode_MAX 0 -#endif - -#if (k_SwapBytes_Mode_MAX != 0) && defined(MY_CPU_AMD64) - #define k_SwapBytes_Mode_MIN k_SwapBytes_Mode_SSE2 -#else - #define k_SwapBytes_Mode_MIN 0 -#endif - -#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_AVX2) - #define USE_SWAP_AVX2 -#endif -#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSSE3) - #define USE_SWAP_SSSE3 -#endif -#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSE2) - #define USE_SWAP_128 -#endif - -#if k_SwapBytes_Mode_MAX <= k_SwapBytes_Mode_MIN || !defined(USE_SWAP_128) -#define FORCE_SWAP_MODE -#endif - - -#ifdef USE_SWAP_128 -/* - MMX - SSE - SSE2 - SSE3 - SSSE3 - SSE4.1 - SSE4.2 - SSE4A - AES - AVX, AVX2, FMA -*/ - -#include // sse2 -// typedef __m128i v128; - -#define SWAP2_128(i) { \ - const __m128i v = *(const __m128i *)(const void *)(items + (i) * 8); \ - *( __m128i *)( void *)(items + (i) * 8) = \ - _mm_or_si128( \ - _mm_slli_epi16(v, 8), \ - _mm_srli_epi16(v, 8)); } -// _mm_or_si128() has more ports to execute than _mm_add_epi16(). - -static -#ifdef SWAP_ATTRIB_SSE2 -SWAP_ATTRIB_SSE2 -#endif -void -Z7_FASTCALL -SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP2_128(0) SWAP2_128(1) items += 2 * 8; - SWAP2_128(0) SWAP2_128(1) items += 2 * 8; - } - while (items != lim); -} - -/* -// sse2 -#define SWAP4_128_pack(i) { \ - __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \ - __m128i v0 = _mm_unpacklo_epi8(v, mask); \ - __m128i v1 = _mm_unpackhi_epi8(v, mask); \ - v0 = _mm_shufflelo_epi16(v0, 0x1b); \ - v1 = _mm_shufflelo_epi16(v1, 0x1b); \ - v0 = _mm_shufflehi_epi16(v0, 0x1b); \ - v1 = _mm_shufflehi_epi16(v1, 0x1b); \ - *(__m128i *)(void *)(items + (i) * 4) = _mm_packus_epi16(v0, v1); } - -static -#ifdef SWAP_ATTRIB_SSE2 -SWAP_ATTRIB_SSE2 -#endif -void -Z7_FASTCALL -SwapBytes4_128_pack(CSwapUInt32 *items, const CSwapUInt32 *lim) -{ - const __m128i mask = _mm_setzero_si128(); - // const __m128i mask = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP4_128_pack(0); items += 1 * 4; - // SWAP4_128_pack(0); SWAP4_128_pack(1); items += 2 * 4; - } - while (items != lim); -} - -// sse2 -#define SWAP4_128_shift(i) { \ - __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \ - __m128i v2; \ - v2 = _mm_or_si128( \ - _mm_slli_si128(_mm_and_si128(v, mask), 1), \ - _mm_and_si128(_mm_srli_si128(v, 1), mask)); \ - v = _mm_or_si128( \ - _mm_slli_epi32(v, 24), \ - _mm_srli_epi32(v, 24)); \ - *(__m128i *)(void *)(items + (i) * 4) = _mm_or_si128(v2, v); } - -static -#ifdef SWAP_ATTRIB_SSE2 -SWAP_ATTRIB_SSE2 -#endif -void -Z7_FASTCALL -SwapBytes4_128_shift(CSwapUInt32 *items, const CSwapUInt32 *lim) -{ - #define M1 0xff00 - const __m128i mask = _mm_set_epi32(M1, M1, M1, M1); - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4; - // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4; - SWAP4_128_shift(0); items += 1 * 4; - } - while (items != lim); -} -*/ - - -#if defined(USE_SWAP_SSSE3) || defined(USE_SWAP_AVX2) - -#define SWAP_SHUF_REV_SEQ_2_VALS(v) (v)+1, (v) -#define SWAP_SHUF_REV_SEQ_4_VALS(v) (v)+3, (v)+2, (v)+1, (v) - -#define SWAP2_SHUF_MASK_16_BYTES \ - SWAP_SHUF_REV_SEQ_2_VALS (0 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (1 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (2 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (3 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (4 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (5 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (6 * 2), \ - SWAP_SHUF_REV_SEQ_2_VALS (7 * 2) - -#define SWAP4_SHUF_MASK_16_BYTES \ - SWAP_SHUF_REV_SEQ_4_VALS (0 * 4), \ - SWAP_SHUF_REV_SEQ_4_VALS (1 * 4), \ - SWAP_SHUF_REV_SEQ_4_VALS (2 * 4), \ - SWAP_SHUF_REV_SEQ_4_VALS (3 * 4) - -#if defined(USE_SWAP_AVX2) -/* if we use 256_BIT_INIT_MASK, each static array mask will be larger for 16 bytes */ -// #define SWAP_USE_256_BIT_INIT_MASK -#endif - -#if defined(SWAP_USE_256_BIT_INIT_MASK) && defined(USE_SWAP_AVX2) -#define SWAP_MASK_INIT_SIZE 32 -#else -#define SWAP_MASK_INIT_SIZE 16 -#endif - -MY_ALIGN(SWAP_MASK_INIT_SIZE) -static const Byte k_ShufMask_Swap2[] = -{ - SWAP2_SHUF_MASK_16_BYTES - #if SWAP_MASK_INIT_SIZE > 16 - , SWAP2_SHUF_MASK_16_BYTES - #endif -}; - -MY_ALIGN(SWAP_MASK_INIT_SIZE) -static const Byte k_ShufMask_Swap4[] = -{ - SWAP4_SHUF_MASK_16_BYTES - #if SWAP_MASK_INIT_SIZE > 16 - , SWAP4_SHUF_MASK_16_BYTES - #endif -}; - - -#ifdef USE_SWAP_SSSE3 - -#include // ssse3 - -#define SHUF_128(i) *(items + (i)) = \ - _mm_shuffle_epi8(*(items + (i)), mask); // SSSE3 - -// Z7_NO_INLINE -static -#ifdef SWAP_ATTRIB_SSSE3 -SWAP_ATTRIB_SSSE3 -#endif -Z7_ATTRIB_NO_VECTORIZE -void -Z7_FASTCALL -ShufBytes_128(void *items8, const void *lim8, const void *mask128_ptr) -{ - __m128i *items = (__m128i *)items8; - const __m128i *lim = (const __m128i *)lim8; - // const __m128i mask = _mm_set_epi8(SHUF_SWAP2_MASK_16_VALS); - // const __m128i mask = _mm_set_epi8(SHUF_SWAP4_MASK_16_VALS); - // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); - // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); - // const __m128i mask = *(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]); - const __m128i mask = *(const __m128i *)mask128_ptr; - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SHUF_128(0) SHUF_128(1) items += 2; - SHUF_128(0) SHUF_128(1) items += 2; - } - while (items != lim); -} - -#endif // USE_SWAP_SSSE3 - - - -#ifdef USE_SWAP_AVX2 - -#include // avx, avx2 -#if defined(__clang__) -#include -#include -#endif - -#define SHUF_256(i) *(items + (i)) = \ - _mm256_shuffle_epi8(*(items + (i)), mask); // AVX2 - -// Z7_NO_INLINE -static -#ifdef SWAP_ATTRIB_AVX2 -SWAP_ATTRIB_AVX2 -#endif -Z7_ATTRIB_NO_VECTORIZE -void -Z7_FASTCALL -ShufBytes_256(void *items8, const void *lim8, const void *mask128_ptr) -{ - __m256i *items = (__m256i *)items8; - const __m256i *lim = (const __m256i *)lim8; - /* - UNUSED_VAR(mask128_ptr) - __m256i mask = - for Swap4: _mm256_setr_epi8(SWAP4_SHUF_MASK_16_BYTES, SWAP4_SHUF_MASK_16_BYTES); - for Swap2: _mm256_setr_epi8(SWAP2_SHUF_MASK_16_BYTES, SWAP2_SHUF_MASK_16_BYTES); - */ - const __m256i mask = - #if SWAP_MASK_INIT_SIZE > 16 - *(const __m256i *)(const void *)mask128_ptr; - #else - /* msvc: broadcastsi128() version reserves the stack for no reason - msvc 19.29-: _mm256_insertf128_si256() / _mm256_set_m128i)) versions use non-avx movdqu xmm0,XMMWORD PTR [r8] - msvc 19.30+ (VS2022): replaces _mm256_set_m128i(m,m) to vbroadcastf128(m) as we want - */ - // _mm256_broadcastsi128_si256(*mask128_ptr); -#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 80000) - #define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1) -#else - #define MY_mm256_set_m128i _mm256_set_m128i -#endif - MY_mm256_set_m128i( - *(const __m128i *)mask128_ptr, - *(const __m128i *)mask128_ptr); - #endif - - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SHUF_256(0) SHUF_256(1) items += 2; - SHUF_256(0) SHUF_256(1) items += 2; - } - while (items != lim); -} - -#endif // USE_SWAP_AVX2 -#endif // USE_SWAP_SSSE3 || USE_SWAP_AVX2 -#endif // USE_SWAP_128 - - - -// compile message "NEON intrinsics not available with the soft-float ABI" -#elif defined(MY_CPU_ARM_OR_ARM64) \ - && defined(MY_CPU_LE) \ - && !defined(Z7_DISABLE_ARM_NEON) - - #if defined(__clang__) && (__clang_major__ >= 8) \ - || defined(__GNUC__) && (__GNUC__ >= 6) - #if defined(__ARM_FP) - #if (defined(__ARM_ARCH) && (__ARM_ARCH >= 4)) \ - || defined(MY_CPU_ARM64) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) - #define USE_SWAP_128 - #ifdef MY_CPU_ARM64 - // #define SWAP_ATTRIB_NEON __attribute__((__target__(""))) - #else -#if defined(Z7_CLANG_VERSION) - // #define SWAP_ATTRIB_NEON __attribute__((__target__("neon"))) -#else - // #pragma message("SWAP_ATTRIB_NEON __attribute__((__target__(fpu=neon))") - #define SWAP_ATTRIB_NEON __attribute__((__target__("fpu=neon"))) -#endif - #endif // MY_CPU_ARM64 - #endif // __ARM_NEON - #endif // __ARM_ARCH - #endif // __ARM_FP - - #elif defined(_MSC_VER) - #if (_MSC_VER >= 1910) - #define USE_SWAP_128 - #endif - #endif - - #ifdef USE_SWAP_128 - #if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) - #include - #else - -/* -#if !defined(__ARM_NEON) -#if defined(Z7_GCC_VERSION) && (__GNUC__ < 5) \ - || defined(Z7_GCC_VERSION) && (__GNUC__ == 5) && (Z7_GCC_VERSION < 90201) \ - || defined(Z7_GCC_VERSION) && (__GNUC__ == 5) && (Z7_GCC_VERSION < 100100) -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -#pragma message("#define __ARM_NEON 1") -// #define __ARM_NEON 1 -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif -#endif -*/ - #include - #endif - #endif - -#ifndef USE_SWAP_128 - #define FORCE_SWAP_MODE -#else - -#ifdef MY_CPU_ARM64 - // for debug : comment it - #define FORCE_SWAP_MODE -#else - #define k_SwapBytes_Mode_NEON 1 -#endif -// typedef uint8x16_t v128; -#define SWAP2_128(i) *(uint8x16_t *) (void *)(items + (i) * 8) = \ - vrev16q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 8)); -#define SWAP4_128(i) *(uint8x16_t *) (void *)(items + (i) * 4) = \ - vrev32q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 4)); - -// Z7_NO_INLINE -static -#ifdef SWAP_ATTRIB_NEON -SWAP_ATTRIB_NEON -#endif -Z7_ATTRIB_NO_VECTORIZE -void -Z7_FASTCALL -SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP2_128(0) SWAP2_128(1) items += 2 * 8; - SWAP2_128(0) SWAP2_128(1) items += 2 * 8; - } - while (items != lim); -} - -// Z7_NO_INLINE -static -#ifdef SWAP_ATTRIB_NEON -SWAP_ATTRIB_NEON -#endif -Z7_ATTRIB_NO_VECTORIZE -void -Z7_FASTCALL -SwapBytes4_128(CSwapUInt32 *items, const CSwapUInt32 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP4_128(0) SWAP4_128(1) items += 2 * 4; - SWAP4_128(0) SWAP4_128(1) items += 2 * 4; - } - while (items != lim); -} - -#endif // USE_SWAP_128 - -#else // MY_CPU_ARM_OR_ARM64 -#define FORCE_SWAP_MODE -#endif // MY_CPU_ARM_OR_ARM64 - - - - - - -#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_X86) - /* _byteswap_ushort() in MSVC x86 32-bit works via slow { mov dh, al; mov dl, ah } - So we use own versions of byteswap function */ - #if (_MSC_VER < 1400 ) // old MSVC-X86 without _rotr16() support - #define SWAP2_16(i) { UInt32 v = items[i]; v += (v << 16); v >>= 8; items[i] = (CSwapUInt16)v; } - #else // is new MSVC-X86 with fast _rotr16() - #include - #define SWAP2_16(i) { items[i] = _rotr16(items[i], 8); } - #endif -#else // is not MSVC-X86 - #define SWAP2_16(i) { CSwapUInt16 v = items[i]; items[i] = Z7_BSWAP16(v); } -#endif // MSVC-X86 - -#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) - #define SWAP4_32(i) { CSwapUInt32 v = items[i]; items[i] = Z7_BSWAP32(v); } -#else - #define SWAP4_32(i) \ - { UInt32 v = items[i]; \ - v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); \ - v = rotlFixed(v, 16); \ - items[i] = v; } -#endif - - - - -#if defined(FORCE_SWAP_MODE) && defined(USE_SWAP_128) - #define DEFAULT_Swap2 SwapBytes2_128 - #if !defined(MY_CPU_X86_OR_AMD64) - #define DEFAULT_Swap4 SwapBytes4_128 - #endif -#endif - -#if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4) - -#define SWAP_BASE_FUNCS_PREFIXES \ -Z7_FORCE_INLINE \ -static \ -Z7_ATTRIB_NO_VECTOR \ -void Z7_FASTCALL - - -#if defined(MY_CPU_ARM_OR_ARM64) -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Wlanguage-extension-token" -#endif -#endif - - -#ifdef MY_CPU_64BIT - -#if defined(MY_CPU_ARM64) \ - && defined(__ARM_ARCH) && (__ARM_ARCH >= 8) \ - && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \ - || (defined(__clang__) && (__clang_major__ >= 4))) - - #define SWAP2_64_VAR(v) asm ("rev16 %x0,%x0" : "+r" (v)); - #define SWAP4_64_VAR(v) asm ("rev32 %x0,%x0" : "+r" (v)); - -#else // is not ARM64-GNU - -#if !defined(MY_CPU_X86_OR_AMD64) || (k_SwapBytes_Mode_MIN == 0) || !defined(USE_SWAP_128) - #define SWAP2_64_VAR(v) \ - v = ( 0x00ff00ff00ff00ff & (v >> 8)) \ - + ((0x00ff00ff00ff00ff & v) << 8); - /* plus gives faster code in MSVC */ -#endif - -#ifdef Z7_CPU_FAST_BSWAP_SUPPORTED - #define SWAP4_64_VAR(v) \ - v = Z7_BSWAP64(v); \ - v = Z7_ROTL64(v, 32); -#else - #define SWAP4_64_VAR(v) \ - v = ( 0x000000ff000000ff & (v >> 24)) \ - + ((0x000000ff000000ff & v) << 24 ) \ - + ( 0x0000ff000000ff00 & (v >> 8)) \ - + ((0x0000ff000000ff00 & v) << 8 ) \ - ; -#endif - -#endif // ARM64-GNU - - -#ifdef SWAP2_64_VAR - -#define SWAP2_64(i) { \ - UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 4); \ - SWAP2_64_VAR(v) \ - *(UInt64 *)(void *)(items + (i) * 4) = v; } - -SWAP_BASE_FUNCS_PREFIXES -SwapBytes2_64(CSwapUInt16 *items, const CSwapUInt16 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP2_64(0) SWAP2_64(1) items += 2 * 4; - SWAP2_64(0) SWAP2_64(1) items += 2 * 4; - } - while (items != lim); -} - - #define DEFAULT_Swap2 SwapBytes2_64 - #if !defined(FORCE_SWAP_MODE) - #define SWAP2_DEFAULT_MODE 0 - #endif -#else // !defined(SWAP2_64_VAR) - #define DEFAULT_Swap2 SwapBytes2_128 - #if !defined(FORCE_SWAP_MODE) - #define SWAP2_DEFAULT_MODE 1 - #endif -#endif // SWAP2_64_VAR - - -#define SWAP4_64(i) { \ - UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 2); \ - SWAP4_64_VAR(v) \ - *(UInt64 *)(void *)(items + (i) * 2) = v; } - -SWAP_BASE_FUNCS_PREFIXES -SwapBytes4_64(CSwapUInt32 *items, const CSwapUInt32 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP4_64(0) SWAP4_64(1) items += 2 * 2; - SWAP4_64(0) SWAP4_64(1) items += 2 * 2; - } - while (items != lim); -} - -#define DEFAULT_Swap4 SwapBytes4_64 - -#else // is not 64BIT - - -#if defined(MY_CPU_ARM_OR_ARM64) \ - && defined(__ARM_ARCH) && (__ARM_ARCH >= 6) \ - && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \ - || (defined(__clang__) && (__clang_major__ >= 4))) - -#ifdef MY_CPU_64BIT - #define SWAP2_32_VAR(v) asm ("rev16 %w0,%w0" : "+r" (v)); -#else - #define SWAP2_32_VAR(v) asm ("rev16 %0,%0" : "+r" (v)); // for clang/gcc - // asm ("rev16 %r0,%r0" : "+r" (a)); // for gcc -#endif - -#elif defined(_MSC_VER) && (_MSC_VER < 1300) && defined(MY_CPU_X86) \ - || !defined(Z7_CPU_FAST_BSWAP_SUPPORTED) \ - || !defined(Z7_CPU_FAST_ROTATE_SUPPORTED) - // old msvc doesn't support _byteswap_ulong() - #define SWAP2_32_VAR(v) \ - v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); - -#else // is not ARM and is not old-MSVC-X86 and fast BSWAP/ROTATE are supported - #define SWAP2_32_VAR(v) \ - v = Z7_BSWAP32(v); \ - v = rotlFixed(v, 16); - -#endif // GNU-ARM* - -#define SWAP2_32(i) { \ - UInt32 v = *(const UInt32 *)(const void *)(items + (i) * 2); \ - SWAP2_32_VAR(v); \ - *(UInt32 *)(void *)(items + (i) * 2) = v; } - - -SWAP_BASE_FUNCS_PREFIXES -SwapBytes2_32(CSwapUInt16 *items, const CSwapUInt16 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP2_32(0) SWAP2_32(1) items += 2 * 2; - SWAP2_32(0) SWAP2_32(1) items += 2 * 2; - } - while (items != lim); -} - - -SWAP_BASE_FUNCS_PREFIXES -SwapBytes4_32(CSwapUInt32 *items, const CSwapUInt32 *lim) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - SWAP4_32(0) SWAP4_32(1) items += 2; - SWAP4_32(0) SWAP4_32(1) items += 2; - } - while (items != lim); -} - -#define DEFAULT_Swap2 SwapBytes2_32 -#define DEFAULT_Swap4 SwapBytes4_32 -#if !defined(FORCE_SWAP_MODE) - #define SWAP2_DEFAULT_MODE 0 -#endif - -#endif // MY_CPU_64BIT -#endif // if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4) - - - -#if !defined(FORCE_SWAP_MODE) -static unsigned g_SwapBytes_Mode; -#endif - -/* size of largest unrolled loop iteration: 128 bytes = 4 * 32 bytes (AVX). */ -#define SWAP_ITERATION_BLOCK_SIZE_MAX (1 << 7) - -// 32 bytes for (AVX) or 2 * 16-bytes for NEON. -#define SWAP_VECTOR_ALIGN_SIZE (1 << 5) - -Z7_NO_INLINE -void z7_SwapBytes2(CSwapUInt16 *items, size_t numItems) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--) - { - SWAP2_16(0) - items++; - } - { - const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt16) - 1; - size_t numItems2 = numItems; - CSwapUInt16 *lim; - numItems &= k_Align_Mask; - numItems2 &= ~(size_t)k_Align_Mask; - lim = items + numItems2; - if (numItems2 != 0) - { - #if !defined(FORCE_SWAP_MODE) - #ifdef MY_CPU_X86_OR_AMD64 - #ifdef USE_SWAP_AVX2 - if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3) - ShufBytes_256((__m256i *)(void *)items, - (const __m256i *)(const void *)lim, - (const __m128i *)(const void *)&(k_ShufMask_Swap2[0])); - else - #endif - #ifdef USE_SWAP_SSSE3 - if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3) - ShufBytes_128((__m128i *)(void *)items, - (const __m128i *)(const void *)lim, - (const __m128i *)(const void *)&(k_ShufMask_Swap2[0])); - else - #endif - #endif // MY_CPU_X86_OR_AMD64 - #if SWAP2_DEFAULT_MODE == 0 - if (g_SwapBytes_Mode != 0) - SwapBytes2_128(items, lim); - else - #endif - #endif // FORCE_SWAP_MODE - DEFAULT_Swap2(items, lim); - } - items = lim; - } - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (; numItems != 0; numItems--) - { - SWAP2_16(0) - items++; - } -} - - -Z7_NO_INLINE -void z7_SwapBytes4(CSwapUInt32 *items, size_t numItems) -{ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--) - { - SWAP4_32(0) - items++; - } - { - const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt32) - 1; - size_t numItems2 = numItems; - CSwapUInt32 *lim; - numItems &= k_Align_Mask; - numItems2 &= ~(size_t)k_Align_Mask; - lim = items + numItems2; - if (numItems2 != 0) - { - #if !defined(FORCE_SWAP_MODE) - #ifdef MY_CPU_X86_OR_AMD64 - #ifdef USE_SWAP_AVX2 - if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3) - ShufBytes_256((__m256i *)(void *)items, - (const __m256i *)(const void *)lim, - (const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); - else - #endif - #ifdef USE_SWAP_SSSE3 - if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3) - ShufBytes_128((__m128i *)(void *)items, - (const __m128i *)(const void *)lim, - (const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); - else - #endif - #else // MY_CPU_X86_OR_AMD64 - - if (g_SwapBytes_Mode != 0) - SwapBytes4_128(items, lim); - else - #endif // MY_CPU_X86_OR_AMD64 - #endif // FORCE_SWAP_MODE - DEFAULT_Swap4(items, lim); - } - items = lim; - } - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - for (; numItems != 0; numItems--) - { - SWAP4_32(0) - items++; - } -} - - -// #define SHOW_HW_STATUS - -#ifdef SHOW_HW_STATUS -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - -void z7_SwapBytesPrepare(void) -{ -#ifndef FORCE_SWAP_MODE - unsigned mode = 0; // k_SwapBytes_Mode_BASE; - -#ifdef MY_CPU_ARM_OR_ARM64 - { - if (CPU_IsSupported_NEON()) - { - // #pragma message ("=== SwapBytes NEON") - PRF(printf("\n=== SwapBytes NEON\n");) - mode = k_SwapBytes_Mode_NEON; - } - } -#else // MY_CPU_ARM_OR_ARM64 - { - #ifdef USE_SWAP_AVX2 - if (CPU_IsSupported_AVX2()) - { - // #pragma message ("=== SwapBytes AVX2") - PRF(printf("\n=== SwapBytes AVX2\n");) - mode = k_SwapBytes_Mode_AVX2; - } - else - #endif - #ifdef USE_SWAP_SSSE3 - if (CPU_IsSupported_SSSE3()) - { - // #pragma message ("=== SwapBytes SSSE3") - PRF(printf("\n=== SwapBytes SSSE3\n");) - mode = k_SwapBytes_Mode_SSSE3; - } - else - #endif - #if !defined(MY_CPU_AMD64) - if (CPU_IsSupported_SSE2()) - #endif - { - // #pragma message ("=== SwapBytes SSE2") - PRF(printf("\n=== SwapBytes SSE2\n");) - mode = k_SwapBytes_Mode_SSE2; - } - } -#endif // MY_CPU_ARM_OR_ARM64 - g_SwapBytes_Mode = mode; - // g_SwapBytes_Mode = 0; // for debug -#endif // FORCE_SWAP_MODE - PRF(printf("\n=== SwapBytesPrepare\n");) -} - -#undef PRF +/* SwapBytes.c -- Byte Swap conversion filter +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "Compiler.h" +#include "CpuArch.h" +#include "RotateDefs.h" +#include "SwapBytes.h" + +typedef UInt16 CSwapUInt16; +typedef UInt32 CSwapUInt32; + +// #define k_SwapBytes_Mode_BASE 0 + +#ifdef MY_CPU_X86_OR_AMD64 + +#define k_SwapBytes_Mode_SSE2 1 +#define k_SwapBytes_Mode_SSSE3 2 +#define k_SwapBytes_Mode_AVX2 3 + + // #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900) + #if defined(__clang__) && (__clang_major__ >= 4) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2 + #define SWAP_ATTRIB_SSE2 __attribute__((__target__("sse2"))) + #define SWAP_ATTRIB_SSSE3 __attribute__((__target__("ssse3"))) + #define SWAP_ATTRIB_AVX2 __attribute__((__target__("avx2"))) + #elif defined(_MSC_VER) + #if (_MSC_VER == 1900) + #pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX + #endif + #if (_MSC_VER >= 1900) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2 + #elif (_MSC_VER >= 1500) // (VS2008) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSSE3 + #elif (_MSC_VER >= 1310) // (VS2003) + #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSE2 + #endif + #endif // _MSC_VER + +/* +// for debug +#ifdef k_SwapBytes_Mode_MAX +#undef k_SwapBytes_Mode_MAX +#endif +*/ + +#ifndef k_SwapBytes_Mode_MAX +#define k_SwapBytes_Mode_MAX 0 +#endif + +#if (k_SwapBytes_Mode_MAX != 0) && defined(MY_CPU_AMD64) + #define k_SwapBytes_Mode_MIN k_SwapBytes_Mode_SSE2 +#else + #define k_SwapBytes_Mode_MIN 0 +#endif + +#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_AVX2) + #define USE_SWAP_AVX2 +#endif +#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSSE3) + #define USE_SWAP_SSSE3 +#endif +#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSE2) + #define USE_SWAP_128 +#endif + +#if k_SwapBytes_Mode_MAX <= k_SwapBytes_Mode_MIN || !defined(USE_SWAP_128) +#define FORCE_SWAP_MODE +#endif + + +#ifdef USE_SWAP_128 +/* + MMX + SSE + SSE2 + SSE3 + SSSE3 + SSE4.1 + SSE4.2 + SSE4A + AES + AVX, AVX2, FMA +*/ + +#include // sse2 +// typedef __m128i v128; + +#define SWAP2_128(i) { \ + const __m128i v = *(const __m128i *)(const void *)(items + (i) * 8); \ + *( __m128i *)( void *)(items + (i) * 8) = \ + _mm_or_si128( \ + _mm_slli_epi16(v, 8), \ + _mm_srli_epi16(v, 8)); } +// _mm_or_si128() has more ports to execute than _mm_add_epi16(). + +static +#ifdef SWAP_ATTRIB_SSE2 +SWAP_ATTRIB_SSE2 +#endif +void +Z7_FASTCALL +SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + } + while (items != lim); +} + +/* +// sse2 +#define SWAP4_128_pack(i) { \ + __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \ + __m128i v0 = _mm_unpacklo_epi8(v, mask); \ + __m128i v1 = _mm_unpackhi_epi8(v, mask); \ + v0 = _mm_shufflelo_epi16(v0, 0x1b); \ + v1 = _mm_shufflelo_epi16(v1, 0x1b); \ + v0 = _mm_shufflehi_epi16(v0, 0x1b); \ + v1 = _mm_shufflehi_epi16(v1, 0x1b); \ + *(__m128i *)(void *)(items + (i) * 4) = _mm_packus_epi16(v0, v1); } + +static +#ifdef SWAP_ATTRIB_SSE2 +SWAP_ATTRIB_SSE2 +#endif +void +Z7_FASTCALL +SwapBytes4_128_pack(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + const __m128i mask = _mm_setzero_si128(); + // const __m128i mask = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_128_pack(0); items += 1 * 4; + // SWAP4_128_pack(0); SWAP4_128_pack(1); items += 2 * 4; + } + while (items != lim); +} + +// sse2 +#define SWAP4_128_shift(i) { \ + __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \ + __m128i v2; \ + v2 = _mm_or_si128( \ + _mm_slli_si128(_mm_and_si128(v, mask), 1), \ + _mm_and_si128(_mm_srli_si128(v, 1), mask)); \ + v = _mm_or_si128( \ + _mm_slli_epi32(v, 24), \ + _mm_srli_epi32(v, 24)); \ + *(__m128i *)(void *)(items + (i) * 4) = _mm_or_si128(v2, v); } + +static +#ifdef SWAP_ATTRIB_SSE2 +SWAP_ATTRIB_SSE2 +#endif +void +Z7_FASTCALL +SwapBytes4_128_shift(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + #define M1 0xff00 + const __m128i mask = _mm_set_epi32(M1, M1, M1, M1); + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4; + // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4; + SWAP4_128_shift(0); items += 1 * 4; + } + while (items != lim); +} +*/ + + +#if defined(USE_SWAP_SSSE3) || defined(USE_SWAP_AVX2) + +#define SWAP_SHUF_REV_SEQ_2_VALS(v) (v)+1, (v) +#define SWAP_SHUF_REV_SEQ_4_VALS(v) (v)+3, (v)+2, (v)+1, (v) + +#define SWAP2_SHUF_MASK_16_BYTES \ + SWAP_SHUF_REV_SEQ_2_VALS (0 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (1 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (2 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (3 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (4 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (5 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (6 * 2), \ + SWAP_SHUF_REV_SEQ_2_VALS (7 * 2) + +#define SWAP4_SHUF_MASK_16_BYTES \ + SWAP_SHUF_REV_SEQ_4_VALS (0 * 4), \ + SWAP_SHUF_REV_SEQ_4_VALS (1 * 4), \ + SWAP_SHUF_REV_SEQ_4_VALS (2 * 4), \ + SWAP_SHUF_REV_SEQ_4_VALS (3 * 4) + +#if defined(USE_SWAP_AVX2) +/* if we use 256_BIT_INIT_MASK, each static array mask will be larger for 16 bytes */ +// #define SWAP_USE_256_BIT_INIT_MASK +#endif + +#if defined(SWAP_USE_256_BIT_INIT_MASK) && defined(USE_SWAP_AVX2) +#define SWAP_MASK_INIT_SIZE 32 +#else +#define SWAP_MASK_INIT_SIZE 16 +#endif + +MY_ALIGN(SWAP_MASK_INIT_SIZE) +static const Byte k_ShufMask_Swap2[] = +{ + SWAP2_SHUF_MASK_16_BYTES + #if SWAP_MASK_INIT_SIZE > 16 + , SWAP2_SHUF_MASK_16_BYTES + #endif +}; + +MY_ALIGN(SWAP_MASK_INIT_SIZE) +static const Byte k_ShufMask_Swap4[] = +{ + SWAP4_SHUF_MASK_16_BYTES + #if SWAP_MASK_INIT_SIZE > 16 + , SWAP4_SHUF_MASK_16_BYTES + #endif +}; + + +#ifdef USE_SWAP_SSSE3 + +#include // ssse3 + +#define SHUF_128(i) *(items + (i)) = \ + _mm_shuffle_epi8(*(items + (i)), mask); // SSSE3 + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_SSSE3 +SWAP_ATTRIB_SSSE3 +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +ShufBytes_128(void *items8, const void *lim8, const void *mask128_ptr) +{ + __m128i *items = (__m128i *)items8; + const __m128i *lim = (const __m128i *)lim8; + // const __m128i mask = _mm_set_epi8(SHUF_SWAP2_MASK_16_VALS); + // const __m128i mask = _mm_set_epi8(SHUF_SWAP4_MASK_16_VALS); + // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + // const __m128i mask = *(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]); + const __m128i mask = *(const __m128i *)mask128_ptr; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SHUF_128(0) SHUF_128(1) items += 2; + SHUF_128(0) SHUF_128(1) items += 2; + } + while (items != lim); +} + +#endif // USE_SWAP_SSSE3 + + + +#ifdef USE_SWAP_AVX2 + +#include // avx, avx2 +#if defined(__clang__) +#include +#include +#endif + +#define SHUF_256(i) *(items + (i)) = \ + _mm256_shuffle_epi8(*(items + (i)), mask); // AVX2 + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_AVX2 +SWAP_ATTRIB_AVX2 +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +ShufBytes_256(void *items8, const void *lim8, const void *mask128_ptr) +{ + __m256i *items = (__m256i *)items8; + const __m256i *lim = (const __m256i *)lim8; + /* + UNUSED_VAR(mask128_ptr) + __m256i mask = + for Swap4: _mm256_setr_epi8(SWAP4_SHUF_MASK_16_BYTES, SWAP4_SHUF_MASK_16_BYTES); + for Swap2: _mm256_setr_epi8(SWAP2_SHUF_MASK_16_BYTES, SWAP2_SHUF_MASK_16_BYTES); + */ + const __m256i mask = + #if SWAP_MASK_INIT_SIZE > 16 + *(const __m256i *)(const void *)mask128_ptr; + #else + /* msvc: broadcastsi128() version reserves the stack for no reason + msvc 19.29-: _mm256_insertf128_si256() / _mm256_set_m128i)) versions use non-avx movdqu xmm0,XMMWORD PTR [r8] + msvc 19.30+ (VS2022): replaces _mm256_set_m128i(m,m) to vbroadcastf128(m) as we want + */ + // _mm256_broadcastsi128_si256(*mask128_ptr); +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 80000) + #define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1) +#else + #define MY_mm256_set_m128i _mm256_set_m128i +#endif + MY_mm256_set_m128i( + *(const __m128i *)mask128_ptr, + *(const __m128i *)mask128_ptr); + #endif + + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SHUF_256(0) SHUF_256(1) items += 2; + SHUF_256(0) SHUF_256(1) items += 2; + } + while (items != lim); +} + +#endif // USE_SWAP_AVX2 +#endif // USE_SWAP_SSSE3 || USE_SWAP_AVX2 +#endif // USE_SWAP_128 + + + +// compile message "NEON intrinsics not available with the soft-float ABI" +#elif defined(MY_CPU_ARM_OR_ARM64) \ + && defined(MY_CPU_LE) \ + && !defined(Z7_DISABLE_ARM_NEON) + + #if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 6) + #if defined(__ARM_FP) + #if (defined(__ARM_ARCH) && (__ARM_ARCH >= 4)) \ + || defined(MY_CPU_ARM64) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) + #define USE_SWAP_128 + #ifdef MY_CPU_ARM64 + // #define SWAP_ATTRIB_NEON __attribute__((__target__(""))) + #else +#if defined(Z7_CLANG_VERSION) + // #define SWAP_ATTRIB_NEON __attribute__((__target__("neon"))) +#else + // #pragma message("SWAP_ATTRIB_NEON __attribute__((__target__(fpu=neon))") + #define SWAP_ATTRIB_NEON __attribute__((__target__("fpu=neon"))) +#endif + #endif // MY_CPU_ARM64 + #endif // __ARM_NEON + #endif // __ARM_ARCH + #endif // __ARM_FP + + #elif defined(_MSC_VER) + #if (_MSC_VER >= 1910) + #define USE_SWAP_128 + #endif + #endif + + #ifdef USE_SWAP_128 + #if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_ARM64) + #include + #else + +/* +#if !defined(__ARM_NEON) +#if defined(Z7_GCC_VERSION) && (__GNUC__ < 5) \ + || defined(Z7_GCC_VERSION) && (__GNUC__ == 5) && (Z7_GCC_VERSION < 90201) \ + || defined(Z7_GCC_VERSION) && (__GNUC__ == 5) && (Z7_GCC_VERSION < 100100) +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#pragma message("#define __ARM_NEON 1") +// #define __ARM_NEON 1 +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif +*/ + #include + #endif + #endif + +#ifndef USE_SWAP_128 + #define FORCE_SWAP_MODE +#else + +#ifdef MY_CPU_ARM64 + // for debug : comment it + #define FORCE_SWAP_MODE +#else + #define k_SwapBytes_Mode_NEON 1 +#endif +// typedef uint8x16_t v128; +#define SWAP2_128(i) *(uint8x16_t *) (void *)(items + (i) * 8) = \ + vrev16q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 8)); +#define SWAP4_128(i) *(uint8x16_t *) (void *)(items + (i) * 4) = \ + vrev32q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 4)); + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_NEON +SWAP_ATTRIB_NEON +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + SWAP2_128(0) SWAP2_128(1) items += 2 * 8; + } + while (items != lim); +} + +// Z7_NO_INLINE +static +#ifdef SWAP_ATTRIB_NEON +SWAP_ATTRIB_NEON +#endif +Z7_ATTRIB_NO_VECTORIZE +void +Z7_FASTCALL +SwapBytes4_128(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_128(0) SWAP4_128(1) items += 2 * 4; + SWAP4_128(0) SWAP4_128(1) items += 2 * 4; + } + while (items != lim); +} + +#endif // USE_SWAP_128 + +#else // MY_CPU_ARM_OR_ARM64 +#define FORCE_SWAP_MODE +#endif // MY_CPU_ARM_OR_ARM64 + + + + + + +#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_X86) + /* _byteswap_ushort() in MSVC x86 32-bit works via slow { mov dh, al; mov dl, ah } + So we use own versions of byteswap function */ + #if (_MSC_VER < 1400 ) // old MSVC-X86 without _rotr16() support + #define SWAP2_16(i) { UInt32 v = items[i]; v += (v << 16); v >>= 8; items[i] = (CSwapUInt16)v; } + #else // is new MSVC-X86 with fast _rotr16() + #include + #define SWAP2_16(i) { items[i] = _rotr16(items[i], 8); } + #endif +#else // is not MSVC-X86 + #define SWAP2_16(i) { CSwapUInt16 v = items[i]; items[i] = Z7_BSWAP16(v); } +#endif // MSVC-X86 + +#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) + #define SWAP4_32(i) { CSwapUInt32 v = items[i]; items[i] = Z7_BSWAP32(v); } +#else + #define SWAP4_32(i) \ + { UInt32 v = items[i]; \ + v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); \ + v = rotlFixed(v, 16); \ + items[i] = v; } +#endif + + + + +#if defined(FORCE_SWAP_MODE) && defined(USE_SWAP_128) + #define DEFAULT_Swap2 SwapBytes2_128 + #if !defined(MY_CPU_X86_OR_AMD64) + #define DEFAULT_Swap4 SwapBytes4_128 + #endif +#endif + +#if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4) + +#define SWAP_BASE_FUNCS_PREFIXES \ +Z7_FORCE_INLINE \ +static \ +Z7_ATTRIB_NO_VECTOR \ +void Z7_FASTCALL + + +#if defined(MY_CPU_ARM_OR_ARM64) +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wlanguage-extension-token" +#endif +#endif + + +#ifdef MY_CPU_64BIT + +#if defined(MY_CPU_ARM64) \ + && defined(__ARM_ARCH) && (__ARM_ARCH >= 8) \ + && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4))) + + #define SWAP2_64_VAR(v) asm ("rev16 %x0,%x0" : "+r" (v)); + #define SWAP4_64_VAR(v) asm ("rev32 %x0,%x0" : "+r" (v)); + +#else // is not ARM64-GNU + +#if !defined(MY_CPU_X86_OR_AMD64) || (k_SwapBytes_Mode_MIN == 0) || !defined(USE_SWAP_128) + #define SWAP2_64_VAR(v) \ + v = ( 0x00ff00ff00ff00ff & (v >> 8)) \ + + ((0x00ff00ff00ff00ff & v) << 8); + /* plus gives faster code in MSVC */ +#endif + +#ifdef Z7_CPU_FAST_BSWAP_SUPPORTED + #define SWAP4_64_VAR(v) \ + v = Z7_BSWAP64(v); \ + v = Z7_ROTL64(v, 32); +#else + #define SWAP4_64_VAR(v) \ + v = ( 0x000000ff000000ff & (v >> 24)) \ + + ((0x000000ff000000ff & v) << 24 ) \ + + ( 0x0000ff000000ff00 & (v >> 8)) \ + + ((0x0000ff000000ff00 & v) << 8 ) \ + ; +#endif + +#endif // ARM64-GNU + + +#ifdef SWAP2_64_VAR + +#define SWAP2_64(i) { \ + UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 4); \ + SWAP2_64_VAR(v) \ + *(UInt64 *)(void *)(items + (i) * 4) = v; } + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes2_64(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_64(0) SWAP2_64(1) items += 2 * 4; + SWAP2_64(0) SWAP2_64(1) items += 2 * 4; + } + while (items != lim); +} + + #define DEFAULT_Swap2 SwapBytes2_64 + #if !defined(FORCE_SWAP_MODE) + #define SWAP2_DEFAULT_MODE 0 + #endif +#else // !defined(SWAP2_64_VAR) + #define DEFAULT_Swap2 SwapBytes2_128 + #if !defined(FORCE_SWAP_MODE) + #define SWAP2_DEFAULT_MODE 1 + #endif +#endif // SWAP2_64_VAR + + +#define SWAP4_64(i) { \ + UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 2); \ + SWAP4_64_VAR(v) \ + *(UInt64 *)(void *)(items + (i) * 2) = v; } + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes4_64(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_64(0) SWAP4_64(1) items += 2 * 2; + SWAP4_64(0) SWAP4_64(1) items += 2 * 2; + } + while (items != lim); +} + +#define DEFAULT_Swap4 SwapBytes4_64 + +#else // is not 64BIT + + +#if defined(MY_CPU_ARM_OR_ARM64) \ + && defined(__ARM_ARCH) && (__ARM_ARCH >= 6) \ + && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4))) + +#ifdef MY_CPU_64BIT + #define SWAP2_32_VAR(v) asm ("rev16 %w0,%w0" : "+r" (v)); +#else + #define SWAP2_32_VAR(v) asm ("rev16 %0,%0" : "+r" (v)); // for clang/gcc + // asm ("rev16 %r0,%r0" : "+r" (a)); // for gcc +#endif + +#elif defined(_MSC_VER) && (_MSC_VER < 1300) && defined(MY_CPU_X86) \ + || !defined(Z7_CPU_FAST_BSWAP_SUPPORTED) \ + || !defined(Z7_CPU_FAST_ROTATE_SUPPORTED) + // old msvc doesn't support _byteswap_ulong() + #define SWAP2_32_VAR(v) \ + v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); + +#else // is not ARM and is not old-MSVC-X86 and fast BSWAP/ROTATE are supported + #define SWAP2_32_VAR(v) \ + v = Z7_BSWAP32(v); \ + v = rotlFixed(v, 16); + +#endif // GNU-ARM* + +#define SWAP2_32(i) { \ + UInt32 v = *(const UInt32 *)(const void *)(items + (i) * 2); \ + SWAP2_32_VAR(v); \ + *(UInt32 *)(void *)(items + (i) * 2) = v; } + + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes2_32(CSwapUInt16 *items, const CSwapUInt16 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP2_32(0) SWAP2_32(1) items += 2 * 2; + SWAP2_32(0) SWAP2_32(1) items += 2 * 2; + } + while (items != lim); +} + + +SWAP_BASE_FUNCS_PREFIXES +SwapBytes4_32(CSwapUInt32 *items, const CSwapUInt32 *lim) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + SWAP4_32(0) SWAP4_32(1) items += 2; + SWAP4_32(0) SWAP4_32(1) items += 2; + } + while (items != lim); +} + +#define DEFAULT_Swap2 SwapBytes2_32 +#define DEFAULT_Swap4 SwapBytes4_32 +#if !defined(FORCE_SWAP_MODE) + #define SWAP2_DEFAULT_MODE 0 +#endif + +#endif // MY_CPU_64BIT +#endif // if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4) + + + +#if !defined(FORCE_SWAP_MODE) +static unsigned g_SwapBytes_Mode; +#endif + +/* size of largest unrolled loop iteration: 128 bytes = 4 * 32 bytes (AVX). */ +#define SWAP_ITERATION_BLOCK_SIZE_MAX (1 << 7) + +// 32 bytes for (AVX) or 2 * 16-bytes for NEON. +#define SWAP_VECTOR_ALIGN_SIZE (1 << 5) + +Z7_NO_INLINE +void z7_SwapBytes2(CSwapUInt16 *items, size_t numItems) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--) + { + SWAP2_16(0) + items++; + } + { + const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt16) - 1; + size_t numItems2 = numItems; + CSwapUInt16 *lim; + numItems &= k_Align_Mask; + numItems2 &= ~(size_t)k_Align_Mask; + lim = items + numItems2; + if (numItems2 != 0) + { + #if !defined(FORCE_SWAP_MODE) + #ifdef MY_CPU_X86_OR_AMD64 + #ifdef USE_SWAP_AVX2 + if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3) + ShufBytes_256((__m256i *)(void *)items, + (const __m256i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap2[0])); + else + #endif + #ifdef USE_SWAP_SSSE3 + if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3) + ShufBytes_128((__m128i *)(void *)items, + (const __m128i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap2[0])); + else + #endif + #endif // MY_CPU_X86_OR_AMD64 + #if SWAP2_DEFAULT_MODE == 0 + if (g_SwapBytes_Mode != 0) + SwapBytes2_128(items, lim); + else + #endif + #endif // FORCE_SWAP_MODE + DEFAULT_Swap2(items, lim); + } + items = lim; + } + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0; numItems--) + { + SWAP2_16(0) + items++; + } +} + + +Z7_NO_INLINE +void z7_SwapBytes4(CSwapUInt32 *items, size_t numItems) +{ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--) + { + SWAP4_32(0) + items++; + } + { + const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt32) - 1; + size_t numItems2 = numItems; + CSwapUInt32 *lim; + numItems &= k_Align_Mask; + numItems2 &= ~(size_t)k_Align_Mask; + lim = items + numItems2; + if (numItems2 != 0) + { + #if !defined(FORCE_SWAP_MODE) + #ifdef MY_CPU_X86_OR_AMD64 + #ifdef USE_SWAP_AVX2 + if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3) + ShufBytes_256((__m256i *)(void *)items, + (const __m256i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + else + #endif + #ifdef USE_SWAP_SSSE3 + if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3) + ShufBytes_128((__m128i *)(void *)items, + (const __m128i *)(const void *)lim, + (const __m128i *)(const void *)&(k_ShufMask_Swap4[0])); + else + #endif + #else // MY_CPU_X86_OR_AMD64 + + if (g_SwapBytes_Mode != 0) + SwapBytes4_128(items, lim); + else + #endif // MY_CPU_X86_OR_AMD64 + #endif // FORCE_SWAP_MODE + DEFAULT_Swap4(items, lim); + } + items = lim; + } + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + for (; numItems != 0; numItems--) + { + SWAP4_32(0) + items++; + } +} + + +// #define SHOW_HW_STATUS + +#ifdef SHOW_HW_STATUS +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +void z7_SwapBytesPrepare(void) +{ +#ifndef FORCE_SWAP_MODE + unsigned mode = 0; // k_SwapBytes_Mode_BASE; + +#ifdef MY_CPU_ARM_OR_ARM64 + { + if (CPU_IsSupported_NEON()) + { + // #pragma message ("=== SwapBytes NEON") + PRF(printf("\n=== SwapBytes NEON\n");) + mode = k_SwapBytes_Mode_NEON; + } + } +#else // MY_CPU_ARM_OR_ARM64 + { + #ifdef USE_SWAP_AVX2 + if (CPU_IsSupported_AVX2()) + { + // #pragma message ("=== SwapBytes AVX2") + PRF(printf("\n=== SwapBytes AVX2\n");) + mode = k_SwapBytes_Mode_AVX2; + } + else + #endif + #ifdef USE_SWAP_SSSE3 + if (CPU_IsSupported_SSSE3()) + { + // #pragma message ("=== SwapBytes SSSE3") + PRF(printf("\n=== SwapBytes SSSE3\n");) + mode = k_SwapBytes_Mode_SSSE3; + } + else + #endif + #if !defined(MY_CPU_AMD64) + if (CPU_IsSupported_SSE2()) + #endif + { + // #pragma message ("=== SwapBytes SSE2") + PRF(printf("\n=== SwapBytes SSE2\n");) + mode = k_SwapBytes_Mode_SSE2; + } + } +#endif // MY_CPU_ARM_OR_ARM64 + g_SwapBytes_Mode = mode; + // g_SwapBytes_Mode = 0; // for debug +#endif // FORCE_SWAP_MODE + PRF(printf("\n=== SwapBytesPrepare\n");) +} + +#undef PRF diff --git a/C/SwapBytes.h b/C/SwapBytes.h index 593a3bd6c..d44246738 100644 --- a/C/SwapBytes.h +++ b/C/SwapBytes.h @@ -1,17 +1,17 @@ -/* SwapBytes.h -- Byte Swap conversion filter -2023-04-02 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_SWAP_BYTES_H -#define ZIP7_INC_SWAP_BYTES_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -void z7_SwapBytes2(UInt16 *data, size_t numItems); -void z7_SwapBytes4(UInt32 *data, size_t numItems); -void z7_SwapBytesPrepare(void); - -EXTERN_C_END - -#endif +/* SwapBytes.h -- Byte Swap conversion filter +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_SWAP_BYTES_H +#define ZIP7_INC_SWAP_BYTES_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +void z7_SwapBytes2(UInt16 *data, size_t numItems); +void z7_SwapBytes4(UInt32 *data, size_t numItems); +void z7_SwapBytesPrepare(void); + +EXTERN_C_END + +#endif diff --git a/C/Threads.c b/C/Threads.c index a04c00588..464efeca4 100644 --- a/C/Threads.c +++ b/C/Threads.c @@ -1,581 +1,581 @@ -/* Threads.c -- multithreading library -2024-03-28 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#ifdef _WIN32 - -#ifndef USE_THREADS_CreateThread -#include -#endif - -#include "Threads.h" - -static WRes GetError(void) -{ - const DWORD res = GetLastError(); - return res ? (WRes)res : 1; -} - -static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); } -static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } - -WRes HandlePtr_Close(HANDLE *p) -{ - if (*p != NULL) - { - if (!CloseHandle(*p)) - return GetError(); - *p = NULL; - } - return 0; -} - -WRes Handle_WaitObject(HANDLE h) -{ - DWORD dw = WaitForSingleObject(h, INFINITE); - /* - (dw) result: - WAIT_OBJECT_0 // 0 - WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space - WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space - WAIT_FAILED // 0xFFFFFFFF - */ - if (dw == WAIT_FAILED) - { - dw = GetLastError(); - if (dw == 0) - return WAIT_FAILED; - } - return (WRes)dw; -} - -#define Thread_Wait(p) Handle_WaitObject(*(p)) - -WRes Thread_Wait_Close(CThread *p) -{ - WRes res = Thread_Wait(p); - WRes res2 = Thread_Close(p); - return (res != 0 ? res : res2); -} - -WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) -{ - /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ - - #ifdef USE_THREADS_CreateThread - - DWORD threadId; - *p = CreateThread(NULL, 0, func, param, 0, &threadId); - - #else - - unsigned threadId; - *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); - - #endif - - /* maybe we must use errno here, but probably GetLastError() is also OK. */ - return HandleToWRes(*p); -} - - -WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) -{ - #ifdef USE_THREADS_CreateThread - - UNUSED_VAR(affinity) - return Thread_Create(p, func, param); - - #else - - /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ - HANDLE h; - WRes wres; - unsigned threadId; - h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId)); - *p = h; - wres = HandleToWRes(h); - if (h) - { - { - // DWORD_PTR prevMask = - SetThreadAffinityMask(h, (DWORD_PTR)affinity); - /* - if (prevMask == 0) - { - // affinity change is non-critical error, so we can ignore it - // wres = GetError(); - } - */ - } - { - DWORD prevSuspendCount = ResumeThread(h); - /* ResumeThread() returns: - 0 : was_not_suspended - 1 : was_resumed - -1 : error - */ - if (prevSuspendCount == (DWORD)-1) - wres = GetError(); - } - } - - /* maybe we must use errno here, but probably GetLastError() is also OK. */ - return wres; - - #endif -} - - -static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) -{ - *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); - return HandleToWRes(*p); -} - -WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } -WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } - -WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } -WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } -WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } -WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } - - -WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) -{ - // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore() - *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); - return HandleToWRes(*p); -} - -WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) -{ - // if (Semaphore_IsCreated(p)) - { - WRes wres = Semaphore_Close(p); - if (wres != 0) - return wres; - } - return Semaphore_Create(p, initCount, maxCount); -} - -static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) - { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } -WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) - { return Semaphore_Release(p, (LONG)num, NULL); } -WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } - -WRes CriticalSection_Init(CCriticalSection *p) -{ - /* InitializeCriticalSection() can raise exception: - Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception - Windows Vista+ : no exceptions */ - #ifdef _MSC_VER - #ifdef __clang__ - #pragma GCC diagnostic ignored "-Wlanguage-extension-token" - #endif - __try - #endif - { - InitializeCriticalSection(p); - /* InitializeCriticalSectionAndSpinCount(p, 0); */ - } - #ifdef _MSC_VER - __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; } - #endif - return 0; -} - - - - -#else // _WIN32 - -// ---------- POSIX ---------- - -#if defined(__linux__) && !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) -#ifndef Z7_AFFINITY_DISABLE -// _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET -// clang < 3.6 : unknown warning group '-Wreserved-id-macro' -// clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier" -// clang >= 13 : do not give warning -#if !defined(_GNU_SOURCE) -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -// #define _GNU_SOURCE -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif // !defined(_GNU_SOURCE) -#endif // Z7_AFFINITY_DISABLE -#endif // __linux__ - -#include "Threads.h" - -#include -#include -#include -#ifdef Z7_AFFINITY_SUPPORTED -// #include -#endif - - -// #include -// #define PRF(p) p -#define PRF(p) -#define Print(s) PRF(printf("\n%s\n", s);) - -WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet) -{ - // new thread in Posix probably inherits affinity from parrent thread - Print("Thread_Create_With_CpuSet") - - pthread_attr_t attr; - int ret; - // int ret2; - - p->_created = 0; - - RINOK(pthread_attr_init(&attr)) - - ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - - if (!ret) - { - if (cpuSet) - { - // pthread_attr_setaffinity_np() is not supported for MUSL compile. - // so we check for __GLIBC__ here -#if defined(Z7_AFFINITY_SUPPORTED) && defined( __GLIBC__) - /* - printf("\n affinity :"); - unsigned i; - for (i = 0; i < sizeof(*cpuSet) && i < 8; i++) - { - Byte b = *((const Byte *)cpuSet + i); - char temp[32]; - #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) - temp[0] = GET_HEX_CHAR((b & 0xF)); - temp[1] = GET_HEX_CHAR((b >> 4)); - // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian - // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian - temp[2] = 0; - printf("%s", temp); - } - printf("\n"); - */ - - // ret2 = - pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet); - // if (ret2) ret = ret2; -#endif - } - - ret = pthread_create(&p->_tid, &attr, func, param); - - if (!ret) - { - p->_created = 1; - /* - if (cpuSet) - { - // ret2 = - pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet); - // if (ret2) ret = ret2; - } - */ - } - } - // ret2 = - pthread_attr_destroy(&attr); - // if (ret2 != 0) ret = ret2; - return ret; -} - - -WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) -{ - return Thread_Create_With_CpuSet(p, func, param, NULL); -} - - -WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) -{ - Print("Thread_Create_WithAffinity") - CCpuSet cs; - unsigned i; - CpuSet_Zero(&cs); - for (i = 0; i < sizeof(affinity) * 8; i++) - { - if (affinity == 0) - break; - if (affinity & 1) - { - CpuSet_Set(&cs, i); - } - affinity >>= 1; - } - return Thread_Create_With_CpuSet(p, func, param, &cs); -} - - -WRes Thread_Close(CThread *p) -{ - // Print("Thread_Close") - int ret; - if (!p->_created) - return 0; - - ret = pthread_detach(p->_tid); - p->_tid = 0; - p->_created = 0; - return ret; -} - - -WRes Thread_Wait_Close(CThread *p) -{ - // Print("Thread_Wait_Close") - void *thread_return; - int ret; - if (!p->_created) - return EINVAL; - - ret = pthread_join(p->_tid, &thread_return); - // probably we can't use that (_tid) after pthread_join(), so we close thread here - p->_created = 0; - p->_tid = 0; - return ret; -} - - - -static WRes Event_Create(CEvent *p, int manualReset, int signaled) -{ - RINOK(pthread_mutex_init(&p->_mutex, NULL)) - RINOK(pthread_cond_init(&p->_cond, NULL)) - p->_manual_reset = manualReset; - p->_state = (signaled ? True : False); - p->_created = 1; - return 0; -} - -WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) - { return Event_Create(p, True, signaled); } -WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) - { return ManualResetEvent_Create(p, 0); } -WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) - { return Event_Create(p, False, signaled); } -WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) - { return AutoResetEvent_Create(p, 0); } - - -#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) -// freebsd: -#pragma GCC diagnostic ignored "-Wthread-safety-analysis" -#endif - -WRes Event_Set(CEvent *p) -{ - RINOK(pthread_mutex_lock(&p->_mutex)) - p->_state = True; - { - const int res1 = pthread_cond_broadcast(&p->_cond); - const int res2 = pthread_mutex_unlock(&p->_mutex); - return (res2 ? res2 : res1); - } -} - -WRes Event_Reset(CEvent *p) -{ - RINOK(pthread_mutex_lock(&p->_mutex)) - p->_state = False; - return pthread_mutex_unlock(&p->_mutex); -} - -WRes Event_Wait(CEvent *p) -{ - RINOK(pthread_mutex_lock(&p->_mutex)) - while (p->_state == False) - { - // ETIMEDOUT - // ret = - pthread_cond_wait(&p->_cond, &p->_mutex); - // if (ret != 0) break; - } - if (p->_manual_reset == False) - { - p->_state = False; - } - return pthread_mutex_unlock(&p->_mutex); -} - -WRes Event_Close(CEvent *p) -{ - if (!p->_created) - return 0; - p->_created = 0; - { - const int res1 = pthread_mutex_destroy(&p->_mutex); - const int res2 = pthread_cond_destroy(&p->_cond); - return (res1 ? res1 : res2); - } -} - - -WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) -{ - if (initCount > maxCount || maxCount < 1) - return EINVAL; - RINOK(pthread_mutex_init(&p->_mutex, NULL)) - RINOK(pthread_cond_init(&p->_cond, NULL)) - p->_count = initCount; - p->_maxCount = maxCount; - p->_created = 1; - return 0; -} - - -WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) -{ - if (Semaphore_IsCreated(p)) - { - /* - WRes wres = Semaphore_Close(p); - if (wres != 0) - return wres; - */ - if (initCount > maxCount || maxCount < 1) - return EINVAL; - // return EINVAL; // for debug - p->_count = initCount; - p->_maxCount = maxCount; - return 0; - } - return Semaphore_Create(p, initCount, maxCount); -} - - -WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) -{ - UInt32 newCount; - int ret; - - if (releaseCount < 1) - return EINVAL; - - RINOK(pthread_mutex_lock(&p->_mutex)) - - newCount = p->_count + releaseCount; - if (newCount > p->_maxCount) - ret = ERROR_TOO_MANY_POSTS; // EINVAL; - else - { - p->_count = newCount; - ret = pthread_cond_broadcast(&p->_cond); - } - RINOK(pthread_mutex_unlock(&p->_mutex)) - return ret; -} - -WRes Semaphore_Wait(CSemaphore *p) -{ - RINOK(pthread_mutex_lock(&p->_mutex)) - while (p->_count < 1) - { - pthread_cond_wait(&p->_cond, &p->_mutex); - } - p->_count--; - return pthread_mutex_unlock(&p->_mutex); -} - -WRes Semaphore_Close(CSemaphore *p) -{ - if (!p->_created) - return 0; - p->_created = 0; - { - const int res1 = pthread_mutex_destroy(&p->_mutex); - const int res2 = pthread_cond_destroy(&p->_cond); - return (res1 ? res1 : res2); - } -} - - - -WRes CriticalSection_Init(CCriticalSection *p) -{ - // Print("CriticalSection_Init") - if (!p) - return EINTR; - return pthread_mutex_init(&p->_mutex, NULL); -} - -void CriticalSection_Enter(CCriticalSection *p) -{ - // Print("CriticalSection_Enter") - if (p) - { - // int ret = - pthread_mutex_lock(&p->_mutex); - } -} - -void CriticalSection_Leave(CCriticalSection *p) -{ - // Print("CriticalSection_Leave") - if (p) - { - // int ret = - pthread_mutex_unlock(&p->_mutex); - } -} - -void CriticalSection_Delete(CCriticalSection *p) -{ - // Print("CriticalSection_Delete") - if (p) - { - // int ret = - pthread_mutex_destroy(&p->_mutex); - } -} - -LONG InterlockedIncrement(LONG volatile *addend) -{ - // Print("InterlockedIncrement") - #ifdef USE_HACK_UNSAFE_ATOMIC - LONG val = *addend + 1; - *addend = val; - return val; - #else - - #if defined(__clang__) && (__clang_major__ >= 8) - #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst" - #endif - return __sync_add_and_fetch(addend, 1); - #endif -} - -LONG InterlockedDecrement(LONG volatile *addend) -{ - // Print("InterlockedDecrement") - #ifdef USE_HACK_UNSAFE_ATOMIC - LONG val = *addend - 1; - *addend = val; - return val; - #else - return __sync_sub_and_fetch(addend, 1); - #endif -} - -#endif // _WIN32 - -WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p) -{ - if (Event_IsCreated(p)) - return Event_Reset(p); - return AutoResetEvent_CreateNotSignaled(p); -} - -#undef PRF -#undef Print +/* Threads.c -- multithreading library +2024-03-28 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifdef _WIN32 + +#ifndef USE_THREADS_CreateThread +#include +#endif + +#include "Threads.h" + +static WRes GetError(void) +{ + const DWORD res = GetLastError(); + return res ? (WRes)res : 1; +} + +static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); } +static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } + +WRes HandlePtr_Close(HANDLE *p) +{ + if (*p != NULL) + { + if (!CloseHandle(*p)) + return GetError(); + *p = NULL; + } + return 0; +} + +WRes Handle_WaitObject(HANDLE h) +{ + DWORD dw = WaitForSingleObject(h, INFINITE); + /* + (dw) result: + WAIT_OBJECT_0 // 0 + WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space + WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space + WAIT_FAILED // 0xFFFFFFFF + */ + if (dw == WAIT_FAILED) + { + dw = GetLastError(); + if (dw == 0) + return WAIT_FAILED; + } + return (WRes)dw; +} + +#define Thread_Wait(p) Handle_WaitObject(*(p)) + +WRes Thread_Wait_Close(CThread *p) +{ + WRes res = Thread_Wait(p); + WRes res2 = Thread_Close(p); + return (res != 0 ? res : res2); +} + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + + #ifdef USE_THREADS_CreateThread + + DWORD threadId; + *p = CreateThread(NULL, 0, func, param, 0, &threadId); + + #else + + unsigned threadId; + *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); + + #endif + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return HandleToWRes(*p); +} + + +WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) +{ + #ifdef USE_THREADS_CreateThread + + UNUSED_VAR(affinity) + return Thread_Create(p, func, param); + + #else + + /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + HANDLE h; + WRes wres; + unsigned threadId; + h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId)); + *p = h; + wres = HandleToWRes(h); + if (h) + { + { + // DWORD_PTR prevMask = + SetThreadAffinityMask(h, (DWORD_PTR)affinity); + /* + if (prevMask == 0) + { + // affinity change is non-critical error, so we can ignore it + // wres = GetError(); + } + */ + } + { + DWORD prevSuspendCount = ResumeThread(h); + /* ResumeThread() returns: + 0 : was_not_suspended + 1 : was_resumed + -1 : error + */ + if (prevSuspendCount == (DWORD)-1) + wres = GetError(); + } + } + + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return wres; + + #endif +} + + +static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) +{ + *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); + return HandleToWRes(*p); +} + +WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } +WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore() + *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); + return HandleToWRes(*p); +} + +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + // if (Semaphore_IsCreated(p)) + { + WRes wres = Semaphore_Close(p); + if (wres != 0) + return wres; + } + return Semaphore_Create(p, initCount, maxCount); +} + +static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) + { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) + { return Semaphore_Release(p, (LONG)num, NULL); } +WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } + +WRes CriticalSection_Init(CCriticalSection *p) +{ + /* InitializeCriticalSection() can raise exception: + Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception + Windows Vista+ : no exceptions */ + #ifdef _MSC_VER + #ifdef __clang__ + #pragma GCC diagnostic ignored "-Wlanguage-extension-token" + #endif + __try + #endif + { + InitializeCriticalSection(p); + /* InitializeCriticalSectionAndSpinCount(p, 0); */ + } + #ifdef _MSC_VER + __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; } + #endif + return 0; +} + + + + +#else // _WIN32 + +// ---------- POSIX ---------- + +#if defined(__linux__) && !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) +#ifndef Z7_AFFINITY_DISABLE +// _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET +// clang < 3.6 : unknown warning group '-Wreserved-id-macro' +// clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier" +// clang >= 13 : do not give warning +#if !defined(_GNU_SOURCE) +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +// #define _GNU_SOURCE +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif // !defined(_GNU_SOURCE) +#endif // Z7_AFFINITY_DISABLE +#endif // __linux__ + +#include "Threads.h" + +#include +#include +#include +#ifdef Z7_AFFINITY_SUPPORTED +// #include +#endif + + +// #include +// #define PRF(p) p +#define PRF(p) +#define Print(s) PRF(printf("\n%s\n", s);) + +WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet) +{ + // new thread in Posix probably inherits affinity from parrent thread + Print("Thread_Create_With_CpuSet") + + pthread_attr_t attr; + int ret; + // int ret2; + + p->_created = 0; + + RINOK(pthread_attr_init(&attr)) + + ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + if (!ret) + { + if (cpuSet) + { + // pthread_attr_setaffinity_np() is not supported for MUSL compile. + // so we check for __GLIBC__ here +#if defined(Z7_AFFINITY_SUPPORTED) && defined( __GLIBC__) + /* + printf("\n affinity :"); + unsigned i; + for (i = 0; i < sizeof(*cpuSet) && i < 8; i++) + { + Byte b = *((const Byte *)cpuSet + i); + char temp[32]; + #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) + temp[0] = GET_HEX_CHAR((b & 0xF)); + temp[1] = GET_HEX_CHAR((b >> 4)); + // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian + // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian + temp[2] = 0; + printf("%s", temp); + } + printf("\n"); + */ + + // ret2 = + pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet); + // if (ret2) ret = ret2; +#endif + } + + ret = pthread_create(&p->_tid, &attr, func, param); + + if (!ret) + { + p->_created = 1; + /* + if (cpuSet) + { + // ret2 = + pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet); + // if (ret2) ret = ret2; + } + */ + } + } + // ret2 = + pthread_attr_destroy(&attr); + // if (ret2 != 0) ret = ret2; + return ret; +} + + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + return Thread_Create_With_CpuSet(p, func, param, NULL); +} + + +WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) +{ + Print("Thread_Create_WithAffinity") + CCpuSet cs; + unsigned i; + CpuSet_Zero(&cs); + for (i = 0; i < sizeof(affinity) * 8; i++) + { + if (affinity == 0) + break; + if (affinity & 1) + { + CpuSet_Set(&cs, i); + } + affinity >>= 1; + } + return Thread_Create_With_CpuSet(p, func, param, &cs); +} + + +WRes Thread_Close(CThread *p) +{ + // Print("Thread_Close") + int ret; + if (!p->_created) + return 0; + + ret = pthread_detach(p->_tid); + p->_tid = 0; + p->_created = 0; + return ret; +} + + +WRes Thread_Wait_Close(CThread *p) +{ + // Print("Thread_Wait_Close") + void *thread_return; + int ret; + if (!p->_created) + return EINVAL; + + ret = pthread_join(p->_tid, &thread_return); + // probably we can't use that (_tid) after pthread_join(), so we close thread here + p->_created = 0; + p->_tid = 0; + return ret; +} + + + +static WRes Event_Create(CEvent *p, int manualReset, int signaled) +{ + RINOK(pthread_mutex_init(&p->_mutex, NULL)) + RINOK(pthread_cond_init(&p->_cond, NULL)) + p->_manual_reset = manualReset; + p->_state = (signaled ? True : False); + p->_created = 1; + return 0; +} + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) + { return Event_Create(p, True, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) + { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) + { return Event_Create(p, False, signaled); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) + { return AutoResetEvent_Create(p, 0); } + + +#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) +// freebsd: +#pragma GCC diagnostic ignored "-Wthread-safety-analysis" +#endif + +WRes Event_Set(CEvent *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + p->_state = True; + { + const int res1 = pthread_cond_broadcast(&p->_cond); + const int res2 = pthread_mutex_unlock(&p->_mutex); + return (res2 ? res2 : res1); + } +} + +WRes Event_Reset(CEvent *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + p->_state = False; + return pthread_mutex_unlock(&p->_mutex); +} + +WRes Event_Wait(CEvent *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + while (p->_state == False) + { + // ETIMEDOUT + // ret = + pthread_cond_wait(&p->_cond, &p->_mutex); + // if (ret != 0) break; + } + if (p->_manual_reset == False) + { + p->_state = False; + } + return pthread_mutex_unlock(&p->_mutex); +} + +WRes Event_Close(CEvent *p) +{ + if (!p->_created) + return 0; + p->_created = 0; + { + const int res1 = pthread_mutex_destroy(&p->_mutex); + const int res2 = pthread_cond_destroy(&p->_cond); + return (res1 ? res1 : res2); + } +} + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + if (initCount > maxCount || maxCount < 1) + return EINVAL; + RINOK(pthread_mutex_init(&p->_mutex, NULL)) + RINOK(pthread_cond_init(&p->_cond, NULL)) + p->_count = initCount; + p->_maxCount = maxCount; + p->_created = 1; + return 0; +} + + +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + if (Semaphore_IsCreated(p)) + { + /* + WRes wres = Semaphore_Close(p); + if (wres != 0) + return wres; + */ + if (initCount > maxCount || maxCount < 1) + return EINVAL; + // return EINVAL; // for debug + p->_count = initCount; + p->_maxCount = maxCount; + return 0; + } + return Semaphore_Create(p, initCount, maxCount); +} + + +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount) +{ + UInt32 newCount; + int ret; + + if (releaseCount < 1) + return EINVAL; + + RINOK(pthread_mutex_lock(&p->_mutex)) + + newCount = p->_count + releaseCount; + if (newCount > p->_maxCount) + ret = ERROR_TOO_MANY_POSTS; // EINVAL; + else + { + p->_count = newCount; + ret = pthread_cond_broadcast(&p->_cond); + } + RINOK(pthread_mutex_unlock(&p->_mutex)) + return ret; +} + +WRes Semaphore_Wait(CSemaphore *p) +{ + RINOK(pthread_mutex_lock(&p->_mutex)) + while (p->_count < 1) + { + pthread_cond_wait(&p->_cond, &p->_mutex); + } + p->_count--; + return pthread_mutex_unlock(&p->_mutex); +} + +WRes Semaphore_Close(CSemaphore *p) +{ + if (!p->_created) + return 0; + p->_created = 0; + { + const int res1 = pthread_mutex_destroy(&p->_mutex); + const int res2 = pthread_cond_destroy(&p->_cond); + return (res1 ? res1 : res2); + } +} + + + +WRes CriticalSection_Init(CCriticalSection *p) +{ + // Print("CriticalSection_Init") + if (!p) + return EINTR; + return pthread_mutex_init(&p->_mutex, NULL); +} + +void CriticalSection_Enter(CCriticalSection *p) +{ + // Print("CriticalSection_Enter") + if (p) + { + // int ret = + pthread_mutex_lock(&p->_mutex); + } +} + +void CriticalSection_Leave(CCriticalSection *p) +{ + // Print("CriticalSection_Leave") + if (p) + { + // int ret = + pthread_mutex_unlock(&p->_mutex); + } +} + +void CriticalSection_Delete(CCriticalSection *p) +{ + // Print("CriticalSection_Delete") + if (p) + { + // int ret = + pthread_mutex_destroy(&p->_mutex); + } +} + +LONG InterlockedIncrement(LONG volatile *addend) +{ + // Print("InterlockedIncrement") + #ifdef USE_HACK_UNSAFE_ATOMIC + LONG val = *addend + 1; + *addend = val; + return val; + #else + + #if defined(__clang__) && (__clang_major__ >= 8) + #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst" + #endif + return __sync_add_and_fetch(addend, 1); + #endif +} + +LONG InterlockedDecrement(LONG volatile *addend) +{ + // Print("InterlockedDecrement") + #ifdef USE_HACK_UNSAFE_ATOMIC + LONG val = *addend - 1; + *addend = val; + return val; + #else + return __sync_sub_and_fetch(addend, 1); + #endif +} + +#endif // _WIN32 + +WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p) +{ + if (Event_IsCreated(p)) + return Event_Reset(p); + return AutoResetEvent_CreateNotSignaled(p); +} + +#undef PRF +#undef Print diff --git a/C/Threads.h b/C/Threads.h index 2428e887c..c1484a277 100644 --- a/C/Threads.h +++ b/C/Threads.h @@ -1,250 +1,250 @@ -/* Threads.h -- multithreading library -2024-03-28 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_THREADS_H -#define ZIP7_INC_THREADS_H - -#ifdef _WIN32 -#include "7zWindows.h" - -#else - -#include "Compiler.h" - -// #define Z7_AFFINITY_DISABLE -#if defined(__linux__) -#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) -#ifndef Z7_AFFINITY_DISABLE -#define Z7_AFFINITY_SUPPORTED -// #pragma message(" ==== Z7_AFFINITY_SUPPORTED") -#if !defined(_GNU_SOURCE) -// #pragma message(" ==== _GNU_SOURCE set") -// we need _GNU_SOURCE for cpu_set_t, if we compile for MUSL -Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER -#define _GNU_SOURCE -Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER -#endif -#endif -#endif -#endif - -#include - -#endif - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#ifdef _WIN32 - -WRes HandlePtr_Close(HANDLE *h); -WRes Handle_WaitObject(HANDLE h); - -typedef HANDLE CThread; - -#define Thread_CONSTRUCT(p) { *(p) = NULL; } -#define Thread_WasCreated(p) (*(p) != NULL) -#define Thread_Close(p) HandlePtr_Close(p) -// #define Thread_Wait(p) Handle_WaitObject(*(p)) - -#ifdef UNDER_CE - // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() - // if (USE_THREADS_CreateThread is not definned), we use CreateThread() - #define USE_THREADS_CreateThread -#endif - -typedef - #ifdef USE_THREADS_CreateThread - DWORD - #else - unsigned - #endif - THREAD_FUNC_RET_TYPE; - -#define THREAD_FUNC_RET_ZERO 0 - -typedef DWORD_PTR CAffinityMask; -typedef DWORD_PTR CCpuSet; - -#define CpuSet_Zero(p) *(p) = (0) -#define CpuSet_Set(p, cpu) *(p) |= ((DWORD_PTR)1 << (cpu)) - -#else // _WIN32 - -typedef struct -{ - pthread_t _tid; - int _created; -} CThread; - -#define Thread_CONSTRUCT(p) { (p)->_tid = 0; (p)->_created = 0; } -#define Thread_WasCreated(p) ((p)->_created != 0) -WRes Thread_Close(CThread *p); -// #define Thread_Wait Thread_Wait_Close - -typedef void * THREAD_FUNC_RET_TYPE; -#define THREAD_FUNC_RET_ZERO NULL - - -typedef UInt64 CAffinityMask; - -#ifdef Z7_AFFINITY_SUPPORTED - -typedef cpu_set_t CCpuSet; -#define CpuSet_Zero(p) CPU_ZERO(p) -#define CpuSet_Set(p, cpu) CPU_SET(cpu, p) -#define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p) - -#else - -typedef UInt64 CCpuSet; -#define CpuSet_Zero(p) *(p) = (0) -#define CpuSet_Set(p, cpu) *(p) |= ((UInt64)1 << (cpu)) -#define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0) - -#endif - - -#endif // _WIN32 - - -#define THREAD_FUNC_CALL_TYPE Z7_STDCALL - -#if defined(_WIN32) && defined(__GNUC__) -/* GCC compiler for x86 32-bit uses the rule: - the stack is 16-byte aligned before CALL instruction for function calling. - But only root function main() contains instructions that - set 16-byte alignment for stack pointer. And another functions - just keep alignment, if it was set in some parent function. - - The problem: - if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), - the root function of thread doesn't set 16-byte alignment. - And stack frames in all child functions also will be unaligned in that case. - - Here we set (force_align_arg_pointer) attribute for root function of new thread. - Do we need (force_align_arg_pointer) also for another systems? */ - - #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) - // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions -#else - #define THREAD_FUNC_ATTRIB_ALIGN_ARG -#endif - -#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE - -typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); -WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); -WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); -WRes Thread_Wait_Close(CThread *p); - -#ifdef _WIN32 -#define Thread_Create_With_CpuSet(p, func, param, cs) \ - Thread_Create_With_Affinity(p, func, param, *cs) -#else -WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); -#endif - - -#ifdef _WIN32 - -typedef HANDLE CEvent; -typedef CEvent CAutoResetEvent; -typedef CEvent CManualResetEvent; -#define Event_Construct(p) *(p) = NULL -#define Event_IsCreated(p) (*(p) != NULL) -#define Event_Close(p) HandlePtr_Close(p) -#define Event_Wait(p) Handle_WaitObject(*(p)) -WRes Event_Set(CEvent *p); -WRes Event_Reset(CEvent *p); -WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); -WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); -WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); -WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); - -typedef HANDLE CSemaphore; -#define Semaphore_Construct(p) *(p) = NULL -#define Semaphore_IsCreated(p) (*(p) != NULL) -#define Semaphore_Close(p) HandlePtr_Close(p) -#define Semaphore_Wait(p) Handle_WaitObject(*(p)) -WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); -WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); -WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); -WRes Semaphore_Release1(CSemaphore *p); - -typedef CRITICAL_SECTION CCriticalSection; -WRes CriticalSection_Init(CCriticalSection *p); -#define CriticalSection_Delete(p) DeleteCriticalSection(p) -#define CriticalSection_Enter(p) EnterCriticalSection(p) -#define CriticalSection_Leave(p) LeaveCriticalSection(p) - - -#else // _WIN32 - -typedef struct -{ - int _created; - int _manual_reset; - int _state; - pthread_mutex_t _mutex; - pthread_cond_t _cond; -} CEvent; - -typedef CEvent CAutoResetEvent; -typedef CEvent CManualResetEvent; - -#define Event_Construct(p) (p)->_created = 0 -#define Event_IsCreated(p) ((p)->_created) - -WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); -WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); -WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); -WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); - -WRes Event_Set(CEvent *p); -WRes Event_Reset(CEvent *p); -WRes Event_Wait(CEvent *p); -WRes Event_Close(CEvent *p); - - -typedef struct -{ - int _created; - UInt32 _count; - UInt32 _maxCount; - pthread_mutex_t _mutex; - pthread_cond_t _cond; -} CSemaphore; - -#define Semaphore_Construct(p) (p)->_created = 0 -#define Semaphore_IsCreated(p) ((p)->_created) - -WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); -WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); -WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); -#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) -WRes Semaphore_Wait(CSemaphore *p); -WRes Semaphore_Close(CSemaphore *p); - - -typedef struct -{ - pthread_mutex_t _mutex; -} CCriticalSection; - -WRes CriticalSection_Init(CCriticalSection *p); -void CriticalSection_Delete(CCriticalSection *cs); -void CriticalSection_Enter(CCriticalSection *cs); -void CriticalSection_Leave(CCriticalSection *cs); - -LONG InterlockedIncrement(LONG volatile *addend); -LONG InterlockedDecrement(LONG volatile *addend); - -#endif // _WIN32 - -WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p); - -EXTERN_C_END - -#endif +/* Threads.h -- multithreading library +2024-03-28 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_THREADS_H +#define ZIP7_INC_THREADS_H + +#ifdef _WIN32 +#include "7zWindows.h" + +#else + +#include "Compiler.h" + +// #define Z7_AFFINITY_DISABLE +#if defined(__linux__) +#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__) +#ifndef Z7_AFFINITY_DISABLE +#define Z7_AFFINITY_SUPPORTED +// #pragma message(" ==== Z7_AFFINITY_SUPPORTED") +#if !defined(_GNU_SOURCE) +// #pragma message(" ==== _GNU_SOURCE set") +// we need _GNU_SOURCE for cpu_set_t, if we compile for MUSL +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#define _GNU_SOURCE +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif +#endif +#endif +#endif + +#include + +#endif + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#ifdef _WIN32 + +WRes HandlePtr_Close(HANDLE *h); +WRes Handle_WaitObject(HANDLE h); + +typedef HANDLE CThread; + +#define Thread_CONSTRUCT(p) { *(p) = NULL; } +#define Thread_WasCreated(p) (*(p) != NULL) +#define Thread_Close(p) HandlePtr_Close(p) +// #define Thread_Wait(p) Handle_WaitObject(*(p)) + +#ifdef UNDER_CE + // if (USE_THREADS_CreateThread is defined), we use _beginthreadex() + // if (USE_THREADS_CreateThread is not definned), we use CreateThread() + #define USE_THREADS_CreateThread +#endif + +typedef + #ifdef USE_THREADS_CreateThread + DWORD + #else + unsigned + #endif + THREAD_FUNC_RET_TYPE; + +#define THREAD_FUNC_RET_ZERO 0 + +typedef DWORD_PTR CAffinityMask; +typedef DWORD_PTR CCpuSet; + +#define CpuSet_Zero(p) *(p) = (0) +#define CpuSet_Set(p, cpu) *(p) |= ((DWORD_PTR)1 << (cpu)) + +#else // _WIN32 + +typedef struct +{ + pthread_t _tid; + int _created; +} CThread; + +#define Thread_CONSTRUCT(p) { (p)->_tid = 0; (p)->_created = 0; } +#define Thread_WasCreated(p) ((p)->_created != 0) +WRes Thread_Close(CThread *p); +// #define Thread_Wait Thread_Wait_Close + +typedef void * THREAD_FUNC_RET_TYPE; +#define THREAD_FUNC_RET_ZERO NULL + + +typedef UInt64 CAffinityMask; + +#ifdef Z7_AFFINITY_SUPPORTED + +typedef cpu_set_t CCpuSet; +#define CpuSet_Zero(p) CPU_ZERO(p) +#define CpuSet_Set(p, cpu) CPU_SET(cpu, p) +#define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p) + +#else + +typedef UInt64 CCpuSet; +#define CpuSet_Zero(p) *(p) = (0) +#define CpuSet_Set(p, cpu) *(p) |= ((UInt64)1 << (cpu)) +#define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0) + +#endif + + +#endif // _WIN32 + + +#define THREAD_FUNC_CALL_TYPE Z7_STDCALL + +#if defined(_WIN32) && defined(__GNUC__) +/* GCC compiler for x86 32-bit uses the rule: + the stack is 16-byte aligned before CALL instruction for function calling. + But only root function main() contains instructions that + set 16-byte alignment for stack pointer. And another functions + just keep alignment, if it was set in some parent function. + + The problem: + if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(), + the root function of thread doesn't set 16-byte alignment. + And stack frames in all child functions also will be unaligned in that case. + + Here we set (force_align_arg_pointer) attribute for root function of new thread. + Do we need (force_align_arg_pointer) also for another systems? */ + + #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer)) + // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions +#else + #define THREAD_FUNC_ATTRIB_ALIGN_ARG +#endif + +#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE + +typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); +WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity); +WRes Thread_Wait_Close(CThread *p); + +#ifdef _WIN32 +#define Thread_Create_With_CpuSet(p, func, param, cs) \ + Thread_Create_With_Affinity(p, func, param, *cs) +#else +WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet); +#endif + + +#ifdef _WIN32 + +typedef HANDLE CEvent; +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; +#define Event_Construct(p) *(p) = NULL +#define Event_IsCreated(p) (*(p) != NULL) +#define Event_Close(p) HandlePtr_Close(p) +#define Event_Wait(p) Handle_WaitObject(*(p)) +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +typedef HANDLE CSemaphore; +#define Semaphore_Construct(p) *(p) = NULL +#define Semaphore_IsCreated(p) (*(p) != NULL) +#define Semaphore_Close(p) HandlePtr_Close(p) +#define Semaphore_Wait(p) Handle_WaitObject(*(p)) +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +WRes Semaphore_Release1(CSemaphore *p); + +typedef CRITICAL_SECTION CCriticalSection; +WRes CriticalSection_Init(CCriticalSection *p); +#define CriticalSection_Delete(p) DeleteCriticalSection(p) +#define CriticalSection_Enter(p) EnterCriticalSection(p) +#define CriticalSection_Leave(p) LeaveCriticalSection(p) + + +#else // _WIN32 + +typedef struct +{ + int _created; + int _manual_reset; + int _state; + pthread_mutex_t _mutex; + pthread_cond_t _cond; +} CEvent; + +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; + +#define Event_Construct(p) (p)->_created = 0 +#define Event_IsCreated(p) ((p)->_created) + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes Event_Wait(CEvent *p); +WRes Event_Close(CEvent *p); + + +typedef struct +{ + int _created; + UInt32 _count; + UInt32 _maxCount; + pthread_mutex_t _mutex; + pthread_cond_t _cond; +} CSemaphore; + +#define Semaphore_Construct(p) (p)->_created = 0 +#define Semaphore_IsCreated(p) ((p)->_created) + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1) +WRes Semaphore_Wait(CSemaphore *p); +WRes Semaphore_Close(CSemaphore *p); + + +typedef struct +{ + pthread_mutex_t _mutex; +} CCriticalSection; + +WRes CriticalSection_Init(CCriticalSection *p); +void CriticalSection_Delete(CCriticalSection *cs); +void CriticalSection_Enter(CCriticalSection *cs); +void CriticalSection_Leave(CCriticalSection *cs); + +LONG InterlockedIncrement(LONG volatile *addend); +LONG InterlockedDecrement(LONG volatile *addend); + +#endif // _WIN32 + +WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p); + +EXTERN_C_END + +#endif diff --git a/C/Util/7z/7z.dsp b/C/Util/7z/7z.dsp index 019913e5b..474c66080 100644 --- a/C/Util/7z/7z.dsp +++ b/C/Util/7z/7z.dsp @@ -1,249 +1,249 @@ -# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=7z - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "7z.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "7z - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /D "Z7_PPMD_SUPPORT" /D "Z7_EXTRACT_ONLY" /FAcs /Yu"Precomp.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /D "Z7_PPMD_SUPPORT" /D "Z7_EXTRACT_ONLY" /Yu"Precomp.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "7z - Win32 Release" -# Name "7z - Win32 Debug" -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7z.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zArcIn.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrcOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zDec.c -# ADD CPP /D "_7ZIP_PPMD_SUPPPORT" -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra86.c -# End Source File -# Begin Source File - -SOURCE=..\..\BraIA64.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\Delta.c -# End Source File -# Begin Source File - -SOURCE=..\..\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.c -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd.h -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd7.c -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd7.h -# End Source File -# Begin Source File - -SOURCE=..\..\Ppmd7Dec.c -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compiler.h -# End Source File -# Begin Source File - -SOURCE=.\Precomp.c -# ADD CPP /Yc"Precomp.h" -# End Source File -# Begin Source File - -SOURCE=..\..\Precomp.h -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7zMain.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=7z - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "7z.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "7z - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /D "Z7_PPMD_SUPPORT" /D "Z7_EXTRACT_ONLY" /FAcs /Yu"Precomp.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /D "Z7_PPMD_SUPPORT" /D "Z7_EXTRACT_ONLY" /Yu"Precomp.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "7z - Win32 Release" +# Name "7z - Win32 Debug" +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7z.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zArcIn.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrcOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zDec.c +# ADD CPP /D "_7ZIP_PPMD_SUPPPORT" +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra86.c +# End Source File +# Begin Source File + +SOURCE=..\..\BraIA64.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.c +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.c +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd.h +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd7.c +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd7.h +# End Source File +# Begin Source File + +SOURCE=..\..\Ppmd7Dec.c +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compiler.h +# End Source File +# Begin Source File + +SOURCE=.\Precomp.c +# ADD CPP /Yc"Precomp.h" +# End Source File +# Begin Source File + +SOURCE=..\..\Precomp.h +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7zMain.c +# End Source File +# End Target +# End Project diff --git a/C/Util/7z/7z.dsw b/C/Util/7z/7z.dsw index 23089fb79..848d13cb1 100644 --- a/C/Util/7z/7z.dsw +++ b/C/Util/7z/7z.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "7z"=.\7z.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "7z"=.\7z.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/C/Util/7z/7zMain.c b/C/Util/7z/7zMain.c index 8ae9180d5..6baf979e0 100644 --- a/C/Util/7z/7zMain.c +++ b/C/Util/7z/7zMain.c @@ -1,889 +1,889 @@ -/* 7zMain.c - Test application for 7z Decoder -2024-02-28 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include -#include - -#ifndef USE_WINDOWS_FILE -/* for mkdir */ -#ifdef _WIN32 -#include -#else -#include -#include -#ifdef __GNUC__ -#include -#endif -#include -// #include -#include -#include -#endif -#endif - -#include "../../7zFile.h" -#include "../../7z.h" -#include "../../7zAlloc.h" -#include "../../7zBuf.h" -#include "../../7zCrc.h" -#include "../../7zVersion.h" - -#include "../../CpuArch.h" - -#define kInputBufSize ((size_t)1 << 18) - -static const ISzAlloc g_Alloc = { SzAlloc, SzFree }; -// static const ISzAlloc g_Alloc_temp = { SzAllocTemp, SzFreeTemp }; - - -static void Print(const char *s) -{ - fputs(s, stdout); -} - - -static int Buf_EnsureSize(CBuf *dest, size_t size) -{ - if (dest->size >= size) - return 1; - Buf_Free(dest, &g_Alloc); - return Buf_Create(dest, size, &g_Alloc); -} - -#ifndef _WIN32 -#define MY_USE_UTF8 -#endif - -/* #define MY_USE_UTF8 */ - -#ifdef MY_USE_UTF8 - -#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n)))) - -#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) - -#define MY_UTF8_HEAD(n, val) ((Byte)(MY_UTF8_START(n) + (val >> (6 * (n))))) -#define MY_UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F))) - -static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim) -{ - size_t size = 0; - for (;;) - { - UInt32 val; - if (src == srcLim) - return size; - - size++; - val = *src++; - - if (val < 0x80) - continue; - - if (val < MY_UTF8_RANGE(1)) - { - size++; - continue; - } - - if (val >= 0xD800 && val < 0xDC00 && src != srcLim) - { - const UInt32 c2 = *src; - if (c2 >= 0xDC00 && c2 < 0xE000) - { - src++; - size += 3; - continue; - } - } - - size += 2; - } -} - -static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim) -{ - for (;;) - { - UInt32 val; - if (src == srcLim) - return dest; - - val = *src++; - - if (val < 0x80) - { - *dest++ = (Byte)val; - continue; - } - - if (val < MY_UTF8_RANGE(1)) - { - dest[0] = MY_UTF8_HEAD(1, val); - dest[1] = MY_UTF8_CHAR(0, val); - dest += 2; - continue; - } - - if (val >= 0xD800 && val < 0xDC00 && src != srcLim) - { - const UInt32 c2 = *src; - if (c2 >= 0xDC00 && c2 < 0xE000) - { - src++; - val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; - dest[0] = MY_UTF8_HEAD(3, val); - dest[1] = MY_UTF8_CHAR(2, val); - dest[2] = MY_UTF8_CHAR(1, val); - dest[3] = MY_UTF8_CHAR(0, val); - dest += 4; - continue; - } - } - - dest[0] = MY_UTF8_HEAD(2, val); - dest[1] = MY_UTF8_CHAR(1, val); - dest[2] = MY_UTF8_CHAR(0, val); - dest += 3; - } -} - -static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen) -{ - size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen); - destLen += 1; - if (!Buf_EnsureSize(dest, destLen)) - return SZ_ERROR_MEM; - *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0; - return SZ_OK; -} - -#endif - -static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s - #ifndef MY_USE_UTF8 - , UINT codePage - #endif - ) -{ - size_t len = 0; - for (len = 0; s[len] != 0; len++) {} - - #ifndef MY_USE_UTF8 - { - const size_t size = len * 3 + 100; - if (!Buf_EnsureSize(buf, size)) - return SZ_ERROR_MEM; - { - buf->data[0] = 0; - if (len != 0) - { - const char defaultChar = '_'; - BOOL defUsed; - const unsigned numChars = (unsigned)WideCharToMultiByte( - codePage, 0, (LPCWSTR)s, (int)len, (char *)buf->data, (int)size, &defaultChar, &defUsed); - if (numChars == 0 || numChars >= size) - return SZ_ERROR_FAIL; - buf->data[numChars] = 0; - } - return SZ_OK; - } - } - #else - return Utf16_To_Utf8Buf(buf, s, len); - #endif -} - -#ifdef _WIN32 - #ifndef USE_WINDOWS_FILE - static UINT g_FileCodePage = CP_ACP; - #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage - #endif -#else - #define MY_FILE_CODE_PAGE_PARAM -#endif - -static WRes MyCreateDir(const UInt16 *name) -{ - #ifdef USE_WINDOWS_FILE - - return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError(); - - #else - - CBuf buf; - WRes res; - Buf_Init(&buf); - RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)) - - res = - #ifdef _WIN32 - _mkdir((const char *)buf.data) - #else - mkdir((const char *)buf.data, 0777) - #endif - == 0 ? 0 : errno; - Buf_Free(&buf, &g_Alloc); - return res; - - #endif -} - -static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name) -{ - #ifdef USE_WINDOWS_FILE - return OutFile_OpenW(p, (LPCWSTR)name); - #else - CBuf buf; - WRes res; - Buf_Init(&buf); - RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)) - res = OutFile_Open(p, (const char *)buf.data); - Buf_Free(&buf, &g_Alloc); - return res; - #endif -} - - -static SRes PrintString(const UInt16 *s) -{ - CBuf buf; - SRes res; - Buf_Init(&buf); - res = Utf16_To_Char(&buf, s - #ifndef MY_USE_UTF8 - , CP_OEMCP - #endif - ); - if (res == SZ_OK) - Print((const char *)buf.data); - Buf_Free(&buf, &g_Alloc); - return res; -} - -static void UInt64ToStr(UInt64 value, char *s, int numDigits) -{ - char temp[32]; - int pos = 0; - do - { - temp[pos++] = (char)('0' + (unsigned)(value % 10)); - value /= 10; - } - while (value != 0); - - for (numDigits -= pos; numDigits > 0; numDigits--) - *s++ = ' '; - - do - *s++ = temp[--pos]; - while (pos); - *s = '\0'; -} - -static char *UIntToStr(char *s, unsigned value, int numDigits) -{ - char temp[16]; - int pos = 0; - do - temp[pos++] = (char)('0' + (value % 10)); - while (value /= 10); - - for (numDigits -= pos; numDigits > 0; numDigits--) - *s++ = '0'; - - do - *s++ = temp[--pos]; - while (pos); - *s = '\0'; - return s; -} - -static void UIntToStr_2(char *s, unsigned value) -{ - s[0] = (char)('0' + (value / 10)); - s[1] = (char)('0' + (value % 10)); -} - - -#define PERIOD_4 (4 * 365 + 1) -#define PERIOD_100 (PERIOD_4 * 25 - 1) -#define PERIOD_400 (PERIOD_100 * 4 + 1) - - - -#ifndef _WIN32 - -// MS uses long for BOOL, but long is 32-bit in MS. So we use int. -// typedef long BOOL; -typedef int BOOL; - -typedef struct -{ - DWORD dwLowDateTime; - DWORD dwHighDateTime; -} FILETIME; - -static LONG TIME_GetBias(void) -{ - const time_t utc = time(NULL); - struct tm *ptm = localtime(&utc); - const int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ - ptm = gmtime(&utc); - ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ - return (int)(mktime(ptm) - utc); -} - -#define TICKS_PER_SEC 10000000 - -#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) - -#define SET_FILETIME(ft, v64) \ - (ft)->dwLowDateTime = (DWORD)v64; \ - (ft)->dwHighDateTime = (DWORD)(v64 >> 32); - -#define WINAPI -#define TRUE 1 - -static BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) -{ - UInt64 v = GET_TIME_64(fileTime); - v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); - SET_FILETIME(localFileTime, v) - return TRUE; -} - -static const UInt32 kNumTimeQuantumsInSecond = 10000000; -static const UInt32 kFileTimeStartYear = 1601; -static const UInt32 kUnixTimeStartYear = 1970; - -static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft) -{ - const UInt64 kUnixTimeOffset = - (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); - const UInt64 winTime = GET_TIME_64(ft); - return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; -} - -#if defined(_AIX) - #define MY_ST_TIMESPEC st_timespec -#else - #define MY_ST_TIMESPEC timespec -#endif - -static void FILETIME_To_timespec(const FILETIME *ft, struct MY_ST_TIMESPEC *ts) -{ - if (ft) - { - const Int64 sec = Time_FileTimeToUnixTime64(ft); - // time_t is long - const time_t sec2 = (time_t)sec; - if (sec2 == sec) - { - ts->tv_sec = sec2; - { - const UInt64 winTime = GET_TIME_64(ft); - ts->tv_nsec = (long)((winTime % 10000000) * 100); - } - return; - } - } - // else - { - ts->tv_sec = 0; - // ts.tv_nsec = UTIME_NOW; // set to the current time - ts->tv_nsec = UTIME_OMIT; // keep old timesptamp - } -} - -static WRes Set_File_FILETIME(const UInt16 *name, const FILETIME *mTime) -{ - struct timespec times[2]; - - const int flags = 0; // follow link - // = AT_SYMLINK_NOFOLLOW; // don't follow link - - CBuf buf; - int res; - Buf_Init(&buf); - RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)) - FILETIME_To_timespec(NULL, ×[0]); - FILETIME_To_timespec(mTime, ×[1]); - res = utimensat(AT_FDCWD, (const char *)buf.data, times, flags); - Buf_Free(&buf, &g_Alloc); - if (res == 0) - return 0; - return errno; -} - -#endif - -static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft) -{ - ft->dwLowDateTime = (DWORD)(t->Low); - ft->dwHighDateTime = (DWORD)(t->High); -} - -static void ConvertFileTimeToString(const CNtfsFileTime *nTime, char *s) -{ - unsigned year, mon, hour, min, sec; - Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - UInt32 t; - UInt32 v; - // UInt64 v64 = nt->Low | ((UInt64)nt->High << 32); - UInt64 v64; - { - FILETIME fileTime, locTime; - NtfsFileTime_to_FILETIME(nTime, &fileTime); - if (!FileTimeToLocalFileTime(&fileTime, &locTime)) - { - locTime.dwHighDateTime = - locTime.dwLowDateTime = 0; - } - v64 = locTime.dwLowDateTime | ((UInt64)locTime.dwHighDateTime << 32); - } - v64 /= 10000000; - sec = (unsigned)(v64 % 60); v64 /= 60; - min = (unsigned)(v64 % 60); v64 /= 60; - hour = (unsigned)(v64 % 24); v64 /= 24; - - v = (UInt32)v64; - - year = (unsigned)(1601 + v / PERIOD_400 * 400); - v %= PERIOD_400; - - t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; - t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; - t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; - - if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) - ms[1] = 29; - for (mon = 0;; mon++) - { - const UInt32 d = ms[mon]; - if (v < d) - break; - v -= d; - } - s = UIntToStr(s, year, 4); *s++ = '-'; - UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3; - UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3; - UIntToStr_2(s, hour); s[2] = ':'; s += 3; - UIntToStr_2(s, min); s[2] = ':'; s += 3; - UIntToStr_2(s, sec); s[2] = 0; -} - -static void PrintLF(void) -{ - Print("\n"); -} - -static void PrintError(char *s) -{ - Print("\nERROR: "); - Print(s); - PrintLF(); -} - -static void PrintError_WRes(const char *message, WRes wres) -{ - Print("\nERROR: "); - Print(message); - PrintLF(); - { - char s[32]; - UIntToStr(s, (unsigned)wres, 1); - Print("System error code: "); - Print(s); - } - // sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres); - #ifdef _WIN32 - { - char *s = NULL; - if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, wres, 0, (LPSTR) &s, 0, NULL) != 0 && s) - { - Print(" : "); - Print(s); - LocalFree(s); - } - } - #else - { - const char *s = strerror(wres); - if (s) - { - Print(" : "); - Print(s); - } - } - #endif - PrintLF(); -} - -static void GetAttribString(UInt32 wa, BoolInt isDir, char *s) -{ - #ifdef USE_WINDOWS_FILE - s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.'); - s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.'); - s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.'); - s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.'); - s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.'); - s[5] = 0; - #else - s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.'); - s[1] = 0; - #endif -} - - -// #define NUM_PARENTS_MAX 128 - -int Z7_CDECL main(int numargs, char *args[]) -{ - ISzAlloc allocImp; - ISzAlloc allocTempImp; - - CFileInStream archiveStream; - CLookToRead2 lookStream; - CSzArEx db; - SRes res; - UInt16 *temp = NULL; - size_t tempSize = 0; - // UInt32 parents[NUM_PARENTS_MAX]; - - Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"); - - if (numargs == 1) - { - Print( - "Usage: 7zDec \n\n" - "\n" - " e: Extract files from archive (without using directory names)\n" - " l: List contents of archive\n" - " t: Test integrity of archive\n" - " x: eXtract files with full paths\n"); - return 0; - } - - if (numargs < 3) - { - PrintError("incorrect command"); - return 1; - } - - #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE) - g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - #endif - - - allocImp = g_Alloc; - allocTempImp = g_Alloc; - // allocTempImp = g_Alloc_temp; - - { - WRes wres = - #ifdef UNDER_CE - InFile_OpenW(&archiveStream.file, L"\test.7z"); // change it - #else - InFile_Open(&archiveStream.file, args[2]); - #endif - if (wres != 0) - { - PrintError_WRes("cannot open input file", wres); - return 1; - } - } - - FileInStream_CreateVTable(&archiveStream); - archiveStream.wres = 0; - LookToRead2_CreateVTable(&lookStream, False); - lookStream.buf = NULL; - - res = SZ_OK; - - { - lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); - if (!lookStream.buf) - res = SZ_ERROR_MEM; - else - { - lookStream.bufSize = kInputBufSize; - lookStream.realStream = &archiveStream.vt; - LookToRead2_INIT(&lookStream) - } - } - - CrcGenerateTable(); - - SzArEx_Init(&db); - - if (res == SZ_OK) - { - res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); - } - - if (res == SZ_OK) - { - char *command = args[1]; - int listCommand = 0, testCommand = 0, fullPaths = 0; - - if (strcmp(command, "l") == 0) listCommand = 1; - else if (strcmp(command, "t") == 0) testCommand = 1; - else if (strcmp(command, "e") == 0) { } - else if (strcmp(command, "x") == 0) { fullPaths = 1; } - else - { - PrintError("incorrect command"); - res = SZ_ERROR_FAIL; - } - - if (res == SZ_OK) - { - UInt32 i; - - /* - if you need cache, use these 3 variables. - if you use external function, you can make these variable as static. - */ - UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ - Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ - size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ - - for (i = 0; i < db.NumFiles; i++) - { - size_t offset = 0; - size_t outSizeProcessed = 0; - // const CSzFileItem *f = db.Files + i; - size_t len; - const BoolInt isDir = SzArEx_IsDir(&db, i); - if (listCommand == 0 && isDir && !fullPaths) - continue; - len = SzArEx_GetFileNameUtf16(&db, i, NULL); - // len = SzArEx_GetFullNameLen(&db, i); - - if (len > tempSize) - { - SzFree(NULL, temp); - tempSize = len; - temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0])); - if (!temp) - { - res = SZ_ERROR_MEM; - break; - } - } - - SzArEx_GetFileNameUtf16(&db, i, temp); - /* - if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp) - { - res = SZ_ERROR_FAIL; - break; - } - */ - - if (listCommand) - { - char attr[8], s[32], t[32]; - UInt64 fileSize; - - GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr); - - fileSize = SzArEx_GetFileSize(&db, i); - UInt64ToStr(fileSize, s, 10); - - if (SzBitWithVals_Check(&db.MTime, i)) - ConvertFileTimeToString(&db.MTime.Vals[i], t); - else - { - size_t j; - for (j = 0; j < 19; j++) - t[j] = ' '; - t[j] = '\0'; - } - - Print(t); - Print(" "); - Print(attr); - Print(" "); - Print(s); - Print(" "); - res = PrintString(temp); - if (res != SZ_OK) - break; - if (isDir) - Print("/"); - PrintLF(); - continue; - } - - Print(testCommand ? - "T ": - "- "); - res = PrintString(temp); - if (res != SZ_OK) - break; - - if (isDir) - Print("/"); - else - { - res = SzArEx_Extract(&db, &lookStream.vt, i, - &blockIndex, &outBuffer, &outBufferSize, - &offset, &outSizeProcessed, - &allocImp, &allocTempImp); - if (res != SZ_OK) - break; - } - - if (!testCommand) - { - CSzFile outFile; - size_t processedSize; - size_t j; - UInt16 *name = (UInt16 *)temp; - const UInt16 *destPath = (const UInt16 *)name; - - for (j = 0; name[j] != 0; j++) - if (name[j] == '/') - { - if (fullPaths) - { - name[j] = 0; - MyCreateDir(name); - name[j] = CHAR_PATH_SEPARATOR; - } - else - destPath = name + j + 1; - } - - if (isDir) - { - MyCreateDir(destPath); - PrintLF(); - continue; - } - else - { - const WRes wres = OutFile_OpenUtf16(&outFile, destPath); - if (wres != 0) - { - PrintError_WRes("cannot open output file", wres); - res = SZ_ERROR_FAIL; - break; - } - } - - processedSize = outSizeProcessed; - - { - const WRes wres = File_Write(&outFile, outBuffer + offset, &processedSize); - if (wres != 0 || processedSize != outSizeProcessed) - { - PrintError_WRes("cannot write output file", wres); - res = SZ_ERROR_FAIL; - break; - } - } - - { - FILETIME mtime; - FILETIME *mtimePtr = NULL; - - #ifdef USE_WINDOWS_FILE - FILETIME ctime; - FILETIME *ctimePtr = NULL; - #endif - - if (SzBitWithVals_Check(&db.MTime, i)) - { - const CNtfsFileTime *t = &db.MTime.Vals[i]; - mtime.dwLowDateTime = (DWORD)(t->Low); - mtime.dwHighDateTime = (DWORD)(t->High); - mtimePtr = &mtime; - } - - #ifdef USE_WINDOWS_FILE - if (SzBitWithVals_Check(&db.CTime, i)) - { - const CNtfsFileTime *t = &db.CTime.Vals[i]; - ctime.dwLowDateTime = (DWORD)(t->Low); - ctime.dwHighDateTime = (DWORD)(t->High); - ctimePtr = &ctime; - } - - if (mtimePtr || ctimePtr) - SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr); - #endif - - { - const WRes wres = File_Close(&outFile); - if (wres != 0) - { - PrintError_WRes("cannot close output file", wres); - res = SZ_ERROR_FAIL; - break; - } - } - - #ifndef USE_WINDOWS_FILE - #ifdef _WIN32 - mtimePtr = mtimePtr; - #else - if (mtimePtr) - Set_File_FILETIME(destPath, mtimePtr); - #endif - #endif - } - - #ifdef USE_WINDOWS_FILE - if (SzBitWithVals_Check(&db.Attribs, i)) - { - UInt32 attrib = db.Attribs.Vals[i]; - /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker. - We remove posix bits, if we detect posix mode field */ - if ((attrib & 0xF0000000) != 0) - attrib &= 0x7FFF; - SetFileAttributesW((LPCWSTR)destPath, attrib); - } - #endif - } - PrintLF(); - } - ISzAlloc_Free(&allocImp, outBuffer); - } - } - - SzFree(NULL, temp); - SzArEx_Free(&db, &allocImp); - ISzAlloc_Free(&allocImp, lookStream.buf); - - File_Close(&archiveStream.file); - - if (res == SZ_OK) - { - Print("\nEverything is Ok\n"); - return 0; - } - - if (res == SZ_ERROR_UNSUPPORTED) - PrintError("decoder doesn't support this archive"); - else if (res == SZ_ERROR_MEM) - PrintError("cannot allocate memory"); - else if (res == SZ_ERROR_CRC) - PrintError("CRC error"); - else if (res == SZ_ERROR_READ /* || archiveStream.Res != 0 */) - PrintError_WRes("Read Error", archiveStream.wres); - else - { - char s[32]; - UInt64ToStr((unsigned)res, s, 0); - PrintError(s); - } - - return 1; -} +/* 7zMain.c - Test application for 7z Decoder +2024-02-28 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#ifndef USE_WINDOWS_FILE +/* for mkdir */ +#ifdef _WIN32 +#include +#else +#include +#include +#ifdef __GNUC__ +#include +#endif +#include +// #include +#include +#include +#endif +#endif + +#include "../../7zFile.h" +#include "../../7z.h" +#include "../../7zAlloc.h" +#include "../../7zBuf.h" +#include "../../7zCrc.h" +#include "../../7zVersion.h" + +#include "../../CpuArch.h" + +#define kInputBufSize ((size_t)1 << 18) + +static const ISzAlloc g_Alloc = { SzAlloc, SzFree }; +// static const ISzAlloc g_Alloc_temp = { SzAllocTemp, SzFreeTemp }; + + +static void Print(const char *s) +{ + fputs(s, stdout); +} + + +static int Buf_EnsureSize(CBuf *dest, size_t size) +{ + if (dest->size >= size) + return 1; + Buf_Free(dest, &g_Alloc); + return Buf_Create(dest, size, &g_Alloc); +} + +#ifndef _WIN32 +#define MY_USE_UTF8 +#endif + +/* #define MY_USE_UTF8 */ + +#ifdef MY_USE_UTF8 + +#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n)))) + +#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) + +#define MY_UTF8_HEAD(n, val) ((Byte)(MY_UTF8_START(n) + (val >> (6 * (n))))) +#define MY_UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F))) + +static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim) +{ + size_t size = 0; + for (;;) + { + UInt32 val; + if (src == srcLim) + return size; + + size++; + val = *src++; + + if (val < 0x80) + continue; + + if (val < MY_UTF8_RANGE(1)) + { + size++; + continue; + } + + if (val >= 0xD800 && val < 0xDC00 && src != srcLim) + { + const UInt32 c2 = *src; + if (c2 >= 0xDC00 && c2 < 0xE000) + { + src++; + size += 3; + continue; + } + } + + size += 2; + } +} + +static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim) +{ + for (;;) + { + UInt32 val; + if (src == srcLim) + return dest; + + val = *src++; + + if (val < 0x80) + { + *dest++ = (Byte)val; + continue; + } + + if (val < MY_UTF8_RANGE(1)) + { + dest[0] = MY_UTF8_HEAD(1, val); + dest[1] = MY_UTF8_CHAR(0, val); + dest += 2; + continue; + } + + if (val >= 0xD800 && val < 0xDC00 && src != srcLim) + { + const UInt32 c2 = *src; + if (c2 >= 0xDC00 && c2 < 0xE000) + { + src++; + val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + dest[0] = MY_UTF8_HEAD(3, val); + dest[1] = MY_UTF8_CHAR(2, val); + dest[2] = MY_UTF8_CHAR(1, val); + dest[3] = MY_UTF8_CHAR(0, val); + dest += 4; + continue; + } + } + + dest[0] = MY_UTF8_HEAD(2, val); + dest[1] = MY_UTF8_CHAR(1, val); + dest[2] = MY_UTF8_CHAR(0, val); + dest += 3; + } +} + +static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen) +{ + size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen); + destLen += 1; + if (!Buf_EnsureSize(dest, destLen)) + return SZ_ERROR_MEM; + *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0; + return SZ_OK; +} + +#endif + +static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s + #ifndef MY_USE_UTF8 + , UINT codePage + #endif + ) +{ + size_t len = 0; + for (len = 0; s[len] != 0; len++) {} + + #ifndef MY_USE_UTF8 + { + const size_t size = len * 3 + 100; + if (!Buf_EnsureSize(buf, size)) + return SZ_ERROR_MEM; + { + buf->data[0] = 0; + if (len != 0) + { + const char defaultChar = '_'; + BOOL defUsed; + const unsigned numChars = (unsigned)WideCharToMultiByte( + codePage, 0, (LPCWSTR)s, (int)len, (char *)buf->data, (int)size, &defaultChar, &defUsed); + if (numChars == 0 || numChars >= size) + return SZ_ERROR_FAIL; + buf->data[numChars] = 0; + } + return SZ_OK; + } + } + #else + return Utf16_To_Utf8Buf(buf, s, len); + #endif +} + +#ifdef _WIN32 + #ifndef USE_WINDOWS_FILE + static UINT g_FileCodePage = CP_ACP; + #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage + #endif +#else + #define MY_FILE_CODE_PAGE_PARAM +#endif + +static WRes MyCreateDir(const UInt16 *name) +{ + #ifdef USE_WINDOWS_FILE + + return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError(); + + #else + + CBuf buf; + WRes res; + Buf_Init(&buf); + RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)) + + res = + #ifdef _WIN32 + _mkdir((const char *)buf.data) + #else + mkdir((const char *)buf.data, 0777) + #endif + == 0 ? 0 : errno; + Buf_Free(&buf, &g_Alloc); + return res; + + #endif +} + +static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name) +{ + #ifdef USE_WINDOWS_FILE + return OutFile_OpenW(p, (LPCWSTR)name); + #else + CBuf buf; + WRes res; + Buf_Init(&buf); + RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)) + res = OutFile_Open(p, (const char *)buf.data); + Buf_Free(&buf, &g_Alloc); + return res; + #endif +} + + +static SRes PrintString(const UInt16 *s) +{ + CBuf buf; + SRes res; + Buf_Init(&buf); + res = Utf16_To_Char(&buf, s + #ifndef MY_USE_UTF8 + , CP_OEMCP + #endif + ); + if (res == SZ_OK) + Print((const char *)buf.data); + Buf_Free(&buf, &g_Alloc); + return res; +} + +static void UInt64ToStr(UInt64 value, char *s, int numDigits) +{ + char temp[32]; + int pos = 0; + do + { + temp[pos++] = (char)('0' + (unsigned)(value % 10)); + value /= 10; + } + while (value != 0); + + for (numDigits -= pos; numDigits > 0; numDigits--) + *s++ = ' '; + + do + *s++ = temp[--pos]; + while (pos); + *s = '\0'; +} + +static char *UIntToStr(char *s, unsigned value, int numDigits) +{ + char temp[16]; + int pos = 0; + do + temp[pos++] = (char)('0' + (value % 10)); + while (value /= 10); + + for (numDigits -= pos; numDigits > 0; numDigits--) + *s++ = '0'; + + do + *s++ = temp[--pos]; + while (pos); + *s = '\0'; + return s; +} + +static void UIntToStr_2(char *s, unsigned value) +{ + s[0] = (char)('0' + (value / 10)); + s[1] = (char)('0' + (value % 10)); +} + + +#define PERIOD_4 (4 * 365 + 1) +#define PERIOD_100 (PERIOD_4 * 25 - 1) +#define PERIOD_400 (PERIOD_100 * 4 + 1) + + + +#ifndef _WIN32 + +// MS uses long for BOOL, but long is 32-bit in MS. So we use int. +// typedef long BOOL; +typedef int BOOL; + +typedef struct +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME; + +static LONG TIME_GetBias(void) +{ + const time_t utc = time(NULL); + struct tm *ptm = localtime(&utc); + const int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ + ptm = gmtime(&utc); + ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ + return (int)(mktime(ptm) - utc); +} + +#define TICKS_PER_SEC 10000000 + +#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) + +#define SET_FILETIME(ft, v64) \ + (ft)->dwLowDateTime = (DWORD)v64; \ + (ft)->dwHighDateTime = (DWORD)(v64 >> 32); + +#define WINAPI +#define TRUE 1 + +static BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) +{ + UInt64 v = GET_TIME_64(fileTime); + v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); + SET_FILETIME(localFileTime, v) + return TRUE; +} + +static const UInt32 kNumTimeQuantumsInSecond = 10000000; +static const UInt32 kFileTimeStartYear = 1601; +static const UInt32 kUnixTimeStartYear = 1970; + +static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft) +{ + const UInt64 kUnixTimeOffset = + (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); + const UInt64 winTime = GET_TIME_64(ft); + return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; +} + +#if defined(_AIX) + #define MY_ST_TIMESPEC st_timespec +#else + #define MY_ST_TIMESPEC timespec +#endif + +static void FILETIME_To_timespec(const FILETIME *ft, struct MY_ST_TIMESPEC *ts) +{ + if (ft) + { + const Int64 sec = Time_FileTimeToUnixTime64(ft); + // time_t is long + const time_t sec2 = (time_t)sec; + if (sec2 == sec) + { + ts->tv_sec = sec2; + { + const UInt64 winTime = GET_TIME_64(ft); + ts->tv_nsec = (long)((winTime % 10000000) * 100); + } + return; + } + } + // else + { + ts->tv_sec = 0; + // ts.tv_nsec = UTIME_NOW; // set to the current time + ts->tv_nsec = UTIME_OMIT; // keep old timesptamp + } +} + +static WRes Set_File_FILETIME(const UInt16 *name, const FILETIME *mTime) +{ + struct timespec times[2]; + + const int flags = 0; // follow link + // = AT_SYMLINK_NOFOLLOW; // don't follow link + + CBuf buf; + int res; + Buf_Init(&buf); + RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM)) + FILETIME_To_timespec(NULL, ×[0]); + FILETIME_To_timespec(mTime, ×[1]); + res = utimensat(AT_FDCWD, (const char *)buf.data, times, flags); + Buf_Free(&buf, &g_Alloc); + if (res == 0) + return 0; + return errno; +} + +#endif + +static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft) +{ + ft->dwLowDateTime = (DWORD)(t->Low); + ft->dwHighDateTime = (DWORD)(t->High); +} + +static void ConvertFileTimeToString(const CNtfsFileTime *nTime, char *s) +{ + unsigned year, mon, hour, min, sec; + Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + UInt32 t; + UInt32 v; + // UInt64 v64 = nt->Low | ((UInt64)nt->High << 32); + UInt64 v64; + { + FILETIME fileTime, locTime; + NtfsFileTime_to_FILETIME(nTime, &fileTime); + if (!FileTimeToLocalFileTime(&fileTime, &locTime)) + { + locTime.dwHighDateTime = + locTime.dwLowDateTime = 0; + } + v64 = locTime.dwLowDateTime | ((UInt64)locTime.dwHighDateTime << 32); + } + v64 /= 10000000; + sec = (unsigned)(v64 % 60); v64 /= 60; + min = (unsigned)(v64 % 60); v64 /= 60; + hour = (unsigned)(v64 % 24); v64 /= 24; + + v = (UInt32)v64; + + year = (unsigned)(1601 + v / PERIOD_400 * 400); + v %= PERIOD_400; + + t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; + t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; + t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; + + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + ms[1] = 29; + for (mon = 0;; mon++) + { + const UInt32 d = ms[mon]; + if (v < d) + break; + v -= d; + } + s = UIntToStr(s, year, 4); *s++ = '-'; + UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3; + UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3; + UIntToStr_2(s, hour); s[2] = ':'; s += 3; + UIntToStr_2(s, min); s[2] = ':'; s += 3; + UIntToStr_2(s, sec); s[2] = 0; +} + +static void PrintLF(void) +{ + Print("\n"); +} + +static void PrintError(char *s) +{ + Print("\nERROR: "); + Print(s); + PrintLF(); +} + +static void PrintError_WRes(const char *message, WRes wres) +{ + Print("\nERROR: "); + Print(message); + PrintLF(); + { + char s[32]; + UIntToStr(s, (unsigned)wres, 1); + Print("System error code: "); + Print(s); + } + // sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres); + #ifdef _WIN32 + { + char *s = NULL; + if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, wres, 0, (LPSTR) &s, 0, NULL) != 0 && s) + { + Print(" : "); + Print(s); + LocalFree(s); + } + } + #else + { + const char *s = strerror(wres); + if (s) + { + Print(" : "); + Print(s); + } + } + #endif + PrintLF(); +} + +static void GetAttribString(UInt32 wa, BoolInt isDir, char *s) +{ + #ifdef USE_WINDOWS_FILE + s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.'); + s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.'); + s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.'); + s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.'); + s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.'); + s[5] = 0; + #else + s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.'); + s[1] = 0; + #endif +} + + +// #define NUM_PARENTS_MAX 128 + +int Z7_CDECL main(int numargs, char *args[]) +{ + ISzAlloc allocImp; + ISzAlloc allocTempImp; + + CFileInStream archiveStream; + CLookToRead2 lookStream; + CSzArEx db; + SRes res; + UInt16 *temp = NULL; + size_t tempSize = 0; + // UInt32 parents[NUM_PARENTS_MAX]; + + Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"); + + if (numargs == 1) + { + Print( + "Usage: 7zDec \n\n" + "\n" + " e: Extract files from archive (without using directory names)\n" + " l: List contents of archive\n" + " t: Test integrity of archive\n" + " x: eXtract files with full paths\n"); + return 0; + } + + if (numargs < 3) + { + PrintError("incorrect command"); + return 1; + } + + #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE) + g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + #endif + + + allocImp = g_Alloc; + allocTempImp = g_Alloc; + // allocTempImp = g_Alloc_temp; + + { + WRes wres = + #ifdef UNDER_CE + InFile_OpenW(&archiveStream.file, L"\test.7z"); // change it + #else + InFile_Open(&archiveStream.file, args[2]); + #endif + if (wres != 0) + { + PrintError_WRes("cannot open input file", wres); + return 1; + } + } + + FileInStream_CreateVTable(&archiveStream); + archiveStream.wres = 0; + LookToRead2_CreateVTable(&lookStream, False); + lookStream.buf = NULL; + + res = SZ_OK; + + { + lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); + if (!lookStream.buf) + res = SZ_ERROR_MEM; + else + { + lookStream.bufSize = kInputBufSize; + lookStream.realStream = &archiveStream.vt; + LookToRead2_INIT(&lookStream) + } + } + + CrcGenerateTable(); + + SzArEx_Init(&db); + + if (res == SZ_OK) + { + res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); + } + + if (res == SZ_OK) + { + char *command = args[1]; + int listCommand = 0, testCommand = 0, fullPaths = 0; + + if (strcmp(command, "l") == 0) listCommand = 1; + else if (strcmp(command, "t") == 0) testCommand = 1; + else if (strcmp(command, "e") == 0) { } + else if (strcmp(command, "x") == 0) { fullPaths = 1; } + else + { + PrintError("incorrect command"); + res = SZ_ERROR_FAIL; + } + + if (res == SZ_OK) + { + UInt32 i; + + /* + if you need cache, use these 3 variables. + if you use external function, you can make these variable as static. + */ + UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ + Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ + size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ + + for (i = 0; i < db.NumFiles; i++) + { + size_t offset = 0; + size_t outSizeProcessed = 0; + // const CSzFileItem *f = db.Files + i; + size_t len; + const BoolInt isDir = SzArEx_IsDir(&db, i); + if (listCommand == 0 && isDir && !fullPaths) + continue; + len = SzArEx_GetFileNameUtf16(&db, i, NULL); + // len = SzArEx_GetFullNameLen(&db, i); + + if (len > tempSize) + { + SzFree(NULL, temp); + tempSize = len; + temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0])); + if (!temp) + { + res = SZ_ERROR_MEM; + break; + } + } + + SzArEx_GetFileNameUtf16(&db, i, temp); + /* + if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp) + { + res = SZ_ERROR_FAIL; + break; + } + */ + + if (listCommand) + { + char attr[8], s[32], t[32]; + UInt64 fileSize; + + GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr); + + fileSize = SzArEx_GetFileSize(&db, i); + UInt64ToStr(fileSize, s, 10); + + if (SzBitWithVals_Check(&db.MTime, i)) + ConvertFileTimeToString(&db.MTime.Vals[i], t); + else + { + size_t j; + for (j = 0; j < 19; j++) + t[j] = ' '; + t[j] = '\0'; + } + + Print(t); + Print(" "); + Print(attr); + Print(" "); + Print(s); + Print(" "); + res = PrintString(temp); + if (res != SZ_OK) + break; + if (isDir) + Print("/"); + PrintLF(); + continue; + } + + Print(testCommand ? + "T ": + "- "); + res = PrintString(temp); + if (res != SZ_OK) + break; + + if (isDir) + Print("/"); + else + { + res = SzArEx_Extract(&db, &lookStream.vt, i, + &blockIndex, &outBuffer, &outBufferSize, + &offset, &outSizeProcessed, + &allocImp, &allocTempImp); + if (res != SZ_OK) + break; + } + + if (!testCommand) + { + CSzFile outFile; + size_t processedSize; + size_t j; + UInt16 *name = (UInt16 *)temp; + const UInt16 *destPath = (const UInt16 *)name; + + for (j = 0; name[j] != 0; j++) + if (name[j] == '/') + { + if (fullPaths) + { + name[j] = 0; + MyCreateDir(name); + name[j] = CHAR_PATH_SEPARATOR; + } + else + destPath = name + j + 1; + } + + if (isDir) + { + MyCreateDir(destPath); + PrintLF(); + continue; + } + else + { + const WRes wres = OutFile_OpenUtf16(&outFile, destPath); + if (wres != 0) + { + PrintError_WRes("cannot open output file", wres); + res = SZ_ERROR_FAIL; + break; + } + } + + processedSize = outSizeProcessed; + + { + const WRes wres = File_Write(&outFile, outBuffer + offset, &processedSize); + if (wres != 0 || processedSize != outSizeProcessed) + { + PrintError_WRes("cannot write output file", wres); + res = SZ_ERROR_FAIL; + break; + } + } + + { + FILETIME mtime; + FILETIME *mtimePtr = NULL; + + #ifdef USE_WINDOWS_FILE + FILETIME ctime; + FILETIME *ctimePtr = NULL; + #endif + + if (SzBitWithVals_Check(&db.MTime, i)) + { + const CNtfsFileTime *t = &db.MTime.Vals[i]; + mtime.dwLowDateTime = (DWORD)(t->Low); + mtime.dwHighDateTime = (DWORD)(t->High); + mtimePtr = &mtime; + } + + #ifdef USE_WINDOWS_FILE + if (SzBitWithVals_Check(&db.CTime, i)) + { + const CNtfsFileTime *t = &db.CTime.Vals[i]; + ctime.dwLowDateTime = (DWORD)(t->Low); + ctime.dwHighDateTime = (DWORD)(t->High); + ctimePtr = &ctime; + } + + if (mtimePtr || ctimePtr) + SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr); + #endif + + { + const WRes wres = File_Close(&outFile); + if (wres != 0) + { + PrintError_WRes("cannot close output file", wres); + res = SZ_ERROR_FAIL; + break; + } + } + + #ifndef USE_WINDOWS_FILE + #ifdef _WIN32 + mtimePtr = mtimePtr; + #else + if (mtimePtr) + Set_File_FILETIME(destPath, mtimePtr); + #endif + #endif + } + + #ifdef USE_WINDOWS_FILE + if (SzBitWithVals_Check(&db.Attribs, i)) + { + UInt32 attrib = db.Attribs.Vals[i]; + /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker. + We remove posix bits, if we detect posix mode field */ + if ((attrib & 0xF0000000) != 0) + attrib &= 0x7FFF; + SetFileAttributesW((LPCWSTR)destPath, attrib); + } + #endif + } + PrintLF(); + } + ISzAlloc_Free(&allocImp, outBuffer); + } + } + + SzFree(NULL, temp); + SzArEx_Free(&db, &allocImp); + ISzAlloc_Free(&allocImp, lookStream.buf); + + File_Close(&archiveStream.file); + + if (res == SZ_OK) + { + Print("\nEverything is Ok\n"); + return 0; + } + + if (res == SZ_ERROR_UNSUPPORTED) + PrintError("decoder doesn't support this archive"); + else if (res == SZ_ERROR_MEM) + PrintError("cannot allocate memory"); + else if (res == SZ_ERROR_CRC) + PrintError("CRC error"); + else if (res == SZ_ERROR_READ /* || archiveStream.Res != 0 */) + PrintError_WRes("Read Error", archiveStream.wres); + else + { + char s[32]; + UInt64ToStr((unsigned)res, s, 0); + PrintError(s); + } + + return 1; +} diff --git a/C/Util/7z/Precomp.c b/C/Util/7z/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/7z/Precomp.c +++ b/C/Util/7z/Precomp.c @@ -1,4 +1,4 @@ -/* Precomp.c -- StdAfx -2013-01-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" +/* Precomp.c -- StdAfx +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" diff --git a/C/Util/7z/Precomp.h b/C/Util/7z/Precomp.h index 52b87ea64..13a41eff2 100644 --- a/C/Util/7z/Precomp.h +++ b/C/Util/7z/Precomp.h @@ -1,13 +1,13 @@ -/* Precomp.h -- Precomp -2024-01-23 : Igor Pavlov : Public domain */ - -// #ifndef ZIP7_INC_PRECOMP_LOC_H -// #define ZIP7_INC_PRECOMP_LOC_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../Precomp.h" - -// #endif +/* Precomp.h -- Precomp +2024-01-23 : Igor Pavlov : Public domain */ + +// #ifndef ZIP7_INC_PRECOMP_LOC_H +// #define ZIP7_INC_PRECOMP_LOC_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../Precomp.h" + +// #endif diff --git a/C/Util/7z/makefile b/C/Util/7z/makefile index 168a6d14b..987f06561 100644 --- a/C/Util/7z/makefile +++ b/C/Util/7z/makefile @@ -1,44 +1,44 @@ -CFLAGS = $(CFLAGS) -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY - -PROG = 7zDec.exe - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zBuf.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zArcIn.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\Lzma2Dec.obj \ - $O\LzmaDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - -7Z_OBJS = \ - $O\7zMain.obj \ - -!include "../../../CPP/7zip/Crc.mak" -!include "../../../CPP/7zip/LzmaDec.mak" - -OBJS = \ - $O\Precomp.obj \ - $(7Z_OBJS) \ - $(C_OBJS) \ - $(ASM_OBJS) \ - -!include "../../../CPP/Build.mak" - -$(7Z_OBJS): $(*B).c - $(CCOMPL_USE) -$(C_OBJS): ../../$(*B).c - $(CCOMPL_USE) -$O\Precomp.obj: Precomp.c - $(CCOMPL_PCH) - -!include "../../Asm_c.mak" +CFLAGS = $(CFLAGS) -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY + +PROG = 7zDec.exe + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zBuf.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zArcIn.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\Lzma2Dec.obj \ + $O\LzmaDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + +7Z_OBJS = \ + $O\7zMain.obj \ + +!include "../../../CPP/7zip/Crc.mak" +!include "../../../CPP/7zip/LzmaDec.mak" + +OBJS = \ + $O\Precomp.obj \ + $(7Z_OBJS) \ + $(C_OBJS) \ + $(ASM_OBJS) \ + +!include "../../../CPP/Build.mak" + +$(7Z_OBJS): $(*B).c + $(CCOMPL_USE) +$(C_OBJS): ../../$(*B).c + $(CCOMPL_USE) +$O\Precomp.obj: Precomp.c + $(CCOMPL_PCH) + +!include "../../Asm_c.mak" diff --git a/C/Util/7z/makefile.gcc b/C/Util/7z/makefile.gcc index 0b8b713c7..f48d36211 100644 --- a/C/Util/7z/makefile.gcc +++ b/C/Util/7z/makefile.gcc @@ -1,32 +1,32 @@ -PROG = 7zdec - -LOCAL_FLAGS = -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY - -include ../../../CPP/7zip/LzmaDec_gcc.mak - - -OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $O/Bcj2.o \ - $O/Bra.o \ - $O/Bra86.o \ - $O/BraIA64.o \ - $O/CpuArch.o \ - $O/Delta.o \ - $O/Lzma2Dec.o \ - $O/LzmaDec.o \ - $O/Ppmd7.o \ - $O/Ppmd7Dec.o \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - $O/7zAlloc.o \ - $O/7zArcIn.o \ - $O/7zBuf.o \ - $O/7zBuf2.o \ - $O/7zDec.o \ - $O/7zMain.o \ - $O/7zFile.o \ - $O/7zStream.o \ - - -include ../../7zip_gcc_c.mak +PROG = 7zdec + +LOCAL_FLAGS = -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY + +include ../../../CPP/7zip/LzmaDec_gcc.mak + + +OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $O/Bcj2.o \ + $O/Bra.o \ + $O/Bra86.o \ + $O/BraIA64.o \ + $O/CpuArch.o \ + $O/Delta.o \ + $O/Lzma2Dec.o \ + $O/LzmaDec.o \ + $O/Ppmd7.o \ + $O/Ppmd7Dec.o \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + $O/7zAlloc.o \ + $O/7zArcIn.o \ + $O/7zBuf.o \ + $O/7zBuf2.o \ + $O/7zDec.o \ + $O/7zMain.o \ + $O/7zFile.o \ + $O/7zStream.o \ + + +include ../../7zip_gcc_c.mak diff --git a/C/Util/7zipInstall/7zipInstall.c b/C/Util/7zipInstall/7zipInstall.c index 9430c223d..7d8e8c42a 100644 --- a/C/Util/7zipInstall/7zipInstall.c +++ b/C/Util/7zipInstall/7zipInstall.c @@ -1,1699 +1,1699 @@ -/* 7zipInstall.c - 7-Zip Installer -2024-04-05 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#define SZ_ERROR_ABORT 100 - -#include "../../7zWindows.h" - -#if defined(_MSC_VER) && _MSC_VER < 1600 -#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union -#endif - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -#ifdef Z7_OLD_WIN_SDK -struct IShellView; -#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE -SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); -#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize -typedef enum { - SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists - SHGFP_TYPE_DEFAULT = 1, // default value, may not exist -} SHGFP_TYPE; -#endif -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../7z.h" -#include "../../7zAlloc.h" -#include "../../7zCrc.h" -#include "../../7zFile.h" -#include "../../7zVersion.h" -#include "../../CpuArch.h" -#include "../../DllSecur.h" - -#include "resource.h" - -#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__) - // #pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - -#define LLL_(quote) L##quote -#define LLL(quote) LLL_(quote) - -#define wcscat lstrcatW -#define wcslen (size_t)lstrlenW -#define wcscpy lstrcpyW -// wcsncpy() and lstrcpynW() work differently. We don't use them. - -#define kInputBufSize ((size_t)1 << 18) - -#define Z7_7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR) -#define Z7_7ZIP_DLL_VER_COMPAT ((16 << 16) | 3) - -static LPCSTR const k_7zip = "7-Zip"; - -static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip"; - -// #define Z7_64BIT_INSTALLER 1 - -#ifdef _WIN64 - #define Z7_64BIT_INSTALLER 1 -#endif - -#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION) - -#ifdef Z7_64BIT_INSTALLER - - // #define USE_7ZIP_32_DLL - - #if defined(_M_ARM64) || defined(_M_ARM) - #define k_Postfix L" (arm64)" - #else - #define k_Postfix L" (x64)" - #define USE_7ZIP_32_DLL - #endif -#else - #if defined(_M_ARM64) || defined(_M_ARM) - #define k_Postfix L" (arm)" - #else - // #define k_Postfix L" (x86)" - #define k_Postfix - #endif -#endif - -#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix - - -static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver; - -static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup"; - -static LPCWSTR const k_Reg_Path = L"Path"; - -static LPCWSTR const k_Reg_Path32 = L"Path" - #ifdef Z7_64BIT_INSTALLER - L"64" - #else - L"32" - #endif - ; - -#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64) - #define k_Reg_WOW_Flag KEY_WOW64_64KEY -#else - #define k_Reg_WOW_Flag 0 -#endif - -#ifdef USE_7ZIP_32_DLL -#ifdef _WIN64 - #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY -#else - #define k_Reg_WOW_Flag_32 0 -#endif -#endif - -#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}" - -static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; -static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32"; - -#define g_AllUsers True - -static BoolInt g_Install_was_Pressed; -static BoolInt g_Finished; -static BoolInt g_SilentMode; - -static HWND g_HWND; -static HWND g_Path_HWND; -static HWND g_InfoLine_HWND; -static HWND g_Progress_HWND; - -static DWORD g_TotalSize; - -static WCHAR cmd[MAX_PATH + 4]; -static WCHAR cmdError[MAX_PATH + 4]; -static WCHAR path[MAX_PATH * 2 + 40]; - - - -static void CpyAscii(wchar_t *dest, const char *s) -{ - for (;;) - { - Byte b = (Byte)*s++; - *dest++ = b; - if (b == 0) - return; - } -} - -static void CatAscii(wchar_t *dest, const char *s) -{ - dest += wcslen(dest); - CpyAscii(dest, s); -} - -static void PrintErrorMessage(const char *s1, const wchar_t *s2) -{ - WCHAR m[MAX_PATH + 512]; - m[0] = 0; - CatAscii(m, "ERROR:"); - if (s1) - { - CatAscii(m, "\n"); - CatAscii(m, s1); - } - if (s2) - { - CatAscii(m, "\n"); - wcscat(m, s2); - } - MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR | MB_OK); -} - - -typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle); -typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); -typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen); - -static HMODULE g_version_dll_hModule; - -static DWORD GetFileVersion(LPCWSTR s) -{ - DWORD size = 0; - void *vi = NULL; - DWORD version = 0; - - Func_GetFileVersionInfoSizeW my_GetFileVersionInfoSizeW; - Func_GetFileVersionInfoW my_GetFileVersionInfoW; - Func_VerQueryValueW my_VerQueryValueW; - - if (!g_version_dll_hModule) - { - wchar_t buf[MAX_PATH + 100]; - { - unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2); - if (len == 0 || len > MAX_PATH) - return 0; - } - { - unsigned pos = (unsigned)lstrlenW(buf); - if (buf[pos - 1] != '\\') - buf[pos++] = '\\'; - lstrcpyW(buf + pos, L"version.dll"); - } - g_version_dll_hModule = LoadLibraryW(buf); - if (!g_version_dll_hModule) - return 0; - } - - my_GetFileVersionInfoSizeW = (Func_GetFileVersionInfoSizeW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule, - "GetFileVersionInfoSizeW"); - my_GetFileVersionInfoW = (Func_GetFileVersionInfoW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule, - "GetFileVersionInfoW"); - my_VerQueryValueW = (Func_VerQueryValueW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule, - "VerQueryValueW"); - - if (!my_GetFileVersionInfoSizeW - || !my_GetFileVersionInfoW - || !my_VerQueryValueW) - return 0; - - size = my_GetFileVersionInfoSizeW(s, NULL); - if (size == 0) - return 0; - - vi = malloc(size); - if (!vi) - return 0; - - if (my_GetFileVersionInfoW(s, 0, size, vi)) - { - VS_FIXEDFILEINFO *fi = NULL; - UINT fiLen = 0; - if (my_VerQueryValueW(vi, L"\\", (LPVOID *)&fi, &fiLen)) - version = fi->dwFileVersionMS; - } - - free(vi); - return version; -} - - -static WRes MyCreateDir(LPCWSTR name) -{ - return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); -} - -#define IS_SEPAR(c) (c == WCHAR_PATH_SEPARATOR) -#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) -#define IS_DRIVE_PATH(s) (IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2])) - -static int ReverseFind_PathSepar(const wchar_t *s) -{ - int separ = -1; - int i; - for (i = 0;; i++) - { - wchar_t c = s[i]; - if (c == 0) - return separ; - if (IS_SEPAR(c)) - separ = i; - } -} - -static WRes CreateComplexDir(void) -{ - WCHAR s[MAX_PATH + 10]; - - unsigned prefixSize = 0; - WRes wres; - - { - size_t len = wcslen(path); - if (len > MAX_PATH) - return ERROR_INVALID_NAME; - wcscpy(s, path); - } - - if (IS_DRIVE_PATH(s)) - prefixSize = 3; - else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1])) - prefixSize = 2; - else - return ERROR_INVALID_NAME; - - { - DWORD attrib = GetFileAttributesW(s); - if (attrib != INVALID_FILE_ATTRIBUTES) - return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ? 0 : ERROR_ALREADY_EXISTS; - } - - wres = MyCreateDir(s); - if (wres == 0 || wres == ERROR_ALREADY_EXISTS) - return 0; - - { - size_t len = wcslen(s); - { - const int pos = ReverseFind_PathSepar(s); - if (pos < 0) - return wres; - if ((unsigned)pos < prefixSize) - return wres; - if ((unsigned)pos == len - 1) - { - if (len == 1) - return 0; - s[pos] = 0; - len = (unsigned)pos; - } - } - - for (;;) - { - int pos; - wres = MyCreateDir(s); - if (wres == 0) - break; - if (wres == ERROR_ALREADY_EXISTS) - { - const DWORD attrib = GetFileAttributesW(s); - if (attrib != INVALID_FILE_ATTRIBUTES) - if ((attrib & FILE_ATTRIBUTE_DIRECTORY) == 0) - return ERROR_ALREADY_EXISTS; - break; - } - pos = ReverseFind_PathSepar(s); - if (pos < 0 || pos == 0 || (unsigned)pos < prefixSize) - return wres; - s[pos] = 0; - } - - for (;;) - { - const size_t pos = wcslen(s); - if (pos >= len) - return 0; - s[pos] = CHAR_PATH_SEPARATOR; - wres = MyCreateDir(s); - if (wres != 0) - return wres; - } - } -} - - -static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest) -{ - DWORD cnt = MAX_PATH * sizeof(name[0]); - DWORD type = 0; - const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt); - if (type != REG_SZ) - return False; - return res == ERROR_SUCCESS; -} - -static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) -{ - HKEY key = 0; - const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); - if (res != ERROR_SUCCESS) - return False; - { - const BoolInt res2 = MyRegistry_QueryString(key, valName, dest); - RegCloseKey(key); - return res2; - } -} - -static LONG MyRegistry_SetString(HKEY hKey, LPCWSTR name, LPCWSTR val) -{ - return RegSetValueExW(hKey, name, 0, REG_SZ, - (const BYTE *)val, (DWORD)(wcslen(val) + 1) * sizeof(val[0])); -} - -static LONG MyRegistry_SetDWORD(HKEY hKey, LPCWSTR name, DWORD val) -{ - return RegSetValueExW(hKey, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(DWORD)); -} - - -static LONG MyRegistry_CreateKey(HKEY parentKey, LPCWSTR name, HKEY *destKey) -{ - return RegCreateKeyExW(parentKey, name, 0, NULL, - REG_OPTION_NON_VOLATILE, - KEY_ALL_ACCESS | k_Reg_WOW_Flag, - NULL, destKey, NULL); -} - -static LONG MyRegistry_CreateKeyAndVal(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val) -{ - HKEY destKey = 0; - LONG res = MyRegistry_CreateKey(parentKey, keyName, &destKey); - if (res == ERROR_SUCCESS) - { - res = MyRegistry_SetString(destKey, valName, val); - /* res = */ RegCloseKey(destKey); - } - return res; -} - - -#ifdef USE_7ZIP_32_DLL - -static LONG MyRegistry_CreateKey_32(HKEY parentKey, LPCWSTR name, HKEY *destKey) -{ - return RegCreateKeyExW(parentKey, name, 0, NULL, - REG_OPTION_NON_VOLATILE, - KEY_ALL_ACCESS | k_Reg_WOW_Flag_32, - NULL, destKey, NULL); -} - -static LONG MyRegistry_CreateKeyAndVal_32(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val) -{ - HKEY destKey = 0; - LONG res = MyRegistry_CreateKey_32(parentKey, keyName, &destKey); - if (res == ERROR_SUCCESS) - { - res = MyRegistry_SetString(destKey, valName, val); - /* res = */ RegCloseKey(destKey); - } - return res; -} - -#endif - - - -#ifdef UNDER_CE - #define kBufSize (1 << 13) -#else - #define kBufSize (1 << 15) -#endif - -#define kSignatureSearchLimit (1 << 22) - -static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos) -{ - Byte buf[kBufSize]; - size_t numPrevBytes = 0; - *resPos = 0; - - for (;;) - { - size_t processed, pos; - if (*resPos > kSignatureSearchLimit) - return False; - processed = kBufSize - numPrevBytes; - if (File_Read(stream, buf + numPrevBytes, &processed) != 0) - return False; - processed += numPrevBytes; - if (processed < k7zStartHeaderSize || - (processed == k7zStartHeaderSize && numPrevBytes != 0)) - return False; - processed -= k7zStartHeaderSize; - for (pos = 0; pos <= processed; pos++) - { - for (; pos <= processed && buf[pos] != '7'; pos++); - if (pos > processed) - break; - if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0) - if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8)) - { - *resPos += pos; - return True; - } - } - *resPos += processed; - numPrevBytes = k7zStartHeaderSize; - memmove(buf, buf + processed, k7zStartHeaderSize); - } -} - -static void HexToString(UInt32 val, WCHAR *s) -{ - UInt64 v = val; - unsigned i; - for (i = 1;; i++) - { - v >>= 4; - if (v == 0) - break; - } - s[i] = 0; - do - { - unsigned t = (unsigned)((val & 0xF)); - val >>= 4; - s[--i] = (WCHAR)(unsigned)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } - while (i); -} - - -#ifndef UNDER_CE - -static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM data) -{ - UNUSED_VAR(lp) - UNUSED_VAR(data) - UNUSED_VAR(hwnd) - - switch (uMsg) - { - case BFFM_INITIALIZED: - { - SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, data); - break; - } - case BFFM_SELCHANGED: - { - // show selected path for BIF_STATUSTEXT - WCHAR dir[MAX_PATH]; - if (!SHGetPathFromIDListW((LPITEMIDLIST)lp, dir)) - dir[0] = 0; - SendMessage(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir); - break; - } - default: - break; - } - return 0; -} - -static BoolInt MyBrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, - LPCWSTR initialFolder, LPWSTR resultPath) -{ - WCHAR displayName[MAX_PATH]; - BROWSEINFOW browseInfo; - - displayName[0] = 0; - browseInfo.hwndOwner = owner; - browseInfo.pidlRoot = NULL; - - // there are Unicode/Astring problems in some WinCE SDK ? - browseInfo.pszDisplayName = displayName; - browseInfo.lpszTitle = title; - browseInfo.ulFlags = ulFlags; - browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL; - browseInfo.lParam = (LPARAM)initialFolder; - { - LPITEMIDLIST idlist = SHBrowseForFolderW(&browseInfo); - if (idlist) - { - SHGetPathFromIDListW(idlist, resultPath); - // free idlist - // CoTaskMemFree(idlist); - return True; - } - return False; - } -} - -#endif - -static void NormalizePrefix(WCHAR *s) -{ - size_t i = 0; - - for (;; i++) - { - const wchar_t c = s[i]; - if (c == 0) - break; - if (c == '/') - s[i] = WCHAR_PATH_SEPARATOR; - } - - if (i != 0 && s[i - 1] != WCHAR_PATH_SEPARATOR) - { - s[i] = WCHAR_PATH_SEPARATOR; - s[i + 1] = 0; - } -} - -static char MyCharLower_Ascii(char c) -{ - if (c >= 'A' && c <= 'Z') - return (char)((unsigned char)c + 0x20); - return c; -} - -static wchar_t MyWCharLower_Ascii(wchar_t c) -{ - if (c >= 'A' && c <= 'Z') - return (wchar_t)(c + 0x20); - return c; -} - -static LPCWSTR FindSubString(LPCWSTR s1, const char *s2) -{ - for (;;) - { - unsigned i; - if (*s1 == 0) - return NULL; - for (i = 0;; i++) - { - const char b = s2[i]; - if (b == 0) - return s1; - if (MyWCharLower_Ascii(s1[i]) != (Byte)MyCharLower_Ascii(b)) - { - s1++; - break; - } - } - } -} - -static void Set7zipPostfix(WCHAR *s) -{ - NormalizePrefix(s); - if (FindSubString(s, "7-Zip")) - return; - CatAscii(s, "7-Zip\\"); -} - - -static int Install(void); - -static void OnClose(void) -{ - if (g_Install_was_Pressed && !g_Finished) - { - if (MessageBoxW(g_HWND, - L"Do you want to cancel " k_7zip_with_Ver L" installation?", - k_7zip_with_Ver, - MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) - return; - } - DestroyWindow(g_HWND); - g_HWND = NULL; -} - -static -#ifdef Z7_OLD_WIN_SDK - BOOL -#else - INT_PTR -#endif -CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - // UNUSED_VAR(hwnd) - UNUSED_VAR(lParam) - - switch (message) - { - case WM_INITDIALOG: - g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH); - g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE); - g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS); - - SetWindowTextW(hwnd, k_7zip_Setup); - SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path); - - ShowWindow(g_Progress_HWND, SW_HIDE); - ShowWindow(g_InfoLine_HWND, SW_HIDE); - - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - if (g_Finished) - { - OnClose(); - break; - } - if (!g_Install_was_Pressed) - { - SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE); - - EnableWindow(g_Path_HWND, FALSE); - EnableWindow(GetDlgItem(hwnd, IDB_EXTRACT_SET_PATH), FALSE); - EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); - - g_Install_was_Pressed = True; - return TRUE; - } - break; - } - - case IDCANCEL: - { - OnClose(); - break; - } - - case IDB_EXTRACT_SET_PATH: - { - #ifndef UNDER_CE - - WCHAR s[MAX_PATH]; - WCHAR s2[MAX_PATH]; - GetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s, MAX_PATH); - if (MyBrowseForFolder(hwnd, L"Select the folder for installation:" , - 0 - | BIF_NEWDIALOGSTYLE // 5.0 of ?.dll ? - | BIF_RETURNONLYFSDIRS - // | BIF_STATUSTEXT // doesn't work for BIF_NEWDIALOGSTYLE - , s, s2)) - { - Set7zipPostfix(s2); - SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s2); - } - - #endif - break; - } - - default: return FALSE; - } - break; - - case WM_CLOSE: - OnClose(); - break; - /* - case WM_DESTROY: - PostQuitMessage(0); - return TRUE; - */ - default: - return FALSE; - } - - return TRUE; -} - - - -static LONG SetRegKey_Path2(HKEY parentKey) -{ - HKEY destKey = 0; - LONG res = MyRegistry_CreateKey(parentKey, k_Reg_Software_7zip, &destKey); - if (res == ERROR_SUCCESS) - { - res = MyRegistry_SetString(destKey, k_Reg_Path32, path); - /* res = */ MyRegistry_SetString(destKey, k_Reg_Path, path); - /* res = */ RegCloseKey(destKey); - } - return res; -} - -static void SetRegKey_Path(void) -{ - SetRegKey_Path2(HKEY_CURRENT_USER); - SetRegKey_Path2(HKEY_LOCAL_MACHINE); -} - - -static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath) -{ - IShellLinkW* sl; - - // CoInitialize has already been called. - HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); - - if (SUCCEEDED(hres)) - { - IPersistFile* pf; - - sl->lpVtbl->SetPath(sl, targetPath); - // sl->lpVtbl->SetDescription(sl, description); - hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf); - - if (SUCCEEDED(hres)) - { - hres = pf->lpVtbl->Save(pf, srcPath, TRUE); - pf->lpVtbl->Release(pf); - } - sl->lpVtbl->Release(sl); - } - - return hres; -} - -static void SetShellProgramsGroup(HWND hwndOwner) -{ - #ifdef UNDER_CE - - // CpyAscii(link, "\\Program Files\\"); - UNUSED_VAR(hwndOwner) - - #else - - unsigned i = (g_AllUsers ? 0 : 2); - - for (; i < 3; i++) - { - BoolInt isOK = True; - WCHAR link[MAX_PATH + 40]; - WCHAR destPath[MAX_PATH + 40]; - - link[0] = 0; - - if (SHGetFolderPathW(hwndOwner, - i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, - NULL, SHGFP_TYPE_CURRENT, link) != S_OK) - continue; - - NormalizePrefix(link); - CatAscii(link, k_7zip); - // CatAscii(link, "2"); - - if (i != 0) - MyCreateDir(link); - - NormalizePrefix(link); - - { - unsigned baseLen = (unsigned)wcslen(link); - unsigned k; - - for (k = 0; k < 2; k++) - { - CpyAscii(link + baseLen, k == 0 ? - "7-Zip File Manager.lnk" : - "7-Zip Help.lnk" - ); - wcscpy(destPath, path); - CatAscii(destPath, k == 0 ? - "7zFM.exe" : - "7-zip.chm"); - - if (i == 0) - DeleteFileW(link); - else if (CreateShellLink(link, destPath) != S_OK) - isOK = False; - } - } - - if (i != 0 && isOK) - break; - } - - #endif -} - -static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; -static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension"; - -static void WriteCLSID(void) -{ - HKEY destKey; - LONG res; - - #ifdef USE_7ZIP_32_DLL - - MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension); - - res = MyRegistry_CreateKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey); - - if (res == ERROR_SUCCESS) - { - WCHAR destPath[MAX_PATH + 40]; - wcscpy(destPath, path); - CatAscii(destPath, "7-zip32.dll"); - /* res = */ MyRegistry_SetString(destKey, NULL, destPath); - /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment"); - // DeleteRegValue(destKey, L"InprocServer32"); - /* res = */ RegCloseKey(destKey); - } - - #endif - - - MyRegistry_CreateKeyAndVal(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension); - - destKey = 0; - res = MyRegistry_CreateKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey); - - if (res == ERROR_SUCCESS) - { - WCHAR destPath[MAX_PATH + 40]; - wcscpy(destPath, path); - CatAscii(destPath, "7-zip.dll"); - /* res = */ MyRegistry_SetString(destKey, NULL, destPath); - /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment"); - // DeleteRegValue(destKey, L"InprocServer32"); - /* res = */ RegCloseKey(destKey); - } -} - -static LPCSTR const k_ShellEx_Items[] = -{ - "*\\shellex\\ContextMenuHandlers" - , "Directory\\shellex\\ContextMenuHandlers" - , "Folder\\shellex\\ContextMenuHandlers" - , "Directory\\shellex\\DragDropHandlers" - , "Drive\\shellex\\DragDropHandlers" -}; - -static void WriteShellEx(void) -{ - unsigned i; - WCHAR destPath[MAX_PATH + 40]; - - for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++) - { - CpyAscii(destPath, k_ShellEx_Items[i]); - CatAscii(destPath, "\\7-Zip"); - - #ifdef USE_7ZIP_32_DLL - MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); - #endif - MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); - } - - #ifdef USE_7ZIP_32_DLL - MyRegistry_CreateKeyAndVal_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension); - #endif - MyRegistry_CreateKeyAndVal (HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension); - - - wcscpy(destPath, path); - CatAscii(destPath, "7zFM.exe"); - - { - HKEY destKey = 0; - LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey); - if (res == ERROR_SUCCESS) - { - MyRegistry_SetString(destKey, NULL, destPath); - MyRegistry_SetString(destKey, L"Path", path); - RegCloseKey(destKey); - } - - } - - { - HKEY destKey = 0; - LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\7-Zip", &destKey); - if (res == ERROR_SUCCESS) - { - MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str); - MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS)); - MyRegistry_SetString(destKey, L"DisplayIcon", destPath); - MyRegistry_SetString(destKey, L"InstallLocation", path); - - destPath[0] = '\"'; - wcscpy(destPath + 1, path); - CatAscii(destPath, "Uninstall.exe\""); - MyRegistry_SetString(destKey, L"UninstallString", destPath); - - CatAscii(destPath, " /S"); - MyRegistry_SetString(destKey, L"QuietUninstallString", destPath); - - MyRegistry_SetDWORD(destKey, L"NoModify", 1); - MyRegistry_SetDWORD(destKey, L"NoRepair", 1); - - MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10); - - MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR); - MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR); - - MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME)); - - // MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html"); - // MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/"); - // MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/"); - - RegCloseKey(destKey); - } - } -} - - -static const wchar_t *GetCmdParam(const wchar_t *s) -{ - unsigned pos = 0; - BoolInt quoteMode = False; - for (;; s++) - { - wchar_t c = *s; - if (c == 0 || (c == L' ' && !quoteMode)) - break; - if (c == L'\"') - { - quoteMode = !quoteMode; - continue; - } - if (pos >= Z7_ARRAY_SIZE(cmd) - 1) - exit(1); - cmd[pos++] = c; - } - cmd[pos] = 0; - return s; -} - - -static void RemoveQuotes(wchar_t *s) -{ - const wchar_t *src = s; - for (;;) - { - wchar_t c = *src++; - if (c == '\"') - continue; - *s++ = c; - if (c == 0) - return; - } -} - -// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') - - -typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); - -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - lpCmdLine, int nCmdShow) -{ - - UNUSED_VAR(hPrevInstance) - UNUSED_VAR(lpCmdLine) - UNUSED_VAR(nCmdShow) - - #ifndef UNDER_CE - LoadSecurityDlls(); - CoInitialize(NULL); - #endif - - CrcGenerateTable(); - - { - const wchar_t *s = GetCommandLineW(); - - #ifndef UNDER_CE - s = GetCmdParam(s); - #endif - - for (;;) - { - { - const wchar_t c = *s; - if (c == 0) - break; - if (c == ' ') - { - s++; - continue; - } - } - - { - const wchar_t *s2 = GetCmdParam(s); - BoolInt error = True; - if (cmd[0] == '/') - { - if (cmd[1] == 'S') - { - if (cmd[2] == 0) - { - g_SilentMode = True; - error = False; - } - } - else if (cmd[1] == 'D' && cmd[2] == '=') - { - wcscpy(path, cmd + 3); - // RemoveQuotes(path); - error = False; - } - } - s = s2; - if (error && cmdError[0] == 0) - wcscpy(cmdError, cmd); - } - } - - if (cmdError[0] != 0) - { - if (!g_SilentMode) - PrintErrorMessage("Unsupported command:", cmdError); - return 1; - } - } - - #if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64) - { - BOOL isWow64 = FALSE; - const Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process) - Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"kernel32.dll"), - "IsWow64Process"); - - if (func_IsWow64Process) - func_IsWow64Process(GetCurrentProcess(), &isWow64); - - if (!isWow64) - { - if (!g_SilentMode) - PrintErrorMessage("This installation requires Windows " - #ifdef MY_CPU_X86_OR_AMD64 - "x64" - #else - "64-bit" - #endif - , NULL); - return 1; - } - } - #endif - - - if (path[0] == 0) - { - HKEY key = 0; - BoolInt ok = False; - const LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key); - if (res == ERROR_SUCCESS) - { - ok = MyRegistry_QueryString(key, k_Reg_Path32, path); - // ok = MyRegistry_QueryString(key, k_Reg_Path, path); - RegCloseKey(key); - } - - // ok = False; - if (!ok) - { - /* - #ifdef UNDER_CE - CpyAscii(path, "\\Program Files\\"); - #else - - #ifdef Z7_64BIT_INSTALLER - { - DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH); - if (ttt == 0 || ttt > MAX_PATH) - CpyAscii(path, "C:\\"); - } - #else - if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE)) - CpyAscii(path, "C:\\"); - #endif - #endif - */ - if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path)) - CpyAscii(path, - #ifdef UNDER_CE - "\\Program Files\\" - #else - "C:\\" - #endif - ); - - Set7zipPostfix(path); - } - } - - NormalizePrefix(path); - - if (g_SilentMode) - return Install(); - - { - int retCode = 1; - // INT_PTR res = DialogBox( - g_HWND = CreateDialog( - hInstance, - // GetModuleHandle(NULL), - MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc); - if (!g_HWND) - return 1; - - { - const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); - // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); - SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); - } - - - { - BOOL bRet; - MSG msg; - - // we need messages for all thread windows (including EDITTEXT window in dialog) - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) - { - if (bRet == -1) - return retCode; - if (!g_HWND) - return retCode; - - if (!IsDialogMessage(g_HWND, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - if (!g_HWND) - return retCode; - - if (g_Install_was_Pressed && !g_Finished) - { - retCode = Install(); - g_Finished = True; - if (retCode != 0) - break; - if (!g_HWND) - break; - { - SetDlgItemTextW(g_HWND, IDOK, L"Close"); - EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE); - EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE); - SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE); - } - } - } - - if (g_HWND) - { - DestroyWindow(g_HWND); - g_HWND = NULL; - } - } - - return retCode; - } -} - - -static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message) -{ - LPWSTR msgBuf; - if (FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) - return False; - wcscpy(message, msgBuf); - LocalFree(msgBuf); - return True; -} - - - -static int Install(void) -{ - CFileInStream archiveStream; - CLookToRead2 lookStream; - CSzArEx db; - - SRes res = SZ_OK; - WRes winRes = 0; - const char *errorMessage = NULL; - - ISzAlloc allocImp; - ISzAlloc allocTempImp; - WCHAR sfxPath[MAX_PATH + 2]; - - int needRebootLevel = 0; - - allocImp.Alloc = SzAlloc; - allocImp.Free = SzFree; - - allocTempImp.Alloc = SzAllocTemp; - allocTempImp.Free = SzFreeTemp; - - { - const DWORD len = GetModuleFileNameW(NULL, sfxPath, MAX_PATH); - if (len == 0 || len > MAX_PATH) - return 1; - } - - winRes = InFile_OpenW(&archiveStream.file, sfxPath); - - if (winRes == 0) - { - UInt64 pos = 0; - if (!FindSignature(&archiveStream.file, &pos)) - errorMessage = "Can't find 7z archive"; - else - winRes = File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET); - } - - if (winRes != 0) - res = SZ_ERROR_FAIL; - - if (errorMessage) - res = SZ_ERROR_FAIL; - -if (res == SZ_OK) -{ - size_t pathLen; - if (!g_SilentMode) - { - GetDlgItemTextW(g_HWND, IDE_EXTRACT_PATH, path, MAX_PATH); - } - - FileInStream_CreateVTable(&archiveStream); - LookToRead2_CreateVTable(&lookStream, False); - lookStream.buf = NULL; - - RemoveQuotes(path); - { - // Remove post spaces - unsigned endPos = 0; - unsigned i = 0; - - for (;;) - { - const wchar_t c = path[i++]; - if (c == 0) - break; - if (c != ' ') - endPos = i; - } - - path[endPos] = 0; - if (path[0] == 0) - { - PrintErrorMessage("Incorrect path", NULL); - return 1; - } - } - - NormalizePrefix(path); - winRes = CreateComplexDir(); - - if (winRes != 0) - res = SZ_ERROR_FAIL; - - pathLen = wcslen(path); - - if (res == SZ_OK) - { - lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); - if (!lookStream.buf) - res = SZ_ERROR_MEM; - else - { - lookStream.bufSize = kInputBufSize; - lookStream.realStream = &archiveStream.vt; - LookToRead2_INIT(&lookStream) - } - } - - SzArEx_Init(&db); - - if (res == SZ_OK) - { - res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); - } - - if (res == SZ_OK) - { - UInt32 i; - UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if (!outBuf) */ - Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */ - size_t outBufSize = 0; /* it can have any value before first call, if (!outBuf) */ - - g_TotalSize = 0; - - if (!g_SilentMode) - { - ShowWindow(g_Progress_HWND, SW_SHOW); - ShowWindow(g_InfoLine_HWND, SW_SHOW); - SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, db.NumFiles); - } - - for (i = 0; i < db.NumFiles; i++) - { - size_t offset = 0; - size_t outSizeProcessed = 0; - WCHAR *temp; - - if (!g_SilentMode) - { - MSG msg; - - // g_HWND - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (!IsDialogMessage(g_HWND, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - if (!g_HWND) - return 1; - } - - // Sleep(10); - SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); - } - - { - const size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL); - if (len >= MAX_PATH) - { - res = SZ_ERROR_FAIL; - break; - } - } - - temp = path + pathLen; - - SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp); - - if (!g_SilentMode) - SetWindowTextW(g_InfoLine_HWND, temp); - - { - res = SzArEx_Extract(&db, &lookStream.vt, i, - &blockIndex, &outBuf, &outBufSize, - &offset, &outSizeProcessed, - &allocImp, &allocTempImp); - if (res != SZ_OK) - break; - } - - { - CSzFile outFile; - size_t processedSize; - size_t j; - // size_t nameStartPos = 0; - UInt32 tempIndex = 0; - int fileLevel = 1 << 2; - WCHAR origPath[MAX_PATH * 2 + 10]; - - for (j = 0; temp[j] != 0; j++) - { - if (temp[j] == '/') - { - temp[j] = 0; - MyCreateDir(path); - temp[j] = CHAR_PATH_SEPARATOR; - // nameStartPos = j + 1; - } - } - - if (SzArEx_IsDir(&db, i)) - { - MyCreateDir(path); - continue; - } - - { - // BoolInt skipFile = False; - - wcscpy(origPath, path); - - for (;;) - { - WRes openRes; - - if (tempIndex != 0) - { - if (tempIndex > 100) - { - res = SZ_ERROR_FAIL; - break; - } - wcscpy(path, origPath); - CatAscii(path, ".tmp"); - if (tempIndex > 1) - HexToString(tempIndex, path + wcslen(path)); - if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) - { - tempIndex++; - continue; - } - } - - { - SetFileAttributesW(path, 0); - openRes = OutFile_OpenW(&outFile, path); - if (openRes == 0) - break; - } - - if (tempIndex != 0) - { - tempIndex++; - continue; - } - - if (FindSubString(temp, "7-zip.dll") - #ifdef USE_7ZIP_32_DLL - || FindSubString(temp, "7-zip32.dll") - #endif - ) - { - const DWORD ver = GetFileVersion(path); - fileLevel = ((ver < Z7_7ZIP_DLL_VER_COMPAT || ver > Z7_7ZIP_CUR_VER) ? 2 : 1); - tempIndex++; - continue; - } - - if (g_SilentMode) - { - tempIndex++; - continue; - } - { - WCHAR message[MAX_PATH * 3 + 100]; - int mbRes; - - CpyAscii(message, "Can't open file\n"); - wcscat(message, path); - CatAscii(message, "\n"); - - GetErrorMessage(openRes, message + wcslen(message)); - - mbRes = MessageBoxW(g_HWND, message, L"Error", MB_ICONERROR | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3); - if (mbRes == IDABORT) - { - res = SZ_ERROR_ABORT; - tempIndex = 0; - break; - } - if (mbRes == IDIGNORE) - { - // skipFile = True; - tempIndex++; - } - } - } - - if (res != SZ_OK) - break; - - /* - if (skipFile) - continue; - */ - } - - // if (res == SZ_OK) - { - processedSize = outSizeProcessed; - winRes = File_Write(&outFile, outBuf + offset, &processedSize); - if (winRes != 0 || processedSize != outSizeProcessed) - { - errorMessage = "Can't write output file"; - res = SZ_ERROR_FAIL; - } - - g_TotalSize += (DWORD)outSizeProcessed; - - #ifdef USE_WINDOWS_FILE - if (SzBitWithVals_Check(&db.MTime, i)) - { - const CNtfsFileTime *t = db.MTime.Vals + i; - FILETIME mTime; - mTime.dwLowDateTime = t->Low; - mTime.dwHighDateTime = t->High; - SetFileTime(outFile.handle, NULL, NULL, &mTime); - } - #endif - - { - const WRes winRes2 = File_Close(&outFile); - if (res != SZ_OK) - break; - if (winRes2 != 0) - { - winRes = winRes2; - break; - } - } - - #ifdef USE_WINDOWS_FILE - if (SzBitWithVals_Check(&db.Attribs, i)) - SetFileAttributesW(path, db.Attribs.Vals[i]); - #endif - } - - if (tempIndex != 0) - { - // is it supported at win2000 ? - #ifndef UNDER_CE - if (!MoveFileExW(path, origPath, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING)) - { - winRes = GetLastError(); - break; - } - needRebootLevel |= fileLevel; - #endif - } - - } - } - - ISzAlloc_Free(&allocImp, outBuf); - - if (!g_SilentMode) - SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); - - path[pathLen] = 0; - - if (i == db.NumFiles) - { - SetRegKey_Path(); - WriteCLSID(); - WriteShellEx(); - - SetShellProgramsGroup(g_HWND); - if (!g_SilentMode) - SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is installed"); - } - } - - SzArEx_Free(&db, &allocImp); - - ISzAlloc_Free(&allocImp, lookStream.buf); - - File_Close(&archiveStream.file); - -} - - if (winRes != 0) - res = SZ_ERROR_FAIL; - - if (res == SZ_OK) - { - if (!g_SilentMode && needRebootLevel > 1) - { - if (MessageBoxW(g_HWND, L"You must restart your system to complete the installation.\nRestart now?", - k_7zip_Setup, MB_YESNO | MB_DEFBUTTON2) == IDYES) - { - #ifndef UNDER_CE - - // Get a token for this process. - HANDLE hToken; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) - { - TOKEN_PRIVILEGES tkp; - // Get the LUID for the shutdown privilege. - LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); - tkp.PrivilegeCount = 1; // one privilege to set - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - // Get the shutdown privilege for this process. - AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); - - if (GetLastError() == ERROR_SUCCESS) - { - if (!ExitWindowsEx(EWX_REBOOT, 0)) - { - } - } - } - - #endif - } - } - - if (res == SZ_OK) - return 0; - } - - if (!g_SilentMode) - { - if (winRes != 0) - { - WCHAR m[MAX_PATH + 100]; - m[0] = 0; - GetErrorMessage(winRes, m); - PrintErrorMessage(NULL, m); - } - else - { - if (res == SZ_ERROR_ABORT) - return 2; - - if (res == SZ_ERROR_UNSUPPORTED) - errorMessage = "Decoder doesn't support this archive"; - else if (res == SZ_ERROR_MEM) - errorMessage = "Can't allocate required memory"; - else if (res == SZ_ERROR_CRC) - errorMessage = "CRC error"; - else if (res == SZ_ERROR_DATA) - errorMessage = "Data error"; - - if (!errorMessage) - errorMessage = "ERROR"; - PrintErrorMessage(errorMessage, NULL); - } - } - - return 1; -} +/* 7zipInstall.c - 7-Zip Installer +2024-04-05 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#define SZ_ERROR_ABORT 100 + +#include "../../7zWindows.h" + +#if defined(_MSC_VER) && _MSC_VER < 1600 +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union +#endif + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +#ifdef Z7_OLD_WIN_SDK +struct IShellView; +#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE +SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); +#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize +typedef enum { + SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists + SHGFP_TYPE_DEFAULT = 1, // default value, may not exist +} SHGFP_TYPE; +#endif +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../7z.h" +#include "../../7zAlloc.h" +#include "../../7zCrc.h" +#include "../../7zFile.h" +#include "../../7zVersion.h" +#include "../../CpuArch.h" +#include "../../DllSecur.h" + +#include "resource.h" + +#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__) + // #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +#define LLL_(quote) L##quote +#define LLL(quote) LLL_(quote) + +#define wcscat lstrcatW +#define wcslen (size_t)lstrlenW +#define wcscpy lstrcpyW +// wcsncpy() and lstrcpynW() work differently. We don't use them. + +#define kInputBufSize ((size_t)1 << 18) + +#define Z7_7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR) +#define Z7_7ZIP_DLL_VER_COMPAT ((16 << 16) | 3) + +static LPCSTR const k_7zip = "7-Zip"; + +static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip"; + +// #define Z7_64BIT_INSTALLER 1 + +#ifdef _WIN64 + #define Z7_64BIT_INSTALLER 1 +#endif + +#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION) + +#ifdef Z7_64BIT_INSTALLER + + // #define USE_7ZIP_32_DLL + + #if defined(_M_ARM64) || defined(_M_ARM) + #define k_Postfix L" (arm64)" + #else + #define k_Postfix L" (x64)" + #define USE_7ZIP_32_DLL + #endif +#else + #if defined(_M_ARM64) || defined(_M_ARM) + #define k_Postfix L" (arm)" + #else + // #define k_Postfix L" (x86)" + #define k_Postfix + #endif +#endif + +#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix + + +static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver; + +static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup"; + +static LPCWSTR const k_Reg_Path = L"Path"; + +static LPCWSTR const k_Reg_Path32 = L"Path" + #ifdef Z7_64BIT_INSTALLER + L"64" + #else + L"32" + #endif + ; + +#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64) + #define k_Reg_WOW_Flag KEY_WOW64_64KEY +#else + #define k_Reg_WOW_Flag 0 +#endif + +#ifdef USE_7ZIP_32_DLL +#ifdef _WIN64 + #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY +#else + #define k_Reg_WOW_Flag_32 0 +#endif +#endif + +#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}" + +static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; +static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32"; + +#define g_AllUsers True + +static BoolInt g_Install_was_Pressed; +static BoolInt g_Finished; +static BoolInt g_SilentMode; + +static HWND g_HWND; +static HWND g_Path_HWND; +static HWND g_InfoLine_HWND; +static HWND g_Progress_HWND; + +static DWORD g_TotalSize; + +static WCHAR cmd[MAX_PATH + 4]; +static WCHAR cmdError[MAX_PATH + 4]; +static WCHAR path[MAX_PATH * 2 + 40]; + + + +static void CpyAscii(wchar_t *dest, const char *s) +{ + for (;;) + { + Byte b = (Byte)*s++; + *dest++ = b; + if (b == 0) + return; + } +} + +static void CatAscii(wchar_t *dest, const char *s) +{ + dest += wcslen(dest); + CpyAscii(dest, s); +} + +static void PrintErrorMessage(const char *s1, const wchar_t *s2) +{ + WCHAR m[MAX_PATH + 512]; + m[0] = 0; + CatAscii(m, "ERROR:"); + if (s1) + { + CatAscii(m, "\n"); + CatAscii(m, s1); + } + if (s2) + { + CatAscii(m, "\n"); + wcscat(m, s2); + } + MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR | MB_OK); +} + + +typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle); +typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); +typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen); + +static HMODULE g_version_dll_hModule; + +static DWORD GetFileVersion(LPCWSTR s) +{ + DWORD size = 0; + void *vi = NULL; + DWORD version = 0; + + Func_GetFileVersionInfoSizeW my_GetFileVersionInfoSizeW; + Func_GetFileVersionInfoW my_GetFileVersionInfoW; + Func_VerQueryValueW my_VerQueryValueW; + + if (!g_version_dll_hModule) + { + wchar_t buf[MAX_PATH + 100]; + { + unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2); + if (len == 0 || len > MAX_PATH) + return 0; + } + { + unsigned pos = (unsigned)lstrlenW(buf); + if (buf[pos - 1] != '\\') + buf[pos++] = '\\'; + lstrcpyW(buf + pos, L"version.dll"); + } + g_version_dll_hModule = LoadLibraryW(buf); + if (!g_version_dll_hModule) + return 0; + } + + my_GetFileVersionInfoSizeW = (Func_GetFileVersionInfoSizeW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule, + "GetFileVersionInfoSizeW"); + my_GetFileVersionInfoW = (Func_GetFileVersionInfoW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule, + "GetFileVersionInfoW"); + my_VerQueryValueW = (Func_VerQueryValueW) Z7_CAST_FUNC_C GetProcAddress(g_version_dll_hModule, + "VerQueryValueW"); + + if (!my_GetFileVersionInfoSizeW + || !my_GetFileVersionInfoW + || !my_VerQueryValueW) + return 0; + + size = my_GetFileVersionInfoSizeW(s, NULL); + if (size == 0) + return 0; + + vi = malloc(size); + if (!vi) + return 0; + + if (my_GetFileVersionInfoW(s, 0, size, vi)) + { + VS_FIXEDFILEINFO *fi = NULL; + UINT fiLen = 0; + if (my_VerQueryValueW(vi, L"\\", (LPVOID *)&fi, &fiLen)) + version = fi->dwFileVersionMS; + } + + free(vi); + return version; +} + + +static WRes MyCreateDir(LPCWSTR name) +{ + return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); +} + +#define IS_SEPAR(c) (c == WCHAR_PATH_SEPARATOR) +#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) +#define IS_DRIVE_PATH(s) (IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2])) + +static int ReverseFind_PathSepar(const wchar_t *s) +{ + int separ = -1; + int i; + for (i = 0;; i++) + { + wchar_t c = s[i]; + if (c == 0) + return separ; + if (IS_SEPAR(c)) + separ = i; + } +} + +static WRes CreateComplexDir(void) +{ + WCHAR s[MAX_PATH + 10]; + + unsigned prefixSize = 0; + WRes wres; + + { + size_t len = wcslen(path); + if (len > MAX_PATH) + return ERROR_INVALID_NAME; + wcscpy(s, path); + } + + if (IS_DRIVE_PATH(s)) + prefixSize = 3; + else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1])) + prefixSize = 2; + else + return ERROR_INVALID_NAME; + + { + DWORD attrib = GetFileAttributesW(s); + if (attrib != INVALID_FILE_ATTRIBUTES) + return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ? 0 : ERROR_ALREADY_EXISTS; + } + + wres = MyCreateDir(s); + if (wres == 0 || wres == ERROR_ALREADY_EXISTS) + return 0; + + { + size_t len = wcslen(s); + { + const int pos = ReverseFind_PathSepar(s); + if (pos < 0) + return wres; + if ((unsigned)pos < prefixSize) + return wres; + if ((unsigned)pos == len - 1) + { + if (len == 1) + return 0; + s[pos] = 0; + len = (unsigned)pos; + } + } + + for (;;) + { + int pos; + wres = MyCreateDir(s); + if (wres == 0) + break; + if (wres == ERROR_ALREADY_EXISTS) + { + const DWORD attrib = GetFileAttributesW(s); + if (attrib != INVALID_FILE_ATTRIBUTES) + if ((attrib & FILE_ATTRIBUTE_DIRECTORY) == 0) + return ERROR_ALREADY_EXISTS; + break; + } + pos = ReverseFind_PathSepar(s); + if (pos < 0 || pos == 0 || (unsigned)pos < prefixSize) + return wres; + s[pos] = 0; + } + + for (;;) + { + const size_t pos = wcslen(s); + if (pos >= len) + return 0; + s[pos] = CHAR_PATH_SEPARATOR; + wres = MyCreateDir(s); + if (wres != 0) + return wres; + } + } +} + + +static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest) +{ + DWORD cnt = MAX_PATH * sizeof(name[0]); + DWORD type = 0; + const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt); + if (type != REG_SZ) + return False; + return res == ERROR_SUCCESS; +} + +static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) +{ + HKEY key = 0; + const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); + if (res != ERROR_SUCCESS) + return False; + { + const BoolInt res2 = MyRegistry_QueryString(key, valName, dest); + RegCloseKey(key); + return res2; + } +} + +static LONG MyRegistry_SetString(HKEY hKey, LPCWSTR name, LPCWSTR val) +{ + return RegSetValueExW(hKey, name, 0, REG_SZ, + (const BYTE *)val, (DWORD)(wcslen(val) + 1) * sizeof(val[0])); +} + +static LONG MyRegistry_SetDWORD(HKEY hKey, LPCWSTR name, DWORD val) +{ + return RegSetValueExW(hKey, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(DWORD)); +} + + +static LONG MyRegistry_CreateKey(HKEY parentKey, LPCWSTR name, HKEY *destKey) +{ + return RegCreateKeyExW(parentKey, name, 0, NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS | k_Reg_WOW_Flag, + NULL, destKey, NULL); +} + +static LONG MyRegistry_CreateKeyAndVal(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val) +{ + HKEY destKey = 0; + LONG res = MyRegistry_CreateKey(parentKey, keyName, &destKey); + if (res == ERROR_SUCCESS) + { + res = MyRegistry_SetString(destKey, valName, val); + /* res = */ RegCloseKey(destKey); + } + return res; +} + + +#ifdef USE_7ZIP_32_DLL + +static LONG MyRegistry_CreateKey_32(HKEY parentKey, LPCWSTR name, HKEY *destKey) +{ + return RegCreateKeyExW(parentKey, name, 0, NULL, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS | k_Reg_WOW_Flag_32, + NULL, destKey, NULL); +} + +static LONG MyRegistry_CreateKeyAndVal_32(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val) +{ + HKEY destKey = 0; + LONG res = MyRegistry_CreateKey_32(parentKey, keyName, &destKey); + if (res == ERROR_SUCCESS) + { + res = MyRegistry_SetString(destKey, valName, val); + /* res = */ RegCloseKey(destKey); + } + return res; +} + +#endif + + + +#ifdef UNDER_CE + #define kBufSize (1 << 13) +#else + #define kBufSize (1 << 15) +#endif + +#define kSignatureSearchLimit (1 << 22) + +static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos) +{ + Byte buf[kBufSize]; + size_t numPrevBytes = 0; + *resPos = 0; + + for (;;) + { + size_t processed, pos; + if (*resPos > kSignatureSearchLimit) + return False; + processed = kBufSize - numPrevBytes; + if (File_Read(stream, buf + numPrevBytes, &processed) != 0) + return False; + processed += numPrevBytes; + if (processed < k7zStartHeaderSize || + (processed == k7zStartHeaderSize && numPrevBytes != 0)) + return False; + processed -= k7zStartHeaderSize; + for (pos = 0; pos <= processed; pos++) + { + for (; pos <= processed && buf[pos] != '7'; pos++); + if (pos > processed) + break; + if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0) + if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8)) + { + *resPos += pos; + return True; + } + } + *resPos += processed; + numPrevBytes = k7zStartHeaderSize; + memmove(buf, buf + processed, k7zStartHeaderSize); + } +} + +static void HexToString(UInt32 val, WCHAR *s) +{ + UInt64 v = val; + unsigned i; + for (i = 1;; i++) + { + v >>= 4; + if (v == 0) + break; + } + s[i] = 0; + do + { + unsigned t = (unsigned)((val & 0xF)); + val >>= 4; + s[--i] = (WCHAR)(unsigned)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } + while (i); +} + + +#ifndef UNDER_CE + +static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM data) +{ + UNUSED_VAR(lp) + UNUSED_VAR(data) + UNUSED_VAR(hwnd) + + switch (uMsg) + { + case BFFM_INITIALIZED: + { + SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, data); + break; + } + case BFFM_SELCHANGED: + { + // show selected path for BIF_STATUSTEXT + WCHAR dir[MAX_PATH]; + if (!SHGetPathFromIDListW((LPITEMIDLIST)lp, dir)) + dir[0] = 0; + SendMessage(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir); + break; + } + default: + break; + } + return 0; +} + +static BoolInt MyBrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, + LPCWSTR initialFolder, LPWSTR resultPath) +{ + WCHAR displayName[MAX_PATH]; + BROWSEINFOW browseInfo; + + displayName[0] = 0; + browseInfo.hwndOwner = owner; + browseInfo.pidlRoot = NULL; + + // there are Unicode/Astring problems in some WinCE SDK ? + browseInfo.pszDisplayName = displayName; + browseInfo.lpszTitle = title; + browseInfo.ulFlags = ulFlags; + browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL; + browseInfo.lParam = (LPARAM)initialFolder; + { + LPITEMIDLIST idlist = SHBrowseForFolderW(&browseInfo); + if (idlist) + { + SHGetPathFromIDListW(idlist, resultPath); + // free idlist + // CoTaskMemFree(idlist); + return True; + } + return False; + } +} + +#endif + +static void NormalizePrefix(WCHAR *s) +{ + size_t i = 0; + + for (;; i++) + { + const wchar_t c = s[i]; + if (c == 0) + break; + if (c == '/') + s[i] = WCHAR_PATH_SEPARATOR; + } + + if (i != 0 && s[i - 1] != WCHAR_PATH_SEPARATOR) + { + s[i] = WCHAR_PATH_SEPARATOR; + s[i + 1] = 0; + } +} + +static char MyCharLower_Ascii(char c) +{ + if (c >= 'A' && c <= 'Z') + return (char)((unsigned char)c + 0x20); + return c; +} + +static wchar_t MyWCharLower_Ascii(wchar_t c) +{ + if (c >= 'A' && c <= 'Z') + return (wchar_t)(c + 0x20); + return c; +} + +static LPCWSTR FindSubString(LPCWSTR s1, const char *s2) +{ + for (;;) + { + unsigned i; + if (*s1 == 0) + return NULL; + for (i = 0;; i++) + { + const char b = s2[i]; + if (b == 0) + return s1; + if (MyWCharLower_Ascii(s1[i]) != (Byte)MyCharLower_Ascii(b)) + { + s1++; + break; + } + } + } +} + +static void Set7zipPostfix(WCHAR *s) +{ + NormalizePrefix(s); + if (FindSubString(s, "7-Zip")) + return; + CatAscii(s, "7-Zip\\"); +} + + +static int Install(void); + +static void OnClose(void) +{ + if (g_Install_was_Pressed && !g_Finished) + { + if (MessageBoxW(g_HWND, + L"Do you want to cancel " k_7zip_with_Ver L" installation?", + k_7zip_with_Ver, + MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) + return; + } + DestroyWindow(g_HWND); + g_HWND = NULL; +} + +static +#ifdef Z7_OLD_WIN_SDK + BOOL +#else + INT_PTR +#endif +CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + // UNUSED_VAR(hwnd) + UNUSED_VAR(lParam) + + switch (message) + { + case WM_INITDIALOG: + g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH); + g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE); + g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS); + + SetWindowTextW(hwnd, k_7zip_Setup); + SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path); + + ShowWindow(g_Progress_HWND, SW_HIDE); + ShowWindow(g_InfoLine_HWND, SW_HIDE); + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + if (g_Finished) + { + OnClose(); + break; + } + if (!g_Install_was_Pressed) + { + SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE); + + EnableWindow(g_Path_HWND, FALSE); + EnableWindow(GetDlgItem(hwnd, IDB_EXTRACT_SET_PATH), FALSE); + EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); + + g_Install_was_Pressed = True; + return TRUE; + } + break; + } + + case IDCANCEL: + { + OnClose(); + break; + } + + case IDB_EXTRACT_SET_PATH: + { + #ifndef UNDER_CE + + WCHAR s[MAX_PATH]; + WCHAR s2[MAX_PATH]; + GetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s, MAX_PATH); + if (MyBrowseForFolder(hwnd, L"Select the folder for installation:" , + 0 + | BIF_NEWDIALOGSTYLE // 5.0 of ?.dll ? + | BIF_RETURNONLYFSDIRS + // | BIF_STATUSTEXT // doesn't work for BIF_NEWDIALOGSTYLE + , s, s2)) + { + Set7zipPostfix(s2); + SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s2); + } + + #endif + break; + } + + default: return FALSE; + } + break; + + case WM_CLOSE: + OnClose(); + break; + /* + case WM_DESTROY: + PostQuitMessage(0); + return TRUE; + */ + default: + return FALSE; + } + + return TRUE; +} + + + +static LONG SetRegKey_Path2(HKEY parentKey) +{ + HKEY destKey = 0; + LONG res = MyRegistry_CreateKey(parentKey, k_Reg_Software_7zip, &destKey); + if (res == ERROR_SUCCESS) + { + res = MyRegistry_SetString(destKey, k_Reg_Path32, path); + /* res = */ MyRegistry_SetString(destKey, k_Reg_Path, path); + /* res = */ RegCloseKey(destKey); + } + return res; +} + +static void SetRegKey_Path(void) +{ + SetRegKey_Path2(HKEY_CURRENT_USER); + SetRegKey_Path2(HKEY_LOCAL_MACHINE); +} + + +static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath) +{ + IShellLinkW* sl; + + // CoInitialize has already been called. + HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); + + if (SUCCEEDED(hres)) + { + IPersistFile* pf; + + sl->lpVtbl->SetPath(sl, targetPath); + // sl->lpVtbl->SetDescription(sl, description); + hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf); + + if (SUCCEEDED(hres)) + { + hres = pf->lpVtbl->Save(pf, srcPath, TRUE); + pf->lpVtbl->Release(pf); + } + sl->lpVtbl->Release(sl); + } + + return hres; +} + +static void SetShellProgramsGroup(HWND hwndOwner) +{ + #ifdef UNDER_CE + + // CpyAscii(link, "\\Program Files\\"); + UNUSED_VAR(hwndOwner) + + #else + + unsigned i = (g_AllUsers ? 0 : 2); + + for (; i < 3; i++) + { + BoolInt isOK = True; + WCHAR link[MAX_PATH + 40]; + WCHAR destPath[MAX_PATH + 40]; + + link[0] = 0; + + if (SHGetFolderPathW(hwndOwner, + i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, + NULL, SHGFP_TYPE_CURRENT, link) != S_OK) + continue; + + NormalizePrefix(link); + CatAscii(link, k_7zip); + // CatAscii(link, "2"); + + if (i != 0) + MyCreateDir(link); + + NormalizePrefix(link); + + { + unsigned baseLen = (unsigned)wcslen(link); + unsigned k; + + for (k = 0; k < 2; k++) + { + CpyAscii(link + baseLen, k == 0 ? + "7-Zip File Manager.lnk" : + "7-Zip Help.lnk" + ); + wcscpy(destPath, path); + CatAscii(destPath, k == 0 ? + "7zFM.exe" : + "7-zip.chm"); + + if (i == 0) + DeleteFileW(link); + else if (CreateShellLink(link, destPath) != S_OK) + isOK = False; + } + } + + if (i != 0 && isOK) + break; + } + + #endif +} + +static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; +static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension"; + +static void WriteCLSID(void) +{ + HKEY destKey; + LONG res; + + #ifdef USE_7ZIP_32_DLL + + MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension); + + res = MyRegistry_CreateKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey); + + if (res == ERROR_SUCCESS) + { + WCHAR destPath[MAX_PATH + 40]; + wcscpy(destPath, path); + CatAscii(destPath, "7-zip32.dll"); + /* res = */ MyRegistry_SetString(destKey, NULL, destPath); + /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment"); + // DeleteRegValue(destKey, L"InprocServer32"); + /* res = */ RegCloseKey(destKey); + } + + #endif + + + MyRegistry_CreateKeyAndVal(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension); + + destKey = 0; + res = MyRegistry_CreateKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey); + + if (res == ERROR_SUCCESS) + { + WCHAR destPath[MAX_PATH + 40]; + wcscpy(destPath, path); + CatAscii(destPath, "7-zip.dll"); + /* res = */ MyRegistry_SetString(destKey, NULL, destPath); + /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment"); + // DeleteRegValue(destKey, L"InprocServer32"); + /* res = */ RegCloseKey(destKey); + } +} + +static LPCSTR const k_ShellEx_Items[] = +{ + "*\\shellex\\ContextMenuHandlers" + , "Directory\\shellex\\ContextMenuHandlers" + , "Folder\\shellex\\ContextMenuHandlers" + , "Directory\\shellex\\DragDropHandlers" + , "Drive\\shellex\\DragDropHandlers" +}; + +static void WriteShellEx(void) +{ + unsigned i; + WCHAR destPath[MAX_PATH + 40]; + + for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++) + { + CpyAscii(destPath, k_ShellEx_Items[i]); + CatAscii(destPath, "\\7-Zip"); + + #ifdef USE_7ZIP_32_DLL + MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); + #endif + MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID); + } + + #ifdef USE_7ZIP_32_DLL + MyRegistry_CreateKeyAndVal_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension); + #endif + MyRegistry_CreateKeyAndVal (HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension); + + + wcscpy(destPath, path); + CatAscii(destPath, "7zFM.exe"); + + { + HKEY destKey = 0; + LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey); + if (res == ERROR_SUCCESS) + { + MyRegistry_SetString(destKey, NULL, destPath); + MyRegistry_SetString(destKey, L"Path", path); + RegCloseKey(destKey); + } + + } + + { + HKEY destKey = 0; + LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\7-Zip", &destKey); + if (res == ERROR_SUCCESS) + { + MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str); + MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS)); + MyRegistry_SetString(destKey, L"DisplayIcon", destPath); + MyRegistry_SetString(destKey, L"InstallLocation", path); + + destPath[0] = '\"'; + wcscpy(destPath + 1, path); + CatAscii(destPath, "Uninstall.exe\""); + MyRegistry_SetString(destKey, L"UninstallString", destPath); + + CatAscii(destPath, " /S"); + MyRegistry_SetString(destKey, L"QuietUninstallString", destPath); + + MyRegistry_SetDWORD(destKey, L"NoModify", 1); + MyRegistry_SetDWORD(destKey, L"NoRepair", 1); + + MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10); + + MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR); + MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR); + + MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME)); + + // MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html"); + // MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/"); + // MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/"); + + RegCloseKey(destKey); + } + } +} + + +static const wchar_t *GetCmdParam(const wchar_t *s) +{ + unsigned pos = 0; + BoolInt quoteMode = False; + for (;; s++) + { + wchar_t c = *s; + if (c == 0 || (c == L' ' && !quoteMode)) + break; + if (c == L'\"') + { + quoteMode = !quoteMode; + continue; + } + if (pos >= Z7_ARRAY_SIZE(cmd) - 1) + exit(1); + cmd[pos++] = c; + } + cmd[pos] = 0; + return s; +} + + +static void RemoveQuotes(wchar_t *s) +{ + const wchar_t *src = s; + for (;;) + { + wchar_t c = *src++; + if (c == '\"') + continue; + *s++ = c; + if (c == 0) + return; + } +} + +// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') + + +typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + lpCmdLine, int nCmdShow) +{ + + UNUSED_VAR(hPrevInstance) + UNUSED_VAR(lpCmdLine) + UNUSED_VAR(nCmdShow) + + #ifndef UNDER_CE + LoadSecurityDlls(); + CoInitialize(NULL); + #endif + + CrcGenerateTable(); + + { + const wchar_t *s = GetCommandLineW(); + + #ifndef UNDER_CE + s = GetCmdParam(s); + #endif + + for (;;) + { + { + const wchar_t c = *s; + if (c == 0) + break; + if (c == ' ') + { + s++; + continue; + } + } + + { + const wchar_t *s2 = GetCmdParam(s); + BoolInt error = True; + if (cmd[0] == '/') + { + if (cmd[1] == 'S') + { + if (cmd[2] == 0) + { + g_SilentMode = True; + error = False; + } + } + else if (cmd[1] == 'D' && cmd[2] == '=') + { + wcscpy(path, cmd + 3); + // RemoveQuotes(path); + error = False; + } + } + s = s2; + if (error && cmdError[0] == 0) + wcscpy(cmdError, cmd); + } + } + + if (cmdError[0] != 0) + { + if (!g_SilentMode) + PrintErrorMessage("Unsupported command:", cmdError); + return 1; + } + } + + #if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64) + { + BOOL isWow64 = FALSE; + const Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process) + Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"kernel32.dll"), + "IsWow64Process"); + + if (func_IsWow64Process) + func_IsWow64Process(GetCurrentProcess(), &isWow64); + + if (!isWow64) + { + if (!g_SilentMode) + PrintErrorMessage("This installation requires Windows " + #ifdef MY_CPU_X86_OR_AMD64 + "x64" + #else + "64-bit" + #endif + , NULL); + return 1; + } + } + #endif + + + if (path[0] == 0) + { + HKEY key = 0; + BoolInt ok = False; + const LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key); + if (res == ERROR_SUCCESS) + { + ok = MyRegistry_QueryString(key, k_Reg_Path32, path); + // ok = MyRegistry_QueryString(key, k_Reg_Path, path); + RegCloseKey(key); + } + + // ok = False; + if (!ok) + { + /* + #ifdef UNDER_CE + CpyAscii(path, "\\Program Files\\"); + #else + + #ifdef Z7_64BIT_INSTALLER + { + DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH); + if (ttt == 0 || ttt > MAX_PATH) + CpyAscii(path, "C:\\"); + } + #else + if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE)) + CpyAscii(path, "C:\\"); + #endif + #endif + */ + if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path)) + CpyAscii(path, + #ifdef UNDER_CE + "\\Program Files\\" + #else + "C:\\" + #endif + ); + + Set7zipPostfix(path); + } + } + + NormalizePrefix(path); + + if (g_SilentMode) + return Install(); + + { + int retCode = 1; + // INT_PTR res = DialogBox( + g_HWND = CreateDialog( + hInstance, + // GetModuleHandle(NULL), + MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc); + if (!g_HWND) + return 1; + + { + const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); + // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); + SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); + } + + + { + BOOL bRet; + MSG msg; + + // we need messages for all thread windows (including EDITTEXT window in dialog) + while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) + { + if (bRet == -1) + return retCode; + if (!g_HWND) + return retCode; + + if (!IsDialogMessage(g_HWND, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (!g_HWND) + return retCode; + + if (g_Install_was_Pressed && !g_Finished) + { + retCode = Install(); + g_Finished = True; + if (retCode != 0) + break; + if (!g_HWND) + break; + { + SetDlgItemTextW(g_HWND, IDOK, L"Close"); + EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE); + EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE); + SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE); + } + } + } + + if (g_HWND) + { + DestroyWindow(g_HWND); + g_HWND = NULL; + } + } + + return retCode; + } +} + + +static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message) +{ + LPWSTR msgBuf; + if (FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) + return False; + wcscpy(message, msgBuf); + LocalFree(msgBuf); + return True; +} + + + +static int Install(void) +{ + CFileInStream archiveStream; + CLookToRead2 lookStream; + CSzArEx db; + + SRes res = SZ_OK; + WRes winRes = 0; + const char *errorMessage = NULL; + + ISzAlloc allocImp; + ISzAlloc allocTempImp; + WCHAR sfxPath[MAX_PATH + 2]; + + int needRebootLevel = 0; + + allocImp.Alloc = SzAlloc; + allocImp.Free = SzFree; + + allocTempImp.Alloc = SzAllocTemp; + allocTempImp.Free = SzFreeTemp; + + { + const DWORD len = GetModuleFileNameW(NULL, sfxPath, MAX_PATH); + if (len == 0 || len > MAX_PATH) + return 1; + } + + winRes = InFile_OpenW(&archiveStream.file, sfxPath); + + if (winRes == 0) + { + UInt64 pos = 0; + if (!FindSignature(&archiveStream.file, &pos)) + errorMessage = "Can't find 7z archive"; + else + winRes = File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET); + } + + if (winRes != 0) + res = SZ_ERROR_FAIL; + + if (errorMessage) + res = SZ_ERROR_FAIL; + +if (res == SZ_OK) +{ + size_t pathLen; + if (!g_SilentMode) + { + GetDlgItemTextW(g_HWND, IDE_EXTRACT_PATH, path, MAX_PATH); + } + + FileInStream_CreateVTable(&archiveStream); + LookToRead2_CreateVTable(&lookStream, False); + lookStream.buf = NULL; + + RemoveQuotes(path); + { + // Remove post spaces + unsigned endPos = 0; + unsigned i = 0; + + for (;;) + { + const wchar_t c = path[i++]; + if (c == 0) + break; + if (c != ' ') + endPos = i; + } + + path[endPos] = 0; + if (path[0] == 0) + { + PrintErrorMessage("Incorrect path", NULL); + return 1; + } + } + + NormalizePrefix(path); + winRes = CreateComplexDir(); + + if (winRes != 0) + res = SZ_ERROR_FAIL; + + pathLen = wcslen(path); + + if (res == SZ_OK) + { + lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); + if (!lookStream.buf) + res = SZ_ERROR_MEM; + else + { + lookStream.bufSize = kInputBufSize; + lookStream.realStream = &archiveStream.vt; + LookToRead2_INIT(&lookStream) + } + } + + SzArEx_Init(&db); + + if (res == SZ_OK) + { + res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); + } + + if (res == SZ_OK) + { + UInt32 i; + UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if (!outBuf) */ + Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */ + size_t outBufSize = 0; /* it can have any value before first call, if (!outBuf) */ + + g_TotalSize = 0; + + if (!g_SilentMode) + { + ShowWindow(g_Progress_HWND, SW_SHOW); + ShowWindow(g_InfoLine_HWND, SW_SHOW); + SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, db.NumFiles); + } + + for (i = 0; i < db.NumFiles; i++) + { + size_t offset = 0; + size_t outSizeProcessed = 0; + WCHAR *temp; + + if (!g_SilentMode) + { + MSG msg; + + // g_HWND + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (!IsDialogMessage(g_HWND, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (!g_HWND) + return 1; + } + + // Sleep(10); + SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); + } + + { + const size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL); + if (len >= MAX_PATH) + { + res = SZ_ERROR_FAIL; + break; + } + } + + temp = path + pathLen; + + SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp); + + if (!g_SilentMode) + SetWindowTextW(g_InfoLine_HWND, temp); + + { + res = SzArEx_Extract(&db, &lookStream.vt, i, + &blockIndex, &outBuf, &outBufSize, + &offset, &outSizeProcessed, + &allocImp, &allocTempImp); + if (res != SZ_OK) + break; + } + + { + CSzFile outFile; + size_t processedSize; + size_t j; + // size_t nameStartPos = 0; + UInt32 tempIndex = 0; + int fileLevel = 1 << 2; + WCHAR origPath[MAX_PATH * 2 + 10]; + + for (j = 0; temp[j] != 0; j++) + { + if (temp[j] == '/') + { + temp[j] = 0; + MyCreateDir(path); + temp[j] = CHAR_PATH_SEPARATOR; + // nameStartPos = j + 1; + } + } + + if (SzArEx_IsDir(&db, i)) + { + MyCreateDir(path); + continue; + } + + { + // BoolInt skipFile = False; + + wcscpy(origPath, path); + + for (;;) + { + WRes openRes; + + if (tempIndex != 0) + { + if (tempIndex > 100) + { + res = SZ_ERROR_FAIL; + break; + } + wcscpy(path, origPath); + CatAscii(path, ".tmp"); + if (tempIndex > 1) + HexToString(tempIndex, path + wcslen(path)); + if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) + { + tempIndex++; + continue; + } + } + + { + SetFileAttributesW(path, 0); + openRes = OutFile_OpenW(&outFile, path); + if (openRes == 0) + break; + } + + if (tempIndex != 0) + { + tempIndex++; + continue; + } + + if (FindSubString(temp, "7-zip.dll") + #ifdef USE_7ZIP_32_DLL + || FindSubString(temp, "7-zip32.dll") + #endif + ) + { + const DWORD ver = GetFileVersion(path); + fileLevel = ((ver < Z7_7ZIP_DLL_VER_COMPAT || ver > Z7_7ZIP_CUR_VER) ? 2 : 1); + tempIndex++; + continue; + } + + if (g_SilentMode) + { + tempIndex++; + continue; + } + { + WCHAR message[MAX_PATH * 3 + 100]; + int mbRes; + + CpyAscii(message, "Can't open file\n"); + wcscat(message, path); + CatAscii(message, "\n"); + + GetErrorMessage(openRes, message + wcslen(message)); + + mbRes = MessageBoxW(g_HWND, message, L"Error", MB_ICONERROR | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3); + if (mbRes == IDABORT) + { + res = SZ_ERROR_ABORT; + tempIndex = 0; + break; + } + if (mbRes == IDIGNORE) + { + // skipFile = True; + tempIndex++; + } + } + } + + if (res != SZ_OK) + break; + + /* + if (skipFile) + continue; + */ + } + + // if (res == SZ_OK) + { + processedSize = outSizeProcessed; + winRes = File_Write(&outFile, outBuf + offset, &processedSize); + if (winRes != 0 || processedSize != outSizeProcessed) + { + errorMessage = "Can't write output file"; + res = SZ_ERROR_FAIL; + } + + g_TotalSize += (DWORD)outSizeProcessed; + + #ifdef USE_WINDOWS_FILE + if (SzBitWithVals_Check(&db.MTime, i)) + { + const CNtfsFileTime *t = db.MTime.Vals + i; + FILETIME mTime; + mTime.dwLowDateTime = t->Low; + mTime.dwHighDateTime = t->High; + SetFileTime(outFile.handle, NULL, NULL, &mTime); + } + #endif + + { + const WRes winRes2 = File_Close(&outFile); + if (res != SZ_OK) + break; + if (winRes2 != 0) + { + winRes = winRes2; + break; + } + } + + #ifdef USE_WINDOWS_FILE + if (SzBitWithVals_Check(&db.Attribs, i)) + SetFileAttributesW(path, db.Attribs.Vals[i]); + #endif + } + + if (tempIndex != 0) + { + // is it supported at win2000 ? + #ifndef UNDER_CE + if (!MoveFileExW(path, origPath, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING)) + { + winRes = GetLastError(); + break; + } + needRebootLevel |= fileLevel; + #endif + } + + } + } + + ISzAlloc_Free(&allocImp, outBuf); + + if (!g_SilentMode) + SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); + + path[pathLen] = 0; + + if (i == db.NumFiles) + { + SetRegKey_Path(); + WriteCLSID(); + WriteShellEx(); + + SetShellProgramsGroup(g_HWND); + if (!g_SilentMode) + SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is installed"); + } + } + + SzArEx_Free(&db, &allocImp); + + ISzAlloc_Free(&allocImp, lookStream.buf); + + File_Close(&archiveStream.file); + +} + + if (winRes != 0) + res = SZ_ERROR_FAIL; + + if (res == SZ_OK) + { + if (!g_SilentMode && needRebootLevel > 1) + { + if (MessageBoxW(g_HWND, L"You must restart your system to complete the installation.\nRestart now?", + k_7zip_Setup, MB_YESNO | MB_DEFBUTTON2) == IDYES) + { + #ifndef UNDER_CE + + // Get a token for this process. + HANDLE hToken; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + { + TOKEN_PRIVILEGES tkp; + // Get the LUID for the shutdown privilege. + LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; // one privilege to set + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + // Get the shutdown privilege for this process. + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); + + if (GetLastError() == ERROR_SUCCESS) + { + if (!ExitWindowsEx(EWX_REBOOT, 0)) + { + } + } + } + + #endif + } + } + + if (res == SZ_OK) + return 0; + } + + if (!g_SilentMode) + { + if (winRes != 0) + { + WCHAR m[MAX_PATH + 100]; + m[0] = 0; + GetErrorMessage(winRes, m); + PrintErrorMessage(NULL, m); + } + else + { + if (res == SZ_ERROR_ABORT) + return 2; + + if (res == SZ_ERROR_UNSUPPORTED) + errorMessage = "Decoder doesn't support this archive"; + else if (res == SZ_ERROR_MEM) + errorMessage = "Can't allocate required memory"; + else if (res == SZ_ERROR_CRC) + errorMessage = "CRC error"; + else if (res == SZ_ERROR_DATA) + errorMessage = "Data error"; + + if (!errorMessage) + errorMessage = "ERROR"; + PrintErrorMessage(errorMessage, NULL); + } + } + + return 1; +} diff --git a/C/Util/7zipInstall/7zipInstall.dsp b/C/Util/7zipInstall/7zipInstall.dsp index 8f3cc0445..4c6ea4d83 100644 --- a/C/Util/7zipInstall/7zipInstall.dsp +++ b/C/Util/7zipInstall/7zipInstall.dsp @@ -1,248 +1,248 @@ -# Microsoft Developer Studio Project File - Name="7zipInstall" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=7zipInstall - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "7zipInstall.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "7zipInstall.mak" CFG="7zipInstall - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "7zipInstall - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "7zipInstall - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "7zipInstall - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /machine:I386 - -!ELSEIF "$(CFG)" == "7zipInstall - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "7zipInstall - Win32 Release" -# Name "7zipInstall - Win32 Debug" -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7z.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zArcIn.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrcOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra86.c -# End Source File -# Begin Source File - -SOURCE=..\..\BraIA64.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\Delta.c -# End Source File -# Begin Source File - -SOURCE=..\..\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\DllSecur.c -# End Source File -# Begin Source File - -SOURCE=..\..\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.c -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compiler.h -# End Source File -# Begin Source File - -SOURCE=.\Precomp.c -# ADD CPP /Yc"Precomp.h" -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7zipInstall.c -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="7zipInstall" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=7zipInstall - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "7zipInstall.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "7zipInstall.mak" CFG="7zipInstall - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "7zipInstall - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "7zipInstall - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "7zipInstall - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "7zipInstall - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "7zipInstall - Win32 Release" +# Name "7zipInstall - Win32 Debug" +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7z.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zArcIn.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrcOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra86.c +# End Source File +# Begin Source File + +SOURCE=..\..\BraIA64.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.c +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\DllSecur.c +# End Source File +# Begin Source File + +SOURCE=..\..\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.c +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compiler.h +# End Source File +# Begin Source File + +SOURCE=.\Precomp.c +# ADD CPP /Yc"Precomp.h" +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7zipInstall.c +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# End Target +# End Project diff --git a/C/Util/7zipInstall/7zipInstall.dsw b/C/Util/7zipInstall/7zipInstall.dsw index bb73ae982..b7db73f46 100644 --- a/C/Util/7zipInstall/7zipInstall.dsw +++ b/C/Util/7zipInstall/7zipInstall.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "7zipInstall"=.\7zipInstall.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "7zipInstall"=.\7zipInstall.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/C/Util/7zipInstall/7zipInstall.manifest b/C/Util/7zipInstall/7zipInstall.manifest index 9fbd7b5ac..f5c3ae5e7 100644 --- a/C/Util/7zipInstall/7zipInstall.manifest +++ b/C/Util/7zipInstall/7zipInstall.manifest @@ -1,18 +1,18 @@ - - - -7-Zip Installer - - - - - - - - - - - - -true - + + + +7-Zip Installer + + + + + + + + + + + + +true + diff --git a/C/Util/7zipInstall/Precomp.c b/C/Util/7zipInstall/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/7zipInstall/Precomp.c +++ b/C/Util/7zipInstall/Precomp.c @@ -1,4 +1,4 @@ -/* Precomp.c -- StdAfx -2013-01-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" +/* Precomp.c -- StdAfx +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" diff --git a/C/Util/7zipInstall/Precomp.h b/C/Util/7zipInstall/Precomp.h index 52b87ea64..13a41eff2 100644 --- a/C/Util/7zipInstall/Precomp.h +++ b/C/Util/7zipInstall/Precomp.h @@ -1,13 +1,13 @@ -/* Precomp.h -- Precomp -2024-01-23 : Igor Pavlov : Public domain */ - -// #ifndef ZIP7_INC_PRECOMP_LOC_H -// #define ZIP7_INC_PRECOMP_LOC_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../Precomp.h" - -// #endif +/* Precomp.h -- Precomp +2024-01-23 : Igor Pavlov : Public domain */ + +// #ifndef ZIP7_INC_PRECOMP_LOC_H +// #define ZIP7_INC_PRECOMP_LOC_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../Precomp.h" + +// #endif diff --git a/C/Util/7zipInstall/makefile b/C/Util/7zipInstall/makefile index 193358a62..424bd6ccc 100644 --- a/C/Util/7zipInstall/makefile +++ b/C/Util/7zipInstall/makefile @@ -1,47 +1,47 @@ -PROG = 7zipInstall.exe -MY_FIXED = 1 - -!IFDEF Z7_64BIT_INSTALLER -CFLAGS = $(CFLAGS) -DZ7_64BIT_INSTALLER -!ENDIF - -CFLAGS = $(CFLAGS) \ - -DZ7_LZMA_SIZE_OPT \ - -DZ7_NO_METHOD_LZMA2 \ - -DZ7_NO_METHODS_FILTERS \ - -DZ7_USE_NATIVE_BRANCH_FILTER \ - -DZ7_EXTRACT_ONLY \ - -MAIN_OBJS = \ - $O\7zipInstall.obj \ - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zArcIn.obj \ - $O\7zBuf.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\CpuArch.obj \ - $O\DllSecur.obj \ - $O\LzmaDec.obj \ - -OBJS = \ - $(MAIN_OBJS) \ - $(C_OBJS) \ - $(ASM_OBJS) \ - $O\resource.res - -!include "../../../CPP/7zip/Crc.mak" -# !include "../../../CPP/7zip/LzmaDec.mak" - -!include "../../../CPP/Build.mak" - -$(MAIN_OBJS): $(*B).c - $(COMPL_O1) -$(C_OBJS): ../../$(*B).c - $(COMPL_O1) - -!include "../../Asm_c.mak" +PROG = 7zipInstall.exe +MY_FIXED = 1 + +!IFDEF Z7_64BIT_INSTALLER +CFLAGS = $(CFLAGS) -DZ7_64BIT_INSTALLER +!ENDIF + +CFLAGS = $(CFLAGS) \ + -DZ7_LZMA_SIZE_OPT \ + -DZ7_NO_METHOD_LZMA2 \ + -DZ7_NO_METHODS_FILTERS \ + -DZ7_USE_NATIVE_BRANCH_FILTER \ + -DZ7_EXTRACT_ONLY \ + +MAIN_OBJS = \ + $O\7zipInstall.obj \ + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zArcIn.obj \ + $O\7zBuf.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\CpuArch.obj \ + $O\DllSecur.obj \ + $O\LzmaDec.obj \ + +OBJS = \ + $(MAIN_OBJS) \ + $(C_OBJS) \ + $(ASM_OBJS) \ + $O\resource.res + +!include "../../../CPP/7zip/Crc.mak" +# !include "../../../CPP/7zip/LzmaDec.mak" + +!include "../../../CPP/Build.mak" + +$(MAIN_OBJS): $(*B).c + $(COMPL_O1) +$(C_OBJS): ../../$(*B).c + $(COMPL_O1) + +!include "../../Asm_c.mak" diff --git a/C/Util/7zipInstall/resource.h b/C/Util/7zipInstall/resource.h index e7811a13a..63c6b4c28 100644 --- a/C/Util/7zipInstall/resource.h +++ b/C/Util/7zipInstall/resource.h @@ -1,9 +1,9 @@ -#define IDD_INSTALL 100 - -#define IDT_EXTRACT_EXTRACT_TO 110 -#define IDE_EXTRACT_PATH 111 -#define IDB_EXTRACT_SET_PATH 112 -#define IDT_CUR_FILE 113 -#define IDC_PROGRESS 114 - -#define IDI_ICON 1 +#define IDD_INSTALL 100 + +#define IDT_EXTRACT_EXTRACT_TO 110 +#define IDE_EXTRACT_PATH 111 +#define IDB_EXTRACT_SET_PATH 112 +#define IDT_CUR_FILE 113 +#define IDC_PROGRESS 114 + +#define IDI_ICON 1 diff --git a/C/Util/7zipInstall/resource.rc b/C/Util/7zipInstall/resource.rc index 908727ba9..40ed5807a 100644 --- a/C/Util/7zipInstall/resource.rc +++ b/C/Util/7zipInstall/resource.rc @@ -1,48 +1,48 @@ -#include -// #include -// #include -#include - -#define USE_COPYRIGHT_CR -#include "../../7zVersion.rc" -#include "resource.h" - -MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer", "7zipInstall", "7zipInstall.exe") - -1 ICON "7zip.ico" - -#define xc 184 -#define yc 96 - -#define m 8 -#define bxs 64 -#define bys 16 -#define bxsDots 20 - -#define xs (xc + m + m) -#define ys (yc + m + m) - -#define bx1 (xs - m - bxs) -#define bx2 (bx1 - m - bxs) - -#define by (ys - m - bys) - -IDD_INSTALL DIALOG 0, 0, xs, ys -STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE -CAPTION "Install 7-Zip" -FONT 8, "MS Shell Dlg" -BEGIN - LTEXT "Destination folder:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 - EDITTEXT IDE_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP - - LTEXT "", IDT_CUR_FILE, m, 50, xc, 8 - CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10 - - DEFPUSHBUTTON "&Install", IDOK, bx2, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -END - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "7zipInstall.manifest" -#endif +#include +// #include +// #include +#include + +#define USE_COPYRIGHT_CR +#include "../../7zVersion.rc" +#include "resource.h" + +MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer", "7zipInstall", "7zipInstall.exe") + +1 ICON "7zip.ico" + +#define xc 184 +#define yc 96 + +#define m 8 +#define bxs 64 +#define bys 16 +#define bxsDots 20 + +#define xs (xc + m + m) +#define ys (yc + m + m) + +#define bx1 (xs - m - bxs) +#define bx2 (bx1 - m - bxs) + +#define by (ys - m - bys) + +IDD_INSTALL DIALOG 0, 0, xs, ys +STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE +CAPTION "Install 7-Zip" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Destination folder:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 + EDITTEXT IDE_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP + + LTEXT "", IDT_CUR_FILE, m, 50, xc, 8 + CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10 + + DEFPUSHBUTTON "&Install", IDOK, bx2, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys +END + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "7zipInstall.manifest" +#endif diff --git a/C/Util/7zipUninstall/7zipUninstall.c b/C/Util/7zipUninstall/7zipUninstall.c index 3b4c9c5a6..e7051e258 100644 --- a/C/Util/7zipUninstall/7zipUninstall.c +++ b/C/Util/7zipUninstall/7zipUninstall.c @@ -1,1234 +1,1234 @@ -/* 7zipUninstall.c - 7-Zip Uninstaller -2024-03-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #define SZ_ERROR_ABORT 100 - -#include "../../7zTypes.h" -#include "../../7zWindows.h" - -#if defined(_MSC_VER) && _MSC_VER < 1600 -#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union -#endif - -#ifdef Z7_OLD_WIN_SDK -struct IShellView; -#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE -SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); -#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize -typedef enum { - SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists - SHGFP_TYPE_DEFAULT = 1, // default value, may not exist -} SHGFP_TYPE; -#endif -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../7zVersion.h" - -#include "resource.h" - - - - -#define LLL_(quote) L##quote -#define LLL(quote) LLL_(quote) - -#define wcscat lstrcatW -#define wcslen (size_t)lstrlenW -#define wcscpy lstrcpyW - -// static LPCWSTR const k_7zip = L"7-Zip"; - -// #define Z7_64BIT_INSTALLER 1 - -#ifdef _WIN64 - #define Z7_64BIT_INSTALLER 1 -#endif - -#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION) - -#ifdef Z7_64BIT_INSTALLER - - // #define USE_7ZIP_32_DLL - - #if defined(_M_ARM64) || defined(_M_ARM) - #define k_Postfix L" (arm64)" - #else - #define k_Postfix L" (x64)" - #define USE_7ZIP_32_DLL - #endif -#else - #if defined(_M_ARM64) || defined(_M_ARM) - #define k_Postfix L" (arm)" - #else - // #define k_Postfix L" (x86)" - #define k_Postfix - #endif -#endif - -#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix - -static LPCWSTR const k_7zip_with_Ver_Uninstall = k_7zip_with_Ver L" Uninstall"; - -static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip"; - -static LPCWSTR const k_Reg_Path = L"Path"; - -static LPCWSTR const k_Reg_Path32 = L"Path" - #ifdef Z7_64BIT_INSTALLER - L"64" - #else - L"32" - #endif - ; - -#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64) - #define k_Reg_WOW_Flag KEY_WOW64_64KEY -#else - #define k_Reg_WOW_Flag 0 -#endif - -#ifdef USE_7ZIP_32_DLL -#ifdef _WIN64 - #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY -#else - #define k_Reg_WOW_Flag_32 0 -#endif -#endif - -#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}" - -static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; -static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32"; - - -#define g_AllUsers True - -static BoolInt g_Install_was_Pressed; -static BoolInt g_Finished; -static BoolInt g_SilentMode; - -static HWND g_HWND; -static HWND g_Path_HWND; -static HWND g_InfoLine_HWND; -static HWND g_Progress_HWND; - -// RegDeleteKeyExW is supported starting from win2003sp1/xp-pro-x64 -// Z7_WIN32_WINNT_MIN < 0x0600 // Vista -#if !defined(Z7_WIN32_WINNT_MIN) \ - || Z7_WIN32_WINNT_MIN < 0x0502 /* < win2003 */ \ - || Z7_WIN32_WINNT_MIN == 0x0502 && !defined(_M_AMD64) -#define Z7_USE_DYN_RegDeleteKeyExW -#endif - -#ifdef Z7_USE_DYN_RegDeleteKeyExW -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); -static Func_RegDeleteKeyExW func_RegDeleteKeyExW; -#endif - -static WCHAR cmd[MAX_PATH + 4]; -static WCHAR cmdError[MAX_PATH + 4]; -static WCHAR path[MAX_PATH * 2 + 40]; -static WCHAR workDir[MAX_PATH + 10]; -static WCHAR modulePath[MAX_PATH + 10]; -static WCHAR modulePrefix[MAX_PATH + 10]; -static WCHAR tempPath[MAX_PATH * 2 + 40]; -static WCHAR cmdLine[MAX_PATH * 3 + 40]; -static WCHAR copyPath[MAX_PATH * 2 + 40]; - -static LPCWSTR const kUninstallExe = L"Uninstall.exe"; - -#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c))) - - -static void CpyAscii(wchar_t *dest, const char *s) -{ - for (;;) - { - const Byte b = (Byte)*s++; - *dest++ = b; - if (b == 0) - return; - } -} - -static void CatAscii(wchar_t *dest, const char *s) -{ - dest += wcslen(dest); - CpyAscii(dest, s); -} - -static void PrintErrorMessage(const char *s1, const wchar_t *s2) -{ - WCHAR m[MAX_PATH + 512]; - m[0] = 0; - CatAscii(m, "ERROR:"); - if (s1) - { - CatAscii(m, "\n"); - CatAscii(m, s1); - } - if (s2) - { - CatAscii(m, "\n"); - wcscat(m, s2); - } - MessageBoxW(g_HWND, m, k_7zip_with_Ver_Uninstall, MB_ICONERROR | MB_OK); -} - - -static BoolInt AreStringsEqual_NoCase(const wchar_t *s1, const wchar_t *s2) -{ - for (;;) - { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; - if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2)) - return False; - if (c2 == 0) - return True; - } -} - -static BoolInt IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) -{ - for (;;) - { - wchar_t c1; - const wchar_t c2 = *s2++; - if (c2 == 0) - return True; - c1 = *s1++; - if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2)) - return False; - } -} - -static void NormalizePrefix(WCHAR *s) -{ - const size_t len = wcslen(s); - if (len != 0) - if (s[len - 1] != WCHAR_PATH_SEPARATOR) - { - s[len] = WCHAR_PATH_SEPARATOR; - s[len + 1] = 0; - } -} - -static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest) -{ - DWORD cnt = MAX_PATH * sizeof(name[0]); - DWORD type = 0; - const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt); - if (type != REG_SZ) - return False; - return res == ERROR_SUCCESS; -} - -static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) -{ - HKEY key = 0; - const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); - if (res != ERROR_SUCCESS) - return False; - { - const BoolInt res2 = MyRegistry_QueryString(key, valName, dest); - RegCloseKey(key); - return res2; - } -} - -static LONG MyRegistry_OpenKey_ReadWrite(HKEY parentKey, LPCWSTR name, HKEY *destKey) -{ - return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag, destKey); -} - -static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCWSTR name) -{ -#if k_Reg_WOW_Flag != 0 -#ifdef Z7_USE_DYN_RegDeleteKeyExW - if (!func_RegDeleteKeyExW) - return E_FAIL; - return func_RegDeleteKeyExW -#else - return RegDeleteKeyExW -#endif - (parentKey, name, k_Reg_WOW_Flag, 0); -#else - return RegDeleteKeyW(parentKey, name); -#endif -} - -#ifdef USE_7ZIP_32_DLL - -static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) -{ - HKEY key = 0; - const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key); - if (res != ERROR_SUCCESS) - return False; - { - const BoolInt res2 = MyRegistry_QueryString(key, valName, dest); - RegCloseKey(key); - return res2; - } -} - -static LONG MyRegistry_OpenKey_ReadWrite_32(HKEY parentKey, LPCWSTR name, HKEY *destKey) -{ - return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag_32, destKey); -} - -static LONG MyRegistry_DeleteKey_32(HKEY parentKey, LPCWSTR name) -{ -#if k_Reg_WOW_Flag_32 != 0 -#ifdef Z7_USE_DYN_RegDeleteKeyExW - if (!func_RegDeleteKeyExW) - return E_FAIL; - return func_RegDeleteKeyExW -#else - return RegDeleteKeyExW -#endif - (parentKey, name, k_Reg_WOW_Flag_32, 0); -#else - return RegDeleteKeyW(parentKey, name); -#endif -} - -#endif - - - - -static void MyReg_DeleteVal_Path_if_Equal(HKEY hKey, LPCWSTR name) -{ - WCHAR s[MAX_PATH + 10]; - if (MyRegistry_QueryString(hKey, name, s)) - { - NormalizePrefix(s); - if (AreStringsEqual_NoCase(s, path)) - RegDeleteValueW(hKey, name); - } -} - -static void SetRegKey_Path2(HKEY parentKey) -{ - HKEY key = 0; - const LONG res = MyRegistry_OpenKey_ReadWrite(parentKey, k_Reg_Software_7zip, &key); - if (res == ERROR_SUCCESS) - { - MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path32); - MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path); - - RegCloseKey(key); - // MyRegistry_DeleteKey(parentKey, k_Reg_Software_7zip); - } -} - -static void SetRegKey_Path(void) -{ - SetRegKey_Path2(HKEY_CURRENT_USER); - SetRegKey_Path2(HKEY_LOCAL_MACHINE); -} - -static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath) -{ - IShellLinkW *sl; - - // CoInitialize has already been called. - HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); - - if (SUCCEEDED(hres)) - { - IPersistFile *pf; - - hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID *)&pf); - - if (SUCCEEDED(hres)) - { - WCHAR s[MAX_PATH + 10]; - hres = pf->lpVtbl->Load(pf, srcPath, TRUE); - pf->lpVtbl->Release(pf); - - if (SUCCEEDED(hres)) - { - hres = sl->lpVtbl->GetPath(sl, s, MAX_PATH, NULL, 0); // SLGP_RAWPATH - if (!AreStringsEqual_NoCase(s, targetPath)) - hres = S_FALSE; - } - } - - sl->lpVtbl->Release(sl); - } - - return hres; -} - -static void SetShellProgramsGroup(HWND hwndOwner) -{ - #ifdef UNDER_CE - - UNUSED_VAR(hwndOwner) - - #else - - unsigned i = (g_AllUsers ? 1 : 2); - - for (; i < 3; i++) - { - // BoolInt isOK = True; - WCHAR link[MAX_PATH + 40]; - WCHAR destPath[MAX_PATH + 40]; - - link[0] = 0; - - if (SHGetFolderPathW(hwndOwner, - i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, - NULL, SHGFP_TYPE_CURRENT, link) != S_OK) - continue; - - NormalizePrefix(link); - CatAscii(link, "7-Zip\\"); - - { - const size_t baseLen = wcslen(link); - unsigned k; - BoolInt needDelete = False; - - for (k = 0; k < 2; k++) - { - CpyAscii(link + baseLen, k == 0 ? - "7-Zip File Manager.lnk" : - "7-Zip Help.lnk"); - wcscpy(destPath, path); - CatAscii(destPath, k == 0 ? - "7zFM.exe" : - "7-zip.chm"); - - if (CreateShellLink(link, destPath) == S_OK) - { - needDelete = True; - DeleteFileW(link); - } - } - - if (needDelete) - { - link[baseLen] = 0; - RemoveDirectoryW(link); - } - } - } - - #endif -} - - -static LPCSTR const k_ShellEx_Items[] = -{ - "*\\shellex\\ContextMenuHandlers" - , "Directory\\shellex\\ContextMenuHandlers" - , "Folder\\shellex\\ContextMenuHandlers" - , "Directory\\shellex\\DragDropHandlers" - , "Drive\\shellex\\DragDropHandlers" -}; - -static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; - -static LPCWSTR const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe"; -#define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" -static LPCWSTR const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip"; - - -static void RemoveQuotes(wchar_t *s) -{ - const size_t len = wcslen(s); - size_t i; - if (len == 0 || s[0] != '\"' || s[len - 1] != '\"') - return; - for (i = 0; i < len; i++) - s[i] = s[i + 1]; - s[len - 2] = 0; -} - -static BoolInt AreEqual_Path_PrefixName(const wchar_t *s, const wchar_t *prefix, const wchar_t *name) -{ - if (!IsString1PrefixedByString2_NoCase(s, prefix)) - return False; - return AreStringsEqual_NoCase(s + wcslen(prefix), name); -} - -static void WriteCLSID(void) -{ - WCHAR s[MAX_PATH + 30]; - - if (MyRegistry_QueryString2(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) - { - if (AreEqual_Path_PrefixName(s, path, L"7-zip.dll")) - { - { - const LONG res = MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc); - if (res == ERROR_SUCCESS) - MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip); - } - - { - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++) - { - WCHAR destPath[MAX_PATH]; - CpyAscii(destPath, k_ShellEx_Items[i]); - CatAscii(destPath, "\\7-Zip"); - - MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath); - } - } - - { - HKEY destKey = 0; - const LONG res = MyRegistry_OpenKey_ReadWrite(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey); - if (res == ERROR_SUCCESS) - { - RegDeleteValueW(destKey, k_7zip_CLSID); - /* res = */ RegCloseKey(destKey); - } - } - } - } - - - #ifdef USE_7ZIP_32_DLL - - if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) - { - if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll")) - { - { - const LONG res = MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc); - if (res == ERROR_SUCCESS) - MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip); - } - - { - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++) - { - WCHAR destPath[MAX_PATH]; - CpyAscii(destPath, k_ShellEx_Items[i]); - CatAscii(destPath, "\\7-Zip"); - - MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath); - } - } - - { - HKEY destKey = 0; - const LONG res = MyRegistry_OpenKey_ReadWrite_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey); - if (res == ERROR_SUCCESS) - { - RegDeleteValueW(destKey, k_7zip_CLSID); - /* res = */ RegCloseKey(destKey); - } - } - } - } - - #endif - - - if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm, NULL, s)) - { - // RemoveQuotes(s); - if (AreEqual_Path_PrefixName(s, path, L"7zFM.exe")) - MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm); - } - - if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_Uninstall_7zip, L"UninstallString", s)) - { - RemoveQuotes(s); - if (AreEqual_Path_PrefixName(s, path, kUninstallExe)) - MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip); - } -} - - -static const wchar_t *GetCmdParam(const wchar_t *s) -{ - unsigned pos = 0; - BoolInt quoteMode = False; - for (;; s++) - { - const wchar_t c = *s; - if (c == 0 || (c == L' ' && !quoteMode)) - break; - if (c == L'\"') - { - quoteMode = !quoteMode; - continue; - } - if (pos >= Z7_ARRAY_SIZE(cmd) - 1) - exit(1); - cmd[pos++] = c; - } - cmd[pos] = 0; - return s; -} - -/* -static void RemoveQuotes(wchar_t *s) -{ - const wchar_t *src = s; - for (;;) - { - wchar_t c = *src++; - if (c == '\"') - continue; - *s++ = c; - if (c == 0) - return; - } -} -*/ - -static BoolInt DoesFileOrDirExist(void) -{ - return (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES); -} - -static BOOL RemoveFileAfterReboot2(const WCHAR *s) -{ - #ifndef UNDER_CE - return MoveFileExW(s, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); - #else - UNUSED_VAR(s) - return TRUE; - #endif -} - -static BOOL RemoveFileAfterReboot(void) -{ - return RemoveFileAfterReboot2(path); -} - -// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') - -static BoolInt IsThereSpace(const wchar_t *s) -{ - for (;;) - { - const wchar_t c = *s++; - if (c == 0) - return False; - if (c == ' ') - return True; - } -} - -static void AddPathParam(wchar_t *dest, const wchar_t *src) -{ - const BoolInt needQuote = IsThereSpace(src); - if (needQuote) - CatAscii(dest, "\""); - wcscat(dest, src); - if (needQuote) - CatAscii(dest, "\""); -} - - - -static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message) -{ - LPWSTR msgBuf; - if (FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) - return False; - wcscpy(message, msgBuf); - LocalFree(msgBuf); - return True; -} - -static BOOL RemoveDir(void) -{ - const DWORD attrib = GetFileAttributesW(path); - if (attrib == INVALID_FILE_ATTRIBUTES) - return TRUE; - if (RemoveDirectoryW(path)) - return TRUE; - return RemoveFileAfterReboot(); -} - - - - - -#define k_Lang "Lang" - -// NUM_LANG_TXT_FILES files are placed before en.ttt -#define NUM_LANG_TXT_FILES 92 - -#ifdef USE_7ZIP_32_DLL - #define NUM_EXTRA_FILES_64BIT 1 -#else - #define NUM_EXTRA_FILES_64BIT 0 -#endif - -#define NUM_FILES (NUM_LANG_TXT_FILES + 1 + 13 + NUM_EXTRA_FILES_64BIT) - -static const char * const k_Names = - "af an ar ast az ba be bg bn br ca co cs cy da de el eo es et eu ext" - " fa fi fr fur fy ga gl gu he hi hr hu hy id io is it ja ka kaa kab kk ko ku ku-ckb ky" - " lij lt lv mk mn mng mng2 mr ms nb ne nl nn pa-in pl ps pt pt-br ro ru" - " sa si sk sl sq sr-spc sr-spl sv sw ta tg th tk tr tt ug uk uz uz-cyrl va vi yo zh-cn zh-tw" - " en.ttt" - " descript.ion" - " History.txt" - " License.txt" - " readme.txt" - " 7-zip.chm" - " 7z.sfx" - " 7zCon.sfx" - " 7z.exe" - " 7zG.exe" - " 7z.dll" - " 7zFM.exe" - #ifdef USE_7ZIP_32_DLL - " 7-zip32.dll" - #endif - " 7-zip.dll" - " Uninstall.exe"; - - - -static int Install(void) -{ - SRes res = SZ_OK; - WRes winRes = 0; - - // BoolInt needReboot = False; - const size_t pathLen = wcslen(path); - - if (!g_SilentMode) - { - ShowWindow(g_Progress_HWND, SW_SHOW); - ShowWindow(g_InfoLine_HWND, SW_SHOW); - SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, NUM_FILES); - } - - { - unsigned i; - const char *curName = k_Names; - - for (i = 0; *curName != 0; i++) - { - WCHAR *temp; - - if (!g_SilentMode) - { - MSG msg; - - // g_HWND - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (!IsDialogMessage(g_HWND, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - if (!g_HWND) - return 1; - } - - // Sleep(1); - SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); - } - - path[pathLen] = 0; - temp = path + pathLen; - - if (i <= NUM_LANG_TXT_FILES) - CpyAscii(temp, k_Lang "\\"); - - { - WCHAR *dest = temp + wcslen(temp); - - for (;;) - { - const char c = *curName; - if (c == 0) - break; - curName++; - if (c == ' ') - break; - *dest++ = (Byte)c; - } - - *dest = 0; - } - - if (i < NUM_LANG_TXT_FILES) - CatAscii(temp, ".txt"); - - if (!g_SilentMode) - SetWindowTextW(g_InfoLine_HWND, temp); - - { - const DWORD attrib = GetFileAttributesW(path); - if (attrib == INVALID_FILE_ATTRIBUTES) - continue; - if (attrib & FILE_ATTRIBUTE_READONLY) - SetFileAttributesW(path, 0); - if (!DeleteFileW(path)) - { - if (!RemoveFileAfterReboot()) - { - winRes = GetLastError(); - } - /* - else - needReboot = True; - */ - } - } - } - - CpyAscii(path + pathLen, k_Lang); - RemoveDir(); - - path[pathLen] = 0; - RemoveDir(); - - if (!g_SilentMode) - SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); - - if (*curName == 0) - { - SetRegKey_Path(); - WriteCLSID(); - SetShellProgramsGroup(g_HWND); - if (!g_SilentMode) - SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is uninstalled"); - } - } - - if (winRes != 0) - res = SZ_ERROR_FAIL; - - if (res == SZ_OK) - { - // if (!g_SilentMode && needReboot); - return 0; - } - - if (!g_SilentMode) - { - WCHAR m[MAX_PATH + 100]; - m[0] = 0; - if (winRes == 0 || !GetErrorMessage(winRes, m)) - CpyAscii(m, "ERROR"); - PrintErrorMessage("System ERROR:", m); - } - - return 1; -} - - -static void OnClose(void) -{ - if (g_Install_was_Pressed && !g_Finished) - { - if (MessageBoxW(g_HWND, - L"Do you want to cancel uninstallation?", - k_7zip_with_Ver_Uninstall, - MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) - return; - } - DestroyWindow(g_HWND); - g_HWND = NULL; -} - -static -#ifdef Z7_OLD_WIN_SDK - BOOL -#else - INT_PTR -#endif -CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - UNUSED_VAR(lParam) - - switch (message) - { - case WM_INITDIALOG: - g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH); - g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE); - g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS); - - SetWindowTextW(hwnd, k_7zip_with_Ver_Uninstall); - SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path); - - ShowWindow(g_Progress_HWND, SW_HIDE); - ShowWindow(g_InfoLine_HWND, SW_HIDE); - - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - if (g_Finished) - { - OnClose(); - break; - } - if (!g_Install_was_Pressed) - { - SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE); - - EnableWindow(g_Path_HWND, FALSE); - EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); - - g_Install_was_Pressed = True; - return TRUE; - } - break; - } - - case IDCANCEL: - { - OnClose(); - break; - } - - default: return FALSE; - } - break; - - case WM_CLOSE: - OnClose(); - break; - /* - case WM_DESTROY: - PostQuitMessage(0); - return TRUE; - */ - default: - return FALSE; - } - - return TRUE; -} - - -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - lpCmdLine, int nCmdShow) -{ - const wchar_t *cmdParams; - BoolInt useTemp = True; - - UNUSED_VAR(hPrevInstance) - UNUSED_VAR(lpCmdLine) - UNUSED_VAR(nCmdShow) - -#ifndef UNDER_CE - CoInitialize(NULL); -#endif - -#ifndef UNDER_CE -#ifdef Z7_USE_DYN_RegDeleteKeyExW - func_RegDeleteKeyExW = - (Func_RegDeleteKeyExW) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"advapi32.dll"), - "RegDeleteKeyExW"); -#endif -#endif - - { - const wchar_t *s = GetCommandLineW(); - - #ifndef UNDER_CE - s = GetCmdParam(s); - #endif - - cmdParams = s; - - for (;;) - { - { - wchar_t c = *s; - if (c == 0) - break; - if (c == ' ') - { - s++; - continue; - } - } - - { - const wchar_t *s2 = GetCmdParam(s); - BoolInt error = True; - if (cmd[0] == '/') - { - if (cmd[1] == 'S') - { - if (cmd[2] == 0) - { - g_SilentMode = True; - error = False; - } - } - else if (cmd[1] == 'N') - { - if (cmd[2] == 0) - { - useTemp = False; - error = False; - } - } - else if (cmd[1] == 'D' && cmd[2] == '=') - { - wcscpy(workDir, cmd + 3); - // RemoveQuotes(workDir); - useTemp = False; - error = False; - } - } - s = s2; - if (error && cmdError[0] == 0) - wcscpy(cmdError, cmd); - } - } - - if (cmdError[0] != 0) - { - if (!g_SilentMode) - PrintErrorMessage("Unsupported command:", cmdError); - return 1; - } - } - - { - wchar_t *name; - const DWORD len = GetModuleFileNameW(NULL, modulePath, MAX_PATH); - if (len == 0 || len > MAX_PATH) - return 1; - - name = NULL; - wcscpy(modulePrefix, modulePath); - - { - wchar_t *s = modulePrefix; - for (;;) - { - const wchar_t c = *s++; - if (c == 0) - break; - if (c == WCHAR_PATH_SEPARATOR) - name = s; - } - } - - if (!name) - return 1; - - if (!AreStringsEqual_NoCase(name, kUninstallExe)) - useTemp = False; - - *name = 0; // keep only prefix for modulePrefix - } - - - if (useTemp) - { - DWORD winRes = GetTempPathW(MAX_PATH, path); - - // GetTempPath: the returned string ends with a backslash - /* - { - WCHAR s[MAX_PATH + 1]; - wcscpy(s, path); - GetLongPathNameW(s, path, MAX_PATH); - } - */ - - if (winRes != 0 && winRes <= MAX_PATH + 1 - && !IsString1PrefixedByString2_NoCase(modulePrefix, path)) - { - unsigned i; - DWORD d; - - const size_t pathLen = wcslen(path); - d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); - - for (i = 0; i < 100; i++, d += GetTickCount()) - { - CpyAscii(path + pathLen, "7z"); - - { - wchar_t *s = path + wcslen(path); - UInt32 value = d; - unsigned k; - for (k = 0; k < 8; k++) - { - const unsigned t = value & 0xF; - value >>= 4; - s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } - s[k] = 0; - } - - if (DoesFileOrDirExist()) - continue; - if (CreateDirectoryW(path, NULL)) - { - CatAscii(path, STRING_PATH_SEPARATOR); - wcscpy(tempPath, path); - break; - } - if (GetLastError() != ERROR_ALREADY_EXISTS) - break; - } - - if (tempPath[0] != 0) - { - wcscpy(copyPath, tempPath); - CatAscii(copyPath, "Uninst.exe"); // we need not "Uninstall.exe" here - - if (CopyFileW(modulePath, copyPath, TRUE)) - { - RemoveFileAfterReboot2(copyPath); - RemoveFileAfterReboot2(tempPath); - - { - STARTUPINFOW si; - PROCESS_INFORMATION pi; - cmdLine[0] = 0; - - // maybe CreateProcess supports path with spaces even without quotes. - AddPathParam(cmdLine, copyPath); - CatAscii(cmdLine, " /N /D="); - AddPathParam(cmdLine, modulePrefix); - - if (cmdParams[0] != 0 && wcslen(cmdParams) < MAX_PATH * 2 + 10) - wcscat(cmdLine, cmdParams); - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - - if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, tempPath, &si, &pi)) - { - CloseHandle(pi.hThread); - if (pi.hProcess) - { - CloseHandle(pi.hProcess); - return 0; - } - } - } - } - } - } - } - - wcscpy(path, modulePrefix); - - if (workDir[0] != 0) - { - wcscpy(path, workDir); - NormalizePrefix(path); - } - - /* - if (path[0] == 0) - { - HKEY key = 0; - BoolInt ok = False; - LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key); - if (res == ERROR_SUCCESS) - { - ok = MyRegistry_QueryString(key, k_Reg_Path32, path); - // ok = MyRegistry_QueryString(key, k_Reg_Path, path); - RegCloseKey(key); - } - } - */ - - - if (g_SilentMode) - return Install(); - - { - int retCode = 1; - g_HWND = CreateDialog( - hInstance, - // GetModuleHandle(NULL), - MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc); - if (!g_HWND) - return 1; - - { - const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); - // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); - SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); - } - - { - BOOL bRet; - MSG msg; - - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) - { - if (bRet == -1) - return retCode; - if (!g_HWND) - return retCode; - - if (!IsDialogMessage(g_HWND, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - if (!g_HWND) - return retCode; - - if (g_Install_was_Pressed && !g_Finished) - { - retCode = Install(); - g_Finished = True; - if (retCode != 0) - break; - if (!g_HWND) - break; - { - SetDlgItemTextW(g_HWND, IDOK, L"Close"); - EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE); - EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE); - SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE); - } - } - } - - if (g_HWND) - { - DestroyWindow(g_HWND); - g_HWND = NULL; - } - } - - return retCode; - } -} +/* 7zipUninstall.c - 7-Zip Uninstaller +2024-03-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #define SZ_ERROR_ABORT 100 + +#include "../../7zTypes.h" +#include "../../7zWindows.h" + +#if defined(_MSC_VER) && _MSC_VER < 1600 +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union +#endif + +#ifdef Z7_OLD_WIN_SDK +struct IShellView; +#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE +SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); +#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize +typedef enum { + SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists + SHGFP_TYPE_DEFAULT = 1, // default value, may not exist +} SHGFP_TYPE; +#endif +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../7zVersion.h" + +#include "resource.h" + + + + +#define LLL_(quote) L##quote +#define LLL(quote) LLL_(quote) + +#define wcscat lstrcatW +#define wcslen (size_t)lstrlenW +#define wcscpy lstrcpyW + +// static LPCWSTR const k_7zip = L"7-Zip"; + +// #define Z7_64BIT_INSTALLER 1 + +#ifdef _WIN64 + #define Z7_64BIT_INSTALLER 1 +#endif + +#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION) + +#ifdef Z7_64BIT_INSTALLER + + // #define USE_7ZIP_32_DLL + + #if defined(_M_ARM64) || defined(_M_ARM) + #define k_Postfix L" (arm64)" + #else + #define k_Postfix L" (x64)" + #define USE_7ZIP_32_DLL + #endif +#else + #if defined(_M_ARM64) || defined(_M_ARM) + #define k_Postfix L" (arm)" + #else + // #define k_Postfix L" (x86)" + #define k_Postfix + #endif +#endif + +#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix + +static LPCWSTR const k_7zip_with_Ver_Uninstall = k_7zip_with_Ver L" Uninstall"; + +static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip"; + +static LPCWSTR const k_Reg_Path = L"Path"; + +static LPCWSTR const k_Reg_Path32 = L"Path" + #ifdef Z7_64BIT_INSTALLER + L"64" + #else + L"32" + #endif + ; + +#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64) + #define k_Reg_WOW_Flag KEY_WOW64_64KEY +#else + #define k_Reg_WOW_Flag 0 +#endif + +#ifdef USE_7ZIP_32_DLL +#ifdef _WIN64 + #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY +#else + #define k_Reg_WOW_Flag_32 0 +#endif +#endif + +#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}" + +static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID; +static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32"; + + +#define g_AllUsers True + +static BoolInt g_Install_was_Pressed; +static BoolInt g_Finished; +static BoolInt g_SilentMode; + +static HWND g_HWND; +static HWND g_Path_HWND; +static HWND g_InfoLine_HWND; +static HWND g_Progress_HWND; + +// RegDeleteKeyExW is supported starting from win2003sp1/xp-pro-x64 +// Z7_WIN32_WINNT_MIN < 0x0600 // Vista +#if !defined(Z7_WIN32_WINNT_MIN) \ + || Z7_WIN32_WINNT_MIN < 0x0502 /* < win2003 */ \ + || Z7_WIN32_WINNT_MIN == 0x0502 && !defined(_M_AMD64) +#define Z7_USE_DYN_RegDeleteKeyExW +#endif + +#ifdef Z7_USE_DYN_RegDeleteKeyExW +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); +static Func_RegDeleteKeyExW func_RegDeleteKeyExW; +#endif + +static WCHAR cmd[MAX_PATH + 4]; +static WCHAR cmdError[MAX_PATH + 4]; +static WCHAR path[MAX_PATH * 2 + 40]; +static WCHAR workDir[MAX_PATH + 10]; +static WCHAR modulePath[MAX_PATH + 10]; +static WCHAR modulePrefix[MAX_PATH + 10]; +static WCHAR tempPath[MAX_PATH * 2 + 40]; +static WCHAR cmdLine[MAX_PATH * 3 + 40]; +static WCHAR copyPath[MAX_PATH * 2 + 40]; + +static LPCWSTR const kUninstallExe = L"Uninstall.exe"; + +#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c))) + + +static void CpyAscii(wchar_t *dest, const char *s) +{ + for (;;) + { + const Byte b = (Byte)*s++; + *dest++ = b; + if (b == 0) + return; + } +} + +static void CatAscii(wchar_t *dest, const char *s) +{ + dest += wcslen(dest); + CpyAscii(dest, s); +} + +static void PrintErrorMessage(const char *s1, const wchar_t *s2) +{ + WCHAR m[MAX_PATH + 512]; + m[0] = 0; + CatAscii(m, "ERROR:"); + if (s1) + { + CatAscii(m, "\n"); + CatAscii(m, s1); + } + if (s2) + { + CatAscii(m, "\n"); + wcscat(m, s2); + } + MessageBoxW(g_HWND, m, k_7zip_with_Ver_Uninstall, MB_ICONERROR | MB_OK); +} + + +static BoolInt AreStringsEqual_NoCase(const wchar_t *s1, const wchar_t *s2) +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2)) + return False; + if (c2 == 0) + return True; + } +} + +static BoolInt IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) +{ + for (;;) + { + wchar_t c1; + const wchar_t c2 = *s2++; + if (c2 == 0) + return True; + c1 = *s1++; + if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2)) + return False; + } +} + +static void NormalizePrefix(WCHAR *s) +{ + const size_t len = wcslen(s); + if (len != 0) + if (s[len - 1] != WCHAR_PATH_SEPARATOR) + { + s[len] = WCHAR_PATH_SEPARATOR; + s[len + 1] = 0; + } +} + +static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest) +{ + DWORD cnt = MAX_PATH * sizeof(name[0]); + DWORD type = 0; + const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt); + if (type != REG_SZ) + return False; + return res == ERROR_SUCCESS; +} + +static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) +{ + HKEY key = 0; + const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key); + if (res != ERROR_SUCCESS) + return False; + { + const BoolInt res2 = MyRegistry_QueryString(key, valName, dest); + RegCloseKey(key); + return res2; + } +} + +static LONG MyRegistry_OpenKey_ReadWrite(HKEY parentKey, LPCWSTR name, HKEY *destKey) +{ + return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag, destKey); +} + +static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCWSTR name) +{ +#if k_Reg_WOW_Flag != 0 +#ifdef Z7_USE_DYN_RegDeleteKeyExW + if (!func_RegDeleteKeyExW) + return E_FAIL; + return func_RegDeleteKeyExW +#else + return RegDeleteKeyExW +#endif + (parentKey, name, k_Reg_WOW_Flag, 0); +#else + return RegDeleteKeyW(parentKey, name); +#endif +} + +#ifdef USE_7ZIP_32_DLL + +static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest) +{ + HKEY key = 0; + const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key); + if (res != ERROR_SUCCESS) + return False; + { + const BoolInt res2 = MyRegistry_QueryString(key, valName, dest); + RegCloseKey(key); + return res2; + } +} + +static LONG MyRegistry_OpenKey_ReadWrite_32(HKEY parentKey, LPCWSTR name, HKEY *destKey) +{ + return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag_32, destKey); +} + +static LONG MyRegistry_DeleteKey_32(HKEY parentKey, LPCWSTR name) +{ +#if k_Reg_WOW_Flag_32 != 0 +#ifdef Z7_USE_DYN_RegDeleteKeyExW + if (!func_RegDeleteKeyExW) + return E_FAIL; + return func_RegDeleteKeyExW +#else + return RegDeleteKeyExW +#endif + (parentKey, name, k_Reg_WOW_Flag_32, 0); +#else + return RegDeleteKeyW(parentKey, name); +#endif +} + +#endif + + + + +static void MyReg_DeleteVal_Path_if_Equal(HKEY hKey, LPCWSTR name) +{ + WCHAR s[MAX_PATH + 10]; + if (MyRegistry_QueryString(hKey, name, s)) + { + NormalizePrefix(s); + if (AreStringsEqual_NoCase(s, path)) + RegDeleteValueW(hKey, name); + } +} + +static void SetRegKey_Path2(HKEY parentKey) +{ + HKEY key = 0; + const LONG res = MyRegistry_OpenKey_ReadWrite(parentKey, k_Reg_Software_7zip, &key); + if (res == ERROR_SUCCESS) + { + MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path32); + MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path); + + RegCloseKey(key); + // MyRegistry_DeleteKey(parentKey, k_Reg_Software_7zip); + } +} + +static void SetRegKey_Path(void) +{ + SetRegKey_Path2(HKEY_CURRENT_USER); + SetRegKey_Path2(HKEY_LOCAL_MACHINE); +} + +static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath) +{ + IShellLinkW *sl; + + // CoInitialize has already been called. + HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl); + + if (SUCCEEDED(hres)) + { + IPersistFile *pf; + + hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID *)&pf); + + if (SUCCEEDED(hres)) + { + WCHAR s[MAX_PATH + 10]; + hres = pf->lpVtbl->Load(pf, srcPath, TRUE); + pf->lpVtbl->Release(pf); + + if (SUCCEEDED(hres)) + { + hres = sl->lpVtbl->GetPath(sl, s, MAX_PATH, NULL, 0); // SLGP_RAWPATH + if (!AreStringsEqual_NoCase(s, targetPath)) + hres = S_FALSE; + } + } + + sl->lpVtbl->Release(sl); + } + + return hres; +} + +static void SetShellProgramsGroup(HWND hwndOwner) +{ + #ifdef UNDER_CE + + UNUSED_VAR(hwndOwner) + + #else + + unsigned i = (g_AllUsers ? 1 : 2); + + for (; i < 3; i++) + { + // BoolInt isOK = True; + WCHAR link[MAX_PATH + 40]; + WCHAR destPath[MAX_PATH + 40]; + + link[0] = 0; + + if (SHGetFolderPathW(hwndOwner, + i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS, + NULL, SHGFP_TYPE_CURRENT, link) != S_OK) + continue; + + NormalizePrefix(link); + CatAscii(link, "7-Zip\\"); + + { + const size_t baseLen = wcslen(link); + unsigned k; + BoolInt needDelete = False; + + for (k = 0; k < 2; k++) + { + CpyAscii(link + baseLen, k == 0 ? + "7-Zip File Manager.lnk" : + "7-Zip Help.lnk"); + wcscpy(destPath, path); + CatAscii(destPath, k == 0 ? + "7zFM.exe" : + "7-zip.chm"); + + if (CreateShellLink(link, destPath) == S_OK) + { + needDelete = True; + DeleteFileW(link); + } + } + + if (needDelete) + { + link[baseLen] = 0; + RemoveDirectoryW(link); + } + } + } + + #endif +} + + +static LPCSTR const k_ShellEx_Items[] = +{ + "*\\shellex\\ContextMenuHandlers" + , "Directory\\shellex\\ContextMenuHandlers" + , "Folder\\shellex\\ContextMenuHandlers" + , "Directory\\shellex\\DragDropHandlers" + , "Drive\\shellex\\DragDropHandlers" +}; + +static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; + +static LPCWSTR const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe"; +#define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" +static LPCWSTR const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip"; + + +static void RemoveQuotes(wchar_t *s) +{ + const size_t len = wcslen(s); + size_t i; + if (len == 0 || s[0] != '\"' || s[len - 1] != '\"') + return; + for (i = 0; i < len; i++) + s[i] = s[i + 1]; + s[len - 2] = 0; +} + +static BoolInt AreEqual_Path_PrefixName(const wchar_t *s, const wchar_t *prefix, const wchar_t *name) +{ + if (!IsString1PrefixedByString2_NoCase(s, prefix)) + return False; + return AreStringsEqual_NoCase(s + wcslen(prefix), name); +} + +static void WriteCLSID(void) +{ + WCHAR s[MAX_PATH + 30]; + + if (MyRegistry_QueryString2(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) + { + if (AreEqual_Path_PrefixName(s, path, L"7-zip.dll")) + { + { + const LONG res = MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc); + if (res == ERROR_SUCCESS) + MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip); + } + + { + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++) + { + WCHAR destPath[MAX_PATH]; + CpyAscii(destPath, k_ShellEx_Items[i]); + CatAscii(destPath, "\\7-Zip"); + + MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath); + } + } + + { + HKEY destKey = 0; + const LONG res = MyRegistry_OpenKey_ReadWrite(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey); + if (res == ERROR_SUCCESS) + { + RegDeleteValueW(destKey, k_7zip_CLSID); + /* res = */ RegCloseKey(destKey); + } + } + } + } + + + #ifdef USE_7ZIP_32_DLL + + if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s)) + { + if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll")) + { + { + const LONG res = MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc); + if (res == ERROR_SUCCESS) + MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip); + } + + { + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++) + { + WCHAR destPath[MAX_PATH]; + CpyAscii(destPath, k_ShellEx_Items[i]); + CatAscii(destPath, "\\7-Zip"); + + MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath); + } + } + + { + HKEY destKey = 0; + const LONG res = MyRegistry_OpenKey_ReadWrite_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey); + if (res == ERROR_SUCCESS) + { + RegDeleteValueW(destKey, k_7zip_CLSID); + /* res = */ RegCloseKey(destKey); + } + } + } + } + + #endif + + + if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm, NULL, s)) + { + // RemoveQuotes(s); + if (AreEqual_Path_PrefixName(s, path, L"7zFM.exe")) + MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm); + } + + if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_Uninstall_7zip, L"UninstallString", s)) + { + RemoveQuotes(s); + if (AreEqual_Path_PrefixName(s, path, kUninstallExe)) + MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip); + } +} + + +static const wchar_t *GetCmdParam(const wchar_t *s) +{ + unsigned pos = 0; + BoolInt quoteMode = False; + for (;; s++) + { + const wchar_t c = *s; + if (c == 0 || (c == L' ' && !quoteMode)) + break; + if (c == L'\"') + { + quoteMode = !quoteMode; + continue; + } + if (pos >= Z7_ARRAY_SIZE(cmd) - 1) + exit(1); + cmd[pos++] = c; + } + cmd[pos] = 0; + return s; +} + +/* +static void RemoveQuotes(wchar_t *s) +{ + const wchar_t *src = s; + for (;;) + { + wchar_t c = *src++; + if (c == '\"') + continue; + *s++ = c; + if (c == 0) + return; + } +} +*/ + +static BoolInt DoesFileOrDirExist(void) +{ + return (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES); +} + +static BOOL RemoveFileAfterReboot2(const WCHAR *s) +{ + #ifndef UNDER_CE + return MoveFileExW(s, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); + #else + UNUSED_VAR(s) + return TRUE; + #endif +} + +static BOOL RemoveFileAfterReboot(void) +{ + return RemoveFileAfterReboot2(path); +} + +// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ') + +static BoolInt IsThereSpace(const wchar_t *s) +{ + for (;;) + { + const wchar_t c = *s++; + if (c == 0) + return False; + if (c == ' ') + return True; + } +} + +static void AddPathParam(wchar_t *dest, const wchar_t *src) +{ + const BoolInt needQuote = IsThereSpace(src); + if (needQuote) + CatAscii(dest, "\""); + wcscat(dest, src); + if (needQuote) + CatAscii(dest, "\""); +} + + + +static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message) +{ + LPWSTR msgBuf; + if (FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) + return False; + wcscpy(message, msgBuf); + LocalFree(msgBuf); + return True; +} + +static BOOL RemoveDir(void) +{ + const DWORD attrib = GetFileAttributesW(path); + if (attrib == INVALID_FILE_ATTRIBUTES) + return TRUE; + if (RemoveDirectoryW(path)) + return TRUE; + return RemoveFileAfterReboot(); +} + + + + + +#define k_Lang "Lang" + +// NUM_LANG_TXT_FILES files are placed before en.ttt +#define NUM_LANG_TXT_FILES 92 + +#ifdef USE_7ZIP_32_DLL + #define NUM_EXTRA_FILES_64BIT 1 +#else + #define NUM_EXTRA_FILES_64BIT 0 +#endif + +#define NUM_FILES (NUM_LANG_TXT_FILES + 1 + 13 + NUM_EXTRA_FILES_64BIT) + +static const char * const k_Names = + "af an ar ast az ba be bg bn br ca co cs cy da de el eo es et eu ext" + " fa fi fr fur fy ga gl gu he hi hr hu hy id io is it ja ka kaa kab kk ko ku ku-ckb ky" + " lij lt lv mk mn mng mng2 mr ms nb ne nl nn pa-in pl ps pt pt-br ro ru" + " sa si sk sl sq sr-spc sr-spl sv sw ta tg th tk tr tt ug uk uz uz-cyrl va vi yo zh-cn zh-tw" + " en.ttt" + " descript.ion" + " History.txt" + " License.txt" + " readme.txt" + " 7-zip.chm" + " 7z.sfx" + " 7zCon.sfx" + " 7z.exe" + " 7zG.exe" + " 7z.dll" + " 7zFM.exe" + #ifdef USE_7ZIP_32_DLL + " 7-zip32.dll" + #endif + " 7-zip.dll" + " Uninstall.exe"; + + + +static int Install(void) +{ + SRes res = SZ_OK; + WRes winRes = 0; + + // BoolInt needReboot = False; + const size_t pathLen = wcslen(path); + + if (!g_SilentMode) + { + ShowWindow(g_Progress_HWND, SW_SHOW); + ShowWindow(g_InfoLine_HWND, SW_SHOW); + SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, NUM_FILES); + } + + { + unsigned i; + const char *curName = k_Names; + + for (i = 0; *curName != 0; i++) + { + WCHAR *temp; + + if (!g_SilentMode) + { + MSG msg; + + // g_HWND + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (!IsDialogMessage(g_HWND, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (!g_HWND) + return 1; + } + + // Sleep(1); + SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); + } + + path[pathLen] = 0; + temp = path + pathLen; + + if (i <= NUM_LANG_TXT_FILES) + CpyAscii(temp, k_Lang "\\"); + + { + WCHAR *dest = temp + wcslen(temp); + + for (;;) + { + const char c = *curName; + if (c == 0) + break; + curName++; + if (c == ' ') + break; + *dest++ = (Byte)c; + } + + *dest = 0; + } + + if (i < NUM_LANG_TXT_FILES) + CatAscii(temp, ".txt"); + + if (!g_SilentMode) + SetWindowTextW(g_InfoLine_HWND, temp); + + { + const DWORD attrib = GetFileAttributesW(path); + if (attrib == INVALID_FILE_ATTRIBUTES) + continue; + if (attrib & FILE_ATTRIBUTE_READONLY) + SetFileAttributesW(path, 0); + if (!DeleteFileW(path)) + { + if (!RemoveFileAfterReboot()) + { + winRes = GetLastError(); + } + /* + else + needReboot = True; + */ + } + } + } + + CpyAscii(path + pathLen, k_Lang); + RemoveDir(); + + path[pathLen] = 0; + RemoveDir(); + + if (!g_SilentMode) + SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0); + + if (*curName == 0) + { + SetRegKey_Path(); + WriteCLSID(); + SetShellProgramsGroup(g_HWND); + if (!g_SilentMode) + SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is uninstalled"); + } + } + + if (winRes != 0) + res = SZ_ERROR_FAIL; + + if (res == SZ_OK) + { + // if (!g_SilentMode && needReboot); + return 0; + } + + if (!g_SilentMode) + { + WCHAR m[MAX_PATH + 100]; + m[0] = 0; + if (winRes == 0 || !GetErrorMessage(winRes, m)) + CpyAscii(m, "ERROR"); + PrintErrorMessage("System ERROR:", m); + } + + return 1; +} + + +static void OnClose(void) +{ + if (g_Install_was_Pressed && !g_Finished) + { + if (MessageBoxW(g_HWND, + L"Do you want to cancel uninstallation?", + k_7zip_with_Ver_Uninstall, + MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES) + return; + } + DestroyWindow(g_HWND); + g_HWND = NULL; +} + +static +#ifdef Z7_OLD_WIN_SDK + BOOL +#else + INT_PTR +#endif +CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + UNUSED_VAR(lParam) + + switch (message) + { + case WM_INITDIALOG: + g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH); + g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE); + g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS); + + SetWindowTextW(hwnd, k_7zip_with_Ver_Uninstall); + SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path); + + ShowWindow(g_Progress_HWND, SW_HIDE); + ShowWindow(g_InfoLine_HWND, SW_HIDE); + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + if (g_Finished) + { + OnClose(); + break; + } + if (!g_Install_was_Pressed) + { + SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE); + + EnableWindow(g_Path_HWND, FALSE); + EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); + + g_Install_was_Pressed = True; + return TRUE; + } + break; + } + + case IDCANCEL: + { + OnClose(); + break; + } + + default: return FALSE; + } + break; + + case WM_CLOSE: + OnClose(); + break; + /* + case WM_DESTROY: + PostQuitMessage(0); + return TRUE; + */ + default: + return FALSE; + } + + return TRUE; +} + + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + lpCmdLine, int nCmdShow) +{ + const wchar_t *cmdParams; + BoolInt useTemp = True; + + UNUSED_VAR(hPrevInstance) + UNUSED_VAR(lpCmdLine) + UNUSED_VAR(nCmdShow) + +#ifndef UNDER_CE + CoInitialize(NULL); +#endif + +#ifndef UNDER_CE +#ifdef Z7_USE_DYN_RegDeleteKeyExW + func_RegDeleteKeyExW = + (Func_RegDeleteKeyExW) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandleW(L"advapi32.dll"), + "RegDeleteKeyExW"); +#endif +#endif + + { + const wchar_t *s = GetCommandLineW(); + + #ifndef UNDER_CE + s = GetCmdParam(s); + #endif + + cmdParams = s; + + for (;;) + { + { + wchar_t c = *s; + if (c == 0) + break; + if (c == ' ') + { + s++; + continue; + } + } + + { + const wchar_t *s2 = GetCmdParam(s); + BoolInt error = True; + if (cmd[0] == '/') + { + if (cmd[1] == 'S') + { + if (cmd[2] == 0) + { + g_SilentMode = True; + error = False; + } + } + else if (cmd[1] == 'N') + { + if (cmd[2] == 0) + { + useTemp = False; + error = False; + } + } + else if (cmd[1] == 'D' && cmd[2] == '=') + { + wcscpy(workDir, cmd + 3); + // RemoveQuotes(workDir); + useTemp = False; + error = False; + } + } + s = s2; + if (error && cmdError[0] == 0) + wcscpy(cmdError, cmd); + } + } + + if (cmdError[0] != 0) + { + if (!g_SilentMode) + PrintErrorMessage("Unsupported command:", cmdError); + return 1; + } + } + + { + wchar_t *name; + const DWORD len = GetModuleFileNameW(NULL, modulePath, MAX_PATH); + if (len == 0 || len > MAX_PATH) + return 1; + + name = NULL; + wcscpy(modulePrefix, modulePath); + + { + wchar_t *s = modulePrefix; + for (;;) + { + const wchar_t c = *s++; + if (c == 0) + break; + if (c == WCHAR_PATH_SEPARATOR) + name = s; + } + } + + if (!name) + return 1; + + if (!AreStringsEqual_NoCase(name, kUninstallExe)) + useTemp = False; + + *name = 0; // keep only prefix for modulePrefix + } + + + if (useTemp) + { + DWORD winRes = GetTempPathW(MAX_PATH, path); + + // GetTempPath: the returned string ends with a backslash + /* + { + WCHAR s[MAX_PATH + 1]; + wcscpy(s, path); + GetLongPathNameW(s, path, MAX_PATH); + } + */ + + if (winRes != 0 && winRes <= MAX_PATH + 1 + && !IsString1PrefixedByString2_NoCase(modulePrefix, path)) + { + unsigned i; + DWORD d; + + const size_t pathLen = wcslen(path); + d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + + for (i = 0; i < 100; i++, d += GetTickCount()) + { + CpyAscii(path + pathLen, "7z"); + + { + wchar_t *s = path + wcslen(path); + UInt32 value = d; + unsigned k; + for (k = 0; k < 8; k++) + { + const unsigned t = value & 0xF; + value >>= 4; + s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } + s[k] = 0; + } + + if (DoesFileOrDirExist()) + continue; + if (CreateDirectoryW(path, NULL)) + { + CatAscii(path, STRING_PATH_SEPARATOR); + wcscpy(tempPath, path); + break; + } + if (GetLastError() != ERROR_ALREADY_EXISTS) + break; + } + + if (tempPath[0] != 0) + { + wcscpy(copyPath, tempPath); + CatAscii(copyPath, "Uninst.exe"); // we need not "Uninstall.exe" here + + if (CopyFileW(modulePath, copyPath, TRUE)) + { + RemoveFileAfterReboot2(copyPath); + RemoveFileAfterReboot2(tempPath); + + { + STARTUPINFOW si; + PROCESS_INFORMATION pi; + cmdLine[0] = 0; + + // maybe CreateProcess supports path with spaces even without quotes. + AddPathParam(cmdLine, copyPath); + CatAscii(cmdLine, " /N /D="); + AddPathParam(cmdLine, modulePrefix); + + if (cmdParams[0] != 0 && wcslen(cmdParams) < MAX_PATH * 2 + 10) + wcscat(cmdLine, cmdParams); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, tempPath, &si, &pi)) + { + CloseHandle(pi.hThread); + if (pi.hProcess) + { + CloseHandle(pi.hProcess); + return 0; + } + } + } + } + } + } + } + + wcscpy(path, modulePrefix); + + if (workDir[0] != 0) + { + wcscpy(path, workDir); + NormalizePrefix(path); + } + + /* + if (path[0] == 0) + { + HKEY key = 0; + BoolInt ok = False; + LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key); + if (res == ERROR_SUCCESS) + { + ok = MyRegistry_QueryString(key, k_Reg_Path32, path); + // ok = MyRegistry_QueryString(key, k_Reg_Path, path); + RegCloseKey(key); + } + } + */ + + + if (g_SilentMode) + return Install(); + + { + int retCode = 1; + g_HWND = CreateDialog( + hInstance, + // GetModuleHandle(NULL), + MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc); + if (!g_HWND) + return 1; + + { + const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON)); + // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon); + SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon); + } + + { + BOOL bRet; + MSG msg; + + while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) + { + if (bRet == -1) + return retCode; + if (!g_HWND) + return retCode; + + if (!IsDialogMessage(g_HWND, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (!g_HWND) + return retCode; + + if (g_Install_was_Pressed && !g_Finished) + { + retCode = Install(); + g_Finished = True; + if (retCode != 0) + break; + if (!g_HWND) + break; + { + SetDlgItemTextW(g_HWND, IDOK, L"Close"); + EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE); + EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE); + SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE); + } + } + } + + if (g_HWND) + { + DestroyWindow(g_HWND); + g_HWND = NULL; + } + } + + return retCode; + } +} diff --git a/C/Util/7zipUninstall/7zipUninstall.dsp b/C/Util/7zipUninstall/7zipUninstall.dsp index f4083a05c..bb7473fc2 100644 --- a/C/Util/7zipUninstall/7zipUninstall.dsp +++ b/C/Util/7zipUninstall/7zipUninstall.dsp @@ -1,132 +1,132 @@ -# Microsoft Developer Studio Project File - Name="7zipUninstall" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=7zipUninstall - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "7zipUninstall.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "7zipUninstall.mak" CFG="7zipUninstall - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "7zipUninstall - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "7zipUninstall - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "7zipUninstall - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /FAcs /Yu"Precomp.h" /FD /GF /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/Uninstall.exe" - -!ELSEIF "$(CFG)" == "7zipUninstall - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/Uninstall.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "7zipUninstall - Win32 Release" -# Name "7zipUninstall - Win32 Debug" -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zVersion.h -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compiler.h -# End Source File -# Begin Source File - -SOURCE=.\Precomp.c -# ADD CPP /Yc"Precomp.h" -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7zipUninstall.c -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="7zipUninstall" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=7zipUninstall - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "7zipUninstall.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "7zipUninstall.mak" CFG="7zipUninstall - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "7zipUninstall - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "7zipUninstall - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "7zipUninstall - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /FAcs /Yu"Precomp.h" /FD /GF /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/Uninstall.exe" + +!ELSEIF "$(CFG)" == "7zipUninstall - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/Uninstall.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "7zipUninstall - Win32 Release" +# Name "7zipUninstall - Win32 Debug" +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zVersion.h +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compiler.h +# End Source File +# Begin Source File + +SOURCE=.\Precomp.c +# ADD CPP /Yc"Precomp.h" +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7zipUninstall.c +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# End Target +# End Project diff --git a/C/Util/7zipUninstall/7zipUninstall.dsw b/C/Util/7zipUninstall/7zipUninstall.dsw index a26aafe6b..2873eda6a 100644 --- a/C/Util/7zipUninstall/7zipUninstall.dsw +++ b/C/Util/7zipUninstall/7zipUninstall.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "7zipUninstall"=.\7zipUninstall.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "7zipUninstall"=.\7zipUninstall.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/C/Util/7zipUninstall/7zipUninstall.manifest b/C/Util/7zipUninstall/7zipUninstall.manifest index e4bafc4af..a60144340 100644 --- a/C/Util/7zipUninstall/7zipUninstall.manifest +++ b/C/Util/7zipUninstall/7zipUninstall.manifest @@ -1,18 +1,18 @@ - - - -7-Zip Uninstaller - - - - - - - - - - - - -true - + + + +7-Zip Uninstaller + + + + + + + + + + + + +true + diff --git a/C/Util/7zipUninstall/Precomp.c b/C/Util/7zipUninstall/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/7zipUninstall/Precomp.c +++ b/C/Util/7zipUninstall/Precomp.c @@ -1,4 +1,4 @@ -/* Precomp.c -- StdAfx -2013-01-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" +/* Precomp.c -- StdAfx +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" diff --git a/C/Util/7zipUninstall/Precomp.h b/C/Util/7zipUninstall/Precomp.h index 52b87ea64..13a41eff2 100644 --- a/C/Util/7zipUninstall/Precomp.h +++ b/C/Util/7zipUninstall/Precomp.h @@ -1,13 +1,13 @@ -/* Precomp.h -- Precomp -2024-01-23 : Igor Pavlov : Public domain */ - -// #ifndef ZIP7_INC_PRECOMP_LOC_H -// #define ZIP7_INC_PRECOMP_LOC_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../Precomp.h" - -// #endif +/* Precomp.h -- Precomp +2024-01-23 : Igor Pavlov : Public domain */ + +// #ifndef ZIP7_INC_PRECOMP_LOC_H +// #define ZIP7_INC_PRECOMP_LOC_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../Precomp.h" + +// #endif diff --git a/C/Util/7zipUninstall/makefile b/C/Util/7zipUninstall/makefile index ecc8a8f03..9d8aafca7 100644 --- a/C/Util/7zipUninstall/makefile +++ b/C/Util/7zipUninstall/makefile @@ -1,18 +1,18 @@ -PROG = 7zipUninstall.exe -MY_FIXED = 1 - -!IFDEF Z7_64BIT_INSTALLER -CFLAGS = $(CFLAGS) -DZ7_64BIT_INSTALLER -!ENDIF - -MAIN_OBJS = \ - $O\7zipUninstall.obj \ - -OBJS = \ - $(MAIN_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(MAIN_OBJS): $(*B).c - $(COMPL_O1) +PROG = 7zipUninstall.exe +MY_FIXED = 1 + +!IFDEF Z7_64BIT_INSTALLER +CFLAGS = $(CFLAGS) -DZ7_64BIT_INSTALLER +!ENDIF + +MAIN_OBJS = \ + $O\7zipUninstall.obj \ + +OBJS = \ + $(MAIN_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(MAIN_OBJS): $(*B).c + $(COMPL_O1) diff --git a/C/Util/7zipUninstall/resource.h b/C/Util/7zipUninstall/resource.h index dfbb7c638..b5c33ff1f 100644 --- a/C/Util/7zipUninstall/resource.h +++ b/C/Util/7zipUninstall/resource.h @@ -1,9 +1,9 @@ -#define IDD_INSTALL 100 - -#define IDT_EXTRACT_EXTRACT_TO 110 -#define IDE_EXTRACT_PATH 111 - -#define IDT_CUR_FILE 113 -#define IDC_PROGRESS 114 - -#define IDI_ICON 1 +#define IDD_INSTALL 100 + +#define IDT_EXTRACT_EXTRACT_TO 110 +#define IDE_EXTRACT_PATH 111 + +#define IDT_CUR_FILE 113 +#define IDC_PROGRESS 114 + +#define IDI_ICON 1 diff --git a/C/Util/7zipUninstall/resource.rc b/C/Util/7zipUninstall/resource.rc index 66b12b139..79400c674 100644 --- a/C/Util/7zipUninstall/resource.rc +++ b/C/Util/7zipUninstall/resource.rc @@ -1,48 +1,48 @@ -#include -// #include -// #include -#include - -#define USE_COPYRIGHT_CR -#include "../../7zVersion.rc" -#include "resource.h" - -MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller", "Uninstall", "Uninstall.exe") - -1 ICON "7zipUninstall.ico" - -#define xc 184 -#define yc 96 - -#define m 8 -#define bxs 64 -#define bys 16 - - -#define xs (xc + m + m) -#define ys (yc + m + m) - -#define bx1 (xs - m - bxs) -#define bx2 (bx1 - m - bxs) - -#define by (ys - m - bys) - -IDD_INSTALL DIALOG 0, 0, xs, ys -STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE -CAPTION "Uninstall 7-Zip" -FONT 8, "MS Shell Dlg" -BEGIN - LTEXT "Uninstall from:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 - EDITTEXT IDE_EXTRACT_PATH, m, 21, xc, 14, ES_AUTOHSCROLL | WS_DISABLED - - - LTEXT "", IDT_CUR_FILE, m, 50, xc, 8 - CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10 - - DEFPUSHBUTTON "&Uninstall", IDOK, bx2, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -END - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "7zipUninstall.manifest" -#endif +#include +// #include +// #include +#include + +#define USE_COPYRIGHT_CR +#include "../../7zVersion.rc" +#include "resource.h" + +MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller", "Uninstall", "Uninstall.exe") + +1 ICON "7zipUninstall.ico" + +#define xc 184 +#define yc 96 + +#define m 8 +#define bxs 64 +#define bys 16 + + +#define xs (xc + m + m) +#define ys (yc + m + m) + +#define bx1 (xs - m - bxs) +#define bx2 (bx1 - m - bxs) + +#define by (ys - m - bys) + +IDD_INSTALL DIALOG 0, 0, xs, ys +STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE +CAPTION "Uninstall 7-Zip" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Uninstall from:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 + EDITTEXT IDE_EXTRACT_PATH, m, 21, xc, 14, ES_AUTOHSCROLL | WS_DISABLED + + + LTEXT "", IDT_CUR_FILE, m, 50, xc, 8 + CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10 + + DEFPUSHBUTTON "&Uninstall", IDOK, bx2, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys +END + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "7zipUninstall.manifest" +#endif diff --git a/C/Util/Lzma/LzmaUtil.c b/C/Util/Lzma/LzmaUtil.c index 2c8208551..b9b974bd1 100644 --- a/C/Util/Lzma/LzmaUtil.c +++ b/C/Util/Lzma/LzmaUtil.c @@ -1,313 +1,313 @@ -/* LzmaUtil.c -- Test application for LZMA compression -2023-03-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include -#include -#include - -#include "../../CpuArch.h" - -#include "../../Alloc.h" -#include "../../7zFile.h" -#include "../../7zVersion.h" -#include "../../LzFind.h" -#include "../../LzmaDec.h" -#include "../../LzmaEnc.h" - -static const char * const kCantReadMessage = "Cannot read input file"; -static const char * const kCantWriteMessage = "Cannot write output file"; -static const char * const kCantAllocateMessage = "Cannot allocate memory"; -static const char * const kDataErrorMessage = "Data error"; - -static void Print(const char *s) -{ - fputs(s, stdout); -} - -static void PrintHelp(void) -{ - Print( - "\n" "LZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE - "\n" - "\n" "Usage: lzma inputFile outputFile" - "\n" " e: encode file" - "\n" " d: decode file" - "\n"); -} - -static int PrintError(const char *message) -{ - Print("\nError: "); - Print(message); - Print("\n"); - return 1; -} - -#define CONVERT_INT_TO_STR(charType, tempSize) \ - unsigned char temp[tempSize]; unsigned i = 0; \ - while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ - *s++ = (charType)('0' + (unsigned)val); \ - while (i != 0) { i--; *s++ = (charType)temp[i]; } \ - *s = 0; \ - return s; - -static char * Convert_unsigned_To_str(unsigned val, char *s) -{ - CONVERT_INT_TO_STR(char, 32) -} - -static void Print_unsigned(unsigned code) -{ - char str[32]; - Convert_unsigned_To_str(code, str); - Print(str); -} - -static int PrintError_WRes(const char *message, WRes wres) -{ - PrintError(message); - Print("\nSystem error code: "); - Print_unsigned((unsigned)wres); - #ifndef _WIN32 - { - const char *s = strerror(wres); - if (s) - { - Print(" : "); - Print(s); - } - } - #endif - Print("\n"); - return 1; -} - -static int PrintErrorNumber(SRes val) -{ - Print("\n7-Zip error code: "); - Print_unsigned((unsigned)val); - Print("\n"); - return 1; -} - -static int PrintUserError(void) -{ - return PrintError("Incorrect command"); -} - - -#define IN_BUF_SIZE (1 << 16) -#define OUT_BUF_SIZE (1 << 16) - - -static SRes Decode2(CLzmaDec *state, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, - UInt64 unpackSize) -{ - const int thereIsSize = (unpackSize != (UInt64)(Int64)-1); - Byte inBuf[IN_BUF_SIZE]; - Byte outBuf[OUT_BUF_SIZE]; - size_t inPos = 0, inSize = 0, outPos = 0; - LzmaDec_Init(state); - for (;;) - { - if (inPos == inSize) - { - inSize = IN_BUF_SIZE; - RINOK(inStream->Read(inStream, inBuf, &inSize)) - inPos = 0; - } - { - SRes res; - SizeT inProcessed = inSize - inPos; - SizeT outProcessed = OUT_BUF_SIZE - outPos; - ELzmaFinishMode finishMode = LZMA_FINISH_ANY; - ELzmaStatus status; - if (thereIsSize && outProcessed > unpackSize) - { - outProcessed = (SizeT)unpackSize; - finishMode = LZMA_FINISH_END; - } - - res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed, - inBuf + inPos, &inProcessed, finishMode, &status); - inPos += inProcessed; - outPos += outProcessed; - unpackSize -= outProcessed; - - if (outStream) - if (outStream->Write(outStream, outBuf, outPos) != outPos) - return SZ_ERROR_WRITE; - - outPos = 0; - - if (res != SZ_OK || (thereIsSize && unpackSize == 0)) - return res; - - if (inProcessed == 0 && outProcessed == 0) - { - if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK) - return SZ_ERROR_DATA; - return res; - } - } - } -} - - -static SRes Decode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream) -{ - UInt64 unpackSize; - int i; - SRes res = 0; - - CLzmaDec state; - - /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */ - unsigned char header[LZMA_PROPS_SIZE + 8]; - - /* Read and parse header */ - - { - size_t size = sizeof(header); - RINOK(SeqInStream_ReadMax(inStream, header, &size)) - if (size != sizeof(header)) - return SZ_ERROR_INPUT_EOF; - } - unpackSize = 0; - for (i = 0; i < 8; i++) - unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8); - - LzmaDec_CONSTRUCT(&state) - RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc)) - res = Decode2(&state, outStream, inStream, unpackSize); - LzmaDec_Free(&state, &g_Alloc); - return res; -} - -static SRes Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, UInt64 fileSize) -{ - CLzmaEncHandle enc; - SRes res; - CLzmaEncProps props; - - enc = LzmaEnc_Create(&g_Alloc); - if (enc == 0) - return SZ_ERROR_MEM; - - LzmaEncProps_Init(&props); - res = LzmaEnc_SetProps(enc, &props); - - if (res == SZ_OK) - { - Byte header[LZMA_PROPS_SIZE + 8]; - size_t headerSize = LZMA_PROPS_SIZE; - int i; - - res = LzmaEnc_WriteProperties(enc, header, &headerSize); - for (i = 0; i < 8; i++) - header[headerSize++] = (Byte)(fileSize >> (8 * i)); - if (outStream->Write(outStream, header, headerSize) != headerSize) - res = SZ_ERROR_WRITE; - else - { - if (res == SZ_OK) - res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc); - } - } - LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); - return res; -} - - -int Z7_CDECL main(int numArgs, const char *args[]) -{ - CFileSeqInStream inStream; - CFileOutStream outStream; - char c; - int res; - int encodeMode; - BoolInt useOutFile = False; - - LzFindPrepare(); - - FileSeqInStream_CreateVTable(&inStream); - File_Construct(&inStream.file); - inStream.wres = 0; - - FileOutStream_CreateVTable(&outStream); - File_Construct(&outStream.file); - outStream.wres = 0; - - if (numArgs == 1) - { - PrintHelp(); - return 0; - } - - if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1) - return PrintUserError(); - - c = args[1][0]; - encodeMode = (c == 'e' || c == 'E'); - if (!encodeMode && c != 'd' && c != 'D') - return PrintUserError(); - - /* - { - size_t t4 = sizeof(UInt32); - size_t t8 = sizeof(UInt64); - if (t4 != 4 || t8 != 8) - return PrintError("Incorrect UInt32 or UInt64"); - } - */ - - { - const WRes wres = InFile_Open(&inStream.file, args[2]); - if (wres != 0) - return PrintError_WRes("Cannot open input file", wres); - } - - if (numArgs > 3) - { - WRes wres; - useOutFile = True; - wres = OutFile_Open(&outStream.file, args[3]); - if (wres != 0) - return PrintError_WRes("Cannot open output file", wres); - } - else if (encodeMode) - PrintUserError(); - - if (encodeMode) - { - UInt64 fileSize; - const WRes wres = File_GetLength(&inStream.file, &fileSize); - if (wres != 0) - return PrintError_WRes("Cannot get file length", wres); - res = Encode(&outStream.vt, &inStream.vt, fileSize); - } - else - { - res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL); - } - - if (useOutFile) - File_Close(&outStream.file); - File_Close(&inStream.file); - - if (res != SZ_OK) - { - if (res == SZ_ERROR_MEM) - return PrintError(kCantAllocateMessage); - else if (res == SZ_ERROR_DATA) - return PrintError(kDataErrorMessage); - else if (res == SZ_ERROR_WRITE) - return PrintError_WRes(kCantWriteMessage, outStream.wres); - else if (res == SZ_ERROR_READ) - return PrintError_WRes(kCantReadMessage, inStream.wres); - return PrintErrorNumber(res); - } - return 0; -} +/* LzmaUtil.c -- Test application for LZMA compression +2023-03-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include +#include + +#include "../../CpuArch.h" + +#include "../../Alloc.h" +#include "../../7zFile.h" +#include "../../7zVersion.h" +#include "../../LzFind.h" +#include "../../LzmaDec.h" +#include "../../LzmaEnc.h" + +static const char * const kCantReadMessage = "Cannot read input file"; +static const char * const kCantWriteMessage = "Cannot write output file"; +static const char * const kCantAllocateMessage = "Cannot allocate memory"; +static const char * const kDataErrorMessage = "Data error"; + +static void Print(const char *s) +{ + fputs(s, stdout); +} + +static void PrintHelp(void) +{ + Print( + "\n" "LZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE + "\n" + "\n" "Usage: lzma inputFile outputFile" + "\n" " e: encode file" + "\n" " d: decode file" + "\n"); +} + +static int PrintError(const char *message) +{ + Print("\nError: "); + Print(message); + Print("\n"); + return 1; +} + +#define CONVERT_INT_TO_STR(charType, tempSize) \ + unsigned char temp[tempSize]; unsigned i = 0; \ + while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ + *s++ = (charType)('0' + (unsigned)val); \ + while (i != 0) { i--; *s++ = (charType)temp[i]; } \ + *s = 0; \ + return s; + +static char * Convert_unsigned_To_str(unsigned val, char *s) +{ + CONVERT_INT_TO_STR(char, 32) +} + +static void Print_unsigned(unsigned code) +{ + char str[32]; + Convert_unsigned_To_str(code, str); + Print(str); +} + +static int PrintError_WRes(const char *message, WRes wres) +{ + PrintError(message); + Print("\nSystem error code: "); + Print_unsigned((unsigned)wres); + #ifndef _WIN32 + { + const char *s = strerror(wres); + if (s) + { + Print(" : "); + Print(s); + } + } + #endif + Print("\n"); + return 1; +} + +static int PrintErrorNumber(SRes val) +{ + Print("\n7-Zip error code: "); + Print_unsigned((unsigned)val); + Print("\n"); + return 1; +} + +static int PrintUserError(void) +{ + return PrintError("Incorrect command"); +} + + +#define IN_BUF_SIZE (1 << 16) +#define OUT_BUF_SIZE (1 << 16) + + +static SRes Decode2(CLzmaDec *state, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + UInt64 unpackSize) +{ + const int thereIsSize = (unpackSize != (UInt64)(Int64)-1); + Byte inBuf[IN_BUF_SIZE]; + Byte outBuf[OUT_BUF_SIZE]; + size_t inPos = 0, inSize = 0, outPos = 0; + LzmaDec_Init(state); + for (;;) + { + if (inPos == inSize) + { + inSize = IN_BUF_SIZE; + RINOK(inStream->Read(inStream, inBuf, &inSize)) + inPos = 0; + } + { + SRes res; + SizeT inProcessed = inSize - inPos; + SizeT outProcessed = OUT_BUF_SIZE - outPos; + ELzmaFinishMode finishMode = LZMA_FINISH_ANY; + ELzmaStatus status; + if (thereIsSize && outProcessed > unpackSize) + { + outProcessed = (SizeT)unpackSize; + finishMode = LZMA_FINISH_END; + } + + res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed, + inBuf + inPos, &inProcessed, finishMode, &status); + inPos += inProcessed; + outPos += outProcessed; + unpackSize -= outProcessed; + + if (outStream) + if (outStream->Write(outStream, outBuf, outPos) != outPos) + return SZ_ERROR_WRITE; + + outPos = 0; + + if (res != SZ_OK || (thereIsSize && unpackSize == 0)) + return res; + + if (inProcessed == 0 && outProcessed == 0) + { + if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK) + return SZ_ERROR_DATA; + return res; + } + } + } +} + + +static SRes Decode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream) +{ + UInt64 unpackSize; + int i; + SRes res = 0; + + CLzmaDec state; + + /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */ + unsigned char header[LZMA_PROPS_SIZE + 8]; + + /* Read and parse header */ + + { + size_t size = sizeof(header); + RINOK(SeqInStream_ReadMax(inStream, header, &size)) + if (size != sizeof(header)) + return SZ_ERROR_INPUT_EOF; + } + unpackSize = 0; + for (i = 0; i < 8; i++) + unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8); + + LzmaDec_CONSTRUCT(&state) + RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc)) + res = Decode2(&state, outStream, inStream, unpackSize); + LzmaDec_Free(&state, &g_Alloc); + return res; +} + +static SRes Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, UInt64 fileSize) +{ + CLzmaEncHandle enc; + SRes res; + CLzmaEncProps props; + + enc = LzmaEnc_Create(&g_Alloc); + if (enc == 0) + return SZ_ERROR_MEM; + + LzmaEncProps_Init(&props); + res = LzmaEnc_SetProps(enc, &props); + + if (res == SZ_OK) + { + Byte header[LZMA_PROPS_SIZE + 8]; + size_t headerSize = LZMA_PROPS_SIZE; + int i; + + res = LzmaEnc_WriteProperties(enc, header, &headerSize); + for (i = 0; i < 8; i++) + header[headerSize++] = (Byte)(fileSize >> (8 * i)); + if (outStream->Write(outStream, header, headerSize) != headerSize) + res = SZ_ERROR_WRITE; + else + { + if (res == SZ_OK) + res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc); + } + } + LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); + return res; +} + + +int Z7_CDECL main(int numArgs, const char *args[]) +{ + CFileSeqInStream inStream; + CFileOutStream outStream; + char c; + int res; + int encodeMode; + BoolInt useOutFile = False; + + LzFindPrepare(); + + FileSeqInStream_CreateVTable(&inStream); + File_Construct(&inStream.file); + inStream.wres = 0; + + FileOutStream_CreateVTable(&outStream); + File_Construct(&outStream.file); + outStream.wres = 0; + + if (numArgs == 1) + { + PrintHelp(); + return 0; + } + + if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1) + return PrintUserError(); + + c = args[1][0]; + encodeMode = (c == 'e' || c == 'E'); + if (!encodeMode && c != 'd' && c != 'D') + return PrintUserError(); + + /* + { + size_t t4 = sizeof(UInt32); + size_t t8 = sizeof(UInt64); + if (t4 != 4 || t8 != 8) + return PrintError("Incorrect UInt32 or UInt64"); + } + */ + + { + const WRes wres = InFile_Open(&inStream.file, args[2]); + if (wres != 0) + return PrintError_WRes("Cannot open input file", wres); + } + + if (numArgs > 3) + { + WRes wres; + useOutFile = True; + wres = OutFile_Open(&outStream.file, args[3]); + if (wres != 0) + return PrintError_WRes("Cannot open output file", wres); + } + else if (encodeMode) + PrintUserError(); + + if (encodeMode) + { + UInt64 fileSize; + const WRes wres = File_GetLength(&inStream.file, &fileSize); + if (wres != 0) + return PrintError_WRes("Cannot get file length", wres); + res = Encode(&outStream.vt, &inStream.vt, fileSize); + } + else + { + res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL); + } + + if (useOutFile) + File_Close(&outStream.file); + File_Close(&inStream.file); + + if (res != SZ_OK) + { + if (res == SZ_ERROR_MEM) + return PrintError(kCantAllocateMessage); + else if (res == SZ_ERROR_DATA) + return PrintError(kDataErrorMessage); + else if (res == SZ_ERROR_WRITE) + return PrintError_WRes(kCantWriteMessage, outStream.wres); + else if (res == SZ_ERROR_READ) + return PrintError_WRes(kCantReadMessage, inStream.wres); + return PrintErrorNumber(res); + } + return 0; +} diff --git a/C/Util/Lzma/LzmaUtil.dsp b/C/Util/Lzma/LzmaUtil.dsp index 0815eb56c..e2e7d4282 100644 --- a/C/Util/Lzma/LzmaUtil.dsp +++ b/C/Util/Lzma/LzmaUtil.dsp @@ -1,188 +1,188 @@ -# Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=LzmaUtil - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "LzmaUtil.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "LzmaUtil - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe" - -!ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "LzmaUtil - Win32 Release" -# Name "LzmaUtil - Win32 Debug" -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=.\LzmaUtil.c -# End Source File -# Begin Source File - -SOURCE=..\..\Precomp.h -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.c -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=LzmaUtil - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LzmaUtil.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LzmaUtil - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe" + +!ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "LzmaUtil - Win32 Release" +# Name "LzmaUtil - Win32 Debug" +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=.\LzmaUtil.c +# End Source File +# Begin Source File + +SOURCE=..\..\Precomp.h +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.h +# End Source File +# End Target +# End Project diff --git a/C/Util/Lzma/LzmaUtil.dsw b/C/Util/Lzma/LzmaUtil.dsw index f43548752..c52eaf6d0 100644 --- a/C/Util/Lzma/LzmaUtil.dsw +++ b/C/Util/Lzma/LzmaUtil.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/C/Util/Lzma/Precomp.h b/C/Util/Lzma/Precomp.h index 52b87ea64..13a41eff2 100644 --- a/C/Util/Lzma/Precomp.h +++ b/C/Util/Lzma/Precomp.h @@ -1,13 +1,13 @@ -/* Precomp.h -- Precomp -2024-01-23 : Igor Pavlov : Public domain */ - -// #ifndef ZIP7_INC_PRECOMP_LOC_H -// #define ZIP7_INC_PRECOMP_LOC_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../Precomp.h" - -// #endif +/* Precomp.h -- Precomp +2024-01-23 : Igor Pavlov : Public domain */ + +// #ifndef ZIP7_INC_PRECOMP_LOC_H +// #define ZIP7_INC_PRECOMP_LOC_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../Precomp.h" + +// #endif diff --git a/C/Util/Lzma/makefile b/C/Util/Lzma/makefile index 9d971f666..7813bdb05 100644 --- a/C/Util/Lzma/makefile +++ b/C/Util/Lzma/makefile @@ -1,30 +1,30 @@ -# MY_STATIC_LINK=1 -PROG = LZMAc.exe - -CFLAGS = $(CFLAGS) \ - -LIB_OBJS = \ - $O\LzmaUtil.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\LzFindOpt.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\7zFile.obj \ - $O\7zStream.obj \ - $O\Threads.obj \ - -OBJS = \ - $(LIB_OBJS) \ - $(C_OBJS) \ - -!include "../../../CPP/Build.mak" - -$(LIB_OBJS): $(*B).c - $(COMPL_O2) -$(C_OBJS): ../../$(*B).c - $(COMPL_O2) +# MY_STATIC_LINK=1 +PROG = LZMAc.exe + +CFLAGS = $(CFLAGS) \ + +LIB_OBJS = \ + $O\LzmaUtil.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\LzFindOpt.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\7zFile.obj \ + $O\7zStream.obj \ + $O\Threads.obj \ + +OBJS = \ + $(LIB_OBJS) \ + $(C_OBJS) \ + +!include "../../../CPP/Build.mak" + +$(LIB_OBJS): $(*B).c + $(COMPL_O2) +$(C_OBJS): ../../$(*B).c + $(COMPL_O2) diff --git a/C/Util/Lzma/makefile.gcc b/C/Util/Lzma/makefile.gcc index 6ce77a0f2..2acb0b808 100644 --- a/C/Util/Lzma/makefile.gcc +++ b/C/Util/Lzma/makefile.gcc @@ -1,21 +1,21 @@ -PROG = 7lzma - -include ../../../CPP/7zip/LzmaDec_gcc.mak - - -OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $O/7zFile.o \ - $O/7zStream.o \ - $O/Alloc.o \ - $O/CpuArch.o \ - $O/LzFind.o \ - $O/LzFindMt.o \ - $O/LzFindOpt.o \ - $O/LzmaDec.o \ - $O/LzmaEnc.o \ - $O/LzmaUtil.o \ - $O/Threads.o \ - - -include ../../7zip_gcc_c.mak +PROG = 7lzma + +include ../../../CPP/7zip/LzmaDec_gcc.mak + + +OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $O/7zFile.o \ + $O/7zStream.o \ + $O/Alloc.o \ + $O/CpuArch.o \ + $O/LzFind.o \ + $O/LzFindMt.o \ + $O/LzFindOpt.o \ + $O/LzmaDec.o \ + $O/LzmaEnc.o \ + $O/LzmaUtil.o \ + $O/Threads.o \ + + +include ../../7zip_gcc_c.mak diff --git a/C/Util/LzmaLib/LzmaLib.def b/C/Util/LzmaLib/LzmaLib.def index 43b959778..8bc6add93 100644 --- a/C/Util/LzmaLib/LzmaLib.def +++ b/C/Util/LzmaLib/LzmaLib.def @@ -1,4 +1,4 @@ -EXPORTS - LzmaCompress - LzmaUncompress - +EXPORTS + LzmaCompress + LzmaUncompress + diff --git a/C/Util/LzmaLib/LzmaLib.dsp b/C/Util/LzmaLib/LzmaLib.dsp index 431c0241b..bacd96793 100644 --- a/C/Util/LzmaLib/LzmaLib.dsp +++ b/C/Util/LzmaLib/LzmaLib.dsp @@ -1,202 +1,202 @@ -# Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=LzmaLib - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "LzmaLib.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "LzmaLib - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "LzmaLib - Win32 Release" -# Name "LzmaLib - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\LzmaLib.def -# End Source File -# Begin Source File - -SOURCE=.\LzmaLibExports.c -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzFindOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaLib.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaLib.h -# End Source File -# Begin Source File - -SOURCE=..\..\Precomp.h -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.c -# End Source File -# Begin Source File - -SOURCE=..\..\Threads.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=LzmaLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LzmaLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LzmaLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "LzmaLib - Win32 Release" +# Name "LzmaLib - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\LzmaLib.def +# End Source File +# Begin Source File + +SOURCE=.\LzmaLibExports.c +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzFindOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaLib.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaLib.h +# End Source File +# Begin Source File + +SOURCE=..\..\Precomp.h +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.c +# End Source File +# Begin Source File + +SOURCE=..\..\Threads.h +# End Source File +# End Target +# End Project diff --git a/C/Util/LzmaLib/LzmaLib.dsw b/C/Util/LzmaLib/LzmaLib.dsw index f6c55593f..6faf33365 100644 --- a/C/Util/LzmaLib/LzmaLib.dsw +++ b/C/Util/LzmaLib/LzmaLib.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/C/Util/LzmaLib/LzmaLibExports.c b/C/Util/LzmaLib/LzmaLibExports.c index 10318eb45..a46c9a807 100644 --- a/C/Util/LzmaLib/LzmaLibExports.c +++ b/C/Util/LzmaLib/LzmaLibExports.c @@ -1,15 +1,15 @@ -/* LzmaLibExports.c -- LZMA library DLL Entry point -2023-03-05 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "../../7zWindows.h" - -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) -{ - UNUSED_VAR(hInstance) - UNUSED_VAR(dwReason) - UNUSED_VAR(lpReserved) - return TRUE; -} +/* LzmaLibExports.c -- LZMA library DLL Entry point +2023-03-05 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "../../7zWindows.h" + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + UNUSED_VAR(hInstance) + UNUSED_VAR(dwReason) + UNUSED_VAR(lpReserved) + return TRUE; +} diff --git a/C/Util/LzmaLib/Precomp.c b/C/Util/LzmaLib/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/LzmaLib/Precomp.c +++ b/C/Util/LzmaLib/Precomp.c @@ -1,4 +1,4 @@ -/* Precomp.c -- StdAfx -2013-01-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" +/* Precomp.c -- StdAfx +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" diff --git a/C/Util/LzmaLib/Precomp.h b/C/Util/LzmaLib/Precomp.h index 52b87ea64..13a41eff2 100644 --- a/C/Util/LzmaLib/Precomp.h +++ b/C/Util/LzmaLib/Precomp.h @@ -1,13 +1,13 @@ -/* Precomp.h -- Precomp -2024-01-23 : Igor Pavlov : Public domain */ - -// #ifndef ZIP7_INC_PRECOMP_LOC_H -// #define ZIP7_INC_PRECOMP_LOC_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../Precomp.h" - -// #endif +/* Precomp.h -- Precomp +2024-01-23 : Igor Pavlov : Public domain */ + +// #ifndef ZIP7_INC_PRECOMP_LOC_H +// #define ZIP7_INC_PRECOMP_LOC_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../Precomp.h" + +// #endif diff --git a/C/Util/LzmaLib/makefile b/C/Util/LzmaLib/makefile index df56c113d..9ed0aa49f 100644 --- a/C/Util/LzmaLib/makefile +++ b/C/Util/LzmaLib/makefile @@ -1,59 +1,59 @@ -MY_STATIC_LINK=1 -SLIB = sLZMA.lib -PROG = LZMA.dll -SLIBPATH = $O\$(SLIB) - -DEF_FILE = LzmaLib.def -CFLAGS = $(CFLAGS) \ - -LIB_OBJS = \ - $O\LzmaLibExports.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\LzmaLib.obj \ - $O\Threads.obj \ - -!include "../../../CPP/7zip/LzFindOpt.mak" -!include "../../../CPP/7zip/LzmaDec.mak" - -OBJS = \ - $O\Precomp.obj \ - $(LIB_OBJS) \ - $(C_OBJS) \ - $(ASM_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(SLIBPATH): $O $(OBJS) - lib -out:$(SLIBPATH) $(OBJS) $(LIBS) - - -MAK_SINGLE_FILE = 1 - -$O\Precomp.obj: Precomp.c - $(CCOMPL_PCH) - -!IFDEF MAK_SINGLE_FILE - -$(LIB_OBJS): $(*B).c - $(CCOMPL_USE) -$(C_OBJS): ../../$(*B).c - $(CCOMPL_USE) - -!ELSE - -{.}.c{$O}.obj:: - $(CCOMPLB_USE) -{../../../C}.c{$O}.obj:: - $(CCOMPLB_USE) - -!ENDIF - -!include "../../Asm_c.mak" +MY_STATIC_LINK=1 +SLIB = sLZMA.lib +PROG = LZMA.dll +SLIBPATH = $O\$(SLIB) + +DEF_FILE = LzmaLib.def +CFLAGS = $(CFLAGS) \ + +LIB_OBJS = \ + $O\LzmaLibExports.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\LzmaLib.obj \ + $O\Threads.obj \ + +!include "../../../CPP/7zip/LzFindOpt.mak" +!include "../../../CPP/7zip/LzmaDec.mak" + +OBJS = \ + $O\Precomp.obj \ + $(LIB_OBJS) \ + $(C_OBJS) \ + $(ASM_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(SLIBPATH): $O $(OBJS) + lib -out:$(SLIBPATH) $(OBJS) $(LIBS) + + +MAK_SINGLE_FILE = 1 + +$O\Precomp.obj: Precomp.c + $(CCOMPL_PCH) + +!IFDEF MAK_SINGLE_FILE + +$(LIB_OBJS): $(*B).c + $(CCOMPL_USE) +$(C_OBJS): ../../$(*B).c + $(CCOMPL_USE) + +!ELSE + +{.}.c{$O}.obj:: + $(CCOMPLB_USE) +{../../../C}.c{$O}.obj:: + $(CCOMPLB_USE) + +!ENDIF + +!include "../../Asm_c.mak" diff --git a/C/Util/LzmaLib/resource.rc b/C/Util/LzmaLib/resource.rc index d95e3f358..674832e05 100644 --- a/C/Util/LzmaLib/resource.rc +++ b/C/Util/LzmaLib/resource.rc @@ -1,3 +1,3 @@ -#include "../../7zVersion.rc" - -MY_VERSION_INFO_DLL("LZMA library", "LZMA") +#include "../../7zVersion.rc" + +MY_VERSION_INFO_DLL("LZMA library", "LZMA") diff --git a/C/Util/SfxSetup/Precomp.c b/C/Util/SfxSetup/Precomp.c index 34b60f8fc..01605e3c2 100644 --- a/C/Util/SfxSetup/Precomp.c +++ b/C/Util/SfxSetup/Precomp.c @@ -1,4 +1,4 @@ -/* Precomp.c -- StdAfx -2013-01-21 : Igor Pavlov : Public domain */ - -#include "Precomp.h" +/* Precomp.c -- StdAfx +2013-01-21 : Igor Pavlov : Public domain */ + +#include "Precomp.h" diff --git a/C/Util/SfxSetup/Precomp.h b/C/Util/SfxSetup/Precomp.h index 52b87ea64..13a41eff2 100644 --- a/C/Util/SfxSetup/Precomp.h +++ b/C/Util/SfxSetup/Precomp.h @@ -1,13 +1,13 @@ -/* Precomp.h -- Precomp -2024-01-23 : Igor Pavlov : Public domain */ - -// #ifndef ZIP7_INC_PRECOMP_LOC_H -// #define ZIP7_INC_PRECOMP_LOC_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../Precomp.h" - -// #endif +/* Precomp.h -- Precomp +2024-01-23 : Igor Pavlov : Public domain */ + +// #ifndef ZIP7_INC_PRECOMP_LOC_H +// #define ZIP7_INC_PRECOMP_LOC_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../Precomp.h" + +// #endif diff --git a/C/Util/SfxSetup/SfxSetup.c b/C/Util/SfxSetup/SfxSetup.c index 11af9a06c..9b5c1f911 100644 --- a/C/Util/SfxSetup/SfxSetup.c +++ b/C/Util/SfxSetup/SfxSetup.c @@ -1,657 +1,657 @@ -/* SfxSetup.c - 7z SFX Setup -2024-01-24 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#ifndef UNICODE -#define UNICODE -#endif - -#ifndef _UNICODE -#define _UNICODE -#endif - -#ifdef _CONSOLE -#include -#endif - -#include "../../7z.h" -#include "../../7zAlloc.h" -#include "../../7zCrc.h" -#include "../../7zFile.h" -#include "../../CpuArch.h" -#include "../../DllSecur.h" - -#define k_EXE_ExtIndex 2 - -#define kInputBufSize ((size_t)1 << 18) - - -#define wcscat lstrcatW -#define wcslen (size_t)lstrlenW -#define wcscpy lstrcpyW -// wcsncpy() and lstrcpynW() work differently. We don't use them. - -static const char * const kExts[] = -{ - "bat" - , "cmd" - , "exe" - , "inf" - , "msi" - #ifdef UNDER_CE - , "cab" - #endif - , "html" - , "htm" -}; - -static const char * const kNames[] = -{ - "setup" - , "install" - , "run" - , "start" -}; - -static unsigned FindExt(const wchar_t *s, unsigned *extLen) -{ - unsigned len = (unsigned)wcslen(s); - unsigned i; - for (i = len; i > 0; i--) - { - if (s[i - 1] == '.') - { - *extLen = len - i; - return i - 1; - } - } - *extLen = 0; - return len; -} - -#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c))) - -static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len) -{ - unsigned i; - for (i = 0; i < num; i++) - { - const char *item = items[i]; - const unsigned itemLen = (unsigned)strlen(item); - unsigned j; - if (len != itemLen) - continue; - for (j = 0; j < len; j++) - { - const unsigned c = (Byte)item[j]; - if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j]) - break; - } - if (j == len) - return i; - } - return i; -} - -#ifdef _CONSOLE -static BOOL WINAPI HandlerRoutine(DWORD ctrlType) -{ - UNUSED_VAR(ctrlType); - return TRUE; -} -#endif - - -#ifdef _CONSOLE -static void PrintStr(const char *s) -{ - fputs(s, stdout); -} -#endif - -static void PrintErrorMessage(const char *message) -{ - #ifdef _CONSOLE - PrintStr("\n7-Zip Error: "); - PrintStr(message); - PrintStr("\n"); - #else - #ifdef UNDER_CE - WCHAR messageW[256 + 4]; - unsigned i; - for (i = 0; i < 256 && message[i] != 0; i++) - messageW[i] = message[i]; - messageW[i] = 0; - MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR); - #else - MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR); - #endif - #endif -} - -static WRes MyCreateDir(const WCHAR *name) -{ - return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); -} - -#ifdef UNDER_CE -#define kBufferSize (1 << 13) -#else -#define kBufferSize (1 << 15) -#endif - -#define kSignatureSearchLimit (1 << 22) - -static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos) -{ - Byte buf[kBufferSize]; - size_t numPrevBytes = 0; - *resPos = 0; - for (;;) - { - size_t processed, pos; - if (*resPos > kSignatureSearchLimit) - return False; - processed = kBufferSize - numPrevBytes; - if (File_Read(stream, buf + numPrevBytes, &processed) != 0) - return False; - processed += numPrevBytes; - if (processed < k7zStartHeaderSize || - (processed == k7zStartHeaderSize && numPrevBytes != 0)) - return False; - processed -= k7zStartHeaderSize; - for (pos = 0; pos <= processed; pos++) - { - for (; pos <= processed && buf[pos] != '7'; pos++); - if (pos > processed) - break; - if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0) - if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8)) - { - *resPos += pos; - return True; - } - } - *resPos += processed; - numPrevBytes = k7zStartHeaderSize; - memmove(buf, buf + processed, k7zStartHeaderSize); - } -} - -static BoolInt DoesFileOrDirExist(const WCHAR *path) -{ - WIN32_FIND_DATAW fd; - HANDLE handle; - handle = FindFirstFileW(path, &fd); - if (handle == INVALID_HANDLE_VALUE) - return False; - FindClose(handle); - return True; -} - -static WRes RemoveDirWithSubItems(WCHAR *path) -{ - WIN32_FIND_DATAW fd; - HANDLE handle; - WRes res = 0; - const size_t len = wcslen(path); - wcscpy(path + len, L"*"); - handle = FindFirstFileW(path, &fd); - path[len] = L'\0'; - if (handle == INVALID_HANDLE_VALUE) - return GetLastError(); - - for (;;) - { - if (wcscmp(fd.cFileName, L".") != 0 && - wcscmp(fd.cFileName, L"..") != 0) - { - wcscpy(path + len, fd.cFileName); - if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) - { - wcscat(path, WSTRING_PATH_SEPARATOR); - res = RemoveDirWithSubItems(path); - } - else - { - SetFileAttributesW(path, 0); - if (DeleteFileW(path) == 0) - res = GetLastError(); - } - - if (res != 0) - break; - } - - if (!FindNextFileW(handle, &fd)) - { - res = GetLastError(); - if (res == ERROR_NO_MORE_FILES) - res = 0; - break; - } - } - - path[len] = L'\0'; - FindClose(handle); - if (res == 0) - { - if (!RemoveDirectoryW(path)) - res = GetLastError(); - } - return res; -} - -#ifdef _CONSOLE -int Z7_CDECL main(void) -#else -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - lpCmdLine, int nCmdShow) -#endif -{ - CFileInStream archiveStream; - CLookToRead2 lookStream; - CSzArEx db; - SRes res = SZ_OK; - ISzAlloc allocImp; - ISzAlloc allocTempImp; - WCHAR sfxPath[MAX_PATH + 2]; - WCHAR path[MAX_PATH * 3 + 2]; - #ifndef UNDER_CE - WCHAR workCurDir[MAX_PATH + 32]; - #endif - size_t pathLen; - DWORD winRes; - const wchar_t *cmdLineParams; - const char *errorMessage = NULL; - BoolInt useShellExecute = True; - DWORD exitCode = 0; - - LoadSecurityDlls(); - - #ifdef _CONSOLE - SetConsoleCtrlHandler(HandlerRoutine, TRUE); - #else - UNUSED_VAR(hInstance) - UNUSED_VAR(hPrevInstance) - UNUSED_VAR(lpCmdLine) - UNUSED_VAR(nCmdShow) - #endif - - CrcGenerateTable(); - - allocImp.Alloc = SzAlloc; - allocImp.Free = SzFree; - - allocTempImp.Alloc = SzAllocTemp; - allocTempImp.Free = SzFreeTemp; - - FileInStream_CreateVTable(&archiveStream); - LookToRead2_CreateVTable(&lookStream, False); - lookStream.buf = NULL; - - winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH); - if (winRes == 0 || winRes > MAX_PATH) - return 1; - { - cmdLineParams = GetCommandLineW(); - #ifndef UNDER_CE - { - BoolInt quoteMode = False; - for (;; cmdLineParams++) - { - const wchar_t c = *cmdLineParams; - if (c == L'\"') - quoteMode = !quoteMode; - else if (c == 0 || (c == L' ' && !quoteMode)) - break; - } - } - #endif - } - - { - unsigned i; - DWORD d; - winRes = GetTempPathW(MAX_PATH, path); - if (winRes == 0 || winRes > MAX_PATH) - return 1; - pathLen = wcslen(path); - d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); - - for (i = 0;; i++, d += GetTickCount()) - { - if (i >= 100) - { - res = SZ_ERROR_FAIL; - break; - } - wcscpy(path + pathLen, L"7z"); - - { - wchar_t *s = path + wcslen(path); - UInt32 value = d; - unsigned k; - for (k = 0; k < 8; k++) - { - const unsigned t = value & 0xF; - value >>= 4; - s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } - s[k] = '\0'; - } - - if (DoesFileOrDirExist(path)) - continue; - if (CreateDirectoryW(path, NULL)) - { - wcscat(path, WSTRING_PATH_SEPARATOR); - pathLen = wcslen(path); - break; - } - if (GetLastError() != ERROR_ALREADY_EXISTS) - { - res = SZ_ERROR_FAIL; - break; - } - } - - #ifndef UNDER_CE - wcscpy(workCurDir, path); - #endif - if (res != SZ_OK) - errorMessage = "Can't create temp folder"; - } - - if (res != SZ_OK) - { - if (!errorMessage) - errorMessage = "Error"; - PrintErrorMessage(errorMessage); - return 1; - } - - if (InFile_OpenW(&archiveStream.file, sfxPath) != 0) - { - errorMessage = "can not open input file"; - res = SZ_ERROR_FAIL; - } - else - { - UInt64 pos = 0; - if (!FindSignature(&archiveStream.file, &pos)) - res = SZ_ERROR_FAIL; - else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0) - res = SZ_ERROR_FAIL; - if (res != 0) - errorMessage = "Can't find 7z archive"; - } - - if (res == SZ_OK) - { - lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); - if (!lookStream.buf) - res = SZ_ERROR_MEM; - else - { - lookStream.bufSize = kInputBufSize; - lookStream.realStream = &archiveStream.vt; - LookToRead2_INIT(&lookStream) - } - } - - SzArEx_Init(&db); - - if (res == SZ_OK) - { - res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); - } - - if (res == SZ_OK) - { - UInt32 executeFileIndex = (UInt32)(Int32)-1; - UInt32 minPrice = 1 << 30; - UInt32 i; - UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ - Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ - size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ - - for (i = 0; i < db.NumFiles; i++) - { - size_t offset = 0; - size_t outSizeProcessed = 0; - WCHAR *temp; - - if (SzArEx_GetFileNameUtf16(&db, i, NULL) >= MAX_PATH) - { - res = SZ_ERROR_FAIL; - break; - } - - temp = path + pathLen; - - SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp); - { - res = SzArEx_Extract(&db, &lookStream.vt, i, - &blockIndex, &outBuffer, &outBufferSize, - &offset, &outSizeProcessed, - &allocImp, &allocTempImp); - if (res != SZ_OK) - break; - } - { - CSzFile outFile; - size_t processedSize; - size_t j; - size_t nameStartPos = 0; - for (j = 0; temp[j] != 0; j++) - { - if (temp[j] == '/') - { - temp[j] = 0; - MyCreateDir(path); - temp[j] = CHAR_PATH_SEPARATOR; - nameStartPos = j + 1; - } - } - - if (SzArEx_IsDir(&db, i)) - { - MyCreateDir(path); - continue; - } - else - { - unsigned extLen; - const WCHAR *name = temp + nameStartPos; - unsigned len = (unsigned)wcslen(name); - const unsigned nameLen = FindExt(temp + nameStartPos, &extLen); - const unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen); - const unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen); - - const unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12)); - if (minPrice > price) - { - minPrice = price; - executeFileIndex = i; - useShellExecute = (extPrice != k_EXE_ExtIndex); - } - - if (DoesFileOrDirExist(path)) - { - errorMessage = "Duplicate file"; - res = SZ_ERROR_FAIL; - break; - } - if (OutFile_OpenW(&outFile, path)) - { - errorMessage = "Can't open output file"; - res = SZ_ERROR_FAIL; - break; - } - } - - processedSize = outSizeProcessed; - if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed) - { - errorMessage = "Can't write output file"; - res = SZ_ERROR_FAIL; - } - - #ifdef USE_WINDOWS_FILE - if (SzBitWithVals_Check(&db.MTime, i)) - { - const CNtfsFileTime *t = db.MTime.Vals + i; - FILETIME mTime; - mTime.dwLowDateTime = t->Low; - mTime.dwHighDateTime = t->High; - SetFileTime(outFile.handle, NULL, NULL, &mTime); - } - #endif - - { - const WRes res2 = File_Close(&outFile); - if (res != SZ_OK) - break; - if (res2 != 0) - { - errorMessage = "Can't close output file"; - res = SZ_ERROR_FAIL; - break; - } - } - #ifdef USE_WINDOWS_FILE - if (SzBitWithVals_Check(&db.Attribs, i)) - SetFileAttributesW(path, db.Attribs.Vals[i]); - #endif - } - } - - if (res == SZ_OK) - { - if (executeFileIndex == (UInt32)(Int32)-1) - { - errorMessage = "There is no file to execute"; - res = SZ_ERROR_FAIL; - } - else - { - WCHAR *temp = path + pathLen; - UInt32 j; - SzArEx_GetFileNameUtf16(&db, executeFileIndex, (UInt16 *)temp); - for (j = 0; temp[j] != 0; j++) - if (temp[j] == '/') - temp[j] = CHAR_PATH_SEPARATOR; - } - } - ISzAlloc_Free(&allocImp, outBuffer); - } - - SzArEx_Free(&db, &allocImp); - - ISzAlloc_Free(&allocImp, lookStream.buf); - - File_Close(&archiveStream.file); - - if (res == SZ_OK) - { - HANDLE hProcess = 0; - - #ifndef UNDER_CE - WCHAR oldCurDir[MAX_PATH + 2]; - oldCurDir[0] = 0; - { - const DWORD needLen = GetCurrentDirectory(MAX_PATH + 1, oldCurDir); - if (needLen == 0 || needLen > MAX_PATH) - oldCurDir[0] = 0; - SetCurrentDirectory(workCurDir); - } - #endif - - if (useShellExecute) - { - SHELLEXECUTEINFO ei; - UINT32 executeRes; - BOOL success; - - memset(&ei, 0, sizeof(ei)); - ei.cbSize = sizeof(ei); - ei.lpFile = path; - ei.fMask = SEE_MASK_NOCLOSEPROCESS - #ifndef UNDER_CE - | SEE_MASK_FLAG_DDEWAIT - #endif - /* | SEE_MASK_NO_CONSOLE */ - ; - if (wcslen(cmdLineParams) != 0) - ei.lpParameters = cmdLineParams; - ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */ - success = ShellExecuteEx(&ei); - executeRes = (UINT32)(UINT_PTR)ei.hInstApp; - if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */ - res = SZ_ERROR_FAIL; - else - hProcess = ei.hProcess; - } - else - { - STARTUPINFOW si; - PROCESS_INFORMATION pi; - WCHAR cmdLine[MAX_PATH * 3]; - - wcscpy(cmdLine, path); - wcscat(cmdLine, cmdLineParams); - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0) - res = SZ_ERROR_FAIL; - else - { - CloseHandle(pi.hThread); - hProcess = pi.hProcess; - } - } - - if (hProcess != 0) - { - WaitForSingleObject(hProcess, INFINITE); - if (!GetExitCodeProcess(hProcess, &exitCode)) - exitCode = 1; - CloseHandle(hProcess); - } - - #ifndef UNDER_CE - SetCurrentDirectory(oldCurDir); - #endif - } - - path[pathLen] = L'\0'; - RemoveDirWithSubItems(path); - - if (res == SZ_OK) - return (int)exitCode; - - { - if (res == SZ_ERROR_UNSUPPORTED) - errorMessage = "Decoder doesn't support this archive"; - else if (res == SZ_ERROR_MEM) - errorMessage = "Can't allocate required memory"; - else if (res == SZ_ERROR_CRC) - errorMessage = "CRC error"; - else - { - if (!errorMessage) - errorMessage = "ERROR"; - } - - if (errorMessage) - PrintErrorMessage(errorMessage); - } - return 1; -} +/* SfxSetup.c - 7z SFX Setup +2024-01-24 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#ifndef UNICODE +#define UNICODE +#endif + +#ifndef _UNICODE +#define _UNICODE +#endif + +#ifdef _CONSOLE +#include +#endif + +#include "../../7z.h" +#include "../../7zAlloc.h" +#include "../../7zCrc.h" +#include "../../7zFile.h" +#include "../../CpuArch.h" +#include "../../DllSecur.h" + +#define k_EXE_ExtIndex 2 + +#define kInputBufSize ((size_t)1 << 18) + + +#define wcscat lstrcatW +#define wcslen (size_t)lstrlenW +#define wcscpy lstrcpyW +// wcsncpy() and lstrcpynW() work differently. We don't use them. + +static const char * const kExts[] = +{ + "bat" + , "cmd" + , "exe" + , "inf" + , "msi" + #ifdef UNDER_CE + , "cab" + #endif + , "html" + , "htm" +}; + +static const char * const kNames[] = +{ + "setup" + , "install" + , "run" + , "start" +}; + +static unsigned FindExt(const wchar_t *s, unsigned *extLen) +{ + unsigned len = (unsigned)wcslen(s); + unsigned i; + for (i = len; i > 0; i--) + { + if (s[i - 1] == '.') + { + *extLen = len - i; + return i - 1; + } + } + *extLen = 0; + return len; +} + +#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c))) + +static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len) +{ + unsigned i; + for (i = 0; i < num; i++) + { + const char *item = items[i]; + const unsigned itemLen = (unsigned)strlen(item); + unsigned j; + if (len != itemLen) + continue; + for (j = 0; j < len; j++) + { + const unsigned c = (Byte)item[j]; + if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j]) + break; + } + if (j == len) + return i; + } + return i; +} + +#ifdef _CONSOLE +static BOOL WINAPI HandlerRoutine(DWORD ctrlType) +{ + UNUSED_VAR(ctrlType); + return TRUE; +} +#endif + + +#ifdef _CONSOLE +static void PrintStr(const char *s) +{ + fputs(s, stdout); +} +#endif + +static void PrintErrorMessage(const char *message) +{ + #ifdef _CONSOLE + PrintStr("\n7-Zip Error: "); + PrintStr(message); + PrintStr("\n"); + #else + #ifdef UNDER_CE + WCHAR messageW[256 + 4]; + unsigned i; + for (i = 0; i < 256 && message[i] != 0; i++) + messageW[i] = message[i]; + messageW[i] = 0; + MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR); + #else + MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR); + #endif + #endif +} + +static WRes MyCreateDir(const WCHAR *name) +{ + return CreateDirectoryW(name, NULL) ? 0 : GetLastError(); +} + +#ifdef UNDER_CE +#define kBufferSize (1 << 13) +#else +#define kBufferSize (1 << 15) +#endif + +#define kSignatureSearchLimit (1 << 22) + +static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos) +{ + Byte buf[kBufferSize]; + size_t numPrevBytes = 0; + *resPos = 0; + for (;;) + { + size_t processed, pos; + if (*resPos > kSignatureSearchLimit) + return False; + processed = kBufferSize - numPrevBytes; + if (File_Read(stream, buf + numPrevBytes, &processed) != 0) + return False; + processed += numPrevBytes; + if (processed < k7zStartHeaderSize || + (processed == k7zStartHeaderSize && numPrevBytes != 0)) + return False; + processed -= k7zStartHeaderSize; + for (pos = 0; pos <= processed; pos++) + { + for (; pos <= processed && buf[pos] != '7'; pos++); + if (pos > processed) + break; + if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0) + if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8)) + { + *resPos += pos; + return True; + } + } + *resPos += processed; + numPrevBytes = k7zStartHeaderSize; + memmove(buf, buf + processed, k7zStartHeaderSize); + } +} + +static BoolInt DoesFileOrDirExist(const WCHAR *path) +{ + WIN32_FIND_DATAW fd; + HANDLE handle; + handle = FindFirstFileW(path, &fd); + if (handle == INVALID_HANDLE_VALUE) + return False; + FindClose(handle); + return True; +} + +static WRes RemoveDirWithSubItems(WCHAR *path) +{ + WIN32_FIND_DATAW fd; + HANDLE handle; + WRes res = 0; + const size_t len = wcslen(path); + wcscpy(path + len, L"*"); + handle = FindFirstFileW(path, &fd); + path[len] = L'\0'; + if (handle == INVALID_HANDLE_VALUE) + return GetLastError(); + + for (;;) + { + if (wcscmp(fd.cFileName, L".") != 0 && + wcscmp(fd.cFileName, L"..") != 0) + { + wcscpy(path + len, fd.cFileName); + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + wcscat(path, WSTRING_PATH_SEPARATOR); + res = RemoveDirWithSubItems(path); + } + else + { + SetFileAttributesW(path, 0); + if (DeleteFileW(path) == 0) + res = GetLastError(); + } + + if (res != 0) + break; + } + + if (!FindNextFileW(handle, &fd)) + { + res = GetLastError(); + if (res == ERROR_NO_MORE_FILES) + res = 0; + break; + } + } + + path[len] = L'\0'; + FindClose(handle); + if (res == 0) + { + if (!RemoveDirectoryW(path)) + res = GetLastError(); + } + return res; +} + +#ifdef _CONSOLE +int Z7_CDECL main(void) +#else +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + lpCmdLine, int nCmdShow) +#endif +{ + CFileInStream archiveStream; + CLookToRead2 lookStream; + CSzArEx db; + SRes res = SZ_OK; + ISzAlloc allocImp; + ISzAlloc allocTempImp; + WCHAR sfxPath[MAX_PATH + 2]; + WCHAR path[MAX_PATH * 3 + 2]; + #ifndef UNDER_CE + WCHAR workCurDir[MAX_PATH + 32]; + #endif + size_t pathLen; + DWORD winRes; + const wchar_t *cmdLineParams; + const char *errorMessage = NULL; + BoolInt useShellExecute = True; + DWORD exitCode = 0; + + LoadSecurityDlls(); + + #ifdef _CONSOLE + SetConsoleCtrlHandler(HandlerRoutine, TRUE); + #else + UNUSED_VAR(hInstance) + UNUSED_VAR(hPrevInstance) + UNUSED_VAR(lpCmdLine) + UNUSED_VAR(nCmdShow) + #endif + + CrcGenerateTable(); + + allocImp.Alloc = SzAlloc; + allocImp.Free = SzFree; + + allocTempImp.Alloc = SzAllocTemp; + allocTempImp.Free = SzFreeTemp; + + FileInStream_CreateVTable(&archiveStream); + LookToRead2_CreateVTable(&lookStream, False); + lookStream.buf = NULL; + + winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH); + if (winRes == 0 || winRes > MAX_PATH) + return 1; + { + cmdLineParams = GetCommandLineW(); + #ifndef UNDER_CE + { + BoolInt quoteMode = False; + for (;; cmdLineParams++) + { + const wchar_t c = *cmdLineParams; + if (c == L'\"') + quoteMode = !quoteMode; + else if (c == 0 || (c == L' ' && !quoteMode)) + break; + } + } + #endif + } + + { + unsigned i; + DWORD d; + winRes = GetTempPathW(MAX_PATH, path); + if (winRes == 0 || winRes > MAX_PATH) + return 1; + pathLen = wcslen(path); + d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + + for (i = 0;; i++, d += GetTickCount()) + { + if (i >= 100) + { + res = SZ_ERROR_FAIL; + break; + } + wcscpy(path + pathLen, L"7z"); + + { + wchar_t *s = path + wcslen(path); + UInt32 value = d; + unsigned k; + for (k = 0; k < 8; k++) + { + const unsigned t = value & 0xF; + value >>= 4; + s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } + s[k] = '\0'; + } + + if (DoesFileOrDirExist(path)) + continue; + if (CreateDirectoryW(path, NULL)) + { + wcscat(path, WSTRING_PATH_SEPARATOR); + pathLen = wcslen(path); + break; + } + if (GetLastError() != ERROR_ALREADY_EXISTS) + { + res = SZ_ERROR_FAIL; + break; + } + } + + #ifndef UNDER_CE + wcscpy(workCurDir, path); + #endif + if (res != SZ_OK) + errorMessage = "Can't create temp folder"; + } + + if (res != SZ_OK) + { + if (!errorMessage) + errorMessage = "Error"; + PrintErrorMessage(errorMessage); + return 1; + } + + if (InFile_OpenW(&archiveStream.file, sfxPath) != 0) + { + errorMessage = "can not open input file"; + res = SZ_ERROR_FAIL; + } + else + { + UInt64 pos = 0; + if (!FindSignature(&archiveStream.file, &pos)) + res = SZ_ERROR_FAIL; + else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0) + res = SZ_ERROR_FAIL; + if (res != 0) + errorMessage = "Can't find 7z archive"; + } + + if (res == SZ_OK) + { + lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize); + if (!lookStream.buf) + res = SZ_ERROR_MEM; + else + { + lookStream.bufSize = kInputBufSize; + lookStream.realStream = &archiveStream.vt; + LookToRead2_INIT(&lookStream) + } + } + + SzArEx_Init(&db); + + if (res == SZ_OK) + { + res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp); + } + + if (res == SZ_OK) + { + UInt32 executeFileIndex = (UInt32)(Int32)-1; + UInt32 minPrice = 1 << 30; + UInt32 i; + UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */ + Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */ + size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */ + + for (i = 0; i < db.NumFiles; i++) + { + size_t offset = 0; + size_t outSizeProcessed = 0; + WCHAR *temp; + + if (SzArEx_GetFileNameUtf16(&db, i, NULL) >= MAX_PATH) + { + res = SZ_ERROR_FAIL; + break; + } + + temp = path + pathLen; + + SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp); + { + res = SzArEx_Extract(&db, &lookStream.vt, i, + &blockIndex, &outBuffer, &outBufferSize, + &offset, &outSizeProcessed, + &allocImp, &allocTempImp); + if (res != SZ_OK) + break; + } + { + CSzFile outFile; + size_t processedSize; + size_t j; + size_t nameStartPos = 0; + for (j = 0; temp[j] != 0; j++) + { + if (temp[j] == '/') + { + temp[j] = 0; + MyCreateDir(path); + temp[j] = CHAR_PATH_SEPARATOR; + nameStartPos = j + 1; + } + } + + if (SzArEx_IsDir(&db, i)) + { + MyCreateDir(path); + continue; + } + else + { + unsigned extLen; + const WCHAR *name = temp + nameStartPos; + unsigned len = (unsigned)wcslen(name); + const unsigned nameLen = FindExt(temp + nameStartPos, &extLen); + const unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen); + const unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen); + + const unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12)); + if (minPrice > price) + { + minPrice = price; + executeFileIndex = i; + useShellExecute = (extPrice != k_EXE_ExtIndex); + } + + if (DoesFileOrDirExist(path)) + { + errorMessage = "Duplicate file"; + res = SZ_ERROR_FAIL; + break; + } + if (OutFile_OpenW(&outFile, path)) + { + errorMessage = "Can't open output file"; + res = SZ_ERROR_FAIL; + break; + } + } + + processedSize = outSizeProcessed; + if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed) + { + errorMessage = "Can't write output file"; + res = SZ_ERROR_FAIL; + } + + #ifdef USE_WINDOWS_FILE + if (SzBitWithVals_Check(&db.MTime, i)) + { + const CNtfsFileTime *t = db.MTime.Vals + i; + FILETIME mTime; + mTime.dwLowDateTime = t->Low; + mTime.dwHighDateTime = t->High; + SetFileTime(outFile.handle, NULL, NULL, &mTime); + } + #endif + + { + const WRes res2 = File_Close(&outFile); + if (res != SZ_OK) + break; + if (res2 != 0) + { + errorMessage = "Can't close output file"; + res = SZ_ERROR_FAIL; + break; + } + } + #ifdef USE_WINDOWS_FILE + if (SzBitWithVals_Check(&db.Attribs, i)) + SetFileAttributesW(path, db.Attribs.Vals[i]); + #endif + } + } + + if (res == SZ_OK) + { + if (executeFileIndex == (UInt32)(Int32)-1) + { + errorMessage = "There is no file to execute"; + res = SZ_ERROR_FAIL; + } + else + { + WCHAR *temp = path + pathLen; + UInt32 j; + SzArEx_GetFileNameUtf16(&db, executeFileIndex, (UInt16 *)temp); + for (j = 0; temp[j] != 0; j++) + if (temp[j] == '/') + temp[j] = CHAR_PATH_SEPARATOR; + } + } + ISzAlloc_Free(&allocImp, outBuffer); + } + + SzArEx_Free(&db, &allocImp); + + ISzAlloc_Free(&allocImp, lookStream.buf); + + File_Close(&archiveStream.file); + + if (res == SZ_OK) + { + HANDLE hProcess = 0; + + #ifndef UNDER_CE + WCHAR oldCurDir[MAX_PATH + 2]; + oldCurDir[0] = 0; + { + const DWORD needLen = GetCurrentDirectory(MAX_PATH + 1, oldCurDir); + if (needLen == 0 || needLen > MAX_PATH) + oldCurDir[0] = 0; + SetCurrentDirectory(workCurDir); + } + #endif + + if (useShellExecute) + { + SHELLEXECUTEINFO ei; + UINT32 executeRes; + BOOL success; + + memset(&ei, 0, sizeof(ei)); + ei.cbSize = sizeof(ei); + ei.lpFile = path; + ei.fMask = SEE_MASK_NOCLOSEPROCESS + #ifndef UNDER_CE + | SEE_MASK_FLAG_DDEWAIT + #endif + /* | SEE_MASK_NO_CONSOLE */ + ; + if (wcslen(cmdLineParams) != 0) + ei.lpParameters = cmdLineParams; + ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */ + success = ShellExecuteEx(&ei); + executeRes = (UINT32)(UINT_PTR)ei.hInstApp; + if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */ + res = SZ_ERROR_FAIL; + else + hProcess = ei.hProcess; + } + else + { + STARTUPINFOW si; + PROCESS_INFORMATION pi; + WCHAR cmdLine[MAX_PATH * 3]; + + wcscpy(cmdLine, path); + wcscat(cmdLine, cmdLineParams); + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0) + res = SZ_ERROR_FAIL; + else + { + CloseHandle(pi.hThread); + hProcess = pi.hProcess; + } + } + + if (hProcess != 0) + { + WaitForSingleObject(hProcess, INFINITE); + if (!GetExitCodeProcess(hProcess, &exitCode)) + exitCode = 1; + CloseHandle(hProcess); + } + + #ifndef UNDER_CE + SetCurrentDirectory(oldCurDir); + #endif + } + + path[pathLen] = L'\0'; + RemoveDirWithSubItems(path); + + if (res == SZ_OK) + return (int)exitCode; + + { + if (res == SZ_ERROR_UNSUPPORTED) + errorMessage = "Decoder doesn't support this archive"; + else if (res == SZ_ERROR_MEM) + errorMessage = "Can't allocate required memory"; + else if (res == SZ_ERROR_CRC) + errorMessage = "CRC error"; + else + { + if (!errorMessage) + errorMessage = "ERROR"; + } + + if (errorMessage) + PrintErrorMessage(errorMessage); + } + return 1; +} diff --git a/C/Util/SfxSetup/SfxSetup.dsp b/C/Util/SfxSetup/SfxSetup.dsp index be9de6dec..60439a6f7 100644 --- a/C/Util/SfxSetup/SfxSetup.dsp +++ b/C/Util/SfxSetup/SfxSetup.dsp @@ -1,231 +1,231 @@ -# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=SfxSetup - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SfxSetup.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SfxSetup - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 - -!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "SfxSetup - Win32 Release" -# Name "SfxSetup - Win32 Debug" -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\7z.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zAlloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zArcIn.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zCrcOpt.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zFile.h -# End Source File -# Begin Source File - -SOURCE=..\..\7zStream.c -# End Source File -# Begin Source File - -SOURCE=..\..\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.c -# End Source File -# Begin Source File - -SOURCE=..\..\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\Bra86.c -# End Source File -# Begin Source File - -SOURCE=..\..\BraIA64.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.c -# End Source File -# Begin Source File - -SOURCE=..\..\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\Delta.c -# End Source File -# Begin Source File - -SOURCE=..\..\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\DllSecur.c -# End Source File -# Begin Source File - -SOURCE=..\..\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.c -# End Source File -# Begin Source File - -SOURCE=..\..\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.c -# End Source File -# Begin Source File - -SOURCE=..\..\LzmaDec.h -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\Precomp.c -# ADD CPP /Yc"Precomp.h" -# End Source File -# Begin Source File - -SOURCE=.\Precomp.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\SfxSetup.c -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=SfxSetup - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SfxSetup.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SfxSetup - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "SfxSetup - Win32 Release" +# Name "SfxSetup - Win32 Debug" +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\7z.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zAlloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zArcIn.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zCrcOpt.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zFile.h +# End Source File +# Begin Source File + +SOURCE=..\..\7zStream.c +# End Source File +# Begin Source File + +SOURCE=..\..\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.c +# End Source File +# Begin Source File + +SOURCE=..\..\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\Bra86.c +# End Source File +# Begin Source File + +SOURCE=..\..\BraIA64.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.c +# End Source File +# Begin Source File + +SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.c +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\DllSecur.c +# End Source File +# Begin Source File + +SOURCE=..\..\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.c +# End Source File +# Begin Source File + +SOURCE=..\..\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.c +# End Source File +# Begin Source File + +SOURCE=..\..\LzmaDec.h +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Precomp.c +# ADD CPP /Yc"Precomp.h" +# End Source File +# Begin Source File + +SOURCE=.\Precomp.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\SfxSetup.c +# End Source File +# End Target +# End Project diff --git a/C/Util/SfxSetup/SfxSetup.dsw b/C/Util/SfxSetup/SfxSetup.dsw index 128fcdd3e..ea2311129 100644 --- a/C/Util/SfxSetup/SfxSetup.dsw +++ b/C/Util/SfxSetup/SfxSetup.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/C/Util/SfxSetup/makefile b/C/Util/SfxSetup/makefile index 88bb2b65e..b3f25a223 100644 --- a/C/Util/SfxSetup/makefile +++ b/C/Util/SfxSetup/makefile @@ -1,44 +1,44 @@ -PROG = 7zS2.sfx -MY_FIXED = 1 - -CFLAGS = $(CFLAGS) \ - -DZ7_EXTRACT_ONLY \ - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zArcIn.obj \ - $O\7zBuf.obj \ - $O\7zBuf2.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\DllSecur.obj \ - $O\Lzma2Dec.obj \ - $O\LzmaDec.obj \ - -7Z_OBJS = \ - $O\SfxSetup.obj \ - -!include "../../../CPP/7zip/Crc.mak" -# !include "../../../CPP/7zip/LzmaDec.mak" - -OBJS = \ - $(7Z_OBJS) \ - $(C_OBJS) \ - $(ASM_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(7Z_OBJS): $(*B).c - $(COMPL_O1) -$(C_OBJS): ../../$(*B).c - $(COMPL_O1) - -!include "../../Asm_c.mak" +PROG = 7zS2.sfx +MY_FIXED = 1 + +CFLAGS = $(CFLAGS) \ + -DZ7_EXTRACT_ONLY \ + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zArcIn.obj \ + $O\7zBuf.obj \ + $O\7zBuf2.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\DllSecur.obj \ + $O\Lzma2Dec.obj \ + $O\LzmaDec.obj \ + +7Z_OBJS = \ + $O\SfxSetup.obj \ + +!include "../../../CPP/7zip/Crc.mak" +# !include "../../../CPP/7zip/LzmaDec.mak" + +OBJS = \ + $(7Z_OBJS) \ + $(C_OBJS) \ + $(ASM_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(7Z_OBJS): $(*B).c + $(COMPL_O1) +$(C_OBJS): ../../$(*B).c + $(COMPL_O1) + +!include "../../Asm_c.mak" diff --git a/C/Util/SfxSetup/makefile_con b/C/Util/SfxSetup/makefile_con index 2111006a5..9f4b91669 100644 --- a/C/Util/SfxSetup/makefile_con +++ b/C/Util/SfxSetup/makefile_con @@ -1,40 +1,40 @@ -PROG = 7zS2con.sfx -MY_FIXED = 1 - -CFLAGS = $(CFLAGS) -D_CONSOLE \ - -DZ7_EXTRACT_ONLY \ - -C_OBJS = \ - $O\7zAlloc.obj \ - $O\7zArcIn.obj \ - $O\7zBuf.obj \ - $O\7zBuf2.obj \ - $O\7zCrc.obj \ - $O\7zCrcOpt.obj \ - $O\7zFile.obj \ - $O\7zDec.obj \ - $O\7zStream.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\DllSecur.obj \ - $O\Lzma2Dec.obj \ - $O\LzmaDec.obj \ - -7Z_OBJS = \ - $O\SfxSetup.obj \ - -OBJS = \ - $(7Z_OBJS) \ - $(C_OBJS) \ - $O\resource.res - -!include "../../../CPP/Build.mak" - -$(7Z_OBJS): $(*B).c - $(COMPL_O1) -$(C_OBJS): ../../$(*B).c - $(COMPL_O1) +PROG = 7zS2con.sfx +MY_FIXED = 1 + +CFLAGS = $(CFLAGS) -D_CONSOLE \ + -DZ7_EXTRACT_ONLY \ + +C_OBJS = \ + $O\7zAlloc.obj \ + $O\7zArcIn.obj \ + $O\7zBuf.obj \ + $O\7zBuf2.obj \ + $O\7zCrc.obj \ + $O\7zCrcOpt.obj \ + $O\7zFile.obj \ + $O\7zDec.obj \ + $O\7zStream.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\DllSecur.obj \ + $O\Lzma2Dec.obj \ + $O\LzmaDec.obj \ + +7Z_OBJS = \ + $O\SfxSetup.obj \ + +OBJS = \ + $(7Z_OBJS) \ + $(C_OBJS) \ + $O\resource.res + +!include "../../../CPP/Build.mak" + +$(7Z_OBJS): $(*B).c + $(COMPL_O1) +$(C_OBJS): ../../$(*B).c + $(COMPL_O1) diff --git a/C/Util/SfxSetup/resource.rc b/C/Util/SfxSetup/resource.rc index 64f4e2ce7..0c1637f23 100644 --- a/C/Util/SfxSetup/resource.rc +++ b/C/Util/SfxSetup/resource.rc @@ -1,5 +1,5 @@ -#include "../../7zVersion.rc" - -MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx") - -1 ICON "setup.ico" +#include "../../7zVersion.rc" + +MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx") + +1 ICON "setup.ico" diff --git a/C/Xxh64.c b/C/Xxh64.c index d1fa04c31..dc02a0253 100644 --- a/C/Xxh64.c +++ b/C/Xxh64.c @@ -1,327 +1,327 @@ -/* Xxh64.c -- XXH64 hash calculation -original code: Copyright (c) Yann Collet. -2023-08-18 : modified by Igor Pavlov. -This source code is licensed under BSD 2-Clause License. -*/ - -#include "Precomp.h" - -#include "CpuArch.h" -#include "RotateDefs.h" -#include "Xxh64.h" - -#define Z7_XXH_PRIME64_1 UINT64_CONST(0x9E3779B185EBCA87) -#define Z7_XXH_PRIME64_2 UINT64_CONST(0xC2B2AE3D27D4EB4F) -#define Z7_XXH_PRIME64_3 UINT64_CONST(0x165667B19E3779F9) -#define Z7_XXH_PRIME64_4 UINT64_CONST(0x85EBCA77C2B2AE63) -#define Z7_XXH_PRIME64_5 UINT64_CONST(0x27D4EB2F165667C5) - -void Xxh64State_Init(CXxh64State *p) -{ - const UInt64 seed = 0; - p->v[0] = seed + Z7_XXH_PRIME64_1 + Z7_XXH_PRIME64_2; - p->v[1] = seed + Z7_XXH_PRIME64_2; - p->v[2] = seed; - p->v[3] = seed - Z7_XXH_PRIME64_1; -} - -#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) && defined(_MSC_VER) - #define Z7_XXH64_USE_ASM -#endif - -#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) \ - && defined(Z7_MSC_VER_ORIGINAL) && Z7_MSC_VER_ORIGINAL > 1200 -/* we try to avoid __allmul calls in MSVC for 64-bit multiply. - But MSVC6 still uses __allmul for our code. - So for MSVC6 we use default 64-bit multiply without our optimization. -*/ -#define LOW32(b) ((UInt32)(b & 0xffffffff)) -/* MSVC compiler (MSVC > 1200) can use "mul" instruction - without __allmul for our MY_emulu MACRO. - MY_emulu is similar to __emulu(a, b) MACRO */ -#define MY_emulu(a, b) ((UInt64)(a) * (b)) -#define MY_SET_HIGH32(a) ((UInt64)(a) << 32) -#define MY_MUL32_SET_HIGH32(a, b) MY_SET_HIGH32((UInt32)(a) * (UInt32)(b)) -// /* -#define MY_MUL64(a, b) \ - ( MY_emulu((UInt32)(a), LOW32(b)) + \ - MY_SET_HIGH32( \ - (UInt32)((a) >> 32) * LOW32(b) + \ - (UInt32)(a) * (UInt32)((b) >> 32) \ - )) -// */ -/* -#define MY_MUL64(a, b) \ - ( MY_emulu((UInt32)(a), LOW32(b)) \ - + MY_MUL32_SET_HIGH32((a) >> 32, LOW32(b)) + \ - + MY_MUL32_SET_HIGH32(a, (b) >> 32) \ - ) -*/ - -#define MY_MUL_32_64(a32, b) \ - ( MY_emulu((UInt32)(a32), LOW32(b)) \ - + MY_MUL32_SET_HIGH32(a32, (b) >> 32) \ - ) - -#else -#define MY_MUL64(a, b) ((a) * (b)) -#define MY_MUL_32_64(a32, b) ((a32) * (UInt64)(b)) -#endif - - -static -Z7_FORCE_INLINE -UInt64 Xxh64_Round(UInt64 acc, UInt64 input) -{ - acc += MY_MUL64(input, Z7_XXH_PRIME64_2); - acc = Z7_ROTL64(acc, 31); - return MY_MUL64(acc, Z7_XXH_PRIME64_1); -} - -static UInt64 Xxh64_Merge(UInt64 acc, UInt64 val) -{ - acc ^= Xxh64_Round(0, val); - return MY_MUL64(acc, Z7_XXH_PRIME64_1) + Z7_XXH_PRIME64_4; -} - - -#ifdef Z7_XXH64_USE_ASM - -#define Z7_XXH_PRIME64_1_HIGH 0x9E3779B1 -#define Z7_XXH_PRIME64_1_LOW 0x85EBCA87 -#define Z7_XXH_PRIME64_2_HIGH 0xC2B2AE3D -#define Z7_XXH_PRIME64_2_LOW 0x27D4EB4F - -void -Z7_NO_INLINE -__declspec(naked) -Z7_FASTCALL -Xxh64State_UpdateBlocks(CXxh64State *p, const void *data, const void *end) -{ - #if !defined(__clang__) - UNUSED_VAR(p) - UNUSED_VAR(data) - UNUSED_VAR(end) - #endif - __asm push ebx - __asm push ebp - __asm push esi - __asm push edi - - #define STACK_OFFSET 4 * 8 - __asm sub esp, STACK_OFFSET - -#define COPY_1(n) \ - __asm mov eax, [ecx + n * 4] \ - __asm mov [esp + n * 4], eax \ - -#define COPY_2(n) \ - __asm mov eax, [esp + n * 4] \ - __asm mov [ecx + n * 4], eax \ - - COPY_1(0) - __asm mov edi, [ecx + 1 * 4] \ - COPY_1(2) - COPY_1(3) - COPY_1(4) - COPY_1(5) - COPY_1(6) - COPY_1(7) - - __asm mov esi, edx \ - __asm mov [esp + 0 * 8 + 4], ecx - __asm mov ecx, Z7_XXH_PRIME64_2_LOW \ - __asm mov ebp, Z7_XXH_PRIME64_1_LOW \ - -#define R(n, state1, state1_reg) \ - __asm mov eax, [esi + n * 8] \ - __asm imul ebx, eax, Z7_XXH_PRIME64_2_HIGH \ - __asm add ebx, state1 \ - __asm mul ecx \ - __asm add edx, ebx \ - __asm mov ebx, [esi + n * 8 + 4] \ - __asm imul ebx, ecx \ - __asm add eax, [esp + n * 8] \ - __asm adc edx, ebx \ - __asm mov ebx, eax \ - __asm shld eax, edx, 31 \ - __asm shld edx, ebx, 31 \ - __asm imul state1_reg, eax, Z7_XXH_PRIME64_1_HIGH \ - __asm imul edx, ebp \ - __asm add state1_reg, edx \ - __asm mul ebp \ - __asm add state1_reg, edx \ - __asm mov [esp + n * 8], eax \ - -#define R2(n) \ - R(n, [esp + n * 8 + 4], ebx) \ - __asm mov [esp + n * 8 + 4], ebx \ - - __asm align 16 - __asm main_loop: - R(0, edi, edi) - R2(1) - R2(2) - R2(3) - __asm add esi, 32 - __asm cmp esi, [esp + STACK_OFFSET + 4 * 4 + 4] - __asm jne main_loop - - __asm mov ecx, [esp + 0 * 8 + 4] - - COPY_2(0) - __asm mov [ecx + 1 * 4], edi - COPY_2(2) - COPY_2(3) - COPY_2(4) - COPY_2(5) - COPY_2(6) - COPY_2(7) - - __asm add esp, STACK_OFFSET - __asm pop edi - __asm pop esi - __asm pop ebp - __asm pop ebx - __asm ret 4 -} - -#else - -void -Z7_NO_INLINE -Z7_FASTCALL -Xxh64State_UpdateBlocks(CXxh64State *p, const void *_data, const void *end) -{ - const Byte *data = (const Byte *)_data; - UInt64 v[4]; - v[0] = p->v[0]; - v[1] = p->v[1]; - v[2] = p->v[2]; - v[3] = p->v[3]; - do - { - v[0] = Xxh64_Round(v[0], GetUi64(data)); data += 8; - v[1] = Xxh64_Round(v[1], GetUi64(data)); data += 8; - v[2] = Xxh64_Round(v[2], GetUi64(data)); data += 8; - v[3] = Xxh64_Round(v[3], GetUi64(data)); data += 8; - } - while (data != end); - p->v[0] = v[0]; - p->v[1] = v[1]; - p->v[2] = v[2]; - p->v[3] = v[3]; -} - -#endif - -UInt64 Xxh64State_Digest(const CXxh64State *p, const void *_data, UInt64 count) -{ - UInt64 h = p->v[2]; - - if (count >= 32) - { - h = Z7_ROTL64(p->v[0], 1) + - Z7_ROTL64(p->v[1], 7) + - Z7_ROTL64(h, 12) + - Z7_ROTL64(p->v[3], 18); - h = Xxh64_Merge(h, p->v[0]); - h = Xxh64_Merge(h, p->v[1]); - h = Xxh64_Merge(h, p->v[2]); - h = Xxh64_Merge(h, p->v[3]); - } - else - h += Z7_XXH_PRIME64_5; - - h += count; - - // XXH64_finalize(): - { - unsigned cnt = (unsigned)count & 31; - const Byte *data = (const Byte *)_data; - while (cnt >= 8) - { - h ^= Xxh64_Round(0, GetUi64(data)); - data += 8; - h = Z7_ROTL64(h, 27); - h = MY_MUL64(h, Z7_XXH_PRIME64_1) + Z7_XXH_PRIME64_4; - cnt -= 8; - } - if (cnt >= 4) - { - const UInt32 v = GetUi32(data); - data += 4; - h ^= MY_MUL_32_64(v, Z7_XXH_PRIME64_1); - h = Z7_ROTL64(h, 23); - h = MY_MUL64(h, Z7_XXH_PRIME64_2) + Z7_XXH_PRIME64_3; - cnt -= 4; - } - while (cnt) - { - const UInt32 v = *data++; - h ^= MY_MUL_32_64(v, Z7_XXH_PRIME64_5); - h = Z7_ROTL64(h, 11); - h = MY_MUL64(h, Z7_XXH_PRIME64_1); - cnt--; - } - // XXH64_avalanche(h): - h ^= h >> 33; h = MY_MUL64(h, Z7_XXH_PRIME64_2); - h ^= h >> 29; h = MY_MUL64(h, Z7_XXH_PRIME64_3); - h ^= h >> 32; - return h; - } -} - - -void Xxh64_Init(CXxh64 *p) -{ - Xxh64State_Init(&p->state); - p->count = 0; - p->buf64[0] = 0; - p->buf64[1] = 0; - p->buf64[2] = 0; - p->buf64[3] = 0; -} - -void Xxh64_Update(CXxh64 *p, const void *_data, size_t size) -{ - const Byte *data = (const Byte *)_data; - unsigned cnt; - if (size == 0) - return; - cnt = (unsigned)p->count; - p->count += size; - - if (cnt &= 31) - { - unsigned rem = 32 - cnt; - Byte *dest = (Byte *)p->buf64 + cnt; - if (rem > size) - rem = (unsigned)size; - size -= rem; - cnt += rem; - // memcpy((Byte *)p->buf64 + cnt, data, rem); - do - *dest++ = *data++; - while (--rem); - if (cnt != 32) - return; - Xxh64State_UpdateBlocks(&p->state, p->buf64, &p->buf64[4]); - } - - if (size &= ~(size_t)31) - { - Xxh64State_UpdateBlocks(&p->state, data, data + size); - data += size; - } - - cnt = (unsigned)p->count & 31; - if (cnt) - { - // memcpy(p->buf64, data, cnt); - Byte *dest = (Byte *)p->buf64; - do - *dest++ = *data++; - while (--cnt); - } -} +/* Xxh64.c -- XXH64 hash calculation +original code: Copyright (c) Yann Collet. +2023-08-18 : modified by Igor Pavlov. +This source code is licensed under BSD 2-Clause License. +*/ + +#include "Precomp.h" + +#include "CpuArch.h" +#include "RotateDefs.h" +#include "Xxh64.h" + +#define Z7_XXH_PRIME64_1 UINT64_CONST(0x9E3779B185EBCA87) +#define Z7_XXH_PRIME64_2 UINT64_CONST(0xC2B2AE3D27D4EB4F) +#define Z7_XXH_PRIME64_3 UINT64_CONST(0x165667B19E3779F9) +#define Z7_XXH_PRIME64_4 UINT64_CONST(0x85EBCA77C2B2AE63) +#define Z7_XXH_PRIME64_5 UINT64_CONST(0x27D4EB2F165667C5) + +void Xxh64State_Init(CXxh64State *p) +{ + const UInt64 seed = 0; + p->v[0] = seed + Z7_XXH_PRIME64_1 + Z7_XXH_PRIME64_2; + p->v[1] = seed + Z7_XXH_PRIME64_2; + p->v[2] = seed; + p->v[3] = seed - Z7_XXH_PRIME64_1; +} + +#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) && defined(_MSC_VER) + #define Z7_XXH64_USE_ASM +#endif + +#if !defined(MY_CPU_64BIT) && defined(MY_CPU_X86) \ + && defined(Z7_MSC_VER_ORIGINAL) && Z7_MSC_VER_ORIGINAL > 1200 +/* we try to avoid __allmul calls in MSVC for 64-bit multiply. + But MSVC6 still uses __allmul for our code. + So for MSVC6 we use default 64-bit multiply without our optimization. +*/ +#define LOW32(b) ((UInt32)(b & 0xffffffff)) +/* MSVC compiler (MSVC > 1200) can use "mul" instruction + without __allmul for our MY_emulu MACRO. + MY_emulu is similar to __emulu(a, b) MACRO */ +#define MY_emulu(a, b) ((UInt64)(a) * (b)) +#define MY_SET_HIGH32(a) ((UInt64)(a) << 32) +#define MY_MUL32_SET_HIGH32(a, b) MY_SET_HIGH32((UInt32)(a) * (UInt32)(b)) +// /* +#define MY_MUL64(a, b) \ + ( MY_emulu((UInt32)(a), LOW32(b)) + \ + MY_SET_HIGH32( \ + (UInt32)((a) >> 32) * LOW32(b) + \ + (UInt32)(a) * (UInt32)((b) >> 32) \ + )) +// */ +/* +#define MY_MUL64(a, b) \ + ( MY_emulu((UInt32)(a), LOW32(b)) \ + + MY_MUL32_SET_HIGH32((a) >> 32, LOW32(b)) + \ + + MY_MUL32_SET_HIGH32(a, (b) >> 32) \ + ) +*/ + +#define MY_MUL_32_64(a32, b) \ + ( MY_emulu((UInt32)(a32), LOW32(b)) \ + + MY_MUL32_SET_HIGH32(a32, (b) >> 32) \ + ) + +#else +#define MY_MUL64(a, b) ((a) * (b)) +#define MY_MUL_32_64(a32, b) ((a32) * (UInt64)(b)) +#endif + + +static +Z7_FORCE_INLINE +UInt64 Xxh64_Round(UInt64 acc, UInt64 input) +{ + acc += MY_MUL64(input, Z7_XXH_PRIME64_2); + acc = Z7_ROTL64(acc, 31); + return MY_MUL64(acc, Z7_XXH_PRIME64_1); +} + +static UInt64 Xxh64_Merge(UInt64 acc, UInt64 val) +{ + acc ^= Xxh64_Round(0, val); + return MY_MUL64(acc, Z7_XXH_PRIME64_1) + Z7_XXH_PRIME64_4; +} + + +#ifdef Z7_XXH64_USE_ASM + +#define Z7_XXH_PRIME64_1_HIGH 0x9E3779B1 +#define Z7_XXH_PRIME64_1_LOW 0x85EBCA87 +#define Z7_XXH_PRIME64_2_HIGH 0xC2B2AE3D +#define Z7_XXH_PRIME64_2_LOW 0x27D4EB4F + +void +Z7_NO_INLINE +__declspec(naked) +Z7_FASTCALL +Xxh64State_UpdateBlocks(CXxh64State *p, const void *data, const void *end) +{ + #if !defined(__clang__) + UNUSED_VAR(p) + UNUSED_VAR(data) + UNUSED_VAR(end) + #endif + __asm push ebx + __asm push ebp + __asm push esi + __asm push edi + + #define STACK_OFFSET 4 * 8 + __asm sub esp, STACK_OFFSET + +#define COPY_1(n) \ + __asm mov eax, [ecx + n * 4] \ + __asm mov [esp + n * 4], eax \ + +#define COPY_2(n) \ + __asm mov eax, [esp + n * 4] \ + __asm mov [ecx + n * 4], eax \ + + COPY_1(0) + __asm mov edi, [ecx + 1 * 4] \ + COPY_1(2) + COPY_1(3) + COPY_1(4) + COPY_1(5) + COPY_1(6) + COPY_1(7) + + __asm mov esi, edx \ + __asm mov [esp + 0 * 8 + 4], ecx + __asm mov ecx, Z7_XXH_PRIME64_2_LOW \ + __asm mov ebp, Z7_XXH_PRIME64_1_LOW \ + +#define R(n, state1, state1_reg) \ + __asm mov eax, [esi + n * 8] \ + __asm imul ebx, eax, Z7_XXH_PRIME64_2_HIGH \ + __asm add ebx, state1 \ + __asm mul ecx \ + __asm add edx, ebx \ + __asm mov ebx, [esi + n * 8 + 4] \ + __asm imul ebx, ecx \ + __asm add eax, [esp + n * 8] \ + __asm adc edx, ebx \ + __asm mov ebx, eax \ + __asm shld eax, edx, 31 \ + __asm shld edx, ebx, 31 \ + __asm imul state1_reg, eax, Z7_XXH_PRIME64_1_HIGH \ + __asm imul edx, ebp \ + __asm add state1_reg, edx \ + __asm mul ebp \ + __asm add state1_reg, edx \ + __asm mov [esp + n * 8], eax \ + +#define R2(n) \ + R(n, [esp + n * 8 + 4], ebx) \ + __asm mov [esp + n * 8 + 4], ebx \ + + __asm align 16 + __asm main_loop: + R(0, edi, edi) + R2(1) + R2(2) + R2(3) + __asm add esi, 32 + __asm cmp esi, [esp + STACK_OFFSET + 4 * 4 + 4] + __asm jne main_loop + + __asm mov ecx, [esp + 0 * 8 + 4] + + COPY_2(0) + __asm mov [ecx + 1 * 4], edi + COPY_2(2) + COPY_2(3) + COPY_2(4) + COPY_2(5) + COPY_2(6) + COPY_2(7) + + __asm add esp, STACK_OFFSET + __asm pop edi + __asm pop esi + __asm pop ebp + __asm pop ebx + __asm ret 4 +} + +#else + +void +Z7_NO_INLINE +Z7_FASTCALL +Xxh64State_UpdateBlocks(CXxh64State *p, const void *_data, const void *end) +{ + const Byte *data = (const Byte *)_data; + UInt64 v[4]; + v[0] = p->v[0]; + v[1] = p->v[1]; + v[2] = p->v[2]; + v[3] = p->v[3]; + do + { + v[0] = Xxh64_Round(v[0], GetUi64(data)); data += 8; + v[1] = Xxh64_Round(v[1], GetUi64(data)); data += 8; + v[2] = Xxh64_Round(v[2], GetUi64(data)); data += 8; + v[3] = Xxh64_Round(v[3], GetUi64(data)); data += 8; + } + while (data != end); + p->v[0] = v[0]; + p->v[1] = v[1]; + p->v[2] = v[2]; + p->v[3] = v[3]; +} + +#endif + +UInt64 Xxh64State_Digest(const CXxh64State *p, const void *_data, UInt64 count) +{ + UInt64 h = p->v[2]; + + if (count >= 32) + { + h = Z7_ROTL64(p->v[0], 1) + + Z7_ROTL64(p->v[1], 7) + + Z7_ROTL64(h, 12) + + Z7_ROTL64(p->v[3], 18); + h = Xxh64_Merge(h, p->v[0]); + h = Xxh64_Merge(h, p->v[1]); + h = Xxh64_Merge(h, p->v[2]); + h = Xxh64_Merge(h, p->v[3]); + } + else + h += Z7_XXH_PRIME64_5; + + h += count; + + // XXH64_finalize(): + { + unsigned cnt = (unsigned)count & 31; + const Byte *data = (const Byte *)_data; + while (cnt >= 8) + { + h ^= Xxh64_Round(0, GetUi64(data)); + data += 8; + h = Z7_ROTL64(h, 27); + h = MY_MUL64(h, Z7_XXH_PRIME64_1) + Z7_XXH_PRIME64_4; + cnt -= 8; + } + if (cnt >= 4) + { + const UInt32 v = GetUi32(data); + data += 4; + h ^= MY_MUL_32_64(v, Z7_XXH_PRIME64_1); + h = Z7_ROTL64(h, 23); + h = MY_MUL64(h, Z7_XXH_PRIME64_2) + Z7_XXH_PRIME64_3; + cnt -= 4; + } + while (cnt) + { + const UInt32 v = *data++; + h ^= MY_MUL_32_64(v, Z7_XXH_PRIME64_5); + h = Z7_ROTL64(h, 11); + h = MY_MUL64(h, Z7_XXH_PRIME64_1); + cnt--; + } + // XXH64_avalanche(h): + h ^= h >> 33; h = MY_MUL64(h, Z7_XXH_PRIME64_2); + h ^= h >> 29; h = MY_MUL64(h, Z7_XXH_PRIME64_3); + h ^= h >> 32; + return h; + } +} + + +void Xxh64_Init(CXxh64 *p) +{ + Xxh64State_Init(&p->state); + p->count = 0; + p->buf64[0] = 0; + p->buf64[1] = 0; + p->buf64[2] = 0; + p->buf64[3] = 0; +} + +void Xxh64_Update(CXxh64 *p, const void *_data, size_t size) +{ + const Byte *data = (const Byte *)_data; + unsigned cnt; + if (size == 0) + return; + cnt = (unsigned)p->count; + p->count += size; + + if (cnt &= 31) + { + unsigned rem = 32 - cnt; + Byte *dest = (Byte *)p->buf64 + cnt; + if (rem > size) + rem = (unsigned)size; + size -= rem; + cnt += rem; + // memcpy((Byte *)p->buf64 + cnt, data, rem); + do + *dest++ = *data++; + while (--rem); + if (cnt != 32) + return; + Xxh64State_UpdateBlocks(&p->state, p->buf64, &p->buf64[4]); + } + + if (size &= ~(size_t)31) + { + Xxh64State_UpdateBlocks(&p->state, data, data + size); + data += size; + } + + cnt = (unsigned)p->count & 31; + if (cnt) + { + // memcpy(p->buf64, data, cnt); + Byte *dest = (Byte *)p->buf64; + do + *dest++ = *data++; + while (--cnt); + } +} diff --git a/C/Xxh64.h b/C/Xxh64.h index e22dcd4cf..efef65eb3 100644 --- a/C/Xxh64.h +++ b/C/Xxh64.h @@ -1,50 +1,50 @@ -/* Xxh64.h -- XXH64 hash calculation interfaces -2023-08-18 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_XXH64_H -#define ZIP7_INC_XXH64_H - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -#define Z7_XXH64_BLOCK_SIZE (4 * 8) - -typedef struct -{ - UInt64 v[4]; -} CXxh64State; - -void Xxh64State_Init(CXxh64State *p); - -// end != data && end == data + Z7_XXH64_BLOCK_SIZE * numBlocks -void Z7_FASTCALL Xxh64State_UpdateBlocks(CXxh64State *p, const void *data, const void *end); - -/* -Xxh64State_Digest(): -data: - the function processes only - (totalCount & (Z7_XXH64_BLOCK_SIZE - 1)) bytes in (data): (smaller than 32 bytes). -totalCount: total size of hashed stream: - it includes total size of data processed by previous Xxh64State_UpdateBlocks() calls, - and it also includes current processed size in (data). -*/ -UInt64 Xxh64State_Digest(const CXxh64State *p, const void *data, UInt64 totalCount); - - -typedef struct -{ - CXxh64State state; - UInt64 count; - UInt64 buf64[4]; -} CXxh64; - -void Xxh64_Init(CXxh64 *p); -void Xxh64_Update(CXxh64 *p, const void *data, size_t size); - -#define Xxh64_Digest(p) \ - Xxh64State_Digest(&(p)->state, (p)->buf64, (p)->count) - -EXTERN_C_END - -#endif +/* Xxh64.h -- XXH64 hash calculation interfaces +2023-08-18 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XXH64_H +#define ZIP7_INC_XXH64_H + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +#define Z7_XXH64_BLOCK_SIZE (4 * 8) + +typedef struct +{ + UInt64 v[4]; +} CXxh64State; + +void Xxh64State_Init(CXxh64State *p); + +// end != data && end == data + Z7_XXH64_BLOCK_SIZE * numBlocks +void Z7_FASTCALL Xxh64State_UpdateBlocks(CXxh64State *p, const void *data, const void *end); + +/* +Xxh64State_Digest(): +data: + the function processes only + (totalCount & (Z7_XXH64_BLOCK_SIZE - 1)) bytes in (data): (smaller than 32 bytes). +totalCount: total size of hashed stream: + it includes total size of data processed by previous Xxh64State_UpdateBlocks() calls, + and it also includes current processed size in (data). +*/ +UInt64 Xxh64State_Digest(const CXxh64State *p, const void *data, UInt64 totalCount); + + +typedef struct +{ + CXxh64State state; + UInt64 count; + UInt64 buf64[4]; +} CXxh64; + +void Xxh64_Init(CXxh64 *p); +void Xxh64_Update(CXxh64 *p, const void *data, size_t size); + +#define Xxh64_Digest(p) \ + Xxh64State_Digest(&(p)->state, (p)->buf64, (p)->count) + +EXTERN_C_END + +#endif diff --git a/C/Xz.c b/C/Xz.c index 92bae029e..d07550d09 100644 --- a/C/Xz.c +++ b/C/Xz.c @@ -1,92 +1,92 @@ -/* Xz.c - Xz -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "7zCrc.h" -#include "CpuArch.h" -#include "Xz.h" -#include "XzCrc64.h" - -const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; -/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */ - -unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) -{ - unsigned i = 0; - do - { - buf[i++] = (Byte)((v & 0x7F) | 0x80); - v >>= 7; - } - while (v != 0); - buf[(size_t)i - 1] &= 0x7F; - return i; -} - -void Xz_Construct(CXzStream *p) -{ - p->numBlocks = 0; - p->blocks = NULL; - p->flags = 0; -} - -void Xz_Free(CXzStream *p, ISzAllocPtr alloc) -{ - ISzAlloc_Free(alloc, p->blocks); - p->numBlocks = 0; - p->blocks = NULL; -} - -unsigned XzFlags_GetCheckSize(CXzStreamFlags f) -{ - unsigned t = XzFlags_GetCheckType(f); - return (t == 0) ? 0 : ((unsigned)4 << ((t - 1) / 3)); -} - -void XzCheck_Init(CXzCheck *p, unsigned mode) -{ - p->mode = mode; - switch (mode) - { - case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; - case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; - case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; - default: break; - } -} - -void XzCheck_Update(CXzCheck *p, const void *data, size_t size) -{ - switch (p->mode) - { - case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; - case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; - case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; - default: break; - } -} - -int XzCheck_Final(CXzCheck *p, Byte *digest) -{ - switch (p->mode) - { - case XZ_CHECK_CRC32: - SetUi32(digest, CRC_GET_DIGEST(p->crc)) - break; - case XZ_CHECK_CRC64: - { - int i; - UInt64 v = CRC64_GET_DIGEST(p->crc64); - for (i = 0; i < 8; i++, v >>= 8) - digest[i] = (Byte)(v & 0xFF); - break; - } - case XZ_CHECK_SHA256: - Sha256_Final(&p->sha, digest); - break; - default: - return 0; - } - return 1; -} +/* Xz.c - Xz +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" +#include "XzCrc64.h" + +const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; +/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */ + +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) +{ + unsigned i = 0; + do + { + buf[i++] = (Byte)((v & 0x7F) | 0x80); + v >>= 7; + } + while (v != 0); + buf[(size_t)i - 1] &= 0x7F; + return i; +} + +void Xz_Construct(CXzStream *p) +{ + p->numBlocks = 0; + p->blocks = NULL; + p->flags = 0; +} + +void Xz_Free(CXzStream *p, ISzAllocPtr alloc) +{ + ISzAlloc_Free(alloc, p->blocks); + p->numBlocks = 0; + p->blocks = NULL; +} + +unsigned XzFlags_GetCheckSize(CXzStreamFlags f) +{ + unsigned t = XzFlags_GetCheckType(f); + return (t == 0) ? 0 : ((unsigned)4 << ((t - 1) / 3)); +} + +void XzCheck_Init(CXzCheck *p, unsigned mode) +{ + p->mode = mode; + switch (mode) + { + case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break; + case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break; + case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break; + default: break; + } +} + +void XzCheck_Update(CXzCheck *p, const void *data, size_t size) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break; + case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break; + case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break; + default: break; + } +} + +int XzCheck_Final(CXzCheck *p, Byte *digest) +{ + switch (p->mode) + { + case XZ_CHECK_CRC32: + SetUi32(digest, CRC_GET_DIGEST(p->crc)) + break; + case XZ_CHECK_CRC64: + { + int i; + UInt64 v = CRC64_GET_DIGEST(p->crc64); + for (i = 0; i < 8; i++, v >>= 8) + digest[i] = (Byte)(v & 0xFF); + break; + } + case XZ_CHECK_SHA256: + Sha256_Final(&p->sha, digest); + break; + default: + return 0; + } + return 1; +} diff --git a/C/Xz.h b/C/Xz.h index 34502e99f..42bc68534 100644 --- a/C/Xz.h +++ b/C/Xz.h @@ -1,536 +1,536 @@ -/* Xz.h - Xz interface -2024-01-26 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_XZ_H -#define ZIP7_INC_XZ_H - -#include "Sha256.h" -#include "Delta.h" - -EXTERN_C_BEGIN - -#define XZ_ID_Subblock 1 -#define XZ_ID_Delta 3 -#define XZ_ID_X86 4 -#define XZ_ID_PPC 5 -#define XZ_ID_IA64 6 -#define XZ_ID_ARM 7 -#define XZ_ID_ARMT 8 -#define XZ_ID_SPARC 9 -#define XZ_ID_ARM64 0xa -#define XZ_ID_RISCV 0xb -#define XZ_ID_LZMA2 0x21 - -unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); -unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); - -/* ---------- xz block ---------- */ - -#define XZ_BLOCK_HEADER_SIZE_MAX 1024 - -#define XZ_NUM_FILTERS_MAX 4 -#define XZ_BF_NUM_FILTERS_MASK 3 -#define XZ_BF_PACK_SIZE (1 << 6) -#define XZ_BF_UNPACK_SIZE (1 << 7) - -#define XZ_FILTER_PROPS_SIZE_MAX 20 - -typedef struct -{ - UInt64 id; - UInt32 propsSize; - Byte props[XZ_FILTER_PROPS_SIZE_MAX]; -} CXzFilter; - -typedef struct -{ - UInt64 packSize; - UInt64 unpackSize; - Byte flags; - CXzFilter filters[XZ_NUM_FILTERS_MAX]; -} CXzBlock; - -#define XzBlock_GetNumFilters(p) (((unsigned)(p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) -#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) -#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) -#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0) - -SRes XzBlock_Parse(CXzBlock *p, const Byte *header); -SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes); - -/* ---------- xz stream ---------- */ - -#define XZ_SIG_SIZE 6 -#define XZ_FOOTER_SIG_SIZE 2 - -extern const Byte XZ_SIG[XZ_SIG_SIZE]; - -/* -extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; -*/ - -#define XZ_FOOTER_SIG_0 'Y' -#define XZ_FOOTER_SIG_1 'Z' - -#define XZ_STREAM_FLAGS_SIZE 2 -#define XZ_STREAM_CRC_SIZE 4 - -#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) -#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) - -#define XZ_CHECK_MASK 0xF -#define XZ_CHECK_NO 0 -#define XZ_CHECK_CRC32 1 -#define XZ_CHECK_CRC64 4 -#define XZ_CHECK_SHA256 10 - -typedef struct -{ - unsigned mode; - UInt32 crc; - UInt64 crc64; - CSha256 sha; -} CXzCheck; - -void XzCheck_Init(CXzCheck *p, unsigned mode); -void XzCheck_Update(CXzCheck *p, const void *data, size_t size); -int XzCheck_Final(CXzCheck *p, Byte *digest); - -typedef UInt16 CXzStreamFlags; - -#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) -#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) -#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) -unsigned XzFlags_GetCheckSize(CXzStreamFlags f); - -SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); -SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream); - -typedef struct -{ - UInt64 unpackSize; - UInt64 totalSize; -} CXzBlockSizes; - -typedef struct -{ - CXzStreamFlags flags; - // Byte _pad[6]; - size_t numBlocks; - CXzBlockSizes *blocks; - UInt64 startOffset; -} CXzStream; - -void Xz_Construct(CXzStream *p); -void Xz_Free(CXzStream *p, ISzAllocPtr alloc); - -#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) - -UInt64 Xz_GetUnpackSize(const CXzStream *p); -UInt64 Xz_GetPackSize(const CXzStream *p); - -typedef struct -{ - size_t num; - size_t numAllocated; - CXzStream *streams; -} CXzs; - -void Xzs_Construct(CXzs *p); -void Xzs_Free(CXzs *p, ISzAllocPtr alloc); -SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc); - -UInt64 Xzs_GetNumBlocks(const CXzs *p); -UInt64 Xzs_GetUnpackSize(const CXzs *p); - - -// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder - -typedef enum -{ - CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ - CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ - CODER_STATUS_NOT_FINISHED, /* stream was not finished */ - CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ -} ECoderStatus; - - -// ECoderFinishMode values are identical to ELzmaFinishMode - -typedef enum -{ - CODER_FINISH_ANY, /* finish at any point */ - CODER_FINISH_END /* block must be finished at the end */ -} ECoderFinishMode; - - -typedef struct -{ - void *p; // state object; - void (*Free)(void *p, ISzAllocPtr alloc); - SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); - void (*Init)(void *p); - SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - int srcWasFinished, ECoderFinishMode finishMode, - // int *wasFinished, - ECoderStatus *status); - SizeT (*Filter)(void *p, Byte *data, SizeT size); -} IStateCoder; - - -typedef struct -{ - UInt32 methodId; - UInt32 delta; - UInt32 ip; - UInt32 X86_State; - Byte delta_State[DELTA_STATE_SIZE]; -} CXzBcFilterStateBase; - -typedef SizeT (*Xz_Func_BcFilterStateBase_Filter)(CXzBcFilterStateBase *p, Byte *data, SizeT size); - -SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id, - Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc); - - -#define MIXCODER_NUM_FILTERS_MAX 4 - -typedef struct -{ - ISzAllocPtr alloc; - Byte *buf; - unsigned numCoders; - - Byte *outBuf; - size_t outBufSize; - size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode) - BoolInt wasFinished; - SRes res; - ECoderStatus status; - // BoolInt SingleBufMode; - - int finished[MIXCODER_NUM_FILTERS_MAX - 1]; - size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; - size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; - UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; - SRes results[MIXCODER_NUM_FILTERS_MAX]; - IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; -} CMixCoder; - - -typedef enum -{ - XZ_STATE_STREAM_HEADER, - XZ_STATE_STREAM_INDEX, - XZ_STATE_STREAM_INDEX_CRC, - XZ_STATE_STREAM_FOOTER, - XZ_STATE_STREAM_PADDING, - XZ_STATE_BLOCK_HEADER, - XZ_STATE_BLOCK, - XZ_STATE_BLOCK_FOOTER -} EXzState; - - -typedef struct -{ - EXzState state; - unsigned pos; - unsigned alignPos; - unsigned indexPreSize; - - CXzStreamFlags streamFlags; - - unsigned blockHeaderSize; - UInt64 packSize; - UInt64 unpackSize; - - UInt64 numBlocks; // number of finished blocks in current stream - UInt64 indexSize; - UInt64 indexPos; - UInt64 padSize; - - UInt64 numStartedStreams; - UInt64 numFinishedStreams; - UInt64 numTotalBlocks; - - UInt32 crc; - CMixCoder decoder; - CXzBlock block; - CXzCheck check; - CSha256 sha; - - BoolInt parseMode; - BoolInt headerParsedOk; - BoolInt decodeToStreamSignature; - unsigned decodeOnlyOneBlock; - - Byte *outBuf; - size_t outBufSize; - size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked - - Byte shaDigest[SHA256_DIGEST_SIZE]; - Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; -} CXzUnpacker; - -/* alloc : aligned for cache line allocation is better */ -void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); -void XzUnpacker_Init(CXzUnpacker *p); -void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize); -void XzUnpacker_Free(CXzUnpacker *p); - -/* - XzUnpacker - The sequence for decoding functions: - { - XzUnpacker_Construct() - [Decoding_Calls] - XzUnpacker_Free() - } - - [Decoding_Calls] - - There are 3 types of interfaces for [Decoding_Calls] calls: - - Interface-1 : Partial output buffers: - { - XzUnpacker_Init() - for() - { - XzUnpacker_Code(); - } - XzUnpacker_IsStreamWasFinished() - } - - Interface-2 : Direct output buffer: - Use it, if you know exact size of decoded data, and you need - whole xz unpacked data in one output buffer. - xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode. - { - XzUnpacker_Init() - XzUnpacker_SetOutBufMode(); // to set output buffer and size - for() - { - XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code() - } - XzUnpacker_IsStreamWasFinished() - } - - Interface-3 : Direct output buffer : One call full decoding - It unpacks whole input buffer to output buffer in one call. - It uses Interface-2 internally. - { - XzUnpacker_CodeFull() - XzUnpacker_IsStreamWasFinished() - } -*/ - -/* -finishMode: - It has meaning only if the decoding reaches output limit (*destLen). - CODER_FINISH_ANY - use smallest number of input bytes - CODER_FINISH_END - read EndOfStream marker after decoding - -Returns: - SZ_OK - status: - CODER_STATUS_NOT_FINISHED, - CODER_STATUS_NEEDS_MORE_INPUT - the decoder can return it in two cases: - 1) it needs more input data to finish current xz stream - 2) xz stream was finished successfully. But the decoder supports multiple - concatented xz streams. So it expects more input data for new xz streams. - Call XzUnpacker_IsStreamWasFinished() to check that latest xz stream was finished successfully. - - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_DATA - Data error - SZ_ERROR_UNSUPPORTED - Unsupported method or method properties - SZ_ERROR_CRC - CRC error - // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). - - SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: - - xz Stream Signature failure - - CRC32 of xz Stream Header is failed - - The size of Stream padding is not multiple of four bytes. - It's possible to get that error, if xz stream was finished and the stream - contains some another data. In that case you can call XzUnpacker_GetExtraSize() - function to get real size of xz stream. -*/ - - -SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, int srcFinished, - ECoderFinishMode finishMode, ECoderStatus *status); - -SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, - ECoderFinishMode finishMode, ECoderStatus *status); - -/* -If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished() -after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code(). -*/ - -BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); - -/* -XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes, - if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state. -These bytes can be some data after xz archive, or -it can be start of new xz stream. - -Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of -xz stream in two cases, if XzUnpacker_Code() returns: - res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT - res == SZ_ERROR_NO_ARCHIVE -*/ - -UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); - - -/* - for random block decoding: - XzUnpacker_Init(); - set CXzUnpacker::streamFlags - XzUnpacker_PrepareToRandomBlockDecoding() - loop - { - XzUnpacker_Code() - XzUnpacker_IsBlockFinished() - } -*/ - -void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); -BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p); - -#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags)) - - - - - - -/* ---- Single-Thread and Multi-Thread xz Decoding with Input/Output Streams ---- */ - -/* - if (CXzDecMtProps::numThreads > 1), the decoder can try to use - Multi-Threading. The decoder analyses xz block header, and if - there are pack size and unpack size values stored in xz block header, - the decoder reads compressed data of block to internal buffers, - and then it can start parallel decoding, if there are another blocks. - The decoder can switch back to Single-Thread decoding after some conditions. - - The sequence of calls for xz decoding with in/out Streams: - { - XzDecMt_Create() - XzDecMtProps_Init(XzDecMtProps) to set default values of properties - // then you can change some XzDecMtProps parameters with required values - // here you can set the number of threads and (memUseMax) - the maximum - Memory usage for multithreading decoding. - for() - { - XzDecMt_Decode() // one call per one file - } - XzDecMt_Destroy() - } -*/ - - -typedef struct -{ - size_t inBufSize_ST; // size of input buffer for Single-Thread decoding - size_t outStep_ST; // size of output buffer for Single-Thread decoding - BoolInt ignoreErrors; // if set to 1, the decoder can ignore some errors and it skips broken parts of data. - - #ifndef Z7_ST - unsigned numThreads; // the number of threads for Multi-Thread decoding. if (umThreads == 1) it will use Single-thread decoding - size_t inBufSize_MT; // size of small input data buffers for Multi-Thread decoding. Big number of such small buffers can be created - size_t memUseMax; // the limit of total memory usage for Multi-Thread decoding. - // it's recommended to set (memUseMax) manually to value that is smaller of total size of RAM in computer. - #endif -} CXzDecMtProps; - -void XzDecMtProps_Init(CXzDecMtProps *p); - -typedef struct CXzDecMt CXzDecMt; -typedef CXzDecMt * CXzDecMtHandle; -// Z7_DECLARE_HANDLE(CXzDecMtHandle) - -/* - alloc : XzDecMt uses CAlignOffsetAlloc internally for addresses allocated by (alloc). - allocMid : for big allocations, aligned allocation is better -*/ - -CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); -void XzDecMt_Destroy(CXzDecMtHandle p); - - -typedef struct -{ - Byte UnpackSize_Defined; - Byte NumStreams_Defined; - Byte NumBlocks_Defined; - - Byte DataAfterEnd; // there are some additional data after good xz streams, and that data is not new xz stream. - Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data - - UInt64 InSize; // pack size processed. That value doesn't include the data after - // end of xz stream, if that data was not correct - UInt64 OutSize; - - UInt64 NumStreams; - UInt64 NumBlocks; - - SRes DecodeRes; // the error code of xz streams data decoding - SRes ReadRes; // error code from ISeqInStream:Read() - SRes ProgressRes; // error code from ICompressProgress:Progress() - - SRes CombinedRes; // Combined result error code that shows main rusult - // = S_OK, if there is no error. - // but check also (DataAfterEnd) that can show additional minor errors. - - SRes CombinedRes_Type; // = SZ_ERROR_READ, if error from ISeqInStream - // = SZ_ERROR_PROGRESS, if error from ICompressProgress - // = SZ_ERROR_WRITE, if error from ISeqOutStream - // = SZ_ERROR_* codes for decoding -} CXzStatInfo; - -void XzStatInfo_Clear(CXzStatInfo *p); - -/* - -XzDecMt_Decode() -SRes: it's combined decoding result. It also is equal to stat->CombinedRes. - - SZ_OK - no error - check also output value in (stat->DataAfterEnd) - that can show additional possible error - - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_NO_ARCHIVE - is not xz archive - SZ_ERROR_ARCHIVE - Headers error - SZ_ERROR_DATA - Data Error - SZ_ERROR_UNSUPPORTED - Unsupported method or method properties - SZ_ERROR_CRC - CRC Error - SZ_ERROR_INPUT_EOF - it needs more input data - SZ_ERROR_WRITE - ISeqOutStream error - (SZ_ERROR_READ) - ISeqInStream errors - (SZ_ERROR_PROGRESS) - ICompressProgress errors - // SZ_ERROR_THREAD - error in multi-threading functions - MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function -*/ - -SRes XzDecMt_Decode(CXzDecMtHandle p, - const CXzDecMtProps *props, - const UInt64 *outDataSize, // NULL means undefined - int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished - ISeqOutStreamPtr outStream, - // Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - // const Byte *inData, size_t inDataSize, - CXzStatInfo *stat, // out: decoding results and statistics - int *isMT, // out: 0 means that ST (Single-Thread) version was used - // 1 means that MT (Multi-Thread) version was used - ICompressProgressPtr progress); - -EXTERN_C_END - -#endif +/* Xz.h - Xz interface +2024-01-26 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XZ_H +#define ZIP7_INC_XZ_H + +#include "Sha256.h" +#include "Delta.h" + +EXTERN_C_BEGIN + +#define XZ_ID_Subblock 1 +#define XZ_ID_Delta 3 +#define XZ_ID_X86 4 +#define XZ_ID_PPC 5 +#define XZ_ID_IA64 6 +#define XZ_ID_ARM 7 +#define XZ_ID_ARMT 8 +#define XZ_ID_SPARC 9 +#define XZ_ID_ARM64 0xa +#define XZ_ID_RISCV 0xb +#define XZ_ID_LZMA2 0x21 + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value); +unsigned Xz_WriteVarInt(Byte *buf, UInt64 v); + +/* ---------- xz block ---------- */ + +#define XZ_BLOCK_HEADER_SIZE_MAX 1024 + +#define XZ_NUM_FILTERS_MAX 4 +#define XZ_BF_NUM_FILTERS_MASK 3 +#define XZ_BF_PACK_SIZE (1 << 6) +#define XZ_BF_UNPACK_SIZE (1 << 7) + +#define XZ_FILTER_PROPS_SIZE_MAX 20 + +typedef struct +{ + UInt64 id; + UInt32 propsSize; + Byte props[XZ_FILTER_PROPS_SIZE_MAX]; +} CXzFilter; + +typedef struct +{ + UInt64 packSize; + UInt64 unpackSize; + Byte flags; + CXzFilter filters[XZ_NUM_FILTERS_MAX]; +} CXzBlock; + +#define XzBlock_GetNumFilters(p) (((unsigned)(p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1) +#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0) +#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0) +#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0) + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header); +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes); + +/* ---------- xz stream ---------- */ + +#define XZ_SIG_SIZE 6 +#define XZ_FOOTER_SIG_SIZE 2 + +extern const Byte XZ_SIG[XZ_SIG_SIZE]; + +/* +extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; +*/ + +#define XZ_FOOTER_SIG_0 'Y' +#define XZ_FOOTER_SIG_1 'Z' + +#define XZ_STREAM_FLAGS_SIZE 2 +#define XZ_STREAM_CRC_SIZE 4 + +#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE) +#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4) + +#define XZ_CHECK_MASK 0xF +#define XZ_CHECK_NO 0 +#define XZ_CHECK_CRC32 1 +#define XZ_CHECK_CRC64 4 +#define XZ_CHECK_SHA256 10 + +typedef struct +{ + unsigned mode; + UInt32 crc; + UInt64 crc64; + CSha256 sha; +} CXzCheck; + +void XzCheck_Init(CXzCheck *p, unsigned mode); +void XzCheck_Update(CXzCheck *p, const void *data, size_t size); +int XzCheck_Final(CXzCheck *p, Byte *digest); + +typedef UInt16 CXzStreamFlags; + +#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK) +#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK) +#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32) +unsigned XzFlags_GetCheckSize(CXzStreamFlags f); + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf); +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream); + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; +} CXzBlockSizes; + +typedef struct +{ + CXzStreamFlags flags; + // Byte _pad[6]; + size_t numBlocks; + CXzBlockSizes *blocks; + UInt64 startOffset; +} CXzStream; + +void Xz_Construct(CXzStream *p); +void Xz_Free(CXzStream *p, ISzAllocPtr alloc); + +#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1) + +UInt64 Xz_GetUnpackSize(const CXzStream *p); +UInt64 Xz_GetPackSize(const CXzStream *p); + +typedef struct +{ + size_t num; + size_t numAllocated; + CXzStream *streams; +} CXzs; + +void Xzs_Construct(CXzs *p); +void Xzs_Free(CXzs *p, ISzAllocPtr alloc); +SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc); + +UInt64 Xzs_GetNumBlocks(const CXzs *p); +UInt64 Xzs_GetUnpackSize(const CXzs *p); + + +// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + +typedef enum +{ + CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ + CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + CODER_STATUS_NOT_FINISHED, /* stream was not finished */ + CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ +} ECoderStatus; + + +// ECoderFinishMode values are identical to ELzmaFinishMode + +typedef enum +{ + CODER_FINISH_ANY, /* finish at any point */ + CODER_FINISH_END /* block must be finished at the end */ +} ECoderFinishMode; + + +typedef struct +{ + void *p; // state object; + void (*Free)(void *p, ISzAllocPtr alloc); + SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc); + void (*Init)(void *p); + SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status); + SizeT (*Filter)(void *p, Byte *data, SizeT size); +} IStateCoder; + + +typedef struct +{ + UInt32 methodId; + UInt32 delta; + UInt32 ip; + UInt32 X86_State; + Byte delta_State[DELTA_STATE_SIZE]; +} CXzBcFilterStateBase; + +typedef SizeT (*Xz_Func_BcFilterStateBase_Filter)(CXzBcFilterStateBase *p, Byte *data, SizeT size); + +SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id, + Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc); + + +#define MIXCODER_NUM_FILTERS_MAX 4 + +typedef struct +{ + ISzAllocPtr alloc; + Byte *buf; + unsigned numCoders; + + Byte *outBuf; + size_t outBufSize; + size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode) + BoolInt wasFinished; + SRes res; + ECoderStatus status; + // BoolInt SingleBufMode; + + int finished[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; + size_t size[MIXCODER_NUM_FILTERS_MAX - 1]; + UInt64 ids[MIXCODER_NUM_FILTERS_MAX]; + SRes results[MIXCODER_NUM_FILTERS_MAX]; + IStateCoder coders[MIXCODER_NUM_FILTERS_MAX]; +} CMixCoder; + + +typedef enum +{ + XZ_STATE_STREAM_HEADER, + XZ_STATE_STREAM_INDEX, + XZ_STATE_STREAM_INDEX_CRC, + XZ_STATE_STREAM_FOOTER, + XZ_STATE_STREAM_PADDING, + XZ_STATE_BLOCK_HEADER, + XZ_STATE_BLOCK, + XZ_STATE_BLOCK_FOOTER +} EXzState; + + +typedef struct +{ + EXzState state; + unsigned pos; + unsigned alignPos; + unsigned indexPreSize; + + CXzStreamFlags streamFlags; + + unsigned blockHeaderSize; + UInt64 packSize; + UInt64 unpackSize; + + UInt64 numBlocks; // number of finished blocks in current stream + UInt64 indexSize; + UInt64 indexPos; + UInt64 padSize; + + UInt64 numStartedStreams; + UInt64 numFinishedStreams; + UInt64 numTotalBlocks; + + UInt32 crc; + CMixCoder decoder; + CXzBlock block; + CXzCheck check; + CSha256 sha; + + BoolInt parseMode; + BoolInt headerParsedOk; + BoolInt decodeToStreamSignature; + unsigned decodeOnlyOneBlock; + + Byte *outBuf; + size_t outBufSize; + size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked + + Byte shaDigest[SHA256_DIGEST_SIZE]; + Byte buf[XZ_BLOCK_HEADER_SIZE_MAX]; +} CXzUnpacker; + +/* alloc : aligned for cache line allocation is better */ +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc); +void XzUnpacker_Init(CXzUnpacker *p); +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize); +void XzUnpacker_Free(CXzUnpacker *p); + +/* + XzUnpacker + The sequence for decoding functions: + { + XzUnpacker_Construct() + [Decoding_Calls] + XzUnpacker_Free() + } + + [Decoding_Calls] + + There are 3 types of interfaces for [Decoding_Calls] calls: + + Interface-1 : Partial output buffers: + { + XzUnpacker_Init() + for() + { + XzUnpacker_Code(); + } + XzUnpacker_IsStreamWasFinished() + } + + Interface-2 : Direct output buffer: + Use it, if you know exact size of decoded data, and you need + whole xz unpacked data in one output buffer. + xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode. + { + XzUnpacker_Init() + XzUnpacker_SetOutBufMode(); // to set output buffer and size + for() + { + XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code() + } + XzUnpacker_IsStreamWasFinished() + } + + Interface-3 : Direct output buffer : One call full decoding + It unpacks whole input buffer to output buffer in one call. + It uses Interface-2 internally. + { + XzUnpacker_CodeFull() + XzUnpacker_IsStreamWasFinished() + } +*/ + +/* +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + CODER_FINISH_ANY - use smallest number of input bytes + CODER_FINISH_END - read EndOfStream marker after decoding + +Returns: + SZ_OK + status: + CODER_STATUS_NOT_FINISHED, + CODER_STATUS_NEEDS_MORE_INPUT - the decoder can return it in two cases: + 1) it needs more input data to finish current xz stream + 2) xz stream was finished successfully. But the decoder supports multiple + concatented xz streams. So it expects more input data for new xz streams. + Call XzUnpacker_IsStreamWasFinished() to check that latest xz stream was finished successfully. + + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_DATA - Data error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - CRC error + // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons: + - xz Stream Signature failure + - CRC32 of xz Stream Header is failed + - The size of Stream padding is not multiple of four bytes. + It's possible to get that error, if xz stream was finished and the stream + contains some another data. In that case you can call XzUnpacker_GetExtraSize() + function to get real size of xz stream. +*/ + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status); + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status); + +/* +If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished() +after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code(). +*/ + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p); + +/* +XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes, + if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state. +These bytes can be some data after xz archive, or +it can be start of new xz stream. + +Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of +xz stream in two cases, if XzUnpacker_Code() returns: + res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT + res == SZ_ERROR_NO_ARCHIVE +*/ + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p); + + +/* + for random block decoding: + XzUnpacker_Init(); + set CXzUnpacker::streamFlags + XzUnpacker_PrepareToRandomBlockDecoding() + loop + { + XzUnpacker_Code() + XzUnpacker_IsBlockFinished() + } +*/ + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p); +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p); + +#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags)) + + + + + + +/* ---- Single-Thread and Multi-Thread xz Decoding with Input/Output Streams ---- */ + +/* + if (CXzDecMtProps::numThreads > 1), the decoder can try to use + Multi-Threading. The decoder analyses xz block header, and if + there are pack size and unpack size values stored in xz block header, + the decoder reads compressed data of block to internal buffers, + and then it can start parallel decoding, if there are another blocks. + The decoder can switch back to Single-Thread decoding after some conditions. + + The sequence of calls for xz decoding with in/out Streams: + { + XzDecMt_Create() + XzDecMtProps_Init(XzDecMtProps) to set default values of properties + // then you can change some XzDecMtProps parameters with required values + // here you can set the number of threads and (memUseMax) - the maximum + Memory usage for multithreading decoding. + for() + { + XzDecMt_Decode() // one call per one file + } + XzDecMt_Destroy() + } +*/ + + +typedef struct +{ + size_t inBufSize_ST; // size of input buffer for Single-Thread decoding + size_t outStep_ST; // size of output buffer for Single-Thread decoding + BoolInt ignoreErrors; // if set to 1, the decoder can ignore some errors and it skips broken parts of data. + + #ifndef Z7_ST + unsigned numThreads; // the number of threads for Multi-Thread decoding. if (umThreads == 1) it will use Single-thread decoding + size_t inBufSize_MT; // size of small input data buffers for Multi-Thread decoding. Big number of such small buffers can be created + size_t memUseMax; // the limit of total memory usage for Multi-Thread decoding. + // it's recommended to set (memUseMax) manually to value that is smaller of total size of RAM in computer. + #endif +} CXzDecMtProps; + +void XzDecMtProps_Init(CXzDecMtProps *p); + +typedef struct CXzDecMt CXzDecMt; +typedef CXzDecMt * CXzDecMtHandle; +// Z7_DECLARE_HANDLE(CXzDecMtHandle) + +/* + alloc : XzDecMt uses CAlignOffsetAlloc internally for addresses allocated by (alloc). + allocMid : for big allocations, aligned allocation is better +*/ + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid); +void XzDecMt_Destroy(CXzDecMtHandle p); + + +typedef struct +{ + Byte UnpackSize_Defined; + Byte NumStreams_Defined; + Byte NumBlocks_Defined; + + Byte DataAfterEnd; // there are some additional data after good xz streams, and that data is not new xz stream. + Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data + + UInt64 InSize; // pack size processed. That value doesn't include the data after + // end of xz stream, if that data was not correct + UInt64 OutSize; + + UInt64 NumStreams; + UInt64 NumBlocks; + + SRes DecodeRes; // the error code of xz streams data decoding + SRes ReadRes; // error code from ISeqInStream:Read() + SRes ProgressRes; // error code from ICompressProgress:Progress() + + SRes CombinedRes; // Combined result error code that shows main rusult + // = S_OK, if there is no error. + // but check also (DataAfterEnd) that can show additional minor errors. + + SRes CombinedRes_Type; // = SZ_ERROR_READ, if error from ISeqInStream + // = SZ_ERROR_PROGRESS, if error from ICompressProgress + // = SZ_ERROR_WRITE, if error from ISeqOutStream + // = SZ_ERROR_* codes for decoding +} CXzStatInfo; + +void XzStatInfo_Clear(CXzStatInfo *p); + +/* + +XzDecMt_Decode() +SRes: it's combined decoding result. It also is equal to stat->CombinedRes. + + SZ_OK - no error + check also output value in (stat->DataAfterEnd) + that can show additional possible error + + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_NO_ARCHIVE - is not xz archive + SZ_ERROR_ARCHIVE - Headers error + SZ_ERROR_DATA - Data Error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - CRC Error + SZ_ERROR_INPUT_EOF - it needs more input data + SZ_ERROR_WRITE - ISeqOutStream error + (SZ_ERROR_READ) - ISeqInStream errors + (SZ_ERROR_PROGRESS) - ICompressProgress errors + // SZ_ERROR_THREAD - error in multi-threading functions + MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function +*/ + +SRes XzDecMt_Decode(CXzDecMtHandle p, + const CXzDecMtProps *props, + const UInt64 *outDataSize, // NULL means undefined + int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished + ISeqOutStreamPtr outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, // out: decoding results and statistics + int *isMT, // out: 0 means that ST (Single-Thread) version was used + // 1 means that MT (Multi-Thread) version was used + ICompressProgressPtr progress); + +EXTERN_C_END + +#endif diff --git a/C/XzCrc64.c b/C/XzCrc64.c index a0023a6fa..94fc1afb3 100644 --- a/C/XzCrc64.c +++ b/C/XzCrc64.c @@ -1,140 +1,140 @@ -/* XzCrc64.c -- CRC64 calculation -2023-12-08 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "XzCrc64.h" -#include "CpuArch.h" - -#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) - -// for debug only : define Z7_CRC64_DEBUG_BE to test big-endian code in little-endian cpu -// #define Z7_CRC64_DEBUG_BE -#ifdef Z7_CRC64_DEBUG_BE -#undef MY_CPU_LE -#define MY_CPU_BE -#endif - -#ifdef Z7_CRC64_NUM_TABLES - #define Z7_CRC64_NUM_TABLES_USE Z7_CRC64_NUM_TABLES -#else - #define Z7_CRC64_NUM_TABLES_USE 12 -#endif - -#if Z7_CRC64_NUM_TABLES_USE < 1 - #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES -#endif - - -#if Z7_CRC64_NUM_TABLES_USE != 1 - -#ifndef MY_CPU_BE - #define FUNC_NAME_LE_2(s) XzCrc64UpdateT ## s - #define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s) - #define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC64_NUM_TABLES_USE) - UInt64 Z7_FASTCALL FUNC_NAME_LE (UInt64 v, const void *data, size_t size, const UInt64 *table); -#endif -#ifndef MY_CPU_LE - #define FUNC_NAME_BE_2(s) XzCrc64UpdateBeT ## s - #define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s) - #define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC64_NUM_TABLES_USE) - UInt64 Z7_FASTCALL FUNC_NAME_BE (UInt64 v, const void *data, size_t size, const UInt64 *table); -#endif - -#if defined(MY_CPU_LE) - #define FUNC_REF FUNC_NAME_LE -#elif defined(MY_CPU_BE) - #define FUNC_REF FUNC_NAME_BE -#else - #define FUNC_REF g_Crc64Update - static UInt64 (Z7_FASTCALL *FUNC_REF)(UInt64 v, const void *data, size_t size, const UInt64 *table); -#endif - -#endif - - -MY_ALIGN(64) -static UInt64 g_Crc64Table[256 * Z7_CRC64_NUM_TABLES_USE]; - - -UInt64 Z7_FASTCALL Crc64Update(UInt64 v, const void *data, size_t size) -{ -#if Z7_CRC64_NUM_TABLES_USE == 1 - #define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - const UInt64 *table = g_Crc64Table; - const Byte *p = (const Byte *)data; - const Byte *lim = p + size; - for (; p != lim; p++) - v = CRC64_UPDATE_BYTE_2(v, *p); - return v; - #undef CRC64_UPDATE_BYTE_2 -#else - return FUNC_REF (v, data, size, g_Crc64Table); -#endif -} - - -Z7_NO_INLINE -void Z7_FASTCALL Crc64GenerateTable(void) -{ - unsigned i; - for (i = 0; i < 256; i++) - { - UInt64 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1))); - g_Crc64Table[i] = r; - } - -#if Z7_CRC64_NUM_TABLES_USE != 1 -#if 1 || 1 && defined(MY_CPU_X86) // low register count - for (i = 0; i < 256 * (Z7_CRC64_NUM_TABLES_USE - 1); i++) - { - const UInt64 r0 = g_Crc64Table[(size_t)i]; - g_Crc64Table[(size_t)i + 256] = g_Crc64Table[(Byte)r0] ^ (r0 >> 8); - } -#else - for (i = 0; i < 256 * (Z7_CRC64_NUM_TABLES_USE - 1); i += 2) - { - UInt64 r0 = g_Crc64Table[(size_t)(i) ]; - UInt64 r1 = g_Crc64Table[(size_t)(i) + 1]; - r0 = g_Crc64Table[(Byte)r0] ^ (r0 >> 8); - r1 = g_Crc64Table[(Byte)r1] ^ (r1 >> 8); - g_Crc64Table[(size_t)i + 256 ] = r0; - g_Crc64Table[(size_t)i + 256 + 1] = r1; - } -#endif - -#ifndef MY_CPU_LE - { -#ifndef MY_CPU_BE - UInt32 k = 1; - if (*(const Byte *)&k == 1) - FUNC_REF = FUNC_NAME_LE; - else -#endif - { -#ifndef MY_CPU_BE - FUNC_REF = FUNC_NAME_BE; -#endif - for (i = 0; i < 256 * Z7_CRC64_NUM_TABLES_USE; i++) - { - const UInt64 x = g_Crc64Table[i]; - g_Crc64Table[i] = Z7_BSWAP64(x); - } - } - } -#endif // ndef MY_CPU_LE -#endif // Z7_CRC64_NUM_TABLES_USE != 1 -} - -#undef kCrc64Poly -#undef Z7_CRC64_NUM_TABLES_USE -#undef FUNC_REF -#undef FUNC_NAME_LE_2 -#undef FUNC_NAME_LE_1 -#undef FUNC_NAME_LE -#undef FUNC_NAME_BE_2 -#undef FUNC_NAME_BE_1 -#undef FUNC_NAME_BE +/* XzCrc64.c -- CRC64 calculation +2023-12-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "XzCrc64.h" +#include "CpuArch.h" + +#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42) + +// for debug only : define Z7_CRC64_DEBUG_BE to test big-endian code in little-endian cpu +// #define Z7_CRC64_DEBUG_BE +#ifdef Z7_CRC64_DEBUG_BE +#undef MY_CPU_LE +#define MY_CPU_BE +#endif + +#ifdef Z7_CRC64_NUM_TABLES + #define Z7_CRC64_NUM_TABLES_USE Z7_CRC64_NUM_TABLES +#else + #define Z7_CRC64_NUM_TABLES_USE 12 +#endif + +#if Z7_CRC64_NUM_TABLES_USE < 1 + #error Stop_Compiling_Bad_Z7_CRC_NUM_TABLES +#endif + + +#if Z7_CRC64_NUM_TABLES_USE != 1 + +#ifndef MY_CPU_BE + #define FUNC_NAME_LE_2(s) XzCrc64UpdateT ## s + #define FUNC_NAME_LE_1(s) FUNC_NAME_LE_2(s) + #define FUNC_NAME_LE FUNC_NAME_LE_1(Z7_CRC64_NUM_TABLES_USE) + UInt64 Z7_FASTCALL FUNC_NAME_LE (UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif +#ifndef MY_CPU_LE + #define FUNC_NAME_BE_2(s) XzCrc64UpdateBeT ## s + #define FUNC_NAME_BE_1(s) FUNC_NAME_BE_2(s) + #define FUNC_NAME_BE FUNC_NAME_BE_1(Z7_CRC64_NUM_TABLES_USE) + UInt64 Z7_FASTCALL FUNC_NAME_BE (UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +#if defined(MY_CPU_LE) + #define FUNC_REF FUNC_NAME_LE +#elif defined(MY_CPU_BE) + #define FUNC_REF FUNC_NAME_BE +#else + #define FUNC_REF g_Crc64Update + static UInt64 (Z7_FASTCALL *FUNC_REF)(UInt64 v, const void *data, size_t size, const UInt64 *table); +#endif + +#endif + + +MY_ALIGN(64) +static UInt64 g_Crc64Table[256 * Z7_CRC64_NUM_TABLES_USE]; + + +UInt64 Z7_FASTCALL Crc64Update(UInt64 v, const void *data, size_t size) +{ +#if Z7_CRC64_NUM_TABLES_USE == 1 + #define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + const UInt64 *table = g_Crc64Table; + const Byte *p = (const Byte *)data; + const Byte *lim = p + size; + for (; p != lim; p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + return v; + #undef CRC64_UPDATE_BYTE_2 +#else + return FUNC_REF (v, data, size, g_Crc64Table); +#endif +} + + +Z7_NO_INLINE +void Z7_FASTCALL Crc64GenerateTable(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + { + UInt64 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1))); + g_Crc64Table[i] = r; + } + +#if Z7_CRC64_NUM_TABLES_USE != 1 +#if 1 || 1 && defined(MY_CPU_X86) // low register count + for (i = 0; i < 256 * (Z7_CRC64_NUM_TABLES_USE - 1); i++) + { + const UInt64 r0 = g_Crc64Table[(size_t)i]; + g_Crc64Table[(size_t)i + 256] = g_Crc64Table[(Byte)r0] ^ (r0 >> 8); + } +#else + for (i = 0; i < 256 * (Z7_CRC64_NUM_TABLES_USE - 1); i += 2) + { + UInt64 r0 = g_Crc64Table[(size_t)(i) ]; + UInt64 r1 = g_Crc64Table[(size_t)(i) + 1]; + r0 = g_Crc64Table[(Byte)r0] ^ (r0 >> 8); + r1 = g_Crc64Table[(Byte)r1] ^ (r1 >> 8); + g_Crc64Table[(size_t)i + 256 ] = r0; + g_Crc64Table[(size_t)i + 256 + 1] = r1; + } +#endif + +#ifndef MY_CPU_LE + { +#ifndef MY_CPU_BE + UInt32 k = 1; + if (*(const Byte *)&k == 1) + FUNC_REF = FUNC_NAME_LE; + else +#endif + { +#ifndef MY_CPU_BE + FUNC_REF = FUNC_NAME_BE; +#endif + for (i = 0; i < 256 * Z7_CRC64_NUM_TABLES_USE; i++) + { + const UInt64 x = g_Crc64Table[i]; + g_Crc64Table[i] = Z7_BSWAP64(x); + } + } + } +#endif // ndef MY_CPU_LE +#endif // Z7_CRC64_NUM_TABLES_USE != 1 +} + +#undef kCrc64Poly +#undef Z7_CRC64_NUM_TABLES_USE +#undef FUNC_REF +#undef FUNC_NAME_LE_2 +#undef FUNC_NAME_LE_1 +#undef FUNC_NAME_LE +#undef FUNC_NAME_BE_2 +#undef FUNC_NAME_BE_1 +#undef FUNC_NAME_BE diff --git a/C/XzCrc64.h b/C/XzCrc64.h index 4d9e9f825..04f8153df 100644 --- a/C/XzCrc64.h +++ b/C/XzCrc64.h @@ -1,26 +1,26 @@ -/* XzCrc64.h -- CRC64 calculation -2023-12-08 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_XZ_CRC64_H -#define ZIP7_INC_XZ_CRC64_H - -#include - -#include "7zTypes.h" - -EXTERN_C_BEGIN - -// extern UInt64 g_Crc64Table[]; - -void Z7_FASTCALL Crc64GenerateTable(void); - -#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) -#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) -// #define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -UInt64 Z7_FASTCALL Crc64Update(UInt64 crc, const void *data, size_t size); -// UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size); - -EXTERN_C_END - -#endif +/* XzCrc64.h -- CRC64 calculation +2023-12-08 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XZ_CRC64_H +#define ZIP7_INC_XZ_CRC64_H + +#include + +#include "7zTypes.h" + +EXTERN_C_BEGIN + +// extern UInt64 g_Crc64Table[]; + +void Z7_FASTCALL Crc64GenerateTable(void); + +#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF) +#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL) +// #define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt64 Z7_FASTCALL Crc64Update(UInt64 crc, const void *data, size_t size); +// UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size); + +EXTERN_C_END + +#endif diff --git a/C/XzCrc64Opt.c b/C/XzCrc64Opt.c index c855dd594..0c1fc2ffe 100644 --- a/C/XzCrc64Opt.c +++ b/C/XzCrc64Opt.c @@ -1,261 +1,261 @@ -/* XzCrc64Opt.c -- CRC64 calculation (optimized functions) -2023-12-08 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include "CpuArch.h" - -#if !defined(Z7_CRC64_NUM_TABLES) || Z7_CRC64_NUM_TABLES > 1 - -// for debug only : define Z7_CRC64_DEBUG_BE to test big-endian code in little-endian cpu -// #define Z7_CRC64_DEBUG_BE -#ifdef Z7_CRC64_DEBUG_BE -#undef MY_CPU_LE -#define MY_CPU_BE -#endif - -#if defined(MY_CPU_64BIT) -#define Z7_CRC64_USE_64BIT -#endif - -// the value Z7_CRC64_NUM_TABLES_USE must be defined to same value as in XzCrc64.c -#ifdef Z7_CRC64_NUM_TABLES -#define Z7_CRC64_NUM_TABLES_USE Z7_CRC64_NUM_TABLES -#else -#define Z7_CRC64_NUM_TABLES_USE 12 -#endif - -#if Z7_CRC64_NUM_TABLES_USE % 4 || \ - Z7_CRC64_NUM_TABLES_USE < 4 || \ - Z7_CRC64_NUM_TABLES_USE > 4 * 4 - #error Stop_Compiling_Bad_CRC64_NUM_TABLES -#endif - - -#ifndef MY_CPU_BE - -#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -#if defined(Z7_CRC64_USE_64BIT) && (Z7_CRC64_NUM_TABLES_USE % 8 == 0) - -#define Q64LE(n, d) \ - ( (table + ((n) * 8 + 7) * 0x100)[((d) ) & 0xFF] \ - ^ (table + ((n) * 8 + 6) * 0x100)[((d) >> 1 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 5) * 0x100)[((d) >> 2 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 4) * 0x100)[((d) >> 3 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 3) * 0x100)[((d) >> 4 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 2) * 0x100)[((d) >> 5 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 1) * 0x100)[((d) >> 6 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 0) * 0x100)[((d) >> 7 * 8)] ) - -#define R64(a) *((const UInt64 *)(const void *)p + (a)) - -#else - -#define Q32LE(n, d) \ - ( (table + ((n) * 4 + 3) * 0x100)[((d) ) & 0xFF] \ - ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] ) - -#define R32(a) *((const UInt32 *)(const void *)p + (a)) - -#endif - - -#define CRC64_FUNC_PRE_LE2(step) \ -UInt64 Z7_FASTCALL XzCrc64UpdateT ## step (UInt64 v, const void *data, size_t size, const UInt64 *table) - -#define CRC64_FUNC_PRE_LE(step) \ - CRC64_FUNC_PRE_LE2(step); \ - CRC64_FUNC_PRE_LE2(step) - -CRC64_FUNC_PRE_LE(Z7_CRC64_NUM_TABLES_USE) -{ - const Byte *p = (const Byte *)data; - const Byte *lim; - for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC64_NUM_TABLES_USE & 4))) != 0; size--, p++) - v = CRC64_UPDATE_BYTE_2(v, *p); - lim = p + size; - if (size >= Z7_CRC64_NUM_TABLES_USE) - { - lim -= Z7_CRC64_NUM_TABLES_USE; - do - { -#if Z7_CRC64_NUM_TABLES_USE == 4 - const UInt32 d = (UInt32)v ^ R32(0); - v = (v >> 32) ^ Q32LE(0, d); -#elif Z7_CRC64_NUM_TABLES_USE == 8 -#ifdef Z7_CRC64_USE_64BIT - v ^= R64(0); - v = Q64LE(0, v); -#else - UInt32 v0, v1; - v0 = (UInt32)v ^ R32(0); - v1 = (UInt32)(v >> 32) ^ R32(1); - v = Q32LE(1, v0) ^ Q32LE(0, v1); -#endif -#elif Z7_CRC64_NUM_TABLES_USE == 12 - UInt32 w; - UInt32 v0, v1; - v0 = (UInt32)v ^ R32(0); - v1 = (UInt32)(v >> 32) ^ R32(1); - w = R32(2); - v = Q32LE(0, w); - v ^= Q32LE(2, v0) ^ Q32LE(1, v1); -#elif Z7_CRC64_NUM_TABLES_USE == 16 -#ifdef Z7_CRC64_USE_64BIT - UInt64 w; - UInt64 x; - w = R64(1); x = Q64LE(0, w); - v ^= R64(0); v = x ^ Q64LE(1, v); -#else - UInt32 v0, v1; - UInt32 r0, r1; - v0 = (UInt32)v ^ R32(0); - v1 = (UInt32)(v >> 32) ^ R32(1); - r0 = R32(2); - r1 = R32(3); - v = Q32LE(1, r0) ^ Q32LE(0, r1); - v ^= Q32LE(3, v0) ^ Q32LE(2, v1); -#endif -#else -#error Stop_Compiling_Bad_CRC64_NUM_TABLES -#endif - p += Z7_CRC64_NUM_TABLES_USE; - } - while (p <= lim); - lim += Z7_CRC64_NUM_TABLES_USE; - } - for (; p < lim; p++) - v = CRC64_UPDATE_BYTE_2(v, *p); - return v; -} - -#undef CRC64_UPDATE_BYTE_2 -#undef R32 -#undef R64 -#undef Q32LE -#undef Q64LE -#undef CRC64_FUNC_PRE_LE -#undef CRC64_FUNC_PRE_LE2 - -#endif - - - - -#ifndef MY_CPU_LE - -#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[((crc) >> 56) ^ (b)] ^ ((crc) << 8)) - -#if defined(Z7_CRC64_USE_64BIT) && (Z7_CRC64_NUM_TABLES_USE % 8 == 0) - -#define Q64BE(n, d) \ - ( (table + ((n) * 8 + 0) * 0x100)[(Byte)(d)] \ - ^ (table + ((n) * 8 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 3) * 0x100)[((d) >> 3 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 4) * 0x100)[((d) >> 4 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 5) * 0x100)[((d) >> 5 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 6) * 0x100)[((d) >> 6 * 8) & 0xFF] \ - ^ (table + ((n) * 8 + 7) * 0x100)[((d) >> 7 * 8)] ) - -#ifdef Z7_CRC64_DEBUG_BE - #define R64BE(a) GetBe64a((const UInt64 *)(const void *)p + (a)) -#else - #define R64BE(a) *((const UInt64 *)(const void *)p + (a)) -#endif - -#else - -#define Q32BE(n, d) \ - ( (table + ((n) * 4 + 0) * 0x100)[(Byte)(d)] \ - ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \ - ^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] ) - -#ifdef Z7_CRC64_DEBUG_BE - #define R32BE(a) GetBe32a((const UInt32 *)(const void *)p + (a)) -#else - #define R32BE(a) *((const UInt32 *)(const void *)p + (a)) -#endif - -#endif - -#define CRC64_FUNC_PRE_BE2(step) \ -UInt64 Z7_FASTCALL XzCrc64UpdateBeT ## step (UInt64 v, const void *data, size_t size, const UInt64 *table) - -#define CRC64_FUNC_PRE_BE(step) \ - CRC64_FUNC_PRE_BE2(step); \ - CRC64_FUNC_PRE_BE2(step) - -CRC64_FUNC_PRE_BE(Z7_CRC64_NUM_TABLES_USE) -{ - const Byte *p = (const Byte *)data; - const Byte *lim; - v = Z7_BSWAP64(v); - for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC64_NUM_TABLES_USE & 4))) != 0; size--, p++) - v = CRC64_UPDATE_BYTE_2_BE(v, *p); - lim = p + size; - if (size >= Z7_CRC64_NUM_TABLES_USE) - { - lim -= Z7_CRC64_NUM_TABLES_USE; - do - { -#if Z7_CRC64_NUM_TABLES_USE == 4 - const UInt32 d = (UInt32)(v >> 32) ^ R32BE(0); - v = (v << 32) ^ Q32BE(0, d); -#elif Z7_CRC64_NUM_TABLES_USE == 12 - const UInt32 d1 = (UInt32)(v >> 32) ^ R32BE(0); - const UInt32 d0 = (UInt32)(v ) ^ R32BE(1); - const UInt32 w = R32BE(2); - v = Q32BE(0, w); - v ^= Q32BE(2, d1) ^ Q32BE(1, d0); - -#elif Z7_CRC64_NUM_TABLES_USE == 8 - #ifdef Z7_CRC64_USE_64BIT - v ^= R64BE(0); - v = Q64BE(0, v); - #else - const UInt32 d1 = (UInt32)(v >> 32) ^ R32BE(0); - const UInt32 d0 = (UInt32)(v ) ^ R32BE(1); - v = Q32BE(1, d1) ^ Q32BE(0, d0); - #endif -#elif Z7_CRC64_NUM_TABLES_USE == 16 - #ifdef Z7_CRC64_USE_64BIT - const UInt64 w = R64BE(1); - v ^= R64BE(0); - v = Q64BE(0, w) ^ Q64BE(1, v); - #else - const UInt32 d1 = (UInt32)(v >> 32) ^ R32BE(0); - const UInt32 d0 = (UInt32)(v ) ^ R32BE(1); - const UInt32 w1 = R32BE(2); - const UInt32 w0 = R32BE(3); - v = Q32BE(1, w1) ^ Q32BE(0, w0); - v ^= Q32BE(3, d1) ^ Q32BE(2, d0); - #endif -#elif -#error Stop_Compiling_Bad_CRC64_NUM_TABLES -#endif - p += Z7_CRC64_NUM_TABLES_USE; - } - while (p <= lim); - lim += Z7_CRC64_NUM_TABLES_USE; - } - for (; p < lim; p++) - v = CRC64_UPDATE_BYTE_2_BE(v, *p); - return Z7_BSWAP64(v); -} - -#undef CRC64_UPDATE_BYTE_2_BE -#undef R32BE -#undef R64BE -#undef Q32BE -#undef Q64BE -#undef CRC64_FUNC_PRE_BE -#undef CRC64_FUNC_PRE_BE2 - -#endif -#undef Z7_CRC64_NUM_TABLES_USE -#endif +/* XzCrc64Opt.c -- CRC64 calculation (optimized functions) +2023-12-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include "CpuArch.h" + +#if !defined(Z7_CRC64_NUM_TABLES) || Z7_CRC64_NUM_TABLES > 1 + +// for debug only : define Z7_CRC64_DEBUG_BE to test big-endian code in little-endian cpu +// #define Z7_CRC64_DEBUG_BE +#ifdef Z7_CRC64_DEBUG_BE +#undef MY_CPU_LE +#define MY_CPU_BE +#endif + +#if defined(MY_CPU_64BIT) +#define Z7_CRC64_USE_64BIT +#endif + +// the value Z7_CRC64_NUM_TABLES_USE must be defined to same value as in XzCrc64.c +#ifdef Z7_CRC64_NUM_TABLES +#define Z7_CRC64_NUM_TABLES_USE Z7_CRC64_NUM_TABLES +#else +#define Z7_CRC64_NUM_TABLES_USE 12 +#endif + +#if Z7_CRC64_NUM_TABLES_USE % 4 || \ + Z7_CRC64_NUM_TABLES_USE < 4 || \ + Z7_CRC64_NUM_TABLES_USE > 4 * 4 + #error Stop_Compiling_Bad_CRC64_NUM_TABLES +#endif + + +#ifndef MY_CPU_BE + +#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +#if defined(Z7_CRC64_USE_64BIT) && (Z7_CRC64_NUM_TABLES_USE % 8 == 0) + +#define Q64LE(n, d) \ + ( (table + ((n) * 8 + 7) * 0x100)[((d) ) & 0xFF] \ + ^ (table + ((n) * 8 + 6) * 0x100)[((d) >> 1 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 5) * 0x100)[((d) >> 2 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 4) * 0x100)[((d) >> 3 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 3) * 0x100)[((d) >> 4 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 2) * 0x100)[((d) >> 5 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 1) * 0x100)[((d) >> 6 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 0) * 0x100)[((d) >> 7 * 8)] ) + +#define R64(a) *((const UInt64 *)(const void *)p + (a)) + +#else + +#define Q32LE(n, d) \ + ( (table + ((n) * 4 + 3) * 0x100)[((d) ) & 0xFF] \ + ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 1 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 2 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 0) * 0x100)[((d) >> 3 * 8)] ) + +#define R32(a) *((const UInt32 *)(const void *)p + (a)) + +#endif + + +#define CRC64_FUNC_PRE_LE2(step) \ +UInt64 Z7_FASTCALL XzCrc64UpdateT ## step (UInt64 v, const void *data, size_t size, const UInt64 *table) + +#define CRC64_FUNC_PRE_LE(step) \ + CRC64_FUNC_PRE_LE2(step); \ + CRC64_FUNC_PRE_LE2(step) + +CRC64_FUNC_PRE_LE(Z7_CRC64_NUM_TABLES_USE) +{ + const Byte *p = (const Byte *)data; + const Byte *lim; + for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC64_NUM_TABLES_USE & 4))) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + lim = p + size; + if (size >= Z7_CRC64_NUM_TABLES_USE) + { + lim -= Z7_CRC64_NUM_TABLES_USE; + do + { +#if Z7_CRC64_NUM_TABLES_USE == 4 + const UInt32 d = (UInt32)v ^ R32(0); + v = (v >> 32) ^ Q32LE(0, d); +#elif Z7_CRC64_NUM_TABLES_USE == 8 +#ifdef Z7_CRC64_USE_64BIT + v ^= R64(0); + v = Q64LE(0, v); +#else + UInt32 v0, v1; + v0 = (UInt32)v ^ R32(0); + v1 = (UInt32)(v >> 32) ^ R32(1); + v = Q32LE(1, v0) ^ Q32LE(0, v1); +#endif +#elif Z7_CRC64_NUM_TABLES_USE == 12 + UInt32 w; + UInt32 v0, v1; + v0 = (UInt32)v ^ R32(0); + v1 = (UInt32)(v >> 32) ^ R32(1); + w = R32(2); + v = Q32LE(0, w); + v ^= Q32LE(2, v0) ^ Q32LE(1, v1); +#elif Z7_CRC64_NUM_TABLES_USE == 16 +#ifdef Z7_CRC64_USE_64BIT + UInt64 w; + UInt64 x; + w = R64(1); x = Q64LE(0, w); + v ^= R64(0); v = x ^ Q64LE(1, v); +#else + UInt32 v0, v1; + UInt32 r0, r1; + v0 = (UInt32)v ^ R32(0); + v1 = (UInt32)(v >> 32) ^ R32(1); + r0 = R32(2); + r1 = R32(3); + v = Q32LE(1, r0) ^ Q32LE(0, r1); + v ^= Q32LE(3, v0) ^ Q32LE(2, v1); +#endif +#else +#error Stop_Compiling_Bad_CRC64_NUM_TABLES +#endif + p += Z7_CRC64_NUM_TABLES_USE; + } + while (p <= lim); + lim += Z7_CRC64_NUM_TABLES_USE; + } + for (; p < lim; p++) + v = CRC64_UPDATE_BYTE_2(v, *p); + return v; +} + +#undef CRC64_UPDATE_BYTE_2 +#undef R32 +#undef R64 +#undef Q32LE +#undef Q64LE +#undef CRC64_FUNC_PRE_LE +#undef CRC64_FUNC_PRE_LE2 + +#endif + + + + +#ifndef MY_CPU_LE + +#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[((crc) >> 56) ^ (b)] ^ ((crc) << 8)) + +#if defined(Z7_CRC64_USE_64BIT) && (Z7_CRC64_NUM_TABLES_USE % 8 == 0) + +#define Q64BE(n, d) \ + ( (table + ((n) * 8 + 0) * 0x100)[(Byte)(d)] \ + ^ (table + ((n) * 8 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 3) * 0x100)[((d) >> 3 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 4) * 0x100)[((d) >> 4 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 5) * 0x100)[((d) >> 5 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 6) * 0x100)[((d) >> 6 * 8) & 0xFF] \ + ^ (table + ((n) * 8 + 7) * 0x100)[((d) >> 7 * 8)] ) + +#ifdef Z7_CRC64_DEBUG_BE + #define R64BE(a) GetBe64a((const UInt64 *)(const void *)p + (a)) +#else + #define R64BE(a) *((const UInt64 *)(const void *)p + (a)) +#endif + +#else + +#define Q32BE(n, d) \ + ( (table + ((n) * 4 + 0) * 0x100)[(Byte)(d)] \ + ^ (table + ((n) * 4 + 1) * 0x100)[((d) >> 1 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 2) * 0x100)[((d) >> 2 * 8) & 0xFF] \ + ^ (table + ((n) * 4 + 3) * 0x100)[((d) >> 3 * 8)] ) + +#ifdef Z7_CRC64_DEBUG_BE + #define R32BE(a) GetBe32a((const UInt32 *)(const void *)p + (a)) +#else + #define R32BE(a) *((const UInt32 *)(const void *)p + (a)) +#endif + +#endif + +#define CRC64_FUNC_PRE_BE2(step) \ +UInt64 Z7_FASTCALL XzCrc64UpdateBeT ## step (UInt64 v, const void *data, size_t size, const UInt64 *table) + +#define CRC64_FUNC_PRE_BE(step) \ + CRC64_FUNC_PRE_BE2(step); \ + CRC64_FUNC_PRE_BE2(step) + +CRC64_FUNC_PRE_BE(Z7_CRC64_NUM_TABLES_USE) +{ + const Byte *p = (const Byte *)data; + const Byte *lim; + v = Z7_BSWAP64(v); + for (; size && ((unsigned)(ptrdiff_t)p & (7 - (Z7_CRC64_NUM_TABLES_USE & 4))) != 0; size--, p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + lim = p + size; + if (size >= Z7_CRC64_NUM_TABLES_USE) + { + lim -= Z7_CRC64_NUM_TABLES_USE; + do + { +#if Z7_CRC64_NUM_TABLES_USE == 4 + const UInt32 d = (UInt32)(v >> 32) ^ R32BE(0); + v = (v << 32) ^ Q32BE(0, d); +#elif Z7_CRC64_NUM_TABLES_USE == 12 + const UInt32 d1 = (UInt32)(v >> 32) ^ R32BE(0); + const UInt32 d0 = (UInt32)(v ) ^ R32BE(1); + const UInt32 w = R32BE(2); + v = Q32BE(0, w); + v ^= Q32BE(2, d1) ^ Q32BE(1, d0); + +#elif Z7_CRC64_NUM_TABLES_USE == 8 + #ifdef Z7_CRC64_USE_64BIT + v ^= R64BE(0); + v = Q64BE(0, v); + #else + const UInt32 d1 = (UInt32)(v >> 32) ^ R32BE(0); + const UInt32 d0 = (UInt32)(v ) ^ R32BE(1); + v = Q32BE(1, d1) ^ Q32BE(0, d0); + #endif +#elif Z7_CRC64_NUM_TABLES_USE == 16 + #ifdef Z7_CRC64_USE_64BIT + const UInt64 w = R64BE(1); + v ^= R64BE(0); + v = Q64BE(0, w) ^ Q64BE(1, v); + #else + const UInt32 d1 = (UInt32)(v >> 32) ^ R32BE(0); + const UInt32 d0 = (UInt32)(v ) ^ R32BE(1); + const UInt32 w1 = R32BE(2); + const UInt32 w0 = R32BE(3); + v = Q32BE(1, w1) ^ Q32BE(0, w0); + v ^= Q32BE(3, d1) ^ Q32BE(2, d0); + #endif +#elif +#error Stop_Compiling_Bad_CRC64_NUM_TABLES +#endif + p += Z7_CRC64_NUM_TABLES_USE; + } + while (p <= lim); + lim += Z7_CRC64_NUM_TABLES_USE; + } + for (; p < lim; p++) + v = CRC64_UPDATE_BYTE_2_BE(v, *p); + return Z7_BSWAP64(v); +} + +#undef CRC64_UPDATE_BYTE_2_BE +#undef R32BE +#undef R64BE +#undef Q32BE +#undef Q64BE +#undef CRC64_FUNC_PRE_BE +#undef CRC64_FUNC_PRE_BE2 + +#endif +#undef Z7_CRC64_NUM_TABLES_USE +#endif diff --git a/C/XzDec.c b/C/XzDec.c index f4160eaaa..3d1c98e63 100644 --- a/C/XzDec.c +++ b/C/XzDec.c @@ -1,2877 +1,2877 @@ -/* XzDec.c -- Xz Decode -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -// #include - -// #define XZ_DUMP - -/* #define XZ_DUMP */ - -#ifdef XZ_DUMP -#include -#endif - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -#define PRF_STR(s) PRF(printf("\n" s "\n")) -#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) - -#include -#include - -#include "7zCrc.h" -#include "Alloc.h" -#include "Bra.h" -#include "CpuArch.h" -#include "Delta.h" -#include "Lzma2Dec.h" - -// #define USE_SUBBLOCK - -#ifdef USE_SUBBLOCK -#include "Bcj3Dec.c" -#include "SbDec.h" -#endif - -#include "Xz.h" - -#define XZ_CHECK_SIZE_MAX 64 - -#define CODER_BUF_SIZE ((size_t)1 << 17) - -unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) -{ - unsigned i, limit; - *value = 0; - limit = (maxSize > 9) ? 9 : (unsigned)maxSize; - - for (i = 0; i < limit;) - { - Byte b = p[i]; - *value |= (UInt64)(b & 0x7F) << (7 * i++); - if ((b & 0x80) == 0) - return (b == 0 && i != 1) ? 0 : i; - } - return 0; -} - - -/* ---------- XzBcFilterState ---------- */ - -#define BRA_BUF_SIZE (1 << 14) - -typedef struct -{ - size_t bufPos; - size_t bufConv; - size_t bufTotal; - Byte *buf; // must be aligned for 4 bytes - Xz_Func_BcFilterStateBase_Filter filter_func; - // int encodeMode; - CXzBcFilterStateBase base; - // Byte buf[BRA_BUF_SIZE]; -} CXzBcFilterState; - - -static void XzBcFilterState_Free(void *pp, ISzAllocPtr alloc) -{ - if (pp) - { - CXzBcFilterState *p = ((CXzBcFilterState *)pp); - ISzAlloc_Free(alloc, p->buf); - ISzAlloc_Free(alloc, pp); - } -} - - -static SRes XzBcFilterState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) -{ - CXzBcFilterStateBase *p = &((CXzBcFilterState *)pp)->base; - UNUSED_VAR(alloc) - p->ip = 0; - if (p->methodId == XZ_ID_Delta) - { - if (propSize != 1) - return SZ_ERROR_UNSUPPORTED; - p->delta = (UInt32)props[0] + 1; - } - else - { - if (propSize == 4) - { - const UInt32 v = GetUi32(props); - switch (p->methodId) - { - case XZ_ID_PPC: - case XZ_ID_ARM: - case XZ_ID_SPARC: - case XZ_ID_ARM64: - if (v & 3) - return SZ_ERROR_UNSUPPORTED; - break; - case XZ_ID_ARMT: - case XZ_ID_RISCV: - if (v & 1) - return SZ_ERROR_UNSUPPORTED; - break; - case XZ_ID_IA64: - if (v & 0xf) - return SZ_ERROR_UNSUPPORTED; - break; - default: break; - } - p->ip = v; - } - else if (propSize != 0) - return SZ_ERROR_UNSUPPORTED; - } - return SZ_OK; -} - - -static void XzBcFilterState_Init(void *pp) -{ - CXzBcFilterState *p = ((CXzBcFilterState *)pp); - p->bufPos = p->bufConv = p->bufTotal = 0; - p->base.X86_State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; - if (p->base.methodId == XZ_ID_Delta) - Delta_Init(p->base.delta_State); -} - - -static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Dec[] = -{ - Z7_BRANCH_CONV_DEC_2 (BranchConv_PPC), - Z7_BRANCH_CONV_DEC_2 (BranchConv_IA64), - Z7_BRANCH_CONV_DEC_2 (BranchConv_ARM), - Z7_BRANCH_CONV_DEC_2 (BranchConv_ARMT), - Z7_BRANCH_CONV_DEC_2 (BranchConv_SPARC), - Z7_BRANCH_CONV_DEC_2 (BranchConv_ARM64), - Z7_BRANCH_CONV_DEC_2 (BranchConv_RISCV) -}; - -static SizeT XzBcFilterStateBase_Filter_Dec(CXzBcFilterStateBase *p, Byte *data, SizeT size) -{ - switch (p->methodId) - { - case XZ_ID_Delta: - Delta_Decode(p->delta_State, p->delta, data, size); - break; - case XZ_ID_X86: - size = (SizeT)(z7_BranchConvSt_X86_Dec(data, size, p->ip, &p->X86_State) - data); - break; - default: - if (p->methodId >= XZ_ID_PPC) - { - const UInt32 i = p->methodId - XZ_ID_PPC; - if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Dec)) - size = (SizeT)(g_Funcs_BranchConv_RISC_Dec[i](data, size, p->ip) - data); - } - break; - } - p->ip += (UInt32)size; - return size; -} - - -static SizeT XzBcFilterState_Filter(void *pp, Byte *data, SizeT size) -{ - CXzBcFilterState *p = ((CXzBcFilterState *)pp); - return p->filter_func(&p->base, data, size); -} - - -static SRes XzBcFilterState_Code2(void *pp, - Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, int srcWasFinished, - ECoderFinishMode finishMode, - // int *wasFinished - ECoderStatus *status) -{ - CXzBcFilterState *p = ((CXzBcFilterState *)pp); - SizeT destRem = *destLen; - SizeT srcRem = *srcLen; - UNUSED_VAR(finishMode) - - *destLen = 0; - *srcLen = 0; - // *wasFinished = False; - *status = CODER_STATUS_NOT_FINISHED; - - while (destRem != 0) - { - { - size_t size = p->bufConv - p->bufPos; - if (size) - { - if (size > destRem) - size = destRem; - memcpy(dest, p->buf + p->bufPos, size); - p->bufPos += size; - *destLen += size; - dest += size; - destRem -= size; - continue; - } - } - - p->bufTotal -= p->bufPos; - memmove(p->buf, p->buf + p->bufPos, p->bufTotal); - p->bufPos = 0; - p->bufConv = 0; - { - size_t size = BRA_BUF_SIZE - p->bufTotal; - if (size > srcRem) - size = srcRem; - memcpy(p->buf + p->bufTotal, src, size); - *srcLen += size; - src += size; - srcRem -= size; - p->bufTotal += size; - } - if (p->bufTotal == 0) - break; - - p->bufConv = p->filter_func(&p->base, p->buf, p->bufTotal); - - if (p->bufConv == 0) - { - if (!srcWasFinished) - break; - p->bufConv = p->bufTotal; - } - } - - if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished) - { - *status = CODER_STATUS_FINISHED_WITH_MARK; - // *wasFinished = 1; - } - - return SZ_OK; -} - - -#define XZ_IS_SUPPORTED_FILTER_ID(id) \ - ((id) >= XZ_ID_Delta && (id) <= XZ_ID_RISCV) - -SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id, - Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc) -{ - CXzBcFilterState *decoder; - if (!XZ_IS_SUPPORTED_FILTER_ID(id)) - return SZ_ERROR_UNSUPPORTED; - decoder = (CXzBcFilterState *)p->p; - if (!decoder) - { - decoder = (CXzBcFilterState *)ISzAlloc_Alloc(alloc, sizeof(CXzBcFilterState)); - if (!decoder) - return SZ_ERROR_MEM; - decoder->buf = ISzAlloc_Alloc(alloc, BRA_BUF_SIZE); - if (!decoder->buf) - { - ISzAlloc_Free(alloc, decoder); - return SZ_ERROR_MEM; - } - p->p = decoder; - p->Free = XzBcFilterState_Free; - p->SetProps = XzBcFilterState_SetProps; - p->Init = XzBcFilterState_Init; - p->Code2 = XzBcFilterState_Code2; - p->Filter = XzBcFilterState_Filter; - decoder->filter_func = func; - } - decoder->base.methodId = (UInt32)id; - // decoder->encodeMode = encodeMode; - return SZ_OK; -} - - - -/* ---------- SbState ---------- */ - -#ifdef USE_SUBBLOCK - -static void SbState_Free(void *pp, ISzAllocPtr alloc) -{ - CSbDec *p = (CSbDec *)pp; - SbDec_Free(p); - ISzAlloc_Free(alloc, pp); -} - -static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) -{ - UNUSED_VAR(pp) - UNUSED_VAR(props) - UNUSED_VAR(alloc) - return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; -} - -static void SbState_Init(void *pp) -{ - SbDec_Init((CSbDec *)pp); -} - -static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - int srcWasFinished, ECoderFinishMode finishMode, - // int *wasFinished - ECoderStatus *status) -{ - CSbDec *p = (CSbDec *)pp; - SRes res; - UNUSED_VAR(srcWasFinished) - p->dest = dest; - p->destLen = *destLen; - p->src = src; - p->srcLen = *srcLen; - p->finish = finishMode; /* change it */ - res = SbDec_Decode((CSbDec *)pp); - *destLen -= p->destLen; - *srcLen -= p->srcLen; - // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ - *status = (*destLen == 0 && *srcLen == 0) ? - CODER_STATUS_FINISHED_WITH_MARK : - CODER_STATUS_NOT_FINISHED; - return res; -} - -static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc) -{ - CSbDec *decoder = (CSbDec *)p->p; - if (!decoder) - { - decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec)); - if (!decoder) - return SZ_ERROR_MEM; - p->p = decoder; - p->Free = SbState_Free; - p->SetProps = SbState_SetProps; - p->Init = SbState_Init; - p->Code2 = SbState_Code2; - p->Filter = NULL; - } - SbDec_Construct(decoder); - SbDec_SetAlloc(decoder, alloc); - return SZ_OK; -} - -#endif - - - -/* ---------- Lzma2 ---------- */ - -typedef struct -{ - CLzma2Dec decoder; - BoolInt outBufMode; -} CLzma2Dec_Spec; - - -static void Lzma2State_Free(void *pp, ISzAllocPtr alloc) -{ - CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; - if (p->outBufMode) - Lzma2Dec_FreeProbs(&p->decoder, alloc); - else - Lzma2Dec_Free(&p->decoder, alloc); - ISzAlloc_Free(alloc, pp); -} - -static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) -{ - if (propSize != 1) - return SZ_ERROR_UNSUPPORTED; - { - CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; - if (p->outBufMode) - return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc); - else - return Lzma2Dec_Allocate(&p->decoder, props[0], alloc); - } -} - -static void Lzma2State_Init(void *pp) -{ - Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder); -} - - -/* - if (outBufMode), then (dest) is not used. Use NULL. - Data is unpacked to (spec->decoder.decoder.dic) output buffer. -*/ - -static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - int srcWasFinished, ECoderFinishMode finishMode, - // int *wasFinished, - ECoderStatus *status) -{ - CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp; - ELzmaStatus status2; - /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ - SRes res; - UNUSED_VAR(srcWasFinished) - if (spec->outBufMode) - { - SizeT dicPos = spec->decoder.decoder.dicPos; - SizeT dicLimit = dicPos + *destLen; - res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2); - *destLen = spec->decoder.decoder.dicPos - dicPos; - } - else - res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2); - // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK); - // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder - *status = (ECoderStatus)status2; - return res; -} - - -static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc) -{ - CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; - if (!spec) - { - spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec)); - if (!spec) - return SZ_ERROR_MEM; - p->p = spec; - p->Free = Lzma2State_Free; - p->SetProps = Lzma2State_SetProps; - p->Init = Lzma2State_Init; - p->Code2 = Lzma2State_Code2; - p->Filter = NULL; - Lzma2Dec_CONSTRUCT(&spec->decoder) - } - spec->outBufMode = False; - if (outBuf) - { - spec->outBufMode = True; - spec->decoder.decoder.dic = outBuf; - spec->decoder.decoder.dicBufSize = outBufSize; - } - return SZ_OK; -} - - -static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize) -{ - CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; - if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf)) - return SZ_ERROR_FAIL; - if (outBuf) - { - spec->decoder.decoder.dic = outBuf; - spec->decoder.decoder.dicBufSize = outBufSize; - } - return SZ_OK; -} - - - -static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc) -{ - unsigned i; - p->alloc = alloc; - p->buf = NULL; - p->numCoders = 0; - - p->outBufSize = 0; - p->outBuf = NULL; - // p->SingleBufMode = False; - - for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) - p->coders[i].p = NULL; -} - - -static void MixCoder_Free(CMixCoder *p) -{ - unsigned i; - p->numCoders = 0; - for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) - { - IStateCoder *sc = &p->coders[i]; - if (sc->p) - { - sc->Free(sc->p, p->alloc); - sc->p = NULL; - } - } - if (p->buf) - { - ISzAlloc_Free(p->alloc, p->buf); - p->buf = NULL; /* 9.31: the BUG was fixed */ - } -} - -static void MixCoder_Init(CMixCoder *p) -{ - unsigned i; - for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) - { - p->size[i] = 0; - p->pos[i] = 0; - p->finished[i] = 0; - } - for (i = 0; i < p->numCoders; i++) - { - IStateCoder *coder = &p->coders[i]; - coder->Init(coder->p); - p->results[i] = SZ_OK; - } - p->outWritten = 0; - p->wasFinished = False; - p->res = SZ_OK; - p->status = CODER_STATUS_NOT_SPECIFIED; -} - - -static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) -{ - IStateCoder *sc = &p->coders[coderIndex]; - p->ids[coderIndex] = methodId; - if (methodId == XZ_ID_LZMA2) - return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc); -#ifdef USE_SUBBLOCK - if (methodId == XZ_ID_Subblock) - return SbState_SetFromMethod(sc, p->alloc); -#endif - if (coderIndex == 0) - return SZ_ERROR_UNSUPPORTED; - return Xz_StateCoder_Bc_SetFromMethod_Func(sc, methodId, - XzBcFilterStateBase_Filter_Dec, p->alloc); -} - - -static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) -{ - IStateCoder *sc = &p->coders[coderIndex]; - if (methodId == XZ_ID_LZMA2) - return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize); - return SZ_ERROR_UNSUPPORTED; -} - - - -/* - if (destFinish) - then unpack data block is finished at (*destLen) position, - and we can return data that were not processed by filter - -output (status) can be : - CODER_STATUS_NOT_FINISHED - CODER_STATUS_FINISHED_WITH_MARK - CODER_STATUS_NEEDS_MORE_INPUT - not implemented still -*/ - -static SRes MixCoder_Code(CMixCoder *p, - Byte *dest, SizeT *destLen, int destFinish, - const Byte *src, SizeT *srcLen, int srcWasFinished, - ECoderFinishMode finishMode) -{ - SizeT destLenOrig = *destLen; - SizeT srcLenOrig = *srcLen; - - *destLen = 0; - *srcLen = 0; - - if (p->wasFinished) - return p->res; - - p->status = CODER_STATUS_NOT_FINISHED; - - // if (p->SingleBufMode) - if (p->outBuf) - { - SRes res; - SizeT destLen2, srcLen2; - int wasFinished; - - PRF_STR("------- MixCoder Single ----------") - - srcLen2 = srcLenOrig; - destLen2 = destLenOrig; - - { - IStateCoder *coder = &p->coders[0]; - res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode, - // &wasFinished, - &p->status); - wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK); - } - - p->res = res; - - /* - if (wasFinished) - p->status = CODER_STATUS_FINISHED_WITH_MARK; - else - { - if (res == SZ_OK) - if (destLen2 != destLenOrig) - p->status = CODER_STATUS_NEEDS_MORE_INPUT; - } - */ - - - *srcLen = srcLen2; - src += srcLen2; - p->outWritten += destLen2; - - if (res != SZ_OK || srcWasFinished || wasFinished) - p->wasFinished = True; - - if (p->numCoders == 1) - *destLen = destLen2; - else if (p->wasFinished) - { - unsigned i; - size_t processed = p->outWritten; - - for (i = 1; i < p->numCoders; i++) - { - IStateCoder *coder = &p->coders[i]; - processed = coder->Filter(coder->p, p->outBuf, processed); - if (wasFinished || (destFinish && p->outWritten == destLenOrig)) - processed = p->outWritten; - PRF_STR_INT("filter", i) - } - *destLen = processed; - } - return res; - } - - PRF_STR("standard mix") - - if (p->numCoders != 1) - { - if (!p->buf) - { - p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); - if (!p->buf) - return SZ_ERROR_MEM; - } - - finishMode = CODER_FINISH_ANY; - } - - for (;;) - { - BoolInt processed = False; - BoolInt allFinished = True; - SRes resMain = SZ_OK; - unsigned i; - - p->status = CODER_STATUS_NOT_FINISHED; - /* - if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) - break; - */ - - for (i = 0; i < p->numCoders; i++) - { - SRes res; - IStateCoder *coder = &p->coders[i]; - Byte *dest2; - SizeT destLen2, srcLen2; // destLen2_Orig; - const Byte *src2; - int srcFinished2; - int encodingWasFinished; - ECoderStatus status2; - - if (i == 0) - { - src2 = src; - srcLen2 = srcLenOrig - *srcLen; - srcFinished2 = srcWasFinished; - } - else - { - size_t k = i - 1; - src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k]; - srcLen2 = p->size[k] - p->pos[k]; - srcFinished2 = p->finished[k]; - } - - if (i == p->numCoders - 1) - { - dest2 = dest; - destLen2 = destLenOrig - *destLen; - } - else - { - if (p->pos[i] != p->size[i]) - continue; - dest2 = p->buf + (CODER_BUF_SIZE * i); - destLen2 = CODER_BUF_SIZE; - } - - // destLen2_Orig = destLen2; - - if (p->results[i] != SZ_OK) - { - if (resMain == SZ_OK) - resMain = p->results[i]; - continue; - } - - res = coder->Code2(coder->p, - dest2, &destLen2, - src2, &srcLen2, srcFinished2, - finishMode, - // &encodingWasFinished, - &status2); - - if (res != SZ_OK) - { - p->results[i] = res; - if (resMain == SZ_OK) - resMain = res; - } - - encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK); - - if (!encodingWasFinished) - { - allFinished = False; - if (p->numCoders == 1 && res == SZ_OK) - p->status = status2; - } - - if (i == 0) - { - *srcLen += srcLen2; - src += srcLen2; - } - else - p->pos[(size_t)i - 1] += srcLen2; - - if (i == p->numCoders - 1) - { - *destLen += destLen2; - dest += destLen2; - } - else - { - p->size[i] = destLen2; - p->pos[i] = 0; - p->finished[i] = encodingWasFinished; - } - - if (destLen2 != 0 || srcLen2 != 0) - processed = True; - } - - if (!processed) - { - if (allFinished) - p->status = CODER_STATUS_FINISHED_WITH_MARK; - return resMain; - } - } -} - - -SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) -{ - *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); - if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != - GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) - return SZ_ERROR_NO_ARCHIVE; - return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; -} - -static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) -{ - return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) - && GetUi32(buf) == CrcCalc(buf + 4, 6) - && flags == GetBe16(buf + 8) - && buf[10] == XZ_FOOTER_SIG_0 - && buf[11] == XZ_FOOTER_SIG_1; -} - -#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ - { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ - if (s == 0) return SZ_ERROR_ARCHIVE; \ - pos += s; } - - -static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p) -{ - const unsigned numFilters = XzBlock_GetNumFilters(p) - 1; - unsigned i; - { - const CXzFilter *f = &p->filters[numFilters]; - if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40) - return False; - } - - for (i = 0; i < numFilters; i++) - { - const CXzFilter *f = &p->filters[i]; - if (f->id == XZ_ID_Delta) - { - if (f->propsSize != 1) - return False; - } - else if (!XZ_IS_SUPPORTED_FILTER_ID(f->id) - || (f->propsSize != 0 && f->propsSize != 4)) - return False; - } - return True; -} - - -SRes XzBlock_Parse(CXzBlock *p, const Byte *header) -{ - unsigned pos; - unsigned numFilters, i; - unsigned headerSize = (unsigned)header[0] << 2; - - /* (headerSize != 0) : another code checks */ - - if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) - return SZ_ERROR_ARCHIVE; - - pos = 1; - p->flags = header[pos++]; - - p->packSize = (UInt64)(Int64)-1; - if (XzBlock_HasPackSize(p)) - { - READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize) - if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) - return SZ_ERROR_ARCHIVE; - } - - p->unpackSize = (UInt64)(Int64)-1; - if (XzBlock_HasUnpackSize(p)) - { - READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize) - } - - numFilters = XzBlock_GetNumFilters(p); - for (i = 0; i < numFilters; i++) - { - CXzFilter *filter = p->filters + i; - UInt64 size; - READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id) - READ_VARINT_AND_CHECK(header, pos, headerSize, &size) - if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) - return SZ_ERROR_ARCHIVE; - filter->propsSize = (UInt32)size; - memcpy(filter->props, header + pos, (size_t)size); - pos += (unsigned)size; - - #ifdef XZ_DUMP - printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); - { - unsigned i; - for (i = 0; i < size; i++) - printf(" %2X", filter->props[i]); - } - #endif - } - - if (XzBlock_HasUnsupportedFlags(p)) - return SZ_ERROR_UNSUPPORTED; - - while (pos < headerSize) - if (header[pos++] != 0) - return SZ_ERROR_ARCHIVE; - return SZ_OK; -} - - - - -static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize) -{ - unsigned i; - BoolInt needReInit = True; - unsigned numFilters = XzBlock_GetNumFilters(block); - - if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf))) - { - needReInit = False; - for (i = 0; i < numFilters; i++) - if (p->ids[i] != block->filters[numFilters - 1 - i].id) - { - needReInit = True; - break; - } - } - - // p->SingleBufMode = (outBuf != NULL); - p->outBuf = outBuf; - p->outBufSize = outBufSize; - - // p->SingleBufMode = False; - // outBuf = NULL; - - if (needReInit) - { - MixCoder_Free(p); - for (i = 0; i < numFilters; i++) - { - RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize)) - } - p->numCoders = numFilters; - } - else - { - RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize)) - } - - for (i = 0; i < numFilters; i++) - { - const CXzFilter *f = &block->filters[numFilters - 1 - i]; - IStateCoder *sc = &p->coders[i]; - RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)) - } - - MixCoder_Init(p); - return SZ_OK; -} - - - -void XzUnpacker_Init(CXzUnpacker *p) -{ - p->state = XZ_STATE_STREAM_HEADER; - p->pos = 0; - p->numStartedStreams = 0; - p->numFinishedStreams = 0; - p->numTotalBlocks = 0; - p->padSize = 0; - p->decodeOnlyOneBlock = 0; - - p->parseMode = False; - p->decodeToStreamSignature = False; - - // p->outBuf = NULL; - // p->outBufSize = 0; - p->outDataWritten = 0; -} - - -void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize) -{ - p->outBuf = outBuf; - p->outBufSize = outBufSize; -} - - -void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc) -{ - MixCoder_Construct(&p->decoder, alloc); - p->outBuf = NULL; - p->outBufSize = 0; - XzUnpacker_Init(p); -} - - -void XzUnpacker_Free(CXzUnpacker *p) -{ - MixCoder_Free(&p->decoder); -} - - -void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p) -{ - p->indexSize = 0; - p->numBlocks = 0; - Sha256_Init(&p->sha); - p->state = XZ_STATE_BLOCK_HEADER; - p->pos = 0; - p->decodeOnlyOneBlock = 1; -} - - -static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize) -{ - Byte temp[32]; - unsigned num = Xz_WriteVarInt(temp, packSize); - num += Xz_WriteVarInt(temp + num, unpackSize); - Sha256_Update(&p->sha, temp, num); - p->indexSize += num; - p->numBlocks++; -} - - - -SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, int srcFinished, - ECoderFinishMode finishMode, ECoderStatus *status) -{ - SizeT destLenOrig = *destLen; - SizeT srcLenOrig = *srcLen; - *destLen = 0; - *srcLen = 0; - *status = CODER_STATUS_NOT_SPECIFIED; - - for (;;) - { - SizeT srcRem; - - if (p->state == XZ_STATE_BLOCK) - { - SizeT destLen2 = destLenOrig - *destLen; - SizeT srcLen2 = srcLenOrig - *srcLen; - SRes res; - - ECoderFinishMode finishMode2 = finishMode; - BoolInt srcFinished2 = (BoolInt)srcFinished; - BoolInt destFinish = False; - - if (p->block.packSize != (UInt64)(Int64)-1) - { - UInt64 rem = p->block.packSize - p->packSize; - if (srcLen2 >= rem) - { - srcFinished2 = True; - srcLen2 = (SizeT)rem; - } - if (rem == 0 && p->block.unpackSize == p->unpackSize) - return SZ_ERROR_DATA; - } - - if (p->block.unpackSize != (UInt64)(Int64)-1) - { - UInt64 rem = p->block.unpackSize - p->unpackSize; - if (destLen2 >= rem) - { - destFinish = True; - finishMode2 = CODER_FINISH_END; - destLen2 = (SizeT)rem; - } - } - - /* - if (srcLen2 == 0 && destLen2 == 0) - { - *status = CODER_STATUS_NOT_FINISHED; - return SZ_OK; - } - */ - - { - res = MixCoder_Code(&p->decoder, - (p->outBuf ? NULL : dest), &destLen2, destFinish, - src, &srcLen2, srcFinished2, - finishMode2); - - *status = p->decoder.status; - XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2); - if (!p->outBuf) - dest += destLen2; - p->outDataWritten += destLen2; - } - - (*srcLen) += srcLen2; - src += srcLen2; - p->packSize += srcLen2; - (*destLen) += destLen2; - p->unpackSize += destLen2; - - RINOK(res) - - if (*status != CODER_STATUS_FINISHED_WITH_MARK) - { - if (p->block.packSize == p->packSize - && *status == CODER_STATUS_NEEDS_MORE_INPUT) - { - PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT") - *status = CODER_STATUS_NOT_SPECIFIED; - return SZ_ERROR_DATA; - } - - return SZ_OK; - } - { - XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize); - p->state = XZ_STATE_BLOCK_FOOTER; - p->pos = 0; - p->alignPos = 0; - *status = CODER_STATUS_NOT_SPECIFIED; - - if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize) - || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize)) - { - PRF_STR("ERROR: block.size mismatch") - return SZ_ERROR_DATA; - } - } - // continue; - } - - srcRem = srcLenOrig - *srcLen; - - // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes - if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER) - { - *status = CODER_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - switch ((int)p->state) - { - case XZ_STATE_STREAM_HEADER: - { - if (p->pos < XZ_STREAM_HEADER_SIZE) - { - if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) - return SZ_ERROR_NO_ARCHIVE; - if (p->decodeToStreamSignature) - return SZ_OK; - p->buf[p->pos++] = *src++; - (*srcLen)++; - } - else - { - RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)) - p->numStartedStreams++; - p->indexSize = 0; - p->numBlocks = 0; - Sha256_Init(&p->sha); - p->state = XZ_STATE_BLOCK_HEADER; - p->pos = 0; - } - break; - } - - case XZ_STATE_BLOCK_HEADER: - { - if (p->pos == 0) - { - p->buf[p->pos++] = *src++; - (*srcLen)++; - if (p->buf[0] == 0) - { - if (p->decodeOnlyOneBlock) - return SZ_ERROR_DATA; - p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); - p->indexPos = p->indexPreSize; - p->indexSize += p->indexPreSize; - Sha256_Final(&p->sha, p->shaDigest); - Sha256_Init(&p->sha); - p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); - p->state = XZ_STATE_STREAM_INDEX; - break; - } - p->blockHeaderSize = ((unsigned)p->buf[0] << 2) + 4; - break; - } - - if (p->pos != p->blockHeaderSize) - { - unsigned cur = p->blockHeaderSize - p->pos; - if (cur > srcRem) - cur = (unsigned)srcRem; - memcpy(p->buf + p->pos, src, cur); - p->pos += cur; - (*srcLen) += cur; - src += cur; - } - else - { - RINOK(XzBlock_Parse(&p->block, p->buf)) - if (!XzBlock_AreSupportedFilters(&p->block)) - return SZ_ERROR_UNSUPPORTED; - p->numTotalBlocks++; - p->state = XZ_STATE_BLOCK; - p->packSize = 0; - p->unpackSize = 0; - XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); - if (p->parseMode) - { - p->headerParsedOk = True; - return SZ_OK; - } - RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize)) - } - break; - } - - case XZ_STATE_BLOCK_FOOTER: - { - if ((((unsigned)p->packSize + p->alignPos) & 3) != 0) - { - if (srcRem == 0) - { - *status = CODER_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - (*srcLen)++; - p->alignPos++; - if (*src++ != 0) - return SZ_ERROR_CRC; - } - else - { - const unsigned checkSize = XzFlags_GetCheckSize(p->streamFlags); - unsigned cur = checkSize - p->pos; - if (cur != 0) - { - if (srcRem == 0) - { - *status = CODER_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - if (cur > srcRem) - cur = (unsigned)srcRem; - memcpy(p->buf + p->pos, src, cur); - p->pos += cur; - (*srcLen) += cur; - src += cur; - if (checkSize != p->pos) - break; - } - { - Byte digest[XZ_CHECK_SIZE_MAX]; - p->state = XZ_STATE_BLOCK_HEADER; - p->pos = 0; - if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) - return SZ_ERROR_CRC; - if (p->decodeOnlyOneBlock) - { - *status = CODER_STATUS_FINISHED_WITH_MARK; - return SZ_OK; - } - } - } - break; - } - - case XZ_STATE_STREAM_INDEX: - { - if (p->pos < p->indexPreSize) - { - (*srcLen)++; - if (*src++ != p->buf[p->pos++]) - return SZ_ERROR_CRC; - } - else - { - if (p->indexPos < p->indexSize) - { - UInt64 cur = p->indexSize - p->indexPos; - if (srcRem > cur) - srcRem = (SizeT)cur; - p->crc = CrcUpdate(p->crc, src, srcRem); - Sha256_Update(&p->sha, src, srcRem); - (*srcLen) += srcRem; - src += srcRem; - p->indexPos += srcRem; - } - else if ((p->indexPos & 3) != 0) - { - Byte b = *src++; - p->crc = CRC_UPDATE_BYTE(p->crc, b); - (*srcLen)++; - p->indexPos++; - p->indexSize++; - if (b != 0) - return SZ_ERROR_CRC; - } - else - { - Byte digest[SHA256_DIGEST_SIZE]; - p->state = XZ_STATE_STREAM_INDEX_CRC; - p->indexSize += 4; - p->pos = 0; - Sha256_Final(&p->sha, digest); - if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) - return SZ_ERROR_CRC; - } - } - break; - } - - case XZ_STATE_STREAM_INDEX_CRC: - { - if (p->pos < 4) - { - (*srcLen)++; - p->buf[p->pos++] = *src++; - } - else - { - const Byte *ptr = p->buf; - p->state = XZ_STATE_STREAM_FOOTER; - p->pos = 0; - if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr)) - return SZ_ERROR_CRC; - } - break; - } - - case XZ_STATE_STREAM_FOOTER: - { - unsigned cur = XZ_STREAM_FOOTER_SIZE - p->pos; - if (cur > srcRem) - cur = (unsigned)srcRem; - memcpy(p->buf + p->pos, src, cur); - p->pos += cur; - (*srcLen) += cur; - src += cur; - if (p->pos == XZ_STREAM_FOOTER_SIZE) - { - p->state = XZ_STATE_STREAM_PADDING; - p->numFinishedStreams++; - p->padSize = 0; - if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) - return SZ_ERROR_CRC; - } - break; - } - - case XZ_STATE_STREAM_PADDING: - { - if (*src != 0) - { - if (((UInt32)p->padSize & 3) != 0) - return SZ_ERROR_NO_ARCHIVE; - p->pos = 0; - p->state = XZ_STATE_STREAM_HEADER; - } - else - { - (*srcLen)++; - src++; - p->padSize++; - } - break; - } - - case XZ_STATE_BLOCK: break; /* to disable GCC warning */ - - default: return SZ_ERROR_FAIL; - } - } - /* - if (p->state == XZ_STATE_FINISHED) - *status = CODER_STATUS_FINISHED_WITH_MARK; - return SZ_OK; - */ -} - - -SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, - ECoderFinishMode finishMode, ECoderStatus *status) -{ - XzUnpacker_Init(p); - XzUnpacker_SetOutBuf(p, dest, *destLen); - - return XzUnpacker_Code(p, - NULL, destLen, - src, srcLen, True, - finishMode, status); -} - - -BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p) -{ - return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0); -} - -BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p) -{ - return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); -} - -UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p) -{ - UInt64 num = 0; - if (p->state == XZ_STATE_STREAM_PADDING) - num = p->padSize; - else if (p->state == XZ_STATE_STREAM_HEADER) - num = p->padSize + p->pos; - return num; -} - - - - - - - - - - - - - - - - - - - - - -#ifndef Z7_ST -#include "MtDec.h" -#endif - - -void XzDecMtProps_Init(CXzDecMtProps *p) -{ - p->inBufSize_ST = 1 << 18; - p->outStep_ST = 1 << 20; - p->ignoreErrors = False; - - #ifndef Z7_ST - p->numThreads = 1; - p->inBufSize_MT = 1 << 18; - p->memUseMax = sizeof(size_t) << 28; - #endif -} - - - -#ifndef Z7_ST - -/* ---------- CXzDecMtThread ---------- */ - -typedef struct -{ - Byte *outBuf; - size_t outBufSize; - size_t outPreSize; - size_t inPreSize; - size_t inPreHeaderSize; - size_t blockPackSize_for_Index; // including block header and checksum. - size_t blockPackTotal; // including stream header, block header and checksum. - size_t inCodeSize; - size_t outCodeSize; - ECoderStatus status; - SRes codeRes; - BoolInt skipMode; - // BoolInt finishedWithMark; - EMtDecParseState parseState; - BoolInt parsing_Truncated; - BoolInt atBlockHeader; - CXzStreamFlags streamFlags; - // UInt64 numFinishedStreams - UInt64 numStreams; - UInt64 numTotalBlocks; - UInt64 numBlocks; - - BoolInt dec_created; - CXzUnpacker dec; - - Byte mtPad[1 << 7]; -} CXzDecMtThread; - -#endif - - -/* ---------- CXzDecMt ---------- */ - -struct CXzDecMt -{ - CAlignOffsetAlloc alignOffsetAlloc; - ISzAllocPtr allocMid; - - CXzDecMtProps props; - size_t unpackBlockMaxSize; - - ISeqInStreamPtr inStream; - ISeqOutStreamPtr outStream; - ICompressProgressPtr progress; - - BoolInt finishMode; - BoolInt outSize_Defined; - UInt64 outSize; - - UInt64 outProcessed; - UInt64 inProcessed; - UInt64 readProcessed; - BoolInt readWasFinished; - SRes readRes; - SRes writeRes; - - Byte *outBuf; - size_t outBufSize; - Byte *inBuf; - size_t inBufSize; - - CXzUnpacker dec; - - ECoderStatus status; - SRes codeRes; - - #ifndef Z7_ST - BoolInt mainDecoderWasCalled; - // int statErrorDefined; - int finishedDecoderIndex; - - // global values that are used in Parse stage - CXzStreamFlags streamFlags; - // UInt64 numFinishedStreams - UInt64 numStreams; - UInt64 numTotalBlocks; - UInt64 numBlocks; - - // UInt64 numBadBlocks; - SRes mainErrorCode; // it's set to error code, if the size Code() output doesn't patch the size from Parsing stage - // it can be = SZ_ERROR_INPUT_EOF - // it can be = SZ_ERROR_DATA, in some another cases - BoolInt isBlockHeaderState_Parse; - BoolInt isBlockHeaderState_Write; - UInt64 outProcessed_Parse; - BoolInt parsing_Truncated; - - BoolInt mtc_WasConstructed; - CMtDec mtc; - CXzDecMtThread coders[MTDEC_THREADS_MAX]; - #endif -}; - - - -CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) -{ - CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt)); - if (!p) - return NULL; - - AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); - p->alignOffsetAlloc.baseAlloc = alloc; - p->alignOffsetAlloc.numAlignBits = 7; - p->alignOffsetAlloc.offset = 0; - - p->allocMid = allocMid; - - p->outBuf = NULL; - p->outBufSize = 0; - p->inBuf = NULL; - p->inBufSize = 0; - - XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt); - - p->unpackBlockMaxSize = 0; - - XzDecMtProps_Init(&p->props); - - #ifndef Z7_ST - p->mtc_WasConstructed = False; - { - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CXzDecMtThread *coder = &p->coders[i]; - coder->dec_created = False; - coder->outBuf = NULL; - coder->outBufSize = 0; - } - } - #endif - - return (CXzDecMtHandle)p; -} - - -#ifndef Z7_ST - -static void XzDecMt_FreeOutBufs(CXzDecMt *p) -{ - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CXzDecMtThread *coder = &p->coders[i]; - if (coder->outBuf) - { - ISzAlloc_Free(p->allocMid, coder->outBuf); - coder->outBuf = NULL; - coder->outBufSize = 0; - } - } - p->unpackBlockMaxSize = 0; -} - -#endif - - - -static void XzDecMt_FreeSt(CXzDecMt *p) -{ - XzUnpacker_Free(&p->dec); - - if (p->outBuf) - { - ISzAlloc_Free(p->allocMid, p->outBuf); - p->outBuf = NULL; - } - p->outBufSize = 0; - - if (p->inBuf) - { - ISzAlloc_Free(p->allocMid, p->inBuf); - p->inBuf = NULL; - } - p->inBufSize = 0; -} - - -// #define GET_CXzDecMt_p CXzDecMt *p = pp; - -void XzDecMt_Destroy(CXzDecMtHandle p) -{ - // GET_CXzDecMt_p - - XzDecMt_FreeSt(p); - - #ifndef Z7_ST - - if (p->mtc_WasConstructed) - { - MtDec_Destruct(&p->mtc); - p->mtc_WasConstructed = False; - } - { - unsigned i; - for (i = 0; i < MTDEC_THREADS_MAX; i++) - { - CXzDecMtThread *t = &p->coders[i]; - if (t->dec_created) - { - // we don't need to free dict here - XzUnpacker_Free(&t->dec); - t->dec_created = False; - } - } - } - XzDecMt_FreeOutBufs(p); - - #endif - - ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p); -} - - - -#ifndef Z7_ST - -static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) -{ - CXzDecMt *me = (CXzDecMt *)obj; - CXzDecMtThread *coder = &me->coders[coderIndex]; - size_t srcSize = cc->srcSize; - - cc->srcSize = 0; - cc->outPos = 0; - cc->state = MTDEC_PARSE_CONTINUE; - - cc->canCreateNewThread = True; - - if (cc->startCall) - { - coder->outPreSize = 0; - coder->inPreSize = 0; - coder->inPreHeaderSize = 0; - coder->parseState = MTDEC_PARSE_CONTINUE; - coder->parsing_Truncated = False; - coder->skipMode = False; - coder->codeRes = SZ_OK; - coder->status = CODER_STATUS_NOT_SPECIFIED; - coder->inCodeSize = 0; - coder->outCodeSize = 0; - - coder->numStreams = me->numStreams; - coder->numTotalBlocks = me->numTotalBlocks; - coder->numBlocks = me->numBlocks; - - if (!coder->dec_created) - { - XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt); - coder->dec_created = True; - } - - XzUnpacker_Init(&coder->dec); - - if (me->isBlockHeaderState_Parse) - { - coder->dec.streamFlags = me->streamFlags; - coder->atBlockHeader = True; - XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec); - } - else - { - coder->atBlockHeader = False; - me->isBlockHeaderState_Parse = True; - } - - coder->dec.numStartedStreams = me->numStreams; - coder->dec.numTotalBlocks = me->numTotalBlocks; - coder->dec.numBlocks = me->numBlocks; - } - - while (!coder->skipMode) - { - ECoderStatus status; - SRes res; - size_t srcSize2 = srcSize; - size_t destSize = (size_t)0 - 1; - - coder->dec.parseMode = True; - coder->dec.headerParsedOk = False; - - PRF_STR_INT("Parse", srcSize2) - - res = XzUnpacker_Code(&coder->dec, - NULL, &destSize, - cc->src, &srcSize2, cc->srcFinished, - CODER_FINISH_END, &status); - - // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2)); - - coder->codeRes = res; - coder->status = status; - cc->srcSize += srcSize2; - srcSize -= srcSize2; - coder->inPreHeaderSize += srcSize2; - coder->inPreSize = coder->inPreHeaderSize; - - if (res != SZ_OK) - { - cc->state = - coder->parseState = MTDEC_PARSE_END; - /* - if (res == SZ_ERROR_MEM) - return res; - return SZ_OK; - */ - return; // res; - } - - if (coder->dec.headerParsedOk) - { - const CXzBlock *block = &coder->dec.block; - if (XzBlock_HasUnpackSize(block) - // && block->unpackSize <= me->props.outBlockMax - && XzBlock_HasPackSize(block)) - { - { - if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax) - { - cc->state = MTDEC_PARSE_OVERFLOW; - return; // SZ_OK; - } - } - { - const UInt64 packSize = block->packSize; - const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); - const unsigned checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags); - const UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize; - // if (blockPackSum <= me->props.inBlockMax) - // unpackBlockMaxSize - { - coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize); - coder->blockPackTotal = (size_t)blockPackSum; - coder->outPreSize = (size_t)block->unpackSize; - coder->streamFlags = coder->dec.streamFlags; - me->streamFlags = coder->dec.streamFlags; - coder->skipMode = True; - break; - } - } - } - } - else - // if (coder->inPreSize <= me->props.inBlockMax) - { - if (!cc->srcFinished) - return; // SZ_OK; - cc->state = - coder->parseState = MTDEC_PARSE_END; - return; // SZ_OK; - } - cc->state = MTDEC_PARSE_OVERFLOW; - return; // SZ_OK; - } - - // ---------- skipMode ---------- - { - UInt64 rem = coder->blockPackTotal - coder->inPreSize; - size_t cur = srcSize; - if (cur > rem) - cur = (size_t)rem; - cc->srcSize += cur; - coder->inPreSize += cur; - srcSize -= cur; - - if (coder->inPreSize == coder->blockPackTotal) - { - if (srcSize == 0) - { - if (!cc->srcFinished) - return; // SZ_OK; - cc->state = MTDEC_PARSE_END; - } - else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block - cc->state = MTDEC_PARSE_END; - else - { - cc->state = MTDEC_PARSE_NEW; - - { - size_t blockMax = me->unpackBlockMaxSize; - if (blockMax < coder->outPreSize) - blockMax = coder->outPreSize; - { - UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2; - if (me->props.memUseMax < required) - cc->canCreateNewThread = False; - } - } - - if (me->outSize_Defined) - { - // next block can be zero size - const UInt64 rem2 = me->outSize - me->outProcessed_Parse; - if (rem2 < coder->outPreSize) - { - coder->parsing_Truncated = True; - cc->state = MTDEC_PARSE_END; - } - me->outProcessed_Parse += coder->outPreSize; - } - } - } - else if (cc->srcFinished) - cc->state = MTDEC_PARSE_END; - else - return; // SZ_OK; - - coder->parseState = cc->state; - cc->outPos = coder->outPreSize; - - me->numStreams = coder->dec.numStartedStreams; - me->numTotalBlocks = coder->dec.numTotalBlocks; - me->numBlocks = coder->dec.numBlocks + 1; - return; // SZ_OK; - } -} - - -static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex) -{ - CXzDecMt *me = (CXzDecMt *)pp; - CXzDecMtThread *coder = &me->coders[coderIndex]; - Byte *dest; - - if (!coder->dec.headerParsedOk) - return SZ_OK; - - dest = coder->outBuf; - - if (!dest || coder->outBufSize < coder->outPreSize) - { - if (dest) - { - ISzAlloc_Free(me->allocMid, dest); - coder->outBuf = NULL; - coder->outBufSize = 0; - } - { - size_t outPreSize = coder->outPreSize; - if (outPreSize == 0) - outPreSize = 1; - dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize); - } - if (!dest) - return SZ_ERROR_MEM; - coder->outBuf = dest; - coder->outBufSize = coder->outPreSize; - - if (coder->outBufSize > me->unpackBlockMaxSize) - me->unpackBlockMaxSize = coder->outBufSize; - } - - // return SZ_ERROR_MEM; - - XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize); - - { - SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize); - // res = SZ_ERROR_UNSUPPORTED; // to test - coder->codeRes = res; - if (res != SZ_OK) - { - // if (res == SZ_ERROR_MEM) return res; - if (me->props.ignoreErrors && res != SZ_ERROR_MEM) - return SZ_OK; - return res; - } - } - - return SZ_OK; -} - - -static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex, - const Byte *src, size_t srcSize, int srcFinished, - // int finished, int blockFinished, - UInt64 *inCodePos, UInt64 *outCodePos, int *stop) -{ - CXzDecMt *me = (CXzDecMt *)pp; - CXzDecMtThread *coder = &me->coders[coderIndex]; - - *inCodePos = coder->inCodeSize; - *outCodePos = coder->outCodeSize; - *stop = True; - - if (srcSize > coder->inPreSize - coder->inCodeSize) - return SZ_ERROR_FAIL; - - if (coder->inCodeSize < coder->inPreHeaderSize) - { - size_t step = coder->inPreHeaderSize - coder->inCodeSize; - if (step > srcSize) - step = srcSize; - src += step; - srcSize -= step; - coder->inCodeSize += step; - *inCodePos = coder->inCodeSize; - if (coder->inCodeSize < coder->inPreHeaderSize) - { - *stop = False; - return SZ_OK; - } - } - - if (!coder->dec.headerParsedOk) - return SZ_OK; - if (!coder->outBuf) - return SZ_OK; - - if (coder->codeRes == SZ_OK) - { - ECoderStatus status; - SRes res; - size_t srcProcessed = srcSize; - size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten; - - // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur)); - - res = XzUnpacker_Code(&coder->dec, - NULL, &outSizeCur, - src, &srcProcessed, srcFinished, - // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY, - CODER_FINISH_END, - &status); - - // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur)); - - coder->codeRes = res; - coder->status = status; - coder->inCodeSize += srcProcessed; - coder->outCodeSize = coder->dec.outDataWritten; - *inCodePos = coder->inCodeSize; - *outCodePos = coder->outCodeSize; - - if (res == SZ_OK) - { - if (srcProcessed == srcSize) - *stop = False; - return SZ_OK; - } - } - - if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM) - { - *inCodePos = coder->inPreSize; - *outCodePos = coder->outPreSize; - return SZ_OK; - } - return coder->codeRes; -} - - -#define XZDECMT_STREAM_WRITE_STEP (1 << 24) - -static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex, - BoolInt needWriteToStream, - const Byte *src, size_t srcSize, BoolInt isCross, - // int srcFinished, - BoolInt *needContinue, - BoolInt *canRecode) -{ - CXzDecMt *me = (CXzDecMt *)pp; - const CXzDecMtThread *coder = &me->coders[coderIndex]; - - // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize)); - - *needContinue = False; - *canRecode = True; - - if (!needWriteToStream) - return SZ_OK; - - if (!coder->dec.headerParsedOk || !coder->outBuf) - { - if (me->finishedDecoderIndex < 0) - me->finishedDecoderIndex = (int)coderIndex; - return SZ_OK; - } - - if (me->finishedDecoderIndex >= 0) - return SZ_OK; - - me->mtc.inProcessed += coder->inCodeSize; - - *canRecode = False; - - { - SRes res; - size_t size = coder->outCodeSize; - Byte *data = coder->outBuf; - - // we use in me->dec: sha, numBlocks, indexSize - - if (!me->isBlockHeaderState_Write) - { - XzUnpacker_PrepareToRandomBlockDecoding(&me->dec); - me->dec.decodeOnlyOneBlock = False; - me->dec.numStartedStreams = coder->dec.numStartedStreams; - me->dec.streamFlags = coder->streamFlags; - - me->isBlockHeaderState_Write = True; - } - - me->dec.numTotalBlocks = coder->dec.numTotalBlocks; - XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize); - - if (coder->outPreSize != size) - { - if (me->props.ignoreErrors) - { - memset(data + size, 0, coder->outPreSize - size); - size = coder->outPreSize; - } - // me->numBadBlocks++; - if (me->mainErrorCode == SZ_OK) - { - if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT) - me->mainErrorCode = SZ_ERROR_INPUT_EOF; - else - me->mainErrorCode = SZ_ERROR_DATA; - } - } - - if (me->writeRes != SZ_OK) - return me->writeRes; - - res = SZ_OK; - { - if (me->outSize_Defined) - { - const UInt64 rem = me->outSize - me->outProcessed; - if (size > rem) - size = (SizeT)rem; - } - - for (;;) - { - size_t cur = size; - size_t written; - if (cur > XZDECMT_STREAM_WRITE_STEP) - cur = XZDECMT_STREAM_WRITE_STEP; - - written = ISeqOutStream_Write(me->outStream, data, cur); - - // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written)); - - me->outProcessed += written; - if (written != cur) - { - me->writeRes = SZ_ERROR_WRITE; - res = me->writeRes; - break; - } - data += cur; - size -= cur; - // PRF_STR_INT("Written size =", size) - if (size == 0) - break; - res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0); - if (res != SZ_OK) - break; - } - } - - if (coder->codeRes != SZ_OK) - if (!me->props.ignoreErrors) - { - me->finishedDecoderIndex = (int)coderIndex; - return res; - } - - RINOK(res) - - if (coder->inPreSize != coder->inCodeSize - || coder->blockPackTotal != coder->inCodeSize) - { - me->finishedDecoderIndex = (int)coderIndex; - return SZ_OK; - } - - if (coder->parseState != MTDEC_PARSE_END) - { - *needContinue = True; - return SZ_OK; - } - } - - // (coder->state == MTDEC_PARSE_END) means that there are no other working threads - // so we can use mtc variables without lock - - PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed) - - me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; - { - CXzUnpacker *dec = &me->dec; - - PRF_STR_INT("PostSingle", srcSize) - - { - size_t srcProcessed = srcSize; - ECoderStatus status; - size_t outSizeCur = 0; - SRes res; - - // dec->decodeOnlyOneBlock = False; - dec->decodeToStreamSignature = True; - - me->mainDecoderWasCalled = True; - - if (coder->parsing_Truncated) - { - me->parsing_Truncated = True; - return SZ_OK; - } - - /* - We have processed all xz-blocks of stream, - And xz unpacker is at XZ_STATE_BLOCK_HEADER state, where - (src) is a pointer to xz-Index structure. - We finish reading of current xz-Stream, including Zero padding after xz-Stream. - We exit, if we reach extra byte (first byte of new-Stream or another data). - But we don't update input stream pointer for that new extra byte. - If extra byte is not correct first byte of xz-signature, - we have SZ_ERROR_NO_ARCHIVE error here. - */ - - res = XzUnpacker_Code(dec, - NULL, &outSizeCur, - src, &srcProcessed, - me->mtc.readWasFinished, // srcFinished - CODER_FINISH_END, // CODER_FINISH_ANY, - &status); - - // res = SZ_ERROR_ARCHIVE; // for failure test - - me->status = status; - me->codeRes = res; - - if (isCross) - me->mtc.crossStart += srcProcessed; - - me->mtc.inProcessed += srcProcessed; - me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; - - srcSize -= srcProcessed; - src += srcProcessed; - - if (res != SZ_OK) - { - return SZ_OK; - // return res; - } - - if (dec->state == XZ_STATE_STREAM_HEADER) - { - *needContinue = True; - me->isBlockHeaderState_Parse = False; - me->isBlockHeaderState_Write = False; - - if (!isCross) - { - Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); - if (!crossBuf) - return SZ_ERROR_MEM; - if (srcSize != 0) - memcpy(crossBuf, src, srcSize); - me->mtc.crossStart = 0; - me->mtc.crossEnd = srcSize; - } - - PRF_STR_INT("XZ_STATE_STREAM_HEADER crossEnd = ", (unsigned)me->mtc.crossEnd) - - return SZ_OK; - } - - if (status != CODER_STATUS_NEEDS_MORE_INPUT || srcSize != 0) - { - return SZ_ERROR_FAIL; - } - - if (me->mtc.readWasFinished) - { - return SZ_OK; - } - } - - { - size_t inPos; - size_t inLim; - // const Byte *inData; - UInt64 inProgressPrev = me->mtc.inProcessed; - - // XzDecMt_Prepare_InBuf_ST(p); - Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); - if (!crossBuf) - return SZ_ERROR_MEM; - - inPos = 0; - inLim = 0; - - // inData = crossBuf; - - for (;;) - { - SizeT inProcessed; - SizeT outProcessed; - ECoderStatus status; - SRes res; - - if (inPos == inLim) - { - if (!me->mtc.readWasFinished) - { - inPos = 0; - inLim = me->mtc.inBufSize; - me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)crossBuf, &inLim); - me->mtc.readProcessed += inLim; - if (inLim == 0 || me->mtc.readRes != SZ_OK) - me->mtc.readWasFinished = True; - } - } - - inProcessed = inLim - inPos; - outProcessed = 0; - - res = XzUnpacker_Code(dec, - NULL, &outProcessed, - crossBuf + inPos, &inProcessed, - (inProcessed == 0), // srcFinished - CODER_FINISH_END, &status); - - me->codeRes = res; - me->status = status; - inPos += inProcessed; - me->mtc.inProcessed += inProcessed; - me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; - - if (res != SZ_OK) - { - return SZ_OK; - // return res; - } - - if (dec->state == XZ_STATE_STREAM_HEADER) - { - *needContinue = True; - me->mtc.crossStart = inPos; - me->mtc.crossEnd = inLim; - me->isBlockHeaderState_Parse = False; - me->isBlockHeaderState_Write = False; - return SZ_OK; - } - - if (status != CODER_STATUS_NEEDS_MORE_INPUT) - return SZ_ERROR_FAIL; - - if (me->mtc.progress) - { - UInt64 inDelta = me->mtc.inProcessed - inProgressPrev; - if (inDelta >= (1 << 22)) - { - RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress)) - inProgressPrev = me->mtc.inProcessed; - } - } - if (me->mtc.readWasFinished) - return SZ_OK; - } - } - } -} - - -#endif - - - -void XzStatInfo_Clear(CXzStatInfo *p) -{ - p->InSize = 0; - p->OutSize = 0; - - p->NumStreams = 0; - p->NumBlocks = 0; - - p->UnpackSize_Defined = False; - - p->NumStreams_Defined = False; - p->NumBlocks_Defined = False; - - p->DataAfterEnd = False; - p->DecodingTruncated = False; - - p->DecodeRes = SZ_OK; - p->ReadRes = SZ_OK; - p->ProgressRes = SZ_OK; - - p->CombinedRes = SZ_OK; - p->CombinedRes_Type = SZ_OK; -} - - - -/* - XzDecMt_Decode_ST() can return SZ_OK or the following errors - - SZ_ERROR_MEM for memory allocation error - - error from XzUnpacker_Code() function - - SZ_ERROR_WRITE for ISeqOutStream::Write(). stat->CombinedRes_Type = SZ_ERROR_WRITE in that case - - ICompressProgress::Progress() error, stat->CombinedRes_Type = SZ_ERROR_PROGRESS. - But XzDecMt_Decode_ST() doesn't return ISeqInStream::Read() errors. - ISeqInStream::Read() result is set to p->readRes. - also it can set stat->CombinedRes_Type to SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. -*/ - -static SRes XzDecMt_Decode_ST(CXzDecMt *p - #ifndef Z7_ST - , BoolInt tMode - #endif - , CXzStatInfo *stat) -{ - size_t outPos; - size_t inPos, inLim; - const Byte *inData; - UInt64 inPrev, outPrev; - - CXzUnpacker *dec; - - #ifndef Z7_ST - if (tMode) - { - XzDecMt_FreeOutBufs(p); - tMode = (BoolInt)MtDec_PrepareRead(&p->mtc); - } - #endif - - if (!p->outBuf || p->outBufSize != p->props.outStep_ST) - { - ISzAlloc_Free(p->allocMid, p->outBuf); - p->outBufSize = 0; - p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST); - if (!p->outBuf) - return SZ_ERROR_MEM; - p->outBufSize = p->props.outStep_ST; - } - - if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) - { - ISzAlloc_Free(p->allocMid, p->inBuf); - p->inBufSize = 0; - p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); - if (!p->inBuf) - return SZ_ERROR_MEM; - p->inBufSize = p->props.inBufSize_ST; - } - - dec = &p->dec; - dec->decodeToStreamSignature = False; - // dec->decodeOnlyOneBlock = False; - - XzUnpacker_SetOutBuf(dec, NULL, 0); - - inPrev = p->inProcessed; - outPrev = p->outProcessed; - - inPos = 0; - inLim = 0; - inData = NULL; - outPos = 0; - - for (;;) - { - SizeT outSize; - BoolInt finished; - ECoderFinishMode finishMode; - SizeT inProcessed; - ECoderStatus status; - SRes res; - - SizeT outProcessed; - - - - if (inPos == inLim) - { - #ifndef Z7_ST - if (tMode) - { - inData = MtDec_Read(&p->mtc, &inLim); - inPos = 0; - if (inData) - continue; - tMode = False; - inLim = 0; - } - #endif - - if (!p->readWasFinished) - { - inPos = 0; - inLim = p->inBufSize; - inData = p->inBuf; - p->readRes = ISeqInStream_Read(p->inStream, (void *)p->inBuf, &inLim); - p->readProcessed += inLim; - if (inLim == 0 || p->readRes != SZ_OK) - p->readWasFinished = True; - } - } - - outSize = p->props.outStep_ST - outPos; - - finishMode = CODER_FINISH_ANY; - if (p->outSize_Defined) - { - const UInt64 rem = p->outSize - p->outProcessed; - if (outSize >= rem) - { - outSize = (SizeT)rem; - if (p->finishMode) - finishMode = CODER_FINISH_END; - } - } - - inProcessed = inLim - inPos; - outProcessed = outSize; - - res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed, - inData + inPos, &inProcessed, - (inPos == inLim), // srcFinished - finishMode, &status); - - p->codeRes = res; - p->status = status; - - inPos += inProcessed; - outPos += outProcessed; - p->inProcessed += inProcessed; - p->outProcessed += outProcessed; - - finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK); - - if (finished || outProcessed >= outSize) - if (outPos != 0) - { - const size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos); - // p->outProcessed += written; // 21.01: BUG fixed - if (written != outPos) - { - stat->CombinedRes_Type = SZ_ERROR_WRITE; - return SZ_ERROR_WRITE; - } - outPos = 0; - } - - if (p->progress && res == SZ_OK) - { - if (p->inProcessed - inPrev >= (1 << 22) || - p->outProcessed - outPrev >= (1 << 22)) - { - res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed); - if (res != SZ_OK) - { - stat->CombinedRes_Type = SZ_ERROR_PROGRESS; - stat->ProgressRes = res; - return res; - } - inPrev = p->inProcessed; - outPrev = p->outProcessed; - } - } - - if (finished) - { - // p->codeRes is preliminary error from XzUnpacker_Code. - // and it can be corrected later as final result - // so we return SZ_OK here instead of (res); - return SZ_OK; - // return res; - } - } -} - - - -/* -XzStatInfo_SetStat() transforms - CXzUnpacker return code and status to combined CXzStatInfo results. - it can convert SZ_OK to SZ_ERROR_INPUT_EOF - it can convert SZ_ERROR_NO_ARCHIVE to SZ_OK and (DataAfterEnd = 1) -*/ - -static void XzStatInfo_SetStat(const CXzUnpacker *dec, - int finishMode, - // UInt64 readProcessed, - UInt64 inProcessed, - SRes res, // it's result from CXzUnpacker unpacker - ECoderStatus status, - BoolInt decodingTruncated, - CXzStatInfo *stat) -{ - UInt64 extraSize; - - stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0); - stat->InSize = inProcessed; - stat->NumStreams = dec->numStartedStreams; - stat->NumBlocks = dec->numTotalBlocks; - - stat->UnpackSize_Defined = True; - stat->NumStreams_Defined = True; - stat->NumBlocks_Defined = True; - - extraSize = XzUnpacker_GetExtraSize(dec); - - if (res == SZ_OK) - { - if (status == CODER_STATUS_NEEDS_MORE_INPUT) - { - // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams - // any extra data is part of correct data - extraSize = 0; - // if xz stream was not finished, then we need more data - if (!XzUnpacker_IsStreamWasFinished(dec)) - res = SZ_ERROR_INPUT_EOF; - } - else - { - // CODER_STATUS_FINISHED_WITH_MARK is not possible for multi stream xz decoding - // so he we have (status == CODER_STATUS_NOT_FINISHED) - // if (status != CODER_STATUS_FINISHED_WITH_MARK) - if (!decodingTruncated || finishMode) - res = SZ_ERROR_DATA; - } - } - else if (res == SZ_ERROR_NO_ARCHIVE) - { - /* - SZ_ERROR_NO_ARCHIVE is possible for 2 states: - XZ_STATE_STREAM_HEADER - if bad signature or bad CRC - XZ_STATE_STREAM_PADDING - if non-zero padding data - extraSize and inProcessed don't include "bad" byte - */ - // if (inProcessed == extraSize), there was no any good xz stream header, and we keep error - if (inProcessed != extraSize) // if there were good xz streams before error - { - // if (extraSize != 0 || readProcessed != inProcessed) - { - // he we suppose that all xz streams were finsihed OK, and we have - // some extra data after all streams - stat->DataAfterEnd = True; - res = SZ_OK; - } - } - } - - if (stat->DecodeRes == SZ_OK) - stat->DecodeRes = res; - - stat->InSize -= extraSize; -} - - - -SRes XzDecMt_Decode(CXzDecMtHandle p, - const CXzDecMtProps *props, - const UInt64 *outDataSize, int finishMode, - ISeqOutStreamPtr outStream, - // Byte *outBuf, size_t *outBufSize, - ISeqInStreamPtr inStream, - // const Byte *inData, size_t inDataSize, - CXzStatInfo *stat, - int *isMT, - ICompressProgressPtr progress) -{ - // GET_CXzDecMt_p - #ifndef Z7_ST - BoolInt tMode; - #endif - - XzStatInfo_Clear(stat); - - p->props = *props; - - p->inStream = inStream; - p->outStream = outStream; - p->progress = progress; - // p->stat = stat; - - p->outSize = 0; - p->outSize_Defined = False; - if (outDataSize) - { - p->outSize_Defined = True; - p->outSize = *outDataSize; - } - - p->finishMode = (BoolInt)finishMode; - - // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test - - p->writeRes = SZ_OK; - p->outProcessed = 0; - p->inProcessed = 0; - p->readProcessed = 0; - p->readWasFinished = False; - p->readRes = SZ_OK; - - p->codeRes = SZ_OK; - p->status = CODER_STATUS_NOT_SPECIFIED; - - XzUnpacker_Init(&p->dec); - - *isMT = False; - - /* - p->outBuf = NULL; - p->outBufSize = 0; - if (!outStream) - { - p->outBuf = outBuf; - p->outBufSize = *outBufSize; - *outBufSize = 0; - } - */ - - - #ifndef Z7_ST - - p->isBlockHeaderState_Parse = False; - p->isBlockHeaderState_Write = False; - // p->numBadBlocks = 0; - p->mainErrorCode = SZ_OK; - p->mainDecoderWasCalled = False; - - tMode = False; - - if (p->props.numThreads > 1) - { - IMtDecCallback2 vt; - BoolInt needContinue; - SRes res; - // we just free ST buffers here - // but we still keep state variables, that was set in XzUnpacker_Init() - XzDecMt_FreeSt(p); - - p->outProcessed_Parse = 0; - p->parsing_Truncated = False; - - p->numStreams = 0; - p->numTotalBlocks = 0; - p->numBlocks = 0; - p->finishedDecoderIndex = -1; - - if (!p->mtc_WasConstructed) - { - p->mtc_WasConstructed = True; - MtDec_Construct(&p->mtc); - } - - p->mtc.mtCallback = &vt; - p->mtc.mtCallbackObject = p; - - p->mtc.progress = progress; - p->mtc.inStream = inStream; - p->mtc.alloc = &p->alignOffsetAlloc.vt; - // p->mtc.inData = inData; - // p->mtc.inDataSize = inDataSize; - p->mtc.inBufSize = p->props.inBufSize_MT; - // p->mtc.inBlockMax = p->props.inBlockMax; - p->mtc.numThreadsMax = p->props.numThreads; - - *isMT = True; - - vt.Parse = XzDecMt_Callback_Parse; - vt.PreCode = XzDecMt_Callback_PreCode; - vt.Code = XzDecMt_Callback_Code; - vt.Write = XzDecMt_Callback_Write; - - - res = MtDec_Code(&p->mtc); - - - stat->InSize = p->mtc.inProcessed; - - p->inProcessed = p->mtc.inProcessed; - p->readRes = p->mtc.readRes; - p->readWasFinished = p->mtc.readWasFinished; - p->readProcessed = p->mtc.readProcessed; - - tMode = True; - needContinue = False; - - if (res == SZ_OK) - { - if (p->mtc.mtProgress.res != SZ_OK) - { - res = p->mtc.mtProgress.res; - stat->ProgressRes = res; - stat->CombinedRes_Type = SZ_ERROR_PROGRESS; - } - else - needContinue = p->mtc.needContinue; - } - - if (!needContinue) - { - { - SRes codeRes; - BoolInt truncated = False; - ECoderStatus status; - const CXzUnpacker *dec; - - stat->OutSize = p->outProcessed; - - if (p->finishedDecoderIndex >= 0) - { - const CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex]; - codeRes = coder->codeRes; - dec = &coder->dec; - status = coder->status; - } - else if (p->mainDecoderWasCalled) - { - codeRes = p->codeRes; - dec = &p->dec; - status = p->status; - truncated = p->parsing_Truncated; - } - else - return SZ_ERROR_FAIL; - - if (p->mainErrorCode != SZ_OK) - stat->DecodeRes = p->mainErrorCode; - - XzStatInfo_SetStat(dec, p->finishMode, - // p->mtc.readProcessed, - p->mtc.inProcessed, - codeRes, status, - truncated, - stat); - } - - if (res == SZ_OK) - { - stat->ReadRes = p->mtc.readRes; - - if (p->writeRes != SZ_OK) - { - res = p->writeRes; - stat->CombinedRes_Type = SZ_ERROR_WRITE; - } - else if (p->mtc.readRes != SZ_OK - // && p->mtc.inProcessed == p->mtc.readProcessed - && stat->DecodeRes == SZ_ERROR_INPUT_EOF) - { - res = p->mtc.readRes; - stat->CombinedRes_Type = SZ_ERROR_READ; - } - else if (stat->DecodeRes != SZ_OK) - res = stat->DecodeRes; - } - - stat->CombinedRes = res; - if (stat->CombinedRes_Type == SZ_OK) - stat->CombinedRes_Type = res; - return res; - } - - PRF_STR("----- decoding ST -----") - } - - #endif - - - *isMT = False; - - { - SRes res = XzDecMt_Decode_ST(p - #ifndef Z7_ST - , tMode - #endif - , stat - ); - - #ifndef Z7_ST - // we must set error code from MT decoding at first - if (p->mainErrorCode != SZ_OK) - stat->DecodeRes = p->mainErrorCode; - #endif - - XzStatInfo_SetStat(&p->dec, - p->finishMode, - // p->readProcessed, - p->inProcessed, - p->codeRes, p->status, - False, // truncated - stat); - - stat->ReadRes = p->readRes; - - if (res == SZ_OK) - { - if (p->readRes != SZ_OK - // && p->inProcessed == p->readProcessed - && stat->DecodeRes == SZ_ERROR_INPUT_EOF) - { - // we set read error as combined error, only if that error was the reason - // of decoding problem - res = p->readRes; - stat->CombinedRes_Type = SZ_ERROR_READ; - } - else if (stat->DecodeRes != SZ_OK) - res = stat->DecodeRes; - } - - stat->CombinedRes = res; - if (stat->CombinedRes_Type == SZ_OK) - stat->CombinedRes_Type = res; - return res; - } -} - -#undef PRF -#undef PRF_STR -#undef PRF_STR_INT_2 +/* XzDec.c -- Xz Decode +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +// #include + +// #define XZ_DUMP + +/* #define XZ_DUMP */ + +#ifdef XZ_DUMP +#include +#endif + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define PRF_STR(s) PRF(printf("\n" s "\n")) +#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d)) + +#include +#include + +#include "7zCrc.h" +#include "Alloc.h" +#include "Bra.h" +#include "CpuArch.h" +#include "Delta.h" +#include "Lzma2Dec.h" + +// #define USE_SUBBLOCK + +#ifdef USE_SUBBLOCK +#include "Bcj3Dec.c" +#include "SbDec.h" +#endif + +#include "Xz.h" + +#define XZ_CHECK_SIZE_MAX 64 + +#define CODER_BUF_SIZE ((size_t)1 << 17) + +unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) +{ + unsigned i, limit; + *value = 0; + limit = (maxSize > 9) ? 9 : (unsigned)maxSize; + + for (i = 0; i < limit;) + { + Byte b = p[i]; + *value |= (UInt64)(b & 0x7F) << (7 * i++); + if ((b & 0x80) == 0) + return (b == 0 && i != 1) ? 0 : i; + } + return 0; +} + + +/* ---------- XzBcFilterState ---------- */ + +#define BRA_BUF_SIZE (1 << 14) + +typedef struct +{ + size_t bufPos; + size_t bufConv; + size_t bufTotal; + Byte *buf; // must be aligned for 4 bytes + Xz_Func_BcFilterStateBase_Filter filter_func; + // int encodeMode; + CXzBcFilterStateBase base; + // Byte buf[BRA_BUF_SIZE]; +} CXzBcFilterState; + + +static void XzBcFilterState_Free(void *pp, ISzAllocPtr alloc) +{ + if (pp) + { + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + ISzAlloc_Free(alloc, p->buf); + ISzAlloc_Free(alloc, pp); + } +} + + +static SRes XzBcFilterState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + CXzBcFilterStateBase *p = &((CXzBcFilterState *)pp)->base; + UNUSED_VAR(alloc) + p->ip = 0; + if (p->methodId == XZ_ID_Delta) + { + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + p->delta = (UInt32)props[0] + 1; + } + else + { + if (propSize == 4) + { + const UInt32 v = GetUi32(props); + switch (p->methodId) + { + case XZ_ID_PPC: + case XZ_ID_ARM: + case XZ_ID_SPARC: + case XZ_ID_ARM64: + if (v & 3) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_ARMT: + case XZ_ID_RISCV: + if (v & 1) + return SZ_ERROR_UNSUPPORTED; + break; + case XZ_ID_IA64: + if (v & 0xf) + return SZ_ERROR_UNSUPPORTED; + break; + default: break; + } + p->ip = v; + } + else if (propSize != 0) + return SZ_ERROR_UNSUPPORTED; + } + return SZ_OK; +} + + +static void XzBcFilterState_Init(void *pp) +{ + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + p->bufPos = p->bufConv = p->bufTotal = 0; + p->base.X86_State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + if (p->base.methodId == XZ_ID_Delta) + Delta_Init(p->base.delta_State); +} + + +static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Dec[] = +{ + Z7_BRANCH_CONV_DEC_2 (BranchConv_PPC), + Z7_BRANCH_CONV_DEC_2 (BranchConv_IA64), + Z7_BRANCH_CONV_DEC_2 (BranchConv_ARM), + Z7_BRANCH_CONV_DEC_2 (BranchConv_ARMT), + Z7_BRANCH_CONV_DEC_2 (BranchConv_SPARC), + Z7_BRANCH_CONV_DEC_2 (BranchConv_ARM64), + Z7_BRANCH_CONV_DEC_2 (BranchConv_RISCV) +}; + +static SizeT XzBcFilterStateBase_Filter_Dec(CXzBcFilterStateBase *p, Byte *data, SizeT size) +{ + switch (p->methodId) + { + case XZ_ID_Delta: + Delta_Decode(p->delta_State, p->delta, data, size); + break; + case XZ_ID_X86: + size = (SizeT)(z7_BranchConvSt_X86_Dec(data, size, p->ip, &p->X86_State) - data); + break; + default: + if (p->methodId >= XZ_ID_PPC) + { + const UInt32 i = p->methodId - XZ_ID_PPC; + if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Dec)) + size = (SizeT)(g_Funcs_BranchConv_RISC_Dec[i](data, size, p->ip) - data); + } + break; + } + p->ip += (UInt32)size; + return size; +} + + +static SizeT XzBcFilterState_Filter(void *pp, Byte *data, SizeT size) +{ + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + return p->filter_func(&p->base, data, size); +} + + +static SRes XzBcFilterState_Code2(void *pp, + Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CXzBcFilterState *p = ((CXzBcFilterState *)pp); + SizeT destRem = *destLen; + SizeT srcRem = *srcLen; + UNUSED_VAR(finishMode) + + *destLen = 0; + *srcLen = 0; + // *wasFinished = False; + *status = CODER_STATUS_NOT_FINISHED; + + while (destRem != 0) + { + { + size_t size = p->bufConv - p->bufPos; + if (size) + { + if (size > destRem) + size = destRem; + memcpy(dest, p->buf + p->bufPos, size); + p->bufPos += size; + *destLen += size; + dest += size; + destRem -= size; + continue; + } + } + + p->bufTotal -= p->bufPos; + memmove(p->buf, p->buf + p->bufPos, p->bufTotal); + p->bufPos = 0; + p->bufConv = 0; + { + size_t size = BRA_BUF_SIZE - p->bufTotal; + if (size > srcRem) + size = srcRem; + memcpy(p->buf + p->bufTotal, src, size); + *srcLen += size; + src += size; + srcRem -= size; + p->bufTotal += size; + } + if (p->bufTotal == 0) + break; + + p->bufConv = p->filter_func(&p->base, p->buf, p->bufTotal); + + if (p->bufConv == 0) + { + if (!srcWasFinished) + break; + p->bufConv = p->bufTotal; + } + } + + if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + // *wasFinished = 1; + } + + return SZ_OK; +} + + +#define XZ_IS_SUPPORTED_FILTER_ID(id) \ + ((id) >= XZ_ID_Delta && (id) <= XZ_ID_RISCV) + +SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id, + Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc) +{ + CXzBcFilterState *decoder; + if (!XZ_IS_SUPPORTED_FILTER_ID(id)) + return SZ_ERROR_UNSUPPORTED; + decoder = (CXzBcFilterState *)p->p; + if (!decoder) + { + decoder = (CXzBcFilterState *)ISzAlloc_Alloc(alloc, sizeof(CXzBcFilterState)); + if (!decoder) + return SZ_ERROR_MEM; + decoder->buf = ISzAlloc_Alloc(alloc, BRA_BUF_SIZE); + if (!decoder->buf) + { + ISzAlloc_Free(alloc, decoder); + return SZ_ERROR_MEM; + } + p->p = decoder; + p->Free = XzBcFilterState_Free; + p->SetProps = XzBcFilterState_SetProps; + p->Init = XzBcFilterState_Init; + p->Code2 = XzBcFilterState_Code2; + p->Filter = XzBcFilterState_Filter; + decoder->filter_func = func; + } + decoder->base.methodId = (UInt32)id; + // decoder->encodeMode = encodeMode; + return SZ_OK; +} + + + +/* ---------- SbState ---------- */ + +#ifdef USE_SUBBLOCK + +static void SbState_Free(void *pp, ISzAllocPtr alloc) +{ + CSbDec *p = (CSbDec *)pp; + SbDec_Free(p); + ISzAlloc_Free(alloc, pp); +} + +static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + UNUSED_VAR(pp) + UNUSED_VAR(props) + UNUSED_VAR(alloc) + return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static void SbState_Init(void *pp) +{ + SbDec_Init((CSbDec *)pp); +} + +static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished + ECoderStatus *status) +{ + CSbDec *p = (CSbDec *)pp; + SRes res; + UNUSED_VAR(srcWasFinished) + p->dest = dest; + p->destLen = *destLen; + p->src = src; + p->srcLen = *srcLen; + p->finish = finishMode; /* change it */ + res = SbDec_Decode((CSbDec *)pp); + *destLen -= p->destLen; + *srcLen -= p->srcLen; + // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */ + *status = (*destLen == 0 && *srcLen == 0) ? + CODER_STATUS_FINISHED_WITH_MARK : + CODER_STATUS_NOT_FINISHED; + return res; +} + +static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc) +{ + CSbDec *decoder = (CSbDec *)p->p; + if (!decoder) + { + decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec)); + if (!decoder) + return SZ_ERROR_MEM; + p->p = decoder; + p->Free = SbState_Free; + p->SetProps = SbState_SetProps; + p->Init = SbState_Init; + p->Code2 = SbState_Code2; + p->Filter = NULL; + } + SbDec_Construct(decoder); + SbDec_SetAlloc(decoder, alloc); + return SZ_OK; +} + +#endif + + + +/* ---------- Lzma2 ---------- */ + +typedef struct +{ + CLzma2Dec decoder; + BoolInt outBufMode; +} CLzma2Dec_Spec; + + +static void Lzma2State_Free(void *pp, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + Lzma2Dec_FreeProbs(&p->decoder, alloc); + else + Lzma2Dec_Free(&p->decoder, alloc); + ISzAlloc_Free(alloc, pp); +} + +static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc) +{ + if (propSize != 1) + return SZ_ERROR_UNSUPPORTED; + { + CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp; + if (p->outBufMode) + return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc); + else + return Lzma2Dec_Allocate(&p->decoder, props[0], alloc); + } +} + +static void Lzma2State_Init(void *pp) +{ + Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder); +} + + +/* + if (outBufMode), then (dest) is not used. Use NULL. + Data is unpacked to (spec->decoder.decoder.dic) output buffer. +*/ + +static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + int srcWasFinished, ECoderFinishMode finishMode, + // int *wasFinished, + ECoderStatus *status) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp; + ELzmaStatus status2; + /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ + SRes res; + UNUSED_VAR(srcWasFinished) + if (spec->outBufMode) + { + SizeT dicPos = spec->decoder.decoder.dicPos; + SizeT dicLimit = dicPos + *destLen; + res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + *destLen = spec->decoder.decoder.dicPos - dicPos; + } + else + res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2); + // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK); + // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder + *status = (ECoderStatus)status2; + return res; +} + + +static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if (!spec) + { + spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec)); + if (!spec) + return SZ_ERROR_MEM; + p->p = spec; + p->Free = Lzma2State_Free; + p->SetProps = Lzma2State_SetProps; + p->Init = Lzma2State_Init; + p->Code2 = Lzma2State_Code2; + p->Filter = NULL; + Lzma2Dec_CONSTRUCT(&spec->decoder) + } + spec->outBufMode = False; + if (outBuf) + { + spec->outBufMode = True; + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + +static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize) +{ + CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p; + if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf)) + return SZ_ERROR_FAIL; + if (outBuf) + { + spec->decoder.decoder.dic = outBuf; + spec->decoder.decoder.dicBufSize = outBufSize; + } + return SZ_OK; +} + + + +static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc) +{ + unsigned i; + p->alloc = alloc; + p->buf = NULL; + p->numCoders = 0; + + p->outBufSize = 0; + p->outBuf = NULL; + // p->SingleBufMode = False; + + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + p->coders[i].p = NULL; +} + + +static void MixCoder_Free(CMixCoder *p) +{ + unsigned i; + p->numCoders = 0; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) + { + IStateCoder *sc = &p->coders[i]; + if (sc->p) + { + sc->Free(sc->p, p->alloc); + sc->p = NULL; + } + } + if (p->buf) + { + ISzAlloc_Free(p->alloc, p->buf); + p->buf = NULL; /* 9.31: the BUG was fixed */ + } +} + +static void MixCoder_Init(CMixCoder *p) +{ + unsigned i; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) + { + p->size[i] = 0; + p->pos[i] = 0; + p->finished[i] = 0; + } + for (i = 0; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + coder->Init(coder->p); + p->results[i] = SZ_OK; + } + p->outWritten = 0; + p->wasFinished = False; + p->res = SZ_OK; + p->status = CODER_STATUS_NOT_SPECIFIED; +} + + +static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + p->ids[coderIndex] = methodId; + if (methodId == XZ_ID_LZMA2) + return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc); +#ifdef USE_SUBBLOCK + if (methodId == XZ_ID_Subblock) + return SbState_SetFromMethod(sc, p->alloc); +#endif + if (coderIndex == 0) + return SZ_ERROR_UNSUPPORTED; + return Xz_StateCoder_Bc_SetFromMethod_Func(sc, methodId, + XzBcFilterStateBase_Filter_Dec, p->alloc); +} + + +static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize) +{ + IStateCoder *sc = &p->coders[coderIndex]; + if (methodId == XZ_ID_LZMA2) + return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize); + return SZ_ERROR_UNSUPPORTED; +} + + + +/* + if (destFinish) - then unpack data block is finished at (*destLen) position, + and we can return data that were not processed by filter + +output (status) can be : + CODER_STATUS_NOT_FINISHED + CODER_STATUS_FINISHED_WITH_MARK + CODER_STATUS_NEEDS_MORE_INPUT - not implemented still +*/ + +static SRes MixCoder_Code(CMixCoder *p, + Byte *dest, SizeT *destLen, int destFinish, + const Byte *src, SizeT *srcLen, int srcWasFinished, + ECoderFinishMode finishMode) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + + *destLen = 0; + *srcLen = 0; + + if (p->wasFinished) + return p->res; + + p->status = CODER_STATUS_NOT_FINISHED; + + // if (p->SingleBufMode) + if (p->outBuf) + { + SRes res; + SizeT destLen2, srcLen2; + int wasFinished; + + PRF_STR("------- MixCoder Single ----------") + + srcLen2 = srcLenOrig; + destLen2 = destLenOrig; + + { + IStateCoder *coder = &p->coders[0]; + res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode, + // &wasFinished, + &p->status); + wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK); + } + + p->res = res; + + /* + if (wasFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + else + { + if (res == SZ_OK) + if (destLen2 != destLenOrig) + p->status = CODER_STATUS_NEEDS_MORE_INPUT; + } + */ + + + *srcLen = srcLen2; + src += srcLen2; + p->outWritten += destLen2; + + if (res != SZ_OK || srcWasFinished || wasFinished) + p->wasFinished = True; + + if (p->numCoders == 1) + *destLen = destLen2; + else if (p->wasFinished) + { + unsigned i; + size_t processed = p->outWritten; + + for (i = 1; i < p->numCoders; i++) + { + IStateCoder *coder = &p->coders[i]; + processed = coder->Filter(coder->p, p->outBuf, processed); + if (wasFinished || (destFinish && p->outWritten == destLenOrig)) + processed = p->outWritten; + PRF_STR_INT("filter", i) + } + *destLen = processed; + } + return res; + } + + PRF_STR("standard mix") + + if (p->numCoders != 1) + { + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); + if (!p->buf) + return SZ_ERROR_MEM; + } + + finishMode = CODER_FINISH_ANY; + } + + for (;;) + { + BoolInt processed = False; + BoolInt allFinished = True; + SRes resMain = SZ_OK; + unsigned i; + + p->status = CODER_STATUS_NOT_FINISHED; + /* + if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) + break; + */ + + for (i = 0; i < p->numCoders; i++) + { + SRes res; + IStateCoder *coder = &p->coders[i]; + Byte *dest2; + SizeT destLen2, srcLen2; // destLen2_Orig; + const Byte *src2; + int srcFinished2; + int encodingWasFinished; + ECoderStatus status2; + + if (i == 0) + { + src2 = src; + srcLen2 = srcLenOrig - *srcLen; + srcFinished2 = srcWasFinished; + } + else + { + size_t k = i - 1; + src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k]; + srcLen2 = p->size[k] - p->pos[k]; + srcFinished2 = p->finished[k]; + } + + if (i == p->numCoders - 1) + { + dest2 = dest; + destLen2 = destLenOrig - *destLen; + } + else + { + if (p->pos[i] != p->size[i]) + continue; + dest2 = p->buf + (CODER_BUF_SIZE * i); + destLen2 = CODER_BUF_SIZE; + } + + // destLen2_Orig = destLen2; + + if (p->results[i] != SZ_OK) + { + if (resMain == SZ_OK) + resMain = p->results[i]; + continue; + } + + res = coder->Code2(coder->p, + dest2, &destLen2, + src2, &srcLen2, srcFinished2, + finishMode, + // &encodingWasFinished, + &status2); + + if (res != SZ_OK) + { + p->results[i] = res; + if (resMain == SZ_OK) + resMain = res; + } + + encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK); + + if (!encodingWasFinished) + { + allFinished = False; + if (p->numCoders == 1 && res == SZ_OK) + p->status = status2; + } + + if (i == 0) + { + *srcLen += srcLen2; + src += srcLen2; + } + else + p->pos[(size_t)i - 1] += srcLen2; + + if (i == p->numCoders - 1) + { + *destLen += destLen2; + dest += destLen2; + } + else + { + p->size[i] = destLen2; + p->pos[i] = 0; + p->finished[i] = encodingWasFinished; + } + + if (destLen2 != 0 || srcLen2 != 0) + processed = True; + } + + if (!processed) + { + if (allFinished) + p->status = CODER_STATUS_FINISHED_WITH_MARK; + return resMain; + } + } +} + + +SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf) +{ + *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE); + if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) != + GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE)) + return SZ_ERROR_NO_ARCHIVE; + return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED; +} + +static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf) +{ + return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) + && GetUi32(buf) == CrcCalc(buf + 4, 6) + && flags == GetBe16(buf + 8) + && buf[10] == XZ_FOOTER_SIG_0 + && buf[11] == XZ_FOOTER_SIG_1; +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; \ + pos += s; } + + +static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p) +{ + const unsigned numFilters = XzBlock_GetNumFilters(p) - 1; + unsigned i; + { + const CXzFilter *f = &p->filters[numFilters]; + if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40) + return False; + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + if (f->id == XZ_ID_Delta) + { + if (f->propsSize != 1) + return False; + } + else if (!XZ_IS_SUPPORTED_FILTER_ID(f->id) + || (f->propsSize != 0 && f->propsSize != 4)) + return False; + } + return True; +} + + +SRes XzBlock_Parse(CXzBlock *p, const Byte *header) +{ + unsigned pos; + unsigned numFilters, i; + unsigned headerSize = (unsigned)header[0] << 2; + + /* (headerSize != 0) : another code checks */ + + if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) + return SZ_ERROR_ARCHIVE; + + pos = 1; + p->flags = header[pos++]; + + p->packSize = (UInt64)(Int64)-1; + if (XzBlock_HasPackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize) + if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63) + return SZ_ERROR_ARCHIVE; + } + + p->unpackSize = (UInt64)(Int64)-1; + if (XzBlock_HasUnpackSize(p)) + { + READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize) + } + + numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) + { + CXzFilter *filter = p->filters + i; + UInt64 size; + READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id) + READ_VARINT_AND_CHECK(header, pos, headerSize, &size) + if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX) + return SZ_ERROR_ARCHIVE; + filter->propsSize = (UInt32)size; + memcpy(filter->props, header + pos, (size_t)size); + pos += (unsigned)size; + + #ifdef XZ_DUMP + printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); + { + unsigned i; + for (i = 0; i < size; i++) + printf(" %2X", filter->props[i]); + } + #endif + } + + if (XzBlock_HasUnsupportedFlags(p)) + return SZ_ERROR_UNSUPPORTED; + + while (pos < headerSize) + if (header[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return SZ_OK; +} + + + + +static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize) +{ + unsigned i; + BoolInt needReInit = True; + unsigned numFilters = XzBlock_GetNumFilters(block); + + if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf))) + { + needReInit = False; + for (i = 0; i < numFilters; i++) + if (p->ids[i] != block->filters[numFilters - 1 - i].id) + { + needReInit = True; + break; + } + } + + // p->SingleBufMode = (outBuf != NULL); + p->outBuf = outBuf; + p->outBufSize = outBufSize; + + // p->SingleBufMode = False; + // outBuf = NULL; + + if (needReInit) + { + MixCoder_Free(p); + for (i = 0; i < numFilters; i++) + { + RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize)) + } + p->numCoders = numFilters; + } + else + { + RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize)) + } + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &block->filters[numFilters - 1 - i]; + IStateCoder *sc = &p->coders[i]; + RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)) + } + + MixCoder_Init(p); + return SZ_OK; +} + + + +void XzUnpacker_Init(CXzUnpacker *p) +{ + p->state = XZ_STATE_STREAM_HEADER; + p->pos = 0; + p->numStartedStreams = 0; + p->numFinishedStreams = 0; + p->numTotalBlocks = 0; + p->padSize = 0; + p->decodeOnlyOneBlock = 0; + + p->parseMode = False; + p->decodeToStreamSignature = False; + + // p->outBuf = NULL; + // p->outBufSize = 0; + p->outDataWritten = 0; +} + + +void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize) +{ + p->outBuf = outBuf; + p->outBufSize = outBufSize; +} + + +void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc) +{ + MixCoder_Construct(&p->decoder, alloc); + p->outBuf = NULL; + p->outBufSize = 0; + XzUnpacker_Init(p); +} + + +void XzUnpacker_Free(CXzUnpacker *p) +{ + MixCoder_Free(&p->decoder); +} + + +void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p) +{ + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + p->decodeOnlyOneBlock = 1; +} + + +static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize) +{ + Byte temp[32]; + unsigned num = Xz_WriteVarInt(temp, packSize); + num += Xz_WriteVarInt(temp + num, unpackSize); + Sha256_Update(&p->sha, temp, num); + p->indexSize += num; + p->numBlocks++; +} + + + +SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, int srcFinished, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + SizeT destLenOrig = *destLen; + SizeT srcLenOrig = *srcLen; + *destLen = 0; + *srcLen = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + for (;;) + { + SizeT srcRem; + + if (p->state == XZ_STATE_BLOCK) + { + SizeT destLen2 = destLenOrig - *destLen; + SizeT srcLen2 = srcLenOrig - *srcLen; + SRes res; + + ECoderFinishMode finishMode2 = finishMode; + BoolInt srcFinished2 = (BoolInt)srcFinished; + BoolInt destFinish = False; + + if (p->block.packSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.packSize - p->packSize; + if (srcLen2 >= rem) + { + srcFinished2 = True; + srcLen2 = (SizeT)rem; + } + if (rem == 0 && p->block.unpackSize == p->unpackSize) + return SZ_ERROR_DATA; + } + + if (p->block.unpackSize != (UInt64)(Int64)-1) + { + UInt64 rem = p->block.unpackSize - p->unpackSize; + if (destLen2 >= rem) + { + destFinish = True; + finishMode2 = CODER_FINISH_END; + destLen2 = (SizeT)rem; + } + } + + /* + if (srcLen2 == 0 && destLen2 == 0) + { + *status = CODER_STATUS_NOT_FINISHED; + return SZ_OK; + } + */ + + { + res = MixCoder_Code(&p->decoder, + (p->outBuf ? NULL : dest), &destLen2, destFinish, + src, &srcLen2, srcFinished2, + finishMode2); + + *status = p->decoder.status; + XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2); + if (!p->outBuf) + dest += destLen2; + p->outDataWritten += destLen2; + } + + (*srcLen) += srcLen2; + src += srcLen2; + p->packSize += srcLen2; + (*destLen) += destLen2; + p->unpackSize += destLen2; + + RINOK(res) + + if (*status != CODER_STATUS_FINISHED_WITH_MARK) + { + if (p->block.packSize == p->packSize + && *status == CODER_STATUS_NEEDS_MORE_INPUT) + { + PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT") + *status = CODER_STATUS_NOT_SPECIFIED; + return SZ_ERROR_DATA; + } + + return SZ_OK; + } + { + XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize); + p->state = XZ_STATE_BLOCK_FOOTER; + p->pos = 0; + p->alignPos = 0; + *status = CODER_STATUS_NOT_SPECIFIED; + + if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize) + || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize)) + { + PRF_STR("ERROR: block.size mismatch") + return SZ_ERROR_DATA; + } + } + // continue; + } + + srcRem = srcLenOrig - *srcLen; + + // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes + if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + switch ((int)p->state) + { + case XZ_STATE_STREAM_HEADER: + { + if (p->pos < XZ_STREAM_HEADER_SIZE) + { + if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos]) + return SZ_ERROR_NO_ARCHIVE; + if (p->decodeToStreamSignature) + return SZ_OK; + p->buf[p->pos++] = *src++; + (*srcLen)++; + } + else + { + RINOK(Xz_ParseHeader(&p->streamFlags, p->buf)) + p->numStartedStreams++; + p->indexSize = 0; + p->numBlocks = 0; + Sha256_Init(&p->sha); + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + } + break; + } + + case XZ_STATE_BLOCK_HEADER: + { + if (p->pos == 0) + { + p->buf[p->pos++] = *src++; + (*srcLen)++; + if (p->buf[0] == 0) + { + if (p->decodeOnlyOneBlock) + return SZ_ERROR_DATA; + p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks); + p->indexPos = p->indexPreSize; + p->indexSize += p->indexPreSize; + Sha256_Final(&p->sha, p->shaDigest); + Sha256_Init(&p->sha); + p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize); + p->state = XZ_STATE_STREAM_INDEX; + break; + } + p->blockHeaderSize = ((unsigned)p->buf[0] << 2) + 4; + break; + } + + if (p->pos != p->blockHeaderSize) + { + unsigned cur = p->blockHeaderSize - p->pos; + if (cur > srcRem) + cur = (unsigned)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + } + else + { + RINOK(XzBlock_Parse(&p->block, p->buf)) + if (!XzBlock_AreSupportedFilters(&p->block)) + return SZ_ERROR_UNSUPPORTED; + p->numTotalBlocks++; + p->state = XZ_STATE_BLOCK; + p->packSize = 0; + p->unpackSize = 0; + XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags)); + if (p->parseMode) + { + p->headerParsedOk = True; + return SZ_OK; + } + RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize)) + } + break; + } + + case XZ_STATE_BLOCK_FOOTER: + { + if ((((unsigned)p->packSize + p->alignPos) & 3) != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + (*srcLen)++; + p->alignPos++; + if (*src++ != 0) + return SZ_ERROR_CRC; + } + else + { + const unsigned checkSize = XzFlags_GetCheckSize(p->streamFlags); + unsigned cur = checkSize - p->pos; + if (cur != 0) + { + if (srcRem == 0) + { + *status = CODER_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (cur > srcRem) + cur = (unsigned)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (checkSize != p->pos) + break; + } + { + Byte digest[XZ_CHECK_SIZE_MAX]; + p->state = XZ_STATE_BLOCK_HEADER; + p->pos = 0; + if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0) + return SZ_ERROR_CRC; + if (p->decodeOnlyOneBlock) + { + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + } + } + } + break; + } + + case XZ_STATE_STREAM_INDEX: + { + if (p->pos < p->indexPreSize) + { + (*srcLen)++; + if (*src++ != p->buf[p->pos++]) + return SZ_ERROR_CRC; + } + else + { + if (p->indexPos < p->indexSize) + { + UInt64 cur = p->indexSize - p->indexPos; + if (srcRem > cur) + srcRem = (SizeT)cur; + p->crc = CrcUpdate(p->crc, src, srcRem); + Sha256_Update(&p->sha, src, srcRem); + (*srcLen) += srcRem; + src += srcRem; + p->indexPos += srcRem; + } + else if ((p->indexPos & 3) != 0) + { + Byte b = *src++; + p->crc = CRC_UPDATE_BYTE(p->crc, b); + (*srcLen)++; + p->indexPos++; + p->indexSize++; + if (b != 0) + return SZ_ERROR_CRC; + } + else + { + Byte digest[SHA256_DIGEST_SIZE]; + p->state = XZ_STATE_STREAM_INDEX_CRC; + p->indexSize += 4; + p->pos = 0; + Sha256_Final(&p->sha, digest); + if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0) + return SZ_ERROR_CRC; + } + } + break; + } + + case XZ_STATE_STREAM_INDEX_CRC: + { + if (p->pos < 4) + { + (*srcLen)++; + p->buf[p->pos++] = *src++; + } + else + { + const Byte *ptr = p->buf; + p->state = XZ_STATE_STREAM_FOOTER; + p->pos = 0; + if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_FOOTER: + { + unsigned cur = XZ_STREAM_FOOTER_SIZE - p->pos; + if (cur > srcRem) + cur = (unsigned)srcRem; + memcpy(p->buf + p->pos, src, cur); + p->pos += cur; + (*srcLen) += cur; + src += cur; + if (p->pos == XZ_STREAM_FOOTER_SIZE) + { + p->state = XZ_STATE_STREAM_PADDING; + p->numFinishedStreams++; + p->padSize = 0; + if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf)) + return SZ_ERROR_CRC; + } + break; + } + + case XZ_STATE_STREAM_PADDING: + { + if (*src != 0) + { + if (((UInt32)p->padSize & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + p->pos = 0; + p->state = XZ_STATE_STREAM_HEADER; + } + else + { + (*srcLen)++; + src++; + p->padSize++; + } + break; + } + + case XZ_STATE_BLOCK: break; /* to disable GCC warning */ + + default: return SZ_ERROR_FAIL; + } + } + /* + if (p->state == XZ_STATE_FINISHED) + *status = CODER_STATUS_FINISHED_WITH_MARK; + return SZ_OK; + */ +} + + +SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, + ECoderFinishMode finishMode, ECoderStatus *status) +{ + XzUnpacker_Init(p); + XzUnpacker_SetOutBuf(p, dest, *destLen); + + return XzUnpacker_Code(p, + NULL, destLen, + src, srcLen, True, + finishMode, status); +} + + +BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0); +} + +BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p) +{ + return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0); +} + +UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p) +{ + UInt64 num = 0; + if (p->state == XZ_STATE_STREAM_PADDING) + num = p->padSize; + else if (p->state == XZ_STATE_STREAM_HEADER) + num = p->padSize + p->pos; + return num; +} + + + + + + + + + + + + + + + + + + + + + +#ifndef Z7_ST +#include "MtDec.h" +#endif + + +void XzDecMtProps_Init(CXzDecMtProps *p) +{ + p->inBufSize_ST = 1 << 18; + p->outStep_ST = 1 << 20; + p->ignoreErrors = False; + + #ifndef Z7_ST + p->numThreads = 1; + p->inBufSize_MT = 1 << 18; + p->memUseMax = sizeof(size_t) << 28; + #endif +} + + + +#ifndef Z7_ST + +/* ---------- CXzDecMtThread ---------- */ + +typedef struct +{ + Byte *outBuf; + size_t outBufSize; + size_t outPreSize; + size_t inPreSize; + size_t inPreHeaderSize; + size_t blockPackSize_for_Index; // including block header and checksum. + size_t blockPackTotal; // including stream header, block header and checksum. + size_t inCodeSize; + size_t outCodeSize; + ECoderStatus status; + SRes codeRes; + BoolInt skipMode; + // BoolInt finishedWithMark; + EMtDecParseState parseState; + BoolInt parsing_Truncated; + BoolInt atBlockHeader; + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + BoolInt dec_created; + CXzUnpacker dec; + + Byte mtPad[1 << 7]; +} CXzDecMtThread; + +#endif + + +/* ---------- CXzDecMt ---------- */ + +struct CXzDecMt +{ + CAlignOffsetAlloc alignOffsetAlloc; + ISzAllocPtr allocMid; + + CXzDecMtProps props; + size_t unpackBlockMaxSize; + + ISeqInStreamPtr inStream; + ISeqOutStreamPtr outStream; + ICompressProgressPtr progress; + + BoolInt finishMode; + BoolInt outSize_Defined; + UInt64 outSize; + + UInt64 outProcessed; + UInt64 inProcessed; + UInt64 readProcessed; + BoolInt readWasFinished; + SRes readRes; + SRes writeRes; + + Byte *outBuf; + size_t outBufSize; + Byte *inBuf; + size_t inBufSize; + + CXzUnpacker dec; + + ECoderStatus status; + SRes codeRes; + + #ifndef Z7_ST + BoolInt mainDecoderWasCalled; + // int statErrorDefined; + int finishedDecoderIndex; + + // global values that are used in Parse stage + CXzStreamFlags streamFlags; + // UInt64 numFinishedStreams + UInt64 numStreams; + UInt64 numTotalBlocks; + UInt64 numBlocks; + + // UInt64 numBadBlocks; + SRes mainErrorCode; // it's set to error code, if the size Code() output doesn't patch the size from Parsing stage + // it can be = SZ_ERROR_INPUT_EOF + // it can be = SZ_ERROR_DATA, in some another cases + BoolInt isBlockHeaderState_Parse; + BoolInt isBlockHeaderState_Write; + UInt64 outProcessed_Parse; + BoolInt parsing_Truncated; + + BoolInt mtc_WasConstructed; + CMtDec mtc; + CXzDecMtThread coders[MTDEC_THREADS_MAX]; + #endif +}; + + + +CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid) +{ + CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt)); + if (!p) + return NULL; + + AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc); + p->alignOffsetAlloc.baseAlloc = alloc; + p->alignOffsetAlloc.numAlignBits = 7; + p->alignOffsetAlloc.offset = 0; + + p->allocMid = allocMid; + + p->outBuf = NULL; + p->outBufSize = 0; + p->inBuf = NULL; + p->inBufSize = 0; + + XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt); + + p->unpackBlockMaxSize = 0; + + XzDecMtProps_Init(&p->props); + + #ifndef Z7_ST + p->mtc_WasConstructed = False; + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + coder->dec_created = False; + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + #endif + + return (CXzDecMtHandle)p; +} + + +#ifndef Z7_ST + +static void XzDecMt_FreeOutBufs(CXzDecMt *p) +{ + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CXzDecMtThread *coder = &p->coders[i]; + if (coder->outBuf) + { + ISzAlloc_Free(p->allocMid, coder->outBuf); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + } + p->unpackBlockMaxSize = 0; +} + +#endif + + + +static void XzDecMt_FreeSt(CXzDecMt *p) +{ + XzUnpacker_Free(&p->dec); + + if (p->outBuf) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBuf = NULL; + } + p->outBufSize = 0; + + if (p->inBuf) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBuf = NULL; + } + p->inBufSize = 0; +} + + +// #define GET_CXzDecMt_p CXzDecMt *p = pp; + +void XzDecMt_Destroy(CXzDecMtHandle p) +{ + // GET_CXzDecMt_p + + XzDecMt_FreeSt(p); + + #ifndef Z7_ST + + if (p->mtc_WasConstructed) + { + MtDec_Destruct(&p->mtc); + p->mtc_WasConstructed = False; + } + { + unsigned i; + for (i = 0; i < MTDEC_THREADS_MAX; i++) + { + CXzDecMtThread *t = &p->coders[i]; + if (t->dec_created) + { + // we don't need to free dict here + XzUnpacker_Free(&t->dec); + t->dec_created = False; + } + } + } + XzDecMt_FreeOutBufs(p); + + #endif + + ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p); +} + + + +#ifndef Z7_ST + +static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc) +{ + CXzDecMt *me = (CXzDecMt *)obj; + CXzDecMtThread *coder = &me->coders[coderIndex]; + size_t srcSize = cc->srcSize; + + cc->srcSize = 0; + cc->outPos = 0; + cc->state = MTDEC_PARSE_CONTINUE; + + cc->canCreateNewThread = True; + + if (cc->startCall) + { + coder->outPreSize = 0; + coder->inPreSize = 0; + coder->inPreHeaderSize = 0; + coder->parseState = MTDEC_PARSE_CONTINUE; + coder->parsing_Truncated = False; + coder->skipMode = False; + coder->codeRes = SZ_OK; + coder->status = CODER_STATUS_NOT_SPECIFIED; + coder->inCodeSize = 0; + coder->outCodeSize = 0; + + coder->numStreams = me->numStreams; + coder->numTotalBlocks = me->numTotalBlocks; + coder->numBlocks = me->numBlocks; + + if (!coder->dec_created) + { + XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt); + coder->dec_created = True; + } + + XzUnpacker_Init(&coder->dec); + + if (me->isBlockHeaderState_Parse) + { + coder->dec.streamFlags = me->streamFlags; + coder->atBlockHeader = True; + XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec); + } + else + { + coder->atBlockHeader = False; + me->isBlockHeaderState_Parse = True; + } + + coder->dec.numStartedStreams = me->numStreams; + coder->dec.numTotalBlocks = me->numTotalBlocks; + coder->dec.numBlocks = me->numBlocks; + } + + while (!coder->skipMode) + { + ECoderStatus status; + SRes res; + size_t srcSize2 = srcSize; + size_t destSize = (size_t)0 - 1; + + coder->dec.parseMode = True; + coder->dec.headerParsedOk = False; + + PRF_STR_INT("Parse", srcSize2) + + res = XzUnpacker_Code(&coder->dec, + NULL, &destSize, + cc->src, &srcSize2, cc->srcFinished, + CODER_FINISH_END, &status); + + // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2)); + + coder->codeRes = res; + coder->status = status; + cc->srcSize += srcSize2; + srcSize -= srcSize2; + coder->inPreHeaderSize += srcSize2; + coder->inPreSize = coder->inPreHeaderSize; + + if (res != SZ_OK) + { + cc->state = + coder->parseState = MTDEC_PARSE_END; + /* + if (res == SZ_ERROR_MEM) + return res; + return SZ_OK; + */ + return; // res; + } + + if (coder->dec.headerParsedOk) + { + const CXzBlock *block = &coder->dec.block; + if (XzBlock_HasUnpackSize(block) + // && block->unpackSize <= me->props.outBlockMax + && XzBlock_HasPackSize(block)) + { + { + if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax) + { + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + } + { + const UInt64 packSize = block->packSize; + const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); + const unsigned checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags); + const UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize; + // if (blockPackSum <= me->props.inBlockMax) + // unpackBlockMaxSize + { + coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize); + coder->blockPackTotal = (size_t)blockPackSum; + coder->outPreSize = (size_t)block->unpackSize; + coder->streamFlags = coder->dec.streamFlags; + me->streamFlags = coder->dec.streamFlags; + coder->skipMode = True; + break; + } + } + } + } + else + // if (coder->inPreSize <= me->props.inBlockMax) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = + coder->parseState = MTDEC_PARSE_END; + return; // SZ_OK; + } + cc->state = MTDEC_PARSE_OVERFLOW; + return; // SZ_OK; + } + + // ---------- skipMode ---------- + { + UInt64 rem = coder->blockPackTotal - coder->inPreSize; + size_t cur = srcSize; + if (cur > rem) + cur = (size_t)rem; + cc->srcSize += cur; + coder->inPreSize += cur; + srcSize -= cur; + + if (coder->inPreSize == coder->blockPackTotal) + { + if (srcSize == 0) + { + if (!cc->srcFinished) + return; // SZ_OK; + cc->state = MTDEC_PARSE_END; + } + else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block + cc->state = MTDEC_PARSE_END; + else + { + cc->state = MTDEC_PARSE_NEW; + + { + size_t blockMax = me->unpackBlockMaxSize; + if (blockMax < coder->outPreSize) + blockMax = coder->outPreSize; + { + UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2; + if (me->props.memUseMax < required) + cc->canCreateNewThread = False; + } + } + + if (me->outSize_Defined) + { + // next block can be zero size + const UInt64 rem2 = me->outSize - me->outProcessed_Parse; + if (rem2 < coder->outPreSize) + { + coder->parsing_Truncated = True; + cc->state = MTDEC_PARSE_END; + } + me->outProcessed_Parse += coder->outPreSize; + } + } + } + else if (cc->srcFinished) + cc->state = MTDEC_PARSE_END; + else + return; // SZ_OK; + + coder->parseState = cc->state; + cc->outPos = coder->outPreSize; + + me->numStreams = coder->dec.numStartedStreams; + me->numTotalBlocks = coder->dec.numTotalBlocks; + me->numBlocks = coder->dec.numBlocks + 1; + return; // SZ_OK; + } +} + + +static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + Byte *dest; + + if (!coder->dec.headerParsedOk) + return SZ_OK; + + dest = coder->outBuf; + + if (!dest || coder->outBufSize < coder->outPreSize) + { + if (dest) + { + ISzAlloc_Free(me->allocMid, dest); + coder->outBuf = NULL; + coder->outBufSize = 0; + } + { + size_t outPreSize = coder->outPreSize; + if (outPreSize == 0) + outPreSize = 1; + dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize); + } + if (!dest) + return SZ_ERROR_MEM; + coder->outBuf = dest; + coder->outBufSize = coder->outPreSize; + + if (coder->outBufSize > me->unpackBlockMaxSize) + me->unpackBlockMaxSize = coder->outBufSize; + } + + // return SZ_ERROR_MEM; + + XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize); + + { + SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize); + // res = SZ_ERROR_UNSUPPORTED; // to test + coder->codeRes = res; + if (res != SZ_OK) + { + // if (res == SZ_ERROR_MEM) return res; + if (me->props.ignoreErrors && res != SZ_ERROR_MEM) + return SZ_OK; + return res; + } + } + + return SZ_OK; +} + + +static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex, + const Byte *src, size_t srcSize, int srcFinished, + // int finished, int blockFinished, + UInt64 *inCodePos, UInt64 *outCodePos, int *stop) +{ + CXzDecMt *me = (CXzDecMt *)pp; + CXzDecMtThread *coder = &me->coders[coderIndex]; + + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + *stop = True; + + if (srcSize > coder->inPreSize - coder->inCodeSize) + return SZ_ERROR_FAIL; + + if (coder->inCodeSize < coder->inPreHeaderSize) + { + size_t step = coder->inPreHeaderSize - coder->inCodeSize; + if (step > srcSize) + step = srcSize; + src += step; + srcSize -= step; + coder->inCodeSize += step; + *inCodePos = coder->inCodeSize; + if (coder->inCodeSize < coder->inPreHeaderSize) + { + *stop = False; + return SZ_OK; + } + } + + if (!coder->dec.headerParsedOk) + return SZ_OK; + if (!coder->outBuf) + return SZ_OK; + + if (coder->codeRes == SZ_OK) + { + ECoderStatus status; + SRes res; + size_t srcProcessed = srcSize; + size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten; + + // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur)); + + res = XzUnpacker_Code(&coder->dec, + NULL, &outSizeCur, + src, &srcProcessed, srcFinished, + // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY, + CODER_FINISH_END, + &status); + + // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur)); + + coder->codeRes = res; + coder->status = status; + coder->inCodeSize += srcProcessed; + coder->outCodeSize = coder->dec.outDataWritten; + *inCodePos = coder->inCodeSize; + *outCodePos = coder->outCodeSize; + + if (res == SZ_OK) + { + if (srcProcessed == srcSize) + *stop = False; + return SZ_OK; + } + } + + if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM) + { + *inCodePos = coder->inPreSize; + *outCodePos = coder->outPreSize; + return SZ_OK; + } + return coder->codeRes; +} + + +#define XZDECMT_STREAM_WRITE_STEP (1 << 24) + +static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex, + BoolInt needWriteToStream, + const Byte *src, size_t srcSize, BoolInt isCross, + // int srcFinished, + BoolInt *needContinue, + BoolInt *canRecode) +{ + CXzDecMt *me = (CXzDecMt *)pp; + const CXzDecMtThread *coder = &me->coders[coderIndex]; + + // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize)); + + *needContinue = False; + *canRecode = True; + + if (!needWriteToStream) + return SZ_OK; + + if (!coder->dec.headerParsedOk || !coder->outBuf) + { + if (me->finishedDecoderIndex < 0) + me->finishedDecoderIndex = (int)coderIndex; + return SZ_OK; + } + + if (me->finishedDecoderIndex >= 0) + return SZ_OK; + + me->mtc.inProcessed += coder->inCodeSize; + + *canRecode = False; + + { + SRes res; + size_t size = coder->outCodeSize; + Byte *data = coder->outBuf; + + // we use in me->dec: sha, numBlocks, indexSize + + if (!me->isBlockHeaderState_Write) + { + XzUnpacker_PrepareToRandomBlockDecoding(&me->dec); + me->dec.decodeOnlyOneBlock = False; + me->dec.numStartedStreams = coder->dec.numStartedStreams; + me->dec.streamFlags = coder->streamFlags; + + me->isBlockHeaderState_Write = True; + } + + me->dec.numTotalBlocks = coder->dec.numTotalBlocks; + XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize); + + if (coder->outPreSize != size) + { + if (me->props.ignoreErrors) + { + memset(data + size, 0, coder->outPreSize - size); + size = coder->outPreSize; + } + // me->numBadBlocks++; + if (me->mainErrorCode == SZ_OK) + { + if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT) + me->mainErrorCode = SZ_ERROR_INPUT_EOF; + else + me->mainErrorCode = SZ_ERROR_DATA; + } + } + + if (me->writeRes != SZ_OK) + return me->writeRes; + + res = SZ_OK; + { + if (me->outSize_Defined) + { + const UInt64 rem = me->outSize - me->outProcessed; + if (size > rem) + size = (SizeT)rem; + } + + for (;;) + { + size_t cur = size; + size_t written; + if (cur > XZDECMT_STREAM_WRITE_STEP) + cur = XZDECMT_STREAM_WRITE_STEP; + + written = ISeqOutStream_Write(me->outStream, data, cur); + + // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written)); + + me->outProcessed += written; + if (written != cur) + { + me->writeRes = SZ_ERROR_WRITE; + res = me->writeRes; + break; + } + data += cur; + size -= cur; + // PRF_STR_INT("Written size =", size) + if (size == 0) + break; + res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0); + if (res != SZ_OK) + break; + } + } + + if (coder->codeRes != SZ_OK) + if (!me->props.ignoreErrors) + { + me->finishedDecoderIndex = (int)coderIndex; + return res; + } + + RINOK(res) + + if (coder->inPreSize != coder->inCodeSize + || coder->blockPackTotal != coder->inCodeSize) + { + me->finishedDecoderIndex = (int)coderIndex; + return SZ_OK; + } + + if (coder->parseState != MTDEC_PARSE_END) + { + *needContinue = True; + return SZ_OK; + } + } + + // (coder->state == MTDEC_PARSE_END) means that there are no other working threads + // so we can use mtc variables without lock + + PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed) + + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + { + CXzUnpacker *dec = &me->dec; + + PRF_STR_INT("PostSingle", srcSize) + + { + size_t srcProcessed = srcSize; + ECoderStatus status; + size_t outSizeCur = 0; + SRes res; + + // dec->decodeOnlyOneBlock = False; + dec->decodeToStreamSignature = True; + + me->mainDecoderWasCalled = True; + + if (coder->parsing_Truncated) + { + me->parsing_Truncated = True; + return SZ_OK; + } + + /* + We have processed all xz-blocks of stream, + And xz unpacker is at XZ_STATE_BLOCK_HEADER state, where + (src) is a pointer to xz-Index structure. + We finish reading of current xz-Stream, including Zero padding after xz-Stream. + We exit, if we reach extra byte (first byte of new-Stream or another data). + But we don't update input stream pointer for that new extra byte. + If extra byte is not correct first byte of xz-signature, + we have SZ_ERROR_NO_ARCHIVE error here. + */ + + res = XzUnpacker_Code(dec, + NULL, &outSizeCur, + src, &srcProcessed, + me->mtc.readWasFinished, // srcFinished + CODER_FINISH_END, // CODER_FINISH_ANY, + &status); + + // res = SZ_ERROR_ARCHIVE; // for failure test + + me->status = status; + me->codeRes = res; + + if (isCross) + me->mtc.crossStart += srcProcessed; + + me->mtc.inProcessed += srcProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + srcSize -= srcProcessed; + src += srcProcessed; + + if (res != SZ_OK) + { + return SZ_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + + if (!isCross) + { + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + if (srcSize != 0) + memcpy(crossBuf, src, srcSize); + me->mtc.crossStart = 0; + me->mtc.crossEnd = srcSize; + } + + PRF_STR_INT("XZ_STATE_STREAM_HEADER crossEnd = ", (unsigned)me->mtc.crossEnd) + + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT || srcSize != 0) + { + return SZ_ERROR_FAIL; + } + + if (me->mtc.readWasFinished) + { + return SZ_OK; + } + } + + { + size_t inPos; + size_t inLim; + // const Byte *inData; + UInt64 inProgressPrev = me->mtc.inProcessed; + + // XzDecMt_Prepare_InBuf_ST(p); + Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc); + if (!crossBuf) + return SZ_ERROR_MEM; + + inPos = 0; + inLim = 0; + + // inData = crossBuf; + + for (;;) + { + SizeT inProcessed; + SizeT outProcessed; + ECoderStatus status; + SRes res; + + if (inPos == inLim) + { + if (!me->mtc.readWasFinished) + { + inPos = 0; + inLim = me->mtc.inBufSize; + me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)crossBuf, &inLim); + me->mtc.readProcessed += inLim; + if (inLim == 0 || me->mtc.readRes != SZ_OK) + me->mtc.readWasFinished = True; + } + } + + inProcessed = inLim - inPos; + outProcessed = 0; + + res = XzUnpacker_Code(dec, + NULL, &outProcessed, + crossBuf + inPos, &inProcessed, + (inProcessed == 0), // srcFinished + CODER_FINISH_END, &status); + + me->codeRes = res; + me->status = status; + inPos += inProcessed; + me->mtc.inProcessed += inProcessed; + me->mtc.mtProgress.totalInSize = me->mtc.inProcessed; + + if (res != SZ_OK) + { + return SZ_OK; + // return res; + } + + if (dec->state == XZ_STATE_STREAM_HEADER) + { + *needContinue = True; + me->mtc.crossStart = inPos; + me->mtc.crossEnd = inLim; + me->isBlockHeaderState_Parse = False; + me->isBlockHeaderState_Write = False; + return SZ_OK; + } + + if (status != CODER_STATUS_NEEDS_MORE_INPUT) + return SZ_ERROR_FAIL; + + if (me->mtc.progress) + { + UInt64 inDelta = me->mtc.inProcessed - inProgressPrev; + if (inDelta >= (1 << 22)) + { + RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress)) + inProgressPrev = me->mtc.inProcessed; + } + } + if (me->mtc.readWasFinished) + return SZ_OK; + } + } + } +} + + +#endif + + + +void XzStatInfo_Clear(CXzStatInfo *p) +{ + p->InSize = 0; + p->OutSize = 0; + + p->NumStreams = 0; + p->NumBlocks = 0; + + p->UnpackSize_Defined = False; + + p->NumStreams_Defined = False; + p->NumBlocks_Defined = False; + + p->DataAfterEnd = False; + p->DecodingTruncated = False; + + p->DecodeRes = SZ_OK; + p->ReadRes = SZ_OK; + p->ProgressRes = SZ_OK; + + p->CombinedRes = SZ_OK; + p->CombinedRes_Type = SZ_OK; +} + + + +/* + XzDecMt_Decode_ST() can return SZ_OK or the following errors + - SZ_ERROR_MEM for memory allocation error + - error from XzUnpacker_Code() function + - SZ_ERROR_WRITE for ISeqOutStream::Write(). stat->CombinedRes_Type = SZ_ERROR_WRITE in that case + - ICompressProgress::Progress() error, stat->CombinedRes_Type = SZ_ERROR_PROGRESS. + But XzDecMt_Decode_ST() doesn't return ISeqInStream::Read() errors. + ISeqInStream::Read() result is set to p->readRes. + also it can set stat->CombinedRes_Type to SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. +*/ + +static SRes XzDecMt_Decode_ST(CXzDecMt *p + #ifndef Z7_ST + , BoolInt tMode + #endif + , CXzStatInfo *stat) +{ + size_t outPos; + size_t inPos, inLim; + const Byte *inData; + UInt64 inPrev, outPrev; + + CXzUnpacker *dec; + + #ifndef Z7_ST + if (tMode) + { + XzDecMt_FreeOutBufs(p); + tMode = (BoolInt)MtDec_PrepareRead(&p->mtc); + } + #endif + + if (!p->outBuf || p->outBufSize != p->props.outStep_ST) + { + ISzAlloc_Free(p->allocMid, p->outBuf); + p->outBufSize = 0; + p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST); + if (!p->outBuf) + return SZ_ERROR_MEM; + p->outBufSize = p->props.outStep_ST; + } + + if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST) + { + ISzAlloc_Free(p->allocMid, p->inBuf); + p->inBufSize = 0; + p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST); + if (!p->inBuf) + return SZ_ERROR_MEM; + p->inBufSize = p->props.inBufSize_ST; + } + + dec = &p->dec; + dec->decodeToStreamSignature = False; + // dec->decodeOnlyOneBlock = False; + + XzUnpacker_SetOutBuf(dec, NULL, 0); + + inPrev = p->inProcessed; + outPrev = p->outProcessed; + + inPos = 0; + inLim = 0; + inData = NULL; + outPos = 0; + + for (;;) + { + SizeT outSize; + BoolInt finished; + ECoderFinishMode finishMode; + SizeT inProcessed; + ECoderStatus status; + SRes res; + + SizeT outProcessed; + + + + if (inPos == inLim) + { + #ifndef Z7_ST + if (tMode) + { + inData = MtDec_Read(&p->mtc, &inLim); + inPos = 0; + if (inData) + continue; + tMode = False; + inLim = 0; + } + #endif + + if (!p->readWasFinished) + { + inPos = 0; + inLim = p->inBufSize; + inData = p->inBuf; + p->readRes = ISeqInStream_Read(p->inStream, (void *)p->inBuf, &inLim); + p->readProcessed += inLim; + if (inLim == 0 || p->readRes != SZ_OK) + p->readWasFinished = True; + } + } + + outSize = p->props.outStep_ST - outPos; + + finishMode = CODER_FINISH_ANY; + if (p->outSize_Defined) + { + const UInt64 rem = p->outSize - p->outProcessed; + if (outSize >= rem) + { + outSize = (SizeT)rem; + if (p->finishMode) + finishMode = CODER_FINISH_END; + } + } + + inProcessed = inLim - inPos; + outProcessed = outSize; + + res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed, + inData + inPos, &inProcessed, + (inPos == inLim), // srcFinished + finishMode, &status); + + p->codeRes = res; + p->status = status; + + inPos += inProcessed; + outPos += outProcessed; + p->inProcessed += inProcessed; + p->outProcessed += outProcessed; + + finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK); + + if (finished || outProcessed >= outSize) + if (outPos != 0) + { + const size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos); + // p->outProcessed += written; // 21.01: BUG fixed + if (written != outPos) + { + stat->CombinedRes_Type = SZ_ERROR_WRITE; + return SZ_ERROR_WRITE; + } + outPos = 0; + } + + if (p->progress && res == SZ_OK) + { + if (p->inProcessed - inPrev >= (1 << 22) || + p->outProcessed - outPrev >= (1 << 22)) + { + res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed); + if (res != SZ_OK) + { + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + stat->ProgressRes = res; + return res; + } + inPrev = p->inProcessed; + outPrev = p->outProcessed; + } + } + + if (finished) + { + // p->codeRes is preliminary error from XzUnpacker_Code. + // and it can be corrected later as final result + // so we return SZ_OK here instead of (res); + return SZ_OK; + // return res; + } + } +} + + + +/* +XzStatInfo_SetStat() transforms + CXzUnpacker return code and status to combined CXzStatInfo results. + it can convert SZ_OK to SZ_ERROR_INPUT_EOF + it can convert SZ_ERROR_NO_ARCHIVE to SZ_OK and (DataAfterEnd = 1) +*/ + +static void XzStatInfo_SetStat(const CXzUnpacker *dec, + int finishMode, + // UInt64 readProcessed, + UInt64 inProcessed, + SRes res, // it's result from CXzUnpacker unpacker + ECoderStatus status, + BoolInt decodingTruncated, + CXzStatInfo *stat) +{ + UInt64 extraSize; + + stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0); + stat->InSize = inProcessed; + stat->NumStreams = dec->numStartedStreams; + stat->NumBlocks = dec->numTotalBlocks; + + stat->UnpackSize_Defined = True; + stat->NumStreams_Defined = True; + stat->NumBlocks_Defined = True; + + extraSize = XzUnpacker_GetExtraSize(dec); + + if (res == SZ_OK) + { + if (status == CODER_STATUS_NEEDS_MORE_INPUT) + { + // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams + // any extra data is part of correct data + extraSize = 0; + // if xz stream was not finished, then we need more data + if (!XzUnpacker_IsStreamWasFinished(dec)) + res = SZ_ERROR_INPUT_EOF; + } + else + { + // CODER_STATUS_FINISHED_WITH_MARK is not possible for multi stream xz decoding + // so he we have (status == CODER_STATUS_NOT_FINISHED) + // if (status != CODER_STATUS_FINISHED_WITH_MARK) + if (!decodingTruncated || finishMode) + res = SZ_ERROR_DATA; + } + } + else if (res == SZ_ERROR_NO_ARCHIVE) + { + /* + SZ_ERROR_NO_ARCHIVE is possible for 2 states: + XZ_STATE_STREAM_HEADER - if bad signature or bad CRC + XZ_STATE_STREAM_PADDING - if non-zero padding data + extraSize and inProcessed don't include "bad" byte + */ + // if (inProcessed == extraSize), there was no any good xz stream header, and we keep error + if (inProcessed != extraSize) // if there were good xz streams before error + { + // if (extraSize != 0 || readProcessed != inProcessed) + { + // he we suppose that all xz streams were finsihed OK, and we have + // some extra data after all streams + stat->DataAfterEnd = True; + res = SZ_OK; + } + } + } + + if (stat->DecodeRes == SZ_OK) + stat->DecodeRes = res; + + stat->InSize -= extraSize; +} + + + +SRes XzDecMt_Decode(CXzDecMtHandle p, + const CXzDecMtProps *props, + const UInt64 *outDataSize, int finishMode, + ISeqOutStreamPtr outStream, + // Byte *outBuf, size_t *outBufSize, + ISeqInStreamPtr inStream, + // const Byte *inData, size_t inDataSize, + CXzStatInfo *stat, + int *isMT, + ICompressProgressPtr progress) +{ + // GET_CXzDecMt_p + #ifndef Z7_ST + BoolInt tMode; + #endif + + XzStatInfo_Clear(stat); + + p->props = *props; + + p->inStream = inStream; + p->outStream = outStream; + p->progress = progress; + // p->stat = stat; + + p->outSize = 0; + p->outSize_Defined = False; + if (outDataSize) + { + p->outSize_Defined = True; + p->outSize = *outDataSize; + } + + p->finishMode = (BoolInt)finishMode; + + // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test + + p->writeRes = SZ_OK; + p->outProcessed = 0; + p->inProcessed = 0; + p->readProcessed = 0; + p->readWasFinished = False; + p->readRes = SZ_OK; + + p->codeRes = SZ_OK; + p->status = CODER_STATUS_NOT_SPECIFIED; + + XzUnpacker_Init(&p->dec); + + *isMT = False; + + /* + p->outBuf = NULL; + p->outBufSize = 0; + if (!outStream) + { + p->outBuf = outBuf; + p->outBufSize = *outBufSize; + *outBufSize = 0; + } + */ + + + #ifndef Z7_ST + + p->isBlockHeaderState_Parse = False; + p->isBlockHeaderState_Write = False; + // p->numBadBlocks = 0; + p->mainErrorCode = SZ_OK; + p->mainDecoderWasCalled = False; + + tMode = False; + + if (p->props.numThreads > 1) + { + IMtDecCallback2 vt; + BoolInt needContinue; + SRes res; + // we just free ST buffers here + // but we still keep state variables, that was set in XzUnpacker_Init() + XzDecMt_FreeSt(p); + + p->outProcessed_Parse = 0; + p->parsing_Truncated = False; + + p->numStreams = 0; + p->numTotalBlocks = 0; + p->numBlocks = 0; + p->finishedDecoderIndex = -1; + + if (!p->mtc_WasConstructed) + { + p->mtc_WasConstructed = True; + MtDec_Construct(&p->mtc); + } + + p->mtc.mtCallback = &vt; + p->mtc.mtCallbackObject = p; + + p->mtc.progress = progress; + p->mtc.inStream = inStream; + p->mtc.alloc = &p->alignOffsetAlloc.vt; + // p->mtc.inData = inData; + // p->mtc.inDataSize = inDataSize; + p->mtc.inBufSize = p->props.inBufSize_MT; + // p->mtc.inBlockMax = p->props.inBlockMax; + p->mtc.numThreadsMax = p->props.numThreads; + + *isMT = True; + + vt.Parse = XzDecMt_Callback_Parse; + vt.PreCode = XzDecMt_Callback_PreCode; + vt.Code = XzDecMt_Callback_Code; + vt.Write = XzDecMt_Callback_Write; + + + res = MtDec_Code(&p->mtc); + + + stat->InSize = p->mtc.inProcessed; + + p->inProcessed = p->mtc.inProcessed; + p->readRes = p->mtc.readRes; + p->readWasFinished = p->mtc.readWasFinished; + p->readProcessed = p->mtc.readProcessed; + + tMode = True; + needContinue = False; + + if (res == SZ_OK) + { + if (p->mtc.mtProgress.res != SZ_OK) + { + res = p->mtc.mtProgress.res; + stat->ProgressRes = res; + stat->CombinedRes_Type = SZ_ERROR_PROGRESS; + } + else + needContinue = p->mtc.needContinue; + } + + if (!needContinue) + { + { + SRes codeRes; + BoolInt truncated = False; + ECoderStatus status; + const CXzUnpacker *dec; + + stat->OutSize = p->outProcessed; + + if (p->finishedDecoderIndex >= 0) + { + const CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex]; + codeRes = coder->codeRes; + dec = &coder->dec; + status = coder->status; + } + else if (p->mainDecoderWasCalled) + { + codeRes = p->codeRes; + dec = &p->dec; + status = p->status; + truncated = p->parsing_Truncated; + } + else + return SZ_ERROR_FAIL; + + if (p->mainErrorCode != SZ_OK) + stat->DecodeRes = p->mainErrorCode; + + XzStatInfo_SetStat(dec, p->finishMode, + // p->mtc.readProcessed, + p->mtc.inProcessed, + codeRes, status, + truncated, + stat); + } + + if (res == SZ_OK) + { + stat->ReadRes = p->mtc.readRes; + + if (p->writeRes != SZ_OK) + { + res = p->writeRes; + stat->CombinedRes_Type = SZ_ERROR_WRITE; + } + else if (p->mtc.readRes != SZ_OK + // && p->mtc.inProcessed == p->mtc.readProcessed + && stat->DecodeRes == SZ_ERROR_INPUT_EOF) + { + res = p->mtc.readRes; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + else if (stat->DecodeRes != SZ_OK) + res = stat->DecodeRes; + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } + + PRF_STR("----- decoding ST -----") + } + + #endif + + + *isMT = False; + + { + SRes res = XzDecMt_Decode_ST(p + #ifndef Z7_ST + , tMode + #endif + , stat + ); + + #ifndef Z7_ST + // we must set error code from MT decoding at first + if (p->mainErrorCode != SZ_OK) + stat->DecodeRes = p->mainErrorCode; + #endif + + XzStatInfo_SetStat(&p->dec, + p->finishMode, + // p->readProcessed, + p->inProcessed, + p->codeRes, p->status, + False, // truncated + stat); + + stat->ReadRes = p->readRes; + + if (res == SZ_OK) + { + if (p->readRes != SZ_OK + // && p->inProcessed == p->readProcessed + && stat->DecodeRes == SZ_ERROR_INPUT_EOF) + { + // we set read error as combined error, only if that error was the reason + // of decoding problem + res = p->readRes; + stat->CombinedRes_Type = SZ_ERROR_READ; + } + else if (stat->DecodeRes != SZ_OK) + res = stat->DecodeRes; + } + + stat->CombinedRes = res; + if (stat->CombinedRes_Type == SZ_OK) + stat->CombinedRes_Type = res; + return res; + } +} + +#undef PRF +#undef PRF_STR +#undef PRF_STR_INT_2 diff --git a/C/XzEnc.c b/C/XzEnc.c index 3bfa51cb2..c1affadfa 100644 --- a/C/XzEnc.c +++ b/C/XzEnc.c @@ -1,1368 +1,1368 @@ -/* XzEnc.c -- Xz Encode -2024-03-01 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include -#include - -#include "7zCrc.h" -#include "Bra.h" -#include "CpuArch.h" - -#ifdef USE_SUBBLOCK -#include "Bcj3Enc.c" -#include "SbFind.c" -#include "SbEnc.c" -#endif - -#include "XzEnc.h" - -// #define Z7_ST - -#ifndef Z7_ST -#include "MtCoder.h" -#else -#define MTCODER_THREADS_MAX 1 -#define MTCODER_BLOCKS_MAX 1 -#endif - -#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) - -#define XZ_CHECK_SIZE_MAX 64 -/* max pack size for LZMA2 block + pad4 + check_size: */ -#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + XZ_CHECK_SIZE_MAX) - -#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) - - -// #define XzBlock_ClearFlags(p) (p)->flags = 0; -#define XzBlock_ClearFlags_SetNumFilters(p, n) (p)->flags = (Byte)((n) - 1); -#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; -#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; - - -static SRes WriteBytes(ISeqOutStreamPtr s, const void *buf, size_t size) -{ - return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; -} - -static SRes WriteBytes_UpdateCrc(ISeqOutStreamPtr s, const void *buf, size_t size, UInt32 *crc) -{ - *crc = CrcUpdate(*crc, buf, size); - return WriteBytes(s, buf, size); -} - - -static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStreamPtr s) -{ - UInt32 crc; - Byte header[XZ_STREAM_HEADER_SIZE]; - memcpy(header, XZ_SIG, XZ_SIG_SIZE); - header[XZ_SIG_SIZE] = (Byte)(f >> 8); - header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); - crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); - SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc) - return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); -} - - -static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStreamPtr s) -{ - Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; - - unsigned pos = 1; - unsigned numFilters, i; - header[pos++] = p->flags; - - if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); - if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); - numFilters = XzBlock_GetNumFilters(p); - - for (i = 0; i < numFilters; i++) - { - const CXzFilter *f = &p->filters[i]; - pos += Xz_WriteVarInt(header + pos, f->id); - pos += Xz_WriteVarInt(header + pos, f->propsSize); - memcpy(header + pos, f->props, f->propsSize); - pos += f->propsSize; - } - - while ((pos & 3) != 0) - header[pos++] = 0; - - header[0] = (Byte)(pos >> 2); - SetUi32(header + pos, CrcCalc(header, pos)) - return WriteBytes(s, header, pos + 4); -} - - - - -typedef struct -{ - size_t numBlocks; - size_t size; - size_t allocated; - Byte *blocks; -} CXzEncIndex; - - -static void XzEncIndex_Construct(CXzEncIndex *p) -{ - p->numBlocks = 0; - p->size = 0; - p->allocated = 0; - p->blocks = NULL; -} - -static void XzEncIndex_Init(CXzEncIndex *p) -{ - p->numBlocks = 0; - p->size = 0; -} - -static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) -{ - if (p->blocks) - { - ISzAlloc_Free(alloc, p->blocks); - p->blocks = NULL; - } - p->numBlocks = 0; - p->size = 0; - p->allocated = 0; -} - - -static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) -{ - Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); - if (!blocks) - return SZ_ERROR_MEM; - if (p->size != 0) - memcpy(blocks, p->blocks, p->size); - if (p->blocks) - ISzAlloc_Free(alloc, p->blocks); - p->blocks = blocks; - p->allocated = newSize; - return SZ_OK; -} - - -static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) -{ - UInt64 pos; - { - Byte buf[32]; - unsigned pos2 = Xz_WriteVarInt(buf, totalSize); - pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); - pos = numBlocks * pos2; - } - - if (pos <= p->allocated - p->size) - return SZ_OK; - { - UInt64 newSize64 = p->size + pos; - size_t newSize = (size_t)newSize64; - if (newSize != newSize64) - return SZ_ERROR_MEM; - return XzEncIndex_ReAlloc(p, newSize, alloc); - } -} - - -static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) -{ - Byte buf[32]; - unsigned pos = Xz_WriteVarInt(buf, totalSize); - pos += Xz_WriteVarInt(buf + pos, unpackSize); - - if (pos > p->allocated - p->size) - { - size_t newSize = p->allocated * 2 + 16 * 2; - if (newSize < p->size + pos) - return SZ_ERROR_MEM; - RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)) - } - memcpy(p->blocks + p->size, buf, pos); - p->size += pos; - p->numBlocks++; - return SZ_OK; -} - - -static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStreamPtr s) -{ - Byte buf[32]; - UInt64 globalPos; - UInt32 crc = CRC_INIT_VAL; - unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); - - globalPos = pos; - buf[0] = 0; - RINOK(WriteBytes_UpdateCrc(s, buf, pos, &crc)) - RINOK(WriteBytes_UpdateCrc(s, p->blocks, p->size, &crc)) - globalPos += p->size; - - pos = XZ_GET_PAD_SIZE(globalPos); - buf[1] = 0; - buf[2] = 0; - buf[3] = 0; - globalPos += pos; - - crc = CrcUpdate(crc, buf + 4 - pos, pos); - SetUi32(buf + 4, CRC_GET_DIGEST(crc)) - - SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)) - buf[8 + 8] = (Byte)(flags >> 8); - buf[8 + 9] = (Byte)(flags & 0xFF); - SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)) - buf[8 + 10] = XZ_FOOTER_SIG_0; - buf[8 + 11] = XZ_FOOTER_SIG_1; - - return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); -} - - - -/* ---------- CSeqCheckInStream ---------- */ - -typedef struct -{ - ISeqInStream vt; - ISeqInStreamPtr realStream; - const Byte *data; - UInt64 limit; - UInt64 processed; - int realStreamFinished; - CXzCheck check; -} CSeqCheckInStream; - -static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) -{ - p->limit = (UInt64)(Int64)-1; - p->processed = 0; - p->realStreamFinished = 0; - XzCheck_Init(&p->check, checkMode); -} - -static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) -{ - XzCheck_Final(&p->check, digest); -} - -static SRes SeqCheckInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqCheckInStream) - size_t size2 = *size; - SRes res = SZ_OK; - - if (p->limit != (UInt64)(Int64)-1) - { - UInt64 rem = p->limit - p->processed; - if (size2 > rem) - size2 = (size_t)rem; - } - if (size2 != 0) - { - if (p->realStream) - { - res = ISeqInStream_Read(p->realStream, data, &size2); - p->realStreamFinished = (size2 == 0) ? 1 : 0; - } - else - memcpy(data, p->data + (size_t)p->processed, size2); - XzCheck_Update(&p->check, data, size2); - p->processed += size2; - } - *size = size2; - return res; -} - - -/* ---------- CSeqSizeOutStream ---------- */ - -typedef struct -{ - ISeqOutStream vt; - ISeqOutStreamPtr realStream; - Byte *outBuf; - size_t outBufLimit; - UInt64 processed; -} CSeqSizeOutStream; - -static size_t SeqSizeOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqSizeOutStream) - if (p->realStream) - size = ISeqOutStream_Write(p->realStream, data, size); - else - { - if (size > p->outBufLimit - (size_t)p->processed) - return 0; - memcpy(p->outBuf + (size_t)p->processed, data, size); - } - p->processed += size; - return size; -} - - -/* ---------- CSeqInFilter ---------- */ - -#define FILTER_BUF_SIZE (1 << 20) - -typedef struct -{ - ISeqInStream vt; - ISeqInStreamPtr realStream; - IStateCoder StateCoder; - Byte *buf; - size_t curPos; - size_t endPos; - int srcWasFinished; -} CSeqInFilter; - - -static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Enc[] = -{ - Z7_BRANCH_CONV_ENC_2 (BranchConv_PPC), - Z7_BRANCH_CONV_ENC_2 (BranchConv_IA64), - Z7_BRANCH_CONV_ENC_2 (BranchConv_ARM), - Z7_BRANCH_CONV_ENC_2 (BranchConv_ARMT), - Z7_BRANCH_CONV_ENC_2 (BranchConv_SPARC), - Z7_BRANCH_CONV_ENC_2 (BranchConv_ARM64), - Z7_BRANCH_CONV_ENC_2 (BranchConv_RISCV) -}; - -static SizeT XzBcFilterStateBase_Filter_Enc(CXzBcFilterStateBase *p, Byte *data, SizeT size) -{ - switch (p->methodId) - { - case XZ_ID_Delta: - Delta_Encode(p->delta_State, p->delta, data, size); - break; - case XZ_ID_X86: - size = (SizeT)(z7_BranchConvSt_X86_Enc(data, size, p->ip, &p->X86_State) - data); - break; - default: - if (p->methodId >= XZ_ID_PPC) - { - const UInt32 i = p->methodId - XZ_ID_PPC; - if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Enc)) - size = (SizeT)(g_Funcs_BranchConv_RISC_Enc[i](data, size, p->ip) - data); - } - break; - } - p->ip += (UInt32)size; - return size; -} - - -static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) -{ - if (!p->buf) - { - p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); - if (!p->buf) - return SZ_ERROR_MEM; - } - p->curPos = p->endPos = 0; - p->srcWasFinished = 0; - RINOK(Xz_StateCoder_Bc_SetFromMethod_Func(&p->StateCoder, props->id, XzBcFilterStateBase_Filter_Enc, alloc)) - RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)) - p->StateCoder.Init(p->StateCoder.p); - return SZ_OK; -} - - -static SRes SeqInFilter_Read(ISeqInStreamPtr pp, void *data, size_t *size) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInFilter) - const size_t sizeOriginal = *size; - if (sizeOriginal == 0) - return SZ_OK; - *size = 0; - - for (;;) - { - if (!p->srcWasFinished && p->curPos == p->endPos) - { - p->curPos = 0; - p->endPos = FILTER_BUF_SIZE; - RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)) - if (p->endPos == 0) - p->srcWasFinished = 1; - } - { - SizeT srcLen = p->endPos - p->curPos; - ECoderStatus status; - SRes res; - *size = sizeOriginal; - res = p->StateCoder.Code2(p->StateCoder.p, - (Byte *)data, size, - p->buf + p->curPos, &srcLen, - p->srcWasFinished, CODER_FINISH_ANY, - &status); - p->curPos += srcLen; - if (*size != 0 || srcLen == 0 || res != SZ_OK) - return res; - } - } -} - -static void SeqInFilter_Construct(CSeqInFilter *p) -{ - p->buf = NULL; - p->StateCoder.p = NULL; - p->vt.Read = SeqInFilter_Read; -} - -static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) -{ - if (p->StateCoder.p) - { - p->StateCoder.Free(p->StateCoder.p, alloc); - p->StateCoder.p = NULL; - } - if (p->buf) - { - ISzAlloc_Free(alloc, p->buf); - p->buf = NULL; - } -} - - -/* ---------- CSbEncInStream ---------- */ - -#ifdef USE_SUBBLOCK - -typedef struct -{ - ISeqInStream vt; - ISeqInStreamPtr inStream; - CSbEnc enc; -} CSbEncInStream; - -static SRes SbEncInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) -{ - CSbEncInStream *p = Z7_CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); - size_t sizeOriginal = *size; - if (sizeOriginal == 0) - return SZ_OK; - - for (;;) - { - if (p->enc.needRead && !p->enc.readWasFinished) - { - size_t processed = p->enc.needReadSizeMax; - RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)) - p->enc.readPos += processed; - if (processed == 0) - { - p->enc.readWasFinished = True; - p->enc.isFinalFinished = True; - } - p->enc.needRead = False; - } - - *size = sizeOriginal; - RINOK(SbEnc_Read(&p->enc, data, size)) - if (*size != 0 || !p->enc.needRead) - return SZ_OK; - } -} - -void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) -{ - SbEnc_Construct(&p->enc, alloc); - p->vt.Read = SbEncInStream_Read; -} - -SRes SbEncInStream_Init(CSbEncInStream *p) -{ - return SbEnc_Init(&p->enc); -} - -void SbEncInStream_Free(CSbEncInStream *p) -{ - SbEnc_Free(&p->enc); -} - -#endif - - - -/* ---------- CXzProps ---------- */ - - -void XzFilterProps_Init(CXzFilterProps *p) -{ - p->id = 0; - p->delta = 0; - p->ip = 0; - p->ipDefined = False; -} - -void XzProps_Init(CXzProps *p) -{ - p->checkId = XZ_CHECK_CRC32; - p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO; - p->numBlockThreads_Reduced = -1; - p->numBlockThreads_Max = -1; - p->numTotalThreads = -1; - p->reduceSize = (UInt64)(Int64)-1; - p->forceWriteSizesInHeader = 0; - // p->forceWriteSizesInHeader = 1; - - XzFilterProps_Init(&p->filterProps); - Lzma2EncProps_Init(&p->lzma2Props); -} - - -static void XzEncProps_Normalize_Fixed(CXzProps *p) -{ - UInt64 fileSize; - int t1, t1n, t2, t2r, t3; - { - CLzma2EncProps tp = p->lzma2Props; - if (tp.numTotalThreads <= 0) - tp.numTotalThreads = p->numTotalThreads; - Lzma2EncProps_Normalize(&tp); - t1n = tp.numTotalThreads; - } - - t1 = p->lzma2Props.numTotalThreads; - t2 = p->numBlockThreads_Max; - t3 = p->numTotalThreads; - - if (t2 > MTCODER_THREADS_MAX) - t2 = MTCODER_THREADS_MAX; - - if (t3 <= 0) - { - if (t2 <= 0) - t2 = 1; - t3 = t1n * t2; - } - else if (t2 <= 0) - { - t2 = t3 / t1n; - if (t2 == 0) - { - t1 = 1; - t2 = t3; - } - if (t2 > MTCODER_THREADS_MAX) - t2 = MTCODER_THREADS_MAX; - } - else if (t1 <= 0) - { - t1 = t3 / t2; - if (t1 == 0) - t1 = 1; - } - else - t3 = t1n * t2; - - p->lzma2Props.numTotalThreads = t1; - - t2r = t2; - - fileSize = p->reduceSize; - - if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) - p->lzma2Props.lzmaProps.reduceSize = p->blockSize; - - Lzma2EncProps_Normalize(&p->lzma2Props); - - t1 = p->lzma2Props.numTotalThreads; - - { - if (t2 > 1 && fileSize != (UInt64)(Int64)-1) - { - UInt64 numBlocks = fileSize / p->blockSize; - if (numBlocks * p->blockSize != fileSize) - numBlocks++; - if (numBlocks < (unsigned)t2) - { - t2r = (int)numBlocks; - if (t2r == 0) - t2r = 1; - t3 = t1 * t2r; - } - } - } - - p->numBlockThreads_Max = t2; - p->numBlockThreads_Reduced = t2r; - p->numTotalThreads = t3; -} - - -static void XzProps_Normalize(CXzProps *p) -{ - /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. - Lzma2Enc_SetProps() will normalize lzma2Props later. */ - - if (p->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID) - { - p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; - p->numBlockThreads_Reduced = 1; - p->numBlockThreads_Max = 1; - if (p->lzma2Props.numTotalThreads <= 0) - p->lzma2Props.numTotalThreads = p->numTotalThreads; - return; - } - else - { - CLzma2EncProps *lzma2 = &p->lzma2Props; - if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) - { - // xz-auto - p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; - - if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) - { - // if (xz-auto && lzma2-solid) - we use solid for both - p->blockSize = XZ_PROPS_BLOCK_SIZE_SOLID; - p->numBlockThreads_Reduced = 1; - p->numBlockThreads_Max = 1; - if (p->lzma2Props.numTotalThreads <= 0) - p->lzma2Props.numTotalThreads = p->numTotalThreads; - } - else - { - // if (xz-auto && (lzma2-auto || lzma2-fixed_) - // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block - CLzma2EncProps tp = p->lzma2Props; - if (tp.numTotalThreads <= 0) - tp.numTotalThreads = p->numTotalThreads; - - Lzma2EncProps_Normalize(&tp); - - p->blockSize = tp.blockSize; // fixed or solid - p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; - p->numBlockThreads_Max = tp.numBlockThreads_Max; - if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) - lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID - if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) - lzma2->lzmaProps.reduceSize = tp.blockSize; - lzma2->numBlockThreads_Reduced = 1; - lzma2->numBlockThreads_Max = 1; - return; - } - } - else - { - // xz-fixed - // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize - - p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; - { - UInt64 r = p->reduceSize; - if (r > p->blockSize || r == (UInt64)(Int64)-1) - r = p->blockSize; - lzma2->lzmaProps.reduceSize = r; - } - if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) - lzma2->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; - else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) - lzma2->blockSize = p->blockSize; - - XzEncProps_Normalize_Fixed(p); - } - } -} - - -/* ---------- CLzma2WithFilters ---------- */ - -typedef struct -{ - CLzma2EncHandle lzma2; - CSeqInFilter filter; - - #ifdef USE_SUBBLOCK - CSbEncInStream sb; - #endif -} CLzma2WithFilters; - - -static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) -{ - p->lzma2 = NULL; - SeqInFilter_Construct(&p->filter); - - #ifdef USE_SUBBLOCK - SbEncInStream_Construct(&p->sb, alloc); - #endif -} - - -static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) -{ - if (!p->lzma2) - { - p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); - if (!p->lzma2) - return SZ_ERROR_MEM; - } - return SZ_OK; -} - - -static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) -{ - #ifdef USE_SUBBLOCK - SbEncInStream_Free(&p->sb); - #endif - - SeqInFilter_Free(&p->filter, alloc); - if (p->lzma2) - { - Lzma2Enc_Destroy(p->lzma2); - p->lzma2 = NULL; - } -} - - -typedef struct -{ - UInt64 unpackSize; - UInt64 totalSize; - size_t headerSize; -} CXzEncBlockInfo; - - -static SRes Xz_CompressBlock( - CLzma2WithFilters *lzmaf, - - ISeqOutStreamPtr outStream, - Byte *outBufHeader, - Byte *outBufData, size_t outBufDataLimit, - - ISeqInStreamPtr inStream, - // UInt64 expectedSize, - const Byte *inBuf, // used if (!inStream) - size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored - - const CXzProps *props, - ICompressProgressPtr progress, - int *inStreamFinished, /* only for inStream version */ - CXzEncBlockInfo *blockSizes, - ISzAllocPtr alloc, - ISzAllocPtr allocBig) -{ - CSeqCheckInStream checkInStream; - CSeqSizeOutStream seqSizeOutStream; - CXzBlock block; - unsigned filterIndex = 0; - CXzFilter *filter = NULL; - const CXzFilterProps *fp = &props->filterProps; - if (fp->id == 0) - fp = NULL; - - *inStreamFinished = False; - - RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)) - - RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)) - - // XzBlock_ClearFlags(&block) - XzBlock_ClearFlags_SetNumFilters(&block, 1 + (fp ? 1 : 0)) - - if (fp) - { - filter = &block.filters[filterIndex++]; - filter->id = fp->id; - filter->propsSize = 0; - - if (fp->id == XZ_ID_Delta) - { - filter->props[0] = (Byte)(fp->delta - 1); - filter->propsSize = 1; - } - else if (fp->ipDefined) - { - Byte *ptr = filter->props; - SetUi32(ptr, fp->ip) - filter->propsSize = 4; - } - } - - { - CXzFilter *f = &block.filters[filterIndex++]; - f->id = XZ_ID_LZMA2; - f->propsSize = 1; - f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); - } - - seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; - seqSizeOutStream.realStream = outStream; - seqSizeOutStream.outBuf = outBufData; - seqSizeOutStream.outBufLimit = outBufDataLimit; - seqSizeOutStream.processed = 0; - - /* - if (expectedSize != (UInt64)(Int64)-1) - { - block.unpackSize = expectedSize; - if (props->blockSize != (UInt64)(Int64)-1) - if (expectedSize > props->blockSize) - block.unpackSize = props->blockSize; - XzBlock_SetHasUnpackSize(&block) - } - */ - - if (outStream) - { - RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)) - } - - checkInStream.vt.Read = SeqCheckInStream_Read; - SeqCheckInStream_Init(&checkInStream, props->checkId); - - checkInStream.realStream = inStream; - checkInStream.data = inBuf; - checkInStream.limit = props->blockSize; - if (!inStream) - checkInStream.limit = inBufSize; - - if (fp) - { - #ifdef USE_SUBBLOCK - if (fp->id == XZ_ID_Subblock) - { - lzmaf->sb.inStream = &checkInStream.vt; - RINOK(SbEncInStream_Init(&lzmaf->sb)) - } - else - #endif - { - lzmaf->filter.realStream = &checkInStream.vt; - RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)) - } - } - - { - SRes res; - Byte *outBuf = NULL; - size_t outSize = 0; - BoolInt useStream = (fp || inStream); - // useStream = True; - - if (!useStream) - { - XzCheck_Update(&checkInStream.check, inBuf, inBufSize); - checkInStream.processed = inBufSize; - } - - if (!outStream) - { - outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; - outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; - } - - res = Lzma2Enc_Encode2(lzmaf->lzma2, - outBuf ? NULL : &seqSizeOutStream.vt, - outBuf, - outBuf ? &outSize : NULL, - - useStream ? - (fp ? - ( - #ifdef USE_SUBBLOCK - (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: - #endif - &lzmaf->filter.vt) : - &checkInStream.vt) : NULL, - - useStream ? NULL : inBuf, - useStream ? 0 : inBufSize, - - progress); - - if (outBuf) - seqSizeOutStream.processed += outSize; - - RINOK(res) - blockSizes->unpackSize = checkInStream.processed; - } - { - Byte buf[4 + XZ_CHECK_SIZE_MAX]; - const unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); - const UInt64 packSize = seqSizeOutStream.processed; - - buf[0] = 0; - buf[1] = 0; - buf[2] = 0; - buf[3] = 0; - - SeqCheckInStream_GetDigest(&checkInStream, buf + 4); - RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), - padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))) - - blockSizes->totalSize = seqSizeOutStream.processed - padSize; - - if (!outStream) - { - seqSizeOutStream.outBuf = outBufHeader; - seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; - seqSizeOutStream.processed = 0; - - block.unpackSize = blockSizes->unpackSize; - XzBlock_SetHasUnpackSize(&block) - - block.packSize = packSize; - XzBlock_SetHasPackSize(&block) - - RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)) - - blockSizes->headerSize = (size_t)seqSizeOutStream.processed; - blockSizes->totalSize += seqSizeOutStream.processed; - } - } - - if (inStream) - *inStreamFinished = checkInStream.realStreamFinished; - else - { - *inStreamFinished = False; - if (checkInStream.processed != inBufSize) - return SZ_ERROR_FAIL; - } - - return SZ_OK; -} - - - -typedef struct -{ - ICompressProgress vt; - ICompressProgressPtr progress; - UInt64 inOffset; - UInt64 outOffset; -} CCompressProgress_XzEncOffset; - - -static SRes CompressProgress_XzEncOffset_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) -{ - const CCompressProgress_XzEncOffset *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CCompressProgress_XzEncOffset, vt); - inSize += p->inOffset; - outSize += p->outOffset; - return ICompressProgress_Progress(p->progress, inSize, outSize); -} - - - - -struct CXzEnc -{ - ISzAllocPtr alloc; - ISzAllocPtr allocBig; - - CXzProps xzProps; - UInt64 expectedDataSize; - - CXzEncIndex xzIndex; - - CLzma2WithFilters lzmaf_Items[MTCODER_THREADS_MAX]; - - size_t outBufSize; /* size of allocated outBufs[i] */ - Byte *outBufs[MTCODER_BLOCKS_MAX]; - - #ifndef Z7_ST - unsigned checkType; - ISeqOutStreamPtr outStream; - BoolInt mtCoder_WasConstructed; - CMtCoder mtCoder; - CXzEncBlockInfo EncBlocks[MTCODER_BLOCKS_MAX]; - #endif -}; - - -static void XzEnc_Construct(CXzEnc *p) -{ - unsigned i; - - XzEncIndex_Construct(&p->xzIndex); - - for (i = 0; i < MTCODER_THREADS_MAX; i++) - Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); - - #ifndef Z7_ST - p->mtCoder_WasConstructed = False; - { - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - p->outBufs[i] = NULL; - p->outBufSize = 0; - } - #endif -} - - -static void XzEnc_FreeOutBufs(CXzEnc *p) -{ - unsigned i; - for (i = 0; i < MTCODER_BLOCKS_MAX; i++) - if (p->outBufs[i]) - { - ISzAlloc_Free(p->alloc, p->outBufs[i]); - p->outBufs[i] = NULL; - } - p->outBufSize = 0; -} - - -static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) -{ - unsigned i; - - XzEncIndex_Free(&p->xzIndex, alloc); - - for (i = 0; i < MTCODER_THREADS_MAX; i++) - Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); - - #ifndef Z7_ST - if (p->mtCoder_WasConstructed) - { - MtCoder_Destruct(&p->mtCoder); - p->mtCoder_WasConstructed = False; - } - XzEnc_FreeOutBufs(p); - #endif -} - - -CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) -{ - CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); - if (!p) - return NULL; - XzEnc_Construct(p); - XzProps_Init(&p->xzProps); - XzProps_Normalize(&p->xzProps); - p->expectedDataSize = (UInt64)(Int64)-1; - p->alloc = alloc; - p->allocBig = allocBig; - return (CXzEncHandle)p; -} - -// #define GET_CXzEnc_p CXzEnc *p = (CXzEnc *)(void *)pp; - -void XzEnc_Destroy(CXzEncHandle p) -{ - // GET_CXzEnc_p - XzEnc_Free(p, p->alloc); - ISzAlloc_Free(p->alloc, p); -} - - -SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props) -{ - // GET_CXzEnc_p - p->xzProps = *props; - XzProps_Normalize(&p->xzProps); - return SZ_OK; -} - - -void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize) -{ - // GET_CXzEnc_p - p->expectedDataSize = expectedDataSiize; -} - - - - -#ifndef Z7_ST - -static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, - const Byte *src, size_t srcSize, int finished) -{ - CXzEnc *me = (CXzEnc *)pp; - SRes res; - CMtProgressThunk progressThunk; - Byte *dest; - UNUSED_VAR(finished) - { - CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; - bInfo->totalSize = 0; - bInfo->unpackSize = 0; - bInfo->headerSize = 0; - // v23.02: we don't compress empty blocks - // also we must ignore that empty block in XzEnc_MtCallback_Write() - if (srcSize == 0) - return SZ_OK; - } - dest = me->outBufs[outBufIndex]; - if (!dest) - { - dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); - if (!dest) - return SZ_ERROR_MEM; - me->outBufs[outBufIndex] = dest; - } - - MtProgressThunk_CreateVTable(&progressThunk); - progressThunk.mtProgress = &me->mtCoder.mtProgress; - MtProgressThunk_INIT(&progressThunk) - - { - CXzEncBlockInfo blockSizes; - int inStreamFinished; - - res = Xz_CompressBlock( - &me->lzmaf_Items[coderIndex], - - NULL, - dest, - dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, - - NULL, - // srcSize, // expectedSize - src, srcSize, - - &me->xzProps, - &progressThunk.vt, - &inStreamFinished, - &blockSizes, - me->alloc, - me->allocBig); - - if (res == SZ_OK) - me->EncBlocks[outBufIndex] = blockSizes; - - return res; - } -} - - -static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) -{ - CXzEnc *me = (CXzEnc *)pp; - const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; - // v23.02: we don't write empty blocks - // note: if (bInfo->unpackSize == 0) then there is no compressed data of block - if (bInfo->unpackSize == 0) - return SZ_OK; - { - const Byte *data = me->outBufs[outBufIndex]; - RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)) - { - const UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); - RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)) - } - return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); - } -} - -#endif - - - -SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress) -{ - // GET_CXzEnc_p - - const CXzProps *props = &p->xzProps; - - XzEncIndex_Init(&p->xzIndex); - { - UInt64 numBlocks = 1; - UInt64 blockSize = props->blockSize; - - if (blockSize != XZ_PROPS_BLOCK_SIZE_SOLID - && props->reduceSize != (UInt64)(Int64)-1) - { - numBlocks = props->reduceSize / blockSize; - if (numBlocks * blockSize != props->reduceSize) - numBlocks++; - } - else - blockSize = (UInt64)1 << 62; - - RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)) - } - - RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)) - - - #ifndef Z7_ST - if (props->numBlockThreads_Reduced > 1) - { - IMtCoderCallback2 vt; - - if (!p->mtCoder_WasConstructed) - { - p->mtCoder_WasConstructed = True; - MtCoder_Construct(&p->mtCoder); - } - - vt.Code = XzEnc_MtCallback_Code; - vt.Write = XzEnc_MtCallback_Write; - - p->checkType = props->checkId; - p->xzProps = *props; - - p->outStream = outStream; - - p->mtCoder.allocBig = p->allocBig; - p->mtCoder.progress = progress; - p->mtCoder.inStream = inStream; - p->mtCoder.inData = NULL; - p->mtCoder.inDataSize = 0; - p->mtCoder.mtCallback = &vt; - p->mtCoder.mtCallbackObject = p; - - if ( props->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID - || props->blockSize == XZ_PROPS_BLOCK_SIZE_AUTO) - return SZ_ERROR_FAIL; - - p->mtCoder.blockSize = (size_t)props->blockSize; - if (p->mtCoder.blockSize != props->blockSize) - return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ - - { - size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); - if (destBlockSize < p->mtCoder.blockSize) - return SZ_ERROR_PARAM; - if (p->outBufSize != destBlockSize) - XzEnc_FreeOutBufs(p); - p->outBufSize = destBlockSize; - } - - p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; - p->mtCoder.expectedDataSize = p->expectedDataSize; - - RINOK(MtCoder_Code(&p->mtCoder)) - } - else - #endif - { - int writeStartSizes; - CCompressProgress_XzEncOffset progress2; - Byte *bufData = NULL; - size_t bufSize = 0; - - progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; - progress2.inOffset = 0; - progress2.outOffset = 0; - progress2.progress = progress; - - writeStartSizes = 0; - - if (props->blockSize != XZ_PROPS_BLOCK_SIZE_SOLID) - { - writeStartSizes = (props->forceWriteSizesInHeader > 0); - - if (writeStartSizes) - { - size_t t2; - size_t t = (size_t)props->blockSize; - if (t != props->blockSize) - return SZ_ERROR_PARAM; - t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); - if (t < props->blockSize) - return SZ_ERROR_PARAM; - t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; - if (!p->outBufs[0] || t2 != p->outBufSize) - { - XzEnc_FreeOutBufs(p); - p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); - if (!p->outBufs[0]) - return SZ_ERROR_MEM; - p->outBufSize = t2; - } - bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; - bufSize = t; - } - } - - for (;;) - { - CXzEncBlockInfo blockSizes; - int inStreamFinished; - - /* - UInt64 rem = (UInt64)(Int64)-1; - if (props->reduceSize != (UInt64)(Int64)-1 - && props->reduceSize >= progress2.inOffset) - rem = props->reduceSize - progress2.inOffset; - */ - - blockSizes.headerSize = 0; // for GCC - - RINOK(Xz_CompressBlock( - &p->lzmaf_Items[0], - - writeStartSizes ? NULL : outStream, - writeStartSizes ? p->outBufs[0] : NULL, - bufData, bufSize, - - inStream, - // rem, - NULL, 0, - - props, - progress ? &progress2.vt : NULL, - &inStreamFinished, - &blockSizes, - p->alloc, - p->allocBig)) - - { - UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); - - if (writeStartSizes) - { - RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)) - RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)) - } - - RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)) - - progress2.inOffset += blockSizes.unpackSize; - progress2.outOffset += totalPackFull; - } - - if (inStreamFinished) - break; - } - } - - return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); -} - - -#include "Alloc.h" - -SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, - const CXzProps *props, ICompressProgressPtr progress) -{ - SRes res; - CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); - if (!xz) - return SZ_ERROR_MEM; - res = XzEnc_SetProps(xz, props); - if (res == SZ_OK) - res = XzEnc_Encode(xz, outStream, inStream, progress); - XzEnc_Destroy(xz); - return res; -} - - -SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream) -{ - SRes res; - CXzEncIndex xzIndex; - XzEncIndex_Construct(&xzIndex); - res = Xz_WriteHeader((CXzStreamFlags)0, outStream); - if (res == SZ_OK) - res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); - XzEncIndex_Free(&xzIndex, NULL); // g_Alloc - return res; -} +/* XzEnc.c -- Xz Encode +2024-03-01 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include +#include + +#include "7zCrc.h" +#include "Bra.h" +#include "CpuArch.h" + +#ifdef USE_SUBBLOCK +#include "Bcj3Enc.c" +#include "SbFind.c" +#include "SbEnc.c" +#endif + +#include "XzEnc.h" + +// #define Z7_ST + +#ifndef Z7_ST +#include "MtCoder.h" +#else +#define MTCODER_THREADS_MAX 1 +#define MTCODER_BLOCKS_MAX 1 +#endif + +#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) + +#define XZ_CHECK_SIZE_MAX 64 +/* max pack size for LZMA2 block + pad4 + check_size: */ +#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + XZ_CHECK_SIZE_MAX) + +#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) + + +// #define XzBlock_ClearFlags(p) (p)->flags = 0; +#define XzBlock_ClearFlags_SetNumFilters(p, n) (p)->flags = (Byte)((n) - 1); +#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; +#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; + + +static SRes WriteBytes(ISeqOutStreamPtr s, const void *buf, size_t size) +{ + return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; +} + +static SRes WriteBytes_UpdateCrc(ISeqOutStreamPtr s, const void *buf, size_t size, UInt32 *crc) +{ + *crc = CrcUpdate(*crc, buf, size); + return WriteBytes(s, buf, size); +} + + +static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStreamPtr s) +{ + UInt32 crc; + Byte header[XZ_STREAM_HEADER_SIZE]; + memcpy(header, XZ_SIG, XZ_SIG_SIZE); + header[XZ_SIG_SIZE] = (Byte)(f >> 8); + header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); + crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); + SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc) + return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); +} + + +static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStreamPtr s) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + + unsigned pos = 1; + unsigned numFilters, i; + header[pos++] = p->flags; + + if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); + if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); + numFilters = XzBlock_GetNumFilters(p); + + for (i = 0; i < numFilters; i++) + { + const CXzFilter *f = &p->filters[i]; + pos += Xz_WriteVarInt(header + pos, f->id); + pos += Xz_WriteVarInt(header + pos, f->propsSize); + memcpy(header + pos, f->props, f->propsSize); + pos += f->propsSize; + } + + while ((pos & 3) != 0) + header[pos++] = 0; + + header[0] = (Byte)(pos >> 2); + SetUi32(header + pos, CrcCalc(header, pos)) + return WriteBytes(s, header, pos + 4); +} + + + + +typedef struct +{ + size_t numBlocks; + size_t size; + size_t allocated; + Byte *blocks; +} CXzEncIndex; + + +static void XzEncIndex_Construct(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; + p->blocks = NULL; +} + +static void XzEncIndex_Init(CXzEncIndex *p) +{ + p->numBlocks = 0; + p->size = 0; +} + +static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) +{ + if (p->blocks) + { + ISzAlloc_Free(alloc, p->blocks); + p->blocks = NULL; + } + p->numBlocks = 0; + p->size = 0; + p->allocated = 0; +} + + +static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) +{ + Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); + if (!blocks) + return SZ_ERROR_MEM; + if (p->size != 0) + memcpy(blocks, p->blocks, p->size); + if (p->blocks) + ISzAlloc_Free(alloc, p->blocks); + p->blocks = blocks; + p->allocated = newSize; + return SZ_OK; +} + + +static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + UInt64 pos; + { + Byte buf[32]; + unsigned pos2 = Xz_WriteVarInt(buf, totalSize); + pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); + pos = numBlocks * pos2; + } + + if (pos <= p->allocated - p->size) + return SZ_OK; + { + UInt64 newSize64 = p->size + pos; + size_t newSize = (size_t)newSize64; + if (newSize != newSize64) + return SZ_ERROR_MEM; + return XzEncIndex_ReAlloc(p, newSize, alloc); + } +} + + +static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) +{ + Byte buf[32]; + unsigned pos = Xz_WriteVarInt(buf, totalSize); + pos += Xz_WriteVarInt(buf + pos, unpackSize); + + if (pos > p->allocated - p->size) + { + size_t newSize = p->allocated * 2 + 16 * 2; + if (newSize < p->size + pos) + return SZ_ERROR_MEM; + RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)) + } + memcpy(p->blocks + p->size, buf, pos); + p->size += pos; + p->numBlocks++; + return SZ_OK; +} + + +static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStreamPtr s) +{ + Byte buf[32]; + UInt64 globalPos; + UInt32 crc = CRC_INIT_VAL; + unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); + + globalPos = pos; + buf[0] = 0; + RINOK(WriteBytes_UpdateCrc(s, buf, pos, &crc)) + RINOK(WriteBytes_UpdateCrc(s, p->blocks, p->size, &crc)) + globalPos += p->size; + + pos = XZ_GET_PAD_SIZE(globalPos); + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + globalPos += pos; + + crc = CrcUpdate(crc, buf + 4 - pos, pos); + SetUi32(buf + 4, CRC_GET_DIGEST(crc)) + + SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)) + buf[8 + 8] = (Byte)(flags >> 8); + buf[8 + 9] = (Byte)(flags & 0xFF); + SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)) + buf[8 + 10] = XZ_FOOTER_SIG_0; + buf[8 + 11] = XZ_FOOTER_SIG_1; + + return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); +} + + + +/* ---------- CSeqCheckInStream ---------- */ + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr realStream; + const Byte *data; + UInt64 limit; + UInt64 processed; + int realStreamFinished; + CXzCheck check; +} CSeqCheckInStream; + +static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) +{ + p->limit = (UInt64)(Int64)-1; + p->processed = 0; + p->realStreamFinished = 0; + XzCheck_Init(&p->check, checkMode); +} + +static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) +{ + XzCheck_Final(&p->check, digest); +} + +static SRes SeqCheckInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqCheckInStream) + size_t size2 = *size; + SRes res = SZ_OK; + + if (p->limit != (UInt64)(Int64)-1) + { + UInt64 rem = p->limit - p->processed; + if (size2 > rem) + size2 = (size_t)rem; + } + if (size2 != 0) + { + if (p->realStream) + { + res = ISeqInStream_Read(p->realStream, data, &size2); + p->realStreamFinished = (size2 == 0) ? 1 : 0; + } + else + memcpy(data, p->data + (size_t)p->processed, size2); + XzCheck_Update(&p->check, data, size2); + p->processed += size2; + } + *size = size2; + return res; +} + + +/* ---------- CSeqSizeOutStream ---------- */ + +typedef struct +{ + ISeqOutStream vt; + ISeqOutStreamPtr realStream; + Byte *outBuf; + size_t outBufLimit; + UInt64 processed; +} CSeqSizeOutStream; + +static size_t SeqSizeOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqSizeOutStream) + if (p->realStream) + size = ISeqOutStream_Write(p->realStream, data, size); + else + { + if (size > p->outBufLimit - (size_t)p->processed) + return 0; + memcpy(p->outBuf + (size_t)p->processed, data, size); + } + p->processed += size; + return size; +} + + +/* ---------- CSeqInFilter ---------- */ + +#define FILTER_BUF_SIZE (1 << 20) + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr realStream; + IStateCoder StateCoder; + Byte *buf; + size_t curPos; + size_t endPos; + int srcWasFinished; +} CSeqInFilter; + + +static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Enc[] = +{ + Z7_BRANCH_CONV_ENC_2 (BranchConv_PPC), + Z7_BRANCH_CONV_ENC_2 (BranchConv_IA64), + Z7_BRANCH_CONV_ENC_2 (BranchConv_ARM), + Z7_BRANCH_CONV_ENC_2 (BranchConv_ARMT), + Z7_BRANCH_CONV_ENC_2 (BranchConv_SPARC), + Z7_BRANCH_CONV_ENC_2 (BranchConv_ARM64), + Z7_BRANCH_CONV_ENC_2 (BranchConv_RISCV) +}; + +static SizeT XzBcFilterStateBase_Filter_Enc(CXzBcFilterStateBase *p, Byte *data, SizeT size) +{ + switch (p->methodId) + { + case XZ_ID_Delta: + Delta_Encode(p->delta_State, p->delta, data, size); + break; + case XZ_ID_X86: + size = (SizeT)(z7_BranchConvSt_X86_Enc(data, size, p->ip, &p->X86_State) - data); + break; + default: + if (p->methodId >= XZ_ID_PPC) + { + const UInt32 i = p->methodId - XZ_ID_PPC; + if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Enc)) + size = (SizeT)(g_Funcs_BranchConv_RISC_Enc[i](data, size, p->ip) - data); + } + break; + } + p->ip += (UInt32)size; + return size; +} + + +static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) +{ + if (!p->buf) + { + p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); + if (!p->buf) + return SZ_ERROR_MEM; + } + p->curPos = p->endPos = 0; + p->srcWasFinished = 0; + RINOK(Xz_StateCoder_Bc_SetFromMethod_Func(&p->StateCoder, props->id, XzBcFilterStateBase_Filter_Enc, alloc)) + RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)) + p->StateCoder.Init(p->StateCoder.p); + return SZ_OK; +} + + +static SRes SeqInFilter_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInFilter) + const size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + *size = 0; + + for (;;) + { + if (!p->srcWasFinished && p->curPos == p->endPos) + { + p->curPos = 0; + p->endPos = FILTER_BUF_SIZE; + RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)) + if (p->endPos == 0) + p->srcWasFinished = 1; + } + { + SizeT srcLen = p->endPos - p->curPos; + ECoderStatus status; + SRes res; + *size = sizeOriginal; + res = p->StateCoder.Code2(p->StateCoder.p, + (Byte *)data, size, + p->buf + p->curPos, &srcLen, + p->srcWasFinished, CODER_FINISH_ANY, + &status); + p->curPos += srcLen; + if (*size != 0 || srcLen == 0 || res != SZ_OK) + return res; + } + } +} + +static void SeqInFilter_Construct(CSeqInFilter *p) +{ + p->buf = NULL; + p->StateCoder.p = NULL; + p->vt.Read = SeqInFilter_Read; +} + +static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) +{ + if (p->StateCoder.p) + { + p->StateCoder.Free(p->StateCoder.p, alloc); + p->StateCoder.p = NULL; + } + if (p->buf) + { + ISzAlloc_Free(alloc, p->buf); + p->buf = NULL; + } +} + + +/* ---------- CSbEncInStream ---------- */ + +#ifdef USE_SUBBLOCK + +typedef struct +{ + ISeqInStream vt; + ISeqInStreamPtr inStream; + CSbEnc enc; +} CSbEncInStream; + +static SRes SbEncInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size) +{ + CSbEncInStream *p = Z7_CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); + size_t sizeOriginal = *size; + if (sizeOriginal == 0) + return SZ_OK; + + for (;;) + { + if (p->enc.needRead && !p->enc.readWasFinished) + { + size_t processed = p->enc.needReadSizeMax; + RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)) + p->enc.readPos += processed; + if (processed == 0) + { + p->enc.readWasFinished = True; + p->enc.isFinalFinished = True; + } + p->enc.needRead = False; + } + + *size = sizeOriginal; + RINOK(SbEnc_Read(&p->enc, data, size)) + if (*size != 0 || !p->enc.needRead) + return SZ_OK; + } +} + +void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) +{ + SbEnc_Construct(&p->enc, alloc); + p->vt.Read = SbEncInStream_Read; +} + +SRes SbEncInStream_Init(CSbEncInStream *p) +{ + return SbEnc_Init(&p->enc); +} + +void SbEncInStream_Free(CSbEncInStream *p) +{ + SbEnc_Free(&p->enc); +} + +#endif + + + +/* ---------- CXzProps ---------- */ + + +void XzFilterProps_Init(CXzFilterProps *p) +{ + p->id = 0; + p->delta = 0; + p->ip = 0; + p->ipDefined = False; +} + +void XzProps_Init(CXzProps *p) +{ + p->checkId = XZ_CHECK_CRC32; + p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO; + p->numBlockThreads_Reduced = -1; + p->numBlockThreads_Max = -1; + p->numTotalThreads = -1; + p->reduceSize = (UInt64)(Int64)-1; + p->forceWriteSizesInHeader = 0; + // p->forceWriteSizesInHeader = 1; + + XzFilterProps_Init(&p->filterProps); + Lzma2EncProps_Init(&p->lzma2Props); +} + + +static void XzEncProps_Normalize_Fixed(CXzProps *p) +{ + UInt64 fileSize; + int t1, t1n, t2, t2r, t3; + { + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + Lzma2EncProps_Normalize(&tp); + t1n = tp.numTotalThreads; + } + + t1 = p->lzma2Props.numTotalThreads; + t2 = p->numBlockThreads_Max; + t3 = p->numTotalThreads; + + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + + if (t3 <= 0) + { + if (t2 <= 0) + t2 = 1; + t3 = t1n * t2; + } + else if (t2 <= 0) + { + t2 = t3 / t1n; + if (t2 == 0) + { + t1 = 1; + t2 = t3; + } + if (t2 > MTCODER_THREADS_MAX) + t2 = MTCODER_THREADS_MAX; + } + else if (t1 <= 0) + { + t1 = t3 / t2; + if (t1 == 0) + t1 = 1; + } + else + t3 = t1n * t2; + + p->lzma2Props.numTotalThreads = t1; + + t2r = t2; + + fileSize = p->reduceSize; + + if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) + p->lzma2Props.lzmaProps.reduceSize = p->blockSize; + + Lzma2EncProps_Normalize(&p->lzma2Props); + + t1 = p->lzma2Props.numTotalThreads; + + { + if (t2 > 1 && fileSize != (UInt64)(Int64)-1) + { + UInt64 numBlocks = fileSize / p->blockSize; + if (numBlocks * p->blockSize != fileSize) + numBlocks++; + if (numBlocks < (unsigned)t2) + { + t2r = (int)numBlocks; + if (t2r == 0) + t2r = 1; + t3 = t1 * t2r; + } + } + } + + p->numBlockThreads_Max = t2; + p->numBlockThreads_Reduced = t2r; + p->numTotalThreads = t3; +} + + +static void XzProps_Normalize(CXzProps *p) +{ + /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. + Lzma2Enc_SetProps() will normalize lzma2Props later. */ + + if (p->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID) + { + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + return; + } + else + { + CLzma2EncProps *lzma2 = &p->lzma2Props; + if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + { + // xz-auto + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + + if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + { + // if (xz-auto && lzma2-solid) - we use solid for both + p->blockSize = XZ_PROPS_BLOCK_SIZE_SOLID; + p->numBlockThreads_Reduced = 1; + p->numBlockThreads_Max = 1; + if (p->lzma2Props.numTotalThreads <= 0) + p->lzma2Props.numTotalThreads = p->numTotalThreads; + } + else + { + // if (xz-auto && (lzma2-auto || lzma2-fixed_) + // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block + CLzma2EncProps tp = p->lzma2Props; + if (tp.numTotalThreads <= 0) + tp.numTotalThreads = p->numTotalThreads; + + Lzma2EncProps_Normalize(&tp); + + p->blockSize = tp.blockSize; // fixed or solid + p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; + p->numBlockThreads_Max = tp.numBlockThreads_Max; + if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + lzma2->lzmaProps.reduceSize = tp.blockSize; + lzma2->numBlockThreads_Reduced = 1; + lzma2->numBlockThreads_Max = 1; + return; + } + } + else + { + // xz-fixed + // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize + + p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; + { + UInt64 r = p->reduceSize; + if (r > p->blockSize || r == (UInt64)(Int64)-1) + r = p->blockSize; + lzma2->lzmaProps.reduceSize = r; + } + if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO) + lzma2->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; + else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID) + lzma2->blockSize = p->blockSize; + + XzEncProps_Normalize_Fixed(p); + } + } +} + + +/* ---------- CLzma2WithFilters ---------- */ + +typedef struct +{ + CLzma2EncHandle lzma2; + CSeqInFilter filter; + + #ifdef USE_SUBBLOCK + CSbEncInStream sb; + #endif +} CLzma2WithFilters; + + +static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) +{ + p->lzma2 = NULL; + SeqInFilter_Construct(&p->filter); + + #ifdef USE_SUBBLOCK + SbEncInStream_Construct(&p->sb, alloc); + #endif +} + + +static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) +{ + if (!p->lzma2) + { + p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); + if (!p->lzma2) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + + +static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) +{ + #ifdef USE_SUBBLOCK + SbEncInStream_Free(&p->sb); + #endif + + SeqInFilter_Free(&p->filter, alloc); + if (p->lzma2) + { + Lzma2Enc_Destroy(p->lzma2); + p->lzma2 = NULL; + } +} + + +typedef struct +{ + UInt64 unpackSize; + UInt64 totalSize; + size_t headerSize; +} CXzEncBlockInfo; + + +static SRes Xz_CompressBlock( + CLzma2WithFilters *lzmaf, + + ISeqOutStreamPtr outStream, + Byte *outBufHeader, + Byte *outBufData, size_t outBufDataLimit, + + ISeqInStreamPtr inStream, + // UInt64 expectedSize, + const Byte *inBuf, // used if (!inStream) + size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored + + const CXzProps *props, + ICompressProgressPtr progress, + int *inStreamFinished, /* only for inStream version */ + CXzEncBlockInfo *blockSizes, + ISzAllocPtr alloc, + ISzAllocPtr allocBig) +{ + CSeqCheckInStream checkInStream; + CSeqSizeOutStream seqSizeOutStream; + CXzBlock block; + unsigned filterIndex = 0; + CXzFilter *filter = NULL; + const CXzFilterProps *fp = &props->filterProps; + if (fp->id == 0) + fp = NULL; + + *inStreamFinished = False; + + RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)) + + RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)) + + // XzBlock_ClearFlags(&block) + XzBlock_ClearFlags_SetNumFilters(&block, 1 + (fp ? 1 : 0)) + + if (fp) + { + filter = &block.filters[filterIndex++]; + filter->id = fp->id; + filter->propsSize = 0; + + if (fp->id == XZ_ID_Delta) + { + filter->props[0] = (Byte)(fp->delta - 1); + filter->propsSize = 1; + } + else if (fp->ipDefined) + { + Byte *ptr = filter->props; + SetUi32(ptr, fp->ip) + filter->propsSize = 4; + } + } + + { + CXzFilter *f = &block.filters[filterIndex++]; + f->id = XZ_ID_LZMA2; + f->propsSize = 1; + f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); + } + + seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; + seqSizeOutStream.realStream = outStream; + seqSizeOutStream.outBuf = outBufData; + seqSizeOutStream.outBufLimit = outBufDataLimit; + seqSizeOutStream.processed = 0; + + /* + if (expectedSize != (UInt64)(Int64)-1) + { + block.unpackSize = expectedSize; + if (props->blockSize != (UInt64)(Int64)-1) + if (expectedSize > props->blockSize) + block.unpackSize = props->blockSize; + XzBlock_SetHasUnpackSize(&block) + } + */ + + if (outStream) + { + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)) + } + + checkInStream.vt.Read = SeqCheckInStream_Read; + SeqCheckInStream_Init(&checkInStream, props->checkId); + + checkInStream.realStream = inStream; + checkInStream.data = inBuf; + checkInStream.limit = props->blockSize; + if (!inStream) + checkInStream.limit = inBufSize; + + if (fp) + { + #ifdef USE_SUBBLOCK + if (fp->id == XZ_ID_Subblock) + { + lzmaf->sb.inStream = &checkInStream.vt; + RINOK(SbEncInStream_Init(&lzmaf->sb)) + } + else + #endif + { + lzmaf->filter.realStream = &checkInStream.vt; + RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)) + } + } + + { + SRes res; + Byte *outBuf = NULL; + size_t outSize = 0; + BoolInt useStream = (fp || inStream); + // useStream = True; + + if (!useStream) + { + XzCheck_Update(&checkInStream.check, inBuf, inBufSize); + checkInStream.processed = inBufSize; + } + + if (!outStream) + { + outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; + outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; + } + + res = Lzma2Enc_Encode2(lzmaf->lzma2, + outBuf ? NULL : &seqSizeOutStream.vt, + outBuf, + outBuf ? &outSize : NULL, + + useStream ? + (fp ? + ( + #ifdef USE_SUBBLOCK + (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: + #endif + &lzmaf->filter.vt) : + &checkInStream.vt) : NULL, + + useStream ? NULL : inBuf, + useStream ? 0 : inBufSize, + + progress); + + if (outBuf) + seqSizeOutStream.processed += outSize; + + RINOK(res) + blockSizes->unpackSize = checkInStream.processed; + } + { + Byte buf[4 + XZ_CHECK_SIZE_MAX]; + const unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); + const UInt64 packSize = seqSizeOutStream.processed; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = 0; + + SeqCheckInStream_GetDigest(&checkInStream, buf + 4); + RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), + padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))) + + blockSizes->totalSize = seqSizeOutStream.processed - padSize; + + if (!outStream) + { + seqSizeOutStream.outBuf = outBufHeader; + seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; + seqSizeOutStream.processed = 0; + + block.unpackSize = blockSizes->unpackSize; + XzBlock_SetHasUnpackSize(&block) + + block.packSize = packSize; + XzBlock_SetHasPackSize(&block) + + RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)) + + blockSizes->headerSize = (size_t)seqSizeOutStream.processed; + blockSizes->totalSize += seqSizeOutStream.processed; + } + } + + if (inStream) + *inStreamFinished = checkInStream.realStreamFinished; + else + { + *inStreamFinished = False; + if (checkInStream.processed != inBufSize) + return SZ_ERROR_FAIL; + } + + return SZ_OK; +} + + + +typedef struct +{ + ICompressProgress vt; + ICompressProgressPtr progress; + UInt64 inOffset; + UInt64 outOffset; +} CCompressProgress_XzEncOffset; + + +static SRes CompressProgress_XzEncOffset_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) +{ + const CCompressProgress_XzEncOffset *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CCompressProgress_XzEncOffset, vt); + inSize += p->inOffset; + outSize += p->outOffset; + return ICompressProgress_Progress(p->progress, inSize, outSize); +} + + + + +struct CXzEnc +{ + ISzAllocPtr alloc; + ISzAllocPtr allocBig; + + CXzProps xzProps; + UInt64 expectedDataSize; + + CXzEncIndex xzIndex; + + CLzma2WithFilters lzmaf_Items[MTCODER_THREADS_MAX]; + + size_t outBufSize; /* size of allocated outBufs[i] */ + Byte *outBufs[MTCODER_BLOCKS_MAX]; + + #ifndef Z7_ST + unsigned checkType; + ISeqOutStreamPtr outStream; + BoolInt mtCoder_WasConstructed; + CMtCoder mtCoder; + CXzEncBlockInfo EncBlocks[MTCODER_BLOCKS_MAX]; + #endif +}; + + +static void XzEnc_Construct(CXzEnc *p) +{ + unsigned i; + + XzEncIndex_Construct(&p->xzIndex); + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); + + #ifndef Z7_ST + p->mtCoder_WasConstructed = False; + { + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + p->outBufs[i] = NULL; + p->outBufSize = 0; + } + #endif +} + + +static void XzEnc_FreeOutBufs(CXzEnc *p) +{ + unsigned i; + for (i = 0; i < MTCODER_BLOCKS_MAX; i++) + if (p->outBufs[i]) + { + ISzAlloc_Free(p->alloc, p->outBufs[i]); + p->outBufs[i] = NULL; + } + p->outBufSize = 0; +} + + +static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) +{ + unsigned i; + + XzEncIndex_Free(&p->xzIndex, alloc); + + for (i = 0; i < MTCODER_THREADS_MAX; i++) + Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); + + #ifndef Z7_ST + if (p->mtCoder_WasConstructed) + { + MtCoder_Destruct(&p->mtCoder); + p->mtCoder_WasConstructed = False; + } + XzEnc_FreeOutBufs(p); + #endif +} + + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) +{ + CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); + if (!p) + return NULL; + XzEnc_Construct(p); + XzProps_Init(&p->xzProps); + XzProps_Normalize(&p->xzProps); + p->expectedDataSize = (UInt64)(Int64)-1; + p->alloc = alloc; + p->allocBig = allocBig; + return (CXzEncHandle)p; +} + +// #define GET_CXzEnc_p CXzEnc *p = (CXzEnc *)(void *)pp; + +void XzEnc_Destroy(CXzEncHandle p) +{ + // GET_CXzEnc_p + XzEnc_Free(p, p->alloc); + ISzAlloc_Free(p->alloc, p); +} + + +SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props) +{ + // GET_CXzEnc_p + p->xzProps = *props; + XzProps_Normalize(&p->xzProps); + return SZ_OK; +} + + +void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize) +{ + // GET_CXzEnc_p + p->expectedDataSize = expectedDataSiize; +} + + + + +#ifndef Z7_ST + +static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, + const Byte *src, size_t srcSize, int finished) +{ + CXzEnc *me = (CXzEnc *)pp; + SRes res; + CMtProgressThunk progressThunk; + Byte *dest; + UNUSED_VAR(finished) + { + CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + bInfo->totalSize = 0; + bInfo->unpackSize = 0; + bInfo->headerSize = 0; + // v23.02: we don't compress empty blocks + // also we must ignore that empty block in XzEnc_MtCallback_Write() + if (srcSize == 0) + return SZ_OK; + } + dest = me->outBufs[outBufIndex]; + if (!dest) + { + dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); + if (!dest) + return SZ_ERROR_MEM; + me->outBufs[outBufIndex] = dest; + } + + MtProgressThunk_CreateVTable(&progressThunk); + progressThunk.mtProgress = &me->mtCoder.mtProgress; + MtProgressThunk_INIT(&progressThunk) + + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + res = Xz_CompressBlock( + &me->lzmaf_Items[coderIndex], + + NULL, + dest, + dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, + + NULL, + // srcSize, // expectedSize + src, srcSize, + + &me->xzProps, + &progressThunk.vt, + &inStreamFinished, + &blockSizes, + me->alloc, + me->allocBig); + + if (res == SZ_OK) + me->EncBlocks[outBufIndex] = blockSizes; + + return res; + } +} + + +static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) +{ + CXzEnc *me = (CXzEnc *)pp; + const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; + // v23.02: we don't write empty blocks + // note: if (bInfo->unpackSize == 0) then there is no compressed data of block + if (bInfo->unpackSize == 0) + return SZ_OK; + { + const Byte *data = me->outBufs[outBufIndex]; + RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)) + { + const UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); + RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)) + } + return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); + } +} + +#endif + + + +SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress) +{ + // GET_CXzEnc_p + + const CXzProps *props = &p->xzProps; + + XzEncIndex_Init(&p->xzIndex); + { + UInt64 numBlocks = 1; + UInt64 blockSize = props->blockSize; + + if (blockSize != XZ_PROPS_BLOCK_SIZE_SOLID + && props->reduceSize != (UInt64)(Int64)-1) + { + numBlocks = props->reduceSize / blockSize; + if (numBlocks * blockSize != props->reduceSize) + numBlocks++; + } + else + blockSize = (UInt64)1 << 62; + + RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)) + } + + RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)) + + + #ifndef Z7_ST + if (props->numBlockThreads_Reduced > 1) + { + IMtCoderCallback2 vt; + + if (!p->mtCoder_WasConstructed) + { + p->mtCoder_WasConstructed = True; + MtCoder_Construct(&p->mtCoder); + } + + vt.Code = XzEnc_MtCallback_Code; + vt.Write = XzEnc_MtCallback_Write; + + p->checkType = props->checkId; + p->xzProps = *props; + + p->outStream = outStream; + + p->mtCoder.allocBig = p->allocBig; + p->mtCoder.progress = progress; + p->mtCoder.inStream = inStream; + p->mtCoder.inData = NULL; + p->mtCoder.inDataSize = 0; + p->mtCoder.mtCallback = &vt; + p->mtCoder.mtCallbackObject = p; + + if ( props->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID + || props->blockSize == XZ_PROPS_BLOCK_SIZE_AUTO) + return SZ_ERROR_FAIL; + + p->mtCoder.blockSize = (size_t)props->blockSize; + if (p->mtCoder.blockSize != props->blockSize) + return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ + + { + size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); + if (destBlockSize < p->mtCoder.blockSize) + return SZ_ERROR_PARAM; + if (p->outBufSize != destBlockSize) + XzEnc_FreeOutBufs(p); + p->outBufSize = destBlockSize; + } + + p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; + p->mtCoder.expectedDataSize = p->expectedDataSize; + + RINOK(MtCoder_Code(&p->mtCoder)) + } + else + #endif + { + int writeStartSizes; + CCompressProgress_XzEncOffset progress2; + Byte *bufData = NULL; + size_t bufSize = 0; + + progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; + progress2.inOffset = 0; + progress2.outOffset = 0; + progress2.progress = progress; + + writeStartSizes = 0; + + if (props->blockSize != XZ_PROPS_BLOCK_SIZE_SOLID) + { + writeStartSizes = (props->forceWriteSizesInHeader > 0); + + if (writeStartSizes) + { + size_t t2; + size_t t = (size_t)props->blockSize; + if (t != props->blockSize) + return SZ_ERROR_PARAM; + t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); + if (t < props->blockSize) + return SZ_ERROR_PARAM; + t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; + if (!p->outBufs[0] || t2 != p->outBufSize) + { + XzEnc_FreeOutBufs(p); + p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); + if (!p->outBufs[0]) + return SZ_ERROR_MEM; + p->outBufSize = t2; + } + bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; + bufSize = t; + } + } + + for (;;) + { + CXzEncBlockInfo blockSizes; + int inStreamFinished; + + /* + UInt64 rem = (UInt64)(Int64)-1; + if (props->reduceSize != (UInt64)(Int64)-1 + && props->reduceSize >= progress2.inOffset) + rem = props->reduceSize - progress2.inOffset; + */ + + blockSizes.headerSize = 0; // for GCC + + RINOK(Xz_CompressBlock( + &p->lzmaf_Items[0], + + writeStartSizes ? NULL : outStream, + writeStartSizes ? p->outBufs[0] : NULL, + bufData, bufSize, + + inStream, + // rem, + NULL, 0, + + props, + progress ? &progress2.vt : NULL, + &inStreamFinished, + &blockSizes, + p->alloc, + p->allocBig)) + + { + UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); + + if (writeStartSizes) + { + RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)) + RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)) + } + + RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)) + + progress2.inOffset += blockSizes.unpackSize; + progress2.outOffset += totalPackFull; + } + + if (inStreamFinished) + break; + } + } + + return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); +} + + +#include "Alloc.h" + +SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + const CXzProps *props, ICompressProgressPtr progress) +{ + SRes res; + CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); + if (!xz) + return SZ_ERROR_MEM; + res = XzEnc_SetProps(xz, props); + if (res == SZ_OK) + res = XzEnc_Encode(xz, outStream, inStream, progress); + XzEnc_Destroy(xz); + return res; +} + + +SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream) +{ + SRes res; + CXzEncIndex xzIndex; + XzEncIndex_Construct(&xzIndex); + res = Xz_WriteHeader((CXzStreamFlags)0, outStream); + if (res == SZ_OK) + res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); + XzEncIndex_Free(&xzIndex, NULL); // g_Alloc + return res; +} diff --git a/C/XzEnc.h b/C/XzEnc.h index 31026f7e0..77b78c014 100644 --- a/C/XzEnc.h +++ b/C/XzEnc.h @@ -1,61 +1,61 @@ -/* XzEnc.h -- Xz Encode -2023-04-13 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_XZ_ENC_H -#define ZIP7_INC_XZ_ENC_H - -#include "Lzma2Enc.h" - -#include "Xz.h" - -EXTERN_C_BEGIN - - -#define XZ_PROPS_BLOCK_SIZE_AUTO LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO -#define XZ_PROPS_BLOCK_SIZE_SOLID LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID - - -typedef struct -{ - UInt32 id; - UInt32 delta; - UInt32 ip; - int ipDefined; -} CXzFilterProps; - -void XzFilterProps_Init(CXzFilterProps *p); - - -typedef struct -{ - CLzma2EncProps lzma2Props; - CXzFilterProps filterProps; - unsigned checkId; - UInt64 blockSize; - int numBlockThreads_Reduced; - int numBlockThreads_Max; - int numTotalThreads; - int forceWriteSizesInHeader; - UInt64 reduceSize; -} CXzProps; - -void XzProps_Init(CXzProps *p); - -typedef struct CXzEnc CXzEnc; -typedef CXzEnc * CXzEncHandle; -// Z7_DECLARE_HANDLE(CXzEncHandle) - -CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); -void XzEnc_Destroy(CXzEncHandle p); -SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props); -void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize); -SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress); - -SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, - const CXzProps *props, ICompressProgressPtr progress); - -SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream); - -EXTERN_C_END - -#endif +/* XzEnc.h -- Xz Encode +2023-04-13 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_XZ_ENC_H +#define ZIP7_INC_XZ_ENC_H + +#include "Lzma2Enc.h" + +#include "Xz.h" + +EXTERN_C_BEGIN + + +#define XZ_PROPS_BLOCK_SIZE_AUTO LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO +#define XZ_PROPS_BLOCK_SIZE_SOLID LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID + + +typedef struct +{ + UInt32 id; + UInt32 delta; + UInt32 ip; + int ipDefined; +} CXzFilterProps; + +void XzFilterProps_Init(CXzFilterProps *p); + + +typedef struct +{ + CLzma2EncProps lzma2Props; + CXzFilterProps filterProps; + unsigned checkId; + UInt64 blockSize; + int numBlockThreads_Reduced; + int numBlockThreads_Max; + int numTotalThreads; + int forceWriteSizesInHeader; + UInt64 reduceSize; +} CXzProps; + +void XzProps_Init(CXzProps *p); + +typedef struct CXzEnc CXzEnc; +typedef CXzEnc * CXzEncHandle; +// Z7_DECLARE_HANDLE(CXzEncHandle) + +CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig); +void XzEnc_Destroy(CXzEncHandle p); +SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props); +void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize); +SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress); + +SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, + const CXzProps *props, ICompressProgressPtr progress); + +SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream); + +EXTERN_C_END + +#endif diff --git a/C/XzIn.c b/C/XzIn.c index 49470a72f..b68af965c 100644 --- a/C/XzIn.c +++ b/C/XzIn.c @@ -1,340 +1,340 @@ -/* XzIn.c - Xz input -2023-09-07 : Igor Pavlov : Public domain */ - -#include "Precomp.h" - -#include - -#include "7zCrc.h" -#include "CpuArch.h" -#include "Xz.h" - -/* -#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) -*/ -#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) - - -SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream) -{ - Byte sig[XZ_STREAM_HEADER_SIZE]; - size_t processedSize = XZ_STREAM_HEADER_SIZE; - RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize)) - if (processedSize != XZ_STREAM_HEADER_SIZE - || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) - return SZ_ERROR_NO_ARCHIVE; - return Xz_ParseHeader(p, sig); -} - -#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ - { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ - if (s == 0) return SZ_ERROR_ARCHIVE; \ - pos += s; } - -SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes) -{ - Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; - unsigned headerSize; - *headerSizeRes = 0; - RINOK(SeqInStream_ReadByte(inStream, &header[0])) - headerSize = header[0]; - if (headerSize == 0) - { - *headerSizeRes = 1; - *isIndex = True; - return SZ_OK; - } - - *isIndex = False; - headerSize = (headerSize << 2) + 4; - *headerSizeRes = (UInt32)headerSize; - { - size_t processedSize = headerSize - 1; - RINOK(SeqInStream_ReadMax(inStream, header + 1, &processedSize)) - if (processedSize != headerSize - 1) - return SZ_ERROR_INPUT_EOF; - } - return XzBlock_Parse(p, header); -} - -#define ADD_SIZE_CHECK(size, val) \ - { const UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } - -UInt64 Xz_GetUnpackSize(const CXzStream *p) -{ - UInt64 size = 0; - size_t i; - for (i = 0; i < p->numBlocks; i++) - { - ADD_SIZE_CHECK(size, p->blocks[i].unpackSize) - } - return size; -} - -UInt64 Xz_GetPackSize(const CXzStream *p) -{ - UInt64 size = 0; - size_t i; - for (i = 0; i < p->numBlocks; i++) - { - ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3) - } - return size; -} - -/* -SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream) -{ - return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); -} -*/ - -static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) -{ - size_t numBlocks, pos = 1; - UInt32 crc; - - if (size < 5 || buf[0] != 0) - return SZ_ERROR_ARCHIVE; - - size -= 4; - crc = CrcCalc(buf, size); - if (crc != GetUi32(buf + size)) - return SZ_ERROR_ARCHIVE; - - { - UInt64 numBlocks64; - READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64) - numBlocks = (size_t)numBlocks64; - if (numBlocks != numBlocks64 || numBlocks * 2 > size) - return SZ_ERROR_ARCHIVE; - } - - Xz_Free(p, alloc); - if (numBlocks != 0) - { - size_t i; - p->numBlocks = numBlocks; - p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); - if (!p->blocks) - return SZ_ERROR_MEM; - for (i = 0; i < numBlocks; i++) - { - CXzBlockSizes *block = &p->blocks[i]; - READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize) - READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize) - if (block->totalSize == 0) - return SZ_ERROR_ARCHIVE; - } - } - while ((pos & 3) != 0) - if (buf[pos++] != 0) - return SZ_ERROR_ARCHIVE; - return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; -} - -static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc) -{ - SRes res; - size_t size; - Byte *buf; - if (indexSize > ((UInt32)1 << 31)) - return SZ_ERROR_UNSUPPORTED; - size = (size_t)indexSize; - if (size != indexSize) - return SZ_ERROR_UNSUPPORTED; - buf = (Byte *)ISzAlloc_Alloc(alloc, size); - if (!buf) - return SZ_ERROR_MEM; - res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); - if (res == SZ_OK) - res = Xz_ReadIndex2(p, buf, size, alloc); - ISzAlloc_Free(alloc, buf); - return res; -} - -static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size) -{ - RINOK(LookInStream_SeekTo(stream, offset)) - return LookInStream_Read(stream, buf, size); - /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ -} - -static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc) -{ - UInt64 indexSize; - Byte buf[XZ_STREAM_FOOTER_SIZE]; - UInt64 pos = (UInt64)*startOffset; - - if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) - return SZ_ERROR_NO_ARCHIVE; - - pos -= XZ_STREAM_FOOTER_SIZE; - RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) - - if (!XZ_FOOTER_SIG_CHECK(buf + 10)) - { - UInt32 total = 0; - pos += XZ_STREAM_FOOTER_SIZE; - - for (;;) - { - size_t i; - #define TEMP_BUF_SIZE (1 << 10) - Byte temp[TEMP_BUF_SIZE]; - - i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; - pos -= i; - RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)) - total += (UInt32)i; - for (; i != 0; i--) - if (temp[i - 1] != 0) - break; - if (i != 0) - { - if ((i & 3) != 0) - return SZ_ERROR_NO_ARCHIVE; - pos += i; - break; - } - if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) - return SZ_ERROR_NO_ARCHIVE; - } - - if (pos < XZ_STREAM_FOOTER_SIZE) - return SZ_ERROR_NO_ARCHIVE; - pos -= XZ_STREAM_FOOTER_SIZE; - RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) - if (!XZ_FOOTER_SIG_CHECK(buf + 10)) - return SZ_ERROR_NO_ARCHIVE; - } - - p->flags = (CXzStreamFlags)GetBe16(buf + 8); - - if (!XzFlags_IsSupported(p->flags)) - return SZ_ERROR_UNSUPPORTED; - - { - /* to eliminate GCC 6.3 warning: - dereferencing type-punned pointer will break strict-aliasing rules */ - const Byte *buf_ptr = buf; - if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6)) - return SZ_ERROR_ARCHIVE; - } - - indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; - - if (pos < indexSize) - return SZ_ERROR_ARCHIVE; - - pos -= indexSize; - RINOK(LookInStream_SeekTo(stream, pos)) - RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)) - - { - UInt64 totalSize = Xz_GetPackSize(p); - if (totalSize == XZ_SIZE_OVERFLOW - || totalSize >= ((UInt64)1 << 63) - || pos < totalSize + XZ_STREAM_HEADER_SIZE) - return SZ_ERROR_ARCHIVE; - pos -= (totalSize + XZ_STREAM_HEADER_SIZE); - RINOK(LookInStream_SeekTo(stream, pos)) - *startOffset = (Int64)pos; - } - { - CXzStreamFlags headerFlags; - CSecToRead secToRead; - SecToRead_CreateVTable(&secToRead); - secToRead.realStream = stream; - - RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)) - return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; - } -} - - -/* ---------- Xz Streams ---------- */ - -void Xzs_Construct(CXzs *p) -{ - p->num = p->numAllocated = 0; - p->streams = 0; -} - -void Xzs_Free(CXzs *p, ISzAllocPtr alloc) -{ - size_t i; - for (i = 0; i < p->num; i++) - Xz_Free(&p->streams[i], alloc); - ISzAlloc_Free(alloc, p->streams); - p->num = p->numAllocated = 0; - p->streams = 0; -} - -UInt64 Xzs_GetNumBlocks(const CXzs *p) -{ - UInt64 num = 0; - size_t i; - for (i = 0; i < p->num; i++) - num += p->streams[i].numBlocks; - return num; -} - -UInt64 Xzs_GetUnpackSize(const CXzs *p) -{ - UInt64 size = 0; - size_t i; - for (i = 0; i < p->num; i++) - { - ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i])) - } - return size; -} - -/* -UInt64 Xzs_GetPackSize(const CXzs *p) -{ - UInt64 size = 0; - size_t i; - for (i = 0; i < p->num; i++) - { - ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i])) - } - return size; -} -*/ - -SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc) -{ - Int64 endOffset = 0; - RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)) - *startOffset = endOffset; - for (;;) - { - CXzStream st; - SRes res; - Xz_Construct(&st); - res = Xz_ReadBackward(&st, stream, startOffset, alloc); - st.startOffset = (UInt64)*startOffset; - RINOK(res) - if (p->num == p->numAllocated) - { - const size_t newNum = p->num + p->num / 4 + 1; - void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); - if (!data) - return SZ_ERROR_MEM; - p->numAllocated = newNum; - if (p->num != 0) - memcpy(data, p->streams, p->num * sizeof(CXzStream)); - ISzAlloc_Free(alloc, p->streams); - p->streams = (CXzStream *)data; - } - p->streams[p->num++] = st; - if (*startOffset == 0) - break; - RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)) - if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) - return SZ_ERROR_PROGRESS; - } - return SZ_OK; -} +/* XzIn.c - Xz input +2023-09-07 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +#include + +#include "7zCrc.h" +#include "CpuArch.h" +#include "Xz.h" + +/* +#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0) +*/ +#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1) + + +SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream) +{ + Byte sig[XZ_STREAM_HEADER_SIZE]; + size_t processedSize = XZ_STREAM_HEADER_SIZE; + RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize)) + if (processedSize != XZ_STREAM_HEADER_SIZE + || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0) + return SZ_ERROR_NO_ARCHIVE; + return Xz_ParseHeader(p, sig); +} + +#define READ_VARINT_AND_CHECK(buf, pos, size, res) \ + { const unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \ + if (s == 0) return SZ_ERROR_ARCHIVE; \ + pos += s; } + +SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes) +{ + Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; + unsigned headerSize; + *headerSizeRes = 0; + RINOK(SeqInStream_ReadByte(inStream, &header[0])) + headerSize = header[0]; + if (headerSize == 0) + { + *headerSizeRes = 1; + *isIndex = True; + return SZ_OK; + } + + *isIndex = False; + headerSize = (headerSize << 2) + 4; + *headerSizeRes = (UInt32)headerSize; + { + size_t processedSize = headerSize - 1; + RINOK(SeqInStream_ReadMax(inStream, header + 1, &processedSize)) + if (processedSize != headerSize - 1) + return SZ_ERROR_INPUT_EOF; + } + return XzBlock_Parse(p, header); +} + +#define ADD_SIZE_CHECK(size, val) \ + { const UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; } + +UInt64 Xz_GetUnpackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + { + ADD_SIZE_CHECK(size, p->blocks[i].unpackSize) + } + return size; +} + +UInt64 Xz_GetPackSize(const CXzStream *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->numBlocks; i++) + { + ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3) + } + return size; +} + +/* +SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream) +{ + return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f)); +} +*/ + +static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc) +{ + size_t numBlocks, pos = 1; + UInt32 crc; + + if (size < 5 || buf[0] != 0) + return SZ_ERROR_ARCHIVE; + + size -= 4; + crc = CrcCalc(buf, size); + if (crc != GetUi32(buf + size)) + return SZ_ERROR_ARCHIVE; + + { + UInt64 numBlocks64; + READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64) + numBlocks = (size_t)numBlocks64; + if (numBlocks != numBlocks64 || numBlocks * 2 > size) + return SZ_ERROR_ARCHIVE; + } + + Xz_Free(p, alloc); + if (numBlocks != 0) + { + size_t i; + p->numBlocks = numBlocks; + p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks); + if (!p->blocks) + return SZ_ERROR_MEM; + for (i = 0; i < numBlocks; i++) + { + CXzBlockSizes *block = &p->blocks[i]; + READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize) + READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize) + if (block->totalSize == 0) + return SZ_ERROR_ARCHIVE; + } + } + while ((pos & 3) != 0) + if (buf[pos++] != 0) + return SZ_ERROR_ARCHIVE; + return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; +} + +static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc) +{ + SRes res; + size_t size; + Byte *buf; + if (indexSize > ((UInt32)1 << 31)) + return SZ_ERROR_UNSUPPORTED; + size = (size_t)indexSize; + if (size != indexSize) + return SZ_ERROR_UNSUPPORTED; + buf = (Byte *)ISzAlloc_Alloc(alloc, size); + if (!buf) + return SZ_ERROR_MEM; + res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED); + if (res == SZ_OK) + res = Xz_ReadIndex2(p, buf, size, alloc); + ISzAlloc_Free(alloc, buf); + return res; +} + +static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size) +{ + RINOK(LookInStream_SeekTo(stream, offset)) + return LookInStream_Read(stream, buf, size); + /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ +} + +static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc) +{ + UInt64 indexSize; + Byte buf[XZ_STREAM_FOOTER_SIZE]; + UInt64 pos = (UInt64)*startOffset; + + if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) + + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + { + UInt32 total = 0; + pos += XZ_STREAM_FOOTER_SIZE; + + for (;;) + { + size_t i; + #define TEMP_BUF_SIZE (1 << 10) + Byte temp[TEMP_BUF_SIZE]; + + i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; + pos -= i; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)) + total += (UInt32)i; + for (; i != 0; i--) + if (temp[i - 1] != 0) + break; + if (i != 0) + { + if ((i & 3) != 0) + return SZ_ERROR_NO_ARCHIVE; + pos += i; + break; + } + if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) + return SZ_ERROR_NO_ARCHIVE; + } + + if (pos < XZ_STREAM_FOOTER_SIZE) + return SZ_ERROR_NO_ARCHIVE; + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)) + if (!XZ_FOOTER_SIG_CHECK(buf + 10)) + return SZ_ERROR_NO_ARCHIVE; + } + + p->flags = (CXzStreamFlags)GetBe16(buf + 8); + + if (!XzFlags_IsSupported(p->flags)) + return SZ_ERROR_UNSUPPORTED; + + { + /* to eliminate GCC 6.3 warning: + dereferencing type-punned pointer will break strict-aliasing rules */ + const Byte *buf_ptr = buf; + if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6)) + return SZ_ERROR_ARCHIVE; + } + + indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; + + if (pos < indexSize) + return SZ_ERROR_ARCHIVE; + + pos -= indexSize; + RINOK(LookInStream_SeekTo(stream, pos)) + RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)) + + { + UInt64 totalSize = Xz_GetPackSize(p); + if (totalSize == XZ_SIZE_OVERFLOW + || totalSize >= ((UInt64)1 << 63) + || pos < totalSize + XZ_STREAM_HEADER_SIZE) + return SZ_ERROR_ARCHIVE; + pos -= (totalSize + XZ_STREAM_HEADER_SIZE); + RINOK(LookInStream_SeekTo(stream, pos)) + *startOffset = (Int64)pos; + } + { + CXzStreamFlags headerFlags; + CSecToRead secToRead; + SecToRead_CreateVTable(&secToRead); + secToRead.realStream = stream; + + RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt)) + return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE; + } +} + + +/* ---------- Xz Streams ---------- */ + +void Xzs_Construct(CXzs *p) +{ + p->num = p->numAllocated = 0; + p->streams = 0; +} + +void Xzs_Free(CXzs *p, ISzAllocPtr alloc) +{ + size_t i; + for (i = 0; i < p->num; i++) + Xz_Free(&p->streams[i], alloc); + ISzAlloc_Free(alloc, p->streams); + p->num = p->numAllocated = 0; + p->streams = 0; +} + +UInt64 Xzs_GetNumBlocks(const CXzs *p) +{ + UInt64 num = 0; + size_t i; + for (i = 0; i < p->num; i++) + num += p->streams[i].numBlocks; + return num; +} + +UInt64 Xzs_GetUnpackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + { + ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i])) + } + return size; +} + +/* +UInt64 Xzs_GetPackSize(const CXzs *p) +{ + UInt64 size = 0; + size_t i; + for (i = 0; i < p->num; i++) + { + ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i])) + } + return size; +} +*/ + +SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc) +{ + Int64 endOffset = 0; + RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END)) + *startOffset = endOffset; + for (;;) + { + CXzStream st; + SRes res; + Xz_Construct(&st); + res = Xz_ReadBackward(&st, stream, startOffset, alloc); + st.startOffset = (UInt64)*startOffset; + RINOK(res) + if (p->num == p->numAllocated) + { + const size_t newNum = p->num + p->num / 4 + 1; + void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream)); + if (!data) + return SZ_ERROR_MEM; + p->numAllocated = newNum; + if (p->num != 0) + memcpy(data, p->streams, p->num * sizeof(CXzStream)); + ISzAlloc_Free(alloc, p->streams); + p->streams = (CXzStream *)data; + } + p->streams[p->num++] = st; + if (*startOffset == 0) + break; + RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset)) + if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK) + return SZ_ERROR_PROGRESS; + } + return SZ_OK; +} diff --git a/C/ZstdDec.c b/C/ZstdDec.c index ef9eca3d7..6ad47ebcf 100644 --- a/C/ZstdDec.c +++ b/C/ZstdDec.c @@ -1,4067 +1,4067 @@ -/* ZstdDec.c -- Zstd Decoder -2024-06-18 : the code was developed by Igor Pavlov, using Zstandard format - specification and original zstd decoder code as reference code. -original zstd decoder code: Copyright (c) Facebook, Inc. All rights reserved. -This source code is licensed under BSD 3-Clause License. -*/ - -#include "Precomp.h" - -#include -#include -// #include - -#include "Alloc.h" -#include "Xxh64.h" -#include "ZstdDec.h" -#include "CpuArch.h" - -#if defined(MY_CPU_ARM64) -#include -#endif - -/* original-zstd still doesn't support window larger than 2 GiB. - So we also limit our decoder for 2 GiB window: */ -#if defined(MY_CPU_64BIT) && 0 == 1 - #define MAX_WINDOW_SIZE_LOG 41 -#else - #define MAX_WINDOW_SIZE_LOG 31 -#endif - -typedef - #if MAX_WINDOW_SIZE_LOG < 32 - UInt32 - #else - size_t - #endif - CZstdDecOffset; - -// for debug: simpler and smaller code but slow: -// #define Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS - -// #define SHOW_STAT -#ifdef SHOW_STAT -#include -static unsigned g_Num_Blocks_Compressed = 0; -static unsigned g_Num_Blocks_memcpy = 0; -static unsigned g_Num_Wrap_memmove_Num = 0; -static unsigned g_Num_Wrap_memmove_Bytes = 0; -static unsigned g_NumSeqs_total = 0; -// static unsigned g_NumCopy = 0; -static unsigned g_NumOver = 0; -static unsigned g_NumOver2 = 0; -static unsigned g_Num_Match = 0; -static unsigned g_Num_Lits = 0; -static unsigned g_Num_LitsBig = 0; -static unsigned g_Num_Lit0 = 0; -static unsigned g_Num_Rep0 = 0; -static unsigned g_Num_Rep1 = 0; -static unsigned g_Num_Rep2 = 0; -static unsigned g_Num_Rep3 = 0; -static unsigned g_Num_Threshold_0 = 0; -static unsigned g_Num_Threshold_1 = 0; -static unsigned g_Num_Threshold_0sum = 0; -static unsigned g_Num_Threshold_1sum = 0; -#define STAT_UPDATE(v) v -#else -#define STAT_UPDATE(v) -#endif -#define STAT_INC(v) STAT_UPDATE(v++;) - - -typedef struct -{ - const Byte *ptr; - size_t len; -} -CInBufPair; - - -#if defined(MY_CPU_ARM_OR_ARM64) || defined(MY_CPU_X86_OR_AMD64) - #if (defined(__clang__) && (__clang_major__ >= 6)) \ - || (defined(__GNUC__) && (__GNUC__ >= 6)) - // disable for debug: - #define Z7_ZSTD_DEC_USE_BSR - #elif defined(_MSC_VER) && (_MSC_VER >= 1300) - // #if defined(MY_CPU_ARM_OR_ARM64) - #if (_MSC_VER >= 1600) - #include - #endif - // disable for debug: - #define Z7_ZSTD_DEC_USE_BSR - #endif -#endif - -#ifdef Z7_ZSTD_DEC_USE_BSR - #if defined(__clang__) || defined(__GNUC__) - #define MY_clz(x) ((unsigned)__builtin_clz((UInt32)x)) - #else // #if defined(_MSC_VER) - #ifdef MY_CPU_ARM_OR_ARM64 - #define MY_clz _CountLeadingZeros - #endif // MY_CPU_X86_OR_AMD64 - #endif // _MSC_VER -#elif !defined(Z7_ZSTD_DEC_USE_LOG_TABLE) - #define Z7_ZSTD_DEC_USE_LOG_TABLE -#endif - - -static -Z7_FORCE_INLINE -unsigned GetHighestSetBit_32_nonzero_big(UInt32 num) -{ - // (num != 0) - #ifdef MY_clz - return 31 - MY_clz(num); - #elif defined(Z7_ZSTD_DEC_USE_BSR) - { - unsigned long zz; - _BitScanReverse(&zz, num); - return zz; - } - #else - { - int i = -1; - for (;;) - { - i++; - num >>= 1; - if (num == 0) - return (unsigned)i; - } - } - #endif -} - -#ifdef Z7_ZSTD_DEC_USE_LOG_TABLE - -#define R1(a) a, a -#define R2(a) R1(a), R1(a) -#define R3(a) R2(a), R2(a) -#define R4(a) R3(a), R3(a) -#define R5(a) R4(a), R4(a) -#define R6(a) R5(a), R5(a) -#define R7(a) R6(a), R6(a) -#define R8(a) R7(a), R7(a) -#define R9(a) R8(a), R8(a) - -#define Z7_ZSTD_FSE_MAX_ACCURACY 9 -// states[] values in FSE_Generate() can use (Z7_ZSTD_FSE_MAX_ACCURACY + 1) bits. -static const Byte k_zstd_LogTable[2 << Z7_ZSTD_FSE_MAX_ACCURACY] = -{ - R1(0), R1(1), R2(2), R3(3), R4(4), R5(5), R6(6), R7(7), R8(8), R9(9) -}; - -#define GetHighestSetBit_32_nonzero_small(num) (k_zstd_LogTable[num]) -#else -#define GetHighestSetBit_32_nonzero_small GetHighestSetBit_32_nonzero_big -#endif - - -#ifdef MY_clz - #define UPDATE_BIT_OFFSET_FOR_PADDING(b, bitOffset) \ - bitOffset -= (CBitCtr)(MY_clz(b) - 23); -#elif defined(Z7_ZSTD_DEC_USE_BSR) - #define UPDATE_BIT_OFFSET_FOR_PADDING(b, bitOffset) \ - { unsigned long zz; _BitScanReverse(&zz, b); bitOffset -= 8; bitOffset += zz; } -#else - #define UPDATE_BIT_OFFSET_FOR_PADDING(b, bitOffset) \ - for (;;) { bitOffset--; if (b & 0x80) { break; } b <<= 1; } -#endif - -#define SET_bitOffset_TO_PAD(bitOffset, src, srcLen) \ -{ \ - unsigned lastByte = (src)[(size_t)(srcLen) - 1]; \ - if (lastByte == 0) return SZ_ERROR_DATA; \ - bitOffset = (CBitCtr)((srcLen) * 8); \ - UPDATE_BIT_OFFSET_FOR_PADDING(lastByte, bitOffset) \ -} - -#ifndef Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS - -#define SET_bitOffset_TO_PAD_and_SET_BIT_SIZE(bitOffset, src, srcLen_res) \ -{ \ - unsigned lastByte = (src)[(size_t)(srcLen_res) - 1]; \ - if (lastByte == 0) return SZ_ERROR_DATA; \ - srcLen_res *= 8; \ - bitOffset = (CBitCtr)srcLen_res; \ - UPDATE_BIT_OFFSET_FOR_PADDING(lastByte, bitOffset) \ -} - -#endif - -/* -typedef Int32 CBitCtr_signed; -typedef Int32 CBitCtr; -*/ -// /* -typedef ptrdiff_t CBitCtr_signed; -typedef ptrdiff_t CBitCtr; -// */ - - -#define MATCH_LEN_MIN 3 -#define kBlockSizeMax (1u << 17) - -// #define Z7_ZSTD_DEC_PRINT_TABLE - -#ifdef Z7_ZSTD_DEC_PRINT_TABLE -#define NUM_OFFSET_SYMBOLS_PREDEF 29 -#endif -#define NUM_OFFSET_SYMBOLS_MAX (MAX_WINDOW_SIZE_LOG + 1) // 32 -#define NUM_LL_SYMBOLS 36 -#define NUM_ML_SYMBOLS 53 -#define FSE_NUM_SYMBOLS_MAX 53 // NUM_ML_SYMBOLS - -// /* -#if !defined(MY_CPU_X86) || defined(__PIC__) || defined(MY_CPU_64BIT) -#define Z7_ZSTD_DEC_USE_BASES_IN_OBJECT -#endif -// */ -// for debug: -// #define Z7_ZSTD_DEC_USE_BASES_LOCAL -// #define Z7_ZSTD_DEC_USE_BASES_IN_OBJECT - -#define GLOBAL_TABLE(n) k_ ## n - -#if defined(Z7_ZSTD_DEC_USE_BASES_LOCAL) - #define BASES_TABLE(n) a_ ## n -#elif defined(Z7_ZSTD_DEC_USE_BASES_IN_OBJECT) - #define BASES_TABLE(n) p->m_ ## n -#else - #define BASES_TABLE(n) GLOBAL_TABLE(n) -#endif - -#define Z7_ZSTD_DEC_USE_ML_PLUS3 - -#if defined(Z7_ZSTD_DEC_USE_BASES_LOCAL) || \ - defined(Z7_ZSTD_DEC_USE_BASES_IN_OBJECT) - -#define SEQ_EXTRA_TABLES(n) \ - Byte n ## SEQ_LL_EXTRA [NUM_LL_SYMBOLS]; \ - Byte n ## SEQ_ML_EXTRA [NUM_ML_SYMBOLS]; \ - UInt32 n ## SEQ_LL_BASES [NUM_LL_SYMBOLS]; \ - UInt32 n ## SEQ_ML_BASES [NUM_ML_SYMBOLS]; \ - -#define Z7_ZSTD_DEC_USE_BASES_CALC - -#ifdef Z7_ZSTD_DEC_USE_BASES_CALC - - #define FILL_LOC_BASES(n, startSum) \ - { unsigned i; UInt32 sum = startSum; \ - for (i = 0; i != Z7_ARRAY_SIZE(GLOBAL_TABLE(n ## _EXTRA)); i++) \ - { const unsigned a = GLOBAL_TABLE(n ## _EXTRA)[i]; \ - BASES_TABLE(n ## _BASES)[i] = sum; \ - /* if (sum != GLOBAL_TABLE(n ## _BASES)[i]) exit(1); */ \ - sum += (UInt32)1 << a; \ - BASES_TABLE(n ## _EXTRA)[i] = (Byte)a; }} - - #define FILL_LOC_BASES_ALL \ - FILL_LOC_BASES (SEQ_LL, 0) \ - FILL_LOC_BASES (SEQ_ML, MATCH_LEN_MIN) \ - -#else - #define COPY_GLOBAL_ARR(n) \ - memcpy(BASES_TABLE(n), GLOBAL_TABLE(n), sizeof(GLOBAL_TABLE(n))); - #define FILL_LOC_BASES_ALL \ - COPY_GLOBAL_ARR (SEQ_LL_EXTRA) \ - COPY_GLOBAL_ARR (SEQ_ML_EXTRA) \ - COPY_GLOBAL_ARR (SEQ_LL_BASES) \ - COPY_GLOBAL_ARR (SEQ_ML_BASES) \ - -#endif - -#endif - - - -/// The sequence decoding baseline and number of additional bits to read/add -#if !defined(Z7_ZSTD_DEC_USE_BASES_CALC) -static const UInt32 GLOBAL_TABLE(SEQ_LL_BASES) [NUM_LL_SYMBOLS] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, - 0x2000, 0x4000, 0x8000, 0x10000 -}; -#endif - -static const Byte GLOBAL_TABLE(SEQ_LL_EXTRA) [NUM_LL_SYMBOLS] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16 -}; - -#if !defined(Z7_ZSTD_DEC_USE_BASES_CALC) -static const UInt32 GLOBAL_TABLE(SEQ_ML_BASES) [NUM_ML_SYMBOLS] = -{ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, - 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 -}; -#endif - -static const Byte GLOBAL_TABLE(SEQ_ML_EXTRA) [NUM_ML_SYMBOLS] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16 -}; - - -#ifdef Z7_ZSTD_DEC_PRINT_TABLE - -static const Int16 SEQ_LL_PREDEF_DIST [NUM_LL_SYMBOLS] = -{ - 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, - -1,-1,-1,-1 -}; -static const Int16 SEQ_OFFSET_PREDEF_DIST [NUM_OFFSET_SYMBOLS_PREDEF] = -{ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 -}; -static const Int16 SEQ_ML_PREDEF_DIST [NUM_ML_SYMBOLS] = -{ - 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1, - -1,-1,-1,-1,-1 -}; - -#endif - -// typedef int FastInt; -// typedef Int32 FastInt32; -typedef unsigned FastInt; -typedef UInt32 FastInt32; -typedef FastInt32 CFseRecord; - - -#define FSE_REC_LEN_OFFSET 8 -#define FSE_REC_STATE_OFFSET 16 -#define GET_FSE_REC_SYM(st) ((Byte)(st)) -#define GET_FSE_REC_LEN(st) ((Byte)((st) >> FSE_REC_LEN_OFFSET)) -#define GET_FSE_REC_STATE(st) ((st) >> FSE_REC_STATE_OFFSET) - -// #define FSE_REC_SYM_MASK (0xff) -// #define GET_FSE_REC_SYM(st) (st & FSE_REC_SYM_MASK) - -#define W_BASE(state, len, sym) \ - (((UInt32)state << (4 + FSE_REC_STATE_OFFSET)) + \ - (len << FSE_REC_LEN_OFFSET) + (sym)) -#define W(state, len, sym) W_BASE(state, len, sym) -static const CFseRecord k_PredefRecords_LL[1 << 6] = { -W(0,4, 0),W(1,4, 0),W(2,5, 1),W(0,5, 3),W(0,5, 4),W(0,5, 6),W(0,5, 7),W(0,5, 9), -W(0,5,10),W(0,5,12),W(0,6,14),W(0,5,16),W(0,5,18),W(0,5,19),W(0,5,21),W(0,5,22), -W(0,5,24),W(2,5,25),W(0,5,26),W(0,6,27),W(0,6,29),W(0,6,31),W(2,4, 0),W(0,4, 1), -W(0,5, 2),W(2,5, 4),W(0,5, 5),W(2,5, 7),W(0,5, 8),W(2,5,10),W(0,5,11),W(0,6,13), -W(2,5,16),W(0,5,17),W(2,5,19),W(0,5,20),W(2,5,22),W(0,5,23),W(0,4,25),W(1,4,25), -W(2,5,26),W(0,6,28),W(0,6,30),W(3,4, 0),W(1,4, 1),W(2,5, 2),W(2,5, 3),W(2,5, 5), -W(2,5, 6),W(2,5, 8),W(2,5, 9),W(2,5,11),W(2,5,12),W(0,6,15),W(2,5,17),W(2,5,18), -W(2,5,20),W(2,5,21),W(2,5,23),W(2,5,24),W(0,6,35),W(0,6,34),W(0,6,33),W(0,6,32) -}; -static const CFseRecord k_PredefRecords_OF[1 << 5] = { -W(0,5, 0),W(0,4, 6),W(0,5, 9),W(0,5,15),W(0,5,21),W(0,5, 3),W(0,4, 7),W(0,5,12), -W(0,5,18),W(0,5,23),W(0,5, 5),W(0,4, 8),W(0,5,14),W(0,5,20),W(0,5, 2),W(1,4, 7), -W(0,5,11),W(0,5,17),W(0,5,22),W(0,5, 4),W(1,4, 8),W(0,5,13),W(0,5,19),W(0,5, 1), -W(1,4, 6),W(0,5,10),W(0,5,16),W(0,5,28),W(0,5,27),W(0,5,26),W(0,5,25),W(0,5,24) -}; -#if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) -#undef W -#define W(state, len, sym) W_BASE(state, len, (sym + MATCH_LEN_MIN)) -#endif -static const CFseRecord k_PredefRecords_ML[1 << 6] = { -W(0,6, 0),W(0,4, 1),W(2,5, 2),W(0,5, 3),W(0,5, 5),W(0,5, 6),W(0,5, 8),W(0,6,10), -W(0,6,13),W(0,6,16),W(0,6,19),W(0,6,22),W(0,6,25),W(0,6,28),W(0,6,31),W(0,6,33), -W(0,6,35),W(0,6,37),W(0,6,39),W(0,6,41),W(0,6,43),W(0,6,45),W(1,4, 1),W(0,4, 2), -W(2,5, 3),W(0,5, 4),W(2,5, 6),W(0,5, 7),W(0,6, 9),W(0,6,12),W(0,6,15),W(0,6,18), -W(0,6,21),W(0,6,24),W(0,6,27),W(0,6,30),W(0,6,32),W(0,6,34),W(0,6,36),W(0,6,38), -W(0,6,40),W(0,6,42),W(0,6,44),W(2,4, 1),W(3,4, 1),W(1,4, 2),W(2,5, 4),W(2,5, 5), -W(2,5, 7),W(2,5, 8),W(0,6,11),W(0,6,14),W(0,6,17),W(0,6,20),W(0,6,23),W(0,6,26), -W(0,6,29),W(0,6,52),W(0,6,51),W(0,6,50),W(0,6,49),W(0,6,48),W(0,6,47),W(0,6,46) -}; - - -// sum of freqs[] must be correct -// (numSyms != 0) -// (accuracy >= 5) -static -Z7_NO_INLINE -// Z7_FORCE_INLINE -void FSE_Generate(CFseRecord *table, - const Int16 *const freqs, const size_t numSyms, - const unsigned accuracy, UInt32 delta) -{ - size_t size = (size_t)1 << accuracy; - // max value in states[x] is ((1 << accuracy) * 2) - UInt16 states[FSE_NUM_SYMBOLS_MAX]; - { - /* Symbols with "less than 1" probability get a single cell, - starting from the end of the table. - These symbols define a full state reset, reading (accuracy) bits. */ - size_t threshold = size; - { - size_t s = 0; - do - if (freqs[s] == -1) - { - table[--threshold] = (CFseRecord)s; - states[s] = 1; - } - while (++s != numSyms); - } - - #ifdef SHOW_STAT - if (threshold == size) - { - STAT_INC(g_Num_Threshold_0) - STAT_UPDATE(g_Num_Threshold_0sum += (unsigned)size;) - } - else - { - STAT_INC(g_Num_Threshold_1) - STAT_UPDATE(g_Num_Threshold_1sum += (unsigned)size;) - } - #endif - - // { unsigned uuu; for (uuu = 0; uuu < 400; uuu++) - { - // Each (symbol) gets freqs[symbol] cells. - // Cell allocation is spread, not linear. - const size_t step = (size >> 1) + (size >> 3) + 3; - size_t pos = 0; - // const unsigned mask = size - 1; - /* - if (threshold == size) - { - size_t s = 0; - size--; - do - { - int freq = freqs[s]; - if (freq <= 0) - continue; - states[s] = (UInt16)freq; - do - { - table[pos] (CFseRecord)s; - pos = (pos + step) & size; // & mask; - } - while (--freq); - } - while (++s != numSyms); - } - else - */ - { - size_t s = 0; - size--; - do - { - int freq = freqs[s]; - if (freq <= 0) - continue; - states[s] = (UInt16)freq; - do - { - table[pos] = (CFseRecord)s; - // we skip position, if it's already occupied by a "less than 1" probability symbol. - // (step) is coprime to table size, so the cycle will visit each position exactly once - do - pos = (pos + step) & size; // & mask; - while (pos >= threshold); - } - while (--freq); - } - while (++s != numSyms); - } - size++; - // (pos != 0) is unexpected case that means that freqs[] are not correct. - // so it's some failure in code (for example, incorrect predefined freq[] table) - // if (pos != 0) return SZ_ERROR_FAIL; - } - // } - } - { - const CFseRecord * const limit = table + size; - delta = ((UInt32)size << FSE_REC_STATE_OFFSET) - delta; - /* State increases by symbol over time, decreasing number of bits. - Baseline increases until the bit threshold is passed, at which point it resets to 0 */ - do - { - #define TABLE_ITER(a) \ - { \ - const FastInt sym = (FastInt)table[a]; \ - const unsigned nextState = states[sym]; \ - unsigned nb; \ - states[sym] = (UInt16)(nextState + 1); \ - nb = accuracy - GetHighestSetBit_32_nonzero_small(nextState); \ - table[a] = (CFseRecord)(sym - delta \ - + ((UInt32)nb << FSE_REC_LEN_OFFSET) \ - + ((UInt32)nextState << FSE_REC_STATE_OFFSET << nb)); \ - } - TABLE_ITER(0) - TABLE_ITER(1) - table += 2; - } - while (table != limit); - } -} - - -#ifdef Z7_ZSTD_DEC_PRINT_TABLE - -static void Print_Predef(unsigned predefAccuracy, - const unsigned numSymsPredef, - const Int16 * const predefFreqs, - const CFseRecord *checkTable) -{ - CFseRecord table[1 << 6]; - unsigned i; - FSE_Generate(table, predefFreqs, numSymsPredef, predefAccuracy, - #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) - numSymsPredef == NUM_ML_SYMBOLS ? MATCH_LEN_MIN : - #endif - 0 - ); - if (memcmp(table, checkTable, sizeof(UInt32) << predefAccuracy) != 0) - exit(1); - for (i = 0; i < (1u << predefAccuracy); i++) - { - const UInt32 v = table[i]; - const unsigned state = (unsigned)(GET_FSE_REC_STATE(v)); - if (state & 0xf) - exit(1); - if (i != 0) - { - printf(","); - if (i % 8 == 0) - printf("\n"); - } - printf("W(%d,%d,%2d)", - (unsigned)(state >> 4), - (unsigned)((v >> FSE_REC_LEN_OFFSET) & 0xff), - (unsigned)GET_FSE_REC_SYM(v)); - } - printf("\n\n"); -} - -#endif - - -#define GET16(dest, p) { const Byte *ptr = p; dest = GetUi16(ptr); } -#define GET32(dest, p) { const Byte *ptr = p; dest = GetUi32(ptr); } - -// (1 <= numBits <= 9) -#define FORWARD_READ_BITS(destVal, numBits, mask) \ - { const CBitCtr_signed bos3 = (bitOffset) >> 3; \ - if (bos3 >= 0) return SZ_ERROR_DATA; \ - GET16(destVal, src + bos3) \ - destVal >>= (bitOffset) & 7; \ - bitOffset += (CBitCtr_signed)(numBits); \ - mask = (1u << (numBits)) - 1; \ - destVal &= mask; \ - } - -#define FORWARD_READ_1BIT(destVal) \ - { const CBitCtr_signed bos3 = (bitOffset) >> 3; \ - if (bos3 >= 0) return SZ_ERROR_DATA; \ - destVal = *(src + bos3); \ - destVal >>= (bitOffset) & 7; \ - (bitOffset)++; \ - destVal &= 1; \ - } - - -// in: (accuracyMax <= 9) -// at least 2 bytes will be processed from (in) stream. -// at return: (in->len > 0) -static -Z7_NO_INLINE -SRes FSE_DecodeHeader(CFseRecord *const table, - CInBufPair *const in, - const unsigned accuracyMax, - Byte *const accuracyRes, - unsigned numSymbolsMax) -{ - unsigned accuracy; - unsigned remain1; - unsigned syms; - Int16 freqs[FSE_NUM_SYMBOLS_MAX + 3]; // +3 for overwrite (repeat) - const Byte *src = in->ptr; - CBitCtr_signed bitOffset = (CBitCtr_signed)in->len - 1; - if (bitOffset <= 0) - return SZ_ERROR_DATA; - accuracy = *src & 0xf; - accuracy += 5; - if (accuracy > accuracyMax) - return SZ_ERROR_DATA; - *accuracyRes = (Byte)accuracy; - remain1 = (1u << accuracy) + 1; // (it's remain_freqs_sum + 1) - syms = 0; - src += bitOffset; // src points to last byte - bitOffset = 4 - (bitOffset << 3); - - for (;;) - { - // (2 <= remain1) - const unsigned bits = GetHighestSetBit_32_nonzero_small((unsigned)remain1); - // (1 <= bits <= accuracy) - unsigned val; // it must be unsigned or int - unsigned mask; - FORWARD_READ_BITS(val, bits, mask) - { - const unsigned val2 = remain1 + val - mask; - if (val2 > mask) - { - unsigned bit; - FORWARD_READ_1BIT(bit) - if (bit) - val = val2; - } - } - { - // (remain1 >= 2) - // (0 <= (int)val <= remain1) - val = (unsigned)((int)val - 1); - // val now is "probability" of symbol - // (probability == -1) means "less than 1" frequency. - // (-1 <= (int)val <= remain1 - 1) - freqs[syms++] = (Int16)(int)val; - if (val != 0) - { - remain1 -= (int)val < 0 ? 1u : (unsigned)val; - // remain1 -= val; - // val >>= (sizeof(val) * 8 - 2); - // remain1 -= val & 2; - // freqs[syms++] = (Int16)(int)val; - // syms++; - if (remain1 == 1) - break; - if (syms >= FSE_NUM_SYMBOLS_MAX) - return SZ_ERROR_DATA; - } - else // if (val == 0) - { - // freqs[syms++] = 0; - // syms++; - for (;;) - { - unsigned repeat; - FORWARD_READ_BITS(repeat, 2, mask) - freqs[syms ] = 0; - freqs[syms + 1] = 0; - freqs[syms + 2] = 0; - syms += repeat; - if (syms >= FSE_NUM_SYMBOLS_MAX) - return SZ_ERROR_DATA; - if (repeat != 3) - break; - } - } - } - } - - if (syms > numSymbolsMax) - return SZ_ERROR_DATA; - bitOffset += 7; - bitOffset >>= 3; - if (bitOffset > 0) - return SZ_ERROR_DATA; - in->ptr = src + bitOffset; - in->len = (size_t)(1 - bitOffset); - { - // unsigned uuu; for (uuu = 0; uuu < 50; uuu++) - FSE_Generate(table, freqs, syms, accuracy, - #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) - numSymbolsMax == NUM_ML_SYMBOLS ? MATCH_LEN_MIN : - #endif - 0 - ); - } - return SZ_OK; -} - - -// ---------- HUFFMAN ---------- - -#define HUF_MAX_BITS 12 -#define HUF_MAX_SYMBS 256 -#define HUF_DUMMY_SIZE (128 + 8 * 2) // it must multiple of 8 -// #define HUF_DUMMY_SIZE 0 -#define HUF_TABLE_SIZE ((2 << HUF_MAX_BITS) + HUF_DUMMY_SIZE) -#define HUF_GET_SYMBOLS(table) ((table) + (1 << HUF_MAX_BITS) + HUF_DUMMY_SIZE) -// #define HUF_GET_LENS(table) (table) - -typedef struct -{ - // Byte table[HUF_TABLE_SIZE]; - UInt64 table64[HUF_TABLE_SIZE / sizeof(UInt64)]; -} -CZstdDecHufTable; - -/* -Input: - numSyms != 0 - (bits) array size must be aligned for 2 - if (numSyms & 1), then bits[numSyms] == 0, - Huffman tree must be correct before Huf_Build() call: - (sum (1/2^bits[i]) == 1). - && (bits[i] <= HUF_MAX_BITS) -*/ -static -Z7_FORCE_INLINE -void Huf_Build(Byte * const table, - const Byte *bits, const unsigned numSyms) -{ - unsigned counts0[HUF_MAX_BITS + 1]; - unsigned counts1[HUF_MAX_BITS + 1]; - const Byte * const bitsEnd = bits + numSyms; - // /* - { - unsigned t; - for (t = 0; t < Z7_ARRAY_SIZE(counts0); t++) counts0[t] = 0; - for (t = 0; t < Z7_ARRAY_SIZE(counts1); t++) counts1[t] = 0; - } - // */ - // memset(counts0, 0, sizeof(counts0)); - // memset(counts1, 0, sizeof(counts1)); - { - const Byte *bits2 = bits; - // we access additional bits[symbol] if (numSyms & 1) - do - { - counts0[bits2[0]]++; - counts1[bits2[1]]++; - } - while ((bits2 += 2) < bitsEnd); - } - { - unsigned r = 0; - unsigned i = HUF_MAX_BITS; - // Byte *lens = HUF_GET_LENS(symbols); - do - { - const unsigned num = (counts0[i] + counts1[i]) << (HUF_MAX_BITS - i); - counts0[i] = r; - if (num) - { - Byte *lens = &table[r]; - r += num; - memset(lens, (int)i, num); - } - } - while (--i); - counts0[0] = 0; // for speculated loads - // no need for check: - // if (r != (UInt32)1 << HUF_MAX_BITS) exit(0); - } - { - #ifdef MY_CPU_64BIT - UInt64 - #else - UInt32 - #endif - v = 0; - Byte *symbols = HUF_GET_SYMBOLS(table); - do - { - const unsigned nb = *bits++; - if (nb) - { - const unsigned code = counts0[nb]; - const unsigned num = (1u << HUF_MAX_BITS) >> nb; - counts0[nb] = code + num; - // memset(&symbols[code], i, num); - // /* - { - Byte *s2 = &symbols[code]; - if (num <= 2) - { - s2[0] = (Byte)v; - s2[(size_t)num - 1] = (Byte)v; - } - else if (num <= 8) - { - *(UInt32 *)(void *)s2 = (UInt32)v; - *(UInt32 *)(void *)(s2 + (size_t)num - 4) = (UInt32)v; - } - else - { - #ifdef MY_CPU_64BIT - UInt64 *s = (UInt64 *)(void *)s2; - const UInt64 *lim = (UInt64 *)(void *)(s2 + num); - do - { - s[0] = v; s[1] = v; s += 2; - } - while (s != lim); - #else - UInt32 *s = (UInt32 *)(void *)s2; - const UInt32 *lim = (const UInt32 *)(const void *)(s2 + num); - do - { - s[0] = v; s[1] = v; s += 2; - s[0] = v; s[1] = v; s += 2; - } - while (s != lim); - #endif - } - } - // */ - } - v += - #ifdef MY_CPU_64BIT - 0x0101010101010101; - #else - 0x01010101; - #endif - } - while (bits != bitsEnd); - } -} - - - -// how many bytes (src) was moved back from original value. -// we need (HUF_SRC_OFFSET == 3) for optimized 32-bit memory access -#define HUF_SRC_OFFSET 3 - -// v <<= 8 - (bitOffset & 7) + numBits; -// v >>= 32 - HUF_MAX_BITS; -#define HUF_GET_STATE(v, bitOffset, numBits) \ - GET32(v, src + (HUF_SRC_OFFSET - 3) + ((CBitCtr_signed)bitOffset >> 3)) \ - v >>= 32 - HUF_MAX_BITS - 8 + ((unsigned)bitOffset & 7) - numBits; \ - v &= (1u << HUF_MAX_BITS) - 1; \ - - -#ifndef Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS -#if defined(MY_CPU_AMD64) && defined(_MSC_VER) && _MSC_VER == 1400 \ - || !defined(MY_CPU_X86_OR_AMD64) \ - // || 1 == 1 /* for debug : to force STREAM4_PRELOAD mode */ - // we need big number (>=16) of registers for PRELOAD4 - #define Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD4 - // #define Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD2 // for debug -#endif -#endif - -// for debug: simpler and smaller code but slow: -// #define Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE - -#if defined(Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE) || \ - !defined(Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS) - -#define HUF_DECODE(bitOffset, dest) \ -{ \ - UInt32 v; \ - HUF_GET_STATE(v, bitOffset, 0) \ - bitOffset -= table[v]; \ - *(dest) = symbols[v]; \ - if ((CBitCtr_signed)bitOffset < 0) return SZ_ERROR_DATA; \ -} - -#endif - -#if !defined(Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE) || \ - defined(Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD4) || \ - defined(Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD2) \ - -#define HUF_DECODE_2_INIT(v, bitOffset) \ - HUF_GET_STATE(v, bitOffset, 0) - -#define HUF_DECODE_2(v, bitOffset, dest) \ -{ \ - unsigned numBits; \ - numBits = table[v]; \ - *(dest) = symbols[v]; \ - HUF_GET_STATE(v, bitOffset, numBits) \ - bitOffset -= (CBitCtr)numBits; \ - if ((CBitCtr_signed)bitOffset < 0) return SZ_ERROR_DATA; \ -} - -#endif - - -// src == ptr - HUF_SRC_OFFSET -// we are allowed to access 3 bytes before start of input buffer -static -Z7_NO_INLINE -SRes Huf_Decompress_1stream(const Byte * const table, - const Byte *src, const size_t srcLen, - Byte *dest, const size_t destLen) -{ - CBitCtr bitOffset; - if (srcLen == 0) - return SZ_ERROR_DATA; - SET_bitOffset_TO_PAD (bitOffset, src + HUF_SRC_OFFSET, srcLen) - if (destLen) - { - const Byte *symbols = HUF_GET_SYMBOLS(table); - const Byte *destLim = dest + destLen; - #ifdef Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE - { - do - { - HUF_DECODE (bitOffset, dest) - } - while (++dest != destLim); - } - #else - { - UInt32 v; - HUF_DECODE_2_INIT (v, bitOffset) - do - { - HUF_DECODE_2 (v, bitOffset, dest) - } - while (++dest != destLim); - } - #endif - } - return bitOffset == 0 ? SZ_OK : SZ_ERROR_DATA; -} - - -// for debug : it reduces register pressure : by array copy can be slow : -// #define Z7_ZSTD_DEC_USE_HUF_LOCAL - -// src == ptr + (6 - HUF_SRC_OFFSET) -// srcLen >= 10 -// we are allowed to access 3 bytes before start of input buffer -static -Z7_NO_INLINE -SRes Huf_Decompress_4stream(const Byte * const - #ifdef Z7_ZSTD_DEC_USE_HUF_LOCAL - table2, - #else - table, - #endif - const Byte *src, size_t srcLen, - Byte *dest, size_t destLen) -{ - #ifdef Z7_ZSTD_DEC_USE_HUF_LOCAL - Byte table[HUF_TABLE_SIZE]; - #endif - UInt32 sizes[3]; - const size_t delta = (destLen + 3) / 4; - if ((sizes[0] = GetUi16(src + (0 + HUF_SRC_OFFSET - 6))) == 0) return SZ_ERROR_DATA; - if ((sizes[1] = GetUi16(src + (2 + HUF_SRC_OFFSET - 6))) == 0) return SZ_ERROR_DATA; - sizes[1] += sizes[0]; - if ((sizes[2] = GetUi16(src + (4 + HUF_SRC_OFFSET - 6))) == 0) return SZ_ERROR_DATA; - sizes[2] += sizes[1]; - srcLen -= 6; - if (srcLen <= sizes[2]) - return SZ_ERROR_DATA; - - #ifdef Z7_ZSTD_DEC_USE_HUF_LOCAL - { - // unsigned i = 0; for(; i < 1000; i++) - memcpy(table, table2, HUF_TABLE_SIZE); - } - #endif - - #ifndef Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS - { - CBitCtr bitOffset_0, - bitOffset_1, - bitOffset_2, - bitOffset_3; - { - SET_bitOffset_TO_PAD_and_SET_BIT_SIZE (bitOffset_0, src + HUF_SRC_OFFSET, sizes[0]) - SET_bitOffset_TO_PAD_and_SET_BIT_SIZE (bitOffset_1, src + HUF_SRC_OFFSET, sizes[1]) - SET_bitOffset_TO_PAD_and_SET_BIT_SIZE (bitOffset_2, src + HUF_SRC_OFFSET, sizes[2]) - SET_bitOffset_TO_PAD (bitOffset_3, src + HUF_SRC_OFFSET, srcLen) - } - { - const Byte * const symbols = HUF_GET_SYMBOLS(table); - Byte *destLim = dest + destLen - delta * 3; - - if (dest != destLim) - #ifdef Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD4 - { - UInt32 v_0, v_1, v_2, v_3; - HUF_DECODE_2_INIT (v_0, bitOffset_0) - HUF_DECODE_2_INIT (v_1, bitOffset_1) - HUF_DECODE_2_INIT (v_2, bitOffset_2) - HUF_DECODE_2_INIT (v_3, bitOffset_3) - // #define HUF_DELTA (1 << 17) / 4 - do - { - HUF_DECODE_2 (v_3, bitOffset_3, dest + delta * 3) - HUF_DECODE_2 (v_2, bitOffset_2, dest + delta * 2) - HUF_DECODE_2 (v_1, bitOffset_1, dest + delta) - HUF_DECODE_2 (v_0, bitOffset_0, dest) - } - while (++dest != destLim); - /* - {// unsigned y = 0; for (;y < 1; y++) - { - const size_t num = destLen - delta * 3; - Byte *orig = dest - num; - memmove (orig + delta , orig + HUF_DELTA, num); - memmove (orig + delta * 2, orig + HUF_DELTA * 2, num); - memmove (orig + delta * 3, orig + HUF_DELTA * 3, num); - }} - */ - } - #elif defined(Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD2) - { - UInt32 v_0, v_1, v_2, v_3; - HUF_DECODE_2_INIT (v_0, bitOffset_0) - HUF_DECODE_2_INIT (v_1, bitOffset_1) - do - { - HUF_DECODE_2 (v_0, bitOffset_0, dest) - HUF_DECODE_2 (v_1, bitOffset_1, dest + delta) - } - while (++dest != destLim); - dest = destLim - (destLen - delta * 3); - dest += delta * 2; - destLim += delta * 2; - HUF_DECODE_2_INIT (v_2, bitOffset_2) - HUF_DECODE_2_INIT (v_3, bitOffset_3) - do - { - HUF_DECODE_2 (v_2, bitOffset_2, dest) - HUF_DECODE_2 (v_3, bitOffset_3, dest + delta) - } - while (++dest != destLim); - dest -= delta * 2; - destLim -= delta * 2; - } - #else - { - do - { - HUF_DECODE (bitOffset_3, dest + delta * 3) - HUF_DECODE (bitOffset_2, dest + delta * 2) - HUF_DECODE (bitOffset_1, dest + delta) - HUF_DECODE (bitOffset_0, dest) - } - while (++dest != destLim); - } - #endif - - if (bitOffset_3 != (CBitCtr)sizes[2]) - return SZ_ERROR_DATA; - if (destLen &= 3) - { - destLim = dest + 4 - destLen; - do - { - HUF_DECODE (bitOffset_2, dest + delta * 2) - HUF_DECODE (bitOffset_1, dest + delta) - HUF_DECODE (bitOffset_0, dest) - } - while (++dest != destLim); - } - if ( bitOffset_0 != 0 - || bitOffset_1 != (CBitCtr)sizes[0] - || bitOffset_2 != (CBitCtr)sizes[1]) - return SZ_ERROR_DATA; - } - } - #else // Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS - { - unsigned i; - for (i = 0; i < 4; i++) - { - size_t d = destLen; - size_t size = srcLen; - if (i != 3) - { - d = delta; - size = sizes[i]; - } - if (i != 0) - size -= sizes[i - 1]; - destLen -= d; - RINOK(Huf_Decompress_1stream(table, src, size, dest, d)) - dest += d; - src += size; - } - } - #endif - - return SZ_OK; -} - - - -// (in->len != 0) -// we are allowed to access in->ptr[-3] -// at least 2 bytes in (in->ptr) will be processed -static SRes Huf_DecodeTable(CZstdDecHufTable *const p, CInBufPair *const in) -{ - Byte weights[HUF_MAX_SYMBS + 1]; // +1 for extra write for loop unroll - unsigned numSyms; - const unsigned header = *(in->ptr)++; - in->len--; - // memset(weights, 0, sizeof(weights)); - if (header >= 128) - { - // direct representation: 4 bits field (0-15) per weight - numSyms = header - 127; - // numSyms != 0 - { - const size_t numBytes = (numSyms + 1) / 2; - const Byte *const ws = in->ptr; - size_t i = 0; - if (in->len < numBytes) - return SZ_ERROR_DATA; - in->ptr += numBytes; - in->len -= numBytes; - do - { - const unsigned b = ws[i]; - weights[i * 2 ] = (Byte)(b >> 4); - weights[i * 2 + 1] = (Byte)(b & 0xf); - } - while (++i != numBytes); - /* 7ZIP: we can restore correct zero value for weights[numSyms], - if we want to use zero values starting from numSyms in code below. */ - // weights[numSyms] = 0; - } - } - else - { - #define MAX_ACCURACY_LOG_FOR_WEIGHTS 6 - CFseRecord table[1 << MAX_ACCURACY_LOG_FOR_WEIGHTS]; - - Byte accuracy; - const Byte *src; - size_t srcLen; - if (in->len < header) - return SZ_ERROR_DATA; - { - CInBufPair fse_stream; - fse_stream.len = header; - fse_stream.ptr = in->ptr; - in->ptr += header; - in->len -= header; - RINOK(FSE_DecodeHeader(table, &fse_stream, - MAX_ACCURACY_LOG_FOR_WEIGHTS, - &accuracy, - 16 // num weight symbols max (max-symbol is 15) - )) - // at least 2 bytes were processed in fse_stream. - // (srcLen > 0) after FSE_DecodeHeader() - // if (srcLen == 0) return SZ_ERROR_DATA; - src = fse_stream.ptr; - srcLen = fse_stream.len; - } - // we are allowed to access src[-5] - { - // unsigned yyy = 200; do { - CBitCtr bitOffset; - FastInt32 state1, state2; - SET_bitOffset_TO_PAD (bitOffset, src, srcLen) - state1 = accuracy; - src -= state1 >> 2; // src -= 1; // for GET16() optimization - state1 <<= FSE_REC_LEN_OFFSET; - state2 = state1; - numSyms = 0; - for (;;) - { - #define FSE_WEIGHT_DECODE(st) \ - { \ - const unsigned bits = GET_FSE_REC_LEN(st); \ - FastInt r; \ - GET16(r, src + (bitOffset >> 3)) \ - r >>= (unsigned)bitOffset & 7; \ - if ((CBitCtr_signed)(bitOffset -= (CBitCtr)bits) < 0) \ - { if (bitOffset + (CBitCtr)bits != 0) \ - return SZ_ERROR_DATA; \ - break; } \ - r &= 0xff; \ - r >>= 8 - bits; \ - st = table[GET_FSE_REC_STATE(st) + r]; \ - weights[numSyms++] = (Byte)GET_FSE_REC_SYM(st); \ - } - FSE_WEIGHT_DECODE (state1) - FSE_WEIGHT_DECODE (state2) - if (numSyms == HUF_MAX_SYMBS) - return SZ_ERROR_DATA; - } - // src += (unsigned)accuracy >> 2; } while (--yyy); - } - } - - // Build using weights: - { - UInt32 sum = 0; - { - // numSyms >= 1 - unsigned i = 0; - weights[numSyms] = 0; - do - { - sum += ((UInt32)1 << weights[i ]) & ~(UInt32)1; - sum += ((UInt32)1 << weights[i + 1]) & ~(UInt32)1; - i += 2; - } - while (i < numSyms); - if (sum == 0) - return SZ_ERROR_DATA; - } - { - const unsigned maxBits = GetHighestSetBit_32_nonzero_big(sum) + 1; - { - const UInt32 left = ((UInt32)1 << maxBits) - sum; - // (left != 0) - // (left) must be power of 2 in correct stream - if (left & (left - 1)) - return SZ_ERROR_DATA; - weights[numSyms++] = (Byte)GetHighestSetBit_32_nonzero_big(left); - } - // if (numSyms & 1) - weights[numSyms] = 0; // for loop unroll - // numSyms >= 2 - { - unsigned i = 0; - do - { - /* - #define WEIGHT_ITER(a) \ - { unsigned w = weights[i + (a)]; \ - const unsigned t = maxBits - w; \ - w = w ? t: w; \ - if (w > HUF_MAX_BITS) return SZ_ERROR_DATA; \ - weights[i + (a)] = (Byte)w; } - */ - // /* - #define WEIGHT_ITER(a) \ - { unsigned w = weights[i + (a)]; \ - if (w) { \ - w = maxBits - w; \ - if (w > HUF_MAX_BITS) return SZ_ERROR_DATA; \ - weights[i + (a)] = (Byte)w; }} - // */ - WEIGHT_ITER(0) - // WEIGHT_ITER(1) - // i += 2; - } - while (++i != numSyms); - } - } - } - { - // unsigned yyy; for (yyy = 0; yyy < 100; yyy++) - Huf_Build((Byte *)(void *)p->table64, weights, numSyms); - } - return SZ_OK; -} - - -typedef enum -{ - k_SeqMode_Predef = 0, - k_SeqMode_RLE = 1, - k_SeqMode_FSE = 2, - k_SeqMode_Repeat = 3 -} -z7_zstd_enum_SeqMode; - -// predefAccuracy == 5 for OFFSET symbols -// predefAccuracy == 6 for MATCH/LIT LEN symbols -static -SRes -Z7_NO_INLINE -// Z7_FORCE_INLINE -FSE_Decode_SeqTable(CFseRecord * const table, - CInBufPair * const in, - unsigned predefAccuracy, - Byte * const accuracyRes, - unsigned numSymbolsMax, - const CFseRecord * const predefs, - const unsigned seqMode) -{ - // UNUSED_VAR(numSymsPredef) - // UNUSED_VAR(predefFreqs) - if (seqMode == k_SeqMode_FSE) - { - // unsigned y = 50; CInBufPair in2 = *in; do { *in = in2; RINOK( - return - FSE_DecodeHeader(table, in, - predefAccuracy + 3, // accuracyMax - accuracyRes, - numSymbolsMax) - ; - // )} while (--y); return SZ_OK; - } - // numSymsMax = numSymsPredef + ((predefAccuracy & 1) * (32 - 29))); // numSymsMax - // numSymsMax == 32 for offsets - - if (seqMode == k_SeqMode_Predef) - { - *accuracyRes = (Byte)predefAccuracy; - memcpy(table, predefs, sizeof(UInt32) << predefAccuracy); - return SZ_OK; - } - - // (seqMode == k_SeqMode_RLE) - if (in->len == 0) - return SZ_ERROR_DATA; - in->len--; - { - const Byte *ptr = in->ptr; - const unsigned sym = ptr[0]; - in->ptr = ptr + 1; - if (sym >= numSymbolsMax) - return SZ_ERROR_DATA; - table[0] = (FastInt32)sym - #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) - + (numSymbolsMax == NUM_ML_SYMBOLS ? MATCH_LEN_MIN : 0) - #endif - ; - *accuracyRes = 0; - } - return SZ_OK; -} - - -typedef struct -{ - CFseRecord of[1 << 8]; - CFseRecord ll[1 << 9]; - CFseRecord ml[1 << 9]; -} -CZstdDecFseTables; - - -typedef struct -{ - Byte *win; - SizeT cycSize; - /* - if (outBuf_fromCaller) : cycSize = outBufSize_fromCaller - else { - if ( isCyclicMode) : cycSize = cyclic_buffer_size = (winSize + extra_space) - if (!isCyclicMode) : cycSize = ContentSize, - (isCyclicMode == true) if (ContetSize >= winSize) or ContetSize is unknown - } - */ - SizeT winPos; - - CZstdDecOffset reps[3]; - - Byte ll_accuracy; - Byte of_accuracy; - Byte ml_accuracy; - // Byte seqTables_wereSet; - Byte litHuf_wasSet; - - Byte *literalsBase; - - size_t winSize; // from header - size_t totalOutCheck; // totalOutCheck <= winSize - - #ifdef Z7_ZSTD_DEC_USE_BASES_IN_OBJECT - SEQ_EXTRA_TABLES(m_) - #endif - // UInt64 _pad_Alignment; // is not required now - CZstdDecFseTables fse; - CZstdDecHufTable huf; -} -CZstdDec1; - -#define ZstdDec1_GET_BLOCK_SIZE_LIMIT(p) \ - ((p)->winSize < kBlockSizeMax ? (UInt32)(p)->winSize : kBlockSizeMax) - -#define SEQ_TABLES_WERE_NOT_SET_ml_accuracy 1 // accuracy=1 is not used by zstd -#define IS_SEQ_TABLES_WERE_SET(p) (((p)->ml_accuracy != SEQ_TABLES_WERE_NOT_SET_ml_accuracy)) -// #define IS_SEQ_TABLES_WERE_SET(p) ((p)->seqTables_wereSet) - - -static void ZstdDec1_Construct(CZstdDec1 *p) -{ - #ifdef Z7_ZSTD_DEC_PRINT_TABLE - Print_Predef(6, NUM_LL_SYMBOLS, SEQ_LL_PREDEF_DIST, k_PredefRecords_LL); - Print_Predef(5, NUM_OFFSET_SYMBOLS_PREDEF, SEQ_OFFSET_PREDEF_DIST, k_PredefRecords_OF); - Print_Predef(6, NUM_ML_SYMBOLS, SEQ_ML_PREDEF_DIST, k_PredefRecords_ML); - #endif - - p->win = NULL; - p->cycSize = 0; - p->literalsBase = NULL; - #ifdef Z7_ZSTD_DEC_USE_BASES_IN_OBJECT - FILL_LOC_BASES_ALL - #endif -} - - -static void ZstdDec1_Init(CZstdDec1 *p) -{ - p->reps[0] = 1; - p->reps[1] = 4; - p->reps[2] = 8; - // p->seqTables_wereSet = False; - p->ml_accuracy = SEQ_TABLES_WERE_NOT_SET_ml_accuracy; - p->litHuf_wasSet = False; - p->totalOutCheck = 0; -} - - - -#ifdef MY_CPU_LE_UNALIGN - #define Z7_ZSTD_DEC_USE_UNALIGNED_COPY -#endif - -#ifdef Z7_ZSTD_DEC_USE_UNALIGNED_COPY - - #define COPY_CHUNK_SIZE 16 - - #define COPY_CHUNK_4_2(dest, src) \ - { \ - ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \ - ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \ - src += 4 * 2; \ - dest += 4 * 2; \ - } - - /* sse2 doesn't help here in GCC and CLANG. - so we disabled sse2 here */ - /* - #if defined(MY_CPU_AMD64) - #define Z7_ZSTD_DEC_USE_SSE2 - #elif defined(MY_CPU_X86) - #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ - || defined(__SSE2__) \ - // || 1 == 1 // for debug only - #define Z7_ZSTD_DEC_USE_SSE2 - #endif - #endif - */ - - #if defined(MY_CPU_ARM64) - #define COPY_OFFSET_MIN 16 - #define COPY_CHUNK1(dest, src) \ - { \ - vst1q_u8((uint8_t *)(void *)dest, \ - vld1q_u8((const uint8_t *)(const void *)src)); \ - src += 16; \ - dest += 16; \ - } - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK1(dest, src) \ - if ((len -= COPY_CHUNK_SIZE) == 0) break; \ - COPY_CHUNK1(dest, src) \ - } - - #elif defined(Z7_ZSTD_DEC_USE_SSE2) - #include // sse2 - #define COPY_OFFSET_MIN 16 - - #define COPY_CHUNK1(dest, src) \ - { \ - _mm_storeu_si128((__m128i *)(void *)dest, \ - _mm_loadu_si128((const __m128i *)(const void *)src)); \ - src += 16; \ - dest += 16; \ - } - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK1(dest, src) \ - if ((len -= COPY_CHUNK_SIZE) == 0) break; \ - COPY_CHUNK1(dest, src) \ - } - - #elif defined(MY_CPU_64BIT) - #define COPY_OFFSET_MIN 8 - - #define COPY_CHUNK(dest, src) \ - { \ - ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ - ((UInt64 *)(void *)dest)[1] = ((const UInt64 *)(const void *)src)[1]; \ - src += 8 * 2; \ - dest += 8 * 2; \ - } - - #else - #define COPY_OFFSET_MIN 4 - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK_4_2(dest, src); \ - COPY_CHUNK_4_2(dest, src); \ - } - - #endif -#endif - - -#ifndef COPY_CHUNK_SIZE - #define COPY_OFFSET_MIN 4 - #define COPY_CHUNK_SIZE 8 - #define COPY_CHUNK_2(dest, src) \ - { \ - const Byte a0 = src[0]; \ - const Byte a1 = src[1]; \ - dest[0] = a0; \ - dest[1] = a1; \ - src += 2; \ - dest += 2; \ - } - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - } -#endif - - -#define COPY_PREPARE \ - len += (COPY_CHUNK_SIZE - 1); \ - len &= ~(size_t)(COPY_CHUNK_SIZE - 1); \ - { if (len > rem) \ - { len = rem; \ - rem &= (COPY_CHUNK_SIZE - 1); \ - if (rem) { \ - len -= rem; \ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ - do *dest++ = *src++; while (--rem); \ - if (len == 0) return; }}} - -#define COPY_CHUNKS \ -{ \ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ - do { COPY_CHUNK(dest, src) } \ - while (len -= COPY_CHUNK_SIZE); \ -} - -// (len != 0) -// (len <= rem) -static -Z7_FORCE_INLINE -// Z7_ATTRIB_NO_VECTOR -void CopyLiterals(Byte *dest, Byte const *src, size_t len, size_t rem) -{ - COPY_PREPARE - COPY_CHUNKS -} - - -/* we can define Z7_STD_DEC_USE_AFTER_CYC_BUF, if we want to use additional - space after cycSize that can be used to reduce the code in CopyMatch(): */ -// for debug: -// #define Z7_STD_DEC_USE_AFTER_CYC_BUF - -/* -CopyMatch() -if wrap (offset > winPos) -{ - then we have at least (COPY_CHUNK_SIZE) avail in (dest) before we will overwrite (src): - (cycSize >= offset + COPY_CHUNK_SIZE) - if defined(Z7_STD_DEC_USE_AFTER_CYC_BUF) - we are allowed to read win[cycSize + COPY_CHUNK_SIZE - 1], -} -(len != 0) -*/ -static -Z7_FORCE_INLINE -// Z7_ATTRIB_NO_VECTOR -void CopyMatch(size_t offset, size_t len, - Byte *win, size_t winPos, size_t rem, const size_t cycSize) -{ - Byte *dest = win + winPos; - const Byte *src; - // STAT_INC(g_NumCopy) - - if (offset > winPos) - { - size_t back = offset - winPos; - // src = win + cycSize - back; - // cycSize -= offset; - STAT_INC(g_NumOver) - src = dest + (cycSize - offset); - // (src >= dest) here - #ifdef Z7_STD_DEC_USE_AFTER_CYC_BUF - if (back < len) - { - #else - if (back < len + (COPY_CHUNK_SIZE - 1)) - { - if (back >= len) - { - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - *dest++ = *src++; - while (--len); - return; - } - #endif - // back < len - STAT_INC(g_NumOver2) - len -= back; - rem -= back; - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - *dest++ = *src++; - while (--back); - src = dest - offset; - // src = win; - // we go to MAIN-COPY - } - } - else - src = dest - offset; - - // len != 0 - // do *dest++ = *src++; while (--len); return; - - // --- MAIN COPY --- - // if (src >= dest), then ((size_t)(src - dest) >= COPY_CHUNK_SIZE) - // so we have at least COPY_CHUNK_SIZE space before overlap for writing. - COPY_PREPARE - - /* now (len == COPY_CHUNK_SIZE * x) - so we can unroll for aligned copy */ - { - // const unsigned b0 = src[0]; - // (COPY_OFFSET_MIN >= 4) - - if (offset >= COPY_OFFSET_MIN) - { - COPY_CHUNKS - // return; - } - else - #if (COPY_OFFSET_MIN > 4) - #if COPY_CHUNK_SIZE < 8 - #error Stop_Compiling_Bad_COPY_CHUNK_SIZE - #endif - if (offset >= 4) - { - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - COPY_CHUNK_4_2(dest, src) - #if COPY_CHUNK_SIZE != 16 - if (len == 8) break; - #endif - COPY_CHUNK_4_2(dest, src) - } - while (len -= 16); - // return; - } - else - #endif - { - // (offset < 4) - const unsigned b0 = src[0]; - if (offset < 2) - { - #if defined(Z7_ZSTD_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16) - #if defined(MY_CPU_64BIT) - { - const UInt64 v64 = (UInt64)b0 * 0x0101010101010101; - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - ((UInt64 *)(void *)dest)[0] = v64; - ((UInt64 *)(void *)dest)[1] = v64; - dest += 16; - } - while (len -= 16); - } - #else - { - UInt32 v = b0; - v |= v << 8; - v |= v << 16; - do - { - ((UInt32 *)(void *)dest)[0] = v; - ((UInt32 *)(void *)dest)[1] = v; - dest += 8; - ((UInt32 *)(void *)dest)[0] = v; - ((UInt32 *)(void *)dest)[1] = v; - dest += 8; - } - while (len -= 16); - } - #endif - #else - do - { - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += 2; - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += 2; - } - while (len -= 4); - #endif - } - else if (offset == 2) - { - const Byte b1 = src[1]; - { - do - { - dest[0] = (Byte)b0; - dest[1] = b1; - dest += 2; - } - while (len -= 2); - } - } - else // (offset == 3) - { - const Byte *lim = dest + len - 2; - const Byte b1 = src[1]; - const Byte b2 = src[2]; - do - { - dest[0] = (Byte)b0; - dest[1] = b1; - dest[2] = b2; - dest += 3; - } - while (dest < lim); - lim++; // points to last byte that must be written - if (dest <= lim) - { - *dest = (Byte)b0; - if (dest != lim) - dest[1] = b1; - } - } - } - } -} - - - -#define UPDATE_TOTAL_OUT(p, size) \ -{ \ - size_t _toc = (p)->totalOutCheck + (size); \ - const size_t _ws = (p)->winSize; \ - if (_toc >= _ws) _toc = _ws; \ - (p)->totalOutCheck = _toc; \ -} - - -#if defined(MY_CPU_64BIT) && defined(MY_CPU_LE_UNALIGN) -// we can disable it for debug: -#define Z7_ZSTD_DEC_USE_64BIT_LOADS -#endif -// #define Z7_ZSTD_DEC_USE_64BIT_LOADS // for debug : slow in 32-bit - -// SEQ_SRC_OFFSET: how many bytes (src) (seqSrc) was moved back from original value. -// we need (SEQ_SRC_OFFSET != 0) for optimized memory access -#ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - #define SEQ_SRC_OFFSET 7 -#else - #define SEQ_SRC_OFFSET 3 -#endif -#define SRC_PLUS_FOR_4BYTES(bitOffset) (SEQ_SRC_OFFSET - 3) + ((CBitCtr_signed)(bitOffset) >> 3) -#define BIT_OFFSET_7BITS(bitOffset) ((unsigned)(bitOffset) & 7) -/* - if (BIT_OFFSET_DELTA_BITS == 0) : bitOffset == number_of_unprocessed_bits - if (BIT_OFFSET_DELTA_BITS == 1) : bitOffset == number_of_unprocessed_bits - 1 - and we can read 1 bit more in that mode : (8 * n + 1). -*/ -// #define BIT_OFFSET_DELTA_BITS 0 -#define BIT_OFFSET_DELTA_BITS 1 -#if BIT_OFFSET_DELTA_BITS == 1 - #define GET_SHIFT_FROM_BOFFS7(boff7) (7 ^ (boff7)) -#else - #define GET_SHIFT_FROM_BOFFS7(boff7) (8 - BIT_OFFSET_DELTA_BITS - (boff7)) -#endif - -#define UPDATE_BIT_OFFSET(bitOffset, numBits) \ - (bitOffset) -= (CBitCtr)(numBits); - -#define GET_SHIFT(bitOffset) GET_SHIFT_FROM_BOFFS7(BIT_OFFSET_7BITS(bitOffset)) - - -#if defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) - #if (NUM_OFFSET_SYMBOLS_MAX - BIT_OFFSET_DELTA_BITS < 32) - /* if (NUM_OFFSET_SYMBOLS_MAX == 32 && BIT_OFFSET_DELTA_BITS == 1), - we have depth 31 + 9 + 9 + 8 = 57 bits that can b read with single read. */ - #define Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF - #endif - #ifndef Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF - #if (BIT_OFFSET_DELTA_BITS == 1) - /* if (winLimit - winPos <= (kBlockSizeMax = (1 << 17))) - { - the case (16 bits literal extra + 16 match extra) is not possible - in correct stream. So error will be detected for (16 + 16) case. - And longest correct sequence after offset reading is (31 + 9 + 9 + 8 = 57 bits). - So we can use just one 64-bit load here in that case. - } - */ - #define Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML - #endif - #endif -#endif - - -#if !defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) || \ - (!defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) && \ - !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML)) -// in : (0 < bits <= (24 or 25)): -#define STREAM_READ_BITS(dest, bits) \ -{ \ - GET32(dest, src + SRC_PLUS_FOR_4BYTES(bitOffset)) \ - dest <<= GET_SHIFT(bitOffset); \ - UPDATE_BIT_OFFSET(bitOffset, bits) \ - dest >>= 32 - bits; \ -} -#endif - - -#define FSE_Peek_1(table, state) table[state] - -#define STATE_VAR(name) state_ ## name - -// in : (0 <= accuracy <= (24 or 25)) -#define FSE_INIT_STATE(name, cond) \ -{ \ - UInt32 r; \ - const unsigned bits = p->name ## _accuracy; \ - GET32(r, src + SRC_PLUS_FOR_4BYTES(bitOffset)) \ - r <<= GET_SHIFT(bitOffset); \ - r >>= 1; \ - r >>= 31 ^ bits; \ - UPDATE_BIT_OFFSET(bitOffset, bits) \ - cond \ - STATE_VAR(name) = FSE_Peek_1(FSE_TABLE(name), r); \ - /* STATE_VAR(name) = dest << 16; */ \ -} - - -#define FSE_Peek_Plus(name, r) \ - STATE_VAR(name) = FSE_Peek_1(FSE_TABLE(name), \ - GET_FSE_REC_STATE(STATE_VAR(name)) + r); - -#define LZ_LOOP_ERROR_EXIT { return SZ_ERROR_DATA; } - -#define BO_OVERFLOW_CHECK \ - { if ((CBitCtr_signed)bitOffset < 0) LZ_LOOP_ERROR_EXIT } - - -#ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - -#define GET64(dest, p) { const Byte *ptr = p; dest = GetUi64(ptr); } - -#define FSE_PRELOAD \ -{ \ - GET64(v, src - 4 + SRC_PLUS_FOR_4BYTES(bitOffset)) \ - v <<= GET_SHIFT(bitOffset); \ -} - -#define FSE_UPDATE_STATE_2(name, cond) \ -{ \ - const unsigned bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ - UInt64 r = v; \ - v <<= bits; \ - r >>= 1; \ - UPDATE_BIT_OFFSET(bitOffset, bits) \ - cond \ - r >>= 63 ^ bits; \ - FSE_Peek_Plus(name, r); \ -} - -#define FSE_UPDATE_STATES \ - FSE_UPDATE_STATE_2 (ll, {} ) \ - FSE_UPDATE_STATE_2 (ml, {} ) \ - FSE_UPDATE_STATE_2 (of, BO_OVERFLOW_CHECK) \ - -#else // Z7_ZSTD_DEC_USE_64BIT_LOADS - -// it supports 8 bits accuracy for any code -// it supports 9 bits accuracy, if (BIT_OFFSET_DELTA_BITS == 1) -#define FSE_UPDATE_STATE_0(name, cond) \ -{ \ - UInt32 r; \ - const unsigned bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ - GET16(r, src + 2 + SRC_PLUS_FOR_4BYTES(bitOffset)) \ - r >>= (bitOffset & 7); \ - r &= (1 << (8 + BIT_OFFSET_DELTA_BITS)) - 1; \ - UPDATE_BIT_OFFSET(bitOffset, bits) \ - cond \ - r >>= (8 + BIT_OFFSET_DELTA_BITS) - bits; \ - FSE_Peek_Plus(name, r); \ -} - -// for debug (slow): -// #define Z7_ZSTD_DEC_USE_FSE_FUSION_FORCE -#if BIT_OFFSET_DELTA_BITS == 0 || defined(Z7_ZSTD_DEC_USE_FSE_FUSION_FORCE) - #define Z7_ZSTD_DEC_USE_FSE_FUSION -#endif - -#ifdef Z7_ZSTD_DEC_USE_FSE_FUSION -#define FSE_UPDATE_STATE_1(name) \ -{ UInt32 rest2; \ -{ \ - UInt32 r; \ - unsigned bits; \ - GET32(r, src + SRC_PLUS_FOR_4BYTES(bitOffset)) \ - bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ - r <<= GET_SHIFT(bitOffset); \ - rest2 = r << bits; \ - r >>= 1; \ - UPDATE_BIT_OFFSET(bitOffset, bits) \ - r >>= 31 ^ bits; \ - FSE_Peek_Plus(name, r); \ -} - -#define FSE_UPDATE_STATE_3(name) \ -{ \ - const unsigned bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ - rest2 >>= 1; \ - UPDATE_BIT_OFFSET(bitOffset, bits) \ - rest2 >>= 31 ^ bits; \ - FSE_Peek_Plus(name, rest2); \ -}} - -#define FSE_UPDATE_STATES \ - FSE_UPDATE_STATE_1 (ll) \ - FSE_UPDATE_STATE_3 (ml) \ - FSE_UPDATE_STATE_0 (of, BO_OVERFLOW_CHECK) \ - -#else // Z7_ZSTD_DEC_USE_64BIT_LOADS - -#define FSE_UPDATE_STATES \ - FSE_UPDATE_STATE_0 (ll, {} ) \ - FSE_UPDATE_STATE_0 (ml, {} ) \ - FSE_UPDATE_STATE_0 (of, BO_OVERFLOW_CHECK) \ - -#endif // Z7_ZSTD_DEC_USE_FSE_FUSION -#endif // Z7_ZSTD_DEC_USE_64BIT_LOADS - - - -typedef struct -{ - UInt32 numSeqs; - UInt32 literalsLen; - const Byte *literals; -} -CZstdDec1_Vars; - - -// if (BIT_OFFSET_DELTA_BITS != 0), we need (BIT_OFFSET_DELTA_BYTES > 0) -#define BIT_OFFSET_DELTA_BYTES BIT_OFFSET_DELTA_BITS - -/* if (NUM_OFFSET_SYMBOLS_MAX == 32) - max_seq_bit_length = (31) + 16 + 16 + 9 + 8 + 9 = 89 bits - if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) we have longest backward - lookahead offset, and we read UInt64 after literal_len reading. - if (BIT_OFFSET_DELTA_BITS == 1 && NUM_OFFSET_SYMBOLS_MAX == 32) - MAX_BACKWARD_DEPTH = 16 bytes -*/ -#define MAX_BACKWARD_DEPTH \ - ((NUM_OFFSET_SYMBOLS_MAX - 1 + 16 + 16 + 7) / 8 + 7 + BIT_OFFSET_DELTA_BYTES) - -/* srcLen != 0 - src == real_data_ptr - SEQ_SRC_OFFSET - BIT_OFFSET_DELTA_BYTES - if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML) then - (winLimit - p->winPos <= (1 << 17)) is required -*/ -static -Z7_NO_INLINE -// Z7_ATTRIB_NO_VECTOR -SRes Decompress_Sequences(CZstdDec1 * const p, - const Byte *src, const size_t srcLen, - const size_t winLimit, - const CZstdDec1_Vars * const vars) -{ -#ifdef Z7_ZSTD_DEC_USE_BASES_LOCAL - SEQ_EXTRA_TABLES(a_) -#endif - - // for debug: - // #define Z7_ZSTD_DEC_USE_LOCAL_FSE_TABLES -#ifdef Z7_ZSTD_DEC_USE_LOCAL_FSE_TABLES - #define FSE_TABLE(n) fse. n - const CZstdDecFseTables fse = p->fse; - /* - CZstdDecFseTables fse; - #define COPY_FSE_TABLE(n) \ - memcpy(fse. n, p->fse. n, (size_t)4 << p-> n ## _accuracy); - COPY_FSE_TABLE(of) - COPY_FSE_TABLE(ll) - COPY_FSE_TABLE(ml) - */ -#else - #define FSE_TABLE(n) (p->fse. n) -#endif - -#ifdef Z7_ZSTD_DEC_USE_BASES_LOCAL - FILL_LOC_BASES_ALL -#endif - - { - unsigned numSeqs = vars->numSeqs; - const Byte *literals = vars->literals; - ptrdiff_t literalsLen = (ptrdiff_t)vars->literalsLen; - Byte * const win = p->win; - size_t winPos = p->winPos; - const size_t cycSize = p->cycSize; - size_t totalOutCheck = p->totalOutCheck; - const size_t winSize = p->winSize; - size_t reps_0 = p->reps[0]; - size_t reps_1 = p->reps[1]; - size_t reps_2 = p->reps[2]; - UInt32 STATE_VAR(ll), STATE_VAR(of), STATE_VAR(ml); - CBitCtr bitOffset; - - SET_bitOffset_TO_PAD (bitOffset, src + SEQ_SRC_OFFSET, srcLen + BIT_OFFSET_DELTA_BYTES) - - bitOffset -= BIT_OFFSET_DELTA_BITS; - - FSE_INIT_STATE(ll, {} ) - FSE_INIT_STATE(of, {} ) - FSE_INIT_STATE(ml, BO_OVERFLOW_CHECK) - - for (;;) - { - size_t matchLen; - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - UInt64 v; - #endif - - #ifdef Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF - FSE_PRELOAD - #endif - - // if (of_code == 0) - if ((Byte)STATE_VAR(of) == 0) - { - if (GET_FSE_REC_SYM(STATE_VAR(ll)) == 0) - { - const size_t offset = reps_1; - reps_1 = reps_0; - reps_0 = offset; - STAT_INC(g_Num_Rep1) - } - STAT_UPDATE(else g_Num_Rep0++;) - } - else - { - const unsigned of_code = (Byte)STATE_VAR(of); - - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - #if !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) - FSE_PRELOAD - #endif - #else - UInt32 v; - { - const Byte *src4 = src + SRC_PLUS_FOR_4BYTES(bitOffset); - const unsigned skip = GET_SHIFT(bitOffset); - GET32(v, src4) - v <<= skip; - v |= (UInt32)src4[-1] >> (8 - skip); - } - #endif - - UPDATE_BIT_OFFSET(bitOffset, of_code) - - if (of_code == 1) - { - // read 1 bit - #if defined(Z7_MSC_VER_ORIGINAL) || defined(MY_CPU_X86_OR_AMD64) - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - #define CHECK_HIGH_BIT_64(a) ((Int64)(UInt64)(a) < 0) - #else - #define CHECK_HIGH_BIT_32(a) ((Int32)(UInt32)(a) < 0) - #endif - #else - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - #define CHECK_HIGH_BIT_64(a) ((UInt64)(a) & ((UInt64)1 << 63)) - #else - #define CHECK_HIGH_BIT_32(a) ((UInt32)(a) & ((UInt32)1 << 31)) - #endif - #endif - - if - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - CHECK_HIGH_BIT_64 (((UInt64)GET_FSE_REC_SYM(STATE_VAR(ll)) - 1) ^ v) - #else - CHECK_HIGH_BIT_32 (((UInt32)GET_FSE_REC_SYM(STATE_VAR(ll)) - 1) ^ v) - #endif - { - v <<= 1; - { - const size_t offset = reps_2; - reps_2 = reps_1; - reps_1 = reps_0; - reps_0 = offset; - STAT_INC(g_Num_Rep2) - } - } - else - { - if (GET_FSE_REC_SYM(STATE_VAR(ll)) == 0) - { - // litLen == 0 && bit == 1 - STAT_INC(g_Num_Rep3) - v <<= 1; - reps_2 = reps_1; - reps_1 = reps_0; - if (--reps_0 == 0) - { - // LZ_LOOP_ERROR_EXIT - // original-zstd decoder : input is corrupted; force offset to 1 - // reps_0 = 1; - reps_0++; - } - } - else - { - // litLen != 0 && bit == 0 - v <<= 1; - { - const size_t offset = reps_1; - reps_1 = reps_0; - reps_0 = offset; - STAT_INC(g_Num_Rep1) - } - } - } - } - else - { - // (2 <= of_code) - // if (of_code >= 32) LZ_LOOP_ERROR_EXIT // optional check - // we don't allow (of_code >= 32) cases in another code - reps_2 = reps_1; - reps_1 = reps_0; - reps_0 = ((size_t)1 << of_code) - 3 + (size_t) - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - (v >> (64 - of_code)); - v <<= of_code; - #else - (v >> (32 - of_code)); - #endif - } - } - - #ifdef Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML - FSE_PRELOAD - #endif - - matchLen = (size_t)GET_FSE_REC_SYM(STATE_VAR(ml)) - #ifndef Z7_ZSTD_DEC_USE_ML_PLUS3 - + MATCH_LEN_MIN - #endif - ; - { - { - if (matchLen >= 32 + MATCH_LEN_MIN) // if (state_ml & 0x20) - { - const unsigned extra = BASES_TABLE(SEQ_ML_EXTRA) [(size_t)matchLen - MATCH_LEN_MIN]; - matchLen = BASES_TABLE(SEQ_ML_BASES) [(size_t)matchLen - MATCH_LEN_MIN]; - #if defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) && \ - (defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML) || \ - defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF)) - { - UPDATE_BIT_OFFSET(bitOffset, extra) - matchLen += (size_t)(v >> (64 - extra)); - #if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) - FSE_PRELOAD - #else - v <<= extra; - #endif - } - #else - { - UInt32 v32; - STREAM_READ_BITS(v32, extra) - matchLen += v32; - } - #endif - STAT_INC(g_Num_Match) - } - } - } - - #if defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) && \ - !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) && \ - !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML) - FSE_PRELOAD - #endif - - { - size_t litLen = GET_FSE_REC_SYM(STATE_VAR(ll)); - if (litLen) - { - // if (STATE_VAR(ll) & 0x70) - if (litLen >= 16) - { - const unsigned extra = BASES_TABLE(SEQ_LL_EXTRA) [litLen]; - litLen = BASES_TABLE(SEQ_LL_BASES) [litLen]; - #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS - { - UPDATE_BIT_OFFSET(bitOffset, extra) - litLen += (size_t)(v >> (64 - extra)); - #if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) - FSE_PRELOAD - #else - v <<= extra; - #endif - } - #else - { - UInt32 v32; - STREAM_READ_BITS(v32, extra) - litLen += v32; - } - #endif - STAT_INC(g_Num_LitsBig) - } - - if ((literalsLen -= (ptrdiff_t)litLen) < 0) - LZ_LOOP_ERROR_EXIT - totalOutCheck += litLen; - { - const size_t rem = winLimit - winPos; - if (litLen > rem) - LZ_LOOP_ERROR_EXIT - { - const Byte *literals_temp = literals; - Byte *d = win + winPos; - literals += litLen; - winPos += litLen; - CopyLiterals(d, literals_temp, litLen, rem); - } - } - } - STAT_UPDATE(else g_Num_Lit0++;) - } - - #define COPY_MATCH \ - { if (reps_0 > winSize || reps_0 > totalOutCheck) LZ_LOOP_ERROR_EXIT \ - totalOutCheck += matchLen; \ - { const size_t rem = winLimit - winPos; \ - if (matchLen > rem) LZ_LOOP_ERROR_EXIT \ - { const size_t winPos_temp = winPos; \ - winPos += matchLen; \ - CopyMatch(reps_0, matchLen, win, winPos_temp, rem, cycSize); }}} - - if (--numSeqs == 0) - { - COPY_MATCH - break; - } - FSE_UPDATE_STATES - COPY_MATCH - } // for - - if ((CBitCtr_signed)bitOffset != BIT_OFFSET_DELTA_BYTES * 8 - BIT_OFFSET_DELTA_BITS) - return SZ_ERROR_DATA; - - if (literalsLen) - { - const size_t rem = winLimit - winPos; - if ((size_t)literalsLen > rem) - return SZ_ERROR_DATA; - { - Byte *d = win + winPos; - winPos += (size_t)literalsLen; - totalOutCheck += (size_t)literalsLen; - CopyLiterals - // memcpy - (d, literals, (size_t)literalsLen, rem); - } - } - if (totalOutCheck >= winSize) - totalOutCheck = winSize; - p->totalOutCheck = totalOutCheck; - p->winPos = winPos; - p->reps[0] = (CZstdDecOffset)reps_0; - p->reps[1] = (CZstdDecOffset)reps_1; - p->reps[2] = (CZstdDecOffset)reps_2; - } - return SZ_OK; -} - - -// for debug: define to check that ZstdDec1_NeedTempBufferForInput() works correctly: -// #define Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP // define it for debug only -#ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP -static unsigned g_numSeqs; -#endif - - -#define k_LitBlockType_Flag_RLE_or_Treeless 1 -#define k_LitBlockType_Flag_Compressed 2 - -// outLimit : is strong limit -// outLimit <= ZstdDec1_GET_BLOCK_SIZE_LIMIT(p) -// inSize != 0 -static -Z7_NO_INLINE -SRes ZstdDec1_DecodeBlock(CZstdDec1 *p, - const Byte *src, SizeT inSize, SizeT afterAvail, - const size_t outLimit) -{ - CZstdDec1_Vars vars; - vars.literals = p->literalsBase; - { - const unsigned b0 = *src++; - UInt32 numLits, compressedSize; - const Byte *litStream; - Byte *literalsDest; - inSize--; - - if ((b0 & k_LitBlockType_Flag_Compressed) == 0) - { - // we need at least one additional byte for (numSeqs). - // so we check for that additional byte in conditions. - numLits = b0 >> 3; - if (b0 & 4) - { - UInt32 v; - if (inSize < 1 + 1) // we need at least 1 byte here and 1 byte for (numSeqs). - return SZ_ERROR_DATA; - numLits >>= 1; - v = GetUi16(src); - src += 2; - inSize -= 2; - if ((b0 & 8) == 0) - { - src--; - inSize++; - v = (Byte)v; - } - numLits += v << 4; - } - compressedSize = 1; - if ((b0 & k_LitBlockType_Flag_RLE_or_Treeless) == 0) - compressedSize = numLits; - } - else if (inSize < 4) - return SZ_ERROR_DATA; - else - { - const unsigned mode4Streams = b0 & 0xc; - const unsigned numBytes = (3 * mode4Streams + 32) >> 4; - const unsigned numBits = 4 * numBytes - 2; - const UInt32 mask = ((UInt32)16 << numBits) - 1; - compressedSize = GetUi32(src); - numLits = (( - #ifdef MY_CPU_LE_UNALIGN - GetUi32(src - 1) - #else - ((compressedSize << 8) + b0) - #endif - ) >> 4) & mask; - src += numBytes; - inSize -= numBytes; - compressedSize >>= numBits; - compressedSize &= mask; - /* - if (numLits != 0) printf("inSize = %7u num_lits=%7u compressed=%7u ratio = %u ratio2 = %u\n", - i1, numLits, (unsigned)compressedSize * 1, (unsigned)compressedSize * 100 / numLits, - (unsigned)numLits * 100 / (unsigned)inSize); - } - */ - if (compressedSize == 0) - return SZ_ERROR_DATA; // (compressedSize == 0) is not allowed - } - - STAT_UPDATE(g_Num_Lits += numLits;) - - vars.literalsLen = numLits; - - if (compressedSize >= inSize) - return SZ_ERROR_DATA; - litStream = src; - src += compressedSize; - inSize -= compressedSize; - // inSize != 0 - { - UInt32 numSeqs = *src++; - inSize--; - if (numSeqs > 127) - { - UInt32 b1; - if (inSize == 0) - return SZ_ERROR_DATA; - numSeqs -= 128; - b1 = *src++; - inSize--; - if (numSeqs == 127) - { - if (inSize == 0) - return SZ_ERROR_DATA; - numSeqs = (UInt32)(*src++) + 127; - inSize--; - } - numSeqs = (numSeqs << 8) + b1; - } - if (numSeqs * MATCH_LEN_MIN + numLits > outLimit) - return SZ_ERROR_DATA; - vars.numSeqs = numSeqs; - - STAT_UPDATE(g_NumSeqs_total += numSeqs;) - /* - #ifdef SHOW_STAT - printf("\n %5u : %8u, %8u : %5u", (int)g_Num_Blocks_Compressed, (int)numSeqs, (int)g_NumSeqs_total, - (int)g_NumSeqs_total / g_Num_Blocks_Compressed); - #endif - // printf("\nnumSeqs2 = %d", numSeqs); - */ - #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP - if (numSeqs != g_numSeqs) return SZ_ERROR_DATA; // for debug - #endif - if (numSeqs == 0) - { - if (inSize != 0) - return SZ_ERROR_DATA; - literalsDest = p->win + p->winPos; - } - else - literalsDest = p->literalsBase; - } - - if ((b0 & k_LitBlockType_Flag_Compressed) == 0) - { - if (b0 & k_LitBlockType_Flag_RLE_or_Treeless) - { - memset(literalsDest, litStream[0], numLits); - if (vars.numSeqs) - { - // literalsDest == p->literalsBase == vars.literals - #if COPY_CHUNK_SIZE > 1 - memset(p->literalsBase + numLits, 0, COPY_CHUNK_SIZE); - #endif - } - } - else - { - // unsigned y; - // for (y = 0; y < 10000; y++) - memcpy(literalsDest, litStream, numLits); - if (vars.numSeqs) - { - /* we need up to (15 == COPY_CHUNK_SIZE - 1) space for optimized CopyLiterals(). - If we have additional space in input stream after literals stream, - we use direct copy of rar literals in input stream */ - if ((size_t)(src + inSize - litStream) - numLits + afterAvail >= (COPY_CHUNK_SIZE - 1)) - vars.literals = litStream; - else - { - // literalsDest == p->literalsBase == vars.literals - #if COPY_CHUNK_SIZE > 1 - /* CopyLiterals(): - 1) we don't want reading non-initialized data - 2) we will copy only zero byte after literals buffer */ - memset(p->literalsBase + numLits, 0, COPY_CHUNK_SIZE); - #endif - } - } - } - } - else - { - CInBufPair hufStream; - hufStream.ptr = litStream; - hufStream.len = compressedSize; - - if ((b0 & k_LitBlockType_Flag_RLE_or_Treeless) == 0) - { - // unsigned y = 100; CInBufPair hs2 = hufStream; do { hufStream = hs2; - RINOK(Huf_DecodeTable(&p->huf, &hufStream)) - p->litHuf_wasSet = True; - // } while (--y); - } - else if (!p->litHuf_wasSet) - return SZ_ERROR_DATA; - - { - // int yyy; for (yyy = 0; yyy < 34; yyy++) { - SRes sres; - if ((b0 & 0xc) == 0) // mode4Streams - sres = Huf_Decompress_1stream((const Byte *)(const void *)p->huf.table64, - hufStream.ptr - HUF_SRC_OFFSET, hufStream.len, literalsDest, numLits); - else - { - // 6 bytes for the jump table + 4x1 bytes of end-padding Bytes) - if (hufStream.len < 6 + 4) - return SZ_ERROR_DATA; - // the condition from original-zstd decoder: - #define Z7_ZSTD_MIN_LITERALS_FOR_4_STREAMS 6 - if (numLits < Z7_ZSTD_MIN_LITERALS_FOR_4_STREAMS) - return SZ_ERROR_DATA; - sres = Huf_Decompress_4stream((const Byte *)(const void *)p->huf.table64, - hufStream.ptr + (6 - HUF_SRC_OFFSET), hufStream.len, literalsDest, numLits); - } - RINOK(sres) - // } - } - } - - if (vars.numSeqs == 0) - { - p->winPos += numLits; - UPDATE_TOTAL_OUT(p, numLits) - return SZ_OK; - } - } - { - CInBufPair in; - unsigned mode; - unsigned seqMode; - - in.ptr = src; - in.len = inSize; - if (in.len == 0) - return SZ_ERROR_DATA; - in.len--; - mode = *in.ptr++; - if (mode & 3) // Reserved bits - return SZ_ERROR_DATA; - - seqMode = (mode >> 6); - if (seqMode == k_SeqMode_Repeat) - { if (!IS_SEQ_TABLES_WERE_SET(p)) return SZ_ERROR_DATA; } - else RINOK(FSE_Decode_SeqTable( - p->fse.ll, - &in, - 6, // predefAccuracy - &p->ll_accuracy, - NUM_LL_SYMBOLS, - k_PredefRecords_LL, - seqMode)) - - seqMode = (mode >> 4) & 3; - if (seqMode == k_SeqMode_Repeat) - { if (!IS_SEQ_TABLES_WERE_SET(p)) return SZ_ERROR_DATA; } - else RINOK(FSE_Decode_SeqTable( - p->fse.of, - &in, - 5, // predefAccuracy - &p->of_accuracy, - NUM_OFFSET_SYMBOLS_MAX, - k_PredefRecords_OF, - seqMode)) - - seqMode = (mode >> 2) & 3; - if (seqMode == k_SeqMode_Repeat) - { if (!IS_SEQ_TABLES_WERE_SET(p)) return SZ_ERROR_DATA; } - else - { - RINOK(FSE_Decode_SeqTable( - p->fse.ml, - &in, - 6, // predefAccuracy - &p->ml_accuracy, - NUM_ML_SYMBOLS, - k_PredefRecords_ML, - seqMode)) - /* - #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) - // { unsigned y = 1 << 10; do - { - const unsigned accuracy = p->ml_accuracy; - if (accuracy == 0) - p->fse.ml[0] += 3; - else - #ifdef MY_CPU_64BIT - { - // alignemt (UInt64 _pad_Alignment) in fse.ml is required for that code - UInt64 *table = (UInt64 *)(void *)p->fse.ml; - const UInt64 *end = (const UInt64 *)(const void *) - ((const Byte *)(const void *)table + ((size_t)sizeof(CFseRecord) << accuracy)); - do - { - table[0] += ((UInt64)MATCH_LEN_MIN << 32) + MATCH_LEN_MIN; - table[1] += ((UInt64)MATCH_LEN_MIN << 32) + MATCH_LEN_MIN; - table += 2; - } - while (table != end); - } - #else - { - UInt32 *table = p->fse.ml; - const UInt32 *end = (const UInt32 *)(const void *) - ((const Byte *)(const void *)table + ((size_t)sizeof(CFseRecord) << accuracy)); - do - { - table[0] += MATCH_LEN_MIN; - table[1] += MATCH_LEN_MIN; - table += 2; - table[0] += MATCH_LEN_MIN; - table[1] += MATCH_LEN_MIN; - table += 2; - } - while (table != end); - } - #endif - } - // while (--y); } - #endif - */ - } - - // p->seqTables_wereSet = True; - if (in.len == 0) - return SZ_ERROR_DATA; - return Decompress_Sequences(p, - in.ptr - SEQ_SRC_OFFSET - BIT_OFFSET_DELTA_BYTES, in.len, - p->winPos + outLimit, &vars); - } -} - - - - -// inSize != 0 -// it must do similar to ZstdDec1_DecodeBlock() -static size_t ZstdDec1_NeedTempBufferForInput( - const SizeT beforeSize, const Byte * const src, const SizeT inSize) -{ - unsigned b0; - UInt32 pos; - - #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP - g_numSeqs = 1 << 24; - #else - // we have at least 3 bytes before seq data: litBlockType, numSeqs, seqMode - #define MIN_BLOCK_LZ_HEADERS_SIZE 3 - if (beforeSize >= MAX_BACKWARD_DEPTH - MIN_BLOCK_LZ_HEADERS_SIZE) - return 0; - #endif - - b0 = src[0]; - - if ((b0 & k_LitBlockType_Flag_Compressed) == 0) - { - UInt32 numLits = b0 >> 3; - pos = 1; - if (b0 & 4) - { - UInt32 v; - if (inSize < 3) - return 0; - numLits >>= 1; - v = GetUi16(src + 1); - pos = 3; - if ((b0 & 8) == 0) - { - pos = 2; - v = (Byte)v; - } - numLits += v << 4; - } - if (b0 & k_LitBlockType_Flag_RLE_or_Treeless) - numLits = 1; - pos += numLits; - } - else if (inSize < 5) - return 0; - else - { - const unsigned mode4Streams = b0 & 0xc; - const unsigned numBytes = (3 * mode4Streams + 48) >> 4; - const unsigned numBits = 4 * numBytes - 6; - UInt32 cs = GetUi32(src + 1); - cs >>= numBits; - cs &= ((UInt32)16 << numBits) - 1; - if (cs == 0) - return 0; - pos = numBytes + cs; - } - - if (pos >= inSize) - return 0; - { - UInt32 numSeqs = src[pos++]; - if (numSeqs > 127) - { - UInt32 b1; - if (pos >= inSize) - return 0; - numSeqs -= 128; - b1 = src[pos++]; - if (numSeqs == 127) - { - if (pos >= inSize) - return 0; - numSeqs = (UInt32)(src[pos++]) + 127; - } - numSeqs = (numSeqs << 8) + b1; - } - #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP - g_numSeqs = numSeqs; // for debug - #endif - if (numSeqs == 0) - return 0; - } - /* - if (pos >= inSize) - return 0; - pos++; - */ - // we will have one additional byte for seqMode: - if (beforeSize + pos >= MAX_BACKWARD_DEPTH - 1) - return 0; - return 1; -} - - - -// ---------- ZSTD FRAME ---------- - -#define kBlockType_Raw 0 -#define kBlockType_RLE 1 -#define kBlockType_Compressed 2 -#define kBlockType_Reserved 3 - -typedef enum -{ - // begin: states that require 4 bytes: - ZSTD2_STATE_SIGNATURE, - ZSTD2_STATE_HASH, - ZSTD2_STATE_SKIP_HEADER, - // end of states that require 4 bytes - - ZSTD2_STATE_SKIP_DATA, - ZSTD2_STATE_FRAME_HEADER, - ZSTD2_STATE_AFTER_HEADER, - ZSTD2_STATE_BLOCK, - ZSTD2_STATE_DATA, - ZSTD2_STATE_FINISHED -} EZstd2State; - - -struct CZstdDec -{ - EZstd2State frameState; - unsigned tempSize; - - Byte temp[14]; // 14 is required - - Byte descriptor; - Byte windowDescriptor; - Byte isLastBlock; - Byte blockType; - Byte isErrorState; - Byte hashError; - Byte disableHash; - Byte isCyclicMode; - - UInt32 blockSize; - UInt32 dictionaryId; - UInt32 curBlockUnpackRem; // for compressed blocks only - UInt32 inTempPos; - - UInt64 contentSize; - UInt64 contentProcessed; - CXxh64State xxh64; - - Byte *inTemp; - SizeT winBufSize_Allocated; - Byte *win_Base; - - ISzAllocPtr alloc_Small; - ISzAllocPtr alloc_Big; - - CZstdDec1 decoder; -}; - -#define ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p) \ - ((unsigned)(p)->contentProcessed & (Z7_XXH64_BLOCK_SIZE - 1)) - -#define ZSTD_DEC_IS_LAST_BLOCK(p) ((p)->isLastBlock) - - -static void ZstdDec_FreeWindow(CZstdDec * const p) -{ - if (p->win_Base) - { - ISzAlloc_Free(p->alloc_Big, p->win_Base); - p->win_Base = NULL; - // p->decoder.win = NULL; - p->winBufSize_Allocated = 0; - } -} - - -CZstdDecHandle ZstdDec_Create(ISzAllocPtr alloc_Small, ISzAllocPtr alloc_Big) -{ - CZstdDec *p = (CZstdDec *)ISzAlloc_Alloc(alloc_Small, sizeof(CZstdDec)); - if (!p) - return NULL; - p->alloc_Small = alloc_Small; - p->alloc_Big = alloc_Big; - // ZstdDec_CONSTRUCT(p) - p->inTemp = NULL; - p->win_Base = NULL; - p->winBufSize_Allocated = 0; - p->disableHash = False; - ZstdDec1_Construct(&p->decoder); - return p; -} - -void ZstdDec_Destroy(CZstdDecHandle p) -{ - #ifdef SHOW_STAT - #define PRINT_STAT1(name, v) \ - printf("\n%25s = %9u", name, v); - PRINT_STAT1("g_Num_Blocks_Compressed", g_Num_Blocks_Compressed) - PRINT_STAT1("g_Num_Blocks_memcpy", g_Num_Blocks_memcpy) - PRINT_STAT1("g_Num_Wrap_memmove_Num", g_Num_Wrap_memmove_Num) - PRINT_STAT1("g_Num_Wrap_memmove_Bytes", g_Num_Wrap_memmove_Bytes) - if (g_Num_Blocks_Compressed) - { - #define PRINT_STAT(name, v) \ - printf("\n%17s = %9u, per_block = %8u", name, v, v / g_Num_Blocks_Compressed); - PRINT_STAT("g_NumSeqs", g_NumSeqs_total) - // PRINT_STAT("g_NumCopy", g_NumCopy) - PRINT_STAT("g_NumOver", g_NumOver) - PRINT_STAT("g_NumOver2", g_NumOver2) - PRINT_STAT("g_Num_Match", g_Num_Match) - PRINT_STAT("g_Num_Lits", g_Num_Lits) - PRINT_STAT("g_Num_LitsBig", g_Num_LitsBig) - PRINT_STAT("g_Num_Lit0", g_Num_Lit0) - PRINT_STAT("g_Num_Rep_0", g_Num_Rep0) - PRINT_STAT("g_Num_Rep_1", g_Num_Rep1) - PRINT_STAT("g_Num_Rep_2", g_Num_Rep2) - PRINT_STAT("g_Num_Rep_3", g_Num_Rep3) - PRINT_STAT("g_Num_Threshold_0", g_Num_Threshold_0) - PRINT_STAT("g_Num_Threshold_1", g_Num_Threshold_1) - PRINT_STAT("g_Num_Threshold_0sum", g_Num_Threshold_0sum) - PRINT_STAT("g_Num_Threshold_1sum", g_Num_Threshold_1sum) - } - printf("\n"); - #endif - - ISzAlloc_Free(p->alloc_Small, p->decoder.literalsBase); - // p->->decoder.literalsBase = NULL; - ISzAlloc_Free(p->alloc_Small, p->inTemp); - // p->inTemp = NULL; - ZstdDec_FreeWindow(p); - ISzAlloc_Free(p->alloc_Small, p); -} - - - -#define kTempBuffer_PreSize (1u << 6) -#if kTempBuffer_PreSize < MAX_BACKWARD_DEPTH - #error Stop_Compiling_Bad_kTempBuffer_PreSize -#endif - -static SRes ZstdDec_AllocateMisc(CZstdDec *p) -{ - #define k_Lit_AfterAvail (1u << 6) - #if k_Lit_AfterAvail < (COPY_CHUNK_SIZE - 1) - #error Stop_Compiling_Bad_k_Lit_AfterAvail - #endif - // return ZstdDec1_Allocate(&p->decoder, p->alloc_Small); - if (!p->decoder.literalsBase) - { - p->decoder.literalsBase = (Byte *)ISzAlloc_Alloc(p->alloc_Small, - kBlockSizeMax + k_Lit_AfterAvail); - if (!p->decoder.literalsBase) - return SZ_ERROR_MEM; - } - if (!p->inTemp) - { - // we need k_Lit_AfterAvail here for owerread from raw literals stream - p->inTemp = (Byte *)ISzAlloc_Alloc(p->alloc_Small, - kBlockSizeMax + kTempBuffer_PreSize + k_Lit_AfterAvail); - if (!p->inTemp) - return SZ_ERROR_MEM; - } - return SZ_OK; -} - - -static void ZstdDec_Init_ForNewFrame(CZstdDec *p) -{ - p->frameState = ZSTD2_STATE_SIGNATURE; - p->tempSize = 0; - - p->isErrorState = False; - p->hashError = False; - p->isCyclicMode = False; - p->contentProcessed = 0; - Xxh64State_Init(&p->xxh64); - ZstdDec1_Init(&p->decoder); -} - - -void ZstdDec_Init(CZstdDec *p) -{ - ZstdDec_Init_ForNewFrame(p); - p->decoder.winPos = 0; - memset(p->temp, 0, sizeof(p->temp)); -} - - -#define DESCRIPTOR_Get_DictionaryId_Flag(d) ((d) & 3) -#define DESCRIPTOR_FLAG_CHECKSUM (1 << 2) -#define DESCRIPTOR_FLAG_RESERVED (1 << 3) -// #define DESCRIPTOR_FLAG_UNUSED (1 << 4) -#define DESCRIPTOR_FLAG_SINGLE (1 << 5) -#define DESCRIPTOR_Get_ContentSize_Flag3(d) ((d) >> 5) -#define DESCRIPTOR_Is_ContentSize_Defined(d) (((d) & 0xe0) != 0) - - -static EZstd2State ZstdDec_UpdateState(CZstdDec * const p, const Byte b, CZstdDecInfo * const info) -{ - unsigned tempSize = p->tempSize; - p->temp[tempSize++] = b; - p->tempSize = tempSize; - - if (p->frameState == ZSTD2_STATE_BLOCK) - { - if (tempSize < 3) - return ZSTD2_STATE_BLOCK; - { - UInt32 b0 = GetUi32(p->temp); - const unsigned type = ((unsigned)b0 >> 1) & 3; - if (type == kBlockType_RLE && tempSize == 3) - return ZSTD2_STATE_BLOCK; - // info->num_Blocks_forType[type]++; - info->num_Blocks++; - if (type == kBlockType_Reserved) - { - p->isErrorState = True; // SZ_ERROR_UNSUPPORTED - return ZSTD2_STATE_BLOCK; - } - p->blockType = (Byte)type; - p->isLastBlock = (Byte)(b0 & 1); - p->inTempPos = 0; - p->tempSize = 0; - b0 >>= 3; - b0 &= 0x1fffff; - // info->num_BlockBytes_forType[type] += b0; - if (b0 == 0) - { - // empty RAW/RLE blocks are allowed in original-zstd decoder - if (type == kBlockType_Compressed) - { - p->isErrorState = True; - return ZSTD2_STATE_BLOCK; - } - if (!ZSTD_DEC_IS_LAST_BLOCK(p)) - return ZSTD2_STATE_BLOCK; - if (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM) - return ZSTD2_STATE_HASH; - return ZSTD2_STATE_FINISHED; - } - p->blockSize = b0; - { - UInt32 blockLim = ZstdDec1_GET_BLOCK_SIZE_LIMIT(&p->decoder); - // compressed and uncompressed block sizes cannot be larger than min(kBlockSizeMax, window_size) - if (b0 > blockLim) - { - p->isErrorState = True; // SZ_ERROR_UNSUPPORTED; - return ZSTD2_STATE_BLOCK; - } - if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor)) - { - const UInt64 rem = p->contentSize - p->contentProcessed; - if (blockLim > rem) - blockLim = (UInt32)rem; - } - p->curBlockUnpackRem = blockLim; - // uncompressed block size cannot be larger than remain data size: - if (type != kBlockType_Compressed) - { - if (b0 > blockLim) - { - p->isErrorState = True; // SZ_ERROR_UNSUPPORTED; - return ZSTD2_STATE_BLOCK; - } - } - } - } - return ZSTD2_STATE_DATA; - } - - if ((unsigned)p->frameState < ZSTD2_STATE_SKIP_DATA) - { - UInt32 v; - if (tempSize != 4) - return p->frameState; - v = GetUi32(p->temp); - if ((unsigned)p->frameState < ZSTD2_STATE_HASH) // == ZSTD2_STATE_SIGNATURE - { - if (v == 0xfd2fb528) - { - p->tempSize = 0; - info->num_DataFrames++; - return ZSTD2_STATE_FRAME_HEADER; - } - if ((v & 0xfffffff0) == 0x184d2a50) - { - p->tempSize = 0; - info->num_SkipFrames++; - return ZSTD2_STATE_SKIP_HEADER; - } - p->isErrorState = True; - return ZSTD2_STATE_SIGNATURE; - // return ZSTD2_STATE_ERROR; // is not ZSTD stream - } - if (p->frameState == ZSTD2_STATE_HASH) - { - info->checksum_Defined = True; - info->checksum = v; - // #ifndef DISABLE_XXH_CHECK - if (!p->disableHash) - { - if (p->decoder.winPos < ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p)) - { - // unexpected code failure - p->isErrorState = True; - // SZ_ERROR_FAIL; - } - else - if ((UInt32)Xxh64State_Digest(&p->xxh64, - p->decoder.win + (p->decoder.winPos - ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p)), - p->contentProcessed) != v) - { - p->hashError = True; - // return ZSTD2_STATE_ERROR; // hash error - } - } - // #endif - return ZSTD2_STATE_FINISHED; - } - // (p->frameState == ZSTD2_STATE_SKIP_HEADER) - { - p->blockSize = v; - info->skipFrames_Size += v; - p->tempSize = 0; - /* we want the caller could know that there was finished frame - finished frame. So we allow the case where - we have ZSTD2_STATE_SKIP_DATA state with (blockSize == 0). - */ - // if (v == 0) return ZSTD2_STATE_SIGNATURE; - return ZSTD2_STATE_SKIP_DATA; - } - } - - // if (p->frameState == ZSTD2_STATE_FRAME_HEADER) - { - unsigned descriptor; - const Byte *h; - descriptor = p->temp[0]; - p->descriptor = (Byte)descriptor; - if (descriptor & DESCRIPTOR_FLAG_RESERVED) // reserved bit - { - p->isErrorState = True; - return ZSTD2_STATE_FRAME_HEADER; - // return ZSTD2_STATE_ERROR; - } - { - const unsigned n = DESCRIPTOR_Get_ContentSize_Flag3(descriptor); - // tempSize -= 1 + ((1u << (n >> 1)) | ((n + 1) & 1)); - tempSize -= (0x9a563422u >> (n * 4)) & 0xf; - } - if (tempSize != (4u >> (3 - DESCRIPTOR_Get_DictionaryId_Flag(descriptor)))) - return ZSTD2_STATE_FRAME_HEADER; - - info->descriptor_OR = (Byte)(info->descriptor_OR | descriptor); - info->descriptor_NOT_OR = (Byte)(info->descriptor_NOT_OR | ~descriptor); - - h = &p->temp[1]; - { - Byte w = 0; - if ((descriptor & DESCRIPTOR_FLAG_SINGLE) == 0) - { - w = *h++; - if (info->windowDescriptor_MAX < w) - info->windowDescriptor_MAX = w; - // info->are_WindowDescriptors = True; - // info->num_WindowDescriptors++; - } - else - { - // info->are_SingleSegments = True; - // info->num_SingleSegments++; - } - p->windowDescriptor = w; - } - { - unsigned n = DESCRIPTOR_Get_DictionaryId_Flag(descriptor); - UInt32 d = 0; - if (n) - { - n = 1u << (n - 1); - d = GetUi32(h) & ((UInt32)(Int32)-1 >> (32 - 8u * n)); - h += n; - } - p->dictionaryId = d; - // info->dictionaryId_Cur = d; - if (d != 0) - { - if (info->dictionaryId == 0) - info->dictionaryId = d; - else if (info->dictionaryId != d) - info->are_DictionaryId_Different = True; - } - } - { - unsigned n = DESCRIPTOR_Get_ContentSize_Flag3(descriptor); - UInt64 v = 0; - if (n) - { - n >>= 1; - if (n == 1) - v = 256; - v += GetUi64(h) & ((UInt64)(Int64)-1 >> (64 - (8u << n))); - // info->are_ContentSize_Known = True; - // info->num_Frames_with_ContentSize++; - if (info->contentSize_MAX < v) - info->contentSize_MAX = v; - info->contentSize_Total += v; - } - else - { - info->are_ContentSize_Unknown = True; - // info->num_Frames_without_ContentSize++; - } - p->contentSize = v; - } - // if ((size_t)(h - p->temp) != headerSize) return ZSTD2_STATE_ERROR; // it's unexpected internal code failure - p->tempSize = 0; - - info->checksum_Defined = False; - /* - if (descriptor & DESCRIPTOR_FLAG_CHECKSUM) - info->are_Checksums = True; - else - info->are_Non_Checksums = True; - */ - - return ZSTD2_STATE_AFTER_HEADER; // ZSTD2_STATE_BLOCK; - } -} - - -static void ZstdDec_Update_XXH(CZstdDec * const p, size_t xxh64_winPos) -{ - /* - #ifdef DISABLE_XXH_CHECK - UNUSED_VAR(data) - #else - */ - if (!p->disableHash && (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM)) - { - // const size_t pos = p->xxh64_winPos; - const size_t size = (p->decoder.winPos - xxh64_winPos) & ~(size_t)31; - if (size) - { - // p->xxh64_winPos = pos + size; - Xxh64State_UpdateBlocks(&p->xxh64, - p->decoder.win + xxh64_winPos, - p->decoder.win + xxh64_winPos + size); - } - } -} - - -/* -in: - (winLimit) : is relaxed limit, where this function is allowed to stop writing of decoded data (if possible). - - this function uses (winLimit) for RAW/RLE blocks only, - because this function can decode single RAW/RLE block in several different calls. - - this function DOESN'T use (winLimit) for Compressed blocks, - because this function decodes full compressed block in single call. - (CZstdDec1::winPos <= winLimit) - (winLimit <= CZstdDec1::cycSize). - Note: if (ds->outBuf_fromCaller) mode is used, then - { - (strong_limit) is stored in CZstdDec1::cycSize. - So (winLimit) is more strong than (strong_limit). - } - -exit: - Note: (CZstdDecState::winPos) will be set by caller after exit of this function. - - This function can exit for any of these conditions: - - (frameState == ZSTD2_STATE_AFTER_HEADER) - - (frameState == ZSTD2_STATE_FINISHED) : frame was finished : (status == ZSTD_STATUS_FINISHED_FRAME) is set - - finished non-empty non-last block. So (CZstdDec1::winPos_atExit != winPos_atFuncStart). - - ZSTD_STATUS_NEEDS_MORE_INPUT in src - - (CZstdDec1::winPos) have reached (winLimit) in non-finished RAW/RLE block - - This function decodes no more than one non-empty block. - So it fulfills the condition at exit: - (CZstdDec1::winPos_atExit - winPos_atFuncStart <= block_size_max) - Note: (winPos_atExit > winLimit) is possible in some cases after compressed block decoding. - - if (ds->outBuf_fromCaller) mode (useAdditionalWinLimit medo) - { - then this function uses additional strong limit from (CZstdDec1::cycSize). - So this function will not write any data after (CZstdDec1::cycSize) - And it fulfills the condition at exit: - (CZstdDec1::winPos_atExit <= CZstdDec1::cycSize) - } -*/ -static SRes ZstdDec_DecodeBlock(CZstdDec * const p, CZstdDecState * const ds, - SizeT winLimitAdd) -{ - const Byte *src = ds->inBuf; - SizeT * const srcLen = &ds->inPos; - const SizeT inSize = ds->inLim; - // const int useAdditionalWinLimit = ds->outBuf_fromCaller ? 1 : 0; - enum_ZstdStatus * const status = &ds->status; - CZstdDecInfo * const info = &ds->info; - SizeT winLimit; - - const SizeT winPos_atFuncStart = p->decoder.winPos; - src += *srcLen; - *status = ZSTD_STATUS_NOT_SPECIFIED; - - // finishMode = ZSTD_FINISH_ANY; - if (ds->outSize_Defined) - { - if (ds->outSize < ds->outProcessed) - { - // p->isAfterSizeMode = 2; // we have extra bytes already - *status = ZSTD_STATUS_OUT_REACHED; - return SZ_OK; - // size = 0; - } - else - { - // p->outSize >= p->outProcessed - const UInt64 rem = ds->outSize - ds->outProcessed; - /* - if (rem == 0) - p->isAfterSizeMode = 1; // we have reached exact required size - */ - if (winLimitAdd >= rem) - { - winLimitAdd = (SizeT)rem; - // if (p->finishMode) finishMode = ZSTD_FINISH_END; - } - } - } - - winLimit = p->decoder.winPos + winLimitAdd; - // (p->decoder.winPos <= winLimit) - - // while (p->frameState != ZSTD2_STATE_ERROR) - while (!p->isErrorState) - { - SizeT inCur = inSize - *srcLen; - - if (p->frameState == ZSTD2_STATE_DATA) - { - /* (p->decoder.winPos == winPos_atFuncStart) is expected, - because this function doesn't start new block. - if it have finished some non-empty block in this call. */ - if (p->decoder.winPos != winPos_atFuncStart) - return SZ_ERROR_FAIL; // it's unexpected - - /* - if (p->decoder.winPos > winLimit) - { - // we can be here, if in this function call - // - we have extracted non-empty compressed block, and (winPos > winLimit) after that. - // - we have started new block decoding after that. - // It's unexpected case, because we exit after non-empty non-last block. - *status = (inSize == *srcLen) ? - ZSTD_STATUS_NEEDS_MORE_INPUT : - ZSTD_STATUS_NOT_FINISHED; - return SZ_OK; - } - */ - // p->decoder.winPos <= winLimit - - if (p->blockType != kBlockType_Compressed) - { - // it's RLE or RAW block. - // p->BlockSize != 0_ - // winLimit <= p->decoder.cycSize - /* So here we use more strong (winLimit), even for - (ds->outBuf_fromCaller) mode. */ - SizeT outCur = winLimit - p->decoder.winPos; - { - const UInt32 rem = p->blockSize; - if (outCur > rem) - outCur = rem; - } - if (p->blockType == kBlockType_Raw) - { - if (outCur > inCur) - outCur = inCur; - /* output buffer is better aligned for XXH code. - So we use hash for output buffer data */ - // ZstdDec_Update_XXH(p, src, outCur); // for debug: - memcpy(p->decoder.win + p->decoder.winPos, src, outCur); - src += outCur; - *srcLen += outCur; - } - else // kBlockType_RLE - { - #define RLE_BYTE_INDEX_IN_temp 3 - memset(p->decoder.win + p->decoder.winPos, - p->temp[RLE_BYTE_INDEX_IN_temp], outCur); - } - { - const SizeT xxh64_winPos = p->decoder.winPos - ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p); - p->decoder.winPos += outCur; - UPDATE_TOTAL_OUT(&p->decoder, outCur) - p->contentProcessed += outCur; - ZstdDec_Update_XXH(p, xxh64_winPos); - } - // ds->winPos = p->decoder.winPos; // the caller does it instead. for debug: - ds->outProcessed += outCur; - if (p->blockSize -= (UInt32)outCur) - { - /* - if (ds->outSize_Defined) - { - if (ds->outSize <= ds->outProcessed) ds->isAfterSizeMode = (enum_ZstdStatus) - (ds->outSize == ds->outProcessed ? 1u: 2u); - } - */ - *status = (enum_ZstdStatus) - (ds->outSize_Defined && ds->outSize <= ds->outProcessed ? - ZSTD_STATUS_OUT_REACHED : (p->blockType == kBlockType_Raw && inSize == *srcLen) ? - ZSTD_STATUS_NEEDS_MORE_INPUT : - ZSTD_STATUS_NOT_FINISHED); - return SZ_OK; - } - } - else // kBlockType_Compressed - { - // p->blockSize != 0 - // (uncompressed_size_of_block == 0) is allowed - // (p->curBlockUnpackRem == 0) is allowed - /* - if (p->decoder.winPos >= winLimit) - { - if (p->decoder.winPos != winPos_atFuncStart) - { - // it's unexpected case - // We already have some data in finished blocks in this function call. - // So we don't decompress new block after (>=winLimit), - // even if it's empty block. - *status = (inSize == *srcLen) ? - ZSTD_STATUS_NEEDS_MORE_INPUT : - ZSTD_STATUS_NOT_FINISHED; - return SZ_OK; - } - // (p->decoder.winPos == winLimit == winPos_atFuncStart) - // we will decode current block, because that current - // block can be empty block and we want to make some visible - // change of (src) stream after function start. - } - */ - /* - if (ds->outSize_Defined && ds->outSize < ds->outProcessed) - { - // we don't want to start new block, if we have more extra decoded bytes already - *status = ZSTD_STATUS_OUT_REACHED; - return SZ_OK; - } - */ - { - const Byte *comprStream; - size_t afterAvail; - UInt32 inTempPos = p->inTempPos; - const UInt32 rem = p->blockSize - inTempPos; - // rem != 0 - if (inTempPos != 0 // (inTemp) buffer already contains some input data - || inCur < rem // available input data size is smaller than compressed block size - || ZstdDec1_NeedTempBufferForInput(*srcLen, src, rem)) - { - if (inCur > rem) - inCur = rem; - if (inCur) - { - STAT_INC(g_Num_Blocks_memcpy) - // we clear data for backward lookahead reading - if (inTempPos == 0) - memset(p->inTemp + kTempBuffer_PreSize - MAX_BACKWARD_DEPTH, 0, MAX_BACKWARD_DEPTH); - // { unsigned y = 0; for(;y < 1000; y++) - memcpy(p->inTemp + inTempPos + kTempBuffer_PreSize, src, inCur); - // } - src += inCur; - *srcLen += inCur; - inTempPos += (UInt32)inCur; - p->inTempPos = inTempPos; - } - if (inTempPos != p->blockSize) - { - *status = ZSTD_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - #if COPY_CHUNK_SIZE > 1 - memset(p->inTemp + kTempBuffer_PreSize + inTempPos, 0, COPY_CHUNK_SIZE); - #endif - comprStream = p->inTemp + kTempBuffer_PreSize; - afterAvail = k_Lit_AfterAvail; - // we don't want to read non-initialized data or junk in CopyMatch(): - } - else - { - // inCur >= rem - // we use direct decoding from (src) buffer: - afterAvail = inCur - rem; - comprStream = src; - src += rem; - *srcLen += rem; - } - - #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP - ZstdDec1_NeedTempBufferForInput(*srcLen, comprStream, p->blockSize); - #endif - // printf("\nblockSize=%u", p->blockSize); - // printf("%x\n", (unsigned)p->contentProcessed); - STAT_INC(g_Num_Blocks_Compressed) - { - SRes sres; - const size_t winPos = p->decoder.winPos; - /* - if ( useAdditionalWinLimit), we use strong unpack limit: smallest from - - limit from stream : (curBlockUnpackRem) - - limit from caller : (cycSize - winPos) - if (!useAdditionalWinLimit), we use only relaxed limit: - - limit from stream : (curBlockUnpackRem) - */ - SizeT outLimit = p->curBlockUnpackRem; - if (ds->outBuf_fromCaller) - // if (useAdditionalWinLimit) - { - const size_t limit = p->decoder.cycSize - winPos; - if (outLimit > limit) - outLimit = limit; - } - sres = ZstdDec1_DecodeBlock(&p->decoder, - comprStream, p->blockSize, afterAvail, outLimit); - // ds->winPos = p->decoder.winPos; // the caller does it instead. for debug: - if (sres) - { - p->isErrorState = True; - return sres; - } - { - const SizeT xxh64_winPos = winPos - ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p); - const size_t num = p->decoder.winPos - winPos; - ds->outProcessed += num; - p->contentProcessed += num; - ZstdDec_Update_XXH(p, xxh64_winPos); - } - } - // printf("\nwinPos=%x", (int)(unsigned)p->decoder.winPos); - } - } - - /* - if (ds->outSize_Defined) - { - if (ds->outSize <= ds->outProcessed) ds->isAfterSizeMode = (enum_ZstdStatus) - (ds->outSize == ds->outProcessed ? 1u: 2u); - } - */ - - if (!ZSTD_DEC_IS_LAST_BLOCK(p)) - { - p->frameState = ZSTD2_STATE_BLOCK; - if (ds->outSize_Defined && ds->outSize < ds->outProcessed) - { - *status = ZSTD_STATUS_OUT_REACHED; - return SZ_OK; - } - // we exit only if (winPos) was changed in this function call: - if (p->decoder.winPos != winPos_atFuncStart) - { - // decoded block was not empty. So we exit: - *status = (enum_ZstdStatus)( - (inSize == *srcLen) ? - ZSTD_STATUS_NEEDS_MORE_INPUT : - ZSTD_STATUS_NOT_FINISHED); - return SZ_OK; - } - // (p->decoder.winPos == winPos_atFuncStart) - // so current decoded block was empty. - // we will try to decode more blocks in this function. - continue; - } - - // decoded block was last in frame - if (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM) - { - p->frameState = ZSTD2_STATE_HASH; - if (ds->outSize_Defined && ds->outSize < ds->outProcessed) - { - *status = ZSTD_STATUS_OUT_REACHED; - return SZ_OK; // disable if want to - /* We want to get same return codes for any input buffer sizes. - We want to get faster ZSTD_STATUS_OUT_REACHED status. - So we exit with ZSTD_STATUS_OUT_REACHED here, - instead of ZSTD2_STATE_HASH and ZSTD2_STATE_FINISHED processing. - that depends from input buffer size and that can set - ZSTD_STATUS_NEEDS_MORE_INPUT or return SZ_ERROR_DATA or SZ_ERROR_CRC. - */ - } - } - else - { - /* ZSTD2_STATE_FINISHED proccesing doesn't depend from input buffer */ - p->frameState = ZSTD2_STATE_FINISHED; - } - /* - p->frameState = (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM) ? - ZSTD2_STATE_HASH : - ZSTD2_STATE_FINISHED; - */ - /* it's required to process ZSTD2_STATE_FINISHED state in this function call, - because we must check contentSize and hashError in ZSTD2_STATE_FINISHED code, - while the caller can reinit full state for ZSTD2_STATE_FINISHED - So we can't exit from function here. */ - continue; - } - - if (p->frameState == ZSTD2_STATE_FINISHED) - { - *status = ZSTD_STATUS_FINISHED_FRAME; - if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor) - && p->contentSize != p->contentProcessed) - return SZ_ERROR_DATA; - if (p->hashError) // for debug - return SZ_ERROR_CRC; - return SZ_OK; - // p->frameState = ZSTD2_STATE_SIGNATURE; - // continue; - } - - if (p->frameState == ZSTD2_STATE_AFTER_HEADER) - return SZ_OK; // we need memory allocation for that state - - if (p->frameState == ZSTD2_STATE_SKIP_DATA) - { - UInt32 blockSize = p->blockSize; - // (blockSize == 0) is possible - if (inCur > blockSize) - inCur = blockSize; - src += inCur; - *srcLen += inCur; - blockSize -= (UInt32)inCur; - p->blockSize = blockSize; - if (blockSize == 0) - { - p->frameState = ZSTD2_STATE_SIGNATURE; - // continue; // for debug: we can continue without return to caller. - // we notify the caller that skip frame was finished: - *status = ZSTD_STATUS_FINISHED_FRAME; - return SZ_OK; - } - // blockSize != 0 - // (inCur) was smaller than previous value of p->blockSize. - // (inSize == *srcLen) now - *status = ZSTD_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - if (inCur == 0) - { - *status = ZSTD_STATUS_NEEDS_MORE_INPUT; - return SZ_OK; - } - - { - (*srcLen)++; - p->frameState = ZstdDec_UpdateState(p, *src++, info); - } - } - - *status = ZSTD_STATUS_NOT_SPECIFIED; - p->isErrorState = True; - // p->frameState = ZSTD2_STATE_ERROR; - // if (p->frameState = ZSTD2_STATE_SIGNATURE) return SZ_ERROR_NO_ARCHIVE - return SZ_ERROR_DATA; -} - - - - -SRes ZstdDec_Decode(CZstdDecHandle dec, CZstdDecState *p) -{ - p->needWrite_Size = 0; - p->status = ZSTD_STATUS_NOT_SPECIFIED; - dec->disableHash = p->disableHash; - - if (p->outBuf_fromCaller) - { - dec->decoder.win = p->outBuf_fromCaller; - dec->decoder.cycSize = p->outBufSize_fromCaller; - } - - // p->winPos = dec->decoder.winPos; - - for (;;) - { - SizeT winPos, size; - // SizeT outProcessed; - SRes res; - - if (p->wrPos > dec->decoder.winPos) - return SZ_ERROR_FAIL; - - if (dec->frameState == ZSTD2_STATE_FINISHED) - { - if (!p->outBuf_fromCaller) - { - // we need to set positions to zero for new frame. - if (p->wrPos != dec->decoder.winPos) - { - /* We have already asked the caller to flush all data - with (p->needWrite_Size) and (ZSTD_STATUS_FINISHED_FRAME) status. - So it's unexpected case */ - // p->winPos = dec->decoder.winPos; - // p->needWrite_Size = dec->decoder.winPos - p->wrPos; // flush size asking - // return SZ_OK; // ask to flush again - return SZ_ERROR_FAIL; - } - // (p->wrPos == dec->decoder.winPos), and we wrap to zero: - dec->decoder.winPos = 0; - p->winPos = 0; - p->wrPos = 0; - } - ZstdDec_Init_ForNewFrame(dec); - // continue; - } - - winPos = dec->decoder.winPos; - { - SizeT next = dec->decoder.cycSize; - /* cycSize == 0, if no buffer was allocated still, - or, if (outBuf_fromCaller) mode and (outBufSize_fromCaller == 0) */ - if (!p->outBuf_fromCaller - && next - && next <= winPos - && dec->isCyclicMode) - { - // (0 < decoder.cycSize <= winPos) in isCyclicMode. - // so we need to wrap (winPos) and (wrPos) over (cycSize). - const size_t delta = next; - // (delta) is how many bytes we remove from buffer. - /* - // we don't need data older than last (cycSize) bytes. - size_t delta = winPos - next; // num bytes after (cycSize) - if (delta <= next) // it's expected case - delta = next; - // delta == Max(cycSize, winPos - cycSize) - */ - if (p->wrPos < delta) - { - // (wrPos < decoder.cycSize) - // We have asked already the caller to flush required data - // p->status = ZSTD_STATUS_NOT_SPECIFIED; - // p->winPos = winPos; - // p->needWrite_Size = delta - p->wrPos; // flush size asking - // return SZ_OK; // ask to flush again - return SZ_ERROR_FAIL; - } - // p->wrPos >= decoder.cycSize - // we move extra data after (decoder.cycSize) to start of cyclic buffer: - winPos -= delta; - if (winPos) - { - if (winPos >= delta) - return SZ_ERROR_FAIL; - memmove(dec->decoder.win, dec->decoder.win + delta, winPos); - // printf("\nmemmove processed=%8x winPos=%8x\n", (unsigned)p->outProcessed, (unsigned)dec->decoder.winPos); - STAT_INC(g_Num_Wrap_memmove_Num) - STAT_UPDATE(g_Num_Wrap_memmove_Bytes += (unsigned)winPos;) - } - dec->decoder.winPos = winPos; - p->winPos = winPos; - p->wrPos -= delta; - // dec->xxh64_winPos -= delta; - - // (winPos < delta) - #ifdef Z7_STD_DEC_USE_AFTER_CYC_BUF - /* we set the data after cycSize, because - we don't want to read non-initialized data or junk in CopyMatch(). */ - memset(dec->decoder.win + next, 0, COPY_CHUNK_SIZE); - #endif - - /* - if (winPos == next) - { - if (winPos != p->wrPos) - { - // we already requested before to flush full data for that case. - // but we give the caller a second chance to flush data: - p->needWrite_Size = winPos - p->wrPos; - return SZ_OK; - } - // (decoder.cycSize == winPos == p->wrPos) - // so we do second wrapping to zero: - winPos = 0; - dec->decoder.winPos = 0; - p->winPos = 0; - p->wrPos = 0; - } - */ - // (winPos < next) - } - - if (winPos > next) - return SZ_ERROR_FAIL; // it's unexpected case - /* - if (!outBuf_fromCaller && isCyclicMode && cycSize != 0) - then (winPos < cycSize) - else (winPos <= cycSize) - */ - if (!p->outBuf_fromCaller) - { - // that code is optional. We try to optimize write chunk sizes. - /* (next2) is expected next write position in the caller, - if the caller writes by kBlockSizeMax chunks. - */ - /* - const size_t next2 = (winPos + kBlockSizeMax) & (kBlockSizeMax - 1); - if (winPos < next2 && next2 < next) - next = next2; - */ - } - size = next - winPos; - } - - // note: ZstdDec_DecodeBlock() uses (winLimit = winPos + size) only for RLE and RAW blocks - res = ZstdDec_DecodeBlock(dec, p, size); - /* - after one block decoding: - if (!outBuf_fromCaller && isCyclicMode && cycSize != 0) - then (winPos < cycSize + max_block_size) - else (winPos <= cycSize) - */ - - if (!p->outBuf_fromCaller) - p->win = dec->decoder.win; - p->winPos = dec->decoder.winPos; - - // outProcessed = dec->decoder.winPos - winPos; - // p->outProcessed += outProcessed; - - if (res != SZ_OK) - return res; - - if (dec->frameState != ZSTD2_STATE_AFTER_HEADER) - { - if (p->outBuf_fromCaller) - return SZ_OK; - { - // !p->outBuf_fromCaller - /* - if (ZSTD_STATUS_FINISHED_FRAME), we request full flushing here because - 1) it's simpler to work with allocation and extracting of next frame, - 2) it's better to start writing to next new frame with aligned memory - for faster xxh 64-bit reads. - */ - size_t end = dec->decoder.winPos; // end pos for all data flushing - if (p->status != ZSTD_STATUS_FINISHED_FRAME) - { - // we will request flush here only for cases when wrap in cyclic buffer can be required in next call. - if (!dec->isCyclicMode) - return SZ_OK; - // isCyclicMode - { - const size_t delta = dec->decoder.cycSize; - if (end < delta) - return SZ_OK; // (winPos < cycSize). no need for flush - // cycSize <= winPos - // So we ask the caller to flush of (cycSize - wrPos) bytes, - // and then we will wrap cylicBuffer in next call - end = delta; - } - } - p->needWrite_Size = end - p->wrPos; - } - return SZ_OK; - } - - // ZSTD2_STATE_AFTER_HEADER - { - BoolInt useCyclic = False; - size_t cycSize; - - // p->status = ZSTD_STATUS_NOT_FINISHED; - if (dec->dictionaryId != 0) - { - /* actually we can try to decode some data, - because it's possible that some data doesn't use dictionary */ - // p->status = ZSTD_STATUS_NOT_SPECIFIED; - return SZ_ERROR_UNSUPPORTED; - } - - { - UInt64 winSize = dec->contentSize; - UInt64 winSize_Allocate = winSize; - const unsigned descriptor = dec->descriptor; - - if ((descriptor & DESCRIPTOR_FLAG_SINGLE) == 0) - { - const Byte wd = dec->windowDescriptor; - winSize = (UInt64)(8 + (wd & 7)) << ((wd >> 3) + 10 - 3); - if (!DESCRIPTOR_Is_ContentSize_Defined(descriptor) - || winSize_Allocate > winSize) - { - winSize_Allocate = winSize; - useCyclic = True; - } - } - /* - else - { - if (p->info.singleSegment_ContentSize_MAX < winSize) - p->info.singleSegment_ContentSize_MAX = winSize; - // p->info.num_SingleSegments++; - } - */ - if (p->info.windowSize_MAX < winSize) - p->info.windowSize_MAX = winSize; - if (p->info.windowSize_Allocate_MAX < winSize_Allocate) - p->info.windowSize_Allocate_MAX = winSize_Allocate; - /* - winSize_Allocate is MIN(content_size, window_size_from_descriptor). - Wven if (content_size < (window_size_from_descriptor)) - original-zstd still uses (window_size_from_descriptor) to check that decoding is allowed. - We try to follow original-zstd, and here we check (winSize) instead of (winSize_Allocate)) - */ - if ( - // winSize_Allocate // it's relaxed check - winSize // it's more strict check to be compatible with original-zstd - > ((UInt64)1 << MAX_WINDOW_SIZE_LOG)) - return SZ_ERROR_UNSUPPORTED; // SZ_ERROR_MEM - cycSize = (size_t)winSize_Allocate; - if (cycSize != winSize_Allocate) - return SZ_ERROR_MEM; - // cycSize <= winSize - /* later we will use (CZstdDec1::winSize) to check match offsets and check block sizes. - if (there is window descriptor) - { - We will check block size with (window_size_from_descriptor) instead of (winSize_Allocate). - Does original-zstd do it that way also? - } - Here we must reduce full real 64-bit (winSize) to size_t for (CZstdDec1::winSize). - Also we don't want too big values for (CZstdDec1::winSize). - our (CZstdDec1::winSize) will meet the condition: - (CZstdDec1::winSize < kBlockSizeMax || CZstdDec1::winSize <= cycSize). - */ - dec->decoder.winSize = (winSize < kBlockSizeMax) ? (size_t)winSize: cycSize; - // note: (CZstdDec1::winSize > cycSize) is possible, if (!useCyclic) - } - - RINOK(ZstdDec_AllocateMisc(dec)) - - if (p->outBuf_fromCaller) - dec->isCyclicMode = False; - else - { - size_t d = cycSize; - - if (dec->decoder.winPos != p->wrPos) - return SZ_ERROR_FAIL; - - dec->decoder.winPos = 0; - p->wrPos = 0; - p->winPos = dec->decoder.winPos; - - /* - const size_t needWrite = dec->decoder.winPos - p->wrPos; - if (!needWrite) - { - dec->decoder.winPos = 0; - p->wrPos = 0; - p->winPos = dec->decoder.winPos; - } - */ - /* if (!useCyclic) we allocate only cycSize = ContentSize. - But if we want to support the case where new frame starts with winPos != 0, - then we will wrap over zero, and we still need - to set (useCyclic) and allocate additional buffer spaces. - Now we don't allow new frame starting with (winPos != 0). - so (dec->decoder->winPos == 0) - can use (!useCyclic) with reduced buffer sizes. - */ - /* - if (dec->decoder->winPos != 0) - useCyclic = True; - */ - - if (useCyclic) - { - /* cyclyc buffer size must be at least (COPY_CHUNK_SIZE - 1) bytes - larger than window size, because CopyMatch() can write additional - (COPY_CHUNK_SIZE - 1) bytes and overwrite oldests data in cyclyc buffer. - But for performance reasons we align (cycSize) for (kBlockSizeMax). - also we must provide (cycSize >= max_decoded_data_after_cycSize), - because after data move wrapping over zero we must provide (winPos < cycSize). - */ - const size_t alignSize = kBlockSizeMax; - /* here we add (1 << 7) instead of (COPY_CHUNK_SIZE - 1), because - we want to get same (cycSize) for different COPY_CHUNK_SIZE values. */ - // cycSize += (COPY_CHUNK_SIZE - 1) + (alignSize - 1); // for debug : we can get smallest (cycSize) - cycSize += (1 << 7) + alignSize; - cycSize &= ~(size_t)(alignSize - 1); - // cycSize must be aligned for 32, because xxh requires 32-bytes blocks. - // cycSize += 12345; // for debug - // cycSize += 1 << 10; // for debug - // cycSize += 32; // for debug - // cycSize += kBlockSizeMax; // for debug - if (cycSize < d) - return SZ_ERROR_MEM; - /* - in cyclic buffer mode we allow to decode one additional block - that exceeds (cycSize). - So we must allocate additional (kBlockSizeMax) bytes after (cycSize). - if defined(Z7_STD_DEC_USE_AFTER_CYC_BUF) - { - we can read (COPY_CHUNK_SIZE - 1) bytes after (cycSize) - but we aready allocate additional kBlockSizeMax that - is larger than COPY_CHUNK_SIZE. - So we don't need additional space of COPY_CHUNK_SIZE after (cycSize). - } - */ - /* - #ifdef Z7_STD_DEC_USE_AFTER_CYC_BUF - d = cycSize + (1 << 7); // we must add at least (COPY_CHUNK_SIZE - 1) - #endif - */ - d = cycSize + kBlockSizeMax; - if (d < cycSize) - return SZ_ERROR_MEM; - } - - { - const size_t kMinWinAllocSize = 1 << 12; - if (d < kMinWinAllocSize) - d = kMinWinAllocSize; - } - - if (d > dec->winBufSize_Allocated) - { - /* - if (needWrite) - { - p->needWrite_Size = needWrite; - return SZ_OK; - // return SZ_ERROR_FAIL; - } - */ - - if (dec->winBufSize_Allocated != 0) - { - const size_t k_extra = (useCyclic || d >= (1u << 20)) ? - 2 * kBlockSizeMax : 0; - unsigned i = useCyclic ? 17 : 12; - for (; i < sizeof(size_t) * 8; i++) - { - const size_t d2 = ((size_t)1 << i) + k_extra; - if (d2 >= d) - { - d = d2; - break; - } - } - } - // RINOK(ZstdDec_AllocateWindow(dec, d)) - ZstdDec_FreeWindow(dec); - dec->win_Base = (Byte *)ISzAlloc_Alloc(dec->alloc_Big, d); - if (!dec->win_Base) - return SZ_ERROR_MEM; - dec->decoder.win = dec->win_Base; - dec->winBufSize_Allocated = d; - } - /* - else - { - // for non-cyclycMode we want flush data, and set winPos = 0 - if (needWrite) - { - if (!useCyclic || dec->decoder.winPos >= cycSize) - { - p->needWrite_Size = needWrite; - return SZ_OK; - // return SZ_ERROR_FAIL; - } - } - } - */ - - dec->decoder.cycSize = cycSize; - p->win = dec->decoder.win; - // p->cycSize = dec->decoder.cycSize; - dec->isCyclicMode = (Byte)useCyclic; - } // (!p->outBuf_fromCaller) end - - // p->winPos = dec->decoder.winPos; - dec->frameState = ZSTD2_STATE_BLOCK; - // continue; - } // ZSTD2_STATE_AFTER_HEADER end - } -} - - -void ZstdDec_GetResInfo(const CZstdDec *dec, - const CZstdDecState *p, - SRes res, - CZstdDecResInfo *stat) -{ - // ZstdDecInfo_CLEAR(stat); - stat->extraSize = 0; - stat->is_NonFinishedFrame = False; - if (dec->frameState != ZSTD2_STATE_FINISHED) - { - if (dec->frameState == ZSTD2_STATE_SIGNATURE) - { - stat->extraSize = (Byte)dec->tempSize; - if (ZstdDecInfo_GET_NUM_FRAMES(&p->info) == 0) - res = SZ_ERROR_NO_ARCHIVE; - } - else - { - stat->is_NonFinishedFrame = True; - if (res == SZ_OK && p->status == ZSTD_STATUS_NEEDS_MORE_INPUT) - res = SZ_ERROR_INPUT_EOF; - } - } - stat->decode_SRes = res; -} - - -size_t ZstdDec_ReadUnusedFromInBuf( - CZstdDecHandle dec, - size_t afterDecoding_tempPos, - void *data, size_t size) -{ - size_t processed = 0; - if (dec->frameState == ZSTD2_STATE_SIGNATURE) - { - Byte *dest = (Byte *)data; - const size_t tempSize = dec->tempSize; - while (afterDecoding_tempPos < tempSize) - { - if (size == 0) - break; - size--; - *dest++ = dec->temp[afterDecoding_tempPos++]; - processed++; - } - } - return processed; -} - - -void ZstdDecState_Clear(CZstdDecState *p) -{ - memset(p, 0 , sizeof(*p)); -} +/* ZstdDec.c -- Zstd Decoder +2024-06-18 : the code was developed by Igor Pavlov, using Zstandard format + specification and original zstd decoder code as reference code. +original zstd decoder code: Copyright (c) Facebook, Inc. All rights reserved. +This source code is licensed under BSD 3-Clause License. +*/ + +#include "Precomp.h" + +#include +#include +// #include + +#include "Alloc.h" +#include "Xxh64.h" +#include "ZstdDec.h" +#include "CpuArch.h" + +#if defined(MY_CPU_ARM64) +#include +#endif + +/* original-zstd still doesn't support window larger than 2 GiB. + So we also limit our decoder for 2 GiB window: */ +#if defined(MY_CPU_64BIT) && 0 == 1 + #define MAX_WINDOW_SIZE_LOG 41 +#else + #define MAX_WINDOW_SIZE_LOG 31 +#endif + +typedef + #if MAX_WINDOW_SIZE_LOG < 32 + UInt32 + #else + size_t + #endif + CZstdDecOffset; + +// for debug: simpler and smaller code but slow: +// #define Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS + +// #define SHOW_STAT +#ifdef SHOW_STAT +#include +static unsigned g_Num_Blocks_Compressed = 0; +static unsigned g_Num_Blocks_memcpy = 0; +static unsigned g_Num_Wrap_memmove_Num = 0; +static unsigned g_Num_Wrap_memmove_Bytes = 0; +static unsigned g_NumSeqs_total = 0; +// static unsigned g_NumCopy = 0; +static unsigned g_NumOver = 0; +static unsigned g_NumOver2 = 0; +static unsigned g_Num_Match = 0; +static unsigned g_Num_Lits = 0; +static unsigned g_Num_LitsBig = 0; +static unsigned g_Num_Lit0 = 0; +static unsigned g_Num_Rep0 = 0; +static unsigned g_Num_Rep1 = 0; +static unsigned g_Num_Rep2 = 0; +static unsigned g_Num_Rep3 = 0; +static unsigned g_Num_Threshold_0 = 0; +static unsigned g_Num_Threshold_1 = 0; +static unsigned g_Num_Threshold_0sum = 0; +static unsigned g_Num_Threshold_1sum = 0; +#define STAT_UPDATE(v) v +#else +#define STAT_UPDATE(v) +#endif +#define STAT_INC(v) STAT_UPDATE(v++;) + + +typedef struct +{ + const Byte *ptr; + size_t len; +} +CInBufPair; + + +#if defined(MY_CPU_ARM_OR_ARM64) || defined(MY_CPU_X86_OR_AMD64) + #if (defined(__clang__) && (__clang_major__ >= 6)) \ + || (defined(__GNUC__) && (__GNUC__ >= 6)) + // disable for debug: + #define Z7_ZSTD_DEC_USE_BSR + #elif defined(_MSC_VER) && (_MSC_VER >= 1300) + // #if defined(MY_CPU_ARM_OR_ARM64) + #if (_MSC_VER >= 1600) + #include + #endif + // disable for debug: + #define Z7_ZSTD_DEC_USE_BSR + #endif +#endif + +#ifdef Z7_ZSTD_DEC_USE_BSR + #if defined(__clang__) || defined(__GNUC__) + #define MY_clz(x) ((unsigned)__builtin_clz((UInt32)x)) + #else // #if defined(_MSC_VER) + #ifdef MY_CPU_ARM_OR_ARM64 + #define MY_clz _CountLeadingZeros + #endif // MY_CPU_X86_OR_AMD64 + #endif // _MSC_VER +#elif !defined(Z7_ZSTD_DEC_USE_LOG_TABLE) + #define Z7_ZSTD_DEC_USE_LOG_TABLE +#endif + + +static +Z7_FORCE_INLINE +unsigned GetHighestSetBit_32_nonzero_big(UInt32 num) +{ + // (num != 0) + #ifdef MY_clz + return 31 - MY_clz(num); + #elif defined(Z7_ZSTD_DEC_USE_BSR) + { + unsigned long zz; + _BitScanReverse(&zz, num); + return zz; + } + #else + { + int i = -1; + for (;;) + { + i++; + num >>= 1; + if (num == 0) + return (unsigned)i; + } + } + #endif +} + +#ifdef Z7_ZSTD_DEC_USE_LOG_TABLE + +#define R1(a) a, a +#define R2(a) R1(a), R1(a) +#define R3(a) R2(a), R2(a) +#define R4(a) R3(a), R3(a) +#define R5(a) R4(a), R4(a) +#define R6(a) R5(a), R5(a) +#define R7(a) R6(a), R6(a) +#define R8(a) R7(a), R7(a) +#define R9(a) R8(a), R8(a) + +#define Z7_ZSTD_FSE_MAX_ACCURACY 9 +// states[] values in FSE_Generate() can use (Z7_ZSTD_FSE_MAX_ACCURACY + 1) bits. +static const Byte k_zstd_LogTable[2 << Z7_ZSTD_FSE_MAX_ACCURACY] = +{ + R1(0), R1(1), R2(2), R3(3), R4(4), R5(5), R6(6), R7(7), R8(8), R9(9) +}; + +#define GetHighestSetBit_32_nonzero_small(num) (k_zstd_LogTable[num]) +#else +#define GetHighestSetBit_32_nonzero_small GetHighestSetBit_32_nonzero_big +#endif + + +#ifdef MY_clz + #define UPDATE_BIT_OFFSET_FOR_PADDING(b, bitOffset) \ + bitOffset -= (CBitCtr)(MY_clz(b) - 23); +#elif defined(Z7_ZSTD_DEC_USE_BSR) + #define UPDATE_BIT_OFFSET_FOR_PADDING(b, bitOffset) \ + { unsigned long zz; _BitScanReverse(&zz, b); bitOffset -= 8; bitOffset += zz; } +#else + #define UPDATE_BIT_OFFSET_FOR_PADDING(b, bitOffset) \ + for (;;) { bitOffset--; if (b & 0x80) { break; } b <<= 1; } +#endif + +#define SET_bitOffset_TO_PAD(bitOffset, src, srcLen) \ +{ \ + unsigned lastByte = (src)[(size_t)(srcLen) - 1]; \ + if (lastByte == 0) return SZ_ERROR_DATA; \ + bitOffset = (CBitCtr)((srcLen) * 8); \ + UPDATE_BIT_OFFSET_FOR_PADDING(lastByte, bitOffset) \ +} + +#ifndef Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS + +#define SET_bitOffset_TO_PAD_and_SET_BIT_SIZE(bitOffset, src, srcLen_res) \ +{ \ + unsigned lastByte = (src)[(size_t)(srcLen_res) - 1]; \ + if (lastByte == 0) return SZ_ERROR_DATA; \ + srcLen_res *= 8; \ + bitOffset = (CBitCtr)srcLen_res; \ + UPDATE_BIT_OFFSET_FOR_PADDING(lastByte, bitOffset) \ +} + +#endif + +/* +typedef Int32 CBitCtr_signed; +typedef Int32 CBitCtr; +*/ +// /* +typedef ptrdiff_t CBitCtr_signed; +typedef ptrdiff_t CBitCtr; +// */ + + +#define MATCH_LEN_MIN 3 +#define kBlockSizeMax (1u << 17) + +// #define Z7_ZSTD_DEC_PRINT_TABLE + +#ifdef Z7_ZSTD_DEC_PRINT_TABLE +#define NUM_OFFSET_SYMBOLS_PREDEF 29 +#endif +#define NUM_OFFSET_SYMBOLS_MAX (MAX_WINDOW_SIZE_LOG + 1) // 32 +#define NUM_LL_SYMBOLS 36 +#define NUM_ML_SYMBOLS 53 +#define FSE_NUM_SYMBOLS_MAX 53 // NUM_ML_SYMBOLS + +// /* +#if !defined(MY_CPU_X86) || defined(__PIC__) || defined(MY_CPU_64BIT) +#define Z7_ZSTD_DEC_USE_BASES_IN_OBJECT +#endif +// */ +// for debug: +// #define Z7_ZSTD_DEC_USE_BASES_LOCAL +// #define Z7_ZSTD_DEC_USE_BASES_IN_OBJECT + +#define GLOBAL_TABLE(n) k_ ## n + +#if defined(Z7_ZSTD_DEC_USE_BASES_LOCAL) + #define BASES_TABLE(n) a_ ## n +#elif defined(Z7_ZSTD_DEC_USE_BASES_IN_OBJECT) + #define BASES_TABLE(n) p->m_ ## n +#else + #define BASES_TABLE(n) GLOBAL_TABLE(n) +#endif + +#define Z7_ZSTD_DEC_USE_ML_PLUS3 + +#if defined(Z7_ZSTD_DEC_USE_BASES_LOCAL) || \ + defined(Z7_ZSTD_DEC_USE_BASES_IN_OBJECT) + +#define SEQ_EXTRA_TABLES(n) \ + Byte n ## SEQ_LL_EXTRA [NUM_LL_SYMBOLS]; \ + Byte n ## SEQ_ML_EXTRA [NUM_ML_SYMBOLS]; \ + UInt32 n ## SEQ_LL_BASES [NUM_LL_SYMBOLS]; \ + UInt32 n ## SEQ_ML_BASES [NUM_ML_SYMBOLS]; \ + +#define Z7_ZSTD_DEC_USE_BASES_CALC + +#ifdef Z7_ZSTD_DEC_USE_BASES_CALC + + #define FILL_LOC_BASES(n, startSum) \ + { unsigned i; UInt32 sum = startSum; \ + for (i = 0; i != Z7_ARRAY_SIZE(GLOBAL_TABLE(n ## _EXTRA)); i++) \ + { const unsigned a = GLOBAL_TABLE(n ## _EXTRA)[i]; \ + BASES_TABLE(n ## _BASES)[i] = sum; \ + /* if (sum != GLOBAL_TABLE(n ## _BASES)[i]) exit(1); */ \ + sum += (UInt32)1 << a; \ + BASES_TABLE(n ## _EXTRA)[i] = (Byte)a; }} + + #define FILL_LOC_BASES_ALL \ + FILL_LOC_BASES (SEQ_LL, 0) \ + FILL_LOC_BASES (SEQ_ML, MATCH_LEN_MIN) \ + +#else + #define COPY_GLOBAL_ARR(n) \ + memcpy(BASES_TABLE(n), GLOBAL_TABLE(n), sizeof(GLOBAL_TABLE(n))); + #define FILL_LOC_BASES_ALL \ + COPY_GLOBAL_ARR (SEQ_LL_EXTRA) \ + COPY_GLOBAL_ARR (SEQ_ML_EXTRA) \ + COPY_GLOBAL_ARR (SEQ_LL_BASES) \ + COPY_GLOBAL_ARR (SEQ_ML_BASES) \ + +#endif + +#endif + + + +/// The sequence decoding baseline and number of additional bits to read/add +#if !defined(Z7_ZSTD_DEC_USE_BASES_CALC) +static const UInt32 GLOBAL_TABLE(SEQ_LL_BASES) [NUM_LL_SYMBOLS] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 18, 20, 22, 24, 28, 32, 40, 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, + 0x2000, 0x4000, 0x8000, 0x10000 +}; +#endif + +static const Byte GLOBAL_TABLE(SEQ_LL_EXTRA) [NUM_LL_SYMBOLS] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16 +}; + +#if !defined(Z7_ZSTD_DEC_USE_BASES_CALC) +static const UInt32 GLOBAL_TABLE(SEQ_ML_BASES) [NUM_ML_SYMBOLS] = +{ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, + 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 +}; +#endif + +static const Byte GLOBAL_TABLE(SEQ_ML_EXTRA) [NUM_ML_SYMBOLS] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16 +}; + + +#ifdef Z7_ZSTD_DEC_PRINT_TABLE + +static const Int16 SEQ_LL_PREDEF_DIST [NUM_LL_SYMBOLS] = +{ + 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, + -1,-1,-1,-1 +}; +static const Int16 SEQ_OFFSET_PREDEF_DIST [NUM_OFFSET_SYMBOLS_PREDEF] = +{ + 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 +}; +static const Int16 SEQ_ML_PREDEF_DIST [NUM_ML_SYMBOLS] = +{ + 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1, + -1,-1,-1,-1,-1 +}; + +#endif + +// typedef int FastInt; +// typedef Int32 FastInt32; +typedef unsigned FastInt; +typedef UInt32 FastInt32; +typedef FastInt32 CFseRecord; + + +#define FSE_REC_LEN_OFFSET 8 +#define FSE_REC_STATE_OFFSET 16 +#define GET_FSE_REC_SYM(st) ((Byte)(st)) +#define GET_FSE_REC_LEN(st) ((Byte)((st) >> FSE_REC_LEN_OFFSET)) +#define GET_FSE_REC_STATE(st) ((st) >> FSE_REC_STATE_OFFSET) + +// #define FSE_REC_SYM_MASK (0xff) +// #define GET_FSE_REC_SYM(st) (st & FSE_REC_SYM_MASK) + +#define W_BASE(state, len, sym) \ + (((UInt32)state << (4 + FSE_REC_STATE_OFFSET)) + \ + (len << FSE_REC_LEN_OFFSET) + (sym)) +#define W(state, len, sym) W_BASE(state, len, sym) +static const CFseRecord k_PredefRecords_LL[1 << 6] = { +W(0,4, 0),W(1,4, 0),W(2,5, 1),W(0,5, 3),W(0,5, 4),W(0,5, 6),W(0,5, 7),W(0,5, 9), +W(0,5,10),W(0,5,12),W(0,6,14),W(0,5,16),W(0,5,18),W(0,5,19),W(0,5,21),W(0,5,22), +W(0,5,24),W(2,5,25),W(0,5,26),W(0,6,27),W(0,6,29),W(0,6,31),W(2,4, 0),W(0,4, 1), +W(0,5, 2),W(2,5, 4),W(0,5, 5),W(2,5, 7),W(0,5, 8),W(2,5,10),W(0,5,11),W(0,6,13), +W(2,5,16),W(0,5,17),W(2,5,19),W(0,5,20),W(2,5,22),W(0,5,23),W(0,4,25),W(1,4,25), +W(2,5,26),W(0,6,28),W(0,6,30),W(3,4, 0),W(1,4, 1),W(2,5, 2),W(2,5, 3),W(2,5, 5), +W(2,5, 6),W(2,5, 8),W(2,5, 9),W(2,5,11),W(2,5,12),W(0,6,15),W(2,5,17),W(2,5,18), +W(2,5,20),W(2,5,21),W(2,5,23),W(2,5,24),W(0,6,35),W(0,6,34),W(0,6,33),W(0,6,32) +}; +static const CFseRecord k_PredefRecords_OF[1 << 5] = { +W(0,5, 0),W(0,4, 6),W(0,5, 9),W(0,5,15),W(0,5,21),W(0,5, 3),W(0,4, 7),W(0,5,12), +W(0,5,18),W(0,5,23),W(0,5, 5),W(0,4, 8),W(0,5,14),W(0,5,20),W(0,5, 2),W(1,4, 7), +W(0,5,11),W(0,5,17),W(0,5,22),W(0,5, 4),W(1,4, 8),W(0,5,13),W(0,5,19),W(0,5, 1), +W(1,4, 6),W(0,5,10),W(0,5,16),W(0,5,28),W(0,5,27),W(0,5,26),W(0,5,25),W(0,5,24) +}; +#if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) +#undef W +#define W(state, len, sym) W_BASE(state, len, (sym + MATCH_LEN_MIN)) +#endif +static const CFseRecord k_PredefRecords_ML[1 << 6] = { +W(0,6, 0),W(0,4, 1),W(2,5, 2),W(0,5, 3),W(0,5, 5),W(0,5, 6),W(0,5, 8),W(0,6,10), +W(0,6,13),W(0,6,16),W(0,6,19),W(0,6,22),W(0,6,25),W(0,6,28),W(0,6,31),W(0,6,33), +W(0,6,35),W(0,6,37),W(0,6,39),W(0,6,41),W(0,6,43),W(0,6,45),W(1,4, 1),W(0,4, 2), +W(2,5, 3),W(0,5, 4),W(2,5, 6),W(0,5, 7),W(0,6, 9),W(0,6,12),W(0,6,15),W(0,6,18), +W(0,6,21),W(0,6,24),W(0,6,27),W(0,6,30),W(0,6,32),W(0,6,34),W(0,6,36),W(0,6,38), +W(0,6,40),W(0,6,42),W(0,6,44),W(2,4, 1),W(3,4, 1),W(1,4, 2),W(2,5, 4),W(2,5, 5), +W(2,5, 7),W(2,5, 8),W(0,6,11),W(0,6,14),W(0,6,17),W(0,6,20),W(0,6,23),W(0,6,26), +W(0,6,29),W(0,6,52),W(0,6,51),W(0,6,50),W(0,6,49),W(0,6,48),W(0,6,47),W(0,6,46) +}; + + +// sum of freqs[] must be correct +// (numSyms != 0) +// (accuracy >= 5) +static +Z7_NO_INLINE +// Z7_FORCE_INLINE +void FSE_Generate(CFseRecord *table, + const Int16 *const freqs, const size_t numSyms, + const unsigned accuracy, UInt32 delta) +{ + size_t size = (size_t)1 << accuracy; + // max value in states[x] is ((1 << accuracy) * 2) + UInt16 states[FSE_NUM_SYMBOLS_MAX]; + { + /* Symbols with "less than 1" probability get a single cell, + starting from the end of the table. + These symbols define a full state reset, reading (accuracy) bits. */ + size_t threshold = size; + { + size_t s = 0; + do + if (freqs[s] == -1) + { + table[--threshold] = (CFseRecord)s; + states[s] = 1; + } + while (++s != numSyms); + } + + #ifdef SHOW_STAT + if (threshold == size) + { + STAT_INC(g_Num_Threshold_0) + STAT_UPDATE(g_Num_Threshold_0sum += (unsigned)size;) + } + else + { + STAT_INC(g_Num_Threshold_1) + STAT_UPDATE(g_Num_Threshold_1sum += (unsigned)size;) + } + #endif + + // { unsigned uuu; for (uuu = 0; uuu < 400; uuu++) + { + // Each (symbol) gets freqs[symbol] cells. + // Cell allocation is spread, not linear. + const size_t step = (size >> 1) + (size >> 3) + 3; + size_t pos = 0; + // const unsigned mask = size - 1; + /* + if (threshold == size) + { + size_t s = 0; + size--; + do + { + int freq = freqs[s]; + if (freq <= 0) + continue; + states[s] = (UInt16)freq; + do + { + table[pos] (CFseRecord)s; + pos = (pos + step) & size; // & mask; + } + while (--freq); + } + while (++s != numSyms); + } + else + */ + { + size_t s = 0; + size--; + do + { + int freq = freqs[s]; + if (freq <= 0) + continue; + states[s] = (UInt16)freq; + do + { + table[pos] = (CFseRecord)s; + // we skip position, if it's already occupied by a "less than 1" probability symbol. + // (step) is coprime to table size, so the cycle will visit each position exactly once + do + pos = (pos + step) & size; // & mask; + while (pos >= threshold); + } + while (--freq); + } + while (++s != numSyms); + } + size++; + // (pos != 0) is unexpected case that means that freqs[] are not correct. + // so it's some failure in code (for example, incorrect predefined freq[] table) + // if (pos != 0) return SZ_ERROR_FAIL; + } + // } + } + { + const CFseRecord * const limit = table + size; + delta = ((UInt32)size << FSE_REC_STATE_OFFSET) - delta; + /* State increases by symbol over time, decreasing number of bits. + Baseline increases until the bit threshold is passed, at which point it resets to 0 */ + do + { + #define TABLE_ITER(a) \ + { \ + const FastInt sym = (FastInt)table[a]; \ + const unsigned nextState = states[sym]; \ + unsigned nb; \ + states[sym] = (UInt16)(nextState + 1); \ + nb = accuracy - GetHighestSetBit_32_nonzero_small(nextState); \ + table[a] = (CFseRecord)(sym - delta \ + + ((UInt32)nb << FSE_REC_LEN_OFFSET) \ + + ((UInt32)nextState << FSE_REC_STATE_OFFSET << nb)); \ + } + TABLE_ITER(0) + TABLE_ITER(1) + table += 2; + } + while (table != limit); + } +} + + +#ifdef Z7_ZSTD_DEC_PRINT_TABLE + +static void Print_Predef(unsigned predefAccuracy, + const unsigned numSymsPredef, + const Int16 * const predefFreqs, + const CFseRecord *checkTable) +{ + CFseRecord table[1 << 6]; + unsigned i; + FSE_Generate(table, predefFreqs, numSymsPredef, predefAccuracy, + #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) + numSymsPredef == NUM_ML_SYMBOLS ? MATCH_LEN_MIN : + #endif + 0 + ); + if (memcmp(table, checkTable, sizeof(UInt32) << predefAccuracy) != 0) + exit(1); + for (i = 0; i < (1u << predefAccuracy); i++) + { + const UInt32 v = table[i]; + const unsigned state = (unsigned)(GET_FSE_REC_STATE(v)); + if (state & 0xf) + exit(1); + if (i != 0) + { + printf(","); + if (i % 8 == 0) + printf("\n"); + } + printf("W(%d,%d,%2d)", + (unsigned)(state >> 4), + (unsigned)((v >> FSE_REC_LEN_OFFSET) & 0xff), + (unsigned)GET_FSE_REC_SYM(v)); + } + printf("\n\n"); +} + +#endif + + +#define GET16(dest, p) { const Byte *ptr = p; dest = GetUi16(ptr); } +#define GET32(dest, p) { const Byte *ptr = p; dest = GetUi32(ptr); } + +// (1 <= numBits <= 9) +#define FORWARD_READ_BITS(destVal, numBits, mask) \ + { const CBitCtr_signed bos3 = (bitOffset) >> 3; \ + if (bos3 >= 0) return SZ_ERROR_DATA; \ + GET16(destVal, src + bos3) \ + destVal >>= (bitOffset) & 7; \ + bitOffset += (CBitCtr_signed)(numBits); \ + mask = (1u << (numBits)) - 1; \ + destVal &= mask; \ + } + +#define FORWARD_READ_1BIT(destVal) \ + { const CBitCtr_signed bos3 = (bitOffset) >> 3; \ + if (bos3 >= 0) return SZ_ERROR_DATA; \ + destVal = *(src + bos3); \ + destVal >>= (bitOffset) & 7; \ + (bitOffset)++; \ + destVal &= 1; \ + } + + +// in: (accuracyMax <= 9) +// at least 2 bytes will be processed from (in) stream. +// at return: (in->len > 0) +static +Z7_NO_INLINE +SRes FSE_DecodeHeader(CFseRecord *const table, + CInBufPair *const in, + const unsigned accuracyMax, + Byte *const accuracyRes, + unsigned numSymbolsMax) +{ + unsigned accuracy; + unsigned remain1; + unsigned syms; + Int16 freqs[FSE_NUM_SYMBOLS_MAX + 3]; // +3 for overwrite (repeat) + const Byte *src = in->ptr; + CBitCtr_signed bitOffset = (CBitCtr_signed)in->len - 1; + if (bitOffset <= 0) + return SZ_ERROR_DATA; + accuracy = *src & 0xf; + accuracy += 5; + if (accuracy > accuracyMax) + return SZ_ERROR_DATA; + *accuracyRes = (Byte)accuracy; + remain1 = (1u << accuracy) + 1; // (it's remain_freqs_sum + 1) + syms = 0; + src += bitOffset; // src points to last byte + bitOffset = 4 - (bitOffset << 3); + + for (;;) + { + // (2 <= remain1) + const unsigned bits = GetHighestSetBit_32_nonzero_small((unsigned)remain1); + // (1 <= bits <= accuracy) + unsigned val; // it must be unsigned or int + unsigned mask; + FORWARD_READ_BITS(val, bits, mask) + { + const unsigned val2 = remain1 + val - mask; + if (val2 > mask) + { + unsigned bit; + FORWARD_READ_1BIT(bit) + if (bit) + val = val2; + } + } + { + // (remain1 >= 2) + // (0 <= (int)val <= remain1) + val = (unsigned)((int)val - 1); + // val now is "probability" of symbol + // (probability == -1) means "less than 1" frequency. + // (-1 <= (int)val <= remain1 - 1) + freqs[syms++] = (Int16)(int)val; + if (val != 0) + { + remain1 -= (int)val < 0 ? 1u : (unsigned)val; + // remain1 -= val; + // val >>= (sizeof(val) * 8 - 2); + // remain1 -= val & 2; + // freqs[syms++] = (Int16)(int)val; + // syms++; + if (remain1 == 1) + break; + if (syms >= FSE_NUM_SYMBOLS_MAX) + return SZ_ERROR_DATA; + } + else // if (val == 0) + { + // freqs[syms++] = 0; + // syms++; + for (;;) + { + unsigned repeat; + FORWARD_READ_BITS(repeat, 2, mask) + freqs[syms ] = 0; + freqs[syms + 1] = 0; + freqs[syms + 2] = 0; + syms += repeat; + if (syms >= FSE_NUM_SYMBOLS_MAX) + return SZ_ERROR_DATA; + if (repeat != 3) + break; + } + } + } + } + + if (syms > numSymbolsMax) + return SZ_ERROR_DATA; + bitOffset += 7; + bitOffset >>= 3; + if (bitOffset > 0) + return SZ_ERROR_DATA; + in->ptr = src + bitOffset; + in->len = (size_t)(1 - bitOffset); + { + // unsigned uuu; for (uuu = 0; uuu < 50; uuu++) + FSE_Generate(table, freqs, syms, accuracy, + #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) + numSymbolsMax == NUM_ML_SYMBOLS ? MATCH_LEN_MIN : + #endif + 0 + ); + } + return SZ_OK; +} + + +// ---------- HUFFMAN ---------- + +#define HUF_MAX_BITS 12 +#define HUF_MAX_SYMBS 256 +#define HUF_DUMMY_SIZE (128 + 8 * 2) // it must multiple of 8 +// #define HUF_DUMMY_SIZE 0 +#define HUF_TABLE_SIZE ((2 << HUF_MAX_BITS) + HUF_DUMMY_SIZE) +#define HUF_GET_SYMBOLS(table) ((table) + (1 << HUF_MAX_BITS) + HUF_DUMMY_SIZE) +// #define HUF_GET_LENS(table) (table) + +typedef struct +{ + // Byte table[HUF_TABLE_SIZE]; + UInt64 table64[HUF_TABLE_SIZE / sizeof(UInt64)]; +} +CZstdDecHufTable; + +/* +Input: + numSyms != 0 + (bits) array size must be aligned for 2 + if (numSyms & 1), then bits[numSyms] == 0, + Huffman tree must be correct before Huf_Build() call: + (sum (1/2^bits[i]) == 1). + && (bits[i] <= HUF_MAX_BITS) +*/ +static +Z7_FORCE_INLINE +void Huf_Build(Byte * const table, + const Byte *bits, const unsigned numSyms) +{ + unsigned counts0[HUF_MAX_BITS + 1]; + unsigned counts1[HUF_MAX_BITS + 1]; + const Byte * const bitsEnd = bits + numSyms; + // /* + { + unsigned t; + for (t = 0; t < Z7_ARRAY_SIZE(counts0); t++) counts0[t] = 0; + for (t = 0; t < Z7_ARRAY_SIZE(counts1); t++) counts1[t] = 0; + } + // */ + // memset(counts0, 0, sizeof(counts0)); + // memset(counts1, 0, sizeof(counts1)); + { + const Byte *bits2 = bits; + // we access additional bits[symbol] if (numSyms & 1) + do + { + counts0[bits2[0]]++; + counts1[bits2[1]]++; + } + while ((bits2 += 2) < bitsEnd); + } + { + unsigned r = 0; + unsigned i = HUF_MAX_BITS; + // Byte *lens = HUF_GET_LENS(symbols); + do + { + const unsigned num = (counts0[i] + counts1[i]) << (HUF_MAX_BITS - i); + counts0[i] = r; + if (num) + { + Byte *lens = &table[r]; + r += num; + memset(lens, (int)i, num); + } + } + while (--i); + counts0[0] = 0; // for speculated loads + // no need for check: + // if (r != (UInt32)1 << HUF_MAX_BITS) exit(0); + } + { + #ifdef MY_CPU_64BIT + UInt64 + #else + UInt32 + #endif + v = 0; + Byte *symbols = HUF_GET_SYMBOLS(table); + do + { + const unsigned nb = *bits++; + if (nb) + { + const unsigned code = counts0[nb]; + const unsigned num = (1u << HUF_MAX_BITS) >> nb; + counts0[nb] = code + num; + // memset(&symbols[code], i, num); + // /* + { + Byte *s2 = &symbols[code]; + if (num <= 2) + { + s2[0] = (Byte)v; + s2[(size_t)num - 1] = (Byte)v; + } + else if (num <= 8) + { + *(UInt32 *)(void *)s2 = (UInt32)v; + *(UInt32 *)(void *)(s2 + (size_t)num - 4) = (UInt32)v; + } + else + { + #ifdef MY_CPU_64BIT + UInt64 *s = (UInt64 *)(void *)s2; + const UInt64 *lim = (UInt64 *)(void *)(s2 + num); + do + { + s[0] = v; s[1] = v; s += 2; + } + while (s != lim); + #else + UInt32 *s = (UInt32 *)(void *)s2; + const UInt32 *lim = (const UInt32 *)(const void *)(s2 + num); + do + { + s[0] = v; s[1] = v; s += 2; + s[0] = v; s[1] = v; s += 2; + } + while (s != lim); + #endif + } + } + // */ + } + v += + #ifdef MY_CPU_64BIT + 0x0101010101010101; + #else + 0x01010101; + #endif + } + while (bits != bitsEnd); + } +} + + + +// how many bytes (src) was moved back from original value. +// we need (HUF_SRC_OFFSET == 3) for optimized 32-bit memory access +#define HUF_SRC_OFFSET 3 + +// v <<= 8 - (bitOffset & 7) + numBits; +// v >>= 32 - HUF_MAX_BITS; +#define HUF_GET_STATE(v, bitOffset, numBits) \ + GET32(v, src + (HUF_SRC_OFFSET - 3) + ((CBitCtr_signed)bitOffset >> 3)) \ + v >>= 32 - HUF_MAX_BITS - 8 + ((unsigned)bitOffset & 7) - numBits; \ + v &= (1u << HUF_MAX_BITS) - 1; \ + + +#ifndef Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS +#if defined(MY_CPU_AMD64) && defined(_MSC_VER) && _MSC_VER == 1400 \ + || !defined(MY_CPU_X86_OR_AMD64) \ + // || 1 == 1 /* for debug : to force STREAM4_PRELOAD mode */ + // we need big number (>=16) of registers for PRELOAD4 + #define Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD4 + // #define Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD2 // for debug +#endif +#endif + +// for debug: simpler and smaller code but slow: +// #define Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE + +#if defined(Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE) || \ + !defined(Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS) + +#define HUF_DECODE(bitOffset, dest) \ +{ \ + UInt32 v; \ + HUF_GET_STATE(v, bitOffset, 0) \ + bitOffset -= table[v]; \ + *(dest) = symbols[v]; \ + if ((CBitCtr_signed)bitOffset < 0) return SZ_ERROR_DATA; \ +} + +#endif + +#if !defined(Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE) || \ + defined(Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD4) || \ + defined(Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD2) \ + +#define HUF_DECODE_2_INIT(v, bitOffset) \ + HUF_GET_STATE(v, bitOffset, 0) + +#define HUF_DECODE_2(v, bitOffset, dest) \ +{ \ + unsigned numBits; \ + numBits = table[v]; \ + *(dest) = symbols[v]; \ + HUF_GET_STATE(v, bitOffset, numBits) \ + bitOffset -= (CBitCtr)numBits; \ + if ((CBitCtr_signed)bitOffset < 0) return SZ_ERROR_DATA; \ +} + +#endif + + +// src == ptr - HUF_SRC_OFFSET +// we are allowed to access 3 bytes before start of input buffer +static +Z7_NO_INLINE +SRes Huf_Decompress_1stream(const Byte * const table, + const Byte *src, const size_t srcLen, + Byte *dest, const size_t destLen) +{ + CBitCtr bitOffset; + if (srcLen == 0) + return SZ_ERROR_DATA; + SET_bitOffset_TO_PAD (bitOffset, src + HUF_SRC_OFFSET, srcLen) + if (destLen) + { + const Byte *symbols = HUF_GET_SYMBOLS(table); + const Byte *destLim = dest + destLen; + #ifdef Z7_ZSTD_DEC_USE_HUF_STREAM1_SIMPLE + { + do + { + HUF_DECODE (bitOffset, dest) + } + while (++dest != destLim); + } + #else + { + UInt32 v; + HUF_DECODE_2_INIT (v, bitOffset) + do + { + HUF_DECODE_2 (v, bitOffset, dest) + } + while (++dest != destLim); + } + #endif + } + return bitOffset == 0 ? SZ_OK : SZ_ERROR_DATA; +} + + +// for debug : it reduces register pressure : by array copy can be slow : +// #define Z7_ZSTD_DEC_USE_HUF_LOCAL + +// src == ptr + (6 - HUF_SRC_OFFSET) +// srcLen >= 10 +// we are allowed to access 3 bytes before start of input buffer +static +Z7_NO_INLINE +SRes Huf_Decompress_4stream(const Byte * const + #ifdef Z7_ZSTD_DEC_USE_HUF_LOCAL + table2, + #else + table, + #endif + const Byte *src, size_t srcLen, + Byte *dest, size_t destLen) +{ + #ifdef Z7_ZSTD_DEC_USE_HUF_LOCAL + Byte table[HUF_TABLE_SIZE]; + #endif + UInt32 sizes[3]; + const size_t delta = (destLen + 3) / 4; + if ((sizes[0] = GetUi16(src + (0 + HUF_SRC_OFFSET - 6))) == 0) return SZ_ERROR_DATA; + if ((sizes[1] = GetUi16(src + (2 + HUF_SRC_OFFSET - 6))) == 0) return SZ_ERROR_DATA; + sizes[1] += sizes[0]; + if ((sizes[2] = GetUi16(src + (4 + HUF_SRC_OFFSET - 6))) == 0) return SZ_ERROR_DATA; + sizes[2] += sizes[1]; + srcLen -= 6; + if (srcLen <= sizes[2]) + return SZ_ERROR_DATA; + + #ifdef Z7_ZSTD_DEC_USE_HUF_LOCAL + { + // unsigned i = 0; for(; i < 1000; i++) + memcpy(table, table2, HUF_TABLE_SIZE); + } + #endif + + #ifndef Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS + { + CBitCtr bitOffset_0, + bitOffset_1, + bitOffset_2, + bitOffset_3; + { + SET_bitOffset_TO_PAD_and_SET_BIT_SIZE (bitOffset_0, src + HUF_SRC_OFFSET, sizes[0]) + SET_bitOffset_TO_PAD_and_SET_BIT_SIZE (bitOffset_1, src + HUF_SRC_OFFSET, sizes[1]) + SET_bitOffset_TO_PAD_and_SET_BIT_SIZE (bitOffset_2, src + HUF_SRC_OFFSET, sizes[2]) + SET_bitOffset_TO_PAD (bitOffset_3, src + HUF_SRC_OFFSET, srcLen) + } + { + const Byte * const symbols = HUF_GET_SYMBOLS(table); + Byte *destLim = dest + destLen - delta * 3; + + if (dest != destLim) + #ifdef Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD4 + { + UInt32 v_0, v_1, v_2, v_3; + HUF_DECODE_2_INIT (v_0, bitOffset_0) + HUF_DECODE_2_INIT (v_1, bitOffset_1) + HUF_DECODE_2_INIT (v_2, bitOffset_2) + HUF_DECODE_2_INIT (v_3, bitOffset_3) + // #define HUF_DELTA (1 << 17) / 4 + do + { + HUF_DECODE_2 (v_3, bitOffset_3, dest + delta * 3) + HUF_DECODE_2 (v_2, bitOffset_2, dest + delta * 2) + HUF_DECODE_2 (v_1, bitOffset_1, dest + delta) + HUF_DECODE_2 (v_0, bitOffset_0, dest) + } + while (++dest != destLim); + /* + {// unsigned y = 0; for (;y < 1; y++) + { + const size_t num = destLen - delta * 3; + Byte *orig = dest - num; + memmove (orig + delta , orig + HUF_DELTA, num); + memmove (orig + delta * 2, orig + HUF_DELTA * 2, num); + memmove (orig + delta * 3, orig + HUF_DELTA * 3, num); + }} + */ + } + #elif defined(Z7_ZSTD_DEC_USE_HUF_STREAM4_PRELOAD2) + { + UInt32 v_0, v_1, v_2, v_3; + HUF_DECODE_2_INIT (v_0, bitOffset_0) + HUF_DECODE_2_INIT (v_1, bitOffset_1) + do + { + HUF_DECODE_2 (v_0, bitOffset_0, dest) + HUF_DECODE_2 (v_1, bitOffset_1, dest + delta) + } + while (++dest != destLim); + dest = destLim - (destLen - delta * 3); + dest += delta * 2; + destLim += delta * 2; + HUF_DECODE_2_INIT (v_2, bitOffset_2) + HUF_DECODE_2_INIT (v_3, bitOffset_3) + do + { + HUF_DECODE_2 (v_2, bitOffset_2, dest) + HUF_DECODE_2 (v_3, bitOffset_3, dest + delta) + } + while (++dest != destLim); + dest -= delta * 2; + destLim -= delta * 2; + } + #else + { + do + { + HUF_DECODE (bitOffset_3, dest + delta * 3) + HUF_DECODE (bitOffset_2, dest + delta * 2) + HUF_DECODE (bitOffset_1, dest + delta) + HUF_DECODE (bitOffset_0, dest) + } + while (++dest != destLim); + } + #endif + + if (bitOffset_3 != (CBitCtr)sizes[2]) + return SZ_ERROR_DATA; + if (destLen &= 3) + { + destLim = dest + 4 - destLen; + do + { + HUF_DECODE (bitOffset_2, dest + delta * 2) + HUF_DECODE (bitOffset_1, dest + delta) + HUF_DECODE (bitOffset_0, dest) + } + while (++dest != destLim); + } + if ( bitOffset_0 != 0 + || bitOffset_1 != (CBitCtr)sizes[0] + || bitOffset_2 != (CBitCtr)sizes[1]) + return SZ_ERROR_DATA; + } + } + #else // Z7_ZSTD_DEC_USE_HUF_STREAM1_ALWAYS + { + unsigned i; + for (i = 0; i < 4; i++) + { + size_t d = destLen; + size_t size = srcLen; + if (i != 3) + { + d = delta; + size = sizes[i]; + } + if (i != 0) + size -= sizes[i - 1]; + destLen -= d; + RINOK(Huf_Decompress_1stream(table, src, size, dest, d)) + dest += d; + src += size; + } + } + #endif + + return SZ_OK; +} + + + +// (in->len != 0) +// we are allowed to access in->ptr[-3] +// at least 2 bytes in (in->ptr) will be processed +static SRes Huf_DecodeTable(CZstdDecHufTable *const p, CInBufPair *const in) +{ + Byte weights[HUF_MAX_SYMBS + 1]; // +1 for extra write for loop unroll + unsigned numSyms; + const unsigned header = *(in->ptr)++; + in->len--; + // memset(weights, 0, sizeof(weights)); + if (header >= 128) + { + // direct representation: 4 bits field (0-15) per weight + numSyms = header - 127; + // numSyms != 0 + { + const size_t numBytes = (numSyms + 1) / 2; + const Byte *const ws = in->ptr; + size_t i = 0; + if (in->len < numBytes) + return SZ_ERROR_DATA; + in->ptr += numBytes; + in->len -= numBytes; + do + { + const unsigned b = ws[i]; + weights[i * 2 ] = (Byte)(b >> 4); + weights[i * 2 + 1] = (Byte)(b & 0xf); + } + while (++i != numBytes); + /* 7ZIP: we can restore correct zero value for weights[numSyms], + if we want to use zero values starting from numSyms in code below. */ + // weights[numSyms] = 0; + } + } + else + { + #define MAX_ACCURACY_LOG_FOR_WEIGHTS 6 + CFseRecord table[1 << MAX_ACCURACY_LOG_FOR_WEIGHTS]; + + Byte accuracy; + const Byte *src; + size_t srcLen; + if (in->len < header) + return SZ_ERROR_DATA; + { + CInBufPair fse_stream; + fse_stream.len = header; + fse_stream.ptr = in->ptr; + in->ptr += header; + in->len -= header; + RINOK(FSE_DecodeHeader(table, &fse_stream, + MAX_ACCURACY_LOG_FOR_WEIGHTS, + &accuracy, + 16 // num weight symbols max (max-symbol is 15) + )) + // at least 2 bytes were processed in fse_stream. + // (srcLen > 0) after FSE_DecodeHeader() + // if (srcLen == 0) return SZ_ERROR_DATA; + src = fse_stream.ptr; + srcLen = fse_stream.len; + } + // we are allowed to access src[-5] + { + // unsigned yyy = 200; do { + CBitCtr bitOffset; + FastInt32 state1, state2; + SET_bitOffset_TO_PAD (bitOffset, src, srcLen) + state1 = accuracy; + src -= state1 >> 2; // src -= 1; // for GET16() optimization + state1 <<= FSE_REC_LEN_OFFSET; + state2 = state1; + numSyms = 0; + for (;;) + { + #define FSE_WEIGHT_DECODE(st) \ + { \ + const unsigned bits = GET_FSE_REC_LEN(st); \ + FastInt r; \ + GET16(r, src + (bitOffset >> 3)) \ + r >>= (unsigned)bitOffset & 7; \ + if ((CBitCtr_signed)(bitOffset -= (CBitCtr)bits) < 0) \ + { if (bitOffset + (CBitCtr)bits != 0) \ + return SZ_ERROR_DATA; \ + break; } \ + r &= 0xff; \ + r >>= 8 - bits; \ + st = table[GET_FSE_REC_STATE(st) + r]; \ + weights[numSyms++] = (Byte)GET_FSE_REC_SYM(st); \ + } + FSE_WEIGHT_DECODE (state1) + FSE_WEIGHT_DECODE (state2) + if (numSyms == HUF_MAX_SYMBS) + return SZ_ERROR_DATA; + } + // src += (unsigned)accuracy >> 2; } while (--yyy); + } + } + + // Build using weights: + { + UInt32 sum = 0; + { + // numSyms >= 1 + unsigned i = 0; + weights[numSyms] = 0; + do + { + sum += ((UInt32)1 << weights[i ]) & ~(UInt32)1; + sum += ((UInt32)1 << weights[i + 1]) & ~(UInt32)1; + i += 2; + } + while (i < numSyms); + if (sum == 0) + return SZ_ERROR_DATA; + } + { + const unsigned maxBits = GetHighestSetBit_32_nonzero_big(sum) + 1; + { + const UInt32 left = ((UInt32)1 << maxBits) - sum; + // (left != 0) + // (left) must be power of 2 in correct stream + if (left & (left - 1)) + return SZ_ERROR_DATA; + weights[numSyms++] = (Byte)GetHighestSetBit_32_nonzero_big(left); + } + // if (numSyms & 1) + weights[numSyms] = 0; // for loop unroll + // numSyms >= 2 + { + unsigned i = 0; + do + { + /* + #define WEIGHT_ITER(a) \ + { unsigned w = weights[i + (a)]; \ + const unsigned t = maxBits - w; \ + w = w ? t: w; \ + if (w > HUF_MAX_BITS) return SZ_ERROR_DATA; \ + weights[i + (a)] = (Byte)w; } + */ + // /* + #define WEIGHT_ITER(a) \ + { unsigned w = weights[i + (a)]; \ + if (w) { \ + w = maxBits - w; \ + if (w > HUF_MAX_BITS) return SZ_ERROR_DATA; \ + weights[i + (a)] = (Byte)w; }} + // */ + WEIGHT_ITER(0) + // WEIGHT_ITER(1) + // i += 2; + } + while (++i != numSyms); + } + } + } + { + // unsigned yyy; for (yyy = 0; yyy < 100; yyy++) + Huf_Build((Byte *)(void *)p->table64, weights, numSyms); + } + return SZ_OK; +} + + +typedef enum +{ + k_SeqMode_Predef = 0, + k_SeqMode_RLE = 1, + k_SeqMode_FSE = 2, + k_SeqMode_Repeat = 3 +} +z7_zstd_enum_SeqMode; + +// predefAccuracy == 5 for OFFSET symbols +// predefAccuracy == 6 for MATCH/LIT LEN symbols +static +SRes +Z7_NO_INLINE +// Z7_FORCE_INLINE +FSE_Decode_SeqTable(CFseRecord * const table, + CInBufPair * const in, + unsigned predefAccuracy, + Byte * const accuracyRes, + unsigned numSymbolsMax, + const CFseRecord * const predefs, + const unsigned seqMode) +{ + // UNUSED_VAR(numSymsPredef) + // UNUSED_VAR(predefFreqs) + if (seqMode == k_SeqMode_FSE) + { + // unsigned y = 50; CInBufPair in2 = *in; do { *in = in2; RINOK( + return + FSE_DecodeHeader(table, in, + predefAccuracy + 3, // accuracyMax + accuracyRes, + numSymbolsMax) + ; + // )} while (--y); return SZ_OK; + } + // numSymsMax = numSymsPredef + ((predefAccuracy & 1) * (32 - 29))); // numSymsMax + // numSymsMax == 32 for offsets + + if (seqMode == k_SeqMode_Predef) + { + *accuracyRes = (Byte)predefAccuracy; + memcpy(table, predefs, sizeof(UInt32) << predefAccuracy); + return SZ_OK; + } + + // (seqMode == k_SeqMode_RLE) + if (in->len == 0) + return SZ_ERROR_DATA; + in->len--; + { + const Byte *ptr = in->ptr; + const unsigned sym = ptr[0]; + in->ptr = ptr + 1; + if (sym >= numSymbolsMax) + return SZ_ERROR_DATA; + table[0] = (FastInt32)sym + #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) + + (numSymbolsMax == NUM_ML_SYMBOLS ? MATCH_LEN_MIN : 0) + #endif + ; + *accuracyRes = 0; + } + return SZ_OK; +} + + +typedef struct +{ + CFseRecord of[1 << 8]; + CFseRecord ll[1 << 9]; + CFseRecord ml[1 << 9]; +} +CZstdDecFseTables; + + +typedef struct +{ + Byte *win; + SizeT cycSize; + /* + if (outBuf_fromCaller) : cycSize = outBufSize_fromCaller + else { + if ( isCyclicMode) : cycSize = cyclic_buffer_size = (winSize + extra_space) + if (!isCyclicMode) : cycSize = ContentSize, + (isCyclicMode == true) if (ContetSize >= winSize) or ContetSize is unknown + } + */ + SizeT winPos; + + CZstdDecOffset reps[3]; + + Byte ll_accuracy; + Byte of_accuracy; + Byte ml_accuracy; + // Byte seqTables_wereSet; + Byte litHuf_wasSet; + + Byte *literalsBase; + + size_t winSize; // from header + size_t totalOutCheck; // totalOutCheck <= winSize + + #ifdef Z7_ZSTD_DEC_USE_BASES_IN_OBJECT + SEQ_EXTRA_TABLES(m_) + #endif + // UInt64 _pad_Alignment; // is not required now + CZstdDecFseTables fse; + CZstdDecHufTable huf; +} +CZstdDec1; + +#define ZstdDec1_GET_BLOCK_SIZE_LIMIT(p) \ + ((p)->winSize < kBlockSizeMax ? (UInt32)(p)->winSize : kBlockSizeMax) + +#define SEQ_TABLES_WERE_NOT_SET_ml_accuracy 1 // accuracy=1 is not used by zstd +#define IS_SEQ_TABLES_WERE_SET(p) (((p)->ml_accuracy != SEQ_TABLES_WERE_NOT_SET_ml_accuracy)) +// #define IS_SEQ_TABLES_WERE_SET(p) ((p)->seqTables_wereSet) + + +static void ZstdDec1_Construct(CZstdDec1 *p) +{ + #ifdef Z7_ZSTD_DEC_PRINT_TABLE + Print_Predef(6, NUM_LL_SYMBOLS, SEQ_LL_PREDEF_DIST, k_PredefRecords_LL); + Print_Predef(5, NUM_OFFSET_SYMBOLS_PREDEF, SEQ_OFFSET_PREDEF_DIST, k_PredefRecords_OF); + Print_Predef(6, NUM_ML_SYMBOLS, SEQ_ML_PREDEF_DIST, k_PredefRecords_ML); + #endif + + p->win = NULL; + p->cycSize = 0; + p->literalsBase = NULL; + #ifdef Z7_ZSTD_DEC_USE_BASES_IN_OBJECT + FILL_LOC_BASES_ALL + #endif +} + + +static void ZstdDec1_Init(CZstdDec1 *p) +{ + p->reps[0] = 1; + p->reps[1] = 4; + p->reps[2] = 8; + // p->seqTables_wereSet = False; + p->ml_accuracy = SEQ_TABLES_WERE_NOT_SET_ml_accuracy; + p->litHuf_wasSet = False; + p->totalOutCheck = 0; +} + + + +#ifdef MY_CPU_LE_UNALIGN + #define Z7_ZSTD_DEC_USE_UNALIGNED_COPY +#endif + +#ifdef Z7_ZSTD_DEC_USE_UNALIGNED_COPY + + #define COPY_CHUNK_SIZE 16 + + #define COPY_CHUNK_4_2(dest, src) \ + { \ + ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \ + ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \ + src += 4 * 2; \ + dest += 4 * 2; \ + } + + /* sse2 doesn't help here in GCC and CLANG. + so we disabled sse2 here */ + /* + #if defined(MY_CPU_AMD64) + #define Z7_ZSTD_DEC_USE_SSE2 + #elif defined(MY_CPU_X86) + #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ + || defined(__SSE2__) \ + // || 1 == 1 // for debug only + #define Z7_ZSTD_DEC_USE_SSE2 + #endif + #endif + */ + + #if defined(MY_CPU_ARM64) + #define COPY_OFFSET_MIN 16 + #define COPY_CHUNK1(dest, src) \ + { \ + vst1q_u8((uint8_t *)(void *)dest, \ + vld1q_u8((const uint8_t *)(const void *)src)); \ + src += 16; \ + dest += 16; \ + } + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK1(dest, src) \ + if ((len -= COPY_CHUNK_SIZE) == 0) break; \ + COPY_CHUNK1(dest, src) \ + } + + #elif defined(Z7_ZSTD_DEC_USE_SSE2) + #include // sse2 + #define COPY_OFFSET_MIN 16 + + #define COPY_CHUNK1(dest, src) \ + { \ + _mm_storeu_si128((__m128i *)(void *)dest, \ + _mm_loadu_si128((const __m128i *)(const void *)src)); \ + src += 16; \ + dest += 16; \ + } + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK1(dest, src) \ + if ((len -= COPY_CHUNK_SIZE) == 0) break; \ + COPY_CHUNK1(dest, src) \ + } + + #elif defined(MY_CPU_64BIT) + #define COPY_OFFSET_MIN 8 + + #define COPY_CHUNK(dest, src) \ + { \ + ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ + ((UInt64 *)(void *)dest)[1] = ((const UInt64 *)(const void *)src)[1]; \ + src += 8 * 2; \ + dest += 8 * 2; \ + } + + #else + #define COPY_OFFSET_MIN 4 + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK_4_2(dest, src); \ + COPY_CHUNK_4_2(dest, src); \ + } + + #endif +#endif + + +#ifndef COPY_CHUNK_SIZE + #define COPY_OFFSET_MIN 4 + #define COPY_CHUNK_SIZE 8 + #define COPY_CHUNK_2(dest, src) \ + { \ + const Byte a0 = src[0]; \ + const Byte a1 = src[1]; \ + dest[0] = a0; \ + dest[1] = a1; \ + src += 2; \ + dest += 2; \ + } + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + } +#endif + + +#define COPY_PREPARE \ + len += (COPY_CHUNK_SIZE - 1); \ + len &= ~(size_t)(COPY_CHUNK_SIZE - 1); \ + { if (len > rem) \ + { len = rem; \ + rem &= (COPY_CHUNK_SIZE - 1); \ + if (rem) { \ + len -= rem; \ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + do *dest++ = *src++; while (--rem); \ + if (len == 0) return; }}} + +#define COPY_CHUNKS \ +{ \ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + do { COPY_CHUNK(dest, src) } \ + while (len -= COPY_CHUNK_SIZE); \ +} + +// (len != 0) +// (len <= rem) +static +Z7_FORCE_INLINE +// Z7_ATTRIB_NO_VECTOR +void CopyLiterals(Byte *dest, Byte const *src, size_t len, size_t rem) +{ + COPY_PREPARE + COPY_CHUNKS +} + + +/* we can define Z7_STD_DEC_USE_AFTER_CYC_BUF, if we want to use additional + space after cycSize that can be used to reduce the code in CopyMatch(): */ +// for debug: +// #define Z7_STD_DEC_USE_AFTER_CYC_BUF + +/* +CopyMatch() +if wrap (offset > winPos) +{ + then we have at least (COPY_CHUNK_SIZE) avail in (dest) before we will overwrite (src): + (cycSize >= offset + COPY_CHUNK_SIZE) + if defined(Z7_STD_DEC_USE_AFTER_CYC_BUF) + we are allowed to read win[cycSize + COPY_CHUNK_SIZE - 1], +} +(len != 0) +*/ +static +Z7_FORCE_INLINE +// Z7_ATTRIB_NO_VECTOR +void CopyMatch(size_t offset, size_t len, + Byte *win, size_t winPos, size_t rem, const size_t cycSize) +{ + Byte *dest = win + winPos; + const Byte *src; + // STAT_INC(g_NumCopy) + + if (offset > winPos) + { + size_t back = offset - winPos; + // src = win + cycSize - back; + // cycSize -= offset; + STAT_INC(g_NumOver) + src = dest + (cycSize - offset); + // (src >= dest) here + #ifdef Z7_STD_DEC_USE_AFTER_CYC_BUF + if (back < len) + { + #else + if (back < len + (COPY_CHUNK_SIZE - 1)) + { + if (back >= len) + { + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + *dest++ = *src++; + while (--len); + return; + } + #endif + // back < len + STAT_INC(g_NumOver2) + len -= back; + rem -= back; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + *dest++ = *src++; + while (--back); + src = dest - offset; + // src = win; + // we go to MAIN-COPY + } + } + else + src = dest - offset; + + // len != 0 + // do *dest++ = *src++; while (--len); return; + + // --- MAIN COPY --- + // if (src >= dest), then ((size_t)(src - dest) >= COPY_CHUNK_SIZE) + // so we have at least COPY_CHUNK_SIZE space before overlap for writing. + COPY_PREPARE + + /* now (len == COPY_CHUNK_SIZE * x) + so we can unroll for aligned copy */ + { + // const unsigned b0 = src[0]; + // (COPY_OFFSET_MIN >= 4) + + if (offset >= COPY_OFFSET_MIN) + { + COPY_CHUNKS + // return; + } + else + #if (COPY_OFFSET_MIN > 4) + #if COPY_CHUNK_SIZE < 8 + #error Stop_Compiling_Bad_COPY_CHUNK_SIZE + #endif + if (offset >= 4) + { + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + COPY_CHUNK_4_2(dest, src) + #if COPY_CHUNK_SIZE != 16 + if (len == 8) break; + #endif + COPY_CHUNK_4_2(dest, src) + } + while (len -= 16); + // return; + } + else + #endif + { + // (offset < 4) + const unsigned b0 = src[0]; + if (offset < 2) + { + #if defined(Z7_ZSTD_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16) + #if defined(MY_CPU_64BIT) + { + const UInt64 v64 = (UInt64)b0 * 0x0101010101010101; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + ((UInt64 *)(void *)dest)[0] = v64; + ((UInt64 *)(void *)dest)[1] = v64; + dest += 16; + } + while (len -= 16); + } + #else + { + UInt32 v = b0; + v |= v << 8; + v |= v << 16; + do + { + ((UInt32 *)(void *)dest)[0] = v; + ((UInt32 *)(void *)dest)[1] = v; + dest += 8; + ((UInt32 *)(void *)dest)[0] = v; + ((UInt32 *)(void *)dest)[1] = v; + dest += 8; + } + while (len -= 16); + } + #endif + #else + do + { + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += 2; + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += 2; + } + while (len -= 4); + #endif + } + else if (offset == 2) + { + const Byte b1 = src[1]; + { + do + { + dest[0] = (Byte)b0; + dest[1] = b1; + dest += 2; + } + while (len -= 2); + } + } + else // (offset == 3) + { + const Byte *lim = dest + len - 2; + const Byte b1 = src[1]; + const Byte b2 = src[2]; + do + { + dest[0] = (Byte)b0; + dest[1] = b1; + dest[2] = b2; + dest += 3; + } + while (dest < lim); + lim++; // points to last byte that must be written + if (dest <= lim) + { + *dest = (Byte)b0; + if (dest != lim) + dest[1] = b1; + } + } + } + } +} + + + +#define UPDATE_TOTAL_OUT(p, size) \ +{ \ + size_t _toc = (p)->totalOutCheck + (size); \ + const size_t _ws = (p)->winSize; \ + if (_toc >= _ws) _toc = _ws; \ + (p)->totalOutCheck = _toc; \ +} + + +#if defined(MY_CPU_64BIT) && defined(MY_CPU_LE_UNALIGN) +// we can disable it for debug: +#define Z7_ZSTD_DEC_USE_64BIT_LOADS +#endif +// #define Z7_ZSTD_DEC_USE_64BIT_LOADS // for debug : slow in 32-bit + +// SEQ_SRC_OFFSET: how many bytes (src) (seqSrc) was moved back from original value. +// we need (SEQ_SRC_OFFSET != 0) for optimized memory access +#ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + #define SEQ_SRC_OFFSET 7 +#else + #define SEQ_SRC_OFFSET 3 +#endif +#define SRC_PLUS_FOR_4BYTES(bitOffset) (SEQ_SRC_OFFSET - 3) + ((CBitCtr_signed)(bitOffset) >> 3) +#define BIT_OFFSET_7BITS(bitOffset) ((unsigned)(bitOffset) & 7) +/* + if (BIT_OFFSET_DELTA_BITS == 0) : bitOffset == number_of_unprocessed_bits + if (BIT_OFFSET_DELTA_BITS == 1) : bitOffset == number_of_unprocessed_bits - 1 + and we can read 1 bit more in that mode : (8 * n + 1). +*/ +// #define BIT_OFFSET_DELTA_BITS 0 +#define BIT_OFFSET_DELTA_BITS 1 +#if BIT_OFFSET_DELTA_BITS == 1 + #define GET_SHIFT_FROM_BOFFS7(boff7) (7 ^ (boff7)) +#else + #define GET_SHIFT_FROM_BOFFS7(boff7) (8 - BIT_OFFSET_DELTA_BITS - (boff7)) +#endif + +#define UPDATE_BIT_OFFSET(bitOffset, numBits) \ + (bitOffset) -= (CBitCtr)(numBits); + +#define GET_SHIFT(bitOffset) GET_SHIFT_FROM_BOFFS7(BIT_OFFSET_7BITS(bitOffset)) + + +#if defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) + #if (NUM_OFFSET_SYMBOLS_MAX - BIT_OFFSET_DELTA_BITS < 32) + /* if (NUM_OFFSET_SYMBOLS_MAX == 32 && BIT_OFFSET_DELTA_BITS == 1), + we have depth 31 + 9 + 9 + 8 = 57 bits that can b read with single read. */ + #define Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF + #endif + #ifndef Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF + #if (BIT_OFFSET_DELTA_BITS == 1) + /* if (winLimit - winPos <= (kBlockSizeMax = (1 << 17))) + { + the case (16 bits literal extra + 16 match extra) is not possible + in correct stream. So error will be detected for (16 + 16) case. + And longest correct sequence after offset reading is (31 + 9 + 9 + 8 = 57 bits). + So we can use just one 64-bit load here in that case. + } + */ + #define Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML + #endif + #endif +#endif + + +#if !defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) || \ + (!defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) && \ + !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML)) +// in : (0 < bits <= (24 or 25)): +#define STREAM_READ_BITS(dest, bits) \ +{ \ + GET32(dest, src + SRC_PLUS_FOR_4BYTES(bitOffset)) \ + dest <<= GET_SHIFT(bitOffset); \ + UPDATE_BIT_OFFSET(bitOffset, bits) \ + dest >>= 32 - bits; \ +} +#endif + + +#define FSE_Peek_1(table, state) table[state] + +#define STATE_VAR(name) state_ ## name + +// in : (0 <= accuracy <= (24 or 25)) +#define FSE_INIT_STATE(name, cond) \ +{ \ + UInt32 r; \ + const unsigned bits = p->name ## _accuracy; \ + GET32(r, src + SRC_PLUS_FOR_4BYTES(bitOffset)) \ + r <<= GET_SHIFT(bitOffset); \ + r >>= 1; \ + r >>= 31 ^ bits; \ + UPDATE_BIT_OFFSET(bitOffset, bits) \ + cond \ + STATE_VAR(name) = FSE_Peek_1(FSE_TABLE(name), r); \ + /* STATE_VAR(name) = dest << 16; */ \ +} + + +#define FSE_Peek_Plus(name, r) \ + STATE_VAR(name) = FSE_Peek_1(FSE_TABLE(name), \ + GET_FSE_REC_STATE(STATE_VAR(name)) + r); + +#define LZ_LOOP_ERROR_EXIT { return SZ_ERROR_DATA; } + +#define BO_OVERFLOW_CHECK \ + { if ((CBitCtr_signed)bitOffset < 0) LZ_LOOP_ERROR_EXIT } + + +#ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + +#define GET64(dest, p) { const Byte *ptr = p; dest = GetUi64(ptr); } + +#define FSE_PRELOAD \ +{ \ + GET64(v, src - 4 + SRC_PLUS_FOR_4BYTES(bitOffset)) \ + v <<= GET_SHIFT(bitOffset); \ +} + +#define FSE_UPDATE_STATE_2(name, cond) \ +{ \ + const unsigned bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ + UInt64 r = v; \ + v <<= bits; \ + r >>= 1; \ + UPDATE_BIT_OFFSET(bitOffset, bits) \ + cond \ + r >>= 63 ^ bits; \ + FSE_Peek_Plus(name, r); \ +} + +#define FSE_UPDATE_STATES \ + FSE_UPDATE_STATE_2 (ll, {} ) \ + FSE_UPDATE_STATE_2 (ml, {} ) \ + FSE_UPDATE_STATE_2 (of, BO_OVERFLOW_CHECK) \ + +#else // Z7_ZSTD_DEC_USE_64BIT_LOADS + +// it supports 8 bits accuracy for any code +// it supports 9 bits accuracy, if (BIT_OFFSET_DELTA_BITS == 1) +#define FSE_UPDATE_STATE_0(name, cond) \ +{ \ + UInt32 r; \ + const unsigned bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ + GET16(r, src + 2 + SRC_PLUS_FOR_4BYTES(bitOffset)) \ + r >>= (bitOffset & 7); \ + r &= (1 << (8 + BIT_OFFSET_DELTA_BITS)) - 1; \ + UPDATE_BIT_OFFSET(bitOffset, bits) \ + cond \ + r >>= (8 + BIT_OFFSET_DELTA_BITS) - bits; \ + FSE_Peek_Plus(name, r); \ +} + +// for debug (slow): +// #define Z7_ZSTD_DEC_USE_FSE_FUSION_FORCE +#if BIT_OFFSET_DELTA_BITS == 0 || defined(Z7_ZSTD_DEC_USE_FSE_FUSION_FORCE) + #define Z7_ZSTD_DEC_USE_FSE_FUSION +#endif + +#ifdef Z7_ZSTD_DEC_USE_FSE_FUSION +#define FSE_UPDATE_STATE_1(name) \ +{ UInt32 rest2; \ +{ \ + UInt32 r; \ + unsigned bits; \ + GET32(r, src + SRC_PLUS_FOR_4BYTES(bitOffset)) \ + bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ + r <<= GET_SHIFT(bitOffset); \ + rest2 = r << bits; \ + r >>= 1; \ + UPDATE_BIT_OFFSET(bitOffset, bits) \ + r >>= 31 ^ bits; \ + FSE_Peek_Plus(name, r); \ +} + +#define FSE_UPDATE_STATE_3(name) \ +{ \ + const unsigned bits = GET_FSE_REC_LEN(STATE_VAR(name)); \ + rest2 >>= 1; \ + UPDATE_BIT_OFFSET(bitOffset, bits) \ + rest2 >>= 31 ^ bits; \ + FSE_Peek_Plus(name, rest2); \ +}} + +#define FSE_UPDATE_STATES \ + FSE_UPDATE_STATE_1 (ll) \ + FSE_UPDATE_STATE_3 (ml) \ + FSE_UPDATE_STATE_0 (of, BO_OVERFLOW_CHECK) \ + +#else // Z7_ZSTD_DEC_USE_64BIT_LOADS + +#define FSE_UPDATE_STATES \ + FSE_UPDATE_STATE_0 (ll, {} ) \ + FSE_UPDATE_STATE_0 (ml, {} ) \ + FSE_UPDATE_STATE_0 (of, BO_OVERFLOW_CHECK) \ + +#endif // Z7_ZSTD_DEC_USE_FSE_FUSION +#endif // Z7_ZSTD_DEC_USE_64BIT_LOADS + + + +typedef struct +{ + UInt32 numSeqs; + UInt32 literalsLen; + const Byte *literals; +} +CZstdDec1_Vars; + + +// if (BIT_OFFSET_DELTA_BITS != 0), we need (BIT_OFFSET_DELTA_BYTES > 0) +#define BIT_OFFSET_DELTA_BYTES BIT_OFFSET_DELTA_BITS + +/* if (NUM_OFFSET_SYMBOLS_MAX == 32) + max_seq_bit_length = (31) + 16 + 16 + 9 + 8 + 9 = 89 bits + if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) we have longest backward + lookahead offset, and we read UInt64 after literal_len reading. + if (BIT_OFFSET_DELTA_BITS == 1 && NUM_OFFSET_SYMBOLS_MAX == 32) + MAX_BACKWARD_DEPTH = 16 bytes +*/ +#define MAX_BACKWARD_DEPTH \ + ((NUM_OFFSET_SYMBOLS_MAX - 1 + 16 + 16 + 7) / 8 + 7 + BIT_OFFSET_DELTA_BYTES) + +/* srcLen != 0 + src == real_data_ptr - SEQ_SRC_OFFSET - BIT_OFFSET_DELTA_BYTES + if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML) then + (winLimit - p->winPos <= (1 << 17)) is required +*/ +static +Z7_NO_INLINE +// Z7_ATTRIB_NO_VECTOR +SRes Decompress_Sequences(CZstdDec1 * const p, + const Byte *src, const size_t srcLen, + const size_t winLimit, + const CZstdDec1_Vars * const vars) +{ +#ifdef Z7_ZSTD_DEC_USE_BASES_LOCAL + SEQ_EXTRA_TABLES(a_) +#endif + + // for debug: + // #define Z7_ZSTD_DEC_USE_LOCAL_FSE_TABLES +#ifdef Z7_ZSTD_DEC_USE_LOCAL_FSE_TABLES + #define FSE_TABLE(n) fse. n + const CZstdDecFseTables fse = p->fse; + /* + CZstdDecFseTables fse; + #define COPY_FSE_TABLE(n) \ + memcpy(fse. n, p->fse. n, (size_t)4 << p-> n ## _accuracy); + COPY_FSE_TABLE(of) + COPY_FSE_TABLE(ll) + COPY_FSE_TABLE(ml) + */ +#else + #define FSE_TABLE(n) (p->fse. n) +#endif + +#ifdef Z7_ZSTD_DEC_USE_BASES_LOCAL + FILL_LOC_BASES_ALL +#endif + + { + unsigned numSeqs = vars->numSeqs; + const Byte *literals = vars->literals; + ptrdiff_t literalsLen = (ptrdiff_t)vars->literalsLen; + Byte * const win = p->win; + size_t winPos = p->winPos; + const size_t cycSize = p->cycSize; + size_t totalOutCheck = p->totalOutCheck; + const size_t winSize = p->winSize; + size_t reps_0 = p->reps[0]; + size_t reps_1 = p->reps[1]; + size_t reps_2 = p->reps[2]; + UInt32 STATE_VAR(ll), STATE_VAR(of), STATE_VAR(ml); + CBitCtr bitOffset; + + SET_bitOffset_TO_PAD (bitOffset, src + SEQ_SRC_OFFSET, srcLen + BIT_OFFSET_DELTA_BYTES) + + bitOffset -= BIT_OFFSET_DELTA_BITS; + + FSE_INIT_STATE(ll, {} ) + FSE_INIT_STATE(of, {} ) + FSE_INIT_STATE(ml, BO_OVERFLOW_CHECK) + + for (;;) + { + size_t matchLen; + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + UInt64 v; + #endif + + #ifdef Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF + FSE_PRELOAD + #endif + + // if (of_code == 0) + if ((Byte)STATE_VAR(of) == 0) + { + if (GET_FSE_REC_SYM(STATE_VAR(ll)) == 0) + { + const size_t offset = reps_1; + reps_1 = reps_0; + reps_0 = offset; + STAT_INC(g_Num_Rep1) + } + STAT_UPDATE(else g_Num_Rep0++;) + } + else + { + const unsigned of_code = (Byte)STATE_VAR(of); + + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + #if !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) + FSE_PRELOAD + #endif + #else + UInt32 v; + { + const Byte *src4 = src + SRC_PLUS_FOR_4BYTES(bitOffset); + const unsigned skip = GET_SHIFT(bitOffset); + GET32(v, src4) + v <<= skip; + v |= (UInt32)src4[-1] >> (8 - skip); + } + #endif + + UPDATE_BIT_OFFSET(bitOffset, of_code) + + if (of_code == 1) + { + // read 1 bit + #if defined(Z7_MSC_VER_ORIGINAL) || defined(MY_CPU_X86_OR_AMD64) + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + #define CHECK_HIGH_BIT_64(a) ((Int64)(UInt64)(a) < 0) + #else + #define CHECK_HIGH_BIT_32(a) ((Int32)(UInt32)(a) < 0) + #endif + #else + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + #define CHECK_HIGH_BIT_64(a) ((UInt64)(a) & ((UInt64)1 << 63)) + #else + #define CHECK_HIGH_BIT_32(a) ((UInt32)(a) & ((UInt32)1 << 31)) + #endif + #endif + + if + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + CHECK_HIGH_BIT_64 (((UInt64)GET_FSE_REC_SYM(STATE_VAR(ll)) - 1) ^ v) + #else + CHECK_HIGH_BIT_32 (((UInt32)GET_FSE_REC_SYM(STATE_VAR(ll)) - 1) ^ v) + #endif + { + v <<= 1; + { + const size_t offset = reps_2; + reps_2 = reps_1; + reps_1 = reps_0; + reps_0 = offset; + STAT_INC(g_Num_Rep2) + } + } + else + { + if (GET_FSE_REC_SYM(STATE_VAR(ll)) == 0) + { + // litLen == 0 && bit == 1 + STAT_INC(g_Num_Rep3) + v <<= 1; + reps_2 = reps_1; + reps_1 = reps_0; + if (--reps_0 == 0) + { + // LZ_LOOP_ERROR_EXIT + // original-zstd decoder : input is corrupted; force offset to 1 + // reps_0 = 1; + reps_0++; + } + } + else + { + // litLen != 0 && bit == 0 + v <<= 1; + { + const size_t offset = reps_1; + reps_1 = reps_0; + reps_0 = offset; + STAT_INC(g_Num_Rep1) + } + } + } + } + else + { + // (2 <= of_code) + // if (of_code >= 32) LZ_LOOP_ERROR_EXIT // optional check + // we don't allow (of_code >= 32) cases in another code + reps_2 = reps_1; + reps_1 = reps_0; + reps_0 = ((size_t)1 << of_code) - 3 + (size_t) + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + (v >> (64 - of_code)); + v <<= of_code; + #else + (v >> (32 - of_code)); + #endif + } + } + + #ifdef Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML + FSE_PRELOAD + #endif + + matchLen = (size_t)GET_FSE_REC_SYM(STATE_VAR(ml)) + #ifndef Z7_ZSTD_DEC_USE_ML_PLUS3 + + MATCH_LEN_MIN + #endif + ; + { + { + if (matchLen >= 32 + MATCH_LEN_MIN) // if (state_ml & 0x20) + { + const unsigned extra = BASES_TABLE(SEQ_ML_EXTRA) [(size_t)matchLen - MATCH_LEN_MIN]; + matchLen = BASES_TABLE(SEQ_ML_BASES) [(size_t)matchLen - MATCH_LEN_MIN]; + #if defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) && \ + (defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML) || \ + defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF)) + { + UPDATE_BIT_OFFSET(bitOffset, extra) + matchLen += (size_t)(v >> (64 - extra)); + #if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) + FSE_PRELOAD + #else + v <<= extra; + #endif + } + #else + { + UInt32 v32; + STREAM_READ_BITS(v32, extra) + matchLen += v32; + } + #endif + STAT_INC(g_Num_Match) + } + } + } + + #if defined(Z7_ZSTD_DEC_USE_64BIT_LOADS) && \ + !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) && \ + !defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_ML) + FSE_PRELOAD + #endif + + { + size_t litLen = GET_FSE_REC_SYM(STATE_VAR(ll)); + if (litLen) + { + // if (STATE_VAR(ll) & 0x70) + if (litLen >= 16) + { + const unsigned extra = BASES_TABLE(SEQ_LL_EXTRA) [litLen]; + litLen = BASES_TABLE(SEQ_LL_BASES) [litLen]; + #ifdef Z7_ZSTD_DEC_USE_64BIT_LOADS + { + UPDATE_BIT_OFFSET(bitOffset, extra) + litLen += (size_t)(v >> (64 - extra)); + #if defined(Z7_ZSTD_DEC_USE_64BIT_PRELOAD_OF) + FSE_PRELOAD + #else + v <<= extra; + #endif + } + #else + { + UInt32 v32; + STREAM_READ_BITS(v32, extra) + litLen += v32; + } + #endif + STAT_INC(g_Num_LitsBig) + } + + if ((literalsLen -= (ptrdiff_t)litLen) < 0) + LZ_LOOP_ERROR_EXIT + totalOutCheck += litLen; + { + const size_t rem = winLimit - winPos; + if (litLen > rem) + LZ_LOOP_ERROR_EXIT + { + const Byte *literals_temp = literals; + Byte *d = win + winPos; + literals += litLen; + winPos += litLen; + CopyLiterals(d, literals_temp, litLen, rem); + } + } + } + STAT_UPDATE(else g_Num_Lit0++;) + } + + #define COPY_MATCH \ + { if (reps_0 > winSize || reps_0 > totalOutCheck) LZ_LOOP_ERROR_EXIT \ + totalOutCheck += matchLen; \ + { const size_t rem = winLimit - winPos; \ + if (matchLen > rem) LZ_LOOP_ERROR_EXIT \ + { const size_t winPos_temp = winPos; \ + winPos += matchLen; \ + CopyMatch(reps_0, matchLen, win, winPos_temp, rem, cycSize); }}} + + if (--numSeqs == 0) + { + COPY_MATCH + break; + } + FSE_UPDATE_STATES + COPY_MATCH + } // for + + if ((CBitCtr_signed)bitOffset != BIT_OFFSET_DELTA_BYTES * 8 - BIT_OFFSET_DELTA_BITS) + return SZ_ERROR_DATA; + + if (literalsLen) + { + const size_t rem = winLimit - winPos; + if ((size_t)literalsLen > rem) + return SZ_ERROR_DATA; + { + Byte *d = win + winPos; + winPos += (size_t)literalsLen; + totalOutCheck += (size_t)literalsLen; + CopyLiterals + // memcpy + (d, literals, (size_t)literalsLen, rem); + } + } + if (totalOutCheck >= winSize) + totalOutCheck = winSize; + p->totalOutCheck = totalOutCheck; + p->winPos = winPos; + p->reps[0] = (CZstdDecOffset)reps_0; + p->reps[1] = (CZstdDecOffset)reps_1; + p->reps[2] = (CZstdDecOffset)reps_2; + } + return SZ_OK; +} + + +// for debug: define to check that ZstdDec1_NeedTempBufferForInput() works correctly: +// #define Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP // define it for debug only +#ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP +static unsigned g_numSeqs; +#endif + + +#define k_LitBlockType_Flag_RLE_or_Treeless 1 +#define k_LitBlockType_Flag_Compressed 2 + +// outLimit : is strong limit +// outLimit <= ZstdDec1_GET_BLOCK_SIZE_LIMIT(p) +// inSize != 0 +static +Z7_NO_INLINE +SRes ZstdDec1_DecodeBlock(CZstdDec1 *p, + const Byte *src, SizeT inSize, SizeT afterAvail, + const size_t outLimit) +{ + CZstdDec1_Vars vars; + vars.literals = p->literalsBase; + { + const unsigned b0 = *src++; + UInt32 numLits, compressedSize; + const Byte *litStream; + Byte *literalsDest; + inSize--; + + if ((b0 & k_LitBlockType_Flag_Compressed) == 0) + { + // we need at least one additional byte for (numSeqs). + // so we check for that additional byte in conditions. + numLits = b0 >> 3; + if (b0 & 4) + { + UInt32 v; + if (inSize < 1 + 1) // we need at least 1 byte here and 1 byte for (numSeqs). + return SZ_ERROR_DATA; + numLits >>= 1; + v = GetUi16(src); + src += 2; + inSize -= 2; + if ((b0 & 8) == 0) + { + src--; + inSize++; + v = (Byte)v; + } + numLits += v << 4; + } + compressedSize = 1; + if ((b0 & k_LitBlockType_Flag_RLE_or_Treeless) == 0) + compressedSize = numLits; + } + else if (inSize < 4) + return SZ_ERROR_DATA; + else + { + const unsigned mode4Streams = b0 & 0xc; + const unsigned numBytes = (3 * mode4Streams + 32) >> 4; + const unsigned numBits = 4 * numBytes - 2; + const UInt32 mask = ((UInt32)16 << numBits) - 1; + compressedSize = GetUi32(src); + numLits = (( + #ifdef MY_CPU_LE_UNALIGN + GetUi32(src - 1) + #else + ((compressedSize << 8) + b0) + #endif + ) >> 4) & mask; + src += numBytes; + inSize -= numBytes; + compressedSize >>= numBits; + compressedSize &= mask; + /* + if (numLits != 0) printf("inSize = %7u num_lits=%7u compressed=%7u ratio = %u ratio2 = %u\n", + i1, numLits, (unsigned)compressedSize * 1, (unsigned)compressedSize * 100 / numLits, + (unsigned)numLits * 100 / (unsigned)inSize); + } + */ + if (compressedSize == 0) + return SZ_ERROR_DATA; // (compressedSize == 0) is not allowed + } + + STAT_UPDATE(g_Num_Lits += numLits;) + + vars.literalsLen = numLits; + + if (compressedSize >= inSize) + return SZ_ERROR_DATA; + litStream = src; + src += compressedSize; + inSize -= compressedSize; + // inSize != 0 + { + UInt32 numSeqs = *src++; + inSize--; + if (numSeqs > 127) + { + UInt32 b1; + if (inSize == 0) + return SZ_ERROR_DATA; + numSeqs -= 128; + b1 = *src++; + inSize--; + if (numSeqs == 127) + { + if (inSize == 0) + return SZ_ERROR_DATA; + numSeqs = (UInt32)(*src++) + 127; + inSize--; + } + numSeqs = (numSeqs << 8) + b1; + } + if (numSeqs * MATCH_LEN_MIN + numLits > outLimit) + return SZ_ERROR_DATA; + vars.numSeqs = numSeqs; + + STAT_UPDATE(g_NumSeqs_total += numSeqs;) + /* + #ifdef SHOW_STAT + printf("\n %5u : %8u, %8u : %5u", (int)g_Num_Blocks_Compressed, (int)numSeqs, (int)g_NumSeqs_total, + (int)g_NumSeqs_total / g_Num_Blocks_Compressed); + #endif + // printf("\nnumSeqs2 = %d", numSeqs); + */ + #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP + if (numSeqs != g_numSeqs) return SZ_ERROR_DATA; // for debug + #endif + if (numSeqs == 0) + { + if (inSize != 0) + return SZ_ERROR_DATA; + literalsDest = p->win + p->winPos; + } + else + literalsDest = p->literalsBase; + } + + if ((b0 & k_LitBlockType_Flag_Compressed) == 0) + { + if (b0 & k_LitBlockType_Flag_RLE_or_Treeless) + { + memset(literalsDest, litStream[0], numLits); + if (vars.numSeqs) + { + // literalsDest == p->literalsBase == vars.literals + #if COPY_CHUNK_SIZE > 1 + memset(p->literalsBase + numLits, 0, COPY_CHUNK_SIZE); + #endif + } + } + else + { + // unsigned y; + // for (y = 0; y < 10000; y++) + memcpy(literalsDest, litStream, numLits); + if (vars.numSeqs) + { + /* we need up to (15 == COPY_CHUNK_SIZE - 1) space for optimized CopyLiterals(). + If we have additional space in input stream after literals stream, + we use direct copy of rar literals in input stream */ + if ((size_t)(src + inSize - litStream) - numLits + afterAvail >= (COPY_CHUNK_SIZE - 1)) + vars.literals = litStream; + else + { + // literalsDest == p->literalsBase == vars.literals + #if COPY_CHUNK_SIZE > 1 + /* CopyLiterals(): + 1) we don't want reading non-initialized data + 2) we will copy only zero byte after literals buffer */ + memset(p->literalsBase + numLits, 0, COPY_CHUNK_SIZE); + #endif + } + } + } + } + else + { + CInBufPair hufStream; + hufStream.ptr = litStream; + hufStream.len = compressedSize; + + if ((b0 & k_LitBlockType_Flag_RLE_or_Treeless) == 0) + { + // unsigned y = 100; CInBufPair hs2 = hufStream; do { hufStream = hs2; + RINOK(Huf_DecodeTable(&p->huf, &hufStream)) + p->litHuf_wasSet = True; + // } while (--y); + } + else if (!p->litHuf_wasSet) + return SZ_ERROR_DATA; + + { + // int yyy; for (yyy = 0; yyy < 34; yyy++) { + SRes sres; + if ((b0 & 0xc) == 0) // mode4Streams + sres = Huf_Decompress_1stream((const Byte *)(const void *)p->huf.table64, + hufStream.ptr - HUF_SRC_OFFSET, hufStream.len, literalsDest, numLits); + else + { + // 6 bytes for the jump table + 4x1 bytes of end-padding Bytes) + if (hufStream.len < 6 + 4) + return SZ_ERROR_DATA; + // the condition from original-zstd decoder: + #define Z7_ZSTD_MIN_LITERALS_FOR_4_STREAMS 6 + if (numLits < Z7_ZSTD_MIN_LITERALS_FOR_4_STREAMS) + return SZ_ERROR_DATA; + sres = Huf_Decompress_4stream((const Byte *)(const void *)p->huf.table64, + hufStream.ptr + (6 - HUF_SRC_OFFSET), hufStream.len, literalsDest, numLits); + } + RINOK(sres) + // } + } + } + + if (vars.numSeqs == 0) + { + p->winPos += numLits; + UPDATE_TOTAL_OUT(p, numLits) + return SZ_OK; + } + } + { + CInBufPair in; + unsigned mode; + unsigned seqMode; + + in.ptr = src; + in.len = inSize; + if (in.len == 0) + return SZ_ERROR_DATA; + in.len--; + mode = *in.ptr++; + if (mode & 3) // Reserved bits + return SZ_ERROR_DATA; + + seqMode = (mode >> 6); + if (seqMode == k_SeqMode_Repeat) + { if (!IS_SEQ_TABLES_WERE_SET(p)) return SZ_ERROR_DATA; } + else RINOK(FSE_Decode_SeqTable( + p->fse.ll, + &in, + 6, // predefAccuracy + &p->ll_accuracy, + NUM_LL_SYMBOLS, + k_PredefRecords_LL, + seqMode)) + + seqMode = (mode >> 4) & 3; + if (seqMode == k_SeqMode_Repeat) + { if (!IS_SEQ_TABLES_WERE_SET(p)) return SZ_ERROR_DATA; } + else RINOK(FSE_Decode_SeqTable( + p->fse.of, + &in, + 5, // predefAccuracy + &p->of_accuracy, + NUM_OFFSET_SYMBOLS_MAX, + k_PredefRecords_OF, + seqMode)) + + seqMode = (mode >> 2) & 3; + if (seqMode == k_SeqMode_Repeat) + { if (!IS_SEQ_TABLES_WERE_SET(p)) return SZ_ERROR_DATA; } + else + { + RINOK(FSE_Decode_SeqTable( + p->fse.ml, + &in, + 6, // predefAccuracy + &p->ml_accuracy, + NUM_ML_SYMBOLS, + k_PredefRecords_ML, + seqMode)) + /* + #if defined(Z7_ZSTD_DEC_USE_ML_PLUS3) + // { unsigned y = 1 << 10; do + { + const unsigned accuracy = p->ml_accuracy; + if (accuracy == 0) + p->fse.ml[0] += 3; + else + #ifdef MY_CPU_64BIT + { + // alignemt (UInt64 _pad_Alignment) in fse.ml is required for that code + UInt64 *table = (UInt64 *)(void *)p->fse.ml; + const UInt64 *end = (const UInt64 *)(const void *) + ((const Byte *)(const void *)table + ((size_t)sizeof(CFseRecord) << accuracy)); + do + { + table[0] += ((UInt64)MATCH_LEN_MIN << 32) + MATCH_LEN_MIN; + table[1] += ((UInt64)MATCH_LEN_MIN << 32) + MATCH_LEN_MIN; + table += 2; + } + while (table != end); + } + #else + { + UInt32 *table = p->fse.ml; + const UInt32 *end = (const UInt32 *)(const void *) + ((const Byte *)(const void *)table + ((size_t)sizeof(CFseRecord) << accuracy)); + do + { + table[0] += MATCH_LEN_MIN; + table[1] += MATCH_LEN_MIN; + table += 2; + table[0] += MATCH_LEN_MIN; + table[1] += MATCH_LEN_MIN; + table += 2; + } + while (table != end); + } + #endif + } + // while (--y); } + #endif + */ + } + + // p->seqTables_wereSet = True; + if (in.len == 0) + return SZ_ERROR_DATA; + return Decompress_Sequences(p, + in.ptr - SEQ_SRC_OFFSET - BIT_OFFSET_DELTA_BYTES, in.len, + p->winPos + outLimit, &vars); + } +} + + + + +// inSize != 0 +// it must do similar to ZstdDec1_DecodeBlock() +static size_t ZstdDec1_NeedTempBufferForInput( + const SizeT beforeSize, const Byte * const src, const SizeT inSize) +{ + unsigned b0; + UInt32 pos; + + #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP + g_numSeqs = 1 << 24; + #else + // we have at least 3 bytes before seq data: litBlockType, numSeqs, seqMode + #define MIN_BLOCK_LZ_HEADERS_SIZE 3 + if (beforeSize >= MAX_BACKWARD_DEPTH - MIN_BLOCK_LZ_HEADERS_SIZE) + return 0; + #endif + + b0 = src[0]; + + if ((b0 & k_LitBlockType_Flag_Compressed) == 0) + { + UInt32 numLits = b0 >> 3; + pos = 1; + if (b0 & 4) + { + UInt32 v; + if (inSize < 3) + return 0; + numLits >>= 1; + v = GetUi16(src + 1); + pos = 3; + if ((b0 & 8) == 0) + { + pos = 2; + v = (Byte)v; + } + numLits += v << 4; + } + if (b0 & k_LitBlockType_Flag_RLE_or_Treeless) + numLits = 1; + pos += numLits; + } + else if (inSize < 5) + return 0; + else + { + const unsigned mode4Streams = b0 & 0xc; + const unsigned numBytes = (3 * mode4Streams + 48) >> 4; + const unsigned numBits = 4 * numBytes - 6; + UInt32 cs = GetUi32(src + 1); + cs >>= numBits; + cs &= ((UInt32)16 << numBits) - 1; + if (cs == 0) + return 0; + pos = numBytes + cs; + } + + if (pos >= inSize) + return 0; + { + UInt32 numSeqs = src[pos++]; + if (numSeqs > 127) + { + UInt32 b1; + if (pos >= inSize) + return 0; + numSeqs -= 128; + b1 = src[pos++]; + if (numSeqs == 127) + { + if (pos >= inSize) + return 0; + numSeqs = (UInt32)(src[pos++]) + 127; + } + numSeqs = (numSeqs << 8) + b1; + } + #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP + g_numSeqs = numSeqs; // for debug + #endif + if (numSeqs == 0) + return 0; + } + /* + if (pos >= inSize) + return 0; + pos++; + */ + // we will have one additional byte for seqMode: + if (beforeSize + pos >= MAX_BACKWARD_DEPTH - 1) + return 0; + return 1; +} + + + +// ---------- ZSTD FRAME ---------- + +#define kBlockType_Raw 0 +#define kBlockType_RLE 1 +#define kBlockType_Compressed 2 +#define kBlockType_Reserved 3 + +typedef enum +{ + // begin: states that require 4 bytes: + ZSTD2_STATE_SIGNATURE, + ZSTD2_STATE_HASH, + ZSTD2_STATE_SKIP_HEADER, + // end of states that require 4 bytes + + ZSTD2_STATE_SKIP_DATA, + ZSTD2_STATE_FRAME_HEADER, + ZSTD2_STATE_AFTER_HEADER, + ZSTD2_STATE_BLOCK, + ZSTD2_STATE_DATA, + ZSTD2_STATE_FINISHED +} EZstd2State; + + +struct CZstdDec +{ + EZstd2State frameState; + unsigned tempSize; + + Byte temp[14]; // 14 is required + + Byte descriptor; + Byte windowDescriptor; + Byte isLastBlock; + Byte blockType; + Byte isErrorState; + Byte hashError; + Byte disableHash; + Byte isCyclicMode; + + UInt32 blockSize; + UInt32 dictionaryId; + UInt32 curBlockUnpackRem; // for compressed blocks only + UInt32 inTempPos; + + UInt64 contentSize; + UInt64 contentProcessed; + CXxh64State xxh64; + + Byte *inTemp; + SizeT winBufSize_Allocated; + Byte *win_Base; + + ISzAllocPtr alloc_Small; + ISzAllocPtr alloc_Big; + + CZstdDec1 decoder; +}; + +#define ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p) \ + ((unsigned)(p)->contentProcessed & (Z7_XXH64_BLOCK_SIZE - 1)) + +#define ZSTD_DEC_IS_LAST_BLOCK(p) ((p)->isLastBlock) + + +static void ZstdDec_FreeWindow(CZstdDec * const p) +{ + if (p->win_Base) + { + ISzAlloc_Free(p->alloc_Big, p->win_Base); + p->win_Base = NULL; + // p->decoder.win = NULL; + p->winBufSize_Allocated = 0; + } +} + + +CZstdDecHandle ZstdDec_Create(ISzAllocPtr alloc_Small, ISzAllocPtr alloc_Big) +{ + CZstdDec *p = (CZstdDec *)ISzAlloc_Alloc(alloc_Small, sizeof(CZstdDec)); + if (!p) + return NULL; + p->alloc_Small = alloc_Small; + p->alloc_Big = alloc_Big; + // ZstdDec_CONSTRUCT(p) + p->inTemp = NULL; + p->win_Base = NULL; + p->winBufSize_Allocated = 0; + p->disableHash = False; + ZstdDec1_Construct(&p->decoder); + return p; +} + +void ZstdDec_Destroy(CZstdDecHandle p) +{ + #ifdef SHOW_STAT + #define PRINT_STAT1(name, v) \ + printf("\n%25s = %9u", name, v); + PRINT_STAT1("g_Num_Blocks_Compressed", g_Num_Blocks_Compressed) + PRINT_STAT1("g_Num_Blocks_memcpy", g_Num_Blocks_memcpy) + PRINT_STAT1("g_Num_Wrap_memmove_Num", g_Num_Wrap_memmove_Num) + PRINT_STAT1("g_Num_Wrap_memmove_Bytes", g_Num_Wrap_memmove_Bytes) + if (g_Num_Blocks_Compressed) + { + #define PRINT_STAT(name, v) \ + printf("\n%17s = %9u, per_block = %8u", name, v, v / g_Num_Blocks_Compressed); + PRINT_STAT("g_NumSeqs", g_NumSeqs_total) + // PRINT_STAT("g_NumCopy", g_NumCopy) + PRINT_STAT("g_NumOver", g_NumOver) + PRINT_STAT("g_NumOver2", g_NumOver2) + PRINT_STAT("g_Num_Match", g_Num_Match) + PRINT_STAT("g_Num_Lits", g_Num_Lits) + PRINT_STAT("g_Num_LitsBig", g_Num_LitsBig) + PRINT_STAT("g_Num_Lit0", g_Num_Lit0) + PRINT_STAT("g_Num_Rep_0", g_Num_Rep0) + PRINT_STAT("g_Num_Rep_1", g_Num_Rep1) + PRINT_STAT("g_Num_Rep_2", g_Num_Rep2) + PRINT_STAT("g_Num_Rep_3", g_Num_Rep3) + PRINT_STAT("g_Num_Threshold_0", g_Num_Threshold_0) + PRINT_STAT("g_Num_Threshold_1", g_Num_Threshold_1) + PRINT_STAT("g_Num_Threshold_0sum", g_Num_Threshold_0sum) + PRINT_STAT("g_Num_Threshold_1sum", g_Num_Threshold_1sum) + } + printf("\n"); + #endif + + ISzAlloc_Free(p->alloc_Small, p->decoder.literalsBase); + // p->->decoder.literalsBase = NULL; + ISzAlloc_Free(p->alloc_Small, p->inTemp); + // p->inTemp = NULL; + ZstdDec_FreeWindow(p); + ISzAlloc_Free(p->alloc_Small, p); +} + + + +#define kTempBuffer_PreSize (1u << 6) +#if kTempBuffer_PreSize < MAX_BACKWARD_DEPTH + #error Stop_Compiling_Bad_kTempBuffer_PreSize +#endif + +static SRes ZstdDec_AllocateMisc(CZstdDec *p) +{ + #define k_Lit_AfterAvail (1u << 6) + #if k_Lit_AfterAvail < (COPY_CHUNK_SIZE - 1) + #error Stop_Compiling_Bad_k_Lit_AfterAvail + #endif + // return ZstdDec1_Allocate(&p->decoder, p->alloc_Small); + if (!p->decoder.literalsBase) + { + p->decoder.literalsBase = (Byte *)ISzAlloc_Alloc(p->alloc_Small, + kBlockSizeMax + k_Lit_AfterAvail); + if (!p->decoder.literalsBase) + return SZ_ERROR_MEM; + } + if (!p->inTemp) + { + // we need k_Lit_AfterAvail here for owerread from raw literals stream + p->inTemp = (Byte *)ISzAlloc_Alloc(p->alloc_Small, + kBlockSizeMax + kTempBuffer_PreSize + k_Lit_AfterAvail); + if (!p->inTemp) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + + +static void ZstdDec_Init_ForNewFrame(CZstdDec *p) +{ + p->frameState = ZSTD2_STATE_SIGNATURE; + p->tempSize = 0; + + p->isErrorState = False; + p->hashError = False; + p->isCyclicMode = False; + p->contentProcessed = 0; + Xxh64State_Init(&p->xxh64); + ZstdDec1_Init(&p->decoder); +} + + +void ZstdDec_Init(CZstdDec *p) +{ + ZstdDec_Init_ForNewFrame(p); + p->decoder.winPos = 0; + memset(p->temp, 0, sizeof(p->temp)); +} + + +#define DESCRIPTOR_Get_DictionaryId_Flag(d) ((d) & 3) +#define DESCRIPTOR_FLAG_CHECKSUM (1 << 2) +#define DESCRIPTOR_FLAG_RESERVED (1 << 3) +// #define DESCRIPTOR_FLAG_UNUSED (1 << 4) +#define DESCRIPTOR_FLAG_SINGLE (1 << 5) +#define DESCRIPTOR_Get_ContentSize_Flag3(d) ((d) >> 5) +#define DESCRIPTOR_Is_ContentSize_Defined(d) (((d) & 0xe0) != 0) + + +static EZstd2State ZstdDec_UpdateState(CZstdDec * const p, const Byte b, CZstdDecInfo * const info) +{ + unsigned tempSize = p->tempSize; + p->temp[tempSize++] = b; + p->tempSize = tempSize; + + if (p->frameState == ZSTD2_STATE_BLOCK) + { + if (tempSize < 3) + return ZSTD2_STATE_BLOCK; + { + UInt32 b0 = GetUi32(p->temp); + const unsigned type = ((unsigned)b0 >> 1) & 3; + if (type == kBlockType_RLE && tempSize == 3) + return ZSTD2_STATE_BLOCK; + // info->num_Blocks_forType[type]++; + info->num_Blocks++; + if (type == kBlockType_Reserved) + { + p->isErrorState = True; // SZ_ERROR_UNSUPPORTED + return ZSTD2_STATE_BLOCK; + } + p->blockType = (Byte)type; + p->isLastBlock = (Byte)(b0 & 1); + p->inTempPos = 0; + p->tempSize = 0; + b0 >>= 3; + b0 &= 0x1fffff; + // info->num_BlockBytes_forType[type] += b0; + if (b0 == 0) + { + // empty RAW/RLE blocks are allowed in original-zstd decoder + if (type == kBlockType_Compressed) + { + p->isErrorState = True; + return ZSTD2_STATE_BLOCK; + } + if (!ZSTD_DEC_IS_LAST_BLOCK(p)) + return ZSTD2_STATE_BLOCK; + if (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM) + return ZSTD2_STATE_HASH; + return ZSTD2_STATE_FINISHED; + } + p->blockSize = b0; + { + UInt32 blockLim = ZstdDec1_GET_BLOCK_SIZE_LIMIT(&p->decoder); + // compressed and uncompressed block sizes cannot be larger than min(kBlockSizeMax, window_size) + if (b0 > blockLim) + { + p->isErrorState = True; // SZ_ERROR_UNSUPPORTED; + return ZSTD2_STATE_BLOCK; + } + if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor)) + { + const UInt64 rem = p->contentSize - p->contentProcessed; + if (blockLim > rem) + blockLim = (UInt32)rem; + } + p->curBlockUnpackRem = blockLim; + // uncompressed block size cannot be larger than remain data size: + if (type != kBlockType_Compressed) + { + if (b0 > blockLim) + { + p->isErrorState = True; // SZ_ERROR_UNSUPPORTED; + return ZSTD2_STATE_BLOCK; + } + } + } + } + return ZSTD2_STATE_DATA; + } + + if ((unsigned)p->frameState < ZSTD2_STATE_SKIP_DATA) + { + UInt32 v; + if (tempSize != 4) + return p->frameState; + v = GetUi32(p->temp); + if ((unsigned)p->frameState < ZSTD2_STATE_HASH) // == ZSTD2_STATE_SIGNATURE + { + if (v == 0xfd2fb528) + { + p->tempSize = 0; + info->num_DataFrames++; + return ZSTD2_STATE_FRAME_HEADER; + } + if ((v & 0xfffffff0) == 0x184d2a50) + { + p->tempSize = 0; + info->num_SkipFrames++; + return ZSTD2_STATE_SKIP_HEADER; + } + p->isErrorState = True; + return ZSTD2_STATE_SIGNATURE; + // return ZSTD2_STATE_ERROR; // is not ZSTD stream + } + if (p->frameState == ZSTD2_STATE_HASH) + { + info->checksum_Defined = True; + info->checksum = v; + // #ifndef DISABLE_XXH_CHECK + if (!p->disableHash) + { + if (p->decoder.winPos < ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p)) + { + // unexpected code failure + p->isErrorState = True; + // SZ_ERROR_FAIL; + } + else + if ((UInt32)Xxh64State_Digest(&p->xxh64, + p->decoder.win + (p->decoder.winPos - ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p)), + p->contentProcessed) != v) + { + p->hashError = True; + // return ZSTD2_STATE_ERROR; // hash error + } + } + // #endif + return ZSTD2_STATE_FINISHED; + } + // (p->frameState == ZSTD2_STATE_SKIP_HEADER) + { + p->blockSize = v; + info->skipFrames_Size += v; + p->tempSize = 0; + /* we want the caller could know that there was finished frame + finished frame. So we allow the case where + we have ZSTD2_STATE_SKIP_DATA state with (blockSize == 0). + */ + // if (v == 0) return ZSTD2_STATE_SIGNATURE; + return ZSTD2_STATE_SKIP_DATA; + } + } + + // if (p->frameState == ZSTD2_STATE_FRAME_HEADER) + { + unsigned descriptor; + const Byte *h; + descriptor = p->temp[0]; + p->descriptor = (Byte)descriptor; + if (descriptor & DESCRIPTOR_FLAG_RESERVED) // reserved bit + { + p->isErrorState = True; + return ZSTD2_STATE_FRAME_HEADER; + // return ZSTD2_STATE_ERROR; + } + { + const unsigned n = DESCRIPTOR_Get_ContentSize_Flag3(descriptor); + // tempSize -= 1 + ((1u << (n >> 1)) | ((n + 1) & 1)); + tempSize -= (0x9a563422u >> (n * 4)) & 0xf; + } + if (tempSize != (4u >> (3 - DESCRIPTOR_Get_DictionaryId_Flag(descriptor)))) + return ZSTD2_STATE_FRAME_HEADER; + + info->descriptor_OR = (Byte)(info->descriptor_OR | descriptor); + info->descriptor_NOT_OR = (Byte)(info->descriptor_NOT_OR | ~descriptor); + + h = &p->temp[1]; + { + Byte w = 0; + if ((descriptor & DESCRIPTOR_FLAG_SINGLE) == 0) + { + w = *h++; + if (info->windowDescriptor_MAX < w) + info->windowDescriptor_MAX = w; + // info->are_WindowDescriptors = True; + // info->num_WindowDescriptors++; + } + else + { + // info->are_SingleSegments = True; + // info->num_SingleSegments++; + } + p->windowDescriptor = w; + } + { + unsigned n = DESCRIPTOR_Get_DictionaryId_Flag(descriptor); + UInt32 d = 0; + if (n) + { + n = 1u << (n - 1); + d = GetUi32(h) & ((UInt32)(Int32)-1 >> (32 - 8u * n)); + h += n; + } + p->dictionaryId = d; + // info->dictionaryId_Cur = d; + if (d != 0) + { + if (info->dictionaryId == 0) + info->dictionaryId = d; + else if (info->dictionaryId != d) + info->are_DictionaryId_Different = True; + } + } + { + unsigned n = DESCRIPTOR_Get_ContentSize_Flag3(descriptor); + UInt64 v = 0; + if (n) + { + n >>= 1; + if (n == 1) + v = 256; + v += GetUi64(h) & ((UInt64)(Int64)-1 >> (64 - (8u << n))); + // info->are_ContentSize_Known = True; + // info->num_Frames_with_ContentSize++; + if (info->contentSize_MAX < v) + info->contentSize_MAX = v; + info->contentSize_Total += v; + } + else + { + info->are_ContentSize_Unknown = True; + // info->num_Frames_without_ContentSize++; + } + p->contentSize = v; + } + // if ((size_t)(h - p->temp) != headerSize) return ZSTD2_STATE_ERROR; // it's unexpected internal code failure + p->tempSize = 0; + + info->checksum_Defined = False; + /* + if (descriptor & DESCRIPTOR_FLAG_CHECKSUM) + info->are_Checksums = True; + else + info->are_Non_Checksums = True; + */ + + return ZSTD2_STATE_AFTER_HEADER; // ZSTD2_STATE_BLOCK; + } +} + + +static void ZstdDec_Update_XXH(CZstdDec * const p, size_t xxh64_winPos) +{ + /* + #ifdef DISABLE_XXH_CHECK + UNUSED_VAR(data) + #else + */ + if (!p->disableHash && (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM)) + { + // const size_t pos = p->xxh64_winPos; + const size_t size = (p->decoder.winPos - xxh64_winPos) & ~(size_t)31; + if (size) + { + // p->xxh64_winPos = pos + size; + Xxh64State_UpdateBlocks(&p->xxh64, + p->decoder.win + xxh64_winPos, + p->decoder.win + xxh64_winPos + size); + } + } +} + + +/* +in: + (winLimit) : is relaxed limit, where this function is allowed to stop writing of decoded data (if possible). + - this function uses (winLimit) for RAW/RLE blocks only, + because this function can decode single RAW/RLE block in several different calls. + - this function DOESN'T use (winLimit) for Compressed blocks, + because this function decodes full compressed block in single call. + (CZstdDec1::winPos <= winLimit) + (winLimit <= CZstdDec1::cycSize). + Note: if (ds->outBuf_fromCaller) mode is used, then + { + (strong_limit) is stored in CZstdDec1::cycSize. + So (winLimit) is more strong than (strong_limit). + } + +exit: + Note: (CZstdDecState::winPos) will be set by caller after exit of this function. + + This function can exit for any of these conditions: + - (frameState == ZSTD2_STATE_AFTER_HEADER) + - (frameState == ZSTD2_STATE_FINISHED) : frame was finished : (status == ZSTD_STATUS_FINISHED_FRAME) is set + - finished non-empty non-last block. So (CZstdDec1::winPos_atExit != winPos_atFuncStart). + - ZSTD_STATUS_NEEDS_MORE_INPUT in src + - (CZstdDec1::winPos) have reached (winLimit) in non-finished RAW/RLE block + + This function decodes no more than one non-empty block. + So it fulfills the condition at exit: + (CZstdDec1::winPos_atExit - winPos_atFuncStart <= block_size_max) + Note: (winPos_atExit > winLimit) is possible in some cases after compressed block decoding. + + if (ds->outBuf_fromCaller) mode (useAdditionalWinLimit medo) + { + then this function uses additional strong limit from (CZstdDec1::cycSize). + So this function will not write any data after (CZstdDec1::cycSize) + And it fulfills the condition at exit: + (CZstdDec1::winPos_atExit <= CZstdDec1::cycSize) + } +*/ +static SRes ZstdDec_DecodeBlock(CZstdDec * const p, CZstdDecState * const ds, + SizeT winLimitAdd) +{ + const Byte *src = ds->inBuf; + SizeT * const srcLen = &ds->inPos; + const SizeT inSize = ds->inLim; + // const int useAdditionalWinLimit = ds->outBuf_fromCaller ? 1 : 0; + enum_ZstdStatus * const status = &ds->status; + CZstdDecInfo * const info = &ds->info; + SizeT winLimit; + + const SizeT winPos_atFuncStart = p->decoder.winPos; + src += *srcLen; + *status = ZSTD_STATUS_NOT_SPECIFIED; + + // finishMode = ZSTD_FINISH_ANY; + if (ds->outSize_Defined) + { + if (ds->outSize < ds->outProcessed) + { + // p->isAfterSizeMode = 2; // we have extra bytes already + *status = ZSTD_STATUS_OUT_REACHED; + return SZ_OK; + // size = 0; + } + else + { + // p->outSize >= p->outProcessed + const UInt64 rem = ds->outSize - ds->outProcessed; + /* + if (rem == 0) + p->isAfterSizeMode = 1; // we have reached exact required size + */ + if (winLimitAdd >= rem) + { + winLimitAdd = (SizeT)rem; + // if (p->finishMode) finishMode = ZSTD_FINISH_END; + } + } + } + + winLimit = p->decoder.winPos + winLimitAdd; + // (p->decoder.winPos <= winLimit) + + // while (p->frameState != ZSTD2_STATE_ERROR) + while (!p->isErrorState) + { + SizeT inCur = inSize - *srcLen; + + if (p->frameState == ZSTD2_STATE_DATA) + { + /* (p->decoder.winPos == winPos_atFuncStart) is expected, + because this function doesn't start new block. + if it have finished some non-empty block in this call. */ + if (p->decoder.winPos != winPos_atFuncStart) + return SZ_ERROR_FAIL; // it's unexpected + + /* + if (p->decoder.winPos > winLimit) + { + // we can be here, if in this function call + // - we have extracted non-empty compressed block, and (winPos > winLimit) after that. + // - we have started new block decoding after that. + // It's unexpected case, because we exit after non-empty non-last block. + *status = (inSize == *srcLen) ? + ZSTD_STATUS_NEEDS_MORE_INPUT : + ZSTD_STATUS_NOT_FINISHED; + return SZ_OK; + } + */ + // p->decoder.winPos <= winLimit + + if (p->blockType != kBlockType_Compressed) + { + // it's RLE or RAW block. + // p->BlockSize != 0_ + // winLimit <= p->decoder.cycSize + /* So here we use more strong (winLimit), even for + (ds->outBuf_fromCaller) mode. */ + SizeT outCur = winLimit - p->decoder.winPos; + { + const UInt32 rem = p->blockSize; + if (outCur > rem) + outCur = rem; + } + if (p->blockType == kBlockType_Raw) + { + if (outCur > inCur) + outCur = inCur; + /* output buffer is better aligned for XXH code. + So we use hash for output buffer data */ + // ZstdDec_Update_XXH(p, src, outCur); // for debug: + memcpy(p->decoder.win + p->decoder.winPos, src, outCur); + src += outCur; + *srcLen += outCur; + } + else // kBlockType_RLE + { + #define RLE_BYTE_INDEX_IN_temp 3 + memset(p->decoder.win + p->decoder.winPos, + p->temp[RLE_BYTE_INDEX_IN_temp], outCur); + } + { + const SizeT xxh64_winPos = p->decoder.winPos - ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p); + p->decoder.winPos += outCur; + UPDATE_TOTAL_OUT(&p->decoder, outCur) + p->contentProcessed += outCur; + ZstdDec_Update_XXH(p, xxh64_winPos); + } + // ds->winPos = p->decoder.winPos; // the caller does it instead. for debug: + ds->outProcessed += outCur; + if (p->blockSize -= (UInt32)outCur) + { + /* + if (ds->outSize_Defined) + { + if (ds->outSize <= ds->outProcessed) ds->isAfterSizeMode = (enum_ZstdStatus) + (ds->outSize == ds->outProcessed ? 1u: 2u); + } + */ + *status = (enum_ZstdStatus) + (ds->outSize_Defined && ds->outSize <= ds->outProcessed ? + ZSTD_STATUS_OUT_REACHED : (p->blockType == kBlockType_Raw && inSize == *srcLen) ? + ZSTD_STATUS_NEEDS_MORE_INPUT : + ZSTD_STATUS_NOT_FINISHED); + return SZ_OK; + } + } + else // kBlockType_Compressed + { + // p->blockSize != 0 + // (uncompressed_size_of_block == 0) is allowed + // (p->curBlockUnpackRem == 0) is allowed + /* + if (p->decoder.winPos >= winLimit) + { + if (p->decoder.winPos != winPos_atFuncStart) + { + // it's unexpected case + // We already have some data in finished blocks in this function call. + // So we don't decompress new block after (>=winLimit), + // even if it's empty block. + *status = (inSize == *srcLen) ? + ZSTD_STATUS_NEEDS_MORE_INPUT : + ZSTD_STATUS_NOT_FINISHED; + return SZ_OK; + } + // (p->decoder.winPos == winLimit == winPos_atFuncStart) + // we will decode current block, because that current + // block can be empty block and we want to make some visible + // change of (src) stream after function start. + } + */ + /* + if (ds->outSize_Defined && ds->outSize < ds->outProcessed) + { + // we don't want to start new block, if we have more extra decoded bytes already + *status = ZSTD_STATUS_OUT_REACHED; + return SZ_OK; + } + */ + { + const Byte *comprStream; + size_t afterAvail; + UInt32 inTempPos = p->inTempPos; + const UInt32 rem = p->blockSize - inTempPos; + // rem != 0 + if (inTempPos != 0 // (inTemp) buffer already contains some input data + || inCur < rem // available input data size is smaller than compressed block size + || ZstdDec1_NeedTempBufferForInput(*srcLen, src, rem)) + { + if (inCur > rem) + inCur = rem; + if (inCur) + { + STAT_INC(g_Num_Blocks_memcpy) + // we clear data for backward lookahead reading + if (inTempPos == 0) + memset(p->inTemp + kTempBuffer_PreSize - MAX_BACKWARD_DEPTH, 0, MAX_BACKWARD_DEPTH); + // { unsigned y = 0; for(;y < 1000; y++) + memcpy(p->inTemp + inTempPos + kTempBuffer_PreSize, src, inCur); + // } + src += inCur; + *srcLen += inCur; + inTempPos += (UInt32)inCur; + p->inTempPos = inTempPos; + } + if (inTempPos != p->blockSize) + { + *status = ZSTD_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + #if COPY_CHUNK_SIZE > 1 + memset(p->inTemp + kTempBuffer_PreSize + inTempPos, 0, COPY_CHUNK_SIZE); + #endif + comprStream = p->inTemp + kTempBuffer_PreSize; + afterAvail = k_Lit_AfterAvail; + // we don't want to read non-initialized data or junk in CopyMatch(): + } + else + { + // inCur >= rem + // we use direct decoding from (src) buffer: + afterAvail = inCur - rem; + comprStream = src; + src += rem; + *srcLen += rem; + } + + #ifdef Z7_ZSTD_DEC_USE_CHECK_OF_NEED_TEMP + ZstdDec1_NeedTempBufferForInput(*srcLen, comprStream, p->blockSize); + #endif + // printf("\nblockSize=%u", p->blockSize); + // printf("%x\n", (unsigned)p->contentProcessed); + STAT_INC(g_Num_Blocks_Compressed) + { + SRes sres; + const size_t winPos = p->decoder.winPos; + /* + if ( useAdditionalWinLimit), we use strong unpack limit: smallest from + - limit from stream : (curBlockUnpackRem) + - limit from caller : (cycSize - winPos) + if (!useAdditionalWinLimit), we use only relaxed limit: + - limit from stream : (curBlockUnpackRem) + */ + SizeT outLimit = p->curBlockUnpackRem; + if (ds->outBuf_fromCaller) + // if (useAdditionalWinLimit) + { + const size_t limit = p->decoder.cycSize - winPos; + if (outLimit > limit) + outLimit = limit; + } + sres = ZstdDec1_DecodeBlock(&p->decoder, + comprStream, p->blockSize, afterAvail, outLimit); + // ds->winPos = p->decoder.winPos; // the caller does it instead. for debug: + if (sres) + { + p->isErrorState = True; + return sres; + } + { + const SizeT xxh64_winPos = winPos - ZstdDec_GET_UNPROCESSED_XXH64_SIZE(p); + const size_t num = p->decoder.winPos - winPos; + ds->outProcessed += num; + p->contentProcessed += num; + ZstdDec_Update_XXH(p, xxh64_winPos); + } + } + // printf("\nwinPos=%x", (int)(unsigned)p->decoder.winPos); + } + } + + /* + if (ds->outSize_Defined) + { + if (ds->outSize <= ds->outProcessed) ds->isAfterSizeMode = (enum_ZstdStatus) + (ds->outSize == ds->outProcessed ? 1u: 2u); + } + */ + + if (!ZSTD_DEC_IS_LAST_BLOCK(p)) + { + p->frameState = ZSTD2_STATE_BLOCK; + if (ds->outSize_Defined && ds->outSize < ds->outProcessed) + { + *status = ZSTD_STATUS_OUT_REACHED; + return SZ_OK; + } + // we exit only if (winPos) was changed in this function call: + if (p->decoder.winPos != winPos_atFuncStart) + { + // decoded block was not empty. So we exit: + *status = (enum_ZstdStatus)( + (inSize == *srcLen) ? + ZSTD_STATUS_NEEDS_MORE_INPUT : + ZSTD_STATUS_NOT_FINISHED); + return SZ_OK; + } + // (p->decoder.winPos == winPos_atFuncStart) + // so current decoded block was empty. + // we will try to decode more blocks in this function. + continue; + } + + // decoded block was last in frame + if (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM) + { + p->frameState = ZSTD2_STATE_HASH; + if (ds->outSize_Defined && ds->outSize < ds->outProcessed) + { + *status = ZSTD_STATUS_OUT_REACHED; + return SZ_OK; // disable if want to + /* We want to get same return codes for any input buffer sizes. + We want to get faster ZSTD_STATUS_OUT_REACHED status. + So we exit with ZSTD_STATUS_OUT_REACHED here, + instead of ZSTD2_STATE_HASH and ZSTD2_STATE_FINISHED processing. + that depends from input buffer size and that can set + ZSTD_STATUS_NEEDS_MORE_INPUT or return SZ_ERROR_DATA or SZ_ERROR_CRC. + */ + } + } + else + { + /* ZSTD2_STATE_FINISHED proccesing doesn't depend from input buffer */ + p->frameState = ZSTD2_STATE_FINISHED; + } + /* + p->frameState = (p->descriptor & DESCRIPTOR_FLAG_CHECKSUM) ? + ZSTD2_STATE_HASH : + ZSTD2_STATE_FINISHED; + */ + /* it's required to process ZSTD2_STATE_FINISHED state in this function call, + because we must check contentSize and hashError in ZSTD2_STATE_FINISHED code, + while the caller can reinit full state for ZSTD2_STATE_FINISHED + So we can't exit from function here. */ + continue; + } + + if (p->frameState == ZSTD2_STATE_FINISHED) + { + *status = ZSTD_STATUS_FINISHED_FRAME; + if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor) + && p->contentSize != p->contentProcessed) + return SZ_ERROR_DATA; + if (p->hashError) // for debug + return SZ_ERROR_CRC; + return SZ_OK; + // p->frameState = ZSTD2_STATE_SIGNATURE; + // continue; + } + + if (p->frameState == ZSTD2_STATE_AFTER_HEADER) + return SZ_OK; // we need memory allocation for that state + + if (p->frameState == ZSTD2_STATE_SKIP_DATA) + { + UInt32 blockSize = p->blockSize; + // (blockSize == 0) is possible + if (inCur > blockSize) + inCur = blockSize; + src += inCur; + *srcLen += inCur; + blockSize -= (UInt32)inCur; + p->blockSize = blockSize; + if (blockSize == 0) + { + p->frameState = ZSTD2_STATE_SIGNATURE; + // continue; // for debug: we can continue without return to caller. + // we notify the caller that skip frame was finished: + *status = ZSTD_STATUS_FINISHED_FRAME; + return SZ_OK; + } + // blockSize != 0 + // (inCur) was smaller than previous value of p->blockSize. + // (inSize == *srcLen) now + *status = ZSTD_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + if (inCur == 0) + { + *status = ZSTD_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + + { + (*srcLen)++; + p->frameState = ZstdDec_UpdateState(p, *src++, info); + } + } + + *status = ZSTD_STATUS_NOT_SPECIFIED; + p->isErrorState = True; + // p->frameState = ZSTD2_STATE_ERROR; + // if (p->frameState = ZSTD2_STATE_SIGNATURE) return SZ_ERROR_NO_ARCHIVE + return SZ_ERROR_DATA; +} + + + + +SRes ZstdDec_Decode(CZstdDecHandle dec, CZstdDecState *p) +{ + p->needWrite_Size = 0; + p->status = ZSTD_STATUS_NOT_SPECIFIED; + dec->disableHash = p->disableHash; + + if (p->outBuf_fromCaller) + { + dec->decoder.win = p->outBuf_fromCaller; + dec->decoder.cycSize = p->outBufSize_fromCaller; + } + + // p->winPos = dec->decoder.winPos; + + for (;;) + { + SizeT winPos, size; + // SizeT outProcessed; + SRes res; + + if (p->wrPos > dec->decoder.winPos) + return SZ_ERROR_FAIL; + + if (dec->frameState == ZSTD2_STATE_FINISHED) + { + if (!p->outBuf_fromCaller) + { + // we need to set positions to zero for new frame. + if (p->wrPos != dec->decoder.winPos) + { + /* We have already asked the caller to flush all data + with (p->needWrite_Size) and (ZSTD_STATUS_FINISHED_FRAME) status. + So it's unexpected case */ + // p->winPos = dec->decoder.winPos; + // p->needWrite_Size = dec->decoder.winPos - p->wrPos; // flush size asking + // return SZ_OK; // ask to flush again + return SZ_ERROR_FAIL; + } + // (p->wrPos == dec->decoder.winPos), and we wrap to zero: + dec->decoder.winPos = 0; + p->winPos = 0; + p->wrPos = 0; + } + ZstdDec_Init_ForNewFrame(dec); + // continue; + } + + winPos = dec->decoder.winPos; + { + SizeT next = dec->decoder.cycSize; + /* cycSize == 0, if no buffer was allocated still, + or, if (outBuf_fromCaller) mode and (outBufSize_fromCaller == 0) */ + if (!p->outBuf_fromCaller + && next + && next <= winPos + && dec->isCyclicMode) + { + // (0 < decoder.cycSize <= winPos) in isCyclicMode. + // so we need to wrap (winPos) and (wrPos) over (cycSize). + const size_t delta = next; + // (delta) is how many bytes we remove from buffer. + /* + // we don't need data older than last (cycSize) bytes. + size_t delta = winPos - next; // num bytes after (cycSize) + if (delta <= next) // it's expected case + delta = next; + // delta == Max(cycSize, winPos - cycSize) + */ + if (p->wrPos < delta) + { + // (wrPos < decoder.cycSize) + // We have asked already the caller to flush required data + // p->status = ZSTD_STATUS_NOT_SPECIFIED; + // p->winPos = winPos; + // p->needWrite_Size = delta - p->wrPos; // flush size asking + // return SZ_OK; // ask to flush again + return SZ_ERROR_FAIL; + } + // p->wrPos >= decoder.cycSize + // we move extra data after (decoder.cycSize) to start of cyclic buffer: + winPos -= delta; + if (winPos) + { + if (winPos >= delta) + return SZ_ERROR_FAIL; + memmove(dec->decoder.win, dec->decoder.win + delta, winPos); + // printf("\nmemmove processed=%8x winPos=%8x\n", (unsigned)p->outProcessed, (unsigned)dec->decoder.winPos); + STAT_INC(g_Num_Wrap_memmove_Num) + STAT_UPDATE(g_Num_Wrap_memmove_Bytes += (unsigned)winPos;) + } + dec->decoder.winPos = winPos; + p->winPos = winPos; + p->wrPos -= delta; + // dec->xxh64_winPos -= delta; + + // (winPos < delta) + #ifdef Z7_STD_DEC_USE_AFTER_CYC_BUF + /* we set the data after cycSize, because + we don't want to read non-initialized data or junk in CopyMatch(). */ + memset(dec->decoder.win + next, 0, COPY_CHUNK_SIZE); + #endif + + /* + if (winPos == next) + { + if (winPos != p->wrPos) + { + // we already requested before to flush full data for that case. + // but we give the caller a second chance to flush data: + p->needWrite_Size = winPos - p->wrPos; + return SZ_OK; + } + // (decoder.cycSize == winPos == p->wrPos) + // so we do second wrapping to zero: + winPos = 0; + dec->decoder.winPos = 0; + p->winPos = 0; + p->wrPos = 0; + } + */ + // (winPos < next) + } + + if (winPos > next) + return SZ_ERROR_FAIL; // it's unexpected case + /* + if (!outBuf_fromCaller && isCyclicMode && cycSize != 0) + then (winPos < cycSize) + else (winPos <= cycSize) + */ + if (!p->outBuf_fromCaller) + { + // that code is optional. We try to optimize write chunk sizes. + /* (next2) is expected next write position in the caller, + if the caller writes by kBlockSizeMax chunks. + */ + /* + const size_t next2 = (winPos + kBlockSizeMax) & (kBlockSizeMax - 1); + if (winPos < next2 && next2 < next) + next = next2; + */ + } + size = next - winPos; + } + + // note: ZstdDec_DecodeBlock() uses (winLimit = winPos + size) only for RLE and RAW blocks + res = ZstdDec_DecodeBlock(dec, p, size); + /* + after one block decoding: + if (!outBuf_fromCaller && isCyclicMode && cycSize != 0) + then (winPos < cycSize + max_block_size) + else (winPos <= cycSize) + */ + + if (!p->outBuf_fromCaller) + p->win = dec->decoder.win; + p->winPos = dec->decoder.winPos; + + // outProcessed = dec->decoder.winPos - winPos; + // p->outProcessed += outProcessed; + + if (res != SZ_OK) + return res; + + if (dec->frameState != ZSTD2_STATE_AFTER_HEADER) + { + if (p->outBuf_fromCaller) + return SZ_OK; + { + // !p->outBuf_fromCaller + /* + if (ZSTD_STATUS_FINISHED_FRAME), we request full flushing here because + 1) it's simpler to work with allocation and extracting of next frame, + 2) it's better to start writing to next new frame with aligned memory + for faster xxh 64-bit reads. + */ + size_t end = dec->decoder.winPos; // end pos for all data flushing + if (p->status != ZSTD_STATUS_FINISHED_FRAME) + { + // we will request flush here only for cases when wrap in cyclic buffer can be required in next call. + if (!dec->isCyclicMode) + return SZ_OK; + // isCyclicMode + { + const size_t delta = dec->decoder.cycSize; + if (end < delta) + return SZ_OK; // (winPos < cycSize). no need for flush + // cycSize <= winPos + // So we ask the caller to flush of (cycSize - wrPos) bytes, + // and then we will wrap cylicBuffer in next call + end = delta; + } + } + p->needWrite_Size = end - p->wrPos; + } + return SZ_OK; + } + + // ZSTD2_STATE_AFTER_HEADER + { + BoolInt useCyclic = False; + size_t cycSize; + + // p->status = ZSTD_STATUS_NOT_FINISHED; + if (dec->dictionaryId != 0) + { + /* actually we can try to decode some data, + because it's possible that some data doesn't use dictionary */ + // p->status = ZSTD_STATUS_NOT_SPECIFIED; + return SZ_ERROR_UNSUPPORTED; + } + + { + UInt64 winSize = dec->contentSize; + UInt64 winSize_Allocate = winSize; + const unsigned descriptor = dec->descriptor; + + if ((descriptor & DESCRIPTOR_FLAG_SINGLE) == 0) + { + const Byte wd = dec->windowDescriptor; + winSize = (UInt64)(8 + (wd & 7)) << ((wd >> 3) + 10 - 3); + if (!DESCRIPTOR_Is_ContentSize_Defined(descriptor) + || winSize_Allocate > winSize) + { + winSize_Allocate = winSize; + useCyclic = True; + } + } + /* + else + { + if (p->info.singleSegment_ContentSize_MAX < winSize) + p->info.singleSegment_ContentSize_MAX = winSize; + // p->info.num_SingleSegments++; + } + */ + if (p->info.windowSize_MAX < winSize) + p->info.windowSize_MAX = winSize; + if (p->info.windowSize_Allocate_MAX < winSize_Allocate) + p->info.windowSize_Allocate_MAX = winSize_Allocate; + /* + winSize_Allocate is MIN(content_size, window_size_from_descriptor). + Wven if (content_size < (window_size_from_descriptor)) + original-zstd still uses (window_size_from_descriptor) to check that decoding is allowed. + We try to follow original-zstd, and here we check (winSize) instead of (winSize_Allocate)) + */ + if ( + // winSize_Allocate // it's relaxed check + winSize // it's more strict check to be compatible with original-zstd + > ((UInt64)1 << MAX_WINDOW_SIZE_LOG)) + return SZ_ERROR_UNSUPPORTED; // SZ_ERROR_MEM + cycSize = (size_t)winSize_Allocate; + if (cycSize != winSize_Allocate) + return SZ_ERROR_MEM; + // cycSize <= winSize + /* later we will use (CZstdDec1::winSize) to check match offsets and check block sizes. + if (there is window descriptor) + { + We will check block size with (window_size_from_descriptor) instead of (winSize_Allocate). + Does original-zstd do it that way also? + } + Here we must reduce full real 64-bit (winSize) to size_t for (CZstdDec1::winSize). + Also we don't want too big values for (CZstdDec1::winSize). + our (CZstdDec1::winSize) will meet the condition: + (CZstdDec1::winSize < kBlockSizeMax || CZstdDec1::winSize <= cycSize). + */ + dec->decoder.winSize = (winSize < kBlockSizeMax) ? (size_t)winSize: cycSize; + // note: (CZstdDec1::winSize > cycSize) is possible, if (!useCyclic) + } + + RINOK(ZstdDec_AllocateMisc(dec)) + + if (p->outBuf_fromCaller) + dec->isCyclicMode = False; + else + { + size_t d = cycSize; + + if (dec->decoder.winPos != p->wrPos) + return SZ_ERROR_FAIL; + + dec->decoder.winPos = 0; + p->wrPos = 0; + p->winPos = dec->decoder.winPos; + + /* + const size_t needWrite = dec->decoder.winPos - p->wrPos; + if (!needWrite) + { + dec->decoder.winPos = 0; + p->wrPos = 0; + p->winPos = dec->decoder.winPos; + } + */ + /* if (!useCyclic) we allocate only cycSize = ContentSize. + But if we want to support the case where new frame starts with winPos != 0, + then we will wrap over zero, and we still need + to set (useCyclic) and allocate additional buffer spaces. + Now we don't allow new frame starting with (winPos != 0). + so (dec->decoder->winPos == 0) + can use (!useCyclic) with reduced buffer sizes. + */ + /* + if (dec->decoder->winPos != 0) + useCyclic = True; + */ + + if (useCyclic) + { + /* cyclyc buffer size must be at least (COPY_CHUNK_SIZE - 1) bytes + larger than window size, because CopyMatch() can write additional + (COPY_CHUNK_SIZE - 1) bytes and overwrite oldests data in cyclyc buffer. + But for performance reasons we align (cycSize) for (kBlockSizeMax). + also we must provide (cycSize >= max_decoded_data_after_cycSize), + because after data move wrapping over zero we must provide (winPos < cycSize). + */ + const size_t alignSize = kBlockSizeMax; + /* here we add (1 << 7) instead of (COPY_CHUNK_SIZE - 1), because + we want to get same (cycSize) for different COPY_CHUNK_SIZE values. */ + // cycSize += (COPY_CHUNK_SIZE - 1) + (alignSize - 1); // for debug : we can get smallest (cycSize) + cycSize += (1 << 7) + alignSize; + cycSize &= ~(size_t)(alignSize - 1); + // cycSize must be aligned for 32, because xxh requires 32-bytes blocks. + // cycSize += 12345; // for debug + // cycSize += 1 << 10; // for debug + // cycSize += 32; // for debug + // cycSize += kBlockSizeMax; // for debug + if (cycSize < d) + return SZ_ERROR_MEM; + /* + in cyclic buffer mode we allow to decode one additional block + that exceeds (cycSize). + So we must allocate additional (kBlockSizeMax) bytes after (cycSize). + if defined(Z7_STD_DEC_USE_AFTER_CYC_BUF) + { + we can read (COPY_CHUNK_SIZE - 1) bytes after (cycSize) + but we aready allocate additional kBlockSizeMax that + is larger than COPY_CHUNK_SIZE. + So we don't need additional space of COPY_CHUNK_SIZE after (cycSize). + } + */ + /* + #ifdef Z7_STD_DEC_USE_AFTER_CYC_BUF + d = cycSize + (1 << 7); // we must add at least (COPY_CHUNK_SIZE - 1) + #endif + */ + d = cycSize + kBlockSizeMax; + if (d < cycSize) + return SZ_ERROR_MEM; + } + + { + const size_t kMinWinAllocSize = 1 << 12; + if (d < kMinWinAllocSize) + d = kMinWinAllocSize; + } + + if (d > dec->winBufSize_Allocated) + { + /* + if (needWrite) + { + p->needWrite_Size = needWrite; + return SZ_OK; + // return SZ_ERROR_FAIL; + } + */ + + if (dec->winBufSize_Allocated != 0) + { + const size_t k_extra = (useCyclic || d >= (1u << 20)) ? + 2 * kBlockSizeMax : 0; + unsigned i = useCyclic ? 17 : 12; + for (; i < sizeof(size_t) * 8; i++) + { + const size_t d2 = ((size_t)1 << i) + k_extra; + if (d2 >= d) + { + d = d2; + break; + } + } + } + // RINOK(ZstdDec_AllocateWindow(dec, d)) + ZstdDec_FreeWindow(dec); + dec->win_Base = (Byte *)ISzAlloc_Alloc(dec->alloc_Big, d); + if (!dec->win_Base) + return SZ_ERROR_MEM; + dec->decoder.win = dec->win_Base; + dec->winBufSize_Allocated = d; + } + /* + else + { + // for non-cyclycMode we want flush data, and set winPos = 0 + if (needWrite) + { + if (!useCyclic || dec->decoder.winPos >= cycSize) + { + p->needWrite_Size = needWrite; + return SZ_OK; + // return SZ_ERROR_FAIL; + } + } + } + */ + + dec->decoder.cycSize = cycSize; + p->win = dec->decoder.win; + // p->cycSize = dec->decoder.cycSize; + dec->isCyclicMode = (Byte)useCyclic; + } // (!p->outBuf_fromCaller) end + + // p->winPos = dec->decoder.winPos; + dec->frameState = ZSTD2_STATE_BLOCK; + // continue; + } // ZSTD2_STATE_AFTER_HEADER end + } +} + + +void ZstdDec_GetResInfo(const CZstdDec *dec, + const CZstdDecState *p, + SRes res, + CZstdDecResInfo *stat) +{ + // ZstdDecInfo_CLEAR(stat); + stat->extraSize = 0; + stat->is_NonFinishedFrame = False; + if (dec->frameState != ZSTD2_STATE_FINISHED) + { + if (dec->frameState == ZSTD2_STATE_SIGNATURE) + { + stat->extraSize = (Byte)dec->tempSize; + if (ZstdDecInfo_GET_NUM_FRAMES(&p->info) == 0) + res = SZ_ERROR_NO_ARCHIVE; + } + else + { + stat->is_NonFinishedFrame = True; + if (res == SZ_OK && p->status == ZSTD_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + } + } + stat->decode_SRes = res; +} + + +size_t ZstdDec_ReadUnusedFromInBuf( + CZstdDecHandle dec, + size_t afterDecoding_tempPos, + void *data, size_t size) +{ + size_t processed = 0; + if (dec->frameState == ZSTD2_STATE_SIGNATURE) + { + Byte *dest = (Byte *)data; + const size_t tempSize = dec->tempSize; + while (afterDecoding_tempPos < tempSize) + { + if (size == 0) + break; + size--; + *dest++ = dec->temp[afterDecoding_tempPos++]; + processed++; + } + } + return processed; +} + + +void ZstdDecState_Clear(CZstdDecState *p) +{ + memset(p, 0 , sizeof(*p)); +} diff --git a/C/ZstdDec.h b/C/ZstdDec.h index 631151061..cd2613183 100644 --- a/C/ZstdDec.h +++ b/C/ZstdDec.h @@ -1,173 +1,173 @@ -/* ZstdDec.h -- Zstd Decoder interfaces -2024-01-21 : Igor Pavlov : Public domain */ - -#ifndef ZIP7_INC_ZSTD_DEC_H -#define ZIP7_INC_ZSTD_DEC_H - -EXTERN_C_BEGIN - -typedef struct CZstdDec CZstdDec; -typedef CZstdDec * CZstdDecHandle; - -CZstdDecHandle ZstdDec_Create(ISzAllocPtr alloc_Small, ISzAllocPtr alloc_Big); -void ZstdDec_Destroy(CZstdDecHandle p); - -typedef enum -{ - ZSTD_STATUS_NOT_SPECIFIED, /* use main error code instead */ - ZSTD_STATUS_FINISHED_FRAME, /* data frame or skip frame was finished */ - ZSTD_STATUS_NOT_FINISHED, /* just finished non-empty block or unfinished RAW/RLE block */ - ZSTD_STATUS_NEEDS_MORE_INPUT, /* the callee needs more input bytes. It has more priority over ZSTD_STATUS_NOT_FINISHED */ - ZSTD_STATUS_OUT_REACHED /* is not finihed frame and ((outProcessed > outSize) || (outProcessed == outSize && unfinished RAW/RLE block) */ -} enum_ZstdStatus_Dummy; - -#define ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(p) \ - ((p)->status & ZSTD_STATUS_FINISHED_FRAME) -/* - ((p)->status == ZSTD_STATUS_NEEDS_MORE_INPUT || \ - (p)->status == ZSTD_STATUS_FINISHED_FRAME) -*/ - -typedef Byte enum_ZstdStatus; - - -void ZstdDec_Init(CZstdDecHandle p); - -typedef struct -{ - UInt64 num_Blocks; - Byte descriptor_OR; - Byte descriptor_NOT_OR; - Byte are_ContentSize_Unknown; - Byte windowDescriptor_MAX; - - // Byte are_ContentSize_Known; - // Byte are_SingleSegments; - // Byte are_WindowDescriptors; - Byte checksum_Defined; - // Byte are_Checksums; - // Byte are_Non_Checksums; - - // Byte are_DictionaryId; - Byte are_DictionaryId_Different; - - // Byte reserved[3]; - - UInt32 checksum; // checksum of last data frame - /// UInt32 dictionaryId_Cur; - UInt32 dictionaryId; // if there are non-zero dictionary IDs, then it's first dictionaryId - - UInt64 num_DataFrames; - UInt64 num_SkipFrames; - UInt64 skipFrames_Size; - UInt64 contentSize_Total; - UInt64 contentSize_MAX; - // UInt64 num_Checksums; - // UInt64 num_Non_Checksums; // frames without checksum - // UInt64 num_WindowDescriptors; - // UInt64 num_SingleSegments; - // UInt64 num_Frames_with_ContentSize; - // UInt64 num_Frames_without_ContentSize; - UInt64 windowSize_MAX; - UInt64 windowSize_Allocate_MAX; - // UInt64 num_DictionaryIds; - // UInt64 num_Blocks_forType[4]; - // UInt64 num_BlockBytes_forType[4]; - // UInt64 num_SingleSegments; - // UInt64 singleSegment_ContentSize_MAX; -} CZstdDecInfo; - -#define ZstdDecInfo_CLEAR(p) { memset(p, 0, sizeof(*(p))); } - -#define ZstdDecInfo_GET_NUM_FRAMES(p) ((p)->num_DataFrames + (p)->num_SkipFrames) - - -typedef struct CZstdDecState -{ - enum_ZstdStatus status; // out - Byte disableHash; - // Byte mustBeFinished; - Byte outSize_Defined; - // Byte isAfterSizeMode; - // UInt64 inProcessed; - // SRes codeRes; - // Byte needWrite_IsStrong; - - const Byte *inBuf; - size_t inPos; // in/out - size_t inLim; - - const Byte *win; // out - size_t winPos; // out - size_t wrPos; // in/out - // size_t cycSize; // out : if (!outBuf_fromCaller) - size_t needWrite_Size; // out - - Byte *outBuf_fromCaller; - size_t outBufSize_fromCaller; - /* (outBufSize_fromCaller >= full_uncompressed_size_of_all_frames) is required - for success decoding. - If outBufSize_fromCaller < full_uncompressed_size_of_all_frames), - decoding can give error message, because we decode per block basis. - */ - - // size_t outStep; - UInt64 outSize; // total in all frames - UInt64 outProcessed; // out decoded in all frames (it can be >= outSize) - - CZstdDecInfo info; -} CZstdDecState; - -void ZstdDecState_Clear(CZstdDecState *p); - -/* -ZstdDec_Decode() -return: - SZ_OK - no error - SZ_ERROR_DATA - Data Error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported method or method properties - SZ_ERROR_CRC - XXH hash Error - // SZ_ERROR_ARCHIVE - Headers error (not used now) -*/ -SRes ZstdDec_Decode(CZstdDecHandle dec, CZstdDecState *p); - -/* -ZstdDec_ReadUnusedFromInBuf(): -returns: the number of bytes that were read from InBuf -(*afterDecoding_tempPos) must be set to zero before first call of ZstdDec_ReadUnusedFromInBuf() -*/ -size_t ZstdDec_ReadUnusedFromInBuf( - CZstdDecHandle dec, - size_t afterDecoding_tempPos, // in/out - void *data, size_t size); - -typedef struct -{ - SRes decode_SRes; // error code of data decoding - Byte is_NonFinishedFrame; // there is unfinished decoding for data frame or skip frame - Byte extraSize; -} CZstdDecResInfo; - -/* -#define ZstdDecResInfo_CLEAR(p) \ -{ (p)->decode_SRes = 0; \ - (p)->is_NonFinishedFrame; \ - (p)->extraSize = 0; \ -} -// memset(p, 0, sizeof(*p)); -*/ - -/* -additional error codes for CZstdDecResInfo::decode_SRes: - SZ_ERROR_NO_ARCHIVE - is not zstd stream (no frames) - SZ_ERROR_INPUT_EOF - need more data in input stream -*/ -void ZstdDec_GetResInfo(const CZstdDec *dec, - const CZstdDecState *p, - SRes res, // it's result from ZstdDec_Decode() - CZstdDecResInfo *info); - -EXTERN_C_END - -#endif +/* ZstdDec.h -- Zstd Decoder interfaces +2024-01-21 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_ZSTD_DEC_H +#define ZIP7_INC_ZSTD_DEC_H + +EXTERN_C_BEGIN + +typedef struct CZstdDec CZstdDec; +typedef CZstdDec * CZstdDecHandle; + +CZstdDecHandle ZstdDec_Create(ISzAllocPtr alloc_Small, ISzAllocPtr alloc_Big); +void ZstdDec_Destroy(CZstdDecHandle p); + +typedef enum +{ + ZSTD_STATUS_NOT_SPECIFIED, /* use main error code instead */ + ZSTD_STATUS_FINISHED_FRAME, /* data frame or skip frame was finished */ + ZSTD_STATUS_NOT_FINISHED, /* just finished non-empty block or unfinished RAW/RLE block */ + ZSTD_STATUS_NEEDS_MORE_INPUT, /* the callee needs more input bytes. It has more priority over ZSTD_STATUS_NOT_FINISHED */ + ZSTD_STATUS_OUT_REACHED /* is not finihed frame and ((outProcessed > outSize) || (outProcessed == outSize && unfinished RAW/RLE block) */ +} enum_ZstdStatus_Dummy; + +#define ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(p) \ + ((p)->status & ZSTD_STATUS_FINISHED_FRAME) +/* + ((p)->status == ZSTD_STATUS_NEEDS_MORE_INPUT || \ + (p)->status == ZSTD_STATUS_FINISHED_FRAME) +*/ + +typedef Byte enum_ZstdStatus; + + +void ZstdDec_Init(CZstdDecHandle p); + +typedef struct +{ + UInt64 num_Blocks; + Byte descriptor_OR; + Byte descriptor_NOT_OR; + Byte are_ContentSize_Unknown; + Byte windowDescriptor_MAX; + + // Byte are_ContentSize_Known; + // Byte are_SingleSegments; + // Byte are_WindowDescriptors; + Byte checksum_Defined; + // Byte are_Checksums; + // Byte are_Non_Checksums; + + // Byte are_DictionaryId; + Byte are_DictionaryId_Different; + + // Byte reserved[3]; + + UInt32 checksum; // checksum of last data frame + /// UInt32 dictionaryId_Cur; + UInt32 dictionaryId; // if there are non-zero dictionary IDs, then it's first dictionaryId + + UInt64 num_DataFrames; + UInt64 num_SkipFrames; + UInt64 skipFrames_Size; + UInt64 contentSize_Total; + UInt64 contentSize_MAX; + // UInt64 num_Checksums; + // UInt64 num_Non_Checksums; // frames without checksum + // UInt64 num_WindowDescriptors; + // UInt64 num_SingleSegments; + // UInt64 num_Frames_with_ContentSize; + // UInt64 num_Frames_without_ContentSize; + UInt64 windowSize_MAX; + UInt64 windowSize_Allocate_MAX; + // UInt64 num_DictionaryIds; + // UInt64 num_Blocks_forType[4]; + // UInt64 num_BlockBytes_forType[4]; + // UInt64 num_SingleSegments; + // UInt64 singleSegment_ContentSize_MAX; +} CZstdDecInfo; + +#define ZstdDecInfo_CLEAR(p) { memset(p, 0, sizeof(*(p))); } + +#define ZstdDecInfo_GET_NUM_FRAMES(p) ((p)->num_DataFrames + (p)->num_SkipFrames) + + +typedef struct CZstdDecState +{ + enum_ZstdStatus status; // out + Byte disableHash; + // Byte mustBeFinished; + Byte outSize_Defined; + // Byte isAfterSizeMode; + // UInt64 inProcessed; + // SRes codeRes; + // Byte needWrite_IsStrong; + + const Byte *inBuf; + size_t inPos; // in/out + size_t inLim; + + const Byte *win; // out + size_t winPos; // out + size_t wrPos; // in/out + // size_t cycSize; // out : if (!outBuf_fromCaller) + size_t needWrite_Size; // out + + Byte *outBuf_fromCaller; + size_t outBufSize_fromCaller; + /* (outBufSize_fromCaller >= full_uncompressed_size_of_all_frames) is required + for success decoding. + If outBufSize_fromCaller < full_uncompressed_size_of_all_frames), + decoding can give error message, because we decode per block basis. + */ + + // size_t outStep; + UInt64 outSize; // total in all frames + UInt64 outProcessed; // out decoded in all frames (it can be >= outSize) + + CZstdDecInfo info; +} CZstdDecState; + +void ZstdDecState_Clear(CZstdDecState *p); + +/* +ZstdDec_Decode() +return: + SZ_OK - no error + SZ_ERROR_DATA - Data Error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported method or method properties + SZ_ERROR_CRC - XXH hash Error + // SZ_ERROR_ARCHIVE - Headers error (not used now) +*/ +SRes ZstdDec_Decode(CZstdDecHandle dec, CZstdDecState *p); + +/* +ZstdDec_ReadUnusedFromInBuf(): +returns: the number of bytes that were read from InBuf +(*afterDecoding_tempPos) must be set to zero before first call of ZstdDec_ReadUnusedFromInBuf() +*/ +size_t ZstdDec_ReadUnusedFromInBuf( + CZstdDecHandle dec, + size_t afterDecoding_tempPos, // in/out + void *data, size_t size); + +typedef struct +{ + SRes decode_SRes; // error code of data decoding + Byte is_NonFinishedFrame; // there is unfinished decoding for data frame or skip frame + Byte extraSize; +} CZstdDecResInfo; + +/* +#define ZstdDecResInfo_CLEAR(p) \ +{ (p)->decode_SRes = 0; \ + (p)->is_NonFinishedFrame; \ + (p)->extraSize = 0; \ +} +// memset(p, 0, sizeof(*p)); +*/ + +/* +additional error codes for CZstdDecResInfo::decode_SRes: + SZ_ERROR_NO_ARCHIVE - is not zstd stream (no frames) + SZ_ERROR_INPUT_EOF - need more data in input stream +*/ +void ZstdDec_GetResInfo(const CZstdDec *dec, + const CZstdDecState *p, + SRes res, // it's result from ZstdDec_Decode() + CZstdDecResInfo *info); + +EXTERN_C_END + +#endif diff --git a/C/var_clang.mak b/C/var_clang.mak index ee265698e..a6df26e77 100644 --- a/C/var_clang.mak +++ b/C/var_clang.mak @@ -1,11 +1,11 @@ -PLATFORM= -O=b/c -IS_X64= -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM= -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM= +O=b/c +IS_X64= +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM= +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/C/var_clang_arm64.mak b/C/var_clang_arm64.mak index b66ae2119..971101a04 100644 --- a/C/var_clang_arm64.mak +++ b/C/var_clang_arm64.mak @@ -1,12 +1,12 @@ -PLATFORM=arm64 -O=b/c_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64=1 -CROSS_COMPILE= -MY_ARCH= -USE_ASM=1 -ASM_FLAGS=-Wno-unused-macros -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=arm64 +O=b/c_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64=1 +CROSS_COMPILE= +MY_ARCH= +USE_ASM=1 +ASM_FLAGS=-Wno-unused-macros +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/C/var_clang_x64.mak b/C/var_clang_x64.mak index b35f0cca4..34e1b49c5 100644 --- a/C/var_clang_x64.mak +++ b/C/var_clang_x64.mak @@ -1,11 +1,11 @@ -PLATFORM=x64 -O=b/c_$(PLATFORM) -IS_X64=1 -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM=1 -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=x64 +O=b/c_$(PLATFORM) +IS_X64=1 +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM=1 +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/C/var_clang_x86.mak b/C/var_clang_x86.mak index d18f0ae12..bd2317c29 100644 --- a/C/var_clang_x86.mak +++ b/C/var_clang_x86.mak @@ -1,11 +1,11 @@ -PLATFORM=x86 -O=b/c_$(PLATFORM) -IS_X64= -IS_X86=1 -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-m32 -USE_ASM=1 -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=x86 +O=b/c_$(PLATFORM) +IS_X64= +IS_X86=1 +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-m32 +USE_ASM=1 +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/C/var_gcc.mak b/C/var_gcc.mak index 803c8de9d..664491cf2 100644 --- a/C/var_gcc.mak +++ b/C/var_gcc.mak @@ -1,12 +1,12 @@ -PLATFORM= -O=b/g -IS_X64= -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM= -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ - -# -march=armv8-a+crc+crypto +PLATFORM= +O=b/g +IS_X64= +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM= +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ + +# -march=armv8-a+crc+crypto diff --git a/C/var_gcc_arm64.mak b/C/var_gcc_arm64.mak index 562cfaa6d..4bbb687db 100644 --- a/C/var_gcc_arm64.mak +++ b/C/var_gcc_arm64.mak @@ -1,12 +1,12 @@ -PLATFORM=arm64 -O=b/g_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64=1 -CROSS_COMPILE= -MY_ARCH=-mtune=cortex-a53 -USE_ASM=1 -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ - -# -march=armv8-a+crc+crypto +PLATFORM=arm64 +O=b/g_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64=1 +CROSS_COMPILE= +MY_ARCH=-mtune=cortex-a53 +USE_ASM=1 +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ + +# -march=armv8-a+crc+crypto diff --git a/C/var_gcc_x64.mak b/C/var_gcc_x64.mak index 1b965b21b..1acf604f5 100644 --- a/C/var_gcc_x64.mak +++ b/C/var_gcc_x64.mak @@ -1,10 +1,10 @@ -PLATFORM=x64 -O=b/g_$(PLATFORM) -IS_X64=1 -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM=1 -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ +PLATFORM=x64 +O=b/g_$(PLATFORM) +IS_X64=1 +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM=1 +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ diff --git a/C/var_gcc_x86.mak b/C/var_gcc_x86.mak index 3adf4a84a..f0718ec71 100644 --- a/C/var_gcc_x86.mak +++ b/C/var_gcc_x86.mak @@ -1,10 +1,10 @@ -PLATFORM=x86 -O=b/g_$(PLATFORM) -IS_X64= -IS_X86=1 -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-m32 -USE_ASM=1 -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ +PLATFORM=x86 +O=b/g_$(PLATFORM) +IS_X64= +IS_X86=1 +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-m32 +USE_ASM=1 +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ diff --git a/C/var_mac_arm64.mak b/C/var_mac_arm64.mak index 0ba414230..adf5fa1d7 100644 --- a/C/var_mac_arm64.mak +++ b/C/var_mac_arm64.mak @@ -1,11 +1,11 @@ -PLATFORM=arm64 -O=b/m_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64=1 -CROSS_COMPILE= -MY_ARCH=-arch arm64 -USE_ASM=1 -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=arm64 +O=b/m_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64=1 +CROSS_COMPILE= +MY_ARCH=-arch arm64 +USE_ASM=1 +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/C/var_mac_x64.mak b/C/var_mac_x64.mak index 92b15c8b7..13d7aa7fe 100644 --- a/C/var_mac_x64.mak +++ b/C/var_mac_x64.mak @@ -1,11 +1,11 @@ -PLATFORM=x64 -O=b/m_$(PLATFORM) -IS_X64=1 -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-arch x86_64 -USE_ASM= -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=x64 +O=b/m_$(PLATFORM) +IS_X64=1 +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-arch x86_64 +USE_ASM= +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/C/warn_clang.mak b/C/warn_clang.mak index 8cd31c6aa..0d6446d21 100644 --- a/C/warn_clang.mak +++ b/C/warn_clang.mak @@ -1 +1 @@ -CFLAGS_WARN = -Weverything -Wfatal-errors +CFLAGS_WARN = -Weverything -Wfatal-errors diff --git a/C/warn_clang_mac.mak b/C/warn_clang_mac.mak index 71df375c2..44afc5374 100644 --- a/C/warn_clang_mac.mak +++ b/C/warn_clang_mac.mak @@ -1 +1 @@ -CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories +CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories diff --git a/C/warn_gcc.mak b/C/warn_gcc.mak index 8fbdb28f6..7aab7a449 100644 --- a/C/warn_gcc.mak +++ b/C/warn_gcc.mak @@ -1,51 +1,51 @@ -CFLAGS_WARN_GCC_4_5 = \ - -CFLAGS_WARN_GCC_6 = \ - -Waddress \ - -Waggressive-loop-optimizations \ - -Wattributes \ - -Wbool-compare \ - -Wcast-align \ - -Wcomment \ - -Wdiv-by-zero \ - -Wduplicated-cond \ - -Wformat-contains-nul \ - -Winit-self \ - -Wint-to-pointer-cast \ - -Wunused \ - -Wunused-macros \ - -# -Wno-strict-aliasing - -CFLAGS_WARN_GCC_9 = \ - -Waddress \ - -Waddress-of-packed-member \ - -Waggressive-loop-optimizations \ - -Wattributes \ - -Wbool-compare \ - -Wbool-operation \ - -Wcast-align \ - -Wcast-align=strict \ - -Wcomment \ - -Wdangling-else \ - -Wdiv-by-zero \ - -Wduplicated-branches \ - -Wduplicated-cond \ - -Wformat-contains-nul \ - -Wimplicit-fallthrough=5 \ - -Winit-self \ - -Wint-in-bool-context \ - -Wint-to-pointer-cast \ - -Wunused \ - -Wunused-macros \ - -Wconversion \ - -# -Wno-sign-conversion \ - -CFLAGS_WARN_GCC_PPMD_UNALIGNED = \ - -Wno-strict-aliasing \ - - -CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) \ - -# $(CFLAGS_WARN_GCC_PPMD_UNALIGNED) +CFLAGS_WARN_GCC_4_5 = \ + +CFLAGS_WARN_GCC_6 = \ + -Waddress \ + -Waggressive-loop-optimizations \ + -Wattributes \ + -Wbool-compare \ + -Wcast-align \ + -Wcomment \ + -Wdiv-by-zero \ + -Wduplicated-cond \ + -Wformat-contains-nul \ + -Winit-self \ + -Wint-to-pointer-cast \ + -Wunused \ + -Wunused-macros \ + +# -Wno-strict-aliasing + +CFLAGS_WARN_GCC_9 = \ + -Waddress \ + -Waddress-of-packed-member \ + -Waggressive-loop-optimizations \ + -Wattributes \ + -Wbool-compare \ + -Wbool-operation \ + -Wcast-align \ + -Wcast-align=strict \ + -Wcomment \ + -Wdangling-else \ + -Wdiv-by-zero \ + -Wduplicated-branches \ + -Wduplicated-cond \ + -Wformat-contains-nul \ + -Wimplicit-fallthrough=5 \ + -Winit-self \ + -Wint-in-bool-context \ + -Wint-to-pointer-cast \ + -Wunused \ + -Wunused-macros \ + -Wconversion \ + +# -Wno-sign-conversion \ + +CFLAGS_WARN_GCC_PPMD_UNALIGNED = \ + -Wno-strict-aliasing \ + + +CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) \ + +# $(CFLAGS_WARN_GCC_PPMD_UNALIGNED) diff --git a/CPP/7zip/7zip.mak b/CPP/7zip/7zip.mak index 73791a1b0..8bf7e73e0 100644 --- a/CPP/7zip/7zip.mak +++ b/CPP/7zip/7zip.mak @@ -1,240 +1,240 @@ -OBJS = \ - $O\StdAfx.obj \ - $(CURRENT_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(WIN_CTRL_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(UI_COMMON_OBJS) \ - $(AGENT_OBJS) \ - $(CONSOLE_OBJS) \ - $(EXPLORER_OBJS) \ - $(FM_OBJS) \ - $(GUI_OBJS) \ - $(AR_COMMON_OBJS) \ - $(AR_OBJS) \ - $(7Z_OBJS) \ - $(CAB_OBJS) \ - $(CHM_OBJS) \ - $(COM_OBJS) \ - $(ISO_OBJS) \ - $(NSIS_OBJS) \ - $(RAR_OBJS) \ - $(TAR_OBJS) \ - $(UDF_OBJS) \ - $(WIM_OBJS) \ - $(ZIP_OBJS) \ - $(COMPRESS_OBJS) \ - $(CRYPTO_OBJS) \ - $(C_OBJS) \ - $(ASM_OBJS) \ - $O\resource.res \ - -!include "../../../Build.mak" - -# MAK_SINGLE_FILE = 1 - -!IFDEF MAK_SINGLE_FILE - -!IFDEF CURRENT_OBJS -$(CURRENT_OBJS): ./$(*B).cpp - $(COMPL) -!ENDIF - - -!IFDEF COMMON_OBJS -$(COMMON_OBJS): ../../../Common/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF WIN_OBJS -$(WIN_OBJS): ../../../Windows/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF WIN_CTRL_OBJS -$(WIN_CTRL_OBJS): ../../../Windows/Control/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF 7ZIP_COMMON_OBJS -$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF AR_OBJS -$(AR_OBJS): ../../Archive/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF AR_COMMON_OBJS -$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF 7Z_OBJS -$(7Z_OBJS): ../../Archive/7z/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF CAB_OBJS -$(CAB_OBJS): ../../Archive/Cab/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF CHM_OBJS -$(CHM_OBJS): ../../Archive/Chm/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF COM_OBJS -$(COM_OBJS): ../../Archive/Com/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF ISO_OBJS -$(ISO_OBJS): ../../Archive/Iso/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF NSIS_OBJS -$(NSIS_OBJS): ../../Archive/Nsis/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF RAR_OBJS -$(RAR_OBJS): ../../Archive/Rar/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF TAR_OBJS -$(TAR_OBJS): ../../Archive/Tar/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF UDF_OBJS -$(UDF_OBJS): ../../Archive/Udf/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF WIM_OBJS -$(WIM_OBJS): ../../Archive/Wim/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF ZIP_OBJS -$(ZIP_OBJS): ../../Archive/Zip/$(*B).cpp - $(COMPL) $(ZIP_FLAGS) -!ENDIF - -!IFDEF COMPRESS_OBJS -$(COMPRESS_OBJS): ../../Compress/$(*B).cpp - $(COMPL_O2) -!ENDIF - -!IFDEF CRYPTO_OBJS -$(CRYPTO_OBJS): ../../Crypto/$(*B).cpp - $(COMPL_O2) -!ENDIF - -!IFDEF UI_COMMON_OBJS -$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF AGENT_OBJS -$(AGENT_OBJS): ../../UI/Agent/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF CONSOLE_OBJS -$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp - $(COMPL) $(CONSOLE_VARIANT_FLAGS) -!ENDIF - -!IFDEF EXPLORER_OBJS -$(EXPLORER_OBJS): ../../UI/Explorer/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF FM_OBJS -$(FM_OBJS): ../../UI/FileManager/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF GUI_OBJS -$(GUI_OBJS): ../../UI/GUI/$(*B).cpp - $(COMPL) -!ENDIF - -!IFDEF C_OBJS -$(C_OBJS): ../../../../C/$(*B).c - $(COMPL_O2) -!ENDIF - - -!ELSE - -{.}.cpp{$O}.obj:: - $(COMPLB) -{../../../Common}.cpp{$O}.obj:: - $(COMPLB) -{../../../Windows}.cpp{$O}.obj:: - $(COMPLB) -{../../../Windows/Control}.cpp{$O}.obj:: - $(COMPLB) -{../../Common}.cpp{$O}.obj:: - $(COMPLB) - -{../../UI/Common}.cpp{$O}.obj:: - $(COMPLB) -{../../UI/Agent}.cpp{$O}.obj:: - $(COMPLB) -{../../UI/Console}.cpp{$O}.obj:: - $(COMPLB) $(CONSOLE_VARIANT_FLAGS) -{../../UI/Explorer}.cpp{$O}.obj:: - $(COMPLB) -{../../UI/FileManager}.cpp{$O}.obj:: - $(COMPLB) -{../../UI/GUI}.cpp{$O}.obj:: - $(COMPLB) - - -{../../Archive}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Common}.cpp{$O}.obj:: - $(COMPLB) - -{../../Archive/7z}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Cab}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Chm}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Com}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Iso}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Nsis}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Rar}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Tar}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Udf}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Wim}.cpp{$O}.obj:: - $(COMPLB) -{../../Archive/Zip}.cpp{$O}.obj:: - $(COMPLB) $(ZIP_FLAGS) - -{../../Compress}.cpp{$O}.obj:: - $(COMPLB_O2) -{../../Crypto}.cpp{$O}.obj:: - $(COMPLB_O2) -{../../../../C}.c{$O}.obj:: - $(CCOMPLB) - -!ENDIF - -!include "Asm.mak" +OBJS = \ + $O\StdAfx.obj \ + $(CURRENT_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(WIN_CTRL_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(UI_COMMON_OBJS) \ + $(AGENT_OBJS) \ + $(CONSOLE_OBJS) \ + $(EXPLORER_OBJS) \ + $(FM_OBJS) \ + $(GUI_OBJS) \ + $(AR_COMMON_OBJS) \ + $(AR_OBJS) \ + $(7Z_OBJS) \ + $(CAB_OBJS) \ + $(CHM_OBJS) \ + $(COM_OBJS) \ + $(ISO_OBJS) \ + $(NSIS_OBJS) \ + $(RAR_OBJS) \ + $(TAR_OBJS) \ + $(UDF_OBJS) \ + $(WIM_OBJS) \ + $(ZIP_OBJS) \ + $(COMPRESS_OBJS) \ + $(CRYPTO_OBJS) \ + $(C_OBJS) \ + $(ASM_OBJS) \ + $O\resource.res \ + +!include "../../../Build.mak" + +# MAK_SINGLE_FILE = 1 + +!IFDEF MAK_SINGLE_FILE + +!IFDEF CURRENT_OBJS +$(CURRENT_OBJS): ./$(*B).cpp + $(COMPL) +!ENDIF + + +!IFDEF COMMON_OBJS +$(COMMON_OBJS): ../../../Common/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF WIN_OBJS +$(WIN_OBJS): ../../../Windows/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF WIN_CTRL_OBJS +$(WIN_CTRL_OBJS): ../../../Windows/Control/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF 7ZIP_COMMON_OBJS +$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF AR_OBJS +$(AR_OBJS): ../../Archive/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF AR_COMMON_OBJS +$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF 7Z_OBJS +$(7Z_OBJS): ../../Archive/7z/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF CAB_OBJS +$(CAB_OBJS): ../../Archive/Cab/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF CHM_OBJS +$(CHM_OBJS): ../../Archive/Chm/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF COM_OBJS +$(COM_OBJS): ../../Archive/Com/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF ISO_OBJS +$(ISO_OBJS): ../../Archive/Iso/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF NSIS_OBJS +$(NSIS_OBJS): ../../Archive/Nsis/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF RAR_OBJS +$(RAR_OBJS): ../../Archive/Rar/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF TAR_OBJS +$(TAR_OBJS): ../../Archive/Tar/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF UDF_OBJS +$(UDF_OBJS): ../../Archive/Udf/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF WIM_OBJS +$(WIM_OBJS): ../../Archive/Wim/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF ZIP_OBJS +$(ZIP_OBJS): ../../Archive/Zip/$(*B).cpp + $(COMPL) $(ZIP_FLAGS) +!ENDIF + +!IFDEF COMPRESS_OBJS +$(COMPRESS_OBJS): ../../Compress/$(*B).cpp + $(COMPL_O2) +!ENDIF + +!IFDEF CRYPTO_OBJS +$(CRYPTO_OBJS): ../../Crypto/$(*B).cpp + $(COMPL_O2) +!ENDIF + +!IFDEF UI_COMMON_OBJS +$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF AGENT_OBJS +$(AGENT_OBJS): ../../UI/Agent/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF CONSOLE_OBJS +$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp + $(COMPL) $(CONSOLE_VARIANT_FLAGS) +!ENDIF + +!IFDEF EXPLORER_OBJS +$(EXPLORER_OBJS): ../../UI/Explorer/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF FM_OBJS +$(FM_OBJS): ../../UI/FileManager/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF GUI_OBJS +$(GUI_OBJS): ../../UI/GUI/$(*B).cpp + $(COMPL) +!ENDIF + +!IFDEF C_OBJS +$(C_OBJS): ../../../../C/$(*B).c + $(COMPL_O2) +!ENDIF + + +!ELSE + +{.}.cpp{$O}.obj:: + $(COMPLB) +{../../../Common}.cpp{$O}.obj:: + $(COMPLB) +{../../../Windows}.cpp{$O}.obj:: + $(COMPLB) +{../../../Windows/Control}.cpp{$O}.obj:: + $(COMPLB) +{../../Common}.cpp{$O}.obj:: + $(COMPLB) + +{../../UI/Common}.cpp{$O}.obj:: + $(COMPLB) +{../../UI/Agent}.cpp{$O}.obj:: + $(COMPLB) +{../../UI/Console}.cpp{$O}.obj:: + $(COMPLB) $(CONSOLE_VARIANT_FLAGS) +{../../UI/Explorer}.cpp{$O}.obj:: + $(COMPLB) +{../../UI/FileManager}.cpp{$O}.obj:: + $(COMPLB) +{../../UI/GUI}.cpp{$O}.obj:: + $(COMPLB) + + +{../../Archive}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Common}.cpp{$O}.obj:: + $(COMPLB) + +{../../Archive/7z}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Cab}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Chm}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Com}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Iso}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Nsis}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Rar}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Tar}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Udf}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Wim}.cpp{$O}.obj:: + $(COMPLB) +{../../Archive/Zip}.cpp{$O}.obj:: + $(COMPLB) $(ZIP_FLAGS) + +{../../Compress}.cpp{$O}.obj:: + $(COMPLB_O2) +{../../Crypto}.cpp{$O}.obj:: + $(COMPLB_O2) +{../../../../C}.c{$O}.obj:: + $(CCOMPLB) + +!ENDIF + +!include "Asm.mak" diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak index 1a660038b..bcb06a0ca 100644 --- a/CPP/7zip/7zip_gcc.mak +++ b/CPP/7zip/7zip_gcc.mak @@ -1,1352 +1,1368 @@ -# USE_CLANG=1 -# USE_ASM = 1 -# IS_X64 = 1 -# MY_ARCH = -# USE_ASM= -# USE_JWASM=1 - -MY_ARCH_2 = $(MY_ARCH) - -MY_ASM = asmc -ifdef USE_JWASM -MY_ASM = jwasm -endif - -ifndef RC -RC=windres.exe --target=pe-x86-64 -RC=windres.exe -F pe-i386 -RC=windres.exe -endif - - -PROGPATH = $(O)/$(PROG) -PROGPATH_STATIC = $(O)/$(PROG)s - - -ifneq ($(CC), xlc) -CFLAGS_WARN_WALL = -Werror -Wall -Wextra -endif - -# for object file -# -Wa,-aln=test.s -# -save-temps -FLAGS_BASE = -mbranch-protection=standard -march=armv8.5-a -FLAGS_BASE = -mbranch-protection=standard -FLAGS_BASE = -# FLAGS_BASE = -DZ7_NO_UNICODE - -CFLAGS_BASE_LIST = -c - - -#DEBUG_BUILD=1 - -ifdef DEBUG_BUILD -CFLAGS_DEBUG = -g -else -CFLAGS_DEBUG = -DNDEBUG -ifneq ($(CC), $(CROSS_COMPILE)clang) -LFLAGS_STRIP = -s -endif -endif - -# CFLAGS_BASE_LIST = -S -CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \ - $(CFLAGS_DEBUG) -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ - -fPIC - -FLAGS_FLTO = -ffunction-sections -FLAGS_FLTO = -flto -FLAGS_FLTO = $(FLAGS_BASE) -# -DZ7_AFFINITY_DISABLE - - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -ifdef IS_MINGW -LDFLAGS_STATIC_2 = -static -else -ifndef DEF_FILE -ifndef IS_NOT_STANDALONE -ifndef MY_DYNAMIC_LINK -ifneq ($(CC), clang) -LDFLAGS_STATIC_2 = -# -static -# -static-libstdc++ -static-libgcc -endif -endif -endif -endif -endif - -LDFLAGS_STATIC = $(CFLAGS_DEBUG) $(LDFLAGS_STATIC_2) $(LDFLAGS_STATIC_3) - -ifndef O - ifdef IS_MINGW - O=_o - else - O=_o - endif -endif - - -ifdef DEF_FILE - - -ifdef IS_MINGW -SHARED_EXT=.dll -LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC) -else -SHARED_EXT=.so -LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC) -CC_SHARED=-fPIC -endif - - -else - -LDFLAGS = $(LDFLAGS_STATIC) -# -z force-bti -# -s is not required for clang, do we need it for GCC ??? - -#-static -static-libgcc -static-libstdc++ - -ifdef IS_MINGW -SHARED_EXT=.exe -else -SHARED_EXT= -endif - -endif - - -PROGPATH = $(O)/$(PROG)$(SHARED_EXT) -PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT) - -ifdef IS_MINGW - -ifdef MSYSTEM -RM = rm -f -MY_MKDIR=mkdir -p -DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) -LIB_HTMLHELP=-lhtmlhelp -else -RM = del -MY_MKDIR=mkdir -DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll -endif - -LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 -lShell32 $(LIB_HTMLHELP) -LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) - -# v24.00: -DUNICODE and -D_UNICODE are defined in precompilation header files -# CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE -# -Wno-delete-non-virtual-dtor - - -else - -RM = rm -f -MY_MKDIR=mkdir -p -DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) - -# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST -# CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE - -# LOCAL_LIBS=-lpthread -# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl -LIB2 = -lpthread -LIB2 = -lpthread -ldl - - -endif - - - -CFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(FLAGS_FLTO) $(CC_SHARED) -o $@ - - -ifdef IS_MINGW - -ifdef IS_X64 -AFLAGS_ABI = -win64 -else -AFLAGS_ABI = -coff -DABI_CDECL -# -DABI_CDECL -# -DABI_LINUX -# -DABI_CDECL -endif -AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $(/dev/null && echo -z noexecstack || echo) -endif - -endif - - -LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(LFLAGS_NOEXECSTACK) $(OBJS) $(MY_LIBS) $(LIB2) - -# -s : GCC : Remove all symbol table and relocation information from the executable. -# -s : CLANG : unsupported -# -s - -$(PROGPATH): $(OBJS) - $(CXX) -o $(PROGPATH) $(LFLAGS_ALL) - -$(PROGPATH_STATIC): $(OBJS) - $(CXX) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL) - -# -s strips debug sections from executable in GCC - - - - -ifndef NO_DEFAULT_RES -$O/resource.o: resource.rc - $(RC) $(RFLAGS) resource.rc $@ - -# windres.exe : in old version mingw: -# $(RFLAGS) resource.rc $O/resource.o -# windres.exe : in new version mingw: -# $(RC) $(RFLAGS) resource.rc -FO $@ - - -endif - -$O/LzmaAlone.o: LzmaAlone.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/CommandLineParser.o: ../../../Common/CommandLineParser.cpp - $(CXX) $(CXXFLAGS) $< -$O/CRC.o: ../../../Common/CRC.cpp - $(CXX) $(CXXFLAGS) $< - -$O/CrcReg.o: ../../../Common/CrcReg.cpp - $(CXX) $(CXXFLAGS) $< - -$O/DynLimBuf.o: ../../../Common/DynLimBuf.cpp - $(CXX) $(CXXFLAGS) $< -$O/IntToString.o: ../../../Common/IntToString.cpp - $(CXX) $(CXXFLAGS) $< -$O/Lang.o: ../../../Common/Lang.cpp - $(CXX) $(CXXFLAGS) $< -$O/ListFileUtils.o: ../../../Common/ListFileUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzFindPrepare.o: ../../../Common/LzFindPrepare.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyMap.o: ../../../Common/MyMap.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyString.o: ../../../Common/MyString.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyVector.o: ../../../Common/MyVector.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyWindows.o: ../../../Common/MyWindows.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyWindows2.o: ../../../Common/MyWindows2.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyXml.o: ../../../Common/MyXml.cpp - $(CXX) $(CXXFLAGS) $< -$O/NewHandler.o: ../../../Common/NewHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/Random.o: ../../../Common/Random.cpp - $(CXX) $(CXXFLAGS) $< -$O/Sha1Prepare.o: ../../../Common/Sha1Prepare.cpp - $(CXX) $(CXXFLAGS) $< -$O/Sha1Reg.o: ../../../Common/Sha1Reg.cpp - $(CXX) $(CXXFLAGS) $< -$O/Sha256Prepare.o: ../../../Common/Sha256Prepare.cpp - $(CXX) $(CXXFLAGS) $< -$O/Sha256Reg.o: ../../../Common/Sha256Reg.cpp - $(CXX) $(CXXFLAGS) $< -$O/StdInStream.o: ../../../Common/StdInStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/StdOutStream.o: ../../../Common/StdOutStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/StringConvert.o: ../../../Common/StringConvert.cpp - $(CXX) $(CXXFLAGS) $< -$O/StringToInt.o: ../../../Common/StringToInt.cpp - $(CXX) $(CXXFLAGS) $< -$O/TextConfig.o: ../../../Common/TextConfig.cpp - $(CXX) $(CXXFLAGS) $< -$O/UTFConvert.o: ../../../Common/UTFConvert.cpp - $(CXX) $(CXXFLAGS) $< -$O/Wildcard.o: ../../../Common/Wildcard.cpp - $(CXX) $(CXXFLAGS) $< -$O/XzCrc64Init.o: ../../../Common/XzCrc64Init.cpp - $(CXX) $(CXXFLAGS) $< -$O/XzCrc64Reg.o: ../../../Common/XzCrc64Reg.cpp - $(CXX) $(CXXFLAGS) $< -$O/Xxh64Reg.o: ../../../Common/Xxh64Reg.cpp - $(CXX) $(CXXFLAGS) $< - - - -$O/Clipboard.o: ../../../Windows/Clipboard.cpp - $(CXX) $(CXXFLAGS) $< -$O/COM.o: ../../../Windows/COM.cpp - $(CXX) $(CXXFLAGS) $< -$O/CommonDialog.o: ../../../Windows/CommonDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/Console.o: ../../../Windows/Console.cpp - $(CXX) $(CXXFLAGS) $< -$O/DLL.o: ../../../Windows/DLL.cpp - $(CXX) $(CXXFLAGS) $< -$O/ErrorMsg.o: ../../../Windows/ErrorMsg.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileDir.o: ../../../Windows/FileDir.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileFind.o: ../../../Windows/FileFind.cpp - $(CXX) $(CXXFLAGS) $< - -$O/FileIO.o: ../../../Windows/FileIO.cpp - $(CXX) $(CXXFLAGS) $< - -$O/FileLink.o: ../../../Windows/FileLink.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileMapping.o: ../../../Windows/FileMapping.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileName.o: ../../../Windows/FileName.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileSystem.o: ../../../Windows/FileSystem.cpp - $(CXX) $(CXXFLAGS) $< -$O/MemoryGlobal.o: ../../../Windows/MemoryGlobal.cpp - $(CXX) $(CXXFLAGS) $< -$O/MemoryLock.o: ../../../Windows/MemoryLock.cpp - $(CXX) $(CXXFLAGS) $< -$O/Menu.o: ../../../Windows/Menu.cpp - $(CXX) $(CXXFLAGS) $< -$O/NationalTime.o: ../../../Windows/NationalTime.cpp - $(CXX) $(CXXFLAGS) $< -$O/Net.o: ../../../Windows/Net.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProcessMessages.o: ../../../Windows/ProcessMessages.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProcessUtils.o: ../../../Windows/ProcessUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropVariant.o: ../../../Windows/PropVariant.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropVariantConv.o: ../../../Windows/PropVariantConv.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropVariantUtils.o: ../../../Windows/PropVariantUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/Registry.o: ../../../Windows/Registry.cpp - $(CXX) $(CXXFLAGS) $< -$O/ResourceString.o: ../../../Windows/ResourceString.cpp - $(CXX) $(CXXFLAGS) $< -$O/SecurityUtils.o: ../../../Windows/SecurityUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/Shell.o: ../../../Windows/Shell.cpp - $(CXX) $(CXXFLAGS) $< -$O/Synchronization.o: ../../../Windows/Synchronization.cpp - $(CXX) $(CXXFLAGS) $< -$O/System.o: ../../../Windows/System.cpp - $(CXX) $(CXXFLAGS) $< -$O/SystemInfo.o: ../../../Windows/SystemInfo.cpp - $(CXX) $(CXXFLAGS) $< -$O/TimeUtils.o: ../../../Windows/TimeUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/Window.o: ../../../Windows/Window.cpp - $(CXX) $(CXXFLAGS) $< - - - -$O/ComboBox.o: ../../../Windows/Control/ComboBox.cpp - $(CXX) $(CXXFLAGS) $< -$O/Dialog.o: ../../../Windows/Control/Dialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/ImageList.o: ../../../Windows/Control/ImageList.cpp - $(CXX) $(CXXFLAGS) $< -$O/ListView.o: ../../../Windows/Control/ListView.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropertyPage.o: ../../../Windows/Control/PropertyPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/Window2.o: ../../../Windows/Control/Window2.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/CreateCoder.o: ../../Common/CreateCoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/CWrappers.o: ../../Common/CWrappers.cpp - $(CXX) $(CXXFLAGS) $< -$O/FilePathAutoRename.o: ../../Common/FilePathAutoRename.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileStreams.o: ../../Common/FileStreams.cpp - $(CXX) $(CXXFLAGS) $< -$O/FilterCoder.o: ../../Common/FilterCoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/InBuffer.o: ../../Common/InBuffer.cpp - $(CXX) $(CXXFLAGS) $< -$O/InOutTempBuffer.o: ../../Common/InOutTempBuffer.cpp - $(CXX) $(CXXFLAGS) $< -$O/LimitedStreams.o: ../../Common/LimitedStreams.cpp - $(CXX) $(CXXFLAGS) $< -$O/LockedStream.o: ../../Common/LockedStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/MemBlocks.o: ../../Common/MemBlocks.cpp - $(CXX) $(CXXFLAGS) $< -$O/MethodId.o: ../../Common/MethodId.cpp - $(CXX) $(CXXFLAGS) $< -$O/MethodProps.o: ../../Common/MethodProps.cpp - $(CXX) $(CXXFLAGS) $< -$O/MultiOutStream.o: ../../Common/MultiOutStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/OffsetStream.o: ../../Common/OffsetStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/OutBuffer.o: ../../Common/OutBuffer.cpp - $(CXX) $(CXXFLAGS) $< -$O/OutMemStream.o: ../../Common/OutMemStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProgressMt.o: ../../Common/ProgressMt.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProgressUtils.o: ../../Common/ProgressUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropId.o: ../../Common/PropId.cpp - $(CXX) $(CXXFLAGS) $< -$O/StreamBinder.o: ../../Common/StreamBinder.cpp - $(CXX) $(CXXFLAGS) $< -$O/StreamObjects.o: ../../Common/StreamObjects.cpp - $(CXX) $(CXXFLAGS) $< -$O/StreamUtils.o: ../../Common/StreamUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/UniqBlocks.o: ../../Common/UniqBlocks.cpp - $(CXX) $(CXXFLAGS) $< -$O/VirtThread.o: ../../Common/VirtThread.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/ApfsHandler.o: ../../Archive/ApfsHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ApmHandler.o: ../../Archive/ApmHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArHandler.o: ../../Archive/ArHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArjHandler.o: ../../Archive/ArjHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/AvbHandler.o: ../../Archive/AvbHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/Base64Handler.o: ../../Archive/Base64Handler.cpp - $(CXX) $(CXXFLAGS) $< -$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ComHandler.o: ../../Archive/ComHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/CpioHandler.o: ../../Archive/CpioHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/CramfsHandler.o: ../../Archive/CramfsHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/DeflateProps.o: ../../Archive/DeflateProps.cpp - $(CXX) $(CXXFLAGS) $< -$O/DllExports.o: ../../Archive/DllExports.cpp - $(CXX) $(CXXFLAGS) $< -$O/DllExports2.o: ../../Archive/DllExports2.cpp - $(CXX) $(CXXFLAGS) $< -$O/DmgHandler.o: ../../Archive/DmgHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ElfHandler.o: ../../Archive/ElfHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ExtHandler.o: ../../Archive/ExtHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/FatHandler.o: ../../Archive/FatHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/FlvHandler.o: ../../Archive/FlvHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/GptHandler.o: ../../Archive/GptHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/GzHandler.o: ../../Archive/GzHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/HandlerCont.o: ../../Archive/HandlerCont.cpp - $(CXX) $(CXXFLAGS) $< -$O/HfsHandler.o: ../../Archive/HfsHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/IhexHandler.o: ../../Archive/IhexHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/LpHandler.o: ../../Archive/LpHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/LvmHandler.o: ../../Archive/LvmHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzhHandler.o: ../../Archive/LzhHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/MachoHandler.o: ../../Archive/MachoHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/MbrHandler.o: ../../Archive/MbrHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/MslzHandler.o: ../../Archive/MslzHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/MubHandler.o: ../../Archive/MubHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/NtfsHandler.o: ../../Archive/NtfsHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/PeHandler.o: ../../Archive/PeHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/PpmdHandler.o: ../../Archive/PpmdHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/QcowHandler.o: ../../Archive/QcowHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/RpmHandler.o: ../../Archive/RpmHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/SparseHandler.o: ../../Archive/SparseHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/SplitHandler.o: ../../Archive/SplitHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/SwfHandler.o: ../../Archive/SwfHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/UefiHandler.o: ../../Archive/UefiHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/VdiHandler.o: ../../Archive/VdiHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/VhdHandler.o: ../../Archive/VhdHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/VhdxHandler.o: ../../Archive/VhdxHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/VmdkHandler.o: ../../Archive/VmdkHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/XarHandler.o: ../../Archive/XarHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/XzHandler.o: ../../Archive/XzHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZHandler.o: ../../Archive/ZHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZstdHandler.o: ../../Archive/ZstdHandler.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/7zCompressionMode.o: ../../Archive/7z/7zCompressionMode.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zDecode.o: ../../Archive/7z/7zDecode.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zEncode.o: ../../Archive/7z/7zEncode.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zExtract.o: ../../Archive/7z/7zExtract.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zFolderInStream.o: ../../Archive/7z/7zFolderInStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zHandler.o: ../../Archive/7z/7zHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zHandlerOut.o: ../../Archive/7z/7zHandlerOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zHeader.o: ../../Archive/7z/7zHeader.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zIn.o: ../../Archive/7z/7zIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zOut.o: ../../Archive/7z/7zOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zProperties.o: ../../Archive/7z/7zProperties.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zRegister.o: ../../Archive/7z/7zRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zSpecStream.o: ../../Archive/7z/7zSpecStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zUpdate.o: ../../Archive/7z/7zUpdate.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/CabBlockInStream.o: ../../Archive/Cab/CabBlockInStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/CabHandler.o: ../../Archive/Cab/CabHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/CabHeader.o: ../../Archive/Cab/CabHeader.cpp - $(CXX) $(CXXFLAGS) $< -$O/CabIn.o: ../../Archive/Cab/CabIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/CabRegister.o: ../../Archive/Cab/CabRegister.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/ChmHandler.o: ../../Archive/Chm/ChmHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/ChmIn.o: ../../Archive/Chm/ChmIn.cpp - $(CXX) $(CXXFLAGS) $< - -$O/IsoHandler.o: ../../Archive/Iso/IsoHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/IsoHeader.o: ../../Archive/Iso/IsoHeader.cpp - $(CXX) $(CXXFLAGS) $< -$O/IsoIn.o: ../../Archive/Iso/IsoIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/IsoRegister.o: ../../Archive/Iso/IsoRegister.cpp - $(CXX) $(CXXFLAGS) $< - -$O/NsisDecode.o: ../../Archive/Nsis/NsisDecode.cpp - $(CXX) $(CXXFLAGS) $< -$O/NsisHandler.o: ../../Archive/Nsis/NsisHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/NsisIn.o: ../../Archive/Nsis/NsisIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/NsisRegister.o: ../../Archive/Nsis/NsisRegister.cpp - $(CXX) $(CXXFLAGS) $< - -$O/Rar5Handler.o: ../../Archive/Rar/Rar5Handler.cpp - $(CXX) $(CXXFLAGS) $< -$O/RarHandler.o: ../../Archive/Rar/RarHandler.cpp - $(CXX) $(CXXFLAGS) $< - -$O/TarHandler.o: ../../Archive/Tar/TarHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/TarHandlerOut.o: ../../Archive/Tar/TarHandlerOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/TarHeader.o: ../../Archive/Tar/TarHeader.cpp - $(CXX) $(CXXFLAGS) $< -$O/TarIn.o: ../../Archive/Tar/TarIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/TarOut.o: ../../Archive/Tar/TarOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/TarRegister.o: ../../Archive/Tar/TarRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/TarUpdate.o: ../../Archive/Tar/TarUpdate.cpp - $(CXX) $(CXXFLAGS) $< - -$O/UdfHandler.o: ../../Archive/Udf/UdfHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/UdfIn.o: ../../Archive/Udf/UdfIn.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/WimHandler.o: ../../Archive/Wim/WimHandler.cpp - $(CXX) $(CXXFLAGS) $< -$O/WimHandlerOut.o: ../../Archive/Wim/WimHandlerOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/WimIn.o: ../../Archive/Wim/WimIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/WimRegister.o: ../../Archive/Wim/WimRegister.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/ZipAddCommon.o: ../../Archive/Zip/ZipAddCommon.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipHandler.o: ../../Archive/Zip/ZipHandler.cpp - $(CXX) $(CXXFLAGS) $(ZIP_FLAGS) $< -$O/ZipHandlerOut.o: ../../Archive/Zip/ZipHandlerOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipIn.o: ../../Archive/Zip/ZipIn.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipItem.o: ../../Archive/Zip/ZipItem.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipOut.o: ../../Archive/Zip/ZipOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipUpdate.o: ../../Archive/Zip/ZipUpdate.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipRegister.o: ../../Archive/Zip/ZipRegister.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/Bcj2Coder.o: ../../Compress/Bcj2Coder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Bcj2Register.o: ../../Compress/Bcj2Register.cpp - $(CXX) $(CXXFLAGS) $< -$O/BcjCoder.o: ../../Compress/BcjCoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/BcjRegister.o: ../../Compress/BcjRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/BitlDecoder.o: ../../Compress/BitlDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/BranchMisc.o: ../../Compress/BranchMisc.cpp - $(CXX) $(CXXFLAGS) $< -$O/BranchRegister.o: ../../Compress/BranchRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/ByteSwap.o: ../../Compress/ByteSwap.cpp - $(CXX) $(CXXFLAGS) $< -$O/BZip2Crc.o: ../../Compress/BZip2Crc.cpp - $(CXX) $(CXXFLAGS) $< -$O/BZip2Decoder.o: ../../Compress/BZip2Decoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/BZip2Encoder.o: ../../Compress/BZip2Encoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/BZip2Register.o: ../../Compress/BZip2Register.cpp - $(CXX) $(CXXFLAGS) $< -$O/CodecExports.o: ../../Compress/CodecExports.cpp - $(CXX) $(CXXFLAGS) $< -$O/CopyCoder.o: ../../Compress/CopyCoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/CopyRegister.o: ../../Compress/CopyRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/Deflate64Register.o: ../../Compress/Deflate64Register.cpp - $(CXX) $(CXXFLAGS) $< -$O/DeflateDecoder.o: ../../Compress/DeflateDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/DeflateEncoder.o: ../../Compress/DeflateEncoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/DeflateRegister.o: ../../Compress/DeflateRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/DeltaFilter.o: ../../Compress/DeltaFilter.cpp - $(CXX) $(CXXFLAGS) $< -$O/DllExports2Compress.o: ../../Compress/DllExports2Compress.cpp - $(CXX) $(CXXFLAGS) $< -$O/DllExportsCompress.o: ../../Compress/DllExportsCompress.cpp - $(CXX) $(CXXFLAGS) $< -$O/ImplodeDecoder.o: ../../Compress/ImplodeDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ImplodeHuffmanDecoder.o: ../../Compress/ImplodeHuffmanDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzfseDecoder.o: ../../Compress/LzfseDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzhDecoder.o: ../../Compress/LzhDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Lzma2Decoder.o: ../../Compress/Lzma2Decoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Lzma2Encoder.o: ../../Compress/Lzma2Encoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Lzma2Register.o: ../../Compress/Lzma2Register.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzmaDecoder.o: ../../Compress/LzmaDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzmaEncoder.o: ../../Compress/LzmaEncoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzmaRegister.o: ../../Compress/LzmaRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzmsDecoder.o: ../../Compress/LzmsDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzOutWindow.o: ../../Compress/LzOutWindow.cpp - $(CXX) $(CXXFLAGS) $< -$O/LzxDecoder.o: ../../Compress/LzxDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/PpmdDecoder.o: ../../Compress/PpmdDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/PpmdEncoder.o: ../../Compress/PpmdEncoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/PpmdRegister.o: ../../Compress/PpmdRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/PpmdZip.o: ../../Compress/PpmdZip.cpp - $(CXX) $(CXXFLAGS) $< -$O/QuantumDecoder.o: ../../Compress/QuantumDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar1Decoder.o: ../../Compress/Rar1Decoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar2Decoder.o: ../../Compress/Rar2Decoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar3Decoder.o: ../../Compress/Rar3Decoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar3Vm.o: ../../Compress/Rar3Vm.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar5Decoder.o: ../../Compress/Rar5Decoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/RarCodecsRegister.o: ../../Compress/RarCodecsRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/ShrinkDecoder.o: ../../Compress/ShrinkDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/XpressDecoder.o: ../../Compress/XpressDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/XzDecoder.o: ../../Compress/XzDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/XzEncoder.o: ../../Compress/XzEncoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZDecoder.o: ../../Compress/ZDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZlibDecoder.o: ../../Compress/ZlibDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZlibEncoder.o: ../../Compress/ZlibEncoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZstdDecoder.o: ../../Compress/ZstdDecoder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZstdRegister.o: ../../Compress/ZstdRegister.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/7zAes.o: ../../Crypto/7zAes.cpp - $(CXX) $(CXXFLAGS) $< -$O/7zAesRegister.o: ../../Crypto/7zAesRegister.cpp - $(CXX) $(CXXFLAGS) $< -$O/HmacSha1.o: ../../Crypto/HmacSha1.cpp - $(CXX) $(CXXFLAGS) $< -$O/HmacSha256.o: ../../Crypto/HmacSha256.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyAes.o: ../../Crypto/MyAes.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyAesReg.o: ../../Crypto/MyAesReg.cpp - $(CXX) $(CXXFLAGS) $< -$O/Pbkdf2HmacSha1.o: ../../Crypto/Pbkdf2HmacSha1.cpp - $(CXX) $(CXXFLAGS) $< -$O/RandGen.o: ../../Crypto/RandGen.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar20Crypto.o: ../../Crypto/Rar20Crypto.cpp - $(CXX) $(CXXFLAGS) $< -$O/Rar5Aes.o: ../../Crypto/Rar5Aes.cpp - $(CXX) $(CXXFLAGS) $< -$O/RarAes.o: ../../Crypto/RarAes.cpp - $(CXX) $(CXXFLAGS) $< -$O/WzAes.o: ../../Crypto/WzAes.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipCrypto.o: ../../Crypto/ZipCrypto.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipStrong.o: ../../Crypto/ZipStrong.cpp - $(CXX) $(CXXFLAGS) $< - - - -$O/CoderMixer2.o: ../../Archive/Common/CoderMixer2.cpp - $(CXX) $(CXXFLAGS) $< -$O/DummyOutStream.o: ../../Archive/Common/DummyOutStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/FindSignature.o: ../../Archive/Common/FindSignature.cpp - $(CXX) $(CXXFLAGS) $< -$O/HandlerOut.o: ../../Archive/Common/HandlerOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/InStreamWithCRC.o: ../../Archive/Common/InStreamWithCRC.cpp - $(CXX) $(CXXFLAGS) $< -$O/ItemNameUtils.o: ../../Archive/Common/ItemNameUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/MultiStream.o: ../../Archive/Common/MultiStream.cpp - $(CXX) $(CXXFLAGS) $< -$O/OutStreamWithCRC.o: ../../Archive/Common/OutStreamWithCRC.cpp - $(CXX) $(CXXFLAGS) $< -$O/OutStreamWithSha1.o: ../../Archive/Common/OutStreamWithSha1.cpp - $(CXX) $(CXXFLAGS) $< -$O/ParseProperties.o: ../../Archive/Common/ParseProperties.cpp - $(CXX) $(CXXFLAGS) $< - - - - -$O/ArchiveCommandLine.o: ../../UI/Common/ArchiveCommandLine.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveExtractCallback.o: ../../UI/Common/ArchiveExtractCallback.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveName.o: ../../UI/Common/ArchiveName.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveOpenCallback.o: ../../UI/Common/ArchiveOpenCallback.cpp - $(CXX) $(CXXFLAGS) $< -$O/Bench.o: ../../UI/Common/Bench.cpp - $(CXX) $(CXXFLAGS) $< -$O/CompressCall.o: ../../UI/Common/CompressCall.cpp - $(CXX) $(CXXFLAGS) $< -$O/CompressCall2.o: ../../UI/Common/CompressCall2.cpp - $(CXX) $(CXXFLAGS) $< -$O/DefaultName.o: ../../UI/Common/DefaultName.cpp - $(CXX) $(CXXFLAGS) $< -$O/EnumDirItems.o: ../../UI/Common/EnumDirItems.cpp - $(CXX) $(CXXFLAGS) $< -$O/Extract.o: ../../UI/Common/Extract.cpp - $(CXX) $(CXXFLAGS) $< -$O/ExtractingFilePath.o: ../../UI/Common/ExtractingFilePath.cpp - $(CXX) $(CXXFLAGS) $< -$O/HashCalc.o: ../../UI/Common/HashCalc.cpp - $(CXX) $(CXXFLAGS) $< -$O/LoadCodecs.o: ../../UI/Common/LoadCodecs.cpp - $(CXX) $(CXXFLAGS) $< -$O/OpenArchive.o: ../../UI/Common/OpenArchive.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropIDUtils.o: ../../UI/Common/PropIDUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/SetProperties.o: ../../UI/Common/SetProperties.cpp - $(CXX) $(CXXFLAGS) $< -$O/SortUtils.o: ../../UI/Common/SortUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/TempFiles.o: ../../UI/Common/TempFiles.cpp - $(CXX) $(CXXFLAGS) $< -$O/Update.o: ../../UI/Common/Update.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateAction.o: ../../UI/Common/UpdateAction.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateCallback.o: ../../UI/Common/UpdateCallback.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdatePair.o: ../../UI/Common/UpdatePair.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateProduce.o: ../../UI/Common/UpdateProduce.cpp - $(CXX) $(CXXFLAGS) $< -$O/WorkDir.o: ../../UI/Common/WorkDir.cpp - $(CXX) $(CXXFLAGS) $< -$O/ZipRegistry.o: ../../UI/Common/ZipRegistry.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/Agent.o: ../../UI/Agent/Agent.cpp - $(CXX) $(CXXFLAGS) $< -$O/AgentOut.o: ../../UI/Agent/AgentOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/AgentProxy.o: ../../UI/Agent/AgentProxy.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveFolder.o: ../../UI/Agent/ArchiveFolder.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveFolderOpen.o: ../../UI/Agent/ArchiveFolderOpen.cpp - $(CXX) $(CXXFLAGS) $< -$O/ArchiveFolderOut.o: ../../UI/Agent/ArchiveFolderOut.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateCallbackAgent.o: ../../UI/Agent/UpdateCallbackAgent.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/Client7z.o: ../../UI/Client7z/Client7z.cpp - $(CXX) $(CXXFLAGS) $< - - -$O/BenchCon.o: ../../UI/Console/BenchCon.cpp - $(CXX) $(CXXFLAGS) $< -$O/ConsoleClose.o: ../../UI/Console/ConsoleClose.cpp - $(CXX) $(CXXFLAGS) $< -$O/ExtractCallbackConsole.o: ../../UI/Console/ExtractCallbackConsole.cpp - $(CXX) $(CXXFLAGS) $< -$O/HashCon.o: ../../UI/Console/HashCon.cpp - $(CXX) $(CXXFLAGS) $< -$O/List.o: ../../UI/Console/List.cpp - $(CXX) $(CXXFLAGS) $< -$O/Main.o: ../../UI/Console/Main.cpp ../../../../C/7zVersion.h - $(CXX) $(CXXFLAGS) $(CONSOLE_VARIANT_FLAGS) $(CONSOLE_ASM_FLAGS) $< -$O/MainAr.o: ../../UI/Console/MainAr.cpp - $(CXX) $(CXXFLAGS) $< -$O/OpenCallbackConsole.o: ../../UI/Console/OpenCallbackConsole.cpp - $(CXX) $(CXXFLAGS) $< -$O/PercentPrinter.o: ../../UI/Console/PercentPrinter.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateCallbackConsole.o: ../../UI/Console/UpdateCallbackConsole.cpp - $(CXX) $(CXXFLAGS) $< -$O/UserInputUtils.o: ../../UI/Console/UserInputUtils.cpp - $(CXX) $(CXXFLAGS) $< - -$O/BenchmarkDialog.o: ../../UI/GUI/BenchmarkDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/CompressDialog.o: ../../UI/GUI/CompressDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/ExtractDialog.o: ../../UI/GUI/ExtractDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/ExtractGUI.o: ../../UI/GUI/ExtractGUI.cpp - $(CXX) $(CXXFLAGS) $< -$O/GUI.o: ../../UI/GUI/GUI.cpp - $(CXX) $(CXXFLAGS) $< -$O/HashGUI.o: ../../UI/GUI/HashGUI.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateCallbackGUI.o: ../../UI/GUI/UpdateCallbackGUI.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateCallbackGUI2.o: ../../UI/GUI/UpdateCallbackGUI2.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateGUI.o: ../../UI/GUI/UpdateGUI.cpp - $(CXX) $(CXXFLAGS) $< - -$O/MyMessages.o: ../../UI/Explorer/MyMessages.cpp - $(CXX) $(CXXFLAGS) $< -$O/ContextMenu.o: ../../UI/Explorer/ContextMenu.cpp - $(CXX) $(CXXFLAGS) $< -$O/DllExportsExplorer.o: ../../UI/Explorer/DllExportsExplorer.cpp - $(CXX) $(CXXFLAGS) $< -$O/RegistryContextMenu.o: ../../UI/Explorer/RegistryContextMenu.cpp - $(CXX) $(CXXFLAGS) $< - - - -$O/AboutDialog.o: ../../UI/FileManager/AboutDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/AltStreamsFolder.o: ../../UI/FileManager/AltStreamsFolder.cpp - $(CXX) $(CXXFLAGS) $< -$O/App.o: ../../UI/FileManager/App.cpp - $(CXX) $(CXXFLAGS) $< -$O/BrowseDialog.o: ../../UI/FileManager/BrowseDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/BrowseDialog2.o: ../../UI/FileManager/BrowseDialog2.cpp - $(CXX) $(CXXFLAGS) $< -$O/ClassDefs.o: ../../UI/FileManager/ClassDefs.cpp - $(CXX) $(CXXFLAGS) $< -$O/ComboDialog.o: ../../UI/FileManager/ComboDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/CopyDialog.o: ../../UI/FileManager/CopyDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/EditDialog.o: ../../UI/FileManager/EditDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/EditPage.o: ../../UI/FileManager/EditPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/EnumFormatEtc.o: ../../UI/FileManager/EnumFormatEtc.cpp - $(CXX) $(CXXFLAGS) $< -$O/ExtractCallback.o: ../../UI/FileManager/ExtractCallback.cpp - $(CXX) $(CXXFLAGS) $< -$O/FileFolderPluginOpen.o: ../../UI/FileManager/FileFolderPluginOpen.cpp - $(CXX) $(CXXFLAGS) $< -$O/FilePlugins.o: ../../UI/FileManager/FilePlugins.cpp - $(CXX) $(CXXFLAGS) $< -$O/FM.o: ../../UI/FileManager/FM.cpp - $(CXX) $(CXXFLAGS) $< -$O/FoldersPage.o: ../../UI/FileManager/FoldersPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/FormatUtils.o: ../../UI/FileManager/FormatUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/FSDrives.o: ../../UI/FileManager/FSDrives.cpp - $(CXX) $(CXXFLAGS) $< -$O/FSFolder.o: ../../UI/FileManager/FSFolder.cpp - $(CXX) $(CXXFLAGS) $< -$O/FSFolderCopy.o: ../../UI/FileManager/FSFolderCopy.cpp - $(CXX) $(CXXFLAGS) $< -$O/HelpUtils.o: ../../UI/FileManager/HelpUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/LangPage.o: ../../UI/FileManager/LangPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/LangUtils.o: ../../UI/FileManager/LangUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/LinkDialog.o: ../../UI/FileManager/LinkDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/ListViewDialog.o: ../../UI/FileManager/ListViewDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/MemDialog.o: ../../UI/FileManager/MemDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/MenuPage.o: ../../UI/FileManager/MenuPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/MessagesDialog.o: ../../UI/FileManager/MessagesDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/MyLoadMenu.o: ../../UI/FileManager/MyLoadMenu.cpp - $(CXX) $(CXXFLAGS) $< -$O/NetFolder.o: ../../UI/FileManager/NetFolder.cpp - $(CXX) $(CXXFLAGS) $< -$O/OpenCallback.o: ../../UI/FileManager/OpenCallback.cpp - $(CXX) $(CXXFLAGS) $< -$O/OptionsDialog.o: ../../UI/FileManager/OptionsDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/OverwriteDialog.o: ../../UI/FileManager/OverwriteDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/Panel.o: ../../UI/FileManager/Panel.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelCopy.o: ../../UI/FileManager/PanelCopy.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelCrc.o: ../../UI/FileManager/PanelCrc.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelDrag.o: ../../UI/FileManager/PanelDrag.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelFolderChange.o: ../../UI/FileManager/PanelFolderChange.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelItemOpen.o: ../../UI/FileManager/PanelItemOpen.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelItems.o: ../../UI/FileManager/PanelItems.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelKey.o: ../../UI/FileManager/PanelKey.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelListNotify.o: ../../UI/FileManager/PanelListNotify.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelMenu.o: ../../UI/FileManager/PanelMenu.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelOperations.o: ../../UI/FileManager/PanelOperations.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelSelect.o: ../../UI/FileManager/PanelSelect.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelSort.o: ../../UI/FileManager/PanelSort.cpp - $(CXX) $(CXXFLAGS) $< -$O/PanelSplitFile.o: ../../UI/FileManager/PanelSplitFile.cpp - $(CXX) $(CXXFLAGS) $< -$O/PasswordDialog.o: ../../UI/FileManager/PasswordDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProgramLocation.o: ../../UI/FileManager/ProgramLocation.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProgressDialog.o: ../../UI/FileManager/ProgressDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/ProgressDialog2.o: ../../UI/FileManager/ProgressDialog2.cpp - $(CXX) $(CXXFLAGS) $< -$O/PropertyName.o: ../../UI/FileManager/PropertyName.cpp - $(CXX) $(CXXFLAGS) $< -$O/RegistryAssociations.o: ../../UI/FileManager/RegistryAssociations.cpp - $(CXX) $(CXXFLAGS) $< -$O/RegistryPlugins.o: ../../UI/FileManager/RegistryPlugins.cpp - $(CXX) $(CXXFLAGS) $< -$O/RegistryUtils.o: ../../UI/FileManager/RegistryUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/RootFolder.o: ../../UI/FileManager/RootFolder.cpp - $(CXX) $(CXXFLAGS) $< -$O/SettingsPage.o: ../../UI/FileManager/SettingsPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/SplitDialog.o: ../../UI/FileManager/SplitDialog.cpp - $(CXX) $(CXXFLAGS) $< -$O/SplitUtils.o: ../../UI/FileManager/SplitUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/StringUtils.o: ../../UI/FileManager/StringUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/SysIconUtils.o: ../../UI/FileManager/SysIconUtils.cpp - $(CXX) $(CXXFLAGS) $< -$O/SystemPage.o: ../../UI/FileManager/SystemPage.cpp - $(CXX) $(CXXFLAGS) $< -$O/TextPairs.o: ../../UI/FileManager/TextPairs.cpp - $(CXX) $(CXXFLAGS) $< -$O/UpdateCallback100.o: ../../UI/FileManager/UpdateCallback100.cpp - $(CXX) $(CXXFLAGS) $< -$O/VerCtrl.o: ../../UI/FileManager/VerCtrl.cpp - $(CXX) $(CXXFLAGS) $< -$O/ViewSettings.o: ../../UI/FileManager/ViewSettings.cpp - $(CXX) $(CXXFLAGS) $< - -$O/SfxCon.o: ../../Bundles/SFXCon/SfxCon.cpp - $(CXX) $(CXXFLAGS) $< - -$O/$(FILE_IO).o: ../../../$(FILE_IO_2).cpp - $(CXX) $(CXXFLAGS) $< - - - - - - -$O/7zAlloc.o: ../../../../C/7zAlloc.c - $(CC) $(CFLAGS) $< -$O/7zArcIn.o: ../../../../C/7zArcIn.c - $(CC) $(CFLAGS) $< -$O/7zBuf.o: ../../../../C/7zBuf.c - $(CC) $(CFLAGS) $< -$O/7zBuf2.o: ../../../../C/7zBuf2.c - $(CC) $(CFLAGS) $< -$O/7zCrc.o: ../../../../C/7zCrc.c - $(CC) $(CFLAGS) $< -$O/7zDec.o: ../../../../C/7zDec.c - $(CC) $(CFLAGS) $< -$O/7zFile.o: ../../../../C/7zFile.c - $(CC) $(CFLAGS) $< -$O/7zStream.o: ../../../../C/7zStream.c - $(CC) $(CFLAGS) $< -$O/Aes.o: ../../../../C/Aes.c - $(CC) $(CFLAGS) $< -$O/Alloc.o: ../../../../C/Alloc.c - $(CC) $(CFLAGS) $< -$O/Bcj2.o: ../../../../C/Bcj2.c - $(CC) $(CFLAGS) $< -$O/Bcj2Enc.o: ../../../../C/Bcj2Enc.c - $(CC) $(CFLAGS) $< -$O/Blake2s.o: ../../../../C/Blake2s.c - $(CC) $(CFLAGS) $< -$O/Bra.o: ../../../../C/Bra.c - $(CC) $(CFLAGS) $< -$O/Bra86.o: ../../../../C/Bra86.c - $(CC) $(CFLAGS) $< -$O/BraIA64.o: ../../../../C/BraIA64.c - $(CC) $(CFLAGS) $< -$O/BwtSort.o: ../../../../C/BwtSort.c - $(CC) $(CFLAGS) $< - -$O/CpuArch.o: ../../../../C/CpuArch.c - $(CC) $(CFLAGS) $< -$O/Delta.o: ../../../../C/Delta.c - $(CC) $(CFLAGS) $< -$O/DllSecur.o: ../../../../C/DllSecur.c - $(CC) $(CFLAGS) $< -$O/HuffEnc.o: ../../../../C/HuffEnc.c - $(CC) $(CFLAGS) $< -$O/LzFind.o: ../../../../C/LzFind.c - $(CC) $(CFLAGS) $< - -# ifdef MT_FILES -$O/LzFindMt.o: ../../../../C/LzFindMt.c - $(CC) $(CFLAGS) $< - -$O/Threads.o: ../../../../C/Threads.c - $(CC) $(CFLAGS) $< -# endif - -$O/LzmaEnc.o: ../../../../C/LzmaEnc.c - $(CC) $(CFLAGS) $< -$O/Lzma86Dec.o: ../../../../C/Lzma86Dec.c - $(CC) $(CFLAGS) $< -$O/Lzma86Enc.o: ../../../../C/Lzma86Enc.c - $(CC) $(CFLAGS) $< -$O/Lzma2Dec.o: ../../../../C/Lzma2Dec.c - $(CC) $(CFLAGS) $< -$O/Lzma2DecMt.o: ../../../../C/Lzma2DecMt.c - $(CC) $(CFLAGS) $< -$O/Lzma2Enc.o: ../../../../C/Lzma2Enc.c - $(CC) $(CFLAGS) $< -$O/LzmaLib.o: ../../../../C/LzmaLib.c - $(CC) $(CFLAGS) $< -$O/MtCoder.o: ../../../../C/MtCoder.c - $(CC) $(CFLAGS) $< -$O/MtDec.o: ../../../../C/MtDec.c - $(CC) $(CFLAGS) $< -$O/Ppmd7.o: ../../../../C/Ppmd7.c - $(CC) $(CFLAGS) $< -$O/Ppmd7aDec.o: ../../../../C/Ppmd7aDec.c - $(CC) $(CFLAGS) $< -$O/Ppmd7Dec.o: ../../../../C/Ppmd7Dec.c - $(CC) $(CFLAGS) $< -$O/Ppmd7Enc.o: ../../../../C/Ppmd7Enc.c - $(CC) $(CFLAGS) $< -$O/Ppmd8.o: ../../../../C/Ppmd8.c - $(CC) $(CFLAGS) $< -$O/Ppmd8Dec.o: ../../../../C/Ppmd8Dec.c - $(CC) $(CFLAGS) $< -$O/Ppmd8Enc.o: ../../../../C/Ppmd8Enc.c - $(CC) $(CFLAGS) $< -$O/Sha1.o: ../../../../C/Sha1.c - $(CC) $(CFLAGS) $< -$O/Sha256.o: ../../../../C/Sha256.c - $(CC) $(CFLAGS) $< -$O/Sort.o: ../../../../C/Sort.c - $(CC) $(CFLAGS) $< -$O/SwapBytes.o: ../../../../C/SwapBytes.c - $(CC) $(CFLAGS) $< -$O/Xxh64.o: ../../../../C/Xxh64.c - $(CC) $(CFLAGS) $< -$O/Xz.o: ../../../../C/Xz.c - $(CC) $(CFLAGS) $< -$O/XzCrc64.o: ../../../../C/XzCrc64.c - $(CC) $(CFLAGS) $< -$O/XzDec.o: ../../../../C/XzDec.c - $(CC) $(CFLAGS) $< -$O/XzEnc.o: ../../../../C/XzEnc.c - $(CC) $(CFLAGS) $< -$O/XzIn.o: ../../../../C/XzIn.c - $(CC) $(CFLAGS) $< -$O/ZstdDec.o: ../../../../C/ZstdDec.c - $(CC) $(CFLAGS) $< - - -ifdef USE_ASM -ifdef IS_X64 -USE_X86_ASM=1 -USE_X64_ASM=1 -else -ifdef IS_X86 -USE_X86_ASM=1 -endif -endif -endif - -ifdef USE_X86_ASM -$O/7zCrcOpt.o: ../../../../Asm/x86/7zCrcOpt.asm - $(MY_ASM) $(AFLAGS) $< -$O/XzCrc64Opt.o: ../../../../Asm/x86/XzCrc64Opt.asm - $(MY_ASM) $(AFLAGS) $< -$O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm - $(MY_ASM) $(AFLAGS) $< -$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm - $(MY_ASM) $(AFLAGS) $< - -ifndef USE_JWASM -USE_X86_ASM_AES=1 -endif - -else -$O/7zCrcOpt.o: ../../../../C/7zCrcOpt.c - $(CC) $(CFLAGS) $< -$O/XzCrc64Opt.o: ../../../../C/XzCrc64Opt.c - $(CC) $(CFLAGS) $< -$O/Sha1Opt.o: ../../../../C/Sha1Opt.c - $(CC) $(CFLAGS) $< -$O/Sha256Opt.o: ../../../../C/Sha256Opt.c - $(CC) $(CFLAGS) $< -endif - - -ifdef USE_X86_ASM_AES -$O/AesOpt.o: ../../../../Asm/x86/AesOpt.asm - $(MY_ASM) $(AFLAGS) $< -else -$O/AesOpt.o: ../../../../C/AesOpt.c - $(CC) $(CFLAGS) $< -endif - - -ifdef USE_X64_ASM -$O/LzFindOpt.o: ../../../../Asm/x86/LzFindOpt.asm - $(MY_ASM) $(AFLAGS) $< -else -$O/LzFindOpt.o: ../../../../C/LzFindOpt.c - $(CC) $(CFLAGS) $< -endif - -ifdef USE_LZMA_DEC_ASM - -ifdef IS_X64 -$O/LzmaDecOpt.o: ../../../../Asm/x86/LzmaDecOpt.asm - $(MY_ASM) $(AFLAGS) $< -endif - -ifdef IS_ARM64 -$O/LzmaDecOpt.o: ../../../../Asm/arm64/LzmaDecOpt.S ../../../../Asm/arm64/7zAsm.S - $(CC) $(CFLAGS) $(ASM_FLAGS) $< -endif - -$O/LzmaDec.o: ../../../../C/LzmaDec.c - $(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $< - -else - -$O/LzmaDec.o: ../../../../C/LzmaDec.c - $(CC) $(CFLAGS) $< - -endif - - - - -$O/7zMain.o: ../../../../C/Util/7z/7zMain.c - $(CC) $(CFLAGS) $< -$O/LzmaUtil.o: ../../../../C/Util/Lzma/LzmaUtil.c - $(CC) $(CFLAGS) $< - -ifneq ($(CC), xlc) -SHOW_PREDEF=-dM -else -SHOW_PREDEF= -qshowmacros=pre -endif - -predef_cc: - $(CC) $(CFLAGS) -E $(SHOW_PREDEF) ../../../../C/CpuArch.c > predef_cc_log -# $(CC) $(CFLAGS) -E -dM - < /dev/null -predef_cxx: - $(CXX) $(CFLAGS) -E $(SHOW_PREDEF) ../../../Common/CrcReg.cpp > predef_cxx_log - -predef: predef_cc predef_cxx - - -clean: - -$(DEL_OBJ_EXE) +# USE_CLANG=1 +# USE_ASM = 1 +# IS_X64 = 1 +# MY_ARCH = +# USE_ASM= +# USE_JWASM=1 + +MY_ARCH_2 = $(MY_ARCH) + +MY_ASM = asmc +ifdef USE_JWASM +MY_ASM = jwasm +endif + +ifndef RC +RC=windres.exe --target=pe-x86-64 +RC=windres.exe -F pe-i386 +RC=windres.exe +endif + + +PROGPATH = $(O)/$(PROG) +PROGPATH_STATIC = $(O)/$(PROG)s + + +ifneq ($(CC), xlc) +CFLAGS_WARN_WALL = -Werror -Wall -Wextra +endif + +# for object file +# -Wa,-aln=test.s +# -save-temps +FLAGS_BASE = -mbranch-protection=standard -march=armv8.5-a +FLAGS_BASE = -mbranch-protection=standard +FLAGS_BASE = +# FLAGS_BASE = -DZ7_NO_UNICODE + +CFLAGS_BASE_LIST = -c + + +#DEBUG_BUILD=1 + +ifdef DEBUG_BUILD +CFLAGS_DEBUG = -g +else +CFLAGS_DEBUG = -DNDEBUG +ifneq ($(CC), $(CROSS_COMPILE)clang) +LFLAGS_STRIP = -s +endif +endif + +# CFLAGS_BASE_LIST = -S +CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \ + $(CFLAGS_DEBUG) -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ + -fPIC + +FLAGS_FLTO = -ffunction-sections +FLAGS_FLTO = -flto +FLAGS_FLTO = $(FLAGS_BASE) +# -DZ7_AFFINITY_DISABLE + + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef IS_MINGW +LDFLAGS_STATIC_2 = -static +else +ifndef DEF_FILE +ifndef IS_NOT_STANDALONE +ifndef MY_DYNAMIC_LINK +ifneq ($(CC), clang) +LDFLAGS_STATIC_2 = +# -static +# -static-libstdc++ -static-libgcc +endif +endif +endif +endif +endif + +LDFLAGS_STATIC = $(CFLAGS_DEBUG) $(LDFLAGS_STATIC_2) $(LDFLAGS_STATIC_3) + +ifndef O + ifdef IS_MINGW + O=_o + else + O=_o + endif +endif + + +ifdef DEF_FILE + + +ifdef IS_MINGW +SHARED_EXT=.dll +LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC) +else +SHARED_EXT=.so +LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC) +CC_SHARED=-fPIC +endif + + +else + +LDFLAGS = $(LDFLAGS_STATIC) +# -z force-bti +# -s is not required for clang, do we need it for GCC ??? + +#-static -static-libgcc -static-libstdc++ + +ifdef IS_MINGW +SHARED_EXT=.exe +else +SHARED_EXT= +endif + +endif + + +PROGPATH = $(O)/$(PROG)$(SHARED_EXT) +PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT) + +ifdef IS_MINGW + +ifdef MSYSTEM +RM = rm -f +MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) +LIB_HTMLHELP=-lhtmlhelp +else +RM = del +MY_MKDIR=mkdir +DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll +endif + +LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 -lShell32 $(LIB_HTMLHELP) +LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) + +# v24.00: -DUNICODE and -D_UNICODE are defined in precompilation header files +# CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE +# -Wno-delete-non-virtual-dtor + + +else + +RM = rm -f +MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) + +# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST +# CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + +# LOCAL_LIBS=-lpthread +# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl +LIB2 = -lpthread +LIB2 = -lpthread -ldl + + +endif + + + +CFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(FLAGS_FLTO) $(CC_SHARED) -o $@ + + +ifdef IS_MINGW + +ifdef IS_X64 +AFLAGS_ABI = -win64 +else +AFLAGS_ABI = -coff -DABI_CDECL +# -DABI_CDECL +# -DABI_LINUX +# -DABI_CDECL +endif +AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $(/dev/null && echo -z noexecstack || echo) +endif + +endif + + +LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(LFLAGS_NOEXECSTACK) $(OBJS) $(MY_LIBS) $(LIB2) + +# -s : GCC : Remove all symbol table and relocation information from the executable. +# -s : CLANG : unsupported +# -s + +$(PROGPATH): $(OBJS) + $(CXX) -o $(PROGPATH) $(LFLAGS_ALL) + +$(PROGPATH_STATIC): $(OBJS) + $(CXX) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL) + +# -s strips debug sections from executable in GCC + + + + +ifndef NO_DEFAULT_RES +$O/resource.o: resource.rc + $(RC) $(RFLAGS) resource.rc $@ + +# windres.exe : in old version mingw: +# $(RFLAGS) resource.rc $O/resource.o +# windres.exe : in new version mingw: +# $(RC) $(RFLAGS) resource.rc -FO $@ + + +endif + +$O/LzmaAlone.o: LzmaAlone.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/CommandLineParser.o: ../../../Common/CommandLineParser.cpp + $(CXX) $(CXXFLAGS) $< +$O/CRC.o: ../../../Common/CRC.cpp + $(CXX) $(CXXFLAGS) $< + +$O/CrcReg.o: ../../../Common/CrcReg.cpp + $(CXX) $(CXXFLAGS) $< + +$O/DynLimBuf.o: ../../../Common/DynLimBuf.cpp + $(CXX) $(CXXFLAGS) $< +$O/IntToString.o: ../../../Common/IntToString.cpp + $(CXX) $(CXXFLAGS) $< +$O/Lang.o: ../../../Common/Lang.cpp + $(CXX) $(CXXFLAGS) $< +$O/ListFileUtils.o: ../../../Common/ListFileUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzFindPrepare.o: ../../../Common/LzFindPrepare.cpp + $(CXX) $(CXXFLAGS) $< +$O/Md5Reg.o: ../../../Common/Md5Reg.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyMap.o: ../../../Common/MyMap.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyString.o: ../../../Common/MyString.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyVector.o: ../../../Common/MyVector.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyWindows.o: ../../../Common/MyWindows.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyWindows2.o: ../../../Common/MyWindows2.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyXml.o: ../../../Common/MyXml.cpp + $(CXX) $(CXXFLAGS) $< +$O/NewHandler.o: ../../../Common/NewHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/Random.o: ../../../Common/Random.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha1Prepare.o: ../../../Common/Sha1Prepare.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha1Reg.o: ../../../Common/Sha1Reg.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha256Prepare.o: ../../../Common/Sha256Prepare.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha256Reg.o: ../../../Common/Sha256Reg.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha3Reg.o: ../../../Common/Sha3Reg.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha512Prepare.o: ../../../Common/Sha512Prepare.cpp + $(CXX) $(CXXFLAGS) $< +$O/Sha512Reg.o: ../../../Common/Sha512Reg.cpp + $(CXX) $(CXXFLAGS) $< +$O/StdInStream.o: ../../../Common/StdInStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/StdOutStream.o: ../../../Common/StdOutStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/StringConvert.o: ../../../Common/StringConvert.cpp + $(CXX) $(CXXFLAGS) $< +$O/StringToInt.o: ../../../Common/StringToInt.cpp + $(CXX) $(CXXFLAGS) $< +$O/TextConfig.o: ../../../Common/TextConfig.cpp + $(CXX) $(CXXFLAGS) $< +$O/UTFConvert.o: ../../../Common/UTFConvert.cpp + $(CXX) $(CXXFLAGS) $< +$O/Wildcard.o: ../../../Common/Wildcard.cpp + $(CXX) $(CXXFLAGS) $< +$O/XzCrc64Init.o: ../../../Common/XzCrc64Init.cpp + $(CXX) $(CXXFLAGS) $< +$O/XzCrc64Reg.o: ../../../Common/XzCrc64Reg.cpp + $(CXX) $(CXXFLAGS) $< +$O/Xxh64Reg.o: ../../../Common/Xxh64Reg.cpp + $(CXX) $(CXXFLAGS) $< + + + +$O/Clipboard.o: ../../../Windows/Clipboard.cpp + $(CXX) $(CXXFLAGS) $< +$O/COM.o: ../../../Windows/COM.cpp + $(CXX) $(CXXFLAGS) $< +$O/CommonDialog.o: ../../../Windows/CommonDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/Console.o: ../../../Windows/Console.cpp + $(CXX) $(CXXFLAGS) $< +$O/DLL.o: ../../../Windows/DLL.cpp + $(CXX) $(CXXFLAGS) $< +$O/ErrorMsg.o: ../../../Windows/ErrorMsg.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileDir.o: ../../../Windows/FileDir.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileFind.o: ../../../Windows/FileFind.cpp + $(CXX) $(CXXFLAGS) $< + +$O/FileIO.o: ../../../Windows/FileIO.cpp + $(CXX) $(CXXFLAGS) $< + +$O/FileLink.o: ../../../Windows/FileLink.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileMapping.o: ../../../Windows/FileMapping.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileName.o: ../../../Windows/FileName.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileSystem.o: ../../../Windows/FileSystem.cpp + $(CXX) $(CXXFLAGS) $< +$O/MemoryGlobal.o: ../../../Windows/MemoryGlobal.cpp + $(CXX) $(CXXFLAGS) $< +$O/MemoryLock.o: ../../../Windows/MemoryLock.cpp + $(CXX) $(CXXFLAGS) $< +$O/Menu.o: ../../../Windows/Menu.cpp + $(CXX) $(CXXFLAGS) $< +$O/NationalTime.o: ../../../Windows/NationalTime.cpp + $(CXX) $(CXXFLAGS) $< +$O/Net.o: ../../../Windows/Net.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProcessMessages.o: ../../../Windows/ProcessMessages.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProcessUtils.o: ../../../Windows/ProcessUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropVariant.o: ../../../Windows/PropVariant.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropVariantConv.o: ../../../Windows/PropVariantConv.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropVariantUtils.o: ../../../Windows/PropVariantUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/Registry.o: ../../../Windows/Registry.cpp + $(CXX) $(CXXFLAGS) $< +$O/ResourceString.o: ../../../Windows/ResourceString.cpp + $(CXX) $(CXXFLAGS) $< +$O/SecurityUtils.o: ../../../Windows/SecurityUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/Shell.o: ../../../Windows/Shell.cpp + $(CXX) $(CXXFLAGS) $< +$O/Synchronization.o: ../../../Windows/Synchronization.cpp + $(CXX) $(CXXFLAGS) $< +$O/System.o: ../../../Windows/System.cpp + $(CXX) $(CXXFLAGS) $< +$O/SystemInfo.o: ../../../Windows/SystemInfo.cpp + $(CXX) $(CXXFLAGS) $< +$O/TimeUtils.o: ../../../Windows/TimeUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/Window.o: ../../../Windows/Window.cpp + $(CXX) $(CXXFLAGS) $< + + + +$O/ComboBox.o: ../../../Windows/Control/ComboBox.cpp + $(CXX) $(CXXFLAGS) $< +$O/Dialog.o: ../../../Windows/Control/Dialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/ImageList.o: ../../../Windows/Control/ImageList.cpp + $(CXX) $(CXXFLAGS) $< +$O/ListView.o: ../../../Windows/Control/ListView.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropertyPage.o: ../../../Windows/Control/PropertyPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/Window2.o: ../../../Windows/Control/Window2.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/CreateCoder.o: ../../Common/CreateCoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/CWrappers.o: ../../Common/CWrappers.cpp + $(CXX) $(CXXFLAGS) $< +$O/FilePathAutoRename.o: ../../Common/FilePathAutoRename.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileStreams.o: ../../Common/FileStreams.cpp + $(CXX) $(CXXFLAGS) $< +$O/FilterCoder.o: ../../Common/FilterCoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/InBuffer.o: ../../Common/InBuffer.cpp + $(CXX) $(CXXFLAGS) $< +$O/InOutTempBuffer.o: ../../Common/InOutTempBuffer.cpp + $(CXX) $(CXXFLAGS) $< +$O/LimitedStreams.o: ../../Common/LimitedStreams.cpp + $(CXX) $(CXXFLAGS) $< +$O/LockedStream.o: ../../Common/LockedStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/MemBlocks.o: ../../Common/MemBlocks.cpp + $(CXX) $(CXXFLAGS) $< +$O/MethodId.o: ../../Common/MethodId.cpp + $(CXX) $(CXXFLAGS) $< +$O/MethodProps.o: ../../Common/MethodProps.cpp + $(CXX) $(CXXFLAGS) $< +$O/MultiOutStream.o: ../../Common/MultiOutStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/OffsetStream.o: ../../Common/OffsetStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/OutBuffer.o: ../../Common/OutBuffer.cpp + $(CXX) $(CXXFLAGS) $< +$O/OutMemStream.o: ../../Common/OutMemStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProgressMt.o: ../../Common/ProgressMt.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProgressUtils.o: ../../Common/ProgressUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropId.o: ../../Common/PropId.cpp + $(CXX) $(CXXFLAGS) $< +$O/StreamBinder.o: ../../Common/StreamBinder.cpp + $(CXX) $(CXXFLAGS) $< +$O/StreamObjects.o: ../../Common/StreamObjects.cpp + $(CXX) $(CXXFLAGS) $< +$O/StreamUtils.o: ../../Common/StreamUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/UniqBlocks.o: ../../Common/UniqBlocks.cpp + $(CXX) $(CXXFLAGS) $< +$O/VirtThread.o: ../../Common/VirtThread.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/ApfsHandler.o: ../../Archive/ApfsHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ApmHandler.o: ../../Archive/ApmHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArHandler.o: ../../Archive/ArHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArjHandler.o: ../../Archive/ArjHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/AvbHandler.o: ../../Archive/AvbHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/Base64Handler.o: ../../Archive/Base64Handler.cpp + $(CXX) $(CXXFLAGS) $< +$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ComHandler.o: ../../Archive/ComHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/CpioHandler.o: ../../Archive/CpioHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/CramfsHandler.o: ../../Archive/CramfsHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/DeflateProps.o: ../../Archive/DeflateProps.cpp + $(CXX) $(CXXFLAGS) $< +$O/DllExports.o: ../../Archive/DllExports.cpp + $(CXX) $(CXXFLAGS) $< +$O/DllExports2.o: ../../Archive/DllExports2.cpp + $(CXX) $(CXXFLAGS) $< +$O/DmgHandler.o: ../../Archive/DmgHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ElfHandler.o: ../../Archive/ElfHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ExtHandler.o: ../../Archive/ExtHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/FatHandler.o: ../../Archive/FatHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/FlvHandler.o: ../../Archive/FlvHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/GptHandler.o: ../../Archive/GptHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/GzHandler.o: ../../Archive/GzHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/HandlerCont.o: ../../Archive/HandlerCont.cpp + $(CXX) $(CXXFLAGS) $< +$O/HfsHandler.o: ../../Archive/HfsHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/IhexHandler.o: ../../Archive/IhexHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/LpHandler.o: ../../Archive/LpHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/LvmHandler.o: ../../Archive/LvmHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzhHandler.o: ../../Archive/LzhHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/MachoHandler.o: ../../Archive/MachoHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/MbrHandler.o: ../../Archive/MbrHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/MslzHandler.o: ../../Archive/MslzHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/MubHandler.o: ../../Archive/MubHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/NtfsHandler.o: ../../Archive/NtfsHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/PeHandler.o: ../../Archive/PeHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/PpmdHandler.o: ../../Archive/PpmdHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/QcowHandler.o: ../../Archive/QcowHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/RpmHandler.o: ../../Archive/RpmHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/SparseHandler.o: ../../Archive/SparseHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/SplitHandler.o: ../../Archive/SplitHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/SwfHandler.o: ../../Archive/SwfHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/UefiHandler.o: ../../Archive/UefiHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/VdiHandler.o: ../../Archive/VdiHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/VhdHandler.o: ../../Archive/VhdHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/VhdxHandler.o: ../../Archive/VhdxHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/VmdkHandler.o: ../../Archive/VmdkHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/XarHandler.o: ../../Archive/XarHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/XzHandler.o: ../../Archive/XzHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZHandler.o: ../../Archive/ZHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZstdHandler.o: ../../Archive/ZstdHandler.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/7zCompressionMode.o: ../../Archive/7z/7zCompressionMode.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zDecode.o: ../../Archive/7z/7zDecode.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zEncode.o: ../../Archive/7z/7zEncode.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zExtract.o: ../../Archive/7z/7zExtract.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zFolderInStream.o: ../../Archive/7z/7zFolderInStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zHandler.o: ../../Archive/7z/7zHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zHandlerOut.o: ../../Archive/7z/7zHandlerOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zHeader.o: ../../Archive/7z/7zHeader.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zIn.o: ../../Archive/7z/7zIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zOut.o: ../../Archive/7z/7zOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zProperties.o: ../../Archive/7z/7zProperties.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zRegister.o: ../../Archive/7z/7zRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zSpecStream.o: ../../Archive/7z/7zSpecStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zUpdate.o: ../../Archive/7z/7zUpdate.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/CabBlockInStream.o: ../../Archive/Cab/CabBlockInStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/CabHandler.o: ../../Archive/Cab/CabHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/CabHeader.o: ../../Archive/Cab/CabHeader.cpp + $(CXX) $(CXXFLAGS) $< +$O/CabIn.o: ../../Archive/Cab/CabIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/CabRegister.o: ../../Archive/Cab/CabRegister.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/ChmHandler.o: ../../Archive/Chm/ChmHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/ChmIn.o: ../../Archive/Chm/ChmIn.cpp + $(CXX) $(CXXFLAGS) $< + +$O/IsoHandler.o: ../../Archive/Iso/IsoHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/IsoHeader.o: ../../Archive/Iso/IsoHeader.cpp + $(CXX) $(CXXFLAGS) $< +$O/IsoIn.o: ../../Archive/Iso/IsoIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/IsoRegister.o: ../../Archive/Iso/IsoRegister.cpp + $(CXX) $(CXXFLAGS) $< + +$O/NsisDecode.o: ../../Archive/Nsis/NsisDecode.cpp + $(CXX) $(CXXFLAGS) $< +$O/NsisHandler.o: ../../Archive/Nsis/NsisHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/NsisIn.o: ../../Archive/Nsis/NsisIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/NsisRegister.o: ../../Archive/Nsis/NsisRegister.cpp + $(CXX) $(CXXFLAGS) $< + +$O/Rar5Handler.o: ../../Archive/Rar/Rar5Handler.cpp + $(CXX) $(CXXFLAGS) $< +$O/RarHandler.o: ../../Archive/Rar/RarHandler.cpp + $(CXX) $(CXXFLAGS) $< + +$O/TarHandler.o: ../../Archive/Tar/TarHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/TarHandlerOut.o: ../../Archive/Tar/TarHandlerOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/TarHeader.o: ../../Archive/Tar/TarHeader.cpp + $(CXX) $(CXXFLAGS) $< +$O/TarIn.o: ../../Archive/Tar/TarIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/TarOut.o: ../../Archive/Tar/TarOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/TarRegister.o: ../../Archive/Tar/TarRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/TarUpdate.o: ../../Archive/Tar/TarUpdate.cpp + $(CXX) $(CXXFLAGS) $< + +$O/UdfHandler.o: ../../Archive/Udf/UdfHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/UdfIn.o: ../../Archive/Udf/UdfIn.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/WimHandler.o: ../../Archive/Wim/WimHandler.cpp + $(CXX) $(CXXFLAGS) $< +$O/WimHandlerOut.o: ../../Archive/Wim/WimHandlerOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/WimIn.o: ../../Archive/Wim/WimIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/WimRegister.o: ../../Archive/Wim/WimRegister.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/ZipAddCommon.o: ../../Archive/Zip/ZipAddCommon.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipHandler.o: ../../Archive/Zip/ZipHandler.cpp + $(CXX) $(CXXFLAGS) $(ZIP_FLAGS) $< +$O/ZipHandlerOut.o: ../../Archive/Zip/ZipHandlerOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipIn.o: ../../Archive/Zip/ZipIn.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipItem.o: ../../Archive/Zip/ZipItem.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipOut.o: ../../Archive/Zip/ZipOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipUpdate.o: ../../Archive/Zip/ZipUpdate.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipRegister.o: ../../Archive/Zip/ZipRegister.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/Bcj2Coder.o: ../../Compress/Bcj2Coder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Bcj2Register.o: ../../Compress/Bcj2Register.cpp + $(CXX) $(CXXFLAGS) $< +$O/BcjCoder.o: ../../Compress/BcjCoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/BcjRegister.o: ../../Compress/BcjRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/BitlDecoder.o: ../../Compress/BitlDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/BranchMisc.o: ../../Compress/BranchMisc.cpp + $(CXX) $(CXXFLAGS) $< +$O/BranchRegister.o: ../../Compress/BranchRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/ByteSwap.o: ../../Compress/ByteSwap.cpp + $(CXX) $(CXXFLAGS) $< +$O/BZip2Crc.o: ../../Compress/BZip2Crc.cpp + $(CXX) $(CXXFLAGS) $< +$O/BZip2Decoder.o: ../../Compress/BZip2Decoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/BZip2Encoder.o: ../../Compress/BZip2Encoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/BZip2Register.o: ../../Compress/BZip2Register.cpp + $(CXX) $(CXXFLAGS) $< +$O/CodecExports.o: ../../Compress/CodecExports.cpp + $(CXX) $(CXXFLAGS) $< +$O/CopyCoder.o: ../../Compress/CopyCoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/CopyRegister.o: ../../Compress/CopyRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/Deflate64Register.o: ../../Compress/Deflate64Register.cpp + $(CXX) $(CXXFLAGS) $< +$O/DeflateDecoder.o: ../../Compress/DeflateDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/DeflateEncoder.o: ../../Compress/DeflateEncoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/DeflateRegister.o: ../../Compress/DeflateRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/DeltaFilter.o: ../../Compress/DeltaFilter.cpp + $(CXX) $(CXXFLAGS) $< +$O/DllExports2Compress.o: ../../Compress/DllExports2Compress.cpp + $(CXX) $(CXXFLAGS) $< +$O/DllExportsCompress.o: ../../Compress/DllExportsCompress.cpp + $(CXX) $(CXXFLAGS) $< +$O/ImplodeDecoder.o: ../../Compress/ImplodeDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ImplodeHuffmanDecoder.o: ../../Compress/ImplodeHuffmanDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzfseDecoder.o: ../../Compress/LzfseDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzhDecoder.o: ../../Compress/LzhDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Lzma2Decoder.o: ../../Compress/Lzma2Decoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Lzma2Encoder.o: ../../Compress/Lzma2Encoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Lzma2Register.o: ../../Compress/Lzma2Register.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzmaDecoder.o: ../../Compress/LzmaDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzmaEncoder.o: ../../Compress/LzmaEncoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzmaRegister.o: ../../Compress/LzmaRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzmsDecoder.o: ../../Compress/LzmsDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzOutWindow.o: ../../Compress/LzOutWindow.cpp + $(CXX) $(CXXFLAGS) $< +$O/LzxDecoder.o: ../../Compress/LzxDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/PpmdDecoder.o: ../../Compress/PpmdDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/PpmdEncoder.o: ../../Compress/PpmdEncoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/PpmdRegister.o: ../../Compress/PpmdRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/PpmdZip.o: ../../Compress/PpmdZip.cpp + $(CXX) $(CXXFLAGS) $< +$O/QuantumDecoder.o: ../../Compress/QuantumDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar1Decoder.o: ../../Compress/Rar1Decoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar2Decoder.o: ../../Compress/Rar2Decoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar3Decoder.o: ../../Compress/Rar3Decoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar3Vm.o: ../../Compress/Rar3Vm.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar5Decoder.o: ../../Compress/Rar5Decoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/RarCodecsRegister.o: ../../Compress/RarCodecsRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/ShrinkDecoder.o: ../../Compress/ShrinkDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/XpressDecoder.o: ../../Compress/XpressDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/XzDecoder.o: ../../Compress/XzDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/XzEncoder.o: ../../Compress/XzEncoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZDecoder.o: ../../Compress/ZDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZlibDecoder.o: ../../Compress/ZlibDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZlibEncoder.o: ../../Compress/ZlibEncoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZstdDecoder.o: ../../Compress/ZstdDecoder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZstdRegister.o: ../../Compress/ZstdRegister.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/7zAes.o: ../../Crypto/7zAes.cpp + $(CXX) $(CXXFLAGS) $< +$O/7zAesRegister.o: ../../Crypto/7zAesRegister.cpp + $(CXX) $(CXXFLAGS) $< +$O/HmacSha1.o: ../../Crypto/HmacSha1.cpp + $(CXX) $(CXXFLAGS) $< +$O/HmacSha256.o: ../../Crypto/HmacSha256.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyAes.o: ../../Crypto/MyAes.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyAesReg.o: ../../Crypto/MyAesReg.cpp + $(CXX) $(CXXFLAGS) $< +$O/Pbkdf2HmacSha1.o: ../../Crypto/Pbkdf2HmacSha1.cpp + $(CXX) $(CXXFLAGS) $< +$O/RandGen.o: ../../Crypto/RandGen.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar20Crypto.o: ../../Crypto/Rar20Crypto.cpp + $(CXX) $(CXXFLAGS) $< +$O/Rar5Aes.o: ../../Crypto/Rar5Aes.cpp + $(CXX) $(CXXFLAGS) $< +$O/RarAes.o: ../../Crypto/RarAes.cpp + $(CXX) $(CXXFLAGS) $< +$O/WzAes.o: ../../Crypto/WzAes.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipCrypto.o: ../../Crypto/ZipCrypto.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipStrong.o: ../../Crypto/ZipStrong.cpp + $(CXX) $(CXXFLAGS) $< + + + +$O/CoderMixer2.o: ../../Archive/Common/CoderMixer2.cpp + $(CXX) $(CXXFLAGS) $< +$O/DummyOutStream.o: ../../Archive/Common/DummyOutStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/FindSignature.o: ../../Archive/Common/FindSignature.cpp + $(CXX) $(CXXFLAGS) $< +$O/HandlerOut.o: ../../Archive/Common/HandlerOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/InStreamWithCRC.o: ../../Archive/Common/InStreamWithCRC.cpp + $(CXX) $(CXXFLAGS) $< +$O/ItemNameUtils.o: ../../Archive/Common/ItemNameUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/MultiStream.o: ../../Archive/Common/MultiStream.cpp + $(CXX) $(CXXFLAGS) $< +$O/OutStreamWithCRC.o: ../../Archive/Common/OutStreamWithCRC.cpp + $(CXX) $(CXXFLAGS) $< +$O/OutStreamWithSha1.o: ../../Archive/Common/OutStreamWithSha1.cpp + $(CXX) $(CXXFLAGS) $< +$O/ParseProperties.o: ../../Archive/Common/ParseProperties.cpp + $(CXX) $(CXXFLAGS) $< + + + + +$O/ArchiveCommandLine.o: ../../UI/Common/ArchiveCommandLine.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveExtractCallback.o: ../../UI/Common/ArchiveExtractCallback.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveName.o: ../../UI/Common/ArchiveName.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveOpenCallback.o: ../../UI/Common/ArchiveOpenCallback.cpp + $(CXX) $(CXXFLAGS) $< +$O/Bench.o: ../../UI/Common/Bench.cpp + $(CXX) $(CXXFLAGS) $< +$O/CompressCall.o: ../../UI/Common/CompressCall.cpp + $(CXX) $(CXXFLAGS) $< +$O/CompressCall2.o: ../../UI/Common/CompressCall2.cpp + $(CXX) $(CXXFLAGS) $< +$O/DefaultName.o: ../../UI/Common/DefaultName.cpp + $(CXX) $(CXXFLAGS) $< +$O/EnumDirItems.o: ../../UI/Common/EnumDirItems.cpp + $(CXX) $(CXXFLAGS) $< +$O/Extract.o: ../../UI/Common/Extract.cpp + $(CXX) $(CXXFLAGS) $< +$O/ExtractingFilePath.o: ../../UI/Common/ExtractingFilePath.cpp + $(CXX) $(CXXFLAGS) $< +$O/HashCalc.o: ../../UI/Common/HashCalc.cpp + $(CXX) $(CXXFLAGS) $< +$O/LoadCodecs.o: ../../UI/Common/LoadCodecs.cpp + $(CXX) $(CXXFLAGS) $< +$O/OpenArchive.o: ../../UI/Common/OpenArchive.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropIDUtils.o: ../../UI/Common/PropIDUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/SetProperties.o: ../../UI/Common/SetProperties.cpp + $(CXX) $(CXXFLAGS) $< +$O/SortUtils.o: ../../UI/Common/SortUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/TempFiles.o: ../../UI/Common/TempFiles.cpp + $(CXX) $(CXXFLAGS) $< +$O/Update.o: ../../UI/Common/Update.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateAction.o: ../../UI/Common/UpdateAction.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateCallback.o: ../../UI/Common/UpdateCallback.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdatePair.o: ../../UI/Common/UpdatePair.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateProduce.o: ../../UI/Common/UpdateProduce.cpp + $(CXX) $(CXXFLAGS) $< +$O/WorkDir.o: ../../UI/Common/WorkDir.cpp + $(CXX) $(CXXFLAGS) $< +$O/ZipRegistry.o: ../../UI/Common/ZipRegistry.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/Agent.o: ../../UI/Agent/Agent.cpp + $(CXX) $(CXXFLAGS) $< +$O/AgentOut.o: ../../UI/Agent/AgentOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/AgentProxy.o: ../../UI/Agent/AgentProxy.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveFolder.o: ../../UI/Agent/ArchiveFolder.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveFolderOpen.o: ../../UI/Agent/ArchiveFolderOpen.cpp + $(CXX) $(CXXFLAGS) $< +$O/ArchiveFolderOut.o: ../../UI/Agent/ArchiveFolderOut.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateCallbackAgent.o: ../../UI/Agent/UpdateCallbackAgent.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/Client7z.o: ../../UI/Client7z/Client7z.cpp + $(CXX) $(CXXFLAGS) $< + + +$O/BenchCon.o: ../../UI/Console/BenchCon.cpp + $(CXX) $(CXXFLAGS) $< +$O/ConsoleClose.o: ../../UI/Console/ConsoleClose.cpp + $(CXX) $(CXXFLAGS) $< +$O/ExtractCallbackConsole.o: ../../UI/Console/ExtractCallbackConsole.cpp + $(CXX) $(CXXFLAGS) $< +$O/HashCon.o: ../../UI/Console/HashCon.cpp + $(CXX) $(CXXFLAGS) $< +$O/List.o: ../../UI/Console/List.cpp + $(CXX) $(CXXFLAGS) $< +$O/Main.o: ../../UI/Console/Main.cpp ../../../../C/7zVersion.h + $(CXX) $(CXXFLAGS) $(CONSOLE_VARIANT_FLAGS) $(CONSOLE_ASM_FLAGS) $< +$O/MainAr.o: ../../UI/Console/MainAr.cpp + $(CXX) $(CXXFLAGS) $< +$O/OpenCallbackConsole.o: ../../UI/Console/OpenCallbackConsole.cpp + $(CXX) $(CXXFLAGS) $< +$O/PercentPrinter.o: ../../UI/Console/PercentPrinter.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateCallbackConsole.o: ../../UI/Console/UpdateCallbackConsole.cpp + $(CXX) $(CXXFLAGS) $< +$O/UserInputUtils.o: ../../UI/Console/UserInputUtils.cpp + $(CXX) $(CXXFLAGS) $< + +$O/BenchmarkDialog.o: ../../UI/GUI/BenchmarkDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/CompressDialog.o: ../../UI/GUI/CompressDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/ExtractDialog.o: ../../UI/GUI/ExtractDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/ExtractGUI.o: ../../UI/GUI/ExtractGUI.cpp + $(CXX) $(CXXFLAGS) $< +$O/GUI.o: ../../UI/GUI/GUI.cpp + $(CXX) $(CXXFLAGS) $< +$O/HashGUI.o: ../../UI/GUI/HashGUI.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateCallbackGUI.o: ../../UI/GUI/UpdateCallbackGUI.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateCallbackGUI2.o: ../../UI/GUI/UpdateCallbackGUI2.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateGUI.o: ../../UI/GUI/UpdateGUI.cpp + $(CXX) $(CXXFLAGS) $< + +$O/MyMessages.o: ../../UI/Explorer/MyMessages.cpp + $(CXX) $(CXXFLAGS) $< +$O/ContextMenu.o: ../../UI/Explorer/ContextMenu.cpp + $(CXX) $(CXXFLAGS) $< +$O/DllExportsExplorer.o: ../../UI/Explorer/DllExportsExplorer.cpp + $(CXX) $(CXXFLAGS) $< +$O/RegistryContextMenu.o: ../../UI/Explorer/RegistryContextMenu.cpp + $(CXX) $(CXXFLAGS) $< + + + +$O/AboutDialog.o: ../../UI/FileManager/AboutDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/AltStreamsFolder.o: ../../UI/FileManager/AltStreamsFolder.cpp + $(CXX) $(CXXFLAGS) $< +$O/App.o: ../../UI/FileManager/App.cpp + $(CXX) $(CXXFLAGS) $< +$O/BrowseDialog.o: ../../UI/FileManager/BrowseDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/BrowseDialog2.o: ../../UI/FileManager/BrowseDialog2.cpp + $(CXX) $(CXXFLAGS) $< +$O/ClassDefs.o: ../../UI/FileManager/ClassDefs.cpp + $(CXX) $(CXXFLAGS) $< +$O/ComboDialog.o: ../../UI/FileManager/ComboDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/CopyDialog.o: ../../UI/FileManager/CopyDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/EditDialog.o: ../../UI/FileManager/EditDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/EditPage.o: ../../UI/FileManager/EditPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/EnumFormatEtc.o: ../../UI/FileManager/EnumFormatEtc.cpp + $(CXX) $(CXXFLAGS) $< +$O/ExtractCallback.o: ../../UI/FileManager/ExtractCallback.cpp + $(CXX) $(CXXFLAGS) $< +$O/FileFolderPluginOpen.o: ../../UI/FileManager/FileFolderPluginOpen.cpp + $(CXX) $(CXXFLAGS) $< +$O/FilePlugins.o: ../../UI/FileManager/FilePlugins.cpp + $(CXX) $(CXXFLAGS) $< +$O/FM.o: ../../UI/FileManager/FM.cpp + $(CXX) $(CXXFLAGS) $< +$O/FoldersPage.o: ../../UI/FileManager/FoldersPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/FormatUtils.o: ../../UI/FileManager/FormatUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/FSDrives.o: ../../UI/FileManager/FSDrives.cpp + $(CXX) $(CXXFLAGS) $< +$O/FSFolder.o: ../../UI/FileManager/FSFolder.cpp + $(CXX) $(CXXFLAGS) $< +$O/FSFolderCopy.o: ../../UI/FileManager/FSFolderCopy.cpp + $(CXX) $(CXXFLAGS) $< +$O/HelpUtils.o: ../../UI/FileManager/HelpUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/LangPage.o: ../../UI/FileManager/LangPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/LangUtils.o: ../../UI/FileManager/LangUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/LinkDialog.o: ../../UI/FileManager/LinkDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/ListViewDialog.o: ../../UI/FileManager/ListViewDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/MemDialog.o: ../../UI/FileManager/MemDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/MenuPage.o: ../../UI/FileManager/MenuPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/MessagesDialog.o: ../../UI/FileManager/MessagesDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/MyLoadMenu.o: ../../UI/FileManager/MyLoadMenu.cpp + $(CXX) $(CXXFLAGS) $< +$O/NetFolder.o: ../../UI/FileManager/NetFolder.cpp + $(CXX) $(CXXFLAGS) $< +$O/OpenCallback.o: ../../UI/FileManager/OpenCallback.cpp + $(CXX) $(CXXFLAGS) $< +$O/OptionsDialog.o: ../../UI/FileManager/OptionsDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/OverwriteDialog.o: ../../UI/FileManager/OverwriteDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/Panel.o: ../../UI/FileManager/Panel.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelCopy.o: ../../UI/FileManager/PanelCopy.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelCrc.o: ../../UI/FileManager/PanelCrc.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelDrag.o: ../../UI/FileManager/PanelDrag.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelFolderChange.o: ../../UI/FileManager/PanelFolderChange.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelItemOpen.o: ../../UI/FileManager/PanelItemOpen.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelItems.o: ../../UI/FileManager/PanelItems.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelKey.o: ../../UI/FileManager/PanelKey.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelListNotify.o: ../../UI/FileManager/PanelListNotify.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelMenu.o: ../../UI/FileManager/PanelMenu.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelOperations.o: ../../UI/FileManager/PanelOperations.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelSelect.o: ../../UI/FileManager/PanelSelect.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelSort.o: ../../UI/FileManager/PanelSort.cpp + $(CXX) $(CXXFLAGS) $< +$O/PanelSplitFile.o: ../../UI/FileManager/PanelSplitFile.cpp + $(CXX) $(CXXFLAGS) $< +$O/PasswordDialog.o: ../../UI/FileManager/PasswordDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProgramLocation.o: ../../UI/FileManager/ProgramLocation.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProgressDialog.o: ../../UI/FileManager/ProgressDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/ProgressDialog2.o: ../../UI/FileManager/ProgressDialog2.cpp + $(CXX) $(CXXFLAGS) $< +$O/PropertyName.o: ../../UI/FileManager/PropertyName.cpp + $(CXX) $(CXXFLAGS) $< +$O/RegistryAssociations.o: ../../UI/FileManager/RegistryAssociations.cpp + $(CXX) $(CXXFLAGS) $< +$O/RegistryPlugins.o: ../../UI/FileManager/RegistryPlugins.cpp + $(CXX) $(CXXFLAGS) $< +$O/RegistryUtils.o: ../../UI/FileManager/RegistryUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/RootFolder.o: ../../UI/FileManager/RootFolder.cpp + $(CXX) $(CXXFLAGS) $< +$O/SettingsPage.o: ../../UI/FileManager/SettingsPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/SplitDialog.o: ../../UI/FileManager/SplitDialog.cpp + $(CXX) $(CXXFLAGS) $< +$O/SplitUtils.o: ../../UI/FileManager/SplitUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/StringUtils.o: ../../UI/FileManager/StringUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/SysIconUtils.o: ../../UI/FileManager/SysIconUtils.cpp + $(CXX) $(CXXFLAGS) $< +$O/SystemPage.o: ../../UI/FileManager/SystemPage.cpp + $(CXX) $(CXXFLAGS) $< +$O/TextPairs.o: ../../UI/FileManager/TextPairs.cpp + $(CXX) $(CXXFLAGS) $< +$O/UpdateCallback100.o: ../../UI/FileManager/UpdateCallback100.cpp + $(CXX) $(CXXFLAGS) $< +$O/VerCtrl.o: ../../UI/FileManager/VerCtrl.cpp + $(CXX) $(CXXFLAGS) $< +$O/ViewSettings.o: ../../UI/FileManager/ViewSettings.cpp + $(CXX) $(CXXFLAGS) $< + +$O/SfxCon.o: ../../Bundles/SFXCon/SfxCon.cpp + $(CXX) $(CXXFLAGS) $< + +$O/$(FILE_IO).o: ../../../$(FILE_IO_2).cpp + $(CXX) $(CXXFLAGS) $< + + + + + + +$O/7zAlloc.o: ../../../../C/7zAlloc.c + $(CC) $(CFLAGS) $< +$O/7zArcIn.o: ../../../../C/7zArcIn.c + $(CC) $(CFLAGS) $< +$O/7zBuf.o: ../../../../C/7zBuf.c + $(CC) $(CFLAGS) $< +$O/7zBuf2.o: ../../../../C/7zBuf2.c + $(CC) $(CFLAGS) $< +$O/7zCrc.o: ../../../../C/7zCrc.c + $(CC) $(CFLAGS) $< +$O/7zDec.o: ../../../../C/7zDec.c + $(CC) $(CFLAGS) $< +$O/7zFile.o: ../../../../C/7zFile.c + $(CC) $(CFLAGS) $< +$O/7zStream.o: ../../../../C/7zStream.c + $(CC) $(CFLAGS) $< +$O/Aes.o: ../../../../C/Aes.c + $(CC) $(CFLAGS) $< +$O/Alloc.o: ../../../../C/Alloc.c + $(CC) $(CFLAGS) $< +$O/Bcj2.o: ../../../../C/Bcj2.c + $(CC) $(CFLAGS) $< +$O/Bcj2Enc.o: ../../../../C/Bcj2Enc.c + $(CC) $(CFLAGS) $< +$O/Blake2s.o: ../../../../C/Blake2s.c + $(CC) $(CFLAGS) $< +$O/Bra.o: ../../../../C/Bra.c + $(CC) $(CFLAGS) $< +$O/Bra86.o: ../../../../C/Bra86.c + $(CC) $(CFLAGS) $< +$O/BraIA64.o: ../../../../C/BraIA64.c + $(CC) $(CFLAGS) $< +$O/BwtSort.o: ../../../../C/BwtSort.c + $(CC) $(CFLAGS) $< + +$O/CpuArch.o: ../../../../C/CpuArch.c + $(CC) $(CFLAGS) $< +$O/Delta.o: ../../../../C/Delta.c + $(CC) $(CFLAGS) $< +$O/DllSecur.o: ../../../../C/DllSecur.c + $(CC) $(CFLAGS) $< +$O/HuffEnc.o: ../../../../C/HuffEnc.c + $(CC) $(CFLAGS) $< +$O/LzFind.o: ../../../../C/LzFind.c + $(CC) $(CFLAGS) $< + +# ifdef MT_FILES +$O/LzFindMt.o: ../../../../C/LzFindMt.c + $(CC) $(CFLAGS) $< + +$O/Threads.o: ../../../../C/Threads.c + $(CC) $(CFLAGS) $< +# endif + +$O/LzmaEnc.o: ../../../../C/LzmaEnc.c + $(CC) $(CFLAGS) $< +$O/Lzma86Dec.o: ../../../../C/Lzma86Dec.c + $(CC) $(CFLAGS) $< +$O/Lzma86Enc.o: ../../../../C/Lzma86Enc.c + $(CC) $(CFLAGS) $< +$O/Lzma2Dec.o: ../../../../C/Lzma2Dec.c + $(CC) $(CFLAGS) $< +$O/Lzma2DecMt.o: ../../../../C/Lzma2DecMt.c + $(CC) $(CFLAGS) $< +$O/Lzma2Enc.o: ../../../../C/Lzma2Enc.c + $(CC) $(CFLAGS) $< +$O/LzmaLib.o: ../../../../C/LzmaLib.c + $(CC) $(CFLAGS) $< +$O/Md5.o: ../../../../C/Md5.c + $(CC) $(CFLAGS) $< +$O/MtCoder.o: ../../../../C/MtCoder.c + $(CC) $(CFLAGS) $< +$O/MtDec.o: ../../../../C/MtDec.c + $(CC) $(CFLAGS) $< +$O/Ppmd7.o: ../../../../C/Ppmd7.c + $(CC) $(CFLAGS) $< +$O/Ppmd7aDec.o: ../../../../C/Ppmd7aDec.c + $(CC) $(CFLAGS) $< +$O/Ppmd7Dec.o: ../../../../C/Ppmd7Dec.c + $(CC) $(CFLAGS) $< +$O/Ppmd7Enc.o: ../../../../C/Ppmd7Enc.c + $(CC) $(CFLAGS) $< +$O/Ppmd8.o: ../../../../C/Ppmd8.c + $(CC) $(CFLAGS) $< +$O/Ppmd8Dec.o: ../../../../C/Ppmd8Dec.c + $(CC) $(CFLAGS) $< +$O/Ppmd8Enc.o: ../../../../C/Ppmd8Enc.c + $(CC) $(CFLAGS) $< +$O/Sha1.o: ../../../../C/Sha1.c + $(CC) $(CFLAGS) $< +$O/Sha256.o: ../../../../C/Sha256.c + $(CC) $(CFLAGS) $< +$O/Sha3.o: ../../../../C/Sha3.c + $(CC) $(CFLAGS) $< +$O/Sha512.o: ../../../../C/Sha512.c + $(CC) $(CFLAGS) $< +$O/Sha512Opt.o: ../../../../C/Sha512Opt.c + $(CC) $(CFLAGS) $< +$O/Sort.o: ../../../../C/Sort.c + $(CC) $(CFLAGS) $< +$O/SwapBytes.o: ../../../../C/SwapBytes.c + $(CC) $(CFLAGS) $< +$O/Xxh64.o: ../../../../C/Xxh64.c + $(CC) $(CFLAGS) $< +$O/Xz.o: ../../../../C/Xz.c + $(CC) $(CFLAGS) $< +$O/XzCrc64.o: ../../../../C/XzCrc64.c + $(CC) $(CFLAGS) $< +$O/XzDec.o: ../../../../C/XzDec.c + $(CC) $(CFLAGS) $< +$O/XzEnc.o: ../../../../C/XzEnc.c + $(CC) $(CFLAGS) $< +$O/XzIn.o: ../../../../C/XzIn.c + $(CC) $(CFLAGS) $< +$O/ZstdDec.o: ../../../../C/ZstdDec.c + $(CC) $(CFLAGS) $< + + +ifdef USE_ASM +ifdef IS_X64 +USE_X86_ASM=1 +USE_X64_ASM=1 +else +ifdef IS_X86 +USE_X86_ASM=1 +endif +endif +endif + +ifdef USE_X86_ASM +$O/7zCrcOpt.o: ../../../../Asm/x86/7zCrcOpt.asm + $(MY_ASM) $(AFLAGS) $< +$O/XzCrc64Opt.o: ../../../../Asm/x86/XzCrc64Opt.asm + $(MY_ASM) $(AFLAGS) $< +$O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm + $(MY_ASM) $(AFLAGS) $< +$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm + $(MY_ASM) $(AFLAGS) $< + +ifndef USE_JWASM +USE_X86_ASM_AES=1 +endif + +else +$O/7zCrcOpt.o: ../../../../C/7zCrcOpt.c + $(CC) $(CFLAGS) $< +$O/XzCrc64Opt.o: ../../../../C/XzCrc64Opt.c + $(CC) $(CFLAGS) $< +$O/Sha1Opt.o: ../../../../C/Sha1Opt.c + $(CC) $(CFLAGS) $< +$O/Sha256Opt.o: ../../../../C/Sha256Opt.c + $(CC) $(CFLAGS) $< +endif + + +ifdef USE_X86_ASM_AES +$O/AesOpt.o: ../../../../Asm/x86/AesOpt.asm + $(MY_ASM) $(AFLAGS) $< +else +$O/AesOpt.o: ../../../../C/AesOpt.c + $(CC) $(CFLAGS) $< +endif + + +ifdef USE_X64_ASM +$O/LzFindOpt.o: ../../../../Asm/x86/LzFindOpt.asm + $(MY_ASM) $(AFLAGS) $< +else +$O/LzFindOpt.o: ../../../../C/LzFindOpt.c + $(CC) $(CFLAGS) $< +endif + +ifdef USE_LZMA_DEC_ASM + +ifdef IS_X64 +$O/LzmaDecOpt.o: ../../../../Asm/x86/LzmaDecOpt.asm + $(MY_ASM) $(AFLAGS) $< +endif + +ifdef IS_ARM64 +$O/LzmaDecOpt.o: ../../../../Asm/arm64/LzmaDecOpt.S ../../../../Asm/arm64/7zAsm.S + $(CC) $(CFLAGS) $(ASM_FLAGS) $< +endif + +$O/LzmaDec.o: ../../../../C/LzmaDec.c + $(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $< + +else + +$O/LzmaDec.o: ../../../../C/LzmaDec.c + $(CC) $(CFLAGS) $< + +endif + + + + +$O/7zMain.o: ../../../../C/Util/7z/7zMain.c + $(CC) $(CFLAGS) $< +$O/LzmaUtil.o: ../../../../C/Util/Lzma/LzmaUtil.c + $(CC) $(CFLAGS) $< + +ifneq ($(CC), xlc) +SHOW_PREDEF=-dM +else +SHOW_PREDEF= -qshowmacros=pre +endif + +predef_cc: + $(CC) $(CFLAGS) -E $(SHOW_PREDEF) ../../../../C/CpuArch.c > predef_cc_log +# $(CC) $(CFLAGS) -E -dM - < /dev/null +predef_cxx: + $(CXX) $(CFLAGS) -E $(SHOW_PREDEF) ../../../Common/CrcReg.cpp > predef_cxx_log + +predef: predef_cc predef_cxx + + +clean: + -$(DEL_OBJ_EXE) diff --git a/CPP/7zip/Aes.mak b/CPP/7zip/Aes.mak index 5c88cee4d..7d8da2d81 100644 --- a/CPP/7zip/Aes.mak +++ b/CPP/7zip/Aes.mak @@ -1,10 +1,10 @@ -C_OBJS = $(C_OBJS) \ - $O\Aes.obj - -!IF defined(USE_C_AES) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" -C_OBJS = $(C_OBJS) \ - $O\AesOpt.obj -!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" -ASM_OBJS = $(ASM_OBJS) \ - $O\AesOpt.obj -!ENDIF +C_OBJS = $(C_OBJS) \ + $O\Aes.obj + +!IF defined(USE_C_AES) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" +C_OBJS = $(C_OBJS) \ + $O\AesOpt.obj +!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" +ASM_OBJS = $(ASM_OBJS) \ + $O\AesOpt.obj +!ENDIF diff --git a/CPP/7zip/Archive/7z/7z.dsp b/CPP/7zip/Archive/7z/7z.dsp index 63fde59c7..2c3e14472 100644 --- a/CPP/7zip/Archive/7z/7z.dsp +++ b/CPP/7zip/Archive/7z/7z.dsp @@ -1,638 +1,638 @@ -# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=7z - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "7z.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "7z - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\Formats\7z.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\Formats\7z.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "7z - Win32 Release" -# Name "7z - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Archive.def -# End Source File -# Begin Source File - -SOURCE=..\ArchiveExports.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CodecExports.cpp -# End Source File -# Begin Source File - -SOURCE=..\DllExports2.cpp -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Engine" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\7zCompressionMode.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=.\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=.\7zEncode.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zEncode.h -# End Source File -# Begin Source File - -SOURCE=.\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zFolderInStream.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zFolderInStream.h -# End Source File -# Begin Source File - -SOURCE=.\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=.\7zHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zHeader.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=.\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zIn.h -# End Source File -# Begin Source File - -SOURCE=.\7zItem.h -# End Source File -# Begin Source File - -SOURCE=.\7zOut.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zOut.h -# End Source File -# Begin Source File - -SOURCE=.\7zProperties.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zProperties.h -# End Source File -# Begin Source File - -SOURCE=.\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zSpecStream.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zSpecStream.h -# End Source File -# Begin Source File - -SOURCE=.\7zUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=.\7zUpdate.h -# End Source File -# End Group -# Begin Group "Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IMyUnknown.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\Buffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynamicBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\Common\HandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\HandlerOut.h -# End Source File -# Begin Source File - -SOURCE=..\Common\InStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\InStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\OutStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ParseProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ParseProperties.h -# End Source File -# End Group -# Begin Group "7-Zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterArc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterCodec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Handle.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=7z - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "7z.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "7z - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\Formats\7z.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\Formats\7z.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "7z - Win32 Release" +# Name "7z - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Archive.def +# End Source File +# Begin Source File + +SOURCE=..\ArchiveExports.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CodecExports.cpp +# End Source File +# Begin Source File + +SOURCE=..\DllExports2.cpp +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Engine" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\7zCompressionMode.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=.\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=.\7zEncode.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zEncode.h +# End Source File +# Begin Source File + +SOURCE=.\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zFolderInStream.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zFolderInStream.h +# End Source File +# Begin Source File + +SOURCE=.\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=.\7zHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zHeader.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=.\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zIn.h +# End Source File +# Begin Source File + +SOURCE=.\7zItem.h +# End Source File +# Begin Source File + +SOURCE=.\7zOut.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zOut.h +# End Source File +# Begin Source File + +SOURCE=.\7zProperties.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zProperties.h +# End Source File +# Begin Source File + +SOURCE=.\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zSpecStream.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zSpecStream.h +# End Source File +# Begin Source File + +SOURCE=.\7zUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=.\7zUpdate.h +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IMyUnknown.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynamicBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\Common\HandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\HandlerOut.h +# End Source File +# Begin Source File + +SOURCE=..\Common\InStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\InStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\OutStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ParseProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ParseProperties.h +# End Source File +# End Group +# Begin Group "7-Zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterArc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterCodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Handle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/Archive/7z/7z.dsw b/CPP/7zip/Archive/7z/7z.dsw index 5b0e36cca..702a86c72 100644 --- a/CPP/7zip/Archive/7z/7z.dsw +++ b/CPP/7zip/Archive/7z/7z.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "7z"=".\7z.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "7z"=".\7z.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp index 232c63820..6774fc482 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.cpp +++ b/CPP/7zip/Archive/7z/7zCompressionMode.cpp @@ -1,3 +1,3 @@ -// CompressionMethod.cpp - -#include "StdAfx.h" +// CompressionMethod.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h index 297981049..737722dd0 100644 --- a/CPP/7zip/Archive/7z/7zCompressionMode.h +++ b/CPP/7zip/Archive/7z/7zCompressionMode.h @@ -1,90 +1,90 @@ -// 7zCompressionMode.h - -#ifndef ZIP7_INC_7Z_COMPRESSION_MODE_H -#define ZIP7_INC_7Z_COMPRESSION_MODE_H - -#include "../../Common/MethodId.h" -#include "../../Common/MethodProps.h" - -namespace NArchive { -namespace N7z { - -struct CMethodFull: public CMethodProps -{ - CMethodId Id; - UInt32 NumStreams; - int CodecIndex; - UInt32 NumThreads; - bool Set_NumThreads; - - CMethodFull(): CodecIndex(-1), NumThreads(1), Set_NumThreads(false) {} - bool IsSimpleCoder() const { return NumStreams == 1; } -}; - -struct CBond2 -{ - UInt32 OutCoder; - UInt32 OutStream; - UInt32 InCoder; -}; - -struct CCompressionMethodMode -{ - /* - if (Bonds.Empty()), then default bonds must be created - if (Filter_was_Inserted) - { - Methods[0] is filter method - Bonds don't contain bonds for filter (these bonds must be created) - } - */ - - CObjectVector Methods; - CRecordVector Bonds; - - bool IsThereBond_to_Coder(unsigned coderIndex) const - { - FOR_VECTOR(i, Bonds) - if (Bonds[i].InCoder == coderIndex) - return true; - return false; - } - - bool DefaultMethod_was_Inserted; - bool Filter_was_Inserted; - bool PasswordIsDefined; - bool MemoryUsageLimit_WasSet; - - #ifndef Z7_ST - bool NumThreads_WasForced; - bool MultiThreadMixer; - UInt32 NumThreads; - #endif - - UString Password; // _Wipe - UInt64 MemoryUsageLimit; - - bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } - CCompressionMethodMode(): - DefaultMethod_was_Inserted(false) - , Filter_was_Inserted(false) - , PasswordIsDefined(false) - , MemoryUsageLimit_WasSet(false) - #ifndef Z7_ST - , NumThreads_WasForced(false) - , MultiThreadMixer(true) - , NumThreads(1) - #endif - , MemoryUsageLimit((UInt64)1 << 30) - {} - -#ifdef Z7_CPP_IS_SUPPORTED_default - CCompressionMethodMode(const CCompressionMethodMode &) = default; - CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default; -#endif - ~CCompressionMethodMode() { Password.Wipe_and_Empty(); } -}; - -}} - -#endif +// 7zCompressionMode.h + +#ifndef ZIP7_INC_7Z_COMPRESSION_MODE_H +#define ZIP7_INC_7Z_COMPRESSION_MODE_H + +#include "../../Common/MethodId.h" +#include "../../Common/MethodProps.h" + +namespace NArchive { +namespace N7z { + +struct CMethodFull: public CMethodProps +{ + CMethodId Id; + UInt32 NumStreams; + int CodecIndex; + UInt32 NumThreads; + bool Set_NumThreads; + + CMethodFull(): CodecIndex(-1), NumThreads(1), Set_NumThreads(false) {} + bool IsSimpleCoder() const { return NumStreams == 1; } +}; + +struct CBond2 +{ + UInt32 OutCoder; + UInt32 OutStream; + UInt32 InCoder; +}; + +struct CCompressionMethodMode +{ + /* + if (Bonds.Empty()), then default bonds must be created + if (Filter_was_Inserted) + { + Methods[0] is filter method + Bonds don't contain bonds for filter (these bonds must be created) + } + */ + + CObjectVector Methods; + CRecordVector Bonds; + + bool IsThereBond_to_Coder(unsigned coderIndex) const + { + FOR_VECTOR(i, Bonds) + if (Bonds[i].InCoder == coderIndex) + return true; + return false; + } + + bool DefaultMethod_was_Inserted; + bool Filter_was_Inserted; + bool PasswordIsDefined; + bool MemoryUsageLimit_WasSet; + + #ifndef Z7_ST + bool NumThreads_WasForced; + bool MultiThreadMixer; + UInt32 NumThreads; + #endif + + UString Password; // _Wipe + UInt64 MemoryUsageLimit; + + bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } + CCompressionMethodMode(): + DefaultMethod_was_Inserted(false) + , Filter_was_Inserted(false) + , PasswordIsDefined(false) + , MemoryUsageLimit_WasSet(false) + #ifndef Z7_ST + , NumThreads_WasForced(false) + , MultiThreadMixer(true) + , NumThreads(1) + #endif + , MemoryUsageLimit((UInt64)1 << 30) + {} + +#ifdef Z7_CPP_IS_SUPPORTED_default + CCompressionMethodMode(const CCompressionMethodMode &) = default; + CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default; +#endif + ~CCompressionMethodMode() { Password.Wipe_and_Empty(); } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp index f863df928..50cbff621 100644 --- a/CPP/7zip/Archive/7z/7zDecode.cpp +++ b/CPP/7zip/Archive/7z/7zDecode.cpp @@ -1,599 +1,599 @@ -// 7zDecode.cpp - -#include "StdAfx.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "7zDecode.h" - -namespace NArchive { -namespace N7z { - -Z7_CLASS_IMP_COM_1( - CDecProgress - , ICompressProgressInfo -) - CMyComPtr _progress; -public: - CDecProgress(ICompressProgressInfo *progress): _progress(progress) {} -}; - -Z7_COM7F_IMF(CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize)) -{ - return _progress->SetRatioInfo(NULL, outSize); -} - -static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi) -{ - bi.Clear(); - - bi.Bonds.ClearAndSetSize(folder.Bonds.Size()); - unsigned i; - for (i = 0; i < folder.Bonds.Size(); i++) - { - NCoderMixer2::CBond &bond = bi.Bonds[i]; - const N7z::CBond &folderBond = folder.Bonds[i]; - bond.PackIndex = folderBond.PackIndex; - bond.UnpackIndex = folderBond.UnpackIndex; - } - - bi.Coders.ClearAndSetSize(folder.Coders.Size()); - bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); - for (i = 0; i < folder.Coders.Size(); i++) - { - const CCoderInfo &coderInfo = folder.Coders[i]; - bi.Coders[i].NumStreams = coderInfo.NumStreams; - bi.CoderMethodIDs[i] = coderInfo.MethodID; - } - - /* - if (!bi.SetUnpackCoder()) - throw 1112; - */ - bi.UnpackCoder = folder.UnpackCoder; - bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size()); - for (i = 0; i < folder.PackStreams.Size(); i++) - bi.PackStreams[i] = folder.PackStreams[i]; -} - -static inline bool AreCodersEqual( - const NCoderMixer2::CCoderStreamsInfo &a1, - const NCoderMixer2::CCoderStreamsInfo &a2) -{ - return (a1.NumStreams == a2.NumStreams); -} - -static inline bool AreBondsEqual( - const NCoderMixer2::CBond &a1, - const NCoderMixer2::CBond &a2) -{ - return - (a1.PackIndex == a2.PackIndex) && - (a1.UnpackIndex == a2.UnpackIndex); -} - -static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) -{ - if (a1.Coders.Size() != a2.Coders.Size()) - return false; - unsigned i; - for (i = 0; i < a1.Coders.Size(); i++) - if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) - return false; - - if (a1.Bonds.Size() != a2.Bonds.Size()) - return false; - for (i = 0; i < a1.Bonds.Size(); i++) - if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i])) - return false; - - for (i = 0; i < a1.CoderMethodIDs.Size(); i++) - if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) - return false; - - if (a1.PackStreams.Size() != a2.PackStreams.Size()) - return false; - for (i = 0; i < a1.PackStreams.Size(); i++) - if (a1.PackStreams[i] != a2.PackStreams[i]) - return false; - - /* - if (a1.UnpackCoder != a2.UnpackCoder) - return false; - */ - return true; -} - -CDecoder::CDecoder(bool useMixerMT): - _bindInfoPrev_Defined(false) -{ - #if defined(USE_MIXER_ST) && defined(USE_MIXER_MT) - _useMixerMT = useMixerMT; - #else - UNUSED_VAR(useMixerMT) - #endif -} - - -Z7_CLASS_IMP_COM_0( - CLockedInStream -) -public: - CMyComPtr Stream; - UInt64 Pos; - - #ifdef USE_MIXER_MT - NWindows::NSynchronization::CCriticalSection CriticalSection; - #endif -}; - - -#ifdef USE_MIXER_MT - -Z7_CLASS_IMP_COM_1( - CLockedSequentialInStreamMT - , ISequentialInStream -) - CLockedInStream *_glob; - UInt64 _pos; - CMyComPtr _globRef; -public: - void Init(CLockedInStream *lockedInStream, UInt64 startPos) - { - _globRef = lockedInStream; - _glob = lockedInStream; - _pos = startPos; - } -}; - -Z7_COM7F_IMF(CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection); - - if (_pos != _glob->Pos) - { - RINOK(InStream_SeekSet(_glob->Stream, _pos)) - _glob->Pos = _pos; - } - - UInt32 realProcessedSize = 0; - const HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); - _pos += realProcessedSize; - _glob->Pos = _pos; - if (processedSize) - *processedSize = realProcessedSize; - return res; -} - -#endif - - -#ifdef USE_MIXER_ST - -Z7_CLASS_IMP_COM_1( - CLockedSequentialInStreamST - , ISequentialInStream -) - CLockedInStream *_glob; - UInt64 _pos; - CMyComPtr _globRef; -public: - void Init(CLockedInStream *lockedInStream, UInt64 startPos) - { - _globRef = lockedInStream; - _glob = lockedInStream; - _pos = startPos; - } -}; - -Z7_COM7F_IMF(CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (_pos != _glob->Pos) - { - RINOK(InStream_SeekSet(_glob->Stream, _pos)) - _glob->Pos = _pos; - } - - UInt32 realProcessedSize = 0; - const HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); - _pos += realProcessedSize; - _glob->Pos = _pos; - if (processedSize) - *processedSize = realProcessedSize; - return res; -} - -#endif - - - -HRESULT CDecoder::Decode( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, - UInt64 startPos, - const CFolders &folders, unsigned folderIndex, - const UInt64 *unpackSize - - , ISequentialOutStream *outStream - , ICompressProgressInfo *compressProgress - - , ISequentialInStream ** - #ifdef USE_MIXER_ST - inStreamMainRes - #endif - - , bool &dataAfterEnd_Error - - Z7_7Z_DECODER_CRYPRO_VARS_DECL - - #if !defined(Z7_ST) - , bool mtMode, UInt32 numThreads, UInt64 memUsage - #endif - ) -{ - dataAfterEnd_Error = false; - - const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; - CFolderEx folderInfo; - folders.ParseFolderEx(folderIndex, folderInfo); - - if (!folderInfo.IsDecodingSupported()) - return E_NOTIMPL; - - CBindInfoEx bindInfo; - Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo); - if (!bindInfo.CalcMapsAndCheck()) - return E_NOTIMPL; - - UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex); - bool fullUnpack = true; - if (unpackSize) - { - if (*unpackSize > folderUnpackSize) - return E_FAIL; - fullUnpack = (*unpackSize == folderUnpackSize); - } - - /* - We don't need to init isEncrypted and passwordIsDefined - We must upgrade them only - - #ifndef Z7_NO_CRYPTO - isEncrypted = false; - passwordIsDefined = false; - #endif - */ - - if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev)) - { - _bindInfoPrev_Defined = false; - _mixerRef.Release(); - - #ifdef USE_MIXER_MT - #ifdef USE_MIXER_ST - if (_useMixerMT) - #endif - { - _mixerMT = new NCoderMixer2::CMixerMT(false); - _mixerRef = _mixerMT; - _mixer = _mixerMT; - } - #ifdef USE_MIXER_ST - else - #endif - #endif - { - #ifdef USE_MIXER_ST - _mixerST = new NCoderMixer2::CMixerST(false); - _mixerRef = _mixerST; - _mixer = _mixerST; - #endif - } - - RINOK(_mixer->SetBindInfo(bindInfo)) - - FOR_VECTOR(i, folderInfo.Coders) - { - const CCoderInfo &coderInfo = folderInfo.Coders[i]; - - #ifndef Z7_SFX - // we don't support RAR codecs here - if ((coderInfo.MethodID >> 8) == 0x403) - return E_NOTIMPL; - #endif - - CCreatedCoder cod; - RINOK(CreateCoder_Id( - EXTERNAL_CODECS_LOC_VARS - coderInfo.MethodID, false, cod)) - - if (coderInfo.IsSimpleCoder()) - { - if (!cod.Coder) - return E_NOTIMPL; - // CMethodId m = coderInfo.MethodID; - // isFilter = (IsFilterMethod(m) || m == k_AES); - } - else - { - if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams) - return E_NOTIMPL; - } - _mixer->AddCoder(cod); - - // now there is no codec that uses another external codec - /* - #ifdef Z7_EXTERNAL_CODECS - CMyComPtr setCompressCodecsInfo; - decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - // we must use g_ExternalCodecs also - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)); - } - #endif - */ - } - - _bindInfoPrev = bindInfo; - _bindInfoPrev_Defined = true; - } - - RINOK(_mixer->ReInit2()) - - UInt32 packStreamIndex = 0; - UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; - - unsigned i; - - #if !defined(Z7_ST) - bool mt_wasUsed = false; - #endif - - for (i = 0; i < folderInfo.Coders.Size(); i++) - { - const CCoderInfo &coderInfo = folderInfo.Coders[i]; - IUnknown *decoder = _mixer->GetCoder(i).GetUnknown(); - - // now there is no codec that uses another external codec - /* - #ifdef Z7_EXTERNAL_CODECS - { - Z7_DECL_CMyComPtr_QI_FROM(ISetCompressCodecsInfo, - setCompressCodecsInfo, decoder) - if (setCompressCodecsInfo) - { - // we must use g_ExternalCodecs also - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)) - } - } - #endif - */ - - #if !defined(Z7_ST) - if (!mt_wasUsed) - { - if (mtMode) - { - Z7_DECL_CMyComPtr_QI_FROM(ICompressSetCoderMt, - setCoderMt, decoder) - if (setCoderMt) - { - mt_wasUsed = true; - RINOK(setCoderMt->SetNumberOfThreads(numThreads)) - } - } - // if (memUsage != 0) - { - Z7_DECL_CMyComPtr_QI_FROM(ICompressSetMemLimit, - setMemLimit, decoder) - if (setMemLimit) - { - mt_wasUsed = true; - RINOK(setMemLimit->SetMemLimit(memUsage)) - } - } - } - #endif - - { - Z7_DECL_CMyComPtr_QI_FROM( - ICompressSetDecoderProperties2, - setDecoderProperties, decoder) - const CByteBuffer &props = coderInfo.Props; - const UInt32 size32 = (UInt32)props.Size(); - if (props.Size() != size32) - return E_NOTIMPL; - if (setDecoderProperties) - { - HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, size32); - if (res == E_INVALIDARG) - res = E_NOTIMPL; - RINOK(res) - } - else if (size32 != 0) - { - // v23: we fail, if decoder doesn't support properties - return E_NOTIMPL; - } - } - - #ifndef Z7_NO_CRYPTO - { - Z7_DECL_CMyComPtr_QI_FROM( - ICryptoSetPassword, - cryptoSetPassword, decoder) - if (cryptoSetPassword) - { - isEncrypted = true; - if (!getTextPassword) - return E_NOTIMPL; - CMyComBSTR_Wipe passwordBSTR; - RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)) - passwordIsDefined = true; - password.Wipe_and_Empty(); - size_t len = 0; - if (passwordBSTR) - { - password = passwordBSTR; - len = password.Len(); - } - CByteBuffer_Wipe buffer(len * 2); - const LPCOLESTR psw = passwordBSTR; - for (size_t k = 0; k < len; k++) - { - const wchar_t c = psw[k]; - ((Byte *)buffer)[k * 2] = (Byte)c; - ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); - } - RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())) - } - } - #endif - - bool finishMode = false; - { - Z7_DECL_CMyComPtr_QI_FROM( - ICompressSetFinishMode, - setFinishMode, decoder) - if (setFinishMode) - { - finishMode = fullUnpack; - RINOK(setFinishMode->SetFinishMode(BoolToUInt(finishMode))) - } - } - - UInt32 numStreams = (UInt32)coderInfo.NumStreams; - - CObjArray packSizes(numStreams); - CObjArray packSizesPointers(numStreams); - - for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++) - { - int bond = folderInfo.FindBond_for_PackStream(packStreamIndex); - - if (bond >= 0) - packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex]; - else - { - int index = folderInfo.Find_in_PackStreams(packStreamIndex); - if (index < 0) - return E_NOTIMPL; - packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index]; - packSizesPointers[j] = &packSizes[j]; - } - } - - const UInt64 *unpackSizesPointer = - (unpackSize && i == bindInfo.UnpackCoder) ? - unpackSize : - &folders.CoderUnpackSizes[unpackStreamIndexStart + i]; - - _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers, finishMode); - } - - if (outStream) - { - _mixer->SelectMainCoder(!fullUnpack); - } - - CObjectVector< CMyComPtr > inStreams; - - CMyComPtr2_Create lockedInStream; - - #ifdef USE_MIXER_MT - #ifdef USE_MIXER_ST - bool needMtLock = _useMixerMT; - #endif - #endif - - if (folderInfo.PackStreams.Size() > 1) - { - // lockedInStream.Pos = (UInt64)(Int64)-1; - // RINOK(InStream_GetPos(inStream, lockedInStream.Pos)) - RINOK(inStream->Seek((Int64)(startPos + packPositions[0]), STREAM_SEEK_SET, &lockedInStream->Pos)) - lockedInStream->Stream = inStream; - - #ifdef USE_MIXER_MT - #ifdef USE_MIXER_ST - /* - For ST-mixer mode: - If parallel input stream reading from pack streams is possible, - we must use MT-lock for packed streams. - Internal decoders in 7-Zip will not read pack streams in parallel in ST-mixer mode. - So we force to needMtLock mode only if there is unknown (external) decoder. - */ - if (!needMtLock && _mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex)) - needMtLock = true; - #endif - #endif - } - - for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) - { - CMyComPtr packStream; - const UInt64 packPos = startPos + packPositions[j]; - - if (folderInfo.PackStreams.Size() == 1) - { - RINOK(InStream_SeekSet(inStream, packPos)) - packStream = inStream; - } - else - { - #ifdef USE_MIXER_MT - #ifdef USE_MIXER_ST - if (needMtLock) - #endif - { - CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT; - packStream = lockedStreamImpSpec; - lockedStreamImpSpec->Init(lockedInStream.ClsPtr(), packPos); - } - #ifdef USE_MIXER_ST - else - #endif - #endif - { - #ifdef USE_MIXER_ST - CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST; - packStream = lockedStreamImpSpec; - lockedStreamImpSpec->Init(lockedInStream.ClsPtr(), packPos); - #endif - } - } - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - inStreams.AddNew() = streamSpec; - streamSpec->SetStream(packStream); - streamSpec->Init(packPositions[j + 1] - packPositions[j]); - } - - const unsigned num = inStreams.Size(); - CObjArray inStreamPointers(num); - for (i = 0; i < num; i++) - inStreamPointers[i] = inStreams[i]; - - if (outStream) - { - CMyComPtr progress2; - if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex)) - progress2 = new CDecProgress(compressProgress); - - ISequentialOutStream *outStreamPointer = outStream; - return _mixer->Code(inStreamPointers, &outStreamPointer, - progress2 ? (ICompressProgressInfo *)progress2 : compressProgress, - dataAfterEnd_Error); - } - - #ifdef USE_MIXER_ST - return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes); - #else - return E_FAIL; - #endif -} - -}} +// 7zDecode.cpp + +#include "StdAfx.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "7zDecode.h" + +namespace NArchive { +namespace N7z { + +Z7_CLASS_IMP_COM_1( + CDecProgress + , ICompressProgressInfo +) + CMyComPtr _progress; +public: + CDecProgress(ICompressProgressInfo *progress): _progress(progress) {} +}; + +Z7_COM7F_IMF(CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize)) +{ + return _progress->SetRatioInfo(NULL, outSize); +} + +static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi) +{ + bi.Clear(); + + bi.Bonds.ClearAndSetSize(folder.Bonds.Size()); + unsigned i; + for (i = 0; i < folder.Bonds.Size(); i++) + { + NCoderMixer2::CBond &bond = bi.Bonds[i]; + const N7z::CBond &folderBond = folder.Bonds[i]; + bond.PackIndex = folderBond.PackIndex; + bond.UnpackIndex = folderBond.UnpackIndex; + } + + bi.Coders.ClearAndSetSize(folder.Coders.Size()); + bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); + for (i = 0; i < folder.Coders.Size(); i++) + { + const CCoderInfo &coderInfo = folder.Coders[i]; + bi.Coders[i].NumStreams = coderInfo.NumStreams; + bi.CoderMethodIDs[i] = coderInfo.MethodID; + } + + /* + if (!bi.SetUnpackCoder()) + throw 1112; + */ + bi.UnpackCoder = folder.UnpackCoder; + bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size()); + for (i = 0; i < folder.PackStreams.Size(); i++) + bi.PackStreams[i] = folder.PackStreams[i]; +} + +static inline bool AreCodersEqual( + const NCoderMixer2::CCoderStreamsInfo &a1, + const NCoderMixer2::CCoderStreamsInfo &a2) +{ + return (a1.NumStreams == a2.NumStreams); +} + +static inline bool AreBondsEqual( + const NCoderMixer2::CBond &a1, + const NCoderMixer2::CBond &a2) +{ + return + (a1.PackIndex == a2.PackIndex) && + (a1.UnpackIndex == a2.UnpackIndex); +} + +static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) +{ + if (a1.Coders.Size() != a2.Coders.Size()) + return false; + unsigned i; + for (i = 0; i < a1.Coders.Size(); i++) + if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) + return false; + + if (a1.Bonds.Size() != a2.Bonds.Size()) + return false; + for (i = 0; i < a1.Bonds.Size(); i++) + if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i])) + return false; + + for (i = 0; i < a1.CoderMethodIDs.Size(); i++) + if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) + return false; + + if (a1.PackStreams.Size() != a2.PackStreams.Size()) + return false; + for (i = 0; i < a1.PackStreams.Size(); i++) + if (a1.PackStreams[i] != a2.PackStreams[i]) + return false; + + /* + if (a1.UnpackCoder != a2.UnpackCoder) + return false; + */ + return true; +} + +CDecoder::CDecoder(bool useMixerMT): + _bindInfoPrev_Defined(false) +{ + #if defined(USE_MIXER_ST) && defined(USE_MIXER_MT) + _useMixerMT = useMixerMT; + #else + UNUSED_VAR(useMixerMT) + #endif +} + + +Z7_CLASS_IMP_COM_0( + CLockedInStream +) +public: + CMyComPtr Stream; + UInt64 Pos; + + #ifdef USE_MIXER_MT + NWindows::NSynchronization::CCriticalSection CriticalSection; + #endif +}; + + +#ifdef USE_MIXER_MT + +Z7_CLASS_IMP_COM_1( + CLockedSequentialInStreamMT + , ISequentialInStream +) + CLockedInStream *_glob; + UInt64 _pos; + CMyComPtr _globRef; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _globRef = lockedInStream; + _glob = lockedInStream; + _pos = startPos; + } +}; + +Z7_COM7F_IMF(CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection); + + if (_pos != _glob->Pos) + { + RINOK(InStream_SeekSet(_glob->Stream, _pos)) + _glob->Pos = _pos; + } + + UInt32 realProcessedSize = 0; + const HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + _glob->Pos = _pos; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} + +#endif + + +#ifdef USE_MIXER_ST + +Z7_CLASS_IMP_COM_1( + CLockedSequentialInStreamST + , ISequentialInStream +) + CLockedInStream *_glob; + UInt64 _pos; + CMyComPtr _globRef; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _globRef = lockedInStream; + _glob = lockedInStream; + _pos = startPos; + } +}; + +Z7_COM7F_IMF(CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (_pos != _glob->Pos) + { + RINOK(InStream_SeekSet(_glob->Stream, _pos)) + _glob->Pos = _pos; + } + + UInt32 realProcessedSize = 0; + const HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + _glob->Pos = _pos; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} + +#endif + + + +HRESULT CDecoder::Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + UInt64 startPos, + const CFolders &folders, unsigned folderIndex, + const UInt64 *unpackSize + + , ISequentialOutStream *outStream + , ICompressProgressInfo *compressProgress + + , ISequentialInStream ** + #ifdef USE_MIXER_ST + inStreamMainRes + #endif + + , bool &dataAfterEnd_Error + + Z7_7Z_DECODER_CRYPRO_VARS_DECL + + #if !defined(Z7_ST) + , bool mtMode, UInt32 numThreads, UInt64 memUsage + #endif + ) +{ + dataAfterEnd_Error = false; + + const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; + CFolderEx folderInfo; + folders.ParseFolderEx(folderIndex, folderInfo); + + if (!folderInfo.IsDecodingSupported()) + return E_NOTIMPL; + + CBindInfoEx bindInfo; + Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo); + if (!bindInfo.CalcMapsAndCheck()) + return E_NOTIMPL; + + UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex); + bool fullUnpack = true; + if (unpackSize) + { + if (*unpackSize > folderUnpackSize) + return E_FAIL; + fullUnpack = (*unpackSize == folderUnpackSize); + } + + /* + We don't need to init isEncrypted and passwordIsDefined + We must upgrade them only + + #ifndef Z7_NO_CRYPTO + isEncrypted = false; + passwordIsDefined = false; + #endif + */ + + if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev)) + { + _bindInfoPrev_Defined = false; + _mixerRef.Release(); + + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_useMixerMT) + #endif + { + _mixerMT = new NCoderMixer2::CMixerMT(false); + _mixerRef = _mixerMT; + _mixer = _mixerMT; + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + _mixerST = new NCoderMixer2::CMixerST(false); + _mixerRef = _mixerST; + _mixer = _mixerST; + #endif + } + + RINOK(_mixer->SetBindInfo(bindInfo)) + + FOR_VECTOR(i, folderInfo.Coders) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + + #ifndef Z7_SFX + // we don't support RAR codecs here + if ((coderInfo.MethodID >> 8) == 0x403) + return E_NOTIMPL; + #endif + + CCreatedCoder cod; + RINOK(CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + coderInfo.MethodID, false, cod)) + + if (coderInfo.IsSimpleCoder()) + { + if (!cod.Coder) + return E_NOTIMPL; + // CMethodId m = coderInfo.MethodID; + // isFilter = (IsFilterMethod(m) || m == k_AES); + } + else + { + if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams) + return E_NOTIMPL; + } + _mixer->AddCoder(cod); + + // now there is no codec that uses another external codec + /* + #ifdef Z7_EXTERNAL_CODECS + CMyComPtr setCompressCodecsInfo; + decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + // we must use g_ExternalCodecs also + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)); + } + #endif + */ + } + + _bindInfoPrev = bindInfo; + _bindInfoPrev_Defined = true; + } + + RINOK(_mixer->ReInit2()) + + UInt32 packStreamIndex = 0; + UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; + + unsigned i; + + #if !defined(Z7_ST) + bool mt_wasUsed = false; + #endif + + for (i = 0; i < folderInfo.Coders.Size(); i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + IUnknown *decoder = _mixer->GetCoder(i).GetUnknown(); + + // now there is no codec that uses another external codec + /* + #ifdef Z7_EXTERNAL_CODECS + { + Z7_DECL_CMyComPtr_QI_FROM(ISetCompressCodecsInfo, + setCompressCodecsInfo, decoder) + if (setCompressCodecsInfo) + { + // we must use g_ExternalCodecs also + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)) + } + } + #endif + */ + + #if !defined(Z7_ST) + if (!mt_wasUsed) + { + if (mtMode) + { + Z7_DECL_CMyComPtr_QI_FROM(ICompressSetCoderMt, + setCoderMt, decoder) + if (setCoderMt) + { + mt_wasUsed = true; + RINOK(setCoderMt->SetNumberOfThreads(numThreads)) + } + } + // if (memUsage != 0) + { + Z7_DECL_CMyComPtr_QI_FROM(ICompressSetMemLimit, + setMemLimit, decoder) + if (setMemLimit) + { + mt_wasUsed = true; + RINOK(setMemLimit->SetMemLimit(memUsage)) + } + } + } + #endif + + { + Z7_DECL_CMyComPtr_QI_FROM( + ICompressSetDecoderProperties2, + setDecoderProperties, decoder) + const CByteBuffer &props = coderInfo.Props; + const UInt32 size32 = (UInt32)props.Size(); + if (props.Size() != size32) + return E_NOTIMPL; + if (setDecoderProperties) + { + HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, size32); + if (res == E_INVALIDARG) + res = E_NOTIMPL; + RINOK(res) + } + else if (size32 != 0) + { + // v23: we fail, if decoder doesn't support properties + return E_NOTIMPL; + } + } + + #ifndef Z7_NO_CRYPTO + { + Z7_DECL_CMyComPtr_QI_FROM( + ICryptoSetPassword, + cryptoSetPassword, decoder) + if (cryptoSetPassword) + { + isEncrypted = true; + if (!getTextPassword) + return E_NOTIMPL; + CMyComBSTR_Wipe passwordBSTR; + RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)) + passwordIsDefined = true; + password.Wipe_and_Empty(); + size_t len = 0; + if (passwordBSTR) + { + password = passwordBSTR; + len = password.Len(); + } + CByteBuffer_Wipe buffer(len * 2); + const LPCOLESTR psw = passwordBSTR; + for (size_t k = 0; k < len; k++) + { + const wchar_t c = psw[k]; + ((Byte *)buffer)[k * 2] = (Byte)c; + ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())) + } + } + #endif + + bool finishMode = false; + { + Z7_DECL_CMyComPtr_QI_FROM( + ICompressSetFinishMode, + setFinishMode, decoder) + if (setFinishMode) + { + finishMode = fullUnpack; + RINOK(setFinishMode->SetFinishMode(BoolToUInt(finishMode))) + } + } + + UInt32 numStreams = (UInt32)coderInfo.NumStreams; + + CObjArray packSizes(numStreams); + CObjArray packSizesPointers(numStreams); + + for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++) + { + int bond = folderInfo.FindBond_for_PackStream(packStreamIndex); + + if (bond >= 0) + packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex]; + else + { + int index = folderInfo.Find_in_PackStreams(packStreamIndex); + if (index < 0) + return E_NOTIMPL; + packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index]; + packSizesPointers[j] = &packSizes[j]; + } + } + + const UInt64 *unpackSizesPointer = + (unpackSize && i == bindInfo.UnpackCoder) ? + unpackSize : + &folders.CoderUnpackSizes[unpackStreamIndexStart + i]; + + _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers, finishMode); + } + + if (outStream) + { + _mixer->SelectMainCoder(!fullUnpack); + } + + CObjectVector< CMyComPtr > inStreams; + + CMyComPtr2_Create lockedInStream; + + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + bool needMtLock = _useMixerMT; + #endif + #endif + + if (folderInfo.PackStreams.Size() > 1) + { + // lockedInStream.Pos = (UInt64)(Int64)-1; + // RINOK(InStream_GetPos(inStream, lockedInStream.Pos)) + RINOK(inStream->Seek((Int64)(startPos + packPositions[0]), STREAM_SEEK_SET, &lockedInStream->Pos)) + lockedInStream->Stream = inStream; + + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + /* + For ST-mixer mode: + If parallel input stream reading from pack streams is possible, + we must use MT-lock for packed streams. + Internal decoders in 7-Zip will not read pack streams in parallel in ST-mixer mode. + So we force to needMtLock mode only if there is unknown (external) decoder. + */ + if (!needMtLock && _mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex)) + needMtLock = true; + #endif + #endif + } + + for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) + { + CMyComPtr packStream; + const UInt64 packPos = startPos + packPositions[j]; + + if (folderInfo.PackStreams.Size() == 1) + { + RINOK(InStream_SeekSet(inStream, packPos)) + packStream = inStream; + } + else + { + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (needMtLock) + #endif + { + CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT; + packStream = lockedStreamImpSpec; + lockedStreamImpSpec->Init(lockedInStream.ClsPtr(), packPos); + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST; + packStream = lockedStreamImpSpec; + lockedStreamImpSpec->Init(lockedInStream.ClsPtr(), packPos); + #endif + } + } + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + inStreams.AddNew() = streamSpec; + streamSpec->SetStream(packStream); + streamSpec->Init(packPositions[j + 1] - packPositions[j]); + } + + const unsigned num = inStreams.Size(); + CObjArray inStreamPointers(num); + for (i = 0; i < num; i++) + inStreamPointers[i] = inStreams[i]; + + if (outStream) + { + CMyComPtr progress2; + if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex)) + progress2 = new CDecProgress(compressProgress); + + ISequentialOutStream *outStreamPointer = outStream; + return _mixer->Code(inStreamPointers, &outStreamPointer, + progress2 ? (ICompressProgressInfo *)progress2 : compressProgress, + dataAfterEnd_Error); + } + + #ifdef USE_MIXER_ST + return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes); + #else + return E_FAIL; + #endif +} + +}} diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h index 295786c94..ee9d9c255 100644 --- a/CPP/7zip/Archive/7z/7zDecode.h +++ b/CPP/7zip/Archive/7z/7zDecode.h @@ -1,73 +1,73 @@ -// 7zDecode.h - -#ifndef ZIP7_INC_7Z_DECODE_H -#define ZIP7_INC_7Z_DECODE_H - -#include "../Common/CoderMixer2.h" - -#include "7zIn.h" - -namespace NArchive { -namespace N7z { - -struct CBindInfoEx: public NCoderMixer2::CBindInfo -{ - CRecordVector CoderMethodIDs; - - void Clear() - { - CBindInfo::Clear(); - CoderMethodIDs.Clear(); - } -}; - -class CDecoder -{ - bool _bindInfoPrev_Defined; - #ifdef USE_MIXER_ST - #ifdef USE_MIXER_MT - bool _useMixerMT; - #endif - #endif - CBindInfoEx _bindInfoPrev; - - #ifdef USE_MIXER_ST - NCoderMixer2::CMixerST *_mixerST; - #endif - - #ifdef USE_MIXER_MT - NCoderMixer2::CMixerMT *_mixerMT; - #endif - - NCoderMixer2::CMixer *_mixer; - CMyComPtr _mixerRef; - -public: - - CDecoder(bool useMixerMT); - - HRESULT Decode( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, - UInt64 startPos, - const CFolders &folders, unsigned folderIndex, - const UInt64 *unpackSize // if (!unpackSize), then full folder is required - // if (unpackSize), then only *unpackSize bytes from folder are required - - , ISequentialOutStream *outStream - , ICompressProgressInfo *compressProgress - - , ISequentialInStream **inStreamMainRes - , bool &dataAfterEnd_Error - - Z7_7Z_DECODER_CRYPRO_VARS_DECL - - #if !defined(Z7_ST) - , bool mtMode, UInt32 numThreads, UInt64 memUsage - #endif - ); -}; - -}} - -#endif +// 7zDecode.h + +#ifndef ZIP7_INC_7Z_DECODE_H +#define ZIP7_INC_7Z_DECODE_H + +#include "../Common/CoderMixer2.h" + +#include "7zIn.h" + +namespace NArchive { +namespace N7z { + +struct CBindInfoEx: public NCoderMixer2::CBindInfo +{ + CRecordVector CoderMethodIDs; + + void Clear() + { + CBindInfo::Clear(); + CoderMethodIDs.Clear(); + } +}; + +class CDecoder +{ + bool _bindInfoPrev_Defined; + #ifdef USE_MIXER_ST + #ifdef USE_MIXER_MT + bool _useMixerMT; + #endif + #endif + CBindInfoEx _bindInfoPrev; + + #ifdef USE_MIXER_ST + NCoderMixer2::CMixerST *_mixerST; + #endif + + #ifdef USE_MIXER_MT + NCoderMixer2::CMixerMT *_mixerMT; + #endif + + NCoderMixer2::CMixer *_mixer; + CMyComPtr _mixerRef; + +public: + + CDecoder(bool useMixerMT); + + HRESULT Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + UInt64 startPos, + const CFolders &folders, unsigned folderIndex, + const UInt64 *unpackSize // if (!unpackSize), then full folder is required + // if (unpackSize), then only *unpackSize bytes from folder are required + + , ISequentialOutStream *outStream + , ICompressProgressInfo *compressProgress + + , ISequentialInStream **inStreamMainRes + , bool &dataAfterEnd_Error + + Z7_7Z_DECODER_CRYPRO_VARS_DECL + + #if !defined(Z7_ST) + , bool mtMode, UInt32 numThreads, UInt64 memUsage + #endif + ); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index a9ad238f5..71d1ddb79 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -1,721 +1,721 @@ -// 7zEncode.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/FilterCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/InOutTempBuffer.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" - -#include "7zEncode.h" -#include "7zSpecStream.h" - -namespace NArchive { -namespace N7z { - -void CEncoder::InitBindConv() -{ - unsigned numIn = _bindInfo.Coders.Size(); - - SrcIn_to_DestOut.ClearAndSetSize(numIn); - DestOut_to_SrcIn.ClearAndSetSize(numIn); - - unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams(); - SrcOut_to_DestIn.ClearAndSetSize(numOut); - // _DestIn_to_SrcOut.ClearAndSetSize(numOut); - - UInt32 destIn = 0; - UInt32 destOut = 0; - - for (unsigned i = _bindInfo.Coders.Size(); i != 0;) - { - i--; - - const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i]; - - numIn--; - numOut -= coder.NumStreams; - - SrcIn_to_DestOut[numIn] = destOut; - DestOut_to_SrcIn[destOut] = numIn; - - destOut++; - - for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++) - { - UInt32 index = numOut + j; - SrcOut_to_DestIn[index] = destIn; - // _DestIn_to_SrcOut[destIn] = index; - } - } -} - -void CEncoder::SetFolder(CFolder &folder) -{ - folder.Bonds.SetSize(_bindInfo.Bonds.Size()); - - unsigned i; - - for (i = 0; i < _bindInfo.Bonds.Size(); i++) - { - CBond &fb = folder.Bonds[i]; - const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i]; - fb.PackIndex = SrcOut_to_DestIn[mixerBond.PackIndex]; - fb.UnpackIndex = SrcIn_to_DestOut[mixerBond.UnpackIndex]; - } - - folder.Coders.SetSize(_bindInfo.Coders.Size()); - - for (i = 0; i < _bindInfo.Coders.Size(); i++) - { - CCoderInfo &coderInfo = folder.Coders[i]; - const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i]; - - coderInfo.NumStreams = coderStreamsInfo.NumStreams; - coderInfo.MethodID = _decompressionMethods[i]; - // we don't free coderInfo.Props here. So coderInfo.Props can be non-empty. - } - - folder.PackStreams.SetSize(_bindInfo.PackStreams.Size()); - - for (i = 0; i < _bindInfo.PackStreams.Size(); i++) - folder.PackStreams[i] = SrcOut_to_DestIn[_bindInfo.PackStreams[i]]; -} - - - -static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) -{ - Z7_DECL_CMyComPtr_QI_FROM( - ICompressSetCoderProperties, - setCoderProperties, coder) - if (setCoderProperties) - return props.SetCoderProps(setCoderProperties, dataSizeReduce); - return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; -} - - - -void CMtEncMultiProgress::Init(ICompressProgressInfo *progress) -{ - _progress = progress; - OutSize = 0; -} - -Z7_COM7F_IMF(CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) -{ - UInt64 outSize2; - { - #ifndef Z7_ST - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - #endif - outSize2 = OutSize; - } - - if (_progress) - return _progress->SetRatioInfo(inSize, &outSize2); - - return S_OK; -} - - - -HRESULT CEncoder::CreateMixerCoder( - DECL_EXTERNAL_CODECS_LOC_VARS - const UInt64 *inSizeForReduce) -{ - #ifdef USE_MIXER_MT - #ifdef USE_MIXER_ST - if (_options.MultiThreadMixer) - #endif - { - _mixerMT = new NCoderMixer2::CMixerMT(true); - _mixerRef = _mixerMT; - _mixer = _mixerMT; - } - #ifdef USE_MIXER_ST - else - #endif - #endif - { - #ifdef USE_MIXER_ST - _mixerST = new NCoderMixer2::CMixerST(true); - _mixerRef = _mixerST; - _mixer = _mixerST; - #endif - } - - RINOK(_mixer->SetBindInfo(_bindInfo)) - - FOR_VECTOR (m, _options.Methods) - { - const CMethodFull &methodFull = _options.Methods[m]; - - CCreatedCoder cod; - - if (methodFull.CodecIndex >= 0) - { - RINOK(CreateCoder_Index( - EXTERNAL_CODECS_LOC_VARS - (unsigned)methodFull.CodecIndex, true, cod)) - } - else - { - RINOK(CreateCoder_Id( - EXTERNAL_CODECS_LOC_VARS - methodFull.Id, true, cod)) - } - - if (!cod.Coder && !cod.Coder2) - { - return E_NOTIMPL; // unsupported method, if encoder - // return E_FAIL; - } - - if (cod.NumStreams != methodFull.NumStreams) - return E_FAIL; - - CMyComPtr encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2; - - #ifndef Z7_ST - if (methodFull.Set_NumThreads) - { - CMyComPtr setCoderMt; - encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); - if (setCoderMt) - { - RINOK(setCoderMt->SetNumberOfThreads( - /* _options.NumThreads */ - methodFull.NumThreads - )) - } - } - #endif - - RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)) - - /* - CMyComPtr resetSalt; - encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); - if (resetSalt) - { - resetSalt->ResetSalt(); - } - */ - - // now there is no codec that uses another external codec - /* - #ifdef Z7_EXTERNAL_CODECS - CMyComPtr setCompressCodecsInfo; - encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - // we must use g_ExternalCodecs also - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)); - } - #endif - */ - - CMyComPtr cryptoSetPassword; - encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); - - if (cryptoSetPassword) - { - const unsigned sizeInBytes = _options.Password.Len() * 2; - CByteBuffer_Wipe buffer(sizeInBytes); - for (unsigned i = 0; i < _options.Password.Len(); i++) - { - wchar_t c = _options.Password[i]; - ((Byte *)buffer)[i * 2] = (Byte)c; - ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); - } - RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)sizeInBytes)) - } - - _mixer->AddCoder(cod); - } - return S_OK; -} - - - -Z7_CLASS_IMP_COM_1( - CSequentialOutTempBufferImp2 - , ISequentialOutStream -) -public: - CInOutTempBuffer TempBuffer; - CMtEncMultiProgress *_mtProgressSpec; - - CSequentialOutTempBufferImp2(): _mtProgressSpec(NULL) {} -}; - -Z7_COM7F_IMF(CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)) -{ - COM_TRY_BEGIN - if (processed) - *processed = 0; - RINOK(TempBuffer.Write_HRESULT(data, size)) - if (processed) - *processed = size; - if (_mtProgressSpec) - _mtProgressSpec->AddOutSize(size); - return S_OK; - COM_TRY_END -} - - -Z7_CLASS_IMP_COM_1( - CSequentialOutMtNotify - , ISequentialOutStream -) -public: - CMyComPtr _stream; - CMtEncMultiProgress *_mtProgressSpec; - - CSequentialOutMtNotify(): _mtProgressSpec(NULL) {} -}; - -Z7_COM7F_IMF(CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)) -{ - UInt32 realProcessed = 0; - HRESULT res = _stream->Write(data, size, &realProcessed); - if (processed) - *processed = realProcessed; - if (_mtProgressSpec) - _mtProgressSpec->AddOutSize(size); - return res; -} - - -static HRESULT FillProps_from_Coder(IUnknown *coder, CByteBuffer &props) -{ - Z7_DECL_CMyComPtr_QI_FROM( - ICompressWriteCoderProperties, - writeCoderProperties, coder) - if (writeCoderProperties) - { - CMyComPtr2_Create outStreamSpec; - outStreamSpec->Init(); - RINOK(writeCoderProperties->WriteCoderProperties(outStreamSpec)) - outStreamSpec->CopyToBuffer(props); - } - else - props.Free(); - return S_OK; -} - -HRESULT CEncoder::Encode1( - DECL_EXTERNAL_CODECS_LOC_VARS - ISequentialInStream *inStream, - // const UInt64 *inStreamSize, - const UInt64 *inSizeForReduce, - UInt64 expectedDataSize, - CFolder &folderItem, - // CRecordVector &coderUnpackSizes, - // UInt64 &unpackSize, - ISequentialOutStream *outStream, - CRecordVector &packSizes, - ICompressProgressInfo *compressProgress) -{ - RINOK(EncoderConstr()) - - if (!_mixerRef) - { - RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)) - } - - RINOK(_mixer->ReInit2()) - - CMyComPtr2 mtProgress; - CMyComPtr2 mtOutStreamNotify; - - CRecordVector tempBufferSpecs; - CObjectVector > tempBuffers; - - unsigned i; - - for (i = 1; i < _bindInfo.PackStreams.Size(); i++) - { - CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2(); - CMyComPtr tempBuffer = tempBufferSpec; - tempBufferSpecs.Add(tempBufferSpec); - tempBuffers.Add(tempBuffer); - } - - const unsigned numMethods = _bindInfo.Coders.Size(); - - for (i = 0; i < numMethods; i++) - _mixer->SetCoderInfo(i, NULL, NULL, false); - - - /* inStreamSize can be used by BCJ2 to set optimal range of conversion. - But current BCJ2 encoder uses also another way to check exact size of current file. - So inStreamSize is not required. */ - - /* - if (inStreamSize) - _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL); - */ - - - /* - CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; - CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; - */ - - CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; - CMyComPtr outStreamSizeCount; - - // inStreamSizeCountSpec->Init(inStream); - - // ISequentialInStream *inStreamPointer = inStreamSizeCount; - ISequentialInStream *inStreamPointer = inStream; - - CRecordVector outStreamPointers; - - SetFolder(folderItem); - - for (i = 0; i < numMethods; i++) - { - IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); - /* - { - CEncoder *sfEncoder = NULL; - Z7_DECL_CMyComPtr_QI_FROM( - IGetSfEncoderInternal, - sf, coder) - if (sf) - { - RINOK(sf->GetSfEncoder(&sfEncoder)); - if (!sfEncoder) - return E_FAIL; - - } - } - */ - /* - #ifdef Z7_EXTERNAL_CODECS - { - Z7_DECL_CMyComPtr_QI_FROM( - ISetCompressCodecsInfo, - setCompressCodecsInfo, coder) - if (setCompressCodecsInfo) - { - // we must use g_ExternalCodecs also - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)) - } - } - #endif - */ - { - Z7_DECL_CMyComPtr_QI_FROM( - ICryptoResetInitVector, - resetInitVector, coder) - if (resetInitVector) - { - RINOK(resetInitVector->ResetInitVector()) - } - } - { - Z7_DECL_CMyComPtr_QI_FROM( - ICompressSetCoderPropertiesOpt, - optProps, coder) - if (optProps) - { - const PROPID propID = NCoderPropID::kExpectedDataSize; - NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; - RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)) - } - } - // we must write properties from coder after ResetInitVector() - RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props)) - } - - _mixer->SelectMainCoder(false); - const UInt32 mainCoder = _mixer->MainCoderIndex; - - bool useMtProgress = false; - if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder)) - { - #ifdef Z7_ST - if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder)) - #endif - useMtProgress = true; - } - - if (useMtProgress) - { - mtProgress.SetFromCls(new CMtEncMultiProgress); - mtProgress->Init(compressProgress); - - mtOutStreamNotify.SetFromCls(new CSequentialOutMtNotify); - mtOutStreamNotify->_stream = outStream; - mtOutStreamNotify->_mtProgressSpec = mtProgress.ClsPtr(); - - FOR_VECTOR (t, tempBufferSpecs) - { - tempBufferSpecs[t]->_mtProgressSpec = mtProgress.ClsPtr(); - } - } - - - if (_bindInfo.PackStreams.Size() != 0) - { - outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; - outStreamSizeCount = outStreamSizeCountSpec; - outStreamSizeCountSpec->SetStream(mtOutStreamNotify.IsDefined() ? - mtOutStreamNotify.Interface() : outStream); - outStreamSizeCountSpec->Init(); - outStreamPointers.Add(outStreamSizeCount); - } - - for (i = 1; i < _bindInfo.PackStreams.Size(); i++) - outStreamPointers.Add(tempBuffers[i - 1]); - - bool dataAfterEnd_Error; - - RINOK(_mixer->Code( - &inStreamPointer, - outStreamPointers.ConstData(), - mtProgress.IsDefined() ? mtProgress.Interface() : - compressProgress, dataAfterEnd_Error)) - - if (_bindInfo.PackStreams.Size() != 0) - packSizes.Add(outStreamSizeCountSpec->GetSize()); - - for (i = 1; i < _bindInfo.PackStreams.Size(); i++) - { - CInOutTempBuffer &iotb = tempBufferSpecs[i - 1]->TempBuffer; - RINOK(iotb.WriteToStream(outStream)) - packSizes.Add(iotb.GetDataSize()); - } - - /* Code() in some future codec can change properties. - v23: so we fill properties again after Code() */ - for (i = 0; i < numMethods; i++) - { - IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); - RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props)) - } - - return S_OK; -} - - -void CEncoder::Encode_Post( - UInt64 unpackSize, - CRecordVector &coderUnpackSizes) -{ - // unpackSize = 0; - for (unsigned i = 0; i < _bindInfo.Coders.Size(); i++) - { - const int bond = _bindInfo.FindBond_for_UnpackStream(DestOut_to_SrcIn[i]); - UInt64 streamSize; - if (bond < 0) - { - // streamSize = inStreamSizeCountSpec->GetSize(); - // unpackSize = streamSize; - streamSize = unpackSize; - } - else - streamSize = _mixer->GetBondStreamSize((unsigned)bond); - coderUnpackSizes.Add(streamSize); - } -} - - -CEncoder::CEncoder(const CCompressionMethodMode &options): - _constructed(false) -{ - if (options.IsEmpty()) - throw 1; - - _options = options; - - #ifdef USE_MIXER_ST - _mixerST = NULL; - #endif - - #ifdef USE_MIXER_MT - _mixerMT = NULL; - #endif - - _mixer = NULL; -} - - -HRESULT CEncoder::EncoderConstr() -{ - if (_constructed) - return S_OK; - if (_options.Methods.IsEmpty()) - { - // it has only password method; - if (!_options.PasswordIsDefined) - throw 1; - if (!_options.Bonds.IsEmpty()) - throw 1; - - CMethodFull method; - method.Id = k_AES; - method.NumStreams = 1; - _options.Methods.Add(method); - - NCoderMixer2::CCoderStreamsInfo coderStreamsInfo; - coderStreamsInfo.NumStreams = 1; - _bindInfo.Coders.Add(coderStreamsInfo); - - _bindInfo.PackStreams.Add(0); - _bindInfo.UnpackCoder = 0; - } - else - { - - UInt32 numOutStreams = 0; - unsigned i; - - for (i = 0; i < _options.Methods.Size(); i++) - { - const CMethodFull &methodFull = _options.Methods[i]; - NCoderMixer2::CCoderStreamsInfo cod; - - cod.NumStreams = methodFull.NumStreams; - - if (_options.Bonds.IsEmpty()) - { - // if there are no bonds in options, we create bonds via first streams of coders - if (i != _options.Methods.Size() - 1) - { - NCoderMixer2::CBond bond; - bond.PackIndex = numOutStreams; - bond.UnpackIndex = i + 1; // it's next coder - _bindInfo.Bonds.Add(bond); - } - else if (cod.NumStreams != 0) - _bindInfo.PackStreams.Insert(0, numOutStreams); - - for (UInt32 j = 1; j < cod.NumStreams; j++) - _bindInfo.PackStreams.Add(numOutStreams + j); - } - - numOutStreams += cod.NumStreams; - - _bindInfo.Coders.Add(cod); - } - - if (!_options.Bonds.IsEmpty()) - { - for (i = 0; i < _options.Bonds.Size(); i++) - { - NCoderMixer2::CBond mixerBond; - const CBond2 &bond = _options.Bonds[i]; - if (bond.InCoder >= _bindInfo.Coders.Size() - || bond.OutCoder >= _bindInfo.Coders.Size() - || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams) - return E_INVALIDARG; - mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream; - mixerBond.UnpackIndex = bond.InCoder; - _bindInfo.Bonds.Add(mixerBond); - } - - for (i = 0; i < numOutStreams; i++) - if (_bindInfo.FindBond_for_PackStream(i) == -1) - _bindInfo.PackStreams.Add(i); - } - - if (!_bindInfo.SetUnpackCoder()) - return E_INVALIDARG; - - if (!_bindInfo.CalcMapsAndCheck()) - return E_INVALIDARG; - - if (_bindInfo.PackStreams.Size() != 1) - { - /* main_PackStream is pack stream of main path of coders tree. - We find main_PackStream, and place to start of list of out streams. - It allows to use more optimal memory usage for temp buffers, - if main_PackStream is largest stream. */ - - UInt32 ci = _bindInfo.UnpackCoder; - - for (;;) - { - if (_bindInfo.Coders[ci].NumStreams == 0) - break; - - const UInt32 outIndex = _bindInfo.Coder_to_Stream[ci]; - const int bond = _bindInfo.FindBond_for_PackStream(outIndex); - if (bond >= 0) - { - ci = _bindInfo.Bonds[(unsigned)bond].UnpackIndex; - continue; - } - - const int si = _bindInfo.FindStream_in_PackStreams(outIndex); - if (si >= 0) - _bindInfo.PackStreams.MoveToFront((unsigned)si); - break; - } - } - - if (_options.PasswordIsDefined) - { - unsigned numCryptoStreams = _bindInfo.PackStreams.Size(); - - unsigned numInStreams = _bindInfo.Coders.Size(); - - for (i = 0; i < numCryptoStreams; i++) - { - NCoderMixer2::CBond bond; - bond.UnpackIndex = numInStreams + i; - bond.PackIndex = _bindInfo.PackStreams[i]; - _bindInfo.Bonds.Add(bond); - } - _bindInfo.PackStreams.Clear(); - - /* - if (numCryptoStreams == 0) - numCryptoStreams = 1; - */ - - for (i = 0; i < numCryptoStreams; i++) - { - CMethodFull method; - method.NumStreams = 1; - method.Id = k_AES; - _options.Methods.Add(method); - - NCoderMixer2::CCoderStreamsInfo cod; - cod.NumStreams = 1; - _bindInfo.Coders.Add(cod); - - _bindInfo.PackStreams.Add(numOutStreams++); - } - } - - } - - for (unsigned i = _options.Methods.Size(); i != 0;) - _decompressionMethods.Add(_options.Methods[--i].Id); - - if (_bindInfo.Coders.Size() > 16) - return E_INVALIDARG; - if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16) - return E_INVALIDARG; - - if (!_bindInfo.CalcMapsAndCheck()) - return E_INVALIDARG; - - InitBindConv(); - _constructed = true; - return S_OK; -} - -CEncoder::~CEncoder() {} - -}} +// 7zEncode.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/InOutTempBuffer.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" + +#include "7zEncode.h" +#include "7zSpecStream.h" + +namespace NArchive { +namespace N7z { + +void CEncoder::InitBindConv() +{ + unsigned numIn = _bindInfo.Coders.Size(); + + SrcIn_to_DestOut.ClearAndSetSize(numIn); + DestOut_to_SrcIn.ClearAndSetSize(numIn); + + unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams(); + SrcOut_to_DestIn.ClearAndSetSize(numOut); + // _DestIn_to_SrcOut.ClearAndSetSize(numOut); + + UInt32 destIn = 0; + UInt32 destOut = 0; + + for (unsigned i = _bindInfo.Coders.Size(); i != 0;) + { + i--; + + const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i]; + + numIn--; + numOut -= coder.NumStreams; + + SrcIn_to_DestOut[numIn] = destOut; + DestOut_to_SrcIn[destOut] = numIn; + + destOut++; + + for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++) + { + UInt32 index = numOut + j; + SrcOut_to_DestIn[index] = destIn; + // _DestIn_to_SrcOut[destIn] = index; + } + } +} + +void CEncoder::SetFolder(CFolder &folder) +{ + folder.Bonds.SetSize(_bindInfo.Bonds.Size()); + + unsigned i; + + for (i = 0; i < _bindInfo.Bonds.Size(); i++) + { + CBond &fb = folder.Bonds[i]; + const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i]; + fb.PackIndex = SrcOut_to_DestIn[mixerBond.PackIndex]; + fb.UnpackIndex = SrcIn_to_DestOut[mixerBond.UnpackIndex]; + } + + folder.Coders.SetSize(_bindInfo.Coders.Size()); + + for (i = 0; i < _bindInfo.Coders.Size(); i++) + { + CCoderInfo &coderInfo = folder.Coders[i]; + const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i]; + + coderInfo.NumStreams = coderStreamsInfo.NumStreams; + coderInfo.MethodID = _decompressionMethods[i]; + // we don't free coderInfo.Props here. So coderInfo.Props can be non-empty. + } + + folder.PackStreams.SetSize(_bindInfo.PackStreams.Size()); + + for (i = 0; i < _bindInfo.PackStreams.Size(); i++) + folder.PackStreams[i] = SrcOut_to_DestIn[_bindInfo.PackStreams[i]]; +} + + + +static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder) +{ + Z7_DECL_CMyComPtr_QI_FROM( + ICompressSetCoderProperties, + setCoderProperties, coder) + if (setCoderProperties) + return props.SetCoderProps(setCoderProperties, dataSizeReduce); + return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK; +} + + + +void CMtEncMultiProgress::Init(ICompressProgressInfo *progress) +{ + _progress = progress; + OutSize = 0; +} + +Z7_COM7F_IMF(CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) +{ + UInt64 outSize2; + { + #ifndef Z7_ST + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + #endif + outSize2 = OutSize; + } + + if (_progress) + return _progress->SetRatioInfo(inSize, &outSize2); + + return S_OK; +} + + + +HRESULT CEncoder::CreateMixerCoder( + DECL_EXTERNAL_CODECS_LOC_VARS + const UInt64 *inSizeForReduce) +{ + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_options.MultiThreadMixer) + #endif + { + _mixerMT = new NCoderMixer2::CMixerMT(true); + _mixerRef = _mixerMT; + _mixer = _mixerMT; + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + _mixerST = new NCoderMixer2::CMixerST(true); + _mixerRef = _mixerST; + _mixer = _mixerST; + #endif + } + + RINOK(_mixer->SetBindInfo(_bindInfo)) + + FOR_VECTOR (m, _options.Methods) + { + const CMethodFull &methodFull = _options.Methods[m]; + + CCreatedCoder cod; + + if (methodFull.CodecIndex >= 0) + { + RINOK(CreateCoder_Index( + EXTERNAL_CODECS_LOC_VARS + (unsigned)methodFull.CodecIndex, true, cod)) + } + else + { + RINOK(CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + methodFull.Id, true, cod)) + } + + if (!cod.Coder && !cod.Coder2) + { + return E_NOTIMPL; // unsupported method, if encoder + // return E_FAIL; + } + + if (cod.NumStreams != methodFull.NumStreams) + return E_FAIL; + + CMyComPtr encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2; + + #ifndef Z7_ST + if (methodFull.Set_NumThreads) + { + CMyComPtr setCoderMt; + encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads( + /* _options.NumThreads */ + methodFull.NumThreads + )) + } + } + #endif + + RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon)) + + /* + CMyComPtr resetSalt; + encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt); + if (resetSalt) + { + resetSalt->ResetSalt(); + } + */ + + // now there is no codec that uses another external codec + /* + #ifdef Z7_EXTERNAL_CODECS + CMyComPtr setCompressCodecsInfo; + encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + // we must use g_ExternalCodecs also + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)); + } + #endif + */ + + CMyComPtr cryptoSetPassword; + encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); + + if (cryptoSetPassword) + { + const unsigned sizeInBytes = _options.Password.Len() * 2; + CByteBuffer_Wipe buffer(sizeInBytes); + for (unsigned i = 0; i < _options.Password.Len(); i++) + { + wchar_t c = _options.Password[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)sizeInBytes)) + } + + _mixer->AddCoder(cod); + } + return S_OK; +} + + + +Z7_CLASS_IMP_COM_1( + CSequentialOutTempBufferImp2 + , ISequentialOutStream +) +public: + CInOutTempBuffer TempBuffer; + CMtEncMultiProgress *_mtProgressSpec; + + CSequentialOutTempBufferImp2(): _mtProgressSpec(NULL) {} +}; + +Z7_COM7F_IMF(CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)) +{ + COM_TRY_BEGIN + if (processed) + *processed = 0; + RINOK(TempBuffer.Write_HRESULT(data, size)) + if (processed) + *processed = size; + if (_mtProgressSpec) + _mtProgressSpec->AddOutSize(size); + return S_OK; + COM_TRY_END +} + + +Z7_CLASS_IMP_COM_1( + CSequentialOutMtNotify + , ISequentialOutStream +) +public: + CMyComPtr _stream; + CMtEncMultiProgress *_mtProgressSpec; + + CSequentialOutMtNotify(): _mtProgressSpec(NULL) {} +}; + +Z7_COM7F_IMF(CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)) +{ + UInt32 realProcessed = 0; + HRESULT res = _stream->Write(data, size, &realProcessed); + if (processed) + *processed = realProcessed; + if (_mtProgressSpec) + _mtProgressSpec->AddOutSize(size); + return res; +} + + +static HRESULT FillProps_from_Coder(IUnknown *coder, CByteBuffer &props) +{ + Z7_DECL_CMyComPtr_QI_FROM( + ICompressWriteCoderProperties, + writeCoderProperties, coder) + if (writeCoderProperties) + { + CMyComPtr2_Create outStreamSpec; + outStreamSpec->Init(); + RINOK(writeCoderProperties->WriteCoderProperties(outStreamSpec)) + outStreamSpec->CopyToBuffer(props); + } + else + props.Free(); + return S_OK; +} + +HRESULT CEncoder::Encode1( + DECL_EXTERNAL_CODECS_LOC_VARS + ISequentialInStream *inStream, + // const UInt64 *inStreamSize, + const UInt64 *inSizeForReduce, + UInt64 expectedDataSize, + CFolder &folderItem, + // CRecordVector &coderUnpackSizes, + // UInt64 &unpackSize, + ISequentialOutStream *outStream, + CRecordVector &packSizes, + ICompressProgressInfo *compressProgress) +{ + RINOK(EncoderConstr()) + + if (!_mixerRef) + { + RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)) + } + + RINOK(_mixer->ReInit2()) + + CMyComPtr2 mtProgress; + CMyComPtr2 mtOutStreamNotify; + + CRecordVector tempBufferSpecs; + CObjectVector > tempBuffers; + + unsigned i; + + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) + { + CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2(); + CMyComPtr tempBuffer = tempBufferSpec; + tempBufferSpecs.Add(tempBufferSpec); + tempBuffers.Add(tempBuffer); + } + + const unsigned numMethods = _bindInfo.Coders.Size(); + + for (i = 0; i < numMethods; i++) + _mixer->SetCoderInfo(i, NULL, NULL, false); + + + /* inStreamSize can be used by BCJ2 to set optimal range of conversion. + But current BCJ2 encoder uses also another way to check exact size of current file. + So inStreamSize is not required. */ + + /* + if (inStreamSize) + _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL); + */ + + + /* + CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; + CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; + */ + + CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; + CMyComPtr outStreamSizeCount; + + // inStreamSizeCountSpec->Init(inStream); + + // ISequentialInStream *inStreamPointer = inStreamSizeCount; + ISequentialInStream *inStreamPointer = inStream; + + CRecordVector outStreamPointers; + + SetFolder(folderItem); + + for (i = 0; i < numMethods; i++) + { + IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); + /* + { + CEncoder *sfEncoder = NULL; + Z7_DECL_CMyComPtr_QI_FROM( + IGetSfEncoderInternal, + sf, coder) + if (sf) + { + RINOK(sf->GetSfEncoder(&sfEncoder)); + if (!sfEncoder) + return E_FAIL; + + } + } + */ + /* + #ifdef Z7_EXTERNAL_CODECS + { + Z7_DECL_CMyComPtr_QI_FROM( + ISetCompressCodecsInfo, + setCompressCodecsInfo, coder) + if (setCompressCodecsInfo) + { + // we must use g_ExternalCodecs also + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs)) + } + } + #endif + */ + { + Z7_DECL_CMyComPtr_QI_FROM( + ICryptoResetInitVector, + resetInitVector, coder) + if (resetInitVector) + { + RINOK(resetInitVector->ResetInitVector()) + } + } + { + Z7_DECL_CMyComPtr_QI_FROM( + ICompressSetCoderPropertiesOpt, + optProps, coder) + if (optProps) + { + const PROPID propID = NCoderPropID::kExpectedDataSize; + NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; + RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)) + } + } + // we must write properties from coder after ResetInitVector() + RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props)) + } + + _mixer->SelectMainCoder(false); + const UInt32 mainCoder = _mixer->MainCoderIndex; + + bool useMtProgress = false; + if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder)) + { + #ifdef Z7_ST + if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder)) + #endif + useMtProgress = true; + } + + if (useMtProgress) + { + mtProgress.SetFromCls(new CMtEncMultiProgress); + mtProgress->Init(compressProgress); + + mtOutStreamNotify.SetFromCls(new CSequentialOutMtNotify); + mtOutStreamNotify->_stream = outStream; + mtOutStreamNotify->_mtProgressSpec = mtProgress.ClsPtr(); + + FOR_VECTOR (t, tempBufferSpecs) + { + tempBufferSpecs[t]->_mtProgressSpec = mtProgress.ClsPtr(); + } + } + + + if (_bindInfo.PackStreams.Size() != 0) + { + outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; + outStreamSizeCount = outStreamSizeCountSpec; + outStreamSizeCountSpec->SetStream(mtOutStreamNotify.IsDefined() ? + mtOutStreamNotify.Interface() : outStream); + outStreamSizeCountSpec->Init(); + outStreamPointers.Add(outStreamSizeCount); + } + + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) + outStreamPointers.Add(tempBuffers[i - 1]); + + bool dataAfterEnd_Error; + + RINOK(_mixer->Code( + &inStreamPointer, + outStreamPointers.ConstData(), + mtProgress.IsDefined() ? mtProgress.Interface() : + compressProgress, dataAfterEnd_Error)) + + if (_bindInfo.PackStreams.Size() != 0) + packSizes.Add(outStreamSizeCountSpec->GetSize()); + + for (i = 1; i < _bindInfo.PackStreams.Size(); i++) + { + CInOutTempBuffer &iotb = tempBufferSpecs[i - 1]->TempBuffer; + RINOK(iotb.WriteToStream(outStream)) + packSizes.Add(iotb.GetDataSize()); + } + + /* Code() in some future codec can change properties. + v23: so we fill properties again after Code() */ + for (i = 0; i < numMethods; i++) + { + IUnknown *coder = _mixer->GetCoder(i).GetUnknown(); + RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props)) + } + + return S_OK; +} + + +void CEncoder::Encode_Post( + UInt64 unpackSize, + CRecordVector &coderUnpackSizes) +{ + // unpackSize = 0; + for (unsigned i = 0; i < _bindInfo.Coders.Size(); i++) + { + const int bond = _bindInfo.FindBond_for_UnpackStream(DestOut_to_SrcIn[i]); + UInt64 streamSize; + if (bond < 0) + { + // streamSize = inStreamSizeCountSpec->GetSize(); + // unpackSize = streamSize; + streamSize = unpackSize; + } + else + streamSize = _mixer->GetBondStreamSize((unsigned)bond); + coderUnpackSizes.Add(streamSize); + } +} + + +CEncoder::CEncoder(const CCompressionMethodMode &options): + _constructed(false) +{ + if (options.IsEmpty()) + throw 1; + + _options = options; + + #ifdef USE_MIXER_ST + _mixerST = NULL; + #endif + + #ifdef USE_MIXER_MT + _mixerMT = NULL; + #endif + + _mixer = NULL; +} + + +HRESULT CEncoder::EncoderConstr() +{ + if (_constructed) + return S_OK; + if (_options.Methods.IsEmpty()) + { + // it has only password method; + if (!_options.PasswordIsDefined) + throw 1; + if (!_options.Bonds.IsEmpty()) + throw 1; + + CMethodFull method; + method.Id = k_AES; + method.NumStreams = 1; + _options.Methods.Add(method); + + NCoderMixer2::CCoderStreamsInfo coderStreamsInfo; + coderStreamsInfo.NumStreams = 1; + _bindInfo.Coders.Add(coderStreamsInfo); + + _bindInfo.PackStreams.Add(0); + _bindInfo.UnpackCoder = 0; + } + else + { + + UInt32 numOutStreams = 0; + unsigned i; + + for (i = 0; i < _options.Methods.Size(); i++) + { + const CMethodFull &methodFull = _options.Methods[i]; + NCoderMixer2::CCoderStreamsInfo cod; + + cod.NumStreams = methodFull.NumStreams; + + if (_options.Bonds.IsEmpty()) + { + // if there are no bonds in options, we create bonds via first streams of coders + if (i != _options.Methods.Size() - 1) + { + NCoderMixer2::CBond bond; + bond.PackIndex = numOutStreams; + bond.UnpackIndex = i + 1; // it's next coder + _bindInfo.Bonds.Add(bond); + } + else if (cod.NumStreams != 0) + _bindInfo.PackStreams.Insert(0, numOutStreams); + + for (UInt32 j = 1; j < cod.NumStreams; j++) + _bindInfo.PackStreams.Add(numOutStreams + j); + } + + numOutStreams += cod.NumStreams; + + _bindInfo.Coders.Add(cod); + } + + if (!_options.Bonds.IsEmpty()) + { + for (i = 0; i < _options.Bonds.Size(); i++) + { + NCoderMixer2::CBond mixerBond; + const CBond2 &bond = _options.Bonds[i]; + if (bond.InCoder >= _bindInfo.Coders.Size() + || bond.OutCoder >= _bindInfo.Coders.Size() + || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams) + return E_INVALIDARG; + mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream; + mixerBond.UnpackIndex = bond.InCoder; + _bindInfo.Bonds.Add(mixerBond); + } + + for (i = 0; i < numOutStreams; i++) + if (_bindInfo.FindBond_for_PackStream(i) == -1) + _bindInfo.PackStreams.Add(i); + } + + if (!_bindInfo.SetUnpackCoder()) + return E_INVALIDARG; + + if (!_bindInfo.CalcMapsAndCheck()) + return E_INVALIDARG; + + if (_bindInfo.PackStreams.Size() != 1) + { + /* main_PackStream is pack stream of main path of coders tree. + We find main_PackStream, and place to start of list of out streams. + It allows to use more optimal memory usage for temp buffers, + if main_PackStream is largest stream. */ + + UInt32 ci = _bindInfo.UnpackCoder; + + for (;;) + { + if (_bindInfo.Coders[ci].NumStreams == 0) + break; + + const UInt32 outIndex = _bindInfo.Coder_to_Stream[ci]; + const int bond = _bindInfo.FindBond_for_PackStream(outIndex); + if (bond >= 0) + { + ci = _bindInfo.Bonds[(unsigned)bond].UnpackIndex; + continue; + } + + const int si = _bindInfo.FindStream_in_PackStreams(outIndex); + if (si >= 0) + _bindInfo.PackStreams.MoveToFront((unsigned)si); + break; + } + } + + if (_options.PasswordIsDefined) + { + unsigned numCryptoStreams = _bindInfo.PackStreams.Size(); + + unsigned numInStreams = _bindInfo.Coders.Size(); + + for (i = 0; i < numCryptoStreams; i++) + { + NCoderMixer2::CBond bond; + bond.UnpackIndex = numInStreams + i; + bond.PackIndex = _bindInfo.PackStreams[i]; + _bindInfo.Bonds.Add(bond); + } + _bindInfo.PackStreams.Clear(); + + /* + if (numCryptoStreams == 0) + numCryptoStreams = 1; + */ + + for (i = 0; i < numCryptoStreams; i++) + { + CMethodFull method; + method.NumStreams = 1; + method.Id = k_AES; + _options.Methods.Add(method); + + NCoderMixer2::CCoderStreamsInfo cod; + cod.NumStreams = 1; + _bindInfo.Coders.Add(cod); + + _bindInfo.PackStreams.Add(numOutStreams++); + } + } + + } + + for (unsigned i = _options.Methods.Size(); i != 0;) + _decompressionMethods.Add(_options.Methods[--i].Id); + + if (_bindInfo.Coders.Size() > 16) + return E_INVALIDARG; + if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16) + return E_INVALIDARG; + + if (!_bindInfo.CalcMapsAndCheck()) + return E_INVALIDARG; + + InitBindConv(); + _constructed = true; + return S_OK; +} + +CEncoder::~CEncoder() {} + +}} diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h index 75e567983..849ac63b9 100644 --- a/CPP/7zip/Archive/7z/7zEncode.h +++ b/CPP/7zip/Archive/7z/7zEncode.h @@ -1,95 +1,95 @@ -// 7zEncode.h - -#ifndef ZIP7_INC_7Z_ENCODE_H -#define ZIP7_INC_7Z_ENCODE_H - -#include "7zCompressionMode.h" - -#include "../Common/CoderMixer2.h" - -#include "7zItem.h" - -namespace NArchive { -namespace N7z { - -Z7_CLASS_IMP_COM_1( - CMtEncMultiProgress, - ICompressProgressInfo -) - CMyComPtr _progress; - #ifndef Z7_ST - NWindows::NSynchronization::CCriticalSection CriticalSection; - #endif - -public: - UInt64 OutSize; - - CMtEncMultiProgress(): OutSize(0) {} - - void Init(ICompressProgressInfo *progress); - - void AddOutSize(UInt64 addOutSize) - { - #ifndef Z7_ST - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - #endif - OutSize += addOutSize; - } -}; - - -class CEncoder Z7_final MY_UNCOPYABLE -{ - #ifdef USE_MIXER_ST - NCoderMixer2::CMixerST *_mixerST; - #endif - #ifdef USE_MIXER_MT - NCoderMixer2::CMixerMT *_mixerMT; - #endif - - NCoderMixer2::CMixer *_mixer; - CMyComPtr _mixerRef; - - CCompressionMethodMode _options; - NCoderMixer2::CBindInfo _bindInfo; - CRecordVector _decompressionMethods; - - CRecordVector SrcIn_to_DestOut; - CRecordVector SrcOut_to_DestIn; - // CRecordVector DestIn_to_SrcOut; - CRecordVector DestOut_to_SrcIn; - - void InitBindConv(); - void SetFolder(CFolder &folder); - - HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS - const UInt64 *inSizeForReduce); - - bool _constructed; -public: - - CEncoder(const CCompressionMethodMode &options); - ~CEncoder(); - HRESULT EncoderConstr(); - HRESULT Encode1( - DECL_EXTERNAL_CODECS_LOC_VARS - ISequentialInStream *inStream, - // const UInt64 *inStreamSize, - const UInt64 *inSizeForReduce, - UInt64 expectedDataSize, - CFolder &folderItem, - // CRecordVector &coderUnpackSizes, - // UInt64 &unpackSize, - ISequentialOutStream *outStream, - CRecordVector &packSizes, - ICompressProgressInfo *compressProgress); - - void Encode_Post( - UInt64 unpackSize, - CRecordVector &coderUnpackSizes); - -}; - -}} - -#endif +// 7zEncode.h + +#ifndef ZIP7_INC_7Z_ENCODE_H +#define ZIP7_INC_7Z_ENCODE_H + +#include "7zCompressionMode.h" + +#include "../Common/CoderMixer2.h" + +#include "7zItem.h" + +namespace NArchive { +namespace N7z { + +Z7_CLASS_IMP_COM_1( + CMtEncMultiProgress, + ICompressProgressInfo +) + CMyComPtr _progress; + #ifndef Z7_ST + NWindows::NSynchronization::CCriticalSection CriticalSection; + #endif + +public: + UInt64 OutSize; + + CMtEncMultiProgress(): OutSize(0) {} + + void Init(ICompressProgressInfo *progress); + + void AddOutSize(UInt64 addOutSize) + { + #ifndef Z7_ST + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + #endif + OutSize += addOutSize; + } +}; + + +class CEncoder Z7_final MY_UNCOPYABLE +{ + #ifdef USE_MIXER_ST + NCoderMixer2::CMixerST *_mixerST; + #endif + #ifdef USE_MIXER_MT + NCoderMixer2::CMixerMT *_mixerMT; + #endif + + NCoderMixer2::CMixer *_mixer; + CMyComPtr _mixerRef; + + CCompressionMethodMode _options; + NCoderMixer2::CBindInfo _bindInfo; + CRecordVector _decompressionMethods; + + CRecordVector SrcIn_to_DestOut; + CRecordVector SrcOut_to_DestIn; + // CRecordVector DestIn_to_SrcOut; + CRecordVector DestOut_to_SrcIn; + + void InitBindConv(); + void SetFolder(CFolder &folder); + + HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS + const UInt64 *inSizeForReduce); + + bool _constructed; +public: + + CEncoder(const CCompressionMethodMode &options); + ~CEncoder(); + HRESULT EncoderConstr(); + HRESULT Encode1( + DECL_EXTERNAL_CODECS_LOC_VARS + ISequentialInStream *inStream, + // const UInt64 *inStreamSize, + const UInt64 *inSizeForReduce, + UInt64 expectedDataSize, + CFolder &folderItem, + // CRecordVector &coderUnpackSizes, + // UInt64 &unpackSize, + ISequentialOutStream *outStream, + CRecordVector &packSizes, + ICompressProgressInfo *compressProgress); + + void Encode_Post( + UInt64 unpackSize, + CRecordVector &coderUnpackSizes); + +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp index cc4a573ba..1c31e1d08 100644 --- a/CPP/7zip/Archive/7z/7zExtract.cpp +++ b/CPP/7zip/Archive/7z/7zExtract.cpp @@ -1,444 +1,444 @@ -// 7zExtract.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" - -#include "../../../Common/ComTry.h" - -#include "../../Common/ProgressUtils.h" - -#include "7zDecode.h" -#include "7zHandler.h" - -// EXTERN_g_ExternalCodecs - -namespace NArchive { -namespace N7z { - -Z7_CLASS_IMP_COM_1( - CFolderOutStream - , ISequentialOutStream - /* , ICompressGetSubStreamSize */ -) - CMyComPtr _stream; -public: - bool TestMode; - bool CheckCrc; -private: - bool _fileIsOpen; - bool _calcCrc; - UInt32 _crc; - UInt64 _rem; - - const UInt32 *_indexes; - // unsigned _startIndex; - unsigned _numFiles; - unsigned _fileIndex; - - HRESULT OpenFile(bool isCorrupted = false); - HRESULT CloseFile_and_SetResult(Int32 res); - HRESULT CloseFile(); - HRESULT ProcessEmptyFiles(); - -public: - const CDbEx *_db; - CMyComPtr ExtractCallback; - - bool ExtraWriteWasCut; - - CFolderOutStream(): - TestMode(false), - CheckCrc(true) - {} - - HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles); - HRESULT FlushCorrupted(Int32 callbackOperationResult); - - bool WasWritingFinished() const { return _numFiles == 0; } -}; - - -HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles) -{ - // _startIndex = startIndex; - _fileIndex = startIndex; - _indexes = indexes; - _numFiles = numFiles; - - _fileIsOpen = false; - ExtraWriteWasCut = false; - - return ProcessEmptyFiles(); -} - -HRESULT CFolderOutStream::OpenFile(bool isCorrupted) -{ - const CFileItem &fi = _db->Files[_fileIndex]; - const UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex); - Int32 askMode = (_fileIndex == nextFileIndex) ? TestMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract : - NExtract::NAskMode::kSkip; - - if (isCorrupted - && askMode == NExtract::NAskMode::kExtract - && !_db->IsItemAnti(_fileIndex) - && !fi.IsDir) - askMode = NExtract::NAskMode::kTest; - - CMyComPtr realOutStream; - RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode)) - - _stream = realOutStream; - _crc = CRC_INIT_VAL; - _calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir); - - _fileIsOpen = true; - _rem = fi.Size; - - if (askMode == NExtract::NAskMode::kExtract - && !realOutStream - && !_db->IsItemAnti(_fileIndex) - && !fi.IsDir) - askMode = NExtract::NAskMode::kSkip; - return ExtractCallback->PrepareOperation(askMode); -} - -HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res) -{ - _stream.Release(); - _fileIsOpen = false; - - if (!_indexes) - _numFiles--; - else if (*_indexes == _fileIndex) - { - _indexes++; - _numFiles--; - } - - _fileIndex++; - return ExtractCallback->SetOperationResult(res); -} - -HRESULT CFolderOutStream::CloseFile() -{ - const CFileItem &fi = _db->Files[_fileIndex]; - return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ? - NExtract::NOperationResult::kOK : - NExtract::NOperationResult::kCRCError); -} - -HRESULT CFolderOutStream::ProcessEmptyFiles() -{ - while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0) - { - RINOK(OpenFile()) - RINOK(CloseFile()) - } - return S_OK; -} - -Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - if (_fileIsOpen) - { - UInt32 cur = (size < _rem ? size : (UInt32)_rem); - if (_calcCrc) - { - const UInt32 k_Step = (UInt32)1 << 20; - if (cur > k_Step) - cur = k_Step; - } - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, cur, &cur); - if (_calcCrc) - _crc = CrcUpdate(_crc, data, cur); - if (processedSize) - *processedSize += cur; - data = (const Byte *)data + cur; - size -= cur; - _rem -= cur; - if (_rem == 0) - { - RINOK(CloseFile()) - RINOK(ProcessEmptyFiles()) - } - RINOK(result) - if (cur == 0) - break; - continue; - } - - RINOK(ProcessEmptyFiles()) - if (_numFiles == 0) - { - // we support partial extracting - /* - if (processedSize) - *processedSize += size; - break; - */ - ExtraWriteWasCut = true; - // return S_FALSE; - return k_My_HRESULT_WritingWasCut; - } - RINOK(OpenFile()) - } - - return S_OK; -} - -HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult) -{ - while (_numFiles != 0) - { - if (_fileIsOpen) - { - RINOK(CloseFile_and_SetResult(callbackOperationResult)) - } - else - { - RINOK(OpenFile(true)) - } - } - return S_OK; -} - -/* -Z7_COM7F_IMF(CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)) -{ - *value = 0; - // const unsigned numFiles_Original = _numFiles + _fileIndex - _startIndex; - const unsigned numFiles_Original = _numFiles; - if (subStream >= numFiles_Original) - return S_FALSE; // E_FAIL; - *value = _db->Files[_startIndex + (unsigned)subStream].Size; - return S_OK; -} -*/ - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)) -{ - // for GCC - // CFolderOutStream *folderOutStream = new CFolderOutStream; - // CMyComPtr outStream(folderOutStream); - - COM_TRY_BEGIN - - CMyComPtr extractCallback = extractCallbackSpec; - - UInt64 importantTotalUnpacked = 0; - - // numItems = (UInt32)(Int32)-1; - - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _db.Files.Size(); - - if (numItems == 0) - return S_OK; - - { - CNum prevFolder = kNumNoIndex; - UInt32 nextFile = 0; - - UInt32 i; - - for (i = 0; i < numItems; i++) - { - const UInt32 fileIndex = allFilesMode ? i : indices[i]; - const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex == kNumNoIndex) - continue; - if (folderIndex != prevFolder || fileIndex < nextFile) - nextFile = _db.FolderStartFileIndex[folderIndex]; - for (CNum index = nextFile; index <= fileIndex; index++) - importantTotalUnpacked += _db.Files[index].Size; - nextFile = fileIndex + 1; - prevFolder = folderIndex; - } - } - - RINOK(extractCallback->SetTotal(importantTotalUnpacked)) - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - CDecoder decoder( - #if !defined(USE_MIXER_MT) - false - #elif !defined(USE_MIXER_ST) - true - #elif !defined(Z7_7Z_SET_PROPERTIES) - #ifdef Z7_ST - false - #else - true - #endif - #else - _useMultiThreadMixer - #endif - ); - - UInt64 curPacked, curUnpacked; - - CMyComPtr callbackMessage; - extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage); - - CFolderOutStream *folderOutStream = new CFolderOutStream; - CMyComPtr outStream(folderOutStream); - - folderOutStream->_db = &_db; - folderOutStream->ExtractCallback = extractCallback; - folderOutStream->TestMode = (testModeSpec != 0); - folderOutStream->CheckCrc = (_crcSize != 0); - - for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked) - { - RINOK(lps->SetCur()) - - if (i >= numItems) - break; - - curUnpacked = 0; - curPacked = 0; - - UInt32 fileIndex = allFilesMode ? i : indices[i]; - const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; - - UInt32 numSolidFiles = 1; - - if (folderIndex != kNumNoIndex) - { - curPacked = _db.GetFolderFullPackSize(folderIndex); - UInt32 nextFile = fileIndex + 1; - fileIndex = _db.FolderStartFileIndex[folderIndex]; - UInt32 k; - - for (k = i + 1; k < numItems; k++) - { - const UInt32 fileIndex2 = allFilesMode ? k : indices[k]; - if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex - || fileIndex2 < nextFile) - break; - nextFile = fileIndex2 + 1; - } - - numSolidFiles = k - i; - - for (k = fileIndex; k < nextFile; k++) - curUnpacked += _db.Files[k].Size; - } - - { - const HRESULT result = folderOutStream->Init(fileIndex, - allFilesMode ? NULL : indices + i, - numSolidFiles); - - i += numSolidFiles; - - RINOK(result) - } - - if (folderOutStream->WasWritingFinished()) - { - // for debug: to test zero size stream unpacking - // if (folderIndex == kNumNoIndex) // enable this check for debug - continue; - } - - if (folderIndex == kNumNoIndex) - return E_FAIL; - - #ifndef Z7_NO_CRYPTO - CMyComPtr getTextPassword; - if (extractCallback) - extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); - #endif - - try - { - #ifndef Z7_NO_CRYPTO - bool isEncrypted = false; - bool passwordIsDefined = false; - UString_Wipe password; - #endif - - bool dataAfterEnd_Error = false; - - const HRESULT result = decoder.Decode( - EXTERNAL_CODECS_VARS - _inStream, - _db.ArcInfo.DataStartPosition, - _db, folderIndex, - &curUnpacked, - - outStream, - lps, - NULL // *inStreamMainRes - , dataAfterEnd_Error - - Z7_7Z_DECODER_CRYPRO_VARS - #if !defined(Z7_ST) - , true, _numThreads, _memUsage_Decompress - #endif - ); - - if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error) - { - const bool wasFinished = folderOutStream->WasWritingFinished(); - - int resOp = NExtract::NOperationResult::kDataError; - - if (result != S_FALSE) - { - if (result == E_NOTIMPL) - resOp = NExtract::NOperationResult::kUnsupportedMethod; - else if (wasFinished && dataAfterEnd_Error) - resOp = NExtract::NOperationResult::kDataAfterEnd; - } - - RINOK(folderOutStream->FlushCorrupted(resOp)) - - if (wasFinished) - { - // we don't show error, if it's after required files - if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage) - { - RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp)) - } - } - continue; - } - - if (result != S_OK) - return result; - - RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)) - continue; - } - catch(...) - { - RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)) - // continue; - // return E_FAIL; - throw; - } - } - - return S_OK; - - COM_TRY_END -} - -}} +// 7zExtract.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" + +#include "../../../Common/ComTry.h" + +#include "../../Common/ProgressUtils.h" + +#include "7zDecode.h" +#include "7zHandler.h" + +// EXTERN_g_ExternalCodecs + +namespace NArchive { +namespace N7z { + +Z7_CLASS_IMP_COM_1( + CFolderOutStream + , ISequentialOutStream + /* , ICompressGetSubStreamSize */ +) + CMyComPtr _stream; +public: + bool TestMode; + bool CheckCrc; +private: + bool _fileIsOpen; + bool _calcCrc; + UInt32 _crc; + UInt64 _rem; + + const UInt32 *_indexes; + // unsigned _startIndex; + unsigned _numFiles; + unsigned _fileIndex; + + HRESULT OpenFile(bool isCorrupted = false); + HRESULT CloseFile_and_SetResult(Int32 res); + HRESULT CloseFile(); + HRESULT ProcessEmptyFiles(); + +public: + const CDbEx *_db; + CMyComPtr ExtractCallback; + + bool ExtraWriteWasCut; + + CFolderOutStream(): + TestMode(false), + CheckCrc(true) + {} + + HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles); + HRESULT FlushCorrupted(Int32 callbackOperationResult); + + bool WasWritingFinished() const { return _numFiles == 0; } +}; + + +HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles) +{ + // _startIndex = startIndex; + _fileIndex = startIndex; + _indexes = indexes; + _numFiles = numFiles; + + _fileIsOpen = false; + ExtraWriteWasCut = false; + + return ProcessEmptyFiles(); +} + +HRESULT CFolderOutStream::OpenFile(bool isCorrupted) +{ + const CFileItem &fi = _db->Files[_fileIndex]; + const UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex); + Int32 askMode = (_fileIndex == nextFileIndex) ? TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract : + NExtract::NAskMode::kSkip; + + if (isCorrupted + && askMode == NExtract::NAskMode::kExtract + && !_db->IsItemAnti(_fileIndex) + && !fi.IsDir) + askMode = NExtract::NAskMode::kTest; + + CMyComPtr realOutStream; + RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode)) + + _stream = realOutStream; + _crc = CRC_INIT_VAL; + _calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir); + + _fileIsOpen = true; + _rem = fi.Size; + + if (askMode == NExtract::NAskMode::kExtract + && !realOutStream + && !_db->IsItemAnti(_fileIndex) + && !fi.IsDir) + askMode = NExtract::NAskMode::kSkip; + return ExtractCallback->PrepareOperation(askMode); +} + +HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res) +{ + _stream.Release(); + _fileIsOpen = false; + + if (!_indexes) + _numFiles--; + else if (*_indexes == _fileIndex) + { + _indexes++; + _numFiles--; + } + + _fileIndex++; + return ExtractCallback->SetOperationResult(res); +} + +HRESULT CFolderOutStream::CloseFile() +{ + const CFileItem &fi = _db->Files[_fileIndex]; + return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ? + NExtract::NOperationResult::kOK : + NExtract::NOperationResult::kCRCError); +} + +HRESULT CFolderOutStream::ProcessEmptyFiles() +{ + while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0) + { + RINOK(OpenFile()) + RINOK(CloseFile()) + } + return S_OK; +} + +Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (_fileIsOpen) + { + UInt32 cur = (size < _rem ? size : (UInt32)_rem); + if (_calcCrc) + { + const UInt32 k_Step = (UInt32)1 << 20; + if (cur > k_Step) + cur = k_Step; + } + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, cur, &cur); + if (_calcCrc) + _crc = CrcUpdate(_crc, data, cur); + if (processedSize) + *processedSize += cur; + data = (const Byte *)data + cur; + size -= cur; + _rem -= cur; + if (_rem == 0) + { + RINOK(CloseFile()) + RINOK(ProcessEmptyFiles()) + } + RINOK(result) + if (cur == 0) + break; + continue; + } + + RINOK(ProcessEmptyFiles()) + if (_numFiles == 0) + { + // we support partial extracting + /* + if (processedSize) + *processedSize += size; + break; + */ + ExtraWriteWasCut = true; + // return S_FALSE; + return k_My_HRESULT_WritingWasCut; + } + RINOK(OpenFile()) + } + + return S_OK; +} + +HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult) +{ + while (_numFiles != 0) + { + if (_fileIsOpen) + { + RINOK(CloseFile_and_SetResult(callbackOperationResult)) + } + else + { + RINOK(OpenFile(true)) + } + } + return S_OK; +} + +/* +Z7_COM7F_IMF(CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)) +{ + *value = 0; + // const unsigned numFiles_Original = _numFiles + _fileIndex - _startIndex; + const unsigned numFiles_Original = _numFiles; + if (subStream >= numFiles_Original) + return S_FALSE; // E_FAIL; + *value = _db->Files[_startIndex + (unsigned)subStream].Size; + return S_OK; +} +*/ + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)) +{ + // for GCC + // CFolderOutStream *folderOutStream = new CFolderOutStream; + // CMyComPtr outStream(folderOutStream); + + COM_TRY_BEGIN + + CMyComPtr extractCallback = extractCallbackSpec; + + UInt64 importantTotalUnpacked = 0; + + // numItems = (UInt32)(Int32)-1; + + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _db.Files.Size(); + + if (numItems == 0) + return S_OK; + + { + CNum prevFolder = kNumNoIndex; + UInt32 nextFile = 0; + + UInt32 i; + + for (i = 0; i < numItems; i++) + { + const UInt32 fileIndex = allFilesMode ? i : indices[i]; + const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex == kNumNoIndex) + continue; + if (folderIndex != prevFolder || fileIndex < nextFile) + nextFile = _db.FolderStartFileIndex[folderIndex]; + for (CNum index = nextFile; index <= fileIndex; index++) + importantTotalUnpacked += _db.Files[index].Size; + nextFile = fileIndex + 1; + prevFolder = folderIndex; + } + } + + RINOK(extractCallback->SetTotal(importantTotalUnpacked)) + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + CDecoder decoder( + #if !defined(USE_MIXER_MT) + false + #elif !defined(USE_MIXER_ST) + true + #elif !defined(Z7_7Z_SET_PROPERTIES) + #ifdef Z7_ST + false + #else + true + #endif + #else + _useMultiThreadMixer + #endif + ); + + UInt64 curPacked, curUnpacked; + + CMyComPtr callbackMessage; + extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage); + + CFolderOutStream *folderOutStream = new CFolderOutStream; + CMyComPtr outStream(folderOutStream); + + folderOutStream->_db = &_db; + folderOutStream->ExtractCallback = extractCallback; + folderOutStream->TestMode = (testModeSpec != 0); + folderOutStream->CheckCrc = (_crcSize != 0); + + for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked) + { + RINOK(lps->SetCur()) + + if (i >= numItems) + break; + + curUnpacked = 0; + curPacked = 0; + + UInt32 fileIndex = allFilesMode ? i : indices[i]; + const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex]; + + UInt32 numSolidFiles = 1; + + if (folderIndex != kNumNoIndex) + { + curPacked = _db.GetFolderFullPackSize(folderIndex); + UInt32 nextFile = fileIndex + 1; + fileIndex = _db.FolderStartFileIndex[folderIndex]; + UInt32 k; + + for (k = i + 1; k < numItems; k++) + { + const UInt32 fileIndex2 = allFilesMode ? k : indices[k]; + if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex + || fileIndex2 < nextFile) + break; + nextFile = fileIndex2 + 1; + } + + numSolidFiles = k - i; + + for (k = fileIndex; k < nextFile; k++) + curUnpacked += _db.Files[k].Size; + } + + { + const HRESULT result = folderOutStream->Init(fileIndex, + allFilesMode ? NULL : indices + i, + numSolidFiles); + + i += numSolidFiles; + + RINOK(result) + } + + if (folderOutStream->WasWritingFinished()) + { + // for debug: to test zero size stream unpacking + // if (folderIndex == kNumNoIndex) // enable this check for debug + continue; + } + + if (folderIndex == kNumNoIndex) + return E_FAIL; + + #ifndef Z7_NO_CRYPTO + CMyComPtr getTextPassword; + if (extractCallback) + extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + #endif + + try + { + #ifndef Z7_NO_CRYPTO + bool isEncrypted = false; + bool passwordIsDefined = false; + UString_Wipe password; + #endif + + bool dataAfterEnd_Error = false; + + const HRESULT result = decoder.Decode( + EXTERNAL_CODECS_VARS + _inStream, + _db.ArcInfo.DataStartPosition, + _db, folderIndex, + &curUnpacked, + + outStream, + lps, + NULL // *inStreamMainRes + , dataAfterEnd_Error + + Z7_7Z_DECODER_CRYPRO_VARS + #if !defined(Z7_ST) + , true, _numThreads, _memUsage_Decompress + #endif + ); + + if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error) + { + const bool wasFinished = folderOutStream->WasWritingFinished(); + + int resOp = NExtract::NOperationResult::kDataError; + + if (result != S_FALSE) + { + if (result == E_NOTIMPL) + resOp = NExtract::NOperationResult::kUnsupportedMethod; + else if (wasFinished && dataAfterEnd_Error) + resOp = NExtract::NOperationResult::kDataAfterEnd; + } + + RINOK(folderOutStream->FlushCorrupted(resOp)) + + if (wasFinished) + { + // we don't show error, if it's after required files + if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage) + { + RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp)) + } + } + continue; + } + + if (result != S_OK) + return result; + + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)) + continue; + } + catch(...) + { + RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)) + // continue; + // return E_FAIL; + throw; + } + } + + return S_OK; + + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp index 2e9a3e642..082318939 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp +++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp @@ -1,264 +1,264 @@ -// 7zFolderInStream.cpp - -#include "StdAfx.h" - -#include "../../../Windows/TimeUtils.h" - -#include "7zFolderInStream.h" - -namespace NArchive { -namespace N7z { - -void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, - const UInt32 *indexes, unsigned numFiles) -{ - _updateCallback = updateCallback; - _indexes = indexes; - _numFiles = numFiles; - - _totalSize_for_Coder = 0; - ClearFileInfo(); - - Processed.ClearAndReserve(numFiles); - Sizes.ClearAndReserve(numFiles); - CRCs.ClearAndReserve(numFiles); - TimesDefined.ClearAndReserve(numFiles); - MTimes.ClearAndReserve(Need_MTime ? numFiles : (unsigned)0); - CTimes.ClearAndReserve(Need_CTime ? numFiles : (unsigned)0); - ATimes.ClearAndReserve(Need_ATime ? numFiles : (unsigned)0); - Attribs.ClearAndReserve(Need_Attrib ? numFiles : (unsigned)0); - - // FolderCrc = CRC_INIT_VAL; - _stream.Release(); -} - -void CFolderInStream::ClearFileInfo() -{ - _pos = 0; - _crc = CRC_INIT_VAL; - _size_Defined = false; - _times_Defined = false; - _size = 0; - FILETIME_Clear(_mTime); - FILETIME_Clear(_cTime); - FILETIME_Clear(_aTime); - _attrib = 0; -} - -HRESULT CFolderInStream::OpenStream() -{ - while (Processed.Size() < _numFiles) - { - CMyComPtr stream; - const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream); - if (result != S_OK && result != S_FALSE) - return result; - - _stream = stream; - - if (stream) - { - { - CMyComPtr getProps; - stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); - if (getProps) - { - // access could be changed in first myx pass - if (getProps->GetProps(&_size, - Need_CTime ? &_cTime : NULL, - Need_ATime ? &_aTime : NULL, - Need_MTime ? &_mTime : NULL, - Need_Attrib ? &_attrib : NULL) - == S_OK) - { - _size_Defined = true; - _times_Defined = true; - } - return S_OK; - } - } - { - CMyComPtr streamGetSize; - stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); - if (streamGetSize) - { - if (streamGetSize->GetSize(&_size) == S_OK) - _size_Defined = true; - } - return S_OK; - } - } - - RINOK(AddFileInfo(result == S_OK)) - } - return S_OK; -} - -static void AddFt(CRecordVector &vec, const FILETIME &ft) -{ - vec.AddInReserved(FILETIME_To_UInt64(ft)); -} - -/* -HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp, - UInt32 index, UInt64 size, const UInt32 *crc) -{ - PROPVARIANT prop; - prop.vt = VT_EMPTY; - prop.wReserved1 = 0; - - NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size); - RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop)); - if (crc) - { - NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc); - RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop)); - } - return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK); -} -*/ - -HRESULT CFolderInStream::AddFileInfo(bool isProcessed) -{ - // const UInt32 index = _indexes[Processed.Size()]; - Processed.AddInReserved(isProcessed); - Sizes.AddInReserved(_pos); - CRCs.AddInReserved(CRC_GET_DIGEST(_crc)); - if (Need_Attrib) Attribs.AddInReserved(_attrib); - TimesDefined.AddInReserved(_times_Defined); - if (Need_MTime) AddFt(MTimes, _mTime); - if (Need_CTime) AddFt(CTimes, _cTime); - if (Need_ATime) AddFt(ATimes, _aTime); - ClearFileInfo(); - /* - if (isProcessed && _reportArcProp) - RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc)) - */ - return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -Z7_COM7F_IMF(CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - while (size != 0) - { - if (_stream) - { - /* - if (_pos == 0) - { - const UInt32 align = (UInt32)1 << AlignLog; - const UInt32 offset = (UInt32)_totalSize_for_Coder & (align - 1); - if (offset != 0) - { - UInt32 cur = align - offset; - if (cur > size) - cur = size; - memset(data, 0, cur); - data = (Byte *)data + cur; - size -= cur; - // _pos += cur; // for debug - _totalSize_for_Coder += cur; - if (processedSize) - *processedSize += cur; - continue; - } - } - */ - UInt32 cur = size; - const UInt32 kMax = (UInt32)1 << 20; - if (cur > kMax) - cur = kMax; - RINOK(_stream->Read(data, cur, &cur)) - if (cur != 0) - { - // if (Need_Crc) - _crc = CrcUpdate(_crc, data, cur); - /* - if (FolderCrc) - FolderCrc = CrcUpdate(FolderCrc, data, cur); - */ - _pos += cur; - _totalSize_for_Coder += cur; - if (processedSize) - *processedSize = cur; // use +=cur, if continue is possible in loop - return S_OK; - } - - _stream.Release(); - RINOK(AddFileInfo(true)) - } - - if (Processed.Size() >= _numFiles) - break; - RINOK(OpenStream()) - } - return S_OK; -} - -Z7_COM7F_IMF(CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)) -{ - *value = 0; - if (subStream > Sizes.Size()) - return S_FALSE; // E_FAIL; - - const unsigned index = (unsigned)subStream; - if (index < Sizes.Size()) - { - *value = Sizes[index]; - return S_OK; - } - - if (!_size_Defined) - { - *value = _pos; - return S_FALSE; - } - - *value = (_pos > _size ? _pos : _size); - return S_OK; -} - - -/* -HRESULT CFolderInStream::CloseCrcStream() -{ - if (!_crcStream) - return S_OK; - if (!_crcStream_Spec->WasFinished()) - return E_FAIL; - _crc = _crcStream_Spec->GetCRC() ^ CRC_INIT_VAL; // change it - const UInt64 size = _crcStream_Spec->GetSize(); - _pos = size; - _totalSize_for_Coder += size; - _crcStream.Release(); - // _crcStream->ReleaseStream(); - _stream.Release(); - return AddFileInfo(true); -} - -Z7_COM7F_IMF(CFolderInStream::GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream) -{ - RINOK(CloseCrcStream()) - *stream = NULL; - *streamIndexRes = Processed.Size(); - if (Processed.Size() >= _numFiles) - return S_OK; - RINOK(OpenStream()); - if (!_stream) - return S_OK; - if (!_crcStream) - { - _crcStream_Spec = new CSequentialInStreamWithCRC; - _crcStream = _crcStream_Spec; - } - _crcStream_Spec->Init(); - _crcStream_Spec->SetStream(_stream); - *stream = _crcStream; - _crcStream->AddRef(); - return S_OK; -} -*/ - -}} +// 7zFolderInStream.cpp + +#include "StdAfx.h" + +#include "../../../Windows/TimeUtils.h" + +#include "7zFolderInStream.h" + +namespace NArchive { +namespace N7z { + +void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback, + const UInt32 *indexes, unsigned numFiles) +{ + _updateCallback = updateCallback; + _indexes = indexes; + _numFiles = numFiles; + + _totalSize_for_Coder = 0; + ClearFileInfo(); + + Processed.ClearAndReserve(numFiles); + Sizes.ClearAndReserve(numFiles); + CRCs.ClearAndReserve(numFiles); + TimesDefined.ClearAndReserve(numFiles); + MTimes.ClearAndReserve(Need_MTime ? numFiles : (unsigned)0); + CTimes.ClearAndReserve(Need_CTime ? numFiles : (unsigned)0); + ATimes.ClearAndReserve(Need_ATime ? numFiles : (unsigned)0); + Attribs.ClearAndReserve(Need_Attrib ? numFiles : (unsigned)0); + + // FolderCrc = CRC_INIT_VAL; + _stream.Release(); +} + +void CFolderInStream::ClearFileInfo() +{ + _pos = 0; + _crc = CRC_INIT_VAL; + _size_Defined = false; + _times_Defined = false; + _size = 0; + FILETIME_Clear(_mTime); + FILETIME_Clear(_cTime); + FILETIME_Clear(_aTime); + _attrib = 0; +} + +HRESULT CFolderInStream::OpenStream() +{ + while (Processed.Size() < _numFiles) + { + CMyComPtr stream; + const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream); + if (result != S_OK && result != S_FALSE) + return result; + + _stream = stream; + + if (stream) + { + { + CMyComPtr getProps; + stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + { + // access could be changed in first myx pass + if (getProps->GetProps(&_size, + Need_CTime ? &_cTime : NULL, + Need_ATime ? &_aTime : NULL, + Need_MTime ? &_mTime : NULL, + Need_Attrib ? &_attrib : NULL) + == S_OK) + { + _size_Defined = true; + _times_Defined = true; + } + return S_OK; + } + } + { + CMyComPtr streamGetSize; + stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + if (streamGetSize->GetSize(&_size) == S_OK) + _size_Defined = true; + } + return S_OK; + } + } + + RINOK(AddFileInfo(result == S_OK)) + } + return S_OK; +} + +static void AddFt(CRecordVector &vec, const FILETIME &ft) +{ + vec.AddInReserved(FILETIME_To_UInt64(ft)); +} + +/* +HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp, + UInt32 index, UInt64 size, const UInt32 *crc) +{ + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop)); + if (crc) + { + NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop)); + } + return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK); +} +*/ + +HRESULT CFolderInStream::AddFileInfo(bool isProcessed) +{ + // const UInt32 index = _indexes[Processed.Size()]; + Processed.AddInReserved(isProcessed); + Sizes.AddInReserved(_pos); + CRCs.AddInReserved(CRC_GET_DIGEST(_crc)); + if (Need_Attrib) Attribs.AddInReserved(_attrib); + TimesDefined.AddInReserved(_times_Defined); + if (Need_MTime) AddFt(MTimes, _mTime); + if (Need_CTime) AddFt(CTimes, _cTime); + if (Need_ATime) AddFt(ATimes, _aTime); + ClearFileInfo(); + /* + if (isProcessed && _reportArcProp) + RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc)) + */ + return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +Z7_COM7F_IMF(CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + while (size != 0) + { + if (_stream) + { + /* + if (_pos == 0) + { + const UInt32 align = (UInt32)1 << AlignLog; + const UInt32 offset = (UInt32)_totalSize_for_Coder & (align - 1); + if (offset != 0) + { + UInt32 cur = align - offset; + if (cur > size) + cur = size; + memset(data, 0, cur); + data = (Byte *)data + cur; + size -= cur; + // _pos += cur; // for debug + _totalSize_for_Coder += cur; + if (processedSize) + *processedSize += cur; + continue; + } + } + */ + UInt32 cur = size; + const UInt32 kMax = (UInt32)1 << 20; + if (cur > kMax) + cur = kMax; + RINOK(_stream->Read(data, cur, &cur)) + if (cur != 0) + { + // if (Need_Crc) + _crc = CrcUpdate(_crc, data, cur); + /* + if (FolderCrc) + FolderCrc = CrcUpdate(FolderCrc, data, cur); + */ + _pos += cur; + _totalSize_for_Coder += cur; + if (processedSize) + *processedSize = cur; // use +=cur, if continue is possible in loop + return S_OK; + } + + _stream.Release(); + RINOK(AddFileInfo(true)) + } + + if (Processed.Size() >= _numFiles) + break; + RINOK(OpenStream()) + } + return S_OK; +} + +Z7_COM7F_IMF(CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)) +{ + *value = 0; + if (subStream > Sizes.Size()) + return S_FALSE; // E_FAIL; + + const unsigned index = (unsigned)subStream; + if (index < Sizes.Size()) + { + *value = Sizes[index]; + return S_OK; + } + + if (!_size_Defined) + { + *value = _pos; + return S_FALSE; + } + + *value = (_pos > _size ? _pos : _size); + return S_OK; +} + + +/* +HRESULT CFolderInStream::CloseCrcStream() +{ + if (!_crcStream) + return S_OK; + if (!_crcStream_Spec->WasFinished()) + return E_FAIL; + _crc = _crcStream_Spec->GetCRC() ^ CRC_INIT_VAL; // change it + const UInt64 size = _crcStream_Spec->GetSize(); + _pos = size; + _totalSize_for_Coder += size; + _crcStream.Release(); + // _crcStream->ReleaseStream(); + _stream.Release(); + return AddFileInfo(true); +} + +Z7_COM7F_IMF(CFolderInStream::GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream) +{ + RINOK(CloseCrcStream()) + *stream = NULL; + *streamIndexRes = Processed.Size(); + if (Processed.Size() >= _numFiles) + return S_OK; + RINOK(OpenStream()); + if (!_stream) + return S_OK; + if (!_crcStream) + { + _crcStream_Spec = new CSequentialInStreamWithCRC; + _crcStream = _crcStream_Spec; + } + _crcStream_Spec->Init(); + _crcStream_Spec->SetStream(_stream); + *stream = _crcStream; + _crcStream->AddRef(); + return S_OK; +} +*/ + +}} diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h index 7425c8376..6447b25ca 100644 --- a/CPP/7zip/Archive/7z/7zFolderInStream.h +++ b/CPP/7zip/Archive/7z/7zFolderInStream.h @@ -1,101 +1,101 @@ -// 7zFolderInStream.h - -#ifndef ZIP7_INC_7Z_FOLDER_IN_STREAM_H -#define ZIP7_INC_7Z_FOLDER_IN_STREAM_H - -#include "../../../../C/7zCrc.h" - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyVector.h" -// #include "../Common/InStreamWithCRC.h" - -#include "../../ICoder.h" -#include "../IArchive.h" - -namespace NArchive { -namespace N7z { - -Z7_CLASS_IMP_COM_2( - CFolderInStream - , ISequentialInStream - , ICompressGetSubStreamSize -) - /* - Z7_COM7F_IMP(GetNextStream(UInt64 *streamIndex)) - Z7_IFACE_COM7_IMP(ICompressInSubStreams) - */ - - CMyComPtr _stream; - UInt64 _totalSize_for_Coder; - UInt64 _pos; - UInt32 _crc; - bool _size_Defined; - bool _times_Defined; - UInt64 _size; - FILETIME _mTime; - FILETIME _cTime; - FILETIME _aTime; - UInt32 _attrib; - - unsigned _numFiles; - const UInt32 *_indexes; - - CMyComPtr _updateCallback; - - void ClearFileInfo(); - HRESULT OpenStream(); - HRESULT AddFileInfo(bool isProcessed); - // HRESULT CloseCrcStream(); -public: - bool Need_MTime; - bool Need_CTime; - bool Need_ATime; - bool Need_Attrib; - // bool Need_Crc; - // bool Need_FolderCrc; - // unsigned AlignLog; - - CRecordVector Processed; - CRecordVector Sizes; - CRecordVector CRCs; - CRecordVector Attribs; - CRecordVector TimesDefined; - CRecordVector MTimes; - CRecordVector CTimes; - CRecordVector ATimes; - // UInt32 FolderCrc; - - // UInt32 GetFolderCrc() const { return CRC_GET_DIGEST(FolderCrc); } - // CSequentialInStreamWithCRC *_crcStream_Spec; - // CMyComPtr _crcStream; - // CMyComPtr _reportArcProp; - - void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles); - - bool WasFinished() const { return Processed.Size() == _numFiles; } - - UInt64 Get_TotalSize_for_Coder() const { return _totalSize_for_Coder; } - /* - UInt64 GetFullSize() const - { - UInt64 size = 0; - FOR_VECTOR (i, Sizes) - size += Sizes[i]; - return size; - } - */ - - CFolderInStream(): - Need_MTime(false), - Need_CTime(false), - Need_ATime(false), - Need_Attrib(false) - // , Need_Crc(true) - // , Need_FolderCrc(false) - // , AlignLog(0) - {} -}; - -}} - -#endif +// 7zFolderInStream.h + +#ifndef ZIP7_INC_7Z_FOLDER_IN_STREAM_H +#define ZIP7_INC_7Z_FOLDER_IN_STREAM_H + +#include "../../../../C/7zCrc.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyVector.h" +// #include "../Common/InStreamWithCRC.h" + +#include "../../ICoder.h" +#include "../IArchive.h" + +namespace NArchive { +namespace N7z { + +Z7_CLASS_IMP_COM_2( + CFolderInStream + , ISequentialInStream + , ICompressGetSubStreamSize +) + /* + Z7_COM7F_IMP(GetNextStream(UInt64 *streamIndex)) + Z7_IFACE_COM7_IMP(ICompressInSubStreams) + */ + + CMyComPtr _stream; + UInt64 _totalSize_for_Coder; + UInt64 _pos; + UInt32 _crc; + bool _size_Defined; + bool _times_Defined; + UInt64 _size; + FILETIME _mTime; + FILETIME _cTime; + FILETIME _aTime; + UInt32 _attrib; + + unsigned _numFiles; + const UInt32 *_indexes; + + CMyComPtr _updateCallback; + + void ClearFileInfo(); + HRESULT OpenStream(); + HRESULT AddFileInfo(bool isProcessed); + // HRESULT CloseCrcStream(); +public: + bool Need_MTime; + bool Need_CTime; + bool Need_ATime; + bool Need_Attrib; + // bool Need_Crc; + // bool Need_FolderCrc; + // unsigned AlignLog; + + CRecordVector Processed; + CRecordVector Sizes; + CRecordVector CRCs; + CRecordVector Attribs; + CRecordVector TimesDefined; + CRecordVector MTimes; + CRecordVector CTimes; + CRecordVector ATimes; + // UInt32 FolderCrc; + + // UInt32 GetFolderCrc() const { return CRC_GET_DIGEST(FolderCrc); } + // CSequentialInStreamWithCRC *_crcStream_Spec; + // CMyComPtr _crcStream; + // CMyComPtr _reportArcProp; + + void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles); + + bool WasFinished() const { return Processed.Size() == _numFiles; } + + UInt64 Get_TotalSize_for_Coder() const { return _totalSize_for_Coder; } + /* + UInt64 GetFullSize() const + { + UInt64 size = 0; + FOR_VECTOR (i, Sizes) + size += Sizes[i]; + return size; + } + */ + + CFolderInStream(): + Need_MTime(false), + Need_CTime(false), + Need_ATime(false), + Need_Attrib(false) + // , Need_Crc(true) + // , Need_FolderCrc(false) + // , AlignLog(0) + {} +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index 0fd46b81b..81dd96691 100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -1,795 +1,795 @@ -// 7zHandler.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" - -#ifndef Z7_7Z_SET_PROPERTIES -#include "../../../Windows/System.h" -#endif - -#include "../Common/ItemNameUtils.h" - -#include "7zHandler.h" -#include "7zProperties.h" - -#ifdef Z7_7Z_SET_PROPERTIES -#ifdef Z7_EXTRACT_ONLY -#include "../Common/ParseProperties.h" -#endif -#endif - -using namespace NWindows; -using namespace NCOM; - -namespace NArchive { -namespace N7z { - -CHandler::CHandler() -{ - #ifndef Z7_NO_CRYPTO - _isEncrypted = false; - _passwordIsDefined = false; - #endif - - #ifdef Z7_EXTRACT_ONLY - - _crcSize = 4; - - #ifdef Z7_7Z_SET_PROPERTIES - _useMultiThreadMixer = true; - #endif - - #endif -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _db.Files.Size(); - return S_OK; -} - -#ifdef Z7_SFX - -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps)) -{ - *numProps = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 /* index */, - BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)) -{ - return E_NOTIMPL; -} - -#else - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidMethod, - kpidSolid, - kpidNumBlocks - // , kpidIsTree -}; - -IMP_IInArchive_ArcProps - -static inline char GetHex(unsigned value) -{ - return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); -} - -static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id) -{ - int len = 0; - do - { - s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; - s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; - } - while (id != 0); - return (unsigned)-len; -} - -static void ConvertMethodIdToString(AString &res, UInt64 id) -{ - const unsigned kLen = 32; - char s[kLen]; - unsigned len = kLen - 1; - s[len] = 0; - res += s + len - ConvertMethodIdToString_Back(s + len, id); -} - - -static char *GetStringForSizeValue(char *s, UInt32 val) -{ - for (unsigned i = 0; i < 32; i++) - if (((UInt32)1 << i) == val) - { - if (i >= 10) - { - *s++= (char)('0' + i / 10); - i %= 10; - } - *s++ = (char)('0' + i); - *s = 0; - return s; - } - - char c = 'b'; - if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } - else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } - s = ConvertUInt32ToString(val, s); - *s++ = c; - *s = 0; - return s; -} - - -static void GetLzma2String(char *s, unsigned d) -{ - if (d > 40) - { - *s = 0; - return; - // s = MyStpCpy(s, "unsup"); - } - else if ((d & 1) == 0) - d = (d >> 1) + 12; - else - { - // s = GetStringForSizeValue(s, (UInt32)3 << ((d >> 1) + 11)); - d = (d >> 1) + 1; - char c = 'k'; - if (d >= 10) - { - c = 'm'; - d -= 10; - } - s = ConvertUInt32ToString((UInt32)3 << d, s); - *s++ = c; - *s = 0; - return; - } - ConvertUInt32ToString(d, s); -} - - -/* -static inline void AddHexToString(UString &res, Byte value) -{ - res += GetHex((Byte)(value >> 4)); - res += GetHex((Byte)(value & 0xF)); -} -*/ - -static char *AddProp32(char *s, const char *name, UInt32 v) -{ - *s++ = ':'; - s = MyStpCpy(s, name); - return ConvertUInt32ToString(v, s); -} - -void CHandler::AddMethodName(AString &s, UInt64 id) -{ - AString name; - FindMethod(EXTERNAL_CODECS_VARS id, name); - if (name.IsEmpty()) - ConvertMethodIdToString(s, id); - else - s += name; -} - -#endif - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - #ifndef Z7_SFX - COM_TRY_BEGIN - #endif - NCOM::CPropVariant prop; - switch (propID) - { - #ifndef Z7_SFX - case kpidMethod: - { - AString s; - const CParsedMethods &pm = _db.ParsedMethods; - FOR_VECTOR (i, pm.IDs) - { - UInt64 id = pm.IDs[i]; - s.Add_Space_if_NotEmpty(); - char temp[16]; - if (id == k_LZMA2) - { - s += "LZMA2:"; - GetLzma2String(temp, pm.Lzma2Prop); - s += temp; - } - else if (id == k_LZMA) - { - s += "LZMA:"; - GetStringForSizeValue(temp, pm.LzmaDic); - s += temp; - } - /* - else if (id == k_ZSTD) - { - s += "ZSTD"; - } - */ - else - AddMethodName(s, id); - } - prop = s; - break; - } - case kpidSolid: prop = _db.IsSolid(); break; - case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break; - case kpidHeadersSize: prop = _db.HeadersSize; break; - case kpidPhySize: prop = _db.PhySize; break; - case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break; - /* - case kpidIsTree: if (_db.IsTree) prop = true; break; - case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break; - case kpidIsAux: if (_db.IsTree) prop = true; break; - */ - // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break; - #endif - - case kpidWarningFlags: - { - UInt32 v = 0; - if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError; - if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature; - if (v != 0) - prop = v; - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc; - if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError; - if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; - // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported; - if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature; - prop = v; - break; - } - - case kpidReadOnly: - { - if (!_db.CanUpdate()) - prop = true; - break; - } - default: break; - } - return prop.Detach(value); - #ifndef Z7_SFX - COM_TRY_END - #endif -} - -static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, unsigned index) -{ - UInt64 value; - if (v.GetItem(index, value)) - PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns); -} - -bool CHandler::IsFolderEncrypted(CNum folderIndex) const -{ - if (folderIndex == kNumNoIndex) - return false; - const size_t startPos = _db.FoCodersDataOffset[folderIndex]; - const Byte *p = _db.CodersData.ConstData() + startPos; - const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; - CInByte2 inByte; - inByte.Init(p, size); - - CNum numCoders = inByte.ReadNum(); - for (; numCoders != 0; numCoders--) - { - const Byte mainByte = inByte.ReadByte(); - const unsigned idSize = (mainByte & 0xF); - const Byte *longID = inByte.GetPtr(); - UInt64 id64 = 0; - for (unsigned j = 0; j < idSize; j++) - id64 = ((id64 << 8) | longID[j]); - inByte.SkipDataNoCheck(idSize); - if (id64 == k_AES) - return true; - if ((mainByte & 0x20) != 0) - inByte.SkipDataNoCheck(inByte.ReadNum()); - } - return false; -} - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) -{ - *name = NULL; - *propID = kpidNtSecure; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)) -{ - /* - const CFileItem &file = _db.Files[index]; - *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir); - *parent = (UInt32)(Int32)file.Parent; - */ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (/* _db.IsTree && propID == kpidName || - !_db.IsTree && */ propID == kpidPath) - { - if (_db.NameOffsets && _db.NamesBuf) - { - const size_t offset = _db.NameOffsets[index]; - const size_t size = (_db.NameOffsets[index + 1] - offset) * 2; - if (size < ((UInt32)1 << 31)) - { - *data = (const void *)(_db.NamesBuf.ConstData() + offset * 2); - *dataSize = (UInt32)size; - *propType = NPropDataType::kUtf16z; - } - } - return S_OK; - } - /* - if (propID == kpidNtSecure) - { - if (index < (UInt32)_db.SecureIDs.Size()) - { - int id = _db.SecureIDs[index]; - size_t offs = _db.SecureOffsets[id]; - size_t size = _db.SecureOffsets[id + 1] - offs; - if (size >= 0) - { - *data = _db.SecureBuf + offs; - *dataSize = (UInt32)size; - *propType = NPropDataType::kRaw; - } - } - } - */ - return S_OK; -} - -#ifndef Z7_SFX - -HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const -{ - PropVariant_Clear(prop); - if (folderIndex == kNumNoIndex) - return S_OK; - // for (int ttt = 0; ttt < 1; ttt++) { - const unsigned kTempSize = 256; - char temp[kTempSize]; - unsigned pos = kTempSize; - temp[--pos] = 0; - - const size_t startPos = _db.FoCodersDataOffset[folderIndex]; - const Byte *p = _db.CodersData.ConstData() + startPos; - const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; - CInByte2 inByte; - inByte.Init(p, size); - - // numCoders == 0 ??? - CNum numCoders = inByte.ReadNum(); - bool needSpace = false; - - for (; numCoders != 0; numCoders--, needSpace = true) - { - if (pos < 32) // max size of property - break; - const Byte mainByte = inByte.ReadByte(); - UInt64 id64 = 0; - const unsigned idSize = (mainByte & 0xF); - const Byte *longID = inByte.GetPtr(); - for (unsigned j = 0; j < idSize; j++) - id64 = ((id64 << 8) | longID[j]); - inByte.SkipDataNoCheck(idSize); - - if ((mainByte & 0x10) != 0) - { - inByte.ReadNum(); // NumInStreams - inByte.ReadNum(); // NumOutStreams - } - - CNum propsSize = 0; - const Byte *props = NULL; - if ((mainByte & 0x20) != 0) - { - propsSize = inByte.ReadNum(); - props = inByte.GetPtr(); - inByte.SkipDataNoCheck(propsSize); - } - - const char *name = NULL; - char s[32]; - s[0] = 0; - - if (id64 <= (UInt32)0xFFFFFFFF) - { - const UInt32 id = (UInt32)id64; - if (id == k_LZMA) - { - name = "LZMA"; - if (propsSize == 5) - { - const UInt32 dicSize = GetUi32((const Byte *)props + 1); - char *dest = GetStringForSizeValue(s, dicSize); - UInt32 d = props[0]; - if (d != 0x5D) - { - const UInt32 lc = d % 9; - d /= 9; - const UInt32 pb = d / 5; - const UInt32 lp = d % 5; - if (lc != 3) dest = AddProp32(dest, "lc", lc); - if (lp != 0) dest = AddProp32(dest, "lp", lp); - if (pb != 2) dest = AddProp32(dest, "pb", pb); - } - } - } - else if (id == k_LZMA2) - { - name = "LZMA2"; - if (propsSize == 1) - GetLzma2String(s, props[0]); - } - else if (id == k_PPMD) - { - name = "PPMD"; - if (propsSize == 5) - { - char *dest = s; - *dest++ = 'o'; - dest = ConvertUInt32ToString(*props, dest); - dest = MyStpCpy(dest, ":mem"); - GetStringForSizeValue(dest, GetUi32(props + 1)); - } - } - else if (id == k_Delta) - { - name = "Delta"; - if (propsSize == 1) - ConvertUInt32ToString((UInt32)props[0] + 1, s); - } - else if (id == k_ARM64 || id == k_RISCV) - { - name = id == k_ARM64 ? "ARM64" : "RISCV"; - if (propsSize == 4) - ConvertUInt32ToString(GetUi32(props), s); - /* - else if (propsSize != 0) - MyStringCopy(s, "unsupported"); - */ - } - else if (id == k_BCJ2) name = "BCJ2"; - else if (id == k_BCJ) name = "BCJ"; - else if (id == k_AES) - { - name = "7zAES"; - if (propsSize >= 1) - { - const Byte firstByte = props[0]; - const UInt32 numCyclesPower = firstByte & 0x3F; - ConvertUInt32ToString(numCyclesPower, s); - } - } - } - - if (name) - { - const unsigned nameLen = MyStringLen(name); - const unsigned propsLen = MyStringLen(s); - unsigned totalLen = nameLen + propsLen; - if (propsLen != 0) - totalLen++; - if (needSpace) - totalLen++; - if (totalLen + 5 >= pos) - break; - pos -= totalLen; - MyStringCopy(temp + pos, name); - if (propsLen != 0) - { - char *dest = temp + pos + nameLen; - *dest++ = ':'; - MyStringCopy(dest, s); - } - if (needSpace) - temp[pos + totalLen - 1] = ' '; - } - else - { - AString methodName; - FindMethod(EXTERNAL_CODECS_VARS id64, methodName); - if (needSpace) - temp[--pos] = ' '; - if (methodName.IsEmpty()) - pos -= ConvertMethodIdToString_Back(temp + pos, id64); - else - { - const unsigned len = methodName.Len(); - if (len + 5 > pos) - break; - pos -= len; - for (unsigned i = 0; i < len; i++) - temp[pos + i] = methodName[i]; - } - } - } - - if (numCoders != 0 && pos >= 4) - { - temp[--pos] = ' '; - temp[--pos] = '.'; - temp[--pos] = '.'; - temp[--pos] = '.'; - } - - return PropVarEm_Set_Str(prop, temp + pos); - // } -} - -#endif - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - RINOK(PropVariant_Clear(value)) - // COM_TRY_BEGIN - // NCOM::CPropVariant prop; - - /* - const CRef2 &ref2 = _refs[index]; - if (ref2.Refs.IsEmpty()) - return E_FAIL; - const CRef &ref = ref2.Refs.Front(); - */ - - const CFileItem &item = _db.Files[index]; - const UInt32 index2 = index; - - switch (propID) - { - case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; - case kpidSize: - { - PropVarEm_Set_UInt64(value, item.Size); - // prop = ref2.Size; - break; - } - case kpidPackSize: - { - // prop = ref2.PackSize; - { - const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; - if (folderIndex != kNumNoIndex) - { - if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) - PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex)); - /* - else - PropVarEm_Set_UInt64(value, 0); - */ - } - else - PropVarEm_Set_UInt64(value, 0); - } - break; - } - // case kpidIsAux: prop = _db.IsItemAux(index2); break; - case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; } - case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break; - case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break; - case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break; - case kpidAttrib: if (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); break; - case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break; - case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break; - case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break; - /* - case kpidIsAltStream: prop = item.IsAltStream; break; - case kpidNtSecure: - { - int id = _db.SecureIDs[index]; - size_t offs = _db.SecureOffsets[id]; - size_t size = _db.SecureOffsets[id + 1] - offs; - if (size >= 0) - { - prop.SetBlob(_db.SecureBuf + offs, (ULONG)size); - } - break; - } - */ - - case kpidPath: return _db.GetPath_Prop(index, value); - - #ifndef Z7_SFX - - case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); - case kpidBlock: - { - const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; - if (folderIndex != kNumNoIndex) - PropVarEm_Set_UInt32(value, (UInt32)folderIndex); - } - break; - #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES - case kpidPackedSize0: - case kpidPackedSize1: - case kpidPackedSize2: - case kpidPackedSize3: - case kpidPackedSize4: - { - const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; - if (folderIndex != kNumNoIndex) - { - if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 && - _db.FoStartPackStreamIndex[folderIndex + 1] - - _db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0)) - { - PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0)); - } - } - else - PropVarEm_Set_UInt64(value, 0); - } - break; - #endif - - #endif - default: break; - } - // return prop.Detach(value); - return S_OK; - // COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openArchiveCallback)) -{ - COM_TRY_BEGIN - Close(); - #ifndef Z7_SFX - _fileInfoPopIDs.Clear(); - #endif - - try - { - CMyComPtr openArchiveCallbackTemp = openArchiveCallback; - - #ifndef Z7_NO_CRYPTO - CMyComPtr getTextPassword; - if (openArchiveCallback) - openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); - #endif - - CInArchive archive( - #ifdef Z7_7Z_SET_PROPERTIES - _useMultiThreadMixer - #else - true - #endif - ); - _db.IsArc = false; - RINOK(archive.Open(stream, maxCheckStartPosition)) - _db.IsArc = true; - - HRESULT result = archive.ReadDatabase( - EXTERNAL_CODECS_VARS - _db - #ifndef Z7_NO_CRYPTO - , getTextPassword, _isEncrypted, _passwordIsDefined, _password - #endif - ); - RINOK(result) - - _inStream = stream; - } - catch(...) - { - Close(); - // return E_INVALIDARG; - // return S_FALSE; - // we must return out_of_memory here - return E_OUTOFMEMORY; - } - // _inStream = stream; - #ifndef Z7_SFX - FillPopIDs(); - #endif - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - COM_TRY_BEGIN - _inStream.Release(); - _db.Clear(); - #ifndef Z7_NO_CRYPTO - _isEncrypted = false; - _passwordIsDefined = false; - _password.Wipe_and_Empty(); - #endif - return S_OK; - COM_TRY_END -} - -#ifdef Z7_7Z_SET_PROPERTIES -#ifdef Z7_EXTRACT_ONLY - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - COM_TRY_BEGIN - - InitCommon(); - _useMultiThreadMixer = true; - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - const PROPVARIANT &value = values[i]; - UInt32 number; - const unsigned index = ParseStringToUInt32(name, number); - if (index == 0) - { - if (name.IsEqualTo("mtf")) - { - RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer)) - continue; - } - { - HRESULT hres; - if (SetCommonProperty(name, value, hres)) - { - RINOK(hres) - continue; - } - } - return E_INVALIDARG; - } - } - return S_OK; - COM_TRY_END -} - -#endif -#endif - -IMPL_ISetCompressCodecsInfo - -}} +// 7zHandler.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" + +#ifndef Z7_7Z_SET_PROPERTIES +#include "../../../Windows/System.h" +#endif + +#include "../Common/ItemNameUtils.h" + +#include "7zHandler.h" +#include "7zProperties.h" + +#ifdef Z7_7Z_SET_PROPERTIES +#ifdef Z7_EXTRACT_ONLY +#include "../Common/ParseProperties.h" +#endif +#endif + +using namespace NWindows; +using namespace NCOM; + +namespace NArchive { +namespace N7z { + +CHandler::CHandler() +{ + #ifndef Z7_NO_CRYPTO + _isEncrypted = false; + _passwordIsDefined = false; + #endif + + #ifdef Z7_EXTRACT_ONLY + + _crcSize = 4; + + #ifdef Z7_7Z_SET_PROPERTIES + _useMultiThreadMixer = true; + #endif + + #endif +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _db.Files.Size(); + return S_OK; +} + +#ifdef Z7_SFX + +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps)) +{ + *numProps = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 /* index */, + BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)) +{ + return E_NOTIMPL; +} + +#else + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidMethod, + kpidSolid, + kpidNumBlocks + // , kpidIsTree +}; + +IMP_IInArchive_ArcProps + +static inline char GetHex(unsigned value) +{ + return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); +} + +static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id) +{ + int len = 0; + do + { + s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; + s[--len] = GetHex((unsigned)id & 0xF); id >>= 4; + } + while (id != 0); + return (unsigned)-len; +} + +static void ConvertMethodIdToString(AString &res, UInt64 id) +{ + const unsigned kLen = 32; + char s[kLen]; + unsigned len = kLen - 1; + s[len] = 0; + res += s + len - ConvertMethodIdToString_Back(s + len, id); +} + + +static char *GetStringForSizeValue(char *s, UInt32 val) +{ + for (unsigned i = 0; i < 32; i++) + if (((UInt32)1 << i) == val) + { + if (i >= 10) + { + *s++= (char)('0' + i / 10); + i %= 10; + } + *s++ = (char)('0' + i); + *s = 0; + return s; + } + + char c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + s = ConvertUInt32ToString(val, s); + *s++ = c; + *s = 0; + return s; +} + + +static void GetLzma2String(char *s, unsigned d) +{ + if (d > 40) + { + *s = 0; + return; + // s = MyStpCpy(s, "unsup"); + } + else if ((d & 1) == 0) + d = (d >> 1) + 12; + else + { + // s = GetStringForSizeValue(s, (UInt32)3 << ((d >> 1) + 11)); + d = (d >> 1) + 1; + char c = 'k'; + if (d >= 10) + { + c = 'm'; + d -= 10; + } + s = ConvertUInt32ToString((UInt32)3 << d, s); + *s++ = c; + *s = 0; + return; + } + ConvertUInt32ToString(d, s); +} + + +/* +static inline void AddHexToString(UString &res, Byte value) +{ + res += GetHex((Byte)(value >> 4)); + res += GetHex((Byte)(value & 0xF)); +} +*/ + +static char *AddProp32(char *s, const char *name, UInt32 v) +{ + *s++ = ':'; + s = MyStpCpy(s, name); + return ConvertUInt32ToString(v, s); +} + +void CHandler::AddMethodName(AString &s, UInt64 id) +{ + AString name; + FindMethod(EXTERNAL_CODECS_VARS id, name); + if (name.IsEmpty()) + ConvertMethodIdToString(s, id); + else + s += name; +} + +#endif + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + #ifndef Z7_SFX + COM_TRY_BEGIN + #endif + NCOM::CPropVariant prop; + switch (propID) + { + #ifndef Z7_SFX + case kpidMethod: + { + AString s; + const CParsedMethods &pm = _db.ParsedMethods; + FOR_VECTOR (i, pm.IDs) + { + UInt64 id = pm.IDs[i]; + s.Add_Space_if_NotEmpty(); + char temp[16]; + if (id == k_LZMA2) + { + s += "LZMA2:"; + GetLzma2String(temp, pm.Lzma2Prop); + s += temp; + } + else if (id == k_LZMA) + { + s += "LZMA:"; + GetStringForSizeValue(temp, pm.LzmaDic); + s += temp; + } + /* + else if (id == k_ZSTD) + { + s += "ZSTD"; + } + */ + else + AddMethodName(s, id); + } + prop = s; + break; + } + case kpidSolid: prop = _db.IsSolid(); break; + case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break; + case kpidHeadersSize: prop = _db.HeadersSize; break; + case kpidPhySize: prop = _db.PhySize; break; + case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break; + /* + case kpidIsTree: if (_db.IsTree) prop = true; break; + case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break; + case kpidIsAux: if (_db.IsTree) prop = true; break; + */ + // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break; + #endif + + case kpidWarningFlags: + { + UInt32 v = 0; + if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError; + if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature; + if (v != 0) + prop = v; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError; + if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported; + if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature; + prop = v; + break; + } + + case kpidReadOnly: + { + if (!_db.CanUpdate()) + prop = true; + break; + } + default: break; + } + return prop.Detach(value); + #ifndef Z7_SFX + COM_TRY_END + #endif +} + +static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, unsigned index) +{ + UInt64 value; + if (v.GetItem(index, value)) + PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns); +} + +bool CHandler::IsFolderEncrypted(CNum folderIndex) const +{ + if (folderIndex == kNumNoIndex) + return false; + const size_t startPos = _db.FoCodersDataOffset[folderIndex]; + const Byte *p = _db.CodersData.ConstData() + startPos; + const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; + CInByte2 inByte; + inByte.Init(p, size); + + CNum numCoders = inByte.ReadNum(); + for (; numCoders != 0; numCoders--) + { + const Byte mainByte = inByte.ReadByte(); + const unsigned idSize = (mainByte & 0xF); + const Byte *longID = inByte.GetPtr(); + UInt64 id64 = 0; + for (unsigned j = 0; j < idSize; j++) + id64 = ((id64 << 8) | longID[j]); + inByte.SkipDataNoCheck(idSize); + if (id64 == k_AES) + return true; + if ((mainByte & 0x20) != 0) + inByte.SkipDataNoCheck(inByte.ReadNum()); + } + return false; +} + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) +{ + *name = NULL; + *propID = kpidNtSecure; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)) +{ + /* + const CFileItem &file = _db.Files[index]; + *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir); + *parent = (UInt32)(Int32)file.Parent; + */ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (/* _db.IsTree && propID == kpidName || + !_db.IsTree && */ propID == kpidPath) + { + if (_db.NameOffsets && _db.NamesBuf) + { + const size_t offset = _db.NameOffsets[index]; + const size_t size = (_db.NameOffsets[index + 1] - offset) * 2; + if (size < ((UInt32)1 << 31)) + { + *data = (const void *)(_db.NamesBuf.ConstData() + offset * 2); + *dataSize = (UInt32)size; + *propType = NPropDataType::kUtf16z; + } + } + return S_OK; + } + /* + if (propID == kpidNtSecure) + { + if (index < (UInt32)_db.SecureIDs.Size()) + { + int id = _db.SecureIDs[index]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + if (size >= 0) + { + *data = _db.SecureBuf + offs; + *dataSize = (UInt32)size; + *propType = NPropDataType::kRaw; + } + } + } + */ + return S_OK; +} + +#ifndef Z7_SFX + +HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const +{ + PropVariant_Clear(prop); + if (folderIndex == kNumNoIndex) + return S_OK; + // for (int ttt = 0; ttt < 1; ttt++) { + const unsigned kTempSize = 256; + char temp[kTempSize]; + unsigned pos = kTempSize; + temp[--pos] = 0; + + const size_t startPos = _db.FoCodersDataOffset[folderIndex]; + const Byte *p = _db.CodersData.ConstData() + startPos; + const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos; + CInByte2 inByte; + inByte.Init(p, size); + + // numCoders == 0 ??? + CNum numCoders = inByte.ReadNum(); + bool needSpace = false; + + for (; numCoders != 0; numCoders--, needSpace = true) + { + if (pos < 32) // max size of property + break; + const Byte mainByte = inByte.ReadByte(); + UInt64 id64 = 0; + const unsigned idSize = (mainByte & 0xF); + const Byte *longID = inByte.GetPtr(); + for (unsigned j = 0; j < idSize; j++) + id64 = ((id64 << 8) | longID[j]); + inByte.SkipDataNoCheck(idSize); + + if ((mainByte & 0x10) != 0) + { + inByte.ReadNum(); // NumInStreams + inByte.ReadNum(); // NumOutStreams + } + + CNum propsSize = 0; + const Byte *props = NULL; + if ((mainByte & 0x20) != 0) + { + propsSize = inByte.ReadNum(); + props = inByte.GetPtr(); + inByte.SkipDataNoCheck(propsSize); + } + + const char *name = NULL; + char s[32]; + s[0] = 0; + + if (id64 <= (UInt32)0xFFFFFFFF) + { + const UInt32 id = (UInt32)id64; + if (id == k_LZMA) + { + name = "LZMA"; + if (propsSize == 5) + { + const UInt32 dicSize = GetUi32((const Byte *)props + 1); + char *dest = GetStringForSizeValue(s, dicSize); + UInt32 d = props[0]; + if (d != 0x5D) + { + const UInt32 lc = d % 9; + d /= 9; + const UInt32 pb = d / 5; + const UInt32 lp = d % 5; + if (lc != 3) dest = AddProp32(dest, "lc", lc); + if (lp != 0) dest = AddProp32(dest, "lp", lp); + if (pb != 2) dest = AddProp32(dest, "pb", pb); + } + } + } + else if (id == k_LZMA2) + { + name = "LZMA2"; + if (propsSize == 1) + GetLzma2String(s, props[0]); + } + else if (id == k_PPMD) + { + name = "PPMD"; + if (propsSize == 5) + { + char *dest = s; + *dest++ = 'o'; + dest = ConvertUInt32ToString(*props, dest); + dest = MyStpCpy(dest, ":mem"); + GetStringForSizeValue(dest, GetUi32(props + 1)); + } + } + else if (id == k_Delta) + { + name = "Delta"; + if (propsSize == 1) + ConvertUInt32ToString((UInt32)props[0] + 1, s); + } + else if (id == k_ARM64 || id == k_RISCV) + { + name = id == k_ARM64 ? "ARM64" : "RISCV"; + if (propsSize == 4) + ConvertUInt32ToString(GetUi32(props), s); + /* + else if (propsSize != 0) + MyStringCopy(s, "unsupported"); + */ + } + else if (id == k_BCJ2) name = "BCJ2"; + else if (id == k_BCJ) name = "BCJ"; + else if (id == k_AES) + { + name = "7zAES"; + if (propsSize >= 1) + { + const Byte firstByte = props[0]; + const UInt32 numCyclesPower = firstByte & 0x3F; + ConvertUInt32ToString(numCyclesPower, s); + } + } + } + + if (name) + { + const unsigned nameLen = MyStringLen(name); + const unsigned propsLen = MyStringLen(s); + unsigned totalLen = nameLen + propsLen; + if (propsLen != 0) + totalLen++; + if (needSpace) + totalLen++; + if (totalLen + 5 >= pos) + break; + pos -= totalLen; + MyStringCopy(temp + pos, name); + if (propsLen != 0) + { + char *dest = temp + pos + nameLen; + *dest++ = ':'; + MyStringCopy(dest, s); + } + if (needSpace) + temp[pos + totalLen - 1] = ' '; + } + else + { + AString methodName; + FindMethod(EXTERNAL_CODECS_VARS id64, methodName); + if (needSpace) + temp[--pos] = ' '; + if (methodName.IsEmpty()) + pos -= ConvertMethodIdToString_Back(temp + pos, id64); + else + { + const unsigned len = methodName.Len(); + if (len + 5 > pos) + break; + pos -= len; + for (unsigned i = 0; i < len; i++) + temp[pos + i] = methodName[i]; + } + } + } + + if (numCoders != 0 && pos >= 4) + { + temp[--pos] = ' '; + temp[--pos] = '.'; + temp[--pos] = '.'; + temp[--pos] = '.'; + } + + return PropVarEm_Set_Str(prop, temp + pos); + // } +} + +#endif + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + RINOK(PropVariant_Clear(value)) + // COM_TRY_BEGIN + // NCOM::CPropVariant prop; + + /* + const CRef2 &ref2 = _refs[index]; + if (ref2.Refs.IsEmpty()) + return E_FAIL; + const CRef &ref = ref2.Refs.Front(); + */ + + const CFileItem &item = _db.Files[index]; + const UInt32 index2 = index; + + switch (propID) + { + case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break; + case kpidSize: + { + PropVarEm_Set_UInt64(value, item.Size); + // prop = ref2.Size; + break; + } + case kpidPackSize: + { + // prop = ref2.PackSize; + { + const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2) + PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex)); + /* + else + PropVarEm_Set_UInt64(value, 0); + */ + } + else + PropVarEm_Set_UInt64(value, 0); + } + break; + } + // case kpidIsAux: prop = _db.IsItemAux(index2); break; + case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; } + case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break; + case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break; + case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break; + case kpidAttrib: if (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); break; + case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break; + case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break; + case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break; + /* + case kpidIsAltStream: prop = item.IsAltStream; break; + case kpidNtSecure: + { + int id = _db.SecureIDs[index]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + if (size >= 0) + { + prop.SetBlob(_db.SecureBuf + offs, (ULONG)size); + } + break; + } + */ + + case kpidPath: return _db.GetPath_Prop(index, value); + + #ifndef Z7_SFX + + case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value); + case kpidBlock: + { + const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + PropVarEm_Set_UInt32(value, (UInt32)folderIndex); + } + break; + #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES + case kpidPackedSize0: + case kpidPackedSize1: + case kpidPackedSize2: + case kpidPackedSize3: + case kpidPackedSize4: + { + const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 && + _db.FoStartPackStreamIndex[folderIndex + 1] - + _db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0)) + { + PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0)); + } + } + else + PropVarEm_Set_UInt64(value, 0); + } + break; + #endif + + #endif + default: break; + } + // return prop.Detach(value); + return S_OK; + // COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openArchiveCallback)) +{ + COM_TRY_BEGIN + Close(); + #ifndef Z7_SFX + _fileInfoPopIDs.Clear(); + #endif + + try + { + CMyComPtr openArchiveCallbackTemp = openArchiveCallback; + + #ifndef Z7_NO_CRYPTO + CMyComPtr getTextPassword; + if (openArchiveCallback) + openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + #endif + + CInArchive archive( + #ifdef Z7_7Z_SET_PROPERTIES + _useMultiThreadMixer + #else + true + #endif + ); + _db.IsArc = false; + RINOK(archive.Open(stream, maxCheckStartPosition)) + _db.IsArc = true; + + HRESULT result = archive.ReadDatabase( + EXTERNAL_CODECS_VARS + _db + #ifndef Z7_NO_CRYPTO + , getTextPassword, _isEncrypted, _passwordIsDefined, _password + #endif + ); + RINOK(result) + + _inStream = stream; + } + catch(...) + { + Close(); + // return E_INVALIDARG; + // return S_FALSE; + // we must return out_of_memory here + return E_OUTOFMEMORY; + } + // _inStream = stream; + #ifndef Z7_SFX + FillPopIDs(); + #endif + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + COM_TRY_BEGIN + _inStream.Release(); + _db.Clear(); + #ifndef Z7_NO_CRYPTO + _isEncrypted = false; + _passwordIsDefined = false; + _password.Wipe_and_Empty(); + #endif + return S_OK; + COM_TRY_END +} + +#ifdef Z7_7Z_SET_PROPERTIES +#ifdef Z7_EXTRACT_ONLY + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + COM_TRY_BEGIN + + InitCommon(); + _useMultiThreadMixer = true; + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + const PROPVARIANT &value = values[i]; + UInt32 number; + const unsigned index = ParseStringToUInt32(name, number); + if (index == 0) + { + if (name.IsEqualTo("mtf")) + { + RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer)) + continue; + } + { + HRESULT hres; + if (SetCommonProperty(name, value, hres)) + { + RINOK(hres) + continue; + } + } + return E_INVALIDARG; + } + } + return S_OK; + COM_TRY_END +} + +#endif +#endif + +IMPL_ISetCompressCodecsInfo + +}} diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h index ec633bfab..ed535f74d 100644 --- a/CPP/7zip/Archive/7z/7zHandler.h +++ b/CPP/7zip/Archive/7z/7zHandler.h @@ -1,178 +1,178 @@ -// 7z/Handler.h - -#ifndef ZIP7_7Z_HANDLER_H -#define ZIP7_7Z_HANDLER_H - -#include "../../ICoder.h" -#include "../IArchive.h" - -#include "../../Common/CreateCoder.h" - -#ifndef Z7_7Z_SET_PROPERTIES - -#ifdef Z7_EXTRACT_ONLY - #if !defined(Z7_ST) && !defined(Z7_SFX) - #define Z7_7Z_SET_PROPERTIES - #endif -#else - #define Z7_7Z_SET_PROPERTIES -#endif - -#endif - -// #ifdef Z7_7Z_SET_PROPERTIES -#include "../Common/HandlerOut.h" -// #endif - -#include "7zCompressionMode.h" -#include "7zIn.h" - -namespace NArchive { -namespace N7z { - - -#ifndef Z7_EXTRACT_ONLY - -class COutHandler: public CMultiMethodProps -{ - HRESULT SetSolidFromString(const UString &s); - HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value); -public: - UInt64 _numSolidFiles; - UInt64 _numSolidBytes; - bool _numSolidBytesDefined; - bool _solidExtension; - bool _useTypeSorting; - - bool _compressHeaders; - bool _encryptHeadersSpecified; - bool _encryptHeaders; - // bool _useParents; 9.26 - - CHandlerTimeOptions TimeOptions; - - CBoolPair Write_Attrib; - - bool _useMultiThreadMixer; - bool _removeSfxBlock; - // bool _volumeMode; - - UInt32 _decoderCompatibilityVersion; - CUIntVector _enabledFilters; - CUIntVector _disabledFilters; - - void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } - void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } - void InitSolid() - { - InitSolidFiles(); - InitSolidSize(); - _solidExtension = false; - _numSolidBytesDefined = false; - } - - void InitProps7z(); - void InitProps(); - - COutHandler() { InitProps7z(); } - - HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); -}; - -#endif - -class CHandler Z7_final: - public IInArchive, - public IArchiveGetRawProps, - - #ifdef Z7_7Z_SET_PROPERTIES - public ISetProperties, - #endif - - #ifndef Z7_EXTRACT_ONLY - public IOutArchive, - #endif - - Z7_PUBLIC_ISetCompressCodecsInfo_IFEC - - public CMyUnknownImp, - - #ifndef Z7_EXTRACT_ONLY - public COutHandler - #else - public CCommonMethodProps - #endif -{ - Z7_COM_QI_BEGIN2(IInArchive) - Z7_COM_QI_ENTRY(IArchiveGetRawProps) - #ifdef Z7_7Z_SET_PROPERTIES - Z7_COM_QI_ENTRY(ISetProperties) - #endif - #ifndef Z7_EXTRACT_ONLY - Z7_COM_QI_ENTRY(IOutArchive) - #endif - Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInArchive) - Z7_IFACE_COM7_IMP(IArchiveGetRawProps) - #ifdef Z7_7Z_SET_PROPERTIES - Z7_IFACE_COM7_IMP(ISetProperties) - #endif - #ifndef Z7_EXTRACT_ONLY - Z7_IFACE_COM7_IMP(IOutArchive) - #endif - DECL_ISetCompressCodecsInfo - -private: - CMyComPtr _inStream; - NArchive::N7z::CDbEx _db; - - #ifndef Z7_NO_CRYPTO - bool _isEncrypted; - bool _passwordIsDefined; - UString _password; // _Wipe - #endif - - #ifdef Z7_EXTRACT_ONLY - - #ifdef Z7_7Z_SET_PROPERTIES - bool _useMultiThreadMixer; - #endif - - UInt32 _crcSize; - - #else - - CRecordVector _bonds; - - HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); - HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); - HRESULT SetMainMethod(CCompressionMethodMode &method); - - #endif - - bool IsFolderEncrypted(CNum folderIndex) const; - #ifndef Z7_SFX - - CRecordVector _fileInfoPopIDs; - void FillPopIDs(); - void AddMethodName(AString &s, UInt64 id); - HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const; - - #endif - - DECL_EXTERNAL_CODECS_VARS - -public: - CHandler(); - ~CHandler() - { - Close(); - } -}; - -}} - -#endif +// 7z/Handler.h + +#ifndef ZIP7_7Z_HANDLER_H +#define ZIP7_7Z_HANDLER_H + +#include "../../ICoder.h" +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#ifndef Z7_7Z_SET_PROPERTIES + +#ifdef Z7_EXTRACT_ONLY + #if !defined(Z7_ST) && !defined(Z7_SFX) + #define Z7_7Z_SET_PROPERTIES + #endif +#else + #define Z7_7Z_SET_PROPERTIES +#endif + +#endif + +// #ifdef Z7_7Z_SET_PROPERTIES +#include "../Common/HandlerOut.h" +// #endif + +#include "7zCompressionMode.h" +#include "7zIn.h" + +namespace NArchive { +namespace N7z { + + +#ifndef Z7_EXTRACT_ONLY + +class COutHandler: public CMultiMethodProps +{ + HRESULT SetSolidFromString(const UString &s); + HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value); +public: + UInt64 _numSolidFiles; + UInt64 _numSolidBytes; + bool _numSolidBytesDefined; + bool _solidExtension; + bool _useTypeSorting; + + bool _compressHeaders; + bool _encryptHeadersSpecified; + bool _encryptHeaders; + // bool _useParents; 9.26 + + CHandlerTimeOptions TimeOptions; + + CBoolPair Write_Attrib; + + bool _useMultiThreadMixer; + bool _removeSfxBlock; + // bool _volumeMode; + + UInt32 _decoderCompatibilityVersion; + CUIntVector _enabledFilters; + CUIntVector _disabledFilters; + + void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); } + void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); } + void InitSolid() + { + InitSolidFiles(); + InitSolidSize(); + _solidExtension = false; + _numSolidBytesDefined = false; + } + + void InitProps7z(); + void InitProps(); + + COutHandler() { InitProps7z(); } + + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); +}; + +#endif + +class CHandler Z7_final: + public IInArchive, + public IArchiveGetRawProps, + + #ifdef Z7_7Z_SET_PROPERTIES + public ISetProperties, + #endif + + #ifndef Z7_EXTRACT_ONLY + public IOutArchive, + #endif + + Z7_PUBLIC_ISetCompressCodecsInfo_IFEC + + public CMyUnknownImp, + + #ifndef Z7_EXTRACT_ONLY + public COutHandler + #else + public CCommonMethodProps + #endif +{ + Z7_COM_QI_BEGIN2(IInArchive) + Z7_COM_QI_ENTRY(IArchiveGetRawProps) + #ifdef Z7_7Z_SET_PROPERTIES + Z7_COM_QI_ENTRY(ISetProperties) + #endif + #ifndef Z7_EXTRACT_ONLY + Z7_COM_QI_ENTRY(IOutArchive) + #endif + Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInArchive) + Z7_IFACE_COM7_IMP(IArchiveGetRawProps) + #ifdef Z7_7Z_SET_PROPERTIES + Z7_IFACE_COM7_IMP(ISetProperties) + #endif + #ifndef Z7_EXTRACT_ONLY + Z7_IFACE_COM7_IMP(IOutArchive) + #endif + DECL_ISetCompressCodecsInfo + +private: + CMyComPtr _inStream; + NArchive::N7z::CDbEx _db; + + #ifndef Z7_NO_CRYPTO + bool _isEncrypted; + bool _passwordIsDefined; + UString _password; // _Wipe + #endif + + #ifdef Z7_EXTRACT_ONLY + + #ifdef Z7_7Z_SET_PROPERTIES + bool _useMultiThreadMixer; + #endif + + UInt32 _crcSize; + + #else + + CRecordVector _bonds; + + HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m); + HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod); + HRESULT SetMainMethod(CCompressionMethodMode &method); + + #endif + + bool IsFolderEncrypted(CNum folderIndex) const; + #ifndef Z7_SFX + + CRecordVector _fileInfoPopIDs; + void FillPopIDs(); + void AddMethodName(AString &s, UInt64 id); + HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const; + + #endif + + DECL_EXTERNAL_CODECS_VARS + +public: + CHandler(); + ~CHandler() + { + Close(); + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp index 97476a509..ea5ea0f00 100644 --- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp +++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp @@ -1,1158 +1,1158 @@ -// 7zHandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/Wildcard.h" - -#include "../Common/ItemNameUtils.h" -#include "../Common/ParseProperties.h" - -#include "7zHandler.h" -#include "7zOut.h" -#include "7zUpdate.h" - -#ifndef Z7_EXTRACT_ONLY - -using namespace NWindows; - -namespace NArchive { -namespace N7z { - -static const UInt32 k_decoderCompatibilityVersion = 2301; -// 7-Zip version 2301 supports ARM64 filter - -#define k_LZMA_Name "LZMA" -#define kDefaultMethodName "LZMA2" -#define k_Copy_Name "Copy" - -#define k_MatchFinder_ForHeaders "BT2" - -static const UInt32 k_NumFastBytes_ForHeaders = 273; -static const UInt32 k_Level_ForHeaders = 5; -static const UInt32 k_Dictionary_ForHeaders = - #ifdef UNDER_CE - 1 << 18; - #else - 1 << 20; - #endif - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) -{ - *type = NFileTimeType::kWindows; - return S_OK; -} - -HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) -{ - bool isFilter; - dest.CodecIndex = FindMethod_Index( - EXTERNAL_CODECS_VARS - m.MethodName, true, - dest.Id, dest.NumStreams, isFilter); - if (dest.CodecIndex < 0) - return E_INVALIDARG; - (CProps &)dest = (CProps &)m; - return S_OK; -} - -HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) -{ - if (!_compressHeaders) - return S_OK; - COneMethodInfo m; - m.MethodName = k_LZMA_Name; - m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); - m.AddProp_Level(k_Level_ForHeaders); - m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); - m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); - m.AddProp_NumThreads(1); - - CMethodFull &methodFull = headerMethod.Methods.AddNew(); - return PropsMethod_To_FullMethod(methodFull, m); -} - - -HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) -{ - methodMode.Bonds = _bonds; - - // we create local copy of _methods. So we can modify it. - CObjectVector methods = _methods; - - { - FOR_VECTOR (i, methods) - { - AString &methodName = methods[i].MethodName; - if (methodName.IsEmpty()) - methodName = kDefaultMethodName; - } - if (methods.IsEmpty()) - { - COneMethodInfo &m = methods.AddNew(); - m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); - methodMode.DefaultMethod_was_Inserted = true; - } - } - - if (!_filterMethod.MethodName.IsEmpty()) - { - // if (methodMode.Bonds.IsEmpty()) - { - FOR_VECTOR (k, methodMode.Bonds) - { - CBond2 &bond = methodMode.Bonds[k]; - bond.InCoder++; - bond.OutCoder++; - } - methods.Insert(0, _filterMethod); - methodMode.Filter_was_Inserted = true; - } - } - - const UInt64 kSolidBytes_Min = (1 << 24); - const UInt64 kSolidBytes_Max = ((UInt64)1 << 32); - - bool needSolid = false; - - FOR_VECTOR (i, methods) - { - COneMethodInfo &oneMethodInfo = methods[i]; - - SetGlobalLevelTo(oneMethodInfo); - - #ifndef Z7_ST - const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); - if (!numThreads_WasSpecifiedInMethod) - { - // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already - CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads); - } - #endif - - CMethodFull &methodFull = methodMode.Methods.AddNew(); - RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)) - - #ifndef Z7_ST - methodFull.Set_NumThreads = true; - methodFull.NumThreads = methodMode.NumThreads; - #endif - - if (methodFull.Id != k_Copy) - needSolid = true; - - UInt64 dicSize; - switch (methodFull.Id) - { - case k_LZMA: - case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break; - case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break; - case k_Deflate: dicSize = (UInt32)1 << 15; break; - case k_Deflate64: dicSize = (UInt32)1 << 16; break; - case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; - // case k_ZSTD: dicSize = 1 << 23; break; - default: continue; - } - - UInt64 numSolidBytes; - - /* - if (methodFull.Id == k_ZSTD) - { - // continue; - NCompress::NZstd::CEncoderProps encoderProps; - RINOK(oneMethodInfo.Set_PropsTo_zstd(encoderProps)); - CZstdEncProps &zstdProps = encoderProps.EncProps; - ZstdEncProps_NormalizeFull(&zstdProps); - UInt64 cs = (UInt64)(zstdProps.jobSize); - UInt32 winSize = (UInt32)(1 << zstdProps.windowLog); - if (cs < winSize) - cs = winSize; - numSolidBytes = cs << 6; - const UInt64 kSolidBytes_Zstd_Max = ((UInt64)1 << 34); - if (numSolidBytes > kSolidBytes_Zstd_Max) - numSolidBytes = kSolidBytes_Zstd_Max; - - methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder - - #ifndef Z7_ST - if (!numThreads_WasSpecifiedInMethod - && !methodMode.NumThreads_WasForced - && methodMode.MemoryUsageLimit_WasSet - ) - { - const UInt32 numThreads_Original = methodMode.NumThreads; - const UInt32 numThreads_New = ZstdEncProps_GetNumThreads_for_MemUsageLimit( - &zstdProps, - methodMode.MemoryUsageLimit, - numThreads_Original); - if (numThreads_Original != numThreads_New) - { - CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New); - } - } - #endif - } - else - */ - if (methodFull.Id == k_LZMA2) - { - // he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code - /* lzma2 code use dictionary up to fake 4 GiB to calculate ChunkSize. - So we do same */ - UInt64 cs = (UInt64)dicSize << 2; - const UInt32 kMinSize = (UInt32)1 << 20; - const UInt32 kMaxSize = (UInt32)1 << 28; - if (cs < kMinSize) cs = kMinSize; - if (cs > kMaxSize) cs = kMaxSize; - if (cs < dicSize) cs = dicSize; - cs += (kMinSize - 1); - cs &= ~(UInt64)(kMinSize - 1); - // we want to use at least 64 chunks (threads) per one solid block. - - // here we don't use chunkSize property - numSolidBytes = cs << 6; - - // here we get real chunkSize - cs = oneMethodInfo.Get_Xz_BlockSize(); - if (dicSize > cs) - dicSize = cs; - - const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34); - if (numSolidBytes > kSolidBytes_Lzma2_Max) - numSolidBytes = kSolidBytes_Lzma2_Max; - - methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder - - #ifndef Z7_ST - if (!numThreads_WasSpecifiedInMethod - && !methodMode.NumThreads_WasForced - && methodMode.MemoryUsageLimit_WasSet - ) - { - const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); - const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads; - - if (numBlockThreads_Original > 1) - { - /* - const UInt32 kNumThreads_Max = 1024; - if (numBlockThreads > kNumMaxThreads) - numBlockThreads = kNumMaxThreads; - */ - - UInt32 numBlockThreads = numBlockThreads_Original; - const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid - - for (; numBlockThreads > 1; numBlockThreads--) - { - UInt64 size = numBlockThreads * (lzmaMemUsage + cs); - UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; - if (cs < ((UInt32)1 << 26)) numPackChunks++; - if (cs < ((UInt32)1 << 24)) numPackChunks++; - if (cs < ((UInt32)1 << 22)) numPackChunks++; - size += numPackChunks * cs; - // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20)); - if (size <= methodMode.MemoryUsageLimit) - break; - } - - if (numBlockThreads == 0) - numBlockThreads = 1; - if (numBlockThreads != numBlockThreads_Original) - { - const UInt32 numThreads_New = numBlockThreads * lzmaThreads; - CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New); - } - } - } - #endif - } - else - { - numSolidBytes = (UInt64)dicSize << 7; - if (numSolidBytes > kSolidBytes_Max) - numSolidBytes = kSolidBytes_Max; - } - - if (_numSolidBytesDefined) - continue; - - if (numSolidBytes < kSolidBytes_Min) - numSolidBytes = kSolidBytes_Min; - _numSolidBytes = numSolidBytes; - _numSolidBytesDefined = true; - } - - if (!_numSolidBytesDefined) - { - if (needSolid) - _numSolidBytes = kSolidBytes_Max; - else - _numSolidBytes = 0; - } - _numSolidBytesDefined = true; - - - return S_OK; -} - - - -static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined) -{ - // ft = 0; - // ftDefined = false; - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(index, propID, &prop)) - if (prop.vt == VT_FILETIME) - { - ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32); - ftDefined = true; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - else - { - ft = 0; - ftDefined = false; - } - return S_OK; -} - -/* - -#ifdef _WIN32 -static const wchar_t kDirDelimiter1 = L'\\'; -#endif -static const wchar_t kDirDelimiter2 = L'/'; - -static inline bool IsCharDirLimiter(wchar_t c) -{ - return ( - #ifdef _WIN32 - c == kDirDelimiter1 || - #endif - c == kDirDelimiter2); -} - -static int FillSortIndex(CObjectVector &treeFolders, int cur, int curSortIndex) -{ - CTreeFolder &tf = treeFolders[cur]; - tf.SortIndex = curSortIndex++; - for (int i = 0; i < tf.SubFolders.Size(); i++) - curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); - tf.SortIndexEnd = curSortIndex; - return curSortIndex; -} - -static int FindSubFolder(const CObjectVector &treeFolders, int cur, const UString &name, int &insertPos) -{ - const CIntVector &subFolders = treeFolders[cur].SubFolders; - int left = 0, right = subFolders.Size(); - insertPos = -1; - for (;;) - { - if (left == right) - { - insertPos = left; - return -1; - } - int mid = (left + right) / 2; - int midFolder = subFolders[mid]; - int compare = CompareFileNames(name, treeFolders[midFolder].Name); - if (compare == 0) - return midFolder; - if (compare < 0) - right = mid; - else - left = mid + 1; - } -} - -static int AddFolder(CObjectVector &treeFolders, int cur, const UString &name) -{ - int insertPos; - int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); - if (folderIndex < 0) - { - folderIndex = treeFolders.Size(); - CTreeFolder &newFolder = treeFolders.AddNew(); - newFolder.Parent = cur; - newFolder.Name = name; - treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); - } - // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; - return folderIndex; -} -*/ - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback)) -{ - COM_TRY_BEGIN - - const CDbEx *db = NULL; - #ifdef Z7_7Z_VOL - if (_volumes.Size() > 1) - return E_FAIL; - const CVolume *volume = 0; - if (_volumes.Size() == 1) - { - volume = &_volumes.Front(); - db = &volume->Database; - } - #else - if (_inStream) - db = &_db; - #endif - - if (db && !db->CanUpdate()) - return E_NOTIMPL; - - /* - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveGetRawProps, - getRawProps, updateCallback) - - CUniqBlocks secureBlocks; - secureBlocks.AddUniq(NULL, 0); - - CObjectVector treeFolders; - { - CTreeFolder folder; - folder.Parent = -1; - treeFolders.Add(folder); - } - */ - - CObjectVector updateItems; - - bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val); - bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val); - bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true); - bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true); - - if (db && !db->Files.IsEmpty()) - { - if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); - if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); - if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); - if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty(); - } - - // UString s; - UString name; - - for (UInt32 i = 0; i < numItems; i++) - { - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)) - CUpdateItem ui; - ui.NewProps = IntToBool(newProps); - ui.NewData = IntToBool(newData); - ui.IndexInArchive = (int)indexInArchive; - ui.IndexInClient = i; - ui.IsAnti = false; - ui.Size = 0; - - name.Empty(); - // bool isAltStream = false; - if (ui.IndexInArchive != -1) - { - if (!db || (unsigned)ui.IndexInArchive >= db->Files.Size()) - return E_INVALIDARG; - const CFileItem &fi = db->Files[(unsigned)ui.IndexInArchive]; - if (!ui.NewProps) - { - _db.GetPath((unsigned)ui.IndexInArchive, name); - } - ui.IsDir = fi.IsDir; - ui.Size = fi.Size; - // isAltStream = fi.IsAltStream; - ui.IsAnti = db->IsItemAnti((unsigned)ui.IndexInArchive); - - if (!ui.NewProps) - { - ui.CTimeDefined = db->CTime.GetItem((unsigned)ui.IndexInArchive, ui.CTime); - ui.ATimeDefined = db->ATime.GetItem((unsigned)ui.IndexInArchive, ui.ATime); - ui.MTimeDefined = db->MTime.GetItem((unsigned)ui.IndexInArchive, ui.MTime); - } - } - - if (ui.NewProps) - { - bool folderStatusIsDefined; - if (need_Attrib) - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)) - if (prop.vt == VT_EMPTY) - ui.AttribDefined = false; - else if (prop.vt != VT_UI4) - return E_INVALIDARG; - else - { - ui.Attrib = prop.ulVal; - ui.AttribDefined = true; - } - } - - // we need MTime to sort files. - if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)) - if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)) - if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)) - - /* - if (getRawProps) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - - getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); - if (dataSize != 0 && propType != NPropDataType::kRaw) - return E_FAIL; - ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); - } - */ - - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidPath, &prop)) - if (prop.vt == VT_EMPTY) - { - } - else if (prop.vt != VT_BSTR) - return E_INVALIDARG; - else - { - name = prop.bstrVal; - NItemName::ReplaceSlashes_OsToUnix(name); - } - } - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)) - if (prop.vt == VT_EMPTY) - folderStatusIsDefined = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - { - ui.IsDir = (prop.boolVal != VARIANT_FALSE); - folderStatusIsDefined = true; - } - } - - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)) - if (prop.vt == VT_EMPTY) - ui.IsAnti = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - ui.IsAnti = (prop.boolVal != VARIANT_FALSE); - } - - /* - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); - if (prop.vt == VT_EMPTY) - isAltStream = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - isAltStream = (prop.boolVal != VARIANT_FALSE); - } - */ - - if (ui.IsAnti) - { - ui.AttribDefined = false; - - ui.CTimeDefined = false; - ui.ATimeDefined = false; - ui.MTimeDefined = false; - - ui.Size = 0; - } - - if (!folderStatusIsDefined && ui.AttribDefined) - ui.SetDirStatusFromAttrib(); - } - else - { - /* - if (_db.SecureIDs.IsEmpty()) - ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); - else - { - int id = _db.SecureIDs[ui.IndexInArchive]; - size_t offs = _db.SecureOffsets[id]; - size_t size = _db.SecureOffsets[id + 1] - offs; - ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); - } - */ - } - - /* - { - int folderIndex = 0; - if (_useParents) - { - int j; - s.Empty(); - for (j = 0; j < name.Len(); j++) - { - wchar_t c = name[j]; - if (IsCharDirLimiter(c)) - { - folderIndex = AddFolder(treeFolders, folderIndex, s); - s.Empty(); - continue; - } - s += c; - } - if (isAltStream) - { - int colonPos = s.Find(':'); - if (colonPos < 0) - { - // isAltStream = false; - return E_INVALIDARG; - } - UString mainName = s.Left(colonPos); - int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); - if (treeFolders[newFolderIndex].UpdateItemIndex < 0) - { - for (int j = updateItems.Size() - 1; j >= 0; j--) - { - CUpdateItem &ui2 = updateItems[j]; - if (ui2.ParentFolderIndex == folderIndex - && ui2.Name == mainName) - { - ui2.TreeFolderIndex = newFolderIndex; - treeFolders[newFolderIndex].UpdateItemIndex = j; - } - } - } - folderIndex = newFolderIndex; - s.Delete(0, colonPos + 1); - } - ui.Name = s; - } - else - ui.Name = name; - ui.IsAltStream = isAltStream; - ui.ParentFolderIndex = folderIndex; - ui.TreeFolderIndex = -1; - if (ui.IsDir && !s.IsEmpty()) - { - ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); - treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); - } - } - */ - ui.Name = name; - - if (ui.NewData) - { - ui.Size = 0; - if (!ui.IsDir) - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(i, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - ui.Size = (UInt64)prop.uhVal.QuadPart; - if (ui.Size != 0 && ui.IsAnti) - return E_INVALIDARG; - } - } - - updateItems.Add(ui); - } - - /* - FillSortIndex(treeFolders, 0, 0); - for (i = 0; i < (UInt32)updateItems.Size(); i++) - { - CUpdateItem &ui = updateItems[i]; - ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; - ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; - } - */ - - CCompressionMethodMode methodMode, headerMethod; - - methodMode.MemoryUsageLimit = _memUsage_Compress; - methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet; - - #ifndef Z7_ST - { - UInt32 numThreads = _numThreads; - const UInt32 kNumThreads_Max = 1024; - if (numThreads > kNumThreads_Max) - numThreads = kNumThreads_Max; - methodMode.NumThreads = numThreads; - methodMode.NumThreads_WasForced = _numThreads_WasForced; - methodMode.MultiThreadMixer = _useMultiThreadMixer; - // headerMethod.NumThreads = 1; - headerMethod.MultiThreadMixer = _useMultiThreadMixer; - } - #endif - - const HRESULT res = SetMainMethod(methodMode); - RINOK(res) - - RINOK(SetHeaderMethod(headerMethod)) - - Z7_DECL_CMyComPtr_QI_FROM( - ICryptoGetTextPassword2, - getPassword2, updateCallback) - - methodMode.PasswordIsDefined = false; - methodMode.Password.Wipe_and_Empty(); - if (getPassword2) - { - CMyComBSTR_Wipe password; - Int32 passwordIsDefined; - RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)) - methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); - if (methodMode.PasswordIsDefined && password) - methodMode.Password = password; - } - - bool compressMainHeader = _compressHeaders; // check it - - bool encryptHeaders = false; - - #ifndef Z7_NO_CRYPTO - if (!methodMode.PasswordIsDefined && _passwordIsDefined) - { - // if header is compressed, we use that password for updated archive - methodMode.PasswordIsDefined = true; - methodMode.Password = _password; - } - #endif - - if (methodMode.PasswordIsDefined) - { - if (_encryptHeadersSpecified) - encryptHeaders = _encryptHeaders; - #ifndef Z7_NO_CRYPTO - else - encryptHeaders = _passwordIsDefined; - #endif - compressMainHeader = true; - if (encryptHeaders) - { - headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; - headerMethod.Password = methodMode.Password; - } - } - - if (numItems < 2) - compressMainHeader = false; - - const int level = GetLevel(); - - CUpdateOptions options; - options.Need_CTime = need_CTime; - options.Need_ATime = need_ATime; - options.Need_MTime = need_MTime; - options.Need_Attrib = need_Attrib; - // options.Need_Crc = (_crcSize != 0); // for debug - - options.Method = &methodMode; - options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; - options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); - options.MaxFilter = (level >= 8); - options.AnalysisLevel = GetAnalysisLevel(); - - options.SetFilterSupporting_ver_enabled_disabled( - _decoderCompatibilityVersion, - _enabledFilters, - _disabledFilters); - - options.HeaderOptions.CompressMainHeader = compressMainHeader; - /* - options.HeaderOptions.WriteCTime = Write_CTime; - options.HeaderOptions.WriteATime = Write_ATime; - options.HeaderOptions.WriteMTime = Write_MTime; - options.HeaderOptions.WriteAttrib = Write_Attrib; - */ - - options.NumSolidFiles = _numSolidFiles; - options.NumSolidBytes = _numSolidBytes; - options.SolidExtension = _solidExtension; - options.UseTypeSorting = _useTypeSorting; - - options.RemoveSfxBlock = _removeSfxBlock; - // options.VolumeMode = _volumeMode; - - options.MultiThreadMixer = _useMultiThreadMixer; - - /* - if (secureBlocks.Sorted.Size() > 1) - { - secureBlocks.GetReverseMap(); - for (int i = 0; i < updateItems.Size(); i++) - { - int &secureIndex = updateItems[i].SecureIndex; - secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; - } - } - */ - - return Update( - EXTERNAL_CODECS_VARS - #ifdef Z7_7Z_VOL - volume ? volume->Stream: 0, - volume ? db : 0, - #else - _inStream, - db, - #endif - updateItems, - // treeFolders, - // secureBlocks, - outStream, updateCallback, options); - - COM_TRY_END -} - -static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream) -{ - stream = 0; - { - const unsigned index = ParseStringToUInt32(srcString, coder); - if (index == 0) - return E_INVALIDARG; - srcString.DeleteFrontal(index); - } - if (srcString[0] == 's') - { - srcString.Delete(0); - const unsigned index = ParseStringToUInt32(srcString, stream); - if (index == 0) - return E_INVALIDARG; - srcString.DeleteFrontal(index); - } - return S_OK; -} - -void COutHandler::InitProps7z() -{ - _removeSfxBlock = false; - _compressHeaders = true; - _encryptHeadersSpecified = false; - _encryptHeaders = false; - // _useParents = false; - - TimeOptions.Init(); - Write_Attrib.Init(); - - _useMultiThreadMixer = true; - - // _volumeMode = false; - - InitSolid(); - _useTypeSorting = false; - - _decoderCompatibilityVersion = k_decoderCompatibilityVersion; - _enabledFilters.Clear(); - _disabledFilters.Clear(); -} - -void COutHandler::InitProps() -{ - CMultiMethodProps::Init(); - InitProps7z(); -} - - - -HRESULT COutHandler::SetSolidFromString(const UString &s) -{ - UString s2 = s; - s2.MakeLower_Ascii(); - for (unsigned i = 0; i < s2.Len();) - { - const wchar_t *start = ((const wchar_t *)s2) + i; - const wchar_t *end; - UInt64 v = ConvertStringToUInt64(start, &end); - if (start == end) - { - if (s2[i++] != 'e') - return E_INVALIDARG; - _solidExtension = true; - continue; - } - i += (unsigned)(end - start); - if (i == s2.Len()) - return E_INVALIDARG; - const wchar_t c = s2[i++]; - if (c == 'f') - { - if (v < 1) - v = 1; - _numSolidFiles = v; - } - else - { - unsigned numBits; - switch (c) - { - case 'b': numBits = 0; break; - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - case 't': numBits = 40; break; - default: return E_INVALIDARG; - } - _numSolidBytes = (v << numBits); - _numSolidBytesDefined = true; - /* - if (_numSolidBytes == 0) - _numSolidFiles = 1; - */ - } - } - return S_OK; -} - -HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) -{ - bool isSolid; - switch (value.vt) - { - case VT_EMPTY: isSolid = true; break; - case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; - case VT_BSTR: - if (StringToBool(value.bstrVal, isSolid)) - break; - return SetSolidFromString(value.bstrVal); - default: return E_INVALIDARG; - } - if (isSolid) - InitSolid(); - else - _numSolidFiles = 1; - return S_OK; -} - -static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) -{ - RINOK(PROPVARIANT_to_bool(prop, dest.Val)) - dest.Def = true; - return S_OK; -} - -struct C_Id_Name_pair -{ - UInt32 Id; - const char *Name; -}; - -static const C_Id_Name_pair g_filter_pairs[] = -{ - { k_Delta, "Delta" }, - { k_ARM64, "ARM64" }, - { k_RISCV, "RISCV" }, - { k_SWAP2, "SWAP2" }, - { k_SWAP4, "SWAP4" }, - { k_BCJ, "BCJ" }, - { k_BCJ2 , "BCJ2" }, - { k_PPC, "PPC" }, - { k_IA64, "IA64" }, - { k_ARM, "ARM" }, - { k_ARMT, "ARMT" }, - { k_SPARC, "SPARC" } -}; - - -HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) -{ - UString name = nameSpec; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - if (name[0] == L's') - { - name.Delete(0); - if (name.IsEmpty()) - return SetSolidFromPROPVARIANT(value); - if (value.vt != VT_EMPTY) - return E_INVALIDARG; - return SetSolidFromString(name); - } - - UInt32 number; - const unsigned index = ParseStringToUInt32(name, number); - // UString realName = name.Ptr(index); - if (index == 0) - { - if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); - if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); - // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); - - if (name.IsEqualTo("hcf")) - { - bool compressHeadersFull = true; - RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)) - return compressHeadersFull ? S_OK: E_INVALIDARG; - } - - if (name.IsEqualTo("he")) - { - RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)) - _encryptHeadersSpecified = true; - return S_OK; - } - - { - bool processed; - RINOK(TimeOptions.Parse(name, value, processed)) - if (processed) - { - if ( TimeOptions.Prec != (UInt32)(Int32)-1 - && TimeOptions.Prec != k_PropVar_TimePrec_0 - && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec - && TimeOptions.Prec != k_PropVar_TimePrec_100ns) - return E_INVALIDARG; - return S_OK; - } - } - - if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); - - if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); - - if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting); - - if (name.IsPrefixedBy_Ascii_NoCase("yv")) - { - name.Delete(0, 2); - UInt32 v = 1 << 16; // if no number is noit specified, we use big value - RINOK(ParsePropToUInt32(name, value, v)) - _decoderCompatibilityVersion = v; - // if (v == 0) _decoderCompatibilityVersion = k_decoderCompatibilityVersion; - return S_OK; - } - - if (name.IsPrefixedBy_Ascii_NoCase("yf")) - { - name.Delete(0, 2); - CUIntVector *vec; - if (name.IsEqualTo_Ascii_NoCase("a")) vec = &_enabledFilters; - else if (name.IsEqualTo_Ascii_NoCase("d")) vec = &_disabledFilters; - else return E_INVALIDARG; - - if (value.vt != VT_BSTR) - return E_INVALIDARG; - for (unsigned k = 0;; k++) - { - if (k == Z7_ARRAY_SIZE(g_filter_pairs)) - { - // maybe we can ignore unsupported filter names here? - return E_INVALIDARG; - } - const C_Id_Name_pair &pair = g_filter_pairs[k]; - if (StringsAreEqualNoCase_Ascii(value.bstrVal, pair.Name)) - { - vec->AddToUniqueSorted(pair.Id); - break; - } - } - return S_OK; - } - - // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); - } - return CMultiMethodProps::SetProperty(name, value); -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - COM_TRY_BEGIN - _bonds.Clear(); - InitProps(); - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - const PROPVARIANT &value = values[i]; - - if (name.Find(L':') >= 0) // 'b' was used as NCoderPropID::kBlockSize2 before v23 - if (name[0] == 'b') - { - if (value.vt != VT_EMPTY) - return E_INVALIDARG; - name.Delete(0); - - CBond2 bond; - RINOK(ParseBond(name, bond.OutCoder, bond.OutStream)) - if (name[0] != ':') - return E_INVALIDARG; - name.Delete(0); - UInt32 inStream = 0; - RINOK(ParseBond(name, bond.InCoder, inStream)) - if (inStream != 0) - return E_INVALIDARG; - if (!name.IsEmpty()) - return E_INVALIDARG; - _bonds.Add(bond); - continue; - } - - RINOK(SetProperty(name, value)) - } - - unsigned numEmptyMethods = GetNumEmptyMethods(); - if (numEmptyMethods > 0) - { - unsigned k; - for (k = 0; k < _bonds.Size(); k++) - { - const CBond2 &bond = _bonds[k]; - if (bond.InCoder < (UInt32)numEmptyMethods || - bond.OutCoder < (UInt32)numEmptyMethods) - return E_INVALIDARG; - } - for (k = 0; k < _bonds.Size(); k++) - { - CBond2 &bond = _bonds[k]; - bond.InCoder -= (UInt32)numEmptyMethods; - bond.OutCoder -= (UInt32)numEmptyMethods; - } - _methods.DeleteFrontal(numEmptyMethods); - } - - FOR_VECTOR (k, _bonds) - { - const CBond2 &bond = _bonds[k]; - if (bond.InCoder >= (UInt32)_methods.Size() || - bond.OutCoder >= (UInt32)_methods.Size()) - return E_INVALIDARG; - } - - return S_OK; - COM_TRY_END -} - -}} - -#endif +// 7zHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/Wildcard.h" + +#include "../Common/ItemNameUtils.h" +#include "../Common/ParseProperties.h" + +#include "7zHandler.h" +#include "7zOut.h" +#include "7zUpdate.h" + +#ifndef Z7_EXTRACT_ONLY + +using namespace NWindows; + +namespace NArchive { +namespace N7z { + +static const UInt32 k_decoderCompatibilityVersion = 2301; +// 7-Zip version 2301 supports ARM64 filter + +#define k_LZMA_Name "LZMA" +#define kDefaultMethodName "LZMA2" +#define k_Copy_Name "Copy" + +#define k_MatchFinder_ForHeaders "BT2" + +static const UInt32 k_NumFastBytes_ForHeaders = 273; +static const UInt32 k_Level_ForHeaders = 5; +static const UInt32 k_Dictionary_ForHeaders = + #ifdef UNDER_CE + 1 << 18; + #else + 1 << 20; + #endif + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) +{ + *type = NFileTimeType::kWindows; + return S_OK; +} + +HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) +{ + bool isFilter; + dest.CodecIndex = FindMethod_Index( + EXTERNAL_CODECS_VARS + m.MethodName, true, + dest.Id, dest.NumStreams, isFilter); + if (dest.CodecIndex < 0) + return E_INVALIDARG; + (CProps &)dest = (CProps &)m; + return S_OK; +} + +HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) +{ + if (!_compressHeaders) + return S_OK; + COneMethodInfo m; + m.MethodName = k_LZMA_Name; + m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); + m.AddProp_Level(k_Level_ForHeaders); + m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); + m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); + m.AddProp_NumThreads(1); + + CMethodFull &methodFull = headerMethod.Methods.AddNew(); + return PropsMethod_To_FullMethod(methodFull, m); +} + + +HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode) +{ + methodMode.Bonds = _bonds; + + // we create local copy of _methods. So we can modify it. + CObjectVector methods = _methods; + + { + FOR_VECTOR (i, methods) + { + AString &methodName = methods[i].MethodName; + if (methodName.IsEmpty()) + methodName = kDefaultMethodName; + } + if (methods.IsEmpty()) + { + COneMethodInfo &m = methods.AddNew(); + m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); + methodMode.DefaultMethod_was_Inserted = true; + } + } + + if (!_filterMethod.MethodName.IsEmpty()) + { + // if (methodMode.Bonds.IsEmpty()) + { + FOR_VECTOR (k, methodMode.Bonds) + { + CBond2 &bond = methodMode.Bonds[k]; + bond.InCoder++; + bond.OutCoder++; + } + methods.Insert(0, _filterMethod); + methodMode.Filter_was_Inserted = true; + } + } + + const UInt64 kSolidBytes_Min = (1 << 24); + const UInt64 kSolidBytes_Max = ((UInt64)1 << 32); + + bool needSolid = false; + + FOR_VECTOR (i, methods) + { + COneMethodInfo &oneMethodInfo = methods[i]; + + SetGlobalLevelTo(oneMethodInfo); + + #ifndef Z7_ST + const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); + if (!numThreads_WasSpecifiedInMethod) + { + // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already + CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads); + } + #endif + + CMethodFull &methodFull = methodMode.Methods.AddNew(); + RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)) + + #ifndef Z7_ST + methodFull.Set_NumThreads = true; + methodFull.NumThreads = methodMode.NumThreads; + #endif + + if (methodFull.Id != k_Copy) + needSolid = true; + + UInt64 dicSize; + switch (methodFull.Id) + { + case k_LZMA: + case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break; + case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break; + case k_Deflate: dicSize = (UInt32)1 << 15; break; + case k_Deflate64: dicSize = (UInt32)1 << 16; break; + case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; + // case k_ZSTD: dicSize = 1 << 23; break; + default: continue; + } + + UInt64 numSolidBytes; + + /* + if (methodFull.Id == k_ZSTD) + { + // continue; + NCompress::NZstd::CEncoderProps encoderProps; + RINOK(oneMethodInfo.Set_PropsTo_zstd(encoderProps)); + CZstdEncProps &zstdProps = encoderProps.EncProps; + ZstdEncProps_NormalizeFull(&zstdProps); + UInt64 cs = (UInt64)(zstdProps.jobSize); + UInt32 winSize = (UInt32)(1 << zstdProps.windowLog); + if (cs < winSize) + cs = winSize; + numSolidBytes = cs << 6; + const UInt64 kSolidBytes_Zstd_Max = ((UInt64)1 << 34); + if (numSolidBytes > kSolidBytes_Zstd_Max) + numSolidBytes = kSolidBytes_Zstd_Max; + + methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder + + #ifndef Z7_ST + if (!numThreads_WasSpecifiedInMethod + && !methodMode.NumThreads_WasForced + && methodMode.MemoryUsageLimit_WasSet + ) + { + const UInt32 numThreads_Original = methodMode.NumThreads; + const UInt32 numThreads_New = ZstdEncProps_GetNumThreads_for_MemUsageLimit( + &zstdProps, + methodMode.MemoryUsageLimit, + numThreads_Original); + if (numThreads_Original != numThreads_New) + { + CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New); + } + } + #endif + } + else + */ + if (methodFull.Id == k_LZMA2) + { + // he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code + /* lzma2 code use dictionary up to fake 4 GiB to calculate ChunkSize. + So we do same */ + UInt64 cs = (UInt64)dicSize << 2; + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + if (cs < kMinSize) cs = kMinSize; + if (cs > kMaxSize) cs = kMaxSize; + if (cs < dicSize) cs = dicSize; + cs += (kMinSize - 1); + cs &= ~(UInt64)(kMinSize - 1); + // we want to use at least 64 chunks (threads) per one solid block. + + // here we don't use chunkSize property + numSolidBytes = cs << 6; + + // here we get real chunkSize + cs = oneMethodInfo.Get_Xz_BlockSize(); + if (dicSize > cs) + dicSize = cs; + + const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34); + if (numSolidBytes > kSolidBytes_Lzma2_Max) + numSolidBytes = kSolidBytes_Lzma2_Max; + + methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder + + #ifndef Z7_ST + if (!numThreads_WasSpecifiedInMethod + && !methodMode.NumThreads_WasForced + && methodMode.MemoryUsageLimit_WasSet + ) + { + const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); + const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads; + + if (numBlockThreads_Original > 1) + { + /* + const UInt32 kNumThreads_Max = 1024; + if (numBlockThreads > kNumMaxThreads) + numBlockThreads = kNumMaxThreads; + */ + + UInt32 numBlockThreads = numBlockThreads_Original; + const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid + + for (; numBlockThreads > 1; numBlockThreads--) + { + UInt64 size = numBlockThreads * (lzmaMemUsage + cs); + UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; + if (cs < ((UInt32)1 << 26)) numPackChunks++; + if (cs < ((UInt32)1 << 24)) numPackChunks++; + if (cs < ((UInt32)1 << 22)) numPackChunks++; + size += numPackChunks * cs; + // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20)); + if (size <= methodMode.MemoryUsageLimit) + break; + } + + if (numBlockThreads == 0) + numBlockThreads = 1; + if (numBlockThreads != numBlockThreads_Original) + { + const UInt32 numThreads_New = numBlockThreads * lzmaThreads; + CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New); + } + } + } + #endif + } + else + { + numSolidBytes = (UInt64)dicSize << 7; + if (numSolidBytes > kSolidBytes_Max) + numSolidBytes = kSolidBytes_Max; + } + + if (_numSolidBytesDefined) + continue; + + if (numSolidBytes < kSolidBytes_Min) + numSolidBytes = kSolidBytes_Min; + _numSolidBytes = numSolidBytes; + _numSolidBytesDefined = true; + } + + if (!_numSolidBytesDefined) + { + if (needSolid) + _numSolidBytes = kSolidBytes_Max; + else + _numSolidBytes = 0; + } + _numSolidBytesDefined = true; + + + return S_OK; +} + + + +static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined) +{ + // ft = 0; + // ftDefined = false; + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(index, propID, &prop)) + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32); + ftDefined = true; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + else + { + ft = 0; + ftDefined = false; + } + return S_OK; +} + +/* + +#ifdef _WIN32 +static const wchar_t kDirDelimiter1 = L'\\'; +#endif +static const wchar_t kDirDelimiter2 = L'/'; + +static inline bool IsCharDirLimiter(wchar_t c) +{ + return ( + #ifdef _WIN32 + c == kDirDelimiter1 || + #endif + c == kDirDelimiter2); +} + +static int FillSortIndex(CObjectVector &treeFolders, int cur, int curSortIndex) +{ + CTreeFolder &tf = treeFolders[cur]; + tf.SortIndex = curSortIndex++; + for (int i = 0; i < tf.SubFolders.Size(); i++) + curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); + tf.SortIndexEnd = curSortIndex; + return curSortIndex; +} + +static int FindSubFolder(const CObjectVector &treeFolders, int cur, const UString &name, int &insertPos) +{ + const CIntVector &subFolders = treeFolders[cur].SubFolders; + int left = 0, right = subFolders.Size(); + insertPos = -1; + for (;;) + { + if (left == right) + { + insertPos = left; + return -1; + } + int mid = (left + right) / 2; + int midFolder = subFolders[mid]; + int compare = CompareFileNames(name, treeFolders[midFolder].Name); + if (compare == 0) + return midFolder; + if (compare < 0) + right = mid; + else + left = mid + 1; + } +} + +static int AddFolder(CObjectVector &treeFolders, int cur, const UString &name) +{ + int insertPos; + int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); + if (folderIndex < 0) + { + folderIndex = treeFolders.Size(); + CTreeFolder &newFolder = treeFolders.AddNew(); + newFolder.Parent = cur; + newFolder.Name = name; + treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); + } + // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; + return folderIndex; +} +*/ + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback)) +{ + COM_TRY_BEGIN + + const CDbEx *db = NULL; + #ifdef Z7_7Z_VOL + if (_volumes.Size() > 1) + return E_FAIL; + const CVolume *volume = 0; + if (_volumes.Size() == 1) + { + volume = &_volumes.Front(); + db = &volume->Database; + } + #else + if (_inStream) + db = &_db; + #endif + + if (db && !db->CanUpdate()) + return E_NOTIMPL; + + /* + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveGetRawProps, + getRawProps, updateCallback) + + CUniqBlocks secureBlocks; + secureBlocks.AddUniq(NULL, 0); + + CObjectVector treeFolders; + { + CTreeFolder folder; + folder.Parent = -1; + treeFolders.Add(folder); + } + */ + + CObjectVector updateItems; + + bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val); + bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val); + bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true); + bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true); + + if (db && !db->Files.IsEmpty()) + { + if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); + if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); + if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); + if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty(); + } + + // UString s; + UString name; + + for (UInt32 i = 0; i < numItems; i++) + { + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)) + CUpdateItem ui; + ui.NewProps = IntToBool(newProps); + ui.NewData = IntToBool(newData); + ui.IndexInArchive = (int)indexInArchive; + ui.IndexInClient = i; + ui.IsAnti = false; + ui.Size = 0; + + name.Empty(); + // bool isAltStream = false; + if (ui.IndexInArchive != -1) + { + if (!db || (unsigned)ui.IndexInArchive >= db->Files.Size()) + return E_INVALIDARG; + const CFileItem &fi = db->Files[(unsigned)ui.IndexInArchive]; + if (!ui.NewProps) + { + _db.GetPath((unsigned)ui.IndexInArchive, name); + } + ui.IsDir = fi.IsDir; + ui.Size = fi.Size; + // isAltStream = fi.IsAltStream; + ui.IsAnti = db->IsItemAnti((unsigned)ui.IndexInArchive); + + if (!ui.NewProps) + { + ui.CTimeDefined = db->CTime.GetItem((unsigned)ui.IndexInArchive, ui.CTime); + ui.ATimeDefined = db->ATime.GetItem((unsigned)ui.IndexInArchive, ui.ATime); + ui.MTimeDefined = db->MTime.GetItem((unsigned)ui.IndexInArchive, ui.MTime); + } + } + + if (ui.NewProps) + { + bool folderStatusIsDefined; + if (need_Attrib) + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)) + if (prop.vt == VT_EMPTY) + ui.AttribDefined = false; + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + { + ui.Attrib = prop.ulVal; + ui.AttribDefined = true; + } + } + + // we need MTime to sort files. + if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)) + if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)) + if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)) + + /* + if (getRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + + getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); + if (dataSize != 0 && propType != NPropDataType::kRaw) + return E_FAIL; + ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); + } + */ + + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidPath, &prop)) + if (prop.vt == VT_EMPTY) + { + } + else if (prop.vt != VT_BSTR) + return E_INVALIDARG; + else + { + name = prop.bstrVal; + NItemName::ReplaceSlashes_OsToUnix(name); + } + } + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)) + if (prop.vt == VT_EMPTY) + folderStatusIsDefined = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + { + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + folderStatusIsDefined = true; + } + } + + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)) + if (prop.vt == VT_EMPTY) + ui.IsAnti = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsAnti = (prop.boolVal != VARIANT_FALSE); + } + + /* + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); + if (prop.vt == VT_EMPTY) + isAltStream = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + isAltStream = (prop.boolVal != VARIANT_FALSE); + } + */ + + if (ui.IsAnti) + { + ui.AttribDefined = false; + + ui.CTimeDefined = false; + ui.ATimeDefined = false; + ui.MTimeDefined = false; + + ui.Size = 0; + } + + if (!folderStatusIsDefined && ui.AttribDefined) + ui.SetDirStatusFromAttrib(); + } + else + { + /* + if (_db.SecureIDs.IsEmpty()) + ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); + else + { + int id = _db.SecureIDs[ui.IndexInArchive]; + size_t offs = _db.SecureOffsets[id]; + size_t size = _db.SecureOffsets[id + 1] - offs; + ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); + } + */ + } + + /* + { + int folderIndex = 0; + if (_useParents) + { + int j; + s.Empty(); + for (j = 0; j < name.Len(); j++) + { + wchar_t c = name[j]; + if (IsCharDirLimiter(c)) + { + folderIndex = AddFolder(treeFolders, folderIndex, s); + s.Empty(); + continue; + } + s += c; + } + if (isAltStream) + { + int colonPos = s.Find(':'); + if (colonPos < 0) + { + // isAltStream = false; + return E_INVALIDARG; + } + UString mainName = s.Left(colonPos); + int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); + if (treeFolders[newFolderIndex].UpdateItemIndex < 0) + { + for (int j = updateItems.Size() - 1; j >= 0; j--) + { + CUpdateItem &ui2 = updateItems[j]; + if (ui2.ParentFolderIndex == folderIndex + && ui2.Name == mainName) + { + ui2.TreeFolderIndex = newFolderIndex; + treeFolders[newFolderIndex].UpdateItemIndex = j; + } + } + } + folderIndex = newFolderIndex; + s.Delete(0, colonPos + 1); + } + ui.Name = s; + } + else + ui.Name = name; + ui.IsAltStream = isAltStream; + ui.ParentFolderIndex = folderIndex; + ui.TreeFolderIndex = -1; + if (ui.IsDir && !s.IsEmpty()) + { + ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); + treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); + } + } + */ + ui.Name = name; + + if (ui.NewData) + { + ui.Size = 0; + if (!ui.IsDir) + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(i, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + ui.Size = (UInt64)prop.uhVal.QuadPart; + if (ui.Size != 0 && ui.IsAnti) + return E_INVALIDARG; + } + } + + updateItems.Add(ui); + } + + /* + FillSortIndex(treeFolders, 0, 0); + for (i = 0; i < (UInt32)updateItems.Size(); i++) + { + CUpdateItem &ui = updateItems[i]; + ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; + ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; + } + */ + + CCompressionMethodMode methodMode, headerMethod; + + methodMode.MemoryUsageLimit = _memUsage_Compress; + methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet; + + #ifndef Z7_ST + { + UInt32 numThreads = _numThreads; + const UInt32 kNumThreads_Max = 1024; + if (numThreads > kNumThreads_Max) + numThreads = kNumThreads_Max; + methodMode.NumThreads = numThreads; + methodMode.NumThreads_WasForced = _numThreads_WasForced; + methodMode.MultiThreadMixer = _useMultiThreadMixer; + // headerMethod.NumThreads = 1; + headerMethod.MultiThreadMixer = _useMultiThreadMixer; + } + #endif + + const HRESULT res = SetMainMethod(methodMode); + RINOK(res) + + RINOK(SetHeaderMethod(headerMethod)) + + Z7_DECL_CMyComPtr_QI_FROM( + ICryptoGetTextPassword2, + getPassword2, updateCallback) + + methodMode.PasswordIsDefined = false; + methodMode.Password.Wipe_and_Empty(); + if (getPassword2) + { + CMyComBSTR_Wipe password; + Int32 passwordIsDefined; + RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)) + methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); + if (methodMode.PasswordIsDefined && password) + methodMode.Password = password; + } + + bool compressMainHeader = _compressHeaders; // check it + + bool encryptHeaders = false; + + #ifndef Z7_NO_CRYPTO + if (!methodMode.PasswordIsDefined && _passwordIsDefined) + { + // if header is compressed, we use that password for updated archive + methodMode.PasswordIsDefined = true; + methodMode.Password = _password; + } + #endif + + if (methodMode.PasswordIsDefined) + { + if (_encryptHeadersSpecified) + encryptHeaders = _encryptHeaders; + #ifndef Z7_NO_CRYPTO + else + encryptHeaders = _passwordIsDefined; + #endif + compressMainHeader = true; + if (encryptHeaders) + { + headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; + headerMethod.Password = methodMode.Password; + } + } + + if (numItems < 2) + compressMainHeader = false; + + const int level = GetLevel(); + + CUpdateOptions options; + options.Need_CTime = need_CTime; + options.Need_ATime = need_ATime; + options.Need_MTime = need_MTime; + options.Need_Attrib = need_Attrib; + // options.Need_Crc = (_crcSize != 0); // for debug + + options.Method = &methodMode; + options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; + options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); + options.MaxFilter = (level >= 8); + options.AnalysisLevel = GetAnalysisLevel(); + + options.SetFilterSupporting_ver_enabled_disabled( + _decoderCompatibilityVersion, + _enabledFilters, + _disabledFilters); + + options.HeaderOptions.CompressMainHeader = compressMainHeader; + /* + options.HeaderOptions.WriteCTime = Write_CTime; + options.HeaderOptions.WriteATime = Write_ATime; + options.HeaderOptions.WriteMTime = Write_MTime; + options.HeaderOptions.WriteAttrib = Write_Attrib; + */ + + options.NumSolidFiles = _numSolidFiles; + options.NumSolidBytes = _numSolidBytes; + options.SolidExtension = _solidExtension; + options.UseTypeSorting = _useTypeSorting; + + options.RemoveSfxBlock = _removeSfxBlock; + // options.VolumeMode = _volumeMode; + + options.MultiThreadMixer = _useMultiThreadMixer; + + /* + if (secureBlocks.Sorted.Size() > 1) + { + secureBlocks.GetReverseMap(); + for (int i = 0; i < updateItems.Size(); i++) + { + int &secureIndex = updateItems[i].SecureIndex; + secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; + } + } + */ + + return Update( + EXTERNAL_CODECS_VARS + #ifdef Z7_7Z_VOL + volume ? volume->Stream: 0, + volume ? db : 0, + #else + _inStream, + db, + #endif + updateItems, + // treeFolders, + // secureBlocks, + outStream, updateCallback, options); + + COM_TRY_END +} + +static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream) +{ + stream = 0; + { + const unsigned index = ParseStringToUInt32(srcString, coder); + if (index == 0) + return E_INVALIDARG; + srcString.DeleteFrontal(index); + } + if (srcString[0] == 's') + { + srcString.Delete(0); + const unsigned index = ParseStringToUInt32(srcString, stream); + if (index == 0) + return E_INVALIDARG; + srcString.DeleteFrontal(index); + } + return S_OK; +} + +void COutHandler::InitProps7z() +{ + _removeSfxBlock = false; + _compressHeaders = true; + _encryptHeadersSpecified = false; + _encryptHeaders = false; + // _useParents = false; + + TimeOptions.Init(); + Write_Attrib.Init(); + + _useMultiThreadMixer = true; + + // _volumeMode = false; + + InitSolid(); + _useTypeSorting = false; + + _decoderCompatibilityVersion = k_decoderCompatibilityVersion; + _enabledFilters.Clear(); + _disabledFilters.Clear(); +} + +void COutHandler::InitProps() +{ + CMultiMethodProps::Init(); + InitProps7z(); +} + + + +HRESULT COutHandler::SetSolidFromString(const UString &s) +{ + UString s2 = s; + s2.MakeLower_Ascii(); + for (unsigned i = 0; i < s2.Len();) + { + const wchar_t *start = ((const wchar_t *)s2) + i; + const wchar_t *end; + UInt64 v = ConvertStringToUInt64(start, &end); + if (start == end) + { + if (s2[i++] != 'e') + return E_INVALIDARG; + _solidExtension = true; + continue; + } + i += (unsigned)(end - start); + if (i == s2.Len()) + return E_INVALIDARG; + const wchar_t c = s2[i++]; + if (c == 'f') + { + if (v < 1) + v = 1; + _numSolidFiles = v; + } + else + { + unsigned numBits; + switch (c) + { + case 'b': numBits = 0; break; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return E_INVALIDARG; + } + _numSolidBytes = (v << numBits); + _numSolidBytesDefined = true; + /* + if (_numSolidBytes == 0) + _numSolidFiles = 1; + */ + } + } + return S_OK; +} + +HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) +{ + bool isSolid; + switch (value.vt) + { + case VT_EMPTY: isSolid = true; break; + case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; + case VT_BSTR: + if (StringToBool(value.bstrVal, isSolid)) + break; + return SetSolidFromString(value.bstrVal); + default: return E_INVALIDARG; + } + if (isSolid) + InitSolid(); + else + _numSolidFiles = 1; + return S_OK; +} + +static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) +{ + RINOK(PROPVARIANT_to_bool(prop, dest.Val)) + dest.Def = true; + return S_OK; +} + +struct C_Id_Name_pair +{ + UInt32 Id; + const char *Name; +}; + +static const C_Id_Name_pair g_filter_pairs[] = +{ + { k_Delta, "Delta" }, + { k_ARM64, "ARM64" }, + { k_RISCV, "RISCV" }, + { k_SWAP2, "SWAP2" }, + { k_SWAP4, "SWAP4" }, + { k_BCJ, "BCJ" }, + { k_BCJ2 , "BCJ2" }, + { k_PPC, "PPC" }, + { k_IA64, "IA64" }, + { k_ARM, "ARM" }, + { k_ARMT, "ARMT" }, + { k_SPARC, "SPARC" } +}; + + +HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + if (name[0] == L's') + { + name.Delete(0); + if (name.IsEmpty()) + return SetSolidFromPROPVARIANT(value); + if (value.vt != VT_EMPTY) + return E_INVALIDARG; + return SetSolidFromString(name); + } + + UInt32 number; + const unsigned index = ParseStringToUInt32(name, number); + // UString realName = name.Ptr(index); + if (index == 0) + { + if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); + if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); + // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); + + if (name.IsEqualTo("hcf")) + { + bool compressHeadersFull = true; + RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)) + return compressHeadersFull ? S_OK: E_INVALIDARG; + } + + if (name.IsEqualTo("he")) + { + RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)) + _encryptHeadersSpecified = true; + return S_OK; + } + + { + bool processed; + RINOK(TimeOptions.Parse(name, value, processed)) + if (processed) + { + if ( TimeOptions.Prec != (UInt32)(Int32)-1 + && TimeOptions.Prec != k_PropVar_TimePrec_0 + && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec + && TimeOptions.Prec != k_PropVar_TimePrec_100ns) + return E_INVALIDARG; + return S_OK; + } + } + + if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); + + if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); + + if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting); + + if (name.IsPrefixedBy_Ascii_NoCase("yv")) + { + name.Delete(0, 2); + UInt32 v = 1 << 16; // if no number is noit specified, we use big value + RINOK(ParsePropToUInt32(name, value, v)) + _decoderCompatibilityVersion = v; + // if (v == 0) _decoderCompatibilityVersion = k_decoderCompatibilityVersion; + return S_OK; + } + + if (name.IsPrefixedBy_Ascii_NoCase("yf")) + { + name.Delete(0, 2); + CUIntVector *vec; + if (name.IsEqualTo_Ascii_NoCase("a")) vec = &_enabledFilters; + else if (name.IsEqualTo_Ascii_NoCase("d")) vec = &_disabledFilters; + else return E_INVALIDARG; + + if (value.vt != VT_BSTR) + return E_INVALIDARG; + for (unsigned k = 0;; k++) + { + if (k == Z7_ARRAY_SIZE(g_filter_pairs)) + { + // maybe we can ignore unsupported filter names here? + return E_INVALIDARG; + } + const C_Id_Name_pair &pair = g_filter_pairs[k]; + if (StringsAreEqualNoCase_Ascii(value.bstrVal, pair.Name)) + { + vec->AddToUniqueSorted(pair.Id); + break; + } + } + return S_OK; + } + + // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); + } + return CMultiMethodProps::SetProperty(name, value); +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + COM_TRY_BEGIN + _bonds.Clear(); + InitProps(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &value = values[i]; + + if (name.Find(L':') >= 0) // 'b' was used as NCoderPropID::kBlockSize2 before v23 + if (name[0] == 'b') + { + if (value.vt != VT_EMPTY) + return E_INVALIDARG; + name.Delete(0); + + CBond2 bond; + RINOK(ParseBond(name, bond.OutCoder, bond.OutStream)) + if (name[0] != ':') + return E_INVALIDARG; + name.Delete(0); + UInt32 inStream = 0; + RINOK(ParseBond(name, bond.InCoder, inStream)) + if (inStream != 0) + return E_INVALIDARG; + if (!name.IsEmpty()) + return E_INVALIDARG; + _bonds.Add(bond); + continue; + } + + RINOK(SetProperty(name, value)) + } + + unsigned numEmptyMethods = GetNumEmptyMethods(); + if (numEmptyMethods > 0) + { + unsigned k; + for (k = 0; k < _bonds.Size(); k++) + { + const CBond2 &bond = _bonds[k]; + if (bond.InCoder < (UInt32)numEmptyMethods || + bond.OutCoder < (UInt32)numEmptyMethods) + return E_INVALIDARG; + } + for (k = 0; k < _bonds.Size(); k++) + { + CBond2 &bond = _bonds[k]; + bond.InCoder -= (UInt32)numEmptyMethods; + bond.OutCoder -= (UInt32)numEmptyMethods; + } + _methods.DeleteFrontal(numEmptyMethods); + } + + FOR_VECTOR (k, _bonds) + { + const CBond2 &bond = _bonds[k]; + if (bond.InCoder >= (UInt32)_methods.Size() || + bond.OutCoder >= (UInt32)_methods.Size()) + return E_INVALIDARG; + } + + return S_OK; + COM_TRY_END +} + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zHeader.cpp b/CPP/7zip/Archive/7z/7zHeader.cpp index e5c8d5539..d5f94973b 100644 --- a/CPP/7zip/Archive/7z/7zHeader.cpp +++ b/CPP/7zip/Archive/7z/7zHeader.cpp @@ -1,19 +1,19 @@ -// 7zHeader.cpp - -#include "StdAfx.h" - -#include "7zHeader.h" - -namespace NArchive { -namespace N7z { - -Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; -#ifdef Z7_7Z_VOL -Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; -#endif - -// We can change signature. So file doesn't contain correct signature. -// struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } }; -// static SignatureInitializer g_SignatureInitializer; - -}} +// 7zHeader.cpp + +#include "StdAfx.h" + +#include "7zHeader.h" + +namespace NArchive { +namespace N7z { + +Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; +#ifdef Z7_7Z_VOL +Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; +#endif + +// We can change signature. So file doesn't contain correct signature. +// struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } }; +// static SignatureInitializer g_SignatureInitializer; + +}} diff --git a/CPP/7zip/Archive/7z/7zHeader.h b/CPP/7zip/Archive/7z/7zHeader.h index 1300faebc..22e796070 100644 --- a/CPP/7zip/Archive/7z/7zHeader.h +++ b/CPP/7zip/Archive/7z/7zHeader.h @@ -1,156 +1,156 @@ -// 7z/7zHeader.h - -#ifndef ZIP7_INC_7Z_HEADER_H -#define ZIP7_INC_7Z_HEADER_H - -#include "../../../Common/MyTypes.h" - -namespace NArchive { -namespace N7z { - -const unsigned kSignatureSize = 6; -extern Byte kSignature[kSignatureSize]; - -// #define Z7_7Z_VOL -// 7z-MultiVolume is not finished yet. -// It can work already, but I still do not like some -// things of that new multivolume format. -// So please keep it commented. - -#ifdef Z7_7Z_VOL -extern Byte kFinishSignature[kSignatureSize]; -#endif - -struct CArchiveVersion -{ - Byte Major; - Byte Minor; -}; - -const Byte kMajorVersion = 0; - -struct CStartHeader -{ - UInt64 NextHeaderOffset; - UInt64 NextHeaderSize; - UInt32 NextHeaderCRC; -}; - -const UInt32 kStartHeaderSize = 20; - -#ifdef Z7_7Z_VOL -struct CFinishHeader: public CStartHeader -{ - UInt64 ArchiveStartOffset; // data offset from end if that struct - UInt64 AdditionalStartBlockSize; // start signature & start header size -}; - -const UInt32 kFinishHeaderSize = kStartHeaderSize + 16; -#endif - -namespace NID -{ - enum EEnum - { - kEnd, - - kHeader, - - kArchiveProperties, - - kAdditionalStreamsInfo, - kMainStreamsInfo, - kFilesInfo, - - kPackInfo, - kUnpackInfo, - kSubStreamsInfo, - - kSize, - kCRC, - - kFolder, - - kCodersUnpackSize, - kNumUnpackStream, - - kEmptyStream, - kEmptyFile, - kAnti, - - kName, - kCTime, - kATime, - kMTime, - kWinAttrib, - kComment, - - kEncodedHeader, - - kStartPos, - kDummy - - // kNtSecure, - // kParent, - // kIsAux - }; -} - - -const UInt32 k_Copy = 0; -const UInt32 k_Delta = 3; -const UInt32 k_ARM64 = 0xa; -const UInt32 k_RISCV = 0xb; - -const UInt32 k_LZMA2 = 0x21; - -const UInt32 k_SWAP2 = 0x20302; -const UInt32 k_SWAP4 = 0x20304; - -const UInt32 k_LZMA = 0x30101; -const UInt32 k_PPMD = 0x30401; - -const UInt32 k_Deflate = 0x40108; -const UInt32 k_Deflate64 = 0x40109; -const UInt32 k_BZip2 = 0x40202; - -const UInt32 k_BCJ = 0x3030103; -const UInt32 k_BCJ2 = 0x303011B; -const UInt32 k_PPC = 0x3030205; -const UInt32 k_IA64 = 0x3030401; -const UInt32 k_ARM = 0x3030501; -const UInt32 k_ARMT = 0x3030701; -const UInt32 k_SPARC = 0x3030805; - -const UInt32 k_AES = 0x6F10701; - -// const UInt32 k_ZSTD = 0x4015D; // winzip zstd -// 0x4F71101, 7z-zstd - -inline bool IsFilterMethod(UInt64 m) -{ - if (m > (UInt32)0xFFFFFFFF) - return false; - switch ((UInt32)m) - { - case k_Delta: - case k_ARM64: - case k_RISCV: - case k_BCJ: - case k_BCJ2: - case k_PPC: - case k_IA64: - case k_ARM: - case k_ARMT: - case k_SPARC: - case k_SWAP2: - case k_SWAP4: - return true; - default: break; - } - return false; -} - -}} - -#endif +// 7z/7zHeader.h + +#ifndef ZIP7_INC_7Z_HEADER_H +#define ZIP7_INC_7Z_HEADER_H + +#include "../../../Common/MyTypes.h" + +namespace NArchive { +namespace N7z { + +const unsigned kSignatureSize = 6; +extern Byte kSignature[kSignatureSize]; + +// #define Z7_7Z_VOL +// 7z-MultiVolume is not finished yet. +// It can work already, but I still do not like some +// things of that new multivolume format. +// So please keep it commented. + +#ifdef Z7_7Z_VOL +extern Byte kFinishSignature[kSignatureSize]; +#endif + +struct CArchiveVersion +{ + Byte Major; + Byte Minor; +}; + +const Byte kMajorVersion = 0; + +struct CStartHeader +{ + UInt64 NextHeaderOffset; + UInt64 NextHeaderSize; + UInt32 NextHeaderCRC; +}; + +const UInt32 kStartHeaderSize = 20; + +#ifdef Z7_7Z_VOL +struct CFinishHeader: public CStartHeader +{ + UInt64 ArchiveStartOffset; // data offset from end if that struct + UInt64 AdditionalStartBlockSize; // start signature & start header size +}; + +const UInt32 kFinishHeaderSize = kStartHeaderSize + 16; +#endif + +namespace NID +{ + enum EEnum + { + kEnd, + + kHeader, + + kArchiveProperties, + + kAdditionalStreamsInfo, + kMainStreamsInfo, + kFilesInfo, + + kPackInfo, + kUnpackInfo, + kSubStreamsInfo, + + kSize, + kCRC, + + kFolder, + + kCodersUnpackSize, + kNumUnpackStream, + + kEmptyStream, + kEmptyFile, + kAnti, + + kName, + kCTime, + kATime, + kMTime, + kWinAttrib, + kComment, + + kEncodedHeader, + + kStartPos, + kDummy + + // kNtSecure, + // kParent, + // kIsAux + }; +} + + +const UInt32 k_Copy = 0; +const UInt32 k_Delta = 3; +const UInt32 k_ARM64 = 0xa; +const UInt32 k_RISCV = 0xb; + +const UInt32 k_LZMA2 = 0x21; + +const UInt32 k_SWAP2 = 0x20302; +const UInt32 k_SWAP4 = 0x20304; + +const UInt32 k_LZMA = 0x30101; +const UInt32 k_PPMD = 0x30401; + +const UInt32 k_Deflate = 0x40108; +const UInt32 k_Deflate64 = 0x40109; +const UInt32 k_BZip2 = 0x40202; + +const UInt32 k_BCJ = 0x3030103; +const UInt32 k_BCJ2 = 0x303011B; +const UInt32 k_PPC = 0x3030205; +const UInt32 k_IA64 = 0x3030401; +const UInt32 k_ARM = 0x3030501; +const UInt32 k_ARMT = 0x3030701; +const UInt32 k_SPARC = 0x3030805; + +const UInt32 k_AES = 0x6F10701; + +// const UInt32 k_ZSTD = 0x4015D; // winzip zstd +// 0x4F71101, 7z-zstd + +inline bool IsFilterMethod(UInt64 m) +{ + if (m > (UInt32)0xFFFFFFFF) + return false; + switch ((UInt32)m) + { + case k_Delta: + case k_ARM64: + case k_RISCV: + case k_BCJ: + case k_BCJ2: + case k_PPC: + case k_IA64: + case k_ARM: + case k_ARMT: + case k_SPARC: + case k_SWAP2: + case k_SWAP4: + return true; + default: break; + } + return false; +} + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp index 81862d00b..e2efc520a 100644 --- a/CPP/7zip/Archive/7z/7zIn.cpp +++ b/CPP/7zip/Archive/7z/7zIn.cpp @@ -1,1764 +1,1764 @@ -// 7zIn.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include -#else -#include -#endif - -#include "../../../../C/7zCrc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyBuffer2.h" -// #include "../../../Common/UTFConvert.h" - -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "7zDecode.h" -#include "7zIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader -#ifndef Z7_SFX -#define FORMAT_7Z_RECOVERY -#endif - -using namespace NWindows; -using namespace NCOM; - -unsigned BoolVector_CountSum(const CBoolVector &v); -Z7_NO_INLINE -unsigned BoolVector_CountSum(const CBoolVector &v) -{ - unsigned sum = 0; - const unsigned size = v.Size(); - if (size) - { - const bool *p = v.ConstData(); - const bool * const lim = p + size; - do - if (*p) - sum++; - while (++p != lim); - } - return sum; -} - -static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i) -{ - return i < v.Size() ? v[i] : false; -} - -Z7_NO_INLINE -static void BoolVector_Fill_False(CBoolVector &v, unsigned size) -{ - v.ClearAndSetSize(size); - bool *p = v.NonConstData(); - for (unsigned i = 0; i < size; i++) - p[i] = false; -} - - -namespace NArchive { -namespace N7z { - -#define k_Scan_NumCoders_MAX 64 -#define k_Scan_NumCodersStreams_in_Folder_MAX 64 - -class CInArchiveException {}; -class CUnsupportedFeatureException: public CInArchiveException {}; - -Z7_ATTR_NORETURN -static void ThrowException() { throw CInArchiveException(); } -Z7_ATTR_NORETURN -static inline void ThrowEndOfData() { ThrowException(); } -Z7_ATTR_NORETURN -static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); } -Z7_ATTR_NORETURN -static inline void ThrowIncorrect() { ThrowException(); } - -class CStreamSwitch -{ - CInArchive *_archive; - bool _needRemove; - bool _needUpdatePos; -public: - CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {} - ~CStreamSwitch() { Remove(); } - void Remove(); - void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos); - void Set(CInArchive *archive, const CByteBuffer &byteBuffer); - void Set(CInArchive *archive, const CObjectVector *dataVector); -}; - -void CStreamSwitch::Remove() -{ - if (_needRemove) - { - if (_archive->_inByteBack->GetRem() != 0) - _archive->ThereIsHeaderError = true; - _archive->DeleteByteStream(_needUpdatePos); - _needRemove = false; - } -} - -void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos) -{ - Remove(); - _archive = archive; - _archive->AddByteStream(data, size); - _needRemove = true; - _needUpdatePos = needUpdatePos; -} - -void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) -{ - Set(archive, byteBuffer, byteBuffer.Size(), false); -} - -void CStreamSwitch::Set(CInArchive *archive, const CObjectVector *dataVector) -{ - Remove(); - const Byte external = archive->ReadByte(); - if (external != 0) - { - if (!dataVector) - ThrowIncorrect(); - const CNum dataIndex = archive->ReadNum(); - if (dataIndex >= dataVector->Size()) - ThrowIncorrect(); - Set(archive, (*dataVector)[dataIndex]); - } -} - -void CInArchive::AddByteStream(const Byte *buf, size_t size) -{ - if (_numInByteBufs == kNumBufLevelsMax) - ThrowIncorrect(); - _inByteBack = &_inByteVector[_numInByteBufs++]; - _inByteBack->Init(buf, size); -} - - -Byte CInByte2::ReadByte() -{ - if (_pos >= _size) - ThrowEndOfData(); - return _buffer[_pos++]; -} - -void CInByte2::ReadBytes(Byte *data, size_t size) -{ - if (size == 0) - return; - if (size > _size - _pos) - ThrowEndOfData(); - memcpy(data, _buffer + _pos, size); - _pos += size; -} - -void CInByte2::SkipData(UInt64 size) -{ - if (size > _size - _pos) - ThrowEndOfData(); - _pos += (size_t)size; -} - -void CInByte2::SkipData() -{ - SkipData(ReadNumber()); -} - -static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) -{ - if (size == 0) - { - processed = 0; - return 0; - } - - const unsigned b = *p++; - size--; - - if ((b & 0x80) == 0) - { - processed = 1; - return b; - } - - if (size == 0) - { - processed = 0; - return 0; - } - - UInt64 value = (UInt64)*p; - p++; - size--; - - for (unsigned i = 1; i < 8; i++) - { - const unsigned mask = (unsigned)0x80 >> i; - if ((b & mask) == 0) - { - const UInt64 high = b & (mask - 1); - value |= (high << (i * 8)); - processed = i + 1; - return value; - } - - if (size == 0) - { - processed = 0; - return 0; - } - - value |= ((UInt64)*p << (i * 8)); - p++; - size--; - } - - processed = 9; - return value; -} - -UInt64 CInByte2::ReadNumber() -{ - size_t processed; - const UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed); - if (processed == 0) - ThrowEndOfData(); - _pos += processed; - return res; -} - -CNum CInByte2::ReadNum() -{ - /* - if (_pos < _size) - { - Byte val = _buffer[_pos]; - if ((unsigned)val < 0x80) - { - _pos++; - return (unsigned)val; - } - } - */ - const UInt64 value = ReadNumber(); - if (value > kNumMax) - ThrowUnsupported(); - return (CNum)value; -} - -UInt32 CInByte2::ReadUInt32() -{ - if (_pos + 4 > _size) - ThrowEndOfData(); - const UInt32 res = Get32(_buffer + _pos); - _pos += 4; - return res; -} - -UInt64 CInByte2::ReadUInt64() -{ - if (_pos + 8 > _size) - ThrowEndOfData(); - const UInt64 res = Get64(_buffer + _pos); - _pos += 8; - return res; -} - -#define Y0 '7' -#define Y1 'z' -#define Y2 0xBC -#define Y3 0xAF -#define Y4 0x27 -#define Y5 0x1C - -#define IS_SIGNATURE(p)( \ - (p)[2] == Y2 && \ - (p)[3] == Y3 && \ - (p)[5] == Y5 && \ - (p)[4] == Y4 && \ - (p)[1] == Y1 && \ - (p)[0] == Y0) - -/* FindSignature_10() is allowed to access data up to and including &limit[9]. - limit[10] access is not allowed. - return: - (return_ptr < limit) : signature was found at (return_ptr) - (return_ptr >= limit) : limit was reached or crossed. So no signature found before limit -*/ -Z7_NO_INLINE -static const Byte *FindSignature_10(const Byte *p, const Byte *limit) -{ - for (;;) - { - for (;;) - { - if (p >= limit) - return limit; - const Byte b = p[5]; - p += 6; - if (b == Y0) { break; } - if (b == Y1) { p -= 1; break; } - if (b == Y2) { p -= 2; break; } - if (b == Y3) { p -= 3; break; } - if (b == Y4) { p -= 4; break; } - if (b == Y5) { p -= 5; break; } - } - if (IS_SIGNATURE(p - 1)) - return p - 1; - } -} - - -static inline bool TestStartCrc(const Byte *p) -{ - return CrcCalc(p + 12, 20) == Get32(p + 8); -} - -static inline bool TestSignature2(const Byte *p) -{ - if (!IS_SIGNATURE(p)) - return false; - #ifdef FORMAT_7Z_RECOVERY - if (TestStartCrc(p)) - return true; - for (unsigned i = 8; i < kHeaderSize; i++) - if (p[i] != 0) - return false; - return (p[6] != 0 || p[7] != 0); - #else - return TestStartCrc(p); - #endif -} - - -HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) -{ - RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)) - - if (TestSignature2(_header)) - return S_OK; - if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) - return S_FALSE; - - const UInt32 kBufSize = (1 << 15) + kHeaderSize; // must be > (kHeaderSize * 2) - CAlignedBuffer1 buf(kBufSize); - memcpy(buf, _header, kHeaderSize); - UInt64 offset = 0; - - for (;;) - { - UInt32 readSize = - (offset == 0) ? - kBufSize - kHeaderSize - kHeaderSize : - kBufSize - kHeaderSize; - if (searchHeaderSizeLimit) - { - const UInt64 rem = *searchHeaderSizeLimit - offset; - if (readSize > rem) - readSize = (UInt32)rem; - if (readSize == 0) - return S_FALSE; - } - - UInt32 processed = 0; - RINOK(stream->Read(buf + kHeaderSize, readSize, &processed)) - if (processed == 0) - return S_FALSE; - - /* &buf[0] was already tested for signature before. - So first search here will be for &buf[1] */ - - for (UInt32 pos = 0;;) - { - const Byte *p = buf + pos + 1; - const Byte *lim = buf + processed + 1; - /* we have (kHeaderSize - 1 = 31) filled bytes starting from (lim), - and it's safe to access just 10 bytes in that reserved area */ - p = FindSignature_10(p, lim); - if (p >= lim) - break; - pos = (UInt32)(p - buf); - if (TestStartCrc(p)) - { - memcpy(_header, p, kHeaderSize); - _arhiveBeginStreamPosition += offset + pos; - return InStream_SeekSet(stream, _arhiveBeginStreamPosition + kHeaderSize); - } - } - - offset += processed; - memmove(buf, buf + processed, kHeaderSize); - } -} - -// S_FALSE means that file is not archive -HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) -{ - HeadersSize = 0; - Close(); - RINOK(InStream_GetPos_GetSize(stream, _arhiveBeginStreamPosition, _fileEndPosition)) - RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)) - _stream = stream; - return S_OK; -} - -void CInArchive::Close() -{ - _numInByteBufs = 0; - _stream.Release(); - ThereIsHeaderError = false; -} - -void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) -{ - for (;;) - { - if (ReadID() == NID::kEnd) - break; - SkipData(); - } -} - -// CFolder &folder can be non empty. So we must set all fields - -void CInByte2::ParseFolder(CFolder &folder) -{ - const UInt32 numCoders = ReadNum(); - - if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) - ThrowUnsupported(); - - folder.Coders.SetSize(numCoders); - - UInt32 numInStreams = 0; - UInt32 i; - for (i = 0; i < numCoders; i++) - { - CCoderInfo &coder = folder.Coders[i]; - { - const Byte mainByte = ReadByte(); - if ((mainByte & 0xC0) != 0) - ThrowUnsupported(); - const unsigned idSize = (mainByte & 0xF); - if (idSize > 8 || idSize > GetRem()) - ThrowUnsupported(); - const Byte *longID = GetPtr(); - UInt64 id = 0; - for (unsigned j = 0; j < idSize; j++) - id = ((id << 8) | longID[j]); - SkipDataNoCheck(idSize); - coder.MethodID = id; - - if ((mainByte & 0x10) != 0) - { - coder.NumStreams = ReadNum(); - // if (coder.NumStreams > k_Scan_NumCodersStreams_in_Folder_MAX) ThrowUnsupported(); - /* numOutStreams = */ ReadNum(); - // if (ReadNum() != 1) // numOutStreams ThrowUnsupported(); - } - else - { - coder.NumStreams = 1; - } - - if ((mainByte & 0x20) != 0) - { - const CNum propsSize = ReadNum(); - coder.Props.Alloc((size_t)propsSize); - ReadBytes((Byte *)coder.Props, (size_t)propsSize); - } - else - coder.Props.Free(); - } - numInStreams += coder.NumStreams; - } - - const UInt32 numBonds = numCoders - 1; - folder.Bonds.SetSize(numBonds); - for (i = 0; i < numBonds; i++) - { - CBond &bp = folder.Bonds[i]; - bp.PackIndex = ReadNum(); - bp.UnpackIndex = ReadNum(); - } - - if (numInStreams < numBonds) - ThrowUnsupported(); - const UInt32 numPackStreams = numInStreams - numBonds; - folder.PackStreams.SetSize(numPackStreams); - - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams; i++) - if (folder.FindBond_for_PackStream(i) < 0) - { - folder.PackStreams[0] = i; - break; - } - if (i == numInStreams) - ThrowUnsupported(); - } - else - for (i = 0; i < numPackStreams; i++) - folder.PackStreams[i] = ReadNum(); -} - -void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const -{ - const size_t startPos = FoCodersDataOffset[folderIndex]; - CInByte2 inByte; - inByte.Init(CodersData.ConstData() + startPos, FoCodersDataOffset[folderIndex + 1] - startPos); - inByte.ParseFolder(folder); - if (inByte.GetRem() != 0) - throw 20120424; -} - - -void CDatabase::GetPath(unsigned index, UString &path) const -{ - path.Empty(); - if (!NameOffsets || !NamesBuf) - return; - - const size_t offset = NameOffsets[index]; - const size_t size = NameOffsets[index + 1] - offset; - - if (size >= (1 << 28)) - return; - - wchar_t *s = path.GetBuf((unsigned)size - 1); - - const Byte *p = ((const Byte *)NamesBuf + offset * 2); - - #if defined(_WIN32) && defined(MY_CPU_LE) - - wmemcpy(s, (const wchar_t *)(const void *)p, size); - - #else - - for (size_t i = 0; i < size; i++) - { - *s = Get16(p); - p += 2; - s++; - } - - #endif - - path.ReleaseBuf_SetLen((unsigned)size - 1); -} - -HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() -{ - PropVariant_Clear(path); - if (!NameOffsets || !NamesBuf) - return S_OK; - - const size_t offset = NameOffsets[index]; - const size_t size = NameOffsets[index + 1] - offset; - - if (size >= (1 << 14)) - return S_OK; - - // (size) includes null terminator - - /* - #if WCHAR_MAX > 0xffff - - const Byte *p = ((const Byte *)NamesBuf + offset * 2); - size = Utf16LE__Get_Num_WCHARs(p, size - 1); - // (size) doesn't include null terminator - RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size)); - wchar_t *s = path->bstrVal; - wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, size, s); - *sEnd = 0; - if (s + size != sEnd) return E_FAIL; - - #else - */ - - RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1)) - wchar_t *s = path->bstrVal; - const Byte *p = ((const Byte *)NamesBuf + offset * 2); - // Utf16LE__To_WCHARs_Sep(p, size, s); - - for (size_t i = 0; i < size; i++) - { - wchar_t c = Get16(p); - p += 2; - #if WCHAR_PATH_SEPARATOR != L'/' - if (c == L'/') - c = WCHAR_PATH_SEPARATOR; - else if (c == L'\\') - c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme - #endif - *s++ = c; - } - - // #endif - - return S_OK; - - /* - unsigned cur = index; - unsigned size = 0; - - for (int i = 0;; i++) - { - size_t len = NameOffsets[cur + 1] - NameOffsets[cur]; - size += (unsigned)len; - if (i > 256 || len > (1 << 14) || size > (1 << 14)) - return PropVarEm_Set_Str(path, "[TOO-LONG]"); - cur = Files[cur].Parent; - if (cur < 0) - break; - } - size--; - - RINOK(PropVarEm_Alloc_Bstr(path, size)); - wchar_t *s = path->bstrVal; - s += size; - *s = 0; - cur = index; - - for (;;) - { - unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); - const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; - for (; len != 0; len--) - { - p -= 2; - --s; - wchar_t c = Get16(p); - if (c == '/') - c = WCHAR_PATH_SEPARATOR; - *s = c; - } - - const CFileItem &file = Files[cur]; - cur = file.Parent; - if (cur < 0) - return S_OK; - *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR); - } - */ -} - -void CInArchive::WaitId(UInt64 id) -{ - for (;;) - { - const UInt64 type = ReadID(); - if (type == id) - return; - if (type == NID::kEnd) - ThrowIncorrect(); - SkipData(); - } -} - - -void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v) -{ - const unsigned numItems = v.Defs.Size(); - v.Vals.ClearAndSetSize(numItems); - UInt32 *p = &v.Vals[0]; - const bool *defs = &v.Defs[0]; - for (unsigned i = 0; i < numItems; i++) - { - UInt32 a = 0; - if (defs[i]) - a = ReadUInt32(); - p[i] = a; - } -} - - -void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) -{ - ReadBoolVector2(numItems, crcs.Defs); - Read_UInt32_Vector(crcs); -} - - -void CInArchive::ReadPackInfo(CFolders &f) -{ - const CNum numPackStreams = ReadNum(); - - WaitId(NID::kSize); - f.PackPositions.Alloc(numPackStreams + 1); - f.NumPackStreams = numPackStreams; - UInt64 sum = 0; - for (CNum i = 0; i < numPackStreams; i++) - { - f.PackPositions[i] = sum; - const UInt64 packSize = ReadNumber(); - sum += packSize; - if (sum < packSize) - ThrowIncorrect(); - } - f.PackPositions[numPackStreams] = sum; - - UInt64 type; - for (;;) - { - type = ReadID(); - if (type == NID::kEnd) - return; - if (type == NID::kCRC) - { - CUInt32DefVector PackCRCs; - ReadHashDigests(numPackStreams, PackCRCs); - continue; - } - SkipData(); - } -} - -void CInArchive::ReadUnpackInfo( - const CObjectVector *dataVector, - CFolders &folders) -{ - WaitId(NID::kFolder); - const CNum numFolders = ReadNum(); - - CNum numCodersOutStreams = 0; - { - CStreamSwitch streamSwitch; - streamSwitch.Set(this, dataVector); - const Byte *startBufPtr = _inByteBack->GetPtr(); - folders.NumFolders = numFolders; - - folders.FoStartPackStreamIndex.Alloc(numFolders + 1); - folders.FoToMainUnpackSizeIndex.Alloc(numFolders); - folders.FoCodersDataOffset.Alloc(numFolders + 1); - folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); - - CBoolVector StreamUsed; - CBoolVector CoderUsed; - - CNum packStreamIndex = 0; - CNum fo; - CInByte2 *inByte = _inByteBack; - - for (fo = 0; fo < numFolders; fo++) - { - UInt32 indexOfMainStream = 0; - UInt32 numPackStreams = 0; - folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr); - - CNum numInStreams = 0; - const CNum numCoders = inByte->ReadNum(); - - if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) - ThrowUnsupported(); - - for (CNum ci = 0; ci < numCoders; ci++) - { - const Byte mainByte = inByte->ReadByte(); - if ((mainByte & 0xC0) != 0) - ThrowUnsupported(); - - const unsigned idSize = (mainByte & 0xF); - if (idSize > 8) - ThrowUnsupported(); - if (idSize > inByte->GetRem()) - ThrowEndOfData(); - const Byte *longID = inByte->GetPtr(); - UInt64 id = 0; - for (unsigned j = 0; j < idSize; j++) - id = ((id << 8) | longID[j]); - inByte->SkipDataNoCheck(idSize); - if (folders.ParsedMethods.IDs.Size() < 128) - folders.ParsedMethods.IDs.AddToUniqueSorted(id); - - CNum coderInStreams = 1; - if ((mainByte & 0x10) != 0) - { - coderInStreams = inByte->ReadNum(); - if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) - ThrowUnsupported(); - if (inByte->ReadNum() != 1) - ThrowUnsupported(); - } - - numInStreams += coderInStreams; - if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) - ThrowUnsupported(); - - if ((mainByte & 0x20) != 0) - { - const CNum propsSize = inByte->ReadNum(); - if (propsSize > inByte->GetRem()) - ThrowEndOfData(); - if (id == k_LZMA2 && propsSize == 1) - { - const Byte v = *_inByteBack->GetPtr(); - if (folders.ParsedMethods.Lzma2Prop < v) - folders.ParsedMethods.Lzma2Prop = v; - } - else if (id == k_LZMA && propsSize == 5) - { - const UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1); - if (folders.ParsedMethods.LzmaDic < dicSize) - folders.ParsedMethods.LzmaDic = dicSize; - } - inByte->SkipDataNoCheck((size_t)propsSize); - } - } - - if (numCoders == 1 && numInStreams == 1) - { - indexOfMainStream = 0; - numPackStreams = 1; - } - else - { - UInt32 i; - const CNum numBonds = numCoders - 1; - if (numInStreams < numBonds) - ThrowUnsupported(); - - BoolVector_Fill_False(StreamUsed, numInStreams); - BoolVector_Fill_False(CoderUsed, numCoders); - - for (i = 0; i < numBonds; i++) - { - CNum index = ReadNum(); - if (index >= numInStreams || StreamUsed[index]) - ThrowUnsupported(); - StreamUsed[index] = true; - - index = ReadNum(); - if (index >= numCoders || CoderUsed[index]) - ThrowUnsupported(); - CoderUsed[index] = true; - } - - numPackStreams = numInStreams - numBonds; - - if (numPackStreams != 1) - for (i = 0; i < numPackStreams; i++) - { - const CNum index = inByte->ReadNum(); // PackStreams - if (index >= numInStreams || StreamUsed[index]) - ThrowUnsupported(); - StreamUsed[index] = true; - } - - for (i = 0; i < numCoders; i++) - if (!CoderUsed[i]) - { - indexOfMainStream = i; - break; - } - - if (i == numCoders) - ThrowUnsupported(); - } - - folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; - numCodersOutStreams += numCoders; - folders.FoStartPackStreamIndex[fo] = packStreamIndex; - if (numPackStreams > folders.NumPackStreams - packStreamIndex) - ThrowIncorrect(); - packStreamIndex += numPackStreams; - folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; - } - - const size_t dataSize = (size_t)(_inByteBack->GetPtr() - startBufPtr); - folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; - folders.FoStartPackStreamIndex[fo] = packStreamIndex; - folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr); - folders.CodersData.CopyFrom(startBufPtr, dataSize); - - // if (folders.NumPackStreams != packStreamIndex) ThrowUnsupported(); - } - - WaitId(NID::kCodersUnpackSize); - folders.CoderUnpackSizes.Alloc(numCodersOutStreams); - for (CNum i = 0; i < numCodersOutStreams; i++) - folders.CoderUnpackSizes[i] = ReadNumber(); - - for (;;) - { - const UInt64 type = ReadID(); - if (type == NID::kEnd) - return; - if (type == NID::kCRC) - { - ReadHashDigests(numFolders, folders.FolderCRCs); - continue; - } - SkipData(); - } -} - -void CInArchive::ReadSubStreamsInfo( - CFolders &folders, - CRecordVector &unpackSizes, - CUInt32DefVector &digests) -{ - folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); - CNum i; - for (i = 0; i < folders.NumFolders; i++) - folders.NumUnpackStreamsVector[i] = 1; - - UInt64 type; - - for (;;) - { - type = ReadID(); - if (type == NID::kNumUnpackStream) - { - for (i = 0; i < folders.NumFolders; i++) - folders.NumUnpackStreamsVector[i] = ReadNum(); - continue; - } - if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd) - break; - SkipData(); - } - - if (type == NID::kSize) - { - for (i = 0; i < folders.NumFolders; i++) - { - // v3.13 incorrectly worked with empty folders - // v4.07: we check that folder is empty - const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; - if (numSubstreams == 0) - continue; - UInt64 sum = 0; - for (CNum j = 1; j < numSubstreams; j++) - { - const UInt64 size = ReadNumber(); - unpackSizes.Add(size); - sum += size; - if (sum < size) - ThrowIncorrect(); - } - const UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i); - if (folderUnpackSize < sum) - ThrowIncorrect(); - unpackSizes.Add(folderUnpackSize - sum); - } - type = ReadID(); - } - else - { - for (i = 0; i < folders.NumFolders; i++) - { - /* v9.26 - v9.29 incorrectly worked: - if (folders.NumUnpackStreamsVector[i] == 0), it threw error */ - const CNum val = folders.NumUnpackStreamsVector[i]; - if (val > 1) - ThrowIncorrect(); - if (val == 1) - unpackSizes.Add(folders.GetFolderUnpackSize(i)); - } - } - - unsigned numDigests = 0; - for (i = 0; i < folders.NumFolders; i++) - { - const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; - if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i)) - numDigests += numSubstreams; - } - - for (;;) - { - if (type == NID::kEnd) - break; - if (type == NID::kCRC) - { - // CUInt32DefVector digests2; - // ReadHashDigests(numDigests, digests2); - CBoolVector digests2; - ReadBoolVector2(numDigests, digests2); - - digests.ClearAndSetSize(unpackSizes.Size()); - - unsigned k = 0; - unsigned k2 = 0; - - for (i = 0; i < folders.NumFolders; i++) - { - const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; - if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) - { - digests.Defs[k] = true; - digests.Vals[k] = folders.FolderCRCs.Vals[i]; - k++; - } - else for (CNum j = 0; j < numSubstreams; j++) - { - bool defined = digests2[k2++]; - digests.Defs[k] = defined; - UInt32 crc = 0; - if (defined) - crc = ReadUInt32(); - digests.Vals[k] = crc; - k++; - } - } - // if (k != unpackSizes.Size()) throw 1234567; - } - else - SkipData(); - - type = ReadID(); - } - - if (digests.Defs.Size() != unpackSizes.Size()) - { - digests.ClearAndSetSize(unpackSizes.Size()); - unsigned k = 0; - for (i = 0; i < folders.NumFolders; i++) - { - const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; - if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) - { - digests.Defs[k] = true; - digests.Vals[k] = folders.FolderCRCs.Vals[i]; - k++; - } - else for (CNum j = 0; j < numSubstreams; j++) - { - digests.Defs[k] = false; - digests.Vals[k] = 0; - k++; - } - } - } -} - - - -void CInArchive::ReadStreamsInfo( - const CObjectVector *dataVector, - UInt64 &dataOffset, - CFolders &folders, - CRecordVector &unpackSizes, - CUInt32DefVector &digests) -{ - UInt64 type = ReadID(); - - if (type == NID::kPackInfo) - { - dataOffset = ReadNumber(); - if (dataOffset > _rangeLimit) - ThrowIncorrect(); - ReadPackInfo(folders); - if (folders.PackPositions[folders.NumPackStreams] > _rangeLimit - dataOffset) - ThrowIncorrect(); - type = ReadID(); - } - - if (type == NID::kUnpackInfo) - { - ReadUnpackInfo(dataVector, folders); - type = ReadID(); - } - - if (folders.NumFolders != 0 && !folders.PackPositions) - { - // if there are folders, we need PackPositions also - folders.PackPositions.Alloc(1); - folders.PackPositions[0] = 0; - } - - if (type == NID::kSubStreamsInfo) - { - ReadSubStreamsInfo(folders, unpackSizes, digests); - type = ReadID(); - } - else - { - folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); - /* If digests.Defs.Size() == 0, it means that there are no crcs. - So we don't need to fill digests with values. */ - // digests.Vals.ClearAndSetSize(folders.NumFolders); - // BoolVector_Fill_False(digests.Defs, folders.NumFolders); - for (CNum i = 0; i < folders.NumFolders; i++) - { - folders.NumUnpackStreamsVector[i] = 1; - unpackSizes.Add(folders.GetFolderUnpackSize(i)); - // digests.Vals[i] = 0; - } - } - - if (type != NID::kEnd) - ThrowIncorrect(); -} - -void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v) -{ - v.ClearAndSetSize(numItems); - Byte b = 0; - Byte mask = 0; - bool *p = &v[0]; - for (unsigned i = 0; i < numItems; i++) - { - if (mask == 0) - { - b = ReadByte(); - mask = 0x80; - } - p[i] = ((b & mask) != 0); - mask = (Byte)(mask >> 1); - } -} - -void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v) -{ - const Byte allAreDefined = ReadByte(); - if (allAreDefined == 0) - { - ReadBoolVector(numItems, v); - return; - } - v.ClearAndSetSize(numItems); - bool *p = &v[0]; - for (unsigned i = 0; i < numItems; i++) - p[i] = true; -} - -void CInArchive::ReadUInt64DefVector(const CObjectVector &dataVector, - CUInt64DefVector &v, unsigned numItems) -{ - ReadBoolVector2(numItems, v.Defs); - - CStreamSwitch streamSwitch; - streamSwitch.Set(this, &dataVector); - - v.Vals.ClearAndSetSize(numItems); - UInt64 *p = &v.Vals[0]; - const bool *defs = &v.Defs[0]; - - for (unsigned i = 0; i < numItems; i++) - { - UInt64 t = 0; - if (defs[i]) - t = ReadUInt64(); - p[i] = t; - } -} - -HRESULT CInArchive::ReadAndDecodePackedStreams( - DECL_EXTERNAL_CODECS_LOC_VARS - UInt64 baseOffset, - UInt64 &dataOffset, CObjectVector &dataVector - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ) -{ - CFolders folders; - CRecordVector unpackSizes; - CUInt32DefVector digests; - - ReadStreamsInfo(NULL, - dataOffset, - folders, - unpackSizes, - digests); - - CDecoder decoder(_useMixerMT); - - for (CNum i = 0; i < folders.NumFolders; i++) - { - CByteBuffer &data = dataVector.AddNew(); - const UInt64 unpackSize64 = folders.GetFolderUnpackSize(i); - const size_t unpackSize = (size_t)unpackSize64; - if (unpackSize != unpackSize64) - ThrowUnsupported(); - data.Alloc(unpackSize); - - CMyComPtr2_Create outStreamSpec; - outStreamSpec->Init(data, unpackSize); - - bool dataAfterEnd_Error = false; - - HRESULT result = decoder.Decode( - EXTERNAL_CODECS_LOC_VARS - _stream, baseOffset + dataOffset, - folders, i, - NULL, // &unpackSize64 - - outStreamSpec, - NULL, // *compressProgress - - NULL // **inStreamMainRes - , dataAfterEnd_Error - - Z7_7Z_DECODER_CRYPRO_VARS - #if !defined(Z7_ST) - , false // mtMode - , 1 // numThreads - , 0 // memUsage - #endif - ); - - RINOK(result) - - if (dataAfterEnd_Error) - ThereIsHeaderError = true; - - if (unpackSize != outStreamSpec->GetPos()) - ThrowIncorrect(); - - if (folders.FolderCRCs.ValidAndDefined(i)) - if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) - ThrowIncorrect(); - } - - if (folders.PackPositions) - HeadersSize += folders.PackPositions[folders.NumPackStreams]; - - return S_OK; -} - -HRESULT CInArchive::ReadHeader( - DECL_EXTERNAL_CODECS_LOC_VARS - CDbEx &db - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ) -{ - UInt64 type = ReadID(); - - if (type == NID::kArchiveProperties) - { - ReadArchiveProperties(db.ArcInfo); - type = ReadID(); - } - - CObjectVector dataVector; - - if (type == NID::kAdditionalStreamsInfo) - { - const HRESULT result = ReadAndDecodePackedStreams( - EXTERNAL_CODECS_LOC_VARS - db.ArcInfo.StartPositionAfterHeader, - db.ArcInfo.DataStartPosition2, - dataVector - Z7_7Z_DECODER_CRYPRO_VARS - ); - RINOK(result) - db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader; - type = ReadID(); - } - - CRecordVector unpackSizes; - CUInt32DefVector digests; - - if (type == NID::kMainStreamsInfo) - { - ReadStreamsInfo(&dataVector, - db.ArcInfo.DataStartPosition, - (CFolders &)db, - unpackSizes, - digests); - db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader; - type = ReadID(); - } - - if (type == NID::kFilesInfo) - { - - const CNum numFiles = ReadNum(); - - db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); - // if (!db.PackSizes.IsEmpty()) - db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); - if (numFiles > 0 && !digests.Defs.IsEmpty()) - db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); - - CBoolVector emptyStreamVector; - CBoolVector emptyFileVector; - CBoolVector antiFileVector; - unsigned numEmptyStreams = 0; - - for (;;) - { - const UInt64 type2 = ReadID(); - if (type2 == NID::kEnd) - break; - const UInt64 size = ReadNumber(); - if (size > _inByteBack->GetRem()) - ThrowIncorrect(); - CStreamSwitch switchProp; - switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true); - bool addPropIdToList = true; - bool isKnownType = true; - if (type2 > ((UInt32)1 << 30)) - isKnownType = false; - else switch ((UInt32)type2) - { - case NID::kName: - { - CStreamSwitch streamSwitch; - streamSwitch.Set(this, &dataVector); - const size_t rem = _inByteBack->GetRem(); - db.NamesBuf.Alloc(rem); - ReadBytes(db.NamesBuf, rem); - db.NameOffsets.Alloc(numFiles + 1); - size_t pos = 0; - unsigned i; - for (i = 0; i < numFiles; i++) - { - const size_t curRem = (rem - pos) / 2; - const UInt16 *buf = (const UInt16 *)(const void *)(db.NamesBuf.ConstData() + pos); - size_t j; - for (j = 0; j < curRem && buf[j] != 0; j++); - if (j == curRem) - ThrowEndOfData(); - db.NameOffsets[i] = pos / 2; - pos += j * 2 + 2; - } - db.NameOffsets[i] = pos / 2; - if (pos != rem) - ThereIsHeaderError = true; - break; - } - - case NID::kWinAttrib: - { - ReadBoolVector2(numFiles, db.Attrib.Defs); - CStreamSwitch streamSwitch; - streamSwitch.Set(this, &dataVector); - Read_UInt32_Vector(db.Attrib); - break; - } - - /* - case NID::kIsAux: - { - ReadBoolVector(numFiles, db.IsAux); - break; - } - case NID::kParent: - { - db.IsTree = true; - // CBoolVector boolVector; - // ReadBoolVector2(numFiles, boolVector); - // CStreamSwitch streamSwitch; - // streamSwitch.Set(this, &dataVector); - CBoolVector boolVector; - ReadBoolVector2(numFiles, boolVector); - - db.ThereAreAltStreams = false; - for (i = 0; i < numFiles; i++) - { - CFileItem &file = db.Files[i]; - // file.Parent = -1; - // if (boolVector[i]) - file.Parent = (int)ReadUInt32(); - file.IsAltStream = !boolVector[i]; - if (file.IsAltStream) - db.ThereAreAltStreams = true; - } - break; - } - */ - case NID::kEmptyStream: - { - ReadBoolVector(numFiles, emptyStreamVector); - numEmptyStreams = BoolVector_CountSum(emptyStreamVector); - emptyFileVector.Clear(); - antiFileVector.Clear(); - break; - } - case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; - case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; - case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break; - case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break; - case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break; - case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break; - case NID::kDummy: - { - for (UInt64 j = 0; j < size; j++) - if (ReadByte() != 0) - ThereIsHeaderError = true; - addPropIdToList = false; - break; - } - /* - case NID::kNtSecure: - { - try - { - { - CStreamSwitch streamSwitch; - streamSwitch.Set(this, &dataVector); - UInt32 numDescriptors = ReadUInt32(); - size_t offset = 0; - db.SecureOffsets.Clear(); - for (i = 0; i < numDescriptors; i++) - { - UInt32 size = ReadUInt32(); - db.SecureOffsets.Add(offset); - offset += size; - } - // ThrowIncorrect();; - db.SecureOffsets.Add(offset); - db.SecureBuf.SetCapacity(offset); - for (i = 0; i < numDescriptors; i++) - { - offset = db.SecureOffsets[i]; - ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); - } - db.SecureIDs.Clear(); - for (unsigned i = 0; i < numFiles; i++) - { - db.SecureIDs.Add(ReadNum()); - // db.SecureIDs.Add(ReadUInt32()); - } - // ReadUInt32(); - if (_inByteBack->GetRem() != 0) - ThrowIncorrect();; - } - } - catch(CInArchiveException &) - { - ThereIsHeaderError = true; - addPropIdToList = isKnownType = false; - db.ClearSecure(); - } - break; - } - */ - default: - addPropIdToList = isKnownType = false; - } - if (isKnownType) - { - if (addPropIdToList) - db.ArcInfo.FileInfoPopIDs.Add(type2); - } - else - { - db.UnsupportedFeatureWarning = true; - _inByteBack->SkipRem(); - } - // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 0.02) - if (_inByteBack->GetRem() != 0) - ThrowIncorrect(); - } - - type = ReadID(); // Read (NID::kEnd) end of headers - - if (numFiles - numEmptyStreams != unpackSizes.Size()) - ThrowUnsupported(); - - CNum emptyFileIndex = 0; - CNum sizeIndex = 0; - - const unsigned numAntiItems = BoolVector_CountSum(antiFileVector); - - if (numAntiItems != 0) - db.IsAnti.ClearAndSetSize(numFiles); - - db.Files.ClearAndSetSize(numFiles); - - for (CNum i = 0; i < numFiles; i++) - { - CFileItem &file = db.Files[i]; - bool isAnti; - file.Crc = 0; - if (!BoolVector_Item_IsValidAndTrue(emptyStreamVector, i)) - { - file.HasStream = true; - file.IsDir = false; - isAnti = false; - file.Size = unpackSizes[sizeIndex]; - file.CrcDefined = digests.ValidAndDefined(sizeIndex); - if (file.CrcDefined) - file.Crc = digests.Vals[sizeIndex]; - sizeIndex++; - } - else - { - file.HasStream = false; - file.IsDir = !BoolVector_Item_IsValidAndTrue(emptyFileVector, emptyFileIndex); - isAnti = BoolVector_Item_IsValidAndTrue(antiFileVector, emptyFileIndex); - emptyFileIndex++; - file.Size = 0; - file.CrcDefined = false; - } - if (numAntiItems != 0) - db.IsAnti[i] = isAnti; - } - - } - - db.FillLinks(); - - if (type != NID::kEnd || _inByteBack->GetRem() != 0) - { - db.UnsupportedFeatureWarning = true; - // ThrowIncorrect(); - } - - return S_OK; -} - - -void CDbEx::FillLinks() -{ - FolderStartFileIndex.Alloc(NumFolders); - FileIndexToFolderIndexMap.Alloc(Files.Size()); - - CNum folderIndex = 0; - CNum indexInFolder = 0; - unsigned i; - - for (i = 0; i < Files.Size(); i++) - { - const bool emptyStream = !Files[i].HasStream; - if (indexInFolder == 0) - { - if (emptyStream) - { - FileIndexToFolderIndexMap[i] = kNumNoIndex; - continue; - } - // v3.13 incorrectly worked with empty folders - // v4.07: we skip empty folders - for (;;) - { - if (folderIndex >= NumFolders) - ThrowIncorrect(); - FolderStartFileIndex[folderIndex] = i; - if (NumUnpackStreamsVector[folderIndex] != 0) - break; - folderIndex++; - } - } - FileIndexToFolderIndexMap[i] = folderIndex; - if (emptyStream) - continue; - if (++indexInFolder >= NumUnpackStreamsVector[folderIndex]) - { - folderIndex++; - indexInFolder = 0; - } - } - - if (indexInFolder != 0) - { - folderIndex++; - // 18.06 - ThereIsHeaderError = true; - // ThrowIncorrect(); - } - - for (;;) - { - if (folderIndex >= NumFolders) - return; - FolderStartFileIndex[folderIndex] = i; - if (NumUnpackStreamsVector[folderIndex] != 0) - { - // 18.06 - ThereIsHeaderError = true; - // ThrowIncorrect(); - } - folderIndex++; - } -} - - -HRESULT CInArchive::ReadDatabase2( - DECL_EXTERNAL_CODECS_LOC_VARS - CDbEx &db - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ) -{ - db.Clear(); - db.ArcInfo.StartPosition = _arhiveBeginStreamPosition; - - db.ArcInfo.Version.Major = _header[6]; - db.ArcInfo.Version.Minor = _header[7]; - - if (db.ArcInfo.Version.Major != kMajorVersion) - { - // db.UnsupportedVersion = true; - return S_FALSE; - } - - UInt64 nextHeaderOffset = Get64(_header + 12); - UInt64 nextHeaderSize = Get64(_header + 20); - UInt32 nextHeaderCRC = Get32(_header + 28); - - #ifdef FORMAT_7Z_RECOVERY - const UInt32 crcFromArc = Get32(_header + 8); - if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) - { - UInt64 cur, fileSize; - RINOK(InStream_GetPos(_stream, cur)) - const unsigned kCheckSize = 512; - Byte buf[kCheckSize]; - RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize)) - const UInt64 rem = fileSize - cur; - unsigned checkSize = kCheckSize; - if (rem < kCheckSize) - checkSize = (unsigned)(rem); - if (checkSize < 3) - return S_FALSE; - RINOK(InStream_SeekSet(_stream, fileSize - checkSize)) - RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)) - - if (buf[checkSize - 1] != 0) - return S_FALSE; - - unsigned i; - for (i = checkSize - 2;; i--) - { - if ((buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo) || - (buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo)) - break; - if (i == 0) - return S_FALSE; - } - nextHeaderSize = checkSize - i; - nextHeaderOffset = rem - nextHeaderSize; - nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); - RINOK(InStream_SeekSet(_stream, cur)) - db.StartHeaderWasRecovered = true; - } - else - #endif - { - // Crc was tested already at signature check - // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect(); - } - - db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; - db.PhySize = kHeaderSize; - - db.IsArc = false; - if ((Int64)nextHeaderOffset < 0 || - nextHeaderSize > ((UInt64)1 << 62)) - return S_FALSE; - - HeadersSize = kHeaderSize; - - if (nextHeaderSize == 0) - { - if (nextHeaderOffset != 0 || nextHeaderCRC != 0) - return S_FALSE; - db.IsArc = true; - db.HeadersSize = HeadersSize; - return S_OK; - } - - if (!db.StartHeaderWasRecovered) - db.IsArc = true; - - HeadersSize += nextHeaderSize; - // db.EndHeaderOffset = nextHeaderOffset; - _rangeLimit = nextHeaderOffset; - - db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; - if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize) - { - db.UnexpectedEnd = true; - return S_FALSE; - } - RINOK(_stream->Seek((Int64)nextHeaderOffset, STREAM_SEEK_CUR, NULL)) - - const size_t nextHeaderSize_t = (size_t)nextHeaderSize; - if (nextHeaderSize_t != nextHeaderSize) - return E_OUTOFMEMORY; - CByteBuffer buffer2(nextHeaderSize_t); - - RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t)) - - if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC) - ThrowIncorrect(); - - if (!db.StartHeaderWasRecovered) - db.PhySizeWasConfirmed = true; - - CStreamSwitch streamSwitch; - streamSwitch.Set(this, buffer2); - - CObjectVector dataVector; - - const UInt64 type = ReadID(); - if (type != NID::kHeader) - { - if (type != NID::kEncodedHeader) - ThrowIncorrect(); - const HRESULT result = ReadAndDecodePackedStreams( - EXTERNAL_CODECS_LOC_VARS - db.ArcInfo.StartPositionAfterHeader, - db.ArcInfo.DataStartPosition2, - dataVector - Z7_7Z_DECODER_CRYPRO_VARS - ); - RINOK(result) - if (dataVector.Size() == 0) - return S_OK; - if (dataVector.Size() > 1) - ThrowIncorrect(); - streamSwitch.Remove(); - streamSwitch.Set(this, dataVector.Front()); - if (ReadID() != NID::kHeader) - ThrowIncorrect(); - } - - db.IsArc = true; - - db.HeadersSize = HeadersSize; - - return ReadHeader( - EXTERNAL_CODECS_LOC_VARS - db - Z7_7Z_DECODER_CRYPRO_VARS - ); -} - - -HRESULT CInArchive::ReadDatabase( - DECL_EXTERNAL_CODECS_LOC_VARS - CDbEx &db - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ) -{ - try - { - const HRESULT res = ReadDatabase2( - EXTERNAL_CODECS_LOC_VARS db - Z7_7Z_DECODER_CRYPRO_VARS - ); - if (ThereIsHeaderError) - db.ThereIsHeaderError = true; - if (res == E_NOTIMPL) - ThrowUnsupported(); - return res; - } - catch(CUnsupportedFeatureException &) - { - db.UnsupportedFeatureError = true; - return S_FALSE; - } - catch(CInArchiveException &) - { - db.ThereIsHeaderError = true; - return S_FALSE; - } -} - -}} +// 7zIn.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "../../../../C/7zCrc.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyBuffer2.h" +// #include "../../../Common/UTFConvert.h" + +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "7zDecode.h" +#include "7zIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader +#ifndef Z7_SFX +#define FORMAT_7Z_RECOVERY +#endif + +using namespace NWindows; +using namespace NCOM; + +unsigned BoolVector_CountSum(const CBoolVector &v); +Z7_NO_INLINE +unsigned BoolVector_CountSum(const CBoolVector &v) +{ + unsigned sum = 0; + const unsigned size = v.Size(); + if (size) + { + const bool *p = v.ConstData(); + const bool * const lim = p + size; + do + if (*p) + sum++; + while (++p != lim); + } + return sum; +} + +static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i) +{ + return i < v.Size() ? v[i] : false; +} + +Z7_NO_INLINE +static void BoolVector_Fill_False(CBoolVector &v, unsigned size) +{ + v.ClearAndSetSize(size); + bool *p = v.NonConstData(); + for (unsigned i = 0; i < size; i++) + p[i] = false; +} + + +namespace NArchive { +namespace N7z { + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + +class CInArchiveException {}; +class CUnsupportedFeatureException: public CInArchiveException {}; + +Z7_ATTR_NORETURN +static void ThrowException() { throw CInArchiveException(); } +Z7_ATTR_NORETURN +static inline void ThrowEndOfData() { ThrowException(); } +Z7_ATTR_NORETURN +static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); } +Z7_ATTR_NORETURN +static inline void ThrowIncorrect() { ThrowException(); } + +class CStreamSwitch +{ + CInArchive *_archive; + bool _needRemove; + bool _needUpdatePos; +public: + CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {} + ~CStreamSwitch() { Remove(); } + void Remove(); + void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos); + void Set(CInArchive *archive, const CByteBuffer &byteBuffer); + void Set(CInArchive *archive, const CObjectVector *dataVector); +}; + +void CStreamSwitch::Remove() +{ + if (_needRemove) + { + if (_archive->_inByteBack->GetRem() != 0) + _archive->ThereIsHeaderError = true; + _archive->DeleteByteStream(_needUpdatePos); + _needRemove = false; + } +} + +void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos) +{ + Remove(); + _archive = archive; + _archive->AddByteStream(data, size); + _needRemove = true; + _needUpdatePos = needUpdatePos; +} + +void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) +{ + Set(archive, byteBuffer, byteBuffer.Size(), false); +} + +void CStreamSwitch::Set(CInArchive *archive, const CObjectVector *dataVector) +{ + Remove(); + const Byte external = archive->ReadByte(); + if (external != 0) + { + if (!dataVector) + ThrowIncorrect(); + const CNum dataIndex = archive->ReadNum(); + if (dataIndex >= dataVector->Size()) + ThrowIncorrect(); + Set(archive, (*dataVector)[dataIndex]); + } +} + +void CInArchive::AddByteStream(const Byte *buf, size_t size) +{ + if (_numInByteBufs == kNumBufLevelsMax) + ThrowIncorrect(); + _inByteBack = &_inByteVector[_numInByteBufs++]; + _inByteBack->Init(buf, size); +} + + +Byte CInByte2::ReadByte() +{ + if (_pos >= _size) + ThrowEndOfData(); + return _buffer[_pos++]; +} + +void CInByte2::ReadBytes(Byte *data, size_t size) +{ + if (size == 0) + return; + if (size > _size - _pos) + ThrowEndOfData(); + memcpy(data, _buffer + _pos, size); + _pos += size; +} + +void CInByte2::SkipData(UInt64 size) +{ + if (size > _size - _pos) + ThrowEndOfData(); + _pos += (size_t)size; +} + +void CInByte2::SkipData() +{ + SkipData(ReadNumber()); +} + +static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) +{ + if (size == 0) + { + processed = 0; + return 0; + } + + const unsigned b = *p++; + size--; + + if ((b & 0x80) == 0) + { + processed = 1; + return b; + } + + if (size == 0) + { + processed = 0; + return 0; + } + + UInt64 value = (UInt64)*p; + p++; + size--; + + for (unsigned i = 1; i < 8; i++) + { + const unsigned mask = (unsigned)0x80 >> i; + if ((b & mask) == 0) + { + const UInt64 high = b & (mask - 1); + value |= (high << (i * 8)); + processed = i + 1; + return value; + } + + if (size == 0) + { + processed = 0; + return 0; + } + + value |= ((UInt64)*p << (i * 8)); + p++; + size--; + } + + processed = 9; + return value; +} + +UInt64 CInByte2::ReadNumber() +{ + size_t processed; + const UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed); + if (processed == 0) + ThrowEndOfData(); + _pos += processed; + return res; +} + +CNum CInByte2::ReadNum() +{ + /* + if (_pos < _size) + { + Byte val = _buffer[_pos]; + if ((unsigned)val < 0x80) + { + _pos++; + return (unsigned)val; + } + } + */ + const UInt64 value = ReadNumber(); + if (value > kNumMax) + ThrowUnsupported(); + return (CNum)value; +} + +UInt32 CInByte2::ReadUInt32() +{ + if (_pos + 4 > _size) + ThrowEndOfData(); + const UInt32 res = Get32(_buffer + _pos); + _pos += 4; + return res; +} + +UInt64 CInByte2::ReadUInt64() +{ + if (_pos + 8 > _size) + ThrowEndOfData(); + const UInt64 res = Get64(_buffer + _pos); + _pos += 8; + return res; +} + +#define Y0 '7' +#define Y1 'z' +#define Y2 0xBC +#define Y3 0xAF +#define Y4 0x27 +#define Y5 0x1C + +#define IS_SIGNATURE(p)( \ + (p)[2] == Y2 && \ + (p)[3] == Y3 && \ + (p)[5] == Y5 && \ + (p)[4] == Y4 && \ + (p)[1] == Y1 && \ + (p)[0] == Y0) + +/* FindSignature_10() is allowed to access data up to and including &limit[9]. + limit[10] access is not allowed. + return: + (return_ptr < limit) : signature was found at (return_ptr) + (return_ptr >= limit) : limit was reached or crossed. So no signature found before limit +*/ +Z7_NO_INLINE +static const Byte *FindSignature_10(const Byte *p, const Byte *limit) +{ + for (;;) + { + for (;;) + { + if (p >= limit) + return limit; + const Byte b = p[5]; + p += 6; + if (b == Y0) { break; } + if (b == Y1) { p -= 1; break; } + if (b == Y2) { p -= 2; break; } + if (b == Y3) { p -= 3; break; } + if (b == Y4) { p -= 4; break; } + if (b == Y5) { p -= 5; break; } + } + if (IS_SIGNATURE(p - 1)) + return p - 1; + } +} + + +static inline bool TestStartCrc(const Byte *p) +{ + return CrcCalc(p + 12, 20) == Get32(p + 8); +} + +static inline bool TestSignature2(const Byte *p) +{ + if (!IS_SIGNATURE(p)) + return false; + #ifdef FORMAT_7Z_RECOVERY + if (TestStartCrc(p)) + return true; + for (unsigned i = 8; i < kHeaderSize; i++) + if (p[i] != 0) + return false; + return (p[6] != 0 || p[7] != 0); + #else + return TestStartCrc(p); + #endif +} + + +HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)) + + if (TestSignature2(_header)) + return S_OK; + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + + const UInt32 kBufSize = (1 << 15) + kHeaderSize; // must be > (kHeaderSize * 2) + CAlignedBuffer1 buf(kBufSize); + memcpy(buf, _header, kHeaderSize); + UInt64 offset = 0; + + for (;;) + { + UInt32 readSize = + (offset == 0) ? + kBufSize - kHeaderSize - kHeaderSize : + kBufSize - kHeaderSize; + if (searchHeaderSizeLimit) + { + const UInt64 rem = *searchHeaderSizeLimit - offset; + if (readSize > rem) + readSize = (UInt32)rem; + if (readSize == 0) + return S_FALSE; + } + + UInt32 processed = 0; + RINOK(stream->Read(buf + kHeaderSize, readSize, &processed)) + if (processed == 0) + return S_FALSE; + + /* &buf[0] was already tested for signature before. + So first search here will be for &buf[1] */ + + for (UInt32 pos = 0;;) + { + const Byte *p = buf + pos + 1; + const Byte *lim = buf + processed + 1; + /* we have (kHeaderSize - 1 = 31) filled bytes starting from (lim), + and it's safe to access just 10 bytes in that reserved area */ + p = FindSignature_10(p, lim); + if (p >= lim) + break; + pos = (UInt32)(p - buf); + if (TestStartCrc(p)) + { + memcpy(_header, p, kHeaderSize); + _arhiveBeginStreamPosition += offset + pos; + return InStream_SeekSet(stream, _arhiveBeginStreamPosition + kHeaderSize); + } + } + + offset += processed; + memmove(buf, buf + processed, kHeaderSize); + } +} + +// S_FALSE means that file is not archive +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + HeadersSize = 0; + Close(); + RINOK(InStream_GetPos_GetSize(stream, _arhiveBeginStreamPosition, _fileEndPosition)) + RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)) + _stream = stream; + return S_OK; +} + +void CInArchive::Close() +{ + _numInByteBufs = 0; + _stream.Release(); + ThereIsHeaderError = false; +} + +void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) +{ + for (;;) + { + if (ReadID() == NID::kEnd) + break; + SkipData(); + } +} + +// CFolder &folder can be non empty. So we must set all fields + +void CInByte2::ParseFolder(CFolder &folder) +{ + const UInt32 numCoders = ReadNum(); + + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + ThrowUnsupported(); + + folder.Coders.SetSize(numCoders); + + UInt32 numInStreams = 0; + UInt32 i; + for (i = 0; i < numCoders; i++) + { + CCoderInfo &coder = folder.Coders[i]; + { + const Byte mainByte = ReadByte(); + if ((mainByte & 0xC0) != 0) + ThrowUnsupported(); + const unsigned idSize = (mainByte & 0xF); + if (idSize > 8 || idSize > GetRem()) + ThrowUnsupported(); + const Byte *longID = GetPtr(); + UInt64 id = 0; + for (unsigned j = 0; j < idSize; j++) + id = ((id << 8) | longID[j]); + SkipDataNoCheck(idSize); + coder.MethodID = id; + + if ((mainByte & 0x10) != 0) + { + coder.NumStreams = ReadNum(); + // if (coder.NumStreams > k_Scan_NumCodersStreams_in_Folder_MAX) ThrowUnsupported(); + /* numOutStreams = */ ReadNum(); + // if (ReadNum() != 1) // numOutStreams ThrowUnsupported(); + } + else + { + coder.NumStreams = 1; + } + + if ((mainByte & 0x20) != 0) + { + const CNum propsSize = ReadNum(); + coder.Props.Alloc((size_t)propsSize); + ReadBytes((Byte *)coder.Props, (size_t)propsSize); + } + else + coder.Props.Free(); + } + numInStreams += coder.NumStreams; + } + + const UInt32 numBonds = numCoders - 1; + folder.Bonds.SetSize(numBonds); + for (i = 0; i < numBonds; i++) + { + CBond &bp = folder.Bonds[i]; + bp.PackIndex = ReadNum(); + bp.UnpackIndex = ReadNum(); + } + + if (numInStreams < numBonds) + ThrowUnsupported(); + const UInt32 numPackStreams = numInStreams - numBonds; + folder.PackStreams.SetSize(numPackStreams); + + if (numPackStreams == 1) + { + for (i = 0; i < numInStreams; i++) + if (folder.FindBond_for_PackStream(i) < 0) + { + folder.PackStreams[0] = i; + break; + } + if (i == numInStreams) + ThrowUnsupported(); + } + else + for (i = 0; i < numPackStreams; i++) + folder.PackStreams[i] = ReadNum(); +} + +void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const +{ + const size_t startPos = FoCodersDataOffset[folderIndex]; + CInByte2 inByte; + inByte.Init(CodersData.ConstData() + startPos, FoCodersDataOffset[folderIndex + 1] - startPos); + inByte.ParseFolder(folder); + if (inByte.GetRem() != 0) + throw 20120424; +} + + +void CDatabase::GetPath(unsigned index, UString &path) const +{ + path.Empty(); + if (!NameOffsets || !NamesBuf) + return; + + const size_t offset = NameOffsets[index]; + const size_t size = NameOffsets[index + 1] - offset; + + if (size >= (1 << 28)) + return; + + wchar_t *s = path.GetBuf((unsigned)size - 1); + + const Byte *p = ((const Byte *)NamesBuf + offset * 2); + + #if defined(_WIN32) && defined(MY_CPU_LE) + + wmemcpy(s, (const wchar_t *)(const void *)p, size); + + #else + + for (size_t i = 0; i < size; i++) + { + *s = Get16(p); + p += 2; + s++; + } + + #endif + + path.ReleaseBuf_SetLen((unsigned)size - 1); +} + +HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() +{ + PropVariant_Clear(path); + if (!NameOffsets || !NamesBuf) + return S_OK; + + const size_t offset = NameOffsets[index]; + const size_t size = NameOffsets[index + 1] - offset; + + if (size >= (1 << 14)) + return S_OK; + + // (size) includes null terminator + + /* + #if WCHAR_MAX > 0xffff + + const Byte *p = ((const Byte *)NamesBuf + offset * 2); + size = Utf16LE__Get_Num_WCHARs(p, size - 1); + // (size) doesn't include null terminator + RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size)); + wchar_t *s = path->bstrVal; + wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, size, s); + *sEnd = 0; + if (s + size != sEnd) return E_FAIL; + + #else + */ + + RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1)) + wchar_t *s = path->bstrVal; + const Byte *p = ((const Byte *)NamesBuf + offset * 2); + // Utf16LE__To_WCHARs_Sep(p, size, s); + + for (size_t i = 0; i < size; i++) + { + wchar_t c = Get16(p); + p += 2; + #if WCHAR_PATH_SEPARATOR != L'/' + if (c == L'/') + c = WCHAR_PATH_SEPARATOR; + else if (c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme + #endif + *s++ = c; + } + + // #endif + + return S_OK; + + /* + unsigned cur = index; + unsigned size = 0; + + for (int i = 0;; i++) + { + size_t len = NameOffsets[cur + 1] - NameOffsets[cur]; + size += (unsigned)len; + if (i > 256 || len > (1 << 14) || size > (1 << 14)) + return PropVarEm_Set_Str(path, "[TOO-LONG]"); + cur = Files[cur].Parent; + if (cur < 0) + break; + } + size--; + + RINOK(PropVarEm_Alloc_Bstr(path, size)); + wchar_t *s = path->bstrVal; + s += size; + *s = 0; + cur = index; + + for (;;) + { + unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); + const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; + for (; len != 0; len--) + { + p -= 2; + --s; + wchar_t c = Get16(p); + if (c == '/') + c = WCHAR_PATH_SEPARATOR; + *s = c; + } + + const CFileItem &file = Files[cur]; + cur = file.Parent; + if (cur < 0) + return S_OK; + *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR); + } + */ +} + +void CInArchive::WaitId(UInt64 id) +{ + for (;;) + { + const UInt64 type = ReadID(); + if (type == id) + return; + if (type == NID::kEnd) + ThrowIncorrect(); + SkipData(); + } +} + + +void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v) +{ + const unsigned numItems = v.Defs.Size(); + v.Vals.ClearAndSetSize(numItems); + UInt32 *p = &v.Vals[0]; + const bool *defs = &v.Defs[0]; + for (unsigned i = 0; i < numItems; i++) + { + UInt32 a = 0; + if (defs[i]) + a = ReadUInt32(); + p[i] = a; + } +} + + +void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) +{ + ReadBoolVector2(numItems, crcs.Defs); + Read_UInt32_Vector(crcs); +} + + +void CInArchive::ReadPackInfo(CFolders &f) +{ + const CNum numPackStreams = ReadNum(); + + WaitId(NID::kSize); + f.PackPositions.Alloc(numPackStreams + 1); + f.NumPackStreams = numPackStreams; + UInt64 sum = 0; + for (CNum i = 0; i < numPackStreams; i++) + { + f.PackPositions[i] = sum; + const UInt64 packSize = ReadNumber(); + sum += packSize; + if (sum < packSize) + ThrowIncorrect(); + } + f.PackPositions[numPackStreams] = sum; + + UInt64 type; + for (;;) + { + type = ReadID(); + if (type == NID::kEnd) + return; + if (type == NID::kCRC) + { + CUInt32DefVector PackCRCs; + ReadHashDigests(numPackStreams, PackCRCs); + continue; + } + SkipData(); + } +} + +void CInArchive::ReadUnpackInfo( + const CObjectVector *dataVector, + CFolders &folders) +{ + WaitId(NID::kFolder); + const CNum numFolders = ReadNum(); + + CNum numCodersOutStreams = 0; + { + CStreamSwitch streamSwitch; + streamSwitch.Set(this, dataVector); + const Byte *startBufPtr = _inByteBack->GetPtr(); + folders.NumFolders = numFolders; + + folders.FoStartPackStreamIndex.Alloc(numFolders + 1); + folders.FoToMainUnpackSizeIndex.Alloc(numFolders); + folders.FoCodersDataOffset.Alloc(numFolders + 1); + folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); + + CBoolVector StreamUsed; + CBoolVector CoderUsed; + + CNum packStreamIndex = 0; + CNum fo; + CInByte2 *inByte = _inByteBack; + + for (fo = 0; fo < numFolders; fo++) + { + UInt32 indexOfMainStream = 0; + UInt32 numPackStreams = 0; + folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr); + + CNum numInStreams = 0; + const CNum numCoders = inByte->ReadNum(); + + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) + ThrowUnsupported(); + + for (CNum ci = 0; ci < numCoders; ci++) + { + const Byte mainByte = inByte->ReadByte(); + if ((mainByte & 0xC0) != 0) + ThrowUnsupported(); + + const unsigned idSize = (mainByte & 0xF); + if (idSize > 8) + ThrowUnsupported(); + if (idSize > inByte->GetRem()) + ThrowEndOfData(); + const Byte *longID = inByte->GetPtr(); + UInt64 id = 0; + for (unsigned j = 0; j < idSize; j++) + id = ((id << 8) | longID[j]); + inByte->SkipDataNoCheck(idSize); + if (folders.ParsedMethods.IDs.Size() < 128) + folders.ParsedMethods.IDs.AddToUniqueSorted(id); + + CNum coderInStreams = 1; + if ((mainByte & 0x10) != 0) + { + coderInStreams = inByte->ReadNum(); + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + ThrowUnsupported(); + if (inByte->ReadNum() != 1) + ThrowUnsupported(); + } + + numInStreams += coderInStreams; + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) + ThrowUnsupported(); + + if ((mainByte & 0x20) != 0) + { + const CNum propsSize = inByte->ReadNum(); + if (propsSize > inByte->GetRem()) + ThrowEndOfData(); + if (id == k_LZMA2 && propsSize == 1) + { + const Byte v = *_inByteBack->GetPtr(); + if (folders.ParsedMethods.Lzma2Prop < v) + folders.ParsedMethods.Lzma2Prop = v; + } + else if (id == k_LZMA && propsSize == 5) + { + const UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1); + if (folders.ParsedMethods.LzmaDic < dicSize) + folders.ParsedMethods.LzmaDic = dicSize; + } + inByte->SkipDataNoCheck((size_t)propsSize); + } + } + + if (numCoders == 1 && numInStreams == 1) + { + indexOfMainStream = 0; + numPackStreams = 1; + } + else + { + UInt32 i; + const CNum numBonds = numCoders - 1; + if (numInStreams < numBonds) + ThrowUnsupported(); + + BoolVector_Fill_False(StreamUsed, numInStreams); + BoolVector_Fill_False(CoderUsed, numCoders); + + for (i = 0; i < numBonds; i++) + { + CNum index = ReadNum(); + if (index >= numInStreams || StreamUsed[index]) + ThrowUnsupported(); + StreamUsed[index] = true; + + index = ReadNum(); + if (index >= numCoders || CoderUsed[index]) + ThrowUnsupported(); + CoderUsed[index] = true; + } + + numPackStreams = numInStreams - numBonds; + + if (numPackStreams != 1) + for (i = 0; i < numPackStreams; i++) + { + const CNum index = inByte->ReadNum(); // PackStreams + if (index >= numInStreams || StreamUsed[index]) + ThrowUnsupported(); + StreamUsed[index] = true; + } + + for (i = 0; i < numCoders; i++) + if (!CoderUsed[i]) + { + indexOfMainStream = i; + break; + } + + if (i == numCoders) + ThrowUnsupported(); + } + + folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; + numCodersOutStreams += numCoders; + folders.FoStartPackStreamIndex[fo] = packStreamIndex; + if (numPackStreams > folders.NumPackStreams - packStreamIndex) + ThrowIncorrect(); + packStreamIndex += numPackStreams; + folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + } + + const size_t dataSize = (size_t)(_inByteBack->GetPtr() - startBufPtr); + folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; + folders.FoStartPackStreamIndex[fo] = packStreamIndex; + folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr); + folders.CodersData.CopyFrom(startBufPtr, dataSize); + + // if (folders.NumPackStreams != packStreamIndex) ThrowUnsupported(); + } + + WaitId(NID::kCodersUnpackSize); + folders.CoderUnpackSizes.Alloc(numCodersOutStreams); + for (CNum i = 0; i < numCodersOutStreams; i++) + folders.CoderUnpackSizes[i] = ReadNumber(); + + for (;;) + { + const UInt64 type = ReadID(); + if (type == NID::kEnd) + return; + if (type == NID::kCRC) + { + ReadHashDigests(numFolders, folders.FolderCRCs); + continue; + } + SkipData(); + } +} + +void CInArchive::ReadSubStreamsInfo( + CFolders &folders, + CRecordVector &unpackSizes, + CUInt32DefVector &digests) +{ + folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); + CNum i; + for (i = 0; i < folders.NumFolders; i++) + folders.NumUnpackStreamsVector[i] = 1; + + UInt64 type; + + for (;;) + { + type = ReadID(); + if (type == NID::kNumUnpackStream) + { + for (i = 0; i < folders.NumFolders; i++) + folders.NumUnpackStreamsVector[i] = ReadNum(); + continue; + } + if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd) + break; + SkipData(); + } + + if (type == NID::kSize) + { + for (i = 0; i < folders.NumFolders; i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams == 0) + continue; + UInt64 sum = 0; + for (CNum j = 1; j < numSubstreams; j++) + { + const UInt64 size = ReadNumber(); + unpackSizes.Add(size); + sum += size; + if (sum < size) + ThrowIncorrect(); + } + const UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i); + if (folderUnpackSize < sum) + ThrowIncorrect(); + unpackSizes.Add(folderUnpackSize - sum); + } + type = ReadID(); + } + else + { + for (i = 0; i < folders.NumFolders; i++) + { + /* v9.26 - v9.29 incorrectly worked: + if (folders.NumUnpackStreamsVector[i] == 0), it threw error */ + const CNum val = folders.NumUnpackStreamsVector[i]; + if (val > 1) + ThrowIncorrect(); + if (val == 1) + unpackSizes.Add(folders.GetFolderUnpackSize(i)); + } + } + + unsigned numDigests = 0; + for (i = 0; i < folders.NumFolders; i++) + { + const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i)) + numDigests += numSubstreams; + } + + for (;;) + { + if (type == NID::kEnd) + break; + if (type == NID::kCRC) + { + // CUInt32DefVector digests2; + // ReadHashDigests(numDigests, digests2); + CBoolVector digests2; + ReadBoolVector2(numDigests, digests2); + + digests.ClearAndSetSize(unpackSizes.Size()); + + unsigned k = 0; + unsigned k2 = 0; + + for (i = 0; i < folders.NumFolders; i++) + { + const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) + { + digests.Defs[k] = true; + digests.Vals[k] = folders.FolderCRCs.Vals[i]; + k++; + } + else for (CNum j = 0; j < numSubstreams; j++) + { + bool defined = digests2[k2++]; + digests.Defs[k] = defined; + UInt32 crc = 0; + if (defined) + crc = ReadUInt32(); + digests.Vals[k] = crc; + k++; + } + } + // if (k != unpackSizes.Size()) throw 1234567; + } + else + SkipData(); + + type = ReadID(); + } + + if (digests.Defs.Size() != unpackSizes.Size()) + { + digests.ClearAndSetSize(unpackSizes.Size()); + unsigned k = 0; + for (i = 0; i < folders.NumFolders; i++) + { + const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; + if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) + { + digests.Defs[k] = true; + digests.Vals[k] = folders.FolderCRCs.Vals[i]; + k++; + } + else for (CNum j = 0; j < numSubstreams; j++) + { + digests.Defs[k] = false; + digests.Vals[k] = 0; + k++; + } + } + } +} + + + +void CInArchive::ReadStreamsInfo( + const CObjectVector *dataVector, + UInt64 &dataOffset, + CFolders &folders, + CRecordVector &unpackSizes, + CUInt32DefVector &digests) +{ + UInt64 type = ReadID(); + + if (type == NID::kPackInfo) + { + dataOffset = ReadNumber(); + if (dataOffset > _rangeLimit) + ThrowIncorrect(); + ReadPackInfo(folders); + if (folders.PackPositions[folders.NumPackStreams] > _rangeLimit - dataOffset) + ThrowIncorrect(); + type = ReadID(); + } + + if (type == NID::kUnpackInfo) + { + ReadUnpackInfo(dataVector, folders); + type = ReadID(); + } + + if (folders.NumFolders != 0 && !folders.PackPositions) + { + // if there are folders, we need PackPositions also + folders.PackPositions.Alloc(1); + folders.PackPositions[0] = 0; + } + + if (type == NID::kSubStreamsInfo) + { + ReadSubStreamsInfo(folders, unpackSizes, digests); + type = ReadID(); + } + else + { + folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); + /* If digests.Defs.Size() == 0, it means that there are no crcs. + So we don't need to fill digests with values. */ + // digests.Vals.ClearAndSetSize(folders.NumFolders); + // BoolVector_Fill_False(digests.Defs, folders.NumFolders); + for (CNum i = 0; i < folders.NumFolders; i++) + { + folders.NumUnpackStreamsVector[i] = 1; + unpackSizes.Add(folders.GetFolderUnpackSize(i)); + // digests.Vals[i] = 0; + } + } + + if (type != NID::kEnd) + ThrowIncorrect(); +} + +void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v) +{ + v.ClearAndSetSize(numItems); + Byte b = 0; + Byte mask = 0; + bool *p = &v[0]; + for (unsigned i = 0; i < numItems; i++) + { + if (mask == 0) + { + b = ReadByte(); + mask = 0x80; + } + p[i] = ((b & mask) != 0); + mask = (Byte)(mask >> 1); + } +} + +void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v) +{ + const Byte allAreDefined = ReadByte(); + if (allAreDefined == 0) + { + ReadBoolVector(numItems, v); + return; + } + v.ClearAndSetSize(numItems); + bool *p = &v[0]; + for (unsigned i = 0; i < numItems; i++) + p[i] = true; +} + +void CInArchive::ReadUInt64DefVector(const CObjectVector &dataVector, + CUInt64DefVector &v, unsigned numItems) +{ + ReadBoolVector2(numItems, v.Defs); + + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + + v.Vals.ClearAndSetSize(numItems); + UInt64 *p = &v.Vals[0]; + const bool *defs = &v.Defs[0]; + + for (unsigned i = 0; i < numItems; i++) + { + UInt64 t = 0; + if (defs[i]) + t = ReadUInt64(); + p[i] = t; + } +} + +HRESULT CInArchive::ReadAndDecodePackedStreams( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 baseOffset, + UInt64 &dataOffset, CObjectVector &dataVector + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ) +{ + CFolders folders; + CRecordVector unpackSizes; + CUInt32DefVector digests; + + ReadStreamsInfo(NULL, + dataOffset, + folders, + unpackSizes, + digests); + + CDecoder decoder(_useMixerMT); + + for (CNum i = 0; i < folders.NumFolders; i++) + { + CByteBuffer &data = dataVector.AddNew(); + const UInt64 unpackSize64 = folders.GetFolderUnpackSize(i); + const size_t unpackSize = (size_t)unpackSize64; + if (unpackSize != unpackSize64) + ThrowUnsupported(); + data.Alloc(unpackSize); + + CMyComPtr2_Create outStreamSpec; + outStreamSpec->Init(data, unpackSize); + + bool dataAfterEnd_Error = false; + + HRESULT result = decoder.Decode( + EXTERNAL_CODECS_LOC_VARS + _stream, baseOffset + dataOffset, + folders, i, + NULL, // &unpackSize64 + + outStreamSpec, + NULL, // *compressProgress + + NULL // **inStreamMainRes + , dataAfterEnd_Error + + Z7_7Z_DECODER_CRYPRO_VARS + #if !defined(Z7_ST) + , false // mtMode + , 1 // numThreads + , 0 // memUsage + #endif + ); + + RINOK(result) + + if (dataAfterEnd_Error) + ThereIsHeaderError = true; + + if (unpackSize != outStreamSpec->GetPos()) + ThrowIncorrect(); + + if (folders.FolderCRCs.ValidAndDefined(i)) + if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) + ThrowIncorrect(); + } + + if (folders.PackPositions) + HeadersSize += folders.PackPositions[folders.NumPackStreams]; + + return S_OK; +} + +HRESULT CInArchive::ReadHeader( + DECL_EXTERNAL_CODECS_LOC_VARS + CDbEx &db + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ) +{ + UInt64 type = ReadID(); + + if (type == NID::kArchiveProperties) + { + ReadArchiveProperties(db.ArcInfo); + type = ReadID(); + } + + CObjectVector dataVector; + + if (type == NID::kAdditionalStreamsInfo) + { + const HRESULT result = ReadAndDecodePackedStreams( + EXTERNAL_CODECS_LOC_VARS + db.ArcInfo.StartPositionAfterHeader, + db.ArcInfo.DataStartPosition2, + dataVector + Z7_7Z_DECODER_CRYPRO_VARS + ); + RINOK(result) + db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader; + type = ReadID(); + } + + CRecordVector unpackSizes; + CUInt32DefVector digests; + + if (type == NID::kMainStreamsInfo) + { + ReadStreamsInfo(&dataVector, + db.ArcInfo.DataStartPosition, + (CFolders &)db, + unpackSizes, + digests); + db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader; + type = ReadID(); + } + + if (type == NID::kFilesInfo) + { + + const CNum numFiles = ReadNum(); + + db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); + // if (!db.PackSizes.IsEmpty()) + db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); + if (numFiles > 0 && !digests.Defs.IsEmpty()) + db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); + + CBoolVector emptyStreamVector; + CBoolVector emptyFileVector; + CBoolVector antiFileVector; + unsigned numEmptyStreams = 0; + + for (;;) + { + const UInt64 type2 = ReadID(); + if (type2 == NID::kEnd) + break; + const UInt64 size = ReadNumber(); + if (size > _inByteBack->GetRem()) + ThrowIncorrect(); + CStreamSwitch switchProp; + switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true); + bool addPropIdToList = true; + bool isKnownType = true; + if (type2 > ((UInt32)1 << 30)) + isKnownType = false; + else switch ((UInt32)type2) + { + case NID::kName: + { + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + const size_t rem = _inByteBack->GetRem(); + db.NamesBuf.Alloc(rem); + ReadBytes(db.NamesBuf, rem); + db.NameOffsets.Alloc(numFiles + 1); + size_t pos = 0; + unsigned i; + for (i = 0; i < numFiles; i++) + { + const size_t curRem = (rem - pos) / 2; + const UInt16 *buf = (const UInt16 *)(const void *)(db.NamesBuf.ConstData() + pos); + size_t j; + for (j = 0; j < curRem && buf[j] != 0; j++); + if (j == curRem) + ThrowEndOfData(); + db.NameOffsets[i] = pos / 2; + pos += j * 2 + 2; + } + db.NameOffsets[i] = pos / 2; + if (pos != rem) + ThereIsHeaderError = true; + break; + } + + case NID::kWinAttrib: + { + ReadBoolVector2(numFiles, db.Attrib.Defs); + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + Read_UInt32_Vector(db.Attrib); + break; + } + + /* + case NID::kIsAux: + { + ReadBoolVector(numFiles, db.IsAux); + break; + } + case NID::kParent: + { + db.IsTree = true; + // CBoolVector boolVector; + // ReadBoolVector2(numFiles, boolVector); + // CStreamSwitch streamSwitch; + // streamSwitch.Set(this, &dataVector); + CBoolVector boolVector; + ReadBoolVector2(numFiles, boolVector); + + db.ThereAreAltStreams = false; + for (i = 0; i < numFiles; i++) + { + CFileItem &file = db.Files[i]; + // file.Parent = -1; + // if (boolVector[i]) + file.Parent = (int)ReadUInt32(); + file.IsAltStream = !boolVector[i]; + if (file.IsAltStream) + db.ThereAreAltStreams = true; + } + break; + } + */ + case NID::kEmptyStream: + { + ReadBoolVector(numFiles, emptyStreamVector); + numEmptyStreams = BoolVector_CountSum(emptyStreamVector); + emptyFileVector.Clear(); + antiFileVector.Clear(); + break; + } + case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; + case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; + case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break; + case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break; + case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break; + case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break; + case NID::kDummy: + { + for (UInt64 j = 0; j < size; j++) + if (ReadByte() != 0) + ThereIsHeaderError = true; + addPropIdToList = false; + break; + } + /* + case NID::kNtSecure: + { + try + { + { + CStreamSwitch streamSwitch; + streamSwitch.Set(this, &dataVector); + UInt32 numDescriptors = ReadUInt32(); + size_t offset = 0; + db.SecureOffsets.Clear(); + for (i = 0; i < numDescriptors; i++) + { + UInt32 size = ReadUInt32(); + db.SecureOffsets.Add(offset); + offset += size; + } + // ThrowIncorrect();; + db.SecureOffsets.Add(offset); + db.SecureBuf.SetCapacity(offset); + for (i = 0; i < numDescriptors; i++) + { + offset = db.SecureOffsets[i]; + ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); + } + db.SecureIDs.Clear(); + for (unsigned i = 0; i < numFiles; i++) + { + db.SecureIDs.Add(ReadNum()); + // db.SecureIDs.Add(ReadUInt32()); + } + // ReadUInt32(); + if (_inByteBack->GetRem() != 0) + ThrowIncorrect();; + } + } + catch(CInArchiveException &) + { + ThereIsHeaderError = true; + addPropIdToList = isKnownType = false; + db.ClearSecure(); + } + break; + } + */ + default: + addPropIdToList = isKnownType = false; + } + if (isKnownType) + { + if (addPropIdToList) + db.ArcInfo.FileInfoPopIDs.Add(type2); + } + else + { + db.UnsupportedFeatureWarning = true; + _inByteBack->SkipRem(); + } + // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 0.02) + if (_inByteBack->GetRem() != 0) + ThrowIncorrect(); + } + + type = ReadID(); // Read (NID::kEnd) end of headers + + if (numFiles - numEmptyStreams != unpackSizes.Size()) + ThrowUnsupported(); + + CNum emptyFileIndex = 0; + CNum sizeIndex = 0; + + const unsigned numAntiItems = BoolVector_CountSum(antiFileVector); + + if (numAntiItems != 0) + db.IsAnti.ClearAndSetSize(numFiles); + + db.Files.ClearAndSetSize(numFiles); + + for (CNum i = 0; i < numFiles; i++) + { + CFileItem &file = db.Files[i]; + bool isAnti; + file.Crc = 0; + if (!BoolVector_Item_IsValidAndTrue(emptyStreamVector, i)) + { + file.HasStream = true; + file.IsDir = false; + isAnti = false; + file.Size = unpackSizes[sizeIndex]; + file.CrcDefined = digests.ValidAndDefined(sizeIndex); + if (file.CrcDefined) + file.Crc = digests.Vals[sizeIndex]; + sizeIndex++; + } + else + { + file.HasStream = false; + file.IsDir = !BoolVector_Item_IsValidAndTrue(emptyFileVector, emptyFileIndex); + isAnti = BoolVector_Item_IsValidAndTrue(antiFileVector, emptyFileIndex); + emptyFileIndex++; + file.Size = 0; + file.CrcDefined = false; + } + if (numAntiItems != 0) + db.IsAnti[i] = isAnti; + } + + } + + db.FillLinks(); + + if (type != NID::kEnd || _inByteBack->GetRem() != 0) + { + db.UnsupportedFeatureWarning = true; + // ThrowIncorrect(); + } + + return S_OK; +} + + +void CDbEx::FillLinks() +{ + FolderStartFileIndex.Alloc(NumFolders); + FileIndexToFolderIndexMap.Alloc(Files.Size()); + + CNum folderIndex = 0; + CNum indexInFolder = 0; + unsigned i; + + for (i = 0; i < Files.Size(); i++) + { + const bool emptyStream = !Files[i].HasStream; + if (indexInFolder == 0) + { + if (emptyStream) + { + FileIndexToFolderIndexMap[i] = kNumNoIndex; + continue; + } + // v3.13 incorrectly worked with empty folders + // v4.07: we skip empty folders + for (;;) + { + if (folderIndex >= NumFolders) + ThrowIncorrect(); + FolderStartFileIndex[folderIndex] = i; + if (NumUnpackStreamsVector[folderIndex] != 0) + break; + folderIndex++; + } + } + FileIndexToFolderIndexMap[i] = folderIndex; + if (emptyStream) + continue; + if (++indexInFolder >= NumUnpackStreamsVector[folderIndex]) + { + folderIndex++; + indexInFolder = 0; + } + } + + if (indexInFolder != 0) + { + folderIndex++; + // 18.06 + ThereIsHeaderError = true; + // ThrowIncorrect(); + } + + for (;;) + { + if (folderIndex >= NumFolders) + return; + FolderStartFileIndex[folderIndex] = i; + if (NumUnpackStreamsVector[folderIndex] != 0) + { + // 18.06 + ThereIsHeaderError = true; + // ThrowIncorrect(); + } + folderIndex++; + } +} + + +HRESULT CInArchive::ReadDatabase2( + DECL_EXTERNAL_CODECS_LOC_VARS + CDbEx &db + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ) +{ + db.Clear(); + db.ArcInfo.StartPosition = _arhiveBeginStreamPosition; + + db.ArcInfo.Version.Major = _header[6]; + db.ArcInfo.Version.Minor = _header[7]; + + if (db.ArcInfo.Version.Major != kMajorVersion) + { + // db.UnsupportedVersion = true; + return S_FALSE; + } + + UInt64 nextHeaderOffset = Get64(_header + 12); + UInt64 nextHeaderSize = Get64(_header + 20); + UInt32 nextHeaderCRC = Get32(_header + 28); + + #ifdef FORMAT_7Z_RECOVERY + const UInt32 crcFromArc = Get32(_header + 8); + if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) + { + UInt64 cur, fileSize; + RINOK(InStream_GetPos(_stream, cur)) + const unsigned kCheckSize = 512; + Byte buf[kCheckSize]; + RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize)) + const UInt64 rem = fileSize - cur; + unsigned checkSize = kCheckSize; + if (rem < kCheckSize) + checkSize = (unsigned)(rem); + if (checkSize < 3) + return S_FALSE; + RINOK(InStream_SeekSet(_stream, fileSize - checkSize)) + RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)) + + if (buf[checkSize - 1] != 0) + return S_FALSE; + + unsigned i; + for (i = checkSize - 2;; i--) + { + if ((buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo) || + (buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo)) + break; + if (i == 0) + return S_FALSE; + } + nextHeaderSize = checkSize - i; + nextHeaderOffset = rem - nextHeaderSize; + nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); + RINOK(InStream_SeekSet(_stream, cur)) + db.StartHeaderWasRecovered = true; + } + else + #endif + { + // Crc was tested already at signature check + // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect(); + } + + db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; + db.PhySize = kHeaderSize; + + db.IsArc = false; + if ((Int64)nextHeaderOffset < 0 || + nextHeaderSize > ((UInt64)1 << 62)) + return S_FALSE; + + HeadersSize = kHeaderSize; + + if (nextHeaderSize == 0) + { + if (nextHeaderOffset != 0 || nextHeaderCRC != 0) + return S_FALSE; + db.IsArc = true; + db.HeadersSize = HeadersSize; + return S_OK; + } + + if (!db.StartHeaderWasRecovered) + db.IsArc = true; + + HeadersSize += nextHeaderSize; + // db.EndHeaderOffset = nextHeaderOffset; + _rangeLimit = nextHeaderOffset; + + db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; + if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize) + { + db.UnexpectedEnd = true; + return S_FALSE; + } + RINOK(_stream->Seek((Int64)nextHeaderOffset, STREAM_SEEK_CUR, NULL)) + + const size_t nextHeaderSize_t = (size_t)nextHeaderSize; + if (nextHeaderSize_t != nextHeaderSize) + return E_OUTOFMEMORY; + CByteBuffer buffer2(nextHeaderSize_t); + + RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t)) + + if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC) + ThrowIncorrect(); + + if (!db.StartHeaderWasRecovered) + db.PhySizeWasConfirmed = true; + + CStreamSwitch streamSwitch; + streamSwitch.Set(this, buffer2); + + CObjectVector dataVector; + + const UInt64 type = ReadID(); + if (type != NID::kHeader) + { + if (type != NID::kEncodedHeader) + ThrowIncorrect(); + const HRESULT result = ReadAndDecodePackedStreams( + EXTERNAL_CODECS_LOC_VARS + db.ArcInfo.StartPositionAfterHeader, + db.ArcInfo.DataStartPosition2, + dataVector + Z7_7Z_DECODER_CRYPRO_VARS + ); + RINOK(result) + if (dataVector.Size() == 0) + return S_OK; + if (dataVector.Size() > 1) + ThrowIncorrect(); + streamSwitch.Remove(); + streamSwitch.Set(this, dataVector.Front()); + if (ReadID() != NID::kHeader) + ThrowIncorrect(); + } + + db.IsArc = true; + + db.HeadersSize = HeadersSize; + + return ReadHeader( + EXTERNAL_CODECS_LOC_VARS + db + Z7_7Z_DECODER_CRYPRO_VARS + ); +} + + +HRESULT CInArchive::ReadDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + CDbEx &db + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ) +{ + try + { + const HRESULT res = ReadDatabase2( + EXTERNAL_CODECS_LOC_VARS db + Z7_7Z_DECODER_CRYPRO_VARS + ); + if (ThereIsHeaderError) + db.ThereIsHeaderError = true; + if (res == E_NOTIMPL) + ThrowUnsupported(); + return res; + } + catch(CUnsupportedFeatureException &) + { + db.UnsupportedFeatureError = true; + return S_FALSE; + } + catch(CInArchiveException &) + { + db.ThereIsHeaderError = true; + return S_FALSE; + } +} + +}} diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h index 99bb779aa..ddbe020e5 100644 --- a/CPP/7zip/Archive/7z/7zIn.h +++ b/CPP/7zip/Archive/7z/7zIn.h @@ -1,454 +1,454 @@ -// 7zIn.h - -#ifndef ZIP7_INC_7Z_IN_H -#define ZIP7_INC_7Z_IN_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../IPassword.h" -#include "../../IStream.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/InBuffer.h" - -#include "7zItem.h" - -namespace NArchive { -namespace N7z { - -/* - We don't need to init isEncrypted and passwordIsDefined - We must upgrade them only */ - -#ifdef Z7_NO_CRYPTO -#define Z7_7Z_DECODER_CRYPRO_VARS_DECL -#define Z7_7Z_DECODER_CRYPRO_VARS -#else -#define Z7_7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password -#define Z7_7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password -#endif - -struct CParsedMethods -{ - Byte Lzma2Prop; - UInt32 LzmaDic; - CRecordVector IDs; - - CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} -}; - -struct CFolderEx: public CFolder -{ - unsigned UnpackCoder; -}; - -struct CFolders -{ - CNum NumPackStreams; - CNum NumFolders; - - CObjArray PackPositions; // NumPackStreams + 1 - // CUInt32DefVector PackCRCs; // we don't use PackCRCs now - - CUInt32DefVector FolderCRCs; // NumFolders - CObjArray NumUnpackStreamsVector; // NumFolders - - CObjArray CoderUnpackSizes; // including unpack sizes of bond coders - CObjArray FoToCoderUnpackSizes; // NumFolders + 1 - CObjArray FoStartPackStreamIndex; // NumFolders + 1 - CObjArray FoToMainUnpackSizeIndex; // NumFolders - - CObjArray FoCodersDataOffset; // NumFolders + 1 - CByteBuffer CodersData; - - CParsedMethods ParsedMethods; - - void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const; - void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const - { - ParseFolderInfo(folderIndex, folder); - folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex]; - } - - unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const - { - return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]); - } - - UInt64 GetFolderUnpackSize(unsigned folderIndex) const - { - return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]]; - } - - UInt64 GetStreamPackSize(unsigned index) const - { - return PackPositions[index + 1] - PackPositions[index]; - } - - CFolders(): NumPackStreams(0), NumFolders(0) {} - - void Clear() - { - NumPackStreams = 0; - PackPositions.Free(); - // PackCRCs.Clear(); - - NumFolders = 0; - FolderCRCs.Clear(); - NumUnpackStreamsVector.Free(); - CoderUnpackSizes.Free(); - FoToCoderUnpackSizes.Free(); - FoStartPackStreamIndex.Free(); - FoToMainUnpackSizeIndex.Free(); - FoCodersDataOffset.Free(); - CodersData.Free(); - } -}; - -struct CDatabase: public CFolders -{ - CRecordVector Files; - - CUInt64DefVector CTime; - CUInt64DefVector ATime; - CUInt64DefVector MTime; - CUInt64DefVector StartPos; - CUInt32DefVector Attrib; - CBoolVector IsAnti; - /* - CBoolVector IsAux; - CByteBuffer SecureBuf; - CRecordVector SecureIDs; - */ - - CByteBuffer NamesBuf; - CObjArray NameOffsets; // numFiles + 1, offsets of utf-16 symbols - - /* - void ClearSecure() - { - SecureBuf.Free(); - SecureIDs.Clear(); - } - */ - - void Clear() - { - CFolders::Clear(); - // ClearSecure(); - - NamesBuf.Free(); - NameOffsets.Free(); - - Files.Clear(); - CTime.Clear(); - ATime.Clear(); - MTime.Clear(); - StartPos.Clear(); - Attrib.Clear(); - IsAnti.Clear(); - // IsAux.Clear(); - } - - bool IsSolid() const - { - for (CNum i = 0; i < NumFolders; i++) - if (NumUnpackStreamsVector[i] > 1) - return true; - return false; - } - bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } - // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } - - /* - const void* GetName(unsigned index) const - { - if (!NameOffsets || !NamesBuf) - return NULL; - return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2); - }; - */ - void GetPath(unsigned index, UString &path) const; - HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw(); -}; - - -struct CInArchiveInfo -{ - CArchiveVersion Version; - UInt64 StartPosition; // in stream - UInt64 StartPositionAfterHeader; // in stream - UInt64 DataStartPosition; // in stream - UInt64 DataStartPosition2; // in stream. it's for headers - CRecordVector FileInfoPopIDs; - - void Clear() - { - StartPosition = 0; - StartPositionAfterHeader = 0; - DataStartPosition = 0; - DataStartPosition2 = 0; - FileInfoPopIDs.Clear(); - } -}; - - -struct CDbEx: public CDatabase -{ - CInArchiveInfo ArcInfo; - - CObjArray FolderStartFileIndex; - CObjArray FileIndexToFolderIndexMap; - - UInt64 HeadersSize; - UInt64 PhySize; - // UInt64 EndHeaderOffset; // relative to position after StartHeader (32 bytes) - - /* - CRecordVector SecureOffsets; - bool IsTree; - bool ThereAreAltStreams; - */ - - bool IsArc; - bool PhySizeWasConfirmed; - - bool ThereIsHeaderError; - bool UnexpectedEnd; - // bool UnsupportedVersion; - - bool StartHeaderWasRecovered; - bool UnsupportedFeatureWarning; - bool UnsupportedFeatureError; - - /* - void ClearSecureEx() - { - ClearSecure(); - SecureOffsets.Clear(); - } - */ - - void Clear() - { - IsArc = false; - PhySizeWasConfirmed = false; - - ThereIsHeaderError = false; - UnexpectedEnd = false; - // UnsupportedVersion = false; - - StartHeaderWasRecovered = false; - UnsupportedFeatureError = false; - UnsupportedFeatureWarning = false; - - /* - IsTree = false; - ThereAreAltStreams = false; - */ - - CDatabase::Clear(); - - // SecureOffsets.Clear(); - ArcInfo.Clear(); - FolderStartFileIndex.Free(); - FileIndexToFolderIndexMap.Free(); - - HeadersSize = 0; - PhySize = 0; - // EndHeaderOffset = 0; - } - - bool CanUpdate() const - { - if (ThereIsHeaderError - || UnexpectedEnd - || StartHeaderWasRecovered - || UnsupportedFeatureError) - return false; - return true; - } - - void FillLinks(); - - UInt64 GetFolderStreamPos(size_t folderIndex, size_t indexInFolder) const - { - return ArcInfo.DataStartPosition + PackPositions.ConstData() - [FoStartPackStreamIndex.ConstData()[folderIndex] + indexInFolder]; - } - - UInt64 GetFolderFullPackSize(size_t folderIndex) const - { - return - PackPositions[FoStartPackStreamIndex.ConstData()[folderIndex + 1]] - - PackPositions[FoStartPackStreamIndex.ConstData()[folderIndex]]; - } - - UInt64 GetFolderPackStreamSize(size_t folderIndex, size_t streamIndex) const - { - const size_t i = FoStartPackStreamIndex.ConstData()[folderIndex] + streamIndex; - return PackPositions.ConstData()[i + 1] - - PackPositions.ConstData()[i]; - } - - /* - UInt64 GetFilePackSize(size_t fileIndex) const - { - const CNum folderIndex = FileIndexToFolderIndexMap[fileIndex]; - if (folderIndex != kNumNoIndex) - if (FolderStartFileIndex[folderIndex] == fileIndex) - return GetFolderFullPackSize(folderIndex); - return 0; - } - */ -}; - -const unsigned kNumBufLevelsMax = 4; - -struct CInByte2 -{ - const Byte *_buffer; -public: - size_t _size; - size_t _pos; - - size_t GetRem() const { return _size - _pos; } - const Byte *GetPtr() const { return _buffer + _pos; } - void Init(const Byte *buffer, size_t size) - { - _buffer = buffer; - _size = size; - _pos = 0; - } - Byte ReadByte(); - void ReadBytes(Byte *data, size_t size); - void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; } - void SkipData(UInt64 size); - - void SkipData(); - void SkipRem() { _pos = _size; } - UInt64 ReadNumber(); - CNum ReadNum(); - UInt32 ReadUInt32(); - UInt64 ReadUInt64(); - - void ParseFolder(CFolder &folder); -}; - -class CStreamSwitch; - -const UInt32 kHeaderSize = 32; - -class CInArchive -{ - friend class CStreamSwitch; - - CMyComPtr _stream; - - unsigned _numInByteBufs; - CInByte2 _inByteVector[kNumBufLevelsMax]; - - CInByte2 *_inByteBack; - bool ThereIsHeaderError; - - UInt64 _arhiveBeginStreamPosition; - UInt64 _fileEndPosition; - - UInt64 _rangeLimit; // relative to position after StartHeader (32 bytes) - - Byte _header[kHeaderSize]; - - UInt64 HeadersSize; - - bool _useMixerMT; - - void AddByteStream(const Byte *buffer, size_t size); - - void DeleteByteStream(bool needUpdatePos) - { - _numInByteBufs--; - if (_numInByteBufs > 0) - { - _inByteBack = &_inByteVector[_numInByteBufs - 1]; - if (needUpdatePos) - _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos; - } - } - - HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - - void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); } - Byte ReadByte() { return _inByteBack->ReadByte(); } - UInt64 ReadNumber() { return _inByteBack->ReadNumber(); } - CNum ReadNum() { return _inByteBack->ReadNum(); } - UInt64 ReadID() { return _inByteBack->ReadNumber(); } - UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); } - UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); } - void SkipData(UInt64 size) { _inByteBack->SkipData(size); } - void SkipData() { _inByteBack->SkipData(); } - void WaitId(UInt64 id); - - void Read_UInt32_Vector(CUInt32DefVector &v); - - void ReadArchiveProperties(CInArchiveInfo &archiveInfo); - void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs); - - void ReadPackInfo(CFolders &f); - - void ReadUnpackInfo( - const CObjectVector *dataVector, - CFolders &folders); - - void ReadSubStreamsInfo( - CFolders &folders, - CRecordVector &unpackSizes, - CUInt32DefVector &digests); - - void ReadStreamsInfo( - const CObjectVector *dataVector, - UInt64 &dataOffset, - CFolders &folders, - CRecordVector &unpackSizes, - CUInt32DefVector &digests); - - void ReadBoolVector(unsigned numItems, CBoolVector &v); - void ReadBoolVector2(unsigned numItems, CBoolVector &v); - void ReadUInt64DefVector(const CObjectVector &dataVector, - CUInt64DefVector &v, unsigned numItems); - HRESULT ReadAndDecodePackedStreams( - DECL_EXTERNAL_CODECS_LOC_VARS - UInt64 baseOffset, UInt64 &dataOffset, - CObjectVector &dataVector - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ); - HRESULT ReadHeader( - DECL_EXTERNAL_CODECS_LOC_VARS - CDbEx &db - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ); - HRESULT ReadDatabase2( - DECL_EXTERNAL_CODECS_LOC_VARS - CDbEx &db - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ); -public: - CInArchive(bool useMixerMT): - _numInByteBufs(0), - _useMixerMT(useMixerMT) - {} - - HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive - void Close(); - - HRESULT ReadDatabase( - DECL_EXTERNAL_CODECS_LOC_VARS - CDbEx &db - Z7_7Z_DECODER_CRYPRO_VARS_DECL - ); -}; - -}} - -#endif +// 7zIn.h + +#ifndef ZIP7_INC_7Z_IN_H +#define ZIP7_INC_7Z_IN_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../IPassword.h" +#include "../../IStream.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/InBuffer.h" + +#include "7zItem.h" + +namespace NArchive { +namespace N7z { + +/* + We don't need to init isEncrypted and passwordIsDefined + We must upgrade them only */ + +#ifdef Z7_NO_CRYPTO +#define Z7_7Z_DECODER_CRYPRO_VARS_DECL +#define Z7_7Z_DECODER_CRYPRO_VARS +#else +#define Z7_7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password +#define Z7_7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password +#endif + +struct CParsedMethods +{ + Byte Lzma2Prop; + UInt32 LzmaDic; + CRecordVector IDs; + + CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {} +}; + +struct CFolderEx: public CFolder +{ + unsigned UnpackCoder; +}; + +struct CFolders +{ + CNum NumPackStreams; + CNum NumFolders; + + CObjArray PackPositions; // NumPackStreams + 1 + // CUInt32DefVector PackCRCs; // we don't use PackCRCs now + + CUInt32DefVector FolderCRCs; // NumFolders + CObjArray NumUnpackStreamsVector; // NumFolders + + CObjArray CoderUnpackSizes; // including unpack sizes of bond coders + CObjArray FoToCoderUnpackSizes; // NumFolders + 1 + CObjArray FoStartPackStreamIndex; // NumFolders + 1 + CObjArray FoToMainUnpackSizeIndex; // NumFolders + + CObjArray FoCodersDataOffset; // NumFolders + 1 + CByteBuffer CodersData; + + CParsedMethods ParsedMethods; + + void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const; + void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const + { + ParseFolderInfo(folderIndex, folder); + folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex]; + } + + unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const + { + return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]); + } + + UInt64 GetFolderUnpackSize(unsigned folderIndex) const + { + return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]]; + } + + UInt64 GetStreamPackSize(unsigned index) const + { + return PackPositions[index + 1] - PackPositions[index]; + } + + CFolders(): NumPackStreams(0), NumFolders(0) {} + + void Clear() + { + NumPackStreams = 0; + PackPositions.Free(); + // PackCRCs.Clear(); + + NumFolders = 0; + FolderCRCs.Clear(); + NumUnpackStreamsVector.Free(); + CoderUnpackSizes.Free(); + FoToCoderUnpackSizes.Free(); + FoStartPackStreamIndex.Free(); + FoToMainUnpackSizeIndex.Free(); + FoCodersDataOffset.Free(); + CodersData.Free(); + } +}; + +struct CDatabase: public CFolders +{ + CRecordVector Files; + + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CUInt32DefVector Attrib; + CBoolVector IsAnti; + /* + CBoolVector IsAux; + CByteBuffer SecureBuf; + CRecordVector SecureIDs; + */ + + CByteBuffer NamesBuf; + CObjArray NameOffsets; // numFiles + 1, offsets of utf-16 symbols + + /* + void ClearSecure() + { + SecureBuf.Free(); + SecureIDs.Clear(); + } + */ + + void Clear() + { + CFolders::Clear(); + // ClearSecure(); + + NamesBuf.Free(); + NameOffsets.Free(); + + Files.Clear(); + CTime.Clear(); + ATime.Clear(); + MTime.Clear(); + StartPos.Clear(); + Attrib.Clear(); + IsAnti.Clear(); + // IsAux.Clear(); + } + + bool IsSolid() const + { + for (CNum i = 0; i < NumFolders; i++) + if (NumUnpackStreamsVector[i] > 1) + return true; + return false; + } + bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } + // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } + + /* + const void* GetName(unsigned index) const + { + if (!NameOffsets || !NamesBuf) + return NULL; + return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2); + }; + */ + void GetPath(unsigned index, UString &path) const; + HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw(); +}; + + +struct CInArchiveInfo +{ + CArchiveVersion Version; + UInt64 StartPosition; // in stream + UInt64 StartPositionAfterHeader; // in stream + UInt64 DataStartPosition; // in stream + UInt64 DataStartPosition2; // in stream. it's for headers + CRecordVector FileInfoPopIDs; + + void Clear() + { + StartPosition = 0; + StartPositionAfterHeader = 0; + DataStartPosition = 0; + DataStartPosition2 = 0; + FileInfoPopIDs.Clear(); + } +}; + + +struct CDbEx: public CDatabase +{ + CInArchiveInfo ArcInfo; + + CObjArray FolderStartFileIndex; + CObjArray FileIndexToFolderIndexMap; + + UInt64 HeadersSize; + UInt64 PhySize; + // UInt64 EndHeaderOffset; // relative to position after StartHeader (32 bytes) + + /* + CRecordVector SecureOffsets; + bool IsTree; + bool ThereAreAltStreams; + */ + + bool IsArc; + bool PhySizeWasConfirmed; + + bool ThereIsHeaderError; + bool UnexpectedEnd; + // bool UnsupportedVersion; + + bool StartHeaderWasRecovered; + bool UnsupportedFeatureWarning; + bool UnsupportedFeatureError; + + /* + void ClearSecureEx() + { + ClearSecure(); + SecureOffsets.Clear(); + } + */ + + void Clear() + { + IsArc = false; + PhySizeWasConfirmed = false; + + ThereIsHeaderError = false; + UnexpectedEnd = false; + // UnsupportedVersion = false; + + StartHeaderWasRecovered = false; + UnsupportedFeatureError = false; + UnsupportedFeatureWarning = false; + + /* + IsTree = false; + ThereAreAltStreams = false; + */ + + CDatabase::Clear(); + + // SecureOffsets.Clear(); + ArcInfo.Clear(); + FolderStartFileIndex.Free(); + FileIndexToFolderIndexMap.Free(); + + HeadersSize = 0; + PhySize = 0; + // EndHeaderOffset = 0; + } + + bool CanUpdate() const + { + if (ThereIsHeaderError + || UnexpectedEnd + || StartHeaderWasRecovered + || UnsupportedFeatureError) + return false; + return true; + } + + void FillLinks(); + + UInt64 GetFolderStreamPos(size_t folderIndex, size_t indexInFolder) const + { + return ArcInfo.DataStartPosition + PackPositions.ConstData() + [FoStartPackStreamIndex.ConstData()[folderIndex] + indexInFolder]; + } + + UInt64 GetFolderFullPackSize(size_t folderIndex) const + { + return + PackPositions[FoStartPackStreamIndex.ConstData()[folderIndex + 1]] - + PackPositions[FoStartPackStreamIndex.ConstData()[folderIndex]]; + } + + UInt64 GetFolderPackStreamSize(size_t folderIndex, size_t streamIndex) const + { + const size_t i = FoStartPackStreamIndex.ConstData()[folderIndex] + streamIndex; + return PackPositions.ConstData()[i + 1] - + PackPositions.ConstData()[i]; + } + + /* + UInt64 GetFilePackSize(size_t fileIndex) const + { + const CNum folderIndex = FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex != kNumNoIndex) + if (FolderStartFileIndex[folderIndex] == fileIndex) + return GetFolderFullPackSize(folderIndex); + return 0; + } + */ +}; + +const unsigned kNumBufLevelsMax = 4; + +struct CInByte2 +{ + const Byte *_buffer; +public: + size_t _size; + size_t _pos; + + size_t GetRem() const { return _size - _pos; } + const Byte *GetPtr() const { return _buffer + _pos; } + void Init(const Byte *buffer, size_t size) + { + _buffer = buffer; + _size = size; + _pos = 0; + } + Byte ReadByte(); + void ReadBytes(Byte *data, size_t size); + void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; } + void SkipData(UInt64 size); + + void SkipData(); + void SkipRem() { _pos = _size; } + UInt64 ReadNumber(); + CNum ReadNum(); + UInt32 ReadUInt32(); + UInt64 ReadUInt64(); + + void ParseFolder(CFolder &folder); +}; + +class CStreamSwitch; + +const UInt32 kHeaderSize = 32; + +class CInArchive +{ + friend class CStreamSwitch; + + CMyComPtr _stream; + + unsigned _numInByteBufs; + CInByte2 _inByteVector[kNumBufLevelsMax]; + + CInByte2 *_inByteBack; + bool ThereIsHeaderError; + + UInt64 _arhiveBeginStreamPosition; + UInt64 _fileEndPosition; + + UInt64 _rangeLimit; // relative to position after StartHeader (32 bytes) + + Byte _header[kHeaderSize]; + + UInt64 HeadersSize; + + bool _useMixerMT; + + void AddByteStream(const Byte *buffer, size_t size); + + void DeleteByteStream(bool needUpdatePos) + { + _numInByteBufs--; + if (_numInByteBufs > 0) + { + _inByteBack = &_inByteVector[_numInByteBufs - 1]; + if (needUpdatePos) + _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos; + } + } + + HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); + + void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); } + Byte ReadByte() { return _inByteBack->ReadByte(); } + UInt64 ReadNumber() { return _inByteBack->ReadNumber(); } + CNum ReadNum() { return _inByteBack->ReadNum(); } + UInt64 ReadID() { return _inByteBack->ReadNumber(); } + UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); } + UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); } + void SkipData(UInt64 size) { _inByteBack->SkipData(size); } + void SkipData() { _inByteBack->SkipData(); } + void WaitId(UInt64 id); + + void Read_UInt32_Vector(CUInt32DefVector &v); + + void ReadArchiveProperties(CInArchiveInfo &archiveInfo); + void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs); + + void ReadPackInfo(CFolders &f); + + void ReadUnpackInfo( + const CObjectVector *dataVector, + CFolders &folders); + + void ReadSubStreamsInfo( + CFolders &folders, + CRecordVector &unpackSizes, + CUInt32DefVector &digests); + + void ReadStreamsInfo( + const CObjectVector *dataVector, + UInt64 &dataOffset, + CFolders &folders, + CRecordVector &unpackSizes, + CUInt32DefVector &digests); + + void ReadBoolVector(unsigned numItems, CBoolVector &v); + void ReadBoolVector2(unsigned numItems, CBoolVector &v); + void ReadUInt64DefVector(const CObjectVector &dataVector, + CUInt64DefVector &v, unsigned numItems); + HRESULT ReadAndDecodePackedStreams( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 baseOffset, UInt64 &dataOffset, + CObjectVector &dataVector + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ); + HRESULT ReadHeader( + DECL_EXTERNAL_CODECS_LOC_VARS + CDbEx &db + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ); + HRESULT ReadDatabase2( + DECL_EXTERNAL_CODECS_LOC_VARS + CDbEx &db + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ); +public: + CInArchive(bool useMixerMT): + _numInByteBufs(0), + _useMixerMT(useMixerMT) + {} + + HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive + void Close(); + + HRESULT ReadDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + CDbEx &db + Z7_7Z_DECODER_CRYPRO_VARS_DECL + ); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h index 3db643a74..06737c812 100644 --- a/CPP/7zip/Archive/7z/7zItem.h +++ b/CPP/7zip/Archive/7z/7zItem.h @@ -1,207 +1,207 @@ -// 7zItem.h - -#ifndef ZIP7_INC_7Z_ITEM_H -#define ZIP7_INC_7Z_ITEM_H - -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyString.h" - -#include "../../Common/MethodId.h" - -#include "7zHeader.h" - -namespace NArchive { -namespace N7z { - -typedef UInt32 CNum; -const CNum kNumMax = 0x7FFFFFFF; -const CNum kNumNoIndex = 0xFFFFFFFF; - -struct CCoderInfo -{ - CMethodId MethodID; - CByteBuffer Props; - UInt32 NumStreams; - - bool IsSimpleCoder() const { return NumStreams == 1; } -}; - - -struct CBond -{ - UInt32 PackIndex; - UInt32 UnpackIndex; -}; - - -struct CFolder -{ - Z7_CLASS_NO_COPY(CFolder) -public: - CObjArray2 Coders; - CObjArray2 Bonds; - CObjArray2 PackStreams; - - CFolder() {} - - bool IsDecodingSupported() const { return Coders.Size() <= 32; } - - int Find_in_PackStreams(UInt32 packStream) const - { - FOR_VECTOR(i, PackStreams) - if (PackStreams[i] == packStream) - return (int)i; - return -1; - } - - int FindBond_for_PackStream(UInt32 packStream) const - { - FOR_VECTOR(i, Bonds) - if (Bonds[i].PackIndex == packStream) - return (int)i; - return -1; - } - - /* - int FindBond_for_UnpackStream(UInt32 unpackStream) const - { - FOR_VECTOR(i, Bonds) - if (Bonds[i].UnpackIndex == unpackStream) - return i; - return -1; - } - - int FindOutCoder() const - { - for (int i = (int)Coders.Size() - 1; i >= 0; i--) - if (FindBond_for_UnpackStream(i) < 0) - return i; - return -1; - } - */ - - bool IsEncrypted() const - { - FOR_VECTOR(i, Coders) - if (Coders[i].MethodID == k_AES) - return true; - return false; - } -}; - - -struct CUInt32DefVector -{ - CBoolVector Defs; - CRecordVector Vals; - - void ClearAndSetSize(unsigned newSize) - { - Defs.ClearAndSetSize(newSize); - Vals.ClearAndSetSize(newSize); - } - - void Clear() - { - Defs.Clear(); - Vals.Clear(); - } - - void ReserveDown() - { - Defs.ReserveDown(); - Vals.ReserveDown(); - } - - bool GetItem(unsigned index, UInt32 &value) const - { - if (index < Defs.Size() && Defs[index]) - { - value = Vals[index]; - return true; - } - value = 0; - return false; - } - - bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; } - - bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } - - void SetItem(unsigned index, bool defined, UInt32 value); - void if_NonEmpty_FillResidue_with_false(unsigned numItems) - { - if (Defs.Size() != 0 && Defs.Size() < numItems) - SetItem(numItems - 1, false, 0); - } -}; - - -struct CUInt64DefVector -{ - CBoolVector Defs; - CRecordVector Vals; - - void Clear() - { - Defs.Clear(); - Vals.Clear(); - } - - void ReserveDown() - { - Defs.ReserveDown(); - Vals.ReserveDown(); - } - - bool GetItem(unsigned index, UInt64 &value) const - { - if (index < Defs.Size() && Defs[index]) - { - value = Vals[index]; - return true; - } - value = 0; - return false; - } - - bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } - - void SetItem(unsigned index, bool defined, UInt64 value); -}; - - -struct CFileItem -{ - UInt64 Size; - UInt32 Crc; - /* - int Parent; - bool IsAltStream; - */ - bool HasStream; // Test it !!! it means that there is - // stream in some folder. It can be empty stream - bool IsDir; - bool CrcDefined; - - /* - void Clear() - { - HasStream = true; - IsDir = false; - CrcDefined = false; - } - - CFileItem(): - // Parent(-1), - // IsAltStream(false), - HasStream(true), - IsDir(false), - CrcDefined(false), - {} - */ -}; - -}} - -#endif +// 7zItem.h + +#ifndef ZIP7_INC_7Z_ITEM_H +#define ZIP7_INC_7Z_ITEM_H + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyString.h" + +#include "../../Common/MethodId.h" + +#include "7zHeader.h" + +namespace NArchive { +namespace N7z { + +typedef UInt32 CNum; +const CNum kNumMax = 0x7FFFFFFF; +const CNum kNumNoIndex = 0xFFFFFFFF; + +struct CCoderInfo +{ + CMethodId MethodID; + CByteBuffer Props; + UInt32 NumStreams; + + bool IsSimpleCoder() const { return NumStreams == 1; } +}; + + +struct CBond +{ + UInt32 PackIndex; + UInt32 UnpackIndex; +}; + + +struct CFolder +{ + Z7_CLASS_NO_COPY(CFolder) +public: + CObjArray2 Coders; + CObjArray2 Bonds; + CObjArray2 PackStreams; + + CFolder() {} + + bool IsDecodingSupported() const { return Coders.Size() <= 32; } + + int Find_in_PackStreams(UInt32 packStream) const + { + FOR_VECTOR(i, PackStreams) + if (PackStreams[i] == packStream) + return (int)i; + return -1; + } + + int FindBond_for_PackStream(UInt32 packStream) const + { + FOR_VECTOR(i, Bonds) + if (Bonds[i].PackIndex == packStream) + return (int)i; + return -1; + } + + /* + int FindBond_for_UnpackStream(UInt32 unpackStream) const + { + FOR_VECTOR(i, Bonds) + if (Bonds[i].UnpackIndex == unpackStream) + return i; + return -1; + } + + int FindOutCoder() const + { + for (int i = (int)Coders.Size() - 1; i >= 0; i--) + if (FindBond_for_UnpackStream(i) < 0) + return i; + return -1; + } + */ + + bool IsEncrypted() const + { + FOR_VECTOR(i, Coders) + if (Coders[i].MethodID == k_AES) + return true; + return false; + } +}; + + +struct CUInt32DefVector +{ + CBoolVector Defs; + CRecordVector Vals; + + void ClearAndSetSize(unsigned newSize) + { + Defs.ClearAndSetSize(newSize); + Vals.ClearAndSetSize(newSize); + } + + void Clear() + { + Defs.Clear(); + Vals.Clear(); + } + + void ReserveDown() + { + Defs.ReserveDown(); + Vals.ReserveDown(); + } + + bool GetItem(unsigned index, UInt32 &value) const + { + if (index < Defs.Size() && Defs[index]) + { + value = Vals[index]; + return true; + } + value = 0; + return false; + } + + bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; } + + bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } + + void SetItem(unsigned index, bool defined, UInt32 value); + void if_NonEmpty_FillResidue_with_false(unsigned numItems) + { + if (Defs.Size() != 0 && Defs.Size() < numItems) + SetItem(numItems - 1, false, 0); + } +}; + + +struct CUInt64DefVector +{ + CBoolVector Defs; + CRecordVector Vals; + + void Clear() + { + Defs.Clear(); + Vals.Clear(); + } + + void ReserveDown() + { + Defs.ReserveDown(); + Vals.ReserveDown(); + } + + bool GetItem(unsigned index, UInt64 &value) const + { + if (index < Defs.Size() && Defs[index]) + { + value = Vals[index]; + return true; + } + value = 0; + return false; + } + + bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; } + + void SetItem(unsigned index, bool defined, UInt64 value); +}; + + +struct CFileItem +{ + UInt64 Size; + UInt32 Crc; + /* + int Parent; + bool IsAltStream; + */ + bool HasStream; // Test it !!! it means that there is + // stream in some folder. It can be empty stream + bool IsDir; + bool CrcDefined; + + /* + void Clear() + { + HasStream = true; + IsDir = false; + CrcDefined = false; + } + + CFileItem(): + // Parent(-1), + // IsAltStream(false), + HasStream(true), + IsDir(false), + CrcDefined(false), + {} + */ +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp index 463eb48ac..d0c8cf293 100644 --- a/CPP/7zip/Archive/7z/7zOut.cpp +++ b/CPP/7zip/Archive/7z/7zOut.cpp @@ -1,1026 +1,1026 @@ -// 7zOut.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/AutoPtr.h" -// #include "../../../Common/UTFConvert.h" - -#include "../../Common/StreamObjects.h" -#include "../Common/OutStreamWithCRC.h" - -#include "7zOut.h" - -unsigned BoolVector_CountSum(const CBoolVector &v); - -static UInt64 UInt64Vector_CountSum(const CRecordVector &v) -{ - UInt64 sum = 0; - const unsigned size = v.Size(); - if (size) - { - const UInt64 *p = v.ConstData(); - const UInt64 * const lim = p + size; - do - sum += *p++; - while (p != lim); - } - return sum; -} - - -namespace NArchive { -namespace N7z { - -static void FillSignature(Byte *buf) -{ - memcpy(buf, kSignature, kSignatureSize); - buf[kSignatureSize] = kMajorVersion; - buf[kSignatureSize + 1] = 4; -} - -#ifdef Z7_7Z_VOL -HRESULT COutArchive::WriteFinishSignature() -{ - RINOK(WriteDirect(kFinishSignature, kSignatureSize)); - CArchiveVersion av; - av.Major = kMajorVersion; - av.Minor = 2; - RINOK(WriteDirectByte(av.Major)); - return WriteDirectByte(av.Minor); -} -#endif - -static void SetUInt32(Byte *p, UInt32 d) -{ - for (int i = 0; i < 4; i++, d >>= 8) - p[i] = (Byte)d; -} - -static void SetUInt64(Byte *p, UInt64 d) -{ - for (int i = 0; i < 8; i++, d >>= 8) - p[i] = (Byte)d; -} - -HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) -{ - Byte buf[32]; - FillSignature(buf); - SetUInt64(buf + 8 + 4, h.NextHeaderOffset); - SetUInt64(buf + 8 + 12, h.NextHeaderSize); - SetUInt32(buf + 8 + 20, h.NextHeaderCRC); - SetUInt32(buf + 8, CrcCalc(buf + 8 + 4, 20)); - return WriteDirect(buf, sizeof(buf)); -} - -#ifdef Z7_7Z_VOL -HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h) -{ - CCRC crc; - crc.UpdateUInt64(h.NextHeaderOffset); - crc.UpdateUInt64(h.NextHeaderSize); - crc.UpdateUInt32(h.NextHeaderCRC); - crc.UpdateUInt64(h.ArchiveStartOffset); - crc.UpdateUInt64(h.AdditionalStartBlockSize); - RINOK(WriteDirectUInt32(crc.GetDigest())); - RINOK(WriteDirectUInt64(h.NextHeaderOffset)); - RINOK(WriteDirectUInt64(h.NextHeaderSize)); - RINOK(WriteDirectUInt32(h.NextHeaderCRC)); - RINOK(WriteDirectUInt64(h.ArchiveStartOffset)); - return WriteDirectUInt64(h.AdditionalStartBlockSize); -} -#endif - -HRESULT COutArchive::Create_and_WriteStartPrefix(ISequentialOutStream *stream /* , bool endMarker */) -{ - Close(); - #ifdef Z7_7Z_VOL - // endMarker = false; - _endMarker = endMarker; - #endif - SeqStream = stream; - // if (!endMarker) - { - SeqStream.QueryInterface(IID_IOutStream, &Stream); - if (!Stream) - { - return E_NOTIMPL; - // endMarker = true; - } - RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_signatureHeaderPos)) - Byte buf[32]; - FillSignature(buf); - memset(&buf[8], 0, 32 - 8); - return WriteDirect(buf, sizeof(buf)); - } - #ifdef Z7_7Z_VOL - if (endMarker) - { - /* - CStartHeader sh; - sh.NextHeaderOffset = (UInt32)(Int32)-1; - sh.NextHeaderSize = (UInt32)(Int32)-1; - sh.NextHeaderCRC = 0; - WriteStartHeader(sh); - return S_OK; - */ - } - #endif -} - -void COutArchive::Close() -{ - SeqStream.Release(); - Stream.Release(); -} - -UInt64 COutArchive::GetPos() const -{ - if (_countMode) - return _countSize; - if (_writeToStream) - return _outByte.GetProcessedSize(); - return _outByte2.GetPos(); -} - -void COutArchive::WriteBytes(const void *data, size_t size) -{ - if (_countMode) - _countSize += size; - else if (_writeToStream) - { - _outByte.WriteBytes(data, size); - // _crc = CrcUpdate(_crc, data, size); - } - else - _outByte2.WriteBytes(data, size); -} - -void COutArchive::WriteByte(Byte b) -{ - if (_countMode) - _countSize++; - else if (_writeToStream) - WriteByte_ToStream(b); - else - _outByte2.WriteByte(b); -} - -/* -void COutArchive::WriteUInt32(UInt32 value) -{ - for (int i = 0; i < 4; i++) - { - WriteByte((Byte)value); - value >>= 8; - } -} - -void COutArchive::WriteUInt64(UInt64 value) -{ - for (int i = 0; i < 8; i++) - { - WriteByte((Byte)value); - value >>= 8; - } -} -*/ - -void COutArchive::WriteNumber(UInt64 value) -{ - Byte firstByte = 0; - Byte mask = 0x80; - int i; - for (i = 0; i < 8; i++) - { - if (value < ((UInt64(1) << ( 7 * (i + 1))))) - { - firstByte |= Byte(value >> (8 * i)); - break; - } - firstByte |= mask; - mask = (Byte)(mask >> 1); - } - WriteByte(firstByte); - for (; i > 0; i--) - { - WriteByte((Byte)value); - value >>= 8; - } -} - -static unsigned GetBigNumberSize(UInt64 value) -{ - unsigned i; - for (i = 1; i < 9; i++) - if (value < (((UInt64)1 << (i * 7)))) - break; - return i; -} - -#ifdef Z7_7Z_VOL -UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props) -{ - UInt32 result = GetBigNumberSize(dataSize) * 2 + 41; - if (nameLength != 0) - { - nameLength = (nameLength + 1) * 2; - result += nameLength + GetBigNumberSize(nameLength) + 2; - } - if (props) - { - result += 20; - } - if (result >= 128) - result++; - result += kSignatureSize + 2 + kFinishHeaderSize; - return result; -} - -UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) -{ - UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props); - int testSize; - if (volSize > headersSizeBase) - testSize = volSize - headersSizeBase; - else - testSize = 1; - UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props); - UInt64 pureSize = 1; - if (volSize > headersSize) - pureSize = volSize - headersSize; - return pureSize; -} -#endif - -void COutArchive::WriteFolder(const CFolder &folder) -{ - WriteNumber(folder.Coders.Size()); - unsigned i; - - for (i = 0; i < folder.Coders.Size(); i++) - { - const CCoderInfo &coder = folder.Coders[i]; - { - UInt64 id = coder.MethodID; - unsigned idSize; - for (idSize = 1; idSize < sizeof(id); idSize++) - if ((id >> (8 * idSize)) == 0) - break; - // idSize &= 0xF; // idSize is smaller than 16 already - Byte temp[16]; - for (unsigned t = idSize; t != 0; t--, id >>= 8) - temp[t] = (Byte)(id & 0xFF); - - unsigned b = idSize; - const bool isComplex = !coder.IsSimpleCoder(); - b |= (isComplex ? 0x10 : 0); - - const size_t propsSize = coder.Props.Size(); - b |= ((propsSize != 0) ? 0x20 : 0); - temp[0] = (Byte)b; - WriteBytes(temp, idSize + 1); - if (isComplex) - { - WriteNumber(coder.NumStreams); - WriteNumber(1); // NumOutStreams; - } - if (propsSize == 0) - continue; - WriteNumber(propsSize); - WriteBytes(coder.Props, propsSize); - } - } - - for (i = 0; i < folder.Bonds.Size(); i++) - { - const CBond &bond = folder.Bonds[i]; - WriteNumber(bond.PackIndex); - WriteNumber(bond.UnpackIndex); - } - - if (folder.PackStreams.Size() > 1) - for (i = 0; i < folder.PackStreams.Size(); i++) - WriteNumber(folder.PackStreams[i]); -} - -void COutArchive::Write_BoolVector(const CBoolVector &boolVector) -{ - Byte b = 0; - Byte mask = 0x80; - FOR_VECTOR (i, boolVector) - { - if (boolVector[i]) - b |= mask; - mask = (Byte)(mask >> 1); - if (mask == 0) - { - WriteByte(b); - mask = 0x80; - b = 0; - } - } - if (mask != 0x80) - WriteByte(b); -} - -static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } - -void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector) -{ - WriteByte(id); - WriteNumber(Bv_GetSizeInBytes(boolVector)); - Write_BoolVector(boolVector); -} - -void COutArchive::Write_BoolVector_numDefined(const CBoolVector &boolVector, unsigned numDefined) -{ - if (numDefined == boolVector.Size()) - WriteByte(1); - else - { - WriteByte(0); - Write_BoolVector(boolVector); - } -} - - -void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) -{ - const unsigned numDefined = BoolVector_CountSum(digests.Defs); - if (numDefined == 0) - return; - WriteByte(NID::kCRC); - Write_BoolVector_numDefined(digests.Defs, numDefined); - Write_UInt32DefVector_numDefined(digests, numDefined); -} - - -void COutArchive::WritePackInfo( - UInt64 dataOffset, - const CRecordVector &packSizes, - const CUInt32DefVector &packCRCs) -{ - if (packSizes.IsEmpty()) - return; - WriteByte(NID::kPackInfo); - WriteNumber(dataOffset); - WriteNumber(packSizes.Size()); - WriteByte(NID::kSize); - FOR_VECTOR (i, packSizes) - WriteNumber(packSizes[i]); - - WriteHashDigests(packCRCs); - - WriteByte(NID::kEnd); -} - -void COutArchive::WriteUnpackInfo(const CObjectVector &folders, const COutFolders &outFolders) -{ - if (folders.IsEmpty()) - return; - - WriteByte(NID::kUnpackInfo); - - WriteByte(NID::kFolder); - WriteNumber(folders.Size()); - { - WriteByte(0); - FOR_VECTOR (i, folders) - WriteFolder(folders[i]); - } - - WriteByte(NID::kCodersUnpackSize); - FOR_VECTOR (i, outFolders.CoderUnpackSizes) - WriteNumber(outFolders.CoderUnpackSizes[i]); - - WriteHashDigests(outFolders.FolderUnpackCRCs); - - WriteByte(NID::kEnd); -} - -void COutArchive::WriteSubStreamsInfo(const CObjectVector &folders, - const COutFolders &outFolders, - const CRecordVector &unpackSizes, - const CUInt32DefVector &digests) -{ - const CRecordVector &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector; - WriteByte(NID::kSubStreamsInfo); - - unsigned i; - for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) - if (numUnpackStreamsInFolders[i] != 1) - { - WriteByte(NID::kNumUnpackStream); - for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) - WriteNumber(numUnpackStreamsInFolders[i]); - break; - } - - for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) - if (numUnpackStreamsInFolders[i] > 1) - { - WriteByte(NID::kSize); - CNum index = 0; - for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) - { - CNum num = numUnpackStreamsInFolders[i]; - for (CNum j = 0; j < num; j++) - { - if (j + 1 != num) - WriteNumber(unpackSizes[index]); - index++; - } - } - break; - } - - CUInt32DefVector digests2; - - unsigned digestIndex = 0; - for (i = 0; i < folders.Size(); i++) - { - unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i]; - if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i)) - digestIndex++; - else - for (unsigned j = 0; j < numSubStreams; j++, digestIndex++) - { - digests2.Defs.Add(digests.Defs[digestIndex]); - digests2.Vals.Add(digests.Vals[digestIndex]); - } - } - WriteHashDigests(digests2); - WriteByte(NID::kEnd); -} - -// 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. - -void COutArchive::SkipToAligned(unsigned pos, unsigned alignShifts) -{ - if (!_useAlign) - return; - - const unsigned alignSize = (unsigned)1 << alignShifts; - pos += (unsigned)GetPos(); - pos &= (alignSize - 1); - if (pos == 0) - return; - unsigned skip = alignSize - pos; - if (skip < 2) - skip += alignSize; - skip -= 2; - WriteByte(NID::kDummy); - WriteByte((Byte)skip); - for (unsigned i = 0; i < skip; i++) - WriteByte(0); -} - -void COutArchive::WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts) -{ - const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); - const UInt64 dataSize = ((UInt64)numDefined << itemSizeShifts) + bvSize + 2; - SkipToAligned(3 + bvSize + GetBigNumberSize(dataSize), itemSizeShifts); - - WriteByte(type); - WriteNumber(dataSize); - Write_BoolVector_numDefined(v, numDefined); - WriteByte(0); // 0 means no switching to external stream -} - - -void COutArchive::Write_UInt32DefVector_numDefined(const CUInt32DefVector &v, unsigned numDefined) -{ - if (_countMode) - { - _countSize += (size_t)numDefined * 4; - return; - } - - const bool * const defs = v.Defs.ConstData(); - const UInt32 * const vals = v.Vals.ConstData(); - const size_t num = v.Defs.Size(); - - for (size_t i = 0; i < num; i++) - if (defs[i]) - { - UInt32 value = vals[i]; - for (int k = 0; k < 4; k++) - { - if (_writeToStream) - WriteByte_ToStream((Byte)value); - else - _outByte2.WriteByte((Byte)value); - // WriteByte((Byte)value); - value >>= 8; - } - // WriteUInt32(v.Vals[i]); - } -} - - -void COutArchive::Write_UInt64DefVector_type(const CUInt64DefVector &v, Byte type) -{ - const unsigned numDefined = BoolVector_CountSum(v.Defs); - if (numDefined == 0) - return; - - WriteAlignedBools(v.Defs, numDefined, type, 3); - - if (_countMode) - { - _countSize += (size_t)numDefined * 8; - return; - } - - const bool * const defs = v.Defs.ConstData(); - const UInt64 * const vals = v.Vals.ConstData(); - const size_t num = v.Defs.Size(); - - for (size_t i = 0; i < num; i++) - if (defs[i]) - { - UInt64 value = vals[i]; - for (int k = 0; k < 8; k++) - { - if (_writeToStream) - WriteByte_ToStream((Byte)value); - else - _outByte2.WriteByte((Byte)value); - // WriteByte((Byte)value); - value >>= 8; - } - // WriteUInt64(v.Vals[i]); - } -} - - -HRESULT COutArchive::EncodeStream( - DECL_EXTERNAL_CODECS_LOC_VARS - CEncoder &encoder, const CByteBuffer &data, - CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders) -{ - CMyComPtr2_Create streamSpec; - streamSpec->Init(data, data.Size()); - outFolders.FolderUnpackCRCs.Defs.Add(true); - outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size())); - // outFolders.NumUnpackStreamsVector.Add(1); - const UInt64 dataSize64 = data.Size(); - const UInt64 expectSize = data.Size(); - RINOK(encoder.Encode1( - EXTERNAL_CODECS_LOC_VARS - streamSpec, - // NULL, - &dataSize64, // inSizeForReduce - expectSize, - folders.AddNew(), - // outFolders.CoderUnpackSizes, unpackSize, - SeqStream, packSizes, NULL)) - if (!streamSpec->WasFinished()) - return E_FAIL; - encoder.Encode_Post(dataSize64, outFolders.CoderUnpackSizes); - return S_OK; -} - -void COutArchive::WriteHeader( - const CArchiveDatabaseOut &db, - // const CHeaderOptions &headerOptions, - UInt64 &headerOffset) -{ - /* - bool thereIsSecure = (db.SecureBuf.Size() != 0); - */ - _useAlign = true; - - headerOffset = UInt64Vector_CountSum(db.PackSizes); - - WriteByte(NID::kHeader); - - /* - { - // It's example for per archive properies writing - - WriteByte(NID::kArchiveProperties); - - // you must use random 40-bit number that will identify you - // then you can use same kDeveloperID for any properties and methods - const UInt64 kDeveloperID = 0x123456789A; // change that value to real random 40-bit number - - #define GENERATE_7Z_ID(developerID, subID) (((UInt64)0x3F << 56) | ((UInt64)developerID << 16) | subID) - - { - const UInt64 kSubID = 0x1; // you can use small number for subID - const UInt64 kID = GENERATE_7Z_ID(kDeveloperID, kSubID); - WriteNumber(kID); - const unsigned kPropsSize = 3; // it's example size - WriteNumber(kPropsSize); - for (unsigned i = 0; i < kPropsSize; i++) - WriteByte((Byte)(i & 0xFF)); - } - { - const UInt64 kSubID = 0x2; // you can use small number for subID - const UInt64 kID = GENERATE_7Z_ID(kDeveloperID, kSubID); - WriteNumber(kID); - const unsigned kPropsSize = 5; // it's example size - WriteNumber(kPropsSize); - for (unsigned i = 0; i < kPropsSize; i++) - WriteByte((Byte)(i + 16)); - } - WriteByte(NID::kEnd); - } - */ - - if (db.Folders.Size() > 0) - { - WriteByte(NID::kMainStreamsInfo); - WritePackInfo(0, db.PackSizes, db.PackCRCs); - WriteUnpackInfo(db.Folders, (const COutFolders &)db); - - CRecordVector unpackSizes; - CUInt32DefVector digests; - FOR_VECTOR (i, db.Files) - { - const CFileItem &file = db.Files[i]; - if (!file.HasStream) - continue; - unpackSizes.Add(file.Size); - digests.Defs.Add(file.CrcDefined); - digests.Vals.Add(file.Crc); - } - - WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests); - WriteByte(NID::kEnd); - } - - if (db.Files.IsEmpty()) - { - WriteByte(NID::kEnd); - return; - } - - WriteByte(NID::kFilesInfo); - WriteNumber(db.Files.Size()); - - { - /* ---------- Empty Streams ---------- */ - CBoolVector emptyStreamVector; - emptyStreamVector.ClearAndSetSize(db.Files.Size()); - unsigned numEmptyStreams = 0; - { - FOR_VECTOR (i, db.Files) - if (db.Files[i].HasStream) - emptyStreamVector[i] = false; - else - { - emptyStreamVector[i] = true; - numEmptyStreams++; - } - } - - if (numEmptyStreams != 0) - { - WritePropBoolVector(NID::kEmptyStream, emptyStreamVector); - - CBoolVector emptyFileVector, antiVector; - emptyFileVector.ClearAndSetSize(numEmptyStreams); - antiVector.ClearAndSetSize(numEmptyStreams); - bool thereAreEmptyFiles = false, thereAreAntiItems = false; - unsigned cur = 0; - - FOR_VECTOR (i, db.Files) - { - const CFileItem &file = db.Files[i]; - if (file.HasStream) - continue; - emptyFileVector[cur] = !file.IsDir; - if (!file.IsDir) - thereAreEmptyFiles = true; - bool isAnti = db.IsItemAnti(i); - antiVector[cur] = isAnti; - if (isAnti) - thereAreAntiItems = true; - cur++; - } - - if (thereAreEmptyFiles) - WritePropBoolVector(NID::kEmptyFile, emptyFileVector); - if (thereAreAntiItems) - WritePropBoolVector(NID::kAnti, antiVector); - } - } - - - { - /* ---------- Names ---------- */ - - size_t namesDataSize = 0; - { - FOR_VECTOR (i, db.Files) - { - const UString &name = db.Names[i]; - const size_t numUtfChars = - /* - #if WCHAR_MAX > 0xffff - Get_Num_Utf16_chars_from_wchar_string(name.Ptr()); - #else - */ - name.Len(); - // #endif - namesDataSize += numUtfChars; - } - } - if (namesDataSize) - { - namesDataSize += db.Files.Size(); // we will write tail zero wchar for each name - namesDataSize *= 2; // 2 bytes per wchar for UTF16 encoding - namesDataSize++; // for additional switch byte (zero value) - SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4); - WriteByte(NID::kName); - WriteNumber(namesDataSize); - - if (_countMode) - _countSize += namesDataSize; - else - { - WriteByte(0); - FOR_VECTOR (i, db.Files) - { - const UString &name = db.Names[i]; - const wchar_t *p = name.Ptr(); - const size_t len = (size_t)name.Len() + 1; - const wchar_t * const lim = p + len; - if (_writeToStream) - { - do - { - const wchar_t c = *p++; - WriteByte_ToStream((Byte)c); - WriteByte_ToStream((Byte)(c >> 8)); - } - while (p != lim); - } - else - { - Byte *dest = _outByte2.GetDest_and_Update(len * 2); - do - { - /* - #if WCHAR_MAX > 0xffff - if (c >= 0x10000) - { - c -= 0x10000; - if (c < (1 << 20)) - { - unsigned c0 = 0xd800 + ((c >> 10) & 0x3FF); - WriteByte((Byte)c0); - WriteByte((Byte)(c0 >> 8)); - c = 0xdc00 + (c & 0x3FF); - } - else - c = '_'; // we change character unsupported by UTF16 - } - #endif - */ - const wchar_t c = *p++; - SetUi16(dest, (UInt16)c) - dest += 2; - } - while (p != lim); - } - } - } - } - } - - /* if (headerOptions.WriteCTime) */ Write_UInt64DefVector_type(db.CTime, NID::kCTime); - /* if (headerOptions.WriteATime) */ Write_UInt64DefVector_type(db.ATime, NID::kATime); - /* if (headerOptions.WriteMTime) */ Write_UInt64DefVector_type(db.MTime, NID::kMTime); - Write_UInt64DefVector_type(db.StartPos, NID::kStartPos); - - { - /* ---------- Write Attrib ---------- */ - const unsigned numDefined = BoolVector_CountSum(db.Attrib.Defs); - if (numDefined != 0) - { - WriteAlignedBools(db.Attrib.Defs, numDefined, NID::kWinAttrib, 2); - Write_UInt32DefVector_numDefined(db.Attrib, numDefined); - } - } - - /* - { - // ---------- Write IsAux ---------- - if (BoolVector_CountSum(db.IsAux) != 0) - WritePropBoolVector(NID::kIsAux, db.IsAux); - } - - { - // ---------- Write Parent ---------- - CBoolVector boolVector; - boolVector.Reserve(db.Files.Size()); - unsigned numIsDir = 0; - unsigned numParentLinks = 0; - for (i = 0; i < db.Files.Size(); i++) - { - const CFileItem &file = db.Files[i]; - bool defined = !file.IsAltStream; - boolVector.Add(defined); - if (defined) - numIsDir++; - if (file.Parent >= 0) - numParentLinks++; - } - if (numParentLinks > 0) - { - // WriteAlignedBools(boolVector, numDefined, NID::kParent, 2); - const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector); - const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1; - SkipToAligned(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 2); - - WriteByte(NID::kParent); - WriteNumber(dataSize); - Write_BoolVector_numDefined(boolVector, numIsDir); - for (i = 0; i < db.Files.Size(); i++) - { - const CFileItem &file = db.Files[i]; - // if (file.Parent >= 0) - WriteUInt32(file.Parent); - } - } - } - - if (thereIsSecure) - { - UInt64 secureDataSize = 1 + 4 + - db.SecureBuf.Size() + - db.SecureSizes.Size() * 4; - // secureDataSize += db.SecureIDs.Size() * 4; - for (i = 0; i < db.SecureIDs.Size(); i++) - secureDataSize += GetBigNumberSize(db.SecureIDs[i]); - SkipToAligned(2 + GetBigNumberSize(secureDataSize), 2); - WriteByte(NID::kNtSecure); - WriteNumber(secureDataSize); - WriteByte(0); - WriteUInt32(db.SecureSizes.Size()); - for (i = 0; i < db.SecureSizes.Size(); i++) - WriteUInt32(db.SecureSizes[i]); - WriteBytes(db.SecureBuf, db.SecureBuf.Size()); - for (i = 0; i < db.SecureIDs.Size(); i++) - { - WriteNumber(db.SecureIDs[i]); - // WriteUInt32(db.SecureIDs[i]); - } - } - */ - - WriteByte(NID::kEnd); // for files - WriteByte(NID::kEnd); // for headers -} - -HRESULT COutArchive::WriteDatabase( - DECL_EXTERNAL_CODECS_LOC_VARS - const CArchiveDatabaseOut &db, - const CCompressionMethodMode *options, - const CHeaderOptions &headerOptions) -{ - if (!db.CheckNumFiles()) - return E_FAIL; - - CStartHeader sh; - sh.NextHeaderOffset = 0; - sh.NextHeaderSize = 0; - sh.NextHeaderCRC = 0; // CrcCalc(NULL, 0); - - if (!db.IsEmpty()) - { - CMyComPtr2_Create crcStream; - crcStream->SetStream(SeqStream); - crcStream->Init(); - - bool encodeHeaders = false; - if (options) - if (options->IsEmpty()) - options = NULL; - if (options) - if (options->PasswordIsDefined || headerOptions.CompressMainHeader) - encodeHeaders = true; - - if (!_outByte.Create(1 << 16)) - return E_OUTOFMEMORY; - _outByte.SetStream(crcStream.Interface()); - _outByte.Init(); - // _crc = CRC_INIT_VAL; - _countMode = encodeHeaders; - _writeToStream = true; - _countSize = 0; - WriteHeader(db, /* headerOptions, */ sh.NextHeaderOffset); - - if (encodeHeaders) - { - CByteBuffer buf(_countSize); - _outByte2.Init((Byte *)buf, _countSize); - - _countMode = false; - _writeToStream = false; - WriteHeader(db, /* headerOptions, */ sh.NextHeaderOffset); - - if (_countSize != _outByte2.GetPos()) - return E_FAIL; - - CCompressionMethodMode encryptOptions; - encryptOptions.PasswordIsDefined = options->PasswordIsDefined; - encryptOptions.Password = options->Password; - CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); - CRecordVector packSizes; - CObjectVector folders; - COutFolders outFolders; - - RINOK(EncodeStream( - EXTERNAL_CODECS_LOC_VARS - encoder, buf, - packSizes, folders, outFolders)) - - _writeToStream = true; - - if (folders.Size() == 0) - throw 1; - - WriteID(NID::kEncodedHeader); - WritePackInfo(sh.NextHeaderOffset, packSizes, CUInt32DefVector()); - WriteUnpackInfo(folders, outFolders); - WriteByte(NID::kEnd); - - sh.NextHeaderOffset += UInt64Vector_CountSum(packSizes); - } - RINOK(_outByte.Flush()) - sh.NextHeaderCRC = crcStream->GetCRC(); - // sh.NextHeaderCRC = CRC_GET_DIGEST(_crc); - // if (CRC_GET_DIGEST(_crc) != sh.NextHeaderCRC) throw 1; - sh.NextHeaderSize = _outByte.GetProcessedSize(); - } - #ifdef Z7_7Z_VOL - if (_endMarker) - { - CFinishHeader h; - h.NextHeaderSize = headerSize; - h.NextHeaderCRC = headerCRC; - h.NextHeaderOffset = - UInt64(0) - (headerSize + - 4 + kFinishHeaderSize); - h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset; - h.AdditionalStartBlockSize = 0; - RINOK(WriteFinishHeader(h)); - return WriteFinishSignature(); - } - else - #endif - if (Stream) - { - RINOK(Stream->Seek((Int64)_signatureHeaderPos, STREAM_SEEK_SET, NULL)) - return WriteStartHeader(sh); - } - return S_OK; -} - -void CUInt32DefVector::SetItem(unsigned index, bool defined, UInt32 value) -{ - while (index >= Defs.Size()) - Defs.Add(false); - Defs[index] = defined; - if (!defined) - return; - while (index >= Vals.Size()) - Vals.Add(0); - Vals[index] = value; -} - -void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value) -{ - while (index >= Defs.Size()) - Defs.Add(false); - Defs[index] = defined; - if (!defined) - return; - while (index >= Vals.Size()) - Vals.Add(0); - Vals[index] = value; -} - -void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name) -{ - unsigned index = Files.Size(); - CTime.SetItem(index, file2.CTimeDefined, file2.CTime); - ATime.SetItem(index, file2.ATimeDefined, file2.ATime); - MTime.SetItem(index, file2.MTimeDefined, file2.MTime); - StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); - Attrib.SetItem(index, file2.AttribDefined, file2.Attrib); - SetItem_Anti(index, file2.IsAnti); - // SetItem_Aux(index, file2.IsAux); - Names.Add(name); - Files.Add(file); -} - -}} +// 7zOut.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/AutoPtr.h" +// #include "../../../Common/UTFConvert.h" + +#include "../../Common/StreamObjects.h" +#include "../Common/OutStreamWithCRC.h" + +#include "7zOut.h" + +unsigned BoolVector_CountSum(const CBoolVector &v); + +static UInt64 UInt64Vector_CountSum(const CRecordVector &v) +{ + UInt64 sum = 0; + const unsigned size = v.Size(); + if (size) + { + const UInt64 *p = v.ConstData(); + const UInt64 * const lim = p + size; + do + sum += *p++; + while (p != lim); + } + return sum; +} + + +namespace NArchive { +namespace N7z { + +static void FillSignature(Byte *buf) +{ + memcpy(buf, kSignature, kSignatureSize); + buf[kSignatureSize] = kMajorVersion; + buf[kSignatureSize + 1] = 4; +} + +#ifdef Z7_7Z_VOL +HRESULT COutArchive::WriteFinishSignature() +{ + RINOK(WriteDirect(kFinishSignature, kSignatureSize)); + CArchiveVersion av; + av.Major = kMajorVersion; + av.Minor = 2; + RINOK(WriteDirectByte(av.Major)); + return WriteDirectByte(av.Minor); +} +#endif + +static void SetUInt32(Byte *p, UInt32 d) +{ + for (int i = 0; i < 4; i++, d >>= 8) + p[i] = (Byte)d; +} + +static void SetUInt64(Byte *p, UInt64 d) +{ + for (int i = 0; i < 8; i++, d >>= 8) + p[i] = (Byte)d; +} + +HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) +{ + Byte buf[32]; + FillSignature(buf); + SetUInt64(buf + 8 + 4, h.NextHeaderOffset); + SetUInt64(buf + 8 + 12, h.NextHeaderSize); + SetUInt32(buf + 8 + 20, h.NextHeaderCRC); + SetUInt32(buf + 8, CrcCalc(buf + 8 + 4, 20)); + return WriteDirect(buf, sizeof(buf)); +} + +#ifdef Z7_7Z_VOL +HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h) +{ + CCRC crc; + crc.UpdateUInt64(h.NextHeaderOffset); + crc.UpdateUInt64(h.NextHeaderSize); + crc.UpdateUInt32(h.NextHeaderCRC); + crc.UpdateUInt64(h.ArchiveStartOffset); + crc.UpdateUInt64(h.AdditionalStartBlockSize); + RINOK(WriteDirectUInt32(crc.GetDigest())); + RINOK(WriteDirectUInt64(h.NextHeaderOffset)); + RINOK(WriteDirectUInt64(h.NextHeaderSize)); + RINOK(WriteDirectUInt32(h.NextHeaderCRC)); + RINOK(WriteDirectUInt64(h.ArchiveStartOffset)); + return WriteDirectUInt64(h.AdditionalStartBlockSize); +} +#endif + +HRESULT COutArchive::Create_and_WriteStartPrefix(ISequentialOutStream *stream /* , bool endMarker */) +{ + Close(); + #ifdef Z7_7Z_VOL + // endMarker = false; + _endMarker = endMarker; + #endif + SeqStream = stream; + // if (!endMarker) + { + SeqStream.QueryInterface(IID_IOutStream, &Stream); + if (!Stream) + { + return E_NOTIMPL; + // endMarker = true; + } + RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_signatureHeaderPos)) + Byte buf[32]; + FillSignature(buf); + memset(&buf[8], 0, 32 - 8); + return WriteDirect(buf, sizeof(buf)); + } + #ifdef Z7_7Z_VOL + if (endMarker) + { + /* + CStartHeader sh; + sh.NextHeaderOffset = (UInt32)(Int32)-1; + sh.NextHeaderSize = (UInt32)(Int32)-1; + sh.NextHeaderCRC = 0; + WriteStartHeader(sh); + return S_OK; + */ + } + #endif +} + +void COutArchive::Close() +{ + SeqStream.Release(); + Stream.Release(); +} + +UInt64 COutArchive::GetPos() const +{ + if (_countMode) + return _countSize; + if (_writeToStream) + return _outByte.GetProcessedSize(); + return _outByte2.GetPos(); +} + +void COutArchive::WriteBytes(const void *data, size_t size) +{ + if (_countMode) + _countSize += size; + else if (_writeToStream) + { + _outByte.WriteBytes(data, size); + // _crc = CrcUpdate(_crc, data, size); + } + else + _outByte2.WriteBytes(data, size); +} + +void COutArchive::WriteByte(Byte b) +{ + if (_countMode) + _countSize++; + else if (_writeToStream) + WriteByte_ToStream(b); + else + _outByte2.WriteByte(b); +} + +/* +void COutArchive::WriteUInt32(UInt32 value) +{ + for (int i = 0; i < 4; i++) + { + WriteByte((Byte)value); + value >>= 8; + } +} + +void COutArchive::WriteUInt64(UInt64 value) +{ + for (int i = 0; i < 8; i++) + { + WriteByte((Byte)value); + value >>= 8; + } +} +*/ + +void COutArchive::WriteNumber(UInt64 value) +{ + Byte firstByte = 0; + Byte mask = 0x80; + int i; + for (i = 0; i < 8; i++) + { + if (value < ((UInt64(1) << ( 7 * (i + 1))))) + { + firstByte |= Byte(value >> (8 * i)); + break; + } + firstByte |= mask; + mask = (Byte)(mask >> 1); + } + WriteByte(firstByte); + for (; i > 0; i--) + { + WriteByte((Byte)value); + value >>= 8; + } +} + +static unsigned GetBigNumberSize(UInt64 value) +{ + unsigned i; + for (i = 1; i < 9; i++) + if (value < (((UInt64)1 << (i * 7)))) + break; + return i; +} + +#ifdef Z7_7Z_VOL +UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props) +{ + UInt32 result = GetBigNumberSize(dataSize) * 2 + 41; + if (nameLength != 0) + { + nameLength = (nameLength + 1) * 2; + result += nameLength + GetBigNumberSize(nameLength) + 2; + } + if (props) + { + result += 20; + } + if (result >= 128) + result++; + result += kSignatureSize + 2 + kFinishHeaderSize; + return result; +} + +UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) +{ + UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props); + int testSize; + if (volSize > headersSizeBase) + testSize = volSize - headersSizeBase; + else + testSize = 1; + UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props); + UInt64 pureSize = 1; + if (volSize > headersSize) + pureSize = volSize - headersSize; + return pureSize; +} +#endif + +void COutArchive::WriteFolder(const CFolder &folder) +{ + WriteNumber(folder.Coders.Size()); + unsigned i; + + for (i = 0; i < folder.Coders.Size(); i++) + { + const CCoderInfo &coder = folder.Coders[i]; + { + UInt64 id = coder.MethodID; + unsigned idSize; + for (idSize = 1; idSize < sizeof(id); idSize++) + if ((id >> (8 * idSize)) == 0) + break; + // idSize &= 0xF; // idSize is smaller than 16 already + Byte temp[16]; + for (unsigned t = idSize; t != 0; t--, id >>= 8) + temp[t] = (Byte)(id & 0xFF); + + unsigned b = idSize; + const bool isComplex = !coder.IsSimpleCoder(); + b |= (isComplex ? 0x10 : 0); + + const size_t propsSize = coder.Props.Size(); + b |= ((propsSize != 0) ? 0x20 : 0); + temp[0] = (Byte)b; + WriteBytes(temp, idSize + 1); + if (isComplex) + { + WriteNumber(coder.NumStreams); + WriteNumber(1); // NumOutStreams; + } + if (propsSize == 0) + continue; + WriteNumber(propsSize); + WriteBytes(coder.Props, propsSize); + } + } + + for (i = 0; i < folder.Bonds.Size(); i++) + { + const CBond &bond = folder.Bonds[i]; + WriteNumber(bond.PackIndex); + WriteNumber(bond.UnpackIndex); + } + + if (folder.PackStreams.Size() > 1) + for (i = 0; i < folder.PackStreams.Size(); i++) + WriteNumber(folder.PackStreams[i]); +} + +void COutArchive::Write_BoolVector(const CBoolVector &boolVector) +{ + Byte b = 0; + Byte mask = 0x80; + FOR_VECTOR (i, boolVector) + { + if (boolVector[i]) + b |= mask; + mask = (Byte)(mask >> 1); + if (mask == 0) + { + WriteByte(b); + mask = 0x80; + b = 0; + } + } + if (mask != 0x80) + WriteByte(b); +} + +static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } + +void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector) +{ + WriteByte(id); + WriteNumber(Bv_GetSizeInBytes(boolVector)); + Write_BoolVector(boolVector); +} + +void COutArchive::Write_BoolVector_numDefined(const CBoolVector &boolVector, unsigned numDefined) +{ + if (numDefined == boolVector.Size()) + WriteByte(1); + else + { + WriteByte(0); + Write_BoolVector(boolVector); + } +} + + +void COutArchive::WriteHashDigests(const CUInt32DefVector &digests) +{ + const unsigned numDefined = BoolVector_CountSum(digests.Defs); + if (numDefined == 0) + return; + WriteByte(NID::kCRC); + Write_BoolVector_numDefined(digests.Defs, numDefined); + Write_UInt32DefVector_numDefined(digests, numDefined); +} + + +void COutArchive::WritePackInfo( + UInt64 dataOffset, + const CRecordVector &packSizes, + const CUInt32DefVector &packCRCs) +{ + if (packSizes.IsEmpty()) + return; + WriteByte(NID::kPackInfo); + WriteNumber(dataOffset); + WriteNumber(packSizes.Size()); + WriteByte(NID::kSize); + FOR_VECTOR (i, packSizes) + WriteNumber(packSizes[i]); + + WriteHashDigests(packCRCs); + + WriteByte(NID::kEnd); +} + +void COutArchive::WriteUnpackInfo(const CObjectVector &folders, const COutFolders &outFolders) +{ + if (folders.IsEmpty()) + return; + + WriteByte(NID::kUnpackInfo); + + WriteByte(NID::kFolder); + WriteNumber(folders.Size()); + { + WriteByte(0); + FOR_VECTOR (i, folders) + WriteFolder(folders[i]); + } + + WriteByte(NID::kCodersUnpackSize); + FOR_VECTOR (i, outFolders.CoderUnpackSizes) + WriteNumber(outFolders.CoderUnpackSizes[i]); + + WriteHashDigests(outFolders.FolderUnpackCRCs); + + WriteByte(NID::kEnd); +} + +void COutArchive::WriteSubStreamsInfo(const CObjectVector &folders, + const COutFolders &outFolders, + const CRecordVector &unpackSizes, + const CUInt32DefVector &digests) +{ + const CRecordVector &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector; + WriteByte(NID::kSubStreamsInfo); + + unsigned i; + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + if (numUnpackStreamsInFolders[i] != 1) + { + WriteByte(NID::kNumUnpackStream); + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + WriteNumber(numUnpackStreamsInFolders[i]); + break; + } + + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + if (numUnpackStreamsInFolders[i] > 1) + { + WriteByte(NID::kSize); + CNum index = 0; + for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) + { + CNum num = numUnpackStreamsInFolders[i]; + for (CNum j = 0; j < num; j++) + { + if (j + 1 != num) + WriteNumber(unpackSizes[index]); + index++; + } + } + break; + } + + CUInt32DefVector digests2; + + unsigned digestIndex = 0; + for (i = 0; i < folders.Size(); i++) + { + unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i]; + if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i)) + digestIndex++; + else + for (unsigned j = 0; j < numSubStreams; j++, digestIndex++) + { + digests2.Defs.Add(digests.Defs[digestIndex]); + digests2.Vals.Add(digests.Vals[digestIndex]); + } + } + WriteHashDigests(digests2); + WriteByte(NID::kEnd); +} + +// 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. + +void COutArchive::SkipToAligned(unsigned pos, unsigned alignShifts) +{ + if (!_useAlign) + return; + + const unsigned alignSize = (unsigned)1 << alignShifts; + pos += (unsigned)GetPos(); + pos &= (alignSize - 1); + if (pos == 0) + return; + unsigned skip = alignSize - pos; + if (skip < 2) + skip += alignSize; + skip -= 2; + WriteByte(NID::kDummy); + WriteByte((Byte)skip); + for (unsigned i = 0; i < skip; i++) + WriteByte(0); +} + +void COutArchive::WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts) +{ + const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); + const UInt64 dataSize = ((UInt64)numDefined << itemSizeShifts) + bvSize + 2; + SkipToAligned(3 + bvSize + GetBigNumberSize(dataSize), itemSizeShifts); + + WriteByte(type); + WriteNumber(dataSize); + Write_BoolVector_numDefined(v, numDefined); + WriteByte(0); // 0 means no switching to external stream +} + + +void COutArchive::Write_UInt32DefVector_numDefined(const CUInt32DefVector &v, unsigned numDefined) +{ + if (_countMode) + { + _countSize += (size_t)numDefined * 4; + return; + } + + const bool * const defs = v.Defs.ConstData(); + const UInt32 * const vals = v.Vals.ConstData(); + const size_t num = v.Defs.Size(); + + for (size_t i = 0; i < num; i++) + if (defs[i]) + { + UInt32 value = vals[i]; + for (int k = 0; k < 4; k++) + { + if (_writeToStream) + WriteByte_ToStream((Byte)value); + else + _outByte2.WriteByte((Byte)value); + // WriteByte((Byte)value); + value >>= 8; + } + // WriteUInt32(v.Vals[i]); + } +} + + +void COutArchive::Write_UInt64DefVector_type(const CUInt64DefVector &v, Byte type) +{ + const unsigned numDefined = BoolVector_CountSum(v.Defs); + if (numDefined == 0) + return; + + WriteAlignedBools(v.Defs, numDefined, type, 3); + + if (_countMode) + { + _countSize += (size_t)numDefined * 8; + return; + } + + const bool * const defs = v.Defs.ConstData(); + const UInt64 * const vals = v.Vals.ConstData(); + const size_t num = v.Defs.Size(); + + for (size_t i = 0; i < num; i++) + if (defs[i]) + { + UInt64 value = vals[i]; + for (int k = 0; k < 8; k++) + { + if (_writeToStream) + WriteByte_ToStream((Byte)value); + else + _outByte2.WriteByte((Byte)value); + // WriteByte((Byte)value); + value >>= 8; + } + // WriteUInt64(v.Vals[i]); + } +} + + +HRESULT COutArchive::EncodeStream( + DECL_EXTERNAL_CODECS_LOC_VARS + CEncoder &encoder, const CByteBuffer &data, + CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders) +{ + CMyComPtr2_Create streamSpec; + streamSpec->Init(data, data.Size()); + outFolders.FolderUnpackCRCs.Defs.Add(true); + outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size())); + // outFolders.NumUnpackStreamsVector.Add(1); + const UInt64 dataSize64 = data.Size(); + const UInt64 expectSize = data.Size(); + RINOK(encoder.Encode1( + EXTERNAL_CODECS_LOC_VARS + streamSpec, + // NULL, + &dataSize64, // inSizeForReduce + expectSize, + folders.AddNew(), + // outFolders.CoderUnpackSizes, unpackSize, + SeqStream, packSizes, NULL)) + if (!streamSpec->WasFinished()) + return E_FAIL; + encoder.Encode_Post(dataSize64, outFolders.CoderUnpackSizes); + return S_OK; +} + +void COutArchive::WriteHeader( + const CArchiveDatabaseOut &db, + // const CHeaderOptions &headerOptions, + UInt64 &headerOffset) +{ + /* + bool thereIsSecure = (db.SecureBuf.Size() != 0); + */ + _useAlign = true; + + headerOffset = UInt64Vector_CountSum(db.PackSizes); + + WriteByte(NID::kHeader); + + /* + { + // It's example for per archive properies writing + + WriteByte(NID::kArchiveProperties); + + // you must use random 40-bit number that will identify you + // then you can use same kDeveloperID for any properties and methods + const UInt64 kDeveloperID = 0x123456789A; // change that value to real random 40-bit number + + #define GENERATE_7Z_ID(developerID, subID) (((UInt64)0x3F << 56) | ((UInt64)developerID << 16) | subID) + + { + const UInt64 kSubID = 0x1; // you can use small number for subID + const UInt64 kID = GENERATE_7Z_ID(kDeveloperID, kSubID); + WriteNumber(kID); + const unsigned kPropsSize = 3; // it's example size + WriteNumber(kPropsSize); + for (unsigned i = 0; i < kPropsSize; i++) + WriteByte((Byte)(i & 0xFF)); + } + { + const UInt64 kSubID = 0x2; // you can use small number for subID + const UInt64 kID = GENERATE_7Z_ID(kDeveloperID, kSubID); + WriteNumber(kID); + const unsigned kPropsSize = 5; // it's example size + WriteNumber(kPropsSize); + for (unsigned i = 0; i < kPropsSize; i++) + WriteByte((Byte)(i + 16)); + } + WriteByte(NID::kEnd); + } + */ + + if (db.Folders.Size() > 0) + { + WriteByte(NID::kMainStreamsInfo); + WritePackInfo(0, db.PackSizes, db.PackCRCs); + WriteUnpackInfo(db.Folders, (const COutFolders &)db); + + CRecordVector unpackSizes; + CUInt32DefVector digests; + FOR_VECTOR (i, db.Files) + { + const CFileItem &file = db.Files[i]; + if (!file.HasStream) + continue; + unpackSizes.Add(file.Size); + digests.Defs.Add(file.CrcDefined); + digests.Vals.Add(file.Crc); + } + + WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests); + WriteByte(NID::kEnd); + } + + if (db.Files.IsEmpty()) + { + WriteByte(NID::kEnd); + return; + } + + WriteByte(NID::kFilesInfo); + WriteNumber(db.Files.Size()); + + { + /* ---------- Empty Streams ---------- */ + CBoolVector emptyStreamVector; + emptyStreamVector.ClearAndSetSize(db.Files.Size()); + unsigned numEmptyStreams = 0; + { + FOR_VECTOR (i, db.Files) + if (db.Files[i].HasStream) + emptyStreamVector[i] = false; + else + { + emptyStreamVector[i] = true; + numEmptyStreams++; + } + } + + if (numEmptyStreams != 0) + { + WritePropBoolVector(NID::kEmptyStream, emptyStreamVector); + + CBoolVector emptyFileVector, antiVector; + emptyFileVector.ClearAndSetSize(numEmptyStreams); + antiVector.ClearAndSetSize(numEmptyStreams); + bool thereAreEmptyFiles = false, thereAreAntiItems = false; + unsigned cur = 0; + + FOR_VECTOR (i, db.Files) + { + const CFileItem &file = db.Files[i]; + if (file.HasStream) + continue; + emptyFileVector[cur] = !file.IsDir; + if (!file.IsDir) + thereAreEmptyFiles = true; + bool isAnti = db.IsItemAnti(i); + antiVector[cur] = isAnti; + if (isAnti) + thereAreAntiItems = true; + cur++; + } + + if (thereAreEmptyFiles) + WritePropBoolVector(NID::kEmptyFile, emptyFileVector); + if (thereAreAntiItems) + WritePropBoolVector(NID::kAnti, antiVector); + } + } + + + { + /* ---------- Names ---------- */ + + size_t namesDataSize = 0; + { + FOR_VECTOR (i, db.Files) + { + const UString &name = db.Names[i]; + const size_t numUtfChars = + /* + #if WCHAR_MAX > 0xffff + Get_Num_Utf16_chars_from_wchar_string(name.Ptr()); + #else + */ + name.Len(); + // #endif + namesDataSize += numUtfChars; + } + } + if (namesDataSize) + { + namesDataSize += db.Files.Size(); // we will write tail zero wchar for each name + namesDataSize *= 2; // 2 bytes per wchar for UTF16 encoding + namesDataSize++; // for additional switch byte (zero value) + SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4); + WriteByte(NID::kName); + WriteNumber(namesDataSize); + + if (_countMode) + _countSize += namesDataSize; + else + { + WriteByte(0); + FOR_VECTOR (i, db.Files) + { + const UString &name = db.Names[i]; + const wchar_t *p = name.Ptr(); + const size_t len = (size_t)name.Len() + 1; + const wchar_t * const lim = p + len; + if (_writeToStream) + { + do + { + const wchar_t c = *p++; + WriteByte_ToStream((Byte)c); + WriteByte_ToStream((Byte)(c >> 8)); + } + while (p != lim); + } + else + { + Byte *dest = _outByte2.GetDest_and_Update(len * 2); + do + { + /* + #if WCHAR_MAX > 0xffff + if (c >= 0x10000) + { + c -= 0x10000; + if (c < (1 << 20)) + { + unsigned c0 = 0xd800 + ((c >> 10) & 0x3FF); + WriteByte((Byte)c0); + WriteByte((Byte)(c0 >> 8)); + c = 0xdc00 + (c & 0x3FF); + } + else + c = '_'; // we change character unsupported by UTF16 + } + #endif + */ + const wchar_t c = *p++; + SetUi16(dest, (UInt16)c) + dest += 2; + } + while (p != lim); + } + } + } + } + } + + /* if (headerOptions.WriteCTime) */ Write_UInt64DefVector_type(db.CTime, NID::kCTime); + /* if (headerOptions.WriteATime) */ Write_UInt64DefVector_type(db.ATime, NID::kATime); + /* if (headerOptions.WriteMTime) */ Write_UInt64DefVector_type(db.MTime, NID::kMTime); + Write_UInt64DefVector_type(db.StartPos, NID::kStartPos); + + { + /* ---------- Write Attrib ---------- */ + const unsigned numDefined = BoolVector_CountSum(db.Attrib.Defs); + if (numDefined != 0) + { + WriteAlignedBools(db.Attrib.Defs, numDefined, NID::kWinAttrib, 2); + Write_UInt32DefVector_numDefined(db.Attrib, numDefined); + } + } + + /* + { + // ---------- Write IsAux ---------- + if (BoolVector_CountSum(db.IsAux) != 0) + WritePropBoolVector(NID::kIsAux, db.IsAux); + } + + { + // ---------- Write Parent ---------- + CBoolVector boolVector; + boolVector.Reserve(db.Files.Size()); + unsigned numIsDir = 0; + unsigned numParentLinks = 0; + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + bool defined = !file.IsAltStream; + boolVector.Add(defined); + if (defined) + numIsDir++; + if (file.Parent >= 0) + numParentLinks++; + } + if (numParentLinks > 0) + { + // WriteAlignedBools(boolVector, numDefined, NID::kParent, 2); + const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector); + const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1; + SkipToAligned(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 2); + + WriteByte(NID::kParent); + WriteNumber(dataSize); + Write_BoolVector_numDefined(boolVector, numIsDir); + for (i = 0; i < db.Files.Size(); i++) + { + const CFileItem &file = db.Files[i]; + // if (file.Parent >= 0) + WriteUInt32(file.Parent); + } + } + } + + if (thereIsSecure) + { + UInt64 secureDataSize = 1 + 4 + + db.SecureBuf.Size() + + db.SecureSizes.Size() * 4; + // secureDataSize += db.SecureIDs.Size() * 4; + for (i = 0; i < db.SecureIDs.Size(); i++) + secureDataSize += GetBigNumberSize(db.SecureIDs[i]); + SkipToAligned(2 + GetBigNumberSize(secureDataSize), 2); + WriteByte(NID::kNtSecure); + WriteNumber(secureDataSize); + WriteByte(0); + WriteUInt32(db.SecureSizes.Size()); + for (i = 0; i < db.SecureSizes.Size(); i++) + WriteUInt32(db.SecureSizes[i]); + WriteBytes(db.SecureBuf, db.SecureBuf.Size()); + for (i = 0; i < db.SecureIDs.Size(); i++) + { + WriteNumber(db.SecureIDs[i]); + // WriteUInt32(db.SecureIDs[i]); + } + } + */ + + WriteByte(NID::kEnd); // for files + WriteByte(NID::kEnd); // for headers +} + +HRESULT COutArchive::WriteDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + const CArchiveDatabaseOut &db, + const CCompressionMethodMode *options, + const CHeaderOptions &headerOptions) +{ + if (!db.CheckNumFiles()) + return E_FAIL; + + CStartHeader sh; + sh.NextHeaderOffset = 0; + sh.NextHeaderSize = 0; + sh.NextHeaderCRC = 0; // CrcCalc(NULL, 0); + + if (!db.IsEmpty()) + { + CMyComPtr2_Create crcStream; + crcStream->SetStream(SeqStream); + crcStream->Init(); + + bool encodeHeaders = false; + if (options) + if (options->IsEmpty()) + options = NULL; + if (options) + if (options->PasswordIsDefined || headerOptions.CompressMainHeader) + encodeHeaders = true; + + if (!_outByte.Create(1 << 16)) + return E_OUTOFMEMORY; + _outByte.SetStream(crcStream.Interface()); + _outByte.Init(); + // _crc = CRC_INIT_VAL; + _countMode = encodeHeaders; + _writeToStream = true; + _countSize = 0; + WriteHeader(db, /* headerOptions, */ sh.NextHeaderOffset); + + if (encodeHeaders) + { + CByteBuffer buf(_countSize); + _outByte2.Init((Byte *)buf, _countSize); + + _countMode = false; + _writeToStream = false; + WriteHeader(db, /* headerOptions, */ sh.NextHeaderOffset); + + if (_countSize != _outByte2.GetPos()) + return E_FAIL; + + CCompressionMethodMode encryptOptions; + encryptOptions.PasswordIsDefined = options->PasswordIsDefined; + encryptOptions.Password = options->Password; + CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); + CRecordVector packSizes; + CObjectVector folders; + COutFolders outFolders; + + RINOK(EncodeStream( + EXTERNAL_CODECS_LOC_VARS + encoder, buf, + packSizes, folders, outFolders)) + + _writeToStream = true; + + if (folders.Size() == 0) + throw 1; + + WriteID(NID::kEncodedHeader); + WritePackInfo(sh.NextHeaderOffset, packSizes, CUInt32DefVector()); + WriteUnpackInfo(folders, outFolders); + WriteByte(NID::kEnd); + + sh.NextHeaderOffset += UInt64Vector_CountSum(packSizes); + } + RINOK(_outByte.Flush()) + sh.NextHeaderCRC = crcStream->GetCRC(); + // sh.NextHeaderCRC = CRC_GET_DIGEST(_crc); + // if (CRC_GET_DIGEST(_crc) != sh.NextHeaderCRC) throw 1; + sh.NextHeaderSize = _outByte.GetProcessedSize(); + } + #ifdef Z7_7Z_VOL + if (_endMarker) + { + CFinishHeader h; + h.NextHeaderSize = headerSize; + h.NextHeaderCRC = headerCRC; + h.NextHeaderOffset = + UInt64(0) - (headerSize + + 4 + kFinishHeaderSize); + h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset; + h.AdditionalStartBlockSize = 0; + RINOK(WriteFinishHeader(h)); + return WriteFinishSignature(); + } + else + #endif + if (Stream) + { + RINOK(Stream->Seek((Int64)_signatureHeaderPos, STREAM_SEEK_SET, NULL)) + return WriteStartHeader(sh); + } + return S_OK; +} + +void CUInt32DefVector::SetItem(unsigned index, bool defined, UInt32 value) +{ + while (index >= Defs.Size()) + Defs.Add(false); + Defs[index] = defined; + if (!defined) + return; + while (index >= Vals.Size()) + Vals.Add(0); + Vals[index] = value; +} + +void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value) +{ + while (index >= Defs.Size()) + Defs.Add(false); + Defs[index] = defined; + if (!defined) + return; + while (index >= Vals.Size()) + Vals.Add(0); + Vals[index] = value; +} + +void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name) +{ + unsigned index = Files.Size(); + CTime.SetItem(index, file2.CTimeDefined, file2.CTime); + ATime.SetItem(index, file2.ATimeDefined, file2.ATime); + MTime.SetItem(index, file2.MTimeDefined, file2.MTime); + StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); + Attrib.SetItem(index, file2.AttribDefined, file2.Attrib); + SetItem_Anti(index, file2.IsAnti); + // SetItem_Aux(index, file2.IsAux); + Names.Add(name); + Files.Add(file); +} + +}} diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h index ffb5acb70..c65d268d0 100644 --- a/CPP/7zip/Archive/7z/7zOut.h +++ b/CPP/7zip/Archive/7z/7zOut.h @@ -1,346 +1,346 @@ -// 7zOut.h - -#ifndef ZIP7_INC_7Z_OUT_H -#define ZIP7_INC_7Z_OUT_H - -#include "7zCompressionMode.h" -#include "7zEncode.h" -#include "7zHeader.h" -#include "7zItem.h" - -#include "../../Common/OutBuffer.h" -#include "../../Common/StreamUtils.h" - -namespace NArchive { -namespace N7z { - -const unsigned k_StartHeadersRewriteSize = 32; - -class CWriteBufferLoc -{ - Byte *_data; - Byte *_dataLim; - Byte *_dataBase; -public: - // CWriteBufferLoc(): _data(NULL), _dataLim(NULL), _dataBase(NULL) {} - void Init(Byte *data, size_t size) - { - _data = data; - _dataBase = data; - _dataLim = data + size; - } - - Byte *GetDest_and_Update(size_t size) - { - Byte *dest = _data; - if (size > (size_t)(_dataLim - dest)) - throw 1; - _data = dest + size; - return dest; - } - void WriteBytes(const void *data, size_t size) - { - if (size == 0) - return; - Byte *dest = GetDest_and_Update(size); - memcpy(dest, data, size); - } - void WriteByte(Byte b) - { - Byte *dest = _data; - if (dest == _dataLim) - throw 1; - *dest++ = b; - _data = dest; - } - size_t GetPos() const { return (size_t)(_data - _dataBase); } -}; - - -struct CHeaderOptions -{ - bool CompressMainHeader; - /* - bool WriteCTime; - bool WriteATime; - bool WriteMTime; - */ - - CHeaderOptions(): - CompressMainHeader(true) - /* - , WriteCTime(false) - , WriteATime(false) - , WriteMTime(true) - */ - {} -}; - - -struct CFileItem2 -{ - UInt64 CTime; - UInt64 ATime; - UInt64 MTime; - UInt64 StartPos; - UInt32 Attrib; - - bool CTimeDefined; - bool ATimeDefined; - bool MTimeDefined; - bool StartPosDefined; - bool AttribDefined; - bool IsAnti; - // bool IsAux; - - /* - void Init() - { - CTimeDefined = false; - ATimeDefined = false; - MTimeDefined = false; - StartPosDefined = false; - AttribDefined = false; - IsAnti = false; - // IsAux = false; - } - */ -}; - - -struct COutFolders -{ - CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. - - CRecordVector NumUnpackStreamsVector; - CRecordVector CoderUnpackSizes; // including unpack sizes of bond coders - - void OutFoldersClear() - { - FolderUnpackCRCs.Clear(); - NumUnpackStreamsVector.Clear(); - CoderUnpackSizes.Clear(); - } - - void OutFoldersReserveDown() - { - FolderUnpackCRCs.ReserveDown(); - NumUnpackStreamsVector.ReserveDown(); - CoderUnpackSizes.ReserveDown(); - } -}; - - -struct CArchiveDatabaseOut: public COutFolders -{ - CRecordVector PackSizes; - CUInt32DefVector PackCRCs; - CObjectVector Folders; - - CRecordVector Files; - UStringVector Names; - CUInt64DefVector CTime; - CUInt64DefVector ATime; - CUInt64DefVector MTime; - CUInt64DefVector StartPos; - CUInt32DefVector Attrib; - CBoolVector IsAnti; - - /* - CBoolVector IsAux; - - CByteBuffer SecureBuf; - CRecordVector SecureSizes; - CRecordVector SecureIDs; - - void ClearSecure() - { - SecureBuf.Free(); - SecureSizes.Clear(); - SecureIDs.Clear(); - } - */ - - void Clear() - { - OutFoldersClear(); - - PackSizes.Clear(); - PackCRCs.Clear(); - Folders.Clear(); - - Files.Clear(); - Names.Clear(); - CTime.Clear(); - ATime.Clear(); - MTime.Clear(); - StartPos.Clear(); - Attrib.Clear(); - IsAnti.Clear(); - - /* - IsAux.Clear(); - ClearSecure(); - */ - } - - void ReserveDown() - { - OutFoldersReserveDown(); - - PackSizes.ReserveDown(); - PackCRCs.ReserveDown(); - Folders.ReserveDown(); - - Files.ReserveDown(); - Names.ReserveDown(); - CTime.ReserveDown(); - ATime.ReserveDown(); - MTime.ReserveDown(); - StartPos.ReserveDown(); - Attrib.ReserveDown(); - IsAnti.ReserveDown(); - - /* - IsAux.ReserveDown(); - */ - } - - bool IsEmpty() const - { - return ( - PackSizes.IsEmpty() && - NumUnpackStreamsVector.IsEmpty() && - Folders.IsEmpty() && - Files.IsEmpty()); - } - - bool CheckNumFiles() const - { - unsigned size = Files.Size(); - return ( - CTime.CheckSize(size) - && ATime.CheckSize(size) - && MTime.CheckSize(size) - && StartPos.CheckSize(size) - && Attrib.CheckSize(size) - && (size == IsAnti.Size() || IsAnti.Size() == 0)); - } - - bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } - // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } - - void SetItem_Anti(unsigned index, bool isAnti) - { - while (index >= IsAnti.Size()) - IsAnti.Add(false); - IsAnti[index] = isAnti; - } - /* - void SetItem_Aux(unsigned index, bool isAux) - { - while (index >= IsAux.Size()) - IsAux.Add(false); - IsAux[index] = isAux; - } - */ - - void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name); -}; - - -class COutArchive -{ - HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); } - - UInt64 GetPos() const; - void WriteBytes(const void *data, size_t size); - void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); } - void WriteByte(Byte b); - void WriteByte_ToStream(Byte b) - { - _outByte.WriteByte(b); - // _crc = CRC_UPDATE_BYTE(_crc, b); - } - // void WriteUInt32(UInt32 value); - // void WriteUInt64(UInt64 value); - void WriteNumber(UInt64 value); - void WriteID(UInt64 value) { WriteNumber(value); } - - void WriteFolder(const CFolder &folder); - HRESULT WriteFileHeader(const CFileItem &itemInfo); - void Write_BoolVector(const CBoolVector &boolVector); - void Write_BoolVector_numDefined(const CBoolVector &boolVector, unsigned numDefined); - void WritePropBoolVector(Byte id, const CBoolVector &boolVector); - - void WriteHashDigests(const CUInt32DefVector &digests); - - void WritePackInfo( - UInt64 dataOffset, - const CRecordVector &packSizes, - const CUInt32DefVector &packCRCs); - - void WriteUnpackInfo( - const CObjectVector &folders, - const COutFolders &outFolders); - - void WriteSubStreamsInfo( - const CObjectVector &folders, - const COutFolders &outFolders, - const CRecordVector &unpackSizes, - const CUInt32DefVector &digests); - - void SkipToAligned(unsigned pos, unsigned alignShifts); - void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts); - void Write_UInt32DefVector_numDefined(const CUInt32DefVector &v, unsigned numDefined); - void Write_UInt64DefVector_type(const CUInt64DefVector &v, Byte type); - - HRESULT EncodeStream( - DECL_EXTERNAL_CODECS_LOC_VARS - CEncoder &encoder, const CByteBuffer &data, - CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders); - void WriteHeader( - const CArchiveDatabaseOut &db, - // const CHeaderOptions &headerOptions, - UInt64 &headerOffset); - - bool _countMode; - bool _writeToStream; - bool _useAlign; - #ifdef Z7_7Z_VOL - bool _endMarker; - #endif - // UInt32 _crc; - size_t _countSize; - CWriteBufferLoc _outByte2; - COutBuffer _outByte; - UInt64 _signatureHeaderPos; - CMyComPtr Stream; - - #ifdef Z7_7Z_VOL - HRESULT WriteFinishSignature(); - HRESULT WriteFinishHeader(const CFinishHeader &h); - #endif - HRESULT WriteStartHeader(const CStartHeader &h); - -public: - CMyComPtr SeqStream; - - // COutArchive(); - HRESULT Create_and_WriteStartPrefix(ISequentialOutStream *stream /* , bool endMarker */); - void Close(); - HRESULT WriteDatabase( - DECL_EXTERNAL_CODECS_LOC_VARS - const CArchiveDatabaseOut &db, - const CCompressionMethodMode *options, - const CHeaderOptions &headerOptions); - - #ifdef Z7_7Z_VOL - static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false); - static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false); - #endif -}; - -}} - -#endif +// 7zOut.h + +#ifndef ZIP7_INC_7Z_OUT_H +#define ZIP7_INC_7Z_OUT_H + +#include "7zCompressionMode.h" +#include "7zEncode.h" +#include "7zHeader.h" +#include "7zItem.h" + +#include "../../Common/OutBuffer.h" +#include "../../Common/StreamUtils.h" + +namespace NArchive { +namespace N7z { + +const unsigned k_StartHeadersRewriteSize = 32; + +class CWriteBufferLoc +{ + Byte *_data; + Byte *_dataLim; + Byte *_dataBase; +public: + // CWriteBufferLoc(): _data(NULL), _dataLim(NULL), _dataBase(NULL) {} + void Init(Byte *data, size_t size) + { + _data = data; + _dataBase = data; + _dataLim = data + size; + } + + Byte *GetDest_and_Update(size_t size) + { + Byte *dest = _data; + if (size > (size_t)(_dataLim - dest)) + throw 1; + _data = dest + size; + return dest; + } + void WriteBytes(const void *data, size_t size) + { + if (size == 0) + return; + Byte *dest = GetDest_and_Update(size); + memcpy(dest, data, size); + } + void WriteByte(Byte b) + { + Byte *dest = _data; + if (dest == _dataLim) + throw 1; + *dest++ = b; + _data = dest; + } + size_t GetPos() const { return (size_t)(_data - _dataBase); } +}; + + +struct CHeaderOptions +{ + bool CompressMainHeader; + /* + bool WriteCTime; + bool WriteATime; + bool WriteMTime; + */ + + CHeaderOptions(): + CompressMainHeader(true) + /* + , WriteCTime(false) + , WriteATime(false) + , WriteMTime(true) + */ + {} +}; + + +struct CFileItem2 +{ + UInt64 CTime; + UInt64 ATime; + UInt64 MTime; + UInt64 StartPos; + UInt32 Attrib; + + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + bool StartPosDefined; + bool AttribDefined; + bool IsAnti; + // bool IsAux; + + /* + void Init() + { + CTimeDefined = false; + ATimeDefined = false; + MTimeDefined = false; + StartPosDefined = false; + AttribDefined = false; + IsAnti = false; + // IsAux = false; + } + */ +}; + + +struct COutFolders +{ + CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only. + + CRecordVector NumUnpackStreamsVector; + CRecordVector CoderUnpackSizes; // including unpack sizes of bond coders + + void OutFoldersClear() + { + FolderUnpackCRCs.Clear(); + NumUnpackStreamsVector.Clear(); + CoderUnpackSizes.Clear(); + } + + void OutFoldersReserveDown() + { + FolderUnpackCRCs.ReserveDown(); + NumUnpackStreamsVector.ReserveDown(); + CoderUnpackSizes.ReserveDown(); + } +}; + + +struct CArchiveDatabaseOut: public COutFolders +{ + CRecordVector PackSizes; + CUInt32DefVector PackCRCs; + CObjectVector Folders; + + CRecordVector Files; + UStringVector Names; + CUInt64DefVector CTime; + CUInt64DefVector ATime; + CUInt64DefVector MTime; + CUInt64DefVector StartPos; + CUInt32DefVector Attrib; + CBoolVector IsAnti; + + /* + CBoolVector IsAux; + + CByteBuffer SecureBuf; + CRecordVector SecureSizes; + CRecordVector SecureIDs; + + void ClearSecure() + { + SecureBuf.Free(); + SecureSizes.Clear(); + SecureIDs.Clear(); + } + */ + + void Clear() + { + OutFoldersClear(); + + PackSizes.Clear(); + PackCRCs.Clear(); + Folders.Clear(); + + Files.Clear(); + Names.Clear(); + CTime.Clear(); + ATime.Clear(); + MTime.Clear(); + StartPos.Clear(); + Attrib.Clear(); + IsAnti.Clear(); + + /* + IsAux.Clear(); + ClearSecure(); + */ + } + + void ReserveDown() + { + OutFoldersReserveDown(); + + PackSizes.ReserveDown(); + PackCRCs.ReserveDown(); + Folders.ReserveDown(); + + Files.ReserveDown(); + Names.ReserveDown(); + CTime.ReserveDown(); + ATime.ReserveDown(); + MTime.ReserveDown(); + StartPos.ReserveDown(); + Attrib.ReserveDown(); + IsAnti.ReserveDown(); + + /* + IsAux.ReserveDown(); + */ + } + + bool IsEmpty() const + { + return ( + PackSizes.IsEmpty() && + NumUnpackStreamsVector.IsEmpty() && + Folders.IsEmpty() && + Files.IsEmpty()); + } + + bool CheckNumFiles() const + { + unsigned size = Files.Size(); + return ( + CTime.CheckSize(size) + && ATime.CheckSize(size) + && MTime.CheckSize(size) + && StartPos.CheckSize(size) + && Attrib.CheckSize(size) + && (size == IsAnti.Size() || IsAnti.Size() == 0)); + } + + bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); } + // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); } + + void SetItem_Anti(unsigned index, bool isAnti) + { + while (index >= IsAnti.Size()) + IsAnti.Add(false); + IsAnti[index] = isAnti; + } + /* + void SetItem_Aux(unsigned index, bool isAux) + { + while (index >= IsAux.Size()) + IsAux.Add(false); + IsAux[index] = isAux; + } + */ + + void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name); +}; + + +class COutArchive +{ + HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); } + + UInt64 GetPos() const; + void WriteBytes(const void *data, size_t size); + void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); } + void WriteByte(Byte b); + void WriteByte_ToStream(Byte b) + { + _outByte.WriteByte(b); + // _crc = CRC_UPDATE_BYTE(_crc, b); + } + // void WriteUInt32(UInt32 value); + // void WriteUInt64(UInt64 value); + void WriteNumber(UInt64 value); + void WriteID(UInt64 value) { WriteNumber(value); } + + void WriteFolder(const CFolder &folder); + HRESULT WriteFileHeader(const CFileItem &itemInfo); + void Write_BoolVector(const CBoolVector &boolVector); + void Write_BoolVector_numDefined(const CBoolVector &boolVector, unsigned numDefined); + void WritePropBoolVector(Byte id, const CBoolVector &boolVector); + + void WriteHashDigests(const CUInt32DefVector &digests); + + void WritePackInfo( + UInt64 dataOffset, + const CRecordVector &packSizes, + const CUInt32DefVector &packCRCs); + + void WriteUnpackInfo( + const CObjectVector &folders, + const COutFolders &outFolders); + + void WriteSubStreamsInfo( + const CObjectVector &folders, + const COutFolders &outFolders, + const CRecordVector &unpackSizes, + const CUInt32DefVector &digests); + + void SkipToAligned(unsigned pos, unsigned alignShifts); + void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts); + void Write_UInt32DefVector_numDefined(const CUInt32DefVector &v, unsigned numDefined); + void Write_UInt64DefVector_type(const CUInt64DefVector &v, Byte type); + + HRESULT EncodeStream( + DECL_EXTERNAL_CODECS_LOC_VARS + CEncoder &encoder, const CByteBuffer &data, + CRecordVector &packSizes, CObjectVector &folders, COutFolders &outFolders); + void WriteHeader( + const CArchiveDatabaseOut &db, + // const CHeaderOptions &headerOptions, + UInt64 &headerOffset); + + bool _countMode; + bool _writeToStream; + bool _useAlign; + #ifdef Z7_7Z_VOL + bool _endMarker; + #endif + // UInt32 _crc; + size_t _countSize; + CWriteBufferLoc _outByte2; + COutBuffer _outByte; + UInt64 _signatureHeaderPos; + CMyComPtr Stream; + + #ifdef Z7_7Z_VOL + HRESULT WriteFinishSignature(); + HRESULT WriteFinishHeader(const CFinishHeader &h); + #endif + HRESULT WriteStartHeader(const CStartHeader &h); + +public: + CMyComPtr SeqStream; + + // COutArchive(); + HRESULT Create_and_WriteStartPrefix(ISequentialOutStream *stream /* , bool endMarker */); + void Close(); + HRESULT WriteDatabase( + DECL_EXTERNAL_CODECS_LOC_VARS + const CArchiveDatabaseOut &db, + const CCompressionMethodMode *options, + const CHeaderOptions &headerOptions); + + #ifdef Z7_7Z_VOL + static UInt32 GetVolHeadersSize(UInt64 dataSize, int nameLength = 0, bool props = false); + static UInt64 GetVolPureSize(UInt64 volSize, int nameLength = 0, bool props = false); + #endif +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp index 48ae16fd5..d3b3cbe57 100644 --- a/CPP/7zip/Archive/7z/7zProperties.cpp +++ b/CPP/7zip/Archive/7z/7zProperties.cpp @@ -1,182 +1,182 @@ -// 7zProperties.cpp - -#include "StdAfx.h" - -#include "7zHandler.h" -#include "7zProperties.h" - -namespace NArchive { -namespace N7z { - -struct CPropMap -{ - Byte FilePropID; - // CStatProp StatProp; - VARTYPE vt; - UInt32 StatPropID; -}; - -// #define STAT_PROP(name, id, vt) { name, id, vt } -#define STAT_PROP(name, id, vt) vt, id - -#define STAT_PROP2(id, vt) STAT_PROP(NULL, id, vt) - -#define k_7z_id_Encrypted 97 -#define k_7z_id_Method 98 -#define k_7z_id_Block 99 - -static const CPropMap kPropMap[] = -{ - { NID::kName, STAT_PROP2(kpidPath, VT_BSTR) }, - { NID::kSize, STAT_PROP2(kpidSize, VT_UI8) }, - { NID::kPackInfo, STAT_PROP2(kpidPackSize, VT_UI8) }, - - #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES -#define k_7z_id_PackedSize0 100 - { k_7z_id_PackedSize0 + 0, STAT_PROP("Pack0", kpidPackedSize0, VT_UI8) }, - { k_7z_id_PackedSize0 + 1, STAT_PROP("Pack1", kpidPackedSize1, VT_UI8) }, - { k_7z_id_PackedSize0 + 2, STAT_PROP("Pack2", kpidPackedSize2, VT_UI8) }, - { k_7z_id_PackedSize0 + 3, STAT_PROP("Pack3", kpidPackedSize3, VT_UI8) }, - { k_7z_id_PackedSize0 + 4, STAT_PROP("Pack4", kpidPackedSize4, VT_UI8) }, - #endif - - { NID::kCTime, STAT_PROP2(kpidCTime, VT_FILETIME) }, - { NID::kMTime, STAT_PROP2(kpidMTime, VT_FILETIME) }, - { NID::kATime, STAT_PROP2(kpidATime, VT_FILETIME) }, - { NID::kWinAttrib, STAT_PROP2(kpidAttrib, VT_UI4) }, - { NID::kStartPos, STAT_PROP2(kpidPosition, VT_UI8) }, - - { NID::kCRC, STAT_PROP2(kpidCRC, VT_UI4) }, - // { NID::kIsAux, STAT_PROP2(kpidIsAux, VT_BOOL) }, - { NID::kAnti, STAT_PROP2(kpidIsAnti, VT_BOOL) } - - #ifndef Z7_SFX - , { k_7z_id_Encrypted, STAT_PROP2(kpidEncrypted, VT_BOOL) } - , { k_7z_id_Method, STAT_PROP2(kpidMethod, VT_BSTR) } - , { k_7z_id_Block, STAT_PROP2(kpidBlock, VT_UI4) } - #endif -}; - -static void CopyOneItem(CRecordVector &src, - CRecordVector &dest, const UInt32 item) -{ - FOR_VECTOR (i, src) - if (src[i] == item) - { - dest.Add(item); - src.Delete(i); - return; - } -} - -static void RemoveOneItem(CRecordVector &src, const UInt32 item) -{ - FOR_VECTOR (i, src) - if (src[i] == item) - { - src.Delete(i); - return; - } -} - -static void InsertToHead(CRecordVector &dest, const UInt32 item) -{ - FOR_VECTOR (i, dest) - if (dest[i] == item) - { - dest.Delete(i); - break; - } - dest.Insert(0, item); -} - -#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id); - -void CHandler::FillPopIDs() -{ - _fileInfoPopIDs.Clear(); - - #ifdef Z7_7Z_VOL - if (_volumes.Size() < 1) - return; - const CVolume &volume = _volumes.Front(); - const CArchiveDatabaseEx &_db = volume.Database; - #endif - - CRecordVector fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs; - - RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); - RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); - /* - RemoveOneItem(fileInfoPopIDs, NID::kParent); - RemoveOneItem(fileInfoPopIDs, NID::kNtSecure); - */ - - COPY_ONE_ITEM(kName) - COPY_ONE_ITEM(kAnti) - COPY_ONE_ITEM(kSize) - COPY_ONE_ITEM(kPackInfo) - COPY_ONE_ITEM(kCTime) - COPY_ONE_ITEM(kMTime) - COPY_ONE_ITEM(kATime) - COPY_ONE_ITEM(kWinAttrib) - COPY_ONE_ITEM(kCRC) - COPY_ONE_ITEM(kComment) - - _fileInfoPopIDs += fileInfoPopIDs; - - #ifndef Z7_SFX - _fileInfoPopIDs.Add(k_7z_id_Encrypted); - _fileInfoPopIDs.Add(k_7z_id_Method); - _fileInfoPopIDs.Add(k_7z_id_Block); - #endif - - #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES - for (unsigned i = 0; i < 5; i++) - _fileInfoPopIDs.Add(k_7z_id_PackedSize0 + i); - #endif - - #ifndef Z7_SFX - InsertToHead(_fileInfoPopIDs, NID::kMTime); - InsertToHead(_fileInfoPopIDs, NID::kPackInfo); - InsertToHead(_fileInfoPopIDs, NID::kSize); - InsertToHead(_fileInfoPopIDs, NID::kName); - #endif -} - -Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps)) -{ - *numProps = _fileInfoPopIDs.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) -{ - if (index >= _fileInfoPopIDs.Size()) - return E_INVALIDARG; - const UInt64 id = _fileInfoPopIDs[index]; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPropMap); i++) - { - const CPropMap &pr = kPropMap[i]; - if (pr.FilePropID == id) - { - *propID = pr.StatPropID; - *varType = pr.vt; - /* - const CStatProp &st = pr.StatProp; - *propID = st.PropID; - *varType = st.vt; - */ - /* - if (st.lpwstrName) - *name = ::SysAllocString(st.lpwstrName); - else - */ - *name = NULL; - return S_OK; - } - } - return E_INVALIDARG; -} - -}} +// 7zProperties.cpp + +#include "StdAfx.h" + +#include "7zHandler.h" +#include "7zProperties.h" + +namespace NArchive { +namespace N7z { + +struct CPropMap +{ + Byte FilePropID; + // CStatProp StatProp; + VARTYPE vt; + UInt32 StatPropID; +}; + +// #define STAT_PROP(name, id, vt) { name, id, vt } +#define STAT_PROP(name, id, vt) vt, id + +#define STAT_PROP2(id, vt) STAT_PROP(NULL, id, vt) + +#define k_7z_id_Encrypted 97 +#define k_7z_id_Method 98 +#define k_7z_id_Block 99 + +static const CPropMap kPropMap[] = +{ + { NID::kName, STAT_PROP2(kpidPath, VT_BSTR) }, + { NID::kSize, STAT_PROP2(kpidSize, VT_UI8) }, + { NID::kPackInfo, STAT_PROP2(kpidPackSize, VT_UI8) }, + + #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES +#define k_7z_id_PackedSize0 100 + { k_7z_id_PackedSize0 + 0, STAT_PROP("Pack0", kpidPackedSize0, VT_UI8) }, + { k_7z_id_PackedSize0 + 1, STAT_PROP("Pack1", kpidPackedSize1, VT_UI8) }, + { k_7z_id_PackedSize0 + 2, STAT_PROP("Pack2", kpidPackedSize2, VT_UI8) }, + { k_7z_id_PackedSize0 + 3, STAT_PROP("Pack3", kpidPackedSize3, VT_UI8) }, + { k_7z_id_PackedSize0 + 4, STAT_PROP("Pack4", kpidPackedSize4, VT_UI8) }, + #endif + + { NID::kCTime, STAT_PROP2(kpidCTime, VT_FILETIME) }, + { NID::kMTime, STAT_PROP2(kpidMTime, VT_FILETIME) }, + { NID::kATime, STAT_PROP2(kpidATime, VT_FILETIME) }, + { NID::kWinAttrib, STAT_PROP2(kpidAttrib, VT_UI4) }, + { NID::kStartPos, STAT_PROP2(kpidPosition, VT_UI8) }, + + { NID::kCRC, STAT_PROP2(kpidCRC, VT_UI4) }, + // { NID::kIsAux, STAT_PROP2(kpidIsAux, VT_BOOL) }, + { NID::kAnti, STAT_PROP2(kpidIsAnti, VT_BOOL) } + + #ifndef Z7_SFX + , { k_7z_id_Encrypted, STAT_PROP2(kpidEncrypted, VT_BOOL) } + , { k_7z_id_Method, STAT_PROP2(kpidMethod, VT_BSTR) } + , { k_7z_id_Block, STAT_PROP2(kpidBlock, VT_UI4) } + #endif +}; + +static void CopyOneItem(CRecordVector &src, + CRecordVector &dest, const UInt32 item) +{ + FOR_VECTOR (i, src) + if (src[i] == item) + { + dest.Add(item); + src.Delete(i); + return; + } +} + +static void RemoveOneItem(CRecordVector &src, const UInt32 item) +{ + FOR_VECTOR (i, src) + if (src[i] == item) + { + src.Delete(i); + return; + } +} + +static void InsertToHead(CRecordVector &dest, const UInt32 item) +{ + FOR_VECTOR (i, dest) + if (dest[i] == item) + { + dest.Delete(i); + break; + } + dest.Insert(0, item); +} + +#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id); + +void CHandler::FillPopIDs() +{ + _fileInfoPopIDs.Clear(); + + #ifdef Z7_7Z_VOL + if (_volumes.Size() < 1) + return; + const CVolume &volume = _volumes.Front(); + const CArchiveDatabaseEx &_db = volume.Database; + #endif + + CRecordVector fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs; + + RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); + RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); + /* + RemoveOneItem(fileInfoPopIDs, NID::kParent); + RemoveOneItem(fileInfoPopIDs, NID::kNtSecure); + */ + + COPY_ONE_ITEM(kName) + COPY_ONE_ITEM(kAnti) + COPY_ONE_ITEM(kSize) + COPY_ONE_ITEM(kPackInfo) + COPY_ONE_ITEM(kCTime) + COPY_ONE_ITEM(kMTime) + COPY_ONE_ITEM(kATime) + COPY_ONE_ITEM(kWinAttrib) + COPY_ONE_ITEM(kCRC) + COPY_ONE_ITEM(kComment) + + _fileInfoPopIDs += fileInfoPopIDs; + + #ifndef Z7_SFX + _fileInfoPopIDs.Add(k_7z_id_Encrypted); + _fileInfoPopIDs.Add(k_7z_id_Method); + _fileInfoPopIDs.Add(k_7z_id_Block); + #endif + + #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES + for (unsigned i = 0; i < 5; i++) + _fileInfoPopIDs.Add(k_7z_id_PackedSize0 + i); + #endif + + #ifndef Z7_SFX + InsertToHead(_fileInfoPopIDs, NID::kMTime); + InsertToHead(_fileInfoPopIDs, NID::kPackInfo); + InsertToHead(_fileInfoPopIDs, NID::kSize); + InsertToHead(_fileInfoPopIDs, NID::kName); + #endif +} + +Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps)) +{ + *numProps = _fileInfoPopIDs.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) +{ + if (index >= _fileInfoPopIDs.Size()) + return E_INVALIDARG; + const UInt64 id = _fileInfoPopIDs[index]; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPropMap); i++) + { + const CPropMap &pr = kPropMap[i]; + if (pr.FilePropID == id) + { + *propID = pr.StatPropID; + *varType = pr.vt; + /* + const CStatProp &st = pr.StatProp; + *propID = st.PropID; + *varType = st.vt; + */ + /* + if (st.lpwstrName) + *name = ::SysAllocString(st.lpwstrName); + else + */ + *name = NULL; + return S_OK; + } + } + return E_INVALIDARG; +} + +}} diff --git a/CPP/7zip/Archive/7z/7zProperties.h b/CPP/7zip/Archive/7z/7zProperties.h index 8a4221bd5..091c39b40 100644 --- a/CPP/7zip/Archive/7z/7zProperties.h +++ b/CPP/7zip/Archive/7z/7zProperties.h @@ -1,26 +1,26 @@ -// 7zProperties.h - -#ifndef ZIP7_INC_7Z_PROPERTIES_H -#define ZIP7_INC_7Z_PROPERTIES_H - -#include "../../PropID.h" - -namespace NArchive { -namespace N7z { - -// #define Z7_7Z_SHOW_PACK_STREAMS_SIZES // for debug - -#ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES -enum -{ - kpidPackedSize0 = kpidUserDefined, - kpidPackedSize1, - kpidPackedSize2, - kpidPackedSize3, - kpidPackedSize4 -}; -#endif - -}} - -#endif +// 7zProperties.h + +#ifndef ZIP7_INC_7Z_PROPERTIES_H +#define ZIP7_INC_7Z_PROPERTIES_H + +#include "../../PropID.h" + +namespace NArchive { +namespace N7z { + +// #define Z7_7Z_SHOW_PACK_STREAMS_SIZES // for debug + +#ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES +enum +{ + kpidPackedSize0 = kpidUserDefined, + kpidPackedSize1, + kpidPackedSize2, + kpidPackedSize3, + kpidPackedSize4 +}; +#endif + +}} + +#endif diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp index 7364f6445..1f11079e6 100644 --- a/CPP/7zip/Archive/7z/7zRegister.cpp +++ b/CPP/7zip/Archive/7z/7zRegister.cpp @@ -1,27 +1,27 @@ -// 7zRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "7zHandler.h" - -namespace NArchive { -namespace N7z { - -static Byte k_Signature_Dec[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}; - -REGISTER_ARC_IO_DECREMENT_SIG( - "7z", "7z", NULL, 7, - k_Signature_Dec, - 0, - NArcInfoFlags::kFindSignature - | NArcInfoFlags::kCTime - | NArcInfoFlags::kATime - | NArcInfoFlags::kMTime - | NArcInfoFlags::kMTime_Default - , TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows) - | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows) - , NULL) - -}} +// 7zRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "7zHandler.h" + +namespace NArchive { +namespace N7z { + +static Byte k_Signature_Dec[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}; + +REGISTER_ARC_IO_DECREMENT_SIG( + "7z", "7z", NULL, 7, + k_Signature_Dec, + 0, + NArcInfoFlags::kFindSignature + | NArcInfoFlags::kCTime + | NArcInfoFlags::kATime + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows) + , NULL) + +}} diff --git a/CPP/7zip/Archive/7z/7zSpecStream.cpp b/CPP/7zip/Archive/7z/7zSpecStream.cpp index 1cc0767d0..8b531bc7c 100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.cpp +++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp @@ -1,31 +1,31 @@ -// 7zSpecStream.cpp - -#include "StdAfx.h" - -#include "7zSpecStream.h" - -/* -Z7_COM7F_IMF(CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize; - const HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return result; -} - -Z7_COM7F_IMF(CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value)) -{ - if (!_getSubStreamSize) - return E_NOTIMPL; - return _getSubStreamSize->GetSubStreamSize(subStream, value); -} - -Z7_COM7F_IMF(CSequentialInStreamSizeCount2::GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream)) -{ - if (!_compressGetSubStreamSize) - return E_NOTIMPL; - return _compressGetSubStreamSize->GetNextInSubStream(streamIndexRes, stream); -} -*/ +// 7zSpecStream.cpp + +#include "StdAfx.h" + +#include "7zSpecStream.h" + +/* +Z7_COM7F_IMF(CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize; + const HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return result; +} + +Z7_COM7F_IMF(CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value)) +{ + if (!_getSubStreamSize) + return E_NOTIMPL; + return _getSubStreamSize->GetSubStreamSize(subStream, value); +} + +Z7_COM7F_IMF(CSequentialInStreamSizeCount2::GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream)) +{ + if (!_compressGetSubStreamSize) + return E_NOTIMPL; + return _compressGetSubStreamSize->GetNextInSubStream(streamIndexRes, stream); +} +*/ diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h index 3ea681fe8..78f631e43 100644 --- a/CPP/7zip/Archive/7z/7zSpecStream.h +++ b/CPP/7zip/Archive/7z/7zSpecStream.h @@ -1,49 +1,49 @@ -// 7zSpecStream.h - -#ifndef ZIP7_INC_7Z_SPEC_STREAM_H -#define ZIP7_INC_7Z_SPEC_STREAM_H - -#include "../../../Common/MyCom.h" - -#include "../../ICoder.h" - -/* -#define Z7_COM_QI_ENTRY_AG_2(i, sub0, sub) else if (iid == IID_ ## i) \ - { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ - { i *ti = this; *outObject = ti; } } - -class CSequentialInStreamSizeCount2 Z7_final: - public ISequentialInStream, - public ICompressGetSubStreamSize, - public ICompressInSubStreams, - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ISequentialInStream) - Z7_COM_QI_ENTRY(ICompressGetSubStreamSize) - Z7_COM_QI_ENTRY_AG_2(ISequentialInStream, _stream, _compressGetSubStreamSize) - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ISequentialInStream) - Z7_IFACE_COM7_IMP(ICompressGetSubStreamSize) - Z7_IFACE_COM7_IMP(ICompressInSubStreams) - - CMyComPtr _stream; - CMyComPtr _getSubStreamSize; - CMyComPtr _compressGetSubStreamSize; - UInt64 _size; -public: - void Init(ISequentialInStream *stream) - { - _size = 0; - _getSubStreamSize.Release(); - _compressGetSubStreamSize.Release(); - _stream = stream; - _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize); - _stream.QueryInterface(IID_ICompressInSubStreams, &_compressGetSubStreamSize); - } - UInt64 GetSize() const { return _size; } -}; -*/ - -#endif +// 7zSpecStream.h + +#ifndef ZIP7_INC_7Z_SPEC_STREAM_H +#define ZIP7_INC_7Z_SPEC_STREAM_H + +#include "../../../Common/MyCom.h" + +#include "../../ICoder.h" + +/* +#define Z7_COM_QI_ENTRY_AG_2(i, sub0, sub) else if (iid == IID_ ## i) \ + { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ + { i *ti = this; *outObject = ti; } } + +class CSequentialInStreamSizeCount2 Z7_final: + public ISequentialInStream, + public ICompressGetSubStreamSize, + public ICompressInSubStreams, + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ISequentialInStream) + Z7_COM_QI_ENTRY(ICompressGetSubStreamSize) + Z7_COM_QI_ENTRY_AG_2(ISequentialInStream, _stream, _compressGetSubStreamSize) + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ISequentialInStream) + Z7_IFACE_COM7_IMP(ICompressGetSubStreamSize) + Z7_IFACE_COM7_IMP(ICompressInSubStreams) + + CMyComPtr _stream; + CMyComPtr _getSubStreamSize; + CMyComPtr _compressGetSubStreamSize; + UInt64 _size; +public: + void Init(ISequentialInStream *stream) + { + _size = 0; + _getSubStreamSize.Release(); + _compressGetSubStreamSize.Release(); + _stream = stream; + _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize); + _stream.QueryInterface(IID_ICompressInSubStreams, &_compressGetSubStreamSize); + } + UInt64 GetSize() const { return _size; } +}; +*/ + +#endif diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp index b97b893cb..c8c5d269d 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.cpp +++ b/CPP/7zip/Archive/7z/7zUpdate.cpp @@ -1,3088 +1,3088 @@ -// 7zUpdate.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyLinux.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/Wildcard.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "../Common/ItemNameUtils.h" - -#include "7zDecode.h" -#include "7zEncode.h" -#include "7zFolderInStream.h" -#include "7zHandler.h" -#include "7zOut.h" -#include "7zUpdate.h" - -namespace NArchive { -namespace N7z { - -#define k_X86 k_BCJ - -struct CFilterMode -{ - UInt32 Id; - UInt32 Delta; // required File Size alignment, if Id is not k_Delta. - // (Delta == 0) means unknown alignment - UInt32 Offset; // for k_ARM64 / k_RISCV - // UInt32 AlignSizeOpt; // for k_ARM64 - - CFilterMode(): - Id(0), - Delta(0), - Offset(0) - // , AlignSizeOpt(0) - {} - - void ClearFilterMode() - { - Id = 0; - Delta = 0; - Offset = 0; - // AlignSizeOpt = 0; - } - - // it sets Delta as Align value, if Id is exe filter - // in another cases it sets Delta = 0, that - void SetDelta() - { - if (Id == k_IA64) - Delta = 16; - else if (Id == k_ARM64 || Id == k_ARM || Id == k_PPC || Id == k_SPARC) - Delta = 4; - else if (Id == k_ARMT || Id == k_RISCV) - Delta = 2; - else if (Id == k_BCJ || Id == k_BCJ2) - Delta = 1; // do we need it? - else - Delta = 0; - } -}; - - -/* ---------- PE ---------- */ - -#define MZ_SIG 0x5A4D - -#define PE_SIG 0x00004550 -#define PE_OptHeader_Magic_32 0x10B -#define PE_OptHeader_Magic_64 0x20B -// #define PE_SectHeaderSize 40 -// #define PE_SECT_EXECUTE 0x20000000 - -static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode) -{ - if (size < 512 || GetUi16(buf) != MZ_SIG) - return 0; - - const Byte *p; - UInt32 peOffset, optHeaderSize, filterId; - - peOffset = GetUi32(buf + 0x3C); - if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) - return 0; - p = buf + peOffset; - if (GetUi32(p) != PE_SIG) - return 0; - p += 4; - - const unsigned machine = GetUi16(p); - - switch (machine) - { - case 0x014C: - case 0x8664: filterId = k_X86; break; - case 0xAA64: filterId = k_ARM64; break; - - /* - IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE - IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE - IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE - Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2). - */ - - case 0x01C0: // WinCE old - case 0x01C2: filterId = k_ARM; break; // WinCE new - case 0x01C4: filterId = k_ARMT; break; // WinRT - - case 0x5032: // RISCV32 - case 0x5064: // RISCV64 - // case 0x5128: // RISCV128 - filterId = k_RISCV; break; - - case 0x0200: filterId = k_IA64; break; - default: return 0; - } - - const UInt32 numSections = GetUi16(p + 2); - optHeaderSize = GetUi16(p + 16); - if (optHeaderSize > (1 << 10)) - return 0; - - p += 20; /* headerSize */ - - switch (GetUi16(p)) - { - case PE_OptHeader_Magic_32: - case PE_OptHeader_Magic_64: - break; - default: - return 0; - } - - // Windows exe file sizes are not aligned for 4 KiB. - // So we can't use (CFilterMode::Offset != 0) in solid archives. - // So we just don't set Offset here. -#define NUM_SCAN_SECTIONS_MAX (1 << 6) -// #define EXE_SECTION_OFFSET_MAX (1 << 27) -// #define EXE_SECTION_SIZE_MIN (1 << 8) -// #define EXE_SECTION_SIZE_MAX (1 << 27) -#define PE_SectHeaderSize 40 -// #define PE_SECT_EXECUTE 0x20000000 - -/* - if (numSections > NUM_SCAN_SECTIONS_MAX) - return 0; -*/ - - if ((size_t)(p - buf) + optHeaderSize <= size) - { - p += optHeaderSize; -/* - // UInt32 numExeSections = 0; - // bool execute_finded = false; - // UInt32 sect_va = 0; - // UInt32 sect_size = 0; - // UInt32 sect_offset = 0; -*/ - if (numSections <= NUM_SCAN_SECTIONS_MAX) - if (machine == 0x8664) - for (UInt32 i = 0; i < numSections - ; i++, p += PE_SectHeaderSize) - { - // UInt32 characts, rawSize, offset; - if ((UInt32)(p - buf) + PE_SectHeaderSize > size) - { - // return 0; - break; - } - if (memcmp(p, ".a64xrm", 8) == 0) - { - // ARM64EC - filterId = k_ARM64; - break; - } -/* - rawSize = GetUi32(p + 16); - offset = GetUi32(p + 20); - characts = GetUi32(p + 36); - if (rawSize >= EXE_SECTION_SIZE_MIN && - rawSize <= EXE_SECTION_SIZE_MAX && - offset <= EXE_SECTION_OFFSET_MAX && - // offset < limit && - offset > 0) - { - if ((characts & PE_SECT_EXECUTE) != 0) - { - // execute_finded = true; - // sect_va = GetUi32(p + 12); - // sect_size = rawSize; - // sect_offset = offset; - break; - } - } -*/ - } - } - - /* - filterMode->Offset = 0; - if (filterId == k_ARM64) - { - // filterMode->AlignSizeOpt = (1 << 12); - // const UInt32 offs = (sect_va - sect_offset) & 0xFFF; - // if (offs != 0) - // filterMode->Offset = offs; // change it - } - */ - filterMode->Id = filterId; - return 1; -} - - -/* - Filters don't improve the compression ratio for relocatable object files (".o"). - But we can get compression ratio gain, if we compress object - files and executables in same solid block. - So we use filters for relocatable object files (".o"): -*/ -// #define Z7_7Z_CREATE_ARC_DISABLE_FILTER_FOR_OBJ - -/* ---------- ELF ---------- */ - -#define ELF_SIG 0x464C457F - -#define ELF_CLASS_32 1 -#define ELF_CLASS_64 2 - -#define ELF_DATA_2LSB 1 -#define ELF_DATA_2MSB 2 - -static UInt16 Get16(const Byte *p, BoolInt be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); } -static UInt32 Get32(const Byte *p, BoolInt be) { if (be) return GetBe32(p); return GetUi32(p); } -// static UInt64 Get64(const Byte *p, BoolInt be) { if (be) return GetBe64(p); return GetUi64(p); } - -static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode) -{ - BoolInt /* is32, */ be; - UInt32 filterId; - - if (size < 512 || buf[6] != 1) /* ver */ - return 0; - - if (GetUi32(buf) != ELF_SIG) - return 0; - - switch (buf[4]) - { - case ELF_CLASS_32: /* is32 = True; */ break; - case ELF_CLASS_64: /* is32 = False; */ break; - default: return 0; - } - - switch (buf[5]) - { - case ELF_DATA_2LSB: be = False; break; - case ELF_DATA_2MSB: be = True; break; - default: return 0; - } - -#ifdef Z7_7Z_CREATE_ARC_DISABLE_FILTER_FOR_OBJ -#define ELF_ET_REL 1 - if (Get16(buf + 0x10, be) == ELF_ET_REL) - return 0; -#endif - - switch (Get16(buf + 0x12, be)) - { - case 3: - case 6: - case 62: filterId = k_X86; break; - case 2: - case 18: - case 43: filterId = k_SPARC; break; - case 20: - case 21: if (!be) return 0; filterId = k_PPC; break; - case 40: if (be) return 0; filterId = k_ARM; break; - case 183: if (be) return 0; filterId = k_ARM64; break; - case 243: if (be) return 0; filterId = k_RISCV; break; - - /* Some IA-64 ELF executables have size that is not aligned for 16 bytes. - So we don't use IA-64 filter for IA-64 ELF */ - // case 50: if ( be) return 0; filterId = k_IA64; break; - - default: return 0; - } - - filterMode->Id = filterId; - return 1; -} - - - -/* ---------- Mach-O ---------- */ - -#define MACH_SIG_BE_32 0xCEFAEDFE -#define MACH_SIG_BE_64 0xCFFAEDFE -#define MACH_SIG_LE_32 0xFEEDFACE -#define MACH_SIG_LE_64 0xFEEDFACF - -#define MACH_ARCH_ABI64 (1 << 24) -#define MACH_MACHINE_386 7 -#define MACH_MACHINE_ARM 12 -#define MACH_MACHINE_SPARC 14 -#define MACH_MACHINE_PPC 18 -#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC) -#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386) -#define MACH_MACHINE_ARM64 (MACH_ARCH_ABI64 | MACH_MACHINE_ARM) - -static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode) -{ - UInt32 filterId, numCommands, commandsSize; - - if (size < 512) - return 0; - - BoolInt /* mode64, */ be; - switch (GetUi32(buf)) - { - case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break; - case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break; - case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break; - case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break; - default: return 0; - } - -#ifdef Z7_7Z_CREATE_ARC_DISABLE_FILTER_FOR_OBJ -#define MACH_TYPE_OBJECT 1 - if (Get32(buf + 0xC, be) == MACH_TYPE_OBJECT) - return 0; -#endif - - switch (Get32(buf + 4, be)) - { - case MACH_MACHINE_386: - case MACH_MACHINE_AMD64: filterId = k_X86; break; - case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break; - case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break; - case MACH_MACHINE_PPC: - case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break; - case MACH_MACHINE_ARM64: if ( be) return 0; filterId = k_ARM64; break; - default: return 0; - } - - numCommands = Get32(buf + 0x10, be); - commandsSize = Get32(buf + 0x14, be); - - if (commandsSize > (1 << 24) || numCommands > (1 << 18)) - return 0; - - filterMode->Id = filterId; - return 1; -} - - -/* ---------- WAV ---------- */ - -#define WAV_SUBCHUNK_fmt 0x20746D66 -#define WAV_SUBCHUNK_data 0x61746164 - -#define RIFF_SIG 0x46464952 - -static BoolInt Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode) -{ - UInt32 subChunkSize, pos; - if (size < 0x2C) - return False; - - if (GetUi32(buf + 0) != RIFF_SIG || - GetUi32(buf + 8) != 0x45564157 || // WAVE - GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt) - return False; - subChunkSize = GetUi32(buf + 0x10); - /* [0x14 = format] = 1 (PCM) */ - if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1) - return False; - - const unsigned numChannels = GetUi16(buf + 0x16); - const unsigned bitsPerSample = GetUi16(buf + 0x22); - if ((bitsPerSample & 0x7) != 0) - return False; - const UInt32 delta = (UInt32)numChannels * (bitsPerSample >> 3); - if (delta == 0 || delta > 256) - return False; - - pos = 0x14 + subChunkSize; - - const int kNumSubChunksTests = 10; - // Do we need to scan more than 3 sub-chunks? - for (int i = 0; i < kNumSubChunksTests; i++) - { - if (pos + 8 > size) - return False; - subChunkSize = GetUi32(buf + pos + 4); - if (GetUi32(buf + pos) == WAV_SUBCHUNK_data) - { - filterMode->Id = k_Delta; - filterMode->Delta = delta; - return True; - } - if (subChunkSize > (1 << 16)) - return False; - pos += subChunkSize + 8; - } - return False; -} - - -/* - filterMode->Delta will be set as: - = delta value : [1, 256] : for k_Delta - = 0 for another filters (branch filters) -*/ -static BoolInt ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode) -{ - filterMode->ClearFilterMode(); - - if (Parse_EXE(buf, size, filterMode)) return True; - if (Parse_ELF(buf, size, filterMode)) return True; - if (Parse_MACH(buf, size, filterMode)) return True; - return Parse_WAV(buf, size, filterMode); -} - - - - -struct CFilterMode2: public CFilterMode -{ - bool Encrypted; - unsigned GroupIndex; - - CFilterMode2(): Encrypted(false) {} - - int Compare(const CFilterMode2 &m) const - { - if (!Encrypted) - { - if (m.Encrypted) - return -1; - } - else if (!m.Encrypted) - return 1; - - const UInt32 id1 = Id; - const UInt32 id2 = m.Id; - /* - // we can change the order to place k_ARM64 files close to another exe files - if (id1 <= k_SPARC && - id2 <= k_SPARC) - { - #define k_ARM64_FOR_SORT 0x3030901 - if (id1 == k_ARM64) id1 = k_ARM64_FOR_SORT; - if (id2 == k_ARM64) id2 = k_ARM64_FOR_SORT; - } - */ - if (id1 < id2) return -1; - if (id1 > id2) return 1; - - if (Delta < m.Delta) return -1; - if (Delta > m.Delta) return 1; - - if (Offset < m.Offset) return -1; - if (Offset > m.Offset) return 1; - - /* we don't go here, because GetGroup() - and operator ==(const CFilterMode2 &m) - add only unique CFilterMode2:: { Id, Delta, Offset, Encrypted } items. - */ - /* - if (GroupIndex < m.GroupIndex) return -1; - if (GroupIndex > m.GroupIndex) return 1; - */ - return 0; - } - - bool operator ==(const CFilterMode2 &m) const - { - return Id == m.Id - && Delta == m.Delta - && Offset == m.Offset - && Encrypted == m.Encrypted; - } -}; - -static unsigned GetGroup(CRecordVector &filters, const CFilterMode2 &m) -{ - unsigned i; - for (i = 0; i < filters.Size(); i++) - { - const CFilterMode2 &m2 = filters[i]; - if (m == m2) - return i; - /* - if (m.Encrypted != m2.Encrypted) - { - if (!m.Encrypted) - break; - continue; - } - - if (m.Id < m2.Id) break; - if (m.Id != m2.Id) continue; - - if (m.Delta < m2.Delta) break; - if (m.Delta != m2.Delta) continue; - */ - } - // filters.Insert(i, m); - // return i; - return filters.Add(m); -} - -static inline bool Is86Filter(CMethodId m) -{ - return (m == k_BCJ || m == k_BCJ2); -} - -static inline bool IsExeFilter(CMethodId m) -{ - switch (m) - { - case k_ARM64: - case k_RISCV: - case k_BCJ: - case k_BCJ2: - case k_ARM: - case k_ARMT: - case k_PPC: - case k_SPARC: - case k_IA64: - return true; - default: break; - } - return false; -} - -static unsigned Get_FilterGroup_for_Folder( - CRecordVector &filters, const CFolderEx &f, bool extractFilter) -{ - CFilterMode2 m; - // m.Id = 0; - // m.Delta = 0; - // m.Offset = 0; - m.Encrypted = f.IsEncrypted(); - - if (extractFilter) - { - const CCoderInfo &coder = f.Coders[f.UnpackCoder]; - - if (coder.MethodID == k_Delta) - { - if (coder.Props.Size() == 1) - { - m.Delta = (unsigned)coder.Props[0] + 1; - m.Id = k_Delta; - } - } - else if (IsExeFilter(coder.MethodID)) - { - m.Id = (UInt32)coder.MethodID; - if (m.Id == k_BCJ2) - m.Id = k_BCJ; - m.SetDelta(); - if (m.Id == k_ARM64 || - m.Id == k_RISCV) - if (coder.Props.Size() == 4) - m.Offset = GetUi32(coder.Props); - } - } - - return GetGroup(filters, m); -} - - - - -static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, - UInt64 position, UInt64 size, ICompressProgressInfo *progress) -{ - RINOK(InStream_SeekSet(inStream, position)) - CMyComPtr2_Create streamSpec; - streamSpec->SetStream(inStream); - streamSpec->Init(size); - CMyComPtr2_Create copyCoder; - RINOK(copyCoder.Interface()->Code(streamSpec, outStream, NULL, NULL, progress)) - return (copyCoder->TotalSize == size ? S_OK : E_FAIL); -} - -/* -unsigned CUpdateItem::GetExtensionPos() const -{ - int slashPos = Name.ReverseFind_PathSepar(); - int dotPos = Name.ReverseFind_Dot(); - if (dotPos <= slashPos) - return Name.Len(); - return dotPos + 1; -} - -UString CUpdateItem::GetExtension() const -{ - return Name.Ptr(GetExtensionPos()); -} -*/ - -#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; } - -#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) - -/* -static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) -{ - size_t c1 = a1.GetCapacity(); - size_t c2 = a2.GetCapacity(); - RINOZ_COMP(c1, c2); - for (size_t i = 0; i < c1; i++) - RINOZ_COMP(a1[i], a2[i]); - return 0; -} - -static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) -{ - RINOZ_COMP(c1.NumInStreams, c2.NumInStreams); - RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams); - RINOZ_COMP(c1.MethodID, c2.MethodID); - return CompareBuffers(c1.Props, c2.Props); -} - -static int CompareBonds(const CBond &b1, const CBond &b2) -{ - RINOZ_COMP(b1.InIndex, b2.InIndex); - return MyCompare(b1.OutIndex, b2.OutIndex); -} - -static int CompareFolders(const CFolder &f1, const CFolder &f2) -{ - int s1 = f1.Coders.Size(); - int s2 = f2.Coders.Size(); - RINOZ_COMP(s1, s2); - int i; - for (i = 0; i < s1; i++) - RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); - s1 = f1.Bonds.Size(); - s2 = f2.Bonds.Size(); - RINOZ_COMP(s1, s2); - for (i = 0; i < s1; i++) - RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i])); - return 0; -} -*/ - -/* -static int CompareFiles(const CFileItem &f1, const CFileItem &f2) -{ - return CompareFileNames(f1.Name, f2.Name); -} -*/ - -struct CFolderRepack -{ - unsigned FolderIndex; - CNum NumCopyFiles; -}; - -/* -static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *) -{ - int i1 = p1->FolderIndex; - int i2 = p2->FolderIndex; - // In that version we don't want to parse folders here, so we don't compare folders - // probably it must be improved in future - // const CDbEx &db = *(const CDbEx *)param; - // RINOZ(CompareFolders( - // db.Folders[i1], - // db.Folders[i2])); - - return MyCompare(i1, i2); - - // RINOZ_COMP( - // db.NumUnpackStreamsVector[i1], - // db.NumUnpackStreamsVector[i2]); - // if (db.NumUnpackStreamsVector[i1] == 0) - // return 0; - // return CompareFiles( - // db.Files[db.FolderStartFileIndex[i1]], - // db.Files[db.FolderStartFileIndex[i2]]); -} -*/ - -/* - we sort empty files and dirs in such order: - - Dir.NonAnti (name sorted) - - File.NonAnti (name sorted) - - File.Anti (name sorted) - - Dir.Anti (reverse name sorted) -*/ - -static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param) -{ - const CObjectVector &updateItems = *(const CObjectVector *)param; - const CUpdateItem &u1 = updateItems[*p1]; - const CUpdateItem &u2 = updateItems[*p2]; - // NonAnti < Anti - if (u1.IsAnti != u2.IsAnti) - return (u1.IsAnti ? 1 : -1); - if (u1.IsDir != u2.IsDir) - { - // Dir.NonAnti < File < Dir.Anti - if (u1.IsDir) - return (u1.IsAnti ? 1 : -1); - return (u2.IsAnti ? -1 : 1); - } - int n = CompareFileNames(u1.Name, u2.Name); - return (u1.IsDir && u1.IsAnti) ? -n : n; -} - -static const char *g_Exts = - " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo" - " zip jar ear war msi" - " 3gp avi mov mpeg mpg mpe wmv" - " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" - " swf" - " chm hxi hxs" - " gif jpeg jpg jp2 png tiff bmp ico psd psp" - " awg ps eps cgm dxf svg vrml wmf emf ai md" - " cad dwg pps key sxi" - " max 3ds" - " iso bin nrg mdf img pdi tar cpio xpi" - " vfd vhd vud vmc vsv" - " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" - " inl inc idl acf asa" - " h hpp hxx c cpp cxx m mm go swift" - " rc java cs rs pas bas vb cls ctl frm dlg def" - " f77 f f90 f95" - " asm s" - " sql manifest dep" - " mak clw csproj vcproj sln dsp dsw" - " class" - " bat cmd bash sh" - " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" - " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs" - " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" - " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" - " abw afp cwk lwp wpd wps wpt wrf wri" - " abf afm bdf fon mgf otf pcf pfa snf ttf" - " dbf mdb nsf ntf wdb db fdb gdb" - " exe dll ocx vbx sfx sys tlb awx com obj lib out o so" - " pdb pch idb ncb opt"; - -static unsigned GetExtIndex(const char *ext) -{ - unsigned extIndex = 1; - const char *p = g_Exts; - for (;;) - { - char c = *p++; - if (c == 0) - return extIndex; - if (c == ' ') - continue; - unsigned pos = 0; - for (;;) - { - char c2 = ext[pos++]; - if (c2 == 0 && (c == 0 || c == ' ')) - return extIndex; - if (c != c2) - break; - c = *p++; - } - extIndex++; - for (;;) - { - if (c == 0) - return extIndex; - if (c == ' ') - break; - c = *p++; - } - } -} - -struct CRefItem -{ - const CUpdateItem *UpdateItem; - UInt32 Index; - unsigned ExtensionPos; - unsigned NamePos; - unsigned ExtensionIndex; - - CRefItem() {} - CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): - UpdateItem(&ui), - Index(index), - ExtensionPos(0), - NamePos(0), - ExtensionIndex(0) - { - if (sortByType) - { - const int slashPos = ui.Name.ReverseFind_PathSepar(); - NamePos = (unsigned)(slashPos + 1); - const int dotPos = ui.Name.ReverseFind_Dot(); - if (dotPos <= slashPos) - ExtensionPos = ui.Name.Len(); - else - { - ExtensionPos = (unsigned)(dotPos + 1); - if (ExtensionPos != ui.Name.Len()) - { - AString s; - for (unsigned pos = ExtensionPos;; pos++) - { - const wchar_t c = ui.Name[pos]; - if (c >= 0x80) - break; - if (c == 0) - { - ExtensionIndex = GetExtIndex(s); - break; - } - s.Add_Char((char)MyCharLower_Ascii((char)c)); - } - } - } - } - } -}; - -struct CSortParam -{ - // const CObjectVector *TreeFolders; - bool SortByType; -}; - -/* - we sort files in such order: - - Dir.NonAnti (name sorted) - - alt streams - - Dirs - - Dir.Anti (reverse name sorted) -*/ - - -static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) -{ - const CRefItem &a1 = *p1; - const CRefItem &a2 = *p2; - const CUpdateItem &u1 = *a1.UpdateItem; - const CUpdateItem &u2 = *a2.UpdateItem; - - /* - if (u1.IsAltStream != u2.IsAltStream) - return u1.IsAltStream ? 1 : -1; - */ - - // Actually there are no dirs that time. They were stored in other steps - // So that code is unused? - if (u1.IsDir != u2.IsDir) - return u1.IsDir ? 1 : -1; - if (u1.IsDir) - { - if (u1.IsAnti != u2.IsAnti) - return (u1.IsAnti ? 1 : -1); - int n = CompareFileNames(u1.Name, u2.Name); - return -n; - } - - // bool sortByType = *(bool *)param; - const CSortParam *sortParam = (const CSortParam *)param; - const bool sortByType = sortParam->SortByType; - if (sortByType) - { - RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex) - RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos))) - RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos))) - if (!u1.MTimeDefined && u2.MTimeDefined) return 1; - if (u1.MTimeDefined && !u2.MTimeDefined) return -1; - if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime) - RINOZ_COMP(u1.Size, u2.Size) - } - /* - int par1 = a1.UpdateItem->ParentFolderIndex; - int par2 = a2.UpdateItem->ParentFolderIndex; - const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1]; - const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2]; - - int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd; - int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd; - if (b1 < b2) - { - if (e1 <= b2) - return -1; - // p2 in p1 - int par = par2; - for (;;) - { - const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; - par = tf.Parent; - if (par == par1) - { - RINOZ(CompareFileNames(u1.Name, tf.Name)); - break; - } - } - } - else if (b2 < b1) - { - if (e2 <= b1) - return 1; - // p1 in p2 - int par = par1; - for (;;) - { - const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; - par = tf.Parent; - if (par == par2) - { - RINOZ(CompareFileNames(tf.Name, u2.Name)); - break; - } - } - } - */ - // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex); - RINOK(CompareFileNames(u1.Name, u2.Name)) - RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient) - RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive) - return 0; -} - -struct CSolidGroup -{ - CRecordVector Indices; - - CRecordVector folderRefs; -}; - -static const char * const g_Exe_Exts[] = -{ - "dll" - , "exe" - , "ocx" - , "sfx" - , "sys" -}; - -static const char * const g_ExeUnix_Exts[] = -{ - "so" - , "dylib" -}; - -static bool IsExt_Exe(const wchar_t *ext) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exe_Exts); i++) - if (StringsAreEqualNoCase_Ascii(ext, g_Exe_Exts[i])) - return true; - return false; -} - -/* -static bool IsExt_ExeUnix(const wchar_t *ext) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++) - if (StringsAreEqualNoCase_Ascii(ext, g_ExeUnix_Exts[i])) - return true; - return false; -} -*/ - -// we try to find "so" extension in such name: libstdc++.so.6.0.29 -static bool IsExt_ExeUnix_NumericAllowed(const UString &path) -{ - unsigned pos = path.Len(); - unsigned dotPos = pos; - for (;;) - { - if (pos == 0) - return false; - const wchar_t c = path[--pos]; - if (IS_PATH_SEPAR(c)) - return false; - if (c == '.') - { - const unsigned num = (dotPos - pos) - 1; - if (num < 1) - return false; - const wchar_t *cur = path.Ptr(pos + 1); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++) - { - const char *ext = g_ExeUnix_Exts[i]; - if (num == MyStringLen(ext)) - if (IsString1PrefixedByString2_NoCase_Ascii(cur, ext)) - return true; - } - const wchar_t *end; - ConvertStringToUInt32(cur, &end); - if ((size_t)(end - cur) != num) - return false; - dotPos = pos; - } - } -} - - -struct CAnalysis -{ - CMyComPtr Callback; - CByteBuffer Buffer; - - bool ParseWav; - bool ParseExe; - bool ParseExeUnix; - bool ParseNoExt; - bool ParseAll; - - /* - bool Need_ATime; - bool ATime_Defined; - FILETIME ATime; - */ - - CAnalysis(): - ParseWav(false), - ParseExe(false), - ParseExeUnix(false), - ParseNoExt(false), - ParseAll(false) - /* - , Need_ATime(false) - , ATime_Defined(false) - */ - {} - - HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); -}; - -static const size_t kAnalysisBufSize = 1 << 14; - -HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode) -{ - filterMode.Id = 0; - filterMode.Delta = 0; - filterMode.Offset = 0; - - CFilterMode filterModeTemp = filterMode; - - const int slashPos = ui.Name.ReverseFind_PathSepar(); - const int dotPos = ui.Name.ReverseFind_Dot(); - - // if (dotPos > slashPos) - { - bool needReadFile = ParseAll; - /* if (Callback) is not supported by client, - we still try to use file name extension to detect executable file */ - bool probablyIsSameIsa = false; - - if (!needReadFile || !Callback) - { - const wchar_t *ext = NULL; - if (dotPos > slashPos) - ext = ui.Name.Ptr((unsigned)(dotPos + 1)); - // 7-zip stores posix attributes in high 16 bits and sets (0x8000) flag - if (ui.Attrib & 0x8000) - { - const unsigned st_mode = ui.Attrib >> 16; - /* note: executable ".so" can be without execute permission, - and symbolic link to such ".so" file is possible */ - // st_mode = 00111; // for debug - /* in Linux we expect such permissions: - 0755 : for most executables - 0644 : for some ".so" files - 0777 : in WSL for all files. - We can try to exclude some such 0777 cases from analysis, - if there is non-executable extension. - */ - - if ((st_mode & ( - MY_LIN_S_IXUSR | - MY_LIN_S_IXGRP | - MY_LIN_S_IXOTH)) != 0 - && MY_LIN_S_ISREG(st_mode) - && (ui.Size >= (1u << 11))) - { - #ifndef _WIN32 - probablyIsSameIsa = true; - #endif - needReadFile = true; - } - } - - if (!needReadFile) - { - if (!ext) - needReadFile = ParseNoExt; - else - { - bool isUnixExt = false; - if (ParseExeUnix) - isUnixExt = IsExt_ExeUnix_NumericAllowed(ui.Name); - if (isUnixExt) - { - needReadFile = true; - #ifndef _WIN32 - probablyIsSameIsa = true; - #endif - } - else if (IsExt_Exe(ext)) - { - needReadFile = ParseExe; - #ifdef _WIN32 - probablyIsSameIsa = true; - #endif - } - else if (StringsAreEqualNoCase_Ascii(ext, "wav")) - { - if (!needReadFile) - needReadFile = ParseWav; - } - } - } - } - - if (needReadFile) - { - BoolInt parseRes = false; - if (Callback) - { - if (Buffer.Size() != kAnalysisBufSize) - Buffer.Alloc(kAnalysisBufSize); - CMyComPtr stream; - HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze); - if (result == S_OK && stream) - { - /* - if (Need_ATime) - { - // access time could be changed in analysis pass - CMyComPtr getProps; - stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); - if (getProps) - if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK) - ATime_Defined = true; - } - */ - size_t size = kAnalysisBufSize; - result = ReadStream(stream, Buffer, &size); - stream.Release(); - // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK)); - if (result == S_OK) - { - parseRes = ParseFile(Buffer, size, &filterModeTemp); - } - } - } // Callback - else if (probablyIsSameIsa) - { - #ifdef MY_CPU_X86_OR_AMD64 - filterModeTemp.Id = k_X86; - #endif - #ifdef MY_CPU_ARM64 - filterModeTemp.Id = k_ARM64; - #endif - #ifdef MY_CPU_RISCV - filterModeTemp.Id = k_RISCV; - #endif - #ifdef MY_CPU_SPARC - filterModeTemp.Id = k_SPARC; - #endif - parseRes = true; - } - - if (parseRes - && filterModeTemp.Id != k_Delta - && filterModeTemp.Delta == 0) - { - /* ParseFile() sets (filterModeTemp.Delta == 0) for all - methods except of k_Delta. */ - // it's not k_Delta - // So we call SetDelta() to set Delta - filterModeTemp.SetDelta(); - if (filterModeTemp.Delta > 1) - { - /* If file Size is not aligned, then branch filter - will not work for next file in solid block. - Maybe we should allow filter for non-aligned-size file in non-solid archives ? - */ - if (ui.Size % filterModeTemp.Delta != 0) - parseRes = false; - // windows exe files are not aligned for 4 KiB. - /* - else if (filterModeTemp.Id == k_ARM64 && filterModeTemp.Offset != 0) - { - if (ui.Size % (1 << 12) != 0) - { - // If Size is not aligned for 4 KiB, then Offset will not work for next file in solid block. - // so we place such file in group with (Offset==0). - filterModeTemp.Offset = 0; - } - } - */ - } - } - if (!parseRes) - filterModeTemp.ClearFilterMode(); - } - } - - filterMode = filterModeTemp; - return S_OK; -} - -static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m) -{ - m.Id = methodID; - m.NumStreams = numStreams; -} - - -// we add bond for mode.Methods[0] that is filter -static HRESULT AddBondForFilter(CCompressionMethodMode &mode) -{ - for (unsigned c = 1; c < mode.Methods.Size(); c++) - { - if (!mode.IsThereBond_to_Coder(c)) - { - CBond2 bond; - bond.OutCoder = 0; - bond.OutStream = 0; - bond.InCoder = c; - mode.Bonds.Add(bond); - return S_OK; - } - } - return E_INVALIDARG; -} - -/* -static HRESULT AddBondForFilter_if_ThereAreBonds(CCompressionMethodMode &mode) -{ - if (!mode.Bonds.IsEmpty()) - return AddBondForFilter(mode); - return S_OK; -} -*/ - -static HRESULT AddBcj2Methods(CCompressionMethodMode &mode) -{ - // mode.Methods[0] must be k_BCJ2 method ! - // mode.Methods[1] : we expect that there is at least one method after BCJ2 - - CMethodFull m; - GetMethodFull(k_LZMA, 1, m); - - m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20); - m.AddProp32(NCoderPropID::kNumFastBytes, 128); - m.AddProp32(NCoderPropID::kNumThreads, 1); - m.AddProp32(NCoderPropID::kLitPosBits, 2); - m.AddProp32(NCoderPropID::kLitContextBits, 0); - // m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2"); - - const unsigned methodIndex = mode.Methods.Size(); - - if (mode.Bonds.IsEmpty()) - { - for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++) - { - CBond2 bond; - bond.OutCoder = i; - bond.OutStream = 0; - bond.InCoder = i + 1; - mode.Bonds.Add(bond); - } - } - - mode.Methods.Add(m); - mode.Methods.Add(m); - - RINOK(AddBondForFilter(mode)) - CBond2 bond; - bond.OutCoder = 0; // index of BCJ2 coder - bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond); - bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond); - return S_OK; -} - - -static HRESULT MakeExeMethod(CCompressionMethodMode &mode, - const CFilterMode &filterMode, - const bool bcj2_IsAllowed, - const CUIntVector &disabledFilterIDs) -{ - if (mode.Filter_was_Inserted) - { - // filter was inserted, but bond for that filter was not added still. - const CMethodFull &m = mode.Methods[0]; - if (m.Id == k_BCJ2) - return AddBcj2Methods(mode); - if (!m.IsSimpleCoder()) - return E_NOTIMPL; - if (mode.Bonds.IsEmpty()) - return S_OK; - return AddBondForFilter(mode); - } - - if (filterMode.Id == 0) - return S_OK; - - unsigned nextCoder; - - const bool useBcj2 = bcj2_IsAllowed - && Is86Filter(filterMode.Id) - && disabledFilterIDs.FindInSorted(k_BCJ2) < 0; - - if (!useBcj2 && disabledFilterIDs.FindInSorted(filterMode.Id) >= 0) - { - // required filter is disabled, - // but we still can use information about data alignment. -#if 0 // 1 for debug - // we can return here, if we want default lzma properties - return S_OK; -#else - // we will try to change lzma/lzma2 properties - nextCoder = 0; - if (!mode.Bonds.IsEmpty()) - for (unsigned c = 0;; c++) - { - if (c == mode.Methods.Size()) - return S_OK; - if (!mode.IsThereBond_to_Coder(c)) - { - nextCoder = c; - break; - } - } -#endif - } - else - { - // we insert new filter method: - CMethodFull &m = mode.Methods.InsertNew(0); // 0 == index of new inserted item - { - // we move all coder indexes in bonds up for 1 position: - FOR_VECTOR (k, mode.Bonds) - { - CBond2 &bond = mode.Bonds[k]; - bond.InCoder++; - bond.OutCoder++; - } - } - if (useBcj2) - { - GetMethodFull(k_BCJ2, 4, m); - return AddBcj2Methods(mode); - } - - GetMethodFull(filterMode.Id, 1, m); - - if (filterMode.Id == k_Delta) - m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta); - else if (filterMode.Id == k_ARM64 - || filterMode.Id == k_RISCV) - { - // if (filterMode.Offset != 0) - m.AddProp32( - NCoderPropID::kDefaultProp, - // NCoderPropID::kBranchOffset, - filterMode.Offset); - } - - nextCoder = 1; - if (!mode.Bonds.IsEmpty()) - { - RINOK(AddBondForFilter(mode)) - nextCoder = mode.Bonds.Back().InCoder; - } - } - - if (nextCoder >= mode.Methods.Size()) - { - // we don't expect that case, if there was non-filter method. - // but we return S_OK to support filter-only case. - return S_OK; - } - - int alignBits = -1; - { - const UInt32 delta = filterMode.Delta; - if (delta == 0 || delta > 16) - { - // if (delta == 0) alignBits = GetAlignForFilterMethod(filterMode.Id); - } - else if ((delta & ((1 << 4) - 1)) == 0) alignBits = 4; - else if ((delta & ((1 << 3) - 1)) == 0) alignBits = 3; - else if ((delta & ((1 << 2) - 1)) == 0) alignBits = 2; - else if ((delta & ((1 << 1) - 1)) == 0) alignBits = 1; - // else alignBits = 0; - /* alignBits=0 is default mode for lzma/lzma2. - So we don't set alignBits=0 here. */ - } - if (alignBits <= 0) - return S_OK; - // (alignBits > 0) - CMethodFull &nextMethod = mode.Methods[nextCoder]; - if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2) - if (!nextMethod.Are_Lzma_Model_Props_Defined()) - { - if (alignBits > 2 || filterMode.Id == k_Delta) - nextMethod.AddProp32(NCoderPropID::kPosStateBits, (unsigned)alignBits); - const unsigned lc = (alignBits < 3) ? (unsigned)(3 - alignBits) : 0u; - nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc); - nextMethod.AddProp32(NCoderPropID::kLitPosBits, (unsigned)alignBits); - } - return S_OK; -} - - -static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2) -{ - file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined; - file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; - file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; - file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; - file2.IsAnti = ui.IsAnti; - // file2.IsAux = false; - file2.StartPosDefined = false; - // file2.StartPos = 0; -} - - -static void UpdateItem_To_FileItem(const CUpdateItem &ui, - CFileItem &file, CFileItem2 &file2) -{ - UpdateItem_To_FileItem2(ui, file2); - - file.Size = ui.Size; - file.IsDir = ui.IsDir; - file.HasStream = ui.HasStream(); - // file.IsAltStream = ui.IsAltStream; -} - - - -Z7_CLASS_IMP_COM_2( - CRepackInStreamWithSizes - , ISequentialInStream - , ICompressGetSubStreamSize -) - CMyComPtr _stream; - UInt64 _size; - const CBoolVector *_extractStatuses; - UInt32 _startIndex; -public: - const CDbEx *_db; - - void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses) - { - _startIndex = startIndex; - _extractStatuses = extractStatuses; - _size = 0; - _stream = stream; - } - UInt64 GetSize() const { return _size; } -}; - -Z7_COM7F_IMF(CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize; - const HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return result; -} - -Z7_COM7F_IMF(CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value)) -{ - *value = 0; - if (subStream >= _extractStatuses->Size()) - return S_FALSE; // E_FAIL; - const unsigned index = (unsigned)subStream; - if ((*_extractStatuses)[index]) - { - const CFileItem &fi = _db->Files[_startIndex + index]; - if (fi.HasStream) - *value = fi.Size; - } - return S_OK; -} - - -class CRepackStreamBase -{ -protected: - bool _needWrite; - bool _fileIsOpen; - bool _calcCrc; - UInt32 _crc; - UInt64 _rem; - - const CBoolVector *_extractStatuses; - UInt32 _startIndex; - unsigned _currentIndex; - - HRESULT OpenFile(); - HRESULT CloseFile(); - HRESULT ProcessEmptyFiles(); - -public: - const CDbEx *_db; - CMyComPtr _opCallback; - CMyComPtr _extractCallback; - - HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses); - HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } -}; - -HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses) -{ - _startIndex = startIndex; - _extractStatuses = extractStatuses; - - _currentIndex = 0; - _fileIsOpen = false; - - return ProcessEmptyFiles(); -} - -HRESULT CRepackStreamBase::OpenFile() -{ - UInt32 arcIndex = _startIndex + _currentIndex; - const CFileItem &fi = _db->Files[arcIndex]; - - _needWrite = (*_extractStatuses)[_currentIndex]; - if (_opCallback) - { - RINOK(_opCallback->ReportOperation( - NEventIndexType::kInArcIndex, arcIndex, - _needWrite ? - NUpdateNotifyOp::kRepack : - NUpdateNotifyOp::kSkip)) - } - - _crc = CRC_INIT_VAL; - _calcCrc = (fi.CrcDefined && !fi.IsDir); - - _fileIsOpen = true; - _rem = fi.Size; - return S_OK; -} - -const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002; - -HRESULT CRepackStreamBase::CloseFile() -{ - UInt32 arcIndex = _startIndex + _currentIndex; - const CFileItem &fi = _db->Files[arcIndex]; - _fileIsOpen = false; - _currentIndex++; - if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) - return S_OK; - - if (_extractCallback) - { - RINOK(_extractCallback->ReportExtractResult( - NEventIndexType::kInArcIndex, arcIndex, - NExtract::NOperationResult::kCRCError)) - } - // return S_FALSE; - return k_My_HRESULT_CRC_ERROR; -} - -HRESULT CRepackStreamBase::ProcessEmptyFiles() -{ - while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) - { - RINOK(OpenFile()) - RINOK(CloseFile()) - } - return S_OK; -} - - - -#ifndef Z7_ST - -class CFolderOutStream2 Z7_final: - public CRepackStreamBase, - public ISequentialOutStream, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(ISequentialOutStream) -public: - CMyComPtr _stream; -}; - -Z7_COM7F_IMF(CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - if (_fileIsOpen) - { - UInt32 cur = (size < _rem ? size : (UInt32)_rem); - HRESULT result = S_OK; - if (_needWrite) - result = _stream->Write(data, cur, &cur); - if (_calcCrc) - _crc = CrcUpdate(_crc, data, cur); - if (processedSize) - *processedSize += cur; - data = (const Byte *)data + cur; - size -= cur; - _rem -= cur; - if (_rem == 0) - { - RINOK(CloseFile()) - RINOK(ProcessEmptyFiles()) - } - RINOK(result) - if (cur == 0) - break; - continue; - } - - RINOK(ProcessEmptyFiles()) - if (_currentIndex == _extractStatuses->Size()) - { - // we don't support write cut here - return E_FAIL; - } - RINOK(OpenFile()) - } - - return S_OK; -} - -#endif - - - -static const UInt32 kTempBufSize = 1 << 16; - -class CFolderInStream2 Z7_final: - public CRepackStreamBase, - public ISequentialInStream, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(ISequentialInStream) - - Byte *_buf; -public: - CMyComPtr _inStream; - HRESULT Result; - - CFolderInStream2(): - Result(S_OK) - { - _buf = new Byte[kTempBufSize]; - } - - ~CFolderInStream2() - { - delete []_buf; - } - - void Init() { Result = S_OK; } -}; - -Z7_COM7F_IMF(CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - if (_fileIsOpen) - { - UInt32 cur = (size < _rem ? size : (UInt32)_rem); - - void *buf; - if (_needWrite) - buf = data; - else - { - buf = _buf; - if (cur > kTempBufSize) - cur = kTempBufSize; - } - - const HRESULT result = _inStream->Read(buf, cur, &cur); - _crc = CrcUpdate(_crc, buf, cur); - _rem -= cur; - - if (_needWrite) - { - data = (Byte *)data + cur; - size -= cur; - if (processedSize) - *processedSize += cur; - } - - if (result != S_OK) - Result = result; - - if (_rem == 0) - { - RINOK(CloseFile()) - RINOK(ProcessEmptyFiles()) - } - - RINOK(result) - - if (cur == 0) - return E_FAIL; - - continue; - } - - RINOK(ProcessEmptyFiles()) - if (_currentIndex == _extractStatuses->Size()) - { - return S_OK; - } - RINOK(OpenFile()) - } - - return S_OK; -} - - -class CThreadDecoder Z7_final - #ifndef Z7_ST - : public CVirtThread - #endif -{ -public: - CDecoder Decoder; - - CThreadDecoder(bool multiThreadMixer): - Decoder(multiThreadMixer) - { - #ifndef Z7_ST - if (multiThreadMixer) - { - MtMode = false; - NumThreads = 1; - FosSpec = new CFolderOutStream2; - Fos = FosSpec; - Result = E_FAIL; - } - #endif - // UnpackSize = 0; - // send_UnpackSize = false; - } - - #ifndef Z7_ST - - bool dataAfterEnd_Error; - HRESULT Result; - CMyComPtr InStream; - - CFolderOutStream2 *FosSpec; - CMyComPtr Fos; - - UInt64 StartPos; - const CFolders *Folders; - unsigned FolderIndex; - - // bool send_UnpackSize; - // UInt64 UnpackSize; - - #ifndef Z7_NO_CRYPTO - CMyComPtr getTextPassword; - #endif - - DECL_EXTERNAL_CODECS_LOC_VARS_DECL - - #ifndef Z7_ST - bool MtMode; - UInt32 NumThreads; - #endif - - - ~CThreadDecoder() Z7_DESTRUCTOR_override - { - /* WaitThreadFinish() will be called in ~CVirtThread(). - But we need WaitThreadFinish() call before - destructors of this class members. - */ - CVirtThread::WaitThreadFinish(); - } -private: - virtual void Execute() Z7_override; - - #endif -}; - -#ifndef Z7_ST - -void CThreadDecoder::Execute() -{ - try - { - #ifndef Z7_NO_CRYPTO - bool isEncrypted = false; - bool passwordIsDefined = false; - UString password; - #endif - - dataAfterEnd_Error = false; - - Result = Decoder.Decode( - EXTERNAL_CODECS_LOC_VARS - InStream, - StartPos, - *Folders, FolderIndex, - - // send_UnpackSize ? &UnpackSize : NULL, - NULL, // unpackSize : FULL unpack - - Fos, - NULL, // compressProgress - - NULL // *inStreamMainRes - , dataAfterEnd_Error - - Z7_7Z_DECODER_CRYPRO_VARS - #ifndef Z7_ST - , MtMode, NumThreads, - 0 // MemUsage - #endif - - ); - } - catch(...) - { - Result = E_FAIL; - } - - /* - if (Result == S_OK) - Result = FosSpec->CheckFinishedState(); - */ - FosSpec->_stream.Release(); -} - -#endif - -#ifndef Z7_NO_CRYPTO - -Z7_CLASS_IMP_NOQIB_1( - CCryptoGetTextPassword - , ICryptoGetTextPassword -) -public: - UString Password; -}; - -Z7_COM7F_IMF(CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)) -{ - return StringToBstr(Password, password); -} - -#endif - - -static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2) -{ - file = inDb.Files[index]; - file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); - file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime); - file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime); - file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos); - file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib); - file2.IsAnti = inDb.IsItemAnti(index); - // file2.IsAux = inDb.IsItemAux(index); -} - -HRESULT Update( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, - const CDbEx *db, - CObjectVector &updateItems, - // const CObjectVector &treeFolders, - // const CUniqBlocks &secureBlocks, - ISequentialOutStream *seqOutStream, - IArchiveUpdateCallback *updateCallback, - const CUpdateOptions &options) -{ - UInt64 numSolidFiles = options.NumSolidFiles; - if (numSolidFiles == 0) - numSolidFiles = 1; - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveUpdateCallbackFile, - opCallback, updateCallback) - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveExtractCallbackMessage2, - extractCallback, updateCallback) - - /* - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveUpdateCallbackArcProp, - reportArcProp, updateCallback) - */ - - // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); - - CMyComPtr v_StreamSetRestriction; - { - Z7_DECL_CMyComPtr_QI_FROM( - IOutStream, - outStream, seqOutStream) - if (!outStream) - return E_NOTIMPL; - const UInt64 sfxBlockSize = (db && !options.RemoveSfxBlock) ? - db->ArcInfo.StartPosition: 0; - seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&v_StreamSetRestriction); - if (v_StreamSetRestriction) - { - UInt64 offset = 0; - RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &offset)) - RINOK(v_StreamSetRestriction->SetRestriction( - outStream ? offset + sfxBlockSize : 0, - outStream ? offset + sfxBlockSize + k_StartHeadersRewriteSize : 0)) - } - outStream.Release(); - if (sfxBlockSize != 0) - { - RINOK(WriteRange(inStream, seqOutStream, 0, sfxBlockSize, NULL)) - } - } - - CIntArr fileIndexToUpdateIndexMap; - UInt64 complexity = 0; - bool isThere_UnknownSize = false; - UInt64 inSizeForReduce2 = 0; - - #ifndef Z7_NO_CRYPTO - bool needEncryptedRepack = false; - #endif - - CRecordVector filters; - CObjectVector groups; - - #ifndef Z7_ST - bool thereAreRepacks = false; - #endif - - bool useFilters = options.UseFilters; - if (useFilters) - { - const CCompressionMethodMode &method = *options.Method; - - FOR_VECTOR (i, method.Methods) - { - /* IsFilterMethod() knows only built-in codecs - FIXME: we should check IsFilter status for external filters too */ - if (IsFilterMethod(method.Methods[i].Id)) - { - useFilters = false; - break; - } - } - } - - if (db) - { - fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); - unsigned i; - - for (i = 0; i < db->Files.Size(); i++) - fileIndexToUpdateIndexMap[i] = -1; - - for (i = 0; i < updateItems.Size(); i++) - { - int index = updateItems[i].IndexInArchive; - if (index != -1) - fileIndexToUpdateIndexMap[(unsigned)index] = (int)i; - } - - for (i = 0; i < db->NumFolders; i++) - { - CNum indexInFolder = 0; - CNum numCopyItems = 0; - const CNum numUnpackStreams = db->NumUnpackStreamsVector[i]; - UInt64 repackSize = 0; - - for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++) - { - if (fi >= db->Files.Size()) - return E_FAIL; - - const CFileItem &file = db->Files[fi]; - if (file.HasStream) - { - indexInFolder++; - const int updateIndex = fileIndexToUpdateIndexMap[fi]; - if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData) - { - numCopyItems++; - repackSize += file.Size; - } - } - } - - if (numCopyItems == 0) - continue; - - CFolderRepack rep; - rep.FolderIndex = i; - rep.NumCopyFiles = numCopyItems; - CFolderEx f; - db->ParseFolderEx(i, f); - - #ifndef Z7_NO_CRYPTO - const bool isEncrypted = f.IsEncrypted(); - #endif - const bool needCopy = (numCopyItems == numUnpackStreams); - const bool extractFilter = (useFilters || needCopy); - - const unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f, extractFilter); - - while (groupIndex >= groups.Size()) - groups.AddNew(); - - groups[groupIndex].folderRefs.Add(rep); - - if (needCopy) - complexity += db->GetFolderFullPackSize(i); - else - { - #ifndef Z7_ST - thereAreRepacks = true; - #endif - complexity += repackSize; - if (inSizeForReduce2 < repackSize) - inSizeForReduce2 = repackSize; - #ifndef Z7_NO_CRYPTO - if (isEncrypted) - needEncryptedRepack = true; - #endif - } - } - } - - UInt64 inSizeForReduce = 0; - { - const bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0); - FOR_VECTOR (i, updateItems) - { - const CUpdateItem &ui = updateItems[i]; - if (ui.NewData) - { - if (ui.Size == (UInt64)(Int64)-1) - isThere_UnknownSize = true; - else - { - complexity += ui.Size; - if (isSolid) - inSizeForReduce += ui.Size; - else if (inSizeForReduce < ui.Size) - inSizeForReduce = ui.Size; - } - } - } - } - - if (isThere_UnknownSize) - inSizeForReduce = (UInt64)(Int64)-1; - else - RINOK(updateCallback->SetTotal(complexity)) - - if (inSizeForReduce < inSizeForReduce2) - inSizeForReduce = inSizeForReduce2; - - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - #ifndef Z7_ST - - CStreamBinder sb; - /* - if (options.MultiThreadMixer) - { - RINOK(sb.CreateEvents()); - } - */ - - #endif - - CThreadDecoder threadDecoder(options.MultiThreadMixer); - - #ifndef Z7_ST - if (options.MultiThreadMixer && thereAreRepacks) - { - #ifdef Z7_EXTERNAL_CODECS - threadDecoder._externalCodecs = _externalCodecs; - #endif - const WRes wres = threadDecoder.Create(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - #endif - - { - CAnalysis analysis; - // analysis.Need_ATime = options.Need_ATime; - int analysisLevel = options.AnalysisLevel; - // (analysisLevel < 0) means default level (5) - if (analysisLevel < 0) - analysisLevel = 5; - if (analysisLevel != 0) - { - analysis.Callback = opCallback; - analysis.ParseWav = true; - if (analysisLevel >= 5) - { - analysis.ParseExe = true; - analysis.ParseExeUnix = true; - // analysis.ParseNoExt = true; - if (analysisLevel >= 7) - { - analysis.ParseNoExt = true; - if (analysisLevel >= 9) - analysis.ParseAll = true; - } - } - } - - // ---------- Split files to groups ---------- - - const CCompressionMethodMode &method = *options.Method; - - FOR_VECTOR (i, updateItems) - { - const CUpdateItem &ui = updateItems[i]; - if (!ui.NewData || !ui.HasStream()) - continue; - - CFilterMode2 fm; - if (useFilters) - { - // analysis.ATime_Defined = false; - RINOK(analysis.GetFilterGroup(i, ui, fm)) - /* - if (analysis.ATime_Defined) - { - ui.ATime = FILETIME_To_UInt64(analysis.ATime); - ui.ATime_WasReadByAnalysis = true; - } - */ - } - fm.Encrypted = method.PasswordIsDefined; - - const unsigned groupIndex = GetGroup(filters, fm); - while (groupIndex >= groups.Size()) - groups.AddNew(); - groups[groupIndex].Indices.Add(i); - } - } - - - #ifndef Z7_NO_CRYPTO - - CCryptoGetTextPassword *getPasswordSpec = NULL; - CMyComPtr getTextPassword; - if (needEncryptedRepack) - { - getPasswordSpec = new CCryptoGetTextPassword; - getTextPassword = getPasswordSpec; - - #ifndef Z7_ST - threadDecoder.getTextPassword = getPasswordSpec; - #endif - - if (options.Method->PasswordIsDefined) - getPasswordSpec->Password = options.Method->Password; - else - { - Z7_DECL_CMyComPtr_QI_FROM( - ICryptoGetTextPassword, - getDecoderPassword, updateCallback) - if (!getDecoderPassword) - return E_NOTIMPL; - CMyComBSTR password; - RINOK(getDecoderPassword->CryptoGetTextPassword(&password)) - if (password) - getPasswordSpec->Password = password; - } - } - - #endif - - // ---------- Compress ---------- - - COutArchive archive; - CArchiveDatabaseOut newDatabase; - - RINOK(archive.Create_and_WriteStartPrefix(seqOutStream)) - - /* - CIntVector treeFolderToArcIndex; - treeFolderToArcIndex.Reserve(treeFolders.Size()); - for (i = 0; i < treeFolders.Size(); i++) - treeFolderToArcIndex.Add(-1); - // ---------- Write Tree (only AUX dirs) ---------- - for (i = 1; i < treeFolders.Size(); i++) - { - const CTreeFolder &treeFolder = treeFolders[i]; - CFileItem file; - CFileItem2 file2; - file2.Init(); - int secureID = 0; - if (treeFolder.UpdateItemIndex < 0) - { - // we can store virtual dir item wuthout attrib, but we want all items have attrib. - file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY); - file2.IsAux = true; - } - else - { - const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex]; - // if item is not dir, then it's parent for alt streams. - // we will write such items later - if (!ui.IsDir) - continue; - secureID = ui.SecureIndex; - if (ui.NewProps) - UpdateItem_To_FileItem(ui, file, file2); - else - GetFile(*db, ui.IndexInArchive, file, file2); - } - file.Size = 0; - file.HasStream = false; - file.IsDir = true; - file.Parent = treeFolder.Parent; - - treeFolderToArcIndex[i] = newDatabase.Files.Size(); - newDatabase.AddFile(file, file2, treeFolder.Name); - - if (totalSecureDataSize != 0) - newDatabase.SecureIDs.Add(secureID); - } - */ - - { - /* ---------- Write non-AUX dirs and Empty files ---------- */ - CUIntVector emptyRefs; - - unsigned i; - - for (i = 0; i < updateItems.Size(); i++) - { - const CUpdateItem &ui = updateItems[i]; - if (ui.NewData) - { - if (ui.HasStream()) - continue; - } - else if (ui.IndexInArchive != -1 && db->Files[(unsigned)ui.IndexInArchive].HasStream) - continue; - /* - if (ui.TreeFolderIndex >= 0) - continue; - */ - emptyRefs.Add(i); - } - - emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); - - for (i = 0; i < emptyRefs.Size(); i++) - { - const CUpdateItem &ui = updateItems[emptyRefs[i]]; - CFileItem file; - CFileItem2 file2; - UString name; - if (ui.NewProps) - { - UpdateItem_To_FileItem(ui, file, file2); - file.CrcDefined = false; - name = ui.Name; - } - else - { - GetFile(*db, (unsigned)ui.IndexInArchive, file, file2); - db->GetPath((unsigned)ui.IndexInArchive, name); - } - - /* - if (totalSecureDataSize != 0) - newDatabase.SecureIDs.Add(ui.SecureIndex); - file.Parent = ui.ParentFolderIndex; - */ - newDatabase.AddFile(file, file2, name); - } - } - - lps->ProgressOffset = 0; - - { - // ---------- Sort Filters ---------- - FOR_VECTOR (i, filters) - { - filters[i].GroupIndex = i; - } - filters.Sort2(); - } - - for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++) - { - const CFilterMode2 &filterMode = filters[groupIndex]; - - CCompressionMethodMode method = *options.Method; - { - const HRESULT res = MakeExeMethod(method, filterMode, - // bcj2_IsAllowed: - #ifdef Z7_ST - false - #else - options.MaxFilter && options.MultiThreadMixer - #endif - , options.DisabledFilterIDs); - - RINOK(res) - } - - if (filterMode.Encrypted) - { - if (!method.PasswordIsDefined) - { - #ifndef Z7_NO_CRYPTO - if (getPasswordSpec) - method.Password = getPasswordSpec->Password; - #endif - method.PasswordIsDefined = true; - } - } - else - { - method.PasswordIsDefined = false; - method.Password.Empty(); - } - - CEncoder encoder(method); - - // ---------- Repack and copy old solid blocks ---------- - - const CSolidGroup &group = groups[filterMode.GroupIndex]; - - FOR_VECTOR (folderRefIndex, group.folderRefs) - { - const CFolderRepack &rep = group.folderRefs[folderRefIndex]; - - const unsigned folderIndex = rep.FolderIndex; - - const CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; - - if (rep.NumCopyFiles == numUnpackStreams) - { - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, - NUpdateNotifyOp::kReplicate)) - - // ---------- Copy old solid block ---------- - { - CNum indexInFolder = 0; - for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) - { - if (db->Files[fi].HasStream) - { - indexInFolder++; - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, (UInt32)fi, - NUpdateNotifyOp::kReplicate)) - } - } - } - } - - const UInt64 packSize = db->GetFolderFullPackSize(folderIndex); - RINOK(WriteRange(inStream, archive.SeqStream, - db->GetFolderStreamPos(folderIndex, 0), packSize, lps)) - lps->ProgressOffset += packSize; - - const unsigned folderIndex_New = newDatabase.Folders.Size(); - CFolder &folder = newDatabase.Folders.AddNew(); - // v23.01: we copy FolderCrc, if FolderCrc was used - if (db->FolderCRCs.ValidAndDefined(folderIndex)) - newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, - true, db->FolderCRCs.Vals[folderIndex]); - - db->ParseFolderInfo(folderIndex, folder); - const CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; - FOR_VECTOR (j, folder.PackStreams) - { - newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); - // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); - // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); - } - - size_t indexStart = db->FoToCoderUnpackSizes[folderIndex]; - const size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; - for (; indexStart < indexEnd; indexStart++) - newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes.ConstData()[indexStart]); - } - else - { - // ---------- Repack old solid block ---------- - - CBoolVector extractStatuses; - - CNum indexInFolder = 0; - - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, - NUpdateNotifyOp::kRepack)) - } - - /* We could reduce data size of decoded folder, if we don't need to repack - last files in folder. But the gain in speed is small in most cases. - So we unpack full folder. */ - - UInt64 sizeToEncode = 0; - - /* - UInt64 importantUnpackSize = 0; - unsigned numImportantFiles = 0; - UInt64 decodeSize = 0; - */ - - for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) - { - bool needExtract = false; - const CFileItem &file = db->Files[fi]; - - if (file.HasStream) - { - indexInFolder++; - const int updateIndex = fileIndexToUpdateIndexMap[fi]; - if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData) - needExtract = true; - // decodeSize += file.Size; - } - - extractStatuses.Add(needExtract); - if (needExtract) - { - sizeToEncode += file.Size; - /* - numImportantFiles = extractStatuses.Size(); - importantUnpackSize = decodeSize; - */ - } - } - - // extractStatuses.DeleteFrom(numImportantFiles); - - unsigned startPackIndex = newDatabase.PackSizes.Size(); - UInt64 curUnpackSize; - { - CMyComPtr sbInStream; - CRepackStreamBase *repackBase; - CFolderInStream2 *FosSpec2 = NULL; - - CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes; - CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; - { - #ifndef Z7_ST - if (options.MultiThreadMixer) - { - repackBase = threadDecoder.FosSpec; - CMyComPtr sbOutStream; - sb.CreateStreams2(sbInStream, sbOutStream); - RINOK(sb.Create_ReInit()) - - threadDecoder.FosSpec->_stream = sbOutStream; - - threadDecoder.InStream = inStream; - threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); - threadDecoder.Folders = (const CFolders *)db; - threadDecoder.FolderIndex = folderIndex; - - // threadDecoder.UnpackSize = importantUnpackSize; - // threadDecoder.send_UnpackSize = true; - } - else - #endif - { - FosSpec2 = new CFolderInStream2; - FosSpec2->Init(); - sbInStream = FosSpec2; - repackBase = FosSpec2; - - #ifndef Z7_NO_CRYPTO - bool isEncrypted = false; - bool passwordIsDefined = false; - UString password; - #endif - - CMyComPtr decodedStream; - bool dataAfterEnd_Error = false; - - const HRESULT res = threadDecoder.Decoder.Decode( - EXTERNAL_CODECS_LOC_VARS - inStream, - db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);, - *db, folderIndex, - // &importantUnpackSize, // *unpackSize - NULL, // *unpackSize : FULL unpack - - NULL, // *outStream - NULL, // *compressProgress - - &decodedStream - , dataAfterEnd_Error - - Z7_7Z_DECODER_CRYPRO_VARS - #ifndef Z7_ST - , false // mtMode - , 1 // numThreads - , 0 // memUsage - #endif - ); - - RINOK(res) - if (!decodedStream) - return E_FAIL; - - FosSpec2->_inStream = decodedStream; - } - - repackBase->_db = db; - repackBase->_opCallback = opCallback; - repackBase->_extractCallback = extractCallback; - - UInt32 startIndex = db->FolderStartFileIndex[folderIndex]; - RINOK(repackBase->Init(startIndex, &extractStatuses)) - - inStreamSizeCountSpec->_db = db; - inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses); - - #ifndef Z7_ST - if (options.MultiThreadMixer) - { - WRes wres = threadDecoder.Start(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - #endif - } - - // curUnpackSize = sizeToEncode; - - HRESULT encodeRes = encoder.Encode1( - EXTERNAL_CODECS_LOC_VARS - inStreamSizeCount, - // NULL, - &inSizeForReduce, - sizeToEncode, // expectedDataSize - newDatabase.Folders.AddNew(), - // newDatabase.CoderUnpackSizes, curUnpackSize, - archive.SeqStream, newDatabase.PackSizes, lps); - - if (encodeRes == k_My_HRESULT_CRC_ERROR) - return E_FAIL; - - curUnpackSize = inStreamSizeCountSpec->GetSize(); - - if (encodeRes == S_OK) - { - encoder.Encode_Post(curUnpackSize, newDatabase.CoderUnpackSizes); - } - - #ifndef Z7_ST - if (options.MultiThreadMixer) - { - // 16.00: hang was fixed : for case if decoding was not finished. - // We close CBinderInStream and it calls CStreamBinder::CloseRead() - inStreamSizeCount.Release(); - sbInStream.Release(); - - { - const WRes wres = threadDecoder.WaitExecuteFinish(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - - const HRESULT decodeRes = threadDecoder.Result; - // if (res == k_My_HRESULT_CRC_ERROR) - if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error) - { - if (extractCallback) - { - RINOK(extractCallback->ReportExtractResult( - NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex], - // NEventIndexType::kBlockIndex, (UInt32)folderIndex, - (decodeRes != S_OK ? - NExtract::NOperationResult::kDataError : - NExtract::NOperationResult::kDataAfterEnd))) - } - if (decodeRes != S_OK) - return E_FAIL; - } - RINOK(decodeRes) - if (encodeRes == S_OK) - if (sb.ProcessedSize != sizeToEncode) - encodeRes = E_FAIL; - } - else - #endif - { - if (FosSpec2->Result == S_FALSE) - { - if (extractCallback) - { - RINOK(extractCallback->ReportExtractResult( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, - NExtract::NOperationResult::kDataError)) - } - return E_FAIL; - } - RINOK(FosSpec2->Result) - } - - RINOK(encodeRes) - RINOK(repackBase->CheckFinishedState()) - - if (curUnpackSize != sizeToEncode) - return E_FAIL; - } - - for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) - lps->OutSize += newDatabase.PackSizes[startPackIndex]; - lps->InSize += curUnpackSize; - } - - newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); - - CNum indexInFolder = 0; - for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) - { - if (db->Files[fi].HasStream) - { - indexInFolder++; - const int updateIndex = fileIndexToUpdateIndexMap[fi]; - if (updateIndex >= 0) - { - const CUpdateItem &ui = updateItems[(unsigned)updateIndex]; - if (ui.NewData) - continue; - - UString name; - CFileItem file; - CFileItem2 file2; - GetFile(*db, fi, file, file2); - - if (ui.NewProps) - { - UpdateItem_To_FileItem2(ui, file2); - file.IsDir = ui.IsDir; - name = ui.Name; - } - else - db->GetPath(fi, name); - - /* - file.Parent = ui.ParentFolderIndex; - if (ui.TreeFolderIndex >= 0) - treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); - if (totalSecureDataSize != 0) - newDatabase.SecureIDs.Add(ui.SecureIndex); - */ - newDatabase.AddFile(file, file2, name); - } - } - } - } - - - // ---------- Compress files to new solid blocks ---------- - - const unsigned numFiles = group.Indices.Size(); - if (numFiles == 0) - continue; - CRecordVector refItems; - refItems.ClearAndSetSize(numFiles); - // bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1 - const bool sortByType = options.UseTypeSorting; - - unsigned i; - - for (i = 0; i < numFiles; i++) - refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); - - CSortParam sortParam; - // sortParam.TreeFolders = &treeFolders; - sortParam.SortByType = sortByType; - refItems.Sort(CompareUpdateItems, (void *)&sortParam); - - CObjArray indices(numFiles); - - for (i = 0; i < numFiles; i++) - { - const UInt32 index = refItems[i].Index; - indices[i] = index; - /* - const CUpdateItem &ui = updateItems[index]; - CFileItem file; - if (ui.NewProps) - UpdateItem_To_FileItem(ui, file); - else - file = db.Files[ui.IndexInArchive]; - if (file.IsAnti || file.IsDir) - return E_FAIL; - newDatabase.Files.Add(file); - */ - } - - for (i = 0; i < numFiles;) - { - UInt64 totalSize = 0; - unsigned numSubFiles; - - const wchar_t *prevExtension = NULL; - - for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) - { - const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; - totalSize += ui.Size; - if (totalSize > options.NumSolidBytes) - break; - if (options.SolidExtension) - { - const int slashPos = ui.Name.ReverseFind_PathSepar(); - const int dotPos = ui.Name.ReverseFind_Dot(); - const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : (unsigned)(dotPos + 1)); - if (numSubFiles == 0) - prevExtension = ext; - else if (!StringsAreEqualNoCase(ext, prevExtension)) - break; - } - } - - if (numSubFiles < 1) - numSubFiles = 1; - - RINOK(lps->SetCur()) - - /* - const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size(); - - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, - NUpdateNotifyOp::kAdd)); - } - */ - - - CMyComPtr2_Create inStreamSpec; // solidInStream; - - // inStreamSpec->_reportArcProp = reportArcProp; - - inStreamSpec->Need_CTime = options.Need_CTime; - inStreamSpec->Need_ATime = options.Need_ATime; - inStreamSpec->Need_MTime = options.Need_MTime; - inStreamSpec->Need_Attrib = options.Need_Attrib; - // inStreamSpec->Need_Crc = options.Need_Crc; - - inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); - - unsigned startPackIndex = newDatabase.PackSizes.Size(); - // UInt64 curFolderUnpackSize = totalSize; - // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug - const UInt64 expectedDataSize = totalSize; - - // const unsigned folderIndex_New = newDatabase.Folders.Size(); - - RINOK(encoder.Encode1( - EXTERNAL_CODECS_LOC_VARS - inStreamSpec, - // NULL, - &inSizeForReduce, - expectedDataSize, // expected size - newDatabase.Folders.AddNew(), - // newDatabase.CoderUnpackSizes, curFolderUnpackSize, - archive.SeqStream, newDatabase.PackSizes, lps)) - - if (!inStreamSpec->WasFinished()) - return E_FAIL; - - /* - if (inStreamSpec->Need_FolderCrc) - newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, - true, inStreamSpec->GetFolderCrc()); - */ - - const UInt64 curFolderUnpackSize = inStreamSpec->Get_TotalSize_for_Coder(); - encoder.Encode_Post(curFolderUnpackSize, newDatabase.CoderUnpackSizes); - - UInt64 packSize = 0; - // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex; - for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) - packSize += newDatabase.PackSizes[startPackIndex]; - lps->OutSize += packSize; - - // for () - // newDatabase.PackCRCsDefined.Add(false); - // newDatabase.PackCRCs.Add(0); - - CNum numUnpackStreams = 0; - UInt64 skippedSize = 0; - UInt64 procSize = 0; - // unsigned numProcessedFiles = 0; - - for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) - { - const CUpdateItem &ui = updateItems[indices[i + subIndex]]; - CFileItem file; - CFileItem2 file2; - UString name; - if (ui.NewProps) - { - UpdateItem_To_FileItem(ui, file, file2); - name = ui.Name; - } - else - { - GetFile(*db, (unsigned)ui.IndexInArchive, file, file2); - db->GetPath((unsigned)ui.IndexInArchive, name); - } - if (file2.IsAnti || file.IsDir) - return E_FAIL; - - /* - CFileItem &file = newDatabase.Files[ - startFileIndexInDatabase + i + subIndex]; - */ - if (!inStreamSpec->Processed[subIndex]) - { - // we don't add file here - skippedSize += ui.Size; - continue; // comment it for debug - // name += ".locked"; // for debug - } - - // if (inStreamSpec->Need_Crc) - file.Crc = inStreamSpec->CRCs[subIndex]; - file.Size = inStreamSpec->Sizes[subIndex]; - - procSize += file.Size; - // if (file.Size >= 0) // for debug: test purposes - if (file.Size != 0) - { - file.CrcDefined = true; // inStreamSpec->Need_Crc; - file.HasStream = true; - numUnpackStreams++; - } - else - { - file.CrcDefined = false; - file.HasStream = false; - } - - if (inStreamSpec->TimesDefined[subIndex]) - { - if (inStreamSpec->Need_CTime) - { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; } - if (inStreamSpec->Need_ATime - // && !ui.ATime_WasReadByAnalysis - ) - { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; } - if (inStreamSpec->Need_MTime) - { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; } - if (inStreamSpec->Need_Attrib) - { - file2.AttribDefined = true; - file2.Attrib = inStreamSpec->Attribs[subIndex]; - } - } - - /* - file.Parent = ui.ParentFolderIndex; - if (ui.TreeFolderIndex >= 0) - treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); - if (totalSecureDataSize != 0) - newDatabase.SecureIDs.Add(ui.SecureIndex); - */ - /* - if (reportArcProp) - { - RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size, - file.CrcDefined ? &file.Crc : NULL)) - } - */ - - // numProcessedFiles++; - newDatabase.AddFile(file, file2, name); - } - - /* - // for debug: - // we can write crc to folders area, if folder contains only one file - if (numUnpackStreams == 1 && numSubFiles == 1) - { - const CFileItem &file = newDatabase.Files.Back(); - if (file.CrcDefined) - newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, true, file.Crc); - } - */ - - /* - // it's optional check to ensure that sizes are correct - if (inStreamSpec->TotalSize_for_Coder != curFolderUnpackSize) - return E_FAIL; - */ - // if (inStreamSpec->AlignLog == 0) - { - if (procSize != curFolderUnpackSize) - return E_FAIL; - } - // else - { - /* - { - const CFolder &old = newDatabase.Folders.Back(); - CFolder &folder = newDatabase.Folders.AddNew(); - { - const unsigned numBonds = old.Bonds.Size(); - folder.Bonds.SetSize(numBonds + 1); - for (unsigned k = 0; k < numBonds; k++) - folder.Bonds[k] = old.Bonds[k]; - CBond &bond = folder.Bonds[numBonds]; - bond.PackIndex = 0; - bond.UnpackIndex = 0; - } - { - const unsigned numCoders = old.Coders.Size(); - folder.Coders.SetSize(numCoders + 1); - for (unsigned k = 0; k < numCoders; k++) - folder.Coders[k] = old.Coders[k]; - CCoderInfo &cod = folder.Coders[numCoders]; - cod.Props.Alloc(1); - cod.Props[0] = (Byte)inStreamSpec->AlignLog; - cod.NumStreams = 1; - } - { - const unsigned numPackStreams = old.Coders.Size(); - folder.Coders.SetSize(numPackStreams); - for (unsigned k = 0; k < numPackStreams; k++) - folder.PackStreams[k] = old.PackStreams[k]; - } - } - newDatabase.Folders.Delete(newDatabase.Folders.Size() - 2); - */ - } - - - lps->InSize += procSize; - // lps->InSize += curFolderUnpackSize; - - // numUnpackStreams = 0 is very bad case for locked files - // v3.13 doesn't understand it. - newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); - i += numSubFiles; - - if (skippedSize != 0 && complexity >= skippedSize) - { - complexity -= skippedSize; - RINOK(updateCallback->SetTotal(complexity)) - } - - /* - if (reportArcProp) - { - PROPVARIANT prop; - prop.vt = VT_EMPTY; - prop.wReserved1 = 0; - { - NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles); - RINOK(reportArcProp->ReportProp( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop)); - } - { - NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize); - RINOK(reportArcProp->ReportProp( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop)); - } - { - NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize); - RINOK(reportArcProp->ReportProp( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop)); - } - { - NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams); - RINOK(reportArcProp->ReportProp( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop)); - } - RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK)); - } - */ - /* - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kBlockIndex, (UInt32)folderIndex, - NUpdateNotifyOp::kOpFinished)); - } - */ - } - } - - RINOK(lps->SetCur()) - - /* - fileIndexToUpdateIndexMap.ClearAndFree(); - groups.ClearAndFree(); - */ - - /* - for (i = 0; i < newDatabase.Files.Size(); i++) - { - CFileItem &file = newDatabase.Files[i]; - file.Parent = treeFolderToArcIndex[file.Parent]; - } - - if (totalSecureDataSize != 0) - { - newDatabase.SecureBuf.SetCapacity(totalSecureDataSize); - size_t pos = 0; - newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size()); - for (i = 0; i < secureBlocks.Sorted.Size(); i++) - { - const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; - size_t size = buf.GetCapacity(); - if (size != 0) - memcpy(newDatabase.SecureBuf + pos, buf, size); - newDatabase.SecureSizes.Add((UInt32)size); - pos += size; - } - } - */ - - { - const unsigned numFolders = newDatabase.Folders.Size(); - if (newDatabase.NumUnpackStreamsVector.Size() != numFolders - || newDatabase.FolderUnpackCRCs.Defs.Size() > numFolders) - return E_FAIL; - newDatabase.FolderUnpackCRCs.if_NonEmpty_FillResidue_with_false(numFolders); - } - - updateItems.ClearAndFree(); - newDatabase.ReserveDown(); - - if (opCallback) - RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader)) - - RINOK(archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS - newDatabase, options.HeaderMethod, options.HeaderOptions)) - - if (v_StreamSetRestriction) - RINOK(v_StreamSetRestriction->SetRestriction(0, 0)) - - return S_OK; -} - -}} +// 7zUpdate.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyLinux.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/Wildcard.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "7zDecode.h" +#include "7zEncode.h" +#include "7zFolderInStream.h" +#include "7zHandler.h" +#include "7zOut.h" +#include "7zUpdate.h" + +namespace NArchive { +namespace N7z { + +#define k_X86 k_BCJ + +struct CFilterMode +{ + UInt32 Id; + UInt32 Delta; // required File Size alignment, if Id is not k_Delta. + // (Delta == 0) means unknown alignment + UInt32 Offset; // for k_ARM64 / k_RISCV + // UInt32 AlignSizeOpt; // for k_ARM64 + + CFilterMode(): + Id(0), + Delta(0), + Offset(0) + // , AlignSizeOpt(0) + {} + + void ClearFilterMode() + { + Id = 0; + Delta = 0; + Offset = 0; + // AlignSizeOpt = 0; + } + + // it sets Delta as Align value, if Id is exe filter + // in another cases it sets Delta = 0, that + void SetDelta() + { + if (Id == k_IA64) + Delta = 16; + else if (Id == k_ARM64 || Id == k_ARM || Id == k_PPC || Id == k_SPARC) + Delta = 4; + else if (Id == k_ARMT || Id == k_RISCV) + Delta = 2; + else if (Id == k_BCJ || Id == k_BCJ2) + Delta = 1; // do we need it? + else + Delta = 0; + } +}; + + +/* ---------- PE ---------- */ + +#define MZ_SIG 0x5A4D + +#define PE_SIG 0x00004550 +#define PE_OptHeader_Magic_32 0x10B +#define PE_OptHeader_Magic_64 0x20B +// #define PE_SectHeaderSize 40 +// #define PE_SECT_EXECUTE 0x20000000 + +static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + if (size < 512 || GetUi16(buf) != MZ_SIG) + return 0; + + const Byte *p; + UInt32 peOffset, optHeaderSize, filterId; + + peOffset = GetUi32(buf + 0x3C); + if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) + return 0; + p = buf + peOffset; + if (GetUi32(p) != PE_SIG) + return 0; + p += 4; + + const unsigned machine = GetUi16(p); + + switch (machine) + { + case 0x014C: + case 0x8664: filterId = k_X86; break; + case 0xAA64: filterId = k_ARM64; break; + + /* + IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE + IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE + IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE + Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2). + */ + + case 0x01C0: // WinCE old + case 0x01C2: filterId = k_ARM; break; // WinCE new + case 0x01C4: filterId = k_ARMT; break; // WinRT + + case 0x5032: // RISCV32 + case 0x5064: // RISCV64 + // case 0x5128: // RISCV128 + filterId = k_RISCV; break; + + case 0x0200: filterId = k_IA64; break; + default: return 0; + } + + const UInt32 numSections = GetUi16(p + 2); + optHeaderSize = GetUi16(p + 16); + if (optHeaderSize > (1 << 10)) + return 0; + + p += 20; /* headerSize */ + + switch (GetUi16(p)) + { + case PE_OptHeader_Magic_32: + case PE_OptHeader_Magic_64: + break; + default: + return 0; + } + + // Windows exe file sizes are not aligned for 4 KiB. + // So we can't use (CFilterMode::Offset != 0) in solid archives. + // So we just don't set Offset here. +#define NUM_SCAN_SECTIONS_MAX (1 << 6) +// #define EXE_SECTION_OFFSET_MAX (1 << 27) +// #define EXE_SECTION_SIZE_MIN (1 << 8) +// #define EXE_SECTION_SIZE_MAX (1 << 27) +#define PE_SectHeaderSize 40 +// #define PE_SECT_EXECUTE 0x20000000 + +/* + if (numSections > NUM_SCAN_SECTIONS_MAX) + return 0; +*/ + + if ((size_t)(p - buf) + optHeaderSize <= size) + { + p += optHeaderSize; +/* + // UInt32 numExeSections = 0; + // bool execute_finded = false; + // UInt32 sect_va = 0; + // UInt32 sect_size = 0; + // UInt32 sect_offset = 0; +*/ + if (numSections <= NUM_SCAN_SECTIONS_MAX) + if (machine == 0x8664) + for (UInt32 i = 0; i < numSections + ; i++, p += PE_SectHeaderSize) + { + // UInt32 characts, rawSize, offset; + if ((UInt32)(p - buf) + PE_SectHeaderSize > size) + { + // return 0; + break; + } + if (memcmp(p, ".a64xrm", 8) == 0) + { + // ARM64EC + filterId = k_ARM64; + break; + } +/* + rawSize = GetUi32(p + 16); + offset = GetUi32(p + 20); + characts = GetUi32(p + 36); + if (rawSize >= EXE_SECTION_SIZE_MIN && + rawSize <= EXE_SECTION_SIZE_MAX && + offset <= EXE_SECTION_OFFSET_MAX && + // offset < limit && + offset > 0) + { + if ((characts & PE_SECT_EXECUTE) != 0) + { + // execute_finded = true; + // sect_va = GetUi32(p + 12); + // sect_size = rawSize; + // sect_offset = offset; + break; + } + } +*/ + } + } + + /* + filterMode->Offset = 0; + if (filterId == k_ARM64) + { + // filterMode->AlignSizeOpt = (1 << 12); + // const UInt32 offs = (sect_va - sect_offset) & 0xFFF; + // if (offs != 0) + // filterMode->Offset = offs; // change it + } + */ + filterMode->Id = filterId; + return 1; +} + + +/* + Filters don't improve the compression ratio for relocatable object files (".o"). + But we can get compression ratio gain, if we compress object + files and executables in same solid block. + So we use filters for relocatable object files (".o"): +*/ +// #define Z7_7Z_CREATE_ARC_DISABLE_FILTER_FOR_OBJ + +/* ---------- ELF ---------- */ + +#define ELF_SIG 0x464C457F + +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 + +#define ELF_DATA_2LSB 1 +#define ELF_DATA_2MSB 2 + +static UInt16 Get16(const Byte *p, BoolInt be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); } +static UInt32 Get32(const Byte *p, BoolInt be) { if (be) return GetBe32(p); return GetUi32(p); } +// static UInt64 Get64(const Byte *p, BoolInt be) { if (be) return GetBe64(p); return GetUi64(p); } + +static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + BoolInt /* is32, */ be; + UInt32 filterId; + + if (size < 512 || buf[6] != 1) /* ver */ + return 0; + + if (GetUi32(buf) != ELF_SIG) + return 0; + + switch (buf[4]) + { + case ELF_CLASS_32: /* is32 = True; */ break; + case ELF_CLASS_64: /* is32 = False; */ break; + default: return 0; + } + + switch (buf[5]) + { + case ELF_DATA_2LSB: be = False; break; + case ELF_DATA_2MSB: be = True; break; + default: return 0; + } + +#ifdef Z7_7Z_CREATE_ARC_DISABLE_FILTER_FOR_OBJ +#define ELF_ET_REL 1 + if (Get16(buf + 0x10, be) == ELF_ET_REL) + return 0; +#endif + + switch (Get16(buf + 0x12, be)) + { + case 3: + case 6: + case 62: filterId = k_X86; break; + case 2: + case 18: + case 43: filterId = k_SPARC; break; + case 20: + case 21: if (!be) return 0; filterId = k_PPC; break; + case 40: if (be) return 0; filterId = k_ARM; break; + case 183: if (be) return 0; filterId = k_ARM64; break; + case 243: if (be) return 0; filterId = k_RISCV; break; + + /* Some IA-64 ELF executables have size that is not aligned for 16 bytes. + So we don't use IA-64 filter for IA-64 ELF */ + // case 50: if ( be) return 0; filterId = k_IA64; break; + + default: return 0; + } + + filterMode->Id = filterId; + return 1; +} + + + +/* ---------- Mach-O ---------- */ + +#define MACH_SIG_BE_32 0xCEFAEDFE +#define MACH_SIG_BE_64 0xCFFAEDFE +#define MACH_SIG_LE_32 0xFEEDFACE +#define MACH_SIG_LE_64 0xFEEDFACF + +#define MACH_ARCH_ABI64 (1 << 24) +#define MACH_MACHINE_386 7 +#define MACH_MACHINE_ARM 12 +#define MACH_MACHINE_SPARC 14 +#define MACH_MACHINE_PPC 18 +#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC) +#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386) +#define MACH_MACHINE_ARM64 (MACH_ARCH_ABI64 | MACH_MACHINE_ARM) + +static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + UInt32 filterId, numCommands, commandsSize; + + if (size < 512) + return 0; + + BoolInt /* mode64, */ be; + switch (GetUi32(buf)) + { + case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break; + case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break; + case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break; + case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break; + default: return 0; + } + +#ifdef Z7_7Z_CREATE_ARC_DISABLE_FILTER_FOR_OBJ +#define MACH_TYPE_OBJECT 1 + if (Get32(buf + 0xC, be) == MACH_TYPE_OBJECT) + return 0; +#endif + + switch (Get32(buf + 4, be)) + { + case MACH_MACHINE_386: + case MACH_MACHINE_AMD64: filterId = k_X86; break; + case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break; + case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break; + case MACH_MACHINE_PPC: + case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break; + case MACH_MACHINE_ARM64: if ( be) return 0; filterId = k_ARM64; break; + default: return 0; + } + + numCommands = Get32(buf + 0x10, be); + commandsSize = Get32(buf + 0x14, be); + + if (commandsSize > (1 << 24) || numCommands > (1 << 18)) + return 0; + + filterMode->Id = filterId; + return 1; +} + + +/* ---------- WAV ---------- */ + +#define WAV_SUBCHUNK_fmt 0x20746D66 +#define WAV_SUBCHUNK_data 0x61746164 + +#define RIFF_SIG 0x46464952 + +static BoolInt Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + UInt32 subChunkSize, pos; + if (size < 0x2C) + return False; + + if (GetUi32(buf + 0) != RIFF_SIG || + GetUi32(buf + 8) != 0x45564157 || // WAVE + GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt) + return False; + subChunkSize = GetUi32(buf + 0x10); + /* [0x14 = format] = 1 (PCM) */ + if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1) + return False; + + const unsigned numChannels = GetUi16(buf + 0x16); + const unsigned bitsPerSample = GetUi16(buf + 0x22); + if ((bitsPerSample & 0x7) != 0) + return False; + const UInt32 delta = (UInt32)numChannels * (bitsPerSample >> 3); + if (delta == 0 || delta > 256) + return False; + + pos = 0x14 + subChunkSize; + + const int kNumSubChunksTests = 10; + // Do we need to scan more than 3 sub-chunks? + for (int i = 0; i < kNumSubChunksTests; i++) + { + if (pos + 8 > size) + return False; + subChunkSize = GetUi32(buf + pos + 4); + if (GetUi32(buf + pos) == WAV_SUBCHUNK_data) + { + filterMode->Id = k_Delta; + filterMode->Delta = delta; + return True; + } + if (subChunkSize > (1 << 16)) + return False; + pos += subChunkSize + 8; + } + return False; +} + + +/* + filterMode->Delta will be set as: + = delta value : [1, 256] : for k_Delta + = 0 for another filters (branch filters) +*/ +static BoolInt ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode) +{ + filterMode->ClearFilterMode(); + + if (Parse_EXE(buf, size, filterMode)) return True; + if (Parse_ELF(buf, size, filterMode)) return True; + if (Parse_MACH(buf, size, filterMode)) return True; + return Parse_WAV(buf, size, filterMode); +} + + + + +struct CFilterMode2: public CFilterMode +{ + bool Encrypted; + unsigned GroupIndex; + + CFilterMode2(): Encrypted(false) {} + + int Compare(const CFilterMode2 &m) const + { + if (!Encrypted) + { + if (m.Encrypted) + return -1; + } + else if (!m.Encrypted) + return 1; + + const UInt32 id1 = Id; + const UInt32 id2 = m.Id; + /* + // we can change the order to place k_ARM64 files close to another exe files + if (id1 <= k_SPARC && + id2 <= k_SPARC) + { + #define k_ARM64_FOR_SORT 0x3030901 + if (id1 == k_ARM64) id1 = k_ARM64_FOR_SORT; + if (id2 == k_ARM64) id2 = k_ARM64_FOR_SORT; + } + */ + if (id1 < id2) return -1; + if (id1 > id2) return 1; + + if (Delta < m.Delta) return -1; + if (Delta > m.Delta) return 1; + + if (Offset < m.Offset) return -1; + if (Offset > m.Offset) return 1; + + /* we don't go here, because GetGroup() + and operator ==(const CFilterMode2 &m) + add only unique CFilterMode2:: { Id, Delta, Offset, Encrypted } items. + */ + /* + if (GroupIndex < m.GroupIndex) return -1; + if (GroupIndex > m.GroupIndex) return 1; + */ + return 0; + } + + bool operator ==(const CFilterMode2 &m) const + { + return Id == m.Id + && Delta == m.Delta + && Offset == m.Offset + && Encrypted == m.Encrypted; + } +}; + +static unsigned GetGroup(CRecordVector &filters, const CFilterMode2 &m) +{ + unsigned i; + for (i = 0; i < filters.Size(); i++) + { + const CFilterMode2 &m2 = filters[i]; + if (m == m2) + return i; + /* + if (m.Encrypted != m2.Encrypted) + { + if (!m.Encrypted) + break; + continue; + } + + if (m.Id < m2.Id) break; + if (m.Id != m2.Id) continue; + + if (m.Delta < m2.Delta) break; + if (m.Delta != m2.Delta) continue; + */ + } + // filters.Insert(i, m); + // return i; + return filters.Add(m); +} + +static inline bool Is86Filter(CMethodId m) +{ + return (m == k_BCJ || m == k_BCJ2); +} + +static inline bool IsExeFilter(CMethodId m) +{ + switch (m) + { + case k_ARM64: + case k_RISCV: + case k_BCJ: + case k_BCJ2: + case k_ARM: + case k_ARMT: + case k_PPC: + case k_SPARC: + case k_IA64: + return true; + default: break; + } + return false; +} + +static unsigned Get_FilterGroup_for_Folder( + CRecordVector &filters, const CFolderEx &f, bool extractFilter) +{ + CFilterMode2 m; + // m.Id = 0; + // m.Delta = 0; + // m.Offset = 0; + m.Encrypted = f.IsEncrypted(); + + if (extractFilter) + { + const CCoderInfo &coder = f.Coders[f.UnpackCoder]; + + if (coder.MethodID == k_Delta) + { + if (coder.Props.Size() == 1) + { + m.Delta = (unsigned)coder.Props[0] + 1; + m.Id = k_Delta; + } + } + else if (IsExeFilter(coder.MethodID)) + { + m.Id = (UInt32)coder.MethodID; + if (m.Id == k_BCJ2) + m.Id = k_BCJ; + m.SetDelta(); + if (m.Id == k_ARM64 || + m.Id == k_RISCV) + if (coder.Props.Size() == 4) + m.Offset = GetUi32(coder.Props); + } + } + + return GetGroup(filters, m); +} + + + + +static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, + UInt64 position, UInt64 size, ICompressProgressInfo *progress) +{ + RINOK(InStream_SeekSet(inStream, position)) + CMyComPtr2_Create streamSpec; + streamSpec->SetStream(inStream); + streamSpec->Init(size); + CMyComPtr2_Create copyCoder; + RINOK(copyCoder.Interface()->Code(streamSpec, outStream, NULL, NULL, progress)) + return (copyCoder->TotalSize == size ? S_OK : E_FAIL); +} + +/* +unsigned CUpdateItem::GetExtensionPos() const +{ + int slashPos = Name.ReverseFind_PathSepar(); + int dotPos = Name.ReverseFind_Dot(); + if (dotPos <= slashPos) + return Name.Len(); + return dotPos + 1; +} + +UString CUpdateItem::GetExtension() const +{ + return Name.Ptr(GetExtensionPos()); +} +*/ + +#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; } + +#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) + +/* +static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) +{ + size_t c1 = a1.GetCapacity(); + size_t c2 = a2.GetCapacity(); + RINOZ_COMP(c1, c2); + for (size_t i = 0; i < c1; i++) + RINOZ_COMP(a1[i], a2[i]); + return 0; +} + +static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) +{ + RINOZ_COMP(c1.NumInStreams, c2.NumInStreams); + RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams); + RINOZ_COMP(c1.MethodID, c2.MethodID); + return CompareBuffers(c1.Props, c2.Props); +} + +static int CompareBonds(const CBond &b1, const CBond &b2) +{ + RINOZ_COMP(b1.InIndex, b2.InIndex); + return MyCompare(b1.OutIndex, b2.OutIndex); +} + +static int CompareFolders(const CFolder &f1, const CFolder &f2) +{ + int s1 = f1.Coders.Size(); + int s2 = f2.Coders.Size(); + RINOZ_COMP(s1, s2); + int i; + for (i = 0; i < s1; i++) + RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); + s1 = f1.Bonds.Size(); + s2 = f2.Bonds.Size(); + RINOZ_COMP(s1, s2); + for (i = 0; i < s1; i++) + RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i])); + return 0; +} +*/ + +/* +static int CompareFiles(const CFileItem &f1, const CFileItem &f2) +{ + return CompareFileNames(f1.Name, f2.Name); +} +*/ + +struct CFolderRepack +{ + unsigned FolderIndex; + CNum NumCopyFiles; +}; + +/* +static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *) +{ + int i1 = p1->FolderIndex; + int i2 = p2->FolderIndex; + // In that version we don't want to parse folders here, so we don't compare folders + // probably it must be improved in future + // const CDbEx &db = *(const CDbEx *)param; + // RINOZ(CompareFolders( + // db.Folders[i1], + // db.Folders[i2])); + + return MyCompare(i1, i2); + + // RINOZ_COMP( + // db.NumUnpackStreamsVector[i1], + // db.NumUnpackStreamsVector[i2]); + // if (db.NumUnpackStreamsVector[i1] == 0) + // return 0; + // return CompareFiles( + // db.Files[db.FolderStartFileIndex[i1]], + // db.Files[db.FolderStartFileIndex[i2]]); +} +*/ + +/* + we sort empty files and dirs in such order: + - Dir.NonAnti (name sorted) + - File.NonAnti (name sorted) + - File.Anti (name sorted) + - Dir.Anti (reverse name sorted) +*/ + +static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param) +{ + const CObjectVector &updateItems = *(const CObjectVector *)param; + const CUpdateItem &u1 = updateItems[*p1]; + const CUpdateItem &u2 = updateItems[*p2]; + // NonAnti < Anti + if (u1.IsAnti != u2.IsAnti) + return (u1.IsAnti ? 1 : -1); + if (u1.IsDir != u2.IsDir) + { + // Dir.NonAnti < File < Dir.Anti + if (u1.IsDir) + return (u1.IsAnti ? 1 : -1); + return (u2.IsAnti ? -1 : 1); + } + int n = CompareFileNames(u1.Name, u2.Name); + return (u1.IsDir && u1.IsAnti) ? -n : n; +} + +static const char *g_Exts = + " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo" + " zip jar ear war msi" + " 3gp avi mov mpeg mpg mpe wmv" + " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" + " swf" + " chm hxi hxs" + " gif jpeg jpg jp2 png tiff bmp ico psd psp" + " awg ps eps cgm dxf svg vrml wmf emf ai md" + " cad dwg pps key sxi" + " max 3ds" + " iso bin nrg mdf img pdi tar cpio xpi" + " vfd vhd vud vmc vsv" + " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" + " inl inc idl acf asa" + " h hpp hxx c cpp cxx m mm go swift" + " rc java cs rs pas bas vb cls ctl frm dlg def" + " f77 f f90 f95" + " asm s" + " sql manifest dep" + " mak clw csproj vcproj sln dsp dsw" + " class" + " bat cmd bash sh" + " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" + " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs" + " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" + " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" + " abw afp cwk lwp wpd wps wpt wrf wri" + " abf afm bdf fon mgf otf pcf pfa snf ttf" + " dbf mdb nsf ntf wdb db fdb gdb" + " exe dll ocx vbx sfx sys tlb awx com obj lib out o so" + " pdb pch idb ncb opt"; + +static unsigned GetExtIndex(const char *ext) +{ + unsigned extIndex = 1; + const char *p = g_Exts; + for (;;) + { + char c = *p++; + if (c == 0) + return extIndex; + if (c == ' ') + continue; + unsigned pos = 0; + for (;;) + { + char c2 = ext[pos++]; + if (c2 == 0 && (c == 0 || c == ' ')) + return extIndex; + if (c != c2) + break; + c = *p++; + } + extIndex++; + for (;;) + { + if (c == 0) + return extIndex; + if (c == ' ') + break; + c = *p++; + } + } +} + +struct CRefItem +{ + const CUpdateItem *UpdateItem; + UInt32 Index; + unsigned ExtensionPos; + unsigned NamePos; + unsigned ExtensionIndex; + + CRefItem() {} + CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): + UpdateItem(&ui), + Index(index), + ExtensionPos(0), + NamePos(0), + ExtensionIndex(0) + { + if (sortByType) + { + const int slashPos = ui.Name.ReverseFind_PathSepar(); + NamePos = (unsigned)(slashPos + 1); + const int dotPos = ui.Name.ReverseFind_Dot(); + if (dotPos <= slashPos) + ExtensionPos = ui.Name.Len(); + else + { + ExtensionPos = (unsigned)(dotPos + 1); + if (ExtensionPos != ui.Name.Len()) + { + AString s; + for (unsigned pos = ExtensionPos;; pos++) + { + const wchar_t c = ui.Name[pos]; + if (c >= 0x80) + break; + if (c == 0) + { + ExtensionIndex = GetExtIndex(s); + break; + } + s.Add_Char((char)MyCharLower_Ascii((char)c)); + } + } + } + } + } +}; + +struct CSortParam +{ + // const CObjectVector *TreeFolders; + bool SortByType; +}; + +/* + we sort files in such order: + - Dir.NonAnti (name sorted) + - alt streams + - Dirs + - Dir.Anti (reverse name sorted) +*/ + + +static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) +{ + const CRefItem &a1 = *p1; + const CRefItem &a2 = *p2; + const CUpdateItem &u1 = *a1.UpdateItem; + const CUpdateItem &u2 = *a2.UpdateItem; + + /* + if (u1.IsAltStream != u2.IsAltStream) + return u1.IsAltStream ? 1 : -1; + */ + + // Actually there are no dirs that time. They were stored in other steps + // So that code is unused? + if (u1.IsDir != u2.IsDir) + return u1.IsDir ? 1 : -1; + if (u1.IsDir) + { + if (u1.IsAnti != u2.IsAnti) + return (u1.IsAnti ? 1 : -1); + int n = CompareFileNames(u1.Name, u2.Name); + return -n; + } + + // bool sortByType = *(bool *)param; + const CSortParam *sortParam = (const CSortParam *)param; + const bool sortByType = sortParam->SortByType; + if (sortByType) + { + RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex) + RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos))) + RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos))) + if (!u1.MTimeDefined && u2.MTimeDefined) return 1; + if (u1.MTimeDefined && !u2.MTimeDefined) return -1; + if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime) + RINOZ_COMP(u1.Size, u2.Size) + } + /* + int par1 = a1.UpdateItem->ParentFolderIndex; + int par2 = a2.UpdateItem->ParentFolderIndex; + const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1]; + const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2]; + + int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd; + int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd; + if (b1 < b2) + { + if (e1 <= b2) + return -1; + // p2 in p1 + int par = par2; + for (;;) + { + const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; + par = tf.Parent; + if (par == par1) + { + RINOZ(CompareFileNames(u1.Name, tf.Name)); + break; + } + } + } + else if (b2 < b1) + { + if (e2 <= b1) + return 1; + // p1 in p2 + int par = par1; + for (;;) + { + const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; + par = tf.Parent; + if (par == par2) + { + RINOZ(CompareFileNames(tf.Name, u2.Name)); + break; + } + } + } + */ + // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex); + RINOK(CompareFileNames(u1.Name, u2.Name)) + RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient) + RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive) + return 0; +} + +struct CSolidGroup +{ + CRecordVector Indices; + + CRecordVector folderRefs; +}; + +static const char * const g_Exe_Exts[] = +{ + "dll" + , "exe" + , "ocx" + , "sfx" + , "sys" +}; + +static const char * const g_ExeUnix_Exts[] = +{ + "so" + , "dylib" +}; + +static bool IsExt_Exe(const wchar_t *ext) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exe_Exts); i++) + if (StringsAreEqualNoCase_Ascii(ext, g_Exe_Exts[i])) + return true; + return false; +} + +/* +static bool IsExt_ExeUnix(const wchar_t *ext) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++) + if (StringsAreEqualNoCase_Ascii(ext, g_ExeUnix_Exts[i])) + return true; + return false; +} +*/ + +// we try to find "so" extension in such name: libstdc++.so.6.0.29 +static bool IsExt_ExeUnix_NumericAllowed(const UString &path) +{ + unsigned pos = path.Len(); + unsigned dotPos = pos; + for (;;) + { + if (pos == 0) + return false; + const wchar_t c = path[--pos]; + if (IS_PATH_SEPAR(c)) + return false; + if (c == '.') + { + const unsigned num = (dotPos - pos) - 1; + if (num < 1) + return false; + const wchar_t *cur = path.Ptr(pos + 1); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++) + { + const char *ext = g_ExeUnix_Exts[i]; + if (num == MyStringLen(ext)) + if (IsString1PrefixedByString2_NoCase_Ascii(cur, ext)) + return true; + } + const wchar_t *end; + ConvertStringToUInt32(cur, &end); + if ((size_t)(end - cur) != num) + return false; + dotPos = pos; + } + } +} + + +struct CAnalysis +{ + CMyComPtr Callback; + CByteBuffer Buffer; + + bool ParseWav; + bool ParseExe; + bool ParseExeUnix; + bool ParseNoExt; + bool ParseAll; + + /* + bool Need_ATime; + bool ATime_Defined; + FILETIME ATime; + */ + + CAnalysis(): + ParseWav(false), + ParseExe(false), + ParseExeUnix(false), + ParseNoExt(false), + ParseAll(false) + /* + , Need_ATime(false) + , ATime_Defined(false) + */ + {} + + HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); +}; + +static const size_t kAnalysisBufSize = 1 << 14; + +HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode) +{ + filterMode.Id = 0; + filterMode.Delta = 0; + filterMode.Offset = 0; + + CFilterMode filterModeTemp = filterMode; + + const int slashPos = ui.Name.ReverseFind_PathSepar(); + const int dotPos = ui.Name.ReverseFind_Dot(); + + // if (dotPos > slashPos) + { + bool needReadFile = ParseAll; + /* if (Callback) is not supported by client, + we still try to use file name extension to detect executable file */ + bool probablyIsSameIsa = false; + + if (!needReadFile || !Callback) + { + const wchar_t *ext = NULL; + if (dotPos > slashPos) + ext = ui.Name.Ptr((unsigned)(dotPos + 1)); + // 7-zip stores posix attributes in high 16 bits and sets (0x8000) flag + if (ui.Attrib & 0x8000) + { + const unsigned st_mode = ui.Attrib >> 16; + /* note: executable ".so" can be without execute permission, + and symbolic link to such ".so" file is possible */ + // st_mode = 00111; // for debug + /* in Linux we expect such permissions: + 0755 : for most executables + 0644 : for some ".so" files + 0777 : in WSL for all files. + We can try to exclude some such 0777 cases from analysis, + if there is non-executable extension. + */ + + if ((st_mode & ( + MY_LIN_S_IXUSR | + MY_LIN_S_IXGRP | + MY_LIN_S_IXOTH)) != 0 + && MY_LIN_S_ISREG(st_mode) + && (ui.Size >= (1u << 11))) + { + #ifndef _WIN32 + probablyIsSameIsa = true; + #endif + needReadFile = true; + } + } + + if (!needReadFile) + { + if (!ext) + needReadFile = ParseNoExt; + else + { + bool isUnixExt = false; + if (ParseExeUnix) + isUnixExt = IsExt_ExeUnix_NumericAllowed(ui.Name); + if (isUnixExt) + { + needReadFile = true; + #ifndef _WIN32 + probablyIsSameIsa = true; + #endif + } + else if (IsExt_Exe(ext)) + { + needReadFile = ParseExe; + #ifdef _WIN32 + probablyIsSameIsa = true; + #endif + } + else if (StringsAreEqualNoCase_Ascii(ext, "wav")) + { + if (!needReadFile) + needReadFile = ParseWav; + } + } + } + } + + if (needReadFile) + { + BoolInt parseRes = false; + if (Callback) + { + if (Buffer.Size() != kAnalysisBufSize) + Buffer.Alloc(kAnalysisBufSize); + CMyComPtr stream; + HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze); + if (result == S_OK && stream) + { + /* + if (Need_ATime) + { + // access time could be changed in analysis pass + CMyComPtr getProps; + stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK) + ATime_Defined = true; + } + */ + size_t size = kAnalysisBufSize; + result = ReadStream(stream, Buffer, &size); + stream.Release(); + // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK)); + if (result == S_OK) + { + parseRes = ParseFile(Buffer, size, &filterModeTemp); + } + } + } // Callback + else if (probablyIsSameIsa) + { + #ifdef MY_CPU_X86_OR_AMD64 + filterModeTemp.Id = k_X86; + #endif + #ifdef MY_CPU_ARM64 + filterModeTemp.Id = k_ARM64; + #endif + #ifdef MY_CPU_RISCV + filterModeTemp.Id = k_RISCV; + #endif + #ifdef MY_CPU_SPARC + filterModeTemp.Id = k_SPARC; + #endif + parseRes = true; + } + + if (parseRes + && filterModeTemp.Id != k_Delta + && filterModeTemp.Delta == 0) + { + /* ParseFile() sets (filterModeTemp.Delta == 0) for all + methods except of k_Delta. */ + // it's not k_Delta + // So we call SetDelta() to set Delta + filterModeTemp.SetDelta(); + if (filterModeTemp.Delta > 1) + { + /* If file Size is not aligned, then branch filter + will not work for next file in solid block. + Maybe we should allow filter for non-aligned-size file in non-solid archives ? + */ + if (ui.Size % filterModeTemp.Delta != 0) + parseRes = false; + // windows exe files are not aligned for 4 KiB. + /* + else if (filterModeTemp.Id == k_ARM64 && filterModeTemp.Offset != 0) + { + if (ui.Size % (1 << 12) != 0) + { + // If Size is not aligned for 4 KiB, then Offset will not work for next file in solid block. + // so we place such file in group with (Offset==0). + filterModeTemp.Offset = 0; + } + } + */ + } + } + if (!parseRes) + filterModeTemp.ClearFilterMode(); + } + } + + filterMode = filterModeTemp; + return S_OK; +} + +static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m) +{ + m.Id = methodID; + m.NumStreams = numStreams; +} + + +// we add bond for mode.Methods[0] that is filter +static HRESULT AddBondForFilter(CCompressionMethodMode &mode) +{ + for (unsigned c = 1; c < mode.Methods.Size(); c++) + { + if (!mode.IsThereBond_to_Coder(c)) + { + CBond2 bond; + bond.OutCoder = 0; + bond.OutStream = 0; + bond.InCoder = c; + mode.Bonds.Add(bond); + return S_OK; + } + } + return E_INVALIDARG; +} + +/* +static HRESULT AddBondForFilter_if_ThereAreBonds(CCompressionMethodMode &mode) +{ + if (!mode.Bonds.IsEmpty()) + return AddBondForFilter(mode); + return S_OK; +} +*/ + +static HRESULT AddBcj2Methods(CCompressionMethodMode &mode) +{ + // mode.Methods[0] must be k_BCJ2 method ! + // mode.Methods[1] : we expect that there is at least one method after BCJ2 + + CMethodFull m; + GetMethodFull(k_LZMA, 1, m); + + m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20); + m.AddProp32(NCoderPropID::kNumFastBytes, 128); + m.AddProp32(NCoderPropID::kNumThreads, 1); + m.AddProp32(NCoderPropID::kLitPosBits, 2); + m.AddProp32(NCoderPropID::kLitContextBits, 0); + // m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2"); + + const unsigned methodIndex = mode.Methods.Size(); + + if (mode.Bonds.IsEmpty()) + { + for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++) + { + CBond2 bond; + bond.OutCoder = i; + bond.OutStream = 0; + bond.InCoder = i + 1; + mode.Bonds.Add(bond); + } + } + + mode.Methods.Add(m); + mode.Methods.Add(m); + + RINOK(AddBondForFilter(mode)) + CBond2 bond; + bond.OutCoder = 0; // index of BCJ2 coder + bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond); + bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond); + return S_OK; +} + + +static HRESULT MakeExeMethod(CCompressionMethodMode &mode, + const CFilterMode &filterMode, + const bool bcj2_IsAllowed, + const CUIntVector &disabledFilterIDs) +{ + if (mode.Filter_was_Inserted) + { + // filter was inserted, but bond for that filter was not added still. + const CMethodFull &m = mode.Methods[0]; + if (m.Id == k_BCJ2) + return AddBcj2Methods(mode); + if (!m.IsSimpleCoder()) + return E_NOTIMPL; + if (mode.Bonds.IsEmpty()) + return S_OK; + return AddBondForFilter(mode); + } + + if (filterMode.Id == 0) + return S_OK; + + unsigned nextCoder; + + const bool useBcj2 = bcj2_IsAllowed + && Is86Filter(filterMode.Id) + && disabledFilterIDs.FindInSorted(k_BCJ2) < 0; + + if (!useBcj2 && disabledFilterIDs.FindInSorted(filterMode.Id) >= 0) + { + // required filter is disabled, + // but we still can use information about data alignment. +#if 0 // 1 for debug + // we can return here, if we want default lzma properties + return S_OK; +#else + // we will try to change lzma/lzma2 properties + nextCoder = 0; + if (!mode.Bonds.IsEmpty()) + for (unsigned c = 0;; c++) + { + if (c == mode.Methods.Size()) + return S_OK; + if (!mode.IsThereBond_to_Coder(c)) + { + nextCoder = c; + break; + } + } +#endif + } + else + { + // we insert new filter method: + CMethodFull &m = mode.Methods.InsertNew(0); // 0 == index of new inserted item + { + // we move all coder indexes in bonds up for 1 position: + FOR_VECTOR (k, mode.Bonds) + { + CBond2 &bond = mode.Bonds[k]; + bond.InCoder++; + bond.OutCoder++; + } + } + if (useBcj2) + { + GetMethodFull(k_BCJ2, 4, m); + return AddBcj2Methods(mode); + } + + GetMethodFull(filterMode.Id, 1, m); + + if (filterMode.Id == k_Delta) + m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta); + else if (filterMode.Id == k_ARM64 + || filterMode.Id == k_RISCV) + { + // if (filterMode.Offset != 0) + m.AddProp32( + NCoderPropID::kDefaultProp, + // NCoderPropID::kBranchOffset, + filterMode.Offset); + } + + nextCoder = 1; + if (!mode.Bonds.IsEmpty()) + { + RINOK(AddBondForFilter(mode)) + nextCoder = mode.Bonds.Back().InCoder; + } + } + + if (nextCoder >= mode.Methods.Size()) + { + // we don't expect that case, if there was non-filter method. + // but we return S_OK to support filter-only case. + return S_OK; + } + + int alignBits = -1; + { + const UInt32 delta = filterMode.Delta; + if (delta == 0 || delta > 16) + { + // if (delta == 0) alignBits = GetAlignForFilterMethod(filterMode.Id); + } + else if ((delta & ((1 << 4) - 1)) == 0) alignBits = 4; + else if ((delta & ((1 << 3) - 1)) == 0) alignBits = 3; + else if ((delta & ((1 << 2) - 1)) == 0) alignBits = 2; + else if ((delta & ((1 << 1) - 1)) == 0) alignBits = 1; + // else alignBits = 0; + /* alignBits=0 is default mode for lzma/lzma2. + So we don't set alignBits=0 here. */ + } + if (alignBits <= 0) + return S_OK; + // (alignBits > 0) + CMethodFull &nextMethod = mode.Methods[nextCoder]; + if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2) + if (!nextMethod.Are_Lzma_Model_Props_Defined()) + { + if (alignBits > 2 || filterMode.Id == k_Delta) + nextMethod.AddProp32(NCoderPropID::kPosStateBits, (unsigned)alignBits); + const unsigned lc = (alignBits < 3) ? (unsigned)(3 - alignBits) : 0u; + nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc); + nextMethod.AddProp32(NCoderPropID::kLitPosBits, (unsigned)alignBits); + } + return S_OK; +} + + +static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2) +{ + file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined; + file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; + file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; + file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; + file2.IsAnti = ui.IsAnti; + // file2.IsAux = false; + file2.StartPosDefined = false; + // file2.StartPos = 0; +} + + +static void UpdateItem_To_FileItem(const CUpdateItem &ui, + CFileItem &file, CFileItem2 &file2) +{ + UpdateItem_To_FileItem2(ui, file2); + + file.Size = ui.Size; + file.IsDir = ui.IsDir; + file.HasStream = ui.HasStream(); + // file.IsAltStream = ui.IsAltStream; +} + + + +Z7_CLASS_IMP_COM_2( + CRepackInStreamWithSizes + , ISequentialInStream + , ICompressGetSubStreamSize +) + CMyComPtr _stream; + UInt64 _size; + const CBoolVector *_extractStatuses; + UInt32 _startIndex; +public: + const CDbEx *_db; + + void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses) + { + _startIndex = startIndex; + _extractStatuses = extractStatuses; + _size = 0; + _stream = stream; + } + UInt64 GetSize() const { return _size; } +}; + +Z7_COM7F_IMF(CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize; + const HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return result; +} + +Z7_COM7F_IMF(CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value)) +{ + *value = 0; + if (subStream >= _extractStatuses->Size()) + return S_FALSE; // E_FAIL; + const unsigned index = (unsigned)subStream; + if ((*_extractStatuses)[index]) + { + const CFileItem &fi = _db->Files[_startIndex + index]; + if (fi.HasStream) + *value = fi.Size; + } + return S_OK; +} + + +class CRepackStreamBase +{ +protected: + bool _needWrite; + bool _fileIsOpen; + bool _calcCrc; + UInt32 _crc; + UInt64 _rem; + + const CBoolVector *_extractStatuses; + UInt32 _startIndex; + unsigned _currentIndex; + + HRESULT OpenFile(); + HRESULT CloseFile(); + HRESULT ProcessEmptyFiles(); + +public: + const CDbEx *_db; + CMyComPtr _opCallback; + CMyComPtr _extractCallback; + + HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses); + HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } +}; + +HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses) +{ + _startIndex = startIndex; + _extractStatuses = extractStatuses; + + _currentIndex = 0; + _fileIsOpen = false; + + return ProcessEmptyFiles(); +} + +HRESULT CRepackStreamBase::OpenFile() +{ + UInt32 arcIndex = _startIndex + _currentIndex; + const CFileItem &fi = _db->Files[arcIndex]; + + _needWrite = (*_extractStatuses)[_currentIndex]; + if (_opCallback) + { + RINOK(_opCallback->ReportOperation( + NEventIndexType::kInArcIndex, arcIndex, + _needWrite ? + NUpdateNotifyOp::kRepack : + NUpdateNotifyOp::kSkip)) + } + + _crc = CRC_INIT_VAL; + _calcCrc = (fi.CrcDefined && !fi.IsDir); + + _fileIsOpen = true; + _rem = fi.Size; + return S_OK; +} + +const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002; + +HRESULT CRepackStreamBase::CloseFile() +{ + UInt32 arcIndex = _startIndex + _currentIndex; + const CFileItem &fi = _db->Files[arcIndex]; + _fileIsOpen = false; + _currentIndex++; + if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) + return S_OK; + + if (_extractCallback) + { + RINOK(_extractCallback->ReportExtractResult( + NEventIndexType::kInArcIndex, arcIndex, + NExtract::NOperationResult::kCRCError)) + } + // return S_FALSE; + return k_My_HRESULT_CRC_ERROR; +} + +HRESULT CRepackStreamBase::ProcessEmptyFiles() +{ + while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) + { + RINOK(OpenFile()) + RINOK(CloseFile()) + } + return S_OK; +} + + + +#ifndef Z7_ST + +class CFolderOutStream2 Z7_final: + public CRepackStreamBase, + public ISequentialOutStream, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ISequentialOutStream) +public: + CMyComPtr _stream; +}; + +Z7_COM7F_IMF(CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (_fileIsOpen) + { + UInt32 cur = (size < _rem ? size : (UInt32)_rem); + HRESULT result = S_OK; + if (_needWrite) + result = _stream->Write(data, cur, &cur); + if (_calcCrc) + _crc = CrcUpdate(_crc, data, cur); + if (processedSize) + *processedSize += cur; + data = (const Byte *)data + cur; + size -= cur; + _rem -= cur; + if (_rem == 0) + { + RINOK(CloseFile()) + RINOK(ProcessEmptyFiles()) + } + RINOK(result) + if (cur == 0) + break; + continue; + } + + RINOK(ProcessEmptyFiles()) + if (_currentIndex == _extractStatuses->Size()) + { + // we don't support write cut here + return E_FAIL; + } + RINOK(OpenFile()) + } + + return S_OK; +} + +#endif + + + +static const UInt32 kTempBufSize = 1 << 16; + +class CFolderInStream2 Z7_final: + public CRepackStreamBase, + public ISequentialInStream, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ISequentialInStream) + + Byte *_buf; +public: + CMyComPtr _inStream; + HRESULT Result; + + CFolderInStream2(): + Result(S_OK) + { + _buf = new Byte[kTempBufSize]; + } + + ~CFolderInStream2() + { + delete []_buf; + } + + void Init() { Result = S_OK; } +}; + +Z7_COM7F_IMF(CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (_fileIsOpen) + { + UInt32 cur = (size < _rem ? size : (UInt32)_rem); + + void *buf; + if (_needWrite) + buf = data; + else + { + buf = _buf; + if (cur > kTempBufSize) + cur = kTempBufSize; + } + + const HRESULT result = _inStream->Read(buf, cur, &cur); + _crc = CrcUpdate(_crc, buf, cur); + _rem -= cur; + + if (_needWrite) + { + data = (Byte *)data + cur; + size -= cur; + if (processedSize) + *processedSize += cur; + } + + if (result != S_OK) + Result = result; + + if (_rem == 0) + { + RINOK(CloseFile()) + RINOK(ProcessEmptyFiles()) + } + + RINOK(result) + + if (cur == 0) + return E_FAIL; + + continue; + } + + RINOK(ProcessEmptyFiles()) + if (_currentIndex == _extractStatuses->Size()) + { + return S_OK; + } + RINOK(OpenFile()) + } + + return S_OK; +} + + +class CThreadDecoder Z7_final + #ifndef Z7_ST + : public CVirtThread + #endif +{ +public: + CDecoder Decoder; + + CThreadDecoder(bool multiThreadMixer): + Decoder(multiThreadMixer) + { + #ifndef Z7_ST + if (multiThreadMixer) + { + MtMode = false; + NumThreads = 1; + FosSpec = new CFolderOutStream2; + Fos = FosSpec; + Result = E_FAIL; + } + #endif + // UnpackSize = 0; + // send_UnpackSize = false; + } + + #ifndef Z7_ST + + bool dataAfterEnd_Error; + HRESULT Result; + CMyComPtr InStream; + + CFolderOutStream2 *FosSpec; + CMyComPtr Fos; + + UInt64 StartPos; + const CFolders *Folders; + unsigned FolderIndex; + + // bool send_UnpackSize; + // UInt64 UnpackSize; + + #ifndef Z7_NO_CRYPTO + CMyComPtr getTextPassword; + #endif + + DECL_EXTERNAL_CODECS_LOC_VARS_DECL + + #ifndef Z7_ST + bool MtMode; + UInt32 NumThreads; + #endif + + + ~CThreadDecoder() Z7_DESTRUCTOR_override + { + /* WaitThreadFinish() will be called in ~CVirtThread(). + But we need WaitThreadFinish() call before + destructors of this class members. + */ + CVirtThread::WaitThreadFinish(); + } +private: + virtual void Execute() Z7_override; + + #endif +}; + +#ifndef Z7_ST + +void CThreadDecoder::Execute() +{ + try + { + #ifndef Z7_NO_CRYPTO + bool isEncrypted = false; + bool passwordIsDefined = false; + UString password; + #endif + + dataAfterEnd_Error = false; + + Result = Decoder.Decode( + EXTERNAL_CODECS_LOC_VARS + InStream, + StartPos, + *Folders, FolderIndex, + + // send_UnpackSize ? &UnpackSize : NULL, + NULL, // unpackSize : FULL unpack + + Fos, + NULL, // compressProgress + + NULL // *inStreamMainRes + , dataAfterEnd_Error + + Z7_7Z_DECODER_CRYPRO_VARS + #ifndef Z7_ST + , MtMode, NumThreads, + 0 // MemUsage + #endif + + ); + } + catch(...) + { + Result = E_FAIL; + } + + /* + if (Result == S_OK) + Result = FosSpec->CheckFinishedState(); + */ + FosSpec->_stream.Release(); +} + +#endif + +#ifndef Z7_NO_CRYPTO + +Z7_CLASS_IMP_NOQIB_1( + CCryptoGetTextPassword + , ICryptoGetTextPassword +) +public: + UString Password; +}; + +Z7_COM7F_IMF(CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)) +{ + return StringToBstr(Password, password); +} + +#endif + + +static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2) +{ + file = inDb.Files[index]; + file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); + file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime); + file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime); + file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos); + file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib); + file2.IsAnti = inDb.IsItemAnti(index); + // file2.IsAux = inDb.IsItemAux(index); +} + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + const CDbEx *db, + CObjectVector &updateItems, + // const CObjectVector &treeFolders, + // const CUniqBlocks &secureBlocks, + ISequentialOutStream *seqOutStream, + IArchiveUpdateCallback *updateCallback, + const CUpdateOptions &options) +{ + UInt64 numSolidFiles = options.NumSolidFiles; + if (numSolidFiles == 0) + numSolidFiles = 1; + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveUpdateCallbackFile, + opCallback, updateCallback) + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveExtractCallbackMessage2, + extractCallback, updateCallback) + + /* + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveUpdateCallbackArcProp, + reportArcProp, updateCallback) + */ + + // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); + + CMyComPtr v_StreamSetRestriction; + { + Z7_DECL_CMyComPtr_QI_FROM( + IOutStream, + outStream, seqOutStream) + if (!outStream) + return E_NOTIMPL; + const UInt64 sfxBlockSize = (db && !options.RemoveSfxBlock) ? + db->ArcInfo.StartPosition: 0; + seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&v_StreamSetRestriction); + if (v_StreamSetRestriction) + { + UInt64 offset = 0; + RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &offset)) + RINOK(v_StreamSetRestriction->SetRestriction( + outStream ? offset + sfxBlockSize : 0, + outStream ? offset + sfxBlockSize + k_StartHeadersRewriteSize : 0)) + } + outStream.Release(); + if (sfxBlockSize != 0) + { + RINOK(WriteRange(inStream, seqOutStream, 0, sfxBlockSize, NULL)) + } + } + + CIntArr fileIndexToUpdateIndexMap; + UInt64 complexity = 0; + bool isThere_UnknownSize = false; + UInt64 inSizeForReduce2 = 0; + + #ifndef Z7_NO_CRYPTO + bool needEncryptedRepack = false; + #endif + + CRecordVector filters; + CObjectVector groups; + + #ifndef Z7_ST + bool thereAreRepacks = false; + #endif + + bool useFilters = options.UseFilters; + if (useFilters) + { + const CCompressionMethodMode &method = *options.Method; + + FOR_VECTOR (i, method.Methods) + { + /* IsFilterMethod() knows only built-in codecs + FIXME: we should check IsFilter status for external filters too */ + if (IsFilterMethod(method.Methods[i].Id)) + { + useFilters = false; + break; + } + } + } + + if (db) + { + fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); + unsigned i; + + for (i = 0; i < db->Files.Size(); i++) + fileIndexToUpdateIndexMap[i] = -1; + + for (i = 0; i < updateItems.Size(); i++) + { + int index = updateItems[i].IndexInArchive; + if (index != -1) + fileIndexToUpdateIndexMap[(unsigned)index] = (int)i; + } + + for (i = 0; i < db->NumFolders; i++) + { + CNum indexInFolder = 0; + CNum numCopyItems = 0; + const CNum numUnpackStreams = db->NumUnpackStreamsVector[i]; + UInt64 repackSize = 0; + + for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++) + { + if (fi >= db->Files.Size()) + return E_FAIL; + + const CFileItem &file = db->Files[fi]; + if (file.HasStream) + { + indexInFolder++; + const int updateIndex = fileIndexToUpdateIndexMap[fi]; + if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData) + { + numCopyItems++; + repackSize += file.Size; + } + } + } + + if (numCopyItems == 0) + continue; + + CFolderRepack rep; + rep.FolderIndex = i; + rep.NumCopyFiles = numCopyItems; + CFolderEx f; + db->ParseFolderEx(i, f); + + #ifndef Z7_NO_CRYPTO + const bool isEncrypted = f.IsEncrypted(); + #endif + const bool needCopy = (numCopyItems == numUnpackStreams); + const bool extractFilter = (useFilters || needCopy); + + const unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f, extractFilter); + + while (groupIndex >= groups.Size()) + groups.AddNew(); + + groups[groupIndex].folderRefs.Add(rep); + + if (needCopy) + complexity += db->GetFolderFullPackSize(i); + else + { + #ifndef Z7_ST + thereAreRepacks = true; + #endif + complexity += repackSize; + if (inSizeForReduce2 < repackSize) + inSizeForReduce2 = repackSize; + #ifndef Z7_NO_CRYPTO + if (isEncrypted) + needEncryptedRepack = true; + #endif + } + } + } + + UInt64 inSizeForReduce = 0; + { + const bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0); + FOR_VECTOR (i, updateItems) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + if (ui.Size == (UInt64)(Int64)-1) + isThere_UnknownSize = true; + else + { + complexity += ui.Size; + if (isSolid) + inSizeForReduce += ui.Size; + else if (inSizeForReduce < ui.Size) + inSizeForReduce = ui.Size; + } + } + } + } + + if (isThere_UnknownSize) + inSizeForReduce = (UInt64)(Int64)-1; + else + RINOK(updateCallback->SetTotal(complexity)) + + if (inSizeForReduce < inSizeForReduce2) + inSizeForReduce = inSizeForReduce2; + + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + #ifndef Z7_ST + + CStreamBinder sb; + /* + if (options.MultiThreadMixer) + { + RINOK(sb.CreateEvents()); + } + */ + + #endif + + CThreadDecoder threadDecoder(options.MultiThreadMixer); + + #ifndef Z7_ST + if (options.MultiThreadMixer && thereAreRepacks) + { + #ifdef Z7_EXTERNAL_CODECS + threadDecoder._externalCodecs = _externalCodecs; + #endif + const WRes wres = threadDecoder.Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + #endif + + { + CAnalysis analysis; + // analysis.Need_ATime = options.Need_ATime; + int analysisLevel = options.AnalysisLevel; + // (analysisLevel < 0) means default level (5) + if (analysisLevel < 0) + analysisLevel = 5; + if (analysisLevel != 0) + { + analysis.Callback = opCallback; + analysis.ParseWav = true; + if (analysisLevel >= 5) + { + analysis.ParseExe = true; + analysis.ParseExeUnix = true; + // analysis.ParseNoExt = true; + if (analysisLevel >= 7) + { + analysis.ParseNoExt = true; + if (analysisLevel >= 9) + analysis.ParseAll = true; + } + } + } + + // ---------- Split files to groups ---------- + + const CCompressionMethodMode &method = *options.Method; + + FOR_VECTOR (i, updateItems) + { + const CUpdateItem &ui = updateItems[i]; + if (!ui.NewData || !ui.HasStream()) + continue; + + CFilterMode2 fm; + if (useFilters) + { + // analysis.ATime_Defined = false; + RINOK(analysis.GetFilterGroup(i, ui, fm)) + /* + if (analysis.ATime_Defined) + { + ui.ATime = FILETIME_To_UInt64(analysis.ATime); + ui.ATime_WasReadByAnalysis = true; + } + */ + } + fm.Encrypted = method.PasswordIsDefined; + + const unsigned groupIndex = GetGroup(filters, fm); + while (groupIndex >= groups.Size()) + groups.AddNew(); + groups[groupIndex].Indices.Add(i); + } + } + + + #ifndef Z7_NO_CRYPTO + + CCryptoGetTextPassword *getPasswordSpec = NULL; + CMyComPtr getTextPassword; + if (needEncryptedRepack) + { + getPasswordSpec = new CCryptoGetTextPassword; + getTextPassword = getPasswordSpec; + + #ifndef Z7_ST + threadDecoder.getTextPassword = getPasswordSpec; + #endif + + if (options.Method->PasswordIsDefined) + getPasswordSpec->Password = options.Method->Password; + else + { + Z7_DECL_CMyComPtr_QI_FROM( + ICryptoGetTextPassword, + getDecoderPassword, updateCallback) + if (!getDecoderPassword) + return E_NOTIMPL; + CMyComBSTR password; + RINOK(getDecoderPassword->CryptoGetTextPassword(&password)) + if (password) + getPasswordSpec->Password = password; + } + } + + #endif + + // ---------- Compress ---------- + + COutArchive archive; + CArchiveDatabaseOut newDatabase; + + RINOK(archive.Create_and_WriteStartPrefix(seqOutStream)) + + /* + CIntVector treeFolderToArcIndex; + treeFolderToArcIndex.Reserve(treeFolders.Size()); + for (i = 0; i < treeFolders.Size(); i++) + treeFolderToArcIndex.Add(-1); + // ---------- Write Tree (only AUX dirs) ---------- + for (i = 1; i < treeFolders.Size(); i++) + { + const CTreeFolder &treeFolder = treeFolders[i]; + CFileItem file; + CFileItem2 file2; + file2.Init(); + int secureID = 0; + if (treeFolder.UpdateItemIndex < 0) + { + // we can store virtual dir item wuthout attrib, but we want all items have attrib. + file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY); + file2.IsAux = true; + } + else + { + const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex]; + // if item is not dir, then it's parent for alt streams. + // we will write such items later + if (!ui.IsDir) + continue; + secureID = ui.SecureIndex; + if (ui.NewProps) + UpdateItem_To_FileItem(ui, file, file2); + else + GetFile(*db, ui.IndexInArchive, file, file2); + } + file.Size = 0; + file.HasStream = false; + file.IsDir = true; + file.Parent = treeFolder.Parent; + + treeFolderToArcIndex[i] = newDatabase.Files.Size(); + newDatabase.AddFile(file, file2, treeFolder.Name); + + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(secureID); + } + */ + + { + /* ---------- Write non-AUX dirs and Empty files ---------- */ + CUIntVector emptyRefs; + + unsigned i; + + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + if (ui.HasStream()) + continue; + } + else if (ui.IndexInArchive != -1 && db->Files[(unsigned)ui.IndexInArchive].HasStream) + continue; + /* + if (ui.TreeFolderIndex >= 0) + continue; + */ + emptyRefs.Add(i); + } + + emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); + + for (i = 0; i < emptyRefs.Size(); i++) + { + const CUpdateItem &ui = updateItems[emptyRefs[i]]; + CFileItem file; + CFileItem2 file2; + UString name; + if (ui.NewProps) + { + UpdateItem_To_FileItem(ui, file, file2); + file.CrcDefined = false; + name = ui.Name; + } + else + { + GetFile(*db, (unsigned)ui.IndexInArchive, file, file2); + db->GetPath((unsigned)ui.IndexInArchive, name); + } + + /* + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(ui.SecureIndex); + file.Parent = ui.ParentFolderIndex; + */ + newDatabase.AddFile(file, file2, name); + } + } + + lps->ProgressOffset = 0; + + { + // ---------- Sort Filters ---------- + FOR_VECTOR (i, filters) + { + filters[i].GroupIndex = i; + } + filters.Sort2(); + } + + for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++) + { + const CFilterMode2 &filterMode = filters[groupIndex]; + + CCompressionMethodMode method = *options.Method; + { + const HRESULT res = MakeExeMethod(method, filterMode, + // bcj2_IsAllowed: + #ifdef Z7_ST + false + #else + options.MaxFilter && options.MultiThreadMixer + #endif + , options.DisabledFilterIDs); + + RINOK(res) + } + + if (filterMode.Encrypted) + { + if (!method.PasswordIsDefined) + { + #ifndef Z7_NO_CRYPTO + if (getPasswordSpec) + method.Password = getPasswordSpec->Password; + #endif + method.PasswordIsDefined = true; + } + } + else + { + method.PasswordIsDefined = false; + method.Password.Empty(); + } + + CEncoder encoder(method); + + // ---------- Repack and copy old solid blocks ---------- + + const CSolidGroup &group = groups[filterMode.GroupIndex]; + + FOR_VECTOR (folderRefIndex, group.folderRefs) + { + const CFolderRepack &rep = group.folderRefs[folderRefIndex]; + + const unsigned folderIndex = rep.FolderIndex; + + const CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; + + if (rep.NumCopyFiles == numUnpackStreams) + { + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kReplicate)) + + // ---------- Copy old solid block ---------- + { + CNum indexInFolder = 0; + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) + { + if (db->Files[fi].HasStream) + { + indexInFolder++; + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)fi, + NUpdateNotifyOp::kReplicate)) + } + } + } + } + + const UInt64 packSize = db->GetFolderFullPackSize(folderIndex); + RINOK(WriteRange(inStream, archive.SeqStream, + db->GetFolderStreamPos(folderIndex, 0), packSize, lps)) + lps->ProgressOffset += packSize; + + const unsigned folderIndex_New = newDatabase.Folders.Size(); + CFolder &folder = newDatabase.Folders.AddNew(); + // v23.01: we copy FolderCrc, if FolderCrc was used + if (db->FolderCRCs.ValidAndDefined(folderIndex)) + newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, + true, db->FolderCRCs.Vals[folderIndex]); + + db->ParseFolderInfo(folderIndex, folder); + const CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; + FOR_VECTOR (j, folder.PackStreams) + { + newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); + // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); + // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); + } + + size_t indexStart = db->FoToCoderUnpackSizes[folderIndex]; + const size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; + for (; indexStart < indexEnd; indexStart++) + newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes.ConstData()[indexStart]); + } + else + { + // ---------- Repack old solid block ---------- + + CBoolVector extractStatuses; + + CNum indexInFolder = 0; + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kRepack)) + } + + /* We could reduce data size of decoded folder, if we don't need to repack + last files in folder. But the gain in speed is small in most cases. + So we unpack full folder. */ + + UInt64 sizeToEncode = 0; + + /* + UInt64 importantUnpackSize = 0; + unsigned numImportantFiles = 0; + UInt64 decodeSize = 0; + */ + + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) + { + bool needExtract = false; + const CFileItem &file = db->Files[fi]; + + if (file.HasStream) + { + indexInFolder++; + const int updateIndex = fileIndexToUpdateIndexMap[fi]; + if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData) + needExtract = true; + // decodeSize += file.Size; + } + + extractStatuses.Add(needExtract); + if (needExtract) + { + sizeToEncode += file.Size; + /* + numImportantFiles = extractStatuses.Size(); + importantUnpackSize = decodeSize; + */ + } + } + + // extractStatuses.DeleteFrom(numImportantFiles); + + unsigned startPackIndex = newDatabase.PackSizes.Size(); + UInt64 curUnpackSize; + { + CMyComPtr sbInStream; + CRepackStreamBase *repackBase; + CFolderInStream2 *FosSpec2 = NULL; + + CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes; + CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; + { + #ifndef Z7_ST + if (options.MultiThreadMixer) + { + repackBase = threadDecoder.FosSpec; + CMyComPtr sbOutStream; + sb.CreateStreams2(sbInStream, sbOutStream); + RINOK(sb.Create_ReInit()) + + threadDecoder.FosSpec->_stream = sbOutStream; + + threadDecoder.InStream = inStream; + threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); + threadDecoder.Folders = (const CFolders *)db; + threadDecoder.FolderIndex = folderIndex; + + // threadDecoder.UnpackSize = importantUnpackSize; + // threadDecoder.send_UnpackSize = true; + } + else + #endif + { + FosSpec2 = new CFolderInStream2; + FosSpec2->Init(); + sbInStream = FosSpec2; + repackBase = FosSpec2; + + #ifndef Z7_NO_CRYPTO + bool isEncrypted = false; + bool passwordIsDefined = false; + UString password; + #endif + + CMyComPtr decodedStream; + bool dataAfterEnd_Error = false; + + const HRESULT res = threadDecoder.Decoder.Decode( + EXTERNAL_CODECS_LOC_VARS + inStream, + db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);, + *db, folderIndex, + // &importantUnpackSize, // *unpackSize + NULL, // *unpackSize : FULL unpack + + NULL, // *outStream + NULL, // *compressProgress + + &decodedStream + , dataAfterEnd_Error + + Z7_7Z_DECODER_CRYPRO_VARS + #ifndef Z7_ST + , false // mtMode + , 1 // numThreads + , 0 // memUsage + #endif + ); + + RINOK(res) + if (!decodedStream) + return E_FAIL; + + FosSpec2->_inStream = decodedStream; + } + + repackBase->_db = db; + repackBase->_opCallback = opCallback; + repackBase->_extractCallback = extractCallback; + + UInt32 startIndex = db->FolderStartFileIndex[folderIndex]; + RINOK(repackBase->Init(startIndex, &extractStatuses)) + + inStreamSizeCountSpec->_db = db; + inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses); + + #ifndef Z7_ST + if (options.MultiThreadMixer) + { + WRes wres = threadDecoder.Start(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + #endif + } + + // curUnpackSize = sizeToEncode; + + HRESULT encodeRes = encoder.Encode1( + EXTERNAL_CODECS_LOC_VARS + inStreamSizeCount, + // NULL, + &inSizeForReduce, + sizeToEncode, // expectedDataSize + newDatabase.Folders.AddNew(), + // newDatabase.CoderUnpackSizes, curUnpackSize, + archive.SeqStream, newDatabase.PackSizes, lps); + + if (encodeRes == k_My_HRESULT_CRC_ERROR) + return E_FAIL; + + curUnpackSize = inStreamSizeCountSpec->GetSize(); + + if (encodeRes == S_OK) + { + encoder.Encode_Post(curUnpackSize, newDatabase.CoderUnpackSizes); + } + + #ifndef Z7_ST + if (options.MultiThreadMixer) + { + // 16.00: hang was fixed : for case if decoding was not finished. + // We close CBinderInStream and it calls CStreamBinder::CloseRead() + inStreamSizeCount.Release(); + sbInStream.Release(); + + { + const WRes wres = threadDecoder.WaitExecuteFinish(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + + const HRESULT decodeRes = threadDecoder.Result; + // if (res == k_My_HRESULT_CRC_ERROR) + if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error) + { + if (extractCallback) + { + RINOK(extractCallback->ReportExtractResult( + NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex], + // NEventIndexType::kBlockIndex, (UInt32)folderIndex, + (decodeRes != S_OK ? + NExtract::NOperationResult::kDataError : + NExtract::NOperationResult::kDataAfterEnd))) + } + if (decodeRes != S_OK) + return E_FAIL; + } + RINOK(decodeRes) + if (encodeRes == S_OK) + if (sb.ProcessedSize != sizeToEncode) + encodeRes = E_FAIL; + } + else + #endif + { + if (FosSpec2->Result == S_FALSE) + { + if (extractCallback) + { + RINOK(extractCallback->ReportExtractResult( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NExtract::NOperationResult::kDataError)) + } + return E_FAIL; + } + RINOK(FosSpec2->Result) + } + + RINOK(encodeRes) + RINOK(repackBase->CheckFinishedState()) + + if (curUnpackSize != sizeToEncode) + return E_FAIL; + } + + for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) + lps->OutSize += newDatabase.PackSizes[startPackIndex]; + lps->InSize += curUnpackSize; + } + + newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); + + CNum indexInFolder = 0; + for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) + { + if (db->Files[fi].HasStream) + { + indexInFolder++; + const int updateIndex = fileIndexToUpdateIndexMap[fi]; + if (updateIndex >= 0) + { + const CUpdateItem &ui = updateItems[(unsigned)updateIndex]; + if (ui.NewData) + continue; + + UString name; + CFileItem file; + CFileItem2 file2; + GetFile(*db, fi, file, file2); + + if (ui.NewProps) + { + UpdateItem_To_FileItem2(ui, file2); + file.IsDir = ui.IsDir; + name = ui.Name; + } + else + db->GetPath(fi, name); + + /* + file.Parent = ui.ParentFolderIndex; + if (ui.TreeFolderIndex >= 0) + treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(ui.SecureIndex); + */ + newDatabase.AddFile(file, file2, name); + } + } + } + } + + + // ---------- Compress files to new solid blocks ---------- + + const unsigned numFiles = group.Indices.Size(); + if (numFiles == 0) + continue; + CRecordVector refItems; + refItems.ClearAndSetSize(numFiles); + // bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1 + const bool sortByType = options.UseTypeSorting; + + unsigned i; + + for (i = 0; i < numFiles; i++) + refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); + + CSortParam sortParam; + // sortParam.TreeFolders = &treeFolders; + sortParam.SortByType = sortByType; + refItems.Sort(CompareUpdateItems, (void *)&sortParam); + + CObjArray indices(numFiles); + + for (i = 0; i < numFiles; i++) + { + const UInt32 index = refItems[i].Index; + indices[i] = index; + /* + const CUpdateItem &ui = updateItems[index]; + CFileItem file; + if (ui.NewProps) + UpdateItem_To_FileItem(ui, file); + else + file = db.Files[ui.IndexInArchive]; + if (file.IsAnti || file.IsDir) + return E_FAIL; + newDatabase.Files.Add(file); + */ + } + + for (i = 0; i < numFiles;) + { + UInt64 totalSize = 0; + unsigned numSubFiles; + + const wchar_t *prevExtension = NULL; + + for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) + { + const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; + totalSize += ui.Size; + if (totalSize > options.NumSolidBytes) + break; + if (options.SolidExtension) + { + const int slashPos = ui.Name.ReverseFind_PathSepar(); + const int dotPos = ui.Name.ReverseFind_Dot(); + const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : (unsigned)(dotPos + 1)); + if (numSubFiles == 0) + prevExtension = ext; + else if (!StringsAreEqualNoCase(ext, prevExtension)) + break; + } + } + + if (numSubFiles < 1) + numSubFiles = 1; + + RINOK(lps->SetCur()) + + /* + const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size(); + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kAdd)); + } + */ + + + CMyComPtr2_Create inStreamSpec; // solidInStream; + + // inStreamSpec->_reportArcProp = reportArcProp; + + inStreamSpec->Need_CTime = options.Need_CTime; + inStreamSpec->Need_ATime = options.Need_ATime; + inStreamSpec->Need_MTime = options.Need_MTime; + inStreamSpec->Need_Attrib = options.Need_Attrib; + // inStreamSpec->Need_Crc = options.Need_Crc; + + inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); + + unsigned startPackIndex = newDatabase.PackSizes.Size(); + // UInt64 curFolderUnpackSize = totalSize; + // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug + const UInt64 expectedDataSize = totalSize; + + // const unsigned folderIndex_New = newDatabase.Folders.Size(); + + RINOK(encoder.Encode1( + EXTERNAL_CODECS_LOC_VARS + inStreamSpec, + // NULL, + &inSizeForReduce, + expectedDataSize, // expected size + newDatabase.Folders.AddNew(), + // newDatabase.CoderUnpackSizes, curFolderUnpackSize, + archive.SeqStream, newDatabase.PackSizes, lps)) + + if (!inStreamSpec->WasFinished()) + return E_FAIL; + + /* + if (inStreamSpec->Need_FolderCrc) + newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, + true, inStreamSpec->GetFolderCrc()); + */ + + const UInt64 curFolderUnpackSize = inStreamSpec->Get_TotalSize_for_Coder(); + encoder.Encode_Post(curFolderUnpackSize, newDatabase.CoderUnpackSizes); + + UInt64 packSize = 0; + // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex; + for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) + packSize += newDatabase.PackSizes[startPackIndex]; + lps->OutSize += packSize; + + // for () + // newDatabase.PackCRCsDefined.Add(false); + // newDatabase.PackCRCs.Add(0); + + CNum numUnpackStreams = 0; + UInt64 skippedSize = 0; + UInt64 procSize = 0; + // unsigned numProcessedFiles = 0; + + for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) + { + const CUpdateItem &ui = updateItems[indices[i + subIndex]]; + CFileItem file; + CFileItem2 file2; + UString name; + if (ui.NewProps) + { + UpdateItem_To_FileItem(ui, file, file2); + name = ui.Name; + } + else + { + GetFile(*db, (unsigned)ui.IndexInArchive, file, file2); + db->GetPath((unsigned)ui.IndexInArchive, name); + } + if (file2.IsAnti || file.IsDir) + return E_FAIL; + + /* + CFileItem &file = newDatabase.Files[ + startFileIndexInDatabase + i + subIndex]; + */ + if (!inStreamSpec->Processed[subIndex]) + { + // we don't add file here + skippedSize += ui.Size; + continue; // comment it for debug + // name += ".locked"; // for debug + } + + // if (inStreamSpec->Need_Crc) + file.Crc = inStreamSpec->CRCs[subIndex]; + file.Size = inStreamSpec->Sizes[subIndex]; + + procSize += file.Size; + // if (file.Size >= 0) // for debug: test purposes + if (file.Size != 0) + { + file.CrcDefined = true; // inStreamSpec->Need_Crc; + file.HasStream = true; + numUnpackStreams++; + } + else + { + file.CrcDefined = false; + file.HasStream = false; + } + + if (inStreamSpec->TimesDefined[subIndex]) + { + if (inStreamSpec->Need_CTime) + { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; } + if (inStreamSpec->Need_ATime + // && !ui.ATime_WasReadByAnalysis + ) + { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; } + if (inStreamSpec->Need_MTime) + { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; } + if (inStreamSpec->Need_Attrib) + { + file2.AttribDefined = true; + file2.Attrib = inStreamSpec->Attribs[subIndex]; + } + } + + /* + file.Parent = ui.ParentFolderIndex; + if (ui.TreeFolderIndex >= 0) + treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); + if (totalSecureDataSize != 0) + newDatabase.SecureIDs.Add(ui.SecureIndex); + */ + /* + if (reportArcProp) + { + RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size, + file.CrcDefined ? &file.Crc : NULL)) + } + */ + + // numProcessedFiles++; + newDatabase.AddFile(file, file2, name); + } + + /* + // for debug: + // we can write crc to folders area, if folder contains only one file + if (numUnpackStreams == 1 && numSubFiles == 1) + { + const CFileItem &file = newDatabase.Files.Back(); + if (file.CrcDefined) + newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, true, file.Crc); + } + */ + + /* + // it's optional check to ensure that sizes are correct + if (inStreamSpec->TotalSize_for_Coder != curFolderUnpackSize) + return E_FAIL; + */ + // if (inStreamSpec->AlignLog == 0) + { + if (procSize != curFolderUnpackSize) + return E_FAIL; + } + // else + { + /* + { + const CFolder &old = newDatabase.Folders.Back(); + CFolder &folder = newDatabase.Folders.AddNew(); + { + const unsigned numBonds = old.Bonds.Size(); + folder.Bonds.SetSize(numBonds + 1); + for (unsigned k = 0; k < numBonds; k++) + folder.Bonds[k] = old.Bonds[k]; + CBond &bond = folder.Bonds[numBonds]; + bond.PackIndex = 0; + bond.UnpackIndex = 0; + } + { + const unsigned numCoders = old.Coders.Size(); + folder.Coders.SetSize(numCoders + 1); + for (unsigned k = 0; k < numCoders; k++) + folder.Coders[k] = old.Coders[k]; + CCoderInfo &cod = folder.Coders[numCoders]; + cod.Props.Alloc(1); + cod.Props[0] = (Byte)inStreamSpec->AlignLog; + cod.NumStreams = 1; + } + { + const unsigned numPackStreams = old.Coders.Size(); + folder.Coders.SetSize(numPackStreams); + for (unsigned k = 0; k < numPackStreams; k++) + folder.PackStreams[k] = old.PackStreams[k]; + } + } + newDatabase.Folders.Delete(newDatabase.Folders.Size() - 2); + */ + } + + + lps->InSize += procSize; + // lps->InSize += curFolderUnpackSize; + + // numUnpackStreams = 0 is very bad case for locked files + // v3.13 doesn't understand it. + newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); + i += numSubFiles; + + if (skippedSize != 0 && complexity >= skippedSize) + { + complexity -= skippedSize; + RINOK(updateCallback->SetTotal(complexity)) + } + + /* + if (reportArcProp) + { + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + { + NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop)); + } + RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK)); + } + */ + /* + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kOpFinished)); + } + */ + } + } + + RINOK(lps->SetCur()) + + /* + fileIndexToUpdateIndexMap.ClearAndFree(); + groups.ClearAndFree(); + */ + + /* + for (i = 0; i < newDatabase.Files.Size(); i++) + { + CFileItem &file = newDatabase.Files[i]; + file.Parent = treeFolderToArcIndex[file.Parent]; + } + + if (totalSecureDataSize != 0) + { + newDatabase.SecureBuf.SetCapacity(totalSecureDataSize); + size_t pos = 0; + newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size()); + for (i = 0; i < secureBlocks.Sorted.Size(); i++) + { + const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; + size_t size = buf.GetCapacity(); + if (size != 0) + memcpy(newDatabase.SecureBuf + pos, buf, size); + newDatabase.SecureSizes.Add((UInt32)size); + pos += size; + } + } + */ + + { + const unsigned numFolders = newDatabase.Folders.Size(); + if (newDatabase.NumUnpackStreamsVector.Size() != numFolders + || newDatabase.FolderUnpackCRCs.Defs.Size() > numFolders) + return E_FAIL; + newDatabase.FolderUnpackCRCs.if_NonEmpty_FillResidue_with_false(numFolders); + } + + updateItems.ClearAndFree(); + newDatabase.ReserveDown(); + + if (opCallback) + RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader)) + + RINOK(archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS + newDatabase, options.HeaderMethod, options.HeaderOptions)) + + if (v_StreamSetRestriction) + RINOK(v_StreamSetRestriction->SetRestriction(0, 0)) + + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h index 5e7ddb51f..83a27743a 100644 --- a/CPP/7zip/Archive/7z/7zUpdate.h +++ b/CPP/7zip/Archive/7z/7zUpdate.h @@ -1,167 +1,167 @@ -// 7zUpdate.h - -#ifndef ZIP7_INC_7Z_UPDATE_H -#define ZIP7_INC_7Z_UPDATE_H - -#include "../IArchive.h" - -// #include "../../Common/UniqBlocks.h" - -#include "7zCompressionMode.h" -#include "7zIn.h" - -namespace NArchive { -namespace N7z { - -/* -struct CTreeFolder -{ - UString Name; - int Parent; - CIntVector SubFolders; - int UpdateItemIndex; - int SortIndex; - int SortIndexEnd; - - CTreeFolder(): UpdateItemIndex(-1) {} -}; -*/ - -struct CUpdateItem -{ - int IndexInArchive; - unsigned IndexInClient; - - UInt64 CTime; - UInt64 ATime; - UInt64 MTime; - - UInt64 Size; - UString Name; - /* - bool IsAltStream; - int ParentFolderIndex; - int TreeFolderIndex; - */ - - // that code is not used in 9.26 - // int ParentSortIndex; - // int ParentSortIndexEnd; - - UInt32 Attrib; - - bool NewData; - bool NewProps; - - bool IsAnti; - bool IsDir; - - bool AttribDefined; - bool CTimeDefined; - bool ATimeDefined; - bool MTimeDefined; - - // bool ATime_WasReadByAnalysis; - - // int SecureIndex; // 0 means (no_security) - - bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } - // bool HasStream() const { return !IsDir && !IsAnti /* && Size != 0 */; } // for test purposes - - CUpdateItem(): - // ParentSortIndex(-1), - // IsAltStream(false), - IsAnti(false), - IsDir(false), - AttribDefined(false), - CTimeDefined(false), - ATimeDefined(false), - MTimeDefined(false) - // , ATime_WasReadByAnalysis(false) - // SecureIndex(0) - {} - void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } - - // unsigned GetExtensionPos() const; - // UString GetExtension() const; -}; - -struct CUpdateOptions -{ - const CCompressionMethodMode *Method; - const CCompressionMethodMode *HeaderMethod; - bool UseFilters; // use additional filters for some files - bool MaxFilter; // use BCJ2 filter instead of BCJ - int AnalysisLevel; - - UInt64 NumSolidFiles; - UInt64 NumSolidBytes; - bool SolidExtension; - - bool UseTypeSorting; - - bool RemoveSfxBlock; - bool MultiThreadMixer; - - bool Need_CTime; - bool Need_ATime; - bool Need_MTime; - bool Need_Attrib; - // bool Need_Crc; - - CHeaderOptions HeaderOptions; - - CUIntVector DisabledFilterIDs; - - void Add_DisabledFilter_for_id(UInt32 id, - const CUIntVector &enabledFilters) - { - if (enabledFilters.FindInSorted(id) < 0) - DisabledFilterIDs.AddToUniqueSorted(id); - } - - void SetFilterSupporting_ver_enabled_disabled( - UInt32 compatVer, - const CUIntVector &enabledFilters, - const CUIntVector &disabledFilters) - { - DisabledFilterIDs = disabledFilters; - if (compatVer < 2300) Add_DisabledFilter_for_id(k_ARM64, enabledFilters); - if (compatVer < 2402) Add_DisabledFilter_for_id(k_RISCV, enabledFilters); - } - - CUpdateOptions(): - Method(NULL), - HeaderMethod(NULL), - UseFilters(false), - MaxFilter(false), - AnalysisLevel(-1), - NumSolidFiles((UInt64)(Int64)(-1)), - NumSolidBytes((UInt64)(Int64)(-1)), - SolidExtension(false), - UseTypeSorting(true), - RemoveSfxBlock(false), - MultiThreadMixer(true), - Need_CTime(false), - Need_ATime(false), - Need_MTime(false), - Need_Attrib(false) - // , Need_Crc(true) - { - DisabledFilterIDs.Add(k_RISCV); - } -}; - -HRESULT Update( - DECL_EXTERNAL_CODECS_LOC_VARS - IInStream *inStream, - const CDbEx *db, - CObjectVector &updateItems, - // const CObjectVector &treeFolders, // treeFolders[0] is root - // const CUniqBlocks &secureBlocks, - ISequentialOutStream *seqOutStream, - IArchiveUpdateCallback *updateCallback, - const CUpdateOptions &options); -}} - -#endif +// 7zUpdate.h + +#ifndef ZIP7_INC_7Z_UPDATE_H +#define ZIP7_INC_7Z_UPDATE_H + +#include "../IArchive.h" + +// #include "../../Common/UniqBlocks.h" + +#include "7zCompressionMode.h" +#include "7zIn.h" + +namespace NArchive { +namespace N7z { + +/* +struct CTreeFolder +{ + UString Name; + int Parent; + CIntVector SubFolders; + int UpdateItemIndex; + int SortIndex; + int SortIndexEnd; + + CTreeFolder(): UpdateItemIndex(-1) {} +}; +*/ + +struct CUpdateItem +{ + int IndexInArchive; + unsigned IndexInClient; + + UInt64 CTime; + UInt64 ATime; + UInt64 MTime; + + UInt64 Size; + UString Name; + /* + bool IsAltStream; + int ParentFolderIndex; + int TreeFolderIndex; + */ + + // that code is not used in 9.26 + // int ParentSortIndex; + // int ParentSortIndexEnd; + + UInt32 Attrib; + + bool NewData; + bool NewProps; + + bool IsAnti; + bool IsDir; + + bool AttribDefined; + bool CTimeDefined; + bool ATimeDefined; + bool MTimeDefined; + + // bool ATime_WasReadByAnalysis; + + // int SecureIndex; // 0 means (no_security) + + bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } + // bool HasStream() const { return !IsDir && !IsAnti /* && Size != 0 */; } // for test purposes + + CUpdateItem(): + // ParentSortIndex(-1), + // IsAltStream(false), + IsAnti(false), + IsDir(false), + AttribDefined(false), + CTimeDefined(false), + ATimeDefined(false), + MTimeDefined(false) + // , ATime_WasReadByAnalysis(false) + // SecureIndex(0) + {} + void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } + + // unsigned GetExtensionPos() const; + // UString GetExtension() const; +}; + +struct CUpdateOptions +{ + const CCompressionMethodMode *Method; + const CCompressionMethodMode *HeaderMethod; + bool UseFilters; // use additional filters for some files + bool MaxFilter; // use BCJ2 filter instead of BCJ + int AnalysisLevel; + + UInt64 NumSolidFiles; + UInt64 NumSolidBytes; + bool SolidExtension; + + bool UseTypeSorting; + + bool RemoveSfxBlock; + bool MultiThreadMixer; + + bool Need_CTime; + bool Need_ATime; + bool Need_MTime; + bool Need_Attrib; + // bool Need_Crc; + + CHeaderOptions HeaderOptions; + + CUIntVector DisabledFilterIDs; + + void Add_DisabledFilter_for_id(UInt32 id, + const CUIntVector &enabledFilters) + { + if (enabledFilters.FindInSorted(id) < 0) + DisabledFilterIDs.AddToUniqueSorted(id); + } + + void SetFilterSupporting_ver_enabled_disabled( + UInt32 compatVer, + const CUIntVector &enabledFilters, + const CUIntVector &disabledFilters) + { + DisabledFilterIDs = disabledFilters; + if (compatVer < 2300) Add_DisabledFilter_for_id(k_ARM64, enabledFilters); + if (compatVer < 2402) Add_DisabledFilter_for_id(k_RISCV, enabledFilters); + } + + CUpdateOptions(): + Method(NULL), + HeaderMethod(NULL), + UseFilters(false), + MaxFilter(false), + AnalysisLevel(-1), + NumSolidFiles((UInt64)(Int64)(-1)), + NumSolidBytes((UInt64)(Int64)(-1)), + SolidExtension(false), + UseTypeSorting(true), + RemoveSfxBlock(false), + MultiThreadMixer(true), + Need_CTime(false), + Need_ATime(false), + Need_MTime(false), + Need_Attrib(false) + // , Need_Crc(true) + { + DisabledFilterIDs.Add(k_RISCV); + } +}; + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + const CDbEx *db, + CObjectVector &updateItems, + // const CObjectVector &treeFolders, // treeFolders[0] is root + // const CUniqBlocks &secureBlocks, + ISequentialOutStream *seqOutStream, + IArchiveUpdateCallback *updateCallback, + const CUpdateOptions &options); +}} + +#endif diff --git a/CPP/7zip/Archive/7z/StdAfx.cpp b/CPP/7zip/Archive/7z/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Archive/7z/StdAfx.cpp +++ b/CPP/7zip/Archive/7z/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/7z/StdAfx.h b/CPP/7zip/Archive/7z/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/7z/StdAfx.h +++ b/CPP/7zip/Archive/7z/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile index 005f82a22..ff60e4d43 100644 --- a/CPP/7zip/Archive/7z/makefile +++ b/CPP/7zip/Archive/7z/makefile @@ -1,81 +1,81 @@ -PROG = 7z.dll -DEF_FILE = ../Archive.def -CFLAGS = $(CFLAGS) \ - -DZ7_EXTERNAL_CODECS \ - -AR_OBJS = \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zEncode.obj \ - $O\7zExtract.obj \ - $O\7zFolderInStream.obj \ - $O\7zHandler.obj \ - $O\7zHandlerOut.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zOut.obj \ - $O\7zProperties.obj \ - $O\7zSpecStream.obj \ - $O\7zUpdate.obj \ - $O\7zRegister.obj \ - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\IntToString.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\InOutTempBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\LockedStream.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\VirtThread.obj \ - -COMPRESS_OBJS = \ - $O\CopyCoder.obj \ - $O\CodecExports.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\HandlerOut.obj \ - $O\InStreamWithCRC.obj \ - $O\ItemNameUtils.obj \ - $O\MultiStream.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" - -!include "../../7zip.mak" +PROG = 7z.dll +DEF_FILE = ../Archive.def +CFLAGS = $(CFLAGS) \ + -DZ7_EXTERNAL_CODECS \ + +AR_OBJS = \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zEncode.obj \ + $O\7zExtract.obj \ + $O\7zFolderInStream.obj \ + $O\7zHandler.obj \ + $O\7zHandlerOut.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zOut.obj \ + $O\7zProperties.obj \ + $O\7zSpecStream.obj \ + $O\7zUpdate.obj \ + $O\7zRegister.obj \ + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\InOutTempBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\LockedStream.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\VirtThread.obj \ + +COMPRESS_OBJS = \ + $O\CopyCoder.obj \ + $O\CodecExports.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\HandlerOut.obj \ + $O\InStreamWithCRC.obj \ + $O\ItemNameUtils.obj \ + $O\MultiStream.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Archive/7z/resource.rc b/CPP/7zip/Archive/7z/resource.rc index 3958af8b9..f79dac088 100644 --- a/CPP/7zip/Archive/7z/resource.rc +++ b/CPP/7zip/Archive/7z/resource.rc @@ -1,11 +1,11 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Plugin", "7z") - -0 ICON "../Icons/7z.ico" - -STRINGTABLE -BEGIN - 100 "7z:0" -END - +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_DLL("7z Plugin", "7z") + +0 ICON "../Icons/7z.ico" + +STRINGTABLE +BEGIN + 100 "7z:0" +END + diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp index e08e97311..62b00ed5b 100644 --- a/CPP/7zip/Archive/ApfsHandler.cpp +++ b/CPP/7zip/Archive/ApfsHandler.cpp @@ -1,4470 +1,4470 @@ -// ApfsHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - -#include "../../../C/CpuArch.h" -#include "../../../C/Sha256.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer2.h" -#include "../../Common/MyLinux.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariantConv.h" -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/ItemNameUtils.h" - -#include "HfsHandler.h" - -// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files. -#define APFS_SHOW_ALT_STREAMS - -#define VI_MINUS1 ((unsigned)(int)-1) -#define IsViDef(x) ((int)(x) != -1) -#define IsViNotDef(x) ((int)(x) == -1) - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(_offs_, dest) dest = Get16(p + (_offs_)); -#define G32(_offs_, dest) dest = Get32(p + (_offs_)); -#define G64(_offs_, dest) dest = Get64(p + (_offs_)); - -namespace NArchive { -namespace NApfs { - -struct CUuid -{ - Byte Data[16]; - - void SetHex_To_str(char *s) const - { - ConvertDataToHex_Lower(s, Data, sizeof(Data)); - } - - void AddHexToString(UString &dest) const - { - char temp[sizeof(Data) * 2 + 4]; - SetHex_To_str(temp); - dest += temp; - } - - void SetFrom(const Byte *p) { memcpy(Data, p, 16); } -}; - - -typedef UInt64 oid_t; -typedef UInt64 xid_t; -// typedef Int64 paddr_t; -typedef UInt64 paddr_t_unsigned; - -#define G64o G64 -#define G64x G64 -// #define G64a G64 - -/* -struct prange_t -{ - paddr_t start_paddr; - UInt64 block_count; - - void Parse(const Byte *p) - { - G64a (0, start_paddr); - G64 (8, block_count); - } -}; -*/ - -#define OBJECT_TYPE_NX_SUPERBLOCK 0x1 -#define OBJECT_TYPE_BTREE 0x2 -#define OBJECT_TYPE_BTREE_NODE 0x3 -/* -#define OBJECT_TYPE_SPACEMAN 0x5 -#define OBJECT_TYPE_SPACEMAN_CAB 0x6 -#define OBJECT_TYPE_SPACEMAN_CIB 0x7 -#define OBJECT_TYPE_SPACEMAN_BITMAP 0x8 -#define OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x9 -#define OBJECT_TYPE_EXTENT_LIST_TREE 0xa -*/ -#define OBJECT_TYPE_OMAP 0xb -/* -#define OBJECT_TYPE_CHECKPOINT_MAP 0xc -*/ -#define OBJECT_TYPE_FS 0xd -#define OBJECT_TYPE_FSTREE 0xe -/* -#define OBJECT_TYPE_BLOCKREFTREE 0xf -#define OBJECT_TYPE_SNAPMETATREE 0x10 -#define OBJECT_TYPE_NX_REAPER 0x11 -#define OBJECT_TYPE_NX_REAP_LIST 0x12 -#define OBJECT_TYPE_OMAP_SNAPSHOT 0x13 -#define OBJECT_TYPE_EFI_JUMPSTART 0x14 -#define OBJECT_TYPE_FUSION_MIDDLE_TREE 0x15 -#define OBJECT_TYPE_NX_FUSION_WBC 0x16 -#define OBJECT_TYPE_NX_FUSION_WBC_LIST 0x17 -#define OBJECT_TYPE_ER_STATE 0x18 -#define OBJECT_TYPE_GBITMAP 0x19 -#define OBJECT_TYPE_GBITMAP_TREE 0x1a -#define OBJECT_TYPE_GBITMAP_BLOCK 0x1b -#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x1c -#define OBJECT_TYPE_SNAP_META_EXT 0x1d -*/ -#define OBJECT_TYPE_INTEGRITY_META 0x1e -#define OBJECT_TYPE_FEXT_TREE 0x1f -/* -#define OBJECT_TYPE_RESERVED_20 0x20 - -#define OBJECT_TYPE_INVALID 0x0 -#define OBJECT_TYPE_TEST 0xff -#define OBJECT_TYPE_CONTAINER_KEYBAG 'keys' -#define OBJECT_TYPE_VOLUME_KEYBAG 'recs' -#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey' - -#define OBJ_VIRTUAL 0x0 -#define OBJ_EPHEMERAL 0x80000000 -*/ -#define OBJ_PHYSICAL 0x40000000 -/* -#define OBJ_NOHEADER 0x20000000 -#define OBJ_ENCRYPTED 0x10000000 -#define OBJ_NONPERSISTENT 0x08000000 -*/ -#define OBJECT_TYPE_MASK 0x0000ffff -/* -#define OBJECT_TYPE_FLAGS_MASK 0xffff0000 -#define OBJ_STORAGETYPE_MASK 0xc0000000 -#define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000 -*/ - -// #define MAX_CKSUM_SIZE 8 - -static const unsigned k_obj_phys_Size = 0x20; - -// obj_phys_t -struct CPhys -{ - // Byte cksum[MAX_CKSUM_SIZE]; - oid_t oid; - xid_t xid; - UInt32 type; - UInt32 subtype; - - UInt32 GetType() const { return type & OBJECT_TYPE_MASK; } - void Parse(const Byte *p); -}; - -void CPhys::Parse(const Byte *p) -{ - // memcpy(cksum, p, MAX_CKSUM_SIZE); - G64o (8, oid) - G64x (0x10, xid) - G32 (0x18, type) - G32 (0x1C, subtype) -} - -#define NX_MAX_FILE_SYSTEMS 100 -/* -#define NX_EPH_INFO_COUNT 4 -#define NX_EPH_MIN_BLOCK_COUNT 8 -#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4 -#define NX_TX_MIN_CHECKPOINT_COUNT 4 -#define NX_EPH_INFO_VERSION_1 1 -*/ - -/* -typedef enum -{ - NX_CNTR_OBJ_CKSUM_SET = 0, - NX_CNTR_OBJ_CKSUM_FAIL = 1, - NX_NUM_COUNTERS = 32 -} counter_id_t; -*/ - -/* Incompatible volume feature flags */ -#define APFS_INCOMPAT_CASE_INSENSITIVE (1 << 0) -/* -#define APFS_INCOMPAT_DATALESS_SNAPS (1 << 1) -#define APFS_INCOMPAT_ENC_ROLLED (1 << 2) -*/ -#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE (1 << 3) -/* -#define APFS_INCOMPAT_INCOMPLETE_RESTORE (1 << 4) -*/ -#define APFS_INCOMPAT_SEALED_VOLUME (1 << 5) -/* -#define APFS_INCOMPAT_RESERVED_40 (1 << 6) -*/ - -static const char * const g_APFS_INCOMPAT_Flags[] = -{ - "CASE_INSENSITIVE" - , "DATALESS_SNAPS" - , "ENC_ROLLED" - , "NORMALIZATION_INSENSITIVE" - , "INCOMPLETE_RESTORE" - , "SEALED_VOLUME" -}; - -/* -#define APFS_SUPPORTED_INCOMPAT_MASK \ - ( APFS_INCOMPAT_CASE_INSENSITIVE \ - | APFS_INCOMPAT_DATALESS_SNAPS \ - | APFS_INCOMPAT_ENC_ROLLED \ - | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \ - | APFS_INCOMPAT_INCOMPLETE_RESTORE \ - | APFS_INCOMPAT_SEALED_VOLUME \ - | APFS_INCOMPAT_RESERVED_40 \ -) -*/ - -// superblock_t -struct CSuperBlock -{ - // CPhys o; - // UInt32 magic; - UInt32 block_size; - unsigned block_size_Log; - UInt64 block_count; - // UInt64 features; - // UInt64 readonly_compatible_features; - // UInt64 incompatible_features; - CUuid uuid; - /* - oid_t next_oid; - xid_t next_xid; - UInt32 xp_desc_blocks; - UInt32 xp_data_blocks; - paddr_t xp_desc_base; - paddr_t xp_data_base; - UInt32 xp_desc_next; - UInt32 xp_data_next; - UInt32 xp_desc_index; - UInt32 xp_desc_len; - UInt32 xp_data_index; - UInt32 xp_data_len; - oid_t spaceman_oid; - */ - oid_t omap_oid; - // oid_t reaper_oid; - // UInt32 test_type; - UInt32 max_file_systems; - // oid_t fs_oid[NX_MAX_FILE_SYSTEMS]; - /* - UInt64 counters[NX_NUM_COUNTERS]; // counter_id_t - prange_t blocked_out_prange; - oid_t evict_mapping_tree_oid; - UInt64 flags; - paddr_t efi_jumpstart; - CUuid fusion_uuid; - prange_t keylocker; - UInt64 ephemeral_info[NX_EPH_INFO_COUNT]; - oid_t test_oid; - oid_t fusion_mt_oid; - oid_t fusion_wbc_oid; - prange_t fusion_wbc; - UInt64 newest_mounted_version; - prange_t mkb_locker; - */ - - bool Parse(const Byte *p); -}; - -struct CSuperBlock2 -{ - oid_t fs_oid[NX_MAX_FILE_SYSTEMS]; - void Parse(const Byte *p) - { - for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++) - { - G64o (0xb8 + i * 8, fs_oid[i]) - } - } -}; - - -// we include one additional byte of next field (block_size) -static const unsigned k_SignatureOffset = 32; -static const Byte k_Signature[] = { 'N', 'X', 'S', 'B', 0 }; - -// size must be 4 bytes aligned -static UInt64 Fletcher64(const Byte *data, size_t size) -{ - const UInt32 kMax32 = 0xffffffff; - const UInt64 val = 0; // startVal - UInt64 a = val & kMax32; - UInt64 b = (val >> 32) & kMax32; - for (size_t i = 0; i < size; i += 4) - { - a += GetUi32(data + i); - b += a; - } - a %= kMax32; - b %= kMax32; - b = (UInt32)(kMax32 - ((a + b) % kMax32)); - a = (UInt32)(kMax32 - ((a + b) % kMax32)); - return (a << 32) | b; -} - -static bool CheckFletcher64(const Byte *p, size_t size) -{ - const UInt64 calculated_checksum = Fletcher64(p + 8, size - 8); - const UInt64 stored_checksum = Get64(p); - return (stored_checksum == calculated_checksum); -} - - -static unsigned GetLogSize(UInt32 size) -{ - unsigned k; - for (k = 0; k < 32; k++) - if (((UInt32)1 << k) == size) - return k; - return k; -} - -static const unsigned kApfsHeaderSize = 1 << 12; - -// #define OID_INVALID 0 -#define OID_NX_SUPERBLOCK 1 -// #define OID_RESERVED_COUNT 1024 -// This range of identifiers is reserved for physical, virtual, and ephemeral objects - -bool CSuperBlock::Parse(const Byte *p) -{ - CPhys o; - o.Parse(p); - if (o.oid != OID_NX_SUPERBLOCK) - return false; - if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) - return false; - if (o.subtype != 0) - return false; - if (memcmp(p + k_SignatureOffset, k_Signature, 4) != 0) - return false; - if (!CheckFletcher64(p, kApfsHeaderSize)) - return false; - - G32 (0x24, block_size) - { - const unsigned logSize = GetLogSize(block_size); - // don't change it. Some code requires (block_size <= 16) - if (logSize < 12 || logSize > 16) - return false; - block_size_Log = logSize; - } - - G64 (0x28, block_count) - - const UInt64 kArcSize_MAX = (UInt64)1 << 62; - if (block_count > (kArcSize_MAX >> block_size_Log)) - return false; - - // G64 (0x30, features); - // G64 (0x38, readonly_compatible_features); - // G64 (0x40, incompatible_features); - uuid.SetFrom(p + 0x48); - /* - G64o (0x58, next_oid); - G64x (0x60, next_xid); - G32 (0x68, xp_desc_blocks); - G32 (0x6c, xp_data_blocks); - G64a (0x70, xp_desc_base); - G64a (0x78, xp_data_base); - G32 (0x80, xp_desc_next); - G32 (0x84, xp_data_next); - G32 (0x88, xp_desc_index); - G32 (0x8c, xp_desc_len); - G32 (0x90, xp_data_index); - G32 (0x94, xp_data_len); - G64o (0x98, spaceman_oid); - */ - G64o (0xa0, omap_oid) - // G64o (0xa8, reaper_oid); - // G32 (0xb0, test_type); - G32 (0xb4, max_file_systems) - if (max_file_systems > NX_MAX_FILE_SYSTEMS) - return false; - /* - { - for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++) - { - G64o (0xb8 + i * 8, fs_oid[i]); - } - } - */ - /* - { - for (unsigned i = 0; i < NX_NUM_COUNTERS; i++) - { - G64 (0x3d8 + i * 8, counters[i]); - } - } - blocked_out_prange.Parse(p + 0x4d8); - G64o (0x4e8, evict_mapping_tree_oid); - #define NX_CRYPTO_SW 0x00000004LL - G64 (0x4f0, flags); - G64a (0x4f8, efi_jumpstart); - fusion_uuid.SetFrom(p + 0x500); - keylocker.Parse(p + 0x510); - { - for (unsigned i = 0; i < NX_EPH_INFO_COUNT; i++) - { - G64 (0x520 + i * 8, ephemeral_info[i]); - } - } - G64o (0x540, test_oid); - G64o (0x548, fusion_mt_oid); - G64o (0x550, fusion_wbc_oid); - fusion_wbc.Parse(p + 0x558); - G64 (0x568, newest_mounted_version); // decimal 1412141 001 000 000 - mkb_locker.Parse(p + 0x570); - */ - - return true; -} - - -enum apfs_hash_type_t -{ - APFS_HASH_INVALID = 0, - APFS_HASH_SHA256 = 1, - APFS_HASH_SHA512_256 = 2, - APFS_HASH_SHA384 = 3, - APFS_HASH_SHA512 = 4, - - APFS_HASH_MIN = APFS_HASH_SHA256, - APFS_HASH_MAX = APFS_HASH_SHA512, - - APFS_HASH_DEFAULT = APFS_HASH_SHA256 -}; - -static unsigned GetHashSize(unsigned hashType) -{ - if (hashType > APFS_HASH_MAX) return 0; - if (hashType < APFS_HASH_MIN) return 0; - if (hashType == APFS_HASH_SHA256) return 32; - return hashType * 16; -} - -#define APFS_HASH_MAX_SIZE 64 - -static const char * const g_hash_types[] = -{ - NULL - , "SHA256" - , "SHA512_256" - , "SHA384" - , "SHA512" -}; - - -struct C_integrity_meta_phys -{ - // CPhys im_o; - // UInt32 im_version; - UInt32 im_flags; - // apfs_hash_type_t - UInt32 im_hash_type; - // UInt32 im_root_hash_offset; - // xid_t im_broken_xid; - // UInt64 im_reserved[9]; - - unsigned HashSize; - Byte Hash[APFS_HASH_MAX_SIZE]; - - bool Is_SHA256() const { return im_hash_type == APFS_HASH_SHA256; } - - C_integrity_meta_phys() - { - memset(this, 0, sizeof(*this)); - } - bool Parse(const Byte *p, size_t size, oid_t oid); -}; - -bool C_integrity_meta_phys::Parse(const Byte *p, size_t size, oid_t oid) -{ - CPhys o; - if (!CheckFletcher64(p, size)) - return false; - o.Parse(p); - if (o.GetType() != OBJECT_TYPE_INTEGRITY_META) - return false; - if (o.oid != oid) - return false; - // G32 (0x20, im_version); - G32 (0x24, im_flags) - G32 (0x28, im_hash_type) - UInt32 im_root_hash_offset; - G32 (0x2C, im_root_hash_offset) - // G64x (0x30, im_broken_xid); - const unsigned hashSize = GetHashSize(im_hash_type); - HashSize = hashSize; - if (im_root_hash_offset >= size || size - im_root_hash_offset < hashSize) - return false; - memcpy(Hash, p + im_root_hash_offset, hashSize); - return true; -} - - -struct C_omap_phys -{ - // om_ prefix - // CPhys o; - /* - UInt32 flags; - UInt32 snap_count; - UInt32 tree_type; - UInt32 snapshot_tree_type; - */ - oid_t tree_oid; - /* - oid_t snapshot_tree_oid; - xid_t most_recent_snap; - xid_t pending_revert_min; - xid_t pending_revert_max; - */ - bool Parse(const Byte *p, size_t size, oid_t oid); -}; - -bool C_omap_phys::Parse(const Byte *p, size_t size, oid_t oid) -{ - CPhys o; - if (!CheckFletcher64(p, size)) - return false; - o.Parse(p); - if (o.GetType() != OBJECT_TYPE_OMAP) - return false; - if (o.oid != oid) - return false; - /* - G32 (0x20, flags); - G32 (0x24, snap_count); - G32 (0x28, tree_type); - G32 (0x2C, snapshot_tree_type); - */ - G64o (0x30, tree_oid) - /* - G64o (0x38, snapshot_tree_oid); - G64x (0x40, most_recent_snap); - G64x (0x48, pending_revert_min); - G64x (0x50, pending_revert_max); - */ - return true; -} - - -// #define BTOFF_INVALID 0xffff -/* This value is stored in the off field of nloc_t to indicate that -there's no offset. For example, the last entry in a free -list has no entry after it, so it uses this value for its off field. */ - -// A location within a B-tree node -struct nloc -{ - UInt16 off; - UInt16 len; - - void Parse(const Byte *p) - { - G16 (0, off) - G16 (2, len) - } - UInt32 GetEnd() const { return (UInt32)off + len; } - bool CheckOverLimit(UInt32 limit) - { - return off < limit && len <= limit - off; - } -}; - - -// The location, within a B-tree node, of a key and value -struct kvloc -{ - nloc k; - nloc v; - - void Parse(const Byte *p) - { - k.Parse(p); - v.Parse(p + 4); - } -}; - - -// The location, within a B-tree node, of a fixed-size key and value -struct kvoff -{ - UInt16 k; - UInt16 v; - - void Parse(const Byte *p) - { - G16 (0, k) - G16 (2, v) - } -}; - - -#define BTNODE_ROOT (1 << 0) -#define BTNODE_LEAF (1 << 1) -#define BTNODE_FIXED_KV_SIZE (1 << 2) -#define BTNODE_HASHED (1 << 3) -#define BTNODE_NOHEADER (1 << 4) -/* -#define BTNODE_CHECK_KOFF_INVAL (1 << 15) -*/ - -static const unsigned k_Toc_offset = 0x38; - -// btree_node_phys -struct CBTreeNodePhys -{ - // btn_ prefix - CPhys ophys; - UInt16 flags; - UInt16 level; // the number of child levels below this node. 0 - for a leaf node, 1 for the immediate parent of a leaf node - UInt32 nkeys; // The number of keys stored in this node. - nloc table_space; - /* - nloc free_space; - nloc key_free_list; - nloc val_free_list; - */ - - bool Is_FIXED_KV_SIZE() const { return (flags & BTNODE_FIXED_KV_SIZE) != 0; } - bool Is_NOHEADER() const { return (flags & BTNODE_NOHEADER) != 0; } - bool Is_HASHED() const { return (flags & BTNODE_HASHED) != 0; } - - bool Parse(const Byte *p, size_t size, bool noHeader = false) - { - G16 (0x20, flags) - G16 (0x22, level) - G32 (0x24, nkeys) - table_space.Parse(p + 0x28); - /* - free_space.Parse(p + 0x2C); - key_free_list.Parse(p + 0x30); - val_free_list.Parse(p + 0x34); - */ - memset(&ophys, 0, sizeof(ophys)); - if (noHeader) - { - for (unsigned i = 0; i < k_obj_phys_Size; i++) - if (p[i] != 0) - return false; - } - else - { - if (!CheckFletcher64(p, size)) - return false; - ophys.Parse(p); - } - if (Is_NOHEADER() != noHeader) - return false; - return true; - } -}; - -/* -#define BTREE_UINT64_KEYS (1 << 0) -#define BTREE_SEQUENTIAL_INSERT (1 << 1) -#define BTREE_ALLOW_GHOSTS (1 << 2) -*/ -#define BTREE_EPHEMERAL (1 << 3) -#define BTREE_PHYSICAL (1 << 4) -/* -#define BTREE_NONPERSISTENT (1 << 5) -#define BTREE_KV_NONALIGNED (1 << 6) -#define BTREE_HASHED (1 << 7) -*/ -#define BTREE_NOHEADER (1 << 8) - -/* - BTREE_EPHEMERAL: The nodes in the B-tree use ephemeral object identifiers to link to child nodes - BTREE_PHYSICAL : The nodes in the B-tree use physical object identifiers to link to child nodes. - If neither flag is set, nodes in the B-tree use virtual object - identifiers to link to their child nodes. -*/ - -// Static information about a B-tree. -struct btree_info_fixed -{ - UInt32 flags; - UInt32 node_size; - UInt32 key_size; - UInt32 val_size; - - void Parse(const Byte *p) - { - G32 (0, flags) - G32 (4, node_size) - G32 (8, key_size) - G32 (12, val_size) - } -}; - -static const unsigned k_btree_info_Size = 0x28; - -struct btree_info -{ - btree_info_fixed fixed; - UInt32 longest_key; - UInt32 longest_val; - UInt64 key_count; - UInt64 node_count; - - bool Is_EPHEMERAL() const { return (fixed.flags & BTREE_EPHEMERAL) != 0; } - bool Is_PHYSICAL() const { return (fixed.flags & BTREE_PHYSICAL) != 0; } - bool Is_NOHEADER() const { return (fixed.flags & BTREE_NOHEADER) != 0; } - - void Parse(const Byte *p) - { - fixed.Parse(p); - G32 (0x10, longest_key) - G32 (0x14, longest_val) - G64 (0x18, key_count) - G64 (0x20, node_count) - } -}; - - -/* -typedef UInt32 cp_key_class_t; -typedef UInt32 cp_key_os_version_t; -typedef UInt16 cp_key_revision_t; -typedef UInt32 crypto_flags_t; - -struct wrapped_meta_crypto_state -{ - UInt16 major_version; - UInt16 minor_version; - crypto_flags_t cpflags; - cp_key_class_t persistent_class; - cp_key_os_version_t key_os_version; - cp_key_revision_t key_revision; - // UInt16 unused; - - void Parse(const Byte *p) - { - G16 (0, major_version); - G16 (2, minor_version); - G32 (4, cpflags); - G32 (8, persistent_class); - G32 (12, key_os_version); - G16 (16, key_revision); - } -}; -*/ - - -#define APFS_MODIFIED_NAMELEN 32 -#define sizeof_apfs_modified_by_t (APFS_MODIFIED_NAMELEN + 16) - -struct apfs_modified_by_t -{ - Byte id[APFS_MODIFIED_NAMELEN]; - UInt64 timestamp; - xid_t last_xid; - - void Parse(const Byte *p) - { - memcpy(id, p, APFS_MODIFIED_NAMELEN); - p += APFS_MODIFIED_NAMELEN; - G64 (0, timestamp) - G64x (8, last_xid) - } -}; - - -#define APFS_MAX_HIST 8 -#define APFS_VOLNAME_LEN 256 - -struct CApfs -{ - // apfs_ - CPhys o; - // UInt32 magic; - UInt32 fs_index; // index of the object identifier for this volume's file system in the container's array of file systems. - // UInt64 features; - // UInt64 readonly_compatible_features; - UInt64 incompatible_features; - UInt64 unmount_time; - // UInt64 fs_reserve_block_count; - // UInt64 fs_quota_block_count; - UInt64 fs_alloc_count; - // wrapped_meta_crypto_state meta_crypto; - // UInt32 root_tree_type; - /* The type of the root file-system tree. - The value is typically OBJ_VIRTUAL | OBJECT_TYPE_BTREE, - with a subtype of OBJECT_TYPE_FSTREE */ - - // UInt32 extentref_tree_type; - // UInt32 snap_meta_tree_type; - oid_t omap_oid; - oid_t root_tree_oid; - /* - oid_t extentref_tree_oid; - oid_t snap_meta_tree_oid; - xid_t revert_to_xid; - oid_t revert_to_sblock_oid; - UInt64 next_obj_id; - */ - UInt64 num_files; - UInt64 num_directories; - UInt64 num_symlinks; - UInt64 num_other_fsobjects; - UInt64 num_snapshots; - UInt64 total_blocks_alloced; - UInt64 total_blocks_freed; - CUuid vol_uuid; - UInt64 last_mod_time; - UInt64 fs_flags; - apfs_modified_by_t formatted_by; - apfs_modified_by_t modified_by[APFS_MAX_HIST]; - Byte volname[APFS_VOLNAME_LEN]; - /* - UInt32 next_doc_id; - UInt16 role; // APFS_VOL_ROLE_NONE APFS_VOL_ROLE_SYSTEM .... - UInt16 reserved; - xid_t root_to_xid; - oid_t er_state_oid; - UInt64 cloneinfo_id_epoch; - UInt64 cloneinfo_xid; - oid_t snap_meta_ext_oid; - CUuid volume_group_id; - */ - oid_t integrity_meta_oid; // virtual object identifier of the integrity metadata object - oid_t fext_tree_oid; // virtual object identifier of the file extent tree. - UInt32 fext_tree_type; // The type of the file extent tree. - /* - UInt32 reserved_type; - oid_t reserved_oid; - */ - - UInt64 GetTotalItems() const - { - return num_files + num_directories + num_symlinks + num_other_fsobjects; - } - - bool IsHashedName() const - { - return - (incompatible_features & APFS_INCOMPAT_CASE_INSENSITIVE) != 0 || - (incompatible_features & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) != 0; - } - - bool Parse(const Byte *p, size_t size); -}; - - -bool CApfs::Parse(const Byte *p, size_t size) -{ - o.Parse(p); - if (Get32(p + 32) != 0x42535041) // { 'A', 'P', 'S', 'B' }; - return false; - if (o.GetType() != OBJECT_TYPE_FS) - return false; - if (!CheckFletcher64(p, size)) - return false; - // if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) return false; - - G32 (0x24, fs_index) - // G64 (0x28, features); - // G64 (0x30, readonly_compatible_features); - G64 (0x38, incompatible_features) - G64 (0x40, unmount_time) - // G64 (0x48, fs_reserve_block_count); - // G64 (0x50, fs_quota_block_count); - G64 (0x58, fs_alloc_count) - // meta_crypto.Parse(p + 0x60); - // G32 (0x74, root_tree_type); - // G32 (0x78, extentref_tree_type); - // G32 (0x7C, snap_meta_tree_type); - - G64o (0x80, omap_oid) - G64o (0x88, root_tree_oid) - /* - G64o (0x90, extentref_tree_oid); - G64o (0x98, snap_meta_tree_oid); - G64x (0xa0, revert_to_xid); - G64o (0xa8, revert_to_sblock_oid); - G64 (0xb0, next_obj_id); - */ - G64 (0xb8, num_files) - G64 (0xc0, num_directories) - G64 (0xc8, num_symlinks) - G64 (0xd0, num_other_fsobjects) - G64 (0xd8, num_snapshots) - G64 (0xe0, total_blocks_alloced) - G64 (0xe8, total_blocks_freed) - vol_uuid.SetFrom(p + 0xf0); - G64 (0x100, last_mod_time) - G64 (0x108, fs_flags) - p += 0x110; - formatted_by.Parse(p); - p += sizeof_apfs_modified_by_t; - for (unsigned i = 0; i < APFS_MAX_HIST; i++) - { - modified_by[i].Parse(p); - p += sizeof_apfs_modified_by_t; - } - memcpy(volname, p, APFS_VOLNAME_LEN); - p += APFS_VOLNAME_LEN; - /* - G32 (0, next_doc_id); - G16 (4, role); - G16 (6, reserved); - G64x (8, root_to_xid); - G64o (0x10, er_state_oid); - G64 (0x18, cloneinfo_id_epoch); - G64 (0x20, cloneinfo_xid); - G64o (0x28, snap_meta_ext_oid); - volume_group_id.SetFrom(p + 0x30); - */ - G64o (0x40, integrity_meta_oid) - G64o (0x48, fext_tree_oid) - G32 (0x50, fext_tree_type) - /* - G32 (0x54, reserved_type); - G64o (0x58, reserved_oid); - */ - return true; -} - - -#define OBJ_ID_MASK 0x0fffffffffffffff -/* -#define OBJ_TYPE_MASK 0xf000000000000000 -#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000 -*/ -#define OBJ_TYPE_SHIFT 60 - -typedef enum -{ - APFS_TYPE_ANY = 0, - APFS_TYPE_SNAP_METADATA = 1, - APFS_TYPE_EXTENT = 2, - APFS_TYPE_INODE = 3, - APFS_TYPE_XATTR = 4, - APFS_TYPE_SIBLING_LINK = 5, - APFS_TYPE_DSTREAM_ID = 6, - APFS_TYPE_CRYPTO_STATE = 7, - APFS_TYPE_FILE_EXTENT = 8, - APFS_TYPE_DIR_REC = 9, - APFS_TYPE_DIR_STATS = 10, - APFS_TYPE_SNAP_NAME = 11, - APFS_TYPE_SIBLING_MAP = 12, - APFS_TYPE_FILE_INFO = 13, - APFS_TYPE_MAX_VALID = 13, - APFS_TYPE_MAX = 15, - APFS_TYPE_INVALID = 15 -} j_obj_types; - - -struct j_key_t -{ - UInt64 obj_id_and_type; - - void Parse(const Byte *p) { G64(0, obj_id_and_type) } - unsigned GetType() const { return (unsigned)(obj_id_and_type >> OBJ_TYPE_SHIFT); } - UInt64 GetID() const { return obj_id_and_type & OBJ_ID_MASK; } -}; - - - -#define J_DREC_LEN_MASK 0x000003ff -/* -#define J_DREC_HASH_MASK 0xfffff400 -#define J_DREC_HASH_SHIFT 10 -*/ - -static const unsigned k_SizeOf_j_drec_val = 0x12; - -struct j_drec_val -{ - UInt64 file_id; - UInt64 date_added; /* The time that this directory entry was added to the directory. - It's not updated when modifying the directory entry for example, - by renaming a file without moving it to a different directory. */ - UInt16 flags; - - // bool IsFlags_File() const { return flags == MY_LIN_DT_REG; } - bool IsFlags_Unknown() const { return flags == MY_LIN_DT_UNKNOWN; } - bool IsFlags_Dir() const { return flags == MY_LIN_DT_DIR; } - - // uint8_t xfields[]; - void Parse(const Byte *p) - { - G64 (0, file_id) - G64 (8, date_added) - G16 (0x10, flags) - } -}; - - -struct CItem -{ - // j_key_t hdr; - UInt64 ParentId; - AString Name; - j_drec_val Val; - - unsigned ParentItemIndex; - unsigned RefIndex; - // unsigned iNode_Index; - - void Clear() - { - Name.Empty(); - ParentItemIndex = VI_MINUS1; - RefIndex = VI_MINUS1; - } -}; - - -/* -#define INVALID_INO_NUM 0 -#define ROOT_DIR_PARENT 1 // parent for "root" and "private-dir", there's no inode on disk with this inode number. -*/ -#define ROOT_DIR_INO_NUM 2 // "root" - parent for all main files -#define PRIV_DIR_INO_NUM 3 // "private-dir" -/* -#define SNAP_DIR_INO_NUM 6 // the directory where snapshot metadata is stored. Snapshot inodes are stored in the snapshot metedata tree. -#define PURGEABLE_DIR_INO_NUM 7 -#define MIN_USER_INO_NUM 16 - -#define UNIFIED_ID_SPACE_MARK 0x0800000000000000 -*/ - -//typedef enum -// { -/* -INODE_IS_APFS_PRIVATE = 0x00000001, -INODE_MAINTAIN_DIR_STATS = 0x00000002, -INODE_DIR_STATS_ORIGIN = 0x00000004, -INODE_PROT_CLASS_EXPLICIT = 0x00000008, -INODE_WAS_CLONED = 0x00000010, -INODE_FLAG_UNUSED = 0x00000020, -INODE_HAS_SECURITY_EA = 0x00000040, -INODE_BEING_TRUNCATED = 0x00000080, -INODE_HAS_FINDER_INFO = 0x00000100, -INODE_IS_SPARSE = 0x00000200, -INODE_WAS_EVER_CLONED = 0x00000400, -INODE_ACTIVE_FILE_TRIMMED = 0x00000800, -INODE_PINNED_TO_MAIN = 0x00001000, -INODE_PINNED_TO_TIER2 = 0x00002000, -*/ -// INODE_HAS_RSRC_FORK = 0x00004000, -/* -INODE_NO_RSRC_FORK = 0x00008000, -INODE_ALLOCATION_SPILLEDOVER = 0x00010000, -INODE_FAST_PROMOTE = 0x00020000, -*/ -#define INODE_HAS_UNCOMPRESSED_SIZE 0x00040000 -/* -INODE_IS_PURGEABLE = 0x00080000, -INODE_WANTS_TO_BE_PURGEABLE = 0x00100000, -INODE_IS_SYNC_ROOT = 0x00200000, -INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000, - - -INODE_INHERITED_INTERNAL_FLAGS = \ - ( INODE_MAINTAIN_DIR_STATS \ - | INODE_SNAPSHOT_COW_EXEMPTION), - -INODE_CLONED_INTERNAL_FLAGS = \ - ( INODE_HAS_RSRC_FORK \ - | INODE_NO_RSRC_FORK \ - | INODE_HAS_FINDER_INFO \ - | INODE_SNAPSHOT_COW_EXEMPTION), -*/ -// } -// j_inode_flags; - - -/* -#define APFS_VALID_INTERNAL_INODE_FLAGS \ -( INODE_IS_APFS_PRIVATE \ -| INODE_MAINTAIN_DIR_STATS \ -| INODE_DIR_STATS_ORIGIN \ -| INODE_PROT_CLASS_EXPLICIT \ -| INODE_WAS_CLONED \ -| INODE_HAS_SECURITY_EA \ -| INODE_BEING_TRUNCATED \ -| INODE_HAS_FINDER_INFO \ -| INODE_IS_SPARSE \ -| INODE_WAS_EVER_CLONED \ -| INODE_ACTIVE_FILE_TRIMMED \ -| INODE_PINNED_TO_MAIN \ -| INODE_PINNED_TO_TIER2 \ -| INODE_HAS_RSRC_FORK \ -| INODE_NO_RSRC_FORK \ -| INODE_ALLOCATION_SPILLEDOVER \ -| INODE_FAST_PROMOTE \ -| INODE_HAS_UNCOMPRESSED_SIZE \ -| INODE_IS_PURGEABLE \ -| INODE_WANTS_TO_BE_PURGEABLE \ -| INODE_IS_SYNC_ROOT \ -| INODE_SNAPSHOT_COW_EXEMPTION) - -#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2) -*/ - -static const char * const g_INODE_Flags[] = -{ - "IS_APFS_PRIVATE" - , "MAINTAIN_DIR_STATS" - , "DIR_STATS_ORIGIN" - , "PROT_CLASS_EXPLICIT" - , "WAS_CLONED" - , "FLAG_UNUSED" - , "HAS_SECURITY_EA" - , "BEING_TRUNCATED" - , "HAS_FINDER_INFO" - , "IS_SPARSE" - , "WAS_EVER_CLONED" - , "ACTIVE_FILE_TRIMMED" - , "PINNED_TO_MAIN" - , "PINNED_TO_TIER2" - , "HAS_RSRC_FORK" - , "NO_RSRC_FORK" - , "ALLOCATION_SPILLEDOVER" - , "FAST_PROMOTE" - , "HAS_UNCOMPRESSED_SIZE" - , "IS_PURGEABLE" - , "WANTS_TO_BE_PURGEABLE" - , "IS_SYNC_ROOT" - , "SNAPSHOT_COW_EXEMPTION" -}; - - -// bsd stat.h -/* -#define MY_UF_SETTABLE 0x0000ffff // mask of owner changeable flags -#define MY_UF_NODUMP 0x00000001 // do not dump file -#define MY_UF_IMMUTABLE 0x00000002 // file may not be changed -#define MY_UF_APPEND 0x00000004 // writes to file may only append -#define MY_UF_OPAQUE 0x00000008 // directory is opaque wrt. union -#define MY_UF_NOUNLINK 0x00000010 // file entry may not be removed or renamed Not implement in MacOS -#define MY_UF_COMPRESSED 0x00000020 // file entry is compressed -#define MY_UF_TRACKED 0x00000040 // notify about file entry changes -#define MY_UF_DATAVAULT 0x00000080 // entitlement required for reading and writing -#define MY_UF_HIDDEN 0x00008000 // file entry is hidden - -#define MY_SF_SETTABLE 0xffff0000 // mask of superuser changeable flags -#define MY_SF_ARCHIVED 0x00010000 // file is archived -#define MY_SF_IMMUTABLE 0x00020000 // file may not be changed -#define MY_SF_APPEND 0x00040000 // writes to file may only append -#define MY_SF_RESTRICTED 0x00080000 // entitlement required for writing -#define MY_SF_NOUNLINK 0x00100000 // file entry may not be removed, renamed or used as mount point -#define MY_SF_SNAPSHOT 0x00200000 // snapshot inode -Not implement in MacOS -*/ - -static const char * const g_INODE_BSD_Flags[] = -{ - "UF_NODUMP" - , "UF_IMMUTABLE" - , "UF_APPEND" - , "UF_OPAQUE" - , "UF_NOUNLINK" - , "UF_COMPRESSED" - , "UF_TRACKED" - , "UF_DATAVAULT" - , NULL, NULL, NULL, NULL - , NULL, NULL, NULL - , "UF_HIDDEN" - - , "SF_ARCHIVE" - , "SF_IMMUTABLE" - , "SF_APPEND" - , "SF_RESTRICTED" - , "SF_NOUNLINK" - , "SF_SNAPSHOT" -}; - -/* -#define INO_EXT_TYPE_SNAP_XID 1 -#define INO_EXT_TYPE_DELTA_TREE_OID 2 -#define INO_EXT_TYPE_DOCUMENT_ID 3 -*/ -#define INO_EXT_TYPE_NAME 4 -/* -#define INO_EXT_TYPE_PREV_FSIZE 5 -#define INO_EXT_TYPE_RESERVED_6 6 -#define INO_EXT_TYPE_FINDER_INFO 7 -*/ -#define INO_EXT_TYPE_DSTREAM 8 -/* -#define INO_EXT_TYPE_RESERVED_9 9 -#define INO_EXT_TYPE_DIR_STATS_KEY 10 -#define INO_EXT_TYPE_FS_UUID 11 -#define INO_EXT_TYPE_RESERVED_12 12 -#define INO_EXT_TYPE_SPARSE_BYTES 13 -#define INO_EXT_TYPE_RDEV 14 -#define INO_EXT_TYPE_PURGEABLE_FLAGS 15 -#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16 -*/ - - -static const unsigned k_SizeOf_j_dstream = 8 * 5; - -struct j_dstream -{ - UInt64 size; - UInt64 alloced_size; - UInt64 default_crypto_id; - UInt64 total_bytes_written; - UInt64 total_bytes_read; - - void Parse(const Byte *p) - { - G64 (0, size) - G64 (0x8, alloced_size) - G64 (0x10, default_crypto_id) - G64 (0x18, total_bytes_written) - G64 (0x20, total_bytes_read) - } -}; - -static const unsigned k_SizeOf_j_file_extent_val = 8 * 3; - -#define J_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffU -// #define J_FILE_EXTENT_FLAG_MASK 0xff00000000000000U -// #define J_FILE_EXTENT_FLAG_SHIFT 56 - -#define EXTENT_GET_LEN(x) ((x) & J_FILE_EXTENT_LEN_MASK) - -struct j_file_extent_val -{ - UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t. - // There are currently no flags defined - UInt64 phys_block_num; // The physical block address that the extent starts at - // UInt64 crypto_id; // The encryption key or the encryption tweak used in this extent. - - void Parse(const Byte *p) - { - G64 (0, len_and_flags) - G64 (0x8, phys_block_num) - // G64 (0x10, crypto_id); - } -}; - - -struct CExtent -{ - UInt64 logical_offset; - UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t. - // There are currently no flags defined - UInt64 phys_block_num; // The physical block address that the extent starts at - - UInt64 GetEndOffset() const { return logical_offset + EXTENT_GET_LEN(len_and_flags); } -}; - - -typedef UInt32 MY_uid_t; -typedef UInt32 MY_gid_t; -typedef UInt16 MY_mode_t; - - -typedef enum -{ - XATTR_DATA_STREAM = 1 << 0, - XATTR_DATA_EMBEDDED = 1 << 1, - XATTR_FILE_SYSTEM_OWNED = 1 << 2, - XATTR_RESERVED_8 = 1 << 3 -} j_xattr_flags; - - -struct CAttr -{ - AString Name; - UInt32 flags; - bool dstream_defined; - bool NeedShow; - CByteBuffer Data; - - j_dstream dstream; - UInt64 Id; - - bool Is_dstream_OK_for_SymLink() const - { - return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0; - } - - UInt64 GetSize() const - { - if (dstream_defined) // dstream has more priority - return dstream.size; - return Data.Size(); - } - - void Clear() - { - dstream_defined = false; - NeedShow = true; - Data.Free(); - Name.Empty(); - } - - bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; } - bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; } -}; - - -// j_inode_val_t -struct CNode -{ - unsigned ItemIndex; // index to CItem. We set it only if Node is directory. - unsigned NumCalcedLinks; // Num links to that node - // unsigned NumItems; // Num Items in that node - - UInt64 parent_id; // The identifier of the file system record for the parent directory. - UInt64 private_id; - UInt64 create_time; - UInt64 mod_time; - UInt64 change_time; - UInt64 access_time; - UInt64 internal_flags; - union - { - UInt32 nchildren; /* The number of directory entries. - is valid only if the inode is a directory */ - UInt32 nlink; /* The number of hard links whose target is this inode. - is valid only if the inode isn't a directory. - Inodes with multiple hard links (nlink > 1) - - The parent_id field refers to the parent directory of the primary link. - - The name field contains the name of the primary link. - - The INO_EXT_TYPE_NAME extended field contains the name of this link. - */ - }; - // cp_key_class_t default_protection_class; - UInt32 write_generation_counter; - UInt32 bsd_flags; - MY_uid_t owner; - MY_gid_t group; - MY_mode_t mode; - UInt16 pad1; - UInt64 uncompressed_size; - - j_dstream dstream; - AString PrimaryName; - - bool dstream_defined; - bool refcnt_defined; - - UInt32 refcnt; // j_dstream_id_val_t - CRecordVector Extents; - CObjectVector Attrs; - unsigned SymLinkIndex; // index in Attrs - unsigned DecmpfsIndex; // index in Attrs - unsigned ResourceIndex; // index in Attrs - - NHfs::CCompressHeader CompressHeader; - - CNode(): - ItemIndex(VI_MINUS1), - NumCalcedLinks(0), - // NumItems(0), - dstream_defined(false), - refcnt_defined(false), - SymLinkIndex(VI_MINUS1), - DecmpfsIndex(VI_MINUS1), - ResourceIndex(VI_MINUS1) - {} - - bool IsDir() const { return MY_LIN_S_ISDIR(mode); } - bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); } - - bool Has_UNCOMPRESSED_SIZE() const { return (internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) != 0; } - - unsigned Get_Type_From_mode() const { return mode >> 12; } - - bool GetSize(unsigned attrIndex, UInt64 &size) const - { - if (IsViNotDef(attrIndex)) - { - if (dstream_defined) - { - size = dstream.size; - return true; - } - size = 0; - if (Has_UNCOMPRESSED_SIZE()) - { - size = uncompressed_size; - return true; - } - if (!IsSymLink()) - return false; - attrIndex = SymLinkIndex; - if (IsViNotDef(attrIndex)) - return false; - } - const CAttr &attr = Attrs[(unsigned)attrIndex]; - if (attr.dstream_defined) - size = attr.dstream.size; - else - size = attr.Data.Size(); - return true; - } - - bool GetPackSize(unsigned attrIndex, UInt64 &size) const - { - if (IsViNotDef(attrIndex)) - { - if (dstream_defined) - { - size = dstream.alloced_size; - return true; - } - size = 0; - - if (IsSymLink()) - attrIndex = SymLinkIndex; - else - { - if (!CompressHeader.IsCorrect || - !CompressHeader.IsSupported) - return false; - const CAttr &attr = Attrs[DecmpfsIndex]; - if (!CompressHeader.IsMethod_Resource()) - { - size = attr.Data.Size() - CompressHeader.DataPos; - return true; - } - attrIndex = ResourceIndex; - } - if (IsViNotDef(attrIndex)) - return false; - } - const CAttr &attr = Attrs[(unsigned)attrIndex]; - if (attr.dstream_defined) - size = attr.dstream.alloced_size; - else - size = attr.Data.Size(); - return true; - } - - void Parse(const Byte *p); -}; - - -// it's used for Attr streams -struct CSmallNode -{ - CRecordVector Extents; - // UInt32 NumLinks; - // CSmallNode(): NumLinks(0) {} -}; - -static const unsigned k_SizeOf_j_inode_val = 0x5c; - -void CNode::Parse(const Byte *p) -{ - G64 (0, parent_id) - G64 (0x8, private_id) - G64 (0x10, create_time) - G64 (0x18, mod_time) - G64 (0x20, change_time) - G64 (0x28, access_time) - G64 (0x30, internal_flags) - { - G32 (0x38, nchildren) - // G32 (0x38, nlink); - } - // G32 (0x3c, default_protection_class); - G32 (0x40, write_generation_counter) - G32 (0x44, bsd_flags) - G32 (0x48, owner) - G32 (0x4c, group) - G16 (0x50, mode) - // G16 (0x52, pad1); - G64 (0x54, uncompressed_size) -} - - -struct CRef -{ - unsigned ItemIndex; - unsigned NodeIndex; - unsigned ParentRefIndex; - - #ifdef APFS_SHOW_ALT_STREAMS - unsigned AttrIndex; - bool IsAltStream() const { return IsViDef(AttrIndex); } - unsigned GetAttrIndex() const { return AttrIndex; } - #else - // bool IsAltStream() const { return false; } - unsigned GetAttrIndex() const { return VI_MINUS1; } - #endif -}; - - -struct CRef2 -{ - unsigned VolIndex; - unsigned RefIndex; -}; - - -struct CHashChunk -{ - UInt64 lba; - UInt32 hashed_len; // the value is UInt16 - Byte hash[APFS_HASH_MAX_SIZE]; -}; - -typedef CRecordVector CStreamHashes; - - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithHash - , ISequentialOutStream -) - bool _hashError; - CAlignedBuffer1 _sha; - CMyComPtr _stream; - const CStreamHashes *_hashes; - unsigned _blockSizeLog; - unsigned _chunkIndex; - UInt32 _offsetInChunk; - // UInt64 _size; - - CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; } -public: - COutStreamWithHash(): _sha(sizeof(CSha256)) {} - - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - // void ReleaseStream() { _stream.Release(); } - void Init(const CStreamHashes *hashes, unsigned blockSizeLog) - { - _hashes = hashes; - _blockSizeLog = blockSizeLog; - _chunkIndex = 0; - _offsetInChunk = 0; - _hashError = false; - // _size = 0; - } - // UInt64 GetSize() const { return _size; } - bool FinalCheck(); -}; - - -static bool Sha256_Final_and_CheckDigest(CSha256 *sha256, const Byte *digest) -{ - MY_ALIGN (16) - UInt32 temp[SHA256_NUM_DIGEST_WORDS]; - Sha256_Final(sha256, (Byte *)temp); - return memcmp(temp, digest, SHA256_DIGEST_SIZE) == 0; -} - - -Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - if (processedSize) - *processedSize = size; - while (size != 0) - { - if (_hashError) - break; - if (_chunkIndex >= _hashes->Size()) - { - _hashError = true; - break; - } - if (_offsetInChunk == 0) - Sha256_Init(Sha()); - const CHashChunk &chunk = (*_hashes)[_chunkIndex]; - /* (_blockSizeLog <= 16) && chunk.hashed_len is 16-bit. - so we can use 32-bit chunkSize here */ - const UInt32 chunkSize = ((UInt32)chunk.hashed_len << _blockSizeLog); - const UInt32 rem = chunkSize - _offsetInChunk; - UInt32 cur = size; - if (cur > rem) - cur = (UInt32)rem; - Sha256_Update(Sha(), (const Byte *)data, cur); - data = (const void *)((const Byte *)data + cur); - size -= cur; - // _size += cur; - _offsetInChunk += cur; - if (chunkSize == _offsetInChunk) - { - if (!Sha256_Final_and_CheckDigest(Sha(), chunk.hash)) - _hashError = true; - _offsetInChunk = 0; - _chunkIndex++; - } - } - return result; -} - - -bool COutStreamWithHash::FinalCheck() -{ - if (_hashError) - return false; - - if (_offsetInChunk != 0) - { - const CHashChunk &chunk = (*_hashes)[_chunkIndex]; - { - const UInt32 chunkSize = ((UInt32)chunk.hashed_len << _blockSizeLog); - const UInt32 rem = chunkSize - _offsetInChunk; - Byte b = 0; - for (UInt32 i = 0; i < rem; i++) - Sha256_Update(Sha(), &b, 1); - } - if (!Sha256_Final_and_CheckDigest(Sha(), chunk.hash)) - _hashError = true; - _offsetInChunk = 0; - _chunkIndex++; - } - if (_chunkIndex != _hashes->Size()) - _hashError = true; - return !_hashError; -} - - - -struct CVol -{ - CObjectVector Nodes; - CRecordVector NodeIDs; - CObjectVector Items; - CRecordVector Refs; - - CObjectVector SmallNodes; - CRecordVector SmallNodeIDs; - - CObjectVector FEXT_Nodes; - CRecordVector FEXT_NodeIDs; - - CObjectVector Hash_Vectors; - CRecordVector Hash_IDs; - - unsigned StartRef2Index; // ref2_Index for Refs[0] item - unsigned RootRef2Index; // ref2_Index of virtual root folder (Volume1) - CApfs apfs; - C_integrity_meta_phys integrity; - - bool NodeNotFound; - bool ThereAreUnlinkedNodes; - bool WrongInodeLink; - bool UnsupportedFeature; - bool UnsupportedMethod; - - unsigned NumItems_In_PrivateDir; - unsigned NumAltStreams; - - UString RootName; - - bool ThereAreErrors() const - { - return NodeNotFound || ThereAreUnlinkedNodes || WrongInodeLink; - } - - void AddComment(UString &s) const; - - HRESULT FillRefs(); - - CVol(): - StartRef2Index(0), - RootRef2Index(VI_MINUS1), - NodeNotFound(false), - ThereAreUnlinkedNodes(false), - WrongInodeLink(false), - UnsupportedFeature(false), - UnsupportedMethod(false), - NumItems_In_PrivateDir(0), - NumAltStreams(0) - {} -}; - - -static void ApfsTimeToFileTime(UInt64 apfsTime, FILETIME &ft, UInt32 &ns100) -{ - const UInt64 s = apfsTime / 1000000000; - const UInt32 ns = (UInt32)(apfsTime % 1000000000); - ns100 = (ns % 100); - const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64((Int64)s) + ns / 100; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - -static void AddComment_Name(UString &s, const char *name) -{ - s += name; - s += ": "; -} - -/* -static void AddComment_Bool(UString &s, const char *name, bool val) -{ - AddComment_Name(s, name); - s += val ? "+" : "-"; - s.Add_LF(); -} -*/ - -static void AddComment_UInt64(UString &s, const char *name, UInt64 v) -{ - AddComment_Name(s, name); - s.Add_UInt64(v); - s.Add_LF(); -} - - -static void AddComment_Time(UString &s, const char *name, UInt64 v) -{ - AddComment_Name(s, name); - - FILETIME ft; - UInt32 ns100; - ApfsTimeToFileTime(v, ft, ns100); - char temp[64]; - ConvertUtcFileTimeToString2(ft, ns100, temp - // , kTimestampPrintLevel_SEC); - , kTimestampPrintLevel_NS); - s += temp; - s.Add_LF(); -} - - -static void AddComment_modified_by_t(UString &s, const char *name, const apfs_modified_by_t &v) -{ - AddComment_Name(s, name); - AString s2; - s2.SetFrom_CalcLen((const char *)v.id, sizeof(v.id)); - s += s2; - s.Add_LF(); - s += " "; - AddComment_Time(s, "timestamp", v.timestamp); - s += " "; - AddComment_UInt64(s, "last_xid", v.last_xid); -} - - -static void AddVolInternalName_toString(UString &s, const CApfs &apfs) -{ - AString temp; - temp.SetFrom_CalcLen((const char *)apfs.volname, sizeof(apfs.volname)); - UString unicode; - ConvertUTF8ToUnicode(temp, unicode); - s += unicode; -} - - -void CVol::AddComment(UString &s) const -{ - AddComment_UInt64(s, "fs_index", apfs.fs_index); - { - AddComment_Name(s, "volume_name"); - AddVolInternalName_toString(s, apfs); - s.Add_LF(); - } - AddComment_Name(s, "vol_uuid"); - apfs.vol_uuid.AddHexToString(s); - s.Add_LF(); - - AddComment_Name(s, "incompatible_features"); - s += FlagsToString(g_APFS_INCOMPAT_Flags, - Z7_ARRAY_SIZE(g_APFS_INCOMPAT_Flags), - (UInt32)apfs.incompatible_features); - s.Add_LF(); - - - if (apfs.integrity_meta_oid != 0) - { - /* - AddComment_Name(s, "im_version"); - s.Add_UInt32(integrity.im_version); - s.Add_LF(); - */ - AddComment_Name(s, "im_flags"); - s.Add_UInt32(integrity.im_flags); - s.Add_LF(); - AddComment_Name(s, "im_hash_type"); - const char *p = NULL; - if (integrity.im_hash_type < Z7_ARRAY_SIZE(g_hash_types)) - p = g_hash_types[integrity.im_hash_type]; - if (p) - s += p; - else - s.Add_UInt32(integrity.im_hash_type); - s.Add_LF(); - } - - - // AddComment_UInt64(s, "reserve_block_count", apfs.fs_reserve_block_count, false); - // AddComment_UInt64(s, "quota_block_count", apfs.fs_quota_block_count); - AddComment_UInt64(s, "fs_alloc_count", apfs.fs_alloc_count); - - AddComment_UInt64(s, "num_files", apfs.num_files); - AddComment_UInt64(s, "num_directories", apfs.num_directories); - AddComment_UInt64(s, "num_symlinks", apfs.num_symlinks); - AddComment_UInt64(s, "num_other_fsobjects", apfs.num_other_fsobjects); - - AddComment_UInt64(s, "Num_Attr_Streams", NumAltStreams); - - AddComment_UInt64(s, "num_snapshots", apfs.num_snapshots); - AddComment_UInt64(s, "total_blocks_alloced", apfs.total_blocks_alloced); - AddComment_UInt64(s, "total_blocks_freed", apfs.total_blocks_freed); - - AddComment_Time(s, "unmounted", apfs.unmount_time); - AddComment_Time(s, "last_modified", apfs.last_mod_time); - AddComment_modified_by_t(s, "formatted_by", apfs.formatted_by); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(apfs.modified_by); i++) - { - const apfs_modified_by_t &v = apfs.modified_by[i]; - if (v.last_xid == 0 && v.timestamp == 0 && v.id[0] == 0) - continue; - AString name ("modified_by["); - name.Add_UInt32(i); - name += ']'; - AddComment_modified_by_t(s, name.Ptr(), v); - } -} - - - -struct CKeyValPair -{ - CByteBuffer Key; - CByteBuffer Val; - // unsigned ValPos; // for alognment -}; - - -struct omap_key -{ - oid_t oid; // The object identifier - xid_t xid; // The transaction identifier - void Parse(const Byte *p) - { - G64o (0, oid) - G64x (8, xid) - } -}; - -/* -#define OMAP_VAL_DELETED (1 << 0) -#define OMAP_VAL_SAVED (1 << 1) -#define OMAP_VAL_ENCRYPTED (1 << 2) -*/ -#define OMAP_VAL_NOHEADER (1 << 3) -/* -#define OMAP_VAL_CRYPTO_GENERATION (1 << 4) -*/ - -struct omap_val -{ - UInt32 flags; - UInt32 size; - // paddr_t paddr; - paddr_t_unsigned paddr; - - bool IsFlag_NoHeader() const { return (flags & OMAP_VAL_NOHEADER) != 0; } - - void Parse(const Byte *p) - { - G32 (0, flags) - G32 (4, size) - G64 (8, paddr) - } -}; - - -struct CObjectMap -{ - CRecordVector Keys; - CRecordVector Vals; - - bool Parse(const CObjectVector &pairs); - int FindKey(UInt64 id) const { return Keys.FindInSorted(id); } -}; - -bool CObjectMap::Parse(const CObjectVector &pairs) -{ - omap_key prev; - prev.oid = 0; - prev.xid = 0; - FOR_VECTOR (i, pairs) - { - const CKeyValPair &pair = pairs[i]; - if (pair.Key.Size() != 16 || pair.Val.Size() != 16) - return false; - omap_key key; - key.Parse(pair.Key); - omap_val val; - val.Parse(pair.Val); - /* Object map B-trees are sorted by object identifier and then by transaction identifier - but it's possible to have identical Ids in map ? - do we need to look transaction id ? - and search key with largest transaction id? */ - if (key.oid <= prev.oid) - return false; - prev = key; - Keys.Add(key.oid); - Vals.Add(val); - } - return true; -} - - -struct CMap -{ - CObjectVector Pairs; - - CObjectMap Omap; - btree_info bti; - UInt64 NumNodes; - - // we use thnese options to check: - UInt32 Subtype; - bool IsPhysical; - - bool CheckAtFinish() const - { - return NumNodes == bti.node_count && Pairs.Size() == bti.key_count; - } - - CMap(): - NumNodes(0), - Subtype(0), - IsPhysical(true) - {} -}; - - - -struct CDatabase -{ - CRecordVector Refs2; - CObjectVector Vols; - - bool HeadersError; - bool ThereAreAltStreams; - bool UnsupportedFeature; - bool UnsupportedMethod; - - CSuperBlock sb; - - IInStream *OpenInStream; - IArchiveOpenCallback *OpenCallback; - UInt64 ProgressVal_Cur; - UInt64 ProgressVal_Prev; - UInt64 ProgressVal_NumFilesTotal; - CObjectVector Buffers; - - UInt32 MethodsMask; - UInt64 GetSize(const UInt32 index) const; - - void Clear() - { - HeadersError = false; - ThereAreAltStreams = false; - UnsupportedFeature = false; - UnsupportedMethod = false; - - ProgressVal_Cur = 0; - ProgressVal_Prev = 0; - ProgressVal_NumFilesTotal = 0; - - MethodsMask = 0; - - Vols.Clear(); - Refs2.Clear(); - Buffers.Clear(); - } - - HRESULT SeekReadBlock_FALSE(UInt64 oid, void *data); - void GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const; - HRESULT ReadMap(UInt64 oid, bool noHeader, CVol *vol, const Byte *hash, - CMap &map, unsigned recurseLevel); - HRESULT ReadObjectMap(UInt64 oid, CVol *vol, CObjectMap &map); - HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid); - HRESULT Open2(); - - HRESULT GetAttrStream(IInStream *apfsInStream, const CVol &vol, - const CAttr &attr, ISequentialInStream **stream); - - HRESULT GetAttrStream_dstream(IInStream *apfsInStream, const CVol &vol, - const CAttr &attr, ISequentialInStream **stream); - - HRESULT GetStream2( - IInStream *apfsInStream, - const CRecordVector *extents, UInt64 rem, - ISequentialInStream **stream); -}; - - -HRESULT CDatabase::SeekReadBlock_FALSE(UInt64 oid, void *data) -{ - if (OpenCallback) - { - if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) - { - RINOK(OpenCallback->SetCompleted(NULL, &ProgressVal_Cur)) - ProgressVal_Prev = ProgressVal_Cur; - } - ProgressVal_Cur += sb.block_size; - } - if (oid == 0 || oid >= sb.block_count) - return S_FALSE; - RINOK(InStream_SeekSet(OpenInStream, oid << sb.block_size_Log)) - return ReadStream_FALSE(OpenInStream, data, sb.block_size); -} - - - -API_FUNC_static_IsArc IsArc_APFS(const Byte *p, size_t size) -{ - if (size < kApfsHeaderSize) - return k_IsArc_Res_NEED_MORE; - CSuperBlock sb; - if (!sb.Parse(p)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - - -static bool CheckHash(unsigned hashAlgo, const Byte *data, size_t size, const Byte *digest) -{ - if (hashAlgo == APFS_HASH_SHA256) - { - MY_ALIGN (16) - CSha256 sha; - Sha256_Init(&sha); - Sha256_Update(&sha, data, size); - return Sha256_Final_and_CheckDigest(&sha, digest); - } - return true; -} - - -HRESULT CDatabase::ReadMap(UInt64 oid, bool noHeader, - CVol *vol, const Byte *hash, - CMap &map, unsigned recurseLevel) -{ - // is it allowed to use big number of levels ? - if (recurseLevel > (1 << 10)) - return S_FALSE; - - const UInt32 blockSize = sb.block_size; - if (Buffers.Size() <= recurseLevel) - { - Buffers.AddNew(); - if (Buffers.Size() <= recurseLevel) - throw 123; - Buffers.Back().Alloc(blockSize); - } - const Byte *buf; - { - CByteBuffer &buf2 = Buffers[recurseLevel]; - RINOK(SeekReadBlock_FALSE(oid, buf2)) - buf = buf2; - } - - if (hash && vol) - if (!CheckHash(vol->integrity.im_hash_type, buf, blockSize, hash)) - return S_FALSE; - - CBTreeNodePhys bt; - if (!bt.Parse(buf, blockSize, noHeader)) - return S_FALSE; - - map.NumNodes++; - - /* Specification: All values are stored in leaf nodes, which - makes these B+ trees, and the values in nonleaf nodes are object - identifiers of child nodes. - - The entries in the table of contents are sorted by key. The comparison function used for sorting depends on the keys type - - Object map B-trees are sorted by object identifier and then by transaction identifier. - - Free queue B-trees are sorted by transaction identifier and then by physical address. - - File-system records are sorted according to the rules listed in File-System Objects. - */ - - if (!noHeader) - if (bt.ophys.subtype != map.Subtype) - return S_FALSE; - - unsigned endLimit = blockSize; - - if (recurseLevel == 0) - { - if (!noHeader) - if (bt.ophys.GetType() != OBJECT_TYPE_BTREE) - return S_FALSE; - if ((bt.flags & BTNODE_ROOT) == 0) - return S_FALSE; - endLimit -= k_btree_info_Size; - map.bti.Parse(buf + endLimit); - btree_info &bti = map.bti; - if (bti.fixed.key_size >= blockSize) - return S_FALSE; - if (bti.Is_EPHEMERAL() && - bti.Is_PHYSICAL()) - return S_FALSE; - if (bti.Is_PHYSICAL() != map.IsPhysical) - return S_FALSE; - if (bti.Is_NOHEADER() != noHeader) - return S_FALSE; - // we don't allow volumes with big number of Keys - const unsigned kNumItemsMax = k_VectorSizeMax; - if (map.bti.node_count > kNumItemsMax) - return S_FALSE; - if (map.bti.key_count > kNumItemsMax) - return S_FALSE; - } - else - { - if (!noHeader) - if (bt.ophys.GetType() != OBJECT_TYPE_BTREE_NODE) - return S_FALSE; - if ((bt.flags & BTNODE_ROOT) != 0) - return S_FALSE; - if (map.NumNodes > map.bti.node_count - || map.Pairs.Size() > map.bti.key_count) - return S_FALSE; - } - - const bool isLeaf = (bt.flags & BTNODE_LEAF) != 0; - - if (isLeaf) - { - if (bt.level != 0) - return S_FALSE; - } - else - { - if (bt.level == 0) - return S_FALSE; - } - - if (!bt.table_space.CheckOverLimit(endLimit - k_Toc_offset)) - return S_FALSE; - - const unsigned tableEnd = k_Toc_offset + bt.table_space.GetEnd(); - const unsigned keyValRange = endLimit - tableEnd; - const unsigned tocEntrySize = bt.Is_FIXED_KV_SIZE() ? 4 : 8; - if (bt.table_space.len / tocEntrySize < bt.nkeys) - return S_FALSE; - - for (unsigned i = 0; i < bt.nkeys; i++) - { - const Byte *p = buf + k_Toc_offset + bt.table_space.off + i * tocEntrySize; - if (bt.Is_FIXED_KV_SIZE()) - { - kvoff a; - a.Parse(p); - if (a.k + map.bti.fixed.key_size > keyValRange - || a.v > keyValRange) - return S_FALSE; - { - CKeyValPair pair; - - const Byte *p2 = buf + k_Toc_offset + bt.table_space.len; - p2 += a.k; - pair.Key.CopyFrom(p2, map.bti.fixed.key_size); - - p2 = buf + endLimit; - p2 -= a.v; - if (isLeaf) - { - if (a.v < map.bti.fixed.val_size) - return S_FALSE; - pair.Val.CopyFrom(p2, map.bti.fixed.val_size); - // pair.ValPos = endLimit - a.v; - map.Pairs.Add(pair); - continue; - } - { - if (a.v < 8) - return S_FALSE; - // value is only 64-bit for non leaf. - const oid_t oidNext = Get64(p2); - if (map.bti.Is_PHYSICAL()) - { - RINOK(ReadMap(oidNext, noHeader, vol, - NULL, /* hash */ - map, recurseLevel + 1)) - continue; - } - else - { - // fixme - return S_FALSE; - } - } - } - } - else - { - kvloc a; - a.Parse(p); - if (!a.k.CheckOverLimit(keyValRange) - || a.v.off > keyValRange - || a.v.len > a.v.off) - return S_FALSE; - { - CKeyValPair pair; - const Byte *p2 = buf + k_Toc_offset + bt.table_space.len; - p2 += a.k.off; - pair.Key.CopyFrom(p2, a.k.len); - - p2 = buf + endLimit; - p2 -= a.v.off; - if (isLeaf) - { - pair.Val.CopyFrom(p2, a.v.len); - // pair.ValPos = endLimit - a.v.off; - map.Pairs.Add(pair); - continue; - } - { - if (a.v.len < 8) - return S_FALSE; - - const Byte *hashNew = NULL; - oid_t oidNext = Get64(p2); - - if (bt.Is_HASHED()) - { - if (!vol) - return S_FALSE; - /* - struct btn_index_node_val { - oid_t binv_child_oid; - uint8_t binv_child_hash[BTREE_NODE_HASH_SIZE_MAX]; - }; - */ - /* (a.v.len == 40) is possible if Is_HASHED() - so there is hash (for example, 256-bit) after 64-bit id) */ - if (a.v.len != 8 + vol->integrity.HashSize) - return S_FALSE; - hashNew = p2 + 8; - /* we need to add root_tree_oid here, - but where it's defined in apfs specification ? */ - oidNext += vol->apfs.root_tree_oid; - } - else - { - if (a.v.len != 8) - return S_FALSE; - } - - // value is only 64-bit for non leaf. - - if (map.bti.Is_PHYSICAL()) - { - return S_FALSE; - // the code was not tested: - // RINOK(ReadMap(oidNext, map, recurseLevel + 1)); - // continue; - } - /* - else if (map.bti.Is_EPHEMERAL()) - { - // Ephemeral objects are stored in memory while the container is mounted and in a checkpoint when the container isn't mounted - // the code was not tested: - return S_FALSE; - } - */ - else - { - /* nodes in the B-tree use virtual object identifiers to link to their child nodes. */ - const int index = map.Omap.FindKey(oidNext); - if (index == -1) - return S_FALSE; - const omap_val &ov = map.Omap.Vals[(unsigned)index]; - if (ov.size != blockSize) // change it : it must be multiple of - return S_FALSE; - RINOK(ReadMap(ov.paddr, ov.IsFlag_NoHeader(), vol, hashNew, - map, recurseLevel + 1)) - continue; - } - } - } - } - } - - if (recurseLevel == 0) - if (!map.CheckAtFinish()) - return S_FALSE; - return S_OK; -} - - - -HRESULT CDatabase::ReadObjectMap(UInt64 oid, CVol *vol, CObjectMap &omap) -{ - CByteBuffer buf; - const size_t blockSize = sb.block_size; - buf.Alloc(blockSize); - RINOK(SeekReadBlock_FALSE(oid, buf)) - C_omap_phys op; - if (!op.Parse(buf, blockSize, oid)) - return S_FALSE; - CMap map; - map.Subtype = OBJECT_TYPE_OMAP; - map.IsPhysical = true; - RINOK(ReadMap(op.tree_oid, - false /* noHeader */, - vol, - NULL, /* hash */ - map, 0)) - if (!omap.Parse(map.Pairs)) - return S_FALSE; - return S_OK; -} - - - -HRESULT CDatabase::Open2() -{ - Clear(); - CSuperBlock2 sb2; - { - Byte buf[kApfsHeaderSize]; - RINOK(ReadStream_FALSE(OpenInStream, buf, kApfsHeaderSize)) - if (!sb.Parse(buf)) - return S_FALSE; - sb2.Parse(buf); - } - - { - CObjectMap omap; - RINOK(ReadObjectMap(sb.omap_oid, - NULL, /* CVol */ - omap)) - unsigned numRefs = 0; - for (unsigned i = 0; i < sb.max_file_systems; i++) - { - const oid_t oid = sb2.fs_oid[i]; - if (oid == 0) - continue; - // for (unsigned k = 0; k < 1; k++) // for debug - RINOK(OpenVolume(omap, oid)) - const unsigned a = Vols.Back().Refs.Size(); - numRefs += a; - if (numRefs < a) - return S_FALSE; // overflow - } - } - - const bool needVolumePrefix = (Vols.Size() > 1); - // const bool needVolumePrefix = true; // for debug - { - unsigned numRefs = 0; - FOR_VECTOR (i, Vols) - { - const unsigned a = Vols[i].Refs.Size(); - numRefs += a; - if (numRefs < a) - return S_FALSE; // overflow - } - numRefs += Vols.Size(); - if (numRefs < Vols.Size()) - return S_FALSE; // overflow - Refs2.Reserve(numRefs); - } - { - FOR_VECTOR (i, Vols) - { - CVol &vol = Vols[i]; - - CRef2 ref2; - ref2.VolIndex = i; - - if (needVolumePrefix) - { - vol.RootName = "Volume"; - vol.RootName.Add_UInt32(1 + (UInt32)i); - vol.RootRef2Index = Refs2.Size(); - ref2.RefIndex = VI_MINUS1; - Refs2.Add(ref2); - } - - vol.StartRef2Index = Refs2.Size(); - const unsigned numItems = vol.Refs.Size(); - for (unsigned k = 0; k < numItems; k++) - { - ref2.RefIndex = k; - Refs2.Add(ref2); - } - } - } - return S_OK; -} - - -HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) -{ - const size_t blockSize = sb.block_size; - CByteBuffer buf; - { - const int index = omap.FindKey(fs_oid); - if (index == -1) - return S_FALSE; - const omap_val &ov = omap.Vals[(unsigned)index]; - if (ov.size != blockSize) // change it : it must be multiple of - return S_FALSE; - buf.Alloc(blockSize); - RINOK(SeekReadBlock_FALSE(ov.paddr, buf)) - } - - CVol &vol = Vols.AddNew(); - CApfs &apfs = vol.apfs; - - if (!apfs.Parse(buf, blockSize)) - return S_FALSE; - - if (apfs.fext_tree_oid != 0) - { - if ((apfs.incompatible_features & APFS_INCOMPAT_SEALED_VOLUME) == 0) - return S_FALSE; - if ((apfs.fext_tree_type & OBJ_PHYSICAL) == 0) - return S_FALSE; - if ((apfs.fext_tree_type & OBJECT_TYPE_MASK) != OBJECT_TYPE_BTREE) - return S_FALSE; - - CMap map2; - map2.Subtype = OBJECT_TYPE_FEXT_TREE; - map2.IsPhysical = true; - - RINOK(ReadMap(apfs.fext_tree_oid, - false /* noHeader */, - &vol, - NULL, /* hash */ - map2, 0)) - - UInt64 prevId = 1; - - FOR_VECTOR (i, map2.Pairs) - { - if (OpenCallback && (i & 0xffff) == 1) - { - const UInt64 numFiles = ProgressVal_NumFilesTotal + - (vol.Items.Size() + vol.Nodes.Size()) / 2; - RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur)) - } - // The key half of a record from a file extent tree. - // struct fext_tree_key - const CKeyValPair &pair = map2.Pairs[i]; - if (pair.Key.Size() != 16) - return S_FALSE; - const Byte *p = pair.Key; - const UInt64 id = GetUi64(p); - if (id < prevId) - return S_FALSE; // IDs must be sorted - prevId = id; - - CExtent ext; - ext.logical_offset = GetUi64(p + 8); - { - if (pair.Val.Size() != 16) - return S_FALSE; - const Byte *p2 = pair.Val; - ext.len_and_flags = GetUi64(p2); - ext.phys_block_num = GetUi64(p2 + 8); - } - - PRF(printf("\n%6d: id=%6d logical_addr = %2d len_and_flags=%5x phys_block_num = %5d", - i, (unsigned)id, - (unsigned)ext.logical_offset, - (unsigned)ext.len_and_flags, - (unsigned)ext.phys_block_num)); - - if (vol.FEXT_NodeIDs.IsEmpty() || - vol.FEXT_NodeIDs.Back() != id) - { - vol.FEXT_NodeIDs.Add(id); - vol.FEXT_Nodes.AddNew(); - } - CRecordVector &extents = vol.FEXT_Nodes.Back().Extents; - if (!extents.IsEmpty()) - if (ext.logical_offset != extents.Back().GetEndOffset()) - return S_FALSE; - extents.Add(ext); - continue; - } - - PRF(printf("\n\n")); - } - - /* For each volume, read the root file system tree's virtual object - identifier from the apfs_root_tree_oid field, - and then look it up in the volume object map indicated - by the omap_oid field. */ - - CMap map; - ReadObjectMap(apfs.omap_oid, &vol, map.Omap); - - const Byte *hash_for_root = NULL; - - if (apfs.integrity_meta_oid != 0) - { - if ((apfs.incompatible_features & APFS_INCOMPAT_SEALED_VOLUME) == 0) - return S_FALSE; - const int index = map.Omap.FindKey(apfs.integrity_meta_oid); - if (index == -1) - return S_FALSE; - const omap_val &ov = map.Omap.Vals[(unsigned)index]; - if (ov.size != blockSize) - return S_FALSE; - RINOK(SeekReadBlock_FALSE(ov.paddr, buf)) - if (!vol.integrity.Parse(buf, blockSize, apfs.integrity_meta_oid)) - return S_FALSE; - if (vol.integrity.im_hash_type != 0) - hash_for_root = vol.integrity.Hash; - } - - { - const int index = map.Omap.FindKey(apfs.root_tree_oid); - if (index == -1) - return S_FALSE; - const omap_val &ov = map.Omap.Vals[(unsigned)index]; - if (ov.size != blockSize) // change it : it must be multiple of - return S_FALSE; - map.Subtype = OBJECT_TYPE_FSTREE; - map.IsPhysical = false; - RINOK(ReadMap(ov.paddr, ov.IsFlag_NoHeader(), - &vol, hash_for_root, - map, 0)) - } - - bool needParseAttr = false; - - { - const bool isHashed = apfs.IsHashedName(); - UInt64 prevId = 1; - - { - const UInt64 numApfsItems = vol.apfs.GetTotalItems() - + 2; // we will have 2 additional hidden directories: root and private-dir - const UInt64 numApfsItems_Reserve = numApfsItems - + 16; // we reserve 16 for some possible unexpected items - if (numApfsItems_Reserve < map.Pairs.Size()) - { - vol.Items.ClearAndReserve((unsigned)numApfsItems_Reserve); - vol.Nodes.ClearAndReserve((unsigned)numApfsItems_Reserve); - vol.NodeIDs.ClearAndReserve((unsigned)numApfsItems_Reserve); - } - if (OpenCallback) - { - const UInt64 numFiles = ProgressVal_NumFilesTotal + numApfsItems; - RINOK(OpenCallback->SetTotal(&numFiles, NULL)) - } - } - - CAttr attr; - CItem item; - - FOR_VECTOR (i, map.Pairs) - { - if (OpenCallback && (i & 0xffff) == 1) - { - const UInt64 numFiles = ProgressVal_NumFilesTotal + - (vol.Items.Size() + vol.Nodes.Size()) / 2; - RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur)) - } - - const CKeyValPair &pair = map.Pairs[i]; - j_key_t jkey; - if (pair.Key.Size() < 8) - return S_FALSE; - const Byte *p = pair.Key; - jkey.Parse(p); - const unsigned type = jkey.GetType(); - const UInt64 id = jkey.GetID(); - if (id < prevId) - return S_FALSE; // IDs must be sorted - prevId = id; - - PRF(printf("\n%6d: id=%6d type = %2d ", i, (unsigned)id, type)); - - if (type == APFS_TYPE_INODE) - { - PRF(printf("INODE")); - if (pair.Key.Size() != 8 || - pair.Val.Size() < k_SizeOf_j_inode_val) - return S_FALSE; - - CNode inode; - inode.Parse(pair.Val); - - if (inode.private_id != id) - { - /* private_id : The unique identifier used by this file's data stream. - This identifier appears in the owning_obj_id field of j_phys_ext_val_t - records that describe the extents where the data is stored. - For an inode that doesn't have data, the value of this - field is the file-system object's identifier. - */ - // APFS_TYPE_EXTENT allow to link physical address extents. - // we don't support case (private_id != id) - UnsupportedFeature = true; - // return S_FALSE; - } - const UInt32 extraSize = (UInt32)pair.Val.Size() - k_SizeOf_j_inode_val; - if (extraSize != 0) - { - if (extraSize < 4) - return S_FALSE; - /* - struct xf_blob - { - uint16_t xf_num_exts; - uint16_t xf_used_data; - uint8_t xf_data[]; - }; - */ - const Byte *p2 = pair.Val + k_SizeOf_j_inode_val; - const UInt32 xf_num_exts = Get16(p2); - const UInt32 xf_used_data = Get16(p2 + 2); - UInt32 offset = 4 + (UInt32)xf_num_exts * 4; - if (offset + xf_used_data != extraSize) - return S_FALSE; - - PRF(printf(" parent_id = %d", (unsigned)inode.parent_id)); - - for (unsigned k = 0; k < xf_num_exts; k++) - { - // struct x_field - const Byte *p3 = p2 + 4 + k * 4; - const Byte x_type = p3[0]; - // const Byte x_flags = p3[1]; - const UInt32 x_size = Get16(p3 + 2); - const UInt32 x_size_ceil = (x_size + 7) & ~(UInt32)7; - if (offset + x_size_ceil > extraSize) - return S_FALSE; - const Byte *p4 = p2 + offset; - if (x_type == INO_EXT_TYPE_NAME) - { - if (x_size < 2) - return S_FALSE; - inode.PrimaryName.SetFrom_CalcLen((const char *)p4, x_size); - PRF(printf(" PrimaryName = %s", inode.PrimaryName.Ptr())); - if (inode.PrimaryName.Len() != x_size - 1) - HeadersError = true; - // return S_FALSE; - } - else if (x_type == INO_EXT_TYPE_DSTREAM) - { - if (x_size != k_SizeOf_j_dstream) - return S_FALSE; - if (inode.dstream_defined) - return S_FALSE; - inode.dstream.Parse(p4); - inode.dstream_defined = true; - } - else - { - // UnsupportedFeature = true; - // return S_FALSE; - } - offset += x_size_ceil; - } - if (offset != extraSize) - return S_FALSE; - } - - if (!vol.NodeIDs.IsEmpty()) - if (id <= vol.NodeIDs.Back()) - return S_FALSE; - vol.Nodes.Add(inode); - vol.NodeIDs.Add(id); - continue; - } - - if (type == APFS_TYPE_XATTR) - { - PRF(printf(" XATTR")); - - /* - struct j_xattr_key - { - j_key_t hdr; - uint16_t name_len; - uint8_t name[0]; - } - */ - - UInt32 len; - unsigned nameOffset; - { - nameOffset = 8 + 2; - if (pair.Key.Size() < nameOffset + 1) - return S_FALSE; - len = Get16(p + 8); - } - if (nameOffset + len != pair.Key.Size()) - return S_FALSE; - - attr.Clear(); - attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); - if (attr.Name.Len() != len - 1) - return S_FALSE; - - PRF(printf(" name=%s", attr.Name.Ptr())); - - const unsigned k_SizeOf_j_xattr_val = 4; - if (pair.Val.Size() < k_SizeOf_j_xattr_val) - return S_FALSE; - /* - struct j_xattr_val - { - uint16_t flags; - uint16_t xdata_len; - uint8_t xdata[0]; - } - */ - attr.flags = Get16(pair.Val); - const UInt32 xdata_len = Get16(pair.Val + 2); - - PRF(printf(" flags=%x xdata_len = %d", - (unsigned)attr.flags, - (unsigned)xdata_len)); - - const Byte *p4 = pair.Val + 4; - - if (k_SizeOf_j_xattr_val + xdata_len != pair.Val.Size()) - return S_FALSE; - if (attr.Is_EMBEDDED()) - attr.Data.CopyFrom(p4, xdata_len); - else if (attr.Is_STREAM()) - { - // why (attr.flags == 0x11) here? (0x11 is undocummented flag) - if (k_SizeOf_j_xattr_val + 8 + k_SizeOf_j_dstream != pair.Val.Size()) - return S_FALSE; - attr.Id = Get64(p4); - attr.dstream.Parse(p4 + 8); - attr.dstream_defined = true; - PRF(printf(" streamID=%d streamSize=%d", (unsigned)attr.Id, (unsigned)attr.dstream.size)); - } - else - { - // unknown attribute - // UnsupportedFeature = true; - // return S_FALSE; - } - - if (vol.NodeIDs.IsEmpty() || - vol.NodeIDs.Back() != id) - { - return S_FALSE; - // UnsupportedFeature = true; - // continue; - } - - CNode &inode = vol.Nodes.Back(); - - if (attr.Name.IsEqualTo("com.apple.fs.symlink")) - { - inode.SymLinkIndex = inode.Attrs.Size(); - if (attr.Is_dstream_OK_for_SymLink()) - needParseAttr = true; - } - else if (attr.Name.IsEqualTo("com.apple.decmpfs")) - { - inode.DecmpfsIndex = inode.Attrs.Size(); - // if (attr.dstream_defined) - needParseAttr = true; - } - else if (attr.Name.IsEqualTo("com.apple.ResourceFork")) - { - inode.ResourceIndex = inode.Attrs.Size(); - } - inode.Attrs.Add(attr); - continue; - } - - if (type == APFS_TYPE_DSTREAM_ID) - { - PRF(printf(" DSTREAM_ID")); - if (pair.Key.Size() != 8) - return S_FALSE; - // j_dstream_id_val_t - if (pair.Val.Size() != 4) - return S_FALSE; - const UInt32 refcnt = Get32(pair.Val); - - // The data stream record can be deleted when its reference count reaches zero. - PRF(printf(" refcnt = %d", (unsigned)refcnt)); - - if (vol.NodeIDs.IsEmpty()) - return S_FALSE; - - if (vol.NodeIDs.Back() != id) - { - // is it possible ? - // continue; - return S_FALSE; - } - - CNode &inode = vol.Nodes.Back(); - - if (inode.refcnt_defined) - return S_FALSE; - - inode.refcnt = refcnt; - inode.refcnt_defined = true; - if (inode.refcnt != (UInt32)inode.nlink) - { - PRF(printf(" refcnt != nlink")); - // is it possible ? - // return S_FALSE; - } - continue; - } - - if (type == APFS_TYPE_FILE_EXTENT) - { - PRF(printf(" FILE_EXTENT")); - /* - struct j_file_extent_key - { - j_key_t hdr; - uint64_t logical_addr; - } - */ - if (pair.Key.Size() != 16) - return S_FALSE; - // The offset within the file's data, in bytes, for the data stored in this extent - const UInt64 logical_addr = Get64(p + 8); - - j_file_extent_val eval; - if (pair.Val.Size() != k_SizeOf_j_file_extent_val) - return S_FALSE; - eval.Parse(pair.Val); - - if (logical_addr != 0) - { - PRF(printf(" logical_addr = %d", (unsigned)logical_addr)); - } - PRF(printf(" len = %8d pos = %8d", - (unsigned)eval.len_and_flags, - (unsigned)eval.phys_block_num - )); - - CExtent ext; - ext.logical_offset = logical_addr; - ext.len_and_flags = eval.len_and_flags; - ext.phys_block_num = eval.phys_block_num; - - if (vol.NodeIDs.IsEmpty()) - return S_FALSE; - if (vol.NodeIDs.Back() != id) - { - // extents for Attributs; - if (vol.SmallNodeIDs.IsEmpty() || - vol.SmallNodeIDs.Back() != id) - { - vol.SmallNodeIDs.Add(id); - vol.SmallNodes.AddNew(); - } - vol.SmallNodes.Back().Extents.Add(ext); - continue; - // return S_FALSE; - } - - CNode &inode = vol.Nodes.Back(); - inode.Extents.Add(ext); - continue; - } - - if (type == APFS_TYPE_DIR_REC) - { - UInt32 len; - unsigned nameOffset; - - if (isHashed) - { - /* - struct j_drec_hashed_key - { - j_key_t hdr; - UInt32 name_len_and_hash; - uint8_t name[0]; - } - */ - nameOffset = 8 + 4; - if (pair.Key.Size() < nameOffset + 1) - return S_FALSE; - const UInt32 name_len_and_hash = Get32(p + 8); - len = name_len_and_hash & J_DREC_LEN_MASK; - } - else - { - /* - struct j_drec_key - { - j_key_t hdr; - UInt16 name_len; // The length of the name, including the final null character - uint8_t name[0]; // The name, represented as a null-terminated UTF-8 string - } - */ - nameOffset = 8 + 2; - if (pair.Key.Size() < nameOffset + 1) - return S_FALSE; - len = Get16(p + 8); - } - if (nameOffset + len != pair.Key.Size()) - return S_FALSE; - - // CItem item; - item.Clear(); - - item.ParentId = id; - item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); - if (item.Name.Len() != len - 1) - return S_FALSE; - - if (pair.Val.Size() < k_SizeOf_j_drec_val) - return S_FALSE; - - item.Val.Parse(pair.Val); - - if (pair.Val.Size() > k_SizeOf_j_drec_val) - { - // fixme: parse extra fields; - // UnsupportedFeature = true; - // return S_FALSE; - } - - vol.Items.Add(item); - - /* - if (!vol.NodeIDs.IsEmpty() && vol.NodeIDs.Back() == id) - vol.Nodes.Back().NumItems++; - */ - if (id == PRIV_DIR_INO_NUM) - vol.NumItems_In_PrivateDir++; - - PRF(printf(" DIR_REC next=%6d flags=%2x %s", - (unsigned)item.Val.file_id, - (unsigned)item.Val.flags, - item.Name.Ptr())); - continue; - } - - if (type == APFS_TYPE_FILE_INFO) - { - if (pair.Key.Size() != 16) - return S_FALSE; - // j_file_info_key - const UInt64 info_and_lba = Get64(p + 8); - - #define J_FILE_INFO_LBA_MASK 0x00ffffffffffffffUL - // #define J_FILE_INFO_TYPE_MASK 0xff00000000000000UL - #define J_FILE_INFO_TYPE_SHIFT 56 - #define APFS_FILE_INFO_DATA_HASH 1 - - const unsigned infoType = (unsigned)(info_and_lba >> J_FILE_INFO_TYPE_SHIFT); - // address is a paddr_t - const UInt64 lba = info_and_lba & J_FILE_INFO_LBA_MASK; - // j_file_data_hash_val_t - /* Use this field of the union if the type stored in the info_and_lba field of j_file_info_val_t is - APFS_FILE_INFO_DATA_HASH */ - if (infoType != APFS_FILE_INFO_DATA_HASH) - return S_FALSE; - if (pair.Val.Size() != 3 + vol.integrity.HashSize) - return S_FALSE; - /* - struct j_file_data_hash_val - { - UInt16 hashed_len; // The length, in blocks, of the data segment that was hashed. - UInt8 hash_size; // must be consistent with integrity_meta_phys_t::im_hash_type - UInt8 hash[0]; - } - */ - - const unsigned hash_size = pair.Val[2]; - if (hash_size != vol.integrity.HashSize) - return S_FALSE; - - CHashChunk hr; - hr.hashed_len = GetUi16(pair.Val); - if (hr.hashed_len == 0) - return S_FALSE; - memcpy(hr.hash, (const Byte *)pair.Val + 3, vol.integrity.HashSize); - // (hashed_len <= 4) : we have seen - hr.lba = lba; - - PRF(printf(" FILE_INFO lba = %6x, hashed_len=%6d", - (unsigned)lba, - (unsigned)hr.hashed_len)); - - if (vol.Hash_IDs.IsEmpty() || vol.Hash_IDs.Back() != id) - { - vol.Hash_Vectors.AddNew(); - vol.Hash_IDs.Add(id); - } - CStreamHashes &hashes = vol.Hash_Vectors.Back(); - if (hashes.Size() != 0) - { - const CHashChunk &hr_Back = hashes.Back(); - if (lba != hr_Back.lba + ((UInt64)hr_Back.hashed_len << sb.block_size_Log)) - return S_FALSE; - } - hashes.Add(hr); - continue; - } - - if (type == APFS_TYPE_SNAP_METADATA) - { - if (pair.Key.Size() != 8) - return S_FALSE; - PRF(printf(" SNAP_METADATA")); - // continue; - } - - /* SIBLING items are used, if there are more than one hard link to some inode - key : value - parent_id_1 DIR_REC : inode_id, name_1 - parent_id_2 DIR_REC : inode_id, name_2 - inode_id INODE : parent_id_1, name_1 - inode_id SIBLING_LINK sibling_id_1 : parent_id_1, name_1 - inode_id SIBLING_LINK sibling_id_2 : parent_id_2, name_2 - sibling_id_1 SIBLING_MAP : inode_id - sibling_id_2 SIBLING_MAP : inode_id - */ - - if (type == APFS_TYPE_SIBLING_LINK) - { - if (pair.Key.Size() != 16) - return S_FALSE; - if (pair.Val.Size() < 10 + 1) - return S_FALSE; - /* - // struct j_sibling_key - // The sibling's unique identifier. - // This value matches the object identifier for the sibling map record - const UInt64 sibling_id = Get64(p + 8); - // struct j_sibling_val - const Byte *v = pair.Val; - const UInt64 parent_id = Get64(v); // The object identifier for the inode that's the parent directory. - const unsigned name_len = Get16(v + 8); // len including the final null character - if (10 + name_len != pair.Val.Size()) - return S_FALSE; - if (v[10 + name_len - 1] != 0) - return S_FALSE; - AString name ((const char *)(v + 10)); - if (name.Len() != name_len - 1) - return S_FALSE; - PRF(printf(" SIBLING_LINK sibling_id = %6d : parent_id=%6d %s", - (unsigned)sibling_id, (unsigned)parent_id, name.Ptr())); - */ - continue; - } - - if (type == APFS_TYPE_SIBLING_MAP) - { - // struct j_sibling_map_key - // The object identifier in the header is the sibling's unique identifier - if (pair.Key.Size() != 8 || pair.Val.Size() != 8) - return S_FALSE; - /* - // j_sibling_map_val - // The inode number of the underlying file - const UInt64 file_id = Get64(pair.Val); - PRF(printf(" SIBLING_MAP : file_id = %d", (unsigned)file_id)); - */ - continue; - } - - UnsupportedFeature = true; - // return S_FALSE; - } - ProgressVal_NumFilesTotal += vol.Items.Size(); - } - - - if (needParseAttr) - { - /* we read external streams for attributes - So we can get SymLink for GetProperty(kpidSymLink) later */ - FOR_VECTOR (i, vol.Nodes) - { - CNode &node = vol.Nodes[i]; - - FOR_VECTOR (a, node.Attrs) - { - CAttr &attr = node.Attrs[a]; - if (attr.Data.Size() != 0 || !attr.dstream_defined) - continue; - if (a == node.SymLinkIndex) - { - if (!attr.Is_dstream_OK_for_SymLink()) - continue; - } - else - { - if (a != node.DecmpfsIndex - // && a != node.ResourceIndex - ) - continue; - } - // we don't expect big streams here - // largest dstream for Decmpfs attribute is (2Kib+17) - if (attr.dstream.size > ((UInt32)1 << 16)) - continue; - CMyComPtr inStream; - const HRESULT res = GetAttrStream_dstream(OpenInStream, vol, attr, &inStream); - if (res == S_OK && inStream) - { - CByteBuffer buf2; - const size_t size = (size_t)attr.dstream.size; - buf2.Alloc(size); - if (ReadStream_FAIL(inStream, buf2, size) == S_OK) - attr.Data = buf2; - - ProgressVal_Cur += size; - if (OpenCallback) - if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) - { - - RINOK(OpenCallback->SetCompleted( - &ProgressVal_NumFilesTotal, - &ProgressVal_Cur)) - ProgressVal_Prev = ProgressVal_Cur; - } - } - } - - if (node.Has_UNCOMPRESSED_SIZE()) - if (IsViDef(node.DecmpfsIndex)) - { - CAttr &attr = node.Attrs[node.DecmpfsIndex]; - node.CompressHeader.Parse(attr.Data, attr.Data.Size()); - - if (node.CompressHeader.IsCorrect) - if (node.CompressHeader.Method < sizeof(MethodsMask) * 8) - MethodsMask |= ((UInt32)1 << node.CompressHeader.Method); - - if (node.CompressHeader.IsCorrect - && node.CompressHeader.IsSupported - && node.CompressHeader.UnpackSize == node.uncompressed_size) - { - attr.NeedShow = false; - if (node.CompressHeader.IsMethod_Resource() - && IsViDef(node.ResourceIndex)) - node.Attrs[node.ResourceIndex].NeedShow = false; - } - else - { - vol.UnsupportedMethod = true; - } - } - } - } - - const HRESULT res = vol.FillRefs(); - - if (vol.ThereAreErrors()) - HeadersError = true; - if (vol.UnsupportedFeature) - UnsupportedFeature = true; - if (vol.UnsupportedMethod) - UnsupportedMethod = true; - if (vol.NumAltStreams != 0) - ThereAreAltStreams = true; - - return res; -} - - - -HRESULT CVol::FillRefs() -{ - { - Refs.Reserve(Items.Size()); - // we fill Refs[*] - // we - // and set Nodes[*].ItemIndex for Nodes that are directories; - FOR_VECTOR (i, Items) - { - CItem &item = Items[i]; - const UInt64 id = item.Val.file_id; - // if (item.Id == ROOT_DIR_PARENT) continue; - /* for two root folders items - we don't set Node.ItemIndex; */ - // so nodes - if (id == ROOT_DIR_INO_NUM) - continue; - if (id == PRIV_DIR_INO_NUM) - if (NumItems_In_PrivateDir == 0) // if (inode.NumItems == 0) - continue; - - CRef ref; - ref.ItemIndex = i; - // ref.NodeIndex = VI_MINUS1; - ref.ParentRefIndex = VI_MINUS1; - #ifdef APFS_SHOW_ALT_STREAMS - ref.AttrIndex = VI_MINUS1; - #endif - const int index = NodeIDs.FindInSorted(id); - // const int index = -1; // for debug - ref.NodeIndex = (unsigned)index; - item.RefIndex = Refs.Size(); - Refs.Add(ref); - - if (index == -1) - { - NodeNotFound = true; - continue; - // return S_FALSE; - } - - // item.iNode_Index = index; - CNode &inode = Nodes[(unsigned)index]; - if (!item.Val.IsFlags_Unknown() - && inode.Get_Type_From_mode() != item.Val.flags) - { - Refs.Back().NodeIndex = VI_MINUS1; - WrongInodeLink = true; - continue; - // return S_FALSE; - } - - const bool isDir = inode.IsDir(); - if (isDir) - { - if (IsViDef(inode.ItemIndex)) - { - // hard links to dirs are not supported - Refs.Back().NodeIndex = VI_MINUS1; - WrongInodeLink = true; - continue; - } - inode.ItemIndex = i; - } - inode.NumCalcedLinks++; - - #ifdef APFS_SHOW_ALT_STREAMS - if (!isDir) - { - // we use alt streams only for files - const unsigned numAttrs = inode.Attrs.Size(); - if (numAttrs != 0) - { - ref.ParentRefIndex = item.RefIndex; - for (unsigned k = 0; k < numAttrs; k++) - { - // comment it for debug - const CAttr &attr = inode.Attrs[k]; - if (!attr.NeedShow) - continue; - - if (k == inode.SymLinkIndex) - continue; - ref.AttrIndex = k; - NumAltStreams++; - Refs.Add(ref); - /* - if (attr.dstream_defined) - { - const int idIndex = SmallNodeIDs.FindInSorted(attr.Id); - if (idIndex != -1) - SmallNodes[(unsigned)idIndex].NumLinks++; // for debug - } - */ - } - } - } - #endif - } - } - - - { - // fill ghost nodes - CRef ref; - ref.ItemIndex = VI_MINUS1; - ref.ParentRefIndex = VI_MINUS1; - #ifdef APFS_SHOW_ALT_STREAMS - ref.AttrIndex = VI_MINUS1; - #endif - FOR_VECTOR (i, Nodes) - { - if (Nodes[i].NumCalcedLinks != 0) - continue; - const UInt64 id = NodeIDs[i]; - if (id == ROOT_DIR_INO_NUM || - id == PRIV_DIR_INO_NUM) - continue; - ThereAreUnlinkedNodes = true; - ref.NodeIndex = i; - Refs.Add(ref); - } - } - - /* if want to create Refs for ghost data streams, - we need additional CRef::SmallNodeIndex field */ - - { - /* all Nodes[*].ItemIndex were already filled for directory Nodes, - except of "root" and "private-dir" Nodes. */ - - // now we fill Items[*].ParentItemIndex and Refs[*].ParentRefIndex - - UInt64 prev_ID = (UInt64)(Int64)-1; - unsigned prev_ParentItemIndex = VI_MINUS1; - - FOR_VECTOR (i, Items) - { - CItem &item = Items[i]; - const UInt64 id = item.ParentId; // it's id of parent NODE - if (id != prev_ID) - { - prev_ID = id; - prev_ParentItemIndex = VI_MINUS1; - const int index = NodeIDs.FindInSorted(id); - if (index == -1) - continue; - prev_ParentItemIndex = Nodes[(unsigned)index].ItemIndex; - } - - if (IsViNotDef(prev_ParentItemIndex)) - continue; - item.ParentItemIndex = prev_ParentItemIndex; - if (IsViNotDef(item.RefIndex)) - { - // RefIndex is not set for 2 Items (root folders) - // but there is no node for them usually - continue; - } - CRef &ref = Refs[item.RefIndex]; - - /* - // it's optional check that parent_id is set correclty - if (IsViDef(ref.NodeIndex)) - { - const CNode &node = Nodes[ref.NodeIndex]; - if (node.IsDir() && node.parent_id != id) - return S_FALSE; - } - */ - - /* - if (id == ROOT_DIR_INO_NUM) - { - // ItemIndex in Node for ROOT_DIR_INO_NUM was not set bofere - // probably unused now. - ref.ParentRefIndex = VI_MINUS1; - } - else - */ - ref.ParentRefIndex = Items[prev_ParentItemIndex].RefIndex; - } - } - - { - // check for loops - const unsigned numItems = Items.Size(); - if (numItems + 1 == 0) - return S_FALSE; - CUIntArr arr; - arr.Alloc(numItems); - { - for (unsigned i = 0; i < numItems; i++) - arr[i] = 0; - } - for (unsigned i = 0; i < numItems;) - { - unsigned k = i++; - for (;;) - { - const unsigned a = arr[k]; - if (a != 0) - { - if (a == i) - return S_FALSE; - break; - } - arr[k] = i; - k = Items[k].ParentItemIndex; - if (IsViNotDef(k)) - break; - } - } - } - - return S_OK; -} - - - -Z7_class_CHandler_final: - public IInArchive, - public IArchiveGetRawProps, - public IInArchiveGetStream, - public CMyUnknownImp, - public CDatabase -{ - Z7_IFACES_IMP_UNK_3( - IInArchive, - IArchiveGetRawProps, - IInArchiveGetStream) - - CMyComPtr _stream; - int FindHashIndex_for_Item(UInt32 index); -}; - - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - OpenInStream = inStream; - OpenCallback = callback; - RINOK(Open2()) - _stream = inStream; - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _stream.Release(); - Clear(); - return S_OK; -} - - -enum -{ - kpidBytesWritten = kpidUserDefined, - kpidBytesRead, - kpidPrimeName, - kpidParentINode, - kpidAddTime, - kpidGeneration, - kpidBsdFlags - // kpidUncompressedSize -}; - -static const CStatProp kProps[] = -{ - { NULL, kpidPath, VT_BSTR }, - { NULL, kpidSize, VT_UI8 }, - { NULL, kpidPackSize, VT_UI8 }, - { NULL, kpidPosixAttrib, VT_UI4 }, - { NULL, kpidMTime, VT_FILETIME }, - { NULL, kpidCTime, VT_FILETIME }, - { NULL, kpidATime, VT_FILETIME }, - { NULL, kpidChangeTime, VT_FILETIME }, - { "Added Time", kpidAddTime, VT_FILETIME }, - { NULL, kpidMethod, VT_BSTR }, - { NULL, kpidINode, VT_UI8 }, - { NULL, kpidLinks, VT_UI4 }, - { NULL, kpidSymLink, VT_BSTR }, - { NULL, kpidUserId, VT_UI4 }, - { NULL, kpidGroupId, VT_UI4 }, - { NULL, kpidCharacts, VT_BSTR }, - #ifdef APFS_SHOW_ALT_STREAMS - { NULL, kpidIsAltStream, VT_BOOL }, - #endif - { "Parent iNode", kpidParentINode, VT_UI8 }, - { "Primary Name", kpidPrimeName, VT_BSTR }, - { "Generation", kpidGeneration, VT_UI4 }, - { "Written Size", kpidBytesWritten, VT_UI8 }, - { "Read Size", kpidBytesRead, VT_UI8 }, - { "BSD Flags", kpidBsdFlags, VT_UI4 } - // , { "Uncompressed Size", kpidUncompressedSize, VT_UI8 } -}; - - -static const Byte kArcProps[] = -{ - kpidName, - kpidCharacts, - kpidId, - kpidClusterSize, - kpidCTime, - kpidMTime, - kpidComment -}; - -IMP_IInArchive_Props_WITH_NAME -IMP_IInArchive_ArcProps - - -static void ApfsTimeToProp(UInt64 hfsTime, NWindows::NCOM::CPropVariant &prop) -{ - if (hfsTime == 0) - return; - FILETIME ft; - UInt32 ns100; - ApfsTimeToFileTime(hfsTime, ft, ns100); - prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); -} - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CApfs *apfs = NULL; - if (Vols.Size() == 1) - apfs = &Vols[0].apfs; - switch (propID) - { - case kpidPhySize: - prop = (UInt64)sb.block_count << sb.block_size_Log; - break; - case kpidClusterSize: prop = (UInt32)(sb.block_size); break; - case kpidCharacts: NHfs::MethodsMaskToProp(MethodsMask, prop); break; - case kpidMTime: - if (apfs) - ApfsTimeToProp(apfs->modified_by[0].timestamp, prop); - break; - case kpidCTime: - if (apfs) - ApfsTimeToProp(apfs->formatted_by.timestamp, prop); - break; - case kpidIsTree: prop = true; break; - case kpidErrorFlags: - { - UInt32 flags = 0; - if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; - if (flags != 0) - prop = flags; - break; - } - case kpidWarningFlags: - { - UInt32 flags = 0; - if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature; - if (UnsupportedMethod) flags |= kpv_ErrorFlags_UnsupportedMethod; - if (flags != 0) - prop = flags; - break; - } - - case kpidName: - { - if (apfs) - { - UString s; - AddVolInternalName_toString(s, *apfs); - s += ".apfs"; - prop = s; - } - break; - } - - case kpidId: - { - char s[32 + 4]; - sb.uuid.SetHex_To_str(s); - prop = s; - break; - } - - case kpidComment: - { - UString s; - { - AddComment_UInt64(s, "block_size", sb.block_size); - - FOR_VECTOR (i, Vols) - { - if (Vols.Size() > 1) - { - if (i != 0) - { - s += "----"; - s.Add_LF(); - } - AddComment_UInt64(s, "Volume", i + 1); - } - Vols[i].AddComment(s); - } - } - prop = s; - break; - } - - #ifdef APFS_SHOW_ALT_STREAMS - case kpidIsAltStream: - prop = ThereAreAltStreams; - // prop = false; // for debug - break; - #endif - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = 0; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) -{ - *name = NULL; - *propID = 0; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - UInt32 parentIndex = (UInt32)(Int32)-1; - - if (IsViDef(ref2.RefIndex)) - { - const CRef &ref = vol.Refs[ref2.RefIndex]; - #ifdef APFS_SHOW_ALT_STREAMS - if (ref.IsAltStream()) - *parentType = NParentType::kAltStream; - #endif - if (IsViDef(ref.ParentRefIndex)) - parentIndex = (UInt32)(ref.ParentRefIndex + vol.StartRef2Index); - else if (index != vol.RootRef2Index && IsViDef(vol.RootRef2Index)) - parentIndex = (UInt32)vol.RootRef2Index; - } - - *parent = parentIndex; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - UNUSED_VAR(index) - UNUSED_VAR(propID) - return S_OK; -} - - -static void Utf8Name_to_InterName(const AString &src, UString &dest) -{ - ConvertUTF8ToUnicode(src, dest); - NItemName::NormalizeSlashes_in_FileName_for_OsPath(dest); -} - - -static void AddNodeName(UString &s, const CNode &inode, UInt64 id) -{ - s += "node"; - s.Add_UInt64(id); - if (!inode.PrimaryName.IsEmpty()) - { - s.Add_Dot(); - UString s2; - Utf8Name_to_InterName(inode.PrimaryName, s2); - s += s2; - } -} - - -void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const -{ - const unsigned kNumLevelsMax = (1 << 10); - const unsigned kLenMax = (1 << 12); - UString s; - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - - if (IsViDef(ref2.RefIndex)) - { - const CRef &ref = vol.Refs[ref2.RefIndex]; - unsigned cur = ref.ItemIndex; - UString s2; - if (IsViNotDef(cur)) - { - if (inode) - AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]); - } - else - { - for (unsigned i = 0;; i++) - { - if (i >= kNumLevelsMax || s.Len() > kLenMax) - { - s.Insert(0, UString("[LONG_PATH]")); - break; - } - const CItem &item = vol.Items[(unsigned)cur]; - Utf8Name_to_InterName(item.Name, s2); - // s2 += "a\\b"; // for debug - s.Insert(0, s2); - cur = item.ParentItemIndex; - if (IsViNotDef(cur)) - break; - // ParentItemIndex was not set for such items - // if (item.ParentId == ROOT_DIR_INO_NUM) break; - s.InsertAtFront(WCHAR_PATH_SEPARATOR); - } - } - - #ifdef APFS_SHOW_ALT_STREAMS - if (IsViDef(ref.AttrIndex) && inode) - { - s.Add_Colon(); - Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2); - // s2 += "a\\b"; // for debug - s += s2; - } - #endif - } - - if (!vol.RootName.IsEmpty()) - { - if (IsViDef(ref2.RefIndex)) - s.InsertAtFront(WCHAR_PATH_SEPARATOR); - s.Insert(0, vol.RootName); - } - - path = s; -} - - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - - if (IsViNotDef(ref2.RefIndex)) - { - switch (propID) - { - case kpidName: - case kpidPath: - GetItemPath(index, NULL, prop); - break; - case kpidIsDir: - prop = true; - break; - } - prop.Detach(value); - return S_OK; - } - - const CRef &ref = vol.Refs[ref2.RefIndex]; - - const CItem *item = NULL; - if (IsViDef(ref.ItemIndex)) - item = &vol.Items[ref.ItemIndex]; - - const CNode *inode = NULL; - if (IsViDef(ref.NodeIndex)) - inode = &vol.Nodes[ref.NodeIndex]; - - switch (propID) - { - case kpidPath: - GetItemPath(index, inode, prop); - break; - case kpidPrimeName: - { - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode && !inode->PrimaryName.IsEmpty()) - { - UString s; - ConvertUTF8ToUnicode(inode->PrimaryName, s); - /* - // for debug: - if (inode.PrimaryName != item.Name) throw 123456; - */ - prop = s; - } - break; - } - - case kpidName: - { - UString s; - #ifdef APFS_SHOW_ALT_STREAMS - if (ref.IsAltStream()) - { - // if (inode) - { - const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex]; - ConvertUTF8ToUnicode(attr.Name, s); - } - } - else - #endif - { - if (item) - ConvertUTF8ToUnicode(item->Name, s); - else if (inode) - AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]); - else - break; - } - // s += "s/1bs\\2"; // for debug: - prop = s; - break; - } - - case kpidSymLink: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode) - { - if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex)) - { - const CByteBuffer &buf = inode->Attrs[(unsigned)inode->SymLinkIndex].Data; - if (buf.Size() != 0) - { - AString s; - s.SetFrom_CalcLen((const char *)(const Byte *)buf, (unsigned)buf.Size()); - if (s.Len() == buf.Size() - 1) - { - UString u; - ConvertUTF8ToUnicode(s, u); - prop = u; - } - } - } - } - break; - - case kpidSize: - if (inode) - { - UInt64 size = 0; - if (inode->GetSize(ref.GetAttrIndex(), size) || - !inode->IsDir()) - prop = size; - } - break; - - case kpidPackSize: - if (inode) - { - UInt64 size; - if (inode->GetPackSize(ref.GetAttrIndex(), size) || - !inode->IsDir()) - prop = size; - } - break; - - case kpidMethod: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode) - { - if (inode->CompressHeader.IsCorrect) - inode->CompressHeader.MethodToProp(prop); - else if (IsViDef(inode->DecmpfsIndex)) - prop = "decmpfs"; - else if (!inode->IsDir() && !inode->dstream_defined) - { - if (inode->IsSymLink()) - { - if (IsViDef(inode->SymLinkIndex)) - prop = "symlink"; - } - // else prop = "no_dstream"; - } - } - break; - - /* - case kpidUncompressedSize: - if (inode && inode->Has_UNCOMPRESSED_SIZE()) - prop = inode->uncompressed_size; - break; - */ - - case kpidIsDir: - { - bool isDir = false; - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - { - if (inode) - isDir = inode->IsDir(); - else if (item) - isDir = item->Val.IsFlags_Dir(); - } - prop = isDir; - break; - } - - case kpidPosixAttrib: - { - if (inode) - { - UInt32 mode = inode->mode; - #ifdef APFS_SHOW_ALT_STREAMS - if (ref.IsAltStream()) - { - mode &= 0666; // we disable execution - mode |= MY_LIN_S_IFREG; - } - #endif - prop = (UInt32)mode; - } - else if (item && !item->Val.IsFlags_Unknown()) - prop = (UInt32)(item->Val.flags << 12); - break; - } - - case kpidCTime: if (inode) ApfsTimeToProp(inode->create_time, prop); break; - case kpidMTime: if (inode) ApfsTimeToProp(inode->mod_time, prop); break; - case kpidATime: if (inode) ApfsTimeToProp(inode->access_time, prop); break; - case kpidChangeTime: if (inode) ApfsTimeToProp(inode->change_time, prop); break; - case kpidAddTime: if (item) ApfsTimeToProp(item->Val.date_added, prop); break; - - case kpidBytesWritten: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode && inode->dstream_defined) - prop = inode->dstream.total_bytes_written; - break; - case kpidBytesRead: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode && inode->dstream_defined) - prop = inode->dstream.total_bytes_read; - break; - - #ifdef APFS_SHOW_ALT_STREAMS - case kpidIsAltStream: - prop = ref.IsAltStream(); - break; - #endif - - case kpidCharacts: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode) - { - FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop); - } - break; - - case kpidBsdFlags: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode) - { - FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop); - } - break; - - case kpidGeneration: - #ifdef APFS_SHOW_ALT_STREAMS - // if (!ref.IsAltStream()) - #endif - if (inode) - prop = inode->write_generation_counter; - break; - - case kpidUserId: - if (inode) - prop = (UInt32)inode->owner; - break; - - case kpidGroupId: - if (inode) - prop = (UInt32)inode->group; - break; - - case kpidLinks: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode && !inode->IsDir()) - prop = (UInt32)inode->nlink; - break; - - case kpidINode: - #ifdef APFS_SHOW_ALT_STREAMS - // here we can disable iNode for alt stream. - if (!ref.IsAltStream()) - #endif - if (IsViDef(ref.NodeIndex)) - prop = (UInt32)vol.NodeIDs[ref.NodeIndex]; - break; - - case kpidParentINode: - #ifdef APFS_SHOW_ALT_STREAMS - if (!ref.IsAltStream()) - #endif - if (inode) - prop = (UInt32)inode->parent_id; - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -UInt64 CDatabase::GetSize(const UInt32 index) const -{ - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - if (IsViNotDef(ref2.RefIndex)) - return 0; - const CRef &ref = vol.Refs[ref2.RefIndex]; - if (IsViNotDef(ref.NodeIndex)) - return 0; - const CNode &inode = vol.Nodes[ref.NodeIndex]; - UInt64 size; - if (inode.GetSize(ref.GetAttrIndex(), size)) - return size; - return 0; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = Refs2.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - { - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - totalSize += GetSize(index); - } - RINOK(extractCallback->SetTotal(totalSize)) - } - - UInt64 currentTotalSize = 0, currentItemSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - CMyComPtr2_Create copyCoder; - - // We don't know if zlib without Adler is allowed in APFS. - // But zlib without Adler is allowed in HFS. - // So here we allow apfs/zlib without Adler: - NHfs::CDecoder decoder(true); // IsAdlerOptional - - for (i = 0;; i++, currentTotalSize += currentItemSize) - { - lps->InSize = currentTotalSize; - lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()) - - if (i >= numItems) - break; - - const UInt32 index = allFilesMode ? i : indices[i]; - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - - currentItemSize = GetSize(index); - - int opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (IsViNotDef(ref2.RefIndex)) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const CRef &ref = vol.Refs[ref2.RefIndex]; - bool isDir = false; - if (IsViDef(ref.NodeIndex)) - isDir = vol.Nodes[ref.NodeIndex].IsDir(); - else if (IsViDef(ref.ItemIndex)) - isDir = - #ifdef APFS_SHOW_ALT_STREAMS - !ref.IsAltStream() && - #endif - vol.Items[ref.ItemIndex].Val.IsFlags_Dir(); - - if (isDir) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - opRes = NExtract::NOperationResult::kDataError; - - if (IsViDef(ref.NodeIndex)) - { - const CNode &inode = vol.Nodes[ref.NodeIndex]; - if ( - #ifdef APFS_SHOW_ALT_STREAMS - !ref.IsAltStream() && - #endif - !inode.dstream_defined - && inode.Extents.IsEmpty() - && inode.Has_UNCOMPRESSED_SIZE() - && inode.uncompressed_size == inode.CompressHeader.UnpackSize) - { - if (inode.CompressHeader.IsSupported) - { - CMyComPtr inStreamFork; - UInt64 forkSize = 0; - const CByteBuffer *decmpfs_Data = NULL; - - if (inode.CompressHeader.IsMethod_Resource()) - { - if (IsViDef(inode.ResourceIndex)) - { - const CAttr &attr = inode.Attrs[inode.ResourceIndex]; - forkSize = attr.GetSize(); - GetAttrStream(_stream, vol, attr, &inStreamFork); - } - } - else - { - const CAttr &attr = inode.Attrs[inode.DecmpfsIndex]; - decmpfs_Data = &attr.Data; - } - - if (inStreamFork || decmpfs_Data) - { - const HRESULT hres = decoder.Extract( - inStreamFork, realOutStream, - forkSize, - inode.CompressHeader, - decmpfs_Data, - currentTotalSize, extractCallback, - opRes); - if (hres != S_FALSE && hres != S_OK) - return hres; - } - } - else - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - else - { - CMyComPtr inStream; - if (GetStream(index, &inStream) == S_OK && inStream) - { - CMyComPtr2 hashStream; - - if (vol.integrity.Is_SHA256()) - { - const int hashIndex = FindHashIndex_for_Item(index); - if (hashIndex != -1) - { - hashStream.Create_if_Empty(); - hashStream->SetStream(realOutStream); - hashStream->Init(&(vol.Hash_Vectors[(unsigned)hashIndex]), sb.block_size_Log); - } - } - - RINOK(copyCoder.Interface()->Code(inStream, - hashStream.IsDefined() ? - hashStream.Interface() : - realOutStream.Interface(), - NULL, NULL, lps)) - opRes = NExtract::NOperationResult::kDataError; - if (copyCoder->TotalSize == currentItemSize) - { - opRes = NExtract::NOperationResult::kOK; - if (hashStream.IsDefined()) - if (!hashStream->FinalCheck()) - opRes = NExtract::NOperationResult::kCRCError; - } - else if (copyCoder->TotalSize < currentItemSize) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - } - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = Refs2.Size(); - return S_OK; -} - - -int CHandler::FindHashIndex_for_Item(UInt32 index) -{ - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - if (IsViNotDef(ref2.RefIndex)) - return -1; - - const CRef &ref = vol.Refs[ref2.RefIndex]; - if (IsViNotDef(ref.NodeIndex)) - return -1; - const CNode &inode = vol.Nodes[ref.NodeIndex]; - - unsigned attrIndex = ref.GetAttrIndex(); - - if (IsViNotDef(attrIndex) - && !inode.dstream_defined - && inode.IsSymLink()) - { - attrIndex = inode.SymLinkIndex; - if (IsViNotDef(attrIndex)) - return -1; - } - - if (IsViDef(attrIndex)) - { - /* we have seen examples, where hash available for "com.apple.ResourceFork" stream. - these hashes for "com.apple.ResourceFork" stream are for unpacked data. - but the caller here needs packed data of stream. So we don't use hashes */ - return -1; - } - else - { - if (!inode.dstream_defined) - return -1; - const UInt64 id = vol.NodeIDs[ref.NodeIndex]; - return vol.Hash_IDs.FindInSorted(id); - } -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - *stream = NULL; - - const CRef2 &ref2 = Refs2[index]; - const CVol &vol = Vols[ref2.VolIndex]; - if (IsViNotDef(ref2.RefIndex)) - return S_FALSE; - - const CRef &ref = vol.Refs[ref2.RefIndex]; - if (IsViNotDef(ref.NodeIndex)) - return S_FALSE; - const CNode &inode = vol.Nodes[ref.NodeIndex]; - - const CRecordVector *extents; - UInt64 rem = 0; - - unsigned attrIndex = ref.GetAttrIndex(); - - if (IsViNotDef(attrIndex) - && !inode.dstream_defined - && inode.IsSymLink()) - { - attrIndex = inode.SymLinkIndex; - if (IsViNotDef(attrIndex)) - return S_FALSE; - } - - if (IsViDef(attrIndex)) - { - const CAttr &attr = inode.Attrs[(unsigned)attrIndex]; - if (!attr.dstream_defined) - { - CMyComPtr2 streamTemp; - streamTemp.Create_if_Empty(); - streamTemp->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); - *stream = streamTemp.Detach(); - return S_OK; - } - const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); - if (idIndex != -1) - extents = &vol.SmallNodes[(unsigned)idIndex].Extents; - else - { - const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(attr.Id); - if (fext_Index == -1) - return S_FALSE; - extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents; - } - rem = attr.dstream.size; - } - else - { - if (IsViDef(ref.ItemIndex)) - if (vol.Items[ref.ItemIndex].Val.IsFlags_Dir()) - return S_FALSE; - if (inode.IsDir()) - return S_FALSE; - extents = &inode.Extents; - if (inode.dstream_defined) - { - rem = inode.dstream.size; - if (inode.Extents.Size() == 0) - { - const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(vol.NodeIDs[ref.NodeIndex]); - if (fext_Index != -1) - extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents; - } - } - else - { - // return S_FALSE; // check it !!! How zero size files are stored with dstream_defined? - } - } - return GetStream2(_stream, extents, rem, stream); -} - - - -HRESULT CDatabase::GetAttrStream(IInStream *apfsInStream, const CVol &vol, - const CAttr &attr, ISequentialInStream **stream) -{ - *stream = NULL; - if (!attr.dstream_defined) - { - CMyComPtr2 streamTemp; - streamTemp.Create_if_Empty(); - streamTemp->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); - *stream = streamTemp.Detach(); - return S_OK; - } - return GetAttrStream_dstream(apfsInStream, vol, attr, stream); -} - - -HRESULT CDatabase::GetAttrStream_dstream( IInStream *apfsInStream, const CVol &vol, - const CAttr &attr, ISequentialInStream **stream) -{ - const CRecordVector *extents; - { - const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); - if (idIndex != -1) - extents = &vol.SmallNodes[(unsigned)idIndex].Extents; - else - { - const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(attr.Id); - if (fext_Index == -1) - return S_FALSE; - extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents; - } - } - return GetStream2(apfsInStream, extents, attr.dstream.size, stream); -} - - -HRESULT CDatabase::GetStream2( - IInStream *apfsInStream, - const CRecordVector *extents, UInt64 rem, - ISequentialInStream **stream) -{ - CMyComPtr2 extentStream; - extentStream.Create_if_Empty(); - - UInt64 virt = 0; - FOR_VECTOR (i, *extents) - { - const CExtent &e = (*extents)[i]; - if (virt != e.logical_offset) - return S_FALSE; - const UInt64 len = EXTENT_GET_LEN(e.len_and_flags); - if (len == 0) - { - return S_FALSE; - // continue; - } - if (rem == 0) - return S_FALSE; - UInt64 cur = len; - if (cur > rem) - cur = rem; - CSeekExtent se; - se.Phy = (UInt64)e.phys_block_num << sb.block_size_Log; - se.Virt = virt; - virt += cur; - rem -= cur; - extentStream->Extents.Add(se); - if (rem == 0) - if (i != extents->Size() - 1) - return S_FALSE; - } - - if (rem != 0) - return S_FALSE; - - CSeekExtent se; - se.Phy = 0; - se.Virt = virt; - extentStream->Extents.Add(se); - extentStream->Stream = apfsInStream; - extentStream->Init(); - *stream = extentStream.Detach(); - return S_OK; -} - - -REGISTER_ARC_I( - "APFS", "apfs img", NULL, 0xc3, - k_Signature, - k_SignatureOffset, - 0, - IsArc_APFS) - -}} +// ApfsHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../C/CpuArch.h" +#include "../../../C/Sha256.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer2.h" +#include "../../Common/MyLinux.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariantConv.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" + +#include "HfsHandler.h" + +// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files. +#define APFS_SHOW_ALT_STREAMS + +#define VI_MINUS1 ((unsigned)(int)-1) +#define IsViDef(x) ((int)(x) != -1) +#define IsViNotDef(x) ((int)(x) == -1) + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + +namespace NArchive { +namespace NApfs { + +struct CUuid +{ + Byte Data[16]; + + void SetHex_To_str(char *s) const + { + ConvertDataToHex_Lower(s, Data, sizeof(Data)); + } + + void AddHexToString(UString &dest) const + { + char temp[sizeof(Data) * 2 + 4]; + SetHex_To_str(temp); + dest += temp; + } + + void SetFrom(const Byte *p) { memcpy(Data, p, 16); } +}; + + +typedef UInt64 oid_t; +typedef UInt64 xid_t; +// typedef Int64 paddr_t; +typedef UInt64 paddr_t_unsigned; + +#define G64o G64 +#define G64x G64 +// #define G64a G64 + +/* +struct prange_t +{ + paddr_t start_paddr; + UInt64 block_count; + + void Parse(const Byte *p) + { + G64a (0, start_paddr); + G64 (8, block_count); + } +}; +*/ + +#define OBJECT_TYPE_NX_SUPERBLOCK 0x1 +#define OBJECT_TYPE_BTREE 0x2 +#define OBJECT_TYPE_BTREE_NODE 0x3 +/* +#define OBJECT_TYPE_SPACEMAN 0x5 +#define OBJECT_TYPE_SPACEMAN_CAB 0x6 +#define OBJECT_TYPE_SPACEMAN_CIB 0x7 +#define OBJECT_TYPE_SPACEMAN_BITMAP 0x8 +#define OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x9 +#define OBJECT_TYPE_EXTENT_LIST_TREE 0xa +*/ +#define OBJECT_TYPE_OMAP 0xb +/* +#define OBJECT_TYPE_CHECKPOINT_MAP 0xc +*/ +#define OBJECT_TYPE_FS 0xd +#define OBJECT_TYPE_FSTREE 0xe +/* +#define OBJECT_TYPE_BLOCKREFTREE 0xf +#define OBJECT_TYPE_SNAPMETATREE 0x10 +#define OBJECT_TYPE_NX_REAPER 0x11 +#define OBJECT_TYPE_NX_REAP_LIST 0x12 +#define OBJECT_TYPE_OMAP_SNAPSHOT 0x13 +#define OBJECT_TYPE_EFI_JUMPSTART 0x14 +#define OBJECT_TYPE_FUSION_MIDDLE_TREE 0x15 +#define OBJECT_TYPE_NX_FUSION_WBC 0x16 +#define OBJECT_TYPE_NX_FUSION_WBC_LIST 0x17 +#define OBJECT_TYPE_ER_STATE 0x18 +#define OBJECT_TYPE_GBITMAP 0x19 +#define OBJECT_TYPE_GBITMAP_TREE 0x1a +#define OBJECT_TYPE_GBITMAP_BLOCK 0x1b +#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x1c +#define OBJECT_TYPE_SNAP_META_EXT 0x1d +*/ +#define OBJECT_TYPE_INTEGRITY_META 0x1e +#define OBJECT_TYPE_FEXT_TREE 0x1f +/* +#define OBJECT_TYPE_RESERVED_20 0x20 + +#define OBJECT_TYPE_INVALID 0x0 +#define OBJECT_TYPE_TEST 0xff +#define OBJECT_TYPE_CONTAINER_KEYBAG 'keys' +#define OBJECT_TYPE_VOLUME_KEYBAG 'recs' +#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey' + +#define OBJ_VIRTUAL 0x0 +#define OBJ_EPHEMERAL 0x80000000 +*/ +#define OBJ_PHYSICAL 0x40000000 +/* +#define OBJ_NOHEADER 0x20000000 +#define OBJ_ENCRYPTED 0x10000000 +#define OBJ_NONPERSISTENT 0x08000000 +*/ +#define OBJECT_TYPE_MASK 0x0000ffff +/* +#define OBJECT_TYPE_FLAGS_MASK 0xffff0000 +#define OBJ_STORAGETYPE_MASK 0xc0000000 +#define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000 +*/ + +// #define MAX_CKSUM_SIZE 8 + +static const unsigned k_obj_phys_Size = 0x20; + +// obj_phys_t +struct CPhys +{ + // Byte cksum[MAX_CKSUM_SIZE]; + oid_t oid; + xid_t xid; + UInt32 type; + UInt32 subtype; + + UInt32 GetType() const { return type & OBJECT_TYPE_MASK; } + void Parse(const Byte *p); +}; + +void CPhys::Parse(const Byte *p) +{ + // memcpy(cksum, p, MAX_CKSUM_SIZE); + G64o (8, oid) + G64x (0x10, xid) + G32 (0x18, type) + G32 (0x1C, subtype) +} + +#define NX_MAX_FILE_SYSTEMS 100 +/* +#define NX_EPH_INFO_COUNT 4 +#define NX_EPH_MIN_BLOCK_COUNT 8 +#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4 +#define NX_TX_MIN_CHECKPOINT_COUNT 4 +#define NX_EPH_INFO_VERSION_1 1 +*/ + +/* +typedef enum +{ + NX_CNTR_OBJ_CKSUM_SET = 0, + NX_CNTR_OBJ_CKSUM_FAIL = 1, + NX_NUM_COUNTERS = 32 +} counter_id_t; +*/ + +/* Incompatible volume feature flags */ +#define APFS_INCOMPAT_CASE_INSENSITIVE (1 << 0) +/* +#define APFS_INCOMPAT_DATALESS_SNAPS (1 << 1) +#define APFS_INCOMPAT_ENC_ROLLED (1 << 2) +*/ +#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE (1 << 3) +/* +#define APFS_INCOMPAT_INCOMPLETE_RESTORE (1 << 4) +*/ +#define APFS_INCOMPAT_SEALED_VOLUME (1 << 5) +/* +#define APFS_INCOMPAT_RESERVED_40 (1 << 6) +*/ + +static const char * const g_APFS_INCOMPAT_Flags[] = +{ + "CASE_INSENSITIVE" + , "DATALESS_SNAPS" + , "ENC_ROLLED" + , "NORMALIZATION_INSENSITIVE" + , "INCOMPLETE_RESTORE" + , "SEALED_VOLUME" +}; + +/* +#define APFS_SUPPORTED_INCOMPAT_MASK \ + ( APFS_INCOMPAT_CASE_INSENSITIVE \ + | APFS_INCOMPAT_DATALESS_SNAPS \ + | APFS_INCOMPAT_ENC_ROLLED \ + | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \ + | APFS_INCOMPAT_INCOMPLETE_RESTORE \ + | APFS_INCOMPAT_SEALED_VOLUME \ + | APFS_INCOMPAT_RESERVED_40 \ +) +*/ + +// superblock_t +struct CSuperBlock +{ + // CPhys o; + // UInt32 magic; + UInt32 block_size; + unsigned block_size_Log; + UInt64 block_count; + // UInt64 features; + // UInt64 readonly_compatible_features; + // UInt64 incompatible_features; + CUuid uuid; + /* + oid_t next_oid; + xid_t next_xid; + UInt32 xp_desc_blocks; + UInt32 xp_data_blocks; + paddr_t xp_desc_base; + paddr_t xp_data_base; + UInt32 xp_desc_next; + UInt32 xp_data_next; + UInt32 xp_desc_index; + UInt32 xp_desc_len; + UInt32 xp_data_index; + UInt32 xp_data_len; + oid_t spaceman_oid; + */ + oid_t omap_oid; + // oid_t reaper_oid; + // UInt32 test_type; + UInt32 max_file_systems; + // oid_t fs_oid[NX_MAX_FILE_SYSTEMS]; + /* + UInt64 counters[NX_NUM_COUNTERS]; // counter_id_t + prange_t blocked_out_prange; + oid_t evict_mapping_tree_oid; + UInt64 flags; + paddr_t efi_jumpstart; + CUuid fusion_uuid; + prange_t keylocker; + UInt64 ephemeral_info[NX_EPH_INFO_COUNT]; + oid_t test_oid; + oid_t fusion_mt_oid; + oid_t fusion_wbc_oid; + prange_t fusion_wbc; + UInt64 newest_mounted_version; + prange_t mkb_locker; + */ + + bool Parse(const Byte *p); +}; + +struct CSuperBlock2 +{ + oid_t fs_oid[NX_MAX_FILE_SYSTEMS]; + void Parse(const Byte *p) + { + for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++) + { + G64o (0xb8 + i * 8, fs_oid[i]) + } + } +}; + + +// we include one additional byte of next field (block_size) +static const unsigned k_SignatureOffset = 32; +static const Byte k_Signature[] = { 'N', 'X', 'S', 'B', 0 }; + +// size must be 4 bytes aligned +static UInt64 Fletcher64(const Byte *data, size_t size) +{ + const UInt32 kMax32 = 0xffffffff; + const UInt64 val = 0; // startVal + UInt64 a = val & kMax32; + UInt64 b = (val >> 32) & kMax32; + for (size_t i = 0; i < size; i += 4) + { + a += GetUi32(data + i); + b += a; + } + a %= kMax32; + b %= kMax32; + b = (UInt32)(kMax32 - ((a + b) % kMax32)); + a = (UInt32)(kMax32 - ((a + b) % kMax32)); + return (a << 32) | b; +} + +static bool CheckFletcher64(const Byte *p, size_t size) +{ + const UInt64 calculated_checksum = Fletcher64(p + 8, size - 8); + const UInt64 stored_checksum = Get64(p); + return (stored_checksum == calculated_checksum); +} + + +static unsigned GetLogSize(UInt32 size) +{ + unsigned k; + for (k = 0; k < 32; k++) + if (((UInt32)1 << k) == size) + return k; + return k; +} + +static const unsigned kApfsHeaderSize = 1 << 12; + +// #define OID_INVALID 0 +#define OID_NX_SUPERBLOCK 1 +// #define OID_RESERVED_COUNT 1024 +// This range of identifiers is reserved for physical, virtual, and ephemeral objects + +bool CSuperBlock::Parse(const Byte *p) +{ + CPhys o; + o.Parse(p); + if (o.oid != OID_NX_SUPERBLOCK) + return false; + if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) + return false; + if (o.subtype != 0) + return false; + if (memcmp(p + k_SignatureOffset, k_Signature, 4) != 0) + return false; + if (!CheckFletcher64(p, kApfsHeaderSize)) + return false; + + G32 (0x24, block_size) + { + const unsigned logSize = GetLogSize(block_size); + // don't change it. Some code requires (block_size <= 16) + if (logSize < 12 || logSize > 16) + return false; + block_size_Log = logSize; + } + + G64 (0x28, block_count) + + const UInt64 kArcSize_MAX = (UInt64)1 << 62; + if (block_count > (kArcSize_MAX >> block_size_Log)) + return false; + + // G64 (0x30, features); + // G64 (0x38, readonly_compatible_features); + // G64 (0x40, incompatible_features); + uuid.SetFrom(p + 0x48); + /* + G64o (0x58, next_oid); + G64x (0x60, next_xid); + G32 (0x68, xp_desc_blocks); + G32 (0x6c, xp_data_blocks); + G64a (0x70, xp_desc_base); + G64a (0x78, xp_data_base); + G32 (0x80, xp_desc_next); + G32 (0x84, xp_data_next); + G32 (0x88, xp_desc_index); + G32 (0x8c, xp_desc_len); + G32 (0x90, xp_data_index); + G32 (0x94, xp_data_len); + G64o (0x98, spaceman_oid); + */ + G64o (0xa0, omap_oid) + // G64o (0xa8, reaper_oid); + // G32 (0xb0, test_type); + G32 (0xb4, max_file_systems) + if (max_file_systems > NX_MAX_FILE_SYSTEMS) + return false; + /* + { + for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++) + { + G64o (0xb8 + i * 8, fs_oid[i]); + } + } + */ + /* + { + for (unsigned i = 0; i < NX_NUM_COUNTERS; i++) + { + G64 (0x3d8 + i * 8, counters[i]); + } + } + blocked_out_prange.Parse(p + 0x4d8); + G64o (0x4e8, evict_mapping_tree_oid); + #define NX_CRYPTO_SW 0x00000004LL + G64 (0x4f0, flags); + G64a (0x4f8, efi_jumpstart); + fusion_uuid.SetFrom(p + 0x500); + keylocker.Parse(p + 0x510); + { + for (unsigned i = 0; i < NX_EPH_INFO_COUNT; i++) + { + G64 (0x520 + i * 8, ephemeral_info[i]); + } + } + G64o (0x540, test_oid); + G64o (0x548, fusion_mt_oid); + G64o (0x550, fusion_wbc_oid); + fusion_wbc.Parse(p + 0x558); + G64 (0x568, newest_mounted_version); // decimal 1412141 001 000 000 + mkb_locker.Parse(p + 0x570); + */ + + return true; +} + + +enum apfs_hash_type_t +{ + APFS_HASH_INVALID = 0, + APFS_HASH_SHA256 = 1, + APFS_HASH_SHA512_256 = 2, + APFS_HASH_SHA384 = 3, + APFS_HASH_SHA512 = 4, + + APFS_HASH_MIN = APFS_HASH_SHA256, + APFS_HASH_MAX = APFS_HASH_SHA512, + + APFS_HASH_DEFAULT = APFS_HASH_SHA256 +}; + +static unsigned GetHashSize(unsigned hashType) +{ + if (hashType > APFS_HASH_MAX) return 0; + if (hashType < APFS_HASH_MIN) return 0; + if (hashType == APFS_HASH_SHA256) return 32; + return hashType * 16; +} + +#define APFS_HASH_MAX_SIZE 64 + +static const char * const g_hash_types[] = +{ + NULL + , "SHA256" + , "SHA512_256" + , "SHA384" + , "SHA512" +}; + + +struct C_integrity_meta_phys +{ + // CPhys im_o; + // UInt32 im_version; + UInt32 im_flags; + // apfs_hash_type_t + UInt32 im_hash_type; + // UInt32 im_root_hash_offset; + // xid_t im_broken_xid; + // UInt64 im_reserved[9]; + + unsigned HashSize; + Byte Hash[APFS_HASH_MAX_SIZE]; + + bool Is_SHA256() const { return im_hash_type == APFS_HASH_SHA256; } + + C_integrity_meta_phys() + { + memset(this, 0, sizeof(*this)); + } + bool Parse(const Byte *p, size_t size, oid_t oid); +}; + +bool C_integrity_meta_phys::Parse(const Byte *p, size_t size, oid_t oid) +{ + CPhys o; + if (!CheckFletcher64(p, size)) + return false; + o.Parse(p); + if (o.GetType() != OBJECT_TYPE_INTEGRITY_META) + return false; + if (o.oid != oid) + return false; + // G32 (0x20, im_version); + G32 (0x24, im_flags) + G32 (0x28, im_hash_type) + UInt32 im_root_hash_offset; + G32 (0x2C, im_root_hash_offset) + // G64x (0x30, im_broken_xid); + const unsigned hashSize = GetHashSize(im_hash_type); + HashSize = hashSize; + if (im_root_hash_offset >= size || size - im_root_hash_offset < hashSize) + return false; + memcpy(Hash, p + im_root_hash_offset, hashSize); + return true; +} + + +struct C_omap_phys +{ + // om_ prefix + // CPhys o; + /* + UInt32 flags; + UInt32 snap_count; + UInt32 tree_type; + UInt32 snapshot_tree_type; + */ + oid_t tree_oid; + /* + oid_t snapshot_tree_oid; + xid_t most_recent_snap; + xid_t pending_revert_min; + xid_t pending_revert_max; + */ + bool Parse(const Byte *p, size_t size, oid_t oid); +}; + +bool C_omap_phys::Parse(const Byte *p, size_t size, oid_t oid) +{ + CPhys o; + if (!CheckFletcher64(p, size)) + return false; + o.Parse(p); + if (o.GetType() != OBJECT_TYPE_OMAP) + return false; + if (o.oid != oid) + return false; + /* + G32 (0x20, flags); + G32 (0x24, snap_count); + G32 (0x28, tree_type); + G32 (0x2C, snapshot_tree_type); + */ + G64o (0x30, tree_oid) + /* + G64o (0x38, snapshot_tree_oid); + G64x (0x40, most_recent_snap); + G64x (0x48, pending_revert_min); + G64x (0x50, pending_revert_max); + */ + return true; +} + + +// #define BTOFF_INVALID 0xffff +/* This value is stored in the off field of nloc_t to indicate that +there's no offset. For example, the last entry in a free +list has no entry after it, so it uses this value for its off field. */ + +// A location within a B-tree node +struct nloc +{ + UInt16 off; + UInt16 len; + + void Parse(const Byte *p) + { + G16 (0, off) + G16 (2, len) + } + UInt32 GetEnd() const { return (UInt32)off + len; } + bool CheckOverLimit(UInt32 limit) + { + return off < limit && len <= limit - off; + } +}; + + +// The location, within a B-tree node, of a key and value +struct kvloc +{ + nloc k; + nloc v; + + void Parse(const Byte *p) + { + k.Parse(p); + v.Parse(p + 4); + } +}; + + +// The location, within a B-tree node, of a fixed-size key and value +struct kvoff +{ + UInt16 k; + UInt16 v; + + void Parse(const Byte *p) + { + G16 (0, k) + G16 (2, v) + } +}; + + +#define BTNODE_ROOT (1 << 0) +#define BTNODE_LEAF (1 << 1) +#define BTNODE_FIXED_KV_SIZE (1 << 2) +#define BTNODE_HASHED (1 << 3) +#define BTNODE_NOHEADER (1 << 4) +/* +#define BTNODE_CHECK_KOFF_INVAL (1 << 15) +*/ + +static const unsigned k_Toc_offset = 0x38; + +// btree_node_phys +struct CBTreeNodePhys +{ + // btn_ prefix + CPhys ophys; + UInt16 flags; + UInt16 level; // the number of child levels below this node. 0 - for a leaf node, 1 for the immediate parent of a leaf node + UInt32 nkeys; // The number of keys stored in this node. + nloc table_space; + /* + nloc free_space; + nloc key_free_list; + nloc val_free_list; + */ + + bool Is_FIXED_KV_SIZE() const { return (flags & BTNODE_FIXED_KV_SIZE) != 0; } + bool Is_NOHEADER() const { return (flags & BTNODE_NOHEADER) != 0; } + bool Is_HASHED() const { return (flags & BTNODE_HASHED) != 0; } + + bool Parse(const Byte *p, size_t size, bool noHeader = false) + { + G16 (0x20, flags) + G16 (0x22, level) + G32 (0x24, nkeys) + table_space.Parse(p + 0x28); + /* + free_space.Parse(p + 0x2C); + key_free_list.Parse(p + 0x30); + val_free_list.Parse(p + 0x34); + */ + memset(&ophys, 0, sizeof(ophys)); + if (noHeader) + { + for (unsigned i = 0; i < k_obj_phys_Size; i++) + if (p[i] != 0) + return false; + } + else + { + if (!CheckFletcher64(p, size)) + return false; + ophys.Parse(p); + } + if (Is_NOHEADER() != noHeader) + return false; + return true; + } +}; + +/* +#define BTREE_UINT64_KEYS (1 << 0) +#define BTREE_SEQUENTIAL_INSERT (1 << 1) +#define BTREE_ALLOW_GHOSTS (1 << 2) +*/ +#define BTREE_EPHEMERAL (1 << 3) +#define BTREE_PHYSICAL (1 << 4) +/* +#define BTREE_NONPERSISTENT (1 << 5) +#define BTREE_KV_NONALIGNED (1 << 6) +#define BTREE_HASHED (1 << 7) +*/ +#define BTREE_NOHEADER (1 << 8) + +/* + BTREE_EPHEMERAL: The nodes in the B-tree use ephemeral object identifiers to link to child nodes + BTREE_PHYSICAL : The nodes in the B-tree use physical object identifiers to link to child nodes. + If neither flag is set, nodes in the B-tree use virtual object + identifiers to link to their child nodes. +*/ + +// Static information about a B-tree. +struct btree_info_fixed +{ + UInt32 flags; + UInt32 node_size; + UInt32 key_size; + UInt32 val_size; + + void Parse(const Byte *p) + { + G32 (0, flags) + G32 (4, node_size) + G32 (8, key_size) + G32 (12, val_size) + } +}; + +static const unsigned k_btree_info_Size = 0x28; + +struct btree_info +{ + btree_info_fixed fixed; + UInt32 longest_key; + UInt32 longest_val; + UInt64 key_count; + UInt64 node_count; + + bool Is_EPHEMERAL() const { return (fixed.flags & BTREE_EPHEMERAL) != 0; } + bool Is_PHYSICAL() const { return (fixed.flags & BTREE_PHYSICAL) != 0; } + bool Is_NOHEADER() const { return (fixed.flags & BTREE_NOHEADER) != 0; } + + void Parse(const Byte *p) + { + fixed.Parse(p); + G32 (0x10, longest_key) + G32 (0x14, longest_val) + G64 (0x18, key_count) + G64 (0x20, node_count) + } +}; + + +/* +typedef UInt32 cp_key_class_t; +typedef UInt32 cp_key_os_version_t; +typedef UInt16 cp_key_revision_t; +typedef UInt32 crypto_flags_t; + +struct wrapped_meta_crypto_state +{ + UInt16 major_version; + UInt16 minor_version; + crypto_flags_t cpflags; + cp_key_class_t persistent_class; + cp_key_os_version_t key_os_version; + cp_key_revision_t key_revision; + // UInt16 unused; + + void Parse(const Byte *p) + { + G16 (0, major_version); + G16 (2, minor_version); + G32 (4, cpflags); + G32 (8, persistent_class); + G32 (12, key_os_version); + G16 (16, key_revision); + } +}; +*/ + + +#define APFS_MODIFIED_NAMELEN 32 +#define sizeof_apfs_modified_by_t (APFS_MODIFIED_NAMELEN + 16) + +struct apfs_modified_by_t +{ + Byte id[APFS_MODIFIED_NAMELEN]; + UInt64 timestamp; + xid_t last_xid; + + void Parse(const Byte *p) + { + memcpy(id, p, APFS_MODIFIED_NAMELEN); + p += APFS_MODIFIED_NAMELEN; + G64 (0, timestamp) + G64x (8, last_xid) + } +}; + + +#define APFS_MAX_HIST 8 +#define APFS_VOLNAME_LEN 256 + +struct CApfs +{ + // apfs_ + CPhys o; + // UInt32 magic; + UInt32 fs_index; // index of the object identifier for this volume's file system in the container's array of file systems. + // UInt64 features; + // UInt64 readonly_compatible_features; + UInt64 incompatible_features; + UInt64 unmount_time; + // UInt64 fs_reserve_block_count; + // UInt64 fs_quota_block_count; + UInt64 fs_alloc_count; + // wrapped_meta_crypto_state meta_crypto; + // UInt32 root_tree_type; + /* The type of the root file-system tree. + The value is typically OBJ_VIRTUAL | OBJECT_TYPE_BTREE, + with a subtype of OBJECT_TYPE_FSTREE */ + + // UInt32 extentref_tree_type; + // UInt32 snap_meta_tree_type; + oid_t omap_oid; + oid_t root_tree_oid; + /* + oid_t extentref_tree_oid; + oid_t snap_meta_tree_oid; + xid_t revert_to_xid; + oid_t revert_to_sblock_oid; + UInt64 next_obj_id; + */ + UInt64 num_files; + UInt64 num_directories; + UInt64 num_symlinks; + UInt64 num_other_fsobjects; + UInt64 num_snapshots; + UInt64 total_blocks_alloced; + UInt64 total_blocks_freed; + CUuid vol_uuid; + UInt64 last_mod_time; + UInt64 fs_flags; + apfs_modified_by_t formatted_by; + apfs_modified_by_t modified_by[APFS_MAX_HIST]; + Byte volname[APFS_VOLNAME_LEN]; + /* + UInt32 next_doc_id; + UInt16 role; // APFS_VOL_ROLE_NONE APFS_VOL_ROLE_SYSTEM .... + UInt16 reserved; + xid_t root_to_xid; + oid_t er_state_oid; + UInt64 cloneinfo_id_epoch; + UInt64 cloneinfo_xid; + oid_t snap_meta_ext_oid; + CUuid volume_group_id; + */ + oid_t integrity_meta_oid; // virtual object identifier of the integrity metadata object + oid_t fext_tree_oid; // virtual object identifier of the file extent tree. + UInt32 fext_tree_type; // The type of the file extent tree. + /* + UInt32 reserved_type; + oid_t reserved_oid; + */ + + UInt64 GetTotalItems() const + { + return num_files + num_directories + num_symlinks + num_other_fsobjects; + } + + bool IsHashedName() const + { + return + (incompatible_features & APFS_INCOMPAT_CASE_INSENSITIVE) != 0 || + (incompatible_features & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) != 0; + } + + bool Parse(const Byte *p, size_t size); +}; + + +bool CApfs::Parse(const Byte *p, size_t size) +{ + o.Parse(p); + if (Get32(p + 32) != 0x42535041) // { 'A', 'P', 'S', 'B' }; + return false; + if (o.GetType() != OBJECT_TYPE_FS) + return false; + if (!CheckFletcher64(p, size)) + return false; + // if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) return false; + + G32 (0x24, fs_index) + // G64 (0x28, features); + // G64 (0x30, readonly_compatible_features); + G64 (0x38, incompatible_features) + G64 (0x40, unmount_time) + // G64 (0x48, fs_reserve_block_count); + // G64 (0x50, fs_quota_block_count); + G64 (0x58, fs_alloc_count) + // meta_crypto.Parse(p + 0x60); + // G32 (0x74, root_tree_type); + // G32 (0x78, extentref_tree_type); + // G32 (0x7C, snap_meta_tree_type); + + G64o (0x80, omap_oid) + G64o (0x88, root_tree_oid) + /* + G64o (0x90, extentref_tree_oid); + G64o (0x98, snap_meta_tree_oid); + G64x (0xa0, revert_to_xid); + G64o (0xa8, revert_to_sblock_oid); + G64 (0xb0, next_obj_id); + */ + G64 (0xb8, num_files) + G64 (0xc0, num_directories) + G64 (0xc8, num_symlinks) + G64 (0xd0, num_other_fsobjects) + G64 (0xd8, num_snapshots) + G64 (0xe0, total_blocks_alloced) + G64 (0xe8, total_blocks_freed) + vol_uuid.SetFrom(p + 0xf0); + G64 (0x100, last_mod_time) + G64 (0x108, fs_flags) + p += 0x110; + formatted_by.Parse(p); + p += sizeof_apfs_modified_by_t; + for (unsigned i = 0; i < APFS_MAX_HIST; i++) + { + modified_by[i].Parse(p); + p += sizeof_apfs_modified_by_t; + } + memcpy(volname, p, APFS_VOLNAME_LEN); + p += APFS_VOLNAME_LEN; + /* + G32 (0, next_doc_id); + G16 (4, role); + G16 (6, reserved); + G64x (8, root_to_xid); + G64o (0x10, er_state_oid); + G64 (0x18, cloneinfo_id_epoch); + G64 (0x20, cloneinfo_xid); + G64o (0x28, snap_meta_ext_oid); + volume_group_id.SetFrom(p + 0x30); + */ + G64o (0x40, integrity_meta_oid) + G64o (0x48, fext_tree_oid) + G32 (0x50, fext_tree_type) + /* + G32 (0x54, reserved_type); + G64o (0x58, reserved_oid); + */ + return true; +} + + +#define OBJ_ID_MASK 0x0fffffffffffffff +/* +#define OBJ_TYPE_MASK 0xf000000000000000 +#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000 +*/ +#define OBJ_TYPE_SHIFT 60 + +typedef enum +{ + APFS_TYPE_ANY = 0, + APFS_TYPE_SNAP_METADATA = 1, + APFS_TYPE_EXTENT = 2, + APFS_TYPE_INODE = 3, + APFS_TYPE_XATTR = 4, + APFS_TYPE_SIBLING_LINK = 5, + APFS_TYPE_DSTREAM_ID = 6, + APFS_TYPE_CRYPTO_STATE = 7, + APFS_TYPE_FILE_EXTENT = 8, + APFS_TYPE_DIR_REC = 9, + APFS_TYPE_DIR_STATS = 10, + APFS_TYPE_SNAP_NAME = 11, + APFS_TYPE_SIBLING_MAP = 12, + APFS_TYPE_FILE_INFO = 13, + APFS_TYPE_MAX_VALID = 13, + APFS_TYPE_MAX = 15, + APFS_TYPE_INVALID = 15 +} j_obj_types; + + +struct j_key_t +{ + UInt64 obj_id_and_type; + + void Parse(const Byte *p) { G64(0, obj_id_and_type) } + unsigned GetType() const { return (unsigned)(obj_id_and_type >> OBJ_TYPE_SHIFT); } + UInt64 GetID() const { return obj_id_and_type & OBJ_ID_MASK; } +}; + + + +#define J_DREC_LEN_MASK 0x000003ff +/* +#define J_DREC_HASH_MASK 0xfffff400 +#define J_DREC_HASH_SHIFT 10 +*/ + +static const unsigned k_SizeOf_j_drec_val = 0x12; + +struct j_drec_val +{ + UInt64 file_id; + UInt64 date_added; /* The time that this directory entry was added to the directory. + It's not updated when modifying the directory entry for example, + by renaming a file without moving it to a different directory. */ + UInt16 flags; + + // bool IsFlags_File() const { return flags == MY_LIN_DT_REG; } + bool IsFlags_Unknown() const { return flags == MY_LIN_DT_UNKNOWN; } + bool IsFlags_Dir() const { return flags == MY_LIN_DT_DIR; } + + // uint8_t xfields[]; + void Parse(const Byte *p) + { + G64 (0, file_id) + G64 (8, date_added) + G16 (0x10, flags) + } +}; + + +struct CItem +{ + // j_key_t hdr; + UInt64 ParentId; + AString Name; + j_drec_val Val; + + unsigned ParentItemIndex; + unsigned RefIndex; + // unsigned iNode_Index; + + void Clear() + { + Name.Empty(); + ParentItemIndex = VI_MINUS1; + RefIndex = VI_MINUS1; + } +}; + + +/* +#define INVALID_INO_NUM 0 +#define ROOT_DIR_PARENT 1 // parent for "root" and "private-dir", there's no inode on disk with this inode number. +*/ +#define ROOT_DIR_INO_NUM 2 // "root" - parent for all main files +#define PRIV_DIR_INO_NUM 3 // "private-dir" +/* +#define SNAP_DIR_INO_NUM 6 // the directory where snapshot metadata is stored. Snapshot inodes are stored in the snapshot metedata tree. +#define PURGEABLE_DIR_INO_NUM 7 +#define MIN_USER_INO_NUM 16 + +#define UNIFIED_ID_SPACE_MARK 0x0800000000000000 +*/ + +//typedef enum +// { +/* +INODE_IS_APFS_PRIVATE = 0x00000001, +INODE_MAINTAIN_DIR_STATS = 0x00000002, +INODE_DIR_STATS_ORIGIN = 0x00000004, +INODE_PROT_CLASS_EXPLICIT = 0x00000008, +INODE_WAS_CLONED = 0x00000010, +INODE_FLAG_UNUSED = 0x00000020, +INODE_HAS_SECURITY_EA = 0x00000040, +INODE_BEING_TRUNCATED = 0x00000080, +INODE_HAS_FINDER_INFO = 0x00000100, +INODE_IS_SPARSE = 0x00000200, +INODE_WAS_EVER_CLONED = 0x00000400, +INODE_ACTIVE_FILE_TRIMMED = 0x00000800, +INODE_PINNED_TO_MAIN = 0x00001000, +INODE_PINNED_TO_TIER2 = 0x00002000, +*/ +// INODE_HAS_RSRC_FORK = 0x00004000, +/* +INODE_NO_RSRC_FORK = 0x00008000, +INODE_ALLOCATION_SPILLEDOVER = 0x00010000, +INODE_FAST_PROMOTE = 0x00020000, +*/ +#define INODE_HAS_UNCOMPRESSED_SIZE 0x00040000 +/* +INODE_IS_PURGEABLE = 0x00080000, +INODE_WANTS_TO_BE_PURGEABLE = 0x00100000, +INODE_IS_SYNC_ROOT = 0x00200000, +INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000, + + +INODE_INHERITED_INTERNAL_FLAGS = \ + ( INODE_MAINTAIN_DIR_STATS \ + | INODE_SNAPSHOT_COW_EXEMPTION), + +INODE_CLONED_INTERNAL_FLAGS = \ + ( INODE_HAS_RSRC_FORK \ + | INODE_NO_RSRC_FORK \ + | INODE_HAS_FINDER_INFO \ + | INODE_SNAPSHOT_COW_EXEMPTION), +*/ +// } +// j_inode_flags; + + +/* +#define APFS_VALID_INTERNAL_INODE_FLAGS \ +( INODE_IS_APFS_PRIVATE \ +| INODE_MAINTAIN_DIR_STATS \ +| INODE_DIR_STATS_ORIGIN \ +| INODE_PROT_CLASS_EXPLICIT \ +| INODE_WAS_CLONED \ +| INODE_HAS_SECURITY_EA \ +| INODE_BEING_TRUNCATED \ +| INODE_HAS_FINDER_INFO \ +| INODE_IS_SPARSE \ +| INODE_WAS_EVER_CLONED \ +| INODE_ACTIVE_FILE_TRIMMED \ +| INODE_PINNED_TO_MAIN \ +| INODE_PINNED_TO_TIER2 \ +| INODE_HAS_RSRC_FORK \ +| INODE_NO_RSRC_FORK \ +| INODE_ALLOCATION_SPILLEDOVER \ +| INODE_FAST_PROMOTE \ +| INODE_HAS_UNCOMPRESSED_SIZE \ +| INODE_IS_PURGEABLE \ +| INODE_WANTS_TO_BE_PURGEABLE \ +| INODE_IS_SYNC_ROOT \ +| INODE_SNAPSHOT_COW_EXEMPTION) + +#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2) +*/ + +static const char * const g_INODE_Flags[] = +{ + "IS_APFS_PRIVATE" + , "MAINTAIN_DIR_STATS" + , "DIR_STATS_ORIGIN" + , "PROT_CLASS_EXPLICIT" + , "WAS_CLONED" + , "FLAG_UNUSED" + , "HAS_SECURITY_EA" + , "BEING_TRUNCATED" + , "HAS_FINDER_INFO" + , "IS_SPARSE" + , "WAS_EVER_CLONED" + , "ACTIVE_FILE_TRIMMED" + , "PINNED_TO_MAIN" + , "PINNED_TO_TIER2" + , "HAS_RSRC_FORK" + , "NO_RSRC_FORK" + , "ALLOCATION_SPILLEDOVER" + , "FAST_PROMOTE" + , "HAS_UNCOMPRESSED_SIZE" + , "IS_PURGEABLE" + , "WANTS_TO_BE_PURGEABLE" + , "IS_SYNC_ROOT" + , "SNAPSHOT_COW_EXEMPTION" +}; + + +// bsd stat.h +/* +#define MY_UF_SETTABLE 0x0000ffff // mask of owner changeable flags +#define MY_UF_NODUMP 0x00000001 // do not dump file +#define MY_UF_IMMUTABLE 0x00000002 // file may not be changed +#define MY_UF_APPEND 0x00000004 // writes to file may only append +#define MY_UF_OPAQUE 0x00000008 // directory is opaque wrt. union +#define MY_UF_NOUNLINK 0x00000010 // file entry may not be removed or renamed Not implement in MacOS +#define MY_UF_COMPRESSED 0x00000020 // file entry is compressed +#define MY_UF_TRACKED 0x00000040 // notify about file entry changes +#define MY_UF_DATAVAULT 0x00000080 // entitlement required for reading and writing +#define MY_UF_HIDDEN 0x00008000 // file entry is hidden + +#define MY_SF_SETTABLE 0xffff0000 // mask of superuser changeable flags +#define MY_SF_ARCHIVED 0x00010000 // file is archived +#define MY_SF_IMMUTABLE 0x00020000 // file may not be changed +#define MY_SF_APPEND 0x00040000 // writes to file may only append +#define MY_SF_RESTRICTED 0x00080000 // entitlement required for writing +#define MY_SF_NOUNLINK 0x00100000 // file entry may not be removed, renamed or used as mount point +#define MY_SF_SNAPSHOT 0x00200000 // snapshot inode +Not implement in MacOS +*/ + +static const char * const g_INODE_BSD_Flags[] = +{ + "UF_NODUMP" + , "UF_IMMUTABLE" + , "UF_APPEND" + , "UF_OPAQUE" + , "UF_NOUNLINK" + , "UF_COMPRESSED" + , "UF_TRACKED" + , "UF_DATAVAULT" + , NULL, NULL, NULL, NULL + , NULL, NULL, NULL + , "UF_HIDDEN" + + , "SF_ARCHIVE" + , "SF_IMMUTABLE" + , "SF_APPEND" + , "SF_RESTRICTED" + , "SF_NOUNLINK" + , "SF_SNAPSHOT" +}; + +/* +#define INO_EXT_TYPE_SNAP_XID 1 +#define INO_EXT_TYPE_DELTA_TREE_OID 2 +#define INO_EXT_TYPE_DOCUMENT_ID 3 +*/ +#define INO_EXT_TYPE_NAME 4 +/* +#define INO_EXT_TYPE_PREV_FSIZE 5 +#define INO_EXT_TYPE_RESERVED_6 6 +#define INO_EXT_TYPE_FINDER_INFO 7 +*/ +#define INO_EXT_TYPE_DSTREAM 8 +/* +#define INO_EXT_TYPE_RESERVED_9 9 +#define INO_EXT_TYPE_DIR_STATS_KEY 10 +#define INO_EXT_TYPE_FS_UUID 11 +#define INO_EXT_TYPE_RESERVED_12 12 +#define INO_EXT_TYPE_SPARSE_BYTES 13 +#define INO_EXT_TYPE_RDEV 14 +#define INO_EXT_TYPE_PURGEABLE_FLAGS 15 +#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16 +*/ + + +static const unsigned k_SizeOf_j_dstream = 8 * 5; + +struct j_dstream +{ + UInt64 size; + UInt64 alloced_size; + UInt64 default_crypto_id; + UInt64 total_bytes_written; + UInt64 total_bytes_read; + + void Parse(const Byte *p) + { + G64 (0, size) + G64 (0x8, alloced_size) + G64 (0x10, default_crypto_id) + G64 (0x18, total_bytes_written) + G64 (0x20, total_bytes_read) + } +}; + +static const unsigned k_SizeOf_j_file_extent_val = 8 * 3; + +#define J_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffU +// #define J_FILE_EXTENT_FLAG_MASK 0xff00000000000000U +// #define J_FILE_EXTENT_FLAG_SHIFT 56 + +#define EXTENT_GET_LEN(x) ((x) & J_FILE_EXTENT_LEN_MASK) + +struct j_file_extent_val +{ + UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t. + // There are currently no flags defined + UInt64 phys_block_num; // The physical block address that the extent starts at + // UInt64 crypto_id; // The encryption key or the encryption tweak used in this extent. + + void Parse(const Byte *p) + { + G64 (0, len_and_flags) + G64 (0x8, phys_block_num) + // G64 (0x10, crypto_id); + } +}; + + +struct CExtent +{ + UInt64 logical_offset; + UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t. + // There are currently no flags defined + UInt64 phys_block_num; // The physical block address that the extent starts at + + UInt64 GetEndOffset() const { return logical_offset + EXTENT_GET_LEN(len_and_flags); } +}; + + +typedef UInt32 MY_uid_t; +typedef UInt32 MY_gid_t; +typedef UInt16 MY_mode_t; + + +typedef enum +{ + XATTR_DATA_STREAM = 1 << 0, + XATTR_DATA_EMBEDDED = 1 << 1, + XATTR_FILE_SYSTEM_OWNED = 1 << 2, + XATTR_RESERVED_8 = 1 << 3 +} j_xattr_flags; + + +struct CAttr +{ + AString Name; + UInt32 flags; + bool dstream_defined; + bool NeedShow; + CByteBuffer Data; + + j_dstream dstream; + UInt64 Id; + + bool Is_dstream_OK_for_SymLink() const + { + return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0; + } + + UInt64 GetSize() const + { + if (dstream_defined) // dstream has more priority + return dstream.size; + return Data.Size(); + } + + void Clear() + { + dstream_defined = false; + NeedShow = true; + Data.Free(); + Name.Empty(); + } + + bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; } + bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; } +}; + + +// j_inode_val_t +struct CNode +{ + unsigned ItemIndex; // index to CItem. We set it only if Node is directory. + unsigned NumCalcedLinks; // Num links to that node + // unsigned NumItems; // Num Items in that node + + UInt64 parent_id; // The identifier of the file system record for the parent directory. + UInt64 private_id; + UInt64 create_time; + UInt64 mod_time; + UInt64 change_time; + UInt64 access_time; + UInt64 internal_flags; + union + { + UInt32 nchildren; /* The number of directory entries. + is valid only if the inode is a directory */ + UInt32 nlink; /* The number of hard links whose target is this inode. + is valid only if the inode isn't a directory. + Inodes with multiple hard links (nlink > 1) + - The parent_id field refers to the parent directory of the primary link. + - The name field contains the name of the primary link. + - The INO_EXT_TYPE_NAME extended field contains the name of this link. + */ + }; + // cp_key_class_t default_protection_class; + UInt32 write_generation_counter; + UInt32 bsd_flags; + MY_uid_t owner; + MY_gid_t group; + MY_mode_t mode; + UInt16 pad1; + UInt64 uncompressed_size; + + j_dstream dstream; + AString PrimaryName; + + bool dstream_defined; + bool refcnt_defined; + + UInt32 refcnt; // j_dstream_id_val_t + CRecordVector Extents; + CObjectVector Attrs; + unsigned SymLinkIndex; // index in Attrs + unsigned DecmpfsIndex; // index in Attrs + unsigned ResourceIndex; // index in Attrs + + NHfs::CCompressHeader CompressHeader; + + CNode(): + ItemIndex(VI_MINUS1), + NumCalcedLinks(0), + // NumItems(0), + dstream_defined(false), + refcnt_defined(false), + SymLinkIndex(VI_MINUS1), + DecmpfsIndex(VI_MINUS1), + ResourceIndex(VI_MINUS1) + {} + + bool IsDir() const { return MY_LIN_S_ISDIR(mode); } + bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); } + + bool Has_UNCOMPRESSED_SIZE() const { return (internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) != 0; } + + unsigned Get_Type_From_mode() const { return mode >> 12; } + + bool GetSize(unsigned attrIndex, UInt64 &size) const + { + if (IsViNotDef(attrIndex)) + { + if (dstream_defined) + { + size = dstream.size; + return true; + } + size = 0; + if (Has_UNCOMPRESSED_SIZE()) + { + size = uncompressed_size; + return true; + } + if (!IsSymLink()) + return false; + attrIndex = SymLinkIndex; + if (IsViNotDef(attrIndex)) + return false; + } + const CAttr &attr = Attrs[(unsigned)attrIndex]; + if (attr.dstream_defined) + size = attr.dstream.size; + else + size = attr.Data.Size(); + return true; + } + + bool GetPackSize(unsigned attrIndex, UInt64 &size) const + { + if (IsViNotDef(attrIndex)) + { + if (dstream_defined) + { + size = dstream.alloced_size; + return true; + } + size = 0; + + if (IsSymLink()) + attrIndex = SymLinkIndex; + else + { + if (!CompressHeader.IsCorrect || + !CompressHeader.IsSupported) + return false; + const CAttr &attr = Attrs[DecmpfsIndex]; + if (!CompressHeader.IsMethod_Resource()) + { + size = attr.Data.Size() - CompressHeader.DataPos; + return true; + } + attrIndex = ResourceIndex; + } + if (IsViNotDef(attrIndex)) + return false; + } + const CAttr &attr = Attrs[(unsigned)attrIndex]; + if (attr.dstream_defined) + size = attr.dstream.alloced_size; + else + size = attr.Data.Size(); + return true; + } + + void Parse(const Byte *p); +}; + + +// it's used for Attr streams +struct CSmallNode +{ + CRecordVector Extents; + // UInt32 NumLinks; + // CSmallNode(): NumLinks(0) {} +}; + +static const unsigned k_SizeOf_j_inode_val = 0x5c; + +void CNode::Parse(const Byte *p) +{ + G64 (0, parent_id) + G64 (0x8, private_id) + G64 (0x10, create_time) + G64 (0x18, mod_time) + G64 (0x20, change_time) + G64 (0x28, access_time) + G64 (0x30, internal_flags) + { + G32 (0x38, nchildren) + // G32 (0x38, nlink); + } + // G32 (0x3c, default_protection_class); + G32 (0x40, write_generation_counter) + G32 (0x44, bsd_flags) + G32 (0x48, owner) + G32 (0x4c, group) + G16 (0x50, mode) + // G16 (0x52, pad1); + G64 (0x54, uncompressed_size) +} + + +struct CRef +{ + unsigned ItemIndex; + unsigned NodeIndex; + unsigned ParentRefIndex; + + #ifdef APFS_SHOW_ALT_STREAMS + unsigned AttrIndex; + bool IsAltStream() const { return IsViDef(AttrIndex); } + unsigned GetAttrIndex() const { return AttrIndex; } + #else + // bool IsAltStream() const { return false; } + unsigned GetAttrIndex() const { return VI_MINUS1; } + #endif +}; + + +struct CRef2 +{ + unsigned VolIndex; + unsigned RefIndex; +}; + + +struct CHashChunk +{ + UInt64 lba; + UInt32 hashed_len; // the value is UInt16 + Byte hash[APFS_HASH_MAX_SIZE]; +}; + +typedef CRecordVector CStreamHashes; + + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithHash + , ISequentialOutStream +) + bool _hashError; + CAlignedBuffer1 _sha; + CMyComPtr _stream; + const CStreamHashes *_hashes; + unsigned _blockSizeLog; + unsigned _chunkIndex; + UInt32 _offsetInChunk; + // UInt64 _size; + + CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; } +public: + COutStreamWithHash(): _sha(sizeof(CSha256)) {} + + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + // void ReleaseStream() { _stream.Release(); } + void Init(const CStreamHashes *hashes, unsigned blockSizeLog) + { + _hashes = hashes; + _blockSizeLog = blockSizeLog; + _chunkIndex = 0; + _offsetInChunk = 0; + _hashError = false; + // _size = 0; + } + // UInt64 GetSize() const { return _size; } + bool FinalCheck(); +}; + + +static bool Sha256_Final_and_CheckDigest(CSha256 *sha256, const Byte *digest) +{ + MY_ALIGN (16) + UInt32 temp[SHA256_NUM_DIGEST_WORDS]; + Sha256_Final(sha256, (Byte *)temp); + return memcmp(temp, digest, SHA256_DIGEST_SIZE) == 0; +} + + +Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (processedSize) + *processedSize = size; + while (size != 0) + { + if (_hashError) + break; + if (_chunkIndex >= _hashes->Size()) + { + _hashError = true; + break; + } + if (_offsetInChunk == 0) + Sha256_Init(Sha()); + const CHashChunk &chunk = (*_hashes)[_chunkIndex]; + /* (_blockSizeLog <= 16) && chunk.hashed_len is 16-bit. + so we can use 32-bit chunkSize here */ + const UInt32 chunkSize = ((UInt32)chunk.hashed_len << _blockSizeLog); + const UInt32 rem = chunkSize - _offsetInChunk; + UInt32 cur = size; + if (cur > rem) + cur = (UInt32)rem; + Sha256_Update(Sha(), (const Byte *)data, cur); + data = (const void *)((const Byte *)data + cur); + size -= cur; + // _size += cur; + _offsetInChunk += cur; + if (chunkSize == _offsetInChunk) + { + if (!Sha256_Final_and_CheckDigest(Sha(), chunk.hash)) + _hashError = true; + _offsetInChunk = 0; + _chunkIndex++; + } + } + return result; +} + + +bool COutStreamWithHash::FinalCheck() +{ + if (_hashError) + return false; + + if (_offsetInChunk != 0) + { + const CHashChunk &chunk = (*_hashes)[_chunkIndex]; + { + const UInt32 chunkSize = ((UInt32)chunk.hashed_len << _blockSizeLog); + const UInt32 rem = chunkSize - _offsetInChunk; + Byte b = 0; + for (UInt32 i = 0; i < rem; i++) + Sha256_Update(Sha(), &b, 1); + } + if (!Sha256_Final_and_CheckDigest(Sha(), chunk.hash)) + _hashError = true; + _offsetInChunk = 0; + _chunkIndex++; + } + if (_chunkIndex != _hashes->Size()) + _hashError = true; + return !_hashError; +} + + + +struct CVol +{ + CObjectVector Nodes; + CRecordVector NodeIDs; + CObjectVector Items; + CRecordVector Refs; + + CObjectVector SmallNodes; + CRecordVector SmallNodeIDs; + + CObjectVector FEXT_Nodes; + CRecordVector FEXT_NodeIDs; + + CObjectVector Hash_Vectors; + CRecordVector Hash_IDs; + + unsigned StartRef2Index; // ref2_Index for Refs[0] item + unsigned RootRef2Index; // ref2_Index of virtual root folder (Volume1) + CApfs apfs; + C_integrity_meta_phys integrity; + + bool NodeNotFound; + bool ThereAreUnlinkedNodes; + bool WrongInodeLink; + bool UnsupportedFeature; + bool UnsupportedMethod; + + unsigned NumItems_In_PrivateDir; + unsigned NumAltStreams; + + UString RootName; + + bool ThereAreErrors() const + { + return NodeNotFound || ThereAreUnlinkedNodes || WrongInodeLink; + } + + void AddComment(UString &s) const; + + HRESULT FillRefs(); + + CVol(): + StartRef2Index(0), + RootRef2Index(VI_MINUS1), + NodeNotFound(false), + ThereAreUnlinkedNodes(false), + WrongInodeLink(false), + UnsupportedFeature(false), + UnsupportedMethod(false), + NumItems_In_PrivateDir(0), + NumAltStreams(0) + {} +}; + + +static void ApfsTimeToFileTime(UInt64 apfsTime, FILETIME &ft, UInt32 &ns100) +{ + const UInt64 s = apfsTime / 1000000000; + const UInt32 ns = (UInt32)(apfsTime % 1000000000); + ns100 = (ns % 100); + const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64((Int64)s) + ns / 100; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +static void AddComment_Name(UString &s, const char *name) +{ + s += name; + s += ": "; +} + +/* +static void AddComment_Bool(UString &s, const char *name, bool val) +{ + AddComment_Name(s, name); + s += val ? "+" : "-"; + s.Add_LF(); +} +*/ + +static void AddComment_UInt64(UString &s, const char *name, UInt64 v) +{ + AddComment_Name(s, name); + s.Add_UInt64(v); + s.Add_LF(); +} + + +static void AddComment_Time(UString &s, const char *name, UInt64 v) +{ + AddComment_Name(s, name); + + FILETIME ft; + UInt32 ns100; + ApfsTimeToFileTime(v, ft, ns100); + char temp[64]; + ConvertUtcFileTimeToString2(ft, ns100, temp + // , kTimestampPrintLevel_SEC); + , kTimestampPrintLevel_NS); + s += temp; + s.Add_LF(); +} + + +static void AddComment_modified_by_t(UString &s, const char *name, const apfs_modified_by_t &v) +{ + AddComment_Name(s, name); + AString s2; + s2.SetFrom_CalcLen((const char *)v.id, sizeof(v.id)); + s += s2; + s.Add_LF(); + s += " "; + AddComment_Time(s, "timestamp", v.timestamp); + s += " "; + AddComment_UInt64(s, "last_xid", v.last_xid); +} + + +static void AddVolInternalName_toString(UString &s, const CApfs &apfs) +{ + AString temp; + temp.SetFrom_CalcLen((const char *)apfs.volname, sizeof(apfs.volname)); + UString unicode; + ConvertUTF8ToUnicode(temp, unicode); + s += unicode; +} + + +void CVol::AddComment(UString &s) const +{ + AddComment_UInt64(s, "fs_index", apfs.fs_index); + { + AddComment_Name(s, "volume_name"); + AddVolInternalName_toString(s, apfs); + s.Add_LF(); + } + AddComment_Name(s, "vol_uuid"); + apfs.vol_uuid.AddHexToString(s); + s.Add_LF(); + + AddComment_Name(s, "incompatible_features"); + s += FlagsToString(g_APFS_INCOMPAT_Flags, + Z7_ARRAY_SIZE(g_APFS_INCOMPAT_Flags), + (UInt32)apfs.incompatible_features); + s.Add_LF(); + + + if (apfs.integrity_meta_oid != 0) + { + /* + AddComment_Name(s, "im_version"); + s.Add_UInt32(integrity.im_version); + s.Add_LF(); + */ + AddComment_Name(s, "im_flags"); + s.Add_UInt32(integrity.im_flags); + s.Add_LF(); + AddComment_Name(s, "im_hash_type"); + const char *p = NULL; + if (integrity.im_hash_type < Z7_ARRAY_SIZE(g_hash_types)) + p = g_hash_types[integrity.im_hash_type]; + if (p) + s += p; + else + s.Add_UInt32(integrity.im_hash_type); + s.Add_LF(); + } + + + // AddComment_UInt64(s, "reserve_block_count", apfs.fs_reserve_block_count, false); + // AddComment_UInt64(s, "quota_block_count", apfs.fs_quota_block_count); + AddComment_UInt64(s, "fs_alloc_count", apfs.fs_alloc_count); + + AddComment_UInt64(s, "num_files", apfs.num_files); + AddComment_UInt64(s, "num_directories", apfs.num_directories); + AddComment_UInt64(s, "num_symlinks", apfs.num_symlinks); + AddComment_UInt64(s, "num_other_fsobjects", apfs.num_other_fsobjects); + + AddComment_UInt64(s, "Num_Attr_Streams", NumAltStreams); + + AddComment_UInt64(s, "num_snapshots", apfs.num_snapshots); + AddComment_UInt64(s, "total_blocks_alloced", apfs.total_blocks_alloced); + AddComment_UInt64(s, "total_blocks_freed", apfs.total_blocks_freed); + + AddComment_Time(s, "unmounted", apfs.unmount_time); + AddComment_Time(s, "last_modified", apfs.last_mod_time); + AddComment_modified_by_t(s, "formatted_by", apfs.formatted_by); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(apfs.modified_by); i++) + { + const apfs_modified_by_t &v = apfs.modified_by[i]; + if (v.last_xid == 0 && v.timestamp == 0 && v.id[0] == 0) + continue; + AString name ("modified_by["); + name.Add_UInt32(i); + name += ']'; + AddComment_modified_by_t(s, name.Ptr(), v); + } +} + + + +struct CKeyValPair +{ + CByteBuffer Key; + CByteBuffer Val; + // unsigned ValPos; // for alognment +}; + + +struct omap_key +{ + oid_t oid; // The object identifier + xid_t xid; // The transaction identifier + void Parse(const Byte *p) + { + G64o (0, oid) + G64x (8, xid) + } +}; + +/* +#define OMAP_VAL_DELETED (1 << 0) +#define OMAP_VAL_SAVED (1 << 1) +#define OMAP_VAL_ENCRYPTED (1 << 2) +*/ +#define OMAP_VAL_NOHEADER (1 << 3) +/* +#define OMAP_VAL_CRYPTO_GENERATION (1 << 4) +*/ + +struct omap_val +{ + UInt32 flags; + UInt32 size; + // paddr_t paddr; + paddr_t_unsigned paddr; + + bool IsFlag_NoHeader() const { return (flags & OMAP_VAL_NOHEADER) != 0; } + + void Parse(const Byte *p) + { + G32 (0, flags) + G32 (4, size) + G64 (8, paddr) + } +}; + + +struct CObjectMap +{ + CRecordVector Keys; + CRecordVector Vals; + + bool Parse(const CObjectVector &pairs); + int FindKey(UInt64 id) const { return Keys.FindInSorted(id); } +}; + +bool CObjectMap::Parse(const CObjectVector &pairs) +{ + omap_key prev; + prev.oid = 0; + prev.xid = 0; + FOR_VECTOR (i, pairs) + { + const CKeyValPair &pair = pairs[i]; + if (pair.Key.Size() != 16 || pair.Val.Size() != 16) + return false; + omap_key key; + key.Parse(pair.Key); + omap_val val; + val.Parse(pair.Val); + /* Object map B-trees are sorted by object identifier and then by transaction identifier + but it's possible to have identical Ids in map ? + do we need to look transaction id ? + and search key with largest transaction id? */ + if (key.oid <= prev.oid) + return false; + prev = key; + Keys.Add(key.oid); + Vals.Add(val); + } + return true; +} + + +struct CMap +{ + CObjectVector Pairs; + + CObjectMap Omap; + btree_info bti; + UInt64 NumNodes; + + // we use thnese options to check: + UInt32 Subtype; + bool IsPhysical; + + bool CheckAtFinish() const + { + return NumNodes == bti.node_count && Pairs.Size() == bti.key_count; + } + + CMap(): + NumNodes(0), + Subtype(0), + IsPhysical(true) + {} +}; + + + +struct CDatabase +{ + CRecordVector Refs2; + CObjectVector Vols; + + bool HeadersError; + bool ThereAreAltStreams; + bool UnsupportedFeature; + bool UnsupportedMethod; + + CSuperBlock sb; + + IInStream *OpenInStream; + IArchiveOpenCallback *OpenCallback; + UInt64 ProgressVal_Cur; + UInt64 ProgressVal_Prev; + UInt64 ProgressVal_NumFilesTotal; + CObjectVector Buffers; + + UInt32 MethodsMask; + UInt64 GetSize(const UInt32 index) const; + + void Clear() + { + HeadersError = false; + ThereAreAltStreams = false; + UnsupportedFeature = false; + UnsupportedMethod = false; + + ProgressVal_Cur = 0; + ProgressVal_Prev = 0; + ProgressVal_NumFilesTotal = 0; + + MethodsMask = 0; + + Vols.Clear(); + Refs2.Clear(); + Buffers.Clear(); + } + + HRESULT SeekReadBlock_FALSE(UInt64 oid, void *data); + void GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const; + HRESULT ReadMap(UInt64 oid, bool noHeader, CVol *vol, const Byte *hash, + CMap &map, unsigned recurseLevel); + HRESULT ReadObjectMap(UInt64 oid, CVol *vol, CObjectMap &map); + HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid); + HRESULT Open2(); + + HRESULT GetAttrStream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream); + + HRESULT GetAttrStream_dstream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream); + + HRESULT GetStream2( + IInStream *apfsInStream, + const CRecordVector *extents, UInt64 rem, + ISequentialInStream **stream); +}; + + +HRESULT CDatabase::SeekReadBlock_FALSE(UInt64 oid, void *data) +{ + if (OpenCallback) + { + if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) + { + RINOK(OpenCallback->SetCompleted(NULL, &ProgressVal_Cur)) + ProgressVal_Prev = ProgressVal_Cur; + } + ProgressVal_Cur += sb.block_size; + } + if (oid == 0 || oid >= sb.block_count) + return S_FALSE; + RINOK(InStream_SeekSet(OpenInStream, oid << sb.block_size_Log)) + return ReadStream_FALSE(OpenInStream, data, sb.block_size); +} + + + +API_FUNC_static_IsArc IsArc_APFS(const Byte *p, size_t size) +{ + if (size < kApfsHeaderSize) + return k_IsArc_Res_NEED_MORE; + CSuperBlock sb; + if (!sb.Parse(p)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + + +static bool CheckHash(unsigned hashAlgo, const Byte *data, size_t size, const Byte *digest) +{ + if (hashAlgo == APFS_HASH_SHA256) + { + MY_ALIGN (16) + CSha256 sha; + Sha256_Init(&sha); + Sha256_Update(&sha, data, size); + return Sha256_Final_and_CheckDigest(&sha, digest); + } + return true; +} + + +HRESULT CDatabase::ReadMap(UInt64 oid, bool noHeader, + CVol *vol, const Byte *hash, + CMap &map, unsigned recurseLevel) +{ + // is it allowed to use big number of levels ? + if (recurseLevel > (1 << 10)) + return S_FALSE; + + const UInt32 blockSize = sb.block_size; + if (Buffers.Size() <= recurseLevel) + { + Buffers.AddNew(); + if (Buffers.Size() <= recurseLevel) + throw 123; + Buffers.Back().Alloc(blockSize); + } + const Byte *buf; + { + CByteBuffer &buf2 = Buffers[recurseLevel]; + RINOK(SeekReadBlock_FALSE(oid, buf2)) + buf = buf2; + } + + if (hash && vol) + if (!CheckHash(vol->integrity.im_hash_type, buf, blockSize, hash)) + return S_FALSE; + + CBTreeNodePhys bt; + if (!bt.Parse(buf, blockSize, noHeader)) + return S_FALSE; + + map.NumNodes++; + + /* Specification: All values are stored in leaf nodes, which + makes these B+ trees, and the values in nonleaf nodes are object + identifiers of child nodes. + + The entries in the table of contents are sorted by key. The comparison function used for sorting depends on the keys type + - Object map B-trees are sorted by object identifier and then by transaction identifier. + - Free queue B-trees are sorted by transaction identifier and then by physical address. + - File-system records are sorted according to the rules listed in File-System Objects. + */ + + if (!noHeader) + if (bt.ophys.subtype != map.Subtype) + return S_FALSE; + + unsigned endLimit = blockSize; + + if (recurseLevel == 0) + { + if (!noHeader) + if (bt.ophys.GetType() != OBJECT_TYPE_BTREE) + return S_FALSE; + if ((bt.flags & BTNODE_ROOT) == 0) + return S_FALSE; + endLimit -= k_btree_info_Size; + map.bti.Parse(buf + endLimit); + btree_info &bti = map.bti; + if (bti.fixed.key_size >= blockSize) + return S_FALSE; + if (bti.Is_EPHEMERAL() && + bti.Is_PHYSICAL()) + return S_FALSE; + if (bti.Is_PHYSICAL() != map.IsPhysical) + return S_FALSE; + if (bti.Is_NOHEADER() != noHeader) + return S_FALSE; + // we don't allow volumes with big number of Keys + const unsigned kNumItemsMax = k_VectorSizeMax; + if (map.bti.node_count > kNumItemsMax) + return S_FALSE; + if (map.bti.key_count > kNumItemsMax) + return S_FALSE; + } + else + { + if (!noHeader) + if (bt.ophys.GetType() != OBJECT_TYPE_BTREE_NODE) + return S_FALSE; + if ((bt.flags & BTNODE_ROOT) != 0) + return S_FALSE; + if (map.NumNodes > map.bti.node_count + || map.Pairs.Size() > map.bti.key_count) + return S_FALSE; + } + + const bool isLeaf = (bt.flags & BTNODE_LEAF) != 0; + + if (isLeaf) + { + if (bt.level != 0) + return S_FALSE; + } + else + { + if (bt.level == 0) + return S_FALSE; + } + + if (!bt.table_space.CheckOverLimit(endLimit - k_Toc_offset)) + return S_FALSE; + + const unsigned tableEnd = k_Toc_offset + bt.table_space.GetEnd(); + const unsigned keyValRange = endLimit - tableEnd; + const unsigned tocEntrySize = bt.Is_FIXED_KV_SIZE() ? 4 : 8; + if (bt.table_space.len / tocEntrySize < bt.nkeys) + return S_FALSE; + + for (unsigned i = 0; i < bt.nkeys; i++) + { + const Byte *p = buf + k_Toc_offset + bt.table_space.off + i * tocEntrySize; + if (bt.Is_FIXED_KV_SIZE()) + { + kvoff a; + a.Parse(p); + if (a.k + map.bti.fixed.key_size > keyValRange + || a.v > keyValRange) + return S_FALSE; + { + CKeyValPair pair; + + const Byte *p2 = buf + k_Toc_offset + bt.table_space.len; + p2 += a.k; + pair.Key.CopyFrom(p2, map.bti.fixed.key_size); + + p2 = buf + endLimit; + p2 -= a.v; + if (isLeaf) + { + if (a.v < map.bti.fixed.val_size) + return S_FALSE; + pair.Val.CopyFrom(p2, map.bti.fixed.val_size); + // pair.ValPos = endLimit - a.v; + map.Pairs.Add(pair); + continue; + } + { + if (a.v < 8) + return S_FALSE; + // value is only 64-bit for non leaf. + const oid_t oidNext = Get64(p2); + if (map.bti.Is_PHYSICAL()) + { + RINOK(ReadMap(oidNext, noHeader, vol, + NULL, /* hash */ + map, recurseLevel + 1)) + continue; + } + else + { + // fixme + return S_FALSE; + } + } + } + } + else + { + kvloc a; + a.Parse(p); + if (!a.k.CheckOverLimit(keyValRange) + || a.v.off > keyValRange + || a.v.len > a.v.off) + return S_FALSE; + { + CKeyValPair pair; + const Byte *p2 = buf + k_Toc_offset + bt.table_space.len; + p2 += a.k.off; + pair.Key.CopyFrom(p2, a.k.len); + + p2 = buf + endLimit; + p2 -= a.v.off; + if (isLeaf) + { + pair.Val.CopyFrom(p2, a.v.len); + // pair.ValPos = endLimit - a.v.off; + map.Pairs.Add(pair); + continue; + } + { + if (a.v.len < 8) + return S_FALSE; + + const Byte *hashNew = NULL; + oid_t oidNext = Get64(p2); + + if (bt.Is_HASHED()) + { + if (!vol) + return S_FALSE; + /* + struct btn_index_node_val { + oid_t binv_child_oid; + uint8_t binv_child_hash[BTREE_NODE_HASH_SIZE_MAX]; + }; + */ + /* (a.v.len == 40) is possible if Is_HASHED() + so there is hash (for example, 256-bit) after 64-bit id) */ + if (a.v.len != 8 + vol->integrity.HashSize) + return S_FALSE; + hashNew = p2 + 8; + /* we need to add root_tree_oid here, + but where it's defined in apfs specification ? */ + oidNext += vol->apfs.root_tree_oid; + } + else + { + if (a.v.len != 8) + return S_FALSE; + } + + // value is only 64-bit for non leaf. + + if (map.bti.Is_PHYSICAL()) + { + return S_FALSE; + // the code was not tested: + // RINOK(ReadMap(oidNext, map, recurseLevel + 1)); + // continue; + } + /* + else if (map.bti.Is_EPHEMERAL()) + { + // Ephemeral objects are stored in memory while the container is mounted and in a checkpoint when the container isn't mounted + // the code was not tested: + return S_FALSE; + } + */ + else + { + /* nodes in the B-tree use virtual object identifiers to link to their child nodes. */ + const int index = map.Omap.FindKey(oidNext); + if (index == -1) + return S_FALSE; + const omap_val &ov = map.Omap.Vals[(unsigned)index]; + if (ov.size != blockSize) // change it : it must be multiple of + return S_FALSE; + RINOK(ReadMap(ov.paddr, ov.IsFlag_NoHeader(), vol, hashNew, + map, recurseLevel + 1)) + continue; + } + } + } + } + } + + if (recurseLevel == 0) + if (!map.CheckAtFinish()) + return S_FALSE; + return S_OK; +} + + + +HRESULT CDatabase::ReadObjectMap(UInt64 oid, CVol *vol, CObjectMap &omap) +{ + CByteBuffer buf; + const size_t blockSize = sb.block_size; + buf.Alloc(blockSize); + RINOK(SeekReadBlock_FALSE(oid, buf)) + C_omap_phys op; + if (!op.Parse(buf, blockSize, oid)) + return S_FALSE; + CMap map; + map.Subtype = OBJECT_TYPE_OMAP; + map.IsPhysical = true; + RINOK(ReadMap(op.tree_oid, + false /* noHeader */, + vol, + NULL, /* hash */ + map, 0)) + if (!omap.Parse(map.Pairs)) + return S_FALSE; + return S_OK; +} + + + +HRESULT CDatabase::Open2() +{ + Clear(); + CSuperBlock2 sb2; + { + Byte buf[kApfsHeaderSize]; + RINOK(ReadStream_FALSE(OpenInStream, buf, kApfsHeaderSize)) + if (!sb.Parse(buf)) + return S_FALSE; + sb2.Parse(buf); + } + + { + CObjectMap omap; + RINOK(ReadObjectMap(sb.omap_oid, + NULL, /* CVol */ + omap)) + unsigned numRefs = 0; + for (unsigned i = 0; i < sb.max_file_systems; i++) + { + const oid_t oid = sb2.fs_oid[i]; + if (oid == 0) + continue; + // for (unsigned k = 0; k < 1; k++) // for debug + RINOK(OpenVolume(omap, oid)) + const unsigned a = Vols.Back().Refs.Size(); + numRefs += a; + if (numRefs < a) + return S_FALSE; // overflow + } + } + + const bool needVolumePrefix = (Vols.Size() > 1); + // const bool needVolumePrefix = true; // for debug + { + unsigned numRefs = 0; + FOR_VECTOR (i, Vols) + { + const unsigned a = Vols[i].Refs.Size(); + numRefs += a; + if (numRefs < a) + return S_FALSE; // overflow + } + numRefs += Vols.Size(); + if (numRefs < Vols.Size()) + return S_FALSE; // overflow + Refs2.Reserve(numRefs); + } + { + FOR_VECTOR (i, Vols) + { + CVol &vol = Vols[i]; + + CRef2 ref2; + ref2.VolIndex = i; + + if (needVolumePrefix) + { + vol.RootName = "Volume"; + vol.RootName.Add_UInt32(1 + (UInt32)i); + vol.RootRef2Index = Refs2.Size(); + ref2.RefIndex = VI_MINUS1; + Refs2.Add(ref2); + } + + vol.StartRef2Index = Refs2.Size(); + const unsigned numItems = vol.Refs.Size(); + for (unsigned k = 0; k < numItems; k++) + { + ref2.RefIndex = k; + Refs2.Add(ref2); + } + } + } + return S_OK; +} + + +HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) +{ + const size_t blockSize = sb.block_size; + CByteBuffer buf; + { + const int index = omap.FindKey(fs_oid); + if (index == -1) + return S_FALSE; + const omap_val &ov = omap.Vals[(unsigned)index]; + if (ov.size != blockSize) // change it : it must be multiple of + return S_FALSE; + buf.Alloc(blockSize); + RINOK(SeekReadBlock_FALSE(ov.paddr, buf)) + } + + CVol &vol = Vols.AddNew(); + CApfs &apfs = vol.apfs; + + if (!apfs.Parse(buf, blockSize)) + return S_FALSE; + + if (apfs.fext_tree_oid != 0) + { + if ((apfs.incompatible_features & APFS_INCOMPAT_SEALED_VOLUME) == 0) + return S_FALSE; + if ((apfs.fext_tree_type & OBJ_PHYSICAL) == 0) + return S_FALSE; + if ((apfs.fext_tree_type & OBJECT_TYPE_MASK) != OBJECT_TYPE_BTREE) + return S_FALSE; + + CMap map2; + map2.Subtype = OBJECT_TYPE_FEXT_TREE; + map2.IsPhysical = true; + + RINOK(ReadMap(apfs.fext_tree_oid, + false /* noHeader */, + &vol, + NULL, /* hash */ + map2, 0)) + + UInt64 prevId = 1; + + FOR_VECTOR (i, map2.Pairs) + { + if (OpenCallback && (i & 0xffff) == 1) + { + const UInt64 numFiles = ProgressVal_NumFilesTotal + + (vol.Items.Size() + vol.Nodes.Size()) / 2; + RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur)) + } + // The key half of a record from a file extent tree. + // struct fext_tree_key + const CKeyValPair &pair = map2.Pairs[i]; + if (pair.Key.Size() != 16) + return S_FALSE; + const Byte *p = pair.Key; + const UInt64 id = GetUi64(p); + if (id < prevId) + return S_FALSE; // IDs must be sorted + prevId = id; + + CExtent ext; + ext.logical_offset = GetUi64(p + 8); + { + if (pair.Val.Size() != 16) + return S_FALSE; + const Byte *p2 = pair.Val; + ext.len_and_flags = GetUi64(p2); + ext.phys_block_num = GetUi64(p2 + 8); + } + + PRF(printf("\n%6d: id=%6d logical_addr = %2d len_and_flags=%5x phys_block_num = %5d", + i, (unsigned)id, + (unsigned)ext.logical_offset, + (unsigned)ext.len_and_flags, + (unsigned)ext.phys_block_num)); + + if (vol.FEXT_NodeIDs.IsEmpty() || + vol.FEXT_NodeIDs.Back() != id) + { + vol.FEXT_NodeIDs.Add(id); + vol.FEXT_Nodes.AddNew(); + } + CRecordVector &extents = vol.FEXT_Nodes.Back().Extents; + if (!extents.IsEmpty()) + if (ext.logical_offset != extents.Back().GetEndOffset()) + return S_FALSE; + extents.Add(ext); + continue; + } + + PRF(printf("\n\n")); + } + + /* For each volume, read the root file system tree's virtual object + identifier from the apfs_root_tree_oid field, + and then look it up in the volume object map indicated + by the omap_oid field. */ + + CMap map; + ReadObjectMap(apfs.omap_oid, &vol, map.Omap); + + const Byte *hash_for_root = NULL; + + if (apfs.integrity_meta_oid != 0) + { + if ((apfs.incompatible_features & APFS_INCOMPAT_SEALED_VOLUME) == 0) + return S_FALSE; + const int index = map.Omap.FindKey(apfs.integrity_meta_oid); + if (index == -1) + return S_FALSE; + const omap_val &ov = map.Omap.Vals[(unsigned)index]; + if (ov.size != blockSize) + return S_FALSE; + RINOK(SeekReadBlock_FALSE(ov.paddr, buf)) + if (!vol.integrity.Parse(buf, blockSize, apfs.integrity_meta_oid)) + return S_FALSE; + if (vol.integrity.im_hash_type != 0) + hash_for_root = vol.integrity.Hash; + } + + { + const int index = map.Omap.FindKey(apfs.root_tree_oid); + if (index == -1) + return S_FALSE; + const omap_val &ov = map.Omap.Vals[(unsigned)index]; + if (ov.size != blockSize) // change it : it must be multiple of + return S_FALSE; + map.Subtype = OBJECT_TYPE_FSTREE; + map.IsPhysical = false; + RINOK(ReadMap(ov.paddr, ov.IsFlag_NoHeader(), + &vol, hash_for_root, + map, 0)) + } + + bool needParseAttr = false; + + { + const bool isHashed = apfs.IsHashedName(); + UInt64 prevId = 1; + + { + const UInt64 numApfsItems = vol.apfs.GetTotalItems() + + 2; // we will have 2 additional hidden directories: root and private-dir + const UInt64 numApfsItems_Reserve = numApfsItems + + 16; // we reserve 16 for some possible unexpected items + if (numApfsItems_Reserve < map.Pairs.Size()) + { + vol.Items.ClearAndReserve((unsigned)numApfsItems_Reserve); + vol.Nodes.ClearAndReserve((unsigned)numApfsItems_Reserve); + vol.NodeIDs.ClearAndReserve((unsigned)numApfsItems_Reserve); + } + if (OpenCallback) + { + const UInt64 numFiles = ProgressVal_NumFilesTotal + numApfsItems; + RINOK(OpenCallback->SetTotal(&numFiles, NULL)) + } + } + + CAttr attr; + CItem item; + + FOR_VECTOR (i, map.Pairs) + { + if (OpenCallback && (i & 0xffff) == 1) + { + const UInt64 numFiles = ProgressVal_NumFilesTotal + + (vol.Items.Size() + vol.Nodes.Size()) / 2; + RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur)) + } + + const CKeyValPair &pair = map.Pairs[i]; + j_key_t jkey; + if (pair.Key.Size() < 8) + return S_FALSE; + const Byte *p = pair.Key; + jkey.Parse(p); + const unsigned type = jkey.GetType(); + const UInt64 id = jkey.GetID(); + if (id < prevId) + return S_FALSE; // IDs must be sorted + prevId = id; + + PRF(printf("\n%6d: id=%6d type = %2d ", i, (unsigned)id, type)); + + if (type == APFS_TYPE_INODE) + { + PRF(printf("INODE")); + if (pair.Key.Size() != 8 || + pair.Val.Size() < k_SizeOf_j_inode_val) + return S_FALSE; + + CNode inode; + inode.Parse(pair.Val); + + if (inode.private_id != id) + { + /* private_id : The unique identifier used by this file's data stream. + This identifier appears in the owning_obj_id field of j_phys_ext_val_t + records that describe the extents where the data is stored. + For an inode that doesn't have data, the value of this + field is the file-system object's identifier. + */ + // APFS_TYPE_EXTENT allow to link physical address extents. + // we don't support case (private_id != id) + UnsupportedFeature = true; + // return S_FALSE; + } + const UInt32 extraSize = (UInt32)pair.Val.Size() - k_SizeOf_j_inode_val; + if (extraSize != 0) + { + if (extraSize < 4) + return S_FALSE; + /* + struct xf_blob + { + uint16_t xf_num_exts; + uint16_t xf_used_data; + uint8_t xf_data[]; + }; + */ + const Byte *p2 = pair.Val + k_SizeOf_j_inode_val; + const UInt32 xf_num_exts = Get16(p2); + const UInt32 xf_used_data = Get16(p2 + 2); + UInt32 offset = 4 + (UInt32)xf_num_exts * 4; + if (offset + xf_used_data != extraSize) + return S_FALSE; + + PRF(printf(" parent_id = %d", (unsigned)inode.parent_id)); + + for (unsigned k = 0; k < xf_num_exts; k++) + { + // struct x_field + const Byte *p3 = p2 + 4 + k * 4; + const Byte x_type = p3[0]; + // const Byte x_flags = p3[1]; + const UInt32 x_size = Get16(p3 + 2); + const UInt32 x_size_ceil = (x_size + 7) & ~(UInt32)7; + if (offset + x_size_ceil > extraSize) + return S_FALSE; + const Byte *p4 = p2 + offset; + if (x_type == INO_EXT_TYPE_NAME) + { + if (x_size < 2) + return S_FALSE; + inode.PrimaryName.SetFrom_CalcLen((const char *)p4, x_size); + PRF(printf(" PrimaryName = %s", inode.PrimaryName.Ptr())); + if (inode.PrimaryName.Len() != x_size - 1) + HeadersError = true; + // return S_FALSE; + } + else if (x_type == INO_EXT_TYPE_DSTREAM) + { + if (x_size != k_SizeOf_j_dstream) + return S_FALSE; + if (inode.dstream_defined) + return S_FALSE; + inode.dstream.Parse(p4); + inode.dstream_defined = true; + } + else + { + // UnsupportedFeature = true; + // return S_FALSE; + } + offset += x_size_ceil; + } + if (offset != extraSize) + return S_FALSE; + } + + if (!vol.NodeIDs.IsEmpty()) + if (id <= vol.NodeIDs.Back()) + return S_FALSE; + vol.Nodes.Add(inode); + vol.NodeIDs.Add(id); + continue; + } + + if (type == APFS_TYPE_XATTR) + { + PRF(printf(" XATTR")); + + /* + struct j_xattr_key + { + j_key_t hdr; + uint16_t name_len; + uint8_t name[0]; + } + */ + + UInt32 len; + unsigned nameOffset; + { + nameOffset = 8 + 2; + if (pair.Key.Size() < nameOffset + 1) + return S_FALSE; + len = Get16(p + 8); + } + if (nameOffset + len != pair.Key.Size()) + return S_FALSE; + + attr.Clear(); + attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); + if (attr.Name.Len() != len - 1) + return S_FALSE; + + PRF(printf(" name=%s", attr.Name.Ptr())); + + const unsigned k_SizeOf_j_xattr_val = 4; + if (pair.Val.Size() < k_SizeOf_j_xattr_val) + return S_FALSE; + /* + struct j_xattr_val + { + uint16_t flags; + uint16_t xdata_len; + uint8_t xdata[0]; + } + */ + attr.flags = Get16(pair.Val); + const UInt32 xdata_len = Get16(pair.Val + 2); + + PRF(printf(" flags=%x xdata_len = %d", + (unsigned)attr.flags, + (unsigned)xdata_len)); + + const Byte *p4 = pair.Val + 4; + + if (k_SizeOf_j_xattr_val + xdata_len != pair.Val.Size()) + return S_FALSE; + if (attr.Is_EMBEDDED()) + attr.Data.CopyFrom(p4, xdata_len); + else if (attr.Is_STREAM()) + { + // why (attr.flags == 0x11) here? (0x11 is undocummented flag) + if (k_SizeOf_j_xattr_val + 8 + k_SizeOf_j_dstream != pair.Val.Size()) + return S_FALSE; + attr.Id = Get64(p4); + attr.dstream.Parse(p4 + 8); + attr.dstream_defined = true; + PRF(printf(" streamID=%d streamSize=%d", (unsigned)attr.Id, (unsigned)attr.dstream.size)); + } + else + { + // unknown attribute + // UnsupportedFeature = true; + // return S_FALSE; + } + + if (vol.NodeIDs.IsEmpty() || + vol.NodeIDs.Back() != id) + { + return S_FALSE; + // UnsupportedFeature = true; + // continue; + } + + CNode &inode = vol.Nodes.Back(); + + if (attr.Name.IsEqualTo("com.apple.fs.symlink")) + { + inode.SymLinkIndex = inode.Attrs.Size(); + if (attr.Is_dstream_OK_for_SymLink()) + needParseAttr = true; + } + else if (attr.Name.IsEqualTo("com.apple.decmpfs")) + { + inode.DecmpfsIndex = inode.Attrs.Size(); + // if (attr.dstream_defined) + needParseAttr = true; + } + else if (attr.Name.IsEqualTo("com.apple.ResourceFork")) + { + inode.ResourceIndex = inode.Attrs.Size(); + } + inode.Attrs.Add(attr); + continue; + } + + if (type == APFS_TYPE_DSTREAM_ID) + { + PRF(printf(" DSTREAM_ID")); + if (pair.Key.Size() != 8) + return S_FALSE; + // j_dstream_id_val_t + if (pair.Val.Size() != 4) + return S_FALSE; + const UInt32 refcnt = Get32(pair.Val); + + // The data stream record can be deleted when its reference count reaches zero. + PRF(printf(" refcnt = %d", (unsigned)refcnt)); + + if (vol.NodeIDs.IsEmpty()) + return S_FALSE; + + if (vol.NodeIDs.Back() != id) + { + // is it possible ? + // continue; + return S_FALSE; + } + + CNode &inode = vol.Nodes.Back(); + + if (inode.refcnt_defined) + return S_FALSE; + + inode.refcnt = refcnt; + inode.refcnt_defined = true; + if (inode.refcnt != (UInt32)inode.nlink) + { + PRF(printf(" refcnt != nlink")); + // is it possible ? + // return S_FALSE; + } + continue; + } + + if (type == APFS_TYPE_FILE_EXTENT) + { + PRF(printf(" FILE_EXTENT")); + /* + struct j_file_extent_key + { + j_key_t hdr; + uint64_t logical_addr; + } + */ + if (pair.Key.Size() != 16) + return S_FALSE; + // The offset within the file's data, in bytes, for the data stored in this extent + const UInt64 logical_addr = Get64(p + 8); + + j_file_extent_val eval; + if (pair.Val.Size() != k_SizeOf_j_file_extent_val) + return S_FALSE; + eval.Parse(pair.Val); + + if (logical_addr != 0) + { + PRF(printf(" logical_addr = %d", (unsigned)logical_addr)); + } + PRF(printf(" len = %8d pos = %8d", + (unsigned)eval.len_and_flags, + (unsigned)eval.phys_block_num + )); + + CExtent ext; + ext.logical_offset = logical_addr; + ext.len_and_flags = eval.len_and_flags; + ext.phys_block_num = eval.phys_block_num; + + if (vol.NodeIDs.IsEmpty()) + return S_FALSE; + if (vol.NodeIDs.Back() != id) + { + // extents for Attributs; + if (vol.SmallNodeIDs.IsEmpty() || + vol.SmallNodeIDs.Back() != id) + { + vol.SmallNodeIDs.Add(id); + vol.SmallNodes.AddNew(); + } + vol.SmallNodes.Back().Extents.Add(ext); + continue; + // return S_FALSE; + } + + CNode &inode = vol.Nodes.Back(); + inode.Extents.Add(ext); + continue; + } + + if (type == APFS_TYPE_DIR_REC) + { + UInt32 len; + unsigned nameOffset; + + if (isHashed) + { + /* + struct j_drec_hashed_key + { + j_key_t hdr; + UInt32 name_len_and_hash; + uint8_t name[0]; + } + */ + nameOffset = 8 + 4; + if (pair.Key.Size() < nameOffset + 1) + return S_FALSE; + const UInt32 name_len_and_hash = Get32(p + 8); + len = name_len_and_hash & J_DREC_LEN_MASK; + } + else + { + /* + struct j_drec_key + { + j_key_t hdr; + UInt16 name_len; // The length of the name, including the final null character + uint8_t name[0]; // The name, represented as a null-terminated UTF-8 string + } + */ + nameOffset = 8 + 2; + if (pair.Key.Size() < nameOffset + 1) + return S_FALSE; + len = Get16(p + 8); + } + if (nameOffset + len != pair.Key.Size()) + return S_FALSE; + + // CItem item; + item.Clear(); + + item.ParentId = id; + item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); + if (item.Name.Len() != len - 1) + return S_FALSE; + + if (pair.Val.Size() < k_SizeOf_j_drec_val) + return S_FALSE; + + item.Val.Parse(pair.Val); + + if (pair.Val.Size() > k_SizeOf_j_drec_val) + { + // fixme: parse extra fields; + // UnsupportedFeature = true; + // return S_FALSE; + } + + vol.Items.Add(item); + + /* + if (!vol.NodeIDs.IsEmpty() && vol.NodeIDs.Back() == id) + vol.Nodes.Back().NumItems++; + */ + if (id == PRIV_DIR_INO_NUM) + vol.NumItems_In_PrivateDir++; + + PRF(printf(" DIR_REC next=%6d flags=%2x %s", + (unsigned)item.Val.file_id, + (unsigned)item.Val.flags, + item.Name.Ptr())); + continue; + } + + if (type == APFS_TYPE_FILE_INFO) + { + if (pair.Key.Size() != 16) + return S_FALSE; + // j_file_info_key + const UInt64 info_and_lba = Get64(p + 8); + + #define J_FILE_INFO_LBA_MASK 0x00ffffffffffffffUL + // #define J_FILE_INFO_TYPE_MASK 0xff00000000000000UL + #define J_FILE_INFO_TYPE_SHIFT 56 + #define APFS_FILE_INFO_DATA_HASH 1 + + const unsigned infoType = (unsigned)(info_and_lba >> J_FILE_INFO_TYPE_SHIFT); + // address is a paddr_t + const UInt64 lba = info_and_lba & J_FILE_INFO_LBA_MASK; + // j_file_data_hash_val_t + /* Use this field of the union if the type stored in the info_and_lba field of j_file_info_val_t is + APFS_FILE_INFO_DATA_HASH */ + if (infoType != APFS_FILE_INFO_DATA_HASH) + return S_FALSE; + if (pair.Val.Size() != 3 + vol.integrity.HashSize) + return S_FALSE; + /* + struct j_file_data_hash_val + { + UInt16 hashed_len; // The length, in blocks, of the data segment that was hashed. + UInt8 hash_size; // must be consistent with integrity_meta_phys_t::im_hash_type + UInt8 hash[0]; + } + */ + + const unsigned hash_size = pair.Val[2]; + if (hash_size != vol.integrity.HashSize) + return S_FALSE; + + CHashChunk hr; + hr.hashed_len = GetUi16(pair.Val); + if (hr.hashed_len == 0) + return S_FALSE; + memcpy(hr.hash, (const Byte *)pair.Val + 3, vol.integrity.HashSize); + // (hashed_len <= 4) : we have seen + hr.lba = lba; + + PRF(printf(" FILE_INFO lba = %6x, hashed_len=%6d", + (unsigned)lba, + (unsigned)hr.hashed_len)); + + if (vol.Hash_IDs.IsEmpty() || vol.Hash_IDs.Back() != id) + { + vol.Hash_Vectors.AddNew(); + vol.Hash_IDs.Add(id); + } + CStreamHashes &hashes = vol.Hash_Vectors.Back(); + if (hashes.Size() != 0) + { + const CHashChunk &hr_Back = hashes.Back(); + if (lba != hr_Back.lba + ((UInt64)hr_Back.hashed_len << sb.block_size_Log)) + return S_FALSE; + } + hashes.Add(hr); + continue; + } + + if (type == APFS_TYPE_SNAP_METADATA) + { + if (pair.Key.Size() != 8) + return S_FALSE; + PRF(printf(" SNAP_METADATA")); + // continue; + } + + /* SIBLING items are used, if there are more than one hard link to some inode + key : value + parent_id_1 DIR_REC : inode_id, name_1 + parent_id_2 DIR_REC : inode_id, name_2 + inode_id INODE : parent_id_1, name_1 + inode_id SIBLING_LINK sibling_id_1 : parent_id_1, name_1 + inode_id SIBLING_LINK sibling_id_2 : parent_id_2, name_2 + sibling_id_1 SIBLING_MAP : inode_id + sibling_id_2 SIBLING_MAP : inode_id + */ + + if (type == APFS_TYPE_SIBLING_LINK) + { + if (pair.Key.Size() != 16) + return S_FALSE; + if (pair.Val.Size() < 10 + 1) + return S_FALSE; + /* + // struct j_sibling_key + // The sibling's unique identifier. + // This value matches the object identifier for the sibling map record + const UInt64 sibling_id = Get64(p + 8); + // struct j_sibling_val + const Byte *v = pair.Val; + const UInt64 parent_id = Get64(v); // The object identifier for the inode that's the parent directory. + const unsigned name_len = Get16(v + 8); // len including the final null character + if (10 + name_len != pair.Val.Size()) + return S_FALSE; + if (v[10 + name_len - 1] != 0) + return S_FALSE; + AString name ((const char *)(v + 10)); + if (name.Len() != name_len - 1) + return S_FALSE; + PRF(printf(" SIBLING_LINK sibling_id = %6d : parent_id=%6d %s", + (unsigned)sibling_id, (unsigned)parent_id, name.Ptr())); + */ + continue; + } + + if (type == APFS_TYPE_SIBLING_MAP) + { + // struct j_sibling_map_key + // The object identifier in the header is the sibling's unique identifier + if (pair.Key.Size() != 8 || pair.Val.Size() != 8) + return S_FALSE; + /* + // j_sibling_map_val + // The inode number of the underlying file + const UInt64 file_id = Get64(pair.Val); + PRF(printf(" SIBLING_MAP : file_id = %d", (unsigned)file_id)); + */ + continue; + } + + UnsupportedFeature = true; + // return S_FALSE; + } + ProgressVal_NumFilesTotal += vol.Items.Size(); + } + + + if (needParseAttr) + { + /* we read external streams for attributes + So we can get SymLink for GetProperty(kpidSymLink) later */ + FOR_VECTOR (i, vol.Nodes) + { + CNode &node = vol.Nodes[i]; + + FOR_VECTOR (a, node.Attrs) + { + CAttr &attr = node.Attrs[a]; + if (attr.Data.Size() != 0 || !attr.dstream_defined) + continue; + if (a == node.SymLinkIndex) + { + if (!attr.Is_dstream_OK_for_SymLink()) + continue; + } + else + { + if (a != node.DecmpfsIndex + // && a != node.ResourceIndex + ) + continue; + } + // we don't expect big streams here + // largest dstream for Decmpfs attribute is (2Kib+17) + if (attr.dstream.size > ((UInt32)1 << 16)) + continue; + CMyComPtr inStream; + const HRESULT res = GetAttrStream_dstream(OpenInStream, vol, attr, &inStream); + if (res == S_OK && inStream) + { + CByteBuffer buf2; + const size_t size = (size_t)attr.dstream.size; + buf2.Alloc(size); + if (ReadStream_FAIL(inStream, buf2, size) == S_OK) + attr.Data = buf2; + + ProgressVal_Cur += size; + if (OpenCallback) + if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) + { + + RINOK(OpenCallback->SetCompleted( + &ProgressVal_NumFilesTotal, + &ProgressVal_Cur)) + ProgressVal_Prev = ProgressVal_Cur; + } + } + } + + if (node.Has_UNCOMPRESSED_SIZE()) + if (IsViDef(node.DecmpfsIndex)) + { + CAttr &attr = node.Attrs[node.DecmpfsIndex]; + node.CompressHeader.Parse(attr.Data, attr.Data.Size()); + + if (node.CompressHeader.IsCorrect) + if (node.CompressHeader.Method < sizeof(MethodsMask) * 8) + MethodsMask |= ((UInt32)1 << node.CompressHeader.Method); + + if (node.CompressHeader.IsCorrect + && node.CompressHeader.IsSupported + && node.CompressHeader.UnpackSize == node.uncompressed_size) + { + attr.NeedShow = false; + if (node.CompressHeader.IsMethod_Resource() + && IsViDef(node.ResourceIndex)) + node.Attrs[node.ResourceIndex].NeedShow = false; + } + else + { + vol.UnsupportedMethod = true; + } + } + } + } + + const HRESULT res = vol.FillRefs(); + + if (vol.ThereAreErrors()) + HeadersError = true; + if (vol.UnsupportedFeature) + UnsupportedFeature = true; + if (vol.UnsupportedMethod) + UnsupportedMethod = true; + if (vol.NumAltStreams != 0) + ThereAreAltStreams = true; + + return res; +} + + + +HRESULT CVol::FillRefs() +{ + { + Refs.Reserve(Items.Size()); + // we fill Refs[*] + // we + // and set Nodes[*].ItemIndex for Nodes that are directories; + FOR_VECTOR (i, Items) + { + CItem &item = Items[i]; + const UInt64 id = item.Val.file_id; + // if (item.Id == ROOT_DIR_PARENT) continue; + /* for two root folders items + we don't set Node.ItemIndex; */ + // so nodes + if (id == ROOT_DIR_INO_NUM) + continue; + if (id == PRIV_DIR_INO_NUM) + if (NumItems_In_PrivateDir == 0) // if (inode.NumItems == 0) + continue; + + CRef ref; + ref.ItemIndex = i; + // ref.NodeIndex = VI_MINUS1; + ref.ParentRefIndex = VI_MINUS1; + #ifdef APFS_SHOW_ALT_STREAMS + ref.AttrIndex = VI_MINUS1; + #endif + const int index = NodeIDs.FindInSorted(id); + // const int index = -1; // for debug + ref.NodeIndex = (unsigned)index; + item.RefIndex = Refs.Size(); + Refs.Add(ref); + + if (index == -1) + { + NodeNotFound = true; + continue; + // return S_FALSE; + } + + // item.iNode_Index = index; + CNode &inode = Nodes[(unsigned)index]; + if (!item.Val.IsFlags_Unknown() + && inode.Get_Type_From_mode() != item.Val.flags) + { + Refs.Back().NodeIndex = VI_MINUS1; + WrongInodeLink = true; + continue; + // return S_FALSE; + } + + const bool isDir = inode.IsDir(); + if (isDir) + { + if (IsViDef(inode.ItemIndex)) + { + // hard links to dirs are not supported + Refs.Back().NodeIndex = VI_MINUS1; + WrongInodeLink = true; + continue; + } + inode.ItemIndex = i; + } + inode.NumCalcedLinks++; + + #ifdef APFS_SHOW_ALT_STREAMS + if (!isDir) + { + // we use alt streams only for files + const unsigned numAttrs = inode.Attrs.Size(); + if (numAttrs != 0) + { + ref.ParentRefIndex = item.RefIndex; + for (unsigned k = 0; k < numAttrs; k++) + { + // comment it for debug + const CAttr &attr = inode.Attrs[k]; + if (!attr.NeedShow) + continue; + + if (k == inode.SymLinkIndex) + continue; + ref.AttrIndex = k; + NumAltStreams++; + Refs.Add(ref); + /* + if (attr.dstream_defined) + { + const int idIndex = SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex != -1) + SmallNodes[(unsigned)idIndex].NumLinks++; // for debug + } + */ + } + } + } + #endif + } + } + + + { + // fill ghost nodes + CRef ref; + ref.ItemIndex = VI_MINUS1; + ref.ParentRefIndex = VI_MINUS1; + #ifdef APFS_SHOW_ALT_STREAMS + ref.AttrIndex = VI_MINUS1; + #endif + FOR_VECTOR (i, Nodes) + { + if (Nodes[i].NumCalcedLinks != 0) + continue; + const UInt64 id = NodeIDs[i]; + if (id == ROOT_DIR_INO_NUM || + id == PRIV_DIR_INO_NUM) + continue; + ThereAreUnlinkedNodes = true; + ref.NodeIndex = i; + Refs.Add(ref); + } + } + + /* if want to create Refs for ghost data streams, + we need additional CRef::SmallNodeIndex field */ + + { + /* all Nodes[*].ItemIndex were already filled for directory Nodes, + except of "root" and "private-dir" Nodes. */ + + // now we fill Items[*].ParentItemIndex and Refs[*].ParentRefIndex + + UInt64 prev_ID = (UInt64)(Int64)-1; + unsigned prev_ParentItemIndex = VI_MINUS1; + + FOR_VECTOR (i, Items) + { + CItem &item = Items[i]; + const UInt64 id = item.ParentId; // it's id of parent NODE + if (id != prev_ID) + { + prev_ID = id; + prev_ParentItemIndex = VI_MINUS1; + const int index = NodeIDs.FindInSorted(id); + if (index == -1) + continue; + prev_ParentItemIndex = Nodes[(unsigned)index].ItemIndex; + } + + if (IsViNotDef(prev_ParentItemIndex)) + continue; + item.ParentItemIndex = prev_ParentItemIndex; + if (IsViNotDef(item.RefIndex)) + { + // RefIndex is not set for 2 Items (root folders) + // but there is no node for them usually + continue; + } + CRef &ref = Refs[item.RefIndex]; + + /* + // it's optional check that parent_id is set correclty + if (IsViDef(ref.NodeIndex)) + { + const CNode &node = Nodes[ref.NodeIndex]; + if (node.IsDir() && node.parent_id != id) + return S_FALSE; + } + */ + + /* + if (id == ROOT_DIR_INO_NUM) + { + // ItemIndex in Node for ROOT_DIR_INO_NUM was not set bofere + // probably unused now. + ref.ParentRefIndex = VI_MINUS1; + } + else + */ + ref.ParentRefIndex = Items[prev_ParentItemIndex].RefIndex; + } + } + + { + // check for loops + const unsigned numItems = Items.Size(); + if (numItems + 1 == 0) + return S_FALSE; + CUIntArr arr; + arr.Alloc(numItems); + { + for (unsigned i = 0; i < numItems; i++) + arr[i] = 0; + } + for (unsigned i = 0; i < numItems;) + { + unsigned k = i++; + for (;;) + { + const unsigned a = arr[k]; + if (a != 0) + { + if (a == i) + return S_FALSE; + break; + } + arr[k] = i; + k = Items[k].ParentItemIndex; + if (IsViNotDef(k)) + break; + } + } + } + + return S_OK; +} + + + +Z7_class_CHandler_final: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public CMyUnknownImp, + public CDatabase +{ + Z7_IFACES_IMP_UNK_3( + IInArchive, + IArchiveGetRawProps, + IInArchiveGetStream) + + CMyComPtr _stream; + int FindHashIndex_for_Item(UInt32 index); +}; + + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + OpenInStream = inStream; + OpenCallback = callback; + RINOK(Open2()) + _stream = inStream; + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _stream.Release(); + Clear(); + return S_OK; +} + + +enum +{ + kpidBytesWritten = kpidUserDefined, + kpidBytesRead, + kpidPrimeName, + kpidParentINode, + kpidAddTime, + kpidGeneration, + kpidBsdFlags + // kpidUncompressedSize +}; + +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR }, + { NULL, kpidSize, VT_UI8 }, + { NULL, kpidPackSize, VT_UI8 }, + { NULL, kpidPosixAttrib, VT_UI4 }, + { NULL, kpidMTime, VT_FILETIME }, + { NULL, kpidCTime, VT_FILETIME }, + { NULL, kpidATime, VT_FILETIME }, + { NULL, kpidChangeTime, VT_FILETIME }, + { "Added Time", kpidAddTime, VT_FILETIME }, + { NULL, kpidMethod, VT_BSTR }, + { NULL, kpidINode, VT_UI8 }, + { NULL, kpidLinks, VT_UI4 }, + { NULL, kpidSymLink, VT_BSTR }, + { NULL, kpidUserId, VT_UI4 }, + { NULL, kpidGroupId, VT_UI4 }, + { NULL, kpidCharacts, VT_BSTR }, + #ifdef APFS_SHOW_ALT_STREAMS + { NULL, kpidIsAltStream, VT_BOOL }, + #endif + { "Parent iNode", kpidParentINode, VT_UI8 }, + { "Primary Name", kpidPrimeName, VT_BSTR }, + { "Generation", kpidGeneration, VT_UI4 }, + { "Written Size", kpidBytesWritten, VT_UI8 }, + { "Read Size", kpidBytesRead, VT_UI8 }, + { "BSD Flags", kpidBsdFlags, VT_UI4 } + // , { "Uncompressed Size", kpidUncompressedSize, VT_UI8 } +}; + + +static const Byte kArcProps[] = +{ + kpidName, + kpidCharacts, + kpidId, + kpidClusterSize, + kpidCTime, + kpidMTime, + kpidComment +}; + +IMP_IInArchive_Props_WITH_NAME +IMP_IInArchive_ArcProps + + +static void ApfsTimeToProp(UInt64 hfsTime, NWindows::NCOM::CPropVariant &prop) +{ + if (hfsTime == 0) + return; + FILETIME ft; + UInt32 ns100; + ApfsTimeToFileTime(hfsTime, ft, ns100); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); +} + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CApfs *apfs = NULL; + if (Vols.Size() == 1) + apfs = &Vols[0].apfs; + switch (propID) + { + case kpidPhySize: + prop = (UInt64)sb.block_count << sb.block_size_Log; + break; + case kpidClusterSize: prop = (UInt32)(sb.block_size); break; + case kpidCharacts: NHfs::MethodsMaskToProp(MethodsMask, prop); break; + case kpidMTime: + if (apfs) + ApfsTimeToProp(apfs->modified_by[0].timestamp, prop); + break; + case kpidCTime: + if (apfs) + ApfsTimeToProp(apfs->formatted_by.timestamp, prop); + break; + case kpidIsTree: prop = true; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + case kpidWarningFlags: + { + UInt32 flags = 0; + if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature; + if (UnsupportedMethod) flags |= kpv_ErrorFlags_UnsupportedMethod; + if (flags != 0) + prop = flags; + break; + } + + case kpidName: + { + if (apfs) + { + UString s; + AddVolInternalName_toString(s, *apfs); + s += ".apfs"; + prop = s; + } + break; + } + + case kpidId: + { + char s[32 + 4]; + sb.uuid.SetHex_To_str(s); + prop = s; + break; + } + + case kpidComment: + { + UString s; + { + AddComment_UInt64(s, "block_size", sb.block_size); + + FOR_VECTOR (i, Vols) + { + if (Vols.Size() > 1) + { + if (i != 0) + { + s += "----"; + s.Add_LF(); + } + AddComment_UInt64(s, "Volume", i + 1); + } + Vols[i].AddComment(s); + } + } + prop = s; + break; + } + + #ifdef APFS_SHOW_ALT_STREAMS + case kpidIsAltStream: + prop = ThereAreAltStreams; + // prop = false; // for debug + break; + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = 0; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) +{ + *name = NULL; + *propID = 0; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + UInt32 parentIndex = (UInt32)(Int32)-1; + + if (IsViDef(ref2.RefIndex)) + { + const CRef &ref = vol.Refs[ref2.RefIndex]; + #ifdef APFS_SHOW_ALT_STREAMS + if (ref.IsAltStream()) + *parentType = NParentType::kAltStream; + #endif + if (IsViDef(ref.ParentRefIndex)) + parentIndex = (UInt32)(ref.ParentRefIndex + vol.StartRef2Index); + else if (index != vol.RootRef2Index && IsViDef(vol.RootRef2Index)) + parentIndex = (UInt32)vol.RootRef2Index; + } + + *parent = parentIndex; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + UNUSED_VAR(index) + UNUSED_VAR(propID) + return S_OK; +} + + +static void Utf8Name_to_InterName(const AString &src, UString &dest) +{ + ConvertUTF8ToUnicode(src, dest); + NItemName::NormalizeSlashes_in_FileName_for_OsPath(dest); +} + + +static void AddNodeName(UString &s, const CNode &inode, UInt64 id) +{ + s += "node"; + s.Add_UInt64(id); + if (!inode.PrimaryName.IsEmpty()) + { + s.Add_Dot(); + UString s2; + Utf8Name_to_InterName(inode.PrimaryName, s2); + s += s2; + } +} + + +void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const +{ + const unsigned kNumLevelsMax = (1 << 10); + const unsigned kLenMax = (1 << 12); + UString s; + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + + if (IsViDef(ref2.RefIndex)) + { + const CRef &ref = vol.Refs[ref2.RefIndex]; + unsigned cur = ref.ItemIndex; + UString s2; + if (IsViNotDef(cur)) + { + if (inode) + AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]); + } + else + { + for (unsigned i = 0;; i++) + { + if (i >= kNumLevelsMax || s.Len() > kLenMax) + { + s.Insert(0, UString("[LONG_PATH]")); + break; + } + const CItem &item = vol.Items[(unsigned)cur]; + Utf8Name_to_InterName(item.Name, s2); + // s2 += "a\\b"; // for debug + s.Insert(0, s2); + cur = item.ParentItemIndex; + if (IsViNotDef(cur)) + break; + // ParentItemIndex was not set for such items + // if (item.ParentId == ROOT_DIR_INO_NUM) break; + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + } + } + + #ifdef APFS_SHOW_ALT_STREAMS + if (IsViDef(ref.AttrIndex) && inode) + { + s.Add_Colon(); + Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2); + // s2 += "a\\b"; // for debug + s += s2; + } + #endif + } + + if (!vol.RootName.IsEmpty()) + { + if (IsViDef(ref2.RefIndex)) + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + s.Insert(0, vol.RootName); + } + + path = s; +} + + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + + if (IsViNotDef(ref2.RefIndex)) + { + switch (propID) + { + case kpidName: + case kpidPath: + GetItemPath(index, NULL, prop); + break; + case kpidIsDir: + prop = true; + break; + } + prop.Detach(value); + return S_OK; + } + + const CRef &ref = vol.Refs[ref2.RefIndex]; + + const CItem *item = NULL; + if (IsViDef(ref.ItemIndex)) + item = &vol.Items[ref.ItemIndex]; + + const CNode *inode = NULL; + if (IsViDef(ref.NodeIndex)) + inode = &vol.Nodes[ref.NodeIndex]; + + switch (propID) + { + case kpidPath: + GetItemPath(index, inode, prop); + break; + case kpidPrimeName: + { + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && !inode->PrimaryName.IsEmpty()) + { + UString s; + ConvertUTF8ToUnicode(inode->PrimaryName, s); + /* + // for debug: + if (inode.PrimaryName != item.Name) throw 123456; + */ + prop = s; + } + break; + } + + case kpidName: + { + UString s; + #ifdef APFS_SHOW_ALT_STREAMS + if (ref.IsAltStream()) + { + // if (inode) + { + const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex]; + ConvertUTF8ToUnicode(attr.Name, s); + } + } + else + #endif + { + if (item) + ConvertUTF8ToUnicode(item->Name, s); + else if (inode) + AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]); + else + break; + } + // s += "s/1bs\\2"; // for debug: + prop = s; + break; + } + + case kpidSymLink: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex)) + { + const CByteBuffer &buf = inode->Attrs[(unsigned)inode->SymLinkIndex].Data; + if (buf.Size() != 0) + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)buf, (unsigned)buf.Size()); + if (s.Len() == buf.Size() - 1) + { + UString u; + ConvertUTF8ToUnicode(s, u); + prop = u; + } + } + } + } + break; + + case kpidSize: + if (inode) + { + UInt64 size = 0; + if (inode->GetSize(ref.GetAttrIndex(), size) || + !inode->IsDir()) + prop = size; + } + break; + + case kpidPackSize: + if (inode) + { + UInt64 size; + if (inode->GetPackSize(ref.GetAttrIndex(), size) || + !inode->IsDir()) + prop = size; + } + break; + + case kpidMethod: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + if (inode->CompressHeader.IsCorrect) + inode->CompressHeader.MethodToProp(prop); + else if (IsViDef(inode->DecmpfsIndex)) + prop = "decmpfs"; + else if (!inode->IsDir() && !inode->dstream_defined) + { + if (inode->IsSymLink()) + { + if (IsViDef(inode->SymLinkIndex)) + prop = "symlink"; + } + // else prop = "no_dstream"; + } + } + break; + + /* + case kpidUncompressedSize: + if (inode && inode->Has_UNCOMPRESSED_SIZE()) + prop = inode->uncompressed_size; + break; + */ + + case kpidIsDir: + { + bool isDir = false; + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + { + if (inode) + isDir = inode->IsDir(); + else if (item) + isDir = item->Val.IsFlags_Dir(); + } + prop = isDir; + break; + } + + case kpidPosixAttrib: + { + if (inode) + { + UInt32 mode = inode->mode; + #ifdef APFS_SHOW_ALT_STREAMS + if (ref.IsAltStream()) + { + mode &= 0666; // we disable execution + mode |= MY_LIN_S_IFREG; + } + #endif + prop = (UInt32)mode; + } + else if (item && !item->Val.IsFlags_Unknown()) + prop = (UInt32)(item->Val.flags << 12); + break; + } + + case kpidCTime: if (inode) ApfsTimeToProp(inode->create_time, prop); break; + case kpidMTime: if (inode) ApfsTimeToProp(inode->mod_time, prop); break; + case kpidATime: if (inode) ApfsTimeToProp(inode->access_time, prop); break; + case kpidChangeTime: if (inode) ApfsTimeToProp(inode->change_time, prop); break; + case kpidAddTime: if (item) ApfsTimeToProp(item->Val.date_added, prop); break; + + case kpidBytesWritten: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && inode->dstream_defined) + prop = inode->dstream.total_bytes_written; + break; + case kpidBytesRead: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && inode->dstream_defined) + prop = inode->dstream.total_bytes_read; + break; + + #ifdef APFS_SHOW_ALT_STREAMS + case kpidIsAltStream: + prop = ref.IsAltStream(); + break; + #endif + + case kpidCharacts: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop); + } + break; + + case kpidBsdFlags: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop); + } + break; + + case kpidGeneration: + #ifdef APFS_SHOW_ALT_STREAMS + // if (!ref.IsAltStream()) + #endif + if (inode) + prop = inode->write_generation_counter; + break; + + case kpidUserId: + if (inode) + prop = (UInt32)inode->owner; + break; + + case kpidGroupId: + if (inode) + prop = (UInt32)inode->group; + break; + + case kpidLinks: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && !inode->IsDir()) + prop = (UInt32)inode->nlink; + break; + + case kpidINode: + #ifdef APFS_SHOW_ALT_STREAMS + // here we can disable iNode for alt stream. + if (!ref.IsAltStream()) + #endif + if (IsViDef(ref.NodeIndex)) + prop = (UInt32)vol.NodeIDs[ref.NodeIndex]; + break; + + case kpidParentINode: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + prop = (UInt32)inode->parent_id; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +UInt64 CDatabase::GetSize(const UInt32 index) const +{ + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + if (IsViNotDef(ref2.RefIndex)) + return 0; + const CRef &ref = vol.Refs[ref2.RefIndex]; + if (IsViNotDef(ref.NodeIndex)) + return 0; + const CNode &inode = vol.Nodes[ref.NodeIndex]; + UInt64 size; + if (inode.GetSize(ref.GetAttrIndex(), size)) + return size; + return 0; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Refs2.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + { + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + totalSize += GetSize(index); + } + RINOK(extractCallback->SetTotal(totalSize)) + } + + UInt64 currentTotalSize = 0, currentItemSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + CMyComPtr2_Create copyCoder; + + // We don't know if zlib without Adler is allowed in APFS. + // But zlib without Adler is allowed in HFS. + // So here we allow apfs/zlib without Adler: + NHfs::CDecoder decoder(true); // IsAdlerOptional + + for (i = 0;; i++, currentTotalSize += currentItemSize) + { + lps->InSize = currentTotalSize; + lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()) + + if (i >= numItems) + break; + + const UInt32 index = allFilesMode ? i : indices[i]; + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + + currentItemSize = GetSize(index); + + int opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (IsViNotDef(ref2.RefIndex)) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const CRef &ref = vol.Refs[ref2.RefIndex]; + bool isDir = false; + if (IsViDef(ref.NodeIndex)) + isDir = vol.Nodes[ref.NodeIndex].IsDir(); + else if (IsViDef(ref.ItemIndex)) + isDir = + #ifdef APFS_SHOW_ALT_STREAMS + !ref.IsAltStream() && + #endif + vol.Items[ref.ItemIndex].Val.IsFlags_Dir(); + + if (isDir) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + opRes = NExtract::NOperationResult::kDataError; + + if (IsViDef(ref.NodeIndex)) + { + const CNode &inode = vol.Nodes[ref.NodeIndex]; + if ( + #ifdef APFS_SHOW_ALT_STREAMS + !ref.IsAltStream() && + #endif + !inode.dstream_defined + && inode.Extents.IsEmpty() + && inode.Has_UNCOMPRESSED_SIZE() + && inode.uncompressed_size == inode.CompressHeader.UnpackSize) + { + if (inode.CompressHeader.IsSupported) + { + CMyComPtr inStreamFork; + UInt64 forkSize = 0; + const CByteBuffer *decmpfs_Data = NULL; + + if (inode.CompressHeader.IsMethod_Resource()) + { + if (IsViDef(inode.ResourceIndex)) + { + const CAttr &attr = inode.Attrs[inode.ResourceIndex]; + forkSize = attr.GetSize(); + GetAttrStream(_stream, vol, attr, &inStreamFork); + } + } + else + { + const CAttr &attr = inode.Attrs[inode.DecmpfsIndex]; + decmpfs_Data = &attr.Data; + } + + if (inStreamFork || decmpfs_Data) + { + const HRESULT hres = decoder.Extract( + inStreamFork, realOutStream, + forkSize, + inode.CompressHeader, + decmpfs_Data, + currentTotalSize, extractCallback, + opRes); + if (hres != S_FALSE && hres != S_OK) + return hres; + } + } + else + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else + { + CMyComPtr inStream; + if (GetStream(index, &inStream) == S_OK && inStream) + { + CMyComPtr2 hashStream; + + if (vol.integrity.Is_SHA256()) + { + const int hashIndex = FindHashIndex_for_Item(index); + if (hashIndex != -1) + { + hashStream.Create_if_Empty(); + hashStream->SetStream(realOutStream); + hashStream->Init(&(vol.Hash_Vectors[(unsigned)hashIndex]), sb.block_size_Log); + } + } + + RINOK(copyCoder.Interface()->Code(inStream, + hashStream.IsDefined() ? + hashStream.Interface() : + realOutStream.Interface(), + NULL, NULL, lps)) + opRes = NExtract::NOperationResult::kDataError; + if (copyCoder->TotalSize == currentItemSize) + { + opRes = NExtract::NOperationResult::kOK; + if (hashStream.IsDefined()) + if (!hashStream->FinalCheck()) + opRes = NExtract::NOperationResult::kCRCError; + } + else if (copyCoder->TotalSize < currentItemSize) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = Refs2.Size(); + return S_OK; +} + + +int CHandler::FindHashIndex_for_Item(UInt32 index) +{ + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + if (IsViNotDef(ref2.RefIndex)) + return -1; + + const CRef &ref = vol.Refs[ref2.RefIndex]; + if (IsViNotDef(ref.NodeIndex)) + return -1; + const CNode &inode = vol.Nodes[ref.NodeIndex]; + + unsigned attrIndex = ref.GetAttrIndex(); + + if (IsViNotDef(attrIndex) + && !inode.dstream_defined + && inode.IsSymLink()) + { + attrIndex = inode.SymLinkIndex; + if (IsViNotDef(attrIndex)) + return -1; + } + + if (IsViDef(attrIndex)) + { + /* we have seen examples, where hash available for "com.apple.ResourceFork" stream. + these hashes for "com.apple.ResourceFork" stream are for unpacked data. + but the caller here needs packed data of stream. So we don't use hashes */ + return -1; + } + else + { + if (!inode.dstream_defined) + return -1; + const UInt64 id = vol.NodeIDs[ref.NodeIndex]; + return vol.Hash_IDs.FindInSorted(id); + } +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + *stream = NULL; + + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + if (IsViNotDef(ref2.RefIndex)) + return S_FALSE; + + const CRef &ref = vol.Refs[ref2.RefIndex]; + if (IsViNotDef(ref.NodeIndex)) + return S_FALSE; + const CNode &inode = vol.Nodes[ref.NodeIndex]; + + const CRecordVector *extents; + UInt64 rem = 0; + + unsigned attrIndex = ref.GetAttrIndex(); + + if (IsViNotDef(attrIndex) + && !inode.dstream_defined + && inode.IsSymLink()) + { + attrIndex = inode.SymLinkIndex; + if (IsViNotDef(attrIndex)) + return S_FALSE; + } + + if (IsViDef(attrIndex)) + { + const CAttr &attr = inode.Attrs[(unsigned)attrIndex]; + if (!attr.dstream_defined) + { + CMyComPtr2 streamTemp; + streamTemp.Create_if_Empty(); + streamTemp->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + } + const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex != -1) + extents = &vol.SmallNodes[(unsigned)idIndex].Extents; + else + { + const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(attr.Id); + if (fext_Index == -1) + return S_FALSE; + extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents; + } + rem = attr.dstream.size; + } + else + { + if (IsViDef(ref.ItemIndex)) + if (vol.Items[ref.ItemIndex].Val.IsFlags_Dir()) + return S_FALSE; + if (inode.IsDir()) + return S_FALSE; + extents = &inode.Extents; + if (inode.dstream_defined) + { + rem = inode.dstream.size; + if (inode.Extents.Size() == 0) + { + const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(vol.NodeIDs[ref.NodeIndex]); + if (fext_Index != -1) + extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents; + } + } + else + { + // return S_FALSE; // check it !!! How zero size files are stored with dstream_defined? + } + } + return GetStream2(_stream, extents, rem, stream); +} + + + +HRESULT CDatabase::GetAttrStream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream) +{ + *stream = NULL; + if (!attr.dstream_defined) + { + CMyComPtr2 streamTemp; + streamTemp.Create_if_Empty(); + streamTemp->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + } + return GetAttrStream_dstream(apfsInStream, vol, attr, stream); +} + + +HRESULT CDatabase::GetAttrStream_dstream( IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream) +{ + const CRecordVector *extents; + { + const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex != -1) + extents = &vol.SmallNodes[(unsigned)idIndex].Extents; + else + { + const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(attr.Id); + if (fext_Index == -1) + return S_FALSE; + extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents; + } + } + return GetStream2(apfsInStream, extents, attr.dstream.size, stream); +} + + +HRESULT CDatabase::GetStream2( + IInStream *apfsInStream, + const CRecordVector *extents, UInt64 rem, + ISequentialInStream **stream) +{ + CMyComPtr2 extentStream; + extentStream.Create_if_Empty(); + + UInt64 virt = 0; + FOR_VECTOR (i, *extents) + { + const CExtent &e = (*extents)[i]; + if (virt != e.logical_offset) + return S_FALSE; + const UInt64 len = EXTENT_GET_LEN(e.len_and_flags); + if (len == 0) + { + return S_FALSE; + // continue; + } + if (rem == 0) + return S_FALSE; + UInt64 cur = len; + if (cur > rem) + cur = rem; + CSeekExtent se; + se.Phy = (UInt64)e.phys_block_num << sb.block_size_Log; + se.Virt = virt; + virt += cur; + rem -= cur; + extentStream->Extents.Add(se); + if (rem == 0) + if (i != extents->Size() - 1) + return S_FALSE; + } + + if (rem != 0) + return S_FALSE; + + CSeekExtent se; + se.Phy = 0; + se.Virt = virt; + extentStream->Extents.Add(se); + extentStream->Stream = apfsInStream; + extentStream->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + + +REGISTER_ARC_I( + "APFS", "apfs img", NULL, 0xc3, + k_Signature, + k_SignatureOffset, + 0, + IsArc_APFS) + +}} diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index 3f5fac4d9..e88d2feec 100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -1,360 +1,422 @@ -// ApmHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -// #define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) - -using namespace NWindows; - -namespace NArchive { - -namespace NDmg { - const char *Find_Apple_FS_Ext(const AString &name); - bool Is_Apple_FS_Or_Unknown(const AString &name); -} - -namespace NApm { - -static const Byte kSig0 = 'E'; -static const Byte kSig1 = 'R'; - -static const CUInt32PCharPair k_Flags[] = -{ - { 0, "VALID" }, - { 1, "ALLOCATED" }, - { 2, "IN_USE" }, - { 3, "BOOTABLE" }, - { 4, "READABLE" }, - { 5, "WRITABLE" }, - { 6, "OS_PIC_CODE" }, - // { 7, "OS_SPECIFIC_2" }, // "Unused" - // { 8, "ChainCompatible" }, // "OS_SPECIFIC_1" - // { 9, "RealDeviceDriver" }, - // { 10, "CanChainToNext" }, - { 30, "MOUNTED_AT_STARTUP" }, - { 31, "STARTUP" } -}; - -#define DPME_FLAGS_VALID (1u << 0) -#define DPME_FLAGS_ALLOCATED (1u << 1) - -static const unsigned k_Str_Size = 32; - -struct CItem -{ - UInt32 StartBlock; - UInt32 NumBlocks; - UInt32 Flags; // pmPartStatus - char Name[k_Str_Size]; - char Type[k_Str_Size]; - /* - UInt32 DataStartBlock; - UInt32 NumDataBlocks; - UInt32 BootStartBlock; - UInt32 BootSize; - UInt32 BootAddr; - UInt32 BootEntry; - UInt32 BootChecksum; - char Processor[16]; - */ - - bool Is_Valid_and_Allocated() const - { return (Flags & (DPME_FLAGS_VALID | DPME_FLAGS_ALLOCATED)) != 0; } - - bool Parse(const Byte *p, UInt32 &numBlocksInMap) - { - numBlocksInMap = Get32(p + 4); - StartBlock = Get32(p + 8); - NumBlocks = Get32(p + 0xc); - Flags = Get32(p + 0x58); - memcpy(Name, p + 0x10, k_Str_Size); - memcpy(Type, p + 0x30, k_Str_Size); - if (GetUi32(p) != 0x4d50) // "PM" - return false; - /* - DataStartBlock = Get32(p + 0x50); - NumDataBlocks = Get32(p + 0x54); - BootStartBlock = Get32(p + 0x5c); - BootSize = Get32(p + 0x60); - BootAddr = Get32(p + 0x64); - if (Get32(p + 0x68) != 0) - return false; - BootEntry = Get32(p + 0x6c); - if (Get32(p + 0x70) != 0) - return false; - BootChecksum = Get32(p + 0x74); - memcpy(Processor, p + 0x78, 16); - */ - return true; - } -}; - - -Z7_class_CHandler_final: public CHandlerCont -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - CRecordVector _items; - unsigned _blockSizeLog; - UInt32 _numBlocks; - UInt64 _phySize; - bool _isArc; - - UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override - { - const CItem &item = _items[index]; - pos = BlocksToBytes(item.StartBlock); - size = BlocksToBytes(item.NumBlocks); - return NExtract::NOperationResult::kOK; - } -}; - -static const UInt32 kSectorSize = 512; - -// we support only 4 cluster sizes: 512, 1024, 2048, 4096 */ - -API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size) -{ - if (size < kSectorSize) - return k_IsArc_Res_NEED_MORE; - if (GetUi64(p + 8) != 0) - return k_IsArc_Res_NO; - UInt32 v = GetUi32(p); // we read as little-endian - v ^= (kSig0 | (unsigned)kSig1 << 8); - if ((v & ~((UInt32)0xf << 17))) - return k_IsArc_Res_NO; - if ((0x116u >> (v >> 17)) & 1) - return k_IsArc_Res_YES; - return k_IsArc_Res_NO; -} -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)) -{ - COM_TRY_BEGIN - Close(); - - Byte buf[kSectorSize]; - unsigned numSectors_in_Cluster; - { - RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) - if (GetUi64(buf + 8) != 0) - return S_FALSE; - UInt32 v = GetUi32(buf); // we read as little-endian - v ^= (kSig0 | (unsigned)kSig1 << 8); - if ((v & ~((UInt32)0xf << 17))) - return S_FALSE; - v >>= 16; - if (v == 0) - return S_FALSE; - if (v & (v - 1)) - return S_FALSE; - const unsigned a = (0x30210u >> v) & 3; - // a = 0; // for debug - numSectors_in_Cluster = 1u << a; - _blockSizeLog = 9 + a; - } - - UInt32 numBlocks = Get32(buf + 4); - _numBlocks = numBlocks; - - { - for (unsigned k = numSectors_in_Cluster; --k != 0;) - { - RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) - } - } - - UInt32 numBlocksInMap = 0; - - for (unsigned i = 0;;) - { - RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) - - CItem item; - - UInt32 numBlocksInMap2 = 0; - if (!item.Parse(buf, numBlocksInMap2)) - return S_FALSE; - if (i == 0) - { - numBlocksInMap = numBlocksInMap2; - if (numBlocksInMap > (1 << 8) || numBlocksInMap == 0) - return S_FALSE; - } - else if (numBlocksInMap2 != numBlocksInMap) - return S_FALSE; - - const UInt32 finish = item.StartBlock + item.NumBlocks; - if (finish < item.StartBlock) - return S_FALSE; - if (numBlocks < finish) - numBlocks = finish; - - _items.Add(item); - for (unsigned k = numSectors_in_Cluster; --k != 0;) - { - RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) - } - if (++i == numBlocksInMap) - break; - } - - _phySize = BlocksToBytes(numBlocks); - _isArc = true; - _stream = stream; - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _phySize = 0; - _items.Clear(); - _stream.Release(); - return S_OK; -} - - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidOffset, - kpidCharacts -}; - -static const Byte kArcProps[] = -{ - kpidClusterSize, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static AString GetString(const char *s) -{ - AString res; - res.SetFrom_CalcLen(s, k_Str_Size); - return res; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: - { - int mainIndex = -1; - FOR_VECTOR (i, _items) - { - const CItem &item = _items[i]; - if (!item.Is_Valid_and_Allocated()) - continue; - AString s (GetString(item.Type)); - if (NDmg::Is_Apple_FS_Or_Unknown(s)) - { - if (mainIndex != -1) - { - mainIndex = -1; - break; - } - mainIndex = (int)i; - } - } - if (mainIndex != -1) - prop = (UInt32)(Int32)mainIndex; - break; - } - case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; - case kpidPhySize: prop = _phySize; break; - case kpidNumBlocks: prop = _numBlocks; break; - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch (propID) - { - case kpidPath: - { - AString s (GetString(item.Name)); - if (s.IsEmpty()) - s.Add_UInt32(index); - AString type (GetString(item.Type)); - { - const char *ext = NDmg::Find_Apple_FS_Ext(type); - if (ext) - type = ext; - } - if (!type.IsEmpty()) - { - s.Add_Dot(); - s += type; - } - prop = s; - break; - } - case kpidSize: - case kpidPackSize: - prop = BlocksToBytes(item.NumBlocks); - break; - case kpidOffset: prop = BlocksToBytes(item.StartBlock); break; - case kpidCharacts: FLAGS_TO_PROP(k_Flags, item.Flags, prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -static const Byte k_Signature[] = { kSig0, kSig1 }; - -REGISTER_ARC_I( - "APM", "apm", NULL, 0xD4, - k_Signature, - 0, - 0, - IsArc_Apm) - -}} +// ApmHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get32(p) GetBe32a(p) + +using namespace NWindows; + +namespace NArchive { + +namespace NDmg { + const char *Find_Apple_FS_Ext(const AString &name); + bool Is_Apple_FS_Or_Unknown(const AString &name); +} + +namespace NApm { + +static const Byte kSig0 = 'E'; +static const Byte kSig1 = 'R'; + +static const CUInt32PCharPair k_Flags[] = +{ + { 0, "VALID" }, + { 1, "ALLOCATED" }, + { 2, "IN_USE" }, + { 3, "BOOTABLE" }, + { 4, "READABLE" }, + { 5, "WRITABLE" }, + { 6, "OS_PIC_CODE" }, + // { 7, "OS_SPECIFIC_2" }, // "Unused" + { 8, "ChainCompatible" }, // "OS_SPECIFIC_1" + { 9, "RealDeviceDriver" }, + // { 10, "CanChainToNext" }, + { 30, "MOUNTED_AT_STARTUP" }, + { 31, "STARTUP" } +}; + +#define DPME_FLAGS_VALID (1u << 0) +#define DPME_FLAGS_ALLOCATED (1u << 1) + +static const unsigned k_Str_Size = 32; + +struct CItem +{ + UInt32 StartBlock; + UInt32 NumBlocks; + UInt32 Flags; // pmPartStatus + char Name[k_Str_Size]; + char Type[k_Str_Size]; + /* + UInt32 DataStartBlock; + UInt32 NumDataBlocks; + UInt32 BootStartBlock; + UInt32 BootSize; + UInt32 BootAddr; + UInt32 BootEntry; + UInt32 BootChecksum; + char Processor[16]; + */ + + bool Is_Valid_and_Allocated() const + { return (Flags & (DPME_FLAGS_VALID | DPME_FLAGS_ALLOCATED)) != 0; } + + bool Parse(const UInt32 *p32, UInt32 &numBlocksInMap) + { + if (GetUi32a(p32) != 0x4d50) // "PM" + return false; + numBlocksInMap = Get32(p32 + 4 / 4); + StartBlock = Get32(p32 + 8 / 4); + NumBlocks = Get32(p32 + 0xc / 4); + Flags = Get32(p32 + 0x58 / 4); + memcpy(Name, p32 + 0x10 / 4, k_Str_Size); + memcpy(Type, p32 + 0x30 / 4, k_Str_Size); + /* + DataStartBlock = Get32(p + 0x50); + NumDataBlocks = Get32(p + 0x54); + BootStartBlock = Get32(p + 0x5c); + BootSize = Get32(p + 0x60); + BootAddr = Get32(p + 0x64); + if (Get32(p + 0x68) != 0) + return false; + BootEntry = Get32(p + 0x6c); + if (Get32(p + 0x70) != 0) + return false; + BootChecksum = Get32(p + 0x74); + memcpy(Processor, p32 + 0x78 / 4, 16); + */ + return true; + } +}; + + +Z7_class_CHandler_final: public CHandlerCont +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + CRecordVector _items; + unsigned _blockSizeLog; + bool _isArc; + // UInt32 _numBlocks; + UInt64 _phySize; + + UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override + { + const CItem &item = _items[index]; + pos = BlocksToBytes(item.StartBlock); + size = BlocksToBytes(item.NumBlocks); + return NExtract::NOperationResult::kOK; + } +}; + +static const UInt32 kSectorSize = 512; + +// we support only 4 cluster sizes: 512, 1024, 2048, 4096 */ + +API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size) +{ + if (size < kSectorSize) + return k_IsArc_Res_NEED_MORE; + if (GetUi32(p + 12) != 0) + return k_IsArc_Res_NO; + UInt32 v = GetUi32(p); // we read as little-endian + v ^= kSig0 | (unsigned)kSig1 << 8; + if (v & ~((UInt32)0xf << 17)) + return k_IsArc_Res_NO; + if ((0x116u >> (v >> 17)) & 1) + return k_IsArc_Res_YES; + return k_IsArc_Res_NO; +} +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)) +{ + COM_TRY_BEGIN + Close(); + + UInt32 buf32[kSectorSize / 4]; + unsigned numPadSectors, blockSizeLog_from_Header; + { + // Driver Descriptor Map (DDM) + RINOK(ReadStream_FALSE(stream, buf32, kSectorSize)) + // 8: UInt16 sbDevType : =0 (usually), =1 in Apple Mac OS X 10.3.0 iso + // 10: UInt16 sbDevId : =0 (usually), =1 in Apple Mac OS X 10.3.0 iso + // 12: UInt32 sbData : =0 + if (buf32[3] != 0) + return S_FALSE; + UInt32 v = GetUi32a(buf32); // we read as little-endian + v ^= kSig0 | (unsigned)kSig1 << 8; + if (v & ~((UInt32)0xf << 17)) + return S_FALSE; + v >>= 16; + if (v == 0) + return S_FALSE; + if (v & (v - 1)) + return S_FALSE; + // v == { 16,8,4,2 } : block size (x256 bytes) + const unsigned a = +#if 1 + (0x30210u >> v) & 3; +#else + 0; // for debug : hardcoded switch to 512-bytes mode +#endif + numPadSectors = (1u << a) - 1; + _blockSizeLog = blockSizeLog_from_Header = 9 + a; + } + +/* + some APMs (that are ".iso" macOS installation files) contain + (blockSizeLog == 11) in DDM header, + and contain 2 overlapping maps: + 1) map for 512-bytes-step + 2) map for 2048-bytes-step + 512-bytes-step map is correct. + 2048-bytes-step map can be incorrect in some cases. + + macos 8 / OSX DP2 iso: + There is shared "hfs" item in both maps. + And correct (offset/size) values for "hfs" partition + can be calculated only in 512-bytes mode (ignoring blockSizeLog == 11). + But some records (Macintosh.Apple_Driver*_) + can be correct on both modes: 512-bytes mode / 2048-bytes-step. + + macos 921 ppc / Apple Mac OS X 10.3.0 iso: + Both maps are correct. + If we use 512-bytes-step, each 4th item is (Apple_Void) with zero size. + And these zero size (Apple_Void) items will be first items in 2048-bytes-step map. +*/ + +// we define Z7_APM_SWITCH_TO_512_BYTES, because +// we want to support old MACOS APMs that contain correct value only +// for 512-bytes-step mode +#define Z7_APM_SWITCH_TO_512_BYTES + + const UInt32 numBlocks_from_Header = Get32(buf32 + 1); + UInt32 numBlocks = 0; + { + for (unsigned k = 0; k < numPadSectors; k++) + { + RINOK(ReadStream_FALSE(stream, buf32, kSectorSize)) +#ifdef Z7_APM_SWITCH_TO_512_BYTES + if (k == 0) + { + if (GetUi32a(buf32) == 0x4d50 // "PM" + // && (Get32(buf32 + 0x58 / 4) & 1) // Flags::VALID + // some old APMs don't use VALID flag for Apple_partition_map item + && Get32(buf32 + 8 / 4) == 1) // StartBlock + { + // we switch the mode to 512-bytes-step map reading: + numPadSectors = 0; + _blockSizeLog = 9; + break; + } + } +#endif + } + } + + for (unsigned i = 0;;) + { +#ifdef Z7_APM_SWITCH_TO_512_BYTES + if (i != 0 || _blockSizeLog == blockSizeLog_from_Header) +#endif + { + RINOK(ReadStream_FALSE(stream, buf32, kSectorSize)) + } + + CItem item; + UInt32 numBlocksInMap = 0; + if (!item.Parse(buf32, numBlocksInMap)) + return S_FALSE; + // v24.09: we don't check that all entries have same (numBlocksInMap) values, + // because some APMs have different (numBlocksInMap) values, if (Apple_Void) is used. + if (numBlocksInMap > (1 << 8) || numBlocksInMap <= i) + return S_FALSE; + + const UInt32 finish = item.StartBlock + item.NumBlocks; + if (finish < item.StartBlock) + return S_FALSE; + if (numBlocks < finish) + numBlocks = finish; + + _items.Add(item); + if (numPadSectors != 0) + { + RINOK(stream->Seek(numPadSectors << 9, STREAM_SEEK_CUR, NULL)) + } + if (++i == numBlocksInMap) + break; + } + + _phySize = BlocksToBytes(numBlocks); + // _numBlocks = numBlocks; + const UInt64 physSize = (UInt64)numBlocks_from_Header << blockSizeLog_from_Header; + if (_phySize < physSize) + _phySize = physSize; + _isArc = true; + _stream = stream; + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _phySize = 0; + _items.Clear(); + _stream.Release(); + return S_OK; +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidOffset, + kpidCharacts + // , kpidCpu +}; + +static const Byte kArcProps[] = +{ + kpidClusterSize + // , kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void GetString(AString &dest, const char *src) +{ + dest.SetFrom_CalcLen(src, k_Str_Size); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: + { + int mainIndex = -1; + FOR_VECTOR (i, _items) + { + const CItem &item = _items[i]; + if (!item.Is_Valid_and_Allocated()) + continue; + AString s; + GetString(s, item.Type); + if (NDmg::Is_Apple_FS_Or_Unknown(s)) + { + if (mainIndex != -1) + { + mainIndex = -1; + break; + } + mainIndex = (int)i; + } + } + if (mainIndex != -1) + prop = (UInt32)(Int32)mainIndex; + break; + } + case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; + case kpidPhySize: prop = _phySize; break; + // case kpidNumBlocks: prop = _numBlocks; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: + { + AString s; + GetString(s, item.Name); + if (s.IsEmpty()) + s.Add_UInt32(index); + AString type; + GetString(type, item.Type); + { + const char *ext = NDmg::Find_Apple_FS_Ext(type); + if (ext) + type = ext; + } + if (!type.IsEmpty()) + { + s.Add_Dot(); + s += type; + } + prop = s; + break; + } +/* + case kpidCpu: + { + AString s; + s.SetFrom_CalcLen(item.Processor, sizeof(item.Processor)); + if (!s.IsEmpty()) + prop = s; + break; + } +*/ + case kpidSize: + case kpidPackSize: + prop = BlocksToBytes(item.NumBlocks); + break; + case kpidOffset: prop = BlocksToBytes(item.StartBlock); break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, item.Flags, prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static const Byte k_Signature[] = { kSig0, kSig1 }; + +REGISTER_ARC_I( + "APM", "apm", NULL, 0xD4, + k_Signature, + 0, + 0, + IsArc_Apm) + +}} diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp index 6fb802dac..95e4719fd 100644 --- a/CPP/7zip/Archive/ArHandler.cpp +++ b/CPP/7zip/Archive/ArHandler.cpp @@ -1,842 +1,842 @@ -// ArHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringConvert.h" -#include "../../Common/StringToInt.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/ItemNameUtils.h" - -using namespace NWindows; -using namespace NTime; - -namespace NArchive { -namespace NAr { - -/* -The end of each file member (including last file in archive) is 2-bytes aligned. -It uses 0xA padding if required. - -File Names: - -GNU/SVR4 variant (.a static library): - / - archive symbol table - // - the list of the long filenames, separated by one or more LF characters. - /N - the reference to name string in long filenames list - name/ - the name - -Microsoft variant (.lib static library): - / - First linker file (archive symbol table) - / - Second linker file - // - the list of the long filenames, null-terminated. Each string begins - immediately after the null byte in the previous string. - /N - the reference to name string in long filenames list - name/ - the name - -BSD (Mac OS X) variant: - "__.SYMDEF" - archive symbol table - or - "__.SYMDEF SORTED" - archive symbol table - #1/N - the real filename of length N is appended to the file header. -*/ - -static const unsigned kSignatureLen = 8; -static const Byte kSignature[kSignatureLen] = - { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A }; - -static const unsigned kNameSize = 16; -static const unsigned kTimeSize = 12; -static const unsigned kUserSize = 6; -static const unsigned kModeSize = 8; -static const unsigned kSizeSize = 10; - -static const unsigned kHeaderSize = kNameSize + kTimeSize + kUserSize * 2 + kModeSize + kSizeSize + 1 + 1; - -enum EType -{ - kType_Ar, - kType_ALib, - kType_Deb, - kType_Lib -}; - -static const char * const k_TypeExtionsions[] = -{ - "ar" - , "a" - , "deb" - , "lib" -}; - -enum ESubType -{ - kSubType_None, - kSubType_BSD -}; - -/* -struct CHeader -{ - char Name[kNameSize]; - char MTime[kTimeSize]; - char User[kUserSize]; - char Group[kUserSize]; - char Mode[kModeSize]; - char Size[kSizeSize]; - char Quote; - char NewLine; -}; -*/ - -struct CItem -{ - AString Name; - UInt64 Size; - UInt32 MTime; - UInt32 User; - UInt32 Group; - UInt32 Mode; - - UInt64 HeaderPos; - UInt64 HeaderSize; - - int TextFileIndex; - int SameNameIndex; - - CItem(): TextFileIndex(-1), SameNameIndex(-1) {} - UInt64 GetDataPos() const { return HeaderPos + HeaderSize; } -}; - -class CInArchive -{ - CMyComPtr m_Stream; - -public: - UInt64 Position; - ESubType SubType; - - HRESULT GetNextItem(CItem &itemInfo, bool &filled); - HRESULT Open(IInStream *inStream); - HRESULT SkipData(UInt64 dataSize) - { - return m_Stream->Seek((Int64)(dataSize + (dataSize & 1)), STREAM_SEEK_CUR, &Position); - } -}; - -HRESULT CInArchive::Open(IInStream *inStream) -{ - SubType = kSubType_None; - RINOK(InStream_GetPos(inStream, Position)) - char signature[kSignatureLen]; - RINOK(ReadStream_FALSE(inStream, signature, kSignatureLen)) - Position += kSignatureLen; - if (memcmp(signature, kSignature, kSignatureLen) != 0) - return S_FALSE; - m_Stream = inStream; - return S_OK; -} - -static unsigned RemoveTailSpaces(char *dest, const char *s, unsigned size) -{ - memcpy(dest, s, size); - for (; size != 0; size--) - { - if (dest[size - 1] != ' ') - break; - } - dest[size] = 0; - return size; -} - -static bool OctalToNumber32(const char *s, unsigned size, UInt32 &res) -{ - res = 0; - char sz[32]; - size = RemoveTailSpaces(sz, s, size); - if (size == 0 || strcmp(sz, "-1") == 0) - return true; // some items don't contain any numbers - const char *end; - UInt64 res64 = ConvertOctStringToUInt64(sz, &end); - if ((unsigned)(end - sz) != size) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} - -static bool DecimalToNumber(const char *s, unsigned size, UInt64 &res) -{ - res = 0; - char sz[32]; - size = RemoveTailSpaces(sz, s, size); - if (size == 0 || strcmp(sz, "-1") == 0) - return true; // some items don't contain any numbers - const char *end; - res = ConvertStringToUInt64(sz, &end); - return ((unsigned)(end - sz) == size); -} - -static bool DecimalToNumber32(const char *s, unsigned size, UInt32 &res) -{ - UInt64 res64; - if (!DecimalToNumber(s, size, res64)) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} - -#define RIF(x) { if (!(x)) return S_FALSE; } - - -HRESULT CInArchive::GetNextItem(CItem &item, bool &filled) -{ - filled = false; - - char header[kHeaderSize]; - const char *cur = header; - - { - size_t processedSize = sizeof(header); - item.HeaderPos = Position; - item.HeaderSize = kHeaderSize; - RINOK(ReadStream(m_Stream, header, &processedSize)) - if (processedSize != sizeof(header)) - return S_OK; - if (header[kHeaderSize - 2] != 0x60 || - header[kHeaderSize - 1] != 0x0A) - return S_OK; - for (unsigned i = 0; i < kHeaderSize - 2; i++) - // if (header[i] < 0x20) - if (header[i] == 0) - return S_OK; - Position += processedSize; - } - - UInt32 longNameLen = 0; - if (cur[0] == '#' && - cur[1] == '1' && - cur[2] == '/' && - cur[3] != 0) - { - // BSD variant - RIF(DecimalToNumber32(cur + 3, kNameSize - 3 , longNameLen)) - if (longNameLen >= (1 << 12)) - longNameLen = 0; - } - else - { - char tempString[kNameSize + 1]; - RemoveTailSpaces(tempString, cur, kNameSize); - item.Name = tempString; - } - cur += kNameSize; - - RIF(DecimalToNumber32(cur, kTimeSize, item.MTime)) cur += kTimeSize; - RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize; - RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize; - RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize; - RIF(DecimalToNumber(cur, kSizeSize, item.Size)) cur += kSizeSize; - - if (longNameLen != 0 && longNameLen <= item.Size) - { - SubType = kSubType_BSD; - size_t processedSize = longNameLen; - char *s = item.Name.GetBuf(longNameLen); - HRESULT res = ReadStream(m_Stream, s, &processedSize); - item.Name.ReleaseBuf_CalcLen(longNameLen); - RINOK(res) - if (processedSize != longNameLen) - return S_OK; - item.Size -= longNameLen; - item.HeaderSize += longNameLen; - Position += processedSize; - } - - filled = true; - return S_OK; -} - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - bool _isArc; - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - Int32 _mainSubfile; - - EType _type; - ESubType _subType; - int _longNames_FileIndex; - unsigned _numLibFiles; - AString _errorMessage; - AString _libFiles[2]; - - void UpdateErrorMessage(const char *s); - - HRESULT ParseLongNames(IInStream *stream); - void ChangeDuplicateNames(); - int FindItem(UInt32 offset) const; - HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos); - HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex); -}; - -void CHandler::UpdateErrorMessage(const char *s) -{ - if (!_errorMessage.IsEmpty()) - _errorMessage.Add_LF(); - _errorMessage += s; -} - -static const Byte kArcProps[] = -{ - kpidSubType -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidMTime, - kpidPosixAttrib, - kpidUserId, - kpidGroupId -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -HRESULT CHandler::ParseLongNames(IInStream *stream) -{ - unsigned i; - for (i = 0; i < _items.Size(); i++) - if (_items[i].Name == "//") - break; - if (i == _items.Size()) - return S_OK; - - unsigned fileIndex = i; - const CItem &item = _items[fileIndex]; - if (item.Size > ((UInt32)1 << 30)) - return S_FALSE; - RINOK(InStream_SeekSet(stream, item.GetDataPos())) - const size_t size = (size_t)item.Size; - - CByteArr p(size); - RINOK(ReadStream_FALSE(stream, p, size)) - - for (i = 0; i < _items.Size(); i++) - { - CItem &item2 = _items[i]; - if (item2.Name[0] != '/') - continue; - const char *ptr = item2.Name.Ptr(1); - const char *end; - UInt32 pos = ConvertStringToUInt32(ptr, &end); - if (*end != 0 || end == ptr) - continue; - if (pos >= size) - continue; - UInt32 start = pos; - for (;;) - { - if (pos >= size) - return S_FALSE; - const Byte c = p[pos]; - if (c == 0 || c == 0x0A) - break; - pos++; - } - item2.Name.SetFrom((const char *)(p + start), (unsigned)(pos - start)); - } - - _longNames_FileIndex = (int)fileIndex; - return S_OK; -} - -void CHandler::ChangeDuplicateNames() -{ - unsigned i; - for (i = 1; i < _items.Size(); i++) - { - CItem &item = _items[i]; - if (item.Name[0] == '/') - continue; - CItem &prev = _items[i - 1]; - if (item.Name == prev.Name) - { - if (prev.SameNameIndex < 0) - prev.SameNameIndex = 0; - item.SameNameIndex = prev.SameNameIndex + 1; - } - } - for (i = 0; i < _items.Size(); i++) - { - CItem &item = _items[i]; - if (item.SameNameIndex < 0) - continue; - char sz[32]; - ConvertUInt32ToString((unsigned)item.SameNameIndex + 1, sz); - unsigned len = MyStringLen(sz); - sz[len++] = '.'; - sz[len] = 0; - item.Name.Insert(0, sz); - } -} - -int CHandler::FindItem(UInt32 offset) const -{ - unsigned left = 0, right = _items.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const UInt64 midVal = _items[mid].HeaderPos; - if (offset == midVal) - return (int)mid; - if (offset < midVal) - right = mid; - else - left = mid + 1; - } - return -1; -} - -HRESULT CHandler::AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos) -{ - const int fileIndex = FindItem(offset); - if (fileIndex < (int)0) - return S_FALSE; - - size_t i = pos; - do - { - if (i >= size) - return S_FALSE; - } - while (data[i++] != 0); - - AString &s = _libFiles[_numLibFiles]; - const AString &name = _items[(unsigned)fileIndex].Name; - s += name; - if (!name.IsEmpty() && name.Back() == '/') - s.DeleteBack(); - s += " "; - s += (const char *)(data + pos); - // s.Add_Char((char)0xD); - s.Add_LF(); - pos = i; - return S_OK; -} - -static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); return GetUi32(p); } - -HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) -{ - CItem &item = _items[fileIndex]; - if (item.Name != "/" && - item.Name != "__.SYMDEF" && - item.Name != "__.SYMDEF SORTED") - return S_OK; - if (item.Size > ((UInt32)1 << 30) || - item.Size < 4) - return S_OK; - RINOK(InStream_SeekSet(stream, item.GetDataPos())) - size_t size = (size_t)item.Size; - CByteArr p(size); - RINOK(ReadStream_FALSE(stream, p, size)) - - size_t pos = 0; - - if (item.Name != "/") - { - // "__.SYMDEF" parsing (BSD) - unsigned be; - for (be = 0; be < 2; be++) - { - const UInt32 tableSize = Get32(p, be); - pos = 4; - if (size - pos < tableSize || (tableSize & 7) != 0) - continue; - size_t namesStart = pos + tableSize; - const UInt32 namesSize = Get32(p.ConstData() + namesStart, be); - namesStart += 4; - if (namesStart > size || namesStart + namesSize != size) - continue; - - const UInt32 numSymbols = tableSize >> 3; - UInt32 i; - for (i = 0; i < numSymbols; i++, pos += 8) - { - size_t namePos = Get32(p + pos, be); - const UInt32 offset = Get32(p + pos + 4, be); - if (AddFunc(offset, p + namesStart, namesSize, namePos) != S_OK) - break; - } - if (i == numSymbols) - { - pos = size; - _type = kType_ALib; - _subType = kSubType_BSD; - break; - } - } - if (be == 2) - return S_FALSE; - } - else if (_numLibFiles == 0) - { - // archive symbol table (GNU) - const UInt32 numSymbols = GetBe32(p); - pos = 4; - if (numSymbols > (size - pos) / 4) - return S_FALSE; - pos += 4 * numSymbols; - - for (UInt32 i = 0; i < numSymbols; i++) - { - const UInt32 offset = GetBe32(p + 4 + i * 4); - RINOK(AddFunc(offset, p, size, pos)) - } - _type = kType_ALib; - } - else - { - // Second linker file (Microsoft .lib) - const UInt32 numMembers = GetUi32(p); - pos = 4; - if (numMembers > (size - pos) / 4) - return S_FALSE; - pos += 4 * numMembers; - - if (size - pos < 4) - return S_FALSE; - const UInt32 numSymbols = GetUi32(p + pos); - pos += 4; - if (numSymbols > (size - pos) / 2) - return S_FALSE; - size_t indexStart = pos; - pos += 2 * numSymbols; - - for (UInt32 i = 0; i < numSymbols; i++) - { - // index is 1-based. So 32-bit numSymbols field works as item[0] - const UInt32 index = GetUi16(p + indexStart + i * 2); - if (index == 0 || index > numMembers) - return S_FALSE; - const UInt32 offset = GetUi32(p + index * 4); - RINOK(AddFunc(offset, p, size, pos)) - } - _type = kType_Lib; - } - // size can be 2-byte aligned in linux files - if (pos != size && pos + (pos & 1) != size) - return S_FALSE; - item.TextFileIndex = (int)(_numLibFiles++); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - - UInt64 fileSize; - RINOK(InStream_AtBegin_GetSize(stream, fileSize)) - - CInArchive arc; - RINOK(arc.Open(stream)) - - if (callback) - { - RINOK(callback->SetTotal(NULL, &fileSize)) - const UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &arc.Position)) - } - - CItem item; - for (;;) - { - bool filled; - RINOK(arc.GetNextItem(item, filled)) - if (!filled) - break; - _items.Add(item); - arc.SkipData(item.Size); - if (callback && (_items.Size() & 0xFF) == 0) - { - const UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &arc.Position)) - } - } - - if (_items.IsEmpty()) - { - // we don't need false empty archives (8-bytes signature only) - if (arc.Position != fileSize) - return S_FALSE; - } - - _isArc = true; - - _subType = arc.SubType; - - if (ParseLongNames(stream) != S_OK) - UpdateErrorMessage("Long file names parsing error"); - if (_longNames_FileIndex >= 0) - _items.Delete((unsigned)_longNames_FileIndex); - - if (!_items.IsEmpty() && _items[0].Name == "debian-binary") - { - _type = kType_Deb; - _items.DeleteFrontal(1); - for (unsigned i = 0; i < _items.Size(); i++) - if (_items[i].Name.IsPrefixedBy("data.tar.")) - { - if (_mainSubfile < 0) - _mainSubfile = (int)i; - else - { - _mainSubfile = -1; - break; - } - } - } - else - { - ChangeDuplicateNames(); - bool error = false; - for (unsigned li = 0; li < 2 && li < _items.Size(); li++) - if (ParseLibSymbols(stream, li) != S_OK) - error = true; - if (error) - UpdateErrorMessage("Library symbols information error"); - } - - _stream = stream; - _phySize = arc.Position; - - /* - if (fileSize < _phySize) - UpdateErrorMessage("Unexpected end of archive"); - */ - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _phySize = 0; - - _errorMessage.Empty(); - _stream.Release(); - _items.Clear(); - - _type = kType_Ar; - _subType = kSubType_None; - _mainSubfile = -1; - _longNames_FileIndex = -1; - - _numLibFiles = 0; - _libFiles[0].Empty(); - _libFiles[1].Empty(); - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _phySize; break; - case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; - case kpidExtension: prop = k_TypeExtionsions[(unsigned)_type]; break; - case kpidShortComment: - case kpidSubType: - { - AString s (k_TypeExtionsions[(unsigned)_type]); - if (_subType == kSubType_BSD) - s += ":BSD"; - prop = s; - break; - } - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - prop = v; - break; - } - case kpidWarning: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; - case kpidIsNotArcType: if (_type != kType_Deb) prop = true; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch (propID) - { - case kpidPath: - if (item.TextFileIndex >= 0) - prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt"; - else - prop = (const wchar_t *)NItemName::GetOsPath_Remove_TailSlash(MultiByteToUnicodeString(item.Name, CP_OEMCP)); - break; - case kpidSize: - case kpidPackSize: - if (item.TextFileIndex >= 0) - prop = (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len(); - else - prop = item.Size; - break; - case kpidMTime: - { - if (item.MTime != 0) - PropVariant_SetFrom_UnixTime(prop, item.MTime); - break; - } - case kpidUserId: if (item.User != 0) prop = item.User; break; - case kpidGroupId: if (item.Group != 0) prop = item.Group; break; - case kpidPosixAttrib: - if (item.TextFileIndex < 0) - prop = item.Mode; - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItem &item = _items[allFilesMode ? i : indices[i]]; - totalSize += - (item.TextFileIndex >= 0) ? - (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size; - } - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - - for (i = 0;; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - currentTotalSize += (item.TextFileIndex >= 0) ? - (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - if (testMode) - { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - opRes = NExtract::NOperationResult::kOK; - if (item.TextFileIndex >= 0) - { - const AString &f = _libFiles[(unsigned)item.TextFileIndex]; - if (realOutStream) - RINOK(WriteStream(realOutStream, f, f.Len())) - } - else - { - RINOK(InStream_SeekSet(_stream, item.GetDataPos())) - inStream->Init(item.Size); - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != item.Size) - opRes = NExtract::NOperationResult::kDataError; - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - const CItem &item = _items[index]; - if (item.TextFileIndex >= 0) - { - const AString &f = _libFiles[(unsigned)item.TextFileIndex]; - Create_BufInStream_WithNewBuffer((const void *)(const char *)f, f.Len(), stream); - return S_OK; - } - else - return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream); - COM_TRY_END -} - -REGISTER_ARC_I( - "Ar", "ar a deb udeb lib", NULL, 0xEC, - kSignature, - 0, - 0, - NULL) - -}} +// ArHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/StringToInt.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NAr { + +/* +The end of each file member (including last file in archive) is 2-bytes aligned. +It uses 0xA padding if required. + +File Names: + +GNU/SVR4 variant (.a static library): + / - archive symbol table + // - the list of the long filenames, separated by one or more LF characters. + /N - the reference to name string in long filenames list + name/ - the name + +Microsoft variant (.lib static library): + / - First linker file (archive symbol table) + / - Second linker file + // - the list of the long filenames, null-terminated. Each string begins + immediately after the null byte in the previous string. + /N - the reference to name string in long filenames list + name/ - the name + +BSD (Mac OS X) variant: + "__.SYMDEF" - archive symbol table + or + "__.SYMDEF SORTED" - archive symbol table + #1/N - the real filename of length N is appended to the file header. +*/ + +static const unsigned kSignatureLen = 8; +static const Byte kSignature[kSignatureLen] = + { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A }; + +static const unsigned kNameSize = 16; +static const unsigned kTimeSize = 12; +static const unsigned kUserSize = 6; +static const unsigned kModeSize = 8; +static const unsigned kSizeSize = 10; + +static const unsigned kHeaderSize = kNameSize + kTimeSize + kUserSize * 2 + kModeSize + kSizeSize + 1 + 1; + +enum EType +{ + kType_Ar, + kType_ALib, + kType_Deb, + kType_Lib +}; + +static const char * const k_TypeExtionsions[] = +{ + "ar" + , "a" + , "deb" + , "lib" +}; + +enum ESubType +{ + kSubType_None, + kSubType_BSD +}; + +/* +struct CHeader +{ + char Name[kNameSize]; + char MTime[kTimeSize]; + char User[kUserSize]; + char Group[kUserSize]; + char Mode[kModeSize]; + char Size[kSizeSize]; + char Quote; + char NewLine; +}; +*/ + +struct CItem +{ + AString Name; + UInt64 Size; + UInt32 MTime; + UInt32 User; + UInt32 Group; + UInt32 Mode; + + UInt64 HeaderPos; + UInt64 HeaderSize; + + int TextFileIndex; + int SameNameIndex; + + CItem(): TextFileIndex(-1), SameNameIndex(-1) {} + UInt64 GetDataPos() const { return HeaderPos + HeaderSize; } +}; + +class CInArchive +{ + CMyComPtr m_Stream; + +public: + UInt64 Position; + ESubType SubType; + + HRESULT GetNextItem(CItem &itemInfo, bool &filled); + HRESULT Open(IInStream *inStream); + HRESULT SkipData(UInt64 dataSize) + { + return m_Stream->Seek((Int64)(dataSize + (dataSize & 1)), STREAM_SEEK_CUR, &Position); + } +}; + +HRESULT CInArchive::Open(IInStream *inStream) +{ + SubType = kSubType_None; + RINOK(InStream_GetPos(inStream, Position)) + char signature[kSignatureLen]; + RINOK(ReadStream_FALSE(inStream, signature, kSignatureLen)) + Position += kSignatureLen; + if (memcmp(signature, kSignature, kSignatureLen) != 0) + return S_FALSE; + m_Stream = inStream; + return S_OK; +} + +static unsigned RemoveTailSpaces(char *dest, const char *s, unsigned size) +{ + memcpy(dest, s, size); + for (; size != 0; size--) + { + if (dest[size - 1] != ' ') + break; + } + dest[size] = 0; + return size; +} + +static bool OctalToNumber32(const char *s, unsigned size, UInt32 &res) +{ + res = 0; + char sz[32]; + size = RemoveTailSpaces(sz, s, size); + if (size == 0 || strcmp(sz, "-1") == 0) + return true; // some items don't contain any numbers + const char *end; + UInt64 res64 = ConvertOctStringToUInt64(sz, &end); + if ((unsigned)(end - sz) != size) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +static bool DecimalToNumber(const char *s, unsigned size, UInt64 &res) +{ + res = 0; + char sz[32]; + size = RemoveTailSpaces(sz, s, size); + if (size == 0 || strcmp(sz, "-1") == 0) + return true; // some items don't contain any numbers + const char *end; + res = ConvertStringToUInt64(sz, &end); + return ((unsigned)(end - sz) == size); +} + +static bool DecimalToNumber32(const char *s, unsigned size, UInt32 &res) +{ + UInt64 res64; + if (!DecimalToNumber(s, size, res64)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + + +HRESULT CInArchive::GetNextItem(CItem &item, bool &filled) +{ + filled = false; + + char header[kHeaderSize]; + const char *cur = header; + + { + size_t processedSize = sizeof(header); + item.HeaderPos = Position; + item.HeaderSize = kHeaderSize; + RINOK(ReadStream(m_Stream, header, &processedSize)) + if (processedSize != sizeof(header)) + return S_OK; + if (header[kHeaderSize - 2] != 0x60 || + header[kHeaderSize - 1] != 0x0A) + return S_OK; + for (unsigned i = 0; i < kHeaderSize - 2; i++) + // if (header[i] < 0x20) + if (header[i] == 0) + return S_OK; + Position += processedSize; + } + + UInt32 longNameLen = 0; + if (cur[0] == '#' && + cur[1] == '1' && + cur[2] == '/' && + cur[3] != 0) + { + // BSD variant + RIF(DecimalToNumber32(cur + 3, kNameSize - 3 , longNameLen)) + if (longNameLen >= (1 << 12)) + longNameLen = 0; + } + else + { + char tempString[kNameSize + 1]; + RemoveTailSpaces(tempString, cur, kNameSize); + item.Name = tempString; + } + cur += kNameSize; + + RIF(DecimalToNumber32(cur, kTimeSize, item.MTime)) cur += kTimeSize; + RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize; + RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize; + RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize; + RIF(DecimalToNumber(cur, kSizeSize, item.Size)) cur += kSizeSize; + + if (longNameLen != 0 && longNameLen <= item.Size) + { + SubType = kSubType_BSD; + size_t processedSize = longNameLen; + char *s = item.Name.GetBuf(longNameLen); + HRESULT res = ReadStream(m_Stream, s, &processedSize); + item.Name.ReleaseBuf_CalcLen(longNameLen); + RINOK(res) + if (processedSize != longNameLen) + return S_OK; + item.Size -= longNameLen; + item.HeaderSize += longNameLen; + Position += processedSize; + } + + filled = true; + return S_OK; +} + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + bool _isArc; + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + Int32 _mainSubfile; + + EType _type; + ESubType _subType; + int _longNames_FileIndex; + unsigned _numLibFiles; + AString _errorMessage; + AString _libFiles[2]; + + void UpdateErrorMessage(const char *s); + + HRESULT ParseLongNames(IInStream *stream); + void ChangeDuplicateNames(); + int FindItem(UInt32 offset) const; + HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos); + HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex); +}; + +void CHandler::UpdateErrorMessage(const char *s) +{ + if (!_errorMessage.IsEmpty()) + _errorMessage.Add_LF(); + _errorMessage += s; +} + +static const Byte kArcProps[] = +{ + kpidSubType +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidMTime, + kpidPosixAttrib, + kpidUserId, + kpidGroupId +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +HRESULT CHandler::ParseLongNames(IInStream *stream) +{ + unsigned i; + for (i = 0; i < _items.Size(); i++) + if (_items[i].Name == "//") + break; + if (i == _items.Size()) + return S_OK; + + unsigned fileIndex = i; + const CItem &item = _items[fileIndex]; + if (item.Size > ((UInt32)1 << 30)) + return S_FALSE; + RINOK(InStream_SeekSet(stream, item.GetDataPos())) + const size_t size = (size_t)item.Size; + + CByteArr p(size); + RINOK(ReadStream_FALSE(stream, p, size)) + + for (i = 0; i < _items.Size(); i++) + { + CItem &item2 = _items[i]; + if (item2.Name[0] != '/') + continue; + const char *ptr = item2.Name.Ptr(1); + const char *end; + UInt32 pos = ConvertStringToUInt32(ptr, &end); + if (*end != 0 || end == ptr) + continue; + if (pos >= size) + continue; + UInt32 start = pos; + for (;;) + { + if (pos >= size) + return S_FALSE; + const Byte c = p[pos]; + if (c == 0 || c == 0x0A) + break; + pos++; + } + item2.Name.SetFrom((const char *)(p + start), (unsigned)(pos - start)); + } + + _longNames_FileIndex = (int)fileIndex; + return S_OK; +} + +void CHandler::ChangeDuplicateNames() +{ + unsigned i; + for (i = 1; i < _items.Size(); i++) + { + CItem &item = _items[i]; + if (item.Name[0] == '/') + continue; + CItem &prev = _items[i - 1]; + if (item.Name == prev.Name) + { + if (prev.SameNameIndex < 0) + prev.SameNameIndex = 0; + item.SameNameIndex = prev.SameNameIndex + 1; + } + } + for (i = 0; i < _items.Size(); i++) + { + CItem &item = _items[i]; + if (item.SameNameIndex < 0) + continue; + char sz[32]; + ConvertUInt32ToString((unsigned)item.SameNameIndex + 1, sz); + unsigned len = MyStringLen(sz); + sz[len++] = '.'; + sz[len] = 0; + item.Name.Insert(0, sz); + } +} + +int CHandler::FindItem(UInt32 offset) const +{ + unsigned left = 0, right = _items.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const UInt64 midVal = _items[mid].HeaderPos; + if (offset == midVal) + return (int)mid; + if (offset < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +HRESULT CHandler::AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos) +{ + const int fileIndex = FindItem(offset); + if (fileIndex < (int)0) + return S_FALSE; + + size_t i = pos; + do + { + if (i >= size) + return S_FALSE; + } + while (data[i++] != 0); + + AString &s = _libFiles[_numLibFiles]; + const AString &name = _items[(unsigned)fileIndex].Name; + s += name; + if (!name.IsEmpty() && name.Back() == '/') + s.DeleteBack(); + s += " "; + s += (const char *)(data + pos); + // s.Add_Char((char)0xD); + s.Add_LF(); + pos = i; + return S_OK; +} + +static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); return GetUi32(p); } + +HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex) +{ + CItem &item = _items[fileIndex]; + if (item.Name != "/" && + item.Name != "__.SYMDEF" && + item.Name != "__.SYMDEF SORTED") + return S_OK; + if (item.Size > ((UInt32)1 << 30) || + item.Size < 4) + return S_OK; + RINOK(InStream_SeekSet(stream, item.GetDataPos())) + size_t size = (size_t)item.Size; + CByteArr p(size); + RINOK(ReadStream_FALSE(stream, p, size)) + + size_t pos = 0; + + if (item.Name != "/") + { + // "__.SYMDEF" parsing (BSD) + unsigned be; + for (be = 0; be < 2; be++) + { + const UInt32 tableSize = Get32(p, be); + pos = 4; + if (size - pos < tableSize || (tableSize & 7) != 0) + continue; + size_t namesStart = pos + tableSize; + const UInt32 namesSize = Get32(p.ConstData() + namesStart, be); + namesStart += 4; + if (namesStart > size || namesStart + namesSize != size) + continue; + + const UInt32 numSymbols = tableSize >> 3; + UInt32 i; + for (i = 0; i < numSymbols; i++, pos += 8) + { + size_t namePos = Get32(p + pos, be); + const UInt32 offset = Get32(p + pos + 4, be); + if (AddFunc(offset, p + namesStart, namesSize, namePos) != S_OK) + break; + } + if (i == numSymbols) + { + pos = size; + _type = kType_ALib; + _subType = kSubType_BSD; + break; + } + } + if (be == 2) + return S_FALSE; + } + else if (_numLibFiles == 0) + { + // archive symbol table (GNU) + const UInt32 numSymbols = GetBe32(p); + pos = 4; + if (numSymbols > (size - pos) / 4) + return S_FALSE; + pos += 4 * numSymbols; + + for (UInt32 i = 0; i < numSymbols; i++) + { + const UInt32 offset = GetBe32(p + 4 + i * 4); + RINOK(AddFunc(offset, p, size, pos)) + } + _type = kType_ALib; + } + else + { + // Second linker file (Microsoft .lib) + const UInt32 numMembers = GetUi32(p); + pos = 4; + if (numMembers > (size - pos) / 4) + return S_FALSE; + pos += 4 * numMembers; + + if (size - pos < 4) + return S_FALSE; + const UInt32 numSymbols = GetUi32(p + pos); + pos += 4; + if (numSymbols > (size - pos) / 2) + return S_FALSE; + size_t indexStart = pos; + pos += 2 * numSymbols; + + for (UInt32 i = 0; i < numSymbols; i++) + { + // index is 1-based. So 32-bit numSymbols field works as item[0] + const UInt32 index = GetUi16(p + indexStart + i * 2); + if (index == 0 || index > numMembers) + return S_FALSE; + const UInt32 offset = GetUi32(p + index * 4); + RINOK(AddFunc(offset, p, size, pos)) + } + _type = kType_Lib; + } + // size can be 2-byte aligned in linux files + if (pos != size && pos + (pos & 1) != size) + return S_FALSE; + item.TextFileIndex = (int)(_numLibFiles++); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + + UInt64 fileSize; + RINOK(InStream_AtBegin_GetSize(stream, fileSize)) + + CInArchive arc; + RINOK(arc.Open(stream)) + + if (callback) + { + RINOK(callback->SetTotal(NULL, &fileSize)) + const UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &arc.Position)) + } + + CItem item; + for (;;) + { + bool filled; + RINOK(arc.GetNextItem(item, filled)) + if (!filled) + break; + _items.Add(item); + arc.SkipData(item.Size); + if (callback && (_items.Size() & 0xFF) == 0) + { + const UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &arc.Position)) + } + } + + if (_items.IsEmpty()) + { + // we don't need false empty archives (8-bytes signature only) + if (arc.Position != fileSize) + return S_FALSE; + } + + _isArc = true; + + _subType = arc.SubType; + + if (ParseLongNames(stream) != S_OK) + UpdateErrorMessage("Long file names parsing error"); + if (_longNames_FileIndex >= 0) + _items.Delete((unsigned)_longNames_FileIndex); + + if (!_items.IsEmpty() && _items[0].Name == "debian-binary") + { + _type = kType_Deb; + _items.DeleteFrontal(1); + for (unsigned i = 0; i < _items.Size(); i++) + if (_items[i].Name.IsPrefixedBy("data.tar.")) + { + if (_mainSubfile < 0) + _mainSubfile = (int)i; + else + { + _mainSubfile = -1; + break; + } + } + } + else + { + ChangeDuplicateNames(); + bool error = false; + for (unsigned li = 0; li < 2 && li < _items.Size(); li++) + if (ParseLibSymbols(stream, li) != S_OK) + error = true; + if (error) + UpdateErrorMessage("Library symbols information error"); + } + + _stream = stream; + _phySize = arc.Position; + + /* + if (fileSize < _phySize) + UpdateErrorMessage("Unexpected end of archive"); + */ + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _phySize = 0; + + _errorMessage.Empty(); + _stream.Release(); + _items.Clear(); + + _type = kType_Ar; + _subType = kSubType_None; + _mainSubfile = -1; + _longNames_FileIndex = -1; + + _numLibFiles = 0; + _libFiles[0].Empty(); + _libFiles[1].Empty(); + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + case kpidExtension: prop = k_TypeExtionsions[(unsigned)_type]; break; + case kpidShortComment: + case kpidSubType: + { + AString s (k_TypeExtionsions[(unsigned)_type]); + if (_subType == kSubType_BSD) + s += ":BSD"; + prop = s; + break; + } + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + case kpidWarning: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + case kpidIsNotArcType: if (_type != kType_Deb) prop = true; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: + if (item.TextFileIndex >= 0) + prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt"; + else + prop = (const wchar_t *)NItemName::GetOsPath_Remove_TailSlash(MultiByteToUnicodeString(item.Name, CP_OEMCP)); + break; + case kpidSize: + case kpidPackSize: + if (item.TextFileIndex >= 0) + prop = (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len(); + else + prop = item.Size; + break; + case kpidMTime: + { + if (item.MTime != 0) + PropVariant_SetFrom_UnixTime(prop, item.MTime); + break; + } + case kpidUserId: if (item.User != 0) prop = item.User; break; + case kpidGroupId: if (item.Group != 0) prop = item.Group; break; + case kpidPosixAttrib: + if (item.TextFileIndex < 0) + prop = item.Mode; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItem &item = _items[allFilesMode ? i : indices[i]]; + totalSize += + (item.TextFileIndex >= 0) ? + (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size; + } + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + + for (i = 0;; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + currentTotalSize += (item.TextFileIndex >= 0) ? + (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + if (testMode) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + opRes = NExtract::NOperationResult::kOK; + if (item.TextFileIndex >= 0) + { + const AString &f = _libFiles[(unsigned)item.TextFileIndex]; + if (realOutStream) + RINOK(WriteStream(realOutStream, f, f.Len())) + } + else + { + RINOK(InStream_SeekSet(_stream, item.GetDataPos())) + inStream->Init(item.Size); + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != item.Size) + opRes = NExtract::NOperationResult::kDataError; + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + const CItem &item = _items[index]; + if (item.TextFileIndex >= 0) + { + const AString &f = _libFiles[(unsigned)item.TextFileIndex]; + Create_BufInStream_WithNewBuffer((const void *)(const char *)f, f.Len(), stream); + return S_OK; + } + else + return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream); + COM_TRY_END +} + +REGISTER_ARC_I( + "Ar", "ar a deb udeb lib", NULL, 0xEC, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def index be6e1560a..2ed624623 100644 --- a/CPP/7zip/Archive/Archive.def +++ b/CPP/7zip/Archive/Archive.def @@ -1,14 +1,14 @@ -EXPORTS - CreateObject PRIVATE - - GetHandlerProperty PRIVATE - GetNumberOfFormats PRIVATE - GetHandlerProperty2 PRIVATE - GetIsArc PRIVATE - - SetCodecs PRIVATE - - SetLargePageMode PRIVATE - SetCaseSensitive PRIVATE - - GetModuleProp PRIVATE +EXPORTS + CreateObject PRIVATE + + GetHandlerProperty PRIVATE + GetNumberOfFormats PRIVATE + GetHandlerProperty2 PRIVATE + GetIsArc PRIVATE + + SetCodecs PRIVATE + + SetLargePageMode PRIVATE + SetCaseSensitive PRIVATE + + GetModuleProp PRIVATE diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def index 172e8f85d..f891ad3b8 100644 --- a/CPP/7zip/Archive/Archive2.def +++ b/CPP/7zip/Archive/Archive2.def @@ -1,21 +1,21 @@ -EXPORTS - CreateObject PRIVATE - - GetHandlerProperty PRIVATE - GetNumberOfFormats PRIVATE - GetHandlerProperty2 PRIVATE - GetIsArc PRIVATE - - GetNumberOfMethods PRIVATE - GetMethodProperty PRIVATE - CreateDecoder PRIVATE - CreateEncoder PRIVATE - - GetHashers PRIVATE - - SetCodecs PRIVATE - - SetLargePageMode PRIVATE - SetCaseSensitive PRIVATE - - GetModuleProp PRIVATE +EXPORTS + CreateObject PRIVATE + + GetHandlerProperty PRIVATE + GetNumberOfFormats PRIVATE + GetHandlerProperty2 PRIVATE + GetIsArc PRIVATE + + GetNumberOfMethods PRIVATE + GetMethodProperty PRIVATE + CreateDecoder PRIVATE + CreateEncoder PRIVATE + + GetHashers PRIVATE + + SetCodecs PRIVATE + + SetLargePageMode PRIVATE + SetCaseSensitive PRIVATE + + GetModuleProp PRIVATE diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp index f9829f257..4735fcfff 100644 --- a/CPP/7zip/Archive/ArchiveExports.cpp +++ b/CPP/7zip/Archive/ArchiveExports.cpp @@ -1,158 +1,158 @@ -// ArchiveExports.cpp - -#include "StdAfx.h" - -#include "../../../C/7zVersion.h" - -#include "../../Common/ComTry.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" - -static const unsigned kNumArcsMax = 72; -static unsigned g_NumArcs = 0; -static unsigned g_DefaultArcIndex = 0; -static const CArcInfo *g_Arcs[kNumArcsMax]; - -void RegisterArc(const CArcInfo *arcInfo) throw() -{ - if (g_NumArcs < kNumArcsMax) - { - const char *p = arcInfo->Name; - if (p[0] == '7' && p[1] == 'z' && p[2] == 0) - g_DefaultArcIndex = g_NumArcs; - g_Arcs[g_NumArcs++] = arcInfo; - } - // else throw 1; -} - -Z7_DEFINE_GUID(CLSID_CArchiveHandler, - k_7zip_GUID_Data1, - k_7zip_GUID_Data2, - k_7zip_GUID_Data3_Common, - 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); - -#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5]) - -static inline HRESULT SetPropStrFromBin(const char *s, unsigned size, PROPVARIANT *value) -{ - if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != NULL) - value->vt = VT_BSTR; - return S_OK; -} - -static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) -{ - return SetPropStrFromBin((const char *)&guid, sizeof(guid), value); -} - -static int FindFormatCalssId(const GUID *clsid) -{ - GUID cls = *clsid; - CLS_ARC_ID_ITEM(cls) = 0; - if (cls != CLSID_CArchiveHandler) - return -1; - const Byte id = CLS_ARC_ID_ITEM(*clsid); - for (unsigned i = 0; i < g_NumArcs; i++) - if (g_Arcs[i]->Id == id) - return (int)i; - return -1; -} - -STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject); -STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject) -{ - COM_TRY_BEGIN - { - const int needIn = (*iid == IID_IInArchive); - const int needOut = (*iid == IID_IOutArchive); - if (!needIn && !needOut) - return E_NOINTERFACE; - const int formatIndex = FindFormatCalssId(clsid); - if (formatIndex < 0) - return CLASS_E_CLASSNOTAVAILABLE; - - const CArcInfo &arc = *g_Arcs[formatIndex]; - if (needIn) - { - *outObject = arc.CreateInArchive(); - ((IInArchive *)*outObject)->AddRef(); - } - else - { - if (!arc.CreateOutArchive) - return CLASS_E_CLASSNOTAVAILABLE; - *outObject = arc.CreateOutArchive(); - ((IOutArchive *)*outObject)->AddRef(); - } - } - COM_TRY_END - return S_OK; -} - -STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value); -STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value) -{ - COM_TRY_BEGIN - NWindows::NCOM::PropVariant_Clear(value); - if (formatIndex >= g_NumArcs) - return E_INVALIDARG; - const CArcInfo &arc = *g_Arcs[formatIndex]; - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case NArchive::NHandlerPropID::kName: prop = arc.Name; break; - case NArchive::NHandlerPropID::kClassID: - { - GUID clsId = CLSID_CArchiveHandler; - CLS_ARC_ID_ITEM(clsId) = arc.Id; - return SetPropGUID(clsId, value); - } - case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break; - case NArchive::NHandlerPropID::kAddExtension: if (arc.AddExt) prop = arc.AddExt; break; - case NArchive::NHandlerPropID::kUpdate: prop = (bool)(arc.CreateOutArchive != NULL); break; - case NArchive::NHandlerPropID::kKeepName: prop = ((arc.Flags & NArcInfoFlags::kKeepName) != 0); break; - case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break; - case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break; - case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break; - case NArchive::NHandlerPropID::kTimeFlags: prop = (UInt32)arc.TimeFlags; break; - case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break; - // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break; - - case NArchive::NHandlerPropID::kSignature: - if (arc.SignatureSize != 0 && !arc.IsMultiSignature()) - return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value); - break; - case NArchive::NHandlerPropID::kMultiSignature: - if (arc.SignatureSize != 0 && arc.IsMultiSignature()) - return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value); - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value); -STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value) -{ - return GetHandlerProperty2(g_DefaultArcIndex, propID, value); -} - -STDAPI GetNumberOfFormats(UINT32 *numFormats); -STDAPI GetNumberOfFormats(UINT32 *numFormats) -{ - *numFormats = g_NumArcs; - return S_OK; -} - -STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc); -STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc) -{ - *isArc = NULL; - if (formatIndex >= g_NumArcs) - return E_INVALIDARG; - *isArc = g_Arcs[formatIndex]->IsArc; - return S_OK; -} +// ArchiveExports.cpp + +#include "StdAfx.h" + +#include "../../../C/7zVersion.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" + +static const unsigned kNumArcsMax = 72; +static unsigned g_NumArcs = 0; +static unsigned g_DefaultArcIndex = 0; +static const CArcInfo *g_Arcs[kNumArcsMax]; + +void RegisterArc(const CArcInfo *arcInfo) throw() +{ + if (g_NumArcs < kNumArcsMax) + { + const char *p = arcInfo->Name; + if (p[0] == '7' && p[1] == 'z' && p[2] == 0) + g_DefaultArcIndex = g_NumArcs; + g_Arcs[g_NumArcs++] = arcInfo; + } + // else throw 1; +} + +Z7_DEFINE_GUID(CLSID_CArchiveHandler, + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); + +#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5]) + +static inline HRESULT SetPropStrFromBin(const char *s, unsigned size, PROPVARIANT *value) +{ + if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != NULL) + value->vt = VT_BSTR; + return S_OK; +} + +static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) +{ + return SetPropStrFromBin((const char *)&guid, sizeof(guid), value); +} + +static int FindFormatCalssId(const GUID *clsid) +{ + GUID cls = *clsid; + CLS_ARC_ID_ITEM(cls) = 0; + if (cls != CLSID_CArchiveHandler) + return -1; + const Byte id = CLS_ARC_ID_ITEM(*clsid); + for (unsigned i = 0; i < g_NumArcs; i++) + if (g_Arcs[i]->Id == id) + return (int)i; + return -1; +} + +STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject) +{ + COM_TRY_BEGIN + { + const int needIn = (*iid == IID_IInArchive); + const int needOut = (*iid == IID_IOutArchive); + if (!needIn && !needOut) + return E_NOINTERFACE; + const int formatIndex = FindFormatCalssId(clsid); + if (formatIndex < 0) + return CLASS_E_CLASSNOTAVAILABLE; + + const CArcInfo &arc = *g_Arcs[formatIndex]; + if (needIn) + { + *outObject = arc.CreateInArchive(); + ((IInArchive *)*outObject)->AddRef(); + } + else + { + if (!arc.CreateOutArchive) + return CLASS_E_CLASSNOTAVAILABLE; + *outObject = arc.CreateOutArchive(); + ((IOutArchive *)*outObject)->AddRef(); + } + } + COM_TRY_END + return S_OK; +} + +STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value); +STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::PropVariant_Clear(value); + if (formatIndex >= g_NumArcs) + return E_INVALIDARG; + const CArcInfo &arc = *g_Arcs[formatIndex]; + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case NArchive::NHandlerPropID::kName: prop = arc.Name; break; + case NArchive::NHandlerPropID::kClassID: + { + GUID clsId = CLSID_CArchiveHandler; + CLS_ARC_ID_ITEM(clsId) = arc.Id; + return SetPropGUID(clsId, value); + } + case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break; + case NArchive::NHandlerPropID::kAddExtension: if (arc.AddExt) prop = arc.AddExt; break; + case NArchive::NHandlerPropID::kUpdate: prop = (bool)(arc.CreateOutArchive != NULL); break; + case NArchive::NHandlerPropID::kKeepName: prop = ((arc.Flags & NArcInfoFlags::kKeepName) != 0); break; + case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break; + case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break; + case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break; + case NArchive::NHandlerPropID::kTimeFlags: prop = (UInt32)arc.TimeFlags; break; + case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break; + // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break; + + case NArchive::NHandlerPropID::kSignature: + if (arc.SignatureSize != 0 && !arc.IsMultiSignature()) + return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value); + break; + case NArchive::NHandlerPropID::kMultiSignature: + if (arc.SignatureSize != 0 && arc.IsMultiSignature()) + return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value); + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value); +STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value) +{ + return GetHandlerProperty2(g_DefaultArcIndex, propID, value); +} + +STDAPI GetNumberOfFormats(UINT32 *numFormats); +STDAPI GetNumberOfFormats(UINT32 *numFormats) +{ + *numFormats = g_NumArcs; + return S_OK; +} + +STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc); +STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc) +{ + *isArc = NULL; + if (formatIndex >= g_NumArcs) + return E_INVALIDARG; + *isArc = g_Arcs[formatIndex]->IsArc; + return S_OK; +} diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index ddbaaf646..1d641e4b3 100644 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -1,978 +1,978 @@ -// ArjHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/AutoPtr.h" -#include "../../Common/ComTry.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/LzhDecoder.h" - -#include "Common/ItemNameUtils.h" -#include "Common/OutStreamWithCRC.h" - -namespace NCompress { -namespace NArj { -namespace NDecoder { - -static const unsigned kMatchMinLen = 3; -static const UInt32 kWindowSize = 1 << 15; // must be >= (1 << 14) - -class CCoder -{ - CLzOutWindow _outWindow; - NBitm::CDecoder _inBitStream; - // bool FinishMode; - - class CCoderReleaser - { - CCoder *_coder; - public: - CCoderReleaser(CCoder *coder): _coder(coder) {} - void Disable() { _coder = NULL; } - ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); } - }; - friend class CCoderReleaser; - - HRESULT CodeReal(UInt32 outSize, ICompressProgressInfo *progress); -public: - - // CCoder(): FinishMode(true) {} - UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); } - HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - UInt32 outSize, ICompressProgressInfo *progress); -}; - - -HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress) -{ - const UInt32 kStep = 1 << 20; - UInt32 next = 0; - if (rem > kStep && progress) - next = rem - kStep; - - while (rem != 0) - { - if (rem <= next) - { - if (_inBitStream.ExtraBitsWereRead()) - return S_FALSE; - const UInt64 packSize = _inBitStream.GetProcessedSize(); - const UInt64 pos = _outWindow.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &pos)) - next = 0; - if (rem > kStep) - next = rem - kStep; - } - - UInt32 len; - { - const unsigned kNumBits = 7 + 7; - const UInt32 val = _inBitStream.GetValue(kNumBits); - - if ((val & (1u << (kNumBits - 1))) == 0) - { - _outWindow.PutByte((Byte)(val >> 5)); - _inBitStream.MovePos(1 + 8); - rem--; - continue; - } - - unsigned w; - { - UInt32 flag = (UInt32)1 << (kNumBits - 2); - for (w = 1; w < 7; w++, flag >>= 1) - if ((val & flag) == 0) - break; - } - const unsigned readBits = (w != 7 ? 1 : 0) + w * 2; - const UInt32 mask = ((UInt32)1 << w) - 1; - len = mask + kMatchMinLen - 1 + - ((val >> (kNumBits - readBits)) & mask); - _inBitStream.MovePos(readBits); - } - { - const unsigned kNumBits = 4 + 13; - const UInt32 val = _inBitStream.GetValue(kNumBits); - unsigned readBits = 1; - unsigned w; - if ((val & ((UInt32)1 << 16)) == 0) w = 9; - else if ((val & ((UInt32)1 << 15)) == 0) w = 10; - else if ((val & ((UInt32)1 << 14)) == 0) w = 11; - else if ((val & ((UInt32)1 << 13)) == 0) w = 12; - else { w = 13; readBits = 0; } - - readBits += w + w - 9; - const UInt32 dist = ((UInt32)1 << w) - (1 << 9) + - (((val >> (kNumBits - readBits)) & ((1 << w) - 1))); - _inBitStream.MovePos(readBits); - if (len > rem) - { - // if (FinishMode) - return S_FALSE; - // else len = (UInt32)rem; - } - if (!_outWindow.CopyBlock(dist, len)) - return S_FALSE; - rem -= len; - } - } - - // if (FinishMode) - { - if (_inBitStream.ReadAlignBits() != 0) - return S_FALSE; - } - if (_inBitStream.ExtraBitsWereRead()) - return S_FALSE; - return S_OK; -} - - -HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - UInt32 outSize, ICompressProgressInfo *progress) -{ - try - { - if (!_outWindow.Create(kWindowSize)) - return E_OUTOFMEMORY; - if (!_inBitStream.Create(1 << 17)) - return E_OUTOFMEMORY; - _outWindow.SetStream(outStream); - _outWindow.Init(false); - _inBitStream.SetStream(inStream); - _inBitStream.Init(); - { - CCoderReleaser coderReleaser(this); - RINOK(CodeReal(outSize, progress)) - coderReleaser.Disable(); - } - return _outWindow.Flush(); - } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -}}} - - - - -using namespace NWindows; - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -namespace NArchive { -namespace NArj { - -static const unsigned kBlockSizeMin = 30; -static const unsigned kBlockSizeMax = 2600; - -static const Byte kSig0 = 0x60; -static const Byte kSig1 = 0xEA; - -namespace NCompressionMethod -{ - enum - { - kStored = 0, - kCompressed1a = 1, - kCompressed1b = 2, - kCompressed1c = 3, - kCompressed2 = 4, - kNoDataNoCRC = 8, - kNoData = 9 - }; -} - -namespace NFileType -{ - enum - { - kBinary = 0, - k7BitText, - kArchiveHeader, - kDirectory, - kVolumeLablel, - kChapterLabel - }; -} - -namespace NFlags -{ - const Byte kGarbled = 1 << 0; - // const Byte kAnsiPage = 1 << 1; // or (OLD_SECURED_FLAG) obsolete - const Byte kVolume = 1 << 2; - const Byte kExtFile = 1 << 3; - // const Byte kPathSym = 1 << 4; - // const Byte kBackup = 1 << 5; // obsolete - // const Byte kSecured = 1 << 6; - // const Byte kDualName = 1 << 7; -} - -namespace NHostOS -{ - enum EEnum - { - kMSDOS = 0, // MS-DOS, OS/2, Win32, pkarj 2.50 (FAT / VFAT / FAT32) - kPRIMOS, - kUnix, - kAMIGA, - kMac, - kOS_2, - kAPPLE_GS, - kAtari_ST, - kNext, - kVAX_VMS, - kWIN95 - }; -} - -static const char * const kHostOS[] = -{ - "MSDOS" - , "PRIMOS" - , "UNIX" - , "AMIGA" - , "MAC" - , "OS/2" - , "APPLE GS" - , "ATARI ST" - , "NEXT" - , "VAX VMS" - , "WIN95" -}; - -struct CArcHeader -{ - // Byte ArchiverVersion; - // Byte ExtractVersion; - Byte HostOS; - // Byte Flags; - // Byte SecuryVersion; - // Byte FileType; - // Byte Reserved; - UInt32 CTime; - UInt32 MTime; - UInt32 ArchiveSize; - // UInt32 SecurPos; - // UInt16 FilespecPosInFilename; - UInt16 SecurSize; - // Byte EncryptionVersion; - // Byte LastChapter; - AString Name; - AString Comment; - - HRESULT Parse(const Byte *p, unsigned size); -}; - -API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size) -{ - if (size < kBlockSizeMin + 4) - return k_IsArc_Res_NEED_MORE; - if (p[0] != kSig0 || p[1] != kSig1) - return k_IsArc_Res_NO; - UInt32 blockSize = Get16(p + 2); - if (blockSize < kBlockSizeMin || - blockSize > kBlockSizeMax) - return k_IsArc_Res_NO; - - p += 4; - size -= 4; - - Byte headerSize = p[0]; - if (headerSize < kBlockSizeMin || - headerSize > blockSize || - p[6] != NFileType::kArchiveHeader || - p[28] > 8) // EncryptionVersion - return k_IsArc_Res_NO; - - if (blockSize + 4 <= size) - if (Get32(p + blockSize) != CrcCalc(p, blockSize)) - return k_IsArc_Res_NO; - - return k_IsArc_Res_YES; -} -} - -static HRESULT ReadString(const Byte *p, unsigned &size, AString &res) -{ - unsigned num = size; - for (unsigned i = 0; i < num;) - { - if (p[i++] == 0) - { - size = i; - res = (const char *)p; - return S_OK; - } - } - return S_FALSE; -} - -HRESULT CArcHeader::Parse(const Byte *p, unsigned size) -{ - Byte headerSize = p[0]; - if (headerSize < kBlockSizeMin || headerSize > size) - return S_FALSE; - // ArchiverVersion = p[1]; - // ExtractVersion = p[2]; - HostOS = p[3]; - // Flags = p[4]; - // SecuryVersion = p[5]; - if (p[6] != NFileType::kArchiveHeader) - return S_FALSE; - // Reserved = p[7]; - CTime = Get32(p + 8); - MTime = Get32(p + 12); - ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives) - // SecurPos = Get32(p + 20); - // UInt16 filespecPositionInFilename = Get16(p + 24); - SecurSize = Get16(p + 26); - // EncryptionVersion = p[28]; - // LastChapter = p[29]; - unsigned pos = headerSize; - unsigned size1 = size - pos; - RINOK(ReadString(p + pos, size1, Name)) - pos += size1; - size1 = size - pos; - RINOK(ReadString(p + pos, size1, Comment)) - pos += size1; - return S_OK; -} - - -struct CExtendedInfo -{ - UInt64 Size; - bool CrcError; - - void Clear() - { - Size = 0; - CrcError = false; - } - void ParseToPropVar(NCOM::CPropVariant &prop) const - { - if (Size != 0) - { - AString s; - s += "Extended:"; - s.Add_UInt32((UInt32)Size); - if (CrcError) - s += ":CRC_ERROR"; - prop = s; - } - } -}; - - -struct CItem -{ - AString Name; - AString Comment; - - UInt32 MTime; - UInt32 PackSize; - UInt32 Size; - UInt32 FileCRC; - UInt32 SplitPos; - - Byte Version; - Byte ExtractVersion; - Byte HostOS; - Byte Flags; - Byte Method; - Byte FileType; - - // UInt16 FilespecPosInFilename; - UInt16 FileAccessMode; - // Byte FirstChapter; - // Byte LastChapter; - - UInt64 DataPosition; - - CExtendedInfo ExtendedInfo; - - bool IsEncrypted() const { return (Flags & NFlags::kGarbled) != 0; } - bool IsDir() const { return (FileType == NFileType::kDirectory); } - bool IsSplitAfter() const { return (Flags & NFlags::kVolume) != 0; } - bool IsSplitBefore() const { return (Flags & NFlags::kExtFile) != 0; } - UInt32 GetWinAttrib() const - { - UInt32 atrrib = 0; - switch (HostOS) - { - case NHostOS::kMSDOS: - case NHostOS::kWIN95: - atrrib = FileAccessMode; - break; - } - if (IsDir()) - atrrib |= FILE_ATTRIBUTE_DIRECTORY; - return atrrib; - } - - HRESULT Parse(const Byte *p, unsigned size); -}; - -HRESULT CItem::Parse(const Byte *p, unsigned size) -{ - Byte headerSize = p[0]; - if (headerSize < kBlockSizeMin || headerSize > size) - return S_FALSE; - Version = p[1]; - ExtractVersion = p[2]; - HostOS = p[3]; - Flags = p[4]; - Method = p[5]; - FileType = p[6]; - // Reserved = p[7]; - MTime = Get32(p + 8); - PackSize = Get32(p + 12); - Size = Get32(p + 16); - FileCRC = Get32(p + 20); - // FilespecPosInFilename = Get16(p + 24); - FileAccessMode = Get16(p + 26); - // FirstChapter = p[28]; - // FirstChapter = p[29]; - - SplitPos = 0; - if (IsSplitBefore() && headerSize >= 34) - SplitPos = Get32(p + 30); - - unsigned pos = headerSize; - unsigned size1 = size - pos; - RINOK(ReadString(p + pos, size1, Name)) - pos += size1; - size1 = size - pos; - RINOK(ReadString(p + pos, size1, Comment)) - pos += size1; - - return S_OK; -} - -enum EErrorType -{ - k_ErrorType_OK, - k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd -}; - -class CArc -{ -public: - UInt64 Processed; - EErrorType Error; - bool IsArc; - IInStream *Stream; - IArchiveOpenCallback *Callback; - UInt64 NumFiles; - CArcHeader Header; - - CExtendedInfo ExtendedInfo; - - HRESULT Open(); - HRESULT GetNextItem(CItem &item, bool &filled); - void Close() - { - IsArc = false; - Error = k_ErrorType_OK; - ExtendedInfo.Clear(); - } -private: - unsigned _blockSize; - CByteBuffer _block; - - HRESULT ReadBlock(bool &filled, CExtendedInfo *extendedInfo); - HRESULT SkipExtendedHeaders(CExtendedInfo &extendedInfo); - HRESULT Read(void *data, size_t *size); -}; - -HRESULT CArc::Read(void *data, size_t *size) -{ - HRESULT res = ReadStream(Stream, data, size); - Processed += *size; - return res; -} - -#define READ_STREAM(_dest_, _size_) \ - { size_t _processed_ = (_size_); RINOK(Read(_dest_, &_processed_)); \ - if (_processed_ != (_size_)) { Error = k_ErrorType_UnexpectedEnd; return S_OK; } } - -HRESULT CArc::ReadBlock(bool &filled, CExtendedInfo *extendedInfo) -{ - Error = k_ErrorType_OK; - filled = false; - Byte buf[4]; - const unsigned signSize = extendedInfo ? 0 : 2; - READ_STREAM(buf, signSize + 2) - if (!extendedInfo) - if (buf[0] != kSig0 || buf[1] != kSig1) - { - Error = k_ErrorType_Corrupted; - return S_OK; - } - _blockSize = Get16(buf + signSize); - if (_blockSize == 0) // end of archive - return S_OK; - - if (!extendedInfo) - if (_blockSize < kBlockSizeMin || _blockSize > kBlockSizeMax) - { - Error = k_ErrorType_Corrupted; - return S_OK; - } - - const size_t readSize = _blockSize + 4; - if (readSize > _block.Size()) - { - // extended data size is limited by (64 KB) - // _blockSize is less than 64 KB - const size_t upSize = (_blockSize > kBlockSizeMax ? (1 << 16) : kBlockSizeMax); - _block.Alloc(upSize + 4); - } - - if (extendedInfo) - extendedInfo->Size += _blockSize; - - READ_STREAM(_block, readSize) - if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize)) - { - if (extendedInfo) - extendedInfo->CrcError = true; - else - { - Error = k_ErrorType_Corrupted; - return S_OK; - } - } - filled = true; - return S_OK; -} - -HRESULT CArc::SkipExtendedHeaders(CExtendedInfo &extendedInfo) -{ - extendedInfo.Clear(); - for (UInt32 i = 0;; i++) - { - bool filled; - RINOK(ReadBlock(filled, &extendedInfo)) - if (!filled) - return S_OK; - if (Callback && (i & 0xFF) == 0) - RINOK(Callback->SetCompleted(&NumFiles, &Processed)) - } -} - -HRESULT CArc::Open() -{ - bool filled; - RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL) - if (!filled) - return S_FALSE; - RINOK(Header.Parse(_block, _blockSize)) - IsArc = true; - return SkipExtendedHeaders(ExtendedInfo); -} - -HRESULT CArc::GetNextItem(CItem &item, bool &filled) -{ - RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL) - if (!filled) - return S_OK; - filled = false; - if (item.Parse(_block, _blockSize) != S_OK) - { - Error = k_ErrorType_Corrupted; - return S_OK; - } - /* - UInt32 extraData; - if ((header.Flags & NFlags::kExtFile) != 0) - extraData = GetUi32(_block + pos); - */ - - RINOK(SkipExtendedHeaders(item.ExtendedInfo)) - filled = true; - return S_OK; -} - - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - CArc _arc; - - HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); -}; - -static const Byte kArcProps[] = -{ - kpidName, - kpidCTime, - kpidMTime, - kpidHostOS, - kpidComment, - kpidCharacts -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPosition, - kpidPackSize, - kpidMTime, - kpidAttrib, - kpidEncrypted, - kpidCRC, - kpidMethod, - kpidHostOS, - kpidComment, - kpidCharacts -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop) -{ - if (dosTime == 0) - return; - PropVariant_SetFrom_DosTime(prop, dosTime); -} - -static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) -{ - TYPE_TO_PROP(kHostOS, hostOS, prop); -} - -static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop) -{ - if (!s.IsEmpty()) - prop = MultiByteToUnicodeString(s, CP_OEMCP); -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _phySize; break; - case kpidName: SetUnicodeString(_arc.Header.Name, prop); break; - case kpidCTime: SetTime(_arc.Header.CTime, prop); break; - case kpidMTime: SetTime(_arc.Header.MTime, prop); break; - case kpidHostOS: SetHostOS(_arc.Header.HostOS, prop); break; - case kpidComment: SetUnicodeString(_arc.Header.Comment, prop); break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_arc.IsArc) v |= kpv_ErrorFlags_IsNotArc; - switch (_arc.Error) - { - case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break; - case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break; - case k_ErrorType_OK: - // default: - break; - } - prop = v; - break; - } - case kpidCharacts: _arc.ExtendedInfo.ParseToPropVar(prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItem &item = _items[index]; - switch (propID) - { - case kpidPath: prop = NItemName::GetOsPath(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.Size; break; - case kpidPackSize: prop = item.PackSize; break; - case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break; - case kpidAttrib: prop = item.GetWinAttrib(); break; - case kpidEncrypted: prop = item.IsEncrypted(); break; - case kpidCRC: prop = item.FileCRC; break; - case kpidMethod: prop = item.Method; break; - case kpidHostOS: SetHostOS(item.HostOS, prop); break; - case kpidMTime: SetTime(item.MTime, prop); break; - case kpidComment: SetUnicodeString(item.Comment, prop); break; - case kpidCharacts: item.ExtendedInfo.ParseToPropVar(prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback) -{ - Close(); - - UInt64 endPos; - RINOK(InStream_AtBegin_GetSize(inStream, endPos)) - - _arc.Stream = inStream; - _arc.Callback = callback; - _arc.NumFiles = 0; - _arc.Processed = 0; - - RINOK(_arc.Open()) - - _phySize = _arc.Processed; - if (_arc.Header.ArchiveSize != 0) - _phySize = (UInt64)_arc.Header.ArchiveSize + _arc.Header.SecurSize; - - for (;;) - { - CItem item; - bool filled; - - _arc.Error = k_ErrorType_OK; - RINOK(_arc.GetNextItem(item, filled)) - - if (_arc.Error != k_ErrorType_OK) - break; - - if (!filled) - { - if (_arc.Error == k_ErrorType_OK) - if (_arc.Header.ArchiveSize == 0) - _phySize = _arc.Processed; - break; - } - item.DataPosition = _arc.Processed; - _items.Add(item); - - UInt64 pos = item.DataPosition + item.PackSize; - if (_arc.Header.ArchiveSize == 0) - _phySize = pos; - if (pos > endPos) - { - _arc.Error = k_ErrorType_UnexpectedEnd; - break; - } - - RINOK(InStream_SeekSet(inStream, pos)) - _arc.NumFiles = _items.Size(); - _arc.Processed = pos; - - if (callback && (_items.Size() & 0xFF) == 0) - { - RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed)) - } - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - HRESULT res; - { - res = Open2(inStream, callback); - if (res == S_OK) - { - _stream = inStream; - return S_OK; - } - } - return res; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _arc.Close(); - _phySize = 0; - _items.Clear(); - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - UInt64 totalUnpacked = 0, totalPacked = 0; - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItem &item = _items[allFilesMode ? i : indices[i]]; - totalUnpacked += item.Size; - // totalPacked += item.PackSize; - } - RINOK(extractCallback->SetTotal(totalUnpacked)) - - totalUnpacked = totalPacked = 0; - UInt32 curUnpacked, curPacked; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyUniquePtr lzhDecoder; - CMyUniquePtr arjDecoder; - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - - for (i = 0;; i++, - totalUnpacked += curUnpacked, - totalPacked += curPacked) - { - lps->InSize = totalPacked; - lps->OutSize = totalUnpacked; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - curUnpacked = curPacked = 0; - - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (item.IsDir()) - { - // if (!testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)) - // realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - continue; - } - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - curUnpacked = item.Size; - curPacked = item.PackSize; - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - // realOutStream.Release(); - outStream->Init(); - - inStream->Init(item.PackSize); - - RINOK(InStream_SeekSet(_stream, item.DataPosition)) - - HRESULT result = S_OK; - opRes = NExtract::NOperationResult::kOK; - - if (item.IsEncrypted()) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - { - switch (item.Method) - { - case NCompressionMethod::kStored: - { - result = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); - if (result == S_OK && copyCoder->TotalSize != item.PackSize) - result = S_FALSE; - break; - } - case NCompressionMethod::kCompressed1a: - case NCompressionMethod::kCompressed1b: - case NCompressionMethod::kCompressed1c: - { - lzhDecoder.Create_if_Empty(); - // lzhDecoder->FinishMode = true; - const UInt32 kHistorySize = 26624; - lzhDecoder->SetDictSize(kHistorySize); - result = lzhDecoder->Code(inStream, outStream, curUnpacked, lps); - if (result == S_OK && lzhDecoder->GetInputProcessedSize() != item.PackSize) - result = S_FALSE; - break; - } - case NCompressionMethod::kCompressed2: - { - arjDecoder.Create_if_Empty(); - // arjDecoderSpec->FinishMode = true; - result = arjDecoder->Code(inStream, outStream, curUnpacked, lps); - if (result == S_OK && arjDecoder->GetInputProcessedSize() != item.PackSize) - result = S_FALSE; - break; - } - default: - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - } - - if (opRes == NExtract::NOperationResult::kOK) - { - if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else - { - RINOK(result) - opRes = (outStream->GetCRC() == item.FileCRC) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kCRCError; - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - -static const Byte k_Signature[] = { kSig0, kSig1 }; - -REGISTER_ARC_I( - "Arj", "arj", NULL, 4, - k_Signature, - 0, - 0, - IsArc_Arj) - -}} +// ArjHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/AutoPtr.h" +#include "../../Common/ComTry.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/LzhDecoder.h" + +#include "Common/ItemNameUtils.h" +#include "Common/OutStreamWithCRC.h" + +namespace NCompress { +namespace NArj { +namespace NDecoder { + +static const unsigned kMatchMinLen = 3; +static const UInt32 kWindowSize = 1 << 15; // must be >= (1 << 14) + +class CCoder +{ + CLzOutWindow _outWindow; + NBitm::CDecoder _inBitStream; + // bool FinishMode; + + class CCoderReleaser + { + CCoder *_coder; + public: + CCoderReleaser(CCoder *coder): _coder(coder) {} + void Disable() { _coder = NULL; } + ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); } + }; + friend class CCoderReleaser; + + HRESULT CodeReal(UInt32 outSize, ICompressProgressInfo *progress); +public: + + // CCoder(): FinishMode(true) {} + UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); } + HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt32 outSize, ICompressProgressInfo *progress); +}; + + +HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress) +{ + const UInt32 kStep = 1 << 20; + UInt32 next = 0; + if (rem > kStep && progress) + next = rem - kStep; + + while (rem != 0) + { + if (rem <= next) + { + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + const UInt64 packSize = _inBitStream.GetProcessedSize(); + const UInt64 pos = _outWindow.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)) + next = 0; + if (rem > kStep) + next = rem - kStep; + } + + UInt32 len; + { + const unsigned kNumBits = 7 + 7; + const UInt32 val = _inBitStream.GetValue(kNumBits); + + if ((val & (1u << (kNumBits - 1))) == 0) + { + _outWindow.PutByte((Byte)(val >> 5)); + _inBitStream.MovePos(1 + 8); + rem--; + continue; + } + + unsigned w; + { + UInt32 flag = (UInt32)1 << (kNumBits - 2); + for (w = 1; w < 7; w++, flag >>= 1) + if ((val & flag) == 0) + break; + } + const unsigned readBits = (w != 7 ? 1 : 0) + w * 2; + const UInt32 mask = ((UInt32)1 << w) - 1; + len = mask + kMatchMinLen - 1 + + ((val >> (kNumBits - readBits)) & mask); + _inBitStream.MovePos(readBits); + } + { + const unsigned kNumBits = 4 + 13; + const UInt32 val = _inBitStream.GetValue(kNumBits); + unsigned readBits = 1; + unsigned w; + if ((val & ((UInt32)1 << 16)) == 0) w = 9; + else if ((val & ((UInt32)1 << 15)) == 0) w = 10; + else if ((val & ((UInt32)1 << 14)) == 0) w = 11; + else if ((val & ((UInt32)1 << 13)) == 0) w = 12; + else { w = 13; readBits = 0; } + + readBits += w + w - 9; + const UInt32 dist = ((UInt32)1 << w) - (1 << 9) + + (((val >> (kNumBits - readBits)) & ((1 << w) - 1))); + _inBitStream.MovePos(readBits); + if (len > rem) + { + // if (FinishMode) + return S_FALSE; + // else len = (UInt32)rem; + } + if (!_outWindow.CopyBlock(dist, len)) + return S_FALSE; + rem -= len; + } + } + + // if (FinishMode) + { + if (_inBitStream.ReadAlignBits() != 0) + return S_FALSE; + } + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + return S_OK; +} + + +HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt32 outSize, ICompressProgressInfo *progress) +{ + try + { + if (!_outWindow.Create(kWindowSize)) + return E_OUTOFMEMORY; + if (!_inBitStream.Create(1 << 17)) + return E_OUTOFMEMORY; + _outWindow.SetStream(outStream); + _outWindow.Init(false); + _inBitStream.SetStream(inStream); + _inBitStream.Init(); + { + CCoderReleaser coderReleaser(this); + RINOK(CodeReal(outSize, progress)) + coderReleaser.Disable(); + } + return _outWindow.Flush(); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +}}} + + + + +using namespace NWindows; + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NArj { + +static const unsigned kBlockSizeMin = 30; +static const unsigned kBlockSizeMax = 2600; + +static const Byte kSig0 = 0x60; +static const Byte kSig1 = 0xEA; + +namespace NCompressionMethod +{ + enum + { + kStored = 0, + kCompressed1a = 1, + kCompressed1b = 2, + kCompressed1c = 3, + kCompressed2 = 4, + kNoDataNoCRC = 8, + kNoData = 9 + }; +} + +namespace NFileType +{ + enum + { + kBinary = 0, + k7BitText, + kArchiveHeader, + kDirectory, + kVolumeLablel, + kChapterLabel + }; +} + +namespace NFlags +{ + const Byte kGarbled = 1 << 0; + // const Byte kAnsiPage = 1 << 1; // or (OLD_SECURED_FLAG) obsolete + const Byte kVolume = 1 << 2; + const Byte kExtFile = 1 << 3; + // const Byte kPathSym = 1 << 4; + // const Byte kBackup = 1 << 5; // obsolete + // const Byte kSecured = 1 << 6; + // const Byte kDualName = 1 << 7; +} + +namespace NHostOS +{ + enum EEnum + { + kMSDOS = 0, // MS-DOS, OS/2, Win32, pkarj 2.50 (FAT / VFAT / FAT32) + kPRIMOS, + kUnix, + kAMIGA, + kMac, + kOS_2, + kAPPLE_GS, + kAtari_ST, + kNext, + kVAX_VMS, + kWIN95 + }; +} + +static const char * const kHostOS[] = +{ + "MSDOS" + , "PRIMOS" + , "UNIX" + , "AMIGA" + , "MAC" + , "OS/2" + , "APPLE GS" + , "ATARI ST" + , "NEXT" + , "VAX VMS" + , "WIN95" +}; + +struct CArcHeader +{ + // Byte ArchiverVersion; + // Byte ExtractVersion; + Byte HostOS; + // Byte Flags; + // Byte SecuryVersion; + // Byte FileType; + // Byte Reserved; + UInt32 CTime; + UInt32 MTime; + UInt32 ArchiveSize; + // UInt32 SecurPos; + // UInt16 FilespecPosInFilename; + UInt16 SecurSize; + // Byte EncryptionVersion; + // Byte LastChapter; + AString Name; + AString Comment; + + HRESULT Parse(const Byte *p, unsigned size); +}; + +API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size) +{ + if (size < kBlockSizeMin + 4) + return k_IsArc_Res_NEED_MORE; + if (p[0] != kSig0 || p[1] != kSig1) + return k_IsArc_Res_NO; + UInt32 blockSize = Get16(p + 2); + if (blockSize < kBlockSizeMin || + blockSize > kBlockSizeMax) + return k_IsArc_Res_NO; + + p += 4; + size -= 4; + + Byte headerSize = p[0]; + if (headerSize < kBlockSizeMin || + headerSize > blockSize || + p[6] != NFileType::kArchiveHeader || + p[28] > 8) // EncryptionVersion + return k_IsArc_Res_NO; + + if (blockSize + 4 <= size) + if (Get32(p + blockSize) != CrcCalc(p, blockSize)) + return k_IsArc_Res_NO; + + return k_IsArc_Res_YES; +} +} + +static HRESULT ReadString(const Byte *p, unsigned &size, AString &res) +{ + unsigned num = size; + for (unsigned i = 0; i < num;) + { + if (p[i++] == 0) + { + size = i; + res = (const char *)p; + return S_OK; + } + } + return S_FALSE; +} + +HRESULT CArcHeader::Parse(const Byte *p, unsigned size) +{ + Byte headerSize = p[0]; + if (headerSize < kBlockSizeMin || headerSize > size) + return S_FALSE; + // ArchiverVersion = p[1]; + // ExtractVersion = p[2]; + HostOS = p[3]; + // Flags = p[4]; + // SecuryVersion = p[5]; + if (p[6] != NFileType::kArchiveHeader) + return S_FALSE; + // Reserved = p[7]; + CTime = Get32(p + 8); + MTime = Get32(p + 12); + ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives) + // SecurPos = Get32(p + 20); + // UInt16 filespecPositionInFilename = Get16(p + 24); + SecurSize = Get16(p + 26); + // EncryptionVersion = p[28]; + // LastChapter = p[29]; + unsigned pos = headerSize; + unsigned size1 = size - pos; + RINOK(ReadString(p + pos, size1, Name)) + pos += size1; + size1 = size - pos; + RINOK(ReadString(p + pos, size1, Comment)) + pos += size1; + return S_OK; +} + + +struct CExtendedInfo +{ + UInt64 Size; + bool CrcError; + + void Clear() + { + Size = 0; + CrcError = false; + } + void ParseToPropVar(NCOM::CPropVariant &prop) const + { + if (Size != 0) + { + AString s; + s += "Extended:"; + s.Add_UInt32((UInt32)Size); + if (CrcError) + s += ":CRC_ERROR"; + prop = s; + } + } +}; + + +struct CItem +{ + AString Name; + AString Comment; + + UInt32 MTime; + UInt32 PackSize; + UInt32 Size; + UInt32 FileCRC; + UInt32 SplitPos; + + Byte Version; + Byte ExtractVersion; + Byte HostOS; + Byte Flags; + Byte Method; + Byte FileType; + + // UInt16 FilespecPosInFilename; + UInt16 FileAccessMode; + // Byte FirstChapter; + // Byte LastChapter; + + UInt64 DataPosition; + + CExtendedInfo ExtendedInfo; + + bool IsEncrypted() const { return (Flags & NFlags::kGarbled) != 0; } + bool IsDir() const { return (FileType == NFileType::kDirectory); } + bool IsSplitAfter() const { return (Flags & NFlags::kVolume) != 0; } + bool IsSplitBefore() const { return (Flags & NFlags::kExtFile) != 0; } + UInt32 GetWinAttrib() const + { + UInt32 atrrib = 0; + switch (HostOS) + { + case NHostOS::kMSDOS: + case NHostOS::kWIN95: + atrrib = FileAccessMode; + break; + } + if (IsDir()) + atrrib |= FILE_ATTRIBUTE_DIRECTORY; + return atrrib; + } + + HRESULT Parse(const Byte *p, unsigned size); +}; + +HRESULT CItem::Parse(const Byte *p, unsigned size) +{ + Byte headerSize = p[0]; + if (headerSize < kBlockSizeMin || headerSize > size) + return S_FALSE; + Version = p[1]; + ExtractVersion = p[2]; + HostOS = p[3]; + Flags = p[4]; + Method = p[5]; + FileType = p[6]; + // Reserved = p[7]; + MTime = Get32(p + 8); + PackSize = Get32(p + 12); + Size = Get32(p + 16); + FileCRC = Get32(p + 20); + // FilespecPosInFilename = Get16(p + 24); + FileAccessMode = Get16(p + 26); + // FirstChapter = p[28]; + // FirstChapter = p[29]; + + SplitPos = 0; + if (IsSplitBefore() && headerSize >= 34) + SplitPos = Get32(p + 30); + + unsigned pos = headerSize; + unsigned size1 = size - pos; + RINOK(ReadString(p + pos, size1, Name)) + pos += size1; + size1 = size - pos; + RINOK(ReadString(p + pos, size1, Comment)) + pos += size1; + + return S_OK; +} + +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd +}; + +class CArc +{ +public: + UInt64 Processed; + EErrorType Error; + bool IsArc; + IInStream *Stream; + IArchiveOpenCallback *Callback; + UInt64 NumFiles; + CArcHeader Header; + + CExtendedInfo ExtendedInfo; + + HRESULT Open(); + HRESULT GetNextItem(CItem &item, bool &filled); + void Close() + { + IsArc = false; + Error = k_ErrorType_OK; + ExtendedInfo.Clear(); + } +private: + unsigned _blockSize; + CByteBuffer _block; + + HRESULT ReadBlock(bool &filled, CExtendedInfo *extendedInfo); + HRESULT SkipExtendedHeaders(CExtendedInfo &extendedInfo); + HRESULT Read(void *data, size_t *size); +}; + +HRESULT CArc::Read(void *data, size_t *size) +{ + HRESULT res = ReadStream(Stream, data, size); + Processed += *size; + return res; +} + +#define READ_STREAM(_dest_, _size_) \ + { size_t _processed_ = (_size_); RINOK(Read(_dest_, &_processed_)); \ + if (_processed_ != (_size_)) { Error = k_ErrorType_UnexpectedEnd; return S_OK; } } + +HRESULT CArc::ReadBlock(bool &filled, CExtendedInfo *extendedInfo) +{ + Error = k_ErrorType_OK; + filled = false; + Byte buf[4]; + const unsigned signSize = extendedInfo ? 0 : 2; + READ_STREAM(buf, signSize + 2) + if (!extendedInfo) + if (buf[0] != kSig0 || buf[1] != kSig1) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + _blockSize = Get16(buf + signSize); + if (_blockSize == 0) // end of archive + return S_OK; + + if (!extendedInfo) + if (_blockSize < kBlockSizeMin || _blockSize > kBlockSizeMax) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + + const size_t readSize = _blockSize + 4; + if (readSize > _block.Size()) + { + // extended data size is limited by (64 KB) + // _blockSize is less than 64 KB + const size_t upSize = (_blockSize > kBlockSizeMax ? (1 << 16) : kBlockSizeMax); + _block.Alloc(upSize + 4); + } + + if (extendedInfo) + extendedInfo->Size += _blockSize; + + READ_STREAM(_block, readSize) + if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize)) + { + if (extendedInfo) + extendedInfo->CrcError = true; + else + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + } + filled = true; + return S_OK; +} + +HRESULT CArc::SkipExtendedHeaders(CExtendedInfo &extendedInfo) +{ + extendedInfo.Clear(); + for (UInt32 i = 0;; i++) + { + bool filled; + RINOK(ReadBlock(filled, &extendedInfo)) + if (!filled) + return S_OK; + if (Callback && (i & 0xFF) == 0) + RINOK(Callback->SetCompleted(&NumFiles, &Processed)) + } +} + +HRESULT CArc::Open() +{ + bool filled; + RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL) + if (!filled) + return S_FALSE; + RINOK(Header.Parse(_block, _blockSize)) + IsArc = true; + return SkipExtendedHeaders(ExtendedInfo); +} + +HRESULT CArc::GetNextItem(CItem &item, bool &filled) +{ + RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL) + if (!filled) + return S_OK; + filled = false; + if (item.Parse(_block, _blockSize) != S_OK) + { + Error = k_ErrorType_Corrupted; + return S_OK; + } + /* + UInt32 extraData; + if ((header.Flags & NFlags::kExtFile) != 0) + extraData = GetUi32(_block + pos); + */ + + RINOK(SkipExtendedHeaders(item.ExtendedInfo)) + filled = true; + return S_OK; +} + + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + CArc _arc; + + HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback); +}; + +static const Byte kArcProps[] = +{ + kpidName, + kpidCTime, + kpidMTime, + kpidHostOS, + kpidComment, + kpidCharacts +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPosition, + kpidPackSize, + kpidMTime, + kpidAttrib, + kpidEncrypted, + kpidCRC, + kpidMethod, + kpidHostOS, + kpidComment, + kpidCharacts +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop) +{ + if (dosTime == 0) + return; + PropVariant_SetFrom_DosTime(prop, dosTime); +} + +static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) +{ + TYPE_TO_PROP(kHostOS, hostOS, prop); +} + +static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop) +{ + if (!s.IsEmpty()) + prop = MultiByteToUnicodeString(s, CP_OEMCP); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidName: SetUnicodeString(_arc.Header.Name, prop); break; + case kpidCTime: SetTime(_arc.Header.CTime, prop); break; + case kpidMTime: SetTime(_arc.Header.MTime, prop); break; + case kpidHostOS: SetHostOS(_arc.Header.HostOS, prop); break; + case kpidComment: SetUnicodeString(_arc.Header.Comment, prop); break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_arc.IsArc) v |= kpv_ErrorFlags_IsNotArc; + switch (_arc.Error) + { + case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break; + case k_ErrorType_OK: + // default: + break; + } + prop = v; + break; + } + case kpidCharacts: _arc.ExtendedInfo.ParseToPropVar(prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + switch (propID) + { + case kpidPath: prop = NItemName::GetOsPath(MultiByteToUnicodeString(item.Name, CP_OEMCP)); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidPackSize: prop = item.PackSize; break; + case kpidPosition: if (item.IsSplitBefore() || item.IsSplitAfter()) prop = (UInt64)item.SplitPos; break; + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidEncrypted: prop = item.IsEncrypted(); break; + case kpidCRC: prop = item.FileCRC; break; + case kpidMethod: prop = item.Method; break; + case kpidHostOS: SetHostOS(item.HostOS, prop); break; + case kpidMTime: SetTime(item.MTime, prop); break; + case kpidComment: SetUnicodeString(item.Comment, prop); break; + case kpidCharacts: item.ExtendedInfo.ParseToPropVar(prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback) +{ + Close(); + + UInt64 endPos; + RINOK(InStream_AtBegin_GetSize(inStream, endPos)) + + _arc.Stream = inStream; + _arc.Callback = callback; + _arc.NumFiles = 0; + _arc.Processed = 0; + + RINOK(_arc.Open()) + + _phySize = _arc.Processed; + if (_arc.Header.ArchiveSize != 0) + _phySize = (UInt64)_arc.Header.ArchiveSize + _arc.Header.SecurSize; + + for (;;) + { + CItem item; + bool filled; + + _arc.Error = k_ErrorType_OK; + RINOK(_arc.GetNextItem(item, filled)) + + if (_arc.Error != k_ErrorType_OK) + break; + + if (!filled) + { + if (_arc.Error == k_ErrorType_OK) + if (_arc.Header.ArchiveSize == 0) + _phySize = _arc.Processed; + break; + } + item.DataPosition = _arc.Processed; + _items.Add(item); + + UInt64 pos = item.DataPosition + item.PackSize; + if (_arc.Header.ArchiveSize == 0) + _phySize = pos; + if (pos > endPos) + { + _arc.Error = k_ErrorType_UnexpectedEnd; + break; + } + + RINOK(InStream_SeekSet(inStream, pos)) + _arc.NumFiles = _items.Size(); + _arc.Processed = pos; + + if (callback && (_items.Size() & 0xFF) == 0) + { + RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed)) + } + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + HRESULT res; + { + res = Open2(inStream, callback); + if (res == S_OK) + { + _stream = inStream; + return S_OK; + } + } + return res; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _arc.Close(); + _phySize = 0; + _items.Clear(); + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + UInt64 totalUnpacked = 0, totalPacked = 0; + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItem &item = _items[allFilesMode ? i : indices[i]]; + totalUnpacked += item.Size; + // totalPacked += item.PackSize; + } + RINOK(extractCallback->SetTotal(totalUnpacked)) + + totalUnpacked = totalPacked = 0; + UInt32 curUnpacked, curPacked; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyUniquePtr lzhDecoder; + CMyUniquePtr arjDecoder; + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + + for (i = 0;; i++, + totalUnpacked += curUnpacked, + totalPacked += curPacked) + { + lps->InSize = totalPacked; + lps->OutSize = totalUnpacked; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + curUnpacked = curPacked = 0; + + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (item.IsDir()) + { + // if (!testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)) + // realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + continue; + } + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + curUnpacked = item.Size; + curPacked = item.PackSize; + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + // realOutStream.Release(); + outStream->Init(); + + inStream->Init(item.PackSize); + + RINOK(InStream_SeekSet(_stream, item.DataPosition)) + + HRESULT result = S_OK; + opRes = NExtract::NOperationResult::kOK; + + if (item.IsEncrypted()) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + { + switch (item.Method) + { + case NCompressionMethod::kStored: + { + result = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); + if (result == S_OK && copyCoder->TotalSize != item.PackSize) + result = S_FALSE; + break; + } + case NCompressionMethod::kCompressed1a: + case NCompressionMethod::kCompressed1b: + case NCompressionMethod::kCompressed1c: + { + lzhDecoder.Create_if_Empty(); + // lzhDecoder->FinishMode = true; + const UInt32 kHistorySize = 26624; + lzhDecoder->SetDictSize(kHistorySize); + result = lzhDecoder->Code(inStream, outStream, curUnpacked, lps); + if (result == S_OK && lzhDecoder->GetInputProcessedSize() != item.PackSize) + result = S_FALSE; + break; + } + case NCompressionMethod::kCompressed2: + { + arjDecoder.Create_if_Empty(); + // arjDecoderSpec->FinishMode = true; + result = arjDecoder->Code(inStream, outStream, curUnpacked, lps); + if (result == S_OK && arjDecoder->GetInputProcessedSize() != item.PackSize) + result = S_FALSE; + break; + } + default: + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + } + + if (opRes == NExtract::NOperationResult::kOK) + { + if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else + { + RINOK(result) + opRes = (outStream->GetCRC() == item.FileCRC) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kCRCError; + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + +static const Byte k_Signature[] = { kSig0, kSig1 }; + +REGISTER_ARC_I( + "Arj", "arj", NULL, 4, + k_Signature, + 0, + 0, + IsArc_Arj) + +}} diff --git a/CPP/7zip/Archive/AvbHandler.cpp b/CPP/7zip/Archive/AvbHandler.cpp index 294bb6517..4359fe80f 100644 --- a/CPP/7zip/Archive/AvbHandler.cpp +++ b/CPP/7zip/Archive/AvbHandler.cpp @@ -1,596 +1,596 @@ -// AvbHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -#define G32(_offs_, dest) dest = Get32(p + (_offs_)) -#define G64(_offs_, dest) dest = Get64(p + (_offs_)) - -using namespace NWindows; - -namespace NArchive { - -namespace NExt { -API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); -} - -namespace NAvb { - -static void AddNameToString(AString &s, const Byte *name, unsigned size, bool strictConvert) -{ - for (unsigned i = 0; i < size; i++) - { - Byte c = name[i]; - if (c == 0) - return; - if (strictConvert && c < 32) - c = '_'; - s += (char)c; - } -} - -/* Maximum size of a vbmeta image - 64 KiB. */ -#define VBMETA_MAX_SIZE (64 * 1024) - -#define SIGNATURE { 'A', 'V', 'B', 'f', 0, 0, 0, 1 } - -static const unsigned k_SignatureSize = 8; -static const Byte k_Signature[k_SignatureSize] = SIGNATURE; - -// #define AVB_FOOTER_MAGIC "AVBf" -// #define AVB_FOOTER_MAGIC_LEN 4 -/* The current footer version used - keep in sync with avbtool. */ -#define AVB_FOOTER_VERSION_MAJOR 1 - -/* The struct used as a footer used on partitions, used to find the - * AvbVBMetaImageHeader struct. This struct is always stored at the - * end of a partition. - */ -// #define AVB_FOOTER_SIZE 64 -static const unsigned kFooterSize = 64; - -struct CFooter -{ - /* 0: Four bytes equal to "AVBf" (AVB_FOOTER_MAGIC). */ - // Byte magic[AVB_FOOTER_MAGIC_LEN]; - /* 4: The major version of the footer struct. */ - UInt32 version_major; - /* 8: The minor version of the footer struct. */ - UInt32 version_minor; - - /* 12: The original size of the image on the partition. */ - UInt64 original_image_size; - - /* 20: The offset of the |AvbVBMetaImageHeader| struct. */ - UInt64 vbmeta_offset; - - /* 28: The size of the vbmeta block (header + auth + aux blocks). */ - UInt64 vbmeta_size; - - /* 36: Padding to ensure struct is size AVB_FOOTER_SIZE bytes. This - * must be set to zeroes. - */ - Byte reserved[28]; - - void Parse(const Byte *p) - { - G32 (4, version_major); - G32 (8, version_minor); - G64 (12, original_image_size); - G64 (20, vbmeta_offset); - G64 (28, vbmeta_size); - } -}; - - -/* Size of the vbmeta image header. */ -#define AVB_VBMETA_IMAGE_HEADER_SIZE 256 - -/* Magic for the vbmeta image header. */ -// #define AVB_MAGIC "AVB0" -// #define AVB_MAGIC_LEN 4 -/* Maximum size of the release string including the terminating NUL byte. */ -#define AVB_RELEASE_STRING_SIZE 48 - -struct AvbVBMetaImageHeader -{ - /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ - // Byte magic[AVB_MAGIC_LEN]; - - /* 4: The major version of libavb required for this header. */ - UInt32 required_libavb_version_major; - /* 8: The minor version of libavb required for this header. */ - UInt32 required_libavb_version_minor; - - /* 12: The size of the signature block. */ - UInt64 authentication_data_block_size; - /* 20: The size of the auxiliary data block. */ - UInt64 auxiliary_data_block_size; - - /* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */ - UInt32 algorithm_type; - - /* 32: Offset into the "Authentication data" block of hash data. */ - UInt64 hash_offset; - /* 40: Length of the hash data. */ - UInt64 hash_size; - - /* 48: Offset into the "Authentication data" block of signature data. */ - UInt64 signature_offset; - /* 56: Length of the signature data. */ - UInt64 signature_size; - - /* 64: Offset into the "Auxiliary data" block of public key data. */ - UInt64 public_key_offset; - /* 72: Length of the public key data. */ - UInt64 public_key_size; - - /* 80: Offset into the "Auxiliary data" block of public key metadata. */ - UInt64 public_key_metadata_offset; - /* 88: Length of the public key metadata. Must be set to zero if there - * is no public key metadata. - */ - UInt64 public_key_metadata_size; - - /* 96: Offset into the "Auxiliary data" block of descriptor data. */ - UInt64 descriptors_offset; - /* 104: Length of descriptor data. */ - UInt64 descriptors_size; - - /* 112: The rollback index which can be used to prevent rollback to - * older versions. - */ - UInt64 rollback_index; - - /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be - * set to zero if the vbmeta image is not a top-level image. - */ - UInt32 flags; - - /* 124: The location of the rollback index defined in this header. - * Only valid for the main vbmeta. For chained partitions, the rollback - * index location must be specified in the AvbChainPartitionDescriptor - * and this value must be set to 0. - */ - UInt32 rollback_index_location; - - /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or - * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL - * terminated. Applications must not make assumptions about how this - * string is formatted. - */ - Byte release_string[AVB_RELEASE_STRING_SIZE]; - - /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE - * bytes. This must be set to zeroes. - */ - // Byte reserved[80]; - bool Parse(const Byte *p); -}; - -bool AvbVBMetaImageHeader::Parse(const Byte *p) -{ - // Byte magic[AVB_MAGIC_LEN]; - if (Get32(p) != 0x41564230) // "AVB0" - return false; - G32 (4, required_libavb_version_major); - if (required_libavb_version_major != AVB_FOOTER_VERSION_MAJOR) // "AVB0" - return false; - G32 (8, required_libavb_version_minor); - G64 (12, authentication_data_block_size); - G64 (20, auxiliary_data_block_size); - G32 (28, algorithm_type); - G64 (32, hash_offset); - G64 (40, hash_size); - G64 (48, signature_offset); - G64 (56, signature_size); - G64 (64, public_key_offset); - G64 (72, public_key_size); - G64 (80, public_key_metadata_offset); - G64 (88, public_key_metadata_size); - G64 (96, descriptors_offset); - G64 (104, descriptors_size); - G64 (112, rollback_index); - G32 (120, flags); - G32 (124, rollback_index_location); - memcpy(release_string, p + 128, AVB_RELEASE_STRING_SIZE); - - /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE - * bytes. This must be set to zeroes. - */ - // Byte reserved[80]; - return true; -} - - -static const unsigned k_Descriptor_Size = 16; - -enum AvbDescriptorTag -{ - AVB_DESCRIPTOR_TAG_PROPERTY, - AVB_DESCRIPTOR_TAG_HASHTREE, - AVB_DESCRIPTOR_TAG_HASH, - AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE, - AVB_DESCRIPTOR_TAG_CHAIN_PARTITION -}; - -struct AvbDescriptor -{ - UInt64 Tag; - UInt64 Size; - - void Parse(const Byte *p) - { - G64 (0, Tag); - G64 (8, Size); - } -}; - - -enum AvbHashtreeDescriptorFlags -{ - AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), - AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE = (1 << 1) -}; - -/* A descriptor containing information about a dm-verity hashtree. - * - * Hash-trees are used to verify large partitions typically containing - * file systems. See - * https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for more - * information about dm-verity. - * - * Following this struct are |partition_name_len| bytes of the - * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then - * |root_digest_len| bytes of the root digest. - * - * The |reserved| field is for future expansion and must be set to NUL - * bytes. - * - * Changes in v1.1: - * - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB - * - digest_len may be zero, which indicates the use of a persistent digest - */ - -static const unsigned k_Hashtree_Size_Min = 164; - -struct AvbHashtreeDescriptor -{ - UInt32 dm_verity_version; - UInt64 image_size; - UInt64 tree_offset; - UInt64 tree_size; - UInt32 data_block_size; - UInt32 hash_block_size; - UInt32 fec_num_roots; - UInt64 fec_offset; - UInt64 fec_size; - Byte hash_algorithm[32]; - UInt32 partition_name_len; - UInt32 salt_len; - UInt32 root_digest_len; - UInt32 flags; - Byte reserved[60]; - void Parse(const Byte *p) - { - G32 (0, dm_verity_version); - G64 (4, image_size); - G64 (12, tree_offset); - G64 (20, tree_size); - G32 (28, data_block_size); - G32 (32, hash_block_size); - G32 (36, fec_num_roots); - G64 (40, fec_offset); - G64 (48, fec_size); - memcpy(hash_algorithm, p + 56, 32); - G32 (88, partition_name_len); - G32 (92, salt_len); - G32 (96, root_digest_len); - G32 (100, flags); - } -}; - -static const unsigned k_PropertyDescriptor_Size_Min = 16; - -struct AvbPropertyDescriptor -{ - UInt64 key_num_bytes; - UInt64 value_num_bytes; - - void Parse(const Byte *p) - { - G64 (0, key_num_bytes); - G64 (8, value_num_bytes); - } -}; - -Z7_class_CHandler_final: public CHandlerCont -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - // UInt64 _startOffset; - UInt64 _phySize; - - CFooter Footer; - AString Name; - const char *Ext; - - HRESULT Open2(IInStream *stream); - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override - { - if (index != 0) - return NExtract::NOperationResult::kUnavailable; - // pos = _startOffset; - pos = 0; - size = Footer.original_image_size; - return NExtract::NOperationResult::kOK; - } -}; - - -HRESULT CHandler::Open2(IInStream *stream) -{ - UInt64 fileSize; - { - Byte buf[kFooterSize]; - RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) - if (fileSize < kFooterSize) - return S_FALSE; - RINOK(InStream_SeekSet(stream, fileSize - kFooterSize)) - RINOK(ReadStream_FALSE(stream, buf, kFooterSize)) - if (memcmp(buf, k_Signature, k_SignatureSize) != 0) - return S_FALSE; - Footer.Parse(buf); - if (Footer.vbmeta_size > VBMETA_MAX_SIZE || - Footer.vbmeta_size < AVB_VBMETA_IMAGE_HEADER_SIZE) - return S_FALSE; - for (unsigned i = 36; i < kFooterSize; i++) - if (buf[i] != 0) - return S_FALSE; - } - { - CByteBuffer buf; - buf.Alloc((size_t)Footer.vbmeta_size); - RINOK(InStream_SeekSet(stream, Footer.vbmeta_offset)) - RINOK(ReadStream_FALSE(stream, buf, (size_t)Footer.vbmeta_size)) - - AvbVBMetaImageHeader meta; - if (!meta.Parse(buf)) - return S_FALSE; - - unsigned offset = (unsigned)AVB_VBMETA_IMAGE_HEADER_SIZE; - unsigned rem = (unsigned)(Footer.vbmeta_size - offset); - - if (meta.authentication_data_block_size != 0) - { - if (rem < meta.authentication_data_block_size) - return S_FALSE; - const unsigned u = (unsigned)meta.authentication_data_block_size; - offset += u; - rem -= u; - } - - if (rem < meta.descriptors_offset || - rem - meta.descriptors_offset < meta.descriptors_size) - return S_FALSE; - rem = (unsigned)meta.descriptors_size; - while (rem != 0) - { - if (rem < k_Descriptor_Size) - return S_FALSE; - AvbDescriptor desc; - desc.Parse(buf + offset); - offset += k_Descriptor_Size; - rem -= k_Descriptor_Size; - if (desc.Size > rem) - return S_FALSE; - const unsigned descSize = (unsigned)desc.Size; - if (desc.Tag == AVB_DESCRIPTOR_TAG_HASHTREE) - { - if (descSize < k_Hashtree_Size_Min) - return S_FALSE; - AvbHashtreeDescriptor ht; - ht.Parse(buf + offset); - unsigned pos = k_Hashtree_Size_Min; - - if (pos + ht.partition_name_len > descSize) - return S_FALSE; - Name.Empty(); // UTF-8 - AddNameToString(Name, buf + offset + pos, ht.partition_name_len, false); - pos += ht.partition_name_len; - - if (pos + ht.salt_len > descSize) - return S_FALSE; - CByteBuffer salt; - salt.CopyFrom(buf + offset + pos, ht.salt_len); - pos += ht.salt_len; - - if (pos + ht.root_digest_len > descSize) - return S_FALSE; - CByteBuffer digest; - digest.CopyFrom(buf + offset + pos, ht.root_digest_len); - pos += ht.root_digest_len; - // what is that digest? - } - else if (desc.Tag == AVB_DESCRIPTOR_TAG_PROPERTY) - { - if (descSize < k_PropertyDescriptor_Size_Min + 2) - return S_FALSE; - AvbPropertyDescriptor pt; - pt.Parse(buf + offset); - unsigned pos = k_PropertyDescriptor_Size_Min; - - if (pt.key_num_bytes > descSize - pos - 1) - return S_FALSE; - AString key; // UTF-8 - AddNameToString(key, buf + offset + pos, (unsigned)pt.key_num_bytes, false); - pos += (unsigned)pt.key_num_bytes + 1; - - if (descSize < pos) - return S_FALSE; - if (pt.value_num_bytes > descSize - pos - 1) - return S_FALSE; - AString value; // UTF-8 - AddNameToString(value, buf + offset + pos, (unsigned)pt.value_num_bytes, false); - pos += (unsigned)pt.value_num_bytes + 1; - } - offset += descSize; - rem -= descSize; - } - - _phySize = fileSize; - - // _startOffset = 0; - return S_OK; - } -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - try - { - if (Open2(stream) != S_OK) - return S_FALSE; - _stream = stream; - - { - CMyComPtr parseStream; - if (GetStream(0, &parseStream) == S_OK && parseStream) - { - const size_t kParseSize = 1 << 11; - Byte buf[kParseSize]; - if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK) - { - UInt64 extSize; - if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES) - if (extSize == Footer.original_image_size) - Ext = "ext"; - } - } - } - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _stream.Release(); - // _startOffset = 0; - _phySize = 0; - Ext = NULL; - Name.Empty(); - return S_OK; -} - - -static const Byte kArcProps[] = -{ - kpidName -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidPhySize: prop = _phySize; break; - case kpidName: - { - if (!Name.IsEmpty()) - { - AString s (Name); - s += ".avb"; - prop = s; - } - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidPath: - { - if (!Name.IsEmpty()) - { - AString s (Name); - s += '.'; - s += Ext ? Ext : "img"; - prop = s; - } - break; - } - case kpidPackSize: - case kpidSize: - prop = Footer.original_image_size; - break; - case kpidExtension: prop = (Ext ? Ext : "img"); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - - -REGISTER_ARC_I_NO_SIG( - "AVB", "avb img", NULL, 0xc0, - /* k_Signature, */ - 0, - /* NArcInfoFlags::kUseGlobalOffset | */ - NArcInfoFlags::kBackwardOpen - , - NULL) - -}} +// AvbHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +#define G32(_offs_, dest) dest = Get32(p + (_offs_)) +#define G64(_offs_, dest) dest = Get64(p + (_offs_)) + +using namespace NWindows; + +namespace NArchive { + +namespace NExt { +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); +} + +namespace NAvb { + +static void AddNameToString(AString &s, const Byte *name, unsigned size, bool strictConvert) +{ + for (unsigned i = 0; i < size; i++) + { + Byte c = name[i]; + if (c == 0) + return; + if (strictConvert && c < 32) + c = '_'; + s += (char)c; + } +} + +/* Maximum size of a vbmeta image - 64 KiB. */ +#define VBMETA_MAX_SIZE (64 * 1024) + +#define SIGNATURE { 'A', 'V', 'B', 'f', 0, 0, 0, 1 } + +static const unsigned k_SignatureSize = 8; +static const Byte k_Signature[k_SignatureSize] = SIGNATURE; + +// #define AVB_FOOTER_MAGIC "AVBf" +// #define AVB_FOOTER_MAGIC_LEN 4 +/* The current footer version used - keep in sync with avbtool. */ +#define AVB_FOOTER_VERSION_MAJOR 1 + +/* The struct used as a footer used on partitions, used to find the + * AvbVBMetaImageHeader struct. This struct is always stored at the + * end of a partition. + */ +// #define AVB_FOOTER_SIZE 64 +static const unsigned kFooterSize = 64; + +struct CFooter +{ + /* 0: Four bytes equal to "AVBf" (AVB_FOOTER_MAGIC). */ + // Byte magic[AVB_FOOTER_MAGIC_LEN]; + /* 4: The major version of the footer struct. */ + UInt32 version_major; + /* 8: The minor version of the footer struct. */ + UInt32 version_minor; + + /* 12: The original size of the image on the partition. */ + UInt64 original_image_size; + + /* 20: The offset of the |AvbVBMetaImageHeader| struct. */ + UInt64 vbmeta_offset; + + /* 28: The size of the vbmeta block (header + auth + aux blocks). */ + UInt64 vbmeta_size; + + /* 36: Padding to ensure struct is size AVB_FOOTER_SIZE bytes. This + * must be set to zeroes. + */ + Byte reserved[28]; + + void Parse(const Byte *p) + { + G32 (4, version_major); + G32 (8, version_minor); + G64 (12, original_image_size); + G64 (20, vbmeta_offset); + G64 (28, vbmeta_size); + } +}; + + +/* Size of the vbmeta image header. */ +#define AVB_VBMETA_IMAGE_HEADER_SIZE 256 + +/* Magic for the vbmeta image header. */ +// #define AVB_MAGIC "AVB0" +// #define AVB_MAGIC_LEN 4 +/* Maximum size of the release string including the terminating NUL byte. */ +#define AVB_RELEASE_STRING_SIZE 48 + +struct AvbVBMetaImageHeader +{ + /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ + // Byte magic[AVB_MAGIC_LEN]; + + /* 4: The major version of libavb required for this header. */ + UInt32 required_libavb_version_major; + /* 8: The minor version of libavb required for this header. */ + UInt32 required_libavb_version_minor; + + /* 12: The size of the signature block. */ + UInt64 authentication_data_block_size; + /* 20: The size of the auxiliary data block. */ + UInt64 auxiliary_data_block_size; + + /* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */ + UInt32 algorithm_type; + + /* 32: Offset into the "Authentication data" block of hash data. */ + UInt64 hash_offset; + /* 40: Length of the hash data. */ + UInt64 hash_size; + + /* 48: Offset into the "Authentication data" block of signature data. */ + UInt64 signature_offset; + /* 56: Length of the signature data. */ + UInt64 signature_size; + + /* 64: Offset into the "Auxiliary data" block of public key data. */ + UInt64 public_key_offset; + /* 72: Length of the public key data. */ + UInt64 public_key_size; + + /* 80: Offset into the "Auxiliary data" block of public key metadata. */ + UInt64 public_key_metadata_offset; + /* 88: Length of the public key metadata. Must be set to zero if there + * is no public key metadata. + */ + UInt64 public_key_metadata_size; + + /* 96: Offset into the "Auxiliary data" block of descriptor data. */ + UInt64 descriptors_offset; + /* 104: Length of descriptor data. */ + UInt64 descriptors_size; + + /* 112: The rollback index which can be used to prevent rollback to + * older versions. + */ + UInt64 rollback_index; + + /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be + * set to zero if the vbmeta image is not a top-level image. + */ + UInt32 flags; + + /* 124: The location of the rollback index defined in this header. + * Only valid for the main vbmeta. For chained partitions, the rollback + * index location must be specified in the AvbChainPartitionDescriptor + * and this value must be set to 0. + */ + UInt32 rollback_index_location; + + /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or + * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL + * terminated. Applications must not make assumptions about how this + * string is formatted. + */ + Byte release_string[AVB_RELEASE_STRING_SIZE]; + + /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE + * bytes. This must be set to zeroes. + */ + // Byte reserved[80]; + bool Parse(const Byte *p); +}; + +bool AvbVBMetaImageHeader::Parse(const Byte *p) +{ + // Byte magic[AVB_MAGIC_LEN]; + if (Get32(p) != 0x41564230) // "AVB0" + return false; + G32 (4, required_libavb_version_major); + if (required_libavb_version_major != AVB_FOOTER_VERSION_MAJOR) // "AVB0" + return false; + G32 (8, required_libavb_version_minor); + G64 (12, authentication_data_block_size); + G64 (20, auxiliary_data_block_size); + G32 (28, algorithm_type); + G64 (32, hash_offset); + G64 (40, hash_size); + G64 (48, signature_offset); + G64 (56, signature_size); + G64 (64, public_key_offset); + G64 (72, public_key_size); + G64 (80, public_key_metadata_offset); + G64 (88, public_key_metadata_size); + G64 (96, descriptors_offset); + G64 (104, descriptors_size); + G64 (112, rollback_index); + G32 (120, flags); + G32 (124, rollback_index_location); + memcpy(release_string, p + 128, AVB_RELEASE_STRING_SIZE); + + /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE + * bytes. This must be set to zeroes. + */ + // Byte reserved[80]; + return true; +} + + +static const unsigned k_Descriptor_Size = 16; + +enum AvbDescriptorTag +{ + AVB_DESCRIPTOR_TAG_PROPERTY, + AVB_DESCRIPTOR_TAG_HASHTREE, + AVB_DESCRIPTOR_TAG_HASH, + AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE, + AVB_DESCRIPTOR_TAG_CHAIN_PARTITION +}; + +struct AvbDescriptor +{ + UInt64 Tag; + UInt64 Size; + + void Parse(const Byte *p) + { + G64 (0, Tag); + G64 (8, Size); + } +}; + + +enum AvbHashtreeDescriptorFlags +{ + AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0), + AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE = (1 << 1) +}; + +/* A descriptor containing information about a dm-verity hashtree. + * + * Hash-trees are used to verify large partitions typically containing + * file systems. See + * https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for more + * information about dm-verity. + * + * Following this struct are |partition_name_len| bytes of the + * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then + * |root_digest_len| bytes of the root digest. + * + * The |reserved| field is for future expansion and must be set to NUL + * bytes. + * + * Changes in v1.1: + * - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB + * - digest_len may be zero, which indicates the use of a persistent digest + */ + +static const unsigned k_Hashtree_Size_Min = 164; + +struct AvbHashtreeDescriptor +{ + UInt32 dm_verity_version; + UInt64 image_size; + UInt64 tree_offset; + UInt64 tree_size; + UInt32 data_block_size; + UInt32 hash_block_size; + UInt32 fec_num_roots; + UInt64 fec_offset; + UInt64 fec_size; + Byte hash_algorithm[32]; + UInt32 partition_name_len; + UInt32 salt_len; + UInt32 root_digest_len; + UInt32 flags; + Byte reserved[60]; + void Parse(const Byte *p) + { + G32 (0, dm_verity_version); + G64 (4, image_size); + G64 (12, tree_offset); + G64 (20, tree_size); + G32 (28, data_block_size); + G32 (32, hash_block_size); + G32 (36, fec_num_roots); + G64 (40, fec_offset); + G64 (48, fec_size); + memcpy(hash_algorithm, p + 56, 32); + G32 (88, partition_name_len); + G32 (92, salt_len); + G32 (96, root_digest_len); + G32 (100, flags); + } +}; + +static const unsigned k_PropertyDescriptor_Size_Min = 16; + +struct AvbPropertyDescriptor +{ + UInt64 key_num_bytes; + UInt64 value_num_bytes; + + void Parse(const Byte *p) + { + G64 (0, key_num_bytes); + G64 (8, value_num_bytes); + } +}; + +Z7_class_CHandler_final: public CHandlerCont +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + // UInt64 _startOffset; + UInt64 _phySize; + + CFooter Footer; + AString Name; + const char *Ext; + + HRESULT Open2(IInStream *stream); + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override + { + if (index != 0) + return NExtract::NOperationResult::kUnavailable; + // pos = _startOffset; + pos = 0; + size = Footer.original_image_size; + return NExtract::NOperationResult::kOK; + } +}; + + +HRESULT CHandler::Open2(IInStream *stream) +{ + UInt64 fileSize; + { + Byte buf[kFooterSize]; + RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) + if (fileSize < kFooterSize) + return S_FALSE; + RINOK(InStream_SeekSet(stream, fileSize - kFooterSize)) + RINOK(ReadStream_FALSE(stream, buf, kFooterSize)) + if (memcmp(buf, k_Signature, k_SignatureSize) != 0) + return S_FALSE; + Footer.Parse(buf); + if (Footer.vbmeta_size > VBMETA_MAX_SIZE || + Footer.vbmeta_size < AVB_VBMETA_IMAGE_HEADER_SIZE) + return S_FALSE; + for (unsigned i = 36; i < kFooterSize; i++) + if (buf[i] != 0) + return S_FALSE; + } + { + CByteBuffer buf; + buf.Alloc((size_t)Footer.vbmeta_size); + RINOK(InStream_SeekSet(stream, Footer.vbmeta_offset)) + RINOK(ReadStream_FALSE(stream, buf, (size_t)Footer.vbmeta_size)) + + AvbVBMetaImageHeader meta; + if (!meta.Parse(buf)) + return S_FALSE; + + unsigned offset = (unsigned)AVB_VBMETA_IMAGE_HEADER_SIZE; + unsigned rem = (unsigned)(Footer.vbmeta_size - offset); + + if (meta.authentication_data_block_size != 0) + { + if (rem < meta.authentication_data_block_size) + return S_FALSE; + const unsigned u = (unsigned)meta.authentication_data_block_size; + offset += u; + rem -= u; + } + + if (rem < meta.descriptors_offset || + rem - meta.descriptors_offset < meta.descriptors_size) + return S_FALSE; + rem = (unsigned)meta.descriptors_size; + while (rem != 0) + { + if (rem < k_Descriptor_Size) + return S_FALSE; + AvbDescriptor desc; + desc.Parse(buf + offset); + offset += k_Descriptor_Size; + rem -= k_Descriptor_Size; + if (desc.Size > rem) + return S_FALSE; + const unsigned descSize = (unsigned)desc.Size; + if (desc.Tag == AVB_DESCRIPTOR_TAG_HASHTREE) + { + if (descSize < k_Hashtree_Size_Min) + return S_FALSE; + AvbHashtreeDescriptor ht; + ht.Parse(buf + offset); + unsigned pos = k_Hashtree_Size_Min; + + if (pos + ht.partition_name_len > descSize) + return S_FALSE; + Name.Empty(); // UTF-8 + AddNameToString(Name, buf + offset + pos, ht.partition_name_len, false); + pos += ht.partition_name_len; + + if (pos + ht.salt_len > descSize) + return S_FALSE; + CByteBuffer salt; + salt.CopyFrom(buf + offset + pos, ht.salt_len); + pos += ht.salt_len; + + if (pos + ht.root_digest_len > descSize) + return S_FALSE; + CByteBuffer digest; + digest.CopyFrom(buf + offset + pos, ht.root_digest_len); + pos += ht.root_digest_len; + // what is that digest? + } + else if (desc.Tag == AVB_DESCRIPTOR_TAG_PROPERTY) + { + if (descSize < k_PropertyDescriptor_Size_Min + 2) + return S_FALSE; + AvbPropertyDescriptor pt; + pt.Parse(buf + offset); + unsigned pos = k_PropertyDescriptor_Size_Min; + + if (pt.key_num_bytes > descSize - pos - 1) + return S_FALSE; + AString key; // UTF-8 + AddNameToString(key, buf + offset + pos, (unsigned)pt.key_num_bytes, false); + pos += (unsigned)pt.key_num_bytes + 1; + + if (descSize < pos) + return S_FALSE; + if (pt.value_num_bytes > descSize - pos - 1) + return S_FALSE; + AString value; // UTF-8 + AddNameToString(value, buf + offset + pos, (unsigned)pt.value_num_bytes, false); + pos += (unsigned)pt.value_num_bytes + 1; + } + offset += descSize; + rem -= descSize; + } + + _phySize = fileSize; + + // _startOffset = 0; + return S_OK; + } +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(stream) != S_OK) + return S_FALSE; + _stream = stream; + + { + CMyComPtr parseStream; + if (GetStream(0, &parseStream) == S_OK && parseStream) + { + const size_t kParseSize = 1 << 11; + Byte buf[kParseSize]; + if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK) + { + UInt64 extSize; + if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES) + if (extSize == Footer.original_image_size) + Ext = "ext"; + } + } + } + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _stream.Release(); + // _startOffset = 0; + _phySize = 0; + Ext = NULL; + Name.Empty(); + return S_OK; +} + + +static const Byte kArcProps[] = +{ + kpidName +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: prop = _phySize; break; + case kpidName: + { + if (!Name.IsEmpty()) + { + AString s (Name); + s += ".avb"; + prop = s; + } + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidPath: + { + if (!Name.IsEmpty()) + { + AString s (Name); + s += '.'; + s += Ext ? Ext : "img"; + prop = s; + } + break; + } + case kpidPackSize: + case kpidSize: + prop = Footer.original_image_size; + break; + case kpidExtension: prop = (Ext ? Ext : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + + +REGISTER_ARC_I_NO_SIG( + "AVB", "avb img", NULL, 0xc0, + /* k_Signature, */ + 0, + /* NArcInfoFlags::kUseGlobalOffset | */ + NArcInfoFlags::kBackwardOpen + , + NULL) + +}} diff --git a/CPP/7zip/Archive/Base64Handler.cpp b/CPP/7zip/Archive/Base64Handler.cpp index 59055d450..4df491c12 100644 --- a/CPP/7zip/Archive/Base64Handler.cpp +++ b/CPP/7zip/Archive/Base64Handler.cpp @@ -1,488 +1,488 @@ -// Base64Handler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyVector.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" -#include "../Common/InBuffer.h" - -/* -spaces: - 9(TAB),10(LF),13(CR),32(SPACE) - Non-breaking space: - 0xa0 : Unicode, Windows code pages 1250-1258 - 0xff (unused): DOS code pages - -end of stream markers: '=' (0x3d): - "=" , if numBytes (% 3 == 2) - "==" , if numBytes (% 3 == 1) -*/ - - -static const Byte k_Base64Table[256] = -{ - 66,77,77,77,77,77,77,77,77,65,65,77,77,65,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 65,77,77,77,77,77,77,77,77,77,77,62,77,77,77,63, - 52,53,54,55,56,57,58,59,60,61,77,77,77,64,77,77, - 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, - 15,16,17,18,19,20,21,22,23,24,25,77,77,77,77,77, - 77,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, - 41,42,43,44,45,46,47,48,49,50,51,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 65,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77 -}; - -static const unsigned k_Code_Equals = 64; -static const unsigned k_Code_Space = 65; -static const unsigned k_Code_Zero = 66; - -API_FUNC_static_IsArc IsArc_Base64(const Byte *p, size_t size) -{ - size_t num = 0; - size_t firstSpace = 0; - - for (;;) - { - if (size == 0) - return k_IsArc_Res_NEED_MORE; - UInt32 c = k_Base64Table[(Byte)(*p++)]; - size--; - if (c < 64) - { - num++; - continue; - } - - if (c == k_Code_Space) - { - if (p[-1] == ' ' && firstSpace == 0) - firstSpace = num; - continue; - } - - if (c != k_Code_Equals) - return k_IsArc_Res_NO; - break; - } - - { - // we try to redece false positive detection here. - // we don't expect space character in starting base64 line - const unsigned kNumExpectedNonSpaceSyms = 20; - if (firstSpace != 0 && firstSpace < num && firstSpace < kNumExpectedNonSpaceSyms) - return k_IsArc_Res_NO; - } - - num &= 3; - - if (num <= 1) - return k_IsArc_Res_NO; - if (num != 3) - { - if (size == 0) - return k_IsArc_Res_NEED_MORE; - UInt32 c = k_Base64Table[(Byte)(*p++)]; - size--; - if (c != k_Code_Equals) - return k_IsArc_Res_NO; - } - - for (;;) - { - if (size == 0) - return k_IsArc_Res_YES; - UInt32 c = k_Base64Table[(Byte)(*p++)]; - size--; - if (c == k_Code_Space) - continue; - return k_IsArc_Res_NO; - } -} -} - - -enum EBase64Res -{ - k_Base64_RES_MaybeFinished, - k_Base64_RES_Finished, - k_Base64_RES_NeedMoreInput, - k_Base64_RES_UnexpectedChar -}; - - -static EBase64Res Base64ToBin(Byte *p, size_t size, const Byte **srcEnd, Byte **destEnd) -{ - Byte *dest = p; - UInt32 val = 1; - EBase64Res res = k_Base64_RES_NeedMoreInput; - - for (;;) - { - if (size == 0) - { - if (val == 1) - res = k_Base64_RES_MaybeFinished; - break; - } - UInt32 c = k_Base64Table[(Byte)(*p++)]; - size--; - if (c < 64) - { - val = (val << 6) | c; - if ((val & ((UInt32)1 << 24)) == 0) - continue; - dest[0] = (Byte)(val >> 16); - dest[1] = (Byte)(val >> 8); - dest[2] = (Byte)(val); - dest += 3; - val = 1; - continue; - } - - if (c == k_Code_Space) - continue; - - if (c == k_Code_Equals) - { - if (val >= (1 << 12)) - { - if (val & (1 << 18)) - { - res = k_Base64_RES_Finished; - break; - } - if (size == 0) - break; - c = k_Base64Table[(Byte)(*p++)]; - size--; - if (c == k_Code_Equals) - { - res = k_Base64_RES_Finished; - break; - } - } - } - - p--; - res = k_Base64_RES_UnexpectedChar; - break; - } - - if (val >= ((UInt32)1 << 12)) - { - if (val & (1 << 18)) - { - *dest++ = (Byte)(val >> 10); - val <<= 2; - } - *dest++ = (Byte)(val >> 4); - } - - *srcEnd = p; - *destEnd = dest; - return res; -} - - -static const Byte *Base64_SkipSpaces(const Byte *p, size_t size) -{ - for (;;) - { - if (size == 0) - return p; - const UInt32 c = k_Base64Table[(Byte)(*p++)]; - size--; - if (c == k_Code_Space) - continue; - return p - 1; - } -} - - -// the following function is used by DmgHandler.cpp - -Byte *Base64ToBin(Byte *dest, const char *src); -Byte *Base64ToBin(Byte *dest, const char *src) -{ - UInt32 val = 1; - - for (;;) - { - const UInt32 c = k_Base64Table[(Byte)(*src++)]; - - if (c < 64) - { - val = (val << 6) | c; - if ((val & ((UInt32)1 << 24)) == 0) - continue; - dest[0] = (Byte)(val >> 16); - dest[1] = (Byte)(val >> 8); - dest[2] = (Byte)(val); - dest += 3; - val = 1; - continue; - } - - if (c == k_Code_Space) - continue; - - if (c == k_Code_Equals) - break; - - if (c == k_Code_Zero && val == 1) // end of string - return dest; - - return NULL; - } - - if (val < (1 << 12)) - return NULL; - - if (val & (1 << 18)) - { - *dest++ = (Byte)(val >> 10); - val <<= 2; - } - else if (k_Base64Table[(Byte)(*src++)] != k_Code_Equals) - return NULL; - *dest++ = (Byte)(val >> 4); - - for (;;) - { - const Byte c = k_Base64Table[(Byte)(*src++)]; - if (c == k_Code_Space) - continue; - if (c == k_Code_Zero) - return dest; - return NULL; - } -} - - -namespace NArchive { -namespace NBase64 { - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - bool _isArc; - UInt64 _phySize; - size_t _size; - EBase64Res _sres; - CByteBuffer _data; -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (v != 0) - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - // COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidSize: prop = (UInt64)_size; break; - case kpidPackSize: prop = _phySize; break; - } - prop.Detach(value); - return S_OK; - // COM_TRY_END -} - - -static HRESULT ReadStream_OpenProgress(ISequentialInStream *stream, void *data, size_t size, IArchiveOpenCallback *openCallback) throw() -{ - UInt64 bytes = 0; - while (size != 0) - { - const UInt32 kBlockSize = ((UInt32)1 << 24); - const UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; - UInt32 processedSizeLoc; - RINOK(stream->Read(data, curSize, &processedSizeLoc)) - if (processedSizeLoc == 0) - return E_FAIL; - data = (void *)((Byte *)data + processedSizeLoc); - size -= processedSizeLoc; - bytes += processedSizeLoc; - const UInt64 files = 1; - RINOK(openCallback->SetCompleted(&files, &bytes)) - } - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) -{ - COM_TRY_BEGIN - { - Close(); - { - const unsigned kStartSize = 1 << 12; - _data.Alloc(kStartSize); - size_t size = kStartSize; - RINOK(ReadStream(stream, _data, &size)) - if (IsArc_Base64(_data, size) == k_IsArc_Res_NO) - return S_FALSE; - } - _isArc = true; - - UInt64 packSize64; - RINOK(InStream_GetSize_SeekToEnd(stream, packSize64)) - if (packSize64 == 0) - return S_FALSE; - size_t curSize = 1 << 16; - if (curSize > packSize64) - curSize = (size_t)packSize64; - const unsigned kLogStep = 4; - - for (;;) - { - RINOK(InStream_SeekSet(stream, 0)) - - _data.Alloc(curSize); - RINOK(ReadStream_OpenProgress(stream, _data, curSize, openCallback)) - - const Byte *srcEnd; - Byte *dest; - _sres = Base64ToBin(_data, curSize, &srcEnd, &dest); - _size = (size_t)(dest - _data); - const size_t mainSize = (size_t)(srcEnd - _data); - _phySize = mainSize; - if (_sres == k_Base64_RES_UnexpectedChar) - break; - if (curSize != mainSize) - { - const Byte *end2 = Base64_SkipSpaces(srcEnd, curSize - mainSize); - if ((size_t)(end2 - _data) != curSize) - break; - _phySize = curSize; - } - - if (curSize == packSize64) - break; - - UInt64 curSize64 = packSize64; - if (curSize < (packSize64 >> kLogStep)) - curSize64 = (UInt64)curSize << kLogStep; - curSize = (size_t)curSize64; - if (curSize != curSize64) - return E_OUTOFMEMORY; - } - if (_size == 0) - return S_FALSE; - return S_OK; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - _size = 0; - _isArc = false; - _sres = k_Base64_RES_MaybeFinished; - _data.Free(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - RINOK(extractCallback->SetTotal(_size)) - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - // RINOK(lps->SetCur()) - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - RINOK(extractCallback->PrepareOperation(askMode)) - if (realOutStream) - { - RINOK(WriteStream(realOutStream, (const Byte *)_data, _size)) - } - opRes = NExtract::NOperationResult::kOK; - if (_sres != k_Base64_RES_Finished) - { - if (_sres == k_Base64_RES_NeedMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (_sres == k_Base64_RES_UnexpectedChar) - opRes = NExtract::NOperationResult::kDataError; - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - lps->InSize = _phySize; - lps->OutSize = _size; - return lps->SetCur(); - COM_TRY_END -} - -REGISTER_ARC_I_NO_SIG( - "Base64", "b64", NULL, 0xC5, - 0, - NArcInfoFlags::kKeepName - | NArcInfoFlags::kStartOpen - | NArcInfoFlags::kByExtOnlyOpen, - IsArc_Base64) - -}} +// Base64Handler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyVector.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" +#include "../Common/InBuffer.h" + +/* +spaces: + 9(TAB),10(LF),13(CR),32(SPACE) + Non-breaking space: + 0xa0 : Unicode, Windows code pages 1250-1258 + 0xff (unused): DOS code pages + +end of stream markers: '=' (0x3d): + "=" , if numBytes (% 3 == 2) + "==" , if numBytes (% 3 == 1) +*/ + + +static const Byte k_Base64Table[256] = +{ + 66,77,77,77,77,77,77,77,77,65,65,77,77,65,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 65,77,77,77,77,77,77,77,77,77,77,62,77,77,77,63, + 52,53,54,55,56,57,58,59,60,61,77,77,77,64,77,77, + 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24,25,77,77,77,77,77, + 77,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50,51,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 65,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77 +}; + +static const unsigned k_Code_Equals = 64; +static const unsigned k_Code_Space = 65; +static const unsigned k_Code_Zero = 66; + +API_FUNC_static_IsArc IsArc_Base64(const Byte *p, size_t size) +{ + size_t num = 0; + size_t firstSpace = 0; + + for (;;) + { + if (size == 0) + return k_IsArc_Res_NEED_MORE; + UInt32 c = k_Base64Table[(Byte)(*p++)]; + size--; + if (c < 64) + { + num++; + continue; + } + + if (c == k_Code_Space) + { + if (p[-1] == ' ' && firstSpace == 0) + firstSpace = num; + continue; + } + + if (c != k_Code_Equals) + return k_IsArc_Res_NO; + break; + } + + { + // we try to redece false positive detection here. + // we don't expect space character in starting base64 line + const unsigned kNumExpectedNonSpaceSyms = 20; + if (firstSpace != 0 && firstSpace < num && firstSpace < kNumExpectedNonSpaceSyms) + return k_IsArc_Res_NO; + } + + num &= 3; + + if (num <= 1) + return k_IsArc_Res_NO; + if (num != 3) + { + if (size == 0) + return k_IsArc_Res_NEED_MORE; + UInt32 c = k_Base64Table[(Byte)(*p++)]; + size--; + if (c != k_Code_Equals) + return k_IsArc_Res_NO; + } + + for (;;) + { + if (size == 0) + return k_IsArc_Res_YES; + UInt32 c = k_Base64Table[(Byte)(*p++)]; + size--; + if (c == k_Code_Space) + continue; + return k_IsArc_Res_NO; + } +} +} + + +enum EBase64Res +{ + k_Base64_RES_MaybeFinished, + k_Base64_RES_Finished, + k_Base64_RES_NeedMoreInput, + k_Base64_RES_UnexpectedChar +}; + + +static EBase64Res Base64ToBin(Byte *p, size_t size, const Byte **srcEnd, Byte **destEnd) +{ + Byte *dest = p; + UInt32 val = 1; + EBase64Res res = k_Base64_RES_NeedMoreInput; + + for (;;) + { + if (size == 0) + { + if (val == 1) + res = k_Base64_RES_MaybeFinished; + break; + } + UInt32 c = k_Base64Table[(Byte)(*p++)]; + size--; + if (c < 64) + { + val = (val << 6) | c; + if ((val & ((UInt32)1 << 24)) == 0) + continue; + dest[0] = (Byte)(val >> 16); + dest[1] = (Byte)(val >> 8); + dest[2] = (Byte)(val); + dest += 3; + val = 1; + continue; + } + + if (c == k_Code_Space) + continue; + + if (c == k_Code_Equals) + { + if (val >= (1 << 12)) + { + if (val & (1 << 18)) + { + res = k_Base64_RES_Finished; + break; + } + if (size == 0) + break; + c = k_Base64Table[(Byte)(*p++)]; + size--; + if (c == k_Code_Equals) + { + res = k_Base64_RES_Finished; + break; + } + } + } + + p--; + res = k_Base64_RES_UnexpectedChar; + break; + } + + if (val >= ((UInt32)1 << 12)) + { + if (val & (1 << 18)) + { + *dest++ = (Byte)(val >> 10); + val <<= 2; + } + *dest++ = (Byte)(val >> 4); + } + + *srcEnd = p; + *destEnd = dest; + return res; +} + + +static const Byte *Base64_SkipSpaces(const Byte *p, size_t size) +{ + for (;;) + { + if (size == 0) + return p; + const UInt32 c = k_Base64Table[(Byte)(*p++)]; + size--; + if (c == k_Code_Space) + continue; + return p - 1; + } +} + + +// the following function is used by DmgHandler.cpp + +Byte *Base64ToBin(Byte *dest, const char *src); +Byte *Base64ToBin(Byte *dest, const char *src) +{ + UInt32 val = 1; + + for (;;) + { + const UInt32 c = k_Base64Table[(Byte)(*src++)]; + + if (c < 64) + { + val = (val << 6) | c; + if ((val & ((UInt32)1 << 24)) == 0) + continue; + dest[0] = (Byte)(val >> 16); + dest[1] = (Byte)(val >> 8); + dest[2] = (Byte)(val); + dest += 3; + val = 1; + continue; + } + + if (c == k_Code_Space) + continue; + + if (c == k_Code_Equals) + break; + + if (c == k_Code_Zero && val == 1) // end of string + return dest; + + return NULL; + } + + if (val < (1 << 12)) + return NULL; + + if (val & (1 << 18)) + { + *dest++ = (Byte)(val >> 10); + val <<= 2; + } + else if (k_Base64Table[(Byte)(*src++)] != k_Code_Equals) + return NULL; + *dest++ = (Byte)(val >> 4); + + for (;;) + { + const Byte c = k_Base64Table[(Byte)(*src++)]; + if (c == k_Code_Space) + continue; + if (c == k_Code_Zero) + return dest; + return NULL; + } +} + + +namespace NArchive { +namespace NBase64 { + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + bool _isArc; + UInt64 _phySize; + size_t _size; + EBase64Res _sres; + CByteBuffer _data; +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (v != 0) + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + // COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidSize: prop = (UInt64)_size; break; + case kpidPackSize: prop = _phySize; break; + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + + +static HRESULT ReadStream_OpenProgress(ISequentialInStream *stream, void *data, size_t size, IArchiveOpenCallback *openCallback) throw() +{ + UInt64 bytes = 0; + while (size != 0) + { + const UInt32 kBlockSize = ((UInt32)1 << 24); + const UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; + UInt32 processedSizeLoc; + RINOK(stream->Read(data, curSize, &processedSizeLoc)) + if (processedSizeLoc == 0) + return E_FAIL; + data = (void *)((Byte *)data + processedSizeLoc); + size -= processedSizeLoc; + bytes += processedSizeLoc; + const UInt64 files = 1; + RINOK(openCallback->SetCompleted(&files, &bytes)) + } + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) +{ + COM_TRY_BEGIN + { + Close(); + { + const unsigned kStartSize = 1 << 12; + _data.Alloc(kStartSize); + size_t size = kStartSize; + RINOK(ReadStream(stream, _data, &size)) + if (IsArc_Base64(_data, size) == k_IsArc_Res_NO) + return S_FALSE; + } + _isArc = true; + + UInt64 packSize64; + RINOK(InStream_GetSize_SeekToEnd(stream, packSize64)) + if (packSize64 == 0) + return S_FALSE; + size_t curSize = 1 << 16; + if (curSize > packSize64) + curSize = (size_t)packSize64; + const unsigned kLogStep = 4; + + for (;;) + { + RINOK(InStream_SeekSet(stream, 0)) + + _data.Alloc(curSize); + RINOK(ReadStream_OpenProgress(stream, _data, curSize, openCallback)) + + const Byte *srcEnd; + Byte *dest; + _sres = Base64ToBin(_data, curSize, &srcEnd, &dest); + _size = (size_t)(dest - _data); + const size_t mainSize = (size_t)(srcEnd - _data); + _phySize = mainSize; + if (_sres == k_Base64_RES_UnexpectedChar) + break; + if (curSize != mainSize) + { + const Byte *end2 = Base64_SkipSpaces(srcEnd, curSize - mainSize); + if ((size_t)(end2 - _data) != curSize) + break; + _phySize = curSize; + } + + if (curSize == packSize64) + break; + + UInt64 curSize64 = packSize64; + if (curSize < (packSize64 >> kLogStep)) + curSize64 = (UInt64)curSize << kLogStep; + curSize = (size_t)curSize64; + if (curSize != curSize64) + return E_OUTOFMEMORY; + } + if (_size == 0) + return S_FALSE; + return S_OK; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + _size = 0; + _isArc = false; + _sres = k_Base64_RES_MaybeFinished; + _data.Free(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + RINOK(extractCallback->SetTotal(_size)) + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + // RINOK(lps->SetCur()) + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + RINOK(extractCallback->PrepareOperation(askMode)) + if (realOutStream) + { + RINOK(WriteStream(realOutStream, (const Byte *)_data, _size)) + } + opRes = NExtract::NOperationResult::kOK; + if (_sres != k_Base64_RES_Finished) + { + if (_sres == k_Base64_RES_NeedMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_sres == k_Base64_RES_UnexpectedChar) + opRes = NExtract::NOperationResult::kDataError; + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + lps->InSize = _phySize; + lps->OutSize = _size; + return lps->SetCur(); + COM_TRY_END +} + +REGISTER_ARC_I_NO_SIG( + "Base64", "b64", NULL, 0xC5, + 0, + NArcInfoFlags::kKeepName + | NArcInfoFlags::kStartOpen + | NArcInfoFlags::kByExtOnlyOpen, + IsArc_Base64) + +}} diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp index 3b0636951..ffd7ad043 100644 --- a/CPP/7zip/Archive/Bz2Handler.cpp +++ b/CPP/7zip/Archive/Bz2Handler.cpp @@ -1,478 +1,478 @@ -// Bz2Handler.cpp - -#include "StdAfx.h" - -#include "../../Common/ComTry.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/BZip2Decoder.h" -#include "../Compress/BZip2Encoder.h" -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" -#include "Common/HandlerOut.h" - -using namespace NWindows; - -namespace NArchive { -namespace NBz2 { - -Z7_CLASS_IMP_CHandler_IInArchive_3( - IArchiveOpenSeq, - IOutArchive, - ISetProperties -) - CMyComPtr _stream; - CMyComPtr _seqStream; - - bool _isArc; - bool _needSeekToStart; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - bool _numStreams_Defined; - bool _numBlocks_Defined; - - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numStreams; - UInt64 _numBlocks; - - CSingleMethodProps _props; -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; - case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; - case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; - case kpidNumBlocks: if (_numBlocks_Defined) prop = _numBlocks; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; - prop = v; - break; - } - default: break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; - case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break; - default: break; - } - prop.Detach(value); - return S_OK; -} - -static const unsigned kSignatureCheckSize = 10; - -API_FUNC_static_IsArc IsArc_BZip2(const Byte *p, size_t size) -{ - if (size < kSignatureCheckSize) - return k_IsArc_Res_NEED_MORE; - if (p[0] != 'B' || p[1] != 'Z' || p[2] != 'h' || p[3] < '1' || p[3] > '9') - return k_IsArc_Res_NO; - p += 4; - if (NCompress::NBZip2::IsBlockSig(p)) - return k_IsArc_Res_YES; - if (NCompress::NBZip2::IsEndSig(p)) - return k_IsArc_Res_YES; - return k_IsArc_Res_NO; -} -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) -{ - COM_TRY_BEGIN - Close(); - { - Byte buf[kSignatureCheckSize]; - RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)) - if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO) - return S_FALSE; - _isArc = true; - _stream = stream; - _seqStream = stream; - _needSeekToStart = true; - } - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _needSeekToStart = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - _numStreams_Defined = false; - _numBlocks_Defined = false; - - _packSize = 0; - - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - { - RINOK(extractCallback->SetTotal(_packSize)) - } - - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(InStream_SeekToBegin(_stream)) - } - else - _needSeekToStart = true; - - // try { - - CMyComPtr2_Create decoder; - - #ifndef Z7_ST - RINOK(decoder->SetNumberOfThreads(_props._numThreads)) - #endif - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(); - // realOutStream.Release(); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - - decoder->FinishMode = true; - decoder->Base.DecodeAllStreams = true; - - _dataAfterEnd = false; - _needMoreInput = false; - - HRESULT result = decoder.Interface()->Code(_seqStream, outStream, NULL, NULL, lps); - - if (result != S_FALSE && result != S_OK) - return result; - - if (decoder->Base.NumStreams == 0) - { - _isArc = false; - result = S_FALSE; - } - else - { - const UInt64 inProcessedSize = decoder->GetInputProcessedSize(); - UInt64 packSize = inProcessedSize; - - if (decoder->Base.NeedMoreInput) - _needMoreInput = true; - - if (!decoder->Base.IsBz) - { - packSize = decoder->Base.FinishedPackSize; - if (packSize != inProcessedSize) - _dataAfterEnd = true; - } - - _packSize = packSize; - _unpackSize = decoder->GetOutProcessedSize(); - _numStreams = decoder->Base.NumStreams; - _numBlocks = decoder->GetNumBlocks(); - - _packSize_Defined = true; - _unpackSize_Defined = true; - _numStreams_Defined = true; - _numBlocks_Defined = true; - - // RINOK( - lps.Interface()->SetRatioInfo(&packSize, &_unpackSize); - } - - // outStream.Release(); - - if (!_isArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (decoder->GetCrcError()) - opRes = NExtract::NOperationResult::kCRCError; - else if (_dataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (decoder->Base.MinorError) - opRes = NExtract::NOperationResult::kDataError; - else if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else - return result; - - } - return extractCallback->SetOperationResult(opRes); - - // } catch(...) { return E_FAIL; } - - COM_TRY_END -} - - -/* -static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) -{ - return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value); -} - -static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) -{ - return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value); -} - -static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, - const UInt64 *unpackSize, - const UInt64 *numBlocks) -{ - NCOM::CPropVariant sizeProp; - if (unpackSize) - { - sizeProp = *unpackSize; - RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp)); - RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK)); - } - - if (unpackSize) - { - RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp)); - } - if (numBlocks) - { - NCOM::CPropVariant prop; - prop = *numBlocks; - RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop)); - } - return S_OK; -} -*/ - -static HRESULT UpdateArchive( - UInt64 unpackSize, - ISequentialOutStream *outStream, - const CProps &props, - IArchiveUpdateCallback *updateCallback - // , ArchiveUpdateCallbackArcProp *reportArcProp - ) -{ - { - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)) - if (!fileInStream) - return S_FALSE; - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamGetSize, - streamGetSize, fileInStream) - if (streamGetSize) - { - UInt64 size; - if (streamGetSize->GetSize(&size) == S_OK) - unpackSize = size; - } - } - RINOK(updateCallback->SetTotal(unpackSize)) - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - { - CMyComPtr2_Create encoder; - RINOK(props.SetCoderProps(encoder.ClsPtr(), NULL)) - RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) - /* - if (reportArcProp) - { - unpackSize = encoderSpec->GetInProcessedSize(); - RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks)); - } - */ - } - } - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); -} - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) -{ - *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; - // *timeType = NFileTimeType::kUnix; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback)) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamSetRestriction, - setRestriction, outStream) - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - } - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) - - // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback) - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) - if (prop.vt != VT_EMPTY) - if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) - return E_INVALIDARG; - } - } - - if (IntToBool(newData)) - { - UInt64 size; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - } - - CMethodProps props2 = _props; - #ifndef Z7_ST - props2.AddProp_NumThreads(_props._numThreads); - #endif - - return UpdateArchive(size, outStream, props2, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveUpdateCallbackFile, - opCallback, updateCallback) - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(InStream_SeekToBegin(_stream)) - - return NCompress::CopyStream(_stream, outStream, lps); - - // return ReportArcProps(reportArcProp, NULL, NULL); - - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - return _props.SetProperties(names, values, numProps); -} - -static const Byte k_Signature[] = { 'B', 'Z', 'h' }; - -REGISTER_ARC_IO( - "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, - k_Signature, - 0, - NArcInfoFlags::kKeepName - , 0 - , IsArc_BZip2) - -}} +// Bz2Handler.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/BZip2Decoder.h" +#include "../Compress/BZip2Encoder.h" +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" +#include "Common/HandlerOut.h" + +using namespace NWindows; + +namespace NArchive { +namespace NBz2 { + +Z7_CLASS_IMP_CHandler_IInArchive_3( + IArchiveOpenSeq, + IOutArchive, + ISetProperties +) + CMyComPtr _stream; + CMyComPtr _seqStream; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + bool _numBlocks_Defined; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + UInt64 _numBlocks; + + CSingleMethodProps _props; +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidNumBlocks: if (_numBlocks_Defined) prop = _numBlocks; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + prop = v; + break; + } + default: break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; + case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break; + default: break; + } + prop.Detach(value); + return S_OK; +} + +static const unsigned kSignatureCheckSize = 10; + +API_FUNC_static_IsArc IsArc_BZip2(const Byte *p, size_t size) +{ + if (size < kSignatureCheckSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'B' || p[1] != 'Z' || p[2] != 'h' || p[3] < '1' || p[3] > '9') + return k_IsArc_Res_NO; + p += 4; + if (NCompress::NBZip2::IsBlockSig(p)) + return k_IsArc_Res_YES; + if (NCompress::NBZip2::IsEndSig(p)) + return k_IsArc_Res_YES; + return k_IsArc_Res_NO; +} +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) +{ + COM_TRY_BEGIN + Close(); + { + Byte buf[kSignatureCheckSize]; + RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize)) + if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO) + return S_FALSE; + _isArc = true; + _stream = stream; + _seqStream = stream; + _needSeekToStart = true; + } + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + _numBlocks_Defined = false; + + _packSize = 0; + + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + { + RINOK(extractCallback->SetTotal(_packSize)) + } + + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(InStream_SeekToBegin(_stream)) + } + else + _needSeekToStart = true; + + // try { + + CMyComPtr2_Create decoder; + + #ifndef Z7_ST + RINOK(decoder->SetNumberOfThreads(_props._numThreads)) + #endif + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(); + // realOutStream.Release(); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + + decoder->FinishMode = true; + decoder->Base.DecodeAllStreams = true; + + _dataAfterEnd = false; + _needMoreInput = false; + + HRESULT result = decoder.Interface()->Code(_seqStream, outStream, NULL, NULL, lps); + + if (result != S_FALSE && result != S_OK) + return result; + + if (decoder->Base.NumStreams == 0) + { + _isArc = false; + result = S_FALSE; + } + else + { + const UInt64 inProcessedSize = decoder->GetInputProcessedSize(); + UInt64 packSize = inProcessedSize; + + if (decoder->Base.NeedMoreInput) + _needMoreInput = true; + + if (!decoder->Base.IsBz) + { + packSize = decoder->Base.FinishedPackSize; + if (packSize != inProcessedSize) + _dataAfterEnd = true; + } + + _packSize = packSize; + _unpackSize = decoder->GetOutProcessedSize(); + _numStreams = decoder->Base.NumStreams; + _numBlocks = decoder->GetNumBlocks(); + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + _numBlocks_Defined = true; + + // RINOK( + lps.Interface()->SetRatioInfo(&packSize, &_unpackSize); + } + + // outStream.Release(); + + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (decoder->GetCrcError()) + opRes = NExtract::NOperationResult::kCRCError; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (decoder->Base.MinorError) + opRes = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else + return result; + + } + return extractCallback->SetOperationResult(opRes); + + // } catch(...) { return E_FAIL; } + + COM_TRY_END +} + + +/* +static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value); +} + +static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value); +} + +static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, + const UInt64 *unpackSize, + const UInt64 *numBlocks) +{ + NCOM::CPropVariant sizeProp; + if (unpackSize) + { + sizeProp = *unpackSize; + RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp)); + RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK)); + } + + if (unpackSize) + { + RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp)); + } + if (numBlocks) + { + NCOM::CPropVariant prop; + prop = *numBlocks; + RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop)); + } + return S_OK; +} +*/ + +static HRESULT UpdateArchive( + UInt64 unpackSize, + ISequentialOutStream *outStream, + const CProps &props, + IArchiveUpdateCallback *updateCallback + // , ArchiveUpdateCallbackArcProp *reportArcProp + ) +{ + { + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)) + if (!fileInStream) + return S_FALSE; + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamGetSize, + streamGetSize, fileInStream) + if (streamGetSize) + { + UInt64 size; + if (streamGetSize->GetSize(&size) == S_OK) + unpackSize = size; + } + } + RINOK(updateCallback->SetTotal(unpackSize)) + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + { + CMyComPtr2_Create encoder; + RINOK(props.SetCoderProps(encoder.ClsPtr(), NULL)) + RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) + /* + if (reportArcProp) + { + unpackSize = encoderSpec->GetInProcessedSize(); + RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks)); + } + */ + } + } + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); +} + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) +{ + *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // *timeType = NFileTimeType::kUnix; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback)) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamSetRestriction, + setRestriction, outStream) + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + } + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) + + // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback) + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) + if (prop.vt != VT_EMPTY) + if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + + CMethodProps props2 = _props; + #ifndef Z7_ST + props2.AddProp_NumThreads(_props._numThreads); + #endif + + return UpdateArchive(size, outStream, props2, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveUpdateCallbackFile, + opCallback, updateCallback) + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(InStream_SeekToBegin(_stream)) + + return NCompress::CopyStream(_stream, outStream, lps); + + // return ReportArcProps(reportArcProp, NULL, NULL); + + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + return _props.SetProperties(names, values, numProps); +} + +static const Byte k_Signature[] = { 'B', 'Z', 'h' }; + +REGISTER_ARC_IO( + "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, + k_Signature, + 0, + NArcInfoFlags::kKeepName + , 0 + , IsArc_BZip2) + +}} diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index 1e79714ba..5e1fe8baf 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -1,122 +1,122 @@ -// CabBlockInStream.cpp - -#include "StdAfx.h" - -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - -#include "../../Common/StreamUtils.h" - -#include "CabBlockInStream.h" - -namespace NArchive { -namespace NCab { - -static const UInt32 kBlockSize = 1 << 16; -static const unsigned k_OverReadPadZone_Size = 32; -static const unsigned kHeaderSize = 8; -static const unsigned kReservedMax = 256; -static const unsigned kHeaderOffset = kBlockSize + k_OverReadPadZone_Size; - -bool CBlockPackData::Create() throw() -{ - if (!_buf) - _buf = (Byte *)z7_AlignedAlloc(kBlockSize + k_OverReadPadZone_Size + kHeaderSize + kReservedMax); - return _buf != NULL; -} - -CBlockPackData::~CBlockPackData() throw() -{ - z7_AlignedFree(_buf); -} - -static UInt32 CheckSum(const Byte *p, UInt32 size) throw() -{ -#ifdef MY_CPU_64BIT - - UInt64 sum64 = 0; - if (size >= 16) - { - const Byte *lim = p + (size_t)size - 16; - do - { - sum64 ^= GetUi64(p) ^ GetUi64(p + 8); - p += 16; - } - while (p <= lim); - size = (UInt32)(lim + 16 - p); - } - if (size >= 8) - { - sum64 ^= GetUi64(p); - p += 8; - size -= 8; - } - - UInt32 sum = (UInt32)(sum64 >> 32) ^ (UInt32)sum64; - -#else - - UInt32 sum = 0; - if (size >= 16) - { - const Byte *lim = p + (size_t)size - 16; - do - { - sum ^= GetUi32(p) - ^ GetUi32(p + 4) - ^ GetUi32(p + 8) - ^ GetUi32(p + 12); - p += 16; - } - while (p <= lim); - size = (UInt32)(lim + 16 - p); - } - if (size >= 8) - { - sum ^= GetUi32(p + 0) ^ GetUi32(p + 4); - p += 8; - size -= 8; - } - -#endif - - if (size >= 4) - { - sum ^= GetUi32(p); - p += 4; - } - if (size &= 3) - { - if (size >= 2) - { - if (size > 2) - sum ^= (UInt32)(*p++) << 16; - sum ^= (UInt32)(*p++) << 8; - } - sum ^= (UInt32)(*p++); - } - return sum; -} - - -HRESULT CBlockPackData::Read(ISequentialInStream *stream, Byte ReservedSize, UInt32 &packSizeRes, UInt32 &unpackSize) throw() -{ - const UInt32 reserved8 = kHeaderSize + ReservedSize; - const Byte *header = _buf + kHeaderOffset; - RINOK(ReadStream_FALSE(stream, (void *)header, reserved8)) - unpackSize = GetUi16a(header + 6); - const UInt32 packSize = GetUi16a(header + 4); - packSizeRes = packSize; - if (packSize > kBlockSize - _size) - return S_FALSE; - RINOK(ReadStream_FALSE(stream, _buf + _size, packSize)) - memset(_buf + _size + packSize, 0xff, k_OverReadPadZone_Size); - if (*(const UInt32 *)(const void *)header != 0) // checkSum - if (CheckSum(header, reserved8) != CheckSum(_buf + _size, packSize)) - return S_FALSE; - _size += packSize; - return S_OK; -} - -}} +// CabBlockInStream.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" +#include "../../../../C/CpuArch.h" + +#include "../../Common/StreamUtils.h" + +#include "CabBlockInStream.h" + +namespace NArchive { +namespace NCab { + +static const UInt32 kBlockSize = 1 << 16; +static const unsigned k_OverReadPadZone_Size = 32; +static const unsigned kHeaderSize = 8; +static const unsigned kReservedMax = 256; +static const unsigned kHeaderOffset = kBlockSize + k_OverReadPadZone_Size; + +bool CBlockPackData::Create() throw() +{ + if (!_buf) + _buf = (Byte *)z7_AlignedAlloc(kBlockSize + k_OverReadPadZone_Size + kHeaderSize + kReservedMax); + return _buf != NULL; +} + +CBlockPackData::~CBlockPackData() throw() +{ + z7_AlignedFree(_buf); +} + +static UInt32 CheckSum(const Byte *p, UInt32 size) throw() +{ +#ifdef MY_CPU_64BIT + + UInt64 sum64 = 0; + if (size >= 16) + { + const Byte *lim = p + (size_t)size - 16; + do + { + sum64 ^= GetUi64(p) ^ GetUi64(p + 8); + p += 16; + } + while (p <= lim); + size = (UInt32)(lim + 16 - p); + } + if (size >= 8) + { + sum64 ^= GetUi64(p); + p += 8; + size -= 8; + } + + UInt32 sum = (UInt32)(sum64 >> 32) ^ (UInt32)sum64; + +#else + + UInt32 sum = 0; + if (size >= 16) + { + const Byte *lim = p + (size_t)size - 16; + do + { + sum ^= GetUi32(p) + ^ GetUi32(p + 4) + ^ GetUi32(p + 8) + ^ GetUi32(p + 12); + p += 16; + } + while (p <= lim); + size = (UInt32)(lim + 16 - p); + } + if (size >= 8) + { + sum ^= GetUi32(p + 0) ^ GetUi32(p + 4); + p += 8; + size -= 8; + } + +#endif + + if (size >= 4) + { + sum ^= GetUi32(p); + p += 4; + } + if (size &= 3) + { + if (size >= 2) + { + if (size > 2) + sum ^= (UInt32)(*p++) << 16; + sum ^= (UInt32)(*p++) << 8; + } + sum ^= (UInt32)(*p++); + } + return sum; +} + + +HRESULT CBlockPackData::Read(ISequentialInStream *stream, Byte ReservedSize, UInt32 &packSizeRes, UInt32 &unpackSize) throw() +{ + const UInt32 reserved8 = kHeaderSize + ReservedSize; + const Byte *header = _buf + kHeaderOffset; + RINOK(ReadStream_FALSE(stream, (void *)header, reserved8)) + unpackSize = GetUi16a(header + 6); + const UInt32 packSize = GetUi16a(header + 4); + packSizeRes = packSize; + if (packSize > kBlockSize - _size) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, _buf + _size, packSize)) + memset(_buf + _size + packSize, 0xff, k_OverReadPadZone_Size); + if (*(const UInt32 *)(const void *)header != 0) // checkSum + if (CheckSum(header, reserved8) != CheckSum(_buf + _size, packSize)) + return S_FALSE; + _size += packSize; + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h index f0c890b4b..756877922 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.h +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -1,28 +1,28 @@ -// CabBlockInStream.h - -#ifndef ZIP7_INC_CAB_BLOCK_IN_STREAM_H -#define ZIP7_INC_CAB_BLOCK_IN_STREAM_H - -#include "../../IStream.h" - -namespace NArchive { -namespace NCab { - -class CBlockPackData -{ - Byte *_buf; - UInt32 _size; -public: - CBlockPackData(): _buf(NULL), _size(0) {} - ~CBlockPackData() throw(); - bool Create() throw(); - void InitForNewBlock() { _size = 0; } - HRESULT Read(ISequentialInStream *stream, Byte ReservedSize, UInt32 &packSize, UInt32 &unpackSize) throw(); - UInt32 GetPackSize() const { return _size; } - // 32 bytes of overread zone is available after PackSize: - const Byte *GetData() const { return _buf; } -}; - -}} - -#endif +// CabBlockInStream.h + +#ifndef ZIP7_INC_CAB_BLOCK_IN_STREAM_H +#define ZIP7_INC_CAB_BLOCK_IN_STREAM_H + +#include "../../IStream.h" + +namespace NArchive { +namespace NCab { + +class CBlockPackData +{ + Byte *_buf; + UInt32 _size; +public: + CBlockPackData(): _buf(NULL), _size(0) {} + ~CBlockPackData() throw(); + bool Create() throw(); + void InitForNewBlock() { _size = 0; } + HRESULT Read(ISequentialInStream *stream, Byte ReservedSize, UInt32 &packSize, UInt32 &unpackSize) throw(); + UInt32 GetPackSize() const { return _size; } + // 32 bytes of overread zone is available after PackSize: + const Byte *GetData() const { return _buf; } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index d10059333..0ad2a0ed2 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -1,1272 +1,1272 @@ -// CabHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/AutoPtr.h" -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/DeflateDecoder.h" -#include "../../Compress/LzxDecoder.h" -#include "../../Compress/QuantumDecoder.h" - -#include "../Common/ItemNameUtils.h" - -#include "CabBlockInStream.h" -#include "CabHandler.h" - -using namespace NWindows; - -namespace NArchive { -namespace NCab { - -// #define CAB_DETAILS - -#ifdef CAB_DETAILS -enum -{ - kpidBlockReal = kpidUserDefined -}; -#endif - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidMTime, - kpidAttrib, - kpidMethod, - kpidBlock - #ifdef CAB_DETAILS - , - // kpidBlockReal, // L"BlockReal", - kpidOffset, - kpidVolume - #endif -}; - -static const Byte kArcProps[] = -{ - kpidTotalPhySize, - kpidMethod, - // kpidSolid, - kpidNumBlocks, - kpidNumVolumes, - kpidVolumeIndex, - kpidId -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static const char * const kMethods[] = -{ - "None" - , "MSZip" - , "Quantum" - , "LZX" -}; - -static const unsigned kMethodNameBufSize = 32; // "Quantum:255" - -static void SetMethodName(char *s, unsigned method, unsigned param) -{ - if (method < Z7_ARRAY_SIZE(kMethods)) - { - s = MyStpCpy(s, kMethods[method]); - if (method != NHeader::NMethod::kLZX && - method != NHeader::NMethod::kQuantum) - return; - *s++ = ':'; - method = param; - } - ConvertUInt32ToString(method, s); -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMethod: - { - UInt32 mask = 0; - UInt32 params[2] = { 0, 0 }; - { - FOR_VECTOR (v, m_Database.Volumes) - { - const CRecordVector &folders = m_Database.Volumes[v].Folders; - FOR_VECTOR (i, folders) - { - const CFolder &folder = folders[i]; - const unsigned method = folder.GetMethod(); - mask |= ((UInt32)1 << method); - if (method == NHeader::NMethod::kLZX || - method == NHeader::NMethod::kQuantum) - { - const unsigned di = (method == NHeader::NMethod::kQuantum) ? 0 : 1; - if (params[di] < folder.MethodMinor) - params[di] = folder.MethodMinor; - } - } - } - } - - AString s; - - for (unsigned i = 0; i < kNumMethodsMax; i++) - { - if ((mask & (1 << i)) == 0) - continue; - s.Add_Space_if_NotEmpty(); - char temp[kMethodNameBufSize]; - SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]); - s += temp; - } - - prop = s; - break; - } - // case kpidSolid: prop = _database.IsSolid(); break; - case kpidNumBlocks: - { - UInt32 numFolders = 0; - FOR_VECTOR (v, m_Database.Volumes) - numFolders += m_Database.Volumes[v].Folders.Size(); - prop = numFolders; - break; - } - - case kpidTotalPhySize: - { - if (m_Database.Volumes.Size() > 1) - { - UInt64 sum = 0; - FOR_VECTOR (v, m_Database.Volumes) - sum += m_Database.Volumes[v].ArcInfo.Size; - prop = sum; - } - break; - } - - case kpidNumVolumes: - prop = (UInt32)m_Database.Volumes.Size(); - break; - - case kpidVolumeIndex: - { - if (!m_Database.Volumes.IsEmpty()) - { - const CDatabaseEx &db = m_Database.Volumes[0]; - const CInArcInfo &ai = db.ArcInfo; - prop = (UInt32)ai.CabinetNumber; - } - break; - } - - case kpidId: - { - if (m_Database.Volumes.Size() != 0) - { - prop = (UInt32)m_Database.Volumes[0].ArcInfo.SetID; - } - break; - } - - case kpidOffset: - /* - if (m_Database.Volumes.Size() == 1) - prop = m_Database.Volumes[0].StartPosition; - */ - prop = _offset; - break; - - case kpidPhySize: - /* - if (m_Database.Volumes.Size() == 1) - prop = (UInt64)m_Database.Volumes[0].ArcInfo.Size; - */ - prop = (UInt64)_phySize; - break; - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_errorInHeaders) v |= kpv_ErrorFlags_HeadersError; - if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; - prop = v; - break; - } - - case kpidError: - if (!_errorMessage.IsEmpty()) - prop = _errorMessage; - break; - - case kpidName: - { - if (m_Database.Volumes.Size() == 1) - { - const CDatabaseEx &db = m_Database.Volumes[0]; - const CInArcInfo &ai = db.ArcInfo; - if (ai.SetID != 0) - { - AString s; - s.Add_UInt32(ai.SetID); - s.Add_Char('_'); - s.Add_UInt32(ai.CabinetNumber + 1); - s += ".cab"; - prop = s; - } - /* - // that code is incomplete. It gcan give accurate name of volume - char s[32]; - ConvertUInt32ToString(ai.CabinetNumber + 2, s); - unsigned len = MyStringLen(s); - if (ai.IsThereNext()) - { - AString fn = ai.NextArc.FileName; - if (fn.Len() > 4 && StringsAreEqualNoCase_Ascii(fn.RightPtr(4), ".cab")) - fn.DeleteFrom(fn.Len() - 4); - if (len < fn.Len()) - { - if (strcmp(s, fn.RightPtr(len)) == 0) - { - AString s2 = fn; - s2.DeleteFrom(fn.Len() - len); - ConvertUInt32ToString(ai.CabinetNumber + 1, s); - s2 += s; - s2 += ".cab"; - prop = GetUnicodeString(s2); - } - } - } - */ - } - break; - } - - // case kpidShortComment: - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CMvItem &mvItem = m_Database.Items[index]; - const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; - const unsigned itemIndex = mvItem.ItemIndex; - const CItem &item = db.Items[itemIndex]; - switch (propID) - { - case kpidPath: - { - UString unicodeName; - if (item.IsNameUTF()) - ConvertUTF8ToUnicode(item.Name, unicodeName); - else - unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP); - prop = (const wchar_t *)NItemName::WinPathToOsPath(unicodeName); - break; - } - - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.Size; break; - case kpidAttrib: prop = item.GetWinAttrib(); break; - - case kpidMTime: - { - PropVariant_SetFrom_DosTime(prop, item.Time); - break; - } - - case kpidMethod: - { - const int realFolderIndex = item.GetFolderIndex(db.Folders.Size()); - if (realFolderIndex >= 0) - { - const CFolder &folder = db.Folders[(unsigned)realFolderIndex]; - char s[kMethodNameBufSize]; - SetMethodName(s, folder.GetMethod(), folder.MethodMinor); - prop = s; - } - break; - } - - case kpidBlock: prop.Set_Int32((Int32)m_Database.GetFolderIndex(&mvItem)); break; - - #ifdef CAB_DETAILS - - // case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; - case kpidOffset: prop = (UInt32)item.Offset; break; - case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; - - #endif - - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - - CInArchive archive; - CMyComPtr openVolumeCallback; - if (callback) - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - - CMyComPtr nextStream = inStream; - bool prevChecked = false; - UString startVolName; - bool startVolName_was_Requested = false; - UInt64 numItems = 0; - unsigned numTempVolumes = 0; - // try - { - while (nextStream) - { - CDatabaseEx db; - db.Stream = nextStream; - - HRESULT res = archive.Open(db, maxCheckStartPosition); - - _errorInHeaders |= archive.HeaderError; - _errorInHeaders |= archive.ErrorInNames; - _unexpectedEnd |= archive.UnexpectedEnd; - - if (res == S_OK && !m_Database.Volumes.IsEmpty()) - { - const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; - const unsigned cabNumber = db.ArcInfo.CabinetNumber; - if (lastArc.SetID != db.ArcInfo.SetID) - res = S_FALSE; - else if (prevChecked) - { - if (cabNumber != lastArc.CabinetNumber + 1) - res = S_FALSE; - } - else if (cabNumber >= lastArc.CabinetNumber) - res = S_FALSE; - else if (numTempVolumes != 0) - { - const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo; - if (cabNumber != prevArc.CabinetNumber + 1) - res = S_FALSE; - } - } - - if (archive.IsArc || res == S_OK) - { - _isArc = true; - if (m_Database.Volumes.IsEmpty()) - { - _offset = db.StartPosition; - _phySize = db.ArcInfo.Size; - } - } - - if (res == S_OK) - { - numItems += db.Items.Size(); - m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db); - if (!prevChecked && m_Database.Volumes.Size() > 1) - { - numTempVolumes++; - if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber) - numTempVolumes = 0; - } - } - else - { - if (res != S_FALSE) - return res; - if (m_Database.Volumes.IsEmpty()) - return S_FALSE; - if (prevChecked) - break; - prevChecked = true; - if (numTempVolumes != 0) - { - m_Database.Volumes.DeleteFrontal(numTempVolumes); - numTempVolumes = 0; - } - } - - if (callback) - { - RINOK(callback->SetCompleted(&numItems, NULL)) - } - - nextStream = NULL; - - for (;;) - { - const COtherArc *otherArc = NULL; - - if (!prevChecked) - { - if (numTempVolumes == 0) - { - const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; - if (ai.IsTherePrev()) - otherArc = &ai.PrevArc; - else - prevChecked = true; - } - else - { - const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo; - if (ai.IsThereNext()) - otherArc = &ai.NextArc; - else - { - prevChecked = true; - m_Database.Volumes.DeleteFrontal(numTempVolumes); - numTempVolumes = 0; - } - } - } - - if (!otherArc) - { - const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; - if (ai.IsThereNext()) - otherArc = &ai.NextArc; - } - - if (!otherArc) - break; - if (!openVolumeCallback) - break; - // printf("\n%s", otherArc->FileName); - const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP); - - if (!startVolName_was_Requested) - { - // some "bad" cab example can contain the link to itself. - startVolName_was_Requested = true; - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) - if (prop.vt == VT_BSTR) - startVolName = prop.bstrVal; - } - if (fullName == startVolName) - break; - } - - const HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); - if (result == S_OK) - break; - if (result != S_FALSE) - return result; - - if (!_errorMessage.IsEmpty()) - _errorMessage.Add_LF(); - _errorMessage += "Can't open volume: "; - _errorMessage += fullName; - - if (prevChecked) - break; - prevChecked = true; - if (numTempVolumes != 0) - { - m_Database.Volumes.DeleteFrontal(numTempVolumes); - numTempVolumes = 0; - } - } - - } // read nextStream iteration - - if (numTempVolumes != 0) - { - m_Database.Volumes.DeleteFrontal(numTempVolumes); - numTempVolumes = 0; - } - if (m_Database.Volumes.IsEmpty()) - return S_FALSE; - else - { - m_Database.FillSortAndShrink(); - if (!m_Database.Check()) - return S_FALSE; - } - } - COM_TRY_END - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _errorMessage.Empty(); - _isArc = false; - _errorInHeaders = false; - _unexpectedEnd = false; - // _mainVolIndex = -1; - _phySize = 0; - _offset = 0; - - m_Database.Clear(); - return S_OK; -} - - -Z7_CLASS_IMP_NOQIB_1( - CFolderOutStream - , ISequentialOutStream -) - bool m_TestMode; - bool TempBufMode; - bool m_IsOk; - bool m_FileIsOpen; - - const CMvDatabaseEx *m_Database; - const CRecordVector *m_ExtractStatuses; - - Byte *TempBuf; - UInt32 TempBufSize; - UInt32 TempBufWritten; - unsigned NumIdenticalFiles; - - unsigned m_StartIndex; - unsigned m_CurrentIndex; - - UInt32 m_RemainFileSize; - - UInt64 m_FolderSize; - UInt64 m_PosInFolder; - - CMyComPtr m_ExtractCallback; - CMyComPtr m_RealOutStream; - - void FreeTempBuf() - { - ::MyFree(TempBuf); - TempBuf = NULL; - } - - HRESULT OpenFile(); - HRESULT CloseFileWithResOp(Int32 resOp); - HRESULT CloseFile(); -public: - HRESULT WriteEmptyFiles(); - - CFolderOutStream(): TempBuf(NULL) {} - ~CFolderOutStream() { FreeTempBuf(); } - void Init( - const CMvDatabaseEx *database, - const CRecordVector *extractStatuses, - unsigned startIndex, - UInt64 folderSize, - IArchiveExtractCallback *extractCallback, - bool testMode); - HRESULT FlushCorrupted(unsigned folderIndex); - HRESULT Unsupported(); - - bool NeedMoreWrite() const { return (m_FolderSize > m_PosInFolder); } - UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; } - UInt64 GetPosInFolder() const { return m_PosInFolder; } -}; - - -void CFolderOutStream::Init( - const CMvDatabaseEx *database, - const CRecordVector *extractStatuses, - unsigned startIndex, - UInt64 folderSize, - IArchiveExtractCallback *extractCallback, - bool testMode) -{ - m_Database = database; - m_ExtractStatuses = extractStatuses; - m_StartIndex = startIndex; - m_FolderSize = folderSize; - - m_ExtractCallback = extractCallback; - m_TestMode = testMode; - - m_CurrentIndex = 0; - m_PosInFolder = 0; - m_FileIsOpen = false; - m_IsOk = true; - TempBufMode = false; - NumIdenticalFiles = 0; -} - - -HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) -{ - m_RealOutStream.Release(); - m_FileIsOpen = false; - NumIdenticalFiles--; - return m_ExtractCallback->SetOperationResult(resOp); -} - - -HRESULT CFolderOutStream::CloseFile() -{ - return CloseFileWithResOp(m_IsOk ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError); -} - - -HRESULT CFolderOutStream::OpenFile() -{ - if (NumIdenticalFiles == 0) - { - const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; - const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - unsigned numExtractItems = 0; - unsigned curIndex; - - for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++) - { - const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; - const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; - if (item.Offset != item2.Offset || - item.Size != item2.Size || - item.Size == 0) - break; - if (!m_TestMode && (*m_ExtractStatuses)[curIndex]) - numExtractItems++; - } - - NumIdenticalFiles = (curIndex - m_CurrentIndex); - if (NumIdenticalFiles == 0) - NumIdenticalFiles = 1; - TempBufMode = false; - - if (numExtractItems > 1) - { - if (!TempBuf || item.Size > TempBufSize) - { - FreeTempBuf(); - TempBuf = (Byte *)MyAlloc(item.Size); - TempBufSize = item.Size; - if (!TempBuf) - return E_OUTOFMEMORY; - } - TempBufMode = true; - TempBufWritten = 0; - } - else if (numExtractItems == 1) - { - while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex]) - { - CMyComPtr stream; - RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip)) - if (stream) - return E_FAIL; - RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip)) - m_CurrentIndex++; - m_FileIsOpen = true; - CloseFile(); - } - } - } - - Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? m_TestMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract : - NExtract::NAskMode::kSkip; - RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)) - if (!m_RealOutStream && !m_TestMode) - askMode = NExtract::NAskMode::kSkip; - return m_ExtractCallback->PrepareOperation(askMode); -} - - -HRESULT CFolderOutStream::WriteEmptyFiles() -{ - if (m_FileIsOpen) - return S_OK; - for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++) - { - const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; - const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - const UInt64 fileSize = item.Size; - if (fileSize != 0) - return S_OK; - const HRESULT result = OpenFile(); - m_RealOutStream.Release(); - RINOK(result) - RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - return S_OK; -} - - -Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - // (data == NULL) means Error_Data for solid folder flushing - COM_TRY_BEGIN - - UInt32 realProcessed = 0; - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - if (m_FileIsOpen) - { - UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size); - HRESULT res = S_OK; - if (numBytesToWrite != 0) - { - if (!data) - m_IsOk = false; - - if (m_RealOutStream) - { - UInt32 processedSizeLocal = 0; - // 18.01 : we don't want ZEROs instead of missing data - if (data) - res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); - else - processedSizeLocal = numBytesToWrite; - numBytesToWrite = processedSizeLocal; - } - - if (TempBufMode && TempBuf) - { - if (data) - { - memcpy(TempBuf + TempBufWritten, data, numBytesToWrite); - TempBufWritten += numBytesToWrite; - } - } - } - realProcessed += numBytesToWrite; - if (processedSize) - *processedSize = realProcessed; - if (data) - data = (const void *)((const Byte *)data + numBytesToWrite); - size -= numBytesToWrite; - m_RemainFileSize -= numBytesToWrite; - m_PosInFolder += numBytesToWrite; - - if (res != S_OK) - return res; - - if (m_RemainFileSize == 0) - { - RINOK(CloseFile()) - - while (NumIdenticalFiles) - { - HRESULT result = OpenFile(); - m_FileIsOpen = true; - m_CurrentIndex++; - if (result == S_OK && m_RealOutStream && TempBuf) - result = WriteStream(m_RealOutStream, TempBuf, TempBufWritten); - - if (!TempBuf && TempBufMode && m_RealOutStream) - { - RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnsupportedMethod)) - } - else - { - RINOK(CloseFile()) - } - - RINOK(result) - } - - TempBufMode = false; - } - - if (realProcessed > 0) - break; // with this break this function works as Write-Part - } - else - { - if (m_CurrentIndex >= m_ExtractStatuses->Size()) - { - // we ignore extra data; - realProcessed += size; - if (processedSize) - *processedSize = realProcessed; - m_PosInFolder += size; - return S_OK; - // return E_FAIL; - } - - const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; - const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - - m_RemainFileSize = item.Size; - - const UInt32 fileOffset = item.Offset; - - if (fileOffset < m_PosInFolder) - return E_FAIL; - - if (fileOffset > m_PosInFolder) - { - const UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size); - realProcessed += numBytesToWrite; - if (processedSize) - *processedSize = realProcessed; - if (data) - data = (const void *)((const Byte *)data + numBytesToWrite); - size -= numBytesToWrite; - m_PosInFolder += numBytesToWrite; - } - - if (fileOffset == m_PosInFolder) - { - RINOK(OpenFile()) - m_FileIsOpen = true; - m_CurrentIndex++; - m_IsOk = true; - } - } - } - - return WriteEmptyFiles(); - - COM_TRY_END -} - - -HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex) -{ - if (!NeedMoreWrite()) - { - CMyComPtr callbackMessage; - m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage); - if (callbackMessage) - { - RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, NExtract::NOperationResult::kDataError)) - } - return S_OK; - } - - for (;;) - { - if (!NeedMoreWrite()) - return S_OK; - const UInt64 remain = GetRemain(); - UInt32 size = (UInt32)1 << 20; - if (size > remain) - size = (UInt32)remain; - UInt32 processedSizeLocal = 0; - RINOK(Write(NULL, size, &processedSizeLocal)) - } -} - - -HRESULT CFolderOutStream::Unsupported() -{ - while (m_CurrentIndex < m_ExtractStatuses->Size()) - { - const HRESULT result = OpenFile(); - if (result != S_FALSE && result != S_OK) - return result; - m_RealOutStream.Release(); - RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - m_CurrentIndex++; - } - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = m_Database.Items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalUnPacked = 0; - - UInt32 i; - int lastFolder = -2; - UInt64 lastFolderSize = 0; - - for (i = 0; i < numItems; i++) - { - const unsigned index = allFilesMode ? i : indices[i]; - const CMvItem &mvItem = m_Database.Items[index]; - const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - if (item.IsDir()) - continue; - const int folderIndex = m_Database.GetFolderIndex(&mvItem); - if (folderIndex != lastFolder) - totalUnPacked += lastFolderSize; - lastFolder = folderIndex; - lastFolderSize = item.GetEndOffset(); - } - - totalUnPacked += lastFolderSize; - RINOK(extractCallback->SetTotal(totalUnPacked)) - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - CMyComPtr2 deflateDecoder; - CMyUniquePtr lzxDecoder; - CMyUniquePtr quantumDecoder; - - CBlockPackData blockPackData; - if (!blockPackData.Create()) - return E_OUTOFMEMORY; - - CMyComPtr2_Create inBufStream; - - CRecordVector extractStatuses; - - totalUnPacked = 0; - UInt64 totalPacked = 0; - - for (i = 0;;) - { - lps->OutSize = totalUnPacked; - lps->InSize = totalPacked; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - const unsigned index = allFilesMode ? i : indices[i]; - - const CMvItem &mvItem = m_Database.Items[index]; - const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; - const unsigned itemIndex = mvItem.ItemIndex; - const CItem &item = db.Items[itemIndex]; - - i++; - if (item.IsDir()) - { - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const int folderIndex = m_Database.GetFolderIndex(&mvItem); - - if (folderIndex < 0) - { - // If we need previous archive - const Int32 askMode= testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)) - continue; - } - - const unsigned startIndex2 = m_Database.FolderStartFileIndex[(unsigned)folderIndex]; - unsigned startIndex = startIndex2; - extractStatuses.Clear(); - for (; startIndex < index; startIndex++) - extractStatuses.Add(false); - extractStatuses.Add(true); - startIndex++; - UInt64 curUnpack = item.GetEndOffset(); - - for (; i < numItems; i++) - { - const unsigned indexNext = allFilesMode ? i : indices[i]; - const CMvItem &mvItem2 = m_Database.Items[indexNext]; - const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; - if (item2.IsDir()) - continue; - const int newFolderIndex = m_Database.GetFolderIndex(&mvItem2); - - if (newFolderIndex != folderIndex) - break; - for (; startIndex < indexNext; startIndex++) - extractStatuses.Add(false); - extractStatuses.Add(true); - startIndex++; - curUnpack = item2.GetEndOffset(); - } - - CMyComPtr2_Create cabFolderOutStream; - - const int folderIndex2 = item.GetFolderIndex(db.Folders.Size()); - if (folderIndex2 < 0) - return E_FAIL; - const CFolder &folder = db.Folders[(unsigned)folderIndex2]; - - cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, - curUnpack, extractCallback, testMode != 0); - - HRESULT res = S_OK; - - switch (folder.GetMethod()) - { - case NHeader::NMethod::kNone: - break; - - case NHeader::NMethod::kMSZip: - deflateDecoder.Create_if_Empty(); - break; - - case NHeader::NMethod::kLZX: - lzxDecoder.Create_if_Empty(); - res = lzxDecoder->Set_DictBits_and_Alloc(folder.MethodMinor); - break; - - case NHeader::NMethod::kQuantum: - quantumDecoder.Create_if_Empty(); - res = quantumDecoder->SetParams(folder.MethodMinor); - break; - - default: - res = E_INVALIDARG; - break; - } - - if (res == E_INVALIDARG) - { - RINOK(cabFolderOutStream->Unsupported()) - totalUnPacked += curUnpack; - continue; - } - RINOK(res) - - { - unsigned volIndex = mvItem.VolumeIndex; - int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); - bool keepHistory = false; - bool keepInputBuffer = false; - bool thereWasNotAlignedChunk = false; - - for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();) - { - if (volIndex >= m_Database.Volumes.Size()) - { - res = S_FALSE; - break; - } - - const CDatabaseEx &db2 = m_Database.Volumes[volIndex]; - if (locFolderIndex < 0) - return E_FAIL; - const CFolder &folder2 = db2.Folders[(unsigned)locFolderIndex]; - - if (bl == 0) - { - RINOK(InStream_SeekSet(db2.Stream, db2.StartPosition + folder2.DataStart)) - } - - if (bl == folder2.NumDataBlocks) - { - /* - CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit. - But there are some big CAB archives from MS that contain more - than (0xFFFF) CFDATA blocks in folder. - Old cab extracting software can show error (or ask next volume) - but cab extracting library in new Windows ignores this error. - 15.00 : We also try to ignore such error, if archive is not multi-volume. - */ - if (m_Database.Volumes.Size() > 1) - { - volIndex++; - locFolderIndex = 0; - bl = 0; - continue; - } - } - - bl++; - - if (!keepInputBuffer) - blockPackData.InitForNewBlock(); - - UInt32 packSize, unpackSize; - res = blockPackData.Read(db2.Stream, db2.ArcInfo.GetDataBlockReserveSize(), packSize, unpackSize); - if (res == S_FALSE) - break; - RINOK(res) - keepInputBuffer = (unpackSize == 0); - if (keepInputBuffer) - continue; - - const UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder(); - totalPacked += packSize; - - if (totalUnPacked2 - lps->OutSize >= (1 << 26) - || totalPacked - lps->InSize >= (1 << 24)) - { - lps->OutSize = totalUnPacked2; - lps->InSize = totalPacked; - RINOK(lps->SetCur()) - } - - const unsigned kBlockSizeMax = 1u << 15; - - if (unpackSize != kBlockSizeMax) - { - if (unpackSize > kBlockSizeMax || thereWasNotAlignedChunk) - { - res = S_FALSE; - break; - } - thereWasNotAlignedChunk = true; - } - - /* We don't try to reduce last block. - Note that LZX converts data with x86 filter. - and filter needs larger input data than reduced size. - It's simpler to decompress full chunk here. - also we need full block for quantum for more integrity checks */ - - const UInt64 unpackSize64 = unpackSize; - const UInt32 packSizeChunk = blockPackData.GetPackSize(); - - switch (folder2.GetMethod()) - { - case NHeader::NMethod::kNone: - if (unpackSize != packSizeChunk) - { - res = S_FALSE; - break; - } - res = WriteStream(cabFolderOutStream, blockPackData.GetData(), packSizeChunk); - break; - - case NHeader::NMethod::kMSZip: - { - /* v24.00 : fixed : we check 2-bytes MSZIP signature only - when block was constructed from all volumes. */ - const Byte *packData = blockPackData.GetData(); - if (unpackSize > (1u << 15) + 12 /* MSZIP specification */ - || packSizeChunk < 2 || GetUi16(packData) != 0x4b43) - { - res = S_FALSE; - break; - } - const UInt32 packSizeChunk_2 = packSizeChunk - 2; - inBufStream->Init(packData + 2, packSizeChunk_2); - - deflateDecoder->Set_KeepHistory(keepHistory); - /* v9.31: now we follow MSZIP specification that requires - to finish deflate stream at the end of each block. - But PyCabArc can create CAB archives that don't have - finish marker at the end of block. - Cabarc probably ignores such errors in cab archives. - Maybe we also should ignore such error? - Or we should extract full file and show the warning? */ - deflateDecoder->Set_NeedFinishInput(true); - res = deflateDecoder.Interface()->Code(inBufStream, cabFolderOutStream, NULL, &unpackSize64, NULL); - if (res == S_OK) - { - if (!deflateDecoder->IsFinished()) - res = S_FALSE; - if (!deflateDecoder->IsFinalBlock()) - res = S_FALSE; - if (deflateDecoder->GetInputProcessedSize() != packSizeChunk_2) - res = S_FALSE; - } - break; - } - - case NHeader::NMethod::kLZX: - lzxDecoder->Set_KeepHistory(keepHistory); - lzxDecoder->Set_KeepHistoryForNext(true); - res = lzxDecoder->Code_WithExceedReadWrite(blockPackData.GetData(), - packSizeChunk, unpackSize); - if (res == S_OK) - res = WriteStream(cabFolderOutStream, - lzxDecoder->GetUnpackData(), - lzxDecoder->GetUnpackSize()); - break; - - case NHeader::NMethod::kQuantum: - { - res = quantumDecoder->Code(blockPackData.GetData(), - packSizeChunk, unpackSize, keepHistory); - if (res == S_OK) - { - const UInt32 num = unpackSize; - res = WriteStream(cabFolderOutStream, - quantumDecoder->GetDataPtr() - num, num); - } - break; - } - default: - // it's unexpected case, because we checked method before - // res = E_NOTIMPL; - break; - } - - if (res != S_OK) - { - if (res != S_FALSE) - return res; - break; - } - - keepHistory = true; - } - - if (res == S_OK) - { - RINOK(cabFolderOutStream->WriteEmptyFiles()) - } - } - - if (res != S_OK || cabFolderOutStream->NeedMoreWrite()) - { - RINOK(cabFolderOutStream->FlushCorrupted((unsigned)folderIndex2)) - } - - totalUnPacked += curUnpack; - } - - return S_OK; - - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = m_Database.Items.Size(); - return S_OK; -} - -}} +// CabHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../../C/Alloc.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/AutoPtr.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/DeflateDecoder.h" +#include "../../Compress/LzxDecoder.h" +#include "../../Compress/QuantumDecoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "CabBlockInStream.h" +#include "CabHandler.h" + +using namespace NWindows; + +namespace NArchive { +namespace NCab { + +// #define CAB_DETAILS + +#ifdef CAB_DETAILS +enum +{ + kpidBlockReal = kpidUserDefined +}; +#endif + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidMTime, + kpidAttrib, + kpidMethod, + kpidBlock + #ifdef CAB_DETAILS + , + // kpidBlockReal, // L"BlockReal", + kpidOffset, + kpidVolume + #endif +}; + +static const Byte kArcProps[] = +{ + kpidTotalPhySize, + kpidMethod, + // kpidSolid, + kpidNumBlocks, + kpidNumVolumes, + kpidVolumeIndex, + kpidId +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static const char * const kMethods[] = +{ + "None" + , "MSZip" + , "Quantum" + , "LZX" +}; + +static const unsigned kMethodNameBufSize = 32; // "Quantum:255" + +static void SetMethodName(char *s, unsigned method, unsigned param) +{ + if (method < Z7_ARRAY_SIZE(kMethods)) + { + s = MyStpCpy(s, kMethods[method]); + if (method != NHeader::NMethod::kLZX && + method != NHeader::NMethod::kQuantum) + return; + *s++ = ':'; + method = param; + } + ConvertUInt32ToString(method, s); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMethod: + { + UInt32 mask = 0; + UInt32 params[2] = { 0, 0 }; + { + FOR_VECTOR (v, m_Database.Volumes) + { + const CRecordVector &folders = m_Database.Volumes[v].Folders; + FOR_VECTOR (i, folders) + { + const CFolder &folder = folders[i]; + const unsigned method = folder.GetMethod(); + mask |= ((UInt32)1 << method); + if (method == NHeader::NMethod::kLZX || + method == NHeader::NMethod::kQuantum) + { + const unsigned di = (method == NHeader::NMethod::kQuantum) ? 0 : 1; + if (params[di] < folder.MethodMinor) + params[di] = folder.MethodMinor; + } + } + } + } + + AString s; + + for (unsigned i = 0; i < kNumMethodsMax; i++) + { + if ((mask & (1 << i)) == 0) + continue; + s.Add_Space_if_NotEmpty(); + char temp[kMethodNameBufSize]; + SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]); + s += temp; + } + + prop = s; + break; + } + // case kpidSolid: prop = _database.IsSolid(); break; + case kpidNumBlocks: + { + UInt32 numFolders = 0; + FOR_VECTOR (v, m_Database.Volumes) + numFolders += m_Database.Volumes[v].Folders.Size(); + prop = numFolders; + break; + } + + case kpidTotalPhySize: + { + if (m_Database.Volumes.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, m_Database.Volumes) + sum += m_Database.Volumes[v].ArcInfo.Size; + prop = sum; + } + break; + } + + case kpidNumVolumes: + prop = (UInt32)m_Database.Volumes.Size(); + break; + + case kpidVolumeIndex: + { + if (!m_Database.Volumes.IsEmpty()) + { + const CDatabaseEx &db = m_Database.Volumes[0]; + const CInArcInfo &ai = db.ArcInfo; + prop = (UInt32)ai.CabinetNumber; + } + break; + } + + case kpidId: + { + if (m_Database.Volumes.Size() != 0) + { + prop = (UInt32)m_Database.Volumes[0].ArcInfo.SetID; + } + break; + } + + case kpidOffset: + /* + if (m_Database.Volumes.Size() == 1) + prop = m_Database.Volumes[0].StartPosition; + */ + prop = _offset; + break; + + case kpidPhySize: + /* + if (m_Database.Volumes.Size() == 1) + prop = (UInt64)m_Database.Volumes[0].ArcInfo.Size; + */ + prop = (UInt64)_phySize; + break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_errorInHeaders) v |= kpv_ErrorFlags_HeadersError; + if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + prop = v; + break; + } + + case kpidError: + if (!_errorMessage.IsEmpty()) + prop = _errorMessage; + break; + + case kpidName: + { + if (m_Database.Volumes.Size() == 1) + { + const CDatabaseEx &db = m_Database.Volumes[0]; + const CInArcInfo &ai = db.ArcInfo; + if (ai.SetID != 0) + { + AString s; + s.Add_UInt32(ai.SetID); + s.Add_Char('_'); + s.Add_UInt32(ai.CabinetNumber + 1); + s += ".cab"; + prop = s; + } + /* + // that code is incomplete. It gcan give accurate name of volume + char s[32]; + ConvertUInt32ToString(ai.CabinetNumber + 2, s); + unsigned len = MyStringLen(s); + if (ai.IsThereNext()) + { + AString fn = ai.NextArc.FileName; + if (fn.Len() > 4 && StringsAreEqualNoCase_Ascii(fn.RightPtr(4), ".cab")) + fn.DeleteFrom(fn.Len() - 4); + if (len < fn.Len()) + { + if (strcmp(s, fn.RightPtr(len)) == 0) + { + AString s2 = fn; + s2.DeleteFrom(fn.Len() - len); + ConvertUInt32ToString(ai.CabinetNumber + 1, s); + s2 += s; + s2 += ".cab"; + prop = GetUnicodeString(s2); + } + } + } + */ + } + break; + } + + // case kpidShortComment: + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CMvItem &mvItem = m_Database.Items[index]; + const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; + const unsigned itemIndex = mvItem.ItemIndex; + const CItem &item = db.Items[itemIndex]; + switch (propID) + { + case kpidPath: + { + UString unicodeName; + if (item.IsNameUTF()) + ConvertUTF8ToUnicode(item.Name, unicodeName); + else + unicodeName = MultiByteToUnicodeString(item.Name, CP_ACP); + prop = (const wchar_t *)NItemName::WinPathToOsPath(unicodeName); + break; + } + + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidAttrib: prop = item.GetWinAttrib(); break; + + case kpidMTime: + { + PropVariant_SetFrom_DosTime(prop, item.Time); + break; + } + + case kpidMethod: + { + const int realFolderIndex = item.GetFolderIndex(db.Folders.Size()); + if (realFolderIndex >= 0) + { + const CFolder &folder = db.Folders[(unsigned)realFolderIndex]; + char s[kMethodNameBufSize]; + SetMethodName(s, folder.GetMethod(), folder.MethodMinor); + prop = s; + } + break; + } + + case kpidBlock: prop.Set_Int32((Int32)m_Database.GetFolderIndex(&mvItem)); break; + + #ifdef CAB_DETAILS + + // case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; + case kpidOffset: prop = (UInt32)item.Offset; break; + case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; + + #endif + + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + + CInArchive archive; + CMyComPtr openVolumeCallback; + if (callback) + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + CMyComPtr nextStream = inStream; + bool prevChecked = false; + UString startVolName; + bool startVolName_was_Requested = false; + UInt64 numItems = 0; + unsigned numTempVolumes = 0; + // try + { + while (nextStream) + { + CDatabaseEx db; + db.Stream = nextStream; + + HRESULT res = archive.Open(db, maxCheckStartPosition); + + _errorInHeaders |= archive.HeaderError; + _errorInHeaders |= archive.ErrorInNames; + _unexpectedEnd |= archive.UnexpectedEnd; + + if (res == S_OK && !m_Database.Volumes.IsEmpty()) + { + const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; + const unsigned cabNumber = db.ArcInfo.CabinetNumber; + if (lastArc.SetID != db.ArcInfo.SetID) + res = S_FALSE; + else if (prevChecked) + { + if (cabNumber != lastArc.CabinetNumber + 1) + res = S_FALSE; + } + else if (cabNumber >= lastArc.CabinetNumber) + res = S_FALSE; + else if (numTempVolumes != 0) + { + const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo; + if (cabNumber != prevArc.CabinetNumber + 1) + res = S_FALSE; + } + } + + if (archive.IsArc || res == S_OK) + { + _isArc = true; + if (m_Database.Volumes.IsEmpty()) + { + _offset = db.StartPosition; + _phySize = db.ArcInfo.Size; + } + } + + if (res == S_OK) + { + numItems += db.Items.Size(); + m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db); + if (!prevChecked && m_Database.Volumes.Size() > 1) + { + numTempVolumes++; + if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber) + numTempVolumes = 0; + } + } + else + { + if (res != S_FALSE) + return res; + if (m_Database.Volumes.IsEmpty()) + return S_FALSE; + if (prevChecked) + break; + prevChecked = true; + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } + } + + if (callback) + { + RINOK(callback->SetCompleted(&numItems, NULL)) + } + + nextStream = NULL; + + for (;;) + { + const COtherArc *otherArc = NULL; + + if (!prevChecked) + { + if (numTempVolumes == 0) + { + const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; + if (ai.IsTherePrev()) + otherArc = &ai.PrevArc; + else + prevChecked = true; + } + else + { + const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo; + if (ai.IsThereNext()) + otherArc = &ai.NextArc; + else + { + prevChecked = true; + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } + } + } + + if (!otherArc) + { + const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; + if (ai.IsThereNext()) + otherArc = &ai.NextArc; + } + + if (!otherArc) + break; + if (!openVolumeCallback) + break; + // printf("\n%s", otherArc->FileName); + const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP); + + if (!startVolName_was_Requested) + { + // some "bad" cab example can contain the link to itself. + startVolName_was_Requested = true; + { + NCOM::CPropVariant prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) + if (prop.vt == VT_BSTR) + startVolName = prop.bstrVal; + } + if (fullName == startVolName) + break; + } + + const HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); + if (result == S_OK) + break; + if (result != S_FALSE) + return result; + + if (!_errorMessage.IsEmpty()) + _errorMessage.Add_LF(); + _errorMessage += "Can't open volume: "; + _errorMessage += fullName; + + if (prevChecked) + break; + prevChecked = true; + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } + } + + } // read nextStream iteration + + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } + if (m_Database.Volumes.IsEmpty()) + return S_FALSE; + else + { + m_Database.FillSortAndShrink(); + if (!m_Database.Check()) + return S_FALSE; + } + } + COM_TRY_END + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _errorMessage.Empty(); + _isArc = false; + _errorInHeaders = false; + _unexpectedEnd = false; + // _mainVolIndex = -1; + _phySize = 0; + _offset = 0; + + m_Database.Clear(); + return S_OK; +} + + +Z7_CLASS_IMP_NOQIB_1( + CFolderOutStream + , ISequentialOutStream +) + bool m_TestMode; + bool TempBufMode; + bool m_IsOk; + bool m_FileIsOpen; + + const CMvDatabaseEx *m_Database; + const CRecordVector *m_ExtractStatuses; + + Byte *TempBuf; + UInt32 TempBufSize; + UInt32 TempBufWritten; + unsigned NumIdenticalFiles; + + unsigned m_StartIndex; + unsigned m_CurrentIndex; + + UInt32 m_RemainFileSize; + + UInt64 m_FolderSize; + UInt64 m_PosInFolder; + + CMyComPtr m_ExtractCallback; + CMyComPtr m_RealOutStream; + + void FreeTempBuf() + { + ::MyFree(TempBuf); + TempBuf = NULL; + } + + HRESULT OpenFile(); + HRESULT CloseFileWithResOp(Int32 resOp); + HRESULT CloseFile(); +public: + HRESULT WriteEmptyFiles(); + + CFolderOutStream(): TempBuf(NULL) {} + ~CFolderOutStream() { FreeTempBuf(); } + void Init( + const CMvDatabaseEx *database, + const CRecordVector *extractStatuses, + unsigned startIndex, + UInt64 folderSize, + IArchiveExtractCallback *extractCallback, + bool testMode); + HRESULT FlushCorrupted(unsigned folderIndex); + HRESULT Unsupported(); + + bool NeedMoreWrite() const { return (m_FolderSize > m_PosInFolder); } + UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; } + UInt64 GetPosInFolder() const { return m_PosInFolder; } +}; + + +void CFolderOutStream::Init( + const CMvDatabaseEx *database, + const CRecordVector *extractStatuses, + unsigned startIndex, + UInt64 folderSize, + IArchiveExtractCallback *extractCallback, + bool testMode) +{ + m_Database = database; + m_ExtractStatuses = extractStatuses; + m_StartIndex = startIndex; + m_FolderSize = folderSize; + + m_ExtractCallback = extractCallback; + m_TestMode = testMode; + + m_CurrentIndex = 0; + m_PosInFolder = 0; + m_FileIsOpen = false; + m_IsOk = true; + TempBufMode = false; + NumIdenticalFiles = 0; +} + + +HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) +{ + m_RealOutStream.Release(); + m_FileIsOpen = false; + NumIdenticalFiles--; + return m_ExtractCallback->SetOperationResult(resOp); +} + + +HRESULT CFolderOutStream::CloseFile() +{ + return CloseFileWithResOp(m_IsOk ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError); +} + + +HRESULT CFolderOutStream::OpenFile() +{ + if (NumIdenticalFiles == 0) + { + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + unsigned numExtractItems = 0; + unsigned curIndex; + + for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++) + { + const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; + const CItem &item2 = m_Database->Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; + if (item.Offset != item2.Offset || + item.Size != item2.Size || + item.Size == 0) + break; + if (!m_TestMode && (*m_ExtractStatuses)[curIndex]) + numExtractItems++; + } + + NumIdenticalFiles = (curIndex - m_CurrentIndex); + if (NumIdenticalFiles == 0) + NumIdenticalFiles = 1; + TempBufMode = false; + + if (numExtractItems > 1) + { + if (!TempBuf || item.Size > TempBufSize) + { + FreeTempBuf(); + TempBuf = (Byte *)MyAlloc(item.Size); + TempBufSize = item.Size; + if (!TempBuf) + return E_OUTOFMEMORY; + } + TempBufMode = true; + TempBufWritten = 0; + } + else if (numExtractItems == 1) + { + while (NumIdenticalFiles && !(*m_ExtractStatuses)[m_CurrentIndex]) + { + CMyComPtr stream; + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &stream, NExtract::NAskMode::kSkip)) + if (stream) + return E_FAIL; + RINOK(m_ExtractCallback->PrepareOperation(NExtract::NAskMode::kSkip)) + m_CurrentIndex++; + m_FileIsOpen = true; + CloseFile(); + } + } + } + + Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? m_TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract : + NExtract::NAskMode::kSkip; + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)) + if (!m_RealOutStream && !m_TestMode) + askMode = NExtract::NAskMode::kSkip; + return m_ExtractCallback->PrepareOperation(askMode); +} + + +HRESULT CFolderOutStream::WriteEmptyFiles() +{ + if (m_FileIsOpen) + return S_OK; + for (; m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++) + { + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + const UInt64 fileSize = item.Size; + if (fileSize != 0) + return S_OK; + const HRESULT result = OpenFile(); + m_RealOutStream.Release(); + RINOK(result) + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + return S_OK; +} + + +Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + // (data == NULL) means Error_Data for solid folder flushing + COM_TRY_BEGIN + + UInt32 realProcessed = 0; + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (m_FileIsOpen) + { + UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size); + HRESULT res = S_OK; + if (numBytesToWrite != 0) + { + if (!data) + m_IsOk = false; + + if (m_RealOutStream) + { + UInt32 processedSizeLocal = 0; + // 18.01 : we don't want ZEROs instead of missing data + if (data) + res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); + else + processedSizeLocal = numBytesToWrite; + numBytesToWrite = processedSizeLocal; + } + + if (TempBufMode && TempBuf) + { + if (data) + { + memcpy(TempBuf + TempBufWritten, data, numBytesToWrite); + TempBufWritten += numBytesToWrite; + } + } + } + realProcessed += numBytesToWrite; + if (processedSize) + *processedSize = realProcessed; + if (data) + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_RemainFileSize -= numBytesToWrite; + m_PosInFolder += numBytesToWrite; + + if (res != S_OK) + return res; + + if (m_RemainFileSize == 0) + { + RINOK(CloseFile()) + + while (NumIdenticalFiles) + { + HRESULT result = OpenFile(); + m_FileIsOpen = true; + m_CurrentIndex++; + if (result == S_OK && m_RealOutStream && TempBuf) + result = WriteStream(m_RealOutStream, TempBuf, TempBufWritten); + + if (!TempBuf && TempBufMode && m_RealOutStream) + { + RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnsupportedMethod)) + } + else + { + RINOK(CloseFile()) + } + + RINOK(result) + } + + TempBufMode = false; + } + + if (realProcessed > 0) + break; // with this break this function works as Write-Part + } + else + { + if (m_CurrentIndex >= m_ExtractStatuses->Size()) + { + // we ignore extra data; + realProcessed += size; + if (processedSize) + *processedSize = realProcessed; + m_PosInFolder += size; + return S_OK; + // return E_FAIL; + } + + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + + m_RemainFileSize = item.Size; + + const UInt32 fileOffset = item.Offset; + + if (fileOffset < m_PosInFolder) + return E_FAIL; + + if (fileOffset > m_PosInFolder) + { + const UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size); + realProcessed += numBytesToWrite; + if (processedSize) + *processedSize = realProcessed; + if (data) + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_PosInFolder += numBytesToWrite; + } + + if (fileOffset == m_PosInFolder) + { + RINOK(OpenFile()) + m_FileIsOpen = true; + m_CurrentIndex++; + m_IsOk = true; + } + } + } + + return WriteEmptyFiles(); + + COM_TRY_END +} + + +HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex) +{ + if (!NeedMoreWrite()) + { + CMyComPtr callbackMessage; + m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage); + if (callbackMessage) + { + RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, NExtract::NOperationResult::kDataError)) + } + return S_OK; + } + + for (;;) + { + if (!NeedMoreWrite()) + return S_OK; + const UInt64 remain = GetRemain(); + UInt32 size = (UInt32)1 << 20; + if (size > remain) + size = (UInt32)remain; + UInt32 processedSizeLocal = 0; + RINOK(Write(NULL, size, &processedSizeLocal)) + } +} + + +HRESULT CFolderOutStream::Unsupported() +{ + while (m_CurrentIndex < m_ExtractStatuses->Size()) + { + const HRESULT result = OpenFile(); + if (result != S_FALSE && result != S_OK) + return result; + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + m_CurrentIndex++; + } + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = m_Database.Items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalUnPacked = 0; + + UInt32 i; + int lastFolder = -2; + UInt64 lastFolderSize = 0; + + for (i = 0; i < numItems; i++) + { + const unsigned index = allFilesMode ? i : indices[i]; + const CMvItem &mvItem = m_Database.Items[index]; + const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDir()) + continue; + const int folderIndex = m_Database.GetFolderIndex(&mvItem); + if (folderIndex != lastFolder) + totalUnPacked += lastFolderSize; + lastFolder = folderIndex; + lastFolderSize = item.GetEndOffset(); + } + + totalUnPacked += lastFolderSize; + RINOK(extractCallback->SetTotal(totalUnPacked)) + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + CMyComPtr2 deflateDecoder; + CMyUniquePtr lzxDecoder; + CMyUniquePtr quantumDecoder; + + CBlockPackData blockPackData; + if (!blockPackData.Create()) + return E_OUTOFMEMORY; + + CMyComPtr2_Create inBufStream; + + CRecordVector extractStatuses; + + totalUnPacked = 0; + UInt64 totalPacked = 0; + + for (i = 0;;) + { + lps->OutSize = totalUnPacked; + lps->InSize = totalPacked; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + const unsigned index = allFilesMode ? i : indices[i]; + + const CMvItem &mvItem = m_Database.Items[index]; + const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; + const unsigned itemIndex = mvItem.ItemIndex; + const CItem &item = db.Items[itemIndex]; + + i++; + if (item.IsDir()) + { + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const int folderIndex = m_Database.GetFolderIndex(&mvItem); + + if (folderIndex < 0) + { + // If we need previous archive + const Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)) + continue; + } + + const unsigned startIndex2 = m_Database.FolderStartFileIndex[(unsigned)folderIndex]; + unsigned startIndex = startIndex2; + extractStatuses.Clear(); + for (; startIndex < index; startIndex++) + extractStatuses.Add(false); + extractStatuses.Add(true); + startIndex++; + UInt64 curUnpack = item.GetEndOffset(); + + for (; i < numItems; i++) + { + const unsigned indexNext = allFilesMode ? i : indices[i]; + const CMvItem &mvItem2 = m_Database.Items[indexNext]; + const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; + if (item2.IsDir()) + continue; + const int newFolderIndex = m_Database.GetFolderIndex(&mvItem2); + + if (newFolderIndex != folderIndex) + break; + for (; startIndex < indexNext; startIndex++) + extractStatuses.Add(false); + extractStatuses.Add(true); + startIndex++; + curUnpack = item2.GetEndOffset(); + } + + CMyComPtr2_Create cabFolderOutStream; + + const int folderIndex2 = item.GetFolderIndex(db.Folders.Size()); + if (folderIndex2 < 0) + return E_FAIL; + const CFolder &folder = db.Folders[(unsigned)folderIndex2]; + + cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, + curUnpack, extractCallback, testMode != 0); + + HRESULT res = S_OK; + + switch (folder.GetMethod()) + { + case NHeader::NMethod::kNone: + break; + + case NHeader::NMethod::kMSZip: + deflateDecoder.Create_if_Empty(); + break; + + case NHeader::NMethod::kLZX: + lzxDecoder.Create_if_Empty(); + res = lzxDecoder->Set_DictBits_and_Alloc(folder.MethodMinor); + break; + + case NHeader::NMethod::kQuantum: + quantumDecoder.Create_if_Empty(); + res = quantumDecoder->SetParams(folder.MethodMinor); + break; + + default: + res = E_INVALIDARG; + break; + } + + if (res == E_INVALIDARG) + { + RINOK(cabFolderOutStream->Unsupported()) + totalUnPacked += curUnpack; + continue; + } + RINOK(res) + + { + unsigned volIndex = mvItem.VolumeIndex; + int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); + bool keepHistory = false; + bool keepInputBuffer = false; + bool thereWasNotAlignedChunk = false; + + for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();) + { + if (volIndex >= m_Database.Volumes.Size()) + { + res = S_FALSE; + break; + } + + const CDatabaseEx &db2 = m_Database.Volumes[volIndex]; + if (locFolderIndex < 0) + return E_FAIL; + const CFolder &folder2 = db2.Folders[(unsigned)locFolderIndex]; + + if (bl == 0) + { + RINOK(InStream_SeekSet(db2.Stream, db2.StartPosition + folder2.DataStart)) + } + + if (bl == folder2.NumDataBlocks) + { + /* + CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit. + But there are some big CAB archives from MS that contain more + than (0xFFFF) CFDATA blocks in folder. + Old cab extracting software can show error (or ask next volume) + but cab extracting library in new Windows ignores this error. + 15.00 : We also try to ignore such error, if archive is not multi-volume. + */ + if (m_Database.Volumes.Size() > 1) + { + volIndex++; + locFolderIndex = 0; + bl = 0; + continue; + } + } + + bl++; + + if (!keepInputBuffer) + blockPackData.InitForNewBlock(); + + UInt32 packSize, unpackSize; + res = blockPackData.Read(db2.Stream, db2.ArcInfo.GetDataBlockReserveSize(), packSize, unpackSize); + if (res == S_FALSE) + break; + RINOK(res) + keepInputBuffer = (unpackSize == 0); + if (keepInputBuffer) + continue; + + const UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder(); + totalPacked += packSize; + + if (totalUnPacked2 - lps->OutSize >= (1 << 26) + || totalPacked - lps->InSize >= (1 << 24)) + { + lps->OutSize = totalUnPacked2; + lps->InSize = totalPacked; + RINOK(lps->SetCur()) + } + + const unsigned kBlockSizeMax = 1u << 15; + + if (unpackSize != kBlockSizeMax) + { + if (unpackSize > kBlockSizeMax || thereWasNotAlignedChunk) + { + res = S_FALSE; + break; + } + thereWasNotAlignedChunk = true; + } + + /* We don't try to reduce last block. + Note that LZX converts data with x86 filter. + and filter needs larger input data than reduced size. + It's simpler to decompress full chunk here. + also we need full block for quantum for more integrity checks */ + + const UInt64 unpackSize64 = unpackSize; + const UInt32 packSizeChunk = blockPackData.GetPackSize(); + + switch (folder2.GetMethod()) + { + case NHeader::NMethod::kNone: + if (unpackSize != packSizeChunk) + { + res = S_FALSE; + break; + } + res = WriteStream(cabFolderOutStream, blockPackData.GetData(), packSizeChunk); + break; + + case NHeader::NMethod::kMSZip: + { + /* v24.00 : fixed : we check 2-bytes MSZIP signature only + when block was constructed from all volumes. */ + const Byte *packData = blockPackData.GetData(); + if (unpackSize > (1u << 15) + 12 /* MSZIP specification */ + || packSizeChunk < 2 || GetUi16(packData) != 0x4b43) + { + res = S_FALSE; + break; + } + const UInt32 packSizeChunk_2 = packSizeChunk - 2; + inBufStream->Init(packData + 2, packSizeChunk_2); + + deflateDecoder->Set_KeepHistory(keepHistory); + /* v9.31: now we follow MSZIP specification that requires + to finish deflate stream at the end of each block. + But PyCabArc can create CAB archives that don't have + finish marker at the end of block. + Cabarc probably ignores such errors in cab archives. + Maybe we also should ignore such error? + Or we should extract full file and show the warning? */ + deflateDecoder->Set_NeedFinishInput(true); + res = deflateDecoder.Interface()->Code(inBufStream, cabFolderOutStream, NULL, &unpackSize64, NULL); + if (res == S_OK) + { + if (!deflateDecoder->IsFinished()) + res = S_FALSE; + if (!deflateDecoder->IsFinalBlock()) + res = S_FALSE; + if (deflateDecoder->GetInputProcessedSize() != packSizeChunk_2) + res = S_FALSE; + } + break; + } + + case NHeader::NMethod::kLZX: + lzxDecoder->Set_KeepHistory(keepHistory); + lzxDecoder->Set_KeepHistoryForNext(true); + res = lzxDecoder->Code_WithExceedReadWrite(blockPackData.GetData(), + packSizeChunk, unpackSize); + if (res == S_OK) + res = WriteStream(cabFolderOutStream, + lzxDecoder->GetUnpackData(), + lzxDecoder->GetUnpackSize()); + break; + + case NHeader::NMethod::kQuantum: + { + res = quantumDecoder->Code(blockPackData.GetData(), + packSizeChunk, unpackSize, keepHistory); + if (res == S_OK) + { + const UInt32 num = unpackSize; + res = WriteStream(cabFolderOutStream, + quantumDecoder->GetDataPtr() - num, num); + } + break; + } + default: + // it's unexpected case, because we checked method before + // res = E_NOTIMPL; + break; + } + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + break; + } + + keepHistory = true; + } + + if (res == S_OK) + { + RINOK(cabFolderOutStream->WriteEmptyFiles()) + } + } + + if (res != S_OK || cabFolderOutStream->NeedMoreWrite()) + { + RINOK(cabFolderOutStream->FlushCorrupted((unsigned)folderIndex2)) + } + + totalUnPacked += curUnpack; + } + + return S_OK; + + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = m_Database.Items.Size(); + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h index 1299e283f..1e1811f8a 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.h +++ b/CPP/7zip/Archive/Cab/CabHandler.h @@ -1,29 +1,29 @@ -// CabHandler.h - -#ifndef ZIP7_INC_CAB_HANDLER_H -#define ZIP7_INC_CAB_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "CabIn.h" - -namespace NArchive { -namespace NCab { - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - CMvDatabaseEx m_Database; - UString _errorMessage; - bool _isArc; - bool _errorInHeaders; - bool _unexpectedEnd; - // int _mainVolIndex; - UInt32 _phySize; - UInt64 _offset; -}; - -}} - -#endif +// CabHandler.h + +#ifndef ZIP7_INC_CAB_HANDLER_H +#define ZIP7_INC_CAB_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "CabIn.h" + +namespace NArchive { +namespace NCab { + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + CMvDatabaseEx m_Database; + UString _errorMessage; + bool _isArc; + bool _errorInHeaders; + bool _unexpectedEnd; + // int _mainVolIndex; + UInt32 _phySize; + UInt64 _offset; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp index 76db98e98..370a2f1ef 100644 --- a/CPP/7zip/Archive/Cab/CabHeader.cpp +++ b/CPP/7zip/Archive/Cab/CabHeader.cpp @@ -1,15 +1,15 @@ -// CabHeader.cpp - -#include "StdAfx.h" - -#include "CabHeader.h" - -namespace NArchive { -namespace NCab { -namespace NHeader { - -const Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 }; - -// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; } } g_SignatureInitializer; - -}}} +// CabHeader.cpp + +#include "StdAfx.h" + +#include "CabHeader.h" + +namespace NArchive { +namespace NCab { +namespace NHeader { + +const Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 }; + +// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; } } g_SignatureInitializer; + +}}} diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h index edc97f8e6..ecb9a87b6 100644 --- a/CPP/7zip/Archive/Cab/CabHeader.h +++ b/CPP/7zip/Archive/Cab/CabHeader.h @@ -1,41 +1,41 @@ -// Archive/CabHeader.h - -#ifndef ZIP7_INC_ARCHIVE_CAB_HEADER_H -#define ZIP7_INC_ARCHIVE_CAB_HEADER_H - -#include "../../../Common/MyTypes.h" - -namespace NArchive { -namespace NCab { -namespace NHeader { - -const unsigned kMarkerSize = 8; -extern const Byte kMarker[kMarkerSize]; - -namespace NArcFlags -{ - const unsigned kPrevCabinet = 1; - const unsigned kNextCabinet = 2; - const unsigned kReservePresent = 4; -} - -namespace NMethod -{ - const Byte kNone = 0; - const Byte kMSZip = 1; - const Byte kQuantum = 2; - const Byte kLZX = 3; -} - -const unsigned kFileNameIsUtf8_Mask = 0x80; - -namespace NFolderIndex -{ - const unsigned kContinuedFromPrev = 0xFFFD; - const unsigned kContinuedToNext = 0xFFFE; - const unsigned kContinuedPrevAndNext = 0xFFFF; -} - -}}} - -#endif +// Archive/CabHeader.h + +#ifndef ZIP7_INC_ARCHIVE_CAB_HEADER_H +#define ZIP7_INC_ARCHIVE_CAB_HEADER_H + +#include "../../../Common/MyTypes.h" + +namespace NArchive { +namespace NCab { +namespace NHeader { + +const unsigned kMarkerSize = 8; +extern const Byte kMarker[kMarkerSize]; + +namespace NArcFlags +{ + const unsigned kPrevCabinet = 1; + const unsigned kNextCabinet = 2; + const unsigned kReservePresent = 4; +} + +namespace NMethod +{ + const Byte kNone = 0; + const Byte kMSZip = 1; + const Byte kQuantum = 2; + const Byte kLZX = 3; +} + +const unsigned kFileNameIsUtf8_Mask = 0x80; + +namespace NFolderIndex +{ + const unsigned kContinuedFromPrev = 0xFFFD; + const unsigned kContinuedToNext = 0xFFFE; + const unsigned kContinuedPrevAndNext = 0xFFFF; +} + +}}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp index eee274f63..bd6969a51 100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -1,490 +1,490 @@ -// Archive/CabIn.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../../C/CpuArch.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/StreamUtils.h" - -#include "CabIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -namespace NArchive { -namespace NCab { - -struct CUnexpectedEndException {}; - -void CInArchive::Skip(unsigned size) -{ - if (_inBuffer.Skip(size) != size) - throw CUnexpectedEndException(); -} - -void CInArchive::Read(Byte *data, unsigned size) -{ - if (_inBuffer.ReadBytes(data, size) != size) - throw CUnexpectedEndException(); -} - -void CInArchive::ReadName(AString &s) -{ - for (size_t i = 0; i < ((size_t)1 << 13); i++) - { - Byte b; - if (!_inBuffer.ReadByte(b)) - throw CUnexpectedEndException(); - if (b == 0) - { - s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i); - return; - } - if (_tempBuf.Size() == i) - _tempBuf.ChangeSize_KeepData(i * 2, i); - _tempBuf[i] = b; - } - - for (;;) - { - Byte b; - if (!_inBuffer.ReadByte(b)) - throw CUnexpectedEndException(); - if (b == 0) - break; - } - - ErrorInNames = true; - s = "[ERROR-LONG-PATH]"; -} - -void CInArchive::ReadOtherArc(COtherArc &oa) -{ - ReadName(oa.FileName); - ReadName(oa.DiskName); -} - - -struct CSignatureFinder -{ - Byte *Buf; - UInt32 Pos; - UInt32 End; - const Byte *Signature; - UInt32 SignatureSize; - - UInt32 _headerSize; - UInt32 _alignSize; - UInt32 _bufUseCapacity; - - const UInt64 *SearchLimit; - ISequentialInStream *Stream; - UInt64 Processed; // Global offset of start of Buf - - UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize) - { - _headerSize = headerSize; - for (_alignSize = (1 << 5); _alignSize < _headerSize; _alignSize <<= 1); - _bufUseCapacity = basicSize + _alignSize; - return _bufUseCapacity + 16; - } - - /* - returns: - S_OK - signature found (at Pos) - S_FALSE - signature not found - */ - HRESULT Find(); -}; - - -HRESULT CSignatureFinder::Find() -{ - for (;;) - { - Buf[End] = Signature[0]; // it's for fast search; - - while (End - Pos >= _headerSize) - { - const Byte *p = Buf + Pos; - const Byte b = Signature[0]; - for (;;) - { - if (*p == b) { break; } p++; - if (*p == b) { break; } p++; - } - Pos = (UInt32)(p - Buf); - if (End - Pos < _headerSize) - { - Pos = End - _headerSize + 1; - break; - } - UInt32 i; - for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++); - if (i == SignatureSize) - return S_OK; - Pos++; - } - - if (Pos >= _alignSize) - { - const UInt32 num = (Pos & ~(_alignSize - 1)); - Processed += num; - Pos -= num; - End -= num; - memmove(Buf, Buf + num, End); - } - UInt32 rem = _bufUseCapacity - End; - if (SearchLimit) - { - if (Processed + Pos > *SearchLimit) - return S_FALSE; - const UInt64 rem2 = *SearchLimit - (Processed + End) + _headerSize; - if (rem > rem2) - rem = (UInt32)rem2; - } - - UInt32 processedSize; - if (Processed == 0 && rem == _bufUseCapacity - _headerSize) - rem -= _alignSize; // to make reads more aligned. - RINOK(Stream->Read(Buf + End, rem, &processedSize)) - if (processedSize == 0) - return S_FALSE; - End += processedSize; - } -} - - -bool CInArcInfo::Parse(const Byte *p) -{ - if (Get32(p + 0x0C) != 0 || - Get32(p + 0x14) != 0) - return false; - Size = Get32(p + 8); - if (Size < 36) - return false; - Flags = Get16(p + 0x1E); - if (Flags > 7) - return false; - FileHeadersOffset = Get32(p + 0x10); - if (FileHeadersOffset != 0 && FileHeadersOffset > Size) - return false; - VersionMinor = p[0x18]; - VersionMajor = p[0x19]; - NumFolders = Get16(p + 0x1A); - NumFiles = Get16(p + 0x1C); - return true; -} - - -HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) -{ - IsArc = false; - ErrorInNames = false; - UnexpectedEnd = false; - HeaderError = false; - - db.Clear(); - RINOK(InStream_GetPos(db.Stream, db.StartPosition)) - // UInt64 temp = db.StartPosition; - - CByteBuffer buffer; - CInArcInfo &ai = db.ArcInfo; - UInt64 startInBuf = 0; - - CLimitedSequentialInStream *limitedStreamSpec = NULL; - CMyComPtr limitedStream; - - // for (int iii = 0; iii < 10000; iii++) - { - // db.StartPosition = temp; RINOK(InStream_SeekSet(db.Stream, db.StartPosition)) - - const UInt32 kMainHeaderSize = 32; - Byte header[kMainHeaderSize]; - const UInt32 kBufSize = 1 << 15; - RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize)) - if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header)) - { - limitedStreamSpec = new CLimitedSequentialInStream; - limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(db.Stream); - limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize); - buffer.Alloc(kBufSize); - memcpy(buffer, header, kMainHeaderSize); - UInt32 numProcessedBytes; - RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes)) - _inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize); - } - else - { - if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) - return S_FALSE; - - CSignatureFinder finder; - - finder.Stream = db.Stream; - finder.Signature = NHeader::kMarker; - finder.SignatureSize = NHeader::kMarkerSize; - finder.SearchLimit = searchHeaderSizeLimit; - - buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize)); - finder.Buf = buffer; - - memcpy(buffer, header, kMainHeaderSize); - finder.Processed = db.StartPosition; - finder.End = kMainHeaderSize; - finder.Pos = 1; - - for (;;) - { - RINOK(finder.Find()) - if (ai.Parse(finder.Buf + finder.Pos)) - { - db.StartPosition = finder.Processed + finder.Pos; - limitedStreamSpec = new CLimitedSequentialInStream; - limitedStreamSpec->SetStream(db.Stream); - limitedStream = limitedStreamSpec; - const UInt32 remInFinder = finder.End - finder.Pos; - if (ai.Size <= remInFinder) - { - limitedStreamSpec->Init(0); - finder.End = finder.Pos + ai.Size; - } - else - limitedStreamSpec->Init(ai.Size - remInFinder); - - startInBuf = finder.Pos; - _inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize); - break; - } - finder.Pos++; - } - } - } - - IsArc = true; - - _inBuffer.SetStream(limitedStream); - if (_tempBuf.Size() == 0) - _tempBuf.Alloc(1 << 12); - - Byte p[16]; - const unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0); - Read(p, nextSize); - ai.SetID = Get16(p); - ai.CabinetNumber = Get16(p + 2); - - if (ai.ReserveBlockPresent()) - { - ai.PerCabinet_AreaSize = Get16(p + 4); - ai.PerFolder_AreaSize = p[6]; - ai.PerDataBlock_AreaSize = p[7]; - Skip(ai.PerCabinet_AreaSize); - } - - if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc); - if (ai.IsThereNext()) ReadOtherArc(ai.NextArc); - - UInt32 i; - - db.Folders.ClearAndReserve(ai.NumFolders); - - for (i = 0; i < ai.NumFolders; i++) - { - Read(p, 8); - CFolder folder; - folder.DataStart = Get32(p); - folder.NumDataBlocks = Get16(p + 4); - folder.MethodMajor = p[6]; - folder.MethodMinor = p[7]; - Skip(ai.PerFolder_AreaSize); - db.Folders.AddInReserved(folder); - } - - // for (int iii = 0; iii < 10000; iii++) { - - if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset) - { - // printf("\n!!! Seek Error !!!!\n"); - // fflush(stdout); - RINOK(InStream_SeekSet(db.Stream, db.StartPosition + ai.FileHeadersOffset)) - limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset); - _inBuffer.Init(); - } - - db.Items.ClearAndReserve(ai.NumFiles); - - for (i = 0; i < ai.NumFiles; i++) - { - Read(p, 16); - CItem &item = db.Items.AddNewInReserved(); - item.Size = Get32(p); - item.Offset = Get32(p + 4); - item.FolderIndex = Get16(p + 8); - const UInt16 pureDate = Get16(p + 10); - const UInt16 pureTime = Get16(p + 12); - item.Time = (((UInt32)pureDate << 16)) | pureTime; - item.Attributes = Get16(p + 14); - - ReadName(item.Name); - - if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) - { - HeaderError = true; - return S_FALSE; - } - } - - // } - - return S_OK; -} - - -HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) -{ - try - { - return Open2(db, searchHeaderSizeLimit); - } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } -} - - - -#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } - -static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) -{ - const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param; - const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex]; - const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex]; - const CItem &item1 = db1.Items[p1->ItemIndex]; - const CItem &item2 = db2.Items[p2->ItemIndex]; - const bool isDir1 = item1.IsDir(); - const bool isDir2 = item2.IsDir(); - if (isDir1 && !isDir2) return -1; - if (isDir2 && !isDir1) return 1; - const int f1 = mvDb.GetFolderIndex(p1); - const int f2 = mvDb.GetFolderIndex(p2); - RINOZ(MyCompare(f1, f2)) - RINOZ(MyCompare(item1.Offset, item2.Offset)) - RINOZ(MyCompare(item1.Size, item2.Size)) - RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex)) - return MyCompare(p1->ItemIndex, p2->ItemIndex); -} - - -bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) -{ - const CMvItem *p1 = &Items[i1]; - const CMvItem *p2 = &Items[i2]; - const CDatabaseEx &db1 = Volumes[p1->VolumeIndex]; - const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; - const CItem &item1 = db1.Items[p1->ItemIndex]; - const CItem &item2 = db2.Items[p2->ItemIndex]; - return GetFolderIndex(p1) == GetFolderIndex(p2) - && item1.Offset == item2.Offset - && item1.Size == item2.Size - && item1.Name == item2.Name; -} - - -void CMvDatabaseEx::FillSortAndShrink() -{ - Items.Clear(); - StartFolderOfVol.Clear(); - FolderStartFileIndex.Clear(); - - int offset = 0; - - FOR_VECTOR (v, Volumes) - { - const CDatabaseEx &db = Volumes[v]; - int curOffset = offset; - if (db.IsTherePrevFolder()) - curOffset--; - StartFolderOfVol.Add(curOffset); - offset += db.GetNumberOfNewFolders(); - - CMvItem mvItem; - mvItem.VolumeIndex = v; - FOR_VECTOR (i, db.Items) - { - mvItem.ItemIndex = i; - Items.Add(mvItem); - } - } - - if (Items.Size() > 1) - { - Items.Sort(CompareMvItems, (void *)this); - unsigned j = 1; - unsigned i = 1; - for (; i < Items.Size(); i++) - if (!AreItemsEqual(i, i - 1)) - Items[j++] = Items[i]; - Items.DeleteFrom(j); - } - - FOR_VECTOR (i, Items) - { - const int folderIndex = GetFolderIndex(&Items[i]); - while (folderIndex >= (int)FolderStartFileIndex.Size()) - FolderStartFileIndex.Add(i); - } -} - - -bool CMvDatabaseEx::Check() -{ - for (unsigned v = 1; v < Volumes.Size(); v++) - { - const CDatabaseEx &db1 = Volumes[v]; - if (db1.IsTherePrevFolder()) - { - const CDatabaseEx &db0 = Volumes[v - 1]; - if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty()) - return false; - const CFolder &f0 = db0.Folders.Back(); - const CFolder &f1 = db1.Folders.FrontItem(); - if (f0.MethodMajor != f1.MethodMajor || - f0.MethodMinor != f1.MethodMinor) - return false; - } - } - - UInt32 beginPos = 0; - UInt64 endPos = 0; - int prevFolder = -2; - - FOR_VECTOR (i, Items) - { - const CMvItem &mvItem = Items[i]; - const int fIndex = GetFolderIndex(&mvItem); - if (fIndex >= (int)FolderStartFileIndex.Size()) - return false; - const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - if (item.IsDir()) - continue; - - const int folderIndex = GetFolderIndex(&mvItem); - - if (folderIndex != prevFolder) - prevFolder = folderIndex; - else if (item.Offset < endPos && - (item.Offset != beginPos || item.GetEndOffset() != endPos)) - return false; - - beginPos = item.Offset; - endPos = item.GetEndOffset(); - } - - return true; -} - -}} +// Archive/CabIn.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../../C/CpuArch.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamUtils.h" + +#include "CabIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NCab { + +struct CUnexpectedEndException {}; + +void CInArchive::Skip(unsigned size) +{ + if (_inBuffer.Skip(size) != size) + throw CUnexpectedEndException(); +} + +void CInArchive::Read(Byte *data, unsigned size) +{ + if (_inBuffer.ReadBytes(data, size) != size) + throw CUnexpectedEndException(); +} + +void CInArchive::ReadName(AString &s) +{ + for (size_t i = 0; i < ((size_t)1 << 13); i++) + { + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CUnexpectedEndException(); + if (b == 0) + { + s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i); + return; + } + if (_tempBuf.Size() == i) + _tempBuf.ChangeSize_KeepData(i * 2, i); + _tempBuf[i] = b; + } + + for (;;) + { + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CUnexpectedEndException(); + if (b == 0) + break; + } + + ErrorInNames = true; + s = "[ERROR-LONG-PATH]"; +} + +void CInArchive::ReadOtherArc(COtherArc &oa) +{ + ReadName(oa.FileName); + ReadName(oa.DiskName); +} + + +struct CSignatureFinder +{ + Byte *Buf; + UInt32 Pos; + UInt32 End; + const Byte *Signature; + UInt32 SignatureSize; + + UInt32 _headerSize; + UInt32 _alignSize; + UInt32 _bufUseCapacity; + + const UInt64 *SearchLimit; + ISequentialInStream *Stream; + UInt64 Processed; // Global offset of start of Buf + + UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize) + { + _headerSize = headerSize; + for (_alignSize = (1 << 5); _alignSize < _headerSize; _alignSize <<= 1); + _bufUseCapacity = basicSize + _alignSize; + return _bufUseCapacity + 16; + } + + /* + returns: + S_OK - signature found (at Pos) + S_FALSE - signature not found + */ + HRESULT Find(); +}; + + +HRESULT CSignatureFinder::Find() +{ + for (;;) + { + Buf[End] = Signature[0]; // it's for fast search; + + while (End - Pos >= _headerSize) + { + const Byte *p = Buf + Pos; + const Byte b = Signature[0]; + for (;;) + { + if (*p == b) { break; } p++; + if (*p == b) { break; } p++; + } + Pos = (UInt32)(p - Buf); + if (End - Pos < _headerSize) + { + Pos = End - _headerSize + 1; + break; + } + UInt32 i; + for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++); + if (i == SignatureSize) + return S_OK; + Pos++; + } + + if (Pos >= _alignSize) + { + const UInt32 num = (Pos & ~(_alignSize - 1)); + Processed += num; + Pos -= num; + End -= num; + memmove(Buf, Buf + num, End); + } + UInt32 rem = _bufUseCapacity - End; + if (SearchLimit) + { + if (Processed + Pos > *SearchLimit) + return S_FALSE; + const UInt64 rem2 = *SearchLimit - (Processed + End) + _headerSize; + if (rem > rem2) + rem = (UInt32)rem2; + } + + UInt32 processedSize; + if (Processed == 0 && rem == _bufUseCapacity - _headerSize) + rem -= _alignSize; // to make reads more aligned. + RINOK(Stream->Read(Buf + End, rem, &processedSize)) + if (processedSize == 0) + return S_FALSE; + End += processedSize; + } +} + + +bool CInArcInfo::Parse(const Byte *p) +{ + if (Get32(p + 0x0C) != 0 || + Get32(p + 0x14) != 0) + return false; + Size = Get32(p + 8); + if (Size < 36) + return false; + Flags = Get16(p + 0x1E); + if (Flags > 7) + return false; + FileHeadersOffset = Get32(p + 0x10); + if (FileHeadersOffset != 0 && FileHeadersOffset > Size) + return false; + VersionMinor = p[0x18]; + VersionMajor = p[0x19]; + NumFolders = Get16(p + 0x1A); + NumFiles = Get16(p + 0x1C); + return true; +} + + +HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) +{ + IsArc = false; + ErrorInNames = false; + UnexpectedEnd = false; + HeaderError = false; + + db.Clear(); + RINOK(InStream_GetPos(db.Stream, db.StartPosition)) + // UInt64 temp = db.StartPosition; + + CByteBuffer buffer; + CInArcInfo &ai = db.ArcInfo; + UInt64 startInBuf = 0; + + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr limitedStream; + + // for (int iii = 0; iii < 10000; iii++) + { + // db.StartPosition = temp; RINOK(InStream_SeekSet(db.Stream, db.StartPosition)) + + const UInt32 kMainHeaderSize = 32; + Byte header[kMainHeaderSize]; + const UInt32 kBufSize = 1 << 15; + RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize)) + if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header)) + { + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(db.Stream); + limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize); + buffer.Alloc(kBufSize); + memcpy(buffer, header, kMainHeaderSize); + UInt32 numProcessedBytes; + RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes)) + _inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize); + } + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + + CSignatureFinder finder; + + finder.Stream = db.Stream; + finder.Signature = NHeader::kMarker; + finder.SignatureSize = NHeader::kMarkerSize; + finder.SearchLimit = searchHeaderSizeLimit; + + buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize)); + finder.Buf = buffer; + + memcpy(buffer, header, kMainHeaderSize); + finder.Processed = db.StartPosition; + finder.End = kMainHeaderSize; + finder.Pos = 1; + + for (;;) + { + RINOK(finder.Find()) + if (ai.Parse(finder.Buf + finder.Pos)) + { + db.StartPosition = finder.Processed + finder.Pos; + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStreamSpec->SetStream(db.Stream); + limitedStream = limitedStreamSpec; + const UInt32 remInFinder = finder.End - finder.Pos; + if (ai.Size <= remInFinder) + { + limitedStreamSpec->Init(0); + finder.End = finder.Pos + ai.Size; + } + else + limitedStreamSpec->Init(ai.Size - remInFinder); + + startInBuf = finder.Pos; + _inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize); + break; + } + finder.Pos++; + } + } + } + + IsArc = true; + + _inBuffer.SetStream(limitedStream); + if (_tempBuf.Size() == 0) + _tempBuf.Alloc(1 << 12); + + Byte p[16]; + const unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0); + Read(p, nextSize); + ai.SetID = Get16(p); + ai.CabinetNumber = Get16(p + 2); + + if (ai.ReserveBlockPresent()) + { + ai.PerCabinet_AreaSize = Get16(p + 4); + ai.PerFolder_AreaSize = p[6]; + ai.PerDataBlock_AreaSize = p[7]; + Skip(ai.PerCabinet_AreaSize); + } + + if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc); + if (ai.IsThereNext()) ReadOtherArc(ai.NextArc); + + UInt32 i; + + db.Folders.ClearAndReserve(ai.NumFolders); + + for (i = 0; i < ai.NumFolders; i++) + { + Read(p, 8); + CFolder folder; + folder.DataStart = Get32(p); + folder.NumDataBlocks = Get16(p + 4); + folder.MethodMajor = p[6]; + folder.MethodMinor = p[7]; + Skip(ai.PerFolder_AreaSize); + db.Folders.AddInReserved(folder); + } + + // for (int iii = 0; iii < 10000; iii++) { + + if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset) + { + // printf("\n!!! Seek Error !!!!\n"); + // fflush(stdout); + RINOK(InStream_SeekSet(db.Stream, db.StartPosition + ai.FileHeadersOffset)) + limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset); + _inBuffer.Init(); + } + + db.Items.ClearAndReserve(ai.NumFiles); + + for (i = 0; i < ai.NumFiles; i++) + { + Read(p, 16); + CItem &item = db.Items.AddNewInReserved(); + item.Size = Get32(p); + item.Offset = Get32(p + 4); + item.FolderIndex = Get16(p + 8); + const UInt16 pureDate = Get16(p + 10); + const UInt16 pureTime = Get16(p + 12); + item.Time = (((UInt32)pureDate << 16)) | pureTime; + item.Attributes = Get16(p + 14); + + ReadName(item.Name); + + if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) + { + HeaderError = true; + return S_FALSE; + } + } + + // } + + return S_OK; +} + + +HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) +{ + try + { + return Open2(db, searchHeaderSizeLimit); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } +} + + + +#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } + +static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) +{ + const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param; + const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex]; + const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex]; + const CItem &item1 = db1.Items[p1->ItemIndex]; + const CItem &item2 = db2.Items[p2->ItemIndex]; + const bool isDir1 = item1.IsDir(); + const bool isDir2 = item2.IsDir(); + if (isDir1 && !isDir2) return -1; + if (isDir2 && !isDir1) return 1; + const int f1 = mvDb.GetFolderIndex(p1); + const int f2 = mvDb.GetFolderIndex(p2); + RINOZ(MyCompare(f1, f2)) + RINOZ(MyCompare(item1.Offset, item2.Offset)) + RINOZ(MyCompare(item1.Size, item2.Size)) + RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex)) + return MyCompare(p1->ItemIndex, p2->ItemIndex); +} + + +bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) +{ + const CMvItem *p1 = &Items[i1]; + const CMvItem *p2 = &Items[i2]; + const CDatabaseEx &db1 = Volumes[p1->VolumeIndex]; + const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; + const CItem &item1 = db1.Items[p1->ItemIndex]; + const CItem &item2 = db2.Items[p2->ItemIndex]; + return GetFolderIndex(p1) == GetFolderIndex(p2) + && item1.Offset == item2.Offset + && item1.Size == item2.Size + && item1.Name == item2.Name; +} + + +void CMvDatabaseEx::FillSortAndShrink() +{ + Items.Clear(); + StartFolderOfVol.Clear(); + FolderStartFileIndex.Clear(); + + int offset = 0; + + FOR_VECTOR (v, Volumes) + { + const CDatabaseEx &db = Volumes[v]; + int curOffset = offset; + if (db.IsTherePrevFolder()) + curOffset--; + StartFolderOfVol.Add(curOffset); + offset += db.GetNumberOfNewFolders(); + + CMvItem mvItem; + mvItem.VolumeIndex = v; + FOR_VECTOR (i, db.Items) + { + mvItem.ItemIndex = i; + Items.Add(mvItem); + } + } + + if (Items.Size() > 1) + { + Items.Sort(CompareMvItems, (void *)this); + unsigned j = 1; + unsigned i = 1; + for (; i < Items.Size(); i++) + if (!AreItemsEqual(i, i - 1)) + Items[j++] = Items[i]; + Items.DeleteFrom(j); + } + + FOR_VECTOR (i, Items) + { + const int folderIndex = GetFolderIndex(&Items[i]); + while (folderIndex >= (int)FolderStartFileIndex.Size()) + FolderStartFileIndex.Add(i); + } +} + + +bool CMvDatabaseEx::Check() +{ + for (unsigned v = 1; v < Volumes.Size(); v++) + { + const CDatabaseEx &db1 = Volumes[v]; + if (db1.IsTherePrevFolder()) + { + const CDatabaseEx &db0 = Volumes[v - 1]; + if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty()) + return false; + const CFolder &f0 = db0.Folders.Back(); + const CFolder &f1 = db1.Folders.FrontItem(); + if (f0.MethodMajor != f1.MethodMajor || + f0.MethodMinor != f1.MethodMinor) + return false; + } + } + + UInt32 beginPos = 0; + UInt64 endPos = 0; + int prevFolder = -2; + + FOR_VECTOR (i, Items) + { + const CMvItem &mvItem = Items[i]; + const int fIndex = GetFolderIndex(&mvItem); + if (fIndex >= (int)FolderStartFileIndex.Size()) + return false; + const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDir()) + continue; + + const int folderIndex = GetFolderIndex(&mvItem); + + if (folderIndex != prevFolder) + prevFolder = folderIndex; + else if (item.Offset < endPos && + (item.Offset != beginPos || item.GetEndOffset() != endPos)) + return false; + + beginPos = item.Offset; + endPos = item.GetEndOffset(); + } + + return true; +} + +}} diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h index 3cb3814c5..06aa34c77 100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -1,176 +1,176 @@ -// Archive/CabIn.h - -#ifndef ZIP7_INC_ARCHIVE_CAB_IN_H -#define ZIP7_INC_ARCHIVE_CAB_IN_H - -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyCom.h" - -#include "../../Common/InBuffer.h" - -#include "CabItem.h" - -namespace NArchive { -namespace NCab { - -struct COtherArc -{ - AString FileName; - AString DiskName; - - void Clear() - { - FileName.Empty(); - DiskName.Empty(); - } -}; - - -struct CArchInfo -{ - Byte VersionMinor; // cabinet file format version, minor - Byte VersionMajor; // cabinet file format version, major - UInt32 NumFolders; // number of CFFOLDER entries in this cabinet - UInt32 NumFiles; // number of CFFILE entries in this cabinet - UInt32 Flags; // cabinet file option indicators - UInt32 SetID; // must be the same for all cabinets in a set - UInt32 CabinetNumber; // number of this cabinet file in a set - - UInt16 PerCabinet_AreaSize; // (optional) size of per-cabinet reserved area - Byte PerFolder_AreaSize; // (optional) size of per-folder reserved area - Byte PerDataBlock_AreaSize; // (optional) size of per-datablock reserved area - - COtherArc PrevArc; // prev link can skip some volumes !!! - COtherArc NextArc; - - bool ReserveBlockPresent() const { return (Flags & NHeader::NArcFlags::kReservePresent) != 0; } - bool IsTherePrev() const { return (Flags & NHeader::NArcFlags::kPrevCabinet) != 0; } - bool IsThereNext() const { return (Flags & NHeader::NArcFlags::kNextCabinet) != 0; } - Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlock_AreaSize : 0); } - - CArchInfo() - { - PerCabinet_AreaSize = 0; - PerFolder_AreaSize = 0; - PerDataBlock_AreaSize = 0; - } - - void Clear() - { - PerCabinet_AreaSize = 0; - PerFolder_AreaSize = 0; - PerDataBlock_AreaSize = 0; - - PrevArc.Clear(); - NextArc.Clear(); - } -}; - - -struct CInArcInfo: public CArchInfo -{ - UInt32 Size; // size of this cabinet file in bytes - UInt32 FileHeadersOffset; // offset of the first CFFILE entry - - bool Parse(const Byte *p); -}; - - -struct CDatabase -{ - CRecordVector Folders; - CObjectVector Items; - UInt64 StartPosition; - CInArcInfo ArcInfo; - - void Clear() - { - ArcInfo.Clear(); - Folders.Clear(); - Items.Clear(); - } - - bool IsTherePrevFolder() const - { - FOR_VECTOR (i, Items) - if (Items[i].ContinuedFromPrev()) - return true; - return false; - } - - int GetNumberOfNewFolders() const - { - int res = (int)Folders.Size(); - if (IsTherePrevFolder()) - res--; - return res; - } -}; - - -struct CDatabaseEx: public CDatabase -{ - CMyComPtr Stream; -}; - - -struct CMvItem -{ - unsigned VolumeIndex; - unsigned ItemIndex; -}; - - -class CMvDatabaseEx -{ - bool AreItemsEqual(unsigned i1, unsigned i2); - -public: - CObjectVector Volumes; - CRecordVector Items; - CRecordVector StartFolderOfVol; // can be negative - CRecordVector FolderStartFileIndex; - - int GetFolderIndex(const CMvItem *mvi) const - { - const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; - return StartFolderOfVol[mvi->VolumeIndex] + - db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); - } - - void Clear() - { - Volumes.Clear(); - Items.Clear(); - StartFolderOfVol.Clear(); - FolderStartFileIndex.Clear(); - } - - void FillSortAndShrink(); - bool Check(); -}; - - -class CInArchive -{ - CInBufferBase _inBuffer; - CByteBuffer _tempBuf; - - void Skip(unsigned size); - void Read(Byte *data, unsigned size); - void ReadName(AString &s); - void ReadOtherArc(COtherArc &oa); - HRESULT Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); - -public: - bool IsArc; - bool ErrorInNames; - bool UnexpectedEnd; - bool HeaderError; - - HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); -}; - -}} - -#endif +// Archive/CabIn.h + +#ifndef ZIP7_INC_ARCHIVE_CAB_IN_H +#define ZIP7_INC_ARCHIVE_CAB_IN_H + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" + +#include "../../Common/InBuffer.h" + +#include "CabItem.h" + +namespace NArchive { +namespace NCab { + +struct COtherArc +{ + AString FileName; + AString DiskName; + + void Clear() + { + FileName.Empty(); + DiskName.Empty(); + } +}; + + +struct CArchInfo +{ + Byte VersionMinor; // cabinet file format version, minor + Byte VersionMajor; // cabinet file format version, major + UInt32 NumFolders; // number of CFFOLDER entries in this cabinet + UInt32 NumFiles; // number of CFFILE entries in this cabinet + UInt32 Flags; // cabinet file option indicators + UInt32 SetID; // must be the same for all cabinets in a set + UInt32 CabinetNumber; // number of this cabinet file in a set + + UInt16 PerCabinet_AreaSize; // (optional) size of per-cabinet reserved area + Byte PerFolder_AreaSize; // (optional) size of per-folder reserved area + Byte PerDataBlock_AreaSize; // (optional) size of per-datablock reserved area + + COtherArc PrevArc; // prev link can skip some volumes !!! + COtherArc NextArc; + + bool ReserveBlockPresent() const { return (Flags & NHeader::NArcFlags::kReservePresent) != 0; } + bool IsTherePrev() const { return (Flags & NHeader::NArcFlags::kPrevCabinet) != 0; } + bool IsThereNext() const { return (Flags & NHeader::NArcFlags::kNextCabinet) != 0; } + Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlock_AreaSize : 0); } + + CArchInfo() + { + PerCabinet_AreaSize = 0; + PerFolder_AreaSize = 0; + PerDataBlock_AreaSize = 0; + } + + void Clear() + { + PerCabinet_AreaSize = 0; + PerFolder_AreaSize = 0; + PerDataBlock_AreaSize = 0; + + PrevArc.Clear(); + NextArc.Clear(); + } +}; + + +struct CInArcInfo: public CArchInfo +{ + UInt32 Size; // size of this cabinet file in bytes + UInt32 FileHeadersOffset; // offset of the first CFFILE entry + + bool Parse(const Byte *p); +}; + + +struct CDatabase +{ + CRecordVector Folders; + CObjectVector Items; + UInt64 StartPosition; + CInArcInfo ArcInfo; + + void Clear() + { + ArcInfo.Clear(); + Folders.Clear(); + Items.Clear(); + } + + bool IsTherePrevFolder() const + { + FOR_VECTOR (i, Items) + if (Items[i].ContinuedFromPrev()) + return true; + return false; + } + + int GetNumberOfNewFolders() const + { + int res = (int)Folders.Size(); + if (IsTherePrevFolder()) + res--; + return res; + } +}; + + +struct CDatabaseEx: public CDatabase +{ + CMyComPtr Stream; +}; + + +struct CMvItem +{ + unsigned VolumeIndex; + unsigned ItemIndex; +}; + + +class CMvDatabaseEx +{ + bool AreItemsEqual(unsigned i1, unsigned i2); + +public: + CObjectVector Volumes; + CRecordVector Items; + CRecordVector StartFolderOfVol; // can be negative + CRecordVector FolderStartFileIndex; + + int GetFolderIndex(const CMvItem *mvi) const + { + const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; + return StartFolderOfVol[mvi->VolumeIndex] + + db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); + } + + void Clear() + { + Volumes.Clear(); + Items.Clear(); + StartFolderOfVol.Clear(); + FolderStartFileIndex.Clear(); + } + + void FillSortAndShrink(); + bool Check(); +}; + + +class CInArchive +{ + CInBufferBase _inBuffer; + CByteBuffer _tempBuf; + + void Skip(unsigned size); + void Read(Byte *data, unsigned size); + void ReadName(AString &s); + void ReadOtherArc(COtherArc &oa); + HRESULT Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); + +public: + bool IsArc; + bool ErrorInNames; + bool UnexpectedEnd; + bool HeaderError; + + HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h index 8b4879535..b7e07d1cc 100644 --- a/CPP/7zip/Archive/Cab/CabItem.h +++ b/CPP/7zip/Archive/Cab/CabItem.h @@ -1,66 +1,66 @@ -// Archive/CabItem.h - -#ifndef ZIP7_INC_ARCHIVE_CAB_ITEM_H -#define ZIP7_INC_ARCHIVE_CAB_ITEM_H - -#include "../../../Common/MyString.h" - -#include "CabHeader.h" - -namespace NArchive { -namespace NCab { - -const unsigned kNumMethodsMax = 16; - -struct CFolder -{ - UInt32 DataStart; // offset of the first CFDATA block in this folder - UInt16 NumDataBlocks; // number of CFDATA blocks in this folder - Byte MethodMajor; - Byte MethodMinor; - - Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); } -}; - -struct CItem -{ - AString Name; - UInt32 Offset; - UInt32 Size; - UInt32 Time; - UInt32 FolderIndex; - UInt16 Flags; - UInt16 Attributes; - - UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } - UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; } - bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; } - bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } - - bool ContinuedFromPrev() const - { - return - FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev || - FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; - } - - bool ContinuedToNext() const - { - return - FolderIndex == NHeader::NFolderIndex::kContinuedToNext || - FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; - } - - int GetFolderIndex(unsigned numFolders) const - { - if (ContinuedFromPrev()) - return 0; - if (ContinuedToNext()) - return (int)numFolders - 1; - return (int)FolderIndex; - } -}; - -}} - -#endif +// Archive/CabItem.h + +#ifndef ZIP7_INC_ARCHIVE_CAB_ITEM_H +#define ZIP7_INC_ARCHIVE_CAB_ITEM_H + +#include "../../../Common/MyString.h" + +#include "CabHeader.h" + +namespace NArchive { +namespace NCab { + +const unsigned kNumMethodsMax = 16; + +struct CFolder +{ + UInt32 DataStart; // offset of the first CFDATA block in this folder + UInt16 NumDataBlocks; // number of CFDATA blocks in this folder + Byte MethodMajor; + Byte MethodMinor; + + Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); } +}; + +struct CItem +{ + AString Name; + UInt32 Offset; + UInt32 Size; + UInt32 Time; + UInt32 FolderIndex; + UInt16 Flags; + UInt16 Attributes; + + UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } + UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; } + bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; } + bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } + + bool ContinuedFromPrev() const + { + return + FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev || + FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; + } + + bool ContinuedToNext() const + { + return + FolderIndex == NHeader::NFolderIndex::kContinuedToNext || + FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; + } + + int GetFolderIndex(unsigned numFolders) const + { + if (ContinuedFromPrev()) + return 0; + if (ContinuedToNext()) + return (int)numFolders - 1; + return (int)FolderIndex; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp index 1069c6cb1..8f4f323f9 100644 --- a/CPP/7zip/Archive/Cab/CabRegister.cpp +++ b/CPP/7zip/Archive/Cab/CabRegister.cpp @@ -1,19 +1,19 @@ -// CabRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "CabHandler.h" - -namespace NArchive { -namespace NCab { - -REGISTER_ARC_I( - "Cab", "cab", NULL, 8, - NHeader::kMarker, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -}} +// CabRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "CabHandler.h" + +namespace NArchive { +namespace NCab { + +REGISTER_ARC_I( + "Cab", "cab", NULL, 8, + NHeader::kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Cab/StdAfx.h +++ b/CPP/7zip/Archive/Cab/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp index 21c7f10b1..93c3a85ef 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.cpp +++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp @@ -1,790 +1,790 @@ -// ChmHandler.cpp - -#include "StdAfx.h" - -#include "../../../Common/AutoPtr.h" -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" -#include "../../Common/RegisterArc.h" - -#include "../../Compress/CopyCoder.h" -#include "../../Compress/LzxDecoder.h" - -#include "../Common/ItemNameUtils.h" - -#include "ChmHandler.h" - -using namespace NWindows; -using namespace NTime; - -namespace NArchive { -namespace NChm { - -// #define CHM_DETAILS - -#ifdef CHM_DETAILS - -enum -{ - kpidSection = kpidUserDefined -}; - -#endif - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidMethod, - kpidBlock - - #ifdef CHM_DETAILS - , - L"Section", kpidSection, - kpidOffset - #endif -}; - -/* -static const Byte kArcProps[] = -{ - // kpidNumBlocks, -}; -*/ - -IMP_IInArchive_Props - -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - // COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - /* - case kpidNumBlocks: - { - UInt64 numBlocks = 0; - FOR_VECTOR(i, m_Database.Sections) - { - const CSectionInfo &s = m_Database.Sections[i]; - FOR_VECTOR(j, s.Methods) - { - const CMethodInfo &m = s.Methods[j]; - if (m.IsLzx()) - numBlocks += m.LzxInfo.ResetTable.GetNumBlocks(); - } - } - prop = numBlocks; - break; - } - */ - case kpidOffset: prop = m_Database.StartPosition; break; - case kpidPhySize: prop = m_Database.PhySize; break; - - case kpidErrorFlags: prop = m_ErrorFlags; break; - } - prop.Detach(value); - return S_OK; - // COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - if (m_Database.NewFormat) - { - switch (propID) - { - case kpidSize: - prop = (UInt64)m_Database.NewFormatString.Len(); - break; - } - prop.Detach(value); - return S_OK; - } - - unsigned entryIndex; - if (m_Database.LowLevel) - entryIndex = index; - else - entryIndex = m_Database.Indices[index]; - - const CItem &item = m_Database.Items[entryIndex]; - - switch (propID) - { - case kpidPath: - { - UString us; - // if ( - ConvertUTF8ToUnicode(item.Name, us); - { - if (!m_Database.LowLevel) - { - if (us.Len() > 1 && us[0] == L'/') - us.Delete(0); - } - NItemName::ReplaceToOsSlashes_Remove_TailSlash(us); - prop = us; - } - break; - } - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = item.Size; break; - case kpidMethod: - { - if (!item.IsDir()) - { - if (item.Section == 0) - prop = "Copy"; - else if (item.Section < m_Database.Sections.Size()) - prop = m_Database.Sections[(unsigned)item.Section].GetMethodName(); - } - break; - } - case kpidBlock: - if (m_Database.LowLevel) - prop = item.Section; - else if (item.Section != 0 && item.Section < m_Database.Sections.Size()) - prop = m_Database.GetFolder(index); - break; - - #ifdef CHM_DETAILS - - case kpidSection: prop = (UInt32)item.Section; break; - case kpidOffset: prop = (UInt32)item.Offset; break; - - #endif - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - try - { - CInArchive archive(_help2); - // CProgressImp progressImp(openArchiveCallback); - const HRESULT res = archive.Open(inStream, maxCheckStartPosition, m_Database); - if (!archive.IsArc) m_ErrorFlags |= kpv_ErrorFlags_IsNotArc; - if (archive.HeadersError) m_ErrorFlags |= kpv_ErrorFlags_HeadersError; - if (archive.UnexpectedEnd) m_ErrorFlags |= kpv_ErrorFlags_UnexpectedEnd; - if (archive.UnsupportedFeature) m_ErrorFlags |= kpv_ErrorFlags_UnsupportedFeature; - - RINOK(res) - /* - if (m_Database.LowLevel) - return S_FALSE; - */ - m_Stream = inStream; - } - catch(...) - { - return S_FALSE; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - m_ErrorFlags = 0; - m_Database.Clear(); - m_Stream.Release(); - return S_OK; -} - -Z7_CLASS_IMP_NOQIB_1( - CChmFolderOutStream - , ISequentialOutStream -) - bool m_TestMode; - bool m_IsOk; - bool m_FileIsOpen; - const CFilesDatabase *m_Database; - CMyComPtr m_ExtractCallback; - CMyComPtr m_RealOutStream; - UInt64 m_RemainFileSize; - - HRESULT OpenFile(); - HRESULT WriteEmptyFiles(); - HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); -public: - - UInt64 m_FolderSize; - UInt64 m_PosInFolder; - UInt64 m_PosInSection; - const CRecordVector *m_ExtractStatuses; - unsigned m_StartIndex; - unsigned m_CurrentIndex; - unsigned m_NumFiles; - - void Init( - const CFilesDatabase *database, - IArchiveExtractCallback *extractCallback, - bool testMode); - HRESULT FlushCorrupted(UInt64 maxSize); -}; - -void CChmFolderOutStream::Init( - const CFilesDatabase *database, - IArchiveExtractCallback *extractCallback, - bool testMode) -{ - m_Database = database; - m_ExtractCallback = extractCallback; - m_TestMode = testMode; - - m_CurrentIndex = 0; - m_FileIsOpen = false; -} - -HRESULT CChmFolderOutStream::OpenFile() -{ - Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? m_TestMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract : - NExtract::NAskMode::kSkip; - m_RealOutStream.Release(); - RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)) - if (!m_RealOutStream && !m_TestMode) - askMode = NExtract::NAskMode::kSkip; - return m_ExtractCallback->PrepareOperation(askMode); -} - -HRESULT CChmFolderOutStream::WriteEmptyFiles() -{ - if (m_FileIsOpen) - return S_OK; - for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++) - { - const UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex); - if (fileSize != 0) - return S_OK; - const HRESULT result = OpenFile(); - m_RealOutStream.Release(); - RINOK(result) - RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - return S_OK; -} - -// This is WritePart function -HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) -{ - UInt32 realProcessed = 0; - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - if (m_FileIsOpen) - { - UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size)); - HRESULT res = S_OK; - if (numBytesToWrite > 0) - { - if (!isOK) - m_IsOk = false; - if (m_RealOutStream) - { - UInt32 processedSizeLocal = 0; - res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); - numBytesToWrite = processedSizeLocal; - } - } - realProcessed += numBytesToWrite; - if (processedSize) - *processedSize = realProcessed; - data = (const void *)((const Byte *)data + numBytesToWrite); - size -= numBytesToWrite; - m_RemainFileSize -= numBytesToWrite; - m_PosInSection += numBytesToWrite; - m_PosInFolder += numBytesToWrite; - if (res != S_OK) - return res; - if (m_RemainFileSize == 0) - { - m_RealOutStream.Release(); - RINOK(m_ExtractCallback->SetOperationResult( - m_IsOk ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)) - m_FileIsOpen = false; - } - if (realProcessed > 0) - break; // with this break this function works as write part - } - else - { - if (m_CurrentIndex >= m_NumFiles) - { - realProcessed += size; - if (processedSize) - *processedSize = realProcessed; - return S_OK; - // return E_FAIL; - } - - unsigned fullIndex = m_StartIndex + m_CurrentIndex; - m_RemainFileSize = m_Database->GetFileSize(fullIndex); - UInt64 fileOffset = m_Database->GetFileOffset(fullIndex); - if (fileOffset < m_PosInSection) - return E_FAIL; - - if (fileOffset > m_PosInSection) - { - UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size)); - realProcessed += numBytesToWrite; - if (processedSize) - *processedSize = realProcessed; - data = (const void *)((const Byte *)data + numBytesToWrite); - size -= numBytesToWrite; - m_PosInSection += numBytesToWrite; - m_PosInFolder += numBytesToWrite; - } - - if (fileOffset == m_PosInSection) - { - RINOK(OpenFile()) - m_FileIsOpen = true; - m_CurrentIndex++; - m_IsOk = true; - } - } - } - - return WriteEmptyFiles(); -} - -Z7_COM7F_IMF(CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - return Write2(data, size, processedSize, true); -} - -HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize) -{ - const UInt32 kBufferSize = (1 << 10); - Byte buffer[kBufferSize]; - for (unsigned i = 0; i < kBufferSize; i++) - buffer[i] = 0; - if (maxSize > m_FolderSize) - maxSize = m_FolderSize; - while (m_PosInFolder < maxSize) - { - UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize); - UInt32 processedSizeLocal = 0; - RINOK(Write2(buffer, size, &processedSizeLocal, false)) - if (processedSizeLocal == 0) - return S_OK; - } - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testModeSpec, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - - if (allFilesMode) - numItems = m_Database.NewFormat ? 1: - (m_Database.LowLevel ? - m_Database.Items.Size(): - m_Database.Indices.Size()); - if (numItems == 0) - return S_OK; - const bool testMode = (testModeSpec != 0); - - UInt64 currentTotalSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create inStream; - inStream->SetStream(m_Stream); - - UInt32 i; - - if (m_Database.LowLevel) - { - UInt64 currentItemSize = 0; - UInt64 totalSize = 0; - - if (m_Database.NewFormat) - totalSize = m_Database.NewFormatString.Len(); - else - for (i = 0; i < numItems; i++) - totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size; - - RINOK(extractCallback->SetTotal(totalSize)) - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - currentItemSize = 0; - lps->InSize = currentTotalSize; // Change it - lps->OutSize = currentTotalSize; - - RINOK(lps->SetCur()) - CMyComPtr realOutStream; - const Int32 askMode= testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (m_Database.NewFormat) - { - if (index != 0) - return E_FAIL; - if (!testMode && !realOutStream) - continue; - if (!testMode) - { - const unsigned size = m_Database.NewFormatString.Len(); - RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size)) - } - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const CItem &item = m_Database.Items[index]; - - currentItemSize = item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - if (item.Section != 0) - { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - continue; - } - - if (testMode) - { - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - RINOK(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset)) - inStream->Init(item.Size); - - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult((copyCoder->TotalSize == item.Size) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)) - } - return S_OK; - } - - UInt64 lastFolderIndex = (UInt64)0 - 1; - - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = m_Database.Items[m_Database.Indices[index]]; - const UInt64 sectionIndex = item.Section; - if (item.IsDir() || item.Size == 0) - continue; - if (sectionIndex == 0) - { - currentTotalSize += item.Size; - continue; - } - - if (sectionIndex >= m_Database.Sections.Size()) - continue; - - const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; - if (section.IsLzx()) - { - const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; - UInt64 folderIndex = m_Database.GetFolder(index); - if (lastFolderIndex == folderIndex) - folderIndex++; - lastFolderIndex = m_Database.GetLastFolder(index); - for (; folderIndex <= lastFolderIndex; folderIndex++) - currentTotalSize += lzxInfo.GetFolderSize(); - } - } - - RINOK(extractCallback->SetTotal(currentTotalSize)) - - CMyUniquePtr lzxDecoder; - CMyComPtr2_Create chmFolderOutStream; - - currentTotalSize = 0; - - CRecordVector extractStatuses; - - CByteBuffer packBuf; - - for (i = 0;;) - { - RINOK(extractCallback->SetCompleted(¤tTotalSize)) - - if (i >= numItems) - break; - - UInt32 index = allFilesMode ? i : indices[i]; - i++; - const CItem &item = m_Database.Items[m_Database.Indices[index]]; - const UInt64 sectionIndex = item.Section; - const Int32 askMode= testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - if (item.IsDir()) - { - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - lps->InSize = currentTotalSize; // Change it - lps->OutSize = currentTotalSize; - - if (item.Size == 0 || sectionIndex == 0) - { - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - Int32 opRes = NExtract::NOperationResult::kOK; - if (!testMode && item.Size != 0) - { - RINOK(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset)) - inStream->Init(item.Size); - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != item.Size) - opRes = NExtract::NOperationResult::kDataError; - } - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)) - currentTotalSize += item.Size; - continue; - } - - if (sectionIndex >= m_Database.Sections.Size()) - { - // we must report error here; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)) - continue; - } - - const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; - - if (!section.IsLzx()) - { - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - continue; - } - - const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; - - chmFolderOutStream->Init(&m_Database, extractCallback, testMode); - - lzxDecoder.Create_if_Empty(); - - UInt64 folderIndex = m_Database.GetFolder(index); - - const UInt64 compressedPos = m_Database.ContentOffset + section.Offset; - RINOK(lzxDecoder->Set_DictBits_and_Alloc(lzxInfo.GetNumDictBits())) - - const CItem *lastItem = &item; - extractStatuses.Clear(); - extractStatuses.Add(true); - - for (;; folderIndex++) - { - RINOK(extractCallback->SetCompleted(¤tTotalSize)) - - const UInt64 startPos = lzxInfo.GetFolderPos(folderIndex); - UInt64 finishPos = lastItem->Offset + lastItem->Size; - const UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos); - - lastFolderIndex = m_Database.GetLastFolder(index); - const UInt64 folderSize = lzxInfo.GetFolderSize(); - UInt64 unPackSize = folderSize; - - if (extractStatuses.IsEmpty()) - chmFolderOutStream->m_StartIndex = index + 1; - else - chmFolderOutStream->m_StartIndex = index; - - if (limitFolderIndex == folderIndex) - { - for (; i < numItems; i++) - { - const UInt32 nextIndex = allFilesMode ? i : indices[i]; - const CItem &nextItem = m_Database.Items[m_Database.Indices[nextIndex]]; - if (nextItem.Section != sectionIndex) - break; - const UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex); - if (nextFolderIndex != folderIndex) - break; - for (index++; index < nextIndex; index++) - extractStatuses.Add(false); - extractStatuses.Add(true); - index = nextIndex; - lastItem = &nextItem; - if (nextItem.Size != 0) - finishPos = nextItem.Offset + nextItem.Size; - lastFolderIndex = m_Database.GetLastFolder(index); - } - } - - unPackSize = MyMin(finishPos - startPos, unPackSize); - - chmFolderOutStream->m_FolderSize = folderSize; - chmFolderOutStream->m_PosInFolder = 0; - chmFolderOutStream->m_PosInSection = startPos; - chmFolderOutStream->m_ExtractStatuses = &extractStatuses; - chmFolderOutStream->m_NumFiles = extractStatuses.Size(); - chmFolderOutStream->m_CurrentIndex = 0; - - try - { - const UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex); - const CResetTable &rt = lzxInfo.ResetTable; - const UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize); - - for (UInt32 b = 0; b < numBlocks; b++) - { - UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos; - RINOK(extractCallback->SetCompleted(&completedSize)) - UInt64 bCur = startBlock + b; - if (bCur >= rt.ResetOffsets.Size()) - return E_FAIL; - const UInt64 offset = rt.ResetOffsets[(unsigned)bCur]; - UInt64 compressedSize; - rt.GetCompressedSizeOfBlock(bCur, compressedSize); - - // chm writes full blocks. So we don't need to use reduced size for last block - - RINOK(InStream_SeekSet(m_Stream, compressedPos + offset)) - inStream->Init(compressedSize); - - lzxDecoder->Set_KeepHistory(b > 0); - - HRESULT res = S_FALSE; - if (compressedSize <= (1u << 30)) - { - const unsigned kAdditionalInputSize = 32; - const size_t compressedSizeT = (size_t)compressedSize; - const size_t allocSize = compressedSizeT + kAdditionalInputSize; - if (allocSize <= compressedSize) - throw 2; - packBuf.AllocAtLeast(allocSize); - res = ReadStream_FALSE(inStream, packBuf, compressedSizeT); - if (res == S_OK) - { - memset(packBuf + compressedSizeT, 0xff, kAdditionalInputSize); - lzxDecoder->Set_KeepHistoryForNext(true); - res = lzxDecoder->Code_WithExceedReadWrite(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize; - if (res == S_OK) - res = WriteStream(chmFolderOutStream, - lzxDecoder->GetUnpackData(), - lzxDecoder->GetUnpackSize()); - } - } - - if (res != S_OK) - { - if (res != S_FALSE) - return res; - throw 1; - } - } - } - catch(...) - { - RINOK(chmFolderOutStream->FlushCorrupted(unPackSize)) - } - - currentTotalSize += folderSize; - if (folderIndex == lastFolderIndex) - break; - extractStatuses.Clear(); - } - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = m_Database.NewFormat ? 1: - (m_Database.LowLevel ? - m_Database.Items.Size(): - m_Database.Indices.Size()); - return S_OK; -} - -namespace NChm { - -static const Byte k_Signature[] = { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 }; - -REGISTER_ARC_I_CLS( - CHandler(false), - "Chm", "chm chi chq chw", NULL, 0xE9, - k_Signature, - 0, - 0, - NULL) - -} - -namespace NHxs { - -static const Byte k_Signature[] = { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 }; - -REGISTER_ARC_I_CLS( - CHandler(true), - "Hxs", "hxs hxi hxr hxq hxw lit", NULL, 0xCE, - k_Signature, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -} - -}} +// ChmHandler.cpp + +#include "StdAfx.h" + +#include "../../../Common/AutoPtr.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" +#include "../../Common/RegisterArc.h" + +#include "../../Compress/CopyCoder.h" +#include "../../Compress/LzxDecoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "ChmHandler.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NChm { + +// #define CHM_DETAILS + +#ifdef CHM_DETAILS + +enum +{ + kpidSection = kpidUserDefined +}; + +#endif + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidMethod, + kpidBlock + + #ifdef CHM_DETAILS + , + L"Section", kpidSection, + kpidOffset + #endif +}; + +/* +static const Byte kArcProps[] = +{ + // kpidNumBlocks, +}; +*/ + +IMP_IInArchive_Props + +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + // COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + /* + case kpidNumBlocks: + { + UInt64 numBlocks = 0; + FOR_VECTOR(i, m_Database.Sections) + { + const CSectionInfo &s = m_Database.Sections[i]; + FOR_VECTOR(j, s.Methods) + { + const CMethodInfo &m = s.Methods[j]; + if (m.IsLzx()) + numBlocks += m.LzxInfo.ResetTable.GetNumBlocks(); + } + } + prop = numBlocks; + break; + } + */ + case kpidOffset: prop = m_Database.StartPosition; break; + case kpidPhySize: prop = m_Database.PhySize; break; + + case kpidErrorFlags: prop = m_ErrorFlags; break; + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + if (m_Database.NewFormat) + { + switch (propID) + { + case kpidSize: + prop = (UInt64)m_Database.NewFormatString.Len(); + break; + } + prop.Detach(value); + return S_OK; + } + + unsigned entryIndex; + if (m_Database.LowLevel) + entryIndex = index; + else + entryIndex = m_Database.Indices[index]; + + const CItem &item = m_Database.Items[entryIndex]; + + switch (propID) + { + case kpidPath: + { + UString us; + // if ( + ConvertUTF8ToUnicode(item.Name, us); + { + if (!m_Database.LowLevel) + { + if (us.Len() > 1 && us[0] == L'/') + us.Delete(0); + } + NItemName::ReplaceToOsSlashes_Remove_TailSlash(us); + prop = us; + } + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = item.Size; break; + case kpidMethod: + { + if (!item.IsDir()) + { + if (item.Section == 0) + prop = "Copy"; + else if (item.Section < m_Database.Sections.Size()) + prop = m_Database.Sections[(unsigned)item.Section].GetMethodName(); + } + break; + } + case kpidBlock: + if (m_Database.LowLevel) + prop = item.Section; + else if (item.Section != 0 && item.Section < m_Database.Sections.Size()) + prop = m_Database.GetFolder(index); + break; + + #ifdef CHM_DETAILS + + case kpidSection: prop = (UInt32)item.Section; break; + case kpidOffset: prop = (UInt32)item.Offset; break; + + #endif + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + try + { + CInArchive archive(_help2); + // CProgressImp progressImp(openArchiveCallback); + const HRESULT res = archive.Open(inStream, maxCheckStartPosition, m_Database); + if (!archive.IsArc) m_ErrorFlags |= kpv_ErrorFlags_IsNotArc; + if (archive.HeadersError) m_ErrorFlags |= kpv_ErrorFlags_HeadersError; + if (archive.UnexpectedEnd) m_ErrorFlags |= kpv_ErrorFlags_UnexpectedEnd; + if (archive.UnsupportedFeature) m_ErrorFlags |= kpv_ErrorFlags_UnsupportedFeature; + + RINOK(res) + /* + if (m_Database.LowLevel) + return S_FALSE; + */ + m_Stream = inStream; + } + catch(...) + { + return S_FALSE; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + m_ErrorFlags = 0; + m_Database.Clear(); + m_Stream.Release(); + return S_OK; +} + +Z7_CLASS_IMP_NOQIB_1( + CChmFolderOutStream + , ISequentialOutStream +) + bool m_TestMode; + bool m_IsOk; + bool m_FileIsOpen; + const CFilesDatabase *m_Database; + CMyComPtr m_ExtractCallback; + CMyComPtr m_RealOutStream; + UInt64 m_RemainFileSize; + + HRESULT OpenFile(); + HRESULT WriteEmptyFiles(); + HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); +public: + + UInt64 m_FolderSize; + UInt64 m_PosInFolder; + UInt64 m_PosInSection; + const CRecordVector *m_ExtractStatuses; + unsigned m_StartIndex; + unsigned m_CurrentIndex; + unsigned m_NumFiles; + + void Init( + const CFilesDatabase *database, + IArchiveExtractCallback *extractCallback, + bool testMode); + HRESULT FlushCorrupted(UInt64 maxSize); +}; + +void CChmFolderOutStream::Init( + const CFilesDatabase *database, + IArchiveExtractCallback *extractCallback, + bool testMode) +{ + m_Database = database; + m_ExtractCallback = extractCallback; + m_TestMode = testMode; + + m_CurrentIndex = 0; + m_FileIsOpen = false; +} + +HRESULT CChmFolderOutStream::OpenFile() +{ + Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? m_TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract : + NExtract::NAskMode::kSkip; + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)) + if (!m_RealOutStream && !m_TestMode) + askMode = NExtract::NAskMode::kSkip; + return m_ExtractCallback->PrepareOperation(askMode); +} + +HRESULT CChmFolderOutStream::WriteEmptyFiles() +{ + if (m_FileIsOpen) + return S_OK; + for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++) + { + const UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex); + if (fileSize != 0) + return S_OK; + const HRESULT result = OpenFile(); + m_RealOutStream.Release(); + RINOK(result) + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + return S_OK; +} + +// This is WritePart function +HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) +{ + UInt32 realProcessed = 0; + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (m_FileIsOpen) + { + UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size)); + HRESULT res = S_OK; + if (numBytesToWrite > 0) + { + if (!isOK) + m_IsOk = false; + if (m_RealOutStream) + { + UInt32 processedSizeLocal = 0; + res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); + numBytesToWrite = processedSizeLocal; + } + } + realProcessed += numBytesToWrite; + if (processedSize) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_RemainFileSize -= numBytesToWrite; + m_PosInSection += numBytesToWrite; + m_PosInFolder += numBytesToWrite; + if (res != S_OK) + return res; + if (m_RemainFileSize == 0) + { + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->SetOperationResult( + m_IsOk ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)) + m_FileIsOpen = false; + } + if (realProcessed > 0) + break; // with this break this function works as write part + } + else + { + if (m_CurrentIndex >= m_NumFiles) + { + realProcessed += size; + if (processedSize) + *processedSize = realProcessed; + return S_OK; + // return E_FAIL; + } + + unsigned fullIndex = m_StartIndex + m_CurrentIndex; + m_RemainFileSize = m_Database->GetFileSize(fullIndex); + UInt64 fileOffset = m_Database->GetFileOffset(fullIndex); + if (fileOffset < m_PosInSection) + return E_FAIL; + + if (fileOffset > m_PosInSection) + { + UInt32 numBytesToWrite = (UInt32)MyMin(fileOffset - m_PosInSection, UInt64(size)); + realProcessed += numBytesToWrite; + if (processedSize) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_PosInSection += numBytesToWrite; + m_PosInFolder += numBytesToWrite; + } + + if (fileOffset == m_PosInSection) + { + RINOK(OpenFile()) + m_FileIsOpen = true; + m_CurrentIndex++; + m_IsOk = true; + } + } + } + + return WriteEmptyFiles(); +} + +Z7_COM7F_IMF(CChmFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + return Write2(data, size, processedSize, true); +} + +HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize) +{ + const UInt32 kBufferSize = (1 << 10); + Byte buffer[kBufferSize]; + for (unsigned i = 0; i < kBufferSize; i++) + buffer[i] = 0; + if (maxSize > m_FolderSize) + maxSize = m_FolderSize; + while (m_PosInFolder < maxSize) + { + UInt32 size = (UInt32)MyMin(maxSize - m_PosInFolder, (UInt64)kBufferSize); + UInt32 processedSizeLocal = 0; + RINOK(Write2(buffer, size, &processedSizeLocal, false)) + if (processedSizeLocal == 0) + return S_OK; + } + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + + if (allFilesMode) + numItems = m_Database.NewFormat ? 1: + (m_Database.LowLevel ? + m_Database.Items.Size(): + m_Database.Indices.Size()); + if (numItems == 0) + return S_OK; + const bool testMode = (testModeSpec != 0); + + UInt64 currentTotalSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create inStream; + inStream->SetStream(m_Stream); + + UInt32 i; + + if (m_Database.LowLevel) + { + UInt64 currentItemSize = 0; + UInt64 totalSize = 0; + + if (m_Database.NewFormat) + totalSize = m_Database.NewFormatString.Len(); + else + for (i = 0; i < numItems; i++) + totalSize += m_Database.Items[allFilesMode ? i : indices[i]].Size; + + RINOK(extractCallback->SetTotal(totalSize)) + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + currentItemSize = 0; + lps->InSize = currentTotalSize; // Change it + lps->OutSize = currentTotalSize; + + RINOK(lps->SetCur()) + CMyComPtr realOutStream; + const Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (m_Database.NewFormat) + { + if (index != 0) + return E_FAIL; + if (!testMode && !realOutStream) + continue; + if (!testMode) + { + const unsigned size = m_Database.NewFormatString.Len(); + RINOK(WriteStream(realOutStream, (const char *)m_Database.NewFormatString, size)) + } + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const CItem &item = m_Database.Items[index]; + + currentItemSize = item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + if (item.Section != 0) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + continue; + } + + if (testMode) + { + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + RINOK(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset)) + inStream->Init(item.Size); + + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult((copyCoder->TotalSize == item.Size) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)) + } + return S_OK; + } + + UInt64 lastFolderIndex = (UInt64)0 - 1; + + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = m_Database.Items[m_Database.Indices[index]]; + const UInt64 sectionIndex = item.Section; + if (item.IsDir() || item.Size == 0) + continue; + if (sectionIndex == 0) + { + currentTotalSize += item.Size; + continue; + } + + if (sectionIndex >= m_Database.Sections.Size()) + continue; + + const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; + if (section.IsLzx()) + { + const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; + UInt64 folderIndex = m_Database.GetFolder(index); + if (lastFolderIndex == folderIndex) + folderIndex++; + lastFolderIndex = m_Database.GetLastFolder(index); + for (; folderIndex <= lastFolderIndex; folderIndex++) + currentTotalSize += lzxInfo.GetFolderSize(); + } + } + + RINOK(extractCallback->SetTotal(currentTotalSize)) + + CMyUniquePtr lzxDecoder; + CMyComPtr2_Create chmFolderOutStream; + + currentTotalSize = 0; + + CRecordVector extractStatuses; + + CByteBuffer packBuf; + + for (i = 0;;) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)) + + if (i >= numItems) + break; + + UInt32 index = allFilesMode ? i : indices[i]; + i++; + const CItem &item = m_Database.Items[m_Database.Indices[index]]; + const UInt64 sectionIndex = item.Section; + const Int32 askMode= testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + if (item.IsDir()) + { + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + lps->InSize = currentTotalSize; // Change it + lps->OutSize = currentTotalSize; + + if (item.Size == 0 || sectionIndex == 0) + { + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + Int32 opRes = NExtract::NOperationResult::kOK; + if (!testMode && item.Size != 0) + { + RINOK(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset)) + inStream->Init(item.Size); + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != item.Size) + opRes = NExtract::NOperationResult::kDataError; + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)) + currentTotalSize += item.Size; + continue; + } + + if (sectionIndex >= m_Database.Sections.Size()) + { + // we must report error here; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError)) + continue; + } + + const CSectionInfo §ion = m_Database.Sections[(unsigned)sectionIndex]; + + if (!section.IsLzx()) + { + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + continue; + } + + const CLzxInfo &lzxInfo = section.Methods[0].LzxInfo; + + chmFolderOutStream->Init(&m_Database, extractCallback, testMode); + + lzxDecoder.Create_if_Empty(); + + UInt64 folderIndex = m_Database.GetFolder(index); + + const UInt64 compressedPos = m_Database.ContentOffset + section.Offset; + RINOK(lzxDecoder->Set_DictBits_and_Alloc(lzxInfo.GetNumDictBits())) + + const CItem *lastItem = &item; + extractStatuses.Clear(); + extractStatuses.Add(true); + + for (;; folderIndex++) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)) + + const UInt64 startPos = lzxInfo.GetFolderPos(folderIndex); + UInt64 finishPos = lastItem->Offset + lastItem->Size; + const UInt64 limitFolderIndex = lzxInfo.GetFolder(finishPos); + + lastFolderIndex = m_Database.GetLastFolder(index); + const UInt64 folderSize = lzxInfo.GetFolderSize(); + UInt64 unPackSize = folderSize; + + if (extractStatuses.IsEmpty()) + chmFolderOutStream->m_StartIndex = index + 1; + else + chmFolderOutStream->m_StartIndex = index; + + if (limitFolderIndex == folderIndex) + { + for (; i < numItems; i++) + { + const UInt32 nextIndex = allFilesMode ? i : indices[i]; + const CItem &nextItem = m_Database.Items[m_Database.Indices[nextIndex]]; + if (nextItem.Section != sectionIndex) + break; + const UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex); + if (nextFolderIndex != folderIndex) + break; + for (index++; index < nextIndex; index++) + extractStatuses.Add(false); + extractStatuses.Add(true); + index = nextIndex; + lastItem = &nextItem; + if (nextItem.Size != 0) + finishPos = nextItem.Offset + nextItem.Size; + lastFolderIndex = m_Database.GetLastFolder(index); + } + } + + unPackSize = MyMin(finishPos - startPos, unPackSize); + + chmFolderOutStream->m_FolderSize = folderSize; + chmFolderOutStream->m_PosInFolder = 0; + chmFolderOutStream->m_PosInSection = startPos; + chmFolderOutStream->m_ExtractStatuses = &extractStatuses; + chmFolderOutStream->m_NumFiles = extractStatuses.Size(); + chmFolderOutStream->m_CurrentIndex = 0; + + try + { + const UInt64 startBlock = lzxInfo.GetBlockIndexFromFolderIndex(folderIndex); + const CResetTable &rt = lzxInfo.ResetTable; + const UInt32 numBlocks = (UInt32)rt.GetNumBlocks(unPackSize); + + for (UInt32 b = 0; b < numBlocks; b++) + { + UInt64 completedSize = currentTotalSize + chmFolderOutStream->m_PosInSection - startPos; + RINOK(extractCallback->SetCompleted(&completedSize)) + UInt64 bCur = startBlock + b; + if (bCur >= rt.ResetOffsets.Size()) + return E_FAIL; + const UInt64 offset = rt.ResetOffsets[(unsigned)bCur]; + UInt64 compressedSize; + rt.GetCompressedSizeOfBlock(bCur, compressedSize); + + // chm writes full blocks. So we don't need to use reduced size for last block + + RINOK(InStream_SeekSet(m_Stream, compressedPos + offset)) + inStream->Init(compressedSize); + + lzxDecoder->Set_KeepHistory(b > 0); + + HRESULT res = S_FALSE; + if (compressedSize <= (1u << 30)) + { + const unsigned kAdditionalInputSize = 32; + const size_t compressedSizeT = (size_t)compressedSize; + const size_t allocSize = compressedSizeT + kAdditionalInputSize; + if (allocSize <= compressedSize) + throw 2; + packBuf.AllocAtLeast(allocSize); + res = ReadStream_FALSE(inStream, packBuf, compressedSizeT); + if (res == S_OK) + { + memset(packBuf + compressedSizeT, 0xff, kAdditionalInputSize); + lzxDecoder->Set_KeepHistoryForNext(true); + res = lzxDecoder->Code_WithExceedReadWrite(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize; + if (res == S_OK) + res = WriteStream(chmFolderOutStream, + lzxDecoder->GetUnpackData(), + lzxDecoder->GetUnpackSize()); + } + } + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + throw 1; + } + } + } + catch(...) + { + RINOK(chmFolderOutStream->FlushCorrupted(unPackSize)) + } + + currentTotalSize += folderSize; + if (folderIndex == lastFolderIndex) + break; + extractStatuses.Clear(); + } + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = m_Database.NewFormat ? 1: + (m_Database.LowLevel ? + m_Database.Items.Size(): + m_Database.Indices.Size()); + return S_OK; +} + +namespace NChm { + +static const Byte k_Signature[] = { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 }; + +REGISTER_ARC_I_CLS( + CHandler(false), + "Chm", "chm chi chq chw", NULL, 0xE9, + k_Signature, + 0, + 0, + NULL) + +} + +namespace NHxs { + +static const Byte k_Signature[] = { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 }; + +REGISTER_ARC_I_CLS( + CHandler(true), + "Hxs", "hxs hxi hxr hxq hxw lit", NULL, 0xCE, + k_Signature, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +} + +}} diff --git a/CPP/7zip/Archive/Chm/ChmHandler.h b/CPP/7zip/Archive/Chm/ChmHandler.h index b67a8342b..94821b211 100644 --- a/CPP/7zip/Archive/Chm/ChmHandler.h +++ b/CPP/7zip/Archive/Chm/ChmHandler.h @@ -1,27 +1,27 @@ -// ChmHandler.h - -#ifndef ZIP7_INC_ARCHIVE_CHM_HANDLER_H -#define ZIP7_INC_ARCHIVE_CHM_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "ChmIn.h" - -namespace NArchive { -namespace NChm { - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - CFilesDatabase m_Database; - CMyComPtr m_Stream; - bool _help2; - UInt32 m_ErrorFlags; -public: - CHandler(bool help2): _help2(help2) {} -}; - -}} - -#endif +// ChmHandler.h + +#ifndef ZIP7_INC_ARCHIVE_CHM_HANDLER_H +#define ZIP7_INC_ARCHIVE_CHM_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "ChmIn.h" + +namespace NArchive { +namespace NChm { + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + CFilesDatabase m_Database; + CMyComPtr m_Stream; + bool _help2; + UInt32 m_ErrorFlags; +public: + CHandler(bool help2): _help2(help2) {} +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp index f973c73cc..086606236 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.cpp +++ b/CPP/7zip/Archive/Chm/ChmIn.cpp @@ -1,1026 +1,1026 @@ -// Archive/ChmIn.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/UTFConvert.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/StreamUtils.h" - -#include "ChmIn.h" - -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -namespace NArchive { -namespace NChm { - -static const UInt32 kSignature_ITSP = 0x50535449; -static const UInt32 kSignature_PMGL = 0x4C474D50; -static const UInt32 kSignature_LZXC = 0x43585A4C; - -static const UInt32 kSignature_IFCM = 0x4D434649; -static const UInt32 kSignature_AOLL = 0x4C4C4F41; -static const UInt32 kSignature_CAOL = 0x4C4F4143; - -static const UInt32 kSignature_ITSF = 0x46535449; -static const UInt32 kSignature_ITOL = 0x4C4F5449; -static const UInt32 kSignature_ITLS = 0x534C5449; - -struct CEnexpectedEndException {}; -struct CHeaderErrorException {}; - -// define CHM_LOW, if you want to see low level items -// #define CHM_LOW - -static const Byte kChmLzxGuid[16] = { 0x40, 0x89, 0xC2, 0x7F, 0x31, 0x9D, 0xD0, 0x11, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C }; -static const Byte kHelp2LzxGuid[16] = { 0xC6, 0x07, 0x90, 0x0A, 0x76, 0x40, 0xD3, 0x11, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 }; -static const Byte kDesGuid[16] = { 0xA2, 0xE4, 0xF6, 0x67, 0xBF, 0x60, 0xD3, 0x11, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF }; - -static bool inline AreGuidsEqual(const Byte *g1, const Byte *g2) -{ - return memcmp(g1, g2, 16) == 0; -} - -static void PrintByte(unsigned b, AString &s) -{ - s += (char)GET_HEX_CHAR_UPPER(b >> 4); - s += (char)GET_HEX_CHAR_LOWER(b & 0xF); -} - -AString CMethodInfo::GetGuidString() const -{ - char s[16 * 2 + 8]; - RawLeGuidToString_Braced(Guid, s); - // MyStringUpper_Ascii(s); - return (AString)s; -} - -bool CMethodInfo::IsLzx() const -{ - if (AreGuidsEqual(Guid, kChmLzxGuid)) - return true; - return AreGuidsEqual(Guid, kHelp2LzxGuid); -} - -bool CMethodInfo::IsDes() const -{ - return AreGuidsEqual(Guid, kDesGuid); -} - -AString CMethodInfo::GetName() const -{ - AString s; - if (IsLzx()) - { - s = "LZX:"; - s.Add_UInt32(LzxInfo.GetNumDictBits()); - } - else - { - if (IsDes()) - s = "DES"; - else - { - s = GetGuidString(); - /* - if (ControlData.Size() > 0 && ControlData.Size() <= (1 << 6)) - { - s.Add_Colon(); - for (size_t i = 0; i < ControlData.Size(); i++) - PrintByte(ControlData[i], s); - } - */ - } - } - return s; -} - -bool CSectionInfo::IsLzx() const -{ - if (Methods.Size() != 1) - return false; - return Methods[0].IsLzx(); -} - -UString CSectionInfo::GetMethodName() const -{ - UString s; - if (!IsLzx()) - { - UString temp; - ConvertUTF8ToUnicode(Name, temp); - s += temp; - s += ": "; - } - FOR_VECTOR (i, Methods) - { - if (i != 0) - s.Add_Space(); - s += Methods[i].GetName(); - } - return s; -} - -Byte CInArchive::ReadByte() -{ - Byte b; - if (!_inBuffer.ReadByte(b)) - throw CEnexpectedEndException(); - return b; -} - -void CInArchive::Skip(size_t size) -{ - if (_inBuffer.Skip(size) != size) - throw CEnexpectedEndException(); -} - -void CInArchive::ReadBytes(Byte *data, UInt32 size) -{ - if (_inBuffer.ReadBytes(data, size) != size) - throw CEnexpectedEndException(); -} - -UInt16 CInArchive::ReadUInt16() -{ - Byte b0, b1; - if (!_inBuffer.ReadByte(b0)) throw CEnexpectedEndException(); - if (!_inBuffer.ReadByte(b1)) throw CEnexpectedEndException(); - return (UInt16)(((UInt16)b1 << 8) | b0); -} - -UInt32 CInArchive::ReadUInt32() -{ - Byte p[4]; - ReadBytes(p, 4); - return Get32(p); -} - -UInt64 CInArchive::ReadUInt64() -{ - Byte p[8]; - ReadBytes(p, 8); - return Get64(p); -} - -UInt64 CInArchive::ReadEncInt() -{ - UInt64 val = 0; - for (int i = 0; i < 9; i++) - { - const unsigned b = ReadByte(); - val |= (b & 0x7F); - if (b < 0x80) - return val; - val <<= 7; - } - throw CHeaderErrorException(); -} - -void CInArchive::ReadGUID(Byte *g) -{ - ReadBytes(g, 16); -} - -void CInArchive::ReadString(unsigned size, AString &s) -{ - s.Empty(); - if (size != 0) - { - ReadBytes((Byte *)s.GetBuf(size), size); - s.ReleaseBuf_CalcLen(size); - } -} - -void CInArchive::ReadUString(unsigned size, UString &s) -{ - s.Empty(); - while (size-- != 0) - { - const wchar_t c = ReadUInt16(); - if (c == 0) - { - Skip(2 * size); - return; - } - s += c; - } -} - -HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size) -{ - RINOK(InStream_SeekSet(inStream, pos)) - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr limitedStream(streamSpec); - streamSpec->SetStream(inStream); - streamSpec->Init(size); - m_InStreamRef = limitedStream; - _inBuffer.SetStream(limitedStream); - _inBuffer.Init(); - return S_OK; -} - -HRESULT CInArchive::ReadDirEntry(CDatabase &database) -{ - CItem item; - const UInt64 nameLen = ReadEncInt(); - if (nameLen == 0 || nameLen > (1 << 13)) - return S_FALSE; - ReadString((unsigned)nameLen, item.Name); - item.Section = ReadEncInt(); - item.Offset = ReadEncInt(); - item.Size = ReadEncInt(); - database.Items.Add(item); - return S_OK; -} - -HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) -{ - UInt32 headerSize = ReadUInt32(); - if (headerSize != 0x60) - return S_FALSE; - database.PhySize = headerSize; - - UInt32 unknown1 = ReadUInt32(); - if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file - return S_FALSE; - - IsArc = true; - - /* UInt32 timeStamp = */ ReadUInt32(); - // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and - // fractional seconds (second byte). - // The third and fourth bytes may contain even more fractional bits. - // The 4 least significant bits in the last byte are constant. - /* UInt32 lang = */ ReadUInt32(); - Byte g[16]; - ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} - ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} - const unsigned kNumSections = 2; - UInt64 sectionOffsets[kNumSections]; - UInt64 sectionSizes[kNumSections]; - unsigned i; - for (i = 0; i < kNumSections; i++) - { - sectionOffsets[i] = ReadUInt64(); - sectionSizes[i] = ReadUInt64(); - UInt64 end = sectionOffsets[i] + sectionSizes[i]; - database.UpdatePhySize(end); - } - // if (chmVersion == 3) - database.ContentOffset = ReadUInt64(); - /* - else - database.ContentOffset = database.StartPosition + 0x58 - */ - - // Section 0 - ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]); - if (sectionSizes[0] < 0x18) - return S_FALSE; - if (ReadUInt32() != 0x01FE) - return S_FALSE; - ReadUInt32(); // unknown: 0 - UInt64 fileSize = ReadUInt64(); - database.UpdatePhySize(fileSize); - ReadUInt32(); // unknown: 0 - ReadUInt32(); // unknown: 0 - - // Section 1: The Directory Listing - ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]); - if (ReadUInt32() != kSignature_ITSP) - return S_FALSE; - if (ReadUInt32() != 1) // version - return S_FALSE; - /* UInt32 dirHeaderSize = */ ReadUInt32(); - ReadUInt32(); // 0x0A (unknown) - UInt32 dirChunkSize = ReadUInt32(); // $1000 - if (dirChunkSize < 32) - return S_FALSE; - /* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2. - /* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index, - // 2 if there is one level of PMGI chunks. - - /* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none - // (though at least one file has 0 despite there being no - // index chunk, probably a bug.) - /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk - /* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk - ReadUInt32(); // -1 (unknown) - UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total) - /* UInt32 windowsLangId = */ ReadUInt32(); - ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC} - ReadUInt32(); // 0x54 (This is the length again) - ReadUInt32(); // -1 (unknown) - ReadUInt32(); // -1 (unknown) - ReadUInt32(); // -1 (unknown) - - for (UInt32 ci = 0; ci < numDirChunks; ci++) - { - UInt64 chunkPos = _inBuffer.GetProcessedSize(); - if (ReadUInt32() == kSignature_PMGL) - { - // The quickref area is written backwards from the end of the chunk. - // One quickref entry exists for every n entries in the file, where n - // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5. - - const UInt32 quickrefLength = ReadUInt32(); // Len of free space and/or quickref area at end of directory chunk - if (quickrefLength > dirChunkSize || quickrefLength < 2) - return S_FALSE; - ReadUInt32(); // Always 0 - ReadUInt32(); // Chunk number of previous listing chunk when reading - // directory in sequence (-1 if this is the first listing chunk) - ReadUInt32(); // Chunk number of next listing chunk when reading - // directory in sequence (-1 if this is the last listing chunk) - unsigned numItems = 0; - - for (;;) - { - const UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; - const UInt32 offsetLimit = dirChunkSize - quickrefLength; - if (offset > offsetLimit) - return S_FALSE; - if (offset == offsetLimit) - break; - RINOK(ReadDirEntry(database)) - numItems++; - } - - Skip(quickrefLength - 2); - - const unsigned rrr = ReadUInt16(); - if (rrr != numItems) - { - // Lazarus 9-26-2 chm contains 0 here. - if (rrr != 0) - return S_FALSE; - } - } - else - Skip(dirChunkSize - 4); - } - return S_OK; -} - -HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) -{ - if (ReadUInt32() != 1) // version - return S_FALSE; - if (ReadUInt32() != 0x28) // Location of header section table - return S_FALSE; - UInt32 numHeaderSections = ReadUInt32(); - const unsigned kNumHeaderSectionsMax = 5; - if (numHeaderSections != kNumHeaderSectionsMax) - return S_FALSE; - - IsArc = true; - - ReadUInt32(); // Len of post-header table - Byte g[16]; - ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} - - // header section table - UInt64 sectionOffsets[kNumHeaderSectionsMax]; - UInt64 sectionSizes[kNumHeaderSectionsMax]; - UInt32 i; - for (i = 0; i < numHeaderSections; i++) - { - sectionOffsets[i] = ReadUInt64(); - sectionSizes[i] = ReadUInt64(); - UInt64 end = sectionOffsets[i] + sectionSizes[i]; - database.UpdatePhySize(end); - } - - // Post-Header - ReadUInt32(); // 2 - ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header) - // ----- Directory information - ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1 - ReadUInt64(); // Chunk number of first AOLL chunk in directory - ReadUInt64(); // Chunk number of last AOLL chunk in directory - ReadUInt64(); // 0 (unknown) - ReadUInt32(); // $2000 (Directory chunk size of directory) - ReadUInt32(); // Quickref density for main directory, usually 2 - ReadUInt32(); // 0 (unknown) - ReadUInt32(); // Depth of main directory index tree - // 1 there is no index, 2 if there is one level of AOLI chunks. - ReadUInt64(); // 0 (unknown) - UInt64 numDirEntries = ReadUInt64(); // Number of directory entries - // ----- Directory Index Information - ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index) - ReadUInt64(); // Chunk number of first AOLL chunk in directory index - ReadUInt64(); // Chunk number of last AOLL chunk in directory index - ReadUInt64(); // 0 (unknown) - ReadUInt32(); // $200 (Directory chunk size of directory index) - ReadUInt32(); // Quickref density for directory index, usually 2 - ReadUInt32(); // 0 (unknown) - ReadUInt32(); // Depth of directory index index tree. - ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0. - ReadUInt64(); // Number of directory index entries (same as number of AOLL - // chunks in main directory) - - // (The obvious guess for the following two fields, which recur in a number - // of places, is they are maximum sizes for the directory and directory index. - // However, I have seen no direct evidence that this is the case.) - - ReadUInt32(); // $100000 (Same as field following chunk size in directory) - ReadUInt32(); // $20000 (Same as field following chunk size in directory index) - - ReadUInt64(); // 0 (unknown) - if (ReadUInt32() != kSignature_CAOL) - return S_FALSE; - if (ReadUInt32() != 2) // (Most likely a version number) - return S_FALSE; - UInt32 caolLength = ReadUInt32(); // $50 (Len of the CAOL section, which includes the ITSF section) - if (caolLength >= 0x2C) - { - /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built. - // Does not appear to be a checksum. Many files have - // 'HH' (HTML Help?) here, indicating this may be a compiler ID - // field. But at least one ITOL/ITLS compiler does not set this - // field to a constant value. - ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field) - ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0. - ReadUInt32(); // $2000 (Directory chunk size of directory) - ReadUInt32(); // $200 (Directory chunk size of directory index) - ReadUInt32(); // $100000 (Same as field following chunk size in directory) - ReadUInt32(); // $20000 (Same as field following chunk size in directory index) - ReadUInt32(); // 0 (unknown) - ReadUInt32(); // 0 (Unknown) - if (caolLength == 0x2C) - { - // fprintf(stdout, "\n !!!NewFormat\n"); - // fflush(stdout); - database.ContentOffset = 0; // maybe we must add database.StartPosition here? - database.NewFormat = true; - } - else if (caolLength == 0x50) - { - ReadUInt32(); // 0 (Unknown) - if (ReadUInt32() != kSignature_ITSF) - return S_FALSE; - if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3) - return S_FALSE; - if (ReadUInt32() != 0x20) // $20 (length of ITSF) - return S_FALSE; - UInt32 unknown = ReadUInt32(); - if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases; - return S_FALSE; - database.ContentOffset = database.StartPosition + ReadUInt64(); - /* UInt32 timeStamp = */ ReadUInt32(); - // A timestamp of some sort. - // Considered as a big-endian DWORD, it appears to contain - // seconds (MSB) and fractional seconds (second byte). - // The third and fourth bytes may contain even more fractional - // bits. The 4 least significant bits in the last byte are constant. - /* UInt32 lang = */ ReadUInt32(); // BE? - } - else - return S_FALSE; - } - - // Section 0 - ReadChunk(inStream, database.StartPosition + sectionOffsets[0], sectionSizes[0]); - if (sectionSizes[0] < 0x18) - return S_FALSE; - if (ReadUInt32() != 0x01FE) - return S_FALSE; - ReadUInt32(); // unknown: 0 - UInt64 fileSize = ReadUInt64(); - database.UpdatePhySize(fileSize); - ReadUInt32(); // unknown: 0 - ReadUInt32(); // unknown: 0 - - // Section 1: The Directory Listing - ReadChunk(inStream, database.StartPosition + sectionOffsets[1], sectionSizes[1]); - if (ReadUInt32() != kSignature_IFCM) - return S_FALSE; - if (ReadUInt32() != 1) // (probably a version number) - return S_FALSE; - UInt32 dirChunkSize = ReadUInt32(); // $2000 - if (dirChunkSize < 64) - return S_FALSE; - ReadUInt32(); // $100000 (unknown) - ReadUInt32(); // -1 (unknown) - ReadUInt32(); // -1 (unknown) - UInt32 numDirChunks = ReadUInt32(); - ReadUInt32(); // 0 (unknown, probably high word of above) - - for (UInt32 ci = 0; ci < numDirChunks; ci++) - { - UInt64 chunkPos = _inBuffer.GetProcessedSize(); - if (ReadUInt32() == kSignature_AOLL) - { - UInt32 quickrefLength = ReadUInt32(); // Len of quickref area at end of directory chunk - if (quickrefLength > dirChunkSize || quickrefLength < 2) - return S_FALSE; - ReadUInt64(); // Directory chunk number - // This must match physical position in file, that is - // the chunk size times the chunk number must be the - // offset from the end of the directory header. - ReadUInt64(); // Chunk number of previous listing chunk when reading - // directory in sequence (-1 if first listing chunk) - ReadUInt64(); // Chunk number of next listing chunk when reading - // directory in sequence (-1 if last listing chunk) - ReadUInt64(); // Number of first listing entry in this chunk - ReadUInt32(); // 1 (unknown -- other values have also been seen here) - ReadUInt32(); // 0 (unknown) - - unsigned numItems = 0; - for (;;) - { - const UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; - const UInt32 offsetLimit = dirChunkSize - quickrefLength; - if (offset > offsetLimit) - return S_FALSE; - if (offset == offsetLimit) - break; - if (database.NewFormat) - { - const unsigned nameLen = ReadUInt16(); - if (nameLen == 0) - return S_FALSE; - UString name; - ReadUString(nameLen, name); - AString s; - ConvertUnicodeToUTF8(name, s); - { - const unsigned b = ReadByte(); - s.Add_Space(); - PrintByte(b, s); - } - s.Add_Space(); - UInt64 len = ReadEncInt(); - // then number of items ? - // then length ? - // then some data (binary encoding?) - if (len > 1u << 29) // what limit here we need? - return S_FALSE; - if (len) - do - { - const unsigned b = ReadByte(); - PrintByte(b, s); - } - while (--len); - database.NewFormatString += s; - database.NewFormatString += "\r\n"; - } - else - { - RINOK(ReadDirEntry(database)) - } - numItems++; - } - Skip(quickrefLength - 2); - if (ReadUInt16() != numItems) - return S_FALSE; - if (numItems > numDirEntries) - return S_FALSE; - numDirEntries -= numItems; - } - else - Skip(dirChunkSize - 4); - } - return numDirEntries == 0 ? S_OK : S_FALSE; -} - -HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name) -{ - int index = database.FindItem(name); - if (index < 0) - return S_FALSE; - const CItem &item = database.Items[index]; - _chunkSize = item.Size; - return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size); -} - - -#define DATA_SPACE "::DataSpace/" -#define kNameList DATA_SPACE "NameList" -#define kStorage DATA_SPACE "Storage/" -#define kContent "Content" -#define kControlData "ControlData" -#define kSpanInfo "SpanInfo" -#define kTransform "Transform/" -#define kResetTable "/InstanceData/ResetTable" -#define kTransformList "List" - -static AString GetSectionPrefix(const AString &name) -{ - AString s (kStorage); - s += name; - s.Add_Slash(); - return s; -} - -#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } - -static int CompareFiles(const unsigned *p1, const unsigned *p2, void *param) -{ - const CObjectVector &items = *(const CObjectVector *)param; - const CItem &item1 = items[*p1]; - const CItem &item2 = items[*p2]; - bool isDir1 = item1.IsDir(); - bool isDir2 = item2.IsDir(); - if (isDir1 && !isDir2) - return -1; - if (isDir2) - { - if (!isDir1) - return 1; - } - else - { - RINOZ(MyCompare(item1.Section, item2.Section)) - RINOZ(MyCompare(item1.Offset, item2.Offset)) - RINOZ(MyCompare(item1.Size, item2.Size)) - } - return MyCompare(*p1, *p2); -} - -void CFilesDatabase::SetIndices() -{ - FOR_VECTOR (i, Items) - { - const CItem &item = Items[i]; - if (item.IsUserItem() && item.Name.Len() != 1) - Indices.Add(i); - } -} - -void CFilesDatabase::Sort() -{ - Indices.Sort(CompareFiles, (void *)&Items); -} - -bool CFilesDatabase::Check() -{ - UInt64 maxPos = 0; - UInt64 prevSection = 0; - FOR_VECTOR (i, Indices) - { - const CItem &item = Items[Indices[i]]; - if (item.Section == 0 || item.IsDir()) - continue; - if (item.Section != prevSection) - { - prevSection = item.Section; - maxPos = 0; - continue; - } - if (item.Offset < maxPos) - return false; - maxPos = item.Offset + item.Size; - if (maxPos < item.Offset) - return false; - } - return true; -} - -bool CFilesDatabase::CheckSectionRefs() -{ - FOR_VECTOR (i, Indices) - { - const CItem &item = Items[Indices[i]]; - if (item.Section == 0 || item.IsDir()) - continue; - if (item.Section >= Sections.Size()) - return false; - } - return true; -} - -static int inline GetLog(UInt32 num) -{ - for (int i = 0; i < 32; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - -HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) -{ - { - // The NameList file - RINOK(DecompressStream(inStream, database, (AString)kNameList)) - /* UInt16 length = */ ReadUInt16(); - UInt16 numSections = ReadUInt16(); - for (unsigned i = 0; i < numSections; i++) - { - CSectionInfo section; - const unsigned nameLen = ReadUInt16(); - UString name; - ReadUString(nameLen, name); - if (ReadUInt16() != 0) - return S_FALSE; - ConvertUnicodeToUTF8(name, section.Name); - // if (!ConvertUnicodeToUTF8(name, section.Name)) return S_FALSE; - database.Sections.Add(section); - } - } - - unsigned si; - for (si = 1; si < database.Sections.Size(); si++) - { - CSectionInfo §ion = database.Sections[si]; - AString sectionPrefix (GetSectionPrefix(section.Name)); - { - // Content - int index = database.FindItem(sectionPrefix + kContent); - if (index < 0) - return S_FALSE; - const CItem &item = database.Items[index]; - section.Offset = item.Offset; - section.CompressedSize = item.Size; - } - AString transformPrefix (sectionPrefix + kTransform); - if (database.Help2Format) - { - // Transform List - RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList)) - if ((_chunkSize & 0xF) != 0) - return S_FALSE; - unsigned numGuids = (unsigned)(_chunkSize / 0x10); - if (numGuids < 1) - return S_FALSE; - for (unsigned i = 0; i < numGuids; i++) - { - CMethodInfo method; - ReadGUID(method.Guid); - section.Methods.Add(method); - } - } - else - { - CMethodInfo method; - memcpy(method.Guid, kChmLzxGuid, 16); - section.Methods.Add(method); - } - - { - // Control Data - RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData)) - - FOR_VECTOR (mi, section.Methods) - { - CMethodInfo &method = section.Methods[mi]; - UInt32 numDWORDS = ReadUInt32(); - if (method.IsLzx()) - { - if (numDWORDS < 5) - return S_FALSE; - if (ReadUInt32() != kSignature_LZXC) - return S_FALSE; - CLzxInfo &li = method.LzxInfo; - li.Version = ReadUInt32(); - if (li.Version != 2 && li.Version != 3) - return S_FALSE; - - { - // There is bug in VC6, if we use function call as parameter for inline function - const UInt32 val32 = ReadUInt32(); - const int n = GetLog(val32); - if (n < 0 || n > 16) - return S_FALSE; - li.ResetIntervalBits = (unsigned)n; - } - - { - const UInt32 val32 = ReadUInt32(); - const int n = GetLog(val32); - if (n < 0 || n > 16) - return S_FALSE; - li.WindowSizeBits = (unsigned)n; - } - - li.CacheSize = ReadUInt32(); - numDWORDS -= 5; - if (numDWORDS) - do - ReadUInt32(); - while (--numDWORDS); - } - else - { - if (numDWORDS > 1u << 27) - return S_FALSE; - const size_t numBytes = (size_t)numDWORDS * 4; - // method.ControlData.Alloc(numBytes); - // ReadBytes(method.ControlData, numBytes); - Skip(numBytes); - } - } - } - - { - // SpanInfo - RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo)) - section.UncompressedSize = ReadUInt64(); - } - - // read ResetTable for LZX - FOR_VECTOR (mi, section.Methods) - { - CMethodInfo &method = section.Methods[mi]; - if (method.IsLzx()) - { - // ResetTable; - RINOK(DecompressStream(inStream, database, transformPrefix + - method.GetGuidString() + kResetTable)) - CResetTable &rt = method.LzxInfo.ResetTable; - - if (_chunkSize < 4) - { - if (_chunkSize != 0) - return S_FALSE; - // ResetTable is empty in .chw files - if (section.UncompressedSize != 0) - return S_FALSE; - rt.UncompressedSize = 0; - rt.CompressedSize = 0; - // rt.BlockSize = 0; - } - else - { - const UInt32 ver = ReadUInt32(); // 2 unknown (possibly a version number) - if (ver != 2 && ver != 3) - return S_FALSE; - const UInt32 numEntries = ReadUInt32(); - const unsigned kEntrySize = 8; - if (ReadUInt32() != kEntrySize) - return S_FALSE; - const unsigned kRtHeaderSize = 4 * 4 + 8 * 3; - if (ReadUInt32() != kRtHeaderSize) - return S_FALSE; - if (kRtHeaderSize + kEntrySize * (UInt64)numEntries != _chunkSize) - return S_FALSE; - - rt.UncompressedSize = ReadUInt64(); - rt.CompressedSize = ReadUInt64(); - UInt64 blockSize = ReadUInt64(); - if (blockSize != kBlockSize) - return S_FALSE; - UInt64 numBlocks = (rt.UncompressedSize + kBlockSize + 1) / kBlockSize; - if (numEntries != numBlocks && - numEntries != numBlocks + 1) - return S_FALSE; - - rt.ResetOffsets.ClearAndReserve(numEntries); - - for (UInt32 i = 0; i < numEntries; i++) - { - UInt64 v = ReadUInt64(); - if (i != 0 && v < rt.ResetOffsets[i - 1]) - return S_FALSE; - rt.ResetOffsets.AddInReserved(v); - } - - if (numEntries != 0) - if (rt.ResetOffsets[0] != 0) - return S_FALSE; - - if (numEntries == numBlocks + 1) - { - // Lazarus 9-26-2 chm contains additional entty - if (rt.ResetOffsets.Back() != rt.CompressedSize) - return S_FALSE; - } - } - } - } - } - - database.SetIndices(); - database.Sort(); - return database.Check() ? S_OK : S_FALSE; -} - -HRESULT CInArchive::Open2(IInStream *inStream, - const UInt64 *searchHeaderSizeLimit, - CFilesDatabase &database) -{ - IsArc = false; - HeadersError = false; - UnexpectedEnd = false; - UnsupportedFeature = false; - - database.Clear(); - database.Help2Format = _help2; - const UInt32 chmVersion = 3; - - RINOK(InStream_GetPos(inStream, database.StartPosition)) - - if (!_inBuffer.Create(1 << 14)) - return E_OUTOFMEMORY; - _inBuffer.SetStream(inStream); - _inBuffer.Init(); - - if (_help2) - { - const unsigned kSignatureSize = 8; - const UInt64 signature = ((UInt64)kSignature_ITLS << 32) | kSignature_ITOL; - UInt64 limit = 1 << 18; - - if (searchHeaderSizeLimit) - if (limit > *searchHeaderSizeLimit) - limit = *searchHeaderSizeLimit; - - UInt64 val = 0; - - for (;;) - { - Byte b; - if (!_inBuffer.ReadByte(b)) - return S_FALSE; - val >>= 8; - val |= ((UInt64)b) << ((kSignatureSize - 1) * 8); - if (_inBuffer.GetProcessedSize() >= kSignatureSize) - { - if (val == signature) - break; - if (_inBuffer.GetProcessedSize() > limit) - return S_FALSE; - } - } - - database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize; - RINOK(OpenHelp2(inStream, database)) - if (database.NewFormat) - return S_OK; - } - else - { - if (ReadUInt32() != kSignature_ITSF) - return S_FALSE; - if (ReadUInt32() != chmVersion) - return S_FALSE; - RINOK(OpenChm(inStream, database)) - } - - - #ifndef CHM_LOW - - try - { - try - { - HRESULT res = OpenHighLevel(inStream, database); - if (res == S_FALSE) - { - UnsupportedFeature = true; - database.HighLevelClear(); - return S_OK; - } - RINOK(res) - if (!database.CheckSectionRefs()) - HeadersError = true; - database.LowLevel = false; - } - catch(...) - { - database.HighLevelClear(); - throw; - } - } - // catch(const CInBufferException &e) { return e.ErrorCode; } - catch(CEnexpectedEndException &) { UnexpectedEnd = true; } - catch(CHeaderErrorException &) { HeadersError = true; } - catch(...) { throw; } - - #endif - - return S_OK; -} - -HRESULT CInArchive::Open(IInStream *inStream, - const UInt64 *searchHeaderSizeLimit, - CFilesDatabase &database) -{ - try - { - try - { - HRESULT res = Open2(inStream, searchHeaderSizeLimit, database); - m_InStreamRef.Release(); - return res; - } - catch(...) - { - m_InStreamRef.Release(); - throw; - } - } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(CEnexpectedEndException &) { UnexpectedEnd = true; } - catch(CHeaderErrorException &) { HeadersError = true; } - return S_FALSE; -} - -}} +// Archive/ChmIn.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/UTFConvert.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamUtils.h" + +#include "ChmIn.h" + +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +namespace NArchive { +namespace NChm { + +static const UInt32 kSignature_ITSP = 0x50535449; +static const UInt32 kSignature_PMGL = 0x4C474D50; +static const UInt32 kSignature_LZXC = 0x43585A4C; + +static const UInt32 kSignature_IFCM = 0x4D434649; +static const UInt32 kSignature_AOLL = 0x4C4C4F41; +static const UInt32 kSignature_CAOL = 0x4C4F4143; + +static const UInt32 kSignature_ITSF = 0x46535449; +static const UInt32 kSignature_ITOL = 0x4C4F5449; +static const UInt32 kSignature_ITLS = 0x534C5449; + +struct CEnexpectedEndException {}; +struct CHeaderErrorException {}; + +// define CHM_LOW, if you want to see low level items +// #define CHM_LOW + +static const Byte kChmLzxGuid[16] = { 0x40, 0x89, 0xC2, 0x7F, 0x31, 0x9D, 0xD0, 0x11, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C }; +static const Byte kHelp2LzxGuid[16] = { 0xC6, 0x07, 0x90, 0x0A, 0x76, 0x40, 0xD3, 0x11, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 }; +static const Byte kDesGuid[16] = { 0xA2, 0xE4, 0xF6, 0x67, 0xBF, 0x60, 0xD3, 0x11, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF }; + +static bool inline AreGuidsEqual(const Byte *g1, const Byte *g2) +{ + return memcmp(g1, g2, 16) == 0; +} + +static void PrintByte(unsigned b, AString &s) +{ + s += (char)GET_HEX_CHAR_UPPER(b >> 4); + s += (char)GET_HEX_CHAR_LOWER(b & 0xF); +} + +AString CMethodInfo::GetGuidString() const +{ + char s[16 * 2 + 8]; + RawLeGuidToString_Braced(Guid, s); + // MyStringUpper_Ascii(s); + return (AString)s; +} + +bool CMethodInfo::IsLzx() const +{ + if (AreGuidsEqual(Guid, kChmLzxGuid)) + return true; + return AreGuidsEqual(Guid, kHelp2LzxGuid); +} + +bool CMethodInfo::IsDes() const +{ + return AreGuidsEqual(Guid, kDesGuid); +} + +AString CMethodInfo::GetName() const +{ + AString s; + if (IsLzx()) + { + s = "LZX:"; + s.Add_UInt32(LzxInfo.GetNumDictBits()); + } + else + { + if (IsDes()) + s = "DES"; + else + { + s = GetGuidString(); + /* + if (ControlData.Size() > 0 && ControlData.Size() <= (1 << 6)) + { + s.Add_Colon(); + for (size_t i = 0; i < ControlData.Size(); i++) + PrintByte(ControlData[i], s); + } + */ + } + } + return s; +} + +bool CSectionInfo::IsLzx() const +{ + if (Methods.Size() != 1) + return false; + return Methods[0].IsLzx(); +} + +UString CSectionInfo::GetMethodName() const +{ + UString s; + if (!IsLzx()) + { + UString temp; + ConvertUTF8ToUnicode(Name, temp); + s += temp; + s += ": "; + } + FOR_VECTOR (i, Methods) + { + if (i != 0) + s.Add_Space(); + s += Methods[i].GetName(); + } + return s; +} + +Byte CInArchive::ReadByte() +{ + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CEnexpectedEndException(); + return b; +} + +void CInArchive::Skip(size_t size) +{ + if (_inBuffer.Skip(size) != size) + throw CEnexpectedEndException(); +} + +void CInArchive::ReadBytes(Byte *data, UInt32 size) +{ + if (_inBuffer.ReadBytes(data, size) != size) + throw CEnexpectedEndException(); +} + +UInt16 CInArchive::ReadUInt16() +{ + Byte b0, b1; + if (!_inBuffer.ReadByte(b0)) throw CEnexpectedEndException(); + if (!_inBuffer.ReadByte(b1)) throw CEnexpectedEndException(); + return (UInt16)(((UInt16)b1 << 8) | b0); +} + +UInt32 CInArchive::ReadUInt32() +{ + Byte p[4]; + ReadBytes(p, 4); + return Get32(p); +} + +UInt64 CInArchive::ReadUInt64() +{ + Byte p[8]; + ReadBytes(p, 8); + return Get64(p); +} + +UInt64 CInArchive::ReadEncInt() +{ + UInt64 val = 0; + for (int i = 0; i < 9; i++) + { + const unsigned b = ReadByte(); + val |= (b & 0x7F); + if (b < 0x80) + return val; + val <<= 7; + } + throw CHeaderErrorException(); +} + +void CInArchive::ReadGUID(Byte *g) +{ + ReadBytes(g, 16); +} + +void CInArchive::ReadString(unsigned size, AString &s) +{ + s.Empty(); + if (size != 0) + { + ReadBytes((Byte *)s.GetBuf(size), size); + s.ReleaseBuf_CalcLen(size); + } +} + +void CInArchive::ReadUString(unsigned size, UString &s) +{ + s.Empty(); + while (size-- != 0) + { + const wchar_t c = ReadUInt16(); + if (c == 0) + { + Skip(2 * size); + return; + } + s += c; + } +} + +HRESULT CInArchive::ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size) +{ + RINOK(InStream_SeekSet(inStream, pos)) + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr limitedStream(streamSpec); + streamSpec->SetStream(inStream); + streamSpec->Init(size); + m_InStreamRef = limitedStream; + _inBuffer.SetStream(limitedStream); + _inBuffer.Init(); + return S_OK; +} + +HRESULT CInArchive::ReadDirEntry(CDatabase &database) +{ + CItem item; + const UInt64 nameLen = ReadEncInt(); + if (nameLen == 0 || nameLen > (1 << 13)) + return S_FALSE; + ReadString((unsigned)nameLen, item.Name); + item.Section = ReadEncInt(); + item.Offset = ReadEncInt(); + item.Size = ReadEncInt(); + database.Items.Add(item); + return S_OK; +} + +HRESULT CInArchive::OpenChm(IInStream *inStream, CDatabase &database) +{ + UInt32 headerSize = ReadUInt32(); + if (headerSize != 0x60) + return S_FALSE; + database.PhySize = headerSize; + + UInt32 unknown1 = ReadUInt32(); + if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file + return S_FALSE; + + IsArc = true; + + /* UInt32 timeStamp = */ ReadUInt32(); + // Considered as a big-endian DWORD, it appears to contain seconds (MSB) and + // fractional seconds (second byte). + // The third and fourth bytes may contain even more fractional bits. + // The 4 least significant bits in the last byte are constant. + /* UInt32 lang = */ ReadUInt32(); + Byte g[16]; + ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} + ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} + const unsigned kNumSections = 2; + UInt64 sectionOffsets[kNumSections]; + UInt64 sectionSizes[kNumSections]; + unsigned i; + for (i = 0; i < kNumSections; i++) + { + sectionOffsets[i] = ReadUInt64(); + sectionSizes[i] = ReadUInt64(); + UInt64 end = sectionOffsets[i] + sectionSizes[i]; + database.UpdatePhySize(end); + } + // if (chmVersion == 3) + database.ContentOffset = ReadUInt64(); + /* + else + database.ContentOffset = database.StartPosition + 0x58 + */ + + // Section 0 + ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]); + if (sectionSizes[0] < 0x18) + return S_FALSE; + if (ReadUInt32() != 0x01FE) + return S_FALSE; + ReadUInt32(); // unknown: 0 + UInt64 fileSize = ReadUInt64(); + database.UpdatePhySize(fileSize); + ReadUInt32(); // unknown: 0 + ReadUInt32(); // unknown: 0 + + // Section 1: The Directory Listing + ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]); + if (ReadUInt32() != kSignature_ITSP) + return S_FALSE; + if (ReadUInt32() != 1) // version + return S_FALSE; + /* UInt32 dirHeaderSize = */ ReadUInt32(); + ReadUInt32(); // 0x0A (unknown) + UInt32 dirChunkSize = ReadUInt32(); // $1000 + if (dirChunkSize < 32) + return S_FALSE; + /* UInt32 density = */ ReadUInt32(); // "Density" of quickref section, usually 2. + /* UInt32 depth = */ ReadUInt32(); // Depth of the index tree: 1 there is no index, + // 2 if there is one level of PMGI chunks. + + /* UInt32 chunkNumber = */ ReadUInt32(); // Chunk number of root index chunk, -1 if there is none + // (though at least one file has 0 despite there being no + // index chunk, probably a bug.) + /* UInt32 firstPmglChunkNumber = */ ReadUInt32(); // Chunk number of first PMGL (listing) chunk + /* UInt32 lastPmglChunkNumber = */ ReadUInt32(); // Chunk number of last PMGL (listing) chunk + ReadUInt32(); // -1 (unknown) + UInt32 numDirChunks = ReadUInt32(); // Number of directory chunks (total) + /* UInt32 windowsLangId = */ ReadUInt32(); + ReadGUID(g); // {5D02926A-212E-11D0-9DF9-00A0C922E6EC} + ReadUInt32(); // 0x54 (This is the length again) + ReadUInt32(); // -1 (unknown) + ReadUInt32(); // -1 (unknown) + ReadUInt32(); // -1 (unknown) + + for (UInt32 ci = 0; ci < numDirChunks; ci++) + { + UInt64 chunkPos = _inBuffer.GetProcessedSize(); + if (ReadUInt32() == kSignature_PMGL) + { + // The quickref area is written backwards from the end of the chunk. + // One quickref entry exists for every n entries in the file, where n + // is calculated as 1 + (1 << quickref density). So for density = 2, n = 5. + + const UInt32 quickrefLength = ReadUInt32(); // Len of free space and/or quickref area at end of directory chunk + if (quickrefLength > dirChunkSize || quickrefLength < 2) + return S_FALSE; + ReadUInt32(); // Always 0 + ReadUInt32(); // Chunk number of previous listing chunk when reading + // directory in sequence (-1 if this is the first listing chunk) + ReadUInt32(); // Chunk number of next listing chunk when reading + // directory in sequence (-1 if this is the last listing chunk) + unsigned numItems = 0; + + for (;;) + { + const UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; + const UInt32 offsetLimit = dirChunkSize - quickrefLength; + if (offset > offsetLimit) + return S_FALSE; + if (offset == offsetLimit) + break; + RINOK(ReadDirEntry(database)) + numItems++; + } + + Skip(quickrefLength - 2); + + const unsigned rrr = ReadUInt16(); + if (rrr != numItems) + { + // Lazarus 9-26-2 chm contains 0 here. + if (rrr != 0) + return S_FALSE; + } + } + else + Skip(dirChunkSize - 4); + } + return S_OK; +} + +HRESULT CInArchive::OpenHelp2(IInStream *inStream, CDatabase &database) +{ + if (ReadUInt32() != 1) // version + return S_FALSE; + if (ReadUInt32() != 0x28) // Location of header section table + return S_FALSE; + UInt32 numHeaderSections = ReadUInt32(); + const unsigned kNumHeaderSectionsMax = 5; + if (numHeaderSections != kNumHeaderSectionsMax) + return S_FALSE; + + IsArc = true; + + ReadUInt32(); // Len of post-header table + Byte g[16]; + ReadGUID(g); // {0A9007C1-4076-11D3-8789-0000F8105754} + + // header section table + UInt64 sectionOffsets[kNumHeaderSectionsMax]; + UInt64 sectionSizes[kNumHeaderSectionsMax]; + UInt32 i; + for (i = 0; i < numHeaderSections; i++) + { + sectionOffsets[i] = ReadUInt64(); + sectionSizes[i] = ReadUInt64(); + UInt64 end = sectionOffsets[i] + sectionSizes[i]; + database.UpdatePhySize(end); + } + + // Post-Header + ReadUInt32(); // 2 + ReadUInt32(); // 0x98: offset to CAOL from beginning of post-header) + // ----- Directory information + ReadUInt64(); // Chunk number of top-level AOLI chunk in directory, or -1 + ReadUInt64(); // Chunk number of first AOLL chunk in directory + ReadUInt64(); // Chunk number of last AOLL chunk in directory + ReadUInt64(); // 0 (unknown) + ReadUInt32(); // $2000 (Directory chunk size of directory) + ReadUInt32(); // Quickref density for main directory, usually 2 + ReadUInt32(); // 0 (unknown) + ReadUInt32(); // Depth of main directory index tree + // 1 there is no index, 2 if there is one level of AOLI chunks. + ReadUInt64(); // 0 (unknown) + UInt64 numDirEntries = ReadUInt64(); // Number of directory entries + // ----- Directory Index Information + ReadUInt64(); // -1 (unknown, probably chunk number of top-level AOLI in directory index) + ReadUInt64(); // Chunk number of first AOLL chunk in directory index + ReadUInt64(); // Chunk number of last AOLL chunk in directory index + ReadUInt64(); // 0 (unknown) + ReadUInt32(); // $200 (Directory chunk size of directory index) + ReadUInt32(); // Quickref density for directory index, usually 2 + ReadUInt32(); // 0 (unknown) + ReadUInt32(); // Depth of directory index index tree. + ReadUInt64(); // Possibly flags -- sometimes 1, sometimes 0. + ReadUInt64(); // Number of directory index entries (same as number of AOLL + // chunks in main directory) + + // (The obvious guess for the following two fields, which recur in a number + // of places, is they are maximum sizes for the directory and directory index. + // However, I have seen no direct evidence that this is the case.) + + ReadUInt32(); // $100000 (Same as field following chunk size in directory) + ReadUInt32(); // $20000 (Same as field following chunk size in directory index) + + ReadUInt64(); // 0 (unknown) + if (ReadUInt32() != kSignature_CAOL) + return S_FALSE; + if (ReadUInt32() != 2) // (Most likely a version number) + return S_FALSE; + UInt32 caolLength = ReadUInt32(); // $50 (Len of the CAOL section, which includes the ITSF section) + if (caolLength >= 0x2C) + { + /* UInt32 c7 = */ ReadUInt16(); // Unknown. Remains the same when identical files are built. + // Does not appear to be a checksum. Many files have + // 'HH' (HTML Help?) here, indicating this may be a compiler ID + // field. But at least one ITOL/ITLS compiler does not set this + // field to a constant value. + ReadUInt16(); // 0 (Unknown. Possibly part of 00A4 field) + ReadUInt32(); // Unknown. Two values have been seen -- $43ED, and 0. + ReadUInt32(); // $2000 (Directory chunk size of directory) + ReadUInt32(); // $200 (Directory chunk size of directory index) + ReadUInt32(); // $100000 (Same as field following chunk size in directory) + ReadUInt32(); // $20000 (Same as field following chunk size in directory index) + ReadUInt32(); // 0 (unknown) + ReadUInt32(); // 0 (Unknown) + if (caolLength == 0x2C) + { + // fprintf(stdout, "\n !!!NewFormat\n"); + // fflush(stdout); + database.ContentOffset = 0; // maybe we must add database.StartPosition here? + database.NewFormat = true; + } + else if (caolLength == 0x50) + { + ReadUInt32(); // 0 (Unknown) + if (ReadUInt32() != kSignature_ITSF) + return S_FALSE; + if (ReadUInt32() != 4) // $4 (Version number -- CHM uses 3) + return S_FALSE; + if (ReadUInt32() != 0x20) // $20 (length of ITSF) + return S_FALSE; + UInt32 unknown = ReadUInt32(); + if (unknown != 0 && unknown != 1) // = 0 for some HxW files, 1 in other cases; + return S_FALSE; + database.ContentOffset = database.StartPosition + ReadUInt64(); + /* UInt32 timeStamp = */ ReadUInt32(); + // A timestamp of some sort. + // Considered as a big-endian DWORD, it appears to contain + // seconds (MSB) and fractional seconds (second byte). + // The third and fourth bytes may contain even more fractional + // bits. The 4 least significant bits in the last byte are constant. + /* UInt32 lang = */ ReadUInt32(); // BE? + } + else + return S_FALSE; + } + + // Section 0 + ReadChunk(inStream, database.StartPosition + sectionOffsets[0], sectionSizes[0]); + if (sectionSizes[0] < 0x18) + return S_FALSE; + if (ReadUInt32() != 0x01FE) + return S_FALSE; + ReadUInt32(); // unknown: 0 + UInt64 fileSize = ReadUInt64(); + database.UpdatePhySize(fileSize); + ReadUInt32(); // unknown: 0 + ReadUInt32(); // unknown: 0 + + // Section 1: The Directory Listing + ReadChunk(inStream, database.StartPosition + sectionOffsets[1], sectionSizes[1]); + if (ReadUInt32() != kSignature_IFCM) + return S_FALSE; + if (ReadUInt32() != 1) // (probably a version number) + return S_FALSE; + UInt32 dirChunkSize = ReadUInt32(); // $2000 + if (dirChunkSize < 64) + return S_FALSE; + ReadUInt32(); // $100000 (unknown) + ReadUInt32(); // -1 (unknown) + ReadUInt32(); // -1 (unknown) + UInt32 numDirChunks = ReadUInt32(); + ReadUInt32(); // 0 (unknown, probably high word of above) + + for (UInt32 ci = 0; ci < numDirChunks; ci++) + { + UInt64 chunkPos = _inBuffer.GetProcessedSize(); + if (ReadUInt32() == kSignature_AOLL) + { + UInt32 quickrefLength = ReadUInt32(); // Len of quickref area at end of directory chunk + if (quickrefLength > dirChunkSize || quickrefLength < 2) + return S_FALSE; + ReadUInt64(); // Directory chunk number + // This must match physical position in file, that is + // the chunk size times the chunk number must be the + // offset from the end of the directory header. + ReadUInt64(); // Chunk number of previous listing chunk when reading + // directory in sequence (-1 if first listing chunk) + ReadUInt64(); // Chunk number of next listing chunk when reading + // directory in sequence (-1 if last listing chunk) + ReadUInt64(); // Number of first listing entry in this chunk + ReadUInt32(); // 1 (unknown -- other values have also been seen here) + ReadUInt32(); // 0 (unknown) + + unsigned numItems = 0; + for (;;) + { + const UInt64 offset = _inBuffer.GetProcessedSize() - chunkPos; + const UInt32 offsetLimit = dirChunkSize - quickrefLength; + if (offset > offsetLimit) + return S_FALSE; + if (offset == offsetLimit) + break; + if (database.NewFormat) + { + const unsigned nameLen = ReadUInt16(); + if (nameLen == 0) + return S_FALSE; + UString name; + ReadUString(nameLen, name); + AString s; + ConvertUnicodeToUTF8(name, s); + { + const unsigned b = ReadByte(); + s.Add_Space(); + PrintByte(b, s); + } + s.Add_Space(); + UInt64 len = ReadEncInt(); + // then number of items ? + // then length ? + // then some data (binary encoding?) + if (len > 1u << 29) // what limit here we need? + return S_FALSE; + if (len) + do + { + const unsigned b = ReadByte(); + PrintByte(b, s); + } + while (--len); + database.NewFormatString += s; + database.NewFormatString += "\r\n"; + } + else + { + RINOK(ReadDirEntry(database)) + } + numItems++; + } + Skip(quickrefLength - 2); + if (ReadUInt16() != numItems) + return S_FALSE; + if (numItems > numDirEntries) + return S_FALSE; + numDirEntries -= numItems; + } + else + Skip(dirChunkSize - 4); + } + return numDirEntries == 0 ? S_OK : S_FALSE; +} + +HRESULT CInArchive::DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name) +{ + int index = database.FindItem(name); + if (index < 0) + return S_FALSE; + const CItem &item = database.Items[index]; + _chunkSize = item.Size; + return ReadChunk(inStream, database.ContentOffset + item.Offset, item.Size); +} + + +#define DATA_SPACE "::DataSpace/" +#define kNameList DATA_SPACE "NameList" +#define kStorage DATA_SPACE "Storage/" +#define kContent "Content" +#define kControlData "ControlData" +#define kSpanInfo "SpanInfo" +#define kTransform "Transform/" +#define kResetTable "/InstanceData/ResetTable" +#define kTransformList "List" + +static AString GetSectionPrefix(const AString &name) +{ + AString s (kStorage); + s += name; + s.Add_Slash(); + return s; +} + +#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } + +static int CompareFiles(const unsigned *p1, const unsigned *p2, void *param) +{ + const CObjectVector &items = *(const CObjectVector *)param; + const CItem &item1 = items[*p1]; + const CItem &item2 = items[*p2]; + bool isDir1 = item1.IsDir(); + bool isDir2 = item2.IsDir(); + if (isDir1 && !isDir2) + return -1; + if (isDir2) + { + if (!isDir1) + return 1; + } + else + { + RINOZ(MyCompare(item1.Section, item2.Section)) + RINOZ(MyCompare(item1.Offset, item2.Offset)) + RINOZ(MyCompare(item1.Size, item2.Size)) + } + return MyCompare(*p1, *p2); +} + +void CFilesDatabase::SetIndices() +{ + FOR_VECTOR (i, Items) + { + const CItem &item = Items[i]; + if (item.IsUserItem() && item.Name.Len() != 1) + Indices.Add(i); + } +} + +void CFilesDatabase::Sort() +{ + Indices.Sort(CompareFiles, (void *)&Items); +} + +bool CFilesDatabase::Check() +{ + UInt64 maxPos = 0; + UInt64 prevSection = 0; + FOR_VECTOR (i, Indices) + { + const CItem &item = Items[Indices[i]]; + if (item.Section == 0 || item.IsDir()) + continue; + if (item.Section != prevSection) + { + prevSection = item.Section; + maxPos = 0; + continue; + } + if (item.Offset < maxPos) + return false; + maxPos = item.Offset + item.Size; + if (maxPos < item.Offset) + return false; + } + return true; +} + +bool CFilesDatabase::CheckSectionRefs() +{ + FOR_VECTOR (i, Indices) + { + const CItem &item = Items[Indices[i]]; + if (item.Section == 0 || item.IsDir()) + continue; + if (item.Section >= Sections.Size()) + return false; + } + return true; +} + +static int inline GetLog(UInt32 num) +{ + for (int i = 0; i < 32; i++) + if (((UInt32)1 << i) == num) + return i; + return -1; +} + +HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database) +{ + { + // The NameList file + RINOK(DecompressStream(inStream, database, (AString)kNameList)) + /* UInt16 length = */ ReadUInt16(); + UInt16 numSections = ReadUInt16(); + for (unsigned i = 0; i < numSections; i++) + { + CSectionInfo section; + const unsigned nameLen = ReadUInt16(); + UString name; + ReadUString(nameLen, name); + if (ReadUInt16() != 0) + return S_FALSE; + ConvertUnicodeToUTF8(name, section.Name); + // if (!ConvertUnicodeToUTF8(name, section.Name)) return S_FALSE; + database.Sections.Add(section); + } + } + + unsigned si; + for (si = 1; si < database.Sections.Size(); si++) + { + CSectionInfo §ion = database.Sections[si]; + AString sectionPrefix (GetSectionPrefix(section.Name)); + { + // Content + int index = database.FindItem(sectionPrefix + kContent); + if (index < 0) + return S_FALSE; + const CItem &item = database.Items[index]; + section.Offset = item.Offset; + section.CompressedSize = item.Size; + } + AString transformPrefix (sectionPrefix + kTransform); + if (database.Help2Format) + { + // Transform List + RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList)) + if ((_chunkSize & 0xF) != 0) + return S_FALSE; + unsigned numGuids = (unsigned)(_chunkSize / 0x10); + if (numGuids < 1) + return S_FALSE; + for (unsigned i = 0; i < numGuids; i++) + { + CMethodInfo method; + ReadGUID(method.Guid); + section.Methods.Add(method); + } + } + else + { + CMethodInfo method; + memcpy(method.Guid, kChmLzxGuid, 16); + section.Methods.Add(method); + } + + { + // Control Data + RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData)) + + FOR_VECTOR (mi, section.Methods) + { + CMethodInfo &method = section.Methods[mi]; + UInt32 numDWORDS = ReadUInt32(); + if (method.IsLzx()) + { + if (numDWORDS < 5) + return S_FALSE; + if (ReadUInt32() != kSignature_LZXC) + return S_FALSE; + CLzxInfo &li = method.LzxInfo; + li.Version = ReadUInt32(); + if (li.Version != 2 && li.Version != 3) + return S_FALSE; + + { + // There is bug in VC6, if we use function call as parameter for inline function + const UInt32 val32 = ReadUInt32(); + const int n = GetLog(val32); + if (n < 0 || n > 16) + return S_FALSE; + li.ResetIntervalBits = (unsigned)n; + } + + { + const UInt32 val32 = ReadUInt32(); + const int n = GetLog(val32); + if (n < 0 || n > 16) + return S_FALSE; + li.WindowSizeBits = (unsigned)n; + } + + li.CacheSize = ReadUInt32(); + numDWORDS -= 5; + if (numDWORDS) + do + ReadUInt32(); + while (--numDWORDS); + } + else + { + if (numDWORDS > 1u << 27) + return S_FALSE; + const size_t numBytes = (size_t)numDWORDS * 4; + // method.ControlData.Alloc(numBytes); + // ReadBytes(method.ControlData, numBytes); + Skip(numBytes); + } + } + } + + { + // SpanInfo + RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo)) + section.UncompressedSize = ReadUInt64(); + } + + // read ResetTable for LZX + FOR_VECTOR (mi, section.Methods) + { + CMethodInfo &method = section.Methods[mi]; + if (method.IsLzx()) + { + // ResetTable; + RINOK(DecompressStream(inStream, database, transformPrefix + + method.GetGuidString() + kResetTable)) + CResetTable &rt = method.LzxInfo.ResetTable; + + if (_chunkSize < 4) + { + if (_chunkSize != 0) + return S_FALSE; + // ResetTable is empty in .chw files + if (section.UncompressedSize != 0) + return S_FALSE; + rt.UncompressedSize = 0; + rt.CompressedSize = 0; + // rt.BlockSize = 0; + } + else + { + const UInt32 ver = ReadUInt32(); // 2 unknown (possibly a version number) + if (ver != 2 && ver != 3) + return S_FALSE; + const UInt32 numEntries = ReadUInt32(); + const unsigned kEntrySize = 8; + if (ReadUInt32() != kEntrySize) + return S_FALSE; + const unsigned kRtHeaderSize = 4 * 4 + 8 * 3; + if (ReadUInt32() != kRtHeaderSize) + return S_FALSE; + if (kRtHeaderSize + kEntrySize * (UInt64)numEntries != _chunkSize) + return S_FALSE; + + rt.UncompressedSize = ReadUInt64(); + rt.CompressedSize = ReadUInt64(); + UInt64 blockSize = ReadUInt64(); + if (blockSize != kBlockSize) + return S_FALSE; + UInt64 numBlocks = (rt.UncompressedSize + kBlockSize + 1) / kBlockSize; + if (numEntries != numBlocks && + numEntries != numBlocks + 1) + return S_FALSE; + + rt.ResetOffsets.ClearAndReserve(numEntries); + + for (UInt32 i = 0; i < numEntries; i++) + { + UInt64 v = ReadUInt64(); + if (i != 0 && v < rt.ResetOffsets[i - 1]) + return S_FALSE; + rt.ResetOffsets.AddInReserved(v); + } + + if (numEntries != 0) + if (rt.ResetOffsets[0] != 0) + return S_FALSE; + + if (numEntries == numBlocks + 1) + { + // Lazarus 9-26-2 chm contains additional entty + if (rt.ResetOffsets.Back() != rt.CompressedSize) + return S_FALSE; + } + } + } + } + } + + database.SetIndices(); + database.Sort(); + return database.Check() ? S_OK : S_FALSE; +} + +HRESULT CInArchive::Open2(IInStream *inStream, + const UInt64 *searchHeaderSizeLimit, + CFilesDatabase &database) +{ + IsArc = false; + HeadersError = false; + UnexpectedEnd = false; + UnsupportedFeature = false; + + database.Clear(); + database.Help2Format = _help2; + const UInt32 chmVersion = 3; + + RINOK(InStream_GetPos(inStream, database.StartPosition)) + + if (!_inBuffer.Create(1 << 14)) + return E_OUTOFMEMORY; + _inBuffer.SetStream(inStream); + _inBuffer.Init(); + + if (_help2) + { + const unsigned kSignatureSize = 8; + const UInt64 signature = ((UInt64)kSignature_ITLS << 32) | kSignature_ITOL; + UInt64 limit = 1 << 18; + + if (searchHeaderSizeLimit) + if (limit > *searchHeaderSizeLimit) + limit = *searchHeaderSizeLimit; + + UInt64 val = 0; + + for (;;) + { + Byte b; + if (!_inBuffer.ReadByte(b)) + return S_FALSE; + val >>= 8; + val |= ((UInt64)b) << ((kSignatureSize - 1) * 8); + if (_inBuffer.GetProcessedSize() >= kSignatureSize) + { + if (val == signature) + break; + if (_inBuffer.GetProcessedSize() > limit) + return S_FALSE; + } + } + + database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize; + RINOK(OpenHelp2(inStream, database)) + if (database.NewFormat) + return S_OK; + } + else + { + if (ReadUInt32() != kSignature_ITSF) + return S_FALSE; + if (ReadUInt32() != chmVersion) + return S_FALSE; + RINOK(OpenChm(inStream, database)) + } + + + #ifndef CHM_LOW + + try + { + try + { + HRESULT res = OpenHighLevel(inStream, database); + if (res == S_FALSE) + { + UnsupportedFeature = true; + database.HighLevelClear(); + return S_OK; + } + RINOK(res) + if (!database.CheckSectionRefs()) + HeadersError = true; + database.LowLevel = false; + } + catch(...) + { + database.HighLevelClear(); + throw; + } + } + // catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CEnexpectedEndException &) { UnexpectedEnd = true; } + catch(CHeaderErrorException &) { HeadersError = true; } + catch(...) { throw; } + + #endif + + return S_OK; +} + +HRESULT CInArchive::Open(IInStream *inStream, + const UInt64 *searchHeaderSizeLimit, + CFilesDatabase &database) +{ + try + { + try + { + HRESULT res = Open2(inStream, searchHeaderSizeLimit, database); + m_InStreamRef.Release(); + return res; + } + catch(...) + { + m_InStreamRef.Release(); + throw; + } + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CEnexpectedEndException &) { UnexpectedEnd = true; } + catch(CHeaderErrorException &) { HeadersError = true; } + return S_FALSE; +} + +}} diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h index 40c07948a..faf4edfd5 100644 --- a/CPP/7zip/Archive/Chm/ChmIn.h +++ b/CPP/7zip/Archive/Chm/ChmIn.h @@ -1,282 +1,282 @@ -// Archive/ChmIn.h - -#ifndef ZIP7_INC_ARCHIVE_CHM_IN_H -#define ZIP7_INC_ARCHIVE_CHM_IN_H - -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyString.h" - -#include "../../IStream.h" - -#include "../../Common/InBuffer.h" - -namespace NArchive { -namespace NChm { - -struct CItem -{ - UInt64 Section; - UInt64 Offset; - UInt64 Size; - AString Name; - - bool IsFormatRelatedItem() const - { - if (Name.Len() < 2) - return false; - return Name[0] == ':' && Name[1] == ':'; - } - - bool IsUserItem() const - { - if (Name.Len() < 2) - return false; - return Name[0] == '/'; - } - - bool IsDir() const - { - if (Name.IsEmpty()) - return false; - return (Name.Back() == '/'); - } -}; - - -struct CDatabase -{ - CObjectVector Items; - UInt64 StartPosition; - UInt64 ContentOffset; - AString NewFormatString; - bool Help2Format; - bool NewFormat; - UInt64 PhySize; - - void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; } - - int FindItem(const AString &name) const - { - FOR_VECTOR (i, Items) - if (Items[i].Name == name) - return (int)i; - return -1; - } - - void Clear() - { - NewFormat = false; - NewFormatString.Empty(); - Help2Format = false; - Items.Clear(); - StartPosition = 0; - PhySize = 0; - } -}; - - -const UInt32 kBlockSize = 1 << 15; - -struct CResetTable -{ - UInt64 UncompressedSize; - UInt64 CompressedSize; - // unsigned BlockSizeBits; - CRecordVector ResetOffsets; - - CResetTable(): - UncompressedSize(0), - CompressedSize(0) - {} - - bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const - { - if (blockIndex >= ResetOffsets.Size()) - return false; - UInt64 startPos = ResetOffsets[(unsigned)blockIndex]; - if (blockIndex + numBlocks >= ResetOffsets.Size()) - size = CompressedSize - startPos; - else - size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos; - return true; - } - - bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const - { - return GetCompressedSizeOfBlocks(blockIndex, 1, size); - } - - UInt64 GetNumBlocks(UInt64 size) const - { - return (size + kBlockSize - 1) / kBlockSize; - } -}; - - -struct CLzxInfo -{ - UInt32 Version; - - unsigned ResetIntervalBits; - unsigned WindowSizeBits; - UInt32 CacheSize; - - CResetTable ResetTable; - - CLzxInfo(): - Version(0), - ResetIntervalBits(0), - WindowSizeBits(0), - CacheSize(0) - {} - - unsigned GetNumDictBits() const - { - if (Version == 2 || Version == 3) - return 15 + WindowSizeBits; - return 0; - } - - UInt64 GetFolderSize() const { return (UInt64)kBlockSize << ResetIntervalBits; } - UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); } - UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); } - UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; } - - bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const - { - const UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); - if (blockIndex >= ResetTable.ResetOffsets.Size()) - return false; - offset = ResetTable.ResetOffsets[(unsigned)blockIndex]; - return true; - } - - bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const - { - UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); - return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size); - } -}; - - -struct CMethodInfo -{ - Byte Guid[16]; - // CByteBuffer ControlData; - CLzxInfo LzxInfo; - - bool IsLzx() const; - bool IsDes() const; - AString GetGuidString() const; - AString GetName() const; -}; - - -struct CSectionInfo -{ - UInt64 Offset; - UInt64 CompressedSize; - UInt64 UncompressedSize; - - AString Name; - CObjectVector Methods; - - bool IsLzx() const; - UString GetMethodName() const; -}; - -class CFilesDatabase: public CDatabase -{ -public: - CUIntVector Indices; - CObjectVector Sections; - bool LowLevel; - - UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; } - UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; } - - UInt64 GetFolder(unsigned fileIndex) const - { - const CItem &item = Items[Indices[fileIndex]]; - if (item.Section < Sections.Size()) - { - const CSectionInfo §ion = Sections[(unsigned)item.Section]; - if (section.IsLzx()) - return section.Methods[0].LzxInfo.GetFolder(item.Offset); - } - return 0; - } - - UInt64 GetLastFolder(unsigned fileIndex) const - { - const CItem &item = Items[Indices[fileIndex]]; - if (item.Section < Sections.Size()) - { - const CSectionInfo §ion = Sections[(unsigned)item.Section]; - if (section.IsLzx()) - return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1); - } - return 0; - } - - void HighLevelClear() - { - LowLevel = true; - Indices.Clear(); - Sections.Clear(); - } - - void Clear() - { - CDatabase::Clear(); - HighLevelClear(); - } - - void SetIndices(); - void Sort(); - bool Check(); - bool CheckSectionRefs(); -}; - - -class CInArchive -{ - CMyComPtr m_InStreamRef; - ::CInBuffer _inBuffer; - UInt64 _chunkSize; - bool _help2; - - Byte ReadByte(); - void ReadBytes(Byte *data, UInt32 size); - void Skip(size_t size); - UInt16 ReadUInt16(); - UInt32 ReadUInt32(); - UInt64 ReadUInt64(); - UInt64 ReadEncInt(); - void ReadString(unsigned size, AString &s); - void ReadUString(unsigned size, UString &s); - void ReadGUID(Byte *g); - - HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size); - - HRESULT ReadDirEntry(CDatabase &database); - HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name); - -public: - bool IsArc; - bool HeadersError; - bool UnexpectedEnd; - bool UnsupportedFeature; - - CInArchive(bool help2) { _help2 = help2; } - - HRESULT OpenChm(IInStream *inStream, CDatabase &database); - HRESULT OpenHelp2(IInStream *inStream, CDatabase &database); - HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database); - HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); - HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); -}; - -}} - -#endif +// Archive/ChmIn.h + +#ifndef ZIP7_INC_ARCHIVE_CHM_IN_H +#define ZIP7_INC_ARCHIVE_CHM_IN_H + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyString.h" + +#include "../../IStream.h" + +#include "../../Common/InBuffer.h" + +namespace NArchive { +namespace NChm { + +struct CItem +{ + UInt64 Section; + UInt64 Offset; + UInt64 Size; + AString Name; + + bool IsFormatRelatedItem() const + { + if (Name.Len() < 2) + return false; + return Name[0] == ':' && Name[1] == ':'; + } + + bool IsUserItem() const + { + if (Name.Len() < 2) + return false; + return Name[0] == '/'; + } + + bool IsDir() const + { + if (Name.IsEmpty()) + return false; + return (Name.Back() == '/'); + } +}; + + +struct CDatabase +{ + CObjectVector Items; + UInt64 StartPosition; + UInt64 ContentOffset; + AString NewFormatString; + bool Help2Format; + bool NewFormat; + UInt64 PhySize; + + void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; } + + int FindItem(const AString &name) const + { + FOR_VECTOR (i, Items) + if (Items[i].Name == name) + return (int)i; + return -1; + } + + void Clear() + { + NewFormat = false; + NewFormatString.Empty(); + Help2Format = false; + Items.Clear(); + StartPosition = 0; + PhySize = 0; + } +}; + + +const UInt32 kBlockSize = 1 << 15; + +struct CResetTable +{ + UInt64 UncompressedSize; + UInt64 CompressedSize; + // unsigned BlockSizeBits; + CRecordVector ResetOffsets; + + CResetTable(): + UncompressedSize(0), + CompressedSize(0) + {} + + bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const + { + if (blockIndex >= ResetOffsets.Size()) + return false; + UInt64 startPos = ResetOffsets[(unsigned)blockIndex]; + if (blockIndex + numBlocks >= ResetOffsets.Size()) + size = CompressedSize - startPos; + else + size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos; + return true; + } + + bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const + { + return GetCompressedSizeOfBlocks(blockIndex, 1, size); + } + + UInt64 GetNumBlocks(UInt64 size) const + { + return (size + kBlockSize - 1) / kBlockSize; + } +}; + + +struct CLzxInfo +{ + UInt32 Version; + + unsigned ResetIntervalBits; + unsigned WindowSizeBits; + UInt32 CacheSize; + + CResetTable ResetTable; + + CLzxInfo(): + Version(0), + ResetIntervalBits(0), + WindowSizeBits(0), + CacheSize(0) + {} + + unsigned GetNumDictBits() const + { + if (Version == 2 || Version == 3) + return 15 + WindowSizeBits; + return 0; + } + + UInt64 GetFolderSize() const { return (UInt64)kBlockSize << ResetIntervalBits; } + UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); } + UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); } + UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; } + + bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const + { + const UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); + if (blockIndex >= ResetTable.ResetOffsets.Size()) + return false; + offset = ResetTable.ResetOffsets[(unsigned)blockIndex]; + return true; + } + + bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const + { + UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); + return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size); + } +}; + + +struct CMethodInfo +{ + Byte Guid[16]; + // CByteBuffer ControlData; + CLzxInfo LzxInfo; + + bool IsLzx() const; + bool IsDes() const; + AString GetGuidString() const; + AString GetName() const; +}; + + +struct CSectionInfo +{ + UInt64 Offset; + UInt64 CompressedSize; + UInt64 UncompressedSize; + + AString Name; + CObjectVector Methods; + + bool IsLzx() const; + UString GetMethodName() const; +}; + +class CFilesDatabase: public CDatabase +{ +public: + CUIntVector Indices; + CObjectVector Sections; + bool LowLevel; + + UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; } + UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; } + + UInt64 GetFolder(unsigned fileIndex) const + { + const CItem &item = Items[Indices[fileIndex]]; + if (item.Section < Sections.Size()) + { + const CSectionInfo §ion = Sections[(unsigned)item.Section]; + if (section.IsLzx()) + return section.Methods[0].LzxInfo.GetFolder(item.Offset); + } + return 0; + } + + UInt64 GetLastFolder(unsigned fileIndex) const + { + const CItem &item = Items[Indices[fileIndex]]; + if (item.Section < Sections.Size()) + { + const CSectionInfo §ion = Sections[(unsigned)item.Section]; + if (section.IsLzx()) + return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1); + } + return 0; + } + + void HighLevelClear() + { + LowLevel = true; + Indices.Clear(); + Sections.Clear(); + } + + void Clear() + { + CDatabase::Clear(); + HighLevelClear(); + } + + void SetIndices(); + void Sort(); + bool Check(); + bool CheckSectionRefs(); +}; + + +class CInArchive +{ + CMyComPtr m_InStreamRef; + ::CInBuffer _inBuffer; + UInt64 _chunkSize; + bool _help2; + + Byte ReadByte(); + void ReadBytes(Byte *data, UInt32 size); + void Skip(size_t size); + UInt16 ReadUInt16(); + UInt32 ReadUInt32(); + UInt64 ReadUInt64(); + UInt64 ReadEncInt(); + void ReadString(unsigned size, AString &s); + void ReadUString(unsigned size, UString &s); + void ReadGUID(Byte *g); + + HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size); + + HRESULT ReadDirEntry(CDatabase &database); + HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name); + +public: + bool IsArc; + bool HeadersError; + bool UnexpectedEnd; + bool UnsupportedFeature; + + CInArchive(bool help2) { _help2 = help2; } + + HRESULT OpenChm(IInStream *inStream, CDatabase &database); + HRESULT OpenHelp2(IInStream *inStream, CDatabase &database); + HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database); + HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Chm/StdAfx.h b/CPP/7zip/Archive/Chm/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Chm/StdAfx.h +++ b/CPP/7zip/Archive/Chm/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index 10f7a5904..82d939ddb 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -1,896 +1,896 @@ -// ComHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/IntToString.h" -#include "../../Common/ComTry.h" -#include "../../Common/MyCom.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -namespace NArchive { -namespace NCom { - -static const Byte kSignature[] = - { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; - -enum EType -{ - k_Type_Common, - k_Type_Msi, - k_Type_Msp, - k_Type_Doc, - k_Type_Ppt, - k_Type_Xls -}; - -static const char * const kExtensions[] = -{ - "compound" - , "msi" - , "msp" - , "doc" - , "ppt" - , "xls" -}; - -namespace NFatID -{ - // static const UInt32 kFree = 0xFFFFFFFF; - static const UInt32 kEndOfChain = 0xFFFFFFFE; - // static const UInt32 kFatSector = 0xFFFFFFFD; - // static const UInt32 kMatSector = 0xFFFFFFFC; - static const UInt32 kMaxValue = 0xFFFFFFFA; -} - -namespace NItemType -{ - static const Byte kEmpty = 0; - static const Byte kStorage = 1; - // static const Byte kStream = 2; - // static const Byte kLockBytes = 3; - // static const Byte kProperty = 4; - static const Byte kRootStorage = 5; -} - -static const UInt32 kNameSizeMax = 64; - -struct CItem -{ - Byte Name[kNameSizeMax]; - // UInt16 NameSize; - // UInt32 Flags; - FILETIME CTime; - FILETIME MTime; - UInt64 Size; - UInt32 LeftDid; - UInt32 RightDid; - UInt32 SonDid; - UInt32 Sid; - Byte Type; - - bool IsEmpty() const { return Type == NItemType::kEmpty; } - bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; } - - void Parse(const Byte *p, bool mode64bit); -}; - -struct CRef -{ - int Parent; - UInt32 Did; -}; - -class CDatabase -{ - UInt32 NumSectorsInMiniStream; - CObjArray MiniSids; - - HRESULT AddNode(int parent, UInt32 did); -public: - - CObjArray Fat; - UInt32 FatSize; - - CObjArray Mat; - UInt32 MatSize; - - CObjectVector Items; - CRecordVector Refs; - - UInt32 LongStreamMinSize; - unsigned SectorSizeBits; - unsigned MiniSectorSizeBits; - - Int32 MainSubfile; - - UInt64 PhySize; - UInt64 PhySize_Aligned; - EType Type; - - bool IsNotArcType() const - { - return - Type != k_Type_Msi && - Type != k_Type_Msp; - } - - void UpdatePhySize(UInt64 val, UInt64 val_Aligned) - { - if (PhySize < val) - PhySize = val; - if (PhySize_Aligned < val_Aligned) - PhySize_Aligned = val_Aligned; - } - HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid); - HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest); - - HRESULT Update_PhySize_WithItem(unsigned index); - - void Clear(); - bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; } - UString GetItemPath(UInt32 index) const; - - UInt64 GetItemPackSize(UInt64 size) const - { - UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; - return (size + mask) & ~mask; - } - - bool GetMiniCluster(UInt32 sid, UInt64 &res) const - { - unsigned subBits = SectorSizeBits - MiniSectorSizeBits; - UInt32 fid = sid >> subBits; - if (fid >= NumSectorsInMiniStream) - return false; - res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); - return true; - } - - HRESULT Open(IInStream *inStream); -}; - - -HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid) -{ - const UInt64 end = ((UInt64)sid + 2) << sectorSizeBits; - UpdatePhySize(end, end); - RINOK(InStream_SeekSet(inStream, (((UInt64)sid + 1) << sectorSizeBits))) - return ReadStream_FALSE(inStream, buf, (size_t)1 << sectorSizeBits); -} - -HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) -{ - RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)) - UInt32 sectorSize = (UInt32)1 << sectorSizeBits; - for (UInt32 t = 0; t < sectorSize; t += 4) - *dest++ = Get32(buf + t); - return S_OK; -} - -static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) -{ - ft->dwLowDateTime = Get32(p); - ft->dwHighDateTime = Get32(p + 4); -} - -void CItem::Parse(const Byte *p, bool mode64bit) -{ - memcpy(Name, p, kNameSizeMax); - // NameSize = Get16(p + 64); - Type = p[66]; - LeftDid = Get32(p + 68); - RightDid = Get32(p + 72); - SonDid = Get32(p + 76); - // Flags = Get32(p + 96); - GetFileTimeFromMem(p + 100, &CTime); - GetFileTimeFromMem(p + 108, &MTime); - Sid = Get32(p + 116); - Size = Get32(p + 120); - if (mode64bit) - Size |= ((UInt64)Get32(p + 124) << 32); -} - -void CDatabase::Clear() -{ - PhySize = 0; - PhySize_Aligned = 0; - - Fat.Free(); - MiniSids.Free(); - Mat.Free(); - Items.Clear(); - Refs.Clear(); -} - -static const UInt32 kNoDid = 0xFFFFFFFF; - -HRESULT CDatabase::AddNode(int parent, UInt32 did) -{ - if (did == kNoDid) - return S_OK; - if (did >= (UInt32)Items.Size()) - return S_FALSE; - const CItem &item = Items[did]; - if (item.IsEmpty()) - return S_FALSE; - CRef ref; - ref.Parent = parent; - ref.Did = did; - const unsigned index = Refs.Add(ref); - if (Refs.Size() > Items.Size()) - return S_FALSE; - RINOK(AddNode(parent, item.LeftDid)) - RINOK(AddNode(parent, item.RightDid)) - if (item.IsDir()) - { - RINOK(AddNode((int)index, item.SonDid)) - } - return S_OK; -} - -static UString CompoundNameToFileName(const UString &s) -{ - UString res; - for (unsigned i = 0; i < s.Len(); i++) - { - const wchar_t c = s[i]; - if ((unsigned)(int)c < 0x20) - { - res.Add_Char('['); - res.Add_UInt32((UInt32)(unsigned)(int)c); - res.Add_Char(']'); - } - else - res += c; - } - return res; -} - -static const char k_Msi_Chars[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; - -// static const char * const k_Msi_ID = ""; // "{msi}"; -static const char k_Msi_SpecChar = '!'; - -static const unsigned k_Msi_NumBits = 6; -static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits; -static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1; -static const unsigned k_Msi_StartUnicodeChar = 0x3800; -static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1); - - -static bool IsMsiName(const Byte *p) -{ - UInt32 c = Get16(p); - return - c >= k_Msi_StartUnicodeChar && - c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange; -} - -static bool AreEqualNames(const Byte *rawName, const char *asciiName) -{ - for (unsigned i = 0; i < kNameSizeMax / 2; i++) - { - wchar_t c = Get16(rawName + i * 2); - wchar_t c2 = (Byte)asciiName[i]; - if (c != c2) - return false; - if (c == 0) - return true; - } - return false; -} - -static bool CompoundMsiNameToFileName(const UString &name, UString &res) -{ - res.Empty(); - for (unsigned i = 0; i < name.Len(); i++) - { - wchar_t c = name[i]; - if (c < (wchar_t)k_Msi_StartUnicodeChar || c > (wchar_t)(k_Msi_StartUnicodeChar + k_Msi_UnicodeRange)) - return false; - /* - if (i == 0) - res += k_Msi_ID; - */ - c -= (wchar_t)k_Msi_StartUnicodeChar; - - const unsigned c0 = (unsigned)c & k_Msi_CharMask; - const unsigned c1 = (unsigned)c >> k_Msi_NumBits; - - if (c1 <= k_Msi_NumChars) - { - res.Add_Char(k_Msi_Chars[c0]); - if (c1 == k_Msi_NumChars) - break; - res.Add_Char(k_Msi_Chars[c1]); - } - else - res.Add_Char(k_Msi_SpecChar); - } - return true; -} - -static UString ConvertName(const Byte *p, bool &isMsi) -{ - isMsi = false; - UString s; - - for (unsigned i = 0; i < kNameSizeMax; i += 2) - { - wchar_t c = Get16(p + i); - if (c == 0) - break; - s += c; - } - - UString msiName; - if (CompoundMsiNameToFileName(s, msiName)) - { - isMsi = true; - return msiName; - } - return CompoundNameToFileName(s); -} - -static UString ConvertName(const Byte *p) -{ - bool isMsi; - return ConvertName(p, isMsi); -} - -UString CDatabase::GetItemPath(UInt32 index) const -{ - UString s; - while (index != kNoDid) - { - const CRef &ref = Refs[index]; - const CItem &item = Items[ref.Did]; - if (!s.IsEmpty()) - s.InsertAtFront(WCHAR_PATH_SEPARATOR); - s.Insert(0, ConvertName(item.Name)); - index = (unsigned)ref.Parent; - } - return s; -} - -HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) -{ - const CItem &item = Items[index]; - bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); - if (!isLargeStream) - return S_OK; - const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; - // streamSpec->Size = item.Size; - - const UInt32 clusterSize = (UInt32)1 << bsLog; - const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; - if (numClusters64 >= ((UInt32)1 << 31)) - return S_FALSE; - UInt32 sid = item.Sid; - UInt64 size = item.Size; - - if (size != 0) - { - for (;; size -= clusterSize) - { - // if (isLargeStream) - { - if (sid >= FatSize) - return S_FALSE; - UInt64 end = ((UInt64)sid + 1) << bsLog; - const UInt64 end_Aligned = end + clusterSize; - if (size < clusterSize) - end += size; - else - end = end_Aligned; - UpdatePhySize(end, end_Aligned); - sid = Fat[sid]; - } - if (size <= clusterSize) - break; - } - } - if (sid != NFatID::kEndOfChain) - return S_FALSE; - return S_OK; -} - -// There is name "[!]MsiPatchSequence" in msp files -static const unsigned kMspSequence_Size = 18; -static const Byte kMspSequence[kMspSequence_Size] = - { 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45, - 0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41, - 0x37, 0x41 }; - -HRESULT CDatabase::Open(IInStream *inStream) -{ - MainSubfile = -1; - Type = k_Type_Common; - const UInt32 kHeaderSize = 512; - Byte p[kHeaderSize]; - PhySize = kHeaderSize; - RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)) - if (memcmp(p, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0) - return S_FALSE; - if (Get16(p + 0x1A) > 4) // majorVer - return S_FALSE; - if (Get16(p + 0x1C) != 0xFFFE) // Little-endian - return S_FALSE; - unsigned sectorSizeBits = Get16(p + 0x1E); - bool mode64bit = (sectorSizeBits >= 12); - unsigned miniSectorSizeBits = Get16(p + 0x20); - SectorSizeBits = sectorSizeBits; - MiniSectorSizeBits = miniSectorSizeBits; - - if (sectorSizeBits > 24 || - sectorSizeBits < 7 || - miniSectorSizeBits > 24 || - miniSectorSizeBits < 2 || - miniSectorSizeBits > sectorSizeBits) - return S_FALSE; - UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT - LongStreamMinSize = Get32(p + 0x38); - - UInt32 sectSize = (UInt32)1 << sectorSizeBits; - - CByteBuffer sect(sectSize); - - unsigned ssb2 = sectorSizeBits - 2; - UInt32 numSidsInSec = (UInt32)1 << ssb2; - UInt32 numFatItems = numSectorsForFAT << ssb2; - if ((numFatItems >> ssb2) != numSectorsForFAT) - return S_FALSE; - FatSize = numFatItems; - - { - UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table - const UInt32 kNumHeaderBatItems = 109; - UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); - if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) - return S_FALSE; - CObjArray bat(numBatItems); - UInt32 i; - for (i = 0; i < kNumHeaderBatItems; i++) - bat[i] = Get32(p + 0x4c + i * 4); - UInt32 sid = Get32(p + 0x44); - for (UInt32 s = 0; s < numSectorsForBat; s++) - { - RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)) - i += numSidsInSec - 1; - sid = bat[i]; - } - numBatItems = i; - - Fat.Alloc(numFatItems); - UInt32 j = 0; - - for (i = 0; i < numFatItems; j++, i += numSidsInSec) - { - if (j >= numBatItems) - return S_FALSE; - RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i)) - } - FatSize = numFatItems = i; - } - - UInt32 numMatItems; - { - UInt32 numSectorsForMat = Get32(p + 0x40); - numMatItems = (UInt32)numSectorsForMat << ssb2; - if ((numMatItems >> ssb2) != numSectorsForMat) - return S_FALSE; - Mat.Alloc(numMatItems); - UInt32 i; - UInt32 sid = Get32(p + 0x3C); // short-sector table SID - for (i = 0; i < numMatItems; i += numSidsInSec) - { - RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i)) - if (sid >= numFatItems) - return S_FALSE; - sid = Fat[sid]; - } - if (sid != NFatID::kEndOfChain) - return S_FALSE; - } - - { - CByteBuffer used(numFatItems); - for (UInt32 i = 0; i < numFatItems; i++) - used[i] = 0; - UInt32 sid = Get32(p + 0x30); // directory stream SID - for (;;) - { - if (sid >= numFatItems) - return S_FALSE; - if (used[sid]) - return S_FALSE; - used[sid] = 1; - RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)) - for (UInt32 i = 0; i < sectSize; i += 128) - { - CItem item; - item.Parse(sect + i, mode64bit); - Items.Add(item); - } - sid = Fat[sid]; - if (sid == NFatID::kEndOfChain) - break; - } - } - - const CItem &root = Items[0]; - - { - UInt32 numSectorsInMiniStream; - { - UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; - if (numSatSects64 > NFatID::kMaxValue) - return S_FALSE; - numSectorsInMiniStream = (UInt32)numSatSects64; - } - NumSectorsInMiniStream = numSectorsInMiniStream; - MiniSids.Alloc(numSectorsInMiniStream); - { - UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; - if (matSize64 > NFatID::kMaxValue) - return S_FALSE; - MatSize = (UInt32)matSize64; - if (numMatItems < MatSize) - return S_FALSE; - } - - UInt32 sid = root.Sid; - for (UInt32 i = 0; ; i++) - { - if (sid == NFatID::kEndOfChain) - { - if (i != numSectorsInMiniStream) - return S_FALSE; - break; - } - if (i >= numSectorsInMiniStream) - return S_FALSE; - MiniSids[i] = sid; - if (sid >= numFatItems) - return S_FALSE; - sid = Fat[sid]; - } - } - - RINOK(AddNode(-1, root.SonDid)) - - unsigned numCabs = 0; - - FOR_VECTOR (i, Refs) - { - const CItem &item = Items[Refs[i].Did]; - if (item.IsDir() || numCabs > 1) - continue; - bool isMsiName; - const UString msiName = ConvertName(item.Name, isMsiName); - if (isMsiName && !msiName.IsEmpty()) - { - // bool isThereExt = (msiName.Find(L'.') >= 0); - bool isMsiSpec = (msiName[0] == k_Msi_SpecChar); - if ((msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab")) - || (!isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe")) - // || (!isMsiSpec && !isThereExt) - ) - { - numCabs++; - MainSubfile = (int)i; - } - } - } - - if (numCabs > 1) - MainSubfile = -1; - - { - FOR_VECTOR (t, Items) - { - Update_PhySize_WithItem(t); - } - } - { - if (PhySize != PhySize_Aligned) - { - /* some msi (in rare cases) have unaligned size of archive, - where there is no padding data after payload data in last cluster of archive */ - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) - if (PhySize != fileSize) - PhySize = PhySize_Aligned; - } - } - { - FOR_VECTOR (t, Items) - { - const CItem &item = Items[t]; - - if (IsMsiName(item.Name)) - { - Type = k_Type_Msi; - if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0) - { - Type = k_Type_Msp; - break; - } - continue; - } - if (AreEqualNames(item.Name, "WordDocument")) - { - Type = k_Type_Doc; - break; - } - if (AreEqualNames(item.Name, "PowerPoint Document")) - { - Type = k_Type_Ppt; - break; - } - if (AreEqualNames(item.Name, "Workbook")) - { - Type = k_Type_Xls; - break; - } - } - } - - return S_OK; -} - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CMyComPtr _stream; - CDatabase _db; -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidCTime, - kpidMTime -}; - -static const Byte kArcProps[] = -{ - kpidExtension, - kpidClusterSize, - kpidSectorSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break; - case kpidPhySize: prop = _db.PhySize; break; - case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break; - case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break; - case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break; - case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CRef &ref = _db.Refs[index]; - const CItem &item = _db.Items[ref.Did]; - - switch (propID) - { - case kpidPath: prop = _db.GetItemPath(index); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidCTime: prop = item.CTime; break; - case kpidMTime: prop = item.MTime; break; - case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - try - { - if (_db.Open(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _db.Clear(); - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _db.Refs.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did]; - if (!item.IsDir()) - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _db.Items[_db.Refs[index].Did]; - - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - totalPackSize += _db.GetItemPackSize(item.Size); - totalSize += item.Size; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - Int32 res = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - HRESULT hres = GetStream(index, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kDataError; - else if (hres == E_NOTIMPL) - res = NExtract::NOperationResult::kUnsupportedMethod; - else - { - RINOK(hres) - if (inStream) - { - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - if (copyCoderSpec->TotalSize == item.Size) - res = NExtract::NOperationResult::kOK; - } - } - outStream.Release(); - RINOK(extractCallback->SetOperationResult(res)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _db.Refs.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - const UInt32 itemIndex = _db.Refs[index].Did; - const CItem &item = _db.Items[itemIndex]; - CClusterInStream *streamSpec = new CClusterInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Stream = _stream; - streamSpec->StartOffset = 0; - - const bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size)); - const unsigned bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; - streamSpec->BlockSizeLog = bsLog; - streamSpec->Size = item.Size; - - const UInt32 clusterSize = (UInt32)1 << bsLog; - const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; - if (numClusters64 >= ((UInt32)1 << 31)) - return E_NOTIMPL; - streamSpec->Vector.ClearAndReserve((unsigned)numClusters64); - UInt32 sid = item.Sid; - UInt64 size = item.Size; - - if (size != 0) - { - for (;; size -= clusterSize) - { - if (isLargeStream) - { - if (sid >= _db.FatSize) - return S_FALSE; - streamSpec->Vector.AddInReserved(sid + 1); - sid = _db.Fat[sid]; - } - else - { - UInt64 val = 0; - if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32) - return S_FALSE; - streamSpec->Vector.AddInReserved((UInt32)val); - sid = _db.Mat[sid]; - } - if (size <= clusterSize) - break; - } - } - if (sid != NFatID::kEndOfChain) - return S_FALSE; - RINOK(streamSpec->InitAndSeek()) - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -REGISTER_ARC_I( - "Compound", "msi msp doc xls ppt", NULL, 0xE5, - kSignature, - 0, - 0, - NULL) - -}} +// ComHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/IntToString.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NCom { + +static const Byte kSignature[] = + { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }; + +enum EType +{ + k_Type_Common, + k_Type_Msi, + k_Type_Msp, + k_Type_Doc, + k_Type_Ppt, + k_Type_Xls +}; + +static const char * const kExtensions[] = +{ + "compound" + , "msi" + , "msp" + , "doc" + , "ppt" + , "xls" +}; + +namespace NFatID +{ + // static const UInt32 kFree = 0xFFFFFFFF; + static const UInt32 kEndOfChain = 0xFFFFFFFE; + // static const UInt32 kFatSector = 0xFFFFFFFD; + // static const UInt32 kMatSector = 0xFFFFFFFC; + static const UInt32 kMaxValue = 0xFFFFFFFA; +} + +namespace NItemType +{ + static const Byte kEmpty = 0; + static const Byte kStorage = 1; + // static const Byte kStream = 2; + // static const Byte kLockBytes = 3; + // static const Byte kProperty = 4; + static const Byte kRootStorage = 5; +} + +static const UInt32 kNameSizeMax = 64; + +struct CItem +{ + Byte Name[kNameSizeMax]; + // UInt16 NameSize; + // UInt32 Flags; + FILETIME CTime; + FILETIME MTime; + UInt64 Size; + UInt32 LeftDid; + UInt32 RightDid; + UInt32 SonDid; + UInt32 Sid; + Byte Type; + + bool IsEmpty() const { return Type == NItemType::kEmpty; } + bool IsDir() const { return Type == NItemType::kStorage || Type == NItemType::kRootStorage; } + + void Parse(const Byte *p, bool mode64bit); +}; + +struct CRef +{ + int Parent; + UInt32 Did; +}; + +class CDatabase +{ + UInt32 NumSectorsInMiniStream; + CObjArray MiniSids; + + HRESULT AddNode(int parent, UInt32 did); +public: + + CObjArray Fat; + UInt32 FatSize; + + CObjArray Mat; + UInt32 MatSize; + + CObjectVector Items; + CRecordVector Refs; + + UInt32 LongStreamMinSize; + unsigned SectorSizeBits; + unsigned MiniSectorSizeBits; + + Int32 MainSubfile; + + UInt64 PhySize; + UInt64 PhySize_Aligned; + EType Type; + + bool IsNotArcType() const + { + return + Type != k_Type_Msi && + Type != k_Type_Msp; + } + + void UpdatePhySize(UInt64 val, UInt64 val_Aligned) + { + if (PhySize < val) + PhySize = val; + if (PhySize_Aligned < val_Aligned) + PhySize_Aligned = val_Aligned; + } + HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid); + HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest); + + HRESULT Update_PhySize_WithItem(unsigned index); + + void Clear(); + bool IsLargeStream(UInt64 size) const { return size >= LongStreamMinSize; } + UString GetItemPath(UInt32 index) const; + + UInt64 GetItemPackSize(UInt64 size) const + { + UInt64 mask = ((UInt64)1 << (IsLargeStream(size) ? SectorSizeBits : MiniSectorSizeBits)) - 1; + return (size + mask) & ~mask; + } + + bool GetMiniCluster(UInt32 sid, UInt64 &res) const + { + unsigned subBits = SectorSizeBits - MiniSectorSizeBits; + UInt32 fid = sid >> subBits; + if (fid >= NumSectorsInMiniStream) + return false; + res = (((UInt64)MiniSids[fid] + 1) << subBits) + (sid & ((1 << subBits) - 1)); + return true; + } + + HRESULT Open(IInStream *inStream); +}; + + +HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid) +{ + const UInt64 end = ((UInt64)sid + 2) << sectorSizeBits; + UpdatePhySize(end, end); + RINOK(InStream_SeekSet(inStream, (((UInt64)sid + 1) << sectorSizeBits))) + return ReadStream_FALSE(inStream, buf, (size_t)1 << sectorSizeBits); +} + +HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest) +{ + RINOK(ReadSector(inStream, buf, sectorSizeBits, sid)) + UInt32 sectorSize = (UInt32)1 << sectorSizeBits; + for (UInt32 t = 0; t < sectorSize; t += 4) + *dest++ = Get32(buf + t); + return S_OK; +} + +static void GetFileTimeFromMem(const Byte *p, FILETIME *ft) +{ + ft->dwLowDateTime = Get32(p); + ft->dwHighDateTime = Get32(p + 4); +} + +void CItem::Parse(const Byte *p, bool mode64bit) +{ + memcpy(Name, p, kNameSizeMax); + // NameSize = Get16(p + 64); + Type = p[66]; + LeftDid = Get32(p + 68); + RightDid = Get32(p + 72); + SonDid = Get32(p + 76); + // Flags = Get32(p + 96); + GetFileTimeFromMem(p + 100, &CTime); + GetFileTimeFromMem(p + 108, &MTime); + Sid = Get32(p + 116); + Size = Get32(p + 120); + if (mode64bit) + Size |= ((UInt64)Get32(p + 124) << 32); +} + +void CDatabase::Clear() +{ + PhySize = 0; + PhySize_Aligned = 0; + + Fat.Free(); + MiniSids.Free(); + Mat.Free(); + Items.Clear(); + Refs.Clear(); +} + +static const UInt32 kNoDid = 0xFFFFFFFF; + +HRESULT CDatabase::AddNode(int parent, UInt32 did) +{ + if (did == kNoDid) + return S_OK; + if (did >= (UInt32)Items.Size()) + return S_FALSE; + const CItem &item = Items[did]; + if (item.IsEmpty()) + return S_FALSE; + CRef ref; + ref.Parent = parent; + ref.Did = did; + const unsigned index = Refs.Add(ref); + if (Refs.Size() > Items.Size()) + return S_FALSE; + RINOK(AddNode(parent, item.LeftDid)) + RINOK(AddNode(parent, item.RightDid)) + if (item.IsDir()) + { + RINOK(AddNode((int)index, item.SonDid)) + } + return S_OK; +} + +static UString CompoundNameToFileName(const UString &s) +{ + UString res; + for (unsigned i = 0; i < s.Len(); i++) + { + const wchar_t c = s[i]; + if ((unsigned)(int)c < 0x20) + { + res.Add_Char('['); + res.Add_UInt32((UInt32)(unsigned)(int)c); + res.Add_Char(']'); + } + else + res += c; + } + return res; +} + +static const char k_Msi_Chars[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._"; + +// static const char * const k_Msi_ID = ""; // "{msi}"; +static const char k_Msi_SpecChar = '!'; + +static const unsigned k_Msi_NumBits = 6; +static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits; +static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1; +static const unsigned k_Msi_StartUnicodeChar = 0x3800; +static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1); + + +static bool IsMsiName(const Byte *p) +{ + UInt32 c = Get16(p); + return + c >= k_Msi_StartUnicodeChar && + c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange; +} + +static bool AreEqualNames(const Byte *rawName, const char *asciiName) +{ + for (unsigned i = 0; i < kNameSizeMax / 2; i++) + { + wchar_t c = Get16(rawName + i * 2); + wchar_t c2 = (Byte)asciiName[i]; + if (c != c2) + return false; + if (c == 0) + return true; + } + return false; +} + +static bool CompoundMsiNameToFileName(const UString &name, UString &res) +{ + res.Empty(); + for (unsigned i = 0; i < name.Len(); i++) + { + wchar_t c = name[i]; + if (c < (wchar_t)k_Msi_StartUnicodeChar || c > (wchar_t)(k_Msi_StartUnicodeChar + k_Msi_UnicodeRange)) + return false; + /* + if (i == 0) + res += k_Msi_ID; + */ + c -= (wchar_t)k_Msi_StartUnicodeChar; + + const unsigned c0 = (unsigned)c & k_Msi_CharMask; + const unsigned c1 = (unsigned)c >> k_Msi_NumBits; + + if (c1 <= k_Msi_NumChars) + { + res.Add_Char(k_Msi_Chars[c0]); + if (c1 == k_Msi_NumChars) + break; + res.Add_Char(k_Msi_Chars[c1]); + } + else + res.Add_Char(k_Msi_SpecChar); + } + return true; +} + +static UString ConvertName(const Byte *p, bool &isMsi) +{ + isMsi = false; + UString s; + + for (unsigned i = 0; i < kNameSizeMax; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + break; + s += c; + } + + UString msiName; + if (CompoundMsiNameToFileName(s, msiName)) + { + isMsi = true; + return msiName; + } + return CompoundNameToFileName(s); +} + +static UString ConvertName(const Byte *p) +{ + bool isMsi; + return ConvertName(p, isMsi); +} + +UString CDatabase::GetItemPath(UInt32 index) const +{ + UString s; + while (index != kNoDid) + { + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.Did]; + if (!s.IsEmpty()) + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + s.Insert(0, ConvertName(item.Name)); + index = (unsigned)ref.Parent; + } + return s; +} + +HRESULT CDatabase::Update_PhySize_WithItem(unsigned index) +{ + const CItem &item = Items[index]; + bool isLargeStream = (index == 0 || IsLargeStream(item.Size)); + if (!isLargeStream) + return S_OK; + const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits; + // streamSpec->Size = item.Size; + + const UInt32 clusterSize = (UInt32)1 << bsLog; + const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; + if (numClusters64 >= ((UInt32)1 << 31)) + return S_FALSE; + UInt32 sid = item.Sid; + UInt64 size = item.Size; + + if (size != 0) + { + for (;; size -= clusterSize) + { + // if (isLargeStream) + { + if (sid >= FatSize) + return S_FALSE; + UInt64 end = ((UInt64)sid + 1) << bsLog; + const UInt64 end_Aligned = end + clusterSize; + if (size < clusterSize) + end += size; + else + end = end_Aligned; + UpdatePhySize(end, end_Aligned); + sid = Fat[sid]; + } + if (size <= clusterSize) + break; + } + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + return S_OK; +} + +// There is name "[!]MsiPatchSequence" in msp files +static const unsigned kMspSequence_Size = 18; +static const Byte kMspSequence[kMspSequence_Size] = + { 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45, + 0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41, + 0x37, 0x41 }; + +HRESULT CDatabase::Open(IInStream *inStream) +{ + MainSubfile = -1; + Type = k_Type_Common; + const UInt32 kHeaderSize = 512; + Byte p[kHeaderSize]; + PhySize = kHeaderSize; + RINOK(ReadStream_FALSE(inStream, p, kHeaderSize)) + if (memcmp(p, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0) + return S_FALSE; + if (Get16(p + 0x1A) > 4) // majorVer + return S_FALSE; + if (Get16(p + 0x1C) != 0xFFFE) // Little-endian + return S_FALSE; + unsigned sectorSizeBits = Get16(p + 0x1E); + bool mode64bit = (sectorSizeBits >= 12); + unsigned miniSectorSizeBits = Get16(p + 0x20); + SectorSizeBits = sectorSizeBits; + MiniSectorSizeBits = miniSectorSizeBits; + + if (sectorSizeBits > 24 || + sectorSizeBits < 7 || + miniSectorSizeBits > 24 || + miniSectorSizeBits < 2 || + miniSectorSizeBits > sectorSizeBits) + return S_FALSE; + UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT + LongStreamMinSize = Get32(p + 0x38); + + UInt32 sectSize = (UInt32)1 << sectorSizeBits; + + CByteBuffer sect(sectSize); + + unsigned ssb2 = sectorSizeBits - 2; + UInt32 numSidsInSec = (UInt32)1 << ssb2; + UInt32 numFatItems = numSectorsForFAT << ssb2; + if ((numFatItems >> ssb2) != numSectorsForFAT) + return S_FALSE; + FatSize = numFatItems; + + { + UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table + const UInt32 kNumHeaderBatItems = 109; + UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2); + if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat) + return S_FALSE; + CObjArray bat(numBatItems); + UInt32 i; + for (i = 0; i < kNumHeaderBatItems; i++) + bat[i] = Get32(p + 0x4c + i * 4); + UInt32 sid = Get32(p + 0x44); + for (UInt32 s = 0; s < numSectorsForBat; s++) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, bat + i)) + i += numSidsInSec - 1; + sid = bat[i]; + } + numBatItems = i; + + Fat.Alloc(numFatItems); + UInt32 j = 0; + + for (i = 0; i < numFatItems; j++, i += numSidsInSec) + { + if (j >= numBatItems) + return S_FALSE; + RINOK(ReadIDs(inStream, sect, sectorSizeBits, bat[j], Fat + i)) + } + FatSize = numFatItems = i; + } + + UInt32 numMatItems; + { + UInt32 numSectorsForMat = Get32(p + 0x40); + numMatItems = (UInt32)numSectorsForMat << ssb2; + if ((numMatItems >> ssb2) != numSectorsForMat) + return S_FALSE; + Mat.Alloc(numMatItems); + UInt32 i; + UInt32 sid = Get32(p + 0x3C); // short-sector table SID + for (i = 0; i < numMatItems; i += numSidsInSec) + { + RINOK(ReadIDs(inStream, sect, sectorSizeBits, sid, Mat + i)) + if (sid >= numFatItems) + return S_FALSE; + sid = Fat[sid]; + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + } + + { + CByteBuffer used(numFatItems); + for (UInt32 i = 0; i < numFatItems; i++) + used[i] = 0; + UInt32 sid = Get32(p + 0x30); // directory stream SID + for (;;) + { + if (sid >= numFatItems) + return S_FALSE; + if (used[sid]) + return S_FALSE; + used[sid] = 1; + RINOK(ReadSector(inStream, sect, sectorSizeBits, sid)) + for (UInt32 i = 0; i < sectSize; i += 128) + { + CItem item; + item.Parse(sect + i, mode64bit); + Items.Add(item); + } + sid = Fat[sid]; + if (sid == NFatID::kEndOfChain) + break; + } + } + + const CItem &root = Items[0]; + + { + UInt32 numSectorsInMiniStream; + { + UInt64 numSatSects64 = (root.Size + sectSize - 1) >> sectorSizeBits; + if (numSatSects64 > NFatID::kMaxValue) + return S_FALSE; + numSectorsInMiniStream = (UInt32)numSatSects64; + } + NumSectorsInMiniStream = numSectorsInMiniStream; + MiniSids.Alloc(numSectorsInMiniStream); + { + UInt64 matSize64 = (root.Size + ((UInt64)1 << miniSectorSizeBits) - 1) >> miniSectorSizeBits; + if (matSize64 > NFatID::kMaxValue) + return S_FALSE; + MatSize = (UInt32)matSize64; + if (numMatItems < MatSize) + return S_FALSE; + } + + UInt32 sid = root.Sid; + for (UInt32 i = 0; ; i++) + { + if (sid == NFatID::kEndOfChain) + { + if (i != numSectorsInMiniStream) + return S_FALSE; + break; + } + if (i >= numSectorsInMiniStream) + return S_FALSE; + MiniSids[i] = sid; + if (sid >= numFatItems) + return S_FALSE; + sid = Fat[sid]; + } + } + + RINOK(AddNode(-1, root.SonDid)) + + unsigned numCabs = 0; + + FOR_VECTOR (i, Refs) + { + const CItem &item = Items[Refs[i].Did]; + if (item.IsDir() || numCabs > 1) + continue; + bool isMsiName; + const UString msiName = ConvertName(item.Name, isMsiName); + if (isMsiName && !msiName.IsEmpty()) + { + // bool isThereExt = (msiName.Find(L'.') >= 0); + bool isMsiSpec = (msiName[0] == k_Msi_SpecChar); + if ((msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab")) + || (!isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe")) + // || (!isMsiSpec && !isThereExt) + ) + { + numCabs++; + MainSubfile = (int)i; + } + } + } + + if (numCabs > 1) + MainSubfile = -1; + + { + FOR_VECTOR (t, Items) + { + Update_PhySize_WithItem(t); + } + } + { + if (PhySize != PhySize_Aligned) + { + /* some msi (in rare cases) have unaligned size of archive, + where there is no padding data after payload data in last cluster of archive */ + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) + if (PhySize != fileSize) + PhySize = PhySize_Aligned; + } + } + { + FOR_VECTOR (t, Items) + { + const CItem &item = Items[t]; + + if (IsMsiName(item.Name)) + { + Type = k_Type_Msi; + if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0) + { + Type = k_Type_Msp; + break; + } + continue; + } + if (AreEqualNames(item.Name, "WordDocument")) + { + Type = k_Type_Doc; + break; + } + if (AreEqualNames(item.Name, "PowerPoint Document")) + { + Type = k_Type_Ppt; + break; + } + if (AreEqualNames(item.Name, "Workbook")) + { + Type = k_Type_Xls; + break; + } + } + } + + return S_OK; +} + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CMyComPtr _stream; + CDatabase _db; +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCTime, + kpidMTime +}; + +static const Byte kArcProps[] = +{ + kpidExtension, + kpidClusterSize, + kpidSectorSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break; + case kpidPhySize: prop = _db.PhySize; break; + case kpidClusterSize: prop = (UInt32)1 << _db.SectorSizeBits; break; + case kpidSectorSize: prop = (UInt32)1 << _db.MiniSectorSizeBits; break; + case kpidMainSubfile: if (_db.MainSubfile >= 0) prop = (UInt32)_db.MainSubfile; break; + case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CRef &ref = _db.Refs[index]; + const CItem &item = _db.Items[ref.Did]; + + switch (propID) + { + case kpidPath: prop = _db.GetItemPath(index); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidCTime: prop = item.CTime; break; + case kpidMTime: prop = item.MTime; break; + case kpidPackSize: if (!item.IsDir()) prop = _db.GetItemPackSize(item.Size); break; + case kpidSize: if (!item.IsDir()) prop = item.Size; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + try + { + if (_db.Open(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _db.Clear(); + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _db.Refs.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const CItem &item = _db.Items[_db.Refs[allFilesMode ? i : indices[i]].Did]; + if (!item.IsDir()) + totalSize += item.Size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _db.Items[_db.Refs[index].Did]; + + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + totalPackSize += _db.GetItemPackSize(item.Size); + totalSize += item.Size; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + Int32 res = NExtract::NOperationResult::kDataError; + CMyComPtr inStream; + HRESULT hres = GetStream(index, &inStream); + if (hres == S_FALSE) + res = NExtract::NOperationResult::kDataError; + else if (hres == E_NOTIMPL) + res = NExtract::NOperationResult::kUnsupportedMethod; + else + { + RINOK(hres) + if (inStream) + { + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(res)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _db.Refs.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + const UInt32 itemIndex = _db.Refs[index].Did; + const CItem &item = _db.Items[itemIndex]; + CClusterInStream *streamSpec = new CClusterInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Stream = _stream; + streamSpec->StartOffset = 0; + + const bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size)); + const unsigned bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits; + streamSpec->BlockSizeLog = bsLog; + streamSpec->Size = item.Size; + + const UInt32 clusterSize = (UInt32)1 << bsLog; + const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog; + if (numClusters64 >= ((UInt32)1 << 31)) + return E_NOTIMPL; + streamSpec->Vector.ClearAndReserve((unsigned)numClusters64); + UInt32 sid = item.Sid; + UInt64 size = item.Size; + + if (size != 0) + { + for (;; size -= clusterSize) + { + if (isLargeStream) + { + if (sid >= _db.FatSize) + return S_FALSE; + streamSpec->Vector.AddInReserved(sid + 1); + sid = _db.Fat[sid]; + } + else + { + UInt64 val = 0; + if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32) + return S_FALSE; + streamSpec->Vector.AddInReserved((UInt32)val); + sid = _db.Mat[sid]; + } + if (size <= clusterSize) + break; + } + } + if (sid != NFatID::kEndOfChain) + return S_FALSE; + RINOK(streamSpec->InitAndSeek()) + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "Compound", "msi msp doc xls ppt", NULL, 0xE5, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp index 571245d32..b1c316d1c 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.cpp +++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp @@ -1,1144 +1,1144 @@ -// CoderMixer2.cpp - -#include "StdAfx.h" - -#include "CoderMixer2.h" - -#ifdef USE_MIXER_ST - -Z7_COM7F_IMF(CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessed = 0; - HRESULT result = S_OK; - if (_stream) - result = _stream->Read(data, size, &realProcessed); - _size += realProcessed; - if (size != 0 && realProcessed == 0) - _wasFinished = true; - if (processedSize) - *processedSize = realProcessed; - return result; -} - - -Z7_COM7F_IMF(COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -Z7_COM7F_IMF(COutStreamCalcSize::OutStreamFinish()) -{ - HRESULT result = S_OK; - if (_stream) - { - CMyComPtr outStreamFinish; - _stream.QueryInterface(IID_IOutStreamFinish, &outStreamFinish); - if (outStreamFinish) - result = outStreamFinish->OutStreamFinish(); - } - return result; -} - -#endif - - - - -namespace NCoderMixer2 { - -static void BoolVector_Fill_False(CBoolVector &v, unsigned size) -{ - v.ClearAndSetSize(size); - bool *p = &v[0]; - for (unsigned i = 0; i < size; i++) - p[i] = false; -} - - -HRESULT CCoder::CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const -{ - if (Coder) - { - if (PackSizePointers.IsEmpty() || !PackSizePointers[0]) - return S_OK; - CMyComPtr getInStreamProcessedSize; - Coder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); - // if (!getInStreamProcessedSize) return E_FAIL; - if (getInStreamProcessedSize) - { - UInt64 processed; - RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) - if (processed != (UInt64)(Int64)-1) - { - const UInt64 size = PackSizes[0]; - if (processed < size && Finish) - dataAfterEnd_Error = true; - if (processed > size) - { - // InternalPackSizeError = true; - // return S_FALSE; - } - } - } - } - else if (Coder2) - { - CMyComPtr getInStreamProcessedSize2; - Coder2.QueryInterface(IID_ICompressGetInStreamProcessedSize2, (void **)&getInStreamProcessedSize2); - if (getInStreamProcessedSize2) - FOR_VECTOR (i, PackSizePointers) - { - if (!PackSizePointers[i]) - continue; - UInt64 processed; - RINOK(getInStreamProcessedSize2->GetInStreamProcessedSize2(i, &processed)) - if (processed != (UInt64)(Int64)-1) - { - const UInt64 size = PackSizes[i]; - if (processed < size && Finish) - dataAfterEnd_Error = true; - else if (processed > size) - { - // InternalPackSizeError = true; - // return S_FALSE; - } - } - } - } - - return S_OK; -} - - - -class CBondsChecks -{ - CBoolVector _coderUsed; - - bool Init(); - bool CheckCoder(unsigned coderIndex); -public: - const CBindInfo *BindInfo; - - bool Check(); -}; - -bool CBondsChecks::CheckCoder(unsigned coderIndex) -{ - const CCoderStreamsInfo &coder = BindInfo->Coders[coderIndex]; - - if (coderIndex >= _coderUsed.Size() || _coderUsed[coderIndex]) - return false; - _coderUsed[coderIndex] = true; - - const UInt32 start = BindInfo->Coder_to_Stream[coderIndex]; - - for (unsigned i = 0; i < coder.NumStreams; i++) - { - UInt32 ind = start + i; - - if (BindInfo->IsStream_in_PackStreams(ind)) - continue; - - const int bond = BindInfo->FindBond_for_PackStream(ind); - if (bond < 0) - return false; - if (!CheckCoder(BindInfo->Bonds[(unsigned)bond].UnpackIndex)) - return false; - } - - return true; -} - -bool CBondsChecks::Check() -{ - BoolVector_Fill_False(_coderUsed, BindInfo->Coders.Size()); - - if (!CheckCoder(BindInfo->UnpackCoder)) - return false; - - FOR_VECTOR(i, _coderUsed) - if (!_coderUsed[i]) - return false; - - return true; -} - -void CBindInfo::ClearMaps() -{ - Coder_to_Stream.Clear(); - Stream_to_Coder.Clear(); -} - -bool CBindInfo::CalcMapsAndCheck() -{ - ClearMaps(); - - UInt32 numStreams = 0; - - if (Coders.Size() == 0) - return false; - if (Coders.Size() - 1 != Bonds.Size()) - return false; - - FOR_VECTOR(i, Coders) - { - Coder_to_Stream.Add(numStreams); - - const CCoderStreamsInfo &c = Coders[i]; - - for (unsigned j = 0; j < c.NumStreams; j++) - Stream_to_Coder.Add(i); - - numStreams += c.NumStreams; - } - - if (numStreams != GetNum_Bonds_and_PackStreams()) - return false; - - CBondsChecks bc; - bc.BindInfo = this; - return bc.Check(); -} - - -void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) -{ - Finish = finish; - - if (unpackSize) - { - UnpackSize = *unpackSize; - UnpackSizePointer = &UnpackSize; - } - else - { - UnpackSize = 0; - UnpackSizePointer = NULL; - } - - PackSizes.ClearAndSetSize((unsigned)NumStreams); - PackSizePointers.ClearAndSetSize((unsigned)NumStreams); - - for (unsigned i = 0; i < NumStreams; i++) - { - if (packSizes && packSizes[i]) - { - PackSizes[i] = *(packSizes[i]); - PackSizePointers[i] = &PackSizes[i]; - } - else - { - PackSizes[i] = 0; - PackSizePointers[i] = NULL; - } - } -} - -bool CMixer::Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex) -{ - if (coderIndex == _bi.UnpackCoder) - return true; - - const int bond = _bi.FindBond_for_UnpackStream(coderIndex); - if (bond < 0) - throw 20150213; - - /* - UInt32 coderIndex, coderStreamIndex; - _bi.GetCoder_for_Stream(_bi.Bonds[(unsigned)bond].PackIndex, coderIndex, coderStreamIndex); - */ - const UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[(unsigned)bond].PackIndex]; - - if (!IsFilter_Vector[nextCoder]) - return false; - - return Is_UnpackSize_Correct_for_Coder(nextCoder); -} - -bool CMixer::Is_PackSize_Correct_for_Stream(UInt32 streamIndex) -{ - if (_bi.IsStream_in_PackStreams(streamIndex)) - return true; - - const int bond = _bi.FindBond_for_PackStream(streamIndex); - if (bond < 0) - throw 20150213; - - const UInt32 nextCoder = _bi.Bonds[(unsigned)bond].UnpackIndex; - - if (!IsFilter_Vector[nextCoder]) - return false; - - return Is_PackSize_Correct_for_Coder(nextCoder); -} - -bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex) -{ - const UInt32 startIndex = _bi.Coder_to_Stream[coderIndex]; - const UInt32 numStreams = _bi.Coders[coderIndex].NumStreams; - for (UInt32 i = 0; i < numStreams; i++) - if (!Is_PackSize_Correct_for_Stream(startIndex + i)) - return false; - return true; -} - -bool CMixer::IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex) -{ - if (IsExternal_Vector[coderIndex]) - return true; - const UInt32 startIndex = _bi.Coder_to_Stream[coderIndex]; - const UInt32 numStreams = _bi.Coders[coderIndex].NumStreams; - for (UInt32 i = 0; i < numStreams; i++) - { - const UInt32 si = startIndex + i; - if (_bi.IsStream_in_PackStreams(si)) - continue; - - const int bond = _bi.FindBond_for_PackStream(si); - if (bond < 0) - throw 20150213; - - if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[(unsigned)bond].UnpackIndex)) - return true; - } - return false; -} - - - - -#ifdef USE_MIXER_ST - -CMixerST::CMixerST(bool encodeMode): - CMixer(encodeMode) - {} - -CMixerST::~CMixerST() {} - -void CMixerST::AddCoder(const CCreatedCoder &cod) -{ - IsFilter_Vector.Add(cod.IsFilter); - IsExternal_Vector.Add(cod.IsExternal); - // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; - CCoderST &c2 = _coders.AddNew(); - c2.NumStreams = cod.NumStreams; - c2.Coder = cod.Coder; - c2.Coder2 = cod.Coder2; - - /* - if (isFilter) - { - c2.CanRead = true; - c2.CanWrite = true; - } - else - */ - { - IUnknown *unk = (cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2); - { - Z7_DECL_CMyComPtr_QI_FROM(ISequentialInStream, s, unk) - c2.CanRead = (s != NULL); - } - { - Z7_DECL_CMyComPtr_QI_FROM(ISequentialOutStream, s, unk) - c2.CanWrite = (s != NULL); - } - } -} - -CCoder &CMixerST::GetCoder(unsigned index) -{ - return _coders[index]; -} - -HRESULT CMixerST::ReInit2() { return S_OK; } - -HRESULT CMixerST::GetInStream2( - ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 outStreamIndex, ISequentialInStream **inStreamRes) -{ - UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0; - - if (EncodeMode) - { - _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex); - if (coderStreamIndex != 0) - return E_NOTIMPL; - } - - const CCoder &coder = _coders[coderIndex]; - - CMyComPtr seqInStream; - coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream); - if (!seqInStream) - return E_NOTIMPL; - - const UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams; - const UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex]; - - bool isSet = false; - - if (numInStreams == 1) - { - CMyComPtr setStream; - coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); - if (setStream) - { - CMyComPtr seqInStream2; - RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)) - RINOK(setStream->SetInStream(seqInStream2)) - isSet = true; - } - } - - if (!isSet && numInStreams != 0) - { - CMyComPtr setStream2; - coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); - if (!setStream2) - return E_NOTIMPL; - - for (UInt32 i = 0; i < numInStreams; i++) - { - CMyComPtr seqInStream2; - RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2)) - RINOK(setStream2->SetInStream2(i, seqInStream2)) - } - } - - *inStreamRes = seqInStream.Detach(); - return S_OK; -} - - -HRESULT CMixerST::GetInStream( - ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 inStreamIndex, ISequentialInStream **inStreamRes) -{ - CMyComPtr seqInStream; - - { - int index = -1; - if (EncodeMode) - { - if (_bi.UnpackCoder == inStreamIndex) - index = 0; - } - else - index = _bi.FindStream_in_PackStreams(inStreamIndex); - - if (index >= 0) - { - seqInStream = inStreams[(unsigned)index]; - *inStreamRes = seqInStream.Detach(); - return S_OK; - } - } - - const int bond = FindBond_for_Stream( - true, // forInputStream - inStreamIndex); - if (bond < 0) - return E_INVALIDARG; - - RINOK(GetInStream2(inStreams, /* inSizes, */ - _bi.Bonds[(unsigned)bond].Get_OutIndex(EncodeMode), &seqInStream)) - - while (_binderStreams.Size() <= (unsigned)bond) - _binderStreams.AddNew(); - CStBinderStream &bs = _binderStreams[(unsigned)bond]; - - if (bs.StreamRef || bs.InStreamSpec) - return E_NOTIMPL; - - CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize; - bs.StreamRef = spec; - bs.InStreamSpec = spec; - - spec->SetStream(seqInStream); - spec->Init(); - - seqInStream = bs.InStreamSpec; - - *inStreamRes = seqInStream.Detach(); - return S_OK; -} - - -HRESULT CMixerST::GetOutStream( - ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ - UInt32 outStreamIndex, ISequentialOutStream **outStreamRes) -{ - CMyComPtr seqOutStream; - - { - int index = -1; - if (!EncodeMode) - { - if (_bi.UnpackCoder == outStreamIndex) - index = 0; - } - else - index = _bi.FindStream_in_PackStreams(outStreamIndex); - - if (index >= 0) - { - seqOutStream = outStreams[(unsigned)index]; - *outStreamRes = seqOutStream.Detach(); - return S_OK; - } - } - - const int bond = FindBond_for_Stream( - false, // forInputStream - outStreamIndex); - if (bond < 0) - return E_INVALIDARG; - - const UInt32 inStreamIndex = _bi.Bonds[(unsigned)bond].Get_InIndex(EncodeMode); - - UInt32 coderIndex = inStreamIndex; - UInt32 coderStreamIndex = 0; - - if (!EncodeMode) - _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); - - CCoder &coder = _coders[coderIndex]; - - /* - if (!coder.Coder) - return E_NOTIMPL; - */ - - coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream); - if (!seqOutStream) - return E_NOTIMPL; - - const UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; - const UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; - - bool isSet = false; - - if (numOutStreams == 1) - { - CMyComPtr setOutStream; - coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); - if (setOutStream) - { - CMyComPtr seqOutStream2; - RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)) - RINOK(setOutStream->SetOutStream(seqOutStream2)) - isSet = true; - } - } - - if (!isSet && numOutStreams != 0) - { - return E_NOTIMPL; - /* - CMyComPtr setStream2; - coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); - if (!setStream2) - return E_NOTIMPL; - for (UInt32 i = 0; i < numOutStreams; i++) - { - CMyComPtr seqOutStream2; - RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2)) - RINOK(setStream2->SetOutStream2(i, seqOutStream2)) - } - */ - } - - while (_binderStreams.Size() <= (unsigned)bond) - _binderStreams.AddNew(); - CStBinderStream &bs = _binderStreams[(unsigned)bond]; - - if (bs.StreamRef || bs.OutStreamSpec) - return E_NOTIMPL; - - COutStreamCalcSize *spec = new COutStreamCalcSize; - bs.StreamRef = (ISequentialOutStream *)spec; - bs.OutStreamSpec = spec; - - spec->SetStream(seqOutStream); - spec->Init(); - - seqOutStream = bs.OutStreamSpec; - - *outStreamRes = seqOutStream.Detach(); - return S_OK; -} - - -static HRESULT GetError(HRESULT res, HRESULT res2) -{ - if (res == res2) - return res; - if (res == S_OK) - return res2; - if (res == k_My_HRESULT_WritingWasCut) - { - if (res2 != S_OK) - return res2; - } - return res; -} - - -HRESULT CMixerST::FinishStream(UInt32 streamIndex) -{ - { - int index = -1; - if (!EncodeMode) - { - if (_bi.UnpackCoder == streamIndex) - index = 0; - } - else - index = _bi.FindStream_in_PackStreams(streamIndex); - - if (index >= 0) - return S_OK; - } - - const int bond = FindBond_for_Stream( - false, // forInputStream - streamIndex); - if (bond < 0) - return E_INVALIDARG; - - const UInt32 inStreamIndex = _bi.Bonds[(unsigned)bond].Get_InIndex(EncodeMode); - - UInt32 coderIndex = inStreamIndex; - UInt32 coderStreamIndex = 0; - if (!EncodeMode) - _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); - - CCoder &coder = _coders[coderIndex]; - CMyComPtr finish; - coder.QueryInterface(IID_IOutStreamFinish, (void **)&finish); - HRESULT res = S_OK; - if (finish) - { - res = finish->OutStreamFinish(); - } - return GetError(res, FinishCoder(coderIndex)); -} - - -HRESULT CMixerST::FinishCoder(UInt32 coderIndex) -{ - CCoder &coder = _coders[coderIndex]; - - const UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; - const UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; - - HRESULT res = S_OK; - for (unsigned i = 0; i < numOutStreams; i++) - res = GetError(res, FinishStream(startIndex + i)); - return res; -} - - -void CMixerST::SelectMainCoder(bool useFirst) -{ - unsigned ci = _bi.UnpackCoder; - - int firstNonFilter = -1; - unsigned firstAllowed = ci; - - for (;;) - { - const CCoderST &coder = _coders[ci]; - // break; - - if (ci != _bi.UnpackCoder) - if (EncodeMode ? !coder.CanWrite : !coder.CanRead) - { - firstAllowed = ci; - firstNonFilter = -2; - } - - if (coder.NumStreams != 1) - break; - - const UInt32 st = _bi.Coder_to_Stream[ci]; - if (_bi.IsStream_in_PackStreams(st)) - break; - const int bond = _bi.FindBond_for_PackStream(st); - if (bond < 0) - throw 20150213; - - if (EncodeMode ? !coder.CanRead : !coder.CanWrite) - break; - - if (firstNonFilter == -1 && !IsFilter_Vector[ci]) - firstNonFilter = (int)ci; - - ci = _bi.Bonds[(unsigned)bond].UnpackIndex; - } - - if (useFirst) - ci = firstAllowed; - else if (firstNonFilter >= 0) - ci = (unsigned)firstNonFilter; - - MainCoderIndex = ci; -} - - -HRESULT CMixerST::Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress, - bool &dataAfterEnd_Error) -{ - // InternalPackSizeError = false; - dataAfterEnd_Error = false; - - _binderStreams.Clear(); - const unsigned ci = MainCoderIndex; - - const CCoder &mainCoder = _coders[MainCoderIndex]; - - CObjectVector< CMyComPtr > seqInStreams; - CObjectVector< CMyComPtr > seqOutStreams; - - const UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams; - const UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams; - - const UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci]; - const UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci]; - - UInt32 i; - - for (i = 0; i < numInStreams; i++) - { - CMyComPtr seqInStream; - RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)) - seqInStreams.Add(seqInStream); - } - - for (i = 0; i < numOutStreams; i++) - { - CMyComPtr seqOutStream; - RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream)) - seqOutStreams.Add(seqOutStream); - } - - CRecordVector< ISequentialInStream * > seqInStreamsSpec; - CRecordVector< ISequentialOutStream * > seqOutStreamsSpec; - - for (i = 0; i < numInStreams; i++) - seqInStreamsSpec.Add(seqInStreams[i]); - for (i = 0; i < numOutStreams; i++) - seqOutStreamsSpec.Add(seqOutStreams[i]); - - for (i = 0; i < _coders.Size(); i++) - { - if (i == ci) - continue; - - CCoder &coder = _coders[i]; - - if (EncodeMode) - { - CMyComPtr initEncoder; - coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder); - if (initEncoder) - { - RINOK(initEncoder->InitEncoder()) - } - } - else - { - CMyComPtr setOutStreamSize; - coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); - if (setOutStreamSize) - { - RINOK(setOutStreamSize->SetOutStreamSize( - EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer)) - } - } - } - - const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : mainCoder.PackSizePointers.ConstData(); - const UInt64 * const *outSizes2 = EncodeMode ? mainCoder.PackSizePointers.ConstData() : &mainCoder.UnpackSizePointer; - - HRESULT res; - if (mainCoder.Coder) - { - res = mainCoder.Coder->Code( - seqInStreamsSpec[0], seqOutStreamsSpec[0], - isSizes2[0], outSizes2[0], - progress); - } - else - { - res = mainCoder.Coder2->Code( - seqInStreamsSpec.ConstData(), isSizes2, numInStreams, - seqOutStreamsSpec.ConstData(), outSizes2, numOutStreams, - progress); - } - - if (res == k_My_HRESULT_WritingWasCut) - res = S_OK; - - if (res == S_OK || res == S_FALSE) - { - res = GetError(res, FinishCoder(ci)); - } - - for (i = 0; i < _binderStreams.Size(); i++) - { - const CStBinderStream &bs = _binderStreams[i]; - if (bs.InStreamSpec) - bs.InStreamSpec->ReleaseStream(); - else - bs.OutStreamSpec->ReleaseStream(); - } - - if (res == k_My_HRESULT_WritingWasCut) - res = S_OK; - - if (res != S_OK) - return res; - - for (i = 0; i < _coders.Size(); i++) - { - RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /*, InternalPackSizeError */)) - } - - return S_OK; -} - - -HRESULT CMixerST::GetMainUnpackStream( - ISequentialInStream * const *inStreams, - ISequentialInStream **inStreamRes) -{ - CMyComPtr seqInStream; - - RINOK(GetInStream2(inStreams, /* inSizes, */ - _bi.UnpackCoder, &seqInStream)) - - FOR_VECTOR (i, _coders) - { - CCoder &coder = _coders[i]; - CMyComPtr setOutStreamSize; - coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); - if (setOutStreamSize) - { - RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer)) - } - } - - *inStreamRes = seqInStream.Detach(); - return S_OK; -} - - -UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const -{ - const CStBinderStream &bs = _binderStreams[bondIndex]; - if (bs.InStreamSpec) - return bs.InStreamSpec->GetSize(); - return bs.OutStreamSpec->GetSize(); -} - -#endif - - - - - - -#ifdef USE_MIXER_MT - - -void CCoderMT::Execute() -{ - try - { - Code(NULL); - } - catch(...) - { - Result = E_FAIL; - } -} - -void CCoderMT::Code(ICompressProgressInfo *progress) -{ - unsigned numInStreams = EncodeMode ? 1 : NumStreams; - unsigned numOutStreams = EncodeMode ? NumStreams : 1; - - InStreamPointers.ClearAndReserve(numInStreams); - OutStreamPointers.ClearAndReserve(numOutStreams); - - unsigned i; - - for (i = 0; i < numInStreams; i++) - InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); - - for (i = 0; i < numOutStreams; i++) - OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); - - // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers. - /* - if (UnpackSizePointer) - UnpackSizePointer = &UnpackSize; - for (i = 0; i < NumStreams; i++) - if (PackSizePointers[i]) - PackSizePointers[i] = &PackSizes[i]; - */ - - CReleaser releaser(*this); - - if (Coder) - Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], - EncodeMode ? UnpackSizePointer : PackSizePointers[0], - EncodeMode ? PackSizePointers[0] : UnpackSizePointer, - progress); - else - Result = Coder2->Code( - InStreamPointers.ConstData(), EncodeMode ? &UnpackSizePointer : PackSizePointers.ConstData(), numInStreams, - OutStreamPointers.ConstData(), EncodeMode ? PackSizePointers.ConstData(): &UnpackSizePointer, numOutStreams, - progress); -} - -HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo) -{ - CMixer::SetBindInfo(bindInfo); - - _streamBinders.Clear(); - FOR_VECTOR (i, _bi.Bonds) - { - // RINOK(_streamBinders.AddNew().CreateEvents()) - _streamBinders.AddNew(); - } - return S_OK; -} - -void CMixerMT::AddCoder(const CCreatedCoder &cod) -{ - IsFilter_Vector.Add(cod.IsFilter); - IsExternal_Vector.Add(cod.IsExternal); - // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; - CCoderMT &c2 = _coders.AddNew(); - c2.NumStreams = cod.NumStreams; - c2.Coder = cod.Coder; - c2.Coder2 = cod.Coder2; - c2.EncodeMode = EncodeMode; -} - -CCoder &CMixerMT::GetCoder(unsigned index) -{ - return _coders[index]; -} - -HRESULT CMixerMT::ReInit2() -{ - FOR_VECTOR (i, _streamBinders) - { - RINOK(_streamBinders[i].Create_ReInit()) - } - return S_OK; -} - -void CMixerMT::SelectMainCoder(bool useFirst) -{ - unsigned ci = _bi.UnpackCoder; - - if (!useFirst) - for (;;) - { - if (_coders[ci].NumStreams != 1) - break; - if (!IsFilter_Vector[ci]) - break; - - UInt32 st = _bi.Coder_to_Stream[ci]; - if (_bi.IsStream_in_PackStreams(st)) - break; - const int bond = _bi.FindBond_for_PackStream(st); - if (bond < 0) - throw 20150213; - ci = _bi.Bonds[(unsigned)bond].UnpackIndex; - } - - MainCoderIndex = ci; -} - -HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams) -{ - unsigned i; - - for (i = 0; i < _coders.Size(); i++) - { - CCoderMT &coderInfo = _coders[i]; - const CCoderStreamsInfo &csi = _bi.Coders[i]; - - UInt32 j; - - const unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams; - const unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1; - - coderInfo.InStreams.Clear(); - for (j = 0; j < numInStreams; j++) - coderInfo.InStreams.AddNew(); - - coderInfo.OutStreams.Clear(); - for (j = 0; j < numOutStreams; j++) - coderInfo.OutStreams.AddNew(); - } - - for (i = 0; i < _bi.Bonds.Size(); i++) - { - const CBond &bond = _bi.Bonds[i]; - - UInt32 inCoderIndex, inCoderStreamIndex; - UInt32 outCoderIndex, outCoderStreamIndex; - - { - UInt32 coderIndex, coderStreamIndex; - _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex); - - inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex; - outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex; - - inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex; - outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0; - } - - _streamBinders[i].CreateStreams2( - _coders[inCoderIndex].InStreams[inCoderStreamIndex], - _coders[outCoderIndex].OutStreams[outCoderStreamIndex]); - - CMyComPtr inSetSize, outSetSize; - _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize); - _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize); - if (inSetSize && outSetSize) - { - const UInt32 kBufSize = 1 << 19; - inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); - outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); - } - } - - { - CCoderMT &cod = _coders[_bi.UnpackCoder]; - if (EncodeMode) - cod.InStreams[0] = inStreams[0]; - else - cod.OutStreams[0] = outStreams[0]; - } - - for (i = 0; i < _bi.PackStreams.Size(); i++) - { - UInt32 coderIndex, coderStreamIndex; - _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex); - CCoderMT &cod = _coders[coderIndex]; - if (EncodeMode) - cod.OutStreams[coderStreamIndex] = outStreams[i]; - else - cod.InStreams[coderStreamIndex] = inStreams[i]; - } - - return S_OK; -} - -HRESULT CMixerMT::ReturnIfError(HRESULT code) -{ - FOR_VECTOR (i, _coders) - if (_coders[i].Result == code) - return code; - return S_OK; -} - -HRESULT CMixerMT::Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress, - bool &dataAfterEnd_Error) -{ - // InternalPackSizeError = false; - dataAfterEnd_Error = false; - - Init(inStreams, outStreams); - - unsigned i; - for (i = 0; i < _coders.Size(); i++) - if (i != MainCoderIndex) - { - const WRes wres = _coders[i].Create(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - - for (i = 0; i < _coders.Size(); i++) - if (i != MainCoderIndex) - { - const WRes wres = _coders[i].Start(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - - _coders[MainCoderIndex].Code(progress); - - WRes wres = 0; - for (i = 0; i < _coders.Size(); i++) - if (i != MainCoderIndex) - { - WRes wres2 = _coders[i].WaitExecuteFinish(); - if (wres == 0) - wres = wres2; - } - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - - RINOK(ReturnIfError(E_ABORT)) - RINOK(ReturnIfError(E_OUTOFMEMORY)) - - for (i = 0; i < _coders.Size(); i++) - { - HRESULT result = _coders[i].Result; - if (result != S_OK - && result != k_My_HRESULT_WritingWasCut - && result != S_FALSE - && result != E_FAIL) - return result; - } - - RINOK(ReturnIfError(S_FALSE)) - - for (i = 0; i < _coders.Size(); i++) - { - HRESULT result = _coders[i].Result; - if (result != S_OK && result != k_My_HRESULT_WritingWasCut) - return result; - } - - for (i = 0; i < _coders.Size(); i++) - { - RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /* , InternalPackSizeError */)) - } - - return S_OK; -} - -UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const -{ - return _streamBinders[bondIndex].ProcessedSize; -} - -#endif - -} +// CoderMixer2.cpp + +#include "StdAfx.h" + +#include "CoderMixer2.h" + +#ifdef USE_MIXER_ST + +Z7_COM7F_IMF(CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (_stream) + result = _stream->Read(data, size, &realProcessed); + _size += realProcessed; + if (size != 0 && realProcessed == 0) + _wasFinished = true; + if (processedSize) + *processedSize = realProcessed; + return result; +} + + +Z7_COM7F_IMF(COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +Z7_COM7F_IMF(COutStreamCalcSize::OutStreamFinish()) +{ + HRESULT result = S_OK; + if (_stream) + { + CMyComPtr outStreamFinish; + _stream.QueryInterface(IID_IOutStreamFinish, &outStreamFinish); + if (outStreamFinish) + result = outStreamFinish->OutStreamFinish(); + } + return result; +} + +#endif + + + + +namespace NCoderMixer2 { + +static void BoolVector_Fill_False(CBoolVector &v, unsigned size) +{ + v.ClearAndSetSize(size); + bool *p = &v[0]; + for (unsigned i = 0; i < size; i++) + p[i] = false; +} + + +HRESULT CCoder::CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const +{ + if (Coder) + { + if (PackSizePointers.IsEmpty() || !PackSizePointers[0]) + return S_OK; + CMyComPtr getInStreamProcessedSize; + Coder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); + // if (!getInStreamProcessedSize) return E_FAIL; + if (getInStreamProcessedSize) + { + UInt64 processed; + RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) + if (processed != (UInt64)(Int64)-1) + { + const UInt64 size = PackSizes[0]; + if (processed < size && Finish) + dataAfterEnd_Error = true; + if (processed > size) + { + // InternalPackSizeError = true; + // return S_FALSE; + } + } + } + } + else if (Coder2) + { + CMyComPtr getInStreamProcessedSize2; + Coder2.QueryInterface(IID_ICompressGetInStreamProcessedSize2, (void **)&getInStreamProcessedSize2); + if (getInStreamProcessedSize2) + FOR_VECTOR (i, PackSizePointers) + { + if (!PackSizePointers[i]) + continue; + UInt64 processed; + RINOK(getInStreamProcessedSize2->GetInStreamProcessedSize2(i, &processed)) + if (processed != (UInt64)(Int64)-1) + { + const UInt64 size = PackSizes[i]; + if (processed < size && Finish) + dataAfterEnd_Error = true; + else if (processed > size) + { + // InternalPackSizeError = true; + // return S_FALSE; + } + } + } + } + + return S_OK; +} + + + +class CBondsChecks +{ + CBoolVector _coderUsed; + + bool Init(); + bool CheckCoder(unsigned coderIndex); +public: + const CBindInfo *BindInfo; + + bool Check(); +}; + +bool CBondsChecks::CheckCoder(unsigned coderIndex) +{ + const CCoderStreamsInfo &coder = BindInfo->Coders[coderIndex]; + + if (coderIndex >= _coderUsed.Size() || _coderUsed[coderIndex]) + return false; + _coderUsed[coderIndex] = true; + + const UInt32 start = BindInfo->Coder_to_Stream[coderIndex]; + + for (unsigned i = 0; i < coder.NumStreams; i++) + { + UInt32 ind = start + i; + + if (BindInfo->IsStream_in_PackStreams(ind)) + continue; + + const int bond = BindInfo->FindBond_for_PackStream(ind); + if (bond < 0) + return false; + if (!CheckCoder(BindInfo->Bonds[(unsigned)bond].UnpackIndex)) + return false; + } + + return true; +} + +bool CBondsChecks::Check() +{ + BoolVector_Fill_False(_coderUsed, BindInfo->Coders.Size()); + + if (!CheckCoder(BindInfo->UnpackCoder)) + return false; + + FOR_VECTOR(i, _coderUsed) + if (!_coderUsed[i]) + return false; + + return true; +} + +void CBindInfo::ClearMaps() +{ + Coder_to_Stream.Clear(); + Stream_to_Coder.Clear(); +} + +bool CBindInfo::CalcMapsAndCheck() +{ + ClearMaps(); + + UInt32 numStreams = 0; + + if (Coders.Size() == 0) + return false; + if (Coders.Size() - 1 != Bonds.Size()) + return false; + + FOR_VECTOR(i, Coders) + { + Coder_to_Stream.Add(numStreams); + + const CCoderStreamsInfo &c = Coders[i]; + + for (unsigned j = 0; j < c.NumStreams; j++) + Stream_to_Coder.Add(i); + + numStreams += c.NumStreams; + } + + if (numStreams != GetNum_Bonds_and_PackStreams()) + return false; + + CBondsChecks bc; + bc.BindInfo = this; + return bc.Check(); +} + + +void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) +{ + Finish = finish; + + if (unpackSize) + { + UnpackSize = *unpackSize; + UnpackSizePointer = &UnpackSize; + } + else + { + UnpackSize = 0; + UnpackSizePointer = NULL; + } + + PackSizes.ClearAndSetSize((unsigned)NumStreams); + PackSizePointers.ClearAndSetSize((unsigned)NumStreams); + + for (unsigned i = 0; i < NumStreams; i++) + { + if (packSizes && packSizes[i]) + { + PackSizes[i] = *(packSizes[i]); + PackSizePointers[i] = &PackSizes[i]; + } + else + { + PackSizes[i] = 0; + PackSizePointers[i] = NULL; + } + } +} + +bool CMixer::Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex) +{ + if (coderIndex == _bi.UnpackCoder) + return true; + + const int bond = _bi.FindBond_for_UnpackStream(coderIndex); + if (bond < 0) + throw 20150213; + + /* + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(_bi.Bonds[(unsigned)bond].PackIndex, coderIndex, coderStreamIndex); + */ + const UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[(unsigned)bond].PackIndex]; + + if (!IsFilter_Vector[nextCoder]) + return false; + + return Is_UnpackSize_Correct_for_Coder(nextCoder); +} + +bool CMixer::Is_PackSize_Correct_for_Stream(UInt32 streamIndex) +{ + if (_bi.IsStream_in_PackStreams(streamIndex)) + return true; + + const int bond = _bi.FindBond_for_PackStream(streamIndex); + if (bond < 0) + throw 20150213; + + const UInt32 nextCoder = _bi.Bonds[(unsigned)bond].UnpackIndex; + + if (!IsFilter_Vector[nextCoder]) + return false; + + return Is_PackSize_Correct_for_Coder(nextCoder); +} + +bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex) +{ + const UInt32 startIndex = _bi.Coder_to_Stream[coderIndex]; + const UInt32 numStreams = _bi.Coders[coderIndex].NumStreams; + for (UInt32 i = 0; i < numStreams; i++) + if (!Is_PackSize_Correct_for_Stream(startIndex + i)) + return false; + return true; +} + +bool CMixer::IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex) +{ + if (IsExternal_Vector[coderIndex]) + return true; + const UInt32 startIndex = _bi.Coder_to_Stream[coderIndex]; + const UInt32 numStreams = _bi.Coders[coderIndex].NumStreams; + for (UInt32 i = 0; i < numStreams; i++) + { + const UInt32 si = startIndex + i; + if (_bi.IsStream_in_PackStreams(si)) + continue; + + const int bond = _bi.FindBond_for_PackStream(si); + if (bond < 0) + throw 20150213; + + if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[(unsigned)bond].UnpackIndex)) + return true; + } + return false; +} + + + + +#ifdef USE_MIXER_ST + +CMixerST::CMixerST(bool encodeMode): + CMixer(encodeMode) + {} + +CMixerST::~CMixerST() {} + +void CMixerST::AddCoder(const CCreatedCoder &cod) +{ + IsFilter_Vector.Add(cod.IsFilter); + IsExternal_Vector.Add(cod.IsExternal); + // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; + CCoderST &c2 = _coders.AddNew(); + c2.NumStreams = cod.NumStreams; + c2.Coder = cod.Coder; + c2.Coder2 = cod.Coder2; + + /* + if (isFilter) + { + c2.CanRead = true; + c2.CanWrite = true; + } + else + */ + { + IUnknown *unk = (cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2); + { + Z7_DECL_CMyComPtr_QI_FROM(ISequentialInStream, s, unk) + c2.CanRead = (s != NULL); + } + { + Z7_DECL_CMyComPtr_QI_FROM(ISequentialOutStream, s, unk) + c2.CanWrite = (s != NULL); + } + } +} + +CCoder &CMixerST::GetCoder(unsigned index) +{ + return _coders[index]; +} + +HRESULT CMixerST::ReInit2() { return S_OK; } + +HRESULT CMixerST::GetInStream2( + ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 outStreamIndex, ISequentialInStream **inStreamRes) +{ + UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0; + + if (EncodeMode) + { + _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex); + if (coderStreamIndex != 0) + return E_NOTIMPL; + } + + const CCoder &coder = _coders[coderIndex]; + + CMyComPtr seqInStream; + coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream); + if (!seqInStream) + return E_NOTIMPL; + + const UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams; + const UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex]; + + bool isSet = false; + + if (numInStreams == 1) + { + CMyComPtr setStream; + coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream); + if (setStream) + { + CMyComPtr seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2)) + RINOK(setStream->SetInStream(seqInStream2)) + isSet = true; + } + } + + if (!isSet && numInStreams != 0) + { + CMyComPtr setStream2; + coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + + for (UInt32 i = 0; i < numInStreams; i++) + { + CMyComPtr seqInStream2; + RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2)) + RINOK(setStream2->SetInStream2(i, seqInStream2)) + } + } + + *inStreamRes = seqInStream.Detach(); + return S_OK; +} + + +HRESULT CMixerST::GetInStream( + ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 inStreamIndex, ISequentialInStream **inStreamRes) +{ + CMyComPtr seqInStream; + + { + int index = -1; + if (EncodeMode) + { + if (_bi.UnpackCoder == inStreamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(inStreamIndex); + + if (index >= 0) + { + seqInStream = inStreams[(unsigned)index]; + *inStreamRes = seqInStream.Detach(); + return S_OK; + } + } + + const int bond = FindBond_for_Stream( + true, // forInputStream + inStreamIndex); + if (bond < 0) + return E_INVALIDARG; + + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.Bonds[(unsigned)bond].Get_OutIndex(EncodeMode), &seqInStream)) + + while (_binderStreams.Size() <= (unsigned)bond) + _binderStreams.AddNew(); + CStBinderStream &bs = _binderStreams[(unsigned)bond]; + + if (bs.StreamRef || bs.InStreamSpec) + return E_NOTIMPL; + + CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize; + bs.StreamRef = spec; + bs.InStreamSpec = spec; + + spec->SetStream(seqInStream); + spec->Init(); + + seqInStream = bs.InStreamSpec; + + *inStreamRes = seqInStream.Detach(); + return S_OK; +} + + +HRESULT CMixerST::GetOutStream( + ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ + UInt32 outStreamIndex, ISequentialOutStream **outStreamRes) +{ + CMyComPtr seqOutStream; + + { + int index = -1; + if (!EncodeMode) + { + if (_bi.UnpackCoder == outStreamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(outStreamIndex); + + if (index >= 0) + { + seqOutStream = outStreams[(unsigned)index]; + *outStreamRes = seqOutStream.Detach(); + return S_OK; + } + } + + const int bond = FindBond_for_Stream( + false, // forInputStream + outStreamIndex); + if (bond < 0) + return E_INVALIDARG; + + const UInt32 inStreamIndex = _bi.Bonds[(unsigned)bond].Get_InIndex(EncodeMode); + + UInt32 coderIndex = inStreamIndex; + UInt32 coderStreamIndex = 0; + + if (!EncodeMode) + _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); + + CCoder &coder = _coders[coderIndex]; + + /* + if (!coder.Coder) + return E_NOTIMPL; + */ + + coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream); + if (!seqOutStream) + return E_NOTIMPL; + + const UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; + const UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; + + bool isSet = false; + + if (numOutStreams == 1) + { + CMyComPtr setOutStream; + coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream); + if (setOutStream) + { + CMyComPtr seqOutStream2; + RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2)) + RINOK(setOutStream->SetOutStream(seqOutStream2)) + isSet = true; + } + } + + if (!isSet && numOutStreams != 0) + { + return E_NOTIMPL; + /* + CMyComPtr setStream2; + coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2); + if (!setStream2) + return E_NOTIMPL; + for (UInt32 i = 0; i < numOutStreams; i++) + { + CMyComPtr seqOutStream2; + RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2)) + RINOK(setStream2->SetOutStream2(i, seqOutStream2)) + } + */ + } + + while (_binderStreams.Size() <= (unsigned)bond) + _binderStreams.AddNew(); + CStBinderStream &bs = _binderStreams[(unsigned)bond]; + + if (bs.StreamRef || bs.OutStreamSpec) + return E_NOTIMPL; + + COutStreamCalcSize *spec = new COutStreamCalcSize; + bs.StreamRef = (ISequentialOutStream *)spec; + bs.OutStreamSpec = spec; + + spec->SetStream(seqOutStream); + spec->Init(); + + seqOutStream = bs.OutStreamSpec; + + *outStreamRes = seqOutStream.Detach(); + return S_OK; +} + + +static HRESULT GetError(HRESULT res, HRESULT res2) +{ + if (res == res2) + return res; + if (res == S_OK) + return res2; + if (res == k_My_HRESULT_WritingWasCut) + { + if (res2 != S_OK) + return res2; + } + return res; +} + + +HRESULT CMixerST::FinishStream(UInt32 streamIndex) +{ + { + int index = -1; + if (!EncodeMode) + { + if (_bi.UnpackCoder == streamIndex) + index = 0; + } + else + index = _bi.FindStream_in_PackStreams(streamIndex); + + if (index >= 0) + return S_OK; + } + + const int bond = FindBond_for_Stream( + false, // forInputStream + streamIndex); + if (bond < 0) + return E_INVALIDARG; + + const UInt32 inStreamIndex = _bi.Bonds[(unsigned)bond].Get_InIndex(EncodeMode); + + UInt32 coderIndex = inStreamIndex; + UInt32 coderStreamIndex = 0; + if (!EncodeMode) + _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex); + + CCoder &coder = _coders[coderIndex]; + CMyComPtr finish; + coder.QueryInterface(IID_IOutStreamFinish, (void **)&finish); + HRESULT res = S_OK; + if (finish) + { + res = finish->OutStreamFinish(); + } + return GetError(res, FinishCoder(coderIndex)); +} + + +HRESULT CMixerST::FinishCoder(UInt32 coderIndex) +{ + CCoder &coder = _coders[coderIndex]; + + const UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1; + const UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex; + + HRESULT res = S_OK; + for (unsigned i = 0; i < numOutStreams; i++) + res = GetError(res, FinishStream(startIndex + i)); + return res; +} + + +void CMixerST::SelectMainCoder(bool useFirst) +{ + unsigned ci = _bi.UnpackCoder; + + int firstNonFilter = -1; + unsigned firstAllowed = ci; + + for (;;) + { + const CCoderST &coder = _coders[ci]; + // break; + + if (ci != _bi.UnpackCoder) + if (EncodeMode ? !coder.CanWrite : !coder.CanRead) + { + firstAllowed = ci; + firstNonFilter = -2; + } + + if (coder.NumStreams != 1) + break; + + const UInt32 st = _bi.Coder_to_Stream[ci]; + if (_bi.IsStream_in_PackStreams(st)) + break; + const int bond = _bi.FindBond_for_PackStream(st); + if (bond < 0) + throw 20150213; + + if (EncodeMode ? !coder.CanRead : !coder.CanWrite) + break; + + if (firstNonFilter == -1 && !IsFilter_Vector[ci]) + firstNonFilter = (int)ci; + + ci = _bi.Bonds[(unsigned)bond].UnpackIndex; + } + + if (useFirst) + ci = firstAllowed; + else if (firstNonFilter >= 0) + ci = (unsigned)firstNonFilter; + + MainCoderIndex = ci; +} + + +HRESULT CMixerST::Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) +{ + // InternalPackSizeError = false; + dataAfterEnd_Error = false; + + _binderStreams.Clear(); + const unsigned ci = MainCoderIndex; + + const CCoder &mainCoder = _coders[MainCoderIndex]; + + CObjectVector< CMyComPtr > seqInStreams; + CObjectVector< CMyComPtr > seqOutStreams; + + const UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams; + const UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams; + + const UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci]; + const UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci]; + + UInt32 i; + + for (i = 0; i < numInStreams; i++) + { + CMyComPtr seqInStream; + RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream)) + seqInStreams.Add(seqInStream); + } + + for (i = 0; i < numOutStreams; i++) + { + CMyComPtr seqOutStream; + RINOK(GetOutStream(outStreams, /* outSizes, */ startOutIndex + i, &seqOutStream)) + seqOutStreams.Add(seqOutStream); + } + + CRecordVector< ISequentialInStream * > seqInStreamsSpec; + CRecordVector< ISequentialOutStream * > seqOutStreamsSpec; + + for (i = 0; i < numInStreams; i++) + seqInStreamsSpec.Add(seqInStreams[i]); + for (i = 0; i < numOutStreams; i++) + seqOutStreamsSpec.Add(seqOutStreams[i]); + + for (i = 0; i < _coders.Size(); i++) + { + if (i == ci) + continue; + + CCoder &coder = _coders[i]; + + if (EncodeMode) + { + CMyComPtr initEncoder; + coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder); + if (initEncoder) + { + RINOK(initEncoder->InitEncoder()) + } + } + else + { + CMyComPtr setOutStreamSize; + coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); + if (setOutStreamSize) + { + RINOK(setOutStreamSize->SetOutStreamSize( + EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer)) + } + } + } + + const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : mainCoder.PackSizePointers.ConstData(); + const UInt64 * const *outSizes2 = EncodeMode ? mainCoder.PackSizePointers.ConstData() : &mainCoder.UnpackSizePointer; + + HRESULT res; + if (mainCoder.Coder) + { + res = mainCoder.Coder->Code( + seqInStreamsSpec[0], seqOutStreamsSpec[0], + isSizes2[0], outSizes2[0], + progress); + } + else + { + res = mainCoder.Coder2->Code( + seqInStreamsSpec.ConstData(), isSizes2, numInStreams, + seqOutStreamsSpec.ConstData(), outSizes2, numOutStreams, + progress); + } + + if (res == k_My_HRESULT_WritingWasCut) + res = S_OK; + + if (res == S_OK || res == S_FALSE) + { + res = GetError(res, FinishCoder(ci)); + } + + for (i = 0; i < _binderStreams.Size(); i++) + { + const CStBinderStream &bs = _binderStreams[i]; + if (bs.InStreamSpec) + bs.InStreamSpec->ReleaseStream(); + else + bs.OutStreamSpec->ReleaseStream(); + } + + if (res == k_My_HRESULT_WritingWasCut) + res = S_OK; + + if (res != S_OK) + return res; + + for (i = 0; i < _coders.Size(); i++) + { + RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /*, InternalPackSizeError */)) + } + + return S_OK; +} + + +HRESULT CMixerST::GetMainUnpackStream( + ISequentialInStream * const *inStreams, + ISequentialInStream **inStreamRes) +{ + CMyComPtr seqInStream; + + RINOK(GetInStream2(inStreams, /* inSizes, */ + _bi.UnpackCoder, &seqInStream)) + + FOR_VECTOR (i, _coders) + { + CCoder &coder = _coders[i]; + CMyComPtr setOutStreamSize; + coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize); + if (setOutStreamSize) + { + RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer)) + } + } + + *inStreamRes = seqInStream.Detach(); + return S_OK; +} + + +UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const +{ + const CStBinderStream &bs = _binderStreams[bondIndex]; + if (bs.InStreamSpec) + return bs.InStreamSpec->GetSize(); + return bs.OutStreamSpec->GetSize(); +} + +#endif + + + + + + +#ifdef USE_MIXER_MT + + +void CCoderMT::Execute() +{ + try + { + Code(NULL); + } + catch(...) + { + Result = E_FAIL; + } +} + +void CCoderMT::Code(ICompressProgressInfo *progress) +{ + unsigned numInStreams = EncodeMode ? 1 : NumStreams; + unsigned numOutStreams = EncodeMode ? NumStreams : 1; + + InStreamPointers.ClearAndReserve(numInStreams); + OutStreamPointers.ClearAndReserve(numOutStreams); + + unsigned i; + + for (i = 0; i < numInStreams; i++) + InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]); + + for (i = 0; i < numOutStreams; i++) + OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]); + + // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers. + /* + if (UnpackSizePointer) + UnpackSizePointer = &UnpackSize; + for (i = 0; i < NumStreams; i++) + if (PackSizePointers[i]) + PackSizePointers[i] = &PackSizes[i]; + */ + + CReleaser releaser(*this); + + if (Coder) + Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0], + EncodeMode ? UnpackSizePointer : PackSizePointers[0], + EncodeMode ? PackSizePointers[0] : UnpackSizePointer, + progress); + else + Result = Coder2->Code( + InStreamPointers.ConstData(), EncodeMode ? &UnpackSizePointer : PackSizePointers.ConstData(), numInStreams, + OutStreamPointers.ConstData(), EncodeMode ? PackSizePointers.ConstData(): &UnpackSizePointer, numOutStreams, + progress); +} + +HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo) +{ + CMixer::SetBindInfo(bindInfo); + + _streamBinders.Clear(); + FOR_VECTOR (i, _bi.Bonds) + { + // RINOK(_streamBinders.AddNew().CreateEvents()) + _streamBinders.AddNew(); + } + return S_OK; +} + +void CMixerMT::AddCoder(const CCreatedCoder &cod) +{ + IsFilter_Vector.Add(cod.IsFilter); + IsExternal_Vector.Add(cod.IsExternal); + // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()]; + CCoderMT &c2 = _coders.AddNew(); + c2.NumStreams = cod.NumStreams; + c2.Coder = cod.Coder; + c2.Coder2 = cod.Coder2; + c2.EncodeMode = EncodeMode; +} + +CCoder &CMixerMT::GetCoder(unsigned index) +{ + return _coders[index]; +} + +HRESULT CMixerMT::ReInit2() +{ + FOR_VECTOR (i, _streamBinders) + { + RINOK(_streamBinders[i].Create_ReInit()) + } + return S_OK; +} + +void CMixerMT::SelectMainCoder(bool useFirst) +{ + unsigned ci = _bi.UnpackCoder; + + if (!useFirst) + for (;;) + { + if (_coders[ci].NumStreams != 1) + break; + if (!IsFilter_Vector[ci]) + break; + + UInt32 st = _bi.Coder_to_Stream[ci]; + if (_bi.IsStream_in_PackStreams(st)) + break; + const int bond = _bi.FindBond_for_PackStream(st); + if (bond < 0) + throw 20150213; + ci = _bi.Bonds[(unsigned)bond].UnpackIndex; + } + + MainCoderIndex = ci; +} + +HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams) +{ + unsigned i; + + for (i = 0; i < _coders.Size(); i++) + { + CCoderMT &coderInfo = _coders[i]; + const CCoderStreamsInfo &csi = _bi.Coders[i]; + + UInt32 j; + + const unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams; + const unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1; + + coderInfo.InStreams.Clear(); + for (j = 0; j < numInStreams; j++) + coderInfo.InStreams.AddNew(); + + coderInfo.OutStreams.Clear(); + for (j = 0; j < numOutStreams; j++) + coderInfo.OutStreams.AddNew(); + } + + for (i = 0; i < _bi.Bonds.Size(); i++) + { + const CBond &bond = _bi.Bonds[i]; + + UInt32 inCoderIndex, inCoderStreamIndex; + UInt32 outCoderIndex, outCoderStreamIndex; + + { + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex); + + inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex; + outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex; + + inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex; + outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0; + } + + _streamBinders[i].CreateStreams2( + _coders[inCoderIndex].InStreams[inCoderStreamIndex], + _coders[outCoderIndex].OutStreams[outCoderStreamIndex]); + + CMyComPtr inSetSize, outSetSize; + _coders[inCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&inSetSize); + _coders[outCoderIndex].QueryInterface(IID_ICompressSetBufSize, (void **)&outSetSize); + if (inSetSize && outSetSize) + { + const UInt32 kBufSize = 1 << 19; + inSetSize->SetInBufSize(inCoderStreamIndex, kBufSize); + outSetSize->SetOutBufSize(outCoderStreamIndex, kBufSize); + } + } + + { + CCoderMT &cod = _coders[_bi.UnpackCoder]; + if (EncodeMode) + cod.InStreams[0] = inStreams[0]; + else + cod.OutStreams[0] = outStreams[0]; + } + + for (i = 0; i < _bi.PackStreams.Size(); i++) + { + UInt32 coderIndex, coderStreamIndex; + _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex); + CCoderMT &cod = _coders[coderIndex]; + if (EncodeMode) + cod.OutStreams[coderStreamIndex] = outStreams[i]; + else + cod.InStreams[coderStreamIndex] = inStreams[i]; + } + + return S_OK; +} + +HRESULT CMixerMT::ReturnIfError(HRESULT code) +{ + FOR_VECTOR (i, _coders) + if (_coders[i].Result == code) + return code; + return S_OK; +} + +HRESULT CMixerMT::Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) +{ + // InternalPackSizeError = false; + dataAfterEnd_Error = false; + + Init(inStreams, outStreams); + + unsigned i; + for (i = 0; i < _coders.Size(); i++) + if (i != MainCoderIndex) + { + const WRes wres = _coders[i].Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + + for (i = 0; i < _coders.Size(); i++) + if (i != MainCoderIndex) + { + const WRes wres = _coders[i].Start(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + + _coders[MainCoderIndex].Code(progress); + + WRes wres = 0; + for (i = 0; i < _coders.Size(); i++) + if (i != MainCoderIndex) + { + WRes wres2 = _coders[i].WaitExecuteFinish(); + if (wres == 0) + wres = wres2; + } + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + + RINOK(ReturnIfError(E_ABORT)) + RINOK(ReturnIfError(E_OUTOFMEMORY)) + + for (i = 0; i < _coders.Size(); i++) + { + HRESULT result = _coders[i].Result; + if (result != S_OK + && result != k_My_HRESULT_WritingWasCut + && result != S_FALSE + && result != E_FAIL) + return result; + } + + RINOK(ReturnIfError(S_FALSE)) + + for (i = 0; i < _coders.Size(); i++) + { + HRESULT result = _coders[i].Result; + if (result != S_OK && result != k_My_HRESULT_WritingWasCut) + return result; + } + + for (i = 0; i < _coders.Size(); i++) + { + RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /* , InternalPackSizeError */)) + } + + return S_OK; +} + +UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const +{ + return _streamBinders[bondIndex].ProcessedSize; +} + +#endif + +} diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h index 93f35a2b9..484a6089a 100644 --- a/CPP/7zip/Archive/Common/CoderMixer2.h +++ b/CPP/7zip/Archive/Common/CoderMixer2.h @@ -1,447 +1,447 @@ -// CoderMixer2.h - -#ifndef ZIP7_INC_CODER_MIXER2_H -#define ZIP7_INC_CODER_MIXER2_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyVector.h" - -#include "../../ICoder.h" - -#include "../../Common/CreateCoder.h" - -#ifdef Z7_ST - #define USE_MIXER_ST -#else - #define USE_MIXER_MT - #ifndef Z7_SFX - #define USE_MIXER_ST - #endif -#endif - -#ifdef USE_MIXER_MT -#include "../../Common/StreamBinder.h" -#include "../../Common/VirtThread.h" -#endif - - - -#ifdef USE_MIXER_ST - -Z7_CLASS_IMP_COM_1( - CSequentialInStreamCalcSize - , ISequentialInStream -) - bool _wasFinished; - CMyComPtr _stream; - UInt64 _size; -public: - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - _wasFinished = false; - } - void ReleaseStream() { _stream.Release(); } - UInt64 GetSize() const { return _size; } - bool WasFinished() const { return _wasFinished; } -}; - - -Z7_CLASS_IMP_COM_2( - COutStreamCalcSize - , ISequentialOutStream - , IOutStreamFinish -) - CMyComPtr _stream; - UInt64 _size; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _size = 0; } - UInt64 GetSize() const { return _size; } -}; - -#endif - - - -namespace NCoderMixer2 { - -struct CBond -{ - UInt32 PackIndex; - UInt32 UnpackIndex; - - UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; } - UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; } -}; - - -struct CCoderStreamsInfo -{ - UInt32 NumStreams; -}; - - -struct CBindInfo -{ - CRecordVector Coders; - CRecordVector Bonds; - CRecordVector PackStreams; - unsigned UnpackCoder; - - unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); } - - int FindBond_for_PackStream(UInt32 packStream) const - { - FOR_VECTOR (i, Bonds) - if (Bonds[i].PackIndex == packStream) - return (int)i; - return -1; - } - - int FindBond_for_UnpackStream(UInt32 unpackStream) const - { - FOR_VECTOR (i, Bonds) - if (Bonds[i].UnpackIndex == unpackStream) - return (int)i; - return -1; - } - - bool SetUnpackCoder() - { - bool isOk = false; - FOR_VECTOR (i, Coders) - { - if (FindBond_for_UnpackStream(i) < 0) - { - if (isOk) - return false; - UnpackCoder = i; - isOk = true; - } - } - return isOk; - } - - bool IsStream_in_PackStreams(UInt32 streamIndex) const - { - return FindStream_in_PackStreams(streamIndex) >= 0; - } - - int FindStream_in_PackStreams(UInt32 streamIndex) const - { - FOR_VECTOR (i, PackStreams) - if (PackStreams[i] == streamIndex) - return (int)i; - return -1; - } - - - // that function is used before Maps is calculated - - UInt32 GetStream_for_Coder(UInt32 coderIndex) const - { - UInt32 streamIndex = 0; - for (UInt32 i = 0; i < coderIndex; i++) - streamIndex += Coders[i].NumStreams; - return streamIndex; - } - - // ---------- Maps Section ---------- - - CRecordVector Coder_to_Stream; - CRecordVector Stream_to_Coder; - - void ClearMaps(); - bool CalcMapsAndCheck(); - - // ---------- End of Maps Section ---------- - - void Clear() - { - Coders.Clear(); - Bonds.Clear(); - PackStreams.Clear(); - - ClearMaps(); - } - - void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const - { - coderIndex = Stream_to_Coder[streamIndex]; - coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex]; - } -}; - - - -class CCoder -{ - Z7_CLASS_NO_COPY(CCoder) -public: - CMyComPtr Coder; - CMyComPtr Coder2; - UInt32 NumStreams; - bool Finish; - - UInt64 UnpackSize; - const UInt64 *UnpackSizePointer; - - CRecordVector PackSizes; - CRecordVector PackSizePointers; - - CCoder(): Finish(false) {} - - void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish); - - HRESULT CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const; - - IUnknown *GetUnknown() const - { - return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; - } - - HRESULT QueryInterface(REFGUID iid, void** pp) const - { - return GetUnknown()->QueryInterface(iid, pp); - } -}; - - - -class CMixer -{ - bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex); - -protected: - CBindInfo _bi; - - int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const - { - if (EncodeMode == forInputStream) - return _bi.FindBond_for_UnpackStream(streamIndex); - else - return _bi.FindBond_for_PackStream(streamIndex); - } - - CBoolVector IsFilter_Vector; - CBoolVector IsExternal_Vector; - bool EncodeMode; -public: - unsigned MainCoderIndex; - - // bool InternalPackSizeError; - - CMixer(bool encodeMode): - EncodeMode(encodeMode), - MainCoderIndex(0) - // , InternalPackSizeError(false) - {} - - virtual ~CMixer() {} - /* - Sequence of calling: - - SetBindInfo(); - for each coder - AddCoder(); - SelectMainCoder(); - - for each file - { - ReInit() - for each coder - SetCoderInfo(); - Code(); - } - */ - - virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) - { - _bi = bindInfo; - IsFilter_Vector.Clear(); - MainCoderIndex = 0; - return S_OK; - } - - virtual void AddCoder(const CCreatedCoder &cod) = 0; - virtual CCoder &GetCoder(unsigned index) = 0; - virtual void SelectMainCoder(bool useFirst) = 0; - virtual HRESULT ReInit2() = 0; - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) = 0; - virtual HRESULT Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress, - bool &dataAfterEnd_Error) = 0; - virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0; - - bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex); - bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex); - bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex); -}; - - - - -#ifdef USE_MIXER_ST - -struct CCoderST: public CCoder -{ - bool CanRead; - bool CanWrite; - - CCoderST(): CanRead(false), CanWrite(false) {} -}; - - -struct CStBinderStream -{ - CSequentialInStreamCalcSize *InStreamSpec; - COutStreamCalcSize *OutStreamSpec; - CMyComPtr StreamRef; - - CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {} -}; - - -class CMixerST: - public IUnknown, - public CMixer, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_CLASS_NO_COPY(CMixerST) - - HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 outStreamIndex, ISequentialInStream **inStreamRes); - HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ - UInt32 inStreamIndex, ISequentialInStream **inStreamRes); - HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ - UInt32 outStreamIndex, ISequentialOutStream **outStreamRes); - - HRESULT FinishStream(UInt32 streamIndex); - HRESULT FinishCoder(UInt32 coderIndex); - -public: - CObjectVector _coders; - - CObjectVector _binderStreams; - - CMixerST(bool encodeMode); - ~CMixerST() Z7_DESTRUCTOR_override; - - virtual void AddCoder(const CCreatedCoder &cod) Z7_override; - virtual CCoder &GetCoder(unsigned index) Z7_override; - virtual void SelectMainCoder(bool useFirst) Z7_override; - virtual HRESULT ReInit2() Z7_override; - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override - { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); } - virtual HRESULT Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress, - bool &dataAfterEnd_Error) Z7_override; - virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override; - - HRESULT GetMainUnpackStream( - ISequentialInStream * const *inStreams, - ISequentialInStream **inStreamRes); -}; - -#endif - - - - -#ifdef USE_MIXER_MT - -class CCoderMT: public CCoder, public CVirtThread -{ - Z7_CLASS_NO_COPY(CCoderMT) - CRecordVector InStreamPointers; - CRecordVector OutStreamPointers; - -private: - virtual void Execute() Z7_override; -public: - bool EncodeMode; - HRESULT Result; - CObjectVector< CMyComPtr > InStreams; - CObjectVector< CMyComPtr > OutStreams; - - void Release() - { - InStreamPointers.Clear(); - OutStreamPointers.Clear(); - unsigned i; - for (i = 0; i < InStreams.Size(); i++) - InStreams[i].Release(); - for (i = 0; i < OutStreams.Size(); i++) - OutStreams[i].Release(); - } - - class CReleaser - { - Z7_CLASS_NO_COPY(CReleaser) - CCoderMT &_c; - public: - CReleaser(CCoderMT &c): _c(c) {} - ~CReleaser() { _c.Release(); } - }; - - CCoderMT(): EncodeMode(false) {} - ~CCoderMT() Z7_DESTRUCTOR_override - { - /* WaitThreadFinish() will be called in ~CVirtThread(). - But we need WaitThreadFinish() call before CCoder destructor, - and before destructors of this class members. - */ - CVirtThread::WaitThreadFinish(); - } - - void Code(ICompressProgressInfo *progress); -}; - - -class CMixerMT: - public IUnknown, - public CMixer, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_CLASS_NO_COPY(CMixerMT) - - CObjectVector _streamBinders; - - HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); - HRESULT ReturnIfError(HRESULT code); - - // virtual ~CMixerMT() {} -public: - CObjectVector _coders; - - virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) Z7_override; - virtual void AddCoder(const CCreatedCoder &cod) Z7_override; - virtual CCoder &GetCoder(unsigned index) Z7_override; - virtual void SelectMainCoder(bool useFirst) Z7_override; - virtual HRESULT ReInit2() Z7_override; - virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override - { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); } - virtual HRESULT Code( - ISequentialInStream * const *inStreams, - ISequentialOutStream * const *outStreams, - ICompressProgressInfo *progress, - bool &dataAfterEnd_Error) Z7_override; - virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override; - - CMixerMT(bool encodeMode): CMixer(encodeMode) {} -}; - -#endif - -} - -#endif +// CoderMixer2.h + +#ifndef ZIP7_INC_CODER_MIXER2_H +#define ZIP7_INC_CODER_MIXER2_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyVector.h" + +#include "../../ICoder.h" + +#include "../../Common/CreateCoder.h" + +#ifdef Z7_ST + #define USE_MIXER_ST +#else + #define USE_MIXER_MT + #ifndef Z7_SFX + #define USE_MIXER_ST + #endif +#endif + +#ifdef USE_MIXER_MT +#include "../../Common/StreamBinder.h" +#include "../../Common/VirtThread.h" +#endif + + + +#ifdef USE_MIXER_ST + +Z7_CLASS_IMP_COM_1( + CSequentialInStreamCalcSize + , ISequentialInStream +) + bool _wasFinished; + CMyComPtr _stream; + UInt64 _size; +public: + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + _wasFinished = false; + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + bool WasFinished() const { return _wasFinished; } +}; + + +Z7_CLASS_IMP_COM_2( + COutStreamCalcSize + , ISequentialOutStream + , IOutStreamFinish +) + CMyComPtr _stream; + UInt64 _size; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _size = 0; } + UInt64 GetSize() const { return _size; } +}; + +#endif + + + +namespace NCoderMixer2 { + +struct CBond +{ + UInt32 PackIndex; + UInt32 UnpackIndex; + + UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; } + UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; } +}; + + +struct CCoderStreamsInfo +{ + UInt32 NumStreams; +}; + + +struct CBindInfo +{ + CRecordVector Coders; + CRecordVector Bonds; + CRecordVector PackStreams; + unsigned UnpackCoder; + + unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); } + + int FindBond_for_PackStream(UInt32 packStream) const + { + FOR_VECTOR (i, Bonds) + if (Bonds[i].PackIndex == packStream) + return (int)i; + return -1; + } + + int FindBond_for_UnpackStream(UInt32 unpackStream) const + { + FOR_VECTOR (i, Bonds) + if (Bonds[i].UnpackIndex == unpackStream) + return (int)i; + return -1; + } + + bool SetUnpackCoder() + { + bool isOk = false; + FOR_VECTOR (i, Coders) + { + if (FindBond_for_UnpackStream(i) < 0) + { + if (isOk) + return false; + UnpackCoder = i; + isOk = true; + } + } + return isOk; + } + + bool IsStream_in_PackStreams(UInt32 streamIndex) const + { + return FindStream_in_PackStreams(streamIndex) >= 0; + } + + int FindStream_in_PackStreams(UInt32 streamIndex) const + { + FOR_VECTOR (i, PackStreams) + if (PackStreams[i] == streamIndex) + return (int)i; + return -1; + } + + + // that function is used before Maps is calculated + + UInt32 GetStream_for_Coder(UInt32 coderIndex) const + { + UInt32 streamIndex = 0; + for (UInt32 i = 0; i < coderIndex; i++) + streamIndex += Coders[i].NumStreams; + return streamIndex; + } + + // ---------- Maps Section ---------- + + CRecordVector Coder_to_Stream; + CRecordVector Stream_to_Coder; + + void ClearMaps(); + bool CalcMapsAndCheck(); + + // ---------- End of Maps Section ---------- + + void Clear() + { + Coders.Clear(); + Bonds.Clear(); + PackStreams.Clear(); + + ClearMaps(); + } + + void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const + { + coderIndex = Stream_to_Coder[streamIndex]; + coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex]; + } +}; + + + +class CCoder +{ + Z7_CLASS_NO_COPY(CCoder) +public: + CMyComPtr Coder; + CMyComPtr Coder2; + UInt32 NumStreams; + bool Finish; + + UInt64 UnpackSize; + const UInt64 *UnpackSizePointer; + + CRecordVector PackSizes; + CRecordVector PackSizePointers; + + CCoder(): Finish(false) {} + + void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish); + + HRESULT CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const; + + IUnknown *GetUnknown() const + { + return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2; + } + + HRESULT QueryInterface(REFGUID iid, void** pp) const + { + return GetUnknown()->QueryInterface(iid, pp); + } +}; + + + +class CMixer +{ + bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex); + +protected: + CBindInfo _bi; + + int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const + { + if (EncodeMode == forInputStream) + return _bi.FindBond_for_UnpackStream(streamIndex); + else + return _bi.FindBond_for_PackStream(streamIndex); + } + + CBoolVector IsFilter_Vector; + CBoolVector IsExternal_Vector; + bool EncodeMode; +public: + unsigned MainCoderIndex; + + // bool InternalPackSizeError; + + CMixer(bool encodeMode): + EncodeMode(encodeMode), + MainCoderIndex(0) + // , InternalPackSizeError(false) + {} + + virtual ~CMixer() {} + /* + Sequence of calling: + + SetBindInfo(); + for each coder + AddCoder(); + SelectMainCoder(); + + for each file + { + ReInit() + for each coder + SetCoderInfo(); + Code(); + } + */ + + virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) + { + _bi = bindInfo; + IsFilter_Vector.Clear(); + MainCoderIndex = 0; + return S_OK; + } + + virtual void AddCoder(const CCreatedCoder &cod) = 0; + virtual CCoder &GetCoder(unsigned index) = 0; + virtual void SelectMainCoder(bool useFirst) = 0; + virtual HRESULT ReInit2() = 0; + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) = 0; + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) = 0; + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0; + + bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex); + bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex); + bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex); +}; + + + + +#ifdef USE_MIXER_ST + +struct CCoderST: public CCoder +{ + bool CanRead; + bool CanWrite; + + CCoderST(): CanRead(false), CanWrite(false) {} +}; + + +struct CStBinderStream +{ + CSequentialInStreamCalcSize *InStreamSpec; + COutStreamCalcSize *OutStreamSpec; + CMyComPtr StreamRef; + + CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {} +}; + + +class CMixerST: + public IUnknown, + public CMixer, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_CLASS_NO_COPY(CMixerST) + + HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 outStreamIndex, ISequentialInStream **inStreamRes); + HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */ + UInt32 inStreamIndex, ISequentialInStream **inStreamRes); + HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */ + UInt32 outStreamIndex, ISequentialOutStream **outStreamRes); + + HRESULT FinishStream(UInt32 streamIndex); + HRESULT FinishCoder(UInt32 coderIndex); + +public: + CObjectVector _coders; + + CObjectVector _binderStreams; + + CMixerST(bool encodeMode); + ~CMixerST() Z7_DESTRUCTOR_override; + + virtual void AddCoder(const CCreatedCoder &cod) Z7_override; + virtual CCoder &GetCoder(unsigned index) Z7_override; + virtual void SelectMainCoder(bool useFirst) Z7_override; + virtual HRESULT ReInit2() Z7_override; + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); } + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) Z7_override; + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override; + + HRESULT GetMainUnpackStream( + ISequentialInStream * const *inStreams, + ISequentialInStream **inStreamRes); +}; + +#endif + + + + +#ifdef USE_MIXER_MT + +class CCoderMT: public CCoder, public CVirtThread +{ + Z7_CLASS_NO_COPY(CCoderMT) + CRecordVector InStreamPointers; + CRecordVector OutStreamPointers; + +private: + virtual void Execute() Z7_override; +public: + bool EncodeMode; + HRESULT Result; + CObjectVector< CMyComPtr > InStreams; + CObjectVector< CMyComPtr > OutStreams; + + void Release() + { + InStreamPointers.Clear(); + OutStreamPointers.Clear(); + unsigned i; + for (i = 0; i < InStreams.Size(); i++) + InStreams[i].Release(); + for (i = 0; i < OutStreams.Size(); i++) + OutStreams[i].Release(); + } + + class CReleaser + { + Z7_CLASS_NO_COPY(CReleaser) + CCoderMT &_c; + public: + CReleaser(CCoderMT &c): _c(c) {} + ~CReleaser() { _c.Release(); } + }; + + CCoderMT(): EncodeMode(false) {} + ~CCoderMT() Z7_DESTRUCTOR_override + { + /* WaitThreadFinish() will be called in ~CVirtThread(). + But we need WaitThreadFinish() call before CCoder destructor, + and before destructors of this class members. + */ + CVirtThread::WaitThreadFinish(); + } + + void Code(ICompressProgressInfo *progress); +}; + + +class CMixerMT: + public IUnknown, + public CMixer, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_CLASS_NO_COPY(CMixerMT) + + CObjectVector _streamBinders; + + HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams); + HRESULT ReturnIfError(HRESULT code); + + // virtual ~CMixerMT() {} +public: + CObjectVector _coders; + + virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) Z7_override; + virtual void AddCoder(const CCreatedCoder &cod) Z7_override; + virtual CCoder &GetCoder(unsigned index) Z7_override; + virtual void SelectMainCoder(bool useFirst) Z7_override; + virtual HRESULT ReInit2() Z7_override; + virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override + { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); } + virtual HRESULT Code( + ISequentialInStream * const *inStreams, + ISequentialOutStream * const *outStreams, + ICompressProgressInfo *progress, + bool &dataAfterEnd_Error) Z7_override; + virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override; + + CMixerMT(bool encodeMode): CMixer(encodeMode) {} +}; + +#endif + +} + +#endif diff --git a/CPP/7zip/Archive/Common/DummyOutStream.cpp b/CPP/7zip/Archive/Common/DummyOutStream.cpp index 9e8bb6add..f48c32f2f 100644 --- a/CPP/7zip/Archive/Common/DummyOutStream.cpp +++ b/CPP/7zip/Archive/Common/DummyOutStream.cpp @@ -1,17 +1,17 @@ -// DummyOutStream.cpp - -#include "StdAfx.h" - -#include "DummyOutStream.h" - -Z7_COM7F_IMF(CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize = size; - HRESULT res = S_OK; - if (_stream) - res = _stream->Write(data, size, &realProcessedSize); - _size += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return res; -} +// DummyOutStream.cpp + +#include "StdAfx.h" + +#include "DummyOutStream.h" + +Z7_COM7F_IMF(CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize = size; + HRESULT res = S_OK; + if (_stream) + res = _stream->Write(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} diff --git a/CPP/7zip/Archive/Common/DummyOutStream.h b/CPP/7zip/Archive/Common/DummyOutStream.h index 5fef6b121..f884e13c8 100644 --- a/CPP/7zip/Archive/Common/DummyOutStream.h +++ b/CPP/7zip/Archive/Common/DummyOutStream.h @@ -1,23 +1,23 @@ -// DummyOutStream.h - -#ifndef ZIP7_INC_DUMMY_OUT_STREAM_H -#define ZIP7_INC_DUMMY_OUT_STREAM_H - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -Z7_CLASS_IMP_NOQIB_1( - CDummyOutStream - , ISequentialOutStream -) - CMyComPtr _stream; - UInt64 _size; -public: - void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _size = 0; } - UInt64 GetSize() const { return _size; } -}; - -#endif +// DummyOutStream.h + +#ifndef ZIP7_INC_DUMMY_OUT_STREAM_H +#define ZIP7_INC_DUMMY_OUT_STREAM_H + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +Z7_CLASS_IMP_NOQIB_1( + CDummyOutStream + , ISequentialOutStream +) + CMyComPtr _stream; + UInt64 _size; +public: + void SetStream(ISequentialOutStream *outStream) { _stream = outStream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _size = 0; } + UInt64 GetSize() const { return _size; } +}; + +#endif diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp index ddbc93026..4f46ee7bf 100644 --- a/CPP/7zip/Archive/Common/FindSignature.cpp +++ b/CPP/7zip/Archive/Common/FindSignature.cpp @@ -1,90 +1,90 @@ -// FindSignature.cpp - -#include "StdAfx.h" - -#include - -#include "../../../Common/MyBuffer.h" - -#include "../../Common/StreamUtils.h" - -#include "FindSignature.h" - -HRESULT FindSignatureInStream(ISequentialInStream *stream, - const Byte *signature, unsigned signatureSize, - const UInt64 *limit, UInt64 &resPos) -{ - resPos = 0; - CByteBuffer byteBuffer2(signatureSize); - RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize)) - - if (memcmp(byteBuffer2, signature, signatureSize) == 0) - return S_OK; - - const size_t kBufferSize = 1 << 16; - CByteBuffer byteBuffer(kBufferSize); - Byte *buffer = byteBuffer; - size_t numPrevBytes = signatureSize - 1; - memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes); - resPos = 1; - for (;;) - { - if (limit) - if (resPos > *limit) - return S_FALSE; - do - { - const size_t numReadBytes = kBufferSize - numPrevBytes; - UInt32 processedSize; - RINOK(stream->Read(buffer + numPrevBytes, (UInt32)numReadBytes, &processedSize)) - numPrevBytes += (size_t)processedSize; - if (processedSize == 0) - return S_FALSE; - } - while (numPrevBytes < signatureSize); - const size_t numTests = numPrevBytes - signatureSize + 1; - for (size_t pos = 0; pos < numTests; pos++) - { - const Byte b = signature[0]; - for (; buffer[pos] != b && pos < numTests; pos++); - if (pos == numTests) - break; - if (memcmp(buffer + pos, signature, signatureSize) == 0) - { - resPos += pos; - return S_OK; - } - } - resPos += numTests; - numPrevBytes -= numTests; - memmove(buffer, buffer + numTests, numPrevBytes); - } -} - -namespace NArchive { -HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize); -HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize) -{ - areThereNonZeros = false; - numZeros = 0; - const size_t kBufSize = 1 << 11; - Byte buf[kBufSize]; - for (;;) - { - UInt32 size = 0; - RINOK(stream->Read(buf, kBufSize, &size)) - if (size == 0) - return S_OK; - for (UInt32 i = 0; i < size; i++) - if (buf[i] != 0) - { - areThereNonZeros = true; - numZeros += i; - return S_OK; - } - numZeros += size; - if (numZeros > maxSize) - return S_OK; - } -} -} +// FindSignature.cpp + +#include "StdAfx.h" + +#include + +#include "../../../Common/MyBuffer.h" + +#include "../../Common/StreamUtils.h" + +#include "FindSignature.h" + +HRESULT FindSignatureInStream(ISequentialInStream *stream, + const Byte *signature, unsigned signatureSize, + const UInt64 *limit, UInt64 &resPos) +{ + resPos = 0; + CByteBuffer byteBuffer2(signatureSize); + RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize)) + + if (memcmp(byteBuffer2, signature, signatureSize) == 0) + return S_OK; + + const size_t kBufferSize = 1 << 16; + CByteBuffer byteBuffer(kBufferSize); + Byte *buffer = byteBuffer; + size_t numPrevBytes = signatureSize - 1; + memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes); + resPos = 1; + for (;;) + { + if (limit) + if (resPos > *limit) + return S_FALSE; + do + { + const size_t numReadBytes = kBufferSize - numPrevBytes; + UInt32 processedSize; + RINOK(stream->Read(buffer + numPrevBytes, (UInt32)numReadBytes, &processedSize)) + numPrevBytes += (size_t)processedSize; + if (processedSize == 0) + return S_FALSE; + } + while (numPrevBytes < signatureSize); + const size_t numTests = numPrevBytes - signatureSize + 1; + for (size_t pos = 0; pos < numTests; pos++) + { + const Byte b = signature[0]; + for (; buffer[pos] != b && pos < numTests; pos++); + if (pos == numTests) + break; + if (memcmp(buffer + pos, signature, signatureSize) == 0) + { + resPos += pos; + return S_OK; + } + } + resPos += numTests; + numPrevBytes -= numTests; + memmove(buffer, buffer + numTests, numPrevBytes); + } +} + +namespace NArchive { +HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize); +HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize) +{ + areThereNonZeros = false; + numZeros = 0; + const size_t kBufSize = 1 << 11; + Byte buf[kBufSize]; + for (;;) + { + UInt32 size = 0; + RINOK(stream->Read(buf, kBufSize, &size)) + if (size == 0) + return S_OK; + for (UInt32 i = 0; i < size; i++) + if (buf[i] != 0) + { + areThereNonZeros = true; + numZeros += i; + return S_OK; + } + numZeros += size; + if (numZeros > maxSize) + return S_OK; + } +} +} diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h index cb9384d0f..f0e6cddf3 100644 --- a/CPP/7zip/Archive/Common/FindSignature.h +++ b/CPP/7zip/Archive/Common/FindSignature.h @@ -1,12 +1,12 @@ -// FindSignature.h - -#ifndef ZIP7_INC_FIND_SIGNATURE_H -#define ZIP7_INC_FIND_SIGNATURE_H - -#include "../../IStream.h" - -HRESULT FindSignatureInStream(ISequentialInStream *stream, - const Byte *signature, unsigned signatureSize, - const UInt64 *limit, UInt64 &resPos); - -#endif +// FindSignature.h + +#ifndef ZIP7_INC_FIND_SIGNATURE_H +#define ZIP7_INC_FIND_SIGNATURE_H + +#include "../../IStream.h" + +HRESULT FindSignatureInStream(ISequentialInStream *stream, + const Byte *signature, unsigned signatureSize, + const UInt64 *limit, UInt64 &resPos); + +#endif diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 22290b1b2..17fed675b 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -1,311 +1,311 @@ -// HandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringToInt.h" - -#include "../Common/ParseProperties.h" - -#include "HandlerOut.h" - -namespace NArchive { - -bool ParseSizeString(const wchar_t *s, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res) -{ - if (*s == 0) - { - switch (prop.vt) - { - case VT_UI4: res = prop.ulVal; return true; - case VT_UI8: res = prop.uhVal.QuadPart; return true; - case VT_BSTR: - s = prop.bstrVal; - break; - default: return false; - } - } - else if (prop.vt != VT_EMPTY) - return false; - - bool percentMode = false; - { - const wchar_t c = *s; - if (MyCharLower_Ascii(c) == 'p') - { - percentMode = true; - s++; - } - } - - const wchar_t *end; - const UInt64 v = ConvertStringToUInt64(s, &end); - if (s == end) - return false; - const wchar_t c = *end; - - if (percentMode) - { - if (c != 0) - return false; - res = Calc_From_Val_Percents(percentsBase, v); - return true; - } - - if (c == 0) - { - res = v; - return true; - } - if (end[1] != 0) - return false; - - if (c == '%') - { - res = Calc_From_Val_Percents(percentsBase, v); - return true; - } - - unsigned numBits; - switch (MyCharLower_Ascii(c)) - { - case 'b': numBits = 0; break; - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - case 't': numBits = 40; break; - default: return false; - } - const UInt64 val2 = v << numBits; - if ((val2 >> numBits) != v) - return false; - res = val2; - return true; -} - -bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres) -{ - hres = S_OK; - - if (name.IsPrefixedBy_Ascii_NoCase("mt")) - { - #ifndef Z7_ST - _numThreads = _numProcessors; - _numThreads_WasForced = false; - hres = ParseMtProp2(name.Ptr(2), value, _numThreads, _numThreads_WasForced); - // "mt" means "_numThreads_WasForced = false" here - #endif - return true; - } - - if (name.IsPrefixedBy_Ascii_NoCase("memuse")) - { - UInt64 v; - if (!ParseSizeString(name.Ptr(6), value, _memAvail, v)) - hres = E_INVALIDARG; - _memUsage_Decompress = v; - _memUsage_Compress = v; - _memUsage_WasSet = true; - return true; - } - - return false; -} - - -#ifndef Z7_EXTRACT_ONLY - -static void SetMethodProp32(CMethodProps &m, PROPID propID, UInt32 value) -{ - if (m.FindProp(propID) < 0) - m.AddProp32(propID, value); -} - -void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const -{ - UInt32 level = _level; - if (level != (UInt32)(Int32)-1) - SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); -} - -#ifndef Z7_ST - -static void SetMethodProp32_Replace(CMethodProps &m, PROPID propID, UInt32 value) -{ - const int i = m.FindProp(propID); - if (i >= 0) - { - NWindows::NCOM::CPropVariant &val = m.Props[(unsigned)i].Value; - val = (UInt32)value; - return; - } - m.AddProp32(propID, value); -} - -void CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreads) -{ - SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); -} - -void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo, UInt32 numThreads) -{ - SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); -} - -#endif // Z7_ST - - -void CMultiMethodProps::InitMulti() -{ - _level = (UInt32)(Int32)-1; - _analysisLevel = -1; - _crcSize = 4; - _autoFilter = true; -} - -void CMultiMethodProps::Init() -{ - InitCommon(); - InitMulti(); - _methods.Clear(); - _filterMethod.Clear(); -} - - -HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) -{ - UString name = nameSpec; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - if (name[0] == 'x') - { - name.Delete(0); - _level = 9; - return ParsePropToUInt32(name, value, _level); - } - - if (name.IsPrefixedBy_Ascii_NoCase("yx")) - { - name.Delete(0, 2); - UInt32 v = 9; - RINOK(ParsePropToUInt32(name, value, v)) - _analysisLevel = (int)v; - return S_OK; - } - - if (name.IsPrefixedBy_Ascii_NoCase("crc")) - { - name.Delete(0, 3); - _crcSize = 4; - return ParsePropToUInt32(name, value, _crcSize); - } - - { - HRESULT hres; - if (SetCommonProperty(name, value, hres)) - return hres; - } - - UInt32 number; - const unsigned index = ParseStringToUInt32(name, number); - const UString realName = name.Ptr(index); - if (index == 0) - { - if (name.IsEqualTo("f")) - { - const HRESULT res = PROPVARIANT_to_bool(value, _autoFilter); - if (res == S_OK) - return res; - if (value.vt != VT_BSTR) - return E_INVALIDARG; - return _filterMethod.ParseMethodFromPROPVARIANT(UString(), value); - } - number = 0; - } - if (number > 64) - return E_INVALIDARG; - for (unsigned j = _methods.Size(); j <= number; j++) - _methods.AddNew(); - return _methods[number].ParseMethodFromPROPVARIANT(realName, value); -} - - - -void CSingleMethodProps::Init() -{ - InitCommon(); - InitSingle(); - Clear(); -} - - -HRESULT CSingleMethodProps::SetProperty(const wchar_t *name2, const PROPVARIANT &value) -{ - // processed = false; - UString name = name2; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - if (name.IsPrefixedBy_Ascii_NoCase("x")) - { - UInt32 a = 9; - RINOK(ParsePropToUInt32(name.Ptr(1), value, a)) - _level = a; - AddProp_Level(a); - // processed = true; - return S_OK; - } - { - HRESULT hres; - if (SetCommonProperty(name, value, hres)) - { - // processed = true; - return S_OK; - } - } - RINOK(ParseMethodFromPROPVARIANT(name, value)) - return S_OK; -} - - -HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) -{ - Init(); - - for (UInt32 i = 0; i < numProps; i++) - { - RINOK(SetProperty(names[i], values[i])) - } - - return S_OK; -} - -#endif - - -static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) -{ - RINOK(PROPVARIANT_to_bool(prop, dest.Val)) - dest.Def = true; - return S_OK; -} - -HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed) -{ - processed = true; - if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); } - if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); } - if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); } - if (name.IsPrefixedBy_Ascii_NoCase("tp")) - { - UInt32 v = 0; - RINOK(ParsePropToUInt32(name.Ptr(2), prop, v)) - Prec = v; - return S_OK; - } - processed = false; - return S_OK; -} - -} +// HandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringToInt.h" + +#include "../Common/ParseProperties.h" + +#include "HandlerOut.h" + +namespace NArchive { + +bool ParseSizeString(const wchar_t *s, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res) +{ + if (*s == 0) + { + switch (prop.vt) + { + case VT_UI4: res = prop.ulVal; return true; + case VT_UI8: res = prop.uhVal.QuadPart; return true; + case VT_BSTR: + s = prop.bstrVal; + break; + default: return false; + } + } + else if (prop.vt != VT_EMPTY) + return false; + + bool percentMode = false; + { + const wchar_t c = *s; + if (MyCharLower_Ascii(c) == 'p') + { + percentMode = true; + s++; + } + } + + const wchar_t *end; + const UInt64 v = ConvertStringToUInt64(s, &end); + if (s == end) + return false; + const wchar_t c = *end; + + if (percentMode) + { + if (c != 0) + return false; + res = Calc_From_Val_Percents(percentsBase, v); + return true; + } + + if (c == 0) + { + res = v; + return true; + } + if (end[1] != 0) + return false; + + if (c == '%') + { + res = Calc_From_Val_Percents(percentsBase, v); + return true; + } + + unsigned numBits; + switch (MyCharLower_Ascii(c)) + { + case 'b': numBits = 0; break; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return false; + } + const UInt64 val2 = v << numBits; + if ((val2 >> numBits) != v) + return false; + res = val2; + return true; +} + +bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres) +{ + hres = S_OK; + + if (name.IsPrefixedBy_Ascii_NoCase("mt")) + { + #ifndef Z7_ST + _numThreads = _numProcessors; + _numThreads_WasForced = false; + hres = ParseMtProp2(name.Ptr(2), value, _numThreads, _numThreads_WasForced); + // "mt" means "_numThreads_WasForced = false" here + #endif + return true; + } + + if (name.IsPrefixedBy_Ascii_NoCase("memuse")) + { + UInt64 v; + if (!ParseSizeString(name.Ptr(6), value, _memAvail, v)) + hres = E_INVALIDARG; + _memUsage_Decompress = v; + _memUsage_Compress = v; + _memUsage_WasSet = true; + return true; + } + + return false; +} + + +#ifndef Z7_EXTRACT_ONLY + +static void SetMethodProp32(CMethodProps &m, PROPID propID, UInt32 value) +{ + if (m.FindProp(propID) < 0) + m.AddProp32(propID, value); +} + +void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const +{ + UInt32 level = _level; + if (level != (UInt32)(Int32)-1) + SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level); +} + +#ifndef Z7_ST + +static void SetMethodProp32_Replace(CMethodProps &m, PROPID propID, UInt32 value) +{ + const int i = m.FindProp(propID); + if (i >= 0) + { + NWindows::NCOM::CPropVariant &val = m.Props[(unsigned)i].Value; + val = (UInt32)value; + return; + } + m.AddProp32(propID, value); +} + +void CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreads) +{ + SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); +} + +void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo, UInt32 numThreads) +{ + SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); +} + +#endif // Z7_ST + + +void CMultiMethodProps::InitMulti() +{ + _level = (UInt32)(Int32)-1; + _analysisLevel = -1; + _crcSize = 4; + _autoFilter = true; +} + +void CMultiMethodProps::Init() +{ + InitCommon(); + InitMulti(); + _methods.Clear(); + _filterMethod.Clear(); +} + + +HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + if (name[0] == 'x') + { + name.Delete(0); + _level = 9; + return ParsePropToUInt32(name, value, _level); + } + + if (name.IsPrefixedBy_Ascii_NoCase("yx")) + { + name.Delete(0, 2); + UInt32 v = 9; + RINOK(ParsePropToUInt32(name, value, v)) + _analysisLevel = (int)v; + return S_OK; + } + + if (name.IsPrefixedBy_Ascii_NoCase("crc")) + { + name.Delete(0, 3); + _crcSize = 4; + return ParsePropToUInt32(name, value, _crcSize); + } + + { + HRESULT hres; + if (SetCommonProperty(name, value, hres)) + return hres; + } + + UInt32 number; + const unsigned index = ParseStringToUInt32(name, number); + const UString realName = name.Ptr(index); + if (index == 0) + { + if (name.IsEqualTo("f")) + { + const HRESULT res = PROPVARIANT_to_bool(value, _autoFilter); + if (res == S_OK) + return res; + if (value.vt != VT_BSTR) + return E_INVALIDARG; + return _filterMethod.ParseMethodFromPROPVARIANT(UString(), value); + } + number = 0; + } + if (number > 64) + return E_INVALIDARG; + for (unsigned j = _methods.Size(); j <= number; j++) + _methods.AddNew(); + return _methods[number].ParseMethodFromPROPVARIANT(realName, value); +} + + + +void CSingleMethodProps::Init() +{ + InitCommon(); + InitSingle(); + Clear(); +} + + +HRESULT CSingleMethodProps::SetProperty(const wchar_t *name2, const PROPVARIANT &value) +{ + // processed = false; + UString name = name2; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + if (name.IsPrefixedBy_Ascii_NoCase("x")) + { + UInt32 a = 9; + RINOK(ParsePropToUInt32(name.Ptr(1), value, a)) + _level = a; + AddProp_Level(a); + // processed = true; + return S_OK; + } + { + HRESULT hres; + if (SetCommonProperty(name, value, hres)) + { + // processed = true; + return S_OK; + } + } + RINOK(ParseMethodFromPROPVARIANT(name, value)) + return S_OK; +} + + +HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) +{ + Init(); + + for (UInt32 i = 0; i < numProps; i++) + { + RINOK(SetProperty(names[i], values[i])) + } + + return S_OK; +} + +#endif + + +static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) +{ + RINOK(PROPVARIANT_to_bool(prop, dest.Val)) + dest.Def = true; + return S_OK; +} + +HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed) +{ + processed = true; + if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); } + if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); } + if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); } + if (name.IsPrefixedBy_Ascii_NoCase("tp")) + { + UInt32 v = 0; + RINOK(ParsePropToUInt32(name.Ptr(2), prop, v)) + Prec = v; + return S_OK; + } + processed = false; + return S_OK; +} + +} diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h index 9b8829d0e..9340e1b29 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.h +++ b/CPP/7zip/Archive/Common/HandlerOut.h @@ -1,154 +1,154 @@ -// HandlerOut.h - -#ifndef ZIP7_INC_HANDLER_OUT_H -#define ZIP7_INC_HANDLER_OUT_H - -#include "../../../Windows/System.h" - -#include "../../Common/MethodProps.h" - -namespace NArchive { - -bool ParseSizeString(const wchar_t *name, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res); - -class CCommonMethodProps -{ -protected: - void InitCommon() - { - // _Write_MTime = true; - #ifndef Z7_ST - _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); - _numThreads_WasForced = false; - #endif - - UInt64 memAvail = (UInt64)(sizeof(size_t)) << 28; - _memAvail = memAvail; - _memUsage_Compress = memAvail; - _memUsage_Decompress = memAvail; - _memUsage_WasSet = NWindows::NSystem::GetRamSize(memAvail); - if (_memUsage_WasSet) - { - _memAvail = memAvail; - unsigned bits = sizeof(size_t) * 8; - if (bits == 32) - { - const UInt32 limit2 = (UInt32)7 << 28; - if (memAvail > limit2) - memAvail = limit2; - } - // 80% - is auto usage limit in handlers - // _memUsage_Compress = memAvail * 4 / 5; - // _memUsage_Compress = Calc_From_Val_Percents(memAvail, 80); - _memUsage_Compress = Calc_From_Val_Percents_Less100(memAvail, 80); - _memUsage_Decompress = memAvail / 32 * 17; - } - } - -public: - #ifndef Z7_ST - UInt32 _numThreads; - UInt32 _numProcessors; - bool _numThreads_WasForced; - #endif - - bool _memUsage_WasSet; - UInt64 _memUsage_Compress; - UInt64 _memUsage_Decompress; - UInt64 _memAvail; - - bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres); - - CCommonMethodProps() { InitCommon(); } -}; - - -#ifndef Z7_EXTRACT_ONLY - -class CMultiMethodProps: public CCommonMethodProps -{ - UInt32 _level; - int _analysisLevel; - - void InitMulti(); -public: - UInt32 _crcSize; - CObjectVector _methods; - COneMethodInfo _filterMethod; - bool _autoFilter; - - - void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; - - #ifndef Z7_ST - static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads); - static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads); - #endif - - - unsigned GetNumEmptyMethods() const - { - unsigned i; - for (i = 0; i < _methods.Size(); i++) - if (!_methods[i].IsEmpty()) - break; - return i; - } - - int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } - int GetAnalysisLevel() const { return _analysisLevel; } - - void Init(); - CMultiMethodProps() { InitMulti(); } - - HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); -}; - - -class CSingleMethodProps: public COneMethodInfo, public CCommonMethodProps -{ - UInt32 _level; - - void InitSingle() - { - _level = (UInt32)(Int32)-1; - } - -public: - void Init(); - CSingleMethodProps() { InitSingle(); } - - int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } - HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values); - HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); -}; - -#endif - -struct CHandlerTimeOptions -{ - CBoolPair Write_MTime; - CBoolPair Write_ATime; - CBoolPair Write_CTime; - UInt32 Prec; - - void Init() - { - Write_MTime.Init(); - Write_MTime.Val = true; - Write_ATime.Init(); - Write_CTime.Init(); - Prec = (UInt32)(Int32)-1; - } - - CHandlerTimeOptions() - { - Init(); - } - - HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed); -}; - -} - -#endif +// HandlerOut.h + +#ifndef ZIP7_INC_HANDLER_OUT_H +#define ZIP7_INC_HANDLER_OUT_H + +#include "../../../Windows/System.h" + +#include "../../Common/MethodProps.h" + +namespace NArchive { + +bool ParseSizeString(const wchar_t *name, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res); + +class CCommonMethodProps +{ +protected: + void InitCommon() + { + // _Write_MTime = true; + #ifndef Z7_ST + _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); + _numThreads_WasForced = false; + #endif + + size_t memAvail = (size_t)sizeof(size_t) << 28; + _memAvail = memAvail; + _memUsage_Compress = memAvail; + _memUsage_Decompress = memAvail; + _memUsage_WasSet = NWindows::NSystem::GetRamSize(memAvail); + if (_memUsage_WasSet) + { + _memAvail = memAvail; + unsigned bits = sizeof(size_t) * 8; + if (bits == 32) + { + const UInt32 limit2 = (UInt32)7 << 28; + if (memAvail > limit2) + memAvail = limit2; + } + // 80% - is auto usage limit in handlers + // _memUsage_Compress = memAvail * 4 / 5; + // _memUsage_Compress = Calc_From_Val_Percents(memAvail, 80); + _memUsage_Compress = Calc_From_Val_Percents_Less100(memAvail, 80); + _memUsage_Decompress = memAvail / 32 * 17; + } + } + +public: + #ifndef Z7_ST + UInt32 _numThreads; + UInt32 _numProcessors; + bool _numThreads_WasForced; + #endif + + bool _memUsage_WasSet; + UInt64 _memUsage_Compress; + UInt64 _memUsage_Decompress; + size_t _memAvail; + + bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres); + + CCommonMethodProps() { InitCommon(); } +}; + + +#ifndef Z7_EXTRACT_ONLY + +class CMultiMethodProps: public CCommonMethodProps +{ + UInt32 _level; + int _analysisLevel; + + void InitMulti(); +public: + UInt32 _crcSize; + CObjectVector _methods; + COneMethodInfo _filterMethod; + bool _autoFilter; + + + void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const; + + #ifndef Z7_ST + static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads); + static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads); + #endif + + + unsigned GetNumEmptyMethods() const + { + unsigned i; + for (i = 0; i < _methods.Size(); i++) + if (!_methods[i].IsEmpty()) + break; + return i; + } + + int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } + int GetAnalysisLevel() const { return _analysisLevel; } + + void Init(); + CMultiMethodProps() { InitMulti(); } + + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); +}; + + +class CSingleMethodProps: public COneMethodInfo, public CCommonMethodProps +{ + UInt32 _level; + + void InitSingle() + { + _level = (UInt32)(Int32)-1; + } + +public: + void Init(); + CSingleMethodProps() { InitSingle(); } + + int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values); + HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); +}; + +#endif + +struct CHandlerTimeOptions +{ + CBoolPair Write_MTime; + CBoolPair Write_ATime; + CBoolPair Write_CTime; + UInt32 Prec; + + void Init() + { + Write_MTime.Init(); + Write_MTime.Val = true; + Write_ATime.Init(); + Write_CTime.Init(); + Prec = (UInt32)(Int32)-1; + } + + CHandlerTimeOptions() + { + Init(); + } + + HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed); +}; + +} + +#endif diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp index 3a570272b..735d5d1eb 100644 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp @@ -1,57 +1,57 @@ -// InStreamWithCRC.cpp - -#include "StdAfx.h" - -#include "InStreamWithCRC.h" - -Z7_COM7F_IMF(CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessed = 0; - HRESULT result = S_OK; - if (size != 0) - { - if (_stream) - result = _stream->Read(data, size, &realProcessed); - _size += realProcessed; - if (realProcessed == 0) - _wasFinished = true; - else - _crc = CrcUpdate(_crc, data, realProcessed); - } - if (processedSize) - *processedSize = realProcessed; - return result; -} - -Z7_COM7F_IMF(CSequentialInStreamWithCRC::GetSize(UInt64 *size)) -{ - *size = _fullSize; - return S_OK; -} - - -Z7_COM7F_IMF(CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessed = 0; - HRESULT result = S_OK; - if (_stream) - result = _stream->Read(data, size, &realProcessed); - _size += realProcessed; - /* - if (size != 0 && realProcessed == 0) - _wasFinished = true; - */ - _crc = CrcUpdate(_crc, data, realProcessed); - if (processedSize) - *processedSize = realProcessed; - return result; -} - -Z7_COM7F_IMF(CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - if (seekOrigin != STREAM_SEEK_SET || offset != 0) - return E_FAIL; - _size = 0; - _crc = CRC_INIT_VAL; - return _stream->Seek(offset, seekOrigin, newPosition); -} +// InStreamWithCRC.cpp + +#include "StdAfx.h" + +#include "InStreamWithCRC.h" + +Z7_COM7F_IMF(CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (size != 0) + { + if (_stream) + result = _stream->Read(data, size, &realProcessed); + _size += realProcessed; + if (realProcessed == 0) + _wasFinished = true; + else + _crc = CrcUpdate(_crc, data, realProcessed); + } + if (processedSize) + *processedSize = realProcessed; + return result; +} + +Z7_COM7F_IMF(CSequentialInStreamWithCRC::GetSize(UInt64 *size)) +{ + *size = _fullSize; + return S_OK; +} + + +Z7_COM7F_IMF(CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessed = 0; + HRESULT result = S_OK; + if (_stream) + result = _stream->Read(data, size, &realProcessed); + _size += realProcessed; + /* + if (size != 0 && realProcessed == 0) + _wasFinished = true; + */ + _crc = CrcUpdate(_crc, data, realProcessed); + if (processedSize) + *processedSize = realProcessed; + return result; +} + +Z7_COM7F_IMF(CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + if (seekOrigin != STREAM_SEEK_SET || offset != 0) + return E_FAIL; + _size = 0; + _crc = CRC_INIT_VAL; + return _stream->Seek(offset, seekOrigin, newPosition); +} diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h index 41ff312d1..48736892c 100644 --- a/CPP/7zip/Archive/Common/InStreamWithCRC.h +++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h @@ -1,64 +1,64 @@ -// InStreamWithCRC.h - -#ifndef ZIP7_INC_IN_STREAM_WITH_CRC_H -#define ZIP7_INC_IN_STREAM_WITH_CRC_H - -#include "../../../../C/7zCrc.h" - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -Z7_CLASS_IMP_NOQIB_2( - CSequentialInStreamWithCRC - , ISequentialInStream - , IStreamGetSize -) - CMyComPtr _stream; - UInt64 _size; - UInt32 _crc; - bool _wasFinished; - UInt64 _fullSize; -public: - - CSequentialInStreamWithCRC(): - _fullSize((UInt64)(Int64)-1) - {} - - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void SetFullSize(UInt64 fullSize) { _fullSize = fullSize; } - void Init() - { - _size = 0; - _crc = CRC_INIT_VAL; - _wasFinished = false; - } - void ReleaseStream() { _stream.Release(); } - UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } - UInt64 GetSize() const { return _size; } - bool WasFinished() const { return _wasFinished; } -}; - - -Z7_CLASS_IMP_IInStream( - CInStreamWithCRC -) - CMyComPtr _stream; - UInt64 _size; - UInt32 _crc; - // bool _wasFinished; -public: - void SetStream(IInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - // _wasFinished = false; - _crc = CRC_INIT_VAL; - } - void ReleaseStream() { _stream.Release(); } - UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } - UInt64 GetSize() const { return _size; } - // bool WasFinished() const { return _wasFinished; } -}; - -#endif +// InStreamWithCRC.h + +#ifndef ZIP7_INC_IN_STREAM_WITH_CRC_H +#define ZIP7_INC_IN_STREAM_WITH_CRC_H + +#include "../../../../C/7zCrc.h" + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +Z7_CLASS_IMP_NOQIB_2( + CSequentialInStreamWithCRC + , ISequentialInStream + , IStreamGetSize +) + CMyComPtr _stream; + UInt64 _size; + UInt32 _crc; + bool _wasFinished; + UInt64 _fullSize; +public: + + CSequentialInStreamWithCRC(): + _fullSize((UInt64)(Int64)-1) + {} + + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void SetFullSize(UInt64 fullSize) { _fullSize = fullSize; } + void Init() + { + _size = 0; + _crc = CRC_INIT_VAL; + _wasFinished = false; + } + void ReleaseStream() { _stream.Release(); } + UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } + UInt64 GetSize() const { return _size; } + bool WasFinished() const { return _wasFinished; } +}; + + +Z7_CLASS_IMP_IInStream( + CInStreamWithCRC +) + CMyComPtr _stream; + UInt64 _size; + UInt32 _crc; + // bool _wasFinished; +public: + void SetStream(IInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + // _wasFinished = false; + _crc = CRC_INIT_VAL; + } + void ReleaseStream() { _stream.Release(); } + UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } + UInt64 GetSize() const { return _size; } + // bool WasFinished() const { return _wasFinished; } +}; + +#endif diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp index 89f84f782..8caf1d141 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp +++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp @@ -1,135 +1,135 @@ -// Archive/Common/ItemNameUtils.cpp - -#include "StdAfx.h" - -#include "ItemNameUtils.h" - -namespace NArchive { -namespace NItemName { - -static const wchar_t kOsPathSepar = WCHAR_PATH_SEPARATOR; - -#if WCHAR_PATH_SEPARATOR != L'/' -static const wchar_t kUnixPathSepar = L'/'; -#endif - -void ReplaceSlashes_OsToUnix -#if WCHAR_PATH_SEPARATOR != L'/' - (UString &name) - { - name.Replace(kOsPathSepar, kUnixPathSepar); - } -#else - (UString &) {} -#endif - - -UString GetOsPath(const UString &name) -{ - #if WCHAR_PATH_SEPARATOR != L'/' - UString newName = name; - newName.Replace(kUnixPathSepar, kOsPathSepar); - return newName; - #else - return name; - #endif -} - - -UString GetOsPath_Remove_TailSlash(const UString &name) -{ - if (name.IsEmpty()) - return UString(); - UString newName = GetOsPath(name); - if (newName.Back() == kOsPathSepar) - newName.DeleteBack(); - return newName; -} - - -void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool - #if WCHAR_PATH_SEPARATOR != L'/' - useBackslashReplacement - #endif - ) -{ - if (name.IsEmpty()) - return; - - #if WCHAR_PATH_SEPARATOR != L'/' - { - // name.Replace(kUnixPathSepar, kOsPathSepar); - const unsigned len = name.Len(); - for (unsigned i = 0; i < len; i++) - { - wchar_t c = name[i]; - if (c == L'/') - c = WCHAR_PATH_SEPARATOR; - else if (useBackslashReplacement && c == L'\\') - c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme - else - continue; - name.ReplaceOneCharAtPos(i, c); - } - } - #endif - - if (name.Back() == kOsPathSepar) - name.DeleteBack(); -} - - -void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *name, unsigned len) -{ - for (unsigned i = 0; i < len; i++) - { - wchar_t c = name[i]; - if (c == L'/') - c = L'_'; - #if WCHAR_PATH_SEPARATOR != L'/' - else if (c == L'\\') - c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme - #endif - else - continue; - name[i] = c; - } -} - -void NormalizeSlashes_in_FileName_for_OsPath(UString &name) -{ - NormalizeSlashes_in_FileName_for_OsPath(name.GetBuf(), name.Len()); -} - - -bool HasTailSlash(const AString &name, UINT - #if defined(_WIN32) && !defined(UNDER_CE) - codePage - #endif - ) -{ - if (name.IsEmpty()) - return false; - char c; - #if defined(_WIN32) && !defined(UNDER_CE) - if (codePage != CP_UTF8) - c = *CharPrevExA((WORD)codePage, name, name.Ptr(name.Len()), 0); - else - #endif - { - c = name.Back(); - } - return (c == '/'); -} - - -#ifndef _WIN32 -UString WinPathToOsPath(const UString &name) -{ - UString newName = name; - newName.Replace(L'\\', WCHAR_PATH_SEPARATOR); - return newName; -} -#endif - -}} +// Archive/Common/ItemNameUtils.cpp + +#include "StdAfx.h" + +#include "ItemNameUtils.h" + +namespace NArchive { +namespace NItemName { + +static const wchar_t kOsPathSepar = WCHAR_PATH_SEPARATOR; + +#if WCHAR_PATH_SEPARATOR != L'/' +static const wchar_t kUnixPathSepar = L'/'; +#endif + +void ReplaceSlashes_OsToUnix +#if WCHAR_PATH_SEPARATOR != L'/' + (UString &name) + { + name.Replace(kOsPathSepar, kUnixPathSepar); + } +#else + (UString &) {} +#endif + + +UString GetOsPath(const UString &name) +{ + #if WCHAR_PATH_SEPARATOR != L'/' + UString newName = name; + newName.Replace(kUnixPathSepar, kOsPathSepar); + return newName; + #else + return name; + #endif +} + + +UString GetOsPath_Remove_TailSlash(const UString &name) +{ + if (name.IsEmpty()) + return UString(); + UString newName = GetOsPath(name); + if (newName.Back() == kOsPathSepar) + newName.DeleteBack(); + return newName; +} + + +void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool + #if WCHAR_PATH_SEPARATOR != L'/' + useBackslashReplacement + #endif + ) +{ + if (name.IsEmpty()) + return; + + #if WCHAR_PATH_SEPARATOR != L'/' + { + // name.Replace(kUnixPathSepar, kOsPathSepar); + const unsigned len = name.Len(); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = name[i]; + if (c == L'/') + c = WCHAR_PATH_SEPARATOR; + else if (useBackslashReplacement && c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme + else + continue; + name.ReplaceOneCharAtPos(i, c); + } + } + #endif + + if (name.Back() == kOsPathSepar) + name.DeleteBack(); +} + + +void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *name, unsigned len) +{ + for (unsigned i = 0; i < len; i++) + { + wchar_t c = name[i]; + if (c == L'/') + c = L'_'; + #if WCHAR_PATH_SEPARATOR != L'/' + else if (c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme + #endif + else + continue; + name[i] = c; + } +} + +void NormalizeSlashes_in_FileName_for_OsPath(UString &name) +{ + NormalizeSlashes_in_FileName_for_OsPath(name.GetBuf(), name.Len()); +} + + +bool HasTailSlash(const AString &name, UINT + #if defined(_WIN32) && !defined(UNDER_CE) + codePage + #endif + ) +{ + if (name.IsEmpty()) + return false; + char c; + #if defined(_WIN32) && !defined(UNDER_CE) + if (codePage != CP_UTF8) + c = *CharPrevExA((WORD)codePage, name, name.Ptr(name.Len()), 0); + else + #endif + { + c = name.Back(); + } + return (c == '/'); +} + + +#ifndef _WIN32 +UString WinPathToOsPath(const UString &name) +{ + UString newName = name; + newName.Replace(L'\\', WCHAR_PATH_SEPARATOR); + return newName; +} +#endif + +}} diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h index 96aedeb7b..8ab9b610a 100644 --- a/CPP/7zip/Archive/Common/ItemNameUtils.h +++ b/CPP/7zip/Archive/Common/ItemNameUtils.h @@ -1,30 +1,30 @@ -// Archive/Common/ItemNameUtils.h - -#ifndef ZIP7_INC_ARCHIVE_ITEM_NAME_UTILS_H -#define ZIP7_INC_ARCHIVE_ITEM_NAME_UTILS_H - -#include "../../../Common/MyString.h" - -namespace NArchive { -namespace NItemName { - -void ReplaceSlashes_OsToUnix(UString &name); - -UString GetOsPath(const UString &name); -UString GetOsPath_Remove_TailSlash(const UString &name); - -void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); -void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len); -void NormalizeSlashes_in_FileName_for_OsPath(UString &name); - -bool HasTailSlash(const AString &name, UINT codePage); - -#ifdef _WIN32 - inline UString WinPathToOsPath(const UString &name) { return name; } -#else - UString WinPathToOsPath(const UString &name); -#endif - -}} - -#endif +// Archive/Common/ItemNameUtils.h + +#ifndef ZIP7_INC_ARCHIVE_ITEM_NAME_UTILS_H +#define ZIP7_INC_ARCHIVE_ITEM_NAME_UTILS_H + +#include "../../../Common/MyString.h" + +namespace NArchive { +namespace NItemName { + +void ReplaceSlashes_OsToUnix(UString &name); + +UString GetOsPath(const UString &name); +UString GetOsPath_Remove_TailSlash(const UString &name); + +void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); +void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len); +void NormalizeSlashes_in_FileName_for_OsPath(UString &name); + +bool HasTailSlash(const AString &name, UINT codePage); + +#ifdef _WIN32 + inline UString WinPathToOsPath(const UString &name) { return name; } +#else + UString WinPathToOsPath(const UString &name); +#endif + +}} + +#endif diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp index dfbfe1522..5d357af71 100644 --- a/CPP/7zip/Archive/Common/MultiStream.cpp +++ b/CPP/7zip/Archive/Common/MultiStream.cpp @@ -1,193 +1,193 @@ -// MultiStream.cpp - -#include "StdAfx.h" - -#include "MultiStream.h" - -Z7_COM7F_IMF(CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_pos >= _totalLength) - return S_OK; - - { - unsigned left = 0, mid = _streamIndex, right = Streams.Size(); - for (;;) - { - CSubStreamInfo &m = Streams[mid]; - if (_pos < m.GlobalOffset) - right = mid; - else if (_pos >= m.GlobalOffset + m.Size) - left = mid + 1; - else - break; - mid = (left + right) / 2; - } - _streamIndex = mid; - } - - CSubStreamInfo &s = Streams[_streamIndex]; - UInt64 localPos = _pos - s.GlobalOffset; - if (localPos != s.LocalPos) - { - RINOK(s.Stream->Seek((Int64)localPos, STREAM_SEEK_SET, &s.LocalPos)) - } - { - const UInt64 rem = s.Size - localPos; - if (size > rem) - size = (UInt32)rem; - } - const HRESULT result = s.Stream->Read(data, size, &size); - _pos += size; - s.LocalPos += size; - if (processedSize) - *processedSize = size; - return result; -} - -Z7_COM7F_IMF(CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _pos; break; - case STREAM_SEEK_END: offset += _totalLength; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _pos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - -/* -class COutVolumeStream: - public ISequentialOutStream, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - unsigned _volIndex; - UInt64 _volSize; - UInt64 _curPos; - CMyComPtr _volumeStream; - COutArchive _archive; - CCRC _crc; - -public: - CFileItem _file; - CUpdateOptions _options; - CMyComPtr VolumeCallback; - void Init(IArchiveUpdateCallback2 *volumeCallback, - const UString &name) - { - _file.Name = name; - _file.IsStartPosDefined = true; - _file.StartPos = 0; - - VolumeCallback = volumeCallback; - _volIndex = 0; - _volSize = 0; - } - - HRESULT Flush(); -}; - -HRESULT COutVolumeStream::Flush() -{ - if (_volumeStream) - { - _file.UnPackSize = _curPos; - _file.FileCRC = _crc.GetDigest(); - RINOK(WriteVolumeHeader(_archive, _file, _options)) - _archive.Close(); - _volumeStream.Release(); - _file.StartPos += _file.UnPackSize; - } - return S_OK; -} -*/ - -/* - -#include "../../../Common/Defs.h" - -Z7_COM7F_IMF(COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - while (size > 0) - { - if (_streamIndex >= Streams.Size()) - { - CSubStreamInfo subStream; - RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size)) - RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream)) - subStream.Pos = 0; - Streams.Add(subStream); - continue; - } - CSubStreamInfo &subStream = Streams[_streamIndex]; - if (_offsetPos >= subStream.Size) - { - _offsetPos -= subStream.Size; - _streamIndex++; - continue; - } - if (_offsetPos != subStream.Pos) - { - CMyComPtr outStream; - RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)) - RINOK(outStream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL)) - subStream.Pos = _offsetPos; - } - - const UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos); - UInt32 realProcessed; - RINOK(subStream.Stream->Write(data, curSize, &realProcessed)) - data = (const void *)((const Byte *)data + realProcessed); - size -= realProcessed; - subStream.Pos += realProcessed; - _offsetPos += realProcessed; - _absPos += realProcessed; - if (_absPos > _length) - _length = _absPos; - if (processedSize) - *processedSize += realProcessed; - if (subStream.Pos == subStream.Size) - { - _streamIndex++; - _offsetPos = 0; - } - if (realProcessed != curSize && realProcessed == 0) - return E_FAIL; - } - return S_OK; -} - -Z7_COM7F_IMF(COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _absPos; break; - case STREAM_SEEK_END: offset += _length; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _absPos = (UInt64)offset; - _offsetPos = _absPos; - _streamIndex = 0; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} -*/ +// MultiStream.cpp + +#include "StdAfx.h" + +#include "MultiStream.h" + +Z7_COM7F_IMF(CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_pos >= _totalLength) + return S_OK; + + { + unsigned left = 0, mid = _streamIndex, right = Streams.Size(); + for (;;) + { + CSubStreamInfo &m = Streams[mid]; + if (_pos < m.GlobalOffset) + right = mid; + else if (_pos >= m.GlobalOffset + m.Size) + left = mid + 1; + else + break; + mid = (left + right) / 2; + } + _streamIndex = mid; + } + + CSubStreamInfo &s = Streams[_streamIndex]; + UInt64 localPos = _pos - s.GlobalOffset; + if (localPos != s.LocalPos) + { + RINOK(s.Stream->Seek((Int64)localPos, STREAM_SEEK_SET, &s.LocalPos)) + } + { + const UInt64 rem = s.Size - localPos; + if (size > rem) + size = (UInt32)rem; + } + const HRESULT result = s.Stream->Read(data, size, &size); + _pos += size; + s.LocalPos += size; + if (processedSize) + *processedSize = size; + return result; +} + +Z7_COM7F_IMF(CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _pos; break; + case STREAM_SEEK_END: offset += _totalLength; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _pos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + +/* +class COutVolumeStream: + public ISequentialOutStream, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + unsigned _volIndex; + UInt64 _volSize; + UInt64 _curPos; + CMyComPtr _volumeStream; + COutArchive _archive; + CCRC _crc; + +public: + CFileItem _file; + CUpdateOptions _options; + CMyComPtr VolumeCallback; + void Init(IArchiveUpdateCallback2 *volumeCallback, + const UString &name) + { + _file.Name = name; + _file.IsStartPosDefined = true; + _file.StartPos = 0; + + VolumeCallback = volumeCallback; + _volIndex = 0; + _volSize = 0; + } + + HRESULT Flush(); +}; + +HRESULT COutVolumeStream::Flush() +{ + if (_volumeStream) + { + _file.UnPackSize = _curPos; + _file.FileCRC = _crc.GetDigest(); + RINOK(WriteVolumeHeader(_archive, _file, _options)) + _archive.Close(); + _volumeStream.Release(); + _file.StartPos += _file.UnPackSize; + } + return S_OK; +} +*/ + +/* + +#include "../../../Common/Defs.h" + +Z7_COM7F_IMF(COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + while (size > 0) + { + if (_streamIndex >= Streams.Size()) + { + CSubStreamInfo subStream; + RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size)) + RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream)) + subStream.Pos = 0; + Streams.Add(subStream); + continue; + } + CSubStreamInfo &subStream = Streams[_streamIndex]; + if (_offsetPos >= subStream.Size) + { + _offsetPos -= subStream.Size; + _streamIndex++; + continue; + } + if (_offsetPos != subStream.Pos) + { + CMyComPtr outStream; + RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)) + RINOK(outStream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL)) + subStream.Pos = _offsetPos; + } + + const UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos); + UInt32 realProcessed; + RINOK(subStream.Stream->Write(data, curSize, &realProcessed)) + data = (const void *)((const Byte *)data + realProcessed); + size -= realProcessed; + subStream.Pos += realProcessed; + _offsetPos += realProcessed; + _absPos += realProcessed; + if (_absPos > _length) + _length = _absPos; + if (processedSize) + *processedSize += realProcessed; + if (subStream.Pos == subStream.Size) + { + _streamIndex++; + _offsetPos = 0; + } + if (realProcessed != curSize && realProcessed == 0) + return E_FAIL; + } + return S_OK; +} + +Z7_COM7F_IMF(COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _absPos; break; + case STREAM_SEEK_END: offset += _length; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _absPos = (UInt64)offset; + _offsetPos = _absPos; + _streamIndex = 0; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} +*/ diff --git a/CPP/7zip/Archive/Common/MultiStream.h b/CPP/7zip/Archive/Common/MultiStream.h index ad25e6ce8..901b6ea2a 100644 --- a/CPP/7zip/Archive/Common/MultiStream.h +++ b/CPP/7zip/Archive/Common/MultiStream.h @@ -1,86 +1,86 @@ -// MultiStream.h - -#ifndef ZIP7_INC_MULTI_STREAM_H -#define ZIP7_INC_MULTI_STREAM_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyVector.h" - -#include "../../IStream.h" -#include "../../Archive/IArchive.h" - -Z7_CLASS_IMP_IInStream( - CMultiStream -) - - unsigned _streamIndex; - UInt64 _pos; - UInt64 _totalLength; - -public: - - struct CSubStreamInfo - { - CMyComPtr Stream; - UInt64 Size; - UInt64 GlobalOffset; - UInt64 LocalPos; - CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {} - }; - - CMyComPtr updateCallbackFile; - CObjectVector Streams; - - HRESULT Init() - { - UInt64 total = 0; - FOR_VECTOR (i, Streams) - { - CSubStreamInfo &s = Streams[i]; - s.GlobalOffset = total; - total += s.Size; - s.LocalPos = 0; - { - // it was already set to start - // RINOK(InStream_GetPos(s.Stream, s.LocalPos)); - } - } - _totalLength = total; - _pos = 0; - _streamIndex = 0; - return S_OK; - } -}; - -/* -Z7_CLASS_IMP_COM_1( - COutMultiStream, - IOutStream -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - unsigned _streamIndex; // required stream - UInt64 _offsetPos; // offset from start of _streamIndex index - UInt64 _absPos; - UInt64 _length; - - struct CSubStreamInfo - { - CMyComPtr Stream; - UInt64 Size; - UInt64 Pos; - }; - CObjectVector Streams; -public: - CMyComPtr VolumeCallback; - void Init() - { - _streamIndex = 0; - _offsetPos = 0; - _absPos = 0; - _length = 0; - } -}; -*/ - -#endif +// MultiStream.h + +#ifndef ZIP7_INC_MULTI_STREAM_H +#define ZIP7_INC_MULTI_STREAM_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyVector.h" + +#include "../../IStream.h" +#include "../../Archive/IArchive.h" + +Z7_CLASS_IMP_IInStream( + CMultiStream +) + + unsigned _streamIndex; + UInt64 _pos; + UInt64 _totalLength; + +public: + + struct CSubStreamInfo + { + CMyComPtr Stream; + UInt64 Size; + UInt64 GlobalOffset; + UInt64 LocalPos; + CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {} + }; + + CMyComPtr updateCallbackFile; + CObjectVector Streams; + + HRESULT Init() + { + UInt64 total = 0; + FOR_VECTOR (i, Streams) + { + CSubStreamInfo &s = Streams[i]; + s.GlobalOffset = total; + total += s.Size; + s.LocalPos = 0; + { + // it was already set to start + // RINOK(InStream_GetPos(s.Stream, s.LocalPos)); + } + } + _totalLength = total; + _pos = 0; + _streamIndex = 0; + return S_OK; + } +}; + +/* +Z7_CLASS_IMP_COM_1( + COutMultiStream, + IOutStream +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + unsigned _streamIndex; // required stream + UInt64 _offsetPos; // offset from start of _streamIndex index + UInt64 _absPos; + UInt64 _length; + + struct CSubStreamInfo + { + CMyComPtr Stream; + UInt64 Size; + UInt64 Pos; + }; + CObjectVector Streams; +public: + CMyComPtr VolumeCallback; + void Init() + { + _streamIndex = 0; + _offsetPos = 0; + _absPos = 0; + _length = 0; + } +}; +*/ + +#endif diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp index 086f8e9c5..7dcd44ac1 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp +++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp @@ -1,18 +1,18 @@ -// OutStreamWithCRC.cpp - -#include "StdAfx.h" - -#include "OutStreamWithCRC.h" - -Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - if (_calculate) - _crc = CrcUpdate(_crc, data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} +// OutStreamWithCRC.cpp + +#include "StdAfx.h" + +#include "OutStreamWithCRC.h" + +Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + _crc = CrcUpdate(_crc, data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/CPP/7zip/Archive/Common/OutStreamWithCRC.h index 6e83002da..845146a1b 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h +++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h @@ -1,35 +1,35 @@ -// OutStreamWithCRC.h - -#ifndef ZIP7_INC_OUT_STREAM_WITH_CRC_H -#define ZIP7_INC_OUT_STREAM_WITH_CRC_H - -#include "../../../../C/7zCrc.h" - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithCRC - , ISequentialOutStream -) - CMyComPtr _stream; - UInt64 _size; - UInt32 _crc; - bool _calculate; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(bool calculate = true) - { - _size = 0; - _calculate = calculate; - _crc = CRC_INIT_VAL; - } - void EnableCalc(bool calculate) { _calculate = calculate; } - void InitCRC() { _crc = CRC_INIT_VAL; } - UInt64 GetSize() const { return _size; } - UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } -}; - -#endif +// OutStreamWithCRC.h + +#ifndef ZIP7_INC_OUT_STREAM_WITH_CRC_H +#define ZIP7_INC_OUT_STREAM_WITH_CRC_H + +#include "../../../../C/7zCrc.h" + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithCRC + , ISequentialOutStream +) + CMyComPtr _stream; + UInt64 _size; + UInt32 _crc; + bool _calculate; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate = true) + { + _size = 0; + _calculate = calculate; + _crc = CRC_INIT_VAL; + } + void EnableCalc(bool calculate) { _calculate = calculate; } + void InitCRC() { _crc = CRC_INIT_VAL; } + UInt64 GetSize() const { return _size; } + UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } +}; + +#endif diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp index d223af2e0..2916c30bb 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp @@ -1,29 +1,29 @@ -// OutStreamWithSha1.cpp - -#include "StdAfx.h" - -#include "OutStreamWithSha1.h" - -Z7_COM7F_IMF(COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - if (_calculate) - Sha1_Update(Sha(), (const Byte *)data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -Z7_COM7F_IMF(CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize; - const HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - Sha1_Update(Sha(), (const Byte *)data, realProcessedSize); - if (processedSize) - *processedSize = realProcessedSize; - return result; -} +// OutStreamWithSha1.cpp + +#include "StdAfx.h" + +#include "OutStreamWithSha1.h" + +Z7_COM7F_IMF(COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + Sha1_Update(Sha(), (const Byte *)data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +Z7_COM7F_IMF(CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize; + const HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + Sha1_Update(Sha(), (const Byte *)data, realProcessedSize); + if (processedSize) + *processedSize = realProcessedSize; + return result; +} diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h index 5dfaa45f6..28b2587ed 100644 --- a/CPP/7zip/Archive/Common/OutStreamWithSha1.h +++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h @@ -1,61 +1,61 @@ -// OutStreamWithSha1.h - -#ifndef ZIP7_INC_OUT_STREAM_WITH_SHA1_H -#define ZIP7_INC_OUT_STREAM_WITH_SHA1_H - -#include "../../../../C/Sha1.h" - -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithSha1 - , ISequentialOutStream -) - bool _calculate; - CMyComPtr _stream; - CAlignedBuffer1 _sha; - UInt64 _size; - - CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_sha; } -public: - COutStreamWithSha1(): _sha(sizeof(CSha1)) {} - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(bool calculate = true) - { - _calculate = calculate; - _size = 0; - Sha1_Init(Sha()); - } - void InitSha1() { Sha1_Init(Sha()); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { Sha1_Final(Sha(), digest); } -}; - - -Z7_CLASS_IMP_NOQIB_1( - CInStreamWithSha1 - , ISequentialInStream -) - CMyComPtr _stream; - CAlignedBuffer1 _sha; - UInt64 _size; - - CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_sha; } -public: - CInStreamWithSha1(): _sha(sizeof(CSha1)) {} - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - Sha1_Init(Sha()); - } - void ReleaseStream() { _stream.Release(); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { Sha1_Final(Sha(), digest); } -}; - -#endif +// OutStreamWithSha1.h + +#ifndef ZIP7_INC_OUT_STREAM_WITH_SHA1_H +#define ZIP7_INC_OUT_STREAM_WITH_SHA1_H + +#include "../../../../C/Sha1.h" + +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithSha1 + , ISequentialOutStream +) + bool _calculate; + CMyComPtr _stream; + CAlignedBuffer1 _sha; + UInt64 _size; + + CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_sha; } +public: + COutStreamWithSha1(): _sha(sizeof(CSha1)) {} + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate = true) + { + _calculate = calculate; + _size = 0; + Sha1_Init(Sha()); + } + void InitSha1() { Sha1_Init(Sha()); } + UInt64 GetSize() const { return _size; } + void Final(Byte *digest) { Sha1_Final(Sha(), digest); } +}; + + +Z7_CLASS_IMP_NOQIB_1( + CInStreamWithSha1 + , ISequentialInStream +) + CMyComPtr _stream; + CAlignedBuffer1 _sha; + UInt64 _size; + + CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_sha; } +public: + CInStreamWithSha1(): _sha(sizeof(CSha1)) {} + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init() + { + _size = 0; + Sha1_Init(Sha()); + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + void Final(Byte *digest) { Sha1_Final(Sha(), digest); } +}; + +#endif diff --git a/CPP/7zip/Archive/Common/ParseProperties.cpp b/CPP/7zip/Archive/Common/ParseProperties.cpp index 0fe89b3d2..63e4f3efc 100644 --- a/CPP/7zip/Archive/Common/ParseProperties.cpp +++ b/CPP/7zip/Archive/Common/ParseProperties.cpp @@ -1,3 +1,3 @@ -// ParseProperties.cpp - -#include "StdAfx.h" +// ParseProperties.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/Common/ParseProperties.h b/CPP/7zip/Archive/Common/ParseProperties.h index 09d542538..4ec2e48ed 100644 --- a/CPP/7zip/Archive/Common/ParseProperties.h +++ b/CPP/7zip/Archive/Common/ParseProperties.h @@ -1,6 +1,6 @@ -// ParseProperties.h - -#ifndef ZIP7_INC_PARSE_PROPERTIES_H -#define ZIP7_INC_PARSE_PROPERTIES_H - -#endif +// ParseProperties.h + +#ifndef ZIP7_INC_PARSE_PROPERTIES_H +#define ZIP7_INC_PARSE_PROPERTIES_H + +#endif diff --git a/CPP/7zip/Archive/Common/StdAfx.h b/CPP/7zip/Archive/Common/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Common/StdAfx.h +++ b/CPP/7zip/Archive/Common/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp index 288399ea0..2228040e0 100644 --- a/CPP/7zip/Archive/CpioHandler.cpp +++ b/CPP/7zip/Archive/CpioHandler.cpp @@ -1,1110 +1,1110 @@ -// CpioHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyLinux.h" -#include "../../Common/StringConvert.h" -#include "../../Common/StringToInt.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/ItemNameUtils.h" - -using namespace NWindows; - -namespace NArchive { -namespace NCpio { - -static const Byte kMagicBin0 = 0xC7; -static const Byte kMagicBin1 = 0x71; - -static const Byte kMagicHex = '1'; // New ASCII Format -static const Byte kMagicHexCrc = '2'; // New CRC Format -static const Byte kMagicOct = '7'; // Portable ASCII Format - -static const char * const kName_TRAILER = "TRAILER!!!"; - -static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4; -static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11; -static const unsigned k_HexRecord_Size = 6 + 13 * 8; - -static const unsigned k_RecordSize_Max = k_HexRecord_Size; - -enum EType -{ - k_Type_BinLe, - k_Type_BinBe, - k_Type_Oct, - k_Type_Hex, - k_Type_HexCrc -}; - -static const char * const k_Types[] = -{ - "Binary LE" - , "Binary BE" - , "Portable ASCII" - , "New ASCII" - , "New CRC" -}; - -struct CItem -{ - UInt32 inode; - unsigned MainIndex_ForInode; - UInt32 Mode; - UInt32 MTime; - UInt32 DevMajor; - UInt32 DevMinor; - UInt64 Size; - AString Name; - UInt32 NumLinks; - UInt32 UID; - UInt32 GID; - UInt32 RDevMajor; - UInt32 RDevMinor; - UInt32 ChkSum; - - UInt32 AlignMask; - EType Type; - - UInt32 HeaderSize; - UInt64 HeaderPos; - - CByteBuffer Data; // for symlink - - - UInt32 GetAlignedSize(UInt32 size) const - { - return (size + AlignMask) & ~(UInt32)AlignMask; - } - - UInt64 GetPackSize() const - { - const UInt64 alignMask64 = AlignMask; - return (Size + alignMask64) & ~(UInt64)alignMask64; - } - - bool IsSame_inode_Dev(const CItem &item) const - { - return inode == item.inode - && DevMajor == item.DevMajor - && DevMinor == item.DevMinor; - } - - bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; } - bool IsCrcFormat() const { return Type == k_Type_HexCrc; } - bool IsDir() const { return MY_LIN_S_ISDIR(Mode); } - bool Is_SymLink() const { return MY_LIN_S_ISLNK(Mode); } - bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; } - UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } -}; - - -enum EErrorType -{ - k_ErrorType_OK, - k_ErrorType_BadSignature, - k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd -}; - - -struct CInArchive -{ - EErrorType errorType; - ISequentialInStream *Stream; - UInt64 Processed; - CItem item; - - HRESULT Read(void *data, size_t *size); - HRESULT GetNextItem(); -}; - -HRESULT CInArchive::Read(void *data, size_t *size) -{ - const HRESULT res = ReadStream(Stream, data, size); - Processed += *size; - return res; -} - - -static bool CheckOctRecord(const Byte *p) -{ - for (unsigned i = 6; i < k_OctRecord_Size; i++) - { - const unsigned c = (unsigned)p[i] - '0'; - if (c > 7) - return false; - } - return true; -} - -static bool CheckHexRecord(const Byte *p) -{ - for (unsigned i = 6; i < k_HexRecord_Size; i++) - { - unsigned c = p[i]; - c -= '0'; - if (c > 9) - { - c -= 'A' - '0'; - c &= ~0x20u; - if (c > 5) - return false; - } - } - return true; -} - -static UInt32 ReadHex(const Byte *p) -{ - char sz[16]; - memcpy(sz, p, 8); - sz[8] = 0; - const char *end; - return ConvertHexStringToUInt32(sz, &end); -} - -static UInt32 ReadOct6(const Byte *p) -{ - char sz[16]; - memcpy(sz, p, 6); - sz[6] = 0; - const char *end; - return ConvertOctStringToUInt32(sz, &end); -} - -static UInt64 ReadOct11(const Byte *p) -{ - char sz[16]; - memcpy(sz, p, 11); - sz[11] = 0; - const char *end; - return ConvertOctStringToUInt64(sz, &end); -} - - -#define READ_HEX( y, dest) dest = ReadHex (p + 6 + (y) * 8); -#define READ_OCT_6( y, dest) dest = ReadOct6 (p + 6 + (y)); -#define READ_OCT_11( y, dest) dest = ReadOct11(p + 6 + (y)); - -#define Get32spec(p) (((UInt32)GetUi16(p) << 16) + GetUi16(p + 2)) -#define G16(offs, v) v = GetUi16(p + (offs)) -#define G32(offs, v) v = Get32spec(p + (offs)) - -static const unsigned kNameSizeMax = 1 << 12; - - -API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size) -{ - if (size < k_BinRecord_Size) - return k_IsArc_Res_NEED_MORE; - - UInt32 namePos; - UInt32 nameSize; - UInt32 mode; - // UInt32 rDevMinor; - UInt32 rDevMajor = 0; - - if (p[0] == '0') - { - if (p[1] != '7' || - p[2] != '0' || - p[3] != '7' || - p[4] != '0') - return k_IsArc_Res_NO; - if (p[5] == kMagicOct) - { - if (size < k_OctRecord_Size) - return k_IsArc_Res_NEED_MORE; - if (!CheckOctRecord(p)) - return k_IsArc_Res_NO; - READ_OCT_6 (2 * 6, mode) - // READ_OCT_6 (6 * 6, rDevMinor) - READ_OCT_6 (7 * 6 + 11, nameSize) - namePos = k_OctRecord_Size; - } - else if (p[5] == kMagicHex || p[5] == kMagicHexCrc) - { - if (size < k_HexRecord_Size) - return k_IsArc_Res_NEED_MORE; - if (!CheckHexRecord(p)) - return k_IsArc_Res_NO; - READ_HEX (1, mode) - READ_HEX (9, rDevMajor) - // READ_HEX (10, rDevMinor) - READ_HEX (11, nameSize) - namePos = k_HexRecord_Size; - } - else - return k_IsArc_Res_NO; - } - else - { - if (p[0] == kMagicBin0 && p[1] == kMagicBin1) - { - mode = GetUi16(p + 6); - // rDevMinor = GetUi16(p + 14); - nameSize = GetUi16(p + 20); - } - else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) - { - mode = GetBe16(p + 6); - // rDevMinor = GetBe16(p + 14); - nameSize = GetBe16(p + 20); - } - else - return k_IsArc_Res_NO; - namePos = k_BinRecord_Size; - } - - if (mode >= (1 << 16)) - return k_IsArc_Res_NO; - - /* v23.02: we have disabled rDevMinor check because real file - from Apple contains rDevMinor==255 by some unknown reason */ - if (rDevMajor != 0 - // || rDevMinor != 0 - ) - { - if (!MY_LIN_S_ISCHR(mode) && - !MY_LIN_S_ISBLK(mode)) - return k_IsArc_Res_NO; - } - - // nameSize must include the null byte - if (nameSize == 0 || nameSize > kNameSizeMax) - return k_IsArc_Res_NO; - { - unsigned lim = namePos + nameSize - 1; - if (lim >= size) - lim = (unsigned)size; - else if (p[lim] != 0) - return k_IsArc_Res_NO; - for (unsigned i = namePos; i < lim; i++) - if (p[i] == 0) - return k_IsArc_Res_NO; - } - - return k_IsArc_Res_YES; -} -} - - -#define READ_STREAM(_dest_, _size_) \ - { size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \ -if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } } - -HRESULT CInArchive::GetNextItem() -{ - errorType = k_ErrorType_BadSignature; - - Byte p[k_RecordSize_Max]; - - READ_STREAM(p, k_BinRecord_Size) - - UInt32 nameSize; - UInt32 namePos; - - /* we try to reduce probability of false detection, - so we check some fields for unuxpected values */ - - if (p[0] != '0') - { - if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { item.Type = k_Type_BinLe; } - else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) - { - for (unsigned i = 2; i < k_BinRecord_Size; i += 2) - { - const Byte b = p[i]; - p[i] = p[i + 1]; - p[i + 1] = b; - } - item.Type = k_Type_BinBe; - } - else - return S_OK; - - errorType = k_ErrorType_Corrupted; - - item.AlignMask = 2 - 1; - item.DevMajor = 0; - item.RDevMajor = 0; - item.ChkSum = 0; - - G16(2, item.DevMinor); - G16(4, item.inode); - G16(6, item.Mode); - G16(8, item.UID); - G16(10, item.GID); - G16(12, item.NumLinks); - G16(14, item.RDevMinor); - G32(16, item.MTime); - G16(20, nameSize); - G32(22, item.Size); - - namePos = k_BinRecord_Size; - } - else - { - if (p[1] != '7' || - p[2] != '0' || - p[3] != '7' || - p[4] != '0') - return S_OK; - if (p[5] == kMagicOct) - { - errorType = k_ErrorType_Corrupted; - - item.Type = k_Type_Oct; - READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size) - item.AlignMask = 1 - 1; - item.DevMajor = 0; - item.RDevMajor = 0; - item.ChkSum = 0; - - if (!CheckOctRecord(p)) - return S_OK; - - READ_OCT_6 (0, item.DevMinor) - READ_OCT_6 (1 * 6, item.inode) - READ_OCT_6 (2 * 6, item.Mode) - READ_OCT_6 (3 * 6, item.UID) - READ_OCT_6 (4 * 6, item.GID) - READ_OCT_6 (5 * 6, item.NumLinks) - READ_OCT_6 (6 * 6, item.RDevMinor) - { - UInt64 mTime64; - READ_OCT_11 (7 * 6, mTime64) - item.MTime = 0; - if (mTime64 <= (UInt32)(Int32)-1) - item.MTime = (UInt32)mTime64; - } - READ_OCT_6 (7 * 6 + 11, nameSize) - READ_OCT_11 (8 * 6 + 11, item.Size) // ????? - - namePos = k_OctRecord_Size; - } - else - { - if (p[5] == kMagicHex) item.Type = k_Type_Hex; - else if (p[5] == kMagicHexCrc) item.Type = k_Type_HexCrc; - else return S_OK; - - errorType = k_ErrorType_Corrupted; - - READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size) - - if (!CheckHexRecord(p)) - return S_OK; - - item.AlignMask = 4 - 1; - READ_HEX (0, item.inode) - READ_HEX (1, item.Mode) - READ_HEX (2, item.UID) - READ_HEX (3, item.GID) - READ_HEX (4, item.NumLinks) - READ_HEX (5, item.MTime) - READ_HEX (6, item.Size) - READ_HEX (7, item.DevMajor) - READ_HEX (8, item.DevMinor) - READ_HEX (9, item.RDevMajor) - READ_HEX (10, item.RDevMinor) - READ_HEX (11, nameSize) - READ_HEX (12, item.ChkSum) - - if (item.Type == k_Type_Hex && item.ChkSum != 0) - return S_OK; - - namePos = k_HexRecord_Size; - } - } - - if (item.Mode >= (1 << 16)) - return S_OK; - - /* v23.02: we have disabled rDevMinor check because real file - from Apple contains rDevMinor==255 by some unknown reason */ - if (item.RDevMajor != 0 - // || item.RDevMinor != 0 - ) - { - if (!MY_LIN_S_ISCHR(item.Mode) && - !MY_LIN_S_ISBLK(item.Mode)) - return S_OK; - } - - // Size must be 0 for FIFOs and directories - if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode)) - if (item.Size != 0) - return S_OK; - - // nameSize must include the null byte - if (nameSize == 0 || nameSize > kNameSizeMax) - return S_OK; - item.HeaderSize = item.GetAlignedSize(namePos + nameSize); - const UInt32 rem = item.HeaderSize - namePos; - char *s = item.Name.GetBuf(rem); - size_t processedSize = rem; - RINOK(Read(s, &processedSize)) - if (processedSize != rem) - { - item.Name.ReleaseBuf_SetEnd(0); - errorType = k_ErrorType_UnexpectedEnd; - return S_OK; - } - bool pad_error = false; - for (size_t i = nameSize; i < processedSize; i++) - if (s[i] != 0) - pad_error = true; - item.Name.ReleaseBuf_CalcLen(nameSize); - if (item.Name.Len() + 1 != nameSize || pad_error) - return S_OK; - errorType = k_ErrorType_OK; - return S_OK; -} - - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - EType _type; - EErrorType _error; - bool _isArc; - bool _moreThanOneHardLinks_Error; - bool _numLinks_Error; - bool _pad_Error; - bool _symLink_Error; -}; - -static const Byte kArcProps[] = -{ - kpidSubType -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidPosixAttrib, - kpidLinks, - kpidINode, - kpidUserId, - kpidGroupId, - kpidDevMajor, - kpidDevMinor, - kpidDeviceMajor, - kpidDeviceMinor, - kpidChecksum, - kpidSymLink, - kpidStreamId, // for debug - kpidOffset -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidSubType: prop = k_Types[(unsigned)_type]; break; - case kpidPhySize: prop = _phySize; break; - case kpidINode: prop = true; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) - v |= kpv_ErrorFlags_IsNotArc; - switch (_error) - { - case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break; - case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break; - case k_ErrorType_OK: - case k_ErrorType_BadSignature: - // default: - break; - } - prop = v; - break; - } - case kpidWarningFlags: - { - UInt32 v = 0; - if (_moreThanOneHardLinks_Error) - v |= kpv_ErrorFlags_UnsupportedFeature; // kpv_ErrorFlags_HeadersError - if (_numLinks_Error - || _pad_Error - || _symLink_Error) - v |= kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -static int CompareItems(const unsigned *p1, const unsigned *p2, void *param) -{ - const CObjectVector &items = *(const CObjectVector *)param; - const unsigned index1 = *p1; - const unsigned index2 = *p2; - const CItem &i1 = items[index1]; - const CItem &i2 = items[index2]; - if (i1.DevMajor < i2.DevMajor) return -1; - if (i1.DevMajor > i2.DevMajor) return 1; - if (i1.DevMinor < i2.DevMinor) return -1; - if (i1.DevMinor > i2.DevMinor) return 1; - if (i1.inode < i2.inode) return -1; - if (i1.inode > i2.inode) return 1; - if (i1.IsDir()) - { - if (!i2.IsDir()) - return -1; - } - else if (i2.IsDir()) - return 1; - return MyCompare(index1, index2); -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - - UInt64 endPos; - RINOK(InStream_AtBegin_GetSize(stream, endPos)) - if (callback) - { - RINOK(callback->SetTotal(NULL, &endPos)) - } - - CInArchive arc; - - arc.Stream = stream; - arc.Processed = 0; - - for (;;) - { - CItem &item = arc.item; - item.HeaderPos = arc.Processed; - - RINOK(arc.GetNextItem()) - - _error = arc.errorType; - - if (_error != k_ErrorType_OK) - { - if (_error == k_ErrorType_BadSignature || - _error == k_ErrorType_Corrupted) - arc.Processed = item.HeaderPos; - break; - } - - if (_items.IsEmpty()) - _type = item.Type; - else if (_items.Back().Type != item.Type) - { - _error = k_ErrorType_Corrupted; - arc.Processed = item.HeaderPos; - break; - } - - if (item.IsTrailer()) - break; - - item.MainIndex_ForInode = _items.Size(); - _items.Add(item); - - const UInt64 dataSize = item.GetPackSize(); - arc.Processed += dataSize; - if (arc.Processed > endPos) - { - _error = k_ErrorType_UnexpectedEnd; - break; - } - - if (item.Is_SymLink() && dataSize <= (1 << 12) && item.Size != 0) - { - size_t cur = (size_t)dataSize; - CByteBuffer buf; - buf.Alloc(cur); - RINOK(ReadStream(stream, buf, &cur)) - if (cur != dataSize) - { - _error = k_ErrorType_UnexpectedEnd; - break; - } - size_t i; - - for (i = (size_t)item.Size; i < dataSize; i++) - if (buf[i] != 0) - break; - if (i != dataSize) - _pad_Error = true; - - for (i = 0; i < (size_t)item.Size; i++) - if (buf[i] == 0) - break; - if (i != (size_t)item.Size) - _symLink_Error = true; - else - _items.Back().Data.CopyFrom(buf, (size_t)item.Size); - } - else if (dataSize != 0) - { - UInt64 newPos; - RINOK(stream->Seek((Int64)dataSize, STREAM_SEEK_CUR, &newPos)) - if (arc.Processed != newPos) - return E_FAIL; - } - - if (callback && (_items.Size() & 0xFFF) == 0) - { - const UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos)) - } - } - - _phySize = arc.Processed; - } - - { - if (_error != k_ErrorType_OK) - { - // we try to reduce probability of false detection - if (_items.Size() == 0) - return S_FALSE; - // bin file uses small signature. So we do additional check for single item case. - if (_items.Size() == 1 && _items[0].IsBin()) - return S_FALSE; - } - else - { - // Read tailing zeros. - // Most of cpio files use 512-bytes aligned zeros - // rare case: 4K/8K aligment is possible also - const unsigned kTailSize_MAX = 1 << 9; - Byte buf[kTailSize_MAX]; - - unsigned pos = (unsigned)_phySize & (kTailSize_MAX - 1); - if (pos != 0) // use this check to support 512 bytes alignment only - for (;;) - { - const unsigned rem = kTailSize_MAX - pos; - size_t processed = rem; - RINOK(ReadStream(stream, buf + pos, &processed)) - if (processed != rem) - break; - for (; pos < kTailSize_MAX && buf[pos] == 0; pos++) - {} - if (pos != kTailSize_MAX) - break; - _phySize += processed; - pos = 0; - - // use break to support 512 bytes alignment zero tail - // don't use break to support 512*n bytes alignment zero tail - break; - } - } - } - - { - /* there was such cpio archive example with hard links: - { - all hard links (same dev/inode) are stored in neighboring items, and - (item.Size == 0) for non last hard link items - (item.Size != 0) for last hard link item - } - but here we sort items by (dev/inode) to support cases - where hard links (same dev/inode) are not stored in neighboring items. - - // note: some cpio files have (numLinks == 0) ?? - */ - - CUIntVector indices; - { - const unsigned numItems = _items.Size(); - indices.ClearAndSetSize(numItems); - if (numItems != 0) - { - unsigned *vals = &indices[0]; - for (unsigned i = 0; i < numItems; i++) - vals[i] = i; - indices.Sort(CompareItems, (void *)&_items); - } - } - - /* Note: if cpio archive (maybe incorrect) contains - more then one non empty streams with identical inode number, - we want to extract all such data streams too. - - So we place items with identical inode to groups: - all items in group will have same MainIndex_ForInode, - that is index of last item in group with (Size != 0). - Another (non last) items in group have (Size == 0). - If there are another hard links with same inode number - after (Size != 0) item, we place them to another next group(s). - - Check it: maybe we should use single group for items - with identical inode instead, and ignore some extra data streams ? - */ - - for (unsigned i = 0; i < indices.Size();) - { - unsigned k; - { - const CItem &item_Base = _items[indices[i]]; - - if (item_Base.IsDir()) - { - i++; - continue; - } - - if (i != 0) - { - const CItem &item_Prev = _items[indices[i - 1]]; - if (!item_Prev.IsDir()) - if (item_Base.IsSame_inode_Dev(item_Prev)) - _moreThanOneHardLinks_Error = true; - } - - if (item_Base.Size != 0) - { - if (item_Base.NumLinks != 1) - _numLinks_Error = true; - i++; - continue; - } - - for (k = i + 1; k < indices.Size();) - { - const CItem &item = _items[indices[k]]; - if (item.IsDir()) - break; - if (!item.IsSame_inode_Dev(item_Base)) - break; - k++; - if (item.Size != 0) - break; - } - } - - const unsigned numLinks = k - i; - for (;;) - { - CItem &item = _items[indices[i]]; - if (item.NumLinks != numLinks) - _numLinks_Error = true; - if (++i == k) - break; - // if (item.Size == 0) - item.MainIndex_ForInode = indices[k - 1]; - } - } - } - - _isArc = true; - _stream = stream; - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _items.Clear(); - _stream.Release(); - _phySize = 0; - _type = k_Type_BinLe; - _isArc = false; - _moreThanOneHardLinks_Error = false; - _numLinks_Error = false; - _pad_Error = false; - _symLink_Error = false; - _error = k_ErrorType_OK; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItem &item = _items[index]; - - switch (propID) - { - case kpidPath: - { - UString res; - bool needConvert = true; - #ifdef _WIN32 - // if ( - ConvertUTF8ToUnicode(item.Name, res); - // ) - needConvert = false; - #endif - if (needConvert) - res = MultiByteToUnicodeString(item.Name, CP_OEMCP); - prop = NItemName::GetOsPath(res); - break; - } - case kpidIsDir: prop = item.IsDir(); break; - - case kpidSize: - prop = (UInt64)_items[item.MainIndex_ForInode].Size; - break; - - case kpidPackSize: - prop = (UInt64)item.GetPackSize(); - break; - - case kpidMTime: - { - if (item.MTime != 0) - PropVariant_SetFrom_UnixTime(prop, item.MTime); - break; - } - case kpidPosixAttrib: prop = item.Mode; break; - case kpidINode: prop = item.inode; break; - case kpidStreamId: - if (!item.IsDir()) - prop = (UInt32)item.MainIndex_ForInode; - break; - case kpidDevMajor: prop = (UInt32)item.DevMajor; break; - case kpidDevMinor: prop = (UInt32)item.DevMinor; break; - - case kpidUserId: prop = item.UID; break; - case kpidGroupId: prop = item.GID; break; - - case kpidSymLink: - if (item.Is_SymLink() && item.Data.Size() != 0) - { - AString s; - s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size()); - if (s.Len() == item.Data.Size()) - { - UString u; - bool needConvert = true; - #ifdef _WIN32 - // if ( - ConvertUTF8ToUnicode(item.Name, u); - // ) - needConvert = false; - #endif - if (needConvert) - u = MultiByteToUnicodeString(s, CP_OEMCP); - prop = u; - } - } - break; - - case kpidLinks: prop = item.NumLinks; break; - case kpidDeviceMajor: - // if (item.RDevMajor != 0) - prop = (UInt32)item.RDevMajor; - break; - case kpidDeviceMinor: - // if (item.RDevMinor != 0) - prop = (UInt32)item.RDevMinor; - break; - case kpidChecksum: - if (item.IsCrcFormat()) - prop = item.ChkSum; - break; - case kpidOffset: prop = item.GetDataPosition(); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithSum - , ISequentialOutStream -) - CMyComPtr _stream; - UInt32 _checksum; - bool _calculate; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(bool calculate) - { - _calculate = calculate; - _checksum = 0; - } - UInt32 GetChecksum() const { return _checksum; } -}; - - -Z7_COM7F_IMF(COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - if (processedSize) - *processedSize = size; - if (_calculate) - { - const Byte *p = (const Byte *)data; - const Byte *lim = p + size; - UInt32 sum = _checksum; - if (size >= 4) - { - lim -= 4 - 1; - do - { - sum += p[0] + p[1] + p[2] + p[3]; - p += 4; - } - while (p < lim); - lim += 4 - 1; - } - if (p != lim) { sum += *p++; - if (p != lim) { sum += *p++; - if (p != lim) { sum += *p++; }}} - _checksum = sum; - } - return result; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item2 = _items[index]; - const CItem &item = _items[item2.MainIndex_ForInode]; - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - CMyComPtr2_Create outStreamSum; - - UInt64 total_PackSize = 0; - UInt64 total_UnpackSize = 0; - - for (i = 0;; i++) - { - lps->InSize = total_PackSize; - lps->OutSize = total_UnpackSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item2 = _items[index]; - const CItem &item = _items[item2.MainIndex_ForInode]; - { - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - - total_PackSize += item2.GetPackSize(); - total_UnpackSize += item.Size; - - if (item2.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - if (!testMode && !outStream) - continue; - outStreamSum->Init(item.IsCrcFormat()); - outStreamSum->SetStream(outStream); - RINOK(extractCallback->PrepareOperation(askMode)) - } - RINOK(InStream_SeekSet(_stream, item.GetDataPosition())) - inStream->Init(item.Size); - RINOK(copyCoder.Interface()->Code(inStream, outStreamSum, NULL, NULL, lps)) - outStreamSum->ReleaseStream(); - Int32 res = NExtract::NOperationResult::kDataError; - if (copyCoder->TotalSize == item.Size) - { - res = NExtract::NOperationResult::kOK; - if (item.IsCrcFormat() && item.ChkSum != outStreamSum->GetChecksum()) - res = NExtract::NOperationResult::kCRCError; - } - RINOK(extractCallback->SetOperationResult(res)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - const CItem &item2 = _items[index]; - const CItem &item = _items[item2.MainIndex_ForInode]; - return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream); - COM_TRY_END -} - -static const Byte k_Signature[] = { - 5, '0', '7', '0', '7', '0', - 2, kMagicBin0, kMagicBin1, - 2, kMagicBin1, kMagicBin0 }; - -REGISTER_ARC_I( - "Cpio", "cpio", NULL, 0xED, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - IsArc_Cpio) - -}} +// CpioHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyLinux.h" +#include "../../Common/StringConvert.h" +#include "../../Common/StringToInt.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" + +using namespace NWindows; + +namespace NArchive { +namespace NCpio { + +static const Byte kMagicBin0 = 0xC7; +static const Byte kMagicBin1 = 0x71; + +static const Byte kMagicHex = '1'; // New ASCII Format +static const Byte kMagicHexCrc = '2'; // New CRC Format +static const Byte kMagicOct = '7'; // Portable ASCII Format + +static const char * const kName_TRAILER = "TRAILER!!!"; + +static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4; +static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11; +static const unsigned k_HexRecord_Size = 6 + 13 * 8; + +static const unsigned k_RecordSize_Max = k_HexRecord_Size; + +enum EType +{ + k_Type_BinLe, + k_Type_BinBe, + k_Type_Oct, + k_Type_Hex, + k_Type_HexCrc +}; + +static const char * const k_Types[] = +{ + "Binary LE" + , "Binary BE" + , "Portable ASCII" + , "New ASCII" + , "New CRC" +}; + +struct CItem +{ + UInt32 inode; + unsigned MainIndex_ForInode; + UInt32 Mode; + UInt32 MTime; + UInt32 DevMajor; + UInt32 DevMinor; + UInt64 Size; + AString Name; + UInt32 NumLinks; + UInt32 UID; + UInt32 GID; + UInt32 RDevMajor; + UInt32 RDevMinor; + UInt32 ChkSum; + + UInt32 AlignMask; + EType Type; + + UInt32 HeaderSize; + UInt64 HeaderPos; + + CByteBuffer Data; // for symlink + + + UInt32 GetAlignedSize(UInt32 size) const + { + return (size + AlignMask) & ~(UInt32)AlignMask; + } + + UInt64 GetPackSize() const + { + const UInt64 alignMask64 = AlignMask; + return (Size + alignMask64) & ~(UInt64)alignMask64; + } + + bool IsSame_inode_Dev(const CItem &item) const + { + return inode == item.inode + && DevMajor == item.DevMajor + && DevMinor == item.DevMinor; + } + + bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; } + bool IsCrcFormat() const { return Type == k_Type_HexCrc; } + bool IsDir() const { return MY_LIN_S_ISDIR(Mode); } + bool Is_SymLink() const { return MY_LIN_S_ISLNK(Mode); } + bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; } + UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } +}; + + +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_BadSignature, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd +}; + + +struct CInArchive +{ + EErrorType errorType; + ISequentialInStream *Stream; + UInt64 Processed; + CItem item; + + HRESULT Read(void *data, size_t *size); + HRESULT GetNextItem(); +}; + +HRESULT CInArchive::Read(void *data, size_t *size) +{ + const HRESULT res = ReadStream(Stream, data, size); + Processed += *size; + return res; +} + + +static bool CheckOctRecord(const Byte *p) +{ + for (unsigned i = 6; i < k_OctRecord_Size; i++) + { + const unsigned c = (unsigned)p[i] - '0'; + if (c > 7) + return false; + } + return true; +} + +static bool CheckHexRecord(const Byte *p) +{ + for (unsigned i = 6; i < k_HexRecord_Size; i++) + { + unsigned c = p[i]; + c -= '0'; + if (c > 9) + { + c -= 'A' - '0'; + c &= ~0x20u; + if (c > 5) + return false; + } + } + return true; +} + +static UInt32 ReadHex(const Byte *p) +{ + char sz[16]; + memcpy(sz, p, 8); + sz[8] = 0; + const char *end; + return ConvertHexStringToUInt32(sz, &end); +} + +static UInt32 ReadOct6(const Byte *p) +{ + char sz[16]; + memcpy(sz, p, 6); + sz[6] = 0; + const char *end; + return ConvertOctStringToUInt32(sz, &end); +} + +static UInt64 ReadOct11(const Byte *p) +{ + char sz[16]; + memcpy(sz, p, 11); + sz[11] = 0; + const char *end; + return ConvertOctStringToUInt64(sz, &end); +} + + +#define READ_HEX( y, dest) dest = ReadHex (p + 6 + (y) * 8); +#define READ_OCT_6( y, dest) dest = ReadOct6 (p + 6 + (y)); +#define READ_OCT_11( y, dest) dest = ReadOct11(p + 6 + (y)); + +#define Get32spec(p) (((UInt32)GetUi16(p) << 16) + GetUi16(p + 2)) +#define G16(offs, v) v = GetUi16(p + (offs)) +#define G32(offs, v) v = Get32spec(p + (offs)) + +static const unsigned kNameSizeMax = 1 << 12; + + +API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size) +{ + if (size < k_BinRecord_Size) + return k_IsArc_Res_NEED_MORE; + + UInt32 namePos; + UInt32 nameSize; + UInt32 mode; + // UInt32 rDevMinor; + UInt32 rDevMajor = 0; + + if (p[0] == '0') + { + if (p[1] != '7' || + p[2] != '0' || + p[3] != '7' || + p[4] != '0') + return k_IsArc_Res_NO; + if (p[5] == kMagicOct) + { + if (size < k_OctRecord_Size) + return k_IsArc_Res_NEED_MORE; + if (!CheckOctRecord(p)) + return k_IsArc_Res_NO; + READ_OCT_6 (2 * 6, mode) + // READ_OCT_6 (6 * 6, rDevMinor) + READ_OCT_6 (7 * 6 + 11, nameSize) + namePos = k_OctRecord_Size; + } + else if (p[5] == kMagicHex || p[5] == kMagicHexCrc) + { + if (size < k_HexRecord_Size) + return k_IsArc_Res_NEED_MORE; + if (!CheckHexRecord(p)) + return k_IsArc_Res_NO; + READ_HEX (1, mode) + READ_HEX (9, rDevMajor) + // READ_HEX (10, rDevMinor) + READ_HEX (11, nameSize) + namePos = k_HexRecord_Size; + } + else + return k_IsArc_Res_NO; + } + else + { + if (p[0] == kMagicBin0 && p[1] == kMagicBin1) + { + mode = GetUi16(p + 6); + // rDevMinor = GetUi16(p + 14); + nameSize = GetUi16(p + 20); + } + else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) + { + mode = GetBe16(p + 6); + // rDevMinor = GetBe16(p + 14); + nameSize = GetBe16(p + 20); + } + else + return k_IsArc_Res_NO; + namePos = k_BinRecord_Size; + } + + if (mode >= (1 << 16)) + return k_IsArc_Res_NO; + + /* v23.02: we have disabled rDevMinor check because real file + from Apple contains rDevMinor==255 by some unknown reason */ + if (rDevMajor != 0 + // || rDevMinor != 0 + ) + { + if (!MY_LIN_S_ISCHR(mode) && + !MY_LIN_S_ISBLK(mode)) + return k_IsArc_Res_NO; + } + + // nameSize must include the null byte + if (nameSize == 0 || nameSize > kNameSizeMax) + return k_IsArc_Res_NO; + { + unsigned lim = namePos + nameSize - 1; + if (lim >= size) + lim = (unsigned)size; + else if (p[lim] != 0) + return k_IsArc_Res_NO; + for (unsigned i = namePos; i < lim; i++) + if (p[i] == 0) + return k_IsArc_Res_NO; + } + + return k_IsArc_Res_YES; +} +} + + +#define READ_STREAM(_dest_, _size_) \ + { size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \ +if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } } + +HRESULT CInArchive::GetNextItem() +{ + errorType = k_ErrorType_BadSignature; + + Byte p[k_RecordSize_Max]; + + READ_STREAM(p, k_BinRecord_Size) + + UInt32 nameSize; + UInt32 namePos; + + /* we try to reduce probability of false detection, + so we check some fields for unuxpected values */ + + if (p[0] != '0') + { + if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { item.Type = k_Type_BinLe; } + else if (p[0] == kMagicBin1 && p[1] == kMagicBin0) + { + for (unsigned i = 2; i < k_BinRecord_Size; i += 2) + { + const Byte b = p[i]; + p[i] = p[i + 1]; + p[i + 1] = b; + } + item.Type = k_Type_BinBe; + } + else + return S_OK; + + errorType = k_ErrorType_Corrupted; + + item.AlignMask = 2 - 1; + item.DevMajor = 0; + item.RDevMajor = 0; + item.ChkSum = 0; + + G16(2, item.DevMinor); + G16(4, item.inode); + G16(6, item.Mode); + G16(8, item.UID); + G16(10, item.GID); + G16(12, item.NumLinks); + G16(14, item.RDevMinor); + G32(16, item.MTime); + G16(20, nameSize); + G32(22, item.Size); + + namePos = k_BinRecord_Size; + } + else + { + if (p[1] != '7' || + p[2] != '0' || + p[3] != '7' || + p[4] != '0') + return S_OK; + if (p[5] == kMagicOct) + { + errorType = k_ErrorType_Corrupted; + + item.Type = k_Type_Oct; + READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size) + item.AlignMask = 1 - 1; + item.DevMajor = 0; + item.RDevMajor = 0; + item.ChkSum = 0; + + if (!CheckOctRecord(p)) + return S_OK; + + READ_OCT_6 (0, item.DevMinor) + READ_OCT_6 (1 * 6, item.inode) + READ_OCT_6 (2 * 6, item.Mode) + READ_OCT_6 (3 * 6, item.UID) + READ_OCT_6 (4 * 6, item.GID) + READ_OCT_6 (5 * 6, item.NumLinks) + READ_OCT_6 (6 * 6, item.RDevMinor) + { + UInt64 mTime64; + READ_OCT_11 (7 * 6, mTime64) + item.MTime = 0; + if (mTime64 <= (UInt32)(Int32)-1) + item.MTime = (UInt32)mTime64; + } + READ_OCT_6 (7 * 6 + 11, nameSize) + READ_OCT_11 (8 * 6 + 11, item.Size) // ????? + + namePos = k_OctRecord_Size; + } + else + { + if (p[5] == kMagicHex) item.Type = k_Type_Hex; + else if (p[5] == kMagicHexCrc) item.Type = k_Type_HexCrc; + else return S_OK; + + errorType = k_ErrorType_Corrupted; + + READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size) + + if (!CheckHexRecord(p)) + return S_OK; + + item.AlignMask = 4 - 1; + READ_HEX (0, item.inode) + READ_HEX (1, item.Mode) + READ_HEX (2, item.UID) + READ_HEX (3, item.GID) + READ_HEX (4, item.NumLinks) + READ_HEX (5, item.MTime) + READ_HEX (6, item.Size) + READ_HEX (7, item.DevMajor) + READ_HEX (8, item.DevMinor) + READ_HEX (9, item.RDevMajor) + READ_HEX (10, item.RDevMinor) + READ_HEX (11, nameSize) + READ_HEX (12, item.ChkSum) + + if (item.Type == k_Type_Hex && item.ChkSum != 0) + return S_OK; + + namePos = k_HexRecord_Size; + } + } + + if (item.Mode >= (1 << 16)) + return S_OK; + + /* v23.02: we have disabled rDevMinor check because real file + from Apple contains rDevMinor==255 by some unknown reason */ + if (item.RDevMajor != 0 + // || item.RDevMinor != 0 + ) + { + if (!MY_LIN_S_ISCHR(item.Mode) && + !MY_LIN_S_ISBLK(item.Mode)) + return S_OK; + } + + // Size must be 0 for FIFOs and directories + if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode)) + if (item.Size != 0) + return S_OK; + + // nameSize must include the null byte + if (nameSize == 0 || nameSize > kNameSizeMax) + return S_OK; + item.HeaderSize = item.GetAlignedSize(namePos + nameSize); + const UInt32 rem = item.HeaderSize - namePos; + char *s = item.Name.GetBuf(rem); + size_t processedSize = rem; + RINOK(Read(s, &processedSize)) + if (processedSize != rem) + { + item.Name.ReleaseBuf_SetEnd(0); + errorType = k_ErrorType_UnexpectedEnd; + return S_OK; + } + bool pad_error = false; + for (size_t i = nameSize; i < processedSize; i++) + if (s[i] != 0) + pad_error = true; + item.Name.ReleaseBuf_CalcLen(nameSize); + if (item.Name.Len() + 1 != nameSize || pad_error) + return S_OK; + errorType = k_ErrorType_OK; + return S_OK; +} + + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + EType _type; + EErrorType _error; + bool _isArc; + bool _moreThanOneHardLinks_Error; + bool _numLinks_Error; + bool _pad_Error; + bool _symLink_Error; +}; + +static const Byte kArcProps[] = +{ + kpidSubType +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidPosixAttrib, + kpidLinks, + kpidINode, + kpidUserId, + kpidGroupId, + kpidDevMajor, + kpidDevMinor, + kpidDeviceMajor, + kpidDeviceMinor, + kpidChecksum, + kpidSymLink, + kpidStreamId, // for debug + kpidOffset +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidSubType: prop = k_Types[(unsigned)_type]; break; + case kpidPhySize: prop = _phySize; break; + case kpidINode: prop = true; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + switch (_error) + { + case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break; + case k_ErrorType_OK: + case k_ErrorType_BadSignature: + // default: + break; + } + prop = v; + break; + } + case kpidWarningFlags: + { + UInt32 v = 0; + if (_moreThanOneHardLinks_Error) + v |= kpv_ErrorFlags_UnsupportedFeature; // kpv_ErrorFlags_HeadersError + if (_numLinks_Error + || _pad_Error + || _symLink_Error) + v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static int CompareItems(const unsigned *p1, const unsigned *p2, void *param) +{ + const CObjectVector &items = *(const CObjectVector *)param; + const unsigned index1 = *p1; + const unsigned index2 = *p2; + const CItem &i1 = items[index1]; + const CItem &i2 = items[index2]; + if (i1.DevMajor < i2.DevMajor) return -1; + if (i1.DevMajor > i2.DevMajor) return 1; + if (i1.DevMinor < i2.DevMinor) return -1; + if (i1.DevMinor > i2.DevMinor) return 1; + if (i1.inode < i2.inode) return -1; + if (i1.inode > i2.inode) return 1; + if (i1.IsDir()) + { + if (!i2.IsDir()) + return -1; + } + else if (i2.IsDir()) + return 1; + return MyCompare(index1, index2); +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + + UInt64 endPos; + RINOK(InStream_AtBegin_GetSize(stream, endPos)) + if (callback) + { + RINOK(callback->SetTotal(NULL, &endPos)) + } + + CInArchive arc; + + arc.Stream = stream; + arc.Processed = 0; + + for (;;) + { + CItem &item = arc.item; + item.HeaderPos = arc.Processed; + + RINOK(arc.GetNextItem()) + + _error = arc.errorType; + + if (_error != k_ErrorType_OK) + { + if (_error == k_ErrorType_BadSignature || + _error == k_ErrorType_Corrupted) + arc.Processed = item.HeaderPos; + break; + } + + if (_items.IsEmpty()) + _type = item.Type; + else if (_items.Back().Type != item.Type) + { + _error = k_ErrorType_Corrupted; + arc.Processed = item.HeaderPos; + break; + } + + if (item.IsTrailer()) + break; + + item.MainIndex_ForInode = _items.Size(); + _items.Add(item); + + const UInt64 dataSize = item.GetPackSize(); + arc.Processed += dataSize; + if (arc.Processed > endPos) + { + _error = k_ErrorType_UnexpectedEnd; + break; + } + + if (item.Is_SymLink() && dataSize <= (1 << 12) && item.Size != 0) + { + size_t cur = (size_t)dataSize; + CByteBuffer buf; + buf.Alloc(cur); + RINOK(ReadStream(stream, buf, &cur)) + if (cur != dataSize) + { + _error = k_ErrorType_UnexpectedEnd; + break; + } + size_t i; + + for (i = (size_t)item.Size; i < dataSize; i++) + if (buf[i] != 0) + break; + if (i != dataSize) + _pad_Error = true; + + for (i = 0; i < (size_t)item.Size; i++) + if (buf[i] == 0) + break; + if (i != (size_t)item.Size) + _symLink_Error = true; + else + _items.Back().Data.CopyFrom(buf, (size_t)item.Size); + } + else if (dataSize != 0) + { + UInt64 newPos; + RINOK(stream->Seek((Int64)dataSize, STREAM_SEEK_CUR, &newPos)) + if (arc.Processed != newPos) + return E_FAIL; + } + + if (callback && (_items.Size() & 0xFFF) == 0) + { + const UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos)) + } + } + + _phySize = arc.Processed; + } + + { + if (_error != k_ErrorType_OK) + { + // we try to reduce probability of false detection + if (_items.Size() == 0) + return S_FALSE; + // bin file uses small signature. So we do additional check for single item case. + if (_items.Size() == 1 && _items[0].IsBin()) + return S_FALSE; + } + else + { + // Read tailing zeros. + // Most of cpio files use 512-bytes aligned zeros + // rare case: 4K/8K aligment is possible also + const unsigned kTailSize_MAX = 1 << 9; + Byte buf[kTailSize_MAX]; + + unsigned pos = (unsigned)_phySize & (kTailSize_MAX - 1); + if (pos != 0) // use this check to support 512 bytes alignment only + for (;;) + { + const unsigned rem = kTailSize_MAX - pos; + size_t processed = rem; + RINOK(ReadStream(stream, buf + pos, &processed)) + if (processed != rem) + break; + for (; pos < kTailSize_MAX && buf[pos] == 0; pos++) + {} + if (pos != kTailSize_MAX) + break; + _phySize += processed; + pos = 0; + + // use break to support 512 bytes alignment zero tail + // don't use break to support 512*n bytes alignment zero tail + break; + } + } + } + + { + /* there was such cpio archive example with hard links: + { + all hard links (same dev/inode) are stored in neighboring items, and + (item.Size == 0) for non last hard link items + (item.Size != 0) for last hard link item + } + but here we sort items by (dev/inode) to support cases + where hard links (same dev/inode) are not stored in neighboring items. + + // note: some cpio files have (numLinks == 0) ?? + */ + + CUIntVector indices; + { + const unsigned numItems = _items.Size(); + indices.ClearAndSetSize(numItems); + if (numItems != 0) + { + unsigned *vals = &indices[0]; + for (unsigned i = 0; i < numItems; i++) + vals[i] = i; + indices.Sort(CompareItems, (void *)&_items); + } + } + + /* Note: if cpio archive (maybe incorrect) contains + more then one non empty streams with identical inode number, + we want to extract all such data streams too. + + So we place items with identical inode to groups: + all items in group will have same MainIndex_ForInode, + that is index of last item in group with (Size != 0). + Another (non last) items in group have (Size == 0). + If there are another hard links with same inode number + after (Size != 0) item, we place them to another next group(s). + + Check it: maybe we should use single group for items + with identical inode instead, and ignore some extra data streams ? + */ + + for (unsigned i = 0; i < indices.Size();) + { + unsigned k; + { + const CItem &item_Base = _items[indices[i]]; + + if (item_Base.IsDir()) + { + i++; + continue; + } + + if (i != 0) + { + const CItem &item_Prev = _items[indices[i - 1]]; + if (!item_Prev.IsDir()) + if (item_Base.IsSame_inode_Dev(item_Prev)) + _moreThanOneHardLinks_Error = true; + } + + if (item_Base.Size != 0) + { + if (item_Base.NumLinks != 1) + _numLinks_Error = true; + i++; + continue; + } + + for (k = i + 1; k < indices.Size();) + { + const CItem &item = _items[indices[k]]; + if (item.IsDir()) + break; + if (!item.IsSame_inode_Dev(item_Base)) + break; + k++; + if (item.Size != 0) + break; + } + } + + const unsigned numLinks = k - i; + for (;;) + { + CItem &item = _items[indices[i]]; + if (item.NumLinks != numLinks) + _numLinks_Error = true; + if (++i == k) + break; + // if (item.Size == 0) + item.MainIndex_ForInode = indices[k - 1]; + } + } + } + + _isArc = true; + _stream = stream; + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _items.Clear(); + _stream.Release(); + _phySize = 0; + _type = k_Type_BinLe; + _isArc = false; + _moreThanOneHardLinks_Error = false; + _numLinks_Error = false; + _pad_Error = false; + _symLink_Error = false; + _error = k_ErrorType_OK; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItem &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + UString res; + bool needConvert = true; + #ifdef _WIN32 + // if ( + ConvertUTF8ToUnicode(item.Name, res); + // ) + needConvert = false; + #endif + if (needConvert) + res = MultiByteToUnicodeString(item.Name, CP_OEMCP); + prop = NItemName::GetOsPath(res); + break; + } + case kpidIsDir: prop = item.IsDir(); break; + + case kpidSize: + prop = (UInt64)_items[item.MainIndex_ForInode].Size; + break; + + case kpidPackSize: + prop = (UInt64)item.GetPackSize(); + break; + + case kpidMTime: + { + if (item.MTime != 0) + PropVariant_SetFrom_UnixTime(prop, item.MTime); + break; + } + case kpidPosixAttrib: prop = item.Mode; break; + case kpidINode: prop = item.inode; break; + case kpidStreamId: + if (!item.IsDir()) + prop = (UInt32)item.MainIndex_ForInode; + break; + case kpidDevMajor: prop = (UInt32)item.DevMajor; break; + case kpidDevMinor: prop = (UInt32)item.DevMinor; break; + + case kpidUserId: prop = item.UID; break; + case kpidGroupId: prop = item.GID; break; + + case kpidSymLink: + if (item.Is_SymLink() && item.Data.Size() != 0) + { + AString s; + s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size()); + if (s.Len() == item.Data.Size()) + { + UString u; + bool needConvert = true; + #ifdef _WIN32 + // if ( + ConvertUTF8ToUnicode(item.Name, u); + // ) + needConvert = false; + #endif + if (needConvert) + u = MultiByteToUnicodeString(s, CP_OEMCP); + prop = u; + } + } + break; + + case kpidLinks: prop = item.NumLinks; break; + case kpidDeviceMajor: + // if (item.RDevMajor != 0) + prop = (UInt32)item.RDevMajor; + break; + case kpidDeviceMinor: + // if (item.RDevMinor != 0) + prop = (UInt32)item.RDevMinor; + break; + case kpidChecksum: + if (item.IsCrcFormat()) + prop = item.ChkSum; + break; + case kpidOffset: prop = item.GetDataPosition(); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithSum + , ISequentialOutStream +) + CMyComPtr _stream; + UInt32 _checksum; + bool _calculate; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate) + { + _calculate = calculate; + _checksum = 0; + } + UInt32 GetChecksum() const { return _checksum; } +}; + + +Z7_COM7F_IMF(COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (processedSize) + *processedSize = size; + if (_calculate) + { + const Byte *p = (const Byte *)data; + const Byte *lim = p + size; + UInt32 sum = _checksum; + if (size >= 4) + { + lim -= 4 - 1; + do + { + sum += p[0] + p[1] + p[2] + p[3]; + p += 4; + } + while (p < lim); + lim += 4 - 1; + } + if (p != lim) { sum += *p++; + if (p != lim) { sum += *p++; + if (p != lim) { sum += *p++; }}} + _checksum = sum; + } + return result; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item2 = _items[index]; + const CItem &item = _items[item2.MainIndex_ForInode]; + totalSize += item.Size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + CMyComPtr2_Create outStreamSum; + + UInt64 total_PackSize = 0; + UInt64 total_UnpackSize = 0; + + for (i = 0;; i++) + { + lps->InSize = total_PackSize; + lps->OutSize = total_UnpackSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item2 = _items[index]; + const CItem &item = _items[item2.MainIndex_ForInode]; + { + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + + total_PackSize += item2.GetPackSize(); + total_UnpackSize += item.Size; + + if (item2.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + if (!testMode && !outStream) + continue; + outStreamSum->Init(item.IsCrcFormat()); + outStreamSum->SetStream(outStream); + RINOK(extractCallback->PrepareOperation(askMode)) + } + RINOK(InStream_SeekSet(_stream, item.GetDataPosition())) + inStream->Init(item.Size); + RINOK(copyCoder.Interface()->Code(inStream, outStreamSum, NULL, NULL, lps)) + outStreamSum->ReleaseStream(); + Int32 res = NExtract::NOperationResult::kDataError; + if (copyCoder->TotalSize == item.Size) + { + res = NExtract::NOperationResult::kOK; + if (item.IsCrcFormat() && item.ChkSum != outStreamSum->GetChecksum()) + res = NExtract::NOperationResult::kCRCError; + } + RINOK(extractCallback->SetOperationResult(res)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + const CItem &item2 = _items[index]; + const CItem &item = _items[item2.MainIndex_ForInode]; + return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream); + COM_TRY_END +} + +static const Byte k_Signature[] = { + 5, '0', '7', '0', '7', '0', + 2, kMagicBin0, kMagicBin1, + 2, kMagicBin1, kMagicBin0 }; + +REGISTER_ARC_I( + "Cpio", "cpio", NULL, 0xED, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + IsArc_Cpio) + +}} diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp index 1e8cd8c07..fd83f711e 100644 --- a/CPP/7zip/Archive/CramfsHandler.cpp +++ b/CPP/7zip/Archive/CramfsHandler.cpp @@ -1,784 +1,784 @@ -// CramfsHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" -#include "../../../C/LzmaDec.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyLinux.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/ZlibDecoder.h" - -namespace NArchive { -namespace NCramfs { - -static const Byte kSignature[] = - { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' }; - -static const UInt32 kArcSizeMax = (256 + 16) << 20; -static const UInt32 kNumFilesMax = (1 << 19); -static const unsigned kNumDirLevelsMax = (1 << 8); - -static const UInt32 kHeaderSize = 0x40; -static const unsigned kHeaderNameSize = 16; -static const UInt32 kNodeSize = 12; - -static const UInt32 kFlag_FsVer2 = (1 << 0); - -static const unsigned k_Flags_BlockSize_Shift = 11; -static const unsigned k_Flags_BlockSize_Mask = 7; -static const unsigned k_Flags_Method_Shift = 14; -static const unsigned k_Flags_Method_Mask = 3; - -/* - There is possible collision in flags: - - Original CramFS writes 0 in method field. But it uses ZLIB. - - Modified CramFS writes 0 in method field for "NONE" compression? - How to solve that collision? -*/ - -#define k_Flags_Method_NONE 0 -#define k_Flags_Method_ZLIB 1 -#define k_Flags_Method_LZMA 2 - -static const char * const k_Methods[] = -{ - "Copy" - , "ZLIB" - , "LZMA" - , "Unknown" -}; - -static const CUInt32PCharPair k_Flags[] = -{ - { 0, "Ver2" }, - { 1, "SortedDirs" }, - { 8, "Holes" }, - { 9, "WrongSignature" }, - { 10, "ShiftedRootOffset" } -}; - -static const unsigned kBlockSizeLog = 12; - -/* -struct CNode -{ - UInt16 Mode; - UInt16 Uid; - UInt32 Size; - Byte Gid; - UInt32 NameLen; - UInt32 Offset; - - void Parse(const Byte *p) - { - Mode = GetUi16(p); - Uid = GetUi16(p + 2); - Size = Get32(p + 4) & 0xFFFFFF; - Gid = p[7]; - NameLen = p[8] & 0x3F; - Offset = Get32(p + 8) >> 6; - } -}; -*/ - -#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) - -static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } -static bool IsDir(const Byte *p, bool be) { return MY_LIN_S_ISDIR(GetMode(p, be)); } - -static UInt32 GetSize(const Byte *p, bool be) -{ - if (be) - return GetBe32(p + 4) >> 8; - else - return GetUi32(p + 4) & 0xFFFFFF; -} - -static UInt32 GetNameLen(const Byte *p, bool be) -{ - if (be) - return (p[8] & 0xFC); - else - return ((UInt32)p[8] & (UInt32)0x3F) << 2; -} - -static UInt32 GetOffset(const Byte *p, bool be) -{ - if (be) - return (GetBe32(p + 8) & 0x03FFFFFF) << 2; - else - return GetUi32(p + 8) >> 6 << 2; -} - -struct CItem -{ - UInt32 Offset; - int Parent; -}; - -struct CHeader -{ - bool be; - UInt32 Size; - UInt32 Flags; - // UInt32 Future; - UInt32 Crc; - // UInt32 Edition; - UInt32 NumBlocks; - UInt32 NumFiles; - char Name[kHeaderNameSize]; - - bool Parse(const Byte *p) - { - if (memcmp(p + 16, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0) - return false; - switch (GetUi32(p)) - { - case 0x28CD3D45: be = false; break; - case 0x453DCD28: be = true; break; - default: return false; - } - Size = Get32(p + 4); - Flags = Get32(p + 8); - // Future = Get32(p + 0xC); - Crc = Get32(p + 0x20); - // Edition = Get32(p + 0x24); - NumBlocks = Get32(p + 0x28); - NumFiles = Get32(p + 0x2C); - memcpy(Name, p + 0x30, kHeaderNameSize); - return true; - } - - bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; } - unsigned GetBlockSizeShift() const { return (unsigned)(Flags >> k_Flags_BlockSize_Shift) & k_Flags_BlockSize_Mask; } - unsigned GetMethod() const { return (unsigned)(Flags >> k_Flags_Method_Shift) & k_Flags_Method_Mask; } -}; - - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CRecordVector _items; - CMyComPtr _stream; - Byte *_data; - UInt32 _size; - UInt32 _headersSize; - - UInt32 _errorFlags; - bool _isArc; - - CHeader _h; - UInt32 _phySize; - - unsigned _method; - unsigned _blockSizeLog; - - // Current file - - NCompress::NZlib::CDecoder *_zlibDecoderSpec; - CMyComPtr _zlibDecoder; - - CBufInStream *_inStreamSpec; - CMyComPtr _inStream; - - CBufPtrSeqOutStream *_outStreamSpec; - CMyComPtr _outStream; - - UInt32 _curBlocksOffset; - UInt32 _curNumBlocks; - - HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level); - HRESULT Open2(IInStream *inStream); - AString GetPath(unsigned index) const; - bool GetPackSize(unsigned index, UInt32 &res) const; - void Free(); - - UInt32 GetNumBlocks(UInt32 size) const - { - return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog; - } - - void UpdatePhySize(UInt32 s) - { - if (_phySize < s) - _phySize = s; - } - -public: - CHandler(): _data(NULL) {} - ~CHandler() { Free(); } - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidPosixAttrib - // kpidOffset -}; - -static const Byte kArcProps[] = -{ - kpidVolumeName, - kpidBigEndian, - kpidCharacts, - kpidClusterSize, - kpidMethod, - kpidHeadersSize, - kpidNumSubFiles, - kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level) -{ - const Byte *p = _data + baseOffset; - bool be = _h.be; - if (!IsDir(p, be)) - return S_OK; - UInt32 offset = GetOffset(p, be); - UInt32 size = GetSize(p, be); - if (offset == 0 && size == 0) - return S_OK; - UInt32 end = offset + size; - if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax) - return S_FALSE; - UpdatePhySize(end); - if (end > _headersSize) - _headersSize = end; - - unsigned startIndex = _items.Size(); - - while (size != 0) - { - if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax) - return S_FALSE; - CItem item; - item.Parent = parent; - item.Offset = offset; - _items.Add(item); - UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be); - if (size < nodeLen) - return S_FALSE; - offset += nodeLen; - size -= nodeLen; - } - - unsigned endIndex = _items.Size(); - for (unsigned i = startIndex; i < endIndex; i++) - { - RINOK(OpenDir((int)i, _items[i].Offset, level + 1)) - } - return S_OK; -} - -HRESULT CHandler::Open2(IInStream *inStream) -{ - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)) - if (!_h.Parse(buf)) - return S_FALSE; - _method = k_Flags_Method_ZLIB; - _blockSizeLog = kBlockSizeLog; - _phySize = kHeaderSize; - if (_h.IsVer2()) - { - _method = _h.GetMethod(); - // FIT IT. Now we don't know correct way to work with collision in method field. - if (_method == k_Flags_Method_NONE) - _method = k_Flags_Method_ZLIB; - _blockSizeLog = kBlockSizeLog + _h.GetBlockSizeShift(); - if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax) - return S_FALSE; - _phySize = _h.Size; - } - else - { - UInt64 size; - RINOK(InStream_GetSize_SeekToEnd(inStream, size)) - if (size > kArcSizeMax) - size = kArcSizeMax; - _h.Size = (UInt32)size; - RINOK(InStream_SeekSet(inStream, kHeaderSize)) - } - _data = (Byte *)MidAlloc(_h.Size); - if (!_data) - return E_OUTOFMEMORY; - memcpy(_data, buf, kHeaderSize); - size_t processed = _h.Size - kHeaderSize; - RINOK(ReadStream(inStream, _data + kHeaderSize, &processed)) - if (processed < kNodeSize) - return S_FALSE; - _size = kHeaderSize + (UInt32)processed; - if (_h.IsVer2()) - { - if (_size != _h.Size) - _errorFlags = kpv_ErrorFlags_UnexpectedEnd; - else - { - SetUi32(_data + 0x20, 0) - if (CrcCalc(_data, _h.Size) != _h.Crc) - { - _errorFlags = kpv_ErrorFlags_HeadersError; - // _errorMessage = "CRC error"; - } - } - if (_h.NumFiles >= 1) - _items.ClearAndReserve(_h.NumFiles - 1); - } - - RINOK(OpenDir(-1, kHeaderSize, 0)) - - if (!_h.IsVer2()) - { - FOR_VECTOR (i, _items) - { - const CItem &item = _items[i]; - const Byte *p = _data + item.Offset; - bool be = _h.be; - if (IsDir(p, be)) - continue; - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - continue; - UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); - if (numBlocks == 0) - continue; - UInt32 start = offset + numBlocks * 4; - if (start > _size) - continue; - UInt32 end = Get32(_data + start - 4); - if (end >= start) - UpdatePhySize(end); - } - - // Read tailing zeros. Most cramfs archives use 4096-bytes aligned zeros - const UInt32 kTailSize_MAX = 1 << 12; - UInt32 endPos = (_phySize + kTailSize_MAX - 1) & ~(kTailSize_MAX - 1); - if (endPos > _size) - endPos = _size; - UInt32 pos; - for (pos = _phySize; pos < endPos && _data[pos] == 0; pos++); - if (pos == endPos) - _phySize = endPos; - } - return S_OK; -} - -AString CHandler::GetPath(unsigned index) const -{ - unsigned len = 0; - unsigned indexMem = index; - for (;;) - { - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - unsigned size = GetNameLen(p, _h.be); - p += kNodeSize; - unsigned i; - for (i = 0; i < size && p[i]; i++); - len += i + 1; - index = (unsigned)item.Parent; - if (item.Parent < 0) - break; - } - len--; - - AString path; - char *dest = path.GetBuf_SetEnd(len) + len; - index = indexMem; - for (;;) - { - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - unsigned size = GetNameLen(p, _h.be); - p += kNodeSize; - unsigned i; - for (i = 0; i < size && p[i]; i++); - dest -= i; - memcpy(dest, p, i); - index = (unsigned)item.Parent; - if (item.Parent < 0) - break; - *(--dest) = CHAR_PATH_SEPARATOR; - } - return path; -} - -bool CHandler::GetPackSize(unsigned index, UInt32 &res) const -{ - res = 0; - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - const bool be = _h.be; - const UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - return false; - const UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); - if (numBlocks == 0) - return true; - const UInt32 start = offset + numBlocks * 4; - if (start > _size) - return false; - const UInt32 end = Get32(_data + start - 4); - if (end < start) - return false; - res = end - start; - return true; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)) -{ - COM_TRY_BEGIN - { - Close(); - RINOK(Open2(stream)) - _isArc = true; - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -void CHandler::Free() -{ - MidFree(_data); - _data = NULL; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _phySize = 0; - _errorFlags = 0; - _headersSize = 0; - _items.Clear(); - _stream.Release(); - Free(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidVolumeName: - { - char dest[kHeaderNameSize + 4]; - memcpy(dest, _h.Name, kHeaderNameSize); - dest[kHeaderNameSize] = 0; - prop = dest; - break; - } - case kpidBigEndian: prop = _h.be; break; - case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; - case kpidMethod: prop = k_Methods[_method]; break; - case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; - case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break; - case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break; - case kpidPhySize: prop = _phySize; break; - case kpidHeadersSize: prop = _headersSize; break; - case kpidErrorFlags: - { - UInt32 v = _errorFlags; - if (!_isArc) - v |= kpv_ErrorFlags_IsNotArc; - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - bool be = _h.be; - bool isDir = IsDir(p, be); - switch (propID) - { - case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; - case kpidIsDir: prop = isDir; break; - // case kpidOffset: prop = (UInt32)GetOffset(p, be); break; - case kpidSize: if (!isDir) prop = GetSize(p, be); break; - case kpidPackSize: - if (!isDir) - { - UInt32 size; - if (GetPackSize(index, size)) - prop = size; - } - break; - case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CCramfsInStream: public CCachedInStream -{ - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override; -public: - CHandler *Handler; -}; - -HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - return Handler->ReadBlock(blockIndex, dest, blockSize); -} - -HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - if (_method == k_Flags_Method_ZLIB) - { - if (!_zlibDecoder) - { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; - } - } - else - { - if (_method != k_Flags_Method_LZMA) - { - // probably we must support no-compression archives here. - return E_NOTIMPL; - } - } - - const bool be = _h.be; - const Byte *p2 = _data + (_curBlocksOffset + (UInt32)blockIndex * 4); - const UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p2 - 4)); - const UInt32 end = Get32(p2); - if (end < start || end > _size) - return S_FALSE; - const UInt32 inSize = end - start; - - if (_method == k_Flags_Method_LZMA) - { - const unsigned kLzmaHeaderSize = LZMA_PROPS_SIZE + 4; - if (inSize < kLzmaHeaderSize) - return S_FALSE; - const Byte *p = _data + start; - UInt32 destSize32 = GetUi32(p + LZMA_PROPS_SIZE); - if (destSize32 > blockSize) - return S_FALSE; - SizeT destLen = destSize32; - SizeT srcLen = inSize - kLzmaHeaderSize; - ELzmaStatus status; - SRes res = LzmaDecode(dest, &destLen, p + kLzmaHeaderSize, &srcLen, - p, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc); - if (res != SZ_OK - || (status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - || destLen != destSize32 - || srcLen != inSize - kLzmaHeaderSize) - return S_FALSE; - return S_OK; - } - - if (!_inStream) - { - _inStreamSpec = new CBufInStream(); - _inStream = _inStreamSpec; - } - if (!_outStream) - { - _outStreamSpec = new CBufPtrSeqOutStream(); - _outStream = _outStreamSpec; - } - _inStreamSpec->Init(_data + start, inSize); - _outStreamSpec->Init(dest, blockSize); - RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL)) - return (inSize == _zlibDecoderSpec->GetInputProcessedSize() && - _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - bool be = _h.be; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset; - if (!IsDir(p, be)) - totalSize += GetSize(p, be); - } - extractCallback->SetTotal(totalSize); - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - const Byte *p = _data + item.Offset; - - if (IsDir(p, be)) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - UInt32 curSize = GetSize(p, be); - totalSize += curSize; - UInt32 packSize; - if (GetPackSize(index, packSize)) - totalPackSize += packSize; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - curSize = 0; - - int res = NExtract::NOperationResult::kDataError; - { - CMyComPtr inSeqStream; - HRESULT hres = GetStream(index, &inSeqStream); - if (hres == E_OUTOFMEMORY) - return E_OUTOFMEMORY; - if (hres == S_FALSE || !inSeqStream) - res = NExtract::NOperationResult::kUnsupportedMethod; - else - { - RINOK(hres) - { - hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress); - if (hres == S_OK) - { - if (copyCoderSpec->TotalSize == curSize) - res = NExtract::NOperationResult::kOK; - } - else if (hres == E_NOTIMPL) - res = NExtract::NOperationResult::kUnsupportedMethod; - else if (hres != S_FALSE) - return hres; - } - } - } - RINOK(extractCallback->SetOperationResult(res)) - } - - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - - const CItem &item = _items[index]; - const Byte *p = _data + item.Offset; - - bool be = _h.be; - if (IsDir(p, be)) - return E_FAIL; - - UInt32 size = GetSize(p, be); - UInt32 numBlocks = GetNumBlocks(size); - UInt32 offset = GetOffset(p, be); - if (offset < kHeaderSize) - { - if (offset != 0) - return S_FALSE; - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Init(NULL, 0); - *stream = streamTemp.Detach(); - return S_OK; - } - - if (offset + numBlocks * 4 > _size) - return S_FALSE; - UInt32 prev = offset; - for (UInt32 i = 0; i < numBlocks; i++) - { - UInt32 next = Get32(_data + offset + i * 4); - if (next < prev || next > _size) - return S_FALSE; - prev = next; - } - - CCramfsInStream *streamSpec = new CCramfsInStream; - CMyComPtr streamTemp = streamSpec; - _curNumBlocks = numBlocks; - _curBlocksOffset = offset; - streamSpec->Handler = this; - if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog)) - return E_OUTOFMEMORY; - streamSpec->Init(size); - *stream = streamTemp.Detach(); - - return S_OK; - COM_TRY_END -} - -REGISTER_ARC_I( - "CramFS", "cramfs", NULL, 0xD3, - kSignature, - 16, - 0, - NULL) - -}} +// CramfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" +#include "../../../C/LzmaDec.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyLinux.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/ZlibDecoder.h" + +namespace NArchive { +namespace NCramfs { + +static const Byte kSignature[] = + { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' }; + +static const UInt32 kArcSizeMax = (256 + 16) << 20; +static const UInt32 kNumFilesMax = (1 << 19); +static const unsigned kNumDirLevelsMax = (1 << 8); + +static const UInt32 kHeaderSize = 0x40; +static const unsigned kHeaderNameSize = 16; +static const UInt32 kNodeSize = 12; + +static const UInt32 kFlag_FsVer2 = (1 << 0); + +static const unsigned k_Flags_BlockSize_Shift = 11; +static const unsigned k_Flags_BlockSize_Mask = 7; +static const unsigned k_Flags_Method_Shift = 14; +static const unsigned k_Flags_Method_Mask = 3; + +/* + There is possible collision in flags: + - Original CramFS writes 0 in method field. But it uses ZLIB. + - Modified CramFS writes 0 in method field for "NONE" compression? + How to solve that collision? +*/ + +#define k_Flags_Method_NONE 0 +#define k_Flags_Method_ZLIB 1 +#define k_Flags_Method_LZMA 2 + +static const char * const k_Methods[] = +{ + "Copy" + , "ZLIB" + , "LZMA" + , "Unknown" +}; + +static const CUInt32PCharPair k_Flags[] = +{ + { 0, "Ver2" }, + { 1, "SortedDirs" }, + { 8, "Holes" }, + { 9, "WrongSignature" }, + { 10, "ShiftedRootOffset" } +}; + +static const unsigned kBlockSizeLog = 12; + +/* +struct CNode +{ + UInt16 Mode; + UInt16 Uid; + UInt32 Size; + Byte Gid; + UInt32 NameLen; + UInt32 Offset; + + void Parse(const Byte *p) + { + Mode = GetUi16(p); + Uid = GetUi16(p + 2); + Size = Get32(p + 4) & 0xFFFFFF; + Gid = p[7]; + NameLen = p[8] & 0x3F; + Offset = Get32(p + 8) >> 6; + } +}; +*/ + +#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) + +static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } +static bool IsDir(const Byte *p, bool be) { return MY_LIN_S_ISDIR(GetMode(p, be)); } + +static UInt32 GetSize(const Byte *p, bool be) +{ + if (be) + return GetBe32(p + 4) >> 8; + else + return GetUi32(p + 4) & 0xFFFFFF; +} + +static UInt32 GetNameLen(const Byte *p, bool be) +{ + if (be) + return (p[8] & 0xFC); + else + return ((UInt32)p[8] & (UInt32)0x3F) << 2; +} + +static UInt32 GetOffset(const Byte *p, bool be) +{ + if (be) + return (GetBe32(p + 8) & 0x03FFFFFF) << 2; + else + return GetUi32(p + 8) >> 6 << 2; +} + +struct CItem +{ + UInt32 Offset; + int Parent; +}; + +struct CHeader +{ + bool be; + UInt32 Size; + UInt32 Flags; + // UInt32 Future; + UInt32 Crc; + // UInt32 Edition; + UInt32 NumBlocks; + UInt32 NumFiles; + char Name[kHeaderNameSize]; + + bool Parse(const Byte *p) + { + if (memcmp(p + 16, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0) + return false; + switch (GetUi32(p)) + { + case 0x28CD3D45: be = false; break; + case 0x453DCD28: be = true; break; + default: return false; + } + Size = Get32(p + 4); + Flags = Get32(p + 8); + // Future = Get32(p + 0xC); + Crc = Get32(p + 0x20); + // Edition = Get32(p + 0x24); + NumBlocks = Get32(p + 0x28); + NumFiles = Get32(p + 0x2C); + memcpy(Name, p + 0x30, kHeaderNameSize); + return true; + } + + bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; } + unsigned GetBlockSizeShift() const { return (unsigned)(Flags >> k_Flags_BlockSize_Shift) & k_Flags_BlockSize_Mask; } + unsigned GetMethod() const { return (unsigned)(Flags >> k_Flags_Method_Shift) & k_Flags_Method_Mask; } +}; + + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CRecordVector _items; + CMyComPtr _stream; + Byte *_data; + UInt32 _size; + UInt32 _headersSize; + + UInt32 _errorFlags; + bool _isArc; + + CHeader _h; + UInt32 _phySize; + + unsigned _method; + unsigned _blockSizeLog; + + // Current file + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + CBufInStream *_inStreamSpec; + CMyComPtr _inStream; + + CBufPtrSeqOutStream *_outStreamSpec; + CMyComPtr _outStream; + + UInt32 _curBlocksOffset; + UInt32 _curNumBlocks; + + HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level); + HRESULT Open2(IInStream *inStream); + AString GetPath(unsigned index) const; + bool GetPackSize(unsigned index, UInt32 &res) const; + void Free(); + + UInt32 GetNumBlocks(UInt32 size) const + { + return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog; + } + + void UpdatePhySize(UInt32 s) + { + if (_phySize < s) + _phySize = s; + } + +public: + CHandler(): _data(NULL) {} + ~CHandler() { Free(); } + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidPosixAttrib + // kpidOffset +}; + +static const Byte kArcProps[] = +{ + kpidVolumeName, + kpidBigEndian, + kpidCharacts, + kpidClusterSize, + kpidMethod, + kpidHeadersSize, + kpidNumSubFiles, + kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level) +{ + const Byte *p = _data + baseOffset; + bool be = _h.be; + if (!IsDir(p, be)) + return S_OK; + UInt32 offset = GetOffset(p, be); + UInt32 size = GetSize(p, be); + if (offset == 0 && size == 0) + return S_OK; + UInt32 end = offset + size; + if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax) + return S_FALSE; + UpdatePhySize(end); + if (end > _headersSize) + _headersSize = end; + + unsigned startIndex = _items.Size(); + + while (size != 0) + { + if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax) + return S_FALSE; + CItem item; + item.Parent = parent; + item.Offset = offset; + _items.Add(item); + UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be); + if (size < nodeLen) + return S_FALSE; + offset += nodeLen; + size -= nodeLen; + } + + unsigned endIndex = _items.Size(); + for (unsigned i = startIndex; i < endIndex; i++) + { + RINOK(OpenDir((int)i, _items[i].Offset, level + 1)) + } + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *inStream) +{ + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)) + if (!_h.Parse(buf)) + return S_FALSE; + _method = k_Flags_Method_ZLIB; + _blockSizeLog = kBlockSizeLog; + _phySize = kHeaderSize; + if (_h.IsVer2()) + { + _method = _h.GetMethod(); + // FIT IT. Now we don't know correct way to work with collision in method field. + if (_method == k_Flags_Method_NONE) + _method = k_Flags_Method_ZLIB; + _blockSizeLog = kBlockSizeLog + _h.GetBlockSizeShift(); + if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax) + return S_FALSE; + _phySize = _h.Size; + } + else + { + UInt64 size; + RINOK(InStream_GetSize_SeekToEnd(inStream, size)) + if (size > kArcSizeMax) + size = kArcSizeMax; + _h.Size = (UInt32)size; + RINOK(InStream_SeekSet(inStream, kHeaderSize)) + } + _data = (Byte *)MidAlloc(_h.Size); + if (!_data) + return E_OUTOFMEMORY; + memcpy(_data, buf, kHeaderSize); + size_t processed = _h.Size - kHeaderSize; + RINOK(ReadStream(inStream, _data + kHeaderSize, &processed)) + if (processed < kNodeSize) + return S_FALSE; + _size = kHeaderSize + (UInt32)processed; + if (_h.IsVer2()) + { + if (_size != _h.Size) + _errorFlags = kpv_ErrorFlags_UnexpectedEnd; + else + { + SetUi32(_data + 0x20, 0) + if (CrcCalc(_data, _h.Size) != _h.Crc) + { + _errorFlags = kpv_ErrorFlags_HeadersError; + // _errorMessage = "CRC error"; + } + } + if (_h.NumFiles >= 1) + _items.ClearAndReserve(_h.NumFiles - 1); + } + + RINOK(OpenDir(-1, kHeaderSize, 0)) + + if (!_h.IsVer2()) + { + FOR_VECTOR (i, _items) + { + const CItem &item = _items[i]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + if (IsDir(p, be)) + continue; + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + continue; + UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); + if (numBlocks == 0) + continue; + UInt32 start = offset + numBlocks * 4; + if (start > _size) + continue; + UInt32 end = Get32(_data + start - 4); + if (end >= start) + UpdatePhySize(end); + } + + // Read tailing zeros. Most cramfs archives use 4096-bytes aligned zeros + const UInt32 kTailSize_MAX = 1 << 12; + UInt32 endPos = (_phySize + kTailSize_MAX - 1) & ~(kTailSize_MAX - 1); + if (endPos > _size) + endPos = _size; + UInt32 pos; + for (pos = _phySize; pos < endPos && _data[pos] == 0; pos++); + if (pos == endPos) + _phySize = endPos; + } + return S_OK; +} + +AString CHandler::GetPath(unsigned index) const +{ + unsigned len = 0; + unsigned indexMem = index; + for (;;) + { + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + unsigned size = GetNameLen(p, _h.be); + p += kNodeSize; + unsigned i; + for (i = 0; i < size && p[i]; i++); + len += i + 1; + index = (unsigned)item.Parent; + if (item.Parent < 0) + break; + } + len--; + + AString path; + char *dest = path.GetBuf_SetEnd(len) + len; + index = indexMem; + for (;;) + { + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + unsigned size = GetNameLen(p, _h.be); + p += kNodeSize; + unsigned i; + for (i = 0; i < size && p[i]; i++); + dest -= i; + memcpy(dest, p, i); + index = (unsigned)item.Parent; + if (item.Parent < 0) + break; + *(--dest) = CHAR_PATH_SEPARATOR; + } + return path; +} + +bool CHandler::GetPackSize(unsigned index, UInt32 &res) const +{ + res = 0; + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + const bool be = _h.be; + const UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + return false; + const UInt32 numBlocks = GetNumBlocks(GetSize(p, be)); + if (numBlocks == 0) + return true; + const UInt32 start = offset + numBlocks * 4; + if (start > _size) + return false; + const UInt32 end = Get32(_data + start - 4); + if (end < start) + return false; + res = end - start; + return true; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(stream)) + _isArc = true; + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +void CHandler::Free() +{ + MidFree(_data); + _data = NULL; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _phySize = 0; + _errorFlags = 0; + _headersSize = 0; + _items.Clear(); + _stream.Release(); + Free(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidVolumeName: + { + char dest[kHeaderNameSize + 4]; + memcpy(dest, _h.Name, kHeaderNameSize); + dest[kHeaderNameSize] = 0; + prop = dest; + break; + } + case kpidBigEndian: prop = _h.be; break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; + case kpidMethod: prop = k_Methods[_method]; break; + case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; + case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break; + case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break; + case kpidPhySize: prop = _phySize; break; + case kpidHeadersSize: prop = _headersSize; break; + case kpidErrorFlags: + { + UInt32 v = _errorFlags; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + bool be = _h.be; + bool isDir = IsDir(p, be); + switch (propID) + { + case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break; + case kpidIsDir: prop = isDir; break; + // case kpidOffset: prop = (UInt32)GetOffset(p, be); break; + case kpidSize: if (!isDir) prop = GetSize(p, be); break; + case kpidPackSize: + if (!isDir) + { + UInt32 size; + if (GetPackSize(index, size)) + prop = size; + } + break; + case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CCramfsInStream: public CCachedInStream +{ + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override; +public: + CHandler *Handler; +}; + +HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + return Handler->ReadBlock(blockIndex, dest, blockSize); +} + +HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + if (_method == k_Flags_Method_ZLIB) + { + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + } + } + else + { + if (_method != k_Flags_Method_LZMA) + { + // probably we must support no-compression archives here. + return E_NOTIMPL; + } + } + + const bool be = _h.be; + const Byte *p2 = _data + (_curBlocksOffset + (UInt32)blockIndex * 4); + const UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p2 - 4)); + const UInt32 end = Get32(p2); + if (end < start || end > _size) + return S_FALSE; + const UInt32 inSize = end - start; + + if (_method == k_Flags_Method_LZMA) + { + const unsigned kLzmaHeaderSize = LZMA_PROPS_SIZE + 4; + if (inSize < kLzmaHeaderSize) + return S_FALSE; + const Byte *p = _data + start; + UInt32 destSize32 = GetUi32(p + LZMA_PROPS_SIZE); + if (destSize32 > blockSize) + return S_FALSE; + SizeT destLen = destSize32; + SizeT srcLen = inSize - kLzmaHeaderSize; + ELzmaStatus status; + SRes res = LzmaDecode(dest, &destLen, p + kLzmaHeaderSize, &srcLen, + p, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc); + if (res != SZ_OK + || (status != LZMA_STATUS_FINISHED_WITH_MARK && + status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + || destLen != destSize32 + || srcLen != inSize - kLzmaHeaderSize) + return S_FALSE; + return S_OK; + } + + if (!_inStream) + { + _inStreamSpec = new CBufInStream(); + _inStream = _inStreamSpec; + } + if (!_outStream) + { + _outStreamSpec = new CBufPtrSeqOutStream(); + _outStream = _outStreamSpec; + } + _inStreamSpec->Init(_data + start, inSize); + _outStreamSpec->Init(dest, blockSize); + RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL)) + return (inSize == _zlibDecoderSpec->GetInputProcessedSize() && + _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + bool be = _h.be; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset; + if (!IsDir(p, be)) + totalSize += GetSize(p, be); + } + extractCallback->SetTotal(totalSize); + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + const Byte *p = _data + item.Offset; + + if (IsDir(p, be)) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + UInt32 curSize = GetSize(p, be); + totalSize += curSize; + UInt32 packSize; + if (GetPackSize(index, packSize)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + curSize = 0; + + int res = NExtract::NOperationResult::kDataError; + { + CMyComPtr inSeqStream; + HRESULT hres = GetStream(index, &inSeqStream); + if (hres == E_OUTOFMEMORY) + return E_OUTOFMEMORY; + if (hres == S_FALSE || !inSeqStream) + res = NExtract::NOperationResult::kUnsupportedMethod; + else + { + RINOK(hres) + { + hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress); + if (hres == S_OK) + { + if (copyCoderSpec->TotalSize == curSize) + res = NExtract::NOperationResult::kOK; + } + else if (hres == E_NOTIMPL) + res = NExtract::NOperationResult::kUnsupportedMethod; + else if (hres != S_FALSE) + return hres; + } + } + } + RINOK(extractCallback->SetOperationResult(res)) + } + + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + + const CItem &item = _items[index]; + const Byte *p = _data + item.Offset; + + bool be = _h.be; + if (IsDir(p, be)) + return E_FAIL; + + UInt32 size = GetSize(p, be); + UInt32 numBlocks = GetNumBlocks(size); + UInt32 offset = GetOffset(p, be); + if (offset < kHeaderSize) + { + if (offset != 0) + return S_FALSE; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Init(NULL, 0); + *stream = streamTemp.Detach(); + return S_OK; + } + + if (offset + numBlocks * 4 > _size) + return S_FALSE; + UInt32 prev = offset; + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt32 next = Get32(_data + offset + i * 4); + if (next < prev || next > _size) + return S_FALSE; + prev = next; + } + + CCramfsInStream *streamSpec = new CCramfsInStream; + CMyComPtr streamTemp = streamSpec; + _curNumBlocks = numBlocks; + _curBlocksOffset = offset; + streamSpec->Handler = this; + if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog)) + return E_OUTOFMEMORY; + streamSpec->Init(size); + *stream = streamTemp.Detach(); + + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "CramFS", "cramfs", NULL, 0xD3, + kSignature, + 16, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp index 33c92d747..ca3dc6f56 100644 --- a/CPP/7zip/Archive/DeflateProps.cpp +++ b/CPP/7zip/Archive/DeflateProps.cpp @@ -1,3 +1,3 @@ -// DeflateProps.cpp - -#include "StdAfx.h" +// DeflateProps.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h index 36c328023..666fb39b1 100644 --- a/CPP/7zip/Archive/DeflateProps.h +++ b/CPP/7zip/Archive/DeflateProps.h @@ -1,6 +1,6 @@ -// DeflateProps.h - -#ifndef ZIP7_INC_DEFLATE_PROPS_H -#define ZIP7_INC_DEFLATE_PROPS_H - -#endif +// DeflateProps.h + +#ifndef ZIP7_INC_DEFLATE_PROPS_H +#define ZIP7_INC_DEFLATE_PROPS_H + +#endif diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp index f17944bf4..9def2088c 100644 --- a/CPP/7zip/Archive/DllExports.cpp +++ b/CPP/7zip/Archive/DllExports.cpp @@ -1,96 +1,96 @@ -// DLLExports.cpp - -#include "StdAfx.h" - -#if defined(Z7_LARGE_PAGES) -#include "../../../C/Alloc.h" -#endif - -#include "../../Common/MyWindows.h" -#include "../../Common/MyInitGuid.h" - -#include "../../Common/ComTry.h" - -#include "../../Windows/NtCheck.h" -#include "../../Windows/PropVariant.h" - -#include "../ICoder.h" -#include "../IPassword.h" - -#include "../Common/CreateCoder.h" - -#include "IArchive.h" - -static -HINSTANCE g_hInstance; - -#define NT_CHECK_FAIL_ACTION return FALSE; - -extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/); -extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) -{ - if (dwReason == DLL_PROCESS_ATTACH) - { - g_hInstance = hInstance; - NT_CHECK - } - return TRUE; -} - -Z7_DEFINE_GUID(CLSID_CArchiveHandler, - k_7zip_GUID_Data1, - k_7zip_GUID_Data2, - k_7zip_GUID_Data3_Common, - 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); - -STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject); - -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) -{ - return CreateArchiver(clsid, iid, outObject); -} - -STDAPI SetLargePageMode() -{ - #if defined(Z7_LARGE_PAGES) - SetLargePageSize(); - #endif - return S_OK; -} - -extern bool g_CaseSensitive; - -STDAPI SetCaseSensitive(Int32 caseSensitive) -{ - g_CaseSensitive = (caseSensitive != 0); - return S_OK; -} - -#ifdef Z7_EXTERNAL_CODECS - -CExternalCodecs g_ExternalCodecs; - -STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo) -{ - COM_TRY_BEGIN - - // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL"); - if (compressCodecsInfo) - { - g_ExternalCodecs.GetCodecs = compressCodecsInfo; - return g_ExternalCodecs.Load(); - } - g_ExternalCodecs.ClearAndRelease(); - return S_OK; - - COM_TRY_END -} - -#else - -STDAPI SetCodecs(ICompressCodecsInfo *) -{ - return S_OK; -} - -#endif +// DLLExports.cpp + +#include "StdAfx.h" + +#if defined(Z7_LARGE_PAGES) +#include "../../../C/Alloc.h" +#endif + +#include "../../Common/MyWindows.h" +#include "../../Common/MyInitGuid.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/NtCheck.h" +#include "../../Windows/PropVariant.h" + +#include "../ICoder.h" +#include "../IPassword.h" + +#include "../Common/CreateCoder.h" + +#include "IArchive.h" + +static +HINSTANCE g_hInstance; + +#define NT_CHECK_FAIL_ACTION return FALSE; + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/); +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hInstance = hInstance; + NT_CHECK + } + return TRUE; +} + +Z7_DEFINE_GUID(CLSID_CArchiveHandler, + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); + +STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject); + +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) +{ + return CreateArchiver(clsid, iid, outObject); +} + +STDAPI SetLargePageMode() +{ + #if defined(Z7_LARGE_PAGES) + SetLargePageSize(); + #endif + return S_OK; +} + +extern bool g_CaseSensitive; + +STDAPI SetCaseSensitive(Int32 caseSensitive) +{ + g_CaseSensitive = (caseSensitive != 0); + return S_OK; +} + +#ifdef Z7_EXTERNAL_CODECS + +CExternalCodecs g_ExternalCodecs; + +STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo) +{ + COM_TRY_BEGIN + + // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL"); + if (compressCodecsInfo) + { + g_ExternalCodecs.GetCodecs = compressCodecsInfo; + return g_ExternalCodecs.Load(); + } + g_ExternalCodecs.ClearAndRelease(); + return S_OK; + + COM_TRY_END +} + +#else + +STDAPI SetCodecs(ICompressCodecsInfo *) +{ + return S_OK; +} + +#endif diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp index f5f1fb316..ae8d8acc1 100644 --- a/CPP/7zip/Archive/DllExports2.cpp +++ b/CPP/7zip/Archive/DllExports2.cpp @@ -1,175 +1,175 @@ -// DLLExports2.cpp - -#include "StdAfx.h" - -#include "../../Common/MyWindows.h" -#include "../../Common/MyInitGuid.h" - -#if defined(Z7_LARGE_PAGES) -#include "../../../C/Alloc.h" -#endif - -#include "../../Common/ComTry.h" - -#include "../../Windows/NtCheck.h" -#include "../../Windows/PropVariant.h" - -#include "../ICoder.h" -#include "../IPassword.h" - -#include "../Common/CreateCoder.h" - -#include "IArchive.h" - - -#ifdef _WIN32 - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION return FALSE; -#endif - -static -HINSTANCE g_hInstance; - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - hInstance, DWORD dwReason, LPVOID /*lpReserved*/); - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - hInstance, DWORD dwReason, LPVOID /*lpReserved*/) -{ - if (dwReason == DLL_PROCESS_ATTACH) - { - // OutputDebugStringA("7z.dll DLL_PROCESS_ATTACH"); - g_hInstance = (HINSTANCE)hInstance; - NT_CHECK - } - /* - if (dwReason == DLL_PROCESS_DETACH) - { - OutputDebugStringA("7z.dll DLL_PROCESS_DETACH"); - } - */ - return TRUE; -} - -#else // _WIN32 - -#include "../../Common/StringConvert.h" -// #include - -// STDAPI LibStartup(); -static __attribute__((constructor)) void Init_ForceToUTF8(); -static __attribute__((constructor)) void Init_ForceToUTF8() -{ - g_ForceToUTF8 = IsNativeUTF8(); - // printf("\nDLLExports2.cpp::Init_ForceToUTF8 =%d\n", g_ForceToUTF8 ? 1 : 0); -} - -#endif // _WIN32 - - -Z7_DEFINE_GUID(CLSID_CArchiveHandler, - k_7zip_GUID_Data1, - k_7zip_GUID_Data2, - k_7zip_GUID_Data3_Common, - 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); - -STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); -STDAPI CreateHasher(const GUID *clsid, IHasher **hasher); -STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject); - -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) -{ - // COM_TRY_BEGIN - *outObject = NULL; - if (*iid == IID_ICompressCoder || - *iid == IID_ICompressCoder2 || - *iid == IID_ICompressFilter) - return CreateCoder(clsid, iid, outObject); - if (*iid == IID_IHasher) - return CreateHasher(clsid, (IHasher **)outObject); - return CreateArchiver(clsid, iid, outObject); - // COM_TRY_END -} - -STDAPI SetLargePageMode(); -STDAPI SetLargePageMode() -{ - #if defined(Z7_LARGE_PAGES) - #ifdef _WIN32 - SetLargePageSize(); - #endif - #endif - return S_OK; -} - -extern bool g_CaseSensitive; - -STDAPI SetCaseSensitive(Int32 caseSensitive); -STDAPI SetCaseSensitive(Int32 caseSensitive) -{ - g_CaseSensitive = (caseSensitive != 0); - return S_OK; -} - -/* -UInt32 g_ClientVersion; -STDAPI SetClientVersion(UInt32 version); -STDAPI SetClientVersion(UInt32 version) -{ - g_ClientVersion = version; - return S_OK; -} -*/ - -/* -STDAPI SetProperty(Int32 id, const PROPVARIANT *value); -STDAPI SetProperty(Int32 id, const PROPVARIANT *value) -{ - return S_OK; -} -*/ - -#ifdef Z7_EXTERNAL_CODECS - -CExternalCodecs g_ExternalCodecs; - -STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo); -STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo) -{ - COM_TRY_BEGIN - - // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL"); - if (compressCodecsInfo) - { - g_ExternalCodecs.GetCodecs = compressCodecsInfo; - return g_ExternalCodecs.Load(); - } - g_ExternalCodecs.ClearAndRelease(); - return S_OK; - - COM_TRY_END -} - -#else - -STDAPI SetCodecs(ICompressCodecsInfo *); -STDAPI SetCodecs(ICompressCodecsInfo *) -{ - return S_OK; -} - -#endif +// DLLExports2.cpp + +#include "StdAfx.h" + +#include "../../Common/MyWindows.h" +#include "../../Common/MyInitGuid.h" + +#if defined(Z7_LARGE_PAGES) +#include "../../../C/Alloc.h" +#endif + +#include "../../Common/ComTry.h" + +#include "../../Windows/NtCheck.h" +#include "../../Windows/PropVariant.h" + +#include "../ICoder.h" +#include "../IPassword.h" + +#include "../Common/CreateCoder.h" + +#include "IArchive.h" + + +#ifdef _WIN32 + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION return FALSE; +#endif + +static +HINSTANCE g_hInstance; + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + hInstance, DWORD dwReason, LPVOID /*lpReserved*/); + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + // OutputDebugStringA("7z.dll DLL_PROCESS_ATTACH"); + g_hInstance = (HINSTANCE)hInstance; + NT_CHECK + } + /* + if (dwReason == DLL_PROCESS_DETACH) + { + OutputDebugStringA("7z.dll DLL_PROCESS_DETACH"); + } + */ + return TRUE; +} + +#else // _WIN32 + +#include "../../Common/StringConvert.h" +// #include + +// STDAPI LibStartup(); +static __attribute__((constructor)) void Init_ForceToUTF8(); +static __attribute__((constructor)) void Init_ForceToUTF8() +{ + g_ForceToUTF8 = IsNativeUTF8(); + // printf("\nDLLExports2.cpp::Init_ForceToUTF8 =%d\n", g_ForceToUTF8 ? 1 : 0); +} + +#endif // _WIN32 + + +Z7_DEFINE_GUID(CLSID_CArchiveHandler, + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00); + +STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateHasher(const GUID *clsid, IHasher **hasher); +STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject); + +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) +{ + // COM_TRY_BEGIN + *outObject = NULL; + if (*iid == IID_ICompressCoder || + *iid == IID_ICompressCoder2 || + *iid == IID_ICompressFilter) + return CreateCoder(clsid, iid, outObject); + if (*iid == IID_IHasher) + return CreateHasher(clsid, (IHasher **)outObject); + return CreateArchiver(clsid, iid, outObject); + // COM_TRY_END +} + +STDAPI SetLargePageMode(); +STDAPI SetLargePageMode() +{ + #if defined(Z7_LARGE_PAGES) + #ifdef _WIN32 + SetLargePageSize(); + #endif + #endif + return S_OK; +} + +extern bool g_CaseSensitive; + +STDAPI SetCaseSensitive(Int32 caseSensitive); +STDAPI SetCaseSensitive(Int32 caseSensitive) +{ + g_CaseSensitive = (caseSensitive != 0); + return S_OK; +} + +/* +UInt32 g_ClientVersion; +STDAPI SetClientVersion(UInt32 version); +STDAPI SetClientVersion(UInt32 version) +{ + g_ClientVersion = version; + return S_OK; +} +*/ + +/* +STDAPI SetProperty(Int32 id, const PROPVARIANT *value); +STDAPI SetProperty(Int32 id, const PROPVARIANT *value) +{ + return S_OK; +} +*/ + +#ifdef Z7_EXTERNAL_CODECS + +CExternalCodecs g_ExternalCodecs; + +STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo); +STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo) +{ + COM_TRY_BEGIN + + // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL"); + if (compressCodecsInfo) + { + g_ExternalCodecs.GetCodecs = compressCodecsInfo; + return g_ExternalCodecs.Load(); + } + g_ExternalCodecs.ClearAndRelease(); + return S_OK; + + COM_TRY_END +} + +#else + +STDAPI SetCodecs(ICompressCodecsInfo *); +STDAPI SetCodecs(ICompressCodecsInfo *) +{ + return S_OK; +} + +#endif diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp index 873e5886c..39011929d 100644 --- a/CPP/7zip/Archive/DmgHandler.cpp +++ b/CPP/7zip/Archive/DmgHandler.cpp @@ -1,2336 +1,2336 @@ -// DmgHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/AutoPtr.h" -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer2.h" -#include "../../Common/MyXml.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/BZip2Decoder.h" -#include "../Compress/CopyCoder.h" -#include "../Compress/LzfseDecoder.h" -#include "../Compress/XzDecoder.h" -#include "../Compress/ZlibDecoder.h" - -#include "Common/OutStreamWithCRC.h" - -// #define DMG_SHOW_RAW - -// #define SHOW_DEBUG_INFO - -/* for debug only: we can use block cache also for METHOD_COPY blocks. - It can reduce the number of Stream->Read() requests. - But it can increase memory usage. - Note: METHOD_COPY blocks are not fused usually. - But if METHOD_COPY blocks is fused in some dmg example, - block size can exceed k_Chunk_Size_MAX. - So we don't use cache for METHOD_COPY block, if (block_size > k_Chunk_Size_MAX) -*/ -// for debug only: -// #define Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS - -#ifdef SHOW_DEBUG_INFO -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -#define Get32a(p) GetBe32a(p) -#define Get64a(p) GetBe64a(p) - -Byte *Base64ToBin(Byte *dest, const char *src); - -namespace NArchive { -namespace NDmg { - -// allocation limits for compressed blocks for GetStream() interface: -static const unsigned k_NumChunks_MAX = 128; -static const size_t k_Chunk_Size_MAX = (size_t)1 << 28; -// 256 MB cache for 32-bit: -// 4 GB cache for 64-bit: -static const size_t k_Chunks_TotalSize_MAX = (size_t)1 << (sizeof(size_t) + 24); - -// 2 GB limit for 32-bit: -// 4 GB limit for 64-bit: -// that limit can be increased for 64-bit mode, if there are such dmg files -static const size_t k_XmlSize_MAX = - ((size_t)1 << (sizeof(size_t) / 4 + 30)) - 256; - -static const UInt32 METHOD_ZERO_0 = 0; // sparse -static const UInt32 METHOD_COPY = 1; -static const UInt32 METHOD_ZERO_2 = 2; // sparse : without file CRC calculation -static const UInt32 METHOD_ADC = 0x80000004; -static const UInt32 METHOD_ZLIB = 0x80000005; -static const UInt32 METHOD_BZIP2 = 0x80000006; -static const UInt32 METHOD_LZFSE = 0x80000007; -static const UInt32 METHOD_XZ = 0x80000008; -static const UInt32 METHOD_COMMENT = 0x7FFFFFFE; // is used to comment "+beg" and "+end" in extra field. -static const UInt32 METHOD_END = 0xFFFFFFFF; - - -struct CBlock -{ - UInt32 Type; - UInt64 UnpPos; - // UInt64 UnpSize; - UInt64 PackPos; - UInt64 PackSize; - - bool NeedCrc() const { return Type != METHOD_ZERO_2; } - bool IsZeroMethod() const - { - return (Type & ~(UInt32)METHOD_ZERO_2) == 0; - // return Type == METHOD_ZERO_0 || Type == METHOD_ZERO_2; - } - - bool IsClusteredMethod() const - { - // most of dmg files have non-fused COPY_METHOD blocks. - // so we don't exclude COPY_METHOD blocks when we try to detect size of cluster. - return !IsZeroMethod(); // include COPY_METHOD blocks. - // Type > METHOD_ZERO_2; // for debug: exclude COPY_METHOD blocks. - } - - bool NeedAllocateBuffer() const - { - return -#ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS - !IsZeroMethod(); -#else - Type > METHOD_ZERO_2; - // !IsZeroMethod() && Type != METHOD_COPY; -#endif - } - // we don't store non-data blocks now - // bool ThereAreDataInBlock() const { return Type != METHOD_COMMENT && Type != METHOD_END; } -}; - -static const UInt32 kCheckSumType_CRC = 2; -static const unsigned kChecksumSize_Max = 0x80; - -struct CChecksum -{ - UInt32 Type; - UInt32 NumBits; - Byte Data[kChecksumSize_Max]; - - bool IsCrc32() const { return Type == kCheckSumType_CRC && NumBits == 32; } - UInt32 GetCrc32() const { return Get32(Data); } - void Parse(const Byte *p); - - void PrintType(AString &s) const; - void Print(AString &s) const; - void Print_with_Name(AString &s) const; - void AddToComment(AString &s, const char *name) const; -}; - -void CChecksum::Parse(const Byte *p) -{ - Type = Get32(p); - NumBits = Get32(p + 4); - memcpy(Data, p + 8, kChecksumSize_Max); -} - - -void CChecksum::PrintType(AString &s) const -{ - if (NumBits == 0) - return; - if (IsCrc32()) - s += "CRC"; - else - { - s += "Checksum"; - s.Add_UInt32(Type); - s.Add_Minus(); - s.Add_UInt32(NumBits); - } -} - -void CChecksum::Print(AString &s) const -{ - if (NumBits == 0) - return; - char temp[kChecksumSize_Max * 2 + 2]; - /* - if (IsCrc32()) - ConvertUInt32ToHex8Digits(GetCrc32(), temp); - else - */ - { - UInt32 numBits = kChecksumSize_Max * 8; - if (numBits > NumBits) - numBits = NumBits; - const unsigned numBytes = (numBits + 7) >> 3; - if (numBytes <= 8) - ConvertDataToHex_Upper(temp, Data, numBytes); - else - ConvertDataToHex_Lower(temp, Data, numBytes); - } - s += temp; -} - -void CChecksum::Print_with_Name(AString &s) const -{ - if (NumBits == 0) - return; - PrintType(s); - s += ": "; - Print(s); -} - -static void AddToComment_Prop(AString &s, const char *name, const char *val) -{ - s += name; - s += ": "; - s += val; - s.Add_LF(); -} - -void CChecksum::AddToComment(AString &s, const char *name) const -{ - AString s2; - Print_with_Name(s2); - if (!s2.IsEmpty()) - AddToComment_Prop(s, name, s2); -} - - -struct CFile -{ - UInt64 Size; - CRecordVector Blocks; - UInt64 PackSize; - UInt64 StartPackPos; - UInt64 BlockSize_MAX; - UInt64 StartUnpackSector; // unpack sector position of this file from all files - UInt64 NumUnpackSectors; - Int32 Descriptor; - bool IsCorrect; - bool FullFileChecksum; - AString Name; - // AString Id; - CChecksum Checksum; - - UInt64 GetUnpackSize_of_Block(unsigned blockIndex) const - { - return (blockIndex == Blocks.Size() - 1 ? - Size : Blocks[blockIndex + 1].UnpPos) - Blocks[blockIndex].UnpPos; - } - - CFile(): - Size(0), - PackSize(0), - StartPackPos(0), - BlockSize_MAX(0), - StartUnpackSector(0), - NumUnpackSectors(0), - Descriptor(0), - IsCorrect(false), - FullFileChecksum(false) - { - Checksum.Type = 0; - Checksum.NumBits = 0; - } - HRESULT Parse(const Byte *p, UInt32 size); -}; - -#ifdef DMG_SHOW_RAW -struct CExtraFile -{ - CByteBuffer Data; - AString Name; -}; -#endif - - -static void AddToComment_UInt64(AString &s, UInt64 v, const char *name) -{ - s += name; - s += ": "; - s.Add_UInt64(v); - s.Add_LF(); -} - -struct CForkPair -{ - UInt64 Offset; - UInt64 Len; - - // (p) is aligned for 8-bytes - void Parse(const Byte *p) - { - Offset = Get64a(p); - Len = Get64a(p + 8); - } - - bool GetEndPos(UInt64 &endPos) - { - endPos = Offset + Len; - return endPos >= Offset; - } - - bool UpdateTop(UInt64 limit, UInt64 &top) - { - if (Offset > limit || Len > limit - Offset) - return false; - const UInt64 top2 = Offset + Len; - if (top <= top2) - top = top2; - return true; - } - - void Print(AString &s, const char *name) const; -}; - -void CForkPair::Print(AString &s, const char *name) const -{ - if (Offset != 0 || Len != 0) - { - s += name; s.Add_Minus(); AddToComment_UInt64(s, Offset, "offset"); - s += name; s.Add_Minus(); AddToComment_UInt64(s, Len, "length"); - } -} - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - bool _masterCrcError; - bool _headersError; - bool _dataForkError; - bool _rsrcMode_wasUsed; - - CMyComPtr _inStream; - CObjectVector _files; - - // UInt32 _dataStartOffset; - UInt64 _startPos; - UInt64 _phySize; - - AString _name; - - CForkPair _dataForkPair; - CForkPair rsrcPair, xmlPair, blobPair; - - // UInt64 _runningDataForkOffset; - // UInt32 _segmentNumber; - // UInt32 _segmentCount; - UInt64 _numSectors; // total unpacked number of sectors - Byte _segmentGUID[16]; - - CChecksum _dataForkChecksum; - CChecksum _masterChecksum; - -#ifdef DMG_SHOW_RAW - CObjectVector _extras; -#endif - - HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf); - bool ParseBlob(const CByteBuffer &data); - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback); - HRESULT Extract(IInStream *stream); -}; - - -struct CMethods -{ - CRecordVector Types; - - void Update(const CFile &file); - void AddToString(AString &s) const; -}; - -void CMethods::Update(const CFile &file) -{ - FOR_VECTOR (i, file.Blocks) - { - if (Types.Size() >= (1 << 8)) - break; - Types.AddToUniqueSorted(file.Blocks[i].Type); - } -} - -void CMethods::AddToString(AString &res) const -{ - FOR_VECTOR (i, Types) - { - const UInt32 type = Types[i]; - /* - if (type == METHOD_COMMENT || type == METHOD_END) - continue; - */ - char buf[16]; - const char *s; - switch (type) - { - // case METHOD_COMMENT: s = "Comment"; break; - case METHOD_ZERO_0: s = "Zero0"; break; - case METHOD_ZERO_2: s = "Zero2"; break; - case METHOD_COPY: s = "Copy"; break; - case METHOD_ADC: s = "ADC"; break; - case METHOD_ZLIB: s = "ZLIB"; break; - case METHOD_BZIP2: s = "BZip2"; break; - case METHOD_LZFSE: s = "LZFSE"; break; - case METHOD_XZ: s = "XZ"; break; - default: ConvertUInt32ToHex(type, buf); s = buf; - } - res.Add_OptSpaced(s); - } -} - - - -struct CAppleName -{ - bool IsFs; - const char *Ext; - const char *AppleName; -}; - -static const CAppleName k_Names[] = -{ - { true, "hfs", "Apple_HFS" }, - { true, "hfsx", "Apple_HFSX" }, - { true, "ufs", "Apple_UFS" }, - { true, "apfs", "Apple_APFS" }, - { true, "iso", "Apple_ISO" }, - - // efi_sys partition is FAT32, but it's not main file. So we use (IsFs = false) - { false, "efi_sys", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" }, - - { false, "free", "Apple_Free" }, - { false, "ddm", "DDM" }, - { false, NULL, "Apple_partition_map" }, - { false, NULL, " GPT " }, - /* " GPT " is substring of full name entry in dmg that contains - some small metadata GPT entry. It's not real FS entry: - "Primary GPT Header", - "Primary GPT Table" - "Backup GPT Header", - "Backup GPT Table", - */ - { false, NULL, "MBR" }, - { false, NULL, "Driver" }, - { false, NULL, "Patches" } -}; - -static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names); - -const char *Find_Apple_FS_Ext(const AString &name); -const char *Find_Apple_FS_Ext(const AString &name) -{ - for (unsigned i = 0; i < kNumAppleNames; i++) - { - const CAppleName &a = k_Names[i]; - if (a.Ext) - if (name == a.AppleName) - return a.Ext; - } - return NULL; -} - - -bool Is_Apple_FS_Or_Unknown(const AString &name); -bool Is_Apple_FS_Or_Unknown(const AString &name) -{ - for (unsigned i = 0; i < kNumAppleNames; i++) - { - const CAppleName &a = k_Names[i]; - // if (name.Find(a.AppleName) >= 0) - if (strstr(name, a.AppleName)) - return a.IsFs; - } - return true; -} - - - -// define it for debug only: -// #define Z7_DMG_SINGLE_FILE_MODE - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidComment, - kpidMethod, - kpidNumBlocks, - kpidClusterSize, - kpidChecksum, - kpidCRC, - kpidId - // kpidOffset -#ifdef Z7_DMG_SINGLE_FILE_MODE - , kpidPosition -#endif -}; - -IMP_IInArchive_Props - -static const Byte kArcProps[] = -{ - kpidMethod, - kpidNumBlocks, - kpidClusterSize, - kpidComment -}; - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidMethod: - { - CMethods m; - CRecordVector ChecksumTypes; - { - FOR_VECTOR (i, _files) - { - const CFile &file = _files[i]; - m.Update(file); - if (ChecksumTypes.Size() < (1 << 8)) - ChecksumTypes.AddToUniqueSorted(file.Checksum.Type); - } - } - AString s; - m.AddToString(s); - - FOR_VECTOR (i, ChecksumTypes) - { - const UInt32 type = ChecksumTypes[i]; - switch (type) - { - case kCheckSumType_CRC: - s.Add_OptSpaced("CRC"); - break; - default: - s.Add_OptSpaced("Checksum"); - s.Add_UInt32(type); - } - } - - if (!s.IsEmpty()) - prop = s; - break; - } - case kpidNumBlocks: - { - UInt64 numBlocks = 0; - FOR_VECTOR (i, _files) - numBlocks += _files[i].Blocks.Size(); - prop = numBlocks; - break; - } - case kpidClusterSize: - { - UInt64 blockSize_MAX = 0; - FOR_VECTOR (i, _files) - { - const UInt64 a = _files[i].BlockSize_MAX; - if (blockSize_MAX < a) - blockSize_MAX = a; - } - prop = blockSize_MAX; - break; - } - case kpidMainSubfile: - { - int mainIndex = -1; - FOR_VECTOR (i, _files) - { - if (Is_Apple_FS_Or_Unknown(_files[i].Name)) - { - if (mainIndex != -1) - { - mainIndex = -1; - break; - } - mainIndex = (int)i; - } - } - if (mainIndex != -1) - prop = (UInt32)(Int32)mainIndex; - break; - } - case kpidWarning: - if (_masterCrcError) - prop = "Master CRC error"; - break; - - case kpidWarningFlags: - { - UInt32 v = 0; - if (_headersError) v |= kpv_ErrorFlags_HeadersError; - if (_dataForkError) v |= kpv_ErrorFlags_CrcError; - if (v != 0) - prop = v; - break; - } - - case kpidOffset: prop = _startPos; break; - case kpidPhySize: prop = _phySize; break; - - case kpidComment: - { - AString s; - if (!_name.IsEmpty()) - AddToComment_Prop(s, "Name", _name); - AddToComment_UInt64(s, _numSectors << 9, "unpack-size"); - { - char temp[sizeof(_segmentGUID) * 2 + 2]; - ConvertDataToHex_Lower(temp, _segmentGUID, sizeof(_segmentGUID)); - AddToComment_Prop(s, "ID", temp); - } - _masterChecksum.AddToComment(s, "master-checksum"); - _dataForkChecksum.AddToComment(s, "pack-checksum"); - { - /* - if (_dataStartOffset != 0) - AddToComment_UInt64(s, _dataStartOffset, "payload-start-offset"); - */ - // if (_dataForkPair.Offset != 0) - _dataForkPair.Print(s, "pack"); - rsrcPair.Print(s, "rsrc"); - xmlPair.Print(s, "xml"); - blobPair.Print(s, "blob"); - } - if (_rsrcMode_wasUsed) - s += "RSRC_MODE\n"; - if (!s.IsEmpty()) - prop = s; - } - break; - - case kpidName: - if (!_name.IsEmpty()) - prop = _name + ".dmg"; - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -IMP_IInArchive_ArcProps - - - -static const UInt64 kSectorNumber_LIMIT = (UInt64)1 << (63 - 9); - -HRESULT CFile::Parse(const Byte *p, UInt32 size) -{ - // CFile was initialized to default values: 0 in size variables and (IsCorrect == false) - const unsigned kHeadSize = 0xCC; - if (size < kHeadSize) - return S_FALSE; - if (Get32(p) != 0x6D697368) // "mish" signature - return S_FALSE; - if (Get32(p + 4) != 1) // version - return S_FALSE; - - StartUnpackSector = Get64(p + 8); - NumUnpackSectors = Get64(p + 0x10); - StartPackPos = Get64(p + 0x18); - -#ifdef SHOW_DEBUG_INFO - /* the number of sectors that must be allocated. - == 0x208 for 256KB clusters - == 0x808 for 1MB clusters - == 0x1001 for 1MB clusters in some example - */ - const UInt32 decompressedBufRequested = Get32(p + 0x20); -#endif - - // Descriptor is file index. usually started from -1 - // in one dmg it was started from 0 - Descriptor = (Int32)Get32(p + 0x24); - // char Reserved1[24]; - - Checksum.Parse(p + 0x40); - PRF(printf("\n" " Checksum Type = %2u" - "\n StartUnpackSector = %8x" - "\n NumUnpackSectors = %8x" - "\n StartPos = %8x" - "\n decompressedBufRequested=%8x" - "\n blocksDescriptor=%8x" - , (unsigned)Checksum.Type - , (unsigned)StartUnpackSector - , (unsigned)NumUnpackSectors - , (unsigned)StartPackPos - , (unsigned)decompressedBufRequested - , (unsigned)Descriptor - );) - - const UInt32 numBlocks = Get32(p + 0xC8); - const unsigned kRecordSize = 40; - if ((UInt64)numBlocks * kRecordSize + kHeadSize != size) - return S_FALSE; - - Blocks.ClearAndReserve(numBlocks); - FullFileChecksum = true; - /* IsCorrect = false; by default - So we return S_OK, if we can ignore some error in headers. - */ - - p += kHeadSize; - UInt32 i; - - for (i = 0; i < numBlocks; i++, p += kRecordSize) - { - CBlock b; - b.Type = Get32(p); - { - const UInt64 a = Get64(p + 0x08); - if (a >= kSectorNumber_LIMIT) - return S_OK; - b.UnpPos = a << 9; - } - UInt64 unpSize; - { - const UInt64 a = Get64(p + 0x10); - if (a >= kSectorNumber_LIMIT) - return S_OK; - unpSize = a << 9; - } - const UInt64 newSize = b.UnpPos + unpSize; - if (newSize >= ((UInt64)1 << 63)) - return S_OK; - - b.PackPos = Get64(p + 0x18); - b.PackSize = Get64(p + 0x20); - // b.PackPos can be 0 for some types. So we don't check it - if (b.UnpPos != Size) - return S_OK; - - PRF(printf("\nType=%8x comment=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x", - (unsigned)b.Type, Get32(p + 4), (unsigned)b.UnpPos, (unsigned)unpSize, (unsigned)b.PackPos, (unsigned)b.PackSize)); - - if (b.Type == METHOD_COMMENT) - { - // some files contain 2 comment block records: - // record[0] : Type=METHOD_COMMENT, comment_field = "+beg" - // record[num-2] : Type=METHOD_COMMENT, comment_field = "+end" - // we skip these useless records. - continue; - } - if (b.Type == METHOD_END) - break; - - // we add only blocks that have non empty unpacked data: - if (unpSize != 0) - { - const UInt64 k_max_pos = (UInt64)1 << 63; - if (b.PackPos >= k_max_pos || - b.PackSize >= k_max_pos - b.PackPos) - return S_OK; - - /* we don't count non-ZERO blocks here, because - ZERO blocks in dmg files are not limited by some cluster size. - note: COPY blocks also sometimes are fused to larger blocks. - */ - if (b.IsClusteredMethod()) - if (BlockSize_MAX < unpSize) - BlockSize_MAX = unpSize; - - PackSize += b.PackSize; - if (!b.NeedCrc()) - FullFileChecksum = false; - Blocks.AddInReserved(b); - Size = newSize; - } - } - - PRF(printf("\n");) - - if (i != numBlocks - 1) - { - // return S_FALSE; - return S_OK; - } - - if ((Size >> 9) == NumUnpackSectors) - IsCorrect = true; - return S_OK; -} - - -static const CXmlItem *FindKeyPair(const CXmlItem &item, const char *key, const char *nextTag) -{ - for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) - { - const CXmlItem &si = item.SubItems[i]; - if (si.IsTagged("key") && si.GetSubString() == key) - { - const CXmlItem *si_1 = &item.SubItems[i + 1]; - if (si_1->IsTagged(nextTag)) - return si_1; - } - } - return NULL; -} - -static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag) -{ - const CXmlItem *si_1 = FindKeyPair(item, key, nextTag); - if (si_1) - return si_1->GetSubStringPtr(); - return NULL; -} - -static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }; - -static inline bool IsKoly(const Byte *p) -{ - return memcmp(p, k_Signature, Z7_ARRAY_SIZE(k_Signature)) == 0; - /* - if (Get32(p) != 0x6B6F6C79) // "koly" signature - return false; - if (Get32(p + 4) != 4) // version - return false; - if (Get32(p + 8) != HEADER_SIZE) - return false; - return true; - */ -} - - -HRESULT CHandler::ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf) -{ - size_t size = (size_t)pair.Len; - if (size != pair.Len) - return E_OUTOFMEMORY; - buf.Alloc(size); - RINOK(InStream_SeekSet(stream, _startPos + pair.Offset)) - return ReadStream_FALSE(stream, buf, size); -} - - - -bool CHandler::ParseBlob(const CByteBuffer &data) -{ - const unsigned kHeaderSize = 3 * 4; - if (data.Size() < kHeaderSize) - return false; - const Byte * const p = (const Byte *)data; - if (Get32a(p) != 0xfade0cc0) // CSMAGIC_EMBEDDED_SIGNATURE - return true; - const UInt32 size = Get32a(p + 4); - if (size != data.Size()) - return false; - const UInt32 num = Get32a(p + 8); - if (num > (size - kHeaderSize) / 8) - return false; - - const UInt32 limit = num * 8 + kHeaderSize; - for (size_t i = kHeaderSize; i < limit; i += 8) - { - // type == 0 == CSSLOT_CODEDIRECTORY for CSMAGIC_CODEDIRECTORY item - // UInt32 type = Get32(p + i); - const UInt32 offset = Get32a(p + i + 4); - if (offset < limit || offset > size - 8) - return false; - // offset is not aligned for 4 here !!! - const Byte * const p2 = p + offset; - const UInt32 magic = Get32(p2); - const UInt32 len = Get32(p2 + 4); - if (size - offset < len || len < 8) - return false; - -#ifdef DMG_SHOW_RAW - CExtraFile &extra = _extras.AddNew(); - extra.Name = "_blob_"; - extra.Data.CopyFrom(p2, len); -#endif - - if (magic == 0xfade0c02) // CSMAGIC_CODEDIRECTORY - { -#ifdef DMG_SHOW_RAW - extra.Name += "codedir"; -#endif - - if (len < 11 * 4) - return false; - const UInt32 idOffset = Get32(p2 + 5 * 4); - if (idOffset >= len) - return false; - UInt32 len2 = len - idOffset; - const UInt32 kNameLenMax = 1 << 8; - if (len2 > kNameLenMax) - len2 = kNameLenMax; - _name.SetFrom_CalcLen((const char *)(p2 + idOffset), len2); - /* - // #define kSecCodeSignatureHashSHA1 1 - // #define kSecCodeSignatureHashSHA256 2 - const UInt32 hashOffset = Get32(p2 + 4 * 4); - const UInt32 nSpecialSlots = Get32(p2 + 6 * 4); - const UInt32 nCodeSlots = Get32(p2 + 7 * 4); - const unsigned hashSize = p2[36]; - const unsigned hashType = p2[37]; - // const unsigned unused = p2[38]; - const unsigned pageSize = p2[39]; - */ - } -#ifdef DMG_SHOW_RAW - else if (magic == 0xfade0c01) extra.Name += "requirements"; - else if (magic == 0xfade0b01) extra.Name += "signed"; - else - { - char temp[16]; - ConvertUInt32ToHex8Digits(magic, temp); - extra.Name += temp; - } -#endif - } - - return true; -} - - - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) -{ - /* - - usual dmg contains Koly Header at the end: - - rare case old dmg contains Koly Header at the begin. - */ - - // _dataStartOffset = 0; - UInt64 fileSize; - RINOK(InStream_GetPos_GetSize(stream, _startPos, fileSize)) - - const unsigned HEADER_SIZE = 0x200; - UInt64 buf[HEADER_SIZE / sizeof(UInt64)]; - RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)) - - UInt64 headerPos; - bool front_Koly_Mode = false; - - /* - _dataForkChecksum.Offset == 0 for koly-at-the-end - _dataForkChecksum.Offset == 512 for koly-at-the-start - so we can use (_dataForkChecksum.Offset) to detect "koly-at-the-start" mode - */ - - if (IsKoly((const Byte *)(const void *)buf)) - { - // it can be normal koly-at-the-end or koly-at-the-start - headerPos = _startPos; - /* - if (_startPos <= (1 << 8)) - { - // we want to support front_Koly_Mode, even if there is - // some data before dmg file, like 128 bytes MacBin header - _dataStartOffset = HEADER_SIZE; - front_Koly_Mode = true; - } - */ - } - else - { - /* we try to open in backward mode only for first attempt - when (_startPos == 0) */ - if (_startPos != 0) - return S_FALSE; - headerPos = fileSize; - if (headerPos < HEADER_SIZE) - return S_FALSE; - headerPos -= HEADER_SIZE; - RINOK(InStream_SeekSet(stream, headerPos)) - RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)) - if (!IsKoly((const Byte *)(const void *)buf)) - return S_FALSE; - } - - // UInt32 flags = Get32a((const Byte *)(const void *)buf + 12); - // _runningDataForkOffset = Get64a((const Byte *)(const void *)buf + 0x10); - _dataForkPair.Parse((const Byte *)(const void *)buf + 0x18); - rsrcPair.Parse((const Byte *)(const void *)buf + 0x28); - // _segmentNumber = Get32a(buf + 0x38); // 0 or 1 - // _segmentCount = Get32a(buf + 0x3C); // 0 (if not set) or 1 - memcpy(_segmentGUID, (const Byte *)(const void *)buf + 0x40, 16); - _dataForkChecksum.Parse((const Byte *)(const void *)buf + 0x50); - xmlPair.Parse((const Byte *)(const void *)buf + 0xD8); - // Byte resereved[] - blobPair.Parse((const Byte *)(const void *)buf + 0x128); - _masterChecksum.Parse((const Byte *)(const void *)buf + 0x160); - // UInt32 imageVariant = Get32a((const Byte *)(const void *)buf + 0x1E8); imageVariant = imageVariant; - _numSectors = Get64((const Byte *)(const void *)buf + 0x1EC); // it's not aligned for 8-bytes - // Byte resereved[12]; - - if (_dataForkPair.Offset == HEADER_SIZE - && headerPos + HEADER_SIZE < fileSize) - front_Koly_Mode = true; - - const UInt64 limit = front_Koly_Mode ? fileSize : headerPos; - UInt64 top = 0; - if (!_dataForkPair.UpdateTop(limit, top)) return S_FALSE; - if (!xmlPair.UpdateTop(limit, top)) return S_FALSE; - if (!rsrcPair.UpdateTop(limit, top)) return S_FALSE; - - /* Some old dmg files contain garbage data in blobPair field. - So we need to ignore such garbage case; - And we still need to detect offset of start of archive for "parser" mode. */ - const bool useBlob = blobPair.UpdateTop(limit, top); - - if (front_Koly_Mode) - _phySize = top; - else - { - _phySize = headerPos + HEADER_SIZE; - _startPos = 0; - if (top != headerPos) - { - /* - if expected absolute offset is not equal to real header offset, - 2 cases are possible: - - additional (unknown) headers - - archive with offset. - So we try to read XML with absolute offset to select from these two ways. - */ - CForkPair xmlPair2 = xmlPair; - const char *sz = " len) - xmlPair2.Len = len; - CByteBuffer buf2; - if (xmlPair2.Len < len - || ReadData(stream, xmlPair2, buf2) != S_OK - || memcmp(buf2, sz, len) != 0) - { - // if absolute offset is not OK, probably it's archive with offset - _startPos = headerPos - top; - _phySize = top + HEADER_SIZE; - } - } - } - - if (useBlob - && blobPair.Len != 0 - && blobPair.Len <= (1u << 24)) // we don't want parsing of big blobs - { -#ifdef DMG_SHOW_RAW - CExtraFile &extra = _extras.AddNew(); - extra.Name = "_blob.bin"; - CByteBuffer &blobBuf = extra.Data; -#else - CByteBuffer blobBuf; -#endif - RINOK(ReadData(stream, blobPair, blobBuf)) - if (!ParseBlob(blobBuf)) - _headersError = true; - } - - - UInt64 openTotal = 0; - UInt64 openCur = 0; - if (_dataForkChecksum.IsCrc32()) - openTotal = _dataForkPair.Len; - - const UInt32 RSRC_HEAD_SIZE = 0x100; - - /* we have 2 ways to read files and blocks metadata: - via Xml or via Rsrc. - But some images have no Rsrc fork. - Is it possible that there is no Xml? - Rsrc method will not work for big files. */ - // v23.02: we use xml mode by default - // if (rsrcPair.Len >= RSRC_HEAD_SIZE && rsrcPair.Len <= ((UInt32)1 << 24)) // for debug - if (xmlPair.Len == 0) - { - // We don't know the size of the field "offset" in Rsrc. - // We suppose that it uses 24 bits. So we use Rsrc, only if the rsrcPair.Len <= (1 << 24). - const bool canUseRsrc = (rsrcPair.Len >= RSRC_HEAD_SIZE && rsrcPair.Len <= ((UInt32)1 << 24)); - if (!canUseRsrc) - return S_FALSE; - - _rsrcMode_wasUsed = true; -#ifdef DMG_SHOW_RAW - CExtraFile &extra = _extras.AddNew(); - extra.Name = "rsrc.bin"; - CByteBuffer &rsrcBuf = extra.Data; -#else - CByteBuffer rsrcBuf; -#endif - - RINOK(ReadData(stream, rsrcPair, rsrcBuf)) - - const Byte *p = rsrcBuf; - const UInt32 headSize = Get32a(p + 0); - const UInt32 footerOffset = Get32a(p + 4); - const UInt32 mainDataSize = Get32a(p + 8); - const UInt32 footerSize = Get32a(p + 12); - if (headSize != RSRC_HEAD_SIZE - || footerOffset >= rsrcPair.Len - || mainDataSize >= rsrcPair.Len - || footerOffset < mainDataSize - || footerOffset != headSize + mainDataSize) - return S_FALSE; - - { - const UInt32 footerEnd = footerOffset + footerSize; - if (footerEnd != rsrcPair.Len) - { - // there is rare case dmg example, where there are 4 additional bytes - const UInt64 rem = rsrcPair.Len - footerOffset; - if (rem < footerSize - || rem - footerSize != 4 - || Get32(p + footerEnd) != 0) - return S_FALSE; - } - } - - if (footerSize < 0x1e) - return S_FALSE; - if (memcmp(p, p + footerOffset, 16) != 0) - return S_FALSE; - - p += footerOffset; - - if ((UInt32)Get16(p + 0x18) != 0x1c) - return S_FALSE; - const UInt32 namesOffset = Get16(p + 0x1a); - if (namesOffset > footerSize) - return S_FALSE; - - const UInt32 numItems = (UInt32)Get16(p + 0x1c) + 1; - if (numItems * 8 + 0x1e > namesOffset) - return S_FALSE; - - for (UInt32 i = 0; i < numItems; i++) - { - const Byte *p2 = p + 0x1e + (size_t)i * 8; - const UInt32 typeId = Get32(p2); - const UInt32 k_typeId_blkx = 0x626c6b78; // blkx -#ifndef DMG_SHOW_RAW - if (typeId != k_typeId_blkx) - continue; -#endif - const UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1; - const UInt32 offs = Get16(p2 + 6); - if (0x1c + offs + 12 * numFiles > namesOffset) - return S_FALSE; - - for (UInt32 k = 0; k < numFiles; k++) - { - const Byte *p3 = p + 0x1c + offs + k * 12; - // UInt32 id = Get16(p3); - const UInt32 namePos = Get16(p3 + 2); - // Byte attributes = p3[4]; // = 0x50 for blkx #define (ATTRIBUTE_HDIUTIL) - // we don't know how many bits we can use. So we use 24 bits only - UInt32 blockOffset = Get32(p3 + 4); - blockOffset &= ((UInt32)1 << 24) - 1; - // UInt32 unknown2 = Get32(p3 + 8); // ??? - if (blockOffset + 4 >= mainDataSize) - return S_FALSE; - const Byte *pBlock = rsrcBuf + headSize + blockOffset; - const UInt32 blockSize = Get32(pBlock); - if (mainDataSize - (blockOffset + 4) < blockSize) - return S_FALSE; - - AString name; - - if (namePos != 0xffff) - { - const UInt32 namesBlockSize = footerSize - namesOffset; - if (namePos >= namesBlockSize) - return S_FALSE; - const Byte *namePtr = p + namesOffset + namePos; - const UInt32 nameLen = *namePtr; - if (namesBlockSize - namePos <= nameLen) - return S_FALSE; - for (UInt32 r = 1; r <= nameLen; r++) - { - const Byte c = namePtr[r]; - if (c < 0x20 || c >= 0x80) - break; - name += (char)c; - } - } - - if (typeId == k_typeId_blkx) - { - CFile &file = _files.AddNew(); - file.Name = name; - RINOK(file.Parse(pBlock + 4, blockSize)) - if (!file.IsCorrect) - _headersError = true; - } - -#ifdef DMG_SHOW_RAW - { - AString name2; - name2.Add_UInt32(i); - name2 += '_'; - { - char temp[4 + 1] = { 0 }; - memcpy(temp, p2, 4); - name2 += temp; - } - name2.Trim(); - name2 += '_'; - name2.Add_UInt32(k); - if (!name.IsEmpty()) - { - name2 += '_'; - name2 += name; - } - CExtraFile &extra2 = _extras.AddNew(); - extra2.Name = name2; - extra2.Data.CopyFrom(pBlock + 4, blockSize); - } -#endif - } - } - } - else - { - if (xmlPair.Len > k_XmlSize_MAX) - return S_FALSE; - // if (!canUseXml) return S_FALSE; - const size_t size = (size_t)xmlPair.Len; - // if (size + 1 <= xmlPair.Len) return S_FALSE; // optional check - RINOK(InStream_SeekSet(stream, _startPos + xmlPair.Offset)) - CXml xml; - { - openTotal += size; - if (openArchiveCallback) - { - RINOK(openArchiveCallback->SetTotal(NULL, &openTotal)) - } - size_t pos = 0; - CAlignedBuffer1 xmlStr(size + 1); - for (;;) - { - const size_t k_OpenStep = 1 << 24; - const size_t cur = MyMin(k_OpenStep, size - pos); - RINOK(ReadStream_FALSE(stream, xmlStr + pos, cur)) - pos += cur; - openCur += cur; - if (pos == size) - break; - if (openArchiveCallback) - { - RINOK(openArchiveCallback->SetCompleted(NULL, &openCur)) - } - } - xmlStr[size] = 0; - // if (strlen((const char *)(const void *)(const Byte *)xmlStr) != size) return S_FALSE; - if (!xml.Parse((char *)(void *)(Byte *)xmlStr)) - return S_FALSE; - -#ifdef DMG_SHOW_RAW - CExtraFile &extra = _extras.AddNew(); - extra.Name = "a.xml"; - extra.Data.CopyFrom(xmlStr, size); -#endif - } - - if (xml.Root.Name != "plist") - return S_FALSE; - - const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict"); - if (!dictItem) - return S_FALSE; - - const CXmlItem *rfDictItem = FindKeyPair(*dictItem, "resource-fork", "dict"); - if (!rfDictItem) - return S_FALSE; - - const CXmlItem *arrItem = FindKeyPair(*rfDictItem, "blkx", "array"); - if (!arrItem) - return S_FALSE; - - FOR_VECTOR (i, arrItem->SubItems) - { - const CXmlItem &item = arrItem->SubItems[i]; - if (!item.IsTagged("dict")) - continue; - - CByteBuffer rawBuf; - unsigned destLen = 0; - { - const AString *dataString = GetStringFromKeyPair(item, "Data", "data"); - if (!dataString) - return S_FALSE; - destLen = dataString->Len() / 4 * 3 + 4; - rawBuf.Alloc(destLen); - { - const Byte *endPtr = Base64ToBin(rawBuf, *dataString); - if (!endPtr) - return S_FALSE; - destLen = (unsigned)(endPtr - (const Byte *)rawBuf); - } - -#ifdef DMG_SHOW_RAW - CExtraFile &extra = _extras.AddNew(); - extra.Name.Add_UInt32(_files.Size()); - extra.Data.CopyFrom(rawBuf, destLen); -#endif - } - CFile &file = _files.AddNew(); - { - /* xml code removes front space for such string: - (Apple_Free : 3) - maybe we shoud fix xml code and return full string with space. - */ - const AString *name = GetStringFromKeyPair(item, "Name", "string"); - if (!name || name->IsEmpty()) - name = GetStringFromKeyPair(item, "CFName", "string"); - if (name) - file.Name = *name; - } - /* - { - const AString *s = GetStringFromKeyPair(item, "ID", "string"); - if (s) - file.Id = *s; - } - */ - RINOK(file.Parse(rawBuf, destLen)) - if (!file.IsCorrect) - _headersError = true; - } - } - - if (_masterChecksum.IsCrc32()) - { - UInt32 crc = CRC_INIT_VAL; - unsigned i; - for (i = 0; i < _files.Size(); i++) - { - const CChecksum &cs = _files[i].Checksum; - if ((cs.NumBits & 0x7) != 0) - break; - const UInt32 len = cs.NumBits >> 3; - if (len > kChecksumSize_Max) - break; - crc = CrcUpdate(crc, cs.Data, (size_t)len); - } - if (i == _files.Size()) - _masterCrcError = (CRC_GET_DIGEST(crc) != _masterChecksum.GetCrc32()); - } - - { - UInt64 sec = 0; - FOR_VECTOR (i, _files) - { - const CFile &file = _files[i]; - /* - if (file.Descriptor != (Int32)i - 1) - _headersError = true; - */ - if (file.StartUnpackSector != sec) - _headersError = true; - if (file.NumUnpackSectors >= kSectorNumber_LIMIT) - _headersError = true; - sec += file.NumUnpackSectors; - if (sec >= kSectorNumber_LIMIT) - _headersError = true; - } - if (sec != _numSectors) - _headersError = true; - } - - // data checksum calculation can be slow for big dmg file - if (_dataForkChecksum.IsCrc32()) - { - UInt64 endPos; - if (!_dataForkPair.GetEndPos(endPos) - || _dataForkPair.Offset >= ((UInt64)1 << 63)) - _headersError = true; - else - { - const UInt64 seekPos = _startPos + _dataForkPair.Offset; - if (seekPos > fileSize - || endPos > fileSize - _startPos) - { - _headersError = true; - // kpv_ErrorFlags_UnexpectedEnd - } - else - { - const size_t kBufSize = 1 << 15; - CAlignedBuffer1 buf2(kBufSize); - RINOK(InStream_SeekSet(stream, seekPos)) - if (openArchiveCallback) - { - RINOK(openArchiveCallback->SetTotal(NULL, &openTotal)) - } - UInt32 crc = CRC_INIT_VAL; - UInt64 pos = 0; - for (;;) - { - const UInt64 rem = _dataForkPair.Len - pos; - size_t cur = kBufSize; - if (cur > rem) - cur = (UInt32)rem; - if (cur == 0) - break; - RINOK(ReadStream_FALSE(stream, buf2, cur)) - crc = CrcUpdate(crc, buf2, cur); - pos += cur; - openCur += cur; - if ((pos & ((1 << 24) - 1)) == 0 && openArchiveCallback) - { - RINOK(openArchiveCallback->SetCompleted(NULL, &openCur)) - } - } - if (_dataForkChecksum.GetCrc32() != CRC_GET_DIGEST(crc)) - _dataForkError = true; - } - } - } - - return S_OK; -} - - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *openArchiveCallback)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(stream, openArchiveCallback)) - _inStream = stream; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _masterCrcError = false; - _headersError = false; - _dataForkError = false; - _rsrcMode_wasUsed = false; - _phySize = 0; - _startPos = 0; - _name.Empty(); - _inStream.Release(); - _files.Clear(); -#ifdef DMG_SHOW_RAW - _extras.Clear(); -#endif - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _files.Size() -#ifdef DMG_SHOW_RAW - + _extras.Size() -#endif - ; - return S_OK; -} - -#ifdef DMG_SHOW_RAW -#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR -#endif - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - -#ifdef DMG_SHOW_RAW - if (index >= _files.Size()) - { - const CExtraFile &extra = _extras[index - _files.Size()]; - switch (propID) - { - case kpidPath: - prop = (AString)RAW_PREFIX + extra.Name; - break; - case kpidSize: - case kpidPackSize: - prop = (UInt64)extra.Data.Size(); - break; - } - } - else -#endif - { - const CFile &item = _files[index]; - switch (propID) - { - case kpidSize: prop = item.Size; break; - case kpidPackSize: prop = item.PackSize; break; - case kpidCRC: - { - if (item.Checksum.IsCrc32() && item.FullFileChecksum) - prop = item.Checksum.GetCrc32(); - break; - } - case kpidChecksum: - { - AString s; - item.Checksum.Print(s); - if (!s.IsEmpty()) - prop = s; - break; - } - - /* - case kpidOffset: - { - prop = item.StartPackPos; - break; - } - */ - - case kpidNumBlocks: - prop = (UInt32)item.Blocks.Size(); - break; - case kpidClusterSize: - prop = item.BlockSize_MAX; - break; - - case kpidMethod: - { - AString s; - if (!item.IsCorrect) - s.Add_OptSpaced("CORRUPTED"); - CMethods m; - m.Update(item); - m.AddToString(s); - { - AString s2; - item.Checksum.PrintType(s2); - if (!s2.IsEmpty()) - s.Add_OptSpaced(s2); - } - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidPath: - { -#ifdef Z7_DMG_SINGLE_FILE_MODE - prop = "a.img"; -#else - UString name; - name.Add_UInt32(index); - unsigned num = 10; - unsigned numDigits; - for (numDigits = 1; num < _files.Size(); numDigits++) - num *= 10; - while (name.Len() < numDigits) - name.InsertAtFront(L'0'); - - AString subName; - int pos1 = item.Name.Find('('); - if (pos1 >= 0) - { - pos1++; - const int pos2 = item.Name.Find(')', pos1); - if (pos2 >= 0) - { - subName.SetFrom(item.Name.Ptr(pos1), pos2 - pos1); - pos1 = subName.Find(':'); - if (pos1 >= 0) - subName.DeleteFrom(pos1); - } - } - else - subName = item.Name; // new apfs dmg can be without braces - subName.Trim(); - if (!subName.IsEmpty()) - { - const char *ext = Find_Apple_FS_Ext(subName); - if (ext) - subName = ext; - UString name2; - ConvertUTF8ToUnicode(subName, name2); - name.Add_Dot(); - name += name2; - } - else - { - UString name2; - ConvertUTF8ToUnicode(item.Name, name2); - if (!name2.IsEmpty()) - name += "_"; - name += name2; - } - prop = name; -#endif - - break; - } - - case kpidComment: - { - UString name; - ConvertUTF8ToUnicode(item.Name, name); - prop = name; - break; - } - case kpidId: - { - prop.Set_Int32((Int32)item.Descriptor); - /* - if (!item.Id.IsEmpty()) - { - UString s; - ConvertUTF8ToUnicode(item.Id, s); - prop = s; - } - */ - break; - } -#ifdef Z7_DMG_SINGLE_FILE_MODE - case kpidPosition: - prop = item.StartUnpackSector << 9; - break; -#endif - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -class CAdcDecoder -{ - CLzOutWindow m_OutWindowStream; - CInBuffer m_InStream; - - class CCoderReleaser Z7_final - { - CAdcDecoder *m_Coder; - public: - bool NeedFlush; - CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {} - ~CCoderReleaser() - { - if (NeedFlush) - m_Coder->m_OutWindowStream.Flush(); - } - }; - friend class CCoderReleaser; - -public: - HRESULT Code(ISequentialInStream * const inStream, - ISequentialOutStream *outStream, - const UInt64 * const inSize, - const UInt64 * const outSize, - ICompressProgressInfo * const progress); -}; - - -HRESULT CAdcDecoder::Code(ISequentialInStream * const inStream, - ISequentialOutStream *outStream, - const UInt64 * const inSize, - const UInt64 * const outSizePtr, - ICompressProgressInfo * const progress) -{ - try { - - if (!m_OutWindowStream.Create(1 << 18)) // at least (1 << 16) is required here - return E_OUTOFMEMORY; - if (!m_InStream.Create(1 << 18)) - return E_OUTOFMEMORY; - - m_OutWindowStream.SetStream(outStream); - m_OutWindowStream.Init(false); - m_InStream.SetStream(inStream); - m_InStream.Init(); - - CCoderReleaser coderReleaser(this); - - const UInt32 kStep = 1 << 22; - UInt64 nextLimit = kStep; - const UInt64 outSize = *outSizePtr; - UInt64 pos = 0; - /* match sequences and literal sequences do not cross 64KB range - in some dmg archive examples. But is it so for any Adc stream? */ - - while (pos < outSize) - { - if (pos >= nextLimit && progress) - { - nextLimit += kStep; - const UInt64 packSize = m_InStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &pos)) - } - Byte b; - if (!m_InStream.ReadByte(b)) - return S_FALSE; - const UInt64 rem = outSize - pos; - if (b & 0x80) - { - unsigned num = (unsigned)b - 0x80 + 1; - if (num > rem) - return S_FALSE; - pos += num; - do - { - if (!m_InStream.ReadByte(b)) - return S_FALSE; - m_OutWindowStream.PutByte(b); - } - while (--num); - continue; - } - Byte b1; - if (!m_InStream.ReadByte(b1)) - return S_FALSE; - - UInt32 len, dist; - - if (b & 0x40) - { - len = (UInt32)b - 0x40 + 4; - Byte b2; - if (!m_InStream.ReadByte(b2)) - return S_FALSE; - dist = ((UInt32)b1 << 8) + b2; - } - else - { - len = ((UInt32)b >> 2) + 3; - dist = (((UInt32)b & 3) << 8) + b1; - } - - if (/* dist >= pos || */ len > rem) - return S_FALSE; - if (!m_OutWindowStream.CopyBlock(dist, len)) - return S_FALSE; - pos += len; - } - if (*inSize != m_InStream.GetProcessedSize()) - return S_FALSE; - coderReleaser.NeedFlush = false; - return m_OutWindowStream.Flush(); - - } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - - -struct CDecoders -{ - CMyComPtr2 zlib; - CMyComPtr2 bzip2; - CMyComPtr2 lzfse; - CMyUniquePtr xz; - CMyUniquePtr adc; - - HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const CBlock &block, const UInt64 *unpSize, ICompressProgressInfo *progress); -}; - -HRESULT CDecoders::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const CBlock &block, const UInt64 *unpSize, ICompressProgressInfo *progress) -{ - HRESULT hres; - UInt64 processed; - switch (block.Type) - { - case METHOD_ADC: - adc.Create_if_Empty(); - return adc->Code(inStream, outStream, &block.PackSize, unpSize, progress); - case METHOD_LZFSE: - lzfse.Create_if_Empty(); - return lzfse.Interface()->Code(inStream, outStream, &block.PackSize, unpSize, progress); - case METHOD_ZLIB: - zlib.Create_if_Empty(); - hres = zlib.Interface()->Code(inStream, outStream, NULL, unpSize, progress); - processed = zlib->GetInputProcessedSize(); - break; - case METHOD_BZIP2: - bzip2.Create_if_Empty(); - hres = bzip2.Interface()->Code(inStream, outStream, NULL, unpSize, progress); - processed = bzip2->GetInputProcessedSize(); - break; - case METHOD_XZ: - xz.Create_if_Empty(); - hres = xz->Decode(inStream, outStream, unpSize, true, progress); - processed = xz->Stat.InSize; - break; - default: - return E_NOTIMPL; - } - if (hres == S_OK && processed != block.PackSize) - hres = S_FALSE; - return hres; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _files.Size() -#ifdef DMG_SHOW_RAW - + _extras.Size() -#endif - ; - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; -#ifdef DMG_SHOW_RAW - if (index >= _files.Size()) - totalSize += _extras[index - _files.Size()].Data.Size(); - else -#endif - totalSize += _files[index].Size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - const size_t kZeroBufSize = 1 << 14; - CAlignedBuffer1 zeroBuf(kZeroBufSize); - memset(zeroBuf, 0, kZeroBufSize); - - CDecoders decoders; - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create inStream; - inStream->SetStream(_inStream); - - UInt64 total_PackSize = 0; - UInt64 total_UnpackSize = 0; - UInt64 cur_PackSize = 0; - UInt64 cur_UnpackSize = 0; - - for (i = 0;; i++, - total_PackSize += cur_PackSize, - total_UnpackSize += cur_UnpackSize) - { - lps->InSize = total_PackSize; - lps->OutSize = total_UnpackSize; - cur_PackSize = 0; - cur_UnpackSize = 0; - RINOK(lps->SetCur()) - if (i >= numItems) - return S_OK; - - Int32 opRes = NExtract::NOperationResult::kOK; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - -#ifdef DMG_SHOW_RAW - if (index >= _files.Size()) - { - const CByteBuffer &buf = _extras[index - _files.Size()].Data; - if (realOutStream) - RINOK(WriteStream(realOutStream, buf, buf.Size())) - cur_PackSize = cur_UnpackSize = buf.Size(); - } - else -#endif - { - const CFile &item = _files[index]; - cur_PackSize = item.PackSize; - cur_UnpackSize = item.Size; - - if (!item.IsCorrect) - opRes = NExtract::NOperationResult::kHeadersError; - else - { - CMyComPtr2_Create outCrcStream; - outCrcStream->SetStream(realOutStream); - // realOutStream.Release(); - const bool needCrc = item.Checksum.IsCrc32(); - outCrcStream->Init(needCrc); - - CMyComPtr2_Create outStream; - outStream->SetStream(outCrcStream); - - UInt64 unpPos = 0; - UInt64 packPos = 0; - - FOR_VECTOR (blockIndex, item.Blocks) - { - lps->InSize = total_PackSize + packPos; - lps->OutSize = total_UnpackSize + unpPos; - RINOK(lps->SetCur()) - - const CBlock &block = item.Blocks[blockIndex]; - // if (!block.ThereAreDataInBlock()) continue; - - packPos += block.PackSize; - if (block.UnpPos != unpPos) - { - opRes = NExtract::NOperationResult::kHeadersError; - break; - } - - RINOK(InStream_SeekSet(_inStream, _startPos + _dataForkPair.Offset + item.StartPackPos + block.PackPos)) - inStream->Init(block.PackSize); - - const UInt64 unpSize = item.GetUnpackSize_of_Block(blockIndex); - - outStream->Init(unpSize); - HRESULT res = S_OK; - - outCrcStream->EnableCalc(needCrc && block.NeedCrc()); - - if (block.IsZeroMethod()) - { - if (block.PackSize != 0) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - else if (block.Type == METHOD_COPY) - { - if (unpSize != block.PackSize) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - res = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); - } - else - res = decoders.Code(inStream, outStream, block, &unpSize, lps); - - if (res != S_OK) - { - if (res != S_FALSE) - { - if (res != E_NOTIMPL) - return res; - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - if (opRes == NExtract::NOperationResult::kOK) - opRes = NExtract::NOperationResult::kDataError; - } - - unpPos += unpSize; - - if (!outStream->IsFinishedOK()) - { - if (!block.IsZeroMethod() && opRes == NExtract::NOperationResult::kOK) - opRes = NExtract::NOperationResult::kDataError; - - for (unsigned k = 0;;) - { - const UInt64 rem = outStream->GetRem(); - if (rem == 0) - break; - size_t size = kZeroBufSize; - if (size > rem) - size = (size_t)rem; - RINOK(WriteStream(outStream, zeroBuf, size)) - k++; - if ((k & 0xfff) == 0) - { - lps->OutSize = total_UnpackSize + unpPos - outStream->GetRem(); - RINOK(lps->SetCur()) - } - } - } - } - if (needCrc && opRes == NExtract::NOperationResult::kOK) - { - if (outCrcStream->GetCRC() != item.Checksum.GetCrc32()) - opRes = NExtract::NOperationResult::kCRCError; - } - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - - COM_TRY_END -} - - - - -struct CChunk -{ - int BlockIndex; - UInt64 AccessMark; - Byte *Buf; - size_t BufSize; - - void Free() - { - z7_AlignedFree(Buf); - Buf = NULL; - BufSize = 0; - } - void Alloc(size_t size) - { - Buf = (Byte *)z7_AlignedAlloc(size); - } -}; - - -Z7_CLASS_IMP_IInStream( - CInStream -) - bool _errorMode; - UInt64 _virtPos; - int _latestChunk; - int _latestBlock; - UInt64 _accessMark; - UInt64 _chunks_TotalSize; - CRecordVector _chunks; - -public: - CMyComPtr Stream; - const CFile *File; - UInt64 Size; -private: - UInt64 _startPos; - - ~CInStream(); - CMyComPtr2 outStream; - CMyComPtr2 inStream; - CDecoders decoders; -public: - - // HRESULT - void Init(UInt64 startPos) - { - _errorMode = false; - _startPos = startPos; - _virtPos = 0; - _latestChunk = -1; - _latestBlock = -1; - _accessMark = 0; - _chunks_TotalSize = 0; - - inStream.Create_if_Empty(); - inStream->SetStream(Stream); - - outStream.Create_if_Empty(); - // return S_OK; - } -}; - - -CInStream::~CInStream() -{ - unsigned i = _chunks.Size(); - while (i) - _chunks[--i].Free(); -} - -static unsigned FindBlock(const CRecordVector &blocks, UInt64 pos) -{ - unsigned left = 0, right = blocks.Size(); - for (;;) - { - const unsigned mid = (left + right) / 2; - if (mid == left) - return left; - if (pos < blocks[mid].UnpPos) - right = mid; - else - left = mid; - } -} - -Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - // COM_TRY_BEGIN - try { - - if (_errorMode) - return E_OUTOFMEMORY; - - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_virtPos >= Size) - return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL; - { - const UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - - if (_latestBlock >= 0) - { - const CBlock &block = File->Blocks[(unsigned)_latestBlock]; - if (_virtPos < block.UnpPos || - _virtPos - block.UnpPos >= File->GetUnpackSize_of_Block((unsigned)_latestBlock)) - _latestBlock = -1; - } - - if (_latestBlock < 0) - { - _latestChunk = -1; - const unsigned blockIndex = FindBlock(File->Blocks, _virtPos); - const CBlock &block = File->Blocks[blockIndex]; - const UInt64 unpSize = File->GetUnpackSize_of_Block(blockIndex); - - if (block.NeedAllocateBuffer() - && unpSize <= k_Chunk_Size_MAX) - { - unsigned i = 0; - { - unsigned numChunks = _chunks.Size(); - if (numChunks) - { - const CChunk *chunk = _chunks.ConstData(); - do - { - if (chunk->BlockIndex == (int)blockIndex) - break; - chunk++; - } - while (--numChunks); - i = _chunks.Size() - numChunks; - } - } - if (i != _chunks.Size()) - _latestChunk = (int)i; - else - { - unsigned chunkIndex; - for (;;) - { - if (_chunks.IsEmpty() || - (_chunks.Size() < k_NumChunks_MAX - && _chunks_TotalSize + unpSize <= k_Chunks_TotalSize_MAX)) - { - CChunk chunk; - chunk.Buf = NULL; - chunk.BufSize = 0; - chunk.BlockIndex = -1; - chunk.AccessMark = 0; - chunkIndex = _chunks.Add(chunk); - break; - } - chunkIndex = 0; - if (_chunks.Size() == 1) - break; - { - const CChunk *chunks = _chunks.ConstData(); - UInt64 accessMark_min = chunks[chunkIndex].AccessMark; - const unsigned numChunks = _chunks.Size(); - for (i = 1; i < numChunks; i++) - { - if (chunks[i].AccessMark < accessMark_min) - { - chunkIndex = i; - accessMark_min = chunks[i].AccessMark; - } - } - } - { - CChunk &chunk = _chunks[chunkIndex]; - const UInt64 newTotalSize = _chunks_TotalSize - chunk.BufSize; - if (newTotalSize + unpSize <= k_Chunks_TotalSize_MAX) - break; - _chunks_TotalSize = newTotalSize; - chunk.Free(); - } - // we have called chunk.Free() before, because - // _chunks.Delete() doesn't call chunk.Free(). - _chunks.Delete(chunkIndex); - PRF(printf("\n++num_chunks=%u, _chunks_TotalSize = %u\n", (unsigned)_chunks.Size(), (unsigned)_chunks_TotalSize);) - } - - CChunk &chunk = _chunks[chunkIndex]; - chunk.BlockIndex = -1; - chunk.AccessMark = 0; - - if (chunk.BufSize < unpSize) - { - _chunks_TotalSize -= chunk.BufSize; - chunk.Free(); - // if (unpSize > k_Chunk_Size_MAX) return E_FAIL; - chunk.Alloc((size_t)unpSize); - if (!chunk.Buf) - return E_OUTOFMEMORY; - chunk.BufSize = (size_t)unpSize; - _chunks_TotalSize += chunk.BufSize; - } - - RINOK(InStream_SeekSet(Stream, _startPos + File->StartPackPos + block.PackPos)) - - inStream->Init(block.PackSize); -#ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS - if (block.Type == METHOD_COPY) - { - if (block.PackSize != unpSize) - return E_FAIL; - RINOK(ReadStream_FAIL(inStream, chunk.Buf, (size_t)unpSize)) - } - else -#endif - { - outStream->Init(chunk.Buf, (size_t)unpSize); - RINOK(decoders.Code(inStream, outStream, block, &unpSize, NULL)) - if (outStream->GetPos() != unpSize) - return E_FAIL; - } - chunk.BlockIndex = (int)blockIndex; - _latestChunk = (int)chunkIndex; - } - - _chunks[_latestChunk].AccessMark = _accessMark++; - } - - _latestBlock = (int)blockIndex; - } - - const CBlock &block = File->Blocks[(unsigned)_latestBlock]; - const UInt64 offset = _virtPos - block.UnpPos; - { - const UInt64 rem = File->GetUnpackSize_of_Block((unsigned)_latestBlock) - offset; - if (size > rem) - size = (UInt32)rem; - if (size == 0) // it's unexpected case. but we check it. - return S_OK; - } - HRESULT res = S_OK; - - if (block.IsZeroMethod()) - memset(data, 0, size); - else if (_latestChunk >= 0) - memcpy(data, _chunks[_latestChunk].Buf + (size_t)offset, size); - else - { - if (block.Type != METHOD_COPY) - return E_FAIL; - RINOK(InStream_SeekSet(Stream, _startPos + File->StartPackPos + block.PackPos + offset)) - res = Stream->Read(data, size, &size); - } - - _virtPos += size; - if (processedSize) - *processedSize = size; - return res; - // COM_TRY_END - } - catch(...) - { - _errorMode = true; - return E_OUTOFMEMORY; - } -} - - -Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - -#ifdef DMG_SHOW_RAW - if (index >= _files.Size()) - return S_FALSE; -#endif - - CMyComPtr2 spec; - spec.Create_if_Empty(); - spec->File = &_files[index]; - const CFile &file = *spec->File; - - if (!file.IsCorrect) - return S_FALSE; - - FOR_VECTOR (i, file.Blocks) - { - const CBlock &block = file.Blocks[i]; - if (!block.NeedAllocateBuffer()) - continue; - - switch (block.Type) - { -#ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS - case METHOD_COPY: - break; -#endif - case METHOD_ADC: - case METHOD_ZLIB: - case METHOD_BZIP2: - case METHOD_LZFSE: - case METHOD_XZ: - // case METHOD_END: - if (file.GetUnpackSize_of_Block(i) > k_Chunk_Size_MAX) - return S_FALSE; - break; - default: - return S_FALSE; - } - } - - spec->Stream = _inStream; - spec->Size = spec->File->Size; - // RINOK( - spec->Init(_startPos + _dataForkPair.Offset); - *stream = spec.Detach(); - return S_OK; - - COM_TRY_END -} - -REGISTER_ARC_I( - "Dmg", "dmg", NULL, 0xE4, - k_Signature, - 0, - NArcInfoFlags::kBackwardOpen | - NArcInfoFlags::kUseGlobalOffset, - NULL) - -}} +// DmgHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/AutoPtr.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer2.h" +#include "../../Common/MyXml.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/BZip2Decoder.h" +#include "../Compress/CopyCoder.h" +#include "../Compress/LzfseDecoder.h" +#include "../Compress/XzDecoder.h" +#include "../Compress/ZlibDecoder.h" + +#include "Common/OutStreamWithCRC.h" + +// #define DMG_SHOW_RAW + +// #define SHOW_DEBUG_INFO + +/* for debug only: we can use block cache also for METHOD_COPY blocks. + It can reduce the number of Stream->Read() requests. + But it can increase memory usage. + Note: METHOD_COPY blocks are not fused usually. + But if METHOD_COPY blocks is fused in some dmg example, + block size can exceed k_Chunk_Size_MAX. + So we don't use cache for METHOD_COPY block, if (block_size > k_Chunk_Size_MAX) +*/ +// for debug only: +// #define Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +#define Get32a(p) GetBe32a(p) +#define Get64a(p) GetBe64a(p) + +Byte *Base64ToBin(Byte *dest, const char *src); + +namespace NArchive { +namespace NDmg { + +// allocation limits for compressed blocks for GetStream() interface: +static const unsigned k_NumChunks_MAX = 128; +static const size_t k_Chunk_Size_MAX = (size_t)1 << 28; +// 256 MB cache for 32-bit: +// 4 GB cache for 64-bit: +static const size_t k_Chunks_TotalSize_MAX = (size_t)1 << (sizeof(size_t) + 24); + +// 2 GB limit for 32-bit: +// 4 GB limit for 64-bit: +// that limit can be increased for 64-bit mode, if there are such dmg files +static const size_t k_XmlSize_MAX = + ((size_t)1 << (sizeof(size_t) / 4 + 30)) - 256; + +static const UInt32 METHOD_ZERO_0 = 0; // sparse +static const UInt32 METHOD_COPY = 1; +static const UInt32 METHOD_ZERO_2 = 2; // sparse : without file CRC calculation +static const UInt32 METHOD_ADC = 0x80000004; +static const UInt32 METHOD_ZLIB = 0x80000005; +static const UInt32 METHOD_BZIP2 = 0x80000006; +static const UInt32 METHOD_LZFSE = 0x80000007; +static const UInt32 METHOD_XZ = 0x80000008; +static const UInt32 METHOD_COMMENT = 0x7FFFFFFE; // is used to comment "+beg" and "+end" in extra field. +static const UInt32 METHOD_END = 0xFFFFFFFF; + + +struct CBlock +{ + UInt32 Type; + UInt64 UnpPos; + // UInt64 UnpSize; + UInt64 PackPos; + UInt64 PackSize; + + bool NeedCrc() const { return Type != METHOD_ZERO_2; } + bool IsZeroMethod() const + { + return (Type & ~(UInt32)METHOD_ZERO_2) == 0; + // return Type == METHOD_ZERO_0 || Type == METHOD_ZERO_2; + } + + bool IsClusteredMethod() const + { + // most of dmg files have non-fused COPY_METHOD blocks. + // so we don't exclude COPY_METHOD blocks when we try to detect size of cluster. + return !IsZeroMethod(); // include COPY_METHOD blocks. + // Type > METHOD_ZERO_2; // for debug: exclude COPY_METHOD blocks. + } + + bool NeedAllocateBuffer() const + { + return +#ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS + !IsZeroMethod(); +#else + Type > METHOD_ZERO_2; + // !IsZeroMethod() && Type != METHOD_COPY; +#endif + } + // we don't store non-data blocks now + // bool ThereAreDataInBlock() const { return Type != METHOD_COMMENT && Type != METHOD_END; } +}; + +static const UInt32 kCheckSumType_CRC = 2; +static const unsigned kChecksumSize_Max = 0x80; + +struct CChecksum +{ + UInt32 Type; + UInt32 NumBits; + Byte Data[kChecksumSize_Max]; + + bool IsCrc32() const { return Type == kCheckSumType_CRC && NumBits == 32; } + UInt32 GetCrc32() const { return Get32(Data); } + void Parse(const Byte *p); + + void PrintType(AString &s) const; + void Print(AString &s) const; + void Print_with_Name(AString &s) const; + void AddToComment(AString &s, const char *name) const; +}; + +void CChecksum::Parse(const Byte *p) +{ + Type = Get32(p); + NumBits = Get32(p + 4); + memcpy(Data, p + 8, kChecksumSize_Max); +} + + +void CChecksum::PrintType(AString &s) const +{ + if (NumBits == 0) + return; + if (IsCrc32()) + s += "CRC"; + else + { + s += "Checksum"; + s.Add_UInt32(Type); + s.Add_Minus(); + s.Add_UInt32(NumBits); + } +} + +void CChecksum::Print(AString &s) const +{ + if (NumBits == 0) + return; + char temp[kChecksumSize_Max * 2 + 2]; + /* + if (IsCrc32()) + ConvertUInt32ToHex8Digits(GetCrc32(), temp); + else + */ + { + UInt32 numBits = kChecksumSize_Max * 8; + if (numBits > NumBits) + numBits = NumBits; + const unsigned numBytes = (numBits + 7) >> 3; + if (numBytes <= 8) + ConvertDataToHex_Upper(temp, Data, numBytes); + else + ConvertDataToHex_Lower(temp, Data, numBytes); + } + s += temp; +} + +void CChecksum::Print_with_Name(AString &s) const +{ + if (NumBits == 0) + return; + PrintType(s); + s += ": "; + Print(s); +} + +static void AddToComment_Prop(AString &s, const char *name, const char *val) +{ + s += name; + s += ": "; + s += val; + s.Add_LF(); +} + +void CChecksum::AddToComment(AString &s, const char *name) const +{ + AString s2; + Print_with_Name(s2); + if (!s2.IsEmpty()) + AddToComment_Prop(s, name, s2); +} + + +struct CFile +{ + UInt64 Size; + CRecordVector Blocks; + UInt64 PackSize; + UInt64 StartPackPos; + UInt64 BlockSize_MAX; + UInt64 StartUnpackSector; // unpack sector position of this file from all files + UInt64 NumUnpackSectors; + Int32 Descriptor; + bool IsCorrect; + bool FullFileChecksum; + AString Name; + // AString Id; + CChecksum Checksum; + + UInt64 GetUnpackSize_of_Block(unsigned blockIndex) const + { + return (blockIndex == Blocks.Size() - 1 ? + Size : Blocks[blockIndex + 1].UnpPos) - Blocks[blockIndex].UnpPos; + } + + CFile(): + Size(0), + PackSize(0), + StartPackPos(0), + BlockSize_MAX(0), + StartUnpackSector(0), + NumUnpackSectors(0), + Descriptor(0), + IsCorrect(false), + FullFileChecksum(false) + { + Checksum.Type = 0; + Checksum.NumBits = 0; + } + HRESULT Parse(const Byte *p, UInt32 size); +}; + +#ifdef DMG_SHOW_RAW +struct CExtraFile +{ + CByteBuffer Data; + AString Name; +}; +#endif + + +static void AddToComment_UInt64(AString &s, UInt64 v, const char *name) +{ + s += name; + s += ": "; + s.Add_UInt64(v); + s.Add_LF(); +} + +struct CForkPair +{ + UInt64 Offset; + UInt64 Len; + + // (p) is aligned for 8-bytes + void Parse(const Byte *p) + { + Offset = Get64a(p); + Len = Get64a(p + 8); + } + + bool GetEndPos(UInt64 &endPos) + { + endPos = Offset + Len; + return endPos >= Offset; + } + + bool UpdateTop(UInt64 limit, UInt64 &top) + { + if (Offset > limit || Len > limit - Offset) + return false; + const UInt64 top2 = Offset + Len; + if (top <= top2) + top = top2; + return true; + } + + void Print(AString &s, const char *name) const; +}; + +void CForkPair::Print(AString &s, const char *name) const +{ + if (Offset != 0 || Len != 0) + { + s += name; s.Add_Minus(); AddToComment_UInt64(s, Offset, "offset"); + s += name; s.Add_Minus(); AddToComment_UInt64(s, Len, "length"); + } +} + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + bool _masterCrcError; + bool _headersError; + bool _dataForkError; + bool _rsrcMode_wasUsed; + + CMyComPtr _inStream; + CObjectVector _files; + + // UInt32 _dataStartOffset; + UInt64 _startPos; + UInt64 _phySize; + + AString _name; + + CForkPair _dataForkPair; + CForkPair rsrcPair, xmlPair, blobPair; + + // UInt64 _runningDataForkOffset; + // UInt32 _segmentNumber; + // UInt32 _segmentCount; + UInt64 _numSectors; // total unpacked number of sectors + Byte _segmentGUID[16]; + + CChecksum _dataForkChecksum; + CChecksum _masterChecksum; + +#ifdef DMG_SHOW_RAW + CObjectVector _extras; +#endif + + HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf); + bool ParseBlob(const CByteBuffer &data); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback); + HRESULT Extract(IInStream *stream); +}; + + +struct CMethods +{ + CRecordVector Types; + + void Update(const CFile &file); + void AddToString(AString &s) const; +}; + +void CMethods::Update(const CFile &file) +{ + FOR_VECTOR (i, file.Blocks) + { + if (Types.Size() >= (1 << 8)) + break; + Types.AddToUniqueSorted(file.Blocks[i].Type); + } +} + +void CMethods::AddToString(AString &res) const +{ + FOR_VECTOR (i, Types) + { + const UInt32 type = Types[i]; + /* + if (type == METHOD_COMMENT || type == METHOD_END) + continue; + */ + char buf[16]; + const char *s; + switch (type) + { + // case METHOD_COMMENT: s = "Comment"; break; + case METHOD_ZERO_0: s = "Zero0"; break; + case METHOD_ZERO_2: s = "Zero2"; break; + case METHOD_COPY: s = "Copy"; break; + case METHOD_ADC: s = "ADC"; break; + case METHOD_ZLIB: s = "ZLIB"; break; + case METHOD_BZIP2: s = "BZip2"; break; + case METHOD_LZFSE: s = "LZFSE"; break; + case METHOD_XZ: s = "XZ"; break; + default: ConvertUInt32ToHex(type, buf); s = buf; + } + res.Add_OptSpaced(s); + } +} + + + +struct CAppleName +{ + bool IsFs; + const char *Ext; + const char *AppleName; +}; + +static const CAppleName k_Names[] = +{ + { true, "hfs", "Apple_HFS" }, + { true, "hfsx", "Apple_HFSX" }, + { true, "ufs", "Apple_UFS" }, + { true, "apfs", "Apple_APFS" }, + { true, "iso", "Apple_ISO" }, + + // efi_sys partition is FAT32, but it's not main file. So we use (IsFs = false) + { false, "efi_sys", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" }, + + { false, "free", "Apple_Free" }, + { false, "ddm", "DDM" }, + { false, NULL, "Apple_partition_map" }, + { false, NULL, " GPT " }, + /* " GPT " is substring of full name entry in dmg that contains + some small metadata GPT entry. It's not real FS entry: + "Primary GPT Header", + "Primary GPT Table" + "Backup GPT Header", + "Backup GPT Table", + */ + { false, NULL, "MBR" }, + { false, NULL, "Driver" }, + { false, NULL, "Patches" } +}; + +static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names); + +const char *Find_Apple_FS_Ext(const AString &name); +const char *Find_Apple_FS_Ext(const AString &name) +{ + for (unsigned i = 0; i < kNumAppleNames; i++) + { + const CAppleName &a = k_Names[i]; + if (a.Ext) + if (name == a.AppleName) + return a.Ext; + } + return NULL; +} + + +bool Is_Apple_FS_Or_Unknown(const AString &name); +bool Is_Apple_FS_Or_Unknown(const AString &name) +{ + for (unsigned i = 0; i < kNumAppleNames; i++) + { + const CAppleName &a = k_Names[i]; + // if (name.Find(a.AppleName) >= 0) + if (strstr(name, a.AppleName)) + return a.IsFs; + } + return true; +} + + + +// define it for debug only: +// #define Z7_DMG_SINGLE_FILE_MODE + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidComment, + kpidMethod, + kpidNumBlocks, + kpidClusterSize, + kpidChecksum, + kpidCRC, + kpidId + // kpidOffset +#ifdef Z7_DMG_SINGLE_FILE_MODE + , kpidPosition +#endif +}; + +IMP_IInArchive_Props + +static const Byte kArcProps[] = +{ + kpidMethod, + kpidNumBlocks, + kpidClusterSize, + kpidComment +}; + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidMethod: + { + CMethods m; + CRecordVector ChecksumTypes; + { + FOR_VECTOR (i, _files) + { + const CFile &file = _files[i]; + m.Update(file); + if (ChecksumTypes.Size() < (1 << 8)) + ChecksumTypes.AddToUniqueSorted(file.Checksum.Type); + } + } + AString s; + m.AddToString(s); + + FOR_VECTOR (i, ChecksumTypes) + { + const UInt32 type = ChecksumTypes[i]; + switch (type) + { + case kCheckSumType_CRC: + s.Add_OptSpaced("CRC"); + break; + default: + s.Add_OptSpaced("Checksum"); + s.Add_UInt32(type); + } + } + + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidNumBlocks: + { + UInt64 numBlocks = 0; + FOR_VECTOR (i, _files) + numBlocks += _files[i].Blocks.Size(); + prop = numBlocks; + break; + } + case kpidClusterSize: + { + UInt64 blockSize_MAX = 0; + FOR_VECTOR (i, _files) + { + const UInt64 a = _files[i].BlockSize_MAX; + if (blockSize_MAX < a) + blockSize_MAX = a; + } + prop = blockSize_MAX; + break; + } + case kpidMainSubfile: + { + int mainIndex = -1; + FOR_VECTOR (i, _files) + { + if (Is_Apple_FS_Or_Unknown(_files[i].Name)) + { + if (mainIndex != -1) + { + mainIndex = -1; + break; + } + mainIndex = (int)i; + } + } + if (mainIndex != -1) + prop = (UInt32)(Int32)mainIndex; + break; + } + case kpidWarning: + if (_masterCrcError) + prop = "Master CRC error"; + break; + + case kpidWarningFlags: + { + UInt32 v = 0; + if (_headersError) v |= kpv_ErrorFlags_HeadersError; + if (_dataForkError) v |= kpv_ErrorFlags_CrcError; + if (v != 0) + prop = v; + break; + } + + case kpidOffset: prop = _startPos; break; + case kpidPhySize: prop = _phySize; break; + + case kpidComment: + { + AString s; + if (!_name.IsEmpty()) + AddToComment_Prop(s, "Name", _name); + AddToComment_UInt64(s, _numSectors << 9, "unpack-size"); + { + char temp[sizeof(_segmentGUID) * 2 + 2]; + ConvertDataToHex_Lower(temp, _segmentGUID, sizeof(_segmentGUID)); + AddToComment_Prop(s, "ID", temp); + } + _masterChecksum.AddToComment(s, "master-checksum"); + _dataForkChecksum.AddToComment(s, "pack-checksum"); + { + /* + if (_dataStartOffset != 0) + AddToComment_UInt64(s, _dataStartOffset, "payload-start-offset"); + */ + // if (_dataForkPair.Offset != 0) + _dataForkPair.Print(s, "pack"); + rsrcPair.Print(s, "rsrc"); + xmlPair.Print(s, "xml"); + blobPair.Print(s, "blob"); + } + if (_rsrcMode_wasUsed) + s += "RSRC_MODE\n"; + if (!s.IsEmpty()) + prop = s; + } + break; + + case kpidName: + if (!_name.IsEmpty()) + prop = _name + ".dmg"; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +IMP_IInArchive_ArcProps + + + +static const UInt64 kSectorNumber_LIMIT = (UInt64)1 << (63 - 9); + +HRESULT CFile::Parse(const Byte *p, UInt32 size) +{ + // CFile was initialized to default values: 0 in size variables and (IsCorrect == false) + const unsigned kHeadSize = 0xCC; + if (size < kHeadSize) + return S_FALSE; + if (Get32(p) != 0x6D697368) // "mish" signature + return S_FALSE; + if (Get32(p + 4) != 1) // version + return S_FALSE; + + StartUnpackSector = Get64(p + 8); + NumUnpackSectors = Get64(p + 0x10); + StartPackPos = Get64(p + 0x18); + +#ifdef SHOW_DEBUG_INFO + /* the number of sectors that must be allocated. + == 0x208 for 256KB clusters + == 0x808 for 1MB clusters + == 0x1001 for 1MB clusters in some example + */ + const UInt32 decompressedBufRequested = Get32(p + 0x20); +#endif + + // Descriptor is file index. usually started from -1 + // in one dmg it was started from 0 + Descriptor = (Int32)Get32(p + 0x24); + // char Reserved1[24]; + + Checksum.Parse(p + 0x40); + PRF(printf("\n" " Checksum Type = %2u" + "\n StartUnpackSector = %8x" + "\n NumUnpackSectors = %8x" + "\n StartPos = %8x" + "\n decompressedBufRequested=%8x" + "\n blocksDescriptor=%8x" + , (unsigned)Checksum.Type + , (unsigned)StartUnpackSector + , (unsigned)NumUnpackSectors + , (unsigned)StartPackPos + , (unsigned)decompressedBufRequested + , (unsigned)Descriptor + );) + + const UInt32 numBlocks = Get32(p + 0xC8); + const unsigned kRecordSize = 40; + if ((UInt64)numBlocks * kRecordSize + kHeadSize != size) + return S_FALSE; + + Blocks.ClearAndReserve(numBlocks); + FullFileChecksum = true; + /* IsCorrect = false; by default + So we return S_OK, if we can ignore some error in headers. + */ + + p += kHeadSize; + UInt32 i; + + for (i = 0; i < numBlocks; i++, p += kRecordSize) + { + CBlock b; + b.Type = Get32(p); + { + const UInt64 a = Get64(p + 0x08); + if (a >= kSectorNumber_LIMIT) + return S_OK; + b.UnpPos = a << 9; + } + UInt64 unpSize; + { + const UInt64 a = Get64(p + 0x10); + if (a >= kSectorNumber_LIMIT) + return S_OK; + unpSize = a << 9; + } + const UInt64 newSize = b.UnpPos + unpSize; + if (newSize >= ((UInt64)1 << 63)) + return S_OK; + + b.PackPos = Get64(p + 0x18); + b.PackSize = Get64(p + 0x20); + // b.PackPos can be 0 for some types. So we don't check it + if (b.UnpPos != Size) + return S_OK; + + PRF(printf("\nType=%8x comment=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x", + (unsigned)b.Type, Get32(p + 4), (unsigned)b.UnpPos, (unsigned)unpSize, (unsigned)b.PackPos, (unsigned)b.PackSize)); + + if (b.Type == METHOD_COMMENT) + { + // some files contain 2 comment block records: + // record[0] : Type=METHOD_COMMENT, comment_field = "+beg" + // record[num-2] : Type=METHOD_COMMENT, comment_field = "+end" + // we skip these useless records. + continue; + } + if (b.Type == METHOD_END) + break; + + // we add only blocks that have non empty unpacked data: + if (unpSize != 0) + { + const UInt64 k_max_pos = (UInt64)1 << 63; + if (b.PackPos >= k_max_pos || + b.PackSize >= k_max_pos - b.PackPos) + return S_OK; + + /* we don't count non-ZERO blocks here, because + ZERO blocks in dmg files are not limited by some cluster size. + note: COPY blocks also sometimes are fused to larger blocks. + */ + if (b.IsClusteredMethod()) + if (BlockSize_MAX < unpSize) + BlockSize_MAX = unpSize; + + PackSize += b.PackSize; + if (!b.NeedCrc()) + FullFileChecksum = false; + Blocks.AddInReserved(b); + Size = newSize; + } + } + + PRF(printf("\n");) + + if (i != numBlocks - 1) + { + // return S_FALSE; + return S_OK; + } + + if ((Size >> 9) == NumUnpackSectors) + IsCorrect = true; + return S_OK; +} + + +static const CXmlItem *FindKeyPair(const CXmlItem &item, const char *key, const char *nextTag) +{ + for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++) + { + const CXmlItem &si = item.SubItems[i]; + if (si.IsTagged("key") && si.GetSubString() == key) + { + const CXmlItem *si_1 = &item.SubItems[i + 1]; + if (si_1->IsTagged(nextTag)) + return si_1; + } + } + return NULL; +} + +static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag) +{ + const CXmlItem *si_1 = FindKeyPair(item, key, nextTag); + if (si_1) + return si_1->GetSubStringPtr(); + return NULL; +} + +static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 }; + +static inline bool IsKoly(const Byte *p) +{ + return memcmp(p, k_Signature, Z7_ARRAY_SIZE(k_Signature)) == 0; + /* + if (Get32(p) != 0x6B6F6C79) // "koly" signature + return false; + if (Get32(p + 4) != 4) // version + return false; + if (Get32(p + 8) != HEADER_SIZE) + return false; + return true; + */ +} + + +HRESULT CHandler::ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf) +{ + size_t size = (size_t)pair.Len; + if (size != pair.Len) + return E_OUTOFMEMORY; + buf.Alloc(size); + RINOK(InStream_SeekSet(stream, _startPos + pair.Offset)) + return ReadStream_FALSE(stream, buf, size); +} + + + +bool CHandler::ParseBlob(const CByteBuffer &data) +{ + const unsigned kHeaderSize = 3 * 4; + if (data.Size() < kHeaderSize) + return false; + const Byte * const p = (const Byte *)data; + if (Get32a(p) != 0xfade0cc0) // CSMAGIC_EMBEDDED_SIGNATURE + return true; + const UInt32 size = Get32a(p + 4); + if (size != data.Size()) + return false; + const UInt32 num = Get32a(p + 8); + if (num > (size - kHeaderSize) / 8) + return false; + + const UInt32 limit = num * 8 + kHeaderSize; + for (size_t i = kHeaderSize; i < limit; i += 8) + { + // type == 0 == CSSLOT_CODEDIRECTORY for CSMAGIC_CODEDIRECTORY item + // UInt32 type = Get32(p + i); + const UInt32 offset = Get32a(p + i + 4); + if (offset < limit || offset > size - 8) + return false; + // offset is not aligned for 4 here !!! + const Byte * const p2 = p + offset; + const UInt32 magic = Get32(p2); + const UInt32 len = Get32(p2 + 4); + if (size - offset < len || len < 8) + return false; + +#ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "_blob_"; + extra.Data.CopyFrom(p2, len); +#endif + + if (magic == 0xfade0c02) // CSMAGIC_CODEDIRECTORY + { +#ifdef DMG_SHOW_RAW + extra.Name += "codedir"; +#endif + + if (len < 11 * 4) + return false; + const UInt32 idOffset = Get32(p2 + 5 * 4); + if (idOffset >= len) + return false; + UInt32 len2 = len - idOffset; + const UInt32 kNameLenMax = 1 << 8; + if (len2 > kNameLenMax) + len2 = kNameLenMax; + _name.SetFrom_CalcLen((const char *)(p2 + idOffset), len2); + /* + // #define kSecCodeSignatureHashSHA1 1 + // #define kSecCodeSignatureHashSHA256 2 + const UInt32 hashOffset = Get32(p2 + 4 * 4); + const UInt32 nSpecialSlots = Get32(p2 + 6 * 4); + const UInt32 nCodeSlots = Get32(p2 + 7 * 4); + const unsigned hashSize = p2[36]; + const unsigned hashType = p2[37]; + // const unsigned unused = p2[38]; + const unsigned pageSize = p2[39]; + */ + } +#ifdef DMG_SHOW_RAW + else if (magic == 0xfade0c01) extra.Name += "requirements"; + else if (magic == 0xfade0b01) extra.Name += "signed"; + else + { + char temp[16]; + ConvertUInt32ToHex8Digits(magic, temp); + extra.Name += temp; + } +#endif + } + + return true; +} + + + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) +{ + /* + - usual dmg contains Koly Header at the end: + - rare case old dmg contains Koly Header at the begin. + */ + + // _dataStartOffset = 0; + UInt64 fileSize; + RINOK(InStream_GetPos_GetSize(stream, _startPos, fileSize)) + + const unsigned HEADER_SIZE = 0x200; + UInt64 buf[HEADER_SIZE / sizeof(UInt64)]; + RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)) + + UInt64 headerPos; + bool front_Koly_Mode = false; + + /* + _dataForkChecksum.Offset == 0 for koly-at-the-end + _dataForkChecksum.Offset == 512 for koly-at-the-start + so we can use (_dataForkChecksum.Offset) to detect "koly-at-the-start" mode + */ + + if (IsKoly((const Byte *)(const void *)buf)) + { + // it can be normal koly-at-the-end or koly-at-the-start + headerPos = _startPos; + /* + if (_startPos <= (1 << 8)) + { + // we want to support front_Koly_Mode, even if there is + // some data before dmg file, like 128 bytes MacBin header + _dataStartOffset = HEADER_SIZE; + front_Koly_Mode = true; + } + */ + } + else + { + /* we try to open in backward mode only for first attempt + when (_startPos == 0) */ + if (_startPos != 0) + return S_FALSE; + headerPos = fileSize; + if (headerPos < HEADER_SIZE) + return S_FALSE; + headerPos -= HEADER_SIZE; + RINOK(InStream_SeekSet(stream, headerPos)) + RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE)) + if (!IsKoly((const Byte *)(const void *)buf)) + return S_FALSE; + } + + // UInt32 flags = Get32a((const Byte *)(const void *)buf + 12); + // _runningDataForkOffset = Get64a((const Byte *)(const void *)buf + 0x10); + _dataForkPair.Parse((const Byte *)(const void *)buf + 0x18); + rsrcPair.Parse((const Byte *)(const void *)buf + 0x28); + // _segmentNumber = Get32a(buf + 0x38); // 0 or 1 + // _segmentCount = Get32a(buf + 0x3C); // 0 (if not set) or 1 + memcpy(_segmentGUID, (const Byte *)(const void *)buf + 0x40, 16); + _dataForkChecksum.Parse((const Byte *)(const void *)buf + 0x50); + xmlPair.Parse((const Byte *)(const void *)buf + 0xD8); + // Byte resereved[] + blobPair.Parse((const Byte *)(const void *)buf + 0x128); + _masterChecksum.Parse((const Byte *)(const void *)buf + 0x160); + // UInt32 imageVariant = Get32a((const Byte *)(const void *)buf + 0x1E8); imageVariant = imageVariant; + _numSectors = Get64((const Byte *)(const void *)buf + 0x1EC); // it's not aligned for 8-bytes + // Byte resereved[12]; + + if (_dataForkPair.Offset == HEADER_SIZE + && headerPos + HEADER_SIZE < fileSize) + front_Koly_Mode = true; + + const UInt64 limit = front_Koly_Mode ? fileSize : headerPos; + UInt64 top = 0; + if (!_dataForkPair.UpdateTop(limit, top)) return S_FALSE; + if (!xmlPair.UpdateTop(limit, top)) return S_FALSE; + if (!rsrcPair.UpdateTop(limit, top)) return S_FALSE; + + /* Some old dmg files contain garbage data in blobPair field. + So we need to ignore such garbage case; + And we still need to detect offset of start of archive for "parser" mode. */ + const bool useBlob = blobPair.UpdateTop(limit, top); + + if (front_Koly_Mode) + _phySize = top; + else + { + _phySize = headerPos + HEADER_SIZE; + _startPos = 0; + if (top != headerPos) + { + /* + if expected absolute offset is not equal to real header offset, + 2 cases are possible: + - additional (unknown) headers + - archive with offset. + So we try to read XML with absolute offset to select from these two ways. + */ + CForkPair xmlPair2 = xmlPair; + const char *sz = " len) + xmlPair2.Len = len; + CByteBuffer buf2; + if (xmlPair2.Len < len + || ReadData(stream, xmlPair2, buf2) != S_OK + || memcmp(buf2, sz, len) != 0) + { + // if absolute offset is not OK, probably it's archive with offset + _startPos = headerPos - top; + _phySize = top + HEADER_SIZE; + } + } + } + + if (useBlob + && blobPair.Len != 0 + && blobPair.Len <= (1u << 24)) // we don't want parsing of big blobs + { +#ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "_blob.bin"; + CByteBuffer &blobBuf = extra.Data; +#else + CByteBuffer blobBuf; +#endif + RINOK(ReadData(stream, blobPair, blobBuf)) + if (!ParseBlob(blobBuf)) + _headersError = true; + } + + + UInt64 openTotal = 0; + UInt64 openCur = 0; + if (_dataForkChecksum.IsCrc32()) + openTotal = _dataForkPair.Len; + + const UInt32 RSRC_HEAD_SIZE = 0x100; + + /* we have 2 ways to read files and blocks metadata: + via Xml or via Rsrc. + But some images have no Rsrc fork. + Is it possible that there is no Xml? + Rsrc method will not work for big files. */ + // v23.02: we use xml mode by default + // if (rsrcPair.Len >= RSRC_HEAD_SIZE && rsrcPair.Len <= ((UInt32)1 << 24)) // for debug + if (xmlPair.Len == 0) + { + // We don't know the size of the field "offset" in Rsrc. + // We suppose that it uses 24 bits. So we use Rsrc, only if the rsrcPair.Len <= (1 << 24). + const bool canUseRsrc = (rsrcPair.Len >= RSRC_HEAD_SIZE && rsrcPair.Len <= ((UInt32)1 << 24)); + if (!canUseRsrc) + return S_FALSE; + + _rsrcMode_wasUsed = true; +#ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "rsrc.bin"; + CByteBuffer &rsrcBuf = extra.Data; +#else + CByteBuffer rsrcBuf; +#endif + + RINOK(ReadData(stream, rsrcPair, rsrcBuf)) + + const Byte *p = rsrcBuf; + const UInt32 headSize = Get32a(p + 0); + const UInt32 footerOffset = Get32a(p + 4); + const UInt32 mainDataSize = Get32a(p + 8); + const UInt32 footerSize = Get32a(p + 12); + if (headSize != RSRC_HEAD_SIZE + || footerOffset >= rsrcPair.Len + || mainDataSize >= rsrcPair.Len + || footerOffset < mainDataSize + || footerOffset != headSize + mainDataSize) + return S_FALSE; + + { + const UInt32 footerEnd = footerOffset + footerSize; + if (footerEnd != rsrcPair.Len) + { + // there is rare case dmg example, where there are 4 additional bytes + const UInt64 rem = rsrcPair.Len - footerOffset; + if (rem < footerSize + || rem - footerSize != 4 + || Get32(p + footerEnd) != 0) + return S_FALSE; + } + } + + if (footerSize < 0x1e) + return S_FALSE; + if (memcmp(p, p + footerOffset, 16) != 0) + return S_FALSE; + + p += footerOffset; + + if ((UInt32)Get16(p + 0x18) != 0x1c) + return S_FALSE; + const UInt32 namesOffset = Get16(p + 0x1a); + if (namesOffset > footerSize) + return S_FALSE; + + const UInt32 numItems = (UInt32)Get16(p + 0x1c) + 1; + if (numItems * 8 + 0x1e > namesOffset) + return S_FALSE; + + for (UInt32 i = 0; i < numItems; i++) + { + const Byte *p2 = p + 0x1e + (size_t)i * 8; + const UInt32 typeId = Get32(p2); + const UInt32 k_typeId_blkx = 0x626c6b78; // blkx +#ifndef DMG_SHOW_RAW + if (typeId != k_typeId_blkx) + continue; +#endif + const UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1; + const UInt32 offs = Get16(p2 + 6); + if (0x1c + offs + 12 * numFiles > namesOffset) + return S_FALSE; + + for (UInt32 k = 0; k < numFiles; k++) + { + const Byte *p3 = p + 0x1c + offs + k * 12; + // UInt32 id = Get16(p3); + const UInt32 namePos = Get16(p3 + 2); + // Byte attributes = p3[4]; // = 0x50 for blkx #define (ATTRIBUTE_HDIUTIL) + // we don't know how many bits we can use. So we use 24 bits only + UInt32 blockOffset = Get32(p3 + 4); + blockOffset &= ((UInt32)1 << 24) - 1; + // UInt32 unknown2 = Get32(p3 + 8); // ??? + if (blockOffset + 4 >= mainDataSize) + return S_FALSE; + const Byte *pBlock = rsrcBuf + headSize + blockOffset; + const UInt32 blockSize = Get32(pBlock); + if (mainDataSize - (blockOffset + 4) < blockSize) + return S_FALSE; + + AString name; + + if (namePos != 0xffff) + { + const UInt32 namesBlockSize = footerSize - namesOffset; + if (namePos >= namesBlockSize) + return S_FALSE; + const Byte *namePtr = p + namesOffset + namePos; + const UInt32 nameLen = *namePtr; + if (namesBlockSize - namePos <= nameLen) + return S_FALSE; + for (UInt32 r = 1; r <= nameLen; r++) + { + const Byte c = namePtr[r]; + if (c < 0x20 || c >= 0x80) + break; + name += (char)c; + } + } + + if (typeId == k_typeId_blkx) + { + CFile &file = _files.AddNew(); + file.Name = name; + RINOK(file.Parse(pBlock + 4, blockSize)) + if (!file.IsCorrect) + _headersError = true; + } + +#ifdef DMG_SHOW_RAW + { + AString name2; + name2.Add_UInt32(i); + name2 += '_'; + { + char temp[4 + 1] = { 0 }; + memcpy(temp, p2, 4); + name2 += temp; + } + name2.Trim(); + name2 += '_'; + name2.Add_UInt32(k); + if (!name.IsEmpty()) + { + name2 += '_'; + name2 += name; + } + CExtraFile &extra2 = _extras.AddNew(); + extra2.Name = name2; + extra2.Data.CopyFrom(pBlock + 4, blockSize); + } +#endif + } + } + } + else + { + if (xmlPair.Len > k_XmlSize_MAX) + return S_FALSE; + // if (!canUseXml) return S_FALSE; + const size_t size = (size_t)xmlPair.Len; + // if (size + 1 <= xmlPair.Len) return S_FALSE; // optional check + RINOK(InStream_SeekSet(stream, _startPos + xmlPair.Offset)) + CXml xml; + { + openTotal += size; + if (openArchiveCallback) + { + RINOK(openArchiveCallback->SetTotal(NULL, &openTotal)) + } + size_t pos = 0; + CAlignedBuffer1 xmlStr(size + 1); + for (;;) + { + const size_t k_OpenStep = 1 << 24; + const size_t cur = MyMin(k_OpenStep, size - pos); + RINOK(ReadStream_FALSE(stream, xmlStr + pos, cur)) + pos += cur; + openCur += cur; + if (pos == size) + break; + if (openArchiveCallback) + { + RINOK(openArchiveCallback->SetCompleted(NULL, &openCur)) + } + } + xmlStr[size] = 0; + // if (strlen((const char *)(const void *)(const Byte *)xmlStr) != size) return S_FALSE; + if (!xml.Parse((char *)(void *)(Byte *)xmlStr)) + return S_FALSE; + +#ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name = "a.xml"; + extra.Data.CopyFrom(xmlStr, size); +#endif + } + + if (xml.Root.Name != "plist") + return S_FALSE; + + const CXmlItem *dictItem = xml.Root.FindSubTag_GetPtr("dict"); + if (!dictItem) + return S_FALSE; + + const CXmlItem *rfDictItem = FindKeyPair(*dictItem, "resource-fork", "dict"); + if (!rfDictItem) + return S_FALSE; + + const CXmlItem *arrItem = FindKeyPair(*rfDictItem, "blkx", "array"); + if (!arrItem) + return S_FALSE; + + FOR_VECTOR (i, arrItem->SubItems) + { + const CXmlItem &item = arrItem->SubItems[i]; + if (!item.IsTagged("dict")) + continue; + + CByteBuffer rawBuf; + unsigned destLen = 0; + { + const AString *dataString = GetStringFromKeyPair(item, "Data", "data"); + if (!dataString) + return S_FALSE; + destLen = dataString->Len() / 4 * 3 + 4; + rawBuf.Alloc(destLen); + { + const Byte *endPtr = Base64ToBin(rawBuf, *dataString); + if (!endPtr) + return S_FALSE; + destLen = (unsigned)(endPtr - (const Byte *)rawBuf); + } + +#ifdef DMG_SHOW_RAW + CExtraFile &extra = _extras.AddNew(); + extra.Name.Add_UInt32(_files.Size()); + extra.Data.CopyFrom(rawBuf, destLen); +#endif + } + CFile &file = _files.AddNew(); + { + /* xml code removes front space for such string: + (Apple_Free : 3) + maybe we shoud fix xml code and return full string with space. + */ + const AString *name = GetStringFromKeyPair(item, "Name", "string"); + if (!name || name->IsEmpty()) + name = GetStringFromKeyPair(item, "CFName", "string"); + if (name) + file.Name = *name; + } + /* + { + const AString *s = GetStringFromKeyPair(item, "ID", "string"); + if (s) + file.Id = *s; + } + */ + RINOK(file.Parse(rawBuf, destLen)) + if (!file.IsCorrect) + _headersError = true; + } + } + + if (_masterChecksum.IsCrc32()) + { + UInt32 crc = CRC_INIT_VAL; + unsigned i; + for (i = 0; i < _files.Size(); i++) + { + const CChecksum &cs = _files[i].Checksum; + if ((cs.NumBits & 0x7) != 0) + break; + const UInt32 len = cs.NumBits >> 3; + if (len > kChecksumSize_Max) + break; + crc = CrcUpdate(crc, cs.Data, (size_t)len); + } + if (i == _files.Size()) + _masterCrcError = (CRC_GET_DIGEST(crc) != _masterChecksum.GetCrc32()); + } + + { + UInt64 sec = 0; + FOR_VECTOR (i, _files) + { + const CFile &file = _files[i]; + /* + if (file.Descriptor != (Int32)i - 1) + _headersError = true; + */ + if (file.StartUnpackSector != sec) + _headersError = true; + if (file.NumUnpackSectors >= kSectorNumber_LIMIT) + _headersError = true; + sec += file.NumUnpackSectors; + if (sec >= kSectorNumber_LIMIT) + _headersError = true; + } + if (sec != _numSectors) + _headersError = true; + } + + // data checksum calculation can be slow for big dmg file + if (_dataForkChecksum.IsCrc32()) + { + UInt64 endPos; + if (!_dataForkPair.GetEndPos(endPos) + || _dataForkPair.Offset >= ((UInt64)1 << 63)) + _headersError = true; + else + { + const UInt64 seekPos = _startPos + _dataForkPair.Offset; + if (seekPos > fileSize + || endPos > fileSize - _startPos) + { + _headersError = true; + // kpv_ErrorFlags_UnexpectedEnd + } + else + { + const size_t kBufSize = 1 << 15; + CAlignedBuffer1 buf2(kBufSize); + RINOK(InStream_SeekSet(stream, seekPos)) + if (openArchiveCallback) + { + RINOK(openArchiveCallback->SetTotal(NULL, &openTotal)) + } + UInt32 crc = CRC_INIT_VAL; + UInt64 pos = 0; + for (;;) + { + const UInt64 rem = _dataForkPair.Len - pos; + size_t cur = kBufSize; + if (cur > rem) + cur = (UInt32)rem; + if (cur == 0) + break; + RINOK(ReadStream_FALSE(stream, buf2, cur)) + crc = CrcUpdate(crc, buf2, cur); + pos += cur; + openCur += cur; + if ((pos & ((1 << 24) - 1)) == 0 && openArchiveCallback) + { + RINOK(openArchiveCallback->SetCompleted(NULL, &openCur)) + } + } + if (_dataForkChecksum.GetCrc32() != CRC_GET_DIGEST(crc)) + _dataForkError = true; + } + } + } + + return S_OK; +} + + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *openArchiveCallback)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream, openArchiveCallback)) + _inStream = stream; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _masterCrcError = false; + _headersError = false; + _dataForkError = false; + _rsrcMode_wasUsed = false; + _phySize = 0; + _startPos = 0; + _name.Empty(); + _inStream.Release(); + _files.Clear(); +#ifdef DMG_SHOW_RAW + _extras.Clear(); +#endif + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _files.Size() +#ifdef DMG_SHOW_RAW + + _extras.Size() +#endif + ; + return S_OK; +} + +#ifdef DMG_SHOW_RAW +#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR +#endif + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + +#ifdef DMG_SHOW_RAW + if (index >= _files.Size()) + { + const CExtraFile &extra = _extras[index - _files.Size()]; + switch (propID) + { + case kpidPath: + prop = (AString)RAW_PREFIX + extra.Name; + break; + case kpidSize: + case kpidPackSize: + prop = (UInt64)extra.Data.Size(); + break; + } + } + else +#endif + { + const CFile &item = _files[index]; + switch (propID) + { + case kpidSize: prop = item.Size; break; + case kpidPackSize: prop = item.PackSize; break; + case kpidCRC: + { + if (item.Checksum.IsCrc32() && item.FullFileChecksum) + prop = item.Checksum.GetCrc32(); + break; + } + case kpidChecksum: + { + AString s; + item.Checksum.Print(s); + if (!s.IsEmpty()) + prop = s; + break; + } + + /* + case kpidOffset: + { + prop = item.StartPackPos; + break; + } + */ + + case kpidNumBlocks: + prop = (UInt32)item.Blocks.Size(); + break; + case kpidClusterSize: + prop = item.BlockSize_MAX; + break; + + case kpidMethod: + { + AString s; + if (!item.IsCorrect) + s.Add_OptSpaced("CORRUPTED"); + CMethods m; + m.Update(item); + m.AddToString(s); + { + AString s2; + item.Checksum.PrintType(s2); + if (!s2.IsEmpty()) + s.Add_OptSpaced(s2); + } + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidPath: + { +#ifdef Z7_DMG_SINGLE_FILE_MODE + prop = "a.img"; +#else + UString name; + name.Add_UInt32(index); + unsigned num = 10; + unsigned numDigits; + for (numDigits = 1; num < _files.Size(); numDigits++) + num *= 10; + while (name.Len() < numDigits) + name.InsertAtFront(L'0'); + + AString subName; + int pos1 = item.Name.Find('('); + if (pos1 >= 0) + { + pos1++; + const int pos2 = item.Name.Find(')', pos1); + if (pos2 >= 0) + { + subName.SetFrom(item.Name.Ptr(pos1), pos2 - pos1); + pos1 = subName.Find(':'); + if (pos1 >= 0) + subName.DeleteFrom(pos1); + } + } + else + subName = item.Name; // new apfs dmg can be without braces + subName.Trim(); + if (!subName.IsEmpty()) + { + const char *ext = Find_Apple_FS_Ext(subName); + if (ext) + subName = ext; + UString name2; + ConvertUTF8ToUnicode(subName, name2); + name.Add_Dot(); + name += name2; + } + else + { + UString name2; + ConvertUTF8ToUnicode(item.Name, name2); + if (!name2.IsEmpty()) + name += "_"; + name += name2; + } + prop = name; +#endif + + break; + } + + case kpidComment: + { + UString name; + ConvertUTF8ToUnicode(item.Name, name); + prop = name; + break; + } + case kpidId: + { + prop.Set_Int32((Int32)item.Descriptor); + /* + if (!item.Id.IsEmpty()) + { + UString s; + ConvertUTF8ToUnicode(item.Id, s); + prop = s; + } + */ + break; + } +#ifdef Z7_DMG_SINGLE_FILE_MODE + case kpidPosition: + prop = item.StartUnpackSector << 9; + break; +#endif + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +class CAdcDecoder +{ + CLzOutWindow m_OutWindowStream; + CInBuffer m_InStream; + + class CCoderReleaser Z7_final + { + CAdcDecoder *m_Coder; + public: + bool NeedFlush; + CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {} + ~CCoderReleaser() + { + if (NeedFlush) + m_Coder->m_OutWindowStream.Flush(); + } + }; + friend class CCoderReleaser; + +public: + HRESULT Code(ISequentialInStream * const inStream, + ISequentialOutStream *outStream, + const UInt64 * const inSize, + const UInt64 * const outSize, + ICompressProgressInfo * const progress); +}; + + +HRESULT CAdcDecoder::Code(ISequentialInStream * const inStream, + ISequentialOutStream *outStream, + const UInt64 * const inSize, + const UInt64 * const outSizePtr, + ICompressProgressInfo * const progress) +{ + try { + + if (!m_OutWindowStream.Create(1 << 18)) // at least (1 << 16) is required here + return E_OUTOFMEMORY; + if (!m_InStream.Create(1 << 18)) + return E_OUTOFMEMORY; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(false); + m_InStream.SetStream(inStream); + m_InStream.Init(); + + CCoderReleaser coderReleaser(this); + + const UInt32 kStep = 1 << 22; + UInt64 nextLimit = kStep; + const UInt64 outSize = *outSizePtr; + UInt64 pos = 0; + /* match sequences and literal sequences do not cross 64KB range + in some dmg archive examples. But is it so for any Adc stream? */ + + while (pos < outSize) + { + if (pos >= nextLimit && progress) + { + nextLimit += kStep; + const UInt64 packSize = m_InStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)) + } + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + const UInt64 rem = outSize - pos; + if (b & 0x80) + { + unsigned num = (unsigned)b - 0x80 + 1; + if (num > rem) + return S_FALSE; + pos += num; + do + { + if (!m_InStream.ReadByte(b)) + return S_FALSE; + m_OutWindowStream.PutByte(b); + } + while (--num); + continue; + } + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + + UInt32 len, dist; + + if (b & 0x40) + { + len = (UInt32)b - 0x40 + 4; + Byte b2; + if (!m_InStream.ReadByte(b2)) + return S_FALSE; + dist = ((UInt32)b1 << 8) + b2; + } + else + { + len = ((UInt32)b >> 2) + 3; + dist = (((UInt32)b & 3) << 8) + b1; + } + + if (/* dist >= pos || */ len > rem) + return S_FALSE; + if (!m_OutWindowStream.CopyBlock(dist, len)) + return S_FALSE; + pos += len; + } + if (*inSize != m_InStream.GetProcessedSize()) + return S_FALSE; + coderReleaser.NeedFlush = false; + return m_OutWindowStream.Flush(); + + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + + +struct CDecoders +{ + CMyComPtr2 zlib; + CMyComPtr2 bzip2; + CMyComPtr2 lzfse; + CMyUniquePtr xz; + CMyUniquePtr adc; + + HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const CBlock &block, const UInt64 *unpSize, ICompressProgressInfo *progress); +}; + +HRESULT CDecoders::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const CBlock &block, const UInt64 *unpSize, ICompressProgressInfo *progress) +{ + HRESULT hres; + UInt64 processed; + switch (block.Type) + { + case METHOD_ADC: + adc.Create_if_Empty(); + return adc->Code(inStream, outStream, &block.PackSize, unpSize, progress); + case METHOD_LZFSE: + lzfse.Create_if_Empty(); + return lzfse.Interface()->Code(inStream, outStream, &block.PackSize, unpSize, progress); + case METHOD_ZLIB: + zlib.Create_if_Empty(); + hres = zlib.Interface()->Code(inStream, outStream, NULL, unpSize, progress); + processed = zlib->GetInputProcessedSize(); + break; + case METHOD_BZIP2: + bzip2.Create_if_Empty(); + hres = bzip2.Interface()->Code(inStream, outStream, NULL, unpSize, progress); + processed = bzip2->GetInputProcessedSize(); + break; + case METHOD_XZ: + xz.Create_if_Empty(); + hres = xz->Decode(inStream, outStream, unpSize, true, progress); + processed = xz->Stat.InSize; + break; + default: + return E_NOTIMPL; + } + if (hres == S_OK && processed != block.PackSize) + hres = S_FALSE; + return hres; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _files.Size() +#ifdef DMG_SHOW_RAW + + _extras.Size() +#endif + ; + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; +#ifdef DMG_SHOW_RAW + if (index >= _files.Size()) + totalSize += _extras[index - _files.Size()].Data.Size(); + else +#endif + totalSize += _files[index].Size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + const size_t kZeroBufSize = 1 << 14; + CAlignedBuffer1 zeroBuf(kZeroBufSize); + memset(zeroBuf, 0, kZeroBufSize); + + CDecoders decoders; + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_inStream); + + UInt64 total_PackSize = 0; + UInt64 total_UnpackSize = 0; + UInt64 cur_PackSize = 0; + UInt64 cur_UnpackSize = 0; + + for (i = 0;; i++, + total_PackSize += cur_PackSize, + total_UnpackSize += cur_UnpackSize) + { + lps->InSize = total_PackSize; + lps->OutSize = total_UnpackSize; + cur_PackSize = 0; + cur_UnpackSize = 0; + RINOK(lps->SetCur()) + if (i >= numItems) + return S_OK; + + Int32 opRes = NExtract::NOperationResult::kOK; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + +#ifdef DMG_SHOW_RAW + if (index >= _files.Size()) + { + const CByteBuffer &buf = _extras[index - _files.Size()].Data; + if (realOutStream) + RINOK(WriteStream(realOutStream, buf, buf.Size())) + cur_PackSize = cur_UnpackSize = buf.Size(); + } + else +#endif + { + const CFile &item = _files[index]; + cur_PackSize = item.PackSize; + cur_UnpackSize = item.Size; + + if (!item.IsCorrect) + opRes = NExtract::NOperationResult::kHeadersError; + else + { + CMyComPtr2_Create outCrcStream; + outCrcStream->SetStream(realOutStream); + // realOutStream.Release(); + const bool needCrc = item.Checksum.IsCrc32(); + outCrcStream->Init(needCrc); + + CMyComPtr2_Create outStream; + outStream->SetStream(outCrcStream); + + UInt64 unpPos = 0; + UInt64 packPos = 0; + + FOR_VECTOR (blockIndex, item.Blocks) + { + lps->InSize = total_PackSize + packPos; + lps->OutSize = total_UnpackSize + unpPos; + RINOK(lps->SetCur()) + + const CBlock &block = item.Blocks[blockIndex]; + // if (!block.ThereAreDataInBlock()) continue; + + packPos += block.PackSize; + if (block.UnpPos != unpPos) + { + opRes = NExtract::NOperationResult::kHeadersError; + break; + } + + RINOK(InStream_SeekSet(_inStream, _startPos + _dataForkPair.Offset + item.StartPackPos + block.PackPos)) + inStream->Init(block.PackSize); + + const UInt64 unpSize = item.GetUnpackSize_of_Block(blockIndex); + + outStream->Init(unpSize); + HRESULT res = S_OK; + + outCrcStream->EnableCalc(needCrc && block.NeedCrc()); + + if (block.IsZeroMethod()) + { + if (block.PackSize != 0) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else if (block.Type == METHOD_COPY) + { + if (unpSize != block.PackSize) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + res = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); + } + else + res = decoders.Code(inStream, outStream, block, &unpSize, lps); + + if (res != S_OK) + { + if (res != S_FALSE) + { + if (res != E_NOTIMPL) + return res; + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + if (opRes == NExtract::NOperationResult::kOK) + opRes = NExtract::NOperationResult::kDataError; + } + + unpPos += unpSize; + + if (!outStream->IsFinishedOK()) + { + if (!block.IsZeroMethod() && opRes == NExtract::NOperationResult::kOK) + opRes = NExtract::NOperationResult::kDataError; + + for (unsigned k = 0;;) + { + const UInt64 rem = outStream->GetRem(); + if (rem == 0) + break; + size_t size = kZeroBufSize; + if (size > rem) + size = (size_t)rem; + RINOK(WriteStream(outStream, zeroBuf, size)) + k++; + if ((k & 0xfff) == 0) + { + lps->OutSize = total_UnpackSize + unpPos - outStream->GetRem(); + RINOK(lps->SetCur()) + } + } + } + } + if (needCrc && opRes == NExtract::NOperationResult::kOK) + { + if (outCrcStream->GetCRC() != item.Checksum.GetCrc32()) + opRes = NExtract::NOperationResult::kCRCError; + } + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + + COM_TRY_END +} + + + + +struct CChunk +{ + int BlockIndex; + UInt64 AccessMark; + Byte *Buf; + size_t BufSize; + + void Free() + { + z7_AlignedFree(Buf); + Buf = NULL; + BufSize = 0; + } + void Alloc(size_t size) + { + Buf = (Byte *)z7_AlignedAlloc(size); + } +}; + + +Z7_CLASS_IMP_IInStream( + CInStream +) + bool _errorMode; + UInt64 _virtPos; + int _latestChunk; + int _latestBlock; + UInt64 _accessMark; + UInt64 _chunks_TotalSize; + CRecordVector _chunks; + +public: + CMyComPtr Stream; + const CFile *File; + UInt64 Size; +private: + UInt64 _startPos; + + ~CInStream(); + CMyComPtr2 outStream; + CMyComPtr2 inStream; + CDecoders decoders; +public: + + // HRESULT + void Init(UInt64 startPos) + { + _errorMode = false; + _startPos = startPos; + _virtPos = 0; + _latestChunk = -1; + _latestBlock = -1; + _accessMark = 0; + _chunks_TotalSize = 0; + + inStream.Create_if_Empty(); + inStream->SetStream(Stream); + + outStream.Create_if_Empty(); + // return S_OK; + } +}; + + +CInStream::~CInStream() +{ + unsigned i = _chunks.Size(); + while (i) + _chunks[--i].Free(); +} + +static unsigned FindBlock(const CRecordVector &blocks, UInt64 pos) +{ + unsigned left = 0, right = blocks.Size(); + for (;;) + { + const unsigned mid = (left + right) / 2; + if (mid == left) + return left; + if (pos < blocks[mid].UnpPos) + right = mid; + else + left = mid; + } +} + +Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + // COM_TRY_BEGIN + try { + + if (_errorMode) + return E_OUTOFMEMORY; + + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_virtPos >= Size) + return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL; + { + const UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + + if (_latestBlock >= 0) + { + const CBlock &block = File->Blocks[(unsigned)_latestBlock]; + if (_virtPos < block.UnpPos || + _virtPos - block.UnpPos >= File->GetUnpackSize_of_Block((unsigned)_latestBlock)) + _latestBlock = -1; + } + + if (_latestBlock < 0) + { + _latestChunk = -1; + const unsigned blockIndex = FindBlock(File->Blocks, _virtPos); + const CBlock &block = File->Blocks[blockIndex]; + const UInt64 unpSize = File->GetUnpackSize_of_Block(blockIndex); + + if (block.NeedAllocateBuffer() + && unpSize <= k_Chunk_Size_MAX) + { + unsigned i = 0; + { + unsigned numChunks = _chunks.Size(); + if (numChunks) + { + const CChunk *chunk = _chunks.ConstData(); + do + { + if (chunk->BlockIndex == (int)blockIndex) + break; + chunk++; + } + while (--numChunks); + i = _chunks.Size() - numChunks; + } + } + if (i != _chunks.Size()) + _latestChunk = (int)i; + else + { + unsigned chunkIndex; + for (;;) + { + if (_chunks.IsEmpty() || + (_chunks.Size() < k_NumChunks_MAX + && _chunks_TotalSize + unpSize <= k_Chunks_TotalSize_MAX)) + { + CChunk chunk; + chunk.Buf = NULL; + chunk.BufSize = 0; + chunk.BlockIndex = -1; + chunk.AccessMark = 0; + chunkIndex = _chunks.Add(chunk); + break; + } + chunkIndex = 0; + if (_chunks.Size() == 1) + break; + { + const CChunk *chunks = _chunks.ConstData(); + UInt64 accessMark_min = chunks[chunkIndex].AccessMark; + const unsigned numChunks = _chunks.Size(); + for (i = 1; i < numChunks; i++) + { + if (chunks[i].AccessMark < accessMark_min) + { + chunkIndex = i; + accessMark_min = chunks[i].AccessMark; + } + } + } + { + CChunk &chunk = _chunks[chunkIndex]; + const UInt64 newTotalSize = _chunks_TotalSize - chunk.BufSize; + if (newTotalSize + unpSize <= k_Chunks_TotalSize_MAX) + break; + _chunks_TotalSize = newTotalSize; + chunk.Free(); + } + // we have called chunk.Free() before, because + // _chunks.Delete() doesn't call chunk.Free(). + _chunks.Delete(chunkIndex); + PRF(printf("\n++num_chunks=%u, _chunks_TotalSize = %u\n", (unsigned)_chunks.Size(), (unsigned)_chunks_TotalSize);) + } + + CChunk &chunk = _chunks[chunkIndex]; + chunk.BlockIndex = -1; + chunk.AccessMark = 0; + + if (chunk.BufSize < unpSize) + { + _chunks_TotalSize -= chunk.BufSize; + chunk.Free(); + // if (unpSize > k_Chunk_Size_MAX) return E_FAIL; + chunk.Alloc((size_t)unpSize); + if (!chunk.Buf) + return E_OUTOFMEMORY; + chunk.BufSize = (size_t)unpSize; + _chunks_TotalSize += chunk.BufSize; + } + + RINOK(InStream_SeekSet(Stream, _startPos + File->StartPackPos + block.PackPos)) + + inStream->Init(block.PackSize); +#ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS + if (block.Type == METHOD_COPY) + { + if (block.PackSize != unpSize) + return E_FAIL; + RINOK(ReadStream_FAIL(inStream, chunk.Buf, (size_t)unpSize)) + } + else +#endif + { + outStream->Init(chunk.Buf, (size_t)unpSize); + RINOK(decoders.Code(inStream, outStream, block, &unpSize, NULL)) + if (outStream->GetPos() != unpSize) + return E_FAIL; + } + chunk.BlockIndex = (int)blockIndex; + _latestChunk = (int)chunkIndex; + } + + _chunks[_latestChunk].AccessMark = _accessMark++; + } + + _latestBlock = (int)blockIndex; + } + + const CBlock &block = File->Blocks[(unsigned)_latestBlock]; + const UInt64 offset = _virtPos - block.UnpPos; + { + const UInt64 rem = File->GetUnpackSize_of_Block((unsigned)_latestBlock) - offset; + if (size > rem) + size = (UInt32)rem; + if (size == 0) // it's unexpected case. but we check it. + return S_OK; + } + HRESULT res = S_OK; + + if (block.IsZeroMethod()) + memset(data, 0, size); + else if (_latestChunk >= 0) + memcpy(data, _chunks[_latestChunk].Buf + (size_t)offset, size); + else + { + if (block.Type != METHOD_COPY) + return E_FAIL; + RINOK(InStream_SeekSet(Stream, _startPos + File->StartPackPos + block.PackPos + offset)) + res = Stream->Read(data, size, &size); + } + + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + // COM_TRY_END + } + catch(...) + { + _errorMode = true; + return E_OUTOFMEMORY; + } +} + + +Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + +#ifdef DMG_SHOW_RAW + if (index >= _files.Size()) + return S_FALSE; +#endif + + CMyComPtr2 spec; + spec.Create_if_Empty(); + spec->File = &_files[index]; + const CFile &file = *spec->File; + + if (!file.IsCorrect) + return S_FALSE; + + FOR_VECTOR (i, file.Blocks) + { + const CBlock &block = file.Blocks[i]; + if (!block.NeedAllocateBuffer()) + continue; + + switch (block.Type) + { +#ifdef Z7_DMG_USE_CACHE_FOR_COPY_BLOCKS + case METHOD_COPY: + break; +#endif + case METHOD_ADC: + case METHOD_ZLIB: + case METHOD_BZIP2: + case METHOD_LZFSE: + case METHOD_XZ: + // case METHOD_END: + if (file.GetUnpackSize_of_Block(i) > k_Chunk_Size_MAX) + return S_FALSE; + break; + default: + return S_FALSE; + } + } + + spec->Stream = _inStream; + spec->Size = spec->File->Size; + // RINOK( + spec->Init(_startPos + _dataForkPair.Offset); + *stream = spec.Detach(); + return S_OK; + + COM_TRY_END +} + +REGISTER_ARC_I( + "Dmg", "dmg", NULL, 0xE4, + k_Signature, + 0, + NArcInfoFlags::kBackwardOpen | + NArcInfoFlags::kUseGlobalOffset, + NULL) + +}} diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp index fdf912e22..df2299503 100644 --- a/CPP/7zip/Archive/ElfHandler.cpp +++ b/CPP/7zip/Archive/ElfHandler.cpp @@ -1,1284 +1,1284 @@ -// ElfHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -// #define Z7_ELF_SHOW_DETAILS - -using namespace NWindows; - -static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16a(p); return GetUi16a(p); } -static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32a(p); return GetUi32a(p); } -static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64a(p); return GetUi64a(p); } - -#define G16(offs, v) v = Get16(p + (offs), be) -#define G32(offs, v) v = Get32(p + (offs), be) -#define G64(offs, v) v = Get64(p + (offs), be) - -namespace NArchive { -namespace NElf { - -/* -ELF Structure example: -{ - Header - Program header table (is used at runtime) (list of segment metadata records) - { - Segment (Read) - Segment : PT_PHDR : header table itself - Segment : PT_INTERP - Segment : PT_NOTE - .rela.dyn (RELA, ALLOC) - Segment (Execute/Read) - .text section (PROGBITS, SHF_ALLOC | SHF_EXECINSTR) - Segment (Read) - .rodata (PROGBITS, SHF_ALLOC | SHF_WRITE) - Segment : PT_GNU_EH_FRAME - .eh_frame_hdr - .eh_frame - .gcc_except_table - ... - Segment (Write/Read) (VaSize > Size) - Segment (Read) : PT_GNU_RELRO - Segment (Write/Read) - .data - .bss (Size == 0) (VSize != 0) - } - .comment (VA == 0) - .shstrtab (VA == 0) - Section header table (the data for linking and relocation) -} - - Last top level segment contains .bss section that requires additional VA space. - So (VaSize > Size) for that segment. - - Segments can be unsorted (by offset) in table. - Top level segments has Type=PT_LOAD : "Loadable segment". - Top level segments usually are aligned for page size (4 KB). - Another segments (non PT_LOAD segments) are inside PT_LOAD segments. - - (VA-offset == 0) is possible for some sections and segments at the beginning of file. - (VA-offset == 4KB*N) for most sections and segments where (Size != 0), - (VA-offset != 4KB*N) for .bss section (last section), because (Size == 0), - and that section is not mapped from image file. - Some files contain additional "virtual" 4 KB page in VA space after - end of data of top level segments (PT_LOAD) before new top level segments. - So (VA-offset) value can increase by 4 KB step. -*/ - -#define ELF_CLASS_32 1 -#define ELF_CLASS_64 2 - -#define ELF_DATA_2LSB 1 -#define ELF_DATA_2MSB 2 - -static const unsigned kHeaderSize32 = 0x34; -static const unsigned kHeaderSize64 = 0x40; - -static const unsigned kSegmentSize32 = 0x20; -static const unsigned kSegmentSize64 = 0x38; - -static const unsigned kSectionSize32 = 0x28; -static const unsigned kSectionSize64 = 0x40; - -struct CHeader -{ - bool Mode64; - bool Be; - Byte Os; - Byte AbiVer; - - UInt16 Type; - UInt16 Machine; - // UInt32 Version; - - // UInt64 EntryVa; - UInt64 ProgOffset; - UInt64 SectOffset; - UInt32 Flags; - UInt16 HeaderSize; - UInt16 SegmentEntrySize; - UInt16 NumSegments; - UInt16 SectionEntrySize; - UInt16 NumSections; - UInt16 NamesSectIndex; - - bool Parse(const Byte *p); - - UInt32 GetHeadersSize() const { return (UInt32)HeaderSize + - (UInt32)NumSegments * SegmentEntrySize + - (UInt32)NumSections * SectionEntrySize; } -}; - -bool CHeader::Parse(const Byte *p) -{ - switch (p[4]) - { - case ELF_CLASS_32: Mode64 = false; break; - case ELF_CLASS_64: Mode64 = true; break; - default: return false; - } - bool be; - switch (p[5]) - { - case ELF_DATA_2LSB: be = false; break; - case ELF_DATA_2MSB: be = true; break; - default: return false; - } - Be = be; - if (p[6] != 1) // Version - return false; - Os = p[7]; - // AbiVer = p[8]; - for (int i = 9; i < 16; i++) - if (p[i] != 0) - return false; - - G16(0x10, Type); - G16(0x12, Machine); - if (Get32(p + 0x14, be) != 1) // Version - return false; - - if (Mode64) - { - // G64(0x18, EntryVa); - G64(0x20, ProgOffset); // == kHeaderSize64 == 0x40 usually - G64(0x28, SectOffset); - p += 0x30; - // we expect that fields are aligned - if (ProgOffset & 7) return false; - if (SectOffset & 7) return false; - } - else - { - // G32(0x18, EntryVa); - G32(0x1C, ProgOffset); // == kHeaderSize32 == 0x34 usually - G32(0x20, SectOffset); - p += 0x24; - if (ProgOffset & 3) return false; - if (SectOffset & 3) return false; - } - - G32(0, Flags); - G16(4, HeaderSize); - if (HeaderSize != (Mode64 ? kHeaderSize64 : kHeaderSize32)) - return false; - - G16(6, SegmentEntrySize); - G16(8, NumSegments); - G16(10, SectionEntrySize); - G16(12, NumSections); - G16(14, NamesSectIndex); - - if (ProgOffset < HeaderSize && (ProgOffset || NumSegments)) return false; - if (SectOffset < HeaderSize && (SectOffset || NumSections)) return false; - - if (SegmentEntrySize == 0) { if (NumSegments) return false; } - else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false; - - if (SectionEntrySize == 0) { if (NumSections) return false; } - else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false; - - return true; -} - - -#define PT_PHDR 6 // The program header table itself. -#define PT_GNU_STACK 0x6474e551 - -static const CUInt32PCharPair g_SegnmentTypes[] = -{ - { 0, "Unused" }, - { 1, "Loadable segment" }, - { 2, "Dynamic linking tables" }, - { 3, "Program interpreter path name" }, - { 4, "Note section" }, - { 5, "SHLIB" }, - { 6, "Program header table" }, - { 7, "TLS" }, - { 0x6474e550, "GNU_EH_FRAME" }, - { PT_GNU_STACK, "GNU_STACK" }, - { 0x6474e552, "GNU_RELRO" } -}; - - -static const char * const g_SegmentFlags[] = -{ - "Execute" - , "Write" - , "Read" -}; - -struct CSegment -{ - UInt32 Type; - UInt32 Flags; - UInt64 Offset; - UInt64 Va; - UInt64 Size; // size in file - UInt64 VSize; // size in memory -#ifdef Z7_ELF_SHOW_DETAILS - UInt64 Pa; // usually == Va, or == 0 - UInt64 Align; // if (Align != 0), condition must be met: - // (VSize % Align == Offset % Alig) -#endif - void UpdateTotalSize(UInt64 &totalSize) - { - const UInt64 t = Offset + Size; - if (totalSize < t) - totalSize = t; - } - void Parse(const Byte *p, bool mode64, bool be); -}; - -void CSegment::Parse(const Byte *p, bool mode64, bool be) -{ - G32(0, Type); - if (mode64) - { - G32(4, Flags); - G64(8, Offset); - G64(0x10, Va); - G64(0x20, Size); - G64(0x28, VSize); -#ifdef Z7_ELF_SHOW_DETAILS - G64(0x18, Pa); - G64(0x30, Align); -#endif - } - else - { - G32(4, Offset); - G32(8, Va); - G32(0x10, Size); - G32(0x14, VSize); - G32(0x18, Flags); -#ifdef Z7_ELF_SHOW_DETAILS - G32(0x0C, Pa); - G32(0x1C, Align); -#endif - } -} - -// Section_index = 0 means NO section - -#define SHN_UNDEF 0 - -// Section types - -/* -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -*/ -#define SHT_NOBITS 8 -/* -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_UNKNOWN12 12 -#define SHT_UNKNOWN13 13 -#define SHT_INIT_ARRAY 14 -#define SHT_FINI_ARRAY 15 -#define SHT_PREINIT_ARRAY 16 -#define SHT_GROUP 17 -#define SHT_SYMTAB_SHNDX 18 -*/ - -static const CUInt32PCharPair g_SectTypes[] = -{ - { 0, "NULL" }, - { 1, "PROGBITS" }, - { 2, "SYMTAB" }, - { 3, "STRTAB" }, - { 4, "RELA" }, - { 5, "HASH" }, - { 6, "DYNAMIC" }, - { 7, "NOTE" }, - { 8, "NOBITS" }, - { 9, "REL" }, - { 10, "SHLIB" }, - { 11, "DYNSYM" }, - { 12, "UNKNOWN12" }, - { 13, "UNKNOWN13" }, - { 14, "INIT_ARRAY" }, - { 15, "FINI_ARRAY" }, - { 16, "PREINIT_ARRAY" }, - { 17, "GROUP" }, - { 18, "SYMTAB_SHNDX" }, - - { 0x6ffffff5, "GNU_ATTRIBUTES" }, - { 0x6ffffff6, "GNU_HASH" }, - { 0x6ffffffd, "GNU_verdef" }, - { 0x6ffffffe, "GNU_verneed" }, - { 0x6fffffff, "GNU_versym" }, - // { 0x70000001, "X86_64_UNWIND" }, - { 0x70000001, "ARM_EXIDX" }, - { 0x70000002, "ARM_PREEMPTMAP" }, - { 0x70000003, "ARM_ATTRIBUTES" }, - { 0x70000004, "ARM_DEBUGOVERLAY" }, - { 0x70000005, "ARM_OVERLAYSECTION" } -}; - - -// SHF_ flags -static const CUInt32PCharPair g_SectionFlags[] = -{ - { 0, "WRITE" }, - { 1, "ALLOC" }, - { 2, "EXECINSTR" }, - - { 4, "MERGE" }, - { 5, "STRINGS" }, - { 6, "INFO_LINK" }, - { 7, "LINK_ORDER" }, - { 8, "OS_NONCONFORMING" }, - { 9, "GROUP" }, - { 10, "TLS" }, - { 11, "COMPRESSED" }, - { 12, "DP_SECTION" }, - { 13, "XCORE_SHF_CP_SECTION" }, - { 28, "64_LARGE" }, -}; - -struct CSection -{ - UInt32 Name; - UInt32 Type; - UInt64 Flags; - UInt64 Va; - UInt64 Offset; - UInt64 VSize; - UInt32 Link; - UInt32 Info; - UInt64 AddrAlign; - UInt64 EntSize; - - UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; } - - void UpdateTotalSize(UInt64 &totalSize) - { - const UInt64 t = Offset + GetSize(); - if (totalSize < t) - totalSize = t; - } - bool Parse(const Byte *p, bool mode64, bool be); -}; - -bool CSection::Parse(const Byte *p, bool mode64, bool be) -{ - G32(0, Name); - G32(4, Type); - if (mode64) - { - G64(0x08, Flags); - G64(0x10, Va); - G64(0x18, Offset); - G64(0x20, VSize); - G32(0x28, Link); - G32(0x2C, Info); - G64(0x30, AddrAlign); - G64(0x38, EntSize); - } - else - { - G32(0x08, Flags); - G32(0x0C, Va); - G32(0x10, Offset); - G32(0x14, VSize); - G32(0x18, Link); - G32(0x1C, Info); - G32(0x20, AddrAlign); - G32(0x24, EntSize); - } - if (EntSize >= ((UInt32)1 << 31)) - return false; - if (EntSize >= ((UInt32)1 << 10) && - EntSize >= VSize && - VSize != 0) - return false; - return true; -} - - -static const char * const g_Machines[] = -{ - "None" - , "AT&T WE 32100" - , "SPARC" - , "Intel 386" - , "Motorola 68000" - , "Motorola 88000" - , "Intel 486" - , "Intel i860" - , "MIPS" - , "IBM S/370" - , "MIPS RS3000 LE" - , "RS6000" - , NULL - , NULL - , NULL - , "PA-RISC" - , "nCUBE" - , "Fujitsu VPP500" - , "SPARC 32+" - , "Intel i960" - , "PowerPC" - , "PowerPC 64-bit" - , "IBM S/390" - , "SPU" - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , "NEX v800" - , "Fujitsu FR20" - , "TRW RH-32" - , "Motorola RCE" - , "ARM" - , "Alpha-STD" - , "Hitachi SH" - , "SPARC-V9" - , "Siemens Tricore" - , "ARC" - , "H8/300" - , "H8/300H" - , "H8S" - , "H8/500" - , "IA-64" - , "Stanford MIPS-X" - , "Motorola ColdFire" - , "M68HC12" - , "Fujitsu MMA" - , "Siemens PCP" - , "Sony nCPU" - , "Denso NDR1" - , "Motorola StarCore" - , "Toyota ME16" - , "ST100" - , "Advanced Logic TinyJ" - , "AMD64" - , "Sony DSP" - , NULL - , NULL - , "Siemens FX66" - , "ST9+" - , "ST7" - , "MC68HC16" - , "MC68HC11" - , "MC68HC08" - , "MC68HC05" - , "Silicon Graphics SVx" - , "ST19" - , "Digital VAX" - , "Axis CRIS" - , "Infineon JAVELIN" - , "Element 14 FirePath" - , "LSI ZSP" - , "MMIX" - , "HUANY" - , "SiTera Prism" - , "Atmel AVR" - , "Fujitsu FR30" - , "Mitsubishi D10V" - , "Mitsubishi D30V" - , "NEC v850" - , "Mitsubishi M32R" - , "Matsushita MN10300" - , "Matsushita MN10200" - , "picoJava" - , "OpenRISC" - , "ARC Tangent-A5" - , "Tensilica Xtensa" - , "Alphamosaic VideoCore" - , "Thompson MM GPP" - , "National Semiconductor 32K" - , "Tenor Network TPC" - , "Trebia SNP 1000" - , "ST200" - , "Ubicom IP2xxx" - , "MAX" - , "NS CompactRISC" - , "Fujitsu F2MC16" - , "TI msp430" - , "Blackfin (DSP)" - , "SE S1C33" - , "Sharp embedded" - , "Arca RISC" - , "Unicore" - , "eXcess" - , "DXP" - , "Altera Nios II" - , "NS CRX" - , "Motorola XGATE" - , "Infineon C16x/XC16x" - , "Renesas M16C" - , "Microchip Technology dsPIC30F" - , "Freescale CE" - , "Renesas M32C" - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , "Altium TSK3000" - , "Freescale RS08" - , "Analog Devices SHARC" - , "Cyan Technology eCOG2" - , "Sunplus S+core7 RISC" - , "NJR 24-bit DSP" - , "Broadcom VideoCore III" - , "Lattice FPGA" - , "SE C17" - , "TI TMS320C6000" - , "TI TMS320C2000" - , "TI TMS320C55x" - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , "STM 64bit VLIW Data Signal" - , "Cypress M8C" - , "Renesas R32C" - , "NXP TriMedia" - , "Qualcomm Hexagon" - , "Intel 8051" - , "STMicroelectronics STxP7x" - , "Andes" - , "Cyan Technology eCOG1X" - , "Dallas Semiconductor MAXQ30" - , "NJR 16-bit DSP" - , "M2000" - , "Cray NV2" - , "Renesas RX" - , "Imagination Technologies META" - , "MCST Elbrus" - , "Cyan Technology eCOG16" - , "National Semiconductor CR16" - , "Freescale ETPUnit" - , "Infineon SLE9X" - , "Intel L10M" - , "Intel K10M" - , NULL - , "ARM64" - , NULL - , "Atmel AVR32" - , "STM8" - , "Tilera TILE64" - , "Tilera TILEPro" - , "Xilinx MicroBlaze" - , "NVIDIA CUDA" - , "Tilera TILE-Gx" - , "CloudShield" - , "KIPO-KAIST Core-A 1st" - , "KIPO-KAIST Core-A 2nd" - , "Synopsys ARCompact V2" - , "Open8" - , "Renesas RL78" - , "Broadcom VideoCore V" - , "Renesas 78KOR" - , "Freescale 56800EX" // 200 -}; - -static const CUInt32PCharPair g_MachinePairs[] = -{ - { 243, "RISC-V" }, - { 258, "LoongArch" }, - { 0x9026, "Alpha" }, // EM_ALPHA_EXP, obsolete, (used by NetBSD/alpha) (written in the absence of an ABI) - { 0xbaab, "Xilinx MicroBlaze" } -}; - -static const CUInt32PCharPair g_OS[] = -{ - { 0, "None" }, - { 1, "HP-UX" }, - { 2, "NetBSD" }, - { 3, "Linux" }, - { 4, "Hurd" }, - - { 6, "Solaris" }, - { 7, "AIX" }, - { 8, "IRIX" }, - { 9, "FreeBSD" }, - { 10, "TRU64" }, - { 11, "Novell Modesto" }, - { 12, "OpenBSD" }, - { 13, "OpenVMS" }, - { 14, "HP NSK" }, - { 15, "AROS" }, - { 16, "FenixOS" }, - { 17, "CloudABI" }, - { 18, "OpenVOS" }, - { 64, "Bare-metal TMS320C6000" }, - { 65, "Linux TMS320C6000" }, - { 97, "ARM" }, - { 255, "Standalone" } -}; - -#define k_Machine_MIPS 8 -#define k_Machine_ARM 40 -#define k_Machine_RISCV 243 - -/* -#define EF_ARM_ABIMASK 0xFF000000 -#define EF_ARM_BE8 0x00800000 -#define EF_ARM_GCCMASK 0x00400FFF -#define EF_ARM_ABI_FLOAT_SOFT 0x00000200 -#define EF_ARM_ABI_FLOAT_HARD 0x00000400 -*/ - -static const CUInt32PCharPair g_ARM_Flags[] = -{ - { 1, "HasEntry" }, - { 9, "SF" }, - { 10, "HF" }, - { 23, "BE8" } -}; - - -static const CUInt32PCharPair g_MIPS_Flags[] = -{ - { 0, "NOREORDER" }, - { 1, "PIC" }, - { 2, "CPIC" }, - { 3, "XGOT" }, - { 4, "64BIT_WHIRL" }, - { 5, "ABI2" }, - { 6, "ABI_ON32" }, - { 10, "NAN2008" }, - { 25, "MicroMIPS" }, - { 26, "M16" }, - { 27, "MDMX" } -}; - -static const char * const g_RISCV_Flags[] = -{ - "RVC", - NULL, - NULL, - "RVE", - "TSO" -}; - - -// #define ET_NONE 0 -#define ET_REL 1 -// #define ET_EXEC 2 -#define ET_DYN 3 -// #define ET_CORE 4 - -static const char * const g_Types[] = -{ - "None" - , "Relocatable file" - , "Executable file" - , "Shared object file" - , "Core file" -}; - - - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IArchiveAllowTail -) - CRecordVector _segments; - CRecordVector _sections; - CByteBuffer _namesData; - CMyComPtr _inStream; - UInt64 _totalSize; - CHeader _header; - bool _headersError; - bool _allowTail; - bool _stackFlags_Defined; - UInt32 _stackFlags; - - void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const; - HRESULT Open2(IInStream *stream); -public: - CHandler(): _allowTail(false) {} -}; - -void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const -{ - if (index >= _sections.Size()) - prop = index; // it's possible for some file, but maybe it's ERROR case - else - { - const CSection §ion = _sections[index]; - const UInt32 offset = section.Name; - if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */) - { - if (showNULL) - prop = "NULL"; - return; - } - const Byte *p = _namesData; - const size_t size = _namesData.Size(); - for (size_t i = offset; i < size; i++) - if (p[i] == 0) - { - prop = (const char *)(p + offset); - return; - } - prop = "ERROR"; - } -} - -static const Byte kArcProps[] = -{ - kpidCpu, - kpidBit64, - kpidBigEndian, - kpidHostOS, - kpidCharacts, - kpidComment, - kpidHeadersSize -}; - -enum -{ - kpidLinkSection = kpidUserDefined, - kpidInfoSection, - kpidEntrySize -#ifdef Z7_ELF_SHOW_DETAILS - // , kpidAlign - , kpidPa - , kpidDelta - , kpidOffsetEnd -#endif -}; - -static const CStatProp kProps[] = -{ - { NULL, kpidPath, VT_BSTR }, - { NULL, kpidSize, VT_UI8 }, - { NULL, kpidVirtualSize, VT_UI8 }, - { NULL, kpidOffset, VT_UI8 }, - { NULL, kpidVa, VT_UI8 }, - { NULL, kpidType, VT_BSTR }, - { NULL, kpidCharacts, VT_BSTR } -#ifdef Z7_ELF_SHOW_DETAILS - // , { "Align", kpidAlign, VT_UI8 } - , { NULL, kpidClusterSize, VT_UI8 } - , { "PA", kpidPa, VT_UI8 } - , { "End offset", kpidOffsetEnd, VT_UI8 } - , { "Delta (VA-Offset)", kpidDelta, VT_UI8 } -#endif - , { "Entry Size", kpidEntrySize, VT_UI8} - , { "Link Section", kpidLinkSection, VT_BSTR} - , { "Info Section", kpidInfoSection, VT_BSTR} -}; - -IMP_IInArchive_Props_WITH_NAME -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _totalSize; break; - case kpidHeadersSize: prop = _header.GetHeadersSize(); break; - case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; - case kpidBigEndian: if (_header.Be) prop = _header.Be; break; - case kpidShortComment: - - case kpidCpu: - { - AString s; - if (_header.Machine < Z7_ARRAY_SIZE(g_Machines)) - { - const char *name = g_Machines[_header.Machine]; - if (name) - s = name; - } - if (s.IsEmpty()) - s = TypePairToString(g_MachinePairs, Z7_ARRAY_SIZE(g_MachinePairs), _header.Machine); - UInt32 flags = _header.Flags; - if (flags) - { - s.Add_Space(); - if (_header.Machine == k_Machine_ARM) - { - s += FlagsToString(g_ARM_Flags, Z7_ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1)); - s += " ABI:"; - s.Add_UInt32(flags >> 24); - } - else if (_header.Machine == k_Machine_MIPS) - { - const UInt32 ver = flags >> 28; - s.Add_Char('v'); - s.Add_UInt32(ver); - flags &= ((UInt32)1 << 28) - 1; - const UInt32 abi = (flags >> 12) & 7; - if (abi) - { - s += " ABI:"; - s.Add_UInt32(abi); - } - flags &= ~((UInt32)7 << 12); - s.Add_Space(); - s += FlagsToString(g_MIPS_Flags, Z7_ARRAY_SIZE(g_MIPS_Flags), flags); - } - else if (_header.Machine == k_Machine_RISCV) - { - s += "FLOAT_"; - const UInt32 fl = (flags >> 1) & 3; - /* - static const char * const g_RISCV_Flags_Float[] = - { "SOFT", "SINGLE", "DOUBLE", "QUAD" }; - s += g_RISCV_Flags_Float[fl]; - */ - if (fl) - s.Add_UInt32(16u << fl); - else - s += "SOFT"; - s.Add_Space(); - flags &= ~(UInt32)6; - s += FlagsToString(g_RISCV_Flags, Z7_ARRAY_SIZE(g_RISCV_Flags), flags); - } -#if 0 -#define k_Machine_LOONGARCH 258 - else if (_header.Machine == k_Machine_LOONGARCH) - { - s += "ABI:"; - s.Add_UInt32((flags >> 6) & 3); - s.Add_Dot(); - s.Add_UInt32((flags >> 3) & 7); - s.Add_Dot(); -#if 1 - s.Add_UInt32(flags & 7); -#else - static const char k_LoongArch_Float_Type[8] = { '0', 's', 'f', 'd', '4' ,'5', '6', '7' }; - s.Add_Char(k_LoongArch_Float_Type[flags & 7]); -#endif - flags &= ~(UInt32)0xff; - if (flags) - { - s.Add_Colon(); - char sz[16]; - ConvertUInt32ToHex(flags, sz); - s += sz; - } - } -#endif - else - { - char sz[16]; - ConvertUInt32ToHex(flags, sz); - s += sz; - } - } - prop = s; - break; - } - - case kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break; - case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break; - case kpidComment: - { - AString s; - if (_stackFlags_Defined) - { - s += "STACK: "; - s += FlagsToString(g_SegmentFlags, Z7_ARRAY_SIZE(g_SegmentFlags), _stackFlags); - s.Add_LF(); - /* - if (_header.EntryVa) - { - s += "Entry point: 0x"; - char temp[16 + 4]; - ConvertUInt64ToHex(_header.EntryVa, temp); - s += temp; - s.Add_LF(); - } - */ - } - if (_header.NumSegments) - { - s += "Segments: "; - s.Add_UInt32(_header.NumSegments); - s.Add_LF(); - } - if (_header.NumSections) - { - s += "Sections: "; - s.Add_UInt32(_header.NumSections); - s.Add_LF(); - } - prop = s; - break; - } - case kpidExtension: - { - const char *s = NULL; - if (_header.Type == ET_DYN) - s = "so"; - else if (_header.Type == ET_REL) - s = "o"; - if (s) - prop = s; - break; - } - // case kpidIsSelfExe: prop = (_header.Type != ET_DYN) && (_header.Type == ET_REL); break; - case kpidErrorFlags: - { - UInt32 flags = 0; - if (_headersError) flags |= kpv_ErrorFlags_HeadersError; - if (flags != 0) - prop = flags; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (index < _segments.Size()) - { - const CSegment &item = _segments[index]; - switch (propID) - { - case kpidPath: - { - char sz[16]; - ConvertUInt32ToString(index, sz); - prop = sz; - break; - } - case kpidOffset: prop = item.Offset; break; - case kpidVa: prop = item.Va; break; -#ifdef Z7_ELF_SHOW_DETAILS - case kpidDelta: if (item.Va) { prop = item.Va - item.Offset; } break; - case kpidOffsetEnd: prop = item.Offset + item.Size; break; - case kpidPa: prop = item.Pa; break; - case kpidClusterSize: prop = item.Align; break; -#endif - case kpidSize: - case kpidPackSize: prop = (UInt64)item.Size; break; - case kpidVirtualSize: prop = (UInt64)item.VSize; break; - case kpidType: PAIR_TO_PROP(g_SegnmentTypes, item.Type, prop); break; - case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break; - } - } - else - { - index -= _segments.Size(); - const CSection &item = _sections[index]; - switch (propID) - { - case kpidPath: GetSectionName(index, prop, true); break; - case kpidOffset: prop = item.Offset; break; - case kpidVa: prop = item.Va; break; -#ifdef Z7_ELF_SHOW_DETAILS - case kpidDelta: if (item.Va) { prop = item.Va - item.Offset; } break; - case kpidOffsetEnd: prop = item.Offset + item.GetSize(); break; -#endif - case kpidSize: - case kpidPackSize: prop = (UInt64)(item.Type == SHT_NOBITS ? 0 : item.VSize); break; - case kpidVirtualSize: prop = item.GetSize(); break; - case kpidType: PAIR_TO_PROP(g_SectTypes, item.Type, prop); break; - case kpidCharacts: FLAGS_TO_PROP(g_SectionFlags, (UInt32)item.Flags, prop); break; - // case kpidAlign: prop = item.Align; break; - case kpidLinkSection: GetSectionName(item.Link, prop, false); break; - case kpidInfoSection: GetSectionName(item.Info, prop, false); break; - case kpidEntrySize: prop = (UInt64)item.EntSize; break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *stream) -{ - { - const UInt32 kStartSize = kHeaderSize64; - UInt64 h64[kStartSize / 8]; - RINOK(ReadStream_FALSE(stream, h64, kStartSize)) - const Byte *h = (const Byte *)(const void *)h64; - if (GetUi32a(h) != 0x464c457f) - return S_FALSE; - if (!_header.Parse(h)) - return S_FALSE; - } - - _totalSize = _header.HeaderSize; - - bool addSegments = false; - bool addSections = false; - // first section usually is NULL (with zero offsets and zero sizes). - if (_header.NumSegments == 0 || _header.NumSections > 1) - addSections = true; - else - addSegments = true; -#ifdef Z7_ELF_SHOW_DETAILS - addSections = true; - addSegments = true; -#endif - - if (_header.NumSegments) - { - if (_header.ProgOffset > (UInt64)1 << 60) return S_FALSE; - RINOK(InStream_SeekSet(stream, _header.ProgOffset)) - const size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments; - CByteArr buf(size); - RINOK(ReadStream_FALSE(stream, buf, size)) - { - const UInt64 total = _header.ProgOffset + size; - if (_totalSize < total) - _totalSize = total; - } - if (addSegments) - _segments.ClearAndReserve(_header.NumSegments); - const Byte *p = buf; - for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize) - { - CSegment seg; - seg.Parse(p, _header.Mode64, _header.Be); - seg.UpdateTotalSize(_totalSize); - if (seg.Type == PT_GNU_STACK && !_stackFlags_Defined) - { - _stackFlags = seg.Flags; - _stackFlags_Defined = true; - } - if (addSegments - // we don't show program header table segment - && seg.Type != PT_PHDR - ) - _segments.AddInReserved(seg); - } - } - - if (_header.NumSections) - { - if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE; - RINOK(InStream_SeekSet(stream, _header.SectOffset)) - const size_t size = (size_t)_header.SectionEntrySize * _header.NumSections; - CByteArr buf(size); - RINOK(ReadStream_FALSE(stream, buf, size)) - { - const UInt64 total = _header.SectOffset + size; - if (_totalSize < total) - _totalSize = total; - } - if (addSections) - _sections.ClearAndReserve(_header.NumSections); - const Byte *p = buf; - for (unsigned i = 0; i < _header.NumSections; i++, p += _header.SectionEntrySize) - { - CSection sect; - if (!sect.Parse(p, _header.Mode64, _header.Be)) - { - _headersError = true; - return S_FALSE; - } - sect.UpdateTotalSize(_totalSize); - if (addSections) - _sections.AddInReserved(sect); - } - } - - if (addSections) - { - if (_header.NamesSectIndex < _sections.Size()) - { - const CSection § = _sections[_header.NamesSectIndex]; - const UInt64 size = sect.GetSize(); - if (size && size < ((UInt64)1 << 31) - && (Int64)sect.Offset >= 0) - { - _namesData.Alloc((size_t)size); - RINOK(InStream_SeekSet(stream, sect.Offset)) - RINOK(ReadStream_FALSE(stream, _namesData, (size_t)size)) - } - } - /* - // we cannot delete "NULL" sections, - // because we have links to sections array via indexes - for (int i = _sections.Size() - 1; i >= 0; i--) - if (_sections[i].Type == SHT_NULL) - _items.Delete(i); - */ - } - - if (!_allowTail) - { - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) - if (fileSize > _totalSize) - return S_FALSE; - } - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream)) - _inStream = inStream; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - _headersError = false; - _stackFlags_Defined = false; - - _inStream.Release(); - _segments.Clear(); - _sections.Clear(); - _namesData.Free(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _segments.Size() + _sections.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _segments.Size() + _sections.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - totalSize += (index < _segments.Size()) ? - _segments[index].Size : - _sections[index - _segments.Size()].GetSize(); - } - RINOK(extractCallback->SetTotal(totalSize)) - - totalSize = 0; - UInt64 currentItemSize; - - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create inStream; - inStream->SetStream(_inStream); - - for (i = 0;; i++, totalSize += currentItemSize) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - UInt64 offset; - if (index < _segments.Size()) - { - const CSegment &item = _segments[index]; - currentItemSize = item.Size; - offset = item.Offset; - } - else - { - const CSection &item = _sections[index - _segments.Size()]; - currentItemSize = item.GetSize(); - offset = item.Offset; - } - { - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(InStream_SeekSet(_inStream, offset)) - inStream->Init(currentItemSize); - RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) - } - RINOK(extractCallback->SetOperationResult(copyCoder->TotalSize == currentItemSize ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' }; - -REGISTER_ARC_I( - "ELF", "elf", NULL, 0xDE, - k_Signature, - 0, - NArcInfoFlags::kPreArc, - NULL) - -}} +// ElfHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +// #define Z7_ELF_SHOW_DETAILS + +using namespace NWindows; + +static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16a(p); return GetUi16a(p); } +static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32a(p); return GetUi32a(p); } +static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64a(p); return GetUi64a(p); } + +#define G16(offs, v) v = Get16(p + (offs), be) +#define G32(offs, v) v = Get32(p + (offs), be) +#define G64(offs, v) v = Get64(p + (offs), be) + +namespace NArchive { +namespace NElf { + +/* +ELF Structure example: +{ + Header + Program header table (is used at runtime) (list of segment metadata records) + { + Segment (Read) + Segment : PT_PHDR : header table itself + Segment : PT_INTERP + Segment : PT_NOTE + .rela.dyn (RELA, ALLOC) + Segment (Execute/Read) + .text section (PROGBITS, SHF_ALLOC | SHF_EXECINSTR) + Segment (Read) + .rodata (PROGBITS, SHF_ALLOC | SHF_WRITE) + Segment : PT_GNU_EH_FRAME + .eh_frame_hdr + .eh_frame + .gcc_except_table + ... + Segment (Write/Read) (VaSize > Size) + Segment (Read) : PT_GNU_RELRO + Segment (Write/Read) + .data + .bss (Size == 0) (VSize != 0) + } + .comment (VA == 0) + .shstrtab (VA == 0) + Section header table (the data for linking and relocation) +} + + Last top level segment contains .bss section that requires additional VA space. + So (VaSize > Size) for that segment. + + Segments can be unsorted (by offset) in table. + Top level segments has Type=PT_LOAD : "Loadable segment". + Top level segments usually are aligned for page size (4 KB). + Another segments (non PT_LOAD segments) are inside PT_LOAD segments. + + (VA-offset == 0) is possible for some sections and segments at the beginning of file. + (VA-offset == 4KB*N) for most sections and segments where (Size != 0), + (VA-offset != 4KB*N) for .bss section (last section), because (Size == 0), + and that section is not mapped from image file. + Some files contain additional "virtual" 4 KB page in VA space after + end of data of top level segments (PT_LOAD) before new top level segments. + So (VA-offset) value can increase by 4 KB step. +*/ + +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 + +#define ELF_DATA_2LSB 1 +#define ELF_DATA_2MSB 2 + +static const unsigned kHeaderSize32 = 0x34; +static const unsigned kHeaderSize64 = 0x40; + +static const unsigned kSegmentSize32 = 0x20; +static const unsigned kSegmentSize64 = 0x38; + +static const unsigned kSectionSize32 = 0x28; +static const unsigned kSectionSize64 = 0x40; + +struct CHeader +{ + bool Mode64; + bool Be; + Byte Os; + Byte AbiVer; + + UInt16 Type; + UInt16 Machine; + // UInt32 Version; + + // UInt64 EntryVa; + UInt64 ProgOffset; + UInt64 SectOffset; + UInt32 Flags; + UInt16 HeaderSize; + UInt16 SegmentEntrySize; + UInt16 NumSegments; + UInt16 SectionEntrySize; + UInt16 NumSections; + UInt16 NamesSectIndex; + + bool Parse(const Byte *p); + + UInt32 GetHeadersSize() const { return (UInt32)HeaderSize + + (UInt32)NumSegments * SegmentEntrySize + + (UInt32)NumSections * SectionEntrySize; } +}; + +bool CHeader::Parse(const Byte *p) +{ + switch (p[4]) + { + case ELF_CLASS_32: Mode64 = false; break; + case ELF_CLASS_64: Mode64 = true; break; + default: return false; + } + bool be; + switch (p[5]) + { + case ELF_DATA_2LSB: be = false; break; + case ELF_DATA_2MSB: be = true; break; + default: return false; + } + Be = be; + if (p[6] != 1) // Version + return false; + Os = p[7]; + // AbiVer = p[8]; + for (int i = 9; i < 16; i++) + if (p[i] != 0) + return false; + + G16(0x10, Type); + G16(0x12, Machine); + if (Get32(p + 0x14, be) != 1) // Version + return false; + + if (Mode64) + { + // G64(0x18, EntryVa); + G64(0x20, ProgOffset); // == kHeaderSize64 == 0x40 usually + G64(0x28, SectOffset); + p += 0x30; + // we expect that fields are aligned + if (ProgOffset & 7) return false; + if (SectOffset & 7) return false; + } + else + { + // G32(0x18, EntryVa); + G32(0x1C, ProgOffset); // == kHeaderSize32 == 0x34 usually + G32(0x20, SectOffset); + p += 0x24; + if (ProgOffset & 3) return false; + if (SectOffset & 3) return false; + } + + G32(0, Flags); + G16(4, HeaderSize); + if (HeaderSize != (Mode64 ? kHeaderSize64 : kHeaderSize32)) + return false; + + G16(6, SegmentEntrySize); + G16(8, NumSegments); + G16(10, SectionEntrySize); + G16(12, NumSections); + G16(14, NamesSectIndex); + + if (ProgOffset < HeaderSize && (ProgOffset || NumSegments)) return false; + if (SectOffset < HeaderSize && (SectOffset || NumSections)) return false; + + if (SegmentEntrySize == 0) { if (NumSegments) return false; } + else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false; + + if (SectionEntrySize == 0) { if (NumSections) return false; } + else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false; + + return true; +} + + +#define PT_PHDR 6 // The program header table itself. +#define PT_GNU_STACK 0x6474e551 + +static const CUInt32PCharPair g_SegnmentTypes[] = +{ + { 0, "Unused" }, + { 1, "Loadable segment" }, + { 2, "Dynamic linking tables" }, + { 3, "Program interpreter path name" }, + { 4, "Note section" }, + { 5, "SHLIB" }, + { 6, "Program header table" }, + { 7, "TLS" }, + { 0x6474e550, "GNU_EH_FRAME" }, + { PT_GNU_STACK, "GNU_STACK" }, + { 0x6474e552, "GNU_RELRO" } +}; + + +static const char * const g_SegmentFlags[] = +{ + "Execute" + , "Write" + , "Read" +}; + +struct CSegment +{ + UInt32 Type; + UInt32 Flags; + UInt64 Offset; + UInt64 Va; + UInt64 Size; // size in file + UInt64 VSize; // size in memory +#ifdef Z7_ELF_SHOW_DETAILS + UInt64 Pa; // usually == Va, or == 0 + UInt64 Align; // if (Align != 0), condition must be met: + // (VSize % Align == Offset % Alig) +#endif + void UpdateTotalSize(UInt64 &totalSize) + { + const UInt64 t = Offset + Size; + if (totalSize < t) + totalSize = t; + } + void Parse(const Byte *p, bool mode64, bool be); +}; + +void CSegment::Parse(const Byte *p, bool mode64, bool be) +{ + G32(0, Type); + if (mode64) + { + G32(4, Flags); + G64(8, Offset); + G64(0x10, Va); + G64(0x20, Size); + G64(0x28, VSize); +#ifdef Z7_ELF_SHOW_DETAILS + G64(0x18, Pa); + G64(0x30, Align); +#endif + } + else + { + G32(4, Offset); + G32(8, Va); + G32(0x10, Size); + G32(0x14, VSize); + G32(0x18, Flags); +#ifdef Z7_ELF_SHOW_DETAILS + G32(0x0C, Pa); + G32(0x1C, Align); +#endif + } +} + +// Section_index = 0 means NO section + +#define SHN_UNDEF 0 + +// Section types + +/* +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +*/ +#define SHT_NOBITS 8 +/* +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_UNKNOWN12 12 +#define SHT_UNKNOWN13 13 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +*/ + +static const CUInt32PCharPair g_SectTypes[] = +{ + { 0, "NULL" }, + { 1, "PROGBITS" }, + { 2, "SYMTAB" }, + { 3, "STRTAB" }, + { 4, "RELA" }, + { 5, "HASH" }, + { 6, "DYNAMIC" }, + { 7, "NOTE" }, + { 8, "NOBITS" }, + { 9, "REL" }, + { 10, "SHLIB" }, + { 11, "DYNSYM" }, + { 12, "UNKNOWN12" }, + { 13, "UNKNOWN13" }, + { 14, "INIT_ARRAY" }, + { 15, "FINI_ARRAY" }, + { 16, "PREINIT_ARRAY" }, + { 17, "GROUP" }, + { 18, "SYMTAB_SHNDX" }, + + { 0x6ffffff5, "GNU_ATTRIBUTES" }, + { 0x6ffffff6, "GNU_HASH" }, + { 0x6ffffffd, "GNU_verdef" }, + { 0x6ffffffe, "GNU_verneed" }, + { 0x6fffffff, "GNU_versym" }, + // { 0x70000001, "X86_64_UNWIND" }, + { 0x70000001, "ARM_EXIDX" }, + { 0x70000002, "ARM_PREEMPTMAP" }, + { 0x70000003, "ARM_ATTRIBUTES" }, + { 0x70000004, "ARM_DEBUGOVERLAY" }, + { 0x70000005, "ARM_OVERLAYSECTION" } +}; + + +// SHF_ flags +static const CUInt32PCharPair g_SectionFlags[] = +{ + { 0, "WRITE" }, + { 1, "ALLOC" }, + { 2, "EXECINSTR" }, + + { 4, "MERGE" }, + { 5, "STRINGS" }, + { 6, "INFO_LINK" }, + { 7, "LINK_ORDER" }, + { 8, "OS_NONCONFORMING" }, + { 9, "GROUP" }, + { 10, "TLS" }, + { 11, "COMPRESSED" }, + { 12, "DP_SECTION" }, + { 13, "XCORE_SHF_CP_SECTION" }, + { 28, "64_LARGE" }, +}; + +struct CSection +{ + UInt32 Name; + UInt32 Type; + UInt64 Flags; + UInt64 Va; + UInt64 Offset; + UInt64 VSize; + UInt32 Link; + UInt32 Info; + UInt64 AddrAlign; + UInt64 EntSize; + + UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; } + + void UpdateTotalSize(UInt64 &totalSize) + { + const UInt64 t = Offset + GetSize(); + if (totalSize < t) + totalSize = t; + } + bool Parse(const Byte *p, bool mode64, bool be); +}; + +bool CSection::Parse(const Byte *p, bool mode64, bool be) +{ + G32(0, Name); + G32(4, Type); + if (mode64) + { + G64(0x08, Flags); + G64(0x10, Va); + G64(0x18, Offset); + G64(0x20, VSize); + G32(0x28, Link); + G32(0x2C, Info); + G64(0x30, AddrAlign); + G64(0x38, EntSize); + } + else + { + G32(0x08, Flags); + G32(0x0C, Va); + G32(0x10, Offset); + G32(0x14, VSize); + G32(0x18, Link); + G32(0x1C, Info); + G32(0x20, AddrAlign); + G32(0x24, EntSize); + } + if (EntSize >= ((UInt32)1 << 31)) + return false; + if (EntSize >= ((UInt32)1 << 10) && + EntSize >= VSize && + VSize != 0) + return false; + return true; +} + + +static const char * const g_Machines[] = +{ + "None" + , "AT&T WE 32100" + , "SPARC" + , "Intel 386" + , "Motorola 68000" + , "Motorola 88000" + , "Intel 486" + , "Intel i860" + , "MIPS" + , "IBM S/370" + , "MIPS RS3000 LE" + , "RS6000" + , NULL + , NULL + , NULL + , "PA-RISC" + , "nCUBE" + , "Fujitsu VPP500" + , "SPARC 32+" + , "Intel i960" + , "PowerPC" + , "PowerPC 64-bit" + , "IBM S/390" + , "SPU" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "NEX v800" + , "Fujitsu FR20" + , "TRW RH-32" + , "Motorola RCE" + , "ARM" + , "Alpha-STD" + , "Hitachi SH" + , "SPARC-V9" + , "Siemens Tricore" + , "ARC" + , "H8/300" + , "H8/300H" + , "H8S" + , "H8/500" + , "IA-64" + , "Stanford MIPS-X" + , "Motorola ColdFire" + , "M68HC12" + , "Fujitsu MMA" + , "Siemens PCP" + , "Sony nCPU" + , "Denso NDR1" + , "Motorola StarCore" + , "Toyota ME16" + , "ST100" + , "Advanced Logic TinyJ" + , "AMD64" + , "Sony DSP" + , NULL + , NULL + , "Siemens FX66" + , "ST9+" + , "ST7" + , "MC68HC16" + , "MC68HC11" + , "MC68HC08" + , "MC68HC05" + , "Silicon Graphics SVx" + , "ST19" + , "Digital VAX" + , "Axis CRIS" + , "Infineon JAVELIN" + , "Element 14 FirePath" + , "LSI ZSP" + , "MMIX" + , "HUANY" + , "SiTera Prism" + , "Atmel AVR" + , "Fujitsu FR30" + , "Mitsubishi D10V" + , "Mitsubishi D30V" + , "NEC v850" + , "Mitsubishi M32R" + , "Matsushita MN10300" + , "Matsushita MN10200" + , "picoJava" + , "OpenRISC" + , "ARC Tangent-A5" + , "Tensilica Xtensa" + , "Alphamosaic VideoCore" + , "Thompson MM GPP" + , "National Semiconductor 32K" + , "Tenor Network TPC" + , "Trebia SNP 1000" + , "ST200" + , "Ubicom IP2xxx" + , "MAX" + , "NS CompactRISC" + , "Fujitsu F2MC16" + , "TI msp430" + , "Blackfin (DSP)" + , "SE S1C33" + , "Sharp embedded" + , "Arca RISC" + , "Unicore" + , "eXcess" + , "DXP" + , "Altera Nios II" + , "NS CRX" + , "Motorola XGATE" + , "Infineon C16x/XC16x" + , "Renesas M16C" + , "Microchip Technology dsPIC30F" + , "Freescale CE" + , "Renesas M32C" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "Altium TSK3000" + , "Freescale RS08" + , "Analog Devices SHARC" + , "Cyan Technology eCOG2" + , "Sunplus S+core7 RISC" + , "NJR 24-bit DSP" + , "Broadcom VideoCore III" + , "Lattice FPGA" + , "SE C17" + , "TI TMS320C6000" + , "TI TMS320C2000" + , "TI TMS320C55x" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "STM 64bit VLIW Data Signal" + , "Cypress M8C" + , "Renesas R32C" + , "NXP TriMedia" + , "Qualcomm Hexagon" + , "Intel 8051" + , "STMicroelectronics STxP7x" + , "Andes" + , "Cyan Technology eCOG1X" + , "Dallas Semiconductor MAXQ30" + , "NJR 16-bit DSP" + , "M2000" + , "Cray NV2" + , "Renesas RX" + , "Imagination Technologies META" + , "MCST Elbrus" + , "Cyan Technology eCOG16" + , "National Semiconductor CR16" + , "Freescale ETPUnit" + , "Infineon SLE9X" + , "Intel L10M" + , "Intel K10M" + , NULL + , "ARM64" + , NULL + , "Atmel AVR32" + , "STM8" + , "Tilera TILE64" + , "Tilera TILEPro" + , "Xilinx MicroBlaze" + , "NVIDIA CUDA" + , "Tilera TILE-Gx" + , "CloudShield" + , "KIPO-KAIST Core-A 1st" + , "KIPO-KAIST Core-A 2nd" + , "Synopsys ARCompact V2" + , "Open8" + , "Renesas RL78" + , "Broadcom VideoCore V" + , "Renesas 78KOR" + , "Freescale 56800EX" // 200 +}; + +static const CUInt32PCharPair g_MachinePairs[] = +{ + { 243, "RISC-V" }, + { 258, "LoongArch" }, + { 0x9026, "Alpha" }, // EM_ALPHA_EXP, obsolete, (used by NetBSD/alpha) (written in the absence of an ABI) + { 0xbaab, "Xilinx MicroBlaze" } +}; + +static const CUInt32PCharPair g_OS[] = +{ + { 0, "None" }, + { 1, "HP-UX" }, + { 2, "NetBSD" }, + { 3, "Linux" }, + { 4, "Hurd" }, + + { 6, "Solaris" }, + { 7, "AIX" }, + { 8, "IRIX" }, + { 9, "FreeBSD" }, + { 10, "TRU64" }, + { 11, "Novell Modesto" }, + { 12, "OpenBSD" }, + { 13, "OpenVMS" }, + { 14, "HP NSK" }, + { 15, "AROS" }, + { 16, "FenixOS" }, + { 17, "CloudABI" }, + { 18, "OpenVOS" }, + { 64, "Bare-metal TMS320C6000" }, + { 65, "Linux TMS320C6000" }, + { 97, "ARM" }, + { 255, "Standalone" } +}; + +#define k_Machine_MIPS 8 +#define k_Machine_ARM 40 +#define k_Machine_RISCV 243 + +/* +#define EF_ARM_ABIMASK 0xFF000000 +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_GCCMASK 0x00400FFF +#define EF_ARM_ABI_FLOAT_SOFT 0x00000200 +#define EF_ARM_ABI_FLOAT_HARD 0x00000400 +*/ + +static const CUInt32PCharPair g_ARM_Flags[] = +{ + { 1, "HasEntry" }, + { 9, "SF" }, + { 10, "HF" }, + { 23, "BE8" } +}; + + +static const CUInt32PCharPair g_MIPS_Flags[] = +{ + { 0, "NOREORDER" }, + { 1, "PIC" }, + { 2, "CPIC" }, + { 3, "XGOT" }, + { 4, "64BIT_WHIRL" }, + { 5, "ABI2" }, + { 6, "ABI_ON32" }, + { 10, "NAN2008" }, + { 25, "MicroMIPS" }, + { 26, "M16" }, + { 27, "MDMX" } +}; + +static const char * const g_RISCV_Flags[] = +{ + "RVC", + NULL, + NULL, + "RVE", + "TSO" +}; + + +// #define ET_NONE 0 +#define ET_REL 1 +// #define ET_EXEC 2 +#define ET_DYN 3 +// #define ET_CORE 4 + +static const char * const g_Types[] = +{ + "None" + , "Relocatable file" + , "Executable file" + , "Shared object file" + , "Core file" +}; + + + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IArchiveAllowTail +) + CRecordVector _segments; + CRecordVector _sections; + CByteBuffer _namesData; + CMyComPtr _inStream; + UInt64 _totalSize; + CHeader _header; + bool _headersError; + bool _allowTail; + bool _stackFlags_Defined; + UInt32 _stackFlags; + + void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const; + HRESULT Open2(IInStream *stream); +public: + CHandler(): _allowTail(false) {} +}; + +void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const +{ + if (index >= _sections.Size()) + prop = index; // it's possible for some file, but maybe it's ERROR case + else + { + const CSection §ion = _sections[index]; + const UInt32 offset = section.Name; + if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */) + { + if (showNULL) + prop = "NULL"; + return; + } + const Byte *p = _namesData; + const size_t size = _namesData.Size(); + for (size_t i = offset; i < size; i++) + if (p[i] == 0) + { + prop = (const char *)(p + offset); + return; + } + prop = "ERROR"; + } +} + +static const Byte kArcProps[] = +{ + kpidCpu, + kpidBit64, + kpidBigEndian, + kpidHostOS, + kpidCharacts, + kpidComment, + kpidHeadersSize +}; + +enum +{ + kpidLinkSection = kpidUserDefined, + kpidInfoSection, + kpidEntrySize +#ifdef Z7_ELF_SHOW_DETAILS + // , kpidAlign + , kpidPa + , kpidDelta + , kpidOffsetEnd +#endif +}; + +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR }, + { NULL, kpidSize, VT_UI8 }, + { NULL, kpidVirtualSize, VT_UI8 }, + { NULL, kpidOffset, VT_UI8 }, + { NULL, kpidVa, VT_UI8 }, + { NULL, kpidType, VT_BSTR }, + { NULL, kpidCharacts, VT_BSTR } +#ifdef Z7_ELF_SHOW_DETAILS + // , { "Align", kpidAlign, VT_UI8 } + , { NULL, kpidClusterSize, VT_UI8 } + , { "PA", kpidPa, VT_UI8 } + , { "End offset", kpidOffsetEnd, VT_UI8 } + , { "Delta (VA-Offset)", kpidDelta, VT_UI8 } +#endif + , { "Entry Size", kpidEntrySize, VT_UI8} + , { "Link Section", kpidLinkSection, VT_BSTR} + , { "Info Section", kpidInfoSection, VT_BSTR} +}; + +IMP_IInArchive_Props_WITH_NAME +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _totalSize; break; + case kpidHeadersSize: prop = _header.GetHeadersSize(); break; + case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; + case kpidBigEndian: if (_header.Be) prop = _header.Be; break; + case kpidShortComment: + + case kpidCpu: + { + AString s; + if (_header.Machine < Z7_ARRAY_SIZE(g_Machines)) + { + const char *name = g_Machines[_header.Machine]; + if (name) + s = name; + } + if (s.IsEmpty()) + s = TypePairToString(g_MachinePairs, Z7_ARRAY_SIZE(g_MachinePairs), _header.Machine); + UInt32 flags = _header.Flags; + if (flags) + { + s.Add_Space(); + if (_header.Machine == k_Machine_ARM) + { + s += FlagsToString(g_ARM_Flags, Z7_ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1)); + s += " ABI:"; + s.Add_UInt32(flags >> 24); + } + else if (_header.Machine == k_Machine_MIPS) + { + const UInt32 ver = flags >> 28; + s.Add_Char('v'); + s.Add_UInt32(ver); + flags &= ((UInt32)1 << 28) - 1; + const UInt32 abi = (flags >> 12) & 7; + if (abi) + { + s += " ABI:"; + s.Add_UInt32(abi); + } + flags &= ~((UInt32)7 << 12); + s.Add_Space(); + s += FlagsToString(g_MIPS_Flags, Z7_ARRAY_SIZE(g_MIPS_Flags), flags); + } + else if (_header.Machine == k_Machine_RISCV) + { + s += "FLOAT_"; + const UInt32 fl = (flags >> 1) & 3; + /* + static const char * const g_RISCV_Flags_Float[] = + { "SOFT", "SINGLE", "DOUBLE", "QUAD" }; + s += g_RISCV_Flags_Float[fl]; + */ + if (fl) + s.Add_UInt32(16u << fl); + else + s += "SOFT"; + s.Add_Space(); + flags &= ~(UInt32)6; + s += FlagsToString(g_RISCV_Flags, Z7_ARRAY_SIZE(g_RISCV_Flags), flags); + } +#if 0 +#define k_Machine_LOONGARCH 258 + else if (_header.Machine == k_Machine_LOONGARCH) + { + s += "ABI:"; + s.Add_UInt32((flags >> 6) & 3); + s.Add_Dot(); + s.Add_UInt32((flags >> 3) & 7); + s.Add_Dot(); +#if 1 + s.Add_UInt32(flags & 7); +#else + static const char k_LoongArch_Float_Type[8] = { '0', 's', 'f', 'd', '4' ,'5', '6', '7' }; + s.Add_Char(k_LoongArch_Float_Type[flags & 7]); +#endif + flags &= ~(UInt32)0xff; + if (flags) + { + s.Add_Colon(); + char sz[16]; + ConvertUInt32ToHex(flags, sz); + s += sz; + } + } +#endif + else + { + char sz[16]; + ConvertUInt32ToHex(flags, sz); + s += sz; + } + } + prop = s; + break; + } + + case kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break; + case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break; + case kpidComment: + { + AString s; + if (_stackFlags_Defined) + { + s += "STACK: "; + s += FlagsToString(g_SegmentFlags, Z7_ARRAY_SIZE(g_SegmentFlags), _stackFlags); + s.Add_LF(); + /* + if (_header.EntryVa) + { + s += "Entry point: 0x"; + char temp[16 + 4]; + ConvertUInt64ToHex(_header.EntryVa, temp); + s += temp; + s.Add_LF(); + } + */ + } + if (_header.NumSegments) + { + s += "Segments: "; + s.Add_UInt32(_header.NumSegments); + s.Add_LF(); + } + if (_header.NumSections) + { + s += "Sections: "; + s.Add_UInt32(_header.NumSections); + s.Add_LF(); + } + prop = s; + break; + } + case kpidExtension: + { + const char *s = NULL; + if (_header.Type == ET_DYN) + s = "so"; + else if (_header.Type == ET_REL) + s = "o"; + if (s) + prop = s; + break; + } + // case kpidIsSelfExe: prop = (_header.Type != ET_DYN) && (_header.Type == ET_REL); break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (_headersError) flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (index < _segments.Size()) + { + const CSegment &item = _segments[index]; + switch (propID) + { + case kpidPath: + { + char sz[16]; + ConvertUInt32ToString(index, sz); + prop = sz; + break; + } + case kpidOffset: prop = item.Offset; break; + case kpidVa: prop = item.Va; break; +#ifdef Z7_ELF_SHOW_DETAILS + case kpidDelta: if (item.Va) { prop = item.Va - item.Offset; } break; + case kpidOffsetEnd: prop = item.Offset + item.Size; break; + case kpidPa: prop = item.Pa; break; + case kpidClusterSize: prop = item.Align; break; +#endif + case kpidSize: + case kpidPackSize: prop = (UInt64)item.Size; break; + case kpidVirtualSize: prop = (UInt64)item.VSize; break; + case kpidType: PAIR_TO_PROP(g_SegnmentTypes, item.Type, prop); break; + case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break; + } + } + else + { + index -= _segments.Size(); + const CSection &item = _sections[index]; + switch (propID) + { + case kpidPath: GetSectionName(index, prop, true); break; + case kpidOffset: prop = item.Offset; break; + case kpidVa: prop = item.Va; break; +#ifdef Z7_ELF_SHOW_DETAILS + case kpidDelta: if (item.Va) { prop = item.Va - item.Offset; } break; + case kpidOffsetEnd: prop = item.Offset + item.GetSize(); break; +#endif + case kpidSize: + case kpidPackSize: prop = (UInt64)(item.Type == SHT_NOBITS ? 0 : item.VSize); break; + case kpidVirtualSize: prop = item.GetSize(); break; + case kpidType: PAIR_TO_PROP(g_SectTypes, item.Type, prop); break; + case kpidCharacts: FLAGS_TO_PROP(g_SectionFlags, (UInt32)item.Flags, prop); break; + // case kpidAlign: prop = item.Align; break; + case kpidLinkSection: GetSectionName(item.Link, prop, false); break; + case kpidInfoSection: GetSectionName(item.Info, prop, false); break; + case kpidEntrySize: prop = (UInt64)item.EntSize; break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *stream) +{ + { + const UInt32 kStartSize = kHeaderSize64; + UInt64 h64[kStartSize / 8]; + RINOK(ReadStream_FALSE(stream, h64, kStartSize)) + const Byte *h = (const Byte *)(const void *)h64; + if (GetUi32a(h) != 0x464c457f) + return S_FALSE; + if (!_header.Parse(h)) + return S_FALSE; + } + + _totalSize = _header.HeaderSize; + + bool addSegments = false; + bool addSections = false; + // first section usually is NULL (with zero offsets and zero sizes). + if (_header.NumSegments == 0 || _header.NumSections > 1) + addSections = true; + else + addSegments = true; +#ifdef Z7_ELF_SHOW_DETAILS + addSections = true; + addSegments = true; +#endif + + if (_header.NumSegments) + { + if (_header.ProgOffset > (UInt64)1 << 60) return S_FALSE; + RINOK(InStream_SeekSet(stream, _header.ProgOffset)) + const size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments; + CByteArr buf(size); + RINOK(ReadStream_FALSE(stream, buf, size)) + { + const UInt64 total = _header.ProgOffset + size; + if (_totalSize < total) + _totalSize = total; + } + if (addSegments) + _segments.ClearAndReserve(_header.NumSegments); + const Byte *p = buf; + for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize) + { + CSegment seg; + seg.Parse(p, _header.Mode64, _header.Be); + seg.UpdateTotalSize(_totalSize); + if (seg.Type == PT_GNU_STACK && !_stackFlags_Defined) + { + _stackFlags = seg.Flags; + _stackFlags_Defined = true; + } + if (addSegments + // we don't show program header table segment + && seg.Type != PT_PHDR + ) + _segments.AddInReserved(seg); + } + } + + if (_header.NumSections) + { + if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE; + RINOK(InStream_SeekSet(stream, _header.SectOffset)) + const size_t size = (size_t)_header.SectionEntrySize * _header.NumSections; + CByteArr buf(size); + RINOK(ReadStream_FALSE(stream, buf, size)) + { + const UInt64 total = _header.SectOffset + size; + if (_totalSize < total) + _totalSize = total; + } + if (addSections) + _sections.ClearAndReserve(_header.NumSections); + const Byte *p = buf; + for (unsigned i = 0; i < _header.NumSections; i++, p += _header.SectionEntrySize) + { + CSection sect; + if (!sect.Parse(p, _header.Mode64, _header.Be)) + { + _headersError = true; + return S_FALSE; + } + sect.UpdateTotalSize(_totalSize); + if (addSections) + _sections.AddInReserved(sect); + } + } + + if (addSections) + { + if (_header.NamesSectIndex < _sections.Size()) + { + const CSection § = _sections[_header.NamesSectIndex]; + const UInt64 size = sect.GetSize(); + if (size && size < ((UInt64)1 << 31) + && (Int64)sect.Offset >= 0) + { + _namesData.Alloc((size_t)size); + RINOK(InStream_SeekSet(stream, sect.Offset)) + RINOK(ReadStream_FALSE(stream, _namesData, (size_t)size)) + } + } + /* + // we cannot delete "NULL" sections, + // because we have links to sections array via indexes + for (int i = _sections.Size() - 1; i >= 0; i--) + if (_sections[i].Type == SHT_NULL) + _items.Delete(i); + */ + } + + if (!_allowTail) + { + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) + if (fileSize > _totalSize) + return S_FALSE; + } + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream)) + _inStream = inStream; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + _headersError = false; + _stackFlags_Defined = false; + + _inStream.Release(); + _segments.Clear(); + _sections.Clear(); + _namesData.Free(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _segments.Size() + _sections.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _segments.Size() + _sections.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + totalSize += (index < _segments.Size()) ? + _segments[index].Size : + _sections[index - _segments.Size()].GetSize(); + } + RINOK(extractCallback->SetTotal(totalSize)) + + totalSize = 0; + UInt64 currentItemSize; + + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_inStream); + + for (i = 0;; i++, totalSize += currentItemSize) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + UInt64 offset; + if (index < _segments.Size()) + { + const CSegment &item = _segments[index]; + currentItemSize = item.Size; + offset = item.Offset; + } + else + { + const CSection &item = _sections[index - _segments.Size()]; + currentItemSize = item.GetSize(); + offset = item.Offset; + } + { + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(InStream_SeekSet(_inStream, offset)) + inStream->Init(currentItemSize); + RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) + } + RINOK(extractCallback->SetOperationResult(copyCoder->TotalSize == currentItemSize ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' }; + +REGISTER_ARC_I( + "ELF", "elf", NULL, 0xDE, + k_Signature, + 0, + NArcInfoFlags::kPreArc, + NULL) + +}} diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index 41df87bd0..5af2a9291 100644 --- a/CPP/7zip/Archive/ExtHandler.cpp +++ b/CPP/7zip/Archive/ExtHandler.cpp @@ -1,2858 +1,2858 @@ -// ExtHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -// #include -// #define PRF2(x) x - -#define PRF2(x) - -#ifdef SHOW_DEBUG_INFO -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyLinux.h" -#include "../../Common/StringConvert.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -using namespace NWindows; - -UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size); - -namespace NArchive { -namespace NExt { - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define LE_16(offs, dest) dest = Get16(p + (offs)); -#define LE_32(offs, dest) dest = Get32(p + (offs)); -#define LE_64(offs, dest) dest = Get64(p + (offs)); - -#define HI_16(offs, dest) dest |= (((UInt32)Get16(p + (offs))) << 16); -#define HI_32(offs, dest) dest |= (((UInt64)Get32(p + (offs))) << 32); - -/* -static UInt32 g_Crc32CTable[256]; - -static struct CInitCrc32C -{ - CInitCrc32C() - { - for (unsigned i = 0; i < 256; i++) - { - UInt32 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (0x82F63B78 & ~((r & 1) - 1)); - g_Crc32CTable[i] = r; - } - } -} g_InitCrc32C; - -#define CRC32C_INIT_VAL 0xFFFFFFFF -#define CRC32C_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) -#define CRC32C_UPDATE_BYTE(crc, b) (g_Crc32CTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -static UInt32 Crc32C_Update(UInt32 crc, Byte const *data, size_t size) -{ - for (size_t i = 0; i < size; i++) - crc = CRC32C_UPDATE_BYTE(crc, data[i]); - return crc; -} - -static UInt32 Crc32C_Calc(Byte const *data, size_t size) -{ - return Crc32C_Update(CRC32C_INIT_VAL, data, size); -} -*/ - - -#define CRC16_INIT_VAL 0xFFFF - -#define Crc16Update(crc, data, size) LzhCrc16Update(crc, data, size) - -static UInt32 Crc16Calc(Byte const *data, size_t size) -{ - return Crc16Update(CRC16_INIT_VAL, data, size); -} - - -#define EXT4_GOOD_OLD_INODE_SIZE 128 -#define EXT_NODE_SIZE_MIN 128 - - -// inodes numbers - -// #define k_INODE_BAD 1 // Bad blocks -#define k_INODE_ROOT 2 // Root dir -// #define k_INODE_USR_QUOTA 3 // User quota -// #define k_INODE_GRP_QUOTA 4 // Group quota -// #define k_INODE_BOOT_LOADER 5 // Boot loader -// #define k_INODE_UNDEL_DIR 6 // Undelete dir -#define k_INODE_RESIZE 7 // Reserved group descriptors -// #define k_INODE_JOURNAL 8 // Journal - -// First non-reserved inode for old ext4 filesystems -#define k_INODE_GOOD_OLD_FIRST 11 - -static const char * const k_SysInode_Names[] = -{ - "0" - , "Bad" - , "Root" - , "UserQuota" - , "GroupQuota" - , "BootLoader" - , "Undelete" - , "Resize" - , "Journal" - , "Exclude" - , "Replica" -}; - -static const char * const kHostOS[] = -{ - "Linux" - , "Hurd" - , "Masix" - , "FreeBSD" - , "Lites" -}; - -static const char * const g_FeatureCompat_Flags[] = -{ - "DIR_PREALLOC" - , "IMAGIC_INODES" - , "HAS_JOURNAL" - , "EXT_ATTR" - , "RESIZE_INODE" - , "DIR_INDEX" - , "LAZY_BG" // not in Linux - , NULL // { 7, "EXCLUDE_INODE" // not used - , NULL // { 8, "EXCLUDE_BITMAP" // not in kernel - , "SPARSE_SUPER2" -}; - - -#define EXT4_FEATURE_INCOMPAT_FILETYPE (1 << 1) -#define EXT4_FEATURE_INCOMPAT_64BIT (1 << 7) - -static const char * const g_FeatureIncompat_Flags[] = -{ - "COMPRESSION" - , "FILETYPE" - , "RECOVER" /* Needs recovery */ - , "JOURNAL_DEV" /* Journal device */ - , "META_BG" - , NULL - , "EXTENTS" /* extents support */ - , "64BIT" - , "MMP" - , "FLEX_BG" - , "EA_INODE" /* EA in inode */ - , NULL - , "DIRDATA" /* data in dirent */ - , "BG_USE_META_CSUM" /* use crc32c for bg */ - , "LARGEDIR" /* >2GB or 3-lvl htree */ - , "INLINE_DATA" /* data in inode */ - , "ENCRYPT" // 16 -}; - - -static const UInt32 RO_COMPAT_GDT_CSUM = 1 << 4; -static const UInt32 RO_COMPAT_METADATA_CSUM = 1 << 10; - -static const char * const g_FeatureRoCompat_Flags[] = -{ - "SPARSE_SUPER" - , "LARGE_FILE" - , "BTREE_DIR" - , "HUGE_FILE" - , "GDT_CSUM" - , "DIR_NLINK" - , "EXTRA_ISIZE" - , "HAS_SNAPSHOT" - , "QUOTA" - , "BIGALLOC" - , "METADATA_CSUM" - , "REPLICA" - , "READONLY" // 12 -}; - - - -static const UInt32 k_NodeFlags_HUGE = (UInt32)1 << 18; -static const UInt32 k_NodeFlags_EXTENTS = (UInt32)1 << 19; - - -static const char * const g_NodeFlags[] = -{ - "SECRM" - , "UNRM" - , "COMPR" - , "SYNC" - , "IMMUTABLE" - , "APPEND" - , "NODUMP" - , "NOATIME" - , "DIRTY" - , "COMPRBLK" - , "NOCOMPR" - , "ENCRYPT" - , "INDEX" - , "IMAGIC" - , "JOURNAL_DATA" - , "NOTAIL" - , "DIRSYNC" - , "TOPDIR" - , "HUGE_FILE" - , "EXTENTS" - , NULL - , "EA_INODE" - , "EOFBLOCKS" - , NULL - , NULL - , NULL - , NULL - , NULL - , "INLINE_DATA" // 28 -}; - - -enum -{ - k_Type_UNKNOWN, - k_Type_REG_FILE, - k_Type_DIR, - k_Type_CHRDEV, - k_Type_BLKDEV, - k_Type_FIFO, - k_Type_SOCK, - k_Type_SYMLINK -}; - -static const UInt16 k_TypeToMode[] = -{ - 0, - MY_LIN_S_IFREG, - MY_LIN_S_IFDIR, - MY_LIN_S_IFCHR, - MY_LIN_S_IFBLK, - MY_LIN_S_IFIFO, - MY_LIN_S_IFSOCK, - MY_LIN_S_IFLNK -}; - - -#define EXT4_GOOD_OLD_REV 0 // old (original) format -// #define EXT4_DYNAMIC_REV 1 // V2 format with dynamic inode sizes - -struct CHeader -{ - unsigned BlockBits; - unsigned ClusterBits; - - UInt32 NumInodes; - UInt64 NumBlocks; - // UInt64 NumBlocksSuper; - UInt64 NumFreeBlocks; - UInt32 NumFreeInodes; - // UInt32 FirstDataBlock; - - UInt32 BlocksPerGroup; - UInt32 ClustersPerGroup; - UInt32 InodesPerGroup; - - UInt32 MountTime; - UInt32 WriteTime; - - // UInt16 NumMounts; - // UInt16 NumMountsMax; - - // UInt16 State; - // UInt16 Errors; - // UInt16 MinorRevLevel; - - UInt32 LastCheckTime; - // UInt32 CheckInterval; - UInt32 CreatorOs; - UInt32 RevLevel; - - // UInt16 DefResUid; - // UInt16 DefResGid; - - UInt32 FirstInode; - UInt16 InodeSize; - UInt16 BlockGroupNr; - UInt32 FeatureCompat; - UInt32 FeatureIncompat; - UInt32 FeatureRoCompat; - Byte Uuid[16]; - char VolName[16]; - char LastMount[64]; - // UInt32 BitmapAlgo; - - UInt32 JournalInode; - UInt16 GdSize; // = 64 if 64-bit(); - UInt32 CTime; - UInt16 MinExtraISize; - // UInt16 WantExtraISize; - // UInt32 Flags; - // Byte LogGroupsPerFlex; - // Byte ChecksumType; - - UInt64 WrittenKB; - - bool IsOldRev() const { return RevLevel == EXT4_GOOD_OLD_REV; } - - UInt64 GetNumGroups() const { return (NumBlocks + BlocksPerGroup - 1) / BlocksPerGroup; } - UInt64 GetNumGroups2() const { return ((UInt64)NumInodes + InodesPerGroup - 1) / InodesPerGroup; } - - bool IsThereFileType() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_FILETYPE) != 0; } - bool Is64Bit() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0; } - bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; } - bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; } - - UInt64 GetPhySize() const { return NumBlocks << BlockBits; } - - bool Parse(const Byte *p); -}; - - -static int inline GetLog(UInt32 num) -{ - for (unsigned i = 0; i < 32; i++) - if (((UInt32)1 << i) == num) - return (int)i; - return -1; -} - -static bool inline IsEmptyData(const Byte *data, unsigned size) -{ - for (unsigned i = 0; i < size; i++) - if (data[i] != 0) - return false; - return true; -} - - -bool CHeader::Parse(const Byte *p) -{ - if (GetUi16(p + 0x38) != 0xEF53) - return false; - - LE_32 (0x18, BlockBits) - LE_32 (0x1C, ClusterBits) - - if (ClusterBits != 0 && BlockBits != ClusterBits) - return false; - - if (BlockBits > 16 - 10) - return false; - BlockBits += 10; - - LE_32 (0x00, NumInodes) - LE_32 (0x04, NumBlocks) - // LE_32 (0x08, NumBlocksSuper); - LE_32 (0x0C, NumFreeBlocks) - LE_32 (0x10, NumFreeInodes) - - if (NumInodes < 2 || NumInodes <= NumFreeInodes) - return false; - - UInt32 FirstDataBlock; - LE_32 (0x14, FirstDataBlock) - if (FirstDataBlock != (unsigned)(BlockBits == 10 ? 1 : 0)) - return false; - - LE_32 (0x20, BlocksPerGroup) - LE_32 (0x24, ClustersPerGroup) - - if (BlocksPerGroup != ClustersPerGroup) - return false; - if (BlocksPerGroup == 0) - return false; - if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3))) - { - // it's allowed in ext2 - // return false; - } - - LE_32 (0x28, InodesPerGroup) - - if (InodesPerGroup < 1 || InodesPerGroup > NumInodes) - return false; - - LE_32 (0x2C, MountTime) - LE_32 (0x30, WriteTime) - - // LE_16 (0x34, NumMounts); - // LE_16 (0x36, NumMountsMax); - - // LE_16 (0x3A, State); - // LE_16 (0x3C, Errors); - // LE_16 (0x3E, MinorRevLevel); - - LE_32 (0x40, LastCheckTime) - // LE_32 (0x44, CheckInterval); - LE_32 (0x48, CreatorOs) - LE_32 (0x4C, RevLevel) - - // LE_16 (0x50, DefResUid); - // LE_16 (0x52, DefResGid); - - FirstInode = k_INODE_GOOD_OLD_FIRST; - InodeSize = EXT4_GOOD_OLD_INODE_SIZE; - - if (!IsOldRev()) - { - LE_32 (0x54, FirstInode) - LE_16 (0x58, InodeSize) - if (FirstInode < k_INODE_GOOD_OLD_FIRST) - return false; - if (InodeSize > ((UInt32)1 << BlockBits) - || InodeSize < EXT_NODE_SIZE_MIN - || GetLog(InodeSize) < 0) - return false; - } - - LE_16 (0x5A, BlockGroupNr) - LE_32 (0x5C, FeatureCompat) - LE_32 (0x60, FeatureIncompat) - LE_32 (0x64, FeatureRoCompat) - - memcpy(Uuid, p + 0x68, sizeof(Uuid)); - memcpy(VolName, p + 0x78, sizeof(VolName)); - memcpy(LastMount, p + 0x88, sizeof(LastMount)); - - // LE_32 (0xC8, BitmapAlgo); - - LE_32 (0xE0, JournalInode) - - LE_16 (0xFE, GdSize) - - LE_32 (0x108, CTime) - - if (Is64Bit()) - { - HI_32(0x150, NumBlocks) - // HI_32(0x154, NumBlocksSuper); - HI_32(0x158, NumFreeBlocks) - } - - if (NumBlocks >= (UInt64)1 << (63 - BlockBits)) - return false; - - - LE_16(0x15C, MinExtraISize) - // LE_16(0x15E, WantExtraISize); - // LE_32(0x160, Flags); - // LE_16(0x164, RaidStride); - // LE_16(0x166, MmpInterval); - // LE_64(0x168, MmpBlock); - - // LogGroupsPerFlex = p[0x174]; - // ChecksumType = p[0x175]; - - LE_64 (0x178, WrittenKB) - - // LE_32(0x194, ErrorCount); - // LE_32(0x198, ErrorTime); - // LE_32(0x19C, ErrorINode); - // LE_32(0x1A0, ErrorBlock); - - if (NumBlocks < 1) - return false; - if (NumFreeBlocks > NumBlocks) - return false; - - if (GetNumGroups() != GetNumGroups2()) - return false; - - return true; -} - - -struct CGroupDescriptor -{ - UInt64 BlockBitmap; - UInt64 InodeBitmap; - UInt64 InodeTable; - UInt32 NumFreeBlocks; - UInt32 NumFreeInodes; - UInt32 DirCount; - - UInt16 Flags; - - UInt64 ExcludeBitmap; - UInt32 BlockBitmap_Checksum; - UInt32 InodeBitmap_Checksum; - UInt32 UnusedCount; - UInt16 Checksum; - - void Parse(const Byte *p, unsigned size); -}; - -void CGroupDescriptor::Parse(const Byte *p, unsigned size) -{ - LE_32 (0x00, BlockBitmap) - LE_32 (0x04, InodeBitmap) - LE_32 (0x08, InodeTable) - LE_16 (0x0C, NumFreeBlocks) - LE_16 (0x0E, NumFreeInodes) - LE_16 (0x10, DirCount) - LE_16 (0x12, Flags) - LE_32 (0x14, ExcludeBitmap) - LE_16 (0x18, BlockBitmap_Checksum) - LE_16 (0x1A, InodeBitmap_Checksum) - LE_16 (0x1C, UnusedCount) - LE_16 (0x1E, Checksum) - - if (size >= 64) - { - p += 0x20; - HI_32 (0x00, BlockBitmap) - HI_32 (0x04, InodeBitmap) - HI_32 (0x08, InodeTable) - HI_16 (0x0C, NumFreeBlocks) - HI_16 (0x0E, NumFreeInodes) - HI_16 (0x10, DirCount) - HI_16 (0x12, UnusedCount) // instead of Flags - HI_32 (0x14, ExcludeBitmap) - HI_16 (0x18, BlockBitmap_Checksum) - HI_16 (0x1A, InodeBitmap_Checksum) - // HI_16 (0x1C, Reserved); - } -} - - -static const unsigned kNodeBlockFieldSize = 60; - -struct CExtentTreeHeader -{ - UInt16 NumEntries; - UInt16 MaxEntries; - UInt16 Depth; - // UInt32 Generation; - - bool Parse(const Byte *p) - { - LE_16 (0x02, NumEntries) - LE_16 (0x04, MaxEntries) - LE_16 (0x06, Depth) - // LE_32 (0x08, Generation); - return Get16(p) == 0xF30A; // magic - } -}; - -struct CExtentIndexNode -{ - UInt32 VirtBlock; - UInt64 PhyLeaf; - - void Parse(const Byte *p) - { - LE_32 (0x00, VirtBlock) - LE_32 (0x04, PhyLeaf) - PhyLeaf |= (((UInt64)Get16(p + 8)) << 32); - // unused 16-bit field (at offset 0x0A) can be not zero in some cases. Why? - } -}; - -struct CExtent -{ - UInt32 VirtBlock; - UInt16 Len; - bool IsInited; - UInt64 PhyStart; - - UInt32 GetVirtEnd() const { return VirtBlock + Len; } - bool IsLenOK() const { return VirtBlock + Len >= VirtBlock; } - - void Parse(const Byte *p) - { - LE_32 (0x00, VirtBlock) - LE_16 (0x04, Len) - IsInited = true; - if (Len > (UInt32)0x8000) - { - IsInited = false; - Len = (UInt16)(Len - (UInt32)0x8000); - } - LE_32 (0x08, PhyStart) - UInt16 hi; - LE_16 (0x06, hi) - PhyStart |= ((UInt64)hi << 32); - } -}; - - - -struct CExtTime -{ - UInt32 Val; - UInt32 Extra; -}; - -struct CNode -{ - Int32 ParentNode; // in _refs[], -1 if not dir - int ItemIndex; // in _items[] , (set as >=0 only for if (IsDir()) - int SymLinkIndex; // in _symLinks[] - int DirIndex; // in _dirs[] - - UInt16 Mode; - UInt32 Uid; // fixed 21.02 - UInt32 Gid; // fixed 21.02 - // UInt16 Checksum; - - UInt64 FileSize; - CExtTime MTime; - CExtTime ATime; - CExtTime CTime; - CExtTime ChangeTime; - // CExtTime DTime; - - UInt64 NumBlocks; - UInt32 NumLinks; - UInt32 Flags; - - UInt32 NumLinksCalced; - - Byte Block[kNodeBlockFieldSize]; - - CNode(): - ParentNode(-1), - ItemIndex(-1), - SymLinkIndex(-1), - DirIndex(-1), - NumLinksCalced(0) - {} - - bool IsFlags_HUGE() const { return (Flags & k_NodeFlags_HUGE) != 0; } - bool IsFlags_EXTENTS() const { return (Flags & k_NodeFlags_EXTENTS) != 0; } - - bool IsDir() const { return MY_LIN_S_ISDIR(Mode); } - bool IsRegular() const { return MY_LIN_S_ISREG(Mode); } - bool IsLink() const { return MY_LIN_S_ISLNK(Mode); } - - bool Parse(const Byte *p, const CHeader &_h); -}; - - -bool CNode::Parse(const Byte *p, const CHeader &_h) -{ - MTime.Extra = 0; - ATime.Extra = 0; - CTime.Extra = 0; - CTime.Val = 0; - ChangeTime.Extra = 0; - // DTime.Extra = 0; - - LE_16 (0x00, Mode) - LE_16 (0x02, Uid) - LE_32 (0x04, FileSize) - LE_32 (0x08, ATime.Val) - LE_32 (0x0C, ChangeTime.Val) - LE_32 (0x10, MTime.Val) - // LE_32 (0x14, DTime.Val); - LE_16 (0x18, Gid) - LE_16 (0x1A, NumLinks) - - LE_32 (0x1C, NumBlocks) - LE_32 (0x20, Flags) - // LE_32 (0x24, Union osd1); - - memcpy(Block, p + 0x28, kNodeBlockFieldSize); - - // LE_32 (0x64, Generation); // File version (for NFS) - // LE_32 (0x68, ACL); - - { - UInt32 highSize; - LE_32 (0x6C, highSize) // In ext2/3 this field was named i_dir_acl - - if (IsRegular()) // do we need that check ? - FileSize |= ((UInt64)highSize << 32); - } - - // UInt32 fragmentAddress; - // LE_32 (0x70, fragmentAddress); - - // osd2 - { - // Linux; - // ext2: - // Byte FragmentNumber = p[0x74]; - // Byte FragmentSize = p[0x74 + 1]; - - // ext4: - UInt32 numBlocksHigh; - LE_16 (0x74, numBlocksHigh) - NumBlocks |= (UInt64)numBlocksHigh << 32; - - HI_16 (0x74 + 4, Uid) - HI_16 (0x74 + 6, Gid) - /* - UInt32 checksum; - LE_16 (0x74 + 8, checksum); - checksum = checksum; - */ - } - - // 0x74: Byte Union osd2[12]; - - if (_h.InodeSize > 128) - { - // InodeSize is power of 2, so the following check is not required: - // if (_h.InodeSize < 128 + 2) return false; - UInt16 extra_isize; - LE_16 (0x80, extra_isize) - if (128 + extra_isize > _h.InodeSize) - return false; - if (extra_isize >= 0x1C) - { - // UInt16 checksumUpper; - // LE_16 (0x82, checksumUpper); - LE_32 (0x84, ChangeTime.Extra) - LE_32 (0x88, MTime.Extra) - LE_32 (0x8C, ATime.Extra) - LE_32 (0x90, CTime.Val) - LE_32 (0x94, CTime.Extra) - // LE_32 (0x98, VersionHi) - } - } - - PRF(printf("size = %5d", (unsigned)FileSize)); - - return true; -} - - -struct CItem -{ - unsigned Node; // in _refs[] - int ParentNode; // in _refs[] - int SymLinkItemIndex; // in _items[], if the Node contains SymLink to existing dir - Byte Type; - - AString Name; - - CItem(): - Node(0), - ParentNode(-1), - SymLinkItemIndex(-1), - Type(k_Type_UNKNOWN) - {} - - void Clear() - { - Node = 0; - ParentNode = -1; - SymLinkItemIndex = -1; - Type = k_Type_UNKNOWN; - Name.Empty(); - } - - bool IsDir() const { return Type == k_Type_DIR; } - // bool IsNotDir() const { return Type != k_Type_DIR && Type != k_Type_UNKNOWN; } -}; - - - -static const unsigned kNumTreeLevelsMax = 6; // must be >= 3 - - -Z7_CLASS_IMP_CHandler_IInArchive_2( - IArchiveGetRawProps, - IInArchiveGetStream -) - CObjectVector _items; - CIntVector _refs; // iNode -> (index in _nodes). if (_refs[iNode] < 0), that node is not filled - CRecordVector _nodes; - CObjectVector _dirs; // each CUIntVector contains indexes in _items[] only for dir items; - AStringVector _symLinks; - AStringVector _auxItems; - int _auxSysIndex; - int _auxUnknownIndex; - - CMyComPtr _stream; - UInt64 _phySize; - bool _isArc; - bool _headersError; - bool _headersWarning; - bool _linksError; - - bool _isUTF; - - CHeader _h; - - IArchiveOpenCallback *_openCallback; - UInt64 _totalRead; - UInt64 _totalReadPrev; - - CByteBuffer _tempBufs[kNumTreeLevelsMax]; - - - HRESULT CheckProgress2() - { - const UInt64 numFiles = _items.Size(); - return _openCallback->SetCompleted(&numFiles, &_totalRead); - } - - HRESULT CheckProgress() - { - HRESULT res = S_OK; - if (_openCallback) - { - if (_totalRead - _totalReadPrev >= ((UInt32)1 << 20)) - { - _totalReadPrev = _totalRead; - res = CheckProgress2(); - } - } - return res; - } - - - int GetParentAux(const CItem &item) const - { - if (item.Node < _h.FirstInode && _auxSysIndex >= 0) - return _auxSysIndex; - return _auxUnknownIndex; - } - - HRESULT SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size); - HRESULT ParseDir(const Byte *data, size_t size, unsigned iNodeDir); - int FindTargetItem_for_SymLink(unsigned dirNode, const AString &path) const; - - HRESULT FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector &blocks); - HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector &blocks); - HRESULT FillExtents(const Byte *p, size_t size, CRecordVector &extents, int parentDepth); - - HRESULT GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream); - HRESULT ExtractNode(unsigned nodeIndex, CByteBuffer &data); - - void ClearRefs(); - HRESULT Open2(IInStream *inStream); - - void GetPath(unsigned index, AString &s) const; - bool GetPackSize(unsigned index, UInt64 &res) const; -}; - - - -HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned iNodeDir) -{ - bool isThereSelfLink = false; - - PRF(printf("\n\n========= node = %5d size = %5d", (unsigned)iNodeDir, (unsigned)size)); - - CNode &nodeDir = _nodes[_refs[iNodeDir]]; - nodeDir.DirIndex = (int)_dirs.Size(); - CUIntVector &dir = _dirs.AddNew(); - int parentNode = -1; - - CItem item; - - for (;;) - { - if (size == 0) - break; - if (size < 8) - return S_FALSE; - UInt32 iNode; - LE_32 (0x00, iNode) - unsigned recLen; - LE_16 (0x04, recLen) - const unsigned nameLen = p[6]; - const Byte type = p[7]; - - if (recLen > size) - return S_FALSE; - if (nameLen + 8 > recLen) - return S_FALSE; - - if (iNode >= _refs.Size()) - return S_FALSE; - - item.Clear(); - - if (_h.IsThereFileType()) - item.Type = type; - else if (type != 0) - return S_FALSE; - - item.ParentNode = (int)iNodeDir; - item.Node = iNode; - item.Name.SetFrom_CalcLen((const char *)(p + 8), nameLen); - - p += recLen; - size -= recLen; - - if (item.Name.Len() != nameLen) - return S_FALSE; - - if (_isUTF) - { - // 21.07 : we force UTF8 - // _isUTF = CheckUTF8_AString(item.Name); - } - - if (iNode == 0) - { - /* - ext3 deleted?? - if (item.Name.Len() != 0) - return S_FALSE; - */ - - PRF(printf("\n EMPTY %6d %d %s", (unsigned)recLen, (unsigned)type, (const char *)item.Name)); - if (type == 0xDE) - { - // checksum - } - continue; - } - - const int nodeIndex = _refs[iNode]; - if (nodeIndex < 0) - return S_FALSE; - CNode &node = _nodes[nodeIndex]; - - if (_h.IsThereFileType() && type != 0) - { - if (type >= Z7_ARRAY_SIZE(k_TypeToMode)) - return S_FALSE; - if (k_TypeToMode[type] != (node.Mode & MY_LIN_S_IFMT)) - return S_FALSE; - } - - node.NumLinksCalced++; - - PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR " : " ", (unsigned)item.Node, (const char *)item.Name)); - - if (item.Name[0] == '.') - { - if (item.Name[1] == 0) - { - if (isThereSelfLink) - return S_FALSE; - isThereSelfLink = true; - if (iNode != iNodeDir) - return S_FALSE; - continue; - } - - if (item.Name[1] == '.' && item.Name[2] == 0) - { - if (parentNode >= 0) - return S_FALSE; - if (!node.IsDir()) - return S_FALSE; - if (iNode == iNodeDir && iNode != k_INODE_ROOT) - return S_FALSE; - - parentNode = (int)iNode; - - if (nodeDir.ParentNode < 0) - nodeDir.ParentNode = (int)iNode; - else if ((unsigned)nodeDir.ParentNode != iNode) - return S_FALSE; - - continue; - } - } - - if (iNode == iNodeDir) - return S_FALSE; - - if (parentNode < 0) - return S_FALSE; - - if (node.IsDir()) - { - if (node.ParentNode < 0) - node.ParentNode = (int)iNodeDir; - else if ((unsigned)node.ParentNode != iNodeDir) - return S_FALSE; - const unsigned itemIndex = _items.Size(); - dir.Add(itemIndex); - node.ItemIndex = (int)itemIndex; - } - - _items.Add(item); - } - - if (parentNode < 0 || !isThereSelfLink) - return S_FALSE; - - return S_OK; -} - - -static int CompareItemsNames(const unsigned *p1, const unsigned *p2, void *param) -{ - const CObjectVector &items = *(const CObjectVector *)param; - return strcmp(items[*p1].Name, items[*p2].Name); -} - - -int CHandler::FindTargetItem_for_SymLink(unsigned iNode, const AString &path) const -{ - unsigned pos = 0; - - if (path.IsEmpty()) - return -1; - - if (path[0] == '/') - { - iNode = k_INODE_ROOT; - if (iNode >= _refs.Size()) - return -1; - pos = 1; - } - - AString s; - - while (pos != path.Len()) - { - const CNode &node = _nodes[_refs[iNode]]; - const int slash = path.Find('/', pos); - - if (slash < 0) - { - s = path.Ptr(pos); - pos = path.Len(); - } - else - { - s.SetFrom(path.Ptr(pos), (unsigned)slash - pos); - pos = (unsigned)slash + 1; - } - - if (s[0] == '.') - { - if (s[1] == 0) - continue; - else if (s[1] == '.' && s[2] == 0) - { - if (node.ParentNode < 0) - return -1; - if (iNode == k_INODE_ROOT) - return -1; - iNode = (unsigned)node.ParentNode; - continue; - } - } - - if (node.DirIndex < 0) - return -1; - - const CUIntVector &dir = _dirs[node.DirIndex]; - - /* - for (unsigned i = 0;; i++) - { - if (i >= dir.Size()) - return -1; - const CItem &item = _items[dir[i]]; - if (item.Name == s) - { - iNode = item.Node; - break; - } - } - */ - - unsigned left = 0, right = dir.Size(); - for (;;) - { - if (left == right) - return -1; - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const CItem &item = _items[dir[mid]]; - const int comp = strcmp(s, item.Name); - if (comp == 0) - { - iNode = item.Node; - break; - } - if (comp < 0) - right = mid; - else - left = mid + 1; - } - } - - return _nodes[_refs[iNode]].ItemIndex; -} - - -HRESULT CHandler::SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size) -{ - if (block == 0 || block >= _h.NumBlocks) - return S_FALSE; - if (((size + ((size_t)1 << _h.BlockBits) - 1) >> _h.BlockBits) > _h.NumBlocks - block) - return S_FALSE; - RINOK(InStream_SeekSet(inStream, (UInt64)block << _h.BlockBits)) - _totalRead += size; - return ReadStream_FALSE(inStream, data, size); -} - - -static const unsigned kHeaderSize = 2 * 1024; -static const unsigned kHeaderDataOffset = 1024; - -HRESULT CHandler::Open2(IInStream *inStream) -{ - { - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)) - if (!_h.Parse(buf + kHeaderDataOffset)) - return S_FALSE; - if (_h.BlockGroupNr != 0) - return S_FALSE; // it's just copy of super block - } - - { - // ---------- Read groups and nodes ---------- - - unsigned numGroups; - { - const UInt64 numGroups64 = _h.GetNumGroups(); - if (numGroups64 > (UInt32)1 << 31) - return S_FALSE; - numGroups = (unsigned)numGroups64; - } - - unsigned gdBits = 5; - if (_h.Is64Bit()) - { - if (_h.GdSize != 64) - return S_FALSE; - gdBits = 6; - } - - _isArc = true; - _phySize = _h.GetPhySize(); - - if (_openCallback) - { - RINOK(_openCallback->SetTotal(NULL, &_phySize)) - } - - UInt64 fileSize = 0; - RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) - - CRecordVector groups; - - { - // ---------- Read groups ---------- - - CByteBuffer gdBuf; - const size_t gdBufSize = (size_t)numGroups << gdBits; - if ((gdBufSize >> gdBits) != numGroups) - return S_FALSE; - gdBuf.Alloc(gdBufSize); - RINOK(SeekAndRead(inStream, (_h.BlockBits <= 10 ? 2 : 1), gdBuf, gdBufSize)) - - for (unsigned i = 0; i < numGroups; i++) - { - CGroupDescriptor gd; - - const Byte *p = gdBuf + ((size_t)i << gdBits); - const unsigned gd_Size = (unsigned)1 << gdBits; - gd.Parse(p, gd_Size); - - if (_h.UseMetadataChecksum()) - { - // use CRC32c - } - else if (_h.UseGdtChecksum()) - { - UInt32 crc = Crc16Calc(_h.Uuid, sizeof(_h.Uuid)); - Byte i_le[4]; - SetUi32(i_le, i) - crc = Crc16Update(crc, i_le, 4); - crc = Crc16Update(crc, p, 32 - 2); - if (gd_Size != 32) - crc = Crc16Update(crc, p + 32, gd_Size - 32); - if (crc != gd.Checksum) - return S_FALSE; - } - - groups.Add(gd); - } - } - - { - // ---------- Read nodes ---------- - - if (_h.NumInodes < _h.NumFreeInodes) - return S_FALSE; - - UInt32 numNodes = _h.InodesPerGroup; - if (numNodes > _h.NumInodes) - numNodes = _h.NumInodes; - const size_t nodesDataSize = (size_t)numNodes * _h.InodeSize; - - if (nodesDataSize / _h.InodeSize != numNodes) - return S_FALSE; - - // that code to reduce false detecting cases - if (nodesDataSize > fileSize) - { - if (numNodes > (1 << 24)) - return S_FALSE; - } - - const UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1; - // numReserveInodes = _h.NumInodes + 1; - if (numReserveInodes != 0) - { - _nodes.Reserve(numReserveInodes); - _refs.Reserve(numReserveInodes); - } - - CByteBuffer nodesData; - nodesData.Alloc(nodesDataSize); - - CByteBuffer nodesMap; - const size_t blockSize = (size_t)1 << _h.BlockBits; - nodesMap.Alloc(blockSize); - - unsigned globalNodeIndex = 0; - // unsigned numEmpty = 0; - unsigned numEmpty_in_Maps = 0; - - FOR_VECTOR (gi, groups) - { - if (globalNodeIndex >= _h.NumInodes) - break; - - const CGroupDescriptor &gd = groups[gi]; - - PRF(printf("\n\ng%6d block = %6x\n", gi, (unsigned)gd.InodeTable)); - - RINOK(SeekAndRead(inStream, gd.InodeBitmap, nodesMap, blockSize)) - RINOK(SeekAndRead(inStream, gd.InodeTable, nodesData, nodesDataSize)) - - unsigned numEmpty_in_Map = 0; - - for (size_t n = 0; n < numNodes && globalNodeIndex < _h.NumInodes; n++, globalNodeIndex++) - { - if ((nodesMap[n >> 3] & ((unsigned)1 << (n & 7))) == 0) - { - numEmpty_in_Map++; - continue; - } - - const Byte *p = nodesData + (size_t)n * _h.InodeSize; - if (IsEmptyData(p, _h.InodeSize)) - { - if (globalNodeIndex + 1 >= _h.FirstInode) - { - _headersError = true; - // return S_FALSE; - } - continue; - } - - CNode node; - - PRF(printf("\nnode = %5d ", (unsigned)n)); - - if (!node.Parse(p, _h)) - return S_FALSE; - - // PRF(printf("\n %6d", (unsigned)n)); - /* - SetUi32(p + 0x7C, 0) - SetUi32(p + 0x82, 0) - - UInt32 crc = Crc32C_Calc(_h.Uuid, sizeof(_h.Uuid)); - Byte i_le[4]; - SetUi32(i_le, n); - crc = Crc32C_Update(crc, i_le, 4); - crc = Crc32C_Update(crc, p, _h.InodeSize); - if (crc != node.Checksum) return S_FALSE; - */ - - while (_refs.Size() < globalNodeIndex + 1) - { - // numEmpty++; - _refs.Add(-1); - } - - _refs.Add((int)_nodes.Add(node)); - } - - - numEmpty_in_Maps += numEmpty_in_Map; - - if (numEmpty_in_Map != gd.NumFreeInodes) - { - _headersWarning = true; - // return S_FALSE; - } - } - - if (numEmpty_in_Maps != _h.NumFreeInodes) - { - // some ext2 examples has incorrect value in _h.NumFreeInodes. - // so we disable check; - _headersWarning = true; - } - - if (_refs.Size() <= k_INODE_ROOT) - return S_FALSE; - - // printf("\n numReserveInodes = %6d, _refs.Size() = %d, numEmpty = %7d\n", numReserveInodes, _refs.Size(), (unsigned)numEmpty); - } - } - - _stream = inStream; // we need stream for dir nodes - - { - // ---------- Read Dirs ---------- - - CByteBuffer dataBuf; - - FOR_VECTOR (i, _refs) - { - const int nodeIndex = _refs[i]; - { - if (nodeIndex < 0) - continue; - const CNode &node = _nodes[nodeIndex]; - if (!node.IsDir()) - continue; - } - RINOK(ExtractNode((unsigned)nodeIndex, dataBuf)) - if (dataBuf.Size() == 0) - { - // _headersError = true; - return S_FALSE; - } - else - { - RINOK(ParseDir(dataBuf, dataBuf.Size(), i)) - } - RINOK(CheckProgress()) - } - - const int ref = _refs[k_INODE_ROOT]; - if (ref < 0 || _nodes[ref].ParentNode != k_INODE_ROOT) - return S_FALSE; - } - - { - // ---------- Check NumLinks and unreferenced dir nodes ---------- - - FOR_VECTOR (i, _refs) - { - int nodeIndex = _refs[i]; - if (nodeIndex < 0) - continue; - const CNode &node = _nodes[nodeIndex]; - - if (node.NumLinks != node.NumLinksCalced) - { - if (node.NumLinks != 1 || node.NumLinksCalced != 0 - // ) && i >= _h.FirstInode - ) - { - _linksError = true; - // return S_FALSE; - } - } - - if (!node.IsDir()) - continue; - - if (node.ParentNode < 0) - { - if (i >= _h.FirstInode) - return S_FALSE; - continue; - } - } - } - - { - // ---------- Check that there is no loops in parents list ---------- - - unsigned numNodes = _refs.Size(); - CIntArr UsedByNode(numNodes); - { - { - for (unsigned i = 0; i < numNodes; i++) - UsedByNode[i] = -1; - } - } - - FOR_VECTOR (i, _refs) - { - { - int nodeIndex = _refs[i]; - if (nodeIndex < 0) - continue; - const CNode &node = _nodes[nodeIndex]; - if (node.ParentNode < 0 // not dir - || i == k_INODE_ROOT) - continue; - } - - unsigned c = i; - - for (;;) - { - const int nodeIndex = _refs[c]; - if (nodeIndex < 0) - return S_FALSE; - CNode &node = _nodes[nodeIndex]; - - if (UsedByNode[c] != -1) - { - if ((unsigned)UsedByNode[c] == i) - return S_FALSE; - break; - } - - UsedByNode[c] = (int)i; - if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT) - break; - if ((unsigned)node.ParentNode == i) - return S_FALSE; - c = (unsigned)node.ParentNode; - } - } - } - - { - // ---------- Fill SymLinks data ---------- - - AString s; - CByteBuffer data; - - unsigned i; - for (i = 0; i < _refs.Size(); i++) - { - const int nodeIndex = _refs[i]; - if (nodeIndex < 0) - continue; - CNode &node = _nodes[nodeIndex]; - if (!node.IsLink()) - continue; - if (node.FileSize > ((UInt32)1 << 14)) - continue; - if (ExtractNode((unsigned)nodeIndex, data) == S_OK && data.Size() != 0) - { - s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size()); - if (s.Len() == data.Size()) - node.SymLinkIndex = (int)_symLinks.Add(s); - RINOK(CheckProgress()) - } - } - - for (i = 0; i < _dirs.Size(); i++) - { - _dirs[i].Sort(CompareItemsNames, (void *)&_items); - } - - unsigned prev = 0; - unsigned complex = 0; - - for (i = 0; i < _items.Size(); i++) - { - CItem &item = _items[i]; - const int sym = _nodes[_refs[item.Node]].SymLinkIndex; - if (sym >= 0 && item.ParentNode >= 0) - { - item.SymLinkItemIndex = FindTargetItem_for_SymLink((unsigned)item.ParentNode, _symLinks[sym]); - if (_openCallback) - { - complex++; - if (complex - prev >= (1 << 10)) - { - prev = complex; - RINOK(CheckProgress2()) - } - } - } - } - } - - { - // ---------- Add items and aux folders for unreferenced files ---------- - - bool useSys = false; - bool useUnknown = false; - - FOR_VECTOR (i, _refs) - { - const int nodeIndex = _refs[i]; - if (nodeIndex < 0) - continue; - const CNode &node = _nodes[nodeIndex]; - - if (node.NumLinksCalced == 0 /* || i > 100 && i < 150 */) // for debug - { - CItem item; - item.Node = i; - - // we don't know how to work with k_INODE_RESIZE node (strange FileSize and Block values). - // so we ignore it; - - if (i == k_INODE_RESIZE) - continue; - - if (node.FileSize == 0) - continue; - - if (i < _h.FirstInode) - { - if (item.Node < Z7_ARRAY_SIZE(k_SysInode_Names)) - item.Name = k_SysInode_Names[item.Node]; - useSys = true; - } - else - useUnknown = true; - - if (item.Name.IsEmpty()) - item.Name.Add_UInt32(item.Node); - - _items.Add(item); - } - } - - if (useSys) - _auxSysIndex = (int)_auxItems.Add((AString)"[SYS]"); - if (useUnknown) - _auxUnknownIndex = (int)_auxItems.Add((AString)"[UNKNOWN]"); - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - HRESULT res; - try - { - _openCallback = callback; - res = Open2(stream); - } - catch(...) - { - ClearRefs(); - throw; - } - - if (res != S_OK) - { - ClearRefs(); - return res; - } - _stream = stream; - } - return S_OK; - COM_TRY_END -} - - -void CHandler::ClearRefs() -{ - _stream.Release(); - _items.Clear(); - _nodes.Clear(); - _refs.Clear(); - _auxItems.Clear(); - _symLinks.Clear(); - _dirs.Clear(); - _auxSysIndex = -1; - _auxUnknownIndex = -1; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalRead = 0; - _totalReadPrev = 0; - _phySize = 0; - _isArc = false; - _headersError = false; - _headersWarning = false; - _linksError = false; - _isUTF = true; - - ClearRefs(); - return S_OK; -} - - -static void ChangeSeparatorsInName(char *s, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - { - char c = s[i]; - if (c == CHAR_PATH_SEPARATOR || c == '/') - s[i] = '_'; - } -} - - -void CHandler::GetPath(unsigned index, AString &s) const -{ - s.Empty(); - - if (index >= _items.Size()) - { - s = _auxItems[index - _items.Size()]; - return; - } - - for (;;) - { - const CItem &item = _items[index]; - if (!s.IsEmpty()) - s.InsertAtFront(CHAR_PATH_SEPARATOR); - s.Insert(0, item.Name); - // 18.06 - ChangeSeparatorsInName(s.GetBuf(), item.Name.Len()); - - if (item.ParentNode == k_INODE_ROOT) - return; - - if (item.ParentNode < 0) - { - int aux = GetParentAux(item); - if (aux < 0) - break; - s.InsertAtFront(CHAR_PATH_SEPARATOR); - s.Insert(0, _auxItems[aux]); - return; - } - - const CNode &node = _nodes[_refs[item.ParentNode]]; - if (node.ItemIndex < 0) - return; - index = (unsigned)node.ItemIndex; - - if (s.Len() > ((UInt32)1 << 16)) - { - s.Insert(0, "[LONG]" STRING_PATH_SEPARATOR); - return; - } - } -} - - -bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack) const -{ - if (index >= _items.Size()) - { - totalPack = 0; - return false; - } - - const CItem &item = _items[index]; - const CNode &node = _nodes[_refs[item.Node]]; - - // if (!node.IsFlags_EXTENTS()) - { - totalPack = (UInt64)node.NumBlocks << (node.IsFlags_HUGE() ? _h.BlockBits : 9); - return true; - } - - /* - CExtentTreeHeader eth; - if (!eth.Parse(node.Block)) - return false; - if (eth.NumEntries > 3) - return false; - if (!eth.Depth == 0) - return false; - - UInt64 numBlocks = 0; - { - for (unsigned i = 0; i < eth.NumEntries; i++) - { - CExtent e; - e.Parse(node.Block + 12 + i * 12); - // const CExtent &e = node.leafs[i]; - if (e.IsInited) - numBlocks += e.Len; - } - } - - totalPack = numBlocks << _h.BlockBits; - return true; - */ -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size() + _auxItems.Size(); - return S_OK; -} - -enum -{ - kpidMountTime = kpidUserDefined, - kpidLastCheckTime, - kpidRevision, - kpidINodeSize, - kpidLastMount, - kpidFeatureIncompat, - kpidFeatureRoCompat, - kpidWrittenKB - - // kpidGroupSize, - - // kpidChangeTime = kpidUserDefined + 256, - // kpidDTime -}; - -static const UInt32 kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidPosixAttrib, - kpidMTime, - kpidCTime, - kpidATime, - // kpidChangeTime, - // kpidDTime, - kpidINode, - kpidLinks, - kpidSymLink, - kpidCharacts, - kpidUserId, - kpidGroupId -}; - - -static const CStatProp kArcProps[] = -{ - { NULL, kpidHeadersSize, VT_BSTR }, - // { NULL, kpidFileSystem, VT_BSTR }, - // kpidMethod, - { NULL, kpidClusterSize, VT_UI4 }, - // { "Group Size", kpidGroupSize, VT_UI8 }, - { NULL, kpidFreeSpace, VT_UI8 }, - - { NULL, kpidMTime, VT_FILETIME }, - { NULL, kpidCTime, VT_FILETIME }, - { "Mount Time", kpidMountTime, VT_FILETIME }, - { "Last Check Time", kpidLastCheckTime, VT_FILETIME }, - - { NULL, kpidHostOS, VT_BSTR}, - { "Revision", kpidRevision, VT_UI4}, - { "inode Size", kpidINodeSize, VT_UI4}, - { NULL, kpidCodePage, VT_BSTR}, - { NULL, kpidVolumeName, VT_BSTR}, - { "Last Mounted", kpidLastMount, VT_BSTR}, - { NULL, kpidId, VT_BSTR}, - { NULL, kpidCharacts, VT_BSTR }, - { "Incompatible Features", kpidFeatureIncompat, VT_BSTR }, - { "Readonly-compatible Features", kpidFeatureRoCompat, VT_BSTR }, - { "Written KiB", kpidWrittenKB, VT_UI8 } -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVariant &prop) -{ - UString u; - AString a; - a.SetFrom_CalcLen(s, size); - if (!isUTF || !ConvertUTF8ToUnicode(a, u)) - MultiByteToUnicodeString2(u, a); - prop = u; -} - -static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop) -{ - if (val != 0) - PropVariant_SetFrom_UnixTime(prop, val); -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - - NCOM::CPropVariant prop; - - switch (propID) - { - /* - case kpidFileSystem: - { - AString res = "Ext4"; - prop = res; - break; - } - */ - - case kpidIsTree: prop = true; break; - case kpidIsAux: prop = true; break; - case kpidINode: prop = true; break; - - case kpidClusterSize: prop = (UInt32)1 << _h.BlockBits; break; - // case kpidGroupSize: prop = (UInt64)_h.BlocksPerGroup << _h.BlockBits; break; - - case kpidFreeSpace: prop = (UInt64)_h.NumFreeBlocks << _h.BlockBits; break; - - case kpidCTime: UnixTimeToProp(_h.CTime, prop); break; - case kpidMTime: UnixTimeToProp(_h.WriteTime, prop); break; - case kpidMountTime: UnixTimeToProp(_h.MountTime, prop); break; - case kpidLastCheckTime: UnixTimeToProp(_h.LastCheckTime, prop); break; - - case kpidHostOS: - { - TYPE_TO_PROP(kHostOS, _h.CreatorOs, prop); - break; - } - - case kpidRevision: prop = _h.RevLevel; break; - - case kpidINodeSize: prop = (UInt32)_h.InodeSize; break; - - case kpidId: - { - if (!IsEmptyData(_h.Uuid, sizeof(_h.Uuid))) - { - char s[sizeof(_h.Uuid) * 2 + 2]; - ConvertDataToHex_Lower(s, _h.Uuid, sizeof(_h.Uuid)); - prop = s; - } - break; - } - - case kpidCodePage: if (_isUTF) prop = "UTF-8"; break; - - case kpidShortComment: - case kpidVolumeName: - StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break; - - case kpidLastMount: StringToProp(_isUTF, _h.LastMount, sizeof(_h.LastMount), prop); break; - - case kpidCharacts: FLAGS_TO_PROP(g_FeatureCompat_Flags, _h.FeatureCompat, prop); break; - case kpidFeatureIncompat: FLAGS_TO_PROP(g_FeatureIncompat_Flags, _h.FeatureIncompat, prop); break; - case kpidFeatureRoCompat: FLAGS_TO_PROP(g_FeatureRoCompat_Flags, _h.FeatureRoCompat, prop); break; - case kpidWrittenKB: if (_h.WrittenKB != 0) prop = _h.WrittenKB; break; - - case kpidPhySize: prop = _phySize; break; - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_linksError) v |= kpv_ErrorFlags_HeadersError; - if (_headersError) v |= kpv_ErrorFlags_HeadersError; - if (!_stream && v == 0 && _isArc) - v = kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - - case kpidWarningFlags: - { - UInt32 v = 0; - if (_headersWarning) v |= kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - } - - prop.Detach(value); - return S_OK; - - COM_TRY_END -} - - -/* -static const Byte kRawProps[] = -{ - // kpidSha1, -}; -*/ - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - // *numProps = Z7_ARRAY_SIZE(kRawProps); - *numProps = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) -{ - // *propID = kRawProps[index]; - *propID = 0; - *name = NULL; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - - if (index >= _items.Size()) - return S_OK; - - const CItem &item = _items[index]; - - if (item.ParentNode < 0) - { - const int aux = GetParentAux(item); - if (aux >= 0) - *parent = _items.Size() + (unsigned)aux; - } - else - { - const int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex; - if (itemIndex >= 0) - *parent = (unsigned)itemIndex; - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (propID == kpidName && _isUTF) - { - if (index < _items.Size()) - { - const AString &s = _items[index].Name; - if (!s.IsEmpty()) - { - *data = (void *)(const char *)s; - *dataSize = (UInt32)s.Len() + 1; - *propType = NPropDataType::kUtf8z; - } - return S_OK; - } - else - { - const AString &s = _auxItems[index - _items.Size()]; - { - *data = (void *)(const char *)s; - *dataSize = (UInt32)s.Len() + 1; - *propType = NPropDataType::kUtf8z; - } - return S_OK; - } - } - - return S_OK; -} - - -static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop) -{ - if (t.Val == 0 && t.Extra == 0) - return; - - FILETIME ft; - unsigned low100ns = 0; - // if (t.Extra != 0) - { - // 1901-2446 : - Int64 v = (Int64)(Int32)t.Val; - v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp - UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v); - const UInt32 ns = (t.Extra >> 2); - if (ns < 1000000000) - { - ft64 += ns / 100; - low100ns = (unsigned)(ns % 100); - } - ft.dwLowDateTime = (DWORD)ft64; - ft.dwHighDateTime = (DWORD)(ft64 >> 32); - } - /* - else - { - // 1901-2038 : that code is good for ext4 and compatibility with Extra - NTime::UnixTime64ToFileTime((Int32)t.Val, ft); // for - - // 1970-2106 : that code is good if timestamp is used as unsigned 32-bit - // are there such systems? - // NTime::UnixTimeToFileTime(t.Val, ft); // for - } - */ - prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns); -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - if (index >= _items.Size()) - { - switch (propID) - { - case kpidPath: - case kpidName: - { - prop = _auxItems[index - _items.Size()]; - break; - } - case kpidIsDir: prop = true; break; - case kpidIsAux: prop = true; break; - } - } - else - { - - const CItem &item = _items[index]; - const CNode &node = _nodes[_refs[item.Node]]; - bool isDir = node.IsDir(); - - switch (propID) - { - case kpidPath: - { - UString u; - { - AString s; - GetPath(index, s); - if (!_isUTF || !ConvertUTF8ToUnicode(s, u)) - MultiByteToUnicodeString2(u, s); - } - prop = u; - break; - } - - case kpidName: - { - { - UString u; - { - if (!_isUTF || !ConvertUTF8ToUnicode(item.Name, u)) - MultiByteToUnicodeString2(u, item.Name); - } - prop = u; - } - break; - } - - case kpidIsDir: - { - bool isDir2 = isDir; - if (item.SymLinkItemIndex >= 0) - isDir2 = _nodes[_refs[_items[item.SymLinkItemIndex].Node]].IsDir(); - prop = isDir2; - break; - } - - case kpidSize: if (!isDir) prop = node.FileSize; break; - - case kpidPackSize: - if (!isDir) - { - UInt64 size; - if (GetPackSize(index, size)) - prop = size; - } - break; - - case kpidPosixAttrib: - { - /* - if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode)) - prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; - */ - prop = (UInt32)(node.Mode); - break; - } - - case kpidMTime: ExtTimeToProp(node.MTime, prop); break; - case kpidCTime: ExtTimeToProp(node.CTime, prop); break; - case kpidATime: ExtTimeToProp(node.ATime, prop); break; - // case kpidDTime: ExtTimeToProp(node.DTime, prop); break; - case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break; - case kpidUserId: prop = (UInt32)node.Uid; break; - case kpidGroupId: prop = (UInt32)node.Gid; break; - case kpidLinks: prop = node.NumLinks; break; - case kpidINode: prop = (UInt32)item.Node; break; - case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break; - case kpidCharacts: FLAGS_TO_PROP(g_NodeFlags, (UInt32)node.Flags, prop); break; - - case kpidSymLink: - { - if (node.SymLinkIndex >= 0) - { - UString u; - { - const AString &s = _symLinks[node.SymLinkIndex]; - if (!_isUTF || !ConvertUTF8ToUnicode(s, u)) - MultiByteToUnicodeString2(u, s); - } - prop = u; - } - break; - } - } - - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_CLASS_IMP_IInStream(CClusterInStream2 -) - UInt64 _virtPos; - UInt64 _physPos; - UInt32 _curRem; -public: - unsigned BlockBits; - UInt64 Size; - CMyComPtr Stream; - CRecordVector Vector; - - HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); } - - HRESULT InitAndSeek() - { - _curRem = 0; - _virtPos = 0; - _physPos = 0; - if (Vector.Size() > 0) - { - _physPos = (Vector[0] << BlockBits); - return SeekToPhys(); - } - return S_OK; - } -}; - - -Z7_COM7F_IMF(CClusterInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= Size) - return S_OK; - { - UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - - if (_curRem == 0) - { - const UInt32 blockSize = (UInt32)1 << BlockBits; - const UInt32 virtBlock = (UInt32)(_virtPos >> BlockBits); - const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - const UInt32 phyBlock = Vector[virtBlock]; - - if (phyBlock == 0) - { - UInt32 cur = blockSize - offsetInBlock; - if (cur > size) - cur = size; - memset(data, 0, cur); - _virtPos += cur; - if (processedSize) - *processedSize = cur; - return S_OK; - } - - UInt64 newPos = ((UInt64)phyBlock << BlockBits) + offsetInBlock; - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()) - } - - _curRem = blockSize - offsetInBlock; - - for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) - _curRem += (UInt32)1 << BlockBits; - } - - if (size > _curRem) - size = _curRem; - HRESULT res = Stream->Read(data, size, &size); - if (processedSize) - *processedSize = size; - _physPos += size; - _virtPos += size; - _curRem -= size; - return res; -} - -Z7_COM7F_IMF(CClusterInStream2::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - if (_virtPos != (UInt64)offset) - _curRem = 0; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - -Z7_CLASS_IMP_IInStream( - CExtInStream -) - UInt64 _virtPos; - UInt64 _phyPos; -public: - unsigned BlockBits; - UInt64 Size; - CMyComPtr Stream; - CRecordVector Extents; - - HRESULT StartSeek() - { - _virtPos = 0; - _phyPos = 0; - return InStream_SeekSet(Stream, _phyPos); - } -}; - -Z7_COM7F_IMF(CExtInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= Size) - return S_OK; - { - UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - - UInt32 blockIndex = (UInt32)(_virtPos >> BlockBits); - - unsigned left = 0, right = Extents.Size(); - for (;;) - { - unsigned mid = (left + right) / 2; - if (mid == left) - break; - if (blockIndex < Extents[mid].VirtBlock) - right = mid; - else - left = mid; - } - - { - const CExtent &extent = Extents[left]; - if (blockIndex < extent.VirtBlock) - return E_FAIL; - UInt32 bo = blockIndex - extent.VirtBlock; - if (bo >= extent.Len) - return E_FAIL; - - UInt32 offset = ((UInt32)_virtPos & (((UInt32)1 << BlockBits) - 1)); - UInt32 remBlocks = extent.Len - bo; - UInt64 remBytes = ((UInt64)remBlocks << BlockBits); - remBytes -= offset; - - if (size > remBytes) - size = (UInt32)remBytes; - - if (!extent.IsInited) - { - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } - - const UInt64 phyBlock = extent.PhyStart + bo; - const UInt64 phy = (phyBlock << BlockBits) + offset; - - if (phy != _phyPos) - { - RINOK(InStream_SeekSet(Stream, phy)) - _phyPos = phy; - } - - UInt32 realProcessSize = 0; - - const HRESULT res = Stream->Read(data, size, &realProcessSize); - - _phyPos += realProcessSize; - _virtPos += realProcessSize; - if (processedSize) - *processedSize = realProcessSize; - return res; - } -} - - -Z7_COM7F_IMF(CExtInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - - -HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector &blocks) -{ - const size_t blockSize = (size_t)1 << _h.BlockBits; - CByteBuffer &tempBuf = _tempBufs[level]; - tempBuf.Alloc(blockSize); - - PRF2(printf("\n level = %d, block = %7d", level, (unsigned)block)); - - RINOK(SeekAndRead(_stream, block, tempBuf, blockSize)) - - const Byte *p = tempBuf; - size_t num = (size_t)1 << (_h.BlockBits - 2); - - for (size_t i = 0; i < num; i++) - { - if (blocks.Size() == numBlocks) - break; - UInt32 val = GetUi32(p + 4 * i); - if (val >= _h.NumBlocks) - return S_FALSE; - - if (level != 0) - { - if (val == 0) - { - /* - size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level)); - PRF2(printf("\n num empty = %3d", (unsigned)num)); - for (size_t k = 0; k < num; k++) - { - blocks.Add(0); - if (blocks.Size() == numBlocks) - return S_OK; - } - continue; - */ - return S_FALSE; - } - - RINOK(FillFileBlocks2(val, level - 1, numBlocks, blocks)) - continue; - } - - PRF2(printf("\n i = %3d, blocks.Size() = %6d, block = %5d ", i, blocks.Size(), (unsigned)val)); - - PRF(printf("\n i = %3d, start = %5d ", (unsigned)i, (unsigned)val)); - - blocks.Add(val); - } - - return S_OK; -} - - -static const unsigned kNumDirectNodeBlocks = 12; - -HRESULT CHandler::FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector &blocks) -{ - // ext2 supports zero blocks (blockIndex == 0). - - blocks.ClearAndReserve(numBlocks); - - for (unsigned i = 0; i < kNumDirectNodeBlocks; i++) - { - if (i == numBlocks) - return S_OK; - UInt32 val = GetUi32(p + 4 * i); - if (val >= _h.NumBlocks) - return S_FALSE; - blocks.Add(val); - } - - for (unsigned level = 0; level < 3; level++) - { - if (blocks.Size() == numBlocks) - break; - UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + level)); - if (val >= _h.NumBlocks) - return S_FALSE; - - if (val == 0) - { - /* - size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level + 1)); - for (size_t k = 0; k < num; k++) - { - blocks.Add(0); - if (blocks.Size() == numBlocks) - return S_OK; - } - continue; - */ - return S_FALSE; - } - - RINOK(FillFileBlocks2(val, level, numBlocks, blocks)) - } - - return S_OK; -} - - -static void AddSkipExtents(CRecordVector &extents, UInt32 virtBlock, UInt32 numBlocks) -{ - while (numBlocks != 0) - { - UInt32 len = numBlocks; - const UInt32 kLenMax = (UInt32)1 << 15; - if (len > kLenMax) - len = kLenMax; - CExtent e; - e.VirtBlock = virtBlock; - e.Len = (UInt16)len; - e.IsInited = false; - e.PhyStart = 0; - extents.Add(e); - virtBlock += len; - numBlocks -= len; - } -} - -static bool UpdateExtents(CRecordVector &extents, UInt32 block) -{ - if (extents.IsEmpty()) - { - if (block == 0) - return true; - AddSkipExtents(extents, 0, block); - return true; - } - - const CExtent &prev = extents.Back(); - if (block < prev.VirtBlock) - return false; - UInt32 prevEnd = prev.GetVirtEnd(); - if (block == prevEnd) - return true; - AddSkipExtents(extents, prevEnd, block - prevEnd); - return true; -} - - -HRESULT CHandler::FillExtents(const Byte *p, size_t size, CRecordVector &extents, int parentDepth) -{ - CExtentTreeHeader eth; - if (!eth.Parse(p)) - return S_FALSE; - - if (parentDepth >= 0 && eth.Depth != parentDepth - 1) // (eth.Depth >= parentDepth) - return S_FALSE; - - if (12 + 12 * (size_t)eth.NumEntries > size) - return S_FALSE; - - if (eth.Depth >= kNumTreeLevelsMax) - return S_FALSE; - - if (eth.Depth == 0) - { - for (unsigned i = 0; i < eth.NumEntries; i++) - { - CExtent e; - e.Parse(p + 12 + i * 12); - if (e.PhyStart == 0 - || e.PhyStart > _h.NumBlocks - || e.PhyStart + e.Len > _h.NumBlocks - || !e.IsLenOK()) - return S_FALSE; - if (!UpdateExtents(extents, e.VirtBlock)) - return S_FALSE; - extents.Add(e); - } - - return S_OK; - } - - const size_t blockSize = (size_t)1 << _h.BlockBits; - CByteBuffer &tempBuf = _tempBufs[eth.Depth]; - tempBuf.Alloc(blockSize); - - for (unsigned i = 0; i < eth.NumEntries; i++) - { - CExtentIndexNode e; - e.Parse(p + 12 + i * 12); - - if (e.PhyLeaf == 0 || e.PhyLeaf >= _h.NumBlocks) - return S_FALSE; - - if (!UpdateExtents(extents, e.VirtBlock)) - return S_FALSE; - - RINOK(SeekAndRead(_stream, e.PhyLeaf, tempBuf, blockSize)) - RINOK(FillExtents(tempBuf, blockSize, extents, eth.Depth)) - } - - return S_OK; -} - - -HRESULT CHandler::GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream) -{ - COM_TRY_BEGIN - - *stream = NULL; - - const CNode &node = _nodes[nodeIndex]; - - if (!node.IsFlags_EXTENTS()) - { - // maybe sparse file can have (node.NumBlocks == 0) ? - - /* The following code doesn't work correctly for some CentOS images, - where there are nodes with inline data and (node.NumBlocks != 0). - If you know better way to detect inline data, please notify 7-Zip developers. */ - - if (node.NumBlocks == 0 && node.FileSize < kNodeBlockFieldSize) - { - Create_BufInStream_WithNewBuffer(node.Block, (size_t)node.FileSize, stream); - return S_OK; - } - } - - if (node.FileSize >= ((UInt64)1 << 63)) - return S_FALSE; - - CMyComPtr streamTemp; - - const UInt64 numBlocks64 = (node.FileSize + (UInt64)(((UInt32)1 << _h.BlockBits) - 1)) >> _h.BlockBits; - - if (node.IsFlags_EXTENTS()) - { - if ((UInt32)numBlocks64 != numBlocks64) - return S_FALSE; - - CExtInStream *streamSpec = new CExtInStream; - streamTemp = streamSpec; - - streamSpec->BlockBits = _h.BlockBits; - streamSpec->Size = node.FileSize; - streamSpec->Stream = _stream; - - RINOK(FillExtents(node.Block, kNodeBlockFieldSize, streamSpec->Extents, -1)) - - UInt32 end = 0; - if (!streamSpec->Extents.IsEmpty()) - end = streamSpec->Extents.Back().GetVirtEnd(); - if (end < numBlocks64) - { - AddSkipExtents(streamSpec->Extents, end, (UInt32)(numBlocks64 - end)); - // return S_FALSE; - } - - RINOK(streamSpec->StartSeek()) - } - else - { - { - UInt64 numBlocks2 = numBlocks64; - - if (numBlocks64 > kNumDirectNodeBlocks) - { - UInt64 rem = numBlocks64 - kNumDirectNodeBlocks; - const unsigned refBits = (_h.BlockBits - 2); - const size_t numRefsInBlocks = (size_t)1 << refBits; - numBlocks2++; - if (rem > numRefsInBlocks) - { - numBlocks2++; - const UInt64 numL2 = (rem - 1) >> refBits; - numBlocks2 += numL2; - if (numL2 > numRefsInBlocks) - { - numBlocks2++; - numBlocks2 += (numL2 - 1) >> refBits; - } - } - } - - const unsigned specBits = (node.IsFlags_HUGE() ? 0 : _h.BlockBits - 9); - const UInt32 specMask = ((UInt32)1 << specBits) - 1; - if ((node.NumBlocks & specMask) != 0) - return S_FALSE; - const UInt64 numBlocks64_from_header = node.NumBlocks >> specBits; - if (numBlocks64_from_header < numBlocks2) - { - // why (numBlocks64_from_header > numBlocks2) in some cases? - // return S_FALSE; - } - } - - unsigned numBlocks = (unsigned)numBlocks64; - if (numBlocks != numBlocks64) - return S_FALSE; - - CClusterInStream2 *streamSpec = new CClusterInStream2; - streamTemp = streamSpec; - - streamSpec->BlockBits = _h.BlockBits; - streamSpec->Size = node.FileSize; - streamSpec->Stream = _stream; - - RINOK(FillFileBlocks(node.Block, numBlocks, streamSpec->Vector)) - streamSpec->InitAndSeek(); - } - - *stream = streamTemp.Detach(); - - return S_OK; - - COM_TRY_END -} - - -HRESULT CHandler::ExtractNode(unsigned nodeIndex, CByteBuffer &data) -{ - data.Free(); - const CNode &node = _nodes[nodeIndex]; - size_t size = (size_t)node.FileSize; - if (size != node.FileSize) - return S_FALSE; - CMyComPtr inSeqStream; - RINOK(GetStream_Node(nodeIndex, &inSeqStream)) - if (!inSeqStream) - return S_FALSE; - data.Alloc(size); - _totalRead += size; - return ReadStream_FALSE(inSeqStream, data, size); -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size() + _auxItems.Size(); - if (numItems == 0) - return S_OK; - - UInt64 totalSize = 0; - UInt32 i; - - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - if (index >= _items.Size()) - continue; - const CItem &item = _items[index]; - const CNode &node = _nodes[_refs[item.Node]]; - if (!node.IsDir()) - totalSize += node.FileSize; - } - - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create copyCoder; - - for (i = 0;; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - int opRes; - { - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - const UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - - if (index >= _items.Size()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const CItem &item = _items[index]; - const CNode &node = _nodes[_refs[item.Node]]; - - if (node.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - UInt64 unpackSize = node.FileSize; - totalSize += unpackSize; - UInt64 packSize; - if (GetPackSize(index, packSize)) - totalPackSize += packSize; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - opRes = NExtract::NOperationResult::kDataError; - { - CMyComPtr inSeqStream; - HRESULT hres = GetStream(index, &inSeqStream); - if (hres == S_FALSE || !inSeqStream) - { - if (hres == E_OUTOFMEMORY) - return hres; - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - else - { - RINOK(hres) - { - hres = copyCoder.Interface()->Code(inSeqStream, outStream, NULL, NULL, lps); - if (hres == S_OK) - { - if (copyCoder->TotalSize == unpackSize) - opRes = NExtract::NOperationResult::kOK; - } - else if (hres == E_NOTIMPL) - { - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - else if (hres != S_FALSE) - { - RINOK(hres) - } - } - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - *stream = NULL; - if (index >= _items.Size()) - return S_FALSE; - return GetStream_Node((unsigned)_refs[_items[index].Node], stream); -} - - -API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); -API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize) -{ - if (phySize) - *phySize = 0; - if (size < kHeaderSize) - return k_IsArc_Res_NEED_MORE; - CHeader h; - if (!h.Parse(p + kHeaderDataOffset)) - return k_IsArc_Res_NO; - if (phySize) - *phySize = h.GetPhySize(); - return k_IsArc_Res_YES; -} - - -API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size); -API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size) -{ - return IsArc_Ext_PhySize(p, size, NULL); -} - - -static const Byte k_Signature[] = { 0x53, 0xEF }; - -REGISTER_ARC_I( - "Ext", "ext ext2 ext3 ext4 img", NULL, 0xC7, - k_Signature, - 0x438, - 0, - IsArc_Ext) - -}} +// ExtHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +// #include +// #define PRF2(x) x + +#define PRF2(x) + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyLinux.h" +#include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +using namespace NWindows; + +UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size); + +namespace NArchive { +namespace NExt { + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define LE_16(offs, dest) dest = Get16(p + (offs)); +#define LE_32(offs, dest) dest = Get32(p + (offs)); +#define LE_64(offs, dest) dest = Get64(p + (offs)); + +#define HI_16(offs, dest) dest |= (((UInt32)Get16(p + (offs))) << 16); +#define HI_32(offs, dest) dest |= (((UInt64)Get32(p + (offs))) << 32); + +/* +static UInt32 g_Crc32CTable[256]; + +static struct CInitCrc32C +{ + CInitCrc32C() + { + for (unsigned i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (0x82F63B78 & ~((r & 1) - 1)); + g_Crc32CTable[i] = r; + } + } +} g_InitCrc32C; + +#define CRC32C_INIT_VAL 0xFFFFFFFF +#define CRC32C_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL) +#define CRC32C_UPDATE_BYTE(crc, b) (g_Crc32CTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +static UInt32 Crc32C_Update(UInt32 crc, Byte const *data, size_t size) +{ + for (size_t i = 0; i < size; i++) + crc = CRC32C_UPDATE_BYTE(crc, data[i]); + return crc; +} + +static UInt32 Crc32C_Calc(Byte const *data, size_t size) +{ + return Crc32C_Update(CRC32C_INIT_VAL, data, size); +} +*/ + + +#define CRC16_INIT_VAL 0xFFFF + +#define Crc16Update(crc, data, size) LzhCrc16Update(crc, data, size) + +static UInt32 Crc16Calc(Byte const *data, size_t size) +{ + return Crc16Update(CRC16_INIT_VAL, data, size); +} + + +#define EXT4_GOOD_OLD_INODE_SIZE 128 +#define EXT_NODE_SIZE_MIN 128 + + +// inodes numbers + +// #define k_INODE_BAD 1 // Bad blocks +#define k_INODE_ROOT 2 // Root dir +// #define k_INODE_USR_QUOTA 3 // User quota +// #define k_INODE_GRP_QUOTA 4 // Group quota +// #define k_INODE_BOOT_LOADER 5 // Boot loader +// #define k_INODE_UNDEL_DIR 6 // Undelete dir +#define k_INODE_RESIZE 7 // Reserved group descriptors +// #define k_INODE_JOURNAL 8 // Journal + +// First non-reserved inode for old ext4 filesystems +#define k_INODE_GOOD_OLD_FIRST 11 + +static const char * const k_SysInode_Names[] = +{ + "0" + , "Bad" + , "Root" + , "UserQuota" + , "GroupQuota" + , "BootLoader" + , "Undelete" + , "Resize" + , "Journal" + , "Exclude" + , "Replica" +}; + +static const char * const kHostOS[] = +{ + "Linux" + , "Hurd" + , "Masix" + , "FreeBSD" + , "Lites" +}; + +static const char * const g_FeatureCompat_Flags[] = +{ + "DIR_PREALLOC" + , "IMAGIC_INODES" + , "HAS_JOURNAL" + , "EXT_ATTR" + , "RESIZE_INODE" + , "DIR_INDEX" + , "LAZY_BG" // not in Linux + , NULL // { 7, "EXCLUDE_INODE" // not used + , NULL // { 8, "EXCLUDE_BITMAP" // not in kernel + , "SPARSE_SUPER2" +}; + + +#define EXT4_FEATURE_INCOMPAT_FILETYPE (1 << 1) +#define EXT4_FEATURE_INCOMPAT_64BIT (1 << 7) + +static const char * const g_FeatureIncompat_Flags[] = +{ + "COMPRESSION" + , "FILETYPE" + , "RECOVER" /* Needs recovery */ + , "JOURNAL_DEV" /* Journal device */ + , "META_BG" + , NULL + , "EXTENTS" /* extents support */ + , "64BIT" + , "MMP" + , "FLEX_BG" + , "EA_INODE" /* EA in inode */ + , NULL + , "DIRDATA" /* data in dirent */ + , "BG_USE_META_CSUM" /* use crc32c for bg */ + , "LARGEDIR" /* >2GB or 3-lvl htree */ + , "INLINE_DATA" /* data in inode */ + , "ENCRYPT" // 16 +}; + + +static const UInt32 RO_COMPAT_GDT_CSUM = 1 << 4; +static const UInt32 RO_COMPAT_METADATA_CSUM = 1 << 10; + +static const char * const g_FeatureRoCompat_Flags[] = +{ + "SPARSE_SUPER" + , "LARGE_FILE" + , "BTREE_DIR" + , "HUGE_FILE" + , "GDT_CSUM" + , "DIR_NLINK" + , "EXTRA_ISIZE" + , "HAS_SNAPSHOT" + , "QUOTA" + , "BIGALLOC" + , "METADATA_CSUM" + , "REPLICA" + , "READONLY" // 12 +}; + + + +static const UInt32 k_NodeFlags_HUGE = (UInt32)1 << 18; +static const UInt32 k_NodeFlags_EXTENTS = (UInt32)1 << 19; + + +static const char * const g_NodeFlags[] = +{ + "SECRM" + , "UNRM" + , "COMPR" + , "SYNC" + , "IMMUTABLE" + , "APPEND" + , "NODUMP" + , "NOATIME" + , "DIRTY" + , "COMPRBLK" + , "NOCOMPR" + , "ENCRYPT" + , "INDEX" + , "IMAGIC" + , "JOURNAL_DATA" + , "NOTAIL" + , "DIRSYNC" + , "TOPDIR" + , "HUGE_FILE" + , "EXTENTS" + , NULL + , "EA_INODE" + , "EOFBLOCKS" + , NULL + , NULL + , NULL + , NULL + , NULL + , "INLINE_DATA" // 28 +}; + + +enum +{ + k_Type_UNKNOWN, + k_Type_REG_FILE, + k_Type_DIR, + k_Type_CHRDEV, + k_Type_BLKDEV, + k_Type_FIFO, + k_Type_SOCK, + k_Type_SYMLINK +}; + +static const UInt16 k_TypeToMode[] = +{ + 0, + MY_LIN_S_IFREG, + MY_LIN_S_IFDIR, + MY_LIN_S_IFCHR, + MY_LIN_S_IFBLK, + MY_LIN_S_IFIFO, + MY_LIN_S_IFSOCK, + MY_LIN_S_IFLNK +}; + + +#define EXT4_GOOD_OLD_REV 0 // old (original) format +// #define EXT4_DYNAMIC_REV 1 // V2 format with dynamic inode sizes + +struct CHeader +{ + unsigned BlockBits; + unsigned ClusterBits; + + UInt32 NumInodes; + UInt64 NumBlocks; + // UInt64 NumBlocksSuper; + UInt64 NumFreeBlocks; + UInt32 NumFreeInodes; + // UInt32 FirstDataBlock; + + UInt32 BlocksPerGroup; + UInt32 ClustersPerGroup; + UInt32 InodesPerGroup; + + UInt32 MountTime; + UInt32 WriteTime; + + // UInt16 NumMounts; + // UInt16 NumMountsMax; + + // UInt16 State; + // UInt16 Errors; + // UInt16 MinorRevLevel; + + UInt32 LastCheckTime; + // UInt32 CheckInterval; + UInt32 CreatorOs; + UInt32 RevLevel; + + // UInt16 DefResUid; + // UInt16 DefResGid; + + UInt32 FirstInode; + UInt16 InodeSize; + UInt16 BlockGroupNr; + UInt32 FeatureCompat; + UInt32 FeatureIncompat; + UInt32 FeatureRoCompat; + Byte Uuid[16]; + char VolName[16]; + char LastMount[64]; + // UInt32 BitmapAlgo; + + UInt32 JournalInode; + UInt16 GdSize; // = 64 if 64-bit(); + UInt32 CTime; + UInt16 MinExtraISize; + // UInt16 WantExtraISize; + // UInt32 Flags; + // Byte LogGroupsPerFlex; + // Byte ChecksumType; + + UInt64 WrittenKB; + + bool IsOldRev() const { return RevLevel == EXT4_GOOD_OLD_REV; } + + UInt64 GetNumGroups() const { return (NumBlocks + BlocksPerGroup - 1) / BlocksPerGroup; } + UInt64 GetNumGroups2() const { return ((UInt64)NumInodes + InodesPerGroup - 1) / InodesPerGroup; } + + bool IsThereFileType() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_FILETYPE) != 0; } + bool Is64Bit() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0; } + bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; } + bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; } + + UInt64 GetPhySize() const { return NumBlocks << BlockBits; } + + bool Parse(const Byte *p); +}; + + +static int inline GetLog(UInt32 num) +{ + for (unsigned i = 0; i < 32; i++) + if (((UInt32)1 << i) == num) + return (int)i; + return -1; +} + +static bool inline IsEmptyData(const Byte *data, unsigned size) +{ + for (unsigned i = 0; i < size; i++) + if (data[i] != 0) + return false; + return true; +} + + +bool CHeader::Parse(const Byte *p) +{ + if (GetUi16(p + 0x38) != 0xEF53) + return false; + + LE_32 (0x18, BlockBits) + LE_32 (0x1C, ClusterBits) + + if (ClusterBits != 0 && BlockBits != ClusterBits) + return false; + + if (BlockBits > 16 - 10) + return false; + BlockBits += 10; + + LE_32 (0x00, NumInodes) + LE_32 (0x04, NumBlocks) + // LE_32 (0x08, NumBlocksSuper); + LE_32 (0x0C, NumFreeBlocks) + LE_32 (0x10, NumFreeInodes) + + if (NumInodes < 2 || NumInodes <= NumFreeInodes) + return false; + + UInt32 FirstDataBlock; + LE_32 (0x14, FirstDataBlock) + if (FirstDataBlock != (unsigned)(BlockBits == 10 ? 1 : 0)) + return false; + + LE_32 (0x20, BlocksPerGroup) + LE_32 (0x24, ClustersPerGroup) + + if (BlocksPerGroup != ClustersPerGroup) + return false; + if (BlocksPerGroup == 0) + return false; + if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3))) + { + // it's allowed in ext2 + // return false; + } + + LE_32 (0x28, InodesPerGroup) + + if (InodesPerGroup < 1 || InodesPerGroup > NumInodes) + return false; + + LE_32 (0x2C, MountTime) + LE_32 (0x30, WriteTime) + + // LE_16 (0x34, NumMounts); + // LE_16 (0x36, NumMountsMax); + + // LE_16 (0x3A, State); + // LE_16 (0x3C, Errors); + // LE_16 (0x3E, MinorRevLevel); + + LE_32 (0x40, LastCheckTime) + // LE_32 (0x44, CheckInterval); + LE_32 (0x48, CreatorOs) + LE_32 (0x4C, RevLevel) + + // LE_16 (0x50, DefResUid); + // LE_16 (0x52, DefResGid); + + FirstInode = k_INODE_GOOD_OLD_FIRST; + InodeSize = EXT4_GOOD_OLD_INODE_SIZE; + + if (!IsOldRev()) + { + LE_32 (0x54, FirstInode) + LE_16 (0x58, InodeSize) + if (FirstInode < k_INODE_GOOD_OLD_FIRST) + return false; + if (InodeSize > ((UInt32)1 << BlockBits) + || InodeSize < EXT_NODE_SIZE_MIN + || GetLog(InodeSize) < 0) + return false; + } + + LE_16 (0x5A, BlockGroupNr) + LE_32 (0x5C, FeatureCompat) + LE_32 (0x60, FeatureIncompat) + LE_32 (0x64, FeatureRoCompat) + + memcpy(Uuid, p + 0x68, sizeof(Uuid)); + memcpy(VolName, p + 0x78, sizeof(VolName)); + memcpy(LastMount, p + 0x88, sizeof(LastMount)); + + // LE_32 (0xC8, BitmapAlgo); + + LE_32 (0xE0, JournalInode) + + LE_16 (0xFE, GdSize) + + LE_32 (0x108, CTime) + + if (Is64Bit()) + { + HI_32(0x150, NumBlocks) + // HI_32(0x154, NumBlocksSuper); + HI_32(0x158, NumFreeBlocks) + } + + if (NumBlocks >= (UInt64)1 << (63 - BlockBits)) + return false; + + + LE_16(0x15C, MinExtraISize) + // LE_16(0x15E, WantExtraISize); + // LE_32(0x160, Flags); + // LE_16(0x164, RaidStride); + // LE_16(0x166, MmpInterval); + // LE_64(0x168, MmpBlock); + + // LogGroupsPerFlex = p[0x174]; + // ChecksumType = p[0x175]; + + LE_64 (0x178, WrittenKB) + + // LE_32(0x194, ErrorCount); + // LE_32(0x198, ErrorTime); + // LE_32(0x19C, ErrorINode); + // LE_32(0x1A0, ErrorBlock); + + if (NumBlocks < 1) + return false; + if (NumFreeBlocks > NumBlocks) + return false; + + if (GetNumGroups() != GetNumGroups2()) + return false; + + return true; +} + + +struct CGroupDescriptor +{ + UInt64 BlockBitmap; + UInt64 InodeBitmap; + UInt64 InodeTable; + UInt32 NumFreeBlocks; + UInt32 NumFreeInodes; + UInt32 DirCount; + + UInt16 Flags; + + UInt64 ExcludeBitmap; + UInt32 BlockBitmap_Checksum; + UInt32 InodeBitmap_Checksum; + UInt32 UnusedCount; + UInt16 Checksum; + + void Parse(const Byte *p, unsigned size); +}; + +void CGroupDescriptor::Parse(const Byte *p, unsigned size) +{ + LE_32 (0x00, BlockBitmap) + LE_32 (0x04, InodeBitmap) + LE_32 (0x08, InodeTable) + LE_16 (0x0C, NumFreeBlocks) + LE_16 (0x0E, NumFreeInodes) + LE_16 (0x10, DirCount) + LE_16 (0x12, Flags) + LE_32 (0x14, ExcludeBitmap) + LE_16 (0x18, BlockBitmap_Checksum) + LE_16 (0x1A, InodeBitmap_Checksum) + LE_16 (0x1C, UnusedCount) + LE_16 (0x1E, Checksum) + + if (size >= 64) + { + p += 0x20; + HI_32 (0x00, BlockBitmap) + HI_32 (0x04, InodeBitmap) + HI_32 (0x08, InodeTable) + HI_16 (0x0C, NumFreeBlocks) + HI_16 (0x0E, NumFreeInodes) + HI_16 (0x10, DirCount) + HI_16 (0x12, UnusedCount) // instead of Flags + HI_32 (0x14, ExcludeBitmap) + HI_16 (0x18, BlockBitmap_Checksum) + HI_16 (0x1A, InodeBitmap_Checksum) + // HI_16 (0x1C, Reserved); + } +} + + +static const unsigned kNodeBlockFieldSize = 60; + +struct CExtentTreeHeader +{ + UInt16 NumEntries; + UInt16 MaxEntries; + UInt16 Depth; + // UInt32 Generation; + + bool Parse(const Byte *p) + { + LE_16 (0x02, NumEntries) + LE_16 (0x04, MaxEntries) + LE_16 (0x06, Depth) + // LE_32 (0x08, Generation); + return Get16(p) == 0xF30A; // magic + } +}; + +struct CExtentIndexNode +{ + UInt32 VirtBlock; + UInt64 PhyLeaf; + + void Parse(const Byte *p) + { + LE_32 (0x00, VirtBlock) + LE_32 (0x04, PhyLeaf) + PhyLeaf |= (((UInt64)Get16(p + 8)) << 32); + // unused 16-bit field (at offset 0x0A) can be not zero in some cases. Why? + } +}; + +struct CExtent +{ + UInt32 VirtBlock; + UInt16 Len; + bool IsInited; + UInt64 PhyStart; + + UInt32 GetVirtEnd() const { return VirtBlock + Len; } + bool IsLenOK() const { return VirtBlock + Len >= VirtBlock; } + + void Parse(const Byte *p) + { + LE_32 (0x00, VirtBlock) + LE_16 (0x04, Len) + IsInited = true; + if (Len > (UInt32)0x8000) + { + IsInited = false; + Len = (UInt16)(Len - (UInt32)0x8000); + } + LE_32 (0x08, PhyStart) + UInt16 hi; + LE_16 (0x06, hi) + PhyStart |= ((UInt64)hi << 32); + } +}; + + + +struct CExtTime +{ + UInt32 Val; + UInt32 Extra; +}; + +struct CNode +{ + Int32 ParentNode; // in _refs[], -1 if not dir + int ItemIndex; // in _items[] , (set as >=0 only for if (IsDir()) + int SymLinkIndex; // in _symLinks[] + int DirIndex; // in _dirs[] + + UInt16 Mode; + UInt32 Uid; // fixed 21.02 + UInt32 Gid; // fixed 21.02 + // UInt16 Checksum; + + UInt64 FileSize; + CExtTime MTime; + CExtTime ATime; + CExtTime CTime; + CExtTime ChangeTime; + // CExtTime DTime; + + UInt64 NumBlocks; + UInt32 NumLinks; + UInt32 Flags; + + UInt32 NumLinksCalced; + + Byte Block[kNodeBlockFieldSize]; + + CNode(): + ParentNode(-1), + ItemIndex(-1), + SymLinkIndex(-1), + DirIndex(-1), + NumLinksCalced(0) + {} + + bool IsFlags_HUGE() const { return (Flags & k_NodeFlags_HUGE) != 0; } + bool IsFlags_EXTENTS() const { return (Flags & k_NodeFlags_EXTENTS) != 0; } + + bool IsDir() const { return MY_LIN_S_ISDIR(Mode); } + bool IsRegular() const { return MY_LIN_S_ISREG(Mode); } + bool IsLink() const { return MY_LIN_S_ISLNK(Mode); } + + bool Parse(const Byte *p, const CHeader &_h); +}; + + +bool CNode::Parse(const Byte *p, const CHeader &_h) +{ + MTime.Extra = 0; + ATime.Extra = 0; + CTime.Extra = 0; + CTime.Val = 0; + ChangeTime.Extra = 0; + // DTime.Extra = 0; + + LE_16 (0x00, Mode) + LE_16 (0x02, Uid) + LE_32 (0x04, FileSize) + LE_32 (0x08, ATime.Val) + LE_32 (0x0C, ChangeTime.Val) + LE_32 (0x10, MTime.Val) + // LE_32 (0x14, DTime.Val); + LE_16 (0x18, Gid) + LE_16 (0x1A, NumLinks) + + LE_32 (0x1C, NumBlocks) + LE_32 (0x20, Flags) + // LE_32 (0x24, Union osd1); + + memcpy(Block, p + 0x28, kNodeBlockFieldSize); + + // LE_32 (0x64, Generation); // File version (for NFS) + // LE_32 (0x68, ACL); + + { + UInt32 highSize; + LE_32 (0x6C, highSize) // In ext2/3 this field was named i_dir_acl + + if (IsRegular()) // do we need that check ? + FileSize |= ((UInt64)highSize << 32); + } + + // UInt32 fragmentAddress; + // LE_32 (0x70, fragmentAddress); + + // osd2 + { + // Linux; + // ext2: + // Byte FragmentNumber = p[0x74]; + // Byte FragmentSize = p[0x74 + 1]; + + // ext4: + UInt32 numBlocksHigh; + LE_16 (0x74, numBlocksHigh) + NumBlocks |= (UInt64)numBlocksHigh << 32; + + HI_16 (0x74 + 4, Uid) + HI_16 (0x74 + 6, Gid) + /* + UInt32 checksum; + LE_16 (0x74 + 8, checksum); + checksum = checksum; + */ + } + + // 0x74: Byte Union osd2[12]; + + if (_h.InodeSize > 128) + { + // InodeSize is power of 2, so the following check is not required: + // if (_h.InodeSize < 128 + 2) return false; + UInt16 extra_isize; + LE_16 (0x80, extra_isize) + if (128 + extra_isize > _h.InodeSize) + return false; + if (extra_isize >= 0x1C) + { + // UInt16 checksumUpper; + // LE_16 (0x82, checksumUpper); + LE_32 (0x84, ChangeTime.Extra) + LE_32 (0x88, MTime.Extra) + LE_32 (0x8C, ATime.Extra) + LE_32 (0x90, CTime.Val) + LE_32 (0x94, CTime.Extra) + // LE_32 (0x98, VersionHi) + } + } + + PRF(printf("size = %5d", (unsigned)FileSize)); + + return true; +} + + +struct CItem +{ + unsigned Node; // in _refs[] + int ParentNode; // in _refs[] + int SymLinkItemIndex; // in _items[], if the Node contains SymLink to existing dir + Byte Type; + + AString Name; + + CItem(): + Node(0), + ParentNode(-1), + SymLinkItemIndex(-1), + Type(k_Type_UNKNOWN) + {} + + void Clear() + { + Node = 0; + ParentNode = -1; + SymLinkItemIndex = -1; + Type = k_Type_UNKNOWN; + Name.Empty(); + } + + bool IsDir() const { return Type == k_Type_DIR; } + // bool IsNotDir() const { return Type != k_Type_DIR && Type != k_Type_UNKNOWN; } +}; + + + +static const unsigned kNumTreeLevelsMax = 6; // must be >= 3 + + +Z7_CLASS_IMP_CHandler_IInArchive_2( + IArchiveGetRawProps, + IInArchiveGetStream +) + CObjectVector _items; + CIntVector _refs; // iNode -> (index in _nodes). if (_refs[iNode] < 0), that node is not filled + CRecordVector _nodes; + CObjectVector _dirs; // each CUIntVector contains indexes in _items[] only for dir items; + AStringVector _symLinks; + AStringVector _auxItems; + int _auxSysIndex; + int _auxUnknownIndex; + + CMyComPtr _stream; + UInt64 _phySize; + bool _isArc; + bool _headersError; + bool _headersWarning; + bool _linksError; + + bool _isUTF; + + CHeader _h; + + IArchiveOpenCallback *_openCallback; + UInt64 _totalRead; + UInt64 _totalReadPrev; + + CByteBuffer _tempBufs[kNumTreeLevelsMax]; + + + HRESULT CheckProgress2() + { + const UInt64 numFiles = _items.Size(); + return _openCallback->SetCompleted(&numFiles, &_totalRead); + } + + HRESULT CheckProgress() + { + HRESULT res = S_OK; + if (_openCallback) + { + if (_totalRead - _totalReadPrev >= ((UInt32)1 << 20)) + { + _totalReadPrev = _totalRead; + res = CheckProgress2(); + } + } + return res; + } + + + int GetParentAux(const CItem &item) const + { + if (item.Node < _h.FirstInode && _auxSysIndex >= 0) + return _auxSysIndex; + return _auxUnknownIndex; + } + + HRESULT SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size); + HRESULT ParseDir(const Byte *data, size_t size, unsigned iNodeDir); + int FindTargetItem_for_SymLink(unsigned dirNode, const AString &path) const; + + HRESULT FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector &blocks); + HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector &blocks); + HRESULT FillExtents(const Byte *p, size_t size, CRecordVector &extents, int parentDepth); + + HRESULT GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream); + HRESULT ExtractNode(unsigned nodeIndex, CByteBuffer &data); + + void ClearRefs(); + HRESULT Open2(IInStream *inStream); + + void GetPath(unsigned index, AString &s) const; + bool GetPackSize(unsigned index, UInt64 &res) const; +}; + + + +HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned iNodeDir) +{ + bool isThereSelfLink = false; + + PRF(printf("\n\n========= node = %5d size = %5d", (unsigned)iNodeDir, (unsigned)size)); + + CNode &nodeDir = _nodes[_refs[iNodeDir]]; + nodeDir.DirIndex = (int)_dirs.Size(); + CUIntVector &dir = _dirs.AddNew(); + int parentNode = -1; + + CItem item; + + for (;;) + { + if (size == 0) + break; + if (size < 8) + return S_FALSE; + UInt32 iNode; + LE_32 (0x00, iNode) + unsigned recLen; + LE_16 (0x04, recLen) + const unsigned nameLen = p[6]; + const Byte type = p[7]; + + if (recLen > size) + return S_FALSE; + if (nameLen + 8 > recLen) + return S_FALSE; + + if (iNode >= _refs.Size()) + return S_FALSE; + + item.Clear(); + + if (_h.IsThereFileType()) + item.Type = type; + else if (type != 0) + return S_FALSE; + + item.ParentNode = (int)iNodeDir; + item.Node = iNode; + item.Name.SetFrom_CalcLen((const char *)(p + 8), nameLen); + + p += recLen; + size -= recLen; + + if (item.Name.Len() != nameLen) + return S_FALSE; + + if (_isUTF) + { + // 21.07 : we force UTF8 + // _isUTF = CheckUTF8_AString(item.Name); + } + + if (iNode == 0) + { + /* + ext3 deleted?? + if (item.Name.Len() != 0) + return S_FALSE; + */ + + PRF(printf("\n EMPTY %6d %d %s", (unsigned)recLen, (unsigned)type, (const char *)item.Name)); + if (type == 0xDE) + { + // checksum + } + continue; + } + + const int nodeIndex = _refs[iNode]; + if (nodeIndex < 0) + return S_FALSE; + CNode &node = _nodes[nodeIndex]; + + if (_h.IsThereFileType() && type != 0) + { + if (type >= Z7_ARRAY_SIZE(k_TypeToMode)) + return S_FALSE; + if (k_TypeToMode[type] != (node.Mode & MY_LIN_S_IFMT)) + return S_FALSE; + } + + node.NumLinksCalced++; + + PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR " : " ", (unsigned)item.Node, (const char *)item.Name)); + + if (item.Name[0] == '.') + { + if (item.Name[1] == 0) + { + if (isThereSelfLink) + return S_FALSE; + isThereSelfLink = true; + if (iNode != iNodeDir) + return S_FALSE; + continue; + } + + if (item.Name[1] == '.' && item.Name[2] == 0) + { + if (parentNode >= 0) + return S_FALSE; + if (!node.IsDir()) + return S_FALSE; + if (iNode == iNodeDir && iNode != k_INODE_ROOT) + return S_FALSE; + + parentNode = (int)iNode; + + if (nodeDir.ParentNode < 0) + nodeDir.ParentNode = (int)iNode; + else if ((unsigned)nodeDir.ParentNode != iNode) + return S_FALSE; + + continue; + } + } + + if (iNode == iNodeDir) + return S_FALSE; + + if (parentNode < 0) + return S_FALSE; + + if (node.IsDir()) + { + if (node.ParentNode < 0) + node.ParentNode = (int)iNodeDir; + else if ((unsigned)node.ParentNode != iNodeDir) + return S_FALSE; + const unsigned itemIndex = _items.Size(); + dir.Add(itemIndex); + node.ItemIndex = (int)itemIndex; + } + + _items.Add(item); + } + + if (parentNode < 0 || !isThereSelfLink) + return S_FALSE; + + return S_OK; +} + + +static int CompareItemsNames(const unsigned *p1, const unsigned *p2, void *param) +{ + const CObjectVector &items = *(const CObjectVector *)param; + return strcmp(items[*p1].Name, items[*p2].Name); +} + + +int CHandler::FindTargetItem_for_SymLink(unsigned iNode, const AString &path) const +{ + unsigned pos = 0; + + if (path.IsEmpty()) + return -1; + + if (path[0] == '/') + { + iNode = k_INODE_ROOT; + if (iNode >= _refs.Size()) + return -1; + pos = 1; + } + + AString s; + + while (pos != path.Len()) + { + const CNode &node = _nodes[_refs[iNode]]; + const int slash = path.Find('/', pos); + + if (slash < 0) + { + s = path.Ptr(pos); + pos = path.Len(); + } + else + { + s.SetFrom(path.Ptr(pos), (unsigned)slash - pos); + pos = (unsigned)slash + 1; + } + + if (s[0] == '.') + { + if (s[1] == 0) + continue; + else if (s[1] == '.' && s[2] == 0) + { + if (node.ParentNode < 0) + return -1; + if (iNode == k_INODE_ROOT) + return -1; + iNode = (unsigned)node.ParentNode; + continue; + } + } + + if (node.DirIndex < 0) + return -1; + + const CUIntVector &dir = _dirs[node.DirIndex]; + + /* + for (unsigned i = 0;; i++) + { + if (i >= dir.Size()) + return -1; + const CItem &item = _items[dir[i]]; + if (item.Name == s) + { + iNode = item.Node; + break; + } + } + */ + + unsigned left = 0, right = dir.Size(); + for (;;) + { + if (left == right) + return -1; + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const CItem &item = _items[dir[mid]]; + const int comp = strcmp(s, item.Name); + if (comp == 0) + { + iNode = item.Node; + break; + } + if (comp < 0) + right = mid; + else + left = mid + 1; + } + } + + return _nodes[_refs[iNode]].ItemIndex; +} + + +HRESULT CHandler::SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size) +{ + if (block == 0 || block >= _h.NumBlocks) + return S_FALSE; + if (((size + ((size_t)1 << _h.BlockBits) - 1) >> _h.BlockBits) > _h.NumBlocks - block) + return S_FALSE; + RINOK(InStream_SeekSet(inStream, (UInt64)block << _h.BlockBits)) + _totalRead += size; + return ReadStream_FALSE(inStream, data, size); +} + + +static const unsigned kHeaderSize = 2 * 1024; +static const unsigned kHeaderDataOffset = 1024; + +HRESULT CHandler::Open2(IInStream *inStream) +{ + { + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)) + if (!_h.Parse(buf + kHeaderDataOffset)) + return S_FALSE; + if (_h.BlockGroupNr != 0) + return S_FALSE; // it's just copy of super block + } + + { + // ---------- Read groups and nodes ---------- + + unsigned numGroups; + { + const UInt64 numGroups64 = _h.GetNumGroups(); + if (numGroups64 > (UInt32)1 << 31) + return S_FALSE; + numGroups = (unsigned)numGroups64; + } + + unsigned gdBits = 5; + if (_h.Is64Bit()) + { + if (_h.GdSize != 64) + return S_FALSE; + gdBits = 6; + } + + _isArc = true; + _phySize = _h.GetPhySize(); + + if (_openCallback) + { + RINOK(_openCallback->SetTotal(NULL, &_phySize)) + } + + UInt64 fileSize = 0; + RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) + + CRecordVector groups; + + { + // ---------- Read groups ---------- + + CByteBuffer gdBuf; + const size_t gdBufSize = (size_t)numGroups << gdBits; + if ((gdBufSize >> gdBits) != numGroups) + return S_FALSE; + gdBuf.Alloc(gdBufSize); + RINOK(SeekAndRead(inStream, (_h.BlockBits <= 10 ? 2 : 1), gdBuf, gdBufSize)) + + for (unsigned i = 0; i < numGroups; i++) + { + CGroupDescriptor gd; + + const Byte *p = gdBuf + ((size_t)i << gdBits); + const unsigned gd_Size = (unsigned)1 << gdBits; + gd.Parse(p, gd_Size); + + if (_h.UseMetadataChecksum()) + { + // use CRC32c + } + else if (_h.UseGdtChecksum()) + { + UInt32 crc = Crc16Calc(_h.Uuid, sizeof(_h.Uuid)); + Byte i_le[4]; + SetUi32(i_le, i) + crc = Crc16Update(crc, i_le, 4); + crc = Crc16Update(crc, p, 32 - 2); + if (gd_Size != 32) + crc = Crc16Update(crc, p + 32, gd_Size - 32); + if (crc != gd.Checksum) + return S_FALSE; + } + + groups.Add(gd); + } + } + + { + // ---------- Read nodes ---------- + + if (_h.NumInodes < _h.NumFreeInodes) + return S_FALSE; + + UInt32 numNodes = _h.InodesPerGroup; + if (numNodes > _h.NumInodes) + numNodes = _h.NumInodes; + const size_t nodesDataSize = (size_t)numNodes * _h.InodeSize; + + if (nodesDataSize / _h.InodeSize != numNodes) + return S_FALSE; + + // that code to reduce false detecting cases + if (nodesDataSize > fileSize) + { + if (numNodes > (1 << 24)) + return S_FALSE; + } + + const UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1; + // numReserveInodes = _h.NumInodes + 1; + if (numReserveInodes != 0) + { + _nodes.Reserve(numReserveInodes); + _refs.Reserve(numReserveInodes); + } + + CByteBuffer nodesData; + nodesData.Alloc(nodesDataSize); + + CByteBuffer nodesMap; + const size_t blockSize = (size_t)1 << _h.BlockBits; + nodesMap.Alloc(blockSize); + + unsigned globalNodeIndex = 0; + // unsigned numEmpty = 0; + unsigned numEmpty_in_Maps = 0; + + FOR_VECTOR (gi, groups) + { + if (globalNodeIndex >= _h.NumInodes) + break; + + const CGroupDescriptor &gd = groups[gi]; + + PRF(printf("\n\ng%6d block = %6x\n", gi, (unsigned)gd.InodeTable)); + + RINOK(SeekAndRead(inStream, gd.InodeBitmap, nodesMap, blockSize)) + RINOK(SeekAndRead(inStream, gd.InodeTable, nodesData, nodesDataSize)) + + unsigned numEmpty_in_Map = 0; + + for (size_t n = 0; n < numNodes && globalNodeIndex < _h.NumInodes; n++, globalNodeIndex++) + { + if ((nodesMap[n >> 3] & ((unsigned)1 << (n & 7))) == 0) + { + numEmpty_in_Map++; + continue; + } + + const Byte *p = nodesData + (size_t)n * _h.InodeSize; + if (IsEmptyData(p, _h.InodeSize)) + { + if (globalNodeIndex + 1 >= _h.FirstInode) + { + _headersError = true; + // return S_FALSE; + } + continue; + } + + CNode node; + + PRF(printf("\nnode = %5d ", (unsigned)n)); + + if (!node.Parse(p, _h)) + return S_FALSE; + + // PRF(printf("\n %6d", (unsigned)n)); + /* + SetUi32(p + 0x7C, 0) + SetUi32(p + 0x82, 0) + + UInt32 crc = Crc32C_Calc(_h.Uuid, sizeof(_h.Uuid)); + Byte i_le[4]; + SetUi32(i_le, n); + crc = Crc32C_Update(crc, i_le, 4); + crc = Crc32C_Update(crc, p, _h.InodeSize); + if (crc != node.Checksum) return S_FALSE; + */ + + while (_refs.Size() < globalNodeIndex + 1) + { + // numEmpty++; + _refs.Add(-1); + } + + _refs.Add((int)_nodes.Add(node)); + } + + + numEmpty_in_Maps += numEmpty_in_Map; + + if (numEmpty_in_Map != gd.NumFreeInodes) + { + _headersWarning = true; + // return S_FALSE; + } + } + + if (numEmpty_in_Maps != _h.NumFreeInodes) + { + // some ext2 examples has incorrect value in _h.NumFreeInodes. + // so we disable check; + _headersWarning = true; + } + + if (_refs.Size() <= k_INODE_ROOT) + return S_FALSE; + + // printf("\n numReserveInodes = %6d, _refs.Size() = %d, numEmpty = %7d\n", numReserveInodes, _refs.Size(), (unsigned)numEmpty); + } + } + + _stream = inStream; // we need stream for dir nodes + + { + // ---------- Read Dirs ---------- + + CByteBuffer dataBuf; + + FOR_VECTOR (i, _refs) + { + const int nodeIndex = _refs[i]; + { + if (nodeIndex < 0) + continue; + const CNode &node = _nodes[nodeIndex]; + if (!node.IsDir()) + continue; + } + RINOK(ExtractNode((unsigned)nodeIndex, dataBuf)) + if (dataBuf.Size() == 0) + { + // _headersError = true; + return S_FALSE; + } + else + { + RINOK(ParseDir(dataBuf, dataBuf.Size(), i)) + } + RINOK(CheckProgress()) + } + + const int ref = _refs[k_INODE_ROOT]; + if (ref < 0 || _nodes[ref].ParentNode != k_INODE_ROOT) + return S_FALSE; + } + + { + // ---------- Check NumLinks and unreferenced dir nodes ---------- + + FOR_VECTOR (i, _refs) + { + int nodeIndex = _refs[i]; + if (nodeIndex < 0) + continue; + const CNode &node = _nodes[nodeIndex]; + + if (node.NumLinks != node.NumLinksCalced) + { + if (node.NumLinks != 1 || node.NumLinksCalced != 0 + // ) && i >= _h.FirstInode + ) + { + _linksError = true; + // return S_FALSE; + } + } + + if (!node.IsDir()) + continue; + + if (node.ParentNode < 0) + { + if (i >= _h.FirstInode) + return S_FALSE; + continue; + } + } + } + + { + // ---------- Check that there is no loops in parents list ---------- + + unsigned numNodes = _refs.Size(); + CIntArr UsedByNode(numNodes); + { + { + for (unsigned i = 0; i < numNodes; i++) + UsedByNode[i] = -1; + } + } + + FOR_VECTOR (i, _refs) + { + { + int nodeIndex = _refs[i]; + if (nodeIndex < 0) + continue; + const CNode &node = _nodes[nodeIndex]; + if (node.ParentNode < 0 // not dir + || i == k_INODE_ROOT) + continue; + } + + unsigned c = i; + + for (;;) + { + const int nodeIndex = _refs[c]; + if (nodeIndex < 0) + return S_FALSE; + CNode &node = _nodes[nodeIndex]; + + if (UsedByNode[c] != -1) + { + if ((unsigned)UsedByNode[c] == i) + return S_FALSE; + break; + } + + UsedByNode[c] = (int)i; + if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT) + break; + if ((unsigned)node.ParentNode == i) + return S_FALSE; + c = (unsigned)node.ParentNode; + } + } + } + + { + // ---------- Fill SymLinks data ---------- + + AString s; + CByteBuffer data; + + unsigned i; + for (i = 0; i < _refs.Size(); i++) + { + const int nodeIndex = _refs[i]; + if (nodeIndex < 0) + continue; + CNode &node = _nodes[nodeIndex]; + if (!node.IsLink()) + continue; + if (node.FileSize > ((UInt32)1 << 14)) + continue; + if (ExtractNode((unsigned)nodeIndex, data) == S_OK && data.Size() != 0) + { + s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size()); + if (s.Len() == data.Size()) + node.SymLinkIndex = (int)_symLinks.Add(s); + RINOK(CheckProgress()) + } + } + + for (i = 0; i < _dirs.Size(); i++) + { + _dirs[i].Sort(CompareItemsNames, (void *)&_items); + } + + unsigned prev = 0; + unsigned complex = 0; + + for (i = 0; i < _items.Size(); i++) + { + CItem &item = _items[i]; + const int sym = _nodes[_refs[item.Node]].SymLinkIndex; + if (sym >= 0 && item.ParentNode >= 0) + { + item.SymLinkItemIndex = FindTargetItem_for_SymLink((unsigned)item.ParentNode, _symLinks[sym]); + if (_openCallback) + { + complex++; + if (complex - prev >= (1 << 10)) + { + prev = complex; + RINOK(CheckProgress2()) + } + } + } + } + } + + { + // ---------- Add items and aux folders for unreferenced files ---------- + + bool useSys = false; + bool useUnknown = false; + + FOR_VECTOR (i, _refs) + { + const int nodeIndex = _refs[i]; + if (nodeIndex < 0) + continue; + const CNode &node = _nodes[nodeIndex]; + + if (node.NumLinksCalced == 0 /* || i > 100 && i < 150 */) // for debug + { + CItem item; + item.Node = i; + + // we don't know how to work with k_INODE_RESIZE node (strange FileSize and Block values). + // so we ignore it; + + if (i == k_INODE_RESIZE) + continue; + + if (node.FileSize == 0) + continue; + + if (i < _h.FirstInode) + { + if (item.Node < Z7_ARRAY_SIZE(k_SysInode_Names)) + item.Name = k_SysInode_Names[item.Node]; + useSys = true; + } + else + useUnknown = true; + + if (item.Name.IsEmpty()) + item.Name.Add_UInt32(item.Node); + + _items.Add(item); + } + } + + if (useSys) + _auxSysIndex = (int)_auxItems.Add((AString)"[SYS]"); + if (useUnknown) + _auxUnknownIndex = (int)_auxItems.Add((AString)"[UNKNOWN]"); + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + HRESULT res; + try + { + _openCallback = callback; + res = Open2(stream); + } + catch(...) + { + ClearRefs(); + throw; + } + + if (res != S_OK) + { + ClearRefs(); + return res; + } + _stream = stream; + } + return S_OK; + COM_TRY_END +} + + +void CHandler::ClearRefs() +{ + _stream.Release(); + _items.Clear(); + _nodes.Clear(); + _refs.Clear(); + _auxItems.Clear(); + _symLinks.Clear(); + _dirs.Clear(); + _auxSysIndex = -1; + _auxUnknownIndex = -1; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalRead = 0; + _totalReadPrev = 0; + _phySize = 0; + _isArc = false; + _headersError = false; + _headersWarning = false; + _linksError = false; + _isUTF = true; + + ClearRefs(); + return S_OK; +} + + +static void ChangeSeparatorsInName(char *s, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + { + char c = s[i]; + if (c == CHAR_PATH_SEPARATOR || c == '/') + s[i] = '_'; + } +} + + +void CHandler::GetPath(unsigned index, AString &s) const +{ + s.Empty(); + + if (index >= _items.Size()) + { + s = _auxItems[index - _items.Size()]; + return; + } + + for (;;) + { + const CItem &item = _items[index]; + if (!s.IsEmpty()) + s.InsertAtFront(CHAR_PATH_SEPARATOR); + s.Insert(0, item.Name); + // 18.06 + ChangeSeparatorsInName(s.GetBuf(), item.Name.Len()); + + if (item.ParentNode == k_INODE_ROOT) + return; + + if (item.ParentNode < 0) + { + int aux = GetParentAux(item); + if (aux < 0) + break; + s.InsertAtFront(CHAR_PATH_SEPARATOR); + s.Insert(0, _auxItems[aux]); + return; + } + + const CNode &node = _nodes[_refs[item.ParentNode]]; + if (node.ItemIndex < 0) + return; + index = (unsigned)node.ItemIndex; + + if (s.Len() > ((UInt32)1 << 16)) + { + s.Insert(0, "[LONG]" STRING_PATH_SEPARATOR); + return; + } + } +} + + +bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack) const +{ + if (index >= _items.Size()) + { + totalPack = 0; + return false; + } + + const CItem &item = _items[index]; + const CNode &node = _nodes[_refs[item.Node]]; + + // if (!node.IsFlags_EXTENTS()) + { + totalPack = (UInt64)node.NumBlocks << (node.IsFlags_HUGE() ? _h.BlockBits : 9); + return true; + } + + /* + CExtentTreeHeader eth; + if (!eth.Parse(node.Block)) + return false; + if (eth.NumEntries > 3) + return false; + if (!eth.Depth == 0) + return false; + + UInt64 numBlocks = 0; + { + for (unsigned i = 0; i < eth.NumEntries; i++) + { + CExtent e; + e.Parse(node.Block + 12 + i * 12); + // const CExtent &e = node.leafs[i]; + if (e.IsInited) + numBlocks += e.Len; + } + } + + totalPack = numBlocks << _h.BlockBits; + return true; + */ +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size() + _auxItems.Size(); + return S_OK; +} + +enum +{ + kpidMountTime = kpidUserDefined, + kpidLastCheckTime, + kpidRevision, + kpidINodeSize, + kpidLastMount, + kpidFeatureIncompat, + kpidFeatureRoCompat, + kpidWrittenKB + + // kpidGroupSize, + + // kpidChangeTime = kpidUserDefined + 256, + // kpidDTime +}; + +static const UInt32 kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidPosixAttrib, + kpidMTime, + kpidCTime, + kpidATime, + // kpidChangeTime, + // kpidDTime, + kpidINode, + kpidLinks, + kpidSymLink, + kpidCharacts, + kpidUserId, + kpidGroupId +}; + + +static const CStatProp kArcProps[] = +{ + { NULL, kpidHeadersSize, VT_BSTR }, + // { NULL, kpidFileSystem, VT_BSTR }, + // kpidMethod, + { NULL, kpidClusterSize, VT_UI4 }, + // { "Group Size", kpidGroupSize, VT_UI8 }, + { NULL, kpidFreeSpace, VT_UI8 }, + + { NULL, kpidMTime, VT_FILETIME }, + { NULL, kpidCTime, VT_FILETIME }, + { "Mount Time", kpidMountTime, VT_FILETIME }, + { "Last Check Time", kpidLastCheckTime, VT_FILETIME }, + + { NULL, kpidHostOS, VT_BSTR}, + { "Revision", kpidRevision, VT_UI4}, + { "inode Size", kpidINodeSize, VT_UI4}, + { NULL, kpidCodePage, VT_BSTR}, + { NULL, kpidVolumeName, VT_BSTR}, + { "Last Mounted", kpidLastMount, VT_BSTR}, + { NULL, kpidId, VT_BSTR}, + { NULL, kpidCharacts, VT_BSTR }, + { "Incompatible Features", kpidFeatureIncompat, VT_BSTR }, + { "Readonly-compatible Features", kpidFeatureRoCompat, VT_BSTR }, + { "Written KiB", kpidWrittenKB, VT_UI8 } +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVariant &prop) +{ + UString u; + AString a; + a.SetFrom_CalcLen(s, size); + if (!isUTF || !ConvertUTF8ToUnicode(a, u)) + MultiByteToUnicodeString2(u, a); + prop = u; +} + +static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop) +{ + if (val != 0) + PropVariant_SetFrom_UnixTime(prop, val); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + + NCOM::CPropVariant prop; + + switch (propID) + { + /* + case kpidFileSystem: + { + AString res = "Ext4"; + prop = res; + break; + } + */ + + case kpidIsTree: prop = true; break; + case kpidIsAux: prop = true; break; + case kpidINode: prop = true; break; + + case kpidClusterSize: prop = (UInt32)1 << _h.BlockBits; break; + // case kpidGroupSize: prop = (UInt64)_h.BlocksPerGroup << _h.BlockBits; break; + + case kpidFreeSpace: prop = (UInt64)_h.NumFreeBlocks << _h.BlockBits; break; + + case kpidCTime: UnixTimeToProp(_h.CTime, prop); break; + case kpidMTime: UnixTimeToProp(_h.WriteTime, prop); break; + case kpidMountTime: UnixTimeToProp(_h.MountTime, prop); break; + case kpidLastCheckTime: UnixTimeToProp(_h.LastCheckTime, prop); break; + + case kpidHostOS: + { + TYPE_TO_PROP(kHostOS, _h.CreatorOs, prop); + break; + } + + case kpidRevision: prop = _h.RevLevel; break; + + case kpidINodeSize: prop = (UInt32)_h.InodeSize; break; + + case kpidId: + { + if (!IsEmptyData(_h.Uuid, sizeof(_h.Uuid))) + { + char s[sizeof(_h.Uuid) * 2 + 2]; + ConvertDataToHex_Lower(s, _h.Uuid, sizeof(_h.Uuid)); + prop = s; + } + break; + } + + case kpidCodePage: if (_isUTF) prop = "UTF-8"; break; + + case kpidShortComment: + case kpidVolumeName: + StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break; + + case kpidLastMount: StringToProp(_isUTF, _h.LastMount, sizeof(_h.LastMount), prop); break; + + case kpidCharacts: FLAGS_TO_PROP(g_FeatureCompat_Flags, _h.FeatureCompat, prop); break; + case kpidFeatureIncompat: FLAGS_TO_PROP(g_FeatureIncompat_Flags, _h.FeatureIncompat, prop); break; + case kpidFeatureRoCompat: FLAGS_TO_PROP(g_FeatureRoCompat_Flags, _h.FeatureRoCompat, prop); break; + case kpidWrittenKB: if (_h.WrittenKB != 0) prop = _h.WrittenKB; break; + + case kpidPhySize: prop = _phySize; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_linksError) v |= kpv_ErrorFlags_HeadersError; + if (_headersError) v |= kpv_ErrorFlags_HeadersError; + if (!_stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + + case kpidWarningFlags: + { + UInt32 v = 0; + if (_headersWarning) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + + COM_TRY_END +} + + +/* +static const Byte kRawProps[] = +{ + // kpidSha1, +}; +*/ + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + // *numProps = Z7_ARRAY_SIZE(kRawProps); + *numProps = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) +{ + // *propID = kRawProps[index]; + *propID = 0; + *name = NULL; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + + if (index >= _items.Size()) + return S_OK; + + const CItem &item = _items[index]; + + if (item.ParentNode < 0) + { + const int aux = GetParentAux(item); + if (aux >= 0) + *parent = _items.Size() + (unsigned)aux; + } + else + { + const int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex; + if (itemIndex >= 0) + *parent = (unsigned)itemIndex; + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidName && _isUTF) + { + if (index < _items.Size()) + { + const AString &s = _items[index].Name; + if (!s.IsEmpty()) + { + *data = (void *)(const char *)s; + *dataSize = (UInt32)s.Len() + 1; + *propType = NPropDataType::kUtf8z; + } + return S_OK; + } + else + { + const AString &s = _auxItems[index - _items.Size()]; + { + *data = (void *)(const char *)s; + *dataSize = (UInt32)s.Len() + 1; + *propType = NPropDataType::kUtf8z; + } + return S_OK; + } + } + + return S_OK; +} + + +static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop) +{ + if (t.Val == 0 && t.Extra == 0) + return; + + FILETIME ft; + unsigned low100ns = 0; + // if (t.Extra != 0) + { + // 1901-2446 : + Int64 v = (Int64)(Int32)t.Val; + v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp + UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v); + const UInt32 ns = (t.Extra >> 2); + if (ns < 1000000000) + { + ft64 += ns / 100; + low100ns = (unsigned)(ns % 100); + } + ft.dwLowDateTime = (DWORD)ft64; + ft.dwHighDateTime = (DWORD)(ft64 >> 32); + } + /* + else + { + // 1901-2038 : that code is good for ext4 and compatibility with Extra + NTime::UnixTime64ToFileTime((Int32)t.Val, ft); // for + + // 1970-2106 : that code is good if timestamp is used as unsigned 32-bit + // are there such systems? + // NTime::UnixTimeToFileTime(t.Val, ft); // for + } + */ + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns); +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + if (index >= _items.Size()) + { + switch (propID) + { + case kpidPath: + case kpidName: + { + prop = _auxItems[index - _items.Size()]; + break; + } + case kpidIsDir: prop = true; break; + case kpidIsAux: prop = true; break; + } + } + else + { + + const CItem &item = _items[index]; + const CNode &node = _nodes[_refs[item.Node]]; + bool isDir = node.IsDir(); + + switch (propID) + { + case kpidPath: + { + UString u; + { + AString s; + GetPath(index, s); + if (!_isUTF || !ConvertUTF8ToUnicode(s, u)) + MultiByteToUnicodeString2(u, s); + } + prop = u; + break; + } + + case kpidName: + { + { + UString u; + { + if (!_isUTF || !ConvertUTF8ToUnicode(item.Name, u)) + MultiByteToUnicodeString2(u, item.Name); + } + prop = u; + } + break; + } + + case kpidIsDir: + { + bool isDir2 = isDir; + if (item.SymLinkItemIndex >= 0) + isDir2 = _nodes[_refs[_items[item.SymLinkItemIndex].Node]].IsDir(); + prop = isDir2; + break; + } + + case kpidSize: if (!isDir) prop = node.FileSize; break; + + case kpidPackSize: + if (!isDir) + { + UInt64 size; + if (GetPackSize(index, size)) + prop = size; + } + break; + + case kpidPosixAttrib: + { + /* + if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode)) + prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; + */ + prop = (UInt32)(node.Mode); + break; + } + + case kpidMTime: ExtTimeToProp(node.MTime, prop); break; + case kpidCTime: ExtTimeToProp(node.CTime, prop); break; + case kpidATime: ExtTimeToProp(node.ATime, prop); break; + // case kpidDTime: ExtTimeToProp(node.DTime, prop); break; + case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break; + case kpidUserId: prop = (UInt32)node.Uid; break; + case kpidGroupId: prop = (UInt32)node.Gid; break; + case kpidLinks: prop = node.NumLinks; break; + case kpidINode: prop = (UInt32)item.Node; break; + case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break; + case kpidCharacts: FLAGS_TO_PROP(g_NodeFlags, (UInt32)node.Flags, prop); break; + + case kpidSymLink: + { + if (node.SymLinkIndex >= 0) + { + UString u; + { + const AString &s = _symLinks[node.SymLinkIndex]; + if (!_isUTF || !ConvertUTF8ToUnicode(s, u)) + MultiByteToUnicodeString2(u, s); + } + prop = u; + } + break; + } + } + + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_CLASS_IMP_IInStream(CClusterInStream2 +) + UInt64 _virtPos; + UInt64 _physPos; + UInt32 _curRem; +public: + unsigned BlockBits; + UInt64 Size; + CMyComPtr Stream; + CRecordVector Vector; + + HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); } + + HRESULT InitAndSeek() + { + _curRem = 0; + _virtPos = 0; + _physPos = 0; + if (Vector.Size() > 0) + { + _physPos = (Vector[0] << BlockBits); + return SeekToPhys(); + } + return S_OK; + } +}; + + +Z7_COM7F_IMF(CClusterInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= Size) + return S_OK; + { + UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + + if (_curRem == 0) + { + const UInt32 blockSize = (UInt32)1 << BlockBits; + const UInt32 virtBlock = (UInt32)(_virtPos >> BlockBits); + const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + const UInt32 phyBlock = Vector[virtBlock]; + + if (phyBlock == 0) + { + UInt32 cur = blockSize - offsetInBlock; + if (cur > size) + cur = size; + memset(data, 0, cur); + _virtPos += cur; + if (processedSize) + *processedSize = cur; + return S_OK; + } + + UInt64 newPos = ((UInt64)phyBlock << BlockBits) + offsetInBlock; + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()) + } + + _curRem = blockSize - offsetInBlock; + + for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) + _curRem += (UInt32)1 << BlockBits; + } + + if (size > _curRem) + size = _curRem; + HRESULT res = Stream->Read(data, size, &size); + if (processedSize) + *processedSize = size; + _physPos += size; + _virtPos += size; + _curRem -= size; + return res; +} + +Z7_COM7F_IMF(CClusterInStream2::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + if (_virtPos != (UInt64)offset) + _curRem = 0; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + +Z7_CLASS_IMP_IInStream( + CExtInStream +) + UInt64 _virtPos; + UInt64 _phyPos; +public: + unsigned BlockBits; + UInt64 Size; + CMyComPtr Stream; + CRecordVector Extents; + + HRESULT StartSeek() + { + _virtPos = 0; + _phyPos = 0; + return InStream_SeekSet(Stream, _phyPos); + } +}; + +Z7_COM7F_IMF(CExtInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= Size) + return S_OK; + { + UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + + UInt32 blockIndex = (UInt32)(_virtPos >> BlockBits); + + unsigned left = 0, right = Extents.Size(); + for (;;) + { + unsigned mid = (left + right) / 2; + if (mid == left) + break; + if (blockIndex < Extents[mid].VirtBlock) + right = mid; + else + left = mid; + } + + { + const CExtent &extent = Extents[left]; + if (blockIndex < extent.VirtBlock) + return E_FAIL; + UInt32 bo = blockIndex - extent.VirtBlock; + if (bo >= extent.Len) + return E_FAIL; + + UInt32 offset = ((UInt32)_virtPos & (((UInt32)1 << BlockBits) - 1)); + UInt32 remBlocks = extent.Len - bo; + UInt64 remBytes = ((UInt64)remBlocks << BlockBits); + remBytes -= offset; + + if (size > remBytes) + size = (UInt32)remBytes; + + if (!extent.IsInited) + { + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + const UInt64 phyBlock = extent.PhyStart + bo; + const UInt64 phy = (phyBlock << BlockBits) + offset; + + if (phy != _phyPos) + { + RINOK(InStream_SeekSet(Stream, phy)) + _phyPos = phy; + } + + UInt32 realProcessSize = 0; + + const HRESULT res = Stream->Read(data, size, &realProcessSize); + + _phyPos += realProcessSize; + _virtPos += realProcessSize; + if (processedSize) + *processedSize = realProcessSize; + return res; + } +} + + +Z7_COM7F_IMF(CExtInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + + +HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector &blocks) +{ + const size_t blockSize = (size_t)1 << _h.BlockBits; + CByteBuffer &tempBuf = _tempBufs[level]; + tempBuf.Alloc(blockSize); + + PRF2(printf("\n level = %d, block = %7d", level, (unsigned)block)); + + RINOK(SeekAndRead(_stream, block, tempBuf, blockSize)) + + const Byte *p = tempBuf; + size_t num = (size_t)1 << (_h.BlockBits - 2); + + for (size_t i = 0; i < num; i++) + { + if (blocks.Size() == numBlocks) + break; + UInt32 val = GetUi32(p + 4 * i); + if (val >= _h.NumBlocks) + return S_FALSE; + + if (level != 0) + { + if (val == 0) + { + /* + size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level)); + PRF2(printf("\n num empty = %3d", (unsigned)num)); + for (size_t k = 0; k < num; k++) + { + blocks.Add(0); + if (blocks.Size() == numBlocks) + return S_OK; + } + continue; + */ + return S_FALSE; + } + + RINOK(FillFileBlocks2(val, level - 1, numBlocks, blocks)) + continue; + } + + PRF2(printf("\n i = %3d, blocks.Size() = %6d, block = %5d ", i, blocks.Size(), (unsigned)val)); + + PRF(printf("\n i = %3d, start = %5d ", (unsigned)i, (unsigned)val)); + + blocks.Add(val); + } + + return S_OK; +} + + +static const unsigned kNumDirectNodeBlocks = 12; + +HRESULT CHandler::FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector &blocks) +{ + // ext2 supports zero blocks (blockIndex == 0). + + blocks.ClearAndReserve(numBlocks); + + for (unsigned i = 0; i < kNumDirectNodeBlocks; i++) + { + if (i == numBlocks) + return S_OK; + UInt32 val = GetUi32(p + 4 * i); + if (val >= _h.NumBlocks) + return S_FALSE; + blocks.Add(val); + } + + for (unsigned level = 0; level < 3; level++) + { + if (blocks.Size() == numBlocks) + break; + UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + level)); + if (val >= _h.NumBlocks) + return S_FALSE; + + if (val == 0) + { + /* + size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level + 1)); + for (size_t k = 0; k < num; k++) + { + blocks.Add(0); + if (blocks.Size() == numBlocks) + return S_OK; + } + continue; + */ + return S_FALSE; + } + + RINOK(FillFileBlocks2(val, level, numBlocks, blocks)) + } + + return S_OK; +} + + +static void AddSkipExtents(CRecordVector &extents, UInt32 virtBlock, UInt32 numBlocks) +{ + while (numBlocks != 0) + { + UInt32 len = numBlocks; + const UInt32 kLenMax = (UInt32)1 << 15; + if (len > kLenMax) + len = kLenMax; + CExtent e; + e.VirtBlock = virtBlock; + e.Len = (UInt16)len; + e.IsInited = false; + e.PhyStart = 0; + extents.Add(e); + virtBlock += len; + numBlocks -= len; + } +} + +static bool UpdateExtents(CRecordVector &extents, UInt32 block) +{ + if (extents.IsEmpty()) + { + if (block == 0) + return true; + AddSkipExtents(extents, 0, block); + return true; + } + + const CExtent &prev = extents.Back(); + if (block < prev.VirtBlock) + return false; + UInt32 prevEnd = prev.GetVirtEnd(); + if (block == prevEnd) + return true; + AddSkipExtents(extents, prevEnd, block - prevEnd); + return true; +} + + +HRESULT CHandler::FillExtents(const Byte *p, size_t size, CRecordVector &extents, int parentDepth) +{ + CExtentTreeHeader eth; + if (!eth.Parse(p)) + return S_FALSE; + + if (parentDepth >= 0 && eth.Depth != parentDepth - 1) // (eth.Depth >= parentDepth) + return S_FALSE; + + if (12 + 12 * (size_t)eth.NumEntries > size) + return S_FALSE; + + if (eth.Depth >= kNumTreeLevelsMax) + return S_FALSE; + + if (eth.Depth == 0) + { + for (unsigned i = 0; i < eth.NumEntries; i++) + { + CExtent e; + e.Parse(p + 12 + i * 12); + if (e.PhyStart == 0 + || e.PhyStart > _h.NumBlocks + || e.PhyStart + e.Len > _h.NumBlocks + || !e.IsLenOK()) + return S_FALSE; + if (!UpdateExtents(extents, e.VirtBlock)) + return S_FALSE; + extents.Add(e); + } + + return S_OK; + } + + const size_t blockSize = (size_t)1 << _h.BlockBits; + CByteBuffer &tempBuf = _tempBufs[eth.Depth]; + tempBuf.Alloc(blockSize); + + for (unsigned i = 0; i < eth.NumEntries; i++) + { + CExtentIndexNode e; + e.Parse(p + 12 + i * 12); + + if (e.PhyLeaf == 0 || e.PhyLeaf >= _h.NumBlocks) + return S_FALSE; + + if (!UpdateExtents(extents, e.VirtBlock)) + return S_FALSE; + + RINOK(SeekAndRead(_stream, e.PhyLeaf, tempBuf, blockSize)) + RINOK(FillExtents(tempBuf, blockSize, extents, eth.Depth)) + } + + return S_OK; +} + + +HRESULT CHandler::GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + + *stream = NULL; + + const CNode &node = _nodes[nodeIndex]; + + if (!node.IsFlags_EXTENTS()) + { + // maybe sparse file can have (node.NumBlocks == 0) ? + + /* The following code doesn't work correctly for some CentOS images, + where there are nodes with inline data and (node.NumBlocks != 0). + If you know better way to detect inline data, please notify 7-Zip developers. */ + + if (node.NumBlocks == 0 && node.FileSize < kNodeBlockFieldSize) + { + Create_BufInStream_WithNewBuffer(node.Block, (size_t)node.FileSize, stream); + return S_OK; + } + } + + if (node.FileSize >= ((UInt64)1 << 63)) + return S_FALSE; + + CMyComPtr streamTemp; + + const UInt64 numBlocks64 = (node.FileSize + (UInt64)(((UInt32)1 << _h.BlockBits) - 1)) >> _h.BlockBits; + + if (node.IsFlags_EXTENTS()) + { + if ((UInt32)numBlocks64 != numBlocks64) + return S_FALSE; + + CExtInStream *streamSpec = new CExtInStream; + streamTemp = streamSpec; + + streamSpec->BlockBits = _h.BlockBits; + streamSpec->Size = node.FileSize; + streamSpec->Stream = _stream; + + RINOK(FillExtents(node.Block, kNodeBlockFieldSize, streamSpec->Extents, -1)) + + UInt32 end = 0; + if (!streamSpec->Extents.IsEmpty()) + end = streamSpec->Extents.Back().GetVirtEnd(); + if (end < numBlocks64) + { + AddSkipExtents(streamSpec->Extents, end, (UInt32)(numBlocks64 - end)); + // return S_FALSE; + } + + RINOK(streamSpec->StartSeek()) + } + else + { + { + UInt64 numBlocks2 = numBlocks64; + + if (numBlocks64 > kNumDirectNodeBlocks) + { + UInt64 rem = numBlocks64 - kNumDirectNodeBlocks; + const unsigned refBits = (_h.BlockBits - 2); + const size_t numRefsInBlocks = (size_t)1 << refBits; + numBlocks2++; + if (rem > numRefsInBlocks) + { + numBlocks2++; + const UInt64 numL2 = (rem - 1) >> refBits; + numBlocks2 += numL2; + if (numL2 > numRefsInBlocks) + { + numBlocks2++; + numBlocks2 += (numL2 - 1) >> refBits; + } + } + } + + const unsigned specBits = (node.IsFlags_HUGE() ? 0 : _h.BlockBits - 9); + const UInt32 specMask = ((UInt32)1 << specBits) - 1; + if ((node.NumBlocks & specMask) != 0) + return S_FALSE; + const UInt64 numBlocks64_from_header = node.NumBlocks >> specBits; + if (numBlocks64_from_header < numBlocks2) + { + // why (numBlocks64_from_header > numBlocks2) in some cases? + // return S_FALSE; + } + } + + unsigned numBlocks = (unsigned)numBlocks64; + if (numBlocks != numBlocks64) + return S_FALSE; + + CClusterInStream2 *streamSpec = new CClusterInStream2; + streamTemp = streamSpec; + + streamSpec->BlockBits = _h.BlockBits; + streamSpec->Size = node.FileSize; + streamSpec->Stream = _stream; + + RINOK(FillFileBlocks(node.Block, numBlocks, streamSpec->Vector)) + streamSpec->InitAndSeek(); + } + + *stream = streamTemp.Detach(); + + return S_OK; + + COM_TRY_END +} + + +HRESULT CHandler::ExtractNode(unsigned nodeIndex, CByteBuffer &data) +{ + data.Free(); + const CNode &node = _nodes[nodeIndex]; + size_t size = (size_t)node.FileSize; + if (size != node.FileSize) + return S_FALSE; + CMyComPtr inSeqStream; + RINOK(GetStream_Node(nodeIndex, &inSeqStream)) + if (!inSeqStream) + return S_FALSE; + data.Alloc(size); + _totalRead += size; + return ReadStream_FALSE(inSeqStream, data, size); +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size() + _auxItems.Size(); + if (numItems == 0) + return S_OK; + + UInt64 totalSize = 0; + UInt32 i; + + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + if (index >= _items.Size()) + continue; + const CItem &item = _items[index]; + const CNode &node = _nodes[_refs[item.Node]]; + if (!node.IsDir()) + totalSize += node.FileSize; + } + + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create copyCoder; + + for (i = 0;; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + int opRes; + { + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + + if (index >= _items.Size()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const CItem &item = _items[index]; + const CNode &node = _nodes[_refs[item.Node]]; + + if (node.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + UInt64 unpackSize = node.FileSize; + totalSize += unpackSize; + UInt64 packSize; + if (GetPackSize(index, packSize)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + opRes = NExtract::NOperationResult::kDataError; + { + CMyComPtr inSeqStream; + HRESULT hres = GetStream(index, &inSeqStream); + if (hres == S_FALSE || !inSeqStream) + { + if (hres == E_OUTOFMEMORY) + return hres; + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else + { + RINOK(hres) + { + hres = copyCoder.Interface()->Code(inSeqStream, outStream, NULL, NULL, lps); + if (hres == S_OK) + { + if (copyCoder->TotalSize == unpackSize) + opRes = NExtract::NOperationResult::kOK; + } + else if (hres == E_NOTIMPL) + { + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else if (hres != S_FALSE) + { + RINOK(hres) + } + } + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + *stream = NULL; + if (index >= _items.Size()) + return S_FALSE; + return GetStream_Node((unsigned)_refs[_items[index].Node], stream); +} + + +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize) +{ + if (phySize) + *phySize = 0; + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + CHeader h; + if (!h.Parse(p + kHeaderDataOffset)) + return k_IsArc_Res_NO; + if (phySize) + *phySize = h.GetPhySize(); + return k_IsArc_Res_YES; +} + + +API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size); +API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size) +{ + return IsArc_Ext_PhySize(p, size, NULL); +} + + +static const Byte k_Signature[] = { 0x53, 0xEF }; + +REGISTER_ARC_I( + "Ext", "ext ext2 ext3 ext4 img", NULL, 0xC7, + k_Signature, + 0x438, + 0, + IsArc_Ext) + +}} diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index a2a66507c..b31ee4f6b 100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp @@ -1,1103 +1,1103 @@ -// FatHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get16a(p) GetUi16a(p) -#define Get32a(p) GetUi32a(p) - -#define PRF(x) /* x */ - -namespace NArchive { -namespace NFat { - -static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31; - -struct CHeader -{ - UInt32 NumSectors; - UInt16 NumReservedSectors; - Byte NumFats; - UInt32 NumFatSectors; - UInt32 RootDirSector; - UInt32 NumRootDirSectors; - UInt32 DataSector; - - UInt32 FatSize; - UInt32 BadCluster; - - Byte NumFatBits; - Byte SectorSizeLog; - Byte SectorsPerClusterLog; - Byte ClusterSizeLog; - - UInt16 SectorsPerTrack; - UInt16 NumHeads; - UInt32 NumHiddenSectors; - - bool VolFieldsDefined; - bool HeadersWarning; - - UInt32 VolId; - // Byte VolName[11]; - // Byte FileSys[8]; - - // Byte OemName[5]; - Byte MediaType; - - // 32-bit FAT - UInt16 Flags; - UInt16 FsInfoSector; - UInt32 RootCluster; - - bool IsFat32() const { return NumFatBits == 32; } - UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; } - UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; } - UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } - UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); } - UInt32 IsEoc(UInt32 c) const { return c > BadCluster; } - UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; } - UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; } - UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; } - UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); } - - UInt32 GetFatSector() const - { - UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0; - if (index > NumFats) - index = 0; - return NumReservedSectors + index * NumFatSectors; - } - - UInt64 GetFilePackSize(UInt32 unpackSize) const - { - UInt64 mask = ClusterSize() - 1; - return (unpackSize + mask) & ~mask; - } - - UInt32 GetNumClusters(UInt32 size) const - { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); } - - bool Parse(const Byte *p); -}; - -static int GetLog(UInt32 num) -{ - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - -static const UInt32 kHeaderSize = 512; - -API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); -API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) -{ - if (size < kHeaderSize) - return k_IsArc_Res_NEED_MORE; - CHeader h; - return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO; -} - -bool CHeader::Parse(const Byte *p) -{ - if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) - return false; - - HeadersWarning = false; - - int codeOffset = 0; - switch (p[0]) - { - case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break; - case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break; - default: return false; - } - { - { - const UInt32 val32 = Get16(p + 11); - const int s = GetLog(val32); - if (s < 9 || s > 12) - return false; - SectorSizeLog = (Byte)s; - } - { - const UInt32 val32 = p[13]; - const int s = GetLog(val32); - if (s < 0) - return false; - SectorsPerClusterLog = (Byte)s; - } - ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog); - if (ClusterSizeLog > 24) - return false; - } - - NumReservedSectors = Get16(p + 14); - if (NumReservedSectors == 0) - return false; - - NumFats = p[16]; - if (NumFats < 1 || NumFats > 4) - return false; - - // we also support images that contain 0 in offset field. - const bool isOkOffset = (codeOffset == 0) - || (codeOffset == (p[0] == 0xEB ? 2 : 3)); - - const UInt16 numRootDirEntries = Get16(p + 17); - if (numRootDirEntries == 0) - { - if (codeOffset < 90 && !isOkOffset) - return false; - NumFatBits = 32; - NumRootDirSectors = 0; - } - else - { - // Some FAT12s don't contain VolFields - if (codeOffset < 62 - 24 && !isOkOffset) - return false; - NumFatBits = 0; - const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; - if ((numRootDirEntries & mask) != 0) - return false; - NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); - } - - NumSectors = Get16(p + 19); - if (NumSectors == 0) - NumSectors = Get32(p + 32); - /* - // mkfs.fat could create fat32 image with 16-bit number of sectors. - // v23: we allow 16-bit value for number of sectors in fat32. - else if (IsFat32()) - return false; - */ - - MediaType = p[21]; - NumFatSectors = Get16(p + 22); - SectorsPerTrack = Get16(p + 24); - NumHeads = Get16(p + 26); - NumHiddenSectors = Get32(p + 28); - - // memcpy(OemName, p + 3, 5); - - int curOffset = 36; - p += 36; - if (IsFat32()) - { - if (NumFatSectors != 0) - return false; - NumFatSectors = Get32(p); - if (NumFatSectors >= (1 << 24)) - return false; - - Flags = Get16(p + 4); - if (Get16(p + 6) != 0) - return false; - RootCluster = Get32(p + 8); - FsInfoSector = Get16(p + 12); - for (int i = 16; i < 28; i++) - if (p[i] != 0) - return false; - p += 28; - curOffset += 28; - } - - // DriveNumber = p[0]; - VolFieldsDefined = false; - if (codeOffset >= curOffset + 3) - { - VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig - if (VolFieldsDefined) - { - if (codeOffset < curOffset + 26) - return false; - VolId = Get32(p + 3); - // memcpy(VolName, p + 7, 11); - // memcpy(FileSys, p + 18, 8); - } - } - - if (NumFatSectors == 0) - return false; - RootDirSector = NumReservedSectors + NumFatSectors * NumFats; - DataSector = RootDirSector + NumRootDirSectors; - if (NumSectors < DataSector) - return false; - const UInt32 numDataSectors = NumSectors - DataSector; - const UInt32 numClusters = numDataSectors >> SectorsPerClusterLog; - - BadCluster = 0x0FFFFFF7; - // v23: we support unusual (< 0xFFF5) numClusters values in fat32 systems - if (NumFatBits != 32) - { - if (numClusters >= 0xFFF5) - return false; - NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); - BadCluster &= ((1 << NumFatBits) - 1); - } - - FatSize = numClusters + 2; - if (FatSize > BadCluster) - return false; - if (CalcFatSizeInSectors() > NumFatSectors) - { - /* some third-party program can create such FAT image, where - size of FAT table (NumFatSectors from headers) is smaller than - required value that is calculated from calculated (FatSize) value. - Another FAT unpackers probably ignore that error. - v23.02: we also ignore that error, and - we recalculate (FatSize) value from (NumFatSectors). - New (FatSize) will be smaller than original "full" (FatSize) value. - So we will have some unused clusters at the end of archive. - */ - FatSize = (UInt32)(((UInt64)NumFatSectors << (3 + SectorSizeLog)) / NumFatBits); - HeadersWarning = true; - } - return true; -} - -struct CItem -{ - UString UName; - char DosName[11]; - Byte CTime2; - UInt32 CTime; - UInt32 MTime; - UInt16 ADate; - Byte Attrib; - Byte Flags; - UInt32 Size; - UInt32 Cluster; - Int32 Parent; - - // NT uses Flags to store Low Case status - bool NameIsLow() const { return (Flags & 0x8) != 0; } - bool ExtIsLow() const { return (Flags & 0x10) != 0; } - bool IsDir() const { return (Attrib & 0x10) != 0; } - UString GetShortName() const; - UString GetName() const; - UString GetVolName() const; -}; - -static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower) -{ - memcpy(dest, src, size); - if (toLower) - { - for (unsigned i = 0; i < size; i++) - { - char c = dest[i]; - if (c >= 'A' && c <= 'Z') - dest[i] = (char)(c + 0x20); - } - } - - for (unsigned i = size;;) - { - if (i == 0) - return 0; - if (dest[i - 1] != ' ') - return i; - i--; - } -} - -static UString FatStringToUnicode(const char *s) -{ - return MultiByteToUnicodeString(s, CP_OEMCP); -} - -UString CItem::GetShortName() const -{ - char s[16]; - unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow()); - s[i++] = '.'; - unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); - if (j == 0) - i--; - s[i + j] = 0; - return FatStringToUnicode(s); -} - -UString CItem::GetName() const -{ - if (!UName.IsEmpty()) - return UName; - return GetShortName(); -} - -UString CItem::GetVolName() const -{ - if (!UName.IsEmpty()) - return UName; - char s[12]; - unsigned i = CopyAndTrim(s, DosName, 11, false); - s[i] = 0; - return FatStringToUnicode(s); -} - -struct CDatabase -{ - CHeader Header; - CObjectVector Items; - UInt32 *Fat; - CMyComPtr InStream; - IArchiveOpenCallback *OpenCallback; - - UInt32 NumFreeClusters; - bool VolItemDefined; - CItem VolItem; - UInt32 NumDirClusters; - CByteBuffer ByteBuf; - UInt64 NumCurUsedBytes; - - UInt64 PhySize; - - CDatabase(): Fat(NULL) {} - ~CDatabase() { ClearAndClose(); } - - void Clear(); - void ClearAndClose(); - HRESULT OpenProgressFat(bool changeTotal = true); - HRESULT OpenProgress(); - - UString GetItemPath(UInt32 index) const; - HRESULT Open(); - HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level); - - UInt64 GetHeadersSize() const - { - return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog; - } - HRESULT SeekToSector(UInt32 sector); - HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); } -}; - -HRESULT CDatabase::SeekToSector(UInt32 sector) -{ - return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog); -} - -void CDatabase::Clear() -{ - PhySize = 0; - VolItemDefined = false; - NumDirClusters = 0; - NumCurUsedBytes = 0; - - Items.Clear(); - delete []Fat; - Fat = NULL; -} - -void CDatabase::ClearAndClose() -{ - Clear(); - InStream.Release(); -} - -HRESULT CDatabase::OpenProgressFat(bool changeTotal) -{ - if (!OpenCallback) - return S_OK; - if (changeTotal) - { - const UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + - ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); - RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)) - } - return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes); -} - -HRESULT CDatabase::OpenProgress() -{ - if (!OpenCallback) - return S_OK; - UInt64 numItems = Items.Size(); - return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); -} - -UString CDatabase::GetItemPath(UInt32 index) const -{ - const CItem *item = &Items[index]; - UString name = item->GetName(); - for (;;) - { - index = (UInt32)item->Parent; - if (item->Parent < 0) - return name; - item = &Items[index]; - name.InsertAtFront(WCHAR_PATH_SEPARATOR); - if (item->UName.IsEmpty()) - name.Insert(0, item->GetShortName()); - else - name.Insert(0, item->UName); - } -} - -static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars) -{ - for (unsigned i = 0; i < numChars; i++) - { - wchar_t c = Get16(p + i * 2); - if (c != 0 && c != 0xFFFF) - *dest++ = c; - } - *dest = 0; - return dest; -} - -HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) -{ - unsigned startIndex = Items.Size(); - if (startIndex >= (1 << 30) || level > 256) - return S_FALSE; - - UInt32 sectorIndex = 0; - UInt32 blockSize = Header.ClusterSize(); - bool clusterMode = (Header.IsFat32() || parent >= 0); - if (!clusterMode) - { - blockSize = Header.SectorSize(); - RINOK(SeekToSector(Header.RootDirSector)) - } - - ByteBuf.Alloc(blockSize); - UString curName; - int checkSum = -1; - int numLongRecords = -1; - - for (UInt32 pos = blockSize;; pos += 32) - { - if (pos == blockSize) - { - pos = 0; - - if ((NumDirClusters & 0xFF) == 0) - { - RINOK(OpenProgress()) - } - - if (clusterMode) - { - if (Header.IsEoc(cluster)) - break; - if (!Header.IsValidCluster(cluster)) - return S_FALSE; - PRF(printf("\nCluster = %4X", cluster)); - RINOK(SeekToCluster(cluster)) - const UInt32 newCluster = Fat[cluster]; - if ((newCluster & kFatItemUsedByDirMask) != 0) - return S_FALSE; - Fat[cluster] |= kFatItemUsedByDirMask; - cluster = newCluster; - NumDirClusters++; - NumCurUsedBytes += Header.ClusterSize(); - } - else if (sectorIndex++ >= Header.NumRootDirSectors) - break; - - RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)) - } - - const Byte *p = ByteBuf + pos; - - if (p[0] == 0) - { - /* - // FreeDOS formats FAT partition with cluster chain longer than required. - if (clusterMode && !Header.IsEoc(cluster)) - return S_FALSE; - */ - break; - } - - if (p[0] == 0xE5) - { - if (numLongRecords > 0) - return S_FALSE; - continue; - } - - Byte attrib = p[11]; - if ((attrib & 0x3F) == 0xF) - { - if (p[0] > 0x7F || Get16(p + 26) != 0) - return S_FALSE; - int longIndex = p[0] & 0x3F; - if (longIndex == 0) - return S_FALSE; - bool isLast = (p[0] & 0x40) != 0; - if (numLongRecords < 0) - { - if (!isLast) - return S_FALSE; - numLongRecords = longIndex; - } - else if (isLast || numLongRecords != longIndex) - return S_FALSE; - - numLongRecords--; - - if (p[12] == 0) - { - wchar_t nameBuf[14]; - wchar_t *dest; - - dest = AddSubStringToName(nameBuf, p + 1, 5); - dest = AddSubStringToName(dest, p + 14, 6); - AddSubStringToName(dest, p + 28, 2); - curName = nameBuf + curName; - if (isLast) - checkSum = p[13]; - if (checkSum != p[13]) - return S_FALSE; - } - } - else - { - if (numLongRecords > 0) - return S_FALSE; - CItem item; - memcpy(item.DosName, p, 11); - - if (checkSum >= 0) - { - Byte sum = 0; - for (unsigned i = 0; i < 11; i++) - sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]); - if (sum == checkSum) - item.UName = curName; - } - - if (item.DosName[0] == 5) - item.DosName[0] = (char)(Byte)0xE5; - item.Attrib = attrib; - item.Flags = p[12]; - item.Size = Get32(p + 28); - item.Cluster = Get16(p + 26); - if (Header.NumFatBits > 16) - item.Cluster |= ((UInt32)Get16(p + 20) << 16); - else - { - // OS/2 and WinNT probably can store EA (extended atributes) in that field. - } - - item.CTime = Get32(p + 14); - item.CTime2 = p[13]; - item.ADate = Get16(p + 18); - item.MTime = Get32(p + 22); - item.Parent = parent; - - if (attrib == 8) - { - VolItem = item; - VolItemDefined = true; - } - else - if (memcmp(item.DosName, ". ", 11) != 0 && - memcmp(item.DosName, ".. ", 11) != 0) - { - if (!item.IsDir()) - NumCurUsedBytes += Header.GetFilePackSize(item.Size); - Items.Add(item); - PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1))); - } - numLongRecords = -1; - curName.Empty(); - checkSum = -1; - } - } - - unsigned finishIndex = Items.Size(); - for (unsigned i = startIndex; i < finishIndex; i++) - { - const CItem &item = Items[i]; - if (item.IsDir()) - { - PRF(printf("\n%S", GetItemPath(i))); - RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1)) - } - } - return S_OK; -} - -HRESULT CDatabase::Open() -{ - Clear(); - bool numFreeClustersDefined = false; - { - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)) - if (!Header.Parse(buf)) - return S_FALSE; - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) - - /* we comment that check to support truncated images */ - /* - if (fileSize < Header.GetPhySize()) - return S_FALSE; - */ - - if (Header.IsFat32()) - { - if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize - && SeekToSector(Header.FsInfoSector) == S_OK - && ReadStream_FALSE(InStream, buf, kHeaderSize) == S_OK - && 0xaa550000 == Get32(buf + 508) - && 0x41615252 == Get32(buf) - && 0x61417272 == Get32(buf + 484)) - { - NumFreeClusters = Get32(buf + 488); - numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); - } - else - Header.HeadersWarning = true; - } - } - - // numFreeClustersDefined = false; // to recalculate NumFreeClusters - if (!numFreeClustersDefined) - NumFreeClusters = 0; - - CByteBuffer byteBuf; - Fat = new UInt32[Header.FatSize]; - - RINOK(OpenProgressFat()) - RINOK(SeekToSector(Header.GetFatSector())) - if (Header.NumFatBits == 32) - { - const UInt32 kBufSize = (1 << 15); - byteBuf.Alloc(kBufSize); - for (UInt32 i = 0;;) - { - UInt32 size = Header.FatSize - i; - if (size == 0) - break; - const UInt32 kBufSize32 = kBufSize / 4; - if (size > kBufSize32) - size = kBufSize32; - const UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog; - RINOK(ReadStream_FALSE(InStream, byteBuf, readSize)) - NumCurUsedBytes += readSize; - - const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf; - UInt32 *dest = Fat + i; - const UInt32 *srcLim = src + size; - if (numFreeClustersDefined) - do - *dest++ = Get32a(src) & 0x0FFFFFFF; - while (++src != srcLim); - else - { - UInt32 numFreeClusters = 0; - do - { - const UInt32 v = Get32a(src) & 0x0FFFFFFF; - *dest++ = v; - numFreeClusters += (UInt32)(v - 1) >> 31; - } - while (++src != srcLim); - NumFreeClusters += numFreeClusters; - } - i += size; - if ((i & 0xFFFFF) == 0) - { - RINOK(OpenProgressFat(!numFreeClustersDefined)) - } - } - } - else - { - const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog; - NumCurUsedBytes += kBufSize; - byteBuf.Alloc(kBufSize); - Byte *p = byteBuf; - RINOK(ReadStream_FALSE(InStream, p, kBufSize)) - const UInt32 fatSize = Header.FatSize; - UInt32 *fat = &Fat[0]; - if (Header.NumFatBits == 16) - for (UInt32 j = 0; j < fatSize; j++) - fat[j] = Get16a(p + j * 2); - else - for (UInt32 j = 0; j < fatSize; j++) - fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF; - - if (!numFreeClustersDefined) - { - UInt32 numFreeClusters = 0; - for (UInt32 i = 0; i < fatSize; i++) - numFreeClusters += (UInt32)(fat[i] - 1) >> 31; - NumFreeClusters = numFreeClusters; - } - } - - RINOK(OpenProgressFat()) - - if ((Fat[0] & 0xFF) != Header.MediaType) - { - // that case can mean error in FAT, - // but xdf file: (MediaType == 0xF0 && Fat[0] == 0xFF9) - // 19.00: so we use non-strict check - if ((Fat[0] & 0xFF) < 0xF0) - return S_FALSE; - } - - RINOK(ReadDir(-1, Header.RootCluster, 0)) - - PhySize = Header.GetPhySize(); - return S_OK; -} - - - -Z7_class_CHandler_final: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp, - CDatabase -{ - Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream) -}; - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - const CItem &item = Items[index]; - CClusterInStream *streamSpec = new CClusterInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Stream = InStream; - streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog; - streamSpec->BlockSizeLog = Header.ClusterSizeLog; - streamSpec->Size = item.Size; - - const UInt32 numClusters = Header.GetNumClusters(item.Size); - streamSpec->Vector.ClearAndReserve(numClusters); - UInt32 cluster = item.Cluster; - UInt32 size = item.Size; - - if (size == 0) - { - if (cluster != 0) - return S_FALSE; - } - else - { - const UInt32 clusterSize = Header.ClusterSize(); - for (;; size -= clusterSize) - { - if (!Header.IsValidCluster(cluster)) - return S_FALSE; - streamSpec->Vector.AddInReserved(cluster - 2); - cluster = Fat[cluster]; - if (size <= clusterSize) - break; - } - if (!Header.IsEocAndUnused(cluster)) - return S_FALSE; - } - RINOK(streamSpec->InitAndSeek()) - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidAttrib, - kpidShortName -}; - -enum -{ - kpidNumFats = kpidUserDefined - // kpidOemName, - // kpidVolName, - // kpidFileSysType -}; - -static const CStatProp kArcProps[] = -{ - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidFreeSpace, VT_UI8}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidVolumeName, VT_BSTR}, - - { "FATs", kpidNumFats, VT_UI4}, - { NULL, kpidSectorSize, VT_UI4}, - { NULL, kpidId, VT_UI4}, - // { "OEM Name", kpidOemName, VT_BSTR}, - // { "Volume Name", kpidVolName, VT_BSTR}, - // { "File System Type", kpidFileSysType, VT_BSTR} - // { NULL, kpidSectorsPerTrack, VT_UI4}, - // { NULL, kpidNumHeads, VT_UI4}, - // { NULL, kpidHiddenSectors, VT_UI4} -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - - -static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop) -{ - FILETIME localFileTime, utc; - if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime)) - if (LocalFileTimeToFileTime(&localFileTime, &utc)) - { - UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; - t64 += ms10 * 100000; - utc.dwLowDateTime = (DWORD)t64; - utc.dwHighDateTime = (DWORD)(t64 >> 32); - prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2); - } -} - -/* -static void StringToProp(const Byte *src, unsigned size, NWindows::NCOM::CPropVariant &prop) -{ - char dest[32]; - memcpy(dest, src, size); - dest[size] = 0; - prop = FatStringToUnicode(dest); -} - -#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop) -*/ - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidFileSystem: - { - char s[16]; - s[0] = 'F'; - s[1] = 'A'; - s[2] = 'T'; - ConvertUInt32ToString(Header.NumFatBits, s + 3); - prop = s; - break; - } - case kpidClusterSize: prop = Header.ClusterSize(); break; - case kpidPhySize: prop = PhySize; break; - case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; - case kpidHeadersSize: prop = GetHeadersSize(); break; - case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break; - case kpidShortComment: - case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; - case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; - case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; - // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; - // case kpidNumHeads: prop = Header.NumHeads; break; - // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break; - case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break; - // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break; - // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break; - // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; - case kpidWarningFlags: - { - UInt32 v = 0; - if (Header.HeadersWarning) v |= kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = Items[index]; - switch (propID) - { - case kpidPath: prop = GetItemPath(index); break; - case kpidShortName: prop = item.GetShortName(); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break; - case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; - case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break; - case kpidAttrib: prop = (UInt32)item.Attrib; break; - case kpidSize: if (!item.IsDir()) prop = item.Size; break; - case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - OpenCallback = callback; - InStream = stream; - HRESULT res; - try - { - res = CDatabase::Open(); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - ClearAndClose(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const CItem &item = Items[allFilesMode ? i : indices[i]]; - if (!item.IsDir()) - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - - for (i = 0;; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i == numItems) - break; - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = Items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - totalPackSize += Header.GetFilePackSize(item.Size); - totalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(); - - int res = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - HRESULT hres = GetStream(index, &inStream); - if (hres != S_FALSE) - { - RINOK(hres) - if (inStream) - { - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - if (copyCoderSpec->TotalSize == item.Size) - res = NExtract::NOperationResult::kOK; - } - } - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(res)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = Items.Size(); - return S_OK; -} - -static const Byte k_Signature[] = { 0x55, 0xAA }; - -REGISTER_ARC_I( - "FAT", "fat img", NULL, 0xDA, - k_Signature, - 0x1FE, - 0, - IsArc_Fat) - -}} +// FatHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get16a(p) GetUi16a(p) +#define Get32a(p) GetUi32a(p) + +#define PRF(x) /* x */ + +namespace NArchive { +namespace NFat { + +static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31; + +struct CHeader +{ + UInt32 NumSectors; + UInt16 NumReservedSectors; + Byte NumFats; + UInt32 NumFatSectors; + UInt32 RootDirSector; + UInt32 NumRootDirSectors; + UInt32 DataSector; + + UInt32 FatSize; + UInt32 BadCluster; + + Byte NumFatBits; + Byte SectorSizeLog; + Byte SectorsPerClusterLog; + Byte ClusterSizeLog; + + UInt16 SectorsPerTrack; + UInt16 NumHeads; + UInt32 NumHiddenSectors; + + bool VolFieldsDefined; + bool HeadersWarning; + + UInt32 VolId; + // Byte VolName[11]; + // Byte FileSys[8]; + + // Byte OemName[5]; + Byte MediaType; + + // 32-bit FAT + UInt16 Flags; + UInt16 FsInfoSector; + UInt32 RootCluster; + + bool IsFat32() const { return NumFatBits == 32; } + UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; } + UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; } + UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } + UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); } + UInt32 IsEoc(UInt32 c) const { return c > BadCluster; } + UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; } + UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; } + UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; } + UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); } + + UInt32 GetFatSector() const + { + UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0; + if (index > NumFats) + index = 0; + return NumReservedSectors + index * NumFatSectors; + } + + UInt64 GetFilePackSize(UInt32 unpackSize) const + { + UInt64 mask = ClusterSize() - 1; + return (unpackSize + mask) & ~mask; + } + + UInt32 GetNumClusters(UInt32 size) const + { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); } + + bool Parse(const Byte *p); +}; + +static int GetLog(UInt32 num) +{ + for (int i = 0; i < 31; i++) + if (((UInt32)1 << i) == num) + return i; + return -1; +} + +static const UInt32 kHeaderSize = 512; + +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) +{ + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + CHeader h; + return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO; +} + +bool CHeader::Parse(const Byte *p) +{ + if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) + return false; + + HeadersWarning = false; + + int codeOffset = 0; + switch (p[0]) + { + case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break; + case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break; + default: return false; + } + { + { + const UInt32 val32 = Get16(p + 11); + const int s = GetLog(val32); + if (s < 9 || s > 12) + return false; + SectorSizeLog = (Byte)s; + } + { + const UInt32 val32 = p[13]; + const int s = GetLog(val32); + if (s < 0) + return false; + SectorsPerClusterLog = (Byte)s; + } + ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog); + if (ClusterSizeLog > 24) + return false; + } + + NumReservedSectors = Get16(p + 14); + if (NumReservedSectors == 0) + return false; + + NumFats = p[16]; + if (NumFats < 1 || NumFats > 4) + return false; + + // we also support images that contain 0 in offset field. + const bool isOkOffset = (codeOffset == 0) + || (codeOffset == (p[0] == 0xEB ? 2 : 3)); + + const UInt16 numRootDirEntries = Get16(p + 17); + if (numRootDirEntries == 0) + { + if (codeOffset < 90 && !isOkOffset) + return false; + NumFatBits = 32; + NumRootDirSectors = 0; + } + else + { + // Some FAT12s don't contain VolFields + if (codeOffset < 62 - 24 && !isOkOffset) + return false; + NumFatBits = 0; + const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1; + if ((numRootDirEntries & mask) != 0) + return false; + NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5); + } + + NumSectors = Get16(p + 19); + if (NumSectors == 0) + NumSectors = Get32(p + 32); + /* + // mkfs.fat could create fat32 image with 16-bit number of sectors. + // v23: we allow 16-bit value for number of sectors in fat32. + else if (IsFat32()) + return false; + */ + + MediaType = p[21]; + NumFatSectors = Get16(p + 22); + SectorsPerTrack = Get16(p + 24); + NumHeads = Get16(p + 26); + NumHiddenSectors = Get32(p + 28); + + // memcpy(OemName, p + 3, 5); + + int curOffset = 36; + p += 36; + if (IsFat32()) + { + if (NumFatSectors != 0) + return false; + NumFatSectors = Get32(p); + if (NumFatSectors >= (1 << 24)) + return false; + + Flags = Get16(p + 4); + if (Get16(p + 6) != 0) + return false; + RootCluster = Get32(p + 8); + FsInfoSector = Get16(p + 12); + for (int i = 16; i < 28; i++) + if (p[i] != 0) + return false; + p += 28; + curOffset += 28; + } + + // DriveNumber = p[0]; + VolFieldsDefined = false; + if (codeOffset >= curOffset + 3) + { + VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig + if (VolFieldsDefined) + { + if (codeOffset < curOffset + 26) + return false; + VolId = Get32(p + 3); + // memcpy(VolName, p + 7, 11); + // memcpy(FileSys, p + 18, 8); + } + } + + if (NumFatSectors == 0) + return false; + RootDirSector = NumReservedSectors + NumFatSectors * NumFats; + DataSector = RootDirSector + NumRootDirSectors; + if (NumSectors < DataSector) + return false; + const UInt32 numDataSectors = NumSectors - DataSector; + const UInt32 numClusters = numDataSectors >> SectorsPerClusterLog; + + BadCluster = 0x0FFFFFF7; + // v23: we support unusual (< 0xFFF5) numClusters values in fat32 systems + if (NumFatBits != 32) + { + if (numClusters >= 0xFFF5) + return false; + NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16); + BadCluster &= ((1 << NumFatBits) - 1); + } + + FatSize = numClusters + 2; + if (FatSize > BadCluster) + return false; + if (CalcFatSizeInSectors() > NumFatSectors) + { + /* some third-party program can create such FAT image, where + size of FAT table (NumFatSectors from headers) is smaller than + required value that is calculated from calculated (FatSize) value. + Another FAT unpackers probably ignore that error. + v23.02: we also ignore that error, and + we recalculate (FatSize) value from (NumFatSectors). + New (FatSize) will be smaller than original "full" (FatSize) value. + So we will have some unused clusters at the end of archive. + */ + FatSize = (UInt32)(((UInt64)NumFatSectors << (3 + SectorSizeLog)) / NumFatBits); + HeadersWarning = true; + } + return true; +} + +struct CItem +{ + UString UName; + char DosName[11]; + Byte CTime2; + UInt32 CTime; + UInt32 MTime; + UInt16 ADate; + Byte Attrib; + Byte Flags; + UInt32 Size; + UInt32 Cluster; + Int32 Parent; + + // NT uses Flags to store Low Case status + bool NameIsLow() const { return (Flags & 0x8) != 0; } + bool ExtIsLow() const { return (Flags & 0x10) != 0; } + bool IsDir() const { return (Attrib & 0x10) != 0; } + UString GetShortName() const; + UString GetName() const; + UString GetVolName() const; +}; + +static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower) +{ + memcpy(dest, src, size); + if (toLower) + { + for (unsigned i = 0; i < size; i++) + { + char c = dest[i]; + if (c >= 'A' && c <= 'Z') + dest[i] = (char)(c + 0x20); + } + } + + for (unsigned i = size;;) + { + if (i == 0) + return 0; + if (dest[i - 1] != ' ') + return i; + i--; + } +} + +static UString FatStringToUnicode(const char *s) +{ + return MultiByteToUnicodeString(s, CP_OEMCP); +} + +UString CItem::GetShortName() const +{ + char s[16]; + unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow()); + s[i++] = '.'; + unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow()); + if (j == 0) + i--; + s[i + j] = 0; + return FatStringToUnicode(s); +} + +UString CItem::GetName() const +{ + if (!UName.IsEmpty()) + return UName; + return GetShortName(); +} + +UString CItem::GetVolName() const +{ + if (!UName.IsEmpty()) + return UName; + char s[12]; + unsigned i = CopyAndTrim(s, DosName, 11, false); + s[i] = 0; + return FatStringToUnicode(s); +} + +struct CDatabase +{ + CHeader Header; + CObjectVector Items; + UInt32 *Fat; + CMyComPtr InStream; + IArchiveOpenCallback *OpenCallback; + + UInt32 NumFreeClusters; + bool VolItemDefined; + CItem VolItem; + UInt32 NumDirClusters; + CByteBuffer ByteBuf; + UInt64 NumCurUsedBytes; + + UInt64 PhySize; + + CDatabase(): Fat(NULL) {} + ~CDatabase() { ClearAndClose(); } + + void Clear(); + void ClearAndClose(); + HRESULT OpenProgressFat(bool changeTotal = true); + HRESULT OpenProgress(); + + UString GetItemPath(UInt32 index) const; + HRESULT Open(); + HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level); + + UInt64 GetHeadersSize() const + { + return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog; + } + HRESULT SeekToSector(UInt32 sector); + HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); } +}; + +HRESULT CDatabase::SeekToSector(UInt32 sector) +{ + return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog); +} + +void CDatabase::Clear() +{ + PhySize = 0; + VolItemDefined = false; + NumDirClusters = 0; + NumCurUsedBytes = 0; + + Items.Clear(); + delete []Fat; + Fat = NULL; +} + +void CDatabase::ClearAndClose() +{ + Clear(); + InStream.Release(); +} + +HRESULT CDatabase::OpenProgressFat(bool changeTotal) +{ + if (!OpenCallback) + return S_OK; + if (changeTotal) + { + const UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + + ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); + RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)) + } + return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes); +} + +HRESULT CDatabase::OpenProgress() +{ + if (!OpenCallback) + return S_OK; + UInt64 numItems = Items.Size(); + return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes); +} + +UString CDatabase::GetItemPath(UInt32 index) const +{ + const CItem *item = &Items[index]; + UString name = item->GetName(); + for (;;) + { + index = (UInt32)item->Parent; + if (item->Parent < 0) + return name; + item = &Items[index]; + name.InsertAtFront(WCHAR_PATH_SEPARATOR); + if (item->UName.IsEmpty()) + name.Insert(0, item->GetShortName()); + else + name.Insert(0, item->UName); + } +} + +static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars) +{ + for (unsigned i = 0; i < numChars; i++) + { + wchar_t c = Get16(p + i * 2); + if (c != 0 && c != 0xFFFF) + *dest++ = c; + } + *dest = 0; + return dest; +} + +HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level) +{ + unsigned startIndex = Items.Size(); + if (startIndex >= (1 << 30) || level > 256) + return S_FALSE; + + UInt32 sectorIndex = 0; + UInt32 blockSize = Header.ClusterSize(); + bool clusterMode = (Header.IsFat32() || parent >= 0); + if (!clusterMode) + { + blockSize = Header.SectorSize(); + RINOK(SeekToSector(Header.RootDirSector)) + } + + ByteBuf.Alloc(blockSize); + UString curName; + int checkSum = -1; + int numLongRecords = -1; + + for (UInt32 pos = blockSize;; pos += 32) + { + if (pos == blockSize) + { + pos = 0; + + if ((NumDirClusters & 0xFF) == 0) + { + RINOK(OpenProgress()) + } + + if (clusterMode) + { + if (Header.IsEoc(cluster)) + break; + if (!Header.IsValidCluster(cluster)) + return S_FALSE; + PRF(printf("\nCluster = %4X", cluster)); + RINOK(SeekToCluster(cluster)) + const UInt32 newCluster = Fat[cluster]; + if ((newCluster & kFatItemUsedByDirMask) != 0) + return S_FALSE; + Fat[cluster] |= kFatItemUsedByDirMask; + cluster = newCluster; + NumDirClusters++; + NumCurUsedBytes += Header.ClusterSize(); + } + else if (sectorIndex++ >= Header.NumRootDirSectors) + break; + + RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize)) + } + + const Byte *p = ByteBuf + pos; + + if (p[0] == 0) + { + /* + // FreeDOS formats FAT partition with cluster chain longer than required. + if (clusterMode && !Header.IsEoc(cluster)) + return S_FALSE; + */ + break; + } + + if (p[0] == 0xE5) + { + if (numLongRecords > 0) + return S_FALSE; + continue; + } + + Byte attrib = p[11]; + if ((attrib & 0x3F) == 0xF) + { + if (p[0] > 0x7F || Get16(p + 26) != 0) + return S_FALSE; + int longIndex = p[0] & 0x3F; + if (longIndex == 0) + return S_FALSE; + bool isLast = (p[0] & 0x40) != 0; + if (numLongRecords < 0) + { + if (!isLast) + return S_FALSE; + numLongRecords = longIndex; + } + else if (isLast || numLongRecords != longIndex) + return S_FALSE; + + numLongRecords--; + + if (p[12] == 0) + { + wchar_t nameBuf[14]; + wchar_t *dest; + + dest = AddSubStringToName(nameBuf, p + 1, 5); + dest = AddSubStringToName(dest, p + 14, 6); + AddSubStringToName(dest, p + 28, 2); + curName = nameBuf + curName; + if (isLast) + checkSum = p[13]; + if (checkSum != p[13]) + return S_FALSE; + } + } + else + { + if (numLongRecords > 0) + return S_FALSE; + CItem item; + memcpy(item.DosName, p, 11); + + if (checkSum >= 0) + { + Byte sum = 0; + for (unsigned i = 0; i < 11; i++) + sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]); + if (sum == checkSum) + item.UName = curName; + } + + if (item.DosName[0] == 5) + item.DosName[0] = (char)(Byte)0xE5; + item.Attrib = attrib; + item.Flags = p[12]; + item.Size = Get32(p + 28); + item.Cluster = Get16(p + 26); + if (Header.NumFatBits > 16) + item.Cluster |= ((UInt32)Get16(p + 20) << 16); + else + { + // OS/2 and WinNT probably can store EA (extended atributes) in that field. + } + + item.CTime = Get32(p + 14); + item.CTime2 = p[13]; + item.ADate = Get16(p + 18); + item.MTime = Get32(p + 22); + item.Parent = parent; + + if (attrib == 8) + { + VolItem = item; + VolItemDefined = true; + } + else + if (memcmp(item.DosName, ". ", 11) != 0 && + memcmp(item.DosName, ".. ", 11) != 0) + { + if (!item.IsDir()) + NumCurUsedBytes += Header.GetFilePackSize(item.Size); + Items.Add(item); + PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1))); + } + numLongRecords = -1; + curName.Empty(); + checkSum = -1; + } + } + + unsigned finishIndex = Items.Size(); + for (unsigned i = startIndex; i < finishIndex; i++) + { + const CItem &item = Items[i]; + if (item.IsDir()) + { + PRF(printf("\n%S", GetItemPath(i))); + RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1)) + } + } + return S_OK; +} + +HRESULT CDatabase::Open() +{ + Clear(); + bool numFreeClustersDefined = false; + { + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)) + if (!Header.Parse(buf)) + return S_FALSE; + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) + + /* we comment that check to support truncated images */ + /* + if (fileSize < Header.GetPhySize()) + return S_FALSE; + */ + + if (Header.IsFat32()) + { + if (((UInt32)Header.FsInfoSector << Header.SectorSizeLog) + kHeaderSize <= fileSize + && SeekToSector(Header.FsInfoSector) == S_OK + && ReadStream_FALSE(InStream, buf, kHeaderSize) == S_OK + && 0xaa550000 == Get32(buf + 508) + && 0x41615252 == Get32(buf) + && 0x61417272 == Get32(buf + 484)) + { + NumFreeClusters = Get32(buf + 488); + numFreeClustersDefined = (NumFreeClusters <= Header.FatSize); + } + else + Header.HeadersWarning = true; + } + } + + // numFreeClustersDefined = false; // to recalculate NumFreeClusters + if (!numFreeClustersDefined) + NumFreeClusters = 0; + + CByteBuffer byteBuf; + Fat = new UInt32[Header.FatSize]; + + RINOK(OpenProgressFat()) + RINOK(SeekToSector(Header.GetFatSector())) + if (Header.NumFatBits == 32) + { + const UInt32 kBufSize = (1 << 15); + byteBuf.Alloc(kBufSize); + for (UInt32 i = 0;;) + { + UInt32 size = Header.FatSize - i; + if (size == 0) + break; + const UInt32 kBufSize32 = kBufSize / 4; + if (size > kBufSize32) + size = kBufSize32; + const UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog; + RINOK(ReadStream_FALSE(InStream, byteBuf, readSize)) + NumCurUsedBytes += readSize; + + const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf; + UInt32 *dest = Fat + i; + const UInt32 *srcLim = src + size; + if (numFreeClustersDefined) + do + *dest++ = Get32a(src) & 0x0FFFFFFF; + while (++src != srcLim); + else + { + UInt32 numFreeClusters = 0; + do + { + const UInt32 v = Get32a(src) & 0x0FFFFFFF; + *dest++ = v; + numFreeClusters += (UInt32)(v - 1) >> 31; + } + while (++src != srcLim); + NumFreeClusters += numFreeClusters; + } + i += size; + if ((i & 0xFFFFF) == 0) + { + RINOK(OpenProgressFat(!numFreeClustersDefined)) + } + } + } + else + { + const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog; + NumCurUsedBytes += kBufSize; + byteBuf.Alloc(kBufSize); + Byte *p = byteBuf; + RINOK(ReadStream_FALSE(InStream, p, kBufSize)) + const UInt32 fatSize = Header.FatSize; + UInt32 *fat = &Fat[0]; + if (Header.NumFatBits == 16) + for (UInt32 j = 0; j < fatSize; j++) + fat[j] = Get16a(p + j * 2); + else + for (UInt32 j = 0; j < fatSize; j++) + fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF; + + if (!numFreeClustersDefined) + { + UInt32 numFreeClusters = 0; + for (UInt32 i = 0; i < fatSize; i++) + numFreeClusters += (UInt32)(fat[i] - 1) >> 31; + NumFreeClusters = numFreeClusters; + } + } + + RINOK(OpenProgressFat()) + + if ((Fat[0] & 0xFF) != Header.MediaType) + { + // that case can mean error in FAT, + // but xdf file: (MediaType == 0xF0 && Fat[0] == 0xFF9) + // 19.00: so we use non-strict check + if ((Fat[0] & 0xFF) < 0xF0) + return S_FALSE; + } + + RINOK(ReadDir(-1, Header.RootCluster, 0)) + + PhySize = Header.GetPhySize(); + return S_OK; +} + + + +Z7_class_CHandler_final: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp, + CDatabase +{ + Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream) +}; + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + const CItem &item = Items[index]; + CClusterInStream *streamSpec = new CClusterInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Stream = InStream; + streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog; + streamSpec->BlockSizeLog = Header.ClusterSizeLog; + streamSpec->Size = item.Size; + + const UInt32 numClusters = Header.GetNumClusters(item.Size); + streamSpec->Vector.ClearAndReserve(numClusters); + UInt32 cluster = item.Cluster; + UInt32 size = item.Size; + + if (size == 0) + { + if (cluster != 0) + return S_FALSE; + } + else + { + const UInt32 clusterSize = Header.ClusterSize(); + for (;; size -= clusterSize) + { + if (!Header.IsValidCluster(cluster)) + return S_FALSE; + streamSpec->Vector.AddInReserved(cluster - 2); + cluster = Fat[cluster]; + if (size <= clusterSize) + break; + } + if (!Header.IsEocAndUnused(cluster)) + return S_FALSE; + } + RINOK(streamSpec->InitAndSeek()) + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + kpidShortName +}; + +enum +{ + kpidNumFats = kpidUserDefined + // kpidOemName, + // kpidVolName, + // kpidFileSysType +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidFileSystem, VT_BSTR}, + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidFreeSpace, VT_UI8}, + { NULL, kpidHeadersSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidVolumeName, VT_BSTR}, + + { "FATs", kpidNumFats, VT_UI4}, + { NULL, kpidSectorSize, VT_UI4}, + { NULL, kpidId, VT_UI4}, + // { "OEM Name", kpidOemName, VT_BSTR}, + // { "Volume Name", kpidVolName, VT_BSTR}, + // { "File System Type", kpidFileSysType, VT_BSTR} + // { NULL, kpidSectorsPerTrack, VT_UI4}, + // { NULL, kpidNumHeads, VT_UI4}, + // { NULL, kpidHiddenSectors, VT_UI4} +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + + +static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop) +{ + FILETIME localFileTime, utc; + if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime)) + if (LocalFileTimeToFileTime(&localFileTime, &utc)) + { + UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; + t64 += ms10 * 100000; + utc.dwLowDateTime = (DWORD)t64; + utc.dwHighDateTime = (DWORD)(t64 >> 32); + prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2); + } +} + +/* +static void StringToProp(const Byte *src, unsigned size, NWindows::NCOM::CPropVariant &prop) +{ + char dest[32]; + memcpy(dest, src, size); + dest[size] = 0; + prop = FatStringToUnicode(dest); +} + +#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop) +*/ + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidFileSystem: + { + char s[16]; + s[0] = 'F'; + s[1] = 'A'; + s[2] = 'T'; + ConvertUInt32ToString(Header.NumFatBits, s + 3); + prop = s; + break; + } + case kpidClusterSize: prop = Header.ClusterSize(); break; + case kpidPhySize: prop = PhySize; break; + case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; + case kpidHeadersSize: prop = GetHeadersSize(); break; + case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break; + case kpidShortComment: + case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; + case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; + case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; + // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; + // case kpidNumHeads: prop = Header.NumHeads; break; + // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break; + case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break; + // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break; + // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break; + // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; + case kpidWarningFlags: + { + UInt32 v = 0; + if (Header.HeadersWarning) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = Items[index]; + switch (propID) + { + case kpidPath: prop = GetItemPath(index); break; + case kpidShortName: prop = item.GetShortName(); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break; + case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; + case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break; + case kpidAttrib: prop = (UInt32)item.Attrib; break; + case kpidSize: if (!item.IsDir()) prop = item.Size; break; + case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + OpenCallback = callback; + InStream = stream; + HRESULT res; + try + { + res = CDatabase::Open(); + if (res == S_OK) + return S_OK; + } + catch(...) + { + Close(); + throw; + } + Close(); + return res; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + ClearAndClose(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const CItem &item = Items[allFilesMode ? i : indices[i]]; + if (!item.IsDir()) + totalSize += item.Size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + + for (i = 0;; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i == numItems) + break; + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = Items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + totalPackSize += Header.GetFilePackSize(item.Size); + totalSize += item.Size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(); + + int res = NExtract::NOperationResult::kDataError; + CMyComPtr inStream; + HRESULT hres = GetStream(index, &inStream); + if (hres != S_FALSE) + { + RINOK(hres) + if (inStream) + { + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) + if (copyCoderSpec->TotalSize == item.Size) + res = NExtract::NOperationResult::kOK; + } + } + outStreamSpec->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(res)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = Items.Size(); + return S_OK; +} + +static const Byte k_Signature[] = { 0x55, 0xAA }; + +REGISTER_ARC_I( + "FAT", "fat img", NULL, 0xDA, + k_Signature, + 0x1FE, + 0, + IsArc_Fat) + +}} diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp index 15a699b71..1f746aa97 100644 --- a/CPP/7zip/Archive/FlvHandler.cpp +++ b/CPP/7zip/Archive/FlvHandler.cpp @@ -1,521 +1,521 @@ -// FlvHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/InBuffer.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#define GetBe24(p) ( \ - ((UInt32)((const Byte *)(p))[0] << 16) | \ - ((UInt32)((const Byte *)(p))[1] << 8) | \ - ((const Byte *)(p))[2] ) - -// #define Get16(p) GetBe16(p) -#define Get24(p) GetBe24(p) -#define Get32(p) GetBe32(p) - -namespace NArchive { -namespace NFlv { - -// static const UInt32 kFileSizeMax = (UInt32)1 << 30; -static const UInt32 kNumChunksMax = (UInt32)1 << 23; - -static const UInt32 kTagHeaderSize = 11; - -static const Byte kFlag_Video = 1; -static const Byte kFlag_Audio = 4; - -static const Byte kType_Audio = 8; -static const Byte kType_Video = 9; -static const Byte kType_Meta = 18; -static const unsigned kNumTypes = 19; - -struct CItem -{ - CByteBuffer Data; - Byte Type; -}; - -struct CItem2 -{ - Byte Type; - Byte SubType; - Byte Props; - bool SameSubTypes; - unsigned NumChunks; - size_t Size; - - CReferenceBuf *BufSpec; - CMyComPtr RefBuf; - - bool IsAudio() const { return Type == kType_Audio; } -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CMyComPtr _stream; - CObjectVector _items2; - CByteBuffer _metadata; - bool _isRaw; - UInt64 _phySize; - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - // AString GetComment(); -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidNumBlocks, - kpidComment -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -static const char * const g_AudioTypes[16] = -{ - "pcm" - , "adpcm" - , "mp3" - , "pcm_le" - , "nellymoser16" - , "nellymoser8" - , "nellymoser" - , "g711a" - , "g711m" - , "audio9" - , "aac" - , "speex" - , "audio12" - , "audio13" - , "mp3" - , "audio15" -}; - -static const char * const g_VideoTypes[16] = -{ - "video0" - , "jpeg" - , "h263" - , "screen" - , "vp6" - , "vp6alpha" - , "screen2" - , "avc" - , "video8" - , "video9" - , "video10" - , "video11" - , "video12" - , "video13" - , "video14" - , "video15" -}; - -static const char * const g_Rates[4] = -{ - "5.5 kHz" - , "11 kHz" - , "22 kHz" - , "44 kHz" -}; - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - const CItem2 &item = _items2[index]; - switch (propID) - { - case kpidExtension: - prop = _isRaw ? - (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) : - (item.IsAudio() ? "audio.flv" : "video.flv"); - break; - case kpidSize: - case kpidPackSize: - prop = (UInt64)item.Size; - break; - case kpidNumBlocks: prop = (UInt32)item.NumChunks; break; - case kpidComment: - { - char sz[64]; - char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) ); - if (item.IsAudio()) - { - *s++ = ' '; - s = MyStpCpy(s, g_Rates[(item.Props >> 2) & 3]); - s = MyStpCpy(s, (item.Props & 2) ? " 16-bit" : " 8-bit"); - s = MyStpCpy(s, (item.Props & 1) ? " stereo" : " mono"); - } - prop = sz; - break; - } - } - prop.Detach(value); - return S_OK; -} - -/* -AString CHandler::GetComment() -{ - const Byte *p = _metadata; - size_t size = _metadata.Size(); - AString res; - if (size > 0) - { - p++; - size--; - for (;;) - { - if (size < 2) - break; - int len = Get16(p); - p += 2; - size -= 2; - if (len == 0 || (size_t)len > size) - break; - { - AString temp; - temp.SetFrom_CalcLen((const char *)p, len); - if (!res.IsEmpty()) - res += '\n'; - res += temp; - } - p += len; - size -= len; - if (size < 1) - break; - Byte type = *p++; - size--; - bool ok = false; - switch (type) - { - case 0: - { - if (size < 8) - break; - ok = true; - Byte reverse[8]; - for (int i = 0; i < 8; i++) - { - bool little_endian = 1; - if (little_endian) - reverse[i] = p[7 - i]; - else - reverse[i] = p[i]; - } - double d = *(double *)reverse; - char temp[32]; - sprintf(temp, " = %.3f", d); - res += temp; - p += 8; - size -= 8; - break; - } - case 8: - { - if (size < 4) - break; - ok = true; - // UInt32 numItems = Get32(p); - p += 4; - size -= 4; - break; - } - } - if (!ok) - break; - } - } - return res; -} -*/ - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - // COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - // case kpidComment: prop = GetComment(); break; - case kpidPhySize: prop = (UInt64)_phySize; break; - case kpidIsNotArcType: prop = true; break; - } - prop.Detach(value); - return S_OK; - // COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) -{ - const UInt32 kHeaderSize = 13; - Byte header[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, header, kHeaderSize)) - if (header[0] != 'F' || - header[1] != 'L' || - header[2] != 'V' || - header[3] != 1 || - (header[4] & 0xFA) != 0) - return S_FALSE; - UInt64 offset = Get32(header + 5); - if (offset != 9 || Get32(header + 9) != 0) - return S_FALSE; - offset = kHeaderSize; - - CInBuffer inBuf; - if (!inBuf.Create(1 << 15)) - return E_OUTOFMEMORY; - inBuf.SetStream(stream); - - CObjectVector items; - int lasts[kNumTypes]; - unsigned i; - for (i = 0; i < kNumTypes; i++) - lasts[i] = -1; - - _phySize = offset; - for (;;) - { - Byte buf[kTagHeaderSize]; - CItem item; - if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize) - break; - item.Type = buf[0]; - UInt32 size = Get24(buf + 1); - if (size < 1) - break; - // item.Time = Get24(buf + 4); - // item.Time |= (UInt32)buf[7] << 24; - if (Get24(buf + 8) != 0) // streamID - break; - - UInt32 curSize = kTagHeaderSize + size + 4; - item.Data.Alloc(curSize); - memcpy(item.Data, buf, kTagHeaderSize); - if (inBuf.ReadBytes(item.Data + kTagHeaderSize, size) != size) - break; - if (inBuf.ReadBytes(item.Data + kTagHeaderSize + size, 4) != 4) - break; - - if (Get32(item.Data + kTagHeaderSize + size) != kTagHeaderSize + size) - break; - - offset += curSize; - - // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size); - - if (item.Type == kType_Meta) - { - // _metadata = item.Buf; - } - else - { - if (item.Type != kType_Audio && item.Type != kType_Video) - break; - if (items.Size() >= kNumChunksMax) - return S_FALSE; - Byte firstByte = item.Data[kTagHeaderSize]; - Byte subType, props; - if (item.Type == kType_Audio) - { - subType = (Byte)(firstByte >> 4); - props = (Byte)(firstByte & 0xF); - } - else - { - subType = (Byte)(firstByte & 0xF); - props = (Byte)(firstByte >> 4); - } - int last = lasts[item.Type]; - if (last < 0) - { - CItem2 item2; - item2.RefBuf = item2.BufSpec = new CReferenceBuf; - item2.Size = curSize; - item2.Type = item.Type; - item2.SubType = subType; - item2.Props = props; - item2.NumChunks = 1; - item2.SameSubTypes = true; - lasts[item.Type] = (int)_items2.Add(item2); - } - else - { - CItem2 &item2 = _items2[last]; - if (subType != item2.SubType) - item2.SameSubTypes = false; - item2.Size += curSize; - item2.NumChunks++; - } - items.Add(item); - } - _phySize = offset; - if (callback && (items.Size() & 0xFF) == 0) - { - RINOK(callback->SetCompleted(NULL, &offset)) - } - } - if (items.IsEmpty()) - return S_FALSE; - - _isRaw = (_items2.Size() == 1); - for (i = 0; i < _items2.Size(); i++) - { - CItem2 &item2 = _items2[i]; - CByteBuffer &itemBuf = item2.BufSpec->Buf; - if (_isRaw) - { - if (!item2.SameSubTypes) - return S_FALSE; - itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks); - item2.Size = 0; - } - else - { - itemBuf.Alloc(kHeaderSize + (size_t)item2.Size); - memcpy(itemBuf, header, kHeaderSize); - itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video; - item2.Size = kHeaderSize; - } - } - - for (i = 0; i < items.Size(); i++) - { - const CItem &item = items[i]; - CItem2 &item2 = _items2[lasts[item.Type]]; - size_t size = item.Data.Size(); - const Byte *src = item.Data; - if (_isRaw) - { - src += kTagHeaderSize + 1; - size -= (kTagHeaderSize + 4 + 1); - } - if (size != 0) - { - memcpy(item2.BufSpec->Buf + item2.Size, src, size); - item2.Size += size; - } - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - HRESULT res; - try - { - res = Open2(inStream, callback); - if (res == S_OK) - _stream = inStream; - } - catch(...) { res = S_FALSE; } - if (res != S_OK) - { - Close(); - return S_FALSE; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - _stream.Release(); - _items2.Clear(); - // _metadata.SetCapacity(0); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items2.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items2.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items2[allFilesMode ? i : indices[i]].Size; - extractCallback->SetTotal(totalSize); - - totalSize = 0; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()) - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem2 &item = _items2[index]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - totalSize += item.Size; - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - if (outStream) - { - RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size())) - } - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Init(_items2[index].BufSpec); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -static const Byte k_Signature[] = { 'F', 'L', 'V', 1, }; - -REGISTER_ARC_I( - "FLV", "flv", NULL, 0xD6, - k_Signature, - 0, - 0, - NULL) - -}} +// FlvHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/InBuffer.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#define GetBe24(p) ( \ + ((UInt32)((const Byte *)(p))[0] << 16) | \ + ((UInt32)((const Byte *)(p))[1] << 8) | \ + ((const Byte *)(p))[2] ) + +// #define Get16(p) GetBe16(p) +#define Get24(p) GetBe24(p) +#define Get32(p) GetBe32(p) + +namespace NArchive { +namespace NFlv { + +// static const UInt32 kFileSizeMax = (UInt32)1 << 30; +static const UInt32 kNumChunksMax = (UInt32)1 << 23; + +static const UInt32 kTagHeaderSize = 11; + +static const Byte kFlag_Video = 1; +static const Byte kFlag_Audio = 4; + +static const Byte kType_Audio = 8; +static const Byte kType_Video = 9; +static const Byte kType_Meta = 18; +static const unsigned kNumTypes = 19; + +struct CItem +{ + CByteBuffer Data; + Byte Type; +}; + +struct CItem2 +{ + Byte Type; + Byte SubType; + Byte Props; + bool SameSubTypes; + unsigned NumChunks; + size_t Size; + + CReferenceBuf *BufSpec; + CMyComPtr RefBuf; + + bool IsAudio() const { return Type == kType_Audio; } +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CMyComPtr _stream; + CObjectVector _items2; + CByteBuffer _metadata; + bool _isRaw; + UInt64 _phySize; + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); + // AString GetComment(); +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidNumBlocks, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +static const char * const g_AudioTypes[16] = +{ + "pcm" + , "adpcm" + , "mp3" + , "pcm_le" + , "nellymoser16" + , "nellymoser8" + , "nellymoser" + , "g711a" + , "g711m" + , "audio9" + , "aac" + , "speex" + , "audio12" + , "audio13" + , "mp3" + , "audio15" +}; + +static const char * const g_VideoTypes[16] = +{ + "video0" + , "jpeg" + , "h263" + , "screen" + , "vp6" + , "vp6alpha" + , "screen2" + , "avc" + , "video8" + , "video9" + , "video10" + , "video11" + , "video12" + , "video13" + , "video14" + , "video15" +}; + +static const char * const g_Rates[4] = +{ + "5.5 kHz" + , "11 kHz" + , "22 kHz" + , "44 kHz" +}; + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + const CItem2 &item = _items2[index]; + switch (propID) + { + case kpidExtension: + prop = _isRaw ? + (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) : + (item.IsAudio() ? "audio.flv" : "video.flv"); + break; + case kpidSize: + case kpidPackSize: + prop = (UInt64)item.Size; + break; + case kpidNumBlocks: prop = (UInt32)item.NumChunks; break; + case kpidComment: + { + char sz[64]; + char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) ); + if (item.IsAudio()) + { + *s++ = ' '; + s = MyStpCpy(s, g_Rates[(item.Props >> 2) & 3]); + s = MyStpCpy(s, (item.Props & 2) ? " 16-bit" : " 8-bit"); + s = MyStpCpy(s, (item.Props & 1) ? " stereo" : " mono"); + } + prop = sz; + break; + } + } + prop.Detach(value); + return S_OK; +} + +/* +AString CHandler::GetComment() +{ + const Byte *p = _metadata; + size_t size = _metadata.Size(); + AString res; + if (size > 0) + { + p++; + size--; + for (;;) + { + if (size < 2) + break; + int len = Get16(p); + p += 2; + size -= 2; + if (len == 0 || (size_t)len > size) + break; + { + AString temp; + temp.SetFrom_CalcLen((const char *)p, len); + if (!res.IsEmpty()) + res += '\n'; + res += temp; + } + p += len; + size -= len; + if (size < 1) + break; + Byte type = *p++; + size--; + bool ok = false; + switch (type) + { + case 0: + { + if (size < 8) + break; + ok = true; + Byte reverse[8]; + for (int i = 0; i < 8; i++) + { + bool little_endian = 1; + if (little_endian) + reverse[i] = p[7 - i]; + else + reverse[i] = p[i]; + } + double d = *(double *)reverse; + char temp[32]; + sprintf(temp, " = %.3f", d); + res += temp; + p += 8; + size -= 8; + break; + } + case 8: + { + if (size < 4) + break; + ok = true; + // UInt32 numItems = Get32(p); + p += 4; + size -= 4; + break; + } + } + if (!ok) + break; + } + } + return res; +} +*/ + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + // COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + // case kpidComment: prop = GetComment(); break; + case kpidPhySize: prop = (UInt64)_phySize; break; + case kpidIsNotArcType: prop = true; break; + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + const UInt32 kHeaderSize = 13; + Byte header[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, header, kHeaderSize)) + if (header[0] != 'F' || + header[1] != 'L' || + header[2] != 'V' || + header[3] != 1 || + (header[4] & 0xFA) != 0) + return S_FALSE; + UInt64 offset = Get32(header + 5); + if (offset != 9 || Get32(header + 9) != 0) + return S_FALSE; + offset = kHeaderSize; + + CInBuffer inBuf; + if (!inBuf.Create(1 << 15)) + return E_OUTOFMEMORY; + inBuf.SetStream(stream); + + CObjectVector items; + int lasts[kNumTypes]; + unsigned i; + for (i = 0; i < kNumTypes; i++) + lasts[i] = -1; + + _phySize = offset; + for (;;) + { + Byte buf[kTagHeaderSize]; + CItem item; + if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize) + break; + item.Type = buf[0]; + UInt32 size = Get24(buf + 1); + if (size < 1) + break; + // item.Time = Get24(buf + 4); + // item.Time |= (UInt32)buf[7] << 24; + if (Get24(buf + 8) != 0) // streamID + break; + + UInt32 curSize = kTagHeaderSize + size + 4; + item.Data.Alloc(curSize); + memcpy(item.Data, buf, kTagHeaderSize); + if (inBuf.ReadBytes(item.Data + kTagHeaderSize, size) != size) + break; + if (inBuf.ReadBytes(item.Data + kTagHeaderSize + size, 4) != 4) + break; + + if (Get32(item.Data + kTagHeaderSize + size) != kTagHeaderSize + size) + break; + + offset += curSize; + + // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size); + + if (item.Type == kType_Meta) + { + // _metadata = item.Buf; + } + else + { + if (item.Type != kType_Audio && item.Type != kType_Video) + break; + if (items.Size() >= kNumChunksMax) + return S_FALSE; + Byte firstByte = item.Data[kTagHeaderSize]; + Byte subType, props; + if (item.Type == kType_Audio) + { + subType = (Byte)(firstByte >> 4); + props = (Byte)(firstByte & 0xF); + } + else + { + subType = (Byte)(firstByte & 0xF); + props = (Byte)(firstByte >> 4); + } + int last = lasts[item.Type]; + if (last < 0) + { + CItem2 item2; + item2.RefBuf = item2.BufSpec = new CReferenceBuf; + item2.Size = curSize; + item2.Type = item.Type; + item2.SubType = subType; + item2.Props = props; + item2.NumChunks = 1; + item2.SameSubTypes = true; + lasts[item.Type] = (int)_items2.Add(item2); + } + else + { + CItem2 &item2 = _items2[last]; + if (subType != item2.SubType) + item2.SameSubTypes = false; + item2.Size += curSize; + item2.NumChunks++; + } + items.Add(item); + } + _phySize = offset; + if (callback && (items.Size() & 0xFF) == 0) + { + RINOK(callback->SetCompleted(NULL, &offset)) + } + } + if (items.IsEmpty()) + return S_FALSE; + + _isRaw = (_items2.Size() == 1); + for (i = 0; i < _items2.Size(); i++) + { + CItem2 &item2 = _items2[i]; + CByteBuffer &itemBuf = item2.BufSpec->Buf; + if (_isRaw) + { + if (!item2.SameSubTypes) + return S_FALSE; + itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks); + item2.Size = 0; + } + else + { + itemBuf.Alloc(kHeaderSize + (size_t)item2.Size); + memcpy(itemBuf, header, kHeaderSize); + itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video; + item2.Size = kHeaderSize; + } + } + + for (i = 0; i < items.Size(); i++) + { + const CItem &item = items[i]; + CItem2 &item2 = _items2[lasts[item.Type]]; + size_t size = item.Data.Size(); + const Byte *src = item.Data; + if (_isRaw) + { + src += kTagHeaderSize + 1; + size -= (kTagHeaderSize + 4 + 1); + } + if (size != 0) + { + memcpy(item2.BufSpec->Buf + item2.Size, src, size); + item2.Size += size; + } + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + HRESULT res; + try + { + res = Open2(inStream, callback); + if (res == S_OK) + _stream = inStream; + } + catch(...) { res = S_FALSE; } + if (res != S_OK) + { + Close(); + return S_FALSE; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + _stream.Release(); + _items2.Clear(); + // _metadata.SetCapacity(0); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items2.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items2.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items2[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()) + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem2 &item = _items2[index]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + totalSize += item.Size; + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + if (outStream) + { + RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size())) + } + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Init(_items2[index].BufSpec); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +static const Byte k_Signature[] = { 'F', 'L', 'V', 1, }; + +REGISTER_ARC_I( + "FLV", "flv", NULL, 0xD6, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp index 5dbf7d334..4c291c455 100644 --- a/CPP/7zip/Archive/GptHandler.cpp +++ b/CPP/7zip/Archive/GptHandler.cpp @@ -1,473 +1,473 @@ -// GptHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -using namespace NWindows; - -namespace NArchive { - -namespace NMbr { -const char *GetFileSystem(ISequentialInStream *stream, UInt64 partitionSize); -} - -namespace NFat { -API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); -} - -namespace NGpt { - -static const unsigned k_SignatureSize = 12; -static const Byte k_Signature[k_SignatureSize] = - { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }; - -static const CUInt32PCharPair g_PartitionFlags[] = -{ - { 0, "Sys" }, - { 1, "Ignore" }, - { 2, "Legacy" }, - { 60, "Win-Read-only" }, - { 62, "Win-Hidden" }, - { 63, "Win-Not-Automount" } -}; - -static const unsigned kNameLen = 36; - -struct CPartition -{ - Byte Type[16]; - Byte Id[16]; - UInt64 FirstLba; - UInt64 LastLba; - UInt64 Flags; - const char *Ext; // detected later - Byte Name[kNameLen * 2]; - - bool IsUnused() const - { - for (unsigned i = 0; i < 16; i++) - if (Type[i] != 0) - return false; - return true; - } - - UInt64 GetSize(unsigned sectorSizeLog) const { return (LastLba - FirstLba + 1) << sectorSizeLog; } - UInt64 GetPos(unsigned sectorSizeLog) const { return FirstLba << sectorSizeLog; } - UInt64 GetEnd(unsigned sectorSizeLog) const { return (LastLba + 1) << sectorSizeLog; } - - void Parse(const Byte *p) - { - memcpy(Type, p, 16); - memcpy(Id, p + 16, 16); - FirstLba = Get64(p + 32); - LastLba = Get64(p + 40); - Flags = Get64(p + 48); - memcpy(Name, p + 56, kNameLen * 2); - Ext = NULL; - } -}; - - -struct CPartType -{ - UInt32 Id; - const char *Ext; - const char *Type; -}; - -static const CPartType kPartTypes[] = -{ - // { 0x0, NULL, "Unused" }, - - { 0x21686148, NULL, "BIOS Boot" }, - - { 0xC12A7328, NULL, "EFI System" }, - { 0x024DEE41, NULL, "MBR" }, - - { 0xE3C9E316, NULL, "Windows MSR" }, - { 0xEBD0A0A2, NULL, "Windows BDP" }, - { 0x5808C8AA, NULL, "Windows LDM Metadata" }, - { 0xAF9B60A0, NULL, "Windows LDM Data" }, - { 0xDE94BBA4, NULL, "Windows Recovery" }, - // { 0x37AFFC90, NULL, "IBM GPFS" }, - // { 0xE75CAF8F, NULL, "Windows Storage Spaces" }, - - { 0x0FC63DAF, NULL, "Linux Data" }, - { 0x0657FD6D, NULL, "Linux Swap" }, - { 0x44479540, NULL, "Linux root (x86)" }, - { 0x4F68BCE3, NULL, "Linux root (x86-64)" }, - { 0x69DAD710, NULL, "Linux root (ARM)" }, - { 0xB921B045, NULL, "Linux root (ARM64)" }, - { 0x993D8D3D, NULL, "Linux root (IA-64)" }, - - - { 0x83BD6B9D, NULL, "FreeBSD Boot" }, - { 0x516E7CB4, NULL, "FreeBSD Data" }, - { 0x516E7CB5, NULL, "FreeBSD Swap" }, - { 0x516E7CB6, "ufs", "FreeBSD UFS" }, - { 0x516E7CB8, NULL, "FreeBSD Vinum" }, - { 0x516E7CB8, "zfs", "FreeBSD ZFS" }, - - { 0x48465300, "hfsx", "HFS+" }, - { 0x7C3457EF, "apfs", "APFS" }, -}; - -static int FindPartType(const Byte *guid) -{ - const UInt32 val = Get32(guid); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPartTypes); i++) - if (kPartTypes[i].Id == val) - return (int)i; - return -1; -} - - -static void RawLeGuidToString_Upper(const Byte *g, char *s) -{ - RawLeGuidToString(g, s); - // MyStringUpper_Ascii(s); -} - - -Z7_class_CHandler_final: public CHandlerCont -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - CRecordVector _items; - UInt64 _totalSize; - unsigned _sectorSizeLog; - Byte Guid[16]; - - CByteBuffer _buffer; - - HRESULT Open2(IInStream *stream); - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override - { - const CPartition &item = _items[index]; - pos = item.GetPos(_sectorSizeLog); - size = item.GetSize(_sectorSizeLog); - return NExtract::NOperationResult::kOK; - } -}; - - -HRESULT CHandler::Open2(IInStream *stream) -{ - const unsigned kBufSize = 2 << 12; - _buffer.Alloc(kBufSize); - RINOK(ReadStream_FALSE(stream, _buffer, kBufSize)) - const Byte *buf = _buffer; - if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) - return S_FALSE; - { - for (unsigned sectorSizeLog = 9;; sectorSizeLog += 3) - { - if (sectorSizeLog > 12) - return S_FALSE; - if (memcmp(buf + ((size_t)1 << sectorSizeLog), k_Signature, k_SignatureSize) == 0) - { - buf += ((size_t)1 << sectorSizeLog); - _sectorSizeLog = sectorSizeLog; - break; - } - } - } - const UInt32 kSectorSize = 1u << _sectorSizeLog; - { - // if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision - const UInt32 headerSize = Get32(buf + 12); // = 0x5C usually - if (headerSize > kSectorSize) - return S_FALSE; - const UInt32 crc = Get32(buf + 0x10); - SetUi32(_buffer + kSectorSize + 0x10, 0) - if (CrcCalc(_buffer + kSectorSize, headerSize) != crc) - return S_FALSE; - } - // UInt32 reserved = Get32(buf + 0x14); - const UInt64 curLba = Get64(buf + 0x18); - if (curLba != 1) - return S_FALSE; - const UInt64 backupLba = Get64(buf + 0x20); - // UInt64 firstUsableLba = Get64(buf + 0x28); - // UInt64 lastUsableLba = Get64(buf + 0x30); - memcpy(Guid, buf + 0x38, 16); - const UInt64 tableLba = Get64(buf + 0x48); - if (tableLba < 2 || (tableLba >> (63 - _sectorSizeLog)) != 0) - return S_FALSE; - const UInt32 numEntries = Get32(buf + 0x50); - if (numEntries > (1 << 16)) - return S_FALSE; - const UInt32 entrySize = Get32(buf + 0x54); // = 128 usually - if (entrySize < 128 || entrySize > (1 << 12)) - return S_FALSE; - const UInt32 entriesCrc = Get32(buf + 0x58); - - const UInt32 tableSize = entrySize * numEntries; - const UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1); - _buffer.Alloc(tableSizeAligned); - const UInt64 tableOffset = tableLba * kSectorSize; - RINOK(InStream_SeekSet(stream, tableOffset)) - RINOK(ReadStream_FALSE(stream, _buffer, tableSizeAligned)) - - if (CrcCalc(_buffer, tableSize) != entriesCrc) - return S_FALSE; - - _totalSize = tableOffset + tableSizeAligned; - - for (UInt32 i = 0; i < numEntries; i++) - { - CPartition item; - item.Parse(_buffer + i * entrySize); - if (item.IsUnused()) - continue; - if (item.LastLba < item.FirstLba) - return S_FALSE; - if ((item.LastLba >> (63 - _sectorSizeLog)) != 0) - return S_FALSE; - const UInt64 endPos = item.GetEnd(_sectorSizeLog); - if (_totalSize < endPos) - _totalSize = endPos; - _items.Add(item); - } - - _buffer.Free(); - { - if ((backupLba >> (63 - _sectorSizeLog)) != 0) - return S_FALSE; - const UInt64 end = (backupLba + 1) * kSectorSize; - if (_totalSize < end) - _totalSize = end; - } - { - UInt64 fileEnd; - RINOK(InStream_GetSize_SeekToEnd(stream, fileEnd)) - - if (_totalSize < fileEnd) - { - const UInt64 rem = fileEnd - _totalSize; - const UInt64 kRemMax = 1 << 22; - if (rem <= kRemMax) - { - RINOK(InStream_SeekSet(stream, _totalSize)) - bool areThereNonZeros = false; - UInt64 numZeros = 0; - if (ReadZeroTail(stream, areThereNonZeros, numZeros, kRemMax) == S_OK) - if (!areThereNonZeros) - _totalSize += numZeros; - } - } - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(stream)) - _stream = stream; - - FOR_VECTOR (fileIndex, _items) - { - CPartition &item = _items[fileIndex]; - const int typeIndex = FindPartType(item.Type); - if (typeIndex < 0) - continue; - const CPartType &t = kPartTypes[(unsigned)typeIndex]; - if (t.Ext) - { - item.Ext = t.Ext; - continue; - } - if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows")) - { - CMyComPtr inStream; - if ( - // ((IInArchiveGetStream *)this)-> - GetStream(fileIndex, &inStream) == S_OK && inStream) - { - const char *fs = NMbr::GetFileSystem(inStream, item.GetSize(_sectorSizeLog)); - if (fs) - item.Ext = fs; - } - } - } - - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _sectorSizeLog = 0; - _totalSize = 0; - memset(Guid, 0, sizeof(Guid)); - _items.Clear(); - _stream.Release(); - return S_OK; -} - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidFileSystem, - kpidCharacts, - kpidOffset, - kpidId -}; - -static const Byte kArcProps[] = -{ - kpidSectorSize, - kpidId -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: - { - if (_items.Size() == 1) - prop = (UInt32)0; - break; - } - case kpidPhySize: prop = _totalSize; break; - case kpidSectorSize: prop = (UInt32)((UInt32)1 << _sectorSizeLog); break; - case kpidId: - { - char s[48]; - RawLeGuidToString_Upper(Guid, s); - prop = s; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CPartition &item = _items[index]; - - switch (propID) - { - case kpidPath: - { - // Windows BDP partitions can have identical names. - // So we add the partition number at front - UString s; - s.Add_UInt32(index); - { - UString s2; - for (unsigned i = 0; i < kNameLen; i++) - { - wchar_t c = (wchar_t)Get16(item.Name + i * 2); - if (c == 0) - break; - s2 += c; - } - if (!s2.IsEmpty()) - { - s.Add_Dot(); - s += s2; - } - } - { - s.Add_Dot(); - if (item.Ext) - { - AString fs (item.Ext); - fs.MakeLower_Ascii(); - s += fs; - } - else - s += "img"; - } - prop = s; - break; - } - - case kpidSize: - case kpidPackSize: prop = item.GetSize(_sectorSizeLog); break; - case kpidOffset: prop = item.GetPos(_sectorSizeLog); break; - - case kpidFileSystem: - { - char s[48]; - const char *res; - const int typeIndex = FindPartType(item.Type); - if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type) - res = kPartTypes[(unsigned)typeIndex].Type; - else - { - RawLeGuidToString_Upper(item.Type, s); - res = s; - } - prop = res; - break; - } - - case kpidId: - { - char s[48]; - RawLeGuidToString_Upper(item.Id, s); - prop = s; - break; - } - - case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -// we suppport signature only for 512-bytes sector. -REGISTER_ARC_I( - "GPT", "gpt mbr", NULL, 0xCB, - k_Signature, - 1 << 9, - 0, - NULL) - -}} +// GptHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { + +namespace NMbr { +const char *GetFileSystem(ISequentialInStream *stream, UInt64 partitionSize); +} + +namespace NFat { +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); +} + +namespace NGpt { + +static const unsigned k_SignatureSize = 12; +static const Byte k_Signature[k_SignatureSize] = + { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }; + +static const CUInt32PCharPair g_PartitionFlags[] = +{ + { 0, "Sys" }, + { 1, "Ignore" }, + { 2, "Legacy" }, + { 60, "Win-Read-only" }, + { 62, "Win-Hidden" }, + { 63, "Win-Not-Automount" } +}; + +static const unsigned kNameLen = 36; + +struct CPartition +{ + Byte Type[16]; + Byte Id[16]; + UInt64 FirstLba; + UInt64 LastLba; + UInt64 Flags; + const char *Ext; // detected later + Byte Name[kNameLen * 2]; + + bool IsUnused() const + { + for (unsigned i = 0; i < 16; i++) + if (Type[i] != 0) + return false; + return true; + } + + UInt64 GetSize(unsigned sectorSizeLog) const { return (LastLba - FirstLba + 1) << sectorSizeLog; } + UInt64 GetPos(unsigned sectorSizeLog) const { return FirstLba << sectorSizeLog; } + UInt64 GetEnd(unsigned sectorSizeLog) const { return (LastLba + 1) << sectorSizeLog; } + + void Parse(const Byte *p) + { + memcpy(Type, p, 16); + memcpy(Id, p + 16, 16); + FirstLba = Get64(p + 32); + LastLba = Get64(p + 40); + Flags = Get64(p + 48); + memcpy(Name, p + 56, kNameLen * 2); + Ext = NULL; + } +}; + + +struct CPartType +{ + UInt32 Id; + const char *Ext; + const char *Type; +}; + +static const CPartType kPartTypes[] = +{ + // { 0x0, NULL, "Unused" }, + + { 0x21686148, NULL, "BIOS Boot" }, + + { 0xC12A7328, NULL, "EFI System" }, + { 0x024DEE41, NULL, "MBR" }, + + { 0xE3C9E316, NULL, "Windows MSR" }, + { 0xEBD0A0A2, NULL, "Windows BDP" }, + { 0x5808C8AA, NULL, "Windows LDM Metadata" }, + { 0xAF9B60A0, NULL, "Windows LDM Data" }, + { 0xDE94BBA4, NULL, "Windows Recovery" }, + // { 0x37AFFC90, NULL, "IBM GPFS" }, + // { 0xE75CAF8F, NULL, "Windows Storage Spaces" }, + + { 0x0FC63DAF, NULL, "Linux Data" }, + { 0x0657FD6D, NULL, "Linux Swap" }, + { 0x44479540, NULL, "Linux root (x86)" }, + { 0x4F68BCE3, NULL, "Linux root (x86-64)" }, + { 0x69DAD710, NULL, "Linux root (ARM)" }, + { 0xB921B045, NULL, "Linux root (ARM64)" }, + { 0x993D8D3D, NULL, "Linux root (IA-64)" }, + + + { 0x83BD6B9D, NULL, "FreeBSD Boot" }, + { 0x516E7CB4, NULL, "FreeBSD Data" }, + { 0x516E7CB5, NULL, "FreeBSD Swap" }, + { 0x516E7CB6, "ufs", "FreeBSD UFS" }, + { 0x516E7CB8, NULL, "FreeBSD Vinum" }, + { 0x516E7CB8, "zfs", "FreeBSD ZFS" }, + + { 0x48465300, "hfsx", "HFS+" }, + { 0x7C3457EF, "apfs", "APFS" }, +}; + +static int FindPartType(const Byte *guid) +{ + const UInt32 val = Get32(guid); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPartTypes); i++) + if (kPartTypes[i].Id == val) + return (int)i; + return -1; +} + + +static void RawLeGuidToString_Upper(const Byte *g, char *s) +{ + RawLeGuidToString(g, s); + // MyStringUpper_Ascii(s); +} + + +Z7_class_CHandler_final: public CHandlerCont +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + CRecordVector _items; + UInt64 _totalSize; + unsigned _sectorSizeLog; + Byte Guid[16]; + + CByteBuffer _buffer; + + HRESULT Open2(IInStream *stream); + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override + { + const CPartition &item = _items[index]; + pos = item.GetPos(_sectorSizeLog); + size = item.GetSize(_sectorSizeLog); + return NExtract::NOperationResult::kOK; + } +}; + + +HRESULT CHandler::Open2(IInStream *stream) +{ + const unsigned kBufSize = 2 << 12; + _buffer.Alloc(kBufSize); + RINOK(ReadStream_FALSE(stream, _buffer, kBufSize)) + const Byte *buf = _buffer; + if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) + return S_FALSE; + { + for (unsigned sectorSizeLog = 9;; sectorSizeLog += 3) + { + if (sectorSizeLog > 12) + return S_FALSE; + if (memcmp(buf + ((size_t)1 << sectorSizeLog), k_Signature, k_SignatureSize) == 0) + { + buf += ((size_t)1 << sectorSizeLog); + _sectorSizeLog = sectorSizeLog; + break; + } + } + } + const UInt32 kSectorSize = 1u << _sectorSizeLog; + { + // if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision + const UInt32 headerSize = Get32(buf + 12); // = 0x5C usually + if (headerSize > kSectorSize) + return S_FALSE; + const UInt32 crc = Get32(buf + 0x10); + SetUi32(_buffer + kSectorSize + 0x10, 0) + if (CrcCalc(_buffer + kSectorSize, headerSize) != crc) + return S_FALSE; + } + // UInt32 reserved = Get32(buf + 0x14); + const UInt64 curLba = Get64(buf + 0x18); + if (curLba != 1) + return S_FALSE; + const UInt64 backupLba = Get64(buf + 0x20); + // UInt64 firstUsableLba = Get64(buf + 0x28); + // UInt64 lastUsableLba = Get64(buf + 0x30); + memcpy(Guid, buf + 0x38, 16); + const UInt64 tableLba = Get64(buf + 0x48); + if (tableLba < 2 || (tableLba >> (63 - _sectorSizeLog)) != 0) + return S_FALSE; + const UInt32 numEntries = Get32(buf + 0x50); + if (numEntries > (1 << 16)) + return S_FALSE; + const UInt32 entrySize = Get32(buf + 0x54); // = 128 usually + if (entrySize < 128 || entrySize > (1 << 12)) + return S_FALSE; + const UInt32 entriesCrc = Get32(buf + 0x58); + + const UInt32 tableSize = entrySize * numEntries; + const UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1); + _buffer.Alloc(tableSizeAligned); + const UInt64 tableOffset = tableLba * kSectorSize; + RINOK(InStream_SeekSet(stream, tableOffset)) + RINOK(ReadStream_FALSE(stream, _buffer, tableSizeAligned)) + + if (CrcCalc(_buffer, tableSize) != entriesCrc) + return S_FALSE; + + _totalSize = tableOffset + tableSizeAligned; + + for (UInt32 i = 0; i < numEntries; i++) + { + CPartition item; + item.Parse(_buffer + i * entrySize); + if (item.IsUnused()) + continue; + if (item.LastLba < item.FirstLba) + return S_FALSE; + if ((item.LastLba >> (63 - _sectorSizeLog)) != 0) + return S_FALSE; + const UInt64 endPos = item.GetEnd(_sectorSizeLog); + if (_totalSize < endPos) + _totalSize = endPos; + _items.Add(item); + } + + _buffer.Free(); + { + if ((backupLba >> (63 - _sectorSizeLog)) != 0) + return S_FALSE; + const UInt64 end = (backupLba + 1) * kSectorSize; + if (_totalSize < end) + _totalSize = end; + } + { + UInt64 fileEnd; + RINOK(InStream_GetSize_SeekToEnd(stream, fileEnd)) + + if (_totalSize < fileEnd) + { + const UInt64 rem = fileEnd - _totalSize; + const UInt64 kRemMax = 1 << 22; + if (rem <= kRemMax) + { + RINOK(InStream_SeekSet(stream, _totalSize)) + bool areThereNonZeros = false; + UInt64 numZeros = 0; + if (ReadZeroTail(stream, areThereNonZeros, numZeros, kRemMax) == S_OK) + if (!areThereNonZeros) + _totalSize += numZeros; + } + } + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream)) + _stream = stream; + + FOR_VECTOR (fileIndex, _items) + { + CPartition &item = _items[fileIndex]; + const int typeIndex = FindPartType(item.Type); + if (typeIndex < 0) + continue; + const CPartType &t = kPartTypes[(unsigned)typeIndex]; + if (t.Ext) + { + item.Ext = t.Ext; + continue; + } + if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows")) + { + CMyComPtr inStream; + if ( + // ((IInArchiveGetStream *)this)-> + GetStream(fileIndex, &inStream) == S_OK && inStream) + { + const char *fs = NMbr::GetFileSystem(inStream, item.GetSize(_sectorSizeLog)); + if (fs) + item.Ext = fs; + } + } + } + + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _sectorSizeLog = 0; + _totalSize = 0; + memset(Guid, 0, sizeof(Guid)); + _items.Clear(); + _stream.Release(); + return S_OK; +} + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidFileSystem, + kpidCharacts, + kpidOffset, + kpidId +}; + +static const Byte kArcProps[] = +{ + kpidSectorSize, + kpidId +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: + { + if (_items.Size() == 1) + prop = (UInt32)0; + break; + } + case kpidPhySize: prop = _totalSize; break; + case kpidSectorSize: prop = (UInt32)((UInt32)1 << _sectorSizeLog); break; + case kpidId: + { + char s[48]; + RawLeGuidToString_Upper(Guid, s); + prop = s; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CPartition &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + // Windows BDP partitions can have identical names. + // So we add the partition number at front + UString s; + s.Add_UInt32(index); + { + UString s2; + for (unsigned i = 0; i < kNameLen; i++) + { + wchar_t c = (wchar_t)Get16(item.Name + i * 2); + if (c == 0) + break; + s2 += c; + } + if (!s2.IsEmpty()) + { + s.Add_Dot(); + s += s2; + } + } + { + s.Add_Dot(); + if (item.Ext) + { + AString fs (item.Ext); + fs.MakeLower_Ascii(); + s += fs; + } + else + s += "img"; + } + prop = s; + break; + } + + case kpidSize: + case kpidPackSize: prop = item.GetSize(_sectorSizeLog); break; + case kpidOffset: prop = item.GetPos(_sectorSizeLog); break; + + case kpidFileSystem: + { + char s[48]; + const char *res; + const int typeIndex = FindPartType(item.Type); + if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type) + res = kPartTypes[(unsigned)typeIndex].Type; + else + { + RawLeGuidToString_Upper(item.Type, s); + res = s; + } + prop = res; + break; + } + + case kpidId: + { + char s[48]; + RawLeGuidToString_Upper(item.Id, s); + prop = s; + break; + } + + case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +// we suppport signature only for 512-bytes sector. +REGISTER_ARC_I( + "GPT", "gpt mbr", NULL, 0xCB, + k_Signature, + 1 << 9, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp index 6b590b97e..ca9d24613 100644 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -1,1202 +1,1202 @@ -// GzHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/Defs.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/DeflateDecoder.h" -#include "../Compress/DeflateEncoder.h" - -#include "Common/HandlerOut.h" -#include "Common/InStreamWithCRC.h" -#include "Common/OutStreamWithCRC.h" - -#define Get32(p) GetUi32(p) - -using namespace NWindows; - -using namespace NCompress; -using namespace NDeflate; - -namespace NArchive { -namespace NGz { - - static const Byte kSignature_0 = 0x1F; - static const Byte kSignature_1 = 0x8B; - static const Byte kSignature_2 = 8; // NCompressionMethod::kDeflate - - // Latest versions of gzip program don't write comment field to gz archive. - // We also don't write comment field to gz archive. - - namespace NFlags - { - // const Byte kIsText = 1 << 0; - const Byte kCrc = 1 << 1; - const Byte kExtra = 1 << 2; - const Byte kName = 1 << 3; - const Byte kComment = 1 << 4; - const Byte kReserved = 0xE0; - } - - namespace NExtraFlags - { - const Byte kMaximum = 2; - const Byte kFastest = 4; - } - - namespace NHostOS - { - enum EEnum - { - kFAT = 0, - kAMIGA, - kVMS, - kUnix, - kVM_CMS, - kAtari, - kHPFS, - kMac, - kZ_System, - kCPM, - kTOPS20, - kNTFS, - kQDOS, - kAcorn, - kVFAT, - kMVS, - kBeOS, - kTandem, - - kUnknown = 255 - }; - } - -static const char * const kHostOSes[] = -{ - "FAT" - , "AMIGA" - , "VMS" - , "Unix" - , "VM/CMS" - , "Atari" - , "HPFS" - , "Macintosh" - , "Z-System" - , "CP/M" - , "TOPS-20" - , "NTFS" - , "SMS/QDOS" - , "Acorn" - , "VFAT" - , "MVS" - , "BeOS" - , "Tandem" - , "OS/400" - , "OS/X" -}; - - -class CItem -{ - bool TestFlag(Byte flag) const { return (Flags & flag) != 0; } -public: - Byte Flags; - Byte ExtraFlags; - Byte HostOS; - UInt32 Time; - UInt32 Crc; - UInt32 Size32; - - AString Name; - AString Comment; - // CByteBuffer Extra; - - CItem(): - Flags(0), - ExtraFlags(0), - HostOS(0), - Time(0), - Crc(0), - Size32(0) {} - - void Clear() - { - Name.Empty(); - Comment.Empty(); - // Extra.Free(); - } - - void CopyMetaPropsFrom(const CItem &a) - { - Flags = a.Flags; - HostOS = a.HostOS; - Time = a.Time; - Name = a.Name; - Comment = a.Comment; - // Extra = a.Extra; - } - - void CopyDataPropsFrom(const CItem &a) - { - ExtraFlags = a.ExtraFlags; - Crc = a.Crc; - Size32 = a.Size32; - } - - // bool IsText() const { return TestFlag(NFlags::kIsText); } - bool HeaderCrcIsPresent() const { return TestFlag(NFlags::kCrc); } - bool ExtraFieldIsPresent() const { return TestFlag(NFlags::kExtra); } - bool NameIsPresent() const { return TestFlag(NFlags::kName); } - bool CommentIsPresent() const { return TestFlag(NFlags::kComment); } - bool IsSupported() const { return (Flags & NFlags::kReserved) == 0; } - - HRESULT ReadHeader(NDecoder::CCOMCoder *stream); - HRESULT ReadFooter1(NDecoder::CCOMCoder *stream); - HRESULT ReadFooter2(ISequentialInStream *stream); - - HRESULT WriteHeader(ISequentialOutStream *stream); - HRESULT WriteFooter(ISequentialOutStream *stream); -}; - -static HRESULT ReadBytes(NDecoder::CCOMCoder *stream, Byte *data, UInt32 size) -{ - for (UInt32 i = 0; i < size; i++) - data[i] = stream->ReadAlignedByte(); - return stream->InputEofError() ? S_FALSE : S_OK; -} - -static HRESULT SkipBytes(NDecoder::CCOMCoder *stream, UInt32 size) -{ - for (UInt32 i = 0; i < size; i++) - stream->ReadAlignedByte(); - return stream->InputEofError() ? S_FALSE : S_OK; -} - -static HRESULT ReadUInt16(NDecoder::CCOMCoder *stream, UInt32 &value /* , UInt32 &crc */) -{ - value = 0; - for (int i = 0; i < 2; i++) - { - Byte b = stream->ReadAlignedByte(); - if (stream->InputEofError()) - return S_FALSE; - // crc = CRC_UPDATE_BYTE(crc, b); - value |= ((UInt32)(b) << (8 * i)); - } - return S_OK; -} - -static HRESULT ReadString(NDecoder::CCOMCoder *stream, AString &s, size_t limit /* , UInt32 &crc */) -{ - s.Empty(); - for (size_t i = 0; i < limit; i++) - { - const Byte b = stream->ReadAlignedByte(); - if (stream->InputEofError()) - return S_FALSE; - // crc = CRC_UPDATE_BYTE(crc, b); - if (b == 0) - return S_OK; - s.Add_Char((char)b); - } - return S_FALSE; -} - -static UInt32 Is_Deflate(const Byte *p, size_t size) -{ - if (size < 1) - return k_IsArc_Res_NEED_MORE; - Byte b = *p; - p++; - size--; - unsigned type = ((unsigned)b >> 1) & 3; - if (type == 3) - return k_IsArc_Res_NO; - if (type == 0) - { - // Stored (uncompreessed data) - if ((b >> 3) != 0) - return k_IsArc_Res_NO; - if (size < 4) - return k_IsArc_Res_NEED_MORE; - UInt16 r = (UInt16)~GetUi16(p + 2); - if (GetUi16(p) != r) - return k_IsArc_Res_NO; - } - else if (type == 2) - { - // Dynamic Huffman - if (size < 1) - return k_IsArc_Res_NEED_MORE; - if ((*p & 0x1F) + 1 > 30) // numDistLevels - return k_IsArc_Res_NO; - } - return k_IsArc_Res_YES; -} - -static const unsigned kNameMaxLen = 1 << 12; -static const unsigned kCommentMaxLen = 1 << 16; - -API_FUNC_static_IsArc IsArc_Gz(const Byte *p, size_t size) -{ - if (size < 10) - return k_IsArc_Res_NEED_MORE; - if (p[0] != kSignature_0 || - p[1] != kSignature_1 || - p[2] != kSignature_2) - return k_IsArc_Res_NO; - - const Byte flags = p[3]; - if ((flags & NFlags::kReserved) != 0) - return k_IsArc_Res_NO; - - const Byte extraFlags = p[8]; - // maybe that flag can have another values for some gz archives? - if (extraFlags != 0 && - extraFlags != NExtraFlags::kMaximum && - extraFlags != NExtraFlags::kFastest) - return k_IsArc_Res_NO; - - size -= 10; - p += 10; - - if ((flags & NFlags::kExtra) != 0) - { - if (size < 2) - return k_IsArc_Res_NEED_MORE; - unsigned xlen = GetUi16(p); - size -= 2; - p += 2; - while (xlen != 0) - { - if (xlen < 4) - return k_IsArc_Res_NO; - if (size < 4) - return k_IsArc_Res_NEED_MORE; - const unsigned len = GetUi16(p + 2); - size -= 4; - xlen -= 4; - p += 4; - if (len > xlen) - return k_IsArc_Res_NO; - if (len > size) - return k_IsArc_Res_NEED_MORE; - size -= len; - xlen -= len; - p += len; - } - } - - if ((flags & NFlags::kName) != 0) - { - size_t limit = kNameMaxLen; - if (limit > size) - limit = size; - size_t i; - for (i = 0; i < limit && p[i] != 0; i++); - if (i == size) - return k_IsArc_Res_NEED_MORE; - if (i == limit) - return k_IsArc_Res_NO; - i++; - p += i; - size -= i; - } - - if ((flags & NFlags::kComment) != 0) - { - size_t limit = kCommentMaxLen; - if (limit > size) - limit = size; - size_t i; - for (i = 0; i < limit && p[i] != 0; i++); - if (i == size) - return k_IsArc_Res_NEED_MORE; - if (i == limit) - return k_IsArc_Res_NO; - i++; - p += i; - size -= i; - } - - if ((flags & NFlags::kCrc) != 0) - { - if (size < 2) - return k_IsArc_Res_NEED_MORE; - p += 2; - size -= 2; - } - - return Is_Deflate(p, size); -} -} - -HRESULT CItem::ReadHeader(NDecoder::CCOMCoder *stream) -{ - Clear(); - - // Header-CRC field had another meaning in old version of gzip! - // UInt32 crc = CRC_INIT_VAL; - Byte buf[10]; - - RINOK(ReadBytes(stream, buf, 10)) - - if (buf[0] != kSignature_0 || - buf[1] != kSignature_1 || - buf[2] != kSignature_2) - return S_FALSE; - - Flags = buf[3]; - if (!IsSupported()) - return S_FALSE; - - Time = Get32(buf + 4); - ExtraFlags = buf[8]; - HostOS = buf[9]; - - // crc = CrcUpdate(crc, buf, 10); - - if (ExtraFieldIsPresent()) - { - UInt32 xlen; - RINOK(ReadUInt16(stream, xlen /* , crc */)) - RINOK(SkipBytes(stream, xlen)) - // Extra.SetCapacity(xlen); - // RINOK(ReadStream_FALSE(stream, Extra, xlen)); - // crc = CrcUpdate(crc, Extra, xlen); - } - if (NameIsPresent()) - RINOK(ReadString(stream, Name, kNameMaxLen /* , crc */)) - if (CommentIsPresent()) - RINOK(ReadString(stream, Comment, kCommentMaxLen /* , crc */)) - - if (HeaderCrcIsPresent()) - { - UInt32 headerCRC; - // UInt32 dummy = 0; - RINOK(ReadUInt16(stream, headerCRC /* , dummy */)) - /* - if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC) - return S_FALSE; - */ - } - return stream->InputEofError() ? S_FALSE : S_OK; -} - -HRESULT CItem::ReadFooter1(NDecoder::CCOMCoder *stream) -{ - Byte buf[8]; - RINOK(ReadBytes(stream, buf, 8)) - Crc = Get32(buf); - Size32 = Get32(buf + 4); - return stream->InputEofError() ? S_FALSE : S_OK; -} - -HRESULT CItem::ReadFooter2(ISequentialInStream *stream) -{ - Byte buf[8]; - RINOK(ReadStream_FALSE(stream, buf, 8)) - Crc = Get32(buf); - Size32 = Get32(buf + 4); - return S_OK; -} - -HRESULT CItem::WriteHeader(ISequentialOutStream *stream) -{ - Byte buf[10]; - buf[0] = kSignature_0; - buf[1] = kSignature_1; - buf[2] = kSignature_2; - buf[3] = (Byte)(Flags & NFlags::kName); - // buf[3] |= NFlags::kCrc; - SetUi32(buf + 4, Time) - buf[8] = ExtraFlags; - buf[9] = HostOS; - RINOK(WriteStream(stream, buf, 10)) - // crc = CrcUpdate(CRC_INIT_VAL, buf, 10); - if (NameIsPresent()) - { - // crc = CrcUpdate(crc, (const char *)Name, Name.Len() + 1); - RINOK(WriteStream(stream, (const char *)Name, Name.Len() + 1)) - } - // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc)); - // RINOK(WriteStream(stream, buf, 2)); - return S_OK; -} - -HRESULT CItem::WriteFooter(ISequentialOutStream *stream) -{ - Byte buf[8]; - SetUi32(buf, Crc) - SetUi32(buf + 4, Size32) - return WriteStream(stream, buf, 8); -} - -Z7_CLASS_IMP_CHandler_IInArchive_3( - IArchiveOpenSeq, - IOutArchive, - ISetProperties -) - CItem _item; - - bool _isArc; - bool _needSeekToStart; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - bool _numStreams_Defined; - - UInt64 _packSize; - UInt64 _unpackSize; // real unpack size (NOT from footer) - UInt64 _numStreams; - UInt64 _headerSize; // only start header (without footer) - - CMyComPtr _stream; - CMyComPtr2 _decoder; - - CSingleMethodProps _props; - CHandlerTimeOptions _timeOptions; - -public: - CHandler(): - _isArc(false) - {} - - void CreateDecoder() - { - _decoder.Create_if_Empty(); - } -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidMTime, - kpidHostOS, - kpidCRC - // kpidComment -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidNumStreams -}; - - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; - case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; - case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; - case kpidHeadersSize: if (_headerSize != 0) prop = _headerSize; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; - prop = v; - break; - } - case kpidName: - if (_item.NameIsPresent()) - { - UString s = MultiByteToUnicodeString(_item.Name, CP_ACP); - s += ".gz"; - prop = s; - } - break; - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPath: - if (_item.NameIsPresent()) - prop = MultiByteToUnicodeString(_item.Name, CP_ACP); - break; - // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break; - case kpidMTime: - // gzip specification: MTIME = 0 means no time stamp is available. - if (_item.Time != 0) - PropVariant_SetFrom_UnixTime(prop, _item.Time); - break; - case kpidTimeType: - if (_item.Time != 0) - prop = (UInt32)NFileTimeType::kUnix; - break; - case kpidSize: - { - if (_unpackSize_Defined) - prop = _unpackSize; - else if (_stream) - prop = (UInt64)_item.Size32; - break; - } - case kpidPackSize: - { - if (_packSize_Defined || _stream) - prop = _packSize; - break; - } - case kpidHostOS: TYPE_TO_PROP(kHostOSes, _item.HostOS, prop); break; - case kpidCRC: if (_stream) prop = _item.Crc; break; - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_CLASS_IMP_COM_1( - CCompressProgressInfoImp, - ICompressProgressInfo -) - CMyComPtr Callback; -public: - UInt64 Offset; - void Init(IArchiveOpenCallback *callback) { Callback = callback; } -}; - -Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) -{ - if (Callback) - { - UInt64 files = 0; - UInt64 value = Offset + *inSize; - return Callback->SetCompleted(&files, &value); - } - return S_OK; -} - -/* -*/ - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) -{ - COM_TRY_BEGIN - RINOK(OpenSeq(stream)) - _isArc = false; - UInt64 endPos; - RINOK(stream->Seek(-8, STREAM_SEEK_END, &endPos)) - _packSize = endPos + 8; - RINOK(_item.ReadFooter2(stream)) - _stream = stream; - _isArc = true; - _needSeekToStart = true; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - COM_TRY_BEGIN - try - { - Close(); - CreateDecoder(); - _decoder->SetInStream(stream); - _decoder->InitInStream(true); - RINOK(_item.ReadHeader(_decoder.ClsPtr())) - if (_decoder->InputEofError()) - return S_FALSE; - _headerSize = _decoder->GetInputProcessedSize(); - _isArc = true; - return S_OK; - } - catch(const CInBufferException &e) { return e.ErrorCode; } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _needSeekToStart = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - _numStreams_Defined = false; - - _packSize = 0; - _headerSize = 0; - - _stream.Release(); - if (_decoder) - _decoder->ReleaseInStream(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - RINOK(extractCallback->SetTotal(_packSize)) - // UInt64 currentTotalPacked = 0; - // RINOK(extractCallback->SetCompleted(¤tTotalPacked)); - Int32 retResult; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CreateDecoder(); - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(); - // realOutStream.Release(); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - - bool needReadFirstItem = _needSeekToStart; - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(InStream_SeekToBegin(_stream)) - _decoder->InitInStream(true); - // printf("\nSeek"); - } - else - _needSeekToStart = true; - - bool firstItem = true; - - UInt64 packSize = _decoder->GetInputProcessedSize(); - // printf("\npackSize = %d", (unsigned)packSize); - - UInt64 unpackedSize = 0; - UInt64 numStreams = 0; - - bool crcError = false; - - HRESULT result = S_OK; - - try { - - for (;;) - { - lps->InSize = packSize; - lps->OutSize = unpackedSize; - - RINOK(lps->SetCur()) - - CItem item; - - if (!firstItem || needReadFirstItem) - { - result = item.ReadHeader(_decoder.ClsPtr()); - - if (result != S_OK && result != S_FALSE) - return result; - - if (_decoder->InputEofError()) - result = S_FALSE; - - if (result != S_OK && firstItem) - { - _isArc = false; - break; - } - - if (packSize == _decoder->GetStreamSize()) - { - result = S_OK; - break; - } - - if (result != S_OK) - { - _dataAfterEnd = true; - break; - } - } - - numStreams++; - firstItem = false; - - const UInt64 startOffset = outStream->GetSize(); - outStream->InitCRC(); - - result = _decoder->CodeResume(outStream, NULL, lps); - - packSize = _decoder->GetInputProcessedSize(); - unpackedSize = outStream->GetSize(); - - if (result != S_OK && result != S_FALSE) - return result; - - if (_decoder->InputEofError()) - { - packSize = _decoder->GetStreamSize(); - _needMoreInput = true; - result = S_FALSE; - } - - if (result != S_OK) - break; - - _decoder->AlignToByte(); - - result = item.ReadFooter1(_decoder.ClsPtr()); - - packSize = _decoder->GetInputProcessedSize(); - - if (result != S_OK && result != S_FALSE) - return result; - - if (result != S_OK) - { - if (_decoder->InputEofError()) - { - _needMoreInput = true; - result = S_FALSE; - } - break; - } - - if (item.Crc != outStream->GetCRC() || - item.Size32 != (UInt32)(unpackedSize - startOffset)) - { - crcError = true; - result = S_FALSE; - break; - } - - // break; // we can use break, if we need only first stream - } - - } catch(const CInBufferException &e) { return e.ErrorCode; } - - if (!firstItem) - { - _packSize = packSize; - _unpackSize = unpackedSize; - _numStreams = numStreams; - - _packSize_Defined = true; - _unpackSize_Defined = true; - _numStreams_Defined = true; - } - - // outStream.Release(); - - retResult = NExtract::NOperationResult::kDataError; - - if (!_isArc) - retResult = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - retResult = NExtract::NOperationResult::kUnexpectedEnd; - else if (crcError) - retResult = NExtract::NOperationResult::kCRCError; - else if (_dataAfterEnd) - retResult = NExtract::NOperationResult::kDataAfterEnd; - else if (result == S_FALSE) - retResult = NExtract::NOperationResult::kDataError; - else if (result == S_OK) - retResult = NExtract::NOperationResult::kOK; - else - return result; - } - - return extractCallback->SetOperationResult(retResult); - COM_TRY_END -} - -static const Byte kHostOS = - #ifdef _WIN32 - NHostOS::kFAT; - #else - NHostOS::kUnix; - #endif - - -/* -static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) -{ - return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value); -} - -static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) -{ - return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value); -} - -static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, - const CItem &item, - bool needTime, - bool needCrc, - const UInt64 *unpackSize) -{ - NCOM::CPropVariant timeProp; - NCOM::CPropVariant sizeProp; - if (needTime) - { - FILETIME ft; - NTime::UnixTimeToFileTime(item.Time, ft); - timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix); - } - if (unpackSize) - { - sizeProp = *unpackSize; - RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp)); - } - if (needCrc) - { - NCOM::CPropVariant prop; - prop = item.Crc; - RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop)); - } - { - RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp)); - } - - RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK)); - - if (unpackSize) - { - RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp)); - } - { - RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp)); - } - return S_OK; -} -*/ - -static HRESULT UpdateArchive( - ISequentialOutStream *outStream, - UInt64 unpackSize, - CItem &item, - const CSingleMethodProps &props, - const CHandlerTimeOptions &timeOptions, - IArchiveUpdateCallback *updateCallback - // , IArchiveUpdateCallbackArcProp *reportArcProp - ) -{ - UInt64 unpackSizeReal; - { - CMyComPtr fileInStream; - - RINOK(updateCallback->GetStream(0, &fileInStream)) - - if (!fileInStream) - return S_FALSE; - - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamGetProps, - getProps, fileInStream) - if (getProps) - { - FILETIME mTime; - UInt64 size; - if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK) - { - unpackSize = size; - if (timeOptions.Write_MTime.Val) - NTime::FileTime_To_UnixTime(mTime, item.Time); - } - } - } - - UInt64 complexity = 0; - RINOK(updateCallback->SetTotal(unpackSize)) - RINOK(updateCallback->SetCompleted(&complexity)) - - CMyComPtr2_Create crcStream; - crcStream->SetStream(fileInStream); - crcStream->Init(); - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - item.ExtraFlags = props.GetLevel() >= 7 ? - NExtraFlags::kMaximum : - NExtraFlags::kFastest; - - item.HostOS = kHostOS; - - RINOK(item.WriteHeader(outStream)) - - CMyComPtr2_Create deflateEncoder; - - RINOK(props.SetCoderProps(deflateEncoder.ClsPtr(), NULL)) - RINOK(deflateEncoder.Interface()->Code(crcStream, outStream, NULL, NULL, lps)) - - item.Crc = crcStream->GetCRC(); - unpackSizeReal = crcStream->GetSize(); - item.Size32 = (UInt32)unpackSizeReal; - RINOK(item.WriteFooter(outStream)) - } - /* - if (reportArcProp) - { - RINOK(ReportArcProps(reportArcProp, - item, - props._Write_MTime, // item.Time != 0, - true, // writeCrc - &unpackSizeReal)); - } - */ - return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); -} - - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) -{ - /* - if (_item.Time != 0) - { - we set NFileTimeType::kUnix in precision, - and we return NFileTimeType::kUnix in kpidTimeType - so GetFileTimeType() value is not used in any version of 7-zip. - } - else // (_item.Time == 0) - { - kpidMTime and kpidTimeType are not defined - before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList(); - 22.00 : GetFileTimeType() value is not used - } - */ - - UInt32 t; - t = NFileTimeType::kUnix; - if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val) - { - t = GET_FileTimeType_NotDefined_for_GetFileTimeType; - // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21 - // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21 - } - *timeType = t; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback)) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamSetRestriction, - setRestriction, outStream) - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - } - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) - - // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback) - - CItem newItem; - - if (!IntToBool(newProps)) - { - newItem.CopyMetaPropsFrom(_item); - } - else - { - newItem.HostOS = kHostOS; - if (_timeOptions.Write_MTime.Val) - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)) - if (prop.vt == VT_FILETIME) - NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time); - else if (prop.vt == VT_EMPTY) - newItem.Time = 0; - else - return E_INVALIDARG; - } - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidPath, &prop)) - if (prop.vt == VT_BSTR) - { - UString name = prop.bstrVal; - int slashPos = name.ReverseFind_PathSepar(); - if (slashPos >= 0) - name.DeleteFrontal((unsigned)(slashPos + 1)); - newItem.Name = UnicodeStringToMultiByte(name, CP_ACP); - if (!newItem.Name.IsEmpty()) - newItem.Flags |= NFlags::kName; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) - if (prop.vt != VT_EMPTY) - if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) - return E_INVALIDARG; - } - } - - if (IntToBool(newData)) - { - UInt64 size; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - } - return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - if (!_stream) - return E_NOTIMPL; - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveUpdateCallbackFile, - opCallback, updateCallback) - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - newItem.CopyDataPropsFrom(_item); - - UInt64 offset = 0; - if (IntToBool(newProps)) - { - newItem.WriteHeader(outStream); - offset += _headerSize; - } - RINOK(InStream_SeekSet(_stream, offset)) - - /* - if (reportArcProp) - ReportArcProps(reportArcProp, newItem, - _props._Write_MTime, - false, // writeCrc - NULL); // unpacksize - */ - - return NCompress::CopyStream(_stream, outStream, lps); - - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - _timeOptions.Init(); - _props.Init(); - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - const PROPVARIANT &value = values[i]; - { - bool processed = false; - RINOK(_timeOptions.Parse(name, value, processed)) - if (processed) - { - if (_timeOptions.Write_CTime.Val || - _timeOptions.Write_ATime.Val) - return E_INVALIDARG; - if ( _timeOptions.Prec != (UInt32)(Int32)-1 - && _timeOptions.Prec != k_PropVar_TimePrec_0 - && _timeOptions.Prec != k_PropVar_TimePrec_Unix - && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec - && _timeOptions.Prec != k_PropVar_TimePrec_Base) - return E_INVALIDARG; - continue; - } - } - RINOK(_props.SetProperty(name, value)) - } - return S_OK; -} - -static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 }; - -REGISTER_ARC_IO( - "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF, - k_Signature, 0, - NArcInfoFlags::kKeepName - | NArcInfoFlags::kMTime - | NArcInfoFlags::kMTime_Default - , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) - | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix) - , IsArc_Gz) - -}} +// GzHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/DeflateDecoder.h" +#include "../Compress/DeflateEncoder.h" + +#include "Common/HandlerOut.h" +#include "Common/InStreamWithCRC.h" +#include "Common/OutStreamWithCRC.h" + +#define Get32(p) GetUi32(p) + +using namespace NWindows; + +using namespace NCompress; +using namespace NDeflate; + +namespace NArchive { +namespace NGz { + + static const Byte kSignature_0 = 0x1F; + static const Byte kSignature_1 = 0x8B; + static const Byte kSignature_2 = 8; // NCompressionMethod::kDeflate + + // Latest versions of gzip program don't write comment field to gz archive. + // We also don't write comment field to gz archive. + + namespace NFlags + { + // const Byte kIsText = 1 << 0; + const Byte kCrc = 1 << 1; + const Byte kExtra = 1 << 2; + const Byte kName = 1 << 3; + const Byte kComment = 1 << 4; + const Byte kReserved = 0xE0; + } + + namespace NExtraFlags + { + const Byte kMaximum = 2; + const Byte kFastest = 4; + } + + namespace NHostOS + { + enum EEnum + { + kFAT = 0, + kAMIGA, + kVMS, + kUnix, + kVM_CMS, + kAtari, + kHPFS, + kMac, + kZ_System, + kCPM, + kTOPS20, + kNTFS, + kQDOS, + kAcorn, + kVFAT, + kMVS, + kBeOS, + kTandem, + + kUnknown = 255 + }; + } + +static const char * const kHostOSes[] = +{ + "FAT" + , "AMIGA" + , "VMS" + , "Unix" + , "VM/CMS" + , "Atari" + , "HPFS" + , "Macintosh" + , "Z-System" + , "CP/M" + , "TOPS-20" + , "NTFS" + , "SMS/QDOS" + , "Acorn" + , "VFAT" + , "MVS" + , "BeOS" + , "Tandem" + , "OS/400" + , "OS/X" +}; + + +class CItem +{ + bool TestFlag(Byte flag) const { return (Flags & flag) != 0; } +public: + Byte Flags; + Byte ExtraFlags; + Byte HostOS; + UInt32 Time; + UInt32 Crc; + UInt32 Size32; + + AString Name; + AString Comment; + // CByteBuffer Extra; + + CItem(): + Flags(0), + ExtraFlags(0), + HostOS(0), + Time(0), + Crc(0), + Size32(0) {} + + void Clear() + { + Name.Empty(); + Comment.Empty(); + // Extra.Free(); + } + + void CopyMetaPropsFrom(const CItem &a) + { + Flags = a.Flags; + HostOS = a.HostOS; + Time = a.Time; + Name = a.Name; + Comment = a.Comment; + // Extra = a.Extra; + } + + void CopyDataPropsFrom(const CItem &a) + { + ExtraFlags = a.ExtraFlags; + Crc = a.Crc; + Size32 = a.Size32; + } + + // bool IsText() const { return TestFlag(NFlags::kIsText); } + bool HeaderCrcIsPresent() const { return TestFlag(NFlags::kCrc); } + bool ExtraFieldIsPresent() const { return TestFlag(NFlags::kExtra); } + bool NameIsPresent() const { return TestFlag(NFlags::kName); } + bool CommentIsPresent() const { return TestFlag(NFlags::kComment); } + bool IsSupported() const { return (Flags & NFlags::kReserved) == 0; } + + HRESULT ReadHeader(NDecoder::CCOMCoder *stream); + HRESULT ReadFooter1(NDecoder::CCOMCoder *stream); + HRESULT ReadFooter2(ISequentialInStream *stream); + + HRESULT WriteHeader(ISequentialOutStream *stream); + HRESULT WriteFooter(ISequentialOutStream *stream); +}; + +static HRESULT ReadBytes(NDecoder::CCOMCoder *stream, Byte *data, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + data[i] = stream->ReadAlignedByte(); + return stream->InputEofError() ? S_FALSE : S_OK; +} + +static HRESULT SkipBytes(NDecoder::CCOMCoder *stream, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + stream->ReadAlignedByte(); + return stream->InputEofError() ? S_FALSE : S_OK; +} + +static HRESULT ReadUInt16(NDecoder::CCOMCoder *stream, UInt32 &value /* , UInt32 &crc */) +{ + value = 0; + for (int i = 0; i < 2; i++) + { + Byte b = stream->ReadAlignedByte(); + if (stream->InputEofError()) + return S_FALSE; + // crc = CRC_UPDATE_BYTE(crc, b); + value |= ((UInt32)(b) << (8 * i)); + } + return S_OK; +} + +static HRESULT ReadString(NDecoder::CCOMCoder *stream, AString &s, size_t limit /* , UInt32 &crc */) +{ + s.Empty(); + for (size_t i = 0; i < limit; i++) + { + const Byte b = stream->ReadAlignedByte(); + if (stream->InputEofError()) + return S_FALSE; + // crc = CRC_UPDATE_BYTE(crc, b); + if (b == 0) + return S_OK; + s.Add_Char((char)b); + } + return S_FALSE; +} + +static UInt32 Is_Deflate(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + Byte b = *p; + p++; + size--; + unsigned type = ((unsigned)b >> 1) & 3; + if (type == 3) + return k_IsArc_Res_NO; + if (type == 0) + { + // Stored (uncompreessed data) + if ((b >> 3) != 0) + return k_IsArc_Res_NO; + if (size < 4) + return k_IsArc_Res_NEED_MORE; + UInt16 r = (UInt16)~GetUi16(p + 2); + if (GetUi16(p) != r) + return k_IsArc_Res_NO; + } + else if (type == 2) + { + // Dynamic Huffman + if (size < 1) + return k_IsArc_Res_NEED_MORE; + if ((*p & 0x1F) + 1 > 30) // numDistLevels + return k_IsArc_Res_NO; + } + return k_IsArc_Res_YES; +} + +static const unsigned kNameMaxLen = 1 << 12; +static const unsigned kCommentMaxLen = 1 << 16; + +API_FUNC_static_IsArc IsArc_Gz(const Byte *p, size_t size) +{ + if (size < 10) + return k_IsArc_Res_NEED_MORE; + if (p[0] != kSignature_0 || + p[1] != kSignature_1 || + p[2] != kSignature_2) + return k_IsArc_Res_NO; + + const Byte flags = p[3]; + if ((flags & NFlags::kReserved) != 0) + return k_IsArc_Res_NO; + + const Byte extraFlags = p[8]; + // maybe that flag can have another values for some gz archives? + if (extraFlags != 0 && + extraFlags != NExtraFlags::kMaximum && + extraFlags != NExtraFlags::kFastest) + return k_IsArc_Res_NO; + + size -= 10; + p += 10; + + if ((flags & NFlags::kExtra) != 0) + { + if (size < 2) + return k_IsArc_Res_NEED_MORE; + unsigned xlen = GetUi16(p); + size -= 2; + p += 2; + while (xlen != 0) + { + if (xlen < 4) + return k_IsArc_Res_NO; + if (size < 4) + return k_IsArc_Res_NEED_MORE; + const unsigned len = GetUi16(p + 2); + size -= 4; + xlen -= 4; + p += 4; + if (len > xlen) + return k_IsArc_Res_NO; + if (len > size) + return k_IsArc_Res_NEED_MORE; + size -= len; + xlen -= len; + p += len; + } + } + + if ((flags & NFlags::kName) != 0) + { + size_t limit = kNameMaxLen; + if (limit > size) + limit = size; + size_t i; + for (i = 0; i < limit && p[i] != 0; i++); + if (i == size) + return k_IsArc_Res_NEED_MORE; + if (i == limit) + return k_IsArc_Res_NO; + i++; + p += i; + size -= i; + } + + if ((flags & NFlags::kComment) != 0) + { + size_t limit = kCommentMaxLen; + if (limit > size) + limit = size; + size_t i; + for (i = 0; i < limit && p[i] != 0; i++); + if (i == size) + return k_IsArc_Res_NEED_MORE; + if (i == limit) + return k_IsArc_Res_NO; + i++; + p += i; + size -= i; + } + + if ((flags & NFlags::kCrc) != 0) + { + if (size < 2) + return k_IsArc_Res_NEED_MORE; + p += 2; + size -= 2; + } + + return Is_Deflate(p, size); +} +} + +HRESULT CItem::ReadHeader(NDecoder::CCOMCoder *stream) +{ + Clear(); + + // Header-CRC field had another meaning in old version of gzip! + // UInt32 crc = CRC_INIT_VAL; + Byte buf[10]; + + RINOK(ReadBytes(stream, buf, 10)) + + if (buf[0] != kSignature_0 || + buf[1] != kSignature_1 || + buf[2] != kSignature_2) + return S_FALSE; + + Flags = buf[3]; + if (!IsSupported()) + return S_FALSE; + + Time = Get32(buf + 4); + ExtraFlags = buf[8]; + HostOS = buf[9]; + + // crc = CrcUpdate(crc, buf, 10); + + if (ExtraFieldIsPresent()) + { + UInt32 xlen; + RINOK(ReadUInt16(stream, xlen /* , crc */)) + RINOK(SkipBytes(stream, xlen)) + // Extra.SetCapacity(xlen); + // RINOK(ReadStream_FALSE(stream, Extra, xlen)); + // crc = CrcUpdate(crc, Extra, xlen); + } + if (NameIsPresent()) + RINOK(ReadString(stream, Name, kNameMaxLen /* , crc */)) + if (CommentIsPresent()) + RINOK(ReadString(stream, Comment, kCommentMaxLen /* , crc */)) + + if (HeaderCrcIsPresent()) + { + UInt32 headerCRC; + // UInt32 dummy = 0; + RINOK(ReadUInt16(stream, headerCRC /* , dummy */)) + /* + if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC) + return S_FALSE; + */ + } + return stream->InputEofError() ? S_FALSE : S_OK; +} + +HRESULT CItem::ReadFooter1(NDecoder::CCOMCoder *stream) +{ + Byte buf[8]; + RINOK(ReadBytes(stream, buf, 8)) + Crc = Get32(buf); + Size32 = Get32(buf + 4); + return stream->InputEofError() ? S_FALSE : S_OK; +} + +HRESULT CItem::ReadFooter2(ISequentialInStream *stream) +{ + Byte buf[8]; + RINOK(ReadStream_FALSE(stream, buf, 8)) + Crc = Get32(buf); + Size32 = Get32(buf + 4); + return S_OK; +} + +HRESULT CItem::WriteHeader(ISequentialOutStream *stream) +{ + Byte buf[10]; + buf[0] = kSignature_0; + buf[1] = kSignature_1; + buf[2] = kSignature_2; + buf[3] = (Byte)(Flags & NFlags::kName); + // buf[3] |= NFlags::kCrc; + SetUi32(buf + 4, Time) + buf[8] = ExtraFlags; + buf[9] = HostOS; + RINOK(WriteStream(stream, buf, 10)) + // crc = CrcUpdate(CRC_INIT_VAL, buf, 10); + if (NameIsPresent()) + { + // crc = CrcUpdate(crc, (const char *)Name, Name.Len() + 1); + RINOK(WriteStream(stream, (const char *)Name, Name.Len() + 1)) + } + // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc)); + // RINOK(WriteStream(stream, buf, 2)); + return S_OK; +} + +HRESULT CItem::WriteFooter(ISequentialOutStream *stream) +{ + Byte buf[8]; + SetUi32(buf, Crc) + SetUi32(buf + 4, Size32) + return WriteStream(stream, buf, 8); +} + +Z7_CLASS_IMP_CHandler_IInArchive_3( + IArchiveOpenSeq, + IOutArchive, + ISetProperties +) + CItem _item; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + + UInt64 _packSize; + UInt64 _unpackSize; // real unpack size (NOT from footer) + UInt64 _numStreams; + UInt64 _headerSize; // only start header (without footer) + + CMyComPtr _stream; + CMyComPtr2 _decoder; + + CSingleMethodProps _props; + CHandlerTimeOptions _timeOptions; + +public: + CHandler(): + _isArc(false) + {} + + void CreateDecoder() + { + _decoder.Create_if_Empty(); + } +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidMTime, + kpidHostOS, + kpidCRC + // kpidComment +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidNumStreams +}; + + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidHeadersSize: if (_headerSize != 0) prop = _headerSize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + prop = v; + break; + } + case kpidName: + if (_item.NameIsPresent()) + { + UString s = MultiByteToUnicodeString(_item.Name, CP_ACP); + s += ".gz"; + prop = s; + } + break; + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPath: + if (_item.NameIsPresent()) + prop = MultiByteToUnicodeString(_item.Name, CP_ACP); + break; + // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break; + case kpidMTime: + // gzip specification: MTIME = 0 means no time stamp is available. + if (_item.Time != 0) + PropVariant_SetFrom_UnixTime(prop, _item.Time); + break; + case kpidTimeType: + if (_item.Time != 0) + prop = (UInt32)NFileTimeType::kUnix; + break; + case kpidSize: + { + if (_unpackSize_Defined) + prop = _unpackSize; + else if (_stream) + prop = (UInt64)_item.Size32; + break; + } + case kpidPackSize: + { + if (_packSize_Defined || _stream) + prop = _packSize; + break; + } + case kpidHostOS: TYPE_TO_PROP(kHostOSes, _item.HostOS, prop); break; + case kpidCRC: if (_stream) prop = _item.Crc; break; + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_CLASS_IMP_COM_1( + CCompressProgressInfoImp, + ICompressProgressInfo +) + CMyComPtr Callback; +public: + UInt64 Offset; + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) +{ + if (Callback) + { + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} + +/* +*/ + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) +{ + COM_TRY_BEGIN + RINOK(OpenSeq(stream)) + _isArc = false; + UInt64 endPos; + RINOK(stream->Seek(-8, STREAM_SEEK_END, &endPos)) + _packSize = endPos + 8; + RINOK(_item.ReadFooter2(stream)) + _stream = stream; + _isArc = true; + _needSeekToStart = true; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + COM_TRY_BEGIN + try + { + Close(); + CreateDecoder(); + _decoder->SetInStream(stream); + _decoder->InitInStream(true); + RINOK(_item.ReadHeader(_decoder.ClsPtr())) + if (_decoder->InputEofError()) + return S_FALSE; + _headerSize = _decoder->GetInputProcessedSize(); + _isArc = true; + return S_OK; + } + catch(const CInBufferException &e) { return e.ErrorCode; } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + + _packSize = 0; + _headerSize = 0; + + _stream.Release(); + if (_decoder) + _decoder->ReleaseInStream(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + RINOK(extractCallback->SetTotal(_packSize)) + // UInt64 currentTotalPacked = 0; + // RINOK(extractCallback->SetCompleted(¤tTotalPacked)); + Int32 retResult; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CreateDecoder(); + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(); + // realOutStream.Release(); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + + bool needReadFirstItem = _needSeekToStart; + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(InStream_SeekToBegin(_stream)) + _decoder->InitInStream(true); + // printf("\nSeek"); + } + else + _needSeekToStart = true; + + bool firstItem = true; + + UInt64 packSize = _decoder->GetInputProcessedSize(); + // printf("\npackSize = %d", (unsigned)packSize); + + UInt64 unpackedSize = 0; + UInt64 numStreams = 0; + + bool crcError = false; + + HRESULT result = S_OK; + + try { + + for (;;) + { + lps->InSize = packSize; + lps->OutSize = unpackedSize; + + RINOK(lps->SetCur()) + + CItem item; + + if (!firstItem || needReadFirstItem) + { + result = item.ReadHeader(_decoder.ClsPtr()); + + if (result != S_OK && result != S_FALSE) + return result; + + if (_decoder->InputEofError()) + result = S_FALSE; + + if (result != S_OK && firstItem) + { + _isArc = false; + break; + } + + if (packSize == _decoder->GetStreamSize()) + { + result = S_OK; + break; + } + + if (result != S_OK) + { + _dataAfterEnd = true; + break; + } + } + + numStreams++; + firstItem = false; + + const UInt64 startOffset = outStream->GetSize(); + outStream->InitCRC(); + + result = _decoder->CodeResume(outStream, NULL, lps); + + packSize = _decoder->GetInputProcessedSize(); + unpackedSize = outStream->GetSize(); + + if (result != S_OK && result != S_FALSE) + return result; + + if (_decoder->InputEofError()) + { + packSize = _decoder->GetStreamSize(); + _needMoreInput = true; + result = S_FALSE; + } + + if (result != S_OK) + break; + + _decoder->AlignToByte(); + + result = item.ReadFooter1(_decoder.ClsPtr()); + + packSize = _decoder->GetInputProcessedSize(); + + if (result != S_OK && result != S_FALSE) + return result; + + if (result != S_OK) + { + if (_decoder->InputEofError()) + { + _needMoreInput = true; + result = S_FALSE; + } + break; + } + + if (item.Crc != outStream->GetCRC() || + item.Size32 != (UInt32)(unpackedSize - startOffset)) + { + crcError = true; + result = S_FALSE; + break; + } + + // break; // we can use break, if we need only first stream + } + + } catch(const CInBufferException &e) { return e.ErrorCode; } + + if (!firstItem) + { + _packSize = packSize; + _unpackSize = unpackedSize; + _numStreams = numStreams; + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + } + + // outStream.Release(); + + retResult = NExtract::NOperationResult::kDataError; + + if (!_isArc) + retResult = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + retResult = NExtract::NOperationResult::kUnexpectedEnd; + else if (crcError) + retResult = NExtract::NOperationResult::kCRCError; + else if (_dataAfterEnd) + retResult = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + retResult = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + retResult = NExtract::NOperationResult::kOK; + else + return result; + } + + return extractCallback->SetOperationResult(retResult); + COM_TRY_END +} + +static const Byte kHostOS = + #ifdef _WIN32 + NHostOS::kFAT; + #else + NHostOS::kUnix; + #endif + + +/* +static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value); +} + +static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value); +} + +static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, + const CItem &item, + bool needTime, + bool needCrc, + const UInt64 *unpackSize) +{ + NCOM::CPropVariant timeProp; + NCOM::CPropVariant sizeProp; + if (needTime) + { + FILETIME ft; + NTime::UnixTimeToFileTime(item.Time, ft); + timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix); + } + if (unpackSize) + { + sizeProp = *unpackSize; + RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp)); + } + if (needCrc) + { + NCOM::CPropVariant prop; + prop = item.Crc; + RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop)); + } + { + RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp)); + } + + RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK)); + + if (unpackSize) + { + RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp)); + } + { + RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp)); + } + return S_OK; +} +*/ + +static HRESULT UpdateArchive( + ISequentialOutStream *outStream, + UInt64 unpackSize, + CItem &item, + const CSingleMethodProps &props, + const CHandlerTimeOptions &timeOptions, + IArchiveUpdateCallback *updateCallback + // , IArchiveUpdateCallbackArcProp *reportArcProp + ) +{ + UInt64 unpackSizeReal; + { + CMyComPtr fileInStream; + + RINOK(updateCallback->GetStream(0, &fileInStream)) + + if (!fileInStream) + return S_FALSE; + + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamGetProps, + getProps, fileInStream) + if (getProps) + { + FILETIME mTime; + UInt64 size; + if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK) + { + unpackSize = size; + if (timeOptions.Write_MTime.Val) + NTime::FileTime_To_UnixTime(mTime, item.Time); + } + } + } + + UInt64 complexity = 0; + RINOK(updateCallback->SetTotal(unpackSize)) + RINOK(updateCallback->SetCompleted(&complexity)) + + CMyComPtr2_Create crcStream; + crcStream->SetStream(fileInStream); + crcStream->Init(); + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + item.ExtraFlags = props.GetLevel() >= 7 ? + NExtraFlags::kMaximum : + NExtraFlags::kFastest; + + item.HostOS = kHostOS; + + RINOK(item.WriteHeader(outStream)) + + CMyComPtr2_Create deflateEncoder; + + RINOK(props.SetCoderProps(deflateEncoder.ClsPtr(), NULL)) + RINOK(deflateEncoder.Interface()->Code(crcStream, outStream, NULL, NULL, lps)) + + item.Crc = crcStream->GetCRC(); + unpackSizeReal = crcStream->GetSize(); + item.Size32 = (UInt32)unpackSizeReal; + RINOK(item.WriteFooter(outStream)) + } + /* + if (reportArcProp) + { + RINOK(ReportArcProps(reportArcProp, + item, + props._Write_MTime, // item.Time != 0, + true, // writeCrc + &unpackSizeReal)); + } + */ + return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); +} + + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) +{ + /* + if (_item.Time != 0) + { + we set NFileTimeType::kUnix in precision, + and we return NFileTimeType::kUnix in kpidTimeType + so GetFileTimeType() value is not used in any version of 7-zip. + } + else // (_item.Time == 0) + { + kpidMTime and kpidTimeType are not defined + before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList(); + 22.00 : GetFileTimeType() value is not used + } + */ + + UInt32 t; + t = NFileTimeType::kUnix; + if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val) + { + t = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21 + // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21 + } + *timeType = t; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback)) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamSetRestriction, + setRestriction, outStream) + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + } + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) + + // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback) + + CItem newItem; + + if (!IntToBool(newProps)) + { + newItem.CopyMetaPropsFrom(_item); + } + else + { + newItem.HostOS = kHostOS; + if (_timeOptions.Write_MTime.Val) + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)) + if (prop.vt == VT_FILETIME) + NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time); + else if (prop.vt == VT_EMPTY) + newItem.Time = 0; + else + return E_INVALIDARG; + } + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidPath, &prop)) + if (prop.vt == VT_BSTR) + { + UString name = prop.bstrVal; + int slashPos = name.ReverseFind_PathSepar(); + if (slashPos >= 0) + name.DeleteFrontal((unsigned)(slashPos + 1)); + newItem.Name = UnicodeStringToMultiByte(name, CP_ACP); + if (!newItem.Name.IsEmpty()) + newItem.Flags |= NFlags::kName; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) + if (prop.vt != VT_EMPTY) + if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + if (!_stream) + return E_NOTIMPL; + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveUpdateCallbackFile, + opCallback, updateCallback) + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + newItem.CopyDataPropsFrom(_item); + + UInt64 offset = 0; + if (IntToBool(newProps)) + { + newItem.WriteHeader(outStream); + offset += _headerSize; + } + RINOK(InStream_SeekSet(_stream, offset)) + + /* + if (reportArcProp) + ReportArcProps(reportArcProp, newItem, + _props._Write_MTime, + false, // writeCrc + NULL); // unpacksize + */ + + return NCompress::CopyStream(_stream, outStream, lps); + + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + _timeOptions.Init(); + _props.Init(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + const PROPVARIANT &value = values[i]; + { + bool processed = false; + RINOK(_timeOptions.Parse(name, value, processed)) + if (processed) + { + if (_timeOptions.Write_CTime.Val || + _timeOptions.Write_ATime.Val) + return E_INVALIDARG; + if ( _timeOptions.Prec != (UInt32)(Int32)-1 + && _timeOptions.Prec != k_PropVar_TimePrec_0 + && _timeOptions.Prec != k_PropVar_TimePrec_Unix + && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec + && _timeOptions.Prec != k_PropVar_TimePrec_Base) + return E_INVALIDARG; + continue; + } + } + RINOK(_props.SetProperty(name, value)) + } + return S_OK; +} + +static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 }; + +REGISTER_ARC_IO( + "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF, + k_Signature, 0, + NArcInfoFlags::kKeepName + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix) + , IsArc_Gz) + +}} diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp index 4078241e1..6a0eee247 100644 --- a/CPP/7zip/Archive/HandlerCont.cpp +++ b/CPP/7zip/Archive/HandlerCont.cpp @@ -1,321 +1,321 @@ -// HandlerCont.cpp - -#include "StdAfx.h" - -#include "../../Common/ComTry.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "HandlerCont.h" - -namespace NArchive { - -namespace NExt { -API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size); -} - -Z7_COM7F_IMF(CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - { - RINOK(GetNumberOfItems(&numItems)) - } - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - UInt64 pos, size; - GetItem_ExtractInfo(allFilesMode ? i : indices[i], pos, size); - totalSize += size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - totalSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create streamSpec; - streamSpec->SetStream(_stream); - CMyComPtr2_Create copyCoder; - - for (i = 0;; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - - UInt64 pos, size; - int opRes = GetItem_ExtractInfo(index, pos, size); - totalSize += size; - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - - if (opRes == NExtract::NOperationResult::kOK) - { - RINOK(InStream_SeekSet(_stream, pos)) - streamSpec->Init(size); - - RINOK(copyCoder.Interface()->Code(streamSpec, outStream, NULL, NULL, lps)) - - opRes = NExtract::NOperationResult::kDataError; - if (copyCoder->TotalSize == size) - opRes = NExtract::NOperationResult::kOK; - else if (copyCoder->TotalSize < size) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - } - - outStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - UInt64 pos, size; - if (GetItem_ExtractInfo(index, pos, size) != NExtract::NOperationResult::kOK) - return S_FALSE; - return CreateLimitedInStream(_stream, pos, size, stream); - COM_TRY_END -} - - - -CHandlerImg::CHandlerImg() -{ - Clear_HandlerImg_Vars(); -} - -Z7_COM7F_IMF(CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += _size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - { - if (newPosition) - *newPosition = _virtPos; - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - } - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - -static const Byte k_GDP_Signature[] = - { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }; -// static const Byte k_Ext_Signature[] = { 0x53, 0xEF }; -// static const unsigned k_Ext_Signature_offset = 0x438; - -static const char *GetImgExt(ISequentialInStream *stream) -{ - // const size_t kHeaderSize_for_Ext = (1 << 11); // for ext - const size_t kHeaderSize = 2 << 12; // for 4 KB sector GPT - Byte buf[kHeaderSize]; - size_t processed = kHeaderSize; - if (ReadStream(stream, buf, &processed) == S_OK) - { - if (processed >= kHeaderSize) - if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA) - { - for (unsigned k = (1 << 9); k <= (1u << 12); k <<= 3) - if (memcmp(buf + k, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0) - return "gpt"; - return "mbr"; - } - if (NExt::IsArc_Ext(buf, processed) == k_IsArc_Res_YES) - return "ext"; - } - return NULL; -} - -void CHandlerImg::CloseAtError() -{ - Stream.Release(); -} - -void CHandlerImg::Clear_HandlerImg_Vars() -{ - _imgExt = NULL; - _size = 0; - ClearStreamVars(); - Reset_VirtPos(); - Reset_PosInArc(); -} - -Z7_COM7F_IMF(CHandlerImg::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * openCallback)) -{ - COM_TRY_BEGIN - { - Close(); - HRESULT res; - try - { - res = Open2(stream, openCallback); - if (res == S_OK) - { - CMyComPtr inStream; - const HRESULT res2 = GetStream(0, &inStream); - if (res2 == S_OK && inStream) - _imgExt = GetImgExt(inStream); - // _imgExt = GetImgExt(this); // for debug - /* we reset (_virtPos) to support cases, if some code will - call Read() from Handler object instead of GetStream() object. */ - Reset_VirtPos(); - // optional: we reset (_posInArc). if real seek position of stream will be changed in external code - Reset_PosInArc(); - // optional: here we could also reset seek positions in parent streams.. - return S_OK; - } - } - catch(...) - { - CloseAtError(); - throw; - } - CloseAtError(); - return res; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandlerImg::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - - -Z7_CLASS_IMP_NOQIB_1( - CHandlerImgProgress - , ICompressProgressInfo -) -public: - CHandlerImg &Handler; - CMyComPtr _ratioProgress; - - CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {} -}; - - -Z7_COM7F_IMF(CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - UInt64 inSize2; - if (Handler.Get_PackSizeProcessed(inSize2)) - inSize = &inSize2; - return _ratioProgress->SetRatioInfo(inSize, outSize); -} - - -Z7_COM7F_IMF(CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - RINOK(extractCallback->SetTotal(_size)) - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &outStream, askMode)) - if (!testMode && !outStream) - return S_OK; - RINOK(extractCallback->PrepareOperation(askMode)) - - int opRes = NExtract::NOperationResult::kDataError; - - ClearStreamVars(); - - CMyComPtr inStream; - HRESULT hres = GetStream(0, &inStream); - if (hres == S_FALSE) - hres = E_NOTIMPL; - - if (hres == S_OK && inStream) - { - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - if (Init_PackSizeProcessed()) - { - CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this); - CMyComPtr imgProgress = imgProgressSpec; - imgProgressSpec->_ratioProgress = progress; - progress.Release(); - progress = imgProgress; - } - - CMyComPtr2_Create copyCoder; - - hres = copyCoder.Interface()->Code(inStream, outStream, NULL, &_size, progress); - if (hres == S_OK) - { - if (copyCoder->TotalSize == _size) - opRes = NExtract::NOperationResult::kOK; - - if (_stream_unavailData) - opRes = NExtract::NOperationResult::kUnavailable; - else if (_stream_unsupportedMethod) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else if (_stream_dataError) - opRes = NExtract::NOperationResult::kDataError; - else if (copyCoder->TotalSize < _size) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - } - } - - inStream.Release(); - outStream.Release(); - - if (hres != S_OK) - { - if (hres == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (hres == E_NOTIMPL) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - return hres; - } - - return extractCallback->SetOperationResult(opRes); - COM_TRY_END -} - -} +// HandlerCont.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "HandlerCont.h" + +namespace NArchive { + +namespace NExt { +API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size); +} + +Z7_COM7F_IMF(CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + { + RINOK(GetNumberOfItems(&numItems)) + } + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + UInt64 pos, size; + GetItem_ExtractInfo(allFilesMode ? i : indices[i], pos, size); + totalSize += size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + totalSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create streamSpec; + streamSpec->SetStream(_stream); + CMyComPtr2_Create copyCoder; + + for (i = 0;; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + + UInt64 pos, size; + int opRes = GetItem_ExtractInfo(index, pos, size); + totalSize += size; + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + + if (opRes == NExtract::NOperationResult::kOK) + { + RINOK(InStream_SeekSet(_stream, pos)) + streamSpec->Init(size); + + RINOK(copyCoder.Interface()->Code(streamSpec, outStream, NULL, NULL, lps)) + + opRes = NExtract::NOperationResult::kDataError; + if (copyCoder->TotalSize == size) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoder->TotalSize < size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + + outStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + UInt64 pos, size; + if (GetItem_ExtractInfo(index, pos, size) != NExtract::NOperationResult::kOK) + return S_FALSE; + return CreateLimitedInStream(_stream, pos, size, stream); + COM_TRY_END +} + + + +CHandlerImg::CHandlerImg() +{ + Clear_HandlerImg_Vars(); +} + +Z7_COM7F_IMF(CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + { + if (newPosition) + *newPosition = _virtPos; + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + } + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + +static const Byte k_GDP_Signature[] = + { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }; +// static const Byte k_Ext_Signature[] = { 0x53, 0xEF }; +// static const unsigned k_Ext_Signature_offset = 0x438; + +static const char *GetImgExt(ISequentialInStream *stream) +{ + // const size_t kHeaderSize_for_Ext = (1 << 11); // for ext + const size_t kHeaderSize = 2 << 12; // for 4 KB sector GPT + Byte buf[kHeaderSize]; + size_t processed = kHeaderSize; + if (ReadStream(stream, buf, &processed) == S_OK) + { + if (processed >= kHeaderSize) + if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA) + { + for (unsigned k = (1 << 9); k <= (1u << 12); k <<= 3) + if (memcmp(buf + k, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0) + return "gpt"; + return "mbr"; + } + if (NExt::IsArc_Ext(buf, processed) == k_IsArc_Res_YES) + return "ext"; + } + return NULL; +} + +void CHandlerImg::CloseAtError() +{ + Stream.Release(); +} + +void CHandlerImg::Clear_HandlerImg_Vars() +{ + _imgExt = NULL; + _size = 0; + ClearStreamVars(); + Reset_VirtPos(); + Reset_PosInArc(); +} + +Z7_COM7F_IMF(CHandlerImg::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * openCallback)) +{ + COM_TRY_BEGIN + { + Close(); + HRESULT res; + try + { + res = Open2(stream, openCallback); + if (res == S_OK) + { + CMyComPtr inStream; + const HRESULT res2 = GetStream(0, &inStream); + if (res2 == S_OK && inStream) + _imgExt = GetImgExt(inStream); + // _imgExt = GetImgExt(this); // for debug + /* we reset (_virtPos) to support cases, if some code will + call Read() from Handler object instead of GetStream() object. */ + Reset_VirtPos(); + // optional: we reset (_posInArc). if real seek position of stream will be changed in external code + Reset_PosInArc(); + // optional: here we could also reset seek positions in parent streams.. + return S_OK; + } + } + catch(...) + { + CloseAtError(); + throw; + } + CloseAtError(); + return res; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandlerImg::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + + +Z7_CLASS_IMP_NOQIB_1( + CHandlerImgProgress + , ICompressProgressInfo +) +public: + CHandlerImg &Handler; + CMyComPtr _ratioProgress; + + CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {} +}; + + +Z7_COM7F_IMF(CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + UInt64 inSize2; + if (Handler.Get_PackSizeProcessed(inSize2)) + inSize = &inSize2; + return _ratioProgress->SetRatioInfo(inSize, outSize); +} + + +Z7_COM7F_IMF(CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + RINOK(extractCallback->SetTotal(_size)) + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &outStream, askMode)) + if (!testMode && !outStream) + return S_OK; + RINOK(extractCallback->PrepareOperation(askMode)) + + int opRes = NExtract::NOperationResult::kDataError; + + ClearStreamVars(); + + CMyComPtr inStream; + HRESULT hres = GetStream(0, &inStream); + if (hres == S_FALSE) + hres = E_NOTIMPL; + + if (hres == S_OK && inStream) + { + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + if (Init_PackSizeProcessed()) + { + CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this); + CMyComPtr imgProgress = imgProgressSpec; + imgProgressSpec->_ratioProgress = progress; + progress.Release(); + progress = imgProgress; + } + + CMyComPtr2_Create copyCoder; + + hres = copyCoder.Interface()->Code(inStream, outStream, NULL, &_size, progress); + if (hres == S_OK) + { + if (copyCoder->TotalSize == _size) + opRes = NExtract::NOperationResult::kOK; + + if (_stream_unavailData) + opRes = NExtract::NOperationResult::kUnavailable; + else if (_stream_unsupportedMethod) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else if (_stream_dataError) + opRes = NExtract::NOperationResult::kDataError; + else if (copyCoder->TotalSize < _size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + } + + inStream.Release(); + outStream.Release(); + + if (hres != S_OK) + { + if (hres == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (hres == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return hres; + } + + return extractCallback->SetOperationResult(opRes); + COM_TRY_END +} + +} diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h index 16fba4a7c..82e451aaa 100644 --- a/CPP/7zip/Archive/HandlerCont.h +++ b/CPP/7zip/Archive/HandlerCont.h @@ -1,134 +1,134 @@ -// HandlerCont.h - -#ifndef ZIP7_INC_HANDLER_CONT_H -#define ZIP7_INC_HANDLER_CONT_H - -#include "../../Common/MyCom.h" - -#include "IArchive.h" - -namespace NArchive { - -#define Z7_IFACEM_IInArchive_Cont(x) \ - x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \ - x(Close()) \ - x(GetNumberOfItems(UInt32 *numItems)) \ - x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - /* x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) */ \ - x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ - x(GetNumberOfProperties(UInt32 *numProps)) \ - x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ - x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - - -// #define Z7_COM7F_PUREO(f) virtual Z7_COM7F_IMF(f) Z7_override =0; -// #define Z7_COM7F_PUREO2(t, f) virtual Z7_COM7F_IMF2(t, f) Z7_override =0; - -class CHandlerCont: - public IInArchive, - public IInArchiveGetStream, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_2( - IInArchive, - IInArchiveGetStream) - /* - Z7_IFACEM_IInArchive_Cont(Z7_COM7F_PUREO) - // Z7_IFACE_COM7_PURE(IInArchive_Cont) - */ - Z7_COM7F_IMP(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) -protected: - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - - CMyComPtr _stream; - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0; - // destructor must be virtual for this class - virtual ~CHandlerCont() {} -}; - - - -#define Z7_IFACEM_IInArchive_Img(x) \ - /* x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) */ \ - x(Close()) \ - /* x(GetNumberOfItems(UInt32 *numItems)) */ \ - x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - /* x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) */ \ - x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ - x(GetNumberOfProperties(UInt32 *numProps)) \ - x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ - x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - - -class CHandlerImg: - public IInArchive, - public IInArchiveGetStream, - public IInStream, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_4( - IInArchive, - IInArchiveGetStream, - ISequentialInStream, - IInStream) - - Z7_COM7F_IMP(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) - Z7_COM7F_IMP(GetNumberOfItems(UInt32 *numItems)) - Z7_COM7F_IMP(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) - Z7_IFACE_COM7_IMP(IInStream) - // Z7_IFACEM_IInArchive_Img(Z7_COM7F_PUREO) - -protected: - bool _stream_unavailData; - bool _stream_unsupportedMethod; - bool _stream_dataError; - // bool _stream_UsePackSize; - // UInt64 _stream_PackSize; - UInt64 _virtPos; - UInt64 _posInArc; - UInt64 _size; - CMyComPtr Stream; - const char *_imgExt; - - void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; } - void Reset_VirtPos() { _virtPos = (UInt64)0; } - - void ClearStreamVars() - { - _stream_unavailData = false; - _stream_unsupportedMethod = false; - _stream_dataError = false; - // _stream_UsePackSize = false; - // _stream_PackSize = 0; - } - - void Clear_HandlerImg_Vars(); // it doesn't Release (Stream) var. - - virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; - virtual void CloseAtError(); - - // returns (true), if Get_PackSizeProcessed() is required in Extract() - virtual bool Init_PackSizeProcessed() - { - return false; - } -public: - virtual bool Get_PackSizeProcessed(UInt64 &size) - { - size = 0; - return false; - } - - CHandlerImg(); - // destructor must be virtual for this class - virtual ~CHandlerImg() {} -}; - - -HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize); - -} - -#endif +// HandlerCont.h + +#ifndef ZIP7_INC_HANDLER_CONT_H +#define ZIP7_INC_HANDLER_CONT_H + +#include "../../Common/MyCom.h" + +#include "IArchive.h" + +namespace NArchive { + +#define Z7_IFACEM_IInArchive_Cont(x) \ + x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \ + x(Close()) \ + x(GetNumberOfItems(UInt32 *numItems)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + /* x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) */ \ + x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ + x(GetNumberOfProperties(UInt32 *numProps)) \ + x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ + x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + + +// #define Z7_COM7F_PUREO(f) virtual Z7_COM7F_IMF(f) Z7_override =0; +// #define Z7_COM7F_PUREO2(t, f) virtual Z7_COM7F_IMF2(t, f) Z7_override =0; + +class CHandlerCont: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_2( + IInArchive, + IInArchiveGetStream) + /* + Z7_IFACEM_IInArchive_Cont(Z7_COM7F_PUREO) + // Z7_IFACE_COM7_PURE(IInArchive_Cont) + */ + Z7_COM7F_IMP(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) +protected: + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + + CMyComPtr _stream; + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0; + // destructor must be virtual for this class + virtual ~CHandlerCont() {} +}; + + + +#define Z7_IFACEM_IInArchive_Img(x) \ + /* x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) */ \ + x(Close()) \ + /* x(GetNumberOfItems(UInt32 *numItems)) */ \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + /* x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) */ \ + x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ + x(GetNumberOfProperties(UInt32 *numProps)) \ + x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ + x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + + +class CHandlerImg: + public IInArchive, + public IInArchiveGetStream, + public IInStream, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_4( + IInArchive, + IInArchiveGetStream, + ISequentialInStream, + IInStream) + + Z7_COM7F_IMP(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) + Z7_COM7F_IMP(GetNumberOfItems(UInt32 *numItems)) + Z7_COM7F_IMP(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) + Z7_IFACE_COM7_IMP(IInStream) + // Z7_IFACEM_IInArchive_Img(Z7_COM7F_PUREO) + +protected: + bool _stream_unavailData; + bool _stream_unsupportedMethod; + bool _stream_dataError; + // bool _stream_UsePackSize; + // UInt64 _stream_PackSize; + UInt64 _virtPos; + UInt64 _posInArc; + UInt64 _size; + CMyComPtr Stream; + const char *_imgExt; + + void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; } + void Reset_VirtPos() { _virtPos = (UInt64)0; } + + void ClearStreamVars() + { + _stream_unavailData = false; + _stream_unsupportedMethod = false; + _stream_dataError = false; + // _stream_UsePackSize = false; + // _stream_PackSize = 0; + } + + void Clear_HandlerImg_Vars(); // it doesn't Release (Stream) var. + + virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; + virtual void CloseAtError(); + + // returns (true), if Get_PackSizeProcessed() is required in Extract() + virtual bool Init_PackSizeProcessed() + { + return false; + } +public: + virtual bool Get_PackSizeProcessed(UInt64 &size) + { + size = 0; + return false; + } + + CHandlerImg(); + // destructor must be virtual for this class + virtual ~CHandlerImg() {} +}; + + +HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize); + +} + +#endif diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp index 6e5fe2443..46e023979 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -1,2592 +1,2626 @@ -// HfsHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "HfsHandler.h" - -/* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files - and resource forks. In most cases it looks useless. So we disable it. */ - -#define HFS_SHOW_ALT_STREAMS - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -namespace NArchive { -namespace NHfs { - -static const char * const kResFileName = "rsrc"; // "com.apple.ResourceFork"; - -struct CExtent -{ - UInt32 Pos; - UInt32 NumBlocks; -}; - -struct CIdExtents -{ - UInt32 ID; - UInt32 StartBlock; - CRecordVector Extents; -}; - -struct CFork -{ - UInt64 Size; - UInt32 NumBlocks; - // UInt32 ClumpSize; - CRecordVector Extents; - - CFork(): Size(0), NumBlocks(0) {} - - void Parse(const Byte *p); - - bool IsEmpty() const { return Size == 0 && NumBlocks == 0 && Extents.Size() == 0; } - - UInt32 Calc_NumBlocks_from_Extents() const; - bool Check_NumBlocks() const; - - bool Check_Size_with_NumBlocks(unsigned blockSizeLog) const - { - return Size <= ((UInt64)NumBlocks << blockSizeLog); - } - - bool IsOk(unsigned blockSizeLog) const - { - // we don't check cases with extra (empty) blocks in last extent - return Check_NumBlocks() && Check_Size_with_NumBlocks(blockSizeLog); - } - - bool Upgrade(const CObjectVector &items, UInt32 id); - bool UpgradeAndTest(const CObjectVector &items, UInt32 id, unsigned blockSizeLog) - { - if (!Upgrade(items, id)) - return false; - return IsOk(blockSizeLog); - } -}; - -static const unsigned kNumFixedExtents = 8; -static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; - - -void CFork::Parse(const Byte *p) -{ - Extents.Clear(); - Size = Get64(p); - // ClumpSize = Get32(p + 8); - NumBlocks = Get32(p + 12); - p += 16; - for (unsigned i = 0; i < kNumFixedExtents; i++, p += 8) - { - CExtent e; - e.Pos = Get32(p); - e.NumBlocks = Get32(p + 4); - if (e.NumBlocks != 0) - Extents.Add(e); - } -} - -UInt32 CFork::Calc_NumBlocks_from_Extents() const -{ - UInt32 num = 0; - FOR_VECTOR (i, Extents) - { - num += Extents[i].NumBlocks; - } - return num; -} - -bool CFork::Check_NumBlocks() const -{ - UInt32 num = 0; - FOR_VECTOR (i, Extents) - { - UInt32 next = num + Extents[i].NumBlocks; - if (next < num) - return false; - num = next; - } - return num == NumBlocks; -} - -struct CIdIndexPair -{ - UInt32 ID; - unsigned Index; - - int Compare(const CIdIndexPair &a) const; -}; - -#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; } - -int CIdIndexPair::Compare(const CIdIndexPair &a) const -{ - RINOZ(MyCompare(ID, a.ID)) - return MyCompare(Index, a.Index); -} - -static int FindItemIndex(const CRecordVector &items, UInt32 id) -{ - unsigned left = 0, right = items.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const UInt32 midVal = items[mid].ID; - if (id == midVal) - return (int)items[mid].Index; - if (id < midVal) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int Find_in_IdExtents(const CObjectVector &items, UInt32 id) -{ - unsigned left = 0, right = items.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const UInt32 midVal = items[mid].ID; - if (id == midVal) - return (int)mid; - if (id < midVal) - right = mid; - else - left = mid + 1; - } - return -1; -} - -bool CFork::Upgrade(const CObjectVector &items, UInt32 id) -{ - int index = Find_in_IdExtents(items, id); - if (index < 0) - return true; - const CIdExtents &item = items[index]; - if (Calc_NumBlocks_from_Extents() != item.StartBlock) - return false; - Extents += item.Extents; - return true; -} - - -struct CVolHeader -{ - Byte Header[2]; - UInt16 Version; - // UInt32 Attr; - // UInt32 LastMountedVersion; - // UInt32 JournalInfoBlock; - - UInt32 CTime; - UInt32 MTime; - // UInt32 BackupTime; - // UInt32 CheckedTime; - - UInt32 NumFiles; - UInt32 NumFolders; - unsigned BlockSizeLog; - UInt32 NumBlocks; - UInt32 NumFreeBlocks; - - // UInt32 WriteCount; - // UInt32 FinderInfo[8]; - // UInt64 VolID; - - UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; } - UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; } - bool IsHfsX() const { return Version > 4; } -}; - -inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft) -{ - UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - -enum ERecordType -{ - RECORD_TYPE_FOLDER = 1, - RECORD_TYPE_FILE, - RECORD_TYPE_FOLDER_THREAD, - RECORD_TYPE_FILE_THREAD -}; - - - -// static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr -static const UInt32 kMethod_ZLIB_ATTR = 3; -static const UInt32 kMethod_ZLIB_RSRC = 4; -// static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store -// macos 10.10 -static const UInt32 kMethod_LZVN_ATTR = 7; -static const UInt32 kMethod_LZVN_RSRC = 8; -static const UInt32 kMethod_COPY_ATTR = 9; -static const UInt32 kMethod_COPY_RSRC = 10; -// macos 10.11 -// static const UInt32 kMethod_LZFSE_ATTR = 11; -static const UInt32 kMethod_LZFSE_RSRC = 12; - -// static const UInt32 kMethod_ZBM_RSRC = 14; - -static const char * const g_Methods[] = -{ - NULL - , NULL - , NULL - , "ZLIB-attr" - , "ZLIB-rsrc" - , NULL - , NULL - , "LZVN-attr" - , "LZVN-rsrc" - , "COPY-attr" - , "COPY-rsrc" - , "LZFSE-attr" - , "LZFSE-rsrc" - , NULL - , "ZBM-rsrc" -}; - - -static const Byte k_COPY_Uncompressed_Marker = 0xcc; -static const Byte k_LZVN_Uncompressed_Marker = 6; - -void CCompressHeader::Parse(const Byte *p, size_t dataSize) -{ - Clear(); - - if (dataSize < k_decmpfs_HeaderSize) - return; - if (GetUi32(p) != 0x636D7066) // magic == "fpmc" - return; - Method = GetUi32(p + 4); - UnpackSize = GetUi64(p + 8); - dataSize -= k_decmpfs_HeaderSize; - IsCorrect = true; - - if ( Method == kMethod_ZLIB_RSRC - || Method == kMethod_COPY_RSRC - || Method == kMethod_LZVN_RSRC - || Method == kMethod_LZFSE_RSRC - // || Method == kMethod_ZBM_RSRC // for debug - ) - { - IsResource = true; - if (dataSize == 0) - IsSupported = ( - Method != kMethod_LZFSE_RSRC && - Method != kMethod_COPY_RSRC); - return; - } - - if ( Method == kMethod_ZLIB_ATTR - || Method == kMethod_COPY_ATTR - || Method == kMethod_LZVN_ATTR - // || Method == kMethod_LZFSE_ATTR - ) - { - if (dataSize == 0) - return; - const Byte b = p[k_decmpfs_HeaderSize]; - if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf) - || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker) - || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker)) - { - dataSize--; - // if (UnpackSize > dataSize) - if (UnpackSize != dataSize) - return; - DataPos = k_decmpfs_HeaderSize + 1; - IsSupported = true; - } - else - { - if (Method != kMethod_COPY_ATTR) - IsSupported = true; - DataPos = k_decmpfs_HeaderSize; - } - } -} - - -void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const -{ - if (!IsCorrect) - return; - const UInt32 method = Method; - const char *p = NULL; - if (method < Z7_ARRAY_SIZE(g_Methods)) - p = g_Methods[method]; - AString s; - if (p) - s = p; - else - s.Add_UInt32(method); - // if (!IsSupported) s += "-unsuported"; - prop = s; -} - -void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop) -{ - FLAGS_TO_PROP(g_Methods, methodsMask, prop); -} - - -struct CItem -{ - UString Name; - - UInt32 ParentID; - - UInt16 Type; - UInt16 FileMode; - // UInt16 Flags; - // UInt32 Valence; - UInt32 ID; - UInt32 CTime; - UInt32 MTime; - UInt32 AttrMTime; - UInt32 ATime; - // UInt32 BackupDate; - - /* - UInt32 OwnerID; - UInt32 GroupID; - Byte AdminFlags; - Byte OwnerFlags; - union - { - UInt32 iNodeNum; - UInt32 LinkCount; - UInt32 RawDevice; - } special; - - UInt32 FileType; - UInt32 FileCreator; - UInt16 FinderFlags; - UInt16 Point[2]; - */ - - CFork DataFork; - CFork ResourceFork; - - // for compressed attribute (decmpfs) - int decmpfs_AttrIndex; - CCompressHeader CompressHeader; - - CItem(): - decmpfs_AttrIndex(-1) - {} - bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } - // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); } -}; - - -struct CAttr -{ - UInt32 ID; - bool Fork_defined; - - // UInt32 Size; // for (Fork_defined == false) case - // size_t DataPos; // for (Fork_defined == false) case - CByteBuffer Data; - - CFork Fork; - - UString Name; - - UInt64 GetSize() const - { - if (Fork_defined) - return Fork.Size; - return Data.Size(); - } - - CAttr(): - Fork_defined(false) - // Size(0), - // DataPos(0), - {} -}; - - -static const int kAttrIndex_Item = -1; -static const int kAttrIndex_Resource = -2; - -struct CRef -{ - unsigned ItemIndex; - int AttrIndex; - int Parent; - - CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {} - bool IsResource() const { return AttrIndex == kAttrIndex_Resource; } - bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; } - bool IsItem() const { return AttrIndex == kAttrIndex_Item; } -}; - - -class CDatabase -{ - HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); - HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray); - HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); - HRESULT LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); - bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip); -public: - CRecordVector Refs; - CObjectVector Items; - CObjectVector Attrs; - - // CByteBuffer AttrBuf; - - CVolHeader Header; - bool HeadersError; - bool UnsupportedFeature; - bool ThereAreAltStreams; - // bool CaseSensetive; - UString ResFileName; - - UInt64 SpecOffset; - UInt64 PhySize; - UInt64 PhySize2; - UInt64 ArcFileSize; - UInt32 MethodsMask; - - void Clear() - { - SpecOffset = 0; - PhySize = 0; - PhySize2 = 0; - ArcFileSize = 0; - MethodsMask = 0; - HeadersError = false; - UnsupportedFeature = false; - ThereAreAltStreams = false; - // CaseSensetive = false; - - Refs.Clear(); - Items.Clear(); - Attrs.Clear(); - // AttrBuf.Free(); - } - - UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const - { - if (ref.AttrIndex >= 0) - return Attrs[ref.AttrIndex].GetSize(); - const CItem &item = Items[ref.ItemIndex]; - if (ref.IsResource()) - return item.ResourceFork.Size; - if (item.IsDir()) - return 0; - else if (item.CompressHeader.IsCorrect) - return item.CompressHeader.UnpackSize; - return item.DataFork.Size; - } - - void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const; - HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *progress); -}; - -enum -{ - kHfsID_Root = 1, - kHfsID_RootFolder = 2, - kHfsID_ExtentsFile = 3, - kHfsID_CatalogFile = 4, - kHfsID_BadBlockFile = 5, - kHfsID_AllocationFile = 6, - kHfsID_StartupFile = 7, - kHfsID_AttributesFile = 8, - kHfsID_RepairCatalogFile = 14, - kHfsID_BogusExtentFile = 15, - kHfsID_FirstUserCatalogNode = 16 -}; - -void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const -{ - unsigned len = 0; - const unsigned kNumLevelsMax = (1 << 10); - unsigned cur = index; - unsigned i; - - for (i = 0; i < kNumLevelsMax; i++) - { - const CRef &ref = Refs[cur]; - const UString *s; - - if (ref.IsResource()) - s = &ResFileName; - else if (ref.AttrIndex >= 0) - s = &Attrs[ref.AttrIndex].Name; - else - s = &Items[ref.ItemIndex].Name; - - len += s->Len(); - len++; - cur = (unsigned)ref.Parent; - if (ref.Parent < 0) - break; - } - - len--; - wchar_t *p = path.AllocBstr(len); - p[len] = 0; - cur = index; - - for (;;) - { - const CRef &ref = Refs[cur]; - const UString *s; - wchar_t delimChar = L':'; - - if (ref.IsResource()) - s = &ResFileName; - else if (ref.AttrIndex >= 0) - s = &Attrs[ref.AttrIndex].Name; - else - { - delimChar = WCHAR_PATH_SEPARATOR; - s = &Items[ref.ItemIndex].Name; - } - - unsigned curLen = s->Len(); - len -= curLen; - - const wchar_t *src = (const wchar_t *)*s; - wchar_t *dest = p + len; - for (unsigned j = 0; j < curLen; j++) - { - wchar_t c = src[j]; - // 18.06 - if (c == CHAR_PATH_SEPARATOR || c == '/') - c = '_'; - dest[j] = c; - } - - if (len == 0) - break; - p[--len] = delimChar; - cur = (unsigned)ref.Parent; - } -} - -// Actually we read all blocks. It can be larger than fork.Size - -HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream) -{ - if (fork.NumBlocks >= Header.NumBlocks) - return S_FALSE; - if ((ArcFileSize >> Header.BlockSizeLog) + 1 < fork.NumBlocks) - return S_FALSE; - - const size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog; - if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks) - return S_FALSE; - buf.Alloc(totalSize); - UInt32 curBlock = 0; - FOR_VECTOR (i, fork.Extents) - { - if (curBlock >= fork.NumBlocks) - return S_FALSE; - const CExtent &e = fork.Extents[i]; - if (e.Pos > Header.NumBlocks || - e.NumBlocks > fork.NumBlocks - curBlock || - e.NumBlocks > Header.NumBlocks - e.Pos) - return S_FALSE; - RINOK(InStream_SeekSet(inStream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog))) - RINOK(ReadStream_FALSE(inStream, - (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), - (size_t)e.NumBlocks << Header.BlockSizeLog)) - curBlock += e.NumBlocks; - } - return S_OK; -} - -static const unsigned kNodeDescriptor_Size = 14; - -struct CNodeDescriptor -{ - UInt32 fLink; - // UInt32 bLink; - Byte Kind; - // Byte Height; - unsigned NumRecords; - - bool Parse(const Byte *p, unsigned nodeSizeLog); -}; - - -bool CNodeDescriptor::Parse(const Byte *p, unsigned nodeSizeLog) -{ - fLink = Get32(p); - // bLink = Get32(p + 4); - Kind = p[8]; - // Height = p[9]; - NumRecords = Get16(p + 10); - - const size_t nodeSize = (size_t)1 << nodeSizeLog; - if (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 > nodeSize) - return false; - const size_t limit = nodeSize - ((UInt32)NumRecords + 1) * 2; - - p += nodeSize - 2; - - for (unsigned i = 0; i < NumRecords; i++) - { - const UInt32 offs = Get16(p); - p -= 2; - const UInt32 offsNext = Get16(p); - if (offs < kNodeDescriptor_Size - || offs >= offsNext - || offsNext > limit) - return false; - } - return true; -} - -struct CHeaderRec -{ - // UInt16 TreeDepth; - // UInt32 RootNode; - // UInt32 LeafRecords; - UInt32 FirstLeafNode; - // UInt32 LastLeafNode; - unsigned NodeSizeLog; - // UInt16 MaxKeyLength; - UInt32 TotalNodes; - // UInt32 FreeNodes; - // UInt16 Reserved1; - // UInt32 ClumpSize; - // Byte BtreeType; - // Byte KeyCompareType; - // UInt32 Attributes; - // UInt32 Reserved3[16]; - - HRESULT Parse2(const CByteBuffer &buf); -}; - -HRESULT CHeaderRec::Parse2(const CByteBuffer &buf) -{ - if (buf.Size() < kNodeDescriptor_Size + 0x2A + 16 * 4) - return S_FALSE; - const Byte * p = (const Byte *)buf + kNodeDescriptor_Size; - // TreeDepth = Get16(p); - // RootNode = Get32(p + 2); - // LeafRecords = Get32(p + 6); - FirstLeafNode = Get32(p + 0xA); - // LastLeafNode = Get32(p + 0xE); - const UInt32 nodeSize = Get16(p + 0x12); - - unsigned i; - for (i = 9; ((UInt32)1 << i) != nodeSize; i++) - if (i == 16) - return S_FALSE; - NodeSizeLog = i; - - // MaxKeyLength = Get16(p + 0x14); - TotalNodes = Get32(p + 0x16); - // FreeNodes = Get32(p + 0x1A); - // Reserved1 = Get16(p + 0x1E); - // ClumpSize = Get32(p + 0x20); - // BtreeType = p[0x24]; - // KeyCompareType = p[0x25]; - // Attributes = Get32(p + 0x26); - /* - for (int i = 0; i < 16; i++) - Reserved3[i] = Get32(p + 0x2A + i * 4); - */ - - if ((buf.Size() >> NodeSizeLog) < TotalNodes) - return S_FALSE; - - return S_OK; -} - - -static const Byte kNodeType_Leaf = 0xFF; -// static const Byte kNodeType_Index = 0; -// static const Byte kNodeType_Header = 1; -// static const Byte kNodeType_Mode = 2; - -static const Byte kExtentForkType_Data = 0; -static const Byte kExtentForkType_Resource = 0xFF; - -/* It loads data extents from Extents Overflow File - Most dmg installers are not fragmented. So there are no extents in Overflow File. */ - -HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray) -{ - if (fork.NumBlocks == 0) - return S_OK; - CByteBuffer buf; - RINOK(ReadFile(fork, buf, inStream)) - const Byte *p = (const Byte *)buf; - - // CNodeDescriptor nodeDesc; - // nodeDesc.Parse(p); - CHeaderRec hr; - RINOK(hr.Parse2(buf)) - - UInt32 node = hr.FirstLeafNode; - if (node == 0) - return S_OK; - if (hr.TotalNodes == 0) - return S_FALSE; - - CByteArr usedBuf(hr.TotalNodes); - memset(usedBuf, 0, hr.TotalNodes); - - while (node != 0) - { - if (node >= hr.TotalNodes || usedBuf[node] != 0) - return S_FALSE; - usedBuf[node] = 1; - - const size_t nodeOffset = (size_t)node << hr.NodeSizeLog; - CNodeDescriptor desc; - if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog)) - return S_FALSE; - if (desc.Kind != kNodeType_Leaf) - return S_FALSE; - - UInt32 endBlock = 0; - - for (unsigned i = 0; i < desc.NumRecords; i++) - { - const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); - const Byte *r = p + nodeOffset + nodeSize - i * 2; - const UInt32 offs = Get16(r - 2); - UInt32 recSize = Get16(r - 4) - offs; - const unsigned kKeyLen = 10; - - if (recSize != 2 + kKeyLen + kNumFixedExtents * 8) - return S_FALSE; - - r = p + nodeOffset + offs; - if (Get16(r) != kKeyLen) - return S_FALSE; - - const Byte forkType = r[2]; - unsigned forkTypeIndex; - if (forkType == kExtentForkType_Data) - forkTypeIndex = 0; - else if (forkType == kExtentForkType_Resource) - forkTypeIndex = 1; - else - continue; - CObjectVector &overflowExtents = overflowExtentsArray[forkTypeIndex]; - - const UInt32 id = Get32(r + 4); - const UInt32 startBlock = Get32(r + 8); - r += 2 + kKeyLen; - - bool needNew = true; - - if (overflowExtents.Size() != 0) - { - CIdExtents &e = overflowExtents.Back(); - if (e.ID == id) - { - if (endBlock != startBlock) - return S_FALSE; - needNew = false; - } - } - - if (needNew) - { - CIdExtents &e = overflowExtents.AddNew(); - e.ID = id; - e.StartBlock = startBlock; - endBlock = startBlock; - } - - CIdExtents &e = overflowExtents.Back(); - - for (unsigned k = 0; k < kNumFixedExtents; k++, r += 8) - { - CExtent ee; - ee.Pos = Get32(r); - ee.NumBlocks = Get32(r + 4); - if (ee.NumBlocks != 0) - { - e.Extents.Add(ee); - endBlock += ee.NumBlocks; - } - } - } - - node = desc.fLink; - } - return S_OK; -} - -static void LoadName(const Byte *data, unsigned len, UString &dest) -{ - wchar_t *p = dest.GetBuf(len); - unsigned i; - for (i = 0; i < len; i++) - { - const wchar_t c = Get16(data + i * 2); - if (c == 0) - break; - p[i] = c; - } - p[i] = 0; - dest.ReleaseBuf_SetLen(i); -} - -static bool IsNameEqualTo(const Byte *data, const char *name) -{ - for (unsigned i = 0;; i++) - { - const char c = name[i]; - if (c == 0) - return true; - if (Get16(data + i * 2) != (Byte)c) - return false; - } -} - -static const UInt32 kAttrRecordType_Inline = 0x10; -static const UInt32 kAttrRecordType_Fork = 0x20; -// static const UInt32 kAttrRecordType_Extents = 0x30; - -HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress) -{ - if (fork.NumBlocks == 0) - return S_OK; - - CByteBuffer AttrBuf; - RINOK(ReadFile(fork, AttrBuf, inStream)) - const Byte *p = (const Byte *)AttrBuf; - - // CNodeDescriptor nodeDesc; - // nodeDesc.Parse(p); - CHeaderRec hr; - RINOK(hr.Parse2(AttrBuf)) - - // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); - - UInt32 node = hr.FirstLeafNode; - if (node == 0) - return S_OK; - if (hr.TotalNodes == 0) - return S_FALSE; - - CByteArr usedBuf(hr.TotalNodes); - memset(usedBuf, 0, hr.TotalNodes); - - CFork resFork; - - while (node != 0) - { - if (node >= hr.TotalNodes || usedBuf[node] != 0) - return S_FALSE; - usedBuf[node] = 1; - - const size_t nodeOffset = (size_t)node << hr.NodeSizeLog; - CNodeDescriptor desc; - if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog)) - return S_FALSE; - if (desc.Kind != kNodeType_Leaf) - return S_FALSE; - - for (unsigned i = 0; i < desc.NumRecords; i++) - { - const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); - const Byte *r = p + nodeOffset + nodeSize - i * 2; - const UInt32 offs = Get16(r - 2); - UInt32 recSize = Get16(r - 4) - offs; - const unsigned kHeadSize = 14; - if (recSize < kHeadSize) - return S_FALSE; - - r = p + nodeOffset + offs; - const UInt32 keyLen = Get16(r); - - // UInt16 pad = Get16(r + 2); - const UInt32 fileID = Get32(r + 4); - const unsigned startBlock = Get32(r + 8); - if (startBlock != 0) - { - // that case is still unsupported - UnsupportedFeature = true; - continue; - } - const unsigned nameLen = Get16(r + 12); - - if (keyLen + 2 > recSize || - keyLen != kHeadSize - 2 + nameLen * 2) - return S_FALSE; - r += kHeadSize; - recSize -= kHeadSize; - - const Byte *name = r; - r += nameLen * 2; - recSize -= nameLen * 2; - - if (recSize < 4) - return S_FALSE; - - const UInt32 recordType = Get32(r); - - if (progress && (Attrs.Size() & 0xFFF) == 0) - { - const UInt64 numFiles = 0; - RINOK(progress->SetCompleted(&numFiles, NULL)) - } - - if (Attrs.Size() >= ((UInt32)1 << 31)) - return S_FALSE; - - CAttr &attr = Attrs.AddNew(); - attr.ID = fileID; - LoadName(name, nameLen, attr.Name); - - if (recordType == kAttrRecordType_Fork) - { - // 22.00 : some hfs files contain it; - /* spec: If the attribute has more than 8 extents, there will be additional - records (of type kAttrRecordType_Extents) for this attribute. */ - if (recSize != 8 + kForkRecSize) - return S_FALSE; - if (Get32(r + 4) != 0) // reserved - return S_FALSE; - attr.Fork.Parse(r + 8); - attr.Fork_defined = true; - continue; - } - else if (recordType != kAttrRecordType_Inline) - { - UnsupportedFeature = true; - continue; - } - - const unsigned kRecordHeaderSize = 16; - if (recSize < kRecordHeaderSize) - return S_FALSE; - if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved - return S_FALSE; - const UInt32 dataSize = Get32(r + 12); - - r += kRecordHeaderSize; - recSize -= kRecordHeaderSize; - - if (recSize < dataSize) - return S_FALSE; - - attr.Data.CopyFrom(r, dataSize); - // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; - // attr.Size = dataSize; - } - - node = desc.fLink; - } - return S_OK; -} - - -bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip) -{ - const CAttr &attr = Attrs[attrIndex]; - skip = false; - if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty()) - return false; - - item.CompressHeader.Parse(attr.Data, attr.Data.Size()); - - if (item.CompressHeader.IsCorrect) - { - item.decmpfs_AttrIndex = (int)attrIndex; - skip = true; - if (item.CompressHeader.Method < sizeof(MethodsMask) * 8) - MethodsMask |= ((UInt32)1 << item.CompressHeader.Method); - } - - return true; -} - - -HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) -{ - CByteBuffer buf; - RINOK(ReadFile(fork, buf, inStream)) - const Byte *p = (const Byte *)buf; - - // CNodeDescriptor nodeDesc; - // nodeDesc.Parse(p); - CHeaderRec hr; - RINOK(hr.Parse2(buf)) - - CRecordVector IdToIndexMap; - - const unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles); - - const unsigned kBasicRecSize = 0x58; - const unsigned kMinRecSize = kBasicRecSize + 10; - - if ((UInt64)reserveSize * kMinRecSize < buf.Size()) - { - Items.ClearAndReserve(reserveSize); - Refs.ClearAndReserve(reserveSize); - IdToIndexMap.ClearAndReserve(reserveSize); - } - - // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); - - CByteArr usedBuf(hr.TotalNodes); - if (hr.TotalNodes != 0) - memset(usedBuf, 0, hr.TotalNodes); - - CFork resFork; - - UInt32 node = hr.FirstLeafNode; - UInt32 numFiles = 0; - UInt32 numFolders = 0; - - while (node != 0) - { - if (node >= hr.TotalNodes || usedBuf[node] != 0) - return S_FALSE; - usedBuf[node] = 1; - - const size_t nodeOffset = (size_t)node << hr.NodeSizeLog; - CNodeDescriptor desc; - if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog)) - return S_FALSE; - if (desc.Kind != kNodeType_Leaf) - return S_FALSE; - - for (unsigned i = 0; i < desc.NumRecords; i++) - { - const UInt32 nodeSize = (1 << hr.NodeSizeLog); - const Byte *r = p + nodeOffset + nodeSize - i * 2; - const UInt32 offs = Get16(r - 2); - UInt32 recSize = Get16(r - 4) - offs; - if (recSize < 6) - return S_FALSE; - - r = p + nodeOffset + offs; - UInt32 keyLen = Get16(r); - UInt32 parentID = Get32(r + 2); - if (keyLen < 6 || (keyLen & 1) != 0 || keyLen + 2 > recSize) - return S_FALSE; - r += 6; - recSize -= 6; - keyLen -= 6; - - unsigned nameLen = Get16(r); - if (nameLen * 2 != (unsigned)keyLen) - return S_FALSE; - r += 2; - recSize -= 2; - - r += nameLen * 2; - recSize -= nameLen * 2; - - if (recSize < 2) - return S_FALSE; - UInt16 type = Get16(r); - - if (type != RECORD_TYPE_FOLDER && - type != RECORD_TYPE_FILE) - continue; - - if (recSize < kBasicRecSize) - return S_FALSE; - - CItem &item = Items.AddNew(); - item.ParentID = parentID; - item.Type = type; - // item.Flags = Get16(r + 2); - // item.Valence = Get32(r + 4); - item.ID = Get32(r + 8); - { - const Byte *name = r - (nameLen * 2); - LoadName(name, nameLen, item.Name); - if (item.Name.Len() <= 1) - { - if (item.Name.IsEmpty() && nameLen == 21) - { - if (GetUi32(name) == 0 && - GetUi32(name + 4) == 0 && - IsNameEqualTo(name + 8, "HFS+ Private Data")) - { - // it's folder for "Hard Links" files - item.Name = "[HFS+ Private Data]"; - } - } - - // Some dmg files have ' ' folder item. - if (item.Name.IsEmpty() || item.Name[0] == L' ') - item.Name = "[]"; - } - } - - item.CTime = Get32(r + 0xC); - item.MTime = Get32(r + 0x10); - item.AttrMTime = Get32(r + 0x14); - item.ATime = Get32(r + 0x18); - // item.BackupDate = Get32(r + 0x1C); - - /* - item.OwnerID = Get32(r + 0x20); - item.GroupID = Get32(r + 0x24); - item.AdminFlags = r[0x28]; - item.OwnerFlags = r[0x29]; - */ - item.FileMode = Get16(r + 0x2A); - /* - item.special.iNodeNum = Get16(r + 0x2C); // or .linkCount - item.FileType = Get32(r + 0x30); - item.FileCreator = Get32(r + 0x34); - item.FinderFlags = Get16(r + 0x38); - item.Point[0] = Get16(r + 0x3A); // v - item.Point[1] = Get16(r + 0x3C); // h - */ - - // const refIndex = Refs.Size(); - CIdIndexPair pair; - pair.ID = item.ID; - pair.Index = Items.Size() - 1; - IdToIndexMap.Add(pair); - - recSize -= kBasicRecSize; - r += kBasicRecSize; - if (item.IsDir()) - { - numFolders++; - if (recSize != 0) - return S_FALSE; - } - else - { - numFiles++; - if (recSize != kForkRecSize * 2) - return S_FALSE; - - item.DataFork.Parse(r); - - if (!item.DataFork.UpgradeAndTest(overflowExtentsArray[0], item.ID, Header.BlockSizeLog)) - HeadersError = true; - - item.ResourceFork.Parse(r + kForkRecSize); - if (!item.ResourceFork.IsEmpty()) - { - if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog)) - HeadersError = true; - // ThereAreAltStreams = true; - } - } - if (progress && (Items.Size() & 0xFFF) == 0) - { - const UInt64 numItems = Items.Size(); - RINOK(progress->SetCompleted(&numItems, NULL)) - } - } - node = desc.fLink; - } - - if (Header.NumFiles != numFiles || - Header.NumFolders + 1 != numFolders) - HeadersError = true; - - IdToIndexMap.Sort2(); - { - for (unsigned i = 1; i < IdToIndexMap.Size(); i++) - if (IdToIndexMap[i - 1].ID == IdToIndexMap[i].ID) - return S_FALSE; - } - - - CBoolArr skipAttr(Attrs.Size()); - { - for (unsigned i = 0; i < Attrs.Size(); i++) - skipAttr[i] = false; - } - - { - FOR_VECTOR (i, Attrs) - { - const CAttr &attr = Attrs[i]; - - const int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); - if (itemIndex < 0) - { - HeadersError = true; - continue; - } - - if (attr.Name.IsEqualTo("com.apple.decmpfs")) - { - if (!Parse_decmpgfs(i, Items[itemIndex], skipAttr[i])) - HeadersError = true; - } - } - } - - IdToIndexMap.ClearAndReserve(Items.Size()); - - { - FOR_VECTOR (i, Items) - { - const CItem &item = Items[i]; - - CIdIndexPair pair; - pair.ID = item.ID; - pair.Index = Refs.Size(); - IdToIndexMap.Add(pair); - - CRef ref; - ref.ItemIndex = i; - Refs.Add(ref); - - #ifdef HFS_SHOW_ALT_STREAMS - - if (item.ResourceFork.IsEmpty()) - continue; - if (item.CompressHeader.IsSupported && item.CompressHeader.IsMethod_Resource()) - continue; - - ThereAreAltStreams = true; - ref.AttrIndex = kAttrIndex_Resource; - ref.Parent = (int)(Refs.Size() - 1); - Refs.Add(ref); - - #endif - } - } - - IdToIndexMap.Sort2(); - - { - FOR_VECTOR (i, Refs) - { - CRef &ref = Refs[i]; - if (ref.IsResource()) - continue; - const CItem &item = Items[ref.ItemIndex]; - ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID); - if (ref.Parent >= 0) - { - if (!Items[Refs[ref.Parent].ItemIndex].IsDir()) - { - ref.Parent = -1; - HeadersError = true; - } - } - } - } - - #ifdef HFS_SHOW_ALT_STREAMS - { - FOR_VECTOR (i, Attrs) - { - if (skipAttr[i]) - continue; - const CAttr &attr = Attrs[i]; - - const int refIndex = FindItemIndex(IdToIndexMap, attr.ID); - if (refIndex < 0) - { - HeadersError = true; - continue; - } - - ThereAreAltStreams = true; - - CRef ref; - ref.AttrIndex = (int)i; - ref.Parent = refIndex; - ref.ItemIndex = Refs[refIndex].ItemIndex; - Refs.Add(ref); - } - } - #endif - - return S_OK; -} - -static const unsigned kHeaderPadSize = (1 << 10); -static const unsigned kMainHeaderSize = 512; -static const unsigned kHfsHeaderSize = kHeaderPadSize + kMainHeaderSize; - -API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size) -{ - if (size < kHfsHeaderSize) - return k_IsArc_Res_NEED_MORE; - p += kHeaderPadSize; - if (p[0] == 'B' && p[1] == 'D') - { - if (p[0x7C] != 'H' || p[0x7C + 1] != '+') - return k_IsArc_Res_NO; - } - else - { - if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X')) - return k_IsArc_Res_NO; - UInt32 version = Get16(p + 2); - if (version < 4 || version > 5) - return k_IsArc_Res_NO; - } - return k_IsArc_Res_YES; -} -} - -HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) -{ - Clear(); - Byte buf[kHfsHeaderSize]; - RINOK(ReadStream_FALSE(inStream, buf, kHfsHeaderSize)) - { - for (unsigned i = 0; i < kHeaderPadSize; i++) - if (buf[i] != 0) - return S_FALSE; - } - const Byte *p = buf + kHeaderPadSize; - CVolHeader &h = Header; - - h.Header[0] = p[0]; - h.Header[1] = p[1]; - - if (p[0] == 'B' && p[1] == 'D') - { - /* - It's header for old HFS format. - We don't support old HFS format, but we support - special HFS volume that contains embedded HFS+ volume - */ - - if (p[0x7C] != 'H' || p[0x7C + 1] != '+') - return S_FALSE; - - /* - h.CTime = Get32(p + 0x2); - h.MTime = Get32(p + 0x6); - - h.NumFiles = Get32(p + 0x54); - h.NumFolders = Get32(p + 0x58); - - if (h.NumFolders > ((UInt32)1 << 29) || - h.NumFiles > ((UInt32)1 << 30)) - return S_FALSE; - if (progress) - { - UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1; - RINOK(progress->SetTotal(&numFiles, NULL)) - } - h.NumFreeBlocks = Get16(p + 0x22); - */ - - UInt32 blockSize = Get32(p + 0x14); - - { - unsigned i; - for (i = 9; ((UInt32)1 << i) != blockSize; i++) - if (i == 31) - return S_FALSE; - h.BlockSizeLog = i; - } - - h.NumBlocks = Get16(p + 0x12); - /* - we suppose that it has the follwing layout - { - start block with header - [h.NumBlocks] - end block with header - } - */ - PhySize2 = ((UInt64)h.NumBlocks + 2) << h.BlockSizeLog; - - UInt32 startBlock = Get16(p + 0x7C + 2); - UInt32 blockCount = Get16(p + 0x7C + 4); - SpecOffset = (UInt64)(1 + startBlock) << h.BlockSizeLog; - UInt64 phy = SpecOffset + ((UInt64)blockCount << h.BlockSizeLog); - if (PhySize2 < phy) - PhySize2 = phy; - RINOK(InStream_SeekSet(inStream, SpecOffset)) - RINOK(ReadStream_FALSE(inStream, buf, kHfsHeaderSize)) - } - - if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X')) - return S_FALSE; - h.Version = Get16(p + 2); - if (h.Version < 4 || h.Version > 5) - return S_FALSE; - - // h.Attr = Get32(p + 4); - // h.LastMountedVersion = Get32(p + 8); - // h.JournalInfoBlock = Get32(p + 0xC); - - h.CTime = Get32(p + 0x10); - h.MTime = Get32(p + 0x14); - // h.BackupTime = Get32(p + 0x18); - // h.CheckedTime = Get32(p + 0x1C); - - h.NumFiles = Get32(p + 0x20); - h.NumFolders = Get32(p + 0x24); - - if (h.NumFolders > ((UInt32)1 << 29) || - h.NumFiles > ((UInt32)1 << 30)) - return S_FALSE; - - RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize)) - - if (progress) - { - const UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1; - RINOK(progress->SetTotal(&numFiles, NULL)) - } - - UInt32 blockSize = Get32(p + 0x28); - - { - unsigned i; - for (i = 9; ((UInt32)1 << i) != blockSize; i++) - if (i == 31) - return S_FALSE; - h.BlockSizeLog = i; - } - - h.NumBlocks = Get32(p + 0x2C); - h.NumFreeBlocks = Get32(p + 0x30); - - /* - h.NextCalatlogNodeID = Get32(p + 0x40); - h.WriteCount = Get32(p + 0x44); - for (i = 0; i < 6; i++) - h.FinderInfo[i] = Get32(p + 0x50 + i * 4); - h.VolID = Get64(p + 0x68); - */ - - ResFileName = kResFileName; - - CFork extentsFork, catalogFork, attrFork; - // allocationFork.Parse(p + 0x70 + 0x50 * 0); - extentsFork.Parse(p + 0x70 + 0x50 * 1); - catalogFork.Parse(p + 0x70 + 0x50 * 2); - attrFork.Parse (p + 0x70 + 0x50 * 3); - // startupFork.Parse(p + 0x70 + 0x50 * 4); - - CObjectVector overflowExtents[2]; - if (!extentsFork.IsOk(Header.BlockSizeLog)) - HeadersError = true; - else - { - HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents); - if (res == S_FALSE) - HeadersError = true; - else if (res != S_OK) - return res; - } - - if (!catalogFork.UpgradeAndTest(overflowExtents[0], kHfsID_CatalogFile, Header.BlockSizeLog)) - return S_FALSE; - - if (!attrFork.UpgradeAndTest(overflowExtents[0], kHfsID_AttributesFile, Header.BlockSizeLog)) - HeadersError = true; - else - { - if (attrFork.Size != 0) - RINOK(LoadAttrs(attrFork, inStream, progress)) - } - - RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress)) - - PhySize = Header.GetPhySize(); - return S_OK; -} - - - -Z7_class_CHandler_final: - public IInArchive, - public IArchiveGetRawProps, - public IInArchiveGetStream, - public CMyUnknownImp, - public CDatabase -{ - Z7_IFACES_IMP_UNK_3( - IInArchive, - IArchiveGetRawProps, - IInArchiveGetStream) - - CMyComPtr _stream; - HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidCTime, - kpidMTime, - kpidATime, - kpidChangeTime, - kpidPosixAttrib, - /* - kpidUserId, - kpidGroupId, - */ -#ifdef HFS_SHOW_ALT_STREAMS - kpidIsAltStream, -#endif - kpidMethod -}; - -static const Byte kArcProps[] = -{ - kpidMethod, - kpidCharacts, - kpidClusterSize, - kpidFreeSpace, - kpidCTime, - kpidMTime -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) -{ - if (hfsTime == 0) - return; - FILETIME ft; - HfsTimeToFileTime(hfsTime, ft); - prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base); -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; - case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break; - case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break; - case kpidPhySize: - { - UInt64 v = SpecOffset + PhySize; - if (v < PhySize2) - v = PhySize2; - prop = v; - break; - } - case kpidClusterSize: prop = (UInt32)1 << Header.BlockSizeLog; break; - case kpidFreeSpace: prop = (UInt64)Header.GetFreeSize(); break; - case kpidMTime: HfsTimeToProp(Header.MTime, prop); break; - case kpidCTime: - { - if (Header.CTime != 0) - { - FILETIME localFt, ft; - HfsTimeToFileTime(Header.CTime, localFt); - if (LocalFileTimeToFileTime(&localFt, &ft)) - prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base); - } - break; - } - case kpidIsTree: prop = true; break; - case kpidErrorFlags: - { - UInt32 flags = 0; - if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; - if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature; - if (flags != 0) - prop = flags; - break; - } - case kpidIsAltStream: prop = ThereAreAltStreams; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) -{ - *name = NULL; - *propID = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - const CRef &ref = Refs[index]; - *parentType = ref.IsAltStream() ? - NParentType::kAltStream : - NParentType::kDir; - *parent = (UInt32)(Int32)ref.Parent; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - #ifdef MY_CPU_LE - if (propID == kpidName) - { - const CRef &ref = Refs[index]; - const UString *s; - if (ref.IsResource()) - s = &ResFileName; - else if (ref.AttrIndex >= 0) - s = &Attrs[ref.AttrIndex].Name; - else - s = &Items[ref.ItemIndex].Name; - *data = (const wchar_t *)(*s); - *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t); - *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; - return S_OK; - } - #else - UNUSED_VAR(index) - UNUSED_VAR(propID) - #endif - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CRef &ref = Refs[index]; - const CItem &item = Items[ref.ItemIndex]; - switch (propID) - { - case kpidPath: GetItemPath(index, prop); break; - case kpidName: - { - const UString *s; - if (ref.IsResource()) - s = &ResFileName; - else if (ref.AttrIndex >= 0) - s = &Attrs[ref.AttrIndex].Name; - else - s = &item.Name; - prop = *s; - break; - } - case kpidPackSize: - { - UInt64 size; - if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].GetSize(); - else if (ref.IsResource()) - size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; - else if (item.IsDir()) - break; - else if (item.CompressHeader.IsCorrect) - { - if (item.CompressHeader.IsMethod_Resource()) - size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; - else if (item.decmpfs_AttrIndex >= 0) - { - // size = item.PackSize; - const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; - size = attr.Data.Size() - item.CompressHeader.DataPos; - } - else - size = 0; - } - else - size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog; - prop = size; - break; - } - case kpidSize: - { - UInt64 size; - if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].GetSize(); - else if (ref.IsResource()) - size = item.ResourceFork.Size; - else if (item.IsDir()) - break; - else if (item.CompressHeader.IsCorrect) - size = item.CompressHeader.UnpackSize; - else - size = item.DataFork.Size; - prop = size; - break; - } - case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break; - case kpidIsAltStream: prop = ref.IsAltStream(); break; - case kpidCTime: HfsTimeToProp(item.CTime, prop); break; - case kpidMTime: HfsTimeToProp(item.MTime, prop); break; - case kpidATime: HfsTimeToProp(item.ATime, prop); break; - case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break; - case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break; - /* - case kpidUserId: prop = (UInt32)item.OwnerID; break; - case kpidGroupId: prop = (UInt32)item.GroupID; break; - */ - - case kpidMethod: - if (ref.IsItem()) - item.CompressHeader.MethodToProp(prop); - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream, callback)) - _stream = inStream; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _stream.Release(); - Clear(); - return S_OK; -} - -static const UInt32 kCompressionBlockSize = 1 << 16; - -CDecoder::CDecoder(bool IsAdlerOptional) -{ - /* Some new hfs files contain zlib resource fork without Adler checksum. - We do not know how we must detect case where there is Adler - checksum or there is no Adler checksum. - */ - _zlibDecoder->IsAdlerOptional = IsAdlerOptional; - _lzfseDecoder->LzvnMode = true; -} - -HRESULT CDecoder::ExtractResourceFork_ZLIB( - ISequentialInStream *inStream, ISequentialOutStream *outStream, - UInt64 forkSize, UInt64 unpackSize, - UInt64 progressStart, IArchiveExtractCallback *extractCallback) -{ - const unsigned kHeaderSize = 0x100 + 8; - - const size_t kBufSize = kCompressionBlockSize; - _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header - - RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize)) - Byte *buf = _buf; - const UInt32 dataPos = Get32(buf); - const UInt32 mapPos = Get32(buf + 4); - const UInt32 dataSize = Get32(buf + 8); - const UInt32 mapSize = Get32(buf + 12); - - const UInt32 kResMapSize = 50; - - if (mapSize != kResMapSize - || dataPos > mapPos - || dataSize != mapPos - dataPos - || mapSize > forkSize - || mapPos != forkSize - mapSize) - return S_FALSE; - - const UInt32 dataSize2 = Get32(buf + 0x100); - if (4 + dataSize2 != dataSize - || dataSize2 < 8 - || dataSize2 > dataSize) - return S_FALSE; - - const UInt32 numBlocks = GetUi32(buf + 0x100 + 4); - if (((dataSize2 - 4) >> 3) < numBlocks) - return S_FALSE; - { - const UInt64 up = unpackSize + kCompressionBlockSize - 1; - if (up < unpackSize || up / kCompressionBlockSize != numBlocks) - return S_FALSE; - } - - const UInt32 tableSize = (numBlocks << 3); - - _tableBuf.AllocAtLeast(tableSize); - - RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)) - const Byte *tableBuf = _tableBuf; - - UInt32 prev = 4 + tableSize; - - UInt32 i; - for (i = 0; i < numBlocks; i++) - { - const UInt32 offs = GetUi32(tableBuf + i * 8); - const UInt32 size = GetUi32(tableBuf + i * 8 + 4); - if (size == 0 - || prev != offs - || offs > dataSize2 - || size > dataSize2 - offs) - return S_FALSE; - prev = offs + size; - } - - if (prev != dataSize2) - return S_FALSE; - - CMyComPtr2_Create bufInStream; - - // bool padError = false; - UInt64 outPos = 0; - - for (i = 0; i < numBlocks; i++) - { - const UInt64 rem = unpackSize - outPos; - if (rem == 0) - return S_FALSE; - UInt32 blockSize = kCompressionBlockSize; - if (rem < kCompressionBlockSize) - blockSize = (UInt32)rem; - - const UInt32 size = GetUi32(tableBuf + i * 8 + 4); - - if (size > kCompressionBlockSize + 1) - return S_FALSE; - - RINOK(ReadStream_FALSE(inStream, buf, size)) - - if ((buf[0] & 0xF) == 0xF) - { - // (buf[0] = 0xff) is marker of uncompressed block in APFS - // that code was not tested in HFS - if (size - 1 != blockSize) - return S_FALSE; - - if (outStream) - { - RINOK(WriteStream(outStream, buf + 1, blockSize)) - } - } - else - { - const UInt64 blockSize64 = blockSize; - bufInStream->Init(buf, size); - RINOK(_zlibDecoder.Interface()->Code(bufInStream, outStream, NULL, &blockSize64, NULL)) - if (_zlibDecoder->GetOutputProcessedSize() != blockSize) - return S_FALSE; - const UInt64 inSize = _zlibDecoder->GetInputProcessedSize(); - if (inSize != size) - { - if (inSize > size) - return S_FALSE; - // apfs file can contain junk (non-zeros) after data block. - /* - if (!padError) - { - const Byte *p = buf + (UInt32)inSize; - const Byte *e = p + (size - (UInt32)inSize); - do - { - if (*p != 0) - { - padError = true; - break; - } - } - while (++p != e); - } - */ - } - } - - outPos += blockSize; - if ((i & 0xFF) == 0) - { - const UInt64 progressPos = progressStart + outPos; - RINOK(extractCallback->SetCompleted(&progressPos)) - } - } - - if (outPos != unpackSize) - return S_FALSE; - - // if (padError) return S_FALSE; - - /* We check Resource Map - Are there HFS files with another values in Resource Map ??? */ - - RINOK(ReadStream_FALSE(inStream, buf, mapSize)) - const UInt32 types = Get16(buf + 24); - const UInt32 names = Get16(buf + 26); - const UInt32 numTypes = Get16(buf + 28); - if (numTypes != 0 || types != 28 || names != kResMapSize) - return S_FALSE; - const UInt32 resType = Get32(buf + 30); - const UInt32 numResources = Get16(buf + 34); - const UInt32 resListOffset = Get16(buf + 36); - if (resType != 0x636D7066) // cmpf - return S_FALSE; - if (numResources != 0 || resListOffset != 10) - return S_FALSE; - - const UInt32 entryId = Get16(buf + 38); - const UInt32 nameOffset = Get16(buf + 40); - // Byte attrib = buf[42]; - const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; - if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) - return S_FALSE; - - return S_OK; -} - - - -HRESULT CDecoder::ExtractResourceFork_LZFSE( - ISequentialInStream *inStream, ISequentialOutStream *outStream, - UInt64 forkSize, UInt64 unpackSize, - UInt64 progressStart, IArchiveExtractCallback *extractCallback) -{ - const UInt32 kNumBlocksMax = (UInt32)1 << 29; - if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize) - return S_FALSE; - const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize); - const UInt32 numBlocks2 = numBlocks + 1; - const UInt32 tableSize = (numBlocks2 << 2); - if (tableSize > forkSize) - return S_FALSE; - _tableBuf.AllocAtLeast(tableSize); - RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)) - const Byte *tableBuf = _tableBuf; - - { - UInt32 prev = GetUi32(tableBuf); - if (prev != tableSize) - return S_FALSE; - for (UInt32 i = 1; i < numBlocks2; i++) - { - const UInt32 offs = GetUi32(tableBuf + i * 4); - if (offs <= prev) - return S_FALSE; - prev = offs; - } - if (prev != forkSize) - return S_FALSE; - } - - const size_t kBufSize = kCompressionBlockSize; - _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header - - CMyComPtr2_Create bufInStream; - - UInt64 outPos = 0; - - for (UInt32 i = 0; i < numBlocks; i++) - { - const UInt64 rem = unpackSize - outPos; - if (rem == 0) - return S_FALSE; - UInt32 blockSize = kCompressionBlockSize; - if (rem < kCompressionBlockSize) - blockSize = (UInt32)rem; - - const UInt32 size = - GetUi32(tableBuf + i * 4 + 4) - - GetUi32(tableBuf + i * 4); - - if (size > kCompressionBlockSize + 1) - return S_FALSE; - - RINOK(ReadStream_FALSE(inStream, _buf, size)) - const Byte *buf = _buf; - - if (buf[0] == k_LZVN_Uncompressed_Marker) - { - if (size - 1 != blockSize) - return S_FALSE; - if (outStream) - { - RINOK(WriteStream(outStream, buf + 1, blockSize)) - } - } - else - { - const UInt64 blockSize64 = blockSize; - const UInt64 packSize64 = size; - bufInStream->Init(buf, size); - RINOK(_lzfseDecoder.Interface()->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL)) - // in/out sizes were checked in Code() - } - - outPos += blockSize; - if ((i & 0xFF) == 0) - { - const UInt64 progressPos = progressStart + outPos; - RINOK(extractCallback->SetCompleted(&progressPos)) - } - } - - return S_OK; -} - - -/* -static UInt32 GetUi24(const Byte *p) -{ - return p[0] + ((UInt32)p[1] << 8) + ((UInt32)p[2] << 24); -} - -HRESULT CDecoder::ExtractResourceFork_ZBM( - ISequentialInStream *inStream, ISequentialOutStream *outStream, - UInt64 forkSize, UInt64 unpackSize, - UInt64 progressStart, IArchiveExtractCallback *extractCallback) -{ - const UInt32 kNumBlocksMax = (UInt32)1 << 29; - if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize) - return S_FALSE; - const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize); - const UInt32 numBlocks2 = numBlocks + 1; - const UInt32 tableSize = (numBlocks2 << 2); - if (tableSize > forkSize) - return S_FALSE; - _tableBuf.AllocAtLeast(tableSize); - RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)); - const Byte *tableBuf = _tableBuf; - - { - UInt32 prev = GetUi32(tableBuf); - if (prev != tableSize) - return S_FALSE; - for (UInt32 i = 1; i < numBlocks2; i++) - { - const UInt32 offs = GetUi32(tableBuf + i * 4); - if (offs <= prev) - return S_FALSE; - prev = offs; - } - if (prev != forkSize) - return S_FALSE; - } - - const size_t kBufSize = kCompressionBlockSize; - _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header - - CBufInStream *bufInStream = new CBufInStream; - CMyComPtr bufInStream = bufInStream; - - UInt64 outPos = 0; - - for (UInt32 i = 0; i < numBlocks; i++) - { - const UInt64 rem = unpackSize - outPos; - if (rem == 0) - return S_FALSE; - UInt32 blockSize = kCompressionBlockSize; - if (rem < kCompressionBlockSize) - blockSize = (UInt32)rem; - - const UInt32 size = - GetUi32(tableBuf + i * 4 + 4) - - GetUi32(tableBuf + i * 4); - - // if (size > kCompressionBlockSize + 1) - if (size > blockSize + 1) - return S_FALSE; // we don't expect it, because encode will use uncompressed chunk - - RINOK(ReadStream_FALSE(inStream, _buf, size)); - const Byte *buf = _buf; - - // (size != 0) - // if (size == 0) return S_FALSE; - - if (buf[0] == 0xFF) // uncompressed marker - { - if (size != blockSize + 1) - return S_FALSE; - if (outStream) - { - RINOK(WriteStream(outStream, buf + 1, blockSize)); - } - } - else - { - if (size < 4) - return S_FALSE; - if (buf[0] != 'Z' || - buf[1] != 'B' || - buf[2] != 'M' || - buf[3] != 9) - return S_FALSE; - // for debug: - unsigned packPos = 4; - unsigned unpackPos = 0; - unsigned packRem = size - packPos; - for (;;) - { - if (packRem < 6) - return S_FALSE; - const UInt32 packSize = GetUi24(buf + packPos); - const UInt32 chunkUnpackSize = GetUi24(buf + packPos + 3); - if (packSize < 6) - return S_FALSE; - if (packSize > packRem) - return S_FALSE; - if (chunkUnpackSize > blockSize - unpackPos) - return S_FALSE; - packPos += packSize; - packRem -= packSize; - unpackPos += chunkUnpackSize; - if (packSize == 6) - { - if (chunkUnpackSize != 0) - return S_FALSE; - break; - } - if (packSize >= chunkUnpackSize + 6) - { - if (packSize > chunkUnpackSize + 6) - return S_FALSE; - // uncompressed chunk; - } - else - { - // compressed chunk - const Byte *t = buf + packPos - packSize + 6; - UInt32 r = packSize - 6; - if (r < 9) - return S_FALSE; - const UInt32 v0 = GetUi24(t); - const UInt32 v1 = GetUi24(t + 3); - const UInt32 v2 = GetUi24(t + 6); - if (v0 > v1 || v1 > v2 || v2 > packSize) - return S_FALSE; - // here we need the code that will decompress ZBM chunk - } - } - - if (unpackPos != blockSize) - return S_FALSE; - - UInt32 size1 = size; - if (size1 > kCompressionBlockSize) - { - size1 = kCompressionBlockSize; - // return S_FALSE; - } - if (outStream) - { - RINOK(WriteStream(outStream, buf, size1)) - - const UInt32 kTempSize = 1 << 16; - Byte temp[kTempSize]; - memset(temp, 0, kTempSize); - - for (UInt32 k = size1; k < kCompressionBlockSize; k++) - { - UInt32 cur = kCompressionBlockSize - k; - if (cur > kTempSize) - cur = kTempSize; - RINOK(WriteStream(outStream, temp, cur)) - k += cur; - } - } - - // const UInt64 blockSize64 = blockSize; - // const UInt64 packSize64 = size; - // bufInStream->Init(buf, size); - // RINOK(_zbmDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL)); - // in/out sizes were checked in Code() - } - - outPos += blockSize; - if ((i & 0xFF) == 0) - { - const UInt64 progressPos = progressStart + outPos; - RINOK(extractCallback->SetCompleted(&progressPos)); - } - } - - return S_OK; -} -*/ - -HRESULT CDecoder::Extract( - ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, - UInt64 forkSize, - const CCompressHeader &compressHeader, - const CByteBuffer *data, - UInt64 progressStart, IArchiveExtractCallback *extractCallback, - int &opRes) -{ - opRes = NExtract::NOperationResult::kDataError; - - if (compressHeader.IsMethod_Uncompressed_Inline()) - { - const size_t packSize = data->Size() - compressHeader.DataPos; - if (realOutStream) - { - RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize)) - } - opRes = NExtract::NOperationResult::kOK; - return S_OK; - } - - if (compressHeader.Method == kMethod_ZLIB_ATTR || - compressHeader.Method == kMethod_LZVN_ATTR) - { - CMyComPtr2_Create bufInStream; - const size_t packSize = data->Size() - compressHeader.DataPos; - bufInStream->Init(*data + compressHeader.DataPos, packSize); - - if (compressHeader.Method == kMethod_ZLIB_ATTR) - { - const HRESULT hres = _zlibDecoder.Interface()->Code(bufInStream, realOutStream, - NULL, &compressHeader.UnpackSize, NULL); - if (hres == S_OK) - if (_zlibDecoder->GetOutputProcessedSize() == compressHeader.UnpackSize - && _zlibDecoder->GetInputProcessedSize() == packSize) - opRes = NExtract::NOperationResult::kOK; - return hres; - } - { - const UInt64 packSize64 = packSize; - const HRESULT hres = _lzfseDecoder.Interface()->Code(bufInStream, realOutStream, - &packSize64, &compressHeader.UnpackSize, NULL); - if (hres == S_OK) - { - // in/out sizes were checked in Code() - opRes = NExtract::NOperationResult::kOK; - } - return hres; - } - } - - HRESULT hres; - if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC) - { - hres = ExtractResourceFork_ZLIB( - inStreamFork, realOutStream, - forkSize, compressHeader.UnpackSize, - progressStart, extractCallback); - // for debug: - // hres = NCompress::CopyStream(inStreamFork, realOutStream, NULL); - } - else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC) - { - hres = ExtractResourceFork_LZFSE( - inStreamFork, realOutStream, - forkSize, compressHeader.UnpackSize, - progressStart, extractCallback); - } - /* - else if (compressHeader.Method == NHfs::kMethod_ZBM_RSRC) - { - hres = ExtractResourceFork_ZBM( - inStreamFork, realOutStream, - forkSize, compressHeader.UnpackSize, - progressStart, extractCallback); - } - */ - else - { - opRes = NExtract::NOperationResult::kUnsupportedMethod; - hres = S_FALSE; - } - - if (hres == S_OK) - opRes = NExtract::NOperationResult::kOK; - return hres; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = Refs.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const CRef &ref = Refs[allFilesMode ? i : indices[i]]; - totalSize += Get_UnpackSize_of_Ref(ref); - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 currentTotalSize = 0, currentItemSize = 0; - - const size_t kBufSize = kCompressionBlockSize; - CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header - - // there are hfs without adler in zlib. - CDecoder decoder(true); // IsAdlerOptional - - for (i = 0;; i++, currentTotalSize += currentItemSize) - { - RINOK(extractCallback->SetCompleted(¤tTotalSize)) - if (i >= numItems) - break; - const UInt32 index = allFilesMode ? i : indices[i]; - const CRef &ref = Refs[index]; - const CItem &item = Items[ref.ItemIndex]; - currentItemSize = Get_UnpackSize_of_Ref(ref); - - int opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (ref.IsItem() && item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - - UInt64 pos = 0; - opRes = NExtract::NOperationResult::kDataError; - const CFork *fork = NULL; - - if (ref.AttrIndex >= 0) - { - const CAttr &attr = Attrs[ref.AttrIndex]; - if (attr.Fork_defined && attr.Data.Size() == 0) - fork = &attr.Fork; - else - { - opRes = NExtract::NOperationResult::kOK; - if (realOutStream) - { - RINOK(WriteStream(realOutStream, - // AttrBuf + attr.Pos, attr.Size - attr.Data, attr.Data.Size() - )) - } - } - } - else if (ref.IsResource()) - fork = &item.ResourceFork; - else if (item.CompressHeader.IsSupported) - { - CMyComPtr inStreamFork; - UInt64 forkSize = 0; - const CByteBuffer *decmpfs_Data = NULL; - - if (item.CompressHeader.IsMethod_Resource()) - { - const CFork &resourceFork = item.ResourceFork; - forkSize = resourceFork.Size; - GetForkStream(resourceFork, &inStreamFork); - } - else - { - const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; - decmpfs_Data = &attr.Data; - } - - if (inStreamFork || decmpfs_Data) - { - const HRESULT hres = decoder.Extract( - inStreamFork, realOutStream, - forkSize, - item.CompressHeader, - decmpfs_Data, - currentTotalSize, extractCallback, - opRes); - if (hres != S_FALSE && hres != S_OK) - return hres; - } - } - else if (item.CompressHeader.IsCorrect) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - fork = &item.DataFork; - - if (fork) - { - if (fork->IsOk(Header.BlockSizeLog)) - { - opRes = NExtract::NOperationResult::kOK; - unsigned extentIndex; - for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++) - { - if (opRes != NExtract::NOperationResult::kOK) - break; - if (fork->Size == pos) - break; - const CExtent &e = fork->Extents[extentIndex]; - RINOK(InStream_SeekSet(_stream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog))) - UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; - while (extentRem != 0) - { - const UInt64 rem = fork->Size - pos; - if (rem == 0) - { - // Here we check that there are no extra (empty) blocks in last extent. - if (extentRem >= ((UInt64)1 << Header.BlockSizeLog)) - opRes = NExtract::NOperationResult::kDataError; - break; - } - size_t cur = kBufSize; - if (cur > rem) - cur = (size_t)rem; - if (cur > extentRem) - cur = (size_t)extentRem; - RINOK(ReadStream(_stream, buf, &cur)) - if (cur == 0) - { - opRes = NExtract::NOperationResult::kDataError; - break; - } - if (realOutStream) - { - RINOK(WriteStream(realOutStream, buf, cur)) - } - pos += cur; - extentRem -= cur; - const UInt64 processed = currentTotalSize + pos; - RINOK(extractCallback->SetCompleted(&processed)) - } - } - if (extentIndex != fork->Extents.Size() || fork->Size != pos) - opRes = NExtract::NOperationResult::kDataError; - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = Refs.Size(); - return S_OK; -} - -HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream) -{ - *stream = NULL; - - if (!fork.IsOk(Header.BlockSizeLog)) - return S_FALSE; - - CMyComPtr2 extentStream; - extentStream.Create_if_Empty(); - - UInt64 rem = fork.Size; - UInt64 virt = 0; - - FOR_VECTOR (i, fork.Extents) - { - const CExtent &e = fork.Extents[i]; - if (e.NumBlocks == 0) - continue; - UInt64 cur = ((UInt64)e.NumBlocks << Header.BlockSizeLog); - if (cur > rem) - { - cur = rem; - if (i != fork.Extents.Size() - 1) - return S_FALSE; - } - CSeekExtent se; - se.Phy = (UInt64)e.Pos << Header.BlockSizeLog; - se.Virt = virt; - virt += cur; - rem -= cur; - extentStream->Extents.Add(se); - } - - if (rem != 0) - return S_FALSE; - - CSeekExtent se; - se.Phy = 0; - se.Virt = virt; - extentStream->Extents.Add(se); - extentStream->Stream = _stream; - extentStream->Init(); - *stream = extentStream.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - *stream = NULL; - - const CRef &ref = Refs[index]; - const CFork *fork = NULL; - if (ref.AttrIndex >= 0) - { - const CAttr &attr = Attrs[ref.AttrIndex]; - if (!attr.Fork_defined || attr.Data.Size() != 0) - return S_FALSE; - fork = &attr.Fork; - } - else - { - const CItem &item = Items[ref.ItemIndex]; - if (ref.IsResource()) - fork = &item.ResourceFork; - else if (item.IsDir()) - return S_FALSE; - else if (item.CompressHeader.IsCorrect) - return S_FALSE; - else - fork = &item.DataFork; - } - return GetForkStream(*fork, stream); -} - -static const Byte k_Signature[] = { - 2, 'B', 'D', - 4, 'H', '+', 0, 4, - 4, 'H', 'X', 0, 5 }; - -REGISTER_ARC_I( - "HFS", "hfs hfsx", NULL, 0xE3, - k_Signature, - kHeaderPadSize, - NArcInfoFlags::kMultiSignature, - IsArc_HFS) - -}} +// HfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "HfsHandler.h" + +/* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files + and resource forks. In most cases it looks useless. So we disable it. */ + +#define HFS_SHOW_ALT_STREAMS + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +#define Get16a(p) GetBe16a(p) +#define Get32a(p) GetBe32a(p) + +namespace NArchive { +namespace NHfs { + +static const char * const kResFileName = "rsrc"; // "com.apple.ResourceFork"; + +struct CExtent +{ + UInt32 Pos; + UInt32 NumBlocks; +}; + +struct CIdExtents +{ + UInt32 ID; + UInt32 StartBlock; + CRecordVector Extents; +}; + +struct CFork +{ + UInt64 Size; + UInt32 NumBlocks; + // UInt32 ClumpSize; + CRecordVector Extents; + + CFork(): Size(0), NumBlocks(0) {} + + void Parse(const Byte *p); + + bool IsEmpty() const { return Size == 0 && NumBlocks == 0 && Extents.Size() == 0; } + + UInt32 Calc_NumBlocks_from_Extents() const; + bool Check_NumBlocks() const; + + bool Check_Size_with_NumBlocks(unsigned blockSizeLog) const + { + return Size <= ((UInt64)NumBlocks << blockSizeLog); + } + + bool IsOk(unsigned blockSizeLog) const + { + // we don't check cases with extra (empty) blocks in last extent + return Check_NumBlocks() && Check_Size_with_NumBlocks(blockSizeLog); + } + + bool Upgrade(const CObjectVector &items, UInt32 id); + bool UpgradeAndTest(const CObjectVector &items, UInt32 id, unsigned blockSizeLog) + { + if (!Upgrade(items, id)) + return false; + return IsOk(blockSizeLog); + } +}; + +static const unsigned kNumFixedExtents = 8; +static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; + + +void CFork::Parse(const Byte *p) +{ + Extents.Clear(); + Size = Get64(p); + // ClumpSize = Get32(p + 8); + NumBlocks = Get32(p + 12); + p += 16; + for (unsigned i = 0; i < kNumFixedExtents; i++, p += 8) + { + CExtent e; + e.Pos = Get32(p); + e.NumBlocks = Get32(p + 4); + if (e.NumBlocks != 0) + Extents.Add(e); + } +} + +UInt32 CFork::Calc_NumBlocks_from_Extents() const +{ + UInt32 num = 0; + FOR_VECTOR (i, Extents) + num += Extents[i].NumBlocks; + return num; +} + +bool CFork::Check_NumBlocks() const +{ + UInt32 num = NumBlocks; + FOR_VECTOR (i, Extents) + { + const UInt32 cur = Extents[i].NumBlocks; + if (num < cur) + return false; + num -= cur; + } + return num == 0; +} + +struct CIdIndexPair +{ + UInt32 ID; + unsigned Index; + + int Compare(const CIdIndexPair &a) const; +}; + +#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; } + +int CIdIndexPair::Compare(const CIdIndexPair &a) const +{ + RINOZ(MyCompare(ID, a.ID)) + return MyCompare(Index, a.Index); +} + +static int FindItemIndex(const CRecordVector &items, UInt32 id) +{ + unsigned left = 0, right = items.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const UInt32 midVal = items[mid].ID; + if (id == midVal) + return (int)items[mid].Index; + if (id < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int Find_in_IdExtents(const CObjectVector &items, UInt32 id) +{ + unsigned left = 0, right = items.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const UInt32 midVal = items[mid].ID; + if (id == midVal) + return (int)mid; + if (id < midVal) + right = mid; + else + left = mid + 1; + } + return -1; +} + +bool CFork::Upgrade(const CObjectVector &items, UInt32 id) +{ + const int index = Find_in_IdExtents(items, id); + if (index < 0) + return true; + const CIdExtents &item = items[index]; + if (Calc_NumBlocks_from_Extents() != item.StartBlock) + return false; + Extents += item.Extents; + return true; +} + + +struct CVolHeader +{ + unsigned BlockSizeLog; + UInt32 NumFiles; + UInt32 NumFolders; + UInt32 NumBlocks; + UInt32 NumFreeBlocks; + + bool Is_Hsfx_ver5; + // UInt32 Attr; + // UInt32 LastMountedVersion; + // UInt32 JournalInfoBlock; + + UInt32 CTime; + UInt32 MTime; + // UInt32 BackupTime; + // UInt32 CheckedTime; + + // UInt32 WriteCount; + // UInt32 FinderInfo[8]; + // UInt64 VolID; + + UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; } + UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; } + bool IsHfsX() const { return Is_Hsfx_ver5; } +}; + +inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft) +{ + UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +enum ERecordType +{ + RECORD_TYPE_FOLDER = 1, + RECORD_TYPE_FILE, + RECORD_TYPE_FOLDER_THREAD, + RECORD_TYPE_FILE_THREAD +}; + + + +// static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr +static const UInt32 kMethod_ZLIB_ATTR = 3; +static const UInt32 kMethod_ZLIB_RSRC = 4; +// static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store +// macos 10.10 +static const UInt32 kMethod_LZVN_ATTR = 7; +static const UInt32 kMethod_LZVN_RSRC = 8; +static const UInt32 kMethod_COPY_ATTR = 9; +static const UInt32 kMethod_COPY_RSRC = 10; +// macos 10.11 +// static const UInt32 kMethod_LZFSE_ATTR = 11; +static const UInt32 kMethod_LZFSE_RSRC = 12; + +// static const UInt32 kMethod_ZBM_RSRC = 14; + +static const char * const g_Methods[] = +{ + NULL + , NULL + , NULL + , "ZLIB-attr" + , "ZLIB-rsrc" + , NULL + , NULL + , "LZVN-attr" + , "LZVN-rsrc" + , "COPY-attr" + , "COPY-rsrc" + , "LZFSE-attr" + , "LZFSE-rsrc" + , NULL + , "ZBM-rsrc" +}; + + +static const Byte k_COPY_Uncompressed_Marker = 0xcc; +static const Byte k_LZVN_Uncompressed_Marker = 6; + +void CCompressHeader::Parse(const Byte *p, size_t dataSize) +{ + Clear(); + + if (dataSize < k_decmpfs_HeaderSize) + return; + if (GetUi32(p) != 0x636D7066) // magic == "fpmc" + return; + Method = GetUi32(p + 4); + UnpackSize = GetUi64(p + 8); + dataSize -= k_decmpfs_HeaderSize; + IsCorrect = true; + + if ( Method == kMethod_ZLIB_RSRC + || Method == kMethod_COPY_RSRC + || Method == kMethod_LZVN_RSRC + || Method == kMethod_LZFSE_RSRC + // || Method == kMethod_ZBM_RSRC // for debug + ) + { + IsResource = true; + if (dataSize == 0) + IsSupported = ( + Method != kMethod_LZFSE_RSRC && + Method != kMethod_COPY_RSRC); + return; + } + + if ( Method == kMethod_ZLIB_ATTR + || Method == kMethod_COPY_ATTR + || Method == kMethod_LZVN_ATTR + // || Method == kMethod_LZFSE_ATTR + ) + { + if (dataSize == 0) + return; + const Byte b = p[k_decmpfs_HeaderSize]; + if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf) + || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker) + || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker)) + { + dataSize--; + // if (UnpackSize > dataSize) + if (UnpackSize != dataSize) + return; + DataPos = k_decmpfs_HeaderSize + 1; + IsSupported = true; + } + else + { + if (Method != kMethod_COPY_ATTR) + IsSupported = true; + DataPos = k_decmpfs_HeaderSize; + } + } +} + + +void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const +{ + if (!IsCorrect) + return; + const UInt32 method = Method; + const char *p = NULL; + if (method < Z7_ARRAY_SIZE(g_Methods)) + p = g_Methods[method]; + AString s; + if (p) + s = p; + else + s.Add_UInt32(method); + // if (!IsSupported) s += "-unsuported"; + prop = s; +} + +void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop) +{ + FLAGS_TO_PROP(g_Methods, methodsMask, prop); +} + + +struct CItem +{ + UString Name; + + UInt32 ParentID; + + UInt16 Type; + UInt16 FileMode; + // UInt16 Flags; + // UInt32 Valence; + UInt32 ID; + UInt32 CTime; + UInt32 MTime; + UInt32 AttrMTime; + UInt32 ATime; + // UInt32 BackupDate; + + /* + UInt32 OwnerID; + UInt32 GroupID; + Byte AdminFlags; + Byte OwnerFlags; + union + { + UInt32 iNodeNum; + UInt32 LinkCount; + UInt32 RawDevice; + } special; + + UInt32 FileType; + UInt32 FileCreator; + UInt16 FinderFlags; + UInt16 Point[2]; + */ + + CFork DataFork; + CFork ResourceFork; + + // for compressed attribute (decmpfs) + int decmpfs_AttrIndex; + CCompressHeader CompressHeader; + + CItem(): + decmpfs_AttrIndex(-1) + {} + bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } + // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); } +}; + + +struct CAttr +{ + UInt32 ID; + bool Fork_defined; + + // UInt32 Size; // for (Fork_defined == false) case + // size_t DataPos; // for (Fork_defined == false) case + CByteBuffer Data; + + CFork Fork; + + UString Name; + + UInt64 GetSize() const + { + if (Fork_defined) + return Fork.Size; + return Data.Size(); + } + + CAttr(): + Fork_defined(false) + // Size(0), + // DataPos(0), + {} +}; + + +static const int kAttrIndex_Item = -1; +static const int kAttrIndex_Resource = -2; + +struct CRef +{ + unsigned ItemIndex; + int AttrIndex; + int Parent; + + CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {} + bool IsResource() const { return AttrIndex == kAttrIndex_Resource; } + bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; } + bool IsItem() const { return AttrIndex == kAttrIndex_Item; } +}; + + +class CDatabase +{ + HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); + HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray); + HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); + HRESULT LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); + bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip); +public: + CRecordVector Refs; + CObjectVector Items; + CObjectVector Attrs; + + // CByteBuffer AttrBuf; + + CVolHeader Header; + bool HeadersError; + bool UnsupportedFeature; + bool ThereAreAltStreams; + // bool CaseSensetive; + UInt32 MethodsMask; + UString ResFileName; + + UInt64 SpecOffset; + // UInt64 PhySize; + UInt64 PhySize2; + UInt64 ArcFileSize; + + void Clear() + { + SpecOffset = 0; + // PhySize = 0; + PhySize2 = 0; + ArcFileSize = 0; + MethodsMask = 0; + HeadersError = false; + UnsupportedFeature = false; + ThereAreAltStreams = false; + // CaseSensetive = false; + + Refs.Clear(); + Items.Clear(); + Attrs.Clear(); + // AttrBuf.Free(); + } + + UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const + { + if (ref.AttrIndex >= 0) + return Attrs[ref.AttrIndex].GetSize(); + const CItem &item = Items[ref.ItemIndex]; + if (ref.IsResource()) + return item.ResourceFork.Size; + if (item.IsDir()) + return 0; + else if (item.CompressHeader.IsCorrect) + return item.CompressHeader.UnpackSize; + return item.DataFork.Size; + } + + void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const; + HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *progress); +}; + +enum +{ + kHfsID_Root = 1, + kHfsID_RootFolder = 2, + kHfsID_ExtentsFile = 3, + kHfsID_CatalogFile = 4, + kHfsID_BadBlockFile = 5, + kHfsID_AllocationFile = 6, + kHfsID_StartupFile = 7, + kHfsID_AttributesFile = 8, + kHfsID_RepairCatalogFile = 14, + kHfsID_BogusExtentFile = 15, + kHfsID_FirstUserCatalogNode = 16 +}; + +void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const +{ + unsigned len = 0; + const unsigned kNumLevelsMax = (1 << 10); + unsigned cur = index; + unsigned i; + + for (i = 0; i < kNumLevelsMax; i++) + { + const CRef &ref = Refs[cur]; + const UString *s; + + if (ref.IsResource()) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + s = &Items[ref.ItemIndex].Name; + + len += s->Len(); + len++; + cur = (unsigned)ref.Parent; + if (ref.Parent < 0) + break; + } + + len--; + wchar_t *p = path.AllocBstr(len); + p[len] = 0; + cur = index; + + for (;;) + { + const CRef &ref = Refs[cur]; + const UString *s; + wchar_t delimChar = L':'; + + if (ref.IsResource()) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + { + delimChar = WCHAR_PATH_SEPARATOR; + s = &Items[ref.ItemIndex].Name; + } + + unsigned curLen = s->Len(); + len -= curLen; + + const wchar_t *src = (const wchar_t *)*s; + wchar_t *dest = p + len; + for (unsigned j = 0; j < curLen; j++) + { + wchar_t c = src[j]; + // 18.06 + if (c == CHAR_PATH_SEPARATOR || c == '/') + c = '_'; + dest[j] = c; + } + + if (len == 0) + break; + p[--len] = delimChar; + cur = (unsigned)ref.Parent; + } +} + +// Actually we read all blocks. It can be larger than fork.Size + +HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream) +{ + if (fork.NumBlocks >= Header.NumBlocks) + return S_FALSE; + if (((ArcFileSize - SpecOffset) >> Header.BlockSizeLog) + 1 < fork.NumBlocks) + return S_FALSE; + + const size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog; + if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks) + return S_FALSE; + buf.Alloc(totalSize); + UInt32 curBlock = 0; + FOR_VECTOR (i, fork.Extents) + { + if (curBlock >= fork.NumBlocks) + return S_FALSE; + const CExtent &e = fork.Extents[i]; + if (e.Pos > Header.NumBlocks || + e.NumBlocks > fork.NumBlocks - curBlock || + e.NumBlocks > Header.NumBlocks - e.Pos) + return S_FALSE; + RINOK(InStream_SeekSet(inStream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog))) + RINOK(ReadStream_FALSE(inStream, + (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog), + (size_t)e.NumBlocks << Header.BlockSizeLog)) + curBlock += e.NumBlocks; + } + return S_OK; +} + +static const unsigned kNodeDescriptor_Size = 14; + +struct CNodeDescriptor +{ + UInt32 fLink; + // UInt32 bLink; + Byte Kind; + // Byte Height; + unsigned NumRecords; + + bool Parse(const Byte *p, unsigned nodeSizeLog); +}; + + +bool CNodeDescriptor::Parse(const Byte *p, unsigned nodeSizeLog) +{ + fLink = Get32(p); + // bLink = Get32(p + 4); + Kind = p[8]; + // Height = p[9]; + NumRecords = Get16(p + 10); + + const size_t nodeSize = (size_t)1 << nodeSizeLog; + if (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 > nodeSize) + return false; + const size_t limit = nodeSize - ((UInt32)NumRecords + 1) * 2; + + p += nodeSize - 2; + + for (unsigned i = 0; i < NumRecords; i++) + { + const UInt32 offs = Get16(p); + p -= 2; + const UInt32 offsNext = Get16(p); + if (offs < kNodeDescriptor_Size + || offs >= offsNext + || offsNext > limit) + return false; + } + return true; +} + +struct CHeaderRec +{ + // UInt16 TreeDepth; + // UInt32 RootNode; + // UInt32 LeafRecords; + UInt32 FirstLeafNode; + // UInt32 LastLeafNode; + unsigned NodeSizeLog; + // UInt16 MaxKeyLength; + UInt32 TotalNodes; + // UInt32 FreeNodes; + // UInt16 Reserved1; + // UInt32 ClumpSize; + // Byte BtreeType; + // Byte KeyCompareType; + // UInt32 Attributes; + // UInt32 Reserved3[16]; + + HRESULT Parse2(const CByteBuffer &buf); +}; + +HRESULT CHeaderRec::Parse2(const CByteBuffer &buf) +{ + if (buf.Size() < kNodeDescriptor_Size + 0x2A + 16 * 4) + return S_FALSE; + const Byte * p = (const Byte *)buf + kNodeDescriptor_Size; + // TreeDepth = Get16(p); + // RootNode = Get32(p + 2); + // LeafRecords = Get32(p + 6); + FirstLeafNode = Get32(p + 0xA); + // LastLeafNode = Get32(p + 0xE); + const UInt32 nodeSize = Get16(p + 0x12); + + unsigned i; + for (i = 9; ((UInt32)1 << i) != nodeSize; i++) + if (i == 16) + return S_FALSE; + NodeSizeLog = i; + + // MaxKeyLength = Get16(p + 0x14); + TotalNodes = Get32(p + 0x16); + // FreeNodes = Get32(p + 0x1A); + // Reserved1 = Get16(p + 0x1E); + // ClumpSize = Get32(p + 0x20); + // BtreeType = p[0x24]; + // KeyCompareType = p[0x25]; + // Attributes = Get32(p + 0x26); + /* + for (int i = 0; i < 16; i++) + Reserved3[i] = Get32(p + 0x2A + i * 4); + */ + + if ((buf.Size() >> NodeSizeLog) < TotalNodes) + return S_FALSE; + + return S_OK; +} + + +static const Byte kNodeType_Leaf = 0xFF; +// static const Byte kNodeType_Index = 0; +// static const Byte kNodeType_Header = 1; +// static const Byte kNodeType_Mode = 2; + +static const Byte kExtentForkType_Data = 0; +static const Byte kExtentForkType_Resource = 0xFF; + +/* It loads data extents from Extents Overflow File + Most dmg installers are not fragmented. So there are no extents in Overflow File. */ + +HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray) +{ + if (fork.NumBlocks == 0) + return S_OK; + CByteBuffer buf; + RINOK(ReadFile(fork, buf, inStream)) + const Byte *p = (const Byte *)buf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + RINOK(hr.Parse2(buf)) + + UInt32 node = hr.FirstLeafNode; + if (node == 0) + return S_OK; + if (hr.TotalNodes == 0) + return S_FALSE; + + CByteArr usedBuf(hr.TotalNodes); + memset(usedBuf, 0, hr.TotalNodes); + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + const size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog)) + return S_FALSE; + if (desc.Kind != kNodeType_Leaf) + return S_FALSE; + + UInt32 endBlock = 0; + + for (unsigned i = 0; i < desc.NumRecords; i++) + { + const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); + const Byte *r = p + nodeOffset + nodeSize - i * 2; + const UInt32 offs = Get16(r - 2); + UInt32 recSize = Get16(r - 4) - offs; + const unsigned kKeyLen = 10; + + if (recSize != 2 + kKeyLen + kNumFixedExtents * 8) + return S_FALSE; + + r = p + nodeOffset + offs; + if (Get16(r) != kKeyLen) + return S_FALSE; + + const Byte forkType = r[2]; + unsigned forkTypeIndex; + if (forkType == kExtentForkType_Data) + forkTypeIndex = 0; + else if (forkType == kExtentForkType_Resource) + forkTypeIndex = 1; + else + continue; + CObjectVector &overflowExtents = overflowExtentsArray[forkTypeIndex]; + + const UInt32 id = Get32(r + 4); + const UInt32 startBlock = Get32(r + 8); + r += 2 + kKeyLen; + + bool needNew = true; + + if (overflowExtents.Size() != 0) + { + CIdExtents &e = overflowExtents.Back(); + if (e.ID == id) + { + if (endBlock != startBlock) + return S_FALSE; + needNew = false; + } + } + + if (needNew) + { + CIdExtents &e = overflowExtents.AddNew(); + e.ID = id; + e.StartBlock = startBlock; + endBlock = startBlock; + } + + CIdExtents &e = overflowExtents.Back(); + + for (unsigned k = 0; k < kNumFixedExtents; k++, r += 8) + { + CExtent ee; + ee.Pos = Get32(r); + ee.NumBlocks = Get32(r + 4); + if (ee.NumBlocks != 0) + { + e.Extents.Add(ee); + endBlock += ee.NumBlocks; + } + } + } + + node = desc.fLink; + } + return S_OK; +} + +static void LoadName(const Byte *data, unsigned len, UString &dest) +{ + wchar_t *p = dest.GetBuf(len); + unsigned i; + for (i = 0; i < len; i++) + { + const wchar_t c = Get16(data + i * 2); + if (c == 0) + break; + p[i] = c; + } + p[i] = 0; + dest.ReleaseBuf_SetLen(i); +} + +static bool IsNameEqualTo(const Byte *data, const char *name) +{ + for (unsigned i = 0;; i++) + { + const char c = name[i]; + if (c == 0) + return true; + if (Get16(data + i * 2) != (Byte)c) + return false; + } +} + +static const UInt32 kAttrRecordType_Inline = 0x10; +static const UInt32 kAttrRecordType_Fork = 0x20; +// static const UInt32 kAttrRecordType_Extents = 0x30; + +HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress) +{ + if (fork.NumBlocks == 0) + return S_OK; + + CByteBuffer AttrBuf; + RINOK(ReadFile(fork, AttrBuf, inStream)) + const Byte *p = (const Byte *)AttrBuf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + RINOK(hr.Parse2(AttrBuf)) + + // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); + + UInt32 node = hr.FirstLeafNode; + if (node == 0) + return S_OK; + if (hr.TotalNodes == 0) + return S_FALSE; + + CByteArr usedBuf(hr.TotalNodes); + memset(usedBuf, 0, hr.TotalNodes); + + CFork resFork; + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + const size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog)) + return S_FALSE; + if (desc.Kind != kNodeType_Leaf) + return S_FALSE; + + for (unsigned i = 0; i < desc.NumRecords; i++) + { + const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); + const Byte *r = p + nodeOffset + nodeSize - i * 2; + const UInt32 offs = Get16(r - 2); + UInt32 recSize = Get16(r - 4) - offs; + const unsigned kHeadSize = 14; + if (recSize < kHeadSize) + return S_FALSE; + + r = p + nodeOffset + offs; + const UInt32 keyLen = Get16(r); + + // UInt16 pad = Get16(r + 2); + const UInt32 fileID = Get32(r + 4); + const unsigned startBlock = Get32(r + 8); + if (startBlock != 0) + { + // that case is still unsupported + UnsupportedFeature = true; + continue; + } + const unsigned nameLen = Get16(r + 12); + + if (keyLen + 2 > recSize || + keyLen != kHeadSize - 2 + nameLen * 2) + return S_FALSE; + r += kHeadSize; + recSize -= kHeadSize; + + const Byte *name = r; + r += nameLen * 2; + recSize -= nameLen * 2; + + if (recSize < 4) + return S_FALSE; + + const UInt32 recordType = Get32(r); + + if (progress && (Attrs.Size() & 0xFFF) == 0) + { + const UInt64 numFiles = 0; + RINOK(progress->SetCompleted(&numFiles, NULL)) + } + + if (Attrs.Size() >= ((UInt32)1 << 31)) + return S_FALSE; + + CAttr &attr = Attrs.AddNew(); + attr.ID = fileID; + LoadName(name, nameLen, attr.Name); + + if (recordType == kAttrRecordType_Fork) + { + // 22.00 : some hfs files contain it; + /* spec: If the attribute has more than 8 extents, there will be additional + records (of type kAttrRecordType_Extents) for this attribute. */ + if (recSize != 8 + kForkRecSize) + return S_FALSE; + if (Get32(r + 4) != 0) // reserved + return S_FALSE; + attr.Fork.Parse(r + 8); + attr.Fork_defined = true; + continue; + } + else if (recordType != kAttrRecordType_Inline) + { + UnsupportedFeature = true; + continue; + } + + const unsigned kRecordHeaderSize = 16; + if (recSize < kRecordHeaderSize) + return S_FALSE; + if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved + return S_FALSE; + const UInt32 dataSize = Get32(r + 12); + + r += kRecordHeaderSize; + recSize -= kRecordHeaderSize; + + if (recSize < dataSize) + return S_FALSE; + + attr.Data.CopyFrom(r, dataSize); + // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; + // attr.Size = dataSize; + } + + node = desc.fLink; + } + return S_OK; +} + + +bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip) +{ + const CAttr &attr = Attrs[attrIndex]; + skip = false; + if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty()) + return false; + + item.CompressHeader.Parse(attr.Data, attr.Data.Size()); + + if (item.CompressHeader.IsCorrect) + { + item.decmpfs_AttrIndex = (int)attrIndex; + skip = true; + if (item.CompressHeader.Method < sizeof(MethodsMask) * 8) + MethodsMask |= ((UInt32)1 << item.CompressHeader.Method); + } + + return true; +} + + +HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) +{ + CByteBuffer buf; + RINOK(ReadFile(fork, buf, inStream)) + const Byte *p = (const Byte *)buf; + + // CNodeDescriptor nodeDesc; + // nodeDesc.Parse(p); + CHeaderRec hr; + RINOK(hr.Parse2(buf)) + + CRecordVector IdToIndexMap; + + const unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles); + + const unsigned kBasicRecSize = 0x58; + const unsigned kMinRecSize = kBasicRecSize + 10; + + if ((UInt64)reserveSize * kMinRecSize < buf.Size()) + { + Items.ClearAndReserve(reserveSize); + Refs.ClearAndReserve(reserveSize); + IdToIndexMap.ClearAndReserve(reserveSize); + } + + // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); + + CByteArr usedBuf(hr.TotalNodes); + if (hr.TotalNodes != 0) + memset(usedBuf, 0, hr.TotalNodes); + + CFork resFork; + + UInt32 node = hr.FirstLeafNode; + UInt32 numFiles = 0; + UInt32 numFolders = 0; + + while (node != 0) + { + if (node >= hr.TotalNodes || usedBuf[node] != 0) + return S_FALSE; + usedBuf[node] = 1; + + const size_t nodeOffset = (size_t)node << hr.NodeSizeLog; + CNodeDescriptor desc; + if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog)) + return S_FALSE; + if (desc.Kind != kNodeType_Leaf) + return S_FALSE; + + for (unsigned i = 0; i < desc.NumRecords; i++) + { + const UInt32 nodeSize = (1 << hr.NodeSizeLog); + const Byte *r = p + nodeOffset + nodeSize - i * 2; + const UInt32 offs = Get16(r - 2); + UInt32 recSize = Get16(r - 4) - offs; + if (recSize < 6) + return S_FALSE; + + r = p + nodeOffset + offs; + UInt32 keyLen = Get16(r); + UInt32 parentID = Get32(r + 2); + if (keyLen < 6 || (keyLen & 1) != 0 || keyLen + 2 > recSize) + return S_FALSE; + r += 6; + recSize -= 6; + keyLen -= 6; + + unsigned nameLen = Get16(r); + if (nameLen * 2 != (unsigned)keyLen) + return S_FALSE; + r += 2; + recSize -= 2; + + r += nameLen * 2; + recSize -= nameLen * 2; + + if (recSize < 2) + return S_FALSE; + UInt16 type = Get16(r); + + if (type != RECORD_TYPE_FOLDER && + type != RECORD_TYPE_FILE) + continue; + + if (recSize < kBasicRecSize) + return S_FALSE; + + CItem &item = Items.AddNew(); + item.ParentID = parentID; + item.Type = type; + // item.Flags = Get16(r + 2); + // item.Valence = Get32(r + 4); + item.ID = Get32(r + 8); + { + const Byte *name = r - (nameLen * 2); + LoadName(name, nameLen, item.Name); + if (item.Name.Len() <= 1) + { + if (item.Name.IsEmpty() && nameLen == 21) + { + if (GetUi32(name) == 0 && + GetUi32(name + 4) == 0 && + IsNameEqualTo(name + 8, "HFS+ Private Data")) + { + // it's folder for "Hard Links" files + item.Name = "[HFS+ Private Data]"; + } + } + + // Some dmg files have ' ' folder item. + if (item.Name.IsEmpty() || item.Name[0] == L' ') + item.Name = "[]"; + } + } + + item.CTime = Get32(r + 0xC); + item.MTime = Get32(r + 0x10); + item.AttrMTime = Get32(r + 0x14); + item.ATime = Get32(r + 0x18); + // item.BackupDate = Get32(r + 0x1C); + + /* + item.OwnerID = Get32(r + 0x20); + item.GroupID = Get32(r + 0x24); + item.AdminFlags = r[0x28]; + item.OwnerFlags = r[0x29]; + */ + item.FileMode = Get16(r + 0x2A); + /* + item.special.iNodeNum = Get16(r + 0x2C); // or .linkCount + item.FileType = Get32(r + 0x30); + item.FileCreator = Get32(r + 0x34); + item.FinderFlags = Get16(r + 0x38); + item.Point[0] = Get16(r + 0x3A); // v + item.Point[1] = Get16(r + 0x3C); // h + */ + + // const refIndex = Refs.Size(); + CIdIndexPair pair; + pair.ID = item.ID; + pair.Index = Items.Size() - 1; + IdToIndexMap.Add(pair); + + recSize -= kBasicRecSize; + r += kBasicRecSize; + if (item.IsDir()) + { + numFolders++; + if (recSize != 0) + return S_FALSE; + } + else + { + numFiles++; + if (recSize != kForkRecSize * 2) + return S_FALSE; + + item.DataFork.Parse(r); + + if (!item.DataFork.UpgradeAndTest(overflowExtentsArray[0], item.ID, Header.BlockSizeLog)) + HeadersError = true; + + item.ResourceFork.Parse(r + kForkRecSize); + if (!item.ResourceFork.IsEmpty()) + { + if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog)) + HeadersError = true; + // ThereAreAltStreams = true; + } + } + if (progress && (Items.Size() & 0xFFF) == 0) + { + const UInt64 numItems = Items.Size(); + RINOK(progress->SetCompleted(&numItems, NULL)) + } + } + node = desc.fLink; + } + + if (Header.NumFiles != numFiles || + Header.NumFolders + 1 != numFolders) + HeadersError = true; + + IdToIndexMap.Sort2(); + { + for (unsigned i = 1; i < IdToIndexMap.Size(); i++) + if (IdToIndexMap[i - 1].ID == IdToIndexMap[i].ID) + return S_FALSE; + } + + + CBoolArr skipAttr(Attrs.Size()); + { + for (unsigned i = 0; i < Attrs.Size(); i++) + skipAttr[i] = false; + } + + { + FOR_VECTOR (i, Attrs) + { + const CAttr &attr = Attrs[i]; + + const int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); + if (itemIndex < 0) + { + HeadersError = true; + continue; + } + + if (attr.Name.IsEqualTo("com.apple.decmpfs")) + { + if (!Parse_decmpgfs(i, Items[itemIndex], skipAttr[i])) + HeadersError = true; + } + } + } + + IdToIndexMap.ClearAndReserve(Items.Size()); + + { + FOR_VECTOR (i, Items) + { + const CItem &item = Items[i]; + + CIdIndexPair pair; + pair.ID = item.ID; + pair.Index = Refs.Size(); + IdToIndexMap.Add(pair); + + CRef ref; + ref.ItemIndex = i; + Refs.Add(ref); + + #ifdef HFS_SHOW_ALT_STREAMS + + if (item.ResourceFork.IsEmpty()) + continue; + if (item.CompressHeader.IsSupported && item.CompressHeader.IsMethod_Resource()) + continue; + + ThereAreAltStreams = true; + ref.AttrIndex = kAttrIndex_Resource; + ref.Parent = (int)(Refs.Size() - 1); + Refs.Add(ref); + + #endif + } + } + + IdToIndexMap.Sort2(); + + { + FOR_VECTOR (i, Refs) + { + CRef &ref = Refs[i]; + if (ref.IsResource()) + continue; + const CItem &item = Items[ref.ItemIndex]; + ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID); + if (ref.Parent >= 0) + { + if (!Items[Refs[ref.Parent].ItemIndex].IsDir()) + { + ref.Parent = -1; + HeadersError = true; + } + } + } + } + + #ifdef HFS_SHOW_ALT_STREAMS + { + FOR_VECTOR (i, Attrs) + { + if (skipAttr[i]) + continue; + const CAttr &attr = Attrs[i]; + + const int refIndex = FindItemIndex(IdToIndexMap, attr.ID); + if (refIndex < 0) + { + HeadersError = true; + continue; + } + + ThereAreAltStreams = true; + + CRef ref; + ref.AttrIndex = (int)i; + ref.Parent = refIndex; + ref.ItemIndex = Refs[refIndex].ItemIndex; + Refs.Add(ref); + } + } + #endif + + return S_OK; +} + +static const unsigned kHeaderPadSize = 1 << 10; +static const unsigned kMainHeaderSize = 512; +static const unsigned kHfsHeaderSize = kHeaderPadSize + kMainHeaderSize; + +static const unsigned k_Signature_LE16_HFS_BD = 'B' + ((unsigned)'D' << 8); +static const unsigned k_Signature_LE16_HPLUS = 'H' + ((unsigned)'+' << 8); +static const UInt32 k_Signature_LE32_HFSP_VER4 = 'H' + ((UInt32)'+' << 8) + ((UInt32)4 << 24); +static const UInt32 k_Signature_LE32_HFSX_VER5 = 'H' + ((UInt32)'X' << 8) + ((UInt32)5 << 24); + +API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size) +{ + if (size < kHfsHeaderSize) + return k_IsArc_Res_NEED_MORE; + p += kHeaderPadSize; + const UInt32 sig = GetUi32(p); + if (sig != k_Signature_LE32_HFSP_VER4) + if (sig != k_Signature_LE32_HFSX_VER5) + if ((UInt16)sig != k_Signature_LE16_HFS_BD + || GetUi16(p + 0x7c) != k_Signature_LE16_HPLUS) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) +{ + Clear(); + UInt32 buf32[kHfsHeaderSize / 4]; + RINOK(ReadStream_FALSE(inStream, buf32, kHfsHeaderSize)) + const Byte *p = (const Byte *)buf32 + kHeaderPadSize; + CVolHeader &h = Header; + + if (GetUi16a(p) == k_Signature_LE16_HFS_BD) + { + /* + It's header for old HFS format. + We don't support old HFS format, but we support + special HFS volume that contains embedded HFS+ volume. + HFS MDB : Master directory block + HFS VIB : Volume information block + some old images contain boot data with "LK" signature at start of buf32. + */ +#if 1 + // here we check first bytes of archive, + // because start data can contain signature of some another + // archive type that could have priority over HFS. + const void *buf_ptr = (const void *)buf32; + const unsigned sig = GetUi16a(buf_ptr); + if (sig != 'L' + ((unsigned)'K' << 8)) + { + // some old HFS (non HFS+) files have no "LK" signature, + // but have non-zero data after 2 first bytes in start 1 KiB. + if (sig != 0) + return S_FALSE; +/* + for (unsigned i = 0; i < kHeaderPadSize / 4; i++) + if (buf32[i] != 0) + return S_FALSE; +*/ + } +#endif + if (GetUi16a(p + 0x7c) != k_Signature_LE16_HPLUS) // signature of embedded HFS+ volume + return S_FALSE; + /* + h.CTime = Get32(p + 0x2); + h.MTime = Get32(p + 0x6); + + h.NumFiles = Get32(p + 0x54); + h.NumFolders = Get32(p + 0x58); + + if (h.NumFolders > ((UInt32)1 << 29) || + h.NumFiles > ((UInt32)1 << 30)) + return S_FALSE; + if (progress) + { + UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1; + RINOK(progress->SetTotal(&numFiles, NULL)) + } + h.NumFreeBlocks = Get16(p + 0x22); + */ + + // v24.09: blockSize in old HFS image can be non-power of 2. + const UInt32 blockSize = Get32a(p + 0x14); // drAlBlkSiz + if (blockSize == 0 || (blockSize & 0x1ff)) + return S_FALSE; + const unsigned numBlocks = Get16a(p + 0x12); // drNmAlBlks + // UInt16 drFreeBks = Get16a(p + 0x22); // number of unused allocation blocks + /* + we suppose that it has the following layout: + { + start data with header + blocks[h.NumBlocks] + end data with header (probably size_of_footer <= blockSize). + } + */ + // PhySize2 = ((UInt64)numBlocks + 2) * blockSize; + const unsigned sector_of_FirstBlock = Get16a(p + 0x1c); // drAlBlSt : first allocation block in volume + const UInt32 startBlock = Get16a(p + 0x7c + 2); + const UInt32 blockCount = Get16a(p + 0x7c + 4); + SpecOffset = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here + PhySize2 = SpecOffset + (UInt64)numBlocks * blockSize; + SpecOffset += (UInt64)startBlock * blockSize; + // before v24.09: // SpecOffset = (UInt64)(1 + startBlock) * blockSize; + const UInt64 phy = SpecOffset + (UInt64)blockCount * blockSize; + if (PhySize2 < phy) + PhySize2 = phy; + UInt32 tail = 1 << 10; // at least 1 KiB tail (for footer MDB) is expected. + if (tail < blockSize) + tail = blockSize; + RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize)) + if (ArcFileSize > PhySize2 && + ArcFileSize - PhySize2 <= tail) + { + // data after blocks[h.NumBlocks] must contain another copy of MDB. + // In example where blockSize is not power of 2, we have + // (ArcFileSize - PhySize2) < blockSize. + // We suppose that data after blocks[h.NumBlocks] is part of HFS archive. + // Maybe we should scan for footer MDB data (in last 1 KiB)? + PhySize2 = ArcFileSize; + } + RINOK(InStream_SeekSet(inStream, SpecOffset)) + RINOK(ReadStream_FALSE(inStream, buf32, kHfsHeaderSize)) + } + + // HFS+ / HFSX volume header (starting from offset==1024): + { + // v24.09: we use strict condition test for pair signature(Version): + // H+(4), HX(5): + const UInt32 sig = GetUi32a(p); + // h.Version = Get16(p + 2); + h.Is_Hsfx_ver5 = false; + if (sig != k_Signature_LE32_HFSP_VER4) + { + if (sig != k_Signature_LE32_HFSX_VER5) + return S_FALSE; + h.Is_Hsfx_ver5 = true; + } + } + { + const UInt32 blockSize = Get32a(p + 0x28); + unsigned i; + for (i = 9; ((UInt32)1 << i) != blockSize; i++) + if (i == 31) + return S_FALSE; + h.BlockSizeLog = i; + } +#if 1 + // HFS Plus DOCs: The first 1024 bytes are reserved for use as boot blocks + // v24.09: we don't check starting 1 KiB before old (HFS MDB) block ("BD" signture) . + // but we still check starting 1 KiB before HFS+ / HFSX volume header. + // are there HFS+ / HFSX images with non-zero data in this reserved area? + { + for (unsigned i = 0; i < kHeaderPadSize / 4; i++) + if (buf32[i] != 0) + return S_FALSE; + } +#endif + // h.Attr = Get32a(p + 4); + // h.LastMountedVersion = Get32a(p + 8); + // h.JournalInfoBlock = Get32a(p + 0xC); + h.CTime = Get32a(p + 0x10); + h.MTime = Get32a(p + 0x14); + // h.BackupTime = Get32a(p + 0x18); + // h.CheckedTime = Get32a(p + 0x1C); + h.NumFiles = Get32a(p + 0x20); + h.NumFolders = Get32a(p + 0x24); + if (h.NumFolders > ((UInt32)1 << 29) || + h.NumFiles > ((UInt32)1 << 30)) + return S_FALSE; + + RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize)) + if (progress) + { + const UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1; + RINOK(progress->SetTotal(&numFiles, NULL)) + } + + h.NumBlocks = Get32a(p + 0x2C); + h.NumFreeBlocks = Get32a(p + 0x30); + /* + h.NextCalatlogNodeID = Get32(p + 0x40); + h.WriteCount = Get32(p + 0x44); + for (i = 0; i < 6; i++) + h.FinderInfo[i] = Get32(p + 0x50 + i * 4); + h.VolID = Get64(p + 0x68); + */ + + ResFileName = kResFileName; + + CFork extentsFork, catalogFork, attrFork; + // allocationFork.Parse(p + 0x70 + 0x50 * 0); + extentsFork.Parse(p + 0x70 + 0x50 * 1); + catalogFork.Parse(p + 0x70 + 0x50 * 2); + attrFork.Parse (p + 0x70 + 0x50 * 3); + // startupFork.Parse(p + 0x70 + 0x50 * 4); + + CObjectVector overflowExtents[2]; + if (!extentsFork.IsOk(Header.BlockSizeLog)) + HeadersError = true; + else + { + const HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents); + if (res == S_FALSE) + HeadersError = true; + else if (res != S_OK) + return res; + } + + if (!catalogFork.UpgradeAndTest(overflowExtents[0], kHfsID_CatalogFile, Header.BlockSizeLog)) + return S_FALSE; + + if (!attrFork.UpgradeAndTest(overflowExtents[0], kHfsID_AttributesFile, Header.BlockSizeLog)) + HeadersError = true; + else + { + if (attrFork.Size != 0) + RINOK(LoadAttrs(attrFork, inStream, progress)) + } + + RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress)) + + // PhySize = Header.GetPhySize(); + return S_OK; +} + + + +Z7_class_CHandler_final: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public CMyUnknownImp, + public CDatabase +{ + Z7_IFACES_IMP_UNK_3( + IInArchive, + IArchiveGetRawProps, + IInArchiveGetStream) + + CMyComPtr _stream; + HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidCTime, + kpidMTime, + kpidATime, + kpidChangeTime, + kpidPosixAttrib, + /* + kpidUserId, + kpidGroupId, + */ +#ifdef HFS_SHOW_ALT_STREAMS + kpidIsAltStream, +#endif + kpidMethod +}; + +static const Byte kArcProps[] = +{ + kpidMethod, + kpidCharacts, + kpidClusterSize, + kpidFreeSpace, + kpidCTime, + kpidMTime +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) +{ + if (hfsTime == 0) + return; + FILETIME ft; + HfsTimeToFileTime(hfsTime, ft); + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; + case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break; + case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break; + case kpidPhySize: + { + UInt64 v = SpecOffset + Header.GetPhySize(); // PhySize; + if (v < PhySize2) + v = PhySize2; + prop = v; + break; + } + case kpidClusterSize: prop = (UInt32)1 << Header.BlockSizeLog; break; + case kpidFreeSpace: prop = (UInt64)Header.GetFreeSize(); break; + case kpidMTime: HfsTimeToProp(Header.MTime, prop); break; + case kpidCTime: + { + if (Header.CTime != 0) + { + FILETIME localFt, ft; + HfsTimeToFileTime(Header.CTime, localFt); + if (LocalFileTimeToFileTime(&localFt, &ft)) + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base); + } + break; + } + case kpidIsTree: prop = true; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature; + if (flags != 0) + prop = flags; + break; + } + case kpidIsAltStream: prop = ThereAreAltStreams; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) +{ + *name = NULL; + *propID = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + const CRef &ref = Refs[index]; + *parentType = ref.IsAltStream() ? + NParentType::kAltStream : + NParentType::kDir; + *parent = (UInt32)(Int32)ref.Parent; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + #ifdef MY_CPU_LE + if (propID == kpidName) + { + const CRef &ref = Refs[index]; + const UString *s; + if (ref.IsResource()) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + s = &Items[ref.ItemIndex].Name; + *data = (const wchar_t *)(*s); + *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t); + *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; + return S_OK; + } + #else + UNUSED_VAR(index) + UNUSED_VAR(propID) + #endif + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.ItemIndex]; + switch (propID) + { + case kpidPath: GetItemPath(index, prop); break; + case kpidName: + { + const UString *s; + if (ref.IsResource()) + s = &ResFileName; + else if (ref.AttrIndex >= 0) + s = &Attrs[ref.AttrIndex].Name; + else + s = &item.Name; + prop = *s; + break; + } + case kpidPackSize: + { + UInt64 size; + if (ref.AttrIndex >= 0) + size = Attrs[ref.AttrIndex].GetSize(); + else if (ref.IsResource()) + size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; + else if (item.IsDir()) + break; + else if (item.CompressHeader.IsCorrect) + { + if (item.CompressHeader.IsMethod_Resource()) + size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; + else if (item.decmpfs_AttrIndex >= 0) + { + // size = item.PackSize; + const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; + size = attr.Data.Size() - item.CompressHeader.DataPos; + } + else + size = 0; + } + else + size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog; + prop = size; + break; + } + case kpidSize: + { + UInt64 size; + if (ref.AttrIndex >= 0) + size = Attrs[ref.AttrIndex].GetSize(); + else if (ref.IsResource()) + size = item.ResourceFork.Size; + else if (item.IsDir()) + break; + else if (item.CompressHeader.IsCorrect) + size = item.CompressHeader.UnpackSize; + else + size = item.DataFork.Size; + prop = size; + break; + } + case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break; + case kpidIsAltStream: prop = ref.IsAltStream(); break; + case kpidCTime: HfsTimeToProp(item.CTime, prop); break; + case kpidMTime: HfsTimeToProp(item.MTime, prop); break; + case kpidATime: HfsTimeToProp(item.ATime, prop); break; + case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break; + case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break; + /* + case kpidUserId: prop = (UInt32)item.OwnerID; break; + case kpidGroupId: prop = (UInt32)item.GroupID; break; + */ + + case kpidMethod: + if (ref.IsItem()) + item.CompressHeader.MethodToProp(prop); + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream, callback)) + _stream = inStream; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _stream.Release(); + Clear(); + return S_OK; +} + +static const UInt32 kCompressionBlockSize = 1 << 16; + +CDecoder::CDecoder(bool IsAdlerOptional) +{ + /* Some new hfs files contain zlib resource fork without Adler checksum. + We do not know how we must detect case where there is Adler + checksum or there is no Adler checksum. + */ + _zlibDecoder->IsAdlerOptional = IsAdlerOptional; + _lzfseDecoder->LzvnMode = true; +} + +HRESULT CDecoder::ExtractResourceFork_ZLIB( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) +{ + const unsigned kHeaderSize = 0x100 + 8; + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize)) + Byte *buf = _buf; + const UInt32 dataPos = Get32(buf); + const UInt32 mapPos = Get32(buf + 4); + const UInt32 dataSize = Get32(buf + 8); + const UInt32 mapSize = Get32(buf + 12); + + const UInt32 kResMapSize = 50; + + if (mapSize != kResMapSize + || dataPos > mapPos + || dataSize != mapPos - dataPos + || mapSize > forkSize + || mapPos != forkSize - mapSize) + return S_FALSE; + + const UInt32 dataSize2 = Get32(buf + 0x100); + if (4 + dataSize2 != dataSize + || dataSize2 < 8 + || dataSize2 > dataSize) + return S_FALSE; + + const UInt32 numBlocks = GetUi32(buf + 0x100 + 4); + if (((dataSize2 - 4) >> 3) < numBlocks) + return S_FALSE; + { + const UInt64 up = unpackSize + kCompressionBlockSize - 1; + if (up < unpackSize || up / kCompressionBlockSize != numBlocks) + return S_FALSE; + } + + const UInt32 tableSize = (numBlocks << 3); + + _tableBuf.AllocAtLeast(tableSize); + + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)) + const Byte *tableBuf = _tableBuf; + + UInt32 prev = 4 + tableSize; + + UInt32 i; + for (i = 0; i < numBlocks; i++) + { + const UInt32 offs = GetUi32(tableBuf + i * 8); + const UInt32 size = GetUi32(tableBuf + i * 8 + 4); + if (size == 0 + || prev != offs + || offs > dataSize2 + || size > dataSize2 - offs) + return S_FALSE; + prev = offs + size; + } + + if (prev != dataSize2) + return S_FALSE; + + CMyComPtr2_Create bufInStream; + + // bool padError = false; + UInt64 outPos = 0; + + for (i = 0; i < numBlocks; i++) + { + const UInt64 rem = unpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + const UInt32 size = GetUi32(tableBuf + i * 8 + 4); + + if (size > kCompressionBlockSize + 1) + return S_FALSE; + + RINOK(ReadStream_FALSE(inStream, buf, size)) + + if ((buf[0] & 0xF) == 0xF) + { + // (buf[0] = 0xff) is marker of uncompressed block in APFS + // that code was not tested in HFS + if (size - 1 != blockSize) + return S_FALSE; + + if (outStream) + { + RINOK(WriteStream(outStream, buf + 1, blockSize)) + } + } + else + { + const UInt64 blockSize64 = blockSize; + bufInStream->Init(buf, size); + RINOK(_zlibDecoder.Interface()->Code(bufInStream, outStream, NULL, &blockSize64, NULL)) + if (_zlibDecoder->GetOutputProcessedSize() != blockSize) + return S_FALSE; + const UInt64 inSize = _zlibDecoder->GetInputProcessedSize(); + if (inSize != size) + { + if (inSize > size) + return S_FALSE; + // apfs file can contain junk (non-zeros) after data block. + /* + if (!padError) + { + const Byte *p = buf + (UInt32)inSize; + const Byte *e = p + (size - (UInt32)inSize); + do + { + if (*p != 0) + { + padError = true; + break; + } + } + while (++p != e); + } + */ + } + } + + outPos += blockSize; + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)) + } + } + + if (outPos != unpackSize) + return S_FALSE; + + // if (padError) return S_FALSE; + + /* We check Resource Map + Are there HFS files with another values in Resource Map ??? */ + + RINOK(ReadStream_FALSE(inStream, buf, mapSize)) + const UInt32 types = Get16(buf + 24); + const UInt32 names = Get16(buf + 26); + const UInt32 numTypes = Get16(buf + 28); + if (numTypes != 0 || types != 28 || names != kResMapSize) + return S_FALSE; + const UInt32 resType = Get32(buf + 30); + const UInt32 numResources = Get16(buf + 34); + const UInt32 resListOffset = Get16(buf + 36); + if (resType != 0x636D7066) // cmpf + return S_FALSE; + if (numResources != 0 || resListOffset != 10) + return S_FALSE; + + const UInt32 entryId = Get16(buf + 38); + const UInt32 nameOffset = Get16(buf + 40); + // Byte attrib = buf[42]; + const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; + if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) + return S_FALSE; + + return S_OK; +} + + + +HRESULT CDecoder::ExtractResourceFork_LZFSE( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) +{ + const UInt32 kNumBlocksMax = (UInt32)1 << 29; + if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize) + return S_FALSE; + const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize); + const UInt32 numBlocks2 = numBlocks + 1; + const UInt32 tableSize = (numBlocks2 << 2); + if (tableSize > forkSize) + return S_FALSE; + _tableBuf.AllocAtLeast(tableSize); + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)) + const Byte *tableBuf = _tableBuf; + + { + UInt32 prev = GetUi32(tableBuf); + if (prev != tableSize) + return S_FALSE; + for (UInt32 i = 1; i < numBlocks2; i++) + { + const UInt32 offs = GetUi32(tableBuf + i * 4); + if (offs <= prev) + return S_FALSE; + prev = offs; + } + if (prev != forkSize) + return S_FALSE; + } + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + CMyComPtr2_Create bufInStream; + + UInt64 outPos = 0; + + for (UInt32 i = 0; i < numBlocks; i++) + { + const UInt64 rem = unpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + const UInt32 size = + GetUi32(tableBuf + i * 4 + 4) - + GetUi32(tableBuf + i * 4); + + if (size > kCompressionBlockSize + 1) + return S_FALSE; + + RINOK(ReadStream_FALSE(inStream, _buf, size)) + const Byte *buf = _buf; + + if (buf[0] == k_LZVN_Uncompressed_Marker) + { + if (size - 1 != blockSize) + return S_FALSE; + if (outStream) + { + RINOK(WriteStream(outStream, buf + 1, blockSize)) + } + } + else + { + const UInt64 blockSize64 = blockSize; + const UInt64 packSize64 = size; + bufInStream->Init(buf, size); + RINOK(_lzfseDecoder.Interface()->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL)) + // in/out sizes were checked in Code() + } + + outPos += blockSize; + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)) + } + } + + return S_OK; +} + + +/* +static UInt32 GetUi24(const Byte *p) +{ + return p[0] + ((UInt32)p[1] << 8) + ((UInt32)p[2] << 24); +} + +HRESULT CDecoder::ExtractResourceFork_ZBM( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) +{ + const UInt32 kNumBlocksMax = (UInt32)1 << 29; + if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize) + return S_FALSE; + const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize); + const UInt32 numBlocks2 = numBlocks + 1; + const UInt32 tableSize = (numBlocks2 << 2); + if (tableSize > forkSize) + return S_FALSE; + _tableBuf.AllocAtLeast(tableSize); + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)); + const Byte *tableBuf = _tableBuf; + + { + UInt32 prev = GetUi32(tableBuf); + if (prev != tableSize) + return S_FALSE; + for (UInt32 i = 1; i < numBlocks2; i++) + { + const UInt32 offs = GetUi32(tableBuf + i * 4); + if (offs <= prev) + return S_FALSE; + prev = offs; + } + if (prev != forkSize) + return S_FALSE; + } + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + CBufInStream *bufInStream = new CBufInStream; + CMyComPtr bufInStream = bufInStream; + + UInt64 outPos = 0; + + for (UInt32 i = 0; i < numBlocks; i++) + { + const UInt64 rem = unpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + const UInt32 size = + GetUi32(tableBuf + i * 4 + 4) - + GetUi32(tableBuf + i * 4); + + // if (size > kCompressionBlockSize + 1) + if (size > blockSize + 1) + return S_FALSE; // we don't expect it, because encode will use uncompressed chunk + + RINOK(ReadStream_FALSE(inStream, _buf, size)); + const Byte *buf = _buf; + + // (size != 0) + // if (size == 0) return S_FALSE; + + if (buf[0] == 0xFF) // uncompressed marker + { + if (size != blockSize + 1) + return S_FALSE; + if (outStream) + { + RINOK(WriteStream(outStream, buf + 1, blockSize)); + } + } + else + { + if (size < 4) + return S_FALSE; + if (buf[0] != 'Z' || + buf[1] != 'B' || + buf[2] != 'M' || + buf[3] != 9) + return S_FALSE; + // for debug: + unsigned packPos = 4; + unsigned unpackPos = 0; + unsigned packRem = size - packPos; + for (;;) + { + if (packRem < 6) + return S_FALSE; + const UInt32 packSize = GetUi24(buf + packPos); + const UInt32 chunkUnpackSize = GetUi24(buf + packPos + 3); + if (packSize < 6) + return S_FALSE; + if (packSize > packRem) + return S_FALSE; + if (chunkUnpackSize > blockSize - unpackPos) + return S_FALSE; + packPos += packSize; + packRem -= packSize; + unpackPos += chunkUnpackSize; + if (packSize == 6) + { + if (chunkUnpackSize != 0) + return S_FALSE; + break; + } + if (packSize >= chunkUnpackSize + 6) + { + if (packSize > chunkUnpackSize + 6) + return S_FALSE; + // uncompressed chunk; + } + else + { + // compressed chunk + const Byte *t = buf + packPos - packSize + 6; + UInt32 r = packSize - 6; + if (r < 9) + return S_FALSE; + const UInt32 v0 = GetUi24(t); + const UInt32 v1 = GetUi24(t + 3); + const UInt32 v2 = GetUi24(t + 6); + if (v0 > v1 || v1 > v2 || v2 > packSize) + return S_FALSE; + // here we need the code that will decompress ZBM chunk + } + } + + if (unpackPos != blockSize) + return S_FALSE; + + UInt32 size1 = size; + if (size1 > kCompressionBlockSize) + { + size1 = kCompressionBlockSize; + // return S_FALSE; + } + if (outStream) + { + RINOK(WriteStream(outStream, buf, size1)) + + const UInt32 kTempSize = 1 << 16; + Byte temp[kTempSize]; + memset(temp, 0, kTempSize); + + for (UInt32 k = size1; k < kCompressionBlockSize; k++) + { + UInt32 cur = kCompressionBlockSize - k; + if (cur > kTempSize) + cur = kTempSize; + RINOK(WriteStream(outStream, temp, cur)) + k += cur; + } + } + + // const UInt64 blockSize64 = blockSize; + // const UInt64 packSize64 = size; + // bufInStream->Init(buf, size); + // RINOK(_zbmDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL)); + // in/out sizes were checked in Code() + } + + outPos += blockSize; + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } + } + + return S_OK; +} +*/ + +HRESULT CDecoder::Extract( + ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, + UInt64 forkSize, + const CCompressHeader &compressHeader, + const CByteBuffer *data, + UInt64 progressStart, IArchiveExtractCallback *extractCallback, + int &opRes) +{ + opRes = NExtract::NOperationResult::kDataError; + + if (compressHeader.IsMethod_Uncompressed_Inline()) + { + const size_t packSize = data->Size() - compressHeader.DataPos; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize)) + } + opRes = NExtract::NOperationResult::kOK; + return S_OK; + } + + if (compressHeader.Method == kMethod_ZLIB_ATTR || + compressHeader.Method == kMethod_LZVN_ATTR) + { + CMyComPtr2_Create bufInStream; + const size_t packSize = data->Size() - compressHeader.DataPos; + bufInStream->Init(*data + compressHeader.DataPos, packSize); + + if (compressHeader.Method == kMethod_ZLIB_ATTR) + { + const HRESULT hres = _zlibDecoder.Interface()->Code(bufInStream, realOutStream, + NULL, &compressHeader.UnpackSize, NULL); + if (hres == S_OK) + if (_zlibDecoder->GetOutputProcessedSize() == compressHeader.UnpackSize + && _zlibDecoder->GetInputProcessedSize() == packSize) + opRes = NExtract::NOperationResult::kOK; + return hres; + } + { + const UInt64 packSize64 = packSize; + const HRESULT hres = _lzfseDecoder.Interface()->Code(bufInStream, realOutStream, + &packSize64, &compressHeader.UnpackSize, NULL); + if (hres == S_OK) + { + // in/out sizes were checked in Code() + opRes = NExtract::NOperationResult::kOK; + } + return hres; + } + } + + HRESULT hres; + if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC) + { + hres = ExtractResourceFork_ZLIB( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + // for debug: + // hres = NCompress::CopyStream(inStreamFork, realOutStream, NULL); + } + else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC) + { + hres = ExtractResourceFork_LZFSE( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + } + /* + else if (compressHeader.Method == NHfs::kMethod_ZBM_RSRC) + { + hres = ExtractResourceFork_ZBM( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + } + */ + else + { + opRes = NExtract::NOperationResult::kUnsupportedMethod; + hres = S_FALSE; + } + + if (hres == S_OK) + opRes = NExtract::NOperationResult::kOK; + return hres; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Refs.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const CRef &ref = Refs[allFilesMode ? i : indices[i]]; + totalSize += Get_UnpackSize_of_Ref(ref); + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 currentTotalSize = 0, currentItemSize = 0; + + const size_t kBufSize = kCompressionBlockSize; + CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + // there are hfs without adler in zlib. + CDecoder decoder(true); // IsAdlerOptional + + for (i = 0;; i++, currentTotalSize += currentItemSize) + { + RINOK(extractCallback->SetCompleted(¤tTotalSize)) + if (i >= numItems) + break; + const UInt32 index = allFilesMode ? i : indices[i]; + const CRef &ref = Refs[index]; + const CItem &item = Items[ref.ItemIndex]; + currentItemSize = Get_UnpackSize_of_Ref(ref); + + int opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (ref.IsItem() && item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + + UInt64 pos = 0; + opRes = NExtract::NOperationResult::kDataError; + const CFork *fork = NULL; + + if (ref.AttrIndex >= 0) + { + const CAttr &attr = Attrs[ref.AttrIndex]; + if (attr.Fork_defined && attr.Data.Size() == 0) + fork = &attr.Fork; + else + { + opRes = NExtract::NOperationResult::kOK; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, + // AttrBuf + attr.Pos, attr.Size + attr.Data, attr.Data.Size() + )) + } + } + } + else if (ref.IsResource()) + fork = &item.ResourceFork; + else if (item.CompressHeader.IsSupported) + { + CMyComPtr inStreamFork; + UInt64 forkSize = 0; + const CByteBuffer *decmpfs_Data = NULL; + + if (item.CompressHeader.IsMethod_Resource()) + { + const CFork &resourceFork = item.ResourceFork; + forkSize = resourceFork.Size; + GetForkStream(resourceFork, &inStreamFork); + } + else + { + const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; + decmpfs_Data = &attr.Data; + } + + if (inStreamFork || decmpfs_Data) + { + const HRESULT hres = decoder.Extract( + inStreamFork, realOutStream, + forkSize, + item.CompressHeader, + decmpfs_Data, + currentTotalSize, extractCallback, + opRes); + if (hres != S_FALSE && hres != S_OK) + return hres; + } + } + else if (item.CompressHeader.IsCorrect) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + fork = &item.DataFork; + + if (fork) + { + if (fork->IsOk(Header.BlockSizeLog)) + { + opRes = NExtract::NOperationResult::kOK; + unsigned extentIndex; + for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++) + { + if (opRes != NExtract::NOperationResult::kOK) + break; + if (fork->Size == pos) + break; + const CExtent &e = fork->Extents[extentIndex]; + RINOK(InStream_SeekSet(_stream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog))) + UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; + while (extentRem != 0) + { + const UInt64 rem = fork->Size - pos; + if (rem == 0) + { + // Here we check that there are no extra (empty) blocks in last extent. + if (extentRem >= ((UInt64)1 << Header.BlockSizeLog)) + opRes = NExtract::NOperationResult::kDataError; + break; + } + size_t cur = kBufSize; + if (cur > rem) + cur = (size_t)rem; + if (cur > extentRem) + cur = (size_t)extentRem; + RINOK(ReadStream(_stream, buf, &cur)) + if (cur == 0) + { + opRes = NExtract::NOperationResult::kDataError; + break; + } + if (realOutStream) + { + RINOK(WriteStream(realOutStream, buf, cur)) + } + pos += cur; + extentRem -= cur; + const UInt64 processed = currentTotalSize + pos; + RINOK(extractCallback->SetCompleted(&processed)) + } + } + if (extentIndex != fork->Extents.Size() || fork->Size != pos) + opRes = NExtract::NOperationResult::kDataError; + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = Refs.Size(); + return S_OK; +} + +HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream) +{ + *stream = NULL; + + if (!fork.IsOk(Header.BlockSizeLog)) + return S_FALSE; + + CMyComPtr2 extentStream; + extentStream.Create_if_Empty(); + + UInt64 rem = fork.Size; + UInt64 virt = 0; + + FOR_VECTOR (i, fork.Extents) + { + const CExtent &e = fork.Extents[i]; + if (e.NumBlocks == 0) + continue; + UInt64 cur = ((UInt64)e.NumBlocks << Header.BlockSizeLog); + if (cur > rem) + { + cur = rem; + if (i != fork.Extents.Size() - 1) + return S_FALSE; + } + CSeekExtent se; + se.Phy = SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog); + se.Virt = virt; + virt += cur; + rem -= cur; + extentStream->Extents.Add(se); + } + + if (rem != 0) + return S_FALSE; + + CSeekExtent se; + se.Phy = 0; // = SpecOffset ? + se.Virt = virt; + extentStream->Extents.Add(se); + extentStream->Stream = _stream; + extentStream->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + *stream = NULL; + + const CRef &ref = Refs[index]; + const CFork *fork = NULL; + if (ref.AttrIndex >= 0) + { + const CAttr &attr = Attrs[ref.AttrIndex]; + if (!attr.Fork_defined || attr.Data.Size() != 0) + return S_FALSE; + fork = &attr.Fork; + } + else + { + const CItem &item = Items[ref.ItemIndex]; + if (ref.IsResource()) + fork = &item.ResourceFork; + else if (item.IsDir()) + return S_FALSE; + else if (item.CompressHeader.IsCorrect) + return S_FALSE; + else + fork = &item.DataFork; + } + return GetForkStream(*fork, stream); +} + +static const Byte k_Signature[] = { + 2, 'B', 'D', + 4, 'H', '+', 0, 4, + 4, 'H', 'X', 0, 5 }; + +REGISTER_ARC_I( + "HFS", "hfs hfsx", NULL, 0xE3, + k_Signature, + kHeaderPadSize, + NArcInfoFlags::kMultiSignature, + IsArc_HFS) + +}} diff --git a/CPP/7zip/Archive/HfsHandler.h b/CPP/7zip/Archive/HfsHandler.h index f9a9d8193..6d869c247 100644 --- a/CPP/7zip/Archive/HfsHandler.h +++ b/CPP/7zip/Archive/HfsHandler.h @@ -1,87 +1,87 @@ -// HfsHandler.h - -#ifndef ZIP7_INC_HFS_HANDLER_H -#define ZIP7_INC_HFS_HANDLER_H - -#include "../../Windows/PropVariant.h" - -#include "../Compress/LzfseDecoder.h" -#include "../Compress/ZlibDecoder.h" - -namespace NArchive { -namespace NHfs { - -static const UInt32 k_decmpfs_HeaderSize = 16; - -struct CCompressHeader -{ - UInt64 UnpackSize; - UInt32 Method; - Byte DataPos; - bool IsCorrect; - bool IsSupported; - bool IsResource; - - bool IsMethod_Compressed_Inline() const { return DataPos == k_decmpfs_HeaderSize; } - bool IsMethod_Uncompressed_Inline() const { return DataPos == k_decmpfs_HeaderSize + 1; } - bool IsMethod_Resource() const { return IsResource; } - - void Parse(const Byte *p, size_t size); - - void Clear() - { - UnpackSize = 0; - Method = 0; - DataPos = 0; - IsCorrect = false; - IsSupported = false; - IsResource = false; - } - - CCompressHeader() { Clear(); } - - void MethodToProp(NWindows::NCOM::CPropVariant &prop) const; -}; - -void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop); - - -class CDecoder -{ - CMyComPtr2_Create _zlibDecoder; - CMyComPtr2_Create _lzfseDecoder; - - CByteBuffer _tableBuf; - CByteBuffer _buf; - - HRESULT ExtractResourceFork_ZLIB( - ISequentialInStream *inStream, ISequentialOutStream *realOutStream, - UInt64 forkSize, UInt64 unpackSize, - UInt64 progressStart, IArchiveExtractCallback *extractCallback); - - HRESULT ExtractResourceFork_LZFSE( - ISequentialInStream *inStream, ISequentialOutStream *realOutStream, - UInt64 forkSize, UInt64 unpackSize, - UInt64 progressStart, IArchiveExtractCallback *extractCallback); - - HRESULT ExtractResourceFork_ZBM( - ISequentialInStream *inStream, ISequentialOutStream *realOutStream, - UInt64 forkSize, UInt64 unpackSize, - UInt64 progressStart, IArchiveExtractCallback *extractCallback); - -public: - - HRESULT Extract( - ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, - UInt64 forkSize, - const CCompressHeader &compressHeader, - const CByteBuffer *data, - UInt64 progressStart, IArchiveExtractCallback *extractCallback, - int &opRes); - - CDecoder(bool IsAdlerOptional); -}; - -}} - -#endif +// HfsHandler.h + +#ifndef ZIP7_INC_HFS_HANDLER_H +#define ZIP7_INC_HFS_HANDLER_H + +#include "../../Windows/PropVariant.h" + +#include "../Compress/LzfseDecoder.h" +#include "../Compress/ZlibDecoder.h" + +namespace NArchive { +namespace NHfs { + +static const UInt32 k_decmpfs_HeaderSize = 16; + +struct CCompressHeader +{ + UInt64 UnpackSize; + UInt32 Method; + Byte DataPos; + bool IsCorrect; + bool IsSupported; + bool IsResource; + + bool IsMethod_Compressed_Inline() const { return DataPos == k_decmpfs_HeaderSize; } + bool IsMethod_Uncompressed_Inline() const { return DataPos == k_decmpfs_HeaderSize + 1; } + bool IsMethod_Resource() const { return IsResource; } + + void Parse(const Byte *p, size_t size); + + void Clear() + { + UnpackSize = 0; + Method = 0; + DataPos = 0; + IsCorrect = false; + IsSupported = false; + IsResource = false; + } + + CCompressHeader() { Clear(); } + + void MethodToProp(NWindows::NCOM::CPropVariant &prop) const; +}; + +void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop); + + +class CDecoder +{ + CMyComPtr2_Create _zlibDecoder; + CMyComPtr2_Create _lzfseDecoder; + + CByteBuffer _tableBuf; + CByteBuffer _buf; + + HRESULT ExtractResourceFork_ZLIB( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + + HRESULT ExtractResourceFork_LZFSE( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + + HRESULT ExtractResourceFork_ZBM( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + +public: + + HRESULT Extract( + ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, + UInt64 forkSize, + const CCompressHeader &compressHeader, + const CByteBuffer *data, + UInt64 progressStart, IArchiveExtractCallback *extractCallback, + int &opRes); + + CDecoder(bool IsAdlerOptional); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h index 5e040148d..a81701562 100644 --- a/CPP/7zip/Archive/IArchive.h +++ b/CPP/7zip/Archive/IArchive.h @@ -1,754 +1,754 @@ -// IArchive.h - -#ifndef ZIP7_INC_IARCHIVE_H -#define ZIP7_INC_IARCHIVE_H - -#include "../IProgress.h" -#include "../IStream.h" -#include "../PropID.h" - -Z7_PURE_INTERFACES_BEGIN - - -#define Z7_IFACE_CONSTR_ARCHIVE_SUB(i, base, n) \ - Z7_DECL_IFACE_7ZIP_SUB(i, base, 6, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -#define Z7_IFACE_CONSTR_ARCHIVE(i, n) \ - Z7_IFACE_CONSTR_ARCHIVE_SUB(i, IUnknown, n) - -/* -How the function in 7-Zip returns object for output parameter via pointer - -1) The caller sets the value of variable before function call: - PROPVARIANT : vt = VT_EMPTY - BSTR : NULL - IUnknown* and derived interfaces : NULL - another scalar types : any non-initialized value is allowed - -2) The callee in current 7-Zip code now can free input object for output parameter: - PROPVARIANT : the callee calls VariantClear(propvaiant_ptr) for input - value stored in variable - another types : the callee ignores stored value. - -3) The callee writes new value to variable for output parameter and - returns execution to caller. - -4) The caller must free or release object returned by the callee: - PROPVARIANT : VariantClear(&propvaiant) - BSTR : SysFreeString(bstr) - IUnknown* and derived interfaces : if (ptr) ptr->Relase() -*/ - - -namespace NFileTimeType -{ - enum EEnum - { - kNotDefined = -1, - kWindows = 0, - kUnix, - kDOS, - k1ns - }; -} - -namespace NArcInfoFlags -{ - const UInt32 kKeepName = 1 << 0; // keep name of file in archive name - const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams - const UInt32 kNtSecure = 1 << 2; // the handler supports NT security - const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive - const UInt32 kMultiSignature = 1 << 4; // there are several signatures - const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset - const UInt32 kStartOpen = 1 << 6; // call handler for each start position - const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file - const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward - const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub) - const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links - const UInt32 kHardLinks = 1 << 11; // the handler supports hard links - const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches - const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums) - const UInt32 kCTime = 1 << 14; - const UInt32 kCTime_Default = 1 << 15; - const UInt32 kATime = 1 << 16; - const UInt32 kATime_Default = 1 << 17; - const UInt32 kMTime = 1 << 18; - const UInt32 kMTime_Default = 1 << 19; - // const UInt32 kTTime_Reserved = 1 << 20; - // const UInt32 kTTime_Reserved_Default = 1 << 21; -} - -namespace NArcInfoTimeFlags -{ - const unsigned kTime_Prec_Mask_bit_index = 0; - const unsigned kTime_Prec_Mask_num_bits = 26; - - const unsigned kTime_Prec_Default_bit_index = 27; - const unsigned kTime_Prec_Default_num_bits = 5; -} - -#define TIME_PREC_TO_ARC_FLAGS_MASK(v) \ - ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (v))) - -#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(v) \ - ((UInt32)(v) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index) - -namespace NArchive -{ - namespace NHandlerPropID - { - enum - { - kName = 0, // VT_BSTR - kClassID, // binary GUID in VT_BSTR - kExtension, // VT_BSTR - kAddExtension, // VT_BSTR - kUpdate, // VT_BOOL - kKeepName, // VT_BOOL - kSignature, // binary in VT_BSTR - kMultiSignature, // binary in VT_BSTR - kSignatureOffset, // VT_UI4 - kAltStreams, // VT_BOOL - kNtSecure, // VT_BOOL - kFlags, // VT_UI4 - kTimeFlags // VT_UI4 - }; - } - - namespace NExtract - { - namespace NAskMode - { - enum - { - kExtract = 0, - kTest, - kSkip, - kReadExternal - }; - } - - namespace NOperationResult - { - enum - { - kOK = 0, - kUnsupportedMethod, - kDataError, - kCRCError, - kUnavailable, - kUnexpectedEnd, - kDataAfterEnd, - kIsNotArc, - kHeadersError, - kWrongPassword - // , kMemError - }; - } - } - - namespace NEventIndexType - { - enum - { - kNoIndex = 0, - kInArcIndex, - kBlockIndex, - kOutArcIndex - // kArcProp - }; - } - - namespace NUpdate - { - namespace NOperationResult - { - enum - { - kOK = 0 - // kError = 1, - // kError_FileChanged - }; - } - } -} - -#define Z7_IFACEM_IArchiveOpenCallback(x) \ - x(SetTotal(const UInt64 *files, const UInt64 *bytes)) \ - x(SetCompleted(const UInt64 *files, const UInt64 *bytes)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenCallback, 0x10) - -/* -IArchiveExtractCallback:: - -7-Zip doesn't call IArchiveExtractCallback functions - GetStream() - PrepareOperation() - SetOperationResult() -from different threads simultaneously. -But 7-Zip can call functions for IProgress or ICompressProgressInfo functions -from another threads simultaneously with calls for IArchiveExtractCallback interface. - -IArchiveExtractCallback::GetStream() - UInt32 index - index of item in Archive - Int32 askExtractMode (Extract::NAskMode) - if (askMode != NExtract::NAskMode::kExtract) - { - then the callee doesn't write data to stream: (*outStream == NULL) - } - - Out: - (*outStream == NULL) - for directories - (*outStream == NULL) - if link (hard link or symbolic link) was created - if (*outStream == NULL && askMode == NExtract::NAskMode::kExtract) - { - then the caller must skip extracting of that file. - } - - returns: - S_OK : OK - S_FALSE : data error (for decoders) - -if (IProgress::SetTotal() was called) -{ - IProgress::SetCompleted(completeValue) uses - packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd). - unpackSize - for another formats. -} -else -{ - IProgress::SetCompleted(completeValue) uses packSize. -} - -SetOperationResult() - 7-Zip calls SetOperationResult at the end of extracting, - so the callee can close the file, set attributes, timestamps and security information. - - Int32 opRes (NExtract::NOperationResult) -*/ - -// INTERFACE_IProgress(x) - -#define Z7_IFACEM_IArchiveExtractCallback(x) \ - x(GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)) \ - x(PrepareOperation(Int32 askExtractMode)) \ - x(SetOperationResult(Int32 opRes)) \ - -Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallback, IProgress, 0x20) - - - -/* -v23: -IArchiveExtractCallbackMessage2 can be requested from IArchiveExtractCallback object - by Extract() or UpdateItems() functions to report about extracting errors -ReportExtractResult() - UInt32 indexType (NEventIndexType) - UInt32 index - Int32 opRes (NExtract::NOperationResult) -*/ -/* -before v23: -#define Z7_IFACEM_IArchiveExtractCallbackMessage(x) \ - x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) -Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21) -*/ -#define Z7_IFACEM_IArchiveExtractCallbackMessage2(x) \ - x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) -Z7_IFACE_CONSTR_ARCHIVE(IArchiveExtractCallbackMessage2, 0x22) - -#define Z7_IFACEM_IArchiveOpenVolumeCallback(x) \ - x(GetProperty(PROPID propID, PROPVARIANT *value)) \ - x(GetStream(const wchar_t *name, IInStream **inStream)) -Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenVolumeCallback, 0x30) - - -#define Z7_IFACEM_IInArchiveGetStream(x) \ - x(GetStream(UInt32 index, ISequentialInStream **stream)) -Z7_IFACE_CONSTR_ARCHIVE(IInArchiveGetStream, 0x40) - -#define Z7_IFACEM_IArchiveOpenSetSubArchiveName(x) \ - x(SetSubArchiveName(const wchar_t *name)) -Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSetSubArchiveName, 0x50) - - -/* -IInArchive::Open - stream - if (kUseGlobalOffset), stream current position can be non 0. - if (!kUseGlobalOffset), stream current position is 0. - if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream - if (*maxCheckStartPosition == 0), the handler must check only current position as archive start - -IInArchive::Extract: - indices must be sorted - numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files" - testMode != 0 means "test files without writing to outStream" - -IInArchive::GetArchiveProperty: - kpidOffset - start offset of archive. - VT_EMPTY : means offset = 0. - VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed - kpidPhySize - size of archive. VT_EMPTY means unknown size. - kpidPhySize is allowed to be larger than file size. In that case it must show - supposed size. - - kpidIsDeleted: - kpidIsAltStream: - kpidIsAux: - kpidINode: - must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty. - - -Notes: - Don't call IInArchive functions for same IInArchive object from different threads simultaneously. - Some IInArchive handlers will work incorrectly in that case. -*/ - -#if defined(_MSC_VER) && !defined(__clang__) - #define MY_NO_THROW_DECL_ONLY Z7_COM7F_E -#else - #define MY_NO_THROW_DECL_ONLY -#endif - -#define Z7_IFACEM_IInArchive(x) \ - x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \ - x(Close()) \ - x(GetNumberOfItems(UInt32 *numItems)) \ - x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) \ - x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ - x(GetNumberOfProperties(UInt32 *numProps)) \ - x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ - x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IInArchive, 0x60) - -namespace NParentType -{ - enum - { - kDir = 0, - kAltStream - }; -} - -namespace NPropDataType -{ - const UInt32 kMask_ZeroEnd = 1 << 4; - // const UInt32 kMask_BigEndian = 1 << 5; - const UInt32 kMask_Utf = 1 << 6; - const UInt32 kMask_Utf8 = kMask_Utf | 0; - const UInt32 kMask_Utf16 = kMask_Utf | 1; - // const UInt32 kMask_Utf32 = kMask_Utf | 2; - - const UInt32 kNotDefined = 0; - const UInt32 kRaw = 1; - - const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd; - const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd; -} - -// UTF string (pointer to wchar_t) with zero end and little-endian. -#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1)) - - -/* -GetRawProp: - Result: - S_OK - even if property is not set -*/ - -#define Z7_IFACEM_IArchiveGetRawProps(x) \ - x(GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) \ - x(GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \ - x(GetNumRawProps(UInt32 *numProps)) \ - x(GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRawProps, 0x70) - -#define Z7_IFACEM_IArchiveGetRootProps(x) \ - x(GetRootProp(PROPID propID, PROPVARIANT *value)) \ - x(GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRootProps, 0x71) - -#define Z7_IFACEM_IArchiveOpenSeq(x) \ - x(OpenSeq(ISequentialInStream *stream)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSeq, 0x61) - -/* - OpenForSize - Result: - S_FALSE - is not archive - ? - DATA error -*/ - -/* -const UInt32 kOpenFlags_RealPhySize = 1 << 0; -const UInt32 kOpenFlags_NoSeek = 1 << 1; -// const UInt32 kOpenFlags_BeforeExtract = 1 << 2; -*/ - -/* -Flags: - 0 - opens archive with IInStream, if IInStream interface is supported - - if phySize is not available, it doesn't try to make full parse to get phySize - kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available - kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file - - if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified, - the handler can return S_OK, but it doesn't check even Signature. - So next Extract can be called for that sequential stream. -*/ -/* -#define Z7_IFACEM_IArchiveOpen2(x) \ - x(ArcOpen2(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback)) -Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpen2, 0x62) -*/ - -// ---------- UPDATE ---------- - -/* -GetUpdateItemInfo outs: -*newData *newProps - 0 0 - Copy data and properties from archive - 0 1 - Copy data from archive, request new properties - 1 0 - that combination is unused now - 1 1 - Request new data and new properties. It can be used even for folders - - indexInArchive = -1 if there is no item in archive, or if it doesn't matter. - - -GetStream out: - Result: - S_OK: - (*inStream == NULL) - only for directories - - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file - (*inStream != NULL) - for any file, even for empty file or anti-file - S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason) - (*inStream == NULL) - -The order of calling for hard links: - - GetStream() - - GetProperty(kpidHardLink) - -SetOperationResult() - Int32 opRes (NExtract::NOperationResult::kOK) -*/ - -// INTERFACE_IProgress(x) -#define Z7_IFACEM_IArchiveUpdateCallback(x) \ - x(GetUpdateItemInfo(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) \ - x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - x(GetStream(UInt32 index, ISequentialInStream **inStream)) \ - x(SetOperationResult(Int32 operationResult)) \ - -Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback, IProgress, 0x80) - -// INTERFACE_IArchiveUpdateCallback(x) -#define Z7_IFACEM_IArchiveUpdateCallback2(x) \ - x(GetVolumeSize(UInt32 index, UInt64 *size)) \ - x(GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) \ - -Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) - -namespace NUpdateNotifyOp -{ - enum - { - kAdd = 0, - kUpdate, - kAnalyze, - kReplicate, - kRepack, - kSkip, - kDelete, - kHeader, - kHashRead, - kInFileChanged - // , kOpFinished - // , kNumDefined - }; -} - -/* -IArchiveUpdateCallbackFile::ReportOperation - UInt32 indexType (NEventIndexType) - UInt32 index - UInt32 notifyOp (NUpdateNotifyOp) -*/ - -#define Z7_IFACEM_IArchiveUpdateCallbackFile(x) \ - x(GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp)) \ - x(ReportOperation(UInt32 indexType, UInt32 index, UInt32 notifyOp)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackFile, 0x83) - - -#define Z7_IFACEM_IArchiveGetDiskProperty(x) \ - x(GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetDiskProperty, 0x84) - -/* -#define Z7_IFACEM_IArchiveUpdateCallbackArcProp(x) \ - x(ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) \ - x(ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) \ - x(ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) \ - x(DoNeedArcProp(PROPID propID, Int32 *answer)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackArcProp, 0x85) -*/ - -/* -UpdateItems() -------------- - - outStream: output stream. (the handler) MUST support the case when - Seek position in outStream is not ZERO. - but the caller calls with empty outStream and seek position is ZERO?? - - archives with stub: - - If archive is open and the handler and (Offset > 0), then the handler - knows about stub size. - UpdateItems(): - 1) the handler MUST copy that stub to outStream - 2) the caller MUST NOT copy the stub to outStream, if - "rsfx" property is set with SetProperties - - the handler must support the case where - ISequentialOutStream *outStream -*/ - - -#define Z7_IFACEM_IOutArchive(x) \ - x(UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback)) \ - x(GetFileTimeType(UInt32 *type)) - -Z7_IFACE_CONSTR_ARCHIVE(IOutArchive, 0xA0) - - -/* -ISetProperties::SetProperties() - PROPVARIANT values[i].vt: - VT_EMPTY - VT_BOOL - VT_UI4 - if 32-bit number - VT_UI8 - if 64-bit number - VT_BSTR -*/ - -#define Z7_IFACEM_ISetProperties(x) \ - x(SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) - -Z7_IFACE_CONSTR_ARCHIVE(ISetProperties, 0x03) - -#define Z7_IFACEM_IArchiveKeepModeForNextOpen(x) \ - x(KeepModeForNextOpen()) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveKeepModeForNextOpen, 0x04) - -/* Exe handler: the handler for executable format (PE, ELF, Mach-O). - SFX archive: executable stub + some tail data. - before 9.31: exe handler didn't parse SFX archives as executable format. - for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */ - -#define Z7_IFACEM_IArchiveAllowTail(x) \ - x(AllowTail(Int32 allowTail)) \ - -Z7_IFACE_CONSTR_ARCHIVE(IArchiveAllowTail, 0x05) - - -namespace NRequestMemoryUseFlags -{ - const UInt32 k_AllowedSize_WasForced = 1 << 0; // (*allowedSize) was forced by -mmemx or -smemx - const UInt32 k_DefaultLimit_Exceeded = 1 << 1; // default limit of archive format was exceeded - const UInt32 k_MLimit_Exceeded = 1 << 2; // -mmemx value was exceeded - const UInt32 k_SLimit_Exceeded = 1 << 3; // -smemx value was exceeded - - const UInt32 k_NoErrorMessage = 1 << 10; // do not show error message, and show only request - const UInt32 k_IsReport = 1 << 11; // only report is required, without user request - - const UInt32 k_SkipArc_IsExpected = 1 << 12; // NRequestMemoryAnswerFlags::k_SkipArc flag answer is expected - const UInt32 k_Report_SkipArc = 1 << 13; // report about SkipArc operation - - // const UInt32 k_SkipBigFile_IsExpected = 1 << 14; // NRequestMemoryAnswerFlags::k_SkipBigFiles flag answer is expected (unused) - // const UInt32 k_Report_SkipBigFile = 1 << 15; // report about SkipFile operation (unused) - - // const UInt32 k_SkipBigFiles_IsExpected = 1 << 16; // NRequestMemoryAnswerFlags::k_SkipBigFiles flag answer is expected (unused) - // const UInt32 k_Report_SkipBigFiles = 1 << 17; // report that all big files will be skipped (unused) -} - -namespace NRequestMemoryAnswerFlags -{ - const UInt32 k_Allow = 1 << 0; // allow further archive extraction - const UInt32 k_Stop = 1 << 1; // for exit (and return_code == E_ABORT is used) - const UInt32 k_SkipArc = 1 << 2; // skip current archive extraction - // const UInt32 k_SkipBigFile = 1 << 4; // skip extracting of files that exceed limit (unused) - // const UInt32 k_SkipBigFiles = 1 << 5; // skip extracting of files that exceed limit (unused) - const UInt32 k_Limit_Exceeded = 1 << 10; // limit was exceeded -} - -/* - *allowedSize is in/out: - in : default allowed memory usage size or forced size, if it was changed by switch -mmemx. - out : value specified by user or unchanged value. - - *answerFlags is in/out: - *answerFlags must be set by caller before calling for default action, - - indexType : must be set with NEventIndexType::* constant - (indexType == kNoIndex), if request for whole archive. - index : must be set for some (indexType) types (if - fileIndex , if (indexType == NEventIndexType::kInArcIndex) - 0, if if (indexType == kNoIndex) - path : NULL can be used for any indexType. -*/ -#define Z7_IFACEM_IArchiveRequestMemoryUseCallback(x) \ - x(RequestMemoryUse(UInt32 flags, UInt32 indexType, UInt32 index, const wchar_t *path, \ - UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) -Z7_IFACE_CONSTR_ARCHIVE(IArchiveRequestMemoryUseCallback, 0x09) - - -struct CStatProp -{ - const char *Name; - UInt32 PropID; - VARTYPE vt; -}; - -namespace NWindows { -namespace NCOM { -// PropVariant.cpp -BSTR AllocBstrFromAscii(const char *s) throw(); -}} - - -#define IMP_IInArchive_GetProp_Base(fn, f, k) \ - Z7_COM7F_IMF(CHandler::fn(UInt32 *numProps)) \ - { *numProps = Z7_ARRAY_SIZE(k); return S_OK; } \ - Z7_COM7F_IMF(CHandler::f(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \ - -#define IMP_IInArchive_GetProp_NO_NAME(fn, f, k) \ - IMP_IInArchive_GetProp_Base(fn, f, k) \ - *propID = k[index]; \ - *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; \ - *name = NULL; return S_OK; } \ - -#define IMP_IInArchive_GetProp_WITH_NAME(fn, f, k) \ - IMP_IInArchive_GetProp_Base(fn, f, k) \ - const CStatProp &prop = k[index]; \ - *propID = (PROPID)prop.PropID; \ - *varType = prop.vt; \ - *name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \ - - -#define IMP_IInArchive_Props \ - IMP_IInArchive_GetProp_NO_NAME(GetNumberOfProperties, GetPropertyInfo, kProps) - -#define IMP_IInArchive_Props_WITH_NAME \ - IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfProperties, GetPropertyInfo, kProps) - -#define IMP_IInArchive_ArcProps \ - IMP_IInArchive_GetProp_NO_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps) - -#define IMP_IInArchive_ArcProps_WITH_NAME \ - IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps) - -#define IMP_IInArchive_ArcProps_NO_Table \ - Z7_COM7F_IMF(CHandler::GetNumberOfArchiveProperties(UInt32 *numProps)) \ - { *numProps = 0; return S_OK; } \ - Z7_COM7F_IMF(CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *)) \ - { return E_NOTIMPL; } \ - -#define IMP_IInArchive_ArcProps_NO \ - IMP_IInArchive_ArcProps_NO_Table \ - Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value)) \ - { value->vt = VT_EMPTY; return S_OK; } - - -#define Z7_class_CHandler_final \ - Z7_class_final(CHandler) - - -#define Z7_CLASS_IMP_CHandler_IInArchive_0 \ - Z7_CLASS_IMP_COM_1(CHandler, IInArchive) -#define Z7_CLASS_IMP_CHandler_IInArchive_1(i1) \ - Z7_CLASS_IMP_COM_2(CHandler, IInArchive, i1) -#define Z7_CLASS_IMP_CHandler_IInArchive_2(i1, i2) \ - Z7_CLASS_IMP_COM_3(CHandler, IInArchive, i1, i2) -#define Z7_CLASS_IMP_CHandler_IInArchive_3(i1, i2, i3) \ - Z7_CLASS_IMP_COM_4(CHandler, IInArchive, i1, i2, i3) -#define Z7_CLASS_IMP_CHandler_IInArchive_4(i1, i2, i3, i4) \ - Z7_CLASS_IMP_COM_5(CHandler, IInArchive, i1, i2, i3, i4) -#define Z7_CLASS_IMP_CHandler_IInArchive_5(i1, i2, i3, i4, i5) \ - Z7_CLASS_IMP_COM_6(CHandler, IInArchive, i1, i2, i3, i4, i5) - - - -#define k_IsArc_Res_NO 0 -#define k_IsArc_Res_YES 1 -#define k_IsArc_Res_NEED_MORE 2 -// #define k_IsArc_Res_YES_LOW_PROB 3 - -#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI -#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI - -extern "C" -{ - typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject); - - typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size); - typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc); - - typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats); - typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value); - typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value); - - typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); - typedef HRESULT (WINAPI *Func_SetLargePageMode)(); - // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version); - - typedef IOutArchive * (*Func_CreateOutArchive)(); - typedef IInArchive * (*Func_CreateInArchive)(); -} - - -/* - if there is no time in archive, external MTime of archive - will be used instead of _item.Time from archive. - For 7-zip before 22.00 we need to return some supported value. - But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00. - So we return highest precision value supported by old 7-Zip. - new 7-Zip 22.00 doesn't use that value in usual cases. -*/ - - -#define DECLARE_AND_SET_CLIENT_VERSION_VAR -#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ - NFileTimeType::kWindows - -/* -extern UInt32 g_ClientVersion; - -#define GET_CLIENT_VERSION(major, minor) \ - ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor))) - -#define DECLARE_AND_SET_CLIENT_VERSION_VAR \ - UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR); - -#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ - ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \ - (UInt32)(Int32)NFileTimeType::kNotDefined : \ - NFileTimeType::kWindows)) -*/ - -Z7_PURE_INTERFACES_END -#endif +// IArchive.h + +#ifndef ZIP7_INC_IARCHIVE_H +#define ZIP7_INC_IARCHIVE_H + +#include "../IProgress.h" +#include "../IStream.h" +#include "../PropID.h" + +Z7_PURE_INTERFACES_BEGIN + + +#define Z7_IFACE_CONSTR_ARCHIVE_SUB(i, base, n) \ + Z7_DECL_IFACE_7ZIP_SUB(i, base, 6, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACE_CONSTR_ARCHIVE(i, n) \ + Z7_IFACE_CONSTR_ARCHIVE_SUB(i, IUnknown, n) + +/* +How the function in 7-Zip returns object for output parameter via pointer + +1) The caller sets the value of variable before function call: + PROPVARIANT : vt = VT_EMPTY + BSTR : NULL + IUnknown* and derived interfaces : NULL + another scalar types : any non-initialized value is allowed + +2) The callee in current 7-Zip code now can free input object for output parameter: + PROPVARIANT : the callee calls VariantClear(propvaiant_ptr) for input + value stored in variable + another types : the callee ignores stored value. + +3) The callee writes new value to variable for output parameter and + returns execution to caller. + +4) The caller must free or release object returned by the callee: + PROPVARIANT : VariantClear(&propvaiant) + BSTR : SysFreeString(bstr) + IUnknown* and derived interfaces : if (ptr) ptr->Relase() +*/ + + +namespace NFileTimeType +{ + enum EEnum + { + kNotDefined = -1, + kWindows = 0, + kUnix, + kDOS, + k1ns + }; +} + +namespace NArcInfoFlags +{ + const UInt32 kKeepName = 1 << 0; // keep name of file in archive name + const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams + const UInt32 kNtSecure = 1 << 2; // the handler supports NT security + const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive + const UInt32 kMultiSignature = 1 << 4; // there are several signatures + const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset + const UInt32 kStartOpen = 1 << 6; // call handler for each start position + const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file + const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward + const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub) + const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links + const UInt32 kHardLinks = 1 << 11; // the handler supports hard links + const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches + const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums) + const UInt32 kCTime = 1 << 14; + const UInt32 kCTime_Default = 1 << 15; + const UInt32 kATime = 1 << 16; + const UInt32 kATime_Default = 1 << 17; + const UInt32 kMTime = 1 << 18; + const UInt32 kMTime_Default = 1 << 19; + // const UInt32 kTTime_Reserved = 1 << 20; + // const UInt32 kTTime_Reserved_Default = 1 << 21; +} + +namespace NArcInfoTimeFlags +{ + const unsigned kTime_Prec_Mask_bit_index = 0; + const unsigned kTime_Prec_Mask_num_bits = 26; + + const unsigned kTime_Prec_Default_bit_index = 27; + const unsigned kTime_Prec_Default_num_bits = 5; +} + +#define TIME_PREC_TO_ARC_FLAGS_MASK(v) \ + ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (v))) + +#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(v) \ + ((UInt32)(v) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index) + +namespace NArchive +{ + namespace NHandlerPropID + { + enum + { + kName = 0, // VT_BSTR + kClassID, // binary GUID in VT_BSTR + kExtension, // VT_BSTR + kAddExtension, // VT_BSTR + kUpdate, // VT_BOOL + kKeepName, // VT_BOOL + kSignature, // binary in VT_BSTR + kMultiSignature, // binary in VT_BSTR + kSignatureOffset, // VT_UI4 + kAltStreams, // VT_BOOL + kNtSecure, // VT_BOOL + kFlags, // VT_UI4 + kTimeFlags // VT_UI4 + }; + } + + namespace NExtract + { + namespace NAskMode + { + enum + { + kExtract = 0, + kTest, + kSkip, + kReadExternal + }; + } + + namespace NOperationResult + { + enum + { + kOK = 0, + kUnsupportedMethod, + kDataError, + kCRCError, + kUnavailable, + kUnexpectedEnd, + kDataAfterEnd, + kIsNotArc, + kHeadersError, + kWrongPassword + // , kMemError + }; + } + } + + namespace NEventIndexType + { + enum + { + kNoIndex = 0, + kInArcIndex, + kBlockIndex, + kOutArcIndex + // kArcProp + }; + } + + namespace NUpdate + { + namespace NOperationResult + { + enum + { + kOK = 0 + // kError = 1, + // kError_FileChanged + }; + } + } +} + +#define Z7_IFACEM_IArchiveOpenCallback(x) \ + x(SetTotal(const UInt64 *files, const UInt64 *bytes)) \ + x(SetCompleted(const UInt64 *files, const UInt64 *bytes)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenCallback, 0x10) + +/* +IArchiveExtractCallback:: + +7-Zip doesn't call IArchiveExtractCallback functions + GetStream() + PrepareOperation() + SetOperationResult() +from different threads simultaneously. +But 7-Zip can call functions for IProgress or ICompressProgressInfo functions +from another threads simultaneously with calls for IArchiveExtractCallback interface. + +IArchiveExtractCallback::GetStream() + UInt32 index - index of item in Archive + Int32 askExtractMode (Extract::NAskMode) + if (askMode != NExtract::NAskMode::kExtract) + { + then the callee doesn't write data to stream: (*outStream == NULL) + } + + Out: + (*outStream == NULL) - for directories + (*outStream == NULL) - if link (hard link or symbolic link) was created + if (*outStream == NULL && askMode == NExtract::NAskMode::kExtract) + { + then the caller must skip extracting of that file. + } + + returns: + S_OK : OK + S_FALSE : data error (for decoders) + +if (IProgress::SetTotal() was called) +{ + IProgress::SetCompleted(completeValue) uses + packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd). + unpackSize - for another formats. +} +else +{ + IProgress::SetCompleted(completeValue) uses packSize. +} + +SetOperationResult() + 7-Zip calls SetOperationResult at the end of extracting, + so the callee can close the file, set attributes, timestamps and security information. + + Int32 opRes (NExtract::NOperationResult) +*/ + +// INTERFACE_IProgress(x) + +#define Z7_IFACEM_IArchiveExtractCallback(x) \ + x(GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)) \ + x(PrepareOperation(Int32 askExtractMode)) \ + x(SetOperationResult(Int32 opRes)) \ + +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallback, IProgress, 0x20) + + + +/* +v23: +IArchiveExtractCallbackMessage2 can be requested from IArchiveExtractCallback object + by Extract() or UpdateItems() functions to report about extracting errors +ReportExtractResult() + UInt32 indexType (NEventIndexType) + UInt32 index + Int32 opRes (NExtract::NOperationResult) +*/ +/* +before v23: +#define Z7_IFACEM_IArchiveExtractCallbackMessage(x) \ + x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21) +*/ +#define Z7_IFACEM_IArchiveExtractCallbackMessage2(x) \ + x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveExtractCallbackMessage2, 0x22) + +#define Z7_IFACEM_IArchiveOpenVolumeCallback(x) \ + x(GetProperty(PROPID propID, PROPVARIANT *value)) \ + x(GetStream(const wchar_t *name, IInStream **inStream)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenVolumeCallback, 0x30) + + +#define Z7_IFACEM_IInArchiveGetStream(x) \ + x(GetStream(UInt32 index, ISequentialInStream **stream)) +Z7_IFACE_CONSTR_ARCHIVE(IInArchiveGetStream, 0x40) + +#define Z7_IFACEM_IArchiveOpenSetSubArchiveName(x) \ + x(SetSubArchiveName(const wchar_t *name)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSetSubArchiveName, 0x50) + + +/* +IInArchive::Open + stream + if (kUseGlobalOffset), stream current position can be non 0. + if (!kUseGlobalOffset), stream current position is 0. + if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream + if (*maxCheckStartPosition == 0), the handler must check only current position as archive start + +IInArchive::Extract: + indices must be sorted + numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files" + testMode != 0 means "test files without writing to outStream" + +IInArchive::GetArchiveProperty: + kpidOffset - start offset of archive. + VT_EMPTY : means offset = 0. + VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed + kpidPhySize - size of archive. VT_EMPTY means unknown size. + kpidPhySize is allowed to be larger than file size. In that case it must show + supposed size. + + kpidIsDeleted: + kpidIsAltStream: + kpidIsAux: + kpidINode: + must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty. + + +Notes: + Don't call IInArchive functions for same IInArchive object from different threads simultaneously. + Some IInArchive handlers will work incorrectly in that case. +*/ + +#if defined(_MSC_VER) && !defined(__clang__) + #define MY_NO_THROW_DECL_ONLY Z7_COM7F_E +#else + #define MY_NO_THROW_DECL_ONLY +#endif + +#define Z7_IFACEM_IInArchive(x) \ + x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \ + x(Close()) \ + x(GetNumberOfItems(UInt32 *numItems)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) \ + x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ + x(GetNumberOfProperties(UInt32 *numProps)) \ + x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ + x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IInArchive, 0x60) + +namespace NParentType +{ + enum + { + kDir = 0, + kAltStream + }; +} + +namespace NPropDataType +{ + const UInt32 kMask_ZeroEnd = 1 << 4; + // const UInt32 kMask_BigEndian = 1 << 5; + const UInt32 kMask_Utf = 1 << 6; + const UInt32 kMask_Utf8 = kMask_Utf | 0; + const UInt32 kMask_Utf16 = kMask_Utf | 1; + // const UInt32 kMask_Utf32 = kMask_Utf | 2; + + const UInt32 kNotDefined = 0; + const UInt32 kRaw = 1; + + const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd; + const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd; +} + +// UTF string (pointer to wchar_t) with zero end and little-endian. +#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1)) + + +/* +GetRawProp: + Result: + S_OK - even if property is not set +*/ + +#define Z7_IFACEM_IArchiveGetRawProps(x) \ + x(GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) \ + x(GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \ + x(GetNumRawProps(UInt32 *numProps)) \ + x(GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRawProps, 0x70) + +#define Z7_IFACEM_IArchiveGetRootProps(x) \ + x(GetRootProp(PROPID propID, PROPVARIANT *value)) \ + x(GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRootProps, 0x71) + +#define Z7_IFACEM_IArchiveOpenSeq(x) \ + x(OpenSeq(ISequentialInStream *stream)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSeq, 0x61) + +/* + OpenForSize + Result: + S_FALSE - is not archive + ? - DATA error +*/ + +/* +const UInt32 kOpenFlags_RealPhySize = 1 << 0; +const UInt32 kOpenFlags_NoSeek = 1 << 1; +// const UInt32 kOpenFlags_BeforeExtract = 1 << 2; +*/ + +/* +Flags: + 0 - opens archive with IInStream, if IInStream interface is supported + - if phySize is not available, it doesn't try to make full parse to get phySize + kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available + kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file + + if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified, + the handler can return S_OK, but it doesn't check even Signature. + So next Extract can be called for that sequential stream. +*/ +/* +#define Z7_IFACEM_IArchiveOpen2(x) \ + x(ArcOpen2(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpen2, 0x62) +*/ + +// ---------- UPDATE ---------- + +/* +GetUpdateItemInfo outs: +*newData *newProps + 0 0 - Copy data and properties from archive + 0 1 - Copy data from archive, request new properties + 1 0 - that combination is unused now + 1 1 - Request new data and new properties. It can be used even for folders + + indexInArchive = -1 if there is no item in archive, or if it doesn't matter. + + +GetStream out: + Result: + S_OK: + (*inStream == NULL) - only for directories + - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file + (*inStream != NULL) - for any file, even for empty file or anti-file + S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason) + (*inStream == NULL) + +The order of calling for hard links: + - GetStream() + - GetProperty(kpidHardLink) + +SetOperationResult() + Int32 opRes (NExtract::NOperationResult::kOK) +*/ + +// INTERFACE_IProgress(x) +#define Z7_IFACEM_IArchiveUpdateCallback(x) \ + x(GetUpdateItemInfo(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(GetStream(UInt32 index, ISequentialInStream **inStream)) \ + x(SetOperationResult(Int32 operationResult)) \ + +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback, IProgress, 0x80) + +// INTERFACE_IArchiveUpdateCallback(x) +#define Z7_IFACEM_IArchiveUpdateCallback2(x) \ + x(GetVolumeSize(UInt32 index, UInt64 *size)) \ + x(GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) \ + +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) + +namespace NUpdateNotifyOp +{ + enum + { + kAdd = 0, + kUpdate, + kAnalyze, + kReplicate, + kRepack, + kSkip, + kDelete, + kHeader, + kHashRead, + kInFileChanged + // , kOpFinished + // , kNumDefined + }; +} + +/* +IArchiveUpdateCallbackFile::ReportOperation + UInt32 indexType (NEventIndexType) + UInt32 index + UInt32 notifyOp (NUpdateNotifyOp) +*/ + +#define Z7_IFACEM_IArchiveUpdateCallbackFile(x) \ + x(GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp)) \ + x(ReportOperation(UInt32 indexType, UInt32 index, UInt32 notifyOp)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackFile, 0x83) + + +#define Z7_IFACEM_IArchiveGetDiskProperty(x) \ + x(GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetDiskProperty, 0x84) + +/* +#define Z7_IFACEM_IArchiveUpdateCallbackArcProp(x) \ + x(ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) \ + x(ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) \ + x(ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) \ + x(DoNeedArcProp(PROPID propID, Int32 *answer)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackArcProp, 0x85) +*/ + +/* +UpdateItems() +------------- + + outStream: output stream. (the handler) MUST support the case when + Seek position in outStream is not ZERO. + but the caller calls with empty outStream and seek position is ZERO?? + + archives with stub: + + If archive is open and the handler and (Offset > 0), then the handler + knows about stub size. + UpdateItems(): + 1) the handler MUST copy that stub to outStream + 2) the caller MUST NOT copy the stub to outStream, if + "rsfx" property is set with SetProperties + + the handler must support the case where + ISequentialOutStream *outStream +*/ + + +#define Z7_IFACEM_IOutArchive(x) \ + x(UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback)) \ + x(GetFileTimeType(UInt32 *type)) + +Z7_IFACE_CONSTR_ARCHIVE(IOutArchive, 0xA0) + + +/* +ISetProperties::SetProperties() + PROPVARIANT values[i].vt: + VT_EMPTY + VT_BOOL + VT_UI4 - if 32-bit number + VT_UI8 - if 64-bit number + VT_BSTR +*/ + +#define Z7_IFACEM_ISetProperties(x) \ + x(SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) + +Z7_IFACE_CONSTR_ARCHIVE(ISetProperties, 0x03) + +#define Z7_IFACEM_IArchiveKeepModeForNextOpen(x) \ + x(KeepModeForNextOpen()) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveKeepModeForNextOpen, 0x04) + +/* Exe handler: the handler for executable format (PE, ELF, Mach-O). + SFX archive: executable stub + some tail data. + before 9.31: exe handler didn't parse SFX archives as executable format. + for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */ + +#define Z7_IFACEM_IArchiveAllowTail(x) \ + x(AllowTail(Int32 allowTail)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveAllowTail, 0x05) + + +namespace NRequestMemoryUseFlags +{ + const UInt32 k_AllowedSize_WasForced = 1 << 0; // (*allowedSize) was forced by -mmemx or -smemx + const UInt32 k_DefaultLimit_Exceeded = 1 << 1; // default limit of archive format was exceeded + const UInt32 k_MLimit_Exceeded = 1 << 2; // -mmemx value was exceeded + const UInt32 k_SLimit_Exceeded = 1 << 3; // -smemx value was exceeded + + const UInt32 k_NoErrorMessage = 1 << 10; // do not show error message, and show only request + const UInt32 k_IsReport = 1 << 11; // only report is required, without user request + + const UInt32 k_SkipArc_IsExpected = 1 << 12; // NRequestMemoryAnswerFlags::k_SkipArc flag answer is expected + const UInt32 k_Report_SkipArc = 1 << 13; // report about SkipArc operation + + // const UInt32 k_SkipBigFile_IsExpected = 1 << 14; // NRequestMemoryAnswerFlags::k_SkipBigFiles flag answer is expected (unused) + // const UInt32 k_Report_SkipBigFile = 1 << 15; // report about SkipFile operation (unused) + + // const UInt32 k_SkipBigFiles_IsExpected = 1 << 16; // NRequestMemoryAnswerFlags::k_SkipBigFiles flag answer is expected (unused) + // const UInt32 k_Report_SkipBigFiles = 1 << 17; // report that all big files will be skipped (unused) +} + +namespace NRequestMemoryAnswerFlags +{ + const UInt32 k_Allow = 1 << 0; // allow further archive extraction + const UInt32 k_Stop = 1 << 1; // for exit (and return_code == E_ABORT is used) + const UInt32 k_SkipArc = 1 << 2; // skip current archive extraction + // const UInt32 k_SkipBigFile = 1 << 4; // skip extracting of files that exceed limit (unused) + // const UInt32 k_SkipBigFiles = 1 << 5; // skip extracting of files that exceed limit (unused) + const UInt32 k_Limit_Exceeded = 1 << 10; // limit was exceeded +} + +/* + *allowedSize is in/out: + in : default allowed memory usage size or forced size, if it was changed by switch -mmemx. + out : value specified by user or unchanged value. + + *answerFlags is in/out: + *answerFlags must be set by caller before calling for default action, + + indexType : must be set with NEventIndexType::* constant + (indexType == kNoIndex), if request for whole archive. + index : must be set for some (indexType) types (if + fileIndex , if (indexType == NEventIndexType::kInArcIndex) + 0, if if (indexType == kNoIndex) + path : NULL can be used for any indexType. +*/ +#define Z7_IFACEM_IArchiveRequestMemoryUseCallback(x) \ + x(RequestMemoryUse(UInt32 flags, UInt32 indexType, UInt32 index, const wchar_t *path, \ + UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveRequestMemoryUseCallback, 0x09) + + +struct CStatProp +{ + const char *Name; + UInt32 PropID; + VARTYPE vt; +}; + +namespace NWindows { +namespace NCOM { +// PropVariant.cpp +BSTR AllocBstrFromAscii(const char *s) throw(); +}} + + +#define IMP_IInArchive_GetProp_Base(fn, f, k) \ + Z7_COM7F_IMF(CHandler::fn(UInt32 *numProps)) \ + { *numProps = Z7_ARRAY_SIZE(k); return S_OK; } \ + Z7_COM7F_IMF(CHandler::f(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \ + +#define IMP_IInArchive_GetProp_NO_NAME(fn, f, k) \ + IMP_IInArchive_GetProp_Base(fn, f, k) \ + *propID = k[index]; \ + *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; \ + *name = NULL; return S_OK; } \ + +#define IMP_IInArchive_GetProp_WITH_NAME(fn, f, k) \ + IMP_IInArchive_GetProp_Base(fn, f, k) \ + const CStatProp &prop = k[index]; \ + *propID = (PROPID)prop.PropID; \ + *varType = prop.vt; \ + *name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \ + + +#define IMP_IInArchive_Props \ + IMP_IInArchive_GetProp_NO_NAME(GetNumberOfProperties, GetPropertyInfo, kProps) + +#define IMP_IInArchive_Props_WITH_NAME \ + IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfProperties, GetPropertyInfo, kProps) + +#define IMP_IInArchive_ArcProps \ + IMP_IInArchive_GetProp_NO_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps) + +#define IMP_IInArchive_ArcProps_WITH_NAME \ + IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps) + +#define IMP_IInArchive_ArcProps_NO_Table \ + Z7_COM7F_IMF(CHandler::GetNumberOfArchiveProperties(UInt32 *numProps)) \ + { *numProps = 0; return S_OK; } \ + Z7_COM7F_IMF(CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *)) \ + { return E_NOTIMPL; } \ + +#define IMP_IInArchive_ArcProps_NO \ + IMP_IInArchive_ArcProps_NO_Table \ + Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value)) \ + { value->vt = VT_EMPTY; return S_OK; } + + +#define Z7_class_CHandler_final \ + Z7_class_final(CHandler) + + +#define Z7_CLASS_IMP_CHandler_IInArchive_0 \ + Z7_CLASS_IMP_COM_1(CHandler, IInArchive) +#define Z7_CLASS_IMP_CHandler_IInArchive_1(i1) \ + Z7_CLASS_IMP_COM_2(CHandler, IInArchive, i1) +#define Z7_CLASS_IMP_CHandler_IInArchive_2(i1, i2) \ + Z7_CLASS_IMP_COM_3(CHandler, IInArchive, i1, i2) +#define Z7_CLASS_IMP_CHandler_IInArchive_3(i1, i2, i3) \ + Z7_CLASS_IMP_COM_4(CHandler, IInArchive, i1, i2, i3) +#define Z7_CLASS_IMP_CHandler_IInArchive_4(i1, i2, i3, i4) \ + Z7_CLASS_IMP_COM_5(CHandler, IInArchive, i1, i2, i3, i4) +#define Z7_CLASS_IMP_CHandler_IInArchive_5(i1, i2, i3, i4, i5) \ + Z7_CLASS_IMP_COM_6(CHandler, IInArchive, i1, i2, i3, i4, i5) + + + +#define k_IsArc_Res_NO 0 +#define k_IsArc_Res_YES 1 +#define k_IsArc_Res_NEED_MORE 2 +// #define k_IsArc_Res_YES_LOW_PROB 3 + +#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI +#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI + +extern "C" +{ + typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject); + + typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size); + typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc); + + typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats); + typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value); + typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value); + + typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); + typedef HRESULT (WINAPI *Func_SetLargePageMode)(); + // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version); + + typedef IOutArchive * (*Func_CreateOutArchive)(); + typedef IInArchive * (*Func_CreateInArchive)(); +} + + +/* + if there is no time in archive, external MTime of archive + will be used instead of _item.Time from archive. + For 7-zip before 22.00 we need to return some supported value. + But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00. + So we return highest precision value supported by old 7-Zip. + new 7-Zip 22.00 doesn't use that value in usual cases. +*/ + + +#define DECLARE_AND_SET_CLIENT_VERSION_VAR +#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ + NFileTimeType::kWindows + +/* +extern UInt32 g_ClientVersion; + +#define GET_CLIENT_VERSION(major, minor) \ + ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor))) + +#define DECLARE_AND_SET_CLIENT_VERSION_VAR \ + UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR); + +#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ + ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \ + (UInt32)(Int32)NFileTimeType::kNotDefined : \ + NFileTimeType::kWindows)) +*/ + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp index 21a5eb10b..98ca0a377 100644 --- a/CPP/7zip/Archive/IhexHandler.cpp +++ b/CPP/7zip/Archive/IhexHandler.cpp @@ -1,493 +1,493 @@ -// IhexHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/DynamicBuffer.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringToInt.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/InBuffer.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -namespace NArchive { -namespace NIhex { - -/* We still don't support files with custom record types: 20, 22: used by Samsung */ - -struct CBlock -{ - CByteDynamicBuffer Data; - UInt32 Offset; -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - bool _isArc; - bool _needMoreInput; - bool _dataError; - - UInt64 _phySize; - - CObjectVector _blocks; -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidVa -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _blocks.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_dataError) v |= kpv_ErrorFlags_DataError; - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CBlock &block = _blocks[index]; - switch (propID) - { - case kpidSize: prop = (UInt64)block.Data.GetPos(); break; - case kpidVa: prop = block.Offset; break; - case kpidPath: - { - if (_blocks.Size() != 1) - { - char s[16]; - ConvertUInt32ToString(index, s); - prop = s; - } - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -static int Parse(const Byte *p) -{ - unsigned v0 = p[0]; Z7_PARSE_HEX_DIGIT(v0, return -1;) - unsigned v1 = p[1]; Z7_PARSE_HEX_DIGIT(v1, return -1;) - return (int)((v0 << 4) | v1); -} - -#define kType_Data 0 -#define kType_Eof 1 -#define kType_Seg 2 -// #define kType_CsIp 3 -#define kType_High 4 -// #define kType_Ip32 5 - -#define kType_MAX 5 - -// we don't want to read files with big number of spaces between records -// it's our limitation (out of specification): -static const unsigned k_NumSpaces_LIMIT = 16 + 1; - -#define IS_LINE_DELIMITER(c) (/* (c) == 0 || */ (c) == 10 || (c) == 13) - -API_FUNC_static_IsArc IsArc_Ihex(const Byte *p, size_t size) -{ - if (size < 1) - return k_IsArc_Res_NEED_MORE; - if (p[0] != ':') - return k_IsArc_Res_NO; - p++; - size--; - - const unsigned kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection - - for (unsigned j = 0; j < kNumLinesToCheck; j++) - { - if (size < 4 * 2) - return k_IsArc_Res_NEED_MORE; - - const int num = Parse(p); - if (num < 0) - return k_IsArc_Res_NO; - - const int type = Parse(p + 6); - if (type < 0 || type > kType_MAX) - return k_IsArc_Res_NO; - - unsigned numChars = ((unsigned)num + 5) * 2; - unsigned sum = 0; - - for (unsigned i = 0; i < numChars; i += 2) - { - if (i + 2 > size) - return k_IsArc_Res_NEED_MORE; - int v = Parse(p + i); - if (v < 0) - return k_IsArc_Res_NO; - sum += (unsigned)v; - } - - if (sum & 0xFF) - return k_IsArc_Res_NO; - - if (type == kType_Data) - { - // we don't want to open :0000000000 files - if (num == 0) - return k_IsArc_Res_NO; - } - else - { - if (type == kType_Eof) - { - if (num != 0) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; - } - if (p[2] != 0 || - p[3] != 0 || - p[4] != 0 || - p[5] != 0) - return k_IsArc_Res_NO; - if (type == kType_Seg || type == kType_High) - { - if (num != 2) - return k_IsArc_Res_NO; - } - else - { - if (num != 4) - return k_IsArc_Res_NO; - } - } - - p += numChars; - size -= numChars; - - unsigned numSpaces = k_NumSpaces_LIMIT; - for (;;) - { - if (size == 0) - return k_IsArc_Res_NEED_MORE; - const Byte b = *p++; - size--; - if (b == ':') - break; - if (--numSpaces == 0 || !IS_LINE_DELIMITER(b)) - return k_IsArc_Res_NO; - } - } - - return k_IsArc_Res_YES; -} -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) -{ - COM_TRY_BEGIN - { - Close(); - try - { - const unsigned kStartSize = (2 + (256 + 5) + 2) * 2; - Byte temp[kStartSize]; - { - size_t size = kStartSize; - RINOK(ReadStream(stream, temp, &size)) - const UInt32 isArcRes = IsArc_Ihex(temp, size); - if (isArcRes == k_IsArc_Res_NO) - return S_FALSE; - if (isArcRes == k_IsArc_Res_NEED_MORE && size != kStartSize) - return S_FALSE; - } - _isArc = true; - - RINOK(InStream_SeekToBegin(stream)) - CInBuffer s; - if (!s.Create(1 << 15)) - return E_OUTOFMEMORY; - s.SetStream(stream); - s.Init(); - { - Byte b; - if (!s.ReadByte(b)) - { - _needMoreInput = true; - return S_FALSE; - } - if (b != ':') - { - _dataError = true; - return S_FALSE; - } - } - - UInt32 globalOffset = 0; - const UInt32 k_progressStep = 1 << 24; - UInt64 progressNext = k_progressStep; - - for (;;) - { - if (s.ReadBytes(temp, 2) != 2) - { - _needMoreInput = true; - return S_FALSE; - } - const int num = Parse(temp); - if (num < 0) - { - _dataError = true; - return S_FALSE; - } - { - const size_t numPairs = (unsigned)num + 4; - const size_t numBytes = numPairs * 2; - if (s.ReadBytes(temp, numBytes) != numBytes) - { - _needMoreInput = true; - return S_FALSE; - } - unsigned sum = (unsigned)num; - for (size_t i = 0; i < numPairs; i++) - { - const int a = Parse(temp + i * 2); - if (a < 0) - { - _dataError = true; - return S_FALSE; - } - temp[i] = (Byte)a; - sum += (unsigned)a; - } - if (sum & 0xFF) - { - _dataError = true; - return S_FALSE; - } - } - - const unsigned type = temp[2]; - if (type > kType_MAX) - { - _dataError = true; - return S_FALSE; - } - - const UInt32 a = GetBe16(temp); - - if (type == kType_Data) - { - if (num == 0) - { - // we don't want to open :0000000000 files - // maybe it can mean EOF in old-style files? - _dataError = true; - return S_FALSE; - } - // if (num != 0) - { - const UInt32 offs = globalOffset + a; - CBlock *block = NULL; - if (!_blocks.IsEmpty()) - { - block = &_blocks.Back(); - if (block->Offset + block->Data.GetPos() != offs) - block = NULL; - } - if (!block) - { - block = &_blocks.AddNew(); - block->Offset = offs; - } - block->Data.AddData(temp + 3, (unsigned)num); - } - } - else - { - if (a != 0) // from description: the address field is typically 0. - { - _dataError = true; - return S_FALSE; - } - if (type == kType_Eof) - { - if (num != 0) - { - _dataError = true; - return S_FALSE; - } - _phySize = s.GetProcessedSize(); - Byte b; - if (s.ReadByte(b)) - { - if (b == 10) - _phySize++; - else if (b == 13) - { - _phySize++; - if (s.ReadByte(b)) - { - if (b == 10) - _phySize++; - } - } - } - return S_OK; - } - - if (type == kType_Seg || type == kType_High) - { - if (num != 2) - { - _dataError = true; - return S_FALSE; - } - // here we use optimization trick for num shift calculation: (type == kType_Seg ? 4 : 16) - globalOffset = (UInt32)GetBe16(temp + 3) << (1u << type); - } - else - { - if (num != 4) - { - _dataError = true; - return S_FALSE; - } - } - } - - if (openCallback) - { - const UInt64 processed = s.GetProcessedSize(); - if (processed >= progressNext) - { - progressNext = processed + k_progressStep; - const UInt64 numFiles = _blocks.Size(); - RINOK(openCallback->SetCompleted(&numFiles, &processed)) - } - } - - unsigned numSpaces = k_NumSpaces_LIMIT; - for (;;) - { - Byte b; - if (!s.ReadByte(b)) - { - _needMoreInput = true; - return S_FALSE; - } - if (b == ':') - break; - if (--numSpaces == 0 || !IS_LINE_DELIMITER(b)) - { - _dataError = true; - return S_FALSE; - } - } - } - } - catch(const CInBufferException &e) { return e.ErrorCode; } - } - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - _isArc = false; - _needMoreInput = false; - _dataError = false; - _blocks.Clear(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _blocks.Size(); - if (numItems == 0) - return S_OK; - - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _blocks[allFilesMode ? i : indices[i]].Data.GetPos(); - RINOK(extractCallback->SetTotal(totalSize)) - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - for (i = 0;; i++) - { - lps->InSize = lps->OutSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - const UInt32 index = allFilesMode ? i : indices[i]; - const CByteDynamicBuffer &data = _blocks[index].Data; - lps->OutSize += data.GetPos(); - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - if (realOutStream) - RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetPos())) - } - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - - return S_OK; - COM_TRY_END -} - -// k_Signature: { ':' } - -REGISTER_ARC_I_NO_SIG( - "IHex", "ihex", NULL, 0xCD, - 0, - NArcInfoFlags::kStartOpen, - IsArc_Ihex) - -}} +// IhexHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/DynamicBuffer.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringToInt.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/InBuffer.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +namespace NArchive { +namespace NIhex { + +/* We still don't support files with custom record types: 20, 22: used by Samsung */ + +struct CBlock +{ + CByteDynamicBuffer Data; + UInt32 Offset; +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + bool _isArc; + bool _needMoreInput; + bool _dataError; + + UInt64 _phySize; + + CObjectVector _blocks; +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidVa +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _blocks.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataError) v |= kpv_ErrorFlags_DataError; + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CBlock &block = _blocks[index]; + switch (propID) + { + case kpidSize: prop = (UInt64)block.Data.GetPos(); break; + case kpidVa: prop = block.Offset; break; + case kpidPath: + { + if (_blocks.Size() != 1) + { + char s[16]; + ConvertUInt32ToString(index, s); + prop = s; + } + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static int Parse(const Byte *p) +{ + unsigned v0 = p[0]; Z7_PARSE_HEX_DIGIT(v0, return -1;) + unsigned v1 = p[1]; Z7_PARSE_HEX_DIGIT(v1, return -1;) + return (int)((v0 << 4) | v1); +} + +#define kType_Data 0 +#define kType_Eof 1 +#define kType_Seg 2 +// #define kType_CsIp 3 +#define kType_High 4 +// #define kType_Ip32 5 + +#define kType_MAX 5 + +// we don't want to read files with big number of spaces between records +// it's our limitation (out of specification): +static const unsigned k_NumSpaces_LIMIT = 16 + 1; + +#define IS_LINE_DELIMITER(c) (/* (c) == 0 || */ (c) == 10 || (c) == 13) + +API_FUNC_static_IsArc IsArc_Ihex(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + if (p[0] != ':') + return k_IsArc_Res_NO; + p++; + size--; + + const unsigned kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection + + for (unsigned j = 0; j < kNumLinesToCheck; j++) + { + if (size < 4 * 2) + return k_IsArc_Res_NEED_MORE; + + const int num = Parse(p); + if (num < 0) + return k_IsArc_Res_NO; + + const int type = Parse(p + 6); + if (type < 0 || type > kType_MAX) + return k_IsArc_Res_NO; + + unsigned numChars = ((unsigned)num + 5) * 2; + unsigned sum = 0; + + for (unsigned i = 0; i < numChars; i += 2) + { + if (i + 2 > size) + return k_IsArc_Res_NEED_MORE; + int v = Parse(p + i); + if (v < 0) + return k_IsArc_Res_NO; + sum += (unsigned)v; + } + + if (sum & 0xFF) + return k_IsArc_Res_NO; + + if (type == kType_Data) + { + // we don't want to open :0000000000 files + if (num == 0) + return k_IsArc_Res_NO; + } + else + { + if (type == kType_Eof) + { + if (num != 0) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; + } + if (p[2] != 0 || + p[3] != 0 || + p[4] != 0 || + p[5] != 0) + return k_IsArc_Res_NO; + if (type == kType_Seg || type == kType_High) + { + if (num != 2) + return k_IsArc_Res_NO; + } + else + { + if (num != 4) + return k_IsArc_Res_NO; + } + } + + p += numChars; + size -= numChars; + + unsigned numSpaces = k_NumSpaces_LIMIT; + for (;;) + { + if (size == 0) + return k_IsArc_Res_NEED_MORE; + const Byte b = *p++; + size--; + if (b == ':') + break; + if (--numSpaces == 0 || !IS_LINE_DELIMITER(b)) + return k_IsArc_Res_NO; + } + } + + return k_IsArc_Res_YES; +} +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) +{ + COM_TRY_BEGIN + { + Close(); + try + { + const unsigned kStartSize = (2 + (256 + 5) + 2) * 2; + Byte temp[kStartSize]; + { + size_t size = kStartSize; + RINOK(ReadStream(stream, temp, &size)) + const UInt32 isArcRes = IsArc_Ihex(temp, size); + if (isArcRes == k_IsArc_Res_NO) + return S_FALSE; + if (isArcRes == k_IsArc_Res_NEED_MORE && size != kStartSize) + return S_FALSE; + } + _isArc = true; + + RINOK(InStream_SeekToBegin(stream)) + CInBuffer s; + if (!s.Create(1 << 15)) + return E_OUTOFMEMORY; + s.SetStream(stream); + s.Init(); + { + Byte b; + if (!s.ReadByte(b)) + { + _needMoreInput = true; + return S_FALSE; + } + if (b != ':') + { + _dataError = true; + return S_FALSE; + } + } + + UInt32 globalOffset = 0; + const UInt32 k_progressStep = 1 << 24; + UInt64 progressNext = k_progressStep; + + for (;;) + { + if (s.ReadBytes(temp, 2) != 2) + { + _needMoreInput = true; + return S_FALSE; + } + const int num = Parse(temp); + if (num < 0) + { + _dataError = true; + return S_FALSE; + } + { + const size_t numPairs = (unsigned)num + 4; + const size_t numBytes = numPairs * 2; + if (s.ReadBytes(temp, numBytes) != numBytes) + { + _needMoreInput = true; + return S_FALSE; + } + unsigned sum = (unsigned)num; + for (size_t i = 0; i < numPairs; i++) + { + const int a = Parse(temp + i * 2); + if (a < 0) + { + _dataError = true; + return S_FALSE; + } + temp[i] = (Byte)a; + sum += (unsigned)a; + } + if (sum & 0xFF) + { + _dataError = true; + return S_FALSE; + } + } + + const unsigned type = temp[2]; + if (type > kType_MAX) + { + _dataError = true; + return S_FALSE; + } + + const UInt32 a = GetBe16(temp); + + if (type == kType_Data) + { + if (num == 0) + { + // we don't want to open :0000000000 files + // maybe it can mean EOF in old-style files? + _dataError = true; + return S_FALSE; + } + // if (num != 0) + { + const UInt32 offs = globalOffset + a; + CBlock *block = NULL; + if (!_blocks.IsEmpty()) + { + block = &_blocks.Back(); + if (block->Offset + block->Data.GetPos() != offs) + block = NULL; + } + if (!block) + { + block = &_blocks.AddNew(); + block->Offset = offs; + } + block->Data.AddData(temp + 3, (unsigned)num); + } + } + else + { + if (a != 0) // from description: the address field is typically 0. + { + _dataError = true; + return S_FALSE; + } + if (type == kType_Eof) + { + if (num != 0) + { + _dataError = true; + return S_FALSE; + } + _phySize = s.GetProcessedSize(); + Byte b; + if (s.ReadByte(b)) + { + if (b == 10) + _phySize++; + else if (b == 13) + { + _phySize++; + if (s.ReadByte(b)) + { + if (b == 10) + _phySize++; + } + } + } + return S_OK; + } + + if (type == kType_Seg || type == kType_High) + { + if (num != 2) + { + _dataError = true; + return S_FALSE; + } + // here we use optimization trick for num shift calculation: (type == kType_Seg ? 4 : 16) + globalOffset = (UInt32)GetBe16(temp + 3) << (1u << type); + } + else + { + if (num != 4) + { + _dataError = true; + return S_FALSE; + } + } + } + + if (openCallback) + { + const UInt64 processed = s.GetProcessedSize(); + if (processed >= progressNext) + { + progressNext = processed + k_progressStep; + const UInt64 numFiles = _blocks.Size(); + RINOK(openCallback->SetCompleted(&numFiles, &processed)) + } + } + + unsigned numSpaces = k_NumSpaces_LIMIT; + for (;;) + { + Byte b; + if (!s.ReadByte(b)) + { + _needMoreInput = true; + return S_FALSE; + } + if (b == ':') + break; + if (--numSpaces == 0 || !IS_LINE_DELIMITER(b)) + { + _dataError = true; + return S_FALSE; + } + } + } + } + catch(const CInBufferException &e) { return e.ErrorCode; } + } + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + _isArc = false; + _needMoreInput = false; + _dataError = false; + _blocks.Clear(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _blocks.Size(); + if (numItems == 0) + return S_OK; + + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _blocks[allFilesMode ? i : indices[i]].Data.GetPos(); + RINOK(extractCallback->SetTotal(totalSize)) + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + for (i = 0;; i++) + { + lps->InSize = lps->OutSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + const UInt32 index = allFilesMode ? i : indices[i]; + const CByteDynamicBuffer &data = _blocks[index].Data; + lps->OutSize += data.GetPos(); + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + if (realOutStream) + RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetPos())) + } + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + + return S_OK; + COM_TRY_END +} + +// k_Signature: { ':' } + +REGISTER_ARC_I_NO_SIG( + "IHex", "ihex", NULL, 0xCD, + 0, + NArcInfoFlags::kStartOpen, + IsArc_Ihex) + +}} diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index e35b51549..c08538651 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -1,496 +1,496 @@ -// IsoHandler.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/MyLinux.h" -#include "../../../Common/StringConvert.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "../Common/ItemNameUtils.h" - -#include "IsoHandler.h" - -using namespace NWindows; -using namespace NTime; - -namespace NArchive { -namespace NIso { - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - // kpidCTime, - // kpidATime, - kpidPosixAttrib, - // kpidUserId, - // kpidGroupId, - // kpidLinks, - kpidSymLink -}; - -static const Byte kArcProps[] = -{ - kpidComment, - kpidCTime, - kpidMTime, - // kpidHeadersSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - { - RINOK(_archive.Open(stream)) - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _archive.Clear(); - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _archive.Refs.Size() + _archive.BootEntries.Size(); - return S_OK; -} - -static void AddString(AString &s, const char *name, const Byte *p, unsigned size) -{ - unsigned i; - for (i = 0; i < size && p[i]; i++); - for (; i > 0 && p[i - 1] == ' '; i--); - if (i != 0) - { - AString d; - d.SetFrom((const char *)p, i); - s += name; - s += ": "; - s += d; - s.Add_LF(); - } -} - -static void AddProp_Size64(AString &s, const char *name, UInt64 size) -{ - s += name; - s += ": "; - s.Add_UInt64(size); - s.Add_LF(); -} - -#define ADD_STRING(n, v) AddString(s, n, vol. v, sizeof(vol. v)) - -static void AddErrorMessage(AString &s, const char *message) -{ - if (!s.IsEmpty()) - s += ". "; - s += message; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (_stream) - { - const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex]; - switch (propID) - { - case kpidComment: - { - AString s; - ADD_STRING("System", SystemId); - ADD_STRING("Volume", VolumeId); - ADD_STRING("VolumeSet", VolumeSetId); - ADD_STRING("Publisher", PublisherId); - ADD_STRING("Preparer", DataPreparerId); - ADD_STRING("Application", ApplicationId); - ADD_STRING("Copyright", CopyrightFileId); - ADD_STRING("Abstract", AbstractFileId); - ADD_STRING("Bib", BibFileId); - // ADD_STRING("EscapeSequence", EscapeSequence); - AddProp_Size64(s, "VolumeSpaceSize", vol.Get_VolumeSpaceSize_inBytes()); - AddProp_Size64(s, "VolumeSetSize", vol.VolumeSetSize); - AddProp_Size64(s, "VolumeSequenceNumber", vol.VolumeSequenceNumber); - - prop = s; - break; - } - case kpidCTime: { vol.CTime.GetFileTime(prop); break; } - case kpidMTime: { vol.MTime.GetFileTime(prop); break; } - } - } - - switch (propID) - { - case kpidPhySize: prop = _archive.PhySize; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; - if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; - prop = v; - break; - } - - case kpidError: - { - AString s; - if (_archive.IncorrectBigEndian) - AddErrorMessage(s, "Incorrect big-endian headers"); - if (_archive.SelfLinkedDirs) - AddErrorMessage(s, "Self-linked directory"); - if (_archive.TooDeepDirs) - AddErrorMessage(s, "Too deep directory levels"); - if (!s.IsEmpty()) - prop = s; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (index >= (UInt32)_archive.Refs.Size()) - { - index -= _archive.Refs.Size(); - const CBootInitialEntry &be = _archive.BootEntries[index]; - switch (propID) - { - case kpidPath: - { - AString s ("[BOOT]" STRING_PATH_SEPARATOR); - if (_archive.BootEntries.Size() != 1) - { - s.Add_UInt32(index + 1); - s.Add_Minus(); - } - s += be.GetName(); - prop = s; - break; - } - case kpidIsDir: prop = false; break; - case kpidSize: - case kpidPackSize: - prop = (UInt64)_archive.GetBootItemSize(index); - break; - } - } - else - { - const CRef &ref = _archive.Refs[index]; - const CDir &item = ref.Dir->_subItems[ref.Index]; - switch (propID) - { - case kpidPath: - // if (item.FileId.GetCapacity() >= 0) - { - UString s; - if (_archive.IsJoliet()) - item.GetPathU(s); - else - s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP); - - if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1') - s.DeleteFrom(s.Len() - 2); - - if (!s.IsEmpty() && s.Back() == L'.') - s.DeleteBack(); - - NItemName::ReplaceToOsSlashes_Remove_TailSlash(s); - prop = s; - } - break; - - case kpidSymLink: - if (_archive.IsSusp) - { - UInt32 mode; - if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode)) - { - if (MY_LIN_S_ISLNK(mode)) - { - AString s8; - if (item.GetSymLink(_archive.SuspSkipSize, s8)) - { - UString s = MultiByteToUnicodeString(s8, CP_OEMCP); - prop = s; - } - } - } - } - break; - - - case kpidPosixAttrib: - /* - case kpidLinks: - case kpidUserId: - case kpidGroupId: - */ - { - if (_archive.IsSusp) - { - UInt32 t = 0; - switch (propID) - { - case kpidPosixAttrib: t = k_Px_Mode; break; - /* - case kpidLinks: t = k_Px_Links; break; - case kpidUserId: t = k_Px_User; break; - case kpidGroupId: t = k_Px_Group; break; - */ - } - UInt32 v; - if (item.GetPx(_archive.SuspSkipSize, t, v)) - prop = v; - } - break; - } - - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: - case kpidPackSize: - if (!item.IsDir()) - prop = (UInt64)ref.TotalSize; - break; - - case kpidMTime: - // case kpidCTime: - // case kpidATime: - { - // if - item.DateTime.GetFileTime(prop); - /* - else - { - UInt32 t = 0; - switch (propID) - { - case kpidMTime: t = k_Tf_MTime; break; - case kpidCTime: t = k_Tf_CTime; break; - case kpidATime: t = k_Tf_ATime; break; - } - CRecordingDateTime dt; - if (item.GetTf(_archive.SuspSkipSize, t, dt)) - { - FILETIME utc; - if (dt.GetFileTime(utc)) - prop = utc; - } - } - */ - break; - } - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _archive.Refs.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - UInt32 index = (allFilesMode ? i : indices[i]); - if (index < (UInt32)_archive.Refs.Size()) - { - const CRef &ref = _archive.Refs[index]; - const CDir &item = ref.Dir->_subItems[ref.Index]; - if (!item.IsDir()) - totalSize += ref.TotalSize; - } - else - totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size()); - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 currentTotalSize = 0; - UInt64 currentItemSize; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - - for (i = 0;; i++, currentTotalSize += currentItemSize) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - currentItemSize = 0; - Int32 opRes = NExtract::NOperationResult::kOK; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - UInt64 blockIndex; - if (index < (UInt32)_archive.Refs.Size()) - { - const CRef &ref = _archive.Refs[index]; - const CDir &item = ref.Dir->_subItems[ref.Index]; - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - currentItemSize = ref.TotalSize; - blockIndex = item.ExtentLocation; - } - else - { - unsigned bootIndex = index - _archive.Refs.Size(); - const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; - currentItemSize = _archive.GetBootItemSize(bootIndex); - blockIndex = be.LoadRBA; - } - - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - - if (index < (UInt32)_archive.Refs.Size()) - { - const CRef &ref = _archive.Refs[index]; - UInt64 offset = 0; - for (UInt32 e = 0; e < ref.NumExtents; e++) - { - const CDir &item2 = ref.Dir->_subItems[ref.Index + e]; - if (item2.Size == 0) - continue; - lps->InSize = lps->OutSize = currentTotalSize + offset; - RINOK(InStream_SeekSet(_stream, (UInt64)item2.ExtentLocation * kBlockSize)) - inStream->Init(item2.Size); - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != item2.Size) - { - opRes = NExtract::NOperationResult::kDataError; - break; - } - offset += item2.Size; - } - } - else - { - RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize)) - inStream->Init(currentItemSize); - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != currentItemSize) - opRes = NExtract::NOperationResult::kDataError; - } - // realOutStream.Release(); - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - UInt64 blockIndex; - UInt64 currentItemSize; - - if (index < _archive.Refs.Size()) - { - const CRef &ref = _archive.Refs[index]; - const CDir &item = ref.Dir->_subItems[ref.Index]; - if (item.IsDir()) - return S_FALSE; - - if (ref.NumExtents > 1) - { - CExtentsStream *extentStreamSpec = new CExtentsStream(); - CMyComPtr extentStream = extentStreamSpec; - - extentStreamSpec->Stream = _stream; - - UInt64 virtOffset = 0; - for (UInt32 i = 0; i < ref.NumExtents; i++) - { - const CDir &item2 = ref.Dir->_subItems[ref.Index + i]; - if (item2.Size == 0) - continue; - CSeekExtent se; - se.Phy = (UInt64)item2.ExtentLocation * kBlockSize; - se.Virt = virtOffset; - extentStreamSpec->Extents.Add(se); - virtOffset += item2.Size; - } - if (virtOffset != ref.TotalSize) - return S_FALSE; - CSeekExtent se; - se.Phy = 0; - se.Virt = virtOffset; - extentStreamSpec->Extents.Add(se); - extentStreamSpec->Init(); - *stream = extentStream.Detach(); - return S_OK; - } - - currentItemSize = item.Size; - blockIndex = item.ExtentLocation; - } - else - { - unsigned bootIndex = index - _archive.Refs.Size(); - const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; - currentItemSize = _archive.GetBootItemSize(bootIndex); - blockIndex = be.LoadRBA; - } - - return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream); - COM_TRY_END -} - -}} +// IsoHandler.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/MyLinux.h" +#include "../../../Common/StringConvert.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/ItemNameUtils.h" + +#include "IsoHandler.h" + +using namespace NWindows; +using namespace NTime; + +namespace NArchive { +namespace NIso { + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + // kpidCTime, + // kpidATime, + kpidPosixAttrib, + // kpidUserId, + // kpidGroupId, + // kpidLinks, + kpidSymLink +}; + +static const Byte kArcProps[] = +{ + kpidComment, + kpidCTime, + kpidMTime, + // kpidHeadersSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + { + RINOK(_archive.Open(stream)) + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _archive.Clear(); + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _archive.Refs.Size() + _archive.BootEntries.Size(); + return S_OK; +} + +static void AddString(AString &s, const char *name, const Byte *p, unsigned size) +{ + unsigned i; + for (i = 0; i < size && p[i]; i++); + for (; i > 0 && p[i - 1] == ' '; i--); + if (i != 0) + { + AString d; + d.SetFrom((const char *)p, i); + s += name; + s += ": "; + s += d; + s.Add_LF(); + } +} + +static void AddProp_Size64(AString &s, const char *name, UInt64 size) +{ + s += name; + s += ": "; + s.Add_UInt64(size); + s.Add_LF(); +} + +#define ADD_STRING(n, v) AddString(s, n, vol. v, sizeof(vol. v)) + +static void AddErrorMessage(AString &s, const char *message) +{ + if (!s.IsEmpty()) + s += ". "; + s += message; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (_stream) + { + const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex]; + switch (propID) + { + case kpidComment: + { + AString s; + ADD_STRING("System", SystemId); + ADD_STRING("Volume", VolumeId); + ADD_STRING("VolumeSet", VolumeSetId); + ADD_STRING("Publisher", PublisherId); + ADD_STRING("Preparer", DataPreparerId); + ADD_STRING("Application", ApplicationId); + ADD_STRING("Copyright", CopyrightFileId); + ADD_STRING("Abstract", AbstractFileId); + ADD_STRING("Bib", BibFileId); + // ADD_STRING("EscapeSequence", EscapeSequence); + AddProp_Size64(s, "VolumeSpaceSize", vol.Get_VolumeSpaceSize_inBytes()); + AddProp_Size64(s, "VolumeSetSize", vol.VolumeSetSize); + AddProp_Size64(s, "VolumeSequenceNumber", vol.VolumeSequenceNumber); + + prop = s; + break; + } + case kpidCTime: { vol.CTime.GetFileTime(prop); break; } + case kpidMTime: { vol.MTime.GetFileTime(prop); break; } + } + } + + switch (propID) + { + case kpidPhySize: prop = _archive.PhySize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; + prop = v; + break; + } + + case kpidError: + { + AString s; + if (_archive.IncorrectBigEndian) + AddErrorMessage(s, "Incorrect big-endian headers"); + if (_archive.SelfLinkedDirs) + AddErrorMessage(s, "Self-linked directory"); + if (_archive.TooDeepDirs) + AddErrorMessage(s, "Too deep directory levels"); + if (!s.IsEmpty()) + prop = s; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (index >= (UInt32)_archive.Refs.Size()) + { + index -= _archive.Refs.Size(); + const CBootInitialEntry &be = _archive.BootEntries[index]; + switch (propID) + { + case kpidPath: + { + AString s ("[BOOT]" STRING_PATH_SEPARATOR); + if (_archive.BootEntries.Size() != 1) + { + s.Add_UInt32(index + 1); + s.Add_Minus(); + } + s += be.GetName(); + prop = s; + break; + } + case kpidIsDir: prop = false; break; + case kpidSize: + case kpidPackSize: + prop = (UInt64)_archive.GetBootItemSize(index); + break; + } + } + else + { + const CRef &ref = _archive.Refs[index]; + const CDir &item = ref.Dir->_subItems[ref.Index]; + switch (propID) + { + case kpidPath: + // if (item.FileId.GetCapacity() >= 0) + { + UString s; + if (_archive.IsJoliet()) + item.GetPathU(s); + else + s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP); + + if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1') + s.DeleteFrom(s.Len() - 2); + + if (!s.IsEmpty() && s.Back() == L'.') + s.DeleteBack(); + + NItemName::ReplaceToOsSlashes_Remove_TailSlash(s); + prop = s; + } + break; + + case kpidSymLink: + if (_archive.IsSusp) + { + UInt32 mode; + if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode)) + { + if (MY_LIN_S_ISLNK(mode)) + { + AString s8; + if (item.GetSymLink(_archive.SuspSkipSize, s8)) + { + UString s = MultiByteToUnicodeString(s8, CP_OEMCP); + prop = s; + } + } + } + } + break; + + + case kpidPosixAttrib: + /* + case kpidLinks: + case kpidUserId: + case kpidGroupId: + */ + { + if (_archive.IsSusp) + { + UInt32 t = 0; + switch (propID) + { + case kpidPosixAttrib: t = k_Px_Mode; break; + /* + case kpidLinks: t = k_Px_Links; break; + case kpidUserId: t = k_Px_User; break; + case kpidGroupId: t = k_Px_Group; break; + */ + } + UInt32 v; + if (item.GetPx(_archive.SuspSkipSize, t, v)) + prop = v; + } + break; + } + + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: + case kpidPackSize: + if (!item.IsDir()) + prop = (UInt64)ref.TotalSize; + break; + + case kpidMTime: + // case kpidCTime: + // case kpidATime: + { + // if + item.DateTime.GetFileTime(prop); + /* + else + { + UInt32 t = 0; + switch (propID) + { + case kpidMTime: t = k_Tf_MTime; break; + case kpidCTime: t = k_Tf_CTime; break; + case kpidATime: t = k_Tf_ATime; break; + } + CRecordingDateTime dt; + if (item.GetTf(_archive.SuspSkipSize, t, dt)) + { + FILETIME utc; + if (dt.GetFileTime(utc)) + prop = utc; + } + } + */ + break; + } + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _archive.Refs.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + UInt32 index = (allFilesMode ? i : indices[i]); + if (index < (UInt32)_archive.Refs.Size()) + { + const CRef &ref = _archive.Refs[index]; + const CDir &item = ref.Dir->_subItems[ref.Index]; + if (!item.IsDir()) + totalSize += ref.TotalSize; + } + else + totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size()); + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 currentTotalSize = 0; + UInt64 currentItemSize; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + + for (i = 0;; i++, currentTotalSize += currentItemSize) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + currentItemSize = 0; + Int32 opRes = NExtract::NOperationResult::kOK; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + UInt64 blockIndex; + if (index < (UInt32)_archive.Refs.Size()) + { + const CRef &ref = _archive.Refs[index]; + const CDir &item = ref.Dir->_subItems[ref.Index]; + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + currentItemSize = ref.TotalSize; + blockIndex = item.ExtentLocation; + } + else + { + unsigned bootIndex = index - _archive.Refs.Size(); + const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; + currentItemSize = _archive.GetBootItemSize(bootIndex); + blockIndex = be.LoadRBA; + } + + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + + if (index < (UInt32)_archive.Refs.Size()) + { + const CRef &ref = _archive.Refs[index]; + UInt64 offset = 0; + for (UInt32 e = 0; e < ref.NumExtents; e++) + { + const CDir &item2 = ref.Dir->_subItems[ref.Index + e]; + if (item2.Size == 0) + continue; + lps->InSize = lps->OutSize = currentTotalSize + offset; + RINOK(InStream_SeekSet(_stream, (UInt64)item2.ExtentLocation * kBlockSize)) + inStream->Init(item2.Size); + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != item2.Size) + { + opRes = NExtract::NOperationResult::kDataError; + break; + } + offset += item2.Size; + } + } + else + { + RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize)) + inStream->Init(currentItemSize); + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != currentItemSize) + opRes = NExtract::NOperationResult::kDataError; + } + // realOutStream.Release(); + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + UInt64 blockIndex; + UInt64 currentItemSize; + + if (index < _archive.Refs.Size()) + { + const CRef &ref = _archive.Refs[index]; + const CDir &item = ref.Dir->_subItems[ref.Index]; + if (item.IsDir()) + return S_FALSE; + + if (ref.NumExtents > 1) + { + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr extentStream = extentStreamSpec; + + extentStreamSpec->Stream = _stream; + + UInt64 virtOffset = 0; + for (UInt32 i = 0; i < ref.NumExtents; i++) + { + const CDir &item2 = ref.Dir->_subItems[ref.Index + i]; + if (item2.Size == 0) + continue; + CSeekExtent se; + se.Phy = (UInt64)item2.ExtentLocation * kBlockSize; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + virtOffset += item2.Size; + } + if (virtOffset != ref.TotalSize) + return S_FALSE; + CSeekExtent se; + se.Phy = 0; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; + } + + currentItemSize = item.Size; + blockIndex = item.ExtentLocation; + } + else + { + unsigned bootIndex = index - _archive.Refs.Size(); + const CBootInitialEntry &be = _archive.BootEntries[bootIndex]; + currentItemSize = _archive.GetBootItemSize(bootIndex); + blockIndex = be.LoadRBA; + } + + return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream); + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Iso/IsoHandler.h b/CPP/7zip/Archive/Iso/IsoHandler.h index b17389370..507814ac3 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.h +++ b/CPP/7zip/Archive/Iso/IsoHandler.h @@ -1,24 +1,24 @@ -// IsoHandler.h - -#ifndef ZIP7_INC_ISO_HANDLER_H -#define ZIP7_INC_ISO_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "IsoIn.h" - -namespace NArchive { -namespace NIso { - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CMyComPtr _stream; - CInArchive _archive; -}; - -}} - -#endif +// IsoHandler.h + +#ifndef ZIP7_INC_ISO_HANDLER_H +#define ZIP7_INC_ISO_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "IsoIn.h" + +namespace NArchive { +namespace NIso { + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CMyComPtr _stream; + CInArchive _archive; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp index f3baf3700..3b59060a1 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.cpp +++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp @@ -1,12 +1,12 @@ -// Archive/Iso/Header.h - -#include "StdAfx.h" - -#include "IsoHeader.h" - -namespace NArchive { -namespace NIso { - -const char * const kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"; - -}} +// Archive/Iso/Header.h + +#include "StdAfx.h" + +#include "IsoHeader.h" + +namespace NArchive { +namespace NIso { + +const char * const kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"; + +}} diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h index 4be926937..0b14c9fbc 100644 --- a/CPP/7zip/Archive/Iso/IsoHeader.h +++ b/CPP/7zip/Archive/Iso/IsoHeader.h @@ -1,64 +1,64 @@ -// Archive/IsoHeader.h - -#ifndef ZIP7_INC_ARCHIVE_ISO_HEADER_H -#define ZIP7_INC_ARCHIVE_ISO_HEADER_H - -#include "../../../Common/MyTypes.h" - -namespace NArchive { -namespace NIso { - -namespace NVolDescType -{ - const Byte kBootRecord = 0; - const Byte kPrimaryVol = 1; - const Byte kSupplementaryVol = 2; - const Byte kVolParttition = 3; - const Byte kTerminator = 255; -} - -const Byte kVersion = 1; - -namespace NFileFlags -{ - const Byte kDirectory = 1 << 1; - const Byte kNonFinalExtent = 1 << 7; -} - -extern const char * const kElToritoSpec; - -const UInt32 kStartPos = 0x8000; - -namespace NBootEntryId -{ - const Byte kValidationEntry = 1; - const Byte kInitialEntryNotBootable = 0; - const Byte kInitialEntryBootable = 0x88; - - const Byte kMoreHeaders = 0x90; - const Byte kFinalHeader = 0x91; - - const Byte kExtensionIndicator = 0x44; -} - -namespace NBootPlatformId -{ - const Byte kX86 = 0; - const Byte kPowerPC = 1; - const Byte kMac = 2; -} - -const Byte kBootMediaTypeMask = 0xF; - -namespace NBootMediaType -{ - const Byte kNoEmulation = 0; - const Byte k1d2Floppy = 1; - const Byte k1d44Floppy = 2; - const Byte k2d88Floppy = 3; - const Byte kHardDisk = 4; -} - -}} - -#endif +// Archive/IsoHeader.h + +#ifndef ZIP7_INC_ARCHIVE_ISO_HEADER_H +#define ZIP7_INC_ARCHIVE_ISO_HEADER_H + +#include "../../../Common/MyTypes.h" + +namespace NArchive { +namespace NIso { + +namespace NVolDescType +{ + const Byte kBootRecord = 0; + const Byte kPrimaryVol = 1; + const Byte kSupplementaryVol = 2; + const Byte kVolParttition = 3; + const Byte kTerminator = 255; +} + +const Byte kVersion = 1; + +namespace NFileFlags +{ + const Byte kDirectory = 1 << 1; + const Byte kNonFinalExtent = 1 << 7; +} + +extern const char * const kElToritoSpec; + +const UInt32 kStartPos = 0x8000; + +namespace NBootEntryId +{ + const Byte kValidationEntry = 1; + const Byte kInitialEntryNotBootable = 0; + const Byte kInitialEntryBootable = 0x88; + + const Byte kMoreHeaders = 0x90; + const Byte kFinalHeader = 0x91; + + const Byte kExtensionIndicator = 0x44; +} + +namespace NBootPlatformId +{ + const Byte kX86 = 0; + const Byte kPowerPC = 1; + const Byte kMac = 2; +} + +const Byte kBootMediaTypeMask = 0xF; + +namespace NBootMediaType +{ + const Byte kNoEmulation = 0; + const Byte k1d2Floppy = 1; + const Byte k1d44Floppy = 2; + const Byte k2d88Floppy = 3; + const Byte kHardDisk = 4; +} + +}} + +#endif diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 2e2a8ebb1..0054abf06 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -1,735 +1,735 @@ -// Archive/IsoIn.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyException.h" - -#include "../../Common/StreamUtils.h" - -#include "../HandlerCont.h" - -#include "IsoIn.h" - -namespace NArchive { -namespace NIso { - -struct CUnexpectedEndException {}; -struct CHeaderErrorException {}; -struct CEndianErrorException {}; - -static const char * const kMediaTypes[] = -{ - "NoEmul" - , "1.2M" - , "1.44M" - , "2.88M" - , "HardDisk" -}; - -bool CBootInitialEntry::Parse(const Byte *p) -{ - Bootable = (p[0] == NBootEntryId::kInitialEntryBootable); - BootMediaType = p[1]; - LoadSegment = GetUi16(p + 2); - SystemType = p[4]; - SectorCount = GetUi16(p + 6); - LoadRBA = GetUi32(p + 8); - memcpy(VendorSpec, p + 12, 20); - if (p[5] != 0) - return false; - if (p[0] != NBootEntryId::kInitialEntryBootable - && p[0] != NBootEntryId::kInitialEntryNotBootable) - return false; - return true; -} - -AString CBootInitialEntry::GetName() const -{ - AString s (Bootable ? "Boot" : "NotBoot"); - s.Add_Minus(); - - if (BootMediaType < Z7_ARRAY_SIZE(kMediaTypes)) - s += kMediaTypes[BootMediaType]; - else - s.Add_UInt32(BootMediaType); - - if (VendorSpec[0] == 1) - { - // "Language and Version Information (IBM)" - - unsigned i; - for (i = 1; i < sizeof(VendorSpec); i++) - if (VendorSpec[i] > 0x7F) - break; - if (i == sizeof(VendorSpec)) - { - s.Add_Minus(); - for (i = 1; i < sizeof(VendorSpec); i++) - { - char c = (char)VendorSpec[i]; - if (c == 0) - break; - if (c == '\\' || c == '/') - c = '_'; - s += c; - } - } - } - - s += ".img"; - return s; -} - -Byte CInArchive::ReadByte() -{ - if (m_BufferPos >= kBlockSize) - m_BufferPos = 0; - if (m_BufferPos == 0) - { - size_t processed = kBlockSize; - HRESULT res = ReadStream(_stream, m_Buffer, &processed); - if (res != S_OK) - throw CSystemException(res); - if (processed != kBlockSize) - throw CUnexpectedEndException(); - UInt64 end = _position + processed; - if (PhySize < end) - PhySize = end; - } - Byte b = m_Buffer[m_BufferPos++]; - _position++; - return b; -} - -void CInArchive::ReadBytes(Byte *data, UInt32 size) -{ - for (UInt32 i = 0; i < size; i++) - data[i] = ReadByte(); -} - -void CInArchive::Skip(size_t size) -{ - while (size-- != 0) - ReadByte(); -} - -void CInArchive::SkipZeros(size_t size) -{ - while (size-- != 0) - { - Byte b = ReadByte(); - if (b != 0) - throw CHeaderErrorException(); - } -} - -UInt16 CInArchive::ReadUInt16() -{ - Byte b[4]; - ReadBytes(b, 4); - UInt32 val = 0; - for (int i = 0; i < 2; i++) - { - if (b[i] != b[3 - i]) - IncorrectBigEndian = true; - val |= ((UInt32)(b[i]) << (8 * i)); - } - return (UInt16)val; -} - -UInt32 CInArchive::ReadUInt32Le() -{ - UInt32 val = 0; - for (int i = 0; i < 4; i++) - val |= ((UInt32)(ReadByte()) << (8 * i)); - return val; -} - -UInt32 CInArchive::ReadUInt32Be() -{ - UInt32 val = 0; - for (int i = 0; i < 4; i++) - { - val <<= 8; - val |= ReadByte(); - } - return val; -} - -UInt32 CInArchive::ReadUInt32() -{ - Byte b[8]; - ReadBytes(b, 8); - UInt32 val = 0; - for (int i = 0; i < 4; i++) - { - if (b[i] != b[7 - i]) - throw CEndianErrorException(); - val |= ((UInt32)(b[i]) << (8 * i)); - } - return val; -} - -UInt32 CInArchive::ReadDigits(int numDigits) -{ - UInt32 res = 0; - for (int i = 0; i < numDigits; i++) - { - Byte b = ReadByte(); - if (b < '0' || b > '9') - { - if (b == 0 || b == ' ') // it's bug in some CD's - b = '0'; - else - throw CHeaderErrorException(); - } - UInt32 d = (UInt32)(b - '0'); - res *= 10; - res += d; - } - return res; -} - -void CInArchive::ReadDateTime(CDateTime &d) -{ - d.Year = (UInt16)ReadDigits(4); - d.Month = (Byte)ReadDigits(2); - d.Day = (Byte)ReadDigits(2); - d.Hour = (Byte)ReadDigits(2); - d.Minute = (Byte)ReadDigits(2); - d.Second = (Byte)ReadDigits(2); - d.Hundredths = (Byte)ReadDigits(2); - d.GmtOffset = (signed char)ReadByte(); -} - -void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d) -{ - ReadBytes(d.BootSystemId, sizeof(d.BootSystemId)); - ReadBytes(d.BootId, sizeof(d.BootId)); - ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse)); -} - -void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t) -{ - t.Year = ReadByte(); - t.Month = ReadByte(); - t.Day = ReadByte(); - t.Hour = ReadByte(); - t.Minute = ReadByte(); - t.Second = ReadByte(); - t.GmtOffset = (signed char)ReadByte(); -} - -void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) -{ - r.ExtendedAttributeRecordLen = ReadByte(); - if (r.ExtendedAttributeRecordLen != 0) - throw CHeaderErrorException(); - r.ExtentLocation = ReadUInt32(); - r.Size = ReadUInt32(); - ReadRecordingDateTime(r.DateTime); - r.FileFlags = ReadByte(); - r.FileUnitSize = ReadByte(); - r.InterleaveGapSize = ReadByte(); - r.VolSequenceNumber = ReadUInt16(); - Byte idLen = ReadByte(); - r.FileId.Alloc(idLen); - ReadBytes((Byte *)r.FileId, idLen); - unsigned padSize = 1 - (idLen & 1); - - // SkipZeros(padSize); - Skip(padSize); // it's bug in some cd's. Must be zeros - - unsigned curPos = 33 + idLen + padSize; - if (curPos > len) - throw CHeaderErrorException(); - unsigned rem = len - curPos; - r.SystemUse.Alloc(rem); - ReadBytes((Byte *)r.SystemUse, rem); -} - -void CInArchive::ReadDirRecord(CDirRecord &r) -{ - Byte len = ReadByte(); - // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor. - // But maybe we must use real "len" for other records. - len = 34; - ReadDirRecord2(r, len); -} - -void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d) -{ - d.VolFlags = ReadByte(); - ReadBytes(d.SystemId, sizeof(d.SystemId)); - ReadBytes(d.VolumeId, sizeof(d.VolumeId)); - SkipZeros(8); - d.VolumeSpaceSize = ReadUInt32(); - ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence)); - d.VolumeSetSize = ReadUInt16(); - d.VolumeSequenceNumber = ReadUInt16(); - d.LogicalBlockSize = ReadUInt16(); - d.PathTableSize = ReadUInt32(); - d.LPathTableLocation = ReadUInt32Le(); - d.LOptionalPathTableLocation = ReadUInt32Le(); - d.MPathTableLocation = ReadUInt32Be(); - d.MOptionalPathTableLocation = ReadUInt32Be(); - ReadDirRecord(d.RootDirRecord); - ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId)); - ReadBytes(d.PublisherId, sizeof(d.PublisherId)); - ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId)); - ReadBytes(d.ApplicationId, sizeof(d.ApplicationId)); - ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId)); - ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId)); - ReadBytes(d.BibFileId, sizeof(d.BibFileId)); - ReadDateTime(d.CTime); - ReadDateTime(d.MTime); - ReadDateTime(d.ExpirationTime); - ReadDateTime(d.EffectiveTime); - const Byte fileStructureVersion = ReadByte(); - // d.FileStructureVersion = fileStructureVersion; - if (fileStructureVersion != 1 && // ECMA-119 - fileStructureVersion != 2) // some ISO files have fileStructureVersion == 2. - { - // v24.05: we ignore that field, because we don't know what exact values are allowed there - // throw CHeaderErrorException(); - } - SkipZeros(1); // (Reserved for future standardization) - ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse)); - // Most ISO contain zeros in the following field (reserved for future standardization). - // But some ISO programs write some data to that area. - // So we disable check for zeros. - Skip(653); // SkipZeros(653); -} - -static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' }; - -/* -static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' }; -static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' }; -static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' }; -static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' }; -*/ - -static inline bool CheckSignature(const Byte *sig, const Byte *data) -{ - for (int i = 0; i < 5; i++) - if (sig[i] != data[i]) - return false; - return true; -} - -void CInArchive::SeekToBlock(UInt32 blockIndex) -{ - const HRESULT res = _stream->Seek( - (Int64)((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize), - STREAM_SEEK_SET, &_position); - if (res != S_OK) - throw CSystemException(res); - m_BufferPos = 0; -} - -static const int kNumLevelsMax = 256; - -void CInArchive::ReadDir(CDir &d, int level) -{ - if (!d.IsDir()) - return; - if (level > kNumLevelsMax) - { - TooDeepDirs = true; - return; - } - - { - FOR_VECTOR (i, UniqStartLocations) - if (UniqStartLocations[i] == d.ExtentLocation) - { - SelfLinkedDirs = true; - return; - } - UniqStartLocations.Add(d.ExtentLocation); - } - - SeekToBlock(d.ExtentLocation); - UInt64 startPos = _position; - - bool firstItem = true; - for (;;) - { - UInt64 offset = _position - startPos; - if (offset >= d.Size) - break; - Byte len = ReadByte(); - if (len == 0) - continue; - CDir subItem; - ReadDirRecord2(subItem, len); - if (firstItem && level == 0) - IsSusp = subItem.CheckSusp(SuspSkipSize); - - if (!subItem.IsSystemItem()) - d._subItems.Add(subItem); - - firstItem = false; - } - FOR_VECTOR (i, d._subItems) - ReadDir(d._subItems[i], level + 1); - - UniqStartLocations.DeleteBack(); -} - -void CInArchive::CreateRefs(CDir &d) -{ - if (!d.IsDir()) - return; - for (unsigned i = 0; i < d._subItems.Size();) - { - CRef ref; - CDir &subItem = d._subItems[i]; - subItem.Parent = &d; - ref.Dir = &d; - ref.Index = i++; - ref.NumExtents = 1; - ref.TotalSize = subItem.Size; - if (subItem.IsNonFinalExtent()) - { - for (;;) - { - if (i == d._subItems.Size()) - { - HeadersError = true; - break; - } - const CDir &next = d._subItems[i]; - if (!subItem.AreMultiPartEqualWith(next)) - break; - i++; - ref.NumExtents++; - ref.TotalSize += next.Size; - if (!next.IsNonFinalExtent()) - break; - } - } - Refs.Add(ref); - CreateRefs(subItem); - } -} - -void CInArchive::ReadBootInfo() -{ - if (!_bootIsDefined) - return; - HeadersError = true; - - if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0) - return; - - UInt32 blockIndex = GetUi32(_bootDesc.BootSystemUse); - SeekToBlock(blockIndex); - - Byte buf[32]; - ReadBytes(buf, 32); - - if (buf[0] != NBootEntryId::kValidationEntry - || buf[2] != 0 - || buf[3] != 0 - || buf[30] != 0x55 - || buf[31] != 0xAA) - return; - - { - UInt32 sum = 0; - for (unsigned i = 0; i < 32; i += 2) - sum += GetUi16(buf + i); - if ((sum & 0xFFFF) != 0) - return; - /* - CBootValidationEntry e; - e.PlatformId = buf[1]; - memcpy(e.Id, buf + 4, sizeof(e.Id)); - // UInt16 checkSum = GetUi16(p + 28); - */ - } - - ReadBytes(buf, 32); - { - CBootInitialEntry e; - if (!e.Parse(buf)) - return; - BootEntries.Add(e); - } - - bool error = false; - - for (;;) - { - ReadBytes(buf, 32); - Byte headerIndicator = buf[0]; - if (headerIndicator != NBootEntryId::kMoreHeaders - && headerIndicator != NBootEntryId::kFinalHeader) - break; - - // Section Header - // Byte platform = p[1]; - unsigned numEntries = GetUi16(buf + 2); - // id[28] - - for (unsigned i = 0; i < numEntries; i++) - { - ReadBytes(buf, 32); - CBootInitialEntry e; - if (!e.Parse(buf)) - { - error = true; - break; - } - if (e.BootMediaType & (1 << 5)) - { - // Section entry extension - for (unsigned j = 0;; j++) - { - ReadBytes(buf, 32); - if (j > 32 || buf[0] != NBootEntryId::kExtensionIndicator) - { - error = true; - break; - } - if ((buf[1] & (1 << 5)) == 0) - break; - // info += (buf + 2, 30) - } - } - BootEntries.Add(e); - } - - if (headerIndicator != NBootEntryId::kMoreHeaders) - break; - } - - HeadersError = error; -} - -HRESULT CInArchive::Open2() -{ - _position = 0; - RINOK(InStream_GetSize_SeekToEnd(_stream, _fileSize)) - if (_fileSize < kStartPos) - return S_FALSE; - RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position)) - - PhySize = _position; - m_BufferPos = 0; - // BlockSize = kBlockSize; - - for (;;) - { - Byte sig[7]; - ReadBytes(sig, 7); - Byte ver = sig[6]; - - if (!CheckSignature(kSig_CD001, sig + 1)) - { - return S_FALSE; - /* - if (sig[0] != 0 || ver != 1) - break; - if (CheckSignature(kSig_BEA01, sig + 1)) - { - } - else if (CheckSignature(kSig_TEA01, sig + 1)) - { - break; - } - else if (CheckSignature(kSig_NSR02, sig + 1)) - { - } - else - break; - SkipZeros(0x800 - 7); - continue; - */ - } - - // version = 2 for ISO 9660:1999? - if (ver > 2) - return S_FALSE; - - if (sig[0] == NVolDescType::kTerminator) - { - break; - // Skip(0x800 - 7); - // continue; - } - - switch (sig[0]) - { - case NVolDescType::kBootRecord: - { - _bootIsDefined = true; - ReadBootRecordDescriptor(_bootDesc); - break; - } - case NVolDescType::kPrimaryVol: - case NVolDescType::kSupplementaryVol: - { - // some ISOs have two PrimaryVols. - CVolumeDescriptor vd; - ReadVolumeDescriptor(vd); - if (sig[0] == NVolDescType::kPrimaryVol) - { - // some burners write "Joliet" Escape Sequence to primary volume - memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence)); - } - VolDescs.Add(vd); - break; - } - default: - break; - } - } - - if (VolDescs.IsEmpty()) - return S_FALSE; - for (MainVolDescIndex = (int)VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) - if (VolDescs[MainVolDescIndex].IsJoliet()) - break; - /* FIXME: some volume can contain Rock Ridge, that is better than - Joliet volume. So we need some way to detect such case */ - // MainVolDescIndex = 0; // to read primary volume - const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; - if (vd.LogicalBlockSize != kBlockSize) - return S_FALSE; - - { - FOR_VECTOR (i, VolDescs) - { - const CVolumeDescriptor &vd2 = VolDescs[i]; - UpdatePhySize(0, vd2.Get_VolumeSpaceSize_inBytes()); - } - } - - - IsArc = true; - - (CDirRecord &)_rootDir = vd.RootDirRecord; - ReadDir(_rootDir, 0); - CreateRefs(_rootDir); - ReadBootInfo(); - - { - FOR_VECTOR (i, Refs) - { - const CRef &ref = Refs[i]; - for (UInt32 j = 0; j < ref.NumExtents; j++) - { - const CDir &item = ref.Dir->_subItems[ref.Index + j]; - if (!item.IsDir() && item.Size != 0) - UpdatePhySize(item.ExtentLocation, item.Size); - } - } - } - - { - // find boot item for expand: - // UEFI Specification : 13.3.2.1. ISO-9660 and El Torito - _expand_BootEntries_index = -1; - FOR_VECTOR (i, BootEntries) - { - const CBootInitialEntry &be = BootEntries[i]; - if (be.SectorCount <= 1 && be.BootMediaType == NBootMediaType::kNoEmulation) - if (_expand_BootEntries_index == -1 - || be.LoadRBA >= BootEntries[_expand_BootEntries_index].LoadRBA) - _expand_BootEntries_index = (int)i; - } - } - - { - FOR_VECTOR (i, BootEntries) - { - const CBootInitialEntry &be = BootEntries[i]; - UpdatePhySize(be.LoadRBA, GetBootItemSize(i)); - } - } - - if (PhySize < _fileSize) - { - UInt64 rem = _fileSize - PhySize; - const UInt64 kRemMax = 1 << 21; - if (rem <= kRemMax) - { - RINOK(InStream_SeekSet(_stream, PhySize)) - bool areThereNonZeros = false; - UInt64 numZeros = 0; - RINOK(ReadZeroTail(_stream, areThereNonZeros, numZeros, kRemMax)) - if (!areThereNonZeros) - PhySize += numZeros; - } - } - - return S_OK; -} - -HRESULT CInArchive::Open(IInStream *inStream) -{ - Clear(); - _stream = inStream; - try { return Open2(); } - catch(const CSystemException &e) { return e.ErrorCode; } - catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } - catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; } - catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; } -} - -void CInArchive::Clear() -{ - IsArc = false; - UnexpectedEnd = false; - HeadersError = false; - IncorrectBigEndian = false; - TooDeepDirs = false; - SelfLinkedDirs = false; - - UniqStartLocations.Clear(); - - Refs.Clear(); - _rootDir.Clear(); - VolDescs.Clear(); - _bootIsDefined = false; - BootEntries.Clear(); - SuspSkipSize = 0; - IsSusp = false; - - _expand_BootEntries_index = -1; -} - - -UInt64 CInArchive::GetBootItemSize(unsigned index) const -{ - const CBootInitialEntry &be = BootEntries[index]; - UInt64 size = be.GetSize(); - if (be.BootMediaType == NBootMediaType::k1d2Floppy) size = 1200 << 10; - else if (be.BootMediaType == NBootMediaType::k1d44Floppy) size = 1440 << 10; - else if (be.BootMediaType == NBootMediaType::k2d88Floppy) size = 2880 << 10; - const UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize; - if (startPos < _fileSize) - { - const UInt64 rem = _fileSize - startPos; - /* - UEFI modification to ISO specification: - because SectorCount is 16-bit, size is limited by (32 MB). - UEFI Specification : - 13.3.2.1. ISO-9660 and El Torito - If the value of Sector Count is set to 0 or 1, - EFI will assume the system partition consumes the space - from the beginning of the "no emulation" image to the end of the CD-ROM. - */ - // - if ((int)index == _expand_BootEntries_index || rem < size) - size = rem; - } - return size; -} - -}} +// Archive/IsoIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyException.h" + +#include "../../Common/StreamUtils.h" + +#include "../HandlerCont.h" + +#include "IsoIn.h" + +namespace NArchive { +namespace NIso { + +struct CUnexpectedEndException {}; +struct CHeaderErrorException {}; +struct CEndianErrorException {}; + +static const char * const kMediaTypes[] = +{ + "NoEmul" + , "1.2M" + , "1.44M" + , "2.88M" + , "HardDisk" +}; + +bool CBootInitialEntry::Parse(const Byte *p) +{ + Bootable = (p[0] == NBootEntryId::kInitialEntryBootable); + BootMediaType = p[1]; + LoadSegment = GetUi16(p + 2); + SystemType = p[4]; + SectorCount = GetUi16(p + 6); + LoadRBA = GetUi32(p + 8); + memcpy(VendorSpec, p + 12, 20); + if (p[5] != 0) + return false; + if (p[0] != NBootEntryId::kInitialEntryBootable + && p[0] != NBootEntryId::kInitialEntryNotBootable) + return false; + return true; +} + +AString CBootInitialEntry::GetName() const +{ + AString s (Bootable ? "Boot" : "NotBoot"); + s.Add_Minus(); + + if (BootMediaType < Z7_ARRAY_SIZE(kMediaTypes)) + s += kMediaTypes[BootMediaType]; + else + s.Add_UInt32(BootMediaType); + + if (VendorSpec[0] == 1) + { + // "Language and Version Information (IBM)" + + unsigned i; + for (i = 1; i < sizeof(VendorSpec); i++) + if (VendorSpec[i] > 0x7F) + break; + if (i == sizeof(VendorSpec)) + { + s.Add_Minus(); + for (i = 1; i < sizeof(VendorSpec); i++) + { + char c = (char)VendorSpec[i]; + if (c == 0) + break; + if (c == '\\' || c == '/') + c = '_'; + s += c; + } + } + } + + s += ".img"; + return s; +} + +Byte CInArchive::ReadByte() +{ + if (m_BufferPos >= kBlockSize) + m_BufferPos = 0; + if (m_BufferPos == 0) + { + size_t processed = kBlockSize; + HRESULT res = ReadStream(_stream, m_Buffer, &processed); + if (res != S_OK) + throw CSystemException(res); + if (processed != kBlockSize) + throw CUnexpectedEndException(); + UInt64 end = _position + processed; + if (PhySize < end) + PhySize = end; + } + Byte b = m_Buffer[m_BufferPos++]; + _position++; + return b; +} + +void CInArchive::ReadBytes(Byte *data, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + data[i] = ReadByte(); +} + +void CInArchive::Skip(size_t size) +{ + while (size-- != 0) + ReadByte(); +} + +void CInArchive::SkipZeros(size_t size) +{ + while (size-- != 0) + { + Byte b = ReadByte(); + if (b != 0) + throw CHeaderErrorException(); + } +} + +UInt16 CInArchive::ReadUInt16() +{ + Byte b[4]; + ReadBytes(b, 4); + UInt32 val = 0; + for (int i = 0; i < 2; i++) + { + if (b[i] != b[3 - i]) + IncorrectBigEndian = true; + val |= ((UInt32)(b[i]) << (8 * i)); + } + return (UInt16)val; +} + +UInt32 CInArchive::ReadUInt32Le() +{ + UInt32 val = 0; + for (int i = 0; i < 4; i++) + val |= ((UInt32)(ReadByte()) << (8 * i)); + return val; +} + +UInt32 CInArchive::ReadUInt32Be() +{ + UInt32 val = 0; + for (int i = 0; i < 4; i++) + { + val <<= 8; + val |= ReadByte(); + } + return val; +} + +UInt32 CInArchive::ReadUInt32() +{ + Byte b[8]; + ReadBytes(b, 8); + UInt32 val = 0; + for (int i = 0; i < 4; i++) + { + if (b[i] != b[7 - i]) + throw CEndianErrorException(); + val |= ((UInt32)(b[i]) << (8 * i)); + } + return val; +} + +UInt32 CInArchive::ReadDigits(int numDigits) +{ + UInt32 res = 0; + for (int i = 0; i < numDigits; i++) + { + Byte b = ReadByte(); + if (b < '0' || b > '9') + { + if (b == 0 || b == ' ') // it's bug in some CD's + b = '0'; + else + throw CHeaderErrorException(); + } + UInt32 d = (UInt32)(b - '0'); + res *= 10; + res += d; + } + return res; +} + +void CInArchive::ReadDateTime(CDateTime &d) +{ + d.Year = (UInt16)ReadDigits(4); + d.Month = (Byte)ReadDigits(2); + d.Day = (Byte)ReadDigits(2); + d.Hour = (Byte)ReadDigits(2); + d.Minute = (Byte)ReadDigits(2); + d.Second = (Byte)ReadDigits(2); + d.Hundredths = (Byte)ReadDigits(2); + d.GmtOffset = (signed char)ReadByte(); +} + +void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d) +{ + ReadBytes(d.BootSystemId, sizeof(d.BootSystemId)); + ReadBytes(d.BootId, sizeof(d.BootId)); + ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse)); +} + +void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t) +{ + t.Year = ReadByte(); + t.Month = ReadByte(); + t.Day = ReadByte(); + t.Hour = ReadByte(); + t.Minute = ReadByte(); + t.Second = ReadByte(); + t.GmtOffset = (signed char)ReadByte(); +} + +void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) +{ + r.ExtendedAttributeRecordLen = ReadByte(); + if (r.ExtendedAttributeRecordLen != 0) + throw CHeaderErrorException(); + r.ExtentLocation = ReadUInt32(); + r.Size = ReadUInt32(); + ReadRecordingDateTime(r.DateTime); + r.FileFlags = ReadByte(); + r.FileUnitSize = ReadByte(); + r.InterleaveGapSize = ReadByte(); + r.VolSequenceNumber = ReadUInt16(); + Byte idLen = ReadByte(); + r.FileId.Alloc(idLen); + ReadBytes((Byte *)r.FileId, idLen); + unsigned padSize = 1 - (idLen & 1); + + // SkipZeros(padSize); + Skip(padSize); // it's bug in some cd's. Must be zeros + + unsigned curPos = 33 + idLen + padSize; + if (curPos > len) + throw CHeaderErrorException(); + unsigned rem = len - curPos; + r.SystemUse.Alloc(rem); + ReadBytes((Byte *)r.SystemUse, rem); +} + +void CInArchive::ReadDirRecord(CDirRecord &r) +{ + Byte len = ReadByte(); + // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor. + // But maybe we must use real "len" for other records. + len = 34; + ReadDirRecord2(r, len); +} + +void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d) +{ + d.VolFlags = ReadByte(); + ReadBytes(d.SystemId, sizeof(d.SystemId)); + ReadBytes(d.VolumeId, sizeof(d.VolumeId)); + SkipZeros(8); + d.VolumeSpaceSize = ReadUInt32(); + ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence)); + d.VolumeSetSize = ReadUInt16(); + d.VolumeSequenceNumber = ReadUInt16(); + d.LogicalBlockSize = ReadUInt16(); + d.PathTableSize = ReadUInt32(); + d.LPathTableLocation = ReadUInt32Le(); + d.LOptionalPathTableLocation = ReadUInt32Le(); + d.MPathTableLocation = ReadUInt32Be(); + d.MOptionalPathTableLocation = ReadUInt32Be(); + ReadDirRecord(d.RootDirRecord); + ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId)); + ReadBytes(d.PublisherId, sizeof(d.PublisherId)); + ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId)); + ReadBytes(d.ApplicationId, sizeof(d.ApplicationId)); + ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId)); + ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId)); + ReadBytes(d.BibFileId, sizeof(d.BibFileId)); + ReadDateTime(d.CTime); + ReadDateTime(d.MTime); + ReadDateTime(d.ExpirationTime); + ReadDateTime(d.EffectiveTime); + const Byte fileStructureVersion = ReadByte(); + // d.FileStructureVersion = fileStructureVersion; + if (fileStructureVersion != 1 && // ECMA-119 + fileStructureVersion != 2) // some ISO files have fileStructureVersion == 2. + { + // v24.05: we ignore that field, because we don't know what exact values are allowed there + // throw CHeaderErrorException(); + } + SkipZeros(1); // (Reserved for future standardization) + ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse)); + // Most ISO contain zeros in the following field (reserved for future standardization). + // But some ISO programs write some data to that area. + // So we disable check for zeros. + Skip(653); // SkipZeros(653); +} + +static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' }; + +/* +static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' }; +static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' }; +static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' }; +static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' }; +*/ + +static inline bool CheckSignature(const Byte *sig, const Byte *data) +{ + for (int i = 0; i < 5; i++) + if (sig[i] != data[i]) + return false; + return true; +} + +void CInArchive::SeekToBlock(UInt32 blockIndex) +{ + const HRESULT res = _stream->Seek( + (Int64)((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize), + STREAM_SEEK_SET, &_position); + if (res != S_OK) + throw CSystemException(res); + m_BufferPos = 0; +} + +static const int kNumLevelsMax = 256; + +void CInArchive::ReadDir(CDir &d, int level) +{ + if (!d.IsDir()) + return; + if (level > kNumLevelsMax) + { + TooDeepDirs = true; + return; + } + + { + FOR_VECTOR (i, UniqStartLocations) + if (UniqStartLocations[i] == d.ExtentLocation) + { + SelfLinkedDirs = true; + return; + } + UniqStartLocations.Add(d.ExtentLocation); + } + + SeekToBlock(d.ExtentLocation); + UInt64 startPos = _position; + + bool firstItem = true; + for (;;) + { + UInt64 offset = _position - startPos; + if (offset >= d.Size) + break; + Byte len = ReadByte(); + if (len == 0) + continue; + CDir subItem; + ReadDirRecord2(subItem, len); + if (firstItem && level == 0) + IsSusp = subItem.CheckSusp(SuspSkipSize); + + if (!subItem.IsSystemItem()) + d._subItems.Add(subItem); + + firstItem = false; + } + FOR_VECTOR (i, d._subItems) + ReadDir(d._subItems[i], level + 1); + + UniqStartLocations.DeleteBack(); +} + +void CInArchive::CreateRefs(CDir &d) +{ + if (!d.IsDir()) + return; + for (unsigned i = 0; i < d._subItems.Size();) + { + CRef ref; + CDir &subItem = d._subItems[i]; + subItem.Parent = &d; + ref.Dir = &d; + ref.Index = i++; + ref.NumExtents = 1; + ref.TotalSize = subItem.Size; + if (subItem.IsNonFinalExtent()) + { + for (;;) + { + if (i == d._subItems.Size()) + { + HeadersError = true; + break; + } + const CDir &next = d._subItems[i]; + if (!subItem.AreMultiPartEqualWith(next)) + break; + i++; + ref.NumExtents++; + ref.TotalSize += next.Size; + if (!next.IsNonFinalExtent()) + break; + } + } + Refs.Add(ref); + CreateRefs(subItem); + } +} + +void CInArchive::ReadBootInfo() +{ + if (!_bootIsDefined) + return; + HeadersError = true; + + if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0) + return; + + UInt32 blockIndex = GetUi32(_bootDesc.BootSystemUse); + SeekToBlock(blockIndex); + + Byte buf[32]; + ReadBytes(buf, 32); + + if (buf[0] != NBootEntryId::kValidationEntry + || buf[2] != 0 + || buf[3] != 0 + || buf[30] != 0x55 + || buf[31] != 0xAA) + return; + + { + UInt32 sum = 0; + for (unsigned i = 0; i < 32; i += 2) + sum += GetUi16(buf + i); + if ((sum & 0xFFFF) != 0) + return; + /* + CBootValidationEntry e; + e.PlatformId = buf[1]; + memcpy(e.Id, buf + 4, sizeof(e.Id)); + // UInt16 checkSum = GetUi16(p + 28); + */ + } + + ReadBytes(buf, 32); + { + CBootInitialEntry e; + if (!e.Parse(buf)) + return; + BootEntries.Add(e); + } + + bool error = false; + + for (;;) + { + ReadBytes(buf, 32); + Byte headerIndicator = buf[0]; + if (headerIndicator != NBootEntryId::kMoreHeaders + && headerIndicator != NBootEntryId::kFinalHeader) + break; + + // Section Header + // Byte platform = p[1]; + unsigned numEntries = GetUi16(buf + 2); + // id[28] + + for (unsigned i = 0; i < numEntries; i++) + { + ReadBytes(buf, 32); + CBootInitialEntry e; + if (!e.Parse(buf)) + { + error = true; + break; + } + if (e.BootMediaType & (1 << 5)) + { + // Section entry extension + for (unsigned j = 0;; j++) + { + ReadBytes(buf, 32); + if (j > 32 || buf[0] != NBootEntryId::kExtensionIndicator) + { + error = true; + break; + } + if ((buf[1] & (1 << 5)) == 0) + break; + // info += (buf + 2, 30) + } + } + BootEntries.Add(e); + } + + if (headerIndicator != NBootEntryId::kMoreHeaders) + break; + } + + HeadersError = error; +} + +HRESULT CInArchive::Open2() +{ + _position = 0; + RINOK(InStream_GetSize_SeekToEnd(_stream, _fileSize)) + if (_fileSize < kStartPos) + return S_FALSE; + RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position)) + + PhySize = _position; + m_BufferPos = 0; + // BlockSize = kBlockSize; + + for (;;) + { + Byte sig[7]; + ReadBytes(sig, 7); + Byte ver = sig[6]; + + if (!CheckSignature(kSig_CD001, sig + 1)) + { + return S_FALSE; + /* + if (sig[0] != 0 || ver != 1) + break; + if (CheckSignature(kSig_BEA01, sig + 1)) + { + } + else if (CheckSignature(kSig_TEA01, sig + 1)) + { + break; + } + else if (CheckSignature(kSig_NSR02, sig + 1)) + { + } + else + break; + SkipZeros(0x800 - 7); + continue; + */ + } + + // version = 2 for ISO 9660:1999? + if (ver > 2) + return S_FALSE; + + if (sig[0] == NVolDescType::kTerminator) + { + break; + // Skip(0x800 - 7); + // continue; + } + + switch (sig[0]) + { + case NVolDescType::kBootRecord: + { + _bootIsDefined = true; + ReadBootRecordDescriptor(_bootDesc); + break; + } + case NVolDescType::kPrimaryVol: + case NVolDescType::kSupplementaryVol: + { + // some ISOs have two PrimaryVols. + CVolumeDescriptor vd; + ReadVolumeDescriptor(vd); + if (sig[0] == NVolDescType::kPrimaryVol) + { + // some burners write "Joliet" Escape Sequence to primary volume + memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence)); + } + VolDescs.Add(vd); + break; + } + default: + break; + } + } + + if (VolDescs.IsEmpty()) + return S_FALSE; + for (MainVolDescIndex = (int)VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) + if (VolDescs[MainVolDescIndex].IsJoliet()) + break; + /* FIXME: some volume can contain Rock Ridge, that is better than + Joliet volume. So we need some way to detect such case */ + // MainVolDescIndex = 0; // to read primary volume + const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; + if (vd.LogicalBlockSize != kBlockSize) + return S_FALSE; + + { + FOR_VECTOR (i, VolDescs) + { + const CVolumeDescriptor &vd2 = VolDescs[i]; + UpdatePhySize(0, vd2.Get_VolumeSpaceSize_inBytes()); + } + } + + + IsArc = true; + + (CDirRecord &)_rootDir = vd.RootDirRecord; + ReadDir(_rootDir, 0); + CreateRefs(_rootDir); + ReadBootInfo(); + + { + FOR_VECTOR (i, Refs) + { + const CRef &ref = Refs[i]; + for (UInt32 j = 0; j < ref.NumExtents; j++) + { + const CDir &item = ref.Dir->_subItems[ref.Index + j]; + if (!item.IsDir() && item.Size != 0) + UpdatePhySize(item.ExtentLocation, item.Size); + } + } + } + + { + // find boot item for expand: + // UEFI Specification : 13.3.2.1. ISO-9660 and El Torito + _expand_BootEntries_index = -1; + FOR_VECTOR (i, BootEntries) + { + const CBootInitialEntry &be = BootEntries[i]; + if (be.SectorCount <= 1 && be.BootMediaType == NBootMediaType::kNoEmulation) + if (_expand_BootEntries_index == -1 + || be.LoadRBA >= BootEntries[_expand_BootEntries_index].LoadRBA) + _expand_BootEntries_index = (int)i; + } + } + + { + FOR_VECTOR (i, BootEntries) + { + const CBootInitialEntry &be = BootEntries[i]; + UpdatePhySize(be.LoadRBA, GetBootItemSize(i)); + } + } + + if (PhySize < _fileSize) + { + UInt64 rem = _fileSize - PhySize; + const UInt64 kRemMax = 1 << 21; + if (rem <= kRemMax) + { + RINOK(InStream_SeekSet(_stream, PhySize)) + bool areThereNonZeros = false; + UInt64 numZeros = 0; + RINOK(ReadZeroTail(_stream, areThereNonZeros, numZeros, kRemMax)) + if (!areThereNonZeros) + PhySize += numZeros; + } + } + + return S_OK; +} + +HRESULT CInArchive::Open(IInStream *inStream) +{ + Clear(); + _stream = inStream; + try { return Open2(); } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } + catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; } + catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; } +} + +void CInArchive::Clear() +{ + IsArc = false; + UnexpectedEnd = false; + HeadersError = false; + IncorrectBigEndian = false; + TooDeepDirs = false; + SelfLinkedDirs = false; + + UniqStartLocations.Clear(); + + Refs.Clear(); + _rootDir.Clear(); + VolDescs.Clear(); + _bootIsDefined = false; + BootEntries.Clear(); + SuspSkipSize = 0; + IsSusp = false; + + _expand_BootEntries_index = -1; +} + + +UInt64 CInArchive::GetBootItemSize(unsigned index) const +{ + const CBootInitialEntry &be = BootEntries[index]; + UInt64 size = be.GetSize(); + if (be.BootMediaType == NBootMediaType::k1d2Floppy) size = 1200 << 10; + else if (be.BootMediaType == NBootMediaType::k1d44Floppy) size = 1440 << 10; + else if (be.BootMediaType == NBootMediaType::k2d88Floppy) size = 2880 << 10; + const UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize; + if (startPos < _fileSize) + { + const UInt64 rem = _fileSize - startPos; + /* + UEFI modification to ISO specification: + because SectorCount is 16-bit, size is limited by (32 MB). + UEFI Specification : + 13.3.2.1. ISO-9660 and El Torito + If the value of Sector Count is set to 0 or 1, + EFI will assume the system partition consumes the space + from the beginning of the "no emulation" image to the end of the CD-ROM. + */ + // + if ((int)index == _expand_BootEntries_index || rem < size) + size = rem; + } + return size; +} + +}} diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index 25f0bf17c..e7d1feec5 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -1,322 +1,322 @@ -// Archive/IsoIn.h - -#ifndef ZIP7_INC_ARCHIVE_ISO_IN_H -#define ZIP7_INC_ARCHIVE_ISO_IN_H - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -#include "IsoHeader.h" -#include "IsoItem.h" - -namespace NArchive { -namespace NIso { - -struct CDir: public CDirRecord -{ - CDir *Parent; - CObjectVector _subItems; - - void Clear() - { - Parent = NULL; - _subItems.Clear(); - } - - AString GetPath(bool checkSusp, unsigned skipSize) const - { - AString s; - - unsigned len = 0; - const CDir *cur = this; - - for (;;) - { - unsigned curLen; - cur->GetNameCur(checkSusp, skipSize, curLen); - len += curLen; - cur = cur->Parent; - if (!cur || !cur->Parent) - break; - len++; - } - - char *p = s.GetBuf_SetEnd(len) + len; - - cur = this; - - for (;;) - { - unsigned curLen; - const Byte *name = cur->GetNameCur(checkSusp, skipSize, curLen); - p -= curLen; - if (curLen != 0) - memcpy(p, name, curLen); - cur = cur->Parent; - if (!cur || !cur->Parent) - break; - p--; - *p = CHAR_PATH_SEPARATOR; - } - - return s; - } - - void GetPathU(UString &s) const - { - s.Empty(); - - unsigned len = 0; - const CDir *cur = this; - - for (;;) - { - unsigned curLen = (unsigned)(cur->FileId.Size() / 2); - const Byte *fid = cur->FileId; - - unsigned i; - for (i = 0; i < curLen; i++) - if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0) - break; - len += i; - cur = cur->Parent; - if (!cur || !cur->Parent) - break; - len++; - } - - wchar_t *p = s.GetBuf_SetEnd(len) + len; - - cur = this; - - for (;;) - { - unsigned curLen = (unsigned)(cur->FileId.Size() / 2); - const Byte *fid = cur->FileId; - - unsigned i; - for (i = 0; i < curLen; i++) - if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0) - break; - curLen = i; - - p -= curLen; - for (i = 0; i < curLen; i++) - p[i] = (wchar_t)(((wchar_t)fid[i * 2] << 8) | fid[i * 2 + 1]); - cur = cur->Parent; - if (!cur || !cur->Parent) - break; - p--; - *p = WCHAR_PATH_SEPARATOR; - } - } -}; - -struct CDateTime -{ - UInt16 Year; - Byte Month; - Byte Day; - Byte Hour; - Byte Minute; - Byte Second; - Byte Hundredths; - signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. - - bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && - Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } - - bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const - { - UInt64 v; - const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v); - if (res) - { - v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60)); - v *= 10000000; - if (Hundredths < 100) - v += (UInt32)Hundredths * 100000; - prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2); - } - return res; - } -}; - -struct CBootRecordDescriptor -{ - Byte BootSystemId[32]; // a-characters - Byte BootId[32]; // a-characters - Byte BootSystemUse[1977]; -}; - -struct CBootValidationEntry -{ - Byte PlatformId; - Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM. -}; - -struct CBootInitialEntry -{ - bool Bootable; - Byte BootMediaType; - UInt16 LoadSegment; - /* This is the load segment for the initial boot image. If this - value is 0 the system will use the traditional segment of 7C0. If this value - is non-zero the system will use the specified segment. This applies to x86 - architectures only. For "flat" model architectures (such as Motorola) this - is the address divided by 10. */ - Byte SystemType; // This must be a copy of byte 5 (System Type) from the - // Partition Table found in the boot image. - UInt16 SectorCount; // This is the number of virtual/emulated sectors the system - // will store at Load Segment during the initial boot procedure. - UInt32 LoadRBA; // This is the start address of the virtual disk. CDs use - // Relative/Logical block addressing. - - Byte VendorSpec[20]; - - UInt32 GetSize() const - { - // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10); - return (UInt32)SectorCount * 512; - } - - bool Parse(const Byte *p); - AString GetName() const; -}; - -struct CVolumeDescriptor -{ - Byte VolFlags; - Byte SystemId[32]; // a-characters. An identification of a system - // which can recognize and act upon the content of the Logical - // Sectors with logical Sector Numbers 0 to 15 of the volume. - Byte VolumeId[32]; // d-characters. An identification of the volume. - UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded - Byte EscapeSequence[32]; - UInt16 VolumeSetSize; - UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member. - UInt16 LogicalBlockSize; - UInt32 PathTableSize; - UInt32 LPathTableLocation; - UInt32 LOptionalPathTableLocation; - UInt32 MPathTableLocation; - UInt32 MOptionalPathTableLocation; - CDirRecord RootDirRecord; - Byte VolumeSetId[128]; - Byte PublisherId[128]; - Byte DataPreparerId[128]; - Byte ApplicationId[128]; - Byte CopyrightFileId[37]; - Byte AbstractFileId[37]; - Byte BibFileId[37]; - CDateTime CTime; - CDateTime MTime; - CDateTime ExpirationTime; - CDateTime EffectiveTime; - // Byte FileStructureVersion; // = 1; - Byte ApplicationUse[512]; - - bool IsJoliet() const - { - if ((VolFlags & 1) != 0) - return false; - const Byte b = EscapeSequence[2]; - return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F && - (b == 0x40 || b == 0x43 || b == 0x45)); - } - - UInt64 Get_VolumeSpaceSize_inBytes() const { return (UInt64)VolumeSpaceSize * LogicalBlockSize; } -}; - -struct CRef -{ - const CDir *Dir; - UInt32 Index; - UInt32 NumExtents; - UInt64 TotalSize; -}; - -const UInt32 kBlockSize = 1 << 11; - -class CInArchive -{ - IInStream *_stream; - UInt64 _position; - - UInt32 m_BufferPos; - - void Skip(size_t size); - void SkipZeros(size_t size); - Byte ReadByte(); - void ReadBytes(Byte *data, UInt32 size); - UInt16 ReadUInt16(); - UInt32 ReadUInt32Le(); - UInt32 ReadUInt32Be(); - UInt32 ReadUInt32(); - UInt64 ReadUInt64(); - UInt32 ReadDigits(int numDigits); - void ReadDateTime(CDateTime &d); - void ReadRecordingDateTime(CRecordingDateTime &t); - void ReadDirRecord2(CDirRecord &r, Byte len); - void ReadDirRecord(CDirRecord &r); - - void ReadBootRecordDescriptor(CBootRecordDescriptor &d); - void ReadVolumeDescriptor(CVolumeDescriptor &d); - - void SeekToBlock(UInt32 blockIndex); - void ReadDir(CDir &d, int level); - void CreateRefs(CDir &d); - - void ReadBootInfo(); - HRESULT Open2(); -public: - HRESULT Open(IInStream *inStream); - void Clear(); - - UInt64 _fileSize; - UInt64 PhySize; - - CRecordVector Refs; - CObjectVector VolDescs; - int MainVolDescIndex; - // UInt32 BlockSize; - CObjectVector BootEntries; - -private: - bool _bootIsDefined; -public: - bool IsArc; - bool UnexpectedEnd; - bool HeadersError; - bool IncorrectBigEndian; - bool TooDeepDirs; - bool SelfLinkedDirs; - bool IsSusp; - unsigned SuspSkipSize; - - int _expand_BootEntries_index; - - CRecordVector UniqStartLocations; - - void UpdatePhySize(const UInt32 blockIndex, const UInt64 size) - { - const UInt64 alignedSize = (size + kBlockSize - 1) & ~((UInt64)kBlockSize - 1); - const UInt64 end = (UInt64)blockIndex * kBlockSize + alignedSize; - if (PhySize < end) - PhySize = end; - } - - bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } - - UInt64 GetBootItemSize(unsigned index) const; - -private: - CDir _rootDir; - Byte m_Buffer[kBlockSize]; - CBootRecordDescriptor _bootDesc; -}; - -}} - -#endif +// Archive/IsoIn.h + +#ifndef ZIP7_INC_ARCHIVE_ISO_IN_H +#define ZIP7_INC_ARCHIVE_ISO_IN_H + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +#include "IsoHeader.h" +#include "IsoItem.h" + +namespace NArchive { +namespace NIso { + +struct CDir: public CDirRecord +{ + CDir *Parent; + CObjectVector _subItems; + + void Clear() + { + Parent = NULL; + _subItems.Clear(); + } + + AString GetPath(bool checkSusp, unsigned skipSize) const + { + AString s; + + unsigned len = 0; + const CDir *cur = this; + + for (;;) + { + unsigned curLen; + cur->GetNameCur(checkSusp, skipSize, curLen); + len += curLen; + cur = cur->Parent; + if (!cur || !cur->Parent) + break; + len++; + } + + char *p = s.GetBuf_SetEnd(len) + len; + + cur = this; + + for (;;) + { + unsigned curLen; + const Byte *name = cur->GetNameCur(checkSusp, skipSize, curLen); + p -= curLen; + if (curLen != 0) + memcpy(p, name, curLen); + cur = cur->Parent; + if (!cur || !cur->Parent) + break; + p--; + *p = CHAR_PATH_SEPARATOR; + } + + return s; + } + + void GetPathU(UString &s) const + { + s.Empty(); + + unsigned len = 0; + const CDir *cur = this; + + for (;;) + { + unsigned curLen = (unsigned)(cur->FileId.Size() / 2); + const Byte *fid = cur->FileId; + + unsigned i; + for (i = 0; i < curLen; i++) + if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0) + break; + len += i; + cur = cur->Parent; + if (!cur || !cur->Parent) + break; + len++; + } + + wchar_t *p = s.GetBuf_SetEnd(len) + len; + + cur = this; + + for (;;) + { + unsigned curLen = (unsigned)(cur->FileId.Size() / 2); + const Byte *fid = cur->FileId; + + unsigned i; + for (i = 0; i < curLen; i++) + if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0) + break; + curLen = i; + + p -= curLen; + for (i = 0; i < curLen; i++) + p[i] = (wchar_t)(((wchar_t)fid[i * 2] << 8) | fid[i * 2 + 1]); + cur = cur->Parent; + if (!cur || !cur->Parent) + break; + p--; + *p = WCHAR_PATH_SEPARATOR; + } + } +}; + +struct CDateTime +{ + UInt16 Year; + Byte Month; + Byte Day; + Byte Hour; + Byte Minute; + Byte Second; + Byte Hundredths; + signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. + + bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && + Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } + + bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const + { + UInt64 v; + const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v); + if (res) + { + v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60)); + v *= 10000000; + if (Hundredths < 100) + v += (UInt32)Hundredths * 100000; + prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2); + } + return res; + } +}; + +struct CBootRecordDescriptor +{ + Byte BootSystemId[32]; // a-characters + Byte BootId[32]; // a-characters + Byte BootSystemUse[1977]; +}; + +struct CBootValidationEntry +{ + Byte PlatformId; + Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM. +}; + +struct CBootInitialEntry +{ + bool Bootable; + Byte BootMediaType; + UInt16 LoadSegment; + /* This is the load segment for the initial boot image. If this + value is 0 the system will use the traditional segment of 7C0. If this value + is non-zero the system will use the specified segment. This applies to x86 + architectures only. For "flat" model architectures (such as Motorola) this + is the address divided by 10. */ + Byte SystemType; // This must be a copy of byte 5 (System Type) from the + // Partition Table found in the boot image. + UInt16 SectorCount; // This is the number of virtual/emulated sectors the system + // will store at Load Segment during the initial boot procedure. + UInt32 LoadRBA; // This is the start address of the virtual disk. CDs use + // Relative/Logical block addressing. + + Byte VendorSpec[20]; + + UInt32 GetSize() const + { + // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10); + return (UInt32)SectorCount * 512; + } + + bool Parse(const Byte *p); + AString GetName() const; +}; + +struct CVolumeDescriptor +{ + Byte VolFlags; + Byte SystemId[32]; // a-characters. An identification of a system + // which can recognize and act upon the content of the Logical + // Sectors with logical Sector Numbers 0 to 15 of the volume. + Byte VolumeId[32]; // d-characters. An identification of the volume. + UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded + Byte EscapeSequence[32]; + UInt16 VolumeSetSize; + UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member. + UInt16 LogicalBlockSize; + UInt32 PathTableSize; + UInt32 LPathTableLocation; + UInt32 LOptionalPathTableLocation; + UInt32 MPathTableLocation; + UInt32 MOptionalPathTableLocation; + CDirRecord RootDirRecord; + Byte VolumeSetId[128]; + Byte PublisherId[128]; + Byte DataPreparerId[128]; + Byte ApplicationId[128]; + Byte CopyrightFileId[37]; + Byte AbstractFileId[37]; + Byte BibFileId[37]; + CDateTime CTime; + CDateTime MTime; + CDateTime ExpirationTime; + CDateTime EffectiveTime; + // Byte FileStructureVersion; // = 1; + Byte ApplicationUse[512]; + + bool IsJoliet() const + { + if ((VolFlags & 1) != 0) + return false; + const Byte b = EscapeSequence[2]; + return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F && + (b == 0x40 || b == 0x43 || b == 0x45)); + } + + UInt64 Get_VolumeSpaceSize_inBytes() const { return (UInt64)VolumeSpaceSize * LogicalBlockSize; } +}; + +struct CRef +{ + const CDir *Dir; + UInt32 Index; + UInt32 NumExtents; + UInt64 TotalSize; +}; + +const UInt32 kBlockSize = 1 << 11; + +class CInArchive +{ + IInStream *_stream; + UInt64 _position; + + UInt32 m_BufferPos; + + void Skip(size_t size); + void SkipZeros(size_t size); + Byte ReadByte(); + void ReadBytes(Byte *data, UInt32 size); + UInt16 ReadUInt16(); + UInt32 ReadUInt32Le(); + UInt32 ReadUInt32Be(); + UInt32 ReadUInt32(); + UInt64 ReadUInt64(); + UInt32 ReadDigits(int numDigits); + void ReadDateTime(CDateTime &d); + void ReadRecordingDateTime(CRecordingDateTime &t); + void ReadDirRecord2(CDirRecord &r, Byte len); + void ReadDirRecord(CDirRecord &r); + + void ReadBootRecordDescriptor(CBootRecordDescriptor &d); + void ReadVolumeDescriptor(CVolumeDescriptor &d); + + void SeekToBlock(UInt32 blockIndex); + void ReadDir(CDir &d, int level); + void CreateRefs(CDir &d); + + void ReadBootInfo(); + HRESULT Open2(); +public: + HRESULT Open(IInStream *inStream); + void Clear(); + + UInt64 _fileSize; + UInt64 PhySize; + + CRecordVector Refs; + CObjectVector VolDescs; + int MainVolDescIndex; + // UInt32 BlockSize; + CObjectVector BootEntries; + +private: + bool _bootIsDefined; +public: + bool IsArc; + bool UnexpectedEnd; + bool HeadersError; + bool IncorrectBigEndian; + bool TooDeepDirs; + bool SelfLinkedDirs; + bool IsSusp; + unsigned SuspSkipSize; + + int _expand_BootEntries_index; + + CRecordVector UniqStartLocations; + + void UpdatePhySize(const UInt32 blockIndex, const UInt64 size) + { + const UInt64 alignedSize = (size + kBlockSize - 1) & ~((UInt64)kBlockSize - 1); + const UInt64 end = (UInt64)blockIndex * kBlockSize + alignedSize; + if (PhySize < end) + PhySize = end; + } + + bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } + + UInt64 GetBootItemSize(unsigned index) const; + +private: + CDir _rootDir; + Byte m_Buffer[kBlockSize]; + CBootRecordDescriptor _bootDesc; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h index b2c100a11..65829d05d 100644 --- a/CPP/7zip/Archive/Iso/IsoItem.h +++ b/CPP/7zip/Archive/Iso/IsoItem.h @@ -1,320 +1,320 @@ -// Archive/IsoItem.h - -#ifndef ZIP7_INC_ARCHIVE_ISO_ITEM_H -#define ZIP7_INC_ARCHIVE_ISO_ITEM_H - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyString.h" -#include "../../../Common/MyBuffer.h" - -#include "../../../Windows/TimeUtils.h" - -#include "IsoHeader.h" - -namespace NArchive { -namespace NIso { - -struct CRecordingDateTime -{ - Byte Year; - Byte Month; - Byte Day; - Byte Hour; - Byte Minute; - Byte Second; - signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. - - bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const - { - UInt64 v; - const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v); - if (res) - { - v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60)); - v *= 10000000; - prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base); - } - return res; - } -}; - -enum EPx -{ - k_Px_Mode, - k_Px_Links, - k_Px_User, - k_Px_Group, - k_Px_SerialNumber - - // k_Px_Num -}; - -/* -enum ETf -{ - k_Tf_CTime, - k_Tf_MTime, - k_Tf_ATime, - k_Tf_Attrib, - k_Tf_Backup, - k_Tf_Expiration, - k_Tf_Effective - - // k_Tf_Num -}; -*/ - -struct CDirRecord -{ - UInt32 ExtentLocation; - UInt32 Size; - CRecordingDateTime DateTime; - Byte FileFlags; - Byte FileUnitSize; - Byte InterleaveGapSize; - Byte ExtendedAttributeRecordLen; - UInt16 VolSequenceNumber; - CByteBuffer FileId; - CByteBuffer SystemUse; - - bool AreMultiPartEqualWith(const CDirRecord &a) const - { - return FileId == a.FileId - && (FileFlags & (~NFileFlags::kNonFinalExtent)) == - (a.FileFlags & (~NFileFlags::kNonFinalExtent)); - } - - bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; } - bool IsNonFinalExtent() const { return (FileFlags & NFileFlags::kNonFinalExtent) != 0; } - - bool IsSystemItem() const - { - if (FileId.Size() != 1) - return false; - Byte b = *(const Byte *)FileId; - return (b == 0 || b == 1); - } - - - const Byte* FindSuspRecord(unsigned skipSize, Byte id0, Byte id1, unsigned &lenRes) const - { - lenRes = 0; - if (SystemUse.Size() < skipSize) - return NULL; - const Byte *p = (const Byte *)SystemUse + skipSize; - unsigned rem = (unsigned)(SystemUse.Size() - skipSize); - while (rem >= 5) - { - unsigned len = p[2]; - if (len < 3 || len > rem) - return NULL; - if (p[0] == id0 && p[1] == id1 && p[3] == 1) - { - if (len < 4) - return NULL; // Check it - lenRes = len - 4; - return p + 4; - } - p += len; - rem -= len; - } - return NULL; - } - - - const Byte* GetNameCur(bool checkSusp, unsigned skipSize, unsigned &nameLenRes) const - { - const Byte *res = NULL; - unsigned len = 0; - if (checkSusp) - res = FindSuspRecord(skipSize, 'N', 'M', len); - if (!res || len < 1) - { - res = (const Byte *)FileId; - len = (unsigned)FileId.Size(); - } - else - { - res++; - len--; - } - unsigned i; - for (i = 0; i < len; i++) - if (res[i] == 0) - break; - nameLenRes = i; - return res; - } - - - bool GetSymLink(unsigned skipSize, AString &link) const - { - link.Empty(); - const Byte *p = NULL; - unsigned len = 0; - p = FindSuspRecord(skipSize, 'S', 'L', len); - if (!p || len < 1) - return false; - - if (*p != 0) - return false; - - p++; - len--; - - while (len != 0) - { - if (len < 2) - return false; - unsigned flags = p[0]; - unsigned cl = p[1]; - p += 2; - len -= 2; - - if (cl > len) - return false; - - bool needSlash = false; - - if (flags & (1 << 1)) link += "./"; - else if (flags & (1 << 2)) link += "../"; - else if (flags & (1 << 3)) link.Add_Slash(); - else - needSlash = true; - - for (unsigned i = 0; i < cl; i++) - { - const Byte c = p[i]; - if (c == 0) - { - break; - // return false; - } - link += (char)c; - } - - p += cl; - len -= cl; - - if (len == 0) - break; - - if (needSlash) - link.Add_Slash(); - } - - return true; - } - - static bool GetLe32Be32(const Byte *p, UInt32 &dest) - { - UInt32 v1 = GetUi32(p); - UInt32 v2 = GetBe32(p + 4); - if (v1 == v2) - { - dest = v1; - return true; - } - return false; - } - - - bool GetPx(unsigned skipSize, unsigned pxType, UInt32 &val) const - { - val = 0; - const Byte *p = NULL; - unsigned len = 0; - p = FindSuspRecord(skipSize, 'P', 'X', len); - if (!p) - return false; - // px.Clear(); - if (len < (pxType + 1) * 8) - return false; - - return GetLe32Be32(p + pxType * 8, val); - } - - /* - bool GetTf(int skipSize, unsigned pxType, CRecordingDateTime &t) const - { - const Byte *p = NULL; - unsigned len = 0; - p = FindSuspRecord(skipSize, 'T', 'F', len); - if (!p) - return false; - if (len < 1) - return false; - Byte flags = *p++; - len--; - - unsigned step = 7; - if (flags & 0x80) - { - step = 17; - return false; - } - - if ((flags & (1 << pxType)) == 0) - return false; - - for (unsigned i = 0; i < pxType; i++) - { - if (len < step) - return false; - if (flags & (1 << i)) - { - p += step; - len -= step; - } - } - - if (len < step) - return false; - - t.Year = p[0]; - t.Month = p[1]; - t.Day = p[2]; - t.Hour = p[3]; - t.Minute = p[4]; - t.Second = p[5]; - t.GmtOffset = (signed char)p[6]; - - return true; - } - */ - - bool CheckSusp(const Byte *p, unsigned &startPos) const - { - if (p[0] == 'S' && - p[1] == 'P' && - p[2] == 0x7 && - p[3] == 0x1 && - p[4] == 0xBE && - p[5] == 0xEF) - { - startPos = p[6]; - return true; - } - return false; - } - - bool CheckSusp(unsigned &startPos) const - { - const Byte *p = (const Byte *)SystemUse; - const size_t len = SystemUse.Size(); - const unsigned kMinLen = 7; - if (len < kMinLen) - return false; - if (CheckSusp(p, startPos)) - return true; - const unsigned kOffset2 = 14; - if (len < kOffset2 + kMinLen) - return false; - return CheckSusp(p + kOffset2, startPos); - } -}; - -}} - -#endif +// Archive/IsoItem.h + +#ifndef ZIP7_INC_ARCHIVE_ISO_ITEM_H +#define ZIP7_INC_ARCHIVE_ISO_ITEM_H + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyString.h" +#include "../../../Common/MyBuffer.h" + +#include "../../../Windows/TimeUtils.h" + +#include "IsoHeader.h" + +namespace NArchive { +namespace NIso { + +struct CRecordingDateTime +{ + Byte Year; + Byte Month; + Byte Day; + Byte Hour; + Byte Minute; + Byte Second; + signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. + + bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const + { + UInt64 v; + const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v); + if (res) + { + v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60)); + v *= 10000000; + prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base); + } + return res; + } +}; + +enum EPx +{ + k_Px_Mode, + k_Px_Links, + k_Px_User, + k_Px_Group, + k_Px_SerialNumber + + // k_Px_Num +}; + +/* +enum ETf +{ + k_Tf_CTime, + k_Tf_MTime, + k_Tf_ATime, + k_Tf_Attrib, + k_Tf_Backup, + k_Tf_Expiration, + k_Tf_Effective + + // k_Tf_Num +}; +*/ + +struct CDirRecord +{ + UInt32 ExtentLocation; + UInt32 Size; + CRecordingDateTime DateTime; + Byte FileFlags; + Byte FileUnitSize; + Byte InterleaveGapSize; + Byte ExtendedAttributeRecordLen; + UInt16 VolSequenceNumber; + CByteBuffer FileId; + CByteBuffer SystemUse; + + bool AreMultiPartEqualWith(const CDirRecord &a) const + { + return FileId == a.FileId + && (FileFlags & (~NFileFlags::kNonFinalExtent)) == + (a.FileFlags & (~NFileFlags::kNonFinalExtent)); + } + + bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; } + bool IsNonFinalExtent() const { return (FileFlags & NFileFlags::kNonFinalExtent) != 0; } + + bool IsSystemItem() const + { + if (FileId.Size() != 1) + return false; + Byte b = *(const Byte *)FileId; + return (b == 0 || b == 1); + } + + + const Byte* FindSuspRecord(unsigned skipSize, Byte id0, Byte id1, unsigned &lenRes) const + { + lenRes = 0; + if (SystemUse.Size() < skipSize) + return NULL; + const Byte *p = (const Byte *)SystemUse + skipSize; + unsigned rem = (unsigned)(SystemUse.Size() - skipSize); + while (rem >= 5) + { + unsigned len = p[2]; + if (len < 3 || len > rem) + return NULL; + if (p[0] == id0 && p[1] == id1 && p[3] == 1) + { + if (len < 4) + return NULL; // Check it + lenRes = len - 4; + return p + 4; + } + p += len; + rem -= len; + } + return NULL; + } + + + const Byte* GetNameCur(bool checkSusp, unsigned skipSize, unsigned &nameLenRes) const + { + const Byte *res = NULL; + unsigned len = 0; + if (checkSusp) + res = FindSuspRecord(skipSize, 'N', 'M', len); + if (!res || len < 1) + { + res = (const Byte *)FileId; + len = (unsigned)FileId.Size(); + } + else + { + res++; + len--; + } + unsigned i; + for (i = 0; i < len; i++) + if (res[i] == 0) + break; + nameLenRes = i; + return res; + } + + + bool GetSymLink(unsigned skipSize, AString &link) const + { + link.Empty(); + const Byte *p = NULL; + unsigned len = 0; + p = FindSuspRecord(skipSize, 'S', 'L', len); + if (!p || len < 1) + return false; + + if (*p != 0) + return false; + + p++; + len--; + + while (len != 0) + { + if (len < 2) + return false; + unsigned flags = p[0]; + unsigned cl = p[1]; + p += 2; + len -= 2; + + if (cl > len) + return false; + + bool needSlash = false; + + if (flags & (1 << 1)) link += "./"; + else if (flags & (1 << 2)) link += "../"; + else if (flags & (1 << 3)) link.Add_Slash(); + else + needSlash = true; + + for (unsigned i = 0; i < cl; i++) + { + const Byte c = p[i]; + if (c == 0) + { + break; + // return false; + } + link += (char)c; + } + + p += cl; + len -= cl; + + if (len == 0) + break; + + if (needSlash) + link.Add_Slash(); + } + + return true; + } + + static bool GetLe32Be32(const Byte *p, UInt32 &dest) + { + UInt32 v1 = GetUi32(p); + UInt32 v2 = GetBe32(p + 4); + if (v1 == v2) + { + dest = v1; + return true; + } + return false; + } + + + bool GetPx(unsigned skipSize, unsigned pxType, UInt32 &val) const + { + val = 0; + const Byte *p = NULL; + unsigned len = 0; + p = FindSuspRecord(skipSize, 'P', 'X', len); + if (!p) + return false; + // px.Clear(); + if (len < (pxType + 1) * 8) + return false; + + return GetLe32Be32(p + pxType * 8, val); + } + + /* + bool GetTf(int skipSize, unsigned pxType, CRecordingDateTime &t) const + { + const Byte *p = NULL; + unsigned len = 0; + p = FindSuspRecord(skipSize, 'T', 'F', len); + if (!p) + return false; + if (len < 1) + return false; + Byte flags = *p++; + len--; + + unsigned step = 7; + if (flags & 0x80) + { + step = 17; + return false; + } + + if ((flags & (1 << pxType)) == 0) + return false; + + for (unsigned i = 0; i < pxType; i++) + { + if (len < step) + return false; + if (flags & (1 << i)) + { + p += step; + len -= step; + } + } + + if (len < step) + return false; + + t.Year = p[0]; + t.Month = p[1]; + t.Day = p[2]; + t.Hour = p[3]; + t.Minute = p[4]; + t.Second = p[5]; + t.GmtOffset = (signed char)p[6]; + + return true; + } + */ + + bool CheckSusp(const Byte *p, unsigned &startPos) const + { + if (p[0] == 'S' && + p[1] == 'P' && + p[2] == 0x7 && + p[3] == 0x1 && + p[4] == 0xBE && + p[5] == 0xEF) + { + startPos = p[6]; + return true; + } + return false; + } + + bool CheckSusp(unsigned &startPos) const + { + const Byte *p = (const Byte *)SystemUse; + const size_t len = SystemUse.Size(); + const unsigned kMinLen = 7; + if (len < kMinLen) + return false; + if (CheckSusp(p, startPos)) + return true; + const unsigned kOffset2 = 14; + if (len < kOffset2 + kMinLen) + return false; + return CheckSusp(p + kOffset2, startPos); + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp index 3ea57f2af..41b56bace 100644 --- a/CPP/7zip/Archive/Iso/IsoRegister.cpp +++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp @@ -1,21 +1,21 @@ -// IsoRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "IsoHandler.h" - -namespace NArchive { -namespace NIso { - -static const Byte k_Signature[] = { 'C', 'D', '0', '0', '1' }; - -REGISTER_ARC_I( - "Iso", "iso img", NULL, 0xE7, - k_Signature, - NArchive::NIso::kStartPos + 1, - 0, - NULL) - -}} +// IsoRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "IsoHandler.h" + +namespace NArchive { +namespace NIso { + +static const Byte k_Signature[] = { 'C', 'D', '0', '0', '1' }; + +REGISTER_ARC_I( + "Iso", "iso img", NULL, 0xE7, + k_Signature, + NArchive::NIso::kStartPos + 1, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Iso/StdAfx.h b/CPP/7zip/Archive/Iso/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Iso/StdAfx.h +++ b/CPP/7zip/Archive/Iso/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/LpHandler.cpp b/CPP/7zip/Archive/LpHandler.cpp index 3906483ce..926b6542b 100644 --- a/CPP/7zip/Archive/LpHandler.cpp +++ b/CPP/7zip/Archive/LpHandler.cpp @@ -1,1166 +1,1170 @@ -// LpHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/Sha256.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(_offs_, dest) dest = Get16(p + (_offs_)); -#define G32(_offs_, dest) dest = Get32(p + (_offs_)); -#define G64(_offs_, dest) dest = Get64(p + (_offs_)); - -using namespace NWindows; - -namespace NArchive { - -namespace NExt { -API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); -} - -namespace NLp { - -/* -Android 10+ use Android's Dynamic Partitions to allow the -different read-only system partitions (e.g. system, vendor, product) -to share the same pool of storage space (as LVM in Linux). -Name for partition: "super" (for GPT) or "super.img" (for file). -Dynamic Partition Tools: lpmake -All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.): -boot_a, boot_b, system_a, system_b, vendor_a, vendor_b. -*/ - -#define LP_METADATA_MAJOR_VERSION 10 -// #define LP_METADATA_MINOR_VERSION_MIN 0 -// #define LP_METADATA_MINOR_VERSION_MAX 2 - -// #define LP_SECTOR_SIZE 512 -static const unsigned kSectorSizeLog = 9; - -/* Amount of space reserved at the start of every super partition to avoid - * creating an accidental boot sector. */ -#define LP_PARTITION_RESERVED_BYTES 4096 -#define LP_METADATA_GEOMETRY_SIZE 4096 -#define LP_METADATA_HEADER_MAGIC 0x414C5030 - -static const unsigned k_SignatureSize = 8; -static const Byte k_Signature[k_SignatureSize] = - { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 }; - -// The length (36) is the same as the maximum length of a GPT partition name. -static const unsigned kNameLen = 36; - -static void AddName36ToString(AString &s, const char *name, bool strictConvert) -{ - for (unsigned i = 0; i < kNameLen; i++) - { - char c = name[i]; - if (c == 0) - return; - if (strictConvert && c < 32) - c = '_'; - s += c; - } -} - - -static const unsigned k_Geometry_Size = 0x34; - -// LpMetadataGeometry -struct CGeometry -{ - // UInt32 magic; - // UInt32 struct_size; - // Byte checksum[32]; /* SHA256 checksum of this struct, with this field set to 0. */ - - /* Maximum amount of space a single copy of the metadata can use, - a multiple of LP_SECTOR_SIZE. */ - UInt32 metadata_max_size; - - /* Number of copies of the metadata to keep. - For Non-A/B: 1, For A/B: 2, for A/B/C: 3. - A backup copy of each slot is kept */ - UInt32 metadata_slot_count; - - /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */ - UInt32 logical_block_size; - - bool Parse(const Byte *p) - { - G32 (40, metadata_max_size) - G32 (44, metadata_slot_count) - G32 (48, logical_block_size) - if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20)) - return false; - if (metadata_max_size == 0) - return false; - if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0) - return false; - return true; - } - - UInt64 GetTotalMetadataSize() const - { - // there are 2 copies of GEOMETRY and METADATA slots - return LP_PARTITION_RESERVED_BYTES + - LP_METADATA_GEOMETRY_SIZE * 2 + - ((UInt64)metadata_max_size * metadata_slot_count) * 2; - } -}; - - - -// LpMetadataTableDescriptor -struct CDescriptor -{ - UInt32 offset; /* Location of the table, relative to end of the metadata header. */ - UInt32 num_entries; /* Number of entries in the table. */ - UInt32 entry_size; /* Size of each entry in the table, in bytes. */ - - void Parse(const Byte *p) - { - G32 (0, offset) - G32 (4, num_entries) - G32 (8, entry_size) - } - - bool CheckLimits(UInt32 limit) const - { - if (entry_size == 0) - return false; - const UInt32 size = num_entries * entry_size; - if (size / entry_size != num_entries) - return false; - if (offset > limit || limit - offset < size) - return false; - return true; - } -}; - - -// #define LP_PARTITION_ATTR_NONE 0x0 -// #define LP_PARTITION_ATTR_READONLY (1 << 0) - -/* This flag is only intended to be used with super_empty.img and super.img on - * retrofit devices. On these devices there are A and B super partitions, and - * we don't know ahead of time which slot the image will be applied to. - * - * If set, the partition name needs a slot suffix applied. The slot suffix is - * determined by the metadata slot number (0 = _a, 1 = _b). - */ -// #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1) - -/* This flag is applied automatically when using MetadataBuilder::NewForUpdate. - * It signals that the partition was created (or modified) for a snapshot-based - * update. If this flag is not present, the partition was likely flashed via - * fastboot. - */ -// #define LP_PARTITION_ATTR_UPDATED (1 << 2) - -/* This flag marks a partition as disabled. It should not be used or mapped. */ -// #define LP_PARTITION_ATTR_DISABLED (1 << 3) - -static const char * const g_PartitionAttr[] = -{ - "READONLY" - , "SLOT_SUFFIXED" - , "UPDATED" - , "DISABLED" -}; - -static unsigned const k_MetaPartition_Size = 52; - -// LpMetadataPartition -struct CPartition -{ - /* ASCII characters: alphanumeric or _. at least one ASCII character, - (name) must be unique across all partition names. */ - char name[kNameLen]; - - UInt32 attributes; /* (LP_PARTITION_ATTR_*). */ - - /* Index of the first extent owned by this partition. The extent will - * start at logical sector 0. Gaps between extents are not allowed. */ - UInt32 first_extent_index; - - /* Number of extents in the partition. Every partition must have at least one extent. */ - UInt32 num_extents; - - /* Group this partition belongs to. */ - UInt32 group_index; - - void Parse(const Byte *p) - { - memcpy(name, p, kNameLen); - G32 (36, attributes) - G32 (40, first_extent_index) - G32 (44, num_extents) - G32 (48, group_index) - } - - // calced properties: - UInt32 MethodsMask; - UInt64 NumSectors; - UInt64 NumSectors_Pack; - const char *Ext; - - UInt64 GetSize() const { return NumSectors << kSectorSizeLog; } - UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; } - - CPartition(): - MethodsMask(0), - NumSectors(0), - NumSectors_Pack(0), - Ext(NULL) - {} -}; - - - - -#define LP_TARGET_TYPE_LINEAR 0 -/* This extent is a dm-zero target. The index is ignored and must be 0. */ -#define LP_TARGET_TYPE_ZERO 1 - -static const char * const g_Methods[] = -{ - "RAW" // "LINEAR" - , "ZERO" -}; - -static unsigned const k_MetaExtent_Size = 24; - -// LpMetadataExtent -struct CExtent -{ - UInt64 num_sectors; /* Length in 512-byte sectors. */ - UInt32 target_type; /* Target type for device-mapper (LP_TARGET_TYPE_*). */ - - /* for LINEAR: The sector on the physical partition that this extent maps onto. - for ZERO: must be 0. */ - UInt64 target_data; - - /* for LINEAR: index into the block devices table. - for ZERO: must be 0. */ - UInt32 target_source; - - bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; } - - void Parse(const Byte *p) - { - G64 (0, num_sectors) - G32 (8, target_type) - G64 (12, target_data) - G32 (20, target_source) - } -}; - - -/* This flag is only intended to be used with super_empty.img and super.img on - * retrofit devices. If set, the group needs a slot suffix to be interpreted - * correctly. The suffix is automatically applied by ReadMetadata(). - */ -// #define LP_GROUP_SLOT_SUFFIXED (1 << 0) -static unsigned const k_Group_Size = 48; - -// LpMetadataPartitionGroup -struct CGroup -{ - char name[kNameLen]; - UInt32 flags; /* (LP_GROUP_*). */ - UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */ - - void Parse(const Byte *p) - { - memcpy(name, p, kNameLen); - G32 (36, flags) - G64 (40, maximum_size) - } -}; - - - - -/* This flag is only intended to be used with super_empty.img and super.img on - * retrofit devices. On these devices there are A and B super partitions, and - * we don't know ahead of time which slot the image will be applied to. - * - * If set, the block device needs a slot suffix applied before being used with - * IPartitionOpener. The slot suffix is determined by the metadata slot number - * (0 = _a, 1 = _b). - */ -// #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0) - -static unsigned const k_Device_Size = 64; - -/* This struct defines an entry in the block_devices table. There must be at - * least one device, and the first device must represent the partition holding - * the super metadata. - */ -// LpMetadataBlockDevice -struct CDevice -{ - /* 0: First usable sector for allocating logical partitions. this will be - * the first sector after the initial geometry blocks, followed by the - * space consumed by metadata_max_size*metadata_slot_count*2. - */ - UInt64 first_logical_sector; - - /* 8: Alignment for defining partitions or partition extents. For example, - * an alignment of 1MiB will require that all partitions have a size evenly - * divisible by 1MiB, and that the smallest unit the partition can grow by - * is 1MiB. - * - * Alignment is normally determined at runtime when growing or adding - * partitions. If for some reason the alignment cannot be determined, then - * this predefined alignment in the geometry is used instead. By default - * it is set to 1MiB. - */ - UInt32 alignment; - - /* 12: Alignment offset for "stacked" devices. For example, if the "super" - * partition itself is not aligned within the parent block device's - * partition table, then we adjust for this in deciding where to place - * |first_logical_sector|. - * - * Similar to |alignment|, this will be derived from the operating system. - * If it cannot be determined, it is assumed to be 0. - */ - UInt32 alignment_offset; - - /* 16: Block device size, as specified when the metadata was created. This - * can be used to verify the geometry against a target device. - */ - UInt64 size; - - /* 24: Partition name in the GPT*/ - char partition_name[kNameLen]; - - /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */ - UInt32 flags; - - void Parse(const Byte *p) - { - memcpy(partition_name, p + 24, kNameLen); - G64 (0, first_logical_sector) - G32 (8, alignment) - G32 (12, alignment_offset) - G64 (16, size) - G32 (60, flags) - } -}; - - -/* This device uses Virtual A/B. Note that on retrofit devices, the expanded - * header may not be present. - */ -// #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1 - -static const char * const g_Header_Flags[] = -{ - "VIRTUAL_AB" -}; - - -static const unsigned k_LpMetadataHeader10_size = 128; -static const unsigned k_LpMetadataHeader12_size = 256; - -struct LpMetadataHeader -{ - /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */ - UInt32 magic; - - /* 4: Version number required to read this metadata. If the version is not - * equal to the library version, the metadata should be considered - * incompatible. - */ - UInt16 major_version; - - /* 6: Minor version. A library supporting newer features should be able to - * read metadata with an older minor version. However, an older library - * should not support reading metadata if its minor version is higher. - */ - UInt16 minor_version; - - /* 8: The size of this header struct. */ - UInt32 header_size; - - /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as - * if this field were set to 0. - */ - // Byte header_checksum[32]; - - /* 44: The total size of all tables. This size is contiguous; tables may not - * have gaps in between, and they immediately follow the header. - */ - UInt32 tables_size; - - /* 48: SHA256 checksum of all table contents. */ - Byte tables_checksum[32]; - - /* 80: Partition table descriptor. */ - CDescriptor partitions; - /* 92: Extent table descriptor. */ - CDescriptor extents; - /* 104: Updateable group descriptor. */ - CDescriptor groups; - /* 116: Block device table. */ - CDescriptor block_devices; - - /* Everything past here is header version 1.2+, and is only included if - * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must - * zero these additional fields. - */ - - /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are - * independent of the version number and intended to be informational only. - * New flags can be added without bumping the version. - */ - // UInt32 flags; - - /* 132: Reserved (zero), pad to 256 bytes. */ - // Byte reserved[124]; - - void Parse128(const Byte *p) - { - G32 (0, magic) - G16 (4, major_version) - G16 (6, minor_version) - G32 (8, header_size) - // Byte header_checksum[32]; - G32 (44, tables_size) - memcpy (tables_checksum, p + 48, 32); - partitions.Parse(p + 80); - extents.Parse(p + 92); - groups.Parse(p + 104); - block_devices.Parse(p + 116); - /* Everything past here is header version 1.2+, and is only included if - * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must - * zero these additional fields. - */ - } -}; - - -static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum) -{ - CSha256 sha; - Sha256_Init(&sha); - Sha256_Update(&sha, data, size); - Byte calced[32]; - Sha256_Final(&sha, calced); - return memcmp(checksum, calced, 32) == 0; -} - -static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset) -{ - Byte checksum[32]; - Byte *shaData = &data[hashOffset]; - memcpy(checksum, shaData, 32); - memset(shaData, 0, 32); - return CheckSha256(data, size, checksum); -} - - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CRecordVector _items; - CRecordVector Extents; - - CMyComPtr _stream; - UInt64 _totalSize; - // UInt64 _usedSize; - // UInt64 _headersSize; - - CGeometry geom; - UInt16 Major_version; - UInt16 Minor_version; - UInt32 Flags; - - Int32 _mainFileIndex; - UInt32 MethodsMask; - bool _headerWarning; - AString GroupsString; - AString DevicesString; - AString DeviceArcName; - - HRESULT Open2(IInStream *stream); -}; - - -static void AddComment_UInt64(AString &s, const char *name, UInt64 val) -{ - s.Add_Space(); - s += name; - s += '='; - s.Add_UInt64(val); -} - - -static bool IsBufZero(const Byte *data, size_t size) -{ - for (size_t i = 0; i < size; i += 4) - if (*(const UInt32 *)(const void *)(data + i) != 0) - return false; - return true; -} - - -HRESULT CHandler::Open2(IInStream *stream) -{ - RINOK(InStream_SeekSet(stream, LP_PARTITION_RESERVED_BYTES)) - { - Byte buf[k_Geometry_Size]; - RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size)) - if (memcmp(buf, k_Signature, k_SignatureSize) != 0) - return S_FALSE; - if (!geom.Parse(buf)) - return S_FALSE; - if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8)) - return S_FALSE; - } - - CByteBuffer buffer; - RINOK(InStream_SeekToBegin(stream)) - buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2); - { - // buffer.Size() >= LP_PARTITION_RESERVED_BYTES - RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES)) - if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES)) - { - _headerWarning = true; - // return S_FALSE; - } - } - - RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2)) - // we check that 2 copies of GEOMETRY are identical: - if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0 - || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size)) - { - _headerWarning = true; - // return S_FALSE; - } - - RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size)) - LpMetadataHeader header; - header.Parse128(buffer); - if (header.magic != LP_METADATA_HEADER_MAGIC || - header.major_version != LP_METADATA_MAJOR_VERSION || - header.header_size < k_LpMetadataHeader10_size) - return S_FALSE; - Flags = 0; - if (header.header_size > k_LpMetadataHeader10_size) - { - if (header.header_size != k_LpMetadataHeader12_size) - return S_FALSE; - RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size, - header.header_size - k_LpMetadataHeader10_size)) - Flags = Get32(buffer + k_LpMetadataHeader10_size); - } - Major_version = header.major_version; - Minor_version = header.minor_version; - - if (!CheckSha256_csOffset(buffer, header.header_size, 12)) - return S_FALSE; - - if (geom.metadata_max_size < header.tables_size || - geom.metadata_max_size - header.tables_size < header.header_size) - return S_FALSE; - - buffer.AllocAtLeast(header.tables_size); - RINOK(ReadStream_FALSE(stream, buffer, header.tables_size)) - - const UInt64 totalMetaSize = geom.GetTotalMetadataSize(); - // _headersSize = _totalSize; - _totalSize = totalMetaSize; - - if (!CheckSha256(buffer, header.tables_size, header.tables_checksum)) - return S_FALSE; - - { - const CDescriptor &d = header.partitions; - if (!d.CheckLimits(header.tables_size)) - return S_FALSE; - if (d.entry_size != k_MetaPartition_Size) - return S_FALSE; - for (UInt32 i = 0; i < d.num_entries; i++) - { - CPartition part; - part.Parse(buffer + d.offset + i * d.entry_size); - const UInt32 extLimit = part.first_extent_index + part.num_extents; - if (extLimit < part.first_extent_index || - extLimit > header.extents.num_entries || - part.group_index >= header.groups.num_entries) - return S_FALSE; - _items.Add(part); - } - } - { - const CDescriptor &d = header.extents; - if (!d.CheckLimits(header.tables_size)) - return S_FALSE; - if (d.entry_size != k_MetaExtent_Size) - return S_FALSE; - for (UInt32 i = 0; i < d.num_entries; i++) - { - CExtent e; - e.Parse(buffer + d.offset + i * d.entry_size); - // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE; - if (e.IsRAW()) - { - if (e.target_source >= header.block_devices.num_entries) - return S_FALSE; - const UInt64 endSector = e.target_data + e.num_sectors; - const UInt64 endOffset = endSector << kSectorSizeLog; - if (_totalSize < endOffset) - _totalSize = endOffset; - } - MethodsMask |= (UInt32)1 << e.target_type; - Extents.Add(e); - } - } - - // _usedSize = _totalSize; - { - const CDescriptor &d = header.groups; - if (!d.CheckLimits(header.tables_size)) - return S_FALSE; - if (d.entry_size != k_Group_Size) - return S_FALSE; - AString s; - for (UInt32 i = 0; i < d.num_entries; i++) - { - CGroup g; - g.Parse(buffer + d.offset + i * d.entry_size); - if (_totalSize < g.maximum_size) - _totalSize = g.maximum_size; - s += " "; - AddName36ToString(s, g.name, true); - AddComment_UInt64(s, "maximum_size", g.maximum_size); - AddComment_UInt64(s, "flags", g.flags); - s.Add_LF(); - } - GroupsString = s; - } - - { - const CDescriptor &d = header.block_devices; - if (!d.CheckLimits(header.tables_size)) - return S_FALSE; - if (d.entry_size != k_Device_Size) - return S_FALSE; - AString s; - // CRecordVector devices; - for (UInt32 i = 0; i < d.num_entries; i++) - { - CDevice v; - v.Parse(buffer + d.offset + i * d.entry_size); - // if (i == 0) - { - // it's super_device is first device; - if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog)) - return S_FALSE; - } - if (_totalSize < v.size) - _totalSize = v.size; - s += " "; - if (i == 0) - AddName36ToString(DeviceArcName, v.partition_name, true); - // devices.Add(v); - AddName36ToString(s, v.partition_name, true); - AddComment_UInt64(s, "size", v.size); - AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector); - AddComment_UInt64(s, "alignment", v.alignment); - AddComment_UInt64(s, "alignment_offset", v.alignment_offset); - AddComment_UInt64(s, "flags", v.flags); - s.Add_LF(); - } - DevicesString = s; - } - - { - FOR_VECTOR (i, _items) - { - CPartition &part = _items[i]; - if (part.first_extent_index > Extents.Size() || - part.num_extents > Extents.Size() - part.first_extent_index) - return S_FALSE; - - UInt64 numSectors = 0; - UInt64 numSectors_Pack = 0; - UInt32 methods = 0; - for (UInt32 k = 0; k < part.num_extents; k++) - { - const CExtent &e = Extents[part.first_extent_index + k]; - numSectors += e.num_sectors; - if (e.IsRAW()) - numSectors_Pack += e.num_sectors; - methods |= (UInt32)1 << e.target_type; - } - part.NumSectors = numSectors; - part.NumSectors_Pack = numSectors_Pack; - part.MethodsMask = methods; - } - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(stream)) - _stream = stream; - - int mainFileIndex = -1; - unsigned numNonEmptyParts = 0; - - FOR_VECTOR (fileIndex, _items) - { - CPartition &item = _items[fileIndex]; - if (item.NumSectors != 0) - { - mainFileIndex = (int)fileIndex; - numNonEmptyParts++; - CMyComPtr parseStream; - if (GetStream(fileIndex, &parseStream) == S_OK && parseStream) - { - const size_t kParseSize = 1 << 11; - Byte buf[kParseSize]; - if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK) - { - UInt64 extSize; - if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES) - if (extSize == item.GetSize()) - item.Ext = "ext"; - } - } - } - } - if (numNonEmptyParts == 1) - _mainFileIndex = mainFileIndex; - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - // _usedSize = 0; - // _headersSize = 0; - _items.Clear(); - Extents.Clear(); - _stream.Release(); - _mainFileIndex = -1; - _headerWarning = false; - MethodsMask = 0; - GroupsString.Empty(); - DevicesString.Empty(); - DeviceArcName.Empty(); - return S_OK; -} - - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidCharacts, - kpidMethod, - kpidNumBlocks, - kpidOffset -}; - -static const Byte kArcProps[] = -{ - kpidUnpackVer, - kpidMethod, - kpidClusterSize, - // kpidHeadersSize, - // kpidFreeSpace, - kpidName, - kpidComment -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: - { - if (_mainFileIndex >= 0) - prop = (UInt32)_mainFileIndex; - break; - } - case kpidPhySize: prop = _totalSize; break; - - // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break; - // case kpidHeadersSize: prop = _headersSize; break; - - case kpidMethod: - { - const UInt32 m = MethodsMask; - if (m != 0) - { - FLAGS_TO_PROP(g_Methods, m, prop); - } - break; - } - - case kpidUnpackVer: - { - AString s; - s.Add_UInt32(Major_version); - s.Add_Dot(); - s.Add_UInt32(Minor_version); - prop = s; - break; - } - - case kpidClusterSize: - prop = geom.logical_block_size; - break; - - case kpidComment: - { - AString s; - - s += "metadata_slot_count: "; - s.Add_UInt32(geom.metadata_slot_count); - s.Add_LF(); - - s += "metadata_max_size: "; - s.Add_UInt32(geom.metadata_max_size); - s.Add_LF(); - - if (Flags != 0) - { - s += "flags: "; - s += FlagsToString(g_Header_Flags, Z7_ARRAY_SIZE(g_Header_Flags), Flags); - s.Add_LF(); - } - - if (!GroupsString.IsEmpty()) - { - s += "Groups:"; - s.Add_LF(); - s += GroupsString; - } - - if (!DevicesString.IsEmpty()) - { - s += "BlockDevices:"; - s.Add_LF(); - s += DevicesString; - } - - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidName: - if (!DeviceArcName.IsEmpty()) - prop = DeviceArcName + ".lpimg"; - break; - - case kpidWarningFlags: - if (_headerWarning) - { - UInt32 v = kpv_ErrorFlags_HeadersError; - prop = v; - } - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CPartition &item = _items[index]; - - switch (propID) - { - case kpidPath: - { - AString s; - AddName36ToString(s, item.name, false); - if (s.IsEmpty()) - s.Add_UInt32(index); - if (item.num_extents != 0) - { - s.Add_Dot(); - s += (item.Ext ? item.Ext : "img"); - } - prop = s; - break; - } - - case kpidSize: prop = item.GetSize(); break; - case kpidPackSize: prop = item.GetPackSize(); break; - case kpidNumBlocks: prop = item.num_extents; break; - case kpidMethod: - { - const UInt32 m = item.MethodsMask; - if (m != 0) - { - FLAGS_TO_PROP(g_Methods, m, prop); - } - break; - } - case kpidOffset: - if (item.num_extents != 0) - if (item.first_extent_index < Extents.Size()) - prop = Extents[item.first_extent_index].target_data << kSectorSizeLog; - break; - - case kpidCharacts: - { - AString s; - s += "group:"; - s.Add_UInt32(item.group_index); - s.Add_Space(); - s += FlagsToString(g_PartitionAttr, Z7_ARRAY_SIZE(g_PartitionAttr), item.attributes); - prop = s; - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - - const CPartition &item = _items[index]; - - if (item.first_extent_index > Extents.Size() - || item.num_extents > Extents.Size() - item.first_extent_index) - return S_FALSE; - - if (item.num_extents == 0) - return CreateLimitedInStream(_stream, 0, 0, stream); - - if (item.num_extents == 1) - { - const CExtent &e = Extents[item.first_extent_index]; - if (e.IsRAW()) - { - const UInt64 pos = e.target_data << kSectorSizeLog; - if ((pos >> kSectorSizeLog) != e.target_data) - return S_FALSE; - const UInt64 size = item.GetSize(); - if (pos + size < pos) - return S_FALSE; - return CreateLimitedInStream(_stream, pos, size, stream); - } - } - - CExtentsStream *extentStreamSpec = new CExtentsStream(); - CMyComPtr extentStream = extentStreamSpec; - - // const unsigned kNumDebugExtents = 10; - extentStreamSpec->Extents.Reserve(item.num_extents + 1 - // + kNumDebugExtents - ); - - UInt64 virt = 0; - for (UInt32 k = 0; k < item.num_extents; k++) - { - const CExtent &e = Extents[item.first_extent_index + k]; - - CSeekExtent se; - { - const UInt64 numSectors = e.num_sectors; - if (numSectors == 0) - { - continue; - // return S_FALSE; - } - const UInt64 numBytes = numSectors << kSectorSizeLog; - if ((numBytes >> kSectorSizeLog) != numSectors) - return S_FALSE; - if (numBytes >= ((UInt64)1 << 63) - virt) - return S_FALSE; - - se.Virt = virt; - virt += numBytes; - } - - const UInt64 phySector = e.target_data; - if (e.target_type == LP_TARGET_TYPE_ZERO) - { - if (phySector != 0) - return S_FALSE; - se.SetAs_ZeroFill(); - } - else if (e.target_type == LP_TARGET_TYPE_LINEAR) - { - se.Phy = phySector << kSectorSizeLog; - if ((se.Phy >> kSectorSizeLog) != phySector) - return S_FALSE; - if (se.Phy >= ((UInt64)1 << 63)) - return S_FALSE; - } - else - return S_FALSE; - - extentStreamSpec->Extents.AddInReserved(se); - - /* - { - // for debug - const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents; - for (unsigned i = 0; i < kNumDebugExtents; i++) - { - se.Phy += kAdd; - // se.Phy += (UInt64)1 << 63; // for debug - // se.Phy += 1; // for debug - se.Virt += kAdd; - extentStreamSpec->Extents.AddInReserved(se); - } - } - */ - } - - CSeekExtent se; - se.Phy = 0; - se.Virt = virt; - extentStreamSpec->Extents.Add(se); - extentStreamSpec->Stream = _stream; - extentStreamSpec->Init(); - *stream = extentStream.Detach(); - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - totalSize += _items[index].GetSize(); - } - extractCallback->SetTotal(totalSize); - - totalSize = 0; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - - const UInt64 size = _items[index].GetSize(); - totalSize += size; - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CMyComPtr inStream; - const HRESULT hres = GetStream(index, &inStream); - int opRes = NExtract::NOperationResult::kUnsupportedMethod; - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - opRes = NExtract::NOperationResult::kDataError; - if (copyCoderSpec->TotalSize == size) - opRes = NExtract::NOperationResult::kOK; - else if (copyCoderSpec->TotalSize < size) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - } - outStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - - -REGISTER_ARC_I( - "LP", "lpimg img", NULL, 0xc1, - k_Signature, - LP_PARTITION_RESERVED_BYTES, - 0, - NULL) - -}} +// LpHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/Sha256.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + +using namespace NWindows; + +namespace NArchive { + +namespace NExt { +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); +} + +namespace NLp { + +/* +Android 10+ use Android's Dynamic Partitions to allow the +different read-only system partitions (e.g. system, vendor, product) +to share the same pool of storage space (as LVM in Linux). +Name for partition: "super" (for GPT) or "super.img" (for file). +Dynamic Partition Tools: lpmake +All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.): +boot_a, boot_b, system_a, system_b, vendor_a, vendor_b. +*/ + +#define LP_METADATA_MAJOR_VERSION 10 +// #define LP_METADATA_MINOR_VERSION_MIN 0 +// #define LP_METADATA_MINOR_VERSION_MAX 2 + +// #define LP_SECTOR_SIZE 512 +static const unsigned kSectorSizeLog = 9; + +/* Amount of space reserved at the start of every super partition to avoid + * creating an accidental boot sector. */ +#define LP_PARTITION_RESERVED_BYTES 4096 +#define LP_METADATA_GEOMETRY_SIZE 4096 +#define LP_METADATA_HEADER_MAGIC 0x414C5030 + +static const unsigned k_SignatureSize = 8; +static const Byte k_Signature[k_SignatureSize] = + { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 }; + +// The length (36) is the same as the maximum length of a GPT partition name. +static const unsigned kNameLen = 36; + +static void AddName36ToString(AString &s, const char *name, bool strictConvert) +{ + for (unsigned i = 0; i < kNameLen; i++) + { + char c = name[i]; + if (c == 0) + return; + if (strictConvert && c < 32) + c = '_'; + s += c; + } +} + + +static const unsigned k_Geometry_Size = 0x34; + +// LpMetadataGeometry +struct CGeometry +{ + // UInt32 magic; + // UInt32 struct_size; + // Byte checksum[32]; /* SHA256 checksum of this struct, with this field set to 0. */ + + /* Maximum amount of space a single copy of the metadata can use, + a multiple of LP_SECTOR_SIZE. */ + UInt32 metadata_max_size; + + /* Number of copies of the metadata to keep. + For Non-A/B: 1, For A/B: 2, for A/B/C: 3. + A backup copy of each slot is kept */ + UInt32 metadata_slot_count; + + /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */ + UInt32 logical_block_size; + + bool Parse(const Byte *p) + { + G32 (40, metadata_max_size) + G32 (44, metadata_slot_count) + G32 (48, logical_block_size) + if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20)) + return false; + if (metadata_max_size == 0) + return false; + if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0) + return false; + return true; + } + + UInt64 GetTotalMetadataSize() const + { + // there are 2 copies of GEOMETRY and METADATA slots + return LP_PARTITION_RESERVED_BYTES + + LP_METADATA_GEOMETRY_SIZE * 2 + + ((UInt64)metadata_max_size * metadata_slot_count) * 2; + } +}; + + + +// LpMetadataTableDescriptor +struct CDescriptor +{ + UInt32 offset; /* Location of the table, relative to end of the metadata header. */ + UInt32 num_entries; /* Number of entries in the table. */ + UInt32 entry_size; /* Size of each entry in the table, in bytes. */ + + void Parse(const Byte *p) + { + G32 (0, offset) + G32 (4, num_entries) + G32 (8, entry_size) + } + + bool CheckLimits(UInt32 limit) const + { + if (entry_size == 0) + return false; + const UInt32 size = num_entries * entry_size; + if (size / entry_size != num_entries) + return false; + if (offset > limit || limit - offset < size) + return false; + return true; + } +}; + + +// #define LP_PARTITION_ATTR_NONE 0x0 +// #define LP_PARTITION_ATTR_READONLY (1 << 0) + +/* This flag is only intended to be used with super_empty.img and super.img on + * retrofit devices. On these devices there are A and B super partitions, and + * we don't know ahead of time which slot the image will be applied to. + * + * If set, the partition name needs a slot suffix applied. The slot suffix is + * determined by the metadata slot number (0 = _a, 1 = _b). + */ +// #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1) + +/* This flag is applied automatically when using MetadataBuilder::NewForUpdate. + * It signals that the partition was created (or modified) for a snapshot-based + * update. If this flag is not present, the partition was likely flashed via + * fastboot. + */ +// #define LP_PARTITION_ATTR_UPDATED (1 << 2) + +/* This flag marks a partition as disabled. It should not be used or mapped. */ +// #define LP_PARTITION_ATTR_DISABLED (1 << 3) + +static const char * const g_PartitionAttr[] = +{ + "READONLY" + , "SLOT_SUFFIXED" + , "UPDATED" + , "DISABLED" +}; + +static unsigned const k_MetaPartition_Size = 52; + +// LpMetadataPartition +struct CPartition +{ + /* ASCII characters: alphanumeric or _. at least one ASCII character, + (name) must be unique across all partition names. */ + char name[kNameLen]; + + UInt32 attributes; /* (LP_PARTITION_ATTR_*). */ + + /* Index of the first extent owned by this partition. The extent will + * start at logical sector 0. Gaps between extents are not allowed. */ + UInt32 first_extent_index; + + /* Number of extents in the partition. Every partition must have at least one extent. */ + UInt32 num_extents; + + /* Group this partition belongs to. */ + UInt32 group_index; + + void Parse(const Byte *p) + { + memcpy(name, p, kNameLen); + G32 (36, attributes) + G32 (40, first_extent_index) + G32 (44, num_extents) + G32 (48, group_index) + } + + // calced properties: + UInt32 MethodsMask; + UInt64 NumSectors; + UInt64 NumSectors_Pack; + const char *Ext; + + UInt64 GetSize() const { return NumSectors << kSectorSizeLog; } + UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; } + + CPartition(): + MethodsMask(0), + NumSectors(0), + NumSectors_Pack(0), + Ext(NULL) + {} +}; + + + + +#define LP_TARGET_TYPE_LINEAR 0 +/* This extent is a dm-zero target. The index is ignored and must be 0. */ +#define LP_TARGET_TYPE_ZERO 1 + +static const char * const g_Methods[] = +{ + "RAW" // "LINEAR" + , "ZERO" +}; + +static unsigned const k_MetaExtent_Size = 24; + +// LpMetadataExtent +struct CExtent +{ + UInt64 num_sectors; /* Length in 512-byte sectors. */ + UInt32 target_type; /* Target type for device-mapper (LP_TARGET_TYPE_*). */ + + /* for LINEAR: The sector on the physical partition that this extent maps onto. + for ZERO: must be 0. */ + UInt64 target_data; + + /* for LINEAR: index into the block devices table. + for ZERO: must be 0. */ + UInt32 target_source; + + bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; } + + void Parse(const Byte *p) + { + G64 (0, num_sectors) + G32 (8, target_type) + G64 (12, target_data) + G32 (20, target_source) + } +}; + + +/* This flag is only intended to be used with super_empty.img and super.img on + * retrofit devices. If set, the group needs a slot suffix to be interpreted + * correctly. The suffix is automatically applied by ReadMetadata(). + */ +// #define LP_GROUP_SLOT_SUFFIXED (1 << 0) +static unsigned const k_Group_Size = 48; + +// LpMetadataPartitionGroup +struct CGroup +{ + char name[kNameLen]; + UInt32 flags; /* (LP_GROUP_*). */ + UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */ + + void Parse(const Byte *p) + { + memcpy(name, p, kNameLen); + G32 (36, flags) + G64 (40, maximum_size) + } +}; + + + + +/* This flag is only intended to be used with super_empty.img and super.img on + * retrofit devices. On these devices there are A and B super partitions, and + * we don't know ahead of time which slot the image will be applied to. + * + * If set, the block device needs a slot suffix applied before being used with + * IPartitionOpener. The slot suffix is determined by the metadata slot number + * (0 = _a, 1 = _b). + */ +// #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0) + +static unsigned const k_Device_Size = 64; + +/* This struct defines an entry in the block_devices table. There must be at + * least one device, and the first device must represent the partition holding + * the super metadata. + */ +// LpMetadataBlockDevice +struct CDevice +{ + /* 0: First usable sector for allocating logical partitions. this will be + * the first sector after the initial geometry blocks, followed by the + * space consumed by metadata_max_size*metadata_slot_count*2. + */ + UInt64 first_logical_sector; + + /* 8: Alignment for defining partitions or partition extents. For example, + * an alignment of 1MiB will require that all partitions have a size evenly + * divisible by 1MiB, and that the smallest unit the partition can grow by + * is 1MiB. + * + * Alignment is normally determined at runtime when growing or adding + * partitions. If for some reason the alignment cannot be determined, then + * this predefined alignment in the geometry is used instead. By default + * it is set to 1MiB. + */ + UInt32 alignment; + + /* 12: Alignment offset for "stacked" devices. For example, if the "super" + * partition itself is not aligned within the parent block device's + * partition table, then we adjust for this in deciding where to place + * |first_logical_sector|. + * + * Similar to |alignment|, this will be derived from the operating system. + * If it cannot be determined, it is assumed to be 0. + */ + UInt32 alignment_offset; + + /* 16: Block device size, as specified when the metadata was created. This + * can be used to verify the geometry against a target device. + */ + UInt64 size; + + /* 24: Partition name in the GPT*/ + char partition_name[kNameLen]; + + /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */ + UInt32 flags; + + void Parse(const Byte *p) + { + memcpy(partition_name, p + 24, kNameLen); + G64 (0, first_logical_sector) + G32 (8, alignment) + G32 (12, alignment_offset) + G64 (16, size) + G32 (60, flags) + } +}; + + +/* This device uses Virtual A/B. Note that on retrofit devices, the expanded + * header may not be present. + */ +// #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1 + +static const char * const g_Header_Flags[] = +{ + "VIRTUAL_AB" +}; + + +static const unsigned k_LpMetadataHeader10_size = 128; +static const unsigned k_LpMetadataHeader12_size = 256; + +struct LpMetadataHeader +{ + /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */ + UInt32 magic; + + /* 4: Version number required to read this metadata. If the version is not + * equal to the library version, the metadata should be considered + * incompatible. + */ + UInt16 major_version; + + /* 6: Minor version. A library supporting newer features should be able to + * read metadata with an older minor version. However, an older library + * should not support reading metadata if its minor version is higher. + */ + UInt16 minor_version; + + /* 8: The size of this header struct. */ + UInt32 header_size; + + /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as + * if this field were set to 0. + */ + // Byte header_checksum[32]; + + /* 44: The total size of all tables. This size is contiguous; tables may not + * have gaps in between, and they immediately follow the header. + */ + UInt32 tables_size; + + /* 48: SHA256 checksum of all table contents. */ + Byte tables_checksum[32]; + + /* 80: Partition table descriptor. */ + CDescriptor partitions; + /* 92: Extent table descriptor. */ + CDescriptor extents; + /* 104: Updateable group descriptor. */ + CDescriptor groups; + /* 116: Block device table. */ + CDescriptor block_devices; + + /* Everything past here is header version 1.2+, and is only included if + * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must + * zero these additional fields. + */ + + /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are + * independent of the version number and intended to be informational only. + * New flags can be added without bumping the version. + */ + // UInt32 flags; + + /* 132: Reserved (zero), pad to 256 bytes. */ + // Byte reserved[124]; + + void Parse128(const Byte *p) + { + G32 (0, magic) + G16 (4, major_version) + G16 (6, minor_version) + G32 (8, header_size) + // Byte header_checksum[32]; + G32 (44, tables_size) + memcpy (tables_checksum, p + 48, 32); + partitions.Parse(p + 80); + extents.Parse(p + 92); + groups.Parse(p + 104); + block_devices.Parse(p + 116); + /* Everything past here is header version 1.2+, and is only included if + * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must + * zero these additional fields. + */ + } +}; + + +static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum) +{ + MY_ALIGN (16) + CSha256 sha; + Sha256_Init(&sha); + Sha256_Update(&sha, data, size); + MY_ALIGN (16) + Byte calced[32]; + Sha256_Final(&sha, calced); + return memcmp(checksum, calced, 32) == 0; +} + +static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset) +{ + MY_ALIGN (4) + Byte checksum[32]; + Byte *shaData = &data[hashOffset]; + memcpy(checksum, shaData, 32); + memset(shaData, 0, 32); + return CheckSha256(data, size, checksum); +} + + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CRecordVector _items; + CRecordVector Extents; + + CMyComPtr _stream; + UInt64 _totalSize; + // UInt64 _usedSize; + // UInt64 _headersSize; + + CGeometry geom; + UInt16 Major_version; + UInt16 Minor_version; + UInt32 Flags; + + Int32 _mainFileIndex; + UInt32 MethodsMask; + bool _headerWarning; + AString GroupsString; + AString DevicesString; + AString DeviceArcName; + + HRESULT Open2(IInStream *stream); +}; + + +static void AddComment_UInt64(AString &s, const char *name, UInt64 val) +{ + s.Add_Space(); + s += name; + s += '='; + s.Add_UInt64(val); +} + + +static bool IsBufZero(const Byte *data, size_t size) +{ + for (size_t i = 0; i < size; i += 4) + if (*(const UInt32 *)(const void *)(data + i) != 0) + return false; + return true; +} + + +HRESULT CHandler::Open2(IInStream *stream) +{ + RINOK(InStream_SeekSet(stream, LP_PARTITION_RESERVED_BYTES)) + { + MY_ALIGN (4) + Byte buf[k_Geometry_Size]; + RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size)) + if (memcmp(buf, k_Signature, k_SignatureSize) != 0) + return S_FALSE; + if (!geom.Parse(buf)) + return S_FALSE; + if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8)) + return S_FALSE; + } + + CByteBuffer buffer; + RINOK(InStream_SeekToBegin(stream)) + buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2); + { + // buffer.Size() >= LP_PARTITION_RESERVED_BYTES + RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES)) + if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES)) + { + _headerWarning = true; + // return S_FALSE; + } + } + + RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2)) + // we check that 2 copies of GEOMETRY are identical: + if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0 + || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size)) + { + _headerWarning = true; + // return S_FALSE; + } + + RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size)) + LpMetadataHeader header; + header.Parse128(buffer); + if (header.magic != LP_METADATA_HEADER_MAGIC || + header.major_version != LP_METADATA_MAJOR_VERSION || + header.header_size < k_LpMetadataHeader10_size) + return S_FALSE; + Flags = 0; + if (header.header_size > k_LpMetadataHeader10_size) + { + if (header.header_size != k_LpMetadataHeader12_size) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size, + header.header_size - k_LpMetadataHeader10_size)) + Flags = Get32(buffer + k_LpMetadataHeader10_size); + } + Major_version = header.major_version; + Minor_version = header.minor_version; + + if (!CheckSha256_csOffset(buffer, header.header_size, 12)) + return S_FALSE; + + if (geom.metadata_max_size < header.tables_size || + geom.metadata_max_size - header.tables_size < header.header_size) + return S_FALSE; + + buffer.AllocAtLeast(header.tables_size); + RINOK(ReadStream_FALSE(stream, buffer, header.tables_size)) + + const UInt64 totalMetaSize = geom.GetTotalMetadataSize(); + // _headersSize = _totalSize; + _totalSize = totalMetaSize; + + if (!CheckSha256(buffer, header.tables_size, header.tables_checksum)) + return S_FALSE; + + { + const CDescriptor &d = header.partitions; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_MetaPartition_Size) + return S_FALSE; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CPartition part; + part.Parse(buffer + d.offset + i * d.entry_size); + const UInt32 extLimit = part.first_extent_index + part.num_extents; + if (extLimit < part.first_extent_index || + extLimit > header.extents.num_entries || + part.group_index >= header.groups.num_entries) + return S_FALSE; + _items.Add(part); + } + } + { + const CDescriptor &d = header.extents; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_MetaExtent_Size) + return S_FALSE; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CExtent e; + e.Parse(buffer + d.offset + i * d.entry_size); + // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE; + if (e.IsRAW()) + { + if (e.target_source >= header.block_devices.num_entries) + return S_FALSE; + const UInt64 endSector = e.target_data + e.num_sectors; + const UInt64 endOffset = endSector << kSectorSizeLog; + if (_totalSize < endOffset) + _totalSize = endOffset; + } + MethodsMask |= (UInt32)1 << e.target_type; + Extents.Add(e); + } + } + + // _usedSize = _totalSize; + { + const CDescriptor &d = header.groups; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_Group_Size) + return S_FALSE; + AString s; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CGroup g; + g.Parse(buffer + d.offset + i * d.entry_size); + if (_totalSize < g.maximum_size) + _totalSize = g.maximum_size; + s += " "; + AddName36ToString(s, g.name, true); + AddComment_UInt64(s, "maximum_size", g.maximum_size); + AddComment_UInt64(s, "flags", g.flags); + s.Add_LF(); + } + GroupsString = s; + } + + { + const CDescriptor &d = header.block_devices; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_Device_Size) + return S_FALSE; + AString s; + // CRecordVector devices; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CDevice v; + v.Parse(buffer + d.offset + i * d.entry_size); + // if (i == 0) + { + // it's super_device is first device; + if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog)) + return S_FALSE; + } + if (_totalSize < v.size) + _totalSize = v.size; + s += " "; + if (i == 0) + AddName36ToString(DeviceArcName, v.partition_name, true); + // devices.Add(v); + AddName36ToString(s, v.partition_name, true); + AddComment_UInt64(s, "size", v.size); + AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector); + AddComment_UInt64(s, "alignment", v.alignment); + AddComment_UInt64(s, "alignment_offset", v.alignment_offset); + AddComment_UInt64(s, "flags", v.flags); + s.Add_LF(); + } + DevicesString = s; + } + + { + FOR_VECTOR (i, _items) + { + CPartition &part = _items[i]; + if (part.first_extent_index > Extents.Size() || + part.num_extents > Extents.Size() - part.first_extent_index) + return S_FALSE; + + UInt64 numSectors = 0; + UInt64 numSectors_Pack = 0; + UInt32 methods = 0; + for (UInt32 k = 0; k < part.num_extents; k++) + { + const CExtent &e = Extents[part.first_extent_index + k]; + numSectors += e.num_sectors; + if (e.IsRAW()) + numSectors_Pack += e.num_sectors; + methods |= (UInt32)1 << e.target_type; + } + part.NumSectors = numSectors; + part.NumSectors_Pack = numSectors_Pack; + part.MethodsMask = methods; + } + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream)) + _stream = stream; + + int mainFileIndex = -1; + unsigned numNonEmptyParts = 0; + + FOR_VECTOR (fileIndex, _items) + { + CPartition &item = _items[fileIndex]; + if (item.NumSectors != 0) + { + mainFileIndex = (int)fileIndex; + numNonEmptyParts++; + CMyComPtr parseStream; + if (GetStream(fileIndex, &parseStream) == S_OK && parseStream) + { + const size_t kParseSize = 1 << 11; + Byte buf[kParseSize]; + if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK) + { + UInt64 extSize; + if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES) + if (extSize == item.GetSize()) + item.Ext = "ext"; + } + } + } + } + if (numNonEmptyParts == 1) + _mainFileIndex = mainFileIndex; + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + // _usedSize = 0; + // _headersSize = 0; + _items.Clear(); + Extents.Clear(); + _stream.Release(); + _mainFileIndex = -1; + _headerWarning = false; + MethodsMask = 0; + GroupsString.Empty(); + DevicesString.Empty(); + DeviceArcName.Empty(); + return S_OK; +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCharacts, + kpidMethod, + kpidNumBlocks, + kpidOffset +}; + +static const Byte kArcProps[] = +{ + kpidUnpackVer, + kpidMethod, + kpidClusterSize, + // kpidHeadersSize, + // kpidFreeSpace, + kpidName, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: + { + if (_mainFileIndex >= 0) + prop = (UInt32)_mainFileIndex; + break; + } + case kpidPhySize: prop = _totalSize; break; + + // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break; + // case kpidHeadersSize: prop = _headersSize; break; + + case kpidMethod: + { + const UInt32 m = MethodsMask; + if (m != 0) + { + FLAGS_TO_PROP(g_Methods, m, prop); + } + break; + } + + case kpidUnpackVer: + { + AString s; + s.Add_UInt32(Major_version); + s.Add_Dot(); + s.Add_UInt32(Minor_version); + prop = s; + break; + } + + case kpidClusterSize: + prop = geom.logical_block_size; + break; + + case kpidComment: + { + AString s; + + s += "metadata_slot_count: "; + s.Add_UInt32(geom.metadata_slot_count); + s.Add_LF(); + + s += "metadata_max_size: "; + s.Add_UInt32(geom.metadata_max_size); + s.Add_LF(); + + if (Flags != 0) + { + s += "flags: "; + s += FlagsToString(g_Header_Flags, Z7_ARRAY_SIZE(g_Header_Flags), Flags); + s.Add_LF(); + } + + if (!GroupsString.IsEmpty()) + { + s += "Groups:"; + s.Add_LF(); + s += GroupsString; + } + + if (!DevicesString.IsEmpty()) + { + s += "BlockDevices:"; + s.Add_LF(); + s += DevicesString; + } + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidName: + if (!DeviceArcName.IsEmpty()) + prop = DeviceArcName + ".lpimg"; + break; + + case kpidWarningFlags: + if (_headerWarning) + { + UInt32 v = kpv_ErrorFlags_HeadersError; + prop = v; + } + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CPartition &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + AString s; + AddName36ToString(s, item.name, false); + if (s.IsEmpty()) + s.Add_UInt32(index); + if (item.num_extents != 0) + { + s.Add_Dot(); + s += (item.Ext ? item.Ext : "img"); + } + prop = s; + break; + } + + case kpidSize: prop = item.GetSize(); break; + case kpidPackSize: prop = item.GetPackSize(); break; + case kpidNumBlocks: prop = item.num_extents; break; + case kpidMethod: + { + const UInt32 m = item.MethodsMask; + if (m != 0) + { + FLAGS_TO_PROP(g_Methods, m, prop); + } + break; + } + case kpidOffset: + if (item.num_extents != 0) + if (item.first_extent_index < Extents.Size()) + prop = Extents[item.first_extent_index].target_data << kSectorSizeLog; + break; + + case kpidCharacts: + { + AString s; + s += "group:"; + s.Add_UInt32(item.group_index); + s.Add_Space(); + s += FlagsToString(g_PartitionAttr, Z7_ARRAY_SIZE(g_PartitionAttr), item.attributes); + prop = s; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + + const CPartition &item = _items[index]; + + if (item.first_extent_index > Extents.Size() + || item.num_extents > Extents.Size() - item.first_extent_index) + return S_FALSE; + + if (item.num_extents == 0) + return CreateLimitedInStream(_stream, 0, 0, stream); + + if (item.num_extents == 1) + { + const CExtent &e = Extents[item.first_extent_index]; + if (e.IsRAW()) + { + const UInt64 pos = e.target_data << kSectorSizeLog; + if ((pos >> kSectorSizeLog) != e.target_data) + return S_FALSE; + const UInt64 size = item.GetSize(); + if (pos + size < pos) + return S_FALSE; + return CreateLimitedInStream(_stream, pos, size, stream); + } + } + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr extentStream = extentStreamSpec; + + // const unsigned kNumDebugExtents = 10; + extentStreamSpec->Extents.Reserve(item.num_extents + 1 + // + kNumDebugExtents + ); + + UInt64 virt = 0; + for (UInt32 k = 0; k < item.num_extents; k++) + { + const CExtent &e = Extents[item.first_extent_index + k]; + + CSeekExtent se; + { + const UInt64 numSectors = e.num_sectors; + if (numSectors == 0) + { + continue; + // return S_FALSE; + } + const UInt64 numBytes = numSectors << kSectorSizeLog; + if ((numBytes >> kSectorSizeLog) != numSectors) + return S_FALSE; + if (numBytes >= ((UInt64)1 << 63) - virt) + return S_FALSE; + + se.Virt = virt; + virt += numBytes; + } + + const UInt64 phySector = e.target_data; + if (e.target_type == LP_TARGET_TYPE_ZERO) + { + if (phySector != 0) + return S_FALSE; + se.SetAs_ZeroFill(); + } + else if (e.target_type == LP_TARGET_TYPE_LINEAR) + { + se.Phy = phySector << kSectorSizeLog; + if ((se.Phy >> kSectorSizeLog) != phySector) + return S_FALSE; + if (se.Phy >= ((UInt64)1 << 63)) + return S_FALSE; + } + else + return S_FALSE; + + extentStreamSpec->Extents.AddInReserved(se); + + /* + { + // for debug + const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents; + for (unsigned i = 0; i < kNumDebugExtents; i++) + { + se.Phy += kAdd; + // se.Phy += (UInt64)1 << 63; // for debug + // se.Phy += 1; // for debug + se.Virt += kAdd; + extentStreamSpec->Extents.AddInReserved(se); + } + } + */ + } + + CSeekExtent se; + se.Phy = 0; + se.Virt = virt; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Stream = _stream; + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + totalSize += _items[index].GetSize(); + } + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + + const UInt64 size = _items[index].GetSize(); + totalSize += size; + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CMyComPtr inStream; + const HRESULT hres = GetStream(index, &inStream); + int opRes = NExtract::NOperationResult::kUnsupportedMethod; + if (hres != S_FALSE) + { + if (hres != S_OK) + return hres; + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) + opRes = NExtract::NOperationResult::kDataError; + if (copyCoderSpec->TotalSize == size) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoderSpec->TotalSize < size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "LP", "lpimg img", NULL, 0xc1, + k_Signature, + LP_PARTITION_RESERVED_BYTES, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/LvmHandler.cpp b/CPP/7zip/Archive/LvmHandler.cpp index 65db4b205..d144b2ab4 100644 --- a/CPP/7zip/Archive/LvmHandler.cpp +++ b/CPP/7zip/Archive/LvmHandler.cpp @@ -1,1107 +1,1107 @@ -// LvmHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/StringToInt.h" - -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define LE_32(offs, dest) dest = Get32(p + (offs)) -#define LE_64(offs, dest) dest = Get64(p + (offs)) - -using namespace NWindows; - -namespace NArchive { -namespace NLvm { - -#define SIGNATURE { 'L', 'A', 'B', 'E', 'L', 'O', 'N', 'E' } - -static const unsigned k_SignatureSize = 8; -static const Byte k_Signature[k_SignatureSize] = SIGNATURE; - -static const unsigned k_Signature2Size = 8; -static const Byte k_Signature2[k_Signature2Size] = - { 'L', 'V', 'M', '2', ' ', '0', '0', '1' }; - -static const Byte FMTT_MAGIC[16] = - { ' ', 'L', 'V', 'M', '2', ' ', 'x', '[', '5', 'A', '%', 'r', '0', 'N', '*', '>' }; - -static const UInt32 kSectorSize = 512; - - -struct CPropVal -{ - bool IsNumber; - AString String; - UInt64 Number; - - CPropVal(): IsNumber(false), Number(0) {} -}; - - -struct CConfigProp -{ - AString Name; - - bool IsVector; - CPropVal Val; - CObjectVector Vector; - - CConfigProp(): IsVector(false) {} -}; - - -class CConfigItem -{ -public: - AString Name; - CObjectVector Props; - CObjectVector Items; - - const char *ParseItem(const char *s, int numAllowedLevels); - - int FindProp(const char *name) const throw(); - bool GetPropVal_Number(const char *name, UInt64 &val) const throw(); - bool GetPropVal_String(const char *name, AString &val) const; - - int FindSubItem(const char *tag) const throw(); -}; - -struct CConfig -{ - CConfigItem Root; - - bool Parse(const char *s); -}; - - -static bool IsSpaceChar(char c) -{ - return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A); -} - -static const char *SkipSpaces(const char * s) -{ - for (;; s++) - { - const char c = *s; - if (c == 0) - return s; - if (!IsSpaceChar(c)) - { - if (c != '#') - return s; - s++; - for (;;) - { - const char c2 = *s; - if (c2 == 0) - return s; - if (c2 == '\n') - break; - s++; - } - } - } -} - -#define SKIP_SPACES(s) s = SkipSpaces(s); - -int CConfigItem::FindProp(const char *name) const throw() -{ - FOR_VECTOR (i, Props) - if (Props[i].Name == name) - return (int)i; - return -1; -} - -bool CConfigItem::GetPropVal_Number(const char *name, UInt64 &val) const throw() -{ - val = 0; - int index = FindProp(name); - if (index < 0) - return false; - const CConfigProp &prop = Props[index]; - if (prop.IsVector) - return false; - if (!prop.Val.IsNumber) - return false; - val = prop.Val.Number; - return true; -} - -bool CConfigItem::GetPropVal_String(const char *name, AString &val) const -{ - val.Empty(); - int index = FindProp(name); - if (index < 0) - return false; - const CConfigProp &prop = Props[index]; - if (prop.IsVector) - return false; - if (prop.Val.IsNumber) - return false; - val = prop.Val.String; - return true; -} - -int CConfigItem::FindSubItem(const char *tag) const throw() -{ - FOR_VECTOR (i, Items) - if (Items[i].Name == tag) - return (int)i; - return -1; -} - -static const char *FillProp(const char *s, CPropVal &val) -{ - SKIP_SPACES(s) - const char c = *s; - if (c == 0) - return NULL; - - if (c == '\"') - { - s++; - val.IsNumber = false; - val.String.Empty(); - - for (;;) - { - const char c2 = *s; - if (c2 == 0) - return NULL; - s++; - if (c2 == '\"') - break; - val.String += c2; - } - } - else - { - const char *end; - val.IsNumber = true; - val.Number = ConvertStringToUInt64(s, &end); - if (s == end) - return NULL; - s = end; - } - - SKIP_SPACES(s) - return s; -} - - -const char *CConfigItem::ParseItem(const char *s, int numAllowedLevels) -{ - if (numAllowedLevels < 0) - return NULL; - - for (;;) - { - SKIP_SPACES(s) - const char *beg = s; - - for (;; s++) - { - char c = *s; - if (c == 0 || c == '}') - { - if (s != beg) - return NULL; - return s; - } - if (IsSpaceChar(c) || c == '=' || c == '{') - break; - } - - if (s == beg) - return NULL; - - AString name; - name.SetFrom(beg, (unsigned)(s - beg)); - - SKIP_SPACES(s) - - if (*s == 0 || *s == '}') - return NULL; - - if (*s == '{') - { - s++; - CConfigItem &item = Items.AddNew(); - item.Name = name; - s = item.ParseItem(s, numAllowedLevels - 1); - if (!s) - return NULL; - if (*s != '}') - return NULL; - s++; - continue; - } - - if (*s != '=') - continue; - - s++; - SKIP_SPACES(s) - if (*s == 0) - return NULL; - CConfigProp &prop = Props.AddNew(); - - prop.Name = name; - - if (*s == '[') - { - s++; - prop.IsVector = true; - - for (;;) - { - SKIP_SPACES(s) - char c = *s; - if (c == 0) - return NULL; - if (c == ']') - { - s++; - break; - } - - CPropVal val; - - s = FillProp(s, val); - if (!s) - return NULL; - prop.Vector.Add(val); - SKIP_SPACES(s) - - if (*s == ',') - { - s++; - continue; - } - if (*s != ']') - return NULL; - s++; - break; - } - } - else - { - prop.IsVector = false; - s = FillProp(s, prop.Val); - if (!s) - return NULL; - } - } -} - - -bool CConfig::Parse(const char *s) -{ - s = Root.ParseItem(s, 10); - if (!s) - return false; - SKIP_SPACES(s) - return *s == 0; -} - - -/* -static const CUInt32PCharPair g_PartitionFlags[] = -{ - { 0, "Sys" }, - { 1, "Ignore" }, - { 2, "Legacy" }, - { 60, "Win-Read-only" }, - { 62, "Win-Hidden" }, - { 63, "Win-Not-Automount" } -}; -*/ - -/* -static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } - -static void PrintHex(unsigned v, char *s) -{ - s[0] = GetHex((v >> 4) & 0xF); - s[1] = GetHex(v & 0xF); -} - -static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw() -{ - PrintHex(val >> 8, s); - PrintHex(val & 0xFF, s + 2); -} - -static void GuidToString(const Byte *g, char *s) -{ - ConvertUInt32ToHex8Digits(Get32(g ), s); s += 8; *s++ = '-'; - ConvertUInt16ToHex4Digits(Get16(g + 4), s); s += 4; *s++ = '-'; - ConvertUInt16ToHex4Digits(Get16(g + 6), s); s += 4; *s++ = '-'; - for (unsigned i = 0; i < 8; i++) - { - if (i == 2) - *s++ = '-'; - PrintHex(g[8 + i], s); - s += 2; - } - *s = 0; -} - -*/ - -struct CPhyVol -{ - AString Name; - - // AString id; - // AString device; // "/dev/sda2" - // AString status; // ["ALLOCATABLE"] - // AString flags; // [] - // UInt64 dev_size; // in sectors - UInt64 pe_start; // in sectors - UInt64 pe_count; // in extents - - bool Parse(const CConfigItem &ci) - { - Name = ci.Name; - // ci.GetPropVal_String("id", id); - // ci.GetPropVal_String("device", device); - bool res = true; - // if (!ci.GetPropVal_Number("dev_size", dev_size)) res = false; - if (!ci.GetPropVal_Number("pe_start", pe_start)) res = false; - if (!ci.GetPropVal_Number("pe_count", pe_count)) res = false; - return res; - } -}; - -struct CStripe -{ - AString Name; // "pv0"; - UInt64 ExtentOffset; // ???? -}; - -struct CSegment -{ - UInt64 start_extent; - UInt64 extent_count; - AString type; - CObjectVector stripes; - - bool IsPosSizeOk() const - { - return - (start_extent < ((UInt64)1 << 63)) && - (extent_count < ((UInt64)1 << 63)); - } - - UInt64 GetEndExtent() const { return start_extent + extent_count; } - - bool Parse(const CConfigItem &si) - { - UInt64 stripe_count; - - if (!si.GetPropVal_Number("start_extent", start_extent)) return false; - if (!si.GetPropVal_Number("extent_count", extent_count)) return false; - if (!si.GetPropVal_Number("stripe_count", stripe_count)) return false; - if (!si.GetPropVal_String("type", type)) return false; - - //if (stripe_count != 1) return false; - - const int spi = si.FindProp("stripes"); - if (spi < 0) - return false; - - const CConfigProp &prop = si.Props[spi]; - if (!prop.IsVector) - return false; - - if (stripe_count > (1 << 20)) - return false; - - const unsigned numStripes = (unsigned)stripe_count; - if (prop.Vector.Size() != numStripes * 2) - return false; - - for (unsigned i = 0; i < numStripes; i++) - { - const CPropVal &v0 = prop.Vector[i * 2]; - const CPropVal &v1 = prop.Vector[i * 2 + 1]; - if (v0.IsNumber || !v1.IsNumber) - return false; - CStripe stripe; - stripe.Name = v0.String; - stripe.ExtentOffset = v1.Number; - stripes.Add(stripe); - } - - return true; - } -}; - - -struct CLogVol -{ - bool IsSupported; - - AString Name; - - AString id; - AString status; // ["READ", "WRITE", "VISIBLE"] - AString flags; // [] - - // UInt64 Pos; - // UInt64 Size; - - // UInt64 GetSize() const { return Size; } - // UInt64 GetPos() const { return Pos; } - - CObjectVector Segments; - - CLogVol(): /* Pos(0), Size(0), */ IsSupported(false) {} - - bool Parse(const CConfigItem &ci) - { - Name = ci.Name; - - UInt64 segment_count; - if (!ci.GetPropVal_Number("segment_count", segment_count)) - return false; - - if (ci.Items.Size() != segment_count) - return false; - - FOR_VECTOR (segIndex, ci.Items) - { - const CConfigItem &si = ci.Items[segIndex]; - { - AString t ("segment"); - t.Add_UInt32(segIndex + 1); - if (si.Name != t) - return false; - } - - CSegment segment; - - if (!segment.Parse(si)) - return false; - - // item.Size += (segment.extent_count * _extentSize) << 9; - - Segments.Add(segment); - } - - IsSupported = true; - return true; - } - - bool GetNumExtents(UInt64 &numExtents) const - { - numExtents = 0; - if (Segments.IsEmpty()) - return true; - unsigned i; - for (i = 1; i < Segments.Size(); i++) - if (!Segments[i].IsPosSizeOk()) - return false; - for (i = 1; i < Segments.Size(); i++) - if (Segments[i - 1].GetEndExtent() != Segments[i].start_extent) - return false; - numExtents = Segments.Back().GetEndExtent(); - return true; - } -}; - - -struct CItem -{ - int LogVol; - int PhyVol; - UInt64 Pos; - UInt64 Size; - AString Name; - bool IsSupported; - - CItem(): LogVol(-1), PhyVol(-1), Pos(0), Size(0), IsSupported(false) {} -}; - - -struct CVolGroup -{ - CObjectVector _logVols; - CObjectVector _phyVols; - AString _id; - int _extentSizeBits; - - /* - UInt64 secno; // 3 - AString status; // ["RESIZEABLE", "READ", "WRITE"] - AString flags; // [] - UInt64 max_lv; // 0 - UInt64 max_pv; // 0 - UInt64 metadata_copies; // 0 - */ - - void Clear() - { - _logVols.Clear(); - _phyVols.Clear(); - _id.Empty(); - _extentSizeBits = -1; - } -}; - - -Z7_class_CHandler_final: public CHandlerCont, public CVolGroup -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - CObjectVector _items; - - UInt64 _cTime; - - bool _isArc; - - UInt64 _phySize; - CByteBuffer _buffer; - - UInt64 _cfgPos; - UInt64 _cfgSize; - - HRESULT Open2(IInStream *stream); - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override - { - if (index >= _items.Size()) - { - pos = _cfgPos; - size = _cfgSize; - return NExtract::NOperationResult::kOK; - } - const CItem &item = _items[index]; - if (!item.IsSupported) - return NExtract::NOperationResult::kUnsupportedMethod; - pos = item.Pos; - size = item.Size; - return NExtract::NOperationResult::kOK; - } -}; - -static const UInt32 LVM_CRC_INIT_VAL = 0xf597a6cf; - -static UInt32 Z7_FASTCALL LvmCrcCalc(const void *data, size_t size) -{ - return CrcUpdate(LVM_CRC_INIT_VAL, data, size); -} - -struct CRawLocn -{ - UInt64 Offset; /* Offset in bytes to start sector */ - UInt64 Size; /* Bytes */ - UInt32 Checksum; - UInt32 Flags; - - bool IsEmpty() const { return Offset == 0 && Size == 0; } - - void Parse(const Byte *p) - { - LE_64(0x00, Offset); - LE_64(0x08, Size); - LE_32(0x10, Checksum); - LE_32(0x14, Flags); - } -}; - -// #define MDA_HEADER_SIZE 512 - -struct mda_header -{ - UInt64 Start; /* Absolute start byte of mda_header */ - UInt64 Size; /* Size of metadata area */ - - CRecordVector raw_locns; - - bool Parse(const Byte *p, size_t size) - { - if (memcmp(p + 4, FMTT_MAGIC, 16) != 0) - return false; - UInt32 version; - LE_32(0x14, version); - if (version != 1) - return false; - LE_64(0x18, Start); - LE_64(0x20, Size); - - unsigned pos = 0x28; - - for (;;) - { - if (pos + 0x18 > size) - return false; - CRawLocn locn; - locn.Parse(p + pos); - if (locn.IsEmpty()) - break; - pos += 0x18; - raw_locns.Add(locn); - } - - return true; - } -}; - - -static int inline GetLog(UInt64 num) -{ - for (unsigned i = 0; i < 64; i++) - if (((UInt64)1 << i) == num) - return (int)i; - return -1; -} - -#define ID_LEN 32 - -HRESULT CHandler::Open2(IInStream *stream) -{ - _buffer.Alloc(kSectorSize * 2); - RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2)) - - const Byte *buf = _buffer; - - buf += kSectorSize; - - // label_header - - if (memcmp(buf, k_Signature, k_SignatureSize) != 0) - return S_FALSE; - const UInt64 sectorNumber = Get64(buf + 8); - if (sectorNumber != 1) - return S_FALSE; - if (Get32(buf + 16) != LvmCrcCalc(buf + 20, kSectorSize - 20)) - return S_FALSE; - - const UInt32 offsetToCont = Get32(buf + 20); - if (memcmp(buf + 24, k_Signature2, k_Signature2Size) != 0) - return S_FALSE; - - if (offsetToCont != 32) - return S_FALSE; - - // pv_header - - size_t pos = offsetToCont; - const Byte *p = buf; - - /* - { - Byte id[ID_LEN]; - memcpy(id, p + pos, ID_LEN); - } - */ - - pos += ID_LEN; - const UInt64 device_size_xl = Get64(p + pos); - pos += 8; - - _phySize = device_size_xl; - _isArc = true; - - for (;;) - { - if (pos > kSectorSize - 16) - return S_FALSE; - // disk_locn (data areas) - UInt64 offset = Get64(p + pos); - UInt64 size = Get64(p + pos + 8); - pos += 16; - if (offset == 0 && size == 0) - break; - } - - CConfig cfg; - // bool isFinded = false; - - // for (;;) - { - if (pos > kSectorSize - 16) - return S_FALSE; - // disk_locn (metadata area headers) - UInt64 offset = Get64(p + pos); - UInt64 size = Get64(p + pos + 8); - pos += 16; - if (offset == 0 && size == 0) - { - // break; - return S_FALSE; - } - - CByteBuffer meta; - const size_t sizeT = (size_t)size; - if (sizeT != size) - return S_FALSE; - meta.Alloc(sizeT); - RINOK(InStream_SeekSet(stream, offset)) - RINOK(ReadStream_FALSE(stream, meta, sizeT)) - if (Get32(meta) != LvmCrcCalc(meta + 4, kSectorSize - 4)) - return S_FALSE; - mda_header mh; - if (!mh.Parse(meta, kSectorSize)) - return S_FALSE; - - if (mh.raw_locns.Size() != 1) - return S_FALSE; - unsigned g = 0; - // for (unsigned g = 0; g < mh.raw_locns.Size(); g++) - { - const CRawLocn &locn = mh.raw_locns[g]; - - CByteBuffer vgBuf; - if (locn.Size > ((UInt32)1 << 24)) - return S_FALSE; - - const size_t vgSize = (size_t)locn.Size; - if (vgSize == 0) - return S_FALSE; - - vgBuf.Alloc(vgSize); - - _cfgPos = offset + locn.Offset; - _cfgSize = vgSize; - RINOK(InStream_SeekSet(stream, _cfgPos)) - RINOK(ReadStream_FALSE(stream, vgBuf, vgSize)) - if (locn.Checksum != LvmCrcCalc(vgBuf, vgSize)) - return S_FALSE; - - { - AString s; - s.SetFrom_CalcLen((const char *)(const Byte *)vgBuf, (unsigned)vgSize); - _cfgSize = s.Len(); - if (!cfg.Parse(s)) - return S_FALSE; - // isFinded = true; - // break; - } - } - - // if (isFinded) break; - } - - // if (!isFinded) return S_FALSE; - - if (cfg.Root.Items.Size() != 1) - return S_FALSE; - const CConfigItem &volGroup = cfg.Root.Items[0]; - if (volGroup.Name != "VolGroup00") - return S_FALSE; - - volGroup.GetPropVal_String("id", _id); - - if (!cfg.Root.GetPropVal_Number("creation_time", _cTime)) - _cTime = 0; - - UInt64 extentSize; - if (!volGroup.GetPropVal_Number("extent_size", extentSize)) - return S_FALSE; - - _extentSizeBits = GetLog(extentSize); - if (_extentSizeBits < 0 || _extentSizeBits > (62 - 9)) - return S_FALSE; - - - { - int pvsIndex = volGroup.FindSubItem("physical_volumes"); - if (pvsIndex < 0) - return S_FALSE; - - const CConfigItem &phyVols = volGroup.Items[pvsIndex]; - - FOR_VECTOR (i, phyVols.Items) - { - const CConfigItem &ci = phyVols.Items[i]; - CPhyVol pv; - if (!pv.Parse(ci)) - return S_FALSE; - _phyVols.Add(pv); - } - } - - { - int lvIndex = volGroup.FindSubItem("logical_volumes"); - if (lvIndex < 0) - return S_FALSE; - - const CConfigItem &logVolumes = volGroup.Items[lvIndex]; - - FOR_VECTOR (i, logVolumes.Items) - { - const CConfigItem &ci = logVolumes.Items[i]; - CLogVol &lv = _logVols.AddNew(); - lv.Parse(ci) ; // check error - } - } - - { - FOR_VECTOR (i, _logVols) - { - CLogVol &lv = _logVols[i]; - - CItem item; - - item.LogVol = (int)i; - item.Pos = 0; - item.Size = 0; - item.Name = lv.Name; - - if (lv.IsSupported) - { - UInt64 numExtents; - lv.IsSupported = lv.GetNumExtents(numExtents); - - if (lv.IsSupported) - { - lv.IsSupported = false; - item.Size = numExtents << (_extentSizeBits + 9); - - if (lv.Segments.Size() == 1) - { - const CSegment &segment = lv.Segments[0]; - if (segment.stripes.Size() == 1) - { - const CStripe &stripe = segment.stripes[0]; - FOR_VECTOR (pvIndex, _phyVols) - { - const CPhyVol &pv = _phyVols[pvIndex]; - if (pv.Name == stripe.Name) - { - item.Pos = (pv.pe_start + (stripe.ExtentOffset << _extentSizeBits)) << 9; - lv.IsSupported = true; - item.IsSupported = true; - break; - } - } - } - } - } - } - - _items.Add(item); - } - } - - { - FOR_VECTOR (i, _phyVols) - { - const CPhyVol &pv = _phyVols[i]; - - if (pv.pe_start > (UInt64)1 << (62 - 9)) - return S_FALSE; - if (pv.pe_count > (UInt64)1 << (62 - 9 - _extentSizeBits)) - return S_FALSE; - - CItem item; - - item.PhyVol = (int)i; - item.Pos = pv.pe_start << 9; - item.Size = pv.pe_count << (_extentSizeBits + 9); - item.Name = pv.Name; - item.IsSupported = true; - - _items.Add(item); - } - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(stream)) - _stream = stream; - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - CVolGroup::Clear(); - - _cfgPos = 0; - _cfgSize = 0; - _cTime = 0; - _phySize = 0; - _isArc = false; - _items.Clear(); - - _stream.Release(); - return S_OK; -} - - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidFileSystem, - kpidCharacts, - kpidOffset, - kpidId -}; - -static const Byte kArcProps[] = -{ - kpidId, - kpidCTime, - kpidClusterSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidMainSubfile: - { - /* - if (_items.Size() == 1) - prop = (UInt32)0; - */ - break; - } - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - case kpidId: - { - prop = _id; - break; - } - case kpidClusterSize: - { - if (_extentSizeBits >= 0) - prop = ((UInt64)1 << (_extentSizeBits + 9)); - break; - } - case kpidCTime: - { - if (_cTime != 0) - { - FILETIME ft; - NTime::UnixTime64_To_FileTime((Int64)_cTime, ft); - prop = ft; - } - break; - } - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; - // if (_headerError) v |= kpv_ErrorFlags_HeadersError; - if (v == 0 && !_stream) - v |= kpv_ErrorFlags_UnsupportedMethod; - if (v != 0) - prop = v; - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size() + (_cfgSize == 0 ? 0 : 1); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CItem &item = _items[index]; - - // const CLogVol &item = _items[index]; - - if (index >= _items.Size()) - { - switch (propID) - { - case kpidPath: - { - prop = "meta.txt"; - break; - } - - case kpidSize: - case kpidPackSize: prop = _cfgSize; break; - } - } - else - { - switch (propID) - { - case kpidPath: - { - AString s = item.Name; - s += ".img"; - prop = s; - break; - } - - case kpidSize: - case kpidPackSize: prop = item.Size; break; - case kpidOffset: prop = item.Pos; break; - - case kpidId: - { - // prop = item.id; - break; - } - - // case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -REGISTER_ARC_I( - "LVM", "lvm", NULL, 0xBF, - k_Signature, - kSectorSize, - 0, - NULL) - -}} +// LvmHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringToInt.h" + +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define LE_32(offs, dest) dest = Get32(p + (offs)) +#define LE_64(offs, dest) dest = Get64(p + (offs)) + +using namespace NWindows; + +namespace NArchive { +namespace NLvm { + +#define SIGNATURE { 'L', 'A', 'B', 'E', 'L', 'O', 'N', 'E' } + +static const unsigned k_SignatureSize = 8; +static const Byte k_Signature[k_SignatureSize] = SIGNATURE; + +static const unsigned k_Signature2Size = 8; +static const Byte k_Signature2[k_Signature2Size] = + { 'L', 'V', 'M', '2', ' ', '0', '0', '1' }; + +static const Byte FMTT_MAGIC[16] = + { ' ', 'L', 'V', 'M', '2', ' ', 'x', '[', '5', 'A', '%', 'r', '0', 'N', '*', '>' }; + +static const UInt32 kSectorSize = 512; + + +struct CPropVal +{ + bool IsNumber; + AString String; + UInt64 Number; + + CPropVal(): IsNumber(false), Number(0) {} +}; + + +struct CConfigProp +{ + AString Name; + + bool IsVector; + CPropVal Val; + CObjectVector Vector; + + CConfigProp(): IsVector(false) {} +}; + + +class CConfigItem +{ +public: + AString Name; + CObjectVector Props; + CObjectVector Items; + + const char *ParseItem(const char *s, int numAllowedLevels); + + int FindProp(const char *name) const throw(); + bool GetPropVal_Number(const char *name, UInt64 &val) const throw(); + bool GetPropVal_String(const char *name, AString &val) const; + + int FindSubItem(const char *tag) const throw(); +}; + +struct CConfig +{ + CConfigItem Root; + + bool Parse(const char *s); +}; + + +static bool IsSpaceChar(char c) +{ + return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A); +} + +static const char *SkipSpaces(const char * s) +{ + for (;; s++) + { + const char c = *s; + if (c == 0) + return s; + if (!IsSpaceChar(c)) + { + if (c != '#') + return s; + s++; + for (;;) + { + const char c2 = *s; + if (c2 == 0) + return s; + if (c2 == '\n') + break; + s++; + } + } + } +} + +#define SKIP_SPACES(s) s = SkipSpaces(s); + +int CConfigItem::FindProp(const char *name) const throw() +{ + FOR_VECTOR (i, Props) + if (Props[i].Name == name) + return (int)i; + return -1; +} + +bool CConfigItem::GetPropVal_Number(const char *name, UInt64 &val) const throw() +{ + val = 0; + int index = FindProp(name); + if (index < 0) + return false; + const CConfigProp &prop = Props[index]; + if (prop.IsVector) + return false; + if (!prop.Val.IsNumber) + return false; + val = prop.Val.Number; + return true; +} + +bool CConfigItem::GetPropVal_String(const char *name, AString &val) const +{ + val.Empty(); + int index = FindProp(name); + if (index < 0) + return false; + const CConfigProp &prop = Props[index]; + if (prop.IsVector) + return false; + if (prop.Val.IsNumber) + return false; + val = prop.Val.String; + return true; +} + +int CConfigItem::FindSubItem(const char *tag) const throw() +{ + FOR_VECTOR (i, Items) + if (Items[i].Name == tag) + return (int)i; + return -1; +} + +static const char *FillProp(const char *s, CPropVal &val) +{ + SKIP_SPACES(s) + const char c = *s; + if (c == 0) + return NULL; + + if (c == '\"') + { + s++; + val.IsNumber = false; + val.String.Empty(); + + for (;;) + { + const char c2 = *s; + if (c2 == 0) + return NULL; + s++; + if (c2 == '\"') + break; + val.String += c2; + } + } + else + { + const char *end; + val.IsNumber = true; + val.Number = ConvertStringToUInt64(s, &end); + if (s == end) + return NULL; + s = end; + } + + SKIP_SPACES(s) + return s; +} + + +const char *CConfigItem::ParseItem(const char *s, int numAllowedLevels) +{ + if (numAllowedLevels < 0) + return NULL; + + for (;;) + { + SKIP_SPACES(s) + const char *beg = s; + + for (;; s++) + { + char c = *s; + if (c == 0 || c == '}') + { + if (s != beg) + return NULL; + return s; + } + if (IsSpaceChar(c) || c == '=' || c == '{') + break; + } + + if (s == beg) + return NULL; + + AString name; + name.SetFrom(beg, (unsigned)(s - beg)); + + SKIP_SPACES(s) + + if (*s == 0 || *s == '}') + return NULL; + + if (*s == '{') + { + s++; + CConfigItem &item = Items.AddNew(); + item.Name = name; + s = item.ParseItem(s, numAllowedLevels - 1); + if (!s) + return NULL; + if (*s != '}') + return NULL; + s++; + continue; + } + + if (*s != '=') + continue; + + s++; + SKIP_SPACES(s) + if (*s == 0) + return NULL; + CConfigProp &prop = Props.AddNew(); + + prop.Name = name; + + if (*s == '[') + { + s++; + prop.IsVector = true; + + for (;;) + { + SKIP_SPACES(s) + char c = *s; + if (c == 0) + return NULL; + if (c == ']') + { + s++; + break; + } + + CPropVal val; + + s = FillProp(s, val); + if (!s) + return NULL; + prop.Vector.Add(val); + SKIP_SPACES(s) + + if (*s == ',') + { + s++; + continue; + } + if (*s != ']') + return NULL; + s++; + break; + } + } + else + { + prop.IsVector = false; + s = FillProp(s, prop.Val); + if (!s) + return NULL; + } + } +} + + +bool CConfig::Parse(const char *s) +{ + s = Root.ParseItem(s, 10); + if (!s) + return false; + SKIP_SPACES(s) + return *s == 0; +} + + +/* +static const CUInt32PCharPair g_PartitionFlags[] = +{ + { 0, "Sys" }, + { 1, "Ignore" }, + { 2, "Legacy" }, + { 60, "Win-Read-only" }, + { 62, "Win-Hidden" }, + { 63, "Win-Not-Automount" } +}; +*/ + +/* +static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); } + +static void PrintHex(unsigned v, char *s) +{ + s[0] = GetHex((v >> 4) & 0xF); + s[1] = GetHex(v & 0xF); +} + +static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw() +{ + PrintHex(val >> 8, s); + PrintHex(val & 0xFF, s + 2); +} + +static void GuidToString(const Byte *g, char *s) +{ + ConvertUInt32ToHex8Digits(Get32(g ), s); s += 8; *s++ = '-'; + ConvertUInt16ToHex4Digits(Get16(g + 4), s); s += 4; *s++ = '-'; + ConvertUInt16ToHex4Digits(Get16(g + 6), s); s += 4; *s++ = '-'; + for (unsigned i = 0; i < 8; i++) + { + if (i == 2) + *s++ = '-'; + PrintHex(g[8 + i], s); + s += 2; + } + *s = 0; +} + +*/ + +struct CPhyVol +{ + AString Name; + + // AString id; + // AString device; // "/dev/sda2" + // AString status; // ["ALLOCATABLE"] + // AString flags; // [] + // UInt64 dev_size; // in sectors + UInt64 pe_start; // in sectors + UInt64 pe_count; // in extents + + bool Parse(const CConfigItem &ci) + { + Name = ci.Name; + // ci.GetPropVal_String("id", id); + // ci.GetPropVal_String("device", device); + bool res = true; + // if (!ci.GetPropVal_Number("dev_size", dev_size)) res = false; + if (!ci.GetPropVal_Number("pe_start", pe_start)) res = false; + if (!ci.GetPropVal_Number("pe_count", pe_count)) res = false; + return res; + } +}; + +struct CStripe +{ + AString Name; // "pv0"; + UInt64 ExtentOffset; // ???? +}; + +struct CSegment +{ + UInt64 start_extent; + UInt64 extent_count; + AString type; + CObjectVector stripes; + + bool IsPosSizeOk() const + { + return + (start_extent < ((UInt64)1 << 63)) && + (extent_count < ((UInt64)1 << 63)); + } + + UInt64 GetEndExtent() const { return start_extent + extent_count; } + + bool Parse(const CConfigItem &si) + { + UInt64 stripe_count; + + if (!si.GetPropVal_Number("start_extent", start_extent)) return false; + if (!si.GetPropVal_Number("extent_count", extent_count)) return false; + if (!si.GetPropVal_Number("stripe_count", stripe_count)) return false; + if (!si.GetPropVal_String("type", type)) return false; + + //if (stripe_count != 1) return false; + + const int spi = si.FindProp("stripes"); + if (spi < 0) + return false; + + const CConfigProp &prop = si.Props[spi]; + if (!prop.IsVector) + return false; + + if (stripe_count > (1 << 20)) + return false; + + const unsigned numStripes = (unsigned)stripe_count; + if (prop.Vector.Size() != numStripes * 2) + return false; + + for (unsigned i = 0; i < numStripes; i++) + { + const CPropVal &v0 = prop.Vector[i * 2]; + const CPropVal &v1 = prop.Vector[i * 2 + 1]; + if (v0.IsNumber || !v1.IsNumber) + return false; + CStripe stripe; + stripe.Name = v0.String; + stripe.ExtentOffset = v1.Number; + stripes.Add(stripe); + } + + return true; + } +}; + + +struct CLogVol +{ + bool IsSupported; + + AString Name; + + AString id; + AString status; // ["READ", "WRITE", "VISIBLE"] + AString flags; // [] + + // UInt64 Pos; + // UInt64 Size; + + // UInt64 GetSize() const { return Size; } + // UInt64 GetPos() const { return Pos; } + + CObjectVector Segments; + + CLogVol(): /* Pos(0), Size(0), */ IsSupported(false) {} + + bool Parse(const CConfigItem &ci) + { + Name = ci.Name; + + UInt64 segment_count; + if (!ci.GetPropVal_Number("segment_count", segment_count)) + return false; + + if (ci.Items.Size() != segment_count) + return false; + + FOR_VECTOR (segIndex, ci.Items) + { + const CConfigItem &si = ci.Items[segIndex]; + { + AString t ("segment"); + t.Add_UInt32(segIndex + 1); + if (si.Name != t) + return false; + } + + CSegment segment; + + if (!segment.Parse(si)) + return false; + + // item.Size += (segment.extent_count * _extentSize) << 9; + + Segments.Add(segment); + } + + IsSupported = true; + return true; + } + + bool GetNumExtents(UInt64 &numExtents) const + { + numExtents = 0; + if (Segments.IsEmpty()) + return true; + unsigned i; + for (i = 1; i < Segments.Size(); i++) + if (!Segments[i].IsPosSizeOk()) + return false; + for (i = 1; i < Segments.Size(); i++) + if (Segments[i - 1].GetEndExtent() != Segments[i].start_extent) + return false; + numExtents = Segments.Back().GetEndExtent(); + return true; + } +}; + + +struct CItem +{ + int LogVol; + int PhyVol; + UInt64 Pos; + UInt64 Size; + AString Name; + bool IsSupported; + + CItem(): LogVol(-1), PhyVol(-1), Pos(0), Size(0), IsSupported(false) {} +}; + + +struct CVolGroup +{ + CObjectVector _logVols; + CObjectVector _phyVols; + AString _id; + int _extentSizeBits; + + /* + UInt64 secno; // 3 + AString status; // ["RESIZEABLE", "READ", "WRITE"] + AString flags; // [] + UInt64 max_lv; // 0 + UInt64 max_pv; // 0 + UInt64 metadata_copies; // 0 + */ + + void Clear() + { + _logVols.Clear(); + _phyVols.Clear(); + _id.Empty(); + _extentSizeBits = -1; + } +}; + + +Z7_class_CHandler_final: public CHandlerCont, public CVolGroup +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + CObjectVector _items; + + UInt64 _cTime; + + bool _isArc; + + UInt64 _phySize; + CByteBuffer _buffer; + + UInt64 _cfgPos; + UInt64 _cfgSize; + + HRESULT Open2(IInStream *stream); + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override + { + if (index >= _items.Size()) + { + pos = _cfgPos; + size = _cfgSize; + return NExtract::NOperationResult::kOK; + } + const CItem &item = _items[index]; + if (!item.IsSupported) + return NExtract::NOperationResult::kUnsupportedMethod; + pos = item.Pos; + size = item.Size; + return NExtract::NOperationResult::kOK; + } +}; + +static const UInt32 LVM_CRC_INIT_VAL = 0xf597a6cf; + +static UInt32 Z7_FASTCALL LvmCrcCalc(const void *data, size_t size) +{ + return CrcUpdate(LVM_CRC_INIT_VAL, data, size); +} + +struct CRawLocn +{ + UInt64 Offset; /* Offset in bytes to start sector */ + UInt64 Size; /* Bytes */ + UInt32 Checksum; + UInt32 Flags; + + bool IsEmpty() const { return Offset == 0 && Size == 0; } + + void Parse(const Byte *p) + { + LE_64(0x00, Offset); + LE_64(0x08, Size); + LE_32(0x10, Checksum); + LE_32(0x14, Flags); + } +}; + +// #define MDA_HEADER_SIZE 512 + +struct mda_header +{ + UInt64 Start; /* Absolute start byte of mda_header */ + UInt64 Size; /* Size of metadata area */ + + CRecordVector raw_locns; + + bool Parse(const Byte *p, size_t size) + { + if (memcmp(p + 4, FMTT_MAGIC, 16) != 0) + return false; + UInt32 version; + LE_32(0x14, version); + if (version != 1) + return false; + LE_64(0x18, Start); + LE_64(0x20, Size); + + unsigned pos = 0x28; + + for (;;) + { + if (pos + 0x18 > size) + return false; + CRawLocn locn; + locn.Parse(p + pos); + if (locn.IsEmpty()) + break; + pos += 0x18; + raw_locns.Add(locn); + } + + return true; + } +}; + + +static int inline GetLog(UInt64 num) +{ + for (unsigned i = 0; i < 64; i++) + if (((UInt64)1 << i) == num) + return (int)i; + return -1; +} + +#define ID_LEN 32 + +HRESULT CHandler::Open2(IInStream *stream) +{ + _buffer.Alloc(kSectorSize * 2); + RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2)) + + const Byte *buf = _buffer; + + buf += kSectorSize; + + // label_header + + if (memcmp(buf, k_Signature, k_SignatureSize) != 0) + return S_FALSE; + const UInt64 sectorNumber = Get64(buf + 8); + if (sectorNumber != 1) + return S_FALSE; + if (Get32(buf + 16) != LvmCrcCalc(buf + 20, kSectorSize - 20)) + return S_FALSE; + + const UInt32 offsetToCont = Get32(buf + 20); + if (memcmp(buf + 24, k_Signature2, k_Signature2Size) != 0) + return S_FALSE; + + if (offsetToCont != 32) + return S_FALSE; + + // pv_header + + size_t pos = offsetToCont; + const Byte *p = buf; + + /* + { + Byte id[ID_LEN]; + memcpy(id, p + pos, ID_LEN); + } + */ + + pos += ID_LEN; + const UInt64 device_size_xl = Get64(p + pos); + pos += 8; + + _phySize = device_size_xl; + _isArc = true; + + for (;;) + { + if (pos > kSectorSize - 16) + return S_FALSE; + // disk_locn (data areas) + UInt64 offset = Get64(p + pos); + UInt64 size = Get64(p + pos + 8); + pos += 16; + if (offset == 0 && size == 0) + break; + } + + CConfig cfg; + // bool isFinded = false; + + // for (;;) + { + if (pos > kSectorSize - 16) + return S_FALSE; + // disk_locn (metadata area headers) + UInt64 offset = Get64(p + pos); + UInt64 size = Get64(p + pos + 8); + pos += 16; + if (offset == 0 && size == 0) + { + // break; + return S_FALSE; + } + + CByteBuffer meta; + const size_t sizeT = (size_t)size; + if (sizeT != size) + return S_FALSE; + meta.Alloc(sizeT); + RINOK(InStream_SeekSet(stream, offset)) + RINOK(ReadStream_FALSE(stream, meta, sizeT)) + if (Get32(meta) != LvmCrcCalc(meta + 4, kSectorSize - 4)) + return S_FALSE; + mda_header mh; + if (!mh.Parse(meta, kSectorSize)) + return S_FALSE; + + if (mh.raw_locns.Size() != 1) + return S_FALSE; + unsigned g = 0; + // for (unsigned g = 0; g < mh.raw_locns.Size(); g++) + { + const CRawLocn &locn = mh.raw_locns[g]; + + CByteBuffer vgBuf; + if (locn.Size > ((UInt32)1 << 24)) + return S_FALSE; + + const size_t vgSize = (size_t)locn.Size; + if (vgSize == 0) + return S_FALSE; + + vgBuf.Alloc(vgSize); + + _cfgPos = offset + locn.Offset; + _cfgSize = vgSize; + RINOK(InStream_SeekSet(stream, _cfgPos)) + RINOK(ReadStream_FALSE(stream, vgBuf, vgSize)) + if (locn.Checksum != LvmCrcCalc(vgBuf, vgSize)) + return S_FALSE; + + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)vgBuf, (unsigned)vgSize); + _cfgSize = s.Len(); + if (!cfg.Parse(s)) + return S_FALSE; + // isFinded = true; + // break; + } + } + + // if (isFinded) break; + } + + // if (!isFinded) return S_FALSE; + + if (cfg.Root.Items.Size() != 1) + return S_FALSE; + const CConfigItem &volGroup = cfg.Root.Items[0]; + if (volGroup.Name != "VolGroup00") + return S_FALSE; + + volGroup.GetPropVal_String("id", _id); + + if (!cfg.Root.GetPropVal_Number("creation_time", _cTime)) + _cTime = 0; + + UInt64 extentSize; + if (!volGroup.GetPropVal_Number("extent_size", extentSize)) + return S_FALSE; + + _extentSizeBits = GetLog(extentSize); + if (_extentSizeBits < 0 || _extentSizeBits > (62 - 9)) + return S_FALSE; + + + { + int pvsIndex = volGroup.FindSubItem("physical_volumes"); + if (pvsIndex < 0) + return S_FALSE; + + const CConfigItem &phyVols = volGroup.Items[pvsIndex]; + + FOR_VECTOR (i, phyVols.Items) + { + const CConfigItem &ci = phyVols.Items[i]; + CPhyVol pv; + if (!pv.Parse(ci)) + return S_FALSE; + _phyVols.Add(pv); + } + } + + { + int lvIndex = volGroup.FindSubItem("logical_volumes"); + if (lvIndex < 0) + return S_FALSE; + + const CConfigItem &logVolumes = volGroup.Items[lvIndex]; + + FOR_VECTOR (i, logVolumes.Items) + { + const CConfigItem &ci = logVolumes.Items[i]; + CLogVol &lv = _logVols.AddNew(); + lv.Parse(ci) ; // check error + } + } + + { + FOR_VECTOR (i, _logVols) + { + CLogVol &lv = _logVols[i]; + + CItem item; + + item.LogVol = (int)i; + item.Pos = 0; + item.Size = 0; + item.Name = lv.Name; + + if (lv.IsSupported) + { + UInt64 numExtents; + lv.IsSupported = lv.GetNumExtents(numExtents); + + if (lv.IsSupported) + { + lv.IsSupported = false; + item.Size = numExtents << (_extentSizeBits + 9); + + if (lv.Segments.Size() == 1) + { + const CSegment &segment = lv.Segments[0]; + if (segment.stripes.Size() == 1) + { + const CStripe &stripe = segment.stripes[0]; + FOR_VECTOR (pvIndex, _phyVols) + { + const CPhyVol &pv = _phyVols[pvIndex]; + if (pv.Name == stripe.Name) + { + item.Pos = (pv.pe_start + (stripe.ExtentOffset << _extentSizeBits)) << 9; + lv.IsSupported = true; + item.IsSupported = true; + break; + } + } + } + } + } + } + + _items.Add(item); + } + } + + { + FOR_VECTOR (i, _phyVols) + { + const CPhyVol &pv = _phyVols[i]; + + if (pv.pe_start > (UInt64)1 << (62 - 9)) + return S_FALSE; + if (pv.pe_count > (UInt64)1 << (62 - 9 - _extentSizeBits)) + return S_FALSE; + + CItem item; + + item.PhyVol = (int)i; + item.Pos = pv.pe_start << 9; + item.Size = pv.pe_count << (_extentSizeBits + 9); + item.Name = pv.Name; + item.IsSupported = true; + + _items.Add(item); + } + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream)) + _stream = stream; + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + CVolGroup::Clear(); + + _cfgPos = 0; + _cfgSize = 0; + _cTime = 0; + _phySize = 0; + _isArc = false; + _items.Clear(); + + _stream.Release(); + return S_OK; +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidFileSystem, + kpidCharacts, + kpidOffset, + kpidId +}; + +static const Byte kArcProps[] = +{ + kpidId, + kpidCTime, + kpidClusterSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: + { + /* + if (_items.Size() == 1) + prop = (UInt32)0; + */ + break; + } + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidId: + { + prop = _id; + break; + } + case kpidClusterSize: + { + if (_extentSizeBits >= 0) + prop = ((UInt64)1 << (_extentSizeBits + 9)); + break; + } + case kpidCTime: + { + if (_cTime != 0) + { + FILETIME ft; + NTime::UnixTime64_To_FileTime((Int64)_cTime, ft); + prop = ft; + } + break; + } + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + // if (_headerError) v |= kpv_ErrorFlags_HeadersError; + if (v == 0 && !_stream) + v |= kpv_ErrorFlags_UnsupportedMethod; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size() + (_cfgSize == 0 ? 0 : 1); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CItem &item = _items[index]; + + // const CLogVol &item = _items[index]; + + if (index >= _items.Size()) + { + switch (propID) + { + case kpidPath: + { + prop = "meta.txt"; + break; + } + + case kpidSize: + case kpidPackSize: prop = _cfgSize; break; + } + } + else + { + switch (propID) + { + case kpidPath: + { + AString s = item.Name; + s += ".img"; + prop = s; + break; + } + + case kpidSize: + case kpidPackSize: prop = item.Size; break; + case kpidOffset: prop = item.Pos; break; + + case kpidId: + { + // prop = item.id; + break; + } + + // case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "LVM", "lvm", NULL, 0xBF, + k_Signature, + kSectorSize, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp index fdbb9d40d..89593004d 100644 --- a/CPP/7zip/Archive/LzhHandler.cpp +++ b/CPP/7zip/Archive/LzhHandler.cpp @@ -1,719 +1,719 @@ -// LzhHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/AutoPtr.h" -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../ICoder.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/LzhDecoder.h" - -#include "IArchive.h" - -#include "Common/ItemNameUtils.h" - -using namespace NWindows; -using namespace NTime; - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - - -// CRC-16 (-IBM, -ANSI). The poly is 0x8005 (x^16 + x^15 + x^2 + 1) - -static const UInt16 kCrc16Poly = 0xA001; - -MY_ALIGN(64) -static UInt16 g_LzhCrc16Table[256]; - -#define CRC16_UPDATE_BYTE(crc, b) (g_LzhCrc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size); -UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size) -{ - const Byte *p = (const Byte *)data; - const Byte *pEnd = p + size; - for (; p != pEnd; p++) - crc = CRC16_UPDATE_BYTE(crc, *p); - return crc; -} - -static struct CLzhCrc16TableInit -{ - CLzhCrc16TableInit() - { - for (UInt32 i = 0; i < 256; i++) - { - UInt32 r = i; - for (unsigned j = 0; j < 8; j++) - r = (r >> 1) ^ (kCrc16Poly & ((UInt32)0 - (r & 1))); - g_LzhCrc16Table[i] = (UInt16)r; - } - } -} g_LzhCrc16TableInit; - - -namespace NArchive { -namespace NLzh{ - -const unsigned kMethodIdSize = 5; - -const Byte kExtIdFileName = 0x01; -const Byte kExtIdDirName = 0x02; -const Byte kExtIdUnixTime = 0x54; - -struct CExtension -{ - Byte Type; - CByteBuffer Data; - - AString GetString() const - { - AString s; - s.SetFrom_CalcLen((const char *)(const Byte *)Data, (unsigned)Data.Size()); - return s; - } -}; - -const UInt32 kBasicPartSize = 22; - -API_FUNC_static_IsArc IsArc_Lzh(const Byte *p, size_t size) -{ - if (size < 2 + kBasicPartSize) - return k_IsArc_Res_NEED_MORE; - if (p[2] != '-' || p[3] != 'l' || p[4] != 'h' || p[6] != '-') - return k_IsArc_Res_NO; - Byte n = p[5]; - if (n != 'd') - if (n < '0' || n > '7') - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -struct CItem -{ - AString Name; - Byte Method[kMethodIdSize]; - Byte Attributes; - Byte Level; - Byte OsId; - UInt32 PackSize; - UInt32 Size; - UInt32 ModifiedTime; - UInt16 CRC; - CObjectVector Extensions; - - bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); } - bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); } - bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); } - - bool IsCopyMethod() const - { - return (IsLhMethod() && Method[3] == '0') || - (IsValidMethod() && Method[2] == 'z' && Method[3] == '4'); - } - - bool IsLh1GroupMethod() const - { - if (!IsLhMethod()) - return false; - switch (Method[3]) - { - case '1': - return true; - } - return false; - } - - bool IsLh4GroupMethod() const - { - if (!IsLhMethod()) - return false; - switch (Method[3]) - { - case '4': - case '5': - case '6': - case '7': - return true; - } - return false; - } - - unsigned GetNumDictBits() const - { - if (!IsLhMethod()) - return 0; - switch (Method[3]) - { - case '1': return 12; - case '2': return 13; - case '3': return 13; - case '4': return 12; - case '5': return 13; - case '6': return 15; - case '7': return 16; - } - return 0; - } - - int FindExt(Byte type) const - { - FOR_VECTOR (i, Extensions) - if (Extensions[i].Type == type) - return (int)i; - return -1; - } - - bool GetUnixTime(UInt32 &value) const - { - value = 0; - int index = FindExt(kExtIdUnixTime); - if (index < 0 - || Extensions[index].Data.Size() < 4) - { - if (Level == 2) - { - value = ModifiedTime; - return true; - } - return false; - } - const Byte *data = (const Byte *)(Extensions[index].Data); - value = GetUi32(data); - return true; - } - - AString GetDirName() const - { - int index = FindExt(kExtIdDirName); - if (index < 0) - return AString(); - return Extensions[index].GetString(); - } - - AString GetFileName() const - { - int index = FindExt(kExtIdFileName); - if (index < 0) - return Name; - return Extensions[index].GetString(); - } - - AString GetName() const - { - AString s (GetDirName()); - const char kDirSeparator = '\\'; - // check kDirSeparator in Linux - s.Replace((char)(Byte)0xFF, kDirSeparator); - if (!s.IsEmpty() && s.Back() != kDirSeparator) - s += kDirSeparator; - s += GetFileName(); - return s; - } -}; - -static const Byte *ReadUInt16(const Byte *p, UInt16 &v) -{ - v = Get16(p); - return p + 2; -} - -static const Byte *ReadString(const Byte *p, size_t size, AString &s) -{ - s.Empty(); - for (size_t i = 0; i < size; i++) - { - const Byte c = p[i]; - if (c == 0) - break; - s += (char)c; - } - return p + size; -} - -static Byte CalcSum(const Byte *data, size_t size) -{ - Byte sum = 0; - for (size_t i = 0; i < size; i++) - sum = (Byte)(sum + data[i]); - return sum; -} - -static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &item) -{ - filled = false; - - size_t processedSize = 2; - Byte startHeader[2]; - RINOK(ReadStream(stream, startHeader, &processedSize)) - if (processedSize == 0) - return S_OK; - if (processedSize == 1) - return (startHeader[0] == 0) ? S_OK: S_FALSE; - if (startHeader[0] == 0 && startHeader[1] == 0) - return S_OK; - - Byte header[256]; - processedSize = kBasicPartSize; - RINOK(ReadStream(stream, header, &processedSize)) - if (processedSize != kBasicPartSize) - return (startHeader[0] == 0) ? S_OK: S_FALSE; - - const Byte *p = header; - memcpy(item.Method, p, kMethodIdSize); - if (!item.IsValidMethod()) - return S_OK; - p += kMethodIdSize; - item.PackSize = Get32(p); - item.Size = Get32(p + 4); - item.ModifiedTime = Get32(p + 8); - item.Attributes = p[12]; - item.Level = p[13]; - p += 14; - if (item.Level > 2) - return S_FALSE; - UInt32 headerSize; - if (item.Level < 2) - { - headerSize = startHeader[0]; - if (headerSize < kBasicPartSize) - return S_FALSE; - RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, headerSize - kBasicPartSize)) - if (startHeader[1] != CalcSum(header, headerSize)) - return S_FALSE; - const size_t nameLength = *p++; - if ((size_t)(p - header) + nameLength + 2 > headerSize) - return S_FALSE; - p = ReadString(p, nameLength, item.Name); - } - else - headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); - p = ReadUInt16(p, item.CRC); - if (item.Level != 0) - { - if (item.Level == 2) - { - RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, 2)) - } - if ((size_t)(p - header) + 3 > headerSize) - return S_FALSE; - item.OsId = *p++; - UInt16 nextSize; - p = ReadUInt16(p, nextSize); - while (nextSize != 0) - { - if (nextSize < 3) - return S_FALSE; - if (item.Level == 1) - { - if (item.PackSize < nextSize) - return S_FALSE; - item.PackSize -= nextSize; - } - if (item.Extensions.Size() >= (1 << 8)) - return S_FALSE; - CExtension ext; - RINOK(ReadStream_FALSE(stream, &ext.Type, 1)) - nextSize = (UInt16)(nextSize - 3); - ext.Data.Alloc(nextSize); - RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize)) - item.Extensions.Add(ext); - Byte hdr2[2]; - RINOK(ReadStream_FALSE(stream, hdr2, 2)) - ReadUInt16(hdr2, nextSize); - } - } - filled = true; - return S_OK; -} - - -static const CUInt32PCharPair g_OsPairs[] = -{ - { 0, "MS-DOS" }, - { 'M', "MS-DOS" }, - { '2', "OS/2" }, - { '9', "OS9" }, - { 'K', "OS/68K" }, - { '3', "OS/386" }, - { 'H', "HUMAN" }, - { 'U', "UNIX" }, - { 'C', "CP/M" }, - { 'F', "FLEX" }, - { 'm', "Mac" }, - { 'R', "Runser" }, - { 'T', "TownsOS" }, - { 'X', "XOSK" }, - { 'w', "Windows 95" }, - { 'W', "Windows NT" }, - { 'J', "Java VM" } -}; - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - // kpidAttrib, - kpidCRC, - kpidMethod, - kpidHostOS -}; - - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithCRC - , ISequentialOutStream -) - UInt32 _crc; - CMyComPtr _stream; -public: - void Init(ISequentialOutStream *stream) - { - _stream = stream; - _crc = 0; - } - void ReleaseStream() { _stream.Release(); } - UInt32 GetCRC() const { return _crc; } -}; - -Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT res = S_OK; - if (_stream) - res = _stream->Write(data, size, &size); - _crc = LzhCrc16Update(_crc, data, size); - if (processedSize) - *processedSize = size; - return res; -} - - -struct CItemEx: public CItem -{ - UInt64 DataPosition; -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - CObjectVector _items; - CMyComPtr _stream; - UInt64 _phySize; - UInt32 _errorFlags; - bool _isArc; -public: - CHandler(); -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -CHandler::CHandler() {} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _phySize; break; - - case kpidErrorFlags: - UInt32 v = _errorFlags; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - prop = v; - break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CItemEx &item = _items[index]; - switch (propID) - { - case kpidPath: - { - UString s = NItemName::WinPathToOsPath(MultiByteToUnicodeString(item.GetName(), CP_OEMCP)); - if (!s.IsEmpty()) - { - if (s.Back() == WCHAR_PATH_SEPARATOR) - s.DeleteBack(); - prop = s; - } - break; - } - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: prop = (UInt64)item.Size; break; - case kpidPackSize: prop = (UInt64)item.PackSize; break; - case kpidCRC: prop = (UInt32)item.CRC; break; - case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break; - case kpidMTime: - { - UInt32 unixTime; - if (item.GetUnixTime(unixTime)) - PropVariant_SetFrom_UnixTime(prop, unixTime); - else - PropVariant_SetFrom_DosTime(prop, item.ModifiedTime); - break; - } - // case kpidAttrib: prop = (UInt32)item.Attributes; break; - case kpidMethod: - { - char method2[kMethodIdSize + 1]; - method2[kMethodIdSize] = 0; - memcpy(method2, item.Method, kMethodIdSize); - prop = method2; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - try - { - _items.Clear(); - - UInt64 endPos; - bool needSetTotal = true; - - RINOK(InStream_AtBegin_GetSize(stream, endPos)) - - for (;;) - { - CItemEx item; - bool filled; - const HRESULT res = GetNextItem(stream, filled, item); - RINOK(InStream_GetPos(stream, item.DataPosition)) - if (res == S_FALSE) - { - _errorFlags = kpv_ErrorFlags_HeadersError; - break; - } - - if (res != S_OK) - return S_FALSE; - _phySize = item.DataPosition; - if (!filled) - break; - _items.Add(item); - - _isArc = true; - - UInt64 newPostion; - RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion)) - if (newPostion > endPos) - { - _phySize = endPos; - _errorFlags = kpv_ErrorFlags_UnexpectedEnd; - break; - } - _phySize = newPostion; - if (callback) - { - if (needSetTotal) - { - RINOK(callback->SetTotal(NULL, &endPos)) - needSetTotal = false; - } - if (_items.Size() % 100 == 0) - { - const UInt64 numFiles = _items.Size(); - const UInt64 numBytes = item.DataPosition; - RINOK(callback->SetCompleted(&numFiles, &numBytes)) - } - } - } - if (_items.IsEmpty()) - return S_FALSE; - - _stream = stream; - } - catch(...) - { - return S_FALSE; - } - COM_TRY_END - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _phySize = 0; - _errorFlags = 0; - _items.Clear(); - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalUnPacked = 0 /* , totalPacked = 0 */; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItemEx &item = _items[allFilesMode ? i : indices[i]]; - totalUnPacked += item.Size; - // totalPacked += item.PackSize; - } - RINOK(extractCallback->SetTotal(totalUnPacked)) - - UInt32 cur_Unpacked, cur_Packed; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyUniquePtr lzhDecoder; - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - - for (i = 0;; i++, - lps->OutSize += cur_Unpacked, - lps->InSize += cur_Packed) - { - cur_Unpacked = 0; - cur_Packed = 0; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItemEx &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (item.IsDir()) - { - // if (!testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - continue; - } - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - cur_Unpacked = item.Size; - cur_Packed = item.PackSize; - - CMyComPtr2_Create outStream; - outStream->Init(realOutStream); - realOutStream.Release(); - - RINOK(InStream_SeekSet(_stream, item.DataPosition)) - - inStream->Init(item.PackSize); - - HRESULT res = S_OK; - opRes = NExtract::NOperationResult::kOK; - - if (item.IsCopyMethod()) - { - res = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); - if (res == S_OK && copyCoder->TotalSize != item.PackSize) - res = S_FALSE; - } - else if (item.IsLh4GroupMethod()) - { - lzhDecoder.Create_if_Empty(); - // lzhDecoder->FinishMode = true; - lzhDecoder->SetDictSize((UInt32)1 << item.GetNumDictBits()); - res = lzhDecoder->Code(inStream, outStream, cur_Unpacked, lps); - if (res == S_OK && lzhDecoder->GetInputProcessedSize() != item.PackSize) - res = S_FALSE; - } - /* - else if (item.IsLh1GroupMethod()) - { - if (!lzh1Decoder) - { - lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder; - lzh1Decoder = lzh1DecoderSpec; - } - lzh1DecoderSpec->SetDictionary(item.GetNumDictBits()); - res = lzh1Decoder->Code(inStream, outStream, NULL, &cur_Unpacked, progress); - } - */ - else - opRes = NExtract::NOperationResult::kUnsupportedMethod; - - if (opRes == NExtract::NOperationResult::kOK) - { - if (res == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else - { - RINOK(res) - if (outStream->GetCRC() != item.CRC) - opRes = NExtract::NOperationResult::kCRCError; - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -static const Byte k_Signature[] = { '-', 'l', 'h' }; - -REGISTER_ARC_I( - "Lzh", "lzh lha", NULL, 6, - k_Signature, - 2, - 0, - IsArc_Lzh) - -}} +// LzhHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/AutoPtr.h" +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../ICoder.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/LzhDecoder.h" + +#include "IArchive.h" + +#include "Common/ItemNameUtils.h" + +using namespace NWindows; +using namespace NTime; + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + + +// CRC-16 (-IBM, -ANSI). The poly is 0x8005 (x^16 + x^15 + x^2 + 1) + +static const UInt16 kCrc16Poly = 0xA001; + +MY_ALIGN(64) +static UInt16 g_LzhCrc16Table[256]; + +#define CRC16_UPDATE_BYTE(crc, b) (g_LzhCrc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size); +UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + crc = CRC16_UPDATE_BYTE(crc, *p); + return crc; +} + +static struct CLzhCrc16TableInit +{ + CLzhCrc16TableInit() + { + for (UInt32 i = 0; i < 256; i++) + { + UInt32 r = i; + for (unsigned j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrc16Poly & ((UInt32)0 - (r & 1))); + g_LzhCrc16Table[i] = (UInt16)r; + } + } +} g_LzhCrc16TableInit; + + +namespace NArchive { +namespace NLzh{ + +const unsigned kMethodIdSize = 5; + +const Byte kExtIdFileName = 0x01; +const Byte kExtIdDirName = 0x02; +const Byte kExtIdUnixTime = 0x54; + +struct CExtension +{ + Byte Type; + CByteBuffer Data; + + AString GetString() const + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)Data, (unsigned)Data.Size()); + return s; + } +}; + +const UInt32 kBasicPartSize = 22; + +API_FUNC_static_IsArc IsArc_Lzh(const Byte *p, size_t size) +{ + if (size < 2 + kBasicPartSize) + return k_IsArc_Res_NEED_MORE; + if (p[2] != '-' || p[3] != 'l' || p[4] != 'h' || p[6] != '-') + return k_IsArc_Res_NO; + Byte n = p[5]; + if (n != 'd') + if (n < '0' || n > '7') + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +struct CItem +{ + AString Name; + Byte Method[kMethodIdSize]; + Byte Attributes; + Byte Level; + Byte OsId; + UInt32 PackSize; + UInt32 Size; + UInt32 ModifiedTime; + UInt16 CRC; + CObjectVector Extensions; + + bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); } + bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); } + bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); } + + bool IsCopyMethod() const + { + return (IsLhMethod() && Method[3] == '0') || + (IsValidMethod() && Method[2] == 'z' && Method[3] == '4'); + } + + bool IsLh1GroupMethod() const + { + if (!IsLhMethod()) + return false; + switch (Method[3]) + { + case '1': + return true; + } + return false; + } + + bool IsLh4GroupMethod() const + { + if (!IsLhMethod()) + return false; + switch (Method[3]) + { + case '4': + case '5': + case '6': + case '7': + return true; + } + return false; + } + + unsigned GetNumDictBits() const + { + if (!IsLhMethod()) + return 0; + switch (Method[3]) + { + case '1': return 12; + case '2': return 13; + case '3': return 13; + case '4': return 12; + case '5': return 13; + case '6': return 15; + case '7': return 16; + } + return 0; + } + + int FindExt(Byte type) const + { + FOR_VECTOR (i, Extensions) + if (Extensions[i].Type == type) + return (int)i; + return -1; + } + + bool GetUnixTime(UInt32 &value) const + { + value = 0; + int index = FindExt(kExtIdUnixTime); + if (index < 0 + || Extensions[index].Data.Size() < 4) + { + if (Level == 2) + { + value = ModifiedTime; + return true; + } + return false; + } + const Byte *data = (const Byte *)(Extensions[index].Data); + value = GetUi32(data); + return true; + } + + AString GetDirName() const + { + int index = FindExt(kExtIdDirName); + if (index < 0) + return AString(); + return Extensions[index].GetString(); + } + + AString GetFileName() const + { + int index = FindExt(kExtIdFileName); + if (index < 0) + return Name; + return Extensions[index].GetString(); + } + + AString GetName() const + { + AString s (GetDirName()); + const char kDirSeparator = '\\'; + // check kDirSeparator in Linux + s.Replace((char)(Byte)0xFF, kDirSeparator); + if (!s.IsEmpty() && s.Back() != kDirSeparator) + s += kDirSeparator; + s += GetFileName(); + return s; + } +}; + +static const Byte *ReadUInt16(const Byte *p, UInt16 &v) +{ + v = Get16(p); + return p + 2; +} + +static const Byte *ReadString(const Byte *p, size_t size, AString &s) +{ + s.Empty(); + for (size_t i = 0; i < size; i++) + { + const Byte c = p[i]; + if (c == 0) + break; + s += (char)c; + } + return p + size; +} + +static Byte CalcSum(const Byte *data, size_t size) +{ + Byte sum = 0; + for (size_t i = 0; i < size; i++) + sum = (Byte)(sum + data[i]); + return sum; +} + +static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &item) +{ + filled = false; + + size_t processedSize = 2; + Byte startHeader[2]; + RINOK(ReadStream(stream, startHeader, &processedSize)) + if (processedSize == 0) + return S_OK; + if (processedSize == 1) + return (startHeader[0] == 0) ? S_OK: S_FALSE; + if (startHeader[0] == 0 && startHeader[1] == 0) + return S_OK; + + Byte header[256]; + processedSize = kBasicPartSize; + RINOK(ReadStream(stream, header, &processedSize)) + if (processedSize != kBasicPartSize) + return (startHeader[0] == 0) ? S_OK: S_FALSE; + + const Byte *p = header; + memcpy(item.Method, p, kMethodIdSize); + if (!item.IsValidMethod()) + return S_OK; + p += kMethodIdSize; + item.PackSize = Get32(p); + item.Size = Get32(p + 4); + item.ModifiedTime = Get32(p + 8); + item.Attributes = p[12]; + item.Level = p[13]; + p += 14; + if (item.Level > 2) + return S_FALSE; + UInt32 headerSize; + if (item.Level < 2) + { + headerSize = startHeader[0]; + if (headerSize < kBasicPartSize) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, headerSize - kBasicPartSize)) + if (startHeader[1] != CalcSum(header, headerSize)) + return S_FALSE; + const size_t nameLength = *p++; + if ((size_t)(p - header) + nameLength + 2 > headerSize) + return S_FALSE; + p = ReadString(p, nameLength, item.Name); + } + else + headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8); + p = ReadUInt16(p, item.CRC); + if (item.Level != 0) + { + if (item.Level == 2) + { + RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, 2)) + } + if ((size_t)(p - header) + 3 > headerSize) + return S_FALSE; + item.OsId = *p++; + UInt16 nextSize; + p = ReadUInt16(p, nextSize); + while (nextSize != 0) + { + if (nextSize < 3) + return S_FALSE; + if (item.Level == 1) + { + if (item.PackSize < nextSize) + return S_FALSE; + item.PackSize -= nextSize; + } + if (item.Extensions.Size() >= (1 << 8)) + return S_FALSE; + CExtension ext; + RINOK(ReadStream_FALSE(stream, &ext.Type, 1)) + nextSize = (UInt16)(nextSize - 3); + ext.Data.Alloc(nextSize); + RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize)) + item.Extensions.Add(ext); + Byte hdr2[2]; + RINOK(ReadStream_FALSE(stream, hdr2, 2)) + ReadUInt16(hdr2, nextSize); + } + } + filled = true; + return S_OK; +} + + +static const CUInt32PCharPair g_OsPairs[] = +{ + { 0, "MS-DOS" }, + { 'M', "MS-DOS" }, + { '2', "OS/2" }, + { '9', "OS9" }, + { 'K', "OS/68K" }, + { '3', "OS/386" }, + { 'H', "HUMAN" }, + { 'U', "UNIX" }, + { 'C', "CP/M" }, + { 'F', "FLEX" }, + { 'm', "Mac" }, + { 'R', "Runser" }, + { 'T', "TownsOS" }, + { 'X', "XOSK" }, + { 'w', "Windows 95" }, + { 'W', "Windows NT" }, + { 'J', "Java VM" } +}; + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + // kpidAttrib, + kpidCRC, + kpidMethod, + kpidHostOS +}; + + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithCRC + , ISequentialOutStream +) + UInt32 _crc; + CMyComPtr _stream; +public: + void Init(ISequentialOutStream *stream) + { + _stream = stream; + _crc = 0; + } + void ReleaseStream() { _stream.Release(); } + UInt32 GetCRC() const { return _crc; } +}; + +Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT res = S_OK; + if (_stream) + res = _stream->Write(data, size, &size); + _crc = LzhCrc16Update(_crc, data, size); + if (processedSize) + *processedSize = size; + return res; +} + + +struct CItemEx: public CItem +{ + UInt64 DataPosition; +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + CObjectVector _items; + CMyComPtr _stream; + UInt64 _phySize; + UInt32 _errorFlags; + bool _isArc; +public: + CHandler(); +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +CHandler::CHandler() {} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + + case kpidErrorFlags: + UInt32 v = _errorFlags; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CItemEx &item = _items[index]; + switch (propID) + { + case kpidPath: + { + UString s = NItemName::WinPathToOsPath(MultiByteToUnicodeString(item.GetName(), CP_OEMCP)); + if (!s.IsEmpty()) + { + if (s.Back() == WCHAR_PATH_SEPARATOR) + s.DeleteBack(); + prop = s; + } + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: prop = (UInt64)item.Size; break; + case kpidPackSize: prop = (UInt64)item.PackSize; break; + case kpidCRC: prop = (UInt32)item.CRC; break; + case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break; + case kpidMTime: + { + UInt32 unixTime; + if (item.GetUnixTime(unixTime)) + PropVariant_SetFrom_UnixTime(prop, unixTime); + else + PropVariant_SetFrom_DosTime(prop, item.ModifiedTime); + break; + } + // case kpidAttrib: prop = (UInt32)item.Attributes; break; + case kpidMethod: + { + char method2[kMethodIdSize + 1]; + method2[kMethodIdSize] = 0; + memcpy(method2, item.Method, kMethodIdSize); + prop = method2; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + try + { + _items.Clear(); + + UInt64 endPos; + bool needSetTotal = true; + + RINOK(InStream_AtBegin_GetSize(stream, endPos)) + + for (;;) + { + CItemEx item; + bool filled; + const HRESULT res = GetNextItem(stream, filled, item); + RINOK(InStream_GetPos(stream, item.DataPosition)) + if (res == S_FALSE) + { + _errorFlags = kpv_ErrorFlags_HeadersError; + break; + } + + if (res != S_OK) + return S_FALSE; + _phySize = item.DataPosition; + if (!filled) + break; + _items.Add(item); + + _isArc = true; + + UInt64 newPostion; + RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion)) + if (newPostion > endPos) + { + _phySize = endPos; + _errorFlags = kpv_ErrorFlags_UnexpectedEnd; + break; + } + _phySize = newPostion; + if (callback) + { + if (needSetTotal) + { + RINOK(callback->SetTotal(NULL, &endPos)) + needSetTotal = false; + } + if (_items.Size() % 100 == 0) + { + const UInt64 numFiles = _items.Size(); + const UInt64 numBytes = item.DataPosition; + RINOK(callback->SetCompleted(&numFiles, &numBytes)) + } + } + } + if (_items.IsEmpty()) + return S_FALSE; + + _stream = stream; + } + catch(...) + { + return S_FALSE; + } + COM_TRY_END + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _phySize = 0; + _errorFlags = 0; + _items.Clear(); + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalUnPacked = 0 /* , totalPacked = 0 */; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItemEx &item = _items[allFilesMode ? i : indices[i]]; + totalUnPacked += item.Size; + // totalPacked += item.PackSize; + } + RINOK(extractCallback->SetTotal(totalUnPacked)) + + UInt32 cur_Unpacked, cur_Packed; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyUniquePtr lzhDecoder; + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + + for (i = 0;; i++, + lps->OutSize += cur_Unpacked, + lps->InSize += cur_Packed) + { + cur_Unpacked = 0; + cur_Packed = 0; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItemEx &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (item.IsDir()) + { + // if (!testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + continue; + } + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + cur_Unpacked = item.Size; + cur_Packed = item.PackSize; + + CMyComPtr2_Create outStream; + outStream->Init(realOutStream); + realOutStream.Release(); + + RINOK(InStream_SeekSet(_stream, item.DataPosition)) + + inStream->Init(item.PackSize); + + HRESULT res = S_OK; + opRes = NExtract::NOperationResult::kOK; + + if (item.IsCopyMethod()) + { + res = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); + if (res == S_OK && copyCoder->TotalSize != item.PackSize) + res = S_FALSE; + } + else if (item.IsLh4GroupMethod()) + { + lzhDecoder.Create_if_Empty(); + // lzhDecoder->FinishMode = true; + lzhDecoder->SetDictSize((UInt32)1 << item.GetNumDictBits()); + res = lzhDecoder->Code(inStream, outStream, cur_Unpacked, lps); + if (res == S_OK && lzhDecoder->GetInputProcessedSize() != item.PackSize) + res = S_FALSE; + } + /* + else if (item.IsLh1GroupMethod()) + { + if (!lzh1Decoder) + { + lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder; + lzh1Decoder = lzh1DecoderSpec; + } + lzh1DecoderSpec->SetDictionary(item.GetNumDictBits()); + res = lzh1Decoder->Code(inStream, outStream, NULL, &cur_Unpacked, progress); + } + */ + else + opRes = NExtract::NOperationResult::kUnsupportedMethod; + + if (opRes == NExtract::NOperationResult::kOK) + { + if (res == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else + { + RINOK(res) + if (outStream->GetCRC() != item.CRC) + opRes = NExtract::NOperationResult::kCRCError; + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +static const Byte k_Signature[] = { '-', 'l', 'h' }; + +REGISTER_ARC_I( + "Lzh", "lzh lha", NULL, 6, + k_Signature, + 2, + 0, + IsArc_Lzh) + +}} diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index 0a85bbb04..7cbabf492 100644 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -1,608 +1,608 @@ -// LzmaHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/FilterCoder.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/BcjCoder.h" -#include "../Compress/LzmaDecoder.h" - -#include "Common/DummyOutStream.h" - -using namespace NWindows; - -namespace NArchive { -namespace NLzma { - -static bool CheckDicSize(const Byte *p) -{ - UInt32 dicSize = GetUi32(p); - if (dicSize == 1) - return true; - for (unsigned i = 0; i <= 30; i++) - if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i)) - return true; - return (dicSize == 0xFFFFFFFF); -} - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, - kpidMethod -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidMethod -}; - -struct CHeader -{ - UInt64 Size; - Byte FilterID; - Byte LzmaProps[5]; - - Byte GetProp() const { return LzmaProps[0]; } - UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); } - bool HasSize() const { return (Size != (UInt64)(Int64)-1); } - bool Parse(const Byte *buf, bool isThereFilter); -}; - -bool CHeader::Parse(const Byte *buf, bool isThereFilter) -{ - FilterID = 0; - if (isThereFilter) - FilterID = buf[0]; - const Byte *sig = buf + (isThereFilter ? 1 : 0); - for (int i = 0; i < 5; i++) - LzmaProps[i] = sig[i]; - Size = GetUi64(sig + 5); - return - LzmaProps[0] < 5 * 5 * 9 && - FilterID < 2 && - (!HasSize() || Size < ((UInt64)1 << 56)) - && CheckDicSize(LzmaProps + 1); -} - -class CDecoder Z7_final -{ - CMyComPtr _bcjStream; - CFilterCoder *_filterCoder; -public: - CMyComPtr2 _lzmaDecoder; - - ~CDecoder(); - HRESULT Create(bool filtered, ISequentialInStream *inStream); - - HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress); - - UInt64 GetInputProcessedSize() const { return _lzmaDecoder->GetInputProcessedSize(); } - - void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoder->ReleaseInStream(); } - - HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize) - { return _lzmaDecoder->ReadFromInputStream(data, size, processedSize); } -}; - -HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream) -{ - _lzmaDecoder.Create_if_Empty(); - _lzmaDecoder->FinishStream = true; - - if (filteredMode) - { - if (!_bcjStream) - { - _filterCoder = new CFilterCoder(false); - CMyComPtr coder = _filterCoder; - _filterCoder->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec); - _bcjStream = _filterCoder; - } - } - - return _lzmaDecoder->SetInStream(inStream); -} - -CDecoder::~CDecoder() -{ - ReleaseInStream(); -} - -HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, - ICompressProgressInfo *progress) -{ - if (header.FilterID > 1) - return E_NOTIMPL; - - RINOK(_lzmaDecoder->SetDecoderProperties2(header.LzmaProps, 5)) - - bool filteredMode = (header.FilterID == 1); - - if (filteredMode) - { - RINOK(_filterCoder->SetOutStream(outStream)) - outStream = _bcjStream; - RINOK(_filterCoder->SetOutStreamSize(NULL)) - } - - const UInt64 *Size = header.HasSize() ? &header.Size : NULL; - HRESULT res = _lzmaDecoder->CodeResume(outStream, Size, progress); - - if (filteredMode) - { - { - HRESULT res2 = _filterCoder->OutStreamFinish(); - if (res == S_OK) - res = res2; - } - HRESULT res2 = _filterCoder->ReleaseOutStream(); - if (res == S_OK) - res = res2; - } - - RINOK(res) - - if (header.HasSize()) - if (_lzmaDecoder->GetOutputProcessedSize() != header.Size) - return S_FALSE; - - return S_OK; -} - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IArchiveOpenSeq -) - bool _lzma86; - bool _isArc; - bool _needSeekToStart; - bool _dataAfterEnd; - bool _needMoreInput; - bool _unsupported; - bool _dataError; - - bool _packSize_Defined; - bool _unpackSize_Defined; - bool _numStreams_Defined; - - CHeader _header; - CMyComPtr _stream; - CMyComPtr _seqStream; - - UInt64 _packSize; - UInt64 _unpackSize; - UInt64 _numStreams; - - void GetMethod(NCOM::CPropVariant &prop); - - unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); } -public: - CHandler(bool lzma86) { _lzma86 = lzma86; } -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; - case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; - case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; - case kpidMethod: GetMethod(prop); break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; - if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; - if (_dataError) v |= kpv_ErrorFlags_DataError; - prop = v; - break; - } - default: break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - - -static char * DictSizeToString(UInt32 val, char *s) -{ - for (unsigned i = 0; i < 32; i++) - if (((UInt32)1 << i) == val) - return ::ConvertUInt32ToString(i, s); - char c = 'b'; - if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } - else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } - s = ::ConvertUInt32ToString(val, s); - *s++ = c; - *s = 0; - return s; -} - -static char *AddProp32(char *s, const char *name, UInt32 v) -{ - *s++ = ':'; - s = MyStpCpy(s, name); - return ::ConvertUInt32ToString(v, s); -} - -void CHandler::GetMethod(NCOM::CPropVariant &prop) -{ - if (!_stream) - return; - - char sz[64]; - char *s = sz; - if (_header.FilterID != 0) - s = MyStpCpy(s, "BCJ "); - s = MyStpCpy(s, "LZMA:"); - s = DictSizeToString(_header.GetDicSize(), s); - - UInt32 d = _header.GetProp(); - // if (d != 0x5D) - { - UInt32 lc = d % 9; - d /= 9; - UInt32 pb = d / 5; - UInt32 lp = d % 5; - if (lc != 3) s = AddProp32(s, "lc", lc); - if (lp != 0) s = AddProp32(s, "lp", lp); - if (pb != 2) s = AddProp32(s, "pb", pb); - } - prop = sz; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; - case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; - case kpidMethod: GetMethod(prop); break; - default: break; - } - prop.Detach(value); - return S_OK; -} - -API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size) -{ - const UInt32 kHeaderSize = 1 + 4 + 8; - if (size < kHeaderSize) - return k_IsArc_Res_NEED_MORE; - if (p[0] >= 5 * 5 * 9) - return k_IsArc_Res_NO; - const UInt64 unpackSize = GetUi64(p + 1 + 4); - if (unpackSize != (UInt64)(Int64)-1) - { - if (unpackSize >= ((UInt64)1 << 56)) - return k_IsArc_Res_NO; - } - if (unpackSize != 0) - { - if (size < kHeaderSize + 2) - return k_IsArc_Res_NEED_MORE; - if (p[kHeaderSize] != 0) - return k_IsArc_Res_NO; - if (unpackSize != (UInt64)(Int64)-1) - { - if ((p[kHeaderSize + 1] & 0x80) != 0) - return k_IsArc_Res_NO; - } - } - if (!CheckDicSize(p + 1)) - // return k_IsArc_Res_YES_LOW_PROB; - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size) -{ - if (size < 1) - return k_IsArc_Res_NEED_MORE; - Byte filterID = p[0]; - if (filterID != 0 && filterID != 1) - return k_IsArc_Res_NO; - return IsArc_Lzma(p + 1, size - 1); -} -} - - - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)) -{ - Close(); - - const unsigned headerSize = GetHeaderSize(); - const UInt32 kBufSize = 1 << 7; - Byte buf[kBufSize]; - size_t processedSize = kBufSize; - RINOK(ReadStream(inStream, buf, &processedSize)) - if (processedSize < headerSize + 2) - return S_FALSE; - if (!_header.Parse(buf, _lzma86)) - return S_FALSE; - const Byte *start = buf + headerSize; - if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80 - return S_FALSE; - - RINOK(InStream_GetSize_SeekToEnd(inStream, _packSize)) - - SizeT srcLen = (SizeT)processedSize - headerSize; - - if (srcLen > 10 - && _header.Size == 0 - // && _header.FilterID == 0 - && _header.LzmaProps[0] == 0 - ) - return S_FALSE; - - const UInt32 outLimit = 1 << 11; - Byte outBuf[outLimit]; - - SizeT outSize = outLimit; - if (outSize > _header.Size) - outSize = (SizeT)_header.Size; - SizeT destLen = outSize; - ELzmaStatus status; - - SRes res = LzmaDecode(outBuf, &destLen, start, &srcLen, - _header.LzmaProps, 5, LZMA_FINISH_ANY, - &status, &g_Alloc); - - if (res != SZ_OK) - if (res != SZ_ERROR_INPUT_EOF) - return S_FALSE; - - _isArc = true; - _stream = inStream; - _seqStream = inStream; - _needSeekToStart = true; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _needSeekToStart = false; - _dataAfterEnd = false; - _needMoreInput = false; - _unsupported = false; - _dataError = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - _numStreams_Defined = false; - - _packSize = 0; - - _stream.Release(); - _seqStream.Release(); - return S_OK; -} - -Z7_CLASS_IMP_COM_1( - CCompressProgressInfoImp, - ICompressProgressInfo -) - CMyComPtr Callback; -public: - UInt64 Offset; - - void Init(IArchiveOpenCallback *callback) { Callback = callback; } -}; - -Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) -{ - if (Callback) - { - const UInt64 files = 0; - const UInt64 val = Offset + *inSize; - return Callback->SetCompleted(&files, &val); - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - if (_packSize_Defined) - RINOK(extractCallback->SetTotal(_packSize)) - - Int32 opResult; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(); - realOutStream.Release(); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(InStream_SeekToBegin(_stream)) - } - else - _needSeekToStart = true; - - CDecoder decoder; - RINOK(decoder.Create(_lzma86, _seqStream)) - - bool firstItem = true; - - UInt64 packSize = 0; - UInt64 unpackSize = 0; - UInt64 numStreams = 0; - - bool dataAfterEnd = false; - - HRESULT hres = S_OK; - - for (;;) - { - lps->InSize = packSize; - lps->OutSize = unpackSize; - RINOK(lps->SetCur()) - - const UInt32 kBufSize = 1 + 5 + 8; - Byte buf[kBufSize]; - const UInt32 headerSize = GetHeaderSize(); - UInt32 processed; - RINOK(decoder.ReadInput(buf, headerSize, &processed)) - if (processed != headerSize) - { - if (processed != 0) - dataAfterEnd = true; - break; - } - - CHeader st; - if (!st.Parse(buf, _lzma86)) - { - dataAfterEnd = true; - break; - } - numStreams++; - firstItem = false; - - hres = decoder.Code(st, outStream, lps); - - packSize = decoder.GetInputProcessedSize(); - unpackSize = outStream->GetSize(); - - if (hres == E_NOTIMPL) - { - _unsupported = true; - hres = S_FALSE; - break; - } - if (hres == S_FALSE) - break; - RINOK(hres) - } - - if (firstItem) - { - _isArc = false; - hres = S_FALSE; - } - else if (hres == S_OK || hres == S_FALSE) - { - if (dataAfterEnd) - _dataAfterEnd = true; - else if (decoder._lzmaDecoder->NeedsMoreInput()) - _needMoreInput = true; - - _packSize = packSize; - _unpackSize = unpackSize; - _numStreams = numStreams; - - _packSize_Defined = true; - _unpackSize_Defined = true; - _numStreams_Defined = true; - } - - opResult = NExtract::NOperationResult::kOK; - - if (!_isArc) - opResult = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opResult = NExtract::NOperationResult::kUnexpectedEnd; - else if (_unsupported) - opResult = NExtract::NOperationResult::kUnsupportedMethod; - else if (_dataAfterEnd) - opResult = NExtract::NOperationResult::kDataAfterEnd; - else if (hres == S_FALSE) - opResult = NExtract::NOperationResult::kDataError; - else if (hres == S_OK) - opResult = NExtract::NOperationResult::kOK; - else - return hres; - - // outStream.Release(); - } - return extractCallback->SetOperationResult(opResult); - - COM_TRY_END -} - -namespace NLzmaAr { - -// 2, { 0x5D, 0x00 }, - -REGISTER_ARC_I_CLS_NO_SIG( - CHandler(false), - "lzma", "lzma", NULL, 0xA, - 0, - NArcInfoFlags::kStartOpen | - NArcInfoFlags::kKeepName, - IsArc_Lzma) - -} - -namespace NLzma86Ar { - -REGISTER_ARC_I_CLS_NO_SIG( - CHandler(true), - "lzma86", "lzma86", NULL, 0xB, - 0, - NArcInfoFlags::kKeepName, - IsArc_Lzma86) - -} - -}} +// LzmaHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/FilterCoder.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/BcjCoder.h" +#include "../Compress/LzmaDecoder.h" + +#include "Common/DummyOutStream.h" + +using namespace NWindows; + +namespace NArchive { +namespace NLzma { + +static bool CheckDicSize(const Byte *p) +{ + UInt32 dicSize = GetUi32(p); + if (dicSize == 1) + return true; + for (unsigned i = 0; i <= 30; i++) + if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i)) + return true; + return (dicSize == 0xFFFFFFFF); +} + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, + kpidMethod +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidMethod +}; + +struct CHeader +{ + UInt64 Size; + Byte FilterID; + Byte LzmaProps[5]; + + Byte GetProp() const { return LzmaProps[0]; } + UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); } + bool HasSize() const { return (Size != (UInt64)(Int64)-1); } + bool Parse(const Byte *buf, bool isThereFilter); +}; + +bool CHeader::Parse(const Byte *buf, bool isThereFilter) +{ + FilterID = 0; + if (isThereFilter) + FilterID = buf[0]; + const Byte *sig = buf + (isThereFilter ? 1 : 0); + for (int i = 0; i < 5; i++) + LzmaProps[i] = sig[i]; + Size = GetUi64(sig + 5); + return + LzmaProps[0] < 5 * 5 * 9 && + FilterID < 2 && + (!HasSize() || Size < ((UInt64)1 << 56)) + && CheckDicSize(LzmaProps + 1); +} + +class CDecoder Z7_final +{ + CMyComPtr _bcjStream; + CFilterCoder *_filterCoder; +public: + CMyComPtr2 _lzmaDecoder; + + ~CDecoder(); + HRESULT Create(bool filtered, ISequentialInStream *inStream); + + HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress); + + UInt64 GetInputProcessedSize() const { return _lzmaDecoder->GetInputProcessedSize(); } + + void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoder->ReleaseInStream(); } + + HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize) + { return _lzmaDecoder->ReadFromInputStream(data, size, processedSize); } +}; + +HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream) +{ + _lzmaDecoder.Create_if_Empty(); + _lzmaDecoder->FinishStream = true; + + if (filteredMode) + { + if (!_bcjStream) + { + _filterCoder = new CFilterCoder(false); + CMyComPtr coder = _filterCoder; + _filterCoder->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec); + _bcjStream = _filterCoder; + } + } + + return _lzmaDecoder->SetInStream(inStream); +} + +CDecoder::~CDecoder() +{ + ReleaseInStream(); +} + +HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, + ICompressProgressInfo *progress) +{ + if (header.FilterID > 1) + return E_NOTIMPL; + + RINOK(_lzmaDecoder->SetDecoderProperties2(header.LzmaProps, 5)) + + bool filteredMode = (header.FilterID == 1); + + if (filteredMode) + { + RINOK(_filterCoder->SetOutStream(outStream)) + outStream = _bcjStream; + RINOK(_filterCoder->SetOutStreamSize(NULL)) + } + + const UInt64 *Size = header.HasSize() ? &header.Size : NULL; + HRESULT res = _lzmaDecoder->CodeResume(outStream, Size, progress); + + if (filteredMode) + { + { + HRESULT res2 = _filterCoder->OutStreamFinish(); + if (res == S_OK) + res = res2; + } + HRESULT res2 = _filterCoder->ReleaseOutStream(); + if (res == S_OK) + res = res2; + } + + RINOK(res) + + if (header.HasSize()) + if (_lzmaDecoder->GetOutputProcessedSize() != header.Size) + return S_FALSE; + + return S_OK; +} + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IArchiveOpenSeq +) + bool _lzma86; + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + bool _unsupported; + bool _dataError; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + + CHeader _header; + CMyComPtr _stream; + CMyComPtr _seqStream; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + + void GetMethod(NCOM::CPropVariant &prop); + + unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); } +public: + CHandler(bool lzma86) { _lzma86 = lzma86; } +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidMethod: GetMethod(prop); break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (_dataError) v |= kpv_ErrorFlags_DataError; + prop = v; + break; + } + default: break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + + +static char * DictSizeToString(UInt32 val, char *s) +{ + for (unsigned i = 0; i < 32; i++) + if (((UInt32)1 << i) == val) + return ::ConvertUInt32ToString(i, s); + char c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + s = ::ConvertUInt32ToString(val, s); + *s++ = c; + *s = 0; + return s; +} + +static char *AddProp32(char *s, const char *name, UInt32 v) +{ + *s++ = ':'; + s = MyStpCpy(s, name); + return ::ConvertUInt32ToString(v, s); +} + +void CHandler::GetMethod(NCOM::CPropVariant &prop) +{ + if (!_stream) + return; + + char sz[64]; + char *s = sz; + if (_header.FilterID != 0) + s = MyStpCpy(s, "BCJ "); + s = MyStpCpy(s, "LZMA:"); + s = DictSizeToString(_header.GetDicSize(), s); + + UInt32 d = _header.GetProp(); + // if (d != 0x5D) + { + UInt32 lc = d % 9; + d /= 9; + UInt32 pb = d / 5; + UInt32 lp = d % 5; + if (lc != 3) s = AddProp32(s, "lc", lc); + if (lp != 0) s = AddProp32(s, "lp", lp); + if (pb != 2) s = AddProp32(s, "pb", pb); + } + prop = sz; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; + case kpidMethod: GetMethod(prop); break; + default: break; + } + prop.Detach(value); + return S_OK; +} + +API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size) +{ + const UInt32 kHeaderSize = 1 + 4 + 8; + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] >= 5 * 5 * 9) + return k_IsArc_Res_NO; + const UInt64 unpackSize = GetUi64(p + 1 + 4); + if (unpackSize != (UInt64)(Int64)-1) + { + if (unpackSize >= ((UInt64)1 << 56)) + return k_IsArc_Res_NO; + } + if (unpackSize != 0) + { + if (size < kHeaderSize + 2) + return k_IsArc_Res_NEED_MORE; + if (p[kHeaderSize] != 0) + return k_IsArc_Res_NO; + if (unpackSize != (UInt64)(Int64)-1) + { + if ((p[kHeaderSize + 1] & 0x80) != 0) + return k_IsArc_Res_NO; + } + } + if (!CheckDicSize(p + 1)) + // return k_IsArc_Res_YES_LOW_PROB; + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + Byte filterID = p[0]; + if (filterID != 0 && filterID != 1) + return k_IsArc_Res_NO; + return IsArc_Lzma(p + 1, size - 1); +} +} + + + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)) +{ + Close(); + + const unsigned headerSize = GetHeaderSize(); + const UInt32 kBufSize = 1 << 7; + Byte buf[kBufSize]; + size_t processedSize = kBufSize; + RINOK(ReadStream(inStream, buf, &processedSize)) + if (processedSize < headerSize + 2) + return S_FALSE; + if (!_header.Parse(buf, _lzma86)) + return S_FALSE; + const Byte *start = buf + headerSize; + if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80 + return S_FALSE; + + RINOK(InStream_GetSize_SeekToEnd(inStream, _packSize)) + + SizeT srcLen = (SizeT)processedSize - headerSize; + + if (srcLen > 10 + && _header.Size == 0 + // && _header.FilterID == 0 + && _header.LzmaProps[0] == 0 + ) + return S_FALSE; + + const UInt32 outLimit = 1 << 11; + Byte outBuf[outLimit]; + + SizeT outSize = outLimit; + if (outSize > _header.Size) + outSize = (SizeT)_header.Size; + SizeT destLen = outSize; + ELzmaStatus status; + + SRes res = LzmaDecode(outBuf, &destLen, start, &srcLen, + _header.LzmaProps, 5, LZMA_FINISH_ANY, + &status, &g_Alloc); + + if (res != SZ_OK) + if (res != SZ_ERROR_INPUT_EOF) + return S_FALSE; + + _isArc = true; + _stream = inStream; + _seqStream = inStream; + _needSeekToStart = true; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + _unsupported = false; + _dataError = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + + _packSize = 0; + + _stream.Release(); + _seqStream.Release(); + return S_OK; +} + +Z7_CLASS_IMP_COM_1( + CCompressProgressInfoImp, + ICompressProgressInfo +) + CMyComPtr Callback; +public: + UInt64 Offset; + + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) +{ + if (Callback) + { + const UInt64 files = 0; + const UInt64 val = Offset + *inSize; + return Callback->SetCompleted(&files, &val); + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + if (_packSize_Defined) + RINOK(extractCallback->SetTotal(_packSize)) + + Int32 opResult; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(); + realOutStream.Release(); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(InStream_SeekToBegin(_stream)) + } + else + _needSeekToStart = true; + + CDecoder decoder; + RINOK(decoder.Create(_lzma86, _seqStream)) + + bool firstItem = true; + + UInt64 packSize = 0; + UInt64 unpackSize = 0; + UInt64 numStreams = 0; + + bool dataAfterEnd = false; + + HRESULT hres = S_OK; + + for (;;) + { + lps->InSize = packSize; + lps->OutSize = unpackSize; + RINOK(lps->SetCur()) + + const UInt32 kBufSize = 1 + 5 + 8; + Byte buf[kBufSize]; + const UInt32 headerSize = GetHeaderSize(); + UInt32 processed; + RINOK(decoder.ReadInput(buf, headerSize, &processed)) + if (processed != headerSize) + { + if (processed != 0) + dataAfterEnd = true; + break; + } + + CHeader st; + if (!st.Parse(buf, _lzma86)) + { + dataAfterEnd = true; + break; + } + numStreams++; + firstItem = false; + + hres = decoder.Code(st, outStream, lps); + + packSize = decoder.GetInputProcessedSize(); + unpackSize = outStream->GetSize(); + + if (hres == E_NOTIMPL) + { + _unsupported = true; + hres = S_FALSE; + break; + } + if (hres == S_FALSE) + break; + RINOK(hres) + } + + if (firstItem) + { + _isArc = false; + hres = S_FALSE; + } + else if (hres == S_OK || hres == S_FALSE) + { + if (dataAfterEnd) + _dataAfterEnd = true; + else if (decoder._lzmaDecoder->NeedsMoreInput()) + _needMoreInput = true; + + _packSize = packSize; + _unpackSize = unpackSize; + _numStreams = numStreams; + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + } + + opResult = NExtract::NOperationResult::kOK; + + if (!_isArc) + opResult = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opResult = NExtract::NOperationResult::kUnexpectedEnd; + else if (_unsupported) + opResult = NExtract::NOperationResult::kUnsupportedMethod; + else if (_dataAfterEnd) + opResult = NExtract::NOperationResult::kDataAfterEnd; + else if (hres == S_FALSE) + opResult = NExtract::NOperationResult::kDataError; + else if (hres == S_OK) + opResult = NExtract::NOperationResult::kOK; + else + return hres; + + // outStream.Release(); + } + return extractCallback->SetOperationResult(opResult); + + COM_TRY_END +} + +namespace NLzmaAr { + +// 2, { 0x5D, 0x00 }, + +REGISTER_ARC_I_CLS_NO_SIG( + CHandler(false), + "lzma", "lzma", NULL, 0xA, + 0, + NArcInfoFlags::kStartOpen | + NArcInfoFlags::kKeepName, + IsArc_Lzma) + +} + +namespace NLzma86Ar { + +REGISTER_ARC_I_CLS_NO_SIG( + CHandler(true), + "lzma86", "lzma86", NULL, 0xB, + 0, + NArcInfoFlags::kKeepName, + IsArc_Lzma86) + +} + +}} diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp index 6d064c40e..4920a0462 100644 --- a/CPP/7zip/Archive/MachoHandler.cpp +++ b/CPP/7zip/Archive/MachoHandler.cpp @@ -1,744 +1,744 @@ -// MachoHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/StringConvert.h" -#include "../../Common/IntToString.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } -static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); } - -using namespace NWindows; -using namespace NCOM; - -namespace NArchive { -namespace NMacho { - -#define CPU_ARCH_ABI64 (1 << 24) -#define CPU_TYPE_386 7 -#define CPU_TYPE_ARM 12 -#define CPU_TYPE_SPARC 14 -#define CPU_TYPE_PPC 18 - -#define CPU_SUBTYPE_I386_ALL 3 - -// #define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC) -#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386) -#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM) - -#define CPU_SUBTYPE_LIB64 ((UInt32)1 << 31) - -#define CPU_SUBTYPE_POWERPC_970 100 - -static const char * const k_PowerPc_SubTypes[] = -{ - NULL - , "601" - , "602" - , "603" - , "603e" - , "603ev" - , "604" - , "604e" - , "620" - , "750" - , "7400" - , "7450" -}; - -static const CUInt32PCharPair g_CpuPairs[] = -{ - { CPU_TYPE_AMD64, "x64" }, - { CPU_TYPE_ARM64, "ARM64" }, - { CPU_TYPE_386, "x86" }, - { CPU_TYPE_ARM, "ARM" }, - { CPU_TYPE_SPARC, "SPARC" }, - { CPU_TYPE_PPC, "PowerPC" } -}; - - -#define CMD_SEGMENT_32 1 -#define CMD_SEGMENT_64 0x19 - -#define SECT_TYPE_MASK 0x000000FF -#define SECT_ATTR_MASK 0xFFFFFF00 - -#define SECT_ATTR_ZEROFILL 1 - -static const char * const g_SectTypes[] = -{ - "REGULAR" - , "ZEROFILL" - , "CSTRINGS" - , "4BYTE_LITERALS" - , "8BYTE_LITERALS" - , "LITERAL_POINTERS" - , "NON_LAZY_SYMBOL_POINTERS" - , "LAZY_SYMBOL_POINTERS" - , "SYMBOL_STUBS" - , "MOD_INIT_FUNC_POINTERS" - , "MOD_TERM_FUNC_POINTERS" - , "COALESCED" - , "GB_ZEROFILL" - , "INTERPOSING" - , "16BYTE_LITERALS" - , "DTRACE_DOF" - , "LAZY_DYLIB_SYMBOL_POINTERS" - , "THREAD_LOCAL_REGULAR" - , "THREAD_LOCAL_ZEROFILL" - , "THREAD_LOCAL_VARIABLES" - , "THREAD_LOCAL_VARIABLE_POINTERS" - , "THREAD_LOCAL_INIT_FUNCTION_POINTERS" -}; - -enum EFileType -{ - kType_OBJECT = 1, - kType_EXECUTE, - kType_FVMLIB, - kType_CORE, - kType_PRELOAD, - kType_DYLIB, - kType_DYLINKER, - kType_BUNDLE, - kType_DYLIB_STUB, - kType_DSYM -}; - -static const char * const g_FileTypes[] = -{ - "0" - , "OBJECT" - , "EXECUTE" - , "FVMLIB" - , "CORE" - , "PRELOAD" - , "DYLIB" - , "DYLINKER" - , "BUNDLE" - , "DYLIB_STUB" - , "DSYM" -}; - - -static const char * const g_ArcFlags[] = -{ - "NOUNDEFS" - , "INCRLINK" - , "DYLDLINK" - , "BINDATLOAD" - , "PREBOUND" - , "SPLIT_SEGS" - , "LAZY_INIT" - , "TWOLEVEL" - , "FORCE_FLAT" - , "NOMULTIDEFS" - , "NOFIXPREBINDING" - , "PREBINDABLE" - , "ALLMODSBOUND" - , "SUBSECTIONS_VIA_SYMBOLS" - , "CANONICAL" - , "WEAK_DEFINES" - , "BINDS_TO_WEAK" - , "ALLOW_STACK_EXECUTION" - , "ROOT_SAFE" - , "SETUID_SAFE" - , "NO_REEXPORTED_DYLIBS" - , "PIE" - , "DEAD_STRIPPABLE_DYLIB" - , "HAS_TLV_DESCRIPTORS" - , "NO_HEAP_EXECUTION" -}; - - -static const CUInt32PCharPair g_SectFlags[] = -{ - { 31, "PURE_INSTRUCTIONS" }, - { 30, "NO_TOC" }, - { 29, "STRIP_STATIC_SYMS" }, - { 28, "NO_DEAD_STRIP" }, - { 27, "LIVE_SUPPORT" }, - { 26, "SELF_MODIFYING_CODE" }, - { 25, "DEBUG" }, - { 10, "SOME_INSTRUCTIONS" }, - { 9, "EXT_RELOC" }, - { 8, "LOC_RELOC" } -}; - - -// VM_PROT_* -static const char * const g_SegmentProt[] = -{ - "READ" - , "WRITE" - , "EXECUTE" - /* - , "NO_CHANGE" - , "COPY" - , "TRUSTED" - , "IS_MASK" - */ -}; - -// SG_* - -static const char * const g_SegmentFlags[] = -{ - "SG_HIGHVM" - , "SG_FVMLIB" - , "SG_NORELOC" - , "SG_PROTECTED_VERSION_1" - , "SG_READ_ONLY" -}; - -static const unsigned kNameSize = 16; - -struct CSegment -{ - char Name[kNameSize]; - UInt32 MaxProt; - UInt32 InitProt; - UInt32 Flags; -}; - -struct CSection -{ - char Name[kNameSize]; - // char SegName[kNameSize]; - UInt64 Va; - UInt64 Pa; - UInt64 VSize; - UInt64 PSize; - - UInt32 Align; - UInt32 Flags; - unsigned SegmentIndex; - bool IsDummy; - - CSection(): IsDummy(false) {} - // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; } - UInt64 GetPackSize() const { return PSize; } -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IArchiveAllowTail -) - CMyComPtr _inStream; - CObjectVector _segments; - CObjectVector _sections; - bool _allowTail; - bool _mode64; - bool _be; - UInt32 _cpuType; - UInt32 _cpuSubType; - UInt32 _type; - UInt32 _flags; - UInt32 _headersSize; - UInt64 _totalSize; - - HRESULT Open2(ISequentialInStream *stream); -public: - CHandler(): _allowTail(false) {} -}; - -static const Byte kArcProps[] = -{ - kpidCpu, - kpidBit64, - kpidBigEndian, - kpidCharacts, - kpidHeadersSize -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidCharacts, - kpidOffset, - kpidVa, - kpidClusterSize // Align -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - CPropVariant prop; - switch (propID) - { - case kpidShortComment: - case kpidCpu: - { - AString s; - const UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64; - UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64; - { - s.Add_UInt32(cpu); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CpuPairs); i++) - { - const CUInt32PCharPair &pair = g_CpuPairs[i]; - if (pair.Value == cpu || pair.Value == _cpuType) - { - if (pair.Value == _cpuType) - flag64 = 0; - s = pair.Name; - break; - } - } - - if (flag64 != 0) - s.Add_OptSpaced("64-bit"); - else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64) - s.Add_OptSpaced("64-bit-lib"); - } - const UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64; - if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386)) - { - const char *n = NULL; - if (cpu == CPU_TYPE_PPC) - { - if (t == CPU_SUBTYPE_POWERPC_970) - n = "970"; - else if (t < Z7_ARRAY_SIZE(k_PowerPc_SubTypes)) - n = k_PowerPc_SubTypes[t]; - } - s.Add_Space(); - if (n) - s += n; - else - s.Add_UInt32(t); - } - prop = s; - break; - } - case kpidCharacts: - { - // TYPE_TO_PROP(g_FileTypes, _type, prop); break; - AString res (TypeToString(g_FileTypes, Z7_ARRAY_SIZE(g_FileTypes), _type)); - const AString s (FlagsToString(g_ArcFlags, Z7_ARRAY_SIZE(g_ArcFlags), _flags)); - if (!s.IsEmpty()) - { - res.Add_Space(); - res += s; - } - prop = res; - break; - } - case kpidPhySize: prop = _totalSize; break; - case kpidHeadersSize: prop = _headersSize; break; - case kpidBit64: if (_mode64) prop = _mode64; break; - case kpidBigEndian: if (_be) prop = _be; break; - case kpidExtension: - { - const char *ext = NULL; - if (_type == kType_OBJECT) - ext = "o"; - else if (_type == kType_BUNDLE) - ext = "bundle"; - else if (_type == kType_DYLIB) - ext = "dylib"; // main shared library usually does not have extension - if (ext) - prop = ext; - break; - } - // case kpidIsSelfExe: prop = (_type == kType_EXECUTE); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -static void AddName(AString &s, const char *name) -{ - char temp[kNameSize + 1]; - memcpy(temp, name, kNameSize); - temp[kNameSize] = 0; - s += temp; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - CPropVariant prop; - const CSection &item = _sections[index]; - switch (propID) - { - case kpidPath: - { - AString s; - AddName(s, _segments[item.SegmentIndex].Name); - if (!item.IsDummy) - { - // CSection::SegName and CSegment::Name are same in real cases. - // AddName(s, item.SegName); - AddName(s, item.Name); - } - prop = MultiByteToUnicodeString(s); - break; - } - case kpidSize: /* prop = (UInt64)item.VSize; break; */ - case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; - case kpidCharacts: - { - AString res; - { - if (!item.IsDummy) - { - { - const AString s (TypeToString(g_SectTypes, Z7_ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK)); - if (!s.IsEmpty()) - { - res.Add_OptSpaced("sect_type:"); - res.Add_OptSpaced(s); - } - } - { - const AString s (FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & SECT_ATTR_MASK)); - if (!s.IsEmpty()) - { - res.Add_OptSpaced("sect_flags:"); - res.Add_OptSpaced(s); - } - } - } - const CSegment &seg = _segments[item.SegmentIndex]; - { - const AString s (FlagsToString(g_SegmentFlags, Z7_ARRAY_SIZE(g_SegmentFlags), seg.Flags)); - if (!s.IsEmpty()) - { - res.Add_OptSpaced("seg_flags:"); - res.Add_OptSpaced(s); - } - } - { - const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.MaxProt)); - if (!s.IsEmpty()) - { - res.Add_OptSpaced("max_prot:"); - res.Add_OptSpaced(s); - } - } - { - const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.InitProt)); - if (!s.IsEmpty()) - { - res.Add_OptSpaced("init_prot:"); - res.Add_OptSpaced(s); - } - } - } - if (!res.IsEmpty()) - prop = res; - break; - } - case kpidOffset: prop = item.Pa; break; - case kpidVa: prop = item.Va; break; - case kpidClusterSize: prop = (UInt32)1 << item.Align; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(ISequentialInStream *stream) -{ - const UInt32 kStartHeaderSize = 7 * 4; - - Byte header[kStartHeaderSize]; - RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize)) - bool be, mode64; - switch (GetUi32(header)) - { - case 0xCEFAEDFE: be = true; mode64 = false; break; - case 0xCFFAEDFE: be = true; mode64 = true; break; - case 0xFEEDFACE: be = false; mode64 = false; break; - case 0xFEEDFACF: be = false; mode64 = true; break; - default: return S_FALSE; - } - - _mode64 = mode64; - _be = be; - - const UInt32 numCommands = Get32(header + 0x10, be); - const UInt32 commandsSize = Get32(header + 0x14, be); - - if (numCommands == 0) - return S_FALSE; - - if (commandsSize > (1 << 24) || - numCommands > (1 << 21) || - numCommands * 8 > commandsSize) - return S_FALSE; - - _cpuType = Get32(header + 4, be); - _cpuSubType = Get32(header + 8, be); - _type = Get32(header + 0xC, be); - _flags = Get32(header + 0x18, be); - - /* - // Probably the sections are in first commands. So we can reduce the number of commands. - bool reduceCommands = false; - const UInt32 kNumReduceCommands = 16; - if (numCommands > kNumReduceCommands) - { - reduceCommands = true; - numCommands = kNumReduceCommands; - } - */ - - UInt32 startHeaderSize = kStartHeaderSize; - if (mode64) - startHeaderSize += 4; - _headersSize = startHeaderSize + commandsSize; - _totalSize = _headersSize; - CByteArr buffer(_headersSize); - RINOK(ReadStream_FALSE(stream, buffer + kStartHeaderSize, _headersSize - kStartHeaderSize)) - const Byte *buf = buffer + startHeaderSize; - size_t size = _headersSize - startHeaderSize; - for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++) - { - if (size < 8) - return S_FALSE; - UInt32 cmd = Get32(buf, be); - UInt32 cmdSize = Get32(buf + 4, be); - if (cmdSize < 8) - return S_FALSE; - if (size < cmdSize) - return S_FALSE; - if (cmd == CMD_SEGMENT_32 || cmd == CMD_SEGMENT_64) - { - UInt32 offs = (cmd == CMD_SEGMENT_64) ? 0x48 : 0x38; - if (cmdSize < offs) - break; - - UInt64 vmAddr, vmSize, phAddr, phSize; - - { - if (cmd == CMD_SEGMENT_64) - { - vmAddr = Get64(buf + 0x18, be); - vmSize = Get64(buf + 0x20, be); - phAddr = Get64(buf + 0x28, be); - phSize = Get64(buf + 0x30, be); - } - else - { - vmAddr = Get32(buf + 0x18, be); - vmSize = Get32(buf + 0x1C, be); - phAddr = Get32(buf + 0x20, be); - phSize = Get32(buf + 0x24, be); - } - { - UInt64 totalSize = phAddr + phSize; - if (totalSize < phAddr) - return S_FALSE; - if (_totalSize < totalSize) - _totalSize = totalSize; - } - } - - CSegment seg; - seg.MaxProt = Get32(buf + offs - 16, be); - seg.InitProt = Get32(buf + offs - 12, be); - seg.Flags = Get32(buf + offs - 4, be); - memcpy(seg.Name, buf + 8, kNameSize); - _segments.Add(seg); - - UInt32 numSections = Get32(buf + offs - 8, be); - if (numSections > (1 << 8)) - return S_FALSE; - - if (numSections == 0) - { - CSection § = _sections.AddNew(); - sect.IsDummy = true; - sect.SegmentIndex = _segments.Size() - 1; - sect.Va = vmAddr; - sect.PSize = phSize; - sect.VSize = vmSize; - sect.Pa = phAddr; - sect.Align = 0; - sect.Flags = 0; - } - else do - { - const UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44; - const Byte *p = buf + offs; - if (cmdSize - offs < headSize) - break; - CSection § = _sections.AddNew(); - unsigned f32Offset; - if (cmd == CMD_SEGMENT_64) - { - sect.Va = Get64(p + 0x20, be); - sect.VSize = Get64(p + 0x28, be); - f32Offset = 0x30; - } - else - { - sect.Va = Get32(p + 0x20, be); - sect.VSize = Get32(p + 0x24, be); - f32Offset = 0x28; - } - sect.Pa = Get32(p + f32Offset, be); - sect.Align = Get32(p + f32Offset + 4, be); - // sect.reloff = Get32(p + f32Offset + 8, be); - // sect.nreloc = Get32(p + f32Offset + 12, be); - sect.Flags = Get32(p + f32Offset + 16, be); - if ((sect.Flags & SECT_TYPE_MASK) == SECT_ATTR_ZEROFILL) - sect.PSize = 0; - else - sect.PSize = sect.VSize; - memcpy(sect.Name, p, kNameSize); - // memcpy(sect.SegName, p + kNameSize, kNameSize); - sect.SegmentIndex = _segments.Size() - 1; - offs += headSize; - } - while (--numSections); - - if (offs != cmdSize) - return S_FALSE; - } - buf += cmdSize; - size -= cmdSize; - } - // return (reduceCommands || (size == 0)) ? S_OK : S_FALSE; - if (size != 0) - return S_FALSE; - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream)) - if (!_allowTail) - { - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) - if (fileSize > _totalSize) - return S_FALSE; - } - _inStream = inStream; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - _inStream.Release(); - _sections.Clear(); - _segments.Clear(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _sections.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _sections.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize(); - extractCallback->SetTotal(totalSize); - - UInt64 currentTotalSize = 0; - UInt64 currentItemSize; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_inStream); - - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()) - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CSection &item = _sections[index]; - currentItemSize = item.GetPackSize(); - - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(InStream_SeekSet(_inStream, item.Pa)) - streamSpec->Init(currentItemSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - outStream.Release(); - RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { - 4, 0xCE, 0xFA, 0xED, 0xFE, - 4, 0xCF, 0xFA, 0xED, 0xFE, - 4, 0xFE, 0xED, 0xFA, 0xCE, - 4, 0xFE, 0xED, 0xFA, 0xCF }; - -REGISTER_ARC_I( - "MachO", "macho", NULL, 0xDF, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kPreArc, - NULL) - -}} +// MachoHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringConvert.h" +#include "../../Common/IntToString.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } +static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); } + +using namespace NWindows; +using namespace NCOM; + +namespace NArchive { +namespace NMacho { + +#define CPU_ARCH_ABI64 (1 << 24) +#define CPU_TYPE_386 7 +#define CPU_TYPE_ARM 12 +#define CPU_TYPE_SPARC 14 +#define CPU_TYPE_PPC 18 + +#define CPU_SUBTYPE_I386_ALL 3 + +// #define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC) +#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386) +#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM) + +#define CPU_SUBTYPE_LIB64 ((UInt32)1 << 31) + +#define CPU_SUBTYPE_POWERPC_970 100 + +static const char * const k_PowerPc_SubTypes[] = +{ + NULL + , "601" + , "602" + , "603" + , "603e" + , "603ev" + , "604" + , "604e" + , "620" + , "750" + , "7400" + , "7450" +}; + +static const CUInt32PCharPair g_CpuPairs[] = +{ + { CPU_TYPE_AMD64, "x64" }, + { CPU_TYPE_ARM64, "ARM64" }, + { CPU_TYPE_386, "x86" }, + { CPU_TYPE_ARM, "ARM" }, + { CPU_TYPE_SPARC, "SPARC" }, + { CPU_TYPE_PPC, "PowerPC" } +}; + + +#define CMD_SEGMENT_32 1 +#define CMD_SEGMENT_64 0x19 + +#define SECT_TYPE_MASK 0x000000FF +#define SECT_ATTR_MASK 0xFFFFFF00 + +#define SECT_ATTR_ZEROFILL 1 + +static const char * const g_SectTypes[] = +{ + "REGULAR" + , "ZEROFILL" + , "CSTRINGS" + , "4BYTE_LITERALS" + , "8BYTE_LITERALS" + , "LITERAL_POINTERS" + , "NON_LAZY_SYMBOL_POINTERS" + , "LAZY_SYMBOL_POINTERS" + , "SYMBOL_STUBS" + , "MOD_INIT_FUNC_POINTERS" + , "MOD_TERM_FUNC_POINTERS" + , "COALESCED" + , "GB_ZEROFILL" + , "INTERPOSING" + , "16BYTE_LITERALS" + , "DTRACE_DOF" + , "LAZY_DYLIB_SYMBOL_POINTERS" + , "THREAD_LOCAL_REGULAR" + , "THREAD_LOCAL_ZEROFILL" + , "THREAD_LOCAL_VARIABLES" + , "THREAD_LOCAL_VARIABLE_POINTERS" + , "THREAD_LOCAL_INIT_FUNCTION_POINTERS" +}; + +enum EFileType +{ + kType_OBJECT = 1, + kType_EXECUTE, + kType_FVMLIB, + kType_CORE, + kType_PRELOAD, + kType_DYLIB, + kType_DYLINKER, + kType_BUNDLE, + kType_DYLIB_STUB, + kType_DSYM +}; + +static const char * const g_FileTypes[] = +{ + "0" + , "OBJECT" + , "EXECUTE" + , "FVMLIB" + , "CORE" + , "PRELOAD" + , "DYLIB" + , "DYLINKER" + , "BUNDLE" + , "DYLIB_STUB" + , "DSYM" +}; + + +static const char * const g_ArcFlags[] = +{ + "NOUNDEFS" + , "INCRLINK" + , "DYLDLINK" + , "BINDATLOAD" + , "PREBOUND" + , "SPLIT_SEGS" + , "LAZY_INIT" + , "TWOLEVEL" + , "FORCE_FLAT" + , "NOMULTIDEFS" + , "NOFIXPREBINDING" + , "PREBINDABLE" + , "ALLMODSBOUND" + , "SUBSECTIONS_VIA_SYMBOLS" + , "CANONICAL" + , "WEAK_DEFINES" + , "BINDS_TO_WEAK" + , "ALLOW_STACK_EXECUTION" + , "ROOT_SAFE" + , "SETUID_SAFE" + , "NO_REEXPORTED_DYLIBS" + , "PIE" + , "DEAD_STRIPPABLE_DYLIB" + , "HAS_TLV_DESCRIPTORS" + , "NO_HEAP_EXECUTION" +}; + + +static const CUInt32PCharPair g_SectFlags[] = +{ + { 31, "PURE_INSTRUCTIONS" }, + { 30, "NO_TOC" }, + { 29, "STRIP_STATIC_SYMS" }, + { 28, "NO_DEAD_STRIP" }, + { 27, "LIVE_SUPPORT" }, + { 26, "SELF_MODIFYING_CODE" }, + { 25, "DEBUG" }, + { 10, "SOME_INSTRUCTIONS" }, + { 9, "EXT_RELOC" }, + { 8, "LOC_RELOC" } +}; + + +// VM_PROT_* +static const char * const g_SegmentProt[] = +{ + "READ" + , "WRITE" + , "EXECUTE" + /* + , "NO_CHANGE" + , "COPY" + , "TRUSTED" + , "IS_MASK" + */ +}; + +// SG_* + +static const char * const g_SegmentFlags[] = +{ + "SG_HIGHVM" + , "SG_FVMLIB" + , "SG_NORELOC" + , "SG_PROTECTED_VERSION_1" + , "SG_READ_ONLY" +}; + +static const unsigned kNameSize = 16; + +struct CSegment +{ + char Name[kNameSize]; + UInt32 MaxProt; + UInt32 InitProt; + UInt32 Flags; +}; + +struct CSection +{ + char Name[kNameSize]; + // char SegName[kNameSize]; + UInt64 Va; + UInt64 Pa; + UInt64 VSize; + UInt64 PSize; + + UInt32 Align; + UInt32 Flags; + unsigned SegmentIndex; + bool IsDummy; + + CSection(): IsDummy(false) {} + // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; } + UInt64 GetPackSize() const { return PSize; } +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IArchiveAllowTail +) + CMyComPtr _inStream; + CObjectVector _segments; + CObjectVector _sections; + bool _allowTail; + bool _mode64; + bool _be; + UInt32 _cpuType; + UInt32 _cpuSubType; + UInt32 _type; + UInt32 _flags; + UInt32 _headersSize; + UInt64 _totalSize; + + HRESULT Open2(ISequentialInStream *stream); +public: + CHandler(): _allowTail(false) {} +}; + +static const Byte kArcProps[] = +{ + kpidCpu, + kpidBit64, + kpidBigEndian, + kpidCharacts, + kpidHeadersSize +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCharacts, + kpidOffset, + kpidVa, + kpidClusterSize // Align +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + CPropVariant prop; + switch (propID) + { + case kpidShortComment: + case kpidCpu: + { + AString s; + const UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64; + UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64; + { + s.Add_UInt32(cpu); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CpuPairs); i++) + { + const CUInt32PCharPair &pair = g_CpuPairs[i]; + if (pair.Value == cpu || pair.Value == _cpuType) + { + if (pair.Value == _cpuType) + flag64 = 0; + s = pair.Name; + break; + } + } + + if (flag64 != 0) + s.Add_OptSpaced("64-bit"); + else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64) + s.Add_OptSpaced("64-bit-lib"); + } + const UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64; + if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386)) + { + const char *n = NULL; + if (cpu == CPU_TYPE_PPC) + { + if (t == CPU_SUBTYPE_POWERPC_970) + n = "970"; + else if (t < Z7_ARRAY_SIZE(k_PowerPc_SubTypes)) + n = k_PowerPc_SubTypes[t]; + } + s.Add_Space(); + if (n) + s += n; + else + s.Add_UInt32(t); + } + prop = s; + break; + } + case kpidCharacts: + { + // TYPE_TO_PROP(g_FileTypes, _type, prop); break; + AString res (TypeToString(g_FileTypes, Z7_ARRAY_SIZE(g_FileTypes), _type)); + const AString s (FlagsToString(g_ArcFlags, Z7_ARRAY_SIZE(g_ArcFlags), _flags)); + if (!s.IsEmpty()) + { + res.Add_Space(); + res += s; + } + prop = res; + break; + } + case kpidPhySize: prop = _totalSize; break; + case kpidHeadersSize: prop = _headersSize; break; + case kpidBit64: if (_mode64) prop = _mode64; break; + case kpidBigEndian: if (_be) prop = _be; break; + case kpidExtension: + { + const char *ext = NULL; + if (_type == kType_OBJECT) + ext = "o"; + else if (_type == kType_BUNDLE) + ext = "bundle"; + else if (_type == kType_DYLIB) + ext = "dylib"; // main shared library usually does not have extension + if (ext) + prop = ext; + break; + } + // case kpidIsSelfExe: prop = (_type == kType_EXECUTE); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static void AddName(AString &s, const char *name) +{ + char temp[kNameSize + 1]; + memcpy(temp, name, kNameSize); + temp[kNameSize] = 0; + s += temp; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + CPropVariant prop; + const CSection &item = _sections[index]; + switch (propID) + { + case kpidPath: + { + AString s; + AddName(s, _segments[item.SegmentIndex].Name); + if (!item.IsDummy) + { + // CSection::SegName and CSegment::Name are same in real cases. + // AddName(s, item.SegName); + AddName(s, item.Name); + } + prop = MultiByteToUnicodeString(s); + break; + } + case kpidSize: /* prop = (UInt64)item.VSize; break; */ + case kpidPackSize: prop = (UInt64)item.GetPackSize(); break; + case kpidCharacts: + { + AString res; + { + if (!item.IsDummy) + { + { + const AString s (TypeToString(g_SectTypes, Z7_ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK)); + if (!s.IsEmpty()) + { + res.Add_OptSpaced("sect_type:"); + res.Add_OptSpaced(s); + } + } + { + const AString s (FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & SECT_ATTR_MASK)); + if (!s.IsEmpty()) + { + res.Add_OptSpaced("sect_flags:"); + res.Add_OptSpaced(s); + } + } + } + const CSegment &seg = _segments[item.SegmentIndex]; + { + const AString s (FlagsToString(g_SegmentFlags, Z7_ARRAY_SIZE(g_SegmentFlags), seg.Flags)); + if (!s.IsEmpty()) + { + res.Add_OptSpaced("seg_flags:"); + res.Add_OptSpaced(s); + } + } + { + const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.MaxProt)); + if (!s.IsEmpty()) + { + res.Add_OptSpaced("max_prot:"); + res.Add_OptSpaced(s); + } + } + { + const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.InitProt)); + if (!s.IsEmpty()) + { + res.Add_OptSpaced("init_prot:"); + res.Add_OptSpaced(s); + } + } + } + if (!res.IsEmpty()) + prop = res; + break; + } + case kpidOffset: prop = item.Pa; break; + case kpidVa: prop = item.Va; break; + case kpidClusterSize: prop = (UInt32)1 << item.Align; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(ISequentialInStream *stream) +{ + const UInt32 kStartHeaderSize = 7 * 4; + + Byte header[kStartHeaderSize]; + RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize)) + bool be, mode64; + switch (GetUi32(header)) + { + case 0xCEFAEDFE: be = true; mode64 = false; break; + case 0xCFFAEDFE: be = true; mode64 = true; break; + case 0xFEEDFACE: be = false; mode64 = false; break; + case 0xFEEDFACF: be = false; mode64 = true; break; + default: return S_FALSE; + } + + _mode64 = mode64; + _be = be; + + const UInt32 numCommands = Get32(header + 0x10, be); + const UInt32 commandsSize = Get32(header + 0x14, be); + + if (numCommands == 0) + return S_FALSE; + + if (commandsSize > (1 << 24) || + numCommands > (1 << 21) || + numCommands * 8 > commandsSize) + return S_FALSE; + + _cpuType = Get32(header + 4, be); + _cpuSubType = Get32(header + 8, be); + _type = Get32(header + 0xC, be); + _flags = Get32(header + 0x18, be); + + /* + // Probably the sections are in first commands. So we can reduce the number of commands. + bool reduceCommands = false; + const UInt32 kNumReduceCommands = 16; + if (numCommands > kNumReduceCommands) + { + reduceCommands = true; + numCommands = kNumReduceCommands; + } + */ + + UInt32 startHeaderSize = kStartHeaderSize; + if (mode64) + startHeaderSize += 4; + _headersSize = startHeaderSize + commandsSize; + _totalSize = _headersSize; + CByteArr buffer(_headersSize); + RINOK(ReadStream_FALSE(stream, buffer + kStartHeaderSize, _headersSize - kStartHeaderSize)) + const Byte *buf = buffer + startHeaderSize; + size_t size = _headersSize - startHeaderSize; + for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++) + { + if (size < 8) + return S_FALSE; + UInt32 cmd = Get32(buf, be); + UInt32 cmdSize = Get32(buf + 4, be); + if (cmdSize < 8) + return S_FALSE; + if (size < cmdSize) + return S_FALSE; + if (cmd == CMD_SEGMENT_32 || cmd == CMD_SEGMENT_64) + { + UInt32 offs = (cmd == CMD_SEGMENT_64) ? 0x48 : 0x38; + if (cmdSize < offs) + break; + + UInt64 vmAddr, vmSize, phAddr, phSize; + + { + if (cmd == CMD_SEGMENT_64) + { + vmAddr = Get64(buf + 0x18, be); + vmSize = Get64(buf + 0x20, be); + phAddr = Get64(buf + 0x28, be); + phSize = Get64(buf + 0x30, be); + } + else + { + vmAddr = Get32(buf + 0x18, be); + vmSize = Get32(buf + 0x1C, be); + phAddr = Get32(buf + 0x20, be); + phSize = Get32(buf + 0x24, be); + } + { + UInt64 totalSize = phAddr + phSize; + if (totalSize < phAddr) + return S_FALSE; + if (_totalSize < totalSize) + _totalSize = totalSize; + } + } + + CSegment seg; + seg.MaxProt = Get32(buf + offs - 16, be); + seg.InitProt = Get32(buf + offs - 12, be); + seg.Flags = Get32(buf + offs - 4, be); + memcpy(seg.Name, buf + 8, kNameSize); + _segments.Add(seg); + + UInt32 numSections = Get32(buf + offs - 8, be); + if (numSections > (1 << 8)) + return S_FALSE; + + if (numSections == 0) + { + CSection § = _sections.AddNew(); + sect.IsDummy = true; + sect.SegmentIndex = _segments.Size() - 1; + sect.Va = vmAddr; + sect.PSize = phSize; + sect.VSize = vmSize; + sect.Pa = phAddr; + sect.Align = 0; + sect.Flags = 0; + } + else do + { + const UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44; + const Byte *p = buf + offs; + if (cmdSize - offs < headSize) + break; + CSection § = _sections.AddNew(); + unsigned f32Offset; + if (cmd == CMD_SEGMENT_64) + { + sect.Va = Get64(p + 0x20, be); + sect.VSize = Get64(p + 0x28, be); + f32Offset = 0x30; + } + else + { + sect.Va = Get32(p + 0x20, be); + sect.VSize = Get32(p + 0x24, be); + f32Offset = 0x28; + } + sect.Pa = Get32(p + f32Offset, be); + sect.Align = Get32(p + f32Offset + 4, be); + // sect.reloff = Get32(p + f32Offset + 8, be); + // sect.nreloc = Get32(p + f32Offset + 12, be); + sect.Flags = Get32(p + f32Offset + 16, be); + if ((sect.Flags & SECT_TYPE_MASK) == SECT_ATTR_ZEROFILL) + sect.PSize = 0; + else + sect.PSize = sect.VSize; + memcpy(sect.Name, p, kNameSize); + // memcpy(sect.SegName, p + kNameSize, kNameSize); + sect.SegmentIndex = _segments.Size() - 1; + offs += headSize; + } + while (--numSections); + + if (offs != cmdSize) + return S_FALSE; + } + buf += cmdSize; + size -= cmdSize; + } + // return (reduceCommands || (size == 0)) ? S_OK : S_FALSE; + if (size != 0) + return S_FALSE; + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream)) + if (!_allowTail) + { + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize)) + if (fileSize > _totalSize) + return S_FALSE; + } + _inStream = inStream; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + _inStream.Release(); + _sections.Clear(); + _segments.Clear(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _sections.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _sections.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize(); + extractCallback->SetTotal(totalSize); + + UInt64 currentTotalSize = 0; + UInt64 currentItemSize; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_inStream); + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()) + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CSection &item = _sections[index]; + currentItemSize = item.GetPackSize(); + + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(InStream_SeekSet(_inStream, item.Pa)) + streamSpec->Init(currentItemSize); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) + outStream.Release(); + RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { + 4, 0xCE, 0xFA, 0xED, 0xFE, + 4, 0xCF, 0xFA, 0xED, 0xFE, + 4, 0xFE, 0xED, 0xFA, 0xCE, + 4, 0xFE, 0xED, 0xFA, 0xCF }; + +REGISTER_ARC_I( + "MachO", "macho", NULL, 0xDF, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kPreArc, + NULL) + +}} diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp index e306f4d8c..82d34fd66 100644 --- a/CPP/7zip/Archive/MbrHandler.cpp +++ b/CPP/7zip/Archive/MbrHandler.cpp @@ -1,643 +1,643 @@ -// MbrHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -using namespace NWindows; - -namespace NArchive { - -namespace NFat { -API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); -} - -namespace NMbr { - -struct CChs -{ - Byte Head; - Byte SectCyl; - Byte Cyl8; - - UInt32 GetSector() const { return SectCyl & 0x3F; } - UInt32 GetCyl() const { return ((UInt32)SectCyl >> 6 << 8) | Cyl8; } - void ToString(NCOM::CPropVariant &prop) const; - - void Parse(const Byte *p) - { - Head = p[0]; - SectCyl = p[1]; - Cyl8 = p[2]; - } - bool Check() const { return GetSector() > 0; } -}; - - -// Chs in some MBRs contains only low bits of "Cyl number". So we disable check. -/* -#define RINOZ(x) { int _t_ = (x); if (_t_ != 0) return _t_; } -static int CompareChs(const CChs &c1, const CChs &c2) -{ - RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl())); - RINOZ(MyCompare(c1.Head, c2.Head)); - return MyCompare(c1.GetSector(), c2.GetSector()); -} -*/ - -void CChs::ToString(NCOM::CPropVariant &prop) const -{ - AString s; - s.Add_UInt32(GetCyl()); - s.Add_Minus(); - s.Add_UInt32(Head); - s.Add_Minus(); - s.Add_UInt32(GetSector()); - prop = s; -} - -struct CPartition -{ - Byte Status; - CChs BeginChs; - Byte Type; - CChs EndChs; - UInt32 Lba; - UInt32 NumBlocks; - - CPartition() { memset (this, 0, sizeof(*this)); } - - bool IsEmpty() const { return Type == 0; } - bool IsExtended() const { return Type == 5 || Type == 0xF; } - UInt32 GetLimit() const { return Lba + NumBlocks; } - // bool IsActive() const { return Status == 0x80; } - UInt64 GetPos(unsigned sectorSizeLog) const { return (UInt64)Lba << sectorSizeLog; } - UInt64 GetSize(unsigned sectorSizeLog) const { return (UInt64)NumBlocks << sectorSizeLog; } - - bool CheckLbaLimits() const { return (UInt32)0xFFFFFFFF - Lba >= NumBlocks; } - bool Parse(const Byte *p) - { - Status = p[0]; - BeginChs.Parse(p + 1); - Type = p[4]; - EndChs.Parse(p + 5); - Lba = GetUi32(p + 8); - NumBlocks = GetUi32(p + 12); - if (Type == 0) - return true; - if (Status != 0 && Status != 0x80) - return false; - return BeginChs.Check() - && EndChs.Check() - // && CompareChs(BeginChs, EndChs) <= 0 - && NumBlocks > 0 - && CheckLbaLimits(); - } - - #ifdef SHOW_DEBUG_INFO - void Print() const - { - NCOM::CPropVariant prop, prop2; - BeginChs.ToString(prop); - EndChs.ToString(prop2); - printf(" %2x %2x %8X %8X %12S %12S", (int)Status, (int)Type, Lba, NumBlocks, prop.bstrVal, prop2.bstrVal); - } - #endif -}; - -struct CPartType -{ - UInt32 Id; - const char *Ext; - const char *Name; -}; - -#define kFat "fat" - -/* -if we use "format" command in Windows 10 for existing partition: - - if we format to ExFAT, it sets type=7 - - if we format to UDF, it doesn't change type from previous value. -*/ - -static const unsigned kType_Windows_NTFS = 7; - -static const CPartType kPartTypes[] = -{ - { 0x01, kFat, "FAT12" }, - { 0x04, kFat, "FAT16 DOS 3.0+" }, - { 0x05, NULL, "Extended" }, - { 0x06, kFat, "FAT16 DOS 3.31+" }, - { 0x07, "ntfs", "NTFS" }, - { 0x0B, kFat, "FAT32" }, - { 0x0C, kFat, "FAT32-LBA" }, - { 0x0E, kFat, "FAT16-LBA" }, - { 0x0F, NULL, "Extended-LBA" }, - { 0x11, kFat, "FAT12-Hidden" }, - { 0x14, kFat, "FAT16-Hidden < 32 MB" }, - { 0x16, kFat, "FAT16-Hidden >= 32 MB" }, - { 0x1B, kFat, "FAT32-Hidden" }, - { 0x1C, kFat, "FAT32-LBA-Hidden" }, - { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" }, - { 0x27, "ntfs", "NTFS-WinRE" }, - { 0x82, NULL, "Solaris x86 / Linux swap" }, - { 0x83, NULL, "Linux" }, - { 0x8E, "lvm", "Linux LVM" }, - { 0xA5, NULL, "BSD slice" }, - { 0xBE, NULL, "Solaris 8 boot" }, - { 0xBF, NULL, "New Solaris x86" }, - { 0xC2, NULL, "Linux-Hidden" }, - { 0xC3, NULL, "Linux swap-Hidden" }, - { 0xEE, NULL, "GPT" }, - { 0xEE, NULL, "EFI" } -}; - -static int FindPartType(UInt32 type) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPartTypes); i++) - if (kPartTypes[i].Id == type) - return (int)i; - return -1; -} - -struct CItem -{ - bool IsReal; - bool IsPrim; - bool WasParsed; - const char *FileSystem; - UInt64 Size; - CPartition Part; - - CItem(): - WasParsed(false), - FileSystem(NULL) - {} -}; - - -Z7_class_CHandler_final: public CHandlerCont -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - CObjectVector _items; - UInt64 _totalSize; - CByteBuffer _buffer; - - UInt32 _signature; - unsigned _sectorSizeLog; - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override Z7_final - { - const CItem &item = _items[index]; - pos = item.Part.GetPos(_sectorSizeLog); - size = item.Size; - return NExtract::NOperationResult::kOK; - } - - HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level); -}; - -/* -static bool IsEmptyBuffer(const Byte *data, size_t size) -{ - for (unsigned i = 0; i < size; i++) - if (data[i] != 0) - return false; - return true; -} -*/ - -const char *GetFileSystem(ISequentialInStream *stream, UInt64 partitionSize); - -HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level) -{ - if (level >= 128 || _items.Size() >= 128) - return S_FALSE; - - const unsigned kNumHeaderParts = 4; - CPartition parts[kNumHeaderParts]; - - if (level == 0) - _sectorSizeLog = 9; - const UInt32 kSectorSize = (UInt32)1 << _sectorSizeLog; - UInt32 bufSize = kSectorSize; - if (level == 0 && _totalSize >= (1 << 12)) - bufSize = (1 << 12); - _buffer.Alloc(bufSize); - { - Byte *buf = _buffer; - const UInt64 newPos = (UInt64)lba << _sectorSizeLog; - if (newPos + bufSize > _totalSize) - return S_FALSE; - RINOK(InStream_SeekSet(stream, newPos)) - RINOK(ReadStream_FALSE(stream, buf, bufSize)) - if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) - return S_FALSE; - if (level == 0) - _signature = GetUi32(buf + 0x1B8); - for (unsigned i = 0; i < kNumHeaderParts; i++) - if (!parts[i].Parse(buf + 0x1BE + 16 * i)) - return S_FALSE; - } - - // 23.02: now we try to detect 4kn format (4 KB sectors case) - if (level == 0) - // if (_totalSize >= (1 << 28)) // we don't expect small images with 4 KB sectors - if (bufSize >= (1 << 12)) - { - UInt32 lastLim = 0; - UInt32 firstLba = 0; - UInt32 numBlocks = 0; // in first partition - for (unsigned i = 0; i < kNumHeaderParts; i++) - { - const CPartition &part = parts[i]; - if (part.IsEmpty()) - continue; - if (firstLba == 0 && part.NumBlocks != 0) - { - firstLba = part.Lba; - numBlocks = part.NumBlocks; - } - const UInt32 newLim = part.GetLimit(); - if (newLim < lastLim) - return S_FALSE; - lastLim = newLim; - } - if (lastLim != 0) - { - const UInt64 lim12 = (UInt64)lastLim << 12; - if (lim12 <= _totalSize - // && _totalSize - lim12 < (1 << 28) // we can try to exclude false positive cases - ) - // if (IsEmptyBuffer(&_buffer[(1 << 9)], (1 << 12) - (1 << 9))) - if (InStream_SeekSet(stream, (UInt64)firstLba << 12) == S_OK) - if (GetFileSystem(stream, (UInt64)numBlocks << 12)) - _sectorSizeLog = 12; - } - } - - PRF(printf("\n# %8X", lba)); - - UInt32 limLba = lba + 1; - if (limLba == 0) - return S_FALSE; - - for (unsigned i = 0; i < kNumHeaderParts; i++) - { - CPartition &part = parts[i]; - - if (part.IsEmpty()) - continue; - PRF(printf("\n %2d ", (unsigned)level)); - #ifdef SHOW_DEBUG_INFO - part.Print(); - #endif - - unsigned numItems = _items.Size(); - UInt32 newLba = lba + part.Lba; - - if (part.IsExtended()) - { - // if (part.Type == 5) // Check it! - newLba = baseLba + part.Lba; - if (newLba < limLba) - return S_FALSE; - const HRESULT res = ReadTables(stream, level < 1 ? newLba : baseLba, newLba, level + 1); - if (res != S_FALSE && res != S_OK) - return res; - } - if (newLba < limLba) - return S_FALSE; - part.Lba = newLba; - if (!part.CheckLbaLimits()) - return S_FALSE; - - CItem n; - n.Part = part; - bool addItem = false; - if (numItems == _items.Size()) - { - n.IsPrim = (level == 0); - n.IsReal = true; - addItem = true; - } - else - { - const CItem &back = _items.Back(); - const UInt32 backLimit = back.Part.GetLimit(); - const UInt32 partLimit = part.GetLimit(); - if (backLimit < partLimit) - { - n.IsReal = false; - n.Part.Lba = backLimit; - n.Part.NumBlocks = partLimit - backLimit; - addItem = true; - } - } - if (addItem) - { - if (n.Part.GetLimit() < limLba) - return S_FALSE; - limLba = n.Part.GetLimit(); - n.Size = n.Part.GetSize(_sectorSizeLog); - _items.Add(n); - } - } - return S_OK; -} - - -static const Byte k_Ntfs_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }; - -static bool Is_Ntfs(const Byte *p) -{ - if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) - return false; - switch (p[0]) - { - case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break; - case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break; - default: return false; - } - return memcmp(p + 3, k_Ntfs_Signature, Z7_ARRAY_SIZE(k_Ntfs_Signature)) == 0; -} - -static const Byte k_ExFat_Signature[] = { 'E', 'X', 'F', 'A', 'T', ' ', ' ', ' ' }; - -static bool Is_ExFat(const Byte *p) -{ - if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) - return false; - if (p[0] != 0xEB || p[1] != 0x76 || p[2] != 0x90) - return false; - return memcmp(p + 3, k_ExFat_Signature, Z7_ARRAY_SIZE(k_ExFat_Signature)) == 0; -} - -static bool AllAreZeros(const Byte *p, size_t size) -{ - for (size_t i = 0; i < size; i++) - if (p[i] != 0) - return false; - return true; -} - -static const UInt32 k_Udf_StartPos = 0x8000; -static const Byte k_Udf_Signature[] = { 0, 'B', 'E', 'A', '0', '1', 1, 0 }; - -static bool Is_Udf(const Byte *p) -{ - return memcmp(p + k_Udf_StartPos, k_Udf_Signature, sizeof(k_Udf_Signature)) == 0; -} - - -const char *GetFileSystem(ISequentialInStream *stream, UInt64 partitionSize) -{ - const size_t kHeaderSize = 1 << 9; - if (partitionSize >= kHeaderSize) - { - Byte buf[kHeaderSize]; - if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK) - { - // NTFS is expected default filesystem for (Type == 7) - if (Is_Ntfs(buf)) - return "NTFS"; - if (Is_ExFat(buf)) - return "exFAT"; - if (NFat::IsArc_Fat(buf, kHeaderSize)) - return "FAT"; - const size_t kHeaderSize2 = k_Udf_StartPos + (1 << 9); - if (partitionSize >= kHeaderSize2) - { - if (AllAreZeros(buf, kHeaderSize)) - { - CByteBuffer buffer(kHeaderSize2); - // memcpy(buffer, buf, kHeaderSize); - if (ReadStream_FAIL(stream, buffer + kHeaderSize, kHeaderSize2 - kHeaderSize) == S_OK) - if (Is_Udf(buffer)) - return "UDF"; - } - } - } - } - return NULL; -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - RINOK(InStream_GetSize_SeekToEnd(stream, _totalSize)) - RINOK(ReadTables(stream, 0, 0, 0)) - if (_items.IsEmpty()) - return S_FALSE; - { - const UInt32 lbaLimit = _items.Back().Part.GetLimit(); - const UInt64 lim = (UInt64)lbaLimit << _sectorSizeLog; - if (lim < _totalSize) - { - CItem n; - n.Part.Lba = lbaLimit; - n.Size = _totalSize - lim; - n.IsReal = false; - _items.Add(n); - } - } - - FOR_VECTOR (i, _items) - { - CItem &item = _items[i]; - if (item.Part.Type != kType_Windows_NTFS) - continue; - if (InStream_SeekSet(stream, item.Part.GetPos(_sectorSizeLog)) != S_OK) - continue; - item.FileSystem = GetFileSystem(stream, item.Size); - item.WasParsed = true; - } - - _stream = stream; - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - _items.Clear(); - _stream.Release(); - return S_OK; -} - - -enum -{ - kpidPrimary = kpidUserDefined, - kpidBegChs, - kpidEndChs -}; - -static const CStatProp kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidOffset, VT_UI8}, - { "Primary", kpidPrimary, VT_BOOL}, - { "Begin CHS", kpidBegChs, VT_BSTR}, - { "End CHS", kpidEndChs, VT_BSTR} -}; - -static const Byte kArcProps[] = -{ - kpidSectorSize, - kpidId -}; - -IMP_IInArchive_Props_WITH_NAME -IMP_IInArchive_ArcProps - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: - { - int mainIndex = -1; - FOR_VECTOR (i, _items) - if (_items[i].IsReal) - { - if (mainIndex >= 0) - { - mainIndex = -1; - break; - } - mainIndex = (int)i; - } - if (mainIndex >= 0) - prop = (UInt32)(Int32)mainIndex; - break; - } - case kpidPhySize: prop = _totalSize; break; - case kpidSectorSize: prop = (UInt32)((UInt32)1 << _sectorSizeLog); break; - case kpidId: prop = _signature; break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CItem &item = _items[index]; - const CPartition &part = item.Part; - switch (propID) - { - case kpidPath: - { - AString s; - s.Add_UInt32(index); - if (item.IsReal) - { - s.Add_Dot(); - const char *ext = NULL; - if (item.FileSystem) - { - ext = ""; - AString fs (item.FileSystem); - fs.MakeLower_Ascii(); - s += fs; - } - else if (!item.WasParsed) - { - const int typeIndex = FindPartType(part.Type); - if (typeIndex >= 0) - ext = kPartTypes[(unsigned)typeIndex].Ext; - } - if (!ext) - ext = "img"; - s += ext; - } - prop = s; - break; - } - case kpidFileSystem: - if (item.IsReal) - { - char s[32]; - ConvertUInt32ToString(part.Type, s); - const char *res = s; - if (item.FileSystem) - { - // strcat(s, "-"); - // strcpy(s, item.FileSystem); - res = item.FileSystem; - } - else if (!item.WasParsed) - { - const int typeIndex = FindPartType(part.Type); - if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Name) - res = kPartTypes[(unsigned)typeIndex].Name; - } - prop = res; - } - break; - case kpidSize: - case kpidPackSize: prop = item.Size; break; - case kpidOffset: prop = part.GetPos(_sectorSizeLog); break; - case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break; - case kpidBegChs: if (item.IsReal) part.BeginChs.ToString(prop); break; - case kpidEndChs: if (item.IsReal) part.EndChs.ToString(prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - - // 3, { 1, 1, 0 }, - // 2, { 0x55, 0x1FF }, - -REGISTER_ARC_I_NO_SIG( - "MBR", "mbr", NULL, 0xDB, - 0, - NArcInfoFlags::kPureStartOpen, - NULL) - -}} +// MbrHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +using namespace NWindows; + +namespace NArchive { + +namespace NFat { +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); +} + +namespace NMbr { + +struct CChs +{ + Byte Head; + Byte SectCyl; + Byte Cyl8; + + UInt32 GetSector() const { return SectCyl & 0x3F; } + UInt32 GetCyl() const { return ((UInt32)SectCyl >> 6 << 8) | Cyl8; } + void ToString(NCOM::CPropVariant &prop) const; + + void Parse(const Byte *p) + { + Head = p[0]; + SectCyl = p[1]; + Cyl8 = p[2]; + } + bool Check() const { return GetSector() > 0; } +}; + + +// Chs in some MBRs contains only low bits of "Cyl number". So we disable check. +/* +#define RINOZ(x) { int _t_ = (x); if (_t_ != 0) return _t_; } +static int CompareChs(const CChs &c1, const CChs &c2) +{ + RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl())); + RINOZ(MyCompare(c1.Head, c2.Head)); + return MyCompare(c1.GetSector(), c2.GetSector()); +} +*/ + +void CChs::ToString(NCOM::CPropVariant &prop) const +{ + AString s; + s.Add_UInt32(GetCyl()); + s.Add_Minus(); + s.Add_UInt32(Head); + s.Add_Minus(); + s.Add_UInt32(GetSector()); + prop = s; +} + +struct CPartition +{ + Byte Status; + CChs BeginChs; + Byte Type; + CChs EndChs; + UInt32 Lba; + UInt32 NumBlocks; + + CPartition() { memset (this, 0, sizeof(*this)); } + + bool IsEmpty() const { return Type == 0; } + bool IsExtended() const { return Type == 5 || Type == 0xF; } + UInt32 GetLimit() const { return Lba + NumBlocks; } + // bool IsActive() const { return Status == 0x80; } + UInt64 GetPos(unsigned sectorSizeLog) const { return (UInt64)Lba << sectorSizeLog; } + UInt64 GetSize(unsigned sectorSizeLog) const { return (UInt64)NumBlocks << sectorSizeLog; } + + bool CheckLbaLimits() const { return (UInt32)0xFFFFFFFF - Lba >= NumBlocks; } + bool Parse(const Byte *p) + { + Status = p[0]; + BeginChs.Parse(p + 1); + Type = p[4]; + EndChs.Parse(p + 5); + Lba = GetUi32(p + 8); + NumBlocks = GetUi32(p + 12); + if (Type == 0) + return true; + if (Status != 0 && Status != 0x80) + return false; + return BeginChs.Check() + && EndChs.Check() + // && CompareChs(BeginChs, EndChs) <= 0 + && NumBlocks > 0 + && CheckLbaLimits(); + } + + #ifdef SHOW_DEBUG_INFO + void Print() const + { + NCOM::CPropVariant prop, prop2; + BeginChs.ToString(prop); + EndChs.ToString(prop2); + printf(" %2x %2x %8X %8X %12S %12S", (int)Status, (int)Type, Lba, NumBlocks, prop.bstrVal, prop2.bstrVal); + } + #endif +}; + +struct CPartType +{ + UInt32 Id; + const char *Ext; + const char *Name; +}; + +#define kFat "fat" + +/* +if we use "format" command in Windows 10 for existing partition: + - if we format to ExFAT, it sets type=7 + - if we format to UDF, it doesn't change type from previous value. +*/ + +static const unsigned kType_Windows_NTFS = 7; + +static const CPartType kPartTypes[] = +{ + { 0x01, kFat, "FAT12" }, + { 0x04, kFat, "FAT16 DOS 3.0+" }, + { 0x05, NULL, "Extended" }, + { 0x06, kFat, "FAT16 DOS 3.31+" }, + { 0x07, "ntfs", "NTFS" }, + { 0x0B, kFat, "FAT32" }, + { 0x0C, kFat, "FAT32-LBA" }, + { 0x0E, kFat, "FAT16-LBA" }, + { 0x0F, NULL, "Extended-LBA" }, + { 0x11, kFat, "FAT12-Hidden" }, + { 0x14, kFat, "FAT16-Hidden < 32 MB" }, + { 0x16, kFat, "FAT16-Hidden >= 32 MB" }, + { 0x1B, kFat, "FAT32-Hidden" }, + { 0x1C, kFat, "FAT32-LBA-Hidden" }, + { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" }, + { 0x27, "ntfs", "NTFS-WinRE" }, + { 0x82, NULL, "Solaris x86 / Linux swap" }, + { 0x83, NULL, "Linux" }, + { 0x8E, "lvm", "Linux LVM" }, + { 0xA5, NULL, "BSD slice" }, + { 0xBE, NULL, "Solaris 8 boot" }, + { 0xBF, NULL, "New Solaris x86" }, + { 0xC2, NULL, "Linux-Hidden" }, + { 0xC3, NULL, "Linux swap-Hidden" }, + { 0xEE, NULL, "GPT" }, + { 0xEE, NULL, "EFI" } +}; + +static int FindPartType(UInt32 type) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPartTypes); i++) + if (kPartTypes[i].Id == type) + return (int)i; + return -1; +} + +struct CItem +{ + bool IsReal; + bool IsPrim; + bool WasParsed; + const char *FileSystem; + UInt64 Size; + CPartition Part; + + CItem(): + WasParsed(false), + FileSystem(NULL) + {} +}; + + +Z7_class_CHandler_final: public CHandlerCont +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + CObjectVector _items; + UInt64 _totalSize; + CByteBuffer _buffer; + + UInt32 _signature; + unsigned _sectorSizeLog; + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override Z7_final + { + const CItem &item = _items[index]; + pos = item.Part.GetPos(_sectorSizeLog); + size = item.Size; + return NExtract::NOperationResult::kOK; + } + + HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level); +}; + +/* +static bool IsEmptyBuffer(const Byte *data, size_t size) +{ + for (unsigned i = 0; i < size; i++) + if (data[i] != 0) + return false; + return true; +} +*/ + +const char *GetFileSystem(ISequentialInStream *stream, UInt64 partitionSize); + +HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level) +{ + if (level >= 128 || _items.Size() >= 128) + return S_FALSE; + + const unsigned kNumHeaderParts = 4; + CPartition parts[kNumHeaderParts]; + + if (level == 0) + _sectorSizeLog = 9; + const UInt32 kSectorSize = (UInt32)1 << _sectorSizeLog; + UInt32 bufSize = kSectorSize; + if (level == 0 && _totalSize >= (1 << 12)) + bufSize = (1 << 12); + _buffer.Alloc(bufSize); + { + Byte *buf = _buffer; + const UInt64 newPos = (UInt64)lba << _sectorSizeLog; + if (newPos + bufSize > _totalSize) + return S_FALSE; + RINOK(InStream_SeekSet(stream, newPos)) + RINOK(ReadStream_FALSE(stream, buf, bufSize)) + if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA) + return S_FALSE; + if (level == 0) + _signature = GetUi32(buf + 0x1B8); + for (unsigned i = 0; i < kNumHeaderParts; i++) + if (!parts[i].Parse(buf + 0x1BE + 16 * i)) + return S_FALSE; + } + + // 23.02: now we try to detect 4kn format (4 KB sectors case) + if (level == 0) + // if (_totalSize >= (1 << 28)) // we don't expect small images with 4 KB sectors + if (bufSize >= (1 << 12)) + { + UInt32 lastLim = 0; + UInt32 firstLba = 0; + UInt32 numBlocks = 0; // in first partition + for (unsigned i = 0; i < kNumHeaderParts; i++) + { + const CPartition &part = parts[i]; + if (part.IsEmpty()) + continue; + if (firstLba == 0 && part.NumBlocks != 0) + { + firstLba = part.Lba; + numBlocks = part.NumBlocks; + } + const UInt32 newLim = part.GetLimit(); + if (newLim < lastLim) + return S_FALSE; + lastLim = newLim; + } + if (lastLim != 0) + { + const UInt64 lim12 = (UInt64)lastLim << 12; + if (lim12 <= _totalSize + // && _totalSize - lim12 < (1 << 28) // we can try to exclude false positive cases + ) + // if (IsEmptyBuffer(&_buffer[(1 << 9)], (1 << 12) - (1 << 9))) + if (InStream_SeekSet(stream, (UInt64)firstLba << 12) == S_OK) + if (GetFileSystem(stream, (UInt64)numBlocks << 12)) + _sectorSizeLog = 12; + } + } + + PRF(printf("\n# %8X", lba)); + + UInt32 limLba = lba + 1; + if (limLba == 0) + return S_FALSE; + + for (unsigned i = 0; i < kNumHeaderParts; i++) + { + CPartition &part = parts[i]; + + if (part.IsEmpty()) + continue; + PRF(printf("\n %2d ", (unsigned)level)); + #ifdef SHOW_DEBUG_INFO + part.Print(); + #endif + + unsigned numItems = _items.Size(); + UInt32 newLba = lba + part.Lba; + + if (part.IsExtended()) + { + // if (part.Type == 5) // Check it! + newLba = baseLba + part.Lba; + if (newLba < limLba) + return S_FALSE; + const HRESULT res = ReadTables(stream, level < 1 ? newLba : baseLba, newLba, level + 1); + if (res != S_FALSE && res != S_OK) + return res; + } + if (newLba < limLba) + return S_FALSE; + part.Lba = newLba; + if (!part.CheckLbaLimits()) + return S_FALSE; + + CItem n; + n.Part = part; + bool addItem = false; + if (numItems == _items.Size()) + { + n.IsPrim = (level == 0); + n.IsReal = true; + addItem = true; + } + else + { + const CItem &back = _items.Back(); + const UInt32 backLimit = back.Part.GetLimit(); + const UInt32 partLimit = part.GetLimit(); + if (backLimit < partLimit) + { + n.IsReal = false; + n.Part.Lba = backLimit; + n.Part.NumBlocks = partLimit - backLimit; + addItem = true; + } + } + if (addItem) + { + if (n.Part.GetLimit() < limLba) + return S_FALSE; + limLba = n.Part.GetLimit(); + n.Size = n.Part.GetSize(_sectorSizeLog); + _items.Add(n); + } + } + return S_OK; +} + + +static const Byte k_Ntfs_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }; + +static bool Is_Ntfs(const Byte *p) +{ + if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) + return false; + switch (p[0]) + { + case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break; + case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break; + default: return false; + } + return memcmp(p + 3, k_Ntfs_Signature, Z7_ARRAY_SIZE(k_Ntfs_Signature)) == 0; +} + +static const Byte k_ExFat_Signature[] = { 'E', 'X', 'F', 'A', 'T', ' ', ' ', ' ' }; + +static bool Is_ExFat(const Byte *p) +{ + if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) + return false; + if (p[0] != 0xEB || p[1] != 0x76 || p[2] != 0x90) + return false; + return memcmp(p + 3, k_ExFat_Signature, Z7_ARRAY_SIZE(k_ExFat_Signature)) == 0; +} + +static bool AllAreZeros(const Byte *p, size_t size) +{ + for (size_t i = 0; i < size; i++) + if (p[i] != 0) + return false; + return true; +} + +static const UInt32 k_Udf_StartPos = 0x8000; +static const Byte k_Udf_Signature[] = { 0, 'B', 'E', 'A', '0', '1', 1, 0 }; + +static bool Is_Udf(const Byte *p) +{ + return memcmp(p + k_Udf_StartPos, k_Udf_Signature, sizeof(k_Udf_Signature)) == 0; +} + + +const char *GetFileSystem(ISequentialInStream *stream, UInt64 partitionSize) +{ + const size_t kHeaderSize = 1 << 9; + if (partitionSize >= kHeaderSize) + { + Byte buf[kHeaderSize]; + if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK) + { + // NTFS is expected default filesystem for (Type == 7) + if (Is_Ntfs(buf)) + return "NTFS"; + if (Is_ExFat(buf)) + return "exFAT"; + if (NFat::IsArc_Fat(buf, kHeaderSize)) + return "FAT"; + const size_t kHeaderSize2 = k_Udf_StartPos + (1 << 9); + if (partitionSize >= kHeaderSize2) + { + if (AllAreZeros(buf, kHeaderSize)) + { + CByteBuffer buffer(kHeaderSize2); + // memcpy(buffer, buf, kHeaderSize); + if (ReadStream_FAIL(stream, buffer + kHeaderSize, kHeaderSize2 - kHeaderSize) == S_OK) + if (Is_Udf(buffer)) + return "UDF"; + } + } + } + } + return NULL; +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + RINOK(InStream_GetSize_SeekToEnd(stream, _totalSize)) + RINOK(ReadTables(stream, 0, 0, 0)) + if (_items.IsEmpty()) + return S_FALSE; + { + const UInt32 lbaLimit = _items.Back().Part.GetLimit(); + const UInt64 lim = (UInt64)lbaLimit << _sectorSizeLog; + if (lim < _totalSize) + { + CItem n; + n.Part.Lba = lbaLimit; + n.Size = _totalSize - lim; + n.IsReal = false; + _items.Add(n); + } + } + + FOR_VECTOR (i, _items) + { + CItem &item = _items[i]; + if (item.Part.Type != kType_Windows_NTFS) + continue; + if (InStream_SeekSet(stream, item.Part.GetPos(_sectorSizeLog)) != S_OK) + continue; + item.FileSystem = GetFileSystem(stream, item.Size); + item.WasParsed = true; + } + + _stream = stream; + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + _items.Clear(); + _stream.Release(); + return S_OK; +} + + +enum +{ + kpidPrimary = kpidUserDefined, + kpidBegChs, + kpidEndChs +}; + +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidFileSystem, VT_BSTR}, + { NULL, kpidOffset, VT_UI8}, + { "Primary", kpidPrimary, VT_BOOL}, + { "Begin CHS", kpidBegChs, VT_BSTR}, + { "End CHS", kpidEndChs, VT_BSTR} +}; + +static const Byte kArcProps[] = +{ + kpidSectorSize, + kpidId +}; + +IMP_IInArchive_Props_WITH_NAME +IMP_IInArchive_ArcProps + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: + { + int mainIndex = -1; + FOR_VECTOR (i, _items) + if (_items[i].IsReal) + { + if (mainIndex >= 0) + { + mainIndex = -1; + break; + } + mainIndex = (int)i; + } + if (mainIndex >= 0) + prop = (UInt32)(Int32)mainIndex; + break; + } + case kpidPhySize: prop = _totalSize; break; + case kpidSectorSize: prop = (UInt32)((UInt32)1 << _sectorSizeLog); break; + case kpidId: prop = _signature; break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CItem &item = _items[index]; + const CPartition &part = item.Part; + switch (propID) + { + case kpidPath: + { + AString s; + s.Add_UInt32(index); + if (item.IsReal) + { + s.Add_Dot(); + const char *ext = NULL; + if (item.FileSystem) + { + ext = ""; + AString fs (item.FileSystem); + fs.MakeLower_Ascii(); + s += fs; + } + else if (!item.WasParsed) + { + const int typeIndex = FindPartType(part.Type); + if (typeIndex >= 0) + ext = kPartTypes[(unsigned)typeIndex].Ext; + } + if (!ext) + ext = "img"; + s += ext; + } + prop = s; + break; + } + case kpidFileSystem: + if (item.IsReal) + { + char s[32]; + ConvertUInt32ToString(part.Type, s); + const char *res = s; + if (item.FileSystem) + { + // strcat(s, "-"); + // strcpy(s, item.FileSystem); + res = item.FileSystem; + } + else if (!item.WasParsed) + { + const int typeIndex = FindPartType(part.Type); + if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Name) + res = kPartTypes[(unsigned)typeIndex].Name; + } + prop = res; + } + break; + case kpidSize: + case kpidPackSize: prop = item.Size; break; + case kpidOffset: prop = part.GetPos(_sectorSizeLog); break; + case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break; + case kpidBegChs: if (item.IsReal) part.BeginChs.ToString(prop); break; + case kpidEndChs: if (item.IsReal) part.EndChs.ToString(prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + + // 3, { 1, 1, 0 }, + // 2, { 0x55, 0x1FF }, + +REGISTER_ARC_I_NO_SIG( + "MBR", "mbr", NULL, 0xDB, + 0, + NArcInfoFlags::kPureStartOpen, + NULL) + +}} diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp index 04e341994..daf58bdf9 100644 --- a/CPP/7zip/Archive/MslzHandler.cpp +++ b/CPP/7zip/Archive/MslzHandler.cpp @@ -1,389 +1,389 @@ -// MslzHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/InBuffer.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "Common/DummyOutStream.h" - -namespace NArchive { -namespace NMslz { - -static const UInt32 kUnpackSizeMax = 0xFFFFFFE0; - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IArchiveOpenSeq -) - CMyComPtr _inStream; - CMyComPtr _seqStream; - - bool _isArc; - bool _needSeekToStart; - bool _dataAfterEnd; - bool _needMoreInput; - - bool _packSize_Defined; - bool _unpackSize_Defined; - - UInt32 _unpackSize; - UInt64 _packSize; - UInt64 _originalFileSize; - UString _name; - - void ParseName(Byte replaceByte, IArchiveOpenCallback *callback); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidExtension: prop = "mslz"; break; - case kpidIsNotArcType: prop = true; break; - case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPath: if (!_name.IsEmpty()) prop = _name; break; - case kpidSize: if (_unpackSize_Defined || _inStream) prop = _unpackSize; break; - case kpidPackSize: if (_packSize_Defined || _inStream) prop = _packSize; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -static const unsigned kSignatureSize = 9; -static const unsigned kHeaderSize = kSignatureSize + 1 + 4; -#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 } -// old signature: 53 5A 20 88 F0 27 33 -static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE; - -// we support only 3 chars strings here -static const char * const g_Exts[] = -{ - "bin" - , "dll" - , "exe" - , "kmd" - , "pdf" - , "sys" -}; - -void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback) -{ - if (!callback) - return; - Z7_DECL_CMyComPtr_QI_FROM(IArchiveOpenVolumeCallback, volumeCallback, callback) - if (!volumeCallback) - return; - - NWindows::NCOM::CPropVariant prop; - if (volumeCallback->GetProperty(kpidName, &prop) != S_OK || prop.vt != VT_BSTR) - return; - - UString s = prop.bstrVal; - if (s.IsEmpty() || - s.Back() != L'_') - return; - - s.DeleteBack(); - _name = s; - - if (replaceByte == 0) - { - if (s.Len() < 3 || s[s.Len() - 3] != '.') - return; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exts); i++) - { - const char *ext = g_Exts[i]; - if (s[s.Len() - 2] == (Byte)ext[0] && - s[s.Len() - 1] == (Byte)ext[1]) - { - replaceByte = (Byte)ext[2]; - break; - } - } - } - - if (replaceByte >= 0x20 && replaceByte < 0x80) - _name.Add_Char((char)replaceByte); -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - _needSeekToStart = true; - Byte buffer[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize)) - if (memcmp(buffer, kSignature, kSignatureSize) != 0) - return S_FALSE; - _unpackSize = GetUi32(buffer + 10); - if (_unpackSize > kUnpackSizeMax) - return S_FALSE; - RINOK(InStream_GetSize_SeekToEnd(stream, _originalFileSize)) - _packSize = _originalFileSize; - - ParseName(buffer[kSignatureSize], callback); - - _isArc = true; - _unpackSize_Defined = true; - _inStream = stream; - _seqStream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _originalFileSize = 0; - _packSize = 0; - _unpackSize = 0; - - _isArc = false; - _needSeekToStart = false; - _dataAfterEnd = false; - _needMoreInput = false; - - _packSize_Defined = false; - _unpackSize_Defined = false; - - _seqStream.Release(); - _inStream.Release(); - _name.Empty(); - return S_OK; -} - -// MslzDec is modified LZSS algorithm of Haruhiko Okumura: -// maxLen = 18; Okumura -// maxLen = 16; MS - -#define PROGRESS_AND_WRITE \ - if ((dest & kMask) == 0) { if (outStream) RINOK(WriteStream(outStream, buf, kBufSize)); \ - if ((dest & ((1 << 20) - 1)) == 0) \ - if (progress) \ - { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \ - RINOK(progress->SetRatioInfo(&inSize, &outSize)); }} - -static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, bool &needMoreData, ICompressProgressInfo *progress) -{ - const unsigned kBufSize = (1 << 12); - const unsigned kMask = kBufSize - 1; - Byte buf[kBufSize]; - UInt32 dest = 0; - memset(buf, ' ', kBufSize); - - while (dest < unpackSize) - { - Byte b; - if (!inStream.ReadByte(b)) - { - needMoreData = true; - return S_FALSE; - } - - for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1) - { - if (!inStream.ReadByte(b)) - { - needMoreData = true; - return S_FALSE; - } - - if (mask & 1) - { - buf[dest++ & kMask] = b; - PROGRESS_AND_WRITE - } - else - { - Byte b1; - if (!inStream.ReadByte(b1)) - { - needMoreData = true; - return S_FALSE; - } - const unsigned kMaxLen = 16; // 18 in Okumura's code. - unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask; - unsigned len = (b1 & 0xF) + 3; - if (len > kMaxLen || dest + len > unpackSize) - return S_FALSE; - - do - { - buf[dest++ & kMask] = buf[src++ & kMask]; - PROGRESS_AND_WRITE - } - while (--len != 0); - } - } - } - - if (outStream) - RINOK(WriteStream(outStream, buf, dest & kMask)) - return S_OK; -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - COM_TRY_BEGIN - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - // RINOK(extractCallback->SetTotal(_unpackSize)) - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(); - // realOutStream.Release(); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - if (_needSeekToStart) - { - if (!_inStream) - return E_FAIL; - RINOK(InStream_SeekToBegin(_inStream)) - } - else - _needSeekToStart = true; - - opRes = NExtract::NOperationResult::kDataError; - - bool isArc = false; - bool needMoreInput = false; - try - { - CInBuffer s; - if (!s.Create(1 << 20)) - return E_OUTOFMEMORY; - s.SetStream(_seqStream); - s.Init(); - - Byte buffer[kHeaderSize]; - if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize) - { - UInt32 unpackSize; - if (memcmp(buffer, kSignature, kSignatureSize) == 0) - { - unpackSize = GetUi32(buffer + 10); - if (unpackSize <= kUnpackSizeMax) - { - const HRESULT result = MslzDec(s, outStream, unpackSize, needMoreInput, lps); - if (result == S_OK) - opRes = NExtract::NOperationResult::kOK; - else if (result != S_FALSE) - return result; - _unpackSize = unpackSize; - _unpackSize_Defined = true; - - _packSize = s.GetProcessedSize(); - _packSize_Defined = true; - - if (_inStream && _packSize < _originalFileSize) - _dataAfterEnd = true; - - isArc = true; - } - } - } - } - catch (CInBufferException &e) { return e.ErrorCode; } - - _isArc = isArc; - if (isArc) - _needMoreInput = needMoreInput; - if (!_isArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (_needMoreInput) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (_dataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - } - return extractCallback->SetOperationResult(opRes); - COM_TRY_END -} - -REGISTER_ARC_I( - "MsLZ", "mslz", NULL, 0xD5, - kSignature, - 0, - 0, - NULL) - -}} +// MslzHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/InBuffer.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "Common/DummyOutStream.h" + +namespace NArchive { +namespace NMslz { + +static const UInt32 kUnpackSizeMax = 0xFFFFFFE0; + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IArchiveOpenSeq +) + CMyComPtr _inStream; + CMyComPtr _seqStream; + + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + + UInt32 _unpackSize; + UInt64 _packSize; + UInt64 _originalFileSize; + UString _name; + + void ParseName(Byte replaceByte, IArchiveOpenCallback *callback); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidExtension: prop = "mslz"; break; + case kpidIsNotArcType: prop = true; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPath: if (!_name.IsEmpty()) prop = _name; break; + case kpidSize: if (_unpackSize_Defined || _inStream) prop = _unpackSize; break; + case kpidPackSize: if (_packSize_Defined || _inStream) prop = _packSize; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static const unsigned kSignatureSize = 9; +static const unsigned kHeaderSize = kSignatureSize + 1 + 4; +#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 } +// old signature: 53 5A 20 88 F0 27 33 +static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE; + +// we support only 3 chars strings here +static const char * const g_Exts[] = +{ + "bin" + , "dll" + , "exe" + , "kmd" + , "pdf" + , "sys" +}; + +void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback) +{ + if (!callback) + return; + Z7_DECL_CMyComPtr_QI_FROM(IArchiveOpenVolumeCallback, volumeCallback, callback) + if (!volumeCallback) + return; + + NWindows::NCOM::CPropVariant prop; + if (volumeCallback->GetProperty(kpidName, &prop) != S_OK || prop.vt != VT_BSTR) + return; + + UString s = prop.bstrVal; + if (s.IsEmpty() || + s.Back() != L'_') + return; + + s.DeleteBack(); + _name = s; + + if (replaceByte == 0) + { + if (s.Len() < 3 || s[s.Len() - 3] != '.') + return; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exts); i++) + { + const char *ext = g_Exts[i]; + if (s[s.Len() - 2] == (Byte)ext[0] && + s[s.Len() - 1] == (Byte)ext[1]) + { + replaceByte = (Byte)ext[2]; + break; + } + } + } + + if (replaceByte >= 0x20 && replaceByte < 0x80) + _name.Add_Char((char)replaceByte); +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + _needSeekToStart = true; + Byte buffer[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize)) + if (memcmp(buffer, kSignature, kSignatureSize) != 0) + return S_FALSE; + _unpackSize = GetUi32(buffer + 10); + if (_unpackSize > kUnpackSizeMax) + return S_FALSE; + RINOK(InStream_GetSize_SeekToEnd(stream, _originalFileSize)) + _packSize = _originalFileSize; + + ParseName(buffer[kSignatureSize], callback); + + _isArc = true; + _unpackSize_Defined = true; + _inStream = stream; + _seqStream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _originalFileSize = 0; + _packSize = 0; + _unpackSize = 0; + + _isArc = false; + _needSeekToStart = false; + _dataAfterEnd = false; + _needMoreInput = false; + + _packSize_Defined = false; + _unpackSize_Defined = false; + + _seqStream.Release(); + _inStream.Release(); + _name.Empty(); + return S_OK; +} + +// MslzDec is modified LZSS algorithm of Haruhiko Okumura: +// maxLen = 18; Okumura +// maxLen = 16; MS + +#define PROGRESS_AND_WRITE \ + if ((dest & kMask) == 0) { if (outStream) RINOK(WriteStream(outStream, buf, kBufSize)); \ + if ((dest & ((1 << 20) - 1)) == 0) \ + if (progress) \ + { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \ + RINOK(progress->SetRatioInfo(&inSize, &outSize)); }} + +static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, bool &needMoreData, ICompressProgressInfo *progress) +{ + const unsigned kBufSize = (1 << 12); + const unsigned kMask = kBufSize - 1; + Byte buf[kBufSize]; + UInt32 dest = 0; + memset(buf, ' ', kBufSize); + + while (dest < unpackSize) + { + Byte b; + if (!inStream.ReadByte(b)) + { + needMoreData = true; + return S_FALSE; + } + + for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1) + { + if (!inStream.ReadByte(b)) + { + needMoreData = true; + return S_FALSE; + } + + if (mask & 1) + { + buf[dest++ & kMask] = b; + PROGRESS_AND_WRITE + } + else + { + Byte b1; + if (!inStream.ReadByte(b1)) + { + needMoreData = true; + return S_FALSE; + } + const unsigned kMaxLen = 16; // 18 in Okumura's code. + unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask; + unsigned len = (b1 & 0xF) + 3; + if (len > kMaxLen || dest + len > unpackSize) + return S_FALSE; + + do + { + buf[dest++ & kMask] = buf[src++ & kMask]; + PROGRESS_AND_WRITE + } + while (--len != 0); + } + } + } + + if (outStream) + RINOK(WriteStream(outStream, buf, dest & kMask)) + return S_OK; +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + COM_TRY_BEGIN + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + // RINOK(extractCallback->SetTotal(_unpackSize)) + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(); + // realOutStream.Release(); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + if (_needSeekToStart) + { + if (!_inStream) + return E_FAIL; + RINOK(InStream_SeekToBegin(_inStream)) + } + else + _needSeekToStart = true; + + opRes = NExtract::NOperationResult::kDataError; + + bool isArc = false; + bool needMoreInput = false; + try + { + CInBuffer s; + if (!s.Create(1 << 20)) + return E_OUTOFMEMORY; + s.SetStream(_seqStream); + s.Init(); + + Byte buffer[kHeaderSize]; + if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize) + { + UInt32 unpackSize; + if (memcmp(buffer, kSignature, kSignatureSize) == 0) + { + unpackSize = GetUi32(buffer + 10); + if (unpackSize <= kUnpackSizeMax) + { + const HRESULT result = MslzDec(s, outStream, unpackSize, needMoreInput, lps); + if (result == S_OK) + opRes = NExtract::NOperationResult::kOK; + else if (result != S_FALSE) + return result; + _unpackSize = unpackSize; + _unpackSize_Defined = true; + + _packSize = s.GetProcessedSize(); + _packSize_Defined = true; + + if (_inStream && _packSize < _originalFileSize) + _dataAfterEnd = true; + + isArc = true; + } + } + } + } + catch (CInBufferException &e) { return e.ErrorCode; } + + _isArc = isArc; + if (isArc) + _needMoreInput = needMoreInput; + if (!_isArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (_dataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + } + return extractCallback->SetOperationResult(opRes); + COM_TRY_END +} + +REGISTER_ARC_I( + "MsLZ", "mslz", NULL, 0xD5, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp index 7c35a647f..7363b1b31 100644 --- a/CPP/7zip/Archive/MubHandler.cpp +++ b/CPP/7zip/Archive/MubHandler.cpp @@ -1,262 +1,262 @@ -// MubHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/SwapBytes.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -using namespace NWindows; -using namespace NCOM; - -namespace NArchive { -namespace NMub { - -#define MACH_CPU_ARCH_ABI64 ((UInt32)1 << 24) -#define MACH_CPU_TYPE_386 7 -#define MACH_CPU_TYPE_ARM 12 -#define MACH_CPU_TYPE_SPARC 14 -#define MACH_CPU_TYPE_PPC 18 - -#define MACH_CPU_TYPE_PPC64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_PPC) -#define MACH_CPU_TYPE_AMD64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_386) -#define MACH_CPU_TYPE_ARM64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_ARM) - -#define MACH_CPU_SUBTYPE_LIB64 ((UInt32)1 << 31) - -#define MACH_CPU_SUBTYPE_I386_ALL 3 - -struct CItem -{ - UInt32 Type; - UInt32 SubType; - UInt32 Offset; - UInt32 Size; - UInt32 Align; -}; - -static const UInt32 kNumFilesMax = 6; - -Z7_class_CHandler_final: public CHandlerCont -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - // UInt64 _startPos; - UInt64 _phySize; - UInt32 _numItems; - bool _bigEndian; - CItem _items[kNumFilesMax]; - - HRESULT Open2(IInStream *stream); - - virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override - { - const CItem &item = _items[index]; - pos = item.Offset; - size = item.Size; - return NExtract::NOperationResult::kOK; - } -}; - -static const Byte kArcProps[] = -{ - kpidBigEndian -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidOffset, - kpidClusterSize // Align -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - PropVariant_Clear(value); - switch (propID) - { - case kpidBigEndian: PropVarEm_Set_Bool(value, _bigEndian); break; - case kpidPhySize: PropVarEm_Set_UInt64(value, _phySize); break; - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - PropVariant_Clear(value); - const CItem &item = _items[index]; - switch (propID) - { - case kpidExtension: - { - char temp[32]; - const char *ext = NULL; - switch (item.Type) - { - case MACH_CPU_TYPE_386: ext = "x86"; break; - case MACH_CPU_TYPE_ARM: ext = "arm"; break; - case MACH_CPU_TYPE_SPARC: ext = "sparc"; break; - case MACH_CPU_TYPE_PPC: ext = "ppc"; break; - case MACH_CPU_TYPE_AMD64: ext = "x64"; break; - case MACH_CPU_TYPE_ARM64: ext = "arm64"; break; - case MACH_CPU_TYPE_PPC64: ext = "ppc64"; break; - default: - temp[0] = 'c'; - temp[1] = 'p'; - temp[2] = 'u'; - char *p = ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3); - if (item.Type & MACH_CPU_ARCH_ABI64) - MyStringCopy(p, "_64"); - break; - } - if (ext) - MyStringCopy(temp, ext); - if (item.SubType != 0) - if ((item.Type != MACH_CPU_TYPE_386 && - item.Type != MACH_CPU_TYPE_AMD64) - || (item.SubType & ~(UInt32)MACH_CPU_SUBTYPE_LIB64) != MACH_CPU_SUBTYPE_I386_ALL - ) - { - unsigned pos = MyStringLen(temp); - temp[pos++] = '-'; - ConvertUInt32ToString(item.SubType, temp + pos); - } - return PropVarEm_Set_Str(value, temp); - } - case kpidSize: - case kpidPackSize: - PropVarEm_Set_UInt64(value, item.Size); - break; - case kpidOffset: - PropVarEm_Set_UInt64(value, item.Offset); - break; - case kpidClusterSize: - PropVarEm_Set_UInt32(value, (UInt32)1 << item.Align); - break; - } - return S_OK; -} - -HRESULT CHandler::Open2(IInStream *stream) -{ - // RINOK(InStream_GetPos(stream, _startPos)); - - const UInt32 kHeaderSize = 2; - const UInt32 kRecordSize = 5; - const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize; - UInt32 buf[kBufSize]; - size_t processed = kBufSize * 4; - RINOK(ReadStream(stream, buf, &processed)) - processed >>= 2; - if (processed < kHeaderSize) - return S_FALSE; - - bool be; - switch (buf[0]) - { - case Z7_CONV_BE_TO_NATIVE_CONST32(0xCAFEBABE): be = true; break; - case Z7_CONV_BE_TO_NATIVE_CONST32(0xB9FAF10E): be = false; break; - default: return S_FALSE; - } - _bigEndian = be; - if ( - #if defined(MY_CPU_BE) - ! - #endif - be) - z7_SwapBytes4(&buf[1], processed - 1); - const UInt32 num = buf[1]; - if (num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize) - return S_FALSE; - if (num == 0) - return S_FALSE; - UInt64 endPosMax = kHeaderSize; - - for (UInt32 i = 0; i < num; i++) - { - const UInt32 *p = buf + kHeaderSize + i * kRecordSize; - CItem &sb = _items[i]; - sb.Type = p[0]; - sb.SubType = p[1]; - sb.Offset = p[2]; - sb.Size = p[3]; - const UInt32 align = p[4]; - sb.Align = align; - if (align > 31) - return S_FALSE; - if (sb.Offset < kHeaderSize + num * kRecordSize) - return S_FALSE; - if ((sb.Type & ~MACH_CPU_ARCH_ABI64) >= 0x100 || - (sb.SubType & ~MACH_CPU_SUBTYPE_LIB64) >= 0x100) - return S_FALSE; - - const UInt64 endPos = (UInt64)sb.Offset + sb.Size; - if (endPosMax < endPos) - endPosMax = endPos; - } - _numItems = num; - _phySize = endPosMax; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - try - { - if (Open2(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _stream.Release(); - _numItems = 0; - _phySize = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _numItems; - return S_OK; -} - -namespace NBe { - -static const Byte k_Signature[] = { - 7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0, - 4, 0xB9, 0xFA, 0xF1, 0x0E }; - -REGISTER_ARC_I( - "Mub", "mub", NULL, 0xE2, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - NULL) - -} - -}} +// MubHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/SwapBytes.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +using namespace NWindows; +using namespace NCOM; + +namespace NArchive { +namespace NMub { + +#define MACH_CPU_ARCH_ABI64 ((UInt32)1 << 24) +#define MACH_CPU_TYPE_386 7 +#define MACH_CPU_TYPE_ARM 12 +#define MACH_CPU_TYPE_SPARC 14 +#define MACH_CPU_TYPE_PPC 18 + +#define MACH_CPU_TYPE_PPC64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_PPC) +#define MACH_CPU_TYPE_AMD64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_386) +#define MACH_CPU_TYPE_ARM64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_ARM) + +#define MACH_CPU_SUBTYPE_LIB64 ((UInt32)1 << 31) + +#define MACH_CPU_SUBTYPE_I386_ALL 3 + +struct CItem +{ + UInt32 Type; + UInt32 SubType; + UInt32 Offset; + UInt32 Size; + UInt32 Align; +}; + +static const UInt32 kNumFilesMax = 6; + +Z7_class_CHandler_final: public CHandlerCont +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + // UInt64 _startPos; + UInt64 _phySize; + UInt32 _numItems; + bool _bigEndian; + CItem _items[kNumFilesMax]; + + HRESULT Open2(IInStream *stream); + + virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override + { + const CItem &item = _items[index]; + pos = item.Offset; + size = item.Size; + return NExtract::NOperationResult::kOK; + } +}; + +static const Byte kArcProps[] = +{ + kpidBigEndian +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidOffset, + kpidClusterSize // Align +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + PropVariant_Clear(value); + switch (propID) + { + case kpidBigEndian: PropVarEm_Set_Bool(value, _bigEndian); break; + case kpidPhySize: PropVarEm_Set_UInt64(value, _phySize); break; + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + PropVariant_Clear(value); + const CItem &item = _items[index]; + switch (propID) + { + case kpidExtension: + { + char temp[32]; + const char *ext = NULL; + switch (item.Type) + { + case MACH_CPU_TYPE_386: ext = "x86"; break; + case MACH_CPU_TYPE_ARM: ext = "arm"; break; + case MACH_CPU_TYPE_SPARC: ext = "sparc"; break; + case MACH_CPU_TYPE_PPC: ext = "ppc"; break; + case MACH_CPU_TYPE_AMD64: ext = "x64"; break; + case MACH_CPU_TYPE_ARM64: ext = "arm64"; break; + case MACH_CPU_TYPE_PPC64: ext = "ppc64"; break; + default: + temp[0] = 'c'; + temp[1] = 'p'; + temp[2] = 'u'; + char *p = ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3); + if (item.Type & MACH_CPU_ARCH_ABI64) + MyStringCopy(p, "_64"); + break; + } + if (ext) + MyStringCopy(temp, ext); + if (item.SubType != 0) + if ((item.Type != MACH_CPU_TYPE_386 && + item.Type != MACH_CPU_TYPE_AMD64) + || (item.SubType & ~(UInt32)MACH_CPU_SUBTYPE_LIB64) != MACH_CPU_SUBTYPE_I386_ALL + ) + { + unsigned pos = MyStringLen(temp); + temp[pos++] = '-'; + ConvertUInt32ToString(item.SubType, temp + pos); + } + return PropVarEm_Set_Str(value, temp); + } + case kpidSize: + case kpidPackSize: + PropVarEm_Set_UInt64(value, item.Size); + break; + case kpidOffset: + PropVarEm_Set_UInt64(value, item.Offset); + break; + case kpidClusterSize: + PropVarEm_Set_UInt32(value, (UInt32)1 << item.Align); + break; + } + return S_OK; +} + +HRESULT CHandler::Open2(IInStream *stream) +{ + // RINOK(InStream_GetPos(stream, _startPos)); + + const UInt32 kHeaderSize = 2; + const UInt32 kRecordSize = 5; + const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize; + UInt32 buf[kBufSize]; + size_t processed = kBufSize * 4; + RINOK(ReadStream(stream, buf, &processed)) + processed >>= 2; + if (processed < kHeaderSize) + return S_FALSE; + + bool be; + switch (buf[0]) + { + case Z7_CONV_BE_TO_NATIVE_CONST32(0xCAFEBABE): be = true; break; + case Z7_CONV_BE_TO_NATIVE_CONST32(0xB9FAF10E): be = false; break; + default: return S_FALSE; + } + _bigEndian = be; + if ( + #if defined(MY_CPU_BE) + ! + #endif + be) + z7_SwapBytes4(&buf[1], processed - 1); + const UInt32 num = buf[1]; + if (num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize) + return S_FALSE; + if (num == 0) + return S_FALSE; + UInt64 endPosMax = kHeaderSize; + + for (UInt32 i = 0; i < num; i++) + { + const UInt32 *p = buf + kHeaderSize + i * kRecordSize; + CItem &sb = _items[i]; + sb.Type = p[0]; + sb.SubType = p[1]; + sb.Offset = p[2]; + sb.Size = p[3]; + const UInt32 align = p[4]; + sb.Align = align; + if (align > 31) + return S_FALSE; + if (sb.Offset < kHeaderSize + num * kRecordSize) + return S_FALSE; + if ((sb.Type & ~MACH_CPU_ARCH_ABI64) >= 0x100 || + (sb.SubType & ~MACH_CPU_SUBTYPE_LIB64) >= 0x100) + return S_FALSE; + + const UInt64 endPos = (UInt64)sb.Offset + sb.Size; + if (endPosMax < endPos) + endPosMax = endPos; + } + _numItems = num; + _phySize = endPosMax; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + try + { + if (Open2(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _stream.Release(); + _numItems = 0; + _phySize = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _numItems; + return S_OK; +} + +namespace NBe { + +static const Byte k_Signature[] = { + 7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0, + 4, 0xB9, 0xFA, 0xF1, 0x0E }; + +REGISTER_ARC_I( + "Mub", "mub", NULL, 0xE2, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + NULL) + +} + +}} diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp index 2fa490b90..044de37f3 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.cpp +++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp @@ -1,295 +1,295 @@ -// NsisDecode.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "NsisDecode.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/MethodId.h" - -#include "../../Compress/BcjCoder.h" - -#define Get32(p) GetUi32(p) - -namespace NArchive { -namespace NNsis { - -UInt64 CDecoder::GetInputProcessedSize() const -{ - if (_lzmaDecoder) - return _lzmaDecoder->GetInputProcessedSize(); - if (_deflateDecoder) - return _deflateDecoder->GetInputProcessedSize(); - if (_bzDecoder) - return _bzDecoder->GetInputProcessedSize(); - return 0; -} - - -HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) -{ - useFilter = false; - - if (_decoderInStream) - if (Method != _curMethod) - Release(); - _curMethod = Method; - - if (!_codecInStream) - { - switch ((int)Method) - { - // case NMethodType::kCopy: return E_NOTIMPL; - case NMethodType::kDeflate: - _deflateDecoder = new NCompress::NDeflate::NDecoder::CCOMCoder(); - _codecInStream = _deflateDecoder; - break; - case NMethodType::kBZip2: - _bzDecoder = new NCompress::NBZip2::CNsisDecoder(); - _codecInStream = _bzDecoder; - break; - case NMethodType::kLZMA: - _lzmaDecoder = new NCompress::NLzma::CDecoder(); - _codecInStream = _lzmaDecoder; - break; - default: return E_NOTIMPL; - } - } - - if (Method == NMethodType::kDeflate) - _deflateDecoder->SetNsisMode(IsNsisDeflate); - - if (FilterFlag) - { - Byte flag; - RINOK(ReadStream_FALSE(inStream, &flag, 1)) - if (flag > 1) - return E_NOTIMPL; - useFilter = (flag != 0); - } - - if (!useFilter) - _decoderInStream = _codecInStream; - else - { - if (!_filterInStream) - { - _filter = new CFilterCoder(false); - _filterInStream = _filter; - _filter->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec); - } - RINOK(_filter->SetInStream(_codecInStream)) - _decoderInStream = _filterInStream; - } - - if (Method == NMethodType::kLZMA) - { - const unsigned kPropsSize = LZMA_PROPS_SIZE; - Byte props[kPropsSize]; - RINOK(ReadStream_FALSE(inStream, props, kPropsSize)) - RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize)) - } - - { - CMyComPtr setInStream; - _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream); - if (!setInStream) - return E_NOTIMPL; - RINOK(setInStream->SetInStream(inStream)) - } - - { - CMyComPtr setOutStreamSize; - _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize); - if (!setOutStreamSize) - return E_NOTIMPL; - RINOK(setOutStreamSize->SetOutStreamSize(NULL)) - } - - if (useFilter) - { - RINOK(_filter->SetOutStreamSize(NULL)) - } - - return S_OK; -} - - -static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; - - -HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress) -{ - if (StreamPos > pos) - return E_FAIL; - const UInt64 inSizeStart = GetInputProcessedSize(); - UInt64 offset = 0; - while (StreamPos < pos) - { - size_t size = (size_t)MyMin(pos - StreamPos, (UInt64)Buffer.Size()); - RINOK(Read(Buffer, &size)) - if (size == 0) - return S_FALSE; - StreamPos += size; - offset += size; - - const UInt64 inSize = GetInputProcessedSize() - inSizeStart; - RINOK(progress->SetRatioInfo(&inSize, &offset)) - } - return S_OK; -} - - -HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, - ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, - UInt32 &packSizeRes, UInt32 &unpackSizeRes) -{ - CLimitedSequentialInStream *limitedStreamSpec = NULL; - CMyComPtr limitedStream; - packSizeRes = 0; - unpackSizeRes = 0; - - if (Solid) - { - Byte temp[4]; - size_t processedSize = 4; - RINOK(Read(temp, &processedSize)) - StreamPos += processedSize; - if (processedSize != 4) - return S_FALSE; - UInt32 size = Get32(temp); - if (unpackSizeDefined && size != unpackSize) - return S_FALSE; - unpackSize = size; - unpackSizeDefined = true; - } - else - { - Byte temp[4]; - { - size_t processedSize = 4; - RINOK(ReadStream(InputStream, temp, &processedSize)) - StreamPos += processedSize; - if (processedSize != 4) - return S_FALSE; - } - UInt32 size = Get32(temp); - - if ((size & kMask_IsCompressed) == 0) - { - if (unpackSizeDefined && size != unpackSize) - return S_FALSE; - packSizeRes = size; - if (outBuf) - outBuf->Alloc(size); - - UInt64 offset = 0; - - while (size > 0) - { - UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size()); - UInt32 processedSize; - RINOK(InputStream->Read(Buffer, curSize, &processedSize)) - if (processedSize == 0) - return S_FALSE; - if (outBuf) - memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize); - offset += processedSize; - size -= processedSize; - StreamPos += processedSize; - unpackSizeRes += processedSize; - if (realOutStream) - RINOK(WriteStream(realOutStream, Buffer, processedSize)) - RINOK(progress->SetRatioInfo(&offset, &offset)) - } - - return S_OK; - } - - size &= ~kMask_IsCompressed; - packSizeRes = size; - limitedStreamSpec = new CLimitedSequentialInStream; - limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(InputStream); - limitedStreamSpec->Init(size); - { - bool useFilter; - RINOK(Init(limitedStream, useFilter)) - } - } - - if (outBuf) - { - if (unpackSizeDefined) - outBuf->Alloc(unpackSize); - } - - const UInt64 inSizeStart = GetInputProcessedSize(); - - // we don't allow files larger than 4 GB; - if (!unpackSizeDefined) - unpackSize = 0xFFFFFFFF; - UInt32 offset = 0; - - HRESULT res = S_OK; - - for (;;) - { - size_t rem = unpackSize - offset; - if (rem == 0) - break; - size_t size = Buffer.Size(); - if (size > rem) - size = rem; - RINOK(Read(Buffer, &size)) - if (size == 0) - { - if (unpackSizeDefined) - res = S_FALSE; - break; - } - - if (outBuf) - { - size_t nextSize = offset + size; - if (outBuf->Size() < nextSize) - { - { - const size_t nextSize2 = outBuf->Size() * 2; - if (nextSize < nextSize2) - nextSize = nextSize2; - } - outBuf->ChangeSize_KeepData(nextSize, offset); - } - memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size); - } - - StreamPos += size; - offset += (UInt32)size; - - const UInt64 inSize = GetInputProcessedSize() - inSizeStart; - - if (Solid) - packSizeRes = (UInt32)inSize; - unpackSizeRes += (UInt32)size; - - UInt64 outSize = offset; - RINOK(progress->SetRatioInfo(&inSize, &outSize)) - if (realOutStream) - { - res = WriteStream(realOutStream, Buffer, size); - if (res != S_OK) - break; - } - } - - if (outBuf && offset != outBuf->Size()) - outBuf->ChangeSize_KeepData(offset, offset); - - return res; -} - -}} +// NsisDecode.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "NsisDecode.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/MethodId.h" + +#include "../../Compress/BcjCoder.h" + +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NNsis { + +UInt64 CDecoder::GetInputProcessedSize() const +{ + if (_lzmaDecoder) + return _lzmaDecoder->GetInputProcessedSize(); + if (_deflateDecoder) + return _deflateDecoder->GetInputProcessedSize(); + if (_bzDecoder) + return _bzDecoder->GetInputProcessedSize(); + return 0; +} + + +HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter) +{ + useFilter = false; + + if (_decoderInStream) + if (Method != _curMethod) + Release(); + _curMethod = Method; + + if (!_codecInStream) + { + switch ((int)Method) + { + // case NMethodType::kCopy: return E_NOTIMPL; + case NMethodType::kDeflate: + _deflateDecoder = new NCompress::NDeflate::NDecoder::CCOMCoder(); + _codecInStream = _deflateDecoder; + break; + case NMethodType::kBZip2: + _bzDecoder = new NCompress::NBZip2::CNsisDecoder(); + _codecInStream = _bzDecoder; + break; + case NMethodType::kLZMA: + _lzmaDecoder = new NCompress::NLzma::CDecoder(); + _codecInStream = _lzmaDecoder; + break; + default: return E_NOTIMPL; + } + } + + if (Method == NMethodType::kDeflate) + _deflateDecoder->SetNsisMode(IsNsisDeflate); + + if (FilterFlag) + { + Byte flag; + RINOK(ReadStream_FALSE(inStream, &flag, 1)) + if (flag > 1) + return E_NOTIMPL; + useFilter = (flag != 0); + } + + if (!useFilter) + _decoderInStream = _codecInStream; + else + { + if (!_filterInStream) + { + _filter = new CFilterCoder(false); + _filterInStream = _filter; + _filter->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec); + } + RINOK(_filter->SetInStream(_codecInStream)) + _decoderInStream = _filterInStream; + } + + if (Method == NMethodType::kLZMA) + { + const unsigned kPropsSize = LZMA_PROPS_SIZE; + Byte props[kPropsSize]; + RINOK(ReadStream_FALSE(inStream, props, kPropsSize)) + RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize)) + } + + { + CMyComPtr setInStream; + _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream); + if (!setInStream) + return E_NOTIMPL; + RINOK(setInStream->SetInStream(inStream)) + } + + { + CMyComPtr setOutStreamSize; + _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize); + if (!setOutStreamSize) + return E_NOTIMPL; + RINOK(setOutStreamSize->SetOutStreamSize(NULL)) + } + + if (useFilter) + { + RINOK(_filter->SetOutStreamSize(NULL)) + } + + return S_OK; +} + + +static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + + +HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress) +{ + if (StreamPos > pos) + return E_FAIL; + const UInt64 inSizeStart = GetInputProcessedSize(); + UInt64 offset = 0; + while (StreamPos < pos) + { + size_t size = (size_t)MyMin(pos - StreamPos, (UInt64)Buffer.Size()); + RINOK(Read(Buffer, &size)) + if (size == 0) + return S_FALSE; + StreamPos += size; + offset += size; + + const UInt64 inSize = GetInputProcessedSize() - inSizeStart; + RINOK(progress->SetRatioInfo(&inSize, &offset)) + } + return S_OK; +} + + +HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, + ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + UInt32 &packSizeRes, UInt32 &unpackSizeRes) +{ + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr limitedStream; + packSizeRes = 0; + unpackSizeRes = 0; + + if (Solid) + { + Byte temp[4]; + size_t processedSize = 4; + RINOK(Read(temp, &processedSize)) + StreamPos += processedSize; + if (processedSize != 4) + return S_FALSE; + UInt32 size = Get32(temp); + if (unpackSizeDefined && size != unpackSize) + return S_FALSE; + unpackSize = size; + unpackSizeDefined = true; + } + else + { + Byte temp[4]; + { + size_t processedSize = 4; + RINOK(ReadStream(InputStream, temp, &processedSize)) + StreamPos += processedSize; + if (processedSize != 4) + return S_FALSE; + } + UInt32 size = Get32(temp); + + if ((size & kMask_IsCompressed) == 0) + { + if (unpackSizeDefined && size != unpackSize) + return S_FALSE; + packSizeRes = size; + if (outBuf) + outBuf->Alloc(size); + + UInt64 offset = 0; + + while (size > 0) + { + UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size()); + UInt32 processedSize; + RINOK(InputStream->Read(Buffer, curSize, &processedSize)) + if (processedSize == 0) + return S_FALSE; + if (outBuf) + memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize); + offset += processedSize; + size -= processedSize; + StreamPos += processedSize; + unpackSizeRes += processedSize; + if (realOutStream) + RINOK(WriteStream(realOutStream, Buffer, processedSize)) + RINOK(progress->SetRatioInfo(&offset, &offset)) + } + + return S_OK; + } + + size &= ~kMask_IsCompressed; + packSizeRes = size; + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(InputStream); + limitedStreamSpec->Init(size); + { + bool useFilter; + RINOK(Init(limitedStream, useFilter)) + } + } + + if (outBuf) + { + if (unpackSizeDefined) + outBuf->Alloc(unpackSize); + } + + const UInt64 inSizeStart = GetInputProcessedSize(); + + // we don't allow files larger than 4 GB; + if (!unpackSizeDefined) + unpackSize = 0xFFFFFFFF; + UInt32 offset = 0; + + HRESULT res = S_OK; + + for (;;) + { + size_t rem = unpackSize - offset; + if (rem == 0) + break; + size_t size = Buffer.Size(); + if (size > rem) + size = rem; + RINOK(Read(Buffer, &size)) + if (size == 0) + { + if (unpackSizeDefined) + res = S_FALSE; + break; + } + + if (outBuf) + { + size_t nextSize = offset + size; + if (outBuf->Size() < nextSize) + { + { + const size_t nextSize2 = outBuf->Size() * 2; + if (nextSize < nextSize2) + nextSize = nextSize2; + } + outBuf->ChangeSize_KeepData(nextSize, offset); + } + memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size); + } + + StreamPos += size; + offset += (UInt32)size; + + const UInt64 inSize = GetInputProcessedSize() - inSizeStart; + + if (Solid) + packSizeRes = (UInt32)inSize; + unpackSizeRes += (UInt32)size; + + UInt64 outSize = offset; + RINOK(progress->SetRatioInfo(&inSize, &outSize)) + if (realOutStream) + { + res = WriteStream(realOutStream, Buffer, size); + if (res != S_OK) + break; + } + } + + if (outBuf && offset != outBuf->Size()) + outBuf->ChangeSize_KeepData(offset, offset); + + return res; +} + +}} diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h index a0b27b8ff..1d08d0185 100644 --- a/CPP/7zip/Archive/Nsis/NsisDecode.h +++ b/CPP/7zip/Archive/Nsis/NsisDecode.h @@ -1,97 +1,97 @@ -// NsisDecode.h - -#ifndef ZIP7_INC_NSIS_DECODE_H -#define ZIP7_INC_NSIS_DECODE_H - -#include "../../../Common/MyBuffer.h" - -#include "../../Common/FilterCoder.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/BZip2Decoder.h" -#include "../../Compress/DeflateDecoder.h" -#include "../../Compress/LzmaDecoder.h" - -namespace NArchive { -namespace NNsis { - -namespace NMethodType -{ - enum EEnum - { - kCopy, - kDeflate, - kBZip2, - kLZMA - }; -} - -/* 7-Zip installers 4.38 - 9.08 used modified version of NSIS that - supported BCJ filter for better compression ratio. - We support such modified NSIS archives. */ - -class CDecoder -{ - NMethodType::EEnum _curMethod; // method of created decoder - - CFilterCoder *_filter; - CMyComPtr _filterInStream; - CMyComPtr _codecInStream; - CMyComPtr _decoderInStream; - - NCompress::NBZip2::CNsisDecoder *_bzDecoder; - NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder; - NCompress::NLzma::CDecoder *_lzmaDecoder; - -public: - CMyComPtr InputStream; // for non-solid - UInt64 StreamPos; // the pos in unpacked for solid, the pos in Packed for non-solid - - NMethodType::EEnum Method; - bool FilterFlag; - bool Solid; - bool IsNsisDeflate; - - CByteBuffer Buffer; // temp buf - - CDecoder(): - FilterFlag(false), - Solid(true), - IsNsisDeflate(true) - { - _bzDecoder = NULL; - _deflateDecoder = NULL; - _lzmaDecoder = NULL; - } - - void Release() - { - _filterInStream.Release(); - _codecInStream.Release(); - _decoderInStream.Release(); - InputStream.Release(); - - _bzDecoder = NULL; - _deflateDecoder = NULL; - _lzmaDecoder = NULL; - } - - UInt64 GetInputProcessedSize() const; - - HRESULT Init(ISequentialInStream *inStream, bool &useFilter); - - HRESULT Read(void *data, size_t *processedSize) - { - return ReadStream(_decoderInStream, data, processedSize); - } - - - HRESULT SetToPos(UInt64 pos, ICompressProgressInfo *progress); // for solid - HRESULT Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, - ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, - UInt32 &packSizeRes, UInt32 &unpackSizeRes); -}; - -}} - -#endif +// NsisDecode.h + +#ifndef ZIP7_INC_NSIS_DECODE_H +#define ZIP7_INC_NSIS_DECODE_H + +#include "../../../Common/MyBuffer.h" + +#include "../../Common/FilterCoder.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/BZip2Decoder.h" +#include "../../Compress/DeflateDecoder.h" +#include "../../Compress/LzmaDecoder.h" + +namespace NArchive { +namespace NNsis { + +namespace NMethodType +{ + enum EEnum + { + kCopy, + kDeflate, + kBZip2, + kLZMA + }; +} + +/* 7-Zip installers 4.38 - 9.08 used modified version of NSIS that + supported BCJ filter for better compression ratio. + We support such modified NSIS archives. */ + +class CDecoder +{ + NMethodType::EEnum _curMethod; // method of created decoder + + CFilterCoder *_filter; + CMyComPtr _filterInStream; + CMyComPtr _codecInStream; + CMyComPtr _decoderInStream; + + NCompress::NBZip2::CNsisDecoder *_bzDecoder; + NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder; + NCompress::NLzma::CDecoder *_lzmaDecoder; + +public: + CMyComPtr InputStream; // for non-solid + UInt64 StreamPos; // the pos in unpacked for solid, the pos in Packed for non-solid + + NMethodType::EEnum Method; + bool FilterFlag; + bool Solid; + bool IsNsisDeflate; + + CByteBuffer Buffer; // temp buf + + CDecoder(): + FilterFlag(false), + Solid(true), + IsNsisDeflate(true) + { + _bzDecoder = NULL; + _deflateDecoder = NULL; + _lzmaDecoder = NULL; + } + + void Release() + { + _filterInStream.Release(); + _codecInStream.Release(); + _decoderInStream.Release(); + InputStream.Release(); + + _bzDecoder = NULL; + _deflateDecoder = NULL; + _lzmaDecoder = NULL; + } + + UInt64 GetInputProcessedSize() const; + + HRESULT Init(ISequentialInStream *inStream, bool &useFilter); + + HRESULT Read(void *data, size_t *processedSize) + { + return ReadStream(_decoderInStream, data, processedSize); + } + + + HRESULT SetToPos(UInt64 pos, ICompressProgressInfo *progress); // for solid + HRESULT Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize, + ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + UInt32 &packSizeRes, UInt32 &unpackSizeRes); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp index 4115b4d28..7ce2e8e59 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -1,693 +1,693 @@ -// NSisHandler.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "../Common/ItemNameUtils.h" - -#include "NsisHandler.h" - -#define Get32(p) GetUi32(p) - -using namespace NWindows; - -namespace NArchive { -namespace NNsis { - -#define kBcjMethod "BCJ" -#define kUnknownMethod "Unknown" - -static const char * const kMethods[] = -{ - "Copy" - , "Deflate" - , "BZip2" - , "LZMA" -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidMTime, - kpidAttrib, - kpidMethod, - kpidSolid, - kpidOffset -}; - -static const Byte kArcProps[] = -{ - kpidMethod, - kpidSolid, - kpidBit64, - kpidHeadersSize, - kpidEmbeddedStubSize, - kpidSubType - // kpidCodePage -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -static void AddDictProp(AString &s, UInt32 val) -{ - for (unsigned i = 0; i < 32; i++) - if (((UInt32)1 << i) == val) - { - s.Add_UInt32(i); - return; - } - char c = 'b'; - if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } - else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } - s.Add_UInt32(val); - s.Add_Char(c); -} - -static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) -{ - AString s; - if (useFilter) - { - s += kBcjMethod; - s.Add_Space(); - } - s += ((unsigned)method < Z7_ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod; - if (method == NMethodType::kLZMA) - { - s.Add_Colon(); - AddDictProp(s, dict); - } - return s; -} - -/* -AString CHandler::GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const -{ - AString s; - if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) - { - s += kBcjMethod; - s.Add_Space(); - } - s += (method < Z7_ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; - if (method == NMethodType::kLZMA) - { - s.Add_Colon(); - s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); - } - return s; -} -*/ - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break; - case kpidSubType: - { - AString s (_archive.GetFormatDescription()); - if (!_archive.IsInstaller) - { - s.Add_Space_if_NotEmpty(); - s += "(Uninstall)"; - } - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidBit64: if (_archive.Is64Bit) prop = true; break; - case kpidMethod: prop = _methodString; break; - case kpidSolid: prop = _archive.IsSolid; break; - case kpidOffset: prop = _archive.StartOffset; break; - case kpidPhySize: prop = (UInt64)((UInt64)_archive.ExeStub.Size() + _archive.FirstHeader.ArcSize); break; - case kpidEmbeddedStubSize: prop = (UInt64)_archive.ExeStub.Size(); break; - case kpidHeadersSize: prop = _archive.FirstHeader.HeaderSize; break; - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; - if (_archive.IsTruncated()) v |= kpv_ErrorFlags_UnexpectedEnd; - prop = v; - break; - } - - case kpidName: - { - AString s; - - #ifdef NSIS_SCRIPT - if (!_archive.Name.IsEmpty()) - s = _archive.Name; - if (!_archive.IsInstaller) - { - if (!s.IsEmpty()) - s.Add_Dot(); - s += "Uninstall"; - } - #endif - - if (s.IsEmpty()) - s = _archive.IsInstaller ? "Install" : "Uninstall"; - s += (_archive.ExeStub.Size() == 0) ? ".nsis" : ".exe"; - - prop = _archive.ConvertToUnicode(s); - break; - } - - #ifdef NSIS_SCRIPT - case kpidShortComment: - { - if (!_archive.BrandingText.IsEmpty()) - prop = _archive.ConvertToUnicode(_archive.BrandingText); - break; - } - #endif - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - { - if (_archive.Open(stream, maxCheckStartPosition) != S_OK) - return S_FALSE; - { - UInt32 dict = _archive.DictionarySize; - if (!_archive.IsSolid) - { - FOR_VECTOR (i, _archive.Items) - { - const CItem &item = _archive.Items[i]; - if (item.DictionarySize > dict) - dict = item.DictionarySize; - } - } - _methodString = GetMethod(_archive.UseFilter, _archive.Method, dict); - } - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _archive.Clear(); - _archive.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _archive.Items.Size() - #ifdef NSIS_SCRIPT - + 1 + _archive.LicenseFiles.Size() - #endif - ; - return S_OK; -} - -bool CHandler::GetUncompressedSize(unsigned index, UInt32 &size) const -{ - size = 0; - const CItem &item = _archive.Items[index]; - if (item.Size_Defined) - size = item.Size; - else if (_archive.IsSolid && item.EstimatedSize_Defined) - size = item.EstimatedSize; - else if (!item.IsEmptyFile) - return false; - return true; -} - -bool CHandler::GetCompressedSize(unsigned index, UInt32 &size) const -{ - size = 0; - const CItem &item = _archive.Items[index]; - if (item.CompressedSize_Defined) - size = item.CompressedSize; - else - { - if (_archive.IsSolid) - { - if (index == 0) - size = _archive.FirstHeader.GetDataSize(); - else - return false; - } - else - { - if (!item.IsCompressed) - size = item.Size; - else - return false; - } - } - return true; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - #ifdef NSIS_SCRIPT - if (index >= (UInt32)_archive.Items.Size()) - { - if (index == (UInt32)_archive.Items.Size()) - { - switch (propID) - { - case kpidPath: prop = "[NSIS].nsi"; break; - case kpidSize: - case kpidPackSize: prop = (UInt64)_archive.Script.Len(); break; - case kpidSolid: prop = false; break; - } - } - else - { - const CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; - switch (propID) - { - case kpidPath: prop = lic.Name; break; - case kpidSize: - case kpidPackSize: prop = (UInt64)lic.Size; break; - case kpidSolid: prop = false; break; - } - } - } - else - #endif - { - const CItem &item = _archive.Items[index]; - switch (propID) - { - case kpidOffset: prop = item.Pos; break; - case kpidPath: - { - UString s = NItemName::WinPathToOsPath(_archive.GetReducedName(index)); - if (!s.IsEmpty()) - prop = (const wchar_t *)s; - break; - } - case kpidSize: - { - UInt32 size; - if (GetUncompressedSize(index, size)) - prop = (UInt64)size; - break; - } - case kpidPackSize: - { - UInt32 size; - if (GetCompressedSize(index, size)) - prop = (UInt64)size; - break; - } - case kpidMTime: - { - if (item.MTime.dwHighDateTime > 0x01000000 && - item.MTime.dwHighDateTime < 0xFF000000) - prop = item.MTime; - break; - } - case kpidAttrib: - { - if (item.Attrib_Defined) - prop = item.Attrib; - break; - } - - case kpidMethod: - if (_archive.IsSolid) - prop = _methodString; - else - prop = GetMethod(_archive.UseFilter, item.IsCompressed ? _archive.Method : - NMethodType::kCopy, item.DictionarySize); - break; - - case kpidSolid: prop = _archive.IsSolid; break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -static bool UninstallerPatch(const Byte *p, size_t size, Byte *dest, size_t destSize) -{ - for (;;) - { - if (size < 4) - return false; - const UInt32 len = Get32(p); - if (len == 0) - return size == 4; - if (size < 8) - return false; - const UInt32 offs = Get32(p + 4); - p += 8; - size -= 8; - if (size < len || offs > destSize || len > destSize - offs) - return false; - memcpy(dest + offs, p, len); - p += len; - size -= len; - } -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - GetNumberOfItems(&numItems); - if (numItems == 0) - return S_OK; - - UInt64 totalSize = 0; - UInt64 solidPosMax = 0; - - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = (allFilesMode ? i : indices[i]); - - #ifdef NSIS_SCRIPT - if (index >= _archive.Items.Size()) - { - if (index == _archive.Items.Size()) - totalSize += _archive.Script.Len(); - else - totalSize += _archive.LicenseFiles[index - (_archive.Items.Size() + 1)].Size; - } - else - #endif - { - UInt32 size; - if (_archive.IsSolid) - { - GetUncompressedSize(index, size); - UInt64 pos = (UInt64)_archive.GetPosOfSolidItem(index) + size; - if (solidPosMax < pos) - solidPosMax = pos; - } - else - { - GetCompressedSize(index, size); - totalSize += size; - } - } - } - - extractCallback->SetTotal(totalSize + solidPosMax); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, !_archive.IsSolid); - - if (_archive.IsSolid) - { - RINOK(_archive.SeekTo_DataStreamOffset()) - RINOK(_archive.InitDecoder()) - _archive.Decoder.StreamPos = 0; - } - - /* We use tempBuf for solid archives, if there is duplicate item. - We don't know uncompressed size for non-solid archives, so we can't - allocate exact buffer. - We use tempBuf also for first part (EXE stub) of unistall.exe - and tempBuf2 is used for second part (NSIS script). */ - - CByteBuffer tempBuf; - CByteBuffer tempBuf2; - - /* tempPos is pos in uncompressed stream of previous item for solid archive, that - was written to tempBuf */ - UInt64 tempPos = (UInt64)(Int64)-1; - - /* prevPos is pos in uncompressed stream of previous item for solid archive. - It's used for test mode (where we don't need to test same file second time */ - UInt64 prevPos = (UInt64)(Int64)-1; - - // if there is error in solid archive, we show error for all subsequent files - bool solidDataError = false; - - UInt64 curTotalPacked = 0, curTotalUnpacked = 0; - UInt32 curPacked = 0; - UInt64 curUnpacked = 0; - - for (i = 0; i < numItems; i++, - curTotalPacked += curPacked, - curTotalUnpacked += curUnpacked) - { - lps->InSize = curTotalPacked; - lps->OutSize = curTotalUnpacked; - if (_archive.IsSolid) - lps->OutSize += _archive.Decoder.StreamPos; - - curPacked = 0; - curUnpacked = 0; - RINOK(lps->SetCur()) - - // RINOK(extractCallback->SetCompleted(¤tTotalSize)) - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - bool dataError = false; - - #ifdef NSIS_SCRIPT - if (index >= (UInt32)_archive.Items.Size()) - { - const void *data; - size_t size; - if (index == (UInt32)_archive.Items.Size()) - { - data = (const Byte *)_archive.Script; - size = _archive.Script.Len(); - } - else - { - CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; - if (lic.Text.Size() != 0) - data = lic.Text; - else - data = _archive._data + lic.Offset; - size = lic.Size; - } - curUnpacked = size; - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - if (realOutStream) - RINOK(WriteStream(realOutStream, data, size)) - } - else - #endif - { - const CItem &item = _archive.Items[index]; - - if (!_archive.IsSolid) - GetCompressedSize(index, curPacked); - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - - dataError = solidDataError; - - bool needDecompress = false; - - if (!item.IsEmptyFile) - { - needDecompress = !solidDataError; - if (needDecompress) - { - if (testMode && _archive.IsSolid && _archive.GetPosOfSolidItem(index) == prevPos) - needDecompress = false; - } - } - - if (needDecompress) - { - bool writeToTemp = false; - bool readFromTemp = false; - - if (!_archive.IsSolid) - { - RINOK(_archive.SeekToNonSolidItem(index)) - } - else - { - UInt64 pos = _archive.GetPosOfSolidItem(index); - if (pos < _archive.Decoder.StreamPos) - { - if (pos != tempPos) - solidDataError = dataError = true; - readFromTemp = true; - } - else - { - HRESULT res = _archive.Decoder.SetToPos(pos, lps); - if (res != S_OK) - { - if (res != S_FALSE) - return res; - solidDataError = dataError = true; - } - else if (!testMode && i + 1 < numItems) - { - const UInt32 next = allFilesMode ? i + 1 : indices[i + 1]; - if (next < _archive.Items.Size()) - { - // next cannot be IsEmptyFile - const UInt64 nextPos = _archive.GetPosOfSolidItem(next); - if (nextPos == pos) - { - writeToTemp = true; - tempPos = pos; - } - } - } - } - prevPos = pos; - } - - /* nsis 3.08 can use (PatchSize == 0) for uninstaller without patched section */ - - const bool is_PatchedUninstaller = item.Is_PatchedUninstaller(); - - if (!dataError) - { - // UInt32 unpackSize = 0; - // bool unpackSize_Defined = false; - bool writeToTemp1 = writeToTemp; - if (is_PatchedUninstaller) - { - // unpackSize = item.PatchSize; - // unpackSize_Defined = true; - if (!readFromTemp) - writeToTemp = true; - writeToTemp1 = writeToTemp; - if (_archive.ExeStub.Size() == 0) - { - if (writeToTemp1 && !readFromTemp) - tempBuf.Free(); - writeToTemp1 = false; - } - } - - if (readFromTemp) - { - if (realOutStream && !is_PatchedUninstaller) - RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size())) - } - else - { - UInt32 curUnpacked32 = 0; - const HRESULT res = _archive.Decoder.Decode( - writeToTemp1 ? &tempBuf : NULL, - is_PatchedUninstaller, item.PatchSize, - is_PatchedUninstaller ? NULL : (ISequentialOutStream *)realOutStream, - lps, - curPacked, curUnpacked32); - curUnpacked = curUnpacked32; - if (_archive.IsSolid) - curUnpacked = 0; - if (res != S_OK) - { - if (res != S_FALSE) - return res; - dataError = true; - if (_archive.IsSolid) - solidDataError = true; - } - } - } - - if (!dataError && is_PatchedUninstaller) - { - if (_archive.ExeStub.Size() != 0) - { - CByteBuffer destBuf = _archive.ExeStub; - dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf, destBuf.Size()); - if (realOutStream) - RINOK(WriteStream(realOutStream, destBuf, destBuf.Size())) - } - - if (readFromTemp) - { - if (realOutStream) - RINOK(WriteStream(realOutStream, tempBuf2, tempBuf2.Size())) - } - else - { - UInt32 curPacked2 = 0; - UInt32 curUnpacked2 = 0; - - if (!_archive.IsSolid) - { - RINOK(_archive.SeekTo(_archive.GetPosOfNonSolidItem(index) + 4 + curPacked )) - } - - const HRESULT res = _archive.Decoder.Decode( - writeToTemp ? &tempBuf2 : NULL, - false, 0, - realOutStream, - lps, - curPacked2, curUnpacked2); - curPacked += curPacked2; - if (!_archive.IsSolid) - curUnpacked += curUnpacked2; - if (res != S_OK) - { - if (res != S_FALSE) - return res; - dataError = true; - if (_archive.IsSolid) - solidDataError = true; - } - } - } - } - } - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(dataError ? - NExtract::NOperationResult::kDataError : - NExtract::NOperationResult::kOK)) - } - return S_OK; - COM_TRY_END -} - -}} +// NSisHandler.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../Common/ItemNameUtils.h" + +#include "NsisHandler.h" + +#define Get32(p) GetUi32(p) + +using namespace NWindows; + +namespace NArchive { +namespace NNsis { + +#define kBcjMethod "BCJ" +#define kUnknownMethod "Unknown" + +static const char * const kMethods[] = +{ + "Copy" + , "Deflate" + , "BZip2" + , "LZMA" +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidMTime, + kpidAttrib, + kpidMethod, + kpidSolid, + kpidOffset +}; + +static const Byte kArcProps[] = +{ + kpidMethod, + kpidSolid, + kpidBit64, + kpidHeadersSize, + kpidEmbeddedStubSize, + kpidSubType + // kpidCodePage +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +static void AddDictProp(AString &s, UInt32 val) +{ + for (unsigned i = 0; i < 32; i++) + if (((UInt32)1 << i) == val) + { + s.Add_UInt32(i); + return; + } + char c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + s.Add_UInt32(val); + s.Add_Char(c); +} + +static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict) +{ + AString s; + if (useFilter) + { + s += kBcjMethod; + s.Add_Space(); + } + s += ((unsigned)method < Z7_ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod; + if (method == NMethodType::kLZMA) + { + s.Add_Colon(); + AddDictProp(s, dict); + } + return s; +} + +/* +AString CHandler::GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const +{ + AString s; + if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter) + { + s += kBcjMethod; + s.Add_Space(); + } + s += (method < Z7_ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod; + if (method == NMethodType::kLZMA) + { + s.Add_Colon(); + s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary); + } + return s; +} +*/ + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break; + case kpidSubType: + { + AString s (_archive.GetFormatDescription()); + if (!_archive.IsInstaller) + { + s.Add_Space_if_NotEmpty(); + s += "(Uninstall)"; + } + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidBit64: if (_archive.Is64Bit) prop = true; break; + case kpidMethod: prop = _methodString; break; + case kpidSolid: prop = _archive.IsSolid; break; + case kpidOffset: prop = _archive.StartOffset; break; + case kpidPhySize: prop = (UInt64)((UInt64)_archive.ExeStub.Size() + _archive.FirstHeader.ArcSize); break; + case kpidEmbeddedStubSize: prop = (UInt64)_archive.ExeStub.Size(); break; + case kpidHeadersSize: prop = _archive.FirstHeader.HeaderSize; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_archive.IsTruncated()) v |= kpv_ErrorFlags_UnexpectedEnd; + prop = v; + break; + } + + case kpidName: + { + AString s; + + #ifdef NSIS_SCRIPT + if (!_archive.Name.IsEmpty()) + s = _archive.Name; + if (!_archive.IsInstaller) + { + if (!s.IsEmpty()) + s.Add_Dot(); + s += "Uninstall"; + } + #endif + + if (s.IsEmpty()) + s = _archive.IsInstaller ? "Install" : "Uninstall"; + s += (_archive.ExeStub.Size() == 0) ? ".nsis" : ".exe"; + + prop = _archive.ConvertToUnicode(s); + break; + } + + #ifdef NSIS_SCRIPT + case kpidShortComment: + { + if (!_archive.BrandingText.IsEmpty()) + prop = _archive.ConvertToUnicode(_archive.BrandingText); + break; + } + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + { + if (_archive.Open(stream, maxCheckStartPosition) != S_OK) + return S_FALSE; + { + UInt32 dict = _archive.DictionarySize; + if (!_archive.IsSolid) + { + FOR_VECTOR (i, _archive.Items) + { + const CItem &item = _archive.Items[i]; + if (item.DictionarySize > dict) + dict = item.DictionarySize; + } + } + _methodString = GetMethod(_archive.UseFilter, _archive.Method, dict); + } + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _archive.Clear(); + _archive.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _archive.Items.Size() + #ifdef NSIS_SCRIPT + + 1 + _archive.LicenseFiles.Size() + #endif + ; + return S_OK; +} + +bool CHandler::GetUncompressedSize(unsigned index, UInt32 &size) const +{ + size = 0; + const CItem &item = _archive.Items[index]; + if (item.Size_Defined) + size = item.Size; + else if (_archive.IsSolid && item.EstimatedSize_Defined) + size = item.EstimatedSize; + else if (!item.IsEmptyFile) + return false; + return true; +} + +bool CHandler::GetCompressedSize(unsigned index, UInt32 &size) const +{ + size = 0; + const CItem &item = _archive.Items[index]; + if (item.CompressedSize_Defined) + size = item.CompressedSize; + else + { + if (_archive.IsSolid) + { + if (index == 0) + size = _archive.FirstHeader.GetDataSize(); + else + return false; + } + else + { + if (!item.IsCompressed) + size = item.Size; + else + return false; + } + } + return true; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + #ifdef NSIS_SCRIPT + if (index >= (UInt32)_archive.Items.Size()) + { + if (index == (UInt32)_archive.Items.Size()) + { + switch (propID) + { + case kpidPath: prop = "[NSIS].nsi"; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)_archive.Script.Len(); break; + case kpidSolid: prop = false; break; + } + } + else + { + const CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; + switch (propID) + { + case kpidPath: prop = lic.Name; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)lic.Size; break; + case kpidSolid: prop = false; break; + } + } + } + else + #endif + { + const CItem &item = _archive.Items[index]; + switch (propID) + { + case kpidOffset: prop = item.Pos; break; + case kpidPath: + { + UString s = NItemName::WinPathToOsPath(_archive.GetReducedName(index)); + if (!s.IsEmpty()) + prop = (const wchar_t *)s; + break; + } + case kpidSize: + { + UInt32 size; + if (GetUncompressedSize(index, size)) + prop = (UInt64)size; + break; + } + case kpidPackSize: + { + UInt32 size; + if (GetCompressedSize(index, size)) + prop = (UInt64)size; + break; + } + case kpidMTime: + { + if (item.MTime.dwHighDateTime > 0x01000000 && + item.MTime.dwHighDateTime < 0xFF000000) + prop = item.MTime; + break; + } + case kpidAttrib: + { + if (item.Attrib_Defined) + prop = item.Attrib; + break; + } + + case kpidMethod: + if (_archive.IsSolid) + prop = _methodString; + else + prop = GetMethod(_archive.UseFilter, item.IsCompressed ? _archive.Method : + NMethodType::kCopy, item.DictionarySize); + break; + + case kpidSolid: prop = _archive.IsSolid; break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static bool UninstallerPatch(const Byte *p, size_t size, Byte *dest, size_t destSize) +{ + for (;;) + { + if (size < 4) + return false; + const UInt32 len = Get32(p); + if (len == 0) + return size == 4; + if (size < 8) + return false; + const UInt32 offs = Get32(p + 4); + p += 8; + size -= 8; + if (size < len || offs > destSize || len > destSize - offs) + return false; + memcpy(dest + offs, p, len); + p += len; + size -= len; + } +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + GetNumberOfItems(&numItems); + if (numItems == 0) + return S_OK; + + UInt64 totalSize = 0; + UInt64 solidPosMax = 0; + + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = (allFilesMode ? i : indices[i]); + + #ifdef NSIS_SCRIPT + if (index >= _archive.Items.Size()) + { + if (index == _archive.Items.Size()) + totalSize += _archive.Script.Len(); + else + totalSize += _archive.LicenseFiles[index - (_archive.Items.Size() + 1)].Size; + } + else + #endif + { + UInt32 size; + if (_archive.IsSolid) + { + GetUncompressedSize(index, size); + UInt64 pos = (UInt64)_archive.GetPosOfSolidItem(index) + size; + if (solidPosMax < pos) + solidPosMax = pos; + } + else + { + GetCompressedSize(index, size); + totalSize += size; + } + } + } + + extractCallback->SetTotal(totalSize + solidPosMax); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, !_archive.IsSolid); + + if (_archive.IsSolid) + { + RINOK(_archive.SeekTo_DataStreamOffset()) + RINOK(_archive.InitDecoder()) + _archive.Decoder.StreamPos = 0; + } + + /* We use tempBuf for solid archives, if there is duplicate item. + We don't know uncompressed size for non-solid archives, so we can't + allocate exact buffer. + We use tempBuf also for first part (EXE stub) of unistall.exe + and tempBuf2 is used for second part (NSIS script). */ + + CByteBuffer tempBuf; + CByteBuffer tempBuf2; + + /* tempPos is pos in uncompressed stream of previous item for solid archive, that + was written to tempBuf */ + UInt64 tempPos = (UInt64)(Int64)-1; + + /* prevPos is pos in uncompressed stream of previous item for solid archive. + It's used for test mode (where we don't need to test same file second time */ + UInt64 prevPos = (UInt64)(Int64)-1; + + // if there is error in solid archive, we show error for all subsequent files + bool solidDataError = false; + + UInt64 curTotalPacked = 0, curTotalUnpacked = 0; + UInt32 curPacked = 0; + UInt64 curUnpacked = 0; + + for (i = 0; i < numItems; i++, + curTotalPacked += curPacked, + curTotalUnpacked += curUnpacked) + { + lps->InSize = curTotalPacked; + lps->OutSize = curTotalUnpacked; + if (_archive.IsSolid) + lps->OutSize += _archive.Decoder.StreamPos; + + curPacked = 0; + curUnpacked = 0; + RINOK(lps->SetCur()) + + // RINOK(extractCallback->SetCompleted(¤tTotalSize)) + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + bool dataError = false; + + #ifdef NSIS_SCRIPT + if (index >= (UInt32)_archive.Items.Size()) + { + const void *data; + size_t size; + if (index == (UInt32)_archive.Items.Size()) + { + data = (const Byte *)_archive.Script; + size = _archive.Script.Len(); + } + else + { + CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)]; + if (lic.Text.Size() != 0) + data = lic.Text; + else + data = _archive._data + lic.Offset; + size = lic.Size; + } + curUnpacked = size; + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + if (realOutStream) + RINOK(WriteStream(realOutStream, data, size)) + } + else + #endif + { + const CItem &item = _archive.Items[index]; + + if (!_archive.IsSolid) + GetCompressedSize(index, curPacked); + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + + dataError = solidDataError; + + bool needDecompress = false; + + if (!item.IsEmptyFile) + { + needDecompress = !solidDataError; + if (needDecompress) + { + if (testMode && _archive.IsSolid && _archive.GetPosOfSolidItem(index) == prevPos) + needDecompress = false; + } + } + + if (needDecompress) + { + bool writeToTemp = false; + bool readFromTemp = false; + + if (!_archive.IsSolid) + { + RINOK(_archive.SeekToNonSolidItem(index)) + } + else + { + UInt64 pos = _archive.GetPosOfSolidItem(index); + if (pos < _archive.Decoder.StreamPos) + { + if (pos != tempPos) + solidDataError = dataError = true; + readFromTemp = true; + } + else + { + HRESULT res = _archive.Decoder.SetToPos(pos, lps); + if (res != S_OK) + { + if (res != S_FALSE) + return res; + solidDataError = dataError = true; + } + else if (!testMode && i + 1 < numItems) + { + const UInt32 next = allFilesMode ? i + 1 : indices[i + 1]; + if (next < _archive.Items.Size()) + { + // next cannot be IsEmptyFile + const UInt64 nextPos = _archive.GetPosOfSolidItem(next); + if (nextPos == pos) + { + writeToTemp = true; + tempPos = pos; + } + } + } + } + prevPos = pos; + } + + /* nsis 3.08 can use (PatchSize == 0) for uninstaller without patched section */ + + const bool is_PatchedUninstaller = item.Is_PatchedUninstaller(); + + if (!dataError) + { + // UInt32 unpackSize = 0; + // bool unpackSize_Defined = false; + bool writeToTemp1 = writeToTemp; + if (is_PatchedUninstaller) + { + // unpackSize = item.PatchSize; + // unpackSize_Defined = true; + if (!readFromTemp) + writeToTemp = true; + writeToTemp1 = writeToTemp; + if (_archive.ExeStub.Size() == 0) + { + if (writeToTemp1 && !readFromTemp) + tempBuf.Free(); + writeToTemp1 = false; + } + } + + if (readFromTemp) + { + if (realOutStream && !is_PatchedUninstaller) + RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size())) + } + else + { + UInt32 curUnpacked32 = 0; + const HRESULT res = _archive.Decoder.Decode( + writeToTemp1 ? &tempBuf : NULL, + is_PatchedUninstaller, item.PatchSize, + is_PatchedUninstaller ? NULL : (ISequentialOutStream *)realOutStream, + lps, + curPacked, curUnpacked32); + curUnpacked = curUnpacked32; + if (_archive.IsSolid) + curUnpacked = 0; + if (res != S_OK) + { + if (res != S_FALSE) + return res; + dataError = true; + if (_archive.IsSolid) + solidDataError = true; + } + } + } + + if (!dataError && is_PatchedUninstaller) + { + if (_archive.ExeStub.Size() != 0) + { + CByteBuffer destBuf = _archive.ExeStub; + dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf, destBuf.Size()); + if (realOutStream) + RINOK(WriteStream(realOutStream, destBuf, destBuf.Size())) + } + + if (readFromTemp) + { + if (realOutStream) + RINOK(WriteStream(realOutStream, tempBuf2, tempBuf2.Size())) + } + else + { + UInt32 curPacked2 = 0; + UInt32 curUnpacked2 = 0; + + if (!_archive.IsSolid) + { + RINOK(_archive.SeekTo(_archive.GetPosOfNonSolidItem(index) + 4 + curPacked )) + } + + const HRESULT res = _archive.Decoder.Decode( + writeToTemp ? &tempBuf2 : NULL, + false, 0, + realOutStream, + lps, + curPacked2, curUnpacked2); + curPacked += curPacked2; + if (!_archive.IsSolid) + curUnpacked += curUnpacked2; + if (res != S_OK) + { + if (res != S_FALSE) + return res; + dataError = true; + if (_archive.IsSolid) + solidDataError = true; + } + } + } + } + } + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(dataError ? + NExtract::NOperationResult::kDataError : + NExtract::NOperationResult::kOK)) + } + return S_OK; + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.h b/CPP/7zip/Archive/Nsis/NsisHandler.h index 2f23fe51c..bb90bfe0b 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.h +++ b/CPP/7zip/Archive/Nsis/NsisHandler.h @@ -1,30 +1,30 @@ -// NSisHandler.h - -#ifndef ZIP7_INC_NSIS_HANDLER_H -#define ZIP7_INC_NSIS_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../../Common/CreateCoder.h" - -#include "../IArchive.h" - -#include "NsisIn.h" - -namespace NArchive { -namespace NNsis { - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - CInArchive _archive; - AString _methodString; - - bool GetUncompressedSize(unsigned index, UInt32 &size) const; - bool GetCompressedSize(unsigned index, UInt32 &size) const; - - // AString GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const; -}; - -}} - -#endif +// NSisHandler.h + +#ifndef ZIP7_INC_NSIS_HANDLER_H +#define ZIP7_INC_NSIS_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../../Common/CreateCoder.h" + +#include "../IArchive.h" + +#include "NsisIn.h" + +namespace NArchive { +namespace NNsis { + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + CInArchive _archive; + AString _methodString; + + bool GetUncompressedSize(unsigned index, UInt32 &size) const; + bool GetCompressedSize(unsigned index, UInt32 &size) const; + + // AString GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index 166b877ad..c9e2c014d 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -1,6138 +1,6138 @@ -// NsisIn.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringToInt.h" - -#include "../../Common/LimitedStreams.h" - -#include "NsisIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -// #define NUM_SPEED_TESTS 1000 - -namespace NArchive { -namespace NNsis { - -static const size_t kInputBufSize = 1 << 20; - -const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; -static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; - -static const unsigned kNumCommandParams = 6; -static const unsigned kCmdSize = 4 + kNumCommandParams * 4; - -#ifdef NSIS_SCRIPT -#define CR_LF "\x0D\x0A" -#endif - -static const char * const kErrorStr = "$_ERROR_STR_"; - -#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } - - -/* There are several versions of NSIS: - 1) Original NSIS: - NSIS-2 ANSI - NSIS-3 ANSI - NSIS-3 Unicode - 2) NSIS from Jim Park that extends old NSIS-2 to Unicode support: - NSIS-Park-(1,2,3) ANSI - NSIS-Park-(1,2,3) Unicode - - The command IDs layout is slightly different for different versions. - Also there are additional "log" versions of NSIS that support EW_LOG. - We use the layout of "NSIS-3 Unicode" without "log" as main layout. - And we transfer the command IDs to main layout, if another layout is detected. */ - - -enum -{ - EW_INVALID_OPCODE, - EW_RET, // Return - EW_NOP, // Nop, Goto - EW_ABORT, // Abort - EW_QUIT, // Quit - EW_CALL, // Call, InitPluginsDir - EW_UPDATETEXT, // DetailPrint - EW_SLEEP, // Sleep - EW_BRINGTOFRONT, // BringToFront - EW_CHDETAILSVIEW, // SetDetailsView - EW_SETFILEATTRIBUTES, // SetFileAttributes - EW_CREATEDIR, // CreateDirectory, SetOutPath - EW_IFFILEEXISTS, // IfFileExists - EW_SETFLAG, // SetRebootFlag, ... - EW_IFFLAG, // IfAbort, IfSilent, IfErrors, IfRebootFlag - EW_GETFLAG, // GetInstDirError, GetErrorLevel - EW_RENAME, // Rename - EW_GETFULLPATHNAME, // GetFullPathName - EW_SEARCHPATH, // SearchPath - EW_GETTEMPFILENAME, // GetTempFileName - EW_EXTRACTFILE, // File - EW_DELETEFILE, // Delete - EW_MESSAGEBOX, // MessageBox - EW_RMDIR, // RMDir - EW_STRLEN, // StrLen - EW_ASSIGNVAR, // StrCpy - EW_STRCMP, // StrCmp - EW_READENVSTR, // ReadEnvStr, ExpandEnvStrings - EW_INTCMP, // IntCmp, IntCmpU - EW_INTOP, // IntOp - EW_INTFMT, // IntFmt/Int64Fmt - EW_PUSHPOP, // Push/Pop/Exchange - EW_FINDWINDOW, // FindWindow - EW_SENDMESSAGE, // SendMessage - EW_ISWINDOW, // IsWindow - EW_GETDLGITEM, // GetDlgItem - EW_SETCTLCOLORS, // SetCtlColors - EW_SETBRANDINGIMAGE, // SetBrandingImage / LoadAndSetImage - EW_CREATEFONT, // CreateFont - EW_SHOWWINDOW, // ShowWindow, EnableWindow, HideWindow - EW_SHELLEXEC, // ExecShell - EW_EXECUTE, // Exec, ExecWait - EW_GETFILETIME, // GetFileTime - EW_GETDLLVERSION, // GetDLLVersion - - // EW_GETFONTVERSION, // Park : 2.46.2 - // EW_GETFONTNAME, // Park : 2.46.3 - - EW_REGISTERDLL, // RegDLL, UnRegDLL, CallInstDLL - EW_CREATESHORTCUT, // CreateShortCut - EW_COPYFILES, // CopyFiles - EW_REBOOT, // Reboot - EW_WRITEINI, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI - EW_READINISTR, // ReadINIStr - EW_DELREG, // DeleteRegValue, DeleteRegKey - EW_WRITEREG, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD - EW_READREGSTR, // ReadRegStr, ReadRegDWORD - EW_REGENUM, // EnumRegKey, EnumRegValue - EW_FCLOSE, // FileClose - EW_FOPEN, // FileOpen - EW_FPUTS, // FileWrite, FileWriteByte - EW_FGETS, // FileRead, FileReadByte - - // Park - // EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord - // EW_FGETWS, // FileReadUTF16LE, FileReadWord - - EW_FSEEK, // FileSeek - EW_FINDCLOSE, // FindClose - EW_FINDNEXT, // FindNext - EW_FINDFIRST, // FindFirst - EW_WRITEUNINSTALLER, // WriteUninstaller - - // Park : since 2.46.3 the log is enabled in main Park version - // EW_LOG, // LogSet, LogText - - EW_SECTIONSET, // Get*, Set* - EW_INSTTYPESET, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType - - /* - // before v3.06 nsis it was so: - // instructions not actually implemented in exehead, but used in compiler. - EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR - EW_GETFUNCTIONADDR, - */ - - // v3.06 and later it was changed to: - EW_GETOSINFO, - EW_RESERVEDOPCODE, - - EW_LOCKWINDOW, // LockWindow - - // 2 unicode commands available only in Unicode archive - EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord - EW_FGETWS, // FileReadUTF16LE, FileReadWord - - /* - // since v3.06 the fllowing IDs codes was moved here: - // Opcodes listed here are not actually used in exehead. No exehead opcodes should be present after these! - EW_GETLABELADDR, // --> EW_ASSIGNVAR - EW_GETFUNCTIONADDR, // --> EW_ASSIGNVAR - */ - - // The following IDs are not IDs in real order. - // We just need some IDs to translate eny extended layout to main layout. - - EW_LOG, // LogSet, LogText - - // Park - EW_FINDPROC, // FindProc - - EW_GETFONTVERSION, // GetFontVersion - EW_GETFONTNAME, // GetFontName - - kNumCmds -}; - - - -struct CCommandInfo -{ - Byte NumParams; -}; - -static const CCommandInfo k_Commands[kNumCmds] = -{ - { 0 }, // "Invalid" }, - { 0 }, // Return - { 1 }, // Nop, Goto - { 1 }, // "Abort" }, - { 0 }, // "Quit" }, - { 2 }, // Call - { 6 }, // "DetailPrint" }, // 1 param in new versions, 6 in old NSIS versions - { 1 }, // "Sleep" }, - { 0 }, // "BringToFront" }, - { 2 }, // "SetDetailsView" }, - { 2 }, // "SetFileAttributes" }, - { 3 }, // CreateDirectory, SetOutPath - { 3 }, // "IfFileExists" }, - { 3 }, // SetRebootFlag, ... - { 4 }, // "If" }, // IfAbort, IfSilent, IfErrors, IfRebootFlag - { 2 }, // "Get" }, // GetInstDirError, GetErrorLevel - { 4 }, // "Rename" }, - { 3 }, // "GetFullPathName" }, - { 2 }, // "SearchPath" }, - { 2 }, // "GetTempFileName" }, - { 6 }, // "File" - { 2 }, // "Delete" }, - { 6 }, // "MessageBox" }, - { 2 }, // "RMDir" }, - { 2 }, // "StrLen" }, - { 4 }, // StrCpy, GetCurrentAddress - { 5 }, // "StrCmp" }, - { 3 }, // ReadEnvStr, ExpandEnvStrings - { 6 }, // "IntCmp" }, - { 4 }, // "IntOp" }, - { 4 }, // "IntFmt" }, EW_INTFMT - { 6 }, // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. - { 5 }, // "FindWindow" }, - { 6 }, // "SendMessage" }, - { 3 }, // "IsWindow" }, - { 3 }, // "GetDlgItem" }, - { 2 }, // "SetCtlColors" }, - { 4 }, // "SetBrandingImage" } // LoadAndSetImage - { 5 }, // "CreateFont" }, - { 4 }, // ShowWindow, EnableWindow, HideWindow - { 6 }, // "ExecShell" }, - { 3 }, // "Exec" }, // Exec, ExecWait - { 3 }, // "GetFileTime" }, - { 4 }, // "GetDLLVersion" }, - { 6 }, // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. - { 6 }, // "CreateShortCut" }, - { 4 }, // "CopyFiles" }, - { 1 }, // "Reboot" }, - { 5 }, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI - { 4 }, // "ReadINIStr" }, - { 5 }, // "DeleteReg" }, // DeleteRegKey, DeleteRegValue - { 6 }, // "WriteReg" }, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD - { 5 }, // "ReadReg" }, // ReadRegStr, ReadRegDWORD - { 5 }, // "EnumReg" }, // EnumRegKey, EnumRegValue - { 1 }, // "FileClose" }, - { 4 }, // "FileOpen" }, - { 3 }, // "FileWrite" }, // FileWrite, FileWriteByte - { 4 }, // "FileRead" }, // FileRead, FileReadByte - { 4 }, // "FileSeek" }, - { 1 }, // "FindClose" }, - { 2 }, // "FindNext" }, - { 3 }, // "FindFirst" }, - { 4 }, // "WriteUninstaller" }, - { 5 }, // "Section" }, // *** - { 4 }, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType - - // { 6 }, // "GetLabelAddr" }, // before 3.06 - { 6 }, // "GetOsInfo" }, GetKnownFolderPath, ReadMemory, // v3.06+ - - { 2 }, // "GetFunctionAddress" }, // before 3.06 - - { 1 }, // "LockWindow" }, - { 4 }, // "FileWrite" }, // FileWriteUTF16LE, FileWriteWord - { 4 }, // "FileRead" }, // FileReadUTF16LE, FileReadWord - - { 2 }, // "Log" }, // LogSet, LogText - // Park - { 2 }, // "FindProc" }, - { 2 }, // "GetFontVersion" }, - { 2 }, // "GetFontName" } -}; - -#ifdef NSIS_SCRIPT - -static const char * const k_CommandNames[kNumCmds] = -{ - "Invalid" - , NULL // Return - , NULL // Nop, Goto - , "Abort" - , "Quit" - , NULL // Call - , "DetailPrint" // 1 param in new versions, 6 in old NSIS versions - , "Sleep" - , "BringToFront" - , "SetDetailsView" - , "SetFileAttributes" - , NULL // CreateDirectory, SetOutPath - , "IfFileExists" - , NULL // SetRebootFlag, ... - , "If" // IfAbort, IfSilent, IfErrors, IfRebootFlag - , "Get" // GetInstDirError, GetErrorLevel - , "Rename" - , "GetFullPathName" - , "SearchPath" - , "GetTempFileName" - , NULL // File - , "Delete" - , "MessageBox" - , "RMDir" - , "StrLen" - , NULL // StrCpy, GetCurrentAddress - , "StrCmp" - , NULL // ReadEnvStr, ExpandEnvStrings - , NULL // IntCmp / Int64Cmp / EW_INTCMP - , "IntOp" - , NULL // IntFmt / Int64Fmt / EW_INTFMT - , NULL // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. - , "FindWindow" - , "SendMessage" - , "IsWindow" - , "GetDlgItem" - , "SetCtlColors" - , "SetBrandingImage" - , "CreateFont" - , NULL // ShowWindow, EnableWindow, HideWindow - , "ExecShell" - , "Exec" // Exec, ExecWait - , "GetFileTime" - , "GetDLLVersion" - , NULL // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. - , "CreateShortCut" - , "CopyFiles" - , "Reboot" - , NULL // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI - , "ReadINIStr" - , "DeleteReg" // DeleteRegKey, DeleteRegValue - , "WriteReg" // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD - , "ReadReg" // ReadRegStr, ReadRegDWORD - , "EnumReg" // EnumRegKey, EnumRegValue - , "FileClose" - , "FileOpen" - , "FileWrite" // FileWrite, FileWriteByte - , "FileRead" // FileRead, FileReadByte - , "FileSeek" - , "FindClose" - , "FindNext" - , "FindFirst" - , "WriteUninstaller" - , "Section" // *** - , NULL // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType - - , NULL // "GetOsInfo" // , "GetLabelAddr" // - , "GetFunctionAddress" - - , "LockWindow" - , "FileWrite" // FileWriteUTF16LE, FileWriteWord - , "FileRead" // FileReadUTF16LE, FileReadWord - - , "Log" // LogSet, LogText - - // Park - , "FindProc" - , "GetFontVersion" - , "GetFontName" -}; - -#endif - -/* NSIS can use one name for two CSIDL_*** and CSIDL_COMMON_*** items (CurrentUser / AllUsers) - Some NSIS shell names are not identical to WIN32 CSIDL_* names. - NSIS doesn't use some CSIDL_* values. But we add name for all CSIDL_ (marked with '+'). */ - -static const char * const kShellStrings[] = -{ - "DESKTOP" // + - , "INTERNET" // + - , "SMPROGRAMS" // CSIDL_PROGRAMS - , "CONTROLS" // + - , "PRINTERS" // + - , "DOCUMENTS" // CSIDL_PERSONAL - , "FAVORITES" // CSIDL_FAVORITES - , "SMSTARTUP" // CSIDL_STARTUP - , "RECENT" // CSIDL_RECENT - , "SENDTO" // CSIDL_SENDTO - , "BITBUCKET" // + - , "STARTMENU" - , NULL // CSIDL_MYDOCUMENTS = CSIDL_PERSONAL - , "MUSIC" // CSIDL_MYMUSIC - , "VIDEOS" // CSIDL_MYVIDEO - , NULL - , "DESKTOP" // CSIDL_DESKTOPDIRECTORY - , "DRIVES" // + - , "NETWORK" // + - , "NETHOOD" - , "FONTS" - , "TEMPLATES" - , "STARTMENU" // CSIDL_COMMON_STARTMENU - , "SMPROGRAMS" // CSIDL_COMMON_PROGRAMS - , "SMSTARTUP" // CSIDL_COMMON_STARTUP - , "DESKTOP" // CSIDL_COMMON_DESKTOPDIRECTORY - , "APPDATA" // CSIDL_APPDATA !!! "QUICKLAUNCH" - , "PRINTHOOD" - , "LOCALAPPDATA" - , "ALTSTARTUP" - , "ALTSTARTUP" // CSIDL_COMMON_ALTSTARTUP - , "FAVORITES" // CSIDL_COMMON_FAVORITES - , "INTERNET_CACHE" - , "COOKIES" - , "HISTORY" - , "APPDATA" // CSIDL_COMMON_APPDATA - , "WINDIR" - , "SYSDIR" - , "PROGRAM_FILES" // + - , "PICTURES" // CSIDL_MYPICTURES - , "PROFILE" - , "SYSTEMX86" // + - , "PROGRAM_FILESX86" // + - , "PROGRAM_FILES_COMMON" // + - , "PROGRAM_FILES_COMMONX8" // + CSIDL_PROGRAM_FILES_COMMONX86 - , "TEMPLATES" // CSIDL_COMMON_TEMPLATES - , "DOCUMENTS" // CSIDL_COMMON_DOCUMENTS - , "ADMINTOOLS" // CSIDL_COMMON_ADMINTOOLS - , "ADMINTOOLS" // CSIDL_ADMINTOOLS - , "CONNECTIONS" // + - , NULL - , NULL - , NULL - , "MUSIC" // CSIDL_COMMON_MUSIC - , "PICTURES" // CSIDL_COMMON_PICTURES - , "VIDEOS" // CSIDL_COMMON_VIDEO - , "RESOURCES" - , "RESOURCES_LOCALIZED" - , "COMMON_OEM_LINKS" // + - , "CDBURN_AREA" - , NULL // unused - , "COMPUTERSNEARME" // + -}; - - -static inline void UIntToString(AString &s, UInt32 v) -{ - s.Add_UInt32(v); -} - -#ifdef NSIS_SCRIPT - -void CInArchive::Add_UInt(UInt32 v) -{ - char sz[16]; - ConvertUInt32ToString(v, sz); - Script += sz; -} - -static void Add_SignedInt(CDynLimBuf &s, Int32 v) -{ - char sz[32]; - ConvertInt64ToString(v, sz); - s += sz; -} - -static void Add_Hex(CDynLimBuf &s, UInt32 v) -{ - char sz[16]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt32ToHex(v, sz + 2); - s += sz; -} - -static UInt32 GetUi16Str_Len(const Byte *p) -{ - const Byte *pp = p; - for (; *pp != 0 || *(pp + 1) != 0; pp += 2); - return (UInt32)((pp - p) >> 1); -} - -void CInArchive::AddLicense(UInt32 param, Int32 langID) -{ - Space(); - if (param >= NumStringChars || - param + 1 >= NumStringChars) - { - Script += kErrorStr; - return; - } - strUsed[param] = 1; - - const UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param); - const UInt32 offset = start + (IsUnicode ? 2 : 1); - { - FOR_VECTOR (i, LicenseFiles) - { - const CLicenseFile &lic = LicenseFiles[i]; - if (offset == lic.Offset) - { - Script += lic.Name; - return; - } - } - } - AString fileName ("[LICENSE]"); - if (langID >= 0) - { - fileName += "\\license-"; - // LangId_To_String(fileName, langID); - UIntToString(fileName, (UInt32)langID); - } - else if (++_numRootLicenses > 1) - { - fileName.Add_Minus(); - UIntToString(fileName, _numRootLicenses); - } - const Byte *sz = (_data + start); - const unsigned marker = IsUnicode ? Get16(sz) : *sz; - const bool isRTF = (marker == 2); - fileName += isRTF ? ".rtf" : ".txt"; // if (*sz == 1) it's text; - Script += fileName; - - CLicenseFile &lic = LicenseFiles.AddNew(); - lic.Name = fileName; - lic.Offset = offset; - if (!IsUnicode) - lic.Size = (UInt32)strlen((const char *)sz + 1); - else - { - sz += 2; - const UInt32 len = GetUi16Str_Len(sz); - lic.Size = len * 2; - if (isRTF) - { - lic.Text.Alloc((size_t)len); - for (UInt32 i = 0; i < len; i++, sz += 2) - { - unsigned c = Get16(sz); - if (c >= 256) - c = '?'; - lic.Text[i] = (Byte)(c); - } - lic.Size = len; - lic.Offset = 0; - } - } -} - -#endif - - -#ifdef NSIS_SCRIPT -#define Z7_NSIS_WIN_GENERIC_READ ((UInt32)1 << 31) -#endif -#define Z7_NSIS_WIN_GENERIC_WRITE ((UInt32)1 << 30) -#ifdef NSIS_SCRIPT -#define Z7_NSIS_WIN_GENERIC_EXECUTE ((UInt32)1 << 29) -#define Z7_NSIS_WIN_GENERIC_ALL ((UInt32)1 << 28) -#endif - -#ifdef NSIS_SCRIPT -#define Z7_NSIS_WIN_CREATE_NEW 1 -#endif -#define Z7_NSIS_WIN_CREATE_ALWAYS 2 -#ifdef NSIS_SCRIPT -#define Z7_NSIS_WIN_OPEN_EXISTING 3 -#define Z7_NSIS_WIN_OPEN_ALWAYS 4 -#define Z7_NSIS_WIN_TRUNCATE_EXISTING 5 -#endif - - -// #define kVar_CMDLINE 20 -#define kVar_INSTDIR 21 -#define kVar_OUTDIR 22 -#define kVar_EXEDIR 23 -// #define kVar_LANGUAGE 24 -#define kVar_TEMP 25 -#define kVar_PLUGINSDIR 26 -#define kVar_EXEPATH 27 // NSIS 2.26+ -// #define kVar_EXEFILE 28 // NSIS 2.26+ - -#define kVar_HWNDPARENT_225 27 -#ifdef NSIS_SCRIPT -#define kVar_HWNDPARENT 29 -#endif - -// #define kVar__CLICK 30 -#define kVar_Spec_OUTDIR_225 29 // NSIS 2.04 - 2.25 -#define kVar_Spec_OUTDIR 31 // NSIS 2.26+ - - -static const char * const kVarStrings[] = -{ - "CMDLINE" - , "INSTDIR" - , "OUTDIR" - , "EXEDIR" - , "LANGUAGE" - , "TEMP" - , "PLUGINSDIR" - , "EXEPATH" // NSIS 2.26+ - , "EXEFILE" // NSIS 2.26+ - , "HWNDPARENT" - , "_CLICK" // is set from page->clicknext - , "_OUTDIR" // NSIS 2.04+ -}; - -static const unsigned kNumInternalVars = 20 + Z7_ARRAY_SIZE(kVarStrings); - -#define GET_NUM_INTERNAL_VARS (IsNsis200 ? kNumInternalVars - 3 : IsNsis225 ? kNumInternalVars - 2 : kNumInternalVars) - -void CInArchive::GetVar2(AString &res, UInt32 index) -{ - if (index < 20) - { - if (index >= 10) - { - res += 'R'; - index -= 10; - } - UIntToString(res, index); - } - else - { - unsigned numInternalVars = GET_NUM_INTERNAL_VARS; - if (index < numInternalVars) - { - if (IsNsis225 && index >= kVar_EXEPATH) - index += 2; - res += kVarStrings[index - 20]; - } - else - { - res += '_'; - UIntToString(res, index - numInternalVars); - res += '_'; - } - } -} - -void CInArchive::GetVar(AString &res, UInt32 index) -{ - res += '$'; - GetVar2(res, index); -} - -#ifdef NSIS_SCRIPT - -void CInArchive::Add_Var(UInt32 index) -{ - _tempString_for_GetVar.Empty(); - GetVar(_tempString_for_GetVar, index); - Script += _tempString_for_GetVar; -} - -void CInArchive::AddParam_Var(UInt32 index) -{ - Space(); - Add_Var(index); -} - -void CInArchive::AddParam_UInt(UInt32 value) -{ - Space(); - Add_UInt(value); -} - -#endif - - -#define NS_CODE_SKIP 252 -#define NS_CODE_VAR 253 -#define NS_CODE_SHELL 254 -// #define NS_CODE_LANG 255 - -// #define NS_3_CODE_LANG 1 -#define NS_3_CODE_SHELL 2 -#define NS_3_CODE_VAR 3 -#define NS_3_CODE_SKIP 4 - -#define PARK_CODE_SKIP 0xE000 -#define PARK_CODE_VAR 0xE001 -#define PARK_CODE_SHELL 0xE002 -#define PARK_CODE_LANG 0xE003 - -#define IS_NS_SPEC_CHAR(c) ((c) >= NS_CODE_SKIP) -#define IS_PARK_SPEC_CHAR(c) ((c) >= PARK_CODE_SKIP && (c) <= PARK_CODE_LANG) - -#define DECODE_NUMBER_FROM_2_CHARS(c0, c1) (((unsigned)(c0) & 0x7F) | (((unsigned)((c1) & 0x7F)) << 7)) -#define CONVERT_NUMBER_NS_3_UNICODE(n) n = ((n & 0x7F) | (((n >> 8) & 0x7F) << 7)) -#define CONVERT_NUMBER_PARK(n) n &= 0x7FFF - - -static bool AreStringsEqual_16and8(const Byte *p16, const char *p8) -{ - for (;;) - { - unsigned c16 = Get16(p16); p16 += 2; - unsigned c = (Byte)(*p8++); - if (c16 != c) - return false; - if (c == 0) - return true; - } -} - -void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) -{ - // zeros are not allowed here. - // if (index1 == 0 || index2 == 0) throw 333; - - if ((index1 & 0x80) != 0) - { - unsigned offset = (index1 & 0x3F); - - /* NSIS reads registry string: - keyName = HKLM Software\\Microsoft\\Windows\\CurrentVersion - mask = KEY_WOW64_64KEY, If 64-bit flag in index1 is set - valueName = string(offset) - If registry reading is failed, NSIS uses second parameter (index2) - to read string. The recursion is possible in that case in NSIS. - We don't parse index2 string. We only set strUsed status for that - string (but without recursion). */ - - if (offset >= NumStringChars) - { - s += kErrorStr; - return; - } - - #ifdef NSIS_SCRIPT - strUsed[offset] = 1; - if (index2 < NumStringChars) - strUsed[index2] = 1; - #endif - - const Byte *p = (const Byte *)(_data + _stringsPos); - int id = -1; - if (IsUnicode) - { - p += offset * 2; - if (AreStringsEqual_16and8(p, "ProgramFilesDir")) - id = 0; - else if (AreStringsEqual_16and8(p, "CommonFilesDir")) - id = 1; - } - else - { - p += offset; - if (strcmp((const char *)p, "ProgramFilesDir") == 0) - id = 0; - else if (strcmp((const char *)p, "CommonFilesDir") == 0) - id = 1; - } - - s += ((id >= 0) ? (id == 0 ? "$PROGRAMFILES" : "$COMMONFILES") : - "$_ERROR_UNSUPPORTED_VALUE_REGISTRY_"); - // s += ((index1 & 0x40) != 0) ? "64" : "32"; - if ((index1 & 0x40) != 0) - s += "64"; - - if (id < 0) - { - s += '('; - if (IsUnicode) - { - for (unsigned i = 0; i < 256; i++) - { - wchar_t c = Get16(p + i * 2); - if (c == 0) - break; - if (c < 0x80) - s += (char)c; - } - } - else - s += (const char *)p; - s += ')'; - } - return; - } - - s += '$'; - if (index1 < Z7_ARRAY_SIZE(kShellStrings)) - { - const char *sz = kShellStrings[index1]; - if (sz) - { - s += sz; - return; - } - } - if (index2 < Z7_ARRAY_SIZE(kShellStrings)) - { - const char *sz = kShellStrings[index2]; - if (sz) - { - s += sz; - return; - } - } - s += "_ERROR_UNSUPPORTED_SHELL_"; - s += '['; - UIntToString(s, index1); - s += ','; - UIntToString(s, index2); - s += ']'; -} - -#ifdef NSIS_SCRIPT - -void CInArchive::Add_LangStr_Simple(UInt32 id) -{ - Script += "LSTR_"; - Add_UInt(id); -} - -#endif - -void CInArchive::Add_LangStr(AString &res, UInt32 id) -{ - #ifdef NSIS_SCRIPT - langStrIDs.Add(id); - #endif - res += "$(LSTR_"; - UIntToString(res, id); - res += ')'; -} - -void CInArchive::GetNsisString_Raw(const Byte *s) -{ - Raw_AString.Empty(); - - if (NsisType != k_NsisType_Nsis3) - { - for (;;) - { - Byte c = *s++; - if (c == 0) - return; - if (IS_NS_SPEC_CHAR(c)) - { - Byte c0 = *s++; - if (c0 == 0) - return; - if (c != NS_CODE_SKIP) - { - Byte c1 = *s++; - if (c1 == 0) - return; - - if (c == NS_CODE_SHELL) - GetShellString(Raw_AString, c0, c1); - else - { - unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); - if (c == NS_CODE_VAR) - GetVar(Raw_AString, n); - else // if (c == NS_CODE_LANG) - Add_LangStr(Raw_AString, n); - } - continue; - } - c = c0; - } - Raw_AString += (char)c; - } - } - - // NSIS-3 ANSI - for (;;) - { - Byte c = *s++; - if (c <= NS_3_CODE_SKIP) - { - if (c == 0) - return; - Byte c0 = *s++; - if (c0 == 0) - return; - if (c != NS_3_CODE_SKIP) - { - Byte c1 = *s++; - if (c1 == 0) - return; - - if (c == NS_3_CODE_SHELL) - GetShellString(Raw_AString, c0, c1); - else - { - unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); - if (c == NS_3_CODE_VAR) - GetVar(Raw_AString, n); - else // if (c == NS_3_CODE_LANG) - Add_LangStr(Raw_AString, n); - } - continue; - } - c = c0; - } - Raw_AString += (char)c; - } -} - -#ifdef NSIS_SCRIPT - -void CInArchive::GetNsisString(AString &res, const Byte *s) -{ - for (;;) - { - Byte c = *s++; - if (c == 0) - return; - if (NsisType != k_NsisType_Nsis3) - { - if (IS_NS_SPEC_CHAR(c)) - { - Byte c0 = *s++; - if (c0 == 0) - return; - if (c != NS_CODE_SKIP) - { - Byte c1 = *s++; - if (c1 == 0) - return; - if (c == NS_CODE_SHELL) - GetShellString(res, c0, c1); - else - { - unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); - if (c == NS_CODE_VAR) - GetVar(res, n); - else // if (c == NS_CODE_LANG) - Add_LangStr(res, n); - } - continue; - } - c = c0; - } - } - else - { - // NSIS-3 ANSI - if (c <= NS_3_CODE_SKIP) - { - Byte c0 = *s++; - if (c0 == 0) - return; - if (c0 == 0) - break; - if (c != NS_3_CODE_SKIP) - { - Byte c1 = *s++; - if (c1 == 0) - return; - if (c == NS_3_CODE_SHELL) - GetShellString(res, c0, c1); - else - { - unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); - if (c == NS_3_CODE_VAR) - GetVar(res, n); - else // if (c == NS_3_CODE_LANG) - Add_LangStr(res, n); - } - continue; - } - c = c0; - } - } - - { - const char *e; - if (c == 9) e = "$\\t"; - else if (c == 10) e = "$\\n"; - else if (c == 13) e = "$\\r"; - else if (c == '"') e = "$\\\""; - else if (c == '$') e = "$$"; - else - { - res += (char)c; - continue; - } - res += e; - continue; - } - } -} - -#endif - -void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) -{ - Raw_UString.Empty(); - - if (IsPark()) - { - for (;;) - { - unsigned c = Get16(p); - p += 2; - if (c == 0) - break; - if (c < 0x80) - { - Raw_UString.Add_Char((char)c); - continue; - } - - if (IS_PARK_SPEC_CHAR(c)) - { - unsigned n = Get16(p); - p += 2; - if (n == 0) - break; - if (c != PARK_CODE_SKIP) - { - Raw_AString.Empty(); - if (c == PARK_CODE_SHELL) - GetShellString(Raw_AString, n & 0xFF, n >> 8); - else - { - CONVERT_NUMBER_PARK(n); - if (c == PARK_CODE_VAR) - GetVar(Raw_AString, n); - else // if (c == PARK_CODE_LANG) - Add_LangStr(Raw_AString, n); - } - Raw_UString += Raw_AString.Ptr(); // check it ! - continue; - } - c = n; - } - - Raw_UString += (wchar_t)c; - } - - return; - } - - // NSIS-3 Unicode - for (;;) - { - unsigned c = Get16(p); - p += 2; - if (c > NS_3_CODE_SKIP) - { - Raw_UString += (wchar_t)c; - continue; - } - if (c == 0) - break; - - unsigned n = Get16(p); - p += 2; - if (n == 0) - break; - if (c == NS_3_CODE_SKIP) - { - Raw_UString += (wchar_t)n; - continue; - } - - Raw_AString.Empty(); - if (c == NS_3_CODE_SHELL) - GetShellString(Raw_AString, n & 0xFF, n >> 8); - else - { - CONVERT_NUMBER_NS_3_UNICODE(n); - if (c == NS_3_CODE_VAR) - GetVar(Raw_AString, n); - else // if (c == NS_3_CODE_LANG) - Add_LangStr(Raw_AString, n); - } - Raw_UString += Raw_AString.Ptr(); - } -} - -#ifdef NSIS_SCRIPT - -static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p) -{ - for (;;) - { - unsigned c = Get16(p); - p += 2; - if (c == 0) - break; - if (IsPark()) - { - if (IS_PARK_SPEC_CHAR(c)) - { - unsigned n = Get16(p); - p += 2; - if (n == 0) - break; - if (c != PARK_CODE_SKIP) - { - if (c == PARK_CODE_SHELL) - GetShellString(res, n & 0xFF, n >> 8); - else - { - CONVERT_NUMBER_PARK(n); - if (c == PARK_CODE_VAR) - GetVar(res, n); - else // if (c == PARK_CODE_LANG) - Add_LangStr(res, n); - } - continue; - } - c = n; - } - } - else - { - // NSIS-3 Unicode - if (c <= NS_3_CODE_SKIP) - { - unsigned n = Get16(p); - p += 2; - if (n == 0) - break; - if (c != NS_3_CODE_SKIP) - { - if (c == NS_3_CODE_SHELL) - GetShellString(res, n & 0xFF, n >> 8); - else - { - CONVERT_NUMBER_NS_3_UNICODE(n); - if (c == NS_3_CODE_VAR) - GetVar(res, n); - else // if (c == NS_3_CODE_LANG) - Add_LangStr(res, n); - } - continue; - } - c = n; - } - } - - if (c < 0x80) - { - const char *e; - if (c == 9) e = "$\\t"; - else if (c == 10) e = "$\\n"; - else if (c == 13) e = "$\\r"; - else if (c == '"') e = "$\\\""; - else if (c == '$') e = "$$"; - else - { - res += (char)c; - continue; - } - res += e; - continue; - } - - UInt32 value = c; - /* - if (value >= 0xD800 && value < 0xE000) - { - UInt32 c2; - if (value >= 0xDC00 || srcPos == srcLen) - break; - c2 = src[srcPos++]; - if (c2 < 0xDC00 || c2 >= 0xE000) - break; - value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; - } - */ - unsigned numAdds; - for (numAdds = 1; numAdds < 5; numAdds++) - if (value < (((UInt32)1) << (numAdds * 5 + 6))) - break; - res += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); - do - { - numAdds--; - res += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); - // destPos++; - } - while (numAdds != 0); - - // AddToUtf8(res, c); - } -} - -#endif - -void CInArchive::ReadString2_Raw(UInt32 pos) -{ - Raw_AString.Empty(); - Raw_UString.Empty(); - if ((Int32)pos < 0) - Add_LangStr(Raw_AString, (UInt32)-((Int32)pos + 1)); - else if (pos >= NumStringChars) - { - Raw_AString += kErrorStr; - // UIntToString(Raw_AString, pos); - } - else - { - if (IsUnicode) - GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2); - else - GetNsisString_Raw(_data + _stringsPos + pos); - return; - } - Raw_UString = Raw_AString.Ptr(); -} - -bool CInArchive::IsGoodString(UInt32 param) const -{ - if (param >= NumStringChars) - return false; - if (param == 0) - return true; - const Byte *p = _data + _stringsPos; - unsigned c; - if (IsUnicode) - c = Get16(p + param * 2 - 2); - else - c = p[param - 1]; - // some files have '\\' character before string? - return (c == 0 || c == '\\'); -} - -bool CInArchive::AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const -{ - if (param1 == param2) - return true; - - /* NSIS-3.0a1 probably contains bug, so it can use 2 different strings - with same content. So we check real string also. - Also it's possible to check identical postfix parts of strings. */ - - if (param1 >= NumStringChars || - param2 >= NumStringChars) - return false; - - const Byte *p = _data + _stringsPos; - - if (IsUnicode) - { - const Byte *p1 = p + param1 * 2; - const Byte *p2 = p + param2 * 2; - for (;;) - { - UInt16 c = Get16(p1); - if (c != Get16(p2)) - return false; - if (c == 0) - return true; - p1 += 2; - p2 += 2; - } - } - else - { - const Byte *p1 = p + param1; - const Byte *p2 = p + param2; - for (;;) - { - Byte c = *p1++; - if (c != *p2++) - return false; - if (c == 0) - return true; - } - } -} - -#ifdef NSIS_SCRIPT - -UInt32 CInArchive::GetNumUsedVars() const -{ - UInt32 numUsedVars = 0; - const Byte *data = (const Byte *)_data + _stringsPos; - unsigned npi = 0; - for (UInt32 i = 0; i < NumStringChars;) - { - bool process = true; - if (npi < noParseStringIndexes.Size() && noParseStringIndexes[npi] == i) - { - process = false; - npi++; - } - - if (IsUnicode) - { - if (IsPark()) - { - for (;;) - { - unsigned c = Get16(data + i * 2); - i++; - if (c == 0) - break; - if (IS_PARK_SPEC_CHAR(c)) - { - UInt32 n = Get16(data + i * 2); - i++; - if (n == 0) - break; - if (process && c == PARK_CODE_VAR) - { - CONVERT_NUMBER_PARK(n); - n++; - if (numUsedVars < n) - numUsedVars = n; - } - } - } - } - else // NSIS-3 Unicode - { - for (;;) - { - unsigned c = Get16(data + i * 2); - i++; - if (c == 0) - break; - if (c > NS_3_CODE_SKIP) - continue; - UInt32 n = Get16(data + i * 2); - i++; - if (n == 0) - break; - if (process && c == NS_3_CODE_VAR) - { - CONVERT_NUMBER_NS_3_UNICODE(n); - n++; - if (numUsedVars < n) - numUsedVars = n; - } - } - } - } - else // not Unicode (ANSI) - { - if (NsisType != k_NsisType_Nsis3) - { - for (;;) - { - Byte c = data[i++]; - if (c == 0) - break; - if (IS_NS_SPEC_CHAR(c)) - { - Byte c0 = data[i++]; - if (c0 == 0) - break; - if (c == NS_CODE_SKIP) - continue; - Byte c1 = data[i++]; - if (c1 == 0) - break; - if (process && c == NS_CODE_VAR) - { - UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); - n++; - if (numUsedVars < n) - numUsedVars = n; - } - } - } - } - else - { - // NSIS-3 ANSI - for (;;) - { - Byte c = data[i++]; - if (c == 0) - break; - if (c > NS_3_CODE_SKIP) - continue; - - Byte c0 = data[i++]; - if (c0 == 0) - break; - if (c == NS_3_CODE_SKIP) - continue; - Byte c1 = data[i++]; - if (c1 == 0) - break; - if (process && c == NS_3_CODE_VAR) - { - UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); - n++; - if (numUsedVars < n) - numUsedVars = n; - } - } - } - } - } - return numUsedVars; -} - -void CInArchive::ReadString2(AString &s, UInt32 pos) -{ - if ((Int32)pos < 0) - { - Add_LangStr(s, (UInt32)-((Int32)pos + 1)); - return; - } - - if (pos >= NumStringChars) - { - s += kErrorStr; - // UIntToString(s, pos); - return; - } - - #ifdef NSIS_SCRIPT - strUsed[pos] = 1; - #endif - - if (IsUnicode) - GetNsisString_Unicode(s, _data + _stringsPos + pos * 2); - else - GetNsisString(s, _data + _stringsPos + pos); -} - -#endif - -#ifdef NSIS_SCRIPT - -// #define DEL_DIR 1 -#define DEL_RECURSE 2 -#define DEL_REBOOT 4 -// #define DEL_SIMPLE 8 - -void CInArchive::AddRegRoot(UInt32 val) -{ - Space(); - const char *s; - switch (val) - { - case 0: s = "SHCTX"; break; - case 0x80000000: s = "HKCR"; break; - case 0x80000001: s = "HKCU"; break; - case 0x80000002: s = "HKLM"; break; - case 0x80000003: s = "HKU"; break; - case 0x80000004: s = "HKPD"; break; - case 0x80000005: s = "HKCC"; break; - case 0x80000006: s = "HKDD"; break; - case 0x80000050: s = "HKPT"; break; - case 0x80000060: s = "HKPN"; break; - default: - // Script += " RRRRR "; - // throw 1; - Add_Hex(Script, val); return; - } - Script += s; -} - -static const char * const g_WinAttrib[] = -{ - "READONLY" - , "HIDDEN" - , "SYSTEM" - , NULL - , "DIRECTORY" - , "ARCHIVE" - , "DEVICE" - , "NORMAL" - , "TEMPORARY" - , "SPARSE_FILE" - , "REPARSE_POINT" - , "COMPRESSED" - , "OFFLINE" - , "NOT_CONTENT_INDEXED" - , "ENCRYPTED" - , NULL - , "VIRTUAL" -}; - -#define FLAGS_DELIMITER '|' - -static void FlagsToString2(CDynLimBuf &s, const char * const *table, unsigned num, UInt32 flags) -{ - bool filled = false; - for (unsigned i = 0; i < num; i++) - { - UInt32 f = (UInt32)1 << i; - if ((flags & f) != 0) - { - const char *name = table[i]; - if (name) - { - if (filled) - s += FLAGS_DELIMITER; - filled = true; - s += name; - flags &= ~f; - } - } - } - if (flags != 0) - { - if (filled) - s += FLAGS_DELIMITER; - Add_Hex(s, flags); - } -} - -static bool DoesNeedQuotes(const char *s) -{ - { - char c = s[0]; - if (c == 0 || c == '#' || c == ';' || (c == '/' && s[1] == '*')) - return true; - } - for (;;) - { - char c = *s++; - if (c == 0) - return false; - if (c == ' ') - return true; - } -} - -void CInArchive::Add_QuStr(const AString &s) -{ - bool needQuotes = DoesNeedQuotes(s); - if (needQuotes) - Script += '\"'; - Script += s; - if (needQuotes) - Script += '\"'; -} - -void CInArchive::SpaceQuStr(const AString &s) -{ - Space(); - Add_QuStr(s); -} - -void CInArchive::AddParam(UInt32 pos) -{ - _tempString.Empty(); - ReadString2(_tempString, pos); - SpaceQuStr(_tempString); -} - -void CInArchive::AddParams(const UInt32 *params, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - AddParam(params[i]); -} - -void CInArchive::AddOptionalParam(UInt32 pos) -{ - if (pos != 0) - AddParam(pos); -} - -static unsigned GetNumParams(const UInt32 *params, unsigned num) -{ - for (; num > 0 && params[num - 1] == 0; num--); - return num; -} - -void CInArchive::AddOptionalParams(const UInt32 *params, unsigned num) -{ - AddParams(params, GetNumParams(params, num)); -} - - -static const UInt32 CMD_REF_Goto = (1 << 0); -static const UInt32 CMD_REF_Call = (1 << 1); -static const UInt32 CMD_REF_Pre = (1 << 2); -static const UInt32 CMD_REF_Show = (1 << 3); -static const UInt32 CMD_REF_Leave = (1 << 4); -static const UInt32 CMD_REF_OnFunc = (1 << 5); -static const UInt32 CMD_REF_Section = (1 << 6); -static const UInt32 CMD_REF_InitPluginDir = (1 << 7); -// static const UInt32 CMD_REF_Creator = (1 << 5); // CMD_REF_Pre is used instead -static const unsigned CMD_REF_OnFunc_NumShifts = 28; // it uses for onFunc too -static const unsigned CMD_REF_Page_NumShifts = 16; // it uses for onFunc too -static const UInt32 CMD_REF_Page_Mask = 0x0FFF0000; -static const UInt32 CMD_REF_OnFunc_Mask = 0xF0000000; - -inline bool IsPageFunc(UInt32 flag) -{ - return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave)) != 0; -} - -inline bool IsFunc(UInt32 flag) -{ - // return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; - return (flag & (CMD_REF_Call | CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; -} - -inline bool IsProbablyEndOfFunc(UInt32 flag) -{ - return (flag != 0 && flag != CMD_REF_Goto); -} - -static const char * const kOnFunc[] = -{ - "Init" - , "InstSuccess" - , "InstFailed" - , "UserAbort" - , "GUIInit" - , "GUIEnd" - , "MouseOverSection" - , "VerifyInstDir" - , "SelChange" - , "RebootFailed" -}; - -void CInArchive::Add_FuncName(const UInt32 *labels, UInt32 index) -{ - UInt32 mask = labels[index]; - if (mask & CMD_REF_OnFunc) - { - Script += ".on"; - Script += kOnFunc[labels[index] >> CMD_REF_OnFunc_NumShifts]; - } - else if (mask & CMD_REF_InitPluginDir) - { - /* - if (!IsInstaller) - Script += "un." - */ - Script += "Initialize_____Plugins"; - } - else - { - Script += "func_"; - Add_UInt(index); - } -} - -void CInArchive::AddParam_Func(const UInt32 *labels, UInt32 index) -{ - Space(); - if ((Int32)index >= 0) - Add_FuncName(labels, index); - else - AddQuotes(); -} - - -void CInArchive::Add_LabelName(UInt32 index) -{ - Script += "label_"; - Add_UInt(index); -} - -// param != 0 -void CInArchive::Add_GotoVar(UInt32 param) -{ - Space(); - if ((Int32)param < 0) - Add_Var((UInt32)-((Int32)param + 1)); - else - Add_LabelName(param - 1); -} - -void CInArchive::Add_GotoVar1(UInt32 param) -{ - if (param == 0) - Script += " 0"; - else - Add_GotoVar(param); -} - -void CInArchive::Add_GotoVars2(const UInt32 *params) -{ - Add_GotoVar1(params[0]); - if (params[1] != 0) - Add_GotoVar(params[1]); -} - -static bool NoLabels(const UInt32 *labels, UInt32 num) -{ - for (UInt32 i = 0; i < num; i++) - if (labels[i] != 0) - return false; - return true; -} - -static const char * const k_REBOOTOK = " /REBOOTOK"; - -#define Z7_NSIS_WIN_MB_ABORTRETRYIGNORE 2 -#define Z7_NSIS_WIN_MB_RETRYCANCEL 5 - -static const char * const k_MB_Buttons[] = -{ - "OK" - , "OKCANCEL" - , "ABORTRETRYIGNORE" - , "YESNOCANCEL" - , "YESNO" - , "RETRYCANCEL" - , "CANCELTRYCONTINUE" -}; - -#define Z7_NSIS_WIN_MB_ICONSTOP (1 << 4) - -static const char * const k_MB_Icons[] = -{ - NULL - , "ICONSTOP" - , "ICONQUESTION" - , "ICONEXCLAMATION" - , "ICONINFORMATION" -}; - -static const char * const k_MB_Flags[] = -{ - "HELP" - , "NOFOCUS" - , "SETFOREGROUND" - , "DEFAULT_DESKTOP_ONLY" - , "TOPMOST" - , "RIGHT" - , "RTLREADING" - // , "SERVICE_NOTIFICATION" // unsupported. That bit is used for NSIS purposes -}; - -#define Z7_NSIS_WIN_IDCANCEL 2 -#define Z7_NSIS_WIN_IDIGNORE 5 - -static const char * const k_Button_IDs[] = -{ - "0" - , "IDOK" - , "IDCANCEL" - , "IDABORT" - , "IDRETRY" - , "IDIGNORE" - , "IDYES" - , "IDNO" - , "IDCLOSE" - , "IDHELP" - , "IDTRYAGAIN" - , "IDCONTINUE" -}; - -void CInArchive::Add_ButtonID(UInt32 buttonID) -{ - Space(); - if (buttonID < Z7_ARRAY_SIZE(k_Button_IDs)) - Script += k_Button_IDs[buttonID]; - else - { - Script += "Button_"; - Add_UInt(buttonID); - } -} - -bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const -{ - if (offset >= NumStringChars) - return false; - if (IsUnicode) - return AreStringsEqual_16and8(_data + _stringsPos + offset * 2, s); - else - return strcmp((const char *)(const Byte *)_data + _stringsPos + offset, s) == 0; -} - -static bool StringToUInt32(const char *s, UInt32 &res) -{ - const char *end; - if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) - res = ConvertHexStringToUInt32(s + 2, &end); - else - res = ConvertStringToUInt32(s, &end); - return (*end == 0); -} - -static const unsigned k_CtlColors32_Size = 24; -static const unsigned k_CtlColors64_Size = 28; - -#define GET_CtlColors_SIZE(is64) ((is64) ? k_CtlColors64_Size : k_CtlColors32_Size) - -struct CNsis_CtlColors -{ - UInt32 text; // COLORREF - UInt32 bkc; // COLORREF - UInt32 lbStyle; - UInt32 bkb; // HBRUSH - Int32 bkmode; - Int32 flags; - UInt32 bkb_hi32; - - void Parse(const Byte *p, bool is64); -}; - -void CNsis_CtlColors::Parse(const Byte *p, bool is64) -{ - text = Get32(p); - bkc = Get32(p + 4); - if (is64) - { - bkb = Get32(p + 8); - bkb_hi32 = Get32(p + 12); - lbStyle = Get32(p + 16); - p += 4; - } - else - { - lbStyle = Get32(p + 8); - bkb = Get32(p + 12); - } - bkmode = (Int32)Get32(p + 16); - flags = (Int32)Get32(p + 20); -} - -// Win32 constants -#define Z7_NSIS_WIN_TRANSPARENT 1 -// #define Z7_NSIS_WIN_OPAQUE 2 - -// text/bg colors -#define kColorsFlags_TEXT 1 -#define kColorsFlags_TEXT_SYS 2 -#define kColorsFlags_BK 4 -#define kColorsFlags_BK_SYS 8 -#define kColorsFlags_BKB 16 - -void CInArchive::Add_Color2(UInt32 v) -{ - v = ((v & 0xFF) << 16) | (v & 0xFF00) | ((v >> 16) & 0xFF); - char sz[32]; - for (int i = 5; i >= 0; i--) - { - unsigned t = v & 0xF; - v >>= 4; - sz[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); - } - sz[6] = 0; - Script += sz; -} - -void CInArchive::Add_ColorParam(UInt32 v) -{ - Space(); - Add_Color2(v); -} - -void CInArchive::Add_Color(UInt32 v) -{ - Script += "0x"; - Add_Color2(v); -} - -#define Z7_NSIS_WIN_SW_HIDE 0 -#define Z7_NSIS_WIN_SW_SHOWNORMAL 1 - -#define Z7_NSIS_WIN_SW_SHOWMINIMIZED 2 -#define Z7_NSIS_WIN_SW_SHOWMINNOACTIVE 7 -#define Z7_NSIS_WIN_SW_SHOWNA 8 - -static const char * const kShowWindow_Commands[] = -{ - "HIDE" - , "SHOWNORMAL" // "NORMAL" - , "SHOWMINIMIZED" - , "SHOWMAXIMIZED" // "MAXIMIZE" - , "SHOWNOACTIVATE" - , "SHOW" - , "MINIMIZE" - , "SHOWMINNOACTIVE" - , "SHOWNA" - , "RESTORE" - , "SHOWDEFAULT" - , "FORCEMINIMIZE" // "MAX" -}; - -static void Add_ShowWindow_Cmd_2(AString &s, UInt32 cmd) -{ - if (cmd < Z7_ARRAY_SIZE(kShowWindow_Commands)) - { - s += "SW_"; - s += kShowWindow_Commands[cmd]; - } - else - UIntToString(s, cmd); -} - -void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) -{ - if (cmd < Z7_ARRAY_SIZE(kShowWindow_Commands)) - { - Script += "SW_"; - Script += kShowWindow_Commands[cmd]; - } - else - Add_UInt(cmd); -} - -void CInArchive::Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type) -{ - if (type < tableSize) - Script += table[type]; - else - { - Script += '_'; - Add_UInt(type); - } -} - -#define ADD_TYPE_FROM_LIST(table, type) Add_TypeFromList(table, Z7_ARRAY_SIZE(table), type) - -enum -{ - k_ExecFlags_AutoClose, - k_ExecFlags_ShellVarContext, - k_ExecFlags_Errors, - k_ExecFlags_Abort, - k_ExecFlags_RebootFlag, - k_ExecFlags_reboot_called, - k_ExecFlags_cur_insttype, - k_ExecFlags_plugin_api_version, - k_ExecFlags_Silent, - k_ExecFlags_InstDirError, - k_ExecFlags_rtl, - k_ExecFlags_ErrorLevel, - k_ExecFlags_RegView, - k_ExecFlags_DetailsPrint = 13 -}; - -// Names for NSIS exec_flags_t structure vars -static const char * const kExecFlags_VarsNames[] = -{ - "AutoClose" // autoclose; - , "ShellVarContext" // all_user_var; - , "Errors" // exec_error; - , "Abort" // abort; - , "RebootFlag" // exec_reboot; // NSIS_SUPPORT_REBOOT - , "reboot_called" // reboot_called; // NSIS_SUPPORT_REBOOT - , "cur_insttype" // XXX_cur_insttype; // depreacted - , "plugin_api_version" // plugin_api_version; // see NSISPIAPIVER_CURR - // used to be XXX_insttype_changed - , "Silent" // silent; // NSIS_CONFIG_SILENT_SUPPORT - , "InstDirError" // instdir_error; - , "rtl" // rtl; - , "ErrorLevel" // errlvl; - , "RegView" // alter_reg_view; - , "DetailsPrint" // status_update; -}; - -void CInArchive::Add_ExecFlags(UInt32 flagsType) -{ - ADD_TYPE_FROM_LIST(kExecFlags_VarsNames, flagsType); -} - - -// ---------- Page ---------- - -// page flags -#define PF_CANCEL_ENABLE 4 -#define PF_LICENSE_FORCE_SELECTION 32 -#define PF_LICENSE_NO_FORCE_SELECTION 64 -#define PF_PAGE_EX 512 -#define PF_DIR_NO_BTN_DISABLE 1024 -/* -#define PF_LICENSE_SELECTED 1 -#define PF_NEXT_ENABLE 2 -#define PF_BACK_SHOW 8 -#define PF_LICENSE_STREAM 16 -#define PF_NO_NEXT_FOCUS 128 -#define PF_BACK_ENABLE 256 -*/ - -// page window proc -enum -{ - PWP_LICENSE, - PWP_SELCOM, - PWP_DIR, - PWP_INSTFILES, - PWP_UNINST, - PWP_COMPLETED, - PWP_CUSTOM -}; - -static const char * const kPageTypes[] = -{ - "license" - , "components" - , "directory" - , "instfiles" - , "uninstConfirm" - , "COMPLETED" - , "custom" -}; - -#define SET_FUNC_REF(x, flag) if ((Int32)(x) >= 0 && (x) < bh.Num) \ - { labels[x] = (labels[x] & ~CMD_REF_Page_Mask) | ((flag) | (pageIndex << CMD_REF_Page_NumShifts)); } - -// #define IDD_LICENSE 102 -#define IDD_LICENSE_FSRB 108 -#define IDD_LICENSE_FSCB 109 - -void CInArchive::AddPageOption1(UInt32 param, const char *name) -{ - if (param == 0) - return; - TabString(name); - AddParam(param); - NewLine(); -} - -void CInArchive::AddPageOption(const UInt32 *params, unsigned num, const char *name) -{ - num = GetNumParams(params, num); - if (num == 0) - return; - TabString(name); - AddParams(params, num); - NewLine(); -} - -void CInArchive::Separator() -{ - AddLF(); - AddCommentAndString("--------------------"); - AddLF(); -} - -void CInArchive::Space() -{ - Script += ' '; -} - -void CInArchive::Tab() -{ - Script += " "; -} - -void CInArchive::Tab(bool commented) -{ - Script += commented ? " ; " : " "; -} - -void CInArchive::BigSpaceComment() -{ - Script += " ; "; -} - -void CInArchive::SmallSpaceComment() -{ - Script += " ; "; -} - -void CInArchive::AddCommentAndString(const char *s) -{ - Script += "; "; - Script += s; -} - -void CInArchive::AddError(const char *s) -{ - BigSpaceComment(); - Script += "!!! ERROR: "; - Script += s; -} - -void CInArchive::AddErrorLF(const char *s) -{ - AddError(s); - AddLF(); -} - -void CInArchive::CommentOpen() -{ - AddStringLF("/*"); -} - -void CInArchive::CommentClose() -{ - AddStringLF("*/"); -} - -void CInArchive::AddLF() -{ - Script += CR_LF; -} - -void CInArchive::AddQuotes() -{ - Script += "\"\""; -} - -void CInArchive::TabString(const char *s) -{ - Tab(); - Script += s; -} - -void CInArchive::AddStringLF(const char *s) -{ - Script += s; - AddLF(); -} - -// ---------- Section ---------- - -static const char * const kSection_VarsNames[] = -{ - "Text" - , "InstTypes" - , "Flags" - , "Code" - , "CodeSize" - , "Size" // size in KB -}; - -void CInArchive::Add_SectOp(UInt32 opType) -{ - ADD_TYPE_FROM_LIST(kSection_VarsNames, opType); -} - -void CSection::Parse(const Byte *p) -{ - Name = Get32(p); - InstallTypes = Get32(p + 4); - Flags = Get32(p + 8); - StartCmdIndex = Get32(p + 12); - NumCommands = Get32(p + 16); - SizeKB = Get32(p + 20); -} - -// used for section->flags -#define SF_SELECTED (1 << 0) -#define SF_SECGRP (1 << 1) -#define SF_SECGRPEND (1 << 2) -#define SF_BOLD (1 << 3) -#define SF_RO (1 << 4) -#define SF_EXPAND (1 << 5) -/* -#define SF_PSELECTED (1 << 6) -#define SF_TOGGLED (1 << 7) -#define SF_NAMECHG (1 << 8) -*/ - -bool CInArchive::PrintSectionBegin(const CSection §, unsigned index) -{ - AString name; - if (sect.Flags & SF_BOLD) - name += '!'; - AString s2; - ReadString2(s2, sect.Name); - if (!IsInstaller) - { - if (!StringsAreEqualNoCase_Ascii(s2, "uninstall")) - name += "un."; - } - name += s2; - - if (sect.Flags & SF_SECGRPEND) - { - AddStringLF("SectionGroupEnd"); - return true; - } - - if (sect.Flags & SF_SECGRP) - { - Script += "SectionGroup"; - if (sect.Flags & SF_EXPAND) - Script += " /e"; - SpaceQuStr(name); - Script += " ; Section"; - AddParam_UInt(index); - NewLine(); - return true; - } - - Script += "Section"; - if ((sect.Flags & SF_SELECTED) == 0) - Script += " /o"; - if (!name.IsEmpty()) - SpaceQuStr(name); - - /* - if (!name.IsEmpty()) - Script += ' '; - else - */ - SmallSpaceComment(); - Script += "Section_"; - Add_UInt(index); - - /* - Script += " ; flags = "; - Add_Hex(Script, sect.Flags); - */ - - NewLine(); - - if (sect.SizeKB != 0) - { - // probably we must show AddSize, only if there is additional size. - Tab(); - AddCommentAndString("AddSize"); - AddParam_UInt(sect.SizeKB); - AddLF(); - } - - bool needSectionIn = - (sect.Name != 0 && sect.InstallTypes != 0) || - (sect.Name == 0 && sect.InstallTypes != 0xFFFFFFFF); - if (needSectionIn || (sect.Flags & SF_RO) != 0) - { - TabString("SectionIn"); - UInt32 instTypes = sect.InstallTypes; - for (unsigned i = 0; i < 32; i++, instTypes >>= 1) - if ((instTypes & 1) != 0) - { - AddParam_UInt(i + 1); - } - if ((sect.Flags & SF_RO) != 0) - Script += " RO"; - AddLF(); - } - return false; -} - -void CInArchive::PrintSectionEnd() -{ - AddStringLF("SectionEnd"); - AddLF(); -} - -// static const unsigned kOnFuncShift = 4; - -void CInArchive::ClearLangComment() -{ - langStrIDs.Clear(); -} - -void CInArchive::PrintNumComment(const char *name, UInt32 value) -{ - // size_t len = Script.Len(); - AddCommentAndString(name); - Script += ": "; - Add_UInt(value); - AddLF(); - /* - len = Script.Len() - len; - char sz[16]; - ConvertUInt32ToString(value, sz); - len += MyStringLen(sz); - for (; len < 20; len++) - Space(); - AddStringLF(sz); - */ -} - - -void CInArchive::NewLine() -{ - if (!langStrIDs.IsEmpty()) - { - BigSpaceComment(); - for (unsigned i = 0; i < langStrIDs.Size() && i < 20; i++) - { - /* - if (i != 0) - Script += ' '; - */ - UInt32 langStr = langStrIDs[i]; - if (langStr >= _numLangStrings) - { - AddError("langStr"); - break; - } - UInt32 param = Get32(_mainLang + langStr * 4); - if (param != 0) - AddParam(param); - } - ClearLangComment(); - } - AddLF(); -} - -static const UInt32 kPageSize = 16 * 4; - -static const char * const k_SetOverwrite_Modes[] = -{ - "on" - , "off" - , "try" - , "ifnewer" - , "ifdiff" - // "lastused" -}; - - -void CInArchive::MessageBox_MB_Part(UInt32 param) -{ - { - UInt32 v = param & 0xF; - Script += " MB_"; - if (v < Z7_ARRAY_SIZE(k_MB_Buttons)) - Script += k_MB_Buttons[v]; - else - { - Script += "Buttons_"; - Add_UInt(v); - } - } - { - UInt32 icon = (param >> 4) & 0x7; - if (icon != 0) - { - Script += "|MB_"; - if (icon < Z7_ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon]) - Script += k_MB_Icons[icon]; - else - { - Script += "Icon_"; - Add_UInt(icon); - } - } - } - if ((param & 0x80) != 0) - Script += "|MB_USERICON"; - { - UInt32 defButton = (param >> 8) & 0xF; - if (defButton != 0) - { - Script += "|MB_DEFBUTTON"; - Add_UInt(defButton + 1); - } - } - { - UInt32 modal = (param >> 12) & 0x3; - if (modal == 1) Script += "|MB_SYSTEMMODAL"; - else if (modal == 2) Script += "|MB_TASKMODAL"; - else if (modal == 3) Script += "|0x3000"; - UInt32 flags = (param >> 14); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_MB_Flags); i++) - if ((flags & (1 << i)) != 0) - { - Script += "|MB_"; - Script += k_MB_Flags[i]; - } - } -} - -#define GET_CMD_PARAM(ppp, index) Get32((ppp) + 4 + (index) * 4) - -static const Byte k_InitPluginDir_Commands[] = - { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 }; - -bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) -{ - for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) - if (GetCmd(Get32(rawCmds)) != sequence[kkk]) - return false; - return true; -} - - -static const UInt32 kSectionSize_base = 6 * 4; -// static const UInt32 kSectionSize_8bit = kSectionSize_base + 1024; -// static const UInt32 kSectionSize_16bit = kSectionSize_base + 1024 * 2; -// static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2; -// 8196 is default string length in NSIS-Unicode since 2.37.3 - -#endif - - -static void AddString(AString &dest, const char *src) -{ - dest.Add_Space_if_NotEmpty(); - dest += src; -} - -AString CInArchive::GetFormatDescription() const -{ - AString s ("NSIS-"); - char c; - if (IsPark()) - { - s += "Park-"; - c = '1'; - if (NsisType == k_NsisType_Park2) c = '2'; - else if (NsisType == k_NsisType_Park3) c = '3'; - } - else - { - c = '2'; - if (NsisType == k_NsisType_Nsis3) - c = '3'; - } - s += c; - if (IsNsis200) - s += ".00"; - else if (IsNsis225) - s += ".25"; - - if (IsUnicode) - AddString(s, "Unicode"); - - if (Is64Bit) - AddString(s, "64-bit"); - - if (LogCmdIsEnabled) - AddString(s, "log"); - - if (BadCmd >= 0) - { - AddString(s, "BadCmd="); - UIntToString(s, (UInt32)BadCmd); - } - return s; -} - -#ifdef NSIS_SCRIPT - -static const unsigned kNumAdditionalParkCmds = 3; - -unsigned CInArchive::GetNumSupportedCommands() const -{ - unsigned numCmds = IsPark() ? (unsigned)kNumCmds : (unsigned)(kNumCmds) - kNumAdditionalParkCmds; - if (!LogCmdIsEnabled) - numCmds--; - if (!IsUnicode) - numCmds -= 2; - return numCmds; -} - -#endif - -UInt32 CInArchive::GetCmd(UInt32 a) -{ - if (!IsPark()) - { - if (!LogCmdIsEnabled) - return a; - if (a < EW_SECTIONSET) - return a; - if (a == EW_SECTIONSET) - return EW_LOG; - return a - 1; - } - - if (a < EW_REGISTERDLL) - return a; - if (NsisType >= k_NsisType_Park2) - { - if (a == EW_REGISTERDLL) return EW_GETFONTVERSION; - a--; - } - if (NsisType >= k_NsisType_Park3) - { - if (a == EW_REGISTERDLL) return EW_GETFONTNAME; - a--; - } - if (a >= EW_FSEEK) - { - if (IsUnicode) - { - if (a == EW_FSEEK) return EW_FPUTWS; - if (a == EW_FSEEK + 1) return EW_FPUTWS + 1; - a -= 2; - } - - if (a >= EW_SECTIONSET && LogCmdIsEnabled) - { - if (a == EW_SECTIONSET) - return EW_LOG; - return a - 1; - } - if (a == EW_FPUTWS) - return EW_FINDPROC; - // if (a > EW_FPUTWS) return 0; - } - return a; -} - -void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p) -{ - BadCmd = -1; - - for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) - { - const UInt32 id = GetCmd(Get32(p)); - if (id >= kNumCmds) - continue; - if (BadCmd >= 0 && id >= (unsigned)BadCmd) - continue; - unsigned i; - if (IsNsis3_OrHigher()) - { - if (id == EW_RESERVEDOPCODE) - { - BadCmd = (int)id; - continue; - } - } - else - { - // if (id == EW_GETLABELADDR || id == EW_GETFUNCTIONADDR) - if (id == EW_RESERVEDOPCODE || id == EW_GETOSINFO) - { - BadCmd = (int)id; - continue; - } - } - for (i = 6; i != 0; i--) - { - const UInt32 param = Get32(p + i * 4); - if (param != 0) - break; - } - if (id == EW_FINDPROC && i == 0) - { - BadCmd = (int)id; - continue; - } - if (k_Commands[id].NumParams < i) - BadCmd = (int)id; - } -} - -/* We calculate the number of parameters in commands to detect - layout of commands. It's not very good way. - If you know simpler and more robust way to detect Version and layout, - please write to 7-Zip forum */ - -void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p) -{ - bool strongPark = false; - bool strongNsis = false; - - if (NumStringChars > 2) - { - const Byte *strData = _data + _stringsPos; - if (IsUnicode) - { - UInt32 num = NumStringChars - 2; - for (UInt32 i = 0; i < num; i++) - { - if (Get16(strData + i * 2) == 0) - { - unsigned c2 = Get16(strData + 2 + i * 2); - // it can be TXT/RTF with marker char (1 or 2). so we must check next char - // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL) - if (c2 == NS_3_CODE_VAR) - { - // 18.06: fixed: is it correct ? - // if ((Get16(strData + 3 + i * 2) & 0x8000) != 0) - if ((Get16(strData + 4 + i * 2) & 0x8080) == 0x8080) - { - NsisType = k_NsisType_Nsis3; - strongNsis = true; - break; - } - } - } - } - if (!strongNsis) - { - NsisType = k_NsisType_Park1; - strongPark = true; - } - } - else - { - UInt32 num = NumStringChars - 2; - for (UInt32 i = 0; i < num; i++) - { - if (strData[i] == 0) - { - Byte c2 = strData[i + 1]; - // it can be TXT/RTF with marker char (1 or 2). so we must check next char - // for marker=1 (txt) - if (c2 == NS_3_CODE_VAR) - // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1) - { - if ((strData[i + 2] & 0x80) != 0) - { - // const char *p2 = (const char *)(strData + i + 1); - // p2 = p2; - NsisType = k_NsisType_Nsis3; - strongNsis = true; - break; - } - } - } - } - } - } - - if (NsisType == k_NsisType_Nsis2 && !IsUnicode) - { - const Byte *p2 = p; - - for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) - { - UInt32 cmd = GetCmd(Get32(p2)); - if (cmd != EW_GETDLGITEM && - cmd != EW_ASSIGNVAR) - continue; - - UInt32 params[kNumCommandParams]; - for (unsigned i = 0; i < kNumCommandParams; i++) - params[i] = Get32(p2 + 4 + 4 * i); - - if (cmd == EW_GETDLGITEM) - { - // we can use also EW_SETCTLCOLORS - if (IsVarStr(params[1], kVar_HWNDPARENT_225)) - { - IsNsis225 = true; - if (params[0] == kVar_Spec_OUTDIR_225) - { - IsNsis200 = true; - break; - } - } - } - else // if (cmd == EW_ASSIGNVAR) - { - if (params[0] == kVar_Spec_OUTDIR_225 && - params[2] == 0 && - params[3] == 0 && - IsVarStr(params[1], kVar_OUTDIR)) - IsNsis225 = true; - } - } - } - - bool parkVer_WasDetected = false; - - if (!strongNsis && !IsNsis225 && !IsNsis200) - { - // it must be before FindBadCmd(bh, p); - unsigned mask = 0; - - unsigned numInsertMax = IsUnicode ? 4 : 2; - - const Byte *p2 = p; - - for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) - { - const UInt32 cmd = Get32(p2); // we use original (not converted) command - - if (cmd < EW_WRITEUNINSTALLER || - cmd > EW_WRITEUNINSTALLER + numInsertMax) - continue; - - UInt32 params[kNumCommandParams]; - for (unsigned i = 0; i < kNumCommandParams; i++) - params[i] = Get32(p2 + 4 + 4 * i); - - if (params[4] != 0 || - params[5] != 0 || - params[0] <= 1 || - params[3] <= 1) - continue; - - const UInt32 altParam = params[3]; - if (!IsGoodString(params[0]) || - !IsGoodString(altParam)) - continue; - - UInt32 additional = 0; - if (GetVarIndexFinished(altParam, '\\', additional) != kVar_INSTDIR) - continue; - if (AreTwoParamStringsEqual(altParam + additional, params[0])) - { - const unsigned numInserts = cmd - EW_WRITEUNINSTALLER; - mask |= ((unsigned)1 << numInserts); - } - } - - if (mask == 1) - { - parkVer_WasDetected = true; // it can be original NSIS or Park-1 - } - else if (mask != 0) - { - ENsisType newType = NsisType; - if (IsUnicode) - switch (mask) - { - case (1 << 3): newType = k_NsisType_Park2; break; - case (1 << 4): newType = k_NsisType_Park3; break; - } - else - switch (mask) - { - case (1 << 1): newType = k_NsisType_Park2; break; - case (1 << 2): newType = k_NsisType_Park3; break; - } - if (newType != NsisType) - { - parkVer_WasDetected = true; - NsisType = newType; - } - } - } - - FindBadCmd(bh, p); - - /* - if (strongNsis) - return; - */ - - if (BadCmd < EW_REGISTERDLL) - return; - - /* - // in ANSI archive we don't check Park and log version - if (!IsUnicode) - return; - */ - - // We can support Park-ANSI archives, if we remove if (strongPark) check - if (strongPark && !parkVer_WasDetected) - { - if (BadCmd < EW_SECTIONSET) - { - NsisType = k_NsisType_Park3; - LogCmdIsEnabled = true; // version 3 is provided with log enabled - FindBadCmd(bh, p); - if (BadCmd > 0 && BadCmd < EW_SECTIONSET) - { - NsisType = k_NsisType_Park2; - LogCmdIsEnabled = false; - FindBadCmd(bh, p); - if (BadCmd > 0 && BadCmd < EW_SECTIONSET) - { - NsisType = k_NsisType_Park1; - FindBadCmd(bh, p); - } - } - } - } - - if (BadCmd >= EW_SECTIONSET) - { - LogCmdIsEnabled = !LogCmdIsEnabled; - FindBadCmd(bh, p); - if (BadCmd >= EW_SECTIONSET && LogCmdIsEnabled) - { - LogCmdIsEnabled = false; - FindBadCmd(bh, p); - } - } -} - -Int32 CInArchive::GetVarIndex(UInt32 strPos) const -{ - if (strPos >= NumStringChars) - return -1; - - if (IsUnicode) - { - if (NumStringChars - strPos < 3 * 2) - return -1; - const Byte *p = _data + _stringsPos + strPos * 2; - unsigned code = Get16(p); - if (IsPark()) - { - if (code != PARK_CODE_VAR) - return -1; - UInt32 n = Get16(p + 2); - if (n == 0) - return -1; - CONVERT_NUMBER_PARK(n); - return (Int32)n; - } - - // NSIS-3 - { - if (code != NS_3_CODE_VAR) - return -1; - UInt32 n = Get16(p + 2); - if (n == 0) - return -1; - CONVERT_NUMBER_NS_3_UNICODE(n); - return (Int32)n; - } - } - - if (NumStringChars - strPos < 4) - return -1; - - const Byte *p = _data + _stringsPos + strPos; - unsigned c = *p; - if (NsisType == k_NsisType_Nsis3) - { - if (c != NS_3_CODE_VAR) - return -1; - } - else if (c != NS_CODE_VAR) - return -1; - - const unsigned c0 = p[1]; - if (c0 == 0) - return -1; - const unsigned c1 = p[2]; - if (c1 == 0) - return -1; - return (Int32)DECODE_NUMBER_FROM_2_CHARS(c0, c1); -} - -Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const -{ - resOffset = 0; - Int32 varIndex = GetVarIndex(strPos); - if (varIndex < 0) - return varIndex; - if (IsUnicode) - { - if (NumStringChars - strPos < 2 * 2) - return -1; - resOffset = 2; - } - else - { - if (NumStringChars - strPos < 3) - return -1; - resOffset = 3; - } - return varIndex; -} - -Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const -{ - resOffset = 0; - Int32 varIndex = GetVarIndex(strPos); - if (varIndex < 0) - return varIndex; - if (IsUnicode) - { - if (NumStringChars - strPos < 3 * 2) - return -1; - const Byte *p = _data + _stringsPos + strPos * 2; - if (Get16(p + 4) != endChar) - return -1; - resOffset = 3; - } - else - { - if (NumStringChars - strPos < 4) - return -1; - const Byte *p = _data + _stringsPos + strPos; - if (p[3] != endChar) - return -1; - resOffset = 4; - } - return varIndex; -} - -bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const -{ - if (varIndex > (UInt32)0x7FFF) - return false; - UInt32 resOffset; - return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex; -} - -bool CInArchive::IsAbsolutePathVar(UInt32 strPos) const -{ - Int32 varIndex = GetVarIndex(strPos); - if (varIndex < 0) - return false; - switch (varIndex) - { - case kVar_INSTDIR: - case kVar_EXEDIR: - case kVar_TEMP: - case kVar_PLUGINSDIR: - return true; - } - return false; -} - -#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) - -// We use same check as in NSIS decoder -static bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } -static bool IsDrivePath(const char *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } - -static bool IsAbsolutePath(const wchar_t *s) -{ - return (s[0] == WCHAR_PATH_SEPARATOR && s[1] == WCHAR_PATH_SEPARATOR) || IsDrivePath(s); -} - -static bool IsAbsolutePath(const char *s) -{ - return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s); -} - -void CInArchive::SetItemName(CItem &item, UInt32 strPos) -{ - ReadString2_Raw(strPos); - const bool isAbs = IsAbsolutePathVar(strPos); - if (IsUnicode) - { - item.NameU = Raw_UString; - if (!isAbs && !IsAbsolutePath(Raw_UString)) - item.Prefix = (int)UPrefixes.Size() - 1; - } - else - { - item.NameA = Raw_AString; - if (!isAbs && !IsAbsolutePath(Raw_AString)) - item.Prefix = (int)APrefixes.Size() - 1; - } -} - -HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) -{ - #ifdef NSIS_SCRIPT - CDynLimBuf &s = Script; - - CObjArray labels; - labels.Alloc(bh.Num); - memset(labels, 0, bh.Num * sizeof(UInt32)); - - { - const Byte *p = _data; - UInt32 i; - for (i = 0; i < numOnFunc; i++) - { - UInt32 func = Get32(p + onFuncOffset + 4 * i); - if (func < bh.Num) - labels[func] = (labels[func] & ~CMD_REF_OnFunc_Mask) | (CMD_REF_OnFunc | (i << CMD_REF_OnFunc_NumShifts)); - } - } - - /* - { - for (int i = 0; i < OnFuncs.Size(); i++) - { - UInt32 address = OnFuncs[i] >> kOnFuncShift; - if (address < bh.Num) - } - } - */ - - if (bhPages.Num != 0) - { - Separator(); - PrintNumComment("PAGES", bhPages.Num); - - if (bhPages.Num > (1 << 12) - || bhPages.Offset > _size - || bhPages.Num * kPageSize > _size - bhPages.Offset) - { - AddErrorLF("Pages error"); - } - else - { - - AddLF(); - const Byte *p = _data + bhPages.Offset; - - for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, p += kPageSize) - { - UInt32 dlgID = Get32(p); - UInt32 wndProcID = Get32(p + 4); - UInt32 preFunc = Get32(p + 8); - UInt32 showFunc = Get32(p + 12); - UInt32 leaveFunc = Get32(p + 16); - UInt32 flags = Get32(p + 20); - UInt32 caption = Get32(p + 24); - // UInt32 back = Get32(p + 28); - UInt32 next = Get32(p + 32); - // UInt32 clickNext = Get32(p + 36); - // UInt32 cancel = Get32(p + 40); - UInt32 params[5]; - for (int i = 0; i < 5; i++) - params[i] = Get32(p + 44 + 4 * i); - - SET_FUNC_REF(preFunc, CMD_REF_Pre) - SET_FUNC_REF(showFunc, CMD_REF_Show) - SET_FUNC_REF(leaveFunc, CMD_REF_Leave) - - if (wndProcID == PWP_COMPLETED) - CommentOpen(); - - AddCommentAndString("Page "); - Add_UInt(pageIndex); - AddLF(); - - if (flags & PF_PAGE_EX) - { - s += "PageEx "; - if (!IsInstaller) - s += "un."; - } - else - s += IsInstaller ? "Page " : "UninstPage "; - - if (wndProcID < Z7_ARRAY_SIZE(kPageTypes)) - s += kPageTypes[wndProcID]; - else - Add_UInt(wndProcID); - - - bool needCallbacks = ( - (Int32)preFunc >= 0 || - (Int32)showFunc >= 0 || - (Int32)leaveFunc >= 0); - - if (flags & PF_PAGE_EX) - { - AddLF(); - if (needCallbacks) - TabString("PageCallbacks"); - } - - if (needCallbacks) - { - AddParam_Func(labels, preFunc); // it's creator_function for PWP_CUSTOM - if (wndProcID != PWP_CUSTOM) - { - AddParam_Func(labels, showFunc); - } - AddParam_Func(labels, leaveFunc); - } - - if ((flags & PF_PAGE_EX) == 0) - { - // AddOptionalParam(caption); - if (flags & PF_CANCEL_ENABLE) - s += " /ENABLECANCEL"; - AddLF(); - } - else - { - AddLF(); - AddPageOption1(caption, "Caption"); - } - - if (wndProcID == PWP_LICENSE) - { - if ((flags & PF_LICENSE_NO_FORCE_SELECTION) != 0 || - (flags & PF_LICENSE_FORCE_SELECTION) != 0) - { - TabString("LicenseForceSelection "); - if (flags & PF_LICENSE_NO_FORCE_SELECTION) - s += "off"; - else - { - if (dlgID == IDD_LICENSE_FSCB) - s += "checkbox"; - else if (dlgID == IDD_LICENSE_FSRB) - s += "radiobuttons"; - else - Add_UInt(dlgID); - AddOptionalParams(params + 2, 2); - } - NewLine(); - } - - if (params[0] != 0 || next != 0) - { - TabString("LicenseText"); - AddParam(params[0]); - AddOptionalParam(next); - NewLine(); - } - if (params[1] != 0) - { - TabString("LicenseData"); - if ((Int32)params[1] < 0) - AddParam(params[1]); - else - AddLicense(params[1], -1); - ClearLangComment(); - NewLine(); - } - } - else if (wndProcID == PWP_SELCOM) - AddPageOption(params, 3, "ComponentsText"); - else if (wndProcID == PWP_DIR) - { - AddPageOption(params, 4, "DirText"); - if (params[4] != 0) - { - TabString("DirVar"); - AddParam_Var(params[4] - 1); - AddLF(); - } - if (flags & PF_DIR_NO_BTN_DISABLE) - { - TabString("DirVerify leave"); - AddLF(); - } - - } - else if (wndProcID == PWP_INSTFILES) - { - AddPageOption1(params[2], "CompletedText"); - AddPageOption1(params[1], "DetailsButtonText"); - } - else if (wndProcID == PWP_UNINST) - { - if (params[4] != 0) - { - TabString("DirVar"); - AddParam_Var(params[4] - 1); - AddLF(); - } - AddPageOption(params, 2, "UninstallText"); - } - - if (flags & PF_PAGE_EX) - { - s += "PageExEnd"; - NewLine(); - } - if (wndProcID == PWP_COMPLETED) - CommentClose(); - NewLine(); - } - } - } - - CObjArray Sections; - - { - Separator(); - PrintNumComment("SECTIONS", bhSections.Num); - PrintNumComment("COMMANDS", bh.Num); - AddLF(); - - if (bhSections.Num > (1 << 15) - // || bhSections.Offset > _size - // || (bhSections.Num * SectionSize > _size - bhSections.Offset) - ) - { - AddErrorLF("Sections error"); - } - else if (bhSections.Num != 0) - { - Sections.Alloc((unsigned)bhSections.Num); - const Byte *p = _data + bhSections.Offset; - for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize) - { - CSection §ion = Sections[i]; - section.Parse(p); - if (section.StartCmdIndex < bh.Num) - labels[section.StartCmdIndex] |= CMD_REF_Section; - } - } - } - - #endif - - const Byte *p; - UInt32 kkk; - - #ifdef NSIS_SCRIPT - - p = _data + bh.Offset; - - for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) - { - UInt32 commandId = GetCmd(Get32(p)); - UInt32 mask; - switch (commandId) - { - case EW_NOP: mask = 1 << 0; break; - case EW_IFFILEEXISTS: mask = 3 << 1; break; - case EW_IFFLAG: mask = 3 << 0; break; - case EW_MESSAGEBOX: mask = 5 << 3; break; - case EW_STRCMP: mask = 3 << 2; break; - case EW_INTCMP: mask = 7 << 2; break; - case EW_ISWINDOW: mask = 3 << 1; break; - case EW_CALL: - { - if (Get32(p + 4 + 4) == 1) // it's Call :Label - { - mask = 1 << 0; - break; - } - UInt32 param0 = Get32(p + 4); - if ((Int32)param0 > 0) - labels[param0 - 1] |= CMD_REF_Call; - continue; - } - default: continue; - } - for (unsigned i = 0; mask != 0; i++, mask >>= 1) - if (mask & 1) - { - UInt32 param = Get32(p + 4 + 4 * i); - if ((Int32)param > 0 && (Int32)param <= (Int32)bh.Num) - labels[param - 1] |= CMD_REF_Goto; - } - } - - int InitPluginsDir_Start = -1; - int InitPluginsDir_End = -1; - p = _data + bh.Offset; - for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) - { - UInt32 flg = labels[kkk]; - /* - if (IsFunc(flg)) - { - AddLF(); - for (int i = 0; i < 14; i++) - { - UInt32 commandId = GetCmd(Get32(p + kCmdSize * i)); - s += ", "; - UIntToString(s, commandId); - } - AddLF(); - } - */ - if (IsFunc(flg) - && bh.Num - kkk >= Z7_ARRAY_SIZE(k_InitPluginDir_Commands) - && CompareCommands(p, k_InitPluginDir_Commands, Z7_ARRAY_SIZE(k_InitPluginDir_Commands))) - { - InitPluginsDir_Start = (int)kkk; - InitPluginsDir_End = (int)(kkk + Z7_ARRAY_SIZE(k_InitPluginDir_Commands)); - labels[kkk] |= CMD_REF_InitPluginDir; - break; - } - } - - #endif - - // AString prefixA_Temp; - // UString prefixU_Temp; - - - // const UInt32 kFindS = 158; - - #ifdef NSIS_SCRIPT - - UInt32 curSectionIndex = 0; - // UInt32 lastSectionEndCmd = 0xFFFFFFFF; - bool sectionIsOpen = false; - // int curOnFunc = 0; - bool onFuncIsOpen = false; - - /* - for (unsigned yyy = 0; yyy + 3 < _data.Size(); yyy++) - { - UInt32 val = Get32(_data + yyy); - if (val == kFindS) - val = val; - } - */ - - UInt32 overwrite_State = 0; // "SetOverwrite on" - Int32 allowSkipFiles_State = -1; // -1: on, -2: off, >=0 : RAW value - UInt32 endCommentIndex = 0; - - unsigned numSupportedCommands = GetNumSupportedCommands(); - - #endif - - p = _data + bh.Offset; - - UString spec_outdir_U; - AString spec_outdir_A; - - UPrefixes.Add(UString("$INSTDIR")); - APrefixes.Add(AString("$INSTDIR")); - - p = _data + bh.Offset; - - unsigned spec_outdir_VarIndex = IsNsis225 ? - kVar_Spec_OUTDIR_225 : - kVar_Spec_OUTDIR; - - for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) - { - UInt32 commandId; - UInt32 params[kNumCommandParams]; - commandId = GetCmd(Get32(p)); - { - for (unsigned i = 0; i < kNumCommandParams; i++) - { - params[i] = Get32(p + 4 + 4 * i); - /* - if (params[i] == kFindS) - i = i; - */ - } - } - - #ifdef NSIS_SCRIPT - - bool IsSectionGroup = false; - while (curSectionIndex < bhSections.Num) - { - const CSection § = Sections[curSectionIndex]; - if (sectionIsOpen) - { - if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk) - break; - PrintSectionEnd(); - sectionIsOpen = false; - // lastSectionEndCmd = kkk; - curSectionIndex++; - continue; - } - if (sect.StartCmdIndex != kkk) - break; - if (PrintSectionBegin(sect, curSectionIndex)) - { - IsSectionGroup = true; - curSectionIndex++; - // do we need to flush prefixes in new section? - // FlushOutPathPrefixes(); - } - else - sectionIsOpen = true; - } - - /* - if (curOnFunc < OnFuncs.Size()) - { - if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk) - { - s += "Function .on"; - s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)]; - AddLF(); - onFuncIsOpen = true; - } - } - */ - - if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section) - { - UInt32 flg = labels[kkk]; - if (IsFunc(flg)) - { - if ((int)kkk == InitPluginsDir_Start) - CommentOpen(); - - onFuncIsOpen = true; - s += "Function "; - Add_FuncName(labels, kkk); - if (IsPageFunc(flg)) - { - BigSpaceComment(); - s += "Page "; - Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts); - // if (flg & CMD_REF_Creator) s += ", Creator"; - if (flg & CMD_REF_Leave) s += ", Leave"; - if (flg & CMD_REF_Pre) s += ", Pre"; - if (flg & CMD_REF_Show) s += ", Show"; - } - AddLF(); - } - if (flg & CMD_REF_Goto) - { - Add_LabelName(kkk); - s += ':'; - AddLF(); - } - } - - if (commandId != EW_RET) - { - Tab(kkk < endCommentIndex); - } - - /* - UInt32 originalCmd = Get32(p); - if (originalCmd >= EW_REGISTERDLL) - { - UIntToString(s, originalCmd); - s += ' '; - if (originalCmd != commandId) - { - UIntToString(s, commandId); - s += ' '; - } - } - */ - - unsigned numSkipParams = 0; - - if (commandId < Z7_ARRAY_SIZE(k_Commands) && commandId < numSupportedCommands) - { - numSkipParams = k_Commands[commandId].NumParams; - const char *sz = k_CommandNames[commandId]; - if (sz) - s += sz; - } - else - { - s += "Command"; - Add_UInt(commandId); - /* We don't show wrong commands that use overlapped ids. - So we change commandId to big value */ - if (commandId < (1 << 12)) - commandId += (1 << 12); - } - - #endif - - switch (commandId) - { - case EW_CREATEDIR: - { - bool isSetOutPath = (params[1] != 0); - - if (isSetOutPath) - { - UInt32 par0 = params[0]; - - UInt32 resOffset; - Int32 idx = GetVarIndex(par0, resOffset); - if (idx == (Int32)spec_outdir_VarIndex || - idx == kVar_OUTDIR) - par0 += resOffset; - - ReadString2_Raw(par0); - - if (IsUnicode) - { - if (idx == (Int32)spec_outdir_VarIndex) - Raw_UString.Insert(0, spec_outdir_U); - else if (idx == kVar_OUTDIR) - Raw_UString.Insert(0, UPrefixes.Back()); - UPrefixes.Add(Raw_UString); - } - else - { - if (idx == (Int32)spec_outdir_VarIndex) - Raw_AString.Insert(0, spec_outdir_A); - else if (idx == kVar_OUTDIR) - Raw_AString.Insert(0, APrefixes.Back()); - APrefixes.Add(Raw_AString); - } - } - - #ifdef NSIS_SCRIPT - s += isSetOutPath ? "SetOutPath" : "CreateDirectory"; - AddParam(params[0]); - if (params[2] != 0) // 2.51+ & 3.0b3+ - { - SmallSpaceComment(); - s += "CreateRestrictedDirectory"; - } - #endif - - break; - } - - - case EW_ASSIGNVAR: - { - if (params[0] == spec_outdir_VarIndex) - { - spec_outdir_U.Empty(); - spec_outdir_A.Empty(); - if (IsVarStr(params[1], kVar_OUTDIR) && - params[2] == 0 && - params[3] == 0) - { - spec_outdir_U = UPrefixes.Back(); // outdir_U; - spec_outdir_A = APrefixes.Back(); // outdir_A; - } - } - - #ifdef NSIS_SCRIPT - - if (params[2] == 0 && - params[3] == 0 && - params[4] == 0 && - params[5] == 0 && - params[1] != 0 && - params[1] < NumStringChars) - { - char sz[16]; - ConvertUInt32ToString(kkk + 1, sz); - if (IsDirectString_Equal(params[1], sz)) - { - // we suppose that it's GetCurrentAddress command - // but there is probability that it's StrCpy command - s += "GetCurrentAddress"; - AddParam_Var(params[0]); - SmallSpaceComment(); - } - } - s += "StrCpy"; - AddParam_Var(params[0]); - AddParam(params[1]); - - AddOptionalParams(params + 2, 2); - - #endif - - break; - } - - case EW_EXTRACTFILE: - { - CItem &item = Items.AddNew(); - - UInt32 par1 = params[1]; - - SetItemName(item, par1); - - item.Pos = params[2]; - item.MTime.dwLowDateTime = params[3]; - item.MTime.dwHighDateTime = params[4]; - - #ifdef NSIS_SCRIPT - - { - UInt32 overwrite = params[0] & 0x7; - if (overwrite != overwrite_State) - { - s += "SetOverwrite "; - ADD_TYPE_FROM_LIST(k_SetOverwrite_Modes, overwrite); - overwrite_State = overwrite; - AddLF(); - Tab(kkk < endCommentIndex); - } - } - - { - UInt32 nsisMB = params[0] >> 3; - if ((Int32)nsisMB != allowSkipFiles_State) - { - UInt32 mb = nsisMB & ((1 << 20) - 1); // old/new NSIS - UInt32 b1 = nsisMB >> 21; // NSIS 2.06+ - UInt32 b2 = nsisMB >> 20; // NSIS old - Int32 asf = (Int32)nsisMB; - if (mb == (Z7_NSIS_WIN_MB_ABORTRETRYIGNORE | Z7_NSIS_WIN_MB_ICONSTOP) && (b1 == Z7_NSIS_WIN_IDIGNORE || b2 == Z7_NSIS_WIN_IDIGNORE)) - asf = -1; - else if (mb == (Z7_NSIS_WIN_MB_RETRYCANCEL | Z7_NSIS_WIN_MB_ICONSTOP) && (b1 == Z7_NSIS_WIN_IDCANCEL || b2 == Z7_NSIS_WIN_IDCANCEL)) - asf = -2; - else - { - AddCommentAndString("AllowSkipFiles [Overwrite]: "); - MessageBox_MB_Part(mb); - if (b1 != 0) - { - s += " /SD"; - Add_ButtonID(b1); - } - } - if (asf != allowSkipFiles_State) - { - if (asf < 0) - { - s += "AllowSkipFiles "; - s += (asf == -1) ? "on" : "off"; - } - AddLF(); - Tab(kkk < endCommentIndex); - } - allowSkipFiles_State = (Int32)nsisMB; - } - } - - s += "File"; - AddParam(params[1]); - - /* params[5] contains link to LangString (negative value) - with NLF_FILE_ERROR or NLF_FILE_ERROR_NOIGNORE message for MessageBox. - We don't need to print it. */ - - #endif - - if (IsVarStr(par1, 10)) // is $R0 - { - // we parse InstallLib macro in 7-Zip installers - unsigned kBackOffset = 28; - if (kkk > 1) - { - // detect old version of InstallLib macro - if (Get32(p - 1 * kCmdSize) == EW_NOP) // goto command - kBackOffset -= 2; - } - - if (kkk > kBackOffset) - { - const Byte *p2 = p - kBackOffset * kCmdSize; - UInt32 cmd = Get32(p2); - if (cmd == EW_ASSIGNVAR) - { - UInt32 pars[6]; - for (int i = 0; i < 6; i++) - pars[i] = Get32(p2 + i * 4 + 4); - if (pars[0] == 10 + 4 && pars[2] == 0 && pars[3] == 0) // 10 + 4 means $R4 - { - item.Prefix = -1; - item.NameA.Empty(); - item.NameU.Empty(); - SetItemName(item, pars[1]); - // maybe here we can restore original item name, if new name is empty - } - } - } - } - /* UInt32 allowIgnore = params[5]; */ - break; - } - - case EW_SETFILEATTRIBUTES: - { - if (kkk > 0 && Get32(p - kCmdSize) == EW_EXTRACTFILE) - { - if (params[0] == Get32(p - kCmdSize + 4 + 4 * 1)) // compare with PrevCmd.Params[1] - { - CItem &item = Items.Back(); - item.Attrib_Defined = true; - item.Attrib = params[1]; - } - } - #ifdef NSIS_SCRIPT - AddParam(params[0]); - Space(); - FlagsToString2(s, g_WinAttrib, Z7_ARRAY_SIZE(g_WinAttrib), params[1]); - #endif - break; - } - - case EW_WRITEUNINSTALLER: - { - /* NSIS 2.29+ writes alternative path to params[3] - "$INSTDIR\\" + Str(params[0]) - NSIS installer uses alternative path, if main path - from params[0] is not absolute path */ - - const bool pathOk = (params[0] > 0) && IsGoodString(params[0]); - - if (!pathOk) - { - #ifdef NSIS_SCRIPT - AddError("bad path"); - #endif - break; - } - - #ifdef NSIS_SCRIPT - - bool altPathOk = true; - - const UInt32 altParam = params[3]; - if (altParam != 0) - { - altPathOk = false; - UInt32 additional = 0; - if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR) - altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]); - } - - AddParam(params[0]); - - /* - for (int i = 1; i < 3; i++) - AddParam_UInt(params[i]); - */ - - if (params[3] != 0) - { - SmallSpaceComment(); - AddParam(params[3]); - } - - if (!altPathOk) - { - #ifdef NSIS_SCRIPT - AddError("alt path error"); - #endif - } - - #endif - - if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER) - { - /* We don't support cases with incorrect installer commands. - Such bad installer item can break unpacking for other items. */ - #ifdef NSIS_SCRIPT - AddError("SKIP possible BadCmd"); - #endif - break; - } - - CItem &item = Items.AddNew(); - - SetItemName(item, params[0]); - - item.Pos = params[1]; - item.PatchSize = params[2]; - item.IsUninstaller = true; - const UInt32 param3 = params[3]; - if (param3 != 0 && item.Prefix != -1) - { - /* (item.Prefix != -1) case means that param[0] path was not absolute. - So we use params[3] in that case, as original nsis */ - SetItemName(item, param3); - } - /* UNINSTALLER file doesn't use directory prefixes. - So we remove prefix: */ - item.Prefix = -1; - - /* - // we can add second time to test the code - CItem item2 = item; - item2.NameU += L'2'; - item2.NameA += '2'; - Items.Add(item2); - */ - - break; - } - - #ifdef NSIS_SCRIPT - - case EW_RET: - { - // bool needComment = false; - if (onFuncIsOpen) - { - if (kkk == bh.Num - 1 || IsProbablyEndOfFunc(labels[kkk + 1])) - { - AddStringLF("FunctionEnd"); - - if ((int)kkk + 1 == InitPluginsDir_End) - CommentClose(); - AddLF(); - onFuncIsOpen = false; - // needComment = true; - break; - } - } - // if (!needComment) - if (IsSectionGroup) - break; - if (sectionIsOpen) - { - const CSection § = Sections[curSectionIndex]; - if (sect.StartCmdIndex + sect.NumCommands == kkk) - { - PrintSectionEnd(); - sectionIsOpen = false; - curSectionIndex++; - break; - } - - // needComment = true; - // break; - } - - /* - if (needComment) - s += " ;"; - */ - TabString("Return"); - AddLF(); - break; - } - - case EW_NOP: - { - if (params[0] == 0) - s += "Nop"; - else - { - s += "Goto"; - Add_GotoVar(params[0]); - } - break; - } - - case EW_ABORT: - { - AddOptionalParam(params[0]); - break; - } - - case EW_CALL: - { - if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE) - { - UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1); - - UInt32 pluginPar = 0; - - if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR) - { - pluginPar += par1; - UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2)); - if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT) - { - UInt32 i; - for (i = kkk + 3; i < bh.Num; i++) - { - const Byte *pCmd = p + kCmdSize * (i - kkk); - UInt32 commandId3 = GetCmd(Get32(pCmd)); - if (commandId3 != EW_PUSHPOP - || GET_CMD_PARAM(pCmd, 1) != 0 - || GET_CMD_PARAM(pCmd, 2) != 0) - break; - } - if (i < bh.Num) - { - const Byte *pCmd = p + kCmdSize * (i - kkk); - - // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0); - // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1); - - if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL && - AreTwoParamStringsEqual( - GET_CMD_PARAM(pCmd, 0), - GET_CMD_PARAM(p + kCmdSize, 1))) - { - // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx; - /// new versions of NSIS use params[4] = 1 for Plugin command - if (GET_CMD_PARAM(pCmd, 2) == 0 - // && GET_CMD_PARAM(pCmd, 4) != 0 - ) - { - { - AString s2; - ReadString2(s2, pluginPar); - if (s2.Len() >= 4 && - StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll")) - s2.DeleteFrom(s2.Len() - 4); - s2 += "::"; - AString func; - ReadString2(func, GET_CMD_PARAM(pCmd, 1)); - s2 += func; - Add_QuStr(s2); - - if (GET_CMD_PARAM(pCmd, 3) == 1) - s += " /NOUNLOAD"; - - for (UInt32 j = i - 1; j >= kkk + 3; j--) - { - const Byte *pCmd2 = p + kCmdSize * (j - kkk); - AddParam(GET_CMD_PARAM(pCmd2, 0)); - } - NewLine(); - Tab(true); - endCommentIndex = i + 1; - } - } - } - } - } - } - } - { - const Byte *nextCmd = p + kCmdSize; - UInt32 commandId2 = GetCmd(Get32(nextCmd)); - if (commandId2 == EW_SETFLAG - && GET_CMD_PARAM(nextCmd, 0) == k_ExecFlags_DetailsPrint - && GET_CMD_PARAM(nextCmd, 2) != 0) // is "lastused" - // || commandId2 == EW_UPDATETEXT) - { - if ((Int32)params[0] > 0 && labels[params[0] - 1] & CMD_REF_InitPluginDir) - { - s += "InitPluginsDir"; - AddLF(); - Tab(true); - endCommentIndex = kkk + 2; - } - } - } - - s += "Call "; - if ((Int32)params[0] < 0) - Add_Var((UInt32)-((Int32)params[0] + 1)); - else if (params[0] == 0) - s += '0'; - else - { - const UInt32 val = params[0] - 1; - if (params[1] == 1) // it's Call :Label - { - s += ':'; - Add_LabelName(val); - } - else // if (params[1] == 0) // it's Call Func - Add_FuncName(labels, val); - } - break; - } - - case EW_UPDATETEXT: - case EW_SLEEP: - { - AddParam(params[0]); - break; - } - - case EW_CHDETAILSVIEW: - { - if (params[0] == Z7_NSIS_WIN_SW_SHOWNA && params[1] == Z7_NSIS_WIN_SW_HIDE) s += " show"; - else if (params[1] == Z7_NSIS_WIN_SW_SHOWNA && params[0] == Z7_NSIS_WIN_SW_HIDE) s += " hide"; - else - for (int i = 0; i < 2; i++) - { - Space(); - Add_ShowWindow_Cmd(params[i]); - } - break; - } - - case EW_IFFILEEXISTS: - { - AddParam(params[0]); - Add_GotoVars2(¶ms[1]); - break; - } - - case EW_SETFLAG: - { - AString temp; - ReadString2(temp, params[1]); - if (params[0] == k_ExecFlags_Errors && params[2] == 0) - { - s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors"; - break; - } - s += "Set"; - Add_ExecFlags(params[0]); - - if (params[2] != 0) - { - s += " lastused"; - break; - } - UInt32 v; - if (StringToUInt32(temp, v)) - { - const char *s2 = NULL; - switch (params[0]) - { - case k_ExecFlags_AutoClose: - case k_ExecFlags_RebootFlag: - if (v < 2) { s2 = (v == 0) ? "false" : "true"; } break; - case k_ExecFlags_ShellVarContext: - if (v < 2) { s2 = (v == 0) ? "current" : "all"; } break; - case k_ExecFlags_Silent: - if (v < 2) { s2 = (v == 0) ? "normal" : "silent"; } break; - case k_ExecFlags_RegView: - if (v == 0) s2 = "32"; - else if (v == 256) s2 = "64"; - break; - case k_ExecFlags_DetailsPrint: - if (v == 0) s2 = "both"; - else if (v == 2) s2 = "textonly"; - else if (v == 4) s2 = "listonly"; - else if (v == 6) s2 = "none"; - break; - } - if (s2) - { - s += ' '; - s += s2; - break; - } - } - SpaceQuStr(temp); - break; - } - - case EW_IFFLAG: - { - Add_ExecFlags(params[2]); - Add_GotoVars2(¶ms[0]); - /* - const unsigned kIfErrors = 2; - if (params[2] != kIfErrors && params[3] != 0xFFFFFFFF || - params[2] == kIfErrors && params[3] != 0) - { - s += " # FLAG &= "; - AddParam_UInt(params[3]); - } - */ - break; - } - - case EW_GETFLAG: - { - Add_ExecFlags(params[1]); - AddParam_Var(params[0]); - break; - } - - case EW_RENAME: - { - if (params[2] != 0) - s += k_REBOOTOK; - AddParams(params, 2); - if (params[3] != 0) - { - SmallSpaceComment(); - AddParam(params[3]); // rename comment for log file - } - break; - } - - case EW_GETFULLPATHNAME: - { - if (params[2] == 0) - s += " /SHORT"; - AddParam_Var(params[1]); - AddParam(params[0]); - break; - } - - case EW_SEARCHPATH: - case EW_STRLEN: - { - AddParam_Var(params[0]); - AddParam(params[1]); - break; - } - - case EW_GETTEMPFILENAME: - { - AddParam_Var(params[0]); - AString temp; - ReadString2(temp, params[1]); - if (temp != "$TEMP") - SpaceQuStr(temp); - break; - } - - case EW_DELETEFILE: - { - UInt32 flag = params[1]; - if ((flag & DEL_REBOOT) != 0) - s += k_REBOOTOK; - AddParam(params[0]); - break; - } - - case EW_MESSAGEBOX: - { - MessageBox_MB_Part(params[0]); - AddParam(params[1]); - { - UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+ - if (buttonID != 0) - { - s += " /SD"; - Add_ButtonID(buttonID); - } - } - for (int i = 2; i < 6; i += 2) - if (params[i] != 0) - { - Add_ButtonID(params[i]); - Add_GotoVar1(params[i + 1]); - } - break; - } - - case EW_RMDIR: - { - UInt32 flag = params[1]; - if ((flag & DEL_RECURSE) != 0) - s += " /r"; - if ((flag & DEL_REBOOT) != 0) - s += k_REBOOTOK; - AddParam(params[0]); - break; - } - - case EW_STRCMP: - { - if (params[4] != 0) - s += 'S'; - AddParams(params, 2); - Add_GotoVars2(¶ms[2]); - break; - } - - case EW_READENVSTR: - { - s += (params[2] != 0) ? - "ReadEnvStr" : - "ExpandEnvStrings"; - AddParam_Var(params[0]); - AString temp; - ReadString2(temp, params[1]); - if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%') - { - temp.DeleteBack(); - temp.Delete(0); - } - SpaceQuStr(temp); - break; - } - - case EW_INTCMP: - { - s += "Int"; - const UInt32 param5 = params[5]; - if (param5 & 0x8000) - s += "64"; // v3.03+ - s += "Cmp"; - if (IsNsis3_OrHigher() ? (param5 & 1) : (param5 != 0)) - s += 'U'; - AddParams(params, 2); - Add_GotoVar1(params[2]); - if (params[3] != 0 || params[4] != 0) - Add_GotoVars2(params + 3); - break; - } - - case EW_INTOP: - { - AddParam_Var(params[0]); - const char * const kOps = "+-*/|&^!|&%<>>"; // NSIS 2.01+ - // "+-*/|&^!|&%"; // NSIS 2.0b4+ - // "+-*/|&^~!|&%"; // NSIS old - const UInt32 opIndex = params[3]; - const char c = (opIndex < 14) ? kOps[opIndex] : '?'; - const char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c; - const int numOps = (opIndex == 7) ? 1 : 2; - AddParam(params[1]); - if (numOps == 2 && c == '^' && IsDirectString_Equal(params[2], "0xFFFFFFFF")) - s += " ~ ;"; - Space(); - s += c; - if (numOps != 1) - { - if (opIndex == 13) // v3.03+ : operation ">>>" - s += c; - if (c2 != 0) - s += c2; - AddParam(params[2]); - } - break; - } - - case EW_INTFMT: - { - if (params[3]) - s += "Int64Fmt"; // v3.03+ - else - s += "IntFmt"; - AddParam_Var(params[0]); - AddParams(params + 1, 2); - break; - } - - case EW_PUSHPOP: - { - if (params[2] != 0) - { - s += "Exch"; - if (params[2] != 1) - AddParam_UInt(params[2]); - } - else if (params[1] != 0) - { - s += "Pop"; - AddParam_Var(params[0]); - } - else - { - if (NoLabels(labels + kkk + 1, 2) - && Get32(p + kCmdSize) == EW_PUSHPOP // Exch" - && GET_CMD_PARAM(p + kCmdSize, 2) == 1 - && Get32(p + kCmdSize * 2) == EW_PUSHPOP // Pop $VAR - && GET_CMD_PARAM(p + kCmdSize * 2, 1) != 0) - { - if (IsVarStr(params[0], GET_CMD_PARAM(p + kCmdSize * 2, 0))) - { - s += "Exch"; - AddParam(params[0]); - NewLine(); - Tab(true); - endCommentIndex = kkk + 3; - } - } - s += "Push"; - AddParam(params[0]); - } - break; - } - - case EW_FINDWINDOW: - { - AddParam_Var(params[0]); - AddParam(params[1]); - AddOptionalParams(params + 2, 3); - break; - } - - case EW_SENDMESSAGE: - { - // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] - AddParam(params[1]); - - const char *w = NULL; - AString t; - ReadString2(t, params[2]); - UInt32 wm; - if (StringToUInt32(t, wm)) - { - switch (wm) - { - case 0x0C: w = "SETTEXT"; break; - case 0x10: w = "CLOSE"; break; - case 0x30: w = "SETFONT"; break; - } - } - if (w) - { - s += " ${WM_"; - s += w; - s += '}'; - } - else - SpaceQuStr(t); - - UInt32 spec = params[5]; - for (unsigned i = 0; i < 2; i++) - { - AString s2; - if (spec & ((UInt32)1 << i)) - s2 += "STR:"; - ReadString2(s2, params[3 + i]); - SpaceQuStr(s2); - } - - if ((Int32)params[0] >= 0) - AddParam_Var(params[0]); - - spec >>= 2; - if (spec != 0) - { - s += " /TIMEOUT="; - Add_UInt(spec); - } - break; - } - - case EW_ISWINDOW: - { - AddParam(params[0]); - Add_GotoVars2(¶ms[1]); - break; - } - - case EW_GETDLGITEM: - { - AddParam_Var(params[0]); - AddParams(params + 1, 2); - break; - } - - case EW_SETCTLCOLORS: - { - AddParam(params[0]); - - UInt32 offset = params[1]; - - if (_size < bhCtlColors.Offset - || _size - bhCtlColors.Offset < offset - || _size - bhCtlColors.Offset - offset < GET_CtlColors_SIZE(Is64Bit)) - { - AddError("bad offset"); - break; - } - - const Byte *p2 = _data + bhCtlColors.Offset + offset; - CNsis_CtlColors colors; - colors.Parse(p2, Is64Bit); - - if ((colors.flags & kColorsFlags_BK_SYS) != 0 || - (colors.flags & kColorsFlags_TEXT_SYS) != 0) - s += " /BRANDING"; - - AString bk; - bool bkc = false; - if (colors.bkmode == Z7_NSIS_WIN_TRANSPARENT) - bk += " transparent"; - else if (colors.flags & kColorsFlags_BKB) - { - if ((colors.flags & kColorsFlags_BK_SYS) == 0 && - (colors.flags & kColorsFlags_BK) != 0) - bkc = true; - } - if ((colors.flags & kColorsFlags_TEXT) != 0 || !bk.IsEmpty() || bkc) - { - Space(); - if ((colors.flags & kColorsFlags_TEXT_SYS) != 0 || (colors.flags & kColorsFlags_TEXT) == 0) - AddQuotes(); - else - Add_Color(colors.text); - } - s += bk; - if (bkc) - { - Space(); - Add_Color(colors.bkc); - } - - break; - } - - // case EW_LOADANDSETIMAGE: - case EW_SETBRANDINGIMAGE: - { - s += " /IMGID="; - Add_UInt(params[1]); - if (params[2] == 1) - s += " /RESIZETOFIT"; - AddParam(params[0]); - break; - } - - case EW_CREATEFONT: - { - AddParam_Var(params[0]); - AddParam(params[1]); - AddOptionalParams(params + 2, 2); - if (params[4] & 1) s += " /ITALIC"; - if (params[4] & 2) s += " /UNDERLINE"; - if (params[4] & 4) s += " /STRIKE"; - break; - } - - case EW_SHOWWINDOW: - { - AString hw, sw; - ReadString2(hw, params[0]); - ReadString2(sw, params[1]); - if (params[3] != 0) - s += "EnableWindow"; - else - { - UInt32 val; - bool valDefined = false; - if (StringToUInt32(sw, val)) - { - if (val < Z7_ARRAY_SIZE(kShowWindow_Commands)) - { - sw.Empty(); - sw += "${"; - Add_ShowWindow_Cmd_2(sw, val); - sw += '}'; - valDefined = true; - } - } - bool isHwndParent = IsVarStr(params[0], IsNsis225 ? kVar_HWNDPARENT_225 : kVar_HWNDPARENT); - if (params[2] != 0) - { - if (valDefined && val == 0 && isHwndParent) - { - s += "HideWindow"; - break; - } - } - if (valDefined && val == 5 && isHwndParent && - kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_BRINGTOFRONT) - { - s += " ; "; - } - s += "ShowWindow"; - } - SpaceQuStr(hw); - SpaceQuStr(sw); - break; - } - - case EW_SHELLEXEC: - { - AddParams(params, 2); - if (params[2] != 0 || params[3] != Z7_NSIS_WIN_SW_SHOWNORMAL) - { - AddParam(params[2]); - if (params[3] != Z7_NSIS_WIN_SW_SHOWNORMAL) - { - Space(); - Add_ShowWindow_Cmd(params[3]); - } - } - if (params[5] != 0) - { - s += " ;"; - AddParam(params[5]); // it's tatus text update - } - break; - } - - case EW_EXECUTE: - { - if (params[2] != 0) - s += "Wait"; - AddParam(params[0]); - if (params[2] != 0) - if ((Int32)params[1] >= 0) - AddParam_Var(params[1]); - break; - } - - case EW_GETFILETIME: - case EW_GETDLLVERSION: - { - if (commandId == EW_GETDLLVERSION) - if (params[3] == 2) - s += " /ProductVersion"; // v3.08+ - AddParam(params[2]); - AddParam_Var(params[0]); - AddParam_Var(params[1]); - break; - } - - case EW_REGISTERDLL: - { - AString func; - ReadString2(func, params[1]); - bool printFunc = true; - // params[4] = 1; for plugin command - if (params[2] == 0) - { - s += "CallInstDLL"; - AddParam(params[0]); - if (params[3] == 1) - s += " /NOUNLOAD"; - } - else - { - if (func == "DllUnregisterServer") - { - s += "UnRegDLL"; - printFunc = false; - } - else - { - s += "RegDLL"; - if (func == "DllRegisterServer") - printFunc = false; - } - AddParam(params[0]); - } - if (printFunc) - SpaceQuStr(func); - break; - } - - case EW_CREATESHORTCUT: - { - unsigned numParams; - #define IsNsis3d0b3_OrHigher() 0 // change it - const unsigned v3_0b3 = IsNsis3d0b3_OrHigher(); - for (numParams = 6; numParams > 2; numParams--) - if (params[numParams - 1] != 0) - break; - - const UInt32 spec = params[4]; - const unsigned sw_shift = v3_0b3 ? 12 : 8; - const UInt32 sw_mask = v3_0b3 ? 0x7000 : 0x7F; - if (spec & 0x8000) // NSIS 3.0b0 - s += " /NoWorkingDir"; - - AddParams(params, numParams > 4 ? 4 : numParams); - if (numParams <= 4) - break; - - UInt32 icon = (spec & (v3_0b3 ? 0xFFF : 0xFF)); - Space(); - if (icon != 0) - Add_UInt(icon); - else - AddQuotes(); - - if ((spec >> sw_shift) == 0 && numParams < 6) - break; - UInt32 sw = (spec >> sw_shift) & sw_mask; - Space(); - // NSIS encoder replaces these names: - if (sw == Z7_NSIS_WIN_SW_SHOWMINNOACTIVE) - sw = Z7_NSIS_WIN_SW_SHOWMINIMIZED; - if (sw == 0) - AddQuotes(); - else - Add_ShowWindow_Cmd(sw); - - UInt32 modKey = spec >> 24; - UInt32 key = (spec >> 16) & 0xFF; - - if (modKey == 0 && key == 0) - { - if (numParams < 6) - break; - Space(); - AddQuotes(); - } - else - { - Space(); - if (modKey & 1) s += "SHIFT|"; // HOTKEYF_SHIFT - if (modKey & 2) s += "CONTROL|"; - if (modKey & 4) s += "ALT|"; - if (modKey & 8) s += "EXT|"; - - const unsigned kMy_VK_F1 = 0x70; - if (key >= kMy_VK_F1 && key <= kMy_VK_F1 + 23) - { - s += 'F'; - Add_UInt(key - kMy_VK_F1 + 1); - } - else if ((key >= 'A' && key <= 'Z') || (key >= '0' && key <= '9')) - s += (char)key; - else - { - s += "Char_"; - Add_UInt(key); - } - } - AddOptionalParam(params[5]); // description - break; - } - - case EW_COPYFILES: - { - if (params[2] & 0x04) s += " /SILENT"; // FOF_SILENT - if (params[2] & 0x80) s += " /FILESONLY"; // FOF_FILESONLY - AddParams(params, 2); - if (params[3] != 0) - { - s += " ;"; - AddParam(params[3]); // status text update - } - break; - } - - case EW_REBOOT: - { - if (params[0] != 0xbadf00d) - s += " ; Corrupted ???"; - else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT) - endCommentIndex = kkk + 2; - break; - } - - case EW_WRITEINI: - { - unsigned numAlwaysParams = 0; - if (params[0] == 0) // Section - s += "FlushINI"; - else if (params[4] != 0) - { - s += "WriteINIStr"; - numAlwaysParams = 3; - } - else - { - s += "DeleteINI"; - s += (params[1] == 0) ? "Sec" : "Str"; - numAlwaysParams = 1; - } - AddParam(params[3]); // filename - // Section, EntryName, Value - AddParams(params, numAlwaysParams); - AddOptionalParams(params + numAlwaysParams, 3 - numAlwaysParams); - break; - } - - case EW_READINISTR: - { - AddParam_Var(params[0]); - AddParam(params[3]); // FileName - AddParams(params +1, 2); // Section, EntryName - break; - } - - case EW_DELREG: - { - // NSIS 2.00 used another scheme! - - if (params[4] == 0) - s += "Value"; - else - { - s += "Key"; - if (params[4] & 2) - s += " /ifempty"; - // TODO: /ifnosubkeys, /ifnovalues - } - AddRegRoot(params[1]); - AddParam(params[2]); - AddOptionalParam(params[3]); - break; - } - - case EW_WRITEREG: - { - const char *s2 = NULL; - switch (params[4]) - { - case 1: s2 = "Str"; break; - case 2: s2 = "ExpandStr"; break; // maybe unused - case 3: s2 = "Bin"; break; - case 4: s2 = "DWORD"; break; - default: - s += '?'; - Add_UInt(params[4]); - } - if (params[4] == 1 && params[5] == 2) - s2 = "ExpandStr"; - if (params[4] == 3 && params[5] == 7) - s2 = "MultiStr"; // v3.02+ - if (s2) - s += s2; - AddRegRoot(params[0]); - AddParams(params + 1, 2); // keyName, valueName - if (params[4] != 3) - AddParam(params[3]); // value - else - { - // Binary data. - Space(); - UInt32 offset = params[3]; - bool isSupported = false; - if (AfterHeaderSize >= 4 - && bhData.Offset <= AfterHeaderSize - 4 - && offset <= AfterHeaderSize - 4 - bhData.Offset) - { - // we support it for solid archives. - const Byte *p2 = _afterHeader + bhData.Offset + offset; - UInt32 size = Get32(p2); - if (size <= AfterHeaderSize - 4 - bhData.Offset - offset) - { - for (UInt32 i = 0; i < size; i++) - { - Byte b = (p2 + 4)[i]; - unsigned t; - t = (b >> 4); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); - t = (b & 15); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); - } - isSupported = true; - } - } - if (!isSupported) - { - // we must read from file here; - s += "data["; - Add_UInt(offset); - s += " ... ]"; - s += " ; !!! Unsupported"; - } - } - break; - } - - case EW_READREGSTR: - { - s += (params[4] == 1) ? "DWORD" : "Str"; - AddParam_Var(params[0]); - AddRegRoot(params[1]); - AddParams(params + 2, 2); - break; - } - - case EW_REGENUM: - { - s += (params[4] != 0) ? "Key" : "Value"; - AddParam_Var(params[0]); - AddRegRoot(params[1]); - AddParams(params + 2, 2); - break; - } - - case EW_FCLOSE: - case EW_FINDCLOSE: - { - AddParam_Var(params[0]); - break; - } - - #endif - - case EW_FOPEN: - { - /* - the pattern for empty files is following: - FileOpen $0 "file_name" w - FileClose $0 - */ - - const UInt32 acc = params[1]; // dwDesiredAccess - const UInt32 creat = params[2]; // dwCreationDisposition - if (creat == Z7_NSIS_WIN_CREATE_ALWAYS && acc == Z7_NSIS_WIN_GENERIC_WRITE) - { - if (kkk + 1 < bh.Num) - if (Get32(p + kCmdSize) == EW_FCLOSE) - if (Get32(p + kCmdSize + 4) == params[0]) - { - CItem &item = Items.AddNew(); - item.IsEmptyFile = true; - SetItemName(item, params[3]); - } - } - - #ifdef NSIS_SCRIPT - - AddParam_Var(params[0]); - AddParam(params[3]); - if (acc == 0 && creat == 0) - break; - char cc = 0; - if (creat == Z7_NSIS_WIN_OPEN_EXISTING && acc == Z7_NSIS_WIN_GENERIC_READ) - cc = 'r'; - else if (creat == Z7_NSIS_WIN_CREATE_ALWAYS && acc == Z7_NSIS_WIN_GENERIC_WRITE) - cc = 'w'; - else if (creat == Z7_NSIS_WIN_OPEN_ALWAYS && (acc == (Z7_NSIS_WIN_GENERIC_WRITE | Z7_NSIS_WIN_GENERIC_READ))) - cc = 'a'; - // cc = 0; - if (cc != 0) - { - Space(); - s += cc; - break; - } - - if (acc & Z7_NSIS_WIN_GENERIC_READ) s += " GENERIC_READ"; - if (acc & Z7_NSIS_WIN_GENERIC_WRITE) s += " GENERIC_WRITE"; - if (acc & Z7_NSIS_WIN_GENERIC_EXECUTE) s += " GENERIC_EXECUTE"; - if (acc & Z7_NSIS_WIN_GENERIC_ALL) s += " GENERIC_ALL"; - - const char *s2 = NULL; - switch (creat) - { - case Z7_NSIS_WIN_CREATE_NEW: s2 = "CREATE_NEW"; break; - case Z7_NSIS_WIN_CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break; - case Z7_NSIS_WIN_OPEN_EXISTING: s2 = "OPEN_EXISTING"; break; - case Z7_NSIS_WIN_OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break; - case Z7_NSIS_WIN_TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break; - } - Space(); - if (s2) - s += s2; - else - Add_UInt(creat); - #endif - - break; - } - - #ifdef NSIS_SCRIPT - - case EW_FPUTS: - case EW_FPUTWS: - { - if (commandId == EW_FPUTWS) - s += (params[2] == 0) ? "UTF16LE" : "Word"; - else if (params[2] != 0) - s += "Byte"; - if (params[2] == 0 && params[3]) - s += " /BOM"; // v3.0b3+ - AddParam_Var(params[0]); - AddParam(params[1]); - break; - } - - case EW_FGETS: - case EW_FGETWS: - { - if (commandId == EW_FPUTWS) - s += (params[3] == 0) ? "UTF16LE" : "Word"; - if (params[3] != 0) - s += "Byte"; - AddParam_Var(params[0]); - AddParam_Var(params[1]); - AString maxLenStr; - ReadString2(maxLenStr, params[2]); - UInt32 maxLen; - if (StringToUInt32(maxLenStr, maxLen)) - { - if (maxLen == 1 && params[3] != 0) - break; - if (maxLen == 1023 && params[3] == 0) // NSIS_MAX_STRLEN - 1; can be other value!! - break; - } - SpaceQuStr(maxLenStr); - break; - } - - case EW_FSEEK: - { - AddParam_Var(params[0]); - AddParam(params[2]); - if (params[3] == 1) s += " CUR"; // FILE_CURRENT - if (params[3] == 2) s += " END"; // FILE_END - if ((Int32)params[1] >= 0) - { - if (params[3] == 0) s += " SET"; // FILE_BEGIN - AddParam_Var(params[1]); - } - break; - } - - case EW_FINDNEXT: - { - AddParam_Var(params[1]); - AddParam_Var(params[0]); - break; - } - - case EW_FINDFIRST: - { - AddParam_Var(params[1]); - AddParam_Var(params[0]); - AddParam(params[2]); - break; - } - - case EW_LOG: - { - if (params[0] != 0) - { - s += "Set "; - s += (params[1] == 0) ? "off" : "on"; - } - else - { - s += "Text"; - AddParam(params[1]); - } - break; - } - - case EW_SECTIONSET: - { - if ((Int32)params[2] >= 0) - { - s += "Get"; - Add_SectOp(params[2]); - AddParam(params[0]); - AddParam_Var(params[1]); - } - else - { - s += "Set"; - const UInt32 t = (UInt32)(-(Int32)params[2] - 1); - Add_SectOp(t); - AddParam(params[0]); - AddParam(params[t == 0 ? 4 : 1]); - - // params[3] != 0 means call SectionFlagsChanged in installer - // used by SECTIONSETFLAGS command - } - break; - } - - case EW_INSTTYPESET: - { - unsigned numQwParams = 0; - const char *s2; - if (params[3] == 0) - { - if (params[2] == 0) - { - s2 = "InstTypeGetText"; - numQwParams = 1; - } - else - { - s2 = "InstTypeSetText"; - numQwParams = 2; - } - } - else - { - if (params[2] == 0) - s2 = "GetCurInstType"; - else - { - s2 = "SetCurInstType"; - numQwParams = 1; - } - } - s += s2; - AddParams(params, numQwParams); - if (params[2] == 0) - AddParam_Var(params[1]); - break; - } - - case EW_GETOSINFO: - { - if (IsNsis3_OrHigher()) - { - // v3.06+ - if (params[3] == 0) // GETOSINFO_KNOWNFOLDER - { - s += "GetKnownFolderPath"; - AddParam_Var(params[1]); - AddParam(params[2]); - break; - } - else if (params[3] == 1) // GETOSINFO_READMEMORY - { - s += "ReadMemory"; - AddParam_Var(params[1]); - AddParam(params[2]); - AddParam(params[4]); - // if (params[2] == "0") AddCommentAndString("GetWinVer"); - } - else - s += "GetOsInfo"; - break; - } - s += "GetLabelAddr"; // before v3.06+ - break; - } - - case EW_LOCKWINDOW: - { - s += (params[0] == 0) ? " on" : " off"; - break; - } - - case EW_FINDPROC: - { - AddParam_Var(params[0]); - AddParam(params[1]); - break; - } - - default: - { - numSkipParams = 0; - } - #endif - } - - #ifdef NSIS_SCRIPT - - unsigned numParams = kNumCommandParams; - - for (; numParams > 0; numParams--) - if (params[numParams - 1] != 0) - break; - - if (numParams > numSkipParams) - { - s += " ; !!!! Unknown Params: "; - unsigned i; - for (i = 0; i < numParams; i++) - AddParam(params[i]); - - s += " ;"; - - for (i = 0; i < numParams; i++) - { - Space(); - UInt32 v = params[i]; - if (v > 0xFFF00000) - Add_SignedInt(s, (Int32)v); - else - Add_UInt(v); - } - } - - NewLine(); - - #endif - } - - #ifdef NSIS_SCRIPT - - if (sectionIsOpen) - { - if (curSectionIndex < bhSections.Num) - { - const CSection § = Sections[curSectionIndex]; - if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk) - { - PrintSectionEnd(); - sectionIsOpen = false; - // lastSectionEndCmd = kkk; - curSectionIndex++; - } - } - } - - while (curSectionIndex < bhSections.Num) - { - const CSection § = Sections[curSectionIndex]; - if (sectionIsOpen) - { - if (sect.StartCmdIndex + sect.NumCommands != kkk) - AddErrorLF("SECTION ERROR"); - PrintSectionEnd(); - sectionIsOpen = false; - curSectionIndex++; - } - else - { - if (PrintSectionBegin(sect, curSectionIndex)) - curSectionIndex++; - else - sectionIsOpen = true; - } - } - - #endif - - return S_OK; -} - -static int CompareItems(void *const *p1, void *const *p2, void *param) -{ - const CItem &i1 = **(const CItem *const *)p1; - const CItem &i2 = **(const CItem *const *)p2; - RINOZ(MyCompare(i1.Pos, i2.Pos)) - - /* In another code we check CItem::Pos after each solid item. - So here we place empty files before all non empty files */ - if (i1.IsEmptyFile) - { - if (!i2.IsEmptyFile) - return -1; - } - else if (i2.IsEmptyFile) - return 1; - - const CInArchive *inArchive = (const CInArchive *)param; - if (inArchive->IsUnicode) - { - if (i1.Prefix != i2.Prefix) - { - if (i1.Prefix < 0) return -1; - if (i2.Prefix < 0) return 1; - RINOZ( - inArchive->UPrefixes[i1.Prefix].Compare( - inArchive->UPrefixes[i2.Prefix])) - } - RINOZ(i1.NameU.Compare(i2.NameU)) - } - else - { - if (i1.Prefix != i2.Prefix) - { - if (i1.Prefix < 0) return -1; - if (i2.Prefix < 0) return 1; - RINOZ(strcmp( - inArchive->APrefixes[i1.Prefix], - inArchive->APrefixes[i2.Prefix])) - } - RINOZ(strcmp(i1.NameA, i2.NameA)) - } - return 0; -} - -HRESULT CInArchive::SortItems() -{ - { - Items.Sort(CompareItems, (void *)this); - unsigned i; - - for (i = 0; i + 1 < Items.Size(); i++) - { - const CItem &i1 = Items[i]; - if (i1.IsEmptyFile) - continue; - const CItem &i2 = Items[i + 1]; - if (i1.Pos != i2.Pos) - continue; - - if (IsUnicode) - { - if (i1.NameU != i2.NameU) continue; - if (i1.Prefix != i2.Prefix) - { - if (i1.Prefix < 0 || i2.Prefix < 0) continue; - if (UPrefixes[i1.Prefix] != UPrefixes[i2.Prefix]) continue; - } - } - else - { - if (i1.NameA != i2.NameA) continue; - if (i1.Prefix != i2.Prefix) - { - if (i1.Prefix < 0 || i2.Prefix < 0) continue; - if (APrefixes[i1.Prefix] != APrefixes[i2.Prefix]) continue; - } - } - Items.Delete(i + 1); - i--; - } - - for (i = 0; i < Items.Size(); i++) - { - CItem &item = Items[i]; - if (item.IsEmptyFile) - continue; - const UInt32 curPos = item.Pos + 4; - for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) - { - const CItem &nextItem = Items[nextIndex]; - // if (nextItem.IsEmptyFile) continue; - const UInt32 nextPos = nextItem.Pos; - if (curPos <= nextPos) - { - item.EstimatedSize_Defined = true; - item.EstimatedSize = nextPos - curPos; - break; - } - } - } - - if (!IsSolid) - { - for (i = 0; i < Items.Size(); i++) - { - CItem &item = Items[i]; - if (item.IsEmptyFile) - continue; - RINOK(SeekToNonSolidItem(i)) - const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict - BYTE sig[kSigSize]; - size_t processedSize = kSigSize; - RINOK(ReadStream(_stream, sig, &processedSize)) - if (processedSize < 4) - return S_FALSE; - UInt32 size = Get32(sig); - if ((size & kMask_IsCompressed) != 0) - { - item.IsCompressed = true; - size &= ~kMask_IsCompressed; - if (Method == NMethodType::kLZMA) - { - if (processedSize < 9) - return S_FALSE; - /* - if (FilterFlag) - item.UseFilter = (sig[4] != 0); - */ - item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0)); - } - } - else - { - item.IsCompressed = false; - item.Size = size; - item.Size_Defined = true; - } - item.CompressedSize = size; - item.CompressedSize_Defined = true; - } - } - } - return S_OK; -} - -#ifdef NSIS_SCRIPT -// Flags for common_header.flags -// #define CH_FLAGS_DETAILS_SHOWDETAILS 1 -// #define CH_FLAGS_DETAILS_NEVERSHOW 2 -#define CH_FLAGS_PROGRESS_COLORED 4 -#define CH_FLAGS_SILENT 8 -#define CH_FLAGS_SILENT_LOG 16 -#define CH_FLAGS_AUTO_CLOSE 32 -// #define CH_FLAGS_DIR_NO_SHOW 64 // unused now -#define CH_FLAGS_NO_ROOT_DIR 128 -#define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256 -#define CH_FLAGS_NO_CUSTOM 512 - -static const char * const k_PostStrings[] = -{ - "install_directory_auto_append" - , "uninstchild" // NSIS 2.25+, used by uninstaller: - , "uninstcmd" // NSIS 2.25+, used by uninstaller: - , "wininit" // NSIS 2.25+, used by move file on reboot -}; -#endif - - -void CBlockHeader::Parse(const Byte *p, unsigned bhoSize) -{ - if (bhoSize == 12) - { - // UInt64 a = GetUi64(p); - if (GetUi32(p + 4) != 0) - throw 1; - } - Offset = GetUi32(p); - Num = GetUi32(p + bhoSize - 4); -} - -#define PARSE_BH(k, bh) bh.Parse (p1 + 4 + bhoSize * k, bhoSize) - - -HRESULT CInArchive::Parse() -{ - // UInt32 offset = ReadUInt32(); - // ???? offset == FirstHeader.HeaderSize - const Byte * const p1 = _data; - - if (_size < 4 + 12 * 8) - Is64Bit = false; - else - { - Is64Bit = true; - // here we test high 32-bit of possible UInt64 CBlockHeader::Offset field - for (int k = 0; k < 8; k++) - if (GetUi32(p1 + 4 + 12 * k + 4) != 0) - Is64Bit = false; - } - - const unsigned bhoSize = Is64Bit ? 12 : 8; - if (_size < 4 + bhoSize * 8) - return S_FALSE; - - CBlockHeader bhEntries, bhStrings, bhLangTables; - - PARSE_BH (2, bhEntries); - PARSE_BH (3, bhStrings); - PARSE_BH (4, bhLangTables); - - #ifdef NSIS_SCRIPT - - CBlockHeader bhFont; - PARSE_BH (0, bhPages); - PARSE_BH (1, bhSections); - PARSE_BH (5, bhCtlColors); - PARSE_BH (6, bhFont); - PARSE_BH (7, bhData); - - #endif - - _stringsPos = bhStrings.Offset; - if (_stringsPos > _size - || bhLangTables.Offset > _size - || bhEntries.Offset > _size) - return S_FALSE; - { - if (bhLangTables.Offset < bhStrings.Offset) - return S_FALSE; - const UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset; - if (stringTableSize < 2) - return S_FALSE; - const Byte *strData = _data + _stringsPos; - if (strData[stringTableSize - 1] != 0) - return S_FALSE; - IsUnicode = (Get16(strData) == 0); - NumStringChars = stringTableSize; - if (IsUnicode) - { - if ((stringTableSize & 1) != 0) - return S_FALSE; - NumStringChars >>= 1; - if (strData[stringTableSize - 2] != 0) - return S_FALSE; - } - } - - if (bhEntries.Num > (1 << 25)) - return S_FALSE; - if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) - return S_FALSE; - - DetectNsisType(bhEntries, _data + bhEntries.Offset); - - Decoder.IsNsisDeflate = (NsisType != k_NsisType_Nsis3); - - // some NSIS files (that are not detected as k_NsisType_Nsis3) - // use original (non-NSIS) Deflate - // How to detect these cases? - - // Decoder.IsNsisDeflate = false; - - - #ifdef NSIS_SCRIPT - - { - AddCommentAndString("NSIS script"); - if (IsUnicode) - Script += " (UTF-8)"; - Space(); - Script += GetFormatDescription(); - AddLF(); - } - { - AddCommentAndString(IsInstaller ? "Install" : "Uninstall"); - AddLF(); - } - - AddLF(); - if (Is64Bit) - AddStringLF("Target AMD64-Unicode"); // TODO: Read PE machine type and use the correct CPU type - else if (IsUnicode) - AddStringLF("Unicode true"); - else if (IsNsis3_OrHigher()) - AddStringLF("Unicode false"); // Unicode is the default in 3.07+ - - if (Method != NMethodType::kCopy) - { - const char *m = NULL; - switch ((int)Method) - { - case NMethodType::kDeflate: m = "zlib"; break; - case NMethodType::kBZip2: m = "bzip2"; break; - case NMethodType::kLZMA: m = "lzma"; break; - default: break; - } - Script += "SetCompressor"; - if (IsSolid) - Script += " /SOLID"; - if (m) - { - Space(); - Script += m; - } - AddLF(); - } - if (Method == NMethodType::kLZMA) - { - // if (DictionarySize != (8 << 20)) - { - Script += "SetCompressorDictSize"; - AddParam_UInt(DictionarySize >> 20); - AddLF(); - } - } - - Separator(); - PrintNumComment("HEADER SIZE", FirstHeader.HeaderSize); - // if (bhPages.Offset != 300 && bhPages.Offset != 288) - if (bhPages.Offset != 0) - { - PrintNumComment("START HEADER SIZE", bhPages.Offset); - } - - if (bhSections.Num > 0) - { - if (bhEntries.Offset < bhSections.Offset) - return S_FALSE; - SectionSize = (bhEntries.Offset - bhSections.Offset) / bhSections.Num; - if (bhSections.Offset + bhSections.Num * SectionSize != bhEntries.Offset) - return S_FALSE; - if (SectionSize < kSectionSize_base) - return S_FALSE; - UInt32 maxStringLen = SectionSize - kSectionSize_base; - if (IsUnicode) - { - if ((maxStringLen & 1) != 0) - return S_FALSE; - maxStringLen >>= 1; - } - // if (maxStringLen != 1024) - { - if (maxStringLen == 0) - PrintNumComment("SECTION SIZE", SectionSize); - else - PrintNumComment("MAX STRING LENGTH", maxStringLen); - } - } - - PrintNumComment("STRING CHARS", NumStringChars); - // PrintNumComment("LANG TABLE SIZE", bhCtlColors.Offset - bhLangTables.Offset); - - if (bhCtlColors.Offset > _size) - AddErrorLF("Bad COLORS TABLE"); - // PrintNumComment("COLORS TABLE SIZE", bhFont.Offset - bhCtlColors.Offset); - if (bhCtlColors.Num != 0) - PrintNumComment("COLORS Num", bhCtlColors.Num); - - // bhData uses offset in _afterHeader (not in _data) - // PrintNumComment("FONT TABLE SIZE", bhData.Offset - bhFont.Offset); - if (bhFont.Num != 0) - PrintNumComment("FONTS Num", bhFont.Num); - - // PrintNumComment("DATA SIZE", FirstHeader.HeaderSize - bhData.Offset); - if (bhData.Num != 0) - PrintNumComment("DATA NUM", bhData.Num); - - AddLF(); - - AddStringLF("OutFile [NSIS].exe"); - AddStringLF("!include WinMessages.nsh"); - - AddLF(); - - strUsed.Alloc(NumStringChars); - memset(strUsed, 0, NumStringChars); - - { - UInt32 ehFlags = Get32(p1); - UInt32 showDetails = ehFlags & 3;// CH_FLAGS_DETAILS_SHOWDETAILS & CH_FLAGS_DETAILS_NEVERSHOW; - if (showDetails >= 1 && showDetails <= 2) - { - Script += IsInstaller ? "ShowInstDetails" : "ShowUninstDetails"; - Script += (showDetails == 1) ? " show" : " nevershow"; - AddLF(); - } - if (ehFlags & CH_FLAGS_PROGRESS_COLORED) AddStringLF("InstProgressFlags colored" ); - if ((ehFlags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG)) != 0) - { - Script += IsInstaller ? "SilentInstall " : "SilentUnInstall "; - Script += (ehFlags & CH_FLAGS_SILENT_LOG) ? "silentlog" : "silent"; - AddLF(); - } - if (ehFlags & CH_FLAGS_AUTO_CLOSE) AddStringLF("AutoCloseWindow true"); - if ((ehFlags & CH_FLAGS_NO_ROOT_DIR) == 0) AddStringLF("AllowRootDirInstall true"); - if (ehFlags & CH_FLAGS_NO_CUSTOM) AddStringLF("InstType /NOCUSTOM"); - if (ehFlags & CH_FLAGS_COMP_ONLY_ON_CUSTOM) AddStringLF("InstType /COMPONENTSONLYONCUSTOM"); - } - - // Separator(); - // AddLF(); - - Int32 licenseLangIndex = -1; - { - const Byte *pp = _data + bhPages.Offset; - - for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, pp += kPageSize) - { - UInt32 wndProcID = Get32(pp + 4); - UInt32 param1 = Get32(pp + 44 + 4 * 1); - if (wndProcID != PWP_LICENSE || param1 == 0) - continue; - if ((Int32)param1 < 0) - licenseLangIndex = - ((Int32)param1 + 1); - else - noParseStringIndexes.AddToUniqueSorted(param1); - } - } - - unsigned paramsOffset; - { - unsigned numBhs = 8; - // probably its for old NSIS? - if (bhoSize == 8 && bhPages.Offset == 276) - numBhs = 7; - paramsOffset = 4 + bhoSize * numBhs; - } - - const Byte *p2 = p1 + paramsOffset; - - { - UInt32 rootKey = Get32(p2); // (rootKey = -1) in uninstaller by default (the bug in NSIS) - UInt32 subKey = Get32(p2 + 4); - UInt32 value = Get32(p2 + 8); - if ((rootKey != 0 && rootKey != (UInt32)(Int32)-1) || subKey != 0 || value != 0) - { - Script += "InstallDirRegKey"; - AddRegRoot(rootKey); - AddParam(subKey); - AddParam(value); - AddLF(); - } - } - - - { - UInt32 bg_color1 = Get32(p2 + 12); - UInt32 bg_color2 = Get32(p2 + 16); - UInt32 bg_textcolor = Get32(p2 + 20); - if (bg_color1 != (UInt32)(Int32)-1 || bg_color2 != (UInt32)(Int32)-1 || bg_textcolor != (UInt32)(Int32)-1) - { - Script += "BGGradient"; - if (bg_color1 != 0 || bg_color2 != 0xFF0000 || bg_textcolor != (UInt32)(Int32)-1) - { - Add_ColorParam(bg_color1); - Add_ColorParam(bg_color2); - if (bg_textcolor != (UInt32)(Int32)-1) - Add_ColorParam(bg_textcolor); - } - AddLF(); - } - } - - { - UInt32 lb_bg = Get32(p2 + 24); - UInt32 lb_fg = Get32(p2 + 28); - if ((lb_bg != (UInt32)(Int32)-1 || lb_fg != (UInt32)(Int32)-1) && - (lb_bg != 0 || lb_fg != 0xFF00)) - { - Script += "InstallColors"; - Add_ColorParam(lb_fg); - Add_ColorParam(lb_bg); - AddLF(); - } - } - - UInt32 license_bg = Get32(p2 + 36); - if (license_bg != (UInt32)(Int32)-1 && - license_bg != (UInt32)(Int32)-15) // COLOR_BTNFACE - { - Script += "LicenseBkColor"; - if ((Int32)license_bg == -5) // COLOR_WINDOW - Script += " /windows"; - /* - else if ((Int32)license_bg == -15) - Script += " /grey"; - */ - else - Add_ColorParam(license_bg); - AddLF(); - } - - if (bhLangTables.Num > 0) - { - const UInt32 langtable_size = Get32(p2 + 32); - - if (langtable_size == (UInt32)(Int32)-1) - return E_NOTIMPL; // maybe it's old NSIS archive() - - if (langtable_size < 10) - return S_FALSE; - if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size) - return S_FALSE; - - const UInt32 numStrings = (langtable_size - 10) / 4; - _numLangStrings = numStrings; - AddLF(); - Separator(); - PrintNumComment("LANG TABLES", bhLangTables.Num); - PrintNumComment("LANG STRINGS", numStrings); - AddLF(); - - if (licenseLangIndex >= 0 && (unsigned)licenseLangIndex < numStrings) - { - for (UInt32 i = 0; i < bhLangTables.Num; i++) - { - const Byte * const p = _data + bhLangTables.Offset + langtable_size * i; - const UInt16 langID = Get16(p); - UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4); - if (val != 0) - { - Script += "LicenseLangString "; - Add_LangStr_Simple((UInt32)licenseLangIndex); - AddParam_UInt(langID); - AddLicense(val, langID); - noParseStringIndexes.AddToUniqueSorted(val); - NewLine(); - } - } - AddLF(); - } - - UInt32 names[3] = { 0 }; - - UInt32 i; - for (i = 0; i < bhLangTables.Num; i++) - { - const Byte * const p = _data + bhLangTables.Offset + langtable_size * i; - const UInt16 langID = Get16(p); - if (i == 0 || langID == 1033) - _mainLang = p + 10; - for (unsigned k = 0; k < Z7_ARRAY_SIZE(names) && k < numStrings; k++) - { - UInt32 v = Get32(p + 10 + k * 4); - if (v != 0 && (langID == 1033 || names[k] == 0)) - names[k] = v; - } - } - - const UInt32 name = names[2]; - if (name != 0) - { - Script += "Name"; - AddParam(name); - NewLine(); - - ReadString2(Name, name); - } - - /* - const UInt32 caption = names[1]; - if (caption != 0) - { - Script += "Caption"; - AddParam(caption); - NewLine(); - } - */ - - const UInt32 brandingText = names[0]; - if (brandingText != 0) - { - Script += "BrandingText"; - AddParam(brandingText); - NewLine(); - - ReadString2(BrandingText, brandingText); - } - - for (i = 0; i < bhLangTables.Num; i++) - { - const Byte * const p = _data + bhLangTables.Offset + langtable_size * i; - const UInt16 langID = Get16(p); - - AddLF(); - AddCommentAndString("LANG:"); - AddParam_UInt(langID); - /* - Script += " ("; - LangId_To_String(Script, langID); - Script += ')'; - */ - AddLF(); - // UInt32 dlg_offset = Get32(p + 2); - // UInt32 g_exec_flags_rtl = Get32(p + 6); - - - for (UInt32 j = 0; j < numStrings; j++) - { - UInt32 val = Get32(p + 10 + j * 4); - if (val != 0) - { - if ((Int32)j != licenseLangIndex) - { - Script += "LangString "; - Add_LangStr_Simple(j); - AddParam_UInt(langID); - AddParam(val); - AddLF(); - } - } - } - AddLF(); - } - ClearLangComment(); - } - - { - unsigned numInternalVars = GET_NUM_INTERNAL_VARS; - UInt32 numUsedVars = GetNumUsedVars(); - if (numUsedVars > numInternalVars) - { - Separator(); - PrintNumComment("VARIABLES", numUsedVars - numInternalVars); - AddLF(); - AString temp; - for (UInt32 i = numInternalVars; i < numUsedVars; i++) - { - Script += "Var "; - temp.Empty(); - GetVar2(temp, i); - AddStringLF(temp); - } - AddLF(); - } - } - - onFuncOffset = paramsOffset + 40; - numOnFunc = Z7_ARRAY_SIZE(kOnFunc); - if (bhPages.Offset == 276) - numOnFunc--; - p2 += 40 + numOnFunc * 4; - - #define NSIS_MAX_INST_TYPES 32 - - AddLF(); - - UInt32 i; - for (i = 0; i < NSIS_MAX_INST_TYPES + 1; i++, p2 += 4) - { - UInt32 instType = Get32(p2); - if (instType != 0) - { - Script += "InstType"; - AString s2; - if (!IsInstaller) - s2 += "un."; - ReadString2(s2, instType); - SpaceQuStr(s2); - NewLine(); - } - } - - { - UInt32 installDir = Get32(p2); - p2 += 4; - if (installDir != 0) - { - Script += "InstallDir"; - AddParam(installDir); - NewLine(); - } - } - - if (bhPages.Offset >= 288) - for (i = 0; i < 4; i++) - { - if (i != 0 && bhPages.Offset < 300) - break; - UInt32 param = Get32(p2 + 4 * i); - if (param == 0 || param == (UInt32)(Int32)-1) - continue; - - /* - uninstaller: - UInt32 uninstChild = Get32(p2 + 8); // "$TEMP\\$1u_.exe" - UInt32 uninstCmd = Get32(p2 + 12); // "\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\" - int str_wininit = Get32(p2 + 16); // "$WINDIR\\wininit.ini" - */ - - AddCommentAndString(k_PostStrings[i]); - Script += " ="; - AddParam(param); - NewLine(); - } - - AddLF(); - - #endif - - RINOK(ReadEntries(bhEntries)) - - #ifdef NSIS_SCRIPT - - Separator(); - AddCommentAndString("UNREFERENCED STRINGS:"); - AddLF(); - AddLF(); - CommentOpen(); - - for (i = 0; i < NumStringChars;) - { - if (!strUsed[i] && i != 0) - // Script += "!!! "; - { - Add_UInt(i); - AddParam(i); - NewLine(); - } - if (IsUnicode) - i += GetUi16Str_Len((const Byte *)_data + _stringsPos + i * 2); - else - i += (UInt32)strlen((const char *)(const Byte *)_data + _stringsPos + i); - i++; - } - CommentClose(); - #endif - - return SortItems(); -} - -static bool IsLZMA(const Byte *p, UInt32 &dictionary) -{ - dictionary = Get32(p + 1); - return (p[0] == 0x5D && - p[1] == 0x00 && p[2] == 0x00 && - p[5] == 0x00 && (p[6] & 0x80) == 0x00); -} - -static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) -{ - if (IsLZMA(p, dictionary)) - { - thereIsFlag = false; - return true; - } - if (p[0] <= 1 && IsLZMA(p + 1, dictionary)) - { - thereIsFlag = true; - return true; - } - return false; -} - -static bool IsBZip2(const Byte *p) -{ - return (p[0] == 0x31 && p[1] < 14); -} - -HRESULT CInArchive::Open2(const Byte *sig, size_t size) -{ - const UInt32 kSigSize = 4 + 1 + 5 + 2; // size, flag, 5 - lzma props, 2 - lzma first bytes - if (size < kSigSize) - return S_FALSE; - - _headerIsCompressed = true; - IsSolid = true; - FilterFlag = false; - UseFilter = false; - DictionarySize = 1; - - #ifdef NSIS_SCRIPT - AfterHeaderSize = 0; - #endif - - UInt32 compressedHeaderSize = Get32(sig); - - - /* - XX XX XX XX XX XX XX XX == FirstHeader.HeaderSize, nonsolid, uncompressed - 5D 00 00 dd dd 00 solid LZMA - 00 5D 00 00 dd dd 00 solid LZMA, empty filter (there are no such archives) - 01 5D 00 00 dd dd 00 solid LZMA, BCJ filter (only 7-Zip installer used that format) - - SS SS SS 80 00 5D 00 00 dd dd 00 non-solid LZMA, empty filter - SS SS SS 80 01 5D 00 00 dd dd 00 non-solid LZMA, BCJ filte - SS SS SS 80 01 tt non-solid BZip (tt < 14 - SS SS SS 80 non-solid deflate - - 01 tt solid BZip (tt < 14 - other solid Deflate - */ - - if (compressedHeaderSize == FirstHeader.HeaderSize) - { - _headerIsCompressed = false; - IsSolid = false; - Method = NMethodType::kCopy; - } - else if (IsLZMA(sig, DictionarySize, FilterFlag)) - Method = NMethodType::kLZMA; - else if (sig[3] == 0x80) - { - IsSolid = false; - if (IsLZMA(sig + 4, DictionarySize, FilterFlag) && sig[3] == 0x80) - Method = NMethodType::kLZMA; - else if (IsBZip2(sig + 4)) - Method = NMethodType::kBZip2; - else - Method = NMethodType::kDeflate; - } - else if (IsBZip2(sig)) - Method = NMethodType::kBZip2; - else - Method = NMethodType::kDeflate; - - if (IsSolid) - { - RINOK(SeekTo_DataStreamOffset()) - } - else - { - _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0); - compressedHeaderSize &= ~kMask_IsCompressed; - _nonSolidStartOffset = compressedHeaderSize; - RINOK(SeekTo(DataStreamOffset + 4)) - } - - if (FirstHeader.HeaderSize == 0) - return S_FALSE; - - _data.Alloc(FirstHeader.HeaderSize); - _size = (size_t)FirstHeader.HeaderSize; - - Decoder.Method = Method; - Decoder.FilterFlag = FilterFlag; - Decoder.Solid = IsSolid; - - Decoder.IsNsisDeflate = true; // we need some smart check that NSIS is not NSIS3 here. - - Decoder.InputStream = _stream; - Decoder.Buffer.Alloc(kInputBufSize); - Decoder.StreamPos = 0; - - if (_headerIsCompressed) - { - RINOK(Decoder.Init(_stream, UseFilter)) - if (IsSolid) - { - size_t processedSize = 4; - Byte buf[4]; - RINOK(Decoder.Read(buf, &processedSize)) - if (processedSize != 4) - return S_FALSE; - if (Get32((const Byte *)buf) != FirstHeader.HeaderSize) - return S_FALSE; - } - { - size_t processedSize = FirstHeader.HeaderSize; - RINOK(Decoder.Read(_data, &processedSize)) - if (processedSize != FirstHeader.HeaderSize) - return S_FALSE; - } - - #ifdef NSIS_SCRIPT - if (IsSolid) - { - /* we need additional bytes for data for WriteRegBin */ - AfterHeaderSize = (1 << 12); - _afterHeader.Alloc(AfterHeaderSize); - size_t processedSize = AfterHeaderSize; - RINOK(Decoder.Read(_afterHeader, &processedSize)) - AfterHeaderSize = (UInt32)processedSize; - } - #endif - } - else - { - size_t processedSize = FirstHeader.HeaderSize; - RINOK(ReadStream(_stream, (Byte *)_data, &processedSize)) - if (processedSize < FirstHeader.HeaderSize) - return S_FALSE; - } - - #ifdef NUM_SPEED_TESTS - for (unsigned i = 0; i < NUM_SPEED_TESTS; i++) - { - RINOK(Parse()); - Clear2(); - } - #endif - - return Parse(); -} - -/* -NsisExe = -{ - ExeStub - Archive // must start from 512 * N - #ifndef NSIS_CONFIG_CRC_ANAL - { - Some additional data - } -} - -Archive -{ - FirstHeader - Data - #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc() - { - CRC - } -} - -FirstHeader -{ - UInt32 Flags; - Byte Signature[16]; - // points to the header+sections+entries+stringtable in the datablock - UInt32 HeaderSize; - UInt32 ArcSize; -} -*/ - - -// ---------- PE (EXE) parsing ---------- - -static const unsigned k_PE_StartSize = 0x40; -static const unsigned k_PE_HeaderSize = 4 + 20; -static const unsigned k_PE_OptHeader32_Size_MIN = 96; - -static inline bool CheckPeOffset(UInt32 pe) -{ - return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0); -} - - -static bool IsArc_Pe(const Byte *p, size_t size) -{ - if (size < 2) - return false; - if (p[0] != 'M' || p[1] != 'Z') - return false; - if (size < k_PE_StartSize) - return false; // k_IsArc_Res_NEED_MORE; - UInt32 pe = Get32(p + 0x3C); - if (!CheckPeOffset(pe)) - return false; - if (pe + k_PE_HeaderSize > size) - return false; // k_IsArc_Res_NEED_MORE; - - p += pe; - if (Get32(p) != 0x00004550) - return false; - return Get16(p + 4 + 16) >= k_PE_OptHeader32_Size_MIN; -} - -HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition) -{ - Clear(); - - RINOK(InStream_GetPos(inStream, StartOffset)) - - const UInt32 kStartHeaderSize = 4 * 7; - const unsigned kStep = 512; // nsis start is aligned for 512 - Byte buf[kStep]; - UInt64 pos = StartOffset; - size_t bufSize = 0; - UInt64 pePos = (UInt64)(Int64)-1; - - for (;;) - { - bufSize = kStep; - RINOK(ReadStream(inStream, buf, &bufSize)) - if (bufSize < kStartHeaderSize) - return S_FALSE; - if (memcmp(buf + 4, kSignature, kSignatureSize) == 0) - break; - if (IsArc_Pe(buf, bufSize)) - pePos = pos; - pos += kStep; - UInt64 proc = pos - StartOffset; - if (maxCheckStartPosition && proc > *maxCheckStartPosition) - { - if (pePos == 0) - { - if (proc > (1 << 20)) - return S_FALSE; - } - else - return S_FALSE; - } - } - - if (pePos == (UInt64)(Int64)-1) - { - UInt64 posCur = StartOffset; - for (;;) - { - if (posCur < kStep) - break; - posCur -= kStep; - if (pos - posCur > (1 << 20)) - break; - bufSize = kStep; - RINOK(InStream_SeekSet(inStream, posCur)) - RINOK(ReadStream(inStream, buf, &bufSize)) - if (bufSize < kStep) - break; - if (IsArc_Pe(buf, bufSize)) - { - pePos = posCur; - break; - } - } - - // restore buf to nsis header - bufSize = kStep; - RINOK(InStream_SeekSet(inStream, pos)) - RINOK(ReadStream(inStream, buf, &bufSize)) - if (bufSize < kStartHeaderSize) - return S_FALSE; - } - - StartOffset = pos; - UInt32 peSize = 0; - - if (pePos != (UInt64)(Int64)-1) - { - UInt64 peSize64 = (pos - pePos); - if (peSize64 < (1 << 20)) - { - peSize = (UInt32)peSize64; - StartOffset = pePos; - } - } - - DataStreamOffset = pos + kStartHeaderSize; - FirstHeader.Flags = Get32(buf); - if ((FirstHeader.Flags & (~kFlagsMask)) != 0) - { - // return E_NOTIMPL; - return S_FALSE; - } - IsInstaller = (FirstHeader.Flags & NFlags::kUninstall) == 0; - - FirstHeader.HeaderSize = Get32(buf + kSignatureSize + 4); - FirstHeader.ArcSize = Get32(buf + kSignatureSize + 8); - if (FirstHeader.ArcSize <= kStartHeaderSize) - return S_FALSE; - - /* - if ((FirstHeader.Flags & NFlags::k_BI_ExternalFileSupport) != 0) - { - UInt32 datablock_low = Get32(buf + kSignatureSize + 12); - UInt32 datablock_high = Get32(buf + kSignatureSize + 16); - } - */ - - RINOK(InStream_GetSize_SeekToEnd(inStream, _fileSize)) - - IsArc = true; - - if (peSize != 0) - { - ExeStub.Alloc(peSize); - RINOK(InStream_SeekSet(inStream, pePos)) - RINOK(ReadStream_FALSE(inStream, ExeStub, peSize)) - } - - HRESULT res = S_FALSE; - try - { - CLimitedInStream *_limitedStreamSpec = new CLimitedInStream; - _stream = _limitedStreamSpec; - _limitedStreamSpec->SetStream(inStream); - _limitedStreamSpec->InitAndSeek(pos, FirstHeader.ArcSize); - DataStreamOffset -= pos; - res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize); - } - catch(...) - { - _stream.Release(); - throw; - // res = S_FALSE; - } - if (res != S_OK) - { - _stream.Release(); - // Clear(); - } - return res; -} - -UString CInArchive::ConvertToUnicode(const AString &s) const -{ - if (IsUnicode) - { - UString res; - // if ( - ConvertUTF8ToUnicode(s, res); - return res; - } - return MultiByteToUnicodeString(s); -} - -void CInArchive::Clear2() -{ - IsUnicode = false; - NsisType = k_NsisType_Nsis2; - IsNsis225 = false; - IsNsis200 = false; - LogCmdIsEnabled = false; - BadCmd = -1; - Is64Bit = false; - - #ifdef NSIS_SCRIPT - Name.Empty(); - BrandingText.Empty(); - Script.Empty(); - LicenseFiles.Clear(); - _numRootLicenses = 0; - _numLangStrings = 0; - langStrIDs.Clear(); - LangComment.Empty(); - noParseStringIndexes.Clear(); - #endif - - APrefixes.Clear(); - UPrefixes.Clear(); - Items.Clear(); - IsUnicode = false; - ExeStub.Free(); -} - -void CInArchive::Clear() -{ - Clear2(); - IsArc = false; - _stream.Release(); -} - -}} +// NsisIn.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" + +#include "../../Common/LimitedStreams.h" + +#include "NsisIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +// #define NUM_SPEED_TESTS 1000 + +namespace NArchive { +namespace NNsis { + +static const size_t kInputBufSize = 1 << 20; + +const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; +static const UInt32 kMask_IsCompressed = (UInt32)1 << 31; + +static const unsigned kNumCommandParams = 6; +static const unsigned kCmdSize = 4 + kNumCommandParams * 4; + +#ifdef NSIS_SCRIPT +#define CR_LF "\x0D\x0A" +#endif + +static const char * const kErrorStr = "$_ERROR_STR_"; + +#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } + + +/* There are several versions of NSIS: + 1) Original NSIS: + NSIS-2 ANSI + NSIS-3 ANSI + NSIS-3 Unicode + 2) NSIS from Jim Park that extends old NSIS-2 to Unicode support: + NSIS-Park-(1,2,3) ANSI + NSIS-Park-(1,2,3) Unicode + + The command IDs layout is slightly different for different versions. + Also there are additional "log" versions of NSIS that support EW_LOG. + We use the layout of "NSIS-3 Unicode" without "log" as main layout. + And we transfer the command IDs to main layout, if another layout is detected. */ + + +enum +{ + EW_INVALID_OPCODE, + EW_RET, // Return + EW_NOP, // Nop, Goto + EW_ABORT, // Abort + EW_QUIT, // Quit + EW_CALL, // Call, InitPluginsDir + EW_UPDATETEXT, // DetailPrint + EW_SLEEP, // Sleep + EW_BRINGTOFRONT, // BringToFront + EW_CHDETAILSVIEW, // SetDetailsView + EW_SETFILEATTRIBUTES, // SetFileAttributes + EW_CREATEDIR, // CreateDirectory, SetOutPath + EW_IFFILEEXISTS, // IfFileExists + EW_SETFLAG, // SetRebootFlag, ... + EW_IFFLAG, // IfAbort, IfSilent, IfErrors, IfRebootFlag + EW_GETFLAG, // GetInstDirError, GetErrorLevel + EW_RENAME, // Rename + EW_GETFULLPATHNAME, // GetFullPathName + EW_SEARCHPATH, // SearchPath + EW_GETTEMPFILENAME, // GetTempFileName + EW_EXTRACTFILE, // File + EW_DELETEFILE, // Delete + EW_MESSAGEBOX, // MessageBox + EW_RMDIR, // RMDir + EW_STRLEN, // StrLen + EW_ASSIGNVAR, // StrCpy + EW_STRCMP, // StrCmp + EW_READENVSTR, // ReadEnvStr, ExpandEnvStrings + EW_INTCMP, // IntCmp, IntCmpU + EW_INTOP, // IntOp + EW_INTFMT, // IntFmt/Int64Fmt + EW_PUSHPOP, // Push/Pop/Exchange + EW_FINDWINDOW, // FindWindow + EW_SENDMESSAGE, // SendMessage + EW_ISWINDOW, // IsWindow + EW_GETDLGITEM, // GetDlgItem + EW_SETCTLCOLORS, // SetCtlColors + EW_SETBRANDINGIMAGE, // SetBrandingImage / LoadAndSetImage + EW_CREATEFONT, // CreateFont + EW_SHOWWINDOW, // ShowWindow, EnableWindow, HideWindow + EW_SHELLEXEC, // ExecShell + EW_EXECUTE, // Exec, ExecWait + EW_GETFILETIME, // GetFileTime + EW_GETDLLVERSION, // GetDLLVersion + + // EW_GETFONTVERSION, // Park : 2.46.2 + // EW_GETFONTNAME, // Park : 2.46.3 + + EW_REGISTERDLL, // RegDLL, UnRegDLL, CallInstDLL + EW_CREATESHORTCUT, // CreateShortCut + EW_COPYFILES, // CopyFiles + EW_REBOOT, // Reboot + EW_WRITEINI, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + EW_READINISTR, // ReadINIStr + EW_DELREG, // DeleteRegValue, DeleteRegKey + EW_WRITEREG, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + EW_READREGSTR, // ReadRegStr, ReadRegDWORD + EW_REGENUM, // EnumRegKey, EnumRegValue + EW_FCLOSE, // FileClose + EW_FOPEN, // FileOpen + EW_FPUTS, // FileWrite, FileWriteByte + EW_FGETS, // FileRead, FileReadByte + + // Park + // EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + // EW_FGETWS, // FileReadUTF16LE, FileReadWord + + EW_FSEEK, // FileSeek + EW_FINDCLOSE, // FindClose + EW_FINDNEXT, // FindNext + EW_FINDFIRST, // FindFirst + EW_WRITEUNINSTALLER, // WriteUninstaller + + // Park : since 2.46.3 the log is enabled in main Park version + // EW_LOG, // LogSet, LogText + + EW_SECTIONSET, // Get*, Set* + EW_INSTTYPESET, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + + /* + // before v3.06 nsis it was so: + // instructions not actually implemented in exehead, but used in compiler. + EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR + EW_GETFUNCTIONADDR, + */ + + // v3.06 and later it was changed to: + EW_GETOSINFO, + EW_RESERVEDOPCODE, + + EW_LOCKWINDOW, // LockWindow + + // 2 unicode commands available only in Unicode archive + EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord + EW_FGETWS, // FileReadUTF16LE, FileReadWord + + /* + // since v3.06 the fllowing IDs codes was moved here: + // Opcodes listed here are not actually used in exehead. No exehead opcodes should be present after these! + EW_GETLABELADDR, // --> EW_ASSIGNVAR + EW_GETFUNCTIONADDR, // --> EW_ASSIGNVAR + */ + + // The following IDs are not IDs in real order. + // We just need some IDs to translate eny extended layout to main layout. + + EW_LOG, // LogSet, LogText + + // Park + EW_FINDPROC, // FindProc + + EW_GETFONTVERSION, // GetFontVersion + EW_GETFONTNAME, // GetFontName + + kNumCmds +}; + + + +struct CCommandInfo +{ + Byte NumParams; +}; + +static const CCommandInfo k_Commands[kNumCmds] = +{ + { 0 }, // "Invalid" }, + { 0 }, // Return + { 1 }, // Nop, Goto + { 1 }, // "Abort" }, + { 0 }, // "Quit" }, + { 2 }, // Call + { 6 }, // "DetailPrint" }, // 1 param in new versions, 6 in old NSIS versions + { 1 }, // "Sleep" }, + { 0 }, // "BringToFront" }, + { 2 }, // "SetDetailsView" }, + { 2 }, // "SetFileAttributes" }, + { 3 }, // CreateDirectory, SetOutPath + { 3 }, // "IfFileExists" }, + { 3 }, // SetRebootFlag, ... + { 4 }, // "If" }, // IfAbort, IfSilent, IfErrors, IfRebootFlag + { 2 }, // "Get" }, // GetInstDirError, GetErrorLevel + { 4 }, // "Rename" }, + { 3 }, // "GetFullPathName" }, + { 2 }, // "SearchPath" }, + { 2 }, // "GetTempFileName" }, + { 6 }, // "File" + { 2 }, // "Delete" }, + { 6 }, // "MessageBox" }, + { 2 }, // "RMDir" }, + { 2 }, // "StrLen" }, + { 4 }, // StrCpy, GetCurrentAddress + { 5 }, // "StrCmp" }, + { 3 }, // ReadEnvStr, ExpandEnvStrings + { 6 }, // "IntCmp" }, + { 4 }, // "IntOp" }, + { 4 }, // "IntFmt" }, EW_INTFMT + { 6 }, // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. + { 5 }, // "FindWindow" }, + { 6 }, // "SendMessage" }, + { 3 }, // "IsWindow" }, + { 3 }, // "GetDlgItem" }, + { 2 }, // "SetCtlColors" }, + { 4 }, // "SetBrandingImage" } // LoadAndSetImage + { 5 }, // "CreateFont" }, + { 4 }, // ShowWindow, EnableWindow, HideWindow + { 6 }, // "ExecShell" }, + { 3 }, // "Exec" }, // Exec, ExecWait + { 3 }, // "GetFileTime" }, + { 4 }, // "GetDLLVersion" }, + { 6 }, // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. + { 6 }, // "CreateShortCut" }, + { 4 }, // "CopyFiles" }, + { 1 }, // "Reboot" }, + { 5 }, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + { 4 }, // "ReadINIStr" }, + { 5 }, // "DeleteReg" }, // DeleteRegKey, DeleteRegValue + { 6 }, // "WriteReg" }, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + { 5 }, // "ReadReg" }, // ReadRegStr, ReadRegDWORD + { 5 }, // "EnumReg" }, // EnumRegKey, EnumRegValue + { 1 }, // "FileClose" }, + { 4 }, // "FileOpen" }, + { 3 }, // "FileWrite" }, // FileWrite, FileWriteByte + { 4 }, // "FileRead" }, // FileRead, FileReadByte + { 4 }, // "FileSeek" }, + { 1 }, // "FindClose" }, + { 2 }, // "FindNext" }, + { 3 }, // "FindFirst" }, + { 4 }, // "WriteUninstaller" }, + { 5 }, // "Section" }, // *** + { 4 }, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + + // { 6 }, // "GetLabelAddr" }, // before 3.06 + { 6 }, // "GetOsInfo" }, GetKnownFolderPath, ReadMemory, // v3.06+ + + { 2 }, // "GetFunctionAddress" }, // before 3.06 + + { 1 }, // "LockWindow" }, + { 4 }, // "FileWrite" }, // FileWriteUTF16LE, FileWriteWord + { 4 }, // "FileRead" }, // FileReadUTF16LE, FileReadWord + + { 2 }, // "Log" }, // LogSet, LogText + // Park + { 2 }, // "FindProc" }, + { 2 }, // "GetFontVersion" }, + { 2 }, // "GetFontName" } +}; + +#ifdef NSIS_SCRIPT + +static const char * const k_CommandNames[kNumCmds] = +{ + "Invalid" + , NULL // Return + , NULL // Nop, Goto + , "Abort" + , "Quit" + , NULL // Call + , "DetailPrint" // 1 param in new versions, 6 in old NSIS versions + , "Sleep" + , "BringToFront" + , "SetDetailsView" + , "SetFileAttributes" + , NULL // CreateDirectory, SetOutPath + , "IfFileExists" + , NULL // SetRebootFlag, ... + , "If" // IfAbort, IfSilent, IfErrors, IfRebootFlag + , "Get" // GetInstDirError, GetErrorLevel + , "Rename" + , "GetFullPathName" + , "SearchPath" + , "GetTempFileName" + , NULL // File + , "Delete" + , "MessageBox" + , "RMDir" + , "StrLen" + , NULL // StrCpy, GetCurrentAddress + , "StrCmp" + , NULL // ReadEnvStr, ExpandEnvStrings + , NULL // IntCmp / Int64Cmp / EW_INTCMP + , "IntOp" + , NULL // IntFmt / Int64Fmt / EW_INTFMT + , NULL // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage. + , "FindWindow" + , "SendMessage" + , "IsWindow" + , "GetDlgItem" + , "SetCtlColors" + , "SetBrandingImage" + , "CreateFont" + , NULL // ShowWindow, EnableWindow, HideWindow + , "ExecShell" + , "Exec" // Exec, ExecWait + , "GetFileTime" + , "GetDLLVersion" + , NULL // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage. + , "CreateShortCut" + , "CopyFiles" + , "Reboot" + , NULL // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI + , "ReadINIStr" + , "DeleteReg" // DeleteRegKey, DeleteRegValue + , "WriteReg" // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD + , "ReadReg" // ReadRegStr, ReadRegDWORD + , "EnumReg" // EnumRegKey, EnumRegValue + , "FileClose" + , "FileOpen" + , "FileWrite" // FileWrite, FileWriteByte + , "FileRead" // FileRead, FileReadByte + , "FileSeek" + , "FindClose" + , "FindNext" + , "FindFirst" + , "WriteUninstaller" + , "Section" // *** + , NULL // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType + + , NULL // "GetOsInfo" // , "GetLabelAddr" // + , "GetFunctionAddress" + + , "LockWindow" + , "FileWrite" // FileWriteUTF16LE, FileWriteWord + , "FileRead" // FileReadUTF16LE, FileReadWord + + , "Log" // LogSet, LogText + + // Park + , "FindProc" + , "GetFontVersion" + , "GetFontName" +}; + +#endif + +/* NSIS can use one name for two CSIDL_*** and CSIDL_COMMON_*** items (CurrentUser / AllUsers) + Some NSIS shell names are not identical to WIN32 CSIDL_* names. + NSIS doesn't use some CSIDL_* values. But we add name for all CSIDL_ (marked with '+'). */ + +static const char * const kShellStrings[] = +{ + "DESKTOP" // + + , "INTERNET" // + + , "SMPROGRAMS" // CSIDL_PROGRAMS + , "CONTROLS" // + + , "PRINTERS" // + + , "DOCUMENTS" // CSIDL_PERSONAL + , "FAVORITES" // CSIDL_FAVORITES + , "SMSTARTUP" // CSIDL_STARTUP + , "RECENT" // CSIDL_RECENT + , "SENDTO" // CSIDL_SENDTO + , "BITBUCKET" // + + , "STARTMENU" + , NULL // CSIDL_MYDOCUMENTS = CSIDL_PERSONAL + , "MUSIC" // CSIDL_MYMUSIC + , "VIDEOS" // CSIDL_MYVIDEO + , NULL + , "DESKTOP" // CSIDL_DESKTOPDIRECTORY + , "DRIVES" // + + , "NETWORK" // + + , "NETHOOD" + , "FONTS" + , "TEMPLATES" + , "STARTMENU" // CSIDL_COMMON_STARTMENU + , "SMPROGRAMS" // CSIDL_COMMON_PROGRAMS + , "SMSTARTUP" // CSIDL_COMMON_STARTUP + , "DESKTOP" // CSIDL_COMMON_DESKTOPDIRECTORY + , "APPDATA" // CSIDL_APPDATA !!! "QUICKLAUNCH" + , "PRINTHOOD" + , "LOCALAPPDATA" + , "ALTSTARTUP" + , "ALTSTARTUP" // CSIDL_COMMON_ALTSTARTUP + , "FAVORITES" // CSIDL_COMMON_FAVORITES + , "INTERNET_CACHE" + , "COOKIES" + , "HISTORY" + , "APPDATA" // CSIDL_COMMON_APPDATA + , "WINDIR" + , "SYSDIR" + , "PROGRAM_FILES" // + + , "PICTURES" // CSIDL_MYPICTURES + , "PROFILE" + , "SYSTEMX86" // + + , "PROGRAM_FILESX86" // + + , "PROGRAM_FILES_COMMON" // + + , "PROGRAM_FILES_COMMONX8" // + CSIDL_PROGRAM_FILES_COMMONX86 + , "TEMPLATES" // CSIDL_COMMON_TEMPLATES + , "DOCUMENTS" // CSIDL_COMMON_DOCUMENTS + , "ADMINTOOLS" // CSIDL_COMMON_ADMINTOOLS + , "ADMINTOOLS" // CSIDL_ADMINTOOLS + , "CONNECTIONS" // + + , NULL + , NULL + , NULL + , "MUSIC" // CSIDL_COMMON_MUSIC + , "PICTURES" // CSIDL_COMMON_PICTURES + , "VIDEOS" // CSIDL_COMMON_VIDEO + , "RESOURCES" + , "RESOURCES_LOCALIZED" + , "COMMON_OEM_LINKS" // + + , "CDBURN_AREA" + , NULL // unused + , "COMPUTERSNEARME" // + +}; + + +static inline void UIntToString(AString &s, UInt32 v) +{ + s.Add_UInt32(v); +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_UInt(UInt32 v) +{ + char sz[16]; + ConvertUInt32ToString(v, sz); + Script += sz; +} + +static void Add_SignedInt(CDynLimBuf &s, Int32 v) +{ + char sz[32]; + ConvertInt64ToString(v, sz); + s += sz; +} + +static void Add_Hex(CDynLimBuf &s, UInt32 v) +{ + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(v, sz + 2); + s += sz; +} + +static UInt32 GetUi16Str_Len(const Byte *p) +{ + const Byte *pp = p; + for (; *pp != 0 || *(pp + 1) != 0; pp += 2); + return (UInt32)((pp - p) >> 1); +} + +void CInArchive::AddLicense(UInt32 param, Int32 langID) +{ + Space(); + if (param >= NumStringChars || + param + 1 >= NumStringChars) + { + Script += kErrorStr; + return; + } + strUsed[param] = 1; + + const UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param); + const UInt32 offset = start + (IsUnicode ? 2 : 1); + { + FOR_VECTOR (i, LicenseFiles) + { + const CLicenseFile &lic = LicenseFiles[i]; + if (offset == lic.Offset) + { + Script += lic.Name; + return; + } + } + } + AString fileName ("[LICENSE]"); + if (langID >= 0) + { + fileName += "\\license-"; + // LangId_To_String(fileName, langID); + UIntToString(fileName, (UInt32)langID); + } + else if (++_numRootLicenses > 1) + { + fileName.Add_Minus(); + UIntToString(fileName, _numRootLicenses); + } + const Byte *sz = (_data + start); + const unsigned marker = IsUnicode ? Get16(sz) : *sz; + const bool isRTF = (marker == 2); + fileName += isRTF ? ".rtf" : ".txt"; // if (*sz == 1) it's text; + Script += fileName; + + CLicenseFile &lic = LicenseFiles.AddNew(); + lic.Name = fileName; + lic.Offset = offset; + if (!IsUnicode) + lic.Size = (UInt32)strlen((const char *)sz + 1); + else + { + sz += 2; + const UInt32 len = GetUi16Str_Len(sz); + lic.Size = len * 2; + if (isRTF) + { + lic.Text.Alloc((size_t)len); + for (UInt32 i = 0; i < len; i++, sz += 2) + { + unsigned c = Get16(sz); + if (c >= 256) + c = '?'; + lic.Text[i] = (Byte)(c); + } + lic.Size = len; + lic.Offset = 0; + } + } +} + +#endif + + +#ifdef NSIS_SCRIPT +#define Z7_NSIS_WIN_GENERIC_READ ((UInt32)1 << 31) +#endif +#define Z7_NSIS_WIN_GENERIC_WRITE ((UInt32)1 << 30) +#ifdef NSIS_SCRIPT +#define Z7_NSIS_WIN_GENERIC_EXECUTE ((UInt32)1 << 29) +#define Z7_NSIS_WIN_GENERIC_ALL ((UInt32)1 << 28) +#endif + +#ifdef NSIS_SCRIPT +#define Z7_NSIS_WIN_CREATE_NEW 1 +#endif +#define Z7_NSIS_WIN_CREATE_ALWAYS 2 +#ifdef NSIS_SCRIPT +#define Z7_NSIS_WIN_OPEN_EXISTING 3 +#define Z7_NSIS_WIN_OPEN_ALWAYS 4 +#define Z7_NSIS_WIN_TRUNCATE_EXISTING 5 +#endif + + +// #define kVar_CMDLINE 20 +#define kVar_INSTDIR 21 +#define kVar_OUTDIR 22 +#define kVar_EXEDIR 23 +// #define kVar_LANGUAGE 24 +#define kVar_TEMP 25 +#define kVar_PLUGINSDIR 26 +#define kVar_EXEPATH 27 // NSIS 2.26+ +// #define kVar_EXEFILE 28 // NSIS 2.26+ + +#define kVar_HWNDPARENT_225 27 +#ifdef NSIS_SCRIPT +#define kVar_HWNDPARENT 29 +#endif + +// #define kVar__CLICK 30 +#define kVar_Spec_OUTDIR_225 29 // NSIS 2.04 - 2.25 +#define kVar_Spec_OUTDIR 31 // NSIS 2.26+ + + +static const char * const kVarStrings[] = +{ + "CMDLINE" + , "INSTDIR" + , "OUTDIR" + , "EXEDIR" + , "LANGUAGE" + , "TEMP" + , "PLUGINSDIR" + , "EXEPATH" // NSIS 2.26+ + , "EXEFILE" // NSIS 2.26+ + , "HWNDPARENT" + , "_CLICK" // is set from page->clicknext + , "_OUTDIR" // NSIS 2.04+ +}; + +static const unsigned kNumInternalVars = 20 + Z7_ARRAY_SIZE(kVarStrings); + +#define GET_NUM_INTERNAL_VARS (IsNsis200 ? kNumInternalVars - 3 : IsNsis225 ? kNumInternalVars - 2 : kNumInternalVars) + +void CInArchive::GetVar2(AString &res, UInt32 index) +{ + if (index < 20) + { + if (index >= 10) + { + res += 'R'; + index -= 10; + } + UIntToString(res, index); + } + else + { + unsigned numInternalVars = GET_NUM_INTERNAL_VARS; + if (index < numInternalVars) + { + if (IsNsis225 && index >= kVar_EXEPATH) + index += 2; + res += kVarStrings[index - 20]; + } + else + { + res += '_'; + UIntToString(res, index - numInternalVars); + res += '_'; + } + } +} + +void CInArchive::GetVar(AString &res, UInt32 index) +{ + res += '$'; + GetVar2(res, index); +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_Var(UInt32 index) +{ + _tempString_for_GetVar.Empty(); + GetVar(_tempString_for_GetVar, index); + Script += _tempString_for_GetVar; +} + +void CInArchive::AddParam_Var(UInt32 index) +{ + Space(); + Add_Var(index); +} + +void CInArchive::AddParam_UInt(UInt32 value) +{ + Space(); + Add_UInt(value); +} + +#endif + + +#define NS_CODE_SKIP 252 +#define NS_CODE_VAR 253 +#define NS_CODE_SHELL 254 +// #define NS_CODE_LANG 255 + +// #define NS_3_CODE_LANG 1 +#define NS_3_CODE_SHELL 2 +#define NS_3_CODE_VAR 3 +#define NS_3_CODE_SKIP 4 + +#define PARK_CODE_SKIP 0xE000 +#define PARK_CODE_VAR 0xE001 +#define PARK_CODE_SHELL 0xE002 +#define PARK_CODE_LANG 0xE003 + +#define IS_NS_SPEC_CHAR(c) ((c) >= NS_CODE_SKIP) +#define IS_PARK_SPEC_CHAR(c) ((c) >= PARK_CODE_SKIP && (c) <= PARK_CODE_LANG) + +#define DECODE_NUMBER_FROM_2_CHARS(c0, c1) (((unsigned)(c0) & 0x7F) | (((unsigned)((c1) & 0x7F)) << 7)) +#define CONVERT_NUMBER_NS_3_UNICODE(n) n = ((n & 0x7F) | (((n >> 8) & 0x7F) << 7)) +#define CONVERT_NUMBER_PARK(n) n &= 0x7FFF + + +static bool AreStringsEqual_16and8(const Byte *p16, const char *p8) +{ + for (;;) + { + unsigned c16 = Get16(p16); p16 += 2; + unsigned c = (Byte)(*p8++); + if (c16 != c) + return false; + if (c == 0) + return true; + } +} + +void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) +{ + // zeros are not allowed here. + // if (index1 == 0 || index2 == 0) throw 333; + + if ((index1 & 0x80) != 0) + { + unsigned offset = (index1 & 0x3F); + + /* NSIS reads registry string: + keyName = HKLM Software\\Microsoft\\Windows\\CurrentVersion + mask = KEY_WOW64_64KEY, If 64-bit flag in index1 is set + valueName = string(offset) + If registry reading is failed, NSIS uses second parameter (index2) + to read string. The recursion is possible in that case in NSIS. + We don't parse index2 string. We only set strUsed status for that + string (but without recursion). */ + + if (offset >= NumStringChars) + { + s += kErrorStr; + return; + } + + #ifdef NSIS_SCRIPT + strUsed[offset] = 1; + if (index2 < NumStringChars) + strUsed[index2] = 1; + #endif + + const Byte *p = (const Byte *)(_data + _stringsPos); + int id = -1; + if (IsUnicode) + { + p += offset * 2; + if (AreStringsEqual_16and8(p, "ProgramFilesDir")) + id = 0; + else if (AreStringsEqual_16and8(p, "CommonFilesDir")) + id = 1; + } + else + { + p += offset; + if (strcmp((const char *)p, "ProgramFilesDir") == 0) + id = 0; + else if (strcmp((const char *)p, "CommonFilesDir") == 0) + id = 1; + } + + s += ((id >= 0) ? (id == 0 ? "$PROGRAMFILES" : "$COMMONFILES") : + "$_ERROR_UNSUPPORTED_VALUE_REGISTRY_"); + // s += ((index1 & 0x40) != 0) ? "64" : "32"; + if ((index1 & 0x40) != 0) + s += "64"; + + if (id < 0) + { + s += '('; + if (IsUnicode) + { + for (unsigned i = 0; i < 256; i++) + { + wchar_t c = Get16(p + i * 2); + if (c == 0) + break; + if (c < 0x80) + s += (char)c; + } + } + else + s += (const char *)p; + s += ')'; + } + return; + } + + s += '$'; + if (index1 < Z7_ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index1]; + if (sz) + { + s += sz; + return; + } + } + if (index2 < Z7_ARRAY_SIZE(kShellStrings)) + { + const char *sz = kShellStrings[index2]; + if (sz) + { + s += sz; + return; + } + } + s += "_ERROR_UNSUPPORTED_SHELL_"; + s += '['; + UIntToString(s, index1); + s += ','; + UIntToString(s, index2); + s += ']'; +} + +#ifdef NSIS_SCRIPT + +void CInArchive::Add_LangStr_Simple(UInt32 id) +{ + Script += "LSTR_"; + Add_UInt(id); +} + +#endif + +void CInArchive::Add_LangStr(AString &res, UInt32 id) +{ + #ifdef NSIS_SCRIPT + langStrIDs.Add(id); + #endif + res += "$(LSTR_"; + UIntToString(res, id); + res += ')'; +} + +void CInArchive::GetNsisString_Raw(const Byte *s) +{ + Raw_AString.Empty(); + + if (NsisType != k_NsisType_Nsis3) + { + for (;;) + { + Byte c = *s++; + if (c == 0) + return; + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + + if (c == NS_CODE_SHELL) + GetShellString(Raw_AString, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + continue; + } + c = c0; + } + Raw_AString += (char)c; + } + } + + // NSIS-3 ANSI + for (;;) + { + Byte c = *s++; + if (c <= NS_3_CODE_SKIP) + { + if (c == 0) + return; + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_3_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + + if (c == NS_3_CODE_SHELL) + GetShellString(Raw_AString, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_3_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + continue; + } + c = c0; + } + Raw_AString += (char)c; + } +} + +#ifdef NSIS_SCRIPT + +void CInArchive::GetNsisString(AString &res, const Byte *s) +{ + for (;;) + { + Byte c = *s++; + if (c == 0) + return; + if (NsisType != k_NsisType_Nsis3) + { + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c != NS_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + if (c == NS_CODE_SHELL) + GetShellString(res, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_CODE_VAR) + GetVar(res, n); + else // if (c == NS_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = c0; + } + } + else + { + // NSIS-3 ANSI + if (c <= NS_3_CODE_SKIP) + { + Byte c0 = *s++; + if (c0 == 0) + return; + if (c0 == 0) + break; + if (c != NS_3_CODE_SKIP) + { + Byte c1 = *s++; + if (c1 == 0) + return; + if (c == NS_3_CODE_SHELL) + GetShellString(res, c0, c1); + else + { + unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + if (c == NS_3_CODE_VAR) + GetVar(res, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = c0; + } + } + + { + const char *e; + if (c == 9) e = "$\\t"; + else if (c == 10) e = "$\\n"; + else if (c == 13) e = "$\\r"; + else if (c == '"') e = "$\\\""; + else if (c == '$') e = "$$"; + else + { + res += (char)c; + continue; + } + res += e; + continue; + } + } +} + +#endif + +void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) +{ + Raw_UString.Empty(); + + if (IsPark()) + { + for (;;) + { + unsigned c = Get16(p); + p += 2; + if (c == 0) + break; + if (c < 0x80) + { + Raw_UString.Add_Char((char)c); + continue; + } + + if (IS_PARK_SPEC_CHAR(c)) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != PARK_CODE_SKIP) + { + Raw_AString.Empty(); + if (c == PARK_CODE_SHELL) + GetShellString(Raw_AString, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_PARK(n); + if (c == PARK_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == PARK_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + Raw_UString += Raw_AString.Ptr(); // check it ! + continue; + } + c = n; + } + + Raw_UString += (wchar_t)c; + } + + return; + } + + // NSIS-3 Unicode + for (;;) + { + unsigned c = Get16(p); + p += 2; + if (c > NS_3_CODE_SKIP) + { + Raw_UString += (wchar_t)c; + continue; + } + if (c == 0) + break; + + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c == NS_3_CODE_SKIP) + { + Raw_UString += (wchar_t)n; + continue; + } + + Raw_AString.Empty(); + if (c == NS_3_CODE_SHELL) + GetShellString(Raw_AString, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_NS_3_UNICODE(n); + if (c == NS_3_CODE_VAR) + GetVar(Raw_AString, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(Raw_AString, n); + } + Raw_UString += Raw_AString.Ptr(); + } +} + +#ifdef NSIS_SCRIPT + +static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p) +{ + for (;;) + { + unsigned c = Get16(p); + p += 2; + if (c == 0) + break; + if (IsPark()) + { + if (IS_PARK_SPEC_CHAR(c)) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != PARK_CODE_SKIP) + { + if (c == PARK_CODE_SHELL) + GetShellString(res, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_PARK(n); + if (c == PARK_CODE_VAR) + GetVar(res, n); + else // if (c == PARK_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = n; + } + } + else + { + // NSIS-3 Unicode + if (c <= NS_3_CODE_SKIP) + { + unsigned n = Get16(p); + p += 2; + if (n == 0) + break; + if (c != NS_3_CODE_SKIP) + { + if (c == NS_3_CODE_SHELL) + GetShellString(res, n & 0xFF, n >> 8); + else + { + CONVERT_NUMBER_NS_3_UNICODE(n); + if (c == NS_3_CODE_VAR) + GetVar(res, n); + else // if (c == NS_3_CODE_LANG) + Add_LangStr(res, n); + } + continue; + } + c = n; + } + } + + if (c < 0x80) + { + const char *e; + if (c == 9) e = "$\\t"; + else if (c == 10) e = "$\\n"; + else if (c == 13) e = "$\\r"; + else if (c == '"') e = "$\\\""; + else if (c == '$') e = "$$"; + else + { + res += (char)c; + continue; + } + res += e; + continue; + } + + UInt32 value = c; + /* + if (value >= 0xD800 && value < 0xE000) + { + UInt32 c2; + if (value >= 0xDC00 || srcPos == srcLen) + break; + c2 = src[srcPos++]; + if (c2 < 0xDC00 || c2 >= 0xE000) + break; + value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + } + */ + unsigned numAdds; + for (numAdds = 1; numAdds < 5; numAdds++) + if (value < (((UInt32)1) << (numAdds * 5 + 6))) + break; + res += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); + do + { + numAdds--; + res += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); + // destPos++; + } + while (numAdds != 0); + + // AddToUtf8(res, c); + } +} + +#endif + +void CInArchive::ReadString2_Raw(UInt32 pos) +{ + Raw_AString.Empty(); + Raw_UString.Empty(); + if ((Int32)pos < 0) + Add_LangStr(Raw_AString, (UInt32)-((Int32)pos + 1)); + else if (pos >= NumStringChars) + { + Raw_AString += kErrorStr; + // UIntToString(Raw_AString, pos); + } + else + { + if (IsUnicode) + GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2); + else + GetNsisString_Raw(_data + _stringsPos + pos); + return; + } + Raw_UString = Raw_AString.Ptr(); +} + +bool CInArchive::IsGoodString(UInt32 param) const +{ + if (param >= NumStringChars) + return false; + if (param == 0) + return true; + const Byte *p = _data + _stringsPos; + unsigned c; + if (IsUnicode) + c = Get16(p + param * 2 - 2); + else + c = p[param - 1]; + // some files have '\\' character before string? + return (c == 0 || c == '\\'); +} + +bool CInArchive::AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const +{ + if (param1 == param2) + return true; + + /* NSIS-3.0a1 probably contains bug, so it can use 2 different strings + with same content. So we check real string also. + Also it's possible to check identical postfix parts of strings. */ + + if (param1 >= NumStringChars || + param2 >= NumStringChars) + return false; + + const Byte *p = _data + _stringsPos; + + if (IsUnicode) + { + const Byte *p1 = p + param1 * 2; + const Byte *p2 = p + param2 * 2; + for (;;) + { + UInt16 c = Get16(p1); + if (c != Get16(p2)) + return false; + if (c == 0) + return true; + p1 += 2; + p2 += 2; + } + } + else + { + const Byte *p1 = p + param1; + const Byte *p2 = p + param2; + for (;;) + { + Byte c = *p1++; + if (c != *p2++) + return false; + if (c == 0) + return true; + } + } +} + +#ifdef NSIS_SCRIPT + +UInt32 CInArchive::GetNumUsedVars() const +{ + UInt32 numUsedVars = 0; + const Byte *data = (const Byte *)_data + _stringsPos; + unsigned npi = 0; + for (UInt32 i = 0; i < NumStringChars;) + { + bool process = true; + if (npi < noParseStringIndexes.Size() && noParseStringIndexes[npi] == i) + { + process = false; + npi++; + } + + if (IsUnicode) + { + if (IsPark()) + { + for (;;) + { + unsigned c = Get16(data + i * 2); + i++; + if (c == 0) + break; + if (IS_PARK_SPEC_CHAR(c)) + { + UInt32 n = Get16(data + i * 2); + i++; + if (n == 0) + break; + if (process && c == PARK_CODE_VAR) + { + CONVERT_NUMBER_PARK(n); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else // NSIS-3 Unicode + { + for (;;) + { + unsigned c = Get16(data + i * 2); + i++; + if (c == 0) + break; + if (c > NS_3_CODE_SKIP) + continue; + UInt32 n = Get16(data + i * 2); + i++; + if (n == 0) + break; + if (process && c == NS_3_CODE_VAR) + { + CONVERT_NUMBER_NS_3_UNICODE(n); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else // not Unicode (ANSI) + { + if (NsisType != k_NsisType_Nsis3) + { + for (;;) + { + Byte c = data[i++]; + if (c == 0) + break; + if (IS_NS_SPEC_CHAR(c)) + { + Byte c0 = data[i++]; + if (c0 == 0) + break; + if (c == NS_CODE_SKIP) + continue; + Byte c1 = data[i++]; + if (c1 == 0) + break; + if (process && c == NS_CODE_VAR) + { + UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + else + { + // NSIS-3 ANSI + for (;;) + { + Byte c = data[i++]; + if (c == 0) + break; + if (c > NS_3_CODE_SKIP) + continue; + + Byte c0 = data[i++]; + if (c0 == 0) + break; + if (c == NS_3_CODE_SKIP) + continue; + Byte c1 = data[i++]; + if (c1 == 0) + break; + if (process && c == NS_3_CODE_VAR) + { + UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1); + n++; + if (numUsedVars < n) + numUsedVars = n; + } + } + } + } + } + return numUsedVars; +} + +void CInArchive::ReadString2(AString &s, UInt32 pos) +{ + if ((Int32)pos < 0) + { + Add_LangStr(s, (UInt32)-((Int32)pos + 1)); + return; + } + + if (pos >= NumStringChars) + { + s += kErrorStr; + // UIntToString(s, pos); + return; + } + + #ifdef NSIS_SCRIPT + strUsed[pos] = 1; + #endif + + if (IsUnicode) + GetNsisString_Unicode(s, _data + _stringsPos + pos * 2); + else + GetNsisString(s, _data + _stringsPos + pos); +} + +#endif + +#ifdef NSIS_SCRIPT + +// #define DEL_DIR 1 +#define DEL_RECURSE 2 +#define DEL_REBOOT 4 +// #define DEL_SIMPLE 8 + +void CInArchive::AddRegRoot(UInt32 val) +{ + Space(); + const char *s; + switch (val) + { + case 0: s = "SHCTX"; break; + case 0x80000000: s = "HKCR"; break; + case 0x80000001: s = "HKCU"; break; + case 0x80000002: s = "HKLM"; break; + case 0x80000003: s = "HKU"; break; + case 0x80000004: s = "HKPD"; break; + case 0x80000005: s = "HKCC"; break; + case 0x80000006: s = "HKDD"; break; + case 0x80000050: s = "HKPT"; break; + case 0x80000060: s = "HKPN"; break; + default: + // Script += " RRRRR "; + // throw 1; + Add_Hex(Script, val); return; + } + Script += s; +} + +static const char * const g_WinAttrib[] = +{ + "READONLY" + , "HIDDEN" + , "SYSTEM" + , NULL + , "DIRECTORY" + , "ARCHIVE" + , "DEVICE" + , "NORMAL" + , "TEMPORARY" + , "SPARSE_FILE" + , "REPARSE_POINT" + , "COMPRESSED" + , "OFFLINE" + , "NOT_CONTENT_INDEXED" + , "ENCRYPTED" + , NULL + , "VIRTUAL" +}; + +#define FLAGS_DELIMITER '|' + +static void FlagsToString2(CDynLimBuf &s, const char * const *table, unsigned num, UInt32 flags) +{ + bool filled = false; + for (unsigned i = 0; i < num; i++) + { + UInt32 f = (UInt32)1 << i; + if ((flags & f) != 0) + { + const char *name = table[i]; + if (name) + { + if (filled) + s += FLAGS_DELIMITER; + filled = true; + s += name; + flags &= ~f; + } + } + } + if (flags != 0) + { + if (filled) + s += FLAGS_DELIMITER; + Add_Hex(s, flags); + } +} + +static bool DoesNeedQuotes(const char *s) +{ + { + char c = s[0]; + if (c == 0 || c == '#' || c == ';' || (c == '/' && s[1] == '*')) + return true; + } + for (;;) + { + char c = *s++; + if (c == 0) + return false; + if (c == ' ') + return true; + } +} + +void CInArchive::Add_QuStr(const AString &s) +{ + bool needQuotes = DoesNeedQuotes(s); + if (needQuotes) + Script += '\"'; + Script += s; + if (needQuotes) + Script += '\"'; +} + +void CInArchive::SpaceQuStr(const AString &s) +{ + Space(); + Add_QuStr(s); +} + +void CInArchive::AddParam(UInt32 pos) +{ + _tempString.Empty(); + ReadString2(_tempString, pos); + SpaceQuStr(_tempString); +} + +void CInArchive::AddParams(const UInt32 *params, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + AddParam(params[i]); +} + +void CInArchive::AddOptionalParam(UInt32 pos) +{ + if (pos != 0) + AddParam(pos); +} + +static unsigned GetNumParams(const UInt32 *params, unsigned num) +{ + for (; num > 0 && params[num - 1] == 0; num--); + return num; +} + +void CInArchive::AddOptionalParams(const UInt32 *params, unsigned num) +{ + AddParams(params, GetNumParams(params, num)); +} + + +static const UInt32 CMD_REF_Goto = (1 << 0); +static const UInt32 CMD_REF_Call = (1 << 1); +static const UInt32 CMD_REF_Pre = (1 << 2); +static const UInt32 CMD_REF_Show = (1 << 3); +static const UInt32 CMD_REF_Leave = (1 << 4); +static const UInt32 CMD_REF_OnFunc = (1 << 5); +static const UInt32 CMD_REF_Section = (1 << 6); +static const UInt32 CMD_REF_InitPluginDir = (1 << 7); +// static const UInt32 CMD_REF_Creator = (1 << 5); // CMD_REF_Pre is used instead +static const unsigned CMD_REF_OnFunc_NumShifts = 28; // it uses for onFunc too +static const unsigned CMD_REF_Page_NumShifts = 16; // it uses for onFunc too +static const UInt32 CMD_REF_Page_Mask = 0x0FFF0000; +static const UInt32 CMD_REF_OnFunc_Mask = 0xF0000000; + +inline bool IsPageFunc(UInt32 flag) +{ + return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave)) != 0; +} + +inline bool IsFunc(UInt32 flag) +{ + // return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; + return (flag & (CMD_REF_Call | CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0; +} + +inline bool IsProbablyEndOfFunc(UInt32 flag) +{ + return (flag != 0 && flag != CMD_REF_Goto); +} + +static const char * const kOnFunc[] = +{ + "Init" + , "InstSuccess" + , "InstFailed" + , "UserAbort" + , "GUIInit" + , "GUIEnd" + , "MouseOverSection" + , "VerifyInstDir" + , "SelChange" + , "RebootFailed" +}; + +void CInArchive::Add_FuncName(const UInt32 *labels, UInt32 index) +{ + UInt32 mask = labels[index]; + if (mask & CMD_REF_OnFunc) + { + Script += ".on"; + Script += kOnFunc[labels[index] >> CMD_REF_OnFunc_NumShifts]; + } + else if (mask & CMD_REF_InitPluginDir) + { + /* + if (!IsInstaller) + Script += "un." + */ + Script += "Initialize_____Plugins"; + } + else + { + Script += "func_"; + Add_UInt(index); + } +} + +void CInArchive::AddParam_Func(const UInt32 *labels, UInt32 index) +{ + Space(); + if ((Int32)index >= 0) + Add_FuncName(labels, index); + else + AddQuotes(); +} + + +void CInArchive::Add_LabelName(UInt32 index) +{ + Script += "label_"; + Add_UInt(index); +} + +// param != 0 +void CInArchive::Add_GotoVar(UInt32 param) +{ + Space(); + if ((Int32)param < 0) + Add_Var((UInt32)-((Int32)param + 1)); + else + Add_LabelName(param - 1); +} + +void CInArchive::Add_GotoVar1(UInt32 param) +{ + if (param == 0) + Script += " 0"; + else + Add_GotoVar(param); +} + +void CInArchive::Add_GotoVars2(const UInt32 *params) +{ + Add_GotoVar1(params[0]); + if (params[1] != 0) + Add_GotoVar(params[1]); +} + +static bool NoLabels(const UInt32 *labels, UInt32 num) +{ + for (UInt32 i = 0; i < num; i++) + if (labels[i] != 0) + return false; + return true; +} + +static const char * const k_REBOOTOK = " /REBOOTOK"; + +#define Z7_NSIS_WIN_MB_ABORTRETRYIGNORE 2 +#define Z7_NSIS_WIN_MB_RETRYCANCEL 5 + +static const char * const k_MB_Buttons[] = +{ + "OK" + , "OKCANCEL" + , "ABORTRETRYIGNORE" + , "YESNOCANCEL" + , "YESNO" + , "RETRYCANCEL" + , "CANCELTRYCONTINUE" +}; + +#define Z7_NSIS_WIN_MB_ICONSTOP (1 << 4) + +static const char * const k_MB_Icons[] = +{ + NULL + , "ICONSTOP" + , "ICONQUESTION" + , "ICONEXCLAMATION" + , "ICONINFORMATION" +}; + +static const char * const k_MB_Flags[] = +{ + "HELP" + , "NOFOCUS" + , "SETFOREGROUND" + , "DEFAULT_DESKTOP_ONLY" + , "TOPMOST" + , "RIGHT" + , "RTLREADING" + // , "SERVICE_NOTIFICATION" // unsupported. That bit is used for NSIS purposes +}; + +#define Z7_NSIS_WIN_IDCANCEL 2 +#define Z7_NSIS_WIN_IDIGNORE 5 + +static const char * const k_Button_IDs[] = +{ + "0" + , "IDOK" + , "IDCANCEL" + , "IDABORT" + , "IDRETRY" + , "IDIGNORE" + , "IDYES" + , "IDNO" + , "IDCLOSE" + , "IDHELP" + , "IDTRYAGAIN" + , "IDCONTINUE" +}; + +void CInArchive::Add_ButtonID(UInt32 buttonID) +{ + Space(); + if (buttonID < Z7_ARRAY_SIZE(k_Button_IDs)) + Script += k_Button_IDs[buttonID]; + else + { + Script += "Button_"; + Add_UInt(buttonID); + } +} + +bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const +{ + if (offset >= NumStringChars) + return false; + if (IsUnicode) + return AreStringsEqual_16and8(_data + _stringsPos + offset * 2, s); + else + return strcmp((const char *)(const Byte *)_data + _stringsPos + offset, s) == 0; +} + +static bool StringToUInt32(const char *s, UInt32 &res) +{ + const char *end; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + res = ConvertHexStringToUInt32(s + 2, &end); + else + res = ConvertStringToUInt32(s, &end); + return (*end == 0); +} + +static const unsigned k_CtlColors32_Size = 24; +static const unsigned k_CtlColors64_Size = 28; + +#define GET_CtlColors_SIZE(is64) ((is64) ? k_CtlColors64_Size : k_CtlColors32_Size) + +struct CNsis_CtlColors +{ + UInt32 text; // COLORREF + UInt32 bkc; // COLORREF + UInt32 lbStyle; + UInt32 bkb; // HBRUSH + Int32 bkmode; + Int32 flags; + UInt32 bkb_hi32; + + void Parse(const Byte *p, bool is64); +}; + +void CNsis_CtlColors::Parse(const Byte *p, bool is64) +{ + text = Get32(p); + bkc = Get32(p + 4); + if (is64) + { + bkb = Get32(p + 8); + bkb_hi32 = Get32(p + 12); + lbStyle = Get32(p + 16); + p += 4; + } + else + { + lbStyle = Get32(p + 8); + bkb = Get32(p + 12); + } + bkmode = (Int32)Get32(p + 16); + flags = (Int32)Get32(p + 20); +} + +// Win32 constants +#define Z7_NSIS_WIN_TRANSPARENT 1 +// #define Z7_NSIS_WIN_OPAQUE 2 + +// text/bg colors +#define kColorsFlags_TEXT 1 +#define kColorsFlags_TEXT_SYS 2 +#define kColorsFlags_BK 4 +#define kColorsFlags_BK_SYS 8 +#define kColorsFlags_BKB 16 + +void CInArchive::Add_Color2(UInt32 v) +{ + v = ((v & 0xFF) << 16) | (v & 0xFF00) | ((v >> 16) & 0xFF); + char sz[32]; + for (int i = 5; i >= 0; i--) + { + unsigned t = v & 0xF; + v >>= 4; + sz[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + } + sz[6] = 0; + Script += sz; +} + +void CInArchive::Add_ColorParam(UInt32 v) +{ + Space(); + Add_Color2(v); +} + +void CInArchive::Add_Color(UInt32 v) +{ + Script += "0x"; + Add_Color2(v); +} + +#define Z7_NSIS_WIN_SW_HIDE 0 +#define Z7_NSIS_WIN_SW_SHOWNORMAL 1 + +#define Z7_NSIS_WIN_SW_SHOWMINIMIZED 2 +#define Z7_NSIS_WIN_SW_SHOWMINNOACTIVE 7 +#define Z7_NSIS_WIN_SW_SHOWNA 8 + +static const char * const kShowWindow_Commands[] = +{ + "HIDE" + , "SHOWNORMAL" // "NORMAL" + , "SHOWMINIMIZED" + , "SHOWMAXIMIZED" // "MAXIMIZE" + , "SHOWNOACTIVATE" + , "SHOW" + , "MINIMIZE" + , "SHOWMINNOACTIVE" + , "SHOWNA" + , "RESTORE" + , "SHOWDEFAULT" + , "FORCEMINIMIZE" // "MAX" +}; + +static void Add_ShowWindow_Cmd_2(AString &s, UInt32 cmd) +{ + if (cmd < Z7_ARRAY_SIZE(kShowWindow_Commands)) + { + s += "SW_"; + s += kShowWindow_Commands[cmd]; + } + else + UIntToString(s, cmd); +} + +void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd) +{ + if (cmd < Z7_ARRAY_SIZE(kShowWindow_Commands)) + { + Script += "SW_"; + Script += kShowWindow_Commands[cmd]; + } + else + Add_UInt(cmd); +} + +void CInArchive::Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type) +{ + if (type < tableSize) + Script += table[type]; + else + { + Script += '_'; + Add_UInt(type); + } +} + +#define ADD_TYPE_FROM_LIST(table, type) Add_TypeFromList(table, Z7_ARRAY_SIZE(table), type) + +enum +{ + k_ExecFlags_AutoClose, + k_ExecFlags_ShellVarContext, + k_ExecFlags_Errors, + k_ExecFlags_Abort, + k_ExecFlags_RebootFlag, + k_ExecFlags_reboot_called, + k_ExecFlags_cur_insttype, + k_ExecFlags_plugin_api_version, + k_ExecFlags_Silent, + k_ExecFlags_InstDirError, + k_ExecFlags_rtl, + k_ExecFlags_ErrorLevel, + k_ExecFlags_RegView, + k_ExecFlags_DetailsPrint = 13 +}; + +// Names for NSIS exec_flags_t structure vars +static const char * const kExecFlags_VarsNames[] = +{ + "AutoClose" // autoclose; + , "ShellVarContext" // all_user_var; + , "Errors" // exec_error; + , "Abort" // abort; + , "RebootFlag" // exec_reboot; // NSIS_SUPPORT_REBOOT + , "reboot_called" // reboot_called; // NSIS_SUPPORT_REBOOT + , "cur_insttype" // XXX_cur_insttype; // depreacted + , "plugin_api_version" // plugin_api_version; // see NSISPIAPIVER_CURR + // used to be XXX_insttype_changed + , "Silent" // silent; // NSIS_CONFIG_SILENT_SUPPORT + , "InstDirError" // instdir_error; + , "rtl" // rtl; + , "ErrorLevel" // errlvl; + , "RegView" // alter_reg_view; + , "DetailsPrint" // status_update; +}; + +void CInArchive::Add_ExecFlags(UInt32 flagsType) +{ + ADD_TYPE_FROM_LIST(kExecFlags_VarsNames, flagsType); +} + + +// ---------- Page ---------- + +// page flags +#define PF_CANCEL_ENABLE 4 +#define PF_LICENSE_FORCE_SELECTION 32 +#define PF_LICENSE_NO_FORCE_SELECTION 64 +#define PF_PAGE_EX 512 +#define PF_DIR_NO_BTN_DISABLE 1024 +/* +#define PF_LICENSE_SELECTED 1 +#define PF_NEXT_ENABLE 2 +#define PF_BACK_SHOW 8 +#define PF_LICENSE_STREAM 16 +#define PF_NO_NEXT_FOCUS 128 +#define PF_BACK_ENABLE 256 +*/ + +// page window proc +enum +{ + PWP_LICENSE, + PWP_SELCOM, + PWP_DIR, + PWP_INSTFILES, + PWP_UNINST, + PWP_COMPLETED, + PWP_CUSTOM +}; + +static const char * const kPageTypes[] = +{ + "license" + , "components" + , "directory" + , "instfiles" + , "uninstConfirm" + , "COMPLETED" + , "custom" +}; + +#define SET_FUNC_REF(x, flag) if ((Int32)(x) >= 0 && (x) < bh.Num) \ + { labels[x] = (labels[x] & ~CMD_REF_Page_Mask) | ((flag) | (pageIndex << CMD_REF_Page_NumShifts)); } + +// #define IDD_LICENSE 102 +#define IDD_LICENSE_FSRB 108 +#define IDD_LICENSE_FSCB 109 + +void CInArchive::AddPageOption1(UInt32 param, const char *name) +{ + if (param == 0) + return; + TabString(name); + AddParam(param); + NewLine(); +} + +void CInArchive::AddPageOption(const UInt32 *params, unsigned num, const char *name) +{ + num = GetNumParams(params, num); + if (num == 0) + return; + TabString(name); + AddParams(params, num); + NewLine(); +} + +void CInArchive::Separator() +{ + AddLF(); + AddCommentAndString("--------------------"); + AddLF(); +} + +void CInArchive::Space() +{ + Script += ' '; +} + +void CInArchive::Tab() +{ + Script += " "; +} + +void CInArchive::Tab(bool commented) +{ + Script += commented ? " ; " : " "; +} + +void CInArchive::BigSpaceComment() +{ + Script += " ; "; +} + +void CInArchive::SmallSpaceComment() +{ + Script += " ; "; +} + +void CInArchive::AddCommentAndString(const char *s) +{ + Script += "; "; + Script += s; +} + +void CInArchive::AddError(const char *s) +{ + BigSpaceComment(); + Script += "!!! ERROR: "; + Script += s; +} + +void CInArchive::AddErrorLF(const char *s) +{ + AddError(s); + AddLF(); +} + +void CInArchive::CommentOpen() +{ + AddStringLF("/*"); +} + +void CInArchive::CommentClose() +{ + AddStringLF("*/"); +} + +void CInArchive::AddLF() +{ + Script += CR_LF; +} + +void CInArchive::AddQuotes() +{ + Script += "\"\""; +} + +void CInArchive::TabString(const char *s) +{ + Tab(); + Script += s; +} + +void CInArchive::AddStringLF(const char *s) +{ + Script += s; + AddLF(); +} + +// ---------- Section ---------- + +static const char * const kSection_VarsNames[] = +{ + "Text" + , "InstTypes" + , "Flags" + , "Code" + , "CodeSize" + , "Size" // size in KB +}; + +void CInArchive::Add_SectOp(UInt32 opType) +{ + ADD_TYPE_FROM_LIST(kSection_VarsNames, opType); +} + +void CSection::Parse(const Byte *p) +{ + Name = Get32(p); + InstallTypes = Get32(p + 4); + Flags = Get32(p + 8); + StartCmdIndex = Get32(p + 12); + NumCommands = Get32(p + 16); + SizeKB = Get32(p + 20); +} + +// used for section->flags +#define SF_SELECTED (1 << 0) +#define SF_SECGRP (1 << 1) +#define SF_SECGRPEND (1 << 2) +#define SF_BOLD (1 << 3) +#define SF_RO (1 << 4) +#define SF_EXPAND (1 << 5) +/* +#define SF_PSELECTED (1 << 6) +#define SF_TOGGLED (1 << 7) +#define SF_NAMECHG (1 << 8) +*/ + +bool CInArchive::PrintSectionBegin(const CSection §, unsigned index) +{ + AString name; + if (sect.Flags & SF_BOLD) + name += '!'; + AString s2; + ReadString2(s2, sect.Name); + if (!IsInstaller) + { + if (!StringsAreEqualNoCase_Ascii(s2, "uninstall")) + name += "un."; + } + name += s2; + + if (sect.Flags & SF_SECGRPEND) + { + AddStringLF("SectionGroupEnd"); + return true; + } + + if (sect.Flags & SF_SECGRP) + { + Script += "SectionGroup"; + if (sect.Flags & SF_EXPAND) + Script += " /e"; + SpaceQuStr(name); + Script += " ; Section"; + AddParam_UInt(index); + NewLine(); + return true; + } + + Script += "Section"; + if ((sect.Flags & SF_SELECTED) == 0) + Script += " /o"; + if (!name.IsEmpty()) + SpaceQuStr(name); + + /* + if (!name.IsEmpty()) + Script += ' '; + else + */ + SmallSpaceComment(); + Script += "Section_"; + Add_UInt(index); + + /* + Script += " ; flags = "; + Add_Hex(Script, sect.Flags); + */ + + NewLine(); + + if (sect.SizeKB != 0) + { + // probably we must show AddSize, only if there is additional size. + Tab(); + AddCommentAndString("AddSize"); + AddParam_UInt(sect.SizeKB); + AddLF(); + } + + bool needSectionIn = + (sect.Name != 0 && sect.InstallTypes != 0) || + (sect.Name == 0 && sect.InstallTypes != 0xFFFFFFFF); + if (needSectionIn || (sect.Flags & SF_RO) != 0) + { + TabString("SectionIn"); + UInt32 instTypes = sect.InstallTypes; + for (unsigned i = 0; i < 32; i++, instTypes >>= 1) + if ((instTypes & 1) != 0) + { + AddParam_UInt(i + 1); + } + if ((sect.Flags & SF_RO) != 0) + Script += " RO"; + AddLF(); + } + return false; +} + +void CInArchive::PrintSectionEnd() +{ + AddStringLF("SectionEnd"); + AddLF(); +} + +// static const unsigned kOnFuncShift = 4; + +void CInArchive::ClearLangComment() +{ + langStrIDs.Clear(); +} + +void CInArchive::PrintNumComment(const char *name, UInt32 value) +{ + // size_t len = Script.Len(); + AddCommentAndString(name); + Script += ": "; + Add_UInt(value); + AddLF(); + /* + len = Script.Len() - len; + char sz[16]; + ConvertUInt32ToString(value, sz); + len += MyStringLen(sz); + for (; len < 20; len++) + Space(); + AddStringLF(sz); + */ +} + + +void CInArchive::NewLine() +{ + if (!langStrIDs.IsEmpty()) + { + BigSpaceComment(); + for (unsigned i = 0; i < langStrIDs.Size() && i < 20; i++) + { + /* + if (i != 0) + Script += ' '; + */ + UInt32 langStr = langStrIDs[i]; + if (langStr >= _numLangStrings) + { + AddError("langStr"); + break; + } + UInt32 param = Get32(_mainLang + langStr * 4); + if (param != 0) + AddParam(param); + } + ClearLangComment(); + } + AddLF(); +} + +static const UInt32 kPageSize = 16 * 4; + +static const char * const k_SetOverwrite_Modes[] = +{ + "on" + , "off" + , "try" + , "ifnewer" + , "ifdiff" + // "lastused" +}; + + +void CInArchive::MessageBox_MB_Part(UInt32 param) +{ + { + UInt32 v = param & 0xF; + Script += " MB_"; + if (v < Z7_ARRAY_SIZE(k_MB_Buttons)) + Script += k_MB_Buttons[v]; + else + { + Script += "Buttons_"; + Add_UInt(v); + } + } + { + UInt32 icon = (param >> 4) & 0x7; + if (icon != 0) + { + Script += "|MB_"; + if (icon < Z7_ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon]) + Script += k_MB_Icons[icon]; + else + { + Script += "Icon_"; + Add_UInt(icon); + } + } + } + if ((param & 0x80) != 0) + Script += "|MB_USERICON"; + { + UInt32 defButton = (param >> 8) & 0xF; + if (defButton != 0) + { + Script += "|MB_DEFBUTTON"; + Add_UInt(defButton + 1); + } + } + { + UInt32 modal = (param >> 12) & 0x3; + if (modal == 1) Script += "|MB_SYSTEMMODAL"; + else if (modal == 2) Script += "|MB_TASKMODAL"; + else if (modal == 3) Script += "|0x3000"; + UInt32 flags = (param >> 14); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_MB_Flags); i++) + if ((flags & (1 << i)) != 0) + { + Script += "|MB_"; + Script += k_MB_Flags[i]; + } + } +} + +#define GET_CMD_PARAM(ppp, index) Get32((ppp) + 4 + (index) * 4) + +static const Byte k_InitPluginDir_Commands[] = + { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 }; + +bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) +{ + for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) + if (GetCmd(Get32(rawCmds)) != sequence[kkk]) + return false; + return true; +} + + +static const UInt32 kSectionSize_base = 6 * 4; +// static const UInt32 kSectionSize_8bit = kSectionSize_base + 1024; +// static const UInt32 kSectionSize_16bit = kSectionSize_base + 1024 * 2; +// static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2; +// 8196 is default string length in NSIS-Unicode since 2.37.3 + +#endif + + +static void AddString(AString &dest, const char *src) +{ + dest.Add_Space_if_NotEmpty(); + dest += src; +} + +AString CInArchive::GetFormatDescription() const +{ + AString s ("NSIS-"); + char c; + if (IsPark()) + { + s += "Park-"; + c = '1'; + if (NsisType == k_NsisType_Park2) c = '2'; + else if (NsisType == k_NsisType_Park3) c = '3'; + } + else + { + c = '2'; + if (NsisType == k_NsisType_Nsis3) + c = '3'; + } + s += c; + if (IsNsis200) + s += ".00"; + else if (IsNsis225) + s += ".25"; + + if (IsUnicode) + AddString(s, "Unicode"); + + if (Is64Bit) + AddString(s, "64-bit"); + + if (LogCmdIsEnabled) + AddString(s, "log"); + + if (BadCmd >= 0) + { + AddString(s, "BadCmd="); + UIntToString(s, (UInt32)BadCmd); + } + return s; +} + +#ifdef NSIS_SCRIPT + +static const unsigned kNumAdditionalParkCmds = 3; + +unsigned CInArchive::GetNumSupportedCommands() const +{ + unsigned numCmds = IsPark() ? (unsigned)kNumCmds : (unsigned)(kNumCmds) - kNumAdditionalParkCmds; + if (!LogCmdIsEnabled) + numCmds--; + if (!IsUnicode) + numCmds -= 2; + return numCmds; +} + +#endif + +UInt32 CInArchive::GetCmd(UInt32 a) +{ + if (!IsPark()) + { + if (!LogCmdIsEnabled) + return a; + if (a < EW_SECTIONSET) + return a; + if (a == EW_SECTIONSET) + return EW_LOG; + return a - 1; + } + + if (a < EW_REGISTERDLL) + return a; + if (NsisType >= k_NsisType_Park2) + { + if (a == EW_REGISTERDLL) return EW_GETFONTVERSION; + a--; + } + if (NsisType >= k_NsisType_Park3) + { + if (a == EW_REGISTERDLL) return EW_GETFONTNAME; + a--; + } + if (a >= EW_FSEEK) + { + if (IsUnicode) + { + if (a == EW_FSEEK) return EW_FPUTWS; + if (a == EW_FSEEK + 1) return EW_FPUTWS + 1; + a -= 2; + } + + if (a >= EW_SECTIONSET && LogCmdIsEnabled) + { + if (a == EW_SECTIONSET) + return EW_LOG; + return a - 1; + } + if (a == EW_FPUTWS) + return EW_FINDPROC; + // if (a > EW_FPUTWS) return 0; + } + return a; +} + +void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p) +{ + BadCmd = -1; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + const UInt32 id = GetCmd(Get32(p)); + if (id >= kNumCmds) + continue; + if (BadCmd >= 0 && id >= (unsigned)BadCmd) + continue; + unsigned i; + if (IsNsis3_OrHigher()) + { + if (id == EW_RESERVEDOPCODE) + { + BadCmd = (int)id; + continue; + } + } + else + { + // if (id == EW_GETLABELADDR || id == EW_GETFUNCTIONADDR) + if (id == EW_RESERVEDOPCODE || id == EW_GETOSINFO) + { + BadCmd = (int)id; + continue; + } + } + for (i = 6; i != 0; i--) + { + const UInt32 param = Get32(p + i * 4); + if (param != 0) + break; + } + if (id == EW_FINDPROC && i == 0) + { + BadCmd = (int)id; + continue; + } + if (k_Commands[id].NumParams < i) + BadCmd = (int)id; + } +} + +/* We calculate the number of parameters in commands to detect + layout of commands. It's not very good way. + If you know simpler and more robust way to detect Version and layout, + please write to 7-Zip forum */ + +void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p) +{ + bool strongPark = false; + bool strongNsis = false; + + if (NumStringChars > 2) + { + const Byte *strData = _data + _stringsPos; + if (IsUnicode) + { + UInt32 num = NumStringChars - 2; + for (UInt32 i = 0; i < num; i++) + { + if (Get16(strData + i * 2) == 0) + { + unsigned c2 = Get16(strData + 2 + i * 2); + // it can be TXT/RTF with marker char (1 or 2). so we must check next char + // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL) + if (c2 == NS_3_CODE_VAR) + { + // 18.06: fixed: is it correct ? + // if ((Get16(strData + 3 + i * 2) & 0x8000) != 0) + if ((Get16(strData + 4 + i * 2) & 0x8080) == 0x8080) + { + NsisType = k_NsisType_Nsis3; + strongNsis = true; + break; + } + } + } + } + if (!strongNsis) + { + NsisType = k_NsisType_Park1; + strongPark = true; + } + } + else + { + UInt32 num = NumStringChars - 2; + for (UInt32 i = 0; i < num; i++) + { + if (strData[i] == 0) + { + Byte c2 = strData[i + 1]; + // it can be TXT/RTF with marker char (1 or 2). so we must check next char + // for marker=1 (txt) + if (c2 == NS_3_CODE_VAR) + // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1) + { + if ((strData[i + 2] & 0x80) != 0) + { + // const char *p2 = (const char *)(strData + i + 1); + // p2 = p2; + NsisType = k_NsisType_Nsis3; + strongNsis = true; + break; + } + } + } + } + } + } + + if (NsisType == k_NsisType_Nsis2 && !IsUnicode) + { + const Byte *p2 = p; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) + { + UInt32 cmd = GetCmd(Get32(p2)); + if (cmd != EW_GETDLGITEM && + cmd != EW_ASSIGNVAR) + continue; + + UInt32 params[kNumCommandParams]; + for (unsigned i = 0; i < kNumCommandParams; i++) + params[i] = Get32(p2 + 4 + 4 * i); + + if (cmd == EW_GETDLGITEM) + { + // we can use also EW_SETCTLCOLORS + if (IsVarStr(params[1], kVar_HWNDPARENT_225)) + { + IsNsis225 = true; + if (params[0] == kVar_Spec_OUTDIR_225) + { + IsNsis200 = true; + break; + } + } + } + else // if (cmd == EW_ASSIGNVAR) + { + if (params[0] == kVar_Spec_OUTDIR_225 && + params[2] == 0 && + params[3] == 0 && + IsVarStr(params[1], kVar_OUTDIR)) + IsNsis225 = true; + } + } + } + + bool parkVer_WasDetected = false; + + if (!strongNsis && !IsNsis225 && !IsNsis200) + { + // it must be before FindBadCmd(bh, p); + unsigned mask = 0; + + unsigned numInsertMax = IsUnicode ? 4 : 2; + + const Byte *p2 = p; + + for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize) + { + const UInt32 cmd = Get32(p2); // we use original (not converted) command + + if (cmd < EW_WRITEUNINSTALLER || + cmd > EW_WRITEUNINSTALLER + numInsertMax) + continue; + + UInt32 params[kNumCommandParams]; + for (unsigned i = 0; i < kNumCommandParams; i++) + params[i] = Get32(p2 + 4 + 4 * i); + + if (params[4] != 0 || + params[5] != 0 || + params[0] <= 1 || + params[3] <= 1) + continue; + + const UInt32 altParam = params[3]; + if (!IsGoodString(params[0]) || + !IsGoodString(altParam)) + continue; + + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) != kVar_INSTDIR) + continue; + if (AreTwoParamStringsEqual(altParam + additional, params[0])) + { + const unsigned numInserts = cmd - EW_WRITEUNINSTALLER; + mask |= ((unsigned)1 << numInserts); + } + } + + if (mask == 1) + { + parkVer_WasDetected = true; // it can be original NSIS or Park-1 + } + else if (mask != 0) + { + ENsisType newType = NsisType; + if (IsUnicode) + switch (mask) + { + case (1 << 3): newType = k_NsisType_Park2; break; + case (1 << 4): newType = k_NsisType_Park3; break; + } + else + switch (mask) + { + case (1 << 1): newType = k_NsisType_Park2; break; + case (1 << 2): newType = k_NsisType_Park3; break; + } + if (newType != NsisType) + { + parkVer_WasDetected = true; + NsisType = newType; + } + } + } + + FindBadCmd(bh, p); + + /* + if (strongNsis) + return; + */ + + if (BadCmd < EW_REGISTERDLL) + return; + + /* + // in ANSI archive we don't check Park and log version + if (!IsUnicode) + return; + */ + + // We can support Park-ANSI archives, if we remove if (strongPark) check + if (strongPark && !parkVer_WasDetected) + { + if (BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park3; + LogCmdIsEnabled = true; // version 3 is provided with log enabled + FindBadCmd(bh, p); + if (BadCmd > 0 && BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park2; + LogCmdIsEnabled = false; + FindBadCmd(bh, p); + if (BadCmd > 0 && BadCmd < EW_SECTIONSET) + { + NsisType = k_NsisType_Park1; + FindBadCmd(bh, p); + } + } + } + } + + if (BadCmd >= EW_SECTIONSET) + { + LogCmdIsEnabled = !LogCmdIsEnabled; + FindBadCmd(bh, p); + if (BadCmd >= EW_SECTIONSET && LogCmdIsEnabled) + { + LogCmdIsEnabled = false; + FindBadCmd(bh, p); + } + } +} + +Int32 CInArchive::GetVarIndex(UInt32 strPos) const +{ + if (strPos >= NumStringChars) + return -1; + + if (IsUnicode) + { + if (NumStringChars - strPos < 3 * 2) + return -1; + const Byte *p = _data + _stringsPos + strPos * 2; + unsigned code = Get16(p); + if (IsPark()) + { + if (code != PARK_CODE_VAR) + return -1; + UInt32 n = Get16(p + 2); + if (n == 0) + return -1; + CONVERT_NUMBER_PARK(n); + return (Int32)n; + } + + // NSIS-3 + { + if (code != NS_3_CODE_VAR) + return -1; + UInt32 n = Get16(p + 2); + if (n == 0) + return -1; + CONVERT_NUMBER_NS_3_UNICODE(n); + return (Int32)n; + } + } + + if (NumStringChars - strPos < 4) + return -1; + + const Byte *p = _data + _stringsPos + strPos; + unsigned c = *p; + if (NsisType == k_NsisType_Nsis3) + { + if (c != NS_3_CODE_VAR) + return -1; + } + else if (c != NS_CODE_VAR) + return -1; + + const unsigned c0 = p[1]; + if (c0 == 0) + return -1; + const unsigned c1 = p[2]; + if (c1 == 0) + return -1; + return (Int32)DECODE_NUMBER_FROM_2_CHARS(c0, c1); +} + +Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const +{ + resOffset = 0; + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return varIndex; + if (IsUnicode) + { + if (NumStringChars - strPos < 2 * 2) + return -1; + resOffset = 2; + } + else + { + if (NumStringChars - strPos < 3) + return -1; + resOffset = 3; + } + return varIndex; +} + +Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const +{ + resOffset = 0; + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return varIndex; + if (IsUnicode) + { + if (NumStringChars - strPos < 3 * 2) + return -1; + const Byte *p = _data + _stringsPos + strPos * 2; + if (Get16(p + 4) != endChar) + return -1; + resOffset = 3; + } + else + { + if (NumStringChars - strPos < 4) + return -1; + const Byte *p = _data + _stringsPos + strPos; + if (p[3] != endChar) + return -1; + resOffset = 4; + } + return varIndex; +} + +bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const +{ + if (varIndex > (UInt32)0x7FFF) + return false; + UInt32 resOffset; + return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex; +} + +bool CInArchive::IsAbsolutePathVar(UInt32 strPos) const +{ + Int32 varIndex = GetVarIndex(strPos); + if (varIndex < 0) + return false; + switch (varIndex) + { + case kVar_INSTDIR: + case kVar_EXEDIR: + case kVar_TEMP: + case kVar_PLUGINSDIR: + return true; + } + return false; +} + +#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) + +// We use same check as in NSIS decoder +static bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } +static bool IsDrivePath(const char *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; } + +static bool IsAbsolutePath(const wchar_t *s) +{ + return (s[0] == WCHAR_PATH_SEPARATOR && s[1] == WCHAR_PATH_SEPARATOR) || IsDrivePath(s); +} + +static bool IsAbsolutePath(const char *s) +{ + return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s); +} + +void CInArchive::SetItemName(CItem &item, UInt32 strPos) +{ + ReadString2_Raw(strPos); + const bool isAbs = IsAbsolutePathVar(strPos); + if (IsUnicode) + { + item.NameU = Raw_UString; + if (!isAbs && !IsAbsolutePath(Raw_UString)) + item.Prefix = (int)UPrefixes.Size() - 1; + } + else + { + item.NameA = Raw_AString; + if (!isAbs && !IsAbsolutePath(Raw_AString)) + item.Prefix = (int)APrefixes.Size() - 1; + } +} + +HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) +{ + #ifdef NSIS_SCRIPT + CDynLimBuf &s = Script; + + CObjArray labels; + labels.Alloc(bh.Num); + memset(labels, 0, bh.Num * sizeof(UInt32)); + + { + const Byte *p = _data; + UInt32 i; + for (i = 0; i < numOnFunc; i++) + { + UInt32 func = Get32(p + onFuncOffset + 4 * i); + if (func < bh.Num) + labels[func] = (labels[func] & ~CMD_REF_OnFunc_Mask) | (CMD_REF_OnFunc | (i << CMD_REF_OnFunc_NumShifts)); + } + } + + /* + { + for (int i = 0; i < OnFuncs.Size(); i++) + { + UInt32 address = OnFuncs[i] >> kOnFuncShift; + if (address < bh.Num) + } + } + */ + + if (bhPages.Num != 0) + { + Separator(); + PrintNumComment("PAGES", bhPages.Num); + + if (bhPages.Num > (1 << 12) + || bhPages.Offset > _size + || bhPages.Num * kPageSize > _size - bhPages.Offset) + { + AddErrorLF("Pages error"); + } + else + { + + AddLF(); + const Byte *p = _data + bhPages.Offset; + + for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, p += kPageSize) + { + UInt32 dlgID = Get32(p); + UInt32 wndProcID = Get32(p + 4); + UInt32 preFunc = Get32(p + 8); + UInt32 showFunc = Get32(p + 12); + UInt32 leaveFunc = Get32(p + 16); + UInt32 flags = Get32(p + 20); + UInt32 caption = Get32(p + 24); + // UInt32 back = Get32(p + 28); + UInt32 next = Get32(p + 32); + // UInt32 clickNext = Get32(p + 36); + // UInt32 cancel = Get32(p + 40); + UInt32 params[5]; + for (int i = 0; i < 5; i++) + params[i] = Get32(p + 44 + 4 * i); + + SET_FUNC_REF(preFunc, CMD_REF_Pre) + SET_FUNC_REF(showFunc, CMD_REF_Show) + SET_FUNC_REF(leaveFunc, CMD_REF_Leave) + + if (wndProcID == PWP_COMPLETED) + CommentOpen(); + + AddCommentAndString("Page "); + Add_UInt(pageIndex); + AddLF(); + + if (flags & PF_PAGE_EX) + { + s += "PageEx "; + if (!IsInstaller) + s += "un."; + } + else + s += IsInstaller ? "Page " : "UninstPage "; + + if (wndProcID < Z7_ARRAY_SIZE(kPageTypes)) + s += kPageTypes[wndProcID]; + else + Add_UInt(wndProcID); + + + bool needCallbacks = ( + (Int32)preFunc >= 0 || + (Int32)showFunc >= 0 || + (Int32)leaveFunc >= 0); + + if (flags & PF_PAGE_EX) + { + AddLF(); + if (needCallbacks) + TabString("PageCallbacks"); + } + + if (needCallbacks) + { + AddParam_Func(labels, preFunc); // it's creator_function for PWP_CUSTOM + if (wndProcID != PWP_CUSTOM) + { + AddParam_Func(labels, showFunc); + } + AddParam_Func(labels, leaveFunc); + } + + if ((flags & PF_PAGE_EX) == 0) + { + // AddOptionalParam(caption); + if (flags & PF_CANCEL_ENABLE) + s += " /ENABLECANCEL"; + AddLF(); + } + else + { + AddLF(); + AddPageOption1(caption, "Caption"); + } + + if (wndProcID == PWP_LICENSE) + { + if ((flags & PF_LICENSE_NO_FORCE_SELECTION) != 0 || + (flags & PF_LICENSE_FORCE_SELECTION) != 0) + { + TabString("LicenseForceSelection "); + if (flags & PF_LICENSE_NO_FORCE_SELECTION) + s += "off"; + else + { + if (dlgID == IDD_LICENSE_FSCB) + s += "checkbox"; + else if (dlgID == IDD_LICENSE_FSRB) + s += "radiobuttons"; + else + Add_UInt(dlgID); + AddOptionalParams(params + 2, 2); + } + NewLine(); + } + + if (params[0] != 0 || next != 0) + { + TabString("LicenseText"); + AddParam(params[0]); + AddOptionalParam(next); + NewLine(); + } + if (params[1] != 0) + { + TabString("LicenseData"); + if ((Int32)params[1] < 0) + AddParam(params[1]); + else + AddLicense(params[1], -1); + ClearLangComment(); + NewLine(); + } + } + else if (wndProcID == PWP_SELCOM) + AddPageOption(params, 3, "ComponentsText"); + else if (wndProcID == PWP_DIR) + { + AddPageOption(params, 4, "DirText"); + if (params[4] != 0) + { + TabString("DirVar"); + AddParam_Var(params[4] - 1); + AddLF(); + } + if (flags & PF_DIR_NO_BTN_DISABLE) + { + TabString("DirVerify leave"); + AddLF(); + } + + } + else if (wndProcID == PWP_INSTFILES) + { + AddPageOption1(params[2], "CompletedText"); + AddPageOption1(params[1], "DetailsButtonText"); + } + else if (wndProcID == PWP_UNINST) + { + if (params[4] != 0) + { + TabString("DirVar"); + AddParam_Var(params[4] - 1); + AddLF(); + } + AddPageOption(params, 2, "UninstallText"); + } + + if (flags & PF_PAGE_EX) + { + s += "PageExEnd"; + NewLine(); + } + if (wndProcID == PWP_COMPLETED) + CommentClose(); + NewLine(); + } + } + } + + CObjArray Sections; + + { + Separator(); + PrintNumComment("SECTIONS", bhSections.Num); + PrintNumComment("COMMANDS", bh.Num); + AddLF(); + + if (bhSections.Num > (1 << 15) + // || bhSections.Offset > _size + // || (bhSections.Num * SectionSize > _size - bhSections.Offset) + ) + { + AddErrorLF("Sections error"); + } + else if (bhSections.Num != 0) + { + Sections.Alloc((unsigned)bhSections.Num); + const Byte *p = _data + bhSections.Offset; + for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize) + { + CSection §ion = Sections[i]; + section.Parse(p); + if (section.StartCmdIndex < bh.Num) + labels[section.StartCmdIndex] |= CMD_REF_Section; + } + } + } + + #endif + + const Byte *p; + UInt32 kkk; + + #ifdef NSIS_SCRIPT + + p = _data + bh.Offset; + + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 commandId = GetCmd(Get32(p)); + UInt32 mask; + switch (commandId) + { + case EW_NOP: mask = 1 << 0; break; + case EW_IFFILEEXISTS: mask = 3 << 1; break; + case EW_IFFLAG: mask = 3 << 0; break; + case EW_MESSAGEBOX: mask = 5 << 3; break; + case EW_STRCMP: mask = 3 << 2; break; + case EW_INTCMP: mask = 7 << 2; break; + case EW_ISWINDOW: mask = 3 << 1; break; + case EW_CALL: + { + if (Get32(p + 4 + 4) == 1) // it's Call :Label + { + mask = 1 << 0; + break; + } + UInt32 param0 = Get32(p + 4); + if ((Int32)param0 > 0) + labels[param0 - 1] |= CMD_REF_Call; + continue; + } + default: continue; + } + for (unsigned i = 0; mask != 0; i++, mask >>= 1) + if (mask & 1) + { + UInt32 param = Get32(p + 4 + 4 * i); + if ((Int32)param > 0 && (Int32)param <= (Int32)bh.Num) + labels[param - 1] |= CMD_REF_Goto; + } + } + + int InitPluginsDir_Start = -1; + int InitPluginsDir_End = -1; + p = _data + bh.Offset; + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 flg = labels[kkk]; + /* + if (IsFunc(flg)) + { + AddLF(); + for (int i = 0; i < 14; i++) + { + UInt32 commandId = GetCmd(Get32(p + kCmdSize * i)); + s += ", "; + UIntToString(s, commandId); + } + AddLF(); + } + */ + if (IsFunc(flg) + && bh.Num - kkk >= Z7_ARRAY_SIZE(k_InitPluginDir_Commands) + && CompareCommands(p, k_InitPluginDir_Commands, Z7_ARRAY_SIZE(k_InitPluginDir_Commands))) + { + InitPluginsDir_Start = (int)kkk; + InitPluginsDir_End = (int)(kkk + Z7_ARRAY_SIZE(k_InitPluginDir_Commands)); + labels[kkk] |= CMD_REF_InitPluginDir; + break; + } + } + + #endif + + // AString prefixA_Temp; + // UString prefixU_Temp; + + + // const UInt32 kFindS = 158; + + #ifdef NSIS_SCRIPT + + UInt32 curSectionIndex = 0; + // UInt32 lastSectionEndCmd = 0xFFFFFFFF; + bool sectionIsOpen = false; + // int curOnFunc = 0; + bool onFuncIsOpen = false; + + /* + for (unsigned yyy = 0; yyy + 3 < _data.Size(); yyy++) + { + UInt32 val = Get32(_data + yyy); + if (val == kFindS) + val = val; + } + */ + + UInt32 overwrite_State = 0; // "SetOverwrite on" + Int32 allowSkipFiles_State = -1; // -1: on, -2: off, >=0 : RAW value + UInt32 endCommentIndex = 0; + + unsigned numSupportedCommands = GetNumSupportedCommands(); + + #endif + + p = _data + bh.Offset; + + UString spec_outdir_U; + AString spec_outdir_A; + + UPrefixes.Add(UString("$INSTDIR")); + APrefixes.Add(AString("$INSTDIR")); + + p = _data + bh.Offset; + + unsigned spec_outdir_VarIndex = IsNsis225 ? + kVar_Spec_OUTDIR_225 : + kVar_Spec_OUTDIR; + + for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize) + { + UInt32 commandId; + UInt32 params[kNumCommandParams]; + commandId = GetCmd(Get32(p)); + { + for (unsigned i = 0; i < kNumCommandParams; i++) + { + params[i] = Get32(p + 4 + 4 * i); + /* + if (params[i] == kFindS) + i = i; + */ + } + } + + #ifdef NSIS_SCRIPT + + bool IsSectionGroup = false; + while (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk) + break; + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + continue; + } + if (sect.StartCmdIndex != kkk) + break; + if (PrintSectionBegin(sect, curSectionIndex)) + { + IsSectionGroup = true; + curSectionIndex++; + // do we need to flush prefixes in new section? + // FlushOutPathPrefixes(); + } + else + sectionIsOpen = true; + } + + /* + if (curOnFunc < OnFuncs.Size()) + { + if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk) + { + s += "Function .on"; + s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)]; + AddLF(); + onFuncIsOpen = true; + } + } + */ + + if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section) + { + UInt32 flg = labels[kkk]; + if (IsFunc(flg)) + { + if ((int)kkk == InitPluginsDir_Start) + CommentOpen(); + + onFuncIsOpen = true; + s += "Function "; + Add_FuncName(labels, kkk); + if (IsPageFunc(flg)) + { + BigSpaceComment(); + s += "Page "; + Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts); + // if (flg & CMD_REF_Creator) s += ", Creator"; + if (flg & CMD_REF_Leave) s += ", Leave"; + if (flg & CMD_REF_Pre) s += ", Pre"; + if (flg & CMD_REF_Show) s += ", Show"; + } + AddLF(); + } + if (flg & CMD_REF_Goto) + { + Add_LabelName(kkk); + s += ':'; + AddLF(); + } + } + + if (commandId != EW_RET) + { + Tab(kkk < endCommentIndex); + } + + /* + UInt32 originalCmd = Get32(p); + if (originalCmd >= EW_REGISTERDLL) + { + UIntToString(s, originalCmd); + s += ' '; + if (originalCmd != commandId) + { + UIntToString(s, commandId); + s += ' '; + } + } + */ + + unsigned numSkipParams = 0; + + if (commandId < Z7_ARRAY_SIZE(k_Commands) && commandId < numSupportedCommands) + { + numSkipParams = k_Commands[commandId].NumParams; + const char *sz = k_CommandNames[commandId]; + if (sz) + s += sz; + } + else + { + s += "Command"; + Add_UInt(commandId); + /* We don't show wrong commands that use overlapped ids. + So we change commandId to big value */ + if (commandId < (1 << 12)) + commandId += (1 << 12); + } + + #endif + + switch (commandId) + { + case EW_CREATEDIR: + { + bool isSetOutPath = (params[1] != 0); + + if (isSetOutPath) + { + UInt32 par0 = params[0]; + + UInt32 resOffset; + Int32 idx = GetVarIndex(par0, resOffset); + if (idx == (Int32)spec_outdir_VarIndex || + idx == kVar_OUTDIR) + par0 += resOffset; + + ReadString2_Raw(par0); + + if (IsUnicode) + { + if (idx == (Int32)spec_outdir_VarIndex) + Raw_UString.Insert(0, spec_outdir_U); + else if (idx == kVar_OUTDIR) + Raw_UString.Insert(0, UPrefixes.Back()); + UPrefixes.Add(Raw_UString); + } + else + { + if (idx == (Int32)spec_outdir_VarIndex) + Raw_AString.Insert(0, spec_outdir_A); + else if (idx == kVar_OUTDIR) + Raw_AString.Insert(0, APrefixes.Back()); + APrefixes.Add(Raw_AString); + } + } + + #ifdef NSIS_SCRIPT + s += isSetOutPath ? "SetOutPath" : "CreateDirectory"; + AddParam(params[0]); + if (params[2] != 0) // 2.51+ & 3.0b3+ + { + SmallSpaceComment(); + s += "CreateRestrictedDirectory"; + } + #endif + + break; + } + + + case EW_ASSIGNVAR: + { + if (params[0] == spec_outdir_VarIndex) + { + spec_outdir_U.Empty(); + spec_outdir_A.Empty(); + if (IsVarStr(params[1], kVar_OUTDIR) && + params[2] == 0 && + params[3] == 0) + { + spec_outdir_U = UPrefixes.Back(); // outdir_U; + spec_outdir_A = APrefixes.Back(); // outdir_A; + } + } + + #ifdef NSIS_SCRIPT + + if (params[2] == 0 && + params[3] == 0 && + params[4] == 0 && + params[5] == 0 && + params[1] != 0 && + params[1] < NumStringChars) + { + char sz[16]; + ConvertUInt32ToString(kkk + 1, sz); + if (IsDirectString_Equal(params[1], sz)) + { + // we suppose that it's GetCurrentAddress command + // but there is probability that it's StrCpy command + s += "GetCurrentAddress"; + AddParam_Var(params[0]); + SmallSpaceComment(); + } + } + s += "StrCpy"; + AddParam_Var(params[0]); + AddParam(params[1]); + + AddOptionalParams(params + 2, 2); + + #endif + + break; + } + + case EW_EXTRACTFILE: + { + CItem &item = Items.AddNew(); + + UInt32 par1 = params[1]; + + SetItemName(item, par1); + + item.Pos = params[2]; + item.MTime.dwLowDateTime = params[3]; + item.MTime.dwHighDateTime = params[4]; + + #ifdef NSIS_SCRIPT + + { + UInt32 overwrite = params[0] & 0x7; + if (overwrite != overwrite_State) + { + s += "SetOverwrite "; + ADD_TYPE_FROM_LIST(k_SetOverwrite_Modes, overwrite); + overwrite_State = overwrite; + AddLF(); + Tab(kkk < endCommentIndex); + } + } + + { + UInt32 nsisMB = params[0] >> 3; + if ((Int32)nsisMB != allowSkipFiles_State) + { + UInt32 mb = nsisMB & ((1 << 20) - 1); // old/new NSIS + UInt32 b1 = nsisMB >> 21; // NSIS 2.06+ + UInt32 b2 = nsisMB >> 20; // NSIS old + Int32 asf = (Int32)nsisMB; + if (mb == (Z7_NSIS_WIN_MB_ABORTRETRYIGNORE | Z7_NSIS_WIN_MB_ICONSTOP) && (b1 == Z7_NSIS_WIN_IDIGNORE || b2 == Z7_NSIS_WIN_IDIGNORE)) + asf = -1; + else if (mb == (Z7_NSIS_WIN_MB_RETRYCANCEL | Z7_NSIS_WIN_MB_ICONSTOP) && (b1 == Z7_NSIS_WIN_IDCANCEL || b2 == Z7_NSIS_WIN_IDCANCEL)) + asf = -2; + else + { + AddCommentAndString("AllowSkipFiles [Overwrite]: "); + MessageBox_MB_Part(mb); + if (b1 != 0) + { + s += " /SD"; + Add_ButtonID(b1); + } + } + if (asf != allowSkipFiles_State) + { + if (asf < 0) + { + s += "AllowSkipFiles "; + s += (asf == -1) ? "on" : "off"; + } + AddLF(); + Tab(kkk < endCommentIndex); + } + allowSkipFiles_State = (Int32)nsisMB; + } + } + + s += "File"; + AddParam(params[1]); + + /* params[5] contains link to LangString (negative value) + with NLF_FILE_ERROR or NLF_FILE_ERROR_NOIGNORE message for MessageBox. + We don't need to print it. */ + + #endif + + if (IsVarStr(par1, 10)) // is $R0 + { + // we parse InstallLib macro in 7-Zip installers + unsigned kBackOffset = 28; + if (kkk > 1) + { + // detect old version of InstallLib macro + if (Get32(p - 1 * kCmdSize) == EW_NOP) // goto command + kBackOffset -= 2; + } + + if (kkk > kBackOffset) + { + const Byte *p2 = p - kBackOffset * kCmdSize; + UInt32 cmd = Get32(p2); + if (cmd == EW_ASSIGNVAR) + { + UInt32 pars[6]; + for (int i = 0; i < 6; i++) + pars[i] = Get32(p2 + i * 4 + 4); + if (pars[0] == 10 + 4 && pars[2] == 0 && pars[3] == 0) // 10 + 4 means $R4 + { + item.Prefix = -1; + item.NameA.Empty(); + item.NameU.Empty(); + SetItemName(item, pars[1]); + // maybe here we can restore original item name, if new name is empty + } + } + } + } + /* UInt32 allowIgnore = params[5]; */ + break; + } + + case EW_SETFILEATTRIBUTES: + { + if (kkk > 0 && Get32(p - kCmdSize) == EW_EXTRACTFILE) + { + if (params[0] == Get32(p - kCmdSize + 4 + 4 * 1)) // compare with PrevCmd.Params[1] + { + CItem &item = Items.Back(); + item.Attrib_Defined = true; + item.Attrib = params[1]; + } + } + #ifdef NSIS_SCRIPT + AddParam(params[0]); + Space(); + FlagsToString2(s, g_WinAttrib, Z7_ARRAY_SIZE(g_WinAttrib), params[1]); + #endif + break; + } + + case EW_WRITEUNINSTALLER: + { + /* NSIS 2.29+ writes alternative path to params[3] + "$INSTDIR\\" + Str(params[0]) + NSIS installer uses alternative path, if main path + from params[0] is not absolute path */ + + const bool pathOk = (params[0] > 0) && IsGoodString(params[0]); + + if (!pathOk) + { + #ifdef NSIS_SCRIPT + AddError("bad path"); + #endif + break; + } + + #ifdef NSIS_SCRIPT + + bool altPathOk = true; + + const UInt32 altParam = params[3]; + if (altParam != 0) + { + altPathOk = false; + UInt32 additional = 0; + if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR) + altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]); + } + + AddParam(params[0]); + + /* + for (int i = 1; i < 3; i++) + AddParam_UInt(params[i]); + */ + + if (params[3] != 0) + { + SmallSpaceComment(); + AddParam(params[3]); + } + + if (!altPathOk) + { + #ifdef NSIS_SCRIPT + AddError("alt path error"); + #endif + } + + #endif + + if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER) + { + /* We don't support cases with incorrect installer commands. + Such bad installer item can break unpacking for other items. */ + #ifdef NSIS_SCRIPT + AddError("SKIP possible BadCmd"); + #endif + break; + } + + CItem &item = Items.AddNew(); + + SetItemName(item, params[0]); + + item.Pos = params[1]; + item.PatchSize = params[2]; + item.IsUninstaller = true; + const UInt32 param3 = params[3]; + if (param3 != 0 && item.Prefix != -1) + { + /* (item.Prefix != -1) case means that param[0] path was not absolute. + So we use params[3] in that case, as original nsis */ + SetItemName(item, param3); + } + /* UNINSTALLER file doesn't use directory prefixes. + So we remove prefix: */ + item.Prefix = -1; + + /* + // we can add second time to test the code + CItem item2 = item; + item2.NameU += L'2'; + item2.NameA += '2'; + Items.Add(item2); + */ + + break; + } + + #ifdef NSIS_SCRIPT + + case EW_RET: + { + // bool needComment = false; + if (onFuncIsOpen) + { + if (kkk == bh.Num - 1 || IsProbablyEndOfFunc(labels[kkk + 1])) + { + AddStringLF("FunctionEnd"); + + if ((int)kkk + 1 == InitPluginsDir_End) + CommentClose(); + AddLF(); + onFuncIsOpen = false; + // needComment = true; + break; + } + } + // if (!needComment) + if (IsSectionGroup) + break; + if (sectionIsOpen) + { + const CSection § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + break; + } + + // needComment = true; + // break; + } + + /* + if (needComment) + s += " ;"; + */ + TabString("Return"); + AddLF(); + break; + } + + case EW_NOP: + { + if (params[0] == 0) + s += "Nop"; + else + { + s += "Goto"; + Add_GotoVar(params[0]); + } + break; + } + + case EW_ABORT: + { + AddOptionalParam(params[0]); + break; + } + + case EW_CALL: + { + if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE) + { + UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1); + + UInt32 pluginPar = 0; + + if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR) + { + pluginPar += par1; + UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2)); + if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT) + { + UInt32 i; + for (i = kkk + 3; i < bh.Num; i++) + { + const Byte *pCmd = p + kCmdSize * (i - kkk); + UInt32 commandId3 = GetCmd(Get32(pCmd)); + if (commandId3 != EW_PUSHPOP + || GET_CMD_PARAM(pCmd, 1) != 0 + || GET_CMD_PARAM(pCmd, 2) != 0) + break; + } + if (i < bh.Num) + { + const Byte *pCmd = p + kCmdSize * (i - kkk); + + // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0); + // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1); + + if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL && + AreTwoParamStringsEqual( + GET_CMD_PARAM(pCmd, 0), + GET_CMD_PARAM(p + kCmdSize, 1))) + { + // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx; + /// new versions of NSIS use params[4] = 1 for Plugin command + if (GET_CMD_PARAM(pCmd, 2) == 0 + // && GET_CMD_PARAM(pCmd, 4) != 0 + ) + { + { + AString s2; + ReadString2(s2, pluginPar); + if (s2.Len() >= 4 && + StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll")) + s2.DeleteFrom(s2.Len() - 4); + s2 += "::"; + AString func; + ReadString2(func, GET_CMD_PARAM(pCmd, 1)); + s2 += func; + Add_QuStr(s2); + + if (GET_CMD_PARAM(pCmd, 3) == 1) + s += " /NOUNLOAD"; + + for (UInt32 j = i - 1; j >= kkk + 3; j--) + { + const Byte *pCmd2 = p + kCmdSize * (j - kkk); + AddParam(GET_CMD_PARAM(pCmd2, 0)); + } + NewLine(); + Tab(true); + endCommentIndex = i + 1; + } + } + } + } + } + } + } + { + const Byte *nextCmd = p + kCmdSize; + UInt32 commandId2 = GetCmd(Get32(nextCmd)); + if (commandId2 == EW_SETFLAG + && GET_CMD_PARAM(nextCmd, 0) == k_ExecFlags_DetailsPrint + && GET_CMD_PARAM(nextCmd, 2) != 0) // is "lastused" + // || commandId2 == EW_UPDATETEXT) + { + if ((Int32)params[0] > 0 && labels[params[0] - 1] & CMD_REF_InitPluginDir) + { + s += "InitPluginsDir"; + AddLF(); + Tab(true); + endCommentIndex = kkk + 2; + } + } + } + + s += "Call "; + if ((Int32)params[0] < 0) + Add_Var((UInt32)-((Int32)params[0] + 1)); + else if (params[0] == 0) + s += '0'; + else + { + const UInt32 val = params[0] - 1; + if (params[1] == 1) // it's Call :Label + { + s += ':'; + Add_LabelName(val); + } + else // if (params[1] == 0) // it's Call Func + Add_FuncName(labels, val); + } + break; + } + + case EW_UPDATETEXT: + case EW_SLEEP: + { + AddParam(params[0]); + break; + } + + case EW_CHDETAILSVIEW: + { + if (params[0] == Z7_NSIS_WIN_SW_SHOWNA && params[1] == Z7_NSIS_WIN_SW_HIDE) s += " show"; + else if (params[1] == Z7_NSIS_WIN_SW_SHOWNA && params[0] == Z7_NSIS_WIN_SW_HIDE) s += " hide"; + else + for (int i = 0; i < 2; i++) + { + Space(); + Add_ShowWindow_Cmd(params[i]); + } + break; + } + + case EW_IFFILEEXISTS: + { + AddParam(params[0]); + Add_GotoVars2(¶ms[1]); + break; + } + + case EW_SETFLAG: + { + AString temp; + ReadString2(temp, params[1]); + if (params[0] == k_ExecFlags_Errors && params[2] == 0) + { + s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors"; + break; + } + s += "Set"; + Add_ExecFlags(params[0]); + + if (params[2] != 0) + { + s += " lastused"; + break; + } + UInt32 v; + if (StringToUInt32(temp, v)) + { + const char *s2 = NULL; + switch (params[0]) + { + case k_ExecFlags_AutoClose: + case k_ExecFlags_RebootFlag: + if (v < 2) { s2 = (v == 0) ? "false" : "true"; } break; + case k_ExecFlags_ShellVarContext: + if (v < 2) { s2 = (v == 0) ? "current" : "all"; } break; + case k_ExecFlags_Silent: + if (v < 2) { s2 = (v == 0) ? "normal" : "silent"; } break; + case k_ExecFlags_RegView: + if (v == 0) s2 = "32"; + else if (v == 256) s2 = "64"; + break; + case k_ExecFlags_DetailsPrint: + if (v == 0) s2 = "both"; + else if (v == 2) s2 = "textonly"; + else if (v == 4) s2 = "listonly"; + else if (v == 6) s2 = "none"; + break; + } + if (s2) + { + s += ' '; + s += s2; + break; + } + } + SpaceQuStr(temp); + break; + } + + case EW_IFFLAG: + { + Add_ExecFlags(params[2]); + Add_GotoVars2(¶ms[0]); + /* + const unsigned kIfErrors = 2; + if (params[2] != kIfErrors && params[3] != 0xFFFFFFFF || + params[2] == kIfErrors && params[3] != 0) + { + s += " # FLAG &= "; + AddParam_UInt(params[3]); + } + */ + break; + } + + case EW_GETFLAG: + { + Add_ExecFlags(params[1]); + AddParam_Var(params[0]); + break; + } + + case EW_RENAME: + { + if (params[2] != 0) + s += k_REBOOTOK; + AddParams(params, 2); + if (params[3] != 0) + { + SmallSpaceComment(); + AddParam(params[3]); // rename comment for log file + } + break; + } + + case EW_GETFULLPATHNAME: + { + if (params[2] == 0) + s += " /SHORT"; + AddParam_Var(params[1]); + AddParam(params[0]); + break; + } + + case EW_SEARCHPATH: + case EW_STRLEN: + { + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + + case EW_GETTEMPFILENAME: + { + AddParam_Var(params[0]); + AString temp; + ReadString2(temp, params[1]); + if (temp != "$TEMP") + SpaceQuStr(temp); + break; + } + + case EW_DELETEFILE: + { + UInt32 flag = params[1]; + if ((flag & DEL_REBOOT) != 0) + s += k_REBOOTOK; + AddParam(params[0]); + break; + } + + case EW_MESSAGEBOX: + { + MessageBox_MB_Part(params[0]); + AddParam(params[1]); + { + UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+ + if (buttonID != 0) + { + s += " /SD"; + Add_ButtonID(buttonID); + } + } + for (int i = 2; i < 6; i += 2) + if (params[i] != 0) + { + Add_ButtonID(params[i]); + Add_GotoVar1(params[i + 1]); + } + break; + } + + case EW_RMDIR: + { + UInt32 flag = params[1]; + if ((flag & DEL_RECURSE) != 0) + s += " /r"; + if ((flag & DEL_REBOOT) != 0) + s += k_REBOOTOK; + AddParam(params[0]); + break; + } + + case EW_STRCMP: + { + if (params[4] != 0) + s += 'S'; + AddParams(params, 2); + Add_GotoVars2(¶ms[2]); + break; + } + + case EW_READENVSTR: + { + s += (params[2] != 0) ? + "ReadEnvStr" : + "ExpandEnvStrings"; + AddParam_Var(params[0]); + AString temp; + ReadString2(temp, params[1]); + if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%') + { + temp.DeleteBack(); + temp.Delete(0); + } + SpaceQuStr(temp); + break; + } + + case EW_INTCMP: + { + s += "Int"; + const UInt32 param5 = params[5]; + if (param5 & 0x8000) + s += "64"; // v3.03+ + s += "Cmp"; + if (IsNsis3_OrHigher() ? (param5 & 1) : (param5 != 0)) + s += 'U'; + AddParams(params, 2); + Add_GotoVar1(params[2]); + if (params[3] != 0 || params[4] != 0) + Add_GotoVars2(params + 3); + break; + } + + case EW_INTOP: + { + AddParam_Var(params[0]); + const char * const kOps = "+-*/|&^!|&%<>>"; // NSIS 2.01+ + // "+-*/|&^!|&%"; // NSIS 2.0b4+ + // "+-*/|&^~!|&%"; // NSIS old + const UInt32 opIndex = params[3]; + const char c = (opIndex < 14) ? kOps[opIndex] : '?'; + const char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c; + const int numOps = (opIndex == 7) ? 1 : 2; + AddParam(params[1]); + if (numOps == 2 && c == '^' && IsDirectString_Equal(params[2], "0xFFFFFFFF")) + s += " ~ ;"; + Space(); + s += c; + if (numOps != 1) + { + if (opIndex == 13) // v3.03+ : operation ">>>" + s += c; + if (c2 != 0) + s += c2; + AddParam(params[2]); + } + break; + } + + case EW_INTFMT: + { + if (params[3]) + s += "Int64Fmt"; // v3.03+ + else + s += "IntFmt"; + AddParam_Var(params[0]); + AddParams(params + 1, 2); + break; + } + + case EW_PUSHPOP: + { + if (params[2] != 0) + { + s += "Exch"; + if (params[2] != 1) + AddParam_UInt(params[2]); + } + else if (params[1] != 0) + { + s += "Pop"; + AddParam_Var(params[0]); + } + else + { + if (NoLabels(labels + kkk + 1, 2) + && Get32(p + kCmdSize) == EW_PUSHPOP // Exch" + && GET_CMD_PARAM(p + kCmdSize, 2) == 1 + && Get32(p + kCmdSize * 2) == EW_PUSHPOP // Pop $VAR + && GET_CMD_PARAM(p + kCmdSize * 2, 1) != 0) + { + if (IsVarStr(params[0], GET_CMD_PARAM(p + kCmdSize * 2, 0))) + { + s += "Exch"; + AddParam(params[0]); + NewLine(); + Tab(true); + endCommentIndex = kkk + 3; + } + } + s += "Push"; + AddParam(params[0]); + } + break; + } + + case EW_FINDWINDOW: + { + AddParam_Var(params[0]); + AddParam(params[1]); + AddOptionalParams(params + 2, 3); + break; + } + + case EW_SENDMESSAGE: + { + // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2] + AddParam(params[1]); + + const char *w = NULL; + AString t; + ReadString2(t, params[2]); + UInt32 wm; + if (StringToUInt32(t, wm)) + { + switch (wm) + { + case 0x0C: w = "SETTEXT"; break; + case 0x10: w = "CLOSE"; break; + case 0x30: w = "SETFONT"; break; + } + } + if (w) + { + s += " ${WM_"; + s += w; + s += '}'; + } + else + SpaceQuStr(t); + + UInt32 spec = params[5]; + for (unsigned i = 0; i < 2; i++) + { + AString s2; + if (spec & ((UInt32)1 << i)) + s2 += "STR:"; + ReadString2(s2, params[3 + i]); + SpaceQuStr(s2); + } + + if ((Int32)params[0] >= 0) + AddParam_Var(params[0]); + + spec >>= 2; + if (spec != 0) + { + s += " /TIMEOUT="; + Add_UInt(spec); + } + break; + } + + case EW_ISWINDOW: + { + AddParam(params[0]); + Add_GotoVars2(¶ms[1]); + break; + } + + case EW_GETDLGITEM: + { + AddParam_Var(params[0]); + AddParams(params + 1, 2); + break; + } + + case EW_SETCTLCOLORS: + { + AddParam(params[0]); + + UInt32 offset = params[1]; + + if (_size < bhCtlColors.Offset + || _size - bhCtlColors.Offset < offset + || _size - bhCtlColors.Offset - offset < GET_CtlColors_SIZE(Is64Bit)) + { + AddError("bad offset"); + break; + } + + const Byte *p2 = _data + bhCtlColors.Offset + offset; + CNsis_CtlColors colors; + colors.Parse(p2, Is64Bit); + + if ((colors.flags & kColorsFlags_BK_SYS) != 0 || + (colors.flags & kColorsFlags_TEXT_SYS) != 0) + s += " /BRANDING"; + + AString bk; + bool bkc = false; + if (colors.bkmode == Z7_NSIS_WIN_TRANSPARENT) + bk += " transparent"; + else if (colors.flags & kColorsFlags_BKB) + { + if ((colors.flags & kColorsFlags_BK_SYS) == 0 && + (colors.flags & kColorsFlags_BK) != 0) + bkc = true; + } + if ((colors.flags & kColorsFlags_TEXT) != 0 || !bk.IsEmpty() || bkc) + { + Space(); + if ((colors.flags & kColorsFlags_TEXT_SYS) != 0 || (colors.flags & kColorsFlags_TEXT) == 0) + AddQuotes(); + else + Add_Color(colors.text); + } + s += bk; + if (bkc) + { + Space(); + Add_Color(colors.bkc); + } + + break; + } + + // case EW_LOADANDSETIMAGE: + case EW_SETBRANDINGIMAGE: + { + s += " /IMGID="; + Add_UInt(params[1]); + if (params[2] == 1) + s += " /RESIZETOFIT"; + AddParam(params[0]); + break; + } + + case EW_CREATEFONT: + { + AddParam_Var(params[0]); + AddParam(params[1]); + AddOptionalParams(params + 2, 2); + if (params[4] & 1) s += " /ITALIC"; + if (params[4] & 2) s += " /UNDERLINE"; + if (params[4] & 4) s += " /STRIKE"; + break; + } + + case EW_SHOWWINDOW: + { + AString hw, sw; + ReadString2(hw, params[0]); + ReadString2(sw, params[1]); + if (params[3] != 0) + s += "EnableWindow"; + else + { + UInt32 val; + bool valDefined = false; + if (StringToUInt32(sw, val)) + { + if (val < Z7_ARRAY_SIZE(kShowWindow_Commands)) + { + sw.Empty(); + sw += "${"; + Add_ShowWindow_Cmd_2(sw, val); + sw += '}'; + valDefined = true; + } + } + bool isHwndParent = IsVarStr(params[0], IsNsis225 ? kVar_HWNDPARENT_225 : kVar_HWNDPARENT); + if (params[2] != 0) + { + if (valDefined && val == 0 && isHwndParent) + { + s += "HideWindow"; + break; + } + } + if (valDefined && val == 5 && isHwndParent && + kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_BRINGTOFRONT) + { + s += " ; "; + } + s += "ShowWindow"; + } + SpaceQuStr(hw); + SpaceQuStr(sw); + break; + } + + case EW_SHELLEXEC: + { + AddParams(params, 2); + if (params[2] != 0 || params[3] != Z7_NSIS_WIN_SW_SHOWNORMAL) + { + AddParam(params[2]); + if (params[3] != Z7_NSIS_WIN_SW_SHOWNORMAL) + { + Space(); + Add_ShowWindow_Cmd(params[3]); + } + } + if (params[5] != 0) + { + s += " ;"; + AddParam(params[5]); // it's tatus text update + } + break; + } + + case EW_EXECUTE: + { + if (params[2] != 0) + s += "Wait"; + AddParam(params[0]); + if (params[2] != 0) + if ((Int32)params[1] >= 0) + AddParam_Var(params[1]); + break; + } + + case EW_GETFILETIME: + case EW_GETDLLVERSION: + { + if (commandId == EW_GETDLLVERSION) + if (params[3] == 2) + s += " /ProductVersion"; // v3.08+ + AddParam(params[2]); + AddParam_Var(params[0]); + AddParam_Var(params[1]); + break; + } + + case EW_REGISTERDLL: + { + AString func; + ReadString2(func, params[1]); + bool printFunc = true; + // params[4] = 1; for plugin command + if (params[2] == 0) + { + s += "CallInstDLL"; + AddParam(params[0]); + if (params[3] == 1) + s += " /NOUNLOAD"; + } + else + { + if (func == "DllUnregisterServer") + { + s += "UnRegDLL"; + printFunc = false; + } + else + { + s += "RegDLL"; + if (func == "DllRegisterServer") + printFunc = false; + } + AddParam(params[0]); + } + if (printFunc) + SpaceQuStr(func); + break; + } + + case EW_CREATESHORTCUT: + { + unsigned numParams; + #define IsNsis3d0b3_OrHigher() 0 // change it + const unsigned v3_0b3 = IsNsis3d0b3_OrHigher(); + for (numParams = 6; numParams > 2; numParams--) + if (params[numParams - 1] != 0) + break; + + const UInt32 spec = params[4]; + const unsigned sw_shift = v3_0b3 ? 12 : 8; + const UInt32 sw_mask = v3_0b3 ? 0x7000 : 0x7F; + if (spec & 0x8000) // NSIS 3.0b0 + s += " /NoWorkingDir"; + + AddParams(params, numParams > 4 ? 4 : numParams); + if (numParams <= 4) + break; + + UInt32 icon = (spec & (v3_0b3 ? 0xFFF : 0xFF)); + Space(); + if (icon != 0) + Add_UInt(icon); + else + AddQuotes(); + + if ((spec >> sw_shift) == 0 && numParams < 6) + break; + UInt32 sw = (spec >> sw_shift) & sw_mask; + Space(); + // NSIS encoder replaces these names: + if (sw == Z7_NSIS_WIN_SW_SHOWMINNOACTIVE) + sw = Z7_NSIS_WIN_SW_SHOWMINIMIZED; + if (sw == 0) + AddQuotes(); + else + Add_ShowWindow_Cmd(sw); + + UInt32 modKey = spec >> 24; + UInt32 key = (spec >> 16) & 0xFF; + + if (modKey == 0 && key == 0) + { + if (numParams < 6) + break; + Space(); + AddQuotes(); + } + else + { + Space(); + if (modKey & 1) s += "SHIFT|"; // HOTKEYF_SHIFT + if (modKey & 2) s += "CONTROL|"; + if (modKey & 4) s += "ALT|"; + if (modKey & 8) s += "EXT|"; + + const unsigned kMy_VK_F1 = 0x70; + if (key >= kMy_VK_F1 && key <= kMy_VK_F1 + 23) + { + s += 'F'; + Add_UInt(key - kMy_VK_F1 + 1); + } + else if ((key >= 'A' && key <= 'Z') || (key >= '0' && key <= '9')) + s += (char)key; + else + { + s += "Char_"; + Add_UInt(key); + } + } + AddOptionalParam(params[5]); // description + break; + } + + case EW_COPYFILES: + { + if (params[2] & 0x04) s += " /SILENT"; // FOF_SILENT + if (params[2] & 0x80) s += " /FILESONLY"; // FOF_FILESONLY + AddParams(params, 2); + if (params[3] != 0) + { + s += " ;"; + AddParam(params[3]); // status text update + } + break; + } + + case EW_REBOOT: + { + if (params[0] != 0xbadf00d) + s += " ; Corrupted ???"; + else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT) + endCommentIndex = kkk + 2; + break; + } + + case EW_WRITEINI: + { + unsigned numAlwaysParams = 0; + if (params[0] == 0) // Section + s += "FlushINI"; + else if (params[4] != 0) + { + s += "WriteINIStr"; + numAlwaysParams = 3; + } + else + { + s += "DeleteINI"; + s += (params[1] == 0) ? "Sec" : "Str"; + numAlwaysParams = 1; + } + AddParam(params[3]); // filename + // Section, EntryName, Value + AddParams(params, numAlwaysParams); + AddOptionalParams(params + numAlwaysParams, 3 - numAlwaysParams); + break; + } + + case EW_READINISTR: + { + AddParam_Var(params[0]); + AddParam(params[3]); // FileName + AddParams(params +1, 2); // Section, EntryName + break; + } + + case EW_DELREG: + { + // NSIS 2.00 used another scheme! + + if (params[4] == 0) + s += "Value"; + else + { + s += "Key"; + if (params[4] & 2) + s += " /ifempty"; + // TODO: /ifnosubkeys, /ifnovalues + } + AddRegRoot(params[1]); + AddParam(params[2]); + AddOptionalParam(params[3]); + break; + } + + case EW_WRITEREG: + { + const char *s2 = NULL; + switch (params[4]) + { + case 1: s2 = "Str"; break; + case 2: s2 = "ExpandStr"; break; // maybe unused + case 3: s2 = "Bin"; break; + case 4: s2 = "DWORD"; break; + default: + s += '?'; + Add_UInt(params[4]); + } + if (params[4] == 1 && params[5] == 2) + s2 = "ExpandStr"; + if (params[4] == 3 && params[5] == 7) + s2 = "MultiStr"; // v3.02+ + if (s2) + s += s2; + AddRegRoot(params[0]); + AddParams(params + 1, 2); // keyName, valueName + if (params[4] != 3) + AddParam(params[3]); // value + else + { + // Binary data. + Space(); + UInt32 offset = params[3]; + bool isSupported = false; + if (AfterHeaderSize >= 4 + && bhData.Offset <= AfterHeaderSize - 4 + && offset <= AfterHeaderSize - 4 - bhData.Offset) + { + // we support it for solid archives. + const Byte *p2 = _afterHeader + bhData.Offset + offset; + UInt32 size = Get32(p2); + if (size <= AfterHeaderSize - 4 - bhData.Offset - offset) + { + for (UInt32 i = 0; i < size; i++) + { + Byte b = (p2 + 4)[i]; + unsigned t; + t = (b >> 4); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + t = (b & 15); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); + } + isSupported = true; + } + } + if (!isSupported) + { + // we must read from file here; + s += "data["; + Add_UInt(offset); + s += " ... ]"; + s += " ; !!! Unsupported"; + } + } + break; + } + + case EW_READREGSTR: + { + s += (params[4] == 1) ? "DWORD" : "Str"; + AddParam_Var(params[0]); + AddRegRoot(params[1]); + AddParams(params + 2, 2); + break; + } + + case EW_REGENUM: + { + s += (params[4] != 0) ? "Key" : "Value"; + AddParam_Var(params[0]); + AddRegRoot(params[1]); + AddParams(params + 2, 2); + break; + } + + case EW_FCLOSE: + case EW_FINDCLOSE: + { + AddParam_Var(params[0]); + break; + } + + #endif + + case EW_FOPEN: + { + /* + the pattern for empty files is following: + FileOpen $0 "file_name" w + FileClose $0 + */ + + const UInt32 acc = params[1]; // dwDesiredAccess + const UInt32 creat = params[2]; // dwCreationDisposition + if (creat == Z7_NSIS_WIN_CREATE_ALWAYS && acc == Z7_NSIS_WIN_GENERIC_WRITE) + { + if (kkk + 1 < bh.Num) + if (Get32(p + kCmdSize) == EW_FCLOSE) + if (Get32(p + kCmdSize + 4) == params[0]) + { + CItem &item = Items.AddNew(); + item.IsEmptyFile = true; + SetItemName(item, params[3]); + } + } + + #ifdef NSIS_SCRIPT + + AddParam_Var(params[0]); + AddParam(params[3]); + if (acc == 0 && creat == 0) + break; + char cc = 0; + if (creat == Z7_NSIS_WIN_OPEN_EXISTING && acc == Z7_NSIS_WIN_GENERIC_READ) + cc = 'r'; + else if (creat == Z7_NSIS_WIN_CREATE_ALWAYS && acc == Z7_NSIS_WIN_GENERIC_WRITE) + cc = 'w'; + else if (creat == Z7_NSIS_WIN_OPEN_ALWAYS && (acc == (Z7_NSIS_WIN_GENERIC_WRITE | Z7_NSIS_WIN_GENERIC_READ))) + cc = 'a'; + // cc = 0; + if (cc != 0) + { + Space(); + s += cc; + break; + } + + if (acc & Z7_NSIS_WIN_GENERIC_READ) s += " GENERIC_READ"; + if (acc & Z7_NSIS_WIN_GENERIC_WRITE) s += " GENERIC_WRITE"; + if (acc & Z7_NSIS_WIN_GENERIC_EXECUTE) s += " GENERIC_EXECUTE"; + if (acc & Z7_NSIS_WIN_GENERIC_ALL) s += " GENERIC_ALL"; + + const char *s2 = NULL; + switch (creat) + { + case Z7_NSIS_WIN_CREATE_NEW: s2 = "CREATE_NEW"; break; + case Z7_NSIS_WIN_CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break; + case Z7_NSIS_WIN_OPEN_EXISTING: s2 = "OPEN_EXISTING"; break; + case Z7_NSIS_WIN_OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break; + case Z7_NSIS_WIN_TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break; + } + Space(); + if (s2) + s += s2; + else + Add_UInt(creat); + #endif + + break; + } + + #ifdef NSIS_SCRIPT + + case EW_FPUTS: + case EW_FPUTWS: + { + if (commandId == EW_FPUTWS) + s += (params[2] == 0) ? "UTF16LE" : "Word"; + else if (params[2] != 0) + s += "Byte"; + if (params[2] == 0 && params[3]) + s += " /BOM"; // v3.0b3+ + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + + case EW_FGETS: + case EW_FGETWS: + { + if (commandId == EW_FPUTWS) + s += (params[3] == 0) ? "UTF16LE" : "Word"; + if (params[3] != 0) + s += "Byte"; + AddParam_Var(params[0]); + AddParam_Var(params[1]); + AString maxLenStr; + ReadString2(maxLenStr, params[2]); + UInt32 maxLen; + if (StringToUInt32(maxLenStr, maxLen)) + { + if (maxLen == 1 && params[3] != 0) + break; + if (maxLen == 1023 && params[3] == 0) // NSIS_MAX_STRLEN - 1; can be other value!! + break; + } + SpaceQuStr(maxLenStr); + break; + } + + case EW_FSEEK: + { + AddParam_Var(params[0]); + AddParam(params[2]); + if (params[3] == 1) s += " CUR"; // FILE_CURRENT + if (params[3] == 2) s += " END"; // FILE_END + if ((Int32)params[1] >= 0) + { + if (params[3] == 0) s += " SET"; // FILE_BEGIN + AddParam_Var(params[1]); + } + break; + } + + case EW_FINDNEXT: + { + AddParam_Var(params[1]); + AddParam_Var(params[0]); + break; + } + + case EW_FINDFIRST: + { + AddParam_Var(params[1]); + AddParam_Var(params[0]); + AddParam(params[2]); + break; + } + + case EW_LOG: + { + if (params[0] != 0) + { + s += "Set "; + s += (params[1] == 0) ? "off" : "on"; + } + else + { + s += "Text"; + AddParam(params[1]); + } + break; + } + + case EW_SECTIONSET: + { + if ((Int32)params[2] >= 0) + { + s += "Get"; + Add_SectOp(params[2]); + AddParam(params[0]); + AddParam_Var(params[1]); + } + else + { + s += "Set"; + const UInt32 t = (UInt32)(-(Int32)params[2] - 1); + Add_SectOp(t); + AddParam(params[0]); + AddParam(params[t == 0 ? 4 : 1]); + + // params[3] != 0 means call SectionFlagsChanged in installer + // used by SECTIONSETFLAGS command + } + break; + } + + case EW_INSTTYPESET: + { + unsigned numQwParams = 0; + const char *s2; + if (params[3] == 0) + { + if (params[2] == 0) + { + s2 = "InstTypeGetText"; + numQwParams = 1; + } + else + { + s2 = "InstTypeSetText"; + numQwParams = 2; + } + } + else + { + if (params[2] == 0) + s2 = "GetCurInstType"; + else + { + s2 = "SetCurInstType"; + numQwParams = 1; + } + } + s += s2; + AddParams(params, numQwParams); + if (params[2] == 0) + AddParam_Var(params[1]); + break; + } + + case EW_GETOSINFO: + { + if (IsNsis3_OrHigher()) + { + // v3.06+ + if (params[3] == 0) // GETOSINFO_KNOWNFOLDER + { + s += "GetKnownFolderPath"; + AddParam_Var(params[1]); + AddParam(params[2]); + break; + } + else if (params[3] == 1) // GETOSINFO_READMEMORY + { + s += "ReadMemory"; + AddParam_Var(params[1]); + AddParam(params[2]); + AddParam(params[4]); + // if (params[2] == "0") AddCommentAndString("GetWinVer"); + } + else + s += "GetOsInfo"; + break; + } + s += "GetLabelAddr"; // before v3.06+ + break; + } + + case EW_LOCKWINDOW: + { + s += (params[0] == 0) ? " on" : " off"; + break; + } + + case EW_FINDPROC: + { + AddParam_Var(params[0]); + AddParam(params[1]); + break; + } + + default: + { + numSkipParams = 0; + } + #endif + } + + #ifdef NSIS_SCRIPT + + unsigned numParams = kNumCommandParams; + + for (; numParams > 0; numParams--) + if (params[numParams - 1] != 0) + break; + + if (numParams > numSkipParams) + { + s += " ; !!!! Unknown Params: "; + unsigned i; + for (i = 0; i < numParams; i++) + AddParam(params[i]); + + s += " ;"; + + for (i = 0; i < numParams; i++) + { + Space(); + UInt32 v = params[i]; + if (v > 0xFFF00000) + Add_SignedInt(s, (Int32)v); + else + Add_UInt(v); + } + } + + NewLine(); + + #endif + } + + #ifdef NSIS_SCRIPT + + if (sectionIsOpen) + { + if (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk) + { + PrintSectionEnd(); + sectionIsOpen = false; + // lastSectionEndCmd = kkk; + curSectionIndex++; + } + } + } + + while (curSectionIndex < bhSections.Num) + { + const CSection § = Sections[curSectionIndex]; + if (sectionIsOpen) + { + if (sect.StartCmdIndex + sect.NumCommands != kkk) + AddErrorLF("SECTION ERROR"); + PrintSectionEnd(); + sectionIsOpen = false; + curSectionIndex++; + } + else + { + if (PrintSectionBegin(sect, curSectionIndex)) + curSectionIndex++; + else + sectionIsOpen = true; + } + } + + #endif + + return S_OK; +} + +static int CompareItems(void *const *p1, void *const *p2, void *param) +{ + const CItem &i1 = **(const CItem *const *)p1; + const CItem &i2 = **(const CItem *const *)p2; + RINOZ(MyCompare(i1.Pos, i2.Pos)) + + /* In another code we check CItem::Pos after each solid item. + So here we place empty files before all non empty files */ + if (i1.IsEmptyFile) + { + if (!i2.IsEmptyFile) + return -1; + } + else if (i2.IsEmptyFile) + return 1; + + const CInArchive *inArchive = (const CInArchive *)param; + if (inArchive->IsUnicode) + { + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0) return -1; + if (i2.Prefix < 0) return 1; + RINOZ( + inArchive->UPrefixes[i1.Prefix].Compare( + inArchive->UPrefixes[i2.Prefix])) + } + RINOZ(i1.NameU.Compare(i2.NameU)) + } + else + { + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0) return -1; + if (i2.Prefix < 0) return 1; + RINOZ(strcmp( + inArchive->APrefixes[i1.Prefix], + inArchive->APrefixes[i2.Prefix])) + } + RINOZ(strcmp(i1.NameA, i2.NameA)) + } + return 0; +} + +HRESULT CInArchive::SortItems() +{ + { + Items.Sort(CompareItems, (void *)this); + unsigned i; + + for (i = 0; i + 1 < Items.Size(); i++) + { + const CItem &i1 = Items[i]; + if (i1.IsEmptyFile) + continue; + const CItem &i2 = Items[i + 1]; + if (i1.Pos != i2.Pos) + continue; + + if (IsUnicode) + { + if (i1.NameU != i2.NameU) continue; + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0 || i2.Prefix < 0) continue; + if (UPrefixes[i1.Prefix] != UPrefixes[i2.Prefix]) continue; + } + } + else + { + if (i1.NameA != i2.NameA) continue; + if (i1.Prefix != i2.Prefix) + { + if (i1.Prefix < 0 || i2.Prefix < 0) continue; + if (APrefixes[i1.Prefix] != APrefixes[i2.Prefix]) continue; + } + } + Items.Delete(i + 1); + i--; + } + + for (i = 0; i < Items.Size(); i++) + { + CItem &item = Items[i]; + if (item.IsEmptyFile) + continue; + const UInt32 curPos = item.Pos + 4; + for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++) + { + const CItem &nextItem = Items[nextIndex]; + // if (nextItem.IsEmptyFile) continue; + const UInt32 nextPos = nextItem.Pos; + if (curPos <= nextPos) + { + item.EstimatedSize_Defined = true; + item.EstimatedSize = nextPos - curPos; + break; + } + } + } + + if (!IsSolid) + { + for (i = 0; i < Items.Size(); i++) + { + CItem &item = Items[i]; + if (item.IsEmptyFile) + continue; + RINOK(SeekToNonSolidItem(i)) + const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict + BYTE sig[kSigSize]; + size_t processedSize = kSigSize; + RINOK(ReadStream(_stream, sig, &processedSize)) + if (processedSize < 4) + return S_FALSE; + UInt32 size = Get32(sig); + if ((size & kMask_IsCompressed) != 0) + { + item.IsCompressed = true; + size &= ~kMask_IsCompressed; + if (Method == NMethodType::kLZMA) + { + if (processedSize < 9) + return S_FALSE; + /* + if (FilterFlag) + item.UseFilter = (sig[4] != 0); + */ + item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0)); + } + } + else + { + item.IsCompressed = false; + item.Size = size; + item.Size_Defined = true; + } + item.CompressedSize = size; + item.CompressedSize_Defined = true; + } + } + } + return S_OK; +} + +#ifdef NSIS_SCRIPT +// Flags for common_header.flags +// #define CH_FLAGS_DETAILS_SHOWDETAILS 1 +// #define CH_FLAGS_DETAILS_NEVERSHOW 2 +#define CH_FLAGS_PROGRESS_COLORED 4 +#define CH_FLAGS_SILENT 8 +#define CH_FLAGS_SILENT_LOG 16 +#define CH_FLAGS_AUTO_CLOSE 32 +// #define CH_FLAGS_DIR_NO_SHOW 64 // unused now +#define CH_FLAGS_NO_ROOT_DIR 128 +#define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256 +#define CH_FLAGS_NO_CUSTOM 512 + +static const char * const k_PostStrings[] = +{ + "install_directory_auto_append" + , "uninstchild" // NSIS 2.25+, used by uninstaller: + , "uninstcmd" // NSIS 2.25+, used by uninstaller: + , "wininit" // NSIS 2.25+, used by move file on reboot +}; +#endif + + +void CBlockHeader::Parse(const Byte *p, unsigned bhoSize) +{ + if (bhoSize == 12) + { + // UInt64 a = GetUi64(p); + if (GetUi32(p + 4) != 0) + throw 1; + } + Offset = GetUi32(p); + Num = GetUi32(p + bhoSize - 4); +} + +#define PARSE_BH(k, bh) bh.Parse (p1 + 4 + bhoSize * k, bhoSize) + + +HRESULT CInArchive::Parse() +{ + // UInt32 offset = ReadUInt32(); + // ???? offset == FirstHeader.HeaderSize + const Byte * const p1 = _data; + + if (_size < 4 + 12 * 8) + Is64Bit = false; + else + { + Is64Bit = true; + // here we test high 32-bit of possible UInt64 CBlockHeader::Offset field + for (int k = 0; k < 8; k++) + if (GetUi32(p1 + 4 + 12 * k + 4) != 0) + Is64Bit = false; + } + + const unsigned bhoSize = Is64Bit ? 12 : 8; + if (_size < 4 + bhoSize * 8) + return S_FALSE; + + CBlockHeader bhEntries, bhStrings, bhLangTables; + + PARSE_BH (2, bhEntries); + PARSE_BH (3, bhStrings); + PARSE_BH (4, bhLangTables); + + #ifdef NSIS_SCRIPT + + CBlockHeader bhFont; + PARSE_BH (0, bhPages); + PARSE_BH (1, bhSections); + PARSE_BH (5, bhCtlColors); + PARSE_BH (6, bhFont); + PARSE_BH (7, bhData); + + #endif + + _stringsPos = bhStrings.Offset; + if (_stringsPos > _size + || bhLangTables.Offset > _size + || bhEntries.Offset > _size) + return S_FALSE; + { + if (bhLangTables.Offset < bhStrings.Offset) + return S_FALSE; + const UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset; + if (stringTableSize < 2) + return S_FALSE; + const Byte *strData = _data + _stringsPos; + if (strData[stringTableSize - 1] != 0) + return S_FALSE; + IsUnicode = (Get16(strData) == 0); + NumStringChars = stringTableSize; + if (IsUnicode) + { + if ((stringTableSize & 1) != 0) + return S_FALSE; + NumStringChars >>= 1; + if (strData[stringTableSize - 2] != 0) + return S_FALSE; + } + } + + if (bhEntries.Num > (1 << 25)) + return S_FALSE; + if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) + return S_FALSE; + + DetectNsisType(bhEntries, _data + bhEntries.Offset); + + Decoder.IsNsisDeflate = (NsisType != k_NsisType_Nsis3); + + // some NSIS files (that are not detected as k_NsisType_Nsis3) + // use original (non-NSIS) Deflate + // How to detect these cases? + + // Decoder.IsNsisDeflate = false; + + + #ifdef NSIS_SCRIPT + + { + AddCommentAndString("NSIS script"); + if (IsUnicode) + Script += " (UTF-8)"; + Space(); + Script += GetFormatDescription(); + AddLF(); + } + { + AddCommentAndString(IsInstaller ? "Install" : "Uninstall"); + AddLF(); + } + + AddLF(); + if (Is64Bit) + AddStringLF("Target AMD64-Unicode"); // TODO: Read PE machine type and use the correct CPU type + else if (IsUnicode) + AddStringLF("Unicode true"); + else if (IsNsis3_OrHigher()) + AddStringLF("Unicode false"); // Unicode is the default in 3.07+ + + if (Method != NMethodType::kCopy) + { + const char *m = NULL; + switch ((int)Method) + { + case NMethodType::kDeflate: m = "zlib"; break; + case NMethodType::kBZip2: m = "bzip2"; break; + case NMethodType::kLZMA: m = "lzma"; break; + default: break; + } + Script += "SetCompressor"; + if (IsSolid) + Script += " /SOLID"; + if (m) + { + Space(); + Script += m; + } + AddLF(); + } + if (Method == NMethodType::kLZMA) + { + // if (DictionarySize != (8 << 20)) + { + Script += "SetCompressorDictSize"; + AddParam_UInt(DictionarySize >> 20); + AddLF(); + } + } + + Separator(); + PrintNumComment("HEADER SIZE", FirstHeader.HeaderSize); + // if (bhPages.Offset != 300 && bhPages.Offset != 288) + if (bhPages.Offset != 0) + { + PrintNumComment("START HEADER SIZE", bhPages.Offset); + } + + if (bhSections.Num > 0) + { + if (bhEntries.Offset < bhSections.Offset) + return S_FALSE; + SectionSize = (bhEntries.Offset - bhSections.Offset) / bhSections.Num; + if (bhSections.Offset + bhSections.Num * SectionSize != bhEntries.Offset) + return S_FALSE; + if (SectionSize < kSectionSize_base) + return S_FALSE; + UInt32 maxStringLen = SectionSize - kSectionSize_base; + if (IsUnicode) + { + if ((maxStringLen & 1) != 0) + return S_FALSE; + maxStringLen >>= 1; + } + // if (maxStringLen != 1024) + { + if (maxStringLen == 0) + PrintNumComment("SECTION SIZE", SectionSize); + else + PrintNumComment("MAX STRING LENGTH", maxStringLen); + } + } + + PrintNumComment("STRING CHARS", NumStringChars); + // PrintNumComment("LANG TABLE SIZE", bhCtlColors.Offset - bhLangTables.Offset); + + if (bhCtlColors.Offset > _size) + AddErrorLF("Bad COLORS TABLE"); + // PrintNumComment("COLORS TABLE SIZE", bhFont.Offset - bhCtlColors.Offset); + if (bhCtlColors.Num != 0) + PrintNumComment("COLORS Num", bhCtlColors.Num); + + // bhData uses offset in _afterHeader (not in _data) + // PrintNumComment("FONT TABLE SIZE", bhData.Offset - bhFont.Offset); + if (bhFont.Num != 0) + PrintNumComment("FONTS Num", bhFont.Num); + + // PrintNumComment("DATA SIZE", FirstHeader.HeaderSize - bhData.Offset); + if (bhData.Num != 0) + PrintNumComment("DATA NUM", bhData.Num); + + AddLF(); + + AddStringLF("OutFile [NSIS].exe"); + AddStringLF("!include WinMessages.nsh"); + + AddLF(); + + strUsed.Alloc(NumStringChars); + memset(strUsed, 0, NumStringChars); + + { + UInt32 ehFlags = Get32(p1); + UInt32 showDetails = ehFlags & 3;// CH_FLAGS_DETAILS_SHOWDETAILS & CH_FLAGS_DETAILS_NEVERSHOW; + if (showDetails >= 1 && showDetails <= 2) + { + Script += IsInstaller ? "ShowInstDetails" : "ShowUninstDetails"; + Script += (showDetails == 1) ? " show" : " nevershow"; + AddLF(); + } + if (ehFlags & CH_FLAGS_PROGRESS_COLORED) AddStringLF("InstProgressFlags colored" ); + if ((ehFlags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG)) != 0) + { + Script += IsInstaller ? "SilentInstall " : "SilentUnInstall "; + Script += (ehFlags & CH_FLAGS_SILENT_LOG) ? "silentlog" : "silent"; + AddLF(); + } + if (ehFlags & CH_FLAGS_AUTO_CLOSE) AddStringLF("AutoCloseWindow true"); + if ((ehFlags & CH_FLAGS_NO_ROOT_DIR) == 0) AddStringLF("AllowRootDirInstall true"); + if (ehFlags & CH_FLAGS_NO_CUSTOM) AddStringLF("InstType /NOCUSTOM"); + if (ehFlags & CH_FLAGS_COMP_ONLY_ON_CUSTOM) AddStringLF("InstType /COMPONENTSONLYONCUSTOM"); + } + + // Separator(); + // AddLF(); + + Int32 licenseLangIndex = -1; + { + const Byte *pp = _data + bhPages.Offset; + + for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, pp += kPageSize) + { + UInt32 wndProcID = Get32(pp + 4); + UInt32 param1 = Get32(pp + 44 + 4 * 1); + if (wndProcID != PWP_LICENSE || param1 == 0) + continue; + if ((Int32)param1 < 0) + licenseLangIndex = - ((Int32)param1 + 1); + else + noParseStringIndexes.AddToUniqueSorted(param1); + } + } + + unsigned paramsOffset; + { + unsigned numBhs = 8; + // probably its for old NSIS? + if (bhoSize == 8 && bhPages.Offset == 276) + numBhs = 7; + paramsOffset = 4 + bhoSize * numBhs; + } + + const Byte *p2 = p1 + paramsOffset; + + { + UInt32 rootKey = Get32(p2); // (rootKey = -1) in uninstaller by default (the bug in NSIS) + UInt32 subKey = Get32(p2 + 4); + UInt32 value = Get32(p2 + 8); + if ((rootKey != 0 && rootKey != (UInt32)(Int32)-1) || subKey != 0 || value != 0) + { + Script += "InstallDirRegKey"; + AddRegRoot(rootKey); + AddParam(subKey); + AddParam(value); + AddLF(); + } + } + + + { + UInt32 bg_color1 = Get32(p2 + 12); + UInt32 bg_color2 = Get32(p2 + 16); + UInt32 bg_textcolor = Get32(p2 + 20); + if (bg_color1 != (UInt32)(Int32)-1 || bg_color2 != (UInt32)(Int32)-1 || bg_textcolor != (UInt32)(Int32)-1) + { + Script += "BGGradient"; + if (bg_color1 != 0 || bg_color2 != 0xFF0000 || bg_textcolor != (UInt32)(Int32)-1) + { + Add_ColorParam(bg_color1); + Add_ColorParam(bg_color2); + if (bg_textcolor != (UInt32)(Int32)-1) + Add_ColorParam(bg_textcolor); + } + AddLF(); + } + } + + { + UInt32 lb_bg = Get32(p2 + 24); + UInt32 lb_fg = Get32(p2 + 28); + if ((lb_bg != (UInt32)(Int32)-1 || lb_fg != (UInt32)(Int32)-1) && + (lb_bg != 0 || lb_fg != 0xFF00)) + { + Script += "InstallColors"; + Add_ColorParam(lb_fg); + Add_ColorParam(lb_bg); + AddLF(); + } + } + + UInt32 license_bg = Get32(p2 + 36); + if (license_bg != (UInt32)(Int32)-1 && + license_bg != (UInt32)(Int32)-15) // COLOR_BTNFACE + { + Script += "LicenseBkColor"; + if ((Int32)license_bg == -5) // COLOR_WINDOW + Script += " /windows"; + /* + else if ((Int32)license_bg == -15) + Script += " /grey"; + */ + else + Add_ColorParam(license_bg); + AddLF(); + } + + if (bhLangTables.Num > 0) + { + const UInt32 langtable_size = Get32(p2 + 32); + + if (langtable_size == (UInt32)(Int32)-1) + return E_NOTIMPL; // maybe it's old NSIS archive() + + if (langtable_size < 10) + return S_FALSE; + if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size) + return S_FALSE; + + const UInt32 numStrings = (langtable_size - 10) / 4; + _numLangStrings = numStrings; + AddLF(); + Separator(); + PrintNumComment("LANG TABLES", bhLangTables.Num); + PrintNumComment("LANG STRINGS", numStrings); + AddLF(); + + if (licenseLangIndex >= 0 && (unsigned)licenseLangIndex < numStrings) + { + for (UInt32 i = 0; i < bhLangTables.Num; i++) + { + const Byte * const p = _data + bhLangTables.Offset + langtable_size * i; + const UInt16 langID = Get16(p); + UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4); + if (val != 0) + { + Script += "LicenseLangString "; + Add_LangStr_Simple((UInt32)licenseLangIndex); + AddParam_UInt(langID); + AddLicense(val, langID); + noParseStringIndexes.AddToUniqueSorted(val); + NewLine(); + } + } + AddLF(); + } + + UInt32 names[3] = { 0 }; + + UInt32 i; + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte * const p = _data + bhLangTables.Offset + langtable_size * i; + const UInt16 langID = Get16(p); + if (i == 0 || langID == 1033) + _mainLang = p + 10; + for (unsigned k = 0; k < Z7_ARRAY_SIZE(names) && k < numStrings; k++) + { + UInt32 v = Get32(p + 10 + k * 4); + if (v != 0 && (langID == 1033 || names[k] == 0)) + names[k] = v; + } + } + + const UInt32 name = names[2]; + if (name != 0) + { + Script += "Name"; + AddParam(name); + NewLine(); + + ReadString2(Name, name); + } + + /* + const UInt32 caption = names[1]; + if (caption != 0) + { + Script += "Caption"; + AddParam(caption); + NewLine(); + } + */ + + const UInt32 brandingText = names[0]; + if (brandingText != 0) + { + Script += "BrandingText"; + AddParam(brandingText); + NewLine(); + + ReadString2(BrandingText, brandingText); + } + + for (i = 0; i < bhLangTables.Num; i++) + { + const Byte * const p = _data + bhLangTables.Offset + langtable_size * i; + const UInt16 langID = Get16(p); + + AddLF(); + AddCommentAndString("LANG:"); + AddParam_UInt(langID); + /* + Script += " ("; + LangId_To_String(Script, langID); + Script += ')'; + */ + AddLF(); + // UInt32 dlg_offset = Get32(p + 2); + // UInt32 g_exec_flags_rtl = Get32(p + 6); + + + for (UInt32 j = 0; j < numStrings; j++) + { + UInt32 val = Get32(p + 10 + j * 4); + if (val != 0) + { + if ((Int32)j != licenseLangIndex) + { + Script += "LangString "; + Add_LangStr_Simple(j); + AddParam_UInt(langID); + AddParam(val); + AddLF(); + } + } + } + AddLF(); + } + ClearLangComment(); + } + + { + unsigned numInternalVars = GET_NUM_INTERNAL_VARS; + UInt32 numUsedVars = GetNumUsedVars(); + if (numUsedVars > numInternalVars) + { + Separator(); + PrintNumComment("VARIABLES", numUsedVars - numInternalVars); + AddLF(); + AString temp; + for (UInt32 i = numInternalVars; i < numUsedVars; i++) + { + Script += "Var "; + temp.Empty(); + GetVar2(temp, i); + AddStringLF(temp); + } + AddLF(); + } + } + + onFuncOffset = paramsOffset + 40; + numOnFunc = Z7_ARRAY_SIZE(kOnFunc); + if (bhPages.Offset == 276) + numOnFunc--; + p2 += 40 + numOnFunc * 4; + + #define NSIS_MAX_INST_TYPES 32 + + AddLF(); + + UInt32 i; + for (i = 0; i < NSIS_MAX_INST_TYPES + 1; i++, p2 += 4) + { + UInt32 instType = Get32(p2); + if (instType != 0) + { + Script += "InstType"; + AString s2; + if (!IsInstaller) + s2 += "un."; + ReadString2(s2, instType); + SpaceQuStr(s2); + NewLine(); + } + } + + { + UInt32 installDir = Get32(p2); + p2 += 4; + if (installDir != 0) + { + Script += "InstallDir"; + AddParam(installDir); + NewLine(); + } + } + + if (bhPages.Offset >= 288) + for (i = 0; i < 4; i++) + { + if (i != 0 && bhPages.Offset < 300) + break; + UInt32 param = Get32(p2 + 4 * i); + if (param == 0 || param == (UInt32)(Int32)-1) + continue; + + /* + uninstaller: + UInt32 uninstChild = Get32(p2 + 8); // "$TEMP\\$1u_.exe" + UInt32 uninstCmd = Get32(p2 + 12); // "\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\" + int str_wininit = Get32(p2 + 16); // "$WINDIR\\wininit.ini" + */ + + AddCommentAndString(k_PostStrings[i]); + Script += " ="; + AddParam(param); + NewLine(); + } + + AddLF(); + + #endif + + RINOK(ReadEntries(bhEntries)) + + #ifdef NSIS_SCRIPT + + Separator(); + AddCommentAndString("UNREFERENCED STRINGS:"); + AddLF(); + AddLF(); + CommentOpen(); + + for (i = 0; i < NumStringChars;) + { + if (!strUsed[i] && i != 0) + // Script += "!!! "; + { + Add_UInt(i); + AddParam(i); + NewLine(); + } + if (IsUnicode) + i += GetUi16Str_Len((const Byte *)_data + _stringsPos + i * 2); + else + i += (UInt32)strlen((const char *)(const Byte *)_data + _stringsPos + i); + i++; + } + CommentClose(); + #endif + + return SortItems(); +} + +static bool IsLZMA(const Byte *p, UInt32 &dictionary) +{ + dictionary = Get32(p + 1); + return (p[0] == 0x5D && + p[1] == 0x00 && p[2] == 0x00 && + p[5] == 0x00 && (p[6] & 0x80) == 0x00); +} + +static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag) +{ + if (IsLZMA(p, dictionary)) + { + thereIsFlag = false; + return true; + } + if (p[0] <= 1 && IsLZMA(p + 1, dictionary)) + { + thereIsFlag = true; + return true; + } + return false; +} + +static bool IsBZip2(const Byte *p) +{ + return (p[0] == 0x31 && p[1] < 14); +} + +HRESULT CInArchive::Open2(const Byte *sig, size_t size) +{ + const UInt32 kSigSize = 4 + 1 + 5 + 2; // size, flag, 5 - lzma props, 2 - lzma first bytes + if (size < kSigSize) + return S_FALSE; + + _headerIsCompressed = true; + IsSolid = true; + FilterFlag = false; + UseFilter = false; + DictionarySize = 1; + + #ifdef NSIS_SCRIPT + AfterHeaderSize = 0; + #endif + + UInt32 compressedHeaderSize = Get32(sig); + + + /* + XX XX XX XX XX XX XX XX == FirstHeader.HeaderSize, nonsolid, uncompressed + 5D 00 00 dd dd 00 solid LZMA + 00 5D 00 00 dd dd 00 solid LZMA, empty filter (there are no such archives) + 01 5D 00 00 dd dd 00 solid LZMA, BCJ filter (only 7-Zip installer used that format) + + SS SS SS 80 00 5D 00 00 dd dd 00 non-solid LZMA, empty filter + SS SS SS 80 01 5D 00 00 dd dd 00 non-solid LZMA, BCJ filte + SS SS SS 80 01 tt non-solid BZip (tt < 14 + SS SS SS 80 non-solid deflate + + 01 tt solid BZip (tt < 14 + other solid Deflate + */ + + if (compressedHeaderSize == FirstHeader.HeaderSize) + { + _headerIsCompressed = false; + IsSolid = false; + Method = NMethodType::kCopy; + } + else if (IsLZMA(sig, DictionarySize, FilterFlag)) + Method = NMethodType::kLZMA; + else if (sig[3] == 0x80) + { + IsSolid = false; + if (IsLZMA(sig + 4, DictionarySize, FilterFlag) && sig[3] == 0x80) + Method = NMethodType::kLZMA; + else if (IsBZip2(sig + 4)) + Method = NMethodType::kBZip2; + else + Method = NMethodType::kDeflate; + } + else if (IsBZip2(sig)) + Method = NMethodType::kBZip2; + else + Method = NMethodType::kDeflate; + + if (IsSolid) + { + RINOK(SeekTo_DataStreamOffset()) + } + else + { + _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0); + compressedHeaderSize &= ~kMask_IsCompressed; + _nonSolidStartOffset = compressedHeaderSize; + RINOK(SeekTo(DataStreamOffset + 4)) + } + + if (FirstHeader.HeaderSize == 0) + return S_FALSE; + + _data.Alloc(FirstHeader.HeaderSize); + _size = (size_t)FirstHeader.HeaderSize; + + Decoder.Method = Method; + Decoder.FilterFlag = FilterFlag; + Decoder.Solid = IsSolid; + + Decoder.IsNsisDeflate = true; // we need some smart check that NSIS is not NSIS3 here. + + Decoder.InputStream = _stream; + Decoder.Buffer.Alloc(kInputBufSize); + Decoder.StreamPos = 0; + + if (_headerIsCompressed) + { + RINOK(Decoder.Init(_stream, UseFilter)) + if (IsSolid) + { + size_t processedSize = 4; + Byte buf[4]; + RINOK(Decoder.Read(buf, &processedSize)) + if (processedSize != 4) + return S_FALSE; + if (Get32((const Byte *)buf) != FirstHeader.HeaderSize) + return S_FALSE; + } + { + size_t processedSize = FirstHeader.HeaderSize; + RINOK(Decoder.Read(_data, &processedSize)) + if (processedSize != FirstHeader.HeaderSize) + return S_FALSE; + } + + #ifdef NSIS_SCRIPT + if (IsSolid) + { + /* we need additional bytes for data for WriteRegBin */ + AfterHeaderSize = (1 << 12); + _afterHeader.Alloc(AfterHeaderSize); + size_t processedSize = AfterHeaderSize; + RINOK(Decoder.Read(_afterHeader, &processedSize)) + AfterHeaderSize = (UInt32)processedSize; + } + #endif + } + else + { + size_t processedSize = FirstHeader.HeaderSize; + RINOK(ReadStream(_stream, (Byte *)_data, &processedSize)) + if (processedSize < FirstHeader.HeaderSize) + return S_FALSE; + } + + #ifdef NUM_SPEED_TESTS + for (unsigned i = 0; i < NUM_SPEED_TESTS; i++) + { + RINOK(Parse()); + Clear2(); + } + #endif + + return Parse(); +} + +/* +NsisExe = +{ + ExeStub + Archive // must start from 512 * N + #ifndef NSIS_CONFIG_CRC_ANAL + { + Some additional data + } +} + +Archive +{ + FirstHeader + Data + #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc() + { + CRC + } +} + +FirstHeader +{ + UInt32 Flags; + Byte Signature[16]; + // points to the header+sections+entries+stringtable in the datablock + UInt32 HeaderSize; + UInt32 ArcSize; +} +*/ + + +// ---------- PE (EXE) parsing ---------- + +static const unsigned k_PE_StartSize = 0x40; +static const unsigned k_PE_HeaderSize = 4 + 20; +static const unsigned k_PE_OptHeader32_Size_MIN = 96; + +static inline bool CheckPeOffset(UInt32 pe) +{ + return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0); +} + + +static bool IsArc_Pe(const Byte *p, size_t size) +{ + if (size < 2) + return false; + if (p[0] != 'M' || p[1] != 'Z') + return false; + if (size < k_PE_StartSize) + return false; // k_IsArc_Res_NEED_MORE; + UInt32 pe = Get32(p + 0x3C); + if (!CheckPeOffset(pe)) + return false; + if (pe + k_PE_HeaderSize > size) + return false; // k_IsArc_Res_NEED_MORE; + + p += pe; + if (Get32(p) != 0x00004550) + return false; + return Get16(p + 4 + 16) >= k_PE_OptHeader32_Size_MIN; +} + +HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition) +{ + Clear(); + + RINOK(InStream_GetPos(inStream, StartOffset)) + + const UInt32 kStartHeaderSize = 4 * 7; + const unsigned kStep = 512; // nsis start is aligned for 512 + Byte buf[kStep]; + UInt64 pos = StartOffset; + size_t bufSize = 0; + UInt64 pePos = (UInt64)(Int64)-1; + + for (;;) + { + bufSize = kStep; + RINOK(ReadStream(inStream, buf, &bufSize)) + if (bufSize < kStartHeaderSize) + return S_FALSE; + if (memcmp(buf + 4, kSignature, kSignatureSize) == 0) + break; + if (IsArc_Pe(buf, bufSize)) + pePos = pos; + pos += kStep; + UInt64 proc = pos - StartOffset; + if (maxCheckStartPosition && proc > *maxCheckStartPosition) + { + if (pePos == 0) + { + if (proc > (1 << 20)) + return S_FALSE; + } + else + return S_FALSE; + } + } + + if (pePos == (UInt64)(Int64)-1) + { + UInt64 posCur = StartOffset; + for (;;) + { + if (posCur < kStep) + break; + posCur -= kStep; + if (pos - posCur > (1 << 20)) + break; + bufSize = kStep; + RINOK(InStream_SeekSet(inStream, posCur)) + RINOK(ReadStream(inStream, buf, &bufSize)) + if (bufSize < kStep) + break; + if (IsArc_Pe(buf, bufSize)) + { + pePos = posCur; + break; + } + } + + // restore buf to nsis header + bufSize = kStep; + RINOK(InStream_SeekSet(inStream, pos)) + RINOK(ReadStream(inStream, buf, &bufSize)) + if (bufSize < kStartHeaderSize) + return S_FALSE; + } + + StartOffset = pos; + UInt32 peSize = 0; + + if (pePos != (UInt64)(Int64)-1) + { + UInt64 peSize64 = (pos - pePos); + if (peSize64 < (1 << 20)) + { + peSize = (UInt32)peSize64; + StartOffset = pePos; + } + } + + DataStreamOffset = pos + kStartHeaderSize; + FirstHeader.Flags = Get32(buf); + if ((FirstHeader.Flags & (~kFlagsMask)) != 0) + { + // return E_NOTIMPL; + return S_FALSE; + } + IsInstaller = (FirstHeader.Flags & NFlags::kUninstall) == 0; + + FirstHeader.HeaderSize = Get32(buf + kSignatureSize + 4); + FirstHeader.ArcSize = Get32(buf + kSignatureSize + 8); + if (FirstHeader.ArcSize <= kStartHeaderSize) + return S_FALSE; + + /* + if ((FirstHeader.Flags & NFlags::k_BI_ExternalFileSupport) != 0) + { + UInt32 datablock_low = Get32(buf + kSignatureSize + 12); + UInt32 datablock_high = Get32(buf + kSignatureSize + 16); + } + */ + + RINOK(InStream_GetSize_SeekToEnd(inStream, _fileSize)) + + IsArc = true; + + if (peSize != 0) + { + ExeStub.Alloc(peSize); + RINOK(InStream_SeekSet(inStream, pePos)) + RINOK(ReadStream_FALSE(inStream, ExeStub, peSize)) + } + + HRESULT res = S_FALSE; + try + { + CLimitedInStream *_limitedStreamSpec = new CLimitedInStream; + _stream = _limitedStreamSpec; + _limitedStreamSpec->SetStream(inStream); + _limitedStreamSpec->InitAndSeek(pos, FirstHeader.ArcSize); + DataStreamOffset -= pos; + res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize); + } + catch(...) + { + _stream.Release(); + throw; + // res = S_FALSE; + } + if (res != S_OK) + { + _stream.Release(); + // Clear(); + } + return res; +} + +UString CInArchive::ConvertToUnicode(const AString &s) const +{ + if (IsUnicode) + { + UString res; + // if ( + ConvertUTF8ToUnicode(s, res); + return res; + } + return MultiByteToUnicodeString(s); +} + +void CInArchive::Clear2() +{ + IsUnicode = false; + NsisType = k_NsisType_Nsis2; + IsNsis225 = false; + IsNsis200 = false; + LogCmdIsEnabled = false; + BadCmd = -1; + Is64Bit = false; + + #ifdef NSIS_SCRIPT + Name.Empty(); + BrandingText.Empty(); + Script.Empty(); + LicenseFiles.Clear(); + _numRootLicenses = 0; + _numLangStrings = 0; + langStrIDs.Clear(); + LangComment.Empty(); + noParseStringIndexes.Clear(); + #endif + + APrefixes.Clear(); + UPrefixes.Clear(); + Items.Clear(); + IsUnicode = false; + ExeStub.Free(); +} + +void CInArchive::Clear() +{ + Clear2(); + IsArc = false; + _stream.Release(); +} + +}} diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index 60cba19f0..1f8c96755 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -1,458 +1,458 @@ -// NsisIn.h - -#ifndef ZIP7_INC_ARCHIVE_NSIS_IN_H -#define ZIP7_INC_ARCHIVE_NSIS_IN_H - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/DynLimBuf.h" -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyCom.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../Common/StreamUtils.h" - -#include "NsisDecode.h" - -/* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file. - The code is much larger in that case. */ - -// #define NSIS_SCRIPT - -namespace NArchive { -namespace NNsis { - -const size_t kScriptSizeLimit = 1 << 27; - -const unsigned kSignatureSize = 16; -extern const Byte kSignature[kSignatureSize]; -#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 'N', 'u', 'l', 'l', 's', 'o', 'f', 't', 'I', 'n', 's', 't' } - -const UInt32 kFlagsMask = 0xF; -namespace NFlags -{ - const UInt32 kUninstall = 1; - const UInt32 kSilent = 2; - const UInt32 kNoCrc = 4; - const UInt32 kForceCrc = 8; - // NSISBI fork flags: - const UInt32 k_BI_LongOffset = 16; - const UInt32 k_BI_ExternalFileSupport = 32; - const UInt32 k_BI_ExternalFile = 64; - const UInt32 k_BI_IsStubInstaller = 128; -} - -struct CFirstHeader -{ - UInt32 Flags; - UInt32 HeaderSize; - UInt32 ArcSize; - - bool ThereIsCrc() const - { - return - (Flags & NFlags::kForceCrc) != 0 || - (Flags & NFlags::kNoCrc) == 0; - } - - UInt32 GetDataSize() const { return ArcSize - (ThereIsCrc() ? 4 : 0); } -}; - - -struct CBlockHeader -{ - UInt32 Offset; - UInt32 Num; - - void Parse(const Byte *p, unsigned bhoSize); -}; - -struct CItem -{ - bool IsEmptyFile; - bool IsCompressed; - bool Size_Defined; - bool CompressedSize_Defined; - bool EstimatedSize_Defined; - bool Attrib_Defined; - bool IsUninstaller; - // bool UseFilter; - - UInt32 Attrib; - UInt32 Pos; // = 0, if (IsEmptyFile == true) - UInt32 Size; - UInt32 CompressedSize; - UInt32 EstimatedSize; - UInt32 DictionarySize; - UInt32 PatchSize; // for Uninstaller.exe - int Prefix; // - 1 means no prefix - - FILETIME MTime; - AString NameA; - UString NameU; - - bool Is_PatchedUninstaller() const { return PatchSize != 0; } - - CItem(): - IsEmptyFile(false), - IsCompressed(true), - Size_Defined(false), - CompressedSize_Defined(false), - EstimatedSize_Defined(false), - Attrib_Defined(false), - IsUninstaller(false), - // UseFilter(false), - Attrib(0), - Pos(0), - Size(0), - CompressedSize(0), - EstimatedSize(0), - DictionarySize(1), - PatchSize(0), - Prefix(-1) - { - MTime.dwLowDateTime = 0; - MTime.dwHighDateTime = 0; - } - - /* - bool IsINSTDIR() const - { - return (PrefixA.Len() >= 3 || PrefixU.Len() >= 3); - } - */ -}; - -enum ENsisType -{ - k_NsisType_Nsis2, - k_NsisType_Nsis3, - k_NsisType_Park1, // Park 2.46.1- - k_NsisType_Park2, // Park 2.46.2 : GetFontVersion - k_NsisType_Park3 // Park 2.46.3+ : GetFontName -}; - -#ifdef NSIS_SCRIPT - -struct CSection -{ - UInt32 InstallTypes; // bits set for each of the different install_types, if any. - UInt32 Flags; // SF_* - defined above - UInt32 StartCmdIndex; // code; - UInt32 NumCommands; // code_size; - UInt32 SizeKB; - UInt32 Name; - - void Parse(const Byte *data); -}; - -struct CLicenseFile -{ - UInt32 Offset; - UInt32 Size; - AString Name; - CByteBuffer Text; -}; - -#endif - -class CInArchive -{ -public: - #ifdef NSIS_SCRIPT - CDynLimBuf Script; - #endif - CByteBuffer _data; - CObjectVector Items; - bool IsUnicode; - bool Is64Bit; -private: - UInt32 _stringsPos; // relative to _data - UInt32 NumStringChars; - size_t _size; // it's Header Size - - AString Raw_AString; - UString Raw_UString; - - ENsisType NsisType; - bool IsNsis200; // NSIS 2.03 and before - bool IsNsis225; // NSIS 2.25 and before - bool LogCmdIsEnabled; - int BadCmd; // -1: no bad command; in another cases lowest bad command id - - bool IsPark() const { return NsisType >= k_NsisType_Park1; } - bool IsNsis3_OrHigher() const { return NsisType == k_NsisType_Nsis3; } - - UInt64 _fileSize; - - bool _headerIsCompressed; - UInt32 _nonSolidStartOffset; - - #ifdef NSIS_SCRIPT - - CByteBuffer strUsed; - - CBlockHeader bhPages; - CBlockHeader bhSections; - CBlockHeader bhCtlColors; - CBlockHeader bhData; - UInt32 AfterHeaderSize; - CByteBuffer _afterHeader; - - UInt32 SectionSize; - const Byte *_mainLang; - UInt32 _numLangStrings; - AString LangComment; - CRecordVector langStrIDs; - UInt32 numOnFunc; - UInt32 onFuncOffset; - // CRecordVector OnFuncs; - unsigned _numRootLicenses; - CRecordVector noParseStringIndexes; - AString _tempString_for_GetVar; - AString _tempString_for_AddFuncName; - AString _tempString; - - #endif - - -public: - CMyComPtr _stream; // it's limited stream that contains only NSIS archive - UInt64 StartOffset; // offset in original stream. - UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream - - bool IsArc; - - CDecoder Decoder; - CByteBuffer ExeStub; - CFirstHeader FirstHeader; - NMethodType::EEnum Method; - UInt32 DictionarySize; - bool IsSolid; - bool UseFilter; - bool FilterFlag; - - bool IsInstaller; - AString Name; - AString BrandingText; - UStringVector UPrefixes; - AStringVector APrefixes; - - #ifdef NSIS_SCRIPT - CObjectVector LicenseFiles; - #endif - -private: - void GetShellString(AString &s, unsigned index1, unsigned index2); - void GetNsisString_Raw(const Byte *s); - void GetNsisString_Unicode_Raw(const Byte *s); - void ReadString2_Raw(UInt32 pos); - bool IsGoodString(UInt32 param) const; - bool AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const; - - void Add_LangStr(AString &res, UInt32 id); - - #ifdef NSIS_SCRIPT - - void Add_UInt(UInt32 v); - void AddLicense(UInt32 param, Int32 langID); - - void Add_LangStr_Simple(UInt32 id); - void Add_FuncName(const UInt32 *labels, UInt32 index); - void AddParam_Func(const UInt32 *labels, UInt32 index); - void Add_LabelName(UInt32 index); - - void Add_Color2(UInt32 v); - void Add_ColorParam(UInt32 v); - void Add_Color(UInt32 index); - - void Add_ButtonID(UInt32 buttonID); - - void Add_ShowWindow_Cmd(UInt32 cmd); - void Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type); - void Add_ExecFlags(UInt32 flagsType); - void Add_SectOp(UInt32 opType); - - void Add_Var(UInt32 index); - void AddParam_Var(UInt32 value); - void AddParam_UInt(UInt32 value); - - void Add_GotoVar(UInt32 param); - void Add_GotoVar1(UInt32 param); - void Add_GotoVars2(const UInt32 *params); - - - - bool PrintSectionBegin(const CSection §, unsigned index); - void PrintSectionEnd(); - - void GetNsisString(AString &res, const Byte *s); - void GetNsisString_Unicode(AString &res, const Byte *s); - UInt32 GetNumUsedVars() const; - void ReadString2(AString &s, UInt32 pos); - - void MessageBox_MB_Part(UInt32 param); - void AddParam(UInt32 pos); - void AddOptionalParam(UInt32 pos); - void AddParams(const UInt32 *params, unsigned num); - void AddPageOption1(UInt32 param, const char *name); - void AddPageOption(const UInt32 *params, unsigned num, const char *name); - void AddOptionalParams(const UInt32 *params, unsigned num); - void AddRegRoot(UInt32 value); - - - void ClearLangComment(); - void Separator(); - void Space(); - void Tab(); - void Tab(bool commented); - void BigSpaceComment(); - void SmallSpaceComment(); - void AddCommentAndString(const char *s); - void AddError(const char *s); - void AddErrorLF(const char *s); - void CommentOpen(); - void CommentClose(); - void AddLF(); - void AddQuotes(); - void TabString(const char *s); - void AddStringLF(const char *s); - void NewLine(); - void PrintNumComment(const char *name, UInt32 value); - void Add_QuStr(const AString &s); - void SpaceQuStr(const AString &s); - bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands); - - #endif - - #ifdef NSIS_SCRIPT - unsigned GetNumSupportedCommands() const; - #endif - - UInt32 GetCmd(UInt32 a); - void FindBadCmd(const CBlockHeader &bh, const Byte *); - void DetectNsisType(const CBlockHeader &bh, const Byte *); - - HRESULT ReadEntries(const CBlockHeader &bh); - HRESULT SortItems(); - HRESULT Parse(); - HRESULT Open2(const Byte *data, size_t size); - void Clear2(); - - void GetVar2(AString &res, UInt32 index); - void GetVar(AString &res, UInt32 index); - Int32 GetVarIndex(UInt32 strPos) const; - Int32 GetVarIndex(UInt32 strPos, UInt32 &resOffset) const; - Int32 GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const; - bool IsVarStr(UInt32 strPos, UInt32 varIndex) const; - bool IsAbsolutePathVar(UInt32 strPos) const; - void SetItemName(CItem &item, UInt32 strPos); - -public: - HRESULT Open(IInStream *inStream, const UInt64 *maxCheckStartPosition); - AString GetFormatDescription() const; - HRESULT InitDecoder() - { - bool useFilter; - return Decoder.Init(_stream, useFilter); - } - - HRESULT SeekTo(UInt64 pos) - { - return InStream_SeekSet(_stream, pos); - } - - HRESULT SeekTo_DataStreamOffset() - { - return SeekTo(DataStreamOffset); - } - - HRESULT SeekToNonSolidItem(unsigned index) - { - return SeekTo(GetPosOfNonSolidItem(index)); - } - - void Clear(); - - bool IsDirectString_Equal(UInt32 offset, const char *s) const; - /* - UInt64 GetDataPos(unsigned index) - { - const CItem &item = Items[index]; - return GetOffset() + FirstHeader.HeaderSize + item.Pos; - } - */ - - UInt64 GetPosOfSolidItem(unsigned index) const - { - const CItem &item = Items[index]; - return 4 + (UInt64)FirstHeader.HeaderSize + item.Pos; - } - - UInt64 GetPosOfNonSolidItem(unsigned index) const - { - const CItem &item = Items[index]; - return DataStreamOffset + _nonSolidStartOffset + 4 + item.Pos; - } - - void Release() - { - Decoder.Release(); - } - - bool IsTruncated() const { return (_fileSize - StartOffset < FirstHeader.ArcSize); } - - UString GetReducedName(unsigned index) const - { - const CItem &item = Items[index]; - - UString s; - if (item.Prefix >= 0) - { - if (IsUnicode) - s = UPrefixes[item.Prefix]; - else - s = MultiByteToUnicodeString(APrefixes[item.Prefix]); - if (s.Len() > 0) - if (s.Back() != L'\\') - s.Add_Char('\\'); - } - - if (IsUnicode) - { - s += item.NameU; - if (item.NameU.IsEmpty()) - s += "file"; - } - else - { - s += MultiByteToUnicodeString(item.NameA); - if (item.NameA.IsEmpty()) - s += "file"; - } - - const char * const kRemoveStr = "$INSTDIR\\"; - if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr)) - { - s.Delete(0, MyStringLen(kRemoveStr)); - if (s[0] == L'\\') - s.DeleteFrontal(1); - } - if (item.Is_PatchedUninstaller() && ExeStub.Size() == 0) - s += ".nsis"; - return s; - } - - UString ConvertToUnicode(const AString &s) const; - - CInArchive() - #ifdef NSIS_SCRIPT - : Script(kScriptSizeLimit) - #endif - {} -}; - -}} - -#endif +// NsisIn.h + +#ifndef ZIP7_INC_ARCHIVE_NSIS_IN_H +#define ZIP7_INC_ARCHIVE_NSIS_IN_H + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/DynLimBuf.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../Common/StreamUtils.h" + +#include "NsisDecode.h" + +/* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file. + The code is much larger in that case. */ + +// #define NSIS_SCRIPT + +namespace NArchive { +namespace NNsis { + +const size_t kScriptSizeLimit = 1 << 27; + +const unsigned kSignatureSize = 16; +extern const Byte kSignature[kSignatureSize]; +#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 'N', 'u', 'l', 'l', 's', 'o', 'f', 't', 'I', 'n', 's', 't' } + +const UInt32 kFlagsMask = 0xF; +namespace NFlags +{ + const UInt32 kUninstall = 1; + const UInt32 kSilent = 2; + const UInt32 kNoCrc = 4; + const UInt32 kForceCrc = 8; + // NSISBI fork flags: + const UInt32 k_BI_LongOffset = 16; + const UInt32 k_BI_ExternalFileSupport = 32; + const UInt32 k_BI_ExternalFile = 64; + const UInt32 k_BI_IsStubInstaller = 128; +} + +struct CFirstHeader +{ + UInt32 Flags; + UInt32 HeaderSize; + UInt32 ArcSize; + + bool ThereIsCrc() const + { + return + (Flags & NFlags::kForceCrc) != 0 || + (Flags & NFlags::kNoCrc) == 0; + } + + UInt32 GetDataSize() const { return ArcSize - (ThereIsCrc() ? 4 : 0); } +}; + + +struct CBlockHeader +{ + UInt32 Offset; + UInt32 Num; + + void Parse(const Byte *p, unsigned bhoSize); +}; + +struct CItem +{ + bool IsEmptyFile; + bool IsCompressed; + bool Size_Defined; + bool CompressedSize_Defined; + bool EstimatedSize_Defined; + bool Attrib_Defined; + bool IsUninstaller; + // bool UseFilter; + + UInt32 Attrib; + UInt32 Pos; // = 0, if (IsEmptyFile == true) + UInt32 Size; + UInt32 CompressedSize; + UInt32 EstimatedSize; + UInt32 DictionarySize; + UInt32 PatchSize; // for Uninstaller.exe + int Prefix; // - 1 means no prefix + + FILETIME MTime; + AString NameA; + UString NameU; + + bool Is_PatchedUninstaller() const { return PatchSize != 0; } + + CItem(): + IsEmptyFile(false), + IsCompressed(true), + Size_Defined(false), + CompressedSize_Defined(false), + EstimatedSize_Defined(false), + Attrib_Defined(false), + IsUninstaller(false), + // UseFilter(false), + Attrib(0), + Pos(0), + Size(0), + CompressedSize(0), + EstimatedSize(0), + DictionarySize(1), + PatchSize(0), + Prefix(-1) + { + MTime.dwLowDateTime = 0; + MTime.dwHighDateTime = 0; + } + + /* + bool IsINSTDIR() const + { + return (PrefixA.Len() >= 3 || PrefixU.Len() >= 3); + } + */ +}; + +enum ENsisType +{ + k_NsisType_Nsis2, + k_NsisType_Nsis3, + k_NsisType_Park1, // Park 2.46.1- + k_NsisType_Park2, // Park 2.46.2 : GetFontVersion + k_NsisType_Park3 // Park 2.46.3+ : GetFontName +}; + +#ifdef NSIS_SCRIPT + +struct CSection +{ + UInt32 InstallTypes; // bits set for each of the different install_types, if any. + UInt32 Flags; // SF_* - defined above + UInt32 StartCmdIndex; // code; + UInt32 NumCommands; // code_size; + UInt32 SizeKB; + UInt32 Name; + + void Parse(const Byte *data); +}; + +struct CLicenseFile +{ + UInt32 Offset; + UInt32 Size; + AString Name; + CByteBuffer Text; +}; + +#endif + +class CInArchive +{ +public: + #ifdef NSIS_SCRIPT + CDynLimBuf Script; + #endif + CByteBuffer _data; + CObjectVector Items; + bool IsUnicode; + bool Is64Bit; +private: + UInt32 _stringsPos; // relative to _data + UInt32 NumStringChars; + size_t _size; // it's Header Size + + AString Raw_AString; + UString Raw_UString; + + ENsisType NsisType; + bool IsNsis200; // NSIS 2.03 and before + bool IsNsis225; // NSIS 2.25 and before + bool LogCmdIsEnabled; + int BadCmd; // -1: no bad command; in another cases lowest bad command id + + bool IsPark() const { return NsisType >= k_NsisType_Park1; } + bool IsNsis3_OrHigher() const { return NsisType == k_NsisType_Nsis3; } + + UInt64 _fileSize; + + bool _headerIsCompressed; + UInt32 _nonSolidStartOffset; + + #ifdef NSIS_SCRIPT + + CByteBuffer strUsed; + + CBlockHeader bhPages; + CBlockHeader bhSections; + CBlockHeader bhCtlColors; + CBlockHeader bhData; + UInt32 AfterHeaderSize; + CByteBuffer _afterHeader; + + UInt32 SectionSize; + const Byte *_mainLang; + UInt32 _numLangStrings; + AString LangComment; + CRecordVector langStrIDs; + UInt32 numOnFunc; + UInt32 onFuncOffset; + // CRecordVector OnFuncs; + unsigned _numRootLicenses; + CRecordVector noParseStringIndexes; + AString _tempString_for_GetVar; + AString _tempString_for_AddFuncName; + AString _tempString; + + #endif + + +public: + CMyComPtr _stream; // it's limited stream that contains only NSIS archive + UInt64 StartOffset; // offset in original stream. + UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream + + bool IsArc; + + CDecoder Decoder; + CByteBuffer ExeStub; + CFirstHeader FirstHeader; + NMethodType::EEnum Method; + UInt32 DictionarySize; + bool IsSolid; + bool UseFilter; + bool FilterFlag; + + bool IsInstaller; + AString Name; + AString BrandingText; + UStringVector UPrefixes; + AStringVector APrefixes; + + #ifdef NSIS_SCRIPT + CObjectVector LicenseFiles; + #endif + +private: + void GetShellString(AString &s, unsigned index1, unsigned index2); + void GetNsisString_Raw(const Byte *s); + void GetNsisString_Unicode_Raw(const Byte *s); + void ReadString2_Raw(UInt32 pos); + bool IsGoodString(UInt32 param) const; + bool AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const; + + void Add_LangStr(AString &res, UInt32 id); + + #ifdef NSIS_SCRIPT + + void Add_UInt(UInt32 v); + void AddLicense(UInt32 param, Int32 langID); + + void Add_LangStr_Simple(UInt32 id); + void Add_FuncName(const UInt32 *labels, UInt32 index); + void AddParam_Func(const UInt32 *labels, UInt32 index); + void Add_LabelName(UInt32 index); + + void Add_Color2(UInt32 v); + void Add_ColorParam(UInt32 v); + void Add_Color(UInt32 index); + + void Add_ButtonID(UInt32 buttonID); + + void Add_ShowWindow_Cmd(UInt32 cmd); + void Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type); + void Add_ExecFlags(UInt32 flagsType); + void Add_SectOp(UInt32 opType); + + void Add_Var(UInt32 index); + void AddParam_Var(UInt32 value); + void AddParam_UInt(UInt32 value); + + void Add_GotoVar(UInt32 param); + void Add_GotoVar1(UInt32 param); + void Add_GotoVars2(const UInt32 *params); + + + + bool PrintSectionBegin(const CSection §, unsigned index); + void PrintSectionEnd(); + + void GetNsisString(AString &res, const Byte *s); + void GetNsisString_Unicode(AString &res, const Byte *s); + UInt32 GetNumUsedVars() const; + void ReadString2(AString &s, UInt32 pos); + + void MessageBox_MB_Part(UInt32 param); + void AddParam(UInt32 pos); + void AddOptionalParam(UInt32 pos); + void AddParams(const UInt32 *params, unsigned num); + void AddPageOption1(UInt32 param, const char *name); + void AddPageOption(const UInt32 *params, unsigned num, const char *name); + void AddOptionalParams(const UInt32 *params, unsigned num); + void AddRegRoot(UInt32 value); + + + void ClearLangComment(); + void Separator(); + void Space(); + void Tab(); + void Tab(bool commented); + void BigSpaceComment(); + void SmallSpaceComment(); + void AddCommentAndString(const char *s); + void AddError(const char *s); + void AddErrorLF(const char *s); + void CommentOpen(); + void CommentClose(); + void AddLF(); + void AddQuotes(); + void TabString(const char *s); + void AddStringLF(const char *s); + void NewLine(); + void PrintNumComment(const char *name, UInt32 value); + void Add_QuStr(const AString &s); + void SpaceQuStr(const AString &s); + bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands); + + #endif + + #ifdef NSIS_SCRIPT + unsigned GetNumSupportedCommands() const; + #endif + + UInt32 GetCmd(UInt32 a); + void FindBadCmd(const CBlockHeader &bh, const Byte *); + void DetectNsisType(const CBlockHeader &bh, const Byte *); + + HRESULT ReadEntries(const CBlockHeader &bh); + HRESULT SortItems(); + HRESULT Parse(); + HRESULT Open2(const Byte *data, size_t size); + void Clear2(); + + void GetVar2(AString &res, UInt32 index); + void GetVar(AString &res, UInt32 index); + Int32 GetVarIndex(UInt32 strPos) const; + Int32 GetVarIndex(UInt32 strPos, UInt32 &resOffset) const; + Int32 GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const; + bool IsVarStr(UInt32 strPos, UInt32 varIndex) const; + bool IsAbsolutePathVar(UInt32 strPos) const; + void SetItemName(CItem &item, UInt32 strPos); + +public: + HRESULT Open(IInStream *inStream, const UInt64 *maxCheckStartPosition); + AString GetFormatDescription() const; + HRESULT InitDecoder() + { + bool useFilter; + return Decoder.Init(_stream, useFilter); + } + + HRESULT SeekTo(UInt64 pos) + { + return InStream_SeekSet(_stream, pos); + } + + HRESULT SeekTo_DataStreamOffset() + { + return SeekTo(DataStreamOffset); + } + + HRESULT SeekToNonSolidItem(unsigned index) + { + return SeekTo(GetPosOfNonSolidItem(index)); + } + + void Clear(); + + bool IsDirectString_Equal(UInt32 offset, const char *s) const; + /* + UInt64 GetDataPos(unsigned index) + { + const CItem &item = Items[index]; + return GetOffset() + FirstHeader.HeaderSize + item.Pos; + } + */ + + UInt64 GetPosOfSolidItem(unsigned index) const + { + const CItem &item = Items[index]; + return 4 + (UInt64)FirstHeader.HeaderSize + item.Pos; + } + + UInt64 GetPosOfNonSolidItem(unsigned index) const + { + const CItem &item = Items[index]; + return DataStreamOffset + _nonSolidStartOffset + 4 + item.Pos; + } + + void Release() + { + Decoder.Release(); + } + + bool IsTruncated() const { return (_fileSize - StartOffset < FirstHeader.ArcSize); } + + UString GetReducedName(unsigned index) const + { + const CItem &item = Items[index]; + + UString s; + if (item.Prefix >= 0) + { + if (IsUnicode) + s = UPrefixes[item.Prefix]; + else + s = MultiByteToUnicodeString(APrefixes[item.Prefix]); + if (s.Len() > 0) + if (s.Back() != L'\\') + s.Add_Char('\\'); + } + + if (IsUnicode) + { + s += item.NameU; + if (item.NameU.IsEmpty()) + s += "file"; + } + else + { + s += MultiByteToUnicodeString(item.NameA); + if (item.NameA.IsEmpty()) + s += "file"; + } + + const char * const kRemoveStr = "$INSTDIR\\"; + if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr)) + { + s.Delete(0, MyStringLen(kRemoveStr)); + if (s[0] == L'\\') + s.DeleteFrontal(1); + } + if (item.Is_PatchedUninstaller() && ExeStub.Size() == 0) + s += ".nsis"; + return s; + } + + UString ConvertToUnicode(const AString &s) const; + + CInArchive() + #ifdef NSIS_SCRIPT + : Script(kScriptSizeLimit) + #endif + {} +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/CPP/7zip/Archive/Nsis/NsisRegister.cpp index cadfc023b..a5003817e 100644 --- a/CPP/7zip/Archive/Nsis/NsisRegister.cpp +++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp @@ -1,20 +1,20 @@ -// NsisRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "NsisHandler.h" - -namespace NArchive { -namespace NNsis { - -REGISTER_ARC_I( - "Nsis", "nsis", NULL, 0x9, - kSignature, - 4, - NArcInfoFlags::kFindSignature | - NArcInfoFlags::kUseGlobalOffset, - NULL) - -}} +// NsisRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "NsisHandler.h" + +namespace NArchive { +namespace NNsis { + +REGISTER_ARC_I( + "Nsis", "nsis", NULL, 0x9, + kSignature, + 4, + NArcInfoFlags::kFindSignature | + NArcInfoFlags::kUseGlobalOffset, + NULL) + +}} diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Nsis/StdAfx.h +++ b/CPP/7zip/Archive/Nsis/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index cda7495c6..d55521d0b 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -1,2895 +1,2895 @@ -// NtfsHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO -// #define SHOW_DEBUG_INFO2 - -#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2) -#include -#endif - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/MethodProps.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/DummyOutStream.h" - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#define PRF_UTF16(x) PRF(printf("%S", x)) -#else -#define PRF(x) -#define PRF_UTF16(x) -#endif - -#ifdef SHOW_DEBUG_INFO2 -#define PRF2(x) x -#else -#define PRF2(x) -#endif - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(p, dest) dest = Get16(p) -#define G32(p, dest) dest = Get32(p) -#define G64(p, dest) dest = Get64(p) - -using namespace NWindows; - -namespace NArchive { -namespace Ntfs { - -static const wchar_t * const kVirtualFolder_System = L"[SYSTEM]"; -static const wchar_t * const kVirtualFolder_Lost_Normal = L"[LOST]"; -static const wchar_t * const kVirtualFolder_Lost_Deleted = L"[UNKNOWN]"; - -static const unsigned kNumSysRecs = 16; - -static const unsigned kRecIndex_Volume = 3; -static const unsigned kRecIndex_RootDir = 5; -static const unsigned kRecIndex_BadClus = 8; -static const unsigned kRecIndex_Security = 9; - -struct CHeader -{ - unsigned SectorSizeLog; - unsigned ClusterSizeLog; - unsigned MftRecordSizeLog; - // Byte MediaType; - // UInt32 NumHiddenSectors; - UInt64 NumSectors; - UInt64 NumClusters; - UInt64 MftCluster; - UInt64 SerialNumber; - // UInt16 SectorsPerTrack; - // UInt16 NumHeads; - - UInt64 GetPhySize_Clusters() const { return NumClusters << ClusterSizeLog; } - UInt64 GetPhySize_Max() const { return (NumSectors + 1) << SectorSizeLog; } - UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } - bool Parse(const Byte *p); -}; - -static int GetLog(UInt32 num) -{ - for (int i = 0; i < 31; i++) - if (((UInt32)1 << i) == num) - return i; - return -1; -} - -bool CHeader::Parse(const Byte *p) -{ - if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) - return false; - - // int codeOffset = 0; - switch (p[0]) - { - case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break; - case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break; - default: return false; - } - unsigned sectorsPerClusterLog; - - if (memcmp(p + 3, "NTFS ", 8) != 0) - return false; - { - { - const int t = GetLog(Get16(p + 11)); - if (t < 9 || t > 12) - return false; - SectorSizeLog = (unsigned)t; - } - { - const unsigned v = p[13]; - if (v <= 0x80) - { - const int t = GetLog(v); - if (t < 0) - return false; - sectorsPerClusterLog = (unsigned)t; - } - else - sectorsPerClusterLog = 0x100 - v; - ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog; - if (ClusterSizeLog > 30) - return false; - } - } - - for (int i = 14; i < 21; i++) - if (p[i] != 0) - return false; - - // F8 : a hard disk - // F0 : high-density 3.5-inch floppy disk - if (p[21] != 0xF8) // MediaType = Fixed_Disk - return false; - if (Get16(p + 22) != 0) // NumFatSectors - return false; - // G16(p + 24, SectorsPerTrack); // 63 usually - // G16(p + 26, NumHeads); // 255 - // G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?) - if (Get32(p + 32) != 0) // NumSectors32 - return false; - - // DriveNumber = p[0x24]; - if (p[0x25] != 0) // CurrentHead - return false; - /* - NTFS-HDD: p[0x26] = 0x80 - NTFS-FLASH: p[0x26] = 0 - */ - if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig - return false; - if (p[0x27] != 0) // reserved - return false; - - NumSectors = Get64(p + 0x28); - if (NumSectors >= ((UInt64)1 << (62 - SectorSizeLog))) - return false; - - NumClusters = NumSectors >> sectorsPerClusterLog; - - G64(p + 0x30, MftCluster); // $MFT. - // G64(p + 0x38, Mft2Cluster); - G64(p + 0x48, SerialNumber); // $MFTMirr - - /* - numClusters_per_MftRecord: - numClusters_per_IndexBlock: - only low byte from 4 bytes is used. Another 3 high bytes are zeros. - If the number is positive (number < 0x80), - then it represents the number of clusters. - If the number is negative (number >= 0x80), - then the size of the file record is 2 raised to the absolute value of this number. - example: (0xF6 == -10) means 2^10 = 1024 bytes. - */ - { - UInt32 numClusters_per_MftRecord; - G32(p + 0x40, numClusters_per_MftRecord); - if (numClusters_per_MftRecord >= 0x100 || numClusters_per_MftRecord == 0) - return false; - if (numClusters_per_MftRecord < 0x80) - { - const int t = GetLog(numClusters_per_MftRecord); - if (t < 0) - return false; - MftRecordSizeLog = (unsigned)t + ClusterSizeLog; - } - else - MftRecordSizeLog = 0x100 - numClusters_per_MftRecord; - // what exact MFT record sizes are possible and supported by Windows? - // do we need to change this limit here? - const unsigned k_MftRecordSizeLog_MAX = 12; - if (MftRecordSizeLog > k_MftRecordSizeLog_MAX) - return false; - if (MftRecordSizeLog < SectorSizeLog) - return false; - } - { - UInt32 numClusters_per_IndexBlock; - G32(p + 0x44, numClusters_per_IndexBlock); - return (numClusters_per_IndexBlock < 0x100); - } -} - -struct CMftRef -{ - UInt64 Val; - - UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); } - UInt16 GetNumber() const { return (UInt16)(Val >> 48); } - bool IsBaseItself() const { return Val == 0; } - - CMftRef(): Val(0) {} -}; - -#define ATNAME(n) ATTR_TYPE_ ## n -#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v - -enum -{ - DEF_ATTR_TYPE(0x00, UNUSED), - DEF_ATTR_TYPE(0x10, STANDARD_INFO), - DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST), - DEF_ATTR_TYPE(0x30, FILE_NAME), - DEF_ATTR_TYPE(0x40, OBJECT_ID), - DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR), - DEF_ATTR_TYPE(0x60, VOLUME_NAME), - DEF_ATTR_TYPE(0x70, VOLUME_INFO), - DEF_ATTR_TYPE(0x80, DATA), - DEF_ATTR_TYPE(0x90, INDEX_ROOT), - DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION), - DEF_ATTR_TYPE(0xB0, BITMAP), - DEF_ATTR_TYPE(0xC0, REPARSE_POINT), - DEF_ATTR_TYPE(0xD0, EA_INFO), - DEF_ATTR_TYPE(0xE0, EA), - DEF_ATTR_TYPE(0xF0, PROPERTY_SET), - DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM), - DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE) -}; - - -/* WinXP-64: - Probably only one short name (dos name) per record is allowed. - There are no short names for hard links. - The pair (Win32,Dos) can be in any order. - Posix name can be after or before Win32 name -*/ - -// static const Byte kFileNameType_Posix = 0; // for hard links -static const Byte kFileNameType_Win32 = 1; // after Dos name -static const Byte kFileNameType_Dos = 2; // short name -static const Byte kFileNameType_Win32Dos = 3; // short and full name are same - -struct CFileNameAttr -{ - CMftRef ParentDirRef; - - // Probably these timestamps don't contain some useful timestamps. So we don't use them - // UInt64 CTime; - // UInt64 MTime; - // UInt64 ThisRecMTime; // xp-64: the time of previous name change (not last name change. why?) - // UInt64 ATime; - // UInt64 AllocatedSize; - // UInt64 DataSize; - // UInt16 PackedEaSize; - UString2 Name; - UInt32 Attrib; - Byte NameType; - - bool IsDos() const { return NameType == kFileNameType_Dos; } - bool IsWin32() const { return (NameType == kFileNameType_Win32); } - - bool Parse(const Byte *p, unsigned size); - - CFileNameAttr(): - Attrib(0), - NameType(0) - {} -}; - -static void GetString(const Byte *p, const unsigned len, UString2 &res) -{ - if (len == 0 && res.IsEmpty()) - return; - wchar_t *s = res.GetBuf(len); - unsigned i; - for (i = 0; i < len; i++) - { - const wchar_t c = Get16(p + i * 2); - if (c == 0) - break; - s[i] = c; - } - s[i] = 0; - res.ReleaseBuf_SetLen(i); -} - -bool CFileNameAttr::Parse(const Byte *p, unsigned size) -{ - if (size < 0x42) - return false; - G64(p + 0x00, ParentDirRef.Val); - // G64(p + 0x08, CTime); - // G64(p + 0x10, MTime); - // G64(p + 0x18, ThisRecMTime); - // G64(p + 0x20, ATime); - // G64(p + 0x28, AllocatedSize); - // G64(p + 0x30, DataSize); - G32(p + 0x38, Attrib); - // G16(p + 0x3C, PackedEaSize); - NameType = p[0x41]; - const unsigned len = p[0x40]; - if (0x42 + len * 2 > size) - return false; - if (len != 0) - GetString(p + 0x42, len, Name); - return true; -} - -struct CSiAttr -{ - UInt64 CTime; - UInt64 MTime; - UInt64 ThisRecMTime; - UInt64 ATime; - UInt32 Attrib; - - /* - UInt32 MaxVersions; - UInt32 Version; - UInt32 ClassId; - UInt32 OwnerId; - */ - UInt32 SecurityId; // SecurityId = 0 is possible ? - // UInt64 QuotaCharged; - - bool Parse(const Byte *p, unsigned size); - - CSiAttr(): - CTime(0), - MTime(0), - ThisRecMTime(0), - ATime(0), - Attrib(0), - SecurityId(0) - {} -}; - - -bool CSiAttr::Parse(const Byte *p, unsigned size) -{ - if (size < 0x24) - return false; - G64(p + 0x00, CTime); - G64(p + 0x08, MTime); - G64(p + 0x10, ThisRecMTime); - G64(p + 0x18, ATime); - G32(p + 0x20, Attrib); - SecurityId = 0; - if (size >= 0x38) - G32(p + 0x34, SecurityId); - return true; -} - -static const UInt64 kEmptyExtent = (UInt64)(Int64)-1; - -struct CExtent -{ - UInt64 Virt; - UInt64 Phy; - - bool IsEmpty() const { return Phy == kEmptyExtent; } -}; - -struct CVolInfo -{ - Byte MajorVer; - Byte MinorVer; - // UInt16 Flags; - - bool Parse(const Byte *p, unsigned size); -}; - -bool CVolInfo::Parse(const Byte *p, unsigned size) -{ - if (size < 12) - return false; - MajorVer = p[8]; - MinorVer = p[9]; - // Flags = Get16(p + 10); - return true; -} - -struct CAttr -{ - UInt32 Type; - - Byte NonResident; - - // Non-Resident - Byte CompressionUnit; - - // UInt32 Len; - UString2 Name; - // UInt16 Flags; - // UInt16 Instance; - CByteBuffer Data; - - // Non-Resident - UInt64 LowVcn; - UInt64 HighVcn; - UInt64 AllocatedSize; - UInt64 Size; - UInt64 PackSize; - UInt64 InitializedSize; - - // Resident - // UInt16 ResidentFlags; - - bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; } - - UInt32 Parse(const Byte *p, unsigned size); - bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); } - bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); } - bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.Size()); } - bool ParseExtents(CRecordVector &extents, UInt64 numClustersMax, unsigned compressionUnit) const; - UInt64 GetSize() const { return NonResident ? Size : Data.Size(); } - UInt64 GetPackSize() const - { - if (!NonResident) - return Data.Size(); - if (CompressionUnit != 0) - return PackSize; - return AllocatedSize; - } -}; - -#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } - -static int CompareAttr(void *const *elem1, void *const *elem2, void *) -{ - const CAttr &a1 = *(*((const CAttr *const *)elem1)); - const CAttr &a2 = *(*((const CAttr *const *)elem2)); - RINOZ(MyCompare(a1.Type, a2.Type)) - if (a1.Name.IsEmpty()) - { - if (!a2.Name.IsEmpty()) - return -1; - } - else if (a2.Name.IsEmpty()) - return 1; - else - { - RINOZ(a1.Name.Compare(a2.Name.GetRawPtr())) - } - return MyCompare(a1.LowVcn, a2.LowVcn); -} - -UInt32 CAttr::Parse(const Byte *p, unsigned size) -{ - if (size < 4) - return 0; - G32(p, Type); - if (Type == 0xFFFFFFFF) - return 8; // required size is 4, but attributes are 8 bytes aligned. So we return 8 - if (size < 0x18) - return 0; - - PRF(printf(" T=%2X", Type)); - - UInt32 len = Get32(p + 4); - PRF(printf(" L=%3d", len)); - if (len > size) - return 0; - if ((len & 7) != 0) - return 0; - NonResident = p[8]; - { - unsigned nameLen = p[9]; - UInt32 nameOffset = Get16(p + 0x0A); - if (nameLen != 0) - { - if (nameOffset + nameLen * 2 > len) - return 0; - GetString(p + nameOffset, nameLen, Name); - PRF(printf(" N=")); - PRF_UTF16(Name); - } - } - - // G16(p + 0x0C, Flags); - // G16(p + 0x0E, Instance); - // PRF(printf(" F=%4X", Flags)); - // PRF(printf(" Inst=%d", Instance)); - - UInt32 dataSize; - UInt32 offs; - - if (NonResident) - { - if (len < 0x40) - return 0; - PRF(printf(" NR")); - G64(p + 0x10, LowVcn); - G64(p + 0x18, HighVcn); - G64(p + 0x28, AllocatedSize); - G64(p + 0x30, Size); - G64(p + 0x38, InitializedSize); - G16(p + 0x20, offs); - CompressionUnit = p[0x22]; - - PackSize = Size; - if (CompressionUnit != 0) - { - if (len < 0x48) - return 0; - G64(p + 0x40, PackSize); - PRF(printf(" PS=%I64x", PackSize)); - } - - // PRF(printf("\n")); - PRF(printf(" ASize=%4I64d", AllocatedSize)); - PRF(printf(" Size=%I64d", Size)); - PRF(printf(" IS=%I64d", InitializedSize)); - PRF(printf(" Low=%I64d", LowVcn)); - PRF(printf(" High=%I64d", HighVcn)); - PRF(printf(" CU=%d", (unsigned)CompressionUnit)); - dataSize = len - offs; - } - else - { - if (len < 0x18) - return 0; - G32(p + 0x10, dataSize); - G16(p + 0x14, offs); - // G16(p + 0x16, ResidentFlags); - PRF(printf(" RES")); - PRF(printf(" dataSize=%3d", dataSize)); - // PRF(printf(" ResFlags=%4X", ResidentFlags)); - } - - if (offs > len || dataSize > len || len - dataSize < offs) - return 0; - - Data.CopyFrom(p + offs, dataSize); - - #ifdef SHOW_DEBUG_INFO - PRF(printf(" : ")); - for (unsigned i = 0; i < Data.Size(); i++) - { - PRF(printf(" %02X", (unsigned)Data[i])); - } - #endif - - return len; -} - - -bool CAttr::ParseExtents(CRecordVector &extents, UInt64 numClustersMax, unsigned compressionUnit) const -{ - const Byte *p = Data; - unsigned size = (unsigned)Data.Size(); - UInt64 vcn = LowVcn; - UInt64 lcn = 0; - const UInt64 highVcn1 = HighVcn + 1; - - if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63) - return false; - - extents.DeleteBack(); - - PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn)); - - while (size > 0) - { - const unsigned b = *p++; - size--; - if (b == 0) - break; - unsigned num = b & 0xF; - if (num == 0 || num > 8 || num > size) - return false; - - UInt64 vSize = 0; - { - unsigned i = num; - do vSize = (vSize << 8) | p[--i]; while (i); - } - if (vSize == 0) - return false; - p += num; - size -= num; - if ((highVcn1 - vcn) < vSize) - return false; - - CExtent e; - e.Virt = vcn; - vcn += vSize; - - num = b >> 4; - if (num > 8 || num > size) - return false; - - if (num == 0) - { - // Sparse - - /* if Unit is compressed, it can have many Elements for each compressed Unit: - and last Element for unit MUST be without LCN. - Element 0: numCompressedClusters2, LCN_0 - Element 1: numCompressedClusters2, LCN_1 - ... - Last Element : (16 - total_clusters_in_previous_elements), no LCN - */ - - // sparse is not allowed for (compressionUnit == 0) ? Why ? - if (compressionUnit == 0) - return false; - - e.Phy = kEmptyExtent; - } - else - { - Int64 v = (signed char)p[num - 1]; - { - for (unsigned i = num - 1; i != 0;) - v = (v << 8) | p[--i]; - } - p += num; - size -= num; - lcn = (UInt64)((Int64)lcn + v); - if (lcn > numClustersMax) - return false; - e.Phy = lcn; - } - - extents.Add(e); - } - - CExtent e; - e.Phy = kEmptyExtent; - e.Virt = vcn; - extents.Add(e); - return (highVcn1 == vcn); -} - - -static const UInt64 kEmptyTag = (UInt64)(Int64)-1; - -static const unsigned kNumCacheChunksLog = 1; -static const size_t kNumCacheChunks = (size_t)1 << kNumCacheChunksLog; - -Z7_CLASS_IMP_IInStream( - CInStream -) - UInt64 _virtPos; - UInt64 _physPos; - UInt64 _curRem; - bool _sparseMode; -public: - bool InUse; -private: - unsigned _chunkSizeLog; - CByteBuffer _inBuf; - CByteBuffer _outBuf; -public: - UInt64 Size; - UInt64 InitializedSize; - unsigned BlockSizeLog; - unsigned CompressionUnit; - CRecordVector Extents; - CMyComPtr Stream; -private: - UInt64 _tags[kNumCacheChunks]; - - HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); } - UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); } -public: - HRESULT InitAndSeek(unsigned compressionUnit) - { - CompressionUnit = compressionUnit; - _chunkSizeLog = BlockSizeLog + CompressionUnit; - if (compressionUnit != 0) - { - UInt32 cuSize = GetCuSize(); - _inBuf.Alloc(cuSize); - _outBuf.Alloc(kNumCacheChunks << _chunkSizeLog); - } - for (size_t i = 0; i < kNumCacheChunks; i++) - _tags[i] = kEmptyTag; - - _sparseMode = false; - _curRem = 0; - _virtPos = 0; - _physPos = 0; - const CExtent &e = Extents[0]; - if (!e.IsEmpty()) - _physPos = e.Phy << BlockSizeLog; - return SeekToPhys(); - } -}; - -static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen) -{ - size_t destSize = 0; - while (destSize < destLen) - { - if (srcLen < 2 || (destSize & 0xFFF) != 0) - break; - UInt32 comprSize; - { - const UInt32 v = Get16(src); - if (v == 0) - break; - src += 2; - srcLen -= 2; - comprSize = (v & 0xFFF) + 1; - if (comprSize > srcLen) - break; - srcLen -= comprSize; - if ((v & 0x8000) == 0) - { - if (comprSize != (1 << 12)) - break; - memcpy(dest + destSize, src, comprSize); - src += comprSize; - destSize += comprSize; - continue; - } - } - { - if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0) - return 0; - unsigned numDistBits = 4; - UInt32 sbOffset = 0; - UInt32 pos = 0; - - do - { - comprSize--; - for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1) - { - if ((mask & 1) == 0) - { - if (sbOffset >= (1 << 12)) - return 0; - dest[destSize++] = src[pos++]; - sbOffset++; - comprSize--; - } - else - { - if (comprSize < 2) - return 0; - const UInt32 v = Get16(src + pos); - pos += 2; - comprSize -= 2; - - while (((sbOffset - 1) >> numDistBits) != 0) - numDistBits++; - - UInt32 len = (v & (0xFFFF >> numDistBits)) + 3; - if (sbOffset + len > (1 << 12)) - return 0; - UInt32 dist = (v >> (16 - numDistBits)); - if (dist >= sbOffset) - return 0; - const size_t offs = 1 + dist; - Byte *p = dest + destSize - offs; - destSize += len; - sbOffset += len; - const Byte *lim = p + len; - p[offs] = *p; ++p; - p[offs] = *p; ++p; - do - p[offs] = *p; - while (++p != lim); - } - } - } - while (comprSize > 0); - src += pos; - } - } - return destSize; -} - -Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= Size) - return (Size == _virtPos) ? S_OK: E_FAIL; - if (size == 0) - return S_OK; - { - const UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - - if (_virtPos >= InitializedSize) - { - memset((Byte *)data, 0, size); - _virtPos += size; - *processedSize = size; - return S_OK; - } - - { - const UInt64 rem = InitializedSize - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - - while (_curRem == 0) - { - const UInt64 cacheTag = _virtPos >> _chunkSizeLog; - const size_t cacheIndex = (size_t)cacheTag & (kNumCacheChunks - 1); - - if (_tags[cacheIndex] == cacheTag) - { - const size_t chunkSize = (size_t)1 << _chunkSizeLog; - const size_t offset = (size_t)_virtPos & (chunkSize - 1); - size_t cur = chunkSize - offset; - if (cur > size) - cur = size; - memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur); - *processedSize = (UInt32)cur; - _virtPos += cur; - return S_OK; - } - - PRF2(printf("\nVirtPos = %6d", _virtPos)); - - const UInt32 comprUnitSize = (UInt32)1 << CompressionUnit; - const UInt64 virtBlock = _virtPos >> BlockSizeLog; - const UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1); - - unsigned left = 0, right = Extents.Size(); - for (;;) - { - unsigned mid = (left + right) / 2; - if (mid == left) - break; - if (virtBlock2 < Extents[mid].Virt) - right = mid; - else - left = mid; - } - - bool isCompressed = false; - const UInt64 virtBlock2End = virtBlock2 + comprUnitSize; - if (CompressionUnit != 0) - for (unsigned i = left; i < Extents.Size(); i++) - { - const CExtent &e = Extents[i]; - if (e.Virt >= virtBlock2End) - break; - if (e.IsEmpty()) - { - isCompressed = true; - break; - } - } - - unsigned i; - for (i = left; Extents[i + 1].Virt <= virtBlock; i++); - - _sparseMode = false; - if (!isCompressed) - { - const CExtent &e = Extents[i]; - UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog); - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()) - } - UInt64 next = Extents[i + 1].Virt; - if (next > virtBlock2End) - next &= ~((UInt64)comprUnitSize - 1); - next <<= BlockSizeLog; - if (next > Size) - next = Size; - _curRem = next - _virtPos; - break; - } - - bool thereArePhy = false; - - for (unsigned i2 = left; i2 < Extents.Size(); i2++) - { - const CExtent &e = Extents[i2]; - if (e.Virt >= virtBlock2End) - break; - if (!e.IsEmpty()) - { - thereArePhy = true; - break; - } - } - - if (!thereArePhy) - { - _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos; - _sparseMode = true; - break; - } - - size_t offs = 0; - UInt64 curVirt = virtBlock2; - - for (i = left; i < Extents.Size(); i++) - { - const CExtent &e = Extents[i]; - if (e.IsEmpty()) - break; - if (e.Virt >= virtBlock2End) - return S_FALSE; - const UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog; - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()) - } - UInt64 numChunks = Extents[i + 1].Virt - curVirt; - if (curVirt + numChunks > virtBlock2End) - numChunks = virtBlock2End - curVirt; - const size_t compressed = (size_t)numChunks << BlockSizeLog; - RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed)) - curVirt += numChunks; - _physPos += compressed; - offs += compressed; - } - - const size_t destLenMax = GetCuSize(); - size_t destLen = destLenMax; - const UInt64 rem = Size - (virtBlock2 << BlockSizeLog); - if (destLen > rem) - destLen = (size_t)rem; - - Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog); - const size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs); - _tags[cacheIndex] = cacheTag; - - // some files in Vista have destSize > destLen - if (destSizeRes < destLen) - { - memset(dest, 0, destLenMax); - if (InUse) - return S_FALSE; - } - } - - if (size > _curRem) - size = (UInt32)_curRem; - HRESULT res = S_OK; - if (_sparseMode) - memset(data, 0, size); - else - { - res = Stream->Read(data, size, &size); - _physPos += size; - } - if (processedSize) - *processedSize = size; - _virtPos += size; - _curRem -= size; - return res; -} - -Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - if (_virtPos != (UInt64)offset) - { - _curRem = 0; - _virtPos = (UInt64)offset; - } - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - -static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector &attrs, - unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector &Extents) -{ - { - CExtent e; - e.Virt = 0; - e.Phy = kEmptyExtent; - Extents.Add(e); - } - - const CAttr &attr0 = attrs[attrIndex]; - - /* - if (attrs[attrIndexLim - 1].HighVcn + 1 != (attr0.AllocatedSize >> clusterSizeLog)) - { - } - */ - - if (attr0.AllocatedSize < attr0.Size || - (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) || - (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0) - return S_FALSE; - - for (unsigned i = attrIndex; i < attrIndexLim; i++) - if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit)) - return S_FALSE; - - UInt64 packSizeCalc = 0; - FOR_VECTOR (k, Extents) - { - CExtent &e = Extents[k]; - if (!e.IsEmpty()) - packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog; - PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt)); - PRF2(printf(" Pos = %4I64X", e.Phy)); - } - - if (attr0.CompressionUnit != 0) - { - if (packSizeCalc != attr0.PackSize) - return S_FALSE; - } - else - { - if (packSizeCalc != attr0.AllocatedSize) - return S_FALSE; - } - return S_OK; -} - -struct CDataRef -{ - unsigned Start; - unsigned Num; -}; - -static const UInt32 kMagic_FILE = 0x454C4946; -static const UInt32 kMagic_BAAD = 0x44414142; - -// 22.02: we support some rare case magic values: -static const UInt32 kMagic_INDX = 0x58444e49; -static const UInt32 kMagic_HOLE = 0x454c4f48; -static const UInt32 kMagic_RSTR = 0x52545352; -static const UInt32 kMagic_RCRD = 0x44524352; -static const UInt32 kMagic_CHKD = 0x444b4843; -static const UInt32 kMagic_FFFFFFFF = 0xFFFFFFFF; - - -struct CMftRec -{ - UInt32 Magic; - // UInt64 Lsn; - UInt16 SeqNumber; // Number of times this mft record has been reused - UInt16 Flags; - // UInt16 LinkCount; - // UInt16 NextAttrInstance; - CMftRef BaseMftRef; - // UInt32 ThisRecNumber; - - UInt32 MyNumNameLinks; - int MyItemIndex; // index in Items[] of main item for that record, or -1 if there is no item for that record - - CObjectVector DataAttrs; - CObjectVector FileNames; - CRecordVector DataRefs; - // CAttr SecurityAttr; - - CSiAttr SiAttr; - - CByteBuffer ReparseData; - - int FindWin32Name_for_DosName(unsigned dosNameIndex) const - { - const CFileNameAttr &cur = FileNames[dosNameIndex]; - if (cur.IsDos()) - for (unsigned i = 0; i < FileNames.Size(); i++) - { - const CFileNameAttr &next = FileNames[i]; - if (next.IsWin32() && cur.ParentDirRef.Val == next.ParentDirRef.Val) - return (int)i; - } - return -1; - } - - int FindDosName(unsigned nameIndex) const - { - const CFileNameAttr &cur = FileNames[nameIndex]; - if (cur.IsWin32()) - for (unsigned i = 0; i < FileNames.Size(); i++) - { - const CFileNameAttr &next = FileNames[i]; - if (next.IsDos() && cur.ParentDirRef.Val == next.ParentDirRef.Val) - return (int)i; - } - return -1; - } - - /* - bool IsAltStream(int dataIndex) const - { - return dataIndex >= 0 && ( - (IsDir() || - !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty())); - } - */ - - void MoveAttrsFrom(CMftRec &src) - { - DataAttrs += src.DataAttrs; - FileNames += src.FileNames; - src.DataAttrs.ClearAndFree(); - src.FileNames.ClearAndFree(); - } - - UInt64 GetPackSize() const - { - UInt64 res = 0; - FOR_VECTOR (i, DataRefs) - res += DataAttrs[DataRefs[i].Start].GetPackSize(); - return res; - } - - bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector *attrs); - - bool Is_Magic_Empty() const - { - // what exact Magic values are possible for empty and unused records? - const UInt32 k_Magic_Unused_MAX = 5; // 22.02 - return (Magic <= k_Magic_Unused_MAX); - } - bool Is_Magic_FILE() const { return (Magic == kMagic_FILE); } - // bool Is_Magic_BAAD() const { return (Magic == kMagic_BAAD); } - bool Is_Magic_CanIgnore() const - { - return Is_Magic_Empty() - || Magic == kMagic_BAAD - || Magic == kMagic_INDX - || Magic == kMagic_HOLE - || Magic == kMagic_RSTR - || Magic == kMagic_RCRD - || Magic == kMagic_CHKD - || Magic == kMagic_FFFFFFFF; - } - - bool InUse() const { return (Flags & 1) != 0; } - bool IsDir() const { return (Flags & 2) != 0; } - - void ParseDataNames(); - HRESULT GetStream(IInStream *mainStream, int dataIndex, - unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; - unsigned GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const; - - UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } - - CMftRec(): - SeqNumber(0), - Flags(0), - MyNumNameLinks(0), - MyItemIndex(-1) {} -}; - -void CMftRec::ParseDataNames() -{ - DataRefs.Clear(); - DataAttrs.Sort(CompareAttr, NULL); - - for (unsigned i = 0; i < DataAttrs.Size();) - { - CDataRef ref; - ref.Start = i; - for (i++; i < DataAttrs.Size(); i++) - if (DataAttrs[ref.Start].Name != DataAttrs[i].Name) - break; - ref.Num = i - ref.Start; - DataRefs.Add(ref); - } -} - -HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, - unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const -{ - *destStream = NULL; - CBufferInStream *streamSpec = new CBufferInStream; - CMyComPtr streamTemp = streamSpec; - - if (dataIndex >= 0) - if ((unsigned)dataIndex < DataRefs.Size()) - { - const CDataRef &ref = DataRefs[dataIndex]; - unsigned numNonResident = 0; - unsigned i; - for (i = ref.Start; i < ref.Start + ref.Num; i++) - if (DataAttrs[i].NonResident) - numNonResident++; - - const CAttr &attr0 = DataAttrs[ref.Start]; - - if (numNonResident != 0 || ref.Num != 1) - { - if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) - return S_FALSE; - CInStream *ss = new CInStream; - CMyComPtr streamTemp2 = ss; - RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, ss->Extents)) - ss->Size = attr0.Size; - ss->InitializedSize = attr0.InitializedSize; - ss->Stream = mainStream; - ss->BlockSizeLog = clusterSizeLog; - ss->InUse = InUse(); - RINOK(ss->InitAndSeek(attr0.CompressionUnit)) - *destStream = streamTemp2.Detach(); - return S_OK; - } - - streamSpec->Buf = attr0.Data; - } - - streamSpec->Init(); - *destStream = streamTemp.Detach(); - return S_OK; -} - -unsigned CMftRec::GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const -{ - if (dataIndex < 0) - return 0; - { - const CDataRef &ref = DataRefs[dataIndex]; - unsigned numNonResident = 0; - unsigned i; - for (i = ref.Start; i < ref.Start + ref.Num; i++) - if (DataAttrs[i].NonResident) - numNonResident++; - - const CAttr &attr0 = DataAttrs[ref.Start]; - - if (numNonResident != 0 || ref.Num != 1) - { - if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) - return 0; // error; - CRecordVector extents; - if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK) - return 0; // error; - return extents.Size() - 1; - } - // if (attr0.Data.Size() != 0) - // return 1; - return 0; - } -} - -bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, - CObjectVector *attrs) -{ - G32(p, Magic); - if (!Is_Magic_FILE()) - return Is_Magic_CanIgnore(); - - { - UInt32 usaOffset; - UInt32 numUsaItems; - G16(p + 0x04, usaOffset); - G16(p + 0x06, numUsaItems); - - /* NTFS stores (usn) to 2 last bytes in each sector (before writing record to disk). - Original values of these two bytes are stored in table. - So we restore original data from table */ - - if ((usaOffset & 1) != 0 - || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 - || numUsaItems == 0 - || numUsaItems - 1 != numSectors) - return false; - - if (usaOffset >= 0x30) // NTFS 3.1+ - { - UInt32 iii = Get32(p + 0x2C); - if (iii != recNumber) - { - // ntfs-3g probably writes 0 (that probably is incorrect value) to this field for unused records. - // so we support that "bad" case. - if (iii != 0) - return false; - } - } - - UInt16 usn = Get16(p + usaOffset); - // PRF(printf("\nusn = %d", usn)); - for (UInt32 i = 1; i < numUsaItems; i++) - { - void *pp = p + (i << sectorSizeLog) - 2; - if (Get16(pp) != usn) - return false; - SetUi16(pp, Get16(p + usaOffset + i * 2)) - } - } - - // G64(p + 0x08, Lsn); - G16(p + 0x10, SeqNumber); - // G16(p + 0x12, LinkCount); - // PRF(printf(" L=%d", LinkCount)); - const UInt32 attrOffs = Get16(p + 0x14); - G16(p + 0x16, Flags); - PRF(printf(" F=%4X", Flags)); - - const UInt32 bytesInUse = Get32(p + 0x18); - const UInt32 bytesAlloc = Get32(p + 0x1C); - G64(p + 0x20, BaseMftRef.Val); - if (BaseMftRef.Val != 0) - { - PRF(printf(" BaseRef=%d", (int)BaseMftRef.Val)); - // return false; // Check it; - } - // G16(p + 0x28, NextAttrInstance); - - UInt32 limit = numSectors << sectorSizeLog; - if (attrOffs >= limit - || (attrOffs & 7) != 0 - || (bytesInUse & 7) != 0 - || bytesInUse > limit - || bytesAlloc != limit) - return false; - - limit = bytesInUse; - - for (UInt32 t = attrOffs;;) - { - if (t >= limit) - return false; - - CAttr attr; - // PRF(printf("\n %2d:", Attrs.Size())); - PRF(printf("\n")); - UInt32 len = attr.Parse(p + t, limit - t); - if (len == 0 || limit - t < len) - return false; - t += len; - if (attr.Type == 0xFFFFFFFF) - { - if (t != limit) - return false; - break; - } - switch (attr.Type) - { - case ATTR_TYPE_FILE_NAME: - { - CFileNameAttr fna; - if (!attr.ParseFileName(fna)) - return false; - FileNames.Add(fna); - PRF(printf(" flags = %4x\n ", (int)fna.NameType)); - PRF_UTF16(fna.Name); - break; - } - case ATTR_TYPE_STANDARD_INFO: - if (!attr.ParseSi(SiAttr)) - return false; - break; - case ATTR_TYPE_DATA: - DataAttrs.Add(attr); - break; - case ATTR_TYPE_REPARSE_POINT: - ReparseData = attr.Data; - break; - /* - case ATTR_TYPE_SECURITY_DESCRIPTOR: - SecurityAttr = attr; - break; - */ - default: - if (attrs) - attrs->Add(attr); - break; - } - } - - return true; -} - -/* - NTFS probably creates empty DATA_ATTRIBUTE for empty file, - But it doesn't do it for - $Secure (:$SDS), - $Extend\$Quota - $Extend\$ObjId - $Extend\$Reparse -*/ - -static const int k_Item_DataIndex_IsEmptyFile = -1; // file without unnamed data stream -static const int k_Item_DataIndex_IsDir = -2; - -// static const int k_ParentFolderIndex_Root = -1; -static const int k_ParentFolderIndex_Lost = -2; -static const int k_ParentFolderIndex_Deleted = -3; - -struct CItem -{ - unsigned RecIndex; // index in Recs array - unsigned NameIndex; // index in CMftRec::FileNames - - int DataIndex; /* index in CMftRec::DataRefs - -1: file without unnamed data stream - -2: for directories */ - - int ParentFolder; /* index in Items array - -1: for root items - -2: [LOST] folder - -3: [UNKNOWN] folder (deleted lost) */ - int ParentHost; /* index in Items array, if it's AltStream - -1: if it's not AltStream */ - - CItem(): DataIndex(k_Item_DataIndex_IsDir), ParentFolder(-1), ParentHost(-1) {} - - bool IsAltStream() const { return ParentHost != -1; } - bool IsDir() const { return DataIndex == k_Item_DataIndex_IsDir; } - // check it !!! - // probably NTFS for empty file still creates empty DATA_ATTRIBUTE - // But it doesn't do it for $Secure:$SDS -}; - -struct CDatabase -{ - CRecordVector Items; - CObjectVector Recs; - CMyComPtr InStream; - CHeader Header; - UInt64 PhySize; - - IArchiveOpenCallback *OpenCallback; - - CByteBuffer ByteBuf; - - CObjectVector VolAttrs; - - CByteBuffer SecurData; - CRecordVector SecurOffsets; - - // bool _headerWarning; - bool ThereAreAltStreams; - - bool _showSystemFiles; - bool _showDeletedFiles; - CObjectVector VirtFolderNames; - UString EmptyString; - - int _systemFolderIndex; - int _lostFolderIndex_Normal; - int _lostFolderIndex_Deleted; - - void InitProps() - { - _showSystemFiles = true; - // we show SystemFiles by default since it's difficult to track $Extend\* system files - // it must be fixed later - _showDeletedFiles = false; - } - - CDatabase() { InitProps(); } - ~CDatabase() { ClearAndClose(); } - - void Clear(); - void ClearAndClose(); - - void GetItemPath(unsigned index, NCOM::CPropVariant &path) const; - HRESULT Open(); - - HRESULT SeekToCluster(UInt64 cluster); - - int Find_DirItem_For_MftRec(UInt64 recIndex) const - { - if (recIndex >= Recs.Size()) - return -1; - const CMftRec &rec = Recs[(unsigned)recIndex]; - if (!rec.IsDir()) - return -1; - return rec.MyItemIndex; - /* - unsigned left = 0, right = Items.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - const CItem &item = Items[mid]; - UInt64 midValue = item.RecIndex; - if (recIndex == midValue) - { - // if item is not dir (file or alt stream we don't return it) - // if (item.DataIndex < 0) - if (item.IsDir()) - return mid; - right = mid; - } - else if (recIndex < midValue) - right = mid; - else - left = mid + 1; - } - return -1; - */ - } - - bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const; - - HRESULT ParseSecuritySDS_2(); - void ParseSecuritySDS() - { - HRESULT res = ParseSecuritySDS_2(); - if (res != S_OK) - { - SecurOffsets.Clear(); - SecurData.Free(); - } - } - -}; - -HRESULT CDatabase::SeekToCluster(UInt64 cluster) -{ - return InStream_SeekSet(InStream, cluster << Header.ClusterSizeLog); -} - -void CDatabase::Clear() -{ - Items.Clear(); - Recs.Clear(); - SecurOffsets.Clear(); - SecurData.Free(); - VirtFolderNames.Clear(); - _systemFolderIndex = -1; - _lostFolderIndex_Normal = -1; - _lostFolderIndex_Deleted = -1; - ThereAreAltStreams = false; - // _headerWarning = false; - PhySize = 0; -} - -void CDatabase::ClearAndClose() -{ - Clear(); - InStream.Release(); -} - - -static void CopyName(wchar_t *dest, const wchar_t *src) -{ - for (;;) - { - wchar_t c = *src++; - // 18.06 - if (c == '\\' || c == '/') - c = '_'; - *dest++ = c; - if (c == 0) - return; - } -} - -void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const -{ - const CItem *item = &Items[index]; - unsigned size = 0; - const CMftRec &rec = Recs[item->RecIndex]; - size += rec.FileNames[item->NameIndex].Name.Len(); - - bool isAltStream = item->IsAltStream(); - - if (isAltStream) - { - const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start]; - if (item->RecIndex == kRecIndex_RootDir) - { - wchar_t *s = path.AllocBstr(data.Name.Len() + 1); - s[0] = L':'; - if (!data.Name.IsEmpty()) - CopyName(s + 1, data.Name.GetRawPtr()); - return; - } - - size += data.Name.Len(); - size++; - } - - for (unsigned i = 0;; i++) - { - if (i > 256) - { - path = "[TOO-LONG]"; - return; - } - const wchar_t *servName; - if (item->RecIndex < kNumSysRecs - /* && item->RecIndex != kRecIndex_RootDir */) - servName = kVirtualFolder_System; - else - { - int index2 = item->ParentFolder; - if (index2 >= 0) - { - item = &Items[index2]; - size += Recs[item->RecIndex].FileNames[item->NameIndex].Name.Len() + 1; - continue; - } - if (index2 == -1) - break; - servName = (index2 == k_ParentFolderIndex_Lost) ? - kVirtualFolder_Lost_Normal : - kVirtualFolder_Lost_Deleted; - } - size += MyStringLen(servName) + 1; - break; - } - - wchar_t *s = path.AllocBstr(size); - - item = &Items[index]; - - bool needColon = false; - if (isAltStream) - { - const UString2 &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name; - if (!name.IsEmpty()) - { - size -= name.Len(); - CopyName(s + size, name.GetRawPtr()); - } - s[--size] = ':'; - needColon = true; - } - - { - const UString2 &name = rec.FileNames[item->NameIndex].Name; - unsigned len = name.Len(); - if (len != 0) - CopyName(s + size - len, name.GetRawPtr()); - if (needColon) - s[size] = ':'; - size -= len; - } - - for (;;) - { - const wchar_t *servName; - if (item->RecIndex < kNumSysRecs - /* && && item->RecIndex != kRecIndex_RootDir */) - servName = kVirtualFolder_System; - else - { - int index2 = item->ParentFolder; - if (index2 >= 0) - { - item = &Items[index2]; - const UString2 &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name; - unsigned len = name.Len(); - size--; - if (len != 0) - { - size -= len; - CopyName(s + size, name.GetRawPtr()); - } - s[size + len] = WCHAR_PATH_SEPARATOR; - continue; - } - if (index2 == -1) - break; - servName = (index2 == k_ParentFolderIndex_Lost) ? - kVirtualFolder_Lost_Normal : - kVirtualFolder_Lost_Deleted; - } - MyStringCopy(s, servName); - s[MyStringLen(servName)] = WCHAR_PATH_SEPARATOR; - break; - } -} - -bool CDatabase::FindSecurityDescritor(UInt32 item, UInt64 &offset, UInt32 &size) const -{ - offset = 0; - size = 0; - unsigned left = 0, right = SecurOffsets.Size(); - while (left != right) - { - unsigned mid = (left + right) / 2; - size_t offs = SecurOffsets[mid]; - UInt32 midValue = Get32(((const Byte *)SecurData) + offs + 4); - if (item == midValue) - { - offset = Get64((const Byte *)SecurData + offs + 8) + 20; - size = Get32((const Byte *)SecurData + offs + 16) - 20; - return true; - } - if (item < midValue) - right = mid; - else - left = mid + 1; - } - return false; -} - -/* -static int CompareIDs(const size_t *p1, const size_t *p2, void *data) -{ - UInt32 id1 = Get32(((const Byte *)data) + *p1 + 4); - UInt32 id2 = Get32(((const Byte *)data) + *p2 + 4); - return MyCompare(id1, id2); -} -*/ - -// security data contains duplication copy after each 256 KB. -static const unsigned kSecureDuplicateStepBits = 18; - -HRESULT CDatabase::ParseSecuritySDS_2() -{ - const Byte *p = SecurData; - size_t size = SecurData.Size(); - const size_t kDuplicateStep = (size_t)1 << kSecureDuplicateStepBits; - const size_t kDuplicateMask = kDuplicateStep - 1; - size_t lim = MyMin(size, kDuplicateStep); - UInt32 idPrev = 0; - for (size_t pos = 0; pos < size && size - pos >= 20;) - { - UInt32 id = Get32(p + pos + 4); - UInt64 offs = Get64(p + pos + 8); - UInt32 entrySize = Get32(p + pos + 16); - if (offs == pos && entrySize >= 20 && lim - pos >= entrySize) - { - if (id <= idPrev) - return S_FALSE; - idPrev = id; - SecurOffsets.Add(pos); - pos += entrySize; - pos = (pos + 0xF) & ~(size_t)0xF; - if ((pos & kDuplicateMask) != 0) - continue; - } - else - pos = (pos + kDuplicateStep) & ~kDuplicateMask; - pos += kDuplicateStep; - lim = pos + kDuplicateStep; - if (lim >= size) - lim = size; - } - // we checked that IDs are sorted, so we don't need Sort - // SecurOffsets.Sort(CompareIDs, (void *)p); - return S_OK; -} - -HRESULT CDatabase::Open() -{ - Clear(); - - /* NTFS layout: - 1) main part (as specified by NumClusters). Only that part is available, if we open "\\.\c:" - 2) additional empty sectors (as specified by NumSectors) - 3) the copy of first sector (boot sector) - - We support both cases: - - the file with only main part - - full file (as raw data on partition), including the copy - of first sector (boot sector) at the end of data - - We don't support the case, when only the copy of boot sector - at the end was detected as NTFS signature. - */ - - { - const UInt32 kHeaderSize = 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)) - if (!Header.Parse(buf)) - return S_FALSE; - - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) - PhySize = Header.GetPhySize_Clusters(); - if (fileSize < PhySize) - return S_FALSE; - - UInt64 phySizeMax = Header.GetPhySize_Max(); - if (fileSize >= phySizeMax) - { - RINOK(InStream_SeekSet(InStream, Header.NumSectors << Header.SectorSizeLog)) - Byte buf2[kHeaderSize]; - if (ReadStream_FALSE(InStream, buf2, kHeaderSize) == S_OK) - { - if (memcmp(buf, buf2, kHeaderSize) == 0) - PhySize = phySizeMax; - // else _headerWarning = true; - } - } - } - - SeekToCluster(Header.MftCluster); - - // we use ByteBuf for records reading. - // so the size of ByteBuf must be >= mftRecordSize - const size_t recSize = (size_t)1 << Header.MftRecordSizeLog; - const size_t kBufSize = MyMax((size_t)(1 << 15), recSize); - ByteBuf.Alloc(kBufSize); - RINOK(ReadStream_FALSE(InStream, ByteBuf, recSize)) - { - const UInt32 allocSize = Get32(ByteBuf + 0x1C); - if (allocSize != recSize) - return S_FALSE; - } - // MftRecordSizeLog >= SectorSizeLog - const UInt32 numSectorsInRec = 1u << (Header.MftRecordSizeLog - Header.SectorSizeLog); - CMyComPtr mftStream; - CMftRec mftRec; - { - if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, 0, NULL)) - return S_FALSE; - if (!mftRec.Is_Magic_FILE()) - return S_FALSE; - mftRec.ParseDataNames(); - if (mftRec.DataRefs.IsEmpty()) - return S_FALSE; - RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream)) - if (!mftStream) - return S_FALSE; - } - - // CObjectVector SecurityAttrs; - - const UInt64 mftSize = mftRec.DataAttrs[0].Size; - if ((mftSize >> 4) > Header.GetPhySize_Clusters()) - return S_FALSE; - - { - const UInt64 numFiles = mftSize >> Header.MftRecordSizeLog; - if (numFiles > (1 << 30)) - return S_FALSE; - if (OpenCallback) - { - RINOK(OpenCallback->SetTotal(&numFiles, &mftSize)) - } - Recs.ClearAndReserve((unsigned)numFiles); - } - - for (UInt64 pos64 = 0;;) - { - if (OpenCallback) - { - const UInt64 numFiles = Recs.Size(); - if ((numFiles & 0x3FFF) == 0) - { - RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)) - } - } - size_t readSize = kBufSize; - { - const UInt64 rem = mftSize - pos64; - if (readSize > rem) - readSize = (size_t)rem; - } - if (readSize < recSize) - break; - RINOK(ReadStream_FALSE(mftStream, ByteBuf, readSize)) - pos64 += readSize; - - for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize) - { - PRF(printf("\n---------------------")); - PRF(printf("\n%5d:", Recs.Size())); - - Byte *p = ByteBuf + i; - CMftRec rec; - - CObjectVector *attrs = NULL; - unsigned recIndex = Recs.Size(); - switch (recIndex) - { - case kRecIndex_Volume: attrs = &VolAttrs; break; - // case kRecIndex_Security: attrs = &SecurityAttrs; break; - } - - if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), attrs)) - return S_FALSE; - Recs.Add(rec); - } - } - - /* - // that code looks too complex. And we can get security info without index parsing - for (i = 0; i < SecurityAttrs.Size(); i++) - { - const CAttr &attr = SecurityAttrs[i]; - if (attr.Name == L"$SII") - { - if (attr.Type == ATTR_TYPE_INDEX_ROOT) - { - const Byte *data = attr.Data; - size_t size = attr.Data.Size(); - - // Index Root - UInt32 attrType = Get32(data); - UInt32 collationRule = Get32(data + 4); - UInt32 indexAllocationEtrySizeSize = Get32(data + 8); - UInt32 clustersPerIndexRecord = Get32(data + 0xC); - data += 0x10; - - // Index Header - UInt32 firstEntryOffset = Get32(data); - UInt32 totalSize = Get32(data + 4); - UInt32 allocSize = Get32(data + 8); - UInt32 flags = Get32(data + 0xC); - - int num = 0; - for (int j = 0 ; j < num; j++) - { - if (Get32(data) != 0x1414 || // offset and size - Get32(data + 4) != 0 || - Get32(data + 8) != 0x428) // KeySize / EntrySize - break; - UInt32 flags = Get32(data + 12); - UInt32 id = Get32(data + 0x10); - if (id = Get32(data + 0x18)) - break; - UInt32 descriptorOffset = Get64(data + 0x1C); - UInt32 descriptorSize = Get64(data + 0x24); - data += 0x28; - } - // break; - } - } - } - */ - - unsigned i; - - for (i = 0; i < Recs.Size(); i++) - { - CMftRec &rec = Recs[i]; - if (!rec.Is_Magic_FILE()) - continue; - - if (!rec.BaseMftRef.IsBaseItself()) - { - const UInt64 refIndex = rec.BaseMftRef.GetIndex(); - if (refIndex >= Recs.Size()) - return S_FALSE; - CMftRec &refRec = Recs[(unsigned)refIndex]; - if (!refRec.Is_Magic_FILE()) - continue; - - bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself()); - if (rec.InUse() && refRec.InUse()) - { - if (!moveAttrs) - return S_FALSE; - } - else if (rec.InUse() || refRec.InUse()) - moveAttrs = false; - if (moveAttrs) - refRec.MoveAttrsFrom(rec); - } - } - - for (i = 0; i < Recs.Size(); i++) - { - CMftRec &rec = Recs[i]; - if (!rec.Is_Magic_FILE()) - continue; - rec.ParseDataNames(); - } - - for (i = 0; i < Recs.Size(); i++) - { - CMftRec &rec = Recs[i]; - if (!rec.Is_Magic_FILE() || !rec.BaseMftRef.IsBaseItself()) - continue; - if (i < kNumSysRecs && !_showSystemFiles) - continue; - if (!rec.InUse() && !_showDeletedFiles) - continue; - - rec.MyNumNameLinks = rec.FileNames.Size(); - - // printf("\n%4d: ", i); - - /* Actually DataAttrs / DataRefs are sorted by name. - It can not be more than one unnamed stream in DataRefs - And indexOfUnnamedStream <= 0. - */ - - int indexOfUnnamedStream = -1; - if (!rec.IsDir()) - { - FOR_VECTOR (di, rec.DataRefs) - if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty()) - { - indexOfUnnamedStream = (int)di; - break; - } - } - - if (rec.FileNames.IsEmpty()) - { - bool needShow = true; - if (i < kNumSysRecs) - { - needShow = false; - FOR_VECTOR (di, rec.DataRefs) - if (rec.GetSize(di) != 0) - { - needShow = true; - break; - } - } - if (needShow) - { - CFileNameAttr &fna = rec.FileNames.AddNew(); - // we set incorrect ParentDirRef, that will place item to [LOST] folder - fna.ParentDirRef.Val = (UInt64)(Int64)-1; - char s[16 + 16]; - ConvertUInt32ToString(i, MyStpCpy(s, "[NONAME]-")); - fna.Name.SetFromAscii(s); - fna.NameType = kFileNameType_Win32Dos; - fna.Attrib = 0; - } - } - - // bool isMainName = true; - - FOR_VECTOR (t, rec.FileNames) - { - #ifdef SHOW_DEBUG_INFO - const CFileNameAttr &fna = rec.FileNames[t]; - #endif - PRF(printf("\n %4d ", (int)fna.NameType)); - PRF_UTF16(fna.Name); - // PRF(printf(" | ")); - - if (rec.FindWin32Name_for_DosName(t) >= 0) - { - rec.MyNumNameLinks--; - continue; - } - - CItem item; - item.NameIndex = t; - item.RecIndex = i; - item.DataIndex = rec.IsDir() ? - k_Item_DataIndex_IsDir : - (indexOfUnnamedStream < 0 ? - k_Item_DataIndex_IsEmptyFile : - indexOfUnnamedStream); - - if (rec.MyItemIndex < 0) - rec.MyItemIndex = (int)Items.Size(); - item.ParentHost = (int)Items.Add(item); - - /* we can use that code to reduce the number of alt streams: - it will not show how alt streams for hard links. */ - // if (!isMainName) continue; isMainName = false; - - // unsigned numAltStreams = 0; - - FOR_VECTOR (di, rec.DataRefs) - { - if (!rec.IsDir() && (int)di == indexOfUnnamedStream) - continue; - - const UString2 &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name; - - PRF(printf("\n alt stream: ")); - PRF_UTF16(subName); - - { - // $BadClus:$Bad is sparse file for all clusters. So we skip it. - if (i == kRecIndex_BadClus && subName == L"$Bad") - continue; - } - - // numAltStreams++; - ThereAreAltStreams = true; - item.DataIndex = (int)di; - Items.Add(item); - } - } - } - - if (Recs.Size() > kRecIndex_Security) - { - const CMftRec &rec = Recs[kRecIndex_Security]; - FOR_VECTOR (di, rec.DataRefs) - { - const CAttr &attr = rec.DataAttrs[rec.DataRefs[di].Start]; - if (attr.Name == L"$SDS") - { - CMyComPtr sdsStream; - RINOK(rec.GetStream(InStream, (int)di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream)) - if (sdsStream) - { - const UInt64 size64 = attr.GetSize(); - if (size64 < (UInt32)1 << 29) - { - size_t size = (size_t)size64; - if ((((size + 1) >> kSecureDuplicateStepBits) & 1) != 0) - { - size -= (1 << kSecureDuplicateStepBits); - SecurData.Alloc(size); - if (ReadStream_FALSE(sdsStream, SecurData, size) == S_OK) - { - ParseSecuritySDS(); - break; - } - } - } - } - break; - } - } - } - - bool thereAreUnknownFolders_Normal = false; - bool thereAreUnknownFolders_Deleted = false; - - for (i = 0; i < Items.Size(); i++) - { - CItem &item = Items[i]; - const CMftRec &rec = Recs[item.RecIndex]; - const CFileNameAttr &fn = rec.FileNames[item.NameIndex]; - const CMftRef &parentDirRef = fn.ParentDirRef; - const UInt64 refIndex = parentDirRef.GetIndex(); - if (refIndex == kRecIndex_RootDir) - item.ParentFolder = -1; - else - { - int index = Find_DirItem_For_MftRec(refIndex); - if (index < 0 || - Recs[Items[index].RecIndex].SeqNumber != parentDirRef.GetNumber()) - { - if (Recs[item.RecIndex].InUse()) - { - thereAreUnknownFolders_Normal = true; - index = k_ParentFolderIndex_Lost; - } - else - { - thereAreUnknownFolders_Deleted = true; - index = k_ParentFolderIndex_Deleted; - } - } - item.ParentFolder = index; - } - } - - unsigned virtIndex = Items.Size(); - if (_showSystemFiles) - { - _systemFolderIndex = (int)(virtIndex++); - VirtFolderNames.Add(kVirtualFolder_System); - } - if (thereAreUnknownFolders_Normal) - { - _lostFolderIndex_Normal = (int)(virtIndex++); - VirtFolderNames.Add(kVirtualFolder_Lost_Normal); - } - if (thereAreUnknownFolders_Deleted) - { - _lostFolderIndex_Deleted = (int)(virtIndex++); - VirtFolderNames.Add(kVirtualFolder_Lost_Deleted); - } - - return S_OK; -} - -Z7_class_CHandler_final: - public IInArchive, - public IArchiveGetRawProps, - public IInArchiveGetStream, - public ISetProperties, - public CMyUnknownImp, - public CDatabase -{ - Z7_IFACES_IMP_UNK_4( - IInArchive, - IArchiveGetRawProps, - IInArchiveGetStream, - ISetProperties) -}; - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = 2; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) -{ - *name = NULL; - *propID = index == 0 ? kpidNtReparse : kpidNtSecure; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - int par = -1; - - if (index < Items.Size()) - { - const CItem &item = Items[index]; - - if (item.ParentHost >= 0) - { - *parentType = NParentType::kAltStream; - par = (item.RecIndex == kRecIndex_RootDir ? -1 : item.ParentHost); - } - else if (item.RecIndex < kNumSysRecs) - { - if (_showSystemFiles) - par = _systemFolderIndex; - } - else if (item.ParentFolder >= 0) - par = item.ParentFolder; - else if (item.ParentFolder == k_ParentFolderIndex_Lost) - par = _lostFolderIndex_Normal; - else if (item.ParentFolder == k_ParentFolderIndex_Deleted) - par = _lostFolderIndex_Deleted; - } - *parent = (UInt32)(Int32)par; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (propID == kpidName) - { - #ifdef MY_CPU_LE - const UString2 *s; - if (index >= Items.Size()) - s = &VirtFolderNames[index - Items.Size()]; - else - { - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - if (item.IsAltStream()) - s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name; - else - s = &rec.FileNames[item.NameIndex].Name; - } - if (s->IsEmpty()) - *data = (const wchar_t *)EmptyString; - else - *data = s->GetRawPtr(); - *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t); - *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; - #endif - return S_OK; - } - - if (propID == kpidNtReparse) - { - if (index >= Items.Size()) - return S_OK; - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - const CByteBuffer &reparse = rec.ReparseData; - - if (reparse.Size() != 0) - { - *dataSize = (UInt32)reparse.Size(); - *propType = NPropDataType::kRaw; - *data = (const Byte *)reparse; - } - } - - if (propID == kpidNtSecure) - { - if (index >= Items.Size()) - return S_OK; - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - if (rec.SiAttr.SecurityId > 0) - { - UInt64 offset; - UInt32 size; - if (FindSecurityDescritor(rec.SiAttr.SecurityId, offset, size)) - { - *dataSize = size; - *propType = NPropDataType::kRaw; - *data = (const Byte *)SecurData + offset; - } - } - } - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - if (index >= Items.Size()) - return S_OK; - IInStream *stream2; - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2); - *stream = (ISequentialInStream *)stream2; - return res; - COM_TRY_END -} - -/* -enum -{ - kpidLink2 = kpidUserDefined, - kpidLinkType, - kpidRecMTime, - kpidRecMTime2, - kpidMTime2, - kpidCTime2, - kpidATime2 -}; - -static const CStatProp kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - - // { NULL, kpidLink, VT_BSTR}, - - // { "Link 2", kpidLink2, VT_BSTR}, - // { "Link Type", kpidLinkType, VT_UI2}, - { NULL, kpidINode, VT_UI8}, - - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - - // { "Record Modified", kpidRecMTime, VT_FILETIME}, - - // { "Modified 2", kpidMTime2, VT_FILETIME}, - // { "Created 2", kpidCTime2, VT_FILETIME}, - // { "Accessed 2", kpidATime2, VT_FILETIME}, - // { "Record Modified 2", kpidRecMTime2, VT_FILETIME}, - - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidNumBlocks, VT_UI4}, - { NULL, kpidIsDeleted, VT_BOOL}, -}; -*/ - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidChangeTime, - kpidAttrib, - kpidLinks, - kpidINode, - kpidNumBlocks, - kpidNumAltStreams, - kpidIsAltStream, - kpidShortName, - kpidIsDeleted -}; - -enum -{ - kpidRecordSize = kpidUserDefined -}; - -static const CStatProp kArcProps[] = -{ - { NULL, kpidVolumeName, VT_BSTR}, - { NULL, kpidFileSystem, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidSectorSize, VT_UI4}, - { "MFT Record Size", kpidRecordSize, VT_UI4}, - { NULL, kpidHeadersSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidId, VT_UI8}, -}; - -/* -static const Byte kArcProps[] = -{ - kpidVolumeName, - kpidFileSystem, - kpidClusterSize, - kpidHeadersSize, - kpidCTime, - - kpidSectorSize, - kpidId - // kpidSectorsPerTrack, - // kpidNumHeads, - // kpidHiddenSectors -}; -*/ - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -static void NtfsTimeToProp(UInt64 t, NCOM::CPropVariant &prop) -{ - FILETIME ft; - ft.dwLowDateTime = (DWORD)t; - ft.dwHighDateTime = (DWORD)(t >> 32); - prop = ft; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL); - - switch (propID) - { - case kpidClusterSize: prop = Header.ClusterSize(); break; - case kpidPhySize: prop = PhySize; break; - /* - case kpidHeadersSize: - { - UInt64 val = 0; - for (unsigned i = 0; i < kNumSysRecs; i++) - { - printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize()); - if (i == 8) - i = i - val += Recs[i].GetPackSize(); - } - prop = val; - break; - } - */ - case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break; - case kpidMTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.MTime, prop); break; - case kpidShortComment: - case kpidVolumeName: - { - FOR_VECTOR (i, VolAttrs) - { - const CAttr &attr = VolAttrs[i]; - if (attr.Type == ATTR_TYPE_VOLUME_NAME) - { - UString2 name; - GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name); - if (!name.IsEmpty()) - prop = name.GetRawPtr(); - break; - } - } - break; - } - case kpidFileSystem: - { - AString s ("NTFS"); - FOR_VECTOR (i, VolAttrs) - { - const CAttr &attr = VolAttrs[i]; - if (attr.Type == ATTR_TYPE_VOLUME_INFO) - { - CVolInfo vi; - if (attr.ParseVolInfo(vi)) - { - s.Add_Space(); - s.Add_UInt32(vi.MajorVer); - s.Add_Dot(); - s.Add_UInt32(vi.MinorVer); - } - break; - } - } - prop = s; - break; - } - case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; - case kpidRecordSize: prop = (UInt32)1 << Header.MftRecordSizeLog; break; - case kpidId: prop = Header.SerialNumber; break; - - case kpidIsTree: prop = true; break; - case kpidIsDeleted: prop = _showDeletedFiles; break; - case kpidIsAltStream: prop = ThereAreAltStreams; break; - case kpidIsAux: prop = true; break; - case kpidINode: prop = true; break; - - case kpidWarning: - if (_lostFolderIndex_Normal >= 0) - prop = "There are lost files"; - break; - - /* - case kpidWarningFlags: - { - UInt32 flags = 0; - if (_headerWarning) - flags |= k_ErrorFlags_HeadersError; - if (flags != 0) - prop = flags; - break; - } - */ - - // case kpidMediaType: prop = Header.MediaType; break; - // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; - // case kpidNumHeads: prop = Header.NumHeads; break; - // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (index >= Items.Size()) - { - switch (propID) - { - case kpidName: - case kpidPath: - prop = VirtFolderNames[index - Items.Size()].GetRawPtr(); - break; - case kpidIsDir: prop = true; break; - case kpidIsAux: prop = true; break; - case kpidIsDeleted: - if ((int)index == _lostFolderIndex_Deleted) - prop = true; - break; - } - prop.Detach(value); - return S_OK; - } - - const CItem &item = Items[index]; - const CMftRec &rec = Recs[item.RecIndex]; - - const CAttr *data= NULL; - if (item.DataIndex >= 0) - data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; - - // const CFileNameAttr *fn = &rec.FileNames[item.NameIndex]; - /* - if (rec.FileNames.Size() > 0) - fn = &rec.FileNames[0]; - */ - - switch (propID) - { - case kpidPath: - GetItemPath(index, prop); - break; - - /* - case kpidLink: - if (!rec.ReparseAttr.SubsName.IsEmpty()) - { - prop = rec.ReparseAttr.SubsName; - } - break; - case kpidLink2: - if (!rec.ReparseAttr.PrintName.IsEmpty()) - { - prop = rec.ReparseAttr.PrintName; - } - break; - - case kpidLinkType: - if (rec.ReparseAttr.Tag != 0) - { - prop = (rec.ReparseAttr.Tag & 0xFFFF); - } - break; - */ - - case kpidINode: - { - // const CMftRec &rec = Recs[item.RecIndex]; - // prop = ((UInt64)rec.SeqNumber << 48) | item.RecIndex; - prop = (UInt32)item.RecIndex; - break; - } - case kpidStreamId: - { - if (item.DataIndex >= 0) - prop = ((UInt64)item.RecIndex << 32) | (unsigned)item.DataIndex; - break; - } - - case kpidName: - { - const UString2 *s; - if (item.IsAltStream()) - s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name; - else - s = &rec.FileNames[item.NameIndex].Name; - if (s->IsEmpty()) - prop = (const wchar_t *)EmptyString; - else - prop = s->GetRawPtr(); - break; - } - - case kpidShortName: - { - if (!item.IsAltStream()) - { - int dosNameIndex = rec.FindDosName(item.NameIndex); - if (dosNameIndex >= 0) - { - const UString2 &s = rec.FileNames[dosNameIndex].Name; - if (s.IsEmpty()) - prop = (const wchar_t *)EmptyString; - else - prop = s.GetRawPtr(); - } - } - break; - } - - case kpidIsDir: prop = item.IsDir(); break; - case kpidIsAltStream: prop = item.IsAltStream(); break; - case kpidIsDeleted: prop = !rec.InUse(); break; - case kpidIsAux: prop = false; break; - - case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; - case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; - case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break; - case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break; - - /* - case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break; - case kpidCTime2: if (fn) NtfsTimeToProp(fn->CTime, prop); break; - case kpidATime2: if (fn) NtfsTimeToProp(fn->ATime, prop); break; - case kpidRecMTime2: if (fn) NtfsTimeToProp(fn->ThisRecMTime, prop); break; - */ - - case kpidAttrib: - { - UInt32 attrib; - /* WinXP-64: The CFileNameAttr::Attrib is not updated after some changes. Why? - CSiAttr:attrib is updated better. So we use CSiAttr:Sttrib */ - /* - if (fn) - attrib = fn->Attrib; - else - */ - attrib = rec.SiAttr.Attrib; - if (item.IsDir()) - attrib |= FILE_ATTRIBUTE_DIRECTORY; - - /* some system entries can contain extra flags (Index View). - // 0x10000000 (Directory) - // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View) - But we don't need them */ - attrib &= 0xFFFF; - - prop = attrib; - break; - } - case kpidLinks: if (rec.MyNumNameLinks != 1) prop = rec.MyNumNameLinks; break; - - case kpidNumAltStreams: - { - if (!item.IsAltStream()) - { - unsigned num = rec.DataRefs.Size(); - if (num > 0) - { - if (!rec.IsDir() && rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty()) - num--; - if (num > 0) - prop = (UInt32)num; - } - } - break; - } - - case kpidSize: if (data) prop = data->GetSize(); else if (!item.IsDir()) prop = (UInt64)0; break; - case kpidPackSize: if (data) prop = data->GetPackSize(); else if (!item.IsDir()) prop = (UInt64)0; break; - case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - OpenCallback = callback; - InStream = stream; - HRESULT res; - try - { - res = CDatabase::Open(); - if (res == S_OK) - return S_OK; - } - catch(...) - { - Close(); - throw; - } - Close(); - return res; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - ClearAndClose(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = Items.Size(); - if (numItems == 0) - return S_OK; - UInt32 i; - UInt64 totalSize = 0; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - if (index >= (UInt32)Items.Size()) - continue; - const CItem &item = Items[allFilesMode ? i : indices[i]]; - const CMftRec &rec = Recs[item.RecIndex]; - if (item.DataIndex >= 0) - totalSize += rec.GetSize((unsigned)item.DataIndex); - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - UInt32 clusterSize = Header.ClusterSize(); - CByteBuffer buf(clusterSize); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create outStream; - - for (i = 0;; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (index >= (UInt32)Items.Size() || Items[index].IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const CItem &item = Items[index]; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - outStream->SetStream(realOutStream); - realOutStream.Release(); - outStream->Init(); - - const CMftRec &rec = Recs[item.RecIndex]; - - int res = NExtract::NOperationResult::kDataError; - { - CMyComPtr inStream; - HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream); - if (hres == S_FALSE) - res = NExtract::NOperationResult::kUnsupportedMethod; - else - { - RINOK(hres) - if (inStream) - { - hres = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); - if (hres != S_OK && hres != S_FALSE) - { - RINOK(hres) - } - if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK) - res = NExtract::NOperationResult::kOK; - } - } - } - if (item.DataIndex >= 0) - { - const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; - totalPackSize += data.GetPackSize(); - totalSize += data.GetSize(); - } - outStream->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(res)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = Items.Size() + VirtFolderNames.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - InitProps(); - - for (UInt32 i = 0; i < numProps; i++) - { - const wchar_t *name = names[i]; - const PROPVARIANT &prop = values[i]; - - if (StringsAreEqualNoCase_Ascii(name, "ld")) - { - RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles)) - } - else if (StringsAreEqualNoCase_Ascii(name, "ls")) - { - RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles)) - } - else if (IsString1PrefixedByString2_NoCase_Ascii(name, "mt")) - { - } - else if (IsString1PrefixedByString2_NoCase_Ascii(name, "memuse")) - { - } - else - return E_INVALIDARG; - } - return S_OK; -} - -static const Byte k_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }; - -REGISTER_ARC_I( - "NTFS", "ntfs img", NULL, 0xD9, - k_Signature, - 3, - 0, - NULL) - -}} +// NtfsHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO +// #define SHOW_DEBUG_INFO2 + +#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2) +#include +#endif + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/MethodProps.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/DummyOutStream.h" + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#define PRF_UTF16(x) PRF(printf("%S", x)) +#else +#define PRF(x) +#define PRF_UTF16(x) +#endif + +#ifdef SHOW_DEBUG_INFO2 +#define PRF2(x) x +#else +#define PRF2(x) +#endif + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(p, dest) dest = Get16(p) +#define G32(p, dest) dest = Get32(p) +#define G64(p, dest) dest = Get64(p) + +using namespace NWindows; + +namespace NArchive { +namespace Ntfs { + +static const wchar_t * const kVirtualFolder_System = L"[SYSTEM]"; +static const wchar_t * const kVirtualFolder_Lost_Normal = L"[LOST]"; +static const wchar_t * const kVirtualFolder_Lost_Deleted = L"[UNKNOWN]"; + +static const unsigned kNumSysRecs = 16; + +static const unsigned kRecIndex_Volume = 3; +static const unsigned kRecIndex_RootDir = 5; +static const unsigned kRecIndex_BadClus = 8; +static const unsigned kRecIndex_Security = 9; + +struct CHeader +{ + unsigned SectorSizeLog; + unsigned ClusterSizeLog; + unsigned MftRecordSizeLog; + // Byte MediaType; + // UInt32 NumHiddenSectors; + UInt64 NumSectors; + UInt64 NumClusters; + UInt64 MftCluster; + UInt64 SerialNumber; + // UInt16 SectorsPerTrack; + // UInt16 NumHeads; + + UInt64 GetPhySize_Clusters() const { return NumClusters << ClusterSizeLog; } + UInt64 GetPhySize_Max() const { return (NumSectors + 1) << SectorSizeLog; } + UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; } + bool Parse(const Byte *p); +}; + +static int GetLog(UInt32 num) +{ + for (int i = 0; i < 31; i++) + if (((UInt32)1 << i) == num) + return i; + return -1; +} + +bool CHeader::Parse(const Byte *p) +{ + if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) + return false; + + // int codeOffset = 0; + switch (p[0]) + { + case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break; + case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break; + default: return false; + } + unsigned sectorsPerClusterLog; + + if (memcmp(p + 3, "NTFS ", 8) != 0) + return false; + { + { + const int t = GetLog(Get16(p + 11)); + if (t < 9 || t > 12) + return false; + SectorSizeLog = (unsigned)t; + } + { + const unsigned v = p[13]; + if (v <= 0x80) + { + const int t = GetLog(v); + if (t < 0) + return false; + sectorsPerClusterLog = (unsigned)t; + } + else + sectorsPerClusterLog = 0x100 - v; + ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog; + if (ClusterSizeLog > 30) + return false; + } + } + + for (int i = 14; i < 21; i++) + if (p[i] != 0) + return false; + + // F8 : a hard disk + // F0 : high-density 3.5-inch floppy disk + if (p[21] != 0xF8) // MediaType = Fixed_Disk + return false; + if (Get16(p + 22) != 0) // NumFatSectors + return false; + // G16(p + 24, SectorsPerTrack); // 63 usually + // G16(p + 26, NumHeads); // 255 + // G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?) + if (Get32(p + 32) != 0) // NumSectors32 + return false; + + // DriveNumber = p[0x24]; + if (p[0x25] != 0) // CurrentHead + return false; + /* + NTFS-HDD: p[0x26] = 0x80 + NTFS-FLASH: p[0x26] = 0 + */ + if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig + return false; + if (p[0x27] != 0) // reserved + return false; + + NumSectors = Get64(p + 0x28); + if (NumSectors >= ((UInt64)1 << (62 - SectorSizeLog))) + return false; + + NumClusters = NumSectors >> sectorsPerClusterLog; + + G64(p + 0x30, MftCluster); // $MFT. + // G64(p + 0x38, Mft2Cluster); + G64(p + 0x48, SerialNumber); // $MFTMirr + + /* + numClusters_per_MftRecord: + numClusters_per_IndexBlock: + only low byte from 4 bytes is used. Another 3 high bytes are zeros. + If the number is positive (number < 0x80), + then it represents the number of clusters. + If the number is negative (number >= 0x80), + then the size of the file record is 2 raised to the absolute value of this number. + example: (0xF6 == -10) means 2^10 = 1024 bytes. + */ + { + UInt32 numClusters_per_MftRecord; + G32(p + 0x40, numClusters_per_MftRecord); + if (numClusters_per_MftRecord >= 0x100 || numClusters_per_MftRecord == 0) + return false; + if (numClusters_per_MftRecord < 0x80) + { + const int t = GetLog(numClusters_per_MftRecord); + if (t < 0) + return false; + MftRecordSizeLog = (unsigned)t + ClusterSizeLog; + } + else + MftRecordSizeLog = 0x100 - numClusters_per_MftRecord; + // what exact MFT record sizes are possible and supported by Windows? + // do we need to change this limit here? + const unsigned k_MftRecordSizeLog_MAX = 12; + if (MftRecordSizeLog > k_MftRecordSizeLog_MAX) + return false; + if (MftRecordSizeLog < SectorSizeLog) + return false; + } + { + UInt32 numClusters_per_IndexBlock; + G32(p + 0x44, numClusters_per_IndexBlock); + return (numClusters_per_IndexBlock < 0x100); + } +} + +struct CMftRef +{ + UInt64 Val; + + UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); } + UInt16 GetNumber() const { return (UInt16)(Val >> 48); } + bool IsBaseItself() const { return Val == 0; } + + CMftRef(): Val(0) {} +}; + +#define ATNAME(n) ATTR_TYPE_ ## n +#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v + +enum +{ + DEF_ATTR_TYPE(0x00, UNUSED), + DEF_ATTR_TYPE(0x10, STANDARD_INFO), + DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST), + DEF_ATTR_TYPE(0x30, FILE_NAME), + DEF_ATTR_TYPE(0x40, OBJECT_ID), + DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR), + DEF_ATTR_TYPE(0x60, VOLUME_NAME), + DEF_ATTR_TYPE(0x70, VOLUME_INFO), + DEF_ATTR_TYPE(0x80, DATA), + DEF_ATTR_TYPE(0x90, INDEX_ROOT), + DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION), + DEF_ATTR_TYPE(0xB0, BITMAP), + DEF_ATTR_TYPE(0xC0, REPARSE_POINT), + DEF_ATTR_TYPE(0xD0, EA_INFO), + DEF_ATTR_TYPE(0xE0, EA), + DEF_ATTR_TYPE(0xF0, PROPERTY_SET), + DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM), + DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE) +}; + + +/* WinXP-64: + Probably only one short name (dos name) per record is allowed. + There are no short names for hard links. + The pair (Win32,Dos) can be in any order. + Posix name can be after or before Win32 name +*/ + +// static const Byte kFileNameType_Posix = 0; // for hard links +static const Byte kFileNameType_Win32 = 1; // after Dos name +static const Byte kFileNameType_Dos = 2; // short name +static const Byte kFileNameType_Win32Dos = 3; // short and full name are same + +struct CFileNameAttr +{ + CMftRef ParentDirRef; + + // Probably these timestamps don't contain some useful timestamps. So we don't use them + // UInt64 CTime; + // UInt64 MTime; + // UInt64 ThisRecMTime; // xp-64: the time of previous name change (not last name change. why?) + // UInt64 ATime; + // UInt64 AllocatedSize; + // UInt64 DataSize; + // UInt16 PackedEaSize; + UString2 Name; + UInt32 Attrib; + Byte NameType; + + bool IsDos() const { return NameType == kFileNameType_Dos; } + bool IsWin32() const { return (NameType == kFileNameType_Win32); } + + bool Parse(const Byte *p, unsigned size); + + CFileNameAttr(): + Attrib(0), + NameType(0) + {} +}; + +static void GetString(const Byte *p, const unsigned len, UString2 &res) +{ + if (len == 0 && res.IsEmpty()) + return; + wchar_t *s = res.GetBuf(len); + unsigned i; + for (i = 0; i < len; i++) + { + const wchar_t c = Get16(p + i * 2); + if (c == 0) + break; + s[i] = c; + } + s[i] = 0; + res.ReleaseBuf_SetLen(i); +} + +bool CFileNameAttr::Parse(const Byte *p, unsigned size) +{ + if (size < 0x42) + return false; + G64(p + 0x00, ParentDirRef.Val); + // G64(p + 0x08, CTime); + // G64(p + 0x10, MTime); + // G64(p + 0x18, ThisRecMTime); + // G64(p + 0x20, ATime); + // G64(p + 0x28, AllocatedSize); + // G64(p + 0x30, DataSize); + G32(p + 0x38, Attrib); + // G16(p + 0x3C, PackedEaSize); + NameType = p[0x41]; + const unsigned len = p[0x40]; + if (0x42 + len * 2 > size) + return false; + if (len != 0) + GetString(p + 0x42, len, Name); + return true; +} + +struct CSiAttr +{ + UInt64 CTime; + UInt64 MTime; + UInt64 ThisRecMTime; + UInt64 ATime; + UInt32 Attrib; + + /* + UInt32 MaxVersions; + UInt32 Version; + UInt32 ClassId; + UInt32 OwnerId; + */ + UInt32 SecurityId; // SecurityId = 0 is possible ? + // UInt64 QuotaCharged; + + bool Parse(const Byte *p, unsigned size); + + CSiAttr(): + CTime(0), + MTime(0), + ThisRecMTime(0), + ATime(0), + Attrib(0), + SecurityId(0) + {} +}; + + +bool CSiAttr::Parse(const Byte *p, unsigned size) +{ + if (size < 0x24) + return false; + G64(p + 0x00, CTime); + G64(p + 0x08, MTime); + G64(p + 0x10, ThisRecMTime); + G64(p + 0x18, ATime); + G32(p + 0x20, Attrib); + SecurityId = 0; + if (size >= 0x38) + G32(p + 0x34, SecurityId); + return true; +} + +static const UInt64 kEmptyExtent = (UInt64)(Int64)-1; + +struct CExtent +{ + UInt64 Virt; + UInt64 Phy; + + bool IsEmpty() const { return Phy == kEmptyExtent; } +}; + +struct CVolInfo +{ + Byte MajorVer; + Byte MinorVer; + // UInt16 Flags; + + bool Parse(const Byte *p, unsigned size); +}; + +bool CVolInfo::Parse(const Byte *p, unsigned size) +{ + if (size < 12) + return false; + MajorVer = p[8]; + MinorVer = p[9]; + // Flags = Get16(p + 10); + return true; +} + +struct CAttr +{ + UInt32 Type; + + Byte NonResident; + + // Non-Resident + Byte CompressionUnit; + + // UInt32 Len; + UString2 Name; + // UInt16 Flags; + // UInt16 Instance; + CByteBuffer Data; + + // Non-Resident + UInt64 LowVcn; + UInt64 HighVcn; + UInt64 AllocatedSize; + UInt64 Size; + UInt64 PackSize; + UInt64 InitializedSize; + + // Resident + // UInt16 ResidentFlags; + + bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; } + + UInt32 Parse(const Byte *p, unsigned size); + bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); } + bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); } + bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.Size()); } + bool ParseExtents(CRecordVector &extents, UInt64 numClustersMax, unsigned compressionUnit) const; + UInt64 GetSize() const { return NonResident ? Size : Data.Size(); } + UInt64 GetPackSize() const + { + if (!NonResident) + return Data.Size(); + if (CompressionUnit != 0) + return PackSize; + return AllocatedSize; + } +}; + +#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } + +static int CompareAttr(void *const *elem1, void *const *elem2, void *) +{ + const CAttr &a1 = *(*((const CAttr *const *)elem1)); + const CAttr &a2 = *(*((const CAttr *const *)elem2)); + RINOZ(MyCompare(a1.Type, a2.Type)) + if (a1.Name.IsEmpty()) + { + if (!a2.Name.IsEmpty()) + return -1; + } + else if (a2.Name.IsEmpty()) + return 1; + else + { + RINOZ(a1.Name.Compare(a2.Name.GetRawPtr())) + } + return MyCompare(a1.LowVcn, a2.LowVcn); +} + +UInt32 CAttr::Parse(const Byte *p, unsigned size) +{ + if (size < 4) + return 0; + G32(p, Type); + if (Type == 0xFFFFFFFF) + return 8; // required size is 4, but attributes are 8 bytes aligned. So we return 8 + if (size < 0x18) + return 0; + + PRF(printf(" T=%2X", Type)); + + UInt32 len = Get32(p + 4); + PRF(printf(" L=%3d", len)); + if (len > size) + return 0; + if ((len & 7) != 0) + return 0; + NonResident = p[8]; + { + unsigned nameLen = p[9]; + UInt32 nameOffset = Get16(p + 0x0A); + if (nameLen != 0) + { + if (nameOffset + nameLen * 2 > len) + return 0; + GetString(p + nameOffset, nameLen, Name); + PRF(printf(" N=")); + PRF_UTF16(Name); + } + } + + // G16(p + 0x0C, Flags); + // G16(p + 0x0E, Instance); + // PRF(printf(" F=%4X", Flags)); + // PRF(printf(" Inst=%d", Instance)); + + UInt32 dataSize; + UInt32 offs; + + if (NonResident) + { + if (len < 0x40) + return 0; + PRF(printf(" NR")); + G64(p + 0x10, LowVcn); + G64(p + 0x18, HighVcn); + G64(p + 0x28, AllocatedSize); + G64(p + 0x30, Size); + G64(p + 0x38, InitializedSize); + G16(p + 0x20, offs); + CompressionUnit = p[0x22]; + + PackSize = Size; + if (CompressionUnit != 0) + { + if (len < 0x48) + return 0; + G64(p + 0x40, PackSize); + PRF(printf(" PS=%I64x", PackSize)); + } + + // PRF(printf("\n")); + PRF(printf(" ASize=%4I64d", AllocatedSize)); + PRF(printf(" Size=%I64d", Size)); + PRF(printf(" IS=%I64d", InitializedSize)); + PRF(printf(" Low=%I64d", LowVcn)); + PRF(printf(" High=%I64d", HighVcn)); + PRF(printf(" CU=%d", (unsigned)CompressionUnit)); + dataSize = len - offs; + } + else + { + if (len < 0x18) + return 0; + G32(p + 0x10, dataSize); + G16(p + 0x14, offs); + // G16(p + 0x16, ResidentFlags); + PRF(printf(" RES")); + PRF(printf(" dataSize=%3d", dataSize)); + // PRF(printf(" ResFlags=%4X", ResidentFlags)); + } + + if (offs > len || dataSize > len || len - dataSize < offs) + return 0; + + Data.CopyFrom(p + offs, dataSize); + + #ifdef SHOW_DEBUG_INFO + PRF(printf(" : ")); + for (unsigned i = 0; i < Data.Size(); i++) + { + PRF(printf(" %02X", (unsigned)Data[i])); + } + #endif + + return len; +} + + +bool CAttr::ParseExtents(CRecordVector &extents, UInt64 numClustersMax, unsigned compressionUnit) const +{ + const Byte *p = Data; + unsigned size = (unsigned)Data.Size(); + UInt64 vcn = LowVcn; + UInt64 lcn = 0; + const UInt64 highVcn1 = HighVcn + 1; + + if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63) + return false; + + extents.DeleteBack(); + + PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn)); + + while (size > 0) + { + const unsigned b = *p++; + size--; + if (b == 0) + break; + unsigned num = b & 0xF; + if (num == 0 || num > 8 || num > size) + return false; + + UInt64 vSize = 0; + { + unsigned i = num; + do vSize = (vSize << 8) | p[--i]; while (i); + } + if (vSize == 0) + return false; + p += num; + size -= num; + if ((highVcn1 - vcn) < vSize) + return false; + + CExtent e; + e.Virt = vcn; + vcn += vSize; + + num = b >> 4; + if (num > 8 || num > size) + return false; + + if (num == 0) + { + // Sparse + + /* if Unit is compressed, it can have many Elements for each compressed Unit: + and last Element for unit MUST be without LCN. + Element 0: numCompressedClusters2, LCN_0 + Element 1: numCompressedClusters2, LCN_1 + ... + Last Element : (16 - total_clusters_in_previous_elements), no LCN + */ + + // sparse is not allowed for (compressionUnit == 0) ? Why ? + if (compressionUnit == 0) + return false; + + e.Phy = kEmptyExtent; + } + else + { + Int64 v = (signed char)p[num - 1]; + { + for (unsigned i = num - 1; i != 0;) + v = (v << 8) | p[--i]; + } + p += num; + size -= num; + lcn = (UInt64)((Int64)lcn + v); + if (lcn > numClustersMax) + return false; + e.Phy = lcn; + } + + extents.Add(e); + } + + CExtent e; + e.Phy = kEmptyExtent; + e.Virt = vcn; + extents.Add(e); + return (highVcn1 == vcn); +} + + +static const UInt64 kEmptyTag = (UInt64)(Int64)-1; + +static const unsigned kNumCacheChunksLog = 1; +static const size_t kNumCacheChunks = (size_t)1 << kNumCacheChunksLog; + +Z7_CLASS_IMP_IInStream( + CInStream +) + UInt64 _virtPos; + UInt64 _physPos; + UInt64 _curRem; + bool _sparseMode; +public: + bool InUse; +private: + unsigned _chunkSizeLog; + CByteBuffer _inBuf; + CByteBuffer _outBuf; +public: + UInt64 Size; + UInt64 InitializedSize; + unsigned BlockSizeLog; + unsigned CompressionUnit; + CRecordVector Extents; + CMyComPtr Stream; +private: + UInt64 _tags[kNumCacheChunks]; + + HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); } + UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); } +public: + HRESULT InitAndSeek(unsigned compressionUnit) + { + CompressionUnit = compressionUnit; + _chunkSizeLog = BlockSizeLog + CompressionUnit; + if (compressionUnit != 0) + { + UInt32 cuSize = GetCuSize(); + _inBuf.Alloc(cuSize); + _outBuf.Alloc(kNumCacheChunks << _chunkSizeLog); + } + for (size_t i = 0; i < kNumCacheChunks; i++) + _tags[i] = kEmptyTag; + + _sparseMode = false; + _curRem = 0; + _virtPos = 0; + _physPos = 0; + const CExtent &e = Extents[0]; + if (!e.IsEmpty()) + _physPos = e.Phy << BlockSizeLog; + return SeekToPhys(); + } +}; + +static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen) +{ + size_t destSize = 0; + while (destSize < destLen) + { + if (srcLen < 2 || (destSize & 0xFFF) != 0) + break; + UInt32 comprSize; + { + const UInt32 v = Get16(src); + if (v == 0) + break; + src += 2; + srcLen -= 2; + comprSize = (v & 0xFFF) + 1; + if (comprSize > srcLen) + break; + srcLen -= comprSize; + if ((v & 0x8000) == 0) + { + if (comprSize != (1 << 12)) + break; + memcpy(dest + destSize, src, comprSize); + src += comprSize; + destSize += comprSize; + continue; + } + } + { + if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0) + return 0; + unsigned numDistBits = 4; + UInt32 sbOffset = 0; + UInt32 pos = 0; + + do + { + comprSize--; + for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1) + { + if ((mask & 1) == 0) + { + if (sbOffset >= (1 << 12)) + return 0; + dest[destSize++] = src[pos++]; + sbOffset++; + comprSize--; + } + else + { + if (comprSize < 2) + return 0; + const UInt32 v = Get16(src + pos); + pos += 2; + comprSize -= 2; + + while (((sbOffset - 1) >> numDistBits) != 0) + numDistBits++; + + UInt32 len = (v & (0xFFFF >> numDistBits)) + 3; + if (sbOffset + len > (1 << 12)) + return 0; + UInt32 dist = (v >> (16 - numDistBits)); + if (dist >= sbOffset) + return 0; + const size_t offs = 1 + dist; + Byte *p = dest + destSize - offs; + destSize += len; + sbOffset += len; + const Byte *lim = p + len; + p[offs] = *p; ++p; + p[offs] = *p; ++p; + do + p[offs] = *p; + while (++p != lim); + } + } + } + while (comprSize > 0); + src += pos; + } + } + return destSize; +} + +Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= Size) + return (Size == _virtPos) ? S_OK: E_FAIL; + if (size == 0) + return S_OK; + { + const UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + + if (_virtPos >= InitializedSize) + { + memset((Byte *)data, 0, size); + _virtPos += size; + *processedSize = size; + return S_OK; + } + + { + const UInt64 rem = InitializedSize - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + + while (_curRem == 0) + { + const UInt64 cacheTag = _virtPos >> _chunkSizeLog; + const size_t cacheIndex = (size_t)cacheTag & (kNumCacheChunks - 1); + + if (_tags[cacheIndex] == cacheTag) + { + const size_t chunkSize = (size_t)1 << _chunkSizeLog; + const size_t offset = (size_t)_virtPos & (chunkSize - 1); + size_t cur = chunkSize - offset; + if (cur > size) + cur = size; + memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur); + *processedSize = (UInt32)cur; + _virtPos += cur; + return S_OK; + } + + PRF2(printf("\nVirtPos = %6d", _virtPos)); + + const UInt32 comprUnitSize = (UInt32)1 << CompressionUnit; + const UInt64 virtBlock = _virtPos >> BlockSizeLog; + const UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1); + + unsigned left = 0, right = Extents.Size(); + for (;;) + { + unsigned mid = (left + right) / 2; + if (mid == left) + break; + if (virtBlock2 < Extents[mid].Virt) + right = mid; + else + left = mid; + } + + bool isCompressed = false; + const UInt64 virtBlock2End = virtBlock2 + comprUnitSize; + if (CompressionUnit != 0) + for (unsigned i = left; i < Extents.Size(); i++) + { + const CExtent &e = Extents[i]; + if (e.Virt >= virtBlock2End) + break; + if (e.IsEmpty()) + { + isCompressed = true; + break; + } + } + + unsigned i; + for (i = left; Extents[i + 1].Virt <= virtBlock; i++); + + _sparseMode = false; + if (!isCompressed) + { + const CExtent &e = Extents[i]; + UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog); + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()) + } + UInt64 next = Extents[i + 1].Virt; + if (next > virtBlock2End) + next &= ~((UInt64)comprUnitSize - 1); + next <<= BlockSizeLog; + if (next > Size) + next = Size; + _curRem = next - _virtPos; + break; + } + + bool thereArePhy = false; + + for (unsigned i2 = left; i2 < Extents.Size(); i2++) + { + const CExtent &e = Extents[i2]; + if (e.Virt >= virtBlock2End) + break; + if (!e.IsEmpty()) + { + thereArePhy = true; + break; + } + } + + if (!thereArePhy) + { + _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos; + _sparseMode = true; + break; + } + + size_t offs = 0; + UInt64 curVirt = virtBlock2; + + for (i = left; i < Extents.Size(); i++) + { + const CExtent &e = Extents[i]; + if (e.IsEmpty()) + break; + if (e.Virt >= virtBlock2End) + return S_FALSE; + const UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog; + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()) + } + UInt64 numChunks = Extents[i + 1].Virt - curVirt; + if (curVirt + numChunks > virtBlock2End) + numChunks = virtBlock2End - curVirt; + const size_t compressed = (size_t)numChunks << BlockSizeLog; + RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed)) + curVirt += numChunks; + _physPos += compressed; + offs += compressed; + } + + const size_t destLenMax = GetCuSize(); + size_t destLen = destLenMax; + const UInt64 rem = Size - (virtBlock2 << BlockSizeLog); + if (destLen > rem) + destLen = (size_t)rem; + + Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog); + const size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs); + _tags[cacheIndex] = cacheTag; + + // some files in Vista have destSize > destLen + if (destSizeRes < destLen) + { + memset(dest, 0, destLenMax); + if (InUse) + return S_FALSE; + } + } + + if (size > _curRem) + size = (UInt32)_curRem; + HRESULT res = S_OK; + if (_sparseMode) + memset(data, 0, size); + else + { + res = Stream->Read(data, size, &size); + _physPos += size; + } + if (processedSize) + *processedSize = size; + _virtPos += size; + _curRem -= size; + return res; +} + +Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + if (_virtPos != (UInt64)offset) + { + _curRem = 0; + _virtPos = (UInt64)offset; + } + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + +static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector &attrs, + unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector &Extents) +{ + { + CExtent e; + e.Virt = 0; + e.Phy = kEmptyExtent; + Extents.Add(e); + } + + const CAttr &attr0 = attrs[attrIndex]; + + /* + if (attrs[attrIndexLim - 1].HighVcn + 1 != (attr0.AllocatedSize >> clusterSizeLog)) + { + } + */ + + if (attr0.AllocatedSize < attr0.Size || + (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) || + (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0) + return S_FALSE; + + for (unsigned i = attrIndex; i < attrIndexLim; i++) + if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit)) + return S_FALSE; + + UInt64 packSizeCalc = 0; + FOR_VECTOR (k, Extents) + { + CExtent &e = Extents[k]; + if (!e.IsEmpty()) + packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog; + PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt)); + PRF2(printf(" Pos = %4I64X", e.Phy)); + } + + if (attr0.CompressionUnit != 0) + { + if (packSizeCalc != attr0.PackSize) + return S_FALSE; + } + else + { + if (packSizeCalc != attr0.AllocatedSize) + return S_FALSE; + } + return S_OK; +} + +struct CDataRef +{ + unsigned Start; + unsigned Num; +}; + +static const UInt32 kMagic_FILE = 0x454C4946; +static const UInt32 kMagic_BAAD = 0x44414142; + +// 22.02: we support some rare case magic values: +static const UInt32 kMagic_INDX = 0x58444e49; +static const UInt32 kMagic_HOLE = 0x454c4f48; +static const UInt32 kMagic_RSTR = 0x52545352; +static const UInt32 kMagic_RCRD = 0x44524352; +static const UInt32 kMagic_CHKD = 0x444b4843; +static const UInt32 kMagic_FFFFFFFF = 0xFFFFFFFF; + + +struct CMftRec +{ + UInt32 Magic; + // UInt64 Lsn; + UInt16 SeqNumber; // Number of times this mft record has been reused + UInt16 Flags; + // UInt16 LinkCount; + // UInt16 NextAttrInstance; + CMftRef BaseMftRef; + // UInt32 ThisRecNumber; + + UInt32 MyNumNameLinks; + int MyItemIndex; // index in Items[] of main item for that record, or -1 if there is no item for that record + + CObjectVector DataAttrs; + CObjectVector FileNames; + CRecordVector DataRefs; + // CAttr SecurityAttr; + + CSiAttr SiAttr; + + CByteBuffer ReparseData; + + int FindWin32Name_for_DosName(unsigned dosNameIndex) const + { + const CFileNameAttr &cur = FileNames[dosNameIndex]; + if (cur.IsDos()) + for (unsigned i = 0; i < FileNames.Size(); i++) + { + const CFileNameAttr &next = FileNames[i]; + if (next.IsWin32() && cur.ParentDirRef.Val == next.ParentDirRef.Val) + return (int)i; + } + return -1; + } + + int FindDosName(unsigned nameIndex) const + { + const CFileNameAttr &cur = FileNames[nameIndex]; + if (cur.IsWin32()) + for (unsigned i = 0; i < FileNames.Size(); i++) + { + const CFileNameAttr &next = FileNames[i]; + if (next.IsDos() && cur.ParentDirRef.Val == next.ParentDirRef.Val) + return (int)i; + } + return -1; + } + + /* + bool IsAltStream(int dataIndex) const + { + return dataIndex >= 0 && ( + (IsDir() || + !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty())); + } + */ + + void MoveAttrsFrom(CMftRec &src) + { + DataAttrs += src.DataAttrs; + FileNames += src.FileNames; + src.DataAttrs.ClearAndFree(); + src.FileNames.ClearAndFree(); + } + + UInt64 GetPackSize() const + { + UInt64 res = 0; + FOR_VECTOR (i, DataRefs) + res += DataAttrs[DataRefs[i].Start].GetPackSize(); + return res; + } + + bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector *attrs); + + bool Is_Magic_Empty() const + { + // what exact Magic values are possible for empty and unused records? + const UInt32 k_Magic_Unused_MAX = 5; // 22.02 + return (Magic <= k_Magic_Unused_MAX); + } + bool Is_Magic_FILE() const { return (Magic == kMagic_FILE); } + // bool Is_Magic_BAAD() const { return (Magic == kMagic_BAAD); } + bool Is_Magic_CanIgnore() const + { + return Is_Magic_Empty() + || Magic == kMagic_BAAD + || Magic == kMagic_INDX + || Magic == kMagic_HOLE + || Magic == kMagic_RSTR + || Magic == kMagic_RCRD + || Magic == kMagic_CHKD + || Magic == kMagic_FFFFFFFF; + } + + bool InUse() const { return (Flags & 1) != 0; } + bool IsDir() const { return (Flags & 2) != 0; } + + void ParseDataNames(); + HRESULT GetStream(IInStream *mainStream, int dataIndex, + unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const; + unsigned GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const; + + UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); } + + CMftRec(): + SeqNumber(0), + Flags(0), + MyNumNameLinks(0), + MyItemIndex(-1) {} +}; + +void CMftRec::ParseDataNames() +{ + DataRefs.Clear(); + DataAttrs.Sort(CompareAttr, NULL); + + for (unsigned i = 0; i < DataAttrs.Size();) + { + CDataRef ref; + ref.Start = i; + for (i++; i < DataAttrs.Size(); i++) + if (DataAttrs[ref.Start].Name != DataAttrs[i].Name) + break; + ref.Num = i - ref.Start; + DataRefs.Add(ref); + } +} + +HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex, + unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const +{ + *destStream = NULL; + CBufferInStream *streamSpec = new CBufferInStream; + CMyComPtr streamTemp = streamSpec; + + if (dataIndex >= 0) + if ((unsigned)dataIndex < DataRefs.Size()) + { + const CDataRef &ref = DataRefs[dataIndex]; + unsigned numNonResident = 0; + unsigned i; + for (i = ref.Start; i < ref.Start + ref.Num; i++) + if (DataAttrs[i].NonResident) + numNonResident++; + + const CAttr &attr0 = DataAttrs[ref.Start]; + + if (numNonResident != 0 || ref.Num != 1) + { + if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) + return S_FALSE; + CInStream *ss = new CInStream; + CMyComPtr streamTemp2 = ss; + RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, ss->Extents)) + ss->Size = attr0.Size; + ss->InitializedSize = attr0.InitializedSize; + ss->Stream = mainStream; + ss->BlockSizeLog = clusterSizeLog; + ss->InUse = InUse(); + RINOK(ss->InitAndSeek(attr0.CompressionUnit)) + *destStream = streamTemp2.Detach(); + return S_OK; + } + + streamSpec->Buf = attr0.Data; + } + + streamSpec->Init(); + *destStream = streamTemp.Detach(); + return S_OK; +} + +unsigned CMftRec::GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const +{ + if (dataIndex < 0) + return 0; + { + const CDataRef &ref = DataRefs[dataIndex]; + unsigned numNonResident = 0; + unsigned i; + for (i = ref.Start; i < ref.Start + ref.Num; i++) + if (DataAttrs[i].NonResident) + numNonResident++; + + const CAttr &attr0 = DataAttrs[ref.Start]; + + if (numNonResident != 0 || ref.Num != 1) + { + if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported()) + return 0; // error; + CRecordVector extents; + if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK) + return 0; // error; + return extents.Size() - 1; + } + // if (attr0.Data.Size() != 0) + // return 1; + return 0; + } +} + +bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, + CObjectVector *attrs) +{ + G32(p, Magic); + if (!Is_Magic_FILE()) + return Is_Magic_CanIgnore(); + + { + UInt32 usaOffset; + UInt32 numUsaItems; + G16(p + 0x04, usaOffset); + G16(p + 0x06, numUsaItems); + + /* NTFS stores (usn) to 2 last bytes in each sector (before writing record to disk). + Original values of these two bytes are stored in table. + So we restore original data from table */ + + if ((usaOffset & 1) != 0 + || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2 + || numUsaItems == 0 + || numUsaItems - 1 != numSectors) + return false; + + if (usaOffset >= 0x30) // NTFS 3.1+ + { + UInt32 iii = Get32(p + 0x2C); + if (iii != recNumber) + { + // ntfs-3g probably writes 0 (that probably is incorrect value) to this field for unused records. + // so we support that "bad" case. + if (iii != 0) + return false; + } + } + + UInt16 usn = Get16(p + usaOffset); + // PRF(printf("\nusn = %d", usn)); + for (UInt32 i = 1; i < numUsaItems; i++) + { + void *pp = p + (i << sectorSizeLog) - 2; + if (Get16(pp) != usn) + return false; + SetUi16(pp, Get16(p + usaOffset + i * 2)) + } + } + + // G64(p + 0x08, Lsn); + G16(p + 0x10, SeqNumber); + // G16(p + 0x12, LinkCount); + // PRF(printf(" L=%d", LinkCount)); + const UInt32 attrOffs = Get16(p + 0x14); + G16(p + 0x16, Flags); + PRF(printf(" F=%4X", Flags)); + + const UInt32 bytesInUse = Get32(p + 0x18); + const UInt32 bytesAlloc = Get32(p + 0x1C); + G64(p + 0x20, BaseMftRef.Val); + if (BaseMftRef.Val != 0) + { + PRF(printf(" BaseRef=%d", (int)BaseMftRef.Val)); + // return false; // Check it; + } + // G16(p + 0x28, NextAttrInstance); + + UInt32 limit = numSectors << sectorSizeLog; + if (attrOffs >= limit + || (attrOffs & 7) != 0 + || (bytesInUse & 7) != 0 + || bytesInUse > limit + || bytesAlloc != limit) + return false; + + limit = bytesInUse; + + for (UInt32 t = attrOffs;;) + { + if (t >= limit) + return false; + + CAttr attr; + // PRF(printf("\n %2d:", Attrs.Size())); + PRF(printf("\n")); + UInt32 len = attr.Parse(p + t, limit - t); + if (len == 0 || limit - t < len) + return false; + t += len; + if (attr.Type == 0xFFFFFFFF) + { + if (t != limit) + return false; + break; + } + switch (attr.Type) + { + case ATTR_TYPE_FILE_NAME: + { + CFileNameAttr fna; + if (!attr.ParseFileName(fna)) + return false; + FileNames.Add(fna); + PRF(printf(" flags = %4x\n ", (int)fna.NameType)); + PRF_UTF16(fna.Name); + break; + } + case ATTR_TYPE_STANDARD_INFO: + if (!attr.ParseSi(SiAttr)) + return false; + break; + case ATTR_TYPE_DATA: + DataAttrs.Add(attr); + break; + case ATTR_TYPE_REPARSE_POINT: + ReparseData = attr.Data; + break; + /* + case ATTR_TYPE_SECURITY_DESCRIPTOR: + SecurityAttr = attr; + break; + */ + default: + if (attrs) + attrs->Add(attr); + break; + } + } + + return true; +} + +/* + NTFS probably creates empty DATA_ATTRIBUTE for empty file, + But it doesn't do it for + $Secure (:$SDS), + $Extend\$Quota + $Extend\$ObjId + $Extend\$Reparse +*/ + +static const int k_Item_DataIndex_IsEmptyFile = -1; // file without unnamed data stream +static const int k_Item_DataIndex_IsDir = -2; + +// static const int k_ParentFolderIndex_Root = -1; +static const int k_ParentFolderIndex_Lost = -2; +static const int k_ParentFolderIndex_Deleted = -3; + +struct CItem +{ + unsigned RecIndex; // index in Recs array + unsigned NameIndex; // index in CMftRec::FileNames + + int DataIndex; /* index in CMftRec::DataRefs + -1: file without unnamed data stream + -2: for directories */ + + int ParentFolder; /* index in Items array + -1: for root items + -2: [LOST] folder + -3: [UNKNOWN] folder (deleted lost) */ + int ParentHost; /* index in Items array, if it's AltStream + -1: if it's not AltStream */ + + CItem(): DataIndex(k_Item_DataIndex_IsDir), ParentFolder(-1), ParentHost(-1) {} + + bool IsAltStream() const { return ParentHost != -1; } + bool IsDir() const { return DataIndex == k_Item_DataIndex_IsDir; } + // check it !!! + // probably NTFS for empty file still creates empty DATA_ATTRIBUTE + // But it doesn't do it for $Secure:$SDS +}; + +struct CDatabase +{ + CRecordVector Items; + CObjectVector Recs; + CMyComPtr InStream; + CHeader Header; + UInt64 PhySize; + + IArchiveOpenCallback *OpenCallback; + + CByteBuffer ByteBuf; + + CObjectVector VolAttrs; + + CByteBuffer SecurData; + CRecordVector SecurOffsets; + + // bool _headerWarning; + bool ThereAreAltStreams; + + bool _showSystemFiles; + bool _showDeletedFiles; + CObjectVector VirtFolderNames; + UString EmptyString; + + int _systemFolderIndex; + int _lostFolderIndex_Normal; + int _lostFolderIndex_Deleted; + + void InitProps() + { + _showSystemFiles = true; + // we show SystemFiles by default since it's difficult to track $Extend\* system files + // it must be fixed later + _showDeletedFiles = false; + } + + CDatabase() { InitProps(); } + ~CDatabase() { ClearAndClose(); } + + void Clear(); + void ClearAndClose(); + + void GetItemPath(unsigned index, NCOM::CPropVariant &path) const; + HRESULT Open(); + + HRESULT SeekToCluster(UInt64 cluster); + + int Find_DirItem_For_MftRec(UInt64 recIndex) const + { + if (recIndex >= Recs.Size()) + return -1; + const CMftRec &rec = Recs[(unsigned)recIndex]; + if (!rec.IsDir()) + return -1; + return rec.MyItemIndex; + /* + unsigned left = 0, right = Items.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + const CItem &item = Items[mid]; + UInt64 midValue = item.RecIndex; + if (recIndex == midValue) + { + // if item is not dir (file or alt stream we don't return it) + // if (item.DataIndex < 0) + if (item.IsDir()) + return mid; + right = mid; + } + else if (recIndex < midValue) + right = mid; + else + left = mid + 1; + } + return -1; + */ + } + + bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const; + + HRESULT ParseSecuritySDS_2(); + void ParseSecuritySDS() + { + HRESULT res = ParseSecuritySDS_2(); + if (res != S_OK) + { + SecurOffsets.Clear(); + SecurData.Free(); + } + } + +}; + +HRESULT CDatabase::SeekToCluster(UInt64 cluster) +{ + return InStream_SeekSet(InStream, cluster << Header.ClusterSizeLog); +} + +void CDatabase::Clear() +{ + Items.Clear(); + Recs.Clear(); + SecurOffsets.Clear(); + SecurData.Free(); + VirtFolderNames.Clear(); + _systemFolderIndex = -1; + _lostFolderIndex_Normal = -1; + _lostFolderIndex_Deleted = -1; + ThereAreAltStreams = false; + // _headerWarning = false; + PhySize = 0; +} + +void CDatabase::ClearAndClose() +{ + Clear(); + InStream.Release(); +} + + +static void CopyName(wchar_t *dest, const wchar_t *src) +{ + for (;;) + { + wchar_t c = *src++; + // 18.06 + if (c == '\\' || c == '/') + c = '_'; + *dest++ = c; + if (c == 0) + return; + } +} + +void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const +{ + const CItem *item = &Items[index]; + unsigned size = 0; + const CMftRec &rec = Recs[item->RecIndex]; + size += rec.FileNames[item->NameIndex].Name.Len(); + + bool isAltStream = item->IsAltStream(); + + if (isAltStream) + { + const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start]; + if (item->RecIndex == kRecIndex_RootDir) + { + wchar_t *s = path.AllocBstr(data.Name.Len() + 1); + s[0] = L':'; + if (!data.Name.IsEmpty()) + CopyName(s + 1, data.Name.GetRawPtr()); + return; + } + + size += data.Name.Len(); + size++; + } + + for (unsigned i = 0;; i++) + { + if (i > 256) + { + path = "[TOO-LONG]"; + return; + } + const wchar_t *servName; + if (item->RecIndex < kNumSysRecs + /* && item->RecIndex != kRecIndex_RootDir */) + servName = kVirtualFolder_System; + else + { + int index2 = item->ParentFolder; + if (index2 >= 0) + { + item = &Items[index2]; + size += Recs[item->RecIndex].FileNames[item->NameIndex].Name.Len() + 1; + continue; + } + if (index2 == -1) + break; + servName = (index2 == k_ParentFolderIndex_Lost) ? + kVirtualFolder_Lost_Normal : + kVirtualFolder_Lost_Deleted; + } + size += MyStringLen(servName) + 1; + break; + } + + wchar_t *s = path.AllocBstr(size); + + item = &Items[index]; + + bool needColon = false; + if (isAltStream) + { + const UString2 &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name; + if (!name.IsEmpty()) + { + size -= name.Len(); + CopyName(s + size, name.GetRawPtr()); + } + s[--size] = ':'; + needColon = true; + } + + { + const UString2 &name = rec.FileNames[item->NameIndex].Name; + unsigned len = name.Len(); + if (len != 0) + CopyName(s + size - len, name.GetRawPtr()); + if (needColon) + s[size] = ':'; + size -= len; + } + + for (;;) + { + const wchar_t *servName; + if (item->RecIndex < kNumSysRecs + /* && && item->RecIndex != kRecIndex_RootDir */) + servName = kVirtualFolder_System; + else + { + int index2 = item->ParentFolder; + if (index2 >= 0) + { + item = &Items[index2]; + const UString2 &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name; + unsigned len = name.Len(); + size--; + if (len != 0) + { + size -= len; + CopyName(s + size, name.GetRawPtr()); + } + s[size + len] = WCHAR_PATH_SEPARATOR; + continue; + } + if (index2 == -1) + break; + servName = (index2 == k_ParentFolderIndex_Lost) ? + kVirtualFolder_Lost_Normal : + kVirtualFolder_Lost_Deleted; + } + MyStringCopy(s, servName); + s[MyStringLen(servName)] = WCHAR_PATH_SEPARATOR; + break; + } +} + +bool CDatabase::FindSecurityDescritor(UInt32 item, UInt64 &offset, UInt32 &size) const +{ + offset = 0; + size = 0; + unsigned left = 0, right = SecurOffsets.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + size_t offs = SecurOffsets[mid]; + UInt32 midValue = Get32(((const Byte *)SecurData) + offs + 4); + if (item == midValue) + { + offset = Get64((const Byte *)SecurData + offs + 8) + 20; + size = Get32((const Byte *)SecurData + offs + 16) - 20; + return true; + } + if (item < midValue) + right = mid; + else + left = mid + 1; + } + return false; +} + +/* +static int CompareIDs(const size_t *p1, const size_t *p2, void *data) +{ + UInt32 id1 = Get32(((const Byte *)data) + *p1 + 4); + UInt32 id2 = Get32(((const Byte *)data) + *p2 + 4); + return MyCompare(id1, id2); +} +*/ + +// security data contains duplication copy after each 256 KB. +static const unsigned kSecureDuplicateStepBits = 18; + +HRESULT CDatabase::ParseSecuritySDS_2() +{ + const Byte *p = SecurData; + size_t size = SecurData.Size(); + const size_t kDuplicateStep = (size_t)1 << kSecureDuplicateStepBits; + const size_t kDuplicateMask = kDuplicateStep - 1; + size_t lim = MyMin(size, kDuplicateStep); + UInt32 idPrev = 0; + for (size_t pos = 0; pos < size && size - pos >= 20;) + { + UInt32 id = Get32(p + pos + 4); + UInt64 offs = Get64(p + pos + 8); + UInt32 entrySize = Get32(p + pos + 16); + if (offs == pos && entrySize >= 20 && lim - pos >= entrySize) + { + if (id <= idPrev) + return S_FALSE; + idPrev = id; + SecurOffsets.Add(pos); + pos += entrySize; + pos = (pos + 0xF) & ~(size_t)0xF; + if ((pos & kDuplicateMask) != 0) + continue; + } + else + pos = (pos + kDuplicateStep) & ~kDuplicateMask; + pos += kDuplicateStep; + lim = pos + kDuplicateStep; + if (lim >= size) + lim = size; + } + // we checked that IDs are sorted, so we don't need Sort + // SecurOffsets.Sort(CompareIDs, (void *)p); + return S_OK; +} + +HRESULT CDatabase::Open() +{ + Clear(); + + /* NTFS layout: + 1) main part (as specified by NumClusters). Only that part is available, if we open "\\.\c:" + 2) additional empty sectors (as specified by NumSectors) + 3) the copy of first sector (boot sector) + + We support both cases: + - the file with only main part + - full file (as raw data on partition), including the copy + of first sector (boot sector) at the end of data + + We don't support the case, when only the copy of boot sector + at the end was detected as NTFS signature. + */ + + { + const UInt32 kHeaderSize = 512; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize)) + if (!Header.Parse(buf)) + return S_FALSE; + + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize)) + PhySize = Header.GetPhySize_Clusters(); + if (fileSize < PhySize) + return S_FALSE; + + UInt64 phySizeMax = Header.GetPhySize_Max(); + if (fileSize >= phySizeMax) + { + RINOK(InStream_SeekSet(InStream, Header.NumSectors << Header.SectorSizeLog)) + Byte buf2[kHeaderSize]; + if (ReadStream_FALSE(InStream, buf2, kHeaderSize) == S_OK) + { + if (memcmp(buf, buf2, kHeaderSize) == 0) + PhySize = phySizeMax; + // else _headerWarning = true; + } + } + } + + SeekToCluster(Header.MftCluster); + + // we use ByteBuf for records reading. + // so the size of ByteBuf must be >= mftRecordSize + const size_t recSize = (size_t)1 << Header.MftRecordSizeLog; + const size_t kBufSize = MyMax((size_t)(1 << 15), recSize); + ByteBuf.Alloc(kBufSize); + RINOK(ReadStream_FALSE(InStream, ByteBuf, recSize)) + { + const UInt32 allocSize = Get32(ByteBuf + 0x1C); + if (allocSize != recSize) + return S_FALSE; + } + // MftRecordSizeLog >= SectorSizeLog + const UInt32 numSectorsInRec = 1u << (Header.MftRecordSizeLog - Header.SectorSizeLog); + CMyComPtr mftStream; + CMftRec mftRec; + { + if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, 0, NULL)) + return S_FALSE; + if (!mftRec.Is_Magic_FILE()) + return S_FALSE; + mftRec.ParseDataNames(); + if (mftRec.DataRefs.IsEmpty()) + return S_FALSE; + RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream)) + if (!mftStream) + return S_FALSE; + } + + // CObjectVector SecurityAttrs; + + const UInt64 mftSize = mftRec.DataAttrs[0].Size; + if ((mftSize >> 4) > Header.GetPhySize_Clusters()) + return S_FALSE; + + { + const UInt64 numFiles = mftSize >> Header.MftRecordSizeLog; + if (numFiles > (1 << 30)) + return S_FALSE; + if (OpenCallback) + { + RINOK(OpenCallback->SetTotal(&numFiles, &mftSize)) + } + Recs.ClearAndReserve((unsigned)numFiles); + } + + for (UInt64 pos64 = 0;;) + { + if (OpenCallback) + { + const UInt64 numFiles = Recs.Size(); + if ((numFiles & 0x3FFF) == 0) + { + RINOK(OpenCallback->SetCompleted(&numFiles, &pos64)) + } + } + size_t readSize = kBufSize; + { + const UInt64 rem = mftSize - pos64; + if (readSize > rem) + readSize = (size_t)rem; + } + if (readSize < recSize) + break; + RINOK(ReadStream_FALSE(mftStream, ByteBuf, readSize)) + pos64 += readSize; + + for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize) + { + PRF(printf("\n---------------------")); + PRF(printf("\n%5d:", Recs.Size())); + + Byte *p = ByteBuf + i; + CMftRec rec; + + CObjectVector *attrs = NULL; + unsigned recIndex = Recs.Size(); + switch (recIndex) + { + case kRecIndex_Volume: attrs = &VolAttrs; break; + // case kRecIndex_Security: attrs = &SecurityAttrs; break; + } + + if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), attrs)) + return S_FALSE; + Recs.Add(rec); + } + } + + /* + // that code looks too complex. And we can get security info without index parsing + for (i = 0; i < SecurityAttrs.Size(); i++) + { + const CAttr &attr = SecurityAttrs[i]; + if (attr.Name == L"$SII") + { + if (attr.Type == ATTR_TYPE_INDEX_ROOT) + { + const Byte *data = attr.Data; + size_t size = attr.Data.Size(); + + // Index Root + UInt32 attrType = Get32(data); + UInt32 collationRule = Get32(data + 4); + UInt32 indexAllocationEtrySizeSize = Get32(data + 8); + UInt32 clustersPerIndexRecord = Get32(data + 0xC); + data += 0x10; + + // Index Header + UInt32 firstEntryOffset = Get32(data); + UInt32 totalSize = Get32(data + 4); + UInt32 allocSize = Get32(data + 8); + UInt32 flags = Get32(data + 0xC); + + int num = 0; + for (int j = 0 ; j < num; j++) + { + if (Get32(data) != 0x1414 || // offset and size + Get32(data + 4) != 0 || + Get32(data + 8) != 0x428) // KeySize / EntrySize + break; + UInt32 flags = Get32(data + 12); + UInt32 id = Get32(data + 0x10); + if (id = Get32(data + 0x18)) + break; + UInt32 descriptorOffset = Get64(data + 0x1C); + UInt32 descriptorSize = Get64(data + 0x24); + data += 0x28; + } + // break; + } + } + } + */ + + unsigned i; + + for (i = 0; i < Recs.Size(); i++) + { + CMftRec &rec = Recs[i]; + if (!rec.Is_Magic_FILE()) + continue; + + if (!rec.BaseMftRef.IsBaseItself()) + { + const UInt64 refIndex = rec.BaseMftRef.GetIndex(); + if (refIndex >= Recs.Size()) + return S_FALSE; + CMftRec &refRec = Recs[(unsigned)refIndex]; + if (!refRec.Is_Magic_FILE()) + continue; + + bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself()); + if (rec.InUse() && refRec.InUse()) + { + if (!moveAttrs) + return S_FALSE; + } + else if (rec.InUse() || refRec.InUse()) + moveAttrs = false; + if (moveAttrs) + refRec.MoveAttrsFrom(rec); + } + } + + for (i = 0; i < Recs.Size(); i++) + { + CMftRec &rec = Recs[i]; + if (!rec.Is_Magic_FILE()) + continue; + rec.ParseDataNames(); + } + + for (i = 0; i < Recs.Size(); i++) + { + CMftRec &rec = Recs[i]; + if (!rec.Is_Magic_FILE() || !rec.BaseMftRef.IsBaseItself()) + continue; + if (i < kNumSysRecs && !_showSystemFiles) + continue; + if (!rec.InUse() && !_showDeletedFiles) + continue; + + rec.MyNumNameLinks = rec.FileNames.Size(); + + // printf("\n%4d: ", i); + + /* Actually DataAttrs / DataRefs are sorted by name. + It can not be more than one unnamed stream in DataRefs + And indexOfUnnamedStream <= 0. + */ + + int indexOfUnnamedStream = -1; + if (!rec.IsDir()) + { + FOR_VECTOR (di, rec.DataRefs) + if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty()) + { + indexOfUnnamedStream = (int)di; + break; + } + } + + if (rec.FileNames.IsEmpty()) + { + bool needShow = true; + if (i < kNumSysRecs) + { + needShow = false; + FOR_VECTOR (di, rec.DataRefs) + if (rec.GetSize(di) != 0) + { + needShow = true; + break; + } + } + if (needShow) + { + CFileNameAttr &fna = rec.FileNames.AddNew(); + // we set incorrect ParentDirRef, that will place item to [LOST] folder + fna.ParentDirRef.Val = (UInt64)(Int64)-1; + char s[16 + 16]; + ConvertUInt32ToString(i, MyStpCpy(s, "[NONAME]-")); + fna.Name.SetFromAscii(s); + fna.NameType = kFileNameType_Win32Dos; + fna.Attrib = 0; + } + } + + // bool isMainName = true; + + FOR_VECTOR (t, rec.FileNames) + { + #ifdef SHOW_DEBUG_INFO + const CFileNameAttr &fna = rec.FileNames[t]; + #endif + PRF(printf("\n %4d ", (int)fna.NameType)); + PRF_UTF16(fna.Name); + // PRF(printf(" | ")); + + if (rec.FindWin32Name_for_DosName(t) >= 0) + { + rec.MyNumNameLinks--; + continue; + } + + CItem item; + item.NameIndex = t; + item.RecIndex = i; + item.DataIndex = rec.IsDir() ? + k_Item_DataIndex_IsDir : + (indexOfUnnamedStream < 0 ? + k_Item_DataIndex_IsEmptyFile : + indexOfUnnamedStream); + + if (rec.MyItemIndex < 0) + rec.MyItemIndex = (int)Items.Size(); + item.ParentHost = (int)Items.Add(item); + + /* we can use that code to reduce the number of alt streams: + it will not show how alt streams for hard links. */ + // if (!isMainName) continue; isMainName = false; + + // unsigned numAltStreams = 0; + + FOR_VECTOR (di, rec.DataRefs) + { + if (!rec.IsDir() && (int)di == indexOfUnnamedStream) + continue; + + const UString2 &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name; + + PRF(printf("\n alt stream: ")); + PRF_UTF16(subName); + + { + // $BadClus:$Bad is sparse file for all clusters. So we skip it. + if (i == kRecIndex_BadClus && subName == L"$Bad") + continue; + } + + // numAltStreams++; + ThereAreAltStreams = true; + item.DataIndex = (int)di; + Items.Add(item); + } + } + } + + if (Recs.Size() > kRecIndex_Security) + { + const CMftRec &rec = Recs[kRecIndex_Security]; + FOR_VECTOR (di, rec.DataRefs) + { + const CAttr &attr = rec.DataAttrs[rec.DataRefs[di].Start]; + if (attr.Name == L"$SDS") + { + CMyComPtr sdsStream; + RINOK(rec.GetStream(InStream, (int)di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream)) + if (sdsStream) + { + const UInt64 size64 = attr.GetSize(); + if (size64 < (UInt32)1 << 29) + { + size_t size = (size_t)size64; + if ((((size + 1) >> kSecureDuplicateStepBits) & 1) != 0) + { + size -= (1 << kSecureDuplicateStepBits); + SecurData.Alloc(size); + if (ReadStream_FALSE(sdsStream, SecurData, size) == S_OK) + { + ParseSecuritySDS(); + break; + } + } + } + } + break; + } + } + } + + bool thereAreUnknownFolders_Normal = false; + bool thereAreUnknownFolders_Deleted = false; + + for (i = 0; i < Items.Size(); i++) + { + CItem &item = Items[i]; + const CMftRec &rec = Recs[item.RecIndex]; + const CFileNameAttr &fn = rec.FileNames[item.NameIndex]; + const CMftRef &parentDirRef = fn.ParentDirRef; + const UInt64 refIndex = parentDirRef.GetIndex(); + if (refIndex == kRecIndex_RootDir) + item.ParentFolder = -1; + else + { + int index = Find_DirItem_For_MftRec(refIndex); + if (index < 0 || + Recs[Items[index].RecIndex].SeqNumber != parentDirRef.GetNumber()) + { + if (Recs[item.RecIndex].InUse()) + { + thereAreUnknownFolders_Normal = true; + index = k_ParentFolderIndex_Lost; + } + else + { + thereAreUnknownFolders_Deleted = true; + index = k_ParentFolderIndex_Deleted; + } + } + item.ParentFolder = index; + } + } + + unsigned virtIndex = Items.Size(); + if (_showSystemFiles) + { + _systemFolderIndex = (int)(virtIndex++); + VirtFolderNames.Add(kVirtualFolder_System); + } + if (thereAreUnknownFolders_Normal) + { + _lostFolderIndex_Normal = (int)(virtIndex++); + VirtFolderNames.Add(kVirtualFolder_Lost_Normal); + } + if (thereAreUnknownFolders_Deleted) + { + _lostFolderIndex_Deleted = (int)(virtIndex++); + VirtFolderNames.Add(kVirtualFolder_Lost_Deleted); + } + + return S_OK; +} + +Z7_class_CHandler_final: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public ISetProperties, + public CMyUnknownImp, + public CDatabase +{ + Z7_IFACES_IMP_UNK_4( + IInArchive, + IArchiveGetRawProps, + IInArchiveGetStream, + ISetProperties) +}; + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = 2; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) +{ + *name = NULL; + *propID = index == 0 ? kpidNtReparse : kpidNtSecure; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + int par = -1; + + if (index < Items.Size()) + { + const CItem &item = Items[index]; + + if (item.ParentHost >= 0) + { + *parentType = NParentType::kAltStream; + par = (item.RecIndex == kRecIndex_RootDir ? -1 : item.ParentHost); + } + else if (item.RecIndex < kNumSysRecs) + { + if (_showSystemFiles) + par = _systemFolderIndex; + } + else if (item.ParentFolder >= 0) + par = item.ParentFolder; + else if (item.ParentFolder == k_ParentFolderIndex_Lost) + par = _lostFolderIndex_Normal; + else if (item.ParentFolder == k_ParentFolderIndex_Deleted) + par = _lostFolderIndex_Deleted; + } + *parent = (UInt32)(Int32)par; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidName) + { + #ifdef MY_CPU_LE + const UString2 *s; + if (index >= Items.Size()) + s = &VirtFolderNames[index - Items.Size()]; + else + { + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + if (item.IsAltStream()) + s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name; + else + s = &rec.FileNames[item.NameIndex].Name; + } + if (s->IsEmpty()) + *data = (const wchar_t *)EmptyString; + else + *data = s->GetRawPtr(); + *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t); + *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE; + #endif + return S_OK; + } + + if (propID == kpidNtReparse) + { + if (index >= Items.Size()) + return S_OK; + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + const CByteBuffer &reparse = rec.ReparseData; + + if (reparse.Size() != 0) + { + *dataSize = (UInt32)reparse.Size(); + *propType = NPropDataType::kRaw; + *data = (const Byte *)reparse; + } + } + + if (propID == kpidNtSecure) + { + if (index >= Items.Size()) + return S_OK; + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + if (rec.SiAttr.SecurityId > 0) + { + UInt64 offset; + UInt32 size; + if (FindSecurityDescritor(rec.SiAttr.SecurityId, offset, size)) + { + *dataSize = size; + *propType = NPropDataType::kRaw; + *data = (const Byte *)SecurData + offset; + } + } + } + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + if (index >= Items.Size()) + return S_OK; + IInStream *stream2; + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2); + *stream = (ISequentialInStream *)stream2; + return res; + COM_TRY_END +} + +/* +enum +{ + kpidLink2 = kpidUserDefined, + kpidLinkType, + kpidRecMTime, + kpidRecMTime2, + kpidMTime2, + kpidCTime2, + kpidATime2 +}; + +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8}, + + // { NULL, kpidLink, VT_BSTR}, + + // { "Link 2", kpidLink2, VT_BSTR}, + // { "Link Type", kpidLinkType, VT_UI2}, + { NULL, kpidINode, VT_UI8}, + + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidATime, VT_FILETIME}, + + // { "Record Modified", kpidRecMTime, VT_FILETIME}, + + // { "Modified 2", kpidMTime2, VT_FILETIME}, + // { "Created 2", kpidCTime2, VT_FILETIME}, + // { "Accessed 2", kpidATime2, VT_FILETIME}, + // { "Record Modified 2", kpidRecMTime2, VT_FILETIME}, + + { NULL, kpidAttrib, VT_UI4}, + { NULL, kpidNumBlocks, VT_UI4}, + { NULL, kpidIsDeleted, VT_BOOL}, +}; +*/ + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidChangeTime, + kpidAttrib, + kpidLinks, + kpidINode, + kpidNumBlocks, + kpidNumAltStreams, + kpidIsAltStream, + kpidShortName, + kpidIsDeleted +}; + +enum +{ + kpidRecordSize = kpidUserDefined +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidVolumeName, VT_BSTR}, + { NULL, kpidFileSystem, VT_BSTR}, + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidSectorSize, VT_UI4}, + { "MFT Record Size", kpidRecordSize, VT_UI4}, + { NULL, kpidHeadersSize, VT_UI8}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidId, VT_UI8}, +}; + +/* +static const Byte kArcProps[] = +{ + kpidVolumeName, + kpidFileSystem, + kpidClusterSize, + kpidHeadersSize, + kpidCTime, + + kpidSectorSize, + kpidId + // kpidSectorsPerTrack, + // kpidNumHeads, + // kpidHiddenSectors +}; +*/ + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +static void NtfsTimeToProp(UInt64 t, NCOM::CPropVariant &prop) +{ + FILETIME ft; + ft.dwLowDateTime = (DWORD)t; + ft.dwHighDateTime = (DWORD)(t >> 32); + prop = ft; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL); + + switch (propID) + { + case kpidClusterSize: prop = Header.ClusterSize(); break; + case kpidPhySize: prop = PhySize; break; + /* + case kpidHeadersSize: + { + UInt64 val = 0; + for (unsigned i = 0; i < kNumSysRecs; i++) + { + printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize()); + if (i == 8) + i = i + val += Recs[i].GetPackSize(); + } + prop = val; + break; + } + */ + case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break; + case kpidMTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.MTime, prop); break; + case kpidShortComment: + case kpidVolumeName: + { + FOR_VECTOR (i, VolAttrs) + { + const CAttr &attr = VolAttrs[i]; + if (attr.Type == ATTR_TYPE_VOLUME_NAME) + { + UString2 name; + GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name); + if (!name.IsEmpty()) + prop = name.GetRawPtr(); + break; + } + } + break; + } + case kpidFileSystem: + { + AString s ("NTFS"); + FOR_VECTOR (i, VolAttrs) + { + const CAttr &attr = VolAttrs[i]; + if (attr.Type == ATTR_TYPE_VOLUME_INFO) + { + CVolInfo vi; + if (attr.ParseVolInfo(vi)) + { + s.Add_Space(); + s.Add_UInt32(vi.MajorVer); + s.Add_Dot(); + s.Add_UInt32(vi.MinorVer); + } + break; + } + } + prop = s; + break; + } + case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break; + case kpidRecordSize: prop = (UInt32)1 << Header.MftRecordSizeLog; break; + case kpidId: prop = Header.SerialNumber; break; + + case kpidIsTree: prop = true; break; + case kpidIsDeleted: prop = _showDeletedFiles; break; + case kpidIsAltStream: prop = ThereAreAltStreams; break; + case kpidIsAux: prop = true; break; + case kpidINode: prop = true; break; + + case kpidWarning: + if (_lostFolderIndex_Normal >= 0) + prop = "There are lost files"; + break; + + /* + case kpidWarningFlags: + { + UInt32 flags = 0; + if (_headerWarning) + flags |= k_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + */ + + // case kpidMediaType: prop = Header.MediaType; break; + // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break; + // case kpidNumHeads: prop = Header.NumHeads; break; + // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (index >= Items.Size()) + { + switch (propID) + { + case kpidName: + case kpidPath: + prop = VirtFolderNames[index - Items.Size()].GetRawPtr(); + break; + case kpidIsDir: prop = true; break; + case kpidIsAux: prop = true; break; + case kpidIsDeleted: + if ((int)index == _lostFolderIndex_Deleted) + prop = true; + break; + } + prop.Detach(value); + return S_OK; + } + + const CItem &item = Items[index]; + const CMftRec &rec = Recs[item.RecIndex]; + + const CAttr *data= NULL; + if (item.DataIndex >= 0) + data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; + + // const CFileNameAttr *fn = &rec.FileNames[item.NameIndex]; + /* + if (rec.FileNames.Size() > 0) + fn = &rec.FileNames[0]; + */ + + switch (propID) + { + case kpidPath: + GetItemPath(index, prop); + break; + + /* + case kpidLink: + if (!rec.ReparseAttr.SubsName.IsEmpty()) + { + prop = rec.ReparseAttr.SubsName; + } + break; + case kpidLink2: + if (!rec.ReparseAttr.PrintName.IsEmpty()) + { + prop = rec.ReparseAttr.PrintName; + } + break; + + case kpidLinkType: + if (rec.ReparseAttr.Tag != 0) + { + prop = (rec.ReparseAttr.Tag & 0xFFFF); + } + break; + */ + + case kpidINode: + { + // const CMftRec &rec = Recs[item.RecIndex]; + // prop = ((UInt64)rec.SeqNumber << 48) | item.RecIndex; + prop = (UInt32)item.RecIndex; + break; + } + case kpidStreamId: + { + if (item.DataIndex >= 0) + prop = ((UInt64)item.RecIndex << 32) | (unsigned)item.DataIndex; + break; + } + + case kpidName: + { + const UString2 *s; + if (item.IsAltStream()) + s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name; + else + s = &rec.FileNames[item.NameIndex].Name; + if (s->IsEmpty()) + prop = (const wchar_t *)EmptyString; + else + prop = s->GetRawPtr(); + break; + } + + case kpidShortName: + { + if (!item.IsAltStream()) + { + int dosNameIndex = rec.FindDosName(item.NameIndex); + if (dosNameIndex >= 0) + { + const UString2 &s = rec.FileNames[dosNameIndex].Name; + if (s.IsEmpty()) + prop = (const wchar_t *)EmptyString; + else + prop = s.GetRawPtr(); + } + } + break; + } + + case kpidIsDir: prop = item.IsDir(); break; + case kpidIsAltStream: prop = item.IsAltStream(); break; + case kpidIsDeleted: prop = !rec.InUse(); break; + case kpidIsAux: prop = false; break; + + case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; + case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; + case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break; + case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break; + + /* + case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break; + case kpidCTime2: if (fn) NtfsTimeToProp(fn->CTime, prop); break; + case kpidATime2: if (fn) NtfsTimeToProp(fn->ATime, prop); break; + case kpidRecMTime2: if (fn) NtfsTimeToProp(fn->ThisRecMTime, prop); break; + */ + + case kpidAttrib: + { + UInt32 attrib; + /* WinXP-64: The CFileNameAttr::Attrib is not updated after some changes. Why? + CSiAttr:attrib is updated better. So we use CSiAttr:Sttrib */ + /* + if (fn) + attrib = fn->Attrib; + else + */ + attrib = rec.SiAttr.Attrib; + if (item.IsDir()) + attrib |= FILE_ATTRIBUTE_DIRECTORY; + + /* some system entries can contain extra flags (Index View). + // 0x10000000 (Directory) + // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View) + But we don't need them */ + attrib &= 0xFFFF; + + prop = attrib; + break; + } + case kpidLinks: if (rec.MyNumNameLinks != 1) prop = rec.MyNumNameLinks; break; + + case kpidNumAltStreams: + { + if (!item.IsAltStream()) + { + unsigned num = rec.DataRefs.Size(); + if (num > 0) + { + if (!rec.IsDir() && rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty()) + num--; + if (num > 0) + prop = (UInt32)num; + } + } + break; + } + + case kpidSize: if (data) prop = data->GetSize(); else if (!item.IsDir()) prop = (UInt64)0; break; + case kpidPackSize: if (data) prop = data->GetPackSize(); else if (!item.IsDir()) prop = (UInt64)0; break; + case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + OpenCallback = callback; + InStream = stream; + HRESULT res; + try + { + res = CDatabase::Open(); + if (res == S_OK) + return S_OK; + } + catch(...) + { + Close(); + throw; + } + Close(); + return res; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + ClearAndClose(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Items.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + if (index >= (UInt32)Items.Size()) + continue; + const CItem &item = Items[allFilesMode ? i : indices[i]]; + const CMftRec &rec = Recs[item.RecIndex]; + if (item.DataIndex >= 0) + totalSize += rec.GetSize((unsigned)item.DataIndex); + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + UInt32 clusterSize = Header.ClusterSize(); + CByteBuffer buf(clusterSize); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create outStream; + + for (i = 0;; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (index >= (UInt32)Items.Size() || Items[index].IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const CItem &item = Items[index]; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + outStream->SetStream(realOutStream); + realOutStream.Release(); + outStream->Init(); + + const CMftRec &rec = Recs[item.RecIndex]; + + int res = NExtract::NOperationResult::kDataError; + { + CMyComPtr inStream; + HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream); + if (hres == S_FALSE) + res = NExtract::NOperationResult::kUnsupportedMethod; + else + { + RINOK(hres) + if (inStream) + { + hres = copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps); + if (hres != S_OK && hres != S_FALSE) + { + RINOK(hres) + } + if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK) + res = NExtract::NOperationResult::kOK; + } + } + } + if (item.DataIndex >= 0) + { + const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start]; + totalPackSize += data.GetPackSize(); + totalSize += data.GetSize(); + } + outStream->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(res)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = Items.Size() + VirtFolderNames.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + InitProps(); + + for (UInt32 i = 0; i < numProps; i++) + { + const wchar_t *name = names[i]; + const PROPVARIANT &prop = values[i]; + + if (StringsAreEqualNoCase_Ascii(name, "ld")) + { + RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles)) + } + else if (StringsAreEqualNoCase_Ascii(name, "ls")) + { + RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles)) + } + else if (IsString1PrefixedByString2_NoCase_Ascii(name, "mt")) + { + } + else if (IsString1PrefixedByString2_NoCase_Ascii(name, "memuse")) + { + } + else + return E_INVALIDARG; + } + return S_OK; +} + +static const Byte k_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }; + +REGISTER_ARC_I( + "NTFS", "ntfs img", NULL, 0xD9, + k_Signature, + 3, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 763ba3ef6..8a0ff0561 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -1,3415 +1,3415 @@ -// PeHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/DynamicBuffer.h" -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(offs, v) v = Get16(p + (offs)) -#define G32(offs, v) v = Get32(p + (offs)) -#define G32_signed(offs, v) v = (Int32)Get32(p + (offs)) -#define G64(offs, v) v = Get64(p + (offs)) - -#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } - -using namespace NWindows; - -namespace NArchive { -namespace NPe { - -static const UInt32 k_Signature32 = 0x00004550; - -static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res) -{ - const UInt32 kBufSizeMax = (UInt32)1 << 15; - UInt32 bufSize = kBufSizeMax; - CByteBuffer buffer(bufSize); - Byte *buf = buffer; - UInt32 sum = 0; - UInt32 pos = 0; - for (;;) - { - UInt32 rem = size - pos; - if (rem > bufSize) - rem = bufSize; - if (rem == 0) - break; - size_t processed = rem; - RINOK(ReadStream(stream, buf, &processed)) - - for (unsigned j = 0; j < 4; j++) - { - UInt32 e = excludePos + j; - if (pos <= e) - { - e -= pos; - if (e < processed) - buf[e] = 0; - } - } - - const unsigned kStep = (1 << 4); - { - for (size_t i = processed; (i & (kStep - 1)) != 0; i++) - buf[i] = 0; - } - { - const Byte *buf2 = buf; - const Byte *bufLimit = buf + processed; - UInt64 sum2 = 0; - for (; buf2 < bufLimit; buf2 += kStep) - { - UInt64 sum3 = (UInt64)Get32(buf2) - + Get32(buf2 + 4) - + Get32(buf2 + 8) - + Get32(buf2 + 12); - sum2 += sum3; - } - sum2 = (UInt32)(sum2) + (UInt64)(sum2 >> 32); - UInt32 sum3 = ((UInt32)sum2 + (UInt32)(sum2 >> 32)); - sum += (sum3 & 0xFFFF) + (sum3 >> 16); - sum = (sum & 0xFFFF) + (sum >> 16); - sum = (sum & 0xFFFF) + (sum >> 16); - } - - pos += (UInt32)processed; - if (rem != processed) - break; - } - res = sum + pos; - return S_OK; -} - - -struct CVersion -{ - UInt16 Major; - UInt16 Minor; - - void Parse(const Byte *p) - { - G16(0, Major); - G16(2, Minor); - } - void ToProp(NCOM::CPropVariant &prop); -}; - -void CVersion::ToProp(NCOM::CPropVariant &prop) -{ - char sz[32]; - ConvertUInt32ToString(Major, sz); - unsigned len = MyStringLen(sz); - sz[len] = '.'; - ConvertUInt32ToString(Minor, sz + len + 1); - prop = sz; -} - -static const unsigned kCoffHeaderSize = 20; -static const unsigned kPeHeaderSize = 4 + kCoffHeaderSize; -static const unsigned k_OptHeader32_Size_MIN = 96; -static const unsigned k_OptHeader64_Size_MIN = 112; - -static const UInt32 PE_IMAGE_FILE_DLL = (1 << 13); - -struct CHeader -{ - UInt16 Machine; - UInt16 NumSections; - UInt32 Time; - UInt32 PointerToSymbolTable; - UInt32 NumSymbols; - UInt16 OptHeaderSize; - UInt16 Flags; - - void ParseBase(const Byte *p); - bool ParseCoff(const Byte *p); - bool ParsePe(const Byte *p); - bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; } -}; - -void CHeader::ParseBase(const Byte *p) -{ - G16( 0, Machine); - G16( 2, NumSections); - G32( 4, Time); - G32( 8, PointerToSymbolTable); - G32(12, NumSymbols); - G16(16, OptHeaderSize); - G16(18, Flags); -} - -bool CHeader::ParsePe(const Byte *p) -{ - if (Get32(p) != k_Signature32) - return false; - ParseBase(p + 4); - return OptHeaderSize >= k_OptHeader32_Size_MIN; -} - -struct CDirLink -{ - UInt32 Va; - UInt32 Size; - - CDirLink(): Va(0), Size(0) {} - void Parse(const Byte *p) - { - G32(0, Va); - G32(4, Size); - } -}; - - -// IMAGE_DIRECTORY_ENTRY_* -static const char * const g_Dir_Names[] = -{ - "EXPORT" - , "IMPORT" - , "RESOURCE" - , "EXCEPTION" - , "SECURITY" - , "BASERELOC" - , "DEBUG" - , "ARCHITECTURE" // "COPYRIGHT" - , "GLOBALPTR" - , "TLS" - , "LOAD_CONFIG" - , "BOUND_IMPORT" - , "IAT" - , "DELAY_IMPORT" - , "COM_DESCRIPTOR" -}; - -enum -{ - kDirLink_EXCEPTION = 3, - kDirLink_Certificate = 4, - kDirLink_BASERELOC = 5, - kDirLink_Debug = 6 -}; - -static const UInt32 kNumDirItemsMax = 16; - -struct CDebugEntry -{ - UInt32 Flags; - UInt32 Time; - CVersion Ver; - UInt32 Type; - UInt32 Size; - UInt32 Va; - UInt32 Pa; - - void Parse(const Byte *p) - { - G32(0, Flags); - G32(4, Time); - Ver.Parse(p + 8); - G32(12, Type); - G32(16, Size); - G32(20, Va); - G32(24, Pa); - } -}; - -static const UInt32 k_CheckSum_Field_Offset = 64; - -static const UInt32 PE_OptHeader_Magic_32 = 0x10B; -static const UInt32 PE_OptHeader_Magic_64 = 0x20B; - -static const UInt32 k_SubSystems_EFI_First = 10; -static const UInt32 k_SubSystems_EFI_Last = 13; - -struct COptHeader -{ - UInt16 Magic; - Byte LinkerVerMajor; - Byte LinkerVerMinor; - - UInt32 CodeSize; - UInt32 InitDataSize; - UInt32 UninitDataSize; - - // UInt32 AddressOfEntryPoint; - // UInt32 BaseOfCode; // VA(.text) == 0x1000 in most cases - // UInt32 BaseOfData32; - UInt64 ImageBase; - - UInt32 SectAlign; - UInt32 FileAlign; - - CVersion OsVer; - CVersion ImageVer; - CVersion SubsysVer; - - UInt32 ImageSize; - UInt32 HeadersSize; - UInt32 CheckSum; - UInt16 SubSystem; - UInt16 DllCharacts; - - UInt64 StackReserve; - UInt64 StackCommit; - UInt64 HeapReserve; - UInt64 HeapCommit; - - UInt32 NumDirItems; - CDirLink DirItems[kNumDirItemsMax]; - - bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; } - bool Parse(const Byte *p, UInt32 size); - - int GetNumFileAlignBits() const - { - for (unsigned i = 0; i < 32; i++) - if (((UInt32)1 << i) == FileAlign) - return (int)i; - return -1; - } - - bool IsSybSystem_EFI() const - { - return - SubSystem >= k_SubSystems_EFI_First && - SubSystem <= k_SubSystems_EFI_Last; - } -}; - -// size is 16-bit -bool COptHeader::Parse(const Byte *p, UInt32 size) -{ - if (size < k_OptHeader32_Size_MIN) - return false; - Magic = Get16(p); - switch (Magic) - { - case PE_OptHeader_Magic_32: - case PE_OptHeader_Magic_64: - break; - default: - return false; - } - LinkerVerMajor = p[2]; - LinkerVerMinor = p[3]; - - G32( 4, CodeSize); - G32( 8, InitDataSize); - G32(12, UninitDataSize); - // G32(16, AddressOfEntryPoint); - // G32(20, BaseOfCode); - - G32(32, SectAlign); - G32(36, FileAlign); - - OsVer.Parse(p + 40); - ImageVer.Parse(p + 44); - SubsysVer.Parse(p + 48); - - // reserved = Get32(p + 52); - - G32(56, ImageSize); - G32(60, HeadersSize); - G32(64, CheckSum); - G16(68, SubSystem); - G16(70, DllCharacts); - - UInt32 pos; - if (Is64Bit()) - { - if (size < k_OptHeader64_Size_MIN) - return false; - // BaseOfData32 = 0; - G64(24, ImageBase); - G64(72, StackReserve); - G64(80, StackCommit); - G64(88, HeapReserve); - G64(96, HeapCommit); - pos = 108; - } - else - { - // G32(24, BaseOfData32); - G32(28, ImageBase); - G32(72, StackReserve); - G32(76, StackCommit); - G32(80, HeapReserve); - G32(84, HeapCommit); - pos = 92; - } - - UInt32 numDirItems; - G32(pos, numDirItems); - NumDirItems = numDirItems; - if (numDirItems > (1 << 13)) - return false; - pos += 4; - if (pos + 8 * numDirItems > size) - return false; - memset((void *)DirItems, 0, sizeof(DirItems)); - if (numDirItems > kNumDirItemsMax) - numDirItems = kNumDirItemsMax; - for (UInt32 i = 0; i < numDirItems; i++) - DirItems[i].Parse(p + pos + i * 8); - return true; -} - -static const UInt32 kSectionSize = 40; - -struct CSection -{ - AString Name; - - UInt32 ExtractSize; - UInt32 VSize; - UInt32 Va; - UInt32 PSize; - UInt32 Pa; - UInt32 Flags; - UInt32 Time; - // UInt16 NumRelocs; // is set to zero for executable images - bool IsRealSect; - bool IsDebug; - bool IsAdditionalSection; - - CSection(): - ExtractSize(0), - IsRealSect(false), - IsDebug(false), - IsAdditionalSection(false) - // , NumRelocs(0) - {} - - void Set_Size_for_all(UInt32 size) - { - PSize = VSize = ExtractSize = size; - } - - UInt32 GetSize_Extract() const - { - return ExtractSize; - } - - void UpdateTotalSize(UInt32 &totalSize) const - { - const UInt32 t = Pa + PSize; - if (totalSize < t) - totalSize = t; - } - - void Parse(const Byte *p); - - int Compare(const CSection &s) const - { - RINOZ(MyCompare(Pa, s.Pa)) - const UInt32 size1 = GetSize_Extract(); - const UInt32 size2 = s.GetSize_Extract(); - return MyCompare(size1, size2); - } -}; - -static const unsigned kNameSize = 8; - -static void GetName(const Byte *name, AString &res) -{ - res.SetFrom_CalcLen((const char *)name, kNameSize); -} - -void CSection::Parse(const Byte *p) -{ - GetName(p, Name); - G32( 8, VSize); - G32(12, Va); - G32(16, PSize); - G32(20, Pa); - // G16(32, NumRelocs); - G32(36, Flags); - // v24.08: we extract only useful data (without extra padding bytes). - // VSize == 0 is not expected, but we support that case too. - // return (VSize && VSize < PSize) ? VSize : PSize; - ExtractSize = (VSize && VSize < PSize) ? VSize : PSize; -} - - - -// IMAGE_FILE_* - -static const CUInt32PCharPair g_HeaderCharacts[] = -{ - { 1, "Executable" }, - { 13, "DLL" }, - { 8, "32-bit" }, - { 5, "LargeAddress" }, - { 0, "NoRelocs" }, - { 2, "NoLineNums" }, - { 3, "NoLocalSyms" }, - { 4, "AggressiveWsTrim" }, - { 9, "NoDebugInfo" }, - { 10, "RemovableRun" }, - { 11, "NetRun" }, - { 12, "System" }, - { 14, "UniCPU" }, - { 7, "Little-Endian" }, - { 15, "Big-Endian" } -}; - -// IMAGE_DLLCHARACTERISTICS_* - -static const char * const g_DllCharacts[] = -{ - NULL - , NULL - , NULL - , NULL - , NULL - , "HighEntropyVA" - , "Relocated" - , "Integrity" - , "NX-Compatible" - , "NoIsolation" - , "NoSEH" - , "NoBind" - , "AppContainer" - , "WDM" - , "GuardCF" - , "TerminalServerAware" -}; - - -// IMAGE_SCN_* constants: - -static const char * const g_SectFlags[] = -{ - NULL - , NULL - , NULL - , "NoPad" - , NULL - , "Code" - , "InitializedData" - , "UninitializedData" - , "Other" - , "Comments" - , NULL // OVER - , "Remove" - , "COMDAT" - , NULL - , "NO_DEFER_SPEC_EXC" - , "GP" // MEM_FARDATA - , NULL // SYSHEAP - , "PURGEABLE" // 16BIT - , "LOCKED" - , "PRELOAD" - , NULL - , NULL - , NULL - , NULL - , "ExtendedRelocations" - , "Discardable" - , "NotCached" - , "NotPaged" - , "Shared" - , "Execute" - , "Read" - , "Write" -}; - -static const CUInt32PCharPair g_MachinePairs[] = -{ - { 0x014C, "x86" }, - { 0x014D, "I860" }, - { 0x0162, "MIPS-R3000" }, - { 0x0166, "MIPS-R4000" }, - { 0x0168, "MIPS-R10000" }, - { 0x0169, "MIPS-V2" }, - { 0x0184, "Alpha" }, - { 0x01A2, "SH3" }, - { 0x01A3, "SH3-DSP" }, - { 0x01A4, "SH3E" }, - { 0x01A6, "SH4" }, - { 0x01A8, "SH5" }, - { 0x01C0, "ARM" }, - { 0x01C2, "ARM-Thumb" }, - { 0x01C4, "ARM-NT" }, - { 0x01D3, "AM33" }, - { 0x01F0, "PPC" }, - { 0x01F1, "PPC-FP" }, - { 0x01F2, "PPC-BE" }, - { 0x0200, "IA-64" }, - { 0x0266, "MIPS-16" }, - { 0x0284, "Alpha-64" }, - { 0x0366, "MIPS-FPU" }, - { 0x0466, "MIPS-FPU16" }, - { 0x0520, "TriCore" }, - { 0x0CEF, "CEF" }, - { 0x0EBC, "EFI" }, - { 0x5032, "RISCV32" }, - { 0x5064, "RISCV64" }, -// { 0x5128, "RISCV128" }, - { 0x6232, "LOONGARCH32" }, - { 0x6264, "LOONGARCH64" }, - { 0x8664, "x64" }, - { 0x9041, "M32R" }, - { 0xA641, "ARM64EC" }, - { 0xA64e, "ARM64X" }, - { 0xAA64, "ARM64" }, - { 0xC0EE, "CEE" } -}; - -static const char * const g_SubSystems[] = -{ - "Unknown" - , "Native" - , "Windows GUI" - , "Windows CUI" - , NULL // "Old Windows CE" - , "OS2" - , NULL - , "Posix" - , "Win9x" - , "Windows CE" - , "EFI" - , "EFI Boot" - , "EFI Runtime" - , "EFI ROM" - , "XBOX" - , NULL - , "Windows Boot" - , "XBOX Catalog" // 17 -}; - -static const char * const g_ResTypes[] = -{ - NULL - , "CURSOR" - , "BITMAP" - , "ICON" - , "MENU" - , "DIALOG" - , "STRING" - , "FONTDIR" - , "FONT" - , "ACCELERATOR" - , "RCDATA" - , "MESSAGETABLE" - , "GROUP_CURSOR" - , NULL - , "GROUP_ICON" - , NULL - , "VERSION" - , "DLGINCLUDE" - , NULL - , "PLUGPLAY" - , "VXD" - , "ANICURSOR" - , "ANIICON" - , "HTML" - , "MANIFEST" -}; - -static const UInt32 kFlag = (UInt32)1 << 31; -static const UInt32 kMask = ~kFlag; - -struct CTableItem -{ - UInt32 Offset; - UInt32 ID; -}; - - -static const UInt32 kBmpHeaderSize = 14; -static const UInt32 kIconHeaderSize = 22; - -struct CResItem -{ - UInt32 Type; - UInt32 ID; - UInt32 Lang; - - UInt32 Size; - UInt32 Offset; - - UInt32 HeaderSize; - Byte Header[kIconHeaderSize]; // it must be enough for max size header. - bool Enabled; - - bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; } - UInt32 GetSize() const { return Size + HeaderSize; } - bool IsBmp() const { return Type == 2; } - bool IsIcon() const { return Type == 3; } - bool IsString() const { return Type == 6; } - bool IsRcData() const { return Type == 10; } - bool IsVersion() const { return Type == 16; } - bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; } -}; - -struct CTextFile -{ - CByteDynamicBuffer Buf; - - size_t FinalSize() const { return Buf.GetPos(); } - - void AddChar(char c); - void AddWChar(UInt16 c); - void AddWChar_Smart(UInt16 c); - void NewLine(); - void AddString(const char *s); - void AddSpaces(int num); - void AddBytes(const Byte *p, size_t size) - { - Buf.AddData(p, size); - } - - void OpenBlock(int num) - { - AddSpaces(num); - AddChar('{'); - NewLine(); - } - void CloseBlock(int num) - { - AddSpaces(num); - AddChar('}'); - NewLine(); - } -}; - -void CTextFile::AddChar(char c) -{ - Byte *p = Buf.GetCurPtrAndGrow(2); - p[0] = (Byte)c; - p[1] = 0; -} - -void CTextFile::AddWChar(UInt16 c) -{ - Byte *p = Buf.GetCurPtrAndGrow(2); - SetUi16(p, c) -} - -void CTextFile::AddWChar_Smart(UInt16 c) -{ - if (c == '\n') - { - AddChar('\\'); - c = 'n'; - } - AddWChar(c); -} - -void CTextFile::NewLine() -{ - AddChar(0x0D); - AddChar(0x0A); -} - -void CTextFile::AddString(const char *s) -{ - for (;; s++) - { - char c = *s; - if (c == 0) - return; - AddChar(c); - } -} - -void CTextFile::AddSpaces(int num) -{ - for (int i = 0; i < num; i++) - AddChar(' '); -} - -struct CStringItem: public CTextFile -{ - UInt32 Lang; -}; - -struct CByteBuffer_WithLang: public CByteBuffer -{ - UInt32 Lang; -}; - - -struct CMixItem -{ - int SectionIndex; - int ResourceIndex; - int StringIndex; - int VersionIndex; - - CMixItem(): SectionIndex(-1), ResourceIndex(-1), StringIndex(-1), VersionIndex(-1) {} - bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; } -}; - -struct CUsedBitmap -{ - CByteBuffer Buf; -public: - void Alloc(size_t size) - { - size = (size + 7) / 8; - Buf.Alloc(size); - memset(Buf, 0, size); - } - - void Free() - { - Buf.Free(); - } - - bool SetRange(size_t from, unsigned size) - { - for (unsigned i = 0; i < size; i++) - { - size_t pos = (from + i) >> 3; - Byte mask = (Byte)(1 << ((from + i) & 7)); - Byte b = Buf[pos]; - if ((b & mask) != 0) - return false; - Buf[pos] = (Byte)(b | mask); - } - return true; - } -}; - -struct CStringKeyValue -{ - UString Key; - UString Value; -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_2( - IInArchiveGetStream, - IArchiveAllowTail -) - CMyComPtr _stream; - CObjectVector _sections; - CHeader _header; - UInt32 _totalSize; - Int32 _mainSubfile; - - CRecordVector _mixItems; - CRecordVector _items; - CObjectVector _strings; - CObjectVector _versionFiles; - UString _versionFullString; - UString _versionShortString; - UString _originalFilename; - CObjectVector _versionKeys; - - CByteBuffer _buf; - bool _oneLang; - UString _resourcesPrefix; - CUsedBitmap _usedRes; - // bool _parseResources; - bool _checksumError; - bool _sectionsError; - - bool IsOpt() const { return _header.OptHeaderSize != 0; } - - COptHeader _optHeader; - - bool _coffMode; - bool _allowTail; - - HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection); - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - - void AddResNameToString(UString &s, UInt32 id) const; - void AddLangPrefix(UString &s, UInt32 lang) const; - HRESULT ReadString(UInt32 offset, UString &dest) const; - HRESULT ReadTable(UInt32 offset, CRecordVector &items); - bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size); - HRESULT OpenResources(unsigned sectIndex, IInStream *stream, IArchiveOpenCallback *callback); - void CloseResources(); - - - bool CheckItem(const CSection §, const CResItem &item, size_t offset) const - { - return item.Offset >= sect.Va && offset <= _buf.Size() && _buf.Size() - offset >= item.Size; - } - -public: - CHandler(bool coffMode = false): - _coffMode(coffMode), - _allowTail(coffMode) - {} -}; - - -enum -{ - kpidSectAlign = kpidUserDefined, - kpidFileAlign, - kpidLinkerVer, - kpidOsVer, - kpidImageVer, - kpidSubsysVer, - kpidCodeSize, - kpidImageSize, - kpidInitDataSize, - kpidUnInitDataSize, - kpidHeadersSizeUnInitDataSize, - kpidSubSystem, - kpidDllCharacts, - kpidStackReserve, - kpidStackCommit, - kpidHeapReserve, - kpidHeapCommit - // , kpidImageBase - // , kpidAddressOfEntryPoint - // , kpidBaseOfCode - // , kpidBaseOfData32 -}; - -static const CStatProp kArcProps[] = -{ - // { NULL, kpidWarning, VT_BSTR}, - { NULL, kpidCpu, VT_BSTR}, - { NULL, kpidBit64, VT_BOOL}, - { NULL, kpidCharacts, VT_BSTR}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidHeadersSize, VT_UI4}, - { NULL, kpidChecksum, VT_UI4}, - { NULL, kpidName, VT_BSTR}, - - { "Image Size", kpidImageSize, VT_UI4}, - { "Section Alignment", kpidSectAlign, VT_UI4}, - { "File Alignment", kpidFileAlign, VT_UI4}, - { "Code Size", kpidCodeSize, VT_UI4}, - { "Initialized Data Size", kpidInitDataSize, VT_UI4}, - { "Uninitialized Data Size", kpidUnInitDataSize, VT_UI4}, - { "Linker Version", kpidLinkerVer, VT_BSTR}, - { "OS Version", kpidOsVer, VT_BSTR}, - { "Image Version", kpidImageVer, VT_BSTR}, - { "Subsystem Version", kpidSubsysVer, VT_BSTR}, - { "Subsystem", kpidSubSystem, VT_BSTR}, - { "DLL Characteristics", kpidDllCharacts, VT_BSTR}, - { "Stack Reserve", kpidStackReserve, VT_UI8}, - { "Stack Commit", kpidStackCommit, VT_UI8}, - { "Heap Reserve", kpidHeapReserve, VT_UI8}, - { "Heap Commit", kpidHeapCommit, VT_UI8}, - { NULL, kpidVa, VT_UI8 }, // "Image Base", kpidImageBase, VT_UI8 - { NULL, kpidComment, VT_BSTR} - - // , { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8} - // , { "Base Of Code", kpidBaseOfCode, VT_UI8} - // , { "Base Of Data", kpidBaseOfData32, VT_UI8} -}; - -// #define kpid_NumRelocs 250 - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidVirtualSize, - kpidCharacts, - kpidOffset, - kpidVa - // , kpid_NumRelocs -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) -{ - if (unixTime != 0) - PropVariant_SetFrom_UnixTime(prop, unixTime); -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _totalSize; break; - case kpidComment: - { - UString s (_versionFullString); - s.Add_LF(); - s += "Data Directories: "; - s.Add_UInt32(_optHeader.NumDirItems); - s.Add_LF(); - s.Add_Char('{'); - s.Add_LF(); - for (unsigned i = 0; i < _optHeader.NumDirItems - && i < Z7_ARRAY_SIZE(_optHeader.DirItems); i++) - { - const CDirLink &di = _optHeader.DirItems[i]; - if (di.Va == 0 && di.Size == 0) - continue; - s += "index="; - s.Add_UInt32(i); - - if (i < Z7_ARRAY_SIZE(g_Dir_Names)) - { - s += " name="; - s += g_Dir_Names[i]; - } - s += " VA=0x"; - char temp[16]; - ConvertUInt32ToHex(di.Va, temp); - s += temp; - s += " Size="; - s.Add_UInt32(di.Size); - s.Add_LF(); - } - s.Add_Char('}'); - s.Add_LF(); - prop = s; - break; - } - case kpidShortComment: - if (!_versionShortString.IsEmpty()) - prop = _versionShortString; - else - { - PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); - } - break; - - case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break; - - // case kpidIsSelfExe: prop = !_header.IsDll(); break; - // case kpidError: - case kpidWarning: if (_checksumError) prop = "Checksum error"; break; - - case kpidWarningFlags: - { - UInt32 v = 0; - if (_sectionsError) v |= kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - - case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break; - case kpidMTime: - case kpidCTime: TimeToProp(_header.Time, prop); break; - case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break; - case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; - - default: - if (IsOpt()) - switch (propID) - { - - case kpidSectAlign: prop = _optHeader.SectAlign; break; - case kpidFileAlign: prop = _optHeader.FileAlign; break; - case kpidLinkerVer: - { - CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor }; - v.ToProp(prop); - break; - } - - case kpidOsVer: _optHeader.OsVer.ToProp(prop); break; - case kpidImageVer: _optHeader.ImageVer.ToProp(prop); break; - case kpidSubsysVer: _optHeader.SubsysVer.ToProp(prop); break; - case kpidCodeSize: prop = _optHeader.CodeSize; break; - case kpidInitDataSize: prop = _optHeader.InitDataSize; break; - case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break; - case kpidImageSize: prop = _optHeader.ImageSize; break; - case kpidHeadersSize: prop = _optHeader.HeadersSize; break; - case kpidChecksum: prop = _optHeader.CheckSum; break; - - case kpidExtension: - if (_header.IsDll()) - prop = "dll"; - else if (_optHeader.IsSybSystem_EFI()) - prop = "efi"; - break; - - case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break; - case kpidSubSystem: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break; - - case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break; - case kpidStackReserve: prop = _optHeader.StackReserve; break; - case kpidStackCommit: prop = _optHeader.StackCommit; break; - case kpidHeapReserve: prop = _optHeader.HeapReserve; break; - case kpidHeapCommit: prop = _optHeader.HeapCommit; break; - case kpidVa: prop = _optHeader.ImageBase; break; // kpidImageBase: - // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break; - // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break; - // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const -{ - if ((offset & 1) != 0 || offset >= _buf.Size()) - return S_FALSE; - size_t rem = _buf.Size() - offset; - if (rem < 2) - return S_FALSE; - unsigned len = Get16(_buf + offset); - if ((rem - 2) / 2 < len) - return S_FALSE; - dest.Empty(); - wchar_t *destBuf = dest.GetBuf(len); - offset += 2; - const Byte *src = _buf + offset; - unsigned i; - for (i = 0; i < len; i++) - { - wchar_t c = (wchar_t)Get16(src + i * 2); - if (c == 0) - break; - destBuf[i] = c; - } - destBuf[i] = 0; - dest.ReleaseBuf_SetLen(i); - return S_OK; -} - -void CHandler::AddResNameToString(UString &s, UInt32 id) const -{ - if ((id & kFlag) != 0) - { - UString name; - if (ReadString(id & kMask, name) == S_OK) - { - const wchar_t *str = L"[]"; - if (name.Len() > 1 && name[0] == '"' && name.Back() == '"') - { - if (name.Len() != 2) - { - name.DeleteBack(); - str = name.Ptr(1); - } - } - else if (!name.IsEmpty()) - str = name; - s += str; - return; - } - } - s.Add_UInt32(id); -} - -void CHandler::AddLangPrefix(UString &s, UInt32 lang) const -{ - if (!_oneLang) - { - AddResNameToString(s, lang); - s.Add_PathSepar(); - } -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CMixItem &mixItem = _mixItems[index]; - if (mixItem.StringIndex >= 0) - { - const CStringItem &item = _strings[mixItem.StringIndex]; - switch (propID) - { - case kpidPath: - { - UString s = _resourcesPrefix; - AddLangPrefix(s, item.Lang); - s += "string.txt"; - prop = s; - break; - } - case kpidSize: - case kpidPackSize: - prop = (UInt64)item.FinalSize(); break; - } - } - else if (mixItem.VersionIndex >= 0) - { - const CByteBuffer_WithLang &item = _versionFiles[mixItem.VersionIndex]; - switch (propID) - { - case kpidPath: - { - UString s = _resourcesPrefix; - AddLangPrefix(s, item.Lang); - s += "version.txt"; - prop = s; - break; - } - case kpidSize: - case kpidPackSize: - prop = (UInt64)item.Size(); break; - } - } - else if (mixItem.ResourceIndex >= 0) - { - const CResItem &item = _items[mixItem.ResourceIndex]; - switch (propID) - { - case kpidPath: - { - UString s = _resourcesPrefix; - AddLangPrefix(s, item.Lang); - { - const char *p = NULL; - if (item.Type < Z7_ARRAY_SIZE(g_ResTypes)) - p = g_ResTypes[item.Type]; - if (p) - s += p; - else - AddResNameToString(s, item.Type); - } - s.Add_PathSepar(); - AddResNameToString(s, item.ID); - if (item.HeaderSize != 0) - { - if (item.IsBmp()) - s += ".bmp"; - else if (item.IsIcon()) - s += ".ico"; - } - prop = s; - break; - } - case kpidSize: prop = (UInt64)item.GetSize(); break; - case kpidPackSize: prop = (UInt64)item.Size; break; - } - } - else - { - const CSection &item = _sections[mixItem.SectionIndex]; - switch (propID) - { - case kpidPath: - { - AString s = item.Name; - s.Replace('/', '_'); - s.Replace('\\', '_'); - prop = MultiByteToUnicodeString(s); - break; - } - case kpidSize: prop = (UInt64)item.GetSize_Extract(); break; - // case kpid_NumRelocs: prop = (UInt32)item.NumRelocs; break; - case kpidPackSize: prop = (UInt64)item.PSize; break; - case kpidVirtualSize: prop = (UInt64)item.VSize; break; - case kpidOffset: prop = item.Pa; break; - case kpidVa: if (item.IsRealSect) prop = item.Va; break; - case kpidMTime: - case kpidCTime: - TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break; - case kpidCharacts: - if (item.IsRealSect) - { - UInt32 flags = item.Flags; - const UInt32 MY_IMAGE_SCN_ALIGN_MASK = 0x00F00000; - AString s = FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & ~MY_IMAGE_SCN_ALIGN_MASK); - const UInt32 align = ((flags >> 20) & 0xF); - if (align != 0) - { - char sz[32]; - ConvertUInt32ToString(1 << (align - 1), sz); - s.Add_Space(); - s += "align_"; - s += sz; - } - prop = s; - } - break; - case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) -{ - thereIsSection = false; - const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug]; - if (debugLink.Size == 0) - return S_OK; - const unsigned kEntrySize = 28; - UInt32 numItems = debugLink.Size / kEntrySize; - if (numItems > 16) - return S_FALSE; - - // MAC's EFI file: numItems can be incorrect. Only first CDebugEntry entry is correct. - // debugLink.Size = kEntrySize + some_data, pointed by entry[0]. - if (numItems * kEntrySize != debugLink.Size) - { - // return S_FALSE; - if (numItems > 1) - numItems = 1; - } - - UInt64 pa = 0; - unsigned i; - for (i = 0; i < _sections.Size(); i++) - { - const CSection § = _sections[i]; - if (sect.Va <= debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize) - { - pa = sect.Pa + (debugLink.Va - sect.Va); - break; - } - } - if (i == _sections.Size()) - { - // Exe for ARM requires S_OK - // return S_FALSE; - return S_OK; - } - - CByteBuffer buffer(debugLink.Size); - Byte *buf = buffer; - - RINOK(InStream_SeekSet(stream, pa)) - RINOK(ReadStream_FALSE(stream, buf, debugLink.Size)) - - for (i = 0; i < numItems; i++) - { - CDebugEntry de; - de.Parse(buf); - - if (de.Size == 0) - continue; - - UInt32 totalSize = de.Pa + de.Size; - if (totalSize > _totalSize) - { - _totalSize = totalSize; - thereIsSection = true; - - CSection § = _sections.AddNew(); - sect.Name = ".debug"; - sect.Name.Add_UInt32(i); - sect.IsDebug = true; - sect.Time = de.Time; - sect.Va = de.Va; - sect.Pa = de.Pa; - sect.Set_Size_for_all(de.Size); - } - buf += kEntrySize; - } - - return S_OK; -} - -HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector &items) -{ - if ((offset & 3) != 0 || offset >= _buf.Size()) - return S_FALSE; - size_t rem = _buf.Size() - offset; - if (rem < 16) - return S_FALSE; - unsigned numNameItems = Get16(_buf + offset + 12); - unsigned numIdItems = Get16(_buf + offset + 14); - unsigned numItems = numNameItems + numIdItems; - if ((rem - 16) / 8 < numItems) - return S_FALSE; - if (!_usedRes.SetRange(offset, 16 + numItems * 8)) - return S_FALSE; - offset += 16; - items.ClearAndReserve(numItems); - for (unsigned i = 0; i < numItems; i++, offset += 8) - { - const Byte *buf = _buf + offset; - CTableItem item; - item.ID = Get32(buf + 0); - if ((bool)((item.ID & kFlag) != 0) != (bool)(i < numNameItems)) - return S_FALSE; - item.Offset = Get32(buf + 4); - items.AddInReserved(item); - } - return S_OK; -} - -static const UInt32 kFileSizeMax = (UInt32)1 << 31; -static const unsigned kNumResItemsMax = (unsigned)1 << 23; -static const unsigned kNumStringLangsMax = 256; - -// BITMAPINFOHEADER -struct CBitmapInfoHeader -{ - // UInt32 HeaderSize; - UInt32 XSize; - Int32 YSize; - UInt16 Planes; - UInt16 BitCount; - UInt32 Compression; - UInt32 SizeImage; - - bool Parse(const Byte *p, size_t size); -}; - -static const UInt32 kBitmapInfoHeader_Size = 0x28; - -bool CBitmapInfoHeader::Parse(const Byte *p, size_t size) -{ - if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size) - return false; - G32( 4, XSize); - G32_signed( 8, YSize); - G16(12, Planes); - G16(14, BitCount); - G32(16, Compression); - G32(20, SizeImage); - return true; -} - -static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount) -{ - return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize; -} - -static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size) -{ - CBitmapInfoHeader h; - if (!h.Parse(src, size)) - return 0; - if (h.YSize < 0) - h.YSize = -h.YSize; - if (h.XSize > (1 << 26) - || h.YSize > (1 << 26) - || h.YSize < 0 - || h.Planes != 1 || h.BitCount > 32) - return 0; - if (h.SizeImage == 0) - { - if (h.Compression != 0) // BI_RGB - return 0; - h.SizeImage = GetImageSize(h.XSize, (UInt32)h.YSize, h.BitCount); - } - UInt32 totalSize = kBmpHeaderSize + size; - UInt32 offBits = totalSize - h.SizeImage; - // BITMAPFILEHEADER - SetUi16(dest, 0x4D42) - SetUi32(dest + 2, totalSize) - SetUi32(dest + 6, 0) - SetUi32(dest + 10, offBits) - return kBmpHeaderSize; -} - -static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size) -{ - CBitmapInfoHeader h; - if (!h.Parse(src, size)) - return 0; - if (h.YSize < 0) - h.YSize = -h.YSize; - if (h.XSize > (1 << 26) - || h.YSize > (1 << 26) - || h.YSize < 0 - || h.Planes != 1 - || h.Compression != 0) // BI_RGB - return 0; - - const UInt32 numBitCount = h.BitCount; - if (numBitCount != 1 && - numBitCount != 4 && - numBitCount != 8 && - numBitCount != 24 && - numBitCount != 32) - return 0; - - if ((h.YSize & 1) != 0) - return 0; - h.YSize /= 2; - if (h.XSize > 0x100 || h.YSize > 0x100) - return 0; - - UInt32 imageSize; - // imageSize is not correct if AND mask array contains zeros - // in this case it is equal image1Size - - // UInt32 imageSize = h.SizeImage; - // if (imageSize == 0) - // { - const UInt32 image1Size = GetImageSize(h.XSize, (UInt32)h.YSize, h.BitCount); - const UInt32 image2Size = GetImageSize(h.XSize, (UInt32)h.YSize, 1); - imageSize = image1Size + image2Size; - // } - UInt32 numColors = 0; - if (numBitCount < 16) - numColors = 1 << numBitCount; - - SetUi16(dest, 0) // Reserved - SetUi16(dest + 2, 1) // RES_ICON - SetUi16(dest + 4, 1) // ResCount - - dest[6] = (Byte)h.XSize; // Width - dest[7] = (Byte)h.YSize; // Height - dest[8] = (Byte)numColors; // ColorCount - dest[9] = 0; // Reserved - - SetUi32(dest + 10, 0) // Reserved1 / Reserved2 - - UInt32 numQuadsBytes = numColors * 4; - UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize; - SetUi32(dest + 14, BytesInRes) - SetUi32(dest + 18, kIconHeaderSize) - - /* - Description = DWORDToString(xSize) + - kDelimiterChar + DWORDToString(ySize) + - kDelimiterChar + DWORDToString(numBitCount); - */ - return kIconHeaderSize; -} - -bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size) -{ - if ((size & 1) != 0) - return false; - - unsigned i; - for (i = 0; i < _strings.Size(); i++) - if (_strings[i].Lang == lang) - break; - if (i == _strings.Size()) - { - if (_strings.Size() >= kNumStringLangsMax) - return false; - CStringItem &item = _strings.AddNew(); - item.Lang = lang; - } - - CStringItem &item = _strings[i]; - id = (id - 1) << 4; - UInt32 pos = 0; - for (i = 0; i < 16; i++) - { - if (size - pos < 2) - return false; - UInt32 len = Get16(src + pos); - pos += 2; - if (len != 0) - { - if (size - pos < len * 2) - return false; - char temp[32]; - ConvertUInt32ToString(id + i, temp); - size_t tempLen = strlen(temp); - size_t j; - for (j = 0; j < tempLen; j++) - item.AddChar(temp[j]); - item.AddChar('\t'); - for (j = 0; j < len; j++, pos += 2) - item.AddWChar_Smart(Get16(src + pos)); - item.NewLine(); - } - } - if (size == pos) - return true; - - // Some rare case files have additional ZERO. - if (size == pos + 2 && Get16(src + pos) == 0) - return true; - - return false; -} - - -// ---------- VERSION ---------- - -static const UInt32 kMy_VS_FFI_SIGNATURE = 0xFEEF04BD; - -struct CMy_VS_FIXEDFILEINFO -{ - // UInt32 Signature; - // UInt32 StrucVersion; - UInt32 VersionMS; - UInt32 VersionLS; - UInt32 ProductVersionMS; - UInt32 ProductVersionLS; - UInt32 FlagsMask; - UInt32 Flags; - UInt32 OS; - UInt32 Type; - UInt32 Subtype; - UInt32 DateMS; - UInt32 DateLS; - - bool Parse(const Byte *p); - void PrintToTextFile(CTextFile &f, CObjectVector &keys); -}; - -bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p) -{ - if (Get32(p) != kMy_VS_FFI_SIGNATURE) // signature; - return false; - // G32(0x04, StrucVersion); - G32(0x08, VersionMS); - G32(0x0C, VersionLS); - G32(0x10, ProductVersionMS); - G32(0x14, ProductVersionLS); - G32(0x18, FlagsMask); - G32(0x1C, Flags); - G32(0x20, OS); - G32(0x24, Type); - G32(0x28, Subtype); - G32(0x2C, DateMS); - G32(0x40, DateLS); - return true; -} - -static void PrintUInt32(CTextFile &f, UInt32 v) -{ - char s[16]; - ConvertUInt32ToString(v, s); - f.AddString(s); -} - -static inline void PrintUInt32(UString &dest, UInt32 v) -{ - dest.Add_UInt32(v); -} - -static void PrintHex(CTextFile &f, UInt32 val) -{ - char temp[16]; - temp[0] = '0'; - temp[1] = 'x'; - ConvertUInt32ToHex(val, temp + 2); - f.AddString(temp); -} - -static void PrintVersion(CTextFile &f, UInt32 ms, UInt32 ls) -{ - PrintUInt32(f, HIWORD(ms)); f.AddChar(','); - PrintUInt32(f, LOWORD(ms)); f.AddChar(','); - PrintUInt32(f, HIWORD(ls)); f.AddChar(','); - PrintUInt32(f, LOWORD(ls)); -} - -static void PrintVersion(UString &s, UInt32 ms, UInt32 ls) -{ - PrintUInt32(s, HIWORD(ms)); s.Add_Dot(); - PrintUInt32(s, LOWORD(ms)); s.Add_Dot(); - PrintUInt32(s, HIWORD(ls)); s.Add_Dot(); - PrintUInt32(s, LOWORD(ls)); -} - -static const char * const k_VS_FileFlags[] = -{ - "DEBUG" - , "PRERELEASE" - , "PATCHED" - , "PRIVATEBUILD" - , "INFOINFERRED" - , "SPECIALBUILD" -}; - -static const CUInt32PCharPair k_VS_FileOS[] = -{ - { 0x10001, "VOS_DOS_WINDOWS16" }, - { 0x10004, "VOS_DOS_WINDOWS32" }, - { 0x20002, "VOS_OS216_PM16" }, - { 0x30003, "VOS_OS232_PM32" }, - { 0x40004, "VOS_NT_WINDOWS32" } -}; - -static const char * const k_VS_FileOS_High[] = -{ - "VOS_UNKNOWN" - , "VOS_DOS" - , "VOS_OS216" - , "VOS_OS232" - , "VOS_NT" - , "VOS_WINCE" -}; - -static const UInt32 kMY_VFT_DRV = 3; -static const UInt32 kMY_VFT_FONT = 4; - -static const char * const k_VS_FileOS_Low[] = -{ - "VOS__BASE" - , "VOS__WINDOWS16" - , "VOS__PM16" - , "VOS__PM32" - , "VOS__WINDOWS32" -}; - -static const char * const k_VS_FileType[] = -{ - "VFT_UNKNOWN" - , "VFT_APP" - , "VFT_DLL" - , "VFT_DRV" - , "VFT_FONT" - , "VFT_VXD" - , "0x6" - , "VFT_STATIC_LIB" -}; - -// Subtype for VFT_DRV Type -static const char * const k_VS_FileSubType_DRV[] = -{ - "0" - , "PRINTER" - , "KEYBOARD" - , "LANGUAGE" - , "DISPLAY" - , "MOUSE" - , "NETWORK" - , "SYSTEM" - , "INSTALLABLE" - , "SOUND" - , "COMM" - , "INPUTMETHOD" - , "VERSIONED_PRINTER" -}; - -// Subtype for VFT_FONT Type -static const char * const k_VS_FileSubType_FONT[] = -{ - "0" - , "VFT2_FONT_RASTER" - , "VFT2_FONT_VECTOR" - , "VFT2_FONT_TRUETYPE" -}; - -static int FindKey(CObjectVector &v, const char *key) -{ - FOR_VECTOR (i, v) - if (v[i].Key.IsEqualTo(key)) - return (int)i; - return -1; -} - -static void AddToUniqueUStringVector(CObjectVector &v, const UString &key, const UString &value) -{ - bool needInsert = false; - unsigned i; - for (i = 0; i < v.Size(); i++) - { - if (v[i].Key == key) - { - if (v[i].Value == value) - return; - needInsert = true; - } - else if (needInsert) - break; - } - CStringKeyValue &pair = v.InsertNew(i); - pair.Key = key; - pair.Value = value; -} - -void CMy_VS_FIXEDFILEINFO::PrintToTextFile(CTextFile &f, CObjectVector &keys) -{ - f.AddString("FILEVERSION "); - PrintVersion(f, VersionMS, VersionLS); - f.NewLine(); - - f.AddString("PRODUCTVERSION "); - PrintVersion(f, ProductVersionMS, ProductVersionLS); - f.NewLine(); - - { - UString s; - PrintVersion(s, VersionMS, VersionLS); - AddToUniqueUStringVector(keys, L"FileVersion", s); - } - { - UString s; - PrintVersion(s, ProductVersionMS, ProductVersionLS); - AddToUniqueUStringVector(keys, L"ProductVersion", s); - } - - f.AddString("FILEFLAGSMASK "); - PrintHex(f, FlagsMask); - f.NewLine(); - - f.AddString("FILEFLAGS "); - { - bool wasPrinted = false; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_VS_FileFlags); i++) - { - if ((Flags & ((UInt32)1 << i)) != 0) - { - if (wasPrinted) - f.AddString(" | "); - f.AddString("VS_FF_"); - f.AddString(k_VS_FileFlags[i]); - wasPrinted = true; - } - } - UInt32 v = Flags & ~(((UInt32)1 << Z7_ARRAY_SIZE(k_VS_FileFlags)) - 1); - if (v != 0 || !wasPrinted) - { - if (wasPrinted) - f.AddString(" | "); - PrintHex(f, v); - } - } - f.NewLine(); - - // OS = 0x111230; - f.AddString("FILEOS "); - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(k_VS_FileOS); i++) - { - const CUInt32PCharPair &pair = k_VS_FileOS[i]; - if (OS == pair.Value) - { - // continue; - // f.AddString("VOS_"); - f.AddString(pair.Name); - break; - } - } - if (i == Z7_ARRAY_SIZE(k_VS_FileOS)) - { - UInt32 high = OS >> 16; - if (high < Z7_ARRAY_SIZE(k_VS_FileOS_High)) - f.AddString(k_VS_FileOS_High[high]); - else - PrintHex(f, high << 16); - UInt32 low = OS & 0xFFFF; - if (low != 0) - { - f.AddString(" | "); - if (low < Z7_ARRAY_SIZE(k_VS_FileOS_Low)) - f.AddString(k_VS_FileOS_Low[low]); - else - PrintHex(f, low); - } - } - f.NewLine(); - - f.AddString("FILETYPE "); - if (Type < Z7_ARRAY_SIZE(k_VS_FileType)) - f.AddString(k_VS_FileType[Type]); - else - PrintHex(f, Type); - f.NewLine(); - - f.AddString("FILESUBTYPE "); - bool needPrintSubType = true; - if (Type == kMY_VFT_DRV) - { - if (Subtype != 0 && Subtype < Z7_ARRAY_SIZE(k_VS_FileSubType_DRV)) - { - f.AddString("VFT2_DRV_"); - f.AddString(k_VS_FileSubType_DRV[Subtype]); - needPrintSubType = false; - } - } - else if (Type == kMY_VFT_FONT) - { - if (Subtype != 0 && Subtype < Z7_ARRAY_SIZE(k_VS_FileSubType_FONT)) - { - f.AddString(k_VS_FileSubType_FONT[Subtype]); - needPrintSubType = false; - } - } - if (needPrintSubType) - PrintHex(f, Subtype); - f.NewLine(); -} - -static void CopyToUString(const Byte *p, UString &s) -{ - for (;;) - { - const wchar_t c = (wchar_t)Get16(p); - p += 2; - if (c == 0) - return; - s += c; - } -} - -static void CopyToUString_ByLen16(const Byte *p, unsigned numChars16, UString &s) -{ - for (; numChars16; numChars16--) - { - const wchar_t c = (wchar_t)Get16(p); - p += 2; - s += c; - } -} - -static bool CompareWStrStrings(const Byte *p, const char *s) -{ - unsigned pos = 0; - for (;;) - { - const Byte c = (Byte)*s++; - if (Get16(p + pos) != c) - return false; - pos += 2; - if (c == 0) - return true; - } -} - -struct CVersionBlock -{ - UInt32 TotalLen; - UInt32 ValueLen; - unsigned IsTextValue; - unsigned StrSize; - - bool Parse(const Byte *p, UInt32 size); -}; - -static int Get_Utf16Str_Len_InBytes(const Byte *p, size_t size) -{ - unsigned pos = 0; - for (;;) - { - if (pos + 1 >= size) - return -1; - if (Get16(p + pos) == 0) - return (int)pos; - pos += 2; - } -} - -static int Get_Utf16Str_Len_InBytes_AllowNonZeroTail(const Byte *p, size_t size) -{ - unsigned pos = 0; - for (;;) - { - if (pos + 1 >= size) - { - if (pos == size) - return (int)pos; - return -1; - } - if (Get16(p + pos) == 0) - return (int)pos; - pos += 2; - } -} - -static const unsigned k_ResoureBlockHeader_Size = 6; - -bool CVersionBlock::Parse(const Byte *p, UInt32 size) -{ - if (size < k_ResoureBlockHeader_Size) - return false; - TotalLen = Get16(p); - ValueLen = Get16(p + 2); - if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size) - return false; - IsTextValue = Get16(p + 4); - if (IsTextValue > 1) - return false; - StrSize = 0; - const int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, - TotalLen - k_ResoureBlockHeader_Size); - if (t < 0) - return false; - StrSize = (unsigned)t; - return true; -} - -static void AddParamString(CTextFile &f, const Byte *p, size_t sLen) -{ - f.AddChar(' '); - f.AddChar('\"'); - f.AddBytes(p, sLen); - f.AddChar('\"'); -} - -static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector &keys) -{ - UInt32 pos; - { - const unsigned k_sizeof_VS_FIXEDFILEINFO = 13 * 4; - - CVersionBlock vb; - if (!vb.Parse(p, size)) - return false; - if (vb.ValueLen != k_sizeof_VS_FIXEDFILEINFO) // maybe 0 is allowed here? - return false; - if (vb.IsTextValue) - return false; - pos = k_ResoureBlockHeader_Size; - if (!CompareWStrStrings(p + pos, "VS_VERSION_INFO")) - return false; - pos += vb.StrSize + 2; - pos += (4 - pos) & 3; - if (pos + vb.ValueLen > vb.TotalLen) - return false; - /* sometimes resource contains zeros in remainder. - So we don't check that size != vb.TotalLen - // if (size != vb.TotalLen) return false; - */ - if (size > vb.TotalLen) - size = vb.TotalLen; - CMy_VS_FIXEDFILEINFO FixedFileInfo; - if (!FixedFileInfo.Parse(p + pos)) - return false; - FixedFileInfo.PrintToTextFile(f, keys); - pos += vb.ValueLen; - } - - f.OpenBlock(0); - - for (;;) - { - pos += (4 - pos) & 3; - if (pos >= size) - break; - - CVersionBlock vb; - if (!vb.Parse(p + pos, size - pos)) - return false; - if (vb.ValueLen != 0) - return false; - const UInt32 endPos = pos + vb.TotalLen; - pos += k_ResoureBlockHeader_Size; - - f.AddSpaces(2); - f.AddString("BLOCK"); - AddParamString(f, p + pos, vb.StrSize); - - f.NewLine(); - f.OpenBlock(2); - - if (CompareWStrStrings(p + pos, "VarFileInfo")) - { - pos += vb.StrSize + 2; - for (;;) - { - pos += (4 - pos) & 3; - if (pos >= endPos) - break; - CVersionBlock vb2; - if (!vb2.Parse(p + pos, endPos - pos)) - return false; - const UInt32 endPos2 = pos + vb2.TotalLen; - if (vb2.IsTextValue) - return false; - pos += k_ResoureBlockHeader_Size; - f.AddSpaces(4); - f.AddString("VALUE"); - AddParamString(f, p + pos, vb2.StrSize); - if (!CompareWStrStrings(p + pos, "Translation")) - return false; - pos += vb2.StrSize + 2; - pos += (4 - pos) & 3; - if (pos + vb2.ValueLen != endPos2) - return false; - if ((vb2.ValueLen & 3) != 0) - return false; - UInt32 num = (vb2.ValueLen >> 2); - for (; num != 0; num--, pos += 4) - { - const UInt32 dw = Get32(p + pos); - const UInt32 lang = LOWORD(dw); - const UInt32 codePage = HIWORD(dw); - - f.AddString(", "); - PrintHex(f, lang); - f.AddString(", "); - PrintUInt32(f, codePage); - } - f.NewLine(); - } - } - else - { - if (!CompareWStrStrings(p + pos, "StringFileInfo")) - return false; - pos += vb.StrSize + 2; - for (;;) - { - pos += (4 - pos) & 3; - if (pos >= endPos) - break; - CVersionBlock vb2; - if (!vb2.Parse(p + pos, endPos - pos)) - return false; - const UInt32 endPos2 = pos + vb2.TotalLen; - if (vb2.ValueLen != 0) - return false; - pos += k_ResoureBlockHeader_Size; - - f.AddSpaces(4); - f.AddString("BLOCK"); - AddParamString(f, p + pos, vb2.StrSize); - pos += vb2.StrSize + 2; - - f.NewLine(); - f.OpenBlock(4); - - for (;;) - { - pos += (4 - pos) & 3; - if (pos >= endPos2) - break; - - CVersionBlock vb3; - if (!vb3.Parse(p + pos, endPos2 - pos)) - return false; - // ValueLen is a number of 16-bit characters (usually it includes zero tail character). - const UInt32 endPos3 = pos + vb3.TotalLen; - pos += k_ResoureBlockHeader_Size; - - // we don't write string if it's not text - if (vb3.IsTextValue) - { - f.AddSpaces(6); - f.AddString("VALUE"); - AddParamString(f, p + pos, vb3.StrSize); - UString key; - UString value; - CopyToUString(p + pos, key); - pos += vb3.StrSize + 2; - - pos += (4 - pos) & 3; - if (vb3.ValueLen != 0 && pos /* + 2 */ <= endPos3) - { - f.AddChar(','); - f.AddSpaces((34 - (int)vb3.StrSize) / 2); - // vb3.TotalLen for some PE files (not from msvc) doesn't include tail zero at the end of Value string. - // we allow that minor error. - const int sLen = Get_Utf16Str_Len_InBytes_AllowNonZeroTail(p + pos, endPos3 - pos); - if (sLen < 0) - return false; - /* - if (vb3.ValueLen - 1 != (unsigned)sLen / 2 && - vb3.ValueLen != (unsigned)sLen / 2) - return false; - */ - AddParamString(f, p + pos, (unsigned)sLen); - CopyToUString_ByLen16(p + pos, (unsigned)sLen / 2, value); - // pos += (unsigned)sLen + 2; - } - AddToUniqueUStringVector(keys, key, value); - } - pos = endPos3; - f.NewLine(); - } - pos = endPos2; - f.CloseBlock(4); - } - } - f.CloseBlock(2); - pos = endPos; - } - - f.CloseBlock(0); - return true; -} - - -HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchiveOpenCallback *callback) -{ - const CSection § = _sections[sectionIndex]; - size_t fileSize = sect.PSize; - { - size_t fileSizeMin = sect.PSize; - - if (sect.VSize < sect.PSize) - { - fileSize = fileSizeMin = sect.VSize; - const int numBits = _optHeader.GetNumFileAlignBits(); - if (numBits > 0) - { - const UInt32 mask = ((UInt32)1 << numBits) - 1; - const size_t end = (size_t)((sect.VSize + mask) & (UInt32)~mask); - if (end > sect.VSize) - { - if (end <= sect.PSize) - fileSize = end; - else - fileSize = sect.PSize; - } - } - } - - if (fileSize > kFileSizeMax) - return S_FALSE; - - { - const UInt64 fileSize64 = fileSize; - if (callback) - RINOK(callback->SetTotal(NULL, &fileSize64)) - } - - RINOK(InStream_SeekSet(stream, sect.Pa)) - - _buf.Alloc(fileSize); - - size_t pos; - - for (pos = 0; pos < fileSize;) - { - { - const UInt64 offset64 = pos; - if (callback) - RINOK(callback->SetCompleted(NULL, &offset64)) - } - size_t rem = MyMin(fileSize - pos, (size_t)(1 << 22)); - RINOK(ReadStream(stream, _buf + pos, &rem)) - if (rem == 0) - { - if (pos < fileSizeMin) - return S_FALSE; - break; - } - pos += rem; - } - - if (pos < fileSize) - memset(_buf + pos, 0, fileSize - pos); - } - - _usedRes.Alloc(fileSize); - CRecordVector specItems; - RINOK(ReadTable(0, specItems)) - - _oneLang = true; - bool stringsOk = true; - size_t maxOffset = 0; - - FOR_VECTOR (i, specItems) - { - const CTableItem &item1 = specItems[i]; - if ((item1.Offset & kFlag) == 0) - return S_FALSE; - - CRecordVector specItems2; - RINOK(ReadTable(item1.Offset & kMask, specItems2)) - - FOR_VECTOR (j, specItems2) - { - const CTableItem &item2 = specItems2[j]; - if ((item2.Offset & kFlag) == 0) - return S_FALSE; - - CRecordVector specItems3; - RINOK(ReadTable(item2.Offset & kMask, specItems3)) - - CResItem item; - item.Type = item1.ID; - item.ID = item2.ID; - - FOR_VECTOR (k, specItems3) - { - if (_items.Size() >= kNumResItemsMax) - return S_FALSE; - const CTableItem &item3 = specItems3[k]; - if ((item3.Offset & kFlag) != 0) - return S_FALSE; - if (item3.Offset >= _buf.Size() || _buf.Size() - item3.Offset < 16) - return S_FALSE; - const Byte *buf = _buf + item3.Offset; - item.Lang = item3.ID; - item.Offset = Get32(buf + 0); - item.Size = Get32(buf + 4); - // UInt32 codePage = Get32(buf + 8); - if (Get32(buf + 12) != 0) - return S_FALSE; - if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back())) - _oneLang = false; - - item.HeaderSize = 0; - - size_t offset = item.Offset - sect.Va; - if (offset > maxOffset) - maxOffset = offset; - if (offset + item.Size > maxOffset) - maxOffset = offset + item.Size; - - if (CheckItem(sect, item, offset)) - { - const Byte *data = _buf + offset; - if (item.IsBmp()) - item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size); - else if (item.IsIcon()) - item.HeaderSize = SetIconHeader(item.Header, data, item.Size); - else if (item.IsString()) - { - if (stringsOk) - stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size); - } - } - - if (item.IsVersion()) - { - if (offset > _buf.Size() || _buf.Size() - offset < item.Size) - continue; - CTextFile f; - if (ParseVersion((const Byte *)_buf + offset, item.Size, f, _versionKeys)) - { - CMixItem mixItem; - mixItem.VersionIndex = (int)_versionFiles.Size(); - mixItem.SectionIndex = (int)sectionIndex; // check it !!!! - CByteBuffer_WithLang &vf = _versionFiles.AddNew(); - vf.Lang = item.Lang; - vf.CopyFrom(f.Buf, f.Buf.GetPos()); - _mixItems.Add(mixItem); - continue; - } - // PrintError("ver.Parse error"); - } - - item.Enabled = true; - _items.Add(item); - } - } - } - - if (stringsOk && !_strings.IsEmpty()) - { - unsigned i; - for (i = 0; i < _items.Size(); i++) - { - CResItem &item = _items[i]; - if (item.IsString()) - item.Enabled = false; - } - for (i = 0; i < _strings.Size(); i++) - { - if (_strings[i].FinalSize() == 0) - continue; - CMixItem mixItem; - mixItem.StringIndex = (int)i; - mixItem.SectionIndex = (int)sectionIndex; - _mixItems.Add(mixItem); - } - } - - _usedRes.Free(); - - { - // PSize can be much larger than VSize in some exe installers. - // it contains archive data after PE resources. - // So we need to use PSize here! - if (maxOffset < sect.PSize) - { - size_t end = fileSize; - - // we skip Zeros to start of aligned block - size_t i; - for (i = maxOffset; i < end; i++) - if (_buf[i] != 0) - break; - if (i == end) - maxOffset = end; - - CSection sect2; - sect2.Flags = 0; - sect2.Pa = sect.Pa + (UInt32)maxOffset; - sect2.Va = sect.Va + (UInt32)maxOffset; - - // 9.29: we use sect.PSize instead of sect.VSize to support some CAB-SFX - // the code for .rsrc_2 is commented. - sect2.PSize = sect.PSize - (UInt32)maxOffset; - - if (sect2.PSize != 0) - { - sect2.ExtractSize = sect2.VSize = sect2.PSize; - sect2.Name = ".rsrc_1"; - sect2.Time = 0; - sect2.IsAdditionalSection = true; - _sections.Add(sect2); - } - } - } - - return S_OK; -} - - -bool CHeader::ParseCoff(const Byte *p) -{ - ParseBase(p); - if (PointerToSymbolTable < kCoffHeaderSize) - return false; - if (NumSymbols >= (1 << 24)) - return false; - if (OptHeaderSize != 0 && OptHeaderSize < k_OptHeader32_Size_MIN) - return false; - - // 18.04: we reduce false detections - if (NumSections == 0 && OptHeaderSize == 0) - return false; - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_MachinePairs); i++) - if (Machine == g_MachinePairs[i].Value) - return true; - if (Machine == 0) - return true; - - return false; -} - - -static inline bool CheckPeOffset(UInt32 pe) -{ - // ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value. - return pe >= 0x40 && pe <= 0x1000 /* && (pe & 7) == 0 */ ; -} - -static const unsigned kStartSize = 0x40; - -API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size) -{ - if (size < 2) - return k_IsArc_Res_NEED_MORE; - if (p[0] != 'M' || p[1] != 'Z') - return k_IsArc_Res_NO; - if (size < kStartSize) - return k_IsArc_Res_NEED_MORE; - UInt32 pe = Get32(p + 0x3C); - if (!CheckPeOffset(pe)) - return k_IsArc_Res_NO; - if (pe + kPeHeaderSize > size) - return k_IsArc_Res_NEED_MORE; - CHeader header; - if (!header.ParsePe(p + pe)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) -{ - UInt32 coffOffset = 0; - if (_coffMode) - { - Byte h[kCoffHeaderSize]; - RINOK(ReadStream_FALSE(stream, h, kCoffHeaderSize)) - if (!_header.ParseCoff(h)) - return S_FALSE; - } - else - { - UInt32 _peOffset; - { - Byte h[kStartSize]; - RINOK(ReadStream_FALSE(stream, h, kStartSize)) - if (h[0] != 'M' || h[1] != 'Z') - return S_FALSE; - /* most of PE files contain 0x0090 at offset 2. - But some rare PE files contain another values. So we don't use that check. - if (Get16(h + 2) != 0x90) return false; */ - _peOffset = Get32(h + 0x3C); - if (!CheckPeOffset(_peOffset)) - return S_FALSE; - coffOffset = _peOffset + 4; - } - { - Byte h[kPeHeaderSize]; - RINOK(InStream_SeekSet(stream, _peOffset)) - RINOK(ReadStream_FALSE(stream, h, kPeHeaderSize)) - if (!_header.ParsePe(h)) - return S_FALSE; - } - } - - const UInt32 optStart = coffOffset + kCoffHeaderSize; - const UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize; - _totalSize = optStart + bufSize; - CByteBuffer buffer(bufSize); - - RINOK(ReadStream_FALSE(stream, buffer, bufSize)) - - // memset((void *)&_optHeader, 0, sizeof(_optHeader)); - if (_header.OptHeaderSize != 0) - if (!_optHeader.Parse(buffer, _header.OptHeaderSize)) - return S_FALSE; - - UInt32 pos = _header.OptHeaderSize; - unsigned i; - for (i = 0; i < _header.NumSections; i++, pos += kSectionSize) - { - CSection § = _sections.AddNew(); - sect.Parse(buffer + pos); - sect.IsRealSect = true; - if (sect.Name.IsEqualTo(".reloc")) - { - const CDirLink &dl = _optHeader.DirItems[kDirLink_BASERELOC]; - if (dl.Va == sect.Va && - dl.Size <= sect.PSize) - sect.ExtractSize = dl.Size; - } - else if (sect.Name.IsEqualTo(".pdata")) - { - const CDirLink &dl = _optHeader.DirItems[kDirLink_EXCEPTION]; - if (dl.Va == sect.Va && - dl.Size <= sect.PSize) - sect.ExtractSize = dl.Size; - } - - /* PE pre-file in .hxs file has errors: - PSize of resource is larger than real size. - So it overlaps next ".its" section. - 7-zip before 22.02: we corrected it. - - 22.02: another bad case is possible in incorrect pe (exe) file: - PSize in .rsrc section is correct, - but next .reloc section has incorrect (Pa) that overlaps with .rsrc. - */ - - if (i != 0) - { - const CSection &prev = _sections[i - 1]; - if (prev.Pa < sect.Pa - && prev.Pa + prev.PSize > sect.Pa - && sect.PSize != 0 - && prev.PSize != 0) - { - _sectionsError = true; - // PRF(printf("\n !!!! Section correction: %s\n ", prev.Name)); - - /* we corrected that case in 7-zip before 22.02: */ - // prev.PSize = sect.Pa - prev.Pa; - - /* 22.02: here we can try to change bad section position to expected postion. - but original Windows code probably will not do same things. */ - // if (prev.PSize <= sect.Va - prev.Va) sect.Pa = prev.Pa + prev.PSize; - } - } - /* last ".its" section in hxs file has incorrect sect.PSize. - 7-zip before 22.02: we reduced section to real sect.VSize */ - /* - if (sect.VSize == 24 && sect.PSize == 512 && i == (unsigned)_header.NumSections - 1) - sect.PSize = sect.VSize; - */ - } - - for (i = 0; i < _sections.Size(); i++) - _sections[i].UpdateTotalSize(_totalSize); - - bool thereISDebug = false; - if (IsOpt()) - { - RINOK(LoadDebugSections(stream, thereISDebug)) - - const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate]; - if (certLink.Size != 0) - { - CSection § = _sections.AddNew(); - sect.Name = "CERTIFICATE"; - sect.Va = 0; - sect.Pa = certLink.Va; - sect.Set_Size_for_all(certLink.Size); - sect.UpdateTotalSize(_totalSize); - } - - if (thereISDebug) - { - /* sometime there is some data after debug section. - We don't see any reference in exe file to that data. - But we suppose that it's part of EXE file */ - - const UInt32 kAlign = 1 << 12; - UInt32 alignPos = _totalSize & (kAlign - 1); - if (alignPos != 0) - { - UInt32 size = kAlign - alignPos; - RINOK(InStream_SeekSet(stream, _totalSize)) - buffer.Alloc(kAlign); - Byte *buf = buffer; - size_t processed = size; - RINOK(ReadStream(stream, buf, &processed)) - - /* - if (processed != 0) - { - printf("\ndata after debug %d, %d \n", (int)size, (int)processed); - fflush(stdout); - } - */ - - size_t k; - for (k = 0; k < processed; k++) - if (buf[k] != 0) - break; - if (processed < size && processed < 100) - _totalSize += (UInt32)processed; - else if (((_totalSize + k) & 0x1FF) == 0 || processed < size) - _totalSize += (UInt32)k; - } - } - } - - if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= optStart) - { - if (_header.NumSymbols >= (1 << 24)) - return S_FALSE; - UInt32 size = _header.NumSymbols * 18; - RINOK(InStream_SeekSet(stream, (UInt64)_header.PointerToSymbolTable + size)) - Byte buf[4]; - RINOK(ReadStream_FALSE(stream, buf, 4)) - UInt32 size2 = Get32(buf); - if (size2 >= (1 << 28)) - return S_FALSE; - size += size2; - - CSection § = _sections.AddNew(); - sect.Name = "COFF_SYMBOLS"; - sect.Va = 0; - sect.Pa = _header.PointerToSymbolTable; - sect.Set_Size_for_all(size); - sect.UpdateTotalSize(_totalSize); - } - - { - CObjectVector sections = _sections; - sections.Sort(); - UInt32 limit = (1 << 12); - unsigned num = 0; - FOR_VECTOR (k, sections) - { - const CSection &s = sections[k]; - if (s.Pa > limit) - { - CSection &s2 = _sections.AddNew(); - s2.Pa = s2.Va = limit; - s2.Set_Size_for_all(s.Pa - limit); - s2.IsAdditionalSection = true; - s2.Name.Add_Char('['); - s2.Name.Add_UInt32(num++); - s2.Name.Add_Char(']'); - limit = s.Pa; - } - UInt32 next = s.Pa + s.PSize; - if (next < s.Pa) - break; - if (next >= limit) - limit = next; - } - } - - - if (IsOpt()) - if (_optHeader.CheckSum != 0) - { - RINOK(InStream_SeekToBegin(stream)) - UInt32 checkSum = 0; - RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum)) - _checksumError = (checkSum != _optHeader.CheckSum); - } - - - if (!_allowTail) - { - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) - if (fileSize > _totalSize) - return S_FALSE; - } - - bool _parseResources = true; - // _parseResources = false; // for debug - - UInt64 mainSize = 0, mainSize2 = 0; - - for (i = 0; i < _sections.Size(); i++) - { - const CSection § = _sections[i]; - if (IsOpt()) - if (_parseResources && sect.Name == ".rsrc") - { - // 20.01: we try to parse only first copy of .rsrc section. - _parseResources = false; - const unsigned numMixItems = _mixItems.Size(); - HRESULT res = OpenResources(i, stream, callback); - if (res == S_OK) - { - _resourcesPrefix = sect.Name.Ptr(); - _resourcesPrefix.Add_PathSepar(); - FOR_VECTOR (j, _items) - { - const CResItem &item = _items[j]; - if (item.Enabled) - { - CMixItem mixItem; - mixItem.SectionIndex = (int)i; - mixItem.ResourceIndex = (int)j; - if (item.IsRcDataOrUnknown()) - { - if (item.Size >= mainSize) - { - mainSize2 = mainSize; - mainSize = item.Size; - _mainSubfile = (Int32)(int)_mixItems.Size(); - } - else if (item.Size >= mainSize2) - mainSize2 = item.Size; - } - _mixItems.Add(mixItem); - } - } - // 9.29: .rsrc_2 code was commented. - // .rsrc_1 now must include that .rsrc_2 block. - /* - if (sect.PSize > sect.VSize) - { - int numBits = _optHeader.GetNumFileAlignBits(); - if (numBits >= 0) - { - UInt32 mask = (1 << numBits) - 1; - UInt32 end = ((sect.VSize + mask) & ~mask); - - if (sect.PSize > end) - { - CSection §2 = _sections.AddNew(); - sect2.Flags = 0; - sect2.Pa = sect.Pa + end; - sect2.Va = sect.Va + end; - sect2.PSize = sect.PSize - end; - sect2.VSize = sect2.PSize; - sect2.Name = ".rsrc_2"; - sect2.Time = 0; - sect2.IsAdditionalSection = true; - } - } - } - */ - continue; - } - if (res != S_FALSE) - return res; - _mixItems.DeleteFrom(numMixItems); - CloseResources(); - } - - if (sect.IsAdditionalSection) - { - if (sect.PSize >= mainSize) - { - mainSize2 = mainSize; - mainSize = sect.PSize; - _mainSubfile = (Int32)(int)_mixItems.Size(); - } - else if (sect.PSize >= mainSize2) - mainSize2 = sect.PSize; - } - - CMixItem mixItem; - mixItem.SectionIndex = (int)i; - _mixItems.Add(mixItem); - } - - if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2) - _mainSubfile = -1; - - for (i = 0; i < _mixItems.Size(); i++) - { - const CMixItem &mixItem = _mixItems[i]; - if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_") - { - _mainSubfile = (Int32)(int)i; - break; - } - } - - for (i = 0; i < _versionKeys.Size(); i++) - { - if (i != 0) - _versionFullString.Add_LF(); - const CStringKeyValue &k = _versionKeys[i]; - _versionFullString += k.Key; - _versionFullString += ": "; - _versionFullString += k.Value; - } - - { - int keyIndex = FindKey(_versionKeys, "OriginalFilename"); - if (keyIndex >= 0) - _originalFilename = _versionKeys[keyIndex].Value; - } - { - int keyIndex = FindKey(_versionKeys, "FileDescription"); - if (keyIndex >= 0) - _versionShortString = _versionKeys[keyIndex].Value; - } - { - int keyIndex = FindKey(_versionKeys, "FileVersion"); - if (keyIndex >= 0) - { - _versionShortString.Add_Space(); - _versionShortString += _versionKeys[keyIndex].Value; - } - } - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - RINOK(Open2(inStream, callback)) - _stream = inStream; - return S_OK; - COM_TRY_END -} - -void CHandler::CloseResources() -{ - _usedRes.Free(); - _items.Clear(); - _strings.Clear(); - _versionFiles.Clear(); - _buf.Free(); - _versionFullString.Empty(); - _versionShortString.Empty(); - _originalFilename.Empty(); - _versionKeys.Clear(); -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - _checksumError = false; - _sectionsError = false; - _mainSubfile = -1; - - _stream.Release(); - _sections.Clear(); - _mixItems.Clear(); - CloseResources(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _mixItems.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _mixItems.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]]; - UInt64 size; - if (mixItem.StringIndex >= 0) - size = _strings[mixItem.StringIndex].FinalSize(); - else if (mixItem.VersionIndex >= 0) - size = _versionFiles[mixItem.VersionIndex].Size(); - else if (mixItem.ResourceIndex >= 0) - size = _items[mixItem.ResourceIndex].GetSize(); - else - size = _sections[mixItem.SectionIndex].GetSize_Extract(); - totalSize += size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - - totalSize = 0; - UInt64 currentItemSize; - - for (i = 0;; i++, totalSize += currentItemSize) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - const CMixItem &mixItem = _mixItems[index]; - - const CSection § = _sections[mixItem.SectionIndex]; - bool isOk = true; - if (mixItem.StringIndex >= 0) - { - const CStringItem &item = _strings[mixItem.StringIndex]; - currentItemSize = item.FinalSize(); - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - if (outStream) - RINOK(WriteStream(outStream, item.Buf, item.FinalSize())) - } - else if (mixItem.VersionIndex >= 0) - { - const CByteBuffer &item = _versionFiles[mixItem.VersionIndex]; - currentItemSize = item.Size(); - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - if (outStream) - RINOK(WriteStream(outStream, item, item.Size())) - } - else if (mixItem.ResourceIndex >= 0) - { - const CResItem &item = _items[mixItem.ResourceIndex]; - currentItemSize = item.GetSize(); - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - size_t offset = item.Offset - sect.Va; - if (!CheckItem(sect, item, offset)) - isOk = false; - else if (outStream) - { - if (item.HeaderSize != 0) - RINOK(WriteStream(outStream, item.Header, item.HeaderSize)) - RINOK(WriteStream(outStream, _buf + offset, item.Size)) - } - } - else - { - currentItemSize = sect.GetSize_Extract(); - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(InStream_SeekSet(_stream, sect.Pa)) - inStream->Init(currentItemSize); - RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) - isOk = (copyCoder->TotalSize == currentItemSize); - } - - outStream.Release(); - RINOK(extractCallback->SetOperationResult(isOk ? - NExtract::NOperationResult::kOK : - NExtract::NOperationResult::kDataError)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - - const CMixItem &mixItem = _mixItems[index]; - const CSection § = _sections[mixItem.SectionIndex]; - if (mixItem.IsSectionItem()) - return CreateLimitedInStream(_stream, sect.Pa, sect.GetSize_Extract(), stream); - - CBufInStream *inStreamSpec = new CBufInStream; - CMyComPtr streamTemp = inStreamSpec; - CReferenceBuf *referenceBuf = new CReferenceBuf; - CMyComPtr ref = referenceBuf; - if (mixItem.StringIndex >= 0) - { - const CStringItem &item = _strings[mixItem.StringIndex]; - referenceBuf->Buf.CopyFrom(item.Buf, item.FinalSize()); - } - else if (mixItem.VersionIndex >= 0) - { - const CByteBuffer &item = _versionFiles[mixItem.VersionIndex]; - referenceBuf->Buf.CopyFrom(item, item.Size()); - } - else - { - const CResItem &item = _items[mixItem.ResourceIndex]; - size_t offset = item.Offset - sect.Va; - if (!CheckItem(sect, item, offset)) - return S_FALSE; - if (item.HeaderSize == 0) - { - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr streamTemp2 = streamSpec; - streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this); - *stream = streamTemp2.Detach(); - return S_OK; - } - referenceBuf->Buf.Alloc(item.HeaderSize + item.Size); - memcpy(referenceBuf->Buf, item.Header, item.HeaderSize); - if (item.Size != 0) - memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); - } - inStreamSpec->Init(referenceBuf); - - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { 'M', 'Z' }; - -REGISTER_ARC_I( - "PE", "exe dll sys", NULL, 0xDD, - k_Signature, - 0, - NArcInfoFlags::kPreArc, - IsArc_Pe) - -} - -namespace NCoff { - -API_FUNC_static_IsArc IsArc_Coff(const Byte *p, size_t size) -{ - if (size < NPe::kCoffHeaderSize) - return k_IsArc_Res_NEED_MORE; - NPe::CHeader header; - if (!header.ParseCoff(p)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -/* -static const Byte k_Signature[] = -{ - 2, 0x4C, 0x01, // x86 - 2, 0x64, 0x86, // x64 - 2, 0x64, 0xAA // ARM64 -}; -REGISTER_ARC_I_CLS( -*/ - -REGISTER_ARC_I_CLS_NO_SIG( - NPe::CHandler(true), - "COFF", "obj", NULL, 0xC6, - // k_Signature, - 0, - // NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kStartOpen, - IsArc_Coff) -} - - -namespace NTe { - -// Terse Executable (TE) image - -struct CDataDir -{ - UInt32 Va; - UInt32 Size; - - void Parse(const Byte *p) - { - G32(0, Va); - G32(4, Size); - } -}; - -static const UInt32 kHeaderSize = 40; - -static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) -{ - for (unsigned i = 0; i < num; i++) - if (pairs[i].Value == value) - return true; - return false; -} - -#define MY_FIND_VALUE(pairs, val) FindValue(pairs, Z7_ARRAY_SIZE(pairs), val) -#define MY_FIND_VALUE_2(strings, val) (val < Z7_ARRAY_SIZE(strings) && strings[val]) - -static const UInt32 kNumSection_MAX = 32; - -struct CHeader -{ - UInt16 Machine; - Byte NumSections; - Byte SubSystem; - UInt16 StrippedSize; - /* - UInt32 AddressOfEntryPoint; - UInt32 BaseOfCode; - UInt64 ImageBase; - */ - CDataDir DataDir[2]; // base relocation and debug directory - - bool ConvertPa(UInt32 &pa) const - { - if (pa < StrippedSize) - return false; - pa = pa - StrippedSize + kHeaderSize; - return true; - } - bool Parse(const Byte *p); -}; - -bool CHeader::Parse(const Byte *p) -{ - NumSections = p[4]; - if (NumSections > kNumSection_MAX) - return false; - SubSystem = p[5]; - G16(2, Machine); - G16(6, StrippedSize); - /* - G32(8, AddressOfEntryPoint); - G32(12, BaseOfCode); - G64(16, ImageBase); - */ - for (unsigned i = 0; i < 2; i++) - { - CDataDir &dd = DataDir[i]; - dd.Parse(p + 24 + i * 8); - if (dd.Size >= ((UInt32)1 << 28)) - return false; - } - return - MY_FIND_VALUE(NPe::g_MachinePairs, Machine) && - MY_FIND_VALUE_2(NPe::g_SubSystems, SubSystem); -} - -API_FUNC_static_IsArc IsArc_Te(const Byte *p, size_t size) -{ - if (size < 2) - return k_IsArc_Res_NEED_MORE; - if (p[0] != 'V' || p[1] != 'Z') - return k_IsArc_Res_NO; - if (size < kHeaderSize) - return k_IsArc_Res_NEED_MORE; - - CHeader h; - if (!h.Parse(p)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - - -struct CSection -{ - Byte Name[NPe::kNameSize]; - - UInt32 ExtractSize; - UInt32 VSize; - UInt32 Va; - UInt32 PSize; - UInt32 Pa; - UInt32 Flags; - // UInt16 NumRelocs; - - void Parse(const Byte *p) - { - memcpy(Name, p, NPe::kNameSize); - G32(8, VSize); - G32(12, Va); - G32(16, PSize); - G32(20, Pa); - // G32(p + 32, NumRelocs); - G32(36, Flags); - ExtractSize = (VSize && VSize < PSize) ? VSize : PSize; - } - - bool Check() const - { - return - Pa <= ((UInt32)1 << 30) && - PSize <= ((UInt32)1 << 30); - } - - UInt32 GetSize_Extract() const - { - return ExtractSize; - } - - void UpdateTotalSize(UInt32 &totalSize) - { - const UInt32 t = Pa + PSize; - if (totalSize < t) - totalSize = t; - } -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_2( - IInArchiveGetStream, - IArchiveAllowTail -) - CRecordVector _items; - CMyComPtr _stream; - UInt32 _totalSize; - bool _allowTail; - CHeader _h; - - HRESULT Open2(IInStream *stream); -public: - CHandler(): _allowTail(false) {} -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidVirtualSize, - kpidCharacts, - kpidOffset, - kpidVa -}; - -enum -{ - kpidSubSystem = kpidUserDefined - // , kpidImageBase -}; - -static const CStatProp kArcProps[] = -{ - // { NULL, kpidHeadersSize, VT_UI4 }, - { NULL, kpidCpu, VT_BSTR}, - { "Subsystem", kpidSubSystem, VT_BSTR }, - // { "Image Base", kpidImageBase, VT_UI8 } -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _totalSize; break; - case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break; - case kpidSubSystem: TYPE_TO_PROP(NPe::g_SubSystems, _h.SubSystem, prop); break; - /* - case kpidImageBase: prop = _h.ImageBase; break; - case kpidAddressOfEntryPoint: prop = _h.AddressOfEntryPoint; break; - case kpidBaseOfCode: prop = _h.BaseOfCode; break; - */ - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - { - const CSection &item = _items[index]; - switch (propID) - { - case kpidPath: - { - AString name; - NPe::GetName(item.Name, name); - prop = MultiByteToUnicodeString(name); - break; - } - case kpidSize: prop = (UInt64)item.GetSize_Extract(); break; - case kpidPackSize: prop = (UInt64)item.PSize; break; - case kpidVirtualSize: prop = (UInt64)item.VSize; break; - case kpidOffset: prop = item.Pa; break; - case kpidVa: prop = item.Va; break; - case kpidCharacts: FLAGS_TO_PROP(NPe::g_SectFlags, item.Flags, prop); break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -HRESULT CHandler::Open2(IInStream *stream) -{ - Byte h[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, h, kHeaderSize)) - if (h[0] != 'V' || h[1] != 'Z') - return S_FALSE; - if (!_h.Parse(h)) - return S_FALSE; - - UInt32 headerSize = NPe::kSectionSize * (UInt32)_h.NumSections; - CByteArr buf(headerSize); - RINOK(ReadStream_FALSE(stream, buf, headerSize)) - headerSize += kHeaderSize; - - _totalSize = headerSize; - _items.ClearAndReserve(_h.NumSections); - for (UInt32 i = 0; i < _h.NumSections; i++) - { - CSection sect; - sect.Parse(buf + i * NPe::kSectionSize); - if (!_h.ConvertPa(sect.Pa)) - return S_FALSE; - if (sect.Pa < headerSize) - return S_FALSE; - if (!sect.Check()) - return S_FALSE; - _items.AddInReserved(sect); - sect.UpdateTotalSize(_totalSize); - } - - if (!_allowTail) - { - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) - if (fileSize > _totalSize) - return S_FALSE; - } - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - Close(); - // try - { - if (Open2(inStream) != S_OK) - return S_FALSE; - _stream = inStream; - } - // catch(...) { return S_FALSE; } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - _stream.Release(); - _items.Clear(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].GetSize_Extract(); - RINOK(extractCallback->SetTotal(totalSize)) - - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create inStream; - inStream->SetStream(_stream); - - totalSize = 0; - - for (i = 0;; i++) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - int opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CSection &item = _items[index]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - const UInt32 size = item.GetSize_Extract(); - totalSize += size; - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(InStream_SeekSet(_stream, item.Pa)) - inStream->Init(size); - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - - opRes = (copyCoder->TotalSize == size) ? - NExtract::NOperationResult::kOK : (copyCoder->TotalSize < size) ? - NExtract::NOperationResult::kUnexpectedEnd : - NExtract::NOperationResult::kDataError; - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - const CSection &item = _items[index]; - return CreateLimitedInStream(_stream, item.Pa, item.GetSize_Extract(), stream); - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) -{ - _allowTail = IntToBool(allowTail); - return S_OK; -} - -static const Byte k_Signature[] = { 'V', 'Z' }; - -REGISTER_ARC_I( - "TE", "te", NULL, 0xCF, - k_Signature, - 0, - NArcInfoFlags::kPreArc, - IsArc_Te) - -} -} +// PeHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/DynamicBuffer.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(offs, v) v = Get16(p + (offs)) +#define G32(offs, v) v = Get32(p + (offs)) +#define G32_signed(offs, v) v = (Int32)Get32(p + (offs)) +#define G64(offs, v) v = Get64(p + (offs)) + +#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } + +using namespace NWindows; + +namespace NArchive { +namespace NPe { + +static const UInt32 k_Signature32 = 0x00004550; + +static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res) +{ + const UInt32 kBufSizeMax = (UInt32)1 << 15; + UInt32 bufSize = kBufSizeMax; + CByteBuffer buffer(bufSize); + Byte *buf = buffer; + UInt32 sum = 0; + UInt32 pos = 0; + for (;;) + { + UInt32 rem = size - pos; + if (rem > bufSize) + rem = bufSize; + if (rem == 0) + break; + size_t processed = rem; + RINOK(ReadStream(stream, buf, &processed)) + + for (unsigned j = 0; j < 4; j++) + { + UInt32 e = excludePos + j; + if (pos <= e) + { + e -= pos; + if (e < processed) + buf[e] = 0; + } + } + + const unsigned kStep = (1 << 4); + { + for (size_t i = processed; (i & (kStep - 1)) != 0; i++) + buf[i] = 0; + } + { + const Byte *buf2 = buf; + const Byte *bufLimit = buf + processed; + UInt64 sum2 = 0; + for (; buf2 < bufLimit; buf2 += kStep) + { + UInt64 sum3 = (UInt64)Get32(buf2) + + Get32(buf2 + 4) + + Get32(buf2 + 8) + + Get32(buf2 + 12); + sum2 += sum3; + } + sum2 = (UInt32)(sum2) + (UInt64)(sum2 >> 32); + UInt32 sum3 = ((UInt32)sum2 + (UInt32)(sum2 >> 32)); + sum += (sum3 & 0xFFFF) + (sum3 >> 16); + sum = (sum & 0xFFFF) + (sum >> 16); + sum = (sum & 0xFFFF) + (sum >> 16); + } + + pos += (UInt32)processed; + if (rem != processed) + break; + } + res = sum + pos; + return S_OK; +} + + +struct CVersion +{ + UInt16 Major; + UInt16 Minor; + + void Parse(const Byte *p) + { + G16(0, Major); + G16(2, Minor); + } + void ToProp(NCOM::CPropVariant &prop); +}; + +void CVersion::ToProp(NCOM::CPropVariant &prop) +{ + char sz[32]; + ConvertUInt32ToString(Major, sz); + unsigned len = MyStringLen(sz); + sz[len] = '.'; + ConvertUInt32ToString(Minor, sz + len + 1); + prop = sz; +} + +static const unsigned kCoffHeaderSize = 20; +static const unsigned kPeHeaderSize = 4 + kCoffHeaderSize; +static const unsigned k_OptHeader32_Size_MIN = 96; +static const unsigned k_OptHeader64_Size_MIN = 112; + +static const UInt32 PE_IMAGE_FILE_DLL = (1 << 13); + +struct CHeader +{ + UInt16 Machine; + UInt16 NumSections; + UInt32 Time; + UInt32 PointerToSymbolTable; + UInt32 NumSymbols; + UInt16 OptHeaderSize; + UInt16 Flags; + + void ParseBase(const Byte *p); + bool ParseCoff(const Byte *p); + bool ParsePe(const Byte *p); + bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; } +}; + +void CHeader::ParseBase(const Byte *p) +{ + G16( 0, Machine); + G16( 2, NumSections); + G32( 4, Time); + G32( 8, PointerToSymbolTable); + G32(12, NumSymbols); + G16(16, OptHeaderSize); + G16(18, Flags); +} + +bool CHeader::ParsePe(const Byte *p) +{ + if (Get32(p) != k_Signature32) + return false; + ParseBase(p + 4); + return OptHeaderSize >= k_OptHeader32_Size_MIN; +} + +struct CDirLink +{ + UInt32 Va; + UInt32 Size; + + CDirLink(): Va(0), Size(0) {} + void Parse(const Byte *p) + { + G32(0, Va); + G32(4, Size); + } +}; + + +// IMAGE_DIRECTORY_ENTRY_* +static const char * const g_Dir_Names[] = +{ + "EXPORT" + , "IMPORT" + , "RESOURCE" + , "EXCEPTION" + , "SECURITY" + , "BASERELOC" + , "DEBUG" + , "ARCHITECTURE" // "COPYRIGHT" + , "GLOBALPTR" + , "TLS" + , "LOAD_CONFIG" + , "BOUND_IMPORT" + , "IAT" + , "DELAY_IMPORT" + , "COM_DESCRIPTOR" +}; + +enum +{ + kDirLink_EXCEPTION = 3, + kDirLink_Certificate = 4, + kDirLink_BASERELOC = 5, + kDirLink_Debug = 6 +}; + +static const UInt32 kNumDirItemsMax = 16; + +struct CDebugEntry +{ + UInt32 Flags; + UInt32 Time; + CVersion Ver; + UInt32 Type; + UInt32 Size; + UInt32 Va; + UInt32 Pa; + + void Parse(const Byte *p) + { + G32(0, Flags); + G32(4, Time); + Ver.Parse(p + 8); + G32(12, Type); + G32(16, Size); + G32(20, Va); + G32(24, Pa); + } +}; + +static const UInt32 k_CheckSum_Field_Offset = 64; + +static const UInt32 PE_OptHeader_Magic_32 = 0x10B; +static const UInt32 PE_OptHeader_Magic_64 = 0x20B; + +static const UInt32 k_SubSystems_EFI_First = 10; +static const UInt32 k_SubSystems_EFI_Last = 13; + +struct COptHeader +{ + UInt16 Magic; + Byte LinkerVerMajor; + Byte LinkerVerMinor; + + UInt32 CodeSize; + UInt32 InitDataSize; + UInt32 UninitDataSize; + + // UInt32 AddressOfEntryPoint; + // UInt32 BaseOfCode; // VA(.text) == 0x1000 in most cases + // UInt32 BaseOfData32; + UInt64 ImageBase; + + UInt32 SectAlign; + UInt32 FileAlign; + + CVersion OsVer; + CVersion ImageVer; + CVersion SubsysVer; + + UInt32 ImageSize; + UInt32 HeadersSize; + UInt32 CheckSum; + UInt16 SubSystem; + UInt16 DllCharacts; + + UInt64 StackReserve; + UInt64 StackCommit; + UInt64 HeapReserve; + UInt64 HeapCommit; + + UInt32 NumDirItems; + CDirLink DirItems[kNumDirItemsMax]; + + bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; } + bool Parse(const Byte *p, UInt32 size); + + int GetNumFileAlignBits() const + { + for (unsigned i = 0; i < 32; i++) + if (((UInt32)1 << i) == FileAlign) + return (int)i; + return -1; + } + + bool IsSybSystem_EFI() const + { + return + SubSystem >= k_SubSystems_EFI_First && + SubSystem <= k_SubSystems_EFI_Last; + } +}; + +// size is 16-bit +bool COptHeader::Parse(const Byte *p, UInt32 size) +{ + if (size < k_OptHeader32_Size_MIN) + return false; + Magic = Get16(p); + switch (Magic) + { + case PE_OptHeader_Magic_32: + case PE_OptHeader_Magic_64: + break; + default: + return false; + } + LinkerVerMajor = p[2]; + LinkerVerMinor = p[3]; + + G32( 4, CodeSize); + G32( 8, InitDataSize); + G32(12, UninitDataSize); + // G32(16, AddressOfEntryPoint); + // G32(20, BaseOfCode); + + G32(32, SectAlign); + G32(36, FileAlign); + + OsVer.Parse(p + 40); + ImageVer.Parse(p + 44); + SubsysVer.Parse(p + 48); + + // reserved = Get32(p + 52); + + G32(56, ImageSize); + G32(60, HeadersSize); + G32(64, CheckSum); + G16(68, SubSystem); + G16(70, DllCharacts); + + UInt32 pos; + if (Is64Bit()) + { + if (size < k_OptHeader64_Size_MIN) + return false; + // BaseOfData32 = 0; + G64(24, ImageBase); + G64(72, StackReserve); + G64(80, StackCommit); + G64(88, HeapReserve); + G64(96, HeapCommit); + pos = 108; + } + else + { + // G32(24, BaseOfData32); + G32(28, ImageBase); + G32(72, StackReserve); + G32(76, StackCommit); + G32(80, HeapReserve); + G32(84, HeapCommit); + pos = 92; + } + + UInt32 numDirItems; + G32(pos, numDirItems); + NumDirItems = numDirItems; + if (numDirItems > (1 << 13)) + return false; + pos += 4; + if (pos + 8 * numDirItems > size) + return false; + memset((void *)DirItems, 0, sizeof(DirItems)); + if (numDirItems > kNumDirItemsMax) + numDirItems = kNumDirItemsMax; + for (UInt32 i = 0; i < numDirItems; i++) + DirItems[i].Parse(p + pos + i * 8); + return true; +} + +static const UInt32 kSectionSize = 40; + +struct CSection +{ + AString Name; + + UInt32 ExtractSize; + UInt32 VSize; + UInt32 Va; + UInt32 PSize; + UInt32 Pa; + UInt32 Flags; + UInt32 Time; + // UInt16 NumRelocs; // is set to zero for executable images + bool IsRealSect; + bool IsDebug; + bool IsAdditionalSection; + + CSection(): + ExtractSize(0), + IsRealSect(false), + IsDebug(false), + IsAdditionalSection(false) + // , NumRelocs(0) + {} + + void Set_Size_for_all(UInt32 size) + { + PSize = VSize = ExtractSize = size; + } + + UInt32 GetSize_Extract() const + { + return ExtractSize; + } + + void UpdateTotalSize(UInt32 &totalSize) const + { + const UInt32 t = Pa + PSize; + if (totalSize < t) + totalSize = t; + } + + void Parse(const Byte *p); + + int Compare(const CSection &s) const + { + RINOZ(MyCompare(Pa, s.Pa)) + const UInt32 size1 = GetSize_Extract(); + const UInt32 size2 = s.GetSize_Extract(); + return MyCompare(size1, size2); + } +}; + +static const unsigned kNameSize = 8; + +static void GetName(const Byte *name, AString &res) +{ + res.SetFrom_CalcLen((const char *)name, kNameSize); +} + +void CSection::Parse(const Byte *p) +{ + GetName(p, Name); + G32( 8, VSize); + G32(12, Va); + G32(16, PSize); + G32(20, Pa); + // G16(32, NumRelocs); + G32(36, Flags); + // v24.08: we extract only useful data (without extra padding bytes). + // VSize == 0 is not expected, but we support that case too. + // return (VSize && VSize < PSize) ? VSize : PSize; + ExtractSize = (VSize && VSize < PSize) ? VSize : PSize; +} + + + +// IMAGE_FILE_* + +static const CUInt32PCharPair g_HeaderCharacts[] = +{ + { 1, "Executable" }, + { 13, "DLL" }, + { 8, "32-bit" }, + { 5, "LargeAddress" }, + { 0, "NoRelocs" }, + { 2, "NoLineNums" }, + { 3, "NoLocalSyms" }, + { 4, "AggressiveWsTrim" }, + { 9, "NoDebugInfo" }, + { 10, "RemovableRun" }, + { 11, "NetRun" }, + { 12, "System" }, + { 14, "UniCPU" }, + { 7, "Little-Endian" }, + { 15, "Big-Endian" } +}; + +// IMAGE_DLLCHARACTERISTICS_* + +static const char * const g_DllCharacts[] = +{ + NULL + , NULL + , NULL + , NULL + , NULL + , "HighEntropyVA" + , "Relocated" + , "Integrity" + , "NX-Compatible" + , "NoIsolation" + , "NoSEH" + , "NoBind" + , "AppContainer" + , "WDM" + , "GuardCF" + , "TerminalServerAware" +}; + + +// IMAGE_SCN_* constants: + +static const char * const g_SectFlags[] = +{ + NULL + , NULL + , NULL + , "NoPad" + , NULL + , "Code" + , "InitializedData" + , "UninitializedData" + , "Other" + , "Comments" + , NULL // OVER + , "Remove" + , "COMDAT" + , NULL + , "NO_DEFER_SPEC_EXC" + , "GP" // MEM_FARDATA + , NULL // SYSHEAP + , "PURGEABLE" // 16BIT + , "LOCKED" + , "PRELOAD" + , NULL + , NULL + , NULL + , NULL + , "ExtendedRelocations" + , "Discardable" + , "NotCached" + , "NotPaged" + , "Shared" + , "Execute" + , "Read" + , "Write" +}; + +static const CUInt32PCharPair g_MachinePairs[] = +{ + { 0x014C, "x86" }, + { 0x014D, "I860" }, + { 0x0162, "MIPS-R3000" }, + { 0x0166, "MIPS-R4000" }, + { 0x0168, "MIPS-R10000" }, + { 0x0169, "MIPS-V2" }, + { 0x0184, "Alpha" }, + { 0x01A2, "SH3" }, + { 0x01A3, "SH3-DSP" }, + { 0x01A4, "SH3E" }, + { 0x01A6, "SH4" }, + { 0x01A8, "SH5" }, + { 0x01C0, "ARM" }, + { 0x01C2, "ARM-Thumb" }, + { 0x01C4, "ARM-NT" }, + { 0x01D3, "AM33" }, + { 0x01F0, "PPC" }, + { 0x01F1, "PPC-FP" }, + { 0x01F2, "PPC-BE" }, + { 0x0200, "IA-64" }, + { 0x0266, "MIPS-16" }, + { 0x0284, "Alpha-64" }, + { 0x0366, "MIPS-FPU" }, + { 0x0466, "MIPS-FPU16" }, + { 0x0520, "TriCore" }, + { 0x0CEF, "CEF" }, + { 0x0EBC, "EFI" }, + { 0x5032, "RISCV32" }, + { 0x5064, "RISCV64" }, +// { 0x5128, "RISCV128" }, + { 0x6232, "LOONGARCH32" }, + { 0x6264, "LOONGARCH64" }, + { 0x8664, "x64" }, + { 0x9041, "M32R" }, + { 0xA641, "ARM64EC" }, + { 0xA64e, "ARM64X" }, + { 0xAA64, "ARM64" }, + { 0xC0EE, "CEE" } +}; + +static const char * const g_SubSystems[] = +{ + "Unknown" + , "Native" + , "Windows GUI" + , "Windows CUI" + , NULL // "Old Windows CE" + , "OS2" + , NULL + , "Posix" + , "Win9x" + , "Windows CE" + , "EFI" + , "EFI Boot" + , "EFI Runtime" + , "EFI ROM" + , "XBOX" + , NULL + , "Windows Boot" + , "XBOX Catalog" // 17 +}; + +static const char * const g_ResTypes[] = +{ + NULL + , "CURSOR" + , "BITMAP" + , "ICON" + , "MENU" + , "DIALOG" + , "STRING" + , "FONTDIR" + , "FONT" + , "ACCELERATOR" + , "RCDATA" + , "MESSAGETABLE" + , "GROUP_CURSOR" + , NULL + , "GROUP_ICON" + , NULL + , "VERSION" + , "DLGINCLUDE" + , NULL + , "PLUGPLAY" + , "VXD" + , "ANICURSOR" + , "ANIICON" + , "HTML" + , "MANIFEST" +}; + +static const UInt32 kFlag = (UInt32)1 << 31; +static const UInt32 kMask = ~kFlag; + +struct CTableItem +{ + UInt32 Offset; + UInt32 ID; +}; + + +static const UInt32 kBmpHeaderSize = 14; +static const UInt32 kIconHeaderSize = 22; + +struct CResItem +{ + UInt32 Type; + UInt32 ID; + UInt32 Lang; + + UInt32 Size; + UInt32 Offset; + + UInt32 HeaderSize; + Byte Header[kIconHeaderSize]; // it must be enough for max size header. + bool Enabled; + + bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; } + UInt32 GetSize() const { return Size + HeaderSize; } + bool IsBmp() const { return Type == 2; } + bool IsIcon() const { return Type == 3; } + bool IsString() const { return Type == 6; } + bool IsRcData() const { return Type == 10; } + bool IsVersion() const { return Type == 16; } + bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; } +}; + +struct CTextFile +{ + CByteDynamicBuffer Buf; + + size_t FinalSize() const { return Buf.GetPos(); } + + void AddChar(char c); + void AddWChar(UInt16 c); + void AddWChar_Smart(UInt16 c); + void NewLine(); + void AddString(const char *s); + void AddSpaces(int num); + void AddBytes(const Byte *p, size_t size) + { + Buf.AddData(p, size); + } + + void OpenBlock(int num) + { + AddSpaces(num); + AddChar('{'); + NewLine(); + } + void CloseBlock(int num) + { + AddSpaces(num); + AddChar('}'); + NewLine(); + } +}; + +void CTextFile::AddChar(char c) +{ + Byte *p = Buf.GetCurPtrAndGrow(2); + p[0] = (Byte)c; + p[1] = 0; +} + +void CTextFile::AddWChar(UInt16 c) +{ + Byte *p = Buf.GetCurPtrAndGrow(2); + SetUi16(p, c) +} + +void CTextFile::AddWChar_Smart(UInt16 c) +{ + if (c == '\n') + { + AddChar('\\'); + c = 'n'; + } + AddWChar(c); +} + +void CTextFile::NewLine() +{ + AddChar(0x0D); + AddChar(0x0A); +} + +void CTextFile::AddString(const char *s) +{ + for (;; s++) + { + char c = *s; + if (c == 0) + return; + AddChar(c); + } +} + +void CTextFile::AddSpaces(int num) +{ + for (int i = 0; i < num; i++) + AddChar(' '); +} + +struct CStringItem: public CTextFile +{ + UInt32 Lang; +}; + +struct CByteBuffer_WithLang: public CByteBuffer +{ + UInt32 Lang; +}; + + +struct CMixItem +{ + int SectionIndex; + int ResourceIndex; + int StringIndex; + int VersionIndex; + + CMixItem(): SectionIndex(-1), ResourceIndex(-1), StringIndex(-1), VersionIndex(-1) {} + bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; } +}; + +struct CUsedBitmap +{ + CByteBuffer Buf; +public: + void Alloc(size_t size) + { + size = (size + 7) / 8; + Buf.Alloc(size); + memset(Buf, 0, size); + } + + void Free() + { + Buf.Free(); + } + + bool SetRange(size_t from, unsigned size) + { + for (unsigned i = 0; i < size; i++) + { + size_t pos = (from + i) >> 3; + Byte mask = (Byte)(1 << ((from + i) & 7)); + Byte b = Buf[pos]; + if ((b & mask) != 0) + return false; + Buf[pos] = (Byte)(b | mask); + } + return true; + } +}; + +struct CStringKeyValue +{ + UString Key; + UString Value; +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_2( + IInArchiveGetStream, + IArchiveAllowTail +) + CMyComPtr _stream; + CObjectVector _sections; + CHeader _header; + UInt32 _totalSize; + Int32 _mainSubfile; + + CRecordVector _mixItems; + CRecordVector _items; + CObjectVector _strings; + CObjectVector _versionFiles; + UString _versionFullString; + UString _versionShortString; + UString _originalFilename; + CObjectVector _versionKeys; + + CByteBuffer _buf; + bool _oneLang; + UString _resourcesPrefix; + CUsedBitmap _usedRes; + // bool _parseResources; + bool _checksumError; + bool _sectionsError; + + bool IsOpt() const { return _header.OptHeaderSize != 0; } + + COptHeader _optHeader; + + bool _coffMode; + bool _allowTail; + + HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); + + void AddResNameToString(UString &s, UInt32 id) const; + void AddLangPrefix(UString &s, UInt32 lang) const; + HRESULT ReadString(UInt32 offset, UString &dest) const; + HRESULT ReadTable(UInt32 offset, CRecordVector &items); + bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size); + HRESULT OpenResources(unsigned sectIndex, IInStream *stream, IArchiveOpenCallback *callback); + void CloseResources(); + + + bool CheckItem(const CSection §, const CResItem &item, size_t offset) const + { + return item.Offset >= sect.Va && offset <= _buf.Size() && _buf.Size() - offset >= item.Size; + } + +public: + CHandler(bool coffMode = false): + _coffMode(coffMode), + _allowTail(coffMode) + {} +}; + + +enum +{ + kpidSectAlign = kpidUserDefined, + kpidFileAlign, + kpidLinkerVer, + kpidOsVer, + kpidImageVer, + kpidSubsysVer, + kpidCodeSize, + kpidImageSize, + kpidInitDataSize, + kpidUnInitDataSize, + kpidHeadersSizeUnInitDataSize, + kpidSubSystem, + kpidDllCharacts, + kpidStackReserve, + kpidStackCommit, + kpidHeapReserve, + kpidHeapCommit + // , kpidImageBase + // , kpidAddressOfEntryPoint + // , kpidBaseOfCode + // , kpidBaseOfData32 +}; + +static const CStatProp kArcProps[] = +{ + // { NULL, kpidWarning, VT_BSTR}, + { NULL, kpidCpu, VT_BSTR}, + { NULL, kpidBit64, VT_BOOL}, + { NULL, kpidCharacts, VT_BSTR}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidHeadersSize, VT_UI4}, + { NULL, kpidChecksum, VT_UI4}, + { NULL, kpidName, VT_BSTR}, + + { "Image Size", kpidImageSize, VT_UI4}, + { "Section Alignment", kpidSectAlign, VT_UI4}, + { "File Alignment", kpidFileAlign, VT_UI4}, + { "Code Size", kpidCodeSize, VT_UI4}, + { "Initialized Data Size", kpidInitDataSize, VT_UI4}, + { "Uninitialized Data Size", kpidUnInitDataSize, VT_UI4}, + { "Linker Version", kpidLinkerVer, VT_BSTR}, + { "OS Version", kpidOsVer, VT_BSTR}, + { "Image Version", kpidImageVer, VT_BSTR}, + { "Subsystem Version", kpidSubsysVer, VT_BSTR}, + { "Subsystem", kpidSubSystem, VT_BSTR}, + { "DLL Characteristics", kpidDllCharacts, VT_BSTR}, + { "Stack Reserve", kpidStackReserve, VT_UI8}, + { "Stack Commit", kpidStackCommit, VT_UI8}, + { "Heap Reserve", kpidHeapReserve, VT_UI8}, + { "Heap Commit", kpidHeapCommit, VT_UI8}, + { NULL, kpidVa, VT_UI8 }, // "Image Base", kpidImageBase, VT_UI8 + { NULL, kpidComment, VT_BSTR} + + // , { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8} + // , { "Base Of Code", kpidBaseOfCode, VT_UI8} + // , { "Base Of Data", kpidBaseOfData32, VT_UI8} +}; + +// #define kpid_NumRelocs 250 + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidVirtualSize, + kpidCharacts, + kpidOffset, + kpidVa + // , kpid_NumRelocs +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) +{ + if (unixTime != 0) + PropVariant_SetFrom_UnixTime(prop, unixTime); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _totalSize; break; + case kpidComment: + { + UString s (_versionFullString); + s.Add_LF(); + s += "Data Directories: "; + s.Add_UInt32(_optHeader.NumDirItems); + s.Add_LF(); + s.Add_Char('{'); + s.Add_LF(); + for (unsigned i = 0; i < _optHeader.NumDirItems + && i < Z7_ARRAY_SIZE(_optHeader.DirItems); i++) + { + const CDirLink &di = _optHeader.DirItems[i]; + if (di.Va == 0 && di.Size == 0) + continue; + s += "index="; + s.Add_UInt32(i); + + if (i < Z7_ARRAY_SIZE(g_Dir_Names)) + { + s += " name="; + s += g_Dir_Names[i]; + } + s += " VA=0x"; + char temp[16]; + ConvertUInt32ToHex(di.Va, temp); + s += temp; + s += " Size="; + s.Add_UInt32(di.Size); + s.Add_LF(); + } + s.Add_Char('}'); + s.Add_LF(); + prop = s; + break; + } + case kpidShortComment: + if (!_versionShortString.IsEmpty()) + prop = _versionShortString; + else + { + PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); + } + break; + + case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break; + + // case kpidIsSelfExe: prop = !_header.IsDll(); break; + // case kpidError: + case kpidWarning: if (_checksumError) prop = "Checksum error"; break; + + case kpidWarningFlags: + { + UInt32 v = 0; + if (_sectionsError) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + + case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break; + case kpidMTime: + case kpidCTime: TimeToProp(_header.Time, prop); break; + case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + + default: + if (IsOpt()) + switch (propID) + { + + case kpidSectAlign: prop = _optHeader.SectAlign; break; + case kpidFileAlign: prop = _optHeader.FileAlign; break; + case kpidLinkerVer: + { + CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor }; + v.ToProp(prop); + break; + } + + case kpidOsVer: _optHeader.OsVer.ToProp(prop); break; + case kpidImageVer: _optHeader.ImageVer.ToProp(prop); break; + case kpidSubsysVer: _optHeader.SubsysVer.ToProp(prop); break; + case kpidCodeSize: prop = _optHeader.CodeSize; break; + case kpidInitDataSize: prop = _optHeader.InitDataSize; break; + case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break; + case kpidImageSize: prop = _optHeader.ImageSize; break; + case kpidHeadersSize: prop = _optHeader.HeadersSize; break; + case kpidChecksum: prop = _optHeader.CheckSum; break; + + case kpidExtension: + if (_header.IsDll()) + prop = "dll"; + else if (_optHeader.IsSybSystem_EFI()) + prop = "efi"; + break; + + case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break; + case kpidSubSystem: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break; + + case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break; + case kpidStackReserve: prop = _optHeader.StackReserve; break; + case kpidStackCommit: prop = _optHeader.StackCommit; break; + case kpidHeapReserve: prop = _optHeader.HeapReserve; break; + case kpidHeapCommit: prop = _optHeader.HeapCommit; break; + case kpidVa: prop = _optHeader.ImageBase; break; // kpidImageBase: + // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break; + // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break; + // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const +{ + if ((offset & 1) != 0 || offset >= _buf.Size()) + return S_FALSE; + size_t rem = _buf.Size() - offset; + if (rem < 2) + return S_FALSE; + unsigned len = Get16(_buf + offset); + if ((rem - 2) / 2 < len) + return S_FALSE; + dest.Empty(); + wchar_t *destBuf = dest.GetBuf(len); + offset += 2; + const Byte *src = _buf + offset; + unsigned i; + for (i = 0; i < len; i++) + { + wchar_t c = (wchar_t)Get16(src + i * 2); + if (c == 0) + break; + destBuf[i] = c; + } + destBuf[i] = 0; + dest.ReleaseBuf_SetLen(i); + return S_OK; +} + +void CHandler::AddResNameToString(UString &s, UInt32 id) const +{ + if ((id & kFlag) != 0) + { + UString name; + if (ReadString(id & kMask, name) == S_OK) + { + const wchar_t *str = L"[]"; + if (name.Len() > 1 && name[0] == '"' && name.Back() == '"') + { + if (name.Len() != 2) + { + name.DeleteBack(); + str = name.Ptr(1); + } + } + else if (!name.IsEmpty()) + str = name; + s += str; + return; + } + } + s.Add_UInt32(id); +} + +void CHandler::AddLangPrefix(UString &s, UInt32 lang) const +{ + if (!_oneLang) + { + AddResNameToString(s, lang); + s.Add_PathSepar(); + } +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CMixItem &mixItem = _mixItems[index]; + if (mixItem.StringIndex >= 0) + { + const CStringItem &item = _strings[mixItem.StringIndex]; + switch (propID) + { + case kpidPath: + { + UString s = _resourcesPrefix; + AddLangPrefix(s, item.Lang); + s += "string.txt"; + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)item.FinalSize(); break; + } + } + else if (mixItem.VersionIndex >= 0) + { + const CByteBuffer_WithLang &item = _versionFiles[mixItem.VersionIndex]; + switch (propID) + { + case kpidPath: + { + UString s = _resourcesPrefix; + AddLangPrefix(s, item.Lang); + s += "version.txt"; + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)item.Size(); break; + } + } + else if (mixItem.ResourceIndex >= 0) + { + const CResItem &item = _items[mixItem.ResourceIndex]; + switch (propID) + { + case kpidPath: + { + UString s = _resourcesPrefix; + AddLangPrefix(s, item.Lang); + { + const char *p = NULL; + if (item.Type < Z7_ARRAY_SIZE(g_ResTypes)) + p = g_ResTypes[item.Type]; + if (p) + s += p; + else + AddResNameToString(s, item.Type); + } + s.Add_PathSepar(); + AddResNameToString(s, item.ID); + if (item.HeaderSize != 0) + { + if (item.IsBmp()) + s += ".bmp"; + else if (item.IsIcon()) + s += ".ico"; + } + prop = s; + break; + } + case kpidSize: prop = (UInt64)item.GetSize(); break; + case kpidPackSize: prop = (UInt64)item.Size; break; + } + } + else + { + const CSection &item = _sections[mixItem.SectionIndex]; + switch (propID) + { + case kpidPath: + { + AString s = item.Name; + s.Replace('/', '_'); + s.Replace('\\', '_'); + prop = MultiByteToUnicodeString(s); + break; + } + case kpidSize: prop = (UInt64)item.GetSize_Extract(); break; + // case kpid_NumRelocs: prop = (UInt32)item.NumRelocs; break; + case kpidPackSize: prop = (UInt64)item.PSize; break; + case kpidVirtualSize: prop = (UInt64)item.VSize; break; + case kpidOffset: prop = item.Pa; break; + case kpidVa: if (item.IsRealSect) prop = item.Va; break; + case kpidMTime: + case kpidCTime: + TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break; + case kpidCharacts: + if (item.IsRealSect) + { + UInt32 flags = item.Flags; + const UInt32 MY_IMAGE_SCN_ALIGN_MASK = 0x00F00000; + AString s = FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & ~MY_IMAGE_SCN_ALIGN_MASK); + const UInt32 align = ((flags >> 20) & 0xF); + if (align != 0) + { + char sz[32]; + ConvertUInt32ToString(1 << (align - 1), sz); + s.Add_Space(); + s += "align_"; + s += sz; + } + prop = s; + } + break; + case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection) +{ + thereIsSection = false; + const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug]; + if (debugLink.Size == 0) + return S_OK; + const unsigned kEntrySize = 28; + UInt32 numItems = debugLink.Size / kEntrySize; + if (numItems > 16) + return S_FALSE; + + // MAC's EFI file: numItems can be incorrect. Only first CDebugEntry entry is correct. + // debugLink.Size = kEntrySize + some_data, pointed by entry[0]. + if (numItems * kEntrySize != debugLink.Size) + { + // return S_FALSE; + if (numItems > 1) + numItems = 1; + } + + UInt64 pa = 0; + unsigned i; + for (i = 0; i < _sections.Size(); i++) + { + const CSection § = _sections[i]; + if (sect.Va <= debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize) + { + pa = sect.Pa + (debugLink.Va - sect.Va); + break; + } + } + if (i == _sections.Size()) + { + // Exe for ARM requires S_OK + // return S_FALSE; + return S_OK; + } + + CByteBuffer buffer(debugLink.Size); + Byte *buf = buffer; + + RINOK(InStream_SeekSet(stream, pa)) + RINOK(ReadStream_FALSE(stream, buf, debugLink.Size)) + + for (i = 0; i < numItems; i++) + { + CDebugEntry de; + de.Parse(buf); + + if (de.Size == 0) + continue; + + UInt32 totalSize = de.Pa + de.Size; + if (totalSize > _totalSize) + { + _totalSize = totalSize; + thereIsSection = true; + + CSection § = _sections.AddNew(); + sect.Name = ".debug"; + sect.Name.Add_UInt32(i); + sect.IsDebug = true; + sect.Time = de.Time; + sect.Va = de.Va; + sect.Pa = de.Pa; + sect.Set_Size_for_all(de.Size); + } + buf += kEntrySize; + } + + return S_OK; +} + +HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector &items) +{ + if ((offset & 3) != 0 || offset >= _buf.Size()) + return S_FALSE; + size_t rem = _buf.Size() - offset; + if (rem < 16) + return S_FALSE; + unsigned numNameItems = Get16(_buf + offset + 12); + unsigned numIdItems = Get16(_buf + offset + 14); + unsigned numItems = numNameItems + numIdItems; + if ((rem - 16) / 8 < numItems) + return S_FALSE; + if (!_usedRes.SetRange(offset, 16 + numItems * 8)) + return S_FALSE; + offset += 16; + items.ClearAndReserve(numItems); + for (unsigned i = 0; i < numItems; i++, offset += 8) + { + const Byte *buf = _buf + offset; + CTableItem item; + item.ID = Get32(buf + 0); + if ((bool)((item.ID & kFlag) != 0) != (bool)(i < numNameItems)) + return S_FALSE; + item.Offset = Get32(buf + 4); + items.AddInReserved(item); + } + return S_OK; +} + +static const UInt32 kFileSizeMax = (UInt32)1 << 31; +static const unsigned kNumResItemsMax = (unsigned)1 << 23; +static const unsigned kNumStringLangsMax = 256; + +// BITMAPINFOHEADER +struct CBitmapInfoHeader +{ + // UInt32 HeaderSize; + UInt32 XSize; + Int32 YSize; + UInt16 Planes; + UInt16 BitCount; + UInt32 Compression; + UInt32 SizeImage; + + bool Parse(const Byte *p, size_t size); +}; + +static const UInt32 kBitmapInfoHeader_Size = 0x28; + +bool CBitmapInfoHeader::Parse(const Byte *p, size_t size) +{ + if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size) + return false; + G32( 4, XSize); + G32_signed( 8, YSize); + G16(12, Planes); + G16(14, BitCount); + G32(16, Compression); + G32(20, SizeImage); + return true; +} + +static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount) +{ + return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize; +} + +static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size) +{ + CBitmapInfoHeader h; + if (!h.Parse(src, size)) + return 0; + if (h.YSize < 0) + h.YSize = -h.YSize; + if (h.XSize > (1 << 26) + || h.YSize > (1 << 26) + || h.YSize < 0 + || h.Planes != 1 || h.BitCount > 32) + return 0; + if (h.SizeImage == 0) + { + if (h.Compression != 0) // BI_RGB + return 0; + h.SizeImage = GetImageSize(h.XSize, (UInt32)h.YSize, h.BitCount); + } + UInt32 totalSize = kBmpHeaderSize + size; + UInt32 offBits = totalSize - h.SizeImage; + // BITMAPFILEHEADER + SetUi16(dest, 0x4D42) + SetUi32(dest + 2, totalSize) + SetUi32(dest + 6, 0) + SetUi32(dest + 10, offBits) + return kBmpHeaderSize; +} + +static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size) +{ + CBitmapInfoHeader h; + if (!h.Parse(src, size)) + return 0; + if (h.YSize < 0) + h.YSize = -h.YSize; + if (h.XSize > (1 << 26) + || h.YSize > (1 << 26) + || h.YSize < 0 + || h.Planes != 1 + || h.Compression != 0) // BI_RGB + return 0; + + const UInt32 numBitCount = h.BitCount; + if (numBitCount != 1 && + numBitCount != 4 && + numBitCount != 8 && + numBitCount != 24 && + numBitCount != 32) + return 0; + + if ((h.YSize & 1) != 0) + return 0; + h.YSize /= 2; + if (h.XSize > 0x100 || h.YSize > 0x100) + return 0; + + UInt32 imageSize; + // imageSize is not correct if AND mask array contains zeros + // in this case it is equal image1Size + + // UInt32 imageSize = h.SizeImage; + // if (imageSize == 0) + // { + const UInt32 image1Size = GetImageSize(h.XSize, (UInt32)h.YSize, h.BitCount); + const UInt32 image2Size = GetImageSize(h.XSize, (UInt32)h.YSize, 1); + imageSize = image1Size + image2Size; + // } + UInt32 numColors = 0; + if (numBitCount < 16) + numColors = 1 << numBitCount; + + SetUi16(dest, 0) // Reserved + SetUi16(dest + 2, 1) // RES_ICON + SetUi16(dest + 4, 1) // ResCount + + dest[6] = (Byte)h.XSize; // Width + dest[7] = (Byte)h.YSize; // Height + dest[8] = (Byte)numColors; // ColorCount + dest[9] = 0; // Reserved + + SetUi32(dest + 10, 0) // Reserved1 / Reserved2 + + UInt32 numQuadsBytes = numColors * 4; + UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize; + SetUi32(dest + 14, BytesInRes) + SetUi32(dest + 18, kIconHeaderSize) + + /* + Description = DWORDToString(xSize) + + kDelimiterChar + DWORDToString(ySize) + + kDelimiterChar + DWORDToString(numBitCount); + */ + return kIconHeaderSize; +} + +bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size) +{ + if ((size & 1) != 0) + return false; + + unsigned i; + for (i = 0; i < _strings.Size(); i++) + if (_strings[i].Lang == lang) + break; + if (i == _strings.Size()) + { + if (_strings.Size() >= kNumStringLangsMax) + return false; + CStringItem &item = _strings.AddNew(); + item.Lang = lang; + } + + CStringItem &item = _strings[i]; + id = (id - 1) << 4; + UInt32 pos = 0; + for (i = 0; i < 16; i++) + { + if (size - pos < 2) + return false; + UInt32 len = Get16(src + pos); + pos += 2; + if (len != 0) + { + if (size - pos < len * 2) + return false; + char temp[32]; + ConvertUInt32ToString(id + i, temp); + size_t tempLen = strlen(temp); + size_t j; + for (j = 0; j < tempLen; j++) + item.AddChar(temp[j]); + item.AddChar('\t'); + for (j = 0; j < len; j++, pos += 2) + item.AddWChar_Smart(Get16(src + pos)); + item.NewLine(); + } + } + if (size == pos) + return true; + + // Some rare case files have additional ZERO. + if (size == pos + 2 && Get16(src + pos) == 0) + return true; + + return false; +} + + +// ---------- VERSION ---------- + +static const UInt32 kMy_VS_FFI_SIGNATURE = 0xFEEF04BD; + +struct CMy_VS_FIXEDFILEINFO +{ + // UInt32 Signature; + // UInt32 StrucVersion; + UInt32 VersionMS; + UInt32 VersionLS; + UInt32 ProductVersionMS; + UInt32 ProductVersionLS; + UInt32 FlagsMask; + UInt32 Flags; + UInt32 OS; + UInt32 Type; + UInt32 Subtype; + UInt32 DateMS; + UInt32 DateLS; + + bool Parse(const Byte *p); + void PrintToTextFile(CTextFile &f, CObjectVector &keys); +}; + +bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p) +{ + if (Get32(p) != kMy_VS_FFI_SIGNATURE) // signature; + return false; + // G32(0x04, StrucVersion); + G32(0x08, VersionMS); + G32(0x0C, VersionLS); + G32(0x10, ProductVersionMS); + G32(0x14, ProductVersionLS); + G32(0x18, FlagsMask); + G32(0x1C, Flags); + G32(0x20, OS); + G32(0x24, Type); + G32(0x28, Subtype); + G32(0x2C, DateMS); + G32(0x40, DateLS); + return true; +} + +static void PrintUInt32(CTextFile &f, UInt32 v) +{ + char s[16]; + ConvertUInt32ToString(v, s); + f.AddString(s); +} + +static inline void PrintUInt32(UString &dest, UInt32 v) +{ + dest.Add_UInt32(v); +} + +static void PrintHex(CTextFile &f, UInt32 val) +{ + char temp[16]; + temp[0] = '0'; + temp[1] = 'x'; + ConvertUInt32ToHex(val, temp + 2); + f.AddString(temp); +} + +static void PrintVersion(CTextFile &f, UInt32 ms, UInt32 ls) +{ + PrintUInt32(f, HIWORD(ms)); f.AddChar(','); + PrintUInt32(f, LOWORD(ms)); f.AddChar(','); + PrintUInt32(f, HIWORD(ls)); f.AddChar(','); + PrintUInt32(f, LOWORD(ls)); +} + +static void PrintVersion(UString &s, UInt32 ms, UInt32 ls) +{ + PrintUInt32(s, HIWORD(ms)); s.Add_Dot(); + PrintUInt32(s, LOWORD(ms)); s.Add_Dot(); + PrintUInt32(s, HIWORD(ls)); s.Add_Dot(); + PrintUInt32(s, LOWORD(ls)); +} + +static const char * const k_VS_FileFlags[] = +{ + "DEBUG" + , "PRERELEASE" + , "PATCHED" + , "PRIVATEBUILD" + , "INFOINFERRED" + , "SPECIALBUILD" +}; + +static const CUInt32PCharPair k_VS_FileOS[] = +{ + { 0x10001, "VOS_DOS_WINDOWS16" }, + { 0x10004, "VOS_DOS_WINDOWS32" }, + { 0x20002, "VOS_OS216_PM16" }, + { 0x30003, "VOS_OS232_PM32" }, + { 0x40004, "VOS_NT_WINDOWS32" } +}; + +static const char * const k_VS_FileOS_High[] = +{ + "VOS_UNKNOWN" + , "VOS_DOS" + , "VOS_OS216" + , "VOS_OS232" + , "VOS_NT" + , "VOS_WINCE" +}; + +static const UInt32 kMY_VFT_DRV = 3; +static const UInt32 kMY_VFT_FONT = 4; + +static const char * const k_VS_FileOS_Low[] = +{ + "VOS__BASE" + , "VOS__WINDOWS16" + , "VOS__PM16" + , "VOS__PM32" + , "VOS__WINDOWS32" +}; + +static const char * const k_VS_FileType[] = +{ + "VFT_UNKNOWN" + , "VFT_APP" + , "VFT_DLL" + , "VFT_DRV" + , "VFT_FONT" + , "VFT_VXD" + , "0x6" + , "VFT_STATIC_LIB" +}; + +// Subtype for VFT_DRV Type +static const char * const k_VS_FileSubType_DRV[] = +{ + "0" + , "PRINTER" + , "KEYBOARD" + , "LANGUAGE" + , "DISPLAY" + , "MOUSE" + , "NETWORK" + , "SYSTEM" + , "INSTALLABLE" + , "SOUND" + , "COMM" + , "INPUTMETHOD" + , "VERSIONED_PRINTER" +}; + +// Subtype for VFT_FONT Type +static const char * const k_VS_FileSubType_FONT[] = +{ + "0" + , "VFT2_FONT_RASTER" + , "VFT2_FONT_VECTOR" + , "VFT2_FONT_TRUETYPE" +}; + +static int FindKey(CObjectVector &v, const char *key) +{ + FOR_VECTOR (i, v) + if (v[i].Key.IsEqualTo(key)) + return (int)i; + return -1; +} + +static void AddToUniqueUStringVector(CObjectVector &v, const UString &key, const UString &value) +{ + bool needInsert = false; + unsigned i; + for (i = 0; i < v.Size(); i++) + { + if (v[i].Key == key) + { + if (v[i].Value == value) + return; + needInsert = true; + } + else if (needInsert) + break; + } + CStringKeyValue &pair = v.InsertNew(i); + pair.Key = key; + pair.Value = value; +} + +void CMy_VS_FIXEDFILEINFO::PrintToTextFile(CTextFile &f, CObjectVector &keys) +{ + f.AddString("FILEVERSION "); + PrintVersion(f, VersionMS, VersionLS); + f.NewLine(); + + f.AddString("PRODUCTVERSION "); + PrintVersion(f, ProductVersionMS, ProductVersionLS); + f.NewLine(); + + { + UString s; + PrintVersion(s, VersionMS, VersionLS); + AddToUniqueUStringVector(keys, L"FileVersion", s); + } + { + UString s; + PrintVersion(s, ProductVersionMS, ProductVersionLS); + AddToUniqueUStringVector(keys, L"ProductVersion", s); + } + + f.AddString("FILEFLAGSMASK "); + PrintHex(f, FlagsMask); + f.NewLine(); + + f.AddString("FILEFLAGS "); + { + bool wasPrinted = false; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_VS_FileFlags); i++) + { + if ((Flags & ((UInt32)1 << i)) != 0) + { + if (wasPrinted) + f.AddString(" | "); + f.AddString("VS_FF_"); + f.AddString(k_VS_FileFlags[i]); + wasPrinted = true; + } + } + UInt32 v = Flags & ~(((UInt32)1 << Z7_ARRAY_SIZE(k_VS_FileFlags)) - 1); + if (v != 0 || !wasPrinted) + { + if (wasPrinted) + f.AddString(" | "); + PrintHex(f, v); + } + } + f.NewLine(); + + // OS = 0x111230; + f.AddString("FILEOS "); + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(k_VS_FileOS); i++) + { + const CUInt32PCharPair &pair = k_VS_FileOS[i]; + if (OS == pair.Value) + { + // continue; + // f.AddString("VOS_"); + f.AddString(pair.Name); + break; + } + } + if (i == Z7_ARRAY_SIZE(k_VS_FileOS)) + { + UInt32 high = OS >> 16; + if (high < Z7_ARRAY_SIZE(k_VS_FileOS_High)) + f.AddString(k_VS_FileOS_High[high]); + else + PrintHex(f, high << 16); + UInt32 low = OS & 0xFFFF; + if (low != 0) + { + f.AddString(" | "); + if (low < Z7_ARRAY_SIZE(k_VS_FileOS_Low)) + f.AddString(k_VS_FileOS_Low[low]); + else + PrintHex(f, low); + } + } + f.NewLine(); + + f.AddString("FILETYPE "); + if (Type < Z7_ARRAY_SIZE(k_VS_FileType)) + f.AddString(k_VS_FileType[Type]); + else + PrintHex(f, Type); + f.NewLine(); + + f.AddString("FILESUBTYPE "); + bool needPrintSubType = true; + if (Type == kMY_VFT_DRV) + { + if (Subtype != 0 && Subtype < Z7_ARRAY_SIZE(k_VS_FileSubType_DRV)) + { + f.AddString("VFT2_DRV_"); + f.AddString(k_VS_FileSubType_DRV[Subtype]); + needPrintSubType = false; + } + } + else if (Type == kMY_VFT_FONT) + { + if (Subtype != 0 && Subtype < Z7_ARRAY_SIZE(k_VS_FileSubType_FONT)) + { + f.AddString(k_VS_FileSubType_FONT[Subtype]); + needPrintSubType = false; + } + } + if (needPrintSubType) + PrintHex(f, Subtype); + f.NewLine(); +} + +static void CopyToUString(const Byte *p, UString &s) +{ + for (;;) + { + const wchar_t c = (wchar_t)Get16(p); + p += 2; + if (c == 0) + return; + s += c; + } +} + +static void CopyToUString_ByLen16(const Byte *p, unsigned numChars16, UString &s) +{ + for (; numChars16; numChars16--) + { + const wchar_t c = (wchar_t)Get16(p); + p += 2; + s += c; + } +} + +static bool CompareWStrStrings(const Byte *p, const char *s) +{ + unsigned pos = 0; + for (;;) + { + const Byte c = (Byte)*s++; + if (Get16(p + pos) != c) + return false; + pos += 2; + if (c == 0) + return true; + } +} + +struct CVersionBlock +{ + UInt32 TotalLen; + UInt32 ValueLen; + unsigned IsTextValue; + unsigned StrSize; + + bool Parse(const Byte *p, UInt32 size); +}; + +static int Get_Utf16Str_Len_InBytes(const Byte *p, size_t size) +{ + unsigned pos = 0; + for (;;) + { + if (pos + 1 >= size) + return -1; + if (Get16(p + pos) == 0) + return (int)pos; + pos += 2; + } +} + +static int Get_Utf16Str_Len_InBytes_AllowNonZeroTail(const Byte *p, size_t size) +{ + unsigned pos = 0; + for (;;) + { + if (pos + 1 >= size) + { + if (pos == size) + return (int)pos; + return -1; + } + if (Get16(p + pos) == 0) + return (int)pos; + pos += 2; + } +} + +static const unsigned k_ResoureBlockHeader_Size = 6; + +bool CVersionBlock::Parse(const Byte *p, UInt32 size) +{ + if (size < k_ResoureBlockHeader_Size) + return false; + TotalLen = Get16(p); + ValueLen = Get16(p + 2); + if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size) + return false; + IsTextValue = Get16(p + 4); + if (IsTextValue > 1) + return false; + StrSize = 0; + const int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, + TotalLen - k_ResoureBlockHeader_Size); + if (t < 0) + return false; + StrSize = (unsigned)t; + return true; +} + +static void AddParamString(CTextFile &f, const Byte *p, size_t sLen) +{ + f.AddChar(' '); + f.AddChar('\"'); + f.AddBytes(p, sLen); + f.AddChar('\"'); +} + +static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector &keys) +{ + UInt32 pos; + { + const unsigned k_sizeof_VS_FIXEDFILEINFO = 13 * 4; + + CVersionBlock vb; + if (!vb.Parse(p, size)) + return false; + if (vb.ValueLen != k_sizeof_VS_FIXEDFILEINFO) // maybe 0 is allowed here? + return false; + if (vb.IsTextValue) + return false; + pos = k_ResoureBlockHeader_Size; + if (!CompareWStrStrings(p + pos, "VS_VERSION_INFO")) + return false; + pos += vb.StrSize + 2; + pos += (4 - pos) & 3; + if (pos + vb.ValueLen > vb.TotalLen) + return false; + /* sometimes resource contains zeros in remainder. + So we don't check that size != vb.TotalLen + // if (size != vb.TotalLen) return false; + */ + if (size > vb.TotalLen) + size = vb.TotalLen; + CMy_VS_FIXEDFILEINFO FixedFileInfo; + if (!FixedFileInfo.Parse(p + pos)) + return false; + FixedFileInfo.PrintToTextFile(f, keys); + pos += vb.ValueLen; + } + + f.OpenBlock(0); + + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= size) + break; + + CVersionBlock vb; + if (!vb.Parse(p + pos, size - pos)) + return false; + if (vb.ValueLen != 0) + return false; + const UInt32 endPos = pos + vb.TotalLen; + pos += k_ResoureBlockHeader_Size; + + f.AddSpaces(2); + f.AddString("BLOCK"); + AddParamString(f, p + pos, vb.StrSize); + + f.NewLine(); + f.OpenBlock(2); + + if (CompareWStrStrings(p + pos, "VarFileInfo")) + { + pos += vb.StrSize + 2; + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= endPos) + break; + CVersionBlock vb2; + if (!vb2.Parse(p + pos, endPos - pos)) + return false; + const UInt32 endPos2 = pos + vb2.TotalLen; + if (vb2.IsTextValue) + return false; + pos += k_ResoureBlockHeader_Size; + f.AddSpaces(4); + f.AddString("VALUE"); + AddParamString(f, p + pos, vb2.StrSize); + if (!CompareWStrStrings(p + pos, "Translation")) + return false; + pos += vb2.StrSize + 2; + pos += (4 - pos) & 3; + if (pos + vb2.ValueLen != endPos2) + return false; + if ((vb2.ValueLen & 3) != 0) + return false; + UInt32 num = (vb2.ValueLen >> 2); + for (; num != 0; num--, pos += 4) + { + const UInt32 dw = Get32(p + pos); + const UInt32 lang = LOWORD(dw); + const UInt32 codePage = HIWORD(dw); + + f.AddString(", "); + PrintHex(f, lang); + f.AddString(", "); + PrintUInt32(f, codePage); + } + f.NewLine(); + } + } + else + { + if (!CompareWStrStrings(p + pos, "StringFileInfo")) + return false; + pos += vb.StrSize + 2; + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= endPos) + break; + CVersionBlock vb2; + if (!vb2.Parse(p + pos, endPos - pos)) + return false; + const UInt32 endPos2 = pos + vb2.TotalLen; + if (vb2.ValueLen != 0) + return false; + pos += k_ResoureBlockHeader_Size; + + f.AddSpaces(4); + f.AddString("BLOCK"); + AddParamString(f, p + pos, vb2.StrSize); + pos += vb2.StrSize + 2; + + f.NewLine(); + f.OpenBlock(4); + + for (;;) + { + pos += (4 - pos) & 3; + if (pos >= endPos2) + break; + + CVersionBlock vb3; + if (!vb3.Parse(p + pos, endPos2 - pos)) + return false; + // ValueLen is a number of 16-bit characters (usually it includes zero tail character). + const UInt32 endPos3 = pos + vb3.TotalLen; + pos += k_ResoureBlockHeader_Size; + + // we don't write string if it's not text + if (vb3.IsTextValue) + { + f.AddSpaces(6); + f.AddString("VALUE"); + AddParamString(f, p + pos, vb3.StrSize); + UString key; + UString value; + CopyToUString(p + pos, key); + pos += vb3.StrSize + 2; + + pos += (4 - pos) & 3; + if (vb3.ValueLen != 0 && pos /* + 2 */ <= endPos3) + { + f.AddChar(','); + f.AddSpaces((34 - (int)vb3.StrSize) / 2); + // vb3.TotalLen for some PE files (not from msvc) doesn't include tail zero at the end of Value string. + // we allow that minor error. + const int sLen = Get_Utf16Str_Len_InBytes_AllowNonZeroTail(p + pos, endPos3 - pos); + if (sLen < 0) + return false; + /* + if (vb3.ValueLen - 1 != (unsigned)sLen / 2 && + vb3.ValueLen != (unsigned)sLen / 2) + return false; + */ + AddParamString(f, p + pos, (unsigned)sLen); + CopyToUString_ByLen16(p + pos, (unsigned)sLen / 2, value); + // pos += (unsigned)sLen + 2; + } + AddToUniqueUStringVector(keys, key, value); + } + pos = endPos3; + f.NewLine(); + } + pos = endPos2; + f.CloseBlock(4); + } + } + f.CloseBlock(2); + pos = endPos; + } + + f.CloseBlock(0); + return true; +} + + +HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchiveOpenCallback *callback) +{ + const CSection § = _sections[sectionIndex]; + size_t fileSize = sect.PSize; + { + size_t fileSizeMin = sect.PSize; + + if (sect.VSize < sect.PSize) + { + fileSize = fileSizeMin = sect.VSize; + const int numBits = _optHeader.GetNumFileAlignBits(); + if (numBits > 0) + { + const UInt32 mask = ((UInt32)1 << numBits) - 1; + const size_t end = (size_t)((sect.VSize + mask) & (UInt32)~mask); + if (end > sect.VSize) + { + if (end <= sect.PSize) + fileSize = end; + else + fileSize = sect.PSize; + } + } + } + + if (fileSize > kFileSizeMax) + return S_FALSE; + + { + const UInt64 fileSize64 = fileSize; + if (callback) + RINOK(callback->SetTotal(NULL, &fileSize64)) + } + + RINOK(InStream_SeekSet(stream, sect.Pa)) + + _buf.Alloc(fileSize); + + size_t pos; + + for (pos = 0; pos < fileSize;) + { + { + const UInt64 offset64 = pos; + if (callback) + RINOK(callback->SetCompleted(NULL, &offset64)) + } + size_t rem = MyMin(fileSize - pos, (size_t)(1 << 22)); + RINOK(ReadStream(stream, _buf + pos, &rem)) + if (rem == 0) + { + if (pos < fileSizeMin) + return S_FALSE; + break; + } + pos += rem; + } + + if (pos < fileSize) + memset(_buf + pos, 0, fileSize - pos); + } + + _usedRes.Alloc(fileSize); + CRecordVector specItems; + RINOK(ReadTable(0, specItems)) + + _oneLang = true; + bool stringsOk = true; + size_t maxOffset = 0; + + FOR_VECTOR (i, specItems) + { + const CTableItem &item1 = specItems[i]; + if ((item1.Offset & kFlag) == 0) + return S_FALSE; + + CRecordVector specItems2; + RINOK(ReadTable(item1.Offset & kMask, specItems2)) + + FOR_VECTOR (j, specItems2) + { + const CTableItem &item2 = specItems2[j]; + if ((item2.Offset & kFlag) == 0) + return S_FALSE; + + CRecordVector specItems3; + RINOK(ReadTable(item2.Offset & kMask, specItems3)) + + CResItem item; + item.Type = item1.ID; + item.ID = item2.ID; + + FOR_VECTOR (k, specItems3) + { + if (_items.Size() >= kNumResItemsMax) + return S_FALSE; + const CTableItem &item3 = specItems3[k]; + if ((item3.Offset & kFlag) != 0) + return S_FALSE; + if (item3.Offset >= _buf.Size() || _buf.Size() - item3.Offset < 16) + return S_FALSE; + const Byte *buf = _buf + item3.Offset; + item.Lang = item3.ID; + item.Offset = Get32(buf + 0); + item.Size = Get32(buf + 4); + // UInt32 codePage = Get32(buf + 8); + if (Get32(buf + 12) != 0) + return S_FALSE; + if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back())) + _oneLang = false; + + item.HeaderSize = 0; + + size_t offset = item.Offset - sect.Va; + if (offset > maxOffset) + maxOffset = offset; + if (offset + item.Size > maxOffset) + maxOffset = offset + item.Size; + + if (CheckItem(sect, item, offset)) + { + const Byte *data = _buf + offset; + if (item.IsBmp()) + item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size); + else if (item.IsIcon()) + item.HeaderSize = SetIconHeader(item.Header, data, item.Size); + else if (item.IsString()) + { + if (stringsOk) + stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size); + } + } + + if (item.IsVersion()) + { + if (offset > _buf.Size() || _buf.Size() - offset < item.Size) + continue; + CTextFile f; + if (ParseVersion((const Byte *)_buf + offset, item.Size, f, _versionKeys)) + { + CMixItem mixItem; + mixItem.VersionIndex = (int)_versionFiles.Size(); + mixItem.SectionIndex = (int)sectionIndex; // check it !!!! + CByteBuffer_WithLang &vf = _versionFiles.AddNew(); + vf.Lang = item.Lang; + vf.CopyFrom(f.Buf, f.Buf.GetPos()); + _mixItems.Add(mixItem); + continue; + } + // PrintError("ver.Parse error"); + } + + item.Enabled = true; + _items.Add(item); + } + } + } + + if (stringsOk && !_strings.IsEmpty()) + { + unsigned i; + for (i = 0; i < _items.Size(); i++) + { + CResItem &item = _items[i]; + if (item.IsString()) + item.Enabled = false; + } + for (i = 0; i < _strings.Size(); i++) + { + if (_strings[i].FinalSize() == 0) + continue; + CMixItem mixItem; + mixItem.StringIndex = (int)i; + mixItem.SectionIndex = (int)sectionIndex; + _mixItems.Add(mixItem); + } + } + + _usedRes.Free(); + + { + // PSize can be much larger than VSize in some exe installers. + // it contains archive data after PE resources. + // So we need to use PSize here! + if (maxOffset < sect.PSize) + { + size_t end = fileSize; + + // we skip Zeros to start of aligned block + size_t i; + for (i = maxOffset; i < end; i++) + if (_buf[i] != 0) + break; + if (i == end) + maxOffset = end; + + CSection sect2; + sect2.Flags = 0; + sect2.Pa = sect.Pa + (UInt32)maxOffset; + sect2.Va = sect.Va + (UInt32)maxOffset; + + // 9.29: we use sect.PSize instead of sect.VSize to support some CAB-SFX + // the code for .rsrc_2 is commented. + sect2.PSize = sect.PSize - (UInt32)maxOffset; + + if (sect2.PSize != 0) + { + sect2.ExtractSize = sect2.VSize = sect2.PSize; + sect2.Name = ".rsrc_1"; + sect2.Time = 0; + sect2.IsAdditionalSection = true; + _sections.Add(sect2); + } + } + } + + return S_OK; +} + + +bool CHeader::ParseCoff(const Byte *p) +{ + ParseBase(p); + if (PointerToSymbolTable < kCoffHeaderSize) + return false; + if (NumSymbols >= (1 << 24)) + return false; + if (OptHeaderSize != 0 && OptHeaderSize < k_OptHeader32_Size_MIN) + return false; + + // 18.04: we reduce false detections + if (NumSections == 0 && OptHeaderSize == 0) + return false; + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_MachinePairs); i++) + if (Machine == g_MachinePairs[i].Value) + return true; + if (Machine == 0) + return true; + + return false; +} + + +static inline bool CheckPeOffset(UInt32 pe) +{ + // ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value. + return pe >= 0x40 && pe <= 0x1000 /* && (pe & 7) == 0 */ ; +} + +static const unsigned kStartSize = 0x40; + +API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size) +{ + if (size < 2) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'M' || p[1] != 'Z') + return k_IsArc_Res_NO; + if (size < kStartSize) + return k_IsArc_Res_NEED_MORE; + UInt32 pe = Get32(p + 0x3C); + if (!CheckPeOffset(pe)) + return k_IsArc_Res_NO; + if (pe + kPeHeaderSize > size) + return k_IsArc_Res_NEED_MORE; + CHeader header; + if (!header.ParsePe(p + pe)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + UInt32 coffOffset = 0; + if (_coffMode) + { + Byte h[kCoffHeaderSize]; + RINOK(ReadStream_FALSE(stream, h, kCoffHeaderSize)) + if (!_header.ParseCoff(h)) + return S_FALSE; + } + else + { + UInt32 _peOffset; + { + Byte h[kStartSize]; + RINOK(ReadStream_FALSE(stream, h, kStartSize)) + if (h[0] != 'M' || h[1] != 'Z') + return S_FALSE; + /* most of PE files contain 0x0090 at offset 2. + But some rare PE files contain another values. So we don't use that check. + if (Get16(h + 2) != 0x90) return false; */ + _peOffset = Get32(h + 0x3C); + if (!CheckPeOffset(_peOffset)) + return S_FALSE; + coffOffset = _peOffset + 4; + } + { + Byte h[kPeHeaderSize]; + RINOK(InStream_SeekSet(stream, _peOffset)) + RINOK(ReadStream_FALSE(stream, h, kPeHeaderSize)) + if (!_header.ParsePe(h)) + return S_FALSE; + } + } + + const UInt32 optStart = coffOffset + kCoffHeaderSize; + const UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize; + _totalSize = optStart + bufSize; + CByteBuffer buffer(bufSize); + + RINOK(ReadStream_FALSE(stream, buffer, bufSize)) + + // memset((void *)&_optHeader, 0, sizeof(_optHeader)); + if (_header.OptHeaderSize != 0) + if (!_optHeader.Parse(buffer, _header.OptHeaderSize)) + return S_FALSE; + + UInt32 pos = _header.OptHeaderSize; + unsigned i; + for (i = 0; i < _header.NumSections; i++, pos += kSectionSize) + { + CSection § = _sections.AddNew(); + sect.Parse(buffer + pos); + sect.IsRealSect = true; + if (sect.Name.IsEqualTo(".reloc")) + { + const CDirLink &dl = _optHeader.DirItems[kDirLink_BASERELOC]; + if (dl.Va == sect.Va && + dl.Size <= sect.PSize) + sect.ExtractSize = dl.Size; + } + else if (sect.Name.IsEqualTo(".pdata")) + { + const CDirLink &dl = _optHeader.DirItems[kDirLink_EXCEPTION]; + if (dl.Va == sect.Va && + dl.Size <= sect.PSize) + sect.ExtractSize = dl.Size; + } + + /* PE pre-file in .hxs file has errors: + PSize of resource is larger than real size. + So it overlaps next ".its" section. + 7-zip before 22.02: we corrected it. + + 22.02: another bad case is possible in incorrect pe (exe) file: + PSize in .rsrc section is correct, + but next .reloc section has incorrect (Pa) that overlaps with .rsrc. + */ + + if (i != 0) + { + const CSection &prev = _sections[i - 1]; + if (prev.Pa < sect.Pa + && prev.Pa + prev.PSize > sect.Pa + && sect.PSize != 0 + && prev.PSize != 0) + { + _sectionsError = true; + // PRF(printf("\n !!!! Section correction: %s\n ", prev.Name)); + + /* we corrected that case in 7-zip before 22.02: */ + // prev.PSize = sect.Pa - prev.Pa; + + /* 22.02: here we can try to change bad section position to expected postion. + but original Windows code probably will not do same things. */ + // if (prev.PSize <= sect.Va - prev.Va) sect.Pa = prev.Pa + prev.PSize; + } + } + /* last ".its" section in hxs file has incorrect sect.PSize. + 7-zip before 22.02: we reduced section to real sect.VSize */ + /* + if (sect.VSize == 24 && sect.PSize == 512 && i == (unsigned)_header.NumSections - 1) + sect.PSize = sect.VSize; + */ + } + + for (i = 0; i < _sections.Size(); i++) + _sections[i].UpdateTotalSize(_totalSize); + + bool thereISDebug = false; + if (IsOpt()) + { + RINOK(LoadDebugSections(stream, thereISDebug)) + + const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate]; + if (certLink.Size != 0) + { + CSection § = _sections.AddNew(); + sect.Name = "CERTIFICATE"; + sect.Va = 0; + sect.Pa = certLink.Va; + sect.Set_Size_for_all(certLink.Size); + sect.UpdateTotalSize(_totalSize); + } + + if (thereISDebug) + { + /* sometime there is some data after debug section. + We don't see any reference in exe file to that data. + But we suppose that it's part of EXE file */ + + const UInt32 kAlign = 1 << 12; + UInt32 alignPos = _totalSize & (kAlign - 1); + if (alignPos != 0) + { + UInt32 size = kAlign - alignPos; + RINOK(InStream_SeekSet(stream, _totalSize)) + buffer.Alloc(kAlign); + Byte *buf = buffer; + size_t processed = size; + RINOK(ReadStream(stream, buf, &processed)) + + /* + if (processed != 0) + { + printf("\ndata after debug %d, %d \n", (int)size, (int)processed); + fflush(stdout); + } + */ + + size_t k; + for (k = 0; k < processed; k++) + if (buf[k] != 0) + break; + if (processed < size && processed < 100) + _totalSize += (UInt32)processed; + else if (((_totalSize + k) & 0x1FF) == 0 || processed < size) + _totalSize += (UInt32)k; + } + } + } + + if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= optStart) + { + if (_header.NumSymbols >= (1 << 24)) + return S_FALSE; + UInt32 size = _header.NumSymbols * 18; + RINOK(InStream_SeekSet(stream, (UInt64)_header.PointerToSymbolTable + size)) + Byte buf[4]; + RINOK(ReadStream_FALSE(stream, buf, 4)) + UInt32 size2 = Get32(buf); + if (size2 >= (1 << 28)) + return S_FALSE; + size += size2; + + CSection § = _sections.AddNew(); + sect.Name = "COFF_SYMBOLS"; + sect.Va = 0; + sect.Pa = _header.PointerToSymbolTable; + sect.Set_Size_for_all(size); + sect.UpdateTotalSize(_totalSize); + } + + { + CObjectVector sections = _sections; + sections.Sort(); + UInt32 limit = (1 << 12); + unsigned num = 0; + FOR_VECTOR (k, sections) + { + const CSection &s = sections[k]; + if (s.Pa > limit) + { + CSection &s2 = _sections.AddNew(); + s2.Pa = s2.Va = limit; + s2.Set_Size_for_all(s.Pa - limit); + s2.IsAdditionalSection = true; + s2.Name.Add_Char('['); + s2.Name.Add_UInt32(num++); + s2.Name.Add_Char(']'); + limit = s.Pa; + } + UInt32 next = s.Pa + s.PSize; + if (next < s.Pa) + break; + if (next >= limit) + limit = next; + } + } + + + if (IsOpt()) + if (_optHeader.CheckSum != 0) + { + RINOK(InStream_SeekToBegin(stream)) + UInt32 checkSum = 0; + RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum)) + _checksumError = (checkSum != _optHeader.CheckSum); + } + + + if (!_allowTail) + { + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) + if (fileSize > _totalSize) + return S_FALSE; + } + + bool _parseResources = true; + // _parseResources = false; // for debug + + UInt64 mainSize = 0, mainSize2 = 0; + + for (i = 0; i < _sections.Size(); i++) + { + const CSection § = _sections[i]; + if (IsOpt()) + if (_parseResources && sect.Name == ".rsrc") + { + // 20.01: we try to parse only first copy of .rsrc section. + _parseResources = false; + const unsigned numMixItems = _mixItems.Size(); + HRESULT res = OpenResources(i, stream, callback); + if (res == S_OK) + { + _resourcesPrefix = sect.Name.Ptr(); + _resourcesPrefix.Add_PathSepar(); + FOR_VECTOR (j, _items) + { + const CResItem &item = _items[j]; + if (item.Enabled) + { + CMixItem mixItem; + mixItem.SectionIndex = (int)i; + mixItem.ResourceIndex = (int)j; + if (item.IsRcDataOrUnknown()) + { + if (item.Size >= mainSize) + { + mainSize2 = mainSize; + mainSize = item.Size; + _mainSubfile = (Int32)(int)_mixItems.Size(); + } + else if (item.Size >= mainSize2) + mainSize2 = item.Size; + } + _mixItems.Add(mixItem); + } + } + // 9.29: .rsrc_2 code was commented. + // .rsrc_1 now must include that .rsrc_2 block. + /* + if (sect.PSize > sect.VSize) + { + int numBits = _optHeader.GetNumFileAlignBits(); + if (numBits >= 0) + { + UInt32 mask = (1 << numBits) - 1; + UInt32 end = ((sect.VSize + mask) & ~mask); + + if (sect.PSize > end) + { + CSection §2 = _sections.AddNew(); + sect2.Flags = 0; + sect2.Pa = sect.Pa + end; + sect2.Va = sect.Va + end; + sect2.PSize = sect.PSize - end; + sect2.VSize = sect2.PSize; + sect2.Name = ".rsrc_2"; + sect2.Time = 0; + sect2.IsAdditionalSection = true; + } + } + } + */ + continue; + } + if (res != S_FALSE) + return res; + _mixItems.DeleteFrom(numMixItems); + CloseResources(); + } + + if (sect.IsAdditionalSection) + { + if (sect.PSize >= mainSize) + { + mainSize2 = mainSize; + mainSize = sect.PSize; + _mainSubfile = (Int32)(int)_mixItems.Size(); + } + else if (sect.PSize >= mainSize2) + mainSize2 = sect.PSize; + } + + CMixItem mixItem; + mixItem.SectionIndex = (int)i; + _mixItems.Add(mixItem); + } + + if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2) + _mainSubfile = -1; + + for (i = 0; i < _mixItems.Size(); i++) + { + const CMixItem &mixItem = _mixItems[i]; + if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_") + { + _mainSubfile = (Int32)(int)i; + break; + } + } + + for (i = 0; i < _versionKeys.Size(); i++) + { + if (i != 0) + _versionFullString.Add_LF(); + const CStringKeyValue &k = _versionKeys[i]; + _versionFullString += k.Key; + _versionFullString += ": "; + _versionFullString += k.Value; + } + + { + int keyIndex = FindKey(_versionKeys, "OriginalFilename"); + if (keyIndex >= 0) + _originalFilename = _versionKeys[keyIndex].Value; + } + { + int keyIndex = FindKey(_versionKeys, "FileDescription"); + if (keyIndex >= 0) + _versionShortString = _versionKeys[keyIndex].Value; + } + { + int keyIndex = FindKey(_versionKeys, "FileVersion"); + if (keyIndex >= 0) + { + _versionShortString.Add_Space(); + _versionShortString += _versionKeys[keyIndex].Value; + } + } + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(inStream, callback)) + _stream = inStream; + return S_OK; + COM_TRY_END +} + +void CHandler::CloseResources() +{ + _usedRes.Free(); + _items.Clear(); + _strings.Clear(); + _versionFiles.Clear(); + _buf.Free(); + _versionFullString.Empty(); + _versionShortString.Empty(); + _originalFilename.Empty(); + _versionKeys.Clear(); +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + _checksumError = false; + _sectionsError = false; + _mainSubfile = -1; + + _stream.Release(); + _sections.Clear(); + _mixItems.Clear(); + CloseResources(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _mixItems.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _mixItems.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]]; + UInt64 size; + if (mixItem.StringIndex >= 0) + size = _strings[mixItem.StringIndex].FinalSize(); + else if (mixItem.VersionIndex >= 0) + size = _versionFiles[mixItem.VersionIndex].Size(); + else if (mixItem.ResourceIndex >= 0) + size = _items[mixItem.ResourceIndex].GetSize(); + else + size = _sections[mixItem.SectionIndex].GetSize_Extract(); + totalSize += size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + + totalSize = 0; + UInt64 currentItemSize; + + for (i = 0;; i++, totalSize += currentItemSize) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + const CMixItem &mixItem = _mixItems[index]; + + const CSection § = _sections[mixItem.SectionIndex]; + bool isOk = true; + if (mixItem.StringIndex >= 0) + { + const CStringItem &item = _strings[mixItem.StringIndex]; + currentItemSize = item.FinalSize(); + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + if (outStream) + RINOK(WriteStream(outStream, item.Buf, item.FinalSize())) + } + else if (mixItem.VersionIndex >= 0) + { + const CByteBuffer &item = _versionFiles[mixItem.VersionIndex]; + currentItemSize = item.Size(); + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + if (outStream) + RINOK(WriteStream(outStream, item, item.Size())) + } + else if (mixItem.ResourceIndex >= 0) + { + const CResItem &item = _items[mixItem.ResourceIndex]; + currentItemSize = item.GetSize(); + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + size_t offset = item.Offset - sect.Va; + if (!CheckItem(sect, item, offset)) + isOk = false; + else if (outStream) + { + if (item.HeaderSize != 0) + RINOK(WriteStream(outStream, item.Header, item.HeaderSize)) + RINOK(WriteStream(outStream, _buf + offset, item.Size)) + } + } + else + { + currentItemSize = sect.GetSize_Extract(); + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(InStream_SeekSet(_stream, sect.Pa)) + inStream->Init(currentItemSize); + RINOK(copyCoder.Interface()->Code(inStream, outStream, NULL, NULL, lps)) + isOk = (copyCoder->TotalSize == currentItemSize); + } + + outStream.Release(); + RINOK(extractCallback->SetOperationResult(isOk ? + NExtract::NOperationResult::kOK : + NExtract::NOperationResult::kDataError)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + + const CMixItem &mixItem = _mixItems[index]; + const CSection § = _sections[mixItem.SectionIndex]; + if (mixItem.IsSectionItem()) + return CreateLimitedInStream(_stream, sect.Pa, sect.GetSize_Extract(), stream); + + CBufInStream *inStreamSpec = new CBufInStream; + CMyComPtr streamTemp = inStreamSpec; + CReferenceBuf *referenceBuf = new CReferenceBuf; + CMyComPtr ref = referenceBuf; + if (mixItem.StringIndex >= 0) + { + const CStringItem &item = _strings[mixItem.StringIndex]; + referenceBuf->Buf.CopyFrom(item.Buf, item.FinalSize()); + } + else if (mixItem.VersionIndex >= 0) + { + const CByteBuffer &item = _versionFiles[mixItem.VersionIndex]; + referenceBuf->Buf.CopyFrom(item, item.Size()); + } + else + { + const CResItem &item = _items[mixItem.ResourceIndex]; + size_t offset = item.Offset - sect.Va; + if (!CheckItem(sect, item, offset)) + return S_FALSE; + if (item.HeaderSize == 0) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp2 = streamSpec; + streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this); + *stream = streamTemp2.Detach(); + return S_OK; + } + referenceBuf->Buf.Alloc(item.HeaderSize + item.Size); + memcpy(referenceBuf->Buf, item.Header, item.HeaderSize); + if (item.Size != 0) + memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size); + } + inStreamSpec->Init(referenceBuf); + + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { 'M', 'Z' }; + +REGISTER_ARC_I( + "PE", "exe dll sys", NULL, 0xDD, + k_Signature, + 0, + NArcInfoFlags::kPreArc, + IsArc_Pe) + +} + +namespace NCoff { + +API_FUNC_static_IsArc IsArc_Coff(const Byte *p, size_t size) +{ + if (size < NPe::kCoffHeaderSize) + return k_IsArc_Res_NEED_MORE; + NPe::CHeader header; + if (!header.ParseCoff(p)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +/* +static const Byte k_Signature[] = +{ + 2, 0x4C, 0x01, // x86 + 2, 0x64, 0x86, // x64 + 2, 0x64, 0xAA // ARM64 +}; +REGISTER_ARC_I_CLS( +*/ + +REGISTER_ARC_I_CLS_NO_SIG( + NPe::CHandler(true), + "COFF", "obj", NULL, 0xC6, + // k_Signature, + 0, + // NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kStartOpen, + IsArc_Coff) +} + + +namespace NTe { + +// Terse Executable (TE) image + +struct CDataDir +{ + UInt32 Va; + UInt32 Size; + + void Parse(const Byte *p) + { + G32(0, Va); + G32(4, Size); + } +}; + +static const UInt32 kHeaderSize = 40; + +static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) +{ + for (unsigned i = 0; i < num; i++) + if (pairs[i].Value == value) + return true; + return false; +} + +#define MY_FIND_VALUE(pairs, val) FindValue(pairs, Z7_ARRAY_SIZE(pairs), val) +#define MY_FIND_VALUE_2(strings, val) (val < Z7_ARRAY_SIZE(strings) && strings[val]) + +static const UInt32 kNumSection_MAX = 32; + +struct CHeader +{ + UInt16 Machine; + Byte NumSections; + Byte SubSystem; + UInt16 StrippedSize; + /* + UInt32 AddressOfEntryPoint; + UInt32 BaseOfCode; + UInt64 ImageBase; + */ + CDataDir DataDir[2]; // base relocation and debug directory + + bool ConvertPa(UInt32 &pa) const + { + if (pa < StrippedSize) + return false; + pa = pa - StrippedSize + kHeaderSize; + return true; + } + bool Parse(const Byte *p); +}; + +bool CHeader::Parse(const Byte *p) +{ + NumSections = p[4]; + if (NumSections > kNumSection_MAX) + return false; + SubSystem = p[5]; + G16(2, Machine); + G16(6, StrippedSize); + /* + G32(8, AddressOfEntryPoint); + G32(12, BaseOfCode); + G64(16, ImageBase); + */ + for (unsigned i = 0; i < 2; i++) + { + CDataDir &dd = DataDir[i]; + dd.Parse(p + 24 + i * 8); + if (dd.Size >= ((UInt32)1 << 28)) + return false; + } + return + MY_FIND_VALUE(NPe::g_MachinePairs, Machine) && + MY_FIND_VALUE_2(NPe::g_SubSystems, SubSystem); +} + +API_FUNC_static_IsArc IsArc_Te(const Byte *p, size_t size) +{ + if (size < 2) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'V' || p[1] != 'Z') + return k_IsArc_Res_NO; + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + + CHeader h; + if (!h.Parse(p)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + + +struct CSection +{ + Byte Name[NPe::kNameSize]; + + UInt32 ExtractSize; + UInt32 VSize; + UInt32 Va; + UInt32 PSize; + UInt32 Pa; + UInt32 Flags; + // UInt16 NumRelocs; + + void Parse(const Byte *p) + { + memcpy(Name, p, NPe::kNameSize); + G32(8, VSize); + G32(12, Va); + G32(16, PSize); + G32(20, Pa); + // G32(p + 32, NumRelocs); + G32(36, Flags); + ExtractSize = (VSize && VSize < PSize) ? VSize : PSize; + } + + bool Check() const + { + return + Pa <= ((UInt32)1 << 30) && + PSize <= ((UInt32)1 << 30); + } + + UInt32 GetSize_Extract() const + { + return ExtractSize; + } + + void UpdateTotalSize(UInt32 &totalSize) + { + const UInt32 t = Pa + PSize; + if (totalSize < t) + totalSize = t; + } +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_2( + IInArchiveGetStream, + IArchiveAllowTail +) + CRecordVector _items; + CMyComPtr _stream; + UInt32 _totalSize; + bool _allowTail; + CHeader _h; + + HRESULT Open2(IInStream *stream); +public: + CHandler(): _allowTail(false) {} +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidVirtualSize, + kpidCharacts, + kpidOffset, + kpidVa +}; + +enum +{ + kpidSubSystem = kpidUserDefined + // , kpidImageBase +}; + +static const CStatProp kArcProps[] = +{ + // { NULL, kpidHeadersSize, VT_UI4 }, + { NULL, kpidCpu, VT_BSTR}, + { "Subsystem", kpidSubSystem, VT_BSTR }, + // { "Image Base", kpidImageBase, VT_UI8 } +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _totalSize; break; + case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break; + case kpidSubSystem: TYPE_TO_PROP(NPe::g_SubSystems, _h.SubSystem, prop); break; + /* + case kpidImageBase: prop = _h.ImageBase; break; + case kpidAddressOfEntryPoint: prop = _h.AddressOfEntryPoint; break; + case kpidBaseOfCode: prop = _h.BaseOfCode; break; + */ + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + { + const CSection &item = _items[index]; + switch (propID) + { + case kpidPath: + { + AString name; + NPe::GetName(item.Name, name); + prop = MultiByteToUnicodeString(name); + break; + } + case kpidSize: prop = (UInt64)item.GetSize_Extract(); break; + case kpidPackSize: prop = (UInt64)item.PSize; break; + case kpidVirtualSize: prop = (UInt64)item.VSize; break; + case kpidOffset: prop = item.Pa; break; + case kpidVa: prop = item.Va; break; + case kpidCharacts: FLAGS_TO_PROP(NPe::g_SectFlags, item.Flags, prop); break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +HRESULT CHandler::Open2(IInStream *stream) +{ + Byte h[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, h, kHeaderSize)) + if (h[0] != 'V' || h[1] != 'Z') + return S_FALSE; + if (!_h.Parse(h)) + return S_FALSE; + + UInt32 headerSize = NPe::kSectionSize * (UInt32)_h.NumSections; + CByteArr buf(headerSize); + RINOK(ReadStream_FALSE(stream, buf, headerSize)) + headerSize += kHeaderSize; + + _totalSize = headerSize; + _items.ClearAndReserve(_h.NumSections); + for (UInt32 i = 0; i < _h.NumSections; i++) + { + CSection sect; + sect.Parse(buf + i * NPe::kSectionSize); + if (!_h.ConvertPa(sect.Pa)) + return S_FALSE; + if (sect.Pa < headerSize) + return S_FALSE; + if (!sect.Check()) + return S_FALSE; + _items.AddInReserved(sect); + sect.UpdateTotalSize(_totalSize); + } + + if (!_allowTail) + { + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(stream, fileSize)) + if (fileSize > _totalSize) + return S_FALSE; + } + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + Close(); + // try + { + if (Open2(inStream) != S_OK) + return S_FALSE; + _stream = inStream; + } + // catch(...) { return S_FALSE; } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + _stream.Release(); + _items.Clear(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].GetSize_Extract(); + RINOK(extractCallback->SetTotal(totalSize)) + + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(_stream); + + totalSize = 0; + + for (i = 0;; i++) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + int opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CSection &item = _items[index]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + const UInt32 size = item.GetSize_Extract(); + totalSize += size; + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(InStream_SeekSet(_stream, item.Pa)) + inStream->Init(size); + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + + opRes = (copyCoder->TotalSize == size) ? + NExtract::NOperationResult::kOK : (copyCoder->TotalSize < size) ? + NExtract::NOperationResult::kUnexpectedEnd : + NExtract::NOperationResult::kDataError; + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + const CSection &item = _items[index]; + return CreateLimitedInStream(_stream, item.Pa, item.GetSize_Extract(), stream); + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail)) +{ + _allowTail = IntToBool(allowTail); + return S_OK; +} + +static const Byte k_Signature[] = { 'V', 'Z' }; + +REGISTER_ARC_I( + "TE", "te", NULL, 0xCF, + k_Signature, + 0, + NArcInfoFlags::kPreArc, + IsArc_Te) + +} +} diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index a7331b889..5f9e1c3f4 100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -1,398 +1,398 @@ -/* PpmdHandler.cpp -- PPMd format handler -2020 : Igor Pavlov : Public domain -This code is based on: - PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain - Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/Alloc.h" -#include "../../../C/Ppmd7.h" -#include "../../../C/Ppmd8.h" - -#include "../../Common/ComTry.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/CWrappers.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -using namespace NWindows; - -namespace NArchive { -namespace NPpmd { - -static const UInt32 kBufSize = (1 << 20); - -struct CBuf -{ - Byte *Buf; - - CBuf(): Buf(NULL) {} - ~CBuf() { ::MidFree(Buf); } - bool Alloc() - { - if (!Buf) - Buf = (Byte *)::MidAlloc(kBufSize); - return (Buf != NULL); - } -}; - -static const UInt32 kHeaderSize = 16; -static const UInt32 kSignature = 0x84ACAF8F; -static const unsigned kNewHeaderVer = 8; - -struct CItem -{ - UInt32 Attrib; - UInt32 Time; - AString Name; - - unsigned Order; - unsigned MemInMB; - unsigned Ver; - unsigned Restor; - - HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize); - bool IsSupported() const - { - return (Ver == 7 && Order >= PPMD7_MIN_ORDER) - || (Ver == 8 && Order >= PPMD8_MIN_ORDER && Restor < PPMD8_RESTORE_METHOD_UNSUPPPORTED); - } -}; - -HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize) -{ - Byte h[kHeaderSize]; - RINOK(ReadStream_FALSE(s, h, kHeaderSize)) - if (GetUi32(h) != kSignature) - return S_FALSE; - Attrib = GetUi32(h + 4); - Time = GetUi32(h + 12); - const unsigned info = GetUi16(h + 8); - Order = (info & 0xF) + 1; - MemInMB = ((info >> 4) & 0xFF) + 1; - Ver = info >> 12; - - if (Ver < 6 || Ver > 11) return S_FALSE; - - UInt32 nameLen = GetUi16(h + 10); - Restor = nameLen >> 14; - if (Restor > 2) - return S_FALSE; - if (Ver >= kNewHeaderVer) - nameLen &= 0x3FFF; - if (nameLen > (1 << 9)) - return S_FALSE; - char *name = Name.GetBuf(nameLen); - const HRESULT res = ReadStream_FALSE(s, name, nameLen); - Name.ReleaseBuf_CalcLen(nameLen); - headerSize = kHeaderSize + nameLen; - return res; -} - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IArchiveOpenSeq -) - CItem _item; - UInt32 _headerSize; - bool _packSize_Defined; - UInt64 _packSize; - CMyComPtr _stream; - - void GetVersion(NCOM::CPropVariant &prop); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidMTime, - kpidAttrib, - kpidMethod -}; - -static const Byte kArcProps[] = -{ - kpidMethod -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -void CHandler::GetVersion(NCOM::CPropVariant &prop) -{ - AString s ("PPMd"); - s.Add_Char((char)('A' + _item.Ver)); - s += ":o"; - s.Add_UInt32(_item.Order); - s += ":mem"; - s.Add_UInt32(_item.MemInMB); - s.Add_Char('m'); - if (_item.Ver >= kNewHeaderVer && _item.Restor != 0) - { - s += ":r"; - s.Add_UInt32(_item.Restor); - } - prop = s; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; - case kpidMethod: GetVersion(prop); break; - } - prop.Detach(value); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break; - case kpidMTime: - { - // time can be in Unix format ??? - FILETIME utc; - if (NTime::DosTime_To_FileTime(_item.Time, utc)) - prop = utc; - break; - } - case kpidAttrib: prop = _item.Attrib; break; - case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; - case kpidMethod: GetVersion(prop); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) -{ - return OpenSeq(stream); -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - COM_TRY_BEGIN - HRESULT res; - try - { - Close(); - res = _item.ReadHeader(stream, _headerSize); - } - catch(...) { res = S_FALSE; } - if (res == S_OK) - _stream = stream; - else - Close(); - return res; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _packSize = 0; - _packSize_Defined = false; - _stream.Release(); - return S_OK; -} - - - -struct CPpmdCpp -{ - unsigned Ver; - CPpmd7 _ppmd7; - CPpmd8 _ppmd8; - - CPpmdCpp(unsigned version) - { - Ver = version; - Ppmd7_Construct(&_ppmd7); - Ppmd8_Construct(&_ppmd8); - } - - ~CPpmdCpp() - { - Ppmd7_Free(&_ppmd7, &g_BigAlloc); - Ppmd8_Free(&_ppmd8, &g_BigAlloc); - } - - bool Alloc(UInt32 memInMB) - { - memInMB <<= 20; - if (Ver == 7) - return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0; - return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0; - } - - void Init(unsigned order, unsigned restor) - { - if (Ver == 7) - Ppmd7_Init(&_ppmd7, order); - else - Ppmd8_Init(&_ppmd8, order, restor); - } - - bool InitRc(CByteInBufWrap *inStream) - { - if (Ver == 7) - { - _ppmd7.rc.dec.Stream = &inStream->vt; - return (Ppmd7a_RangeDec_Init(&_ppmd7.rc.dec) != 0); - } - else - { - _ppmd8.Stream.In = &inStream->vt; - return Ppmd8_Init_RangeDec(&_ppmd8) != 0; - } - } - - bool IsFinishedOK() - { - if (Ver == 7) - return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7.rc.dec); - return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8); - } -}; - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - // extractCallback->SetTotal(_packSize); - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)) - Int32 opRes; -{ - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CByteInBufWrap inBuf; - if (!inBuf.Alloc(1 << 20)) - return E_OUTOFMEMORY; - inBuf.Stream = _stream; - - CBuf outBuf; - if (!outBuf.Alloc()) - return E_OUTOFMEMORY; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - - CPpmdCpp ppmd(_item.Ver); - if (!ppmd.Alloc(_item.MemInMB)) - return E_OUTOFMEMORY; - - opRes = NExtract::NOperationResult::kUnsupportedMethod; - - if (_item.IsSupported()) - { - opRes = NExtract::NOperationResult::kDataError; - - ppmd.Init(_item.Order, _item.Restor); - inBuf.Init(); - UInt64 outSize = 0; - - if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK) - for (;;) - { - lps->InSize = _packSize = inBuf.GetProcessed(); - lps->OutSize = outSize; - RINOK(lps->SetCur()) - - size_t i; - int sym = 0; - - Byte *buf = outBuf.Buf; - if (ppmd.Ver == 7) - { - for (i = 0; i < kBufSize; i++) - { - sym = Ppmd7a_DecodeSymbol(&ppmd._ppmd7); - if (inBuf.Extra || sym < 0) - break; - buf[i] = (Byte)sym; - } - } - else - { - for (i = 0; i < kBufSize; i++) - { - sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8); - if (inBuf.Extra || sym < 0) - break; - buf[i] = (Byte)sym; - } - } - - outSize += i; - _packSize = _headerSize + inBuf.GetProcessed(); - _packSize_Defined = true; - if (realOutStream) - { - RINOK(WriteStream(realOutStream, outBuf.Buf, i)) - } - - if (inBuf.Extra) - { - opRes = NExtract::NOperationResult::kUnexpectedEnd; - break; - } - - if (sym < 0) - { - if (sym == -1 && ppmd.IsFinishedOK()) - opRes = NExtract::NOperationResult::kOK; - break; - } - } - - RINOK(inBuf.Res) - } -} - return extractCallback->SetOperationResult(opRes); -} - - -static const Byte k_Signature[] = { 0x8F, 0xAF, 0xAC, 0x84 }; - -REGISTER_ARC_I( - "Ppmd", "pmd", NULL, 0xD, - k_Signature, - 0, - 0, - NULL) - -}} +/* PpmdHandler.cpp -- PPMd format handler +2020 : Igor Pavlov : Public domain +This code is based on: + PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain + Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/Alloc.h" +#include "../../../C/Ppmd7.h" +#include "../../../C/Ppmd8.h" + +#include "../../Common/ComTry.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/CWrappers.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +using namespace NWindows; + +namespace NArchive { +namespace NPpmd { + +static const UInt32 kBufSize = (1 << 20); + +struct CBuf +{ + Byte *Buf; + + CBuf(): Buf(NULL) {} + ~CBuf() { ::MidFree(Buf); } + bool Alloc() + { + if (!Buf) + Buf = (Byte *)::MidAlloc(kBufSize); + return (Buf != NULL); + } +}; + +static const UInt32 kHeaderSize = 16; +static const UInt32 kSignature = 0x84ACAF8F; +static const unsigned kNewHeaderVer = 8; + +struct CItem +{ + UInt32 Attrib; + UInt32 Time; + AString Name; + + unsigned Order; + unsigned MemInMB; + unsigned Ver; + unsigned Restor; + + HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize); + bool IsSupported() const + { + return (Ver == 7 && Order >= PPMD7_MIN_ORDER) + || (Ver == 8 && Order >= PPMD8_MIN_ORDER && Restor < PPMD8_RESTORE_METHOD_UNSUPPPORTED); + } +}; + +HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize) +{ + Byte h[kHeaderSize]; + RINOK(ReadStream_FALSE(s, h, kHeaderSize)) + if (GetUi32(h) != kSignature) + return S_FALSE; + Attrib = GetUi32(h + 4); + Time = GetUi32(h + 12); + const unsigned info = GetUi16(h + 8); + Order = (info & 0xF) + 1; + MemInMB = ((info >> 4) & 0xFF) + 1; + Ver = info >> 12; + + if (Ver < 6 || Ver > 11) return S_FALSE; + + UInt32 nameLen = GetUi16(h + 10); + Restor = nameLen >> 14; + if (Restor > 2) + return S_FALSE; + if (Ver >= kNewHeaderVer) + nameLen &= 0x3FFF; + if (nameLen > (1 << 9)) + return S_FALSE; + char *name = Name.GetBuf(nameLen); + const HRESULT res = ReadStream_FALSE(s, name, nameLen); + Name.ReleaseBuf_CalcLen(nameLen); + headerSize = kHeaderSize + nameLen; + return res; +} + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IArchiveOpenSeq +) + CItem _item; + UInt32 _headerSize; + bool _packSize_Defined; + UInt64 _packSize; + CMyComPtr _stream; + + void GetVersion(NCOM::CPropVariant &prop); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidMTime, + kpidAttrib, + kpidMethod +}; + +static const Byte kArcProps[] = +{ + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +void CHandler::GetVersion(NCOM::CPropVariant &prop) +{ + AString s ("PPMd"); + s.Add_Char((char)('A' + _item.Ver)); + s += ":o"; + s.Add_UInt32(_item.Order); + s += ":mem"; + s.Add_UInt32(_item.MemInMB); + s.Add_Char('m'); + if (_item.Ver >= kNewHeaderVer && _item.Restor != 0) + { + s += ":r"; + s.Add_UInt32(_item.Restor); + } + prop = s; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidMethod: GetVersion(prop); break; + } + prop.Detach(value); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break; + case kpidMTime: + { + // time can be in Unix format ??? + FILETIME utc; + if (NTime::DosTime_To_FileTime(_item.Time, utc)) + prop = utc; + break; + } + case kpidAttrib: prop = _item.Attrib; break; + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; + case kpidMethod: GetVersion(prop); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) +{ + return OpenSeq(stream); +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + COM_TRY_BEGIN + HRESULT res; + try + { + Close(); + res = _item.ReadHeader(stream, _headerSize); + } + catch(...) { res = S_FALSE; } + if (res == S_OK) + _stream = stream; + else + Close(); + return res; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _packSize = 0; + _packSize_Defined = false; + _stream.Release(); + return S_OK; +} + + + +struct CPpmdCpp +{ + unsigned Ver; + CPpmd7 _ppmd7; + CPpmd8 _ppmd8; + + CPpmdCpp(unsigned version) + { + Ver = version; + Ppmd7_Construct(&_ppmd7); + Ppmd8_Construct(&_ppmd8); + } + + ~CPpmdCpp() + { + Ppmd7_Free(&_ppmd7, &g_BigAlloc); + Ppmd8_Free(&_ppmd8, &g_BigAlloc); + } + + bool Alloc(UInt32 memInMB) + { + memInMB <<= 20; + if (Ver == 7) + return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0; + return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0; + } + + void Init(unsigned order, unsigned restor) + { + if (Ver == 7) + Ppmd7_Init(&_ppmd7, order); + else + Ppmd8_Init(&_ppmd8, order, restor); + } + + bool InitRc(CByteInBufWrap *inStream) + { + if (Ver == 7) + { + _ppmd7.rc.dec.Stream = &inStream->vt; + return (Ppmd7a_RangeDec_Init(&_ppmd7.rc.dec) != 0); + } + else + { + _ppmd8.Stream.In = &inStream->vt; + return Ppmd8_Init_RangeDec(&_ppmd8) != 0; + } + } + + bool IsFinishedOK() + { + if (Ver == 7) + return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7.rc.dec); + return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8); + } +}; + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + // extractCallback->SetTotal(_packSize); + UInt64 currentTotalPacked = 0; + RINOK(extractCallback->SetCompleted(¤tTotalPacked)) + Int32 opRes; +{ + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CByteInBufWrap inBuf; + if (!inBuf.Alloc(1 << 20)) + return E_OUTOFMEMORY; + inBuf.Stream = _stream; + + CBuf outBuf; + if (!outBuf.Alloc()) + return E_OUTOFMEMORY; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + + CPpmdCpp ppmd(_item.Ver); + if (!ppmd.Alloc(_item.MemInMB)) + return E_OUTOFMEMORY; + + opRes = NExtract::NOperationResult::kUnsupportedMethod; + + if (_item.IsSupported()) + { + opRes = NExtract::NOperationResult::kDataError; + + ppmd.Init(_item.Order, _item.Restor); + inBuf.Init(); + UInt64 outSize = 0; + + if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK) + for (;;) + { + lps->InSize = _packSize = inBuf.GetProcessed(); + lps->OutSize = outSize; + RINOK(lps->SetCur()) + + size_t i; + int sym = 0; + + Byte *buf = outBuf.Buf; + if (ppmd.Ver == 7) + { + for (i = 0; i < kBufSize; i++) + { + sym = Ppmd7a_DecodeSymbol(&ppmd._ppmd7); + if (inBuf.Extra || sym < 0) + break; + buf[i] = (Byte)sym; + } + } + else + { + for (i = 0; i < kBufSize; i++) + { + sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8); + if (inBuf.Extra || sym < 0) + break; + buf[i] = (Byte)sym; + } + } + + outSize += i; + _packSize = _headerSize + inBuf.GetProcessed(); + _packSize_Defined = true; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, outBuf.Buf, i)) + } + + if (inBuf.Extra) + { + opRes = NExtract::NOperationResult::kUnexpectedEnd; + break; + } + + if (sym < 0) + { + if (sym == -1 && ppmd.IsFinishedOK()) + opRes = NExtract::NOperationResult::kOK; + break; + } + } + + RINOK(inBuf.Res) + } +} + return extractCallback->SetOperationResult(opRes); +} + + +static const Byte k_Signature[] = { 0x8F, 0xAF, 0xAC, 0x84 }; + +REGISTER_ARC_I( + "Ppmd", "pmd", NULL, 0xD, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp index f1bc1e1bf..b0728805d 100644 --- a/CPP/7zip/Archive/QcowHandler.cpp +++ b/CPP/7zip/Archive/QcowHandler.cpp @@ -1,710 +1,710 @@ -// QcowHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer2.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/DeflateDecoder.h" - -#include "HandlerCont.h" - -#define Get32(p) GetBe32a(p) -#define Get64(p) GetBe64a(p) - -using namespace NWindows; - -namespace NArchive { -namespace NQcow { - -static const Byte k_Signature[] = { 'Q', 'F', 'I', 0xFB, 0, 0, 0 }; - -/* -VA to PA maps: - high bits (L1) : : index in L1 (_dir) : _dir[high_index] points to Table. - mid bits (L2) : _numMidBits : index in Table, Table[index] points to cluster start offset in arc file. - low bits : _clusterBits : offset inside cluster. -*/ - -Z7_class_CHandler_final: public CHandlerImg -{ - Z7_IFACE_COM7_IMP(IInArchive_Img) - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) - - unsigned _clusterBits; - unsigned _numMidBits; - UInt64 _compressedFlag; - - CObjArray2 _dir; - CAlignedBuffer _table; - CByteBuffer _cache; - CByteBuffer _cacheCompressed; - UInt64 _cacheCluster; - - UInt64 _comprPos; - size_t _comprSize; - - bool _needCompression; - bool _isArc; - bool _unsupported; - Byte _compressionType; - - UInt64 _phySize; - - CMyComPtr2 _bufInStream; - CMyComPtr2 _bufOutStream; - CMyComPtr2 _deflateDecoder; - - UInt32 _version; - UInt32 _cryptMethod; - UInt64 _incompatFlags; - - HRESULT Seek2(UInt64 offset) - { - _posInArc = offset; - return InStream_SeekSet(Stream, offset); - } - - HRESULT InitAndSeek() - { - _virtPos = 0; - return Seek2(0); - } - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; -}; - - -static const UInt32 kEmptyDirItem = (UInt32)0 - 1; - -Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - // printf("\nRead _virtPos = %6d size = %6d\n", (UInt32)_virtPos, size); - if (_virtPos >= _size) - return S_OK; - { - const UInt64 rem = _size - _virtPos; - if (size > rem) - size = (UInt32)rem; - if (size == 0) - return S_OK; - } - - for (;;) - { - const UInt64 cluster = _virtPos >> _clusterBits; - const size_t clusterSize = (size_t)1 << _clusterBits; - const size_t lowBits = (size_t)_virtPos & (clusterSize - 1); - { - const size_t rem = clusterSize - lowBits; - if (size > rem) - size = (UInt32)rem; - } - if (cluster == _cacheCluster) - { - memcpy(data, _cache + lowBits, size); - break; - } - - const UInt64 high = cluster >> _numMidBits; - - if (high < _dir.Size()) - { - const UInt32 tabl = _dir[(size_t)high]; - if (tabl != kEmptyDirItem) - { - const size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1); - const Byte *p = _table + ((((size_t)tabl << _numMidBits) + midBits) << 3); - UInt64 v = Get64(p); - - if (v) - { - if (v & _compressedFlag) - { - if (_version <= 1) - return E_FAIL; - /* - the example of table record for 12-bit clusters (4KB uncompressed): - 2 bits : isCompressed status - (4 == _clusterBits - 8) bits : (num_sectors - 1) - packSize = num_sectors * 512; - it uses one additional bit over unpacked cluster_bits. - (49 == 61 - _clusterBits) bits : offset of 512-byte sector - 9 bits : offset in 512-byte sector - */ - const unsigned numOffsetBits = 62 - (_clusterBits - 8); - const UInt64 offset = v & (((UInt64)1 << 62) - 1); - const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; - UInt64 sectorOffset = offset & (((UInt64)1 << numOffsetBits) - (1 << 9)); - const UInt64 offset2inCache = sectorOffset - _comprPos; - - // _comprPos is aligned for 512-bytes - // we try to use previous _cacheCompressed that contains compressed data - // that was read for previous unpacking - - if (sectorOffset >= _comprPos && offset2inCache < _comprSize) - { - if (offset2inCache) - { - _comprSize -= (size_t)offset2inCache; - memmove(_cacheCompressed, _cacheCompressed + (size_t)offset2inCache, _comprSize); - _comprPos = sectorOffset; - } - sectorOffset += _comprSize; - } - else - { - _comprPos = sectorOffset; - _comprSize = 0; - } - - if (dataSize > _comprSize) - { - if (sectorOffset != _posInArc) - { - // printf("\nDeflate-Seek %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc); - RINOK(Seek2(sectorOffset)) - } - if (_cacheCompressed.Size() < dataSize) - return E_FAIL; - const size_t dataSize3 = dataSize - _comprSize; - size_t dataSize2 = dataSize3; - // printf("\n\n=======\nReadStream = %6d _comprPos = %6d \n", (UInt32)dataSize2, (UInt32)_comprPos); - const HRESULT hres = ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2); - _posInArc += dataSize2; - RINOK(hres) - if (dataSize2 != dataSize3) - return E_FAIL; - _comprSize += dataSize2; - } - - const size_t kSectorMask = (1 << 9) - 1; - const size_t offsetInSector = (size_t)offset & kSectorMask; - _bufInStream->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector); - _cacheCluster = (UInt64)(Int64)-1; - if (_cache.Size() < clusterSize) - return E_FAIL; - _bufOutStream->Init(_cache, clusterSize); - // Do we need to use smaller block than clusterSize for last cluster? - const UInt64 blockSize64 = clusterSize; - HRESULT res = _deflateDecoder.Interface()->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); - /* - if (_bufOutStreamSpec->GetPos() != clusterSize) - memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); - */ - if (res == S_OK) - if (!_deflateDecoder->IsFinished() - || _bufOutStream->GetPos() != clusterSize) - res = S_FALSE; - RINOK(res) - _cacheCluster = cluster; - continue; - /* - memcpy(data, _cache + lowBits, size); - break; - */ - } - - // version_3 supports zero clusters - if (((UInt32)v & 511) != 1) - { - v &= _compressedFlag - 1; - v += lowBits; - if (v != _posInArc) - { - // printf("\n%12I64x\n", v - _posInArc); - RINOK(Seek2(v)) - } - const HRESULT res = Stream->Read(data, size, &size); - _posInArc += size; - _virtPos += size; - if (processedSize) - *processedSize = size; - return res; - } - } - } - } - - memset(data, 0, size); - break; - } - - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; -} - - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidClusterSize, - kpidSectorSize, // actually we need variable to show table size - kpidHeadersSize, - kpidUnpackVer, - kpidMethod, - kpidCharacts -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static const CUInt32PCharPair g_IncompatFlags_Characts[] = -{ - { 0, "Dirty" }, - { 1, "Corrupt" }, - { 2, "External_Data_File" }, - { 3, "Compression" }, - { 4, "Extended_L2" } -}; - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break; - case kpidSectorSize: prop = (UInt32)1 << (_numMidBits + 3); break; - case kpidHeadersSize: prop = _table.Size() + (UInt64)_dir.Size() * 8; break; - case kpidPhySize: if (_phySize) prop = _phySize; break; - case kpidUnpackVer: prop = _version; break; - case kpidCharacts: - { - if (_incompatFlags) - { - AString s ("incompatible: "); - // we need to show also high 32-bits. - s += FlagsToString(g_IncompatFlags_Characts, - Z7_ARRAY_SIZE(g_IncompatFlags_Characts), (UInt32)_incompatFlags); - prop = s; - } - break; - } - case kpidMethod: - { - AString s; - - if (_compressionType) - { - if (_compressionType == 1) - s += "ZSTD"; - else - { - s += "Compression:"; - s.Add_UInt32(_compressionType); - } - } - else if (_needCompression) - s.Add_OptSpaced("Deflate"); - - if (_cryptMethod) - { - s.Add_Space_if_NotEmpty(); - if (_cryptMethod == 1) - s += "AES"; - if (_cryptMethod == 2) - s += "LUKS"; - else - { - s += "Encryption:"; - s.Add_UInt32(_cryptMethod); - } - } - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; - // if (_headerError) v |= kpv_ErrorFlags_HeadersError; - if (!Stream && v == 0) - v = kpv_ErrorFlags_HeadersError; - if (v) - prop = v; - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidSize: prop = _size; break; - case kpidPackSize: prop = _phySize; break; - case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) -{ - UInt64 buf64[0x70 / 8]; - RINOK(ReadStream_FALSE(stream, buf64, sizeof(buf64))) - const void *buf = (const void *)buf64; - // signature: { 'Q', 'F', 'I', 0xFB } - if (*(const UInt32 *)buf != Z7_CONV_BE_TO_NATIVE_CONST32(0x514649fb)) - return S_FALSE; - _version = Get32((const Byte *)(const void *)buf64 + 4); - if (_version < 1 || _version > 3) - return S_FALSE; - - const UInt64 k_UncompressedSize_MAX = (UInt64)1 << 60; - const UInt64 k_CompressedSize_MAX = (UInt64)1 << 60; - - _size = Get64((const Byte *)(const void *)buf64 + 0x18); - if (_size > k_UncompressedSize_MAX) - return S_FALSE; - size_t l1Size; - UInt32 headerSize; - - if (_version == 1) - { - // _mTime = Get32((const Byte *)(const void *)buf64 + 0x14); // is unused in most images - _clusterBits = ((const Byte *)(const void *)buf64)[0x20]; - _numMidBits = ((const Byte *)(const void *)buf64)[0x21]; - if (_clusterBits < 9 || _clusterBits > 30) - return S_FALSE; - if (_numMidBits < 1 || _numMidBits > 28) - return S_FALSE; - _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x24); - const unsigned numBits2 = _clusterBits + _numMidBits; - const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2; - if (l1Size64 > ((UInt32)1 << 31)) - return S_FALSE; - l1Size = (size_t)l1Size64; - headerSize = 0x30; - } - else - { - _clusterBits = Get32((const Byte *)(const void *)buf64 + 0x14); - if (_clusterBits < 9 || _clusterBits > 30) - return S_FALSE; - _numMidBits = _clusterBits - 3; - _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x20); - l1Size = Get32((const Byte *)(const void *)buf64 + 0x24); - headerSize = 0x48; - if (_version >= 3) - { - _incompatFlags = Get64((const Byte *)(const void *)buf64 + 0x48); - // const UInt64 CompatFlags = Get64((const Byte *)(const void *)buf64 + 0x50); - // const UInt64 AutoClearFlags = Get64((const Byte *)(const void *)buf64 + 0x58); - // const UInt32 RefCountOrder = Get32((const Byte *)(const void *)buf64 + 0x60); - headerSize = 0x68; - const UInt32 headerSize2 = Get32((const Byte *)(const void *)buf64 + 0x64); - if (headerSize2 > (1u << 30)) - return S_FALSE; - if (headerSize < headerSize2) - headerSize = headerSize2; - if (headerSize2 >= 0x68 + 1) - _compressionType = ((const Byte *)(const void *)buf64)[0x68]; - } - - const UInt64 refOffset = Get64((const Byte *)(const void *)buf64 + 0x30); // must be aligned for cluster - const UInt32 refClusters = Get32((const Byte *)(const void *)buf64 + 0x38); - // UInt32 numSnapshots = Get32((const Byte *)(const void *)buf64 + 0x3C); - // UInt64 snapshotsOffset = Get64((const Byte *)(const void *)buf64 + 0x40); // must be aligned for cluster - /* - if (numSnapshots) - return S_FALSE; - */ - if (refClusters) - { - if (refOffset > k_CompressedSize_MAX) - return S_FALSE; - const UInt64 numBytes = (UInt64)refClusters << _clusterBits; - const UInt64 end = refOffset + numBytes; - if (end > k_CompressedSize_MAX) - return S_FALSE; - /* - CByteBuffer refs; - refs.Alloc(numBytes); - RINOK(InStream_SeekSet(stream, refOffset)) - RINOK(ReadStream_FALSE(stream, refs, numBytes)); - */ - if (_phySize < end) - _phySize = end; - /* - for (size_t i = 0; i < numBytes; i += 2) - { - UInt32 v = GetBe16((const Byte *)refs + (size_t)i); - if (v == 0) - continue; - } - */ - } - } - - const UInt64 l1Offset = Get64((const Byte *)(const void *)buf64 + 0x28); // must be aligned for cluster ? - if (l1Offset < headerSize || l1Offset > k_CompressedSize_MAX) - return S_FALSE; - if (_phySize < headerSize) - _phySize = headerSize; - - _isArc = true; - { - const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8); - // UInt32 backSize = Get32((const Byte *)(const void *)buf64 + 0x10); - if (backOffset) - { - _unsupported = true; - return S_FALSE; - } - } - - UInt64 fileSize = 0; - RINOK(InStream_GetSize_SeekToBegin(stream, fileSize)) - - const size_t clusterSize = (size_t)1 << _clusterBits; - const size_t t1SizeBytes = (size_t)l1Size << 3; - { - const UInt64 end = l1Offset + t1SizeBytes; - if (end > k_CompressedSize_MAX) - return S_FALSE; - // we need to use align end for empty qcow files - // some files has no cluster alignment padding at the end - // but has sector alignment - // end = (end + clusterSize - 1) >> _clusterBits << _clusterBits; - if (_phySize < end) - _phySize = end; - if (end > fileSize) - return S_FALSE; - if (_phySize < fileSize) - { - const UInt64 end2 = (end + 511) & ~(UInt64)511; - if (end2 == fileSize) - _phySize = end2; - } - } - CObjArray table64(l1Size); - { - // if ((t1SizeBytes >> 3) != l1Size) return S_FALSE; - RINOK(InStream_SeekSet(stream, l1Offset)) - RINOK(ReadStream_FALSE(stream, table64, t1SizeBytes)) - } - - _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62); - const UInt64 offsetMask = _compressedFlag - 1; - const size_t midSize = (size_t)1 << (_numMidBits + 3); - size_t numTables = 0; - size_t i; - - for (i = 0; i < l1Size; i++) - { - const UInt64 v = Get64(table64 + (size_t)i) & offsetMask; - if (!v) - continue; - numTables++; - const UInt64 end = v + midSize; - if (end > k_CompressedSize_MAX) - return S_FALSE; - if (_phySize < end) - _phySize = end; - if (end > fileSize) - return S_FALSE; - } - - if (numTables) - { - const size_t size = (size_t)numTables << (_numMidBits + 3); - if (size >> (_numMidBits + 3) != numTables) - return E_OUTOFMEMORY; - _table.Alloc(size); - if (!_table.IsAllocated()) - return E_OUTOFMEMORY; - if (openCallback) - { - const UInt64 totalBytes = size; - RINOK(openCallback->SetTotal(NULL, &totalBytes)) - } - } - - _dir.SetSize((unsigned)l1Size); - - UInt32 curTable = 0; - - for (i = 0; i < l1Size; i++) - { - Byte *buf2; - { - const UInt64 v = Get64(table64 + (size_t)i) & offsetMask; - if (v == 0) - { - _dir[i] = kEmptyDirItem; - continue; - } - _dir[i] = curTable; - const size_t tableOffset = (size_t)curTable << (_numMidBits + 3); - buf2 = (Byte *)_table + tableOffset; - curTable++; - if (openCallback && (tableOffset & 0xFFFFF) == 0) - { - const UInt64 numBytes = tableOffset; - RINOK(openCallback->SetCompleted(NULL, &numBytes)) - } - RINOK(InStream_SeekSet(stream, v)) - RINOK(ReadStream_FALSE(stream, buf2, midSize)) - } - - for (size_t k = 0; k < midSize; k += 8) - { - const UInt64 v = Get64((const Byte *)buf2 + (size_t)k); - if (v == 0) - continue; - UInt64 offset = v & offsetMask; - size_t dataSize = clusterSize; - - if (v & _compressedFlag) - { - if (_version <= 1) - { - const unsigned numOffsetBits = 63 - _clusterBits; - dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; - offset &= ((UInt64)1 << numOffsetBits) - 1; - dataSize = 0; // why ? - // offset &= ~(((UInt64)1 << 9) - 1); - } - else - { - const unsigned numOffsetBits = 62 - (_clusterBits - 8); - dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; - offset &= ((UInt64)1 << numOffsetBits) - (1 << 9); - } - _needCompression = true; - } - else - { - const UInt32 low = (UInt32)v & 511; - if (low) - { - // version_3 supports zero clusters - if (_version < 3 || low != 1) - { - _unsupported = true; - return S_FALSE; - } - } - } - - const UInt64 end = offset + dataSize; - if (_phySize < end) - _phySize = end; - } - } - - if (curTable != numTables) - return E_FAIL; - - if (_cryptMethod) - _unsupported = true; - if (_needCompression && _version <= 1) // that case was not implemented - _unsupported = true; - if (_compressionType) - _unsupported = true; - - Stream = stream; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _table.Free(); - _dir.Free(); - // _cache.Free(); - // _cacheCompressed.Free(); - _phySize = 0; - - _cacheCluster = (UInt64)(Int64)-1; - _comprPos = 0; - _comprSize = 0; - - _needCompression = false; - _isArc = false; - _unsupported = false; - - _compressionType = 0; - _incompatFlags = 0; - - // CHandlerImg: - Clear_HandlerImg_Vars(); - Stream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - if (_unsupported || !Stream) - return S_FALSE; - if (_needCompression) - { - if (_version <= 1 || _compressionType) - return S_FALSE; - _bufInStream.Create_if_Empty(); - _bufOutStream.Create_if_Empty(); - _deflateDecoder.Create_if_Empty(); - _deflateDecoder->Set_NeedFinishInput(true); - const size_t clusterSize = (size_t)1 << _clusterBits; - _cache.AllocAtLeast(clusterSize); - _cacheCompressed.AllocAtLeast(clusterSize * 2); - } - CMyComPtr streamTemp = this; - RINOK(InitAndSeek()) - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - -REGISTER_ARC_I( - "QCOW", "qcow qcow2 qcow2c", NULL, 0xCA, - k_Signature, - 0, - 0, - NULL) - -}} +// QcowHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer2.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/DeflateDecoder.h" + +#include "HandlerCont.h" + +#define Get32(p) GetBe32a(p) +#define Get64(p) GetBe64a(p) + +using namespace NWindows; + +namespace NArchive { +namespace NQcow { + +static const Byte k_Signature[] = { 'Q', 'F', 'I', 0xFB, 0, 0, 0 }; + +/* +VA to PA maps: + high bits (L1) : : index in L1 (_dir) : _dir[high_index] points to Table. + mid bits (L2) : _numMidBits : index in Table, Table[index] points to cluster start offset in arc file. + low bits : _clusterBits : offset inside cluster. +*/ + +Z7_class_CHandler_final: public CHandlerImg +{ + Z7_IFACE_COM7_IMP(IInArchive_Img) + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) + + unsigned _clusterBits; + unsigned _numMidBits; + UInt64 _compressedFlag; + + CObjArray2 _dir; + CAlignedBuffer _table; + CByteBuffer _cache; + CByteBuffer _cacheCompressed; + UInt64 _cacheCluster; + + UInt64 _comprPos; + size_t _comprSize; + + bool _needCompression; + bool _isArc; + bool _unsupported; + Byte _compressionType; + + UInt64 _phySize; + + CMyComPtr2 _bufInStream; + CMyComPtr2 _bufOutStream; + CMyComPtr2 _deflateDecoder; + + UInt32 _version; + UInt32 _cryptMethod; + UInt64 _incompatFlags; + + HRESULT Seek2(UInt64 offset) + { + _posInArc = offset; + return InStream_SeekSet(Stream, offset); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek2(0); + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; +}; + + +static const UInt32 kEmptyDirItem = (UInt32)0 - 1; + +Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + // printf("\nRead _virtPos = %6d size = %6d\n", (UInt32)_virtPos, size); + if (_virtPos >= _size) + return S_OK; + { + const UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + for (;;) + { + const UInt64 cluster = _virtPos >> _clusterBits; + const size_t clusterSize = (size_t)1 << _clusterBits; + const size_t lowBits = (size_t)_virtPos & (clusterSize - 1); + { + const size_t rem = clusterSize - lowBits; + if (size > rem) + size = (UInt32)rem; + } + if (cluster == _cacheCluster) + { + memcpy(data, _cache + lowBits, size); + break; + } + + const UInt64 high = cluster >> _numMidBits; + + if (high < _dir.Size()) + { + const UInt32 tabl = _dir[(size_t)high]; + if (tabl != kEmptyDirItem) + { + const size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1); + const Byte *p = _table + ((((size_t)tabl << _numMidBits) + midBits) << 3); + UInt64 v = Get64(p); + + if (v) + { + if (v & _compressedFlag) + { + if (_version <= 1) + return E_FAIL; + /* + the example of table record for 12-bit clusters (4KB uncompressed): + 2 bits : isCompressed status + (4 == _clusterBits - 8) bits : (num_sectors - 1) + packSize = num_sectors * 512; + it uses one additional bit over unpacked cluster_bits. + (49 == 61 - _clusterBits) bits : offset of 512-byte sector + 9 bits : offset in 512-byte sector + */ + const unsigned numOffsetBits = 62 - (_clusterBits - 8); + const UInt64 offset = v & (((UInt64)1 << 62) - 1); + const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + UInt64 sectorOffset = offset & (((UInt64)1 << numOffsetBits) - (1 << 9)); + const UInt64 offset2inCache = sectorOffset - _comprPos; + + // _comprPos is aligned for 512-bytes + // we try to use previous _cacheCompressed that contains compressed data + // that was read for previous unpacking + + if (sectorOffset >= _comprPos && offset2inCache < _comprSize) + { + if (offset2inCache) + { + _comprSize -= (size_t)offset2inCache; + memmove(_cacheCompressed, _cacheCompressed + (size_t)offset2inCache, _comprSize); + _comprPos = sectorOffset; + } + sectorOffset += _comprSize; + } + else + { + _comprPos = sectorOffset; + _comprSize = 0; + } + + if (dataSize > _comprSize) + { + if (sectorOffset != _posInArc) + { + // printf("\nDeflate-Seek %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc); + RINOK(Seek2(sectorOffset)) + } + if (_cacheCompressed.Size() < dataSize) + return E_FAIL; + const size_t dataSize3 = dataSize - _comprSize; + size_t dataSize2 = dataSize3; + // printf("\n\n=======\nReadStream = %6d _comprPos = %6d \n", (UInt32)dataSize2, (UInt32)_comprPos); + const HRESULT hres = ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2); + _posInArc += dataSize2; + RINOK(hres) + if (dataSize2 != dataSize3) + return E_FAIL; + _comprSize += dataSize2; + } + + const size_t kSectorMask = (1 << 9) - 1; + const size_t offsetInSector = (size_t)offset & kSectorMask; + _bufInStream->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector); + _cacheCluster = (UInt64)(Int64)-1; + if (_cache.Size() < clusterSize) + return E_FAIL; + _bufOutStream->Init(_cache, clusterSize); + // Do we need to use smaller block than clusterSize for last cluster? + const UInt64 blockSize64 = clusterSize; + HRESULT res = _deflateDecoder.Interface()->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); + /* + if (_bufOutStreamSpec->GetPos() != clusterSize) + memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); + */ + if (res == S_OK) + if (!_deflateDecoder->IsFinished() + || _bufOutStream->GetPos() != clusterSize) + res = S_FALSE; + RINOK(res) + _cacheCluster = cluster; + continue; + /* + memcpy(data, _cache + lowBits, size); + break; + */ + } + + // version_3 supports zero clusters + if (((UInt32)v & 511) != 1) + { + v &= _compressedFlag - 1; + v += lowBits; + if (v != _posInArc) + { + // printf("\n%12I64x\n", v - _posInArc); + RINOK(Seek2(v)) + } + const HRESULT res = Stream->Read(data, size, &size); + _posInArc += size; + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + } + } + } + } + + memset(data, 0, size); + break; + } + + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidClusterSize, + kpidSectorSize, // actually we need variable to show table size + kpidHeadersSize, + kpidUnpackVer, + kpidMethod, + kpidCharacts +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static const CUInt32PCharPair g_IncompatFlags_Characts[] = +{ + { 0, "Dirty" }, + { 1, "Corrupt" }, + { 2, "External_Data_File" }, + { 3, "Compression" }, + { 4, "Extended_L2" } +}; + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break; + case kpidSectorSize: prop = (UInt32)1 << (_numMidBits + 3); break; + case kpidHeadersSize: prop = _table.Size() + (UInt64)_dir.Size() * 8; break; + case kpidPhySize: if (_phySize) prop = _phySize; break; + case kpidUnpackVer: prop = _version; break; + case kpidCharacts: + { + if (_incompatFlags) + { + AString s ("incompatible: "); + // we need to show also high 32-bits. + s += FlagsToString(g_IncompatFlags_Characts, + Z7_ARRAY_SIZE(g_IncompatFlags_Characts), (UInt32)_incompatFlags); + prop = s; + } + break; + } + case kpidMethod: + { + AString s; + + if (_compressionType) + { + if (_compressionType == 1) + s += "ZSTD"; + else + { + s += "Compression:"; + s.Add_UInt32(_compressionType); + } + } + else if (_needCompression) + s.Add_OptSpaced("Deflate"); + + if (_cryptMethod) + { + s.Add_Space_if_NotEmpty(); + if (_cryptMethod == 1) + s += "AES"; + if (_cryptMethod == 2) + s += "LUKS"; + else + { + s += "Encryption:"; + s.Add_UInt32(_cryptMethod); + } + } + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + // if (_headerError) v |= kpv_ErrorFlags_HeadersError; + if (!Stream && v == 0) + v = kpv_ErrorFlags_HeadersError; + if (v) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: prop = _phySize; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) +{ + UInt64 buf64[0x70 / 8]; + RINOK(ReadStream_FALSE(stream, buf64, sizeof(buf64))) + const void *buf = (const void *)buf64; + // signature: { 'Q', 'F', 'I', 0xFB } + if (*(const UInt32 *)buf != Z7_CONV_BE_TO_NATIVE_CONST32(0x514649fb)) + return S_FALSE; + _version = Get32((const Byte *)(const void *)buf64 + 4); + if (_version < 1 || _version > 3) + return S_FALSE; + + const UInt64 k_UncompressedSize_MAX = (UInt64)1 << 60; + const UInt64 k_CompressedSize_MAX = (UInt64)1 << 60; + + _size = Get64((const Byte *)(const void *)buf64 + 0x18); + if (_size > k_UncompressedSize_MAX) + return S_FALSE; + size_t l1Size; + UInt32 headerSize; + + if (_version == 1) + { + // _mTime = Get32((const Byte *)(const void *)buf64 + 0x14); // is unused in most images + _clusterBits = ((const Byte *)(const void *)buf64)[0x20]; + _numMidBits = ((const Byte *)(const void *)buf64)[0x21]; + if (_clusterBits < 9 || _clusterBits > 30) + return S_FALSE; + if (_numMidBits < 1 || _numMidBits > 28) + return S_FALSE; + _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x24); + const unsigned numBits2 = _clusterBits + _numMidBits; + const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2; + if (l1Size64 > ((UInt32)1 << 31)) + return S_FALSE; + l1Size = (size_t)l1Size64; + headerSize = 0x30; + } + else + { + _clusterBits = Get32((const Byte *)(const void *)buf64 + 0x14); + if (_clusterBits < 9 || _clusterBits > 30) + return S_FALSE; + _numMidBits = _clusterBits - 3; + _cryptMethod = Get32((const Byte *)(const void *)buf64 + 0x20); + l1Size = Get32((const Byte *)(const void *)buf64 + 0x24); + headerSize = 0x48; + if (_version >= 3) + { + _incompatFlags = Get64((const Byte *)(const void *)buf64 + 0x48); + // const UInt64 CompatFlags = Get64((const Byte *)(const void *)buf64 + 0x50); + // const UInt64 AutoClearFlags = Get64((const Byte *)(const void *)buf64 + 0x58); + // const UInt32 RefCountOrder = Get32((const Byte *)(const void *)buf64 + 0x60); + headerSize = 0x68; + const UInt32 headerSize2 = Get32((const Byte *)(const void *)buf64 + 0x64); + if (headerSize2 > (1u << 30)) + return S_FALSE; + if (headerSize < headerSize2) + headerSize = headerSize2; + if (headerSize2 >= 0x68 + 1) + _compressionType = ((const Byte *)(const void *)buf64)[0x68]; + } + + const UInt64 refOffset = Get64((const Byte *)(const void *)buf64 + 0x30); // must be aligned for cluster + const UInt32 refClusters = Get32((const Byte *)(const void *)buf64 + 0x38); + // UInt32 numSnapshots = Get32((const Byte *)(const void *)buf64 + 0x3C); + // UInt64 snapshotsOffset = Get64((const Byte *)(const void *)buf64 + 0x40); // must be aligned for cluster + /* + if (numSnapshots) + return S_FALSE; + */ + if (refClusters) + { + if (refOffset > k_CompressedSize_MAX) + return S_FALSE; + const UInt64 numBytes = (UInt64)refClusters << _clusterBits; + const UInt64 end = refOffset + numBytes; + if (end > k_CompressedSize_MAX) + return S_FALSE; + /* + CByteBuffer refs; + refs.Alloc(numBytes); + RINOK(InStream_SeekSet(stream, refOffset)) + RINOK(ReadStream_FALSE(stream, refs, numBytes)); + */ + if (_phySize < end) + _phySize = end; + /* + for (size_t i = 0; i < numBytes; i += 2) + { + UInt32 v = GetBe16((const Byte *)refs + (size_t)i); + if (v == 0) + continue; + } + */ + } + } + + const UInt64 l1Offset = Get64((const Byte *)(const void *)buf64 + 0x28); // must be aligned for cluster ? + if (l1Offset < headerSize || l1Offset > k_CompressedSize_MAX) + return S_FALSE; + if (_phySize < headerSize) + _phySize = headerSize; + + _isArc = true; + { + const UInt64 backOffset = Get64((const Byte *)(const void *)buf64 + 8); + // UInt32 backSize = Get32((const Byte *)(const void *)buf64 + 0x10); + if (backOffset) + { + _unsupported = true; + return S_FALSE; + } + } + + UInt64 fileSize = 0; + RINOK(InStream_GetSize_SeekToBegin(stream, fileSize)) + + const size_t clusterSize = (size_t)1 << _clusterBits; + const size_t t1SizeBytes = (size_t)l1Size << 3; + { + const UInt64 end = l1Offset + t1SizeBytes; + if (end > k_CompressedSize_MAX) + return S_FALSE; + // we need to use align end for empty qcow files + // some files has no cluster alignment padding at the end + // but has sector alignment + // end = (end + clusterSize - 1) >> _clusterBits << _clusterBits; + if (_phySize < end) + _phySize = end; + if (end > fileSize) + return S_FALSE; + if (_phySize < fileSize) + { + const UInt64 end2 = (end + 511) & ~(UInt64)511; + if (end2 == fileSize) + _phySize = end2; + } + } + CObjArray table64(l1Size); + { + // if ((t1SizeBytes >> 3) != l1Size) return S_FALSE; + RINOK(InStream_SeekSet(stream, l1Offset)) + RINOK(ReadStream_FALSE(stream, table64, t1SizeBytes)) + } + + _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62); + const UInt64 offsetMask = _compressedFlag - 1; + const size_t midSize = (size_t)1 << (_numMidBits + 3); + size_t numTables = 0; + size_t i; + + for (i = 0; i < l1Size; i++) + { + const UInt64 v = Get64(table64 + (size_t)i) & offsetMask; + if (!v) + continue; + numTables++; + const UInt64 end = v + midSize; + if (end > k_CompressedSize_MAX) + return S_FALSE; + if (_phySize < end) + _phySize = end; + if (end > fileSize) + return S_FALSE; + } + + if (numTables) + { + const size_t size = (size_t)numTables << (_numMidBits + 3); + if (size >> (_numMidBits + 3) != numTables) + return E_OUTOFMEMORY; + _table.Alloc(size); + if (!_table.IsAllocated()) + return E_OUTOFMEMORY; + if (openCallback) + { + const UInt64 totalBytes = size; + RINOK(openCallback->SetTotal(NULL, &totalBytes)) + } + } + + _dir.SetSize((unsigned)l1Size); + + UInt32 curTable = 0; + + for (i = 0; i < l1Size; i++) + { + Byte *buf2; + { + const UInt64 v = Get64(table64 + (size_t)i) & offsetMask; + if (v == 0) + { + _dir[i] = kEmptyDirItem; + continue; + } + _dir[i] = curTable; + const size_t tableOffset = (size_t)curTable << (_numMidBits + 3); + buf2 = (Byte *)_table + tableOffset; + curTable++; + if (openCallback && (tableOffset & 0xFFFFF) == 0) + { + const UInt64 numBytes = tableOffset; + RINOK(openCallback->SetCompleted(NULL, &numBytes)) + } + RINOK(InStream_SeekSet(stream, v)) + RINOK(ReadStream_FALSE(stream, buf2, midSize)) + } + + for (size_t k = 0; k < midSize; k += 8) + { + const UInt64 v = Get64((const Byte *)buf2 + (size_t)k); + if (v == 0) + continue; + UInt64 offset = v & offsetMask; + size_t dataSize = clusterSize; + + if (v & _compressedFlag) + { + if (_version <= 1) + { + const unsigned numOffsetBits = 63 - _clusterBits; + dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + offset &= ((UInt64)1 << numOffsetBits) - 1; + dataSize = 0; // why ? + // offset &= ~(((UInt64)1 << 9) - 1); + } + else + { + const unsigned numOffsetBits = 62 - (_clusterBits - 8); + dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9; + offset &= ((UInt64)1 << numOffsetBits) - (1 << 9); + } + _needCompression = true; + } + else + { + const UInt32 low = (UInt32)v & 511; + if (low) + { + // version_3 supports zero clusters + if (_version < 3 || low != 1) + { + _unsupported = true; + return S_FALSE; + } + } + } + + const UInt64 end = offset + dataSize; + if (_phySize < end) + _phySize = end; + } + } + + if (curTable != numTables) + return E_FAIL; + + if (_cryptMethod) + _unsupported = true; + if (_needCompression && _version <= 1) // that case was not implemented + _unsupported = true; + if (_compressionType) + _unsupported = true; + + Stream = stream; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _table.Free(); + _dir.Free(); + // _cache.Free(); + // _cacheCompressed.Free(); + _phySize = 0; + + _cacheCluster = (UInt64)(Int64)-1; + _comprPos = 0; + _comprSize = 0; + + _needCompression = false; + _isArc = false; + _unsupported = false; + + _compressionType = 0; + _incompatFlags = 0; + + // CHandlerImg: + Clear_HandlerImg_Vars(); + Stream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + if (_unsupported || !Stream) + return S_FALSE; + if (_needCompression) + { + if (_version <= 1 || _compressionType) + return S_FALSE; + _bufInStream.Create_if_Empty(); + _bufOutStream.Create_if_Empty(); + _deflateDecoder.Create_if_Empty(); + _deflateDecoder->Set_NeedFinishInput(true); + const size_t clusterSize = (size_t)1 << _clusterBits; + _cache.AllocAtLeast(clusterSize); + _cacheCompressed.AllocAtLeast(clusterSize * 2); + } + CMyComPtr streamTemp = this; + RINOK(InitAndSeek()) + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "QCOW", "qcow qcow2 qcow2c", NULL, 0xCA, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp index 4887bd1ed..7d75aae99 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp @@ -1,3457 +1,3465 @@ -// Rar5Handler.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/PropVariantUtils.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../IPassword.h" - -#include "../../Common/FilterCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/MethodProps.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/RegisterArc.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../../Common/RegisterCodec.h" - -#include "../../Compress/CopyCoder.h" - -#include "../../Crypto/Rar5Aes.h" - -#include "../../Archive/Common/FindSignature.h" -#include "../../Archive/Common/ItemNameUtils.h" -#include "../../Archive/Common/HandlerOut.h" - -#include "../../Archive/HandlerCont.h" - -#include "../../Archive/Rar/RarVol.h" -#include "Rar5Handler.h" - -using namespace NWindows; - -#define Get32(p) GetUi32(p) - -namespace NArchive { -namespace NRar5 { - -static const unsigned kMarkerSize = 8; - -static const Byte kMarker[kMarkerSize] = - { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 }; - -// Comment length is limited to 256 KB in rar-encoder. -// So we use same limitation -static const size_t kCommentSize_Max = (size_t)1 << 18; - - -static const char * const kHostOS[] = -{ - "Windows" - , "Unix" -}; - - -static const char * const k_ArcFlags[] = -{ - "Volume" - , "VolumeField" - , "Solid" - , "Recovery" - , "Lock" // 4 -}; - - -static const char * const k_FileFlags[] = -{ - "Dir" - , "UnixTime" - , "CRC" - , "UnknownSize" -}; - - -static const char * const g_ExtraTypes[] = -{ - "0" - , "Crypto" - , "Hash" - , "Time" - , "Version" - , "Link" - , "UnixOwner" - , "Subdata" -}; - - -static const char * const g_LinkTypes[] = -{ - "0" - , "UnixSymLink" - , "WinSymLink" - , "WinJunction" - , "HardLink" - , "FileCopy" -}; - - -static const char g_ExtraTimeFlags[] = { 'u', 'M', 'C', 'A', 'n' }; - - -static -Z7_NO_INLINE -unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val_ptr) -{ - if (maxSize > 10) - maxSize = 10; - UInt64 val = 0; - unsigned i; - for (i = 0; i < maxSize;) - { - const unsigned b = p[i]; - val |= (UInt64)(b & 0x7F) << (7 * i); - i++; - if ((b & 0x80) == 0) - { - *val_ptr = val; - return i; - } - } - *val_ptr = 0; -#if 1 - return 0; // 7zip-unrar : strict check of error -#else - return i; // original-unrar : ignore error -#endif -} - - -#define PARSE_VAR_INT(p, size, dest) \ -{ const unsigned num_ = ReadVarInt(p, size, &dest); \ - if (num_ == 0) return false; \ - p += num_; \ - size -= num_; \ -} - - -bool CLinkInfo::Parse(const Byte *p, unsigned size) -{ - const Byte *pStart = p; - UInt64 len; - PARSE_VAR_INT(p, size, Type) - PARSE_VAR_INT(p, size, Flags) - PARSE_VAR_INT(p, size, len) - if (size != len) - return false; - NameLen = (unsigned)len; - NameOffset = (unsigned)(size_t)(p - pStart); - return true; -} - - -static void AddHex64(AString &s, UInt64 v) -{ - char sz[32]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt64ToHex(v, sz + 2); - s += sz; -} - - -static void PrintType(AString &s, const char * const table[], unsigned num, UInt64 val) -{ - char sz[32]; - const char *p = NULL; - if (val < num) - p = table[(unsigned)val]; - if (!p) - { - ConvertUInt64ToString(val, sz); - p = sz; - } - s += p; -} - - -int CItem::FindExtra(unsigned extraID, unsigned &recordDataSize) const -{ - recordDataSize = 0; - size_t offset = 0; - - for (;;) - { - size_t rem = Extra.Size() - offset; - if (rem == 0) - return -1; - - { - UInt64 size; - const unsigned num = ReadVarInt(Extra + offset, rem, &size); - if (num == 0) - return -1; - offset += num; - rem -= num; - if (size > rem) - return -1; - rem = (size_t)size; - } - { - UInt64 id; - const unsigned num = ReadVarInt(Extra + offset, rem, &id); - if (num == 0) - return -1; - offset += num; - rem -= num; - - // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) - // for Subdata record in Service header. - // That record always was last in bad archives, so we can fix that case. - if (id == NExtraID::kSubdata - && RecordType == NHeaderType::kService - && rem + 1 == Extra.Size() - offset) - rem++; - - if (id == extraID) - { - recordDataSize = (unsigned)rem; - return (int)offset; - } - - offset += rem; - } - } -} - - -void CItem::PrintInfo(AString &s) const -{ - size_t offset = 0; - - for (;;) - { - size_t rem = Extra.Size() - offset; - if (rem == 0) - return; - - { - UInt64 size; - unsigned num = ReadVarInt(Extra + offset, rem, &size); - if (num == 0) - return; - offset += num; - rem -= num; - if (size > rem) - break; - rem = (size_t)size; - } - { - UInt64 id; - { - unsigned num = ReadVarInt(Extra + offset, rem, &id); - if (num == 0) - break; - offset += num; - rem -= num; - } - - // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) - // for Subdata record in Service header. - // That record always was last in bad archives, so we can fix that case. - if (id == NExtraID::kSubdata - && RecordType == NHeaderType::kService - && rem + 1 == Extra.Size() - offset) - rem++; - - s.Add_Space_if_NotEmpty(); - PrintType(s, g_ExtraTypes, Z7_ARRAY_SIZE(g_ExtraTypes), id); - - if (id == NExtraID::kTime) - { - const Byte *p = Extra + offset; - UInt64 flags; - const unsigned num = ReadVarInt(p, rem, &flags); - if (num != 0) - { - s.Add_Colon(); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTimeFlags); i++) - if ((flags & ((UInt64)1 << i)) != 0) - s.Add_Char(g_ExtraTimeFlags[i]); - flags &= ~(((UInt64)1 << Z7_ARRAY_SIZE(g_ExtraTimeFlags)) - 1); - if (flags != 0) - { - s.Add_Char('_'); - AddHex64(s, flags); - } - } - } - else if (id == NExtraID::kLink) - { - CLinkInfo linkInfo; - if (linkInfo.Parse(Extra + offset, (unsigned)rem)) - { - s.Add_Colon(); - PrintType(s, g_LinkTypes, Z7_ARRAY_SIZE(g_LinkTypes), linkInfo.Type); - UInt64 flags = linkInfo.Flags; - if (flags != 0) - { - s.Add_Colon(); - if (flags & NLinkFlags::kTargetIsDir) - { - s.Add_Char('D'); - flags &= ~((UInt64)NLinkFlags::kTargetIsDir); - } - if (flags != 0) - { - s.Add_Char('_'); - AddHex64(s, flags); - } - } - } - } - - offset += rem; - } - } - - s.Add_OptSpaced("ERROR"); -} - - -bool CCryptoInfo::Parse(const Byte *p, size_t size) -{ - Algo = 0; - Flags = 0; - Cnt = 0; - PARSE_VAR_INT(p, size, Algo) - PARSE_VAR_INT(p, size, Flags) - if (size > 0) - Cnt = p[0]; - if (size != 1 + 16 + 16 + (unsigned)(IsThereCheck() ? 12 : 0)) - return false; - return true; -} - - -bool CItem::FindExtra_Version(UInt64 &version) const -{ - unsigned size; - const int offset = FindExtra(NExtraID::kVersion, size); - if (offset < 0) - return false; - const Byte *p = Extra + (unsigned)offset; - - UInt64 flags; - PARSE_VAR_INT(p, size, flags) - PARSE_VAR_INT(p, size, version) - return size == 0; -} - -bool CItem::FindExtra_Link(CLinkInfo &link) const -{ - unsigned size; - const int offset = FindExtra(NExtraID::kLink, size); - if (offset < 0) - return false; - if (!link.Parse(Extra + (unsigned)offset, size)) - return false; - link.NameOffset += (unsigned)offset; - return true; -} - -bool CItem::Is_CopyLink() const -{ - CLinkInfo link; - return FindExtra_Link(link) && link.Type == NLinkType::kFileCopy; -} - -bool CItem::Is_HardLink() const -{ - CLinkInfo link; - return FindExtra_Link(link) && link.Type == NLinkType::kHardLink; -} - -bool CItem::Is_CopyLink_or_HardLink() const -{ - CLinkInfo link; - return FindExtra_Link(link) && (link.Type == NLinkType::kFileCopy || link.Type == NLinkType::kHardLink); -} - -void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const -{ - CLinkInfo link; - if (!FindExtra_Link(link)) - return; - - if (link.Type != linkType) - { - if (linkType != NLinkType::kUnixSymLink) - return; - switch ((unsigned)link.Type) - { - case NLinkType::kUnixSymLink: - case NLinkType::kWinSymLink: - case NLinkType::kWinJunction: - break; - default: return; - } - } - - AString s; - s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen); - - UString unicode; - ConvertUTF8ToUnicode(s, unicode); - prop = NItemName::GetOsPath(unicode); -} - -bool CItem::GetAltStreamName(AString &name) const -{ - name.Empty(); - unsigned size; - const int offset = FindExtra(NExtraID::kSubdata, size); - if (offset < 0) - return false; - name.SetFrom_CalcLen((const char *)(Extra + (unsigned)offset), size); - return true; -} - - -class CHash -{ - bool _calcCRC; - UInt32 _crc; - int _blakeOffset; - CAlignedBuffer1 _buf; - // CBlake2sp _blake; - CBlake2sp *BlakeObj() { return (CBlake2sp *)(void *)(Byte *)_buf; } -public: - CHash(): - _buf(sizeof(CBlake2sp)) - {} - - void Init_NoCalc() - { - _calcCRC = false; - _crc = CRC_INIT_VAL; - _blakeOffset = -1; - } - - void Init(const CItem &item); - void Update(const void *data, size_t size); - UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } - - bool Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoder); -}; - -void CHash::Init(const CItem &item) -{ - _crc = CRC_INIT_VAL; - _calcCRC = item.Has_CRC(); - _blakeOffset = item.FindExtra_Blake(); - if (_blakeOffset >= 0) - Blake2sp_Init(BlakeObj()); -} - -void CHash::Update(const void *data, size_t size) -{ - if (_calcCRC) - _crc = CrcUpdate(_crc, data, size); - if (_blakeOffset >= 0) - Blake2sp_Update(BlakeObj(), (const Byte *)data, size); -} - -bool CHash::Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoder) -{ - if (_calcCRC) - { - UInt32 crc = GetCRC(); - if (cryptoDecoder) - crc = cryptoDecoder->Hmac_Convert_Crc32(crc); - if (crc != item.CRC) - return false; - } - if (_blakeOffset >= 0) - { - UInt32 digest[Z7_BLAKE2S_DIGEST_SIZE / sizeof(UInt32)]; - Blake2sp_Final(BlakeObj(), (Byte *)(void *)digest); - if (cryptoDecoder) - cryptoDecoder->Hmac_Convert_32Bytes((Byte *)(void *)digest); - if (memcmp(digest, item.Extra + (unsigned)_blakeOffset, Z7_BLAKE2S_DIGEST_SIZE) != 0) - return false; - } - return true; -} - - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithHash - , ISequentialOutStream -) - bool _size_Defined; - ISequentialOutStream *_stream; - UInt64 _pos; - UInt64 _size; - Byte *_destBuf; -public: - CHash _hash; - - COutStreamWithHash(): _destBuf(NULL) {} - - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void Init(const CItem &item, Byte *destBuf, bool needChecksumCheck) - { - _size_Defined = false; - _size = 0; - _destBuf = NULL; - if (!item.Is_UnknownSize()) - { - _size_Defined = true; - _size = item.Size; - _destBuf = destBuf; - } - _pos = 0; - if (needChecksumCheck) - _hash.Init(item); - else - _hash.Init_NoCalc(); - } - UInt64 GetPos() const { return _pos; } -}; - - -Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_size_Defined) - { - const UInt64 rem = _size - _pos; - if (size > rem) - size = (UInt32)rem; - } - if (_stream) - result = _stream->Write(data, size, &size); - if (_destBuf) - memcpy(_destBuf + (size_t)_pos, data, size); - _hash.Update(data, size); - _pos += size; - if (processedSize) - *processedSize = size; - return result; -} - - - - - -class CInArchive -{ - CAlignedBuffer _buf; - size_t _bufSize; - size_t _bufPos; - ISequentialInStream *_stream; - - CMyComPtr2 m_CryptoDecoder; - - Z7_CLASS_NO_COPY(CInArchive) - - HRESULT ReadStream_Check(void *data, size_t size); - -public: - bool m_CryptoMode; - - bool WrongPassword; - bool IsArc; - bool UnexpectedEnd; - - UInt64 StreamStartPosition; - UInt64 Position; - - size_t Get_Buf_RemainSize() const { return _bufSize - _bufPos; } - bool Is_Buf_Finished() const { return _bufPos == _bufSize; } - const Byte *Get_Buf_Data() const { return _buf + _bufPos; } - void Move_BufPos(size_t num) { _bufPos += num; } - bool ReadVar(UInt64 &val); - - struct CHeader - { - UInt64 Type; - UInt64 Flags; - size_t ExtraSize; - UInt64 DataSize; - }; - - CInArchive() {} - - HRESULT ReadBlockHeader(CHeader &h); - bool ReadFileHeader(const CHeader &header, CItem &item); - void AddToSeekValue(UInt64 addValue) - { - Position += addValue; - } - - HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword, - CInArcInfo &info); -}; - - -static HRESULT MySetPassword(ICryptoGetTextPassword *getTextPassword, NCrypto::NRar5::CDecoder *cryptoDecoder) -{ - CMyComBSTR_Wipe password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)) - AString_Wipe utf8; - const unsigned kPasswordLen_MAX = 127; - UString_Wipe unicode; - unicode.SetFromBstr(password); - if (unicode.Len() > kPasswordLen_MAX) - unicode.DeleteFrom(kPasswordLen_MAX); - ConvertUnicodeToUTF8(unicode, utf8); - cryptoDecoder->SetPassword((const Byte *)(const char *)utf8, utf8.Len()); - return S_OK; -} - - -bool CInArchive::ReadVar(UInt64 &val) -{ - const unsigned offset = ReadVarInt(Get_Buf_Data(), Get_Buf_RemainSize(), &val); - Move_BufPos(offset); - return (offset != 0); -} - - -HRESULT CInArchive::ReadStream_Check(void *data, size_t size) -{ - size_t size2 = size; - RINOK(ReadStream(_stream, data, &size2)) - if (size2 == size) - return S_OK; - UnexpectedEnd = true; - return S_FALSE; -} - - -HRESULT CInArchive::ReadBlockHeader(CHeader &h) -{ - h.Type = 0; - h.Flags = 0; - h.ExtraSize = 0; - h.DataSize = 0; - - Byte buf[AES_BLOCK_SIZE]; - unsigned filled; - - if (m_CryptoMode) - { - _buf.AllocAtLeast(1 << 12); // at least (AES_BLOCK_SIZE * 2) - if (!(Byte *)_buf) - return E_OUTOFMEMORY; - RINOK(ReadStream_Check(_buf, AES_BLOCK_SIZE * 2)) - memcpy(m_CryptoDecoder->_iv, _buf, AES_BLOCK_SIZE); - RINOK(m_CryptoDecoder->Init()) - if (m_CryptoDecoder->Filter(_buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) - return E_FAIL; - memcpy(buf, _buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE); - filled = AES_BLOCK_SIZE; - } - else - { - const unsigned kStartSize = 4 + 3; - RINOK(ReadStream_Check(buf, kStartSize)) - filled = kStartSize; - } - - { - UInt64 val; - unsigned offset = ReadVarInt(buf + 4, 3, &val); - if (offset == 0) - return S_FALSE; - size_t size = (size_t)val; - if (size < 2) - return S_FALSE; - offset += 4; - _bufPos = offset; - size += offset; - _bufSize = size; - if (m_CryptoMode) - size = (size + AES_BLOCK_SIZE - 1) & ~(size_t)(AES_BLOCK_SIZE - 1); - _buf.AllocAtLeast(size); - if (!(Byte *)_buf) - return E_OUTOFMEMORY; - memcpy(_buf, buf, filled); - const size_t rem = size - filled; - AddToSeekValue(size + (m_CryptoMode ? AES_BLOCK_SIZE : 0)); - RINOK(ReadStream_Check(_buf + filled, rem)) - if (m_CryptoMode) - { - if (m_CryptoDecoder->Filter(_buf + filled, (UInt32)rem) != rem) - return E_FAIL; -#if 1 - // optional 7zip-unrar check : remainder must contain zeros. - const size_t pad = size - _bufSize; - const Byte *p = _buf + _bufSize; - for (size_t i = 0; i < pad; i++) - if (p[i]) - return S_FALSE; -#endif - } - } - - if (CrcCalc(_buf + 4, _bufSize - 4) != Get32(buf)) - return S_FALSE; - - if (!ReadVar(h.Type)) return S_FALSE; - if (!ReadVar(h.Flags)) return S_FALSE; - - if (h.Flags & NHeaderFlags::kExtra) - { - UInt64 extraSize; - if (!ReadVar(extraSize)) - return S_FALSE; - if (extraSize >= (1u << 21)) - return S_FALSE; - h.ExtraSize = (size_t)extraSize; - } - - if (h.Flags & NHeaderFlags::kData) - { - if (!ReadVar(h.DataSize)) - return S_FALSE; - } - - if (h.ExtraSize > Get_Buf_RemainSize()) - return S_FALSE; - return S_OK; -} - - -bool CInArcInfo::CLocator::Parse(const Byte *p, size_t size) -{ - Flags = 0; - QuickOpen = 0; - Recovery = 0; - - PARSE_VAR_INT(p, size, Flags) - - if (Is_QuickOpen()) - { - PARSE_VAR_INT(p, size, QuickOpen) - } - if (Is_Recovery()) - { - PARSE_VAR_INT(p, size, Recovery) - } -#if 0 - // another records are possible in future rar formats. - if (size != 0) - return false; -#endif - return true; -} - - -bool CInArcInfo::CMetadata::Parse(const Byte *p, size_t size) -{ - PARSE_VAR_INT(p, size, Flags) - if (Flags & NMetadataFlags::kArcName) - { - UInt64 nameLen; - PARSE_VAR_INT(p, size, nameLen) - if (nameLen > size) - return false; - ArcName.SetFrom_CalcLen((const char *)(const void *)p, (unsigned)nameLen); - p += (size_t)nameLen; - size -= (size_t)nameLen; - } - if (Flags & NMetadataFlags::kCTime) - { - if ((Flags & NMetadataFlags::kUnixTime) && - (Flags & NMetadataFlags::kNanoSec) == 0) - { - if (size < 4) - return false; - CTime = GetUi32(p); - p += 4; - size -= 4; - } - else - { - if (size < 8) - return false; - CTime = GetUi64(p); - p += 8; - size -= 8; - } - } -#if 0 - // another records are possible in future rar formats. - if (size != 0) - return false; -#endif - return true; -} - - -bool CInArcInfo::ParseExtra(const Byte *p, size_t size) -{ - for (;;) - { - if (size == 0) - return true; - UInt64 recSize64, id; - PARSE_VAR_INT(p, size, recSize64) - if (recSize64 > size) - return false; - size_t recSize = (size_t)recSize64; - size -= recSize; - // READ_VAR_INT(p, recSize, recSize) - { - const unsigned num = ReadVarInt(p, recSize, &id); - if (num == 0) - return false; - p += num; - recSize -= num; - } - if (id == kArcExtraRecordType_Metadata) - { - Metadata_Defined = true; - if (!Metadata.Parse(p, recSize)) - Metadata_Error = true; - } - else if (id == kArcExtraRecordType_Locator) - { - Locator_Defined = true; - if (!Locator.Parse(p, recSize)) - Locator_Error = true; - } - else - UnknownExtraRecord = true; - p += recSize; - } -} - - - -HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword, - CInArcInfo &info) -{ - m_CryptoMode = false; - - WrongPassword = false; - IsArc = false; - UnexpectedEnd = false; - - Position = StreamStartPosition; - - UInt64 arcStartPos = StreamStartPosition; - { - Byte marker[kMarkerSize]; - RINOK(ReadStream_FALSE(stream, marker, kMarkerSize)) - if (memcmp(marker, kMarker, kMarkerSize) == 0) - Position += kMarkerSize; - else - { - if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) - return S_FALSE; - RINOK(InStream_SeekSet(stream, StreamStartPosition)) - RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize, - searchHeaderSizeLimit, arcStartPos)) - arcStartPos += StreamStartPosition; - Position = arcStartPos + kMarkerSize; - RINOK(InStream_SeekSet(stream, Position)) - } - } - - info.StartPos = arcStartPos; - _stream = stream; - - CHeader h; - RINOK(ReadBlockHeader(h)) - info.IsEncrypted = false; - - if (h.Type == NHeaderType::kArcEncrypt) - { - info.IsEncrypted = true; - IsArc = true; - if (!getTextPassword) - return E_NOTIMPL; - m_CryptoMode = true; - m_CryptoDecoder.Create_if_Empty(); - RINOK(m_CryptoDecoder->SetDecoderProps( - Get_Buf_Data(), (unsigned)Get_Buf_RemainSize(), false, false)) - RINOK(MySetPassword(getTextPassword, m_CryptoDecoder.ClsPtr())) - if (!m_CryptoDecoder->CalcKey_and_CheckPassword()) - { - WrongPassword = True; - return S_FALSE; - } - RINOK(ReadBlockHeader(h)) - } - - if (h.Type != NHeaderType::kArc) - return S_FALSE; - - IsArc = true; - info.VolNumber = 0; - - if (!ReadVar(info.Flags)) - return S_FALSE; - - if (info.Flags & NArcFlags::kVolNumber) - if (!ReadVar(info.VolNumber)) - return S_FALSE; - - if (h.ExtraSize != Get_Buf_RemainSize()) - return S_FALSE; - if (h.ExtraSize) - { - if (!info.ParseExtra(Get_Buf_Data(), h.ExtraSize)) - info.Extra_Error = true; - } - return S_OK; -} - - -bool CInArchive::ReadFileHeader(const CHeader &header, CItem &item) -{ - item.CommonFlags = (UInt32)header.Flags; - item.PackSize = header.DataSize; - item.UnixMTime = 0; - item.CRC = 0; - - { - UInt64 flags64; - if (!ReadVar(flags64)) return false; - item.Flags = (UInt32)flags64; - } - - if (!ReadVar(item.Size)) return false; - - { - UInt64 attrib; - if (!ReadVar(attrib)) return false; - item.Attrib = (UInt32)attrib; - } - if (item.Has_UnixMTime()) - { - if (Get_Buf_RemainSize() < 4) - return false; - item.UnixMTime = Get32(Get_Buf_Data()); - Move_BufPos(4); - } - if (item.Has_CRC()) - { - if (Get_Buf_RemainSize() < 4) - return false; - item.CRC = Get32(Get_Buf_Data()); - Move_BufPos(4); - } - { - UInt64 method; - if (!ReadVar(method)) return false; - item.Method = (UInt32)method; - } - - if (!ReadVar(item.HostOS)) return false; - - { - UInt64 len; - if (!ReadVar(len)) return false; - if (len > Get_Buf_RemainSize()) - return false; - item.Name.SetFrom_CalcLen((const char *)Get_Buf_Data(), (unsigned)len); - Move_BufPos((size_t)len); - } - - item.Extra.Free(); - const size_t extraSize = header.ExtraSize; - if (extraSize != 0) - { - if (Get_Buf_RemainSize() < extraSize) - return false; - item.Extra.Alloc(extraSize); - memcpy(item.Extra, Get_Buf_Data(), extraSize); - Move_BufPos(extraSize); - } - - return Is_Buf_Finished(); -} - - - -struct CLinkFile -{ - unsigned Index; - unsigned NumLinks; // the number of links to Data - CByteBuffer Data; - HRESULT Res; - bool crcOK; - - CLinkFile(): Index(0), NumLinks(0), Res(S_OK), crcOK(true) {} -}; - - -struct CUnpacker -{ - CMyComPtr2 copyCoder; - CMyComPtr LzCoders[2]; - bool SolidAllowed; - bool NeedCrc; - CFilterCoder *filterStreamSpec; - CMyComPtr filterStream; - CMyComPtr2 cryptoDecoder; - CMyComPtr getTextPassword; - CMyComPtr2 outStream; - - CByteBuffer _tempBuf; - CLinkFile *linkFile; - - CUnpacker(): linkFile(NULL) { SolidAllowed = false; NeedCrc = true; } - - HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS - const CItem &item, bool isSolid, bool &wrongPassword); - - HRESULT Code(const CItem &item, const CItem &lastItem, UInt64 packSize, - ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress, - bool &isCrcOK); - - HRESULT DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS - const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer); -}; - - -static const unsigned kLzMethodMax = 5; - -HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS - const CItem &item, bool isSolid, bool &wrongPassword) -{ - wrongPassword = false; - - if (item.Get_AlgoVersion_RawBits() > 1) - return E_NOTIMPL; - - outStream.Create_if_Empty(); - - const unsigned method = item.Get_Method(); - - if (method == 0) - copyCoder.Create_if_Empty(); - else - { - if (method > kLzMethodMax) - return E_NOTIMPL; - /* - if (item.IsSplitBefore()) - return S_FALSE; - */ - const unsigned lzIndex = item.IsService() ? 1 : 0; - CMyComPtr &lzCoder = LzCoders[lzIndex]; - if (!lzCoder) - { - const UInt32 methodID = 0x40305; - RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodID, false, lzCoder)) - if (!lzCoder) - return E_NOTIMPL; - } - - CMyComPtr csdp; - RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp)) - - const unsigned ver = item.Get_AlgoVersion_HuffRev(); - if (ver > 1) - return E_NOTIMPL; - const Byte props[2] = - { - (Byte)item.Get_DictSize_Main(), - (Byte)((item.Get_DictSize_Frac() << 3) + (ver << 1) + (isSolid ? 1 : 0)) - }; - RINOK(csdp->SetDecoderProperties2(props, 2)) - } - - unsigned cryptoSize = 0; - const int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize); - - if (cryptoOffset >= 0) - { - if (!filterStream) - { - filterStreamSpec = new CFilterCoder(false); - filterStream = filterStreamSpec; - } - - cryptoDecoder.Create_if_Empty(); - - RINOK(cryptoDecoder->SetDecoderProps(item.Extra + (unsigned)cryptoOffset, cryptoSize, true, item.IsService())) - - if (!getTextPassword) - { - wrongPassword = True; - return E_NOTIMPL; - } - - RINOK(MySetPassword(getTextPassword, cryptoDecoder.ClsPtr())) - - if (!cryptoDecoder->CalcKey_and_CheckPassword()) - wrongPassword = True; - } - - return S_OK; -} - - -HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSize, - ISequentialInStream *volsInStream, ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, - bool &isCrcOK) -{ - isCrcOK = true; - - const unsigned method = item.Get_Method(); - if (method > kLzMethodMax) - return E_NOTIMPL; - - const bool needBuf = (linkFile && linkFile->NumLinks != 0); - - if (needBuf && !lastItem.Is_UnknownSize()) - { - const size_t dataSize = (size_t)lastItem.Size; - if (dataSize != lastItem.Size) - return E_NOTIMPL; - linkFile->Data.Alloc(dataSize); - } - - bool isCryptoMode = false; - ISequentialInStream *inStream; - - if (item.IsEncrypted()) - { - filterStreamSpec->Filter = cryptoDecoder; - filterStreamSpec->SetInStream(volsInStream); - filterStreamSpec->SetOutStreamSize(NULL); - inStream = filterStream; - isCryptoMode = true; - } - else - inStream = volsInStream; - - ICompressCoder *commonCoder = (method == 0) ? - copyCoder.Interface() : - LzCoders[item.IsService() ? 1 : 0].Interface(); - - outStream->SetStream(realOutStream); - outStream->Init(lastItem, (needBuf ? (Byte *)linkFile->Data : NULL), NeedCrc); - - HRESULT res = S_OK; - if (packSize != 0 || lastItem.Is_UnknownSize() || lastItem.Size != 0) - { - res = commonCoder->Code(inStream, outStream, &packSize, - lastItem.Is_UnknownSize() ? NULL : &lastItem.Size, progress); - if (!item.IsService()) - SolidAllowed = true; - } - else - { - // res = res; - } - - if (isCryptoMode) - filterStreamSpec->ReleaseInStream(); - - const UInt64 processedSize = outStream->GetPos(); - if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size) - res = S_FALSE; - - // if (res == S_OK) - { - unsigned cryptoSize = 0; - const int cryptoOffset = lastItem.FindExtra(NExtraID::kCrypto, cryptoSize); - NCrypto::NRar5::CDecoder *crypto = NULL; - if (cryptoOffset >= 0) - { - CCryptoInfo cryptoInfo; - if (cryptoInfo.Parse(lastItem.Extra + (unsigned)cryptoOffset, cryptoSize)) - if (cryptoInfo.UseMAC()) - crypto = cryptoDecoder.ClsPtr(); - } - if (NeedCrc) - isCrcOK = outStream->_hash.Check(lastItem, crypto); - } - - if (linkFile) - { - linkFile->Res = res; - linkFile->crcOK = isCrcOK; - if (needBuf - && !lastItem.Is_UnknownSize() - && processedSize != lastItem.Size) - linkFile->Data.ChangeSize_KeepData((size_t)processedSize, (size_t)processedSize); - } - - return res; -} - - -HRESULT CUnpacker::DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS - const CItem &item, UInt64 packSize, - ISequentialInStream *inStream, - CByteBuffer &buffer) -{ - CMyComPtr2_Create out; - _tempBuf.AllocAtLeast((size_t)item.Size); - out->Init(_tempBuf, (size_t)item.Size); - - bool wrongPassword; - - if (item.IsSolid()) - return E_NOTIMPL; - - HRESULT res = Create(EXTERNAL_CODECS_LOC_VARS item, item.IsSolid(), wrongPassword); - - if (res == S_OK) - { - if (wrongPassword) - return S_FALSE; - - CMyComPtr2_Create limitedStream; - limitedStream->SetStream(inStream); - limitedStream->Init(packSize); - - bool crcOK = true; - res = Code(item, item, packSize, limitedStream, out, NULL, crcOK); - if (res == S_OK) - { - if (!crcOK || out->GetPos() != item.Size) - res = S_FALSE; - else - buffer.CopyFrom(_tempBuf, (size_t)item.Size); - } - } - - return res; -} - - -struct CTempBuf -{ - CByteBuffer _buf; - size_t _offset; - bool _isOK; - - void Clear() - { - _offset = 0; - _isOK = true; - } - - CTempBuf() { Clear(); } - - HRESULT Decode(DECL_EXTERNAL_CODECS_LOC_VARS - const CItem &item, - ISequentialInStream *inStream, - CUnpacker &unpacker, - CByteBuffer &destBuf); -}; - - -HRESULT CTempBuf::Decode(DECL_EXTERNAL_CODECS_LOC_VARS - const CItem &item, - ISequentialInStream *inStream, - CUnpacker &unpacker, - CByteBuffer &destBuf) -{ - const size_t kPackSize_Max = (1 << 24); - if (item.Size > (1 << 24) - || item.Size == 0 - || item.PackSize >= kPackSize_Max) - { - Clear(); - return S_OK; - } - - if (item.IsSplit() /* && _isOK */) - { - size_t packSize = (size_t)item.PackSize; - if (packSize > kPackSize_Max - _offset) - return S_OK; - size_t newSize = _offset + packSize; - if (newSize > _buf.Size()) - _buf.ChangeSize_KeepData(newSize, _offset); - - Byte *data = (Byte *)_buf + _offset; - RINOK(ReadStream_FALSE(inStream, data, packSize)) - - _offset += packSize; - - if (item.IsSplitAfter()) - { - CHash hash; - hash.Init(item); - hash.Update(data, packSize); - _isOK = hash.Check(item, NULL); // RAR5 doesn't use HMAC for packed part - } - } - - if (_isOK) - { - if (!item.IsSplitAfter()) - { - if (_offset == 0) - { - RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS - item, item.PackSize, inStream, destBuf)) - } - else - { - CMyComPtr2_Create bufInStream; - bufInStream->Init(_buf, _offset); - RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS - item, _offset, bufInStream, destBuf)) - } - } - } - - return S_OK; -} - - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidAttrib, - // kpidPosixAttrib, // for debug - - kpidIsAltStream, - kpidEncrypted, - kpidSolid, - kpidSplitBefore, - kpidSplitAfter, - kpidCRC, - kpidHostOS, - kpidMethod, - kpidCharacts, - kpidSymLink, - kpidHardLink, - kpidCopyLink, - - kpidVolumeIndex -}; - - -static const Byte kArcProps[] = -{ - kpidTotalPhySize, - kpidCharacts, - kpidEncrypted, - kpidSolid, - kpidNumBlocks, - kpidMethod, - kpidIsVolume, - kpidVolumeIndex, - kpidNumVolumes, - kpidName, - kpidCTime, - kpidComment -}; - - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -UInt64 CHandler::GetPackSize(unsigned refIndex) const -{ - UInt64 size = 0; - unsigned index = _refs[refIndex].Item; - for (;;) - { - const CItem &item = _items[index]; - size += item.PackSize; - if (item.NextItem < 0) - return size; - index = (unsigned)item.NextItem; - } -} - -static char *PrintDictSize(char *s, UInt64 w) -{ - char c = 'K'; w >>= 10; - if ((w & ((1 << 10) - 1)) == 0) { c = 'M'; w >>= 10; - if ((w & ((1 << 10) - 1)) == 0) { c = 'G'; w >>= 10; }} - s = ConvertUInt64ToString(w, s); - *s++ = c; - *s = 0; - return s; -} - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - - NCOM::CPropVariant prop; - - const CInArcInfo *arcInfo = NULL; - if (!_arcs.IsEmpty()) - arcInfo = &_arcs[0].Info; - - switch (propID) - { - case kpidVolumeIndex: if (arcInfo && arcInfo->IsVolume()) prop = arcInfo->GetVolIndex(); break; - case kpidSolid: if (arcInfo) prop = arcInfo->IsSolid(); break; - case kpidCharacts: - { - AString s; - if (arcInfo) - { - s = FlagsToString(k_ArcFlags, Z7_ARRAY_SIZE(k_ArcFlags), (UInt32)arcInfo->Flags); - if (arcInfo->Extra_Error) - s.Add_OptSpaced("Extra-ERROR"); - if (arcInfo->UnsupportedFeature) - s.Add_OptSpaced("unsupported-feature"); - if (arcInfo->Metadata_Defined) - { - s.Add_OptSpaced("Metadata"); - if (arcInfo->Metadata_Error) - s += "-ERROR"; - else - { - if (arcInfo->Metadata.Flags & NMetadataFlags::kArcName) - s.Add_OptSpaced("arc-name"); - if (arcInfo->Metadata.Flags & NMetadataFlags::kCTime) - { - s.Add_OptSpaced("ctime-"); - s += - (arcInfo->Metadata.Flags & NMetadataFlags::kUnixTime) ? - (arcInfo->Metadata.Flags & NMetadataFlags::kNanoSec) ? - "1ns" : "1s" : "win"; - } - } - } - if (arcInfo->Locator_Defined) - { - s.Add_OptSpaced("Locator"); - if (arcInfo->Locator_Error) - s += "-ERROR"; - else - { - if (arcInfo->Locator.Is_QuickOpen()) - { - s.Add_OptSpaced("QuickOpen:"); - s.Add_UInt64(arcInfo->Locator.QuickOpen); - } - if (arcInfo->Locator.Is_Recovery()) - { - s.Add_OptSpaced("Recovery:"); - s.Add_UInt64(arcInfo->Locator.Recovery); - } - } - } - if (arcInfo->UnknownExtraRecord) - s.Add_OptSpaced("Unknown-Extra-Record"); - - } - if (_comment_WasUsedInArc) - { - s.Add_OptSpaced("Comment"); - // s.Add_UInt32((UInt32)_comment.Size()); - } - // - if (_acls.Size() != 0) - { - s.Add_OptSpaced("ACL"); - // s.Add_UInt32(_acls.Size()); - } - if (!s.IsEmpty()) - prop = s; - break; - } - case kpidEncrypted: if (arcInfo) prop = arcInfo->IsEncrypted; break; // it's for encrypted names. - case kpidIsVolume: if (arcInfo) prop = arcInfo->IsVolume(); break; - case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; - case kpidOffset: if (arcInfo && arcInfo->StartPos != 0) prop = arcInfo->StartPos; break; - - case kpidTotalPhySize: - { - if (_arcs.Size() > 1) - { - UInt64 sum = 0; - FOR_VECTOR (v, _arcs) - sum += _arcs[v].Info.GetPhySize(); - prop = sum; - } - break; - } - - case kpidPhySize: - { - if (arcInfo) - prop = arcInfo->GetPhySize(); - break; - } - - case kpidName: - if (arcInfo) - if (!arcInfo->Metadata_Error - && !arcInfo->Metadata.ArcName.IsEmpty()) - { - UString s; - if (ConvertUTF8ToUnicode(arcInfo->Metadata.ArcName, s)) - prop = s; - } - break; - - case kpidCTime: - if (arcInfo) - if (!arcInfo->Metadata_Error - && (arcInfo->Metadata.Flags & NMetadataFlags::kCTime)) - { - const UInt64 ct = arcInfo->Metadata.CTime; - if (arcInfo->Metadata.Flags & NMetadataFlags::kUnixTime) - { - if (arcInfo->Metadata.Flags & NMetadataFlags::kNanoSec) - { - const UInt64 sec = ct / 1000000000; - const UInt64 ns = ct % 1000000000; - UInt64 wt = NTime::UnixTime64_To_FileTime64((Int64)sec); - wt += ns / 100; - const unsigned ns100 = (unsigned)(ns % 100); - FILETIME ft; - ft.dwLowDateTime = (DWORD)(UInt32)wt; - ft.dwHighDateTime = (DWORD)(UInt32)(wt >> 32); - prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); - } - else - { - const UInt64 wt = NTime::UnixTime64_To_FileTime64((Int64)ct); - prop.SetAsTimeFrom_Ft64_Prec(wt, k_PropVar_TimePrec_Unix); - } - } - else - prop.SetAsTimeFrom_Ft64_Prec(ct, k_PropVar_TimePrec_100ns); - } - break; - - case kpidComment: - { - // if (!_arcs.IsEmpty()) - { - // const CArc &arc = _arcs[0]; - const CByteBuffer &cmt = _comment; - if (cmt.Size() != 0 /* && cmt.Size() < (1 << 16) */) - { - AString s; - s.SetFrom_CalcLen((const char *)(const Byte *)cmt, (unsigned)cmt.Size()); - UString unicode; - ConvertUTF8ToUnicode(s, unicode); - prop = unicode; - } - } - break; - } - - case kpidNumBlocks: - { - prop = (UInt32)_numBlocks; - break; - } - - case kpidMethod: - { - AString s; - - UInt64 algo = _algo_Mask; - for (unsigned v = 0; algo != 0; v++, algo >>= 1) - { - if ((algo & 1) == 0) - continue; - s.Add_OptSpaced("v"); - s.Add_UInt32(v + 6); - if (v < Z7_ARRAY_SIZE(_methodMasks)) - { - const UInt64 dict = _dictMaxSizes[v]; - if (dict) - { - char temp[24]; - temp[0] = ':'; - PrintDictSize(temp + 1, dict); - s += temp; - } - unsigned method = _methodMasks[v]; - for (unsigned m = 0; method; m++, method >>= 1) - { - if ((method & 1) == 0) - continue; - s += ":m"; - s.Add_UInt32(m); - } - } - } - if (_rar5comapt_mask & 2) - { - s += ":c"; - if (_rar5comapt_mask & 1) - s.Add_Char('n'); - } - prop = s; - break; - } - - case kpidError: - { - if (/* &_missingVol || */ !_missingVolName.IsEmpty()) - { - UString s ("Missing volume : "); - s += _missingVolName; - prop = s; - } - break; - } - - case kpidErrorFlags: - { - UInt32 v = _errorFlags; - if (!_isArc) - v |= kpv_ErrorFlags_IsNotArc; - if (_error_in_ACL) - v |= kpv_ErrorFlags_HeadersError; - if (_split_Error) - v |= kpv_ErrorFlags_HeadersError; - prop = v; - break; - } - - /* - case kpidWarningFlags: - { - if (_warningFlags != 0) - prop = _warningFlags; - break; - } - */ - - case kpidExtension: - if (_arcs.Size() == 1) - { - if (arcInfo->IsVolume()) - { - AString s ("part"); - UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1; - if (v < 10) - s.Add_Char('0'); - s.Add_UInt32(v); - s += ".rar"; - prop = s; - } - } - break; - - case kpidIsAltStream: prop = true; break; - } - - prop.Detach(value); - return S_OK; - - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = (UInt32)_refs.Size(); - return S_OK; -} - - -static const Byte kRawProps[] = -{ - kpidChecksum, - kpidNtSecure -}; - - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = Z7_ARRAY_SIZE(kRawProps); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) -{ - *propID = kRawProps[index]; - *name = NULL; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - - if (index >= _refs.Size()) - return S_OK; - - const CRefItem &ref = _refs[index]; - const CItem &item = _items[ref.Item]; - - if (item.Is_STM() && ref.Parent >= 0) - { - *parent = (UInt32)ref.Parent; - *parentType = NParentType::kAltStream; - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (index >= _refs.Size()) - return E_INVALIDARG; - - const CItem &item = _items[_refs[index].Item]; - - if (propID == kpidNtSecure) - { - if (item.ACL >= 0) - { - const CByteBuffer &buf = _acls[item.ACL]; - *dataSize = (UInt32)buf.Size(); - *propType = NPropDataType::kRaw; - *data = (const Byte *)buf; - } - return S_OK; - } - - if (propID == kpidChecksum) - { - const int hashRecOffset = item.FindExtra_Blake(); - if (hashRecOffset >= 0) - { - *dataSize = Z7_BLAKE2S_DIGEST_SIZE; - *propType = NPropDataType::kRaw; - *data = item.Extra + (unsigned)hashRecOffset; - } - /* - else if (item.Has_CRC() && item.IsEncrypted()) - { - *dataSize = 4; - *propType = NPropDataType::kRaw; - *data = &item->CRC; // we must show same value for big/little endian here - } - */ - return S_OK; - } - - return S_OK; -} - - -static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop) -{ - unsigned size; - const int offset = item.FindExtra(NExtraID::kTime, size); - if (offset < 0) - return; - - const Byte *p = item.Extra + (unsigned)offset; - UInt64 flags; - // PARSE_VAR_INT(p, size, flags) - { - const unsigned num = ReadVarInt(p, size, &flags); - if (num == 0) - return; - p += num; - size -= num; - } - - if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0) - return; - - unsigned numStamps = 0; - unsigned curStamp = 0; - - for (unsigned i = 0; i < 3; i++) - if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) - { - if (i == stampIndex) - curStamp = numStamps; - numStamps++; - } - - FILETIME ft; - - unsigned timePrec = 0; - unsigned ns100 = 0; - - if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) - { - curStamp *= 4; - if (curStamp + 4 > size) - return; - p += curStamp; - UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p)); - numStamps *= 4; - timePrec = k_PropVar_TimePrec_Unix; - if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) - { - const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF; - if (ns < 1000000000) - { - val += ns / 100; - ns100 = (unsigned)(ns % 100); - timePrec = k_PropVar_TimePrec_1ns; - } - } - ft.dwLowDateTime = (DWORD)val; - ft.dwHighDateTime = (DWORD)(val >> 32); - } - else - { - curStamp *= 8; - if (curStamp + 8 > size) - return; - p += curStamp; - ft.dwLowDateTime = Get32(p); - ft.dwHighDateTime = Get32(p + 4); - } - - prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100); -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - - NCOM::CPropVariant prop; - const CRefItem &ref = _refs[index]; - const CItem &item = _items[ref.Item]; - const CItem &lastItem = _items[ref.Last]; - - switch (propID) - { - case kpidPath: - { - UString unicodeName; - - if (item.Is_STM()) - { - AString s; - if (ref.Parent >= 0) - { - const CItem &mainItem = _items[_refs[ref.Parent].Item]; - s = mainItem.Name; - } - - AString name; - item.GetAltStreamName(name); - if (name[0] != ':') - s.Add_Colon(); - s += name; - ConvertUTF8ToUnicode(s, unicodeName); - } - else - { - ConvertUTF8ToUnicode(item.Name, unicodeName); - - if (item.Version_Defined) - { - char temp[32]; - // temp[0] = ';'; - // ConvertUInt64ToString(item.Version, temp + 1); - // unicodeName += temp; - ConvertUInt64ToString(item.Version, temp); - UString s2 ("[VER]" STRING_PATH_SEPARATOR); - s2 += temp; - s2.Add_PathSepar(); - unicodeName.Insert(0, s2); - } - } - - NItemName::ReplaceToOsSlashes_Remove_TailSlash(unicodeName); - prop = unicodeName; - - break; - } - - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: if (!lastItem.Is_UnknownSize()) prop = lastItem.Size; break; - case kpidPackSize: prop = GetPackSize((unsigned)index); break; - - case kpidMTime: - { - TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop); - if (prop.vt == VT_EMPTY && item.Has_UnixMTime()) - PropVariant_SetFrom_UnixTime(prop, item.UnixMTime); - if (prop.vt == VT_EMPTY && ref.Parent >= 0) - { - const CItem &baseItem = _items[_refs[ref.Parent].Item]; - TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop); - if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime()) - PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime); - } - break; - } - case kpidCTime: TimeRecordToProp(item, NTimeRecord::k_Index_CTime, prop); break; - case kpidATime: TimeRecordToProp(item, NTimeRecord::k_Index_ATime, prop); break; - - case kpidName: - { - if (item.Is_STM()) - { - AString name; - item.GetAltStreamName(name); - if (name[0] == ':') - { - name.DeleteFrontal(1); - UString unicodeName; - ConvertUTF8ToUnicode(name, unicodeName); - prop = unicodeName; - } - } - break; - } - - case kpidIsAltStream: prop = item.Is_STM(); break; - - case kpidSymLink: item.Link_to_Prop(NLinkType::kUnixSymLink, prop); break; - case kpidHardLink: item.Link_to_Prop(NLinkType::kHardLink, prop); break; - case kpidCopyLink: item.Link_to_Prop(NLinkType::kFileCopy, prop); break; - - case kpidAttrib: prop = item.GetWinAttrib(); break; - case kpidPosixAttrib: - if (item.HostOS == kHost_Unix) - prop = (UInt32)item.Attrib; - break; - - case kpidEncrypted: prop = item.IsEncrypted(); break; - case kpidSolid: prop = item.IsSolid(); break; - - case kpidSplitBefore: prop = item.IsSplitBefore(); break; - case kpidSplitAfter: prop = lastItem.IsSplitAfter(); break; - - case kpidVolumeIndex: - { - if (item.VolIndex < _arcs.Size()) - { - const CInArcInfo &arcInfo = _arcs[item.VolIndex].Info; - if (arcInfo.IsVolume()) - prop = (UInt64)arcInfo.GetVolIndex(); - } - break; - } - - case kpidCRC: - { - const CItem *item2 = (lastItem.IsSplitAfter() ? &item : &lastItem); - // we don't want to show crc for encrypted file here, - // because crc is also encrrypted. - if (item2->Has_CRC() && !item2->IsEncrypted()) - prop = item2->CRC; - break; - } - - case kpidMethod: - { - char temp[128]; - const unsigned algo = item.Get_AlgoVersion_RawBits(); - char *s = temp; - // if (algo != 0) - { - *s++ = 'v'; - s = ConvertUInt32ToString((UInt32)algo + 6, s); - if (item.Is_Rar5_Compat()) - *s++ = 'c'; - *s++ = ':'; - } - { - const unsigned m = item.Get_Method(); - *s++ = 'm'; - *s++ = (char)(m + '0'); - if (!item.IsDir()) - { - *s++ = ':'; - const unsigned dictMain = item.Get_DictSize_Main(); - const unsigned frac = item.Get_DictSize_Frac(); - /* - if (frac == 0 && algo == 0) - s = ConvertUInt32ToString(dictMain + 17, s); - else - */ - s = PrintDictSize(s, (UInt64)(32 + frac) << (12 + dictMain)); - if (item.Is_Rar5_Compat()) - { - *s++ = ':'; - *s++ = 'c'; - } - } - } - unsigned cryptoSize = 0; - const int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize); - if (cryptoOffset >= 0) - { - *s++ = ' '; - CCryptoInfo cryptoInfo; - const bool isOK = cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize); - if (cryptoInfo.Algo == 0) - s = MyStpCpy(s, "AES"); - else - { - s = MyStpCpy(s, "Crypto_"); - s = ConvertUInt64ToString(cryptoInfo.Algo, s); - } - if (isOK) - { - *s++ = ':'; - s = ConvertUInt32ToString(cryptoInfo.Cnt, s); - *s++ = ':'; - s = ConvertUInt64ToString(cryptoInfo.Flags, s); - } - } - *s = 0; - prop = temp; - break; - } - - case kpidCharacts: - { - AString s; - - if (item.ACL >= 0) - s.Add_OptSpaced("ACL"); - - const UInt32 flags = item.Flags; - if (flags != 0) - { - const AString s2 = FlagsToString(k_FileFlags, Z7_ARRAY_SIZE(k_FileFlags), flags); - if (!s2.IsEmpty()) - s.Add_OptSpaced(s2); - } - - item.PrintInfo(s); - - if (!s.IsEmpty()) - prop = s; - break; - } - - - case kpidHostOS: - if (item.HostOS < Z7_ARRAY_SIZE(kHostOS)) - prop = kHostOS[(size_t)item.HostOS]; - else - prop = (UInt64)item.HostOS; - break; - } - - prop.Detach(value); - return S_OK; - - COM_TRY_END -} - - - -// ---------- Copy Links ---------- - -static int CompareItemsPaths(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1) -{ - const CItem &item1 = handler._items[handler._refs[p1].Item]; - const CItem &item2 = handler._items[handler._refs[p2].Item]; - - if (item1.Version_Defined) - { - if (!item2.Version_Defined) - return -1; - const int res = MyCompare(item1.Version, item2.Version); - if (res != 0) - return res; - } - else if (item2.Version_Defined) - return 1; - - if (!name1) - name1 = &item1.Name; - return strcmp(*name1, item2.Name); -} - -static int CompareItemsPaths2(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1) -{ - const int res = CompareItemsPaths(handler, p1, p2, name1); - if (res != 0) - return res; - return MyCompare(p1, p2); -} - -static int CompareItemsPaths_Sort(const unsigned *p1, const unsigned *p2, void *param) -{ - return CompareItemsPaths2(*(const CHandler *)param, *p1, *p2, NULL); -} - -static int FindLink(const CHandler &handler, const CUIntVector &sorted, - const AString &s, unsigned index) -{ - unsigned left = 0, right = sorted.Size(); - for (;;) - { - if (left == right) - { - if (left > 0) - { - const unsigned refIndex = sorted[left - 1]; - if (CompareItemsPaths(handler, index, refIndex, &s) == 0) - return (int)refIndex; - } - if (right < sorted.Size()) - { - const unsigned refIndex = sorted[right]; - if (CompareItemsPaths(handler, index, refIndex, &s) == 0) - return (int)refIndex; - } - return -1; - } - - const unsigned mid = (left + right) / 2; - const unsigned refIndex = sorted[mid]; - const int compare = CompareItemsPaths2(handler, index, refIndex, &s); - if (compare == 0) - return (int)refIndex; - if (compare < 0) - right = mid; - else - left = mid + 1; - } -} - -void CHandler::FillLinks() -{ - unsigned i; - - bool need_FillLinks = false; - - for (i = 0; i < _refs.Size(); i++) - { - const CItem &item = _items[_refs[i].Item]; - if (!item.IsDir() - && !item.IsService() - && item.NeedUse_as_CopyLink()) - need_FillLinks = true; - - if (!item.IsSolid()) - _numBlocks++; - - const unsigned algo = item.Get_AlgoVersion_RawBits(); - _algo_Mask |= (UInt64)1 << algo; - _rar5comapt_mask |= 1u << item.Get_Rar5_CompatBit(); - if (!item.IsDir() && algo < Z7_ARRAY_SIZE(_methodMasks)) - { - _methodMasks[algo] |= 1u << (item.Get_Method()); - UInt64 d = 32 + item.Get_DictSize_Frac(); - d <<= (12 + item.Get_DictSize_Main()); - if (_dictMaxSizes[algo] < d) - _dictMaxSizes[algo] = d; - } - } - - if (!need_FillLinks) - return; - - CUIntVector sorted; - for (i = 0; i < _refs.Size(); i++) - { - const CItem &item = _items[_refs[i].Item]; - if (!item.IsDir() && !item.IsService()) - sorted.Add(i); - } - - if (sorted.IsEmpty()) - return; - - sorted.Sort(CompareItemsPaths_Sort, (void *)this); - - AString link; - - for (i = 0; i < _refs.Size(); i++) - { - CRefItem &ref = _refs[i]; - const CItem &item = _items[ref.Item]; - if (item.IsDir() || item.IsService() || item.PackSize != 0) - continue; - CLinkInfo linkInfo; - if (!item.FindExtra_Link(linkInfo) || linkInfo.Type != NLinkType::kFileCopy) - continue; - link.SetFrom_CalcLen((const char *)(item.Extra + linkInfo.NameOffset), linkInfo.NameLen); - const int linkIndex = FindLink(*this, sorted, link, i); - if (linkIndex < 0) - continue; - if ((unsigned)linkIndex >= i) - continue; // we don't support forward links that can lead to loops - const CRefItem &linkRef = _refs[linkIndex]; - const CItem &linkItem = _items[linkRef.Item]; - if (linkItem.Size == item.Size) - { - if (linkRef.Link >= 0) - ref.Link = linkRef.Link; - else if (!linkItem.NeedUse_as_CopyLink()) - ref.Link = linkIndex; - } - } -} - - - -HRESULT CHandler::Open2(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback) -{ - CMyComPtr openVolumeCallback; - // CMyComPtr getTextPassword; - NRar::CVolumeName seqName; - CTempBuf tempBuf; - CUnpacker unpacker; - - if (openCallback) - { - openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword); - } - // unpacker.getTextPassword = getTextPassword; - - CInArchive arch; - int prevSplitFile = -1; - int prevMainFile = -1; - UInt64 totalBytes = 0; - UInt64 curBytes = 0; - bool nextVol_is_Required = false; - - for (;;) - { - CMyComPtr inStream; - - if (_arcs.IsEmpty()) - inStream = stream; - else - { - if (!openVolumeCallback) - break; - if (_arcs.Size() == 1) - { - UString baseName; - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) - if (prop.vt != VT_BSTR) - break; - baseName = prop.bstrVal; - } - if (!seqName.InitName(baseName)) - break; - } - const UString volName = seqName.GetNextName(); - const HRESULT result = openVolumeCallback->GetStream(volName, &inStream); - if (result != S_OK && result != S_FALSE) - return result; - if (!inStream || result != S_OK) - { - if (nextVol_is_Required) - _missingVolName = volName; - break; - } - } - - UInt64 endPos = 0; - RINOK(InStream_GetPos_GetSize(inStream, arch.StreamStartPosition, endPos)) - - if (openCallback) - { - totalBytes += endPos; - RINOK(openCallback->SetTotal(NULL, &totalBytes)) - } - - CInArcInfo arcInfo_Open; - { - const HRESULT res = arch.Open(inStream, maxCheckStartPosition, unpacker.getTextPassword, arcInfo_Open); - if (arch.IsArc && arch.UnexpectedEnd) - _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; - if (_arcs.IsEmpty()) - _isArc = arch.IsArc; - if (res != S_OK) - { - if (res != S_FALSE) - return res; - if (_arcs.IsEmpty()) - return res; - break; - } - } - - CArc &arc = _arcs.AddNew(); - CInArcInfo &arcInfo = arc.Info; - arcInfo = arcInfo_Open; - arc.Stream = inStream; - - CItem item; - - for (;;) - { - item.Clear(); - - arcInfo.EndPos = arch.Position; - if (arch.Position > endPos) - { - _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; - break; - } - RINOK(InStream_SeekSet(inStream, arch.Position)) - - { - CInArchive::CHeader h; - const HRESULT res = arch.ReadBlockHeader(h); - if (res != S_OK) - { - if (res != S_FALSE) - return res; - if (arch.UnexpectedEnd) - { - _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; - if (arcInfo.EndPos < arch.Position) - arcInfo.EndPos = arch.Position; - if (arcInfo.EndPos < endPos) - arcInfo.EndPos = endPos; - } - else - _errorFlags |= kpv_ErrorFlags_HeadersError; - break; - } - - if (h.Type == NHeaderType::kEndOfArc) - { - arcInfo.EndPos = arch.Position; - arcInfo.EndOfArchive_was_Read = true; - if (!arch.ReadVar(arcInfo.EndFlags)) - _errorFlags |= kpv_ErrorFlags_HeadersError; - if (!arch.Is_Buf_Finished() || h.ExtraSize || h.DataSize) - arcInfo.UnsupportedFeature = true; - if (arcInfo.IsVolume()) - { - // for multivolume archives RAR can add ZERO bytes at the end for alignment. - // We must skip these bytes to prevent phySize warning. - RINOK(InStream_SeekSet(inStream, arcInfo.EndPos)) - bool areThereNonZeros; - UInt64 numZeros; - const UInt64 maxSize = 1 << 12; - RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize)) - if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize) - arcInfo.EndPos += numZeros; - } - break; - } - - if (h.Type != NHeaderType::kFile && - h.Type != NHeaderType::kService) - { - _errorFlags |= kpv_ErrorFlags_UnsupportedFeature; - break; - } - - item.RecordType = (Byte)h.Type; - if (!arch.ReadFileHeader(h, item)) - { - _errorFlags |= kpv_ErrorFlags_HeadersError; - break; - } - item.DataPos = arch.Position; - } - - bool isOk_packSize = true; - { - arcInfo.EndPos = arch.Position; - if (arch.Position + item.PackSize < arch.Position) - { - isOk_packSize = false; - _errorFlags |= kpv_ErrorFlags_HeadersError; - if (arcInfo.EndPos < endPos) - arcInfo.EndPos = endPos; - } - else - { - arch.AddToSeekValue(item.PackSize); // Position points to next header; - arcInfo.EndPos = arch.Position; - } - } - - bool needAdd = true; - - if (!_comment_WasUsedInArc - && _comment.Size() == 0 - && item.Is_CMT()) - { - _comment_WasUsedInArc = true; - if ( item.PackSize <= kCommentSize_Max - && item.PackSize == item.Size - && item.PackSize != 0 - && item.Get_Method() == 0 - && !item.IsSplit()) - { - RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_VARS item, item.PackSize, inStream, _comment)) - needAdd = false; - // item.RecordType = (Byte)NHeaderType::kFile; // for debug - } - } - - CRefItem ref; - ref.Item = _items.Size(); - ref.Last = ref.Item; - ref.Parent = -1; - ref.Link = -1; - - if (needAdd) - { - if (item.IsService()) - { - if (item.Is_STM()) - { - if (prevMainFile >= 0) - ref.Parent = prevMainFile; - } - else - { - needAdd = false; - if (item.Is_ACL()) - { - _acl_Used = true; - if (item.IsEncrypted() && !arch.m_CryptoMode) - _error_in_ACL = true; - else if (item.IsSolid() - || prevMainFile < 0 - || item.Size >= (1 << 24) - || item.Size == 0) - _error_in_ACL = true; - if (prevMainFile >= 0 && item.Size < (1 << 24) && item.Size != 0) - { - CItem &mainItem = _items[_refs[prevMainFile].Item]; - - if (mainItem.ACL < 0) - { - CByteBuffer acl; - const HRESULT res = tempBuf.Decode(EXTERNAL_CODECS_VARS item, inStream, unpacker, acl); - if (!item.IsSplitAfter()) - tempBuf.Clear(); - if (res != S_OK) - { - tempBuf.Clear(); - if (res != S_FALSE && res != E_NOTIMPL) - return res; - _error_in_ACL = true; - } - else if (acl.Size() != 0) - { - if (_acls.IsEmpty() || acl != _acls.Back()) - _acls.Add(acl); - mainItem.ACL = (int)_acls.Size() - 1; - } - } - } - } - } - } // item.IsService() - - if (needAdd) - { - if (item.IsSplitBefore()) - { - if (prevSplitFile >= 0) - { - CRefItem &ref2 = _refs[prevSplitFile]; - CItem &prevItem = _items[ref2.Last]; - if (item.IsNextForItem(prevItem)) - { - ref2.Last = _items.Size(); - prevItem.NextItem = (int)ref2.Last; - needAdd = false; - } - } - else - _split_Error = true; - } - } - - if (needAdd) - { - if (item.IsSplitAfter()) - prevSplitFile = (int)_refs.Size(); - if (!item.IsService()) - prevMainFile = (int)_refs.Size(); - } - } - - { - UInt64 version; - if (item.FindExtra_Version(version)) - { - item.Version_Defined = true; - item.Version = version; - } - } - - item.VolIndex = _arcs.Size() - 1; - _items.Add(item); - if (needAdd) - _refs.Add(ref); - - if (openCallback && (_items.Size() & 0xFF) == 0) - { - const UInt64 numFiles = _refs.Size(); // _items.Size() - const UInt64 numBytes = curBytes + item.DataPos; - RINOK(openCallback->SetCompleted(&numFiles, &numBytes)) - } - - if (!isOk_packSize) - break; - } - - curBytes += endPos; - - nextVol_is_Required = false; - - if (!arcInfo.IsVolume()) - break; - - if (arcInfo.EndOfArchive_was_Read) - { - if (!arcInfo.AreMoreVolumes()) - break; - nextVol_is_Required = true; - } - } - - FillLinks(); - return S_OK; -} - - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback)) -{ - COM_TRY_BEGIN - Close(); - return Open2(stream, maxCheckStartPosition, openCallback); - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - COM_TRY_BEGIN - _missingVolName.Empty(); - _errorFlags = 0; - // _warningFlags = 0; - _isArc = false; - _comment_WasUsedInArc = false; - _acl_Used = false; - _error_in_ACL = false; - _split_Error = false; - _numBlocks = 0; - _rar5comapt_mask = 0; - _algo_Mask = 0; // (UInt64)0u - 1; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(_methodMasks); i++) - { - _methodMasks[i] = 0; - _dictMaxSizes[i] = 0; - } - - _refs.Clear(); - _items.Clear(); - _arcs.Clear(); - _acls.Clear(); - _comment.Free(); - return S_OK; - COM_TRY_END -} - - -Z7_CLASS_IMP_NOQIB_1( - CVolsInStream - , ISequentialInStream -) - UInt64 _rem; - ISequentialInStream *_stream; - const CObjectVector *_arcs; - const CObjectVector *_items; - int _itemIndex; -public: - bool CrcIsOK; -private: - CHash _hash; -public: - void Init(const CObjectVector *arcs, - const CObjectVector *items, - unsigned itemIndex) - { - _arcs = arcs; - _items = items; - _itemIndex = (int)itemIndex; - _stream = NULL; - CrcIsOK = true; - } -}; - -Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - UInt32 realProcessedSize = 0; - - while (size != 0) - { - if (!_stream) - { - if (_itemIndex < 0) - break; - const CItem &item = (*_items)[_itemIndex]; - IInStream *s = (*_arcs)[item.VolIndex].Stream; - RINOK(InStream_SeekSet(s, item.GetDataPosition())) - _stream = s; - if (CrcIsOK && item.IsSplitAfter()) - _hash.Init(item); - else - _hash.Init_NoCalc(); - _rem = item.PackSize; - } - { - UInt32 cur = size; - if (cur > _rem) - cur = (UInt32)_rem; - const UInt32 num = cur; - HRESULT res = _stream->Read(data, cur, &cur); - _hash.Update(data, cur); - realProcessedSize += cur; - if (processedSize) - *processedSize = realProcessedSize; - data = (Byte *)data + cur; - size -= cur; - _rem -= cur; - if (_rem == 0) - { - const CItem &item = (*_items)[_itemIndex]; - _itemIndex = item.NextItem; - if (!_hash.Check(item, NULL)) // RAR doesn't use MAC here - CrcIsOK = false; - _stream = NULL; - } - if (res != S_OK) - return res; - if (realProcessedSize != 0) - return S_OK; - if (cur == 0 && num != 0) - return S_OK; - } - } - - return S_OK; -} - - -static int FindLinkBuf(CObjectVector &linkFiles, unsigned index) -{ - unsigned left = 0, right = linkFiles.Size(); - for (;;) - { - if (left == right) - return -1; - const unsigned mid = (left + right) / 2; - const unsigned linkIndex = linkFiles[mid].Index; - if (index == linkIndex) - return (int)mid; - if (index < linkIndex) - right = mid; - else - left = mid + 1; - } -} - - -static inline int DecoderRes_to_OpRes(HRESULT res, bool crcOK) -{ - if (res == E_NOTIMPL) - return NExtract::NOperationResult::kUnsupportedMethod; - // if (res == S_FALSE) - if (res != S_OK) - return NExtract::NOperationResult::kDataError; - return crcOK ? - NExtract::NOperationResult::kOK : - NExtract::NOperationResult::kCRCError; -} - - -static HRESULT CopyData_with_Progress(const Byte *data, size_t size, - ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - UInt64 pos64 = 0; - while (size) - { - const UInt32 kStepSize = (UInt32)1 << 24; - UInt32 cur = kStepSize; - if (cur > size) - cur = (UInt32)size; - RINOK(outStream->Write(data, cur, &cur)) - if (cur == 0) - return E_FAIL; - size -= cur; - data += cur; - pos64 += cur; - if (progress) - { - RINOK(progress->SetRatioInfo(&pos64, &pos64)) - } - } - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = (UInt32)_refs.Size(); - if (numItems == 0) - return S_OK; - - CByteArr extractStatuses(_refs.Size()); - memset(extractStatuses, 0, _refs.Size()); - - // we don't want to use temp buffer for big link files. - const size_t k_CopyLinkFile_MaxSize = (size_t)1 << (28 + sizeof(size_t) / 2); - - const Byte kStatus_Extract = 1 << 0; - const Byte kStatus_Skip = 1 << 1; - const Byte kStatus_Link = 1 << 2; - - /* - In original RAR: - 1) service streams are not allowed to be solid, - and solid flag must be ignored for service streams. - 2) If RAR creates new solid block and first file in solid block is Link file, - then it can clear solid flag for Link file and - clear solid flag for first non-Link file after Link file. - */ - - CObjectVector linkFiles; - - { - UInt64 total = 0; - bool isThereUndefinedSize = false; - bool thereAreLinks = false; - { - unsigned solidLimit = 0; - for (UInt32 t = 0; t < numItems; t++) - { - const unsigned index = (unsigned)(allFilesMode ? t : indices[t]); - const CRefItem &ref = _refs[index]; - const CItem &item = _items[ref.Item]; - const CItem &lastItem = _items[ref.Last]; - - extractStatuses[index] |= kStatus_Extract; - - if (!lastItem.Is_UnknownSize()) - total += lastItem.Size; - else - isThereUndefinedSize = true; - - if (ref.Link >= 0) - { - // 18.06 fixed: we use links for Test mode too - // if (!testMode) - { - if ((unsigned)ref.Link < index) - { - const CRefItem &linkRef = _refs[(unsigned)ref.Link]; - const CItem &linkItem = _items[linkRef.Item]; - if (linkItem.IsSolid()) - if (testMode || linkItem.Size <= k_CopyLinkFile_MaxSize) - { - if (extractStatuses[(unsigned)ref.Link] == 0) - { - const CItem &lastLinkItem = _items[linkRef.Last]; - if (!lastLinkItem.Is_UnknownSize()) - total += lastLinkItem.Size; - else - isThereUndefinedSize = true; - } - extractStatuses[(unsigned)ref.Link] |= kStatus_Link; - thereAreLinks = true; - } - } - } - continue; - } - - if (item.IsService()) - continue; - - if (item.IsSolid()) - { - unsigned j = index; - - while (j > solidLimit) - { - j--; - const CRefItem &ref2 = _refs[j]; - const CItem &item2 = _items[ref2.Item]; - if (!item2.IsService()) - { - if (extractStatuses[j] == 0) - { - const CItem &lastItem2 = _items[ref2.Last]; - if (!lastItem2.Is_UnknownSize()) - total += lastItem2.Size; - else - isThereUndefinedSize = true; - } - extractStatuses[j] |= kStatus_Skip; - if (!item2.IsSolid()) - break; - } - } - } - - solidLimit = index + 1; - } - } - - if (thereAreLinks) - { - unsigned solidLimit = 0; - - FOR_VECTOR (i, _refs) - { - if ((extractStatuses[i] & kStatus_Link) == 0) - continue; - - // We use CLinkFile for testMode too. - // So we can show errors for copy files. - // if (!testMode) - { - CLinkFile &linkFile = linkFiles.AddNew(); - linkFile.Index = i; - } - - const CItem &item = _items[_refs[i].Item]; - /* - if (item.IsService()) - continue; - */ - - if (item.IsSolid()) - { - unsigned j = i; - - while (j > solidLimit) - { - j--; - const CRefItem &ref2 = _refs[j]; - const CItem &item2 = _items[ref2.Item]; - if (!item2.IsService()) - { - if (extractStatuses[j] != 0) - break; - extractStatuses[j] = kStatus_Skip; - { - const CItem &lastItem2 = _items[ref2.Last]; - if (!lastItem2.Is_UnknownSize()) - total += lastItem2.Size; - else - isThereUndefinedSize = true; - } - if (!item2.IsSolid()) - break; - } - } - } - - solidLimit = i + 1; - } - - if (!testMode) - for (UInt32 t = 0; t < numItems; t++) - { - const unsigned index = (unsigned)(allFilesMode ? t : indices[t]); - const CRefItem &ref = _refs[index]; - - const int linkIndex = ref.Link; - if (linkIndex < 0 || (unsigned)linkIndex >= index) - continue; - const CItem &linkItem = _items[_refs[(unsigned)linkIndex].Item]; - if (!linkItem.IsSolid() || linkItem.Size > k_CopyLinkFile_MaxSize) - continue; - const int bufIndex = FindLinkBuf(linkFiles, (unsigned)linkIndex); - if (bufIndex < 0) - return E_FAIL; - linkFiles[bufIndex].NumLinks++; - } - } - - if (total != 0 || !isThereUndefinedSize) - { - RINOK(extractCallback->SetTotal(total)) - } - } - - - - // ---------- MEMORY REQUEST ---------- - { - UInt64 dictMaxSize = 0; - for (UInt32 i = 0; i < _refs.Size(); i++) - { - if (extractStatuses[i] == 0) - continue; - const CRefItem &ref = _refs[i]; - const CItem &item = _items[ref.Item]; -/* - if (!item.IsDir() && !item.IsService() && item.NeedUse_as_CopyLink()) - { - } -*/ - const unsigned algo = item.Get_AlgoVersion_RawBits(); - if (!item.IsDir() && algo < Z7_ARRAY_SIZE(_methodMasks)) - { - const UInt64 d = item.Get_DictSize64(); - if (dictMaxSize < d) - dictMaxSize = d; - } - } - // we use callback, if dict exceeds (1 GB), because - // client code can set low limit (1 GB) for allowed memory usage. - const UInt64 k_MemLimit_for_Callback = (UInt64)1 << 30; - if (dictMaxSize > (_memUsage_WasSet ? - _memUsage_Decompress : k_MemLimit_for_Callback)) - { - { - CMyComPtr requestMem; - extractCallback->QueryInterface(IID_IArchiveRequestMemoryUseCallback, (void **)&requestMem); - if (!requestMem) - { - if (_memUsage_WasSet) - return E_OUTOFMEMORY; - } - else - { - UInt64 allowedSize = _memUsage_WasSet ? - _memUsage_Decompress : - (UInt64)1 << 32; // 4 GB is default allowed limit for RAR7 - - const UInt32 flags = (_memUsage_WasSet ? - NRequestMemoryUseFlags::k_AllowedSize_WasForced | - NRequestMemoryUseFlags::k_MLimit_Exceeded : - (dictMaxSize > allowedSize) ? - NRequestMemoryUseFlags::k_DefaultLimit_Exceeded: - 0) - | NRequestMemoryUseFlags::k_SkipArc_IsExpected - // | NRequestMemoryUseFlags::k_NoErrorMessage // for debug - ; - - // we set "Allow" for default case, if requestMem doesn't process anything. - UInt32 answerFlags = - (_memUsage_WasSet && dictMaxSize > allowedSize) ? - NRequestMemoryAnswerFlags::k_Limit_Exceeded - | NRequestMemoryAnswerFlags::k_SkipArc - : NRequestMemoryAnswerFlags::k_Allow; - - RINOK(requestMem->RequestMemoryUse( - flags, - NEventIndexType::kNoIndex, - // NEventIndexType::kInArcIndex, // for debug - 0, // index - NULL, // path - dictMaxSize, &allowedSize, &answerFlags)) - if ( (answerFlags & NRequestMemoryAnswerFlags::k_Allow) == 0 - || (answerFlags & NRequestMemoryAnswerFlags::k_Stop) - || (answerFlags & NRequestMemoryAnswerFlags::k_SkipArc) - ) - { - return E_OUTOFMEMORY; - } -/* - if ((answerFlags & NRequestMemoryAnswerFlags::k_AskForBigFile) == 0 && - (answerFlags & NRequestMemoryAnswerFlags::k_ReportForBigFile) == 0) - { - // requestMem.Release(); - } -*/ - } - } - } - } - - - - // ---------- UNPACK ---------- - - UInt64 totalUnpacked = 0; - UInt64 totalPacked = 0; - UInt64 curUnpackSize; - UInt64 curPackSize; - - CUnpacker unpacker; - unpacker.NeedCrc = _needChecksumCheck; - CMyComPtr2_Create volsInStream; - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - -/* - bool prevSolidWasSkipped = false; - UInt64 solidDictSize_Skip = 0; -*/ - - for (unsigned i = 0;; i++, - totalUnpacked += curUnpackSize, - totalPacked += curPackSize) - { - lps->InSize = totalPacked; - lps->OutSize = totalUnpacked; - RINOK(lps->SetCur()) - { - const unsigned num = _refs.Size(); - if (i >= num) - break; - for (;;) - { - if (extractStatuses[i] != 0) - break; - i++; - if (i >= num) - break; - } - if (i >= num) - break; - } - curUnpackSize = 0; - curPackSize = 0; - - // isExtract means that we don't skip that item. So we need read data. - const bool isExtract = ((extractStatuses[i] & kStatus_Extract) != 0); - Int32 askMode = - isExtract ? (testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract) : - NExtract::NAskMode::kSkip; - - unpacker.linkFile = NULL; - - // if (!testMode) - if ((extractStatuses[i] & kStatus_Link) != 0) - { - const int bufIndex = FindLinkBuf(linkFiles, i); - if (bufIndex < 0) - return E_FAIL; - unpacker.linkFile = &linkFiles[bufIndex]; - } - - const unsigned index = i; - const CRefItem *ref = &_refs[index]; - const CItem *item = &_items[ref->Item]; - const CItem &lastItem = _items[ref->Last]; - - curUnpackSize = 0; - if (!lastItem.Is_UnknownSize()) - curUnpackSize = lastItem.Size; - - curPackSize = GetPackSize(index); - - bool isSolid = false; - if (!item->IsService()) - { - if (item->IsSolid()) - isSolid = unpacker.SolidAllowed; - unpacker.SolidAllowed = isSolid; - } - - - // ----- request mem ----- -/* - // link files are complicated cases. (ref->Link >= 0) - // link file can refer to non-solid file that can have big dictionary - // link file can refer to solid files that requres buffer - if (!item->IsDir() && requestMem && ref->Link < 0) - { - bool needSkip = false; - if (isSolid) - needSkip = prevSolidWasSkipped; - else - { - // isSolid == false - const unsigned algo = item->Get_AlgoVersion_RawBits(); - // const unsigned m = item.Get_Method(); - if (algo < Z7_ARRAY_SIZE(_methodMasks)) - { - solidDictSize_Skip = item->Get_DictSize64(); - if (solidDictSize_Skip > allowedSize) - needSkip = true; - } - } - if (needSkip) - { - UInt32 answerFlags = 0; - UInt64 allowedSize_File = allowedSize; - RINOK(requestMem->RequestMemoryUse( - NRequestMemoryUseFlags::k_Limit_Exceeded | - NRequestMemoryUseFlags::k_IsReport, - NEventIndexType::kInArcIndex, - index, - NULL, // path - solidDictSize_Skip, &allowedSize_File, &answerFlags)) - if (!item->IsService()) - prevSolidWasSkipped = true; - continue; - } - } - if (!item->IsService() && item->IsDir()) - prevSolidWasSkipped = false; -*/ - - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream((UInt32)index, &realOutStream, askMode)) - - if (item->IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const int index2 = ref->Link; - - int bufIndex = -1; - - if (index2 >= 0) - { - const CRefItem &ref2 = _refs[index2]; - const CItem &item2 = _items[ref2.Item]; - const CItem &lastItem2 = _items[ref2.Last]; - if (!item2.IsSolid()) - { - item = &item2; - ref = &ref2; - if (!lastItem2.Is_UnknownSize()) - curUnpackSize = lastItem2.Size; - else - curUnpackSize = 0; - curPackSize = GetPackSize((unsigned)index2); - } - else - { - if ((unsigned)index2 < index) - bufIndex = FindLinkBuf(linkFiles, (unsigned)index2); - } - } - - bool needCallback = true; - - if (!realOutStream) - { - if (testMode) - { - if (item->NeedUse_as_CopyLink_or_HardLink()) - { - Int32 opRes = NExtract::NOperationResult::kOK; - if (bufIndex >= 0) - { - const CLinkFile &linkFile = linkFiles[bufIndex]; - opRes = DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK); - } - - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(opRes)) - continue; - } - } - else - { - if (item->IsService()) - continue; - - needCallback = false; - - if (!item->NeedUse_as_HardLink()) - if (index2 < 0) - - for (unsigned n = i + 1; n < _refs.Size(); n++) - { - const CItem &nextItem = _items[_refs[n].Item]; - if (nextItem.IsService()) - continue; - if (!nextItem.IsSolid()) - break; - if (extractStatuses[i] != 0) - { - needCallback = true; - break; - } - } - - askMode = NExtract::NAskMode::kSkip; - } - } - - if (needCallback) - { - RINOK(extractCallback->PrepareOperation(askMode)) - } - - if (bufIndex >= 0) - { - CLinkFile &linkFile = linkFiles[bufIndex]; - - if (isExtract) - { - if (linkFile.NumLinks == 0) - return E_FAIL; - - if (needCallback) - if (realOutStream) - { - RINOK(CopyData_with_Progress(linkFile.Data, linkFile.Data.Size(), realOutStream, lps)) - } - - if (--linkFile.NumLinks == 0) - linkFile.Data.Free(); - } - - if (needCallback) - { - RINOK(extractCallback->SetOperationResult(DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK))) - } - continue; - } - - if (!needCallback) - continue; - - if (item->NeedUse_as_CopyLink()) - { - const int opRes = realOutStream ? - NExtract::NOperationResult::kUnsupportedMethod: - NExtract::NOperationResult::kOK; - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)) - continue; - } - - volsInStream->Init(&_arcs, &_items, ref->Item); - - const UInt64 packSize = curPackSize; - - if (item->IsEncrypted()) - if (!unpacker.getTextPassword) - extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword); - - bool wrongPassword; - HRESULT result = unpacker.Create(EXTERNAL_CODECS_VARS *item, isSolid, wrongPassword); - - if (wrongPassword) - { - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kWrongPassword)) - continue; - } - - bool crcOK = true; - if (result == S_OK) - result = unpacker.Code(*item, _items[ref->Last], packSize, volsInStream, realOutStream, lps, crcOK); - realOutStream.Release(); - if (!volsInStream->CrcIsOK) - crcOK = false; - - int opRes = crcOK ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kCRCError; - - if (result != S_OK) - { - if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (result == E_NOTIMPL) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - return result; - } - - RINOK(extractCallback->SetOperationResult(opRes)) - } - - { - FOR_VECTOR (k, linkFiles) - if (linkFiles[k].NumLinks != 0) - return E_FAIL; - } - - return S_OK; - COM_TRY_END -} - - -CHandler::CHandler() -{ - InitDefaults(); -} - -void CHandler::InitDefaults() -{ - _needChecksumCheck = true; - _memUsage_WasSet = false; - _memUsage_Decompress = (UInt64)1 << 32; -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - InitDefaults(); - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - const PROPVARIANT &prop = values[i]; - - if (name.IsPrefixedBy_Ascii_NoCase("mt")) - { - } - else if (name.IsPrefixedBy_Ascii_NoCase("memx")) - { - UInt64 memAvail; - if (!NWindows::NSystem::GetRamSize(memAvail)) - memAvail = (UInt64)(sizeof(size_t)) << 28; - UInt64 v; - if (!ParseSizeString(name.Ptr(4), prop, memAvail, v)) - return E_INVALIDARG; - _memUsage_Decompress = v; - _memUsage_WasSet = true; - } - else if (name.IsPrefixedBy_Ascii_NoCase("crc")) - { - name.Delete(0, 3); - UInt32 crcSize = 1; - RINOK(ParsePropToUInt32(name, prop, crcSize)) - _needChecksumCheck = (crcSize != 0); - } - else - { - return E_INVALIDARG; - } - } - return S_OK; -} - - -IMPL_ISetCompressCodecsInfo - -REGISTER_ARC_I( - "Rar5", "rar r00", NULL, 0xCC, - kMarker, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -}} - - -Z7_CLASS_IMP_COM_2( - CBlake2spHasher - , IHasher - , ICompressSetCoderProperties -) - CAlignedBuffer1 _buf; - // CBlake2sp _blake; - #define Z7_BLACK2S_ALIGN_OBJECT_OFFSET 0 - CBlake2sp *Obj() { return (CBlake2sp *)(void *)((Byte *)_buf + Z7_BLACK2S_ALIGN_OBJECT_OFFSET); } -public: - Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field - CBlake2spHasher(): - _buf(sizeof(CBlake2sp) + Z7_BLACK2S_ALIGN_OBJECT_OFFSET) - { - Blake2sp_SetFunction(Obj(), 0); - Blake2sp_InitState(Obj()); - } -}; - -Z7_COM7F_IMF2(void, CBlake2spHasher::Init()) -{ - Blake2sp_InitState(Obj()); -} - -Z7_COM7F_IMF2(void, CBlake2spHasher::Update(const void *data, UInt32 size)) -{ -#if 1 - Blake2sp_Update(Obj(), (const Byte *)data, (size_t)size); -#else - // for debug: - for (;;) - { - if (size == 0) - return; - UInt32 size2 = (size * 0x85EBCA87) % size / 800; - // UInt32 size2 = size / 2; - if (size2 == 0) - size2 = 1; - Blake2sp_Update(Obj(), (const Byte *)data, size2); - data = (const void *)((const Byte *)data + size2); - size -= size2; - } -#endif -} - -Z7_COM7F_IMF2(void, CBlake2spHasher::Final(Byte *digest)) -{ - Blake2sp_Final(Obj(), digest); -} - -Z7_COM7F_IMF(CBlake2spHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - unsigned algo = 0; - for (UInt32 i = 0; i < numProps; i++) - { - if (propIDs[i] == NCoderPropID::kDefaultProp) - { - const PROPVARIANT &prop = coderProps[i]; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - /* - if (prop.ulVal > Z7_BLAKE2S_ALGO_MAX) - return E_NOTIMPL; - */ - algo = (unsigned)prop.ulVal; - } - } - if (!Blake2sp_SetFunction(Obj(), algo)) - return E_NOTIMPL; - return S_OK; -} - -REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", Z7_BLAKE2S_DIGEST_SIZE) - -static struct CBlake2sp_Prepare { CBlake2sp_Prepare() { z7_Black2sp_Prepare(); } } g_Blake2sp_Prepare; +// Rar5Handler.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariantUtils.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../IPassword.h" + +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/MethodProps.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Common/RegisterCodec.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Crypto/Rar5Aes.h" + +#include "../../Archive/Common/FindSignature.h" +#include "../../Archive/Common/ItemNameUtils.h" +#include "../../Archive/Common/HandlerOut.h" + +#include "../../Archive/HandlerCont.h" + +#include "../../Archive/Rar/RarVol.h" +#include "Rar5Handler.h" + +using namespace NWindows; + +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NRar5 { + +static const unsigned kMarkerSize = 8; + +static const Byte kMarker[kMarkerSize] = + { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 }; + +// Comment length is limited to 256 KB in rar-encoder. +// So we use same limitation +static const size_t kCommentSize_Max = (size_t)1 << 18; + + +static const char * const kHostOS[] = +{ + "Windows" + , "Unix" +}; + + +static const char * const k_ArcFlags[] = +{ + "Volume" + , "VolumeField" + , "Solid" + , "Recovery" + , "Lock" // 4 +}; + + +static const char * const k_FileFlags[] = +{ + "Dir" + , "UnixTime" + , "CRC" + , "UnknownSize" +}; + + +static const char * const g_ExtraTypes[] = +{ + "0" + , "Crypto" + , "Hash" + , "Time" + , "Version" + , "Link" + , "UnixOwner" + , "Subdata" +}; + + +static const char * const g_LinkTypes[] = +{ + "0" + , "UnixSymLink" + , "WinSymLink" + , "WinJunction" + , "HardLink" + , "FileCopy" +}; + + +static const char g_ExtraTimeFlags[] = { 'u', 'M', 'C', 'A', 'n' }; + + +static +Z7_NO_INLINE +unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val_ptr) +{ + if (maxSize > 10) + maxSize = 10; + UInt64 val = 0; + unsigned i; + for (i = 0; i < maxSize;) + { + const unsigned b = p[i]; + val |= (UInt64)(b & 0x7F) << (7 * i); + i++; + if ((b & 0x80) == 0) + { + *val_ptr = val; + return i; + } + } + *val_ptr = 0; +#if 1 + return 0; // 7zip-unrar : strict check of error +#else + return i; // original-unrar : ignore error +#endif +} + + +#define PARSE_VAR_INT(p, size, dest) \ +{ const unsigned num_ = ReadVarInt(p, size, &dest); \ + if (num_ == 0) return false; \ + p += num_; \ + size -= num_; \ +} + + +bool CLinkInfo::Parse(const Byte *p, unsigned size) +{ + const Byte *pStart = p; + UInt64 len; + PARSE_VAR_INT(p, size, Type) + PARSE_VAR_INT(p, size, Flags) + PARSE_VAR_INT(p, size, len) + if (size != len) + return false; + NameLen = (unsigned)len; + NameOffset = (unsigned)(size_t)(p - pStart); + return true; +} + + +static void AddHex64(AString &s, UInt64 v) +{ + char sz[32]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt64ToHex(v, sz + 2); + s += sz; +} + + +static void PrintType(AString &s, const char * const table[], unsigned num, UInt64 val) +{ + char sz[32]; + const char *p = NULL; + if (val < num) + p = table[(unsigned)val]; + if (!p) + { + ConvertUInt64ToString(val, sz); + p = sz; + } + s += p; +} + + +int CItem::FindExtra(unsigned extraID, unsigned &recordDataSize) const +{ + recordDataSize = 0; + size_t offset = 0; + + for (;;) + { + size_t rem = Extra.Size() - offset; + if (rem == 0) + return -1; + + { + UInt64 size; + const unsigned num = ReadVarInt(Extra + offset, rem, &size); + if (num == 0) + return -1; + offset += num; + rem -= num; + if (size > rem) + return -1; + rem = (size_t)size; + } + { + UInt64 id; + const unsigned num = ReadVarInt(Extra + offset, rem, &id); + if (num == 0) + return -1; + offset += num; + rem -= num; + + // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) + // for Subdata record in Service header. + // That record always was last in bad archives, so we can fix that case. + if (id == NExtraID::kSubdata + && RecordType == NHeaderType::kService + && rem + 1 == Extra.Size() - offset) + rem++; + + if (id == extraID) + { + recordDataSize = (unsigned)rem; + return (int)offset; + } + + offset += rem; + } + } +} + + +void CItem::PrintInfo(AString &s) const +{ + size_t offset = 0; + + for (;;) + { + size_t rem = Extra.Size() - offset; + if (rem == 0) + return; + + { + UInt64 size; + unsigned num = ReadVarInt(Extra + offset, rem, &size); + if (num == 0) + return; + offset += num; + rem -= num; + if (size > rem) + break; + rem = (size_t)size; + } + { + UInt64 id; + { + unsigned num = ReadVarInt(Extra + offset, rem, &id); + if (num == 0) + break; + offset += num; + rem -= num; + } + + // There was BUG in RAR 5.21- : it stored (size-1) instead of (size) + // for Subdata record in Service header. + // That record always was last in bad archives, so we can fix that case. + if (id == NExtraID::kSubdata + && RecordType == NHeaderType::kService + && rem + 1 == Extra.Size() - offset) + rem++; + + s.Add_Space_if_NotEmpty(); + PrintType(s, g_ExtraTypes, Z7_ARRAY_SIZE(g_ExtraTypes), id); + + if (id == NExtraID::kTime) + { + const Byte *p = Extra + offset; + UInt64 flags; + const unsigned num = ReadVarInt(p, rem, &flags); + if (num != 0) + { + s.Add_Colon(); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTimeFlags); i++) + if ((flags & ((UInt64)1 << i)) != 0) + s.Add_Char(g_ExtraTimeFlags[i]); + flags &= ~(((UInt64)1 << Z7_ARRAY_SIZE(g_ExtraTimeFlags)) - 1); + if (flags != 0) + { + s.Add_Char('_'); + AddHex64(s, flags); + } + } + } + else if (id == NExtraID::kLink) + { + CLinkInfo linkInfo; + if (linkInfo.Parse(Extra + offset, (unsigned)rem)) + { + s.Add_Colon(); + PrintType(s, g_LinkTypes, Z7_ARRAY_SIZE(g_LinkTypes), linkInfo.Type); + UInt64 flags = linkInfo.Flags; + if (flags != 0) + { + s.Add_Colon(); + if (flags & NLinkFlags::kTargetIsDir) + { + s.Add_Char('D'); + flags &= ~((UInt64)NLinkFlags::kTargetIsDir); + } + if (flags != 0) + { + s.Add_Char('_'); + AddHex64(s, flags); + } + } + } + } + + offset += rem; + } + } + + s.Add_OptSpaced("ERROR"); +} + + +bool CCryptoInfo::Parse(const Byte *p, size_t size) +{ + Algo = 0; + Flags = 0; + Cnt = 0; + PARSE_VAR_INT(p, size, Algo) + PARSE_VAR_INT(p, size, Flags) + if (size > 0) + Cnt = p[0]; + if (size != 1 + 16 + 16 + (unsigned)(IsThereCheck() ? 12 : 0)) + return false; + return true; +} + + +bool CItem::FindExtra_Version(UInt64 &version) const +{ + unsigned size; + const int offset = FindExtra(NExtraID::kVersion, size); + if (offset < 0) + return false; + const Byte *p = Extra + (unsigned)offset; + + UInt64 flags; + PARSE_VAR_INT(p, size, flags) + PARSE_VAR_INT(p, size, version) + return size == 0; +} + +bool CItem::FindExtra_Link(CLinkInfo &link) const +{ + unsigned size; + const int offset = FindExtra(NExtraID::kLink, size); + if (offset < 0) + return false; + if (!link.Parse(Extra + (unsigned)offset, size)) + return false; + link.NameOffset += (unsigned)offset; + return true; +} + +bool CItem::Is_CopyLink() const +{ + CLinkInfo link; + return FindExtra_Link(link) && link.Type == NLinkType::kFileCopy; +} + +bool CItem::Is_HardLink() const +{ + CLinkInfo link; + return FindExtra_Link(link) && link.Type == NLinkType::kHardLink; +} + +bool CItem::Is_CopyLink_or_HardLink() const +{ + CLinkInfo link; + return FindExtra_Link(link) && (link.Type == NLinkType::kFileCopy || link.Type == NLinkType::kHardLink); +} + +void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const +{ + CLinkInfo link; + if (!FindExtra_Link(link)) + return; + + if (link.Type != linkType) + { + if (linkType != NLinkType::kUnixSymLink) + return; + switch ((unsigned)link.Type) + { + case NLinkType::kUnixSymLink: + case NLinkType::kWinSymLink: + case NLinkType::kWinJunction: + break; + default: return; + } + } + + AString s; + s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen); + + UString unicode; + ConvertUTF8ToUnicode(s, unicode); + prop = NItemName::GetOsPath(unicode); +} + +bool CItem::GetAltStreamName(AString &name) const +{ + name.Empty(); + unsigned size; + const int offset = FindExtra(NExtraID::kSubdata, size); + if (offset < 0) + return false; + name.SetFrom_CalcLen((const char *)(Extra + (unsigned)offset), size); + return true; +} + + +class CHash +{ + bool _calcCRC; + UInt32 _crc; + int _blakeOffset; + CAlignedBuffer1 _buf; + // CBlake2sp _blake; + CBlake2sp *BlakeObj() { return (CBlake2sp *)(void *)(Byte *)_buf; } +public: + CHash(): + _buf(sizeof(CBlake2sp)) + {} + + void Init_NoCalc() + { + _calcCRC = false; + _crc = CRC_INIT_VAL; + _blakeOffset = -1; + } + + void Init(const CItem &item); + void Update(const void *data, size_t size); + UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); } + + bool Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoder); +}; + +void CHash::Init(const CItem &item) +{ + _crc = CRC_INIT_VAL; + _calcCRC = item.Has_CRC(); + _blakeOffset = item.FindExtra_Blake(); + if (_blakeOffset >= 0) + Blake2sp_Init(BlakeObj()); +} + +void CHash::Update(const void *data, size_t size) +{ + if (_calcCRC) + _crc = CrcUpdate(_crc, data, size); + if (_blakeOffset >= 0) + Blake2sp_Update(BlakeObj(), (const Byte *)data, size); +} + +bool CHash::Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoder) +{ + if (_calcCRC) + { + UInt32 crc = GetCRC(); + if (cryptoDecoder) + crc = cryptoDecoder->Hmac_Convert_Crc32(crc); + if (crc != item.CRC) + return false; + } + if (_blakeOffset >= 0) + { + UInt32 digest[Z7_BLAKE2S_DIGEST_SIZE / sizeof(UInt32)]; + Blake2sp_Final(BlakeObj(), (Byte *)(void *)digest); + if (cryptoDecoder) + cryptoDecoder->Hmac_Convert_32Bytes((Byte *)(void *)digest); + if (memcmp(digest, item.Extra + (unsigned)_blakeOffset, Z7_BLAKE2S_DIGEST_SIZE) != 0) + return false; + } + return true; +} + + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithHash + , ISequentialOutStream +) + bool _size_Defined; + ISequentialOutStream *_stream; + UInt64 _pos; + UInt64 _size; + Byte *_destBuf; +public: + CHash _hash; + + COutStreamWithHash(): _destBuf(NULL) {} + + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void Init(const CItem &item, Byte *destBuf, bool needChecksumCheck) + { + _size_Defined = false; + _size = 0; + _destBuf = NULL; + if (!item.Is_UnknownSize()) + { + _size_Defined = true; + _size = item.Size; + _destBuf = destBuf; + } + _pos = 0; + if (needChecksumCheck) + _hash.Init(item); + else + _hash.Init_NoCalc(); + } + UInt64 GetPos() const { return _pos; } +}; + + +Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_size_Defined) + { + const UInt64 rem = _size - _pos; + if (size > rem) + size = (UInt32)rem; + } + if (_stream) + result = _stream->Write(data, size, &size); + if (_destBuf) + memcpy(_destBuf + (size_t)_pos, data, size); + _hash.Update(data, size); + _pos += size; + if (processedSize) + *processedSize = size; + return result; +} + + + + + +class CInArchive +{ + CAlignedBuffer _buf; + size_t _bufSize; + size_t _bufPos; + ISequentialInStream *_stream; + + CMyComPtr2 m_CryptoDecoder; + + Z7_CLASS_NO_COPY(CInArchive) + + HRESULT ReadStream_Check(void *data, size_t size); + +public: + bool m_CryptoMode; + + bool WrongPassword; + bool IsArc; + bool UnexpectedEnd; + + UInt64 StreamStartPosition; + UInt64 Position; + + size_t Get_Buf_RemainSize() const { return _bufSize - _bufPos; } + bool Is_Buf_Finished() const { return _bufPos == _bufSize; } + const Byte *Get_Buf_Data() const { return _buf + _bufPos; } + void Move_BufPos(size_t num) { _bufPos += num; } + bool ReadVar(UInt64 &val); + + struct CHeader + { + UInt64 Type; + UInt64 Flags; + size_t ExtraSize; + UInt64 DataSize; + }; + + CInArchive() {} + + HRESULT ReadBlockHeader(CHeader &h); + bool ReadFileHeader(const CHeader &header, CItem &item); + void AddToSeekValue(UInt64 addValue) + { + Position += addValue; + } + + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword, + CInArcInfo &info); +}; + + +static HRESULT MySetPassword(ICryptoGetTextPassword *getTextPassword, NCrypto::NRar5::CDecoder *cryptoDecoder) +{ + CMyComBSTR_Wipe password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + AString_Wipe utf8; + const unsigned kPasswordLen_MAX = 127; + UString_Wipe unicode; + unicode.SetFromBstr(password); + if (unicode.Len() > kPasswordLen_MAX) + unicode.DeleteFrom(kPasswordLen_MAX); + ConvertUnicodeToUTF8(unicode, utf8); + cryptoDecoder->SetPassword((const Byte *)(const char *)utf8, utf8.Len()); + return S_OK; +} + + +bool CInArchive::ReadVar(UInt64 &val) +{ + const unsigned offset = ReadVarInt(Get_Buf_Data(), Get_Buf_RemainSize(), &val); + Move_BufPos(offset); + return (offset != 0); +} + + +HRESULT CInArchive::ReadStream_Check(void *data, size_t size) +{ + size_t size2 = size; + RINOK(ReadStream(_stream, data, &size2)) + if (size2 == size) + return S_OK; + UnexpectedEnd = true; + return S_FALSE; +} + + +HRESULT CInArchive::ReadBlockHeader(CHeader &h) +{ + h.Type = 0; + h.Flags = 0; + h.ExtraSize = 0; + h.DataSize = 0; + + Byte buf[AES_BLOCK_SIZE]; + unsigned filled; + + if (m_CryptoMode) + { + _buf.AllocAtLeast(1 << 12); // at least (AES_BLOCK_SIZE * 2) + if (!(Byte *)_buf) + return E_OUTOFMEMORY; + RINOK(ReadStream_Check(_buf, AES_BLOCK_SIZE * 2)) + memcpy(m_CryptoDecoder->_iv, _buf, AES_BLOCK_SIZE); + RINOK(m_CryptoDecoder->Init()) + // we call RAR5_AES_Filter with: + // data_ptr == aligned_ptr + 16 + // data_size == 16 + if (m_CryptoDecoder->Filter(_buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) + return E_FAIL; + memcpy(buf, _buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE); + filled = AES_BLOCK_SIZE; + } + else + { + const unsigned kStartSize = 4 + 3; + RINOK(ReadStream_Check(buf, kStartSize)) + filled = kStartSize; + } + + { + UInt64 val; + unsigned offset = ReadVarInt(buf + 4, 3, &val); + if (offset == 0) + return S_FALSE; + size_t size = (size_t)val; + if (size < 2) + return S_FALSE; + offset += 4; + _bufPos = offset; + size += offset; + _bufSize = size; + if (m_CryptoMode) + size = (size + AES_BLOCK_SIZE - 1) & ~(size_t)(AES_BLOCK_SIZE - 1); + _buf.AllocAtLeast(size); + if (!(Byte *)_buf) + return E_OUTOFMEMORY; + memcpy(_buf, buf, filled); + const size_t rem = size - filled; + // if (m_CryptoMode), we add AES_BLOCK_SIZE here, because _iv is not included to size. + AddToSeekValue(size + (m_CryptoMode ? AES_BLOCK_SIZE : 0)); + RINOK(ReadStream_Check(_buf + filled, rem)) + if (m_CryptoMode) + { + // we call RAR5_AES_Filter with: + // data_ptr == aligned_ptr + 16 + // (rem) can be big + if (m_CryptoDecoder->Filter(_buf + filled, (UInt32)rem) != rem) + return E_FAIL; +#if 1 + // optional 7zip-unrar check : remainder must contain zeros. + const size_t pad = size - _bufSize; + const Byte *p = _buf + _bufSize; + for (size_t i = 0; i < pad; i++) + if (p[i]) + return S_FALSE; +#endif + } + } + + if (CrcCalc(_buf + 4, _bufSize - 4) != Get32(buf)) + return S_FALSE; + + if (!ReadVar(h.Type)) return S_FALSE; + if (!ReadVar(h.Flags)) return S_FALSE; + + if (h.Flags & NHeaderFlags::kExtra) + { + UInt64 extraSize; + if (!ReadVar(extraSize)) + return S_FALSE; + if (extraSize >= (1u << 21)) + return S_FALSE; + h.ExtraSize = (size_t)extraSize; + } + + if (h.Flags & NHeaderFlags::kData) + { + if (!ReadVar(h.DataSize)) + return S_FALSE; + } + + if (h.ExtraSize > Get_Buf_RemainSize()) + return S_FALSE; + return S_OK; +} + + +bool CInArcInfo::CLocator::Parse(const Byte *p, size_t size) +{ + Flags = 0; + QuickOpen = 0; + Recovery = 0; + + PARSE_VAR_INT(p, size, Flags) + + if (Is_QuickOpen()) + { + PARSE_VAR_INT(p, size, QuickOpen) + } + if (Is_Recovery()) + { + PARSE_VAR_INT(p, size, Recovery) + } +#if 0 + // another records are possible in future rar formats. + if (size != 0) + return false; +#endif + return true; +} + + +bool CInArcInfo::CMetadata::Parse(const Byte *p, size_t size) +{ + PARSE_VAR_INT(p, size, Flags) + if (Flags & NMetadataFlags::kArcName) + { + UInt64 nameLen; + PARSE_VAR_INT(p, size, nameLen) + if (nameLen > size) + return false; + ArcName.SetFrom_CalcLen((const char *)(const void *)p, (unsigned)nameLen); + p += (size_t)nameLen; + size -= (size_t)nameLen; + } + if (Flags & NMetadataFlags::kCTime) + { + if ((Flags & NMetadataFlags::kUnixTime) && + (Flags & NMetadataFlags::kNanoSec) == 0) + { + if (size < 4) + return false; + CTime = GetUi32(p); + p += 4; + size -= 4; + } + else + { + if (size < 8) + return false; + CTime = GetUi64(p); + p += 8; + size -= 8; + } + } +#if 0 + // another records are possible in future rar formats. + if (size != 0) + return false; +#endif + return true; +} + + +bool CInArcInfo::ParseExtra(const Byte *p, size_t size) +{ + for (;;) + { + if (size == 0) + return true; + UInt64 recSize64, id; + PARSE_VAR_INT(p, size, recSize64) + if (recSize64 > size) + return false; + size_t recSize = (size_t)recSize64; + size -= recSize; + // READ_VAR_INT(p, recSize, recSize) + { + const unsigned num = ReadVarInt(p, recSize, &id); + if (num == 0) + return false; + p += num; + recSize -= num; + } + if (id == kArcExtraRecordType_Metadata) + { + Metadata_Defined = true; + if (!Metadata.Parse(p, recSize)) + Metadata_Error = true; + } + else if (id == kArcExtraRecordType_Locator) + { + Locator_Defined = true; + if (!Locator.Parse(p, recSize)) + Locator_Error = true; + } + else + UnknownExtraRecord = true; + p += recSize; + } +} + + + +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword, + CInArcInfo &info) +{ + m_CryptoMode = false; + + WrongPassword = false; + IsArc = false; + UnexpectedEnd = false; + + Position = StreamStartPosition; + + UInt64 arcStartPos = StreamStartPosition; + { + Byte marker[kMarkerSize]; + RINOK(ReadStream_FALSE(stream, marker, kMarkerSize)) + if (memcmp(marker, kMarker, kMarkerSize) == 0) + Position += kMarkerSize; + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + RINOK(InStream_SeekSet(stream, StreamStartPosition)) + RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize, + searchHeaderSizeLimit, arcStartPos)) + arcStartPos += StreamStartPosition; + Position = arcStartPos + kMarkerSize; + RINOK(InStream_SeekSet(stream, Position)) + } + } + + info.StartPos = arcStartPos; + _stream = stream; + + CHeader h; + RINOK(ReadBlockHeader(h)) + info.IsEncrypted = false; + + if (h.Type == NHeaderType::kArcEncrypt) + { + info.IsEncrypted = true; + IsArc = true; + if (!getTextPassword) + return E_NOTIMPL; + m_CryptoMode = true; + m_CryptoDecoder.Create_if_Empty(); + RINOK(m_CryptoDecoder->SetDecoderProps( + Get_Buf_Data(), (unsigned)Get_Buf_RemainSize(), false, false)) + RINOK(MySetPassword(getTextPassword, m_CryptoDecoder.ClsPtr())) + if (!m_CryptoDecoder->CalcKey_and_CheckPassword()) + { + WrongPassword = True; + return S_FALSE; + } + RINOK(ReadBlockHeader(h)) + } + + if (h.Type != NHeaderType::kArc) + return S_FALSE; + + IsArc = true; + info.VolNumber = 0; + + if (!ReadVar(info.Flags)) + return S_FALSE; + + if (info.Flags & NArcFlags::kVolNumber) + if (!ReadVar(info.VolNumber)) + return S_FALSE; + + if (h.ExtraSize != Get_Buf_RemainSize()) + return S_FALSE; + if (h.ExtraSize) + { + if (!info.ParseExtra(Get_Buf_Data(), h.ExtraSize)) + info.Extra_Error = true; + } + return S_OK; +} + + +bool CInArchive::ReadFileHeader(const CHeader &header, CItem &item) +{ + item.CommonFlags = (UInt32)header.Flags; + item.PackSize = header.DataSize; + item.UnixMTime = 0; + item.CRC = 0; + + { + UInt64 flags64; + if (!ReadVar(flags64)) return false; + item.Flags = (UInt32)flags64; + } + + if (!ReadVar(item.Size)) return false; + + { + UInt64 attrib; + if (!ReadVar(attrib)) return false; + item.Attrib = (UInt32)attrib; + } + if (item.Has_UnixMTime()) + { + if (Get_Buf_RemainSize() < 4) + return false; + item.UnixMTime = Get32(Get_Buf_Data()); + Move_BufPos(4); + } + if (item.Has_CRC()) + { + if (Get_Buf_RemainSize() < 4) + return false; + item.CRC = Get32(Get_Buf_Data()); + Move_BufPos(4); + } + { + UInt64 method; + if (!ReadVar(method)) return false; + item.Method = (UInt32)method; + } + + if (!ReadVar(item.HostOS)) return false; + + { + UInt64 len; + if (!ReadVar(len)) return false; + if (len > Get_Buf_RemainSize()) + return false; + item.Name.SetFrom_CalcLen((const char *)Get_Buf_Data(), (unsigned)len); + Move_BufPos((size_t)len); + } + + item.Extra.Free(); + const size_t extraSize = header.ExtraSize; + if (extraSize != 0) + { + if (Get_Buf_RemainSize() < extraSize) + return false; + item.Extra.Alloc(extraSize); + memcpy(item.Extra, Get_Buf_Data(), extraSize); + Move_BufPos(extraSize); + } + + return Is_Buf_Finished(); +} + + + +struct CLinkFile +{ + unsigned Index; + unsigned NumLinks; // the number of links to Data + CByteBuffer Data; + HRESULT Res; + bool crcOK; + + CLinkFile(): Index(0), NumLinks(0), Res(S_OK), crcOK(true) {} +}; + + +struct CUnpacker +{ + CMyComPtr2 copyCoder; + CMyComPtr LzCoders[2]; + bool SolidAllowed; + bool NeedCrc; + CFilterCoder *filterStreamSpec; + CMyComPtr filterStream; + CMyComPtr2 cryptoDecoder; + CMyComPtr getTextPassword; + CMyComPtr2 outStream; + + CByteBuffer _tempBuf; + CLinkFile *linkFile; + + CUnpacker(): linkFile(NULL) { SolidAllowed = false; NeedCrc = true; } + + HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, bool isSolid, bool &wrongPassword); + + HRESULT Code(const CItem &item, const CItem &lastItem, UInt64 packSize, + ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress, + bool &isCrcOK); + + HRESULT DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer); +}; + + +static const unsigned kLzMethodMax = 5; + +HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, bool isSolid, bool &wrongPassword) +{ + wrongPassword = false; + + if (item.Get_AlgoVersion_RawBits() > 1) + return E_NOTIMPL; + + outStream.Create_if_Empty(); + + const unsigned method = item.Get_Method(); + + if (method == 0) + copyCoder.Create_if_Empty(); + else + { + if (method > kLzMethodMax) + return E_NOTIMPL; + /* + if (item.IsSplitBefore()) + return S_FALSE; + */ + const unsigned lzIndex = item.IsService() ? 1 : 0; + CMyComPtr &lzCoder = LzCoders[lzIndex]; + if (!lzCoder) + { + const UInt32 methodID = 0x40305; + RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodID, false, lzCoder)) + if (!lzCoder) + return E_NOTIMPL; + } + + CMyComPtr csdp; + RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp)) + if (!csdp) + return E_NOTIMPL; + const unsigned ver = item.Get_AlgoVersion_HuffRev(); + if (ver > 1) + return E_NOTIMPL; + const Byte props[2] = + { + (Byte)item.Get_DictSize_Main(), + (Byte)((item.Get_DictSize_Frac() << 3) + (ver << 1) + (isSolid ? 1 : 0)) + }; + RINOK(csdp->SetDecoderProperties2(props, 2)) + } + + unsigned cryptoSize = 0; + const int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize); + + if (cryptoOffset >= 0) + { + if (!filterStream) + { + filterStreamSpec = new CFilterCoder(false); + filterStream = filterStreamSpec; + } + + cryptoDecoder.Create_if_Empty(); + + RINOK(cryptoDecoder->SetDecoderProps(item.Extra + (unsigned)cryptoOffset, cryptoSize, true, item.IsService())) + + if (!getTextPassword) + { + wrongPassword = True; + return E_NOTIMPL; + } + + RINOK(MySetPassword(getTextPassword, cryptoDecoder.ClsPtr())) + + if (!cryptoDecoder->CalcKey_and_CheckPassword()) + wrongPassword = True; + } + + return S_OK; +} + + +HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSize, + ISequentialInStream *volsInStream, ISequentialOutStream *realOutStream, ICompressProgressInfo *progress, + bool &isCrcOK) +{ + isCrcOK = true; + + const unsigned method = item.Get_Method(); + if (method > kLzMethodMax) + return E_NOTIMPL; + + const bool needBuf = (linkFile && linkFile->NumLinks != 0); + + if (needBuf && !lastItem.Is_UnknownSize()) + { + const size_t dataSize = (size_t)lastItem.Size; + if (dataSize != lastItem.Size) + return E_NOTIMPL; + linkFile->Data.Alloc(dataSize); + } + + bool isCryptoMode = false; + ISequentialInStream *inStream; + + if (item.IsEncrypted()) + { + filterStreamSpec->Filter = cryptoDecoder; + filterStreamSpec->SetInStream(volsInStream); + filterStreamSpec->SetOutStreamSize(NULL); + inStream = filterStream; + isCryptoMode = true; + } + else + inStream = volsInStream; + + ICompressCoder *commonCoder = (method == 0) ? + copyCoder.Interface() : + LzCoders[item.IsService() ? 1 : 0].Interface(); + + outStream->SetStream(realOutStream); + outStream->Init(lastItem, (needBuf ? (Byte *)linkFile->Data : NULL), NeedCrc); + + HRESULT res = S_OK; + if (packSize != 0 || lastItem.Is_UnknownSize() || lastItem.Size != 0) + { + res = commonCoder->Code(inStream, outStream, &packSize, + lastItem.Is_UnknownSize() ? NULL : &lastItem.Size, progress); + if (!item.IsService()) + SolidAllowed = true; + } + else + { + // res = res; + } + + if (isCryptoMode) + filterStreamSpec->ReleaseInStream(); + + const UInt64 processedSize = outStream->GetPos(); + if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size) + res = S_FALSE; + + // if (res == S_OK) + { + unsigned cryptoSize = 0; + const int cryptoOffset = lastItem.FindExtra(NExtraID::kCrypto, cryptoSize); + NCrypto::NRar5::CDecoder *crypto = NULL; + if (cryptoOffset >= 0) + { + CCryptoInfo cryptoInfo; + if (cryptoInfo.Parse(lastItem.Extra + (unsigned)cryptoOffset, cryptoSize)) + if (cryptoInfo.UseMAC()) + crypto = cryptoDecoder.ClsPtr(); + } + if (NeedCrc) + isCrcOK = outStream->_hash.Check(lastItem, crypto); + } + + if (linkFile) + { + linkFile->Res = res; + linkFile->crcOK = isCrcOK; + if (needBuf + && !lastItem.Is_UnknownSize() + && processedSize != lastItem.Size) + linkFile->Data.ChangeSize_KeepData((size_t)processedSize, (size_t)processedSize); + } + + return res; +} + + +HRESULT CUnpacker::DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, UInt64 packSize, + ISequentialInStream *inStream, + CByteBuffer &buffer) +{ + CMyComPtr2_Create out; + _tempBuf.AllocAtLeast((size_t)item.Size); + out->Init(_tempBuf, (size_t)item.Size); + + bool wrongPassword; + + if (item.IsSolid()) + return E_NOTIMPL; + + HRESULT res = Create(EXTERNAL_CODECS_LOC_VARS item, item.IsSolid(), wrongPassword); + + if (res == S_OK) + { + if (wrongPassword) + return S_FALSE; + + CMyComPtr2_Create limitedStream; + limitedStream->SetStream(inStream); + limitedStream->Init(packSize); + + bool crcOK = true; + res = Code(item, item, packSize, limitedStream, out, NULL, crcOK); + if (res == S_OK) + { + if (!crcOK || out->GetPos() != item.Size) + res = S_FALSE; + else + buffer.CopyFrom(_tempBuf, (size_t)item.Size); + } + } + + return res; +} + + +struct CTempBuf +{ + CByteBuffer _buf; + size_t _offset; + bool _isOK; + + void Clear() + { + _offset = 0; + _isOK = true; + } + + CTempBuf() { Clear(); } + + HRESULT Decode(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, + ISequentialInStream *inStream, + CUnpacker &unpacker, + CByteBuffer &destBuf); +}; + + +HRESULT CTempBuf::Decode(DECL_EXTERNAL_CODECS_LOC_VARS + const CItem &item, + ISequentialInStream *inStream, + CUnpacker &unpacker, + CByteBuffer &destBuf) +{ + const size_t kPackSize_Max = (1 << 24); + if (item.Size > (1 << 24) + || item.Size == 0 + || item.PackSize >= kPackSize_Max) + { + Clear(); + return S_OK; + } + + if (item.IsSplit() /* && _isOK */) + { + size_t packSize = (size_t)item.PackSize; + if (packSize > kPackSize_Max - _offset) + return S_OK; + size_t newSize = _offset + packSize; + if (newSize > _buf.Size()) + _buf.ChangeSize_KeepData(newSize, _offset); + + Byte *data = (Byte *)_buf + _offset; + RINOK(ReadStream_FALSE(inStream, data, packSize)) + + _offset += packSize; + + if (item.IsSplitAfter()) + { + CHash hash; + hash.Init(item); + hash.Update(data, packSize); + _isOK = hash.Check(item, NULL); // RAR5 doesn't use HMAC for packed part + } + } + + if (_isOK) + { + if (!item.IsSplitAfter()) + { + if (_offset == 0) + { + RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS + item, item.PackSize, inStream, destBuf)) + } + else + { + CMyComPtr2_Create bufInStream; + bufInStream->Init(_buf, _offset); + RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS + item, _offset, bufInStream, destBuf)) + } + } + } + + return S_OK; +} + + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + // kpidPosixAttrib, // for debug + + kpidIsAltStream, + kpidEncrypted, + kpidSolid, + kpidSplitBefore, + kpidSplitAfter, + kpidCRC, + kpidHostOS, + kpidMethod, + kpidCharacts, + kpidSymLink, + kpidHardLink, + kpidCopyLink, + + kpidVolumeIndex +}; + + +static const Byte kArcProps[] = +{ + kpidTotalPhySize, + kpidCharacts, + kpidEncrypted, + kpidSolid, + kpidNumBlocks, + kpidMethod, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes, + kpidName, + kpidCTime, + kpidComment +}; + + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +UInt64 CHandler::GetPackSize(unsigned refIndex) const +{ + UInt64 size = 0; + unsigned index = _refs[refIndex].Item; + for (;;) + { + const CItem &item = _items[index]; + size += item.PackSize; + if (item.NextItem < 0) + return size; + index = (unsigned)item.NextItem; + } +} + +static char *PrintDictSize(char *s, UInt64 w) +{ + char c = 'K'; w >>= 10; + if ((w & ((1 << 10) - 1)) == 0) { c = 'M'; w >>= 10; + if ((w & ((1 << 10) - 1)) == 0) { c = 'G'; w >>= 10; }} + s = ConvertUInt64ToString(w, s); + *s++ = c; + *s = 0; + return s; +} + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + + NCOM::CPropVariant prop; + + const CInArcInfo *arcInfo = NULL; + if (!_arcs.IsEmpty()) + arcInfo = &_arcs[0].Info; + + switch (propID) + { + case kpidVolumeIndex: if (arcInfo && arcInfo->IsVolume()) prop = arcInfo->GetVolIndex(); break; + case kpidSolid: if (arcInfo) prop = arcInfo->IsSolid(); break; + case kpidCharacts: + { + AString s; + if (arcInfo) + { + s = FlagsToString(k_ArcFlags, Z7_ARRAY_SIZE(k_ArcFlags), (UInt32)arcInfo->Flags); + if (arcInfo->Extra_Error) + s.Add_OptSpaced("Extra-ERROR"); + if (arcInfo->UnsupportedFeature) + s.Add_OptSpaced("unsupported-feature"); + if (arcInfo->Metadata_Defined) + { + s.Add_OptSpaced("Metadata"); + if (arcInfo->Metadata_Error) + s += "-ERROR"; + else + { + if (arcInfo->Metadata.Flags & NMetadataFlags::kArcName) + s.Add_OptSpaced("arc-name"); + if (arcInfo->Metadata.Flags & NMetadataFlags::kCTime) + { + s.Add_OptSpaced("ctime-"); + s += + (arcInfo->Metadata.Flags & NMetadataFlags::kUnixTime) ? + (arcInfo->Metadata.Flags & NMetadataFlags::kNanoSec) ? + "1ns" : "1s" : "win"; + } + } + } + if (arcInfo->Locator_Defined) + { + s.Add_OptSpaced("Locator"); + if (arcInfo->Locator_Error) + s += "-ERROR"; + else + { + if (arcInfo->Locator.Is_QuickOpen()) + { + s.Add_OptSpaced("QuickOpen:"); + s.Add_UInt64(arcInfo->Locator.QuickOpen); + } + if (arcInfo->Locator.Is_Recovery()) + { + s.Add_OptSpaced("Recovery:"); + s.Add_UInt64(arcInfo->Locator.Recovery); + } + } + } + if (arcInfo->UnknownExtraRecord) + s.Add_OptSpaced("Unknown-Extra-Record"); + + } + if (_comment_WasUsedInArc) + { + s.Add_OptSpaced("Comment"); + // s.Add_UInt32((UInt32)_comment.Size()); + } + // + if (_acls.Size() != 0) + { + s.Add_OptSpaced("ACL"); + // s.Add_UInt32(_acls.Size()); + } + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidEncrypted: if (arcInfo) prop = arcInfo->IsEncrypted; break; // it's for encrypted names. + case kpidIsVolume: if (arcInfo) prop = arcInfo->IsVolume(); break; + case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; + case kpidOffset: if (arcInfo && arcInfo->StartPos != 0) prop = arcInfo->StartPos; break; + + case kpidTotalPhySize: + { + if (_arcs.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, _arcs) + sum += _arcs[v].Info.GetPhySize(); + prop = sum; + } + break; + } + + case kpidPhySize: + { + if (arcInfo) + prop = arcInfo->GetPhySize(); + break; + } + + case kpidName: + if (arcInfo) + if (!arcInfo->Metadata_Error + && !arcInfo->Metadata.ArcName.IsEmpty()) + { + UString s; + if (ConvertUTF8ToUnicode(arcInfo->Metadata.ArcName, s)) + prop = s; + } + break; + + case kpidCTime: + if (arcInfo) + if (!arcInfo->Metadata_Error + && (arcInfo->Metadata.Flags & NMetadataFlags::kCTime)) + { + const UInt64 ct = arcInfo->Metadata.CTime; + if (arcInfo->Metadata.Flags & NMetadataFlags::kUnixTime) + { + if (arcInfo->Metadata.Flags & NMetadataFlags::kNanoSec) + { + const UInt64 sec = ct / 1000000000; + const UInt64 ns = ct % 1000000000; + UInt64 wt = NTime::UnixTime64_To_FileTime64((Int64)sec); + wt += ns / 100; + const unsigned ns100 = (unsigned)(ns % 100); + FILETIME ft; + ft.dwLowDateTime = (DWORD)(UInt32)wt; + ft.dwHighDateTime = (DWORD)(UInt32)(wt >> 32); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); + } + else + { + const UInt64 wt = NTime::UnixTime64_To_FileTime64((Int64)ct); + prop.SetAsTimeFrom_Ft64_Prec(wt, k_PropVar_TimePrec_Unix); + } + } + else + prop.SetAsTimeFrom_Ft64_Prec(ct, k_PropVar_TimePrec_100ns); + } + break; + + case kpidComment: + { + // if (!_arcs.IsEmpty()) + { + // const CArc &arc = _arcs[0]; + const CByteBuffer &cmt = _comment; + if (cmt.Size() != 0 /* && cmt.Size() < (1 << 16) */) + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)cmt, (unsigned)cmt.Size()); + UString unicode; + ConvertUTF8ToUnicode(s, unicode); + prop = unicode; + } + } + break; + } + + case kpidNumBlocks: + { + prop = (UInt32)_numBlocks; + break; + } + + case kpidMethod: + { + AString s; + + UInt64 algo = _algo_Mask; + for (unsigned v = 0; algo != 0; v++, algo >>= 1) + { + if ((algo & 1) == 0) + continue; + s.Add_OptSpaced("v"); + s.Add_UInt32(v + 6); + if (v < Z7_ARRAY_SIZE(_methodMasks)) + { + const UInt64 dict = _dictMaxSizes[v]; + if (dict) + { + char temp[24]; + temp[0] = ':'; + PrintDictSize(temp + 1, dict); + s += temp; + } + unsigned method = _methodMasks[v]; + for (unsigned m = 0; method; m++, method >>= 1) + { + if ((method & 1) == 0) + continue; + s += ":m"; + s.Add_UInt32(m); + } + } + } + if (_rar5comapt_mask & 2) + { + s += ":c"; + if (_rar5comapt_mask & 1) + s.Add_Char('n'); + } + prop = s; + break; + } + + case kpidError: + { + if (/* &_missingVol || */ !_missingVolName.IsEmpty()) + { + UString s ("Missing volume : "); + s += _missingVolName; + prop = s; + } + break; + } + + case kpidErrorFlags: + { + UInt32 v = _errorFlags; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + if (_error_in_ACL) + v |= kpv_ErrorFlags_HeadersError; + if (_split_Error) + v |= kpv_ErrorFlags_HeadersError; + prop = v; + break; + } + + /* + case kpidWarningFlags: + { + if (_warningFlags != 0) + prop = _warningFlags; + break; + } + */ + + case kpidExtension: + if (_arcs.Size() == 1) + { + if (arcInfo->IsVolume()) + { + AString s ("part"); + UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1; + if (v < 10) + s.Add_Char('0'); + s.Add_UInt32(v); + s += ".rar"; + prop = s; + } + } + break; + + case kpidIsAltStream: prop = true; break; + } + + prop.Detach(value); + return S_OK; + + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = (UInt32)_refs.Size(); + return S_OK; +} + + +static const Byte kRawProps[] = +{ + kpidChecksum, + kpidNtSecure +}; + + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = Z7_ARRAY_SIZE(kRawProps); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) +{ + *propID = kRawProps[index]; + *name = NULL; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + + if (index >= _refs.Size()) + return S_OK; + + const CRefItem &ref = _refs[index]; + const CItem &item = _items[ref.Item]; + + if (item.Is_STM() && ref.Parent >= 0) + { + *parent = (UInt32)ref.Parent; + *parentType = NParentType::kAltStream; + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (index >= _refs.Size()) + return E_INVALIDARG; + + const CItem &item = _items[_refs[index].Item]; + + if (propID == kpidNtSecure) + { + if (item.ACL >= 0) + { + const CByteBuffer &buf = _acls[item.ACL]; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + *data = (const Byte *)buf; + } + return S_OK; + } + + if (propID == kpidChecksum) + { + const int hashRecOffset = item.FindExtra_Blake(); + if (hashRecOffset >= 0) + { + *dataSize = Z7_BLAKE2S_DIGEST_SIZE; + *propType = NPropDataType::kRaw; + *data = item.Extra + (unsigned)hashRecOffset; + } + /* + else if (item.Has_CRC() && item.IsEncrypted()) + { + *dataSize = 4; + *propType = NPropDataType::kRaw; + *data = &item->CRC; // we must show same value for big/little endian here + } + */ + return S_OK; + } + + return S_OK; +} + + +static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop) +{ + unsigned size; + const int offset = item.FindExtra(NExtraID::kTime, size); + if (offset < 0) + return; + + const Byte *p = item.Extra + (unsigned)offset; + UInt64 flags; + // PARSE_VAR_INT(p, size, flags) + { + const unsigned num = ReadVarInt(p, size, &flags); + if (num == 0) + return; + p += num; + size -= num; + } + + if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0) + return; + + unsigned numStamps = 0; + unsigned curStamp = 0; + + for (unsigned i = 0; i < 3; i++) + if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) + { + if (i == stampIndex) + curStamp = numStamps; + numStamps++; + } + + FILETIME ft; + + unsigned timePrec = 0; + unsigned ns100 = 0; + + if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) + { + curStamp *= 4; + if (curStamp + 4 > size) + return; + p += curStamp; + UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p)); + numStamps *= 4; + timePrec = k_PropVar_TimePrec_Unix; + if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) + { + const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF; + if (ns < 1000000000) + { + val += ns / 100; + ns100 = (unsigned)(ns % 100); + timePrec = k_PropVar_TimePrec_1ns; + } + } + ft.dwLowDateTime = (DWORD)val; + ft.dwHighDateTime = (DWORD)(val >> 32); + } + else + { + curStamp *= 8; + if (curStamp + 8 > size) + return; + p += curStamp; + ft.dwLowDateTime = Get32(p); + ft.dwHighDateTime = Get32(p + 4); + } + + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100); +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + + NCOM::CPropVariant prop; + const CRefItem &ref = _refs[index]; + const CItem &item = _items[ref.Item]; + const CItem &lastItem = _items[ref.Last]; + + switch (propID) + { + case kpidPath: + { + UString unicodeName; + + if (item.Is_STM()) + { + AString s; + if (ref.Parent >= 0) + { + const CItem &mainItem = _items[_refs[ref.Parent].Item]; + s = mainItem.Name; + } + + AString name; + item.GetAltStreamName(name); + if (name[0] != ':') + s.Add_Colon(); + s += name; + ConvertUTF8ToUnicode(s, unicodeName); + } + else + { + ConvertUTF8ToUnicode(item.Name, unicodeName); + + if (item.Version_Defined) + { + char temp[32]; + // temp[0] = ';'; + // ConvertUInt64ToString(item.Version, temp + 1); + // unicodeName += temp; + ConvertUInt64ToString(item.Version, temp); + UString s2 ("[VER]" STRING_PATH_SEPARATOR); + s2 += temp; + s2.Add_PathSepar(); + unicodeName.Insert(0, s2); + } + } + + NItemName::ReplaceToOsSlashes_Remove_TailSlash(unicodeName); + prop = unicodeName; + + break; + } + + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: if (!lastItem.Is_UnknownSize()) prop = lastItem.Size; break; + case kpidPackSize: prop = GetPackSize((unsigned)index); break; + + case kpidMTime: + { + TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop); + if (prop.vt == VT_EMPTY && item.Has_UnixMTime()) + PropVariant_SetFrom_UnixTime(prop, item.UnixMTime); + if (prop.vt == VT_EMPTY && ref.Parent >= 0) + { + const CItem &baseItem = _items[_refs[ref.Parent].Item]; + TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop); + if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime()) + PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime); + } + break; + } + case kpidCTime: TimeRecordToProp(item, NTimeRecord::k_Index_CTime, prop); break; + case kpidATime: TimeRecordToProp(item, NTimeRecord::k_Index_ATime, prop); break; + + case kpidName: + { + if (item.Is_STM()) + { + AString name; + item.GetAltStreamName(name); + if (name[0] == ':') + { + name.DeleteFrontal(1); + UString unicodeName; + ConvertUTF8ToUnicode(name, unicodeName); + prop = unicodeName; + } + } + break; + } + + case kpidIsAltStream: prop = item.Is_STM(); break; + + case kpidSymLink: item.Link_to_Prop(NLinkType::kUnixSymLink, prop); break; + case kpidHardLink: item.Link_to_Prop(NLinkType::kHardLink, prop); break; + case kpidCopyLink: item.Link_to_Prop(NLinkType::kFileCopy, prop); break; + + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidPosixAttrib: + if (item.HostOS == kHost_Unix) + prop = (UInt32)item.Attrib; + break; + + case kpidEncrypted: prop = item.IsEncrypted(); break; + case kpidSolid: prop = item.IsSolid(); break; + + case kpidSplitBefore: prop = item.IsSplitBefore(); break; + case kpidSplitAfter: prop = lastItem.IsSplitAfter(); break; + + case kpidVolumeIndex: + { + if (item.VolIndex < _arcs.Size()) + { + const CInArcInfo &arcInfo = _arcs[item.VolIndex].Info; + if (arcInfo.IsVolume()) + prop = (UInt64)arcInfo.GetVolIndex(); + } + break; + } + + case kpidCRC: + { + const CItem *item2 = (lastItem.IsSplitAfter() ? &item : &lastItem); + // we don't want to show crc for encrypted file here, + // because crc is also encrrypted. + if (item2->Has_CRC() && !item2->IsEncrypted()) + prop = item2->CRC; + break; + } + + case kpidMethod: + { + char temp[128]; + const unsigned algo = item.Get_AlgoVersion_RawBits(); + char *s = temp; + // if (algo != 0) + { + *s++ = 'v'; + s = ConvertUInt32ToString((UInt32)algo + 6, s); + if (item.Is_Rar5_Compat()) + *s++ = 'c'; + *s++ = ':'; + } + { + const unsigned m = item.Get_Method(); + *s++ = 'm'; + *s++ = (char)(m + '0'); + if (!item.IsDir()) + { + *s++ = ':'; + const unsigned dictMain = item.Get_DictSize_Main(); + const unsigned frac = item.Get_DictSize_Frac(); + /* + if (frac == 0 && algo == 0) + s = ConvertUInt32ToString(dictMain + 17, s); + else + */ + s = PrintDictSize(s, (UInt64)(32 + frac) << (12 + dictMain)); + if (item.Is_Rar5_Compat()) + { + *s++ = ':'; + *s++ = 'c'; + } + } + } + unsigned cryptoSize = 0; + const int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize); + if (cryptoOffset >= 0) + { + *s++ = ' '; + CCryptoInfo cryptoInfo; + const bool isOK = cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize); + if (cryptoInfo.Algo == 0) + s = MyStpCpy(s, "AES"); + else + { + s = MyStpCpy(s, "Crypto_"); + s = ConvertUInt64ToString(cryptoInfo.Algo, s); + } + if (isOK) + { + *s++ = ':'; + s = ConvertUInt32ToString(cryptoInfo.Cnt, s); + *s++ = ':'; + s = ConvertUInt64ToString(cryptoInfo.Flags, s); + } + } + *s = 0; + prop = temp; + break; + } + + case kpidCharacts: + { + AString s; + + if (item.ACL >= 0) + s.Add_OptSpaced("ACL"); + + const UInt32 flags = item.Flags; + if (flags != 0) + { + const AString s2 = FlagsToString(k_FileFlags, Z7_ARRAY_SIZE(k_FileFlags), flags); + if (!s2.IsEmpty()) + s.Add_OptSpaced(s2); + } + + item.PrintInfo(s); + + if (!s.IsEmpty()) + prop = s; + break; + } + + + case kpidHostOS: + if (item.HostOS < Z7_ARRAY_SIZE(kHostOS)) + prop = kHostOS[(size_t)item.HostOS]; + else + prop = (UInt64)item.HostOS; + break; + } + + prop.Detach(value); + return S_OK; + + COM_TRY_END +} + + + +// ---------- Copy Links ---------- + +static int CompareItemsPaths(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1) +{ + const CItem &item1 = handler._items[handler._refs[p1].Item]; + const CItem &item2 = handler._items[handler._refs[p2].Item]; + + if (item1.Version_Defined) + { + if (!item2.Version_Defined) + return -1; + const int res = MyCompare(item1.Version, item2.Version); + if (res != 0) + return res; + } + else if (item2.Version_Defined) + return 1; + + if (!name1) + name1 = &item1.Name; + return strcmp(*name1, item2.Name); +} + +static int CompareItemsPaths2(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1) +{ + const int res = CompareItemsPaths(handler, p1, p2, name1); + if (res != 0) + return res; + return MyCompare(p1, p2); +} + +static int CompareItemsPaths_Sort(const unsigned *p1, const unsigned *p2, void *param) +{ + return CompareItemsPaths2(*(const CHandler *)param, *p1, *p2, NULL); +} + +static int FindLink(const CHandler &handler, const CUIntVector &sorted, + const AString &s, unsigned index) +{ + unsigned left = 0, right = sorted.Size(); + for (;;) + { + if (left == right) + { + if (left > 0) + { + const unsigned refIndex = sorted[left - 1]; + if (CompareItemsPaths(handler, index, refIndex, &s) == 0) + return (int)refIndex; + } + if (right < sorted.Size()) + { + const unsigned refIndex = sorted[right]; + if (CompareItemsPaths(handler, index, refIndex, &s) == 0) + return (int)refIndex; + } + return -1; + } + + const unsigned mid = (left + right) / 2; + const unsigned refIndex = sorted[mid]; + const int compare = CompareItemsPaths2(handler, index, refIndex, &s); + if (compare == 0) + return (int)refIndex; + if (compare < 0) + right = mid; + else + left = mid + 1; + } +} + +void CHandler::FillLinks() +{ + unsigned i; + + bool need_FillLinks = false; + + for (i = 0; i < _refs.Size(); i++) + { + const CItem &item = _items[_refs[i].Item]; + if (!item.IsDir() + && !item.IsService() + && item.NeedUse_as_CopyLink()) + need_FillLinks = true; + + if (!item.IsSolid()) + _numBlocks++; + + const unsigned algo = item.Get_AlgoVersion_RawBits(); + _algo_Mask |= (UInt64)1 << algo; + _rar5comapt_mask |= 1u << item.Get_Rar5_CompatBit(); + if (!item.IsDir() && algo < Z7_ARRAY_SIZE(_methodMasks)) + { + _methodMasks[algo] |= 1u << (item.Get_Method()); + UInt64 d = 32 + item.Get_DictSize_Frac(); + d <<= (12 + item.Get_DictSize_Main()); + if (_dictMaxSizes[algo] < d) + _dictMaxSizes[algo] = d; + } + } + + if (!need_FillLinks) + return; + + CUIntVector sorted; + for (i = 0; i < _refs.Size(); i++) + { + const CItem &item = _items[_refs[i].Item]; + if (!item.IsDir() && !item.IsService()) + sorted.Add(i); + } + + if (sorted.IsEmpty()) + return; + + sorted.Sort(CompareItemsPaths_Sort, (void *)this); + + AString link; + + for (i = 0; i < _refs.Size(); i++) + { + CRefItem &ref = _refs[i]; + const CItem &item = _items[ref.Item]; + if (item.IsDir() || item.IsService() || item.PackSize != 0) + continue; + CLinkInfo linkInfo; + if (!item.FindExtra_Link(linkInfo) || linkInfo.Type != NLinkType::kFileCopy) + continue; + link.SetFrom_CalcLen((const char *)(item.Extra + linkInfo.NameOffset), linkInfo.NameLen); + const int linkIndex = FindLink(*this, sorted, link, i); + if (linkIndex < 0) + continue; + if ((unsigned)linkIndex >= i) + continue; // we don't support forward links that can lead to loops + const CRefItem &linkRef = _refs[linkIndex]; + const CItem &linkItem = _items[linkRef.Item]; + if (linkItem.Size == item.Size) + { + if (linkRef.Link >= 0) + ref.Link = linkRef.Link; + else if (!linkItem.NeedUse_as_CopyLink()) + ref.Link = linkIndex; + } + } +} + + + +HRESULT CHandler::Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + CMyComPtr openVolumeCallback; + // CMyComPtr getTextPassword; + NRar::CVolumeName seqName; + CTempBuf tempBuf; + CUnpacker unpacker; + + if (openCallback) + { + openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword); + } + // unpacker.getTextPassword = getTextPassword; + + CInArchive arch; + int prevSplitFile = -1; + int prevMainFile = -1; + UInt64 totalBytes = 0; + UInt64 curBytes = 0; + bool nextVol_is_Required = false; + + for (;;) + { + CMyComPtr inStream; + + if (_arcs.IsEmpty()) + inStream = stream; + else + { + if (!openVolumeCallback) + break; + if (_arcs.Size() == 1) + { + UString baseName; + { + NCOM::CPropVariant prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) + if (prop.vt != VT_BSTR) + break; + baseName = prop.bstrVal; + } + if (!seqName.InitName(baseName)) + break; + } + const UString volName = seqName.GetNextName(); + const HRESULT result = openVolumeCallback->GetStream(volName, &inStream); + if (result != S_OK && result != S_FALSE) + return result; + if (!inStream || result != S_OK) + { + if (nextVol_is_Required) + _missingVolName = volName; + break; + } + } + + UInt64 endPos = 0; + RINOK(InStream_GetPos_GetSize(inStream, arch.StreamStartPosition, endPos)) + + if (openCallback) + { + totalBytes += endPos; + RINOK(openCallback->SetTotal(NULL, &totalBytes)) + } + + CInArcInfo arcInfo_Open; + { + const HRESULT res = arch.Open(inStream, maxCheckStartPosition, unpacker.getTextPassword, arcInfo_Open); + if (arch.IsArc && arch.UnexpectedEnd) + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + if (_arcs.IsEmpty()) + _isArc = arch.IsArc; + if (res != S_OK) + { + if (res != S_FALSE) + return res; + if (_arcs.IsEmpty()) + return res; + break; + } + } + + CArc &arc = _arcs.AddNew(); + CInArcInfo &arcInfo = arc.Info; + arcInfo = arcInfo_Open; + arc.Stream = inStream; + + CItem item; + + for (;;) + { + item.Clear(); + + arcInfo.EndPos = arch.Position; + if (arch.Position > endPos) + { + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + break; + } + RINOK(InStream_SeekSet(inStream, arch.Position)) + + { + CInArchive::CHeader h; + const HRESULT res = arch.ReadBlockHeader(h); + if (res != S_OK) + { + if (res != S_FALSE) + return res; + if (arch.UnexpectedEnd) + { + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + if (arcInfo.EndPos < arch.Position) + arcInfo.EndPos = arch.Position; + if (arcInfo.EndPos < endPos) + arcInfo.EndPos = endPos; + } + else + _errorFlags |= kpv_ErrorFlags_HeadersError; + break; + } + + if (h.Type == NHeaderType::kEndOfArc) + { + arcInfo.EndPos = arch.Position; + arcInfo.EndOfArchive_was_Read = true; + if (!arch.ReadVar(arcInfo.EndFlags)) + _errorFlags |= kpv_ErrorFlags_HeadersError; + if (!arch.Is_Buf_Finished() || h.ExtraSize || h.DataSize) + arcInfo.UnsupportedFeature = true; + if (arcInfo.IsVolume()) + { + // for multivolume archives RAR can add ZERO bytes at the end for alignment. + // We must skip these bytes to prevent phySize warning. + RINOK(InStream_SeekSet(inStream, arcInfo.EndPos)) + bool areThereNonZeros; + UInt64 numZeros; + const UInt64 maxSize = 1 << 12; + RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize)) + if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize) + arcInfo.EndPos += numZeros; + } + break; + } + + if (h.Type != NHeaderType::kFile && + h.Type != NHeaderType::kService) + { + _errorFlags |= kpv_ErrorFlags_UnsupportedFeature; + break; + } + + item.RecordType = (Byte)h.Type; + if (!arch.ReadFileHeader(h, item)) + { + _errorFlags |= kpv_ErrorFlags_HeadersError; + break; + } + item.DataPos = arch.Position; + } + + bool isOk_packSize = true; + { + arcInfo.EndPos = arch.Position; + if (arch.Position + item.PackSize < arch.Position) + { + isOk_packSize = false; + _errorFlags |= kpv_ErrorFlags_HeadersError; + if (arcInfo.EndPos < endPos) + arcInfo.EndPos = endPos; + } + else + { + arch.AddToSeekValue(item.PackSize); // Position points to next header; + arcInfo.EndPos = arch.Position; + } + } + + bool needAdd = true; + + if (!_comment_WasUsedInArc + && _comment.Size() == 0 + && item.Is_CMT()) + { + _comment_WasUsedInArc = true; + if ( item.PackSize <= kCommentSize_Max + && item.PackSize == item.Size + && item.PackSize != 0 + && item.Get_Method() == 0 + && !item.IsSplit()) + { + RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_VARS item, item.PackSize, inStream, _comment)) + needAdd = false; + // item.RecordType = (Byte)NHeaderType::kFile; // for debug + } + } + + CRefItem ref; + ref.Item = _items.Size(); + ref.Last = ref.Item; + ref.Parent = -1; + ref.Link = -1; + + if (needAdd) + { + if (item.IsService()) + { + if (item.Is_STM()) + { + if (prevMainFile >= 0) + ref.Parent = prevMainFile; + } + else + { + needAdd = false; + if (item.Is_ACL()) + { + _acl_Used = true; + if (item.IsEncrypted() && !arch.m_CryptoMode) + _error_in_ACL = true; + else if (item.IsSolid() + || prevMainFile < 0 + || item.Size >= (1 << 24) + || item.Size == 0) + _error_in_ACL = true; + if (prevMainFile >= 0 && item.Size < (1 << 24) && item.Size != 0) + { + CItem &mainItem = _items[_refs[prevMainFile].Item]; + + if (mainItem.ACL < 0) + { + CByteBuffer acl; + const HRESULT res = tempBuf.Decode(EXTERNAL_CODECS_VARS item, inStream, unpacker, acl); + if (!item.IsSplitAfter()) + tempBuf.Clear(); + if (res != S_OK) + { + tempBuf.Clear(); + if (res != S_FALSE && res != E_NOTIMPL) + return res; + _error_in_ACL = true; + } + else if (acl.Size() != 0) + { + if (_acls.IsEmpty() || acl != _acls.Back()) + _acls.Add(acl); + mainItem.ACL = (int)_acls.Size() - 1; + } + } + } + } + } + } // item.IsService() + + if (needAdd) + { + if (item.IsSplitBefore()) + { + if (prevSplitFile >= 0) + { + CRefItem &ref2 = _refs[prevSplitFile]; + CItem &prevItem = _items[ref2.Last]; + if (item.IsNextForItem(prevItem)) + { + ref2.Last = _items.Size(); + prevItem.NextItem = (int)ref2.Last; + needAdd = false; + } + } + else + _split_Error = true; + } + } + + if (needAdd) + { + if (item.IsSplitAfter()) + prevSplitFile = (int)_refs.Size(); + if (!item.IsService()) + prevMainFile = (int)_refs.Size(); + } + } + + { + UInt64 version; + if (item.FindExtra_Version(version)) + { + item.Version_Defined = true; + item.Version = version; + } + } + + item.VolIndex = _arcs.Size() - 1; + _items.Add(item); + if (needAdd) + _refs.Add(ref); + + if (openCallback && (_items.Size() & 0xFF) == 0) + { + const UInt64 numFiles = _refs.Size(); // _items.Size() + const UInt64 numBytes = curBytes + item.DataPos; + RINOK(openCallback->SetCompleted(&numFiles, &numBytes)) + } + + if (!isOk_packSize) + break; + } + + curBytes += endPos; + + nextVol_is_Required = false; + + if (!arcInfo.IsVolume()) + break; + + if (arcInfo.EndOfArchive_was_Read) + { + if (!arcInfo.AreMoreVolumes()) + break; + nextVol_is_Required = true; + } + } + + FillLinks(); + return S_OK; +} + + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback)) +{ + COM_TRY_BEGIN + Close(); + return Open2(stream, maxCheckStartPosition, openCallback); + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + COM_TRY_BEGIN + _missingVolName.Empty(); + _errorFlags = 0; + // _warningFlags = 0; + _isArc = false; + _comment_WasUsedInArc = false; + _acl_Used = false; + _error_in_ACL = false; + _split_Error = false; + _numBlocks = 0; + _rar5comapt_mask = 0; + _algo_Mask = 0; // (UInt64)0u - 1; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(_methodMasks); i++) + { + _methodMasks[i] = 0; + _dictMaxSizes[i] = 0; + } + + _refs.Clear(); + _items.Clear(); + _arcs.Clear(); + _acls.Clear(); + _comment.Free(); + return S_OK; + COM_TRY_END +} + + +Z7_CLASS_IMP_NOQIB_1( + CVolsInStream + , ISequentialInStream +) + UInt64 _rem; + ISequentialInStream *_stream; + const CObjectVector *_arcs; + const CObjectVector *_items; + int _itemIndex; +public: + bool CrcIsOK; +private: + CHash _hash; +public: + void Init(const CObjectVector *arcs, + const CObjectVector *items, + unsigned itemIndex) + { + _arcs = arcs; + _items = items; + _itemIndex = (int)itemIndex; + _stream = NULL; + CrcIsOK = true; + } +}; + +Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + UInt32 realProcessedSize = 0; + + while (size != 0) + { + if (!_stream) + { + if (_itemIndex < 0) + break; + const CItem &item = (*_items)[_itemIndex]; + IInStream *s = (*_arcs)[item.VolIndex].Stream; + RINOK(InStream_SeekSet(s, item.GetDataPosition())) + _stream = s; + if (CrcIsOK && item.IsSplitAfter()) + _hash.Init(item); + else + _hash.Init_NoCalc(); + _rem = item.PackSize; + } + { + UInt32 cur = size; + if (cur > _rem) + cur = (UInt32)_rem; + const UInt32 num = cur; + HRESULT res = _stream->Read(data, cur, &cur); + _hash.Update(data, cur); + realProcessedSize += cur; + if (processedSize) + *processedSize = realProcessedSize; + data = (Byte *)data + cur; + size -= cur; + _rem -= cur; + if (_rem == 0) + { + const CItem &item = (*_items)[_itemIndex]; + _itemIndex = item.NextItem; + if (!_hash.Check(item, NULL)) // RAR doesn't use MAC here + CrcIsOK = false; + _stream = NULL; + } + if (res != S_OK) + return res; + if (realProcessedSize != 0) + return S_OK; + if (cur == 0 && num != 0) + return S_OK; + } + } + + return S_OK; +} + + +static int FindLinkBuf(CObjectVector &linkFiles, unsigned index) +{ + unsigned left = 0, right = linkFiles.Size(); + for (;;) + { + if (left == right) + return -1; + const unsigned mid = (left + right) / 2; + const unsigned linkIndex = linkFiles[mid].Index; + if (index == linkIndex) + return (int)mid; + if (index < linkIndex) + right = mid; + else + left = mid + 1; + } +} + + +static inline int DecoderRes_to_OpRes(HRESULT res, bool crcOK) +{ + if (res == E_NOTIMPL) + return NExtract::NOperationResult::kUnsupportedMethod; + // if (res == S_FALSE) + if (res != S_OK) + return NExtract::NOperationResult::kDataError; + return crcOK ? + NExtract::NOperationResult::kOK : + NExtract::NOperationResult::kCRCError; +} + + +static HRESULT CopyData_with_Progress(const Byte *data, size_t size, + ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + UInt64 pos64 = 0; + while (size) + { + const UInt32 kStepSize = (UInt32)1 << 24; + UInt32 cur = kStepSize; + if (cur > size) + cur = (UInt32)size; + RINOK(outStream->Write(data, cur, &cur)) + if (cur == 0) + return E_FAIL; + size -= cur; + data += cur; + pos64 += cur; + if (progress) + { + RINOK(progress->SetRatioInfo(&pos64, &pos64)) + } + } + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = (UInt32)_refs.Size(); + if (numItems == 0) + return S_OK; + + CByteArr extractStatuses(_refs.Size()); + memset(extractStatuses, 0, _refs.Size()); + + // we don't want to use temp buffer for big link files. + const size_t k_CopyLinkFile_MaxSize = (size_t)1 << (28 + sizeof(size_t) / 2); + + const Byte kStatus_Extract = 1 << 0; + const Byte kStatus_Skip = 1 << 1; + const Byte kStatus_Link = 1 << 2; + + /* + In original RAR: + 1) service streams are not allowed to be solid, + and solid flag must be ignored for service streams. + 2) If RAR creates new solid block and first file in solid block is Link file, + then it can clear solid flag for Link file and + clear solid flag for first non-Link file after Link file. + */ + + CObjectVector linkFiles; + + { + UInt64 total = 0; + bool isThereUndefinedSize = false; + bool thereAreLinks = false; + { + unsigned solidLimit = 0; + for (UInt32 t = 0; t < numItems; t++) + { + const unsigned index = (unsigned)(allFilesMode ? t : indices[t]); + const CRefItem &ref = _refs[index]; + const CItem &item = _items[ref.Item]; + const CItem &lastItem = _items[ref.Last]; + + extractStatuses[index] |= kStatus_Extract; + + if (!lastItem.Is_UnknownSize()) + total += lastItem.Size; + else + isThereUndefinedSize = true; + + if (ref.Link >= 0) + { + // 18.06 fixed: we use links for Test mode too + // if (!testMode) + { + if ((unsigned)ref.Link < index) + { + const CRefItem &linkRef = _refs[(unsigned)ref.Link]; + const CItem &linkItem = _items[linkRef.Item]; + if (linkItem.IsSolid()) + if (testMode || linkItem.Size <= k_CopyLinkFile_MaxSize) + { + if (extractStatuses[(unsigned)ref.Link] == 0) + { + const CItem &lastLinkItem = _items[linkRef.Last]; + if (!lastLinkItem.Is_UnknownSize()) + total += lastLinkItem.Size; + else + isThereUndefinedSize = true; + } + extractStatuses[(unsigned)ref.Link] |= kStatus_Link; + thereAreLinks = true; + } + } + } + continue; + } + + if (item.IsService()) + continue; + + if (item.IsSolid()) + { + unsigned j = index; + + while (j > solidLimit) + { + j--; + const CRefItem &ref2 = _refs[j]; + const CItem &item2 = _items[ref2.Item]; + if (!item2.IsService()) + { + if (extractStatuses[j] == 0) + { + const CItem &lastItem2 = _items[ref2.Last]; + if (!lastItem2.Is_UnknownSize()) + total += lastItem2.Size; + else + isThereUndefinedSize = true; + } + extractStatuses[j] |= kStatus_Skip; + if (!item2.IsSolid()) + break; + } + } + } + + solidLimit = index + 1; + } + } + + if (thereAreLinks) + { + unsigned solidLimit = 0; + + FOR_VECTOR (i, _refs) + { + if ((extractStatuses[i] & kStatus_Link) == 0) + continue; + + // We use CLinkFile for testMode too. + // So we can show errors for copy files. + // if (!testMode) + { + CLinkFile &linkFile = linkFiles.AddNew(); + linkFile.Index = i; + } + + const CItem &item = _items[_refs[i].Item]; + /* + if (item.IsService()) + continue; + */ + + if (item.IsSolid()) + { + unsigned j = i; + + while (j > solidLimit) + { + j--; + const CRefItem &ref2 = _refs[j]; + const CItem &item2 = _items[ref2.Item]; + if (!item2.IsService()) + { + if (extractStatuses[j] != 0) + break; + extractStatuses[j] = kStatus_Skip; + { + const CItem &lastItem2 = _items[ref2.Last]; + if (!lastItem2.Is_UnknownSize()) + total += lastItem2.Size; + else + isThereUndefinedSize = true; + } + if (!item2.IsSolid()) + break; + } + } + } + + solidLimit = i + 1; + } + + if (!testMode) + for (UInt32 t = 0; t < numItems; t++) + { + const unsigned index = (unsigned)(allFilesMode ? t : indices[t]); + const CRefItem &ref = _refs[index]; + + const int linkIndex = ref.Link; + if (linkIndex < 0 || (unsigned)linkIndex >= index) + continue; + const CItem &linkItem = _items[_refs[(unsigned)linkIndex].Item]; + if (!linkItem.IsSolid() || linkItem.Size > k_CopyLinkFile_MaxSize) + continue; + const int bufIndex = FindLinkBuf(linkFiles, (unsigned)linkIndex); + if (bufIndex < 0) + return E_FAIL; + linkFiles[bufIndex].NumLinks++; + } + } + + if (total != 0 || !isThereUndefinedSize) + { + RINOK(extractCallback->SetTotal(total)) + } + } + + + + // ---------- MEMORY REQUEST ---------- + { + UInt64 dictMaxSize = 0; + for (UInt32 i = 0; i < _refs.Size(); i++) + { + if (extractStatuses[i] == 0) + continue; + const CRefItem &ref = _refs[i]; + const CItem &item = _items[ref.Item]; +/* + if (!item.IsDir() && !item.IsService() && item.NeedUse_as_CopyLink()) + { + } +*/ + const unsigned algo = item.Get_AlgoVersion_RawBits(); + if (!item.IsDir() && algo < Z7_ARRAY_SIZE(_methodMasks)) + { + const UInt64 d = item.Get_DictSize64(); + if (dictMaxSize < d) + dictMaxSize = d; + } + } + // we use callback, if dict exceeds (1 GB), because + // client code can set low limit (1 GB) for allowed memory usage. + const UInt64 k_MemLimit_for_Callback = (UInt64)1 << 30; + if (dictMaxSize > (_memUsage_WasSet ? + _memUsage_Decompress : k_MemLimit_for_Callback)) + { + { + CMyComPtr requestMem; + extractCallback->QueryInterface(IID_IArchiveRequestMemoryUseCallback, (void **)&requestMem); + if (!requestMem) + { + if (_memUsage_WasSet) + return E_OUTOFMEMORY; + } + else + { + UInt64 allowedSize = _memUsage_WasSet ? + _memUsage_Decompress : + (UInt64)1 << 32; // 4 GB is default allowed limit for RAR7 + + const UInt32 flags = (_memUsage_WasSet ? + NRequestMemoryUseFlags::k_AllowedSize_WasForced | + NRequestMemoryUseFlags::k_MLimit_Exceeded : + (dictMaxSize > allowedSize) ? + NRequestMemoryUseFlags::k_DefaultLimit_Exceeded: + 0) + | NRequestMemoryUseFlags::k_SkipArc_IsExpected + // | NRequestMemoryUseFlags::k_NoErrorMessage // for debug + ; + + // we set "Allow" for default case, if requestMem doesn't process anything. + UInt32 answerFlags = + (_memUsage_WasSet && dictMaxSize > allowedSize) ? + NRequestMemoryAnswerFlags::k_Limit_Exceeded + | NRequestMemoryAnswerFlags::k_SkipArc + : NRequestMemoryAnswerFlags::k_Allow; + + RINOK(requestMem->RequestMemoryUse( + flags, + NEventIndexType::kNoIndex, + // NEventIndexType::kInArcIndex, // for debug + 0, // index + NULL, // path + dictMaxSize, &allowedSize, &answerFlags)) + if ( (answerFlags & NRequestMemoryAnswerFlags::k_Allow) == 0 + || (answerFlags & NRequestMemoryAnswerFlags::k_Stop) + || (answerFlags & NRequestMemoryAnswerFlags::k_SkipArc) + ) + { + return E_OUTOFMEMORY; + } +/* + if ((answerFlags & NRequestMemoryAnswerFlags::k_AskForBigFile) == 0 && + (answerFlags & NRequestMemoryAnswerFlags::k_ReportForBigFile) == 0) + { + // requestMem.Release(); + } +*/ + } + } + } + } + + + + // ---------- UNPACK ---------- + + UInt64 totalUnpacked = 0; + UInt64 totalPacked = 0; + UInt64 curUnpackSize; + UInt64 curPackSize; + + CUnpacker unpacker; + unpacker.NeedCrc = _needChecksumCheck; + CMyComPtr2_Create volsInStream; + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + +/* + bool prevSolidWasSkipped = false; + UInt64 solidDictSize_Skip = 0; +*/ + + for (unsigned i = 0;; i++, + totalUnpacked += curUnpackSize, + totalPacked += curPackSize) + { + lps->InSize = totalPacked; + lps->OutSize = totalUnpacked; + RINOK(lps->SetCur()) + { + const unsigned num = _refs.Size(); + if (i >= num) + break; + for (;;) + { + if (extractStatuses[i] != 0) + break; + i++; + if (i >= num) + break; + } + if (i >= num) + break; + } + curUnpackSize = 0; + curPackSize = 0; + + // isExtract means that we don't skip that item. So we need read data. + const bool isExtract = ((extractStatuses[i] & kStatus_Extract) != 0); + Int32 askMode = + isExtract ? (testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + + unpacker.linkFile = NULL; + + // if (!testMode) + if ((extractStatuses[i] & kStatus_Link) != 0) + { + const int bufIndex = FindLinkBuf(linkFiles, i); + if (bufIndex < 0) + return E_FAIL; + unpacker.linkFile = &linkFiles[bufIndex]; + } + + const unsigned index = i; + const CRefItem *ref = &_refs[index]; + const CItem *item = &_items[ref->Item]; + const CItem &lastItem = _items[ref->Last]; + + curUnpackSize = 0; + if (!lastItem.Is_UnknownSize()) + curUnpackSize = lastItem.Size; + + curPackSize = GetPackSize(index); + + bool isSolid = false; + if (!item->IsService()) + { + if (item->IsSolid()) + isSolid = unpacker.SolidAllowed; + unpacker.SolidAllowed = isSolid; + } + + + // ----- request mem ----- +/* + // link files are complicated cases. (ref->Link >= 0) + // link file can refer to non-solid file that can have big dictionary + // link file can refer to solid files that requres buffer + if (!item->IsDir() && requestMem && ref->Link < 0) + { + bool needSkip = false; + if (isSolid) + needSkip = prevSolidWasSkipped; + else + { + // isSolid == false + const unsigned algo = item->Get_AlgoVersion_RawBits(); + // const unsigned m = item.Get_Method(); + if (algo < Z7_ARRAY_SIZE(_methodMasks)) + { + solidDictSize_Skip = item->Get_DictSize64(); + if (solidDictSize_Skip > allowedSize) + needSkip = true; + } + } + if (needSkip) + { + UInt32 answerFlags = 0; + UInt64 allowedSize_File = allowedSize; + RINOK(requestMem->RequestMemoryUse( + NRequestMemoryUseFlags::k_Limit_Exceeded | + NRequestMemoryUseFlags::k_IsReport, + NEventIndexType::kInArcIndex, + index, + NULL, // path + solidDictSize_Skip, &allowedSize_File, &answerFlags)) + if (!item->IsService()) + prevSolidWasSkipped = true; + continue; + } + } + if (!item->IsService() && item->IsDir()) + prevSolidWasSkipped = false; +*/ + + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream((UInt32)index, &realOutStream, askMode)) + + if (item->IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const int index2 = ref->Link; + + int bufIndex = -1; + + if (index2 >= 0) + { + const CRefItem &ref2 = _refs[index2]; + const CItem &item2 = _items[ref2.Item]; + const CItem &lastItem2 = _items[ref2.Last]; + if (!item2.IsSolid()) + { + item = &item2; + ref = &ref2; + if (!lastItem2.Is_UnknownSize()) + curUnpackSize = lastItem2.Size; + else + curUnpackSize = 0; + curPackSize = GetPackSize((unsigned)index2); + } + else + { + if ((unsigned)index2 < index) + bufIndex = FindLinkBuf(linkFiles, (unsigned)index2); + } + } + + bool needCallback = true; + + if (!realOutStream) + { + if (testMode) + { + if (item->NeedUse_as_CopyLink_or_HardLink()) + { + Int32 opRes = NExtract::NOperationResult::kOK; + if (bufIndex >= 0) + { + const CLinkFile &linkFile = linkFiles[bufIndex]; + opRes = DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK); + } + + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(opRes)) + continue; + } + } + else + { + if (item->IsService()) + continue; + + needCallback = false; + + if (!item->NeedUse_as_HardLink()) + if (index2 < 0) + + for (unsigned n = i + 1; n < _refs.Size(); n++) + { + const CItem &nextItem = _items[_refs[n].Item]; + if (nextItem.IsService()) + continue; + if (!nextItem.IsSolid()) + break; + if (extractStatuses[i] != 0) + { + needCallback = true; + break; + } + } + + askMode = NExtract::NAskMode::kSkip; + } + } + + if (needCallback) + { + RINOK(extractCallback->PrepareOperation(askMode)) + } + + if (bufIndex >= 0) + { + CLinkFile &linkFile = linkFiles[bufIndex]; + + if (isExtract) + { + if (linkFile.NumLinks == 0) + return E_FAIL; + + if (needCallback) + if (realOutStream) + { + RINOK(CopyData_with_Progress(linkFile.Data, linkFile.Data.Size(), realOutStream, lps)) + } + + if (--linkFile.NumLinks == 0) + linkFile.Data.Free(); + } + + if (needCallback) + { + RINOK(extractCallback->SetOperationResult(DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK))) + } + continue; + } + + if (!needCallback) + continue; + + if (item->NeedUse_as_CopyLink()) + { + const int opRes = realOutStream ? + NExtract::NOperationResult::kUnsupportedMethod: + NExtract::NOperationResult::kOK; + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)) + continue; + } + + volsInStream->Init(&_arcs, &_items, ref->Item); + + const UInt64 packSize = curPackSize; + + if (item->IsEncrypted()) + if (!unpacker.getTextPassword) + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword); + + bool wrongPassword; + HRESULT result = unpacker.Create(EXTERNAL_CODECS_VARS *item, isSolid, wrongPassword); + + if (wrongPassword) + { + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kWrongPassword)) + continue; + } + + bool crcOK = true; + if (result == S_OK) + result = unpacker.Code(*item, _items[ref->Last], packSize, volsInStream, realOutStream, lps, crcOK); + realOutStream.Release(); + if (!volsInStream->CrcIsOK) + crcOK = false; + + int opRes = crcOK ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kCRCError; + + if (result != S_OK) + { + if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return result; + } + + RINOK(extractCallback->SetOperationResult(opRes)) + } + + { + FOR_VECTOR (k, linkFiles) + if (linkFiles[k].NumLinks != 0) + return E_FAIL; + } + + return S_OK; + COM_TRY_END +} + + +CHandler::CHandler() +{ + InitDefaults(); +} + +void CHandler::InitDefaults() +{ + _needChecksumCheck = true; + _memUsage_WasSet = false; + _memUsage_Decompress = (UInt64)1 << 32; +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + InitDefaults(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name.IsPrefixedBy_Ascii_NoCase("mt")) + { + } + else if (name.IsPrefixedBy_Ascii_NoCase("memx")) + { + size_t memAvail; + if (!NWindows::NSystem::GetRamSize(memAvail)) + memAvail = (size_t)sizeof(size_t) << 28; + UInt64 v; + if (!ParseSizeString(name.Ptr(4), prop, memAvail, v)) + return E_INVALIDARG; + _memUsage_Decompress = v; + _memUsage_WasSet = true; + } + else if (name.IsPrefixedBy_Ascii_NoCase("crc")) + { + name.Delete(0, 3); + UInt32 crcSize = 1; + RINOK(ParsePropToUInt32(name, prop, crcSize)) + _needChecksumCheck = (crcSize != 0); + } + else + { + return E_INVALIDARG; + } + } + return S_OK; +} + + +IMPL_ISetCompressCodecsInfo + +REGISTER_ARC_I( + "Rar5", "rar r00", NULL, 0xCC, + kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} + + +Z7_CLASS_IMP_COM_2( + CBlake2spHasher + , IHasher + , ICompressSetCoderProperties +) + CAlignedBuffer1 _buf; + // CBlake2sp _blake; + #define Z7_BLACK2S_ALIGN_OBJECT_OFFSET 0 + CBlake2sp *Obj() { return (CBlake2sp *)(void *)((Byte *)_buf + Z7_BLACK2S_ALIGN_OBJECT_OFFSET); } +public: + Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field + CBlake2spHasher(): + _buf(sizeof(CBlake2sp) + Z7_BLACK2S_ALIGN_OBJECT_OFFSET) + { + Blake2sp_SetFunction(Obj(), 0); + Blake2sp_InitState(Obj()); + } +}; + +Z7_COM7F_IMF2(void, CBlake2spHasher::Init()) +{ + Blake2sp_InitState(Obj()); +} + +Z7_COM7F_IMF2(void, CBlake2spHasher::Update(const void *data, UInt32 size)) +{ +#if 1 + Blake2sp_Update(Obj(), (const Byte *)data, (size_t)size); +#else + // for debug: + for (;;) + { + if (size == 0) + return; + UInt32 size2 = (size * 0x85EBCA87) % size / 800; + // UInt32 size2 = size / 2; + if (size2 == 0) + size2 = 1; + Blake2sp_Update(Obj(), (const Byte *)data, size2); + data = (const void *)((const Byte *)data + size2); + size -= size2; + } +#endif +} + +Z7_COM7F_IMF2(void, CBlake2spHasher::Final(Byte *digest)) +{ + Blake2sp_Final(Obj(), digest); +} + +Z7_COM7F_IMF(CBlake2spHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + unsigned algo = 0; + for (UInt32 i = 0; i < numProps; i++) + { + if (propIDs[i] == NCoderPropID::kDefaultProp) + { + const PROPVARIANT &prop = coderProps[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + /* + if (prop.ulVal > Z7_BLAKE2S_ALGO_MAX) + return E_NOTIMPL; + */ + algo = (unsigned)prop.ulVal; + } + } + if (!Blake2sp_SetFunction(Obj(), algo)) + return E_NOTIMPL; + return S_OK; +} + +REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", Z7_BLAKE2S_DIGEST_SIZE) + +static struct CBlake2sp_Prepare { CBlake2sp_Prepare() { z7_Black2sp_Prepare(); } } g_Blake2sp_Prepare; diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h index 744f97a59..8f6581ae2 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.h +++ b/CPP/7zip/Archive/Rar/Rar5Handler.h @@ -1,527 +1,527 @@ -// Rar5Handler.h - -#ifndef ZIP7_INC_RAR5_HANDLER_H -#define ZIP7_INC_RAR5_HANDLER_H - -#include "../../../../C/Blake2.h" - -#include "../../../Common/MyBuffer.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../Common/CreateCoder.h" - -#include "../IArchive.h" - -namespace NArchive { -namespace NRar5 { - -namespace NHeaderFlags -{ - const unsigned kExtra = 1 << 0; - const unsigned kData = 1 << 1; - // const unsigned kUnknown = 1 << 2; - const unsigned kPrevVol = 1 << 3; - const unsigned kNextVol = 1 << 4; - // const unsigned kIsChild = 1 << 5; - // const unsigned kPreserveChild = 1 << 6; -} - -namespace NHeaderType -{ - enum - { - kArc = 1, - kFile, - kService, - kArcEncrypt, - kEndOfArc - }; -} - -namespace NArcFlags -{ - const unsigned kVol = 1 << 0; - const unsigned kVolNumber = 1 << 1; - const unsigned kSolid = 1 << 2; - // const unsigned kRecovery = 1 << 3; - // const unsigned kLocked = 1 << 4; -} - -const unsigned kArcExtraRecordType_Locator = 1; -const unsigned kArcExtraRecordType_Metadata = 2; - -namespace NLocatorFlags -{ - const unsigned kQuickOpen = 1 << 0; - const unsigned kRecovery = 1 << 1; -} - -namespace NMetadataFlags -{ - const unsigned kArcName = 1 << 0; - const unsigned kCTime = 1 << 1; - const unsigned kUnixTime = 1 << 2; - const unsigned kNanoSec = 1 << 3; -} - -namespace NFileFlags -{ - const unsigned kIsDir = 1 << 0; - const unsigned kUnixTime = 1 << 1; - const unsigned kCrc32 = 1 << 2; - const unsigned kUnknownSize = 1 << 3; -} - -namespace NMethodFlags -{ - // const unsigned kVersionMask = 0x3F; - const unsigned kSolid = 1 << 6; - const unsigned kRar5_Compat = 1u << 20; -} - -namespace NArcEndFlags -{ - const unsigned kMoreVols = 1 << 0; -} - -enum EHostOS -{ - kHost_Windows = 0, - kHost_Unix -}; - - - -// ---------- Extra ---------- - -namespace NExtraID -{ - enum - { - kCrypto = 1, - kHash, - kTime, - kVersion, - kLink, - kUnixOwner, - kSubdata - }; -} - -const unsigned kCryptoAlgo_AES = 0; - -namespace NCryptoFlags -{ - const unsigned kPswCheck = 1 << 0; - const unsigned kUseMAC = 1 << 1; -} - -struct CCryptoInfo -{ - UInt64 Algo; - UInt64 Flags; - Byte Cnt; - - bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; } - bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; } - bool Parse(const Byte *p, size_t size); -}; - -const unsigned kHashID_Blake2sp = 0; - -namespace NTimeRecord -{ - enum - { - k_Index_MTime = 0, - k_Index_CTime, - k_Index_ATime - }; - - namespace NFlags - { - const unsigned kUnixTime = 1 << 0; - const unsigned kMTime = 1 << 1; - const unsigned kCTime = 1 << 2; - const unsigned kATime = 1 << 3; - const unsigned kUnixNs = 1 << 4; - } -} - -namespace NLinkType -{ - enum - { - kUnixSymLink = 1, - kWinSymLink, - kWinJunction, - kHardLink, - kFileCopy - }; -} - -namespace NLinkFlags -{ - const unsigned kTargetIsDir = 1 << 0; -} - - -struct CLinkInfo -{ - UInt64 Type; - UInt64 Flags; - unsigned NameOffset; - unsigned NameLen; - - bool Parse(const Byte *p, unsigned size); -}; - - -struct CItem -{ - UInt32 CommonFlags; - UInt32 Flags; - - Byte RecordType; - bool Version_Defined; - - int ACL; - - AString Name; - - unsigned VolIndex; - int NextItem; // in _items{} - - UInt32 UnixMTime; - UInt32 CRC; - UInt32 Attrib; - UInt32 Method; - - CByteBuffer Extra; - - UInt64 Size; - UInt64 PackSize; - UInt64 HostOS; - - UInt64 DataPos; - UInt64 Version; - - CItem() { Clear(); } - - void Clear() - { - // CommonFlags = 0; - // Flags = 0; - - // UnixMTime = 0; - // CRC = 0; - - VolIndex = 0; - NextItem = -1; - - Version_Defined = false; - Version = 0; - - Name.Empty(); - Extra.Free(); - ACL = -1; - } - - bool IsSplitBefore() const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; } - bool IsSplitAfter() const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; } - bool IsSplit() const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; } - - bool IsDir() const { return (Flags & NFileFlags::kIsDir) != 0; } - bool Has_UnixMTime() const { return (Flags & NFileFlags::kUnixTime) != 0; } - bool Has_CRC() const { return (Flags & NFileFlags::kCrc32) != 0; } - bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; } - - bool IsNextForItem(const CItem &prev) const - { - return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name); - // && false; - } - - // rar docs: Solid flag can be set only for file headers and is never set for service headers. - bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; } - bool Is_Rar5_Compat() const { return ((UInt32)Method & NMethodFlags::kRar5_Compat) != 0; } - unsigned Get_Rar5_CompatBit() const { return ((UInt32)Method >> 20) & 1; } - - unsigned Get_AlgoVersion_RawBits() const { return (unsigned)Method & 0x3F; } - unsigned Get_AlgoVersion_HuffRev() const - { - unsigned w = (unsigned)Method & 0x3F; - if (w == 1 && Is_Rar5_Compat()) - w = 0; - return w; - } - unsigned Get_Method() const { return ((unsigned)Method >> 7) & 0x7; } - - unsigned Get_DictSize_Main() const - { return ((UInt32)Method >> 10) & (Get_AlgoVersion_RawBits() == 0 ? 0xf : 0x1f); } - unsigned Get_DictSize_Frac() const - { - // original-unrar ignores Frac, if (algo==0) (rar5): - if (Get_AlgoVersion_RawBits() == 0) - return 0; - return ((UInt32)Method >> 15) & 0x1f; - } - UInt64 Get_DictSize64() const - { - // ver 6.* check - // return (((UInt32)Method >> 10) & 0xF); - UInt64 winSize = 0; - const unsigned algo = Get_AlgoVersion_RawBits(); - if (algo <= 1) - { - UInt32 w = 32; - if (algo == 1) - w += Get_DictSize_Frac(); - winSize = (UInt64)w << (12 + Get_DictSize_Main()); - } - return winSize; - } - - - bool IsService() const { return RecordType == NHeaderType::kService; } - - bool Is_STM() const { return IsService() && Name == "STM"; } - bool Is_CMT() const { return IsService() && Name == "CMT"; } - bool Is_ACL() const { return IsService() && Name == "ACL"; } - // bool Is_QO() const { return IsService() && Name == "QO"; } - - int FindExtra(unsigned extraID, unsigned &recordDataSize) const; - void PrintInfo(AString &s) const; - - - bool IsEncrypted() const - { - unsigned size; - return FindExtra(NExtraID::kCrypto, size) >= 0; - } - - int FindExtra_Blake() const - { - unsigned size = 0; - const int offset = FindExtra(NExtraID::kHash, size); - if (offset >= 0 - && size == Z7_BLAKE2S_DIGEST_SIZE + 1 - && Extra[(unsigned)offset] == kHashID_Blake2sp) - return offset + 1; - return -1; - } - - bool FindExtra_Version(UInt64 &version) const; - - bool FindExtra_Link(CLinkInfo &link) const; - void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const; - bool Is_CopyLink() const; - bool Is_HardLink() const; - bool Is_CopyLink_or_HardLink() const; - - bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); } - bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); } - bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); } - - bool GetAltStreamName(AString &name) const; - - UInt32 GetWinAttrib() const - { - UInt32 a; - switch (HostOS) - { - case kHost_Windows: - a = Attrib; - break; - case kHost_Unix: - a = Attrib << 16; - a |= 0x8000; // add posix mode marker - break; - default: - a = 0; - } - if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY; - return a; - } - - UInt64 GetDataPosition() const { return DataPos; } -}; - - -struct CInArcInfo -{ - UInt64 Flags; - UInt64 VolNumber; - UInt64 StartPos; - UInt64 EndPos; - - UInt64 EndFlags; - bool EndOfArchive_was_Read; - - bool IsEncrypted; - bool Locator_Defined; - bool Locator_Error; - bool Metadata_Defined; - bool Metadata_Error; - bool UnknownExtraRecord; - bool Extra_Error; - bool UnsupportedFeature; - - struct CLocator - { - UInt64 Flags; - UInt64 QuickOpen; - UInt64 Recovery; - - bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; } - bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; } - - bool Parse(const Byte *p, size_t size); - CLocator(): - Flags(0), - QuickOpen(0), - Recovery(0) - {} - }; - - struct CMetadata - { - UInt64 Flags; - UInt64 CTime; - AString ArcName; - - bool Parse(const Byte *p, size_t size); - CMetadata(): - Flags(0), - CTime(0) - {} - }; - - CLocator Locator; - CMetadata Metadata; - - bool ParseExtra(const Byte *p, size_t size); - - CInArcInfo(): - Flags(0), - VolNumber(0), - StartPos(0), - EndPos(0), - EndFlags(0), - EndOfArchive_was_Read(false), - IsEncrypted(false), - Locator_Defined(false), - Locator_Error(false), - Metadata_Defined(false), - Metadata_Error(false), - UnknownExtraRecord(false), - Extra_Error(false), - UnsupportedFeature(false) - {} - - /* - void Clear() - { - Flags = 0; - VolNumber = 0; - StartPos = 0; - EndPos = 0; - EndFlags = 0; - EndOfArchive_was_Read = false; - } - */ - - UInt64 GetPhySize() const { return EndPos - StartPos; } - - bool AreMoreVolumes() const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; } - - bool IsVolume() const { return (Flags & NArcFlags::kVol) != 0; } - bool IsSolid() const { return (Flags & NArcFlags::kSolid) != 0; } - bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; } - - UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; } -}; - - -struct CRefItem -{ - unsigned Item; // First item in _items[] - unsigned Last; // Last item in _items[] - int Parent; // in _refs[], if alternate stream - int Link; // in _refs[] -}; - - -struct CArc -{ - CMyComPtr Stream; - CInArcInfo Info; -}; - - -class CHandler Z7_final: - public IInArchive, - public IArchiveGetRawProps, - public ISetProperties, - Z7_PUBLIC_ISetCompressCodecsInfo_IFEC - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IInArchive) - Z7_COM_QI_ENTRY(IArchiveGetRawProps) - Z7_COM_QI_ENTRY(ISetProperties) - Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInArchive) - Z7_IFACE_COM7_IMP(IArchiveGetRawProps) - Z7_IFACE_COM7_IMP(ISetProperties) - DECL_ISetCompressCodecsInfo - - void InitDefaults(); - - bool _isArc; - bool _needChecksumCheck; - bool _memUsage_WasSet; - bool _comment_WasUsedInArc; - bool _acl_Used; - bool _error_in_ACL; - bool _split_Error; -public: - CRecordVector _refs; - CObjectVector _items; - - CHandler(); -private: - CObjectVector _arcs; - CObjectVector _acls; - - UInt32 _errorFlags; - // UInt32 _warningFlags; - - UInt32 _numBlocks; - unsigned _rar5comapt_mask; - unsigned _methodMasks[2]; - UInt64 _algo_Mask; - UInt64 _dictMaxSizes[2]; - - CByteBuffer _comment; - UString _missingVolName; - - UInt64 _memUsage_Decompress; - - DECL_EXTERNAL_CODECS_VARS - - UInt64 GetPackSize(unsigned refIndex) const; - - void FillLinks(); - - HRESULT Open2(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback); -}; - -}} - -#endif +// Rar5Handler.h + +#ifndef ZIP7_INC_RAR5_HANDLER_H +#define ZIP7_INC_RAR5_HANDLER_H + +#include "../../../../C/Blake2.h" + +#include "../../../Common/MyBuffer.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Common/CreateCoder.h" + +#include "../IArchive.h" + +namespace NArchive { +namespace NRar5 { + +namespace NHeaderFlags +{ + const unsigned kExtra = 1 << 0; + const unsigned kData = 1 << 1; + // const unsigned kUnknown = 1 << 2; + const unsigned kPrevVol = 1 << 3; + const unsigned kNextVol = 1 << 4; + // const unsigned kIsChild = 1 << 5; + // const unsigned kPreserveChild = 1 << 6; +} + +namespace NHeaderType +{ + enum + { + kArc = 1, + kFile, + kService, + kArcEncrypt, + kEndOfArc + }; +} + +namespace NArcFlags +{ + const unsigned kVol = 1 << 0; + const unsigned kVolNumber = 1 << 1; + const unsigned kSolid = 1 << 2; + // const unsigned kRecovery = 1 << 3; + // const unsigned kLocked = 1 << 4; +} + +const unsigned kArcExtraRecordType_Locator = 1; +const unsigned kArcExtraRecordType_Metadata = 2; + +namespace NLocatorFlags +{ + const unsigned kQuickOpen = 1 << 0; + const unsigned kRecovery = 1 << 1; +} + +namespace NMetadataFlags +{ + const unsigned kArcName = 1 << 0; + const unsigned kCTime = 1 << 1; + const unsigned kUnixTime = 1 << 2; + const unsigned kNanoSec = 1 << 3; +} + +namespace NFileFlags +{ + const unsigned kIsDir = 1 << 0; + const unsigned kUnixTime = 1 << 1; + const unsigned kCrc32 = 1 << 2; + const unsigned kUnknownSize = 1 << 3; +} + +namespace NMethodFlags +{ + // const unsigned kVersionMask = 0x3F; + const unsigned kSolid = 1 << 6; + const unsigned kRar5_Compat = 1u << 20; +} + +namespace NArcEndFlags +{ + const unsigned kMoreVols = 1 << 0; +} + +enum EHostOS +{ + kHost_Windows = 0, + kHost_Unix +}; + + + +// ---------- Extra ---------- + +namespace NExtraID +{ + enum + { + kCrypto = 1, + kHash, + kTime, + kVersion, + kLink, + kUnixOwner, + kSubdata + }; +} + +const unsigned kCryptoAlgo_AES = 0; + +namespace NCryptoFlags +{ + const unsigned kPswCheck = 1 << 0; + const unsigned kUseMAC = 1 << 1; +} + +struct CCryptoInfo +{ + UInt64 Algo; + UInt64 Flags; + Byte Cnt; + + bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; } + bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; } + bool Parse(const Byte *p, size_t size); +}; + +const unsigned kHashID_Blake2sp = 0; + +namespace NTimeRecord +{ + enum + { + k_Index_MTime = 0, + k_Index_CTime, + k_Index_ATime + }; + + namespace NFlags + { + const unsigned kUnixTime = 1 << 0; + const unsigned kMTime = 1 << 1; + const unsigned kCTime = 1 << 2; + const unsigned kATime = 1 << 3; + const unsigned kUnixNs = 1 << 4; + } +} + +namespace NLinkType +{ + enum + { + kUnixSymLink = 1, + kWinSymLink, + kWinJunction, + kHardLink, + kFileCopy + }; +} + +namespace NLinkFlags +{ + const unsigned kTargetIsDir = 1 << 0; +} + + +struct CLinkInfo +{ + UInt64 Type; + UInt64 Flags; + unsigned NameOffset; + unsigned NameLen; + + bool Parse(const Byte *p, unsigned size); +}; + + +struct CItem +{ + UInt32 CommonFlags; + UInt32 Flags; + + Byte RecordType; + bool Version_Defined; + + int ACL; + + AString Name; + + unsigned VolIndex; + int NextItem; // in _items{} + + UInt32 UnixMTime; + UInt32 CRC; + UInt32 Attrib; + UInt32 Method; + + CByteBuffer Extra; + + UInt64 Size; + UInt64 PackSize; + UInt64 HostOS; + + UInt64 DataPos; + UInt64 Version; + + CItem() { Clear(); } + + void Clear() + { + // CommonFlags = 0; + // Flags = 0; + + // UnixMTime = 0; + // CRC = 0; + + VolIndex = 0; + NextItem = -1; + + Version_Defined = false; + Version = 0; + + Name.Empty(); + Extra.Free(); + ACL = -1; + } + + bool IsSplitBefore() const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; } + bool IsSplitAfter() const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; } + bool IsSplit() const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; } + + bool IsDir() const { return (Flags & NFileFlags::kIsDir) != 0; } + bool Has_UnixMTime() const { return (Flags & NFileFlags::kUnixTime) != 0; } + bool Has_CRC() const { return (Flags & NFileFlags::kCrc32) != 0; } + bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; } + + bool IsNextForItem(const CItem &prev) const + { + return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name); + // && false; + } + + // rar docs: Solid flag can be set only for file headers and is never set for service headers. + bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; } + bool Is_Rar5_Compat() const { return ((UInt32)Method & NMethodFlags::kRar5_Compat) != 0; } + unsigned Get_Rar5_CompatBit() const { return ((UInt32)Method >> 20) & 1; } + + unsigned Get_AlgoVersion_RawBits() const { return (unsigned)Method & 0x3F; } + unsigned Get_AlgoVersion_HuffRev() const + { + unsigned w = (unsigned)Method & 0x3F; + if (w == 1 && Is_Rar5_Compat()) + w = 0; + return w; + } + unsigned Get_Method() const { return ((unsigned)Method >> 7) & 0x7; } + + unsigned Get_DictSize_Main() const + { return ((UInt32)Method >> 10) & (Get_AlgoVersion_RawBits() == 0 ? 0xf : 0x1f); } + unsigned Get_DictSize_Frac() const + { + // original-unrar ignores Frac, if (algo==0) (rar5): + if (Get_AlgoVersion_RawBits() == 0) + return 0; + return ((UInt32)Method >> 15) & 0x1f; + } + UInt64 Get_DictSize64() const + { + // ver 6.* check + // return (((UInt32)Method >> 10) & 0xF); + UInt64 winSize = 0; + const unsigned algo = Get_AlgoVersion_RawBits(); + if (algo <= 1) + { + UInt32 w = 32; + if (algo == 1) + w += Get_DictSize_Frac(); + winSize = (UInt64)w << (12 + Get_DictSize_Main()); + } + return winSize; + } + + + bool IsService() const { return RecordType == NHeaderType::kService; } + + bool Is_STM() const { return IsService() && Name == "STM"; } + bool Is_CMT() const { return IsService() && Name == "CMT"; } + bool Is_ACL() const { return IsService() && Name == "ACL"; } + // bool Is_QO() const { return IsService() && Name == "QO"; } + + int FindExtra(unsigned extraID, unsigned &recordDataSize) const; + void PrintInfo(AString &s) const; + + + bool IsEncrypted() const + { + unsigned size; + return FindExtra(NExtraID::kCrypto, size) >= 0; + } + + int FindExtra_Blake() const + { + unsigned size = 0; + const int offset = FindExtra(NExtraID::kHash, size); + if (offset >= 0 + && size == Z7_BLAKE2S_DIGEST_SIZE + 1 + && Extra[(unsigned)offset] == kHashID_Blake2sp) + return offset + 1; + return -1; + } + + bool FindExtra_Version(UInt64 &version) const; + + bool FindExtra_Link(CLinkInfo &link) const; + void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const; + bool Is_CopyLink() const; + bool Is_HardLink() const; + bool Is_CopyLink_or_HardLink() const; + + bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); } + bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); } + bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); } + + bool GetAltStreamName(AString &name) const; + + UInt32 GetWinAttrib() const + { + UInt32 a; + switch (HostOS) + { + case kHost_Windows: + a = Attrib; + break; + case kHost_Unix: + a = Attrib << 16; + a |= 0x8000; // add posix mode marker + break; + default: + a = 0; + } + if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY; + return a; + } + + UInt64 GetDataPosition() const { return DataPos; } +}; + + +struct CInArcInfo +{ + UInt64 Flags; + UInt64 VolNumber; + UInt64 StartPos; + UInt64 EndPos; + + UInt64 EndFlags; + bool EndOfArchive_was_Read; + + bool IsEncrypted; + bool Locator_Defined; + bool Locator_Error; + bool Metadata_Defined; + bool Metadata_Error; + bool UnknownExtraRecord; + bool Extra_Error; + bool UnsupportedFeature; + + struct CLocator + { + UInt64 Flags; + UInt64 QuickOpen; + UInt64 Recovery; + + bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; } + bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; } + + bool Parse(const Byte *p, size_t size); + CLocator(): + Flags(0), + QuickOpen(0), + Recovery(0) + {} + }; + + struct CMetadata + { + UInt64 Flags; + UInt64 CTime; + AString ArcName; + + bool Parse(const Byte *p, size_t size); + CMetadata(): + Flags(0), + CTime(0) + {} + }; + + CLocator Locator; + CMetadata Metadata; + + bool ParseExtra(const Byte *p, size_t size); + + CInArcInfo(): + Flags(0), + VolNumber(0), + StartPos(0), + EndPos(0), + EndFlags(0), + EndOfArchive_was_Read(false), + IsEncrypted(false), + Locator_Defined(false), + Locator_Error(false), + Metadata_Defined(false), + Metadata_Error(false), + UnknownExtraRecord(false), + Extra_Error(false), + UnsupportedFeature(false) + {} + + /* + void Clear() + { + Flags = 0; + VolNumber = 0; + StartPos = 0; + EndPos = 0; + EndFlags = 0; + EndOfArchive_was_Read = false; + } + */ + + UInt64 GetPhySize() const { return EndPos - StartPos; } + + bool AreMoreVolumes() const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; } + + bool IsVolume() const { return (Flags & NArcFlags::kVol) != 0; } + bool IsSolid() const { return (Flags & NArcFlags::kSolid) != 0; } + bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; } + + UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; } +}; + + +struct CRefItem +{ + unsigned Item; // First item in _items[] + unsigned Last; // Last item in _items[] + int Parent; // in _refs[], if alternate stream + int Link; // in _refs[] +}; + + +struct CArc +{ + CMyComPtr Stream; + CInArcInfo Info; +}; + + +class CHandler Z7_final: + public IInArchive, + public IArchiveGetRawProps, + public ISetProperties, + Z7_PUBLIC_ISetCompressCodecsInfo_IFEC + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IInArchive) + Z7_COM_QI_ENTRY(IArchiveGetRawProps) + Z7_COM_QI_ENTRY(ISetProperties) + Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInArchive) + Z7_IFACE_COM7_IMP(IArchiveGetRawProps) + Z7_IFACE_COM7_IMP(ISetProperties) + DECL_ISetCompressCodecsInfo + + void InitDefaults(); + + bool _isArc; + bool _needChecksumCheck; + bool _memUsage_WasSet; + bool _comment_WasUsedInArc; + bool _acl_Used; + bool _error_in_ACL; + bool _split_Error; +public: + CRecordVector _refs; + CObjectVector _items; + + CHandler(); +private: + CObjectVector _arcs; + CObjectVector _acls; + + UInt32 _errorFlags; + // UInt32 _warningFlags; + + UInt32 _numBlocks; + unsigned _rar5comapt_mask; + unsigned _methodMasks[2]; + UInt64 _algo_Mask; + UInt64 _dictMaxSizes[2]; + + CByteBuffer _comment; + UString _missingVolName; + + UInt64 _memUsage_Decompress; + + DECL_EXTERNAL_CODECS_VARS + + UInt64 GetPackSize(unsigned refIndex) const; + + void FillLinks(); + + HRESULT Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 175037995..9157accb3 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -1,1782 +1,1782 @@ -// RarHandler.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/PropVariantUtils.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../IPassword.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/FilterCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/MethodId.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/RegisterArc.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "../../Crypto/Rar20Crypto.h" -#include "../../Crypto/RarAes.h" - -#include "../Common/FindSignature.h" -#include "../Common/ItemNameUtils.h" -#include "../Common/OutStreamWithCRC.h" - -#include "../HandlerCont.h" - -#include "RarVol.h" -#include "RarHandler.h" - -using namespace NWindows; - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -namespace NArchive { -namespace NRar { - -static const Byte kMarker[NHeader::kMarkerSize] = - { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; - -const unsigned kPasswordLen_MAX = 127; - -bool CItem::IgnoreItem() const -{ - switch (HostOS) - { - case NHeader::NFile::kHostMSDOS: - case NHeader::NFile::kHostOS2: - case NHeader::NFile::kHostWin32: - return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0); - } - return false; -} - -bool CItem::IsDir() const -{ - if (GetDictSize() == NHeader::NFile::kDictDirectoryValue) - return true; - switch (HostOS) - { - case NHeader::NFile::kHostMSDOS: - case NHeader::NFile::kHostOS2: - case NHeader::NFile::kHostWin32: - if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) - return true; - } - return false; -} - -UInt32 CItem::GetWinAttrib() const -{ - UInt32 a; - switch (HostOS) - { - case NHeader::NFile::kHostMSDOS: - case NHeader::NFile::kHostOS2: - case NHeader::NFile::kHostWin32: - a = Attrib; - break; - default: - a = 0; // must be converted from unix value; - } - if (IsDir()) - a |= NHeader::NFile::kWinFileDirectoryAttributeMask; - return a; -} - -static const char * const kHostOS[] = -{ - "MS DOS" - , "OS/2" - , "Win32" - , "Unix" - , "Mac OS" - , "BeOS" -}; - -static const char * const k_Flags[] = -{ - "Volume" - , "Comment" - , "Lock" - , "Solid" - , "NewVolName" // pack_comment in old versuons - , "Authenticity" - , "Recovery" - , "BlockEncryption" - , "FirstVolume" - , "EncryptVer" // 9 -}; - -enum EErrorType -{ - k_ErrorType_OK, - k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd, - k_ErrorType_DecryptionError -}; - -class CInArchive -{ - IInStream *m_Stream; - UInt64 m_StreamStartPosition; - UString _unicodeNameBuffer; - CByteBuffer _comment; - CByteBuffer m_FileHeaderData; - NHeader::NBlock::CBlock m_BlockHeader; - NCrypto::NRar3::CDecoder *m_RarAESSpec; - CMyComPtr m_RarAES; - CAlignedBuffer m_DecryptedDataAligned; - UInt32 m_DecryptedDataSize; - bool m_CryptoMode; - UInt32 m_CryptoPos; - - - HRESULT ReadBytesSpec(void *data, size_t *size); - bool ReadBytesAndTestSize(void *data, UInt32 size); - void ReadName(const Byte *p, unsigned nameSize, CItem &item); - bool ReadHeaderReal(const Byte *p, unsigned size, CItem &item); - - HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); - - void AddToSeekValue(UInt64 addValue) - { - m_Position += addValue; - } - - void FinishCryptoBlock() - { - if (m_CryptoMode) - while ((m_CryptoPos & 0xF) != 0) - { - m_CryptoPos++; - m_Position++; - } - } - -public: - UInt64 m_Position; - CInArcInfo ArcInfo; - bool HeaderErrorWarning; - - HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); - HRESULT GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, - bool &filled, EErrorType &error); -}; - -static bool CheckHeaderCrc(const Byte *header, size_t headerSize) -{ - return Get16(header) == (UInt16)(CrcCalc(header + 2, headerSize - 2) & 0xFFFF); -} - -HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) -{ - HeaderErrorWarning = false; - m_CryptoMode = false; - RINOK(InStream_GetPos_GetSize(stream, m_StreamStartPosition, ArcInfo.FileSize)) - m_Position = m_StreamStartPosition; - - UInt64 arcStartPos = m_StreamStartPosition; - { - Byte marker[NHeader::kMarkerSize]; - RINOK(ReadStream_FALSE(stream, marker, NHeader::kMarkerSize)) - if (memcmp(marker, kMarker, NHeader::kMarkerSize) == 0) - m_Position += NHeader::kMarkerSize; - else - { - if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) - return S_FALSE; - RINOK(InStream_SeekSet(stream, m_StreamStartPosition)) - RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize, - searchHeaderSizeLimit, arcStartPos)) - m_Position = arcStartPos + NHeader::kMarkerSize; - RINOK(InStream_SeekSet(stream, m_Position)) - } - } - Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; - - RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)) - AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); - - - const UInt32 blockSize = Get16(buf + 5); - - ArcInfo.EncryptVersion = 0; - ArcInfo.Flags = Get16(buf + 3); - - UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; - - /* - if (ArcInfo.IsThereEncryptVer()) - { - if (blockSize <= headerSize) - return S_FALSE; - RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); - AddToSeekValue(1); - ArcInfo.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; - headerSize += 1; - } - */ - - if (blockSize < headerSize - || buf[2] != NHeader::NBlockType::kArchiveHeader - || !CheckHeaderCrc(buf, headerSize)) - return S_FALSE; - - size_t commentSize = blockSize - headerSize; - _comment.Alloc(commentSize); - RINOK(ReadStream_FALSE(stream, _comment, commentSize)) - AddToSeekValue(commentSize); - m_Stream = stream; - ArcInfo.StartPos = arcStartPos; - return S_OK; -} - -HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize) -{ - if (m_CryptoMode) - { - size_t size = *resSize; - *resSize = 0; - const Byte *bufData = m_DecryptedDataAligned; - UInt32 bufSize = m_DecryptedDataSize; - size_t i; - for (i = 0; i < size && m_CryptoPos < bufSize; i++) - ((Byte *)data)[i] = bufData[m_CryptoPos++]; - *resSize = i; - return S_OK; - } - return ReadStream(m_Stream, data, resSize); -} - -bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) -{ - size_t processed = size; - if (ReadBytesSpec(data, &processed) != S_OK) - return false; - return processed == size; -} - - -static unsigned DecodeUnicodeFileName(const Byte *name, const Byte *encName, - unsigned encSize, wchar_t *unicodeName, unsigned maxDecSize) -{ - unsigned encPos = 0; - unsigned decPos = 0; - unsigned flagBits = 0; - Byte flags = 0; - - if (encPos >= encSize) - return 0; // error - const unsigned highBits = ((unsigned)encName[encPos++]) << 8; - - while (encPos < encSize && decPos < maxDecSize) - { - if (flagBits == 0) - { - flags = encName[encPos++]; - flagBits = 8; - } - - if (encPos >= encSize) - break; // error - unsigned len = encName[encPos++]; - - flagBits -= 2; - const unsigned mode = (flags >> flagBits) & 3; - - if (mode != 3) - { - if (mode == 1) - len += highBits; - else if (mode == 2) - { - if (encPos >= encSize) - break; // error - len += ((unsigned)encName[encPos++] << 8); - } - unicodeName[decPos++] = (wchar_t)len; - } - else - { - if (len & 0x80) - { - if (encPos >= encSize) - break; // error - Byte correction = encName[encPos++]; - for (len = (len & 0x7f) + 2; len > 0 && decPos < maxDecSize; len--, decPos++) - unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + highBits); - } - else - for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++) - unicodeName[decPos] = name[decPos]; - } - } - - return decPos < maxDecSize ? decPos : maxDecSize - 1; -} - - -void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item) -{ - item.UnicodeName.Empty(); - if (nameSize > 0) - { - unsigned i; - for (i = 0; i < nameSize && p[i] != 0; i++); - item.Name.SetFrom((const char *)p, i); - - if (item.HasUnicodeName()) - { - if (i < nameSize) - { - i++; - unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400); - unsigned len = DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer.GetBuf(uNameSizeMax), uNameSizeMax); - _unicodeNameBuffer.ReleaseBuf_SetEnd(len); - item.UnicodeName = _unicodeNameBuffer; - } - else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) - item.UnicodeName.Empty(); - } - } - else - item.Name.Empty(); -} - -static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) -{ - rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); - const unsigned numDigits = (mask & 3); - rarTime.SubTime[0] = - rarTime.SubTime[1] = - rarTime.SubTime[2] = 0; - if (numDigits > size) - return -1; - for (unsigned i = 0; i < numDigits; i++) - rarTime.SubTime[3 - numDigits + i] = p[i]; - return (int)numDigits; -} - -#define READ_TIME(_mask_, _ttt_) \ - { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += (unsigned)size2, size -= (unsigned)size2; } - -#define READ_TIME_2(_mask_, _def_, _ttt_) \ - _def_ = ((_mask_ & 8) != 0); if (_def_) \ - { if (size < 4) return false; \ - _ttt_ .DosTime = Get32(p); p += 4; size -= 4; \ - READ_TIME(_mask_, _ttt_); } \ - - -bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item) -{ - const Byte *pStart = p; - - item.Clear(); - item.Flags = m_BlockHeader.Flags; - - const unsigned kFileHeaderSize = 25; - - if (size < kFileHeaderSize) - return false; - - item.PackSize = Get32(p); - item.Size = Get32(p + 4); - item.HostOS = p[8]; - item.FileCRC = Get32(p + 9); - item.MTime.DosTime = Get32(p + 13); - item.UnPackVersion = p[17]; - item.Method = p[18]; - unsigned nameSize = Get16(p + 19); - item.Attrib = Get32(p + 21); - - item.MTime.LowSecond = 0; - item.MTime.SubTime[0] = - item.MTime.SubTime[1] = - item.MTime.SubTime[2] = 0; - - p += kFileHeaderSize; - size -= kFileHeaderSize; - if ((item.Flags & NHeader::NFile::kSize64Bits) != 0) - { - if (size < 8) - return false; - item.PackSize |= ((UInt64)Get32(p) << 32); - if (item.PackSize >= ((UInt64)1 << 63)) - return false; - item.Size |= ((UInt64)Get32(p + 4) << 32); - p += 8; - size -= 8; - } - if (nameSize > size) - return false; - ReadName(p, nameSize, item); - p += nameSize; - size -= nameSize; - - /* - // It was commented, since it's difficult to support alt Streams for solid archives. - if (m_BlockHeader.Type == NHeader::NBlockType::kSubBlock) - { - if (item.HasSalt()) - { - if (size < sizeof(item.Salt)) - return false; - size -= sizeof(item.Salt); - p += sizeof(item.Salt); - } - if (item.Name == "ACL" && size == 0) - { - item.IsAltStream = true; - item.Name.Empty(); - item.UnicodeName.SetFromAscii(".ACL"); - } - else if (item.Name == "STM" && size != 0 && (size & 1) == 0) - { - item.IsAltStream = true; - item.Name.Empty(); - for (UInt32 i = 0; i < size; i += 2) - { - wchar_t c = Get16(p + i); - if (c == 0) - return false; - item.UnicodeName += c; - } - } - } - */ - - if (item.HasSalt()) - { - if (size < sizeof(item.Salt)) - return false; - for (unsigned i = 0; i < sizeof(item.Salt); i++) - item.Salt[i] = p[i]; - p += sizeof(item.Salt); - size -= (unsigned)sizeof(item.Salt); - } - - // some rar archives have HasExtTime flag without field. - if (size >= 2 && item.HasExtTime()) - { - Byte aMask = (Byte)(p[0] >> 4); - Byte b = p[1]; - p += 2; - size -= 2; - Byte mMask = (Byte)(b >> 4); - Byte cMask = (Byte)(b & 0xF); - if ((mMask & 8) != 0) - { - READ_TIME(mMask, item.MTime) - } - READ_TIME_2(cMask, item.CTimeDefined, item.CTime) - READ_TIME_2(aMask, item.ATimeDefined, item.ATime) - } - - unsigned fileHeaderWithNameSize = 7 + (unsigned)(p - pStart); - - item.Position = m_Position; - item.MainPartSize = fileHeaderWithNameSize; - item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize); - - if (m_CryptoMode) - item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF); - else - item.AlignSize = 0; - AddToSeekValue(m_BlockHeader.HeadSize); - - // return (m_BlockHeader.Type != NHeader::NBlockType::kSubBlock || item.IsAltStream); - return true; -} - -HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, bool &filled, EErrorType &error) -{ - filled = false; - error = k_ErrorType_OK; - for (;;) - { - RINOK(InStream_SeekSet(m_Stream, m_Position)) - ArcInfo.EndPos = m_Position; - if (!m_CryptoMode && (ArcInfo.Flags & - NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) - { - m_CryptoMode = false; - if (!getTextPassword) - { - error = k_ErrorType_DecryptionError; - return S_OK; // return S_FALSE; - } - if (!m_RarAES) - { - m_RarAESSpec = new NCrypto::NRar3::CDecoder; - m_RarAES = m_RarAESSpec; - } - // m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld()); - - { - // Salt - const UInt32 kSaltSize = 8; - Byte salt[kSaltSize]; - if (!ReadBytesAndTestSize(salt, kSaltSize)) - return S_FALSE; - m_Position += kSaltSize; - RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) - } - - { - // Password - CMyComBSTR_Wipe password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)) - unsigned len = 0; - if (password) - len = MyStringLen(password); - if (len > kPasswordLen_MAX) - len = kPasswordLen_MAX; - - CByteBuffer_Wipe buffer(len * 2); - for (unsigned i = 0; i < len; i++) - { - wchar_t c = password[i]; - ((Byte *)buffer)[i * 2] = (Byte)c; - ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); - } - - m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2); - } - - const UInt32 kDecryptedBufferSize = (1 << 12); - if (m_DecryptedDataAligned.Size() == 0) - { - // const UInt32 kAlign = 16; - m_DecryptedDataAligned.AllocAtLeast(kDecryptedBufferSize); - if (!m_DecryptedDataAligned.IsAllocated()) - return E_OUTOFMEMORY; - } - RINOK(m_RarAES->Init()) - size_t decryptedDataSizeT = kDecryptedBufferSize; - RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT)) - m_DecryptedDataSize = (UInt32)decryptedDataSizeT; - m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize); - - m_CryptoMode = true; - m_CryptoPos = 0; - } - - m_FileHeaderData.AllocAtLeast(7); - size_t processed = 7; - RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed)) - if (processed != 7) - { - if (processed != 0) - error = k_ErrorType_UnexpectedEnd; - ArcInfo.EndPos = m_Position + processed; // test it - return S_OK; - } - - const Byte *p = m_FileHeaderData; - m_BlockHeader.CRC = Get16(p + 0); - m_BlockHeader.Type = p[2]; - m_BlockHeader.Flags = Get16(p + 3); - m_BlockHeader.HeadSize = Get16(p + 5); - - if (m_BlockHeader.HeadSize < 7) - { - error = k_ErrorType_Corrupted; - return S_OK; - // ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive); - } - - if (m_BlockHeader.Type < NHeader::NBlockType::kFileHeader || - m_BlockHeader.Type > NHeader::NBlockType::kEndOfArchive) - { - error = m_CryptoMode ? - k_ErrorType_DecryptionError : - k_ErrorType_Corrupted; - return S_OK; - } - - if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive) - { - bool footerError = false; - - unsigned expectHeadLen = 7; - if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) - expectHeadLen += 4; - if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) - expectHeadLen += 2; - if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_RevSpace) - expectHeadLen += 7; - - // rar 5.0 beta 1 writes incorrect RevSpace and headSize - - if (m_BlockHeader.HeadSize < expectHeadLen) - HeaderErrorWarning = true; - - if (m_BlockHeader.HeadSize > 7) - { - /* We suppose that EndOfArchive header is always small. - It's only 20 bytes for multivolume - Fix the limit, if larger footers are possible */ - if (m_BlockHeader.HeadSize > (1 << 8)) - footerError = true; - else - { - if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) - m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); - UInt32 afterSize = m_BlockHeader.HeadSize - 7; - if (ReadBytesAndTestSize(m_FileHeaderData + 7, afterSize)) - processed += afterSize; - else - { - if (!m_CryptoMode) - { - error = k_ErrorType_UnexpectedEnd; - return S_OK; - } - footerError = true; - } - } - } - - if (footerError || !CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize)) - { - error = m_CryptoMode ? - k_ErrorType_DecryptionError : - k_ErrorType_Corrupted; - } - else - { - ArcInfo.EndFlags = m_BlockHeader.Flags; - UInt32 offset = 7; - - if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) - { - if (processed < offset + 4) - error = k_ErrorType_Corrupted; - else - ArcInfo.DataCRC = Get32(m_FileHeaderData + offset); - offset += 4; - } - - if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) - { - if (processed < offset + 2) - error = k_ErrorType_Corrupted; - else - ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset); - } - - ArcInfo.EndOfArchive_was_Read = true; - } - - m_Position += processed; - FinishCryptoBlock(); - ArcInfo.EndPos = m_Position; - return S_OK; - } - - if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader - /* || m_BlockHeader.Type == NHeader::NBlockType::kSubBlock */) - { - if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) - m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); - // m_CurData = (Byte *)m_FileHeaderData; - // m_PosLimit = m_BlockHeader.HeadSize; - if (!ReadBytesAndTestSize(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7)) - { - error = k_ErrorType_UnexpectedEnd; - return S_OK; - } - - bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item); - if (okItem) - { - if (!CheckHeaderCrc(m_FileHeaderData, (unsigned)m_BlockHeader.HeadSize - item.CommentSize)) - { - error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); - return S_OK; - } - filled = true; - } - - FinishCryptoBlock(); - m_CryptoMode = false; - // Move Position to compressed Data; - RINOK(InStream_SeekSet(m_Stream, m_Position)) - AddToSeekValue(item.PackSize); // m_Position points to next header; - // if (okItem) - return S_OK; - /* - else - continue; - */ - } - - if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) - { - error = k_ErrorType_DecryptionError; - return S_OK; - } - - if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) - { - if (m_FileHeaderData.Size() < 7 + 4) - m_FileHeaderData.ChangeSize_KeepData(7 + 4, 7); - if (!ReadBytesAndTestSize(m_FileHeaderData + 7, 4)) - { - error = k_ErrorType_UnexpectedEnd; - return S_OK; - } - UInt32 dataSize = Get32(m_FileHeaderData + 7); - AddToSeekValue(dataSize); - if (m_CryptoMode && dataSize > (1 << 27)) - { - error = k_ErrorType_DecryptionError; - return S_OK; - } - m_CryptoPos = m_BlockHeader.HeadSize; - } - else - m_CryptoPos = 0; - - { - UInt64 newPos = m_Position + m_BlockHeader.HeadSize; - if (newPos > ArcInfo.FileSize) - { - error = k_ErrorType_UnexpectedEnd; - return S_OK; - } - } - AddToSeekValue(m_BlockHeader.HeadSize); - FinishCryptoBlock(); - m_CryptoMode = false; - } -} - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidAttrib, - - kpidEncrypted, - kpidSolid, - kpidCommented, - kpidSplitBefore, - kpidSplitAfter, - kpidCRC, - kpidHostOS, - kpidMethod, - kpidUnpackVer, - - kpidVolumeIndex -}; - -static const Byte kArcProps[] = -{ - kpidTotalPhySize, - kpidCharacts, - kpidSolid, - kpidNumBlocks, - // kpidEncrypted, - kpidIsVolume, - kpidVolumeIndex, - kpidNumVolumes - // kpidCommented -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -UInt64 CHandler::GetPackSize(unsigned refIndex) const -{ - const CRefItem &refItem = _refItems[refIndex]; - UInt64 totalPackSize = 0; - for (unsigned i = 0; i < refItem.NumItems; i++) - totalPackSize += _items[refItem.ItemIndex + i].PackSize; - return totalPackSize; -} - -bool CHandler::IsSolid(unsigned refIndex) const -{ - const CItem &item = _items[_refItems[refIndex].ItemIndex]; - if (item.UnPackVersion < 20) - { - if (_arcInfo.IsSolid()) - return (refIndex > 0); - return false; - } - return item.IsSolid(); -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidVolumeIndex: if (_arcInfo.Is_VolNumber_Defined()) prop = (UInt32)_arcInfo.VolNumber; break; - case kpidSolid: prop = _arcInfo.IsSolid(); break; - case kpidCharacts: - { - AString s (FlagsToString(k_Flags, Z7_ARRAY_SIZE(k_Flags), _arcInfo.Flags)); - // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop); - if (_arcInfo.Is_DataCRC_Defined()) - { - s.Add_Space_if_NotEmpty(); - s += "VolCRC"; - } - prop = s; - break; - } - // case kpidEncrypted: prop = _arcInfo.IsEncrypted(); break; // it's for encrypted names. - case kpidIsVolume: prop = _arcInfo.IsVolume(); break; - case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; - case kpidOffset: if (_arcs.Size() == 1 && _arcInfo.StartPos != 0) prop = _arcInfo.StartPos; break; - - case kpidTotalPhySize: - { - if (_arcs.Size() > 1) - { - UInt64 sum = 0; - FOR_VECTOR (v, _arcs) - sum += _arcs[v].PhySize; - prop = sum; - } - break; - } - - case kpidPhySize: - { - if (_arcs.Size() != 0) - prop = _arcInfo.GetPhySize(); - break; - } - - // case kpidCommented: prop = _arcInfo.IsCommented(); break; - - case kpidNumBlocks: - { - UInt32 numBlocks = 0; - FOR_VECTOR (i, _refItems) - if (!IsSolid(i)) - numBlocks++; - prop = (UInt32)numBlocks; - break; - } - - - case kpidError: - { - // if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; - - if (/* &_missingVol || */ !_missingVolName.IsEmpty()) - { - UString s ("Missing volume : "); - s += _missingVolName; - prop = s; - } - break; - } - - case kpidErrorFlags: - { - UInt32 v = _errorFlags; - if (!_isArc) - v |= kpv_ErrorFlags_IsNotArc; - prop = v; - break; - } - - case kpidWarningFlags: - { - if (_warningFlags != 0) - prop = _warningFlags; - break; - } - - case kpidExtension: - if (_arcs.Size() == 1) - { - if (_arcInfo.Is_VolNumber_Defined()) - { - AString s ("part"); - UInt32 v = (UInt32)_arcInfo.VolNumber + 1; - if (v < 10) - s += '0'; - s.Add_UInt32(v); - s += ".rar"; - prop = s; - } - } - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _refItems.Size(); - return S_OK; -} - -static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &ft) -{ - if (!NTime::DosTime_To_FileTime(rarTime.DosTime, ft)) - return false; - UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - v += (UInt32)rarTime.LowSecond * 10000000; - v += - ((UInt32)rarTime.SubTime[2] << 16) + - ((UInt32)rarTime.SubTime[1] << 8) + - ((UInt32)rarTime.SubTime[0]); - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); - return true; -} - -static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) -{ - FILETIME localFileTime, utc; - if (RarTimeToFileTime(rarTime, localFileTime) - && LocalFileTimeToFileTime(&localFileTime, &utc)) - prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns); - /* - else - utc.dwHighDateTime = utc.dwLowDateTime = 0; - // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns); - */ -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CRefItem &refItem = _refItems[index]; - const CItem &item = _items[refItem.ItemIndex]; - const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; - - /* - const CItem *mainItem = &item; - if (item.BaseFileIndex >= 0) - mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex]; - */ - switch (propID) - { - case kpidPath: - { - /* - UString u; - if (item.BaseFileIndex >= 0) - u = mainItem->GetName(); - u += item.GetName(); - */ - prop = (const wchar_t *)NItemName::WinPathToOsPath(item.GetName()); - break; - } - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: if (lastItem.Is_Size_Defined()) prop = lastItem.Size; break; - case kpidPackSize: prop = GetPackSize(index); break; - case kpidMTime: RarTimeToProp(item.MTime, prop); break; - case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break; - case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break; - case kpidAttrib: prop = item.GetWinAttrib(); break; - case kpidEncrypted: prop = item.IsEncrypted(); break; - case kpidSolid: prop = IsSolid(index); break; - case kpidCommented: prop = item.IsCommented(); break; - case kpidSplitBefore: prop = item.IsSplitBefore(); break; - case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break; - - case kpidVolumeIndex: - if (_arcInfo.Is_VolNumber_Defined()) - prop = (UInt32)(_arcInfo.VolNumber + refItem.VolumeIndex); - break; - - case kpidCRC: - { - prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC); - break; - } - case kpidUnpackVer: prop = item.UnPackVersion; break; - case kpidMethod: - { - char s[16]; - Byte m = item.Method; - if (m < (Byte)'0' || m > (Byte)'5') - ConvertUInt32ToString(m, s); - else - { - s[0] = 'm'; - s[1] = (char)m; - s[2] = 0; - if (!item.IsDir()) - { - s[2] = ':'; - ConvertUInt32ToString(16 + item.GetDictSize(), &s[3]); - } - } - prop = s; - break; - } - case kpidHostOS: - TYPE_TO_PROP(kHostOS, item.HostOS, prop); - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback) -{ - { - CMyComPtr openVolumeCallback; - CMyComPtr getTextPassword; - - CVolumeName seqName; - - UInt64 totalBytes = 0; - UInt64 curBytes = 0; - - if (openCallback) - { - openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); - } - - bool nextVol_is_Required = false; - - CInArchive archive; - - for (;;) - { - CMyComPtr inStream; - if (!_arcs.IsEmpty()) - { - if (!openVolumeCallback) - break; - - if (_arcs.Size() == 1) - { - if (!_arcInfo.IsVolume()) - break; - UString baseName; - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) - if (prop.vt != VT_BSTR) - break; - baseName = prop.bstrVal; - } - if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName())) - break; - /* - if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume()) - { - seqName.MakeBeforeFirstName(); - } - */ - } - - const UString volName = seqName.GetNextName(); - - HRESULT result = openVolumeCallback->GetStream(volName, &inStream); - - if (result != S_OK && result != S_FALSE) - return result; - - if (!inStream || result != S_OK) - { - if (nextVol_is_Required) - _missingVolName = volName; - break; - } - } - else - inStream = stream; - - UInt64 endPos; - RINOK(InStream_AtBegin_GetSize(inStream, endPos)) - if (openCallback) - { - totalBytes += endPos; - RINOK(openCallback->SetTotal(NULL, &totalBytes)) - } - - RINOK(archive.Open(inStream, maxCheckStartPosition)) - _isArc = true; - CItem item; - - for (;;) - { - if (archive.m_Position > endPos) - { - _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; - break; - } - - EErrorType error; - // bool decryptionError; - // AString errorMessageLoc; - bool filled; - HRESULT result = archive.GetNextItem(item, getTextPassword, filled, error); - - if (error != k_ErrorType_OK) - { - if (error == k_ErrorType_UnexpectedEnd) - _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; - else if (error == k_ErrorType_Corrupted) - _errorFlags |= kpv_ErrorFlags_HeadersError; - else if (error == k_ErrorType_DecryptionError) - _errorFlags |= kpv_ErrorFlags_EncryptedHeadersError; - - // AddErrorMessage(errorMessageLoc); - } - RINOK(result) - - if (!filled) - { - if (error == k_ErrorType_DecryptionError && _items.IsEmpty()) - return S_FALSE; - - if (archive.ArcInfo.ExtraZeroTail_is_Possible()) - { - /* if there is recovery record for multivolume archive, - RAR adds 18 bytes (ZERO bytes) at the end for alignment. - We must skip these bytes to prevent phySize warning. */ - RINOK(InStream_SeekSet(inStream, archive.ArcInfo.EndPos)) - bool areThereNonZeros; - UInt64 numZeros; - const UInt64 maxSize = 1 << 12; - RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize)) - if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize) - archive.ArcInfo.EndPos += numZeros; - } - break; - } - - if (item.IgnoreItem()) - continue; - - bool needAdd = true; - - if (item.IsSplitBefore()) - { - if (!_refItems.IsEmpty()) - { - CRefItem &refItem = _refItems.Back(); - refItem.NumItems++; - needAdd = false; - } - } - - if (needAdd) - { - CRefItem refItem; - refItem.ItemIndex = _items.Size(); - refItem.NumItems = 1; - refItem.VolumeIndex = _arcs.Size(); - _refItems.Add(refItem); - } - - _items.Add(item); - - if (openCallback && _items.Size() % 100 == 0) - { - UInt64 numFiles = _items.Size(); - UInt64 numBytes = curBytes + item.Position; - RINOK(openCallback->SetCompleted(&numFiles, &numBytes)) - } - } - - if (archive.HeaderErrorWarning) - _warningFlags |= kpv_ErrorFlags_HeadersError; - - /* - if (archive.m_Position < endPos) - _warningFlags |= kpv_ErrorFlags_DataAfterEnd; - */ - if (_arcs.IsEmpty()) - _arcInfo = archive.ArcInfo; - // _arcInfo.EndPos = archive.EndPos; - - curBytes += endPos; - { - CArc &arc = _arcs.AddNew(); - arc.PhySize = archive.ArcInfo.GetPhySize(); - arc.Stream = inStream; - } - - nextVol_is_Required = false; - - if (!archive.ArcInfo.IsVolume()) - break; - - if (archive.ArcInfo.EndOfArchive_was_Read) - { - if (!archive.ArcInfo.AreMoreVolumes()) - break; - nextVol_is_Required = true; - } - } - } - - /* - int baseFileIndex = -1; - for (unsigned i = 0; i < _refItems.Size(); i++) - { - CItem &item = _items[_refItems[i].ItemIndex]; - if (item.IsAltStream) - item.BaseFileIndex = baseFileIndex; - else - baseFileIndex = i; - } - */ - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback)) -{ - COM_TRY_BEGIN - Close(); - // try - { - HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); - /* - if (res != S_OK) - Close(); - */ - - return res; - } - // catch(const CInArchiveException &) { Close(); return S_FALSE; } - // catch(...) { Close(); throw; } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - COM_TRY_BEGIN - // _errorMessage.Empty(); - _missingVolName.Empty(); - _errorFlags = 0; - _warningFlags = 0; - _isArc = false; - _refItems.Clear(); - _items.Clear(); - _arcs.Clear(); - return S_OK; - COM_TRY_END -} - -struct CMethodItem -{ - Byte RarUnPackVersion; - CMyComPtr Coder; -}; - - -Z7_CLASS_IMP_NOQIB_1( - CVolsInStream - , ISequentialInStream -) - UInt64 _rem; - ISequentialInStream *_stream; - const CObjectVector *_arcs; - const CObjectVector *_items; - CRefItem _refItem; - unsigned _curIndex; - UInt32 _crc; - bool _calcCrc; - -public: - void Init(const CObjectVector *arcs, - const CObjectVector *items, - const CRefItem &refItem) - { - _arcs = arcs; - _items = items; - _refItem = refItem; - _curIndex = 0; - _stream = NULL; - CrcIsOK = true; - } - - bool CrcIsOK; -}; - - -Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - UInt32 realProcessedSize = 0; - - while (size != 0) - { - if (!_stream) - { - if (_curIndex >= _refItem.NumItems) - break; - const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex]; - unsigned volIndex = _refItem.VolumeIndex + _curIndex; - if (volIndex >= _arcs->Size()) - { - return S_OK; - // return S_FALSE; - } - IInStream *s = (*_arcs)[volIndex].Stream; - RINOK(InStream_SeekSet(s, item.GetDataPosition())) - _stream = s; - _calcCrc = (CrcIsOK && item.IsSplitAfter()); - _crc = CRC_INIT_VAL; - _rem = item.PackSize; - } - { - UInt32 cur = size; - if (cur > _rem) - cur = (UInt32)_rem; - UInt32 num = cur; - HRESULT res = _stream->Read(data, cur, &cur); - if (_calcCrc) - _crc = CrcUpdate(_crc, data, cur); - realProcessedSize += cur; - if (processedSize) - *processedSize = realProcessedSize; - data = (Byte *)data + cur; - size -= cur; - _rem -= cur; - if (_rem == 0) - { - const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex]; - _curIndex++; - if (_calcCrc && CRC_GET_DIGEST(_crc) != item.FileCRC) - CrcIsOK = false; - _stream = NULL; - } - if (res != S_OK) - return res; - if (realProcessedSize != 0) - return S_OK; - if (cur == 0 && num != 0) - return S_OK; - } - } - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - CMyComPtr getTextPassword; - UInt64 // censoredTotalUnPacked = 0, - // censoredTotalPacked = 0, - importantTotalUnPacked = 0; - // importantTotalPacked = 0; - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _refItems.Size(); - if (numItems == 0) - return S_OK; - unsigned lastIndex = 0; - CRecordVector importantIndexes; - CRecordVector extractStatuses; - - bool isThereUndefinedSize = false; - - for (UInt32 t = 0; t < numItems; t++) - { - unsigned index = allFilesMode ? t : indices[t]; - - { - const CRefItem &refItem = _refItems[index]; - const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1]; - - if (item.Is_Size_Defined()) - { - // censoredTotalUnPacked += item.Size; - } - else - isThereUndefinedSize = true; - - // censoredTotalPacked += item.PackSize; - } - - unsigned j; - for (j = lastIndex; j <= index; j++) - // if (!_items[_refItems[j].ItemIndex].IsSolid()) - if (!IsSolid(j)) - lastIndex = j; - - for (j = lastIndex; j <= index; j++) - { - const CRefItem &refItem = _refItems[j]; - const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1]; - - if (item.Is_Size_Defined()) - importantTotalUnPacked += item.Size; - else - isThereUndefinedSize = true; - // importantTotalPacked += item.PackSize; - importantIndexes.Add(j); - extractStatuses.Add(j == index); - } - - lastIndex = index + 1; - } - - if (importantTotalUnPacked != 0 || !isThereUndefinedSize) - { - RINOK(extractCallback->SetTotal(importantTotalUnPacked)) - } - - UInt64 currentImportantTotalUnPacked = 0; - UInt64 currentImportantTotalPacked = 0; - UInt64 currentUnPackSize, currentPackSize; - - CObjectVector methodItems; - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - - CFilterCoder *filterStreamSpec = new CFilterCoder(false); - CMyComPtr filterStream = filterStreamSpec; - - NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL; - CMyComPtr rar20CryptoDecoder; - NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL; - CMyComPtr rar3CryptoDecoder; - - CVolsInStream *volsInStreamSpec = NULL; - CMyComPtr volsInStream; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - bool solidStart = true; - - for (unsigned i = 0;; - i++, - currentImportantTotalUnPacked += currentUnPackSize, - currentImportantTotalPacked += currentPackSize) - { - lps->InSize = currentImportantTotalPacked; - lps->OutSize = currentImportantTotalUnPacked; - RINOK(lps->SetCur()) - - if (i >= importantIndexes.Size()) - break; - - CMyComPtr realOutStream; - - Int32 askMode; - if (extractStatuses[i]) - askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - else - askMode = NExtract::NAskMode::kSkip; - - UInt32 index = importantIndexes[i]; - - const CRefItem &refItem = _refItems[index]; - const CItem &item = _items[refItem.ItemIndex]; - const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; - - UInt64 outSize = (UInt64)(Int64)-1; - currentUnPackSize = 0; - if (lastItem.Is_Size_Defined()) - { - outSize = lastItem.Size; - currentUnPackSize = outSize; - } - - currentPackSize = GetPackSize(index); - - if (item.IgnoreItem()) - continue; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (!IsSolid(index)) - solidStart = true; - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - bool mustBeProcessedAnywhere = false; - if (i < importantIndexes.Size() - 1) - { - // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]]; - // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex]; - // mustBeProcessedAnywhere = nextItemInfo.IsSolid(); - mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]); - } - - if (!mustBeProcessedAnywhere && !testMode && !realOutStream) - continue; - - if (!realOutStream && !testMode) - askMode = NExtract::NAskMode::kSkip; - - RINOK(extractCallback->PrepareOperation(askMode)) - - COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - - if (!volsInStream) - { - volsInStreamSpec = new CVolsInStream; - volsInStream = volsInStreamSpec; - } - - volsInStreamSpec->Init(&_arcs, &_items, refItem); - - UInt64 packSize = currentPackSize; - - // packedPos += item.PackSize; - // unpackedPos += 0; - - CMyComPtr inStream; - - if (item.IsEncrypted()) - { - // CMyComPtr cryptoSetPassword; - - if (item.UnPackVersion >= 29) - { - if (!rar3CryptoDecoder) - { - rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder; - rar3CryptoDecoder = rar3CryptoDecoderSpec; - } - // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); - /* - CMyComPtr cryptoProperties; - RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, - &cryptoProperties)); - */ - RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)) - filterStreamSpec->Filter = rar3CryptoDecoder; - } - else if (item.UnPackVersion >= 20) - { - if (!rar20CryptoDecoder) - { - rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder; - rar20CryptoDecoder = rar20CryptoDecoderSpec; - } - filterStreamSpec->Filter = rar20CryptoDecoder; - } - else - { - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - continue; - } - - // RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); - - if (!getTextPassword) - extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); - - if (!getTextPassword) - { - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - continue; - } - - // if (getTextPassword) - { - CMyComBSTR_Wipe password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)) - - if (item.UnPackVersion >= 29) - { - unsigned len = 0; - if (password) - len = MyStringLen(password); - if (len > kPasswordLen_MAX) - len = kPasswordLen_MAX; - CByteBuffer_Wipe buffer(len * 2); - for (unsigned k = 0; k < len; k++) - { - wchar_t c = password[k]; - ((Byte *)buffer)[k * 2] = (Byte)c; - ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); - } - rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2); - } - else - { - AString_Wipe oemPassword; - if (password) - { - UString_Wipe unicode; - unicode.SetFromBstr(password); - if (unicode.Len() > kPasswordLen_MAX) - unicode.DeleteFrom(kPasswordLen_MAX); - UnicodeStringToMultiByte2(oemPassword, unicode, CP_OEMCP); - } - rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()); - } - } - /* - else - { - RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0)); - } - */ - - filterStreamSpec->SetInStream(volsInStream); - filterStreamSpec->SetOutStreamSize(NULL); - inStream = filterStream; - } - else - { - inStream = volsInStream; - } - - CMyComPtr commonCoder; - - switch (item.Method) - { - case '0': - { - commonCoder = copyCoder; - break; - } - case '1': - case '2': - case '3': - case '4': - case '5': - { - unsigned m; - for (m = 0; m < methodItems.Size(); m++) - if (methodItems[m].RarUnPackVersion == item.UnPackVersion) - break; - if (m == methodItems.Size()) - { - CMethodItem mi; - mi.RarUnPackVersion = item.UnPackVersion; - - mi.Coder.Release(); - if (item.UnPackVersion <= 40) - { - UInt32 methodID = 0x40300; - if (item.UnPackVersion < 20) - methodID += 1; - else if (item.UnPackVersion < 29) - methodID += 2; - else - methodID += 3; - RINOK(CreateCoder_Id(EXTERNAL_CODECS_VARS methodID, false, mi.Coder)) - } - - if (!mi.Coder) - { - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - continue; - } - - m = methodItems.Add(mi); - } - CMyComPtr decoder = methodItems[m].Coder; - - CMyComPtr compressSetDecoderProperties; - RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2, - &compressSetDecoderProperties)) - - Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0); - if (solidStart) - { - isSolid = 0; - solidStart = false; - } - - - RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1)) - - commonCoder = decoder; - break; - } - default: - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) - continue; - } - - HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, progress); - - if (item.IsEncrypted()) - filterStreamSpec->ReleaseInStream(); - - if (outSize == (UInt64)(Int64)-1) - currentUnPackSize = outStreamSpec->GetSize(); - - int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kCRCError; - outStream.Release(); - - if (result != S_OK) - { - if (result == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (result == E_NOTIMPL) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - return result; - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - -IMPL_ISetCompressCodecsInfo - -REGISTER_ARC_I( - "Rar", "rar r00", NULL, 3, - kMarker, - 0, - NArcInfoFlags::kFindSignature, - NULL) - -}} +// RarHandler.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/PropVariantUtils.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../IPassword.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/MethodId.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Crypto/Rar20Crypto.h" +#include "../../Crypto/RarAes.h" + +#include "../Common/FindSignature.h" +#include "../Common/ItemNameUtils.h" +#include "../Common/OutStreamWithCRC.h" + +#include "../HandlerCont.h" + +#include "RarVol.h" +#include "RarHandler.h" + +using namespace NWindows; + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +namespace NArchive { +namespace NRar { + +static const Byte kMarker[NHeader::kMarkerSize] = + { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; + +const unsigned kPasswordLen_MAX = 127; + +bool CItem::IgnoreItem() const +{ + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0); + } + return false; +} + +bool CItem::IsDir() const +{ + if (GetDictSize() == NHeader::NFile::kDictDirectoryValue) + return true; + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + return true; + } + return false; +} + +UInt32 CItem::GetWinAttrib() const +{ + UInt32 a; + switch (HostOS) + { + case NHeader::NFile::kHostMSDOS: + case NHeader::NFile::kHostOS2: + case NHeader::NFile::kHostWin32: + a = Attrib; + break; + default: + a = 0; // must be converted from unix value; + } + if (IsDir()) + a |= NHeader::NFile::kWinFileDirectoryAttributeMask; + return a; +} + +static const char * const kHostOS[] = +{ + "MS DOS" + , "OS/2" + , "Win32" + , "Unix" + , "Mac OS" + , "BeOS" +}; + +static const char * const k_Flags[] = +{ + "Volume" + , "Comment" + , "Lock" + , "Solid" + , "NewVolName" // pack_comment in old versuons + , "Authenticity" + , "Recovery" + , "BlockEncryption" + , "FirstVolume" + , "EncryptVer" // 9 +}; + +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd, + k_ErrorType_DecryptionError +}; + +class CInArchive +{ + IInStream *m_Stream; + UInt64 m_StreamStartPosition; + UString _unicodeNameBuffer; + CByteBuffer _comment; + CByteBuffer m_FileHeaderData; + NHeader::NBlock::CBlock m_BlockHeader; + NCrypto::NRar3::CDecoder *m_RarAESSpec; + CMyComPtr m_RarAES; + CAlignedBuffer m_DecryptedDataAligned; + UInt32 m_DecryptedDataSize; + bool m_CryptoMode; + UInt32 m_CryptoPos; + + + HRESULT ReadBytesSpec(void *data, size_t *size); + bool ReadBytesAndTestSize(void *data, UInt32 size); + void ReadName(const Byte *p, unsigned nameSize, CItem &item); + bool ReadHeaderReal(const Byte *p, unsigned size, CItem &item); + + HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit); + + void AddToSeekValue(UInt64 addValue) + { + m_Position += addValue; + } + + void FinishCryptoBlock() + { + if (m_CryptoMode) + while ((m_CryptoPos & 0xF) != 0) + { + m_CryptoPos++; + m_Position++; + } + } + +public: + UInt64 m_Position; + CInArcInfo ArcInfo; + bool HeaderErrorWarning; + + HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit); + HRESULT GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, + bool &filled, EErrorType &error); +}; + +static bool CheckHeaderCrc(const Byte *header, size_t headerSize) +{ + return Get16(header) == (UInt16)(CrcCalc(header + 2, headerSize - 2) & 0xFFFF); +} + +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + HeaderErrorWarning = false; + m_CryptoMode = false; + RINOK(InStream_GetPos_GetSize(stream, m_StreamStartPosition, ArcInfo.FileSize)) + m_Position = m_StreamStartPosition; + + UInt64 arcStartPos = m_StreamStartPosition; + { + Byte marker[NHeader::kMarkerSize]; + RINOK(ReadStream_FALSE(stream, marker, NHeader::kMarkerSize)) + if (memcmp(marker, kMarker, NHeader::kMarkerSize) == 0) + m_Position += NHeader::kMarkerSize; + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + RINOK(InStream_SeekSet(stream, m_StreamStartPosition)) + RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize, + searchHeaderSizeLimit, arcStartPos)) + m_Position = arcStartPos + NHeader::kMarkerSize; + RINOK(InStream_SeekSet(stream, m_Position)) + } + } + Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1]; + + RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize)) + AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize); + + + const UInt32 blockSize = Get16(buf + 5); + + ArcInfo.EncryptVersion = 0; + ArcInfo.Flags = Get16(buf + 3); + + UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize; + + /* + if (ArcInfo.IsThereEncryptVer()) + { + if (blockSize <= headerSize) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1)); + AddToSeekValue(1); + ArcInfo.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize]; + headerSize += 1; + } + */ + + if (blockSize < headerSize + || buf[2] != NHeader::NBlockType::kArchiveHeader + || !CheckHeaderCrc(buf, headerSize)) + return S_FALSE; + + size_t commentSize = blockSize - headerSize; + _comment.Alloc(commentSize); + RINOK(ReadStream_FALSE(stream, _comment, commentSize)) + AddToSeekValue(commentSize); + m_Stream = stream; + ArcInfo.StartPos = arcStartPos; + return S_OK; +} + +HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize) +{ + if (m_CryptoMode) + { + size_t size = *resSize; + *resSize = 0; + const Byte *bufData = m_DecryptedDataAligned; + UInt32 bufSize = m_DecryptedDataSize; + size_t i; + for (i = 0; i < size && m_CryptoPos < bufSize; i++) + ((Byte *)data)[i] = bufData[m_CryptoPos++]; + *resSize = i; + return S_OK; + } + return ReadStream(m_Stream, data, resSize); +} + +bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size) +{ + size_t processed = size; + if (ReadBytesSpec(data, &processed) != S_OK) + return false; + return processed == size; +} + + +static unsigned DecodeUnicodeFileName(const Byte *name, const Byte *encName, + unsigned encSize, wchar_t *unicodeName, unsigned maxDecSize) +{ + unsigned encPos = 0; + unsigned decPos = 0; + unsigned flagBits = 0; + Byte flags = 0; + + if (encPos >= encSize) + return 0; // error + const unsigned highBits = ((unsigned)encName[encPos++]) << 8; + + while (encPos < encSize && decPos < maxDecSize) + { + if (flagBits == 0) + { + flags = encName[encPos++]; + flagBits = 8; + } + + if (encPos >= encSize) + break; // error + unsigned len = encName[encPos++]; + + flagBits -= 2; + const unsigned mode = (flags >> flagBits) & 3; + + if (mode != 3) + { + if (mode == 1) + len += highBits; + else if (mode == 2) + { + if (encPos >= encSize) + break; // error + len += ((unsigned)encName[encPos++] << 8); + } + unicodeName[decPos++] = (wchar_t)len; + } + else + { + if (len & 0x80) + { + if (encPos >= encSize) + break; // error + Byte correction = encName[encPos++]; + for (len = (len & 0x7f) + 2; len > 0 && decPos < maxDecSize; len--, decPos++) + unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + highBits); + } + else + for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++) + unicodeName[decPos] = name[decPos]; + } + } + + return decPos < maxDecSize ? decPos : maxDecSize - 1; +} + + +void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item) +{ + item.UnicodeName.Empty(); + if (nameSize > 0) + { + unsigned i; + for (i = 0; i < nameSize && p[i] != 0; i++); + item.Name.SetFrom((const char *)p, i); + + if (item.HasUnicodeName()) + { + if (i < nameSize) + { + i++; + unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400); + unsigned len = DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer.GetBuf(uNameSizeMax), uNameSizeMax); + _unicodeNameBuffer.ReleaseBuf_SetEnd(len); + item.UnicodeName = _unicodeNameBuffer; + } + else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName)) + item.UnicodeName.Empty(); + } + } + else + item.Name.Empty(); +} + +static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) +{ + rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); + const unsigned numDigits = (mask & 3); + rarTime.SubTime[0] = + rarTime.SubTime[1] = + rarTime.SubTime[2] = 0; + if (numDigits > size) + return -1; + for (unsigned i = 0; i < numDigits; i++) + rarTime.SubTime[3 - numDigits + i] = p[i]; + return (int)numDigits; +} + +#define READ_TIME(_mask_, _ttt_) \ + { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += (unsigned)size2, size -= (unsigned)size2; } + +#define READ_TIME_2(_mask_, _def_, _ttt_) \ + _def_ = ((_mask_ & 8) != 0); if (_def_) \ + { if (size < 4) return false; \ + _ttt_ .DosTime = Get32(p); p += 4; size -= 4; \ + READ_TIME(_mask_, _ttt_); } \ + + +bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item) +{ + const Byte *pStart = p; + + item.Clear(); + item.Flags = m_BlockHeader.Flags; + + const unsigned kFileHeaderSize = 25; + + if (size < kFileHeaderSize) + return false; + + item.PackSize = Get32(p); + item.Size = Get32(p + 4); + item.HostOS = p[8]; + item.FileCRC = Get32(p + 9); + item.MTime.DosTime = Get32(p + 13); + item.UnPackVersion = p[17]; + item.Method = p[18]; + unsigned nameSize = Get16(p + 19); + item.Attrib = Get32(p + 21); + + item.MTime.LowSecond = 0; + item.MTime.SubTime[0] = + item.MTime.SubTime[1] = + item.MTime.SubTime[2] = 0; + + p += kFileHeaderSize; + size -= kFileHeaderSize; + if ((item.Flags & NHeader::NFile::kSize64Bits) != 0) + { + if (size < 8) + return false; + item.PackSize |= ((UInt64)Get32(p) << 32); + if (item.PackSize >= ((UInt64)1 << 63)) + return false; + item.Size |= ((UInt64)Get32(p + 4) << 32); + p += 8; + size -= 8; + } + if (nameSize > size) + return false; + ReadName(p, nameSize, item); + p += nameSize; + size -= nameSize; + + /* + // It was commented, since it's difficult to support alt Streams for solid archives. + if (m_BlockHeader.Type == NHeader::NBlockType::kSubBlock) + { + if (item.HasSalt()) + { + if (size < sizeof(item.Salt)) + return false; + size -= sizeof(item.Salt); + p += sizeof(item.Salt); + } + if (item.Name == "ACL" && size == 0) + { + item.IsAltStream = true; + item.Name.Empty(); + item.UnicodeName.SetFromAscii(".ACL"); + } + else if (item.Name == "STM" && size != 0 && (size & 1) == 0) + { + item.IsAltStream = true; + item.Name.Empty(); + for (UInt32 i = 0; i < size; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + return false; + item.UnicodeName += c; + } + } + } + */ + + if (item.HasSalt()) + { + if (size < sizeof(item.Salt)) + return false; + for (unsigned i = 0; i < sizeof(item.Salt); i++) + item.Salt[i] = p[i]; + p += sizeof(item.Salt); + size -= (unsigned)sizeof(item.Salt); + } + + // some rar archives have HasExtTime flag without field. + if (size >= 2 && item.HasExtTime()) + { + Byte aMask = (Byte)(p[0] >> 4); + Byte b = p[1]; + p += 2; + size -= 2; + Byte mMask = (Byte)(b >> 4); + Byte cMask = (Byte)(b & 0xF); + if ((mMask & 8) != 0) + { + READ_TIME(mMask, item.MTime) + } + READ_TIME_2(cMask, item.CTimeDefined, item.CTime) + READ_TIME_2(aMask, item.ATimeDefined, item.ATime) + } + + unsigned fileHeaderWithNameSize = 7 + (unsigned)(p - pStart); + + item.Position = m_Position; + item.MainPartSize = fileHeaderWithNameSize; + item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize); + + if (m_CryptoMode) + item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF); + else + item.AlignSize = 0; + AddToSeekValue(m_BlockHeader.HeadSize); + + // return (m_BlockHeader.Type != NHeader::NBlockType::kSubBlock || item.IsAltStream); + return true; +} + +HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, bool &filled, EErrorType &error) +{ + filled = false; + error = k_ErrorType_OK; + for (;;) + { + RINOK(InStream_SeekSet(m_Stream, m_Position)) + ArcInfo.EndPos = m_Position; + if (!m_CryptoMode && (ArcInfo.Flags & + NHeader::NArchive::kBlockHeadersAreEncrypted) != 0) + { + m_CryptoMode = false; + if (!getTextPassword) + { + error = k_ErrorType_DecryptionError; + return S_OK; // return S_FALSE; + } + if (!m_RarAES) + { + m_RarAESSpec = new NCrypto::NRar3::CDecoder; + m_RarAES = m_RarAESSpec; + } + // m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld()); + + { + // Salt + const UInt32 kSaltSize = 8; + Byte salt[kSaltSize]; + if (!ReadBytesAndTestSize(salt, kSaltSize)) + return S_FALSE; + m_Position += kSaltSize; + RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) + } + + { + // Password + CMyComBSTR_Wipe password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + unsigned len = 0; + if (password) + len = MyStringLen(password); + if (len > kPasswordLen_MAX) + len = kPasswordLen_MAX; + + CByteBuffer_Wipe buffer(len * 2); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = password[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + + m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2); + } + + const UInt32 kDecryptedBufferSize = (1 << 12); + if (m_DecryptedDataAligned.Size() == 0) + { + // const UInt32 kAlign = 16; + m_DecryptedDataAligned.AllocAtLeast(kDecryptedBufferSize); + if (!m_DecryptedDataAligned.IsAllocated()) + return E_OUTOFMEMORY; + } + RINOK(m_RarAES->Init()) + size_t decryptedDataSizeT = kDecryptedBufferSize; + RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT)) + m_DecryptedDataSize = (UInt32)decryptedDataSizeT; + m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize); + + m_CryptoMode = true; + m_CryptoPos = 0; + } + + m_FileHeaderData.AllocAtLeast(7); + size_t processed = 7; + RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed)) + if (processed != 7) + { + if (processed != 0) + error = k_ErrorType_UnexpectedEnd; + ArcInfo.EndPos = m_Position + processed; // test it + return S_OK; + } + + const Byte *p = m_FileHeaderData; + m_BlockHeader.CRC = Get16(p + 0); + m_BlockHeader.Type = p[2]; + m_BlockHeader.Flags = Get16(p + 3); + m_BlockHeader.HeadSize = Get16(p + 5); + + if (m_BlockHeader.HeadSize < 7) + { + error = k_ErrorType_Corrupted; + return S_OK; + // ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive); + } + + if (m_BlockHeader.Type < NHeader::NBlockType::kFileHeader || + m_BlockHeader.Type > NHeader::NBlockType::kEndOfArchive) + { + error = m_CryptoMode ? + k_ErrorType_DecryptionError : + k_ErrorType_Corrupted; + return S_OK; + } + + if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive) + { + bool footerError = false; + + unsigned expectHeadLen = 7; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) + expectHeadLen += 4; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) + expectHeadLen += 2; + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_RevSpace) + expectHeadLen += 7; + + // rar 5.0 beta 1 writes incorrect RevSpace and headSize + + if (m_BlockHeader.HeadSize < expectHeadLen) + HeaderErrorWarning = true; + + if (m_BlockHeader.HeadSize > 7) + { + /* We suppose that EndOfArchive header is always small. + It's only 20 bytes for multivolume + Fix the limit, if larger footers are possible */ + if (m_BlockHeader.HeadSize > (1 << 8)) + footerError = true; + else + { + if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) + m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); + UInt32 afterSize = m_BlockHeader.HeadSize - 7; + if (ReadBytesAndTestSize(m_FileHeaderData + 7, afterSize)) + processed += afterSize; + else + { + if (!m_CryptoMode) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + footerError = true; + } + } + } + + if (footerError || !CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize)) + { + error = m_CryptoMode ? + k_ErrorType_DecryptionError : + k_ErrorType_Corrupted; + } + else + { + ArcInfo.EndFlags = m_BlockHeader.Flags; + UInt32 offset = 7; + + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) + { + if (processed < offset + 4) + error = k_ErrorType_Corrupted; + else + ArcInfo.DataCRC = Get32(m_FileHeaderData + offset); + offset += 4; + } + + if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) + { + if (processed < offset + 2) + error = k_ErrorType_Corrupted; + else + ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset); + } + + ArcInfo.EndOfArchive_was_Read = true; + } + + m_Position += processed; + FinishCryptoBlock(); + ArcInfo.EndPos = m_Position; + return S_OK; + } + + if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader + /* || m_BlockHeader.Type == NHeader::NBlockType::kSubBlock */) + { + if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize) + m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7); + // m_CurData = (Byte *)m_FileHeaderData; + // m_PosLimit = m_BlockHeader.HeadSize; + if (!ReadBytesAndTestSize(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7)) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + + bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item); + if (okItem) + { + if (!CheckHeaderCrc(m_FileHeaderData, (unsigned)m_BlockHeader.HeadSize - item.CommentSize)) + { + error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError); + return S_OK; + } + filled = true; + } + + FinishCryptoBlock(); + m_CryptoMode = false; + // Move Position to compressed Data; + RINOK(InStream_SeekSet(m_Stream, m_Position)) + AddToSeekValue(item.PackSize); // m_Position points to next header; + // if (okItem) + return S_OK; + /* + else + continue; + */ + } + + if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10)) + { + error = k_ErrorType_DecryptionError; + return S_OK; + } + + if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0) + { + if (m_FileHeaderData.Size() < 7 + 4) + m_FileHeaderData.ChangeSize_KeepData(7 + 4, 7); + if (!ReadBytesAndTestSize(m_FileHeaderData + 7, 4)) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + UInt32 dataSize = Get32(m_FileHeaderData + 7); + AddToSeekValue(dataSize); + if (m_CryptoMode && dataSize > (1 << 27)) + { + error = k_ErrorType_DecryptionError; + return S_OK; + } + m_CryptoPos = m_BlockHeader.HeadSize; + } + else + m_CryptoPos = 0; + + { + UInt64 newPos = m_Position + m_BlockHeader.HeadSize; + if (newPos > ArcInfo.FileSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + } + AddToSeekValue(m_BlockHeader.HeadSize); + FinishCryptoBlock(); + m_CryptoMode = false; + } +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + + kpidEncrypted, + kpidSolid, + kpidCommented, + kpidSplitBefore, + kpidSplitAfter, + kpidCRC, + kpidHostOS, + kpidMethod, + kpidUnpackVer, + + kpidVolumeIndex +}; + +static const Byte kArcProps[] = +{ + kpidTotalPhySize, + kpidCharacts, + kpidSolid, + kpidNumBlocks, + // kpidEncrypted, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes + // kpidCommented +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +UInt64 CHandler::GetPackSize(unsigned refIndex) const +{ + const CRefItem &refItem = _refItems[refIndex]; + UInt64 totalPackSize = 0; + for (unsigned i = 0; i < refItem.NumItems; i++) + totalPackSize += _items[refItem.ItemIndex + i].PackSize; + return totalPackSize; +} + +bool CHandler::IsSolid(unsigned refIndex) const +{ + const CItem &item = _items[_refItems[refIndex].ItemIndex]; + if (item.UnPackVersion < 20) + { + if (_arcInfo.IsSolid()) + return (refIndex > 0); + return false; + } + return item.IsSolid(); +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidVolumeIndex: if (_arcInfo.Is_VolNumber_Defined()) prop = (UInt32)_arcInfo.VolNumber; break; + case kpidSolid: prop = _arcInfo.IsSolid(); break; + case kpidCharacts: + { + AString s (FlagsToString(k_Flags, Z7_ARRAY_SIZE(k_Flags), _arcInfo.Flags)); + // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop); + if (_arcInfo.Is_DataCRC_Defined()) + { + s.Add_Space_if_NotEmpty(); + s += "VolCRC"; + } + prop = s; + break; + } + // case kpidEncrypted: prop = _arcInfo.IsEncrypted(); break; // it's for encrypted names. + case kpidIsVolume: prop = _arcInfo.IsVolume(); break; + case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break; + case kpidOffset: if (_arcs.Size() == 1 && _arcInfo.StartPos != 0) prop = _arcInfo.StartPos; break; + + case kpidTotalPhySize: + { + if (_arcs.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, _arcs) + sum += _arcs[v].PhySize; + prop = sum; + } + break; + } + + case kpidPhySize: + { + if (_arcs.Size() != 0) + prop = _arcInfo.GetPhySize(); + break; + } + + // case kpidCommented: prop = _arcInfo.IsCommented(); break; + + case kpidNumBlocks: + { + UInt32 numBlocks = 0; + FOR_VECTOR (i, _refItems) + if (!IsSolid(i)) + numBlocks++; + prop = (UInt32)numBlocks; + break; + } + + + case kpidError: + { + // if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + + if (/* &_missingVol || */ !_missingVolName.IsEmpty()) + { + UString s ("Missing volume : "); + s += _missingVolName; + prop = s; + } + break; + } + + case kpidErrorFlags: + { + UInt32 v = _errorFlags; + if (!_isArc) + v |= kpv_ErrorFlags_IsNotArc; + prop = v; + break; + } + + case kpidWarningFlags: + { + if (_warningFlags != 0) + prop = _warningFlags; + break; + } + + case kpidExtension: + if (_arcs.Size() == 1) + { + if (_arcInfo.Is_VolNumber_Defined()) + { + AString s ("part"); + UInt32 v = (UInt32)_arcInfo.VolNumber + 1; + if (v < 10) + s += '0'; + s.Add_UInt32(v); + s += ".rar"; + prop = s; + } + } + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _refItems.Size(); + return S_OK; +} + +static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &ft) +{ + if (!NTime::DosTime_To_FileTime(rarTime.DosTime, ft)) + return false; + UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + v += (UInt32)rarTime.LowSecond * 10000000; + v += + ((UInt32)rarTime.SubTime[2] << 16) + + ((UInt32)rarTime.SubTime[1] << 8) + + ((UInt32)rarTime.SubTime[0]); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + return true; +} + +static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) +{ + FILETIME localFileTime, utc; + if (RarTimeToFileTime(rarTime, localFileTime) + && LocalFileTimeToFileTime(&localFileTime, &utc)) + prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns); + /* + else + utc.dwHighDateTime = utc.dwLowDateTime = 0; + // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns); + */ +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CRefItem &refItem = _refItems[index]; + const CItem &item = _items[refItem.ItemIndex]; + const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + + /* + const CItem *mainItem = &item; + if (item.BaseFileIndex >= 0) + mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex]; + */ + switch (propID) + { + case kpidPath: + { + /* + UString u; + if (item.BaseFileIndex >= 0) + u = mainItem->GetName(); + u += item.GetName(); + */ + prop = (const wchar_t *)NItemName::WinPathToOsPath(item.GetName()); + break; + } + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: if (lastItem.Is_Size_Defined()) prop = lastItem.Size; break; + case kpidPackSize: prop = GetPackSize(index); break; + case kpidMTime: RarTimeToProp(item.MTime, prop); break; + case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break; + case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break; + case kpidAttrib: prop = item.GetWinAttrib(); break; + case kpidEncrypted: prop = item.IsEncrypted(); break; + case kpidSolid: prop = IsSolid(index); break; + case kpidCommented: prop = item.IsCommented(); break; + case kpidSplitBefore: prop = item.IsSplitBefore(); break; + case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break; + + case kpidVolumeIndex: + if (_arcInfo.Is_VolNumber_Defined()) + prop = (UInt32)(_arcInfo.VolNumber + refItem.VolumeIndex); + break; + + case kpidCRC: + { + prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC); + break; + } + case kpidUnpackVer: prop = item.UnPackVersion; break; + case kpidMethod: + { + char s[16]; + Byte m = item.Method; + if (m < (Byte)'0' || m > (Byte)'5') + ConvertUInt32ToString(m, s); + else + { + s[0] = 'm'; + s[1] = (char)m; + s[2] = 0; + if (!item.IsDir()) + { + s[2] = ':'; + ConvertUInt32ToString(16 + item.GetDictSize(), &s[3]); + } + } + prop = s; + break; + } + case kpidHostOS: + TYPE_TO_PROP(kHostOS, item.HostOS, prop); + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback) +{ + { + CMyComPtr openVolumeCallback; + CMyComPtr getTextPassword; + + CVolumeName seqName; + + UInt64 totalBytes = 0; + UInt64 curBytes = 0; + + if (openCallback) + { + openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); + } + + bool nextVol_is_Required = false; + + CInArchive archive; + + for (;;) + { + CMyComPtr inStream; + if (!_arcs.IsEmpty()) + { + if (!openVolumeCallback) + break; + + if (_arcs.Size() == 1) + { + if (!_arcInfo.IsVolume()) + break; + UString baseName; + { + NCOM::CPropVariant prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) + if (prop.vt != VT_BSTR) + break; + baseName = prop.bstrVal; + } + if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName())) + break; + /* + if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume()) + { + seqName.MakeBeforeFirstName(); + } + */ + } + + const UString volName = seqName.GetNextName(); + + HRESULT result = openVolumeCallback->GetStream(volName, &inStream); + + if (result != S_OK && result != S_FALSE) + return result; + + if (!inStream || result != S_OK) + { + if (nextVol_is_Required) + _missingVolName = volName; + break; + } + } + else + inStream = stream; + + UInt64 endPos; + RINOK(InStream_AtBegin_GetSize(inStream, endPos)) + if (openCallback) + { + totalBytes += endPos; + RINOK(openCallback->SetTotal(NULL, &totalBytes)) + } + + RINOK(archive.Open(inStream, maxCheckStartPosition)) + _isArc = true; + CItem item; + + for (;;) + { + if (archive.m_Position > endPos) + { + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + break; + } + + EErrorType error; + // bool decryptionError; + // AString errorMessageLoc; + bool filled; + HRESULT result = archive.GetNextItem(item, getTextPassword, filled, error); + + if (error != k_ErrorType_OK) + { + if (error == k_ErrorType_UnexpectedEnd) + _errorFlags |= kpv_ErrorFlags_UnexpectedEnd; + else if (error == k_ErrorType_Corrupted) + _errorFlags |= kpv_ErrorFlags_HeadersError; + else if (error == k_ErrorType_DecryptionError) + _errorFlags |= kpv_ErrorFlags_EncryptedHeadersError; + + // AddErrorMessage(errorMessageLoc); + } + RINOK(result) + + if (!filled) + { + if (error == k_ErrorType_DecryptionError && _items.IsEmpty()) + return S_FALSE; + + if (archive.ArcInfo.ExtraZeroTail_is_Possible()) + { + /* if there is recovery record for multivolume archive, + RAR adds 18 bytes (ZERO bytes) at the end for alignment. + We must skip these bytes to prevent phySize warning. */ + RINOK(InStream_SeekSet(inStream, archive.ArcInfo.EndPos)) + bool areThereNonZeros; + UInt64 numZeros; + const UInt64 maxSize = 1 << 12; + RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize)) + if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize) + archive.ArcInfo.EndPos += numZeros; + } + break; + } + + if (item.IgnoreItem()) + continue; + + bool needAdd = true; + + if (item.IsSplitBefore()) + { + if (!_refItems.IsEmpty()) + { + CRefItem &refItem = _refItems.Back(); + refItem.NumItems++; + needAdd = false; + } + } + + if (needAdd) + { + CRefItem refItem; + refItem.ItemIndex = _items.Size(); + refItem.NumItems = 1; + refItem.VolumeIndex = _arcs.Size(); + _refItems.Add(refItem); + } + + _items.Add(item); + + if (openCallback && _items.Size() % 100 == 0) + { + UInt64 numFiles = _items.Size(); + UInt64 numBytes = curBytes + item.Position; + RINOK(openCallback->SetCompleted(&numFiles, &numBytes)) + } + } + + if (archive.HeaderErrorWarning) + _warningFlags |= kpv_ErrorFlags_HeadersError; + + /* + if (archive.m_Position < endPos) + _warningFlags |= kpv_ErrorFlags_DataAfterEnd; + */ + if (_arcs.IsEmpty()) + _arcInfo = archive.ArcInfo; + // _arcInfo.EndPos = archive.EndPos; + + curBytes += endPos; + { + CArc &arc = _arcs.AddNew(); + arc.PhySize = archive.ArcInfo.GetPhySize(); + arc.Stream = inStream; + } + + nextVol_is_Required = false; + + if (!archive.ArcInfo.IsVolume()) + break; + + if (archive.ArcInfo.EndOfArchive_was_Read) + { + if (!archive.ArcInfo.AreMoreVolumes()) + break; + nextVol_is_Required = true; + } + } + } + + /* + int baseFileIndex = -1; + for (unsigned i = 0; i < _refItems.Size(); i++) + { + CItem &item = _items[_refItems[i].ItemIndex]; + if (item.IsAltStream) + item.BaseFileIndex = baseFileIndex; + else + baseFileIndex = i; + } + */ + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback)) +{ + COM_TRY_BEGIN + Close(); + // try + { + HRESULT res = Open2(stream, maxCheckStartPosition, openCallback); + /* + if (res != S_OK) + Close(); + */ + + return res; + } + // catch(const CInArchiveException &) { Close(); return S_FALSE; } + // catch(...) { Close(); throw; } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + COM_TRY_BEGIN + // _errorMessage.Empty(); + _missingVolName.Empty(); + _errorFlags = 0; + _warningFlags = 0; + _isArc = false; + _refItems.Clear(); + _items.Clear(); + _arcs.Clear(); + return S_OK; + COM_TRY_END +} + +struct CMethodItem +{ + Byte RarUnPackVersion; + CMyComPtr Coder; +}; + + +Z7_CLASS_IMP_NOQIB_1( + CVolsInStream + , ISequentialInStream +) + UInt64 _rem; + ISequentialInStream *_stream; + const CObjectVector *_arcs; + const CObjectVector *_items; + CRefItem _refItem; + unsigned _curIndex; + UInt32 _crc; + bool _calcCrc; + +public: + void Init(const CObjectVector *arcs, + const CObjectVector *items, + const CRefItem &refItem) + { + _arcs = arcs; + _items = items; + _refItem = refItem; + _curIndex = 0; + _stream = NULL; + CrcIsOK = true; + } + + bool CrcIsOK; +}; + + +Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + UInt32 realProcessedSize = 0; + + while (size != 0) + { + if (!_stream) + { + if (_curIndex >= _refItem.NumItems) + break; + const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex]; + unsigned volIndex = _refItem.VolumeIndex + _curIndex; + if (volIndex >= _arcs->Size()) + { + return S_OK; + // return S_FALSE; + } + IInStream *s = (*_arcs)[volIndex].Stream; + RINOK(InStream_SeekSet(s, item.GetDataPosition())) + _stream = s; + _calcCrc = (CrcIsOK && item.IsSplitAfter()); + _crc = CRC_INIT_VAL; + _rem = item.PackSize; + } + { + UInt32 cur = size; + if (cur > _rem) + cur = (UInt32)_rem; + UInt32 num = cur; + HRESULT res = _stream->Read(data, cur, &cur); + if (_calcCrc) + _crc = CrcUpdate(_crc, data, cur); + realProcessedSize += cur; + if (processedSize) + *processedSize = realProcessedSize; + data = (Byte *)data + cur; + size -= cur; + _rem -= cur; + if (_rem == 0) + { + const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex]; + _curIndex++; + if (_calcCrc && CRC_GET_DIGEST(_crc) != item.FileCRC) + CrcIsOK = false; + _stream = NULL; + } + if (res != S_OK) + return res; + if (realProcessedSize != 0) + return S_OK; + if (cur == 0 && num != 0) + return S_OK; + } + } + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + CMyComPtr getTextPassword; + UInt64 // censoredTotalUnPacked = 0, + // censoredTotalPacked = 0, + importantTotalUnPacked = 0; + // importantTotalPacked = 0; + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _refItems.Size(); + if (numItems == 0) + return S_OK; + unsigned lastIndex = 0; + CRecordVector importantIndexes; + CRecordVector extractStatuses; + + bool isThereUndefinedSize = false; + + for (UInt32 t = 0; t < numItems; t++) + { + unsigned index = allFilesMode ? t : indices[t]; + + { + const CRefItem &refItem = _refItems[index]; + const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1]; + + if (item.Is_Size_Defined()) + { + // censoredTotalUnPacked += item.Size; + } + else + isThereUndefinedSize = true; + + // censoredTotalPacked += item.PackSize; + } + + unsigned j; + for (j = lastIndex; j <= index; j++) + // if (!_items[_refItems[j].ItemIndex].IsSolid()) + if (!IsSolid(j)) + lastIndex = j; + + for (j = lastIndex; j <= index; j++) + { + const CRefItem &refItem = _refItems[j]; + const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1]; + + if (item.Is_Size_Defined()) + importantTotalUnPacked += item.Size; + else + isThereUndefinedSize = true; + // importantTotalPacked += item.PackSize; + importantIndexes.Add(j); + extractStatuses.Add(j == index); + } + + lastIndex = index + 1; + } + + if (importantTotalUnPacked != 0 || !isThereUndefinedSize) + { + RINOK(extractCallback->SetTotal(importantTotalUnPacked)) + } + + UInt64 currentImportantTotalUnPacked = 0; + UInt64 currentImportantTotalPacked = 0; + UInt64 currentUnPackSize, currentPackSize; + + CObjectVector methodItems; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr copyCoder = copyCoderSpec; + + CFilterCoder *filterStreamSpec = new CFilterCoder(false); + CMyComPtr filterStream = filterStreamSpec; + + NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL; + CMyComPtr rar20CryptoDecoder; + NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL; + CMyComPtr rar3CryptoDecoder; + + CVolsInStream *volsInStreamSpec = NULL; + CMyComPtr volsInStream; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + bool solidStart = true; + + for (unsigned i = 0;; + i++, + currentImportantTotalUnPacked += currentUnPackSize, + currentImportantTotalPacked += currentPackSize) + { + lps->InSize = currentImportantTotalPacked; + lps->OutSize = currentImportantTotalUnPacked; + RINOK(lps->SetCur()) + + if (i >= importantIndexes.Size()) + break; + + CMyComPtr realOutStream; + + Int32 askMode; + if (extractStatuses[i]) + askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + else + askMode = NExtract::NAskMode::kSkip; + + UInt32 index = importantIndexes[i]; + + const CRefItem &refItem = _refItems[index]; + const CItem &item = _items[refItem.ItemIndex]; + const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1]; + + UInt64 outSize = (UInt64)(Int64)-1; + currentUnPackSize = 0; + if (lastItem.Is_Size_Defined()) + { + outSize = lastItem.Size; + currentUnPackSize = outSize; + } + + currentPackSize = GetPackSize(index); + + if (item.IgnoreItem()) + continue; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (!IsSolid(index)) + solidStart = true; + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + bool mustBeProcessedAnywhere = false; + if (i < importantIndexes.Size() - 1) + { + // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]]; + // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex]; + // mustBeProcessedAnywhere = nextItemInfo.IsSolid(); + mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]); + } + + if (!mustBeProcessedAnywhere && !testMode && !realOutStream) + continue; + + if (!realOutStream && !testMode) + askMode = NExtract::NAskMode::kSkip; + + RINOK(extractCallback->PrepareOperation(askMode)) + + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + + if (!volsInStream) + { + volsInStreamSpec = new CVolsInStream; + volsInStream = volsInStreamSpec; + } + + volsInStreamSpec->Init(&_arcs, &_items, refItem); + + UInt64 packSize = currentPackSize; + + // packedPos += item.PackSize; + // unpackedPos += 0; + + CMyComPtr inStream; + + if (item.IsEncrypted()) + { + // CMyComPtr cryptoSetPassword; + + if (item.UnPackVersion >= 29) + { + if (!rar3CryptoDecoder) + { + rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder; + rar3CryptoDecoder = rar3CryptoDecoderSpec; + } + // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); + /* + CMyComPtr cryptoProperties; + RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, + &cryptoProperties)); + */ + RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)) + filterStreamSpec->Filter = rar3CryptoDecoder; + } + else if (item.UnPackVersion >= 20) + { + if (!rar20CryptoDecoder) + { + rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder; + rar20CryptoDecoder = rar20CryptoDecoderSpec; + } + filterStreamSpec->Filter = rar20CryptoDecoder; + } + else + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + continue; + } + + // RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); + + if (!getTextPassword) + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); + + if (!getTextPassword) + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + continue; + } + + // if (getTextPassword) + { + CMyComBSTR_Wipe password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + + if (item.UnPackVersion >= 29) + { + unsigned len = 0; + if (password) + len = MyStringLen(password); + if (len > kPasswordLen_MAX) + len = kPasswordLen_MAX; + CByteBuffer_Wipe buffer(len * 2); + for (unsigned k = 0; k < len; k++) + { + wchar_t c = password[k]; + ((Byte *)buffer)[k * 2] = (Byte)c; + ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); + } + rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2); + } + else + { + AString_Wipe oemPassword; + if (password) + { + UString_Wipe unicode; + unicode.SetFromBstr(password); + if (unicode.Len() > kPasswordLen_MAX) + unicode.DeleteFrom(kPasswordLen_MAX); + UnicodeStringToMultiByte2(oemPassword, unicode, CP_OEMCP); + } + rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()); + } + } + /* + else + { + RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0)); + } + */ + + filterStreamSpec->SetInStream(volsInStream); + filterStreamSpec->SetOutStreamSize(NULL); + inStream = filterStream; + } + else + { + inStream = volsInStream; + } + + CMyComPtr commonCoder; + + switch (item.Method) + { + case '0': + { + commonCoder = copyCoder; + break; + } + case '1': + case '2': + case '3': + case '4': + case '5': + { + unsigned m; + for (m = 0; m < methodItems.Size(); m++) + if (methodItems[m].RarUnPackVersion == item.UnPackVersion) + break; + if (m == methodItems.Size()) + { + CMethodItem mi; + mi.RarUnPackVersion = item.UnPackVersion; + + mi.Coder.Release(); + if (item.UnPackVersion <= 40) + { + UInt32 methodID = 0x40300; + if (item.UnPackVersion < 20) + methodID += 1; + else if (item.UnPackVersion < 29) + methodID += 2; + else + methodID += 3; + RINOK(CreateCoder_Id(EXTERNAL_CODECS_VARS methodID, false, mi.Coder)) + } + + if (!mi.Coder) + { + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + continue; + } + + m = methodItems.Add(mi); + } + CMyComPtr decoder = methodItems[m].Coder; + + CMyComPtr compressSetDecoderProperties; + RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2, + &compressSetDecoderProperties)) + + Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0); + if (solidStart) + { + isSolid = 0; + solidStart = false; + } + + + RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1)) + + commonCoder = decoder; + break; + } + default: + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)) + continue; + } + + HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, progress); + + if (item.IsEncrypted()) + filterStreamSpec->ReleaseInStream(); + + if (outSize == (UInt64)(Int64)-1) + currentUnPackSize = outStreamSpec->GetSize(); + + int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kCRCError; + outStream.Release(); + + if (result != S_OK) + { + if (result == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (result == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return result; + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + +IMPL_ISetCompressCodecsInfo + +REGISTER_ARC_I( + "Rar", "rar r00", NULL, 3, + kMarker, + 0, + NArcInfoFlags::kFindSignature, + NULL) + +}} diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h index dbe66f753..6a1da4f00 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.h +++ b/CPP/7zip/Archive/Rar/RarHandler.h @@ -1,115 +1,115 @@ -// RarHandler.h - -#ifndef ZIP7_INC_RAR_HANDLER_H -#define ZIP7_INC_RAR_HANDLER_H - -#include "../IArchive.h" - -#include "../../Common/CreateCoder.h" - -#include "RarItem.h" - -namespace NArchive { -namespace NRar { - -struct CInArcInfo -{ - UInt32 Flags; - Byte EncryptVersion; - - UInt64 StartPos; - UInt64 EndPos; - UInt64 FileSize; - - UInt32 EndFlags; - UInt32 VolNumber; - UInt32 DataCRC; - bool EndOfArchive_was_Read; - - CInArcInfo(): EndFlags(0), VolNumber(0), EndOfArchive_was_Read(false) {} - - UInt64 GetPhySize() const { return EndPos - StartPos; } - - bool ExtraZeroTail_is_Possible() const { return IsVolume() && IsRecovery() && EndOfArchive_was_Read; } - - bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } - bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } - // kLock - bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } - bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } - // kAuthenticity - bool IsRecovery() const { return (Flags & NHeader::NArchive::kRecovery) != 0; } - bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } - bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 0; } - - // bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; } - // bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); } - - bool AreMoreVolumes() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_NextVol) != 0; } - bool Is_VolNumber_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) != 0; } - bool Is_DataCRC_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) != 0; } -}; - -struct CArc -{ - CMyComPtr Stream; - UInt64 PhySize; - // CByteBuffer Comment; - - CArc(): PhySize(0) {} - ISequentialInStream *CreateLimitedStream(UInt64 offset, UInt64 size) const; -}; - -struct CRefItem -{ - unsigned VolumeIndex; - unsigned ItemIndex; - unsigned NumItems; -}; - -class CHandler Z7_final: - public IInArchive, - Z7_PUBLIC_ISetCompressCodecsInfo_IFEC - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IInArchive) - Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInArchive) - DECL_ISetCompressCodecsInfo - - bool _isArc; - - CRecordVector _refItems; - CObjectVector _items; - CObjectVector _arcs; - NArchive::NRar::CInArcInfo _arcInfo; - // AString _errorMessage; - UInt32 _errorFlags; - UInt32 _warningFlags; - UString _missingVolName; - - DECL_EXTERNAL_CODECS_VARS - - UInt64 GetPackSize(unsigned refIndex) const; - bool IsSolid(unsigned refIndex) const; - - /* - void AddErrorMessage(const AString &s) - { - if (!_errorMessage.IsEmpty()) - _errorMessage.Add_LF(); - _errorMessage += s; - } - */ - - HRESULT Open2(IInStream *stream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback); -}; - -}} - -#endif +// RarHandler.h + +#ifndef ZIP7_INC_RAR_HANDLER_H +#define ZIP7_INC_RAR_HANDLER_H + +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#include "RarItem.h" + +namespace NArchive { +namespace NRar { + +struct CInArcInfo +{ + UInt32 Flags; + Byte EncryptVersion; + + UInt64 StartPos; + UInt64 EndPos; + UInt64 FileSize; + + UInt32 EndFlags; + UInt32 VolNumber; + UInt32 DataCRC; + bool EndOfArchive_was_Read; + + CInArcInfo(): EndFlags(0), VolNumber(0), EndOfArchive_was_Read(false) {} + + UInt64 GetPhySize() const { return EndPos - StartPos; } + + bool ExtraZeroTail_is_Possible() const { return IsVolume() && IsRecovery() && EndOfArchive_was_Read; } + + bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; } + bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; } + // kLock + bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; } + bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; } + // kAuthenticity + bool IsRecovery() const { return (Flags & NHeader::NArchive::kRecovery) != 0; } + bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; } + bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 0; } + + // bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; } + // bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); } + + bool AreMoreVolumes() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_NextVol) != 0; } + bool Is_VolNumber_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) != 0; } + bool Is_DataCRC_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) != 0; } +}; + +struct CArc +{ + CMyComPtr Stream; + UInt64 PhySize; + // CByteBuffer Comment; + + CArc(): PhySize(0) {} + ISequentialInStream *CreateLimitedStream(UInt64 offset, UInt64 size) const; +}; + +struct CRefItem +{ + unsigned VolumeIndex; + unsigned ItemIndex; + unsigned NumItems; +}; + +class CHandler Z7_final: + public IInArchive, + Z7_PUBLIC_ISetCompressCodecsInfo_IFEC + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IInArchive) + Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInArchive) + DECL_ISetCompressCodecsInfo + + bool _isArc; + + CRecordVector _refItems; + CObjectVector _items; + CObjectVector _arcs; + NArchive::NRar::CInArcInfo _arcInfo; + // AString _errorMessage; + UInt32 _errorFlags; + UInt32 _warningFlags; + UString _missingVolName; + + DECL_EXTERNAL_CODECS_VARS + + UInt64 GetPackSize(unsigned refIndex) const; + bool IsSolid(unsigned refIndex) const; + + /* + void AddErrorMessage(const AString &s) + { + if (!_errorMessage.IsEmpty()) + _errorMessage.Add_LF(); + _errorMessage += s; + } + */ + + HRESULT Open2(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h index cfa2d729c..031fea62f 100644 --- a/CPP/7zip/Archive/Rar/RarHeader.h +++ b/CPP/7zip/Archive/Rar/RarHeader.h @@ -1,209 +1,209 @@ -// Archive/RarHeader.h - -#ifndef ZIP7_INC_ARCHIVE_RAR_HEADER_H -#define ZIP7_INC_ARCHIVE_RAR_HEADER_H - -#include "../../../Common/MyTypes.h" - -namespace NArchive { -namespace NRar { -namespace NHeader { - -const unsigned kMarkerSize = 7; - -const unsigned kArchiveSolid = 0x1; - -namespace NBlockType -{ - enum EBlockType - { - kMarker = 0x72, - kArchiveHeader, - kFileHeader, - kCommentHeader, - kOldAuthenticity, - kOldSubBlock, - kRecoveryRecord, - kAuthenticity, - kSubBlock, - kEndOfArchive - }; -} - -namespace NArchive -{ - const UInt16 kVolume = 1; - const UInt16 kComment = 2; - const UInt16 kLock = 4; - const UInt16 kSolid = 8; - const UInt16 kNewVolName = 0x10; // ('volname.partN.rar') - const UInt16 kAuthenticity = 0x20; - const UInt16 kRecovery = 0x40; - const UInt16 kBlockEncryption = 0x80; - const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later) - - // const UInt16 kEncryptVer = 0x200; // RAR 3.6 : that feature was discarded by origial RAR - - const UInt16 kEndOfArc_Flags_NextVol = 1; - const UInt16 kEndOfArc_Flags_DataCRC = 2; - const UInt16 kEndOfArc_Flags_RevSpace = 4; - const UInt16 kEndOfArc_Flags_VolNumber = 8; - - const unsigned kHeaderSizeMin = 7; - - const unsigned kArchiveHeaderSize = 13; - - const unsigned kBlockHeadersAreEncrypted = 0x80; -} - -namespace NFile -{ - const unsigned kSplitBefore = 1 << 0; - const unsigned kSplitAfter = 1 << 1; - const unsigned kEncrypted = 1 << 2; - const unsigned kComment = 1 << 3; - const unsigned kSolid = 1 << 4; - - const unsigned kDictBitStart = 5; - const unsigned kNumDictBits = 3; - const unsigned kDictMask = (1 << kNumDictBits) - 1; - const unsigned kDictDirectoryValue = 0x7; - - const unsigned kSize64Bits = 1 << 8; - const unsigned kUnicodeName = 1 << 9; - const unsigned kSalt = 1 << 10; - const unsigned kOldVersion = 1 << 11; - const unsigned kExtTime = 1 << 12; - // const unsigned kExtFlags = 1 << 13; - // const unsigned kSkipIfUnknown = 1 << 14; - - const unsigned kLongBlock = 1 << 15; - - /* - struct CBlock - { - // UInt16 HeadCRC; - // Byte Type; - // UInt16 Flags; - // UInt16 HeadSize; - UInt32 PackSize; - UInt32 UnPackSize; - Byte HostOS; - UInt32 FileCRC; - UInt32 Time; - Byte UnPackVersion; - Byte Method; - UInt16 NameSize; - UInt32 Attributes; - }; - */ - - /* - struct CBlock32 - { - UInt16 HeadCRC; - Byte Type; - UInt16 Flags; - UInt16 HeadSize; - UInt32 PackSize; - UInt32 UnPackSize; - Byte HostOS; - UInt32 FileCRC; - UInt32 Time; - Byte UnPackVersion; - Byte Method; - UInt16 NameSize; - UInt32 Attributes; - UInt16 GetRealCRC(const void *aName, UInt32 aNameSize, - bool anExtraDataDefined = false, Byte *anExtraData = 0) const; - }; - struct CBlock64 - { - UInt16 HeadCRC; - Byte Type; - UInt16 Flags; - UInt16 HeadSize; - UInt32 PackSizeLow; - UInt32 UnPackSizeLow; - Byte HostOS; - UInt32 FileCRC; - UInt32 Time; - Byte UnPackVersion; - Byte Method; - UInt16 NameSize; - UInt32 Attributes; - UInt32 PackSizeHigh; - UInt32 UnPackSizeHigh; - UInt16 GetRealCRC(const void *aName, UInt32 aNameSize) const; - }; - */ - - const unsigned kLabelFileAttribute = 0x08; - const unsigned kWinFileDirectoryAttributeMask = 0x10; - - enum CHostOS - { - kHostMSDOS = 0, - kHostOS2 = 1, - kHostWin32 = 2, - kHostUnix = 3, - kHostMacOS = 4, - kHostBeOS = 5 - }; -} - -namespace NBlock -{ - const UInt16 kLongBlock = 1 << 15; - struct CBlock - { - UInt16 CRC; - Byte Type; - UInt16 Flags; - UInt16 HeadSize; - // UInt32 DataSize; - }; -} - -/* -struct CSubBlock -{ - UInt16 HeadCRC; - Byte HeadType; - UInt16 Flags; - UInt16 HeadSize; - UInt32 DataSize; - UInt16 SubType; - Byte Level; // Reserved : Must be 0 -}; - -struct CCommentBlock -{ - UInt16 HeadCRC; - Byte HeadType; - UInt16 Flags; - UInt16 HeadSize; - UInt16 UnpSize; - Byte UnpVer; - Byte Method; - UInt16 CommCRC; -}; - - -struct CProtectHeader -{ - UInt16 HeadCRC; - Byte HeadType; - UInt16 Flags; - UInt16 HeadSize; - UInt32 DataSize; - Byte Version; - UInt16 RecSectors; - UInt32 TotalBlocks; - Byte Mark[8]; -}; -*/ - -}}} - -#endif +// Archive/RarHeader.h + +#ifndef ZIP7_INC_ARCHIVE_RAR_HEADER_H +#define ZIP7_INC_ARCHIVE_RAR_HEADER_H + +#include "../../../Common/MyTypes.h" + +namespace NArchive { +namespace NRar { +namespace NHeader { + +const unsigned kMarkerSize = 7; + +const unsigned kArchiveSolid = 0x1; + +namespace NBlockType +{ + enum EBlockType + { + kMarker = 0x72, + kArchiveHeader, + kFileHeader, + kCommentHeader, + kOldAuthenticity, + kOldSubBlock, + kRecoveryRecord, + kAuthenticity, + kSubBlock, + kEndOfArchive + }; +} + +namespace NArchive +{ + const UInt16 kVolume = 1; + const UInt16 kComment = 2; + const UInt16 kLock = 4; + const UInt16 kSolid = 8; + const UInt16 kNewVolName = 0x10; // ('volname.partN.rar') + const UInt16 kAuthenticity = 0x20; + const UInt16 kRecovery = 0x40; + const UInt16 kBlockEncryption = 0x80; + const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later) + + // const UInt16 kEncryptVer = 0x200; // RAR 3.6 : that feature was discarded by origial RAR + + const UInt16 kEndOfArc_Flags_NextVol = 1; + const UInt16 kEndOfArc_Flags_DataCRC = 2; + const UInt16 kEndOfArc_Flags_RevSpace = 4; + const UInt16 kEndOfArc_Flags_VolNumber = 8; + + const unsigned kHeaderSizeMin = 7; + + const unsigned kArchiveHeaderSize = 13; + + const unsigned kBlockHeadersAreEncrypted = 0x80; +} + +namespace NFile +{ + const unsigned kSplitBefore = 1 << 0; + const unsigned kSplitAfter = 1 << 1; + const unsigned kEncrypted = 1 << 2; + const unsigned kComment = 1 << 3; + const unsigned kSolid = 1 << 4; + + const unsigned kDictBitStart = 5; + const unsigned kNumDictBits = 3; + const unsigned kDictMask = (1 << kNumDictBits) - 1; + const unsigned kDictDirectoryValue = 0x7; + + const unsigned kSize64Bits = 1 << 8; + const unsigned kUnicodeName = 1 << 9; + const unsigned kSalt = 1 << 10; + const unsigned kOldVersion = 1 << 11; + const unsigned kExtTime = 1 << 12; + // const unsigned kExtFlags = 1 << 13; + // const unsigned kSkipIfUnknown = 1 << 14; + + const unsigned kLongBlock = 1 << 15; + + /* + struct CBlock + { + // UInt16 HeadCRC; + // Byte Type; + // UInt16 Flags; + // UInt16 HeadSize; + UInt32 PackSize; + UInt32 UnPackSize; + Byte HostOS; + UInt32 FileCRC; + UInt32 Time; + Byte UnPackVersion; + Byte Method; + UInt16 NameSize; + UInt32 Attributes; + }; + */ + + /* + struct CBlock32 + { + UInt16 HeadCRC; + Byte Type; + UInt16 Flags; + UInt16 HeadSize; + UInt32 PackSize; + UInt32 UnPackSize; + Byte HostOS; + UInt32 FileCRC; + UInt32 Time; + Byte UnPackVersion; + Byte Method; + UInt16 NameSize; + UInt32 Attributes; + UInt16 GetRealCRC(const void *aName, UInt32 aNameSize, + bool anExtraDataDefined = false, Byte *anExtraData = 0) const; + }; + struct CBlock64 + { + UInt16 HeadCRC; + Byte Type; + UInt16 Flags; + UInt16 HeadSize; + UInt32 PackSizeLow; + UInt32 UnPackSizeLow; + Byte HostOS; + UInt32 FileCRC; + UInt32 Time; + Byte UnPackVersion; + Byte Method; + UInt16 NameSize; + UInt32 Attributes; + UInt32 PackSizeHigh; + UInt32 UnPackSizeHigh; + UInt16 GetRealCRC(const void *aName, UInt32 aNameSize) const; + }; + */ + + const unsigned kLabelFileAttribute = 0x08; + const unsigned kWinFileDirectoryAttributeMask = 0x10; + + enum CHostOS + { + kHostMSDOS = 0, + kHostOS2 = 1, + kHostWin32 = 2, + kHostUnix = 3, + kHostMacOS = 4, + kHostBeOS = 5 + }; +} + +namespace NBlock +{ + const UInt16 kLongBlock = 1 << 15; + struct CBlock + { + UInt16 CRC; + Byte Type; + UInt16 Flags; + UInt16 HeadSize; + // UInt32 DataSize; + }; +} + +/* +struct CSubBlock +{ + UInt16 HeadCRC; + Byte HeadType; + UInt16 Flags; + UInt16 HeadSize; + UInt32 DataSize; + UInt16 SubType; + Byte Level; // Reserved : Must be 0 +}; + +struct CCommentBlock +{ + UInt16 HeadCRC; + Byte HeadType; + UInt16 Flags; + UInt16 HeadSize; + UInt16 UnpSize; + Byte UnpVer; + Byte Method; + UInt16 CommCRC; +}; + + +struct CProtectHeader +{ + UInt16 HeadCRC; + Byte HeadType; + UInt16 Flags; + UInt16 HeadSize; + UInt32 DataSize; + Byte Version; + UInt16 RecSectors; + UInt32 TotalBlocks; + Byte Mark[8]; +}; +*/ + +}}} + +#endif diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h index d302815e2..e1028ba4d 100644 --- a/CPP/7zip/Archive/Rar/RarItem.h +++ b/CPP/7zip/Archive/Rar/RarItem.h @@ -1,97 +1,97 @@ -// RarItem.h - -#ifndef ZIP7_INC_ARCHIVE_RAR_ITEM_H -#define ZIP7_INC_ARCHIVE_RAR_ITEM_H - -#include "../../../Common/StringConvert.h" - -#include "RarHeader.h" - -namespace NArchive { -namespace NRar { - -struct CRarTime -{ - UInt32 DosTime; - Byte LowSecond; - Byte SubTime[3]; -}; - -struct CItem -{ - UInt64 Size; - UInt64 PackSize; - - CRarTime CTime; - CRarTime ATime; - CRarTime MTime; - - UInt32 FileCRC; - UInt32 Attrib; - - UInt16 Flags; - Byte HostOS; - Byte UnPackVersion; - Byte Method; - - bool CTimeDefined; - bool ATimeDefined; - - AString Name; - UString UnicodeName; - - Byte Salt[8]; - - bool Is_Size_Defined() const { return Size != (UInt64)(Int64)-1; } - - bool IsEncrypted() const { return (Flags & NHeader::NFile::kEncrypted) != 0; } - bool IsSolid() const { return (Flags & NHeader::NFile::kSolid) != 0; } - bool IsCommented() const { return (Flags & NHeader::NFile::kComment) != 0; } - bool IsSplitBefore() const { return (Flags & NHeader::NFile::kSplitBefore) != 0; } - bool IsSplitAfter() const { return (Flags & NHeader::NFile::kSplitAfter) != 0; } - bool HasSalt() const { return (Flags & NHeader::NFile::kSalt) != 0; } - bool HasExtTime() const { return (Flags & NHeader::NFile::kExtTime) != 0; } - bool HasUnicodeName()const { return (Flags & NHeader::NFile::kUnicodeName) != 0; } - bool IsOldVersion() const { return (Flags & NHeader::NFile::kOldVersion) != 0; } - - UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; } - bool IsDir() const; - bool IgnoreItem() const; - UInt32 GetWinAttrib() const; - - UInt64 Position; - unsigned MainPartSize; - UInt16 CommentSize; - UInt16 AlignSize; - - // int BaseFileIndex; - // bool IsAltStream; - - UString GetName() const - { - if (( /* IsAltStream || */ HasUnicodeName()) && !UnicodeName.IsEmpty()) - return UnicodeName; - return MultiByteToUnicodeString(Name, CP_OEMCP); - } - - void Clear() - { - CTimeDefined = false; - ATimeDefined = false; - Name.Empty(); - UnicodeName.Empty(); - // IsAltStream = false; - // BaseFileIndex = -1; - } - - CItem() { Clear(); } - - UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; } - // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; } - UInt64 GetCommentPosition() const { return Position + MainPartSize; } - UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; } -}; - -}} - -#endif +// RarItem.h + +#ifndef ZIP7_INC_ARCHIVE_RAR_ITEM_H +#define ZIP7_INC_ARCHIVE_RAR_ITEM_H + +#include "../../../Common/StringConvert.h" + +#include "RarHeader.h" + +namespace NArchive { +namespace NRar { + +struct CRarTime +{ + UInt32 DosTime; + Byte LowSecond; + Byte SubTime[3]; +}; + +struct CItem +{ + UInt64 Size; + UInt64 PackSize; + + CRarTime CTime; + CRarTime ATime; + CRarTime MTime; + + UInt32 FileCRC; + UInt32 Attrib; + + UInt16 Flags; + Byte HostOS; + Byte UnPackVersion; + Byte Method; + + bool CTimeDefined; + bool ATimeDefined; + + AString Name; + UString UnicodeName; + + Byte Salt[8]; + + bool Is_Size_Defined() const { return Size != (UInt64)(Int64)-1; } + + bool IsEncrypted() const { return (Flags & NHeader::NFile::kEncrypted) != 0; } + bool IsSolid() const { return (Flags & NHeader::NFile::kSolid) != 0; } + bool IsCommented() const { return (Flags & NHeader::NFile::kComment) != 0; } + bool IsSplitBefore() const { return (Flags & NHeader::NFile::kSplitBefore) != 0; } + bool IsSplitAfter() const { return (Flags & NHeader::NFile::kSplitAfter) != 0; } + bool HasSalt() const { return (Flags & NHeader::NFile::kSalt) != 0; } + bool HasExtTime() const { return (Flags & NHeader::NFile::kExtTime) != 0; } + bool HasUnicodeName()const { return (Flags & NHeader::NFile::kUnicodeName) != 0; } + bool IsOldVersion() const { return (Flags & NHeader::NFile::kOldVersion) != 0; } + + UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; } + bool IsDir() const; + bool IgnoreItem() const; + UInt32 GetWinAttrib() const; + + UInt64 Position; + unsigned MainPartSize; + UInt16 CommentSize; + UInt16 AlignSize; + + // int BaseFileIndex; + // bool IsAltStream; + + UString GetName() const + { + if (( /* IsAltStream || */ HasUnicodeName()) && !UnicodeName.IsEmpty()) + return UnicodeName; + return MultiByteToUnicodeString(Name, CP_OEMCP); + } + + void Clear() + { + CTimeDefined = false; + ATimeDefined = false; + Name.Empty(); + UnicodeName.Empty(); + // IsAltStream = false; + // BaseFileIndex = -1; + } + + CItem() { Clear(); } + + UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; } + // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; } + UInt64 GetCommentPosition() const { return Position + MainPartSize; } + UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h index a352d4fbf..9ee8e86c3 100644 --- a/CPP/7zip/Archive/Rar/RarVol.h +++ b/CPP/7zip/Archive/Rar/RarVol.h @@ -1,136 +1,136 @@ -// RarVol.h - -#ifndef ZIP7_INC_ARCHIVE_RAR_VOL_H -#define ZIP7_INC_ARCHIVE_RAR_VOL_H - -#include "../../../Common/StringConvert.h" - -#include "RarHeader.h" - -namespace NArchive { -namespace NRar { - -inline bool IsDigit(wchar_t c) -{ - return c >= L'0' && c <= L'9'; -} - -class CVolumeName -{ - bool _needChangeForNext; - UString _before; - UString _changed; - UString _after; -public: - CVolumeName(): _needChangeForNext(true) {} - - bool InitName(const UString &name, bool newStyle = true) - { - _needChangeForNext = true; - _after.Empty(); - UString base (name); - const int dotPos = name.ReverseFind_Dot(); - - if (dotPos >= 0) - { - const UString ext (name.Ptr(dotPos + 1)); - if (ext.IsEqualTo_Ascii_NoCase("rar")) - { - _after = name.Ptr(dotPos); - base.DeleteFrom(dotPos); - } - else if (ext.IsEqualTo_Ascii_NoCase("exe")) - { - _after = ".rar"; - base.DeleteFrom(dotPos); - } - else if (!newStyle) - { - if (ext.IsEqualTo_Ascii_NoCase("000") || - ext.IsEqualTo_Ascii_NoCase("001") || - ext.IsEqualTo_Ascii_NoCase("r00") || - ext.IsEqualTo_Ascii_NoCase("r01")) - { - _changed = ext; - _before.SetFrom(name.Ptr(), (unsigned)dotPos + 1); - return true; - } - } - } - - if (newStyle) - { - unsigned k = base.Len(); - - for (; k != 0; k--) - if (IsDigit(base[k - 1])) - break; - - unsigned i = k; - - for (; i != 0; i--) - if (!IsDigit(base[i - 1])) - break; - - if (i != k) - { - _before.SetFrom(base.Ptr(), i); - _changed.SetFrom(base.Ptr(i), k - i); - _after.Insert(0, base.Ptr(k)); - return true; - } - } - - _after.Empty(); - _before = base; - _before.Add_Dot(); - _changed = "r00"; - _needChangeForNext = false; - return true; - } - - /* - void MakeBeforeFirstName() - { - unsigned len = _changed.Len(); - _changed.Empty(); - for (unsigned i = 0; i < len; i++) - _changed += L'0'; - } - */ - - UString GetNextName() - { - if (_needChangeForNext) - { - unsigned i = _changed.Len(); - if (i == 0) - return UString(); - for (;;) - { - wchar_t c = _changed[--i]; - if (c == L'9') - { - c = L'0'; - _changed.ReplaceOneCharAtPos(i, c); - if (i == 0) - { - _changed.InsertAtFront(L'1'); - break; - } - continue; - } - c++; - _changed.ReplaceOneCharAtPos(i, c); - break; - } - } - - _needChangeForNext = true; - return _before + _changed + _after; - } -}; - -}} - -#endif +// RarVol.h + +#ifndef ZIP7_INC_ARCHIVE_RAR_VOL_H +#define ZIP7_INC_ARCHIVE_RAR_VOL_H + +#include "../../../Common/StringConvert.h" + +#include "RarHeader.h" + +namespace NArchive { +namespace NRar { + +inline bool IsDigit(wchar_t c) +{ + return c >= L'0' && c <= L'9'; +} + +class CVolumeName +{ + bool _needChangeForNext; + UString _before; + UString _changed; + UString _after; +public: + CVolumeName(): _needChangeForNext(true) {} + + bool InitName(const UString &name, bool newStyle = true) + { + _needChangeForNext = true; + _after.Empty(); + UString base (name); + const int dotPos = name.ReverseFind_Dot(); + + if (dotPos >= 0) + { + const UString ext (name.Ptr(dotPos + 1)); + if (ext.IsEqualTo_Ascii_NoCase("rar")) + { + _after = name.Ptr(dotPos); + base.DeleteFrom(dotPos); + } + else if (ext.IsEqualTo_Ascii_NoCase("exe")) + { + _after = ".rar"; + base.DeleteFrom(dotPos); + } + else if (!newStyle) + { + if (ext.IsEqualTo_Ascii_NoCase("000") || + ext.IsEqualTo_Ascii_NoCase("001") || + ext.IsEqualTo_Ascii_NoCase("r00") || + ext.IsEqualTo_Ascii_NoCase("r01")) + { + _changed = ext; + _before.SetFrom(name.Ptr(), (unsigned)dotPos + 1); + return true; + } + } + } + + if (newStyle) + { + unsigned k = base.Len(); + + for (; k != 0; k--) + if (IsDigit(base[k - 1])) + break; + + unsigned i = k; + + for (; i != 0; i--) + if (!IsDigit(base[i - 1])) + break; + + if (i != k) + { + _before.SetFrom(base.Ptr(), i); + _changed.SetFrom(base.Ptr(i), k - i); + _after.Insert(0, base.Ptr(k)); + return true; + } + } + + _after.Empty(); + _before = base; + _before.Add_Dot(); + _changed = "r00"; + _needChangeForNext = false; + return true; + } + + /* + void MakeBeforeFirstName() + { + unsigned len = _changed.Len(); + _changed.Empty(); + for (unsigned i = 0; i < len; i++) + _changed += L'0'; + } + */ + + UString GetNextName() + { + if (_needChangeForNext) + { + unsigned i = _changed.Len(); + if (i == 0) + return UString(); + for (;;) + { + wchar_t c = _changed[--i]; + if (c == L'9') + { + c = L'0'; + _changed.ReplaceOneCharAtPos(i, c); + if (i == 0) + { + _changed.InsertAtFront(L'1'); + break; + } + continue; + } + c++; + _changed.ReplaceOneCharAtPos(i, c); + break; + } + } + + _needChangeForNext = true; + return _before + _changed + _after; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Archive/Rar/StdAfx.cpp +++ b/CPP/7zip/Archive/Rar/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Rar/StdAfx.h +++ b/CPP/7zip/Archive/Rar/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp index 3b48723a0..da2b6ee65 100644 --- a/CPP/7zip/Archive/RpmHandler.cpp +++ b/CPP/7zip/Archive/RpmHandler.cpp @@ -1,775 +1,775 @@ -// RpmHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/MyBuffer.h" -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringConvert.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -// #define Z7_RPM_SHOW_METADATA - -using namespace NWindows; - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) - -namespace NArchive { -namespace NRpm { - -static const unsigned kNameSize = 66; -static const unsigned kLeadSize = kNameSize + 30; -static const unsigned k_HeaderSig_Size = 16; -static const unsigned k_Entry_Size = 16; - -#define RPMSIG_NONE 0 // Old signature -#define RPMSIG_PGP262_1024 1 // Old signature -#define RPMSIG_HEADERSIG 5 // New signature - -enum -{ - kRpmType_Bin = 0, - kRpmType_Src = 1 -}; - -// There are two sets of TAGs: signature tags and header tags - -// ----- Signature TAGs ----- - -#define RPMSIGTAG_SIZE 1000 // Header + Payload size (32bit) - -// ----- Header TAGs ----- - -#define RPMTAG_NAME 1000 -#define RPMTAG_VERSION 1001 -#define RPMTAG_RELEASE 1002 -#define RPMTAG_BUILDTIME 1006 -#define RPMTAG_OS 1021 // string (old version used int?) -#define RPMTAG_ARCH 1022 // string (old version used int?) -#define RPMTAG_PAYLOADFORMAT 1124 -#define RPMTAG_PAYLOADCOMPRESSOR 1125 -// #define RPMTAG_PAYLOADFLAGS 1126 - -enum -{ - k_EntryType_NULL, - k_EntryType_CHAR, - k_EntryType_INT8, - k_EntryType_INT16, - k_EntryType_INT32, - k_EntryType_INT64, - k_EntryType_STRING, - k_EntryType_BIN, - k_EntryType_STRING_ARRAY, - k_EntryType_I18NSTRING -}; - -static const char * const k_CPUs[] = -{ - "noarch" - , "i386" - , "alpha" - , "sparc" - , "mips" - , "ppc" - , "m68k" - , "sgi" - , "rs6000" - , "ia64" - , "sparc64" // 10 ??? - , "mipsel" - , "arm" - , "m68kmint" - , "s390" - , "s390x" - , "ppc64" - , "sh" - , "xtensa" - , "aarch64" // 19 - , "mipsr6" // 20 - , "mips64r6" // 21 - , "riscv64" // 22 - , "loongarch64" // 23 - // , "24" - // , "25" - // , "loongarch64" // 26 : why 23 and 26 for loongarch64? - // 255 for some non specified arch -}; - -static const char * const k_OS[] = -{ - "0" - , "Linux" - , "Irix" - , "solaris" - , "SunOS" - , "AmigaOS" // AIX - , "HP-UX" - , "osf" - , "FreeBSD" - , "SCO_SV" - , "Irix64" - , "NextStep" - , "bsdi" - , "machten" - , "cygwin32-NT" - , "cygwin32-95" - , "MP_RAS" - , "MiNT" - , "OS/390" - , "VM/ESA" - , "Linux/390" // "Linux/ESA" - , "Darwin" // "MacOSX" 21 -}; - -struct CLead -{ - Byte Major; - // Byte Minor; - UInt16 Type; - UInt16 Cpu; - UInt16 Os; - UInt16 SignatureType; - char Name[kNameSize]; - // char Reserved[16]; - - void Parse(const Byte *p) - { - Major = p[4]; - // Minor = p[5]; - Type = Get16(p + 6); - Cpu= Get16(p + 8); - memcpy(Name, p + 10, kNameSize); - p += 10 + kNameSize; - Os = Get16(p); - SignatureType = Get16(p + 2); - } - - bool IsSupported() const { return Major >= 3 && Type <= 1; } -}; - -struct CEntry -{ - UInt32 Tag; - UInt32 Type; - UInt32 Offset; - UInt32 Count; - - void Parse(const Byte *p) - { - Tag = Get32(p + 0); - Type = Get32(p + 4); - Offset = Get32(p + 8); - Count = Get32(p + 12); - } -}; - - -#ifdef Z7_RPM_SHOW_METADATA -struct CMetaFile -{ - UInt32 Tag; - UInt32 Offset; - UInt32 Size; -}; -#endif - -Z7_class_CHandler_final: public CHandlerCont -{ - Z7_IFACE_COM7_IMP(IInArchive_Cont) - - UInt64 _headersSize; // is equal to start offset of payload data - UInt64 _payloadSize; - UInt64 _size; - // _size = _payloadSize, if (_payloadSize_Defined) - // _size = (fileSize - _headersSize), if (!_payloadSize_Defined) - UInt64 _phySize; // _headersSize + _payloadSize, if (_phySize_Defined) - UInt32 _headerPlusPayload_Size; - UInt32 _buildTime; - - bool _payloadSize_Defined; - bool _phySize_Defined; - bool _headerPlusPayload_Size_Defined; - bool _time_Defined; - - Byte _payloadSig[6]; // start data of payload - - AString _name; // p7zip - AString _version; // 9.20.1 - AString _release; // 8.1.1 - AString _arch; // x86_64 - AString _os; // linux - - AString _format; // cpio - AString _compressor; // xz, gzip, bzip2, lzma, zstd - - CLead _lead; - - #ifdef Z7_RPM_SHOW_METADATA - AString _metadata; - CRecordVector _metaFiles; - #endif - - void SetTime(NCOM::CPropVariant &prop) const - { - if (_time_Defined && _buildTime != 0) - PropVariant_SetFrom_UnixTime(prop, _buildTime); - } - - void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const - { - UString us; - if (!ConvertUTF8ToUnicode(s, us)) - us = GetUnicodeString(s); - if (!us.IsEmpty()) - prop = us; - } - - void AddCPU(AString &s) const; - AString GetBaseName() const; - void AddSubFileExtension(AString &res) const; - - HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader); - HRESULT Open2(ISequentialInStream *stream); - - virtual int GetItem_ExtractInfo(UInt32 /* index */, UInt64 &pos, UInt64 &size) const Z7_override - { - pos = _headersSize; - size = _size; - return NExtract::NOperationResult::kOK; - } -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidCpu, - kpidHostOS, - kpidCTime - #ifdef Z7_RPM_SHOW_METADATA - , kpidComment - #endif -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidCTime -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -void CHandler::AddCPU(AString &s) const -{ - if (!_arch.IsEmpty()) - s += _arch; - else - { - if (_lead.Type == kRpmType_Bin) - { - if (_lead.Cpu < Z7_ARRAY_SIZE(k_CPUs)) - s += k_CPUs[_lead.Cpu]; - else - s.Add_UInt32(_lead.Cpu); - } - } -} - -AString CHandler::GetBaseName() const -{ - AString s; - if (!_name.IsEmpty()) - { - s = _name; - if (!_version.IsEmpty()) - { - s.Add_Minus(); - s += _version; - } - if (!_release.IsEmpty()) - { - s.Add_Minus(); - s += _release; - } - } - else - s.SetFrom_CalcLen(_lead.Name, kNameSize); - - s.Add_Dot(); - if (_lead.Type == kRpmType_Src) - s += "src"; - else - AddCPU(s); - return s; -} - -void CHandler::AddSubFileExtension(AString &res) const -{ - if (!_format.IsEmpty()) - res += _format; - else - res += "cpio"; - res.Add_Dot(); - - const char *s; - - if (!_compressor.IsEmpty()) - { - s = _compressor; - if (_compressor == "bzip2") - s = "bz2"; - else if (_compressor == "gzip") - s = "gz"; - else if (_compressor == "zstd") - s = "zst"; - } - else - { - const Byte *p = _payloadSig; - if (p[0] == 0x1F && p[1] == 0x8B && p[2] == 8) - s = "gz"; - else if (p[0] == 0xFD && p[1] == '7' && p[2] == 'z' && p[3] == 'X' && p[4] == 'Z' && p[5] == 0) - s = "xz"; - else if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h' && p[3] >= '1' && p[3] <= '9') - s = "bz2"; - else if (p[0] == 0x28 && p[1] == 0xb5 && p[2] == 0x2f && p[3] == 0xfd) - s = "zst"; - else - s = "lzma"; - } - - res += s; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - - case kpidHeadersSize: prop = _headersSize; break; - case kpidPhySize: if (_phySize_Defined) prop = _phySize; break; - - case kpidMTime: - case kpidCTime: - SetTime(prop); - break; - - case kpidCpu: - { - AString s; - AddCPU(s); - /* - if (_lead.Type == kRpmType_Src) - s = "src"; - */ - SetStringProp(s, prop); - break; - } - - case kpidHostOS: - { - if (!_os.IsEmpty()) - SetStringProp(_os, prop); - else - { - TYPE_TO_PROP(k_OS, _lead.Os, prop); - } - break; - } - - #ifdef Z7_RPM_SHOW_METADATA - // case kpidComment: SetStringProp(_metadata, prop); break; - #endif - - case kpidName: - { - SetStringProp(GetBaseName() + ".rpm", prop); - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - if (index == 0) - switch (propID) - { - case kpidSize: - case kpidPackSize: - prop = _size; - break; - - case kpidMTime: - case kpidCTime: - SetTime(prop); - break; - - case kpidPath: - { - AString s (GetBaseName()); - s.Add_Dot(); - AddSubFileExtension(s); - SetStringProp(s, prop); - break; - } - - /* - case kpidExtension: - { - prop = GetSubFileExtension(); - break; - } - */ - } - #ifdef Z7_RPM_SHOW_METADATA - else - { - index--; - if (index > _metaFiles.Size()) - return E_INVALIDARG; - const CMetaFile &meta = _metaFiles[index]; - switch (propID) - { - case kpidSize: - case kpidPackSize: - prop = meta.Size; - break; - - case kpidMTime: - case kpidCTime: - SetTime(prop); - break; - - case kpidPath: - { - AString s ("[META]"); - s.Add_PathSepar(); - s.Add_UInt32(meta.Tag); - prop = s; - break; - } - } - } - #endif - - prop.Detach(value); - return S_OK; -} - - -HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) -{ - UInt32 numEntries; - UInt32 dataLen; - { - char buf[k_HeaderSig_Size]; - RINOK(ReadStream_FALSE(stream, buf, k_HeaderSig_Size)) - if (Get32(buf) != 0x8EADE801) // buf[3] = 0x01 - is version - return S_FALSE; - // reserved = Get32(buf + 4); - numEntries = Get32(buf + 8); - dataLen = Get32(buf + 12); - if (numEntries >= 1 << 24) - return S_FALSE; - } - size_t indexSize = (size_t)numEntries * k_Entry_Size; - size_t headerSize = indexSize + dataLen; - if (headerSize < dataLen) - return S_FALSE; - CByteBuffer buffer(headerSize); - RINOK(ReadStream_FALSE(stream, buffer, headerSize)) - - for (UInt32 i = 0; i < numEntries; i++) - { - CEntry entry; - - entry.Parse(buffer + (size_t)i * k_Entry_Size); - if (entry.Offset > dataLen) - return S_FALSE; - - const Byte *p = buffer + indexSize + entry.Offset; - size_t rem = dataLen - entry.Offset; - - if (!isMainHeader) - { - if (entry.Tag == RPMSIGTAG_SIZE && - entry.Type == k_EntryType_INT32) - { - if (rem < 4 || entry.Count != 1) - return S_FALSE; - _headerPlusPayload_Size = Get32(p); - _headerPlusPayload_Size_Defined = true; - } - } - else - { - #ifdef Z7_RPM_SHOW_METADATA - { - _metadata.Add_UInt32(entry.Tag); - _metadata += ": "; - } - #endif - - if (entry.Type == k_EntryType_STRING) - { - if (entry.Count != 1) - return S_FALSE; - size_t j; - for (j = 0; j < rem && p[j] != 0; j++); - if (j == rem) - return S_FALSE; - AString s((const char *)p); - switch (entry.Tag) - { - case RPMTAG_NAME: _name = s; break; - case RPMTAG_VERSION: _version = s; break; - case RPMTAG_RELEASE: _release = s; break; - case RPMTAG_ARCH: _arch = s; break; - case RPMTAG_OS: _os = s; break; - case RPMTAG_PAYLOADFORMAT: _format = s; break; - case RPMTAG_PAYLOADCOMPRESSOR: _compressor = s; break; - } - - #ifdef Z7_RPM_SHOW_METADATA - _metadata += s; - #endif - } - else if (entry.Type == k_EntryType_INT32) - { - if (rem / 4 < entry.Count) - return S_FALSE; - if (entry.Tag == RPMTAG_BUILDTIME) - { - if (entry.Count != 1) - return S_FALSE; - _buildTime = Get32(p); - _time_Defined = true; - } - - #ifdef Z7_RPM_SHOW_METADATA - for (UInt32 t = 0; t < entry.Count; t++) - { - if (t != 0) - _metadata.Add_Space(); - _metadata.Add_UInt32(Get32(p + t * 4)); - } - #endif - } - - #ifdef Z7_RPM_SHOW_METADATA - - else if ( - entry.Type == k_EntryType_STRING_ARRAY || - entry.Type == k_EntryType_I18NSTRING) - { - const Byte *p2 = p; - size_t rem2 = rem; - for (UInt32 t = 0; t < entry.Count; t++) - { - if (rem2 == 0) - return S_FALSE; - if (t != 0) - _metadata.Add_LF(); - size_t j; - for (j = 0; j < rem2 && p2[j] != 0; j++); - if (j == rem2) - return S_FALSE; - _metadata += (const char *)p2; - j++; - p2 += j; - rem2 -= j; - } - } - else if (entry.Type == k_EntryType_INT16) - { - if (rem / 2 < entry.Count) - return S_FALSE; - for (UInt32 t = 0; t < entry.Count; t++) - { - if (t != 0) - _metadata.Add_Space(); - _metadata.Add_UInt32(Get16(p + t * 2)); - } - } - else if (entry.Type == k_EntryType_BIN) - { - if (rem < entry.Count) - return S_FALSE; - for (UInt32 t = 0; t < entry.Count; t++) - { - const unsigned b = p[t]; - _metadata += GET_HEX_CHAR_UPPER(b >> 4); - _metadata += GET_HEX_CHAR_UPPER(b & 0xF); - } - } - else - { - // p = p; - } - - _metadata.Add_LF(); - #endif - } - - #ifdef Z7_RPM_SHOW_METADATA - CMetaFile meta; - meta.Offset = entry.Offset; - meta.Tag = entry.Tag; - meta.Size = entry.Count; - _metaFiles.Add(meta); - #endif - } - - headerSize += k_HeaderSig_Size; - _headersSize += headerSize; - if (isMainHeader && _headerPlusPayload_Size_Defined) - { - if (_headerPlusPayload_Size < headerSize) - return S_FALSE; - _payloadSize = _headerPlusPayload_Size - headerSize; - _size = _payloadSize; - _phySize = _headersSize + _payloadSize; - _payloadSize_Defined = true; - _phySize_Defined = true; - } - return S_OK; -} - -HRESULT CHandler::Open2(ISequentialInStream *stream) -{ - { - Byte buf[kLeadSize]; - RINOK(ReadStream_FALSE(stream, buf, kLeadSize)) - if (Get32(buf) != 0xEDABEEDB) - return S_FALSE; - _lead.Parse(buf); - if (!_lead.IsSupported()) - return S_FALSE; - } - - _headersSize = kLeadSize; - - if (_lead.SignatureType == RPMSIG_NONE) - { - - } - else if (_lead.SignatureType == RPMSIG_PGP262_1024) - { - Byte temp[256]; - RINOK(ReadStream_FALSE(stream, temp, sizeof(temp))) - } - else if (_lead.SignatureType == RPMSIG_HEADERSIG) - { - RINOK(ReadHeader(stream, false)) - unsigned pos = (unsigned)_headersSize & 7; - if (pos != 0) - { - Byte temp[8]; - unsigned num = 8 - pos; - RINOK(ReadStream_FALSE(stream, temp, num)) - _headersSize += num; - } - } - else - return S_FALSE; - - return ReadHeader(stream, true); -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)) -{ - COM_TRY_BEGIN - { - Close(); - RINOK(Open2(inStream)) - - // start of payload is allowed to be unaligned - RINOK(ReadStream_FALSE(inStream, _payloadSig, sizeof(_payloadSig))) - - if (!_payloadSize_Defined) - { - UInt64 endPos; - RINOK(InStream_GetSize_SeekToEnd(inStream, endPos)) - _size = endPos - _headersSize; - } - _stream = inStream; - return S_OK; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _headersSize = 0; - _payloadSize = 0; - _size = 0; - _phySize = 0; - _headerPlusPayload_Size = 0; - - _payloadSize_Defined = false; - _phySize_Defined = false; - _headerPlusPayload_Size_Defined = false; - _time_Defined = false; - - _name.Empty(); - _version.Empty(); - _release.Empty(); - _arch.Empty(); - _os.Empty(); - - _format.Empty(); - _compressor.Empty(); - - #ifdef Z7_RPM_SHOW_METADATA - _metadata.Empty(); - _metaFiles.Size(); - #endif - - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1 - #ifdef Z7_RPM_SHOW_METADATA - + _metaFiles.Size() - #endif - ; - - return S_OK; -} - -static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB}; - -REGISTER_ARC_I( - "Rpm", "rpm", NULL, 0xEB, - k_Signature, - 0, - 0, - NULL) - -}} +// RpmHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/MyBuffer.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +// #define Z7_RPM_SHOW_METADATA + +using namespace NWindows; + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) + +namespace NArchive { +namespace NRpm { + +static const unsigned kNameSize = 66; +static const unsigned kLeadSize = kNameSize + 30; +static const unsigned k_HeaderSig_Size = 16; +static const unsigned k_Entry_Size = 16; + +#define RPMSIG_NONE 0 // Old signature +#define RPMSIG_PGP262_1024 1 // Old signature +#define RPMSIG_HEADERSIG 5 // New signature + +enum +{ + kRpmType_Bin = 0, + kRpmType_Src = 1 +}; + +// There are two sets of TAGs: signature tags and header tags + +// ----- Signature TAGs ----- + +#define RPMSIGTAG_SIZE 1000 // Header + Payload size (32bit) + +// ----- Header TAGs ----- + +#define RPMTAG_NAME 1000 +#define RPMTAG_VERSION 1001 +#define RPMTAG_RELEASE 1002 +#define RPMTAG_BUILDTIME 1006 +#define RPMTAG_OS 1021 // string (old version used int?) +#define RPMTAG_ARCH 1022 // string (old version used int?) +#define RPMTAG_PAYLOADFORMAT 1124 +#define RPMTAG_PAYLOADCOMPRESSOR 1125 +// #define RPMTAG_PAYLOADFLAGS 1126 + +enum +{ + k_EntryType_NULL, + k_EntryType_CHAR, + k_EntryType_INT8, + k_EntryType_INT16, + k_EntryType_INT32, + k_EntryType_INT64, + k_EntryType_STRING, + k_EntryType_BIN, + k_EntryType_STRING_ARRAY, + k_EntryType_I18NSTRING +}; + +static const char * const k_CPUs[] = +{ + "noarch" + , "i386" + , "alpha" + , "sparc" + , "mips" + , "ppc" + , "m68k" + , "sgi" + , "rs6000" + , "ia64" + , "sparc64" // 10 ??? + , "mipsel" + , "arm" + , "m68kmint" + , "s390" + , "s390x" + , "ppc64" + , "sh" + , "xtensa" + , "aarch64" // 19 + , "mipsr6" // 20 + , "mips64r6" // 21 + , "riscv64" // 22 + , "loongarch64" // 23 + // , "24" + // , "25" + // , "loongarch64" // 26 : why 23 and 26 for loongarch64? + // 255 for some non specified arch +}; + +static const char * const k_OS[] = +{ + "0" + , "Linux" + , "Irix" + , "solaris" + , "SunOS" + , "AmigaOS" // AIX + , "HP-UX" + , "osf" + , "FreeBSD" + , "SCO_SV" + , "Irix64" + , "NextStep" + , "bsdi" + , "machten" + , "cygwin32-NT" + , "cygwin32-95" + , "MP_RAS" + , "MiNT" + , "OS/390" + , "VM/ESA" + , "Linux/390" // "Linux/ESA" + , "Darwin" // "MacOSX" 21 +}; + +struct CLead +{ + Byte Major; + // Byte Minor; + UInt16 Type; + UInt16 Cpu; + UInt16 Os; + UInt16 SignatureType; + char Name[kNameSize]; + // char Reserved[16]; + + void Parse(const Byte *p) + { + Major = p[4]; + // Minor = p[5]; + Type = Get16(p + 6); + Cpu= Get16(p + 8); + memcpy(Name, p + 10, kNameSize); + p += 10 + kNameSize; + Os = Get16(p); + SignatureType = Get16(p + 2); + } + + bool IsSupported() const { return Major >= 3 && Type <= 1; } +}; + +struct CEntry +{ + UInt32 Tag; + UInt32 Type; + UInt32 Offset; + UInt32 Count; + + void Parse(const Byte *p) + { + Tag = Get32(p + 0); + Type = Get32(p + 4); + Offset = Get32(p + 8); + Count = Get32(p + 12); + } +}; + + +#ifdef Z7_RPM_SHOW_METADATA +struct CMetaFile +{ + UInt32 Tag; + UInt32 Offset; + UInt32 Size; +}; +#endif + +Z7_class_CHandler_final: public CHandlerCont +{ + Z7_IFACE_COM7_IMP(IInArchive_Cont) + + UInt64 _headersSize; // is equal to start offset of payload data + UInt64 _payloadSize; + UInt64 _size; + // _size = _payloadSize, if (_payloadSize_Defined) + // _size = (fileSize - _headersSize), if (!_payloadSize_Defined) + UInt64 _phySize; // _headersSize + _payloadSize, if (_phySize_Defined) + UInt32 _headerPlusPayload_Size; + UInt32 _buildTime; + + bool _payloadSize_Defined; + bool _phySize_Defined; + bool _headerPlusPayload_Size_Defined; + bool _time_Defined; + + Byte _payloadSig[6]; // start data of payload + + AString _name; // p7zip + AString _version; // 9.20.1 + AString _release; // 8.1.1 + AString _arch; // x86_64 + AString _os; // linux + + AString _format; // cpio + AString _compressor; // xz, gzip, bzip2, lzma, zstd + + CLead _lead; + + #ifdef Z7_RPM_SHOW_METADATA + AString _metadata; + CRecordVector _metaFiles; + #endif + + void SetTime(NCOM::CPropVariant &prop) const + { + if (_time_Defined && _buildTime != 0) + PropVariant_SetFrom_UnixTime(prop, _buildTime); + } + + void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const + { + UString us; + if (!ConvertUTF8ToUnicode(s, us)) + us = GetUnicodeString(s); + if (!us.IsEmpty()) + prop = us; + } + + void AddCPU(AString &s) const; + AString GetBaseName() const; + void AddSubFileExtension(AString &res) const; + + HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader); + HRESULT Open2(ISequentialInStream *stream); + + virtual int GetItem_ExtractInfo(UInt32 /* index */, UInt64 &pos, UInt64 &size) const Z7_override + { + pos = _headersSize; + size = _size; + return NExtract::NOperationResult::kOK; + } +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidCpu, + kpidHostOS, + kpidCTime + #ifdef Z7_RPM_SHOW_METADATA + , kpidComment + #endif +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidCTime +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +void CHandler::AddCPU(AString &s) const +{ + if (!_arch.IsEmpty()) + s += _arch; + else + { + if (_lead.Type == kRpmType_Bin) + { + if (_lead.Cpu < Z7_ARRAY_SIZE(k_CPUs)) + s += k_CPUs[_lead.Cpu]; + else + s.Add_UInt32(_lead.Cpu); + } + } +} + +AString CHandler::GetBaseName() const +{ + AString s; + if (!_name.IsEmpty()) + { + s = _name; + if (!_version.IsEmpty()) + { + s.Add_Minus(); + s += _version; + } + if (!_release.IsEmpty()) + { + s.Add_Minus(); + s += _release; + } + } + else + s.SetFrom_CalcLen(_lead.Name, kNameSize); + + s.Add_Dot(); + if (_lead.Type == kRpmType_Src) + s += "src"; + else + AddCPU(s); + return s; +} + +void CHandler::AddSubFileExtension(AString &res) const +{ + if (!_format.IsEmpty()) + res += _format; + else + res += "cpio"; + res.Add_Dot(); + + const char *s; + + if (!_compressor.IsEmpty()) + { + s = _compressor; + if (_compressor == "bzip2") + s = "bz2"; + else if (_compressor == "gzip") + s = "gz"; + else if (_compressor == "zstd") + s = "zst"; + } + else + { + const Byte *p = _payloadSig; + if (p[0] == 0x1F && p[1] == 0x8B && p[2] == 8) + s = "gz"; + else if (p[0] == 0xFD && p[1] == '7' && p[2] == 'z' && p[3] == 'X' && p[4] == 'Z' && p[5] == 0) + s = "xz"; + else if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h' && p[3] >= '1' && p[3] <= '9') + s = "bz2"; + else if (p[0] == 0x28 && p[1] == 0xb5 && p[2] == 0x2f && p[3] == 0xfd) + s = "zst"; + else + s = "lzma"; + } + + res += s; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + + case kpidHeadersSize: prop = _headersSize; break; + case kpidPhySize: if (_phySize_Defined) prop = _phySize; break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidCpu: + { + AString s; + AddCPU(s); + /* + if (_lead.Type == kRpmType_Src) + s = "src"; + */ + SetStringProp(s, prop); + break; + } + + case kpidHostOS: + { + if (!_os.IsEmpty()) + SetStringProp(_os, prop); + else + { + TYPE_TO_PROP(k_OS, _lead.Os, prop); + } + break; + } + + #ifdef Z7_RPM_SHOW_METADATA + // case kpidComment: SetStringProp(_metadata, prop); break; + #endif + + case kpidName: + { + SetStringProp(GetBaseName() + ".rpm", prop); + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + if (index == 0) + switch (propID) + { + case kpidSize: + case kpidPackSize: + prop = _size; + break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidPath: + { + AString s (GetBaseName()); + s.Add_Dot(); + AddSubFileExtension(s); + SetStringProp(s, prop); + break; + } + + /* + case kpidExtension: + { + prop = GetSubFileExtension(); + break; + } + */ + } + #ifdef Z7_RPM_SHOW_METADATA + else + { + index--; + if (index > _metaFiles.Size()) + return E_INVALIDARG; + const CMetaFile &meta = _metaFiles[index]; + switch (propID) + { + case kpidSize: + case kpidPackSize: + prop = meta.Size; + break; + + case kpidMTime: + case kpidCTime: + SetTime(prop); + break; + + case kpidPath: + { + AString s ("[META]"); + s.Add_PathSepar(); + s.Add_UInt32(meta.Tag); + prop = s; + break; + } + } + } + #endif + + prop.Detach(value); + return S_OK; +} + + +HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader) +{ + UInt32 numEntries; + UInt32 dataLen; + { + char buf[k_HeaderSig_Size]; + RINOK(ReadStream_FALSE(stream, buf, k_HeaderSig_Size)) + if (Get32(buf) != 0x8EADE801) // buf[3] = 0x01 - is version + return S_FALSE; + // reserved = Get32(buf + 4); + numEntries = Get32(buf + 8); + dataLen = Get32(buf + 12); + if (numEntries >= 1 << 24) + return S_FALSE; + } + size_t indexSize = (size_t)numEntries * k_Entry_Size; + size_t headerSize = indexSize + dataLen; + if (headerSize < dataLen) + return S_FALSE; + CByteBuffer buffer(headerSize); + RINOK(ReadStream_FALSE(stream, buffer, headerSize)) + + for (UInt32 i = 0; i < numEntries; i++) + { + CEntry entry; + + entry.Parse(buffer + (size_t)i * k_Entry_Size); + if (entry.Offset > dataLen) + return S_FALSE; + + const Byte *p = buffer + indexSize + entry.Offset; + size_t rem = dataLen - entry.Offset; + + if (!isMainHeader) + { + if (entry.Tag == RPMSIGTAG_SIZE && + entry.Type == k_EntryType_INT32) + { + if (rem < 4 || entry.Count != 1) + return S_FALSE; + _headerPlusPayload_Size = Get32(p); + _headerPlusPayload_Size_Defined = true; + } + } + else + { + #ifdef Z7_RPM_SHOW_METADATA + { + _metadata.Add_UInt32(entry.Tag); + _metadata += ": "; + } + #endif + + if (entry.Type == k_EntryType_STRING) + { + if (entry.Count != 1) + return S_FALSE; + size_t j; + for (j = 0; j < rem && p[j] != 0; j++); + if (j == rem) + return S_FALSE; + AString s((const char *)p); + switch (entry.Tag) + { + case RPMTAG_NAME: _name = s; break; + case RPMTAG_VERSION: _version = s; break; + case RPMTAG_RELEASE: _release = s; break; + case RPMTAG_ARCH: _arch = s; break; + case RPMTAG_OS: _os = s; break; + case RPMTAG_PAYLOADFORMAT: _format = s; break; + case RPMTAG_PAYLOADCOMPRESSOR: _compressor = s; break; + } + + #ifdef Z7_RPM_SHOW_METADATA + _metadata += s; + #endif + } + else if (entry.Type == k_EntryType_INT32) + { + if (rem / 4 < entry.Count) + return S_FALSE; + if (entry.Tag == RPMTAG_BUILDTIME) + { + if (entry.Count != 1) + return S_FALSE; + _buildTime = Get32(p); + _time_Defined = true; + } + + #ifdef Z7_RPM_SHOW_METADATA + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata.Add_Space(); + _metadata.Add_UInt32(Get32(p + t * 4)); + } + #endif + } + + #ifdef Z7_RPM_SHOW_METADATA + + else if ( + entry.Type == k_EntryType_STRING_ARRAY || + entry.Type == k_EntryType_I18NSTRING) + { + const Byte *p2 = p; + size_t rem2 = rem; + for (UInt32 t = 0; t < entry.Count; t++) + { + if (rem2 == 0) + return S_FALSE; + if (t != 0) + _metadata.Add_LF(); + size_t j; + for (j = 0; j < rem2 && p2[j] != 0; j++); + if (j == rem2) + return S_FALSE; + _metadata += (const char *)p2; + j++; + p2 += j; + rem2 -= j; + } + } + else if (entry.Type == k_EntryType_INT16) + { + if (rem / 2 < entry.Count) + return S_FALSE; + for (UInt32 t = 0; t < entry.Count; t++) + { + if (t != 0) + _metadata.Add_Space(); + _metadata.Add_UInt32(Get16(p + t * 2)); + } + } + else if (entry.Type == k_EntryType_BIN) + { + if (rem < entry.Count) + return S_FALSE; + for (UInt32 t = 0; t < entry.Count; t++) + { + const unsigned b = p[t]; + _metadata += GET_HEX_CHAR_UPPER(b >> 4); + _metadata += GET_HEX_CHAR_UPPER(b & 0xF); + } + } + else + { + // p = p; + } + + _metadata.Add_LF(); + #endif + } + + #ifdef Z7_RPM_SHOW_METADATA + CMetaFile meta; + meta.Offset = entry.Offset; + meta.Tag = entry.Tag; + meta.Size = entry.Count; + _metaFiles.Add(meta); + #endif + } + + headerSize += k_HeaderSig_Size; + _headersSize += headerSize; + if (isMainHeader && _headerPlusPayload_Size_Defined) + { + if (_headerPlusPayload_Size < headerSize) + return S_FALSE; + _payloadSize = _headerPlusPayload_Size - headerSize; + _size = _payloadSize; + _phySize = _headersSize + _payloadSize; + _payloadSize_Defined = true; + _phySize_Defined = true; + } + return S_OK; +} + +HRESULT CHandler::Open2(ISequentialInStream *stream) +{ + { + Byte buf[kLeadSize]; + RINOK(ReadStream_FALSE(stream, buf, kLeadSize)) + if (Get32(buf) != 0xEDABEEDB) + return S_FALSE; + _lead.Parse(buf); + if (!_lead.IsSupported()) + return S_FALSE; + } + + _headersSize = kLeadSize; + + if (_lead.SignatureType == RPMSIG_NONE) + { + + } + else if (_lead.SignatureType == RPMSIG_PGP262_1024) + { + Byte temp[256]; + RINOK(ReadStream_FALSE(stream, temp, sizeof(temp))) + } + else if (_lead.SignatureType == RPMSIG_HEADERSIG) + { + RINOK(ReadHeader(stream, false)) + unsigned pos = (unsigned)_headersSize & 7; + if (pos != 0) + { + Byte temp[8]; + unsigned num = 8 - pos; + RINOK(ReadStream_FALSE(stream, temp, num)) + _headersSize += num; + } + } + else + return S_FALSE; + + return ReadHeader(stream, true); +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(inStream)) + + // start of payload is allowed to be unaligned + RINOK(ReadStream_FALSE(inStream, _payloadSig, sizeof(_payloadSig))) + + if (!_payloadSize_Defined) + { + UInt64 endPos; + RINOK(InStream_GetSize_SeekToEnd(inStream, endPos)) + _size = endPos - _headersSize; + } + _stream = inStream; + return S_OK; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _headersSize = 0; + _payloadSize = 0; + _size = 0; + _phySize = 0; + _headerPlusPayload_Size = 0; + + _payloadSize_Defined = false; + _phySize_Defined = false; + _headerPlusPayload_Size_Defined = false; + _time_Defined = false; + + _name.Empty(); + _version.Empty(); + _release.Empty(); + _arch.Empty(); + _os.Empty(); + + _format.Empty(); + _compressor.Empty(); + + #ifdef Z7_RPM_SHOW_METADATA + _metadata.Empty(); + _metaFiles.Size(); + #endif + + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1 + #ifdef Z7_RPM_SHOW_METADATA + + _metaFiles.Size() + #endif + ; + + return S_OK; +} + +static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB}; + +REGISTER_ARC_I( + "Rpm", "rpm", NULL, 0xEB, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/SparseHandler.cpp b/CPP/7zip/Archive/SparseHandler.cpp index 56a0ad6a5..5e666ed77 100644 --- a/CPP/7zip/Archive/SparseHandler.cpp +++ b/CPP/7zip/Archive/SparseHandler.cpp @@ -1,556 +1,556 @@ -// SparseHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -#define G16(_offs_, dest) dest = Get16(p + (_offs_)); -#define G32(_offs_, dest) dest = Get32(p + (_offs_)); - -using namespace NWindows; - -namespace NArchive { -namespace NSparse { - -// libsparse and simg2img - -struct CHeader -{ - // UInt32 magic; /* 0xed26ff3a */ - // UInt16 major_version; /* (0x1) - reject images with higher major versions */ - // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */ - UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */ - UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ - UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */ - UInt32 NumBlocks; /* total blocks in the non-sparse output image */ - UInt32 NumChunks; /* total chunks in the sparse input image */ - // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */ - - void Parse(const Byte *p) - { - // G16 (4, major_version); - // G16 (6, minor_version); - G16 (8, file_hdr_sz) - G16 (10, chunk_hdr_sz) - G32 (12, BlockSize) - G32 (16, NumBlocks) - G32 (20, NumChunks) - // G32 (24, image_checksum); - } -}; - -// #define SPARSE_HEADER_MAGIC 0xed26ff3a - -#define CHUNK_TYPE_RAW 0xCAC1 -#define CHUNK_TYPE_FILL 0xCAC2 -#define CHUNK_TYPE_DONT_CARE 0xCAC3 -#define CHUNK_TYPE_CRC32 0xCAC4 - -#define MY_CHUNK_TYPE_FILL 0 -#define MY_CHUNK_TYPE_DONT_CARE 1 -#define MY_CHUNK_TYPE_RAW_START 2 - -static const char * const g_Methods[] = -{ - "RAW" - , "FILL" - , "SPARSE" // "DONT_CARE" - , "CRC32" -}; - -static const unsigned kFillSize = 4; - -struct CChunk -{ - UInt32 VirtBlock; - Byte Fill [kFillSize]; - UInt64 PhyOffset; - - CChunk() - { - Fill[0] = - Fill[1] = - Fill[2] = - Fill[3] = - 0; - } -}; - -static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 }; - - -Z7_class_CHandler_final: public CHandlerImg -{ - Z7_IFACE_COM7_IMP(IInArchive_Img) - - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) - - CRecordVector Chunks; - UInt64 _virtSize_fromChunks; - unsigned _blockSizeLog; - UInt32 _chunkIndexPrev; - - UInt64 _packSizeProcessed; - UInt64 _phySize; - UInt32 _methodFlags; - bool _isArc; - bool _headersError; - bool _unexpectedEnd; - // bool _unsupported; - UInt32 NumChunks; // from header - - HRESULT Seek2(UInt64 offset) - { - _posInArc = offset; - return InStream_SeekSet(Stream, offset); - } - - void InitSeekPositions() - { - /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). - So we must reset these variables before first call of Read() */ - Reset_VirtPos(); - Reset_PosInArc(); - _chunkIndexPrev = 0; - _packSizeProcessed = 0; - } - - // virtual functions - bool Init_PackSizeProcessed() Z7_override - { - _packSizeProcessed = 0; - return true; - } - bool Get_PackSizeProcessed(UInt64 &size) Z7_override - { - size = _packSizeProcessed; - return true; - } - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; - HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); -}; - - - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidClusterSize, - kpidNumBlocks, - kpidMethod -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break; - case kpidNumBlocks: prop = (UInt32)NumChunks; break; - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - - case kpidMethod: - { - FLAGS_TO_PROP(g_Methods, _methodFlags, prop); - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_headersError) v |= kpv_ErrorFlags_HeadersError; - if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; - // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; - if (!Stream && v == 0 && _isArc) - v = kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidSize: prop = _size; break; - case kpidPackSize: prop = _phySize; break; - case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -static unsigned GetLogSize(UInt32 size) -{ - unsigned k; - for (k = 0; k < 32; k++) - if (((UInt32)1 << k) == size) - return k; - return k; -} - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) -{ - const unsigned kHeaderSize = 28; - const unsigned kChunkHeaderSize = 12; - CHeader h; - { - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) - if (memcmp(buf, k_Signature, 6) != 0) - return S_FALSE; - h.Parse(buf); - } - - if (h.file_hdr_sz != kHeaderSize || - h.chunk_hdr_sz != kChunkHeaderSize) - return S_FALSE; - - NumChunks = h.NumChunks; - - const unsigned logSize = GetLogSize(h.BlockSize); - if (logSize < 2 || logSize >= 32) - return S_FALSE; - _blockSizeLog = logSize; - - _size = (UInt64)h.NumBlocks << logSize; - - if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit - return S_FALSE; - - _isArc = true; - Chunks.Reserve(h.NumChunks + 1); - UInt64 offset = kHeaderSize; - UInt32 virtBlock = 0; - UInt32 i; - - for (i = 0; i < h.NumChunks; i++) - { - { - const UInt32 mask = ((UInt32)1 << 16) - 1; - if ((i & mask) == mask && openCallback) - { - RINOK(openCallback->SetCompleted(NULL, &offset)) - } - } - Byte buf[kChunkHeaderSize]; - { - size_t processed = kChunkHeaderSize; - RINOK(ReadStream(stream, buf, &processed)) - if (kChunkHeaderSize != processed) - { - offset += kChunkHeaderSize; - break; - } - } - const UInt32 type = Get32(&buf[0]); - const UInt32 numBlocks = Get32(&buf[4]); - UInt32 size = Get32(&buf[8]); - - if (type < CHUNK_TYPE_RAW || - type > CHUNK_TYPE_CRC32) - return S_FALSE; - if (size < kChunkHeaderSize) - return S_FALSE; - CChunk c; - c.PhyOffset = offset + kChunkHeaderSize; - c.VirtBlock = virtBlock; - offset += size; - size -= kChunkHeaderSize; - _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW)); - - if (numBlocks > h.NumBlocks - virtBlock) - return S_FALSE; - - if (type == CHUNK_TYPE_CRC32) - { - // crc chunk must be last chunk (i == h.NumChunks -1); - if (size != kFillSize || numBlocks != 0) - return S_FALSE; - { - size_t processed = kFillSize; - RINOK(ReadStream(stream, c.Fill, &processed)) - if (kFillSize != processed) - break; - } - continue; - } - // else - { - if (numBlocks == 0) - return S_FALSE; - - if (type == CHUNK_TYPE_DONT_CARE) - { - if (size != 0) - return S_FALSE; - c.PhyOffset = MY_CHUNK_TYPE_DONT_CARE; - } - else if (type == CHUNK_TYPE_FILL) - { - if (size != kFillSize) - return S_FALSE; - c.PhyOffset = MY_CHUNK_TYPE_FILL; - size_t processed = kFillSize; - RINOK(ReadStream(stream, c.Fill, &processed)) - if (kFillSize != processed) - break; - } - else if (type == CHUNK_TYPE_RAW) - { - /* Here we require (size == virtSize). - Probably original decoder also requires it. - But maybe size of last chunk can be non-aligned with blockSize ? */ - const UInt32 virtSize = (numBlocks << _blockSizeLog); - if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog)) - return S_FALSE; - } - else - return S_FALSE; - - virtBlock += numBlocks; - Chunks.AddInReserved(c); - if (type == CHUNK_TYPE_RAW) - RINOK(InStream_SeekSet(stream, offset)) - } - } - - if (i != h.NumChunks) - _unexpectedEnd = true; - else if (virtBlock != h.NumBlocks) - _headersError = true; - - _phySize = offset; - - { - CChunk c; - c.VirtBlock = virtBlock; - c.PhyOffset = offset; - Chunks.AddInReserved(c); - } - _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog; - - Stream = stream; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - Chunks.Clear(); - _isArc = false; - _virtSize_fromChunks = 0; - // _unsupported = false; - _headersError = false; - _unexpectedEnd = false; - _phySize = 0; - _methodFlags = 0; - - _chunkIndexPrev = 0; - _packSizeProcessed = 0; - - // CHandlerImg: - Clear_HandlerImg_Vars(); - Stream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - if (Chunks.Size() < 1) - return S_FALSE; - if (Chunks.Size() < 2 && _virtSize_fromChunks != 0) - return S_FALSE; - // if (_unsupported) return S_FALSE; - InitSeekPositions(); - CMyComPtr streamTemp = this; - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - - -HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) -{ - processed = 0; - if (offset > _phySize || offset + size > _phySize) - { - // we don't expect these cases, if (_phySize) was set correctly. - return S_FALSE; - } - if (offset != _posInArc) - { - const HRESULT res = Seek2(offset); - if (res != S_OK) - { - Reset_PosInArc(); // we don't trust seek_pos in case of error - return res; - } - } - { - size_t size2 = size; - const HRESULT res = ReadStream(Stream, data, &size2); - processed = (UInt32)size2; - _packSizeProcessed += size2; - _posInArc += size2; - if (res != S_OK) - Reset_PosInArc(); // we don't trust seek_pos in case of reading error - return res; - } -} - - -Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug - if (_virtPos >= _virtSize_fromChunks) - return S_OK; - { - const UInt64 rem = _virtSize_fromChunks - _virtPos; - if (size > rem) - size = (UInt32)rem; - if (size == 0) - return S_OK; - } - - UInt32 chunkIndex = _chunkIndexPrev; - if (chunkIndex + 1 >= Chunks.Size()) - return S_FALSE; - { - const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog); - if (blockIndex < Chunks[chunkIndex ].VirtBlock || - blockIndex >= Chunks[chunkIndex + 1].VirtBlock) - { - unsigned left = 0, right = Chunks.Size() - 1; - for (;;) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - if (mid == left) - break; - if (blockIndex < Chunks[mid].VirtBlock) - right = mid; - else - left = mid; - } - chunkIndex = left; - _chunkIndexPrev = chunkIndex; - } - } - - const CChunk &c = Chunks[chunkIndex]; - const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog); - { - const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock; - const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset; - if (size > rem) - size = (UInt32)rem; - } - - const UInt64 phyOffset = c.PhyOffset; - - if (phyOffset >= MY_CHUNK_TYPE_RAW_START) - { - UInt32 processed = 0; - const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed); - if (processedSize) - *processedSize = processed; - _virtPos += processed; - return res; - } - - Byte b = 0; - - if (phyOffset == MY_CHUNK_TYPE_FILL) - { - const Byte b0 = c.Fill [0]; - const Byte b1 = c.Fill [1]; - const Byte b2 = c.Fill [2]; - const Byte b3 = c.Fill [3]; - if (b0 != b1 || - b0 != b2 || - b0 != b3) - { - if (processedSize) - *processedSize = size; - _virtPos += size; - Byte *dest = (Byte *)data; - while (size >= 4) - { - dest[0] = b0; - dest[1] = b1; - dest[2] = b2; - dest[3] = b3; - dest += 4; - size -= 4; - } - if (size > 0) dest[0] = b0; - if (size > 1) dest[1] = b1; - if (size > 2) dest[2] = b2; - return S_OK; - } - b = b0; - } - else if (phyOffset != MY_CHUNK_TYPE_DONT_CARE) - return S_FALSE; - - memset(data, b, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; -} - -REGISTER_ARC_I( - "Sparse", "simg img", NULL, 0xc2, - k_Signature, - 0, - 0, - NULL) - -}} +// SparseHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); + +using namespace NWindows; + +namespace NArchive { +namespace NSparse { + +// libsparse and simg2img + +struct CHeader +{ + // UInt32 magic; /* 0xed26ff3a */ + // UInt16 major_version; /* (0x1) - reject images with higher major versions */ + // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */ + UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */ + UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ + UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */ + UInt32 NumBlocks; /* total blocks in the non-sparse output image */ + UInt32 NumChunks; /* total chunks in the sparse input image */ + // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */ + + void Parse(const Byte *p) + { + // G16 (4, major_version); + // G16 (6, minor_version); + G16 (8, file_hdr_sz) + G16 (10, chunk_hdr_sz) + G32 (12, BlockSize) + G32 (16, NumBlocks) + G32 (20, NumChunks) + // G32 (24, image_checksum); + } +}; + +// #define SPARSE_HEADER_MAGIC 0xed26ff3a + +#define CHUNK_TYPE_RAW 0xCAC1 +#define CHUNK_TYPE_FILL 0xCAC2 +#define CHUNK_TYPE_DONT_CARE 0xCAC3 +#define CHUNK_TYPE_CRC32 0xCAC4 + +#define MY_CHUNK_TYPE_FILL 0 +#define MY_CHUNK_TYPE_DONT_CARE 1 +#define MY_CHUNK_TYPE_RAW_START 2 + +static const char * const g_Methods[] = +{ + "RAW" + , "FILL" + , "SPARSE" // "DONT_CARE" + , "CRC32" +}; + +static const unsigned kFillSize = 4; + +struct CChunk +{ + UInt32 VirtBlock; + Byte Fill [kFillSize]; + UInt64 PhyOffset; + + CChunk() + { + Fill[0] = + Fill[1] = + Fill[2] = + Fill[3] = + 0; + } +}; + +static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 }; + + +Z7_class_CHandler_final: public CHandlerImg +{ + Z7_IFACE_COM7_IMP(IInArchive_Img) + + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) + + CRecordVector Chunks; + UInt64 _virtSize_fromChunks; + unsigned _blockSizeLog; + UInt32 _chunkIndexPrev; + + UInt64 _packSizeProcessed; + UInt64 _phySize; + UInt32 _methodFlags; + bool _isArc; + bool _headersError; + bool _unexpectedEnd; + // bool _unsupported; + UInt32 NumChunks; // from header + + HRESULT Seek2(UInt64 offset) + { + _posInArc = offset; + return InStream_SeekSet(Stream, offset); + } + + void InitSeekPositions() + { + /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). + So we must reset these variables before first call of Read() */ + Reset_VirtPos(); + Reset_PosInArc(); + _chunkIndexPrev = 0; + _packSizeProcessed = 0; + } + + // virtual functions + bool Init_PackSizeProcessed() Z7_override + { + _packSizeProcessed = 0; + return true; + } + bool Get_PackSizeProcessed(UInt64 &size) Z7_override + { + size = _packSizeProcessed; + return true; + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; + HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); +}; + + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidClusterSize, + kpidNumBlocks, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break; + case kpidNumBlocks: prop = (UInt32)NumChunks; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + + case kpidMethod: + { + FLAGS_TO_PROP(g_Methods, _methodFlags, prop); + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_headersError) v |= kpv_ErrorFlags_HeadersError; + if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (!Stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: prop = _phySize; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static unsigned GetLogSize(UInt32 size) +{ + unsigned k; + for (k = 0; k < 32; k++) + if (((UInt32)1 << k) == size) + return k; + return k; +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) +{ + const unsigned kHeaderSize = 28; + const unsigned kChunkHeaderSize = 12; + CHeader h; + { + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) + if (memcmp(buf, k_Signature, 6) != 0) + return S_FALSE; + h.Parse(buf); + } + + if (h.file_hdr_sz != kHeaderSize || + h.chunk_hdr_sz != kChunkHeaderSize) + return S_FALSE; + + NumChunks = h.NumChunks; + + const unsigned logSize = GetLogSize(h.BlockSize); + if (logSize < 2 || logSize >= 32) + return S_FALSE; + _blockSizeLog = logSize; + + _size = (UInt64)h.NumBlocks << logSize; + + if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit + return S_FALSE; + + _isArc = true; + Chunks.Reserve(h.NumChunks + 1); + UInt64 offset = kHeaderSize; + UInt32 virtBlock = 0; + UInt32 i; + + for (i = 0; i < h.NumChunks; i++) + { + { + const UInt32 mask = ((UInt32)1 << 16) - 1; + if ((i & mask) == mask && openCallback) + { + RINOK(openCallback->SetCompleted(NULL, &offset)) + } + } + Byte buf[kChunkHeaderSize]; + { + size_t processed = kChunkHeaderSize; + RINOK(ReadStream(stream, buf, &processed)) + if (kChunkHeaderSize != processed) + { + offset += kChunkHeaderSize; + break; + } + } + const UInt32 type = Get32(&buf[0]); + const UInt32 numBlocks = Get32(&buf[4]); + UInt32 size = Get32(&buf[8]); + + if (type < CHUNK_TYPE_RAW || + type > CHUNK_TYPE_CRC32) + return S_FALSE; + if (size < kChunkHeaderSize) + return S_FALSE; + CChunk c; + c.PhyOffset = offset + kChunkHeaderSize; + c.VirtBlock = virtBlock; + offset += size; + size -= kChunkHeaderSize; + _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW)); + + if (numBlocks > h.NumBlocks - virtBlock) + return S_FALSE; + + if (type == CHUNK_TYPE_CRC32) + { + // crc chunk must be last chunk (i == h.NumChunks -1); + if (size != kFillSize || numBlocks != 0) + return S_FALSE; + { + size_t processed = kFillSize; + RINOK(ReadStream(stream, c.Fill, &processed)) + if (kFillSize != processed) + break; + } + continue; + } + // else + { + if (numBlocks == 0) + return S_FALSE; + + if (type == CHUNK_TYPE_DONT_CARE) + { + if (size != 0) + return S_FALSE; + c.PhyOffset = MY_CHUNK_TYPE_DONT_CARE; + } + else if (type == CHUNK_TYPE_FILL) + { + if (size != kFillSize) + return S_FALSE; + c.PhyOffset = MY_CHUNK_TYPE_FILL; + size_t processed = kFillSize; + RINOK(ReadStream(stream, c.Fill, &processed)) + if (kFillSize != processed) + break; + } + else if (type == CHUNK_TYPE_RAW) + { + /* Here we require (size == virtSize). + Probably original decoder also requires it. + But maybe size of last chunk can be non-aligned with blockSize ? */ + const UInt32 virtSize = (numBlocks << _blockSizeLog); + if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog)) + return S_FALSE; + } + else + return S_FALSE; + + virtBlock += numBlocks; + Chunks.AddInReserved(c); + if (type == CHUNK_TYPE_RAW) + RINOK(InStream_SeekSet(stream, offset)) + } + } + + if (i != h.NumChunks) + _unexpectedEnd = true; + else if (virtBlock != h.NumBlocks) + _headersError = true; + + _phySize = offset; + + { + CChunk c; + c.VirtBlock = virtBlock; + c.PhyOffset = offset; + Chunks.AddInReserved(c); + } + _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog; + + Stream = stream; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + Chunks.Clear(); + _isArc = false; + _virtSize_fromChunks = 0; + // _unsupported = false; + _headersError = false; + _unexpectedEnd = false; + _phySize = 0; + _methodFlags = 0; + + _chunkIndexPrev = 0; + _packSizeProcessed = 0; + + // CHandlerImg: + Clear_HandlerImg_Vars(); + Stream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + if (Chunks.Size() < 1) + return S_FALSE; + if (Chunks.Size() < 2 && _virtSize_fromChunks != 0) + return S_FALSE; + // if (_unsupported) return S_FALSE; + InitSeekPositions(); + CMyComPtr streamTemp = this; + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + + +HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) +{ + processed = 0; + if (offset > _phySize || offset + size > _phySize) + { + // we don't expect these cases, if (_phySize) was set correctly. + return S_FALSE; + } + if (offset != _posInArc) + { + const HRESULT res = Seek2(offset); + if (res != S_OK) + { + Reset_PosInArc(); // we don't trust seek_pos in case of error + return res; + } + } + { + size_t size2 = size; + const HRESULT res = ReadStream(Stream, data, &size2); + processed = (UInt32)size2; + _packSizeProcessed += size2; + _posInArc += size2; + if (res != S_OK) + Reset_PosInArc(); // we don't trust seek_pos in case of reading error + return res; + } +} + + +Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug + if (_virtPos >= _virtSize_fromChunks) + return S_OK; + { + const UInt64 rem = _virtSize_fromChunks - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + UInt32 chunkIndex = _chunkIndexPrev; + if (chunkIndex + 1 >= Chunks.Size()) + return S_FALSE; + { + const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog); + if (blockIndex < Chunks[chunkIndex ].VirtBlock || + blockIndex >= Chunks[chunkIndex + 1].VirtBlock) + { + unsigned left = 0, right = Chunks.Size() - 1; + for (;;) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + if (mid == left) + break; + if (blockIndex < Chunks[mid].VirtBlock) + right = mid; + else + left = mid; + } + chunkIndex = left; + _chunkIndexPrev = chunkIndex; + } + } + + const CChunk &c = Chunks[chunkIndex]; + const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog); + { + const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock; + const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset; + if (size > rem) + size = (UInt32)rem; + } + + const UInt64 phyOffset = c.PhyOffset; + + if (phyOffset >= MY_CHUNK_TYPE_RAW_START) + { + UInt32 processed = 0; + const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed); + if (processedSize) + *processedSize = processed; + _virtPos += processed; + return res; + } + + Byte b = 0; + + if (phyOffset == MY_CHUNK_TYPE_FILL) + { + const Byte b0 = c.Fill [0]; + const Byte b1 = c.Fill [1]; + const Byte b2 = c.Fill [2]; + const Byte b3 = c.Fill [3]; + if (b0 != b1 || + b0 != b2 || + b0 != b3) + { + if (processedSize) + *processedSize = size; + _virtPos += size; + Byte *dest = (Byte *)data; + while (size >= 4) + { + dest[0] = b0; + dest[1] = b1; + dest[2] = b2; + dest[3] = b3; + dest += 4; + size -= 4; + } + if (size > 0) dest[0] = b0; + if (size > 1) dest[1] = b1; + if (size > 2) dest[2] = b2; + return S_OK; + } + b = b0; + } + else if (phyOffset != MY_CHUNK_TYPE_DONT_CARE) + return S_FALSE; + + memset(data, b, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; +} + +REGISTER_ARC_I( + "Sparse", "simg img", NULL, 0xc2, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp index 50a096797..bf89303bb 100644 --- a/CPP/7zip/Archive/SplitHandler.cpp +++ b/CPP/7zip/Archive/SplitHandler.cpp @@ -1,353 +1,353 @@ -// SplitHandler.cpp - -#include "StdAfx.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" - -#include "Common/MultiStream.h" - -using namespace NWindows; - -namespace NArchive { -namespace NSplit { - -static const Byte kProps[] = -{ - kpidPath, - kpidSize -}; - -static const Byte kArcProps[] = -{ - kpidNumVolumes, - kpidTotalPhySize -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CObjectVector > _streams; - CRecordVector _sizes; - UString _subName; - UInt64 _totalSize; - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; - case kpidTotalPhySize: prop = _totalSize; break; - case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; - default: break; - } - prop.Detach(value); - return S_OK; -} - -struct CSeqName -{ - UString _unchangedPart; - UString _changedPart; - bool _splitStyle; - - bool GetNextName(UString &s) - { - { - unsigned i = _changedPart.Len(); - for (;;) - { - wchar_t c = _changedPart[--i]; - - if (_splitStyle) - { - if (c == 'z') - { - _changedPart.ReplaceOneCharAtPos(i, L'a'); - if (i == 0) - return false; - continue; - } - else if (c == 'Z') - { - _changedPart.ReplaceOneCharAtPos(i, L'A'); - if (i == 0) - return false; - continue; - } - } - else - { - if (c == '9') - { - _changedPart.ReplaceOneCharAtPos(i, L'0'); - if (i == 0) - { - _changedPart.InsertAtFront(L'1'); - break; - } - continue; - } - } - - c++; - _changedPart.ReplaceOneCharAtPos(i, c); - break; - } - } - - s = _unchangedPart + _changedPart; - return true; - } -}; - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) -{ - Close(); - if (!callback) - return S_FALSE; - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpenVolumeCallback, - volumeCallback, callback) - if (!volumeCallback) - return S_FALSE; - - UString name; - { - NCOM::CPropVariant prop; - RINOK(volumeCallback->GetProperty(kpidName, &prop)) - if (prop.vt != VT_BSTR) - return S_FALSE; - name = prop.bstrVal; - } - - const int dotPos = name.ReverseFind_Dot(); - const UString prefix = name.Left((unsigned)(dotPos + 1)); - const UString ext = name.Ptr((unsigned)(dotPos + 1)); - UString ext2 = ext; - ext2.MakeLower_Ascii(); - - CSeqName seqName; - - unsigned numLetters = 2; - bool splitStyle = false; - - if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa")) - { - splitStyle = true; - while (numLetters < ext2.Len()) - { - if (ext2[ext2.Len() - numLetters - 1] != 'a') - break; - numLetters++; - } - } - else if (ext2.Len() >= 2 && ( - StringsAreEqual_Ascii(ext2.RightPtr(2), "01") - || StringsAreEqual_Ascii(ext2.RightPtr(2), "00") - )) - { - while (numLetters < ext2.Len()) - { - if (ext2[ext2.Len() - numLetters - 1] != '0') - break; - numLetters++; - } - if (numLetters != ext2.Len()) - return S_FALSE; - } - else - return S_FALSE; - - seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters); - seqName._changedPart = ext.RightPtr(numLetters); - seqName._splitStyle = splitStyle; - - if (prefix.Len() < 1) - _subName = "file"; - else - _subName.SetFrom(prefix, prefix.Len() - 1); - - UInt64 size; - { - /* - NCOM::CPropVariant prop; - RINOK(volumeCallback->GetProperty(kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - */ - } - RINOK(InStream_AtBegin_GetSize(stream, size)) - - _totalSize += size; - _sizes.Add(size); - _streams.Add(stream); - - { - const UInt64 numFiles = _streams.Size(); - RINOK(callback->SetCompleted(&numFiles, NULL)) - } - - for (;;) - { - UString fullName; - if (!seqName.GetNextName(fullName)) - break; - CMyComPtr nextStream; - const HRESULT result = volumeCallback->GetStream(fullName, &nextStream); - if (result == S_FALSE) - break; - if (result != S_OK) - return result; - if (!nextStream) - break; - RINOK(InStream_AtBegin_GetSize(nextStream, size)) - _totalSize += size; - _sizes.Add(size); - _streams.Add(nextStream); - { - const UInt64 numFiles = _streams.Size(); - RINOK(callback->SetCompleted(&numFiles, NULL)) - } - } - - if (_streams.Size() == 1) - { - if (splitStyle) - return S_FALSE; - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - const HRESULT res = Open2(stream, callback); - if (res != S_OK) - Close(); - return res; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _totalSize = 0; - _subName.Empty(); - _streams.Clear(); - _sizes.Clear(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _streams.IsEmpty() ? 0 : 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPath: prop = _subName; break; - case kpidSize: - case kpidPackSize: - prop = _totalSize; - break; - default: break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - UInt64 currentTotalSize = 0; - RINOK(extractCallback->SetTotal(_totalSize)) - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &outStream, askMode)) - if (!testMode && !outStream) - return S_OK; - RINOK(extractCallback->PrepareOperation(askMode)) - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - for (unsigned i = 0;; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()) - if (i == _streams.Size()) - break; - IInStream *inStream = _streams[i]; - RINOK(InStream_SeekToBegin(inStream)) - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - currentTotalSize += copyCoderSpec->TotalSize; - } - outStream.Release(); - return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - if (index != 0) - return E_INVALIDARG; - *stream = NULL; - CMultiStream *streamSpec = new CMultiStream; - CMyComPtr streamTemp = streamSpec; - FOR_VECTOR (i, _streams) - { - CMultiStream::CSubStreamInfo subStreamInfo; - subStreamInfo.Stream = _streams[i]; - subStreamInfo.Size = _sizes[i]; - streamSpec->Streams.Add(subStreamInfo); - } - streamSpec->Init(); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -REGISTER_ARC_I_NO_SIG( - "Split", "001", NULL, 0xEA, - 0, - 0, - NULL) - -}} +// SplitHandler.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/MultiStream.h" + +using namespace NWindows; + +namespace NArchive { +namespace NSplit { + +static const Byte kProps[] = +{ + kpidPath, + kpidSize +}; + +static const Byte kArcProps[] = +{ + kpidNumVolumes, + kpidTotalPhySize +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CObjectVector > _streams; + CRecordVector _sizes; + UString _subName; + UInt64 _totalSize; + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break; + case kpidTotalPhySize: prop = _totalSize; break; + case kpidNumVolumes: prop = (UInt32)_streams.Size(); break; + default: break; + } + prop.Detach(value); + return S_OK; +} + +struct CSeqName +{ + UString _unchangedPart; + UString _changedPart; + bool _splitStyle; + + bool GetNextName(UString &s) + { + { + unsigned i = _changedPart.Len(); + for (;;) + { + wchar_t c = _changedPart[--i]; + + if (_splitStyle) + { + if (c == 'z') + { + _changedPart.ReplaceOneCharAtPos(i, L'a'); + if (i == 0) + return false; + continue; + } + else if (c == 'Z') + { + _changedPart.ReplaceOneCharAtPos(i, L'A'); + if (i == 0) + return false; + continue; + } + } + else + { + if (c == '9') + { + _changedPart.ReplaceOneCharAtPos(i, L'0'); + if (i == 0) + { + _changedPart.InsertAtFront(L'1'); + break; + } + continue; + } + } + + c++; + _changedPart.ReplaceOneCharAtPos(i, c); + break; + } + } + + s = _unchangedPart + _changedPart; + return true; + } +}; + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + Close(); + if (!callback) + return S_FALSE; + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpenVolumeCallback, + volumeCallback, callback) + if (!volumeCallback) + return S_FALSE; + + UString name; + { + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidName, &prop)) + if (prop.vt != VT_BSTR) + return S_FALSE; + name = prop.bstrVal; + } + + const int dotPos = name.ReverseFind_Dot(); + const UString prefix = name.Left((unsigned)(dotPos + 1)); + const UString ext = name.Ptr((unsigned)(dotPos + 1)); + UString ext2 = ext; + ext2.MakeLower_Ascii(); + + CSeqName seqName; + + unsigned numLetters = 2; + bool splitStyle = false; + + if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa")) + { + splitStyle = true; + while (numLetters < ext2.Len()) + { + if (ext2[ext2.Len() - numLetters - 1] != 'a') + break; + numLetters++; + } + } + else if (ext2.Len() >= 2 && ( + StringsAreEqual_Ascii(ext2.RightPtr(2), "01") + || StringsAreEqual_Ascii(ext2.RightPtr(2), "00") + )) + { + while (numLetters < ext2.Len()) + { + if (ext2[ext2.Len() - numLetters - 1] != '0') + break; + numLetters++; + } + if (numLetters != ext2.Len()) + return S_FALSE; + } + else + return S_FALSE; + + seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters); + seqName._changedPart = ext.RightPtr(numLetters); + seqName._splitStyle = splitStyle; + + if (prefix.Len() < 1) + _subName = "file"; + else + _subName.SetFrom(prefix, prefix.Len() - 1); + + UInt64 size; + { + /* + NCOM::CPropVariant prop; + RINOK(volumeCallback->GetProperty(kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + */ + } + RINOK(InStream_AtBegin_GetSize(stream, size)) + + _totalSize += size; + _sizes.Add(size); + _streams.Add(stream); + + { + const UInt64 numFiles = _streams.Size(); + RINOK(callback->SetCompleted(&numFiles, NULL)) + } + + for (;;) + { + UString fullName; + if (!seqName.GetNextName(fullName)) + break; + CMyComPtr nextStream; + const HRESULT result = volumeCallback->GetStream(fullName, &nextStream); + if (result == S_FALSE) + break; + if (result != S_OK) + return result; + if (!nextStream) + break; + RINOK(InStream_AtBegin_GetSize(nextStream, size)) + _totalSize += size; + _sizes.Add(size); + _streams.Add(nextStream); + { + const UInt64 numFiles = _streams.Size(); + RINOK(callback->SetCompleted(&numFiles, NULL)) + } + } + + if (_streams.Size() == 1) + { + if (splitStyle) + return S_FALSE; + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + const HRESULT res = Open2(stream, callback); + if (res != S_OK) + Close(); + return res; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _totalSize = 0; + _subName.Empty(); + _streams.Clear(); + _sizes.Clear(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _streams.IsEmpty() ? 0 : 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPath: prop = _subName; break; + case kpidSize: + case kpidPackSize: + prop = _totalSize; + break; + default: break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + UInt64 currentTotalSize = 0; + RINOK(extractCallback->SetTotal(_totalSize)) + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &outStream, askMode)) + if (!testMode && !outStream) + return S_OK; + RINOK(extractCallback->PrepareOperation(askMode)) + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (unsigned i = 0;; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()) + if (i == _streams.Size()) + break; + IInStream *inStream = _streams[i]; + RINOK(InStream_SeekToBegin(inStream)) + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) + currentTotalSize += copyCoderSpec->TotalSize; + } + outStream.Release(); + return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK); + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + if (index != 0) + return E_INVALIDARG; + *stream = NULL; + CMultiStream *streamSpec = new CMultiStream; + CMyComPtr streamTemp = streamSpec; + FOR_VECTOR (i, _streams) + { + CMultiStream::CSubStreamInfo subStreamInfo; + subStreamInfo.Stream = _streams[i]; + subStreamInfo.Size = _sizes[i]; + streamSpec->Streams.Add(subStreamInfo); + } + streamSpec->Init(); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I_NO_SIG( + "Split", "001", NULL, 0xEA, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index 6b796a0c0..46e0e1ef8 100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -1,2370 +1,2370 @@ -// SquashfsHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/LzmaDec.h" -#include "../../../C/Xz.h" -#include "../../../C/ZstdDec.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyLinux.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringConvert.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariantUtils.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/CWrappers.h" -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/ZlibDecoder.h" -// #include "../Compress/LzmaDecoder.h" - -namespace NArchive { -namespace NSquashfs { - -static const UInt32 kNumFilesMax = 1 << 28; -static const unsigned kNumDirLevelsMax = 1 << 10; - -// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs - -/* -#define Get16(p) (be ? GetBe16(p) : GetUi16(p)) -#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) -#define Get64(p) (be ? GetBe64(p) : GetUi64(p)) -*/ - -static UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } -static UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); } -static UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } - -#define Get16(p) Get16b(p, be) -#define Get32(p) Get32b(p, be) -#define Get64(p) Get64b(p, be) - -#define LE_16(offs, dest) dest = GetUi16(p + (offs)) -#define LE_32(offs, dest) dest = GetUi32(p + (offs)) -#define LE_64(offs, dest) dest = GetUi64(p + (offs)) - -#define GET_16(offs, dest) dest = Get16(p + (offs)) -#define GET_32(offs, dest) dest = Get32(p + (offs)) -#define GET_64(offs, dest) dest = Get64(p + (offs)) - -static const UInt32 kSignature32_LE = 0x73717368; -static const UInt32 kSignature32_BE = 0x68737173; -static const UInt32 kSignature32_LZ = 0x71736873; -static const UInt32 kSignature32_B2 = 0x73687371; - -#define kMethod_ZLIB 1 -#define kMethod_LZMA 2 -#define kMethod_LZO 3 -#define kMethod_XZ 4 -// #define kMethod_LZ4 5 -#define kMethod_ZSTD 6 - -static const char * const k_Methods[] = -{ - "0" - , "ZLIB" - , "LZMA" - , "LZO" - , "XZ" - , "LZ4" - , "ZSTD" -}; - -static const unsigned kMetadataBlockSizeLog = 13; -static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog); - -enum -{ - kType_IPC, - kType_DIR, - kType_FILE, - kType_LNK, - kType_BLK, - kType_CHR, - kType_FIFO, - kType_SOCK -}; - -static const UInt32 k_TypeToMode[] = -{ - 0, - MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK, - MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK -}; - - -enum -{ - kFlag_UNC_INODES, - kFlag_UNC_DATA, - kFlag_CHECK, - kFlag_UNC_FRAGS, - kFlag_NO_FRAGS, - kFlag_ALWAYS_FRAG, - kFlag_DUPLICATE, - kFlag_EXPORT -}; - -static const char * const k_Flags[] = -{ - "UNCOMPRESSED_INODES" - , "UNCOMPRESSED_DATA" - , "CHECK" - , "UNCOMPRESSED_FRAGMENTS" - , "NO_FRAGMENTS" - , "ALWAYS_FRAGMENTS" - , "DUPLICATES_REMOVED" - , "EXPORTABLE" - , "UNCOMPRESSED_XATTRS" - , "NO_XATTRS" - , "COMPRESSOR_OPTIONS" - , "UNCOMPRESSED_IDS" -}; - -static const UInt32 kNotCompressedBit16 = 1 << 15; -static const UInt32 kNotCompressedBit32 = 1 << 24; - -#define GET_COMPRESSED_BLOCK_SIZE(size) ((size) & ~kNotCompressedBit32) -#define IS_COMPRESSED_BLOCK(size) (((size) & kNotCompressedBit32) == 0) - -// static const UInt32 kHeaderSize1 = 0x33; -// static const UInt32 kHeaderSize2 = 0x3F; -static const UInt32 kHeaderSize3 = 0x77; -// static const UInt32 kHeaderSize4 = 0x60; - -struct CHeader -{ - bool be; - bool SeveralMethods; - Byte NumUids; - Byte NumGids; - - UInt32 NumInodes; - UInt32 CTime; - UInt32 BlockSize; - UInt32 NumFrags; - UInt16 Method; - UInt16 BlockSizeLog; - UInt16 Flags; - UInt16 NumIDs; - UInt16 Major; - UInt16 Minor; - UInt64 RootInode; - UInt64 Size; - UInt64 UidTable; - UInt64 GidTable; - UInt64 XattrIdTable; - UInt64 InodeTable; - UInt64 DirTable; - UInt64 FragTable; - UInt64 LookupTable; - - void Parse3(const Byte *p) - { - Method = kMethod_ZLIB; - GET_32 (0x08, Size); - GET_32 (0x0C, UidTable); - GET_32 (0x10, GidTable); - GET_32 (0x14, InodeTable); - GET_32 (0x18, DirTable); - GET_16 (0x20, BlockSize); - GET_16 (0x22, BlockSizeLog); - Flags = p[0x24]; - NumUids = p[0x25]; - NumGids = p[0x26]; - GET_32 (0x27, CTime); - GET_64 (0x2B, RootInode); - NumFrags = 0; - FragTable = UidTable; - - if (Major >= 2) - { - GET_32 (0x33, BlockSize); - GET_32 (0x37, NumFrags); - GET_32 (0x3B, FragTable); - if (Major == 3) - { - GET_64 (0x3F, Size); - GET_64 (0x47, UidTable); - GET_64 (0x4F, GidTable); - GET_64 (0x57, InodeTable); - GET_64 (0x5F, DirTable); - GET_64 (0x67, FragTable); - GET_64 (0x6F, LookupTable); - } - } - } - - void Parse4(const Byte *p) - { - LE_32 (0x08, CTime); - LE_32 (0x0C, BlockSize); - LE_32 (0x10, NumFrags); - LE_16 (0x14, Method); - LE_16 (0x16, BlockSizeLog); - LE_16 (0x18, Flags); - LE_16 (0x1A, NumIDs); - LE_64 (0x20, RootInode); - LE_64 (0x28, Size); - LE_64 (0x30, UidTable); - LE_64 (0x38, XattrIdTable); - LE_64 (0x40, InodeTable); - LE_64 (0x48, DirTable); - LE_64 (0x50, FragTable); - LE_64 (0x58, LookupTable); - GidTable = 0; - } - - bool Parse(const Byte *p) - { - be = false; - SeveralMethods = false; - switch (GetUi32(p)) - { - case kSignature32_LE: break; - case kSignature32_BE: be = true; break; - case kSignature32_LZ: SeveralMethods = true; break; - case kSignature32_B2: SeveralMethods = true; be = true; break; - default: return false; - } - GET_32 (4, NumInodes); - GET_16 (0x1C, Major); - GET_16 (0x1E, Minor); - if (Major <= 3) - Parse3(p); - else - { - if (be) - return false; - Parse4(p); - } - return - InodeTable < DirTable && - DirTable <= FragTable && - FragTable <= Size && - UidTable <= Size && - BlockSizeLog >= 12 && - BlockSizeLog < 31 && - BlockSize == ((UInt32)1 << BlockSizeLog); - } - - bool IsSupported() const { return Major > 0 && Major <= 4 && BlockSizeLog <= 23; } - bool IsOldVersion() const { return Major < 4; } - bool NeedCheckData() const { return (Flags & (1 << kFlag_CHECK)) != 0; } - unsigned GetFileNameOffset() const { return Major <= 2 ? 3 : (Major == 3 ? 5 : 8); } - unsigned GetSymLinkOffset() const { return Major <= 1 ? 5: (Major <= 2 ? 6: (Major == 3 ? 18 : 24)); } - unsigned GetSpecGuidIndex() const { return Major <= 1 ? 0xF: 0xFF; } -}; - -static const UInt32 kFrag_Empty = (UInt32)(Int32)-1; -// static const UInt32 kXattr_Empty = (UInt32)(Int32)-1; - -struct CNode -{ - UInt16 Type; - UInt16 Mode; - UInt16 Uid; - UInt16 Gid; - UInt32 Frag; - UInt32 Offset; - // UInt32 MTime; - // UInt32 Number; - // UInt32 NumLinks; - // UInt32 RDev; - // UInt32 Xattr; - // UInt32 Parent; - - UInt64 FileSize; - UInt64 StartBlock; - // UInt64 Sparse; - - UInt32 Parse1(const Byte *p, UInt32 size, const CHeader &_h); - UInt32 Parse2(const Byte *p, UInt32 size, const CHeader &_h); - UInt32 Parse3(const Byte *p, UInt32 size, const CHeader &_h); - UInt32 Parse4(const Byte *p, UInt32 size, const CHeader &_h); - - bool IsDir() const { return (Type == kType_DIR || Type == kType_DIR + 7); } - bool IsLink() const { return (Type == kType_LNK || Type == kType_LNK + 7); } - UInt64 GetSize() const { return IsDir() ? 0 : FileSize; } - - bool ThereAreFrags() const { return Frag != kFrag_Empty; } - UInt64 GetNumBlocks(const CHeader &_h) const - { - return (FileSize >> _h.BlockSizeLog) + - (!ThereAreFrags() && (FileSize & (_h.BlockSize - 1)) != 0); - } -}; - -UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) -{ - const bool be = _h.be; - if (size < 4) - return 0; - { - const UInt32 t = Get16(p); - if (be) - { - Type = (UInt16)(t >> 12); - Mode = (UInt16)(t & 0xFFF); - Uid = (UInt16)(p[2] >> 4); - Gid = (UInt16)(p[2] & 0xF); - } - else - { - Type = (UInt16)(t & 0xF); - Mode = (UInt16)(t >> 4); - Uid = (UInt16)(p[2] & 0xF); - Gid = (UInt16)(p[2] >> 4); - } - } - - // Xattr = kXattr_Empty; - // MTime = 0; - FileSize = 0; - StartBlock = 0; - Frag = kFrag_Empty; - - if (Type == 0) - { - Byte t = p[3]; - if (be) - { - Type = (UInt16)(t >> 4); - Offset = (UInt16)(t & 0xF); - } - else - { - Type = (UInt16)(t & 0xF); - Offset = (UInt16)(t >> 4); - } - return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0; - } - - Type--; - Uid = (UInt16)(Uid + (Type / 5) * 16); - Type = (UInt16)((Type % 5) + 1); - - if (Type == kType_FILE) - { - if (size < 15) - return 0; - // GET_32 (3, MTime); - GET_32 (7, StartBlock); - UInt32 t; - GET_32 (11, t); - FileSize = t; - UInt32 numBlocks = t >> _h.BlockSizeLog; - if ((t & (_h.BlockSize - 1)) != 0) - numBlocks++; - UInt32 pos = numBlocks * 2 + 15; - return (pos <= size) ? pos : 0; - } - - if (Type == kType_DIR) - { - if (size < 14) - return 0; - UInt32 t = Get32(p + 3); - if (be) - { - FileSize = t >> 13; - Offset = t & 0x1FFF; - } - else - { - FileSize = t & 0x7FFFF; - Offset = t >> 19; - } - // GET_32 (7, MTime); - GET_32 (10, StartBlock); - if (be) - StartBlock &= 0xFFFFFF; - else - StartBlock >>= 8; - return 14; - } - - if (size < 5) - return 0; - - if (Type == kType_LNK) - { - UInt32 len; - GET_16 (3, len); - FileSize = len; - len += 5; - return (len <= size) ? len : 0; - } - - // GET_32 (3, RDev); - return 5; -} - -UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) -{ - const bool be = _h.be; - if (size < 4) - return 0; - { - const UInt32 t = Get16(p); - if (be) - { - Type = (UInt16)(t >> 12); - Mode = (UInt16)(t & 0xFFF); - } - else - { - Type = (UInt16)(t & 0xF); - Mode = (UInt16)(t >> 4); - } - } - - Uid = p[2]; - Gid = p[3]; - - // Xattr = kXattr_Empty; - - if (Type == kType_FILE) - { - if (size < 24) - return 0; - // GET_32 (4, MTime); - GET_32 (8, StartBlock); - GET_32 (12, Frag); - GET_32 (16, Offset); - UInt32 t; - GET_32 (20, t); - FileSize = t; - UInt32 numBlocks = t >> _h.BlockSizeLog; - if (!ThereAreFrags() && (t & (_h.BlockSize - 1)) != 0) - numBlocks++; - UInt32 pos = numBlocks * 4 + 24; - return (pos <= size) ? (UInt32)pos : 0; - } - - FileSize = 0; - // MTime = 0; - StartBlock = 0; - Frag = kFrag_Empty; - - if (Type == kType_DIR) - { - if (size < 15) - return 0; - UInt32 t = Get32(p + 4); - if (be) - { - FileSize = t >> 13; - Offset = t & 0x1FFF; - } - else - { - FileSize = t & 0x7FFFF; - Offset = t >> 19; - } - // GET_32 (8, MTime); - GET_32 (11, StartBlock); - if (be) - StartBlock &= 0xFFFFFF; - else - StartBlock >>= 8; - return 15; - } - - if (Type == kType_DIR + 7) - { - if (size < 18) - return 0; - UInt32 t = Get32(p + 4); - UInt32 t2 = Get16(p + 7); - if (be) - { - FileSize = t >> 5; - Offset = t2 & 0x1FFF; - } - else - { - FileSize = t & 0x7FFFFFF; - Offset = t2 >> 3; - } - // GET_32 (9, MTime); - GET_32 (12, StartBlock); - if (be) - StartBlock &= 0xFFFFFF; - else - StartBlock >>= 8; - UInt32 iCount; - GET_16 (16, iCount); - UInt32 pos = 18; - for (UInt32 i = 0; i < iCount; i++) - { - // 27 bits: index - // 29 bits: startBlock - if (pos + 8 > size) - return 0; - pos += 8 + (UInt32)p[pos + 7] + 1; // nameSize - if (pos > size) - return 0; - } - return pos; - } - - if (Type == kType_FIFO || Type == kType_SOCK) - return 4; - - if (size < 6) - return 0; - - if (Type == kType_LNK) - { - UInt32 len; - GET_16 (4, len); - FileSize = len; - len += 6; - return (len <= size) ? len : 0; - } - - if (Type == kType_BLK || Type == kType_CHR) - { - // GET_16 (4, RDev); - return 6; - } - - return 0; -} - -UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) -{ - const bool be = _h.be; - if (size < 12) - return 0; - - { - const UInt32 t = Get16(p); - if (be) - { - Type = (UInt16)(t >> 12); - Mode = (UInt16)(t & 0xFFF); - } - else - { - Type = (UInt16)(t & 0xF); - Mode = (UInt16)(t >> 4); - } - } - - Uid = p[2]; - Gid = p[3]; - // GET_32 (4, MTime); - // GET_32 (8, Number); - // Xattr = kXattr_Empty; - FileSize = 0; - StartBlock = 0; - - if (Type == kType_FILE || Type == kType_FILE + 7) - { - UInt32 offset; - if (Type == kType_FILE) - { - if (size < 32) - return 0; - GET_64 (12, StartBlock); - GET_32 (20, Frag); - GET_32 (24, Offset); - GET_32 (28, FileSize); - offset = 32; - } - else - { - if (size < 40) - return 0; - // GET_32 (12, NumLinks); - GET_64 (16, StartBlock); - GET_32 (24, Frag); - GET_32 (28, Offset); - GET_64 (32, FileSize); - offset = 40; - } - UInt64 pos = GetNumBlocks(_h) * 4 + offset; - return (pos <= size) ? (UInt32)pos : 0; - } - - if (size < 16) - return 0; - // GET_32 (12, NumLinks); - - if (Type == kType_DIR) - { - if (size < 28) - return 0; - UInt32 t = Get32(p + 16); - if (be) - { - FileSize = t >> 13; - Offset = t & 0x1FFF; - } - else - { - FileSize = t & 0x7FFFF; - Offset = t >> 19; - } - GET_32 (20, StartBlock); - // GET_32 (24, Parent); - return 28; - } - - if (Type == kType_DIR + 7) - { - if (size < 31) - return 0; - UInt32 t = Get32(p + 16); - UInt32 t2 = Get16(p + 19); - if (be) - { - FileSize = t >> 5; - Offset = t2 & 0x1FFF; - } - else - { - FileSize = t & 0x7FFFFFF; - Offset = t2 >> 3; - } - GET_32 (21, StartBlock); - UInt32 iCount; - GET_16 (25, iCount); - // GET_32 (27, Parent); - UInt32 pos = 31; - for (UInt32 i = 0; i < iCount; i++) - { - // UInt32 index - // UInt32 startBlock - if (pos + 9 > size) - return 0; - pos += 9 + (unsigned)p[pos + 8] + 1; // nameSize - if (pos > size) - return 0; - } - return pos; - } - - if (Type == kType_FIFO || Type == kType_SOCK) - return 16; - - if (size < 18) - return 0; - if (Type == kType_LNK) - { - UInt32 len; - GET_16 (16, len); - FileSize = len; - len += 18; - return (len <= size) ? len : 0; - } - - if (Type == kType_BLK || Type == kType_CHR) - { - // GET_16 (16, RDev); - return 18; - } - - return 0; -} - -UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h) -{ - if (size < 20) - return 0; - LE_16 (0, Type); - LE_16 (2, Mode); - LE_16 (4, Uid); - LE_16 (6, Gid); - // LE_32 (8, MTime); - // LE_32 (12, Number); - - // Xattr = kXattr_Empty; - FileSize = 0; - StartBlock = 0; - - if (Type == kType_FILE || Type == kType_FILE + 7) - { - UInt32 offset; - if (Type == kType_FILE) - { - if (size < 32) - return 0; - LE_32 (16, StartBlock); - LE_32 (20, Frag); - LE_32 (24, Offset); - LE_32 (28, FileSize); - offset = 32; - } - else - { - if (size < 56) - return 0; - LE_64 (16, StartBlock); - LE_64 (24, FileSize); - // LE_64 (32, Sparse); - // LE_32 (40, NumLinks); - LE_32 (44, Frag); - LE_32 (48, Offset); - // LE_32 (52, Xattr); - offset = 56; - } - UInt64 pos = GetNumBlocks(_h) * 4 + offset; - return (pos <= size) ? (UInt32)pos : 0; - } - - if (Type == kType_DIR) - { - if (size < 32) - return 0; - LE_32 (16, StartBlock); - // LE_32 (20, NumLinks); - LE_16 (24, FileSize); - LE_16 (26, Offset); - // LE_32 (28, Parent); - return 32; - } - - // LE_32 (16, NumLinks); - - if (Type == kType_DIR + 7) - { - if (size < 40) - return 0; - LE_32 (20, FileSize); - LE_32 (24, StartBlock); - // LE_32 (28, Parent); - UInt32 iCount; - LE_16 (32, iCount); - LE_16 (34, Offset); - // LE_32 (36, Xattr); - - UInt32 pos = 40; - for (UInt32 i = 0; i < iCount; i++) - { - // UInt32 index - // UInt32 startBlock - if (pos + 12 > size) - return 0; - UInt32 nameLen = GetUi32(p + pos + 8); - pos += 12 + nameLen + 1; - if (pos > size || nameLen > (1 << 10)) - return 0; - } - return pos; - } - - unsigned offset = 20; - switch (Type) - { - case kType_FIFO: case kType_FIFO + 7: - case kType_SOCK: case kType_SOCK + 7: - break; - case kType_LNK: case kType_LNK + 7: - { - if (size < 24) - return 0; - UInt32 len; - LE_32 (20, len); - FileSize = len; - offset = len + 24; - if (size < offset || len > (1 << 30)) - return 0; - break; - } - case kType_BLK: case kType_BLK + 7: - case kType_CHR: case kType_CHR + 7: - if (size < 24) - return 0; - // LE_32 (20, RDev); - offset = 24; - break; - default: - return 0; - } - - if (Type >= 8) - { - if (size < offset + 4) - return 0; - // LE_32 (offset, Xattr); - offset += 4; - } - return offset; -} - -struct CItem -{ - int Node; - int Parent; - UInt32 Ptr; - - CItem(): Node(-1), Parent(-1), Ptr(0) {} -}; - -struct CData -{ - CByteBuffer Data; - CRecordVector PackPos; - CRecordVector UnpackPos; // additional item at the end contains TotalUnpackSize - - UInt32 GetNumBlocks() const { return PackPos.Size(); } - void Clear() - { - Data.Free(); - PackPos.Clear(); - UnpackPos.Clear(); - } -}; - -struct CFrag -{ - UInt64 StartBlock; - UInt32 Size; -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - bool _noPropsLZMA; - bool _needCheckLzma; - - CRecordVector _items; - CRecordVector _nodes; - CRecordVector _nodesPos; - CRecordVector _blockToNode; - CData _inodesData; - CData _dirs; - CRecordVector _frags; - CByteBuffer _uids; - CByteBuffer _gids; - CHeader _h; - - UInt64 _sizeCalculated; - CMyComPtr _stream; - - IArchiveOpenCallback *_openCallback; - - UInt32 _openCodePage; - int _nodeIndex; - CRecordVector _blockCompressed; - CRecordVector _blockOffsets; - - CByteBuffer _cachedBlock; - UInt64 _cachedBlockStartPos; - UInt32 _cachedPackBlockSize; - UInt32 _cachedUnpackBlockSize; - - CMyComPtr2_Create _limitedInStream; - CMyComPtr2_Create _outStream; - CMyComPtr2_Create _dynOutStream; - - // CMyComPtr2 _lzmaDecoder; - CMyComPtr2 _zlibDecoder; - - CXzUnpacker _xz; - CZstdDecHandle _zstd; - - CByteBuffer _inputBuffer; - - void ClearCache() - { - _cachedBlockStartPos = 0; - _cachedPackBlockSize = 0; - _cachedUnpackBlockSize = 0; - } - - HRESULT Seek2(UInt64 offset) - { - return InStream_SeekSet(_stream, offset); - } - - HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, - UInt32 inSize, UInt32 outSizeMax); - HRESULT ReadMetadataBlock(UInt32 &packSize); - HRESULT ReadMetadataBlock2(); - HRESULT ReadData(CData &data, UInt64 start, UInt64 end); - - HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); - HRESULT ScanInodes(UInt64 ptr); - HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); - HRESULT Open2(IInStream *inStream); - AString GetPath(unsigned index) const; - bool GetPackSize(unsigned index, UInt64 &res, bool fillOffsets); - -public: - CHandler(); - ~CHandler() - { - XzUnpacker_Free(&_xz); - if (_zstd) - ZstdDec_Destroy(_zstd); - } - - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); -}; - - -CHandler::CHandler(): - _zstd(NULL) -{ - XzUnpacker_Construct(&_xz, &g_Alloc); -} - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidPosixAttrib, - kpidUserId, - kpidGroupId - // kpidLinks, - // kpidOffset -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidFileSystem, - kpidMethod, - kpidClusterSize, - kpidBigEndian, - kpidCTime, - kpidCharacts, - kpidCodePage - // kpidNumBlocks -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) -{ - SizeT destRem = *destLen; - SizeT srcRem = *srcLen; - *destLen = 0; - *srcLen = 0; - const Byte *destStart = dest; - const Byte *srcStart = src; - unsigned mode = 0; - - { - if (srcRem == 0) - return S_FALSE; - UInt32 b = *src; - if (b > 17) - { - src++; - srcRem--; - b -= 17; - mode = (b < 4 ? 1 : 4); - if (b > srcRem || b > destRem) - return S_FALSE; - srcRem -= b; - destRem -= b; - do - *dest++ = *src++; - while (--b); - } - } - - for (;;) - { - if (srcRem < 3) - return S_FALSE; - UInt32 b = *src++; - srcRem--; - UInt32 len, back; - - if (b >= 64) - { - srcRem--; - back = ((b >> 2) & 7) + ((UInt32)*src++ << 3); - len = (b >> 5) + 1; - } - else if (b < 16) - { - if (mode == 0) - { - if (b == 0) - { - for (b = 15;; b += 255) - { - if (srcRem == 0) - return S_FALSE; - UInt32 b2 = *src++; - srcRem--; - if (b2 != 0) - { - b += b2; - break; - } - } - } - - b += 3; - if (b > srcRem || b > destRem) - return S_FALSE; - srcRem -= b; - destRem -= b; - mode = 4; - do - *dest++ = *src++; - while (--b); - continue; - } - - srcRem--; - back = (b >> 2) + ((UInt32)*src++ << 2); - len = 2; - if (mode == 4) - { - back += (1 << 11); - len = 3; - } - } - else - { - UInt32 bOld = b; - b = (b < 32 ? 7 : 31); - len = bOld & b; - - if (len == 0) - { - for (len = b;; len += 255) - { - if (srcRem == 0) - return S_FALSE; - UInt32 b2 = *src++; - srcRem--; - if (b2 != 0) - { - len += b2; - break; - } - } - } - - len += 2; - if (srcRem < 2) - return S_FALSE; - b = *src; - back = (b >> 2) + ((UInt32)src[1] << 6); - src += 2; - srcRem -= 2; - if (bOld < 32) - { - back += ((bOld & 8) << 11); - if (back == 0) - { - *destLen = (size_t)(dest - destStart); - *srcLen = (size_t)(src - srcStart); - return S_OK; - } - back += (1 << 14) - 1; - } - } - - back++; - if (len > destRem || (size_t)(dest - destStart) < back) - return S_FALSE; - destRem -= len; - Byte *destTemp = dest - back; - dest += len; - - do - { - *(destTemp + back) = *destTemp; - destTemp++; - } - while (--len); - - b &= 3; - mode = b; - if (b == 0) - continue; - if (b > srcRem || b > destRem) - return S_FALSE; - srcRem -= b; - destRem -= b; - *dest++ = *src++; - if (b > 1) - { - *dest++ = *src++; - if (b > 2) - *dest++ = *src++; - } - } -} - -HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax) -{ - if (outBuf) - { - *outBufWasWritten = false; - *outBufWasWrittenSize = 0; - } - UInt32 method = _h.Method; - if (_h.SeveralMethods) - { - Byte b; - RINOK(ReadStream_FALSE(_stream, &b, 1)) - RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)) - method = (b == 0x5D ? kMethod_LZMA : kMethod_ZLIB); - } - - if (method == kMethod_ZLIB && _needCheckLzma) - { - Byte b; - RINOK(ReadStream_FALSE(_stream, &b, 1)) - RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)) - if (b == 0) - { - _noPropsLZMA = true; - method = _h.Method = kMethod_LZMA; - } - _needCheckLzma = false; - } - - if (method == kMethod_ZLIB) - { - _zlibDecoder.Create_if_Empty(); - RINOK(_zlibDecoder.Interface()->Code(_limitedInStream, outStream, NULL, NULL, NULL)) - if (inSize != _zlibDecoder->GetInputProcessedSize()) - return S_FALSE; - } - /* - else if (method == kMethod_LZMA) - { - _lzmaDecoder.Create_if_Empty(); - // _lzmaDecoder->FinishStream = true; - const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8; - Byte props[kPropsSize]; - UInt32 propsSize; - UInt64 outSize; - if (_noPropsLZMA) - { - props[0] = 0x5D; - SetUi32(&props[1], _h.BlockSize); - propsSize = 0; - outSize = outSizeMax; - } - else - { - RINOK(ReadStream_FALSE(_limitedInStream, props, kPropsSize)); - propsSize = kPropsSize; - outSize = GetUi64(&props[LZMA_PROPS_SIZE]); - if (outSize > outSizeMax) - return S_FALSE; - } - RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, LZMA_PROPS_SIZE)); - RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL)); - if (inSize != propsSize + _lzmaDecoderSpec->GetInputProcessedSize()) - return S_FALSE; - } - */ - else - { - if (_inputBuffer.Size() < inSize) - _inputBuffer.Alloc(inSize); - RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize)) - - Byte *dest = outBuf; - if (!outBuf) - { - dest = _dynOutStream->GetBufPtrForWriting(outSizeMax); - if (!dest) - return E_OUTOFMEMORY; - } - - SizeT destLen = outSizeMax, srcLen = inSize; - - if (method == kMethod_LZO) - { - RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen)) - } - else if (method == kMethod_LZMA) - { - Byte props[5]; - const Byte *src = _inputBuffer; - - if (_noPropsLZMA) - { - props[0] = 0x5D; - SetUi32(&props[1], _h.BlockSize) - } - else - { - const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8; - if (inSize < kPropsSize) - return S_FALSE; - memcpy(props, src, LZMA_PROPS_SIZE); - UInt64 outSize = GetUi64(src + LZMA_PROPS_SIZE); - if (outSize > outSizeMax) - return S_FALSE; - destLen = (SizeT)outSize; - src += kPropsSize; - inSize -= kPropsSize; - srcLen = inSize; - } - - ELzmaStatus status; - SRes res = LzmaDecode(dest, &destLen, - src, &srcLen, - props, LZMA_PROPS_SIZE, - LZMA_FINISH_END, - &status, &g_Alloc); - if (res != 0) - return SResToHRESULT(res); - if (status != LZMA_STATUS_FINISHED_WITH_MARK - && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - return S_FALSE; - } - else if (method == kMethod_ZSTD) - { - const Byte *src = _inputBuffer; - - if (!_zstd) - { - _zstd = ZstdDec_Create(&g_AlignedAlloc, &g_AlignedAlloc); - if (!_zstd) - return E_OUTOFMEMORY; - } - - CZstdDecState state; - ZstdDecState_Clear(&state); - - state.inBuf = src; - state.inLim = srcLen; // + 1; for debug - // state.outStep = outSizeMax; - - state.outBuf_fromCaller = dest; - state.outBufSize_fromCaller = outSizeMax; - // state.mustBeFinished = True; - - ZstdDec_Init(_zstd); - SRes sres; - for (;;) - { - sres = ZstdDec_Decode(_zstd, &state); - if (sres != SZ_OK) - break; - if (state.inLim == state.inPos - && (state.status == ZSTD_STATUS_NEEDS_MORE_INPUT || - state.status == ZSTD_STATUS_FINISHED_FRAME)) - break; - // sres = sres; - // break; // for debug - } - - CZstdDecResInfo info; - // ZstdDecInfo_Clear(&stat); - // stat->InSize = state.inPos; - ZstdDec_GetResInfo(_zstd, &state, sres, &info); - sres = info.decode_SRes; - if (sres == SZ_OK) - { - if (state.status != ZSTD_STATUS_FINISHED_FRAME - // ||stat.UnexpededEnd - || info.extraSize != 0 - || state.inLim != state.inPos) - sres = SZ_ERROR_DATA; - } - if (sres != SZ_OK) - return SResToHRESULT(sres); - if (state.winPos > outSizeMax) - return E_FAIL; - // memcpy(dest, state.dic, state.dicPos); - destLen = state.winPos; - } - else - { - ECoderStatus status; - const SRes res = XzUnpacker_CodeFull(&_xz, - dest, &destLen, - _inputBuffer, &srcLen, - CODER_FINISH_END, &status); - if (res != 0) - return SResToHRESULT(res); - if (status != CODER_STATUS_NEEDS_MORE_INPUT || !XzUnpacker_IsStreamWasFinished(&_xz)) - return S_FALSE; - } - - if (inSize != srcLen) - return S_FALSE; - if (outBuf) - { - *outBufWasWritten = true; - *outBufWasWrittenSize = (UInt32)destLen; - } - else - _dynOutStream->UpdateSize(destLen); - } - return S_OK; -} - -HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize) -{ - Byte temp[3]; - const unsigned offset = _h.NeedCheckData() ? 3 : 2; - if (offset > packSize) - return S_FALSE; - RINOK(ReadStream_FALSE(_stream, temp, offset)) - // if (NeedCheckData && Major < 4) checkByte must be = 0xFF - const bool be = _h.be; - UInt32 size = Get16(temp); - const bool isCompressed = ((size & kNotCompressedBit16) == 0); - if (size != kNotCompressedBit16) - size &= ~kNotCompressedBit16; - - if (size > kMetadataBlockSize || offset + size > packSize) - return S_FALSE; - packSize = offset + size; - if (isCompressed) - { - _limitedInStream->Init(size); - RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize)) - } - else - { - // size != 0 here - Byte *buf = _dynOutStream->GetBufPtrForWriting(size); - if (!buf) - return E_OUTOFMEMORY; - RINOK(ReadStream_FALSE(_stream, buf, size)) - _dynOutStream->UpdateSize(size); - } - return S_OK; -} - - -HRESULT CHandler::ReadMetadataBlock2() -{ - _dynOutStream->Init(); - UInt32 packSize = kMetadataBlockSize + 3; // check it - return ReadMetadataBlock(packSize); -} - -HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) -{ - if (end < start || end - start >= ((UInt64)1 << 32)) - return S_FALSE; - const UInt32 size = (UInt32)(end - start); - RINOK(Seek2(start)) - _dynOutStream->Init(); - UInt32 packPos = 0; - while (packPos != size) - { - data.PackPos.Add(packPos); - data.UnpackPos.Add((UInt32)_dynOutStream->GetSize()); - if (packPos > size) - return S_FALSE; - UInt32 packSize = size - packPos; - RINOK(ReadMetadataBlock(packSize)) - { - const size_t tSize = _dynOutStream->GetSize(); - if (tSize != (UInt32)tSize) - return S_FALSE; - } - packPos += packSize; - } - data.UnpackPos.Add((UInt32)_dynOutStream->GetSize()); - _dynOutStream->CopyToBuffer(data.Data); - return S_OK; -} - -struct CTempItem -{ - UInt32 StartBlock; - // UInt32 iNodeNumber1; - UInt32 Offset; - // UInt16 iNodeNumber2; - UInt16 Type; -}; - -HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex) -{ - if (level > kNumDirLevelsMax) - return S_FALSE; - - int blockIndex = _inodesData.PackPos.FindInSorted(startBlock); - if (blockIndex < 0) - return S_FALSE; - UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset; - if (unpackPos < offset) - return S_FALSE; - - nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]); - // nodeIndex = _nodesPos.FindInSorted(unpackPos); - if (nodeIndex < 0) - return S_FALSE; - - const CNode &n = _nodes[nodeIndex]; - if (!n.IsDir()) - return S_OK; - blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock); - if (blockIndex < 0) - return S_FALSE; - unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; - if (unpackPos < n.Offset || unpackPos > _dirs.Data.Size()) - return S_FALSE; - - UInt32 rem = (UInt32)_dirs.Data.Size() - unpackPos; - const Byte *p = _dirs.Data + unpackPos; - UInt32 fileSize = (UInt32)n.FileSize; - - // for some squashfs files: fileSize = rem + 3 !!! - if (_h.Major >= 3) - { - if (fileSize < 3) - return S_FALSE; - fileSize -= 3; - } - if (fileSize > rem) - return S_FALSE; - rem = fileSize; - - AString tempString; - - CRecordVector tempItems; - while (rem != 0) - { - const bool be = _h.be; - UInt32 count; - CTempItem tempItem; - if (_h.Major <= 2) - { - if (rem < 4) - return S_FALSE; - count = p[0]; - tempItem.StartBlock = Get32(p); - if (be) - tempItem.StartBlock &= 0xFFFFFF; - else - tempItem.StartBlock >>= 8; - p += 4; - rem -= 4; - } - else - { - if (_h.Major == 3) - { - if (rem < 9) - return S_FALSE; - count = p[0]; - p += 1; - rem -= 1; - } - else - { - if (rem < 12) - return S_FALSE; - count = GetUi32(p); - p += 4; - rem -= 4; - } - GET_32 (0, tempItem.StartBlock); - // GET_32 (4, tempItem.iNodeNumber1); - p += 8; - rem -= 8; - } - count++; - - for (UInt32 i = 0; i < count; i++) - { - if (rem == 0) - return S_FALSE; - - UInt32 nameOffset = _h.GetFileNameOffset(); - if (rem < nameOffset) - return S_FALSE; - - if (_items.Size() >= kNumFilesMax) - return S_FALSE; - if (_openCallback) - { - UInt64 numFiles = _items.Size(); - if ((numFiles & 0xFFFF) == 0) - { - RINOK(_openCallback->SetCompleted(&numFiles, NULL)) - } - } - - CItem item; - item.Ptr = (UInt32)(p - (const Byte *)_dirs.Data); - - UInt32 size; - if (_h.IsOldVersion()) - { - UInt32 t = Get16(p); - if (be) - { - tempItem.Offset = t >> 3; - tempItem.Type = (UInt16)(t & 0x7); - } - else - { - tempItem.Offset = t & 0x1FFF; - tempItem.Type = (UInt16)(t >> 13); - } - size = (UInt32)p[2]; - /* - if (_h.Major > 2) - tempItem.iNodeNumber2 = Get16(p + 3); - */ - } - else - { - GET_16 (0, tempItem.Offset); - // GET_16 (2, tempItem.iNodeNumber2); - GET_16 (4, tempItem.Type); - GET_16 (6, size); - } - p += nameOffset; - rem -= nameOffset; - size++; - if (rem < size) - return S_FALSE; - - if (_openCodePage == CP_UTF8) - { - tempString.SetFrom_CalcLen((const char *)p, size); - if (!CheckUTF8_AString(tempString)) - _openCodePage = CP_OEMCP; - } - - p += size; - rem -= size; - item.Parent = parent; - _items.Add(item); - tempItems.Add(tempItem); - } - } - - const unsigned startItemIndex = _items.Size() - tempItems.Size(); - FOR_VECTOR (i, tempItems) - { - const CTempItem &tempItem = tempItems[i]; - const unsigned index = startItemIndex + i; - CItem &item = _items[index]; - RINOK(OpenDir((int)index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node)) - } - - return S_OK; -} - -HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) -{ - const size_t size = (size_t)num * 4; - ids.Alloc(size); - if (num == 0) - return S_OK; - RINOK(Seek2(start)) - return ReadStream_FALSE(_stream, ids, size); -} - -HRESULT CHandler::Open2(IInStream *inStream) -{ - { - Byte buf[kHeaderSize3]; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3)) - if (!_h.Parse(buf)) - return S_FALSE; - if (!_h.IsSupported()) - return E_NOTIMPL; - - _noPropsLZMA = false; - _needCheckLzma = false; - switch (_h.Method) - { - case kMethod_ZLIB: _needCheckLzma = true; break; - case kMethod_LZMA: - case kMethod_LZO: - case kMethod_XZ: - case kMethod_ZSTD: - break; - default: - return E_NOTIMPL; - } - } - - _stream = inStream; - - if (_h.NumFrags != 0) - { - if (_h.NumFrags > kNumFilesMax) - return S_FALSE; - _frags.ClearAndReserve(_h.NumFrags); - const unsigned bigFrag = (_h.Major > 2); - - const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); - const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; - const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); - CByteBuffer data(numBlocksBytes); - RINOK(Seek2(_h.FragTable)) - RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)) - const bool be = _h.be; - - for (UInt32 i = 0; i < numBlocks; i++) - { - const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); - RINOK(Seek2(offset)) - RINOK(ReadMetadataBlock2()) - const UInt32 unpackSize = (UInt32)_dynOutStream->GetSize(); - if (unpackSize != kMetadataBlockSize) - if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) - return S_FALSE; - const Byte *buf = _dynOutStream->GetBuffer(); - for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) - { - CFrag frag; - if (bigFrag) - { - frag.StartBlock = Get64(buf + j); - frag.Size = Get32(buf + j + 8); - // some archives contain nonzero in unused (buf + j + 12) - j += 16; - } - else - { - frag.StartBlock = Get32(buf + j); - frag.Size = Get32(buf + j + 4); - j += 8; - } - _frags.Add(frag); - } - } - if ((UInt32)_frags.Size() != _h.NumFrags) - return S_FALSE; - } - - RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)) - RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)) - - UInt64 absOffset = _h.RootInode >> 16; - if (absOffset >= ((UInt64)1 << 32)) - return S_FALSE; - { - UInt32 pos = 0; - UInt32 totalSize = (UInt32)_inodesData.Data.Size(); - const unsigned kMinNodeParseSize = 4; - if (_h.NumInodes > totalSize / kMinNodeParseSize) - return S_FALSE; - _nodesPos.ClearAndReserve(_h.NumInodes); - _nodes.ClearAndReserve(_h.NumInodes); - // we use _blockToNode for binary search seed optimizations - _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1); - unsigned curBlock = 0; - for (UInt32 i = 0; i < _h.NumInodes; i++) - { - CNode n; - const Byte *p = _inodesData.Data + pos; - UInt32 size = totalSize - pos; - - switch (_h.Major) - { - case 1: size = n.Parse1(p, size, _h); break; - case 2: size = n.Parse2(p, size, _h); break; - case 3: size = n.Parse3(p, size, _h); break; - default: size = n.Parse4(p, size, _h); break; - } - if (size == 0) - return S_FALSE; - while (pos >= _inodesData.UnpackPos[curBlock]) - { - _blockToNode.Add(_nodesPos.Size()); - curBlock++; - } - _nodesPos.AddInReserved(pos); - _nodes.AddInReserved(n); - pos += size; - } - _blockToNode.Add(_nodesPos.Size()); - if (pos != totalSize) - return S_FALSE; - } - int rootNodeIndex; - RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex)) - - if (_h.Major < 4) - { - RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids)) - RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids)) - } - else - { - const UInt32 size = (UInt32)_h.NumIDs * 4; - _uids.Alloc(size); - - const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; - const UInt32 numBlocksBytes = numBlocks << 3; - CByteBuffer data(numBlocksBytes); - RINOK(Seek2(_h.UidTable)) - RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)) - - for (UInt32 i = 0; i < numBlocks; i++) - { - const UInt64 offset = GetUi64(data + i * 8); - RINOK(Seek2(offset)) - // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); - RINOK(ReadMetadataBlock2()) - const size_t unpackSize = _dynOutStream->GetSize(); - const UInt32 remSize = (i == numBlocks - 1) ? - (size & (kMetadataBlockSize - 1)) : kMetadataBlockSize; - if (unpackSize != remSize) - return S_FALSE; - memcpy(_uids + kMetadataBlockSize * i, _dynOutStream->GetBuffer(), remSize); - } - } - - { - const UInt32 alignSize = 1 << 12; - Byte buf[alignSize]; - RINOK(Seek2(_h.Size)) - UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); - _sizeCalculated = _h.Size; - if (rem != 0) - { - if (ReadStream_FALSE(_stream, buf, rem) == S_OK) - { - size_t i; - for (i = 0; i < rem && buf[i] == 0; i++); - if (i == rem) - _sizeCalculated = _h.Size + rem; - } - } - } - return S_OK; -} - -AString CHandler::GetPath(unsigned index) const -{ - unsigned len = 0; - const unsigned indexMem = index; - const bool be = _h.be; - for (;;) - { - const CItem &item = _items[index]; - const Byte *p = _dirs.Data + item.Ptr; - const unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; - p += _h.GetFileNameOffset(); - unsigned i; - for (i = 0; i < size && p[i]; i++); - len += i + 1; - index = (unsigned)item.Parent; - if (item.Parent < 0) - break; - } - len--; - - AString path; - char *dest = path.GetBuf_SetEnd(len) + len; - index = indexMem; - for (;;) - { - const CItem &item = _items[index]; - const Byte *p = _dirs.Data + item.Ptr; - const unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; - p += _h.GetFileNameOffset(); - unsigned i; - for (i = 0; i < size && p[i]; i++); - dest -= i; - memcpy(dest, p, i); - index = (unsigned)item.Parent; - if (item.Parent < 0) - break; - *(--dest) = CHAR_PATH_SEPARATOR; - } - return path; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - _limitedInStream->SetStream(stream); - HRESULT res; - try - { - _openCallback = callback; - res = Open2(stream); - } - catch(...) - { - Close(); - throw; - } - if (res != S_OK) - { - Close(); - return res; - } - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _openCodePage = CP_UTF8; - _sizeCalculated = 0; - - _limitedInStream->ReleaseStream(); - _stream.Release(); - - _items.Clear(); - _nodes.Clear(); - _nodesPos.Clear(); - _blockToNode.Clear(); - _frags.Clear(); - _inodesData.Clear(); - _dirs.Clear(); - - _uids.Free(); - _gids.Free(); - - _cachedBlock.Free(); - ClearCache(); - - return S_OK; -} - -bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack, bool fillOffsets) -{ - totalPack = 0; - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - const UInt32 ptr = _nodesPos[item.Node]; - const Byte *p = _inodesData.Data + ptr; - const bool be = _h.be; - - const UInt32 type = node.Type; - UInt32 offset; - if (node.IsLink() || node.FileSize == 0) - { - totalPack = node.FileSize; - return true; - } - - const UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h); - - if (fillOffsets) - { - _blockOffsets.Clear(); - _blockCompressed.Clear(); - _blockOffsets.Add(totalPack); - } - - if (_h.Major <= 1) - { - offset = 15; - p += offset; - - for (UInt32 i = 0; i < numBlocks; i++) - { - UInt32 t = Get16(p + i * 2); - if (fillOffsets) - _blockCompressed.Add((t & kNotCompressedBit16) == 0); - if (t != kNotCompressedBit16) - t &= ~kNotCompressedBit16; - totalPack += t; - if (fillOffsets) - _blockOffsets.Add(totalPack); - } - } - else - { - if (_h.Major <= 2) - offset = 24; - else if (type == kType_FILE) - offset = 32; - else if (type == kType_FILE + 7) - offset = (_h.Major <= 3 ? 40 : 56); - else - return false; - - p += offset; - - for (UInt64 i = 0; i < numBlocks; i++) - { - UInt32 t = Get32(p + i * 4); - if (fillOffsets) - _blockCompressed.Add(IS_COMPRESSED_BLOCK(t)); - UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t); - if (size > _h.BlockSize) - return false; - totalPack += size; - if (fillOffsets) - _blockOffsets.Add(totalPack); - } - - if (node.ThereAreFrags()) - { - if (node.Frag >= (UInt32)_frags.Size()) - return false; - const CFrag &frag = _frags[node.Frag]; - if (node.Offset == 0) - { - UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size); - if (size > _h.BlockSize) - return false; - totalPack += size; - } - } - } - return true; -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidMethod: - { - char sz[16]; - const char *s; - if (_noPropsLZMA) - s = "LZMA Spec"; - else if (_h.SeveralMethods) - s = "LZMA ZLIB"; - else - { - s = NULL; - if (_h.Method < Z7_ARRAY_SIZE(k_Methods)) - s = k_Methods[_h.Method]; - if (!s) - { - ConvertUInt32ToString(_h.Method, sz); - s = sz; - } - } - prop = s; - break; - } - case kpidFileSystem: - { - AString res ("SquashFS"); - if (_h.SeveralMethods) - res += "-LZMA"; - res.Add_Space(); - res.Add_UInt32(_h.Major); - res.Add_Dot(); - res.Add_UInt32(_h.Minor); - prop = res; - break; - } - case kpidClusterSize: prop = _h.BlockSize; break; - case kpidBigEndian: prop = _h.be; break; - case kpidCTime: - if (_h.CTime != 0) - PropVariant_SetFrom_UnixTime(prop, _h.CTime); - break; - case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; - // case kpidNumBlocks: prop = _h.NumFrags; break; - case kpidPhySize: prop = _sizeCalculated; break; - case kpidHeadersSize: - if (_sizeCalculated >= _h.InodeTable) - prop = _sizeCalculated - _h.InodeTable; - break; - - case kpidCodePage: - { - char sz[16]; - const char *name = NULL; - switch (_openCodePage) - { - case CP_OEMCP: name = "OEM"; break; - case CP_UTF8: name = "UTF-8"; break; - } - if (!name) - { - ConvertUInt32ToString(_openCodePage, sz); - name = sz; - } - prop = name; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - const bool isDir = node.IsDir(); - const bool be = _h.be; - - switch (propID) - { - case kpidPath: - { - AString path (GetPath(index)); - UString s; - if (_openCodePage == CP_UTF8) - ConvertUTF8ToUnicode(path, s); - else - MultiByteToUnicodeString2(s, path, _openCodePage); - prop = s; - break; - } - case kpidIsDir: prop = isDir; break; - // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break; - case kpidSize: if (!isDir) prop = node.GetSize(); break; - case kpidPackSize: - if (!isDir) - { - UInt64 size; - if (GetPackSize(index, size, false)) - prop = size; - } - break; - case kpidMTime: - { - UInt32 offset = 0; - switch (_h.Major) - { - case 1: - if (node.Type == kType_FILE) - offset = 3; - else if (node.Type == kType_DIR) - offset = 7; - break; - case 2: - if (node.Type == kType_FILE) - offset = 4; - else if (node.Type == kType_DIR) - offset = 8; - else if (node.Type == kType_DIR + 7) - offset = 9; - break; - case 3: offset = 4; break; - case 4: offset = 8; break; - } - if (offset != 0) - { - const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset; - PropVariant_SetFrom_UnixTime(prop, Get32(p)); - } - break; - } - case kpidPosixAttrib: - { - if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode)) - prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; - break; - } - case kpidUserId: - case kpidGroupId: - { - UInt32 id = node.Uid; - const CByteBuffer *ids = &_uids; - if (propID == kpidGroupId) - { - id = node.Gid; - if (_h.Major < 4) - { - if (id == _h.GetSpecGuidIndex()) - id = node.Uid; - else - ids = &_gids; - } - } - const UInt32 offset = (UInt32)id * 4; - if (offset < ids->Size()) - prop = (UInt32)Get32(*ids + offset); - break; - } - /* - case kpidLinks: - if (_h.Major >= 3 && node.Type != kType_FILE) - prop = node.NumLinks; - break; - */ - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CSquashfsInStream: public CCachedInStream -{ - HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override; -public: - CHandler *Handler; -}; - -HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - return Handler->ReadBlock(blockIndex, dest, blockSize); -} - -HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) -{ - const CNode &node = _nodes[_nodeIndex]; - UInt64 blockOffset; - UInt32 packBlockSize; - UInt32 offsetInBlock = 0; - bool compressed; - if (blockIndex < _blockCompressed.Size()) - { - compressed = _blockCompressed[(unsigned)blockIndex]; - blockOffset = _blockOffsets[(unsigned)blockIndex]; - packBlockSize = (UInt32)(_blockOffsets[(unsigned)blockIndex + 1] - blockOffset); - blockOffset += node.StartBlock; - } - else - { - if (!node.ThereAreFrags()) - return S_FALSE; - const CFrag &frag = _frags[node.Frag]; - offsetInBlock = node.Offset; - blockOffset = frag.StartBlock; - packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size); - compressed = IS_COMPRESSED_BLOCK(frag.Size); - } - - if (packBlockSize == 0) - { - // sparse file ??? - memset(dest, 0, blockSize); - return S_OK; - } - - if (blockOffset != _cachedBlockStartPos || - packBlockSize != _cachedPackBlockSize) - { - ClearCache(); - RINOK(Seek2(blockOffset)) - _limitedInStream->Init(packBlockSize); - - if (compressed) - { - _outStream->Init((Byte *)_cachedBlock, _h.BlockSize); - bool outBufWasWritten; - UInt32 outBufWasWrittenSize; - HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize); - RINOK(res) - if (outBufWasWritten) - _cachedUnpackBlockSize = outBufWasWrittenSize; - else - _cachedUnpackBlockSize = (UInt32)_outStream->GetPos(); - } - else - { - if (packBlockSize > _h.BlockSize) - return S_FALSE; - RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize)) - _cachedUnpackBlockSize = packBlockSize; - } - _cachedBlockStartPos = blockOffset; - _cachedPackBlockSize = packBlockSize; - } - if (offsetInBlock + blockSize > _cachedUnpackBlockSize) - return S_FALSE; - if (blockSize != 0) - memcpy(dest, _cachedBlock + offsetInBlock, blockSize); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItem &item = _items[allFilesMode ? i : indices[i]]; - const CNode &node = _nodes[item.Node]; - totalSize += node.GetSize(); - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create copyCoder; - - for (i = 0;; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - int res; - { - CMyComPtr outStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - // const Byte *p = _data + item.Offset; - - if (node.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - const UInt64 unpackSize = node.GetSize(); - totalSize += unpackSize; - UInt64 packSize; - if (GetPackSize(index, packSize, false)) - totalPackSize += packSize; - - if (!testMode && !outStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - res = NExtract::NOperationResult::kDataError; - { - CMyComPtr inSeqStream; - HRESULT hres = GetStream(index, &inSeqStream); - if (hres == S_FALSE || !inSeqStream) - { - if (hres == E_OUTOFMEMORY) - return hres; - res = NExtract::NOperationResult::kUnsupportedMethod; - } - else - { - RINOK(hres) - { - hres = copyCoder.Interface()->Code(inSeqStream, outStream, NULL, NULL, lps); - if (hres == S_OK) - { - if (copyCoder->TotalSize == unpackSize) - res = NExtract::NOperationResult::kOK; - } - else if (hres == E_NOTIMPL) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - } - else if (hres != S_FALSE) - { - RINOK(hres) - } - } - } - } - } - RINOK(extractCallback->SetOperationResult(res)) - } - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - - const CItem &item = _items[index]; - const CNode &node = _nodes[item.Node]; - - if (node.IsDir()) - return E_FAIL; - - const Byte *p = _inodesData.Data + _nodesPos[item.Node]; - - if (node.FileSize == 0 || node.IsLink()) - { - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr streamTemp = streamSpec; - if (node.IsLink()) - streamSpec->Init(p + _h.GetSymLinkOffset(), (size_t)node.FileSize); - else - streamSpec->Init(NULL, 0); - *stream = streamTemp.Detach(); - return S_OK; - } - - UInt64 packSize; - if (!GetPackSize(index, packSize, true)) - return S_FALSE; - - _nodeIndex = item.Node; - - size_t cacheSize = _h.BlockSize; - if (_cachedBlock.Size() != cacheSize) - { - ClearCache(); - _cachedBlock.Alloc(cacheSize); - } - - CSquashfsInStream *streamSpec = new CSquashfsInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Handler = this; - unsigned cacheSizeLog = 22; - if (cacheSizeLog <= _h.BlockSizeLog) - cacheSizeLog = _h.BlockSizeLog + 1; - if (!streamSpec->Alloc(_h.BlockSizeLog, cacheSizeLog - _h.BlockSizeLog)) - return E_OUTOFMEMORY; - streamSpec->Init(node.FileSize); - *stream = streamTemp.Detach(); - - return S_OK; - - COM_TRY_END -} - -static const Byte k_Signature[] = { - 4, 'h', 's', 'q', 's', - 4, 's', 'q', 's', 'h', - 4, 's', 'h', 's', 'q', - 4, 'q', 's', 'h', 's' }; - -REGISTER_ARC_I( - "SquashFS", "squashfs", NULL, 0xD2, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - NULL) - -}} +// SquashfsHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/LzmaDec.h" +#include "../../../C/Xz.h" +#include "../../../C/ZstdDec.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyLinux.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/CWrappers.h" +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/ZlibDecoder.h" +// #include "../Compress/LzmaDecoder.h" + +namespace NArchive { +namespace NSquashfs { + +static const UInt32 kNumFilesMax = 1 << 28; +static const unsigned kNumDirLevelsMax = 1 << 10; + +// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs + +/* +#define Get16(p) (be ? GetBe16(p) : GetUi16(p)) +#define Get32(p) (be ? GetBe32(p) : GetUi32(p)) +#define Get64(p) (be ? GetBe64(p) : GetUi64(p)) +*/ + +static UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); } +static UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); } +static UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); } + +#define Get16(p) Get16b(p, be) +#define Get32(p) Get32b(p, be) +#define Get64(p) Get64b(p, be) + +#define LE_16(offs, dest) dest = GetUi16(p + (offs)) +#define LE_32(offs, dest) dest = GetUi32(p + (offs)) +#define LE_64(offs, dest) dest = GetUi64(p + (offs)) + +#define GET_16(offs, dest) dest = Get16(p + (offs)) +#define GET_32(offs, dest) dest = Get32(p + (offs)) +#define GET_64(offs, dest) dest = Get64(p + (offs)) + +static const UInt32 kSignature32_LE = 0x73717368; +static const UInt32 kSignature32_BE = 0x68737173; +static const UInt32 kSignature32_LZ = 0x71736873; +static const UInt32 kSignature32_B2 = 0x73687371; + +#define kMethod_ZLIB 1 +#define kMethod_LZMA 2 +#define kMethod_LZO 3 +#define kMethod_XZ 4 +// #define kMethod_LZ4 5 +#define kMethod_ZSTD 6 + +static const char * const k_Methods[] = +{ + "0" + , "ZLIB" + , "LZMA" + , "LZO" + , "XZ" + , "LZ4" + , "ZSTD" +}; + +static const unsigned kMetadataBlockSizeLog = 13; +static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog); + +enum +{ + kType_IPC, + kType_DIR, + kType_FILE, + kType_LNK, + kType_BLK, + kType_CHR, + kType_FIFO, + kType_SOCK +}; + +static const UInt32 k_TypeToMode[] = +{ + 0, + MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK, + MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK +}; + + +enum +{ + kFlag_UNC_INODES, + kFlag_UNC_DATA, + kFlag_CHECK, + kFlag_UNC_FRAGS, + kFlag_NO_FRAGS, + kFlag_ALWAYS_FRAG, + kFlag_DUPLICATE, + kFlag_EXPORT +}; + +static const char * const k_Flags[] = +{ + "UNCOMPRESSED_INODES" + , "UNCOMPRESSED_DATA" + , "CHECK" + , "UNCOMPRESSED_FRAGMENTS" + , "NO_FRAGMENTS" + , "ALWAYS_FRAGMENTS" + , "DUPLICATES_REMOVED" + , "EXPORTABLE" + , "UNCOMPRESSED_XATTRS" + , "NO_XATTRS" + , "COMPRESSOR_OPTIONS" + , "UNCOMPRESSED_IDS" +}; + +static const UInt32 kNotCompressedBit16 = 1 << 15; +static const UInt32 kNotCompressedBit32 = 1 << 24; + +#define GET_COMPRESSED_BLOCK_SIZE(size) ((size) & ~kNotCompressedBit32) +#define IS_COMPRESSED_BLOCK(size) (((size) & kNotCompressedBit32) == 0) + +// static const UInt32 kHeaderSize1 = 0x33; +// static const UInt32 kHeaderSize2 = 0x3F; +static const UInt32 kHeaderSize3 = 0x77; +// static const UInt32 kHeaderSize4 = 0x60; + +struct CHeader +{ + bool be; + bool SeveralMethods; + Byte NumUids; + Byte NumGids; + + UInt32 NumInodes; + UInt32 CTime; + UInt32 BlockSize; + UInt32 NumFrags; + UInt16 Method; + UInt16 BlockSizeLog; + UInt16 Flags; + UInt16 NumIDs; + UInt16 Major; + UInt16 Minor; + UInt64 RootInode; + UInt64 Size; + UInt64 UidTable; + UInt64 GidTable; + UInt64 XattrIdTable; + UInt64 InodeTable; + UInt64 DirTable; + UInt64 FragTable; + UInt64 LookupTable; + + void Parse3(const Byte *p) + { + Method = kMethod_ZLIB; + GET_32 (0x08, Size); + GET_32 (0x0C, UidTable); + GET_32 (0x10, GidTable); + GET_32 (0x14, InodeTable); + GET_32 (0x18, DirTable); + GET_16 (0x20, BlockSize); + GET_16 (0x22, BlockSizeLog); + Flags = p[0x24]; + NumUids = p[0x25]; + NumGids = p[0x26]; + GET_32 (0x27, CTime); + GET_64 (0x2B, RootInode); + NumFrags = 0; + FragTable = UidTable; + + if (Major >= 2) + { + GET_32 (0x33, BlockSize); + GET_32 (0x37, NumFrags); + GET_32 (0x3B, FragTable); + if (Major == 3) + { + GET_64 (0x3F, Size); + GET_64 (0x47, UidTable); + GET_64 (0x4F, GidTable); + GET_64 (0x57, InodeTable); + GET_64 (0x5F, DirTable); + GET_64 (0x67, FragTable); + GET_64 (0x6F, LookupTable); + } + } + } + + void Parse4(const Byte *p) + { + LE_32 (0x08, CTime); + LE_32 (0x0C, BlockSize); + LE_32 (0x10, NumFrags); + LE_16 (0x14, Method); + LE_16 (0x16, BlockSizeLog); + LE_16 (0x18, Flags); + LE_16 (0x1A, NumIDs); + LE_64 (0x20, RootInode); + LE_64 (0x28, Size); + LE_64 (0x30, UidTable); + LE_64 (0x38, XattrIdTable); + LE_64 (0x40, InodeTable); + LE_64 (0x48, DirTable); + LE_64 (0x50, FragTable); + LE_64 (0x58, LookupTable); + GidTable = 0; + } + + bool Parse(const Byte *p) + { + be = false; + SeveralMethods = false; + switch (GetUi32(p)) + { + case kSignature32_LE: break; + case kSignature32_BE: be = true; break; + case kSignature32_LZ: SeveralMethods = true; break; + case kSignature32_B2: SeveralMethods = true; be = true; break; + default: return false; + } + GET_32 (4, NumInodes); + GET_16 (0x1C, Major); + GET_16 (0x1E, Minor); + if (Major <= 3) + Parse3(p); + else + { + if (be) + return false; + Parse4(p); + } + return + InodeTable < DirTable && + DirTable <= FragTable && + FragTable <= Size && + UidTable <= Size && + BlockSizeLog >= 12 && + BlockSizeLog < 31 && + BlockSize == ((UInt32)1 << BlockSizeLog); + } + + bool IsSupported() const { return Major > 0 && Major <= 4 && BlockSizeLog <= 23; } + bool IsOldVersion() const { return Major < 4; } + bool NeedCheckData() const { return (Flags & (1 << kFlag_CHECK)) != 0; } + unsigned GetFileNameOffset() const { return Major <= 2 ? 3 : (Major == 3 ? 5 : 8); } + unsigned GetSymLinkOffset() const { return Major <= 1 ? 5: (Major <= 2 ? 6: (Major == 3 ? 18 : 24)); } + unsigned GetSpecGuidIndex() const { return Major <= 1 ? 0xF: 0xFF; } +}; + +static const UInt32 kFrag_Empty = (UInt32)(Int32)-1; +// static const UInt32 kXattr_Empty = (UInt32)(Int32)-1; + +struct CNode +{ + UInt16 Type; + UInt16 Mode; + UInt16 Uid; + UInt16 Gid; + UInt32 Frag; + UInt32 Offset; + // UInt32 MTime; + // UInt32 Number; + // UInt32 NumLinks; + // UInt32 RDev; + // UInt32 Xattr; + // UInt32 Parent; + + UInt64 FileSize; + UInt64 StartBlock; + // UInt64 Sparse; + + UInt32 Parse1(const Byte *p, UInt32 size, const CHeader &_h); + UInt32 Parse2(const Byte *p, UInt32 size, const CHeader &_h); + UInt32 Parse3(const Byte *p, UInt32 size, const CHeader &_h); + UInt32 Parse4(const Byte *p, UInt32 size, const CHeader &_h); + + bool IsDir() const { return (Type == kType_DIR || Type == kType_DIR + 7); } + bool IsLink() const { return (Type == kType_LNK || Type == kType_LNK + 7); } + UInt64 GetSize() const { return IsDir() ? 0 : FileSize; } + + bool ThereAreFrags() const { return Frag != kFrag_Empty; } + UInt64 GetNumBlocks(const CHeader &_h) const + { + return (FileSize >> _h.BlockSizeLog) + + (!ThereAreFrags() && (FileSize & (_h.BlockSize - 1)) != 0); + } +}; + +UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h) +{ + const bool be = _h.be; + if (size < 4) + return 0; + { + const UInt32 t = Get16(p); + if (be) + { + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); + Uid = (UInt16)(p[2] >> 4); + Gid = (UInt16)(p[2] & 0xF); + } + else + { + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); + Uid = (UInt16)(p[2] & 0xF); + Gid = (UInt16)(p[2] >> 4); + } + } + + // Xattr = kXattr_Empty; + // MTime = 0; + FileSize = 0; + StartBlock = 0; + Frag = kFrag_Empty; + + if (Type == 0) + { + Byte t = p[3]; + if (be) + { + Type = (UInt16)(t >> 4); + Offset = (UInt16)(t & 0xF); + } + else + { + Type = (UInt16)(t & 0xF); + Offset = (UInt16)(t >> 4); + } + return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0; + } + + Type--; + Uid = (UInt16)(Uid + (Type / 5) * 16); + Type = (UInt16)((Type % 5) + 1); + + if (Type == kType_FILE) + { + if (size < 15) + return 0; + // GET_32 (3, MTime); + GET_32 (7, StartBlock); + UInt32 t; + GET_32 (11, t); + FileSize = t; + UInt32 numBlocks = t >> _h.BlockSizeLog; + if ((t & (_h.BlockSize - 1)) != 0) + numBlocks++; + UInt32 pos = numBlocks * 2 + 15; + return (pos <= size) ? pos : 0; + } + + if (Type == kType_DIR) + { + if (size < 14) + return 0; + UInt32 t = Get32(p + 3); + if (be) + { + FileSize = t >> 13; + Offset = t & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFF; + Offset = t >> 19; + } + // GET_32 (7, MTime); + GET_32 (10, StartBlock); + if (be) + StartBlock &= 0xFFFFFF; + else + StartBlock >>= 8; + return 14; + } + + if (size < 5) + return 0; + + if (Type == kType_LNK) + { + UInt32 len; + GET_16 (3, len); + FileSize = len; + len += 5; + return (len <= size) ? len : 0; + } + + // GET_32 (3, RDev); + return 5; +} + +UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) +{ + const bool be = _h.be; + if (size < 4) + return 0; + { + const UInt32 t = Get16(p); + if (be) + { + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); + } + else + { + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); + } + } + + Uid = p[2]; + Gid = p[3]; + + // Xattr = kXattr_Empty; + + if (Type == kType_FILE) + { + if (size < 24) + return 0; + // GET_32 (4, MTime); + GET_32 (8, StartBlock); + GET_32 (12, Frag); + GET_32 (16, Offset); + UInt32 t; + GET_32 (20, t); + FileSize = t; + UInt32 numBlocks = t >> _h.BlockSizeLog; + if (!ThereAreFrags() && (t & (_h.BlockSize - 1)) != 0) + numBlocks++; + UInt32 pos = numBlocks * 4 + 24; + return (pos <= size) ? (UInt32)pos : 0; + } + + FileSize = 0; + // MTime = 0; + StartBlock = 0; + Frag = kFrag_Empty; + + if (Type == kType_DIR) + { + if (size < 15) + return 0; + UInt32 t = Get32(p + 4); + if (be) + { + FileSize = t >> 13; + Offset = t & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFF; + Offset = t >> 19; + } + // GET_32 (8, MTime); + GET_32 (11, StartBlock); + if (be) + StartBlock &= 0xFFFFFF; + else + StartBlock >>= 8; + return 15; + } + + if (Type == kType_DIR + 7) + { + if (size < 18) + return 0; + UInt32 t = Get32(p + 4); + UInt32 t2 = Get16(p + 7); + if (be) + { + FileSize = t >> 5; + Offset = t2 & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFFFF; + Offset = t2 >> 3; + } + // GET_32 (9, MTime); + GET_32 (12, StartBlock); + if (be) + StartBlock &= 0xFFFFFF; + else + StartBlock >>= 8; + UInt32 iCount; + GET_16 (16, iCount); + UInt32 pos = 18; + for (UInt32 i = 0; i < iCount; i++) + { + // 27 bits: index + // 29 bits: startBlock + if (pos + 8 > size) + return 0; + pos += 8 + (UInt32)p[pos + 7] + 1; // nameSize + if (pos > size) + return 0; + } + return pos; + } + + if (Type == kType_FIFO || Type == kType_SOCK) + return 4; + + if (size < 6) + return 0; + + if (Type == kType_LNK) + { + UInt32 len; + GET_16 (4, len); + FileSize = len; + len += 6; + return (len <= size) ? len : 0; + } + + if (Type == kType_BLK || Type == kType_CHR) + { + // GET_16 (4, RDev); + return 6; + } + + return 0; +} + +UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) +{ + const bool be = _h.be; + if (size < 12) + return 0; + + { + const UInt32 t = Get16(p); + if (be) + { + Type = (UInt16)(t >> 12); + Mode = (UInt16)(t & 0xFFF); + } + else + { + Type = (UInt16)(t & 0xF); + Mode = (UInt16)(t >> 4); + } + } + + Uid = p[2]; + Gid = p[3]; + // GET_32 (4, MTime); + // GET_32 (8, Number); + // Xattr = kXattr_Empty; + FileSize = 0; + StartBlock = 0; + + if (Type == kType_FILE || Type == kType_FILE + 7) + { + UInt32 offset; + if (Type == kType_FILE) + { + if (size < 32) + return 0; + GET_64 (12, StartBlock); + GET_32 (20, Frag); + GET_32 (24, Offset); + GET_32 (28, FileSize); + offset = 32; + } + else + { + if (size < 40) + return 0; + // GET_32 (12, NumLinks); + GET_64 (16, StartBlock); + GET_32 (24, Frag); + GET_32 (28, Offset); + GET_64 (32, FileSize); + offset = 40; + } + UInt64 pos = GetNumBlocks(_h) * 4 + offset; + return (pos <= size) ? (UInt32)pos : 0; + } + + if (size < 16) + return 0; + // GET_32 (12, NumLinks); + + if (Type == kType_DIR) + { + if (size < 28) + return 0; + UInt32 t = Get32(p + 16); + if (be) + { + FileSize = t >> 13; + Offset = t & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFF; + Offset = t >> 19; + } + GET_32 (20, StartBlock); + // GET_32 (24, Parent); + return 28; + } + + if (Type == kType_DIR + 7) + { + if (size < 31) + return 0; + UInt32 t = Get32(p + 16); + UInt32 t2 = Get16(p + 19); + if (be) + { + FileSize = t >> 5; + Offset = t2 & 0x1FFF; + } + else + { + FileSize = t & 0x7FFFFFF; + Offset = t2 >> 3; + } + GET_32 (21, StartBlock); + UInt32 iCount; + GET_16 (25, iCount); + // GET_32 (27, Parent); + UInt32 pos = 31; + for (UInt32 i = 0; i < iCount; i++) + { + // UInt32 index + // UInt32 startBlock + if (pos + 9 > size) + return 0; + pos += 9 + (unsigned)p[pos + 8] + 1; // nameSize + if (pos > size) + return 0; + } + return pos; + } + + if (Type == kType_FIFO || Type == kType_SOCK) + return 16; + + if (size < 18) + return 0; + if (Type == kType_LNK) + { + UInt32 len; + GET_16 (16, len); + FileSize = len; + len += 18; + return (len <= size) ? len : 0; + } + + if (Type == kType_BLK || Type == kType_CHR) + { + // GET_16 (16, RDev); + return 18; + } + + return 0; +} + +UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h) +{ + if (size < 20) + return 0; + LE_16 (0, Type); + LE_16 (2, Mode); + LE_16 (4, Uid); + LE_16 (6, Gid); + // LE_32 (8, MTime); + // LE_32 (12, Number); + + // Xattr = kXattr_Empty; + FileSize = 0; + StartBlock = 0; + + if (Type == kType_FILE || Type == kType_FILE + 7) + { + UInt32 offset; + if (Type == kType_FILE) + { + if (size < 32) + return 0; + LE_32 (16, StartBlock); + LE_32 (20, Frag); + LE_32 (24, Offset); + LE_32 (28, FileSize); + offset = 32; + } + else + { + if (size < 56) + return 0; + LE_64 (16, StartBlock); + LE_64 (24, FileSize); + // LE_64 (32, Sparse); + // LE_32 (40, NumLinks); + LE_32 (44, Frag); + LE_32 (48, Offset); + // LE_32 (52, Xattr); + offset = 56; + } + UInt64 pos = GetNumBlocks(_h) * 4 + offset; + return (pos <= size) ? (UInt32)pos : 0; + } + + if (Type == kType_DIR) + { + if (size < 32) + return 0; + LE_32 (16, StartBlock); + // LE_32 (20, NumLinks); + LE_16 (24, FileSize); + LE_16 (26, Offset); + // LE_32 (28, Parent); + return 32; + } + + // LE_32 (16, NumLinks); + + if (Type == kType_DIR + 7) + { + if (size < 40) + return 0; + LE_32 (20, FileSize); + LE_32 (24, StartBlock); + // LE_32 (28, Parent); + UInt32 iCount; + LE_16 (32, iCount); + LE_16 (34, Offset); + // LE_32 (36, Xattr); + + UInt32 pos = 40; + for (UInt32 i = 0; i < iCount; i++) + { + // UInt32 index + // UInt32 startBlock + if (pos + 12 > size) + return 0; + UInt32 nameLen = GetUi32(p + pos + 8); + pos += 12 + nameLen + 1; + if (pos > size || nameLen > (1 << 10)) + return 0; + } + return pos; + } + + unsigned offset = 20; + switch (Type) + { + case kType_FIFO: case kType_FIFO + 7: + case kType_SOCK: case kType_SOCK + 7: + break; + case kType_LNK: case kType_LNK + 7: + { + if (size < 24) + return 0; + UInt32 len; + LE_32 (20, len); + FileSize = len; + offset = len + 24; + if (size < offset || len > (1 << 30)) + return 0; + break; + } + case kType_BLK: case kType_BLK + 7: + case kType_CHR: case kType_CHR + 7: + if (size < 24) + return 0; + // LE_32 (20, RDev); + offset = 24; + break; + default: + return 0; + } + + if (Type >= 8) + { + if (size < offset + 4) + return 0; + // LE_32 (offset, Xattr); + offset += 4; + } + return offset; +} + +struct CItem +{ + int Node; + int Parent; + UInt32 Ptr; + + CItem(): Node(-1), Parent(-1), Ptr(0) {} +}; + +struct CData +{ + CByteBuffer Data; + CRecordVector PackPos; + CRecordVector UnpackPos; // additional item at the end contains TotalUnpackSize + + UInt32 GetNumBlocks() const { return PackPos.Size(); } + void Clear() + { + Data.Free(); + PackPos.Clear(); + UnpackPos.Clear(); + } +}; + +struct CFrag +{ + UInt64 StartBlock; + UInt32 Size; +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + bool _noPropsLZMA; + bool _needCheckLzma; + + CRecordVector _items; + CRecordVector _nodes; + CRecordVector _nodesPos; + CRecordVector _blockToNode; + CData _inodesData; + CData _dirs; + CRecordVector _frags; + CByteBuffer _uids; + CByteBuffer _gids; + CHeader _h; + + UInt64 _sizeCalculated; + CMyComPtr _stream; + + IArchiveOpenCallback *_openCallback; + + UInt32 _openCodePage; + int _nodeIndex; + CRecordVector _blockCompressed; + CRecordVector _blockOffsets; + + CByteBuffer _cachedBlock; + UInt64 _cachedBlockStartPos; + UInt32 _cachedPackBlockSize; + UInt32 _cachedUnpackBlockSize; + + CMyComPtr2_Create _limitedInStream; + CMyComPtr2_Create _outStream; + CMyComPtr2_Create _dynOutStream; + + // CMyComPtr2 _lzmaDecoder; + CMyComPtr2 _zlibDecoder; + + CXzUnpacker _xz; + CZstdDecHandle _zstd; + + CByteBuffer _inputBuffer; + + void ClearCache() + { + _cachedBlockStartPos = 0; + _cachedPackBlockSize = 0; + _cachedUnpackBlockSize = 0; + } + + HRESULT Seek2(UInt64 offset) + { + return InStream_SeekSet(_stream, offset); + } + + HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, + UInt32 inSize, UInt32 outSizeMax); + HRESULT ReadMetadataBlock(UInt32 &packSize); + HRESULT ReadMetadataBlock2(); + HRESULT ReadData(CData &data, UInt64 start, UInt64 end); + + HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); + HRESULT ScanInodes(UInt64 ptr); + HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); + HRESULT Open2(IInStream *inStream); + AString GetPath(unsigned index) const; + bool GetPackSize(unsigned index, UInt64 &res, bool fillOffsets); + +public: + CHandler(); + ~CHandler() + { + XzUnpacker_Free(&_xz); + if (_zstd) + ZstdDec_Destroy(_zstd); + } + + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize); +}; + + +CHandler::CHandler(): + _zstd(NULL) +{ + XzUnpacker_Construct(&_xz, &g_Alloc); +} + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidPosixAttrib, + kpidUserId, + kpidGroupId + // kpidLinks, + // kpidOffset +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidFileSystem, + kpidMethod, + kpidClusterSize, + kpidBigEndian, + kpidCTime, + kpidCharacts, + kpidCodePage + // kpidNumBlocks +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen) +{ + SizeT destRem = *destLen; + SizeT srcRem = *srcLen; + *destLen = 0; + *srcLen = 0; + const Byte *destStart = dest; + const Byte *srcStart = src; + unsigned mode = 0; + + { + if (srcRem == 0) + return S_FALSE; + UInt32 b = *src; + if (b > 17) + { + src++; + srcRem--; + b -= 17; + mode = (b < 4 ? 1 : 4); + if (b > srcRem || b > destRem) + return S_FALSE; + srcRem -= b; + destRem -= b; + do + *dest++ = *src++; + while (--b); + } + } + + for (;;) + { + if (srcRem < 3) + return S_FALSE; + UInt32 b = *src++; + srcRem--; + UInt32 len, back; + + if (b >= 64) + { + srcRem--; + back = ((b >> 2) & 7) + ((UInt32)*src++ << 3); + len = (b >> 5) + 1; + } + else if (b < 16) + { + if (mode == 0) + { + if (b == 0) + { + for (b = 15;; b += 255) + { + if (srcRem == 0) + return S_FALSE; + UInt32 b2 = *src++; + srcRem--; + if (b2 != 0) + { + b += b2; + break; + } + } + } + + b += 3; + if (b > srcRem || b > destRem) + return S_FALSE; + srcRem -= b; + destRem -= b; + mode = 4; + do + *dest++ = *src++; + while (--b); + continue; + } + + srcRem--; + back = (b >> 2) + ((UInt32)*src++ << 2); + len = 2; + if (mode == 4) + { + back += (1 << 11); + len = 3; + } + } + else + { + UInt32 bOld = b; + b = (b < 32 ? 7 : 31); + len = bOld & b; + + if (len == 0) + { + for (len = b;; len += 255) + { + if (srcRem == 0) + return S_FALSE; + UInt32 b2 = *src++; + srcRem--; + if (b2 != 0) + { + len += b2; + break; + } + } + } + + len += 2; + if (srcRem < 2) + return S_FALSE; + b = *src; + back = (b >> 2) + ((UInt32)src[1] << 6); + src += 2; + srcRem -= 2; + if (bOld < 32) + { + back += ((bOld & 8) << 11); + if (back == 0) + { + *destLen = (size_t)(dest - destStart); + *srcLen = (size_t)(src - srcStart); + return S_OK; + } + back += (1 << 14) - 1; + } + } + + back++; + if (len > destRem || (size_t)(dest - destStart) < back) + return S_FALSE; + destRem -= len; + Byte *destTemp = dest - back; + dest += len; + + do + { + *(destTemp + back) = *destTemp; + destTemp++; + } + while (--len); + + b &= 3; + mode = b; + if (b == 0) + continue; + if (b > srcRem || b > destRem) + return S_FALSE; + srcRem -= b; + destRem -= b; + *dest++ = *src++; + if (b > 1) + { + *dest++ = *src++; + if (b > 2) + *dest++ = *src++; + } + } +} + +HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax) +{ + if (outBuf) + { + *outBufWasWritten = false; + *outBufWasWrittenSize = 0; + } + UInt32 method = _h.Method; + if (_h.SeveralMethods) + { + Byte b; + RINOK(ReadStream_FALSE(_stream, &b, 1)) + RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)) + method = (b == 0x5D ? kMethod_LZMA : kMethod_ZLIB); + } + + if (method == kMethod_ZLIB && _needCheckLzma) + { + Byte b; + RINOK(ReadStream_FALSE(_stream, &b, 1)) + RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL)) + if (b == 0) + { + _noPropsLZMA = true; + method = _h.Method = kMethod_LZMA; + } + _needCheckLzma = false; + } + + if (method == kMethod_ZLIB) + { + _zlibDecoder.Create_if_Empty(); + RINOK(_zlibDecoder.Interface()->Code(_limitedInStream, outStream, NULL, NULL, NULL)) + if (inSize != _zlibDecoder->GetInputProcessedSize()) + return S_FALSE; + } + /* + else if (method == kMethod_LZMA) + { + _lzmaDecoder.Create_if_Empty(); + // _lzmaDecoder->FinishStream = true; + const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8; + Byte props[kPropsSize]; + UInt32 propsSize; + UInt64 outSize; + if (_noPropsLZMA) + { + props[0] = 0x5D; + SetUi32(&props[1], _h.BlockSize); + propsSize = 0; + outSize = outSizeMax; + } + else + { + RINOK(ReadStream_FALSE(_limitedInStream, props, kPropsSize)); + propsSize = kPropsSize; + outSize = GetUi64(&props[LZMA_PROPS_SIZE]); + if (outSize > outSizeMax) + return S_FALSE; + } + RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, LZMA_PROPS_SIZE)); + RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL)); + if (inSize != propsSize + _lzmaDecoderSpec->GetInputProcessedSize()) + return S_FALSE; + } + */ + else + { + if (_inputBuffer.Size() < inSize) + _inputBuffer.Alloc(inSize); + RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize)) + + Byte *dest = outBuf; + if (!outBuf) + { + dest = _dynOutStream->GetBufPtrForWriting(outSizeMax); + if (!dest) + return E_OUTOFMEMORY; + } + + SizeT destLen = outSizeMax, srcLen = inSize; + + if (method == kMethod_LZO) + { + RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen)) + } + else if (method == kMethod_LZMA) + { + Byte props[5]; + const Byte *src = _inputBuffer; + + if (_noPropsLZMA) + { + props[0] = 0x5D; + SetUi32(&props[1], _h.BlockSize) + } + else + { + const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8; + if (inSize < kPropsSize) + return S_FALSE; + memcpy(props, src, LZMA_PROPS_SIZE); + UInt64 outSize = GetUi64(src + LZMA_PROPS_SIZE); + if (outSize > outSizeMax) + return S_FALSE; + destLen = (SizeT)outSize; + src += kPropsSize; + inSize -= kPropsSize; + srcLen = inSize; + } + + ELzmaStatus status; + SRes res = LzmaDecode(dest, &destLen, + src, &srcLen, + props, LZMA_PROPS_SIZE, + LZMA_FINISH_END, + &status, &g_Alloc); + if (res != 0) + return SResToHRESULT(res); + if (status != LZMA_STATUS_FINISHED_WITH_MARK + && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + return S_FALSE; + } + else if (method == kMethod_ZSTD) + { + const Byte *src = _inputBuffer; + + if (!_zstd) + { + _zstd = ZstdDec_Create(&g_AlignedAlloc, &g_AlignedAlloc); + if (!_zstd) + return E_OUTOFMEMORY; + } + + CZstdDecState state; + ZstdDecState_Clear(&state); + + state.inBuf = src; + state.inLim = srcLen; // + 1; for debug + // state.outStep = outSizeMax; + + state.outBuf_fromCaller = dest; + state.outBufSize_fromCaller = outSizeMax; + // state.mustBeFinished = True; + + ZstdDec_Init(_zstd); + SRes sres; + for (;;) + { + sres = ZstdDec_Decode(_zstd, &state); + if (sres != SZ_OK) + break; + if (state.inLim == state.inPos + && (state.status == ZSTD_STATUS_NEEDS_MORE_INPUT || + state.status == ZSTD_STATUS_FINISHED_FRAME)) + break; + // sres = sres; + // break; // for debug + } + + CZstdDecResInfo info; + // ZstdDecInfo_Clear(&stat); + // stat->InSize = state.inPos; + ZstdDec_GetResInfo(_zstd, &state, sres, &info); + sres = info.decode_SRes; + if (sres == SZ_OK) + { + if (state.status != ZSTD_STATUS_FINISHED_FRAME + // ||stat.UnexpededEnd + || info.extraSize != 0 + || state.inLim != state.inPos) + sres = SZ_ERROR_DATA; + } + if (sres != SZ_OK) + return SResToHRESULT(sres); + if (state.winPos > outSizeMax) + return E_FAIL; + // memcpy(dest, state.dic, state.dicPos); + destLen = state.winPos; + } + else + { + ECoderStatus status; + const SRes res = XzUnpacker_CodeFull(&_xz, + dest, &destLen, + _inputBuffer, &srcLen, + CODER_FINISH_END, &status); + if (res != 0) + return SResToHRESULT(res); + if (status != CODER_STATUS_NEEDS_MORE_INPUT || !XzUnpacker_IsStreamWasFinished(&_xz)) + return S_FALSE; + } + + if (inSize != srcLen) + return S_FALSE; + if (outBuf) + { + *outBufWasWritten = true; + *outBufWasWrittenSize = (UInt32)destLen; + } + else + _dynOutStream->UpdateSize(destLen); + } + return S_OK; +} + +HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize) +{ + Byte temp[3]; + const unsigned offset = _h.NeedCheckData() ? 3 : 2; + if (offset > packSize) + return S_FALSE; + RINOK(ReadStream_FALSE(_stream, temp, offset)) + // if (NeedCheckData && Major < 4) checkByte must be = 0xFF + const bool be = _h.be; + UInt32 size = Get16(temp); + const bool isCompressed = ((size & kNotCompressedBit16) == 0); + if (size != kNotCompressedBit16) + size &= ~kNotCompressedBit16; + + if (size > kMetadataBlockSize || offset + size > packSize) + return S_FALSE; + packSize = offset + size; + if (isCompressed) + { + _limitedInStream->Init(size); + RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize)) + } + else + { + // size != 0 here + Byte *buf = _dynOutStream->GetBufPtrForWriting(size); + if (!buf) + return E_OUTOFMEMORY; + RINOK(ReadStream_FALSE(_stream, buf, size)) + _dynOutStream->UpdateSize(size); + } + return S_OK; +} + + +HRESULT CHandler::ReadMetadataBlock2() +{ + _dynOutStream->Init(); + UInt32 packSize = kMetadataBlockSize + 3; // check it + return ReadMetadataBlock(packSize); +} + +HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) +{ + if (end < start || end - start >= ((UInt64)1 << 32)) + return S_FALSE; + const UInt32 size = (UInt32)(end - start); + RINOK(Seek2(start)) + _dynOutStream->Init(); + UInt32 packPos = 0; + while (packPos != size) + { + data.PackPos.Add(packPos); + data.UnpackPos.Add((UInt32)_dynOutStream->GetSize()); + if (packPos > size) + return S_FALSE; + UInt32 packSize = size - packPos; + RINOK(ReadMetadataBlock(packSize)) + { + const size_t tSize = _dynOutStream->GetSize(); + if (tSize != (UInt32)tSize) + return S_FALSE; + } + packPos += packSize; + } + data.UnpackPos.Add((UInt32)_dynOutStream->GetSize()); + _dynOutStream->CopyToBuffer(data.Data); + return S_OK; +} + +struct CTempItem +{ + UInt32 StartBlock; + // UInt32 iNodeNumber1; + UInt32 Offset; + // UInt16 iNodeNumber2; + UInt16 Type; +}; + +HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex) +{ + if (level > kNumDirLevelsMax) + return S_FALSE; + + int blockIndex = _inodesData.PackPos.FindInSorted(startBlock); + if (blockIndex < 0) + return S_FALSE; + UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset; + if (unpackPos < offset) + return S_FALSE; + + nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]); + // nodeIndex = _nodesPos.FindInSorted(unpackPos); + if (nodeIndex < 0) + return S_FALSE; + + const CNode &n = _nodes[nodeIndex]; + if (!n.IsDir()) + return S_OK; + blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock); + if (blockIndex < 0) + return S_FALSE; + unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset; + if (unpackPos < n.Offset || unpackPos > _dirs.Data.Size()) + return S_FALSE; + + UInt32 rem = (UInt32)_dirs.Data.Size() - unpackPos; + const Byte *p = _dirs.Data + unpackPos; + UInt32 fileSize = (UInt32)n.FileSize; + + // for some squashfs files: fileSize = rem + 3 !!! + if (_h.Major >= 3) + { + if (fileSize < 3) + return S_FALSE; + fileSize -= 3; + } + if (fileSize > rem) + return S_FALSE; + rem = fileSize; + + AString tempString; + + CRecordVector tempItems; + while (rem != 0) + { + const bool be = _h.be; + UInt32 count; + CTempItem tempItem; + if (_h.Major <= 2) + { + if (rem < 4) + return S_FALSE; + count = p[0]; + tempItem.StartBlock = Get32(p); + if (be) + tempItem.StartBlock &= 0xFFFFFF; + else + tempItem.StartBlock >>= 8; + p += 4; + rem -= 4; + } + else + { + if (_h.Major == 3) + { + if (rem < 9) + return S_FALSE; + count = p[0]; + p += 1; + rem -= 1; + } + else + { + if (rem < 12) + return S_FALSE; + count = GetUi32(p); + p += 4; + rem -= 4; + } + GET_32 (0, tempItem.StartBlock); + // GET_32 (4, tempItem.iNodeNumber1); + p += 8; + rem -= 8; + } + count++; + + for (UInt32 i = 0; i < count; i++) + { + if (rem == 0) + return S_FALSE; + + UInt32 nameOffset = _h.GetFileNameOffset(); + if (rem < nameOffset) + return S_FALSE; + + if (_items.Size() >= kNumFilesMax) + return S_FALSE; + if (_openCallback) + { + UInt64 numFiles = _items.Size(); + if ((numFiles & 0xFFFF) == 0) + { + RINOK(_openCallback->SetCompleted(&numFiles, NULL)) + } + } + + CItem item; + item.Ptr = (UInt32)(p - (const Byte *)_dirs.Data); + + UInt32 size; + if (_h.IsOldVersion()) + { + UInt32 t = Get16(p); + if (be) + { + tempItem.Offset = t >> 3; + tempItem.Type = (UInt16)(t & 0x7); + } + else + { + tempItem.Offset = t & 0x1FFF; + tempItem.Type = (UInt16)(t >> 13); + } + size = (UInt32)p[2]; + /* + if (_h.Major > 2) + tempItem.iNodeNumber2 = Get16(p + 3); + */ + } + else + { + GET_16 (0, tempItem.Offset); + // GET_16 (2, tempItem.iNodeNumber2); + GET_16 (4, tempItem.Type); + GET_16 (6, size); + } + p += nameOffset; + rem -= nameOffset; + size++; + if (rem < size) + return S_FALSE; + + if (_openCodePage == CP_UTF8) + { + tempString.SetFrom_CalcLen((const char *)p, size); + if (!CheckUTF8_AString(tempString)) + _openCodePage = CP_OEMCP; + } + + p += size; + rem -= size; + item.Parent = parent; + _items.Add(item); + tempItems.Add(tempItem); + } + } + + const unsigned startItemIndex = _items.Size() - tempItems.Size(); + FOR_VECTOR (i, tempItems) + { + const CTempItem &tempItem = tempItems[i]; + const unsigned index = startItemIndex + i; + CItem &item = _items[index]; + RINOK(OpenDir((int)index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node)) + } + + return S_OK; +} + +HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) +{ + const size_t size = (size_t)num * 4; + ids.Alloc(size); + if (num == 0) + return S_OK; + RINOK(Seek2(start)) + return ReadStream_FALSE(_stream, ids, size); +} + +HRESULT CHandler::Open2(IInStream *inStream) +{ + { + Byte buf[kHeaderSize3]; + RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3)) + if (!_h.Parse(buf)) + return S_FALSE; + if (!_h.IsSupported()) + return E_NOTIMPL; + + _noPropsLZMA = false; + _needCheckLzma = false; + switch (_h.Method) + { + case kMethod_ZLIB: _needCheckLzma = true; break; + case kMethod_LZMA: + case kMethod_LZO: + case kMethod_XZ: + case kMethod_ZSTD: + break; + default: + return E_NOTIMPL; + } + } + + _stream = inStream; + + if (_h.NumFrags != 0) + { + if (_h.NumFrags > kNumFilesMax) + return S_FALSE; + _frags.ClearAndReserve(_h.NumFrags); + const unsigned bigFrag = (_h.Major > 2); + + const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); + const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; + const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); + CByteBuffer data(numBlocksBytes); + RINOK(Seek2(_h.FragTable)) + RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)) + const bool be = _h.be; + + for (UInt32 i = 0; i < numBlocks; i++) + { + const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); + RINOK(Seek2(offset)) + RINOK(ReadMetadataBlock2()) + const UInt32 unpackSize = (UInt32)_dynOutStream->GetSize(); + if (unpackSize != kMetadataBlockSize) + if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) + return S_FALSE; + const Byte *buf = _dynOutStream->GetBuffer(); + for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) + { + CFrag frag; + if (bigFrag) + { + frag.StartBlock = Get64(buf + j); + frag.Size = Get32(buf + j + 8); + // some archives contain nonzero in unused (buf + j + 12) + j += 16; + } + else + { + frag.StartBlock = Get32(buf + j); + frag.Size = Get32(buf + j + 4); + j += 8; + } + _frags.Add(frag); + } + } + if ((UInt32)_frags.Size() != _h.NumFrags) + return S_FALSE; + } + + RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)) + RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)) + + UInt64 absOffset = _h.RootInode >> 16; + if (absOffset >= ((UInt64)1 << 32)) + return S_FALSE; + { + UInt32 pos = 0; + UInt32 totalSize = (UInt32)_inodesData.Data.Size(); + const unsigned kMinNodeParseSize = 4; + if (_h.NumInodes > totalSize / kMinNodeParseSize) + return S_FALSE; + _nodesPos.ClearAndReserve(_h.NumInodes); + _nodes.ClearAndReserve(_h.NumInodes); + // we use _blockToNode for binary search seed optimizations + _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1); + unsigned curBlock = 0; + for (UInt32 i = 0; i < _h.NumInodes; i++) + { + CNode n; + const Byte *p = _inodesData.Data + pos; + UInt32 size = totalSize - pos; + + switch (_h.Major) + { + case 1: size = n.Parse1(p, size, _h); break; + case 2: size = n.Parse2(p, size, _h); break; + case 3: size = n.Parse3(p, size, _h); break; + default: size = n.Parse4(p, size, _h); break; + } + if (size == 0) + return S_FALSE; + while (pos >= _inodesData.UnpackPos[curBlock]) + { + _blockToNode.Add(_nodesPos.Size()); + curBlock++; + } + _nodesPos.AddInReserved(pos); + _nodes.AddInReserved(n); + pos += size; + } + _blockToNode.Add(_nodesPos.Size()); + if (pos != totalSize) + return S_FALSE; + } + int rootNodeIndex; + RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex)) + + if (_h.Major < 4) + { + RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids)) + RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids)) + } + else + { + const UInt32 size = (UInt32)_h.NumIDs * 4; + _uids.Alloc(size); + + const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; + const UInt32 numBlocksBytes = numBlocks << 3; + CByteBuffer data(numBlocksBytes); + RINOK(Seek2(_h.UidTable)) + RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)) + + for (UInt32 i = 0; i < numBlocks; i++) + { + const UInt64 offset = GetUi64(data + i * 8); + RINOK(Seek2(offset)) + // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); + RINOK(ReadMetadataBlock2()) + const size_t unpackSize = _dynOutStream->GetSize(); + const UInt32 remSize = (i == numBlocks - 1) ? + (size & (kMetadataBlockSize - 1)) : kMetadataBlockSize; + if (unpackSize != remSize) + return S_FALSE; + memcpy(_uids + kMetadataBlockSize * i, _dynOutStream->GetBuffer(), remSize); + } + } + + { + const UInt32 alignSize = 1 << 12; + Byte buf[alignSize]; + RINOK(Seek2(_h.Size)) + UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); + _sizeCalculated = _h.Size; + if (rem != 0) + { + if (ReadStream_FALSE(_stream, buf, rem) == S_OK) + { + size_t i; + for (i = 0; i < rem && buf[i] == 0; i++); + if (i == rem) + _sizeCalculated = _h.Size + rem; + } + } + } + return S_OK; +} + +AString CHandler::GetPath(unsigned index) const +{ + unsigned len = 0; + const unsigned indexMem = index; + const bool be = _h.be; + for (;;) + { + const CItem &item = _items[index]; + const Byte *p = _dirs.Data + item.Ptr; + const unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; + p += _h.GetFileNameOffset(); + unsigned i; + for (i = 0; i < size && p[i]; i++); + len += i + 1; + index = (unsigned)item.Parent; + if (item.Parent < 0) + break; + } + len--; + + AString path; + char *dest = path.GetBuf_SetEnd(len) + len; + index = indexMem; + for (;;) + { + const CItem &item = _items[index]; + const Byte *p = _dirs.Data + item.Ptr; + const unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1; + p += _h.GetFileNameOffset(); + unsigned i; + for (i = 0; i < size && p[i]; i++); + dest -= i; + memcpy(dest, p, i); + index = (unsigned)item.Parent; + if (item.Parent < 0) + break; + *(--dest) = CHAR_PATH_SEPARATOR; + } + return path; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + _limitedInStream->SetStream(stream); + HRESULT res; + try + { + _openCallback = callback; + res = Open2(stream); + } + catch(...) + { + Close(); + throw; + } + if (res != S_OK) + { + Close(); + return res; + } + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _openCodePage = CP_UTF8; + _sizeCalculated = 0; + + _limitedInStream->ReleaseStream(); + _stream.Release(); + + _items.Clear(); + _nodes.Clear(); + _nodesPos.Clear(); + _blockToNode.Clear(); + _frags.Clear(); + _inodesData.Clear(); + _dirs.Clear(); + + _uids.Free(); + _gids.Free(); + + _cachedBlock.Free(); + ClearCache(); + + return S_OK; +} + +bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack, bool fillOffsets) +{ + totalPack = 0; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + const UInt32 ptr = _nodesPos[item.Node]; + const Byte *p = _inodesData.Data + ptr; + const bool be = _h.be; + + const UInt32 type = node.Type; + UInt32 offset; + if (node.IsLink() || node.FileSize == 0) + { + totalPack = node.FileSize; + return true; + } + + const UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h); + + if (fillOffsets) + { + _blockOffsets.Clear(); + _blockCompressed.Clear(); + _blockOffsets.Add(totalPack); + } + + if (_h.Major <= 1) + { + offset = 15; + p += offset; + + for (UInt32 i = 0; i < numBlocks; i++) + { + UInt32 t = Get16(p + i * 2); + if (fillOffsets) + _blockCompressed.Add((t & kNotCompressedBit16) == 0); + if (t != kNotCompressedBit16) + t &= ~kNotCompressedBit16; + totalPack += t; + if (fillOffsets) + _blockOffsets.Add(totalPack); + } + } + else + { + if (_h.Major <= 2) + offset = 24; + else if (type == kType_FILE) + offset = 32; + else if (type == kType_FILE + 7) + offset = (_h.Major <= 3 ? 40 : 56); + else + return false; + + p += offset; + + for (UInt64 i = 0; i < numBlocks; i++) + { + UInt32 t = Get32(p + i * 4); + if (fillOffsets) + _blockCompressed.Add(IS_COMPRESSED_BLOCK(t)); + UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t); + if (size > _h.BlockSize) + return false; + totalPack += size; + if (fillOffsets) + _blockOffsets.Add(totalPack); + } + + if (node.ThereAreFrags()) + { + if (node.Frag >= (UInt32)_frags.Size()) + return false; + const CFrag &frag = _frags[node.Frag]; + if (node.Offset == 0) + { + UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size); + if (size > _h.BlockSize) + return false; + totalPack += size; + } + } + } + return true; +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidMethod: + { + char sz[16]; + const char *s; + if (_noPropsLZMA) + s = "LZMA Spec"; + else if (_h.SeveralMethods) + s = "LZMA ZLIB"; + else + { + s = NULL; + if (_h.Method < Z7_ARRAY_SIZE(k_Methods)) + s = k_Methods[_h.Method]; + if (!s) + { + ConvertUInt32ToString(_h.Method, sz); + s = sz; + } + } + prop = s; + break; + } + case kpidFileSystem: + { + AString res ("SquashFS"); + if (_h.SeveralMethods) + res += "-LZMA"; + res.Add_Space(); + res.Add_UInt32(_h.Major); + res.Add_Dot(); + res.Add_UInt32(_h.Minor); + prop = res; + break; + } + case kpidClusterSize: prop = _h.BlockSize; break; + case kpidBigEndian: prop = _h.be; break; + case kpidCTime: + if (_h.CTime != 0) + PropVariant_SetFrom_UnixTime(prop, _h.CTime); + break; + case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; + // case kpidNumBlocks: prop = _h.NumFrags; break; + case kpidPhySize: prop = _sizeCalculated; break; + case kpidHeadersSize: + if (_sizeCalculated >= _h.InodeTable) + prop = _sizeCalculated - _h.InodeTable; + break; + + case kpidCodePage: + { + char sz[16]; + const char *name = NULL; + switch (_openCodePage) + { + case CP_OEMCP: name = "OEM"; break; + case CP_UTF8: name = "UTF-8"; break; + } + if (!name) + { + ConvertUInt32ToString(_openCodePage, sz); + name = sz; + } + prop = name; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + const bool isDir = node.IsDir(); + const bool be = _h.be; + + switch (propID) + { + case kpidPath: + { + AString path (GetPath(index)); + UString s; + if (_openCodePage == CP_UTF8) + ConvertUTF8ToUnicode(path, s); + else + MultiByteToUnicodeString2(s, path, _openCodePage); + prop = s; + break; + } + case kpidIsDir: prop = isDir; break; + // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break; + case kpidSize: if (!isDir) prop = node.GetSize(); break; + case kpidPackSize: + if (!isDir) + { + UInt64 size; + if (GetPackSize(index, size, false)) + prop = size; + } + break; + case kpidMTime: + { + UInt32 offset = 0; + switch (_h.Major) + { + case 1: + if (node.Type == kType_FILE) + offset = 3; + else if (node.Type == kType_DIR) + offset = 7; + break; + case 2: + if (node.Type == kType_FILE) + offset = 4; + else if (node.Type == kType_DIR) + offset = 8; + else if (node.Type == kType_DIR + 7) + offset = 9; + break; + case 3: offset = 4; break; + case 4: offset = 8; break; + } + if (offset != 0) + { + const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset; + PropVariant_SetFrom_UnixTime(prop, Get32(p)); + } + break; + } + case kpidPosixAttrib: + { + if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode)) + prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; + break; + } + case kpidUserId: + case kpidGroupId: + { + UInt32 id = node.Uid; + const CByteBuffer *ids = &_uids; + if (propID == kpidGroupId) + { + id = node.Gid; + if (_h.Major < 4) + { + if (id == _h.GetSpecGuidIndex()) + id = node.Uid; + else + ids = &_gids; + } + } + const UInt32 offset = (UInt32)id * 4; + if (offset < ids->Size()) + prop = (UInt32)Get32(*ids + offset); + break; + } + /* + case kpidLinks: + if (_h.Major >= 3 && node.Type != kType_FILE) + prop = node.NumLinks; + break; + */ + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CSquashfsInStream: public CCachedInStream +{ + HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override; +public: + CHandler *Handler; +}; + +HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + return Handler->ReadBlock(blockIndex, dest, blockSize); +} + +HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) +{ + const CNode &node = _nodes[_nodeIndex]; + UInt64 blockOffset; + UInt32 packBlockSize; + UInt32 offsetInBlock = 0; + bool compressed; + if (blockIndex < _blockCompressed.Size()) + { + compressed = _blockCompressed[(unsigned)blockIndex]; + blockOffset = _blockOffsets[(unsigned)blockIndex]; + packBlockSize = (UInt32)(_blockOffsets[(unsigned)blockIndex + 1] - blockOffset); + blockOffset += node.StartBlock; + } + else + { + if (!node.ThereAreFrags()) + return S_FALSE; + const CFrag &frag = _frags[node.Frag]; + offsetInBlock = node.Offset; + blockOffset = frag.StartBlock; + packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size); + compressed = IS_COMPRESSED_BLOCK(frag.Size); + } + + if (packBlockSize == 0) + { + // sparse file ??? + memset(dest, 0, blockSize); + return S_OK; + } + + if (blockOffset != _cachedBlockStartPos || + packBlockSize != _cachedPackBlockSize) + { + ClearCache(); + RINOK(Seek2(blockOffset)) + _limitedInStream->Init(packBlockSize); + + if (compressed) + { + _outStream->Init((Byte *)_cachedBlock, _h.BlockSize); + bool outBufWasWritten; + UInt32 outBufWasWrittenSize; + HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize); + RINOK(res) + if (outBufWasWritten) + _cachedUnpackBlockSize = outBufWasWrittenSize; + else + _cachedUnpackBlockSize = (UInt32)_outStream->GetPos(); + } + else + { + if (packBlockSize > _h.BlockSize) + return S_FALSE; + RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize)) + _cachedUnpackBlockSize = packBlockSize; + } + _cachedBlockStartPos = blockOffset; + _cachedPackBlockSize = packBlockSize; + } + if (offsetInBlock + blockSize > _cachedUnpackBlockSize) + return S_FALSE; + if (blockSize != 0) + memcpy(dest, _cachedBlock + offsetInBlock, blockSize); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItem &item = _items[allFilesMode ? i : indices[i]]; + const CNode &node = _nodes[item.Node]; + totalSize += node.GetSize(); + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create copyCoder; + + for (i = 0;; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + int res; + { + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + // const Byte *p = _data + item.Offset; + + if (node.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + const UInt64 unpackSize = node.GetSize(); + totalSize += unpackSize; + UInt64 packSize; + if (GetPackSize(index, packSize, false)) + totalPackSize += packSize; + + if (!testMode && !outStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + res = NExtract::NOperationResult::kDataError; + { + CMyComPtr inSeqStream; + HRESULT hres = GetStream(index, &inSeqStream); + if (hres == S_FALSE || !inSeqStream) + { + if (hres == E_OUTOFMEMORY) + return hres; + res = NExtract::NOperationResult::kUnsupportedMethod; + } + else + { + RINOK(hres) + { + hres = copyCoder.Interface()->Code(inSeqStream, outStream, NULL, NULL, lps); + if (hres == S_OK) + { + if (copyCoder->TotalSize == unpackSize) + res = NExtract::NOperationResult::kOK; + } + else if (hres == E_NOTIMPL) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + } + else if (hres != S_FALSE) + { + RINOK(hres) + } + } + } + } + } + RINOK(extractCallback->SetOperationResult(res)) + } + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + + const CItem &item = _items[index]; + const CNode &node = _nodes[item.Node]; + + if (node.IsDir()) + return E_FAIL; + + const Byte *p = _inodesData.Data + _nodesPos[item.Node]; + + if (node.FileSize == 0 || node.IsLink()) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + if (node.IsLink()) + streamSpec->Init(p + _h.GetSymLinkOffset(), (size_t)node.FileSize); + else + streamSpec->Init(NULL, 0); + *stream = streamTemp.Detach(); + return S_OK; + } + + UInt64 packSize; + if (!GetPackSize(index, packSize, true)) + return S_FALSE; + + _nodeIndex = item.Node; + + size_t cacheSize = _h.BlockSize; + if (_cachedBlock.Size() != cacheSize) + { + ClearCache(); + _cachedBlock.Alloc(cacheSize); + } + + CSquashfsInStream *streamSpec = new CSquashfsInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Handler = this; + unsigned cacheSizeLog = 22; + if (cacheSizeLog <= _h.BlockSizeLog) + cacheSizeLog = _h.BlockSizeLog + 1; + if (!streamSpec->Alloc(_h.BlockSizeLog, cacheSizeLog - _h.BlockSizeLog)) + return E_OUTOFMEMORY; + streamSpec->Init(node.FileSize); + *stream = streamTemp.Detach(); + + return S_OK; + + COM_TRY_END +} + +static const Byte k_Signature[] = { + 4, 'h', 's', 'q', 's', + 4, 's', 'q', 's', 'h', + 4, 's', 'h', 's', 'q', + 4, 'q', 's', 'h', 's' }; + +REGISTER_ARC_I( + "SquashFS", "squashfs", NULL, 0xD2, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + NULL) + +}} diff --git a/CPP/7zip/Archive/StdAfx.h b/CPP/7zip/Archive/StdAfx.h index aa6fe0328..80866550d 100644 --- a/CPP/7zip/Archive/StdAfx.h +++ b/CPP/7zip/Archive/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index 5bc3c9434..b143d9a9b 100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -1,994 +1,994 @@ -// SwfHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/MyString.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/InBuffer.h" -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/LzmaDecoder.h" -#include "../Compress/ZlibDecoder.h" - -#include "Common/DummyOutStream.h" - -// #define Z7_SWF_UPDATE - -#ifdef Z7_SWF_UPDATE - -#include "../Compress/LzmaEncoder.h" -#include "../Compress/ZlibEncoder.h" - -#include "Common/HandlerOut.h" - -#endif - -using namespace NWindows; - -namespace NArchive { - -static const UInt32 kFileSizeMax = (UInt32)1 << 29; - -namespace NSwfc { - -static const unsigned kHeaderBaseSize = 8; -static const unsigned kHeaderLzmaSize = 17; - -static const Byte SWF_UNCOMPRESSED = 'F'; -static const Byte SWF_COMPRESSED_ZLIB = 'C'; -static const Byte SWF_COMPRESSED_LZMA = 'Z'; - -static const Byte SWF_MIN_COMPRESSED_ZLIB_VER = 6; -static const Byte SWF_MIN_COMPRESSED_LZMA_VER = 13; - -static const Byte kVerLim = 64; - -API_FUNC_static_IsArc IsArc_Swf(const Byte *p, size_t size) -{ - if (size < kHeaderBaseSize) - return k_IsArc_Res_NEED_MORE; - if (p[0] != SWF_UNCOMPRESSED || - p[1] != 'W' || - p[2] != 'S' || - p[3] >= kVerLim) - return k_IsArc_Res_NO; - UInt32 uncompressedSize = GetUi32(p + 4); - if (uncompressedSize > kFileSizeMax) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -API_FUNC_static_IsArc IsArc_Swfc(const Byte *p, size_t size) -{ - if (size < kHeaderBaseSize + 2 + 1) // 2 + 1 (for zlib check) - return k_IsArc_Res_NEED_MORE; - if ((p[0] != SWF_COMPRESSED_ZLIB && - p[0] != SWF_COMPRESSED_LZMA) || - p[1] != 'W' || - p[2] != 'S' || - p[3] >= kVerLim) - return k_IsArc_Res_NO; - UInt32 uncompressedSize = GetUi32(p + 4); - if (uncompressedSize > kFileSizeMax) - return k_IsArc_Res_NO; - - if (p[0] == SWF_COMPRESSED_ZLIB) - { - if (!NCompress::NZlib::IsZlib_3bytes(p + 8)) - return k_IsArc_Res_NO; - } - else - { - if (size < kHeaderLzmaSize + 2) - return k_IsArc_Res_NEED_MORE; - if (p[kHeaderLzmaSize] != 0 || - (p[kHeaderLzmaSize + 1] & 0x80) != 0) - return k_IsArc_Res_NO; - UInt32 lzmaPackSize = GetUi32(p + 8); - UInt32 lzmaProp = p[12]; - UInt32 lzmaDicSize = GetUi32(p + 13); - if (lzmaProp > 5 * 5 * 9 || - lzmaDicSize > ((UInt32)1 << 28) || - lzmaPackSize < 5 || - lzmaPackSize > ((UInt32)1 << 28)) - return k_IsArc_Res_NO; - } - - return k_IsArc_Res_YES; -} -} - -struct CItem -{ - Byte Buf[kHeaderLzmaSize]; - unsigned HeaderSize; - - UInt32 GetSize() const { return GetUi32(Buf + 4); } - UInt32 GetLzmaPackSize() const { return GetUi32(Buf + 8); } - UInt32 GetLzmaDicSize() const { return GetUi32(Buf + 13); } - - bool IsSwf() const { return (Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < kVerLim); } - bool IsUncompressed() const { return Buf[0] == SWF_UNCOMPRESSED; } - bool IsZlib() const { return Buf[0] == SWF_COMPRESSED_ZLIB; } - bool IsLzma() const { return Buf[0] == SWF_COMPRESSED_LZMA; } - - void MakeUncompressed() - { - Buf[0] = SWF_UNCOMPRESSED; - HeaderSize = kHeaderBaseSize; - } - void MakeZlib() - { - Buf[0] = SWF_COMPRESSED_ZLIB; - if (Buf[3] < SWF_MIN_COMPRESSED_ZLIB_VER) - Buf[3] = SWF_MIN_COMPRESSED_ZLIB_VER; - } - void MakeLzma(UInt32 packSize) - { - Buf[0] = SWF_COMPRESSED_LZMA; - if (Buf[3] < SWF_MIN_COMPRESSED_LZMA_VER) - Buf[3] = SWF_MIN_COMPRESSED_LZMA_VER; - SetUi32(Buf + 8, packSize) - HeaderSize = kHeaderLzmaSize; - } - - HRESULT ReadHeader(ISequentialInStream *stream) - { - HeaderSize = kHeaderBaseSize; - return ReadStream_FALSE(stream, Buf, kHeaderBaseSize); - } - HRESULT WriteHeader(ISequentialOutStream *stream) - { - return WriteStream(stream, Buf, HeaderSize); - } -}; - - -Z7_class_CHandler_final: - public IInArchive, - public IArchiveOpenSeq, - #ifdef Z7_SWF_UPDATE - public IOutArchive, - public ISetProperties, - #endif - public CMyUnknownImp -{ - #ifdef Z7_SWF_UPDATE - Z7_IFACES_IMP_UNK_4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) - #else - Z7_IFACES_IMP_UNK_2(IInArchive, IArchiveOpenSeq) - #endif - - CItem _item; - UInt64 _packSize; - bool _packSizeDefined; - CMyComPtr _seqStream; - CMyComPtr _stream; - -#ifdef Z7_SWF_UPDATE - CSingleMethodProps _props; - bool _lzmaMode; -#endif - -public: - #ifdef Z7_SWF_UPDATE - CHandler(): _lzmaMode(false) {} - #endif -}; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, - kpidMethod -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; - case kpidIsNotArcType: prop = true; break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -static void DicSizeToString(char *s, UInt32 val) -{ - char c = 0; - unsigned i; - for (i = 0; i < 32; i++) - if (((UInt32)1 << i) == val) - { - val = i; - break; - } - if (i == 32) - { - c = 'b'; - if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } - else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } - } - ::ConvertUInt32ToString(val, s); - unsigned pos = MyStringLen(s); - s[pos++] = c; - s[pos] = 0; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidSize: prop = (UInt64)_item.GetSize(); break; - case kpidPackSize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; - case kpidMethod: - { - char s[32]; - if (_item.IsZlib()) - MyStringCopy(s, "zlib"); - else - { - MyStringCopy(s, "LZMA:"); - DicSizeToString(s + 5, _item.GetLzmaDicSize()); - } - prop = s; - break; - } - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) -{ - RINOK(OpenSeq(stream)) - _stream = stream; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - Close(); - RINOK(_item.ReadHeader(stream)) - if (!_item.IsSwf()) - return S_FALSE; - if (_item.IsLzma()) - { - RINOK(ReadStream_FALSE(stream, _item.Buf + kHeaderBaseSize, kHeaderLzmaSize - kHeaderBaseSize)) - _item.HeaderSize = kHeaderLzmaSize; - _packSize = _item.GetLzmaPackSize(); - _packSizeDefined = true; - } - else if (!_item.IsZlib()) - return S_FALSE; - if (_item.GetSize() < _item.HeaderSize) - return S_FALSE; - _seqStream = stream; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _packSize = 0; - _packSizeDefined = false; - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -Z7_CLASS_IMP_COM_1( - CCompressProgressInfoImp, - ICompressProgressInfo -) - CMyComPtr Callback; -public: - UInt64 Offset; - void Init(IArchiveOpenCallback *callback) { Callback = callback; } -}; - -Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) -{ - if (Callback) - { - const UInt64 files = 0; - const UInt64 value = Offset + *inSize; - return Callback->SetCompleted(&files, &value); - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - RINOK(extractCallback->SetTotal(_item.GetSize())) - Int32 opRes; -{ - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(); - // realOutStream.Release(); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - lps->InSize = _item.HeaderSize; - lps->OutSize = outStream->GetSize(); - RINOK(lps->SetCur()) - - CItem item = _item; - item.MakeUncompressed(); - if (_stream) - RINOK(InStream_SeekSet(_stream, _item.HeaderSize)) - NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL; - NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL; - CMyComPtr _decoder; - - CMyComPtr inStream2; - - const UInt64 unpackSize = _item.GetSize() - (UInt32)8; - if (_item.IsZlib()) - { - _decoderZlibSpec = new NCompress::NZlib::CDecoder; - _decoder = _decoderZlibSpec; - inStream2 = _seqStream; - } - else - { - /* Some .swf files with lzma contain additional 8 bytes at the end - in uncompressed stream. - What does that data mean ??? - We don't decompress these additional 8 bytes */ - - // unpackSize = _item.GetSize(); - // SetUi32(item.Buf + 4, (UInt32)(unpackSize + 8)); - CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; - inStream2 = limitedStreamSpec; - limitedStreamSpec->SetStream(_seqStream); - limitedStreamSpec->Init(_item.GetLzmaPackSize()); - - _decoderLzmaSpec = new NCompress::NLzma::CDecoder; - _decoder = _decoderLzmaSpec; - // _decoderLzmaSpec->FinishStream = true; - - Byte props[5]; - memcpy(props, _item.Buf + 12, 5); - UInt32 dicSize = _item.GetLzmaDicSize(); - if (dicSize > (UInt32)unpackSize) - { - dicSize = (UInt32)unpackSize; - SetUi32(props + 1, dicSize) - } - RINOK(_decoderLzmaSpec->SetDecoderProperties2(props, 5)) - } - RINOK(item.WriteHeader(outStream)) - const HRESULT result = _decoder->Code(inStream2, outStream, NULL, &unpackSize, lps); - opRes = NExtract::NOperationResult::kDataError; - if (result == S_OK) - { - if (item.GetSize() == outStream->GetSize()) - { - if (_item.IsZlib()) - { - _packSizeDefined = true; - _packSize = _decoderZlibSpec->GetInputProcessedSize(); - opRes = NExtract::NOperationResult::kOK; - } - else - { - // if (_decoderLzmaSpec->GetInputProcessedSize() == _packSize) - opRes = NExtract::NOperationResult::kOK; - } - } - } - else if (result != S_FALSE) - return result; - - // outStream.Release(); - } - return extractCallback->SetOperationResult(opRes); - COM_TRY_END -} - - -#ifdef Z7_SWF_UPDATE - -static HRESULT UpdateArchive(ISequentialOutStream *outStream, UInt64 size, - bool lzmaMode, const CSingleMethodProps &props, - IArchiveUpdateCallback *updateCallback) -{ - UInt64 complexity = 0; - RINOK(updateCallback->SetTotal(size)) - RINOK(updateCallback->SetCompleted(&complexity)) - - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)) - - /* - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - realOutStream.Release(); - */ - - CItem item; - const HRESULT res = item.ReadHeader(fileInStream); - if (res == S_FALSE) - return E_INVALIDARG; - RINOK(res) - if (!item.IsSwf() || !item.IsUncompressed() || size != item.GetSize()) - return E_INVALIDARG; - - NCompress::NZlib::CEncoder *encoderZlibSpec = NULL; - NCompress::NLzma::CEncoder *encoderLzmaSpec = NULL; - CMyComPtr encoder; - CMyComPtr outSeekStream; - if (lzmaMode) - { - outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); - if (!outSeekStream) - return E_NOTIMPL; - encoderLzmaSpec = new NCompress::NLzma::CEncoder; - encoder = encoderLzmaSpec; - RINOK(props.SetCoderProps(encoderLzmaSpec, &size)) - item.MakeLzma((UInt32)0xFFFFFFFF); - CBufPtrSeqOutStream *propStreamSpec = new CBufPtrSeqOutStream; - CMyComPtr propStream = propStreamSpec; - propStreamSpec->Init(item.Buf + 12, 5); - RINOK(encoderLzmaSpec->WriteCoderProperties(propStream)) - } - else - { - encoderZlibSpec = new NCompress::NZlib::CEncoder; - encoder = encoderZlibSpec; - encoderZlibSpec->Create(); - RINOK(props.SetCoderProps(encoderZlibSpec->DeflateEncoderSpec, NULL)) - item.MakeZlib(); - } - RINOK(item.WriteHeader(outStream)) - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, lps)) - UInt64 inputProcessed; - if (lzmaMode) - { - UInt64 curPos = 0; - RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &curPos)) - const UInt64 packSize = curPos - kHeaderLzmaSize; - if (packSize > (UInt32)0xFFFFFFFF) - return E_INVALIDARG; - item.MakeLzma((UInt32)packSize); - RINOK(outSeekStream->Seek(0, STREAM_SEEK_SET, NULL)) - RINOK(item.WriteHeader(outStream)) - inputProcessed = encoderLzmaSpec->GetInputProcessedSize(); - } - else - { - inputProcessed = encoderZlibSpec->GetInputProcessedSize(); - } - if (inputProcessed + kHeaderBaseSize != size) - return E_INVALIDARG; - return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); -} - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) -{ - *timeType = NFileTimeType::kUnix; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback)) -{ - if (numItems != 1) - return E_INVALIDARG; - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) - if (prop.vt == VT_BOOL) - { - if (prop.boolVal != VARIANT_FALSE) - return E_INVALIDARG; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - } - - if (IntToBool(newData)) - { - UInt64 size; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - } - return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - if (!_seqStream) - return E_NOTIMPL; - - if (_stream) - { - RINOK(InStream_SeekToBegin(_stream)) - } - else - _item.WriteHeader(outStream); - return NCompress::CopyStream(_seqStream, outStream, NULL); -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - _lzmaMode = false; - RINOK(_props.SetProperties(names, values, numProps)) - const AString &m = _props.MethodName; - if (m.IsEqualTo_Ascii_NoCase("lzma")) - { - return E_NOTIMPL; - // _lzmaMode = true; - } - else if (m.IsEqualTo_Ascii_NoCase("Deflate") || m.IsEmpty()) - _lzmaMode = false; - else - return E_INVALIDARG; - return S_OK; -} - -#endif - - -static const Byte k_Signature[] = { - 3, 'C', 'W', 'S', - 3, 'Z', 'W', 'S' }; - -REGISTER_ARC_I( - "SWFc", "swf", "~.swf", 0xD8, - k_Signature, - 0, - NArcInfoFlags::kMultiSignature, - IsArc_Swfc) - -} - -namespace NSwf { - -static const unsigned kNumTagsMax = 1 << 23; - -struct CTag -{ - UInt32 Type; - CByteBuffer Buf; -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IArchiveOpenSeq -) - CObjectVector _tags; - NSwfc::CItem _item; - UInt64 _phySize; - - HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback); - HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback); -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidComment, -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _phySize; break; - case kpidIsNotArcType: prop = true; break; - } - prop.Detach(value); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _tags.Size(); - return S_OK; -} - -static const char * const g_TagDesc[92] = -{ - "End" - , "ShowFrame" - , "DefineShape" - , NULL - , "PlaceObject" - , "RemoveObject" - , "DefineBits" - , "DefineButton" - , "JPEGTables" - , "SetBackgroundColor" - , "DefineFont" - , "DefineText" - , "DoAction" - , "DefineFontInfo" - , "DefineSound" - , "StartSound" - , NULL - , "DefineButtonSound" - , "SoundStreamHead" - , "SoundStreamBlock" - , "DefineBitsLossless" - , "DefineBitsJPEG2" - , "DefineShape2" - , "DefineButtonCxform" - , "Protect" - , NULL - , "PlaceObject2" - , NULL - , "RemoveObject2" - , NULL - , NULL - , NULL - , "DefineShape3" - , "DefineText2" - , "DefineButton2" - , "DefineBitsJPEG3" - , "DefineBitsLossless2" - , "DefineEditText" - , NULL - , "DefineSprite" - , NULL - , "41" - , NULL - , "FrameLabel" - , NULL - , "SoundStreamHead2" - , "DefineMorphShape" - , NULL - , "DefineFont2" - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , NULL - , "ExportAssets" - , "ImportAssets" - , "EnableDebugger" - , "DoInitAction" - , "DefineVideoStream" - , "VideoFrame" - , "DefineFontInfo2" - , NULL - , "EnableDebugger2" - , "ScriptLimits" - , "SetTabIndex" - , NULL - , NULL - , "FileAttributes" - , "PlaceObject3" - , "ImportAssets2" - , NULL - , "DefineFontAlignZones" - , "CSMTextSettings" - , "DefineFont3" - , "SymbolClass" - , "Metadata" - , "DefineScalingGrid" - , NULL - , NULL - , NULL - , "DoABC" - , "DefineShape4" - , "DefineMorphShape2" - , NULL - , "DefineSceneAndFrameLabelData" - , "DefineBinaryData" - , "DefineFontName" - , "StartSound2" - , "DefineBitsJPEG4" - , "DefineFont4" -}; - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - const CTag &tag = _tags[index]; - switch (propID) - { - case kpidPath: - { - char s[32]; - ConvertUInt32ToString(index, s); - size_t i = strlen(s); - s[i++] = '.'; - ConvertUInt32ToString(tag.Type, s + i); - prop = s; - break; - } - case kpidSize: - case kpidPackSize: - prop = (UInt64)tag.Buf.Size(); break; - case kpidComment: - TYPE_TO_PROP(g_TagDesc, tag.Type, prop); - break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - return OpenSeq2(stream, callback); -} - -static UInt16 Read16(CInBuffer &stream) -{ - UInt32 res = 0; - for (unsigned i = 0; i < 2; i++) - { - Byte b; - if (!stream.ReadByte(b)) - throw 1; - res |= (UInt32)b << (i * 8); - } - return (UInt16)res; -} - -static UInt32 Read32(CInBuffer &stream) -{ - UInt32 res = 0; - for (unsigned i = 0; i < 4; i++) - { - Byte b; - if (!stream.ReadByte(b)) - throw 1; - res |= (UInt32)b << (i * 8); - } - return res; -} - -struct CBitReader -{ - CInBuffer *stream; - unsigned NumBits; - Byte Val; - - CBitReader(): NumBits(0), Val(0) {} - - UInt32 ReadBits(unsigned numBits); -}; - -UInt32 CBitReader::ReadBits(unsigned numBits) -{ - UInt32 res = 0; - while (numBits > 0) - { - if (NumBits == 0) - { - Val = stream->ReadByte(); - NumBits = 8; - } - if (numBits <= NumBits) - { - res <<= numBits; - NumBits -= numBits; - res |= (Val >> NumBits); - Val = (Byte)(Val & (((unsigned)1 << NumBits) - 1)); - break; - } - else - { - res <<= NumBits; - res |= Val; - numBits -= NumBits; - NumBits = 0; - } - } - return res; -} - -HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback) -{ - RINOK(_item.ReadHeader(stream)) - if (!_item.IsSwf() || !_item.IsUncompressed()) - return S_FALSE; - const UInt32 uncompressedSize = _item.GetSize(); - if (uncompressedSize > kFileSizeMax) - return S_FALSE; - - - CInBuffer s; - if (!s.Create(1 << 20)) - return E_OUTOFMEMORY; - s.SetStream(stream); - s.Init(); - { - CBitReader br; - br.stream = &s; - const unsigned numBits = br.ReadBits(5); - /* UInt32 xMin = */ br.ReadBits(numBits); - /* UInt32 xMax = */ br.ReadBits(numBits); - /* UInt32 yMin = */ br.ReadBits(numBits); - /* UInt32 yMax = */ br.ReadBits(numBits); - } - /* UInt32 frameDelay = */ Read16(s); - /* UInt32 numFrames = */ Read16(s); - - _tags.Clear(); - UInt64 offsetPrev = 0; - for (;;) - { - const UInt32 pair = Read16(s); - const UInt32 type = pair >> 6; - UInt32 length = pair & 0x3F; - if (length == 0x3F) - length = Read32(s); - if (type == 0) - break; - const UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderBaseSize + length; - if (offset > uncompressedSize || _tags.Size() >= kNumTagsMax) - return S_FALSE; - CTag &tag = _tags.AddNew(); - tag.Type = type; - tag.Buf.Alloc(length); - if (s.ReadBytes(tag.Buf, length) != length) - return S_FALSE; - if (callback && offset >= offsetPrev + (1 << 20)) - { - const UInt64 numItems = _tags.Size(); - RINOK(callback->SetCompleted(&numItems, &offset)) - offsetPrev = offset; - } - } - _phySize = s.GetProcessedSize() + NSwfc::kHeaderBaseSize; - if (_phySize != uncompressedSize) - { - // do we need to support files extracted from SFW-LZMA with additional 8 bytes? - return S_FALSE; - } - return S_OK; -} - -HRESULT CHandler::OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback) -{ - HRESULT res; - try { res = OpenSeq3(stream, callback); } - catch(...) { res = S_FALSE; } - return res; -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - return OpenSeq2(stream, NULL); -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _tags.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _tags[allFilesMode ? i : indices[i]].Buf.Size(); - RINOK(extractCallback->SetTotal(totalSize)) - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - totalSize = 0; - - for (i = 0; i < numItems; i++) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()) - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CByteBuffer &buf = _tags[index].Buf; - totalSize += buf.Size(); - - CMyComPtr outStream; - RINOK(extractCallback->GetStream(index, &outStream, askMode)) - if (!testMode && !outStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - if (outStream) - RINOK(WriteStream(outStream, buf, buf.Size())) - outStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - return S_OK; - COM_TRY_END -} - -static const Byte k_Signature[] = { 'F', 'W', 'S' }; - -REGISTER_ARC_I( - "SWF", "swf", NULL, 0xD7, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - NSwfc::IsArc_Swf) - -}} +// SwfHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/InBuffer.h" +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/LzmaDecoder.h" +#include "../Compress/ZlibDecoder.h" + +#include "Common/DummyOutStream.h" + +// #define Z7_SWF_UPDATE + +#ifdef Z7_SWF_UPDATE + +#include "../Compress/LzmaEncoder.h" +#include "../Compress/ZlibEncoder.h" + +#include "Common/HandlerOut.h" + +#endif + +using namespace NWindows; + +namespace NArchive { + +static const UInt32 kFileSizeMax = (UInt32)1 << 29; + +namespace NSwfc { + +static const unsigned kHeaderBaseSize = 8; +static const unsigned kHeaderLzmaSize = 17; + +static const Byte SWF_UNCOMPRESSED = 'F'; +static const Byte SWF_COMPRESSED_ZLIB = 'C'; +static const Byte SWF_COMPRESSED_LZMA = 'Z'; + +static const Byte SWF_MIN_COMPRESSED_ZLIB_VER = 6; +static const Byte SWF_MIN_COMPRESSED_LZMA_VER = 13; + +static const Byte kVerLim = 64; + +API_FUNC_static_IsArc IsArc_Swf(const Byte *p, size_t size) +{ + if (size < kHeaderBaseSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] != SWF_UNCOMPRESSED || + p[1] != 'W' || + p[2] != 'S' || + p[3] >= kVerLim) + return k_IsArc_Res_NO; + UInt32 uncompressedSize = GetUi32(p + 4); + if (uncompressedSize > kFileSizeMax) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +API_FUNC_static_IsArc IsArc_Swfc(const Byte *p, size_t size) +{ + if (size < kHeaderBaseSize + 2 + 1) // 2 + 1 (for zlib check) + return k_IsArc_Res_NEED_MORE; + if ((p[0] != SWF_COMPRESSED_ZLIB && + p[0] != SWF_COMPRESSED_LZMA) || + p[1] != 'W' || + p[2] != 'S' || + p[3] >= kVerLim) + return k_IsArc_Res_NO; + UInt32 uncompressedSize = GetUi32(p + 4); + if (uncompressedSize > kFileSizeMax) + return k_IsArc_Res_NO; + + if (p[0] == SWF_COMPRESSED_ZLIB) + { + if (!NCompress::NZlib::IsZlib_3bytes(p + 8)) + return k_IsArc_Res_NO; + } + else + { + if (size < kHeaderLzmaSize + 2) + return k_IsArc_Res_NEED_MORE; + if (p[kHeaderLzmaSize] != 0 || + (p[kHeaderLzmaSize + 1] & 0x80) != 0) + return k_IsArc_Res_NO; + UInt32 lzmaPackSize = GetUi32(p + 8); + UInt32 lzmaProp = p[12]; + UInt32 lzmaDicSize = GetUi32(p + 13); + if (lzmaProp > 5 * 5 * 9 || + lzmaDicSize > ((UInt32)1 << 28) || + lzmaPackSize < 5 || + lzmaPackSize > ((UInt32)1 << 28)) + return k_IsArc_Res_NO; + } + + return k_IsArc_Res_YES; +} +} + +struct CItem +{ + Byte Buf[kHeaderLzmaSize]; + unsigned HeaderSize; + + UInt32 GetSize() const { return GetUi32(Buf + 4); } + UInt32 GetLzmaPackSize() const { return GetUi32(Buf + 8); } + UInt32 GetLzmaDicSize() const { return GetUi32(Buf + 13); } + + bool IsSwf() const { return (Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < kVerLim); } + bool IsUncompressed() const { return Buf[0] == SWF_UNCOMPRESSED; } + bool IsZlib() const { return Buf[0] == SWF_COMPRESSED_ZLIB; } + bool IsLzma() const { return Buf[0] == SWF_COMPRESSED_LZMA; } + + void MakeUncompressed() + { + Buf[0] = SWF_UNCOMPRESSED; + HeaderSize = kHeaderBaseSize; + } + void MakeZlib() + { + Buf[0] = SWF_COMPRESSED_ZLIB; + if (Buf[3] < SWF_MIN_COMPRESSED_ZLIB_VER) + Buf[3] = SWF_MIN_COMPRESSED_ZLIB_VER; + } + void MakeLzma(UInt32 packSize) + { + Buf[0] = SWF_COMPRESSED_LZMA; + if (Buf[3] < SWF_MIN_COMPRESSED_LZMA_VER) + Buf[3] = SWF_MIN_COMPRESSED_LZMA_VER; + SetUi32(Buf + 8, packSize) + HeaderSize = kHeaderLzmaSize; + } + + HRESULT ReadHeader(ISequentialInStream *stream) + { + HeaderSize = kHeaderBaseSize; + return ReadStream_FALSE(stream, Buf, kHeaderBaseSize); + } + HRESULT WriteHeader(ISequentialOutStream *stream) + { + return WriteStream(stream, Buf, HeaderSize); + } +}; + + +Z7_class_CHandler_final: + public IInArchive, + public IArchiveOpenSeq, + #ifdef Z7_SWF_UPDATE + public IOutArchive, + public ISetProperties, + #endif + public CMyUnknownImp +{ + #ifdef Z7_SWF_UPDATE + Z7_IFACES_IMP_UNK_4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties) + #else + Z7_IFACES_IMP_UNK_2(IInArchive, IArchiveOpenSeq) + #endif + + CItem _item; + UInt64 _packSize; + bool _packSizeDefined; + CMyComPtr _seqStream; + CMyComPtr _stream; + +#ifdef Z7_SWF_UPDATE + CSingleMethodProps _props; + bool _lzmaMode; +#endif + +public: + #ifdef Z7_SWF_UPDATE + CHandler(): _lzmaMode(false) {} + #endif +}; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; + case kpidIsNotArcType: prop = true; break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +static void DicSizeToString(char *s, UInt32 val) +{ + char c = 0; + unsigned i; + for (i = 0; i < 32; i++) + if (((UInt32)1 << i) == val) + { + val = i; + break; + } + if (i == 32) + { + c = 'b'; + if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; } + else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; } + } + ::ConvertUInt32ToString(val, s); + unsigned pos = MyStringLen(s); + s[pos++] = c; + s[pos] = 0; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidSize: prop = (UInt64)_item.GetSize(); break; + case kpidPackSize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break; + case kpidMethod: + { + char s[32]; + if (_item.IsZlib()) + MyStringCopy(s, "zlib"); + else + { + MyStringCopy(s, "LZMA:"); + DicSizeToString(s + 5, _item.GetLzmaDicSize()); + } + prop = s; + break; + } + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *)) +{ + RINOK(OpenSeq(stream)) + _stream = stream; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + Close(); + RINOK(_item.ReadHeader(stream)) + if (!_item.IsSwf()) + return S_FALSE; + if (_item.IsLzma()) + { + RINOK(ReadStream_FALSE(stream, _item.Buf + kHeaderBaseSize, kHeaderLzmaSize - kHeaderBaseSize)) + _item.HeaderSize = kHeaderLzmaSize; + _packSize = _item.GetLzmaPackSize(); + _packSizeDefined = true; + } + else if (!_item.IsZlib()) + return S_FALSE; + if (_item.GetSize() < _item.HeaderSize) + return S_FALSE; + _seqStream = stream; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _packSize = 0; + _packSizeDefined = false; + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +Z7_CLASS_IMP_COM_1( + CCompressProgressInfoImp, + ICompressProgressInfo +) + CMyComPtr Callback; +public: + UInt64 Offset; + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) +{ + if (Callback) + { + const UInt64 files = 0; + const UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + RINOK(extractCallback->SetTotal(_item.GetSize())) + Int32 opRes; +{ + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(); + // realOutStream.Release(); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + lps->InSize = _item.HeaderSize; + lps->OutSize = outStream->GetSize(); + RINOK(lps->SetCur()) + + CItem item = _item; + item.MakeUncompressed(); + if (_stream) + RINOK(InStream_SeekSet(_stream, _item.HeaderSize)) + NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL; + NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL; + CMyComPtr _decoder; + + CMyComPtr inStream2; + + const UInt64 unpackSize = _item.GetSize() - (UInt32)8; + if (_item.IsZlib()) + { + _decoderZlibSpec = new NCompress::NZlib::CDecoder; + _decoder = _decoderZlibSpec; + inStream2 = _seqStream; + } + else + { + /* Some .swf files with lzma contain additional 8 bytes at the end + in uncompressed stream. + What does that data mean ??? + We don't decompress these additional 8 bytes */ + + // unpackSize = _item.GetSize(); + // SetUi32(item.Buf + 4, (UInt32)(unpackSize + 8)); + CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream; + inStream2 = limitedStreamSpec; + limitedStreamSpec->SetStream(_seqStream); + limitedStreamSpec->Init(_item.GetLzmaPackSize()); + + _decoderLzmaSpec = new NCompress::NLzma::CDecoder; + _decoder = _decoderLzmaSpec; + // _decoderLzmaSpec->FinishStream = true; + + Byte props[5]; + memcpy(props, _item.Buf + 12, 5); + UInt32 dicSize = _item.GetLzmaDicSize(); + if (dicSize > (UInt32)unpackSize) + { + dicSize = (UInt32)unpackSize; + SetUi32(props + 1, dicSize) + } + RINOK(_decoderLzmaSpec->SetDecoderProperties2(props, 5)) + } + RINOK(item.WriteHeader(outStream)) + const HRESULT result = _decoder->Code(inStream2, outStream, NULL, &unpackSize, lps); + opRes = NExtract::NOperationResult::kDataError; + if (result == S_OK) + { + if (item.GetSize() == outStream->GetSize()) + { + if (_item.IsZlib()) + { + _packSizeDefined = true; + _packSize = _decoderZlibSpec->GetInputProcessedSize(); + opRes = NExtract::NOperationResult::kOK; + } + else + { + // if (_decoderLzmaSpec->GetInputProcessedSize() == _packSize) + opRes = NExtract::NOperationResult::kOK; + } + } + } + else if (result != S_FALSE) + return result; + + // outStream.Release(); + } + return extractCallback->SetOperationResult(opRes); + COM_TRY_END +} + + +#ifdef Z7_SWF_UPDATE + +static HRESULT UpdateArchive(ISequentialOutStream *outStream, UInt64 size, + bool lzmaMode, const CSingleMethodProps &props, + IArchiveUpdateCallback *updateCallback) +{ + UInt64 complexity = 0; + RINOK(updateCallback->SetTotal(size)) + RINOK(updateCallback->SetCompleted(&complexity)) + + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)) + + /* + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + realOutStream.Release(); + */ + + CItem item; + const HRESULT res = item.ReadHeader(fileInStream); + if (res == S_FALSE) + return E_INVALIDARG; + RINOK(res) + if (!item.IsSwf() || !item.IsUncompressed() || size != item.GetSize()) + return E_INVALIDARG; + + NCompress::NZlib::CEncoder *encoderZlibSpec = NULL; + NCompress::NLzma::CEncoder *encoderLzmaSpec = NULL; + CMyComPtr encoder; + CMyComPtr outSeekStream; + if (lzmaMode) + { + outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); + if (!outSeekStream) + return E_NOTIMPL; + encoderLzmaSpec = new NCompress::NLzma::CEncoder; + encoder = encoderLzmaSpec; + RINOK(props.SetCoderProps(encoderLzmaSpec, &size)) + item.MakeLzma((UInt32)0xFFFFFFFF); + CBufPtrSeqOutStream *propStreamSpec = new CBufPtrSeqOutStream; + CMyComPtr propStream = propStreamSpec; + propStreamSpec->Init(item.Buf + 12, 5); + RINOK(encoderLzmaSpec->WriteCoderProperties(propStream)) + } + else + { + encoderZlibSpec = new NCompress::NZlib::CEncoder; + encoder = encoderZlibSpec; + encoderZlibSpec->Create(); + RINOK(props.SetCoderProps(encoderZlibSpec->DeflateEncoderSpec, NULL)) + item.MakeZlib(); + } + RINOK(item.WriteHeader(outStream)) + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, lps)) + UInt64 inputProcessed; + if (lzmaMode) + { + UInt64 curPos = 0; + RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &curPos)) + const UInt64 packSize = curPos - kHeaderLzmaSize; + if (packSize > (UInt32)0xFFFFFFFF) + return E_INVALIDARG; + item.MakeLzma((UInt32)packSize); + RINOK(outSeekStream->Seek(0, STREAM_SEEK_SET, NULL)) + RINOK(item.WriteHeader(outStream)) + inputProcessed = encoderLzmaSpec->GetInputProcessedSize(); + } + else + { + inputProcessed = encoderZlibSpec->GetInputProcessedSize(); + } + if (inputProcessed + kHeaderBaseSize != size) + return E_INVALIDARG; + return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); +} + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) +{ + *timeType = NFileTimeType::kUnix; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback)) +{ + if (numItems != 1) + return E_INVALIDARG; + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) + if (prop.vt == VT_BOOL) + { + if (prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + if (!_seqStream) + return E_NOTIMPL; + + if (_stream) + { + RINOK(InStream_SeekToBegin(_stream)) + } + else + _item.WriteHeader(outStream); + return NCompress::CopyStream(_seqStream, outStream, NULL); +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + _lzmaMode = false; + RINOK(_props.SetProperties(names, values, numProps)) + const AString &m = _props.MethodName; + if (m.IsEqualTo_Ascii_NoCase("lzma")) + { + return E_NOTIMPL; + // _lzmaMode = true; + } + else if (m.IsEqualTo_Ascii_NoCase("Deflate") || m.IsEmpty()) + _lzmaMode = false; + else + return E_INVALIDARG; + return S_OK; +} + +#endif + + +static const Byte k_Signature[] = { + 3, 'C', 'W', 'S', + 3, 'Z', 'W', 'S' }; + +REGISTER_ARC_I( + "SWFc", "swf", "~.swf", 0xD8, + k_Signature, + 0, + NArcInfoFlags::kMultiSignature, + IsArc_Swfc) + +} + +namespace NSwf { + +static const unsigned kNumTagsMax = 1 << 23; + +struct CTag +{ + UInt32 Type; + CByteBuffer Buf; +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IArchiveOpenSeq +) + CObjectVector _tags; + NSwfc::CItem _item; + UInt64 _phySize; + + HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback); + HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback); +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidComment, +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidIsNotArcType: prop = true; break; + } + prop.Detach(value); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _tags.Size(); + return S_OK; +} + +static const char * const g_TagDesc[92] = +{ + "End" + , "ShowFrame" + , "DefineShape" + , NULL + , "PlaceObject" + , "RemoveObject" + , "DefineBits" + , "DefineButton" + , "JPEGTables" + , "SetBackgroundColor" + , "DefineFont" + , "DefineText" + , "DoAction" + , "DefineFontInfo" + , "DefineSound" + , "StartSound" + , NULL + , "DefineButtonSound" + , "SoundStreamHead" + , "SoundStreamBlock" + , "DefineBitsLossless" + , "DefineBitsJPEG2" + , "DefineShape2" + , "DefineButtonCxform" + , "Protect" + , NULL + , "PlaceObject2" + , NULL + , "RemoveObject2" + , NULL + , NULL + , NULL + , "DefineShape3" + , "DefineText2" + , "DefineButton2" + , "DefineBitsJPEG3" + , "DefineBitsLossless2" + , "DefineEditText" + , NULL + , "DefineSprite" + , NULL + , "41" + , NULL + , "FrameLabel" + , NULL + , "SoundStreamHead2" + , "DefineMorphShape" + , NULL + , "DefineFont2" + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , NULL + , "ExportAssets" + , "ImportAssets" + , "EnableDebugger" + , "DoInitAction" + , "DefineVideoStream" + , "VideoFrame" + , "DefineFontInfo2" + , NULL + , "EnableDebugger2" + , "ScriptLimits" + , "SetTabIndex" + , NULL + , NULL + , "FileAttributes" + , "PlaceObject3" + , "ImportAssets2" + , NULL + , "DefineFontAlignZones" + , "CSMTextSettings" + , "DefineFont3" + , "SymbolClass" + , "Metadata" + , "DefineScalingGrid" + , NULL + , NULL + , NULL + , "DoABC" + , "DefineShape4" + , "DefineMorphShape2" + , NULL + , "DefineSceneAndFrameLabelData" + , "DefineBinaryData" + , "DefineFontName" + , "StartSound2" + , "DefineBitsJPEG4" + , "DefineFont4" +}; + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + const CTag &tag = _tags[index]; + switch (propID) + { + case kpidPath: + { + char s[32]; + ConvertUInt32ToString(index, s); + size_t i = strlen(s); + s[i++] = '.'; + ConvertUInt32ToString(tag.Type, s + i); + prop = s; + break; + } + case kpidSize: + case kpidPackSize: + prop = (UInt64)tag.Buf.Size(); break; + case kpidComment: + TYPE_TO_PROP(g_TagDesc, tag.Type, prop); + break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + return OpenSeq2(stream, callback); +} + +static UInt16 Read16(CInBuffer &stream) +{ + UInt32 res = 0; + for (unsigned i = 0; i < 2; i++) + { + Byte b; + if (!stream.ReadByte(b)) + throw 1; + res |= (UInt32)b << (i * 8); + } + return (UInt16)res; +} + +static UInt32 Read32(CInBuffer &stream) +{ + UInt32 res = 0; + for (unsigned i = 0; i < 4; i++) + { + Byte b; + if (!stream.ReadByte(b)) + throw 1; + res |= (UInt32)b << (i * 8); + } + return res; +} + +struct CBitReader +{ + CInBuffer *stream; + unsigned NumBits; + Byte Val; + + CBitReader(): NumBits(0), Val(0) {} + + UInt32 ReadBits(unsigned numBits); +}; + +UInt32 CBitReader::ReadBits(unsigned numBits) +{ + UInt32 res = 0; + while (numBits > 0) + { + if (NumBits == 0) + { + Val = stream->ReadByte(); + NumBits = 8; + } + if (numBits <= NumBits) + { + res <<= numBits; + NumBits -= numBits; + res |= (Val >> NumBits); + Val = (Byte)(Val & (((unsigned)1 << NumBits) - 1)); + break; + } + else + { + res <<= NumBits; + res |= Val; + numBits -= NumBits; + NumBits = 0; + } + } + return res; +} + +HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback) +{ + RINOK(_item.ReadHeader(stream)) + if (!_item.IsSwf() || !_item.IsUncompressed()) + return S_FALSE; + const UInt32 uncompressedSize = _item.GetSize(); + if (uncompressedSize > kFileSizeMax) + return S_FALSE; + + + CInBuffer s; + if (!s.Create(1 << 20)) + return E_OUTOFMEMORY; + s.SetStream(stream); + s.Init(); + { + CBitReader br; + br.stream = &s; + const unsigned numBits = br.ReadBits(5); + /* UInt32 xMin = */ br.ReadBits(numBits); + /* UInt32 xMax = */ br.ReadBits(numBits); + /* UInt32 yMin = */ br.ReadBits(numBits); + /* UInt32 yMax = */ br.ReadBits(numBits); + } + /* UInt32 frameDelay = */ Read16(s); + /* UInt32 numFrames = */ Read16(s); + + _tags.Clear(); + UInt64 offsetPrev = 0; + for (;;) + { + const UInt32 pair = Read16(s); + const UInt32 type = pair >> 6; + UInt32 length = pair & 0x3F; + if (length == 0x3F) + length = Read32(s); + if (type == 0) + break; + const UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderBaseSize + length; + if (offset > uncompressedSize || _tags.Size() >= kNumTagsMax) + return S_FALSE; + CTag &tag = _tags.AddNew(); + tag.Type = type; + tag.Buf.Alloc(length); + if (s.ReadBytes(tag.Buf, length) != length) + return S_FALSE; + if (callback && offset >= offsetPrev + (1 << 20)) + { + const UInt64 numItems = _tags.Size(); + RINOK(callback->SetCompleted(&numItems, &offset)) + offsetPrev = offset; + } + } + _phySize = s.GetProcessedSize() + NSwfc::kHeaderBaseSize; + if (_phySize != uncompressedSize) + { + // do we need to support files extracted from SFW-LZMA with additional 8 bytes? + return S_FALSE; + } + return S_OK; +} + +HRESULT CHandler::OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback) +{ + HRESULT res; + try { res = OpenSeq3(stream, callback); } + catch(...) { res = S_FALSE; } + return res; +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + return OpenSeq2(stream, NULL); +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _tags.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _tags[allFilesMode ? i : indices[i]].Buf.Size(); + RINOK(extractCallback->SetTotal(totalSize)) + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + totalSize = 0; + + for (i = 0; i < numItems; i++) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()) + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CByteBuffer &buf = _tags[index].Buf; + totalSize += buf.Size(); + + CMyComPtr outStream; + RINOK(extractCallback->GetStream(index, &outStream, askMode)) + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + if (outStream) + RINOK(WriteStream(outStream, buf, buf.Size())) + outStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + return S_OK; + COM_TRY_END +} + +static const Byte k_Signature[] = { 'F', 'W', 'S' }; + +REGISTER_ARC_I( + "SWF", "swf", NULL, 0xD7, + k_Signature, + 0, + NArcInfoFlags::kKeepName, + NSwfc::IsArc_Swf) + +}} diff --git a/CPP/7zip/Archive/Tar/StdAfx.h b/CPP/7zip/Archive/Tar/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Tar/StdAfx.h +++ b/CPP/7zip/Archive/Tar/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index b67a0133f..29f28e8f5 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -1,1094 +1,1094 @@ -// TarHandler.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/MethodProps.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../Common/ItemNameUtils.h" - -#include "TarHandler.h" - -using namespace NWindows; - -namespace NArchive { -namespace NTar { - -// 21.02: we use UTF8 code page by default, even if some files show error -// before 21.02 : CP_OEMCP; -// static const UINT k_DefaultCodePage = CP_UTF8; - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidPosixAttrib, -#if 0 - kpidAttrib, -#endif - kpidUser, - kpidGroup, - kpidUserId, - kpidGroupId, - kpidSymLink, - kpidHardLink, - kpidCharacts, - kpidComment - , kpidDeviceMajor - , kpidDeviceMinor - // , kpidDevice - // , kpidHeadersSize // for debug - // , kpidOffset // for debug -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidCodePage, - kpidCharacts, - kpidComment -}; - -static const char *k_Characts_Prefix = "PREFIX"; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break; - case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break; - case kpidErrorFlags: - { - UInt32 flags = 0; - if (!_isArc) - flags |= kpv_ErrorFlags_IsNotArc; - else switch ((int)_arc._error) - { - case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; - case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; - // case k_ErrorType_OK: break; - // case k_ErrorType_Warning: break; - // case k_ErrorType_OK: - default: break; - } - if (flags != 0) - prop = flags; - break; - } - - case kpidWarningFlags: - { - if (_arc._is_Warning) - prop = kpv_ErrorFlags_HeadersError; - break; - } - - case kpidCodePage: - { - char sz[16]; - const char *name = NULL; - switch (_openCodePage) - { - case CP_OEMCP: name = "OEM"; break; - case CP_UTF8: name = "UTF-8"; break; - default: break; - } - if (!name) - { - ConvertUInt32ToString(_openCodePage, sz); - name = sz; - } - prop = name; - break; - } - - case kpidCharacts: - { - AString s; - if (_arc._are_Gnu) s.Add_OptSpaced("GNU"); - if (_arc._are_Posix) s.Add_OptSpaced("POSIX"); - if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM"); - if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix); - if (_arc._are_LongName) s.Add_OptSpaced("LongName"); - if (_arc._are_LongLink) s.Add_OptSpaced("LongLink"); - if (_arc._are_Pax) s.Add_OptSpaced("PAX"); - if (_arc._are_pax_path) s.Add_OptSpaced("path"); - if (_arc._are_pax_link) s.Add_OptSpaced("linkpath"); - if (_arc._are_mtime) s.Add_OptSpaced("mtime"); - if (_arc._are_atime) s.Add_OptSpaced("atime"); - if (_arc._are_ctime) s.Add_OptSpaced("ctime"); - if (_arc._are_SCHILY_fflags) s.Add_OptSpaced("SCHILY.fflags"); - if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR"); - s.Add_OptSpaced(_encodingCharacts.GetCharactsString()); - prop = s; - break; - } - - case kpidComment: - { - if (_arc.PaxGlobal_Defined) - { - AString s; - _arc.PaxGlobal.Print_To_String(s); - if (!s.IsEmpty()) - prop = s; - } - break; - } - default: break; - } - prop.Detach(value); - return S_OK; -} - - -void CEncodingCharacts::Check(const AString &s) -{ - IsAscii = s.IsAscii(); - if (!IsAscii) - { - /* - { - Oem_Checked = true; - UString u; - MultiByteToUnicodeString2(u, s, CP_OEMCP); - Oem_Ok = (u.Find((wchar_t)0xfffd) <= 0); - } - Utf_Checked = true; - */ - UtfCheck.Check_AString(s); - } -} - - -AString CEncodingCharacts::GetCharactsString() const -{ - AString s; - if (IsAscii) - { - s += "ASCII"; - } - /* - if (Oem_Checked) - { - s.Add_Space_if_NotEmpty(); - s += (Oem_Ok ? "oem-ok" : "oem-error"); - } - if (Utf_Checked) - */ - else - { - s.Add_Space_if_NotEmpty(); - s += (UtfCheck.IsOK() ? "UTF8" : "UTF8-ERROR"); // "UTF8-error" - { - AString s2; - UtfCheck.PrintStatus(s2); - s.Add_Space_if_NotEmpty(); - s += s2; - } - } - return s; -} - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) -{ - UInt64 endPos; - { - RINOK(InStream_AtBegin_GetSize(stream, endPos)) - } - - _arc._phySize_Defined = true; - - // bool utf8_OK = true; - - _arc.SeqStream = stream; - _arc.InStream = stream; - _arc.OpenCallback = callback; - - CItemEx item; - for (;;) - { - _arc.NumFiles = _items.Size(); - RINOK(_arc.ReadItem(item)) - if (!_arc.filled) - break; - - _isArc = true; - - /* - if (!_forceCodePage) - { - if (utf8_OK) utf8_OK = CheckUTF8(item.Name, item.NameCouldBeReduced); - if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName, item.LinkNameCouldBeReduced); - if (utf8_OK) utf8_OK = CheckUTF8(item.User); - if (utf8_OK) utf8_OK = CheckUTF8(item.Group); - } - */ - - item.EncodingCharacts.Check(item.Name); - _encodingCharacts.Update(item.EncodingCharacts); - - _items.Add(item); - - RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize)) - if (_arc._phySize > endPos) - { - _arc._error = k_ErrorType_UnexpectedEnd; - break; - } - /* - if (_phySize == endPos) - { - _errorMessage = "There are no trailing zero-filled records"; - break; - } - */ - /* - if (callback) - { - if (_items.Size() == 1) - { - RINOK(callback->SetTotal(NULL, &endPos)); - } - if ((_items.Size() & 0x3FF) == 0) - { - const UInt64 numFiles = _items.Size(); - RINOK(callback->SetCompleted(&numFiles, &_phySize)); - } - } - */ - } - - /* - if (!_forceCodePage) - { - if (!utf8_OK) - _curCodePage = k_DefaultCodePage; - } - */ - _openCodePage = _curCodePage; - - if (_items.Size() == 0) - { - if (_arc._error != k_ErrorType_OK) - { - _isArc = false; - return S_FALSE; - } - if (!callback) - return S_FALSE; - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpenVolumeCallback, - openVolumeCallback, callback) - if (!openVolumeCallback) - return S_FALSE; - NCOM::CPropVariant prop; - if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK) - return S_FALSE; - if (prop.vt != VT_BSTR) - return S_FALSE; - unsigned len = MyStringLen(prop.bstrVal); - if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0) - return S_FALSE; - } - - _isArc = true; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)) -{ - COM_TRY_BEGIN - // for (int i = 0; i < 10; i++) // for debug - { - Close(); - RINOK(Open2(stream, openArchiveCallback)) - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - Close(); - _seqStream = stream; - _isArc = true; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - - _arc.Clear(); - - _curIndex = 0; - _latestIsRead = false; - _encodingCharacts.Clear(); - _items.Clear(); - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1); - return S_OK; -} - -CHandler::CHandler() -{ - // copyCoder = new NCompress::CCopyCoder(); - // copyCoder = copyCoder; - _openCodePage = CP_UTF8; - Init(); -} - -HRESULT CHandler::SkipTo(UInt32 index) -{ - while (_curIndex < index || !_latestIsRead) - { - if (_latestIsRead) - { - const UInt64 packSize = _latestItem.Get_PackSize_Aligned(); - RINOK(copyCoder.Interface()->Code(_seqStream, NULL, &packSize, &packSize, NULL)) - _arc._phySize += copyCoder->TotalSize; - if (copyCoder->TotalSize != packSize) - { - _arc._error = k_ErrorType_UnexpectedEnd; - return S_FALSE; - } - _latestIsRead = false; - _curIndex++; - } - else - { - _arc.SeqStream = _seqStream; - _arc.InStream = NULL; - RINOK(_arc.ReadItem(_latestItem)) - if (!_arc.filled) - { - _arc._phySize_Defined = true; - return E_INVALIDARG; - } - _latestIsRead = true; - } - } - return S_OK; -} - -void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const -{ - UString dest; - if (_curCodePage == CP_UTF8) - ConvertUTF8ToUnicode(s, dest); - else - MultiByteToUnicodeString2(dest, s, _curCodePage); - if (toOs) - NItemName::ReplaceToOsSlashes_Remove_TailSlash(dest, - true); // useBackslashReplacement - prop = dest; -} - - -// CPaxTime is defined (NumDigits >= 0) -static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop) -{ - UInt64 v; - if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v)) - return; - if (pt.Ns != 0) - v += pt.Ns / 100; - FILETIME ft; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); - prop.SetAsTimeFrom_FT_Prec_Ns100(ft, - k_PropVar_TimePrec_Base + (unsigned)pt.NumDigits, pt.Ns % 100); -} - - -static void AddSpecCharToString(const char c, AString &s) -{ - if ((Byte)c <= 0x20 || (Byte)c > 127) - { - s.Add_Char('['); - s.Add_Char(GET_HEX_CHAR_LOWER((Byte)c >> 4)); - s.Add_Char(GET_HEX_CHAR_LOWER(c & 15)); - s.Add_Char(']'); - } - else - s.Add_Char(c); -} - -static void AddSpecUInt64(AString &s, const char *name, UInt64 v) -{ - if (v != 0) - { - s.Add_OptSpaced(name); - if (v > 1) - { - s.Add_Colon(); - s.Add_UInt64(v); - } - } -} - -static void AddSpecBools(AString &s, const char *name, bool b1, bool b2) -{ - if (b1) - { - s.Add_OptSpaced(name); - if (b2) - s.Add_Char('*'); - } -} - - -#if 0 -static bool Parse_Attrib_from_SCHILY_fflags(const AString &s, UInt32 &attribRes) -{ - UInt32 attrib = 0; - attribRes = attrib; - unsigned pos = 0; - while (pos < s.Len()) - { - int pos2 = s.Find(',', pos); - if (pos2 < 0) - pos2 = (int)s.Len(); - const AString str = s.Mid(pos, (unsigned)pos2 - pos); - if (str.IsEqualTo("hidden")) attrib |= FILE_ATTRIBUTE_HIDDEN; - else if (str.IsEqualTo("rdonly")) attrib |= FILE_ATTRIBUTE_READONLY; - else if (str.IsEqualTo("system")) attrib |= FILE_ATTRIBUTE_SYSTEM; - else - return false; - pos = (unsigned)pos2 + 1; - } - attribRes = attrib; - return true; -} -#endif - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CItemEx *item; - if (_stream) - item = &_items[index]; - else - { - if (index < _curIndex) - return E_INVALIDARG; - else - { - RINOK(SkipTo(index)) - item = &_latestItem; - } - } - - switch (propID) - { - case kpidPath: TarStringToUnicode(item->Name, prop, true); break; - case kpidIsDir: prop = item->IsDir(); break; - case kpidSize: prop = item->Get_UnpackSize(); break; - case kpidPackSize: prop = item->Get_PackSize_Aligned(); break; - case kpidMTime: - { - /* - // for debug: - PropVariant_SetFrom_UnixTime(prop, 1 << 30); - prop.wReserved1 = k_PropVar_TimePrec_Base + 1; - prop.wReserved2 = 12; - break; - */ - - if (item->PaxTimes.MTime.IsDefined()) - PaxTimeToProp(item->PaxTimes.MTime, prop); - else - // if (item->MTime != 0) - { - // we allow (item->MTime == 0) - FILETIME ft; - if (NTime::UnixTime64_To_FileTime(item->MTime, ft)) - { - unsigned prec = k_PropVar_TimePrec_Unix; - if (item->MTime_IsBin) - { - /* we report here that it's Int64-UnixTime - instead of basic UInt32-UnixTime range */ - prec = k_PropVar_TimePrec_Base; - } - prop.SetAsTimeFrom_FT_Prec(ft, prec); - } - } - break; - } - case kpidATime: - if (item->PaxTimes.ATime.IsDefined()) - PaxTimeToProp(item->PaxTimes.ATime, prop); - break; - case kpidCTime: - if (item->PaxTimes.CTime.IsDefined()) - PaxTimeToProp(item->PaxTimes.CTime, prop); - break; - case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; - - // kpidAttrib has priority over kpidPosixAttrib in 7-Zip. - // but if we want kpidPosixAttrib priority for TAR, we disable kpidAttrib. -#if 0 - case kpidAttrib: - { - if (!item->SCHILY_fflags.IsEmpty()) - { - UInt32 attrib = 0; - if (Parse_Attrib_from_SCHILY_fflags(item->SCHILY_fflags, attrib)) - { - if (attrib != 0) - { - if (item->IsDir()) - attrib |= FILE_ATTRIBUTE_DIRECTORY; - attrib |= ((UInt32)item->Get_Combined_Mode() << 16) | 0x8000; // FILE_ATTRIBUTE_UNIX_EXTENSION; - prop = attrib; - } - } - } - break; - } -#endif - - case kpidUser: - if (!item->User.IsEmpty()) - TarStringToUnicode(item->User, prop); - break; - case kpidGroup: - if (!item->Group.IsEmpty()) - TarStringToUnicode(item->Group, prop); - break; - - case kpidUserId: - // if (item->UID != 0) - prop = (UInt32)item->UID; - break; - case kpidGroupId: - // if (item->GID != 0) - prop = (UInt32)item->GID; - break; - - case kpidDeviceMajor: - if (item->DeviceMajor_Defined) - // if (item->DeviceMajor != 0) - prop = (UInt32)item->DeviceMajor; - break; - - case kpidDeviceMinor: - if (item->DeviceMinor_Defined) - // if (item->DeviceMinor != 0) - prop = (UInt32)item->DeviceMinor; - break; - /* - case kpidDevice: - if (item->DeviceMajor_Defined) - if (item->DeviceMinor_Defined) - prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor); - break; - */ - - case kpidSymLink: - if (item->Is_SymLink()) - if (!item->LinkName.IsEmpty()) - TarStringToUnicode(item->LinkName, prop); - break; - case kpidHardLink: - if (item->Is_HardLink()) - if (!item->LinkName.IsEmpty()) - TarStringToUnicode(item->LinkName, prop); - break; - - case kpidCharacts: - { - AString s; - { - s.Add_Space_if_NotEmpty(); - AddSpecCharToString(item->LinkFlag, s); - } - if (item->IsMagic_GNU()) - s.Add_OptSpaced("GNU"); - else if (item->IsMagic_Posix_ustar_00()) - s.Add_OptSpaced("POSIX"); - else - { - s.Add_Space_if_NotEmpty(); - for (unsigned i = 0; i < sizeof(item->Magic); i++) - AddSpecCharToString(item->Magic[i], s); - } - - if (item->IsSignedChecksum) - s.Add_OptSpaced("SignedChecksum"); - - if (item->Prefix_WasUsed) - s.Add_OptSpaced(k_Characts_Prefix); - - s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString()); - - // AddSpecUInt64(s, "LongName", item->Num_LongName_Records); - // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records); - AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2); - AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2); - - if (item->MTime_IsBin) - s.Add_OptSpaced("bin_mtime"); - if (item->PackSize_IsBin) - s.Add_OptSpaced("bin_psize"); - if (item->Size_IsBin) - s.Add_OptSpaced("bin_size"); - - AddSpecUInt64(s, "PAX", item->Num_Pax_Records); - - if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime"); - if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime"); - if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime"); - - if (item->pax_path_WasUsed) - s.Add_OptSpaced("pax_path"); - if (item->pax_link_WasUsed) - s.Add_OptSpaced("pax_linkpath"); - if (item->pax_size_WasUsed) - s.Add_OptSpaced("pax_size"); - if (!item->SCHILY_fflags.IsEmpty()) - { - s.Add_OptSpaced("SCHILY.fflags="); - s += item->SCHILY_fflags; - } - if (item->IsThereWarning()) - s.Add_OptSpaced("WARNING"); - if (item->HeaderError) - s.Add_OptSpaced("ERROR"); - if (item->Pax_Error) - s.Add_OptSpaced("PAX_error"); - if (!item->PaxExtra.RawLines.IsEmpty()) - s.Add_OptSpaced("PAX_unsupported_line"); - if (item->Pax_Overflow) - s.Add_OptSpaced("PAX_overflow"); - if (!s.IsEmpty()) - prop = s; - break; - } - case kpidComment: - { - AString s; - item->PaxExtra.Print_To_String(s); - if (!s.IsEmpty()) - prop = s; - break; - } - // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug - // case kpidOffset: prop = item->HeaderPos; break; // for debug - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - ISequentialInStream *stream = _seqStream; - const bool seqMode = (_stream == NULL); - if (!seqMode) - stream = _stream; - - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (_stream && numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize(); - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 totalPackSize; - totalSize = totalPackSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create inStream; - inStream->SetStream(stream); - CMyComPtr2_Create outStreamSpec; - - for (i = 0; ; i++) - { - lps->InSize = totalPackSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems && !seqMode) - break; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItemEx *item; - if (seqMode) - { - const HRESULT res = SkipTo(index); - if (res == E_INVALIDARG) - break; - RINOK(res) - item = &_latestItem; - } - else - item = &_items[index]; - - Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - const UInt64 unpackSize = item->Get_UnpackSize(); - totalSize += unpackSize; - totalPackSize += item->Get_PackSize_Aligned(); - if (item->IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - // realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - bool skipMode = false; - if (!testMode && !realOutStream) - { - if (!seqMode) - { - /* - // GetStream() creates link. - // so we can show extracting info in GetStream() instead - if (item->Is_HardLink() || - item->Is_SymLink()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - */ - continue; - } - skipMode = true; - askMode = NExtract::NAskMode::kSkip; - } - RINOK(extractCallback->PrepareOperation(askMode)) - - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(skipMode ? 0 : unpackSize, true); - - Int32 opRes = NExtract::NOperationResult::kOK; - CMyComPtr inStream2; - if (!item->Is_Sparse()) - inStream2 = inStream; - else - { - GetStream(index, &inStream2); - if (!inStream2) - return E_FAIL; - } - - { - if (item->Is_SymLink()) - { - RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())) - } - else - { - if (!seqMode) - { - RINOK(InStream_SeekSet(_stream, item->Get_DataPos())) - } - inStream->Init(item->Get_PackSize_Aligned()); - RINOK(copyCoder.Interface()->Code(inStream2, outStreamSpec, NULL, NULL, lps)) - } - if (outStreamSpec->GetRem() != 0) - opRes = NExtract::NOperationResult::kDataError; - } - if (seqMode) - { - _latestIsRead = false; - _curIndex++; - } - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - - -Z7_CLASS_IMP_IInStream( - CSparseStream -) - UInt64 _phyPos; - UInt64 _virtPos; - bool _needStartSeek; - -public: - CHandler *Handler; - CMyComPtr HandlerRef; - unsigned ItemIndex; - CRecordVector PhyOffsets; - - void Init() - { - _virtPos = 0; - _phyPos = 0; - _needStartSeek = true; - } -}; - - -Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - const CItemEx &item = Handler->_items[ItemIndex]; - if (_virtPos >= item.Size) - return S_OK; - { - UInt64 rem = item.Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - - HRESULT res = S_OK; - - if (item.SparseBlocks.IsEmpty()) - memset(data, 0, size); - else - { - unsigned left = 0, right = item.SparseBlocks.Size(); - for (;;) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - if (mid == left) - break; - if (_virtPos < item.SparseBlocks[mid].Offset) - right = mid; - else - left = mid; - } - - const CSparseBlock &sb = item.SparseBlocks[left]; - UInt64 relat = _virtPos - sb.Offset; - - if (_virtPos >= sb.Offset && relat < sb.Size) - { - UInt64 rem = sb.Size - relat; - if (size > rem) - size = (UInt32)rem; - UInt64 phyPos = PhyOffsets[left] + relat; - if (_needStartSeek || _phyPos != phyPos) - { - RINOK(InStream_SeekSet(Handler->_stream, (item.Get_DataPos() + phyPos))) - _needStartSeek = false; - _phyPos = phyPos; - } - res = Handler->_stream->Read(data, size, &size); - _phyPos += size; - } - else - { - UInt64 next = item.Size; - if (_virtPos < sb.Offset) - next = sb.Offset; - else if (left + 1 < item.SparseBlocks.Size()) - next = item.SparseBlocks[left + 1].Offset; - UInt64 rem = next - _virtPos; - if (size > rem) - size = (UInt32)rem; - memset(data, 0, size); - } - } - - _virtPos += size; - if (processedSize) - *processedSize = size; - return res; -} - -Z7_COM7F_IMF(CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - - const CItemEx &item = _items[index]; - - if (item.Is_Sparse()) - { - CSparseStream *streamSpec = new CSparseStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->Init(); - streamSpec->Handler = this; - streamSpec->HandlerRef = (IInArchive *)this; - streamSpec->ItemIndex = index; - streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size()); - UInt64 offs = 0; - FOR_VECTOR(i, item.SparseBlocks) - { - const CSparseBlock &sb = item.SparseBlocks[i]; - streamSpec->PhyOffsets.AddInReserved(offs); - offs += sb.Size; - } - *stream = streamTemp.Detach(); - return S_OK; - } - - if (item.Is_SymLink()) - { - Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); - return S_OK; - } - - return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream); - - COM_TRY_END -} - - -void CHandler::Init() -{ - _forceCodePage = false; - _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; - _posixMode = false; - _posixMode_WasForced = false; - // TimeOptions.Clear(); - _handlerTimeOptions.Init(); - // _handlerTimeOptions.Write_MTime.Val = true; // it's default already -} - - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - Init(); - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - const PROPVARIANT &prop = values[i]; - - if (name[0] == L'x') - { - // some clients write 'x' property. So we support it - UInt32 level = 0; - RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)) - } - else if (name.IsEqualTo("cp")) - { - UInt32 cp = CP_OEMCP; - RINOK(ParsePropToUInt32(L"", prop, cp)) - _forceCodePage = true; - _curCodePage = _specifiedCodePage = cp; - } - else if (name.IsPrefixedBy_Ascii_NoCase("mt")) - { - } - else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) - { - } - else if (name.IsEqualTo("m")) - { - if (prop.vt != VT_BSTR) - return E_INVALIDARG; - const UString s = prop.bstrVal; - if (s.IsEqualTo_Ascii_NoCase("pax") || - s.IsEqualTo_Ascii_NoCase("posix")) - _posixMode = true; - else if (s.IsEqualTo_Ascii_NoCase("gnu")) - _posixMode = false; - else - return E_INVALIDARG; - _posixMode_WasForced = true; - } - else - { - /* - if (name.IsPrefixedBy_Ascii_NoCase("td")) - { - name.Delete(0, 3); - if (prop.vt == VT_EMPTY) - { - if (name.IsEqualTo_Ascii_NoCase("n")) - { - // TimeOptions.UseNativeDigits = true; - } - else if (name.IsEqualTo_Ascii_NoCase("r")) - { - // TimeOptions.RemoveZeroDigits = true; - } - else - return E_INVALIDARG; - } - else - { - UInt32 numTimeDigits = 0; - RINOK(ParsePropToUInt32(name, prop, numTimeDigits)); - TimeOptions.NumDigits_WasForced = true; - TimeOptions.NumDigits = numTimeDigits; - } - } - */ - bool processed = false; - RINOK(_handlerTimeOptions.Parse(name, prop, processed)) - if (processed) - continue; - return E_INVALIDARG; - } - } - return S_OK; -} - -}} +// TarHandler.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/MethodProps.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../Common/ItemNameUtils.h" + +#include "TarHandler.h" + +using namespace NWindows; + +namespace NArchive { +namespace NTar { + +// 21.02: we use UTF8 code page by default, even if some files show error +// before 21.02 : CP_OEMCP; +// static const UINT k_DefaultCodePage = CP_UTF8; + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidPosixAttrib, +#if 0 + kpidAttrib, +#endif + kpidUser, + kpidGroup, + kpidUserId, + kpidGroupId, + kpidSymLink, + kpidHardLink, + kpidCharacts, + kpidComment + , kpidDeviceMajor + , kpidDeviceMinor + // , kpidDevice + // , kpidHeadersSize // for debug + // , kpidOffset // for debug +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidCodePage, + kpidCharacts, + kpidComment +}; + +static const char *k_Characts_Prefix = "PREFIX"; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break; + case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (!_isArc) + flags |= kpv_ErrorFlags_IsNotArc; + else switch ((int)_arc._error) + { + case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; + case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; + // case k_ErrorType_OK: break; + // case k_ErrorType_Warning: break; + // case k_ErrorType_OK: + default: break; + } + if (flags != 0) + prop = flags; + break; + } + + case kpidWarningFlags: + { + if (_arc._is_Warning) + prop = kpv_ErrorFlags_HeadersError; + break; + } + + case kpidCodePage: + { + char sz[16]; + const char *name = NULL; + switch (_openCodePage) + { + case CP_OEMCP: name = "OEM"; break; + case CP_UTF8: name = "UTF-8"; break; + default: break; + } + if (!name) + { + ConvertUInt32ToString(_openCodePage, sz); + name = sz; + } + prop = name; + break; + } + + case kpidCharacts: + { + AString s; + if (_arc._are_Gnu) s.Add_OptSpaced("GNU"); + if (_arc._are_Posix) s.Add_OptSpaced("POSIX"); + if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM"); + if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix); + if (_arc._are_LongName) s.Add_OptSpaced("LongName"); + if (_arc._are_LongLink) s.Add_OptSpaced("LongLink"); + if (_arc._are_Pax) s.Add_OptSpaced("PAX"); + if (_arc._are_pax_path) s.Add_OptSpaced("path"); + if (_arc._are_pax_link) s.Add_OptSpaced("linkpath"); + if (_arc._are_mtime) s.Add_OptSpaced("mtime"); + if (_arc._are_atime) s.Add_OptSpaced("atime"); + if (_arc._are_ctime) s.Add_OptSpaced("ctime"); + if (_arc._are_SCHILY_fflags) s.Add_OptSpaced("SCHILY.fflags"); + if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR"); + s.Add_OptSpaced(_encodingCharacts.GetCharactsString()); + prop = s; + break; + } + + case kpidComment: + { + if (_arc.PaxGlobal_Defined) + { + AString s; + _arc.PaxGlobal.Print_To_String(s); + if (!s.IsEmpty()) + prop = s; + } + break; + } + default: break; + } + prop.Detach(value); + return S_OK; +} + + +void CEncodingCharacts::Check(const AString &s) +{ + IsAscii = s.IsAscii(); + if (!IsAscii) + { + /* + { + Oem_Checked = true; + UString u; + MultiByteToUnicodeString2(u, s, CP_OEMCP); + Oem_Ok = (u.Find((wchar_t)0xfffd) <= 0); + } + Utf_Checked = true; + */ + UtfCheck.Check_AString(s); + } +} + + +AString CEncodingCharacts::GetCharactsString() const +{ + AString s; + if (IsAscii) + { + s += "ASCII"; + } + /* + if (Oem_Checked) + { + s.Add_Space_if_NotEmpty(); + s += (Oem_Ok ? "oem-ok" : "oem-error"); + } + if (Utf_Checked) + */ + else + { + s.Add_Space_if_NotEmpty(); + s += (UtfCheck.IsOK() ? "UTF8" : "UTF8-ERROR"); // "UTF8-error" + { + AString s2; + UtfCheck.PrintStatus(s2); + s.Add_Space_if_NotEmpty(); + s += s2; + } + } + return s; +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) +{ + UInt64 endPos; + { + RINOK(InStream_AtBegin_GetSize(stream, endPos)) + } + + _arc._phySize_Defined = true; + + // bool utf8_OK = true; + + _arc.SeqStream = stream; + _arc.InStream = stream; + _arc.OpenCallback = callback; + + CItemEx item; + for (;;) + { + _arc.NumFiles = _items.Size(); + RINOK(_arc.ReadItem(item)) + if (!_arc.filled) + break; + + _isArc = true; + + /* + if (!_forceCodePage) + { + if (utf8_OK) utf8_OK = CheckUTF8(item.Name, item.NameCouldBeReduced); + if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName, item.LinkNameCouldBeReduced); + if (utf8_OK) utf8_OK = CheckUTF8(item.User); + if (utf8_OK) utf8_OK = CheckUTF8(item.Group); + } + */ + + item.EncodingCharacts.Check(item.Name); + _encodingCharacts.Update(item.EncodingCharacts); + + _items.Add(item); + + RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize)) + if (_arc._phySize > endPos) + { + _arc._error = k_ErrorType_UnexpectedEnd; + break; + } + /* + if (_phySize == endPos) + { + _errorMessage = "There are no trailing zero-filled records"; + break; + } + */ + /* + if (callback) + { + if (_items.Size() == 1) + { + RINOK(callback->SetTotal(NULL, &endPos)); + } + if ((_items.Size() & 0x3FF) == 0) + { + const UInt64 numFiles = _items.Size(); + RINOK(callback->SetCompleted(&numFiles, &_phySize)); + } + } + */ + } + + /* + if (!_forceCodePage) + { + if (!utf8_OK) + _curCodePage = k_DefaultCodePage; + } + */ + _openCodePage = _curCodePage; + + if (_items.Size() == 0) + { + if (_arc._error != k_ErrorType_OK) + { + _isArc = false; + return S_FALSE; + } + if (!callback) + return S_FALSE; + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpenVolumeCallback, + openVolumeCallback, callback) + if (!openVolumeCallback) + return S_FALSE; + NCOM::CPropVariant prop; + if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK) + return S_FALSE; + if (prop.vt != VT_BSTR) + return S_FALSE; + unsigned len = MyStringLen(prop.bstrVal); + if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0) + return S_FALSE; + } + + _isArc = true; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)) +{ + COM_TRY_BEGIN + // for (int i = 0; i < 10; i++) // for debug + { + Close(); + RINOK(Open2(stream, openArchiveCallback)) + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + Close(); + _seqStream = stream; + _isArc = true; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + + _arc.Clear(); + + _curIndex = 0; + _latestIsRead = false; + _encodingCharacts.Clear(); + _items.Clear(); + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1); + return S_OK; +} + +CHandler::CHandler() +{ + // copyCoder = new NCompress::CCopyCoder(); + // copyCoder = copyCoder; + _openCodePage = CP_UTF8; + Init(); +} + +HRESULT CHandler::SkipTo(UInt32 index) +{ + while (_curIndex < index || !_latestIsRead) + { + if (_latestIsRead) + { + const UInt64 packSize = _latestItem.Get_PackSize_Aligned(); + RINOK(copyCoder.Interface()->Code(_seqStream, NULL, &packSize, &packSize, NULL)) + _arc._phySize += copyCoder->TotalSize; + if (copyCoder->TotalSize != packSize) + { + _arc._error = k_ErrorType_UnexpectedEnd; + return S_FALSE; + } + _latestIsRead = false; + _curIndex++; + } + else + { + _arc.SeqStream = _seqStream; + _arc.InStream = NULL; + RINOK(_arc.ReadItem(_latestItem)) + if (!_arc.filled) + { + _arc._phySize_Defined = true; + return E_INVALIDARG; + } + _latestIsRead = true; + } + } + return S_OK; +} + +void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const +{ + UString dest; + if (_curCodePage == CP_UTF8) + ConvertUTF8ToUnicode(s, dest); + else + MultiByteToUnicodeString2(dest, s, _curCodePage); + if (toOs) + NItemName::ReplaceToOsSlashes_Remove_TailSlash(dest, + true); // useBackslashReplacement + prop = dest; +} + + +// CPaxTime is defined (NumDigits >= 0) +static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop) +{ + UInt64 v; + if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v)) + return; + if (pt.Ns != 0) + v += pt.Ns / 100; + FILETIME ft; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, + k_PropVar_TimePrec_Base + (unsigned)pt.NumDigits, pt.Ns % 100); +} + + +static void AddSpecCharToString(const char c, AString &s) +{ + if ((Byte)c <= 0x20 || (Byte)c > 127) + { + s.Add_Char('['); + s.Add_Char(GET_HEX_CHAR_LOWER((Byte)c >> 4)); + s.Add_Char(GET_HEX_CHAR_LOWER(c & 15)); + s.Add_Char(']'); + } + else + s.Add_Char(c); +} + +static void AddSpecUInt64(AString &s, const char *name, UInt64 v) +{ + if (v != 0) + { + s.Add_OptSpaced(name); + if (v > 1) + { + s.Add_Colon(); + s.Add_UInt64(v); + } + } +} + +static void AddSpecBools(AString &s, const char *name, bool b1, bool b2) +{ + if (b1) + { + s.Add_OptSpaced(name); + if (b2) + s.Add_Char('*'); + } +} + + +#if 0 +static bool Parse_Attrib_from_SCHILY_fflags(const AString &s, UInt32 &attribRes) +{ + UInt32 attrib = 0; + attribRes = attrib; + unsigned pos = 0; + while (pos < s.Len()) + { + int pos2 = s.Find(',', pos); + if (pos2 < 0) + pos2 = (int)s.Len(); + const AString str = s.Mid(pos, (unsigned)pos2 - pos); + if (str.IsEqualTo("hidden")) attrib |= FILE_ATTRIBUTE_HIDDEN; + else if (str.IsEqualTo("rdonly")) attrib |= FILE_ATTRIBUTE_READONLY; + else if (str.IsEqualTo("system")) attrib |= FILE_ATTRIBUTE_SYSTEM; + else + return false; + pos = (unsigned)pos2 + 1; + } + attribRes = attrib; + return true; +} +#endif + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CItemEx *item; + if (_stream) + item = &_items[index]; + else + { + if (index < _curIndex) + return E_INVALIDARG; + else + { + RINOK(SkipTo(index)) + item = &_latestItem; + } + } + + switch (propID) + { + case kpidPath: TarStringToUnicode(item->Name, prop, true); break; + case kpidIsDir: prop = item->IsDir(); break; + case kpidSize: prop = item->Get_UnpackSize(); break; + case kpidPackSize: prop = item->Get_PackSize_Aligned(); break; + case kpidMTime: + { + /* + // for debug: + PropVariant_SetFrom_UnixTime(prop, 1 << 30); + prop.wReserved1 = k_PropVar_TimePrec_Base + 1; + prop.wReserved2 = 12; + break; + */ + + if (item->PaxTimes.MTime.IsDefined()) + PaxTimeToProp(item->PaxTimes.MTime, prop); + else + // if (item->MTime != 0) + { + // we allow (item->MTime == 0) + FILETIME ft; + if (NTime::UnixTime64_To_FileTime(item->MTime, ft)) + { + unsigned prec = k_PropVar_TimePrec_Unix; + if (item->MTime_IsBin) + { + /* we report here that it's Int64-UnixTime + instead of basic UInt32-UnixTime range */ + prec = k_PropVar_TimePrec_Base; + } + prop.SetAsTimeFrom_FT_Prec(ft, prec); + } + } + break; + } + case kpidATime: + if (item->PaxTimes.ATime.IsDefined()) + PaxTimeToProp(item->PaxTimes.ATime, prop); + break; + case kpidCTime: + if (item->PaxTimes.CTime.IsDefined()) + PaxTimeToProp(item->PaxTimes.CTime, prop); + break; + case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; + + // kpidAttrib has priority over kpidPosixAttrib in 7-Zip. + // but if we want kpidPosixAttrib priority for TAR, we disable kpidAttrib. +#if 0 + case kpidAttrib: + { + if (!item->SCHILY_fflags.IsEmpty()) + { + UInt32 attrib = 0; + if (Parse_Attrib_from_SCHILY_fflags(item->SCHILY_fflags, attrib)) + { + if (attrib != 0) + { + if (item->IsDir()) + attrib |= FILE_ATTRIBUTE_DIRECTORY; + attrib |= ((UInt32)item->Get_Combined_Mode() << 16) | 0x8000; // FILE_ATTRIBUTE_UNIX_EXTENSION; + prop = attrib; + } + } + } + break; + } +#endif + + case kpidUser: + if (!item->User.IsEmpty()) + TarStringToUnicode(item->User, prop); + break; + case kpidGroup: + if (!item->Group.IsEmpty()) + TarStringToUnicode(item->Group, prop); + break; + + case kpidUserId: + // if (item->UID != 0) + prop = (UInt32)item->UID; + break; + case kpidGroupId: + // if (item->GID != 0) + prop = (UInt32)item->GID; + break; + + case kpidDeviceMajor: + if (item->DeviceMajor_Defined) + // if (item->DeviceMajor != 0) + prop = (UInt32)item->DeviceMajor; + break; + + case kpidDeviceMinor: + if (item->DeviceMinor_Defined) + // if (item->DeviceMinor != 0) + prop = (UInt32)item->DeviceMinor; + break; + /* + case kpidDevice: + if (item->DeviceMajor_Defined) + if (item->DeviceMinor_Defined) + prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor); + break; + */ + + case kpidSymLink: + if (item->Is_SymLink()) + if (!item->LinkName.IsEmpty()) + TarStringToUnicode(item->LinkName, prop); + break; + case kpidHardLink: + if (item->Is_HardLink()) + if (!item->LinkName.IsEmpty()) + TarStringToUnicode(item->LinkName, prop); + break; + + case kpidCharacts: + { + AString s; + { + s.Add_Space_if_NotEmpty(); + AddSpecCharToString(item->LinkFlag, s); + } + if (item->IsMagic_GNU()) + s.Add_OptSpaced("GNU"); + else if (item->IsMagic_Posix_ustar_00()) + s.Add_OptSpaced("POSIX"); + else + { + s.Add_Space_if_NotEmpty(); + for (unsigned i = 0; i < sizeof(item->Magic); i++) + AddSpecCharToString(item->Magic[i], s); + } + + if (item->IsSignedChecksum) + s.Add_OptSpaced("SignedChecksum"); + + if (item->Prefix_WasUsed) + s.Add_OptSpaced(k_Characts_Prefix); + + s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString()); + + // AddSpecUInt64(s, "LongName", item->Num_LongName_Records); + // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records); + AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2); + AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2); + + if (item->MTime_IsBin) + s.Add_OptSpaced("bin_mtime"); + if (item->PackSize_IsBin) + s.Add_OptSpaced("bin_psize"); + if (item->Size_IsBin) + s.Add_OptSpaced("bin_size"); + + AddSpecUInt64(s, "PAX", item->Num_Pax_Records); + + if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime"); + if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime"); + if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime"); + + if (item->pax_path_WasUsed) + s.Add_OptSpaced("pax_path"); + if (item->pax_link_WasUsed) + s.Add_OptSpaced("pax_linkpath"); + if (item->pax_size_WasUsed) + s.Add_OptSpaced("pax_size"); + if (!item->SCHILY_fflags.IsEmpty()) + { + s.Add_OptSpaced("SCHILY.fflags="); + s += item->SCHILY_fflags; + } + if (item->IsThereWarning()) + s.Add_OptSpaced("WARNING"); + if (item->HeaderError) + s.Add_OptSpaced("ERROR"); + if (item->Pax_Error) + s.Add_OptSpaced("PAX_error"); + if (!item->PaxExtra.RawLines.IsEmpty()) + s.Add_OptSpaced("PAX_unsupported_line"); + if (item->Pax_Overflow) + s.Add_OptSpaced("PAX_overflow"); + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidComment: + { + AString s; + item->PaxExtra.Print_To_String(s); + if (!s.IsEmpty()) + prop = s; + break; + } + // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug + // case kpidOffset: prop = item->HeaderPos; break; // for debug + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + ISequentialInStream *stream = _seqStream; + const bool seqMode = (_stream == NULL); + if (!seqMode) + stream = _stream; + + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (_stream && numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize(); + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 totalPackSize; + totalSize = totalPackSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create inStream; + inStream->SetStream(stream); + CMyComPtr2_Create outStreamSpec; + + for (i = 0; ; i++) + { + lps->InSize = totalPackSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems && !seqMode) + break; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItemEx *item; + if (seqMode) + { + const HRESULT res = SkipTo(index); + if (res == E_INVALIDARG) + break; + RINOK(res) + item = &_latestItem; + } + else + item = &_items[index]; + + Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + const UInt64 unpackSize = item->Get_UnpackSize(); + totalSize += unpackSize; + totalPackSize += item->Get_PackSize_Aligned(); + if (item->IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + // realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + bool skipMode = false; + if (!testMode && !realOutStream) + { + if (!seqMode) + { + /* + // GetStream() creates link. + // so we can show extracting info in GetStream() instead + if (item->Is_HardLink() || + item->Is_SymLink()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + */ + continue; + } + skipMode = true; + askMode = NExtract::NAskMode::kSkip; + } + RINOK(extractCallback->PrepareOperation(askMode)) + + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(skipMode ? 0 : unpackSize, true); + + Int32 opRes = NExtract::NOperationResult::kOK; + CMyComPtr inStream2; + if (!item->Is_Sparse()) + inStream2 = inStream; + else + { + GetStream(index, &inStream2); + if (!inStream2) + return E_FAIL; + } + + { + if (item->Is_SymLink()) + { + RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())) + } + else + { + if (!seqMode) + { + RINOK(InStream_SeekSet(_stream, item->Get_DataPos())) + } + inStream->Init(item->Get_PackSize_Aligned()); + RINOK(copyCoder.Interface()->Code(inStream2, outStreamSpec, NULL, NULL, lps)) + } + if (outStreamSpec->GetRem() != 0) + opRes = NExtract::NOperationResult::kDataError; + } + if (seqMode) + { + _latestIsRead = false; + _curIndex++; + } + outStreamSpec->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + + +Z7_CLASS_IMP_IInStream( + CSparseStream +) + UInt64 _phyPos; + UInt64 _virtPos; + bool _needStartSeek; + +public: + CHandler *Handler; + CMyComPtr HandlerRef; + unsigned ItemIndex; + CRecordVector PhyOffsets; + + void Init() + { + _virtPos = 0; + _phyPos = 0; + _needStartSeek = true; + } +}; + + +Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + const CItemEx &item = Handler->_items[ItemIndex]; + if (_virtPos >= item.Size) + return S_OK; + { + UInt64 rem = item.Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + + HRESULT res = S_OK; + + if (item.SparseBlocks.IsEmpty()) + memset(data, 0, size); + else + { + unsigned left = 0, right = item.SparseBlocks.Size(); + for (;;) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + if (mid == left) + break; + if (_virtPos < item.SparseBlocks[mid].Offset) + right = mid; + else + left = mid; + } + + const CSparseBlock &sb = item.SparseBlocks[left]; + UInt64 relat = _virtPos - sb.Offset; + + if (_virtPos >= sb.Offset && relat < sb.Size) + { + UInt64 rem = sb.Size - relat; + if (size > rem) + size = (UInt32)rem; + UInt64 phyPos = PhyOffsets[left] + relat; + if (_needStartSeek || _phyPos != phyPos) + { + RINOK(InStream_SeekSet(Handler->_stream, (item.Get_DataPos() + phyPos))) + _needStartSeek = false; + _phyPos = phyPos; + } + res = Handler->_stream->Read(data, size, &size); + _phyPos += size; + } + else + { + UInt64 next = item.Size; + if (_virtPos < sb.Offset) + next = sb.Offset; + else if (left + 1 < item.SparseBlocks.Size()) + next = item.SparseBlocks[left + 1].Offset; + UInt64 rem = next - _virtPos; + if (size > rem) + size = (UInt32)rem; + memset(data, 0, size); + } + } + + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; +} + +Z7_COM7F_IMF(CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + + const CItemEx &item = _items[index]; + + if (item.Is_Sparse()) + { + CSparseStream *streamSpec = new CSparseStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Init(); + streamSpec->Handler = this; + streamSpec->HandlerRef = (IInArchive *)this; + streamSpec->ItemIndex = index; + streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size()); + UInt64 offs = 0; + FOR_VECTOR(i, item.SparseBlocks) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + streamSpec->PhyOffsets.AddInReserved(offs); + offs += sb.Size; + } + *stream = streamTemp.Detach(); + return S_OK; + } + + if (item.Is_SymLink()) + { + Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); + return S_OK; + } + + return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream); + + COM_TRY_END +} + + +void CHandler::Init() +{ + _forceCodePage = false; + _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; + _posixMode = false; + _posixMode_WasForced = false; + // TimeOptions.Clear(); + _handlerTimeOptions.Init(); + // _handlerTimeOptions.Write_MTime.Val = true; // it's default already +} + + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + Init(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name[0] == L'x') + { + // some clients write 'x' property. So we support it + UInt32 level = 0; + RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)) + } + else if (name.IsEqualTo("cp")) + { + UInt32 cp = CP_OEMCP; + RINOK(ParsePropToUInt32(L"", prop, cp)) + _forceCodePage = true; + _curCodePage = _specifiedCodePage = cp; + } + else if (name.IsPrefixedBy_Ascii_NoCase("mt")) + { + } + else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) + { + } + else if (name.IsEqualTo("m")) + { + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + const UString s = prop.bstrVal; + if (s.IsEqualTo_Ascii_NoCase("pax") || + s.IsEqualTo_Ascii_NoCase("posix")) + _posixMode = true; + else if (s.IsEqualTo_Ascii_NoCase("gnu")) + _posixMode = false; + else + return E_INVALIDARG; + _posixMode_WasForced = true; + } + else + { + /* + if (name.IsPrefixedBy_Ascii_NoCase("td")) + { + name.Delete(0, 3); + if (prop.vt == VT_EMPTY) + { + if (name.IsEqualTo_Ascii_NoCase("n")) + { + // TimeOptions.UseNativeDigits = true; + } + else if (name.IsEqualTo_Ascii_NoCase("r")) + { + // TimeOptions.RemoveZeroDigits = true; + } + else + return E_INVALIDARG; + } + else + { + UInt32 numTimeDigits = 0; + RINOK(ParsePropToUInt32(name, prop, numTimeDigits)); + TimeOptions.NumDigits_WasForced = true; + TimeOptions.NumDigits = numTimeDigits; + } + } + */ + bool processed = false; + RINOK(_handlerTimeOptions.Parse(name, prop, processed)) + if (processed) + continue; + return E_INVALIDARG; + } + } + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h index c16dea2ce..f1ef3b69c 100644 --- a/CPP/7zip/Archive/Tar/TarHandler.h +++ b/CPP/7zip/Archive/Tar/TarHandler.h @@ -1,57 +1,57 @@ -// TarHandler.h - -#ifndef ZIP7_INC_TAR_HANDLER_H -#define ZIP7_INC_TAR_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../../Compress/CopyCoder.h" - -#include "../Common/HandlerOut.h" - -#include "TarIn.h" - -namespace NArchive { -namespace NTar { - -Z7_CLASS_IMP_CHandler_IInArchive_4( - IArchiveOpenSeq - , IInArchiveGetStream - , ISetProperties - , IOutArchive -) -public: - CObjectVector _items; - CMyComPtr _stream; - CMyComPtr _seqStream; -private: - bool _isArc; - bool _posixMode_WasForced; - bool _posixMode; - bool _forceCodePage; - UInt32 _specifiedCodePage; - UInt32 _curCodePage; - UInt32 _openCodePage; - // CTimeOptions TimeOptions; - CHandlerTimeOptions _handlerTimeOptions; - CEncodingCharacts _encodingCharacts; - - UInt32 _curIndex; - bool _latestIsRead; - CItemEx _latestItem; - - CArchive _arc; - - CMyComPtr2_Create copyCoder; - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); - HRESULT SkipTo(UInt32 index); - void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; -public: - void Init(); - CHandler(); -}; - -}} - -#endif +// TarHandler.h + +#ifndef ZIP7_INC_TAR_HANDLER_H +#define ZIP7_INC_TAR_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/HandlerOut.h" + +#include "TarIn.h" + +namespace NArchive { +namespace NTar { + +Z7_CLASS_IMP_CHandler_IInArchive_4( + IArchiveOpenSeq + , IInArchiveGetStream + , ISetProperties + , IOutArchive +) +public: + CObjectVector _items; + CMyComPtr _stream; + CMyComPtr _seqStream; +private: + bool _isArc; + bool _posixMode_WasForced; + bool _posixMode; + bool _forceCodePage; + UInt32 _specifiedCodePage; + UInt32 _curCodePage; + UInt32 _openCodePage; + // CTimeOptions TimeOptions; + CHandlerTimeOptions _handlerTimeOptions; + CEncodingCharacts _encodingCharacts; + + UInt32 _curIndex; + bool _latestIsRead; + CItemEx _latestItem; + + CArchive _arc; + + CMyComPtr2_Create copyCoder; + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); + HRESULT SkipTo(UInt32 index); + void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; +public: + void Init(); + CHandler(); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp index 308e52c53..bcbb35d8b 100644 --- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp +++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp @@ -1,332 +1,332 @@ -// TarHandlerOut.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../Common/ComTry.h" -#include "../../../Common/MyLinux.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/TimeUtils.h" - -#include "../Common/ItemNameUtils.h" - -#include "TarHandler.h" -#include "TarUpdate.h" - -using namespace NWindows; - -namespace NArchive { -namespace NTar { - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) -{ - UInt32 t = NFileTimeType::kUnix; - const UInt32 prec = _handlerTimeOptions.Prec; - if (prec != (UInt32)(Int32)-1) - { - t = NFileTimeType::kWindows; - if (prec == k_PropVar_TimePrec_0 || - prec == k_PropVar_TimePrec_100ns) - t = NFileTimeType::kWindows; - else if (prec == k_PropVar_TimePrec_HighPrec) - t = k_PropVar_TimePrec_1ns; - else if (prec >= k_PropVar_TimePrec_Base) - t = prec; - } - // 7-Zip before 22.00 fails, if unknown typeType. - *type = t; - return S_OK; -} - - -void Get_AString_From_UString(const UString &s, AString &res, - UINT codePage, unsigned utfFlags) -{ - if (codePage == CP_UTF8) - ConvertUnicodeToUTF8_Flags(s, res, utfFlags); - else - UnicodeStringToMultiByte2(res, s, codePage); -} - - -HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, - UINT codePage, unsigned utfFlags, bool convertSlash) -{ - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propId, &prop)) - - if (prop.vt == VT_BSTR) - { - UString s = prop.bstrVal; - if (convertSlash) - NItemName::ReplaceSlashes_OsToUnix(s); - Get_AString_From_UString(s, res, codePage, utfFlags); - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - - return S_OK; -} - - -// sort old files with original order. - -static int CompareUpdateItems(void *const *p1, void *const *p2, void *) -{ - const CUpdateItem &u1 = *(*((const CUpdateItem *const *)p1)); - const CUpdateItem &u2 = *(*((const CUpdateItem *const *)p2)); - if (!u1.NewProps) - { - if (u2.NewProps) - return -1; - return MyCompare(u1.IndexInArc, u2.IndexInArc); - } - if (!u2.NewProps) - return 1; - return MyCompare(u1.IndexInClient, u2.IndexInClient); -} - - -static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback, - CPaxTime &pt) -{ - pt.Clear(); - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, pid, &prop)) - return Prop_To_PaxTime(prop, pt); -} - - -/* -static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i, - UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined) -{ - NWindows::NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidDevice, &prop)); - if (prop.vt == VT_EMPTY) - return S_OK; - if (prop.vt != VT_UI8) - return E_INVALIDARG; - { - const UInt64 v = prop.uhVal.QuadPart; - majo = MY_dev_major(v); - mino = MY_dev_minor(v); - majo_defined = true; - mino_defined = true; - } - return S_OK; -} -*/ - -static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i, - UInt32 pid, UInt32 &id, bool &defined) -{ - defined = false; - NWindows::NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, pid, &prop)) - if (prop.vt == VT_EMPTY) - return S_OK; - if (prop.vt == VT_UI4) - { - id = prop.ulVal; - defined = true; - return S_OK; - } - return E_INVALIDARG; -} - - -static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i, - UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id, - UINT codePage, unsigned utfFlags) -{ - // printf("\ncallback->GetProperty(i, pidId, &prop))\n"); - - bool isSet = false; - { - NWindows::NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, pidId, &prop)) - if (prop.vt == VT_UI4) - { - isSet = true; - id = prop.ulVal; - // printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id); - name.Empty(); - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - { - NWindows::NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, pidName, &prop)) - if (prop.vt == VT_BSTR) - { - const UString s = prop.bstrVal; - Get_AString_From_UString(s, name, codePage, utfFlags); - if (!isSet) - id = 0; - } - else if (prop.vt == VT_UI4) - { - id = prop.ulVal; - name.Empty(); - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - return S_OK; -} - - - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback)) -{ - COM_TRY_BEGIN - - if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning - /* || _isSparse */ - )) || _seqStream) - return E_NOTIMPL; - CObjectVector updateItems; - const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); - const unsigned utfFlags = g_Unicode_To_UTF8_Flags; - /* - // for debug only: - unsigned utfFlags = 0; - utfFlags |= Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE; - utfFlags |= Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR; - */ - - for (UInt32 i = 0; i < numItems; i++) - { - CUpdateItem ui; - Int32 newData; - Int32 newProps; - UInt32 indexInArc; - - if (!callback) - return E_FAIL; - - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)) - - ui.NewProps = IntToBool(newProps); - ui.NewData = IntToBool(newData); - ui.IndexInArc = (int)indexInArc; - ui.IndexInClient = i; - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidIsDir, &prop)) - if (prop.vt == VT_EMPTY) - ui.IsDir = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - ui.IsDir = (prop.boolVal != VARIANT_FALSE); - } - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop)) - if (prop.vt == VT_EMPTY) - ui.Mode = - MY_LIN_S_IRWXO - | MY_LIN_S_IRWXG - | MY_LIN_S_IRWXU - | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG); - else if (prop.vt != VT_UI4) - return E_INVALIDARG; - else - ui.Mode = prop.ulVal; - // 21.07 : we clear high file type bits as GNU TAR. - // we will clear it later - // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; - } - - if (_handlerTimeOptions.Write_MTime.Val) - RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime)) - if (_handlerTimeOptions.Write_ATime.Val) - RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime)) - if (_handlerTimeOptions.Write_CTime.Val) - RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime)) - - RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true)) - if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') - ui.Name.Add_Slash(); - // ui.Name.Add_Slash(); // for debug - - if (_posixMode) - { - RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined)) - RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined)) - } - - RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags)) - RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags)) - } - - if (IntToBool(newData)) - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - ui.Size = prop.uhVal.QuadPart; - /* - // now we support GNU extension for big files - if (ui.Size >= ((UInt64)1 << 33)) - return E_INVALIDARG; - */ - } - - updateItems.Add(ui); - } - - if (_arc._are_Pax_Items) - { - // we restore original order of files, if there are pax items - updateItems.Sort(CompareUpdateItems, NULL); - } - - CUpdateOptions options; - - options.CodePage = codePage; - options.UtfFlags = utfFlags; - options.PosixMode = _posixMode; - - options.Write_MTime = _handlerTimeOptions.Write_MTime; - options.Write_ATime = _handlerTimeOptions.Write_ATime; - options.Write_CTime = _handlerTimeOptions.Write_CTime; - - // options.TimeOptions = TimeOptions; - - const UInt32 prec = _handlerTimeOptions.Prec; - if (prec != (UInt32)(Int32)-1) - { - unsigned numDigits = 0; - if (prec == 0) - numDigits = 7; - else if (prec == k_PropVar_TimePrec_HighPrec - || prec >= k_PropVar_TimePrec_1ns) - numDigits = 9; - else if (prec >= k_PropVar_TimePrec_Base) - numDigits = prec - k_PropVar_TimePrec_Base; - options.TimeOptions.NumDigitsMax = numDigits; - // options.TimeOptions.RemoveZeroMode = - // k_PaxTimeMode_DontRemoveZero; // pure for debug - // k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code - // k_PaxTimeMode_RemoveZero_Always; // original pax code - } - - return UpdateArchive(_stream, outStream, _items, updateItems, - options, callback); - - COM_TRY_END -} - -}} +// TarHandlerOut.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../Common/ComTry.h" +#include "../../../Common/MyLinux.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/TimeUtils.h" + +#include "../Common/ItemNameUtils.h" + +#include "TarHandler.h" +#include "TarUpdate.h" + +using namespace NWindows; + +namespace NArchive { +namespace NTar { + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) +{ + UInt32 t = NFileTimeType::kUnix; + const UInt32 prec = _handlerTimeOptions.Prec; + if (prec != (UInt32)(Int32)-1) + { + t = NFileTimeType::kWindows; + if (prec == k_PropVar_TimePrec_0 || + prec == k_PropVar_TimePrec_100ns) + t = NFileTimeType::kWindows; + else if (prec == k_PropVar_TimePrec_HighPrec) + t = k_PropVar_TimePrec_1ns; + else if (prec >= k_PropVar_TimePrec_Base) + t = prec; + } + // 7-Zip before 22.00 fails, if unknown typeType. + *type = t; + return S_OK; +} + + +void Get_AString_From_UString(const UString &s, AString &res, + UINT codePage, unsigned utfFlags) +{ + if (codePage == CP_UTF8) + ConvertUnicodeToUTF8_Flags(s, res, utfFlags); + else + UnicodeStringToMultiByte2(res, s, codePage); +} + + +HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, + UINT codePage, unsigned utfFlags, bool convertSlash) +{ + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propId, &prop)) + + if (prop.vt == VT_BSTR) + { + UString s = prop.bstrVal; + if (convertSlash) + NItemName::ReplaceSlashes_OsToUnix(s); + Get_AString_From_UString(s, res, codePage, utfFlags); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + + return S_OK; +} + + +// sort old files with original order. + +static int CompareUpdateItems(void *const *p1, void *const *p2, void *) +{ + const CUpdateItem &u1 = *(*((const CUpdateItem *const *)p1)); + const CUpdateItem &u2 = *(*((const CUpdateItem *const *)p2)); + if (!u1.NewProps) + { + if (u2.NewProps) + return -1; + return MyCompare(u1.IndexInArc, u2.IndexInArc); + } + if (!u2.NewProps) + return 1; + return MyCompare(u1.IndexInClient, u2.IndexInClient); +} + + +static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback, + CPaxTime &pt) +{ + pt.Clear(); + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pid, &prop)) + return Prop_To_PaxTime(prop, pt); +} + + +/* +static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i, + UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined) +{ + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidDevice, &prop)); + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt != VT_UI8) + return E_INVALIDARG; + { + const UInt64 v = prop.uhVal.QuadPart; + majo = MY_dev_major(v); + mino = MY_dev_minor(v); + majo_defined = true; + mino_defined = true; + } + return S_OK; +} +*/ + +static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i, + UInt32 pid, UInt32 &id, bool &defined) +{ + defined = false; + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pid, &prop)) + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt == VT_UI4) + { + id = prop.ulVal; + defined = true; + return S_OK; + } + return E_INVALIDARG; +} + + +static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i, + UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id, + UINT codePage, unsigned utfFlags) +{ + // printf("\ncallback->GetProperty(i, pidId, &prop))\n"); + + bool isSet = false; + { + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pidId, &prop)) + if (prop.vt == VT_UI4) + { + isSet = true; + id = prop.ulVal; + // printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id); + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pidName, &prop)) + if (prop.vt == VT_BSTR) + { + const UString s = prop.bstrVal; + Get_AString_From_UString(s, name, codePage, utfFlags); + if (!isSet) + id = 0; + } + else if (prop.vt == VT_UI4) + { + id = prop.ulVal; + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + + + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback)) +{ + COM_TRY_BEGIN + + if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning + /* || _isSparse */ + )) || _seqStream) + return E_NOTIMPL; + CObjectVector updateItems; + const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); + const unsigned utfFlags = g_Unicode_To_UTF8_Flags; + /* + // for debug only: + unsigned utfFlags = 0; + utfFlags |= Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE; + utfFlags |= Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR; + */ + + for (UInt32 i = 0; i < numItems; i++) + { + CUpdateItem ui; + Int32 newData; + Int32 newProps; + UInt32 indexInArc; + + if (!callback) + return E_FAIL; + + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)) + + ui.NewProps = IntToBool(newProps); + ui.NewData = IntToBool(newData); + ui.IndexInArc = (int)indexInArc; + ui.IndexInClient = i; + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidIsDir, &prop)) + if (prop.vt == VT_EMPTY) + ui.IsDir = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + } + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop)) + if (prop.vt == VT_EMPTY) + ui.Mode = + MY_LIN_S_IRWXO + | MY_LIN_S_IRWXG + | MY_LIN_S_IRWXU + | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG); + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + ui.Mode = prop.ulVal; + // 21.07 : we clear high file type bits as GNU TAR. + // we will clear it later + // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; + } + + if (_handlerTimeOptions.Write_MTime.Val) + RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime)) + if (_handlerTimeOptions.Write_ATime.Val) + RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime)) + if (_handlerTimeOptions.Write_CTime.Val) + RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime)) + + RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true)) + if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') + ui.Name.Add_Slash(); + // ui.Name.Add_Slash(); // for debug + + if (_posixMode) + { + RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined)) + RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined)) + } + + RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags)) + RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags)) + } + + if (IntToBool(newData)) + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + ui.Size = prop.uhVal.QuadPart; + /* + // now we support GNU extension for big files + if (ui.Size >= ((UInt64)1 << 33)) + return E_INVALIDARG; + */ + } + + updateItems.Add(ui); + } + + if (_arc._are_Pax_Items) + { + // we restore original order of files, if there are pax items + updateItems.Sort(CompareUpdateItems, NULL); + } + + CUpdateOptions options; + + options.CodePage = codePage; + options.UtfFlags = utfFlags; + options.PosixMode = _posixMode; + + options.Write_MTime = _handlerTimeOptions.Write_MTime; + options.Write_ATime = _handlerTimeOptions.Write_ATime; + options.Write_CTime = _handlerTimeOptions.Write_CTime; + + // options.TimeOptions = TimeOptions; + + const UInt32 prec = _handlerTimeOptions.Prec; + if (prec != (UInt32)(Int32)-1) + { + unsigned numDigits = 0; + if (prec == 0) + numDigits = 7; + else if (prec == k_PropVar_TimePrec_HighPrec + || prec >= k_PropVar_TimePrec_1ns) + numDigits = 9; + else if (prec >= k_PropVar_TimePrec_Base) + numDigits = prec - k_PropVar_TimePrec_Base; + options.TimeOptions.NumDigitsMax = numDigits; + // options.TimeOptions.RemoveZeroMode = + // k_PaxTimeMode_DontRemoveZero; // pure for debug + // k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code + // k_PaxTimeMode_RemoveZero_Always; // original pax code + } + + return UpdateArchive(_stream, outStream, _items, updateItems, + options, callback); + + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp index d727a2802..deae357eb 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.cpp +++ b/CPP/7zip/Archive/Tar/TarHeader.cpp @@ -1,99 +1,99 @@ -// Archive/TarHeader.cpp - -#include "StdAfx.h" - -#include "TarHeader.h" - -namespace NArchive { -namespace NTar { -namespace NFileHeader { - - const char * const kLongLink = "././@LongLink"; - const char * const kLongLink2 = "@LongLink"; - - // The magic field is filled with this if uname and gname are valid. - namespace NMagic - { - // const char * const kUsTar = "ustar"; // 5 chars - // const char * const kGNUTar = "GNUtar "; // 7 chars and a null - // const char * const kEmpty = "\0\0\0\0\0\0\0\0"; - // 7-Zip used kUsTar_00 before 21.07: - const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; - // GNU TAR uses such header: - const char k_GNU_ustar[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ; - } - -/* -pre-POSIX.1-1988 (i.e. v7) tar header: ------ -Link indicator: -'0' or 0 : Normal file -'1' : Hard link -'2' : Symbolic link -Some pre-POSIX.1-1988 tar implementations indicated a directory by having -a trailing slash (/) in the name. - -Numeric values : octal with leading zeroes. -For historical reasons, a final NUL or space character should also be used. -Thus only 11 octal digits can be stored from 12 bytes field. - -2001 star : introduced a base-256 coding that is indicated by -setting the high-order bit of the leftmost byte of a numeric field. -GNU-tar and BSD-tar followed this idea. - -versions of tar from before the first POSIX standard from 1988 -pad the values with spaces instead of zeroes. - -UStar ------ -UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988. - 257 signature: "ustar", 0, "00" - 265 32 Owner user name - 297 32 Owner group name - 329 8 Device major number - 337 8 Device minor number - 345 155 Filename prefix - -POSIX.1-2001/pax ----- -format is known as extended tar format or pax format -vendor-tagged vendor-specific enhancements. -tags Defined by the POSIX standard: - atime, mtime, path, linkpath, uname, gname, size, uid, gid, ... - - -PAX EXTENSION ------------ -Hard links -A further difference from the ustar header block is that data blocks -for files of typeflag 1 (hard link) may be included, -which means that the size field may be greater than zero. -Archives created by pax -o linkdata shall include these data -blocks with the hard links. -* - -compatiblity ------------- - 7-Zip 16.03 supports "PaxHeader/" - 7-Zip 20.01 supports "PaxHeaders.X/" with optional "./" - 7-Zip 21.02 supports "@PaxHeader" with optional "./" "./" - - GNU tar --format=posix uses "PaxHeaders/" in folder of file - - -GNU TAR format -============== -v7 - Unix V7 -oldgnu - GNU tar <=1.12 : writes zero in last character in name -gnu - GNU tar 1.13 : doesn't write zero in last character in name - as 7-zip 21.07 -ustar - POSIX.1-1988 -posix (pax) - POSIX.1-2001 - - gnu tar: - if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) { - major_t devmajor = major (st->stat.st_rdev); - minor_t devminor = minor (st->stat.st_rdev); } -*/ - -}}} +// Archive/TarHeader.cpp + +#include "StdAfx.h" + +#include "TarHeader.h" + +namespace NArchive { +namespace NTar { +namespace NFileHeader { + + const char * const kLongLink = "././@LongLink"; + const char * const kLongLink2 = "@LongLink"; + + // The magic field is filled with this if uname and gname are valid. + namespace NMagic + { + // const char * const kUsTar = "ustar"; // 5 chars + // const char * const kGNUTar = "GNUtar "; // 7 chars and a null + // const char * const kEmpty = "\0\0\0\0\0\0\0\0"; + // 7-Zip used kUsTar_00 before 21.07: + const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; + // GNU TAR uses such header: + const char k_GNU_ustar[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ; + } + +/* +pre-POSIX.1-1988 (i.e. v7) tar header: +----- +Link indicator: +'0' or 0 : Normal file +'1' : Hard link +'2' : Symbolic link +Some pre-POSIX.1-1988 tar implementations indicated a directory by having +a trailing slash (/) in the name. + +Numeric values : octal with leading zeroes. +For historical reasons, a final NUL or space character should also be used. +Thus only 11 octal digits can be stored from 12 bytes field. + +2001 star : introduced a base-256 coding that is indicated by +setting the high-order bit of the leftmost byte of a numeric field. +GNU-tar and BSD-tar followed this idea. + +versions of tar from before the first POSIX standard from 1988 +pad the values with spaces instead of zeroes. + +UStar +----- +UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988. + 257 signature: "ustar", 0, "00" + 265 32 Owner user name + 297 32 Owner group name + 329 8 Device major number + 337 8 Device minor number + 345 155 Filename prefix + +POSIX.1-2001/pax +---- +format is known as extended tar format or pax format +vendor-tagged vendor-specific enhancements. +tags Defined by the POSIX standard: + atime, mtime, path, linkpath, uname, gname, size, uid, gid, ... + + +PAX EXTENSION +----------- +Hard links +A further difference from the ustar header block is that data blocks +for files of typeflag 1 (hard link) may be included, +which means that the size field may be greater than zero. +Archives created by pax -o linkdata shall include these data +blocks with the hard links. +* + +compatiblity +------------ + 7-Zip 16.03 supports "PaxHeader/" + 7-Zip 20.01 supports "PaxHeaders.X/" with optional "./" + 7-Zip 21.02 supports "@PaxHeader" with optional "./" "./" + + GNU tar --format=posix uses "PaxHeaders/" in folder of file + + +GNU TAR format +============== +v7 - Unix V7 +oldgnu - GNU tar <=1.12 : writes zero in last character in name +gnu - GNU tar 1.13 : doesn't write zero in last character in name + as 7-zip 21.07 +ustar - POSIX.1-1988 +posix (pax) - POSIX.1-2001 + + gnu tar: + if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) { + major_t devmajor = major (st->stat.st_rdev); + minor_t devminor = minor (st->stat.st_rdev); } +*/ + +}}} diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h index e96fa716d..aeccd286c 100644 --- a/CPP/7zip/Archive/Tar/TarHeader.h +++ b/CPP/7zip/Archive/Tar/TarHeader.h @@ -1,90 +1,90 @@ -// Archive/TarHeader.h - -#ifndef ZIP7_INC_ARCHIVE_TAR_HEADER_H -#define ZIP7_INC_ARCHIVE_TAR_HEADER_H - -#include "../../../Common/MyTypes.h" - -namespace NArchive { -namespace NTar { - -namespace NFileHeader -{ - const unsigned kRecordSize = 512; - const unsigned kNameSize = 100; - const unsigned kUserNameSize = 32; - const unsigned kGroupNameSize = 32; - const unsigned kPrefixSize = 155; - - const unsigned kUstarMagic_Offset = 257; - - /* - struct CHeader - { - char Name[kNameSize]; - char Mode[8]; - char UID[8]; - char GID[8]; - char Size[12]; - char ModificationTime[12]; - char CheckSum[8]; - char LinkFlag; - char LinkName[kNameSize]; - char Magic[8]; - char UserName[kUserNameSize]; - char GroupName[kGroupNameSize]; - char DeviceMajor[8]; - char DeviceMinor[8]; - char Prefix[155]; - }; - union CRecord - { - CHeader Header; - Byte Padding[kRecordSize]; - }; - */ - - namespace NLinkFlag - { - const char kOldNormal = 0; // Normal disk file, Unix compatible - const char kNormal = '0'; // Normal disk file - const char kHardLink = '1'; // Link to previously dumped file - const char kSymLink = '2'; // Symbolic link - const char kCharacter = '3'; // Character special file - const char kBlock = '4'; // Block special file - const char kDirectory = '5'; // Directory - const char kFIFO = '6'; // FIFO special file - const char kContiguous = '7'; // Contiguous file - const char kGnu_LongLink = 'K'; - const char kGnu_LongName = 'L'; - const char kSparse = 'S'; - const char kLabel = 'V'; - const char kPax = 'x'; // Extended header with meta data for the next file in the archive (POSIX.1-2001) - const char kPax_2 = 'X'; - const char kGlobal = 'g'; // Global extended header with meta data (POSIX.1-2001) - const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR. - data: list of files created by the --incremental (-G) option - Each file name is preceded by either - - 'Y' (file should be in this archive) - - 'N' (file is a directory, or is not stored in the archive.) - Each file name is terminated by a null + an additional null after - the last file name. */ - // 'A'-'Z' Vendor specific extensions (POSIX.1-1988) - } - - extern const char * const kLongLink; // = "././@LongLink"; - extern const char * const kLongLink2; // = "@LongLink"; - - namespace NMagic - { - // extern const char * const kUsTar; // = "ustar"; // 5 chars - // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null - // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0" - extern const char k_Posix_ustar_00[8]; - extern const char k_GNU_ustar[8]; - } -} - -}} - -#endif +// Archive/TarHeader.h + +#ifndef ZIP7_INC_ARCHIVE_TAR_HEADER_H +#define ZIP7_INC_ARCHIVE_TAR_HEADER_H + +#include "../../../Common/MyTypes.h" + +namespace NArchive { +namespace NTar { + +namespace NFileHeader +{ + const unsigned kRecordSize = 512; + const unsigned kNameSize = 100; + const unsigned kUserNameSize = 32; + const unsigned kGroupNameSize = 32; + const unsigned kPrefixSize = 155; + + const unsigned kUstarMagic_Offset = 257; + + /* + struct CHeader + { + char Name[kNameSize]; + char Mode[8]; + char UID[8]; + char GID[8]; + char Size[12]; + char ModificationTime[12]; + char CheckSum[8]; + char LinkFlag; + char LinkName[kNameSize]; + char Magic[8]; + char UserName[kUserNameSize]; + char GroupName[kGroupNameSize]; + char DeviceMajor[8]; + char DeviceMinor[8]; + char Prefix[155]; + }; + union CRecord + { + CHeader Header; + Byte Padding[kRecordSize]; + }; + */ + + namespace NLinkFlag + { + const char kOldNormal = 0; // Normal disk file, Unix compatible + const char kNormal = '0'; // Normal disk file + const char kHardLink = '1'; // Link to previously dumped file + const char kSymLink = '2'; // Symbolic link + const char kCharacter = '3'; // Character special file + const char kBlock = '4'; // Block special file + const char kDirectory = '5'; // Directory + const char kFIFO = '6'; // FIFO special file + const char kContiguous = '7'; // Contiguous file + const char kGnu_LongLink = 'K'; + const char kGnu_LongName = 'L'; + const char kSparse = 'S'; + const char kLabel = 'V'; + const char kPax = 'x'; // Extended header with meta data for the next file in the archive (POSIX.1-2001) + const char kPax_2 = 'X'; + const char kGlobal = 'g'; // Global extended header with meta data (POSIX.1-2001) + const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR. + data: list of files created by the --incremental (-G) option + Each file name is preceded by either + - 'Y' (file should be in this archive) + - 'N' (file is a directory, or is not stored in the archive.) + Each file name is terminated by a null + an additional null after + the last file name. */ + // 'A'-'Z' Vendor specific extensions (POSIX.1-1988) + } + + extern const char * const kLongLink; // = "././@LongLink"; + extern const char * const kLongLink2; // = "@LongLink"; + + namespace NMagic + { + // extern const char * const kUsTar; // = "ustar"; // 5 chars + // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null + // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0" + extern const char k_Posix_ustar_00[8]; + extern const char k_GNU_ustar[8]; + } +} + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp index aca234124..22b89022a 100644 --- a/CPP/7zip/Archive/Tar/TarIn.cpp +++ b/CPP/7zip/Archive/Tar/TarIn.cpp @@ -1,1150 +1,1150 @@ -// TarIn.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/StringToInt.h" - -#include "../../Common/StreamUtils.h" - -#include "../IArchive.h" - -#include "TarIn.h" - -#define NUM_UNROLL_BYTES (8 * 4) - -Z7_NO_INLINE static bool IsBufNonZero(const void *data, size_t size); -Z7_NO_INLINE static bool IsBufNonZero(const void *data, size_t size) -{ - const Byte *p = (const Byte *)data; - - for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--) - if (*p++ != 0) - return true; - - if (size >= NUM_UNROLL_BYTES) - { - const Byte *lim = p + size; - size &= (NUM_UNROLL_BYTES - 1); - lim -= size; - do - { - if (*(const UInt64 *)(const void *)(p ) != 0) return true; - if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true; - if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true; - if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true; - // if (*(const UInt32 *)(const void *)(p ) != 0) return true; - // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true; - // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true; - // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true; - p += NUM_UNROLL_BYTES; - } - while (p != lim); - } - - for (; size != 0; size--) - if (*p++ != 0) - return true; - - return false; -} - - -namespace NArchive { -namespace NTar { - -static void MyStrNCpy(char *dest, const char *src, unsigned size) -{ - for (unsigned i = 0; i < size; i++) - { - char c = src[i]; - dest[i] = c; - if (c == 0) - break; - } -} - -static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, bool allowEmpty = false) -{ - res = 0; - char sz[32]; - MyStrNCpy(sz, srcString, size); - sz[size] = 0; - const char *end; - unsigned i; - for (i = 0; sz[i] == ' '; i++); - if (sz[i] == 0) - return allowEmpty; - res = ConvertOctStringToUInt64(sz + i, &end); - return (*end == ' ' || *end == 0); -} - -static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false) -{ - const unsigned kSize = 8; - UInt64 res64; - if (!OctalToNumber(srcString, kSize, res64, allowEmpty)) - return false; - res = (UInt32)res64; - return (res64 <= 0xFFFFFFFF); -} - -#define RIF(x) { if (!(x)) return S_OK; } - -static void ReadString(const char *s, unsigned size, AString &result) -{ - result.SetFrom_CalcLen(s, size); -} - -static bool ParseInt64(const char *p, Int64 &val, bool &isBin) -{ - const UInt32 h = GetBe32(p); - val = (Int64)GetBe64(p + 4); - isBin = true; - if (h == (UInt32)1 << 31) - return ((val >> 63) & 1) == 0; - if (h == (UInt32)(Int32)-1) - return ((val >> 63) & 1) != 0; - isBin = false; - UInt64 u; - const bool res = OctalToNumber(p, 12, u); - val = (Int64)u; - return res; -} - -static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin) -{ - // rare case tar : ZEROs in Docker-Windows TARs - // rare case tar : spaces - isBin = false; - if (GetUi32(p) != 0) - for (unsigned i = 0; i < 12; i++) - if (p[i] != ' ') - return ParseInt64(p, val, isBin); - val = 0; - return true; -} - -static bool ParseSize(const char *p, UInt64 &val, bool &isBin) -{ - if (GetBe32(p) == (UInt32)1 << 31) - { - // GNU extension - isBin = true; - val = GetBe64(p + 4); - return ((val >> 63) & 1) == 0; - } - isBin = false; - return OctalToNumber(p, 12, val, - true // 20.03: allow empty size for 'V' Label entry - ); -} - -static bool ParseSize(const char *p, UInt64 &val) -{ - bool isBin; - return ParseSize(p, val, isBin); -} - -#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; } - -API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size) -{ - if (size < NFileHeader::kRecordSize) - return k_IsArc_Res_NEED_MORE; - - const char *p = (const char *)p2; - p += NFileHeader::kNameSize; - - UInt32 mode; - // we allow empty Mode value for LongName prefix items - CHECK(OctalToNumber32(p, mode, true)) p += 8; - - // if (!OctalToNumber32(p, item.UID)) item.UID = 0; - p += 8; - // if (!OctalToNumber32(p, item.GID)) item.GID = 0; - p += 8; - - UInt64 packSize; - Int64 time; - UInt32 checkSum; - bool isBin; - CHECK(ParseSize(p, packSize, isBin)) p += 12; - CHECK(ParseInt64_MTime(p, time, isBin)) p += 12; - CHECK(OctalToNumber32(p, checkSum)) - return k_IsArc_Res_YES; -} - - -HRESULT CArchive::GetNextItemReal(CItemEx &item) -{ - char buf[NFileHeader::kRecordSize]; - - error = k_ErrorType_OK; - filled = false; - - bool thereAreEmptyRecords = false; - for (;;) - { - size_t processedSize = NFileHeader::kRecordSize; - RINOK(ReadStream(SeqStream, buf, &processedSize)) - if (processedSize == 0) - { - if (!thereAreEmptyRecords) - error = k_ErrorType_UnexpectedEnd; // "There are no trailing zero-filled records"; - return S_OK; - } - if (processedSize != NFileHeader::kRecordSize) - { - if (!thereAreEmptyRecords) - error = k_ErrorType_UnexpectedEnd; // error = "There is no correct record at the end of archive"; - else - { - /* - if (IsEmptyData(buf, processedSize)) - error = k_ErrorType_UnexpectedEnd; - else - { - // extraReadSize = processedSize; - // error = k_ErrorType_Corrupted; // some data after the end tail zeros - } - */ - } - - return S_OK; - } - if (IsBufNonZero(buf, NFileHeader::kRecordSize)) - break; - item.HeaderSize += NFileHeader::kRecordSize; - thereAreEmptyRecords = true; - if (OpenCallback) - { - RINOK(Progress(item, 0)) - } - } - if (thereAreEmptyRecords) - { - // error = "There are data after end of archive"; - return S_OK; - } - - char *p = buf; - - error = k_ErrorType_Corrupted; - - // ReadString(p, NFileHeader::kNameSize, item.Name); - p += NFileHeader::kNameSize; - - /* - item.Name_CouldBeReduced = - (item.Name.Len() == NFileHeader::kNameSize || - item.Name.Len() == NFileHeader::kNameSize - 1); - */ - - // we allow empty Mode value for LongName prefix items - RIF(OctalToNumber32(p, item.Mode, true)) p += 8; - - if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8; - if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8; - - RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin)) - item.Size = item.PackSize; - item.Size_IsBin = item.PackSize_IsBin; - p += 12; - RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)) p += 12; - - UInt32 checkSum; - RIF(OctalToNumber32(p, checkSum)) - memset(p, ' ', 8); p += 8; - - item.LinkFlag = *p++; - - ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; - - /* - item.LinkName_CouldBeReduced = - (item.LinkName.Len() == NFileHeader::kNameSize || - item.LinkName.Len() == NFileHeader::kNameSize - 1); - */ - - memcpy(item.Magic, p, 8); p += 8; - - ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize; - ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize; - - item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)) } p += 8; - item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)) } p += 8; - - if (p[0] != 0 - && item.IsMagic_ustar_5chars() - && (item.LinkFlag != 'L' )) - { - item.Prefix_WasUsed = true; - ReadString(p, NFileHeader::kPrefixSize, item.Name); - item.Name.Add_Slash(); - unsigned i; - for (i = 0; i < NFileHeader::kNameSize; i++) - if (buf[i] == 0) - break; - item.Name.AddFrom(buf, i); - } - else - ReadString(buf, NFileHeader::kNameSize, item.Name); - - p += NFileHeader::kPrefixSize; - - if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) - { - item.PackSize = 0; - item.Size = 0; - } - - if (item.LinkFlag == NFileHeader::NLinkFlag::kDirectory) - { - // GNU tar ignores Size field, if LinkFlag is kDirectory - // 21.02 : we set PackSize = 0 to be more compatible with GNU tar - item.PackSize = 0; - // item.Size = 0; - } - - /* - TAR standard requires sum of unsigned byte values. - But some old TAR programs use sum of signed byte values. - So we check both values. - */ - // for (int y = 0; y < 100; y++) // for debug - { - UInt32 sum0 = 0; - { - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - sum0 += (Byte)buf[i]; - } - if (sum0 != checkSum) - { - Int32 sum = 0; - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - sum += (signed char)buf[i]; - if ((UInt32)sum != checkSum) - return S_OK; - item.IsSignedChecksum = true; - } - } - - item.HeaderSize += NFileHeader::kRecordSize; - - if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) - { - Byte isExtended = (Byte)buf[482]; - if (isExtended != 0 && isExtended != 1) - return S_OK; - RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin)) - UInt64 min = 0; - for (unsigned i = 0; i < 4; i++) - { - p = buf + 386 + 24 * i; - if (GetBe32(p) == 0) - { - if (isExtended != 0) - return S_OK; - break; - } - CSparseBlock sb; - RIF(ParseSize(p, sb.Offset)) - RIF(ParseSize(p + 12, sb.Size)) - item.SparseBlocks.Add(sb); - if (sb.Offset < min || sb.Offset > item.Size) - return S_OK; - if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) - return S_OK; - min = sb.Offset + sb.Size; - if (min < sb.Offset) - return S_OK; - } - if (min > item.Size) - return S_OK; - - while (isExtended != 0) - { - size_t processedSize = NFileHeader::kRecordSize; - RINOK(ReadStream(SeqStream, buf, &processedSize)) - if (processedSize != NFileHeader::kRecordSize) - { - error = k_ErrorType_UnexpectedEnd; - return S_OK; - } - - item.HeaderSize += NFileHeader::kRecordSize; - - if (OpenCallback) - { - RINOK(Progress(item, 0)) - } - - isExtended = (Byte)buf[21 * 24]; - if (isExtended != 0 && isExtended != 1) - return S_OK; - for (unsigned i = 0; i < 21; i++) - { - p = buf + 24 * i; - if (GetBe32(p) == 0) - { - if (isExtended != 0) - return S_OK; - break; - } - CSparseBlock sb; - RIF(ParseSize(p, sb.Offset)) - RIF(ParseSize(p + 12, sb.Size)) - item.SparseBlocks.Add(sb); - if (sb.Offset < min || sb.Offset > item.Size) - return S_OK; - if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) - return S_OK; - min = sb.Offset + sb.Size; - if (min < sb.Offset) - return S_OK; - } - } - if (min > item.Size) - return S_OK; - } - - if (item.PackSize >= (UInt64)1 << 63) - return S_OK; - - filled = true; - error = k_ErrorType_OK; - return S_OK; -} - - -HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset) -{ - const UInt64 pos = item.Get_DataPos() + posOffset; - if (NumFiles - NumFiles_Prev < (1 << 16) - // && NumRecords - NumRecords_Prev < (1 << 16) - && pos - Pos_Prev < ((UInt32)1 << 28)) - return S_OK; - { - Pos_Prev = pos; - NumFiles_Prev = NumFiles; - // NumRecords_Prev = NumRecords; - // Sleep(100); // for debug - return OpenCallback->SetCompleted(&NumFiles, &pos); - } -} - - -HRESULT CArchive::ReadDataToBuffer(const CItemEx &item, - CTempBuffer &tb, size_t stringLimit) -{ - tb.Init(); - UInt64 packSize = item.Get_PackSize_Aligned(); - if (packSize == 0) - return S_OK; - - UInt64 pos; - - { - size_t size = stringLimit; - if (size > packSize) - size = (size_t)packSize; - tb.Buffer.AllocAtLeast(size); - size_t processedSize = size; - const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize); - pos = processedSize; - if (processedSize != size) - { - error = k_ErrorType_UnexpectedEnd; - return res; - } - RINOK(res) - - packSize -= size; - - size_t i; - const Byte *p = tb.Buffer; - for (i = 0; i < size; i++) - if (p[i] == 0) - break; - if (i >= item.PackSize) - tb.StringSize_IsConfirmed = true; - if (i > item.PackSize) - { - tb.StringSize = (size_t)item.PackSize; - tb.IsNonZeroTail = true; - } - else - { - tb.StringSize = i; - if (i != size) - { - tb.StringSize_IsConfirmed = true; - if (IsBufNonZero(p + i, size - i)) - tb.IsNonZeroTail = true; - } - } - - if (packSize == 0) - return S_OK; - } - - if (InStream) - { - RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL)) - return S_OK; - } - const unsigned kBufSize = 1 << 15; - Buffer.AllocAtLeast(kBufSize); - - do - { - if (OpenCallback) - { - RINOK(Progress(item, pos)) - } - - unsigned size = kBufSize; - if (size > packSize) - size = (unsigned)packSize; - size_t processedSize = size; - const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize); - if (processedSize != size) - { - error = k_ErrorType_UnexpectedEnd; - return res; - } - if (!tb.IsNonZeroTail) - { - if (IsBufNonZero(Buffer, size)) - tb.IsNonZeroTail = true; - } - packSize -= size; - pos += size; - } - while (packSize != 0); - return S_OK; -} - - - -struct CPaxInfo: public CPaxTimes -{ - bool DoubleTagError; - bool TagParsingError; - bool UnknownLines_Overflow; - bool Size_Defined; - bool UID_Defined; - bool GID_Defined; - bool Path_Defined; - bool Link_Defined; - bool User_Defined; - bool Group_Defined; - bool SCHILY_fflags_Defined; - - UInt64 Size; - UInt32 UID; - UInt32 GID; - - AString Path; - AString Link; - AString User; - AString Group; - AString UnknownLines; - AString SCHILY_fflags; - - bool ParseID(const AString &val, bool &defined, UInt32 &res) - { - if (defined) - DoubleTagError = true; - if (val.IsEmpty()) - return false; - const char *end2; - res = ConvertStringToUInt32(val.Ptr(), &end2); - if (*end2 != 0) - return false; - defined = true; - return true; - } - - bool ParsePax(const CTempBuffer &tb, bool isFile); -}; - - -static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError) -{ - if (pt.IsDefined()) - doubleTagError = true; - pt.Clear(); - const char *s = src.Ptr(); - bool isNegative = false; - if (*s == '-') - { - isNegative = true; - s++; - } - const char *end; - { - UInt64 sec = ConvertStringToUInt64(s, &end); - if (s == end) - return false; - if (sec >= ((UInt64)1 << 63)) - return false; - if (isNegative) - sec = (UInt64)-(Int64)sec; - pt.Sec = (Int64)sec; - } - if (*end == 0) - { - pt.Ns = 0; - pt.NumDigits = 0; - return true; - } - if (*end != '.') - return false; - s = end + 1; - - UInt32 ns = 0; - unsigned i; - const unsigned kNsDigits = 9; - for (i = 0;; i++) - { - const char c = s[i]; - if (c == 0) - break; - if (c < '0' || c > '9') - return false; - // we ignore digits after 9 digits as GNU TAR - if (i < kNsDigits) - { - ns *= 10; - ns += (unsigned)(c - '0'); - } - } - pt.NumDigits = (int)(i < kNsDigits ? i : kNsDigits); - while (i < kNsDigits) - { - ns *= 10; - i++; - } - if (isNegative && ns != 0) - { - pt.Sec--; - ns = (UInt32)1000 * 1000 * 1000 - ns; - } - pt.Ns = ns; - return true; -} - - -bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile) -{ - DoubleTagError = false; - TagParsingError = false; - UnknownLines_Overflow = false; - Size_Defined = false; - UID_Defined = false; - GID_Defined = false; - Path_Defined = false; - Link_Defined = false; - User_Defined = false; - Group_Defined = false; - SCHILY_fflags_Defined = false; - - // CPaxTimes::Clear(); - - const char *s = (const char *)(const void *)(const Byte *)tb.Buffer; - size_t rem = tb.StringSize; - - Clear(); - - AString name, val; - - while (rem != 0) - { - unsigned i; - for (i = 0;; i++) - { - if (i > 24 || i >= rem) // we use limitation for size of (size) field - return false; - if (s[i] == ' ') - break; - } - if (i == 0) - return false; - const char *end; - const UInt32 size = ConvertStringToUInt32(s, &end); - const unsigned offset = (unsigned)(end - s) + 1; - if (size > rem - || size <= offset + 1 - || offset != i + 1 - || s[size - 1] != '\n') - return false; - - for (i = offset; i < size; i++) - if (s[i] == 0) - return false; - - for (i = offset; i < size - 1; i++) - if (s[i] == '=') - break; - if (i == size - 1) - return false; - - name.SetFrom(s + offset, i - offset); - val.SetFrom(s + i + 1, (unsigned)(size - 1 - (i + 1))); - - bool parsed = false; - if (isFile) - { - bool isDetectedName = true; - // only lower case (name) is supported - if (name.IsEqualTo("path")) - { - if (Path_Defined) - DoubleTagError = true; - Path = val; - Path_Defined = true; - parsed = true; - } - else if (name.IsEqualTo("linkpath")) - { - if (Link_Defined) - DoubleTagError = true; - Link = val; - Link_Defined = true; - parsed = true; - } - else if (name.IsEqualTo("uname")) - { - if (User_Defined) - DoubleTagError = true; - User = val; - User_Defined = true; - parsed = true; - } - else if (name.IsEqualTo("gname")) - { - if (Group_Defined) - DoubleTagError = true; - Group = val; - Group_Defined = true; - parsed = true; - } - else if (name.IsEqualTo("uid")) - { - parsed = ParseID(val, UID_Defined, UID); - } - else if (name.IsEqualTo("gid")) - { - parsed = ParseID(val, GID_Defined, GID); - } - else if (name.IsEqualTo("size")) - { - if (Size_Defined) - DoubleTagError = true; - Size_Defined = false; - if (!val.IsEmpty()) - { - const char *end2; - Size = ConvertStringToUInt64(val.Ptr(), &end2); - if (*end2 == 0) - { - Size_Defined = true; - parsed = true; - } - } - } - else if (name.IsEqualTo("mtime")) - { parsed = ParsePaxTime(val, MTime, DoubleTagError); } - else if (name.IsEqualTo("atime")) - { parsed = ParsePaxTime(val, ATime, DoubleTagError); } - else if (name.IsEqualTo("ctime")) - { parsed = ParsePaxTime(val, CTime, DoubleTagError); } - else if (name.IsEqualTo("SCHILY.fflags")) - { - if (SCHILY_fflags_Defined) - DoubleTagError = true; - SCHILY_fflags = val; - SCHILY_fflags_Defined = true; - parsed = true; - } - else - isDetectedName = false; - if (isDetectedName && !parsed) - TagParsingError = true; - } - if (!parsed) - { - if (!UnknownLines_Overflow) - { - const unsigned addSize = size - offset; - if (UnknownLines.Len() + addSize < (1 << 16)) - UnknownLines.AddFrom(s + offset, addSize); - else - UnknownLines_Overflow = true; - } - } - - s += size; - rem -= size; - } - return true; -} - - -HRESULT CArchive::ReadItem2(CItemEx &item) -{ - // CItem - - item.SparseBlocks.Clear(); - item.PaxTimes.Clear(); - - // CItemEx - - item.HeaderSize = 0; - item.Num_Pax_Records = 0; - - item.LongName_WasUsed = false; - item.LongName_WasUsed_2 = false; - - item.LongLink_WasUsed = false; - item.LongLink_WasUsed_2 = false; - - item.HeaderError = false; - item.IsSignedChecksum = false; - item.Prefix_WasUsed = false; - - item.Pax_Error = false; - item.Pax_Overflow = false; - item.pax_path_WasUsed = false; - item.pax_link_WasUsed = false; - item.pax_size_WasUsed = false; - - item.PaxExtra.Clear(); - item.SCHILY_fflags.Empty(); - - item.EncodingCharacts.Clear(); - - // CArchive temp variable - - NameBuf.Init(); - LinkBuf.Init(); - PaxBuf.Init(); - PaxBuf_global.Init(); - - UInt64 numExtraRecords = 0; - - for (;;) - { - if (OpenCallback) - { - RINOK(Progress(item, 0)) - } - - RINOK(GetNextItemReal(item)) - - // NumRecords++; - - if (!filled) - { - if (error == k_ErrorType_OK) - if (numExtraRecords != 0 - || item.LongName_WasUsed - || item.LongLink_WasUsed - || item.Num_Pax_Records != 0) - error = k_ErrorType_Corrupted; - return S_OK; - } - if (error != k_ErrorType_OK) - return S_OK; - - numExtraRecords++; - - const char lf = item.LinkFlag; - if (lf == NFileHeader::NLinkFlag::kGnu_LongName || - lf == NFileHeader::NLinkFlag::kGnu_LongLink) - { - // GNU tar ignores item.Name after LinkFlag test - // 22.00 : now we also ignore item.Name here - /* - if (item.Name != NFileHeader::kLongLink && - item.Name != NFileHeader::kLongLink2) - { - break; - // return S_OK; - } - */ - - CTempBuffer *tb = - lf == NFileHeader::NLinkFlag::kGnu_LongName ? - &NameBuf : - &LinkBuf; - - /* - if (item.PackSize > (1 << 29)) - { - // break; - return S_OK; - } - */ - - const unsigned kLongNameSizeMax = (unsigned)1 << 14; - RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax)) - if (error != k_ErrorType_OK) - return S_OK; - - if (lf == NFileHeader::NLinkFlag::kGnu_LongName) - { - item.LongName_WasUsed_2 = - item.LongName_WasUsed; - item.LongName_WasUsed = true; - } - else - { - item.LongLink_WasUsed_2 = - item.LongLink_WasUsed; - item.LongLink_WasUsed = true; - } - - if (!tb->StringSize_IsConfirmed) - tb->StringSize = 0; - item.HeaderSize += item.Get_PackSize_Aligned(); - if (tb->StringSize == 0 || - tb->StringSize + 1 != item.PackSize) - item.HeaderError = true; - if (tb->IsNonZeroTail) - item.HeaderError = true; - continue; - } - - if (lf == NFileHeader::NLinkFlag::kGlobal || - lf == NFileHeader::NLinkFlag::kPax || - lf == NFileHeader::NLinkFlag::kPax_2) - { - // GNU tar ignores item.Name after LinkFlag test - // 22.00 : now we also ignore item.Name here - /* - if (item.PackSize > (UInt32)1 << 26) - { - break; // we don't want big PaxBuf files - // return S_OK; - } - */ - const unsigned kParsingPaxSizeMax = (unsigned)1 << 26; - - const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize); - - CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf); - - RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax)) - if (error != k_ErrorType_OK) - return S_OK; - - item.HeaderSize += item.Get_PackSize_Aligned(); - - if (tb->StringSize != item.PackSize - || tb->StringSize == 0 - || tb->IsNonZeroTail) - item.Pax_Error = true; - - item.Num_Pax_Records++; - if (lf != NFileHeader::NLinkFlag::kGlobal) - { - item.PaxExtra.RecordPath = item.Name; - continue; - } - // break; // for debug - { - if (PaxGlobal_Defined) - _is_PaxGlobal_Error = true; - CPaxInfo paxInfo; - if (paxInfo.ParsePax(PaxBuf_global, false)) - { - PaxGlobal.RawLines = paxInfo.UnknownLines; - PaxGlobal.RecordPath = item.Name; - PaxGlobal_Defined = true; - } - else - _is_PaxGlobal_Error = true; - - if (isStartHeader - && item.Num_Pax_Records == 1 - && numExtraRecords == 1) - { - // we skip global pax header info after parsing - item.HeaderPos += item.HeaderSize; - item.HeaderSize = 0; - item.Num_Pax_Records = 0; - numExtraRecords = 0; - } - else - _is_PaxGlobal_Error = true; - } - continue; - } - - /* - if (lf == NFileHeader::NLinkFlag::kDumpDir || - lf == NFileHeader::NLinkFlag::kSparse) - { - // GNU Extensions to the Archive Format - break; - } - if (lf > '7' || (lf < '0' && lf != 0)) - { - break; - // return S_OK; - } - */ - break; - } - - // we still use name from main header, if long_name is bad - if (item.LongName_WasUsed && NameBuf.StringSize != 0) - { - NameBuf.CopyToString(item.Name); - // item.Name_CouldBeReduced = false; - } - - if (item.LongLink_WasUsed) - { - // we use empty link, if long_link is bad - LinkBuf.CopyToString(item.LinkName); - // item.LinkName_CouldBeReduced = false; - } - - error = k_ErrorType_OK; - - if (PaxBuf.StringSize != 0) - { - CPaxInfo paxInfo; - if (!paxInfo.ParsePax(PaxBuf, true)) - item.Pax_Error = true; - else - { - if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty()) - { - item.Name = paxInfo.Path; - item.pax_path_WasUsed = true; - } - if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty()) - { - item.LinkName = paxInfo.Link; - item.pax_link_WasUsed = true; - } - if (paxInfo.User_Defined) - { - item.User = paxInfo.User; - // item.pax_uname_WasUsed = true; - } - if (paxInfo.Group_Defined) - { - item.Group = paxInfo.Group; - // item.pax_gname_WasUsed = true; - } - if (paxInfo.SCHILY_fflags_Defined) - { - item.SCHILY_fflags = paxInfo.SCHILY_fflags; - // item.SCHILY_fflags_WasUsed = true; - } - if (paxInfo.UID_Defined) - { - item.UID = (UInt32)paxInfo.UID; - } - if (paxInfo.GID_Defined) - { - item.GID = (UInt32)paxInfo.GID; - } - - if (paxInfo.Size_Defined) - { - const UInt64 piSize = paxInfo.Size; - // GNU TAR ignores (item.Size) in that case - if (item.Size != 0 && item.Size != piSize) - item.Pax_Error = true; - item.Size = piSize; - item.PackSize = piSize; - item.pax_size_WasUsed = true; - } - - item.PaxTimes = paxInfo; - item.PaxExtra.RawLines = paxInfo.UnknownLines; - if (paxInfo.UnknownLines_Overflow) - item.Pax_Overflow = true; - if (paxInfo.TagParsingError) - item.Pax_Error = true; - if (paxInfo.DoubleTagError) - item.Pax_Error = true; - } - } - - return S_OK; -} - - - -HRESULT CArchive::ReadItem(CItemEx &item) -{ - item.HeaderPos = _phySize; - - const HRESULT res = ReadItem2(item); - - /* - if (error == k_ErrorType_Warning) - _is_Warning = true; - else - */ - - if (error != k_ErrorType_OK) - _error = error; - - RINOK(res) - - if (filled) - { - if (item.IsMagic_GNU()) - _are_Gnu = true; - else if (item.IsMagic_Posix_ustar_00()) - _are_Posix = true; - - if (item.Num_Pax_Records != 0) - _are_Pax = true; - - if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true; - if (item.PaxTimes.ATime.IsDefined()) _are_atime = true; - if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true; - if (!item.SCHILY_fflags.IsEmpty()) _are_SCHILY_fflags = true; - - if (item.pax_path_WasUsed) - _are_pax_path = true; - if (item.pax_link_WasUsed) - _are_pax_link = true; - if (item.LongName_WasUsed) - _are_LongName = true; - if (item.LongLink_WasUsed) - _are_LongLink = true; - if (item.Prefix_WasUsed) - _pathPrefix_WasUsed = true; - /* - if (item.IsSparse()) - _isSparse = true; - */ - if (item.Is_PaxExtendedHeader()) - _are_Pax_Items = true; - if (item.IsThereWarning() - || item.HeaderError - || item.Pax_Error) - _is_Warning = true; - } - - const UInt64 headerEnd = item.HeaderPos + item.HeaderSize; - // _headersSize += headerEnd - _phySize; - // we don't count skipped records - _headersSize += item.HeaderSize; - _phySize = headerEnd; - return S_OK; -} - -}} +// TarIn.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/StringToInt.h" + +#include "../../Common/StreamUtils.h" + +#include "../IArchive.h" + +#include "TarIn.h" + +#define NUM_UNROLL_BYTES (8 * 4) + +Z7_NO_INLINE static bool IsBufNonZero(const void *data, size_t size); +Z7_NO_INLINE static bool IsBufNonZero(const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + + for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--) + if (*p++ != 0) + return true; + + if (size >= NUM_UNROLL_BYTES) + { + const Byte *lim = p + size; + size &= (NUM_UNROLL_BYTES - 1); + lim -= size; + do + { + if (*(const UInt64 *)(const void *)(p ) != 0) return true; + if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true; + if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true; + if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true; + // if (*(const UInt32 *)(const void *)(p ) != 0) return true; + // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true; + // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true; + // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true; + p += NUM_UNROLL_BYTES; + } + while (p != lim); + } + + for (; size != 0; size--) + if (*p++ != 0) + return true; + + return false; +} + + +namespace NArchive { +namespace NTar { + +static void MyStrNCpy(char *dest, const char *src, unsigned size) +{ + for (unsigned i = 0; i < size; i++) + { + char c = src[i]; + dest[i] = c; + if (c == 0) + break; + } +} + +static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, bool allowEmpty = false) +{ + res = 0; + char sz[32]; + MyStrNCpy(sz, srcString, size); + sz[size] = 0; + const char *end; + unsigned i; + for (i = 0; sz[i] == ' '; i++); + if (sz[i] == 0) + return allowEmpty; + res = ConvertOctStringToUInt64(sz + i, &end); + return (*end == ' ' || *end == 0); +} + +static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false) +{ + const unsigned kSize = 8; + UInt64 res64; + if (!OctalToNumber(srcString, kSize, res64, allowEmpty)) + return false; + res = (UInt32)res64; + return (res64 <= 0xFFFFFFFF); +} + +#define RIF(x) { if (!(x)) return S_OK; } + +static void ReadString(const char *s, unsigned size, AString &result) +{ + result.SetFrom_CalcLen(s, size); +} + +static bool ParseInt64(const char *p, Int64 &val, bool &isBin) +{ + const UInt32 h = GetBe32(p); + val = (Int64)GetBe64(p + 4); + isBin = true; + if (h == (UInt32)1 << 31) + return ((val >> 63) & 1) == 0; + if (h == (UInt32)(Int32)-1) + return ((val >> 63) & 1) != 0; + isBin = false; + UInt64 u; + const bool res = OctalToNumber(p, 12, u); + val = (Int64)u; + return res; +} + +static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin) +{ + // rare case tar : ZEROs in Docker-Windows TARs + // rare case tar : spaces + isBin = false; + if (GetUi32(p) != 0) + for (unsigned i = 0; i < 12; i++) + if (p[i] != ' ') + return ParseInt64(p, val, isBin); + val = 0; + return true; +} + +static bool ParseSize(const char *p, UInt64 &val, bool &isBin) +{ + if (GetBe32(p) == (UInt32)1 << 31) + { + // GNU extension + isBin = true; + val = GetBe64(p + 4); + return ((val >> 63) & 1) == 0; + } + isBin = false; + return OctalToNumber(p, 12, val, + true // 20.03: allow empty size for 'V' Label entry + ); +} + +static bool ParseSize(const char *p, UInt64 &val) +{ + bool isBin; + return ParseSize(p, val, isBin); +} + +#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; } + +API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size) +{ + if (size < NFileHeader::kRecordSize) + return k_IsArc_Res_NEED_MORE; + + const char *p = (const char *)p2; + p += NFileHeader::kNameSize; + + UInt32 mode; + // we allow empty Mode value for LongName prefix items + CHECK(OctalToNumber32(p, mode, true)) p += 8; + + // if (!OctalToNumber32(p, item.UID)) item.UID = 0; + p += 8; + // if (!OctalToNumber32(p, item.GID)) item.GID = 0; + p += 8; + + UInt64 packSize; + Int64 time; + UInt32 checkSum; + bool isBin; + CHECK(ParseSize(p, packSize, isBin)) p += 12; + CHECK(ParseInt64_MTime(p, time, isBin)) p += 12; + CHECK(OctalToNumber32(p, checkSum)) + return k_IsArc_Res_YES; +} + + +HRESULT CArchive::GetNextItemReal(CItemEx &item) +{ + char buf[NFileHeader::kRecordSize]; + + error = k_ErrorType_OK; + filled = false; + + bool thereAreEmptyRecords = false; + for (;;) + { + size_t processedSize = NFileHeader::kRecordSize; + RINOK(ReadStream(SeqStream, buf, &processedSize)) + if (processedSize == 0) + { + if (!thereAreEmptyRecords) + error = k_ErrorType_UnexpectedEnd; // "There are no trailing zero-filled records"; + return S_OK; + } + if (processedSize != NFileHeader::kRecordSize) + { + if (!thereAreEmptyRecords) + error = k_ErrorType_UnexpectedEnd; // error = "There is no correct record at the end of archive"; + else + { + /* + if (IsEmptyData(buf, processedSize)) + error = k_ErrorType_UnexpectedEnd; + else + { + // extraReadSize = processedSize; + // error = k_ErrorType_Corrupted; // some data after the end tail zeros + } + */ + } + + return S_OK; + } + if (IsBufNonZero(buf, NFileHeader::kRecordSize)) + break; + item.HeaderSize += NFileHeader::kRecordSize; + thereAreEmptyRecords = true; + if (OpenCallback) + { + RINOK(Progress(item, 0)) + } + } + if (thereAreEmptyRecords) + { + // error = "There are data after end of archive"; + return S_OK; + } + + char *p = buf; + + error = k_ErrorType_Corrupted; + + // ReadString(p, NFileHeader::kNameSize, item.Name); + p += NFileHeader::kNameSize; + + /* + item.Name_CouldBeReduced = + (item.Name.Len() == NFileHeader::kNameSize || + item.Name.Len() == NFileHeader::kNameSize - 1); + */ + + // we allow empty Mode value for LongName prefix items + RIF(OctalToNumber32(p, item.Mode, true)) p += 8; + + if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8; + if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8; + + RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin)) + item.Size = item.PackSize; + item.Size_IsBin = item.PackSize_IsBin; + p += 12; + RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)) p += 12; + + UInt32 checkSum; + RIF(OctalToNumber32(p, checkSum)) + memset(p, ' ', 8); p += 8; + + item.LinkFlag = *p++; + + ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; + + /* + item.LinkName_CouldBeReduced = + (item.LinkName.Len() == NFileHeader::kNameSize || + item.LinkName.Len() == NFileHeader::kNameSize - 1); + */ + + memcpy(item.Magic, p, 8); p += 8; + + ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize; + ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize; + + item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)) } p += 8; + item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)) } p += 8; + + if (p[0] != 0 + && item.IsMagic_ustar_5chars() + && (item.LinkFlag != 'L' )) + { + item.Prefix_WasUsed = true; + ReadString(p, NFileHeader::kPrefixSize, item.Name); + item.Name.Add_Slash(); + unsigned i; + for (i = 0; i < NFileHeader::kNameSize; i++) + if (buf[i] == 0) + break; + item.Name.AddFrom(buf, i); + } + else + ReadString(buf, NFileHeader::kNameSize, item.Name); + + p += NFileHeader::kPrefixSize; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) + { + item.PackSize = 0; + item.Size = 0; + } + + if (item.LinkFlag == NFileHeader::NLinkFlag::kDirectory) + { + // GNU tar ignores Size field, if LinkFlag is kDirectory + // 21.02 : we set PackSize = 0 to be more compatible with GNU tar + item.PackSize = 0; + // item.Size = 0; + } + + /* + TAR standard requires sum of unsigned byte values. + But some old TAR programs use sum of signed byte values. + So we check both values. + */ + // for (int y = 0; y < 100; y++) // for debug + { + UInt32 sum0 = 0; + { + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + sum0 += (Byte)buf[i]; + } + if (sum0 != checkSum) + { + Int32 sum = 0; + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + sum += (signed char)buf[i]; + if ((UInt32)sum != checkSum) + return S_OK; + item.IsSignedChecksum = true; + } + } + + item.HeaderSize += NFileHeader::kRecordSize; + + if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse) + { + Byte isExtended = (Byte)buf[482]; + if (isExtended != 0 && isExtended != 1) + return S_OK; + RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin)) + UInt64 min = 0; + for (unsigned i = 0; i < 4; i++) + { + p = buf + 386 + 24 * i; + if (GetBe32(p) == 0) + { + if (isExtended != 0) + return S_OK; + break; + } + CSparseBlock sb; + RIF(ParseSize(p, sb.Offset)) + RIF(ParseSize(p + 12, sb.Size)) + item.SparseBlocks.Add(sb); + if (sb.Offset < min || sb.Offset > item.Size) + return S_OK; + if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) + return S_OK; + min = sb.Offset + sb.Size; + if (min < sb.Offset) + return S_OK; + } + if (min > item.Size) + return S_OK; + + while (isExtended != 0) + { + size_t processedSize = NFileHeader::kRecordSize; + RINOK(ReadStream(SeqStream, buf, &processedSize)) + if (processedSize != NFileHeader::kRecordSize) + { + error = k_ErrorType_UnexpectedEnd; + return S_OK; + } + + item.HeaderSize += NFileHeader::kRecordSize; + + if (OpenCallback) + { + RINOK(Progress(item, 0)) + } + + isExtended = (Byte)buf[21 * 24]; + if (isExtended != 0 && isExtended != 1) + return S_OK; + for (unsigned i = 0; i < 21; i++) + { + p = buf + 24 * i; + if (GetBe32(p) == 0) + { + if (isExtended != 0) + return S_OK; + break; + } + CSparseBlock sb; + RIF(ParseSize(p, sb.Offset)) + RIF(ParseSize(p + 12, sb.Size)) + item.SparseBlocks.Add(sb); + if (sb.Offset < min || sb.Offset > item.Size) + return S_OK; + if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0) + return S_OK; + min = sb.Offset + sb.Size; + if (min < sb.Offset) + return S_OK; + } + } + if (min > item.Size) + return S_OK; + } + + if (item.PackSize >= (UInt64)1 << 63) + return S_OK; + + filled = true; + error = k_ErrorType_OK; + return S_OK; +} + + +HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset) +{ + const UInt64 pos = item.Get_DataPos() + posOffset; + if (NumFiles - NumFiles_Prev < (1 << 16) + // && NumRecords - NumRecords_Prev < (1 << 16) + && pos - Pos_Prev < ((UInt32)1 << 28)) + return S_OK; + { + Pos_Prev = pos; + NumFiles_Prev = NumFiles; + // NumRecords_Prev = NumRecords; + // Sleep(100); // for debug + return OpenCallback->SetCompleted(&NumFiles, &pos); + } +} + + +HRESULT CArchive::ReadDataToBuffer(const CItemEx &item, + CTempBuffer &tb, size_t stringLimit) +{ + tb.Init(); + UInt64 packSize = item.Get_PackSize_Aligned(); + if (packSize == 0) + return S_OK; + + UInt64 pos; + + { + size_t size = stringLimit; + if (size > packSize) + size = (size_t)packSize; + tb.Buffer.AllocAtLeast(size); + size_t processedSize = size; + const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize); + pos = processedSize; + if (processedSize != size) + { + error = k_ErrorType_UnexpectedEnd; + return res; + } + RINOK(res) + + packSize -= size; + + size_t i; + const Byte *p = tb.Buffer; + for (i = 0; i < size; i++) + if (p[i] == 0) + break; + if (i >= item.PackSize) + tb.StringSize_IsConfirmed = true; + if (i > item.PackSize) + { + tb.StringSize = (size_t)item.PackSize; + tb.IsNonZeroTail = true; + } + else + { + tb.StringSize = i; + if (i != size) + { + tb.StringSize_IsConfirmed = true; + if (IsBufNonZero(p + i, size - i)) + tb.IsNonZeroTail = true; + } + } + + if (packSize == 0) + return S_OK; + } + + if (InStream) + { + RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL)) + return S_OK; + } + const unsigned kBufSize = 1 << 15; + Buffer.AllocAtLeast(kBufSize); + + do + { + if (OpenCallback) + { + RINOK(Progress(item, pos)) + } + + unsigned size = kBufSize; + if (size > packSize) + size = (unsigned)packSize; + size_t processedSize = size; + const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize); + if (processedSize != size) + { + error = k_ErrorType_UnexpectedEnd; + return res; + } + if (!tb.IsNonZeroTail) + { + if (IsBufNonZero(Buffer, size)) + tb.IsNonZeroTail = true; + } + packSize -= size; + pos += size; + } + while (packSize != 0); + return S_OK; +} + + + +struct CPaxInfo: public CPaxTimes +{ + bool DoubleTagError; + bool TagParsingError; + bool UnknownLines_Overflow; + bool Size_Defined; + bool UID_Defined; + bool GID_Defined; + bool Path_Defined; + bool Link_Defined; + bool User_Defined; + bool Group_Defined; + bool SCHILY_fflags_Defined; + + UInt64 Size; + UInt32 UID; + UInt32 GID; + + AString Path; + AString Link; + AString User; + AString Group; + AString UnknownLines; + AString SCHILY_fflags; + + bool ParseID(const AString &val, bool &defined, UInt32 &res) + { + if (defined) + DoubleTagError = true; + if (val.IsEmpty()) + return false; + const char *end2; + res = ConvertStringToUInt32(val.Ptr(), &end2); + if (*end2 != 0) + return false; + defined = true; + return true; + } + + bool ParsePax(const CTempBuffer &tb, bool isFile); +}; + + +static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError) +{ + if (pt.IsDefined()) + doubleTagError = true; + pt.Clear(); + const char *s = src.Ptr(); + bool isNegative = false; + if (*s == '-') + { + isNegative = true; + s++; + } + const char *end; + { + UInt64 sec = ConvertStringToUInt64(s, &end); + if (s == end) + return false; + if (sec >= ((UInt64)1 << 63)) + return false; + if (isNegative) + sec = (UInt64)-(Int64)sec; + pt.Sec = (Int64)sec; + } + if (*end == 0) + { + pt.Ns = 0; + pt.NumDigits = 0; + return true; + } + if (*end != '.') + return false; + s = end + 1; + + UInt32 ns = 0; + unsigned i; + const unsigned kNsDigits = 9; + for (i = 0;; i++) + { + const char c = s[i]; + if (c == 0) + break; + if (c < '0' || c > '9') + return false; + // we ignore digits after 9 digits as GNU TAR + if (i < kNsDigits) + { + ns *= 10; + ns += (unsigned)(c - '0'); + } + } + pt.NumDigits = (int)(i < kNsDigits ? i : kNsDigits); + while (i < kNsDigits) + { + ns *= 10; + i++; + } + if (isNegative && ns != 0) + { + pt.Sec--; + ns = (UInt32)1000 * 1000 * 1000 - ns; + } + pt.Ns = ns; + return true; +} + + +bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile) +{ + DoubleTagError = false; + TagParsingError = false; + UnknownLines_Overflow = false; + Size_Defined = false; + UID_Defined = false; + GID_Defined = false; + Path_Defined = false; + Link_Defined = false; + User_Defined = false; + Group_Defined = false; + SCHILY_fflags_Defined = false; + + // CPaxTimes::Clear(); + + const char *s = (const char *)(const void *)(const Byte *)tb.Buffer; + size_t rem = tb.StringSize; + + Clear(); + + AString name, val; + + while (rem != 0) + { + unsigned i; + for (i = 0;; i++) + { + if (i > 24 || i >= rem) // we use limitation for size of (size) field + return false; + if (s[i] == ' ') + break; + } + if (i == 0) + return false; + const char *end; + const UInt32 size = ConvertStringToUInt32(s, &end); + const unsigned offset = (unsigned)(end - s) + 1; + if (size > rem + || size <= offset + 1 + || offset != i + 1 + || s[size - 1] != '\n') + return false; + + for (i = offset; i < size; i++) + if (s[i] == 0) + return false; + + for (i = offset; i < size - 1; i++) + if (s[i] == '=') + break; + if (i == size - 1) + return false; + + name.SetFrom(s + offset, i - offset); + val.SetFrom(s + i + 1, (unsigned)(size - 1 - (i + 1))); + + bool parsed = false; + if (isFile) + { + bool isDetectedName = true; + // only lower case (name) is supported + if (name.IsEqualTo("path")) + { + if (Path_Defined) + DoubleTagError = true; + Path = val; + Path_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("linkpath")) + { + if (Link_Defined) + DoubleTagError = true; + Link = val; + Link_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("uname")) + { + if (User_Defined) + DoubleTagError = true; + User = val; + User_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("gname")) + { + if (Group_Defined) + DoubleTagError = true; + Group = val; + Group_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("uid")) + { + parsed = ParseID(val, UID_Defined, UID); + } + else if (name.IsEqualTo("gid")) + { + parsed = ParseID(val, GID_Defined, GID); + } + else if (name.IsEqualTo("size")) + { + if (Size_Defined) + DoubleTagError = true; + Size_Defined = false; + if (!val.IsEmpty()) + { + const char *end2; + Size = ConvertStringToUInt64(val.Ptr(), &end2); + if (*end2 == 0) + { + Size_Defined = true; + parsed = true; + } + } + } + else if (name.IsEqualTo("mtime")) + { parsed = ParsePaxTime(val, MTime, DoubleTagError); } + else if (name.IsEqualTo("atime")) + { parsed = ParsePaxTime(val, ATime, DoubleTagError); } + else if (name.IsEqualTo("ctime")) + { parsed = ParsePaxTime(val, CTime, DoubleTagError); } + else if (name.IsEqualTo("SCHILY.fflags")) + { + if (SCHILY_fflags_Defined) + DoubleTagError = true; + SCHILY_fflags = val; + SCHILY_fflags_Defined = true; + parsed = true; + } + else + isDetectedName = false; + if (isDetectedName && !parsed) + TagParsingError = true; + } + if (!parsed) + { + if (!UnknownLines_Overflow) + { + const unsigned addSize = size - offset; + if (UnknownLines.Len() + addSize < (1 << 16)) + UnknownLines.AddFrom(s + offset, addSize); + else + UnknownLines_Overflow = true; + } + } + + s += size; + rem -= size; + } + return true; +} + + +HRESULT CArchive::ReadItem2(CItemEx &item) +{ + // CItem + + item.SparseBlocks.Clear(); + item.PaxTimes.Clear(); + + // CItemEx + + item.HeaderSize = 0; + item.Num_Pax_Records = 0; + + item.LongName_WasUsed = false; + item.LongName_WasUsed_2 = false; + + item.LongLink_WasUsed = false; + item.LongLink_WasUsed_2 = false; + + item.HeaderError = false; + item.IsSignedChecksum = false; + item.Prefix_WasUsed = false; + + item.Pax_Error = false; + item.Pax_Overflow = false; + item.pax_path_WasUsed = false; + item.pax_link_WasUsed = false; + item.pax_size_WasUsed = false; + + item.PaxExtra.Clear(); + item.SCHILY_fflags.Empty(); + + item.EncodingCharacts.Clear(); + + // CArchive temp variable + + NameBuf.Init(); + LinkBuf.Init(); + PaxBuf.Init(); + PaxBuf_global.Init(); + + UInt64 numExtraRecords = 0; + + for (;;) + { + if (OpenCallback) + { + RINOK(Progress(item, 0)) + } + + RINOK(GetNextItemReal(item)) + + // NumRecords++; + + if (!filled) + { + if (error == k_ErrorType_OK) + if (numExtraRecords != 0 + || item.LongName_WasUsed + || item.LongLink_WasUsed + || item.Num_Pax_Records != 0) + error = k_ErrorType_Corrupted; + return S_OK; + } + if (error != k_ErrorType_OK) + return S_OK; + + numExtraRecords++; + + const char lf = item.LinkFlag; + if (lf == NFileHeader::NLinkFlag::kGnu_LongName || + lf == NFileHeader::NLinkFlag::kGnu_LongLink) + { + // GNU tar ignores item.Name after LinkFlag test + // 22.00 : now we also ignore item.Name here + /* + if (item.Name != NFileHeader::kLongLink && + item.Name != NFileHeader::kLongLink2) + { + break; + // return S_OK; + } + */ + + CTempBuffer *tb = + lf == NFileHeader::NLinkFlag::kGnu_LongName ? + &NameBuf : + &LinkBuf; + + /* + if (item.PackSize > (1 << 29)) + { + // break; + return S_OK; + } + */ + + const unsigned kLongNameSizeMax = (unsigned)1 << 14; + RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax)) + if (error != k_ErrorType_OK) + return S_OK; + + if (lf == NFileHeader::NLinkFlag::kGnu_LongName) + { + item.LongName_WasUsed_2 = + item.LongName_WasUsed; + item.LongName_WasUsed = true; + } + else + { + item.LongLink_WasUsed_2 = + item.LongLink_WasUsed; + item.LongLink_WasUsed = true; + } + + if (!tb->StringSize_IsConfirmed) + tb->StringSize = 0; + item.HeaderSize += item.Get_PackSize_Aligned(); + if (tb->StringSize == 0 || + tb->StringSize + 1 != item.PackSize) + item.HeaderError = true; + if (tb->IsNonZeroTail) + item.HeaderError = true; + continue; + } + + if (lf == NFileHeader::NLinkFlag::kGlobal || + lf == NFileHeader::NLinkFlag::kPax || + lf == NFileHeader::NLinkFlag::kPax_2) + { + // GNU tar ignores item.Name after LinkFlag test + // 22.00 : now we also ignore item.Name here + /* + if (item.PackSize > (UInt32)1 << 26) + { + break; // we don't want big PaxBuf files + // return S_OK; + } + */ + const unsigned kParsingPaxSizeMax = (unsigned)1 << 26; + + const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize); + + CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf); + + RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax)) + if (error != k_ErrorType_OK) + return S_OK; + + item.HeaderSize += item.Get_PackSize_Aligned(); + + if (tb->StringSize != item.PackSize + || tb->StringSize == 0 + || tb->IsNonZeroTail) + item.Pax_Error = true; + + item.Num_Pax_Records++; + if (lf != NFileHeader::NLinkFlag::kGlobal) + { + item.PaxExtra.RecordPath = item.Name; + continue; + } + // break; // for debug + { + if (PaxGlobal_Defined) + _is_PaxGlobal_Error = true; + CPaxInfo paxInfo; + if (paxInfo.ParsePax(PaxBuf_global, false)) + { + PaxGlobal.RawLines = paxInfo.UnknownLines; + PaxGlobal.RecordPath = item.Name; + PaxGlobal_Defined = true; + } + else + _is_PaxGlobal_Error = true; + + if (isStartHeader + && item.Num_Pax_Records == 1 + && numExtraRecords == 1) + { + // we skip global pax header info after parsing + item.HeaderPos += item.HeaderSize; + item.HeaderSize = 0; + item.Num_Pax_Records = 0; + numExtraRecords = 0; + } + else + _is_PaxGlobal_Error = true; + } + continue; + } + + /* + if (lf == NFileHeader::NLinkFlag::kDumpDir || + lf == NFileHeader::NLinkFlag::kSparse) + { + // GNU Extensions to the Archive Format + break; + } + if (lf > '7' || (lf < '0' && lf != 0)) + { + break; + // return S_OK; + } + */ + break; + } + + // we still use name from main header, if long_name is bad + if (item.LongName_WasUsed && NameBuf.StringSize != 0) + { + NameBuf.CopyToString(item.Name); + // item.Name_CouldBeReduced = false; + } + + if (item.LongLink_WasUsed) + { + // we use empty link, if long_link is bad + LinkBuf.CopyToString(item.LinkName); + // item.LinkName_CouldBeReduced = false; + } + + error = k_ErrorType_OK; + + if (PaxBuf.StringSize != 0) + { + CPaxInfo paxInfo; + if (!paxInfo.ParsePax(PaxBuf, true)) + item.Pax_Error = true; + else + { + if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty()) + { + item.Name = paxInfo.Path; + item.pax_path_WasUsed = true; + } + if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty()) + { + item.LinkName = paxInfo.Link; + item.pax_link_WasUsed = true; + } + if (paxInfo.User_Defined) + { + item.User = paxInfo.User; + // item.pax_uname_WasUsed = true; + } + if (paxInfo.Group_Defined) + { + item.Group = paxInfo.Group; + // item.pax_gname_WasUsed = true; + } + if (paxInfo.SCHILY_fflags_Defined) + { + item.SCHILY_fflags = paxInfo.SCHILY_fflags; + // item.SCHILY_fflags_WasUsed = true; + } + if (paxInfo.UID_Defined) + { + item.UID = (UInt32)paxInfo.UID; + } + if (paxInfo.GID_Defined) + { + item.GID = (UInt32)paxInfo.GID; + } + + if (paxInfo.Size_Defined) + { + const UInt64 piSize = paxInfo.Size; + // GNU TAR ignores (item.Size) in that case + if (item.Size != 0 && item.Size != piSize) + item.Pax_Error = true; + item.Size = piSize; + item.PackSize = piSize; + item.pax_size_WasUsed = true; + } + + item.PaxTimes = paxInfo; + item.PaxExtra.RawLines = paxInfo.UnknownLines; + if (paxInfo.UnknownLines_Overflow) + item.Pax_Overflow = true; + if (paxInfo.TagParsingError) + item.Pax_Error = true; + if (paxInfo.DoubleTagError) + item.Pax_Error = true; + } + } + + return S_OK; +} + + + +HRESULT CArchive::ReadItem(CItemEx &item) +{ + item.HeaderPos = _phySize; + + const HRESULT res = ReadItem2(item); + + /* + if (error == k_ErrorType_Warning) + _is_Warning = true; + else + */ + + if (error != k_ErrorType_OK) + _error = error; + + RINOK(res) + + if (filled) + { + if (item.IsMagic_GNU()) + _are_Gnu = true; + else if (item.IsMagic_Posix_ustar_00()) + _are_Posix = true; + + if (item.Num_Pax_Records != 0) + _are_Pax = true; + + if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true; + if (item.PaxTimes.ATime.IsDefined()) _are_atime = true; + if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true; + if (!item.SCHILY_fflags.IsEmpty()) _are_SCHILY_fflags = true; + + if (item.pax_path_WasUsed) + _are_pax_path = true; + if (item.pax_link_WasUsed) + _are_pax_link = true; + if (item.LongName_WasUsed) + _are_LongName = true; + if (item.LongLink_WasUsed) + _are_LongLink = true; + if (item.Prefix_WasUsed) + _pathPrefix_WasUsed = true; + /* + if (item.IsSparse()) + _isSparse = true; + */ + if (item.Is_PaxExtendedHeader()) + _are_Pax_Items = true; + if (item.IsThereWarning() + || item.HeaderError + || item.Pax_Error) + _is_Warning = true; + } + + const UInt64 headerEnd = item.HeaderPos + item.HeaderSize; + // _headersSize += headerEnd - _phySize; + // we don't count skipped records + _headersSize += item.HeaderSize; + _phySize = headerEnd; + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h index c2ba0cc23..edfc94a0e 100644 --- a/CPP/7zip/Archive/Tar/TarIn.h +++ b/CPP/7zip/Archive/Tar/TarIn.h @@ -1,151 +1,151 @@ -// TarIn.h - -#ifndef ZIP7_INC_ARCHIVE_TAR_IN_H -#define ZIP7_INC_ARCHIVE_TAR_IN_H - -#include "../IArchive.h" - -#include "TarItem.h" - -namespace NArchive { -namespace NTar { - -enum EErrorType -{ - k_ErrorType_OK, - k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd - // , k_ErrorType_Warning -}; - - -struct CTempBuffer -{ - CByteBuffer Buffer; - size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize) - bool IsNonZeroTail; - bool StringSize_IsConfirmed; - - void CopyToString(AString &s) - { - s.Empty(); - if (StringSize != 0) - s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize); - } - - void Init() - { - StringSize = 0; - IsNonZeroTail = false; - StringSize_IsConfirmed = false; - } -}; - - -class CArchive -{ -public: - bool _phySize_Defined; - bool _is_Warning; - bool PaxGlobal_Defined; - bool _is_PaxGlobal_Error; - bool _are_Pax_Items; - bool _are_Gnu; - bool _are_Posix; - bool _are_Pax; - bool _are_mtime; - bool _are_atime; - bool _are_ctime; - bool _are_pax_path; - bool _are_pax_link; - bool _are_LongName; - bool _are_LongLink; - bool _pathPrefix_WasUsed; - bool _are_SCHILY_fflags; - // bool _isSparse; - - // temp internal vars for ReadItem(): - bool filled; -private: - EErrorType error; - -public: - UInt64 _phySize; - UInt64 _headersSize; - EErrorType _error; - - ISequentialInStream *SeqStream; - IInStream *InStream; - IArchiveOpenCallback *OpenCallback; - UInt64 NumFiles; - UInt64 NumFiles_Prev; - UInt64 Pos_Prev; - // UInt64 NumRecords; - // UInt64 NumRecords_Prev; - - CPaxExtra PaxGlobal; - - void Clear() - { - SeqStream = NULL; - InStream = NULL; - OpenCallback = NULL; - NumFiles = 0; - NumFiles_Prev = 0; - Pos_Prev = 0; - // NumRecords = 0; - // NumRecords_Prev = 0; - - PaxGlobal.Clear(); - PaxGlobal_Defined = false; - _is_PaxGlobal_Error = false; - _are_Pax_Items = false; // if there are final paxItems - _are_Gnu = false; - _are_Posix = false; - _are_Pax = false; - _are_mtime = false; - _are_atime = false; - _are_ctime = false; - _are_pax_path = false; - _are_pax_link = false; - _are_LongName = false; - _are_LongLink = false; - _pathPrefix_WasUsed = false; - _are_SCHILY_fflags = false; - // _isSparse = false; - - _is_Warning = false; - _error = k_ErrorType_OK; - - _phySize_Defined = false; - _phySize = 0; - _headersSize = 0; - } - -private: - CTempBuffer NameBuf; - CTempBuffer LinkBuf; - CTempBuffer PaxBuf; - CTempBuffer PaxBuf_global; - - CByteBuffer Buffer; - - HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit); - HRESULT Progress(const CItemEx &item, UInt64 posOffset); - HRESULT GetNextItemReal(CItemEx &item); - HRESULT ReadItem2(CItemEx &itemInfo); -public: - CArchive() - { - // we will call Clear() in CHandler::Close(). - // Clear(); // it's not required here - } - HRESULT ReadItem(CItemEx &itemInfo); -}; - - -API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size); - -}} - -#endif +// TarIn.h + +#ifndef ZIP7_INC_ARCHIVE_TAR_IN_H +#define ZIP7_INC_ARCHIVE_TAR_IN_H + +#include "../IArchive.h" + +#include "TarItem.h" + +namespace NArchive { +namespace NTar { + +enum EErrorType +{ + k_ErrorType_OK, + k_ErrorType_Corrupted, + k_ErrorType_UnexpectedEnd + // , k_ErrorType_Warning +}; + + +struct CTempBuffer +{ + CByteBuffer Buffer; + size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize) + bool IsNonZeroTail; + bool StringSize_IsConfirmed; + + void CopyToString(AString &s) + { + s.Empty(); + if (StringSize != 0) + s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize); + } + + void Init() + { + StringSize = 0; + IsNonZeroTail = false; + StringSize_IsConfirmed = false; + } +}; + + +class CArchive +{ +public: + bool _phySize_Defined; + bool _is_Warning; + bool PaxGlobal_Defined; + bool _is_PaxGlobal_Error; + bool _are_Pax_Items; + bool _are_Gnu; + bool _are_Posix; + bool _are_Pax; + bool _are_mtime; + bool _are_atime; + bool _are_ctime; + bool _are_pax_path; + bool _are_pax_link; + bool _are_LongName; + bool _are_LongLink; + bool _pathPrefix_WasUsed; + bool _are_SCHILY_fflags; + // bool _isSparse; + + // temp internal vars for ReadItem(): + bool filled; +private: + EErrorType error; + +public: + UInt64 _phySize; + UInt64 _headersSize; + EErrorType _error; + + ISequentialInStream *SeqStream; + IInStream *InStream; + IArchiveOpenCallback *OpenCallback; + UInt64 NumFiles; + UInt64 NumFiles_Prev; + UInt64 Pos_Prev; + // UInt64 NumRecords; + // UInt64 NumRecords_Prev; + + CPaxExtra PaxGlobal; + + void Clear() + { + SeqStream = NULL; + InStream = NULL; + OpenCallback = NULL; + NumFiles = 0; + NumFiles_Prev = 0; + Pos_Prev = 0; + // NumRecords = 0; + // NumRecords_Prev = 0; + + PaxGlobal.Clear(); + PaxGlobal_Defined = false; + _is_PaxGlobal_Error = false; + _are_Pax_Items = false; // if there are final paxItems + _are_Gnu = false; + _are_Posix = false; + _are_Pax = false; + _are_mtime = false; + _are_atime = false; + _are_ctime = false; + _are_pax_path = false; + _are_pax_link = false; + _are_LongName = false; + _are_LongLink = false; + _pathPrefix_WasUsed = false; + _are_SCHILY_fflags = false; + // _isSparse = false; + + _is_Warning = false; + _error = k_ErrorType_OK; + + _phySize_Defined = false; + _phySize = 0; + _headersSize = 0; + } + +private: + CTempBuffer NameBuf; + CTempBuffer LinkBuf; + CTempBuffer PaxBuf; + CTempBuffer PaxBuf_global; + + CByteBuffer Buffer; + + HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit); + HRESULT Progress(const CItemEx &item, UInt64 posOffset); + HRESULT GetNextItemReal(CItemEx &item); + HRESULT ReadItem2(CItemEx &itemInfo); +public: + CArchive() + { + // we will call Clear() in CHandler::Close(). + // Clear(); // it's not required here + } + HRESULT ReadItem(CItemEx &itemInfo); +}; + + +API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size); + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h index e632a081d..112f38dc7 100644 --- a/CPP/7zip/Archive/Tar/TarItem.h +++ b/CPP/7zip/Archive/Tar/TarItem.h @@ -1,364 +1,364 @@ -// TarItem.h - -#ifndef ZIP7_INC_ARCHIVE_TAR_ITEM_H -#define ZIP7_INC_ARCHIVE_TAR_ITEM_H - -#include "../../../Common/MyLinux.h" -#include "../../../Common/UTFConvert.h" - -#include "TarHeader.h" - -namespace NArchive { -namespace NTar { - -struct CSparseBlock -{ - UInt64 Offset; - UInt64 Size; -}; - - -enum EPaxTimeRemoveZeroMode -{ - k_PaxTimeMode_DontRemoveZero, - k_PaxTimeMode_RemoveZero_if_PureSecondOnly, - k_PaxTimeMode_RemoveZero_Always -}; - -struct CTimeOptions -{ - EPaxTimeRemoveZeroMode RemoveZeroMode; - unsigned NumDigitsMax; - - void Init() - { - RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly; - NumDigitsMax = 0; - } - CTimeOptions() { Init(); } -}; - - -struct CPaxTime -{ - Int32 NumDigits; // -1 means undefined - UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files. - Int64 Sec; // can be negative - - Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; } - - bool IsDefined() const { return NumDigits != -1; } - // bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); } - - void Clear() - { - NumDigits = -1; - Ns = 0; - Sec = 0; - } - CPaxTime() { Clear(); } - - /* - void ReducePrecison(int numDigits) - { - // we don't use this->NumDigits here - if (numDigits > 0) - { - if (numDigits >= 9) - return; - UInt32 r = 1; - for (unsigned i = numDigits; i < 9; i++) - r *= 10; - Ns /= r; - Ns *= r; - return; - } - Ns = 0; - if (numDigits == 0) - return; - UInt32 r; - if (numDigits == -1) r = 60; - else if (numDigits == -2) r = 60 * 60; - else if (numDigits == -3) r = 60 * 60 * 24; - else return; - Sec /= r; - Sec *= r; - } - */ -}; - - -struct CPaxTimes -{ - CPaxTime MTime; - CPaxTime ATime; - CPaxTime CTime; - - void Clear() - { - MTime.Clear(); - ATime.Clear(); - CTime.Clear(); - } - - /* - void ReducePrecison(int numDigits) - { - MTime.ReducePrecison(numDigits); - CTime.ReducePrecison(numDigits); - ATime.ReducePrecison(numDigits); - } - */ -}; - - -struct CItem -{ - UInt64 PackSize; - UInt64 Size; - Int64 MTime; - - char LinkFlag; - bool DeviceMajor_Defined; - bool DeviceMinor_Defined; - - UInt32 Mode; - UInt32 UID; - UInt32 GID; - UInt32 DeviceMajor; - UInt32 DeviceMinor; - - AString Name; - AString LinkName; - AString User; - AString Group; - - char Magic[8]; - - CPaxTimes PaxTimes; - - CRecordVector SparseBlocks; - - void SetMagic_Posix(bool posixMode) - { - memcpy(Magic, posixMode ? - NFileHeader::NMagic::k_Posix_ustar_00 : - NFileHeader::NMagic::k_GNU_ustar, - 8); - } - - bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } - bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } - bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } - - UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; } - - bool Is_PaxExtendedHeader() const - { - switch (LinkFlag) - { - case NFileHeader::NLinkFlag::kPax: - case NFileHeader::NLinkFlag::kPax_2: - case NFileHeader::NLinkFlag::kGlobal: - return true; - default: break; - } - return false; - } - - UInt32 Get_Combined_Mode() const - { - return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); - } - - void Set_LinkFlag_for_File(UInt32 mode) - { - char lf = NFileHeader::NLinkFlag::kNormal; - if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter; - else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock; - else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO; - // else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory; - // else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink; - LinkFlag = lf; - } - - UInt32 Get_FileTypeMode_from_LinkFlag() const - { - switch (LinkFlag) - { - /* - case NFileHeader::NLinkFlag::kDirectory: - case NFileHeader::NLinkFlag::kDumpDir: - return MY_LIN_S_IFDIR; - */ - case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; - case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; - case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; - case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; - // case return MY_LIN_S_IFSOCK; - default: break; - } - - if (IsDir()) - return MY_LIN_S_IFDIR; - return MY_LIN_S_IFREG; - } - - bool IsDir() const - { - switch (LinkFlag) - { - case NFileHeader::NLinkFlag::kDirectory: - case NFileHeader::NLinkFlag::kDumpDir: - return true; - case NFileHeader::NLinkFlag::kOldNormal: - case NFileHeader::NLinkFlag::kNormal: - case NFileHeader::NLinkFlag::kSymLink: - if (Name.IsEmpty()) - return false; - // GNU TAR uses last character as directory marker - // we also do it - return Name.Back() == '/'; - // return NItemName::HasTailSlash(Name, CP_OEMCP); - default: break; - } - return false; - } - - bool IsMagic_ustar_5chars() const - { - for (unsigned i = 0; i < 5; i++) - if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar[i]) - return false; - return true; - } - - bool IsMagic_Posix_ustar_00() const - { - for (unsigned i = 0; i < 8; i++) - if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i]) - return false; - return true; - } - - bool IsMagic_GNU() const - { - for (unsigned i = 0; i < 8; i++) - if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar[i]) - return false; - return true; - } - - UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } - - bool IsThereWarning() const - { - // that Header Warning is possible if (Size != 0) for dir item - return (PackSize < Size) && (LinkFlag == NFileHeader::NLinkFlag::kDirectory); - } -}; - - - -struct CEncodingCharacts -{ - bool IsAscii; - // bool Oem_Checked; - // bool Oem_Ok; - // bool Utf_Checked; - CUtf8Check UtfCheck; - - void Clear() - { - IsAscii = true; - // Oem_Checked = false; - // Oem_Ok = false; - // Utf_Checked = false; - UtfCheck.Clear(); - } - - void Update(const CEncodingCharacts &ec) - { - if (!ec.IsAscii) - IsAscii = false; - - // if (ec.Utf_Checked) - { - UtfCheck.Update(ec.UtfCheck); - // Utf_Checked = true; - } - } - - CEncodingCharacts() { Clear(); } - void Check(const AString &s); - AString GetCharactsString() const; -}; - - -struct CPaxExtra -{ - AString RecordPath; - AString RawLines; - - void Clear() - { - RecordPath.Empty(); - RawLines.Empty(); - } - - void Print_To_String(AString &s) const - { - if (!RecordPath.IsEmpty()) - { - s += RecordPath; - s.Add_LF(); - } - if (!RawLines.IsEmpty()) - s += RawLines; - } -}; - - -struct CItemEx: public CItem -{ - bool HeaderError; - - bool IsSignedChecksum; - bool Prefix_WasUsed; - - bool Pax_Error; - bool Pax_Overflow; - bool pax_path_WasUsed; - bool pax_link_WasUsed; - bool pax_size_WasUsed; - - bool MTime_IsBin; - bool PackSize_IsBin; - bool Size_IsBin; - - bool LongName_WasUsed; - bool LongName_WasUsed_2; - - bool LongLink_WasUsed; - bool LongLink_WasUsed_2; - - // bool Name_CouldBeReduced; - // bool LinkName_CouldBeReduced; - - UInt64 HeaderPos; - UInt64 HeaderSize; - - UInt64 Num_Pax_Records; - CPaxExtra PaxExtra; - AString SCHILY_fflags; - - CEncodingCharacts EncodingCharacts; - - UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; } - // UInt64 GetFullSize() const { return HeaderSize + PackSize; } - UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); } -}; - -}} - -#endif +// TarItem.h + +#ifndef ZIP7_INC_ARCHIVE_TAR_ITEM_H +#define ZIP7_INC_ARCHIVE_TAR_ITEM_H + +#include "../../../Common/MyLinux.h" +#include "../../../Common/UTFConvert.h" + +#include "TarHeader.h" + +namespace NArchive { +namespace NTar { + +struct CSparseBlock +{ + UInt64 Offset; + UInt64 Size; +}; + + +enum EPaxTimeRemoveZeroMode +{ + k_PaxTimeMode_DontRemoveZero, + k_PaxTimeMode_RemoveZero_if_PureSecondOnly, + k_PaxTimeMode_RemoveZero_Always +}; + +struct CTimeOptions +{ + EPaxTimeRemoveZeroMode RemoveZeroMode; + unsigned NumDigitsMax; + + void Init() + { + RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly; + NumDigitsMax = 0; + } + CTimeOptions() { Init(); } +}; + + +struct CPaxTime +{ + Int32 NumDigits; // -1 means undefined + UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files. + Int64 Sec; // can be negative + + Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; } + + bool IsDefined() const { return NumDigits != -1; } + // bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); } + + void Clear() + { + NumDigits = -1; + Ns = 0; + Sec = 0; + } + CPaxTime() { Clear(); } + + /* + void ReducePrecison(int numDigits) + { + // we don't use this->NumDigits here + if (numDigits > 0) + { + if (numDigits >= 9) + return; + UInt32 r = 1; + for (unsigned i = numDigits; i < 9; i++) + r *= 10; + Ns /= r; + Ns *= r; + return; + } + Ns = 0; + if (numDigits == 0) + return; + UInt32 r; + if (numDigits == -1) r = 60; + else if (numDigits == -2) r = 60 * 60; + else if (numDigits == -3) r = 60 * 60 * 24; + else return; + Sec /= r; + Sec *= r; + } + */ +}; + + +struct CPaxTimes +{ + CPaxTime MTime; + CPaxTime ATime; + CPaxTime CTime; + + void Clear() + { + MTime.Clear(); + ATime.Clear(); + CTime.Clear(); + } + + /* + void ReducePrecison(int numDigits) + { + MTime.ReducePrecison(numDigits); + CTime.ReducePrecison(numDigits); + ATime.ReducePrecison(numDigits); + } + */ +}; + + +struct CItem +{ + UInt64 PackSize; + UInt64 Size; + Int64 MTime; + + char LinkFlag; + bool DeviceMajor_Defined; + bool DeviceMinor_Defined; + + UInt32 Mode; + UInt32 UID; + UInt32 GID; + UInt32 DeviceMajor; + UInt32 DeviceMinor; + + AString Name; + AString LinkName; + AString User; + AString Group; + + char Magic[8]; + + CPaxTimes PaxTimes; + + CRecordVector SparseBlocks; + + void SetMagic_Posix(bool posixMode) + { + memcpy(Magic, posixMode ? + NFileHeader::NMagic::k_Posix_ustar_00 : + NFileHeader::NMagic::k_GNU_ustar, + 8); + } + + bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } + bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } + bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } + + UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; } + + bool Is_PaxExtendedHeader() const + { + switch (LinkFlag) + { + case NFileHeader::NLinkFlag::kPax: + case NFileHeader::NLinkFlag::kPax_2: + case NFileHeader::NLinkFlag::kGlobal: + return true; + default: break; + } + return false; + } + + UInt32 Get_Combined_Mode() const + { + return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); + } + + void Set_LinkFlag_for_File(UInt32 mode) + { + char lf = NFileHeader::NLinkFlag::kNormal; + if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter; + else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock; + else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO; + // else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory; + // else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink; + LinkFlag = lf; + } + + UInt32 Get_FileTypeMode_from_LinkFlag() const + { + switch (LinkFlag) + { + /* + case NFileHeader::NLinkFlag::kDirectory: + case NFileHeader::NLinkFlag::kDumpDir: + return MY_LIN_S_IFDIR; + */ + case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; + case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; + case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; + case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; + // case return MY_LIN_S_IFSOCK; + default: break; + } + + if (IsDir()) + return MY_LIN_S_IFDIR; + return MY_LIN_S_IFREG; + } + + bool IsDir() const + { + switch (LinkFlag) + { + case NFileHeader::NLinkFlag::kDirectory: + case NFileHeader::NLinkFlag::kDumpDir: + return true; + case NFileHeader::NLinkFlag::kOldNormal: + case NFileHeader::NLinkFlag::kNormal: + case NFileHeader::NLinkFlag::kSymLink: + if (Name.IsEmpty()) + return false; + // GNU TAR uses last character as directory marker + // we also do it + return Name.Back() == '/'; + // return NItemName::HasTailSlash(Name, CP_OEMCP); + default: break; + } + return false; + } + + bool IsMagic_ustar_5chars() const + { + for (unsigned i = 0; i < 5; i++) + if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar[i]) + return false; + return true; + } + + bool IsMagic_Posix_ustar_00() const + { + for (unsigned i = 0; i < 8; i++) + if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i]) + return false; + return true; + } + + bool IsMagic_GNU() const + { + for (unsigned i = 0; i < 8; i++) + if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar[i]) + return false; + return true; + } + + UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } + + bool IsThereWarning() const + { + // that Header Warning is possible if (Size != 0) for dir item + return (PackSize < Size) && (LinkFlag == NFileHeader::NLinkFlag::kDirectory); + } +}; + + + +struct CEncodingCharacts +{ + bool IsAscii; + // bool Oem_Checked; + // bool Oem_Ok; + // bool Utf_Checked; + CUtf8Check UtfCheck; + + void Clear() + { + IsAscii = true; + // Oem_Checked = false; + // Oem_Ok = false; + // Utf_Checked = false; + UtfCheck.Clear(); + } + + void Update(const CEncodingCharacts &ec) + { + if (!ec.IsAscii) + IsAscii = false; + + // if (ec.Utf_Checked) + { + UtfCheck.Update(ec.UtfCheck); + // Utf_Checked = true; + } + } + + CEncodingCharacts() { Clear(); } + void Check(const AString &s); + AString GetCharactsString() const; +}; + + +struct CPaxExtra +{ + AString RecordPath; + AString RawLines; + + void Clear() + { + RecordPath.Empty(); + RawLines.Empty(); + } + + void Print_To_String(AString &s) const + { + if (!RecordPath.IsEmpty()) + { + s += RecordPath; + s.Add_LF(); + } + if (!RawLines.IsEmpty()) + s += RawLines; + } +}; + + +struct CItemEx: public CItem +{ + bool HeaderError; + + bool IsSignedChecksum; + bool Prefix_WasUsed; + + bool Pax_Error; + bool Pax_Overflow; + bool pax_path_WasUsed; + bool pax_link_WasUsed; + bool pax_size_WasUsed; + + bool MTime_IsBin; + bool PackSize_IsBin; + bool Size_IsBin; + + bool LongName_WasUsed; + bool LongName_WasUsed_2; + + bool LongLink_WasUsed; + bool LongLink_WasUsed_2; + + // bool Name_CouldBeReduced; + // bool LinkName_CouldBeReduced; + + UInt64 HeaderPos; + UInt64 HeaderSize; + + UInt64 Num_Pax_Records; + CPaxExtra PaxExtra; + AString SCHILY_fflags; + + CEncodingCharacts EncodingCharacts; + + UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; } + // UInt64 GetFullSize() const { return HeaderSize + PackSize; } + UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp index 943b7b9f0..8a80c0c26 100644 --- a/CPP/7zip/Archive/Tar/TarOut.cpp +++ b/CPP/7zip/Archive/Tar/TarOut.cpp @@ -1,644 +1,644 @@ -// TarOut.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" - -#include "../../../Common/IntToString.h" - -#include "../../Common/StreamUtils.h" - -#include "TarOut.h" - -namespace NArchive { -namespace NTar { - -using namespace NFileHeader; - -// it's path prefix assigned by 7-Zip to show that file path was cut -#define K_PREFIX_PATH_CUT "@PathCut" - -static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1; - -static void WriteOctal_8(char *s, UInt32 val) -{ - const unsigned kNumDigits = 8 - 1; - if (val >= ((UInt32)1 << (kNumDigits * 3))) - { - val = 0; - // return false; - } - for (unsigned i = 0; i < kNumDigits; i++) - { - s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); - val >>= 3; - } - // return true; -} - -static void WriteBin_64bit(char *s, UInt64 val) -{ - for (unsigned i = 0; i < 8; i++, val <<= 8) - s[i] = (char)(val >> 56); -} - -static void WriteOctal_12(char *s, UInt64 val) -{ - const unsigned kNumDigits = 12 - 1; - if (val >= ((UInt64)1 << (kNumDigits * 3))) - { - // GNU extension; - s[0] = (char)(Byte)0x80; - s[1] = s[2] = s[3] = 0; - WriteBin_64bit(s + 4, val); - return; - } - for (unsigned i = 0; i < kNumDigits; i++) - { - s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); - val >>= 3; - } -} - -static void WriteOctal_12_Signed(char *s, const Int64 val) -{ - if (val >= 0) - { - WriteOctal_12(s, (UInt64)val); - return; - } - s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; - WriteBin_64bit(s + 4, (UInt64)val); -} - -static void CopyString(char *dest, const AString &src, const unsigned maxSize) -{ - unsigned len = src.Len(); - if (len == 0) - return; - // 21.07: new gnu : we don't require additional 0 character at the end - // if (len >= maxSize) - if (len > maxSize) - { - len = maxSize; - /* - // oldgnu needs 0 character at the end - len = maxSize - 1; - dest[len] = 0; - */ - } - memcpy(dest, src.Ptr(), len); -} - -// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; } -#define RETURN_IF_NOT_TRUE(x) { x; } - -#define COPY_STRING_CHECK(dest, src, size) \ - CopyString(dest, src, size); dest += (size); - -#define WRITE_OCTAL_8_CHECK(dest, src) \ - RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src)) - - -HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax - // , bool zero_PackSize - // , bool zero_MTime - ) -{ - /* - if (isPax) { we don't use Glob_Name and Prefix } - if (!isPax) - { - we use Glob_Name if it's not empty - we use Prefix if it's not empty - } - */ - char record[kRecordSize]; - memset(record, 0, kRecordSize); - char *cur = record; - - COPY_STRING_CHECK (cur, - (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name, - kNameSize) - - WRITE_OCTAL_8_CHECK (cur, item.Mode) cur += 8; // & k_7_oct_digits_Val_Max - WRITE_OCTAL_8_CHECK (cur, item.UID) cur += 8; - WRITE_OCTAL_8_CHECK (cur, item.GID) cur += 8; - - WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12; - WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12; - - // we will use binary init for checksum instead of memset - // checksum field: - // memset(cur, ' ', 8); - cur += 8; - - *cur++ = item.LinkFlag; - - COPY_STRING_CHECK (cur, item.LinkName, kNameSize) - - memcpy(cur, item.Magic, 8); - cur += 8; - - COPY_STRING_CHECK (cur, item.User, kUserNameSize) - COPY_STRING_CHECK (cur, item.Group, kGroupNameSize) - - const bool needDevice = (IsPosixMode && !isPax); - - if (item.DeviceMajor_Defined) - WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor) - else if (needDevice) - WRITE_OCTAL_8_CHECK (cur, 0) - cur += 8; - - if (item.DeviceMinor_Defined) - WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor) - else if (needDevice) - WRITE_OCTAL_8_CHECK (cur, 0) - cur += 8; - - if (!isPax && !Prefix.IsEmpty()) - { - COPY_STRING_CHECK (cur, Prefix, kPrefixSize) - } - - if (item.Is_Sparse()) - { - record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); - WriteOctal_12(record + 483, item.Size); - for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++) - { - const CSparseBlock &sb = item.SparseBlocks[i]; - char *p = record + 386 + 24 * i; - WriteOctal_12(p, sb.Offset); - WriteOctal_12(p + 12, sb.Size); - } - } - - { - UInt32 sum = (unsigned)(' ') * 8; // we use binary init - { - for (unsigned i = 0; i < kRecordSize; i++) - sum += (Byte)record[i]; - } - /* checksum field is formatted differently from the - other fields: it has [6] digits, a null, then a space. */ - // WRITE_OCTAL_8_CHECK(record + 148, sum); - const unsigned kNumDigits = 6; - for (unsigned i = 0; i < kNumDigits; i++) - { - record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7)); - sum >>= 3; - } - // record[148 + 6] = 0; // we need it, if we use memset(' ') init - record[148 + 7] = ' '; // we need it, if we use binary init - } - - RINOK(Write_Data(record, kRecordSize)) - - if (item.Is_Sparse()) - { - for (unsigned i = 4; i < item.SparseBlocks.Size();) - { - memset(record, 0, kRecordSize); - for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++) - { - const CSparseBlock &sb = item.SparseBlocks[i]; - char *p = record + 24 * t; - WriteOctal_12(p, sb.Offset); - WriteOctal_12(p + 12, sb.Size); - } - record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); - RINOK(Write_Data(record, kRecordSize)) - } - } - - return S_OK; -} - - -static void AddPaxLine(AString &s, const char *name, const AString &val) -{ - // s.Add_LF(); // for debug - const unsigned len = 3 + (unsigned)strlen(name) + val.Len(); - AString n; - for (unsigned numDigits = 1;; numDigits++) - { - n.Empty(); - n.Add_UInt32(numDigits + len); - if (numDigits == n.Len()) - break; - } - s += n; - s.Add_Space(); - s += name; - s.Add_Char('='); - s += val; - s.Add_LF(); -} - -// pt is defined : (pt.NumDigits >= 0) -static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt, - const CTimeOptions &options) -{ - unsigned numDigits = (unsigned)pt.NumDigits; - if (numDigits > options.NumDigitsMax) - numDigits = options.NumDigitsMax; - - bool needNs = false; - UInt32 ns = 0; - if (numDigits != 0) - { - ns = pt.Ns; - // if (ns != 0) before reduction, we show all digits after digits reduction - needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero); - UInt32 d = 1; - for (unsigned k = numDigits; k < 9; k++) - d *= 10; - ns /= d; - ns *= d; - } - - AString v; - { - Int64 sec = pt.Sec; - if (pt.Sec < 0) - { - sec = -sec; - v.Add_Minus(); - if (ns != 0) - { - ns = 1000*1000*1000 - ns; - sec--; - } - } - v.Add_UInt64((UInt64)sec); - } - - if (needNs) - { - AString d; - d.Add_UInt32(ns); - while (d.Len() < 9) - d.InsertAtFront('0'); - // here we have precision - while (d.Len() > (unsigned)numDigits) - d.DeleteBack(); - // GNU TAR reduces '0' digits. - if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always) - while (!d.IsEmpty() && d.Back() == '0') - d.DeleteBack(); - - if (!d.IsEmpty()) - { - v.Add_Dot(); - v += d; - // v += "1234567009999"; // for debug - // for (int y = 0; y < 1000; y++) v += '8'; // for debug - } - } - - AddPaxLine(s, name, v); -} - - -static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v) -{ - if (v > k_7_oct_digits_Val_Max) - { - AString s2; - s2.Add_UInt32(v); - AddPaxLine(s, name, s2); - } -} - - -/* OLD_GNU_TAR: writes name with zero at the end - NEW_GNU_TAR: can write name filled with all kNameSize characters */ - -static const unsigned kNameSize_Max = - kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 - // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip - -#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max) - - -HRESULT COutArchive::WriteHeader(const CItem &item) -{ - Glob_Name.Empty(); - Prefix.Empty(); - - unsigned namePos = 0; - bool needPathCut = false; - bool allowPrefix = false; - - if (!DOES_NAME_FIT_IN_FIELD(item.Name)) - { - const char *s = item.Name; - const char *p = s + item.Name.Len() - 1; - for (; *p == '/' && p != s; p--) - {} - for (; p != s && p[-1] != '/'; p--) - {} - namePos = (unsigned)(p - s); - needPathCut = true; - } - - if (IsPosixMode) - { - AString s; - - if (needPathCut) - { - const unsigned nameLen = item.Name.Len() - namePos; - if ( item.LinkFlag >= NLinkFlag::kNormal - && item.LinkFlag <= NLinkFlag::kDirectory - && namePos > 1 - && nameLen != 0 - // && IsPrefixAllowed - && item.IsMagic_Posix_ustar_00()) - { - /* GNU TAR decoder supports prefix field, only if (magic) - signature matches 6-bytes "ustar\0". - so here we use prefix field only in posix mode with posix signature */ - - allowPrefix = true; - // allowPrefix = false; // for debug - if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max) - { - needPathCut = false; - /* we will set Prefix and Glob_Name later, for such conditions: - if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */ - } - } - - if (needPathCut) - AddPaxLine(s, "path", item.Name); - } - - // AddPaxLine(s, "testname", AString("testval")); // for debug - - if (item.LinkName.Len() > kNameSize_Max) - AddPaxLine(s, "linkpath", item.LinkName); - - const UInt64 kPaxSize_Limit = ((UInt64)1 << 33); - // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug - // bool zero_PackSize = false; - if (item.PackSize >= kPaxSize_Limit) - { - /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB - But old 7-Zip doesn't detect "size" property from pax header. - So we write real size (>= 8 GiB) to main record in binary format, - and old 7-Zip can decode size correctly */ - // zero_PackSize = true; - AString v; - v.Add_UInt64(item.PackSize); - AddPaxLine(s, "size", v); - } - - /* GNU TAR encoder can set "devmajor" / "devminor" attributes, - but GNU TAR decoder doesn't parse "devmajor" / "devminor" */ - if (item.DeviceMajor_Defined) - AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor); - if (item.DeviceMinor_Defined) - AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor); - - AddPax_UInt32_ifBig(s, "uid", item.UID); - AddPax_UInt32_ifBig(s, "gid", item.GID); - - const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33); - const bool zero_MTime = ( - item.MTime < 0 || - item.MTime >= (Int64)kPax_MTime_Limit); - - const CPaxTime &mtime = item.PaxTimes.MTime; - if (mtime.IsDefined()) - { - bool needPax = false; - if (zero_MTime) - needPax = true; - else if (TimeOptions.NumDigitsMax > 0) - if (mtime.Ns != 0 || - (mtime.NumDigits != 0 && - TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero)) - needPax = true; - if (needPax) - AddPaxTime(s, "mtime", mtime, TimeOptions); - } - - if (item.PaxTimes.ATime.IsDefined()) - AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions); - if (item.PaxTimes.CTime.IsDefined()) - AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions); - - if (item.User.Len() > kUserNameSize) - AddPaxLine(s, "uname", item.User); - if (item.Group.Len() > kGroupNameSize) - AddPaxLine(s, "gname", item.Group); - - /* - // for debug - AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a); - */ - - const unsigned paxSize = s.Len(); - if (paxSize != 0) - { - CItem mi = item; - mi.LinkName.Empty(); - // SparseBlocks will be ignored by Is_Sparse() - // mi.SparseBlocks.Clear(); - // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder - - // GNU TAR writes empty for these fields; - mi.User.Empty(); - mi.Group.Empty(); - mi.UID = 0; - mi.GID = 0; - - mi.DeviceMajor_Defined = false; - mi.DeviceMinor_Defined = false; - - mi.Name = "PaxHeader/@PaxHeader"; - mi.Mode = 0644; // octal - if (zero_MTime) - mi.MTime = 0; - mi.LinkFlag = NLinkFlag::kPax; - // mi.LinkFlag = 'Z'; // for debug - mi.PackSize = paxSize; - // for (unsigned y = 0; y < 1; y++) { // for debug - RINOK(WriteHeaderReal(mi, true)) // isPax - RINOK(Write_Data_And_Residual(s, paxSize)) - // } // for debug - /* - we can send (zero_MTime) for compatibility with gnu tar output. - we can send (zero_MTime = false) for better compatibility with old 7-Zip - */ - // return WriteHeaderReal(item); - /* - false, // isPax - false, // zero_PackSize - false); // zero_MTime - */ - } - } - else // !PosixMode - if (!DOES_NAME_FIT_IN_FIELD(item.Name) || - !DOES_NAME_FIT_IN_FIELD(item.LinkName)) - { - // here we can get all fields from main (item) or create new empty item - /* - CItem mi; - mi.SetDefaultWriteFields(); - */ - CItem mi = item; - mi.LinkName.Empty(); - // SparseBlocks will be ignored by Is_Sparse() - // mi.SparseBlocks.Clear(); - mi.Name = kLongLink; - // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug - // 21.07 : we set Mode and MTime props as in GNU TAR: - mi.Mode = 0644; // octal - mi.MTime = 0; - - mi.User.Empty(); - mi.Group.Empty(); - /* - gnu tar sets "root" for such items: - uid_to_uname (0, &uname); - gid_to_gname (0, &gname); - */ - /* - mi.User = "root"; - mi.Group = "root"; - */ - mi.UID = 0; - mi.GID = 0; - mi.DeviceMajor_Defined = false; - mi.DeviceMinor_Defined = false; - - - for (unsigned i = 0; i < 2; i++) - { - const AString *name; - // We suppose that GNU TAR also writes item for long link before item for LongName? - if (i == 0) - { - mi.LinkFlag = NLinkFlag::kGnu_LongLink; - name = &item.LinkName; - } - else - { - mi.LinkFlag = NLinkFlag::kGnu_LongName; - name = &item.Name; - } - if (DOES_NAME_FIT_IN_FIELD(*name)) - continue; - // GNU TAR writes null character after NAME to file. We do same here: - const unsigned nameStreamSize = name->Len() + 1; - mi.PackSize = nameStreamSize; - // for (unsigned y = 0; y < 3; y++) { // for debug - RINOK(WriteHeaderReal(mi)) - RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize)) - // } - - // for debug - /* - const unsigned kSize = (1 << 29) + 16; - CByteBuffer buf; - buf.Alloc(kSize); - memset(buf, 0, kSize); - memcpy(buf, name->Ptr(), name->Len()); - const unsigned nameStreamSize = kSize; - mi.PackSize = nameStreamSize; - // for (unsigned y = 0; y < 3; y++) { // for debug - RINOK(WriteHeaderReal(mi)); - RINOK(WriteBytes(buf, nameStreamSize)); - RINOK(FillDataResidual(nameStreamSize)); - */ - } - } - - // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR - - if (!DOES_NAME_FIT_IN_FIELD(item.Name)) - { - const unsigned nameLen = item.Name.Len() - namePos; - if (!needPathCut) - Prefix.SetFrom(item.Name, namePos - 1); - else - { - Glob_Name = K_PREFIX_PATH_CUT "/_pc_"; - - if (namePos == 0) - Glob_Name += "root"; - else - { - Glob_Name += "crc32/"; - char temp[12]; - ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp); - Glob_Name += temp; - } - - if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max) - Glob_Name.Add_Slash(); - else - { - Prefix = Glob_Name; - Glob_Name.Empty(); - } - } - Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen); - } - - return WriteHeaderReal(item); -} - - -HRESULT COutArchive::Write_Data(const void *data, unsigned size) -{ - Pos += size; - return WriteStream(Stream, data, size); -} - -HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize) -{ - const unsigned v = ((unsigned)dataSize & (kRecordSize - 1)); - if (v == 0) - return S_OK; - const unsigned rem = kRecordSize - v; - Byte buf[kRecordSize]; - memset(buf, 0, rem); - return Write_Data(buf, rem); -} - - -HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size) -{ - RINOK(Write_Data(data, size)) - return Write_AfterDataResidual(size); -} - - -HRESULT COutArchive::WriteFinishHeader() -{ - Byte record[kRecordSize]; - memset(record, 0, kRecordSize); - - const unsigned kNumFinishRecords = 2; - - /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB) - we also can use cluster alignment: - const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords; - const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB - const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1)); - */ - - for (unsigned i = 0; i < kNumFinishRecords; i++) - { - RINOK(Write_Data(record, kRecordSize)) - } - return S_OK; -} - -}} +// TarOut.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" + +#include "../../../Common/IntToString.h" + +#include "../../Common/StreamUtils.h" + +#include "TarOut.h" + +namespace NArchive { +namespace NTar { + +using namespace NFileHeader; + +// it's path prefix assigned by 7-Zip to show that file path was cut +#define K_PREFIX_PATH_CUT "@PathCut" + +static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1; + +static void WriteOctal_8(char *s, UInt32 val) +{ + const unsigned kNumDigits = 8 - 1; + if (val >= ((UInt32)1 << (kNumDigits * 3))) + { + val = 0; + // return false; + } + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } + // return true; +} + +static void WriteBin_64bit(char *s, UInt64 val) +{ + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[i] = (char)(val >> 56); +} + +static void WriteOctal_12(char *s, UInt64 val) +{ + const unsigned kNumDigits = 12 - 1; + if (val >= ((UInt64)1 << (kNumDigits * 3))) + { + // GNU extension; + s[0] = (char)(Byte)0x80; + s[1] = s[2] = s[3] = 0; + WriteBin_64bit(s + 4, val); + return; + } + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } +} + +static void WriteOctal_12_Signed(char *s, const Int64 val) +{ + if (val >= 0) + { + WriteOctal_12(s, (UInt64)val); + return; + } + s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; + WriteBin_64bit(s + 4, (UInt64)val); +} + +static void CopyString(char *dest, const AString &src, const unsigned maxSize) +{ + unsigned len = src.Len(); + if (len == 0) + return; + // 21.07: new gnu : we don't require additional 0 character at the end + // if (len >= maxSize) + if (len > maxSize) + { + len = maxSize; + /* + // oldgnu needs 0 character at the end + len = maxSize - 1; + dest[len] = 0; + */ + } + memcpy(dest, src.Ptr(), len); +} + +// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; } +#define RETURN_IF_NOT_TRUE(x) { x; } + +#define COPY_STRING_CHECK(dest, src, size) \ + CopyString(dest, src, size); dest += (size); + +#define WRITE_OCTAL_8_CHECK(dest, src) \ + RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src)) + + +HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax + // , bool zero_PackSize + // , bool zero_MTime + ) +{ + /* + if (isPax) { we don't use Glob_Name and Prefix } + if (!isPax) + { + we use Glob_Name if it's not empty + we use Prefix if it's not empty + } + */ + char record[kRecordSize]; + memset(record, 0, kRecordSize); + char *cur = record; + + COPY_STRING_CHECK (cur, + (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name, + kNameSize) + + WRITE_OCTAL_8_CHECK (cur, item.Mode) cur += 8; // & k_7_oct_digits_Val_Max + WRITE_OCTAL_8_CHECK (cur, item.UID) cur += 8; + WRITE_OCTAL_8_CHECK (cur, item.GID) cur += 8; + + WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12; + WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12; + + // we will use binary init for checksum instead of memset + // checksum field: + // memset(cur, ' ', 8); + cur += 8; + + *cur++ = item.LinkFlag; + + COPY_STRING_CHECK (cur, item.LinkName, kNameSize) + + memcpy(cur, item.Magic, 8); + cur += 8; + + COPY_STRING_CHECK (cur, item.User, kUserNameSize) + COPY_STRING_CHECK (cur, item.Group, kGroupNameSize) + + const bool needDevice = (IsPosixMode && !isPax); + + if (item.DeviceMajor_Defined) + WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor) + else if (needDevice) + WRITE_OCTAL_8_CHECK (cur, 0) + cur += 8; + + if (item.DeviceMinor_Defined) + WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor) + else if (needDevice) + WRITE_OCTAL_8_CHECK (cur, 0) + cur += 8; + + if (!isPax && !Prefix.IsEmpty()) + { + COPY_STRING_CHECK (cur, Prefix, kPrefixSize) + } + + if (item.Is_Sparse()) + { + record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); + WriteOctal_12(record + 483, item.Size); + for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + char *p = record + 386 + 24 * i; + WriteOctal_12(p, sb.Offset); + WriteOctal_12(p + 12, sb.Size); + } + } + + { + UInt32 sum = (unsigned)(' ') * 8; // we use binary init + { + for (unsigned i = 0; i < kRecordSize; i++) + sum += (Byte)record[i]; + } + /* checksum field is formatted differently from the + other fields: it has [6] digits, a null, then a space. */ + // WRITE_OCTAL_8_CHECK(record + 148, sum); + const unsigned kNumDigits = 6; + for (unsigned i = 0; i < kNumDigits; i++) + { + record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7)); + sum >>= 3; + } + // record[148 + 6] = 0; // we need it, if we use memset(' ') init + record[148 + 7] = ' '; // we need it, if we use binary init + } + + RINOK(Write_Data(record, kRecordSize)) + + if (item.Is_Sparse()) + { + for (unsigned i = 4; i < item.SparseBlocks.Size();) + { + memset(record, 0, kRecordSize); + for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + char *p = record + 24 * t; + WriteOctal_12(p, sb.Offset); + WriteOctal_12(p + 12, sb.Size); + } + record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); + RINOK(Write_Data(record, kRecordSize)) + } + } + + return S_OK; +} + + +static void AddPaxLine(AString &s, const char *name, const AString &val) +{ + // s.Add_LF(); // for debug + const unsigned len = 3 + (unsigned)strlen(name) + val.Len(); + AString n; + for (unsigned numDigits = 1;; numDigits++) + { + n.Empty(); + n.Add_UInt32(numDigits + len); + if (numDigits == n.Len()) + break; + } + s += n; + s.Add_Space(); + s += name; + s.Add_Char('='); + s += val; + s.Add_LF(); +} + +// pt is defined : (pt.NumDigits >= 0) +static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt, + const CTimeOptions &options) +{ + unsigned numDigits = (unsigned)pt.NumDigits; + if (numDigits > options.NumDigitsMax) + numDigits = options.NumDigitsMax; + + bool needNs = false; + UInt32 ns = 0; + if (numDigits != 0) + { + ns = pt.Ns; + // if (ns != 0) before reduction, we show all digits after digits reduction + needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero); + UInt32 d = 1; + for (unsigned k = numDigits; k < 9; k++) + d *= 10; + ns /= d; + ns *= d; + } + + AString v; + { + Int64 sec = pt.Sec; + if (pt.Sec < 0) + { + sec = -sec; + v.Add_Minus(); + if (ns != 0) + { + ns = 1000*1000*1000 - ns; + sec--; + } + } + v.Add_UInt64((UInt64)sec); + } + + if (needNs) + { + AString d; + d.Add_UInt32(ns); + while (d.Len() < 9) + d.InsertAtFront('0'); + // here we have precision + while (d.Len() > (unsigned)numDigits) + d.DeleteBack(); + // GNU TAR reduces '0' digits. + if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always) + while (!d.IsEmpty() && d.Back() == '0') + d.DeleteBack(); + + if (!d.IsEmpty()) + { + v.Add_Dot(); + v += d; + // v += "1234567009999"; // for debug + // for (int y = 0; y < 1000; y++) v += '8'; // for debug + } + } + + AddPaxLine(s, name, v); +} + + +static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v) +{ + if (v > k_7_oct_digits_Val_Max) + { + AString s2; + s2.Add_UInt32(v); + AddPaxLine(s, name, s2); + } +} + + +/* OLD_GNU_TAR: writes name with zero at the end + NEW_GNU_TAR: can write name filled with all kNameSize characters */ + +static const unsigned kNameSize_Max = + kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 + // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip + +#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max) + + +HRESULT COutArchive::WriteHeader(const CItem &item) +{ + Glob_Name.Empty(); + Prefix.Empty(); + + unsigned namePos = 0; + bool needPathCut = false; + bool allowPrefix = false; + + if (!DOES_NAME_FIT_IN_FIELD(item.Name)) + { + const char *s = item.Name; + const char *p = s + item.Name.Len() - 1; + for (; *p == '/' && p != s; p--) + {} + for (; p != s && p[-1] != '/'; p--) + {} + namePos = (unsigned)(p - s); + needPathCut = true; + } + + if (IsPosixMode) + { + AString s; + + if (needPathCut) + { + const unsigned nameLen = item.Name.Len() - namePos; + if ( item.LinkFlag >= NLinkFlag::kNormal + && item.LinkFlag <= NLinkFlag::kDirectory + && namePos > 1 + && nameLen != 0 + // && IsPrefixAllowed + && item.IsMagic_Posix_ustar_00()) + { + /* GNU TAR decoder supports prefix field, only if (magic) + signature matches 6-bytes "ustar\0". + so here we use prefix field only in posix mode with posix signature */ + + allowPrefix = true; + // allowPrefix = false; // for debug + if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max) + { + needPathCut = false; + /* we will set Prefix and Glob_Name later, for such conditions: + if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */ + } + } + + if (needPathCut) + AddPaxLine(s, "path", item.Name); + } + + // AddPaxLine(s, "testname", AString("testval")); // for debug + + if (item.LinkName.Len() > kNameSize_Max) + AddPaxLine(s, "linkpath", item.LinkName); + + const UInt64 kPaxSize_Limit = ((UInt64)1 << 33); + // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug + // bool zero_PackSize = false; + if (item.PackSize >= kPaxSize_Limit) + { + /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB + But old 7-Zip doesn't detect "size" property from pax header. + So we write real size (>= 8 GiB) to main record in binary format, + and old 7-Zip can decode size correctly */ + // zero_PackSize = true; + AString v; + v.Add_UInt64(item.PackSize); + AddPaxLine(s, "size", v); + } + + /* GNU TAR encoder can set "devmajor" / "devminor" attributes, + but GNU TAR decoder doesn't parse "devmajor" / "devminor" */ + if (item.DeviceMajor_Defined) + AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor); + if (item.DeviceMinor_Defined) + AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor); + + AddPax_UInt32_ifBig(s, "uid", item.UID); + AddPax_UInt32_ifBig(s, "gid", item.GID); + + const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33); + const bool zero_MTime = ( + item.MTime < 0 || + item.MTime >= (Int64)kPax_MTime_Limit); + + const CPaxTime &mtime = item.PaxTimes.MTime; + if (mtime.IsDefined()) + { + bool needPax = false; + if (zero_MTime) + needPax = true; + else if (TimeOptions.NumDigitsMax > 0) + if (mtime.Ns != 0 || + (mtime.NumDigits != 0 && + TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero)) + needPax = true; + if (needPax) + AddPaxTime(s, "mtime", mtime, TimeOptions); + } + + if (item.PaxTimes.ATime.IsDefined()) + AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions); + if (item.PaxTimes.CTime.IsDefined()) + AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions); + + if (item.User.Len() > kUserNameSize) + AddPaxLine(s, "uname", item.User); + if (item.Group.Len() > kGroupNameSize) + AddPaxLine(s, "gname", item.Group); + + /* + // for debug + AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a); + */ + + const unsigned paxSize = s.Len(); + if (paxSize != 0) + { + CItem mi = item; + mi.LinkName.Empty(); + // SparseBlocks will be ignored by Is_Sparse() + // mi.SparseBlocks.Clear(); + // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder + + // GNU TAR writes empty for these fields; + mi.User.Empty(); + mi.Group.Empty(); + mi.UID = 0; + mi.GID = 0; + + mi.DeviceMajor_Defined = false; + mi.DeviceMinor_Defined = false; + + mi.Name = "PaxHeader/@PaxHeader"; + mi.Mode = 0644; // octal + if (zero_MTime) + mi.MTime = 0; + mi.LinkFlag = NLinkFlag::kPax; + // mi.LinkFlag = 'Z'; // for debug + mi.PackSize = paxSize; + // for (unsigned y = 0; y < 1; y++) { // for debug + RINOK(WriteHeaderReal(mi, true)) // isPax + RINOK(Write_Data_And_Residual(s, paxSize)) + // } // for debug + /* + we can send (zero_MTime) for compatibility with gnu tar output. + we can send (zero_MTime = false) for better compatibility with old 7-Zip + */ + // return WriteHeaderReal(item); + /* + false, // isPax + false, // zero_PackSize + false); // zero_MTime + */ + } + } + else // !PosixMode + if (!DOES_NAME_FIT_IN_FIELD(item.Name) || + !DOES_NAME_FIT_IN_FIELD(item.LinkName)) + { + // here we can get all fields from main (item) or create new empty item + /* + CItem mi; + mi.SetDefaultWriteFields(); + */ + CItem mi = item; + mi.LinkName.Empty(); + // SparseBlocks will be ignored by Is_Sparse() + // mi.SparseBlocks.Clear(); + mi.Name = kLongLink; + // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug + // 21.07 : we set Mode and MTime props as in GNU TAR: + mi.Mode = 0644; // octal + mi.MTime = 0; + + mi.User.Empty(); + mi.Group.Empty(); + /* + gnu tar sets "root" for such items: + uid_to_uname (0, &uname); + gid_to_gname (0, &gname); + */ + /* + mi.User = "root"; + mi.Group = "root"; + */ + mi.UID = 0; + mi.GID = 0; + mi.DeviceMajor_Defined = false; + mi.DeviceMinor_Defined = false; + + + for (unsigned i = 0; i < 2; i++) + { + const AString *name; + // We suppose that GNU TAR also writes item for long link before item for LongName? + if (i == 0) + { + mi.LinkFlag = NLinkFlag::kGnu_LongLink; + name = &item.LinkName; + } + else + { + mi.LinkFlag = NLinkFlag::kGnu_LongName; + name = &item.Name; + } + if (DOES_NAME_FIT_IN_FIELD(*name)) + continue; + // GNU TAR writes null character after NAME to file. We do same here: + const unsigned nameStreamSize = name->Len() + 1; + mi.PackSize = nameStreamSize; + // for (unsigned y = 0; y < 3; y++) { // for debug + RINOK(WriteHeaderReal(mi)) + RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize)) + // } + + // for debug + /* + const unsigned kSize = (1 << 29) + 16; + CByteBuffer buf; + buf.Alloc(kSize); + memset(buf, 0, kSize); + memcpy(buf, name->Ptr(), name->Len()); + const unsigned nameStreamSize = kSize; + mi.PackSize = nameStreamSize; + // for (unsigned y = 0; y < 3; y++) { // for debug + RINOK(WriteHeaderReal(mi)); + RINOK(WriteBytes(buf, nameStreamSize)); + RINOK(FillDataResidual(nameStreamSize)); + */ + } + } + + // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR + + if (!DOES_NAME_FIT_IN_FIELD(item.Name)) + { + const unsigned nameLen = item.Name.Len() - namePos; + if (!needPathCut) + Prefix.SetFrom(item.Name, namePos - 1); + else + { + Glob_Name = K_PREFIX_PATH_CUT "/_pc_"; + + if (namePos == 0) + Glob_Name += "root"; + else + { + Glob_Name += "crc32/"; + char temp[12]; + ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp); + Glob_Name += temp; + } + + if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max) + Glob_Name.Add_Slash(); + else + { + Prefix = Glob_Name; + Glob_Name.Empty(); + } + } + Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen); + } + + return WriteHeaderReal(item); +} + + +HRESULT COutArchive::Write_Data(const void *data, unsigned size) +{ + Pos += size; + return WriteStream(Stream, data, size); +} + +HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize) +{ + const unsigned v = ((unsigned)dataSize & (kRecordSize - 1)); + if (v == 0) + return S_OK; + const unsigned rem = kRecordSize - v; + Byte buf[kRecordSize]; + memset(buf, 0, rem); + return Write_Data(buf, rem); +} + + +HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size) +{ + RINOK(Write_Data(data, size)) + return Write_AfterDataResidual(size); +} + + +HRESULT COutArchive::WriteFinishHeader() +{ + Byte record[kRecordSize]; + memset(record, 0, kRecordSize); + + const unsigned kNumFinishRecords = 2; + + /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB) + we also can use cluster alignment: + const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords; + const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB + const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1)); + */ + + for (unsigned i = 0; i < kNumFinishRecords; i++) + { + RINOK(Write_Data(record, kRecordSize)) + } + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h index b7aa6fcde..7b99c2684 100644 --- a/CPP/7zip/Archive/Tar/TarOut.h +++ b/CPP/7zip/Archive/Tar/TarOut.h @@ -1,53 +1,53 @@ -// Archive/TarOut.h - -#ifndef ZIP7_INC_ARCHIVE_TAR_OUT_H -#define ZIP7_INC_ARCHIVE_TAR_OUT_H - -#include "../../../Common/MyCom.h" - -#include "../../IStream.h" - -#include "TarItem.h" - -namespace NArchive { -namespace NTar { - -class COutArchive -{ - CMyComPtr Stream; - - AString Glob_Name; - AString Prefix; - - HRESULT WriteHeaderReal(const CItem &item, bool isPax = false - // , bool zero_PackSize = false - // , bool zero_MTime = false - ); - - HRESULT Write_Data(const void *data, unsigned size); - HRESULT Write_Data_And_Residual(const void *data, unsigned size); - -public: - UInt64 Pos; - bool IsPosixMode; - // bool IsPrefixAllowed; // it's used only if (IsPosixMode == true) - CTimeOptions TimeOptions; - - void Create(ISequentialOutStream *outStream) - { - Stream = outStream; - } - HRESULT WriteHeader(const CItem &item); - HRESULT Write_AfterDataResidual(UInt64 dataSize); - HRESULT WriteFinishHeader(); - - COutArchive(): - Pos(0), - IsPosixMode(false) - // , IsPrefixAllowed(true) - {} -}; - -}} - -#endif +// Archive/TarOut.h + +#ifndef ZIP7_INC_ARCHIVE_TAR_OUT_H +#define ZIP7_INC_ARCHIVE_TAR_OUT_H + +#include "../../../Common/MyCom.h" + +#include "../../IStream.h" + +#include "TarItem.h" + +namespace NArchive { +namespace NTar { + +class COutArchive +{ + CMyComPtr Stream; + + AString Glob_Name; + AString Prefix; + + HRESULT WriteHeaderReal(const CItem &item, bool isPax = false + // , bool zero_PackSize = false + // , bool zero_MTime = false + ); + + HRESULT Write_Data(const void *data, unsigned size); + HRESULT Write_Data_And_Residual(const void *data, unsigned size); + +public: + UInt64 Pos; + bool IsPosixMode; + // bool IsPrefixAllowed; // it's used only if (IsPosixMode == true) + CTimeOptions TimeOptions; + + void Create(ISequentialOutStream *outStream) + { + Stream = outStream; + } + HRESULT WriteHeader(const CItem &item); + HRESULT Write_AfterDataResidual(UInt64 dataSize); + HRESULT WriteFinishHeader(); + + COutArchive(): + Pos(0), + IsPosixMode(false) + // , IsPrefixAllowed(true) + {} +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp index 00c520734..709c19171 100644 --- a/CPP/7zip/Archive/Tar/TarRegister.cpp +++ b/CPP/7zip/Archive/Tar/TarRegister.cpp @@ -1,31 +1,31 @@ -// TarRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "TarHandler.h" - -namespace NArchive { -namespace NTar { - -static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' }; - -REGISTER_ARC_IO( - "tar", "tar ova", NULL, 0xEE, - k_Signature, - NFileHeader::kUstarMagic_Offset, - NArcInfoFlags::kStartOpen - | NArcInfoFlags::kSymLinks - | NArcInfoFlags::kHardLinks - | NArcInfoFlags::kMTime - | NArcInfoFlags::kMTime_Default - // | NArcInfoTimeFlags::kCTime - // | NArcInfoTimeFlags::kATime - , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) - | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) - | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns) - | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix) - , IsArc_Tar) - -}} +// TarRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "TarHandler.h" + +namespace NArchive { +namespace NTar { + +static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' }; + +REGISTER_ARC_IO( + "tar", "tar ova", NULL, 0xEE, + k_Signature, + NFileHeader::kUstarMagic_Offset, + NArcInfoFlags::kStartOpen + | NArcInfoFlags::kSymLinks + | NArcInfoFlags::kHardLinks + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + // | NArcInfoTimeFlags::kCTime + // | NArcInfoTimeFlags::kATime + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix) + , IsArc_Tar) + +}} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp index 746053751..d4ed77212 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.cpp +++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp @@ -1,563 +1,563 @@ -// TarUpdate.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "TarOut.h" -#include "TarUpdate.h" - -namespace NArchive { -namespace NTar { - -static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt) -{ - UInt32 ns; - pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns); - pt.Ns = ns * 100; - pt.NumDigits = 7; -} - - -HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt) -{ - pt.Clear(); - if (prop.vt == VT_EMPTY) - { - // pt.Sec = 0; - return S_OK; - } - if (prop.vt != VT_FILETIME) - return E_INVALIDARG; - { - UInt32 ns; - pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns); - ns *= 100; - pt.NumDigits = 7; - const unsigned prec = prop.wReserved1; - if (prec >= k_PropVar_TimePrec_Base) - { - pt.NumDigits = (int)(prec - k_PropVar_TimePrec_Base); - if (prop.wReserved2 < 100) - ns += prop.wReserved2; - } - pt.Ns = ns; - return S_OK; - } -} - - -static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt) -{ - pt.Clear(); - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(pid, &prop)) - return Prop_To_PaxTime(prop, pt); -} - - -static HRESULT GetUser(IStreamGetProp *getProp, - UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id, - UINT codePage, unsigned utfFlags) -{ - // printf("\nGetUser\n"); - // we keep old values, if both GetProperty() return VT_EMPTY - // we clear old values, if any of GetProperty() returns non-VT_EMPTY; - bool isSet = false; - { - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(pidId, &prop)) - if (prop.vt == VT_UI4) - { - isSet = true; - id = prop.ulVal; - name.Empty(); - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - { - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(pidName, &prop)) - if (prop.vt == VT_BSTR) - { - const UString s = prop.bstrVal; - Get_AString_From_UString(s, name, codePage, utfFlags); - // printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr()); - if (!isSet) - id = 0; - } - else if (prop.vt == VT_UI4) - { - id = prop.ulVal; - name.Empty(); - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - return S_OK; -} - - -/* -static HRESULT GetDevice(IStreamGetProp *getProp, - UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined) -{ - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(kpidDevice, &prop)); - if (prop.vt == VT_EMPTY) - return S_OK; - if (prop.vt != VT_UI8) - return E_INVALIDARG; - { - printf("\nTarUpdate.cpp :: GetDevice()\n"); - const UInt64 v = prop.uhVal.QuadPart; - majo = MY_dev_major(v); - mino = MY_dev_minor(v); - majo_defined = true; - mino_defined = true; - } - return S_OK; -} -*/ - -static HRESULT GetDevice(IStreamGetProp *getProp, - UInt32 pid, UInt32 &id, bool &defined) -{ - defined = false; - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(pid, &prop)) - if (prop.vt == VT_EMPTY) - return S_OK; - if (prop.vt == VT_UI4) - { - id = prop.ulVal; - defined = true; - return S_OK; - } - return E_INVALIDARG; -} - - -HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, - const CObjectVector &inputItems, - const CObjectVector &updateItems, - const CUpdateOptions &options, - IArchiveUpdateCallback *updateCallback) -{ - COutArchive outArchive; - outArchive.Create(outStream); - outArchive.Pos = 0; - outArchive.IsPosixMode = options.PosixMode; - outArchive.TimeOptions = options.TimeOptions; - - Z7_DECL_CMyComPtr_QI_FROM(IOutStream, outSeekStream, outStream) - Z7_DECL_CMyComPtr_QI_FROM(IStreamSetRestriction, setRestriction, outStream) - Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackFile, opCallback, outStream) - - if (outSeekStream) - { - /* - // for debug - Byte buf[1 << 14]; - memset (buf, 0, sizeof(buf)); - RINOK(outStream->Write(buf, sizeof(buf), NULL)); - */ - // we need real outArchive.Pos, if outSeekStream->SetSize() will be used. - RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos)) - } - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - - UInt64 complexity = 0; - - unsigned i; - for (i = 0; i < updateItems.Size(); i++) - { - const CUpdateItem &ui = updateItems[i]; - if (ui.NewData) - { - if (ui.Size == (UInt64)(Int64)-1) - break; - complexity += ui.Size; - } - else - complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned(); - } - - if (i == updateItems.Size()) - RINOK(updateCallback->SetTotal(complexity)) - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create inStreamLimited; - inStreamLimited->SetStream(inStream); - - complexity = 0; - - // const int kNumReduceDigits = -1; // for debug - - for (i = 0;; i++) - { - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()) - - if (i == updateItems.Size()) - { - if (outSeekStream && setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - return outArchive.WriteFinishHeader(); - } - - const CUpdateItem &ui = updateItems[i]; - CItem item; - - if (ui.NewProps) - { - item.SetMagic_Posix(options.PosixMode); - item.Name = ui.Name; - item.User = ui.User; - item.Group = ui.Group; - item.UID = ui.UID; - item.GID = ui.GID; - item.DeviceMajor = ui.DeviceMajor; - item.DeviceMinor = ui.DeviceMinor; - item.DeviceMajor_Defined = ui.DeviceMajor_Defined; - item.DeviceMinor_Defined = ui.DeviceMinor_Defined; - - if (ui.IsDir) - { - item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; - item.PackSize = 0; - } - else - { - item.PackSize = ui.Size; - item.Set_LinkFlag_for_File(ui.Mode); - } - - // 22.00 - item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT; - item.PaxTimes = ui.PaxTimes; - // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug - item.MTime = ui.PaxTimes.MTime.GetSec(); - } - else - item = inputItems[(unsigned)ui.IndexInArc]; - - AString symLink; - if (ui.NewData || ui.NewProps) - { - RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, - options.CodePage, options.UtfFlags, true)) - if (!symLink.IsEmpty()) - { - item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; - item.LinkName = symLink; - } - } - - if (ui.NewData) - { - item.SparseBlocks.Clear(); - item.PackSize = ui.Size; - item.Size = ui.Size; -#if 0 - if (ui.Size == (UInt64)(Int64)-1) - return E_INVALIDARG; -#endif - CMyComPtr fileInStream; - - bool needWrite = true; - - if (!symLink.IsEmpty()) - { - item.PackSize = 0; - item.Size = 0; - } - else - { - const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); - - if (res == S_FALSE) - needWrite = false; - else - { - RINOK(res) - - if (!fileInStream) - { - item.PackSize = 0; - item.Size = 0; - } - else - { - Z7_DECL_CMyComPtr_QI_FROM(IStreamGetProp, getProp, fileInStream) - if (getProp) - { - if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime)) - if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime)) - if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime)) - - if (options.PosixMode) - { - /* - RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor, - item.DeviceMajor_Defined, item.DeviceMinor_Defined)); - */ - bool defined = false; - UInt32 val = 0; - RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined)) - if (defined) - { - item.DeviceMajor = val; - item.DeviceMajor_Defined = true; - item.DeviceMinor = 0; - item.DeviceMinor_Defined = false; - RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined)) - } - } - - RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags)) - RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags)) - - { - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(kpidPosixAttrib, &prop)) - if (prop.vt == VT_EMPTY) - item.Mode = - MY_LIN_S_IRWXO - | MY_LIN_S_IRWXG - | MY_LIN_S_IRWXU - | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG); - else if (prop.vt != VT_UI4) - return E_INVALIDARG; - else - item.Mode = prop.ulVal; - // 21.07 : we clear high file type bits as GNU TAR. - item.Set_LinkFlag_for_File(item.Mode); - item.Mode &= ~(UInt32)MY_LIN_S_IFMT; - } - - { - NWindows::NCOM::CPropVariant prop; - RINOK(getProp->GetProperty(kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - const UInt64 size = prop.uhVal.QuadPart; - // printf("\nTAR after GetProperty(kpidSize size = %8d\n", (unsigned)size); - item.PackSize = size; - item.Size = size; - } - /* - printf("\nNum digits = %d %d\n", - (int)item.PaxTimes.MTime.NumDigits, - (int)item.PaxTimes.MTime.Ns); - */ - } - else - { - Z7_DECL_CMyComPtr_QI_FROM(IStreamGetProps, getProps, fileInStream) - if (getProps) - { - FILETIME mTime, aTime, cTime; - UInt64 size2; - if (getProps->GetProps(&size2, - options.Write_CTime.Val ? &cTime : NULL, - options.Write_ATime.Val ? &aTime : NULL, - options.Write_MTime.Val ? &mTime : NULL, - NULL) == S_OK) - { - item.PackSize = size2; - item.Size = size2; - if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime); - if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime); - if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime); - } - } - } - } - - { - // we must request kpidHardLink after updateCallback->GetStream() - AString hardLink; - RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, - options.CodePage, options.UtfFlags, true)) - if (!hardLink.IsEmpty()) - { - item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; - item.LinkName = hardLink; - item.PackSize = 0; - item.Size = 0; - fileInStream.Release(); - } - } - } - } - - // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug - - if (ui.NewProps) - item.MTime = item.PaxTimes.MTime.GetSec(); - - if (needWrite) - { - if (fileInStream) - // if (item.PackSize == (UInt64)(Int64)-1) - if (item.Size == (UInt64)(Int64)-1) - return E_INVALIDARG; - - const UInt64 headerPos = outArchive.Pos; - // item.PackSize = ((UInt64)1 << 33); // for debug - - if (outSeekStream && setRestriction) - RINOK(setRestriction->SetRestriction(outArchive.Pos, (UInt64)(Int64)-1)) - - RINOK(outArchive.WriteHeader(item)) - if (fileInStream) - { - for (unsigned numPasses = 0;; numPasses++) - { - // printf("\nTAR numPasses = %d" " old size = %8d\n", numPasses, (unsigned)item.PackSize); - /* we support 2 attempts to write header: - pass-0: main pass: - pass-1: additional pass, if size_of_file and size_of_header are changed */ - if (numPasses >= 2) - { - // opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged; - // break; - return E_FAIL; - } - - const UInt64 dataPos = outArchive.Pos; - RINOK(copyCoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) - outArchive.Pos += copyCoder->TotalSize; - RINOK(outArchive.Write_AfterDataResidual(copyCoder->TotalSize)) - // printf("\nTAR after Code old size = %8d copyCoder->TotalSize = %8d \n", (unsigned)item.PackSize, (unsigned)copyCoder->TotalSize); - // if (numPasses >= 10) // for debug - if (copyCoder->TotalSize == item.PackSize) - break; - - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient, - NUpdateNotifyOp::kInFileChanged)) - } - - if (!outSeekStream) - return E_FAIL; - const UInt64 nextPos = outArchive.Pos; - RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL)) - outArchive.Pos = headerPos; - item.PackSize = copyCoder->TotalSize; - - RINOK(outArchive.WriteHeader(item)) - - // if (numPasses >= 10) // for debug - if (outArchive.Pos == dataPos) - { - const UInt64 alignedSize = nextPos - dataPos; - if (alignedSize != 0) - { - RINOK(outSeekStream->Seek((Int64)alignedSize, STREAM_SEEK_CUR, NULL)) - outArchive.Pos += alignedSize; - } - break; - } - - // size of header was changed. - // we remove data after header and try new attempt, if required - Z7_DECL_CMyComPtr_QI_FROM(IInStream, fileSeekStream, fileInStream) - if (!fileSeekStream) - return E_FAIL; - RINOK(InStream_SeekToBegin(fileSeekStream)) - RINOK(outSeekStream->SetSize(outArchive.Pos)) - if (item.PackSize == 0) - break; - } - } - } - - complexity += item.PackSize; - fileInStream.Release(); - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - } - else - { - // (ui.NewData == false) - - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, - NUpdateNotifyOp::kReplicate)) - } - - const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc]; - UInt64 size, pos; - - if (ui.NewProps) - { - // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8); - - if (!symLink.IsEmpty()) - { - item.PackSize = 0; - item.Size = 0; - } - else - { - if (ui.IsDir == existItem.IsDir()) - item.LinkFlag = existItem.LinkFlag; - - item.SparseBlocks = existItem.SparseBlocks; - item.Size = existItem.Size; - item.PackSize = existItem.PackSize; - } - - item.DeviceMajor_Defined = existItem.DeviceMajor_Defined; - item.DeviceMinor_Defined = existItem.DeviceMinor_Defined; - item.DeviceMajor = existItem.DeviceMajor; - item.DeviceMinor = existItem.DeviceMinor; - item.UID = existItem.UID; - item.GID = existItem.GID; - - RINOK(outArchive.WriteHeader(item)) - size = existItem.Get_PackSize_Aligned(); - pos = existItem.Get_DataPos(); - } - else - { - size = existItem.Get_FullSize_Aligned(); - pos = existItem.HeaderPos; - } - - if (size != 0) - { - RINOK(InStream_SeekSet(inStream, pos)) - inStreamLimited->Init(size); - if (outSeekStream && setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - // 22.00 : we copy Residual data from old archive to new archive instead of zeroing - RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != size) - return E_FAIL; - outArchive.Pos += size; - // RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize)); - complexity += size; - } - } - } -} - -}} +// TarUpdate.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "TarOut.h" +#include "TarUpdate.h" + +namespace NArchive { +namespace NTar { + +static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt) +{ + UInt32 ns; + pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns); + pt.Ns = ns * 100; + pt.NumDigits = 7; +} + + +HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt) +{ + pt.Clear(); + if (prop.vt == VT_EMPTY) + { + // pt.Sec = 0; + return S_OK; + } + if (prop.vt != VT_FILETIME) + return E_INVALIDARG; + { + UInt32 ns; + pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns); + ns *= 100; + pt.NumDigits = 7; + const unsigned prec = prop.wReserved1; + if (prec >= k_PropVar_TimePrec_Base) + { + pt.NumDigits = (int)(prec - k_PropVar_TimePrec_Base); + if (prop.wReserved2 < 100) + ns += prop.wReserved2; + } + pt.Ns = ns; + return S_OK; + } +} + + +static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt) +{ + pt.Clear(); + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pid, &prop)) + return Prop_To_PaxTime(prop, pt); +} + + +static HRESULT GetUser(IStreamGetProp *getProp, + UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id, + UINT codePage, unsigned utfFlags) +{ + // printf("\nGetUser\n"); + // we keep old values, if both GetProperty() return VT_EMPTY + // we clear old values, if any of GetProperty() returns non-VT_EMPTY; + bool isSet = false; + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pidId, &prop)) + if (prop.vt == VT_UI4) + { + isSet = true; + id = prop.ulVal; + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pidName, &prop)) + if (prop.vt == VT_BSTR) + { + const UString s = prop.bstrVal; + Get_AString_From_UString(s, name, codePage, utfFlags); + // printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr()); + if (!isSet) + id = 0; + } + else if (prop.vt == VT_UI4) + { + id = prop.ulVal; + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + + +/* +static HRESULT GetDevice(IStreamGetProp *getProp, + UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined) +{ + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(kpidDevice, &prop)); + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt != VT_UI8) + return E_INVALIDARG; + { + printf("\nTarUpdate.cpp :: GetDevice()\n"); + const UInt64 v = prop.uhVal.QuadPart; + majo = MY_dev_major(v); + mino = MY_dev_minor(v); + majo_defined = true; + mino_defined = true; + } + return S_OK; +} +*/ + +static HRESULT GetDevice(IStreamGetProp *getProp, + UInt32 pid, UInt32 &id, bool &defined) +{ + defined = false; + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pid, &prop)) + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt == VT_UI4) + { + id = prop.ulVal; + defined = true; + return S_OK; + } + return E_INVALIDARG; +} + + +HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, + const CObjectVector &inputItems, + const CObjectVector &updateItems, + const CUpdateOptions &options, + IArchiveUpdateCallback *updateCallback) +{ + COutArchive outArchive; + outArchive.Create(outStream); + outArchive.Pos = 0; + outArchive.IsPosixMode = options.PosixMode; + outArchive.TimeOptions = options.TimeOptions; + + Z7_DECL_CMyComPtr_QI_FROM(IOutStream, outSeekStream, outStream) + Z7_DECL_CMyComPtr_QI_FROM(IStreamSetRestriction, setRestriction, outStream) + Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackFile, opCallback, outStream) + + if (outSeekStream) + { + /* + // for debug + Byte buf[1 << 14]; + memset (buf, 0, sizeof(buf)); + RINOK(outStream->Write(buf, sizeof(buf), NULL)); + */ + // we need real outArchive.Pos, if outSeekStream->SetSize() will be used. + RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos)) + } + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + + UInt64 complexity = 0; + + unsigned i; + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + if (ui.Size == (UInt64)(Int64)-1) + break; + complexity += ui.Size; + } + else + complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned(); + } + + if (i == updateItems.Size()) + RINOK(updateCallback->SetTotal(complexity)) + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create inStreamLimited; + inStreamLimited->SetStream(inStream); + + complexity = 0; + + // const int kNumReduceDigits = -1; // for debug + + for (i = 0;; i++) + { + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()) + + if (i == updateItems.Size()) + { + if (outSeekStream && setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + return outArchive.WriteFinishHeader(); + } + + const CUpdateItem &ui = updateItems[i]; + CItem item; + + if (ui.NewProps) + { + item.SetMagic_Posix(options.PosixMode); + item.Name = ui.Name; + item.User = ui.User; + item.Group = ui.Group; + item.UID = ui.UID; + item.GID = ui.GID; + item.DeviceMajor = ui.DeviceMajor; + item.DeviceMinor = ui.DeviceMinor; + item.DeviceMajor_Defined = ui.DeviceMajor_Defined; + item.DeviceMinor_Defined = ui.DeviceMinor_Defined; + + if (ui.IsDir) + { + item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; + item.PackSize = 0; + } + else + { + item.PackSize = ui.Size; + item.Set_LinkFlag_for_File(ui.Mode); + } + + // 22.00 + item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT; + item.PaxTimes = ui.PaxTimes; + // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug + item.MTime = ui.PaxTimes.MTime.GetSec(); + } + else + item = inputItems[(unsigned)ui.IndexInArc]; + + AString symLink; + if (ui.NewData || ui.NewProps) + { + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, + options.CodePage, options.UtfFlags, true)) + if (!symLink.IsEmpty()) + { + item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; + item.LinkName = symLink; + } + } + + if (ui.NewData) + { + item.SparseBlocks.Clear(); + item.PackSize = ui.Size; + item.Size = ui.Size; +#if 0 + if (ui.Size == (UInt64)(Int64)-1) + return E_INVALIDARG; +#endif + CMyComPtr fileInStream; + + bool needWrite = true; + + if (!symLink.IsEmpty()) + { + item.PackSize = 0; + item.Size = 0; + } + else + { + const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + + if (res == S_FALSE) + needWrite = false; + else + { + RINOK(res) + + if (!fileInStream) + { + item.PackSize = 0; + item.Size = 0; + } + else + { + Z7_DECL_CMyComPtr_QI_FROM(IStreamGetProp, getProp, fileInStream) + if (getProp) + { + if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime)) + if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime)) + if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime)) + + if (options.PosixMode) + { + /* + RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor, + item.DeviceMajor_Defined, item.DeviceMinor_Defined)); + */ + bool defined = false; + UInt32 val = 0; + RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined)) + if (defined) + { + item.DeviceMajor = val; + item.DeviceMajor_Defined = true; + item.DeviceMinor = 0; + item.DeviceMinor_Defined = false; + RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined)) + } + } + + RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags)) + RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags)) + + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(kpidPosixAttrib, &prop)) + if (prop.vt == VT_EMPTY) + item.Mode = + MY_LIN_S_IRWXO + | MY_LIN_S_IRWXG + | MY_LIN_S_IRWXU + | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG); + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + item.Mode = prop.ulVal; + // 21.07 : we clear high file type bits as GNU TAR. + item.Set_LinkFlag_for_File(item.Mode); + item.Mode &= ~(UInt32)MY_LIN_S_IFMT; + } + + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + const UInt64 size = prop.uhVal.QuadPart; + // printf("\nTAR after GetProperty(kpidSize size = %8d\n", (unsigned)size); + item.PackSize = size; + item.Size = size; + } + /* + printf("\nNum digits = %d %d\n", + (int)item.PaxTimes.MTime.NumDigits, + (int)item.PaxTimes.MTime.Ns); + */ + } + else + { + Z7_DECL_CMyComPtr_QI_FROM(IStreamGetProps, getProps, fileInStream) + if (getProps) + { + FILETIME mTime, aTime, cTime; + UInt64 size2; + if (getProps->GetProps(&size2, + options.Write_CTime.Val ? &cTime : NULL, + options.Write_ATime.Val ? &aTime : NULL, + options.Write_MTime.Val ? &mTime : NULL, + NULL) == S_OK) + { + item.PackSize = size2; + item.Size = size2; + if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime); + if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime); + if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime); + } + } + } + } + + { + // we must request kpidHardLink after updateCallback->GetStream() + AString hardLink; + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, + options.CodePage, options.UtfFlags, true)) + if (!hardLink.IsEmpty()) + { + item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; + item.LinkName = hardLink; + item.PackSize = 0; + item.Size = 0; + fileInStream.Release(); + } + } + } + } + + // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug + + if (ui.NewProps) + item.MTime = item.PaxTimes.MTime.GetSec(); + + if (needWrite) + { + if (fileInStream) + // if (item.PackSize == (UInt64)(Int64)-1) + if (item.Size == (UInt64)(Int64)-1) + return E_INVALIDARG; + + const UInt64 headerPos = outArchive.Pos; + // item.PackSize = ((UInt64)1 << 33); // for debug + + if (outSeekStream && setRestriction) + RINOK(setRestriction->SetRestriction(outArchive.Pos, (UInt64)(Int64)-1)) + + RINOK(outArchive.WriteHeader(item)) + if (fileInStream) + { + for (unsigned numPasses = 0;; numPasses++) + { + // printf("\nTAR numPasses = %d" " old size = %8d\n", numPasses, (unsigned)item.PackSize); + /* we support 2 attempts to write header: + pass-0: main pass: + pass-1: additional pass, if size_of_file and size_of_header are changed */ + if (numPasses >= 2) + { + // opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged; + // break; + return E_FAIL; + } + + const UInt64 dataPos = outArchive.Pos; + RINOK(copyCoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) + outArchive.Pos += copyCoder->TotalSize; + RINOK(outArchive.Write_AfterDataResidual(copyCoder->TotalSize)) + // printf("\nTAR after Code old size = %8d copyCoder->TotalSize = %8d \n", (unsigned)item.PackSize, (unsigned)copyCoder->TotalSize); + // if (numPasses >= 10) // for debug + if (copyCoder->TotalSize == item.PackSize) + break; + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient, + NUpdateNotifyOp::kInFileChanged)) + } + + if (!outSeekStream) + return E_FAIL; + const UInt64 nextPos = outArchive.Pos; + RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL)) + outArchive.Pos = headerPos; + item.PackSize = copyCoder->TotalSize; + + RINOK(outArchive.WriteHeader(item)) + + // if (numPasses >= 10) // for debug + if (outArchive.Pos == dataPos) + { + const UInt64 alignedSize = nextPos - dataPos; + if (alignedSize != 0) + { + RINOK(outSeekStream->Seek((Int64)alignedSize, STREAM_SEEK_CUR, NULL)) + outArchive.Pos += alignedSize; + } + break; + } + + // size of header was changed. + // we remove data after header and try new attempt, if required + Z7_DECL_CMyComPtr_QI_FROM(IInStream, fileSeekStream, fileInStream) + if (!fileSeekStream) + return E_FAIL; + RINOK(InStream_SeekToBegin(fileSeekStream)) + RINOK(outSeekStream->SetSize(outArchive.Pos)) + if (item.PackSize == 0) + break; + } + } + } + + complexity += item.PackSize; + fileInStream.Release(); + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + } + else + { + // (ui.NewData == false) + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, + NUpdateNotifyOp::kReplicate)) + } + + const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc]; + UInt64 size, pos; + + if (ui.NewProps) + { + // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8); + + if (!symLink.IsEmpty()) + { + item.PackSize = 0; + item.Size = 0; + } + else + { + if (ui.IsDir == existItem.IsDir()) + item.LinkFlag = existItem.LinkFlag; + + item.SparseBlocks = existItem.SparseBlocks; + item.Size = existItem.Size; + item.PackSize = existItem.PackSize; + } + + item.DeviceMajor_Defined = existItem.DeviceMajor_Defined; + item.DeviceMinor_Defined = existItem.DeviceMinor_Defined; + item.DeviceMajor = existItem.DeviceMajor; + item.DeviceMinor = existItem.DeviceMinor; + item.UID = existItem.UID; + item.GID = existItem.GID; + + RINOK(outArchive.WriteHeader(item)) + size = existItem.Get_PackSize_Aligned(); + pos = existItem.Get_DataPos(); + } + else + { + size = existItem.Get_FullSize_Aligned(); + pos = existItem.HeaderPos; + } + + if (size != 0) + { + RINOK(InStream_SeekSet(inStream, pos)) + inStreamLimited->Init(size); + if (outSeekStream && setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + // 22.00 : we copy Residual data from old archive to new archive instead of zeroing + RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != size) + return E_FAIL; + outArchive.Pos += size; + // RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize)); + complexity += size; + } + } + } +} + +}} diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h index 7b1e0269b..f6c2e779f 100644 --- a/CPP/7zip/Archive/Tar/TarUpdate.h +++ b/CPP/7zip/Archive/Tar/TarUpdate.h @@ -1,74 +1,74 @@ -// TarUpdate.h - -#ifndef ZIP7_INC_TAR_UPDATE_H -#define ZIP7_INC_TAR_UPDATE_H - -#include "../IArchive.h" - -#include "TarItem.h" - -namespace NArchive { -namespace NTar { - -struct CUpdateItem -{ - int IndexInArc; - unsigned IndexInClient; - UInt64 Size; - // Int64 MTime; - UInt32 Mode; - bool NewData; - bool NewProps; - bool IsDir; - bool DeviceMajor_Defined; - bool DeviceMinor_Defined; - UInt32 UID; - UInt32 GID; - UInt32 DeviceMajor; - UInt32 DeviceMinor; - AString Name; - AString User; - AString Group; - - CPaxTimes PaxTimes; - - CUpdateItem(): - Size(0), - IsDir(false), - DeviceMajor_Defined(false), - DeviceMinor_Defined(false), - UID(0), - GID(0) - {} -}; - - -struct CUpdateOptions -{ - UINT CodePage; - unsigned UtfFlags; - bool PosixMode; - CBoolPair Write_MTime; - CBoolPair Write_ATime; - CBoolPair Write_CTime; - CTimeOptions TimeOptions; -}; - - -HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, - const CObjectVector &inputItems, - const CObjectVector &updateItems, - const CUpdateOptions &options, - IArchiveUpdateCallback *updateCallback); - -HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, - UINT codePage, unsigned utfFlags, bool convertSlash); - -HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt); - -void Get_AString_From_UString(const UString &s, AString &res, - UINT codePage, unsigned utfFlags); - -}} - -#endif +// TarUpdate.h + +#ifndef ZIP7_INC_TAR_UPDATE_H +#define ZIP7_INC_TAR_UPDATE_H + +#include "../IArchive.h" + +#include "TarItem.h" + +namespace NArchive { +namespace NTar { + +struct CUpdateItem +{ + int IndexInArc; + unsigned IndexInClient; + UInt64 Size; + // Int64 MTime; + UInt32 Mode; + bool NewData; + bool NewProps; + bool IsDir; + bool DeviceMajor_Defined; + bool DeviceMinor_Defined; + UInt32 UID; + UInt32 GID; + UInt32 DeviceMajor; + UInt32 DeviceMinor; + AString Name; + AString User; + AString Group; + + CPaxTimes PaxTimes; + + CUpdateItem(): + Size(0), + IsDir(false), + DeviceMajor_Defined(false), + DeviceMinor_Defined(false), + UID(0), + GID(0) + {} +}; + + +struct CUpdateOptions +{ + UINT CodePage; + unsigned UtfFlags; + bool PosixMode; + CBoolPair Write_MTime; + CBoolPair Write_ATime; + CBoolPair Write_CTime; + CTimeOptions TimeOptions; +}; + + +HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, + const CObjectVector &inputItems, + const CObjectVector &updateItems, + const CUpdateOptions &options, + IArchiveUpdateCallback *updateCallback); + +HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, + UINT codePage, unsigned utfFlags, bool convertSlash); + +HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt); + +void Get_AString_From_UString(const UString &s, AString &res, + UINT codePage, unsigned utfFlags); + +}} + +#endif diff --git a/CPP/7zip/Archive/Udf/StdAfx.h b/CPP/7zip/Archive/Udf/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Udf/StdAfx.h +++ b/CPP/7zip/Archive/Udf/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp index e769a6353..7c74c805c 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.cpp +++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp @@ -1,427 +1,427 @@ -// UdfHandler.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/RegisterArc.h" -#include "../../Common/StreamObjects.h" - -#include "../../Compress/CopyCoder.h" - -#include "UdfHandler.h" - -namespace NArchive { -namespace NUdf { - -static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop) -{ - UInt64 numSecs; - const Byte *d = t.Data; - if (!NWindows::NTime::GetSecondsSince1601(t.GetYear(), d[4], d[5], d[6], d[7], d[8], numSecs)) - return; - if (t.IsLocal()) - numSecs = (UInt64)((Int64)numSecs - (Int64)((Int32)t.GetMinutesOffset() * 60)); - const UInt32 m0 = d[9]; - const UInt32 m1 = d[10]; - const UInt32 m2 = d[11]; - unsigned numDigits = 0; - UInt64 v = numSecs * 10000000; - if (m0 < 100 && m1 < 100 && m2 < 100) - { - v += m0 * 100000 + m1 * 1000 + m2 * 10; - numDigits = 6; - } - prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits); -} - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidATime, - kpidCTime, - kpidChangeTime, - // kpidUserId, - // kpidGroupId, - // kpidPosixAttrib, - kpidLinks -}; - -static const Byte kArcProps[] = -{ - kpidUnpackVer, - kpidClusterSize, - kpidSectorSize, - kpidCTime, - kpidMTime, - kpidComment -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: prop = _archive.PhySize; break; - - case kpidUnpackVer: - { - if (_archive.LogVols.Size() == 1) - { - UString s; - const CLogVol &vol = _archive.LogVols[0]; - vol.DomainId.AddUdfVersionTo(s); - if (!s.IsEmpty()) - prop = s; - } - break; - } - case kpidComment: - { - UString comment = _archive.GetComment(); - if (!comment.IsEmpty()) - prop = comment; - break; - } - - case kpidClusterSize: - if (_archive.LogVols.Size() > 0) - { - UInt32 blockSize = _archive.LogVols[0].BlockSize; - unsigned i; - for (i = 1; i < _archive.LogVols.Size(); i++) - if (_archive.LogVols[i].BlockSize != blockSize) - break; - if (i == _archive.LogVols.Size()) - prop = blockSize; - } - break; - - case kpidSectorSize: prop = ((UInt32)1 << _archive.SecLogSize); break; - - case kpidCTime: - if (_archive.LogVols.Size() == 1) - { - const CLogVol &vol = _archive.LogVols[0]; - if (vol.FileSets.Size() >= 1) - UdfTimeToFileTime(vol.FileSets[0].RecordingTime, prop); - } - break; - case kpidMTime: - if (_archive.PrimeVols.Size() == 1) - { - const CPrimeVol &pv = _archive.PrimeVols[0]; - UdfTimeToFileTime(pv.RecordingTime, prop); - } - break; - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; - if (_archive.Unsupported) v |= kpv_ErrorFlags_UnsupportedFeature; - if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_archive.NoEndAnchor) v |= kpv_ErrorFlags_HeadersError; - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -class CProgressImp Z7_final: public CProgressVirt -{ - CMyComPtr _callback; - UInt64 _numFiles; - UInt64 _numBytes; -public: - HRESULT SetTotal(UInt64 numBytes) Z7_override; - HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) Z7_override; - HRESULT SetCompleted() Z7_override; - CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {} -}; - -HRESULT CProgressImp::SetTotal(UInt64 numBytes) -{ - if (_callback) - return _callback->SetTotal(NULL, &numBytes); - return S_OK; -} - -HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes) -{ - _numFiles = numFiles; - _numBytes = numBytes; - return SetCompleted(); -} - -HRESULT CProgressImp::SetCompleted() -{ - if (_callback) - return _callback->SetCompleted(&_numFiles, &_numBytes); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - CProgressImp progressImp(callback); - RINOK(_archive.Open(stream, &progressImp)) - bool showVolName = (_archive.LogVols.Size() > 1); - FOR_VECTOR (volIndex, _archive.LogVols) - { - const CLogVol &vol = _archive.LogVols[volIndex]; - bool showFileSetName = (vol.FileSets.Size() > 1); - // showFileSetName = true; // for debug - FOR_VECTOR (fsIndex, vol.FileSets) - { - const CFileSet &fs = vol.FileSets[fsIndex]; - for (unsigned i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++) - { - CRef2 ref2; - ref2.Vol = volIndex; - ref2.Fs = fsIndex; - ref2.Ref = i; - _refs2.Add(ref2); - } - } - } - _inStream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _inStream.Release(); - _archive.Clear(); - _refs2.Clear(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _refs2.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - { - const CRef2 &ref2 = _refs2[index]; - const CLogVol &vol = _archive.LogVols[ref2.Vol]; - const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - switch (propID) - { - case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref, - _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break; - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break; - case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; - case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; - case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; - case kpidCTime: - if (item.IsExtended) - UdfTimeToFileTime(item.CreateTime, prop); - break; - case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break; - // case kpidUserId: prop = item.Uid; break; - // case kpidGroupId: prop = item.Gid; break; - // case kpidPosixAttrib: prop = (UInt32)item.Permissions; break; - case kpidLinks: prop = (UInt32)item.FileLinkCount; break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - *stream = NULL; - - const CRef2 &ref2 = _refs2[index]; - const CLogVol &vol = _archive.LogVols[ref2.Vol]; - const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - UInt64 size = item.Size; - - if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item)) - return E_NOTIMPL; - - if (item.IsInline) - { - Create_BufInStream_WithNewBuffer(item.InlineData, stream); - return S_OK; - } - - CExtentsStream *extentStreamSpec = new CExtentsStream(); - CMyComPtr extentStream = extentStreamSpec; - - extentStreamSpec->Stream = _inStream; - - UInt64 virtOffset = 0; - FOR_VECTOR (extentIndex, item.Extents) - { - const CMyExtent &extent = item.Extents[extentIndex]; - UInt32 len = extent.GetLen(); - if (len == 0) - continue; - if (size < len) - return S_FALSE; - - const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - UInt32 logBlockNumber = extent.Pos; - const CPartition &partition = _archive.Partitions[partitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + - (UInt64)logBlockNumber * vol.BlockSize; - - CSeekExtent se; - se.Phy = offset; - se.Virt = virtOffset; - virtOffset += len; - extentStreamSpec->Extents.Add(se); - - size -= len; - } - if (size != 0) - return S_FALSE; - CSeekExtent se; - se.Phy = 0; - se.Virt = virtOffset; - extentStreamSpec->Extents.Add(se); - extentStreamSpec->Init(); - *stream = extentStream.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _refs2.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - - for (i = 0; i < numItems; i++) - { - const UInt32 index = (allFilesMode ? i : indices[i]); - const CRef2 &ref2 = _refs2[index]; - const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - if (!item.IsDir()) - totalSize += item.Size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - UInt64 currentTotalSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create outStream; - - for (i = 0;; i++) - { - lps->InSize = lps->OutSize = currentTotalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - const CRef2 &ref2 = _refs2[index]; - const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref]; - const CFile &file = _archive.Files[ref.FileIndex]; - const CItem &item = _archive.Items[file.ItemIndex]; - - if (item.IsDir()) - { - RINOK(extractCallback->PrepareOperation(askMode)) - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - currentTotalSize += item.Size; - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - outStream->SetStream(realOutStream); - realOutStream.Release(); - outStream->Init(item.Size); - Int32 opRes; - { - CMyComPtr udfInStream; - const HRESULT res = GetStream(index, &udfInStream); - if (res == E_NOTIMPL) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else if (res != S_OK) - opRes = NExtract::NOperationResult::kDataError; - else - { - RINOK(copyCoder.Interface()->Code(udfInStream, outStream, NULL, NULL, lps)) - opRes = outStream->IsFinishedOK() ? - NExtract::NOperationResult::kOK: - NExtract::NOperationResult::kDataError; - } - } - outStream->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -static const UInt32 kIsoStartPos = 0x8000; - -// 5, { 0, 'N', 'S', 'R', '0' }, - -static const Byte k_Signature[] = -{ - 8, 0, 'B', 'E', 'A', '0', '1', 1, 0, - 6, 1, 'C', 'D', '0', '0', '1' -}; - -REGISTER_ARC_I( - "Udf", "udf iso img", NULL, 0xE0, - k_Signature, - kIsoStartPos, - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kStartOpen, - IsArc_Udf) - -}} +// UdfHandler.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamObjects.h" + +#include "../../Compress/CopyCoder.h" + +#include "UdfHandler.h" + +namespace NArchive { +namespace NUdf { + +static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop) +{ + UInt64 numSecs; + const Byte *d = t.Data; + if (!NWindows::NTime::GetSecondsSince1601(t.GetYear(), d[4], d[5], d[6], d[7], d[8], numSecs)) + return; + if (t.IsLocal()) + numSecs = (UInt64)((Int64)numSecs - (Int64)((Int32)t.GetMinutesOffset() * 60)); + const UInt32 m0 = d[9]; + const UInt32 m1 = d[10]; + const UInt32 m2 = d[11]; + unsigned numDigits = 0; + UInt64 v = numSecs * 10000000; + if (m0 < 100 && m1 < 100 && m2 < 100) + { + v += m0 * 100000 + m1 * 1000 + m2 * 10; + numDigits = 6; + } + prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits); +} + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidATime, + kpidCTime, + kpidChangeTime, + // kpidUserId, + // kpidGroupId, + // kpidPosixAttrib, + kpidLinks +}; + +static const Byte kArcProps[] = +{ + kpidUnpackVer, + kpidClusterSize, + kpidSectorSize, + kpidCTime, + kpidMTime, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: prop = _archive.PhySize; break; + + case kpidUnpackVer: + { + if (_archive.LogVols.Size() == 1) + { + UString s; + const CLogVol &vol = _archive.LogVols[0]; + vol.DomainId.AddUdfVersionTo(s); + if (!s.IsEmpty()) + prop = s; + } + break; + } + case kpidComment: + { + UString comment = _archive.GetComment(); + if (!comment.IsEmpty()) + prop = comment; + break; + } + + case kpidClusterSize: + if (_archive.LogVols.Size() > 0) + { + UInt32 blockSize = _archive.LogVols[0].BlockSize; + unsigned i; + for (i = 1; i < _archive.LogVols.Size(); i++) + if (_archive.LogVols[i].BlockSize != blockSize) + break; + if (i == _archive.LogVols.Size()) + prop = blockSize; + } + break; + + case kpidSectorSize: prop = ((UInt32)1 << _archive.SecLogSize); break; + + case kpidCTime: + if (_archive.LogVols.Size() == 1) + { + const CLogVol &vol = _archive.LogVols[0]; + if (vol.FileSets.Size() >= 1) + UdfTimeToFileTime(vol.FileSets[0].RecordingTime, prop); + } + break; + case kpidMTime: + if (_archive.PrimeVols.Size() == 1) + { + const CPrimeVol &pv = _archive.PrimeVols[0]; + UdfTimeToFileTime(pv.RecordingTime, prop); + } + break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (_archive.Unsupported) v |= kpv_ErrorFlags_UnsupportedFeature; + if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_archive.NoEndAnchor) v |= kpv_ErrorFlags_HeadersError; + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +class CProgressImp Z7_final: public CProgressVirt +{ + CMyComPtr _callback; + UInt64 _numFiles; + UInt64 _numBytes; +public: + HRESULT SetTotal(UInt64 numBytes) Z7_override; + HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) Z7_override; + HRESULT SetCompleted() Z7_override; + CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {} +}; + +HRESULT CProgressImp::SetTotal(UInt64 numBytes) +{ + if (_callback) + return _callback->SetTotal(NULL, &numBytes); + return S_OK; +} + +HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes) +{ + _numFiles = numFiles; + _numBytes = numBytes; + return SetCompleted(); +} + +HRESULT CProgressImp::SetCompleted() +{ + if (_callback) + return _callback->SetCompleted(&_numFiles, &_numBytes); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + CProgressImp progressImp(callback); + RINOK(_archive.Open(stream, &progressImp)) + bool showVolName = (_archive.LogVols.Size() > 1); + FOR_VECTOR (volIndex, _archive.LogVols) + { + const CLogVol &vol = _archive.LogVols[volIndex]; + bool showFileSetName = (vol.FileSets.Size() > 1); + // showFileSetName = true; // for debug + FOR_VECTOR (fsIndex, vol.FileSets) + { + const CFileSet &fs = vol.FileSets[fsIndex]; + for (unsigned i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++) + { + CRef2 ref2; + ref2.Vol = volIndex; + ref2.Fs = fsIndex; + ref2.Ref = i; + _refs2.Add(ref2); + } + } + } + _inStream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _inStream.Release(); + _archive.Clear(); + _refs2.Clear(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _refs2.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + { + const CRef2 &ref2 = _refs2[index]; + const CLogVol &vol = _archive.LogVols[ref2.Vol]; + const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + switch (propID) + { + case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref, + _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break; + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break; + case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; + case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; + case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; + case kpidCTime: + if (item.IsExtended) + UdfTimeToFileTime(item.CreateTime, prop); + break; + case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break; + // case kpidUserId: prop = item.Uid; break; + // case kpidGroupId: prop = item.Gid; break; + // case kpidPosixAttrib: prop = (UInt32)item.Permissions; break; + case kpidLinks: prop = (UInt32)item.FileLinkCount; break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + *stream = NULL; + + const CRef2 &ref2 = _refs2[index]; + const CLogVol &vol = _archive.LogVols[ref2.Vol]; + const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + UInt64 size = item.Size; + + if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item)) + return E_NOTIMPL; + + if (item.IsInline) + { + Create_BufInStream_WithNewBuffer(item.InlineData, stream); + return S_OK; + } + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr extentStream = extentStreamSpec; + + extentStreamSpec->Stream = _inStream; + + UInt64 virtOffset = 0; + FOR_VECTOR (extentIndex, item.Extents) + { + const CMyExtent &extent = item.Extents[extentIndex]; + UInt32 len = extent.GetLen(); + if (len == 0) + continue; + if (size < len) + return S_FALSE; + + const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + UInt32 logBlockNumber = extent.Pos; + const CPartition &partition = _archive.Partitions[partitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + + (UInt64)logBlockNumber * vol.BlockSize; + + CSeekExtent se; + se.Phy = offset; + se.Virt = virtOffset; + virtOffset += len; + extentStreamSpec->Extents.Add(se); + + size -= len; + } + if (size != 0) + return S_FALSE; + CSeekExtent se; + se.Phy = 0; + se.Virt = virtOffset; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _refs2.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + + for (i = 0; i < numItems; i++) + { + const UInt32 index = (allFilesMode ? i : indices[i]); + const CRef2 &ref2 = _refs2[index]; + const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + if (!item.IsDir()) + totalSize += item.Size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + UInt64 currentTotalSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create outStream; + + for (i = 0;; i++) + { + lps->InSize = lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + const CRef2 &ref2 = _refs2[index]; + const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref]; + const CFile &file = _archive.Files[ref.FileIndex]; + const CItem &item = _archive.Items[file.ItemIndex]; + + if (item.IsDir()) + { + RINOK(extractCallback->PrepareOperation(askMode)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + currentTotalSize += item.Size; + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + outStream->SetStream(realOutStream); + realOutStream.Release(); + outStream->Init(item.Size); + Int32 opRes; + { + CMyComPtr udfInStream; + const HRESULT res = GetStream(index, &udfInStream); + if (res == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else if (res != S_OK) + opRes = NExtract::NOperationResult::kDataError; + else + { + RINOK(copyCoder.Interface()->Code(udfInStream, outStream, NULL, NULL, lps)) + opRes = outStream->IsFinishedOK() ? + NExtract::NOperationResult::kOK: + NExtract::NOperationResult::kDataError; + } + } + outStream->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +static const UInt32 kIsoStartPos = 0x8000; + +// 5, { 0, 'N', 'S', 'R', '0' }, + +static const Byte k_Signature[] = +{ + 8, 0, 'B', 'E', 'A', '0', '1', 1, 0, + 6, 1, 'C', 'D', '0', '0', '1' +}; + +REGISTER_ARC_I( + "Udf", "udf iso img", NULL, 0xE0, + k_Signature, + kIsoStartPos, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kStartOpen, + IsArc_Udf) + +}} diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h index aec18cc29..5426d064f 100644 --- a/CPP/7zip/Archive/Udf/UdfHandler.h +++ b/CPP/7zip/Archive/Udf/UdfHandler.h @@ -1,32 +1,32 @@ -// UdfHandler.h - -#ifndef ZIP7_INC_UDF_HANDLER_H -#define ZIP7_INC_UDF_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../IArchive.h" - -#include "UdfIn.h" - -namespace NArchive { -namespace NUdf { - -struct CRef2 -{ - unsigned Vol; - unsigned Fs; - unsigned Ref; -}; - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CRecordVector _refs2; - CMyComPtr _inStream; - CInArchive _archive; -}; - -}} - -#endif +// UdfHandler.h + +#ifndef ZIP7_INC_UDF_HANDLER_H +#define ZIP7_INC_UDF_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../IArchive.h" + +#include "UdfIn.h" + +namespace NArchive { +namespace NUdf { + +struct CRef2 +{ + unsigned Vol; + unsigned Fs; + unsigned Ref; +}; + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CRecordVector _refs2; + CMyComPtr _inStream; + CInArchive _archive; +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index 382dce768..ce87c5408 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -1,1741 +1,1741 @@ -// Archive/UdfIn.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "../../../../C/CpuArch.h" - -#include "../../../Windows/PropVariantUtils.h" - -#include "../../Common/RegisterArc.h" -#include "../../Common/StreamUtils.h" - -#include "UdfIn.h" - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(_offs_, dest) dest = Get16(p + (_offs_)) -#define G32(_offs_, dest) dest = Get32(p + (_offs_)) -#define G64(_offs_, dest) dest = Get64(p + (_offs_)) - -namespace NArchive { -namespace NUdf { - -static const unsigned kNumPartitionsMax = 64; -static const unsigned kNumLogVolumesMax = 64; -static const unsigned kNumRecursionLevelsMax = 1 << 10; -static const unsigned kNumItemsMax = 1 << 27; -static const unsigned kNumFilesMax = 1 << 28; -static const unsigned kNumRefsMax = 1 << 28; -static const UInt32 kNumExtentsMax = (UInt32)1 << 30; -static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33; -static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; - -#define CRC16_INIT_VAL 0 -#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) - -#define kCrc16Poly 0x1021 -static UInt16 g_Crc16Table[256]; - -static void Z7_FASTCALL Crc16GenerateTable(void) -{ - UInt32 i; - for (i = 0; i < 256; i++) - { - UInt32 r = (i << 8); - for (unsigned j = 0; j < 8; j++) - r = ((r << 1) ^ (kCrc16Poly & ((UInt32)0 - (r >> 15)))) & 0xFFFF; - g_Crc16Table[i] = (UInt16)r; - } -} - -static UInt32 Z7_FASTCALL Crc16Calc(const void *data, size_t size) -{ - UInt32 v = CRC16_INIT_VAL; - const Byte *p = (const Byte *)data; - const Byte *pEnd = p + size; - for (; p != pEnd; p++) - v = CRC16_UPDATE_BYTE(v, *p); - return v; -} - -static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; - - -// ---------- ECMA Part 1 ---------- - -void CDString::Parse(const Byte *p, unsigned size) -{ - Data.CopyFrom(p, size); -} - -static UString ParseDString(const Byte *data, unsigned size) -{ - UString res; - if (size != 0) - { - wchar_t *p; - const Byte type = *data++; - size--; - if (type == 8) - { - p = res.GetBuf(size); - for (unsigned i = 0; i < size; i++) - { - const wchar_t c = data[i]; - if (c == 0) - break; - *p++ = c; - } - } - else if (type == 16) - { - size &= ~(unsigned)1; - p = res.GetBuf(size / 2); - for (unsigned i = 0; i < size; i += 2) - { - const wchar_t c = GetBe16(data + i); - if (c == 0) - break; - *p++ = c; - } - } - else - return UString("[unknown]"); - *p = 0; - res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); - } - return res; -} - -UString CDString32::GetString() const -{ - const unsigned size = Data[sizeof(Data) - 1]; - return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); -} - -UString CDString128::GetString() const -{ - const unsigned size = Data[sizeof(Data) - 1]; - return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); -} - -UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); } - -void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); } - - -static void AddCommentChars(UString &dest, const char *s, size_t size) -{ - for (size_t i = 0; i < size; i++) - { - char c = s[i]; - if (c == 0) - break; - if (c < 0x20) - c = '_'; - dest += (wchar_t)c; - } -} - - -void CRegId::Parse(const Byte *p) -{ - Flags = p[0]; - memcpy(Id, p + 1, sizeof(Id)); - memcpy(Suffix, p + 24, sizeof(Suffix)); -} - -void CRegId::AddCommentTo(UString &s) const -{ - AddCommentChars(s, Id, sizeof(Id)); -} - -void CRegId::AddUdfVersionTo(UString &s) const -{ - // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix" - // UDF 2.1.5.3 - // Revision in hex (3 digits) - const Byte minor = Suffix[0]; - const Byte major = Suffix[1]; - if (major != 0 || minor != 0) - { - char temp[16]; - ConvertUInt32ToHex(major, temp); - s += temp; - s.Add_Dot(); - ConvertUInt32ToHex8Digits(minor, temp); - s += &temp[8 - 2]; - } -} - - -// ---------- ECMA Part 3: Volume Structure ---------- - -void CExtent::Parse(const Byte *p) -{ - /* Len shall be less than < 2^30. - Unless otherwise specified, the length shall be an integral multiple of the logical sector size. - If (Len == 0), no extent is specified and (Pos) shall contain 0 */ - G32 (0, Len); - G32 (4, Pos); -} - - -// ECMA 3/7.2 - -struct CTag -{ - UInt16 Id; - // UInt16 Version; - // Byte Checksum; - // UInt16 SerialNumber; - // UInt16 Crc; - UInt16 CrcLen; - // UInt32 TagLocation; // the number of the logical sector - - HRESULT Parse(const Byte *p, size_t size); -}; - -HRESULT CTag::Parse(const Byte *p, size_t size) -{ - if (size < 16) - return S_FALSE; - { - unsigned sum = 0; - for (unsigned i = 0; i < 16; i++) - sum = sum + p[i]; - if ((Byte)(sum - p[4]) != p[4] || p[5] != 0) - return S_FALSE; - } - Id = Get16(p); - const UInt16 Version = Get16(p + 2); - if (Version != 2 && Version != 3) - return S_FALSE; - // SerialNumber = Get16(p + 6); - const UInt32 crc = Get16(p + 8); - CrcLen = Get16(p + 10); - // TagLocation = Get32(p + 12); - - if (size >= 16 + (size_t)CrcLen) - if (crc == Crc16Calc(p + 16, (size_t)CrcLen)) - return S_OK; - return S_FALSE; -} - -// ECMA 3/7.2.1 - -enum EDescriptorType -{ - DESC_TYPE_SpoaringTable = 0, // UDF - DESC_TYPE_PrimVol = 1, - DESC_TYPE_AnchorVolPtr = 2, - DESC_TYPE_VolPtr = 3, - DESC_TYPE_ImplUseVol = 4, - DESC_TYPE_Partition = 5, - DESC_TYPE_LogicalVol = 6, - DESC_TYPE_UnallocSpace = 7, - DESC_TYPE_Terminating = 8, - DESC_TYPE_LogicalVolIntegrity = 9, - DESC_TYPE_FileSet = 256, - DESC_TYPE_FileId = 257, - DESC_TYPE_AllocationExtent = 258, - DESC_TYPE_Indirect = 259, - DESC_TYPE_Terminal = 260, - DESC_TYPE_File = 261, - DESC_TYPE_ExtendedAttrHeader = 262, - DESC_TYPE_UnallocatedSpaceEntry = 263, - DESC_TYPE_SpaceBitmap = 264, - DESC_TYPE_PartitionIntegrity = 265, - DESC_TYPE_ExtendedFile = 266 -}; - - -void CLogBlockAddr::Parse(const Byte *p) -{ - G32 (0, Pos); - G16 (4, PartitionRef); -} - -void CShortAllocDesc::Parse(const Byte *p) -{ - G32 (0, Len); - G32 (4, Pos); -} - -/* -void CADImpUse::Parse(const Byte *p) -{ - G16 (0, Flags); - G32 (2, UdfUniqueId); -} -*/ - -void CLongAllocDesc::Parse(const Byte *p) -{ - G32 (0, Len); - Location.Parse(p + 4); - // memcpy(ImplUse, p + 10, sizeof(ImplUse)); - // adImpUse.Parse(ImplUse); -} - - -void CPrimeVol::Parse(const Byte *p) -{ - // G32 (16, VolumeDescriptorSequenceNumber); - G32 (20, PrimaryVolumeDescriptorNumber); - VolumeId.Parse(p + 24); - G16 (56, VolumeSequenceNumber); - G16 (58, MaximumVolumeSequenceNumber); - // G16 (60, InterchangeLevel); - // G16 (62, MaximumInterchangeLevel); - // G32 (64, CharacterSetList) - // G32 (68, MaximumCharacterSetList) - VolumeSetId.Parse(p + 72); - // 200 64 Descriptor Character Set charspec (1/7.2.1) - // 264 64 Explanatory Character Set charspec (1/7.2.1) - // VolumeAbstract.Parse(p + 328); - // VolumeCopyrightNotice.Parse(p + 336); - ApplicationId.Parse(p + 344); - RecordingTime.Parse(p + 376); - ImplId.Parse(p + 388); - // 420 64 Implementation Use bytes - // G32 (484, PredecessorVolumeDescriptorSequenceLocation); - // G16 (488, Flags); -} - - - -bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const -{ - const CLogVol &vol = LogVols[volIndex]; - if (partitionRef >= vol.PartitionMaps.Size()) - return false; - const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize); -} - -bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const -{ - FOR_VECTOR (i, item.Extents) - { - const CMyExtent &e = item.Extents[i]; - if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen())) - return false; - } - return true; -} - -HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) -{ - if (!CheckExtent(volIndex, partitionRef, blockPos, len)) - return S_FALSE; - const CLogVol &vol = LogVols[volIndex]; - const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; - RINOK(InStream_SeekSet(_stream, offset)) - offset += len; - UpdatePhySize(offset); - const HRESULT res = ReadStream_FALSE(_stream, buf, len); - if (res == S_FALSE && offset > FileSize) - UnexpectedEnd = true; - return res; -} - -HRESULT CInArchive::ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf) -{ - return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); -} - -HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf) -{ - if (item.Size >= (UInt32)1 << 30) - return S_FALSE; - if (item.IsInline) - { - buf = item.InlineData; - return S_OK; - } - buf.Alloc((size_t)item.Size); - size_t pos = 0; - FOR_VECTOR (i, item.Extents) - { - const CMyExtent &e = item.Extents[i]; - const UInt32 len = e.GetLen(); - RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)) - pos += len; - } - return S_OK; -} - - -void CIcbTag::Parse(const Byte *p) -{ - // G32 (0, PriorDirectNum); - // G16 (4, StrategyType); - // G16 (6, StrategyParam); - // G16 (8, MaxNumOfEntries); - FileType = p[11]; - // ParentIcb.Parse(p + 12); - G16 (18, Flags); -} - - -// ECMA 4/14.9 File Entry -// UDF FileEntry 2.3.6 - -// ECMA 4/14.17 Extended File Entry - -void CItem::Parse(const Byte *p) -{ - // (-1) can be stored in Uid/Gid. - // G32 (36, Uid); - // G32 (40, Gid); - // G32 (44, Permissions); - G16 (48, FileLinkCount); - // RecordFormat = p[50]; - // RecordDisplayAttr = p[51]; - // G32 (52, RecordLen); - G64 (56, Size); - if (IsExtended) - { - // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no - // streams, the Object Size shall be equal to the Information Length. - // G64 (64, ObjectSize); - p += 8; - } - G64 (64, NumLogBlockRecorded); - ATime.Parse(p + 72); - MTime.Parse(p + 84); - if (IsExtended) - { - CreateTime.Parse(p + 96); - p += 12; - } - AttribTime.Parse(p + 96); - // G32 (108, CheckPoint); - /* - if (IsExtended) - { - // Get32(p + 112); // reserved - p += 4; - } - // ExtendedAttrIcb.Parse(p + 112); - if (IsExtended) - { - StreamDirectoryIcb.Parse(p + 128); - p += 16; - } - */ - - // ImplId.Parse(p + 128); - // G64 (160, UniqueId); -} - - -// ECMA 4/14.4 -// UDF 2.3.4 - -/* -File Characteristics: -Deleted bit: - ECMA: If set to ONE, shall mean this File Identifier Descriptor - identifies a file that has been deleted; - UDF: If the space for the file or directory is deallocated, - the implementation shall set the ICB field to zero. - ECMA 167 4/8.6 requires that the File Identifiers of all FIDs in a directory shall be unique. - The implementations shall follow these rules when a Deleted bit is set: - rewrire the compression ID of the File Identifier: 8 -> 254, 16 -> 255. -*/ - -struct CFileId -{ - // UInt16 FileVersion; - Byte FileCharacteristics; - // CByteBuffer ImplUse; - CDString Id; - CLongAllocDesc Icb; - - bool IsItLink_Dir () const { return (FileCharacteristics & FILEID_CHARACS_Dir) != 0; } - bool IsItLink_Deleted() const { return (FileCharacteristics & FILEID_CHARACS_Deleted) != 0; } - bool IsItLink_Parent () const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } - - size_t Parse(const Byte *p, size_t size); -}; - -size_t CFileId::Parse(const Byte *p, size_t size) -{ - size_t processed = 0; - if (size < 38) - return 0; - CTag tag; - if (tag.Parse(p, size) != S_OK) - return 0; - if (tag.Id != DESC_TYPE_FileId) - return 0; - // FileVersion = Get16(p + 16); - // UDF: There shall be only one version of a file as specified below with the value being set to 1. - - FileCharacteristics = p[18]; - const unsigned idLen = p[19]; - Icb.Parse(p + 20); - const unsigned impLen = Get16(p + 36); - if (size < 38 + idLen + impLen) - return 0; - processed = 38; - // ImplUse.CopyFrom(p + processed, impLen); - processed += impLen; - Id.Parse(p + processed, idLen); - processed += idLen; - for (;(processed & 3) != 0; processed++) - if (p[processed] != 0) - return 0; - if ((size_t)tag.CrcLen + 16 != processed) return 0; - return (processed <= size) ? processed : 0; -} - - - -HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed) -{ - if (Files.Size() % 100 == 0) - RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)) - if (numRecurseAllowed-- == 0) - return S_FALSE; - CFile &file = Files.Back(); - const CLogVol &vol = LogVols[volIndex]; - const unsigned partitionRef = lad.Location.PartitionRef; - if (partitionRef >= vol.PartitionMaps.Size()) - return S_FALSE; - CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - - const UInt32 key = lad.Location.Pos; - UInt32 value; - const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; - if (partition.Map.Find(key, value)) - { - if (value == kRecursedErrorValue) - return S_FALSE; - file.ItemIndex = (int)(Int32)value; - } - else - { - value = Items.Size(); - file.ItemIndex = (int)(Int32)value; - if (partition.Map.Set(key, kRecursedErrorValue)) - return S_FALSE; - RINOK(ReadItem(volIndex, (int)fsIndex, lad, isDir, numRecurseAllowed)) - if (!partition.Map.Set(key, value)) - return S_FALSE; - } - return S_OK; -} - - -// (fsIndex = -1) means that it's metadata file - -HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed) -{ - if (Items.Size() >= kNumItemsMax) - return S_FALSE; - CItem &item = Items.AddNew(); - - const CLogVol &vol = LogVols[volIndex]; - - const size_t size = lad.GetLen(); - if (size != vol.BlockSize) - return S_FALSE; - - CByteBuffer buf(size); - RINOK(ReadLad(volIndex, lad, buf)) - - CTag tag; - const Byte *p = buf; - RINOK(tag.Parse(p, size)) - - item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile); - const size_t kExtendOffset = item.IsExtended ? 40 : 0; - - if (size < kExtendOffset + 176) - return S_FALSE; - if (tag.Id != DESC_TYPE_File && - tag.Id != DESC_TYPE_ExtendedFile) - return S_FALSE; - - item.IcbTag.Parse(p + 16); - - if (fsIndex < 0) - { - if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA && - item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR) - return S_FALSE; - } - else if ( - item.IcbTag.FileType != ICB_FILE_TYPE_DIR && - item.IcbTag.FileType != ICB_FILE_TYPE_FILE) - return S_FALSE; - - item.Parse(p); - - _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; - - const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset); - const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset); - - if ((extendedAttrLen & 3) != 0) - return S_FALSE; - size_t pos = 176 + kExtendOffset; - if (extendedAttrLen > size - pos) - return S_FALSE; - /* - if (extendedAttrLen != 16) - { - if (extendedAttrLen < 24) - return S_FALSE; - CTag attrTag; - RINOK(attrTag.Parse(p + pos, size)); - if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader) - return S_FALSE; - // UInt32 implAttrLocation = Get32(p + pos + 16); - // UInt32 applicationlAttrLocation = Get32(p + pos + 20); - } - */ - pos += extendedAttrLen; - - const int descType = item.IcbTag.GetDescriptorType(); - if (allocDescriptorsLen > size - pos) - return S_FALSE; - if (descType == ICB_DESC_TYPE_INLINE) - { - item.IsInline = true; - item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); - } - else - { - item.IsInline = false; - if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG) - return S_FALSE; - for (UInt32 i = 0; i < allocDescriptorsLen;) - { - CMyExtent e; - if (descType == ICB_DESC_TYPE_SHORT) - { - if (i + 8 > allocDescriptorsLen) - return S_FALSE; - CShortAllocDesc sad; - sad.Parse(p + pos + i); - e.Pos = sad.Pos; - e.Len = sad.Len; - e.PartitionRef = lad.Location.PartitionRef; - i += 8; - } - else - { - if (i + 16 > allocDescriptorsLen) - return S_FALSE; - CLongAllocDesc ladNew; - ladNew.Parse(p + pos + i); - e.Pos = ladNew.Location.Pos; - e.PartitionRef = ladNew.Location.PartitionRef; - e.Len = ladNew.Len; - i += 16; - } - item.Extents.Add(e); - } - } - - if (isDir != item.IcbTag.IsDir()) - return S_FALSE; - - if (item.IcbTag.IsDir()) - { - if (fsIndex < 0) - return S_FALSE; - - if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) - return S_FALSE; - CByteBuffer buf2; - RINOK(ReadFromFile(volIndex, item, buf2)) - item.Size = 0; - item.Extents.ClearAndFree(); - item.InlineData.Free(); - - const Byte *p2 = buf2; - size_t size2 = buf2.Size(); - while (size2 != 0) - { - CFileId fileId; - { - const size_t cur = fileId.Parse(p2, size2); - if (cur == 0) - return S_FALSE; - p2 += cur; - size2 -= cur; - } - if (fileId.IsItLink_Parent()) - continue; - if (fileId.IsItLink_Deleted()) - continue; - { - CFile file; - // file.FileVersion = fileId.FileVersion; - // file.FileCharacteristics = fileId.FileCharacteristics; - // file.ImplUse = fileId.ImplUse; - file.Id = fileId.Id; - - _fileNameLengthTotal += file.Id.Data.Size(); - if (_fileNameLengthTotal > kFileNameLengthTotalMax) - return S_FALSE; - - item.SubFiles.Add(Files.Size()); - if (Files.Size() >= kNumFilesMax) - return S_FALSE; - Files.Add(file); - RINOK(ReadFileItem(volIndex, (unsigned)fsIndex, fileId.Icb, - fileId.IsItLink_Dir(), numRecurseAllowed)) - } - } - } - else - { - if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents) - return S_FALSE; - _numExtents += item.Extents.Size(); - - if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize) - return S_FALSE; - _inlineExtentsSize += item.InlineData.Size(); - } - - return S_OK; -} - - -HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed) -{ - if ((_numRefs & 0xFFF) == 0) - { - RINOK(_progress->SetCompleted()) - } - if (numRecurseAllowed-- == 0) - return S_FALSE; - if (_numRefs >= kNumRefsMax) - return S_FALSE; - _numRefs++; - CRef ref; - ref.FileIndex = fileIndex; - ref.Parent = parent; - parent = (int)fs.Refs.Size(); - fs.Refs.Add(ref); - const CItem &item = Items[Files[fileIndex].ItemIndex]; - FOR_VECTOR (i, item.SubFiles) - { - RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed)) - } - return S_OK; -} - - -API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) -{ - UInt32 res = k_IsArc_Res_NO; - unsigned SecLogSize; - for (SecLogSize = 11;; SecLogSize -= 2) - { - if (SecLogSize < 9) - return res; - const UInt32 offset = (UInt32)256 << SecLogSize; - const UInt32 bufSize = (UInt32)1 << SecLogSize; - if (offset + bufSize > size) - res = k_IsArc_Res_NEED_MORE; - else - { - CTag tag; - if (tag.Parse(p + offset, bufSize) == S_OK) - if (tag.Id == DESC_TYPE_AnchorVolPtr) - { - if (Get32(p + offset + 12) == 256 && // TagLocation - tag.CrcLen >= 16) - return k_IsArc_Res_YES; - } - } - } -} - - -HRESULT CInArchive::Open2() -{ - Clear(); - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize)) - FileSize = fileSize; - - // Some UDFs contain additional pad zeros (2 KB). - // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB. - // And when we read last block, result read size can be smaller than required size. - - /* - const size_t kBufSize = 1 << 14; - Byte buf[kBufSize]; - size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize; - RINOK(InStream_SeekSet(_stream, fileSize - readSize)) - RINOK(ReadStream(_stream, buf, &readSize)); - size_t i = readSize; - for (;;) - { - const size_t kSecSizeMin = 1 << 8; - if (i < kSecSizeMin) - return S_FALSE; - i -= kSecSizeMin; - SecLogSize = (readSize - i < ((size_t)1 << 11)) ? 8 : 11; - CTag tag; - if (tag.Parse(buf + i, (1 << SecLogSize)) == S_OK) - if (tag.Id == DESC_TYPE_AnchorVolPtr) - break; - } - PhySize = fileSize; - CExtent extentVDS; - extentVDS.Parse(buf + i + 16); - */ - - /* - An Anchor Volume Descriptor Pointer structure shall be recorded in at - least 2 of the following 3 locations on the media: - Logical Sector 256. - Logical Sector (N - 256). - N - */ - - const size_t kBufSize = 1 << 11; - Byte buf[kBufSize]; - - for (SecLogSize = 11;; SecLogSize -= 2) - { - // Windows 10 uses unusual (SecLogSize = 9) - if (SecLogSize < 9) - return S_FALSE; - const UInt32 offset = (UInt32)256 << SecLogSize; - if (offset >= fileSize) - continue; - RINOK(InStream_SeekSet(_stream, offset)) - const size_t bufSize = (size_t)1 << SecLogSize; - size_t readSize = bufSize; - RINOK(ReadStream(_stream, buf, &readSize)) - if (readSize == bufSize) - { - CTag tag; - if (tag.Parse(buf, readSize) == S_OK) - if (tag.Id == DESC_TYPE_AnchorVolPtr) - { - if (Get32(buf + 12) == 256 && - tag.CrcLen >= 16) // TagLocation - break; - } - } - } - - PhySize = (UInt32)(256 + 1) << SecLogSize; - IsArc = true; - - // UDF 2.2.3 AnchorVolumeDescriptorPointer - - CExtent extentVDS; - extentVDS.Parse(buf + 16); - { - CExtent extentVDS2; - extentVDS2.Parse(buf + 24); - UpdatePhySize(extentVDS); - UpdatePhySize(extentVDS2); - } - - for (UInt32 location = 0; ; location++) - { - if (location >= (extentVDS.Len >> SecLogSize)) - return S_FALSE; - - const size_t bufSize = (size_t)1 << SecLogSize; - { - const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize; - RINOK(InStream_SeekSet(_stream, offs)) - const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); - if (res == S_FALSE && offs + bufSize > FileSize) - UnexpectedEnd = true; - RINOK(res) - } - - CTag tag; - RINOK(tag.Parse(buf, bufSize)) - - if (tag.Id == DESC_TYPE_Terminating) - break; - - if (tag.Id == DESC_TYPE_PrimVol) - { - CPrimeVol &pm = PrimeVols.AddNew(); - pm.Parse(buf); - continue; - } - - if (tag.Id == DESC_TYPE_Partition) - { - // Partition Descriptor - // ECMA 3/10.5 - // UDF 2.2.14 - if (Partitions.Size() >= kNumPartitionsMax) - return S_FALSE; - CPartition partition; - // const UInt32 volDescSeqNumer = Get32(buf + 16); - partition.Flags = Get16(buf + 20); - partition.Number = Get16(buf + 22); - partition.ContentsId.Parse(buf + 24); - - // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); - // ContentsUse contains Partition Header Description. - // ECMA 4/14.3 - // UDF PartitionHeaderDescriptor 2.3.3 - - partition.AccessType = Get32(buf + 184); - partition.Pos = Get32(buf + 188); - partition.Len = Get32(buf + 192); - partition.ImplId.Parse(buf + 196); - // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); - - PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); - Partitions.Add(partition); - continue; - } - - if (tag.Id == DESC_TYPE_LogicalVol) - { - /* Logical Volume Descriptor - ECMA 3/10.6 - UDF 2.60 2.2.4 */ - - if (LogVols.Size() >= kNumLogVolumesMax) - return S_FALSE; - CLogVol &vol = LogVols.AddNew(); - - vol.Id.Parse(buf + 84); - vol.BlockSize = Get32(buf + 212); - if (vol.BlockSize != ((UInt32)1 << SecLogSize)) - { - // UDF 2.2.4.2 LogicalBlockSize - // UDF probably doesn't allow different sizes - return S_FALSE; - } - /* - if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) - return S_FALSE; - */ - - vol.DomainId.Parse(buf + 216); - - // ECMA 4/3.1 - // UDF 2.2.4.4 LogicalVolumeContentsUse - /* the extent in which the first File Set Descriptor Sequence - of the logical volume is recorded */ - vol.FileSetLocation.Parse(buf + 248); - // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); - - vol.ImplId.Parse(buf + 272); - // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse)); - // vol.IntegritySequenceExtent.Parse(buf + 432); - - const UInt32 mapTableLen = Get32(buf + 264); - const UInt32 numPartitionMaps = Get32(buf + 268); - if (numPartitionMaps > kNumPartitionsMax) - return S_FALSE; - - PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); - - size_t pos = 440; - if (mapTableLen > bufSize - pos) - return S_FALSE; - const size_t posLimit = pos + mapTableLen; - - for (UInt32 i = 0; i < numPartitionMaps; i++) - { - // ECMA 3/10.7 Partition maps - if (pos + 2 > posLimit) - return S_FALSE; - CPartitionMap pm; - pm.Type = buf[pos + 0]; - // pm.Length = buf[pos + 1]; - const Byte len = buf[pos + 1]; - if (pos + len > posLimit) - return S_FALSE; - - // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); - if (pm.Type == 1) - { - // ECMA 3/10.7.2 - if (len != 6) - return S_FALSE; - pm.VolumeSequenceNumber = Get16(buf + pos + 2); - pm.PartitionNumber = Get16(buf + pos + 4); - PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber)); - } - else if (pm.Type == 2) - { - if (len != 64) - return S_FALSE; - /* ECMA 10.7.3 / Type 2 Partition Map - 62 bytes: Partition Identifier. */ - - /* UDF - 2.2.8 "*UDF Virtual Partition" - 2.2.9 "*UDF Sparable Partition" - 2.2.10 "*UDF Metadata Partition" - */ - - if (Get16(buf + pos + 2) != 0) // reserved - return S_FALSE; - - pm.PartitionTypeId.Parse(buf + pos + 4); - pm.VolumeSequenceNumber = Get16(buf + pos + 36); - pm.PartitionNumber = Get16(buf + pos + 38); - - if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0) - return S_FALSE; - - // UDF 2.2.10 Metadata Partition Map - pm.MetadataFileLocation = Get32(buf + pos + 40); - // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44); - // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48); - // pm.AllocationUnitSize = Get32(buf + pos + 52); - // pm.AlignmentUnitSize = Get16(buf + pos + 56); - // pm.Flags = buf[pos + 58]; - - PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); - // Unsupported = true; - // return S_FALSE; - } - else - return S_FALSE; - pos += len; - vol.PartitionMaps.Add(pm); - } - continue; - } - - /* - if (tag.Id == DESC_TYPE_UnallocSpace) - { - // UInt32 volDescSeqNumer = Get32(buf + 16); - const UInt32 numAlocDescs = Get32(buf + 20); - // we need examples for (numAlocDescs != 0) case - if (numAlocDescs > (bufSize - 24) / 8) - return S_FALSE; - for (UInt32 i = 0; i < numAlocDescs; i++) - { - CExtent e; - e.Parse(buf + 24 + i * 8); - } - continue; - } - else - continue; - */ - } - - UInt64 totalSize = 0; - - unsigned volIndex; - for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) - { - CLogVol &vol = LogVols[volIndex]; - FOR_VECTOR (pmIndex, vol.PartitionMaps) - { - CPartitionMap &pm = vol.PartitionMaps[pmIndex]; - for (unsigned i = 0;; i++) - { - if (i == Partitions.Size()) - return S_FALSE; - CPartition &part = Partitions[i]; - if (part.Number == pm.PartitionNumber) - { - pm.PartitionIndex = i; - if (pm.Type == 2) - break; - - /* - if (part.VolIndex >= 0) - { - // it's for 2.60. Fix it - if (part.VolIndex != (int)volIndex) - return S_FALSE; - // return S_FALSE; - } - part.VolIndex = volIndex; - */ - - totalSize += (UInt64)part.Len << SecLogSize; - break; - } - } - } - } - - for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) - { - CLogVol &vol = LogVols[volIndex]; - FOR_VECTOR (pmIndex, vol.PartitionMaps) - { - CPartitionMap &pm = vol.PartitionMaps[pmIndex]; - if (pm.Type != 2) - continue; - - { - CLongAllocDesc lad; - lad.Len = vol.BlockSize; - lad.Location.Pos = pm.MetadataFileLocation; - // lad.Location.Pos = pm.MetadataMirrorFileLocation; - - lad.Location.PartitionRef = (UInt16)pmIndex; - - /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex. - so we can use pmIndex or find (Type==1) PartitionMap */ - FOR_VECTOR (pmIndex2, vol.PartitionMaps) - { - const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2]; - if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1) - { - lad.Location.PartitionRef = (UInt16)pmIndex2; - break; - } - } - - RINOK(ReadItem(volIndex, - -1, // (fsIndex = -1) means that it's metadata - lad, - false, // isDir - 1)) // numRecurseAllowed - } - { - const CItem &item = Items.Back(); - if (!CheckItemExtents(volIndex, item)) - return S_FALSE; - if (item.Extents.Size() != 1) - { - if (item.Extents.Size() < 1) - return S_FALSE; - /* Windows 10 writes empty record item.Extents[1]. - we ignore such extent here */ - for (unsigned k = 1; k < item.Extents.Size(); k++) - { - const CMyExtent &e = item.Extents[k]; - if (e.GetLen() != 0) - return S_FALSE; - } - } - - const CMyExtent &e = item.Extents[0]; - const CPartition &part = Partitions[pm.PartitionIndex]; - CPartition mp = part; - mp.IsMetadata = true; - // mp.Number = part.Number; - mp.Pos = part.Pos + e.Pos; - mp.Len = e.Len >> SecLogSize; - pm.PartitionIndex = Partitions.Add(mp); - } - // Items.DeleteBack(); // we can delete that metadata item - - /* - // short version of code to read metadata file. - RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf)); - CTag tag; - RINOK(tag.Parse(buf, 224)); - if (tag.Id != DESC_TYPE_ExtendedFile) - return S_FALSE; - CShortAllocDesc sad; - sad.Parse(buf + 216); - const CPartition &part = Partitions[pm.PartitionIndex]; - CPartition mp = part; - mp.IsMetadata = true; - // mp.Number = part.Number; - mp.Pos = part.Pos + sad.Pos; - mp.Len = sad.Len >> SecLogSize; - pm.PartitionIndex = Partitions.Add(mp); - */ - } - } - - RINOK(_progress->SetTotal(totalSize)) - - PRF(printf("\n Read files")); - - for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) - { - CLogVol &vol = LogVols[volIndex]; - - PRF(printf("\nLogVol %2d", volIndex)); - - CLongAllocDesc nextExtent = vol.FileSetLocation; - // while (nextExtent.ExtentLen != 0) - // for (int i = 0; i < 1; i++) - { - if (nextExtent.GetLen() < 512) - return S_FALSE; - CByteBuffer buf2(nextExtent.GetLen()); - RINOK(ReadLad(volIndex, nextExtent, buf2)) - const Byte *p = buf2; - const size_t size = nextExtent.GetLen(); - - CTag tag; - RINOK(tag.Parse(p, size)) - - /* - // commented in 22.01 - if (tag.Id == DESC_TYPE_ExtendedFile) - { - // ECMA 4 / 14.17 - // 2.60 ?? - return S_FALSE; - } - */ - - if (tag.Id != DESC_TYPE_FileSet) - return S_FALSE; - - PRF(printf("\n FileSet", volIndex)); - CFileSet fs; - fs.RecordingTime.Parse(p + 16); - // fs.InterchangeLevel = Get16(p + 18); - // fs.MaxInterchangeLevel = Get16(p + 20); - fs.FileSetNumber = Get32(p + 40); - fs.FileSetDescNumber = Get32(p + 44); - - fs.LogicalVolumeId.Parse(p + 112); - fs.Id.Parse(p + 304); - fs.CopyrightId.Parse(p + 336); - fs.AbstractId.Parse(p + 368); - - fs.RootDirICB.Parse(p + 400); - fs.DomainId.Parse(p + 416); - - // fs.SystemStreamDirICB.Parse(p + 464); - - vol.FileSets.Add(fs); - - // nextExtent.Parse(p + 448); - } - - FOR_VECTOR (fsIndex, vol.FileSets) - { - CFileSet &fs = vol.FileSets[fsIndex]; - const unsigned fileIndex = Files.Size(); - Files.AddNew(); - RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, - true, // isDir - kNumRecursionLevelsMax)) - RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax)) - } - } - - - for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) - { - const CLogVol &vol = LogVols[volIndex]; - // bool showFileSetName = (vol.FileSets.Size() > 1); - FOR_VECTOR (fsIndex, vol.FileSets) - { - const CFileSet &fs = vol.FileSets[fsIndex]; - for (unsigned i = - // ((showVolName || showFileSetName) ? 0 : 1) - 0; i < fs.Refs.Size(); i++) - { - const CRef &ref = vol.FileSets[fsIndex].Refs[i]; - const CFile &file = Files[ref.FileIndex]; - const CItem &item = Items[file.ItemIndex]; - UInt64 size = item.Size; - - if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) - continue; - - FOR_VECTOR (extentIndex, item.Extents) - { - const CMyExtent &extent = item.Extents[extentIndex]; - const UInt32 len = extent.GetLen(); - if (len == 0) - continue; - if (size < len) - break; - - const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - const UInt32 logBlockNumber = extent.Pos; - const CPartition &partition = Partitions[partitionIndex]; - const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + - (UInt64)logBlockNumber * vol.BlockSize; - UpdatePhySize(offset + len); - } - } - } - } - - { - const UInt32 secMask = ((UInt32)1 << SecLogSize) - 1; - PhySize = (PhySize + secMask) & ~(UInt64)secMask; - } - - NoEndAnchor = true; - - if (PhySize < fileSize) - { - UInt64 rem = fileSize - PhySize; - const size_t secSize = (size_t)1 << SecLogSize; - - RINOK(InStream_SeekSet(_stream, PhySize)) - - // some UDF images contain ZEROs before "Anchor Volume Descriptor Pointer" at the end - - for (unsigned sec = 0; sec < 1024; sec++) - { - if (rem == 0) - break; - - size_t readSize = secSize; - if (readSize > rem) - readSize = (size_t)rem; - - RINOK(ReadStream(_stream, buf, &readSize)) - - if (readSize == 0) - break; - - // some udf contain many EndAnchors - if (readSize == secSize /* && NoEndAnchor */) - { - CTag tag; - if (tag.Parse(buf, readSize) == S_OK - && tag.Id == DESC_TYPE_AnchorVolPtr - && Get32(buf + 12) == (UInt32)((fileSize - rem) >> SecLogSize)) - { - NoEndAnchor = false; - rem -= readSize; - PhySize = fileSize - rem; - continue; - } - } - - size_t i; - for (i = 0; i < readSize && buf[i] == 0; i++); - if (i != readSize) - break; - rem -= readSize; - } - - if (rem == 0) - PhySize = fileSize; - } - - return S_OK; -} - - -HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress) -{ - _progress = progress; - _stream = inStream; - HRESULT res = Open2(); - if (res == S_FALSE && IsArc && !UnexpectedEnd) - Unsupported = true; - return res; - - /* - HRESULT res; - try - { - res = Open2(); - } - catch(...) - { - // Clear(); - // res = S_FALSE; - _stream.Release(); - throw; - } - _stream.Release(); - return res; - */ -} - -void CInArchive::Clear() -{ - IsArc = false; - Unsupported = false; - UnexpectedEnd = false; - NoEndAnchor = false; - - PhySize = 0; - FileSize = 0; - - Partitions.Clear(); - LogVols.Clear(); - PrimeVols.Clear(); - Items.Clear(); - Files.Clear(); - _fileNameLengthTotal = 0; - _numRefs = 0; - _numExtents = 0; - _inlineExtentsSize = 0; - _processedProgressBytes = 0; -} - - -static const char * const g_PartitionTypes[] = -{ - "Pseudo-Overwritable" // UDF - , "Read-Only" - , "Write-Once" - , "Rewritable" - , "Overwritable" -}; - - -static void AddComment_Align(UString &s) -{ - s += " "; -} - -static void AddComment_PropName(UString &s, const char *name) -{ - AddComment_Align(s); - s += name; - s += ": "; -} - -static void AddComment_UInt32(UString &s, const char *name, UInt32 val) -{ - AddComment_PropName(s, name); - s.Add_UInt32(val); - s.Add_LF(); -} - -static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val) -{ - AddComment_Align(s); - AddComment_UInt32(s, name, val); -} - - -static void AddComment_UInt64(UString &s, const char *name, UInt64 val) -{ - AddComment_PropName(s, name); - s.Add_UInt64(val); - s.Add_LF(); -} - -static void AddComment_RegId(UString &s, const char *name, const CRegId &ri) -{ - AddComment_PropName(s, name); - ri.AddCommentTo(s); - s.Add_LF(); -} - -static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri) -{ - AddComment_PropName(s, name); - ri.AddCommentTo(s); - { - UString s2; - ri.AddUdfVersionTo(s2); - if (!s2.IsEmpty()) - { - s += "::"; - s += s2; - } - } - s.Add_LF(); -} - - -// UDF 6.3.1 OS Class - -static const char * const g_OsClasses[] = -{ - NULL - , "DOS" - , "OS/2" - , "Macintosh OS" - , "UNIX" - , "Windows 9x" - , "Windows NT" - , "OS/400" - , "BeOS" - , "Windows CE" -}; - -// UDF 6.3.2 OS Identifier - -static const char * const g_OsIds_Unix[] = -{ - NULL // "Generic" - , "AIX" - , "SUN OS / Solaris" - , "HP/UX" - , "Silicon Graphics Irix" - , "Linux" - , "MKLinux" - , "FreeBSD" - , "NetBSD" -}; - -static void AddOs_Class_Id(UString &s, const Byte *p) -{ - // UDF 2.1.5.3 Implementation Identifier Suffix - // Appendix 6.3 Operating System Identifiers. - const Byte osClass = p[0]; - if (osClass != 0) - { - s += "::"; - s += TypeToString(g_OsClasses, Z7_ARRAY_SIZE(g_OsClasses), osClass); - } - const Byte osId = p[1]; - if (osId != 0) - { - s += "::"; - if (osClass == 4) // unix - { - s += TypeToString(g_OsIds_Unix, Z7_ARRAY_SIZE(g_OsIds_Unix), osId); - } - else - s.Add_UInt32(osId); - } -} - - -static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri) -{ - AddComment_PropName(s, name); - ri.AddCommentTo(s); - { - AddOs_Class_Id(s, ri.Suffix); - } - s.Add_LF(); -} - - -static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri) -{ - AddComment_PropName(s, name); - ri.AddCommentTo(s); - { - // UDF 2.1.5.3 - // UDF Identifier Suffix format - UString s2; - ri.AddUdfVersionTo(s2); - if (!s2.IsEmpty()) - { - s += "::"; - s += s2; - } - AddOs_Class_Id(s, &ri.Suffix[2]); - } - s.Add_LF(); -} - -static void AddComment_DString32(UString &s, const char *name, const CDString32 &d) -{ - AddComment_Align(s); - AddComment_PropName(s, name); - s += d.GetString(); - s.Add_LF(); -} - -UString CInArchive::GetComment() const -{ - UString s; - { - s += "Primary Volumes:"; - s.Add_LF(); - FOR_VECTOR (i, PrimeVols) - { - if (i != 0) - s.Add_LF(); - const CPrimeVol &pv = PrimeVols[i]; - // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber); - // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0) - AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber); - // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1) - AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber); - if (pv.MaximumVolumeSequenceNumber != 1) - AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber); - AddComment_PropName(s, "VolumeId"); - s += pv.VolumeId.GetString(); - s.Add_LF(); - AddComment_PropName(s, "VolumeSetId"); - s += pv.VolumeSetId.GetString(); - s.Add_LF(); - // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel); - // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel); - AddComment_RegId(s, "ApplicationId", pv.ApplicationId); - AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId); - } - } - { - s += "Partitions:"; - s.Add_LF(); - FOR_VECTOR (i, Partitions) - { - if (i != 0) - s.Add_LF(); - const CPartition &part = Partitions[i]; - AddComment_UInt32(s, "PartitionIndex", i); - AddComment_UInt32(s, "PartitionNumber", part.Number); - if (part.IsMetadata) - AddComment_UInt32(s, "IsMetadata", 1); - else - { - AddComment_RegId(s, "ContentsId", part.ContentsId); - AddComment_RegId_Impl(s, "ImplementationId", part.ImplId); - AddComment_PropName(s, "AccessType"); - s += TypeToString(g_PartitionTypes, Z7_ARRAY_SIZE(g_PartitionTypes), part.AccessType); - s.Add_LF(); - } - AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize); - AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize); - } - } - s += "Logical Volumes:"; - s.Add_LF(); - { - FOR_VECTOR (i, LogVols) - { - if (i != 0) - s.Add_LF(); - const CLogVol &vol = LogVols[i]; - if (LogVols.Size() != 1) - AddComment_UInt32(s, "Number", i); - AddComment_PropName(s, "Id"); - s += vol.Id.GetString(); - s.Add_LF(); - AddComment_UInt32(s, "BlockSize", vol.BlockSize); - AddComment_RegId_Domain(s, "DomainId", vol.DomainId); - AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId); - // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len); - // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize); - - s += " Partition Maps:"; - s.Add_LF(); - { - FOR_VECTOR (j, vol.PartitionMaps) - { - if (j != 0) - s.Add_LF(); - const CPartitionMap &pm = vol.PartitionMaps[j]; - AddComment_UInt32_2(s, "PartitionMap", j); - AddComment_UInt32_2(s, "Type", pm.Type); - AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber); - AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber); - if (pm.Type == 2) - { - AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation); - // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation); - // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation); - // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize); - // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize); - // AddComment_UInt32_2(s, "Flags", pm.Flags); - AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId); - } - } - } - s += " File Sets:"; - s.Add_LF(); - { - FOR_VECTOR (j, vol.FileSets) - { - if (j != 0) - s.Add_LF(); - const CFileSet &fs = vol.FileSets[j]; - AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber); - AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber); - - AddComment_Align(s); - AddComment_PropName(s, "LogicalVolumeId"); - s += fs.LogicalVolumeId.GetString(); - s.Add_LF(); - - AddComment_DString32(s, "Id", fs.Id); - AddComment_DString32(s, "CopyrightId", fs.CopyrightId); - AddComment_DString32(s, "AbstractId", fs.AbstractId); - - AddComment_Align(s); - AddComment_RegId_Domain(s, "DomainId", fs.DomainId); - } - } - } - } - return s; -} - -static UString GetSpecName(const UString &name) -{ - UString name2 = name; - name2.Trim(); - if (name2.IsEmpty()) - return UString("[]"); - return name; -} - -static void UpdateWithName(UString &res, const UString &addString) -{ - if (res.IsEmpty()) - res = addString; - else - res.Insert(0, addString + WCHAR_PATH_SEPARATOR); -} - -UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, - bool showVolName, bool showFsName) const -{ - // showVolName = true; - const CLogVol &vol = LogVols[volIndex]; - const CFileSet &fs = vol.FileSets[fsIndex]; - - UString name; - - for (;;) - { - const CRef &ref = fs.Refs[refIndex]; - // we break on root file (that probably has empty name) - if (ref.Parent < 0) - break; - refIndex = (unsigned)ref.Parent; - UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); - } - - if (showFsName) - { - UString newName ("File Set "); - newName.Add_UInt32(fsIndex); - UpdateWithName(name, newName); - } - - if (showVolName) - { - UString newName; - newName.Add_UInt32(volIndex); - UString newName2 = vol.GetName(); - if (newName2.IsEmpty()) - newName2 = "Volume"; - newName.Add_Minus(); - newName += newName2; - UpdateWithName(name, newName); - } - return name; -} - -}} +// Archive/UdfIn.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "../../../../C/CpuArch.h" + +#include "../../../Windows/PropVariantUtils.h" + +#include "../../Common/RegisterArc.h" +#include "../../Common/StreamUtils.h" + +#include "UdfIn.h" + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)) +#define G32(_offs_, dest) dest = Get32(p + (_offs_)) +#define G64(_offs_, dest) dest = Get64(p + (_offs_)) + +namespace NArchive { +namespace NUdf { + +static const unsigned kNumPartitionsMax = 64; +static const unsigned kNumLogVolumesMax = 64; +static const unsigned kNumRecursionLevelsMax = 1 << 10; +static const unsigned kNumItemsMax = 1 << 27; +static const unsigned kNumFilesMax = 1 << 28; +static const unsigned kNumRefsMax = 1 << 28; +static const UInt32 kNumExtentsMax = (UInt32)1 << 30; +static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33; +static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; + +#define CRC16_INIT_VAL 0 +#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) + +#define kCrc16Poly 0x1021 +static UInt16 g_Crc16Table[256]; + +static void Z7_FASTCALL Crc16GenerateTable(void) +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = (i << 8); + for (unsigned j = 0; j < 8; j++) + r = ((r << 1) ^ (kCrc16Poly & ((UInt32)0 - (r >> 15)))) & 0xFFFF; + g_Crc16Table[i] = (UInt16)r; + } +} + +static UInt32 Z7_FASTCALL Crc16Calc(const void *data, size_t size) +{ + UInt32 v = CRC16_INIT_VAL; + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC16_UPDATE_BYTE(v, *p); + return v; +} + +static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; + + +// ---------- ECMA Part 1 ---------- + +void CDString::Parse(const Byte *p, unsigned size) +{ + Data.CopyFrom(p, size); +} + +static UString ParseDString(const Byte *data, unsigned size) +{ + UString res; + if (size != 0) + { + wchar_t *p; + const Byte type = *data++; + size--; + if (type == 8) + { + p = res.GetBuf(size); + for (unsigned i = 0; i < size; i++) + { + const wchar_t c = data[i]; + if (c == 0) + break; + *p++ = c; + } + } + else if (type == 16) + { + size &= ~(unsigned)1; + p = res.GetBuf(size / 2); + for (unsigned i = 0; i < size; i += 2) + { + const wchar_t c = GetBe16(data + i); + if (c == 0) + break; + *p++ = c; + } + } + else + return UString("[unknown]"); + *p = 0; + res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res)); + } + return res; +} + +UString CDString32::GetString() const +{ + const unsigned size = Data[sizeof(Data) - 1]; + return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); +} + +UString CDString128::GetString() const +{ + const unsigned size = Data[sizeof(Data) - 1]; + return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); +} + +UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); } + +void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); } + + +static void AddCommentChars(UString &dest, const char *s, size_t size) +{ + for (size_t i = 0; i < size; i++) + { + char c = s[i]; + if (c == 0) + break; + if (c < 0x20) + c = '_'; + dest += (wchar_t)c; + } +} + + +void CRegId::Parse(const Byte *p) +{ + Flags = p[0]; + memcpy(Id, p + 1, sizeof(Id)); + memcpy(Suffix, p + 24, sizeof(Suffix)); +} + +void CRegId::AddCommentTo(UString &s) const +{ + AddCommentChars(s, Id, sizeof(Id)); +} + +void CRegId::AddUdfVersionTo(UString &s) const +{ + // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix" + // UDF 2.1.5.3 + // Revision in hex (3 digits) + const Byte minor = Suffix[0]; + const Byte major = Suffix[1]; + if (major != 0 || minor != 0) + { + char temp[16]; + ConvertUInt32ToHex(major, temp); + s += temp; + s.Add_Dot(); + ConvertUInt32ToHex8Digits(minor, temp); + s += &temp[8 - 2]; + } +} + + +// ---------- ECMA Part 3: Volume Structure ---------- + +void CExtent::Parse(const Byte *p) +{ + /* Len shall be less than < 2^30. + Unless otherwise specified, the length shall be an integral multiple of the logical sector size. + If (Len == 0), no extent is specified and (Pos) shall contain 0 */ + G32 (0, Len); + G32 (4, Pos); +} + + +// ECMA 3/7.2 + +struct CTag +{ + UInt16 Id; + // UInt16 Version; + // Byte Checksum; + // UInt16 SerialNumber; + // UInt16 Crc; + UInt16 CrcLen; + // UInt32 TagLocation; // the number of the logical sector + + HRESULT Parse(const Byte *p, size_t size); +}; + +HRESULT CTag::Parse(const Byte *p, size_t size) +{ + if (size < 16) + return S_FALSE; + { + unsigned sum = 0; + for (unsigned i = 0; i < 16; i++) + sum = sum + p[i]; + if ((Byte)(sum - p[4]) != p[4] || p[5] != 0) + return S_FALSE; + } + Id = Get16(p); + const UInt16 Version = Get16(p + 2); + if (Version != 2 && Version != 3) + return S_FALSE; + // SerialNumber = Get16(p + 6); + const UInt32 crc = Get16(p + 8); + CrcLen = Get16(p + 10); + // TagLocation = Get32(p + 12); + + if (size >= 16 + (size_t)CrcLen) + if (crc == Crc16Calc(p + 16, (size_t)CrcLen)) + return S_OK; + return S_FALSE; +} + +// ECMA 3/7.2.1 + +enum EDescriptorType +{ + DESC_TYPE_SpoaringTable = 0, // UDF + DESC_TYPE_PrimVol = 1, + DESC_TYPE_AnchorVolPtr = 2, + DESC_TYPE_VolPtr = 3, + DESC_TYPE_ImplUseVol = 4, + DESC_TYPE_Partition = 5, + DESC_TYPE_LogicalVol = 6, + DESC_TYPE_UnallocSpace = 7, + DESC_TYPE_Terminating = 8, + DESC_TYPE_LogicalVolIntegrity = 9, + DESC_TYPE_FileSet = 256, + DESC_TYPE_FileId = 257, + DESC_TYPE_AllocationExtent = 258, + DESC_TYPE_Indirect = 259, + DESC_TYPE_Terminal = 260, + DESC_TYPE_File = 261, + DESC_TYPE_ExtendedAttrHeader = 262, + DESC_TYPE_UnallocatedSpaceEntry = 263, + DESC_TYPE_SpaceBitmap = 264, + DESC_TYPE_PartitionIntegrity = 265, + DESC_TYPE_ExtendedFile = 266 +}; + + +void CLogBlockAddr::Parse(const Byte *p) +{ + G32 (0, Pos); + G16 (4, PartitionRef); +} + +void CShortAllocDesc::Parse(const Byte *p) +{ + G32 (0, Len); + G32 (4, Pos); +} + +/* +void CADImpUse::Parse(const Byte *p) +{ + G16 (0, Flags); + G32 (2, UdfUniqueId); +} +*/ + +void CLongAllocDesc::Parse(const Byte *p) +{ + G32 (0, Len); + Location.Parse(p + 4); + // memcpy(ImplUse, p + 10, sizeof(ImplUse)); + // adImpUse.Parse(ImplUse); +} + + +void CPrimeVol::Parse(const Byte *p) +{ + // G32 (16, VolumeDescriptorSequenceNumber); + G32 (20, PrimaryVolumeDescriptorNumber); + VolumeId.Parse(p + 24); + G16 (56, VolumeSequenceNumber); + G16 (58, MaximumVolumeSequenceNumber); + // G16 (60, InterchangeLevel); + // G16 (62, MaximumInterchangeLevel); + // G32 (64, CharacterSetList) + // G32 (68, MaximumCharacterSetList) + VolumeSetId.Parse(p + 72); + // 200 64 Descriptor Character Set charspec (1/7.2.1) + // 264 64 Explanatory Character Set charspec (1/7.2.1) + // VolumeAbstract.Parse(p + 328); + // VolumeCopyrightNotice.Parse(p + 336); + ApplicationId.Parse(p + 344); + RecordingTime.Parse(p + 376); + ImplId.Parse(p + 388); + // 420 64 Implementation Use bytes + // G32 (484, PredecessorVolumeDescriptorSequenceLocation); + // G16 (488, Flags); +} + + + +bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const +{ + const CLogVol &vol = LogVols[volIndex]; + if (partitionRef >= vol.PartitionMaps.Size()) + return false; + const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize); +} + +bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const +{ + FOR_VECTOR (i, item.Extents) + { + const CMyExtent &e = item.Extents[i]; + if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen())) + return false; + } + return true; +} + +HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) +{ + if (!CheckExtent(volIndex, partitionRef, blockPos, len)) + return S_FALSE; + const CLogVol &vol = LogVols[volIndex]; + const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; + RINOK(InStream_SeekSet(_stream, offset)) + offset += len; + UpdatePhySize(offset); + const HRESULT res = ReadStream_FALSE(_stream, buf, len); + if (res == S_FALSE && offset > FileSize) + UnexpectedEnd = true; + return res; +} + +HRESULT CInArchive::ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf) +{ + return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); +} + +HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf) +{ + if (item.Size >= (UInt32)1 << 30) + return S_FALSE; + if (item.IsInline) + { + buf = item.InlineData; + return S_OK; + } + buf.Alloc((size_t)item.Size); + size_t pos = 0; + FOR_VECTOR (i, item.Extents) + { + const CMyExtent &e = item.Extents[i]; + const UInt32 len = e.GetLen(); + RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)) + pos += len; + } + return S_OK; +} + + +void CIcbTag::Parse(const Byte *p) +{ + // G32 (0, PriorDirectNum); + // G16 (4, StrategyType); + // G16 (6, StrategyParam); + // G16 (8, MaxNumOfEntries); + FileType = p[11]; + // ParentIcb.Parse(p + 12); + G16 (18, Flags); +} + + +// ECMA 4/14.9 File Entry +// UDF FileEntry 2.3.6 + +// ECMA 4/14.17 Extended File Entry + +void CItem::Parse(const Byte *p) +{ + // (-1) can be stored in Uid/Gid. + // G32 (36, Uid); + // G32 (40, Gid); + // G32 (44, Permissions); + G16 (48, FileLinkCount); + // RecordFormat = p[50]; + // RecordDisplayAttr = p[51]; + // G32 (52, RecordLen); + G64 (56, Size); + if (IsExtended) + { + // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no + // streams, the Object Size shall be equal to the Information Length. + // G64 (64, ObjectSize); + p += 8; + } + G64 (64, NumLogBlockRecorded); + ATime.Parse(p + 72); + MTime.Parse(p + 84); + if (IsExtended) + { + CreateTime.Parse(p + 96); + p += 12; + } + AttribTime.Parse(p + 96); + // G32 (108, CheckPoint); + /* + if (IsExtended) + { + // Get32(p + 112); // reserved + p += 4; + } + // ExtendedAttrIcb.Parse(p + 112); + if (IsExtended) + { + StreamDirectoryIcb.Parse(p + 128); + p += 16; + } + */ + + // ImplId.Parse(p + 128); + // G64 (160, UniqueId); +} + + +// ECMA 4/14.4 +// UDF 2.3.4 + +/* +File Characteristics: +Deleted bit: + ECMA: If set to ONE, shall mean this File Identifier Descriptor + identifies a file that has been deleted; + UDF: If the space for the file or directory is deallocated, + the implementation shall set the ICB field to zero. + ECMA 167 4/8.6 requires that the File Identifiers of all FIDs in a directory shall be unique. + The implementations shall follow these rules when a Deleted bit is set: + rewrire the compression ID of the File Identifier: 8 -> 254, 16 -> 255. +*/ + +struct CFileId +{ + // UInt16 FileVersion; + Byte FileCharacteristics; + // CByteBuffer ImplUse; + CDString Id; + CLongAllocDesc Icb; + + bool IsItLink_Dir () const { return (FileCharacteristics & FILEID_CHARACS_Dir) != 0; } + bool IsItLink_Deleted() const { return (FileCharacteristics & FILEID_CHARACS_Deleted) != 0; } + bool IsItLink_Parent () const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } + + size_t Parse(const Byte *p, size_t size); +}; + +size_t CFileId::Parse(const Byte *p, size_t size) +{ + size_t processed = 0; + if (size < 38) + return 0; + CTag tag; + if (tag.Parse(p, size) != S_OK) + return 0; + if (tag.Id != DESC_TYPE_FileId) + return 0; + // FileVersion = Get16(p + 16); + // UDF: There shall be only one version of a file as specified below with the value being set to 1. + + FileCharacteristics = p[18]; + const unsigned idLen = p[19]; + Icb.Parse(p + 20); + const unsigned impLen = Get16(p + 36); + if (size < 38 + idLen + impLen) + return 0; + processed = 38; + // ImplUse.CopyFrom(p + processed, impLen); + processed += impLen; + Id.Parse(p + processed, idLen); + processed += idLen; + for (;(processed & 3) != 0; processed++) + if (p[processed] != 0) + return 0; + if ((size_t)tag.CrcLen + 16 != processed) return 0; + return (processed <= size) ? processed : 0; +} + + + +HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed) +{ + if (Files.Size() % 100 == 0) + RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)) + if (numRecurseAllowed-- == 0) + return S_FALSE; + CFile &file = Files.Back(); + const CLogVol &vol = LogVols[volIndex]; + const unsigned partitionRef = lad.Location.PartitionRef; + if (partitionRef >= vol.PartitionMaps.Size()) + return S_FALSE; + CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; + + const UInt32 key = lad.Location.Pos; + UInt32 value; + const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; + if (partition.Map.Find(key, value)) + { + if (value == kRecursedErrorValue) + return S_FALSE; + file.ItemIndex = (int)(Int32)value; + } + else + { + value = Items.Size(); + file.ItemIndex = (int)(Int32)value; + if (partition.Map.Set(key, kRecursedErrorValue)) + return S_FALSE; + RINOK(ReadItem(volIndex, (int)fsIndex, lad, isDir, numRecurseAllowed)) + if (!partition.Map.Set(key, value)) + return S_FALSE; + } + return S_OK; +} + + +// (fsIndex = -1) means that it's metadata file + +HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed) +{ + if (Items.Size() >= kNumItemsMax) + return S_FALSE; + CItem &item = Items.AddNew(); + + const CLogVol &vol = LogVols[volIndex]; + + const size_t size = lad.GetLen(); + if (size != vol.BlockSize) + return S_FALSE; + + CByteBuffer buf(size); + RINOK(ReadLad(volIndex, lad, buf)) + + CTag tag; + const Byte *p = buf; + RINOK(tag.Parse(p, size)) + + item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile); + const size_t kExtendOffset = item.IsExtended ? 40 : 0; + + if (size < kExtendOffset + 176) + return S_FALSE; + if (tag.Id != DESC_TYPE_File && + tag.Id != DESC_TYPE_ExtendedFile) + return S_FALSE; + + item.IcbTag.Parse(p + 16); + + if (fsIndex < 0) + { + if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA && + item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR) + return S_FALSE; + } + else if ( + item.IcbTag.FileType != ICB_FILE_TYPE_DIR && + item.IcbTag.FileType != ICB_FILE_TYPE_FILE) + return S_FALSE; + + item.Parse(p); + + _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; + + const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset); + const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset); + + if ((extendedAttrLen & 3) != 0) + return S_FALSE; + size_t pos = 176 + kExtendOffset; + if (extendedAttrLen > size - pos) + return S_FALSE; + /* + if (extendedAttrLen != 16) + { + if (extendedAttrLen < 24) + return S_FALSE; + CTag attrTag; + RINOK(attrTag.Parse(p + pos, size)); + if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader) + return S_FALSE; + // UInt32 implAttrLocation = Get32(p + pos + 16); + // UInt32 applicationlAttrLocation = Get32(p + pos + 20); + } + */ + pos += extendedAttrLen; + + const int descType = item.IcbTag.GetDescriptorType(); + if (allocDescriptorsLen > size - pos) + return S_FALSE; + if (descType == ICB_DESC_TYPE_INLINE) + { + item.IsInline = true; + item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); + } + else + { + item.IsInline = false; + if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG) + return S_FALSE; + for (UInt32 i = 0; i < allocDescriptorsLen;) + { + CMyExtent e; + if (descType == ICB_DESC_TYPE_SHORT) + { + if (i + 8 > allocDescriptorsLen) + return S_FALSE; + CShortAllocDesc sad; + sad.Parse(p + pos + i); + e.Pos = sad.Pos; + e.Len = sad.Len; + e.PartitionRef = lad.Location.PartitionRef; + i += 8; + } + else + { + if (i + 16 > allocDescriptorsLen) + return S_FALSE; + CLongAllocDesc ladNew; + ladNew.Parse(p + pos + i); + e.Pos = ladNew.Location.Pos; + e.PartitionRef = ladNew.Location.PartitionRef; + e.Len = ladNew.Len; + i += 16; + } + item.Extents.Add(e); + } + } + + if (isDir != item.IcbTag.IsDir()) + return S_FALSE; + + if (item.IcbTag.IsDir()) + { + if (fsIndex < 0) + return S_FALSE; + + if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) + return S_FALSE; + CByteBuffer buf2; + RINOK(ReadFromFile(volIndex, item, buf2)) + item.Size = 0; + item.Extents.ClearAndFree(); + item.InlineData.Free(); + + const Byte *p2 = buf2; + size_t size2 = buf2.Size(); + while (size2 != 0) + { + CFileId fileId; + { + const size_t cur = fileId.Parse(p2, size2); + if (cur == 0) + return S_FALSE; + p2 += cur; + size2 -= cur; + } + if (fileId.IsItLink_Parent()) + continue; + if (fileId.IsItLink_Deleted()) + continue; + { + CFile file; + // file.FileVersion = fileId.FileVersion; + // file.FileCharacteristics = fileId.FileCharacteristics; + // file.ImplUse = fileId.ImplUse; + file.Id = fileId.Id; + + _fileNameLengthTotal += file.Id.Data.Size(); + if (_fileNameLengthTotal > kFileNameLengthTotalMax) + return S_FALSE; + + item.SubFiles.Add(Files.Size()); + if (Files.Size() >= kNumFilesMax) + return S_FALSE; + Files.Add(file); + RINOK(ReadFileItem(volIndex, (unsigned)fsIndex, fileId.Icb, + fileId.IsItLink_Dir(), numRecurseAllowed)) + } + } + } + else + { + if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents) + return S_FALSE; + _numExtents += item.Extents.Size(); + + if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize) + return S_FALSE; + _inlineExtentsSize += item.InlineData.Size(); + } + + return S_OK; +} + + +HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed) +{ + if ((_numRefs & 0xFFF) == 0) + { + RINOK(_progress->SetCompleted()) + } + if (numRecurseAllowed-- == 0) + return S_FALSE; + if (_numRefs >= kNumRefsMax) + return S_FALSE; + _numRefs++; + CRef ref; + ref.FileIndex = fileIndex; + ref.Parent = parent; + parent = (int)fs.Refs.Size(); + fs.Refs.Add(ref); + const CItem &item = Items[Files[fileIndex].ItemIndex]; + FOR_VECTOR (i, item.SubFiles) + { + RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed)) + } + return S_OK; +} + + +API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) +{ + UInt32 res = k_IsArc_Res_NO; + unsigned SecLogSize; + for (SecLogSize = 11;; SecLogSize -= 2) + { + if (SecLogSize < 9) + return res; + const UInt32 offset = (UInt32)256 << SecLogSize; + const UInt32 bufSize = (UInt32)1 << SecLogSize; + if (offset + bufSize > size) + res = k_IsArc_Res_NEED_MORE; + else + { + CTag tag; + if (tag.Parse(p + offset, bufSize) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + { + if (Get32(p + offset + 12) == 256 && // TagLocation + tag.CrcLen >= 16) + return k_IsArc_Res_YES; + } + } + } +} + + +HRESULT CInArchive::Open2() +{ + Clear(); + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize)) + FileSize = fileSize; + + // Some UDFs contain additional pad zeros (2 KB). + // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB. + // And when we read last block, result read size can be smaller than required size. + + /* + const size_t kBufSize = 1 << 14; + Byte buf[kBufSize]; + size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize; + RINOK(InStream_SeekSet(_stream, fileSize - readSize)) + RINOK(ReadStream(_stream, buf, &readSize)); + size_t i = readSize; + for (;;) + { + const size_t kSecSizeMin = 1 << 8; + if (i < kSecSizeMin) + return S_FALSE; + i -= kSecSizeMin; + SecLogSize = (readSize - i < ((size_t)1 << 11)) ? 8 : 11; + CTag tag; + if (tag.Parse(buf + i, (1 << SecLogSize)) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + break; + } + PhySize = fileSize; + CExtent extentVDS; + extentVDS.Parse(buf + i + 16); + */ + + /* + An Anchor Volume Descriptor Pointer structure shall be recorded in at + least 2 of the following 3 locations on the media: + Logical Sector 256. + Logical Sector (N - 256). + N + */ + + const size_t kBufSize = 1 << 11; + Byte buf[kBufSize]; + + for (SecLogSize = 11;; SecLogSize -= 2) + { + // Windows 10 uses unusual (SecLogSize = 9) + if (SecLogSize < 9) + return S_FALSE; + const UInt32 offset = (UInt32)256 << SecLogSize; + if (offset >= fileSize) + continue; + RINOK(InStream_SeekSet(_stream, offset)) + const size_t bufSize = (size_t)1 << SecLogSize; + size_t readSize = bufSize; + RINOK(ReadStream(_stream, buf, &readSize)) + if (readSize == bufSize) + { + CTag tag; + if (tag.Parse(buf, readSize) == S_OK) + if (tag.Id == DESC_TYPE_AnchorVolPtr) + { + if (Get32(buf + 12) == 256 && + tag.CrcLen >= 16) // TagLocation + break; + } + } + } + + PhySize = (UInt32)(256 + 1) << SecLogSize; + IsArc = true; + + // UDF 2.2.3 AnchorVolumeDescriptorPointer + + CExtent extentVDS; + extentVDS.Parse(buf + 16); + { + CExtent extentVDS2; + extentVDS2.Parse(buf + 24); + UpdatePhySize(extentVDS); + UpdatePhySize(extentVDS2); + } + + for (UInt32 location = 0; ; location++) + { + if (location >= (extentVDS.Len >> SecLogSize)) + return S_FALSE; + + const size_t bufSize = (size_t)1 << SecLogSize; + { + const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize; + RINOK(InStream_SeekSet(_stream, offs)) + const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); + if (res == S_FALSE && offs + bufSize > FileSize) + UnexpectedEnd = true; + RINOK(res) + } + + CTag tag; + RINOK(tag.Parse(buf, bufSize)) + + if (tag.Id == DESC_TYPE_Terminating) + break; + + if (tag.Id == DESC_TYPE_PrimVol) + { + CPrimeVol &pm = PrimeVols.AddNew(); + pm.Parse(buf); + continue; + } + + if (tag.Id == DESC_TYPE_Partition) + { + // Partition Descriptor + // ECMA 3/10.5 + // UDF 2.2.14 + if (Partitions.Size() >= kNumPartitionsMax) + return S_FALSE; + CPartition partition; + // const UInt32 volDescSeqNumer = Get32(buf + 16); + partition.Flags = Get16(buf + 20); + partition.Number = Get16(buf + 22); + partition.ContentsId.Parse(buf + 24); + + // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); + // ContentsUse contains Partition Header Description. + // ECMA 4/14.3 + // UDF PartitionHeaderDescriptor 2.3.3 + + partition.AccessType = Get32(buf + 184); + partition.Pos = Get32(buf + 188); + partition.Len = Get32(buf + 192); + partition.ImplId.Parse(buf + 196); + // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); + + PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); + Partitions.Add(partition); + continue; + } + + if (tag.Id == DESC_TYPE_LogicalVol) + { + /* Logical Volume Descriptor + ECMA 3/10.6 + UDF 2.60 2.2.4 */ + + if (LogVols.Size() >= kNumLogVolumesMax) + return S_FALSE; + CLogVol &vol = LogVols.AddNew(); + + vol.Id.Parse(buf + 84); + vol.BlockSize = Get32(buf + 212); + if (vol.BlockSize != ((UInt32)1 << SecLogSize)) + { + // UDF 2.2.4.2 LogicalBlockSize + // UDF probably doesn't allow different sizes + return S_FALSE; + } + /* + if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) + return S_FALSE; + */ + + vol.DomainId.Parse(buf + 216); + + // ECMA 4/3.1 + // UDF 2.2.4.4 LogicalVolumeContentsUse + /* the extent in which the first File Set Descriptor Sequence + of the logical volume is recorded */ + vol.FileSetLocation.Parse(buf + 248); + // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); + + vol.ImplId.Parse(buf + 272); + // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse)); + // vol.IntegritySequenceExtent.Parse(buf + 432); + + const UInt32 mapTableLen = Get32(buf + 264); + const UInt32 numPartitionMaps = Get32(buf + 268); + if (numPartitionMaps > kNumPartitionsMax) + return S_FALSE; + + PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); + + size_t pos = 440; + if (mapTableLen > bufSize - pos) + return S_FALSE; + const size_t posLimit = pos + mapTableLen; + + for (UInt32 i = 0; i < numPartitionMaps; i++) + { + // ECMA 3/10.7 Partition maps + if (pos + 2 > posLimit) + return S_FALSE; + CPartitionMap pm; + pm.Type = buf[pos + 0]; + // pm.Length = buf[pos + 1]; + const Byte len = buf[pos + 1]; + if (pos + len > posLimit) + return S_FALSE; + + // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); + if (pm.Type == 1) + { + // ECMA 3/10.7.2 + if (len != 6) + return S_FALSE; + pm.VolumeSequenceNumber = Get16(buf + pos + 2); + pm.PartitionNumber = Get16(buf + pos + 4); + PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber)); + } + else if (pm.Type == 2) + { + if (len != 64) + return S_FALSE; + /* ECMA 10.7.3 / Type 2 Partition Map + 62 bytes: Partition Identifier. */ + + /* UDF + 2.2.8 "*UDF Virtual Partition" + 2.2.9 "*UDF Sparable Partition" + 2.2.10 "*UDF Metadata Partition" + */ + + if (Get16(buf + pos + 2) != 0) // reserved + return S_FALSE; + + pm.PartitionTypeId.Parse(buf + pos + 4); + pm.VolumeSequenceNumber = Get16(buf + pos + 36); + pm.PartitionNumber = Get16(buf + pos + 38); + + if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0) + return S_FALSE; + + // UDF 2.2.10 Metadata Partition Map + pm.MetadataFileLocation = Get32(buf + pos + 40); + // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44); + // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48); + // pm.AllocationUnitSize = Get32(buf + pos + 52); + // pm.AlignmentUnitSize = Get16(buf + pos + 56); + // pm.Flags = buf[pos + 58]; + + PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); + // Unsupported = true; + // return S_FALSE; + } + else + return S_FALSE; + pos += len; + vol.PartitionMaps.Add(pm); + } + continue; + } + + /* + if (tag.Id == DESC_TYPE_UnallocSpace) + { + // UInt32 volDescSeqNumer = Get32(buf + 16); + const UInt32 numAlocDescs = Get32(buf + 20); + // we need examples for (numAlocDescs != 0) case + if (numAlocDescs > (bufSize - 24) / 8) + return S_FALSE; + for (UInt32 i = 0; i < numAlocDescs; i++) + { + CExtent e; + e.Parse(buf + 24 + i * 8); + } + continue; + } + else + continue; + */ + } + + UInt64 totalSize = 0; + + unsigned volIndex; + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + FOR_VECTOR (pmIndex, vol.PartitionMaps) + { + CPartitionMap &pm = vol.PartitionMaps[pmIndex]; + for (unsigned i = 0;; i++) + { + if (i == Partitions.Size()) + return S_FALSE; + CPartition &part = Partitions[i]; + if (part.Number == pm.PartitionNumber) + { + pm.PartitionIndex = i; + if (pm.Type == 2) + break; + + /* + if (part.VolIndex >= 0) + { + // it's for 2.60. Fix it + if (part.VolIndex != (int)volIndex) + return S_FALSE; + // return S_FALSE; + } + part.VolIndex = volIndex; + */ + + totalSize += (UInt64)part.Len << SecLogSize; + break; + } + } + } + } + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + FOR_VECTOR (pmIndex, vol.PartitionMaps) + { + CPartitionMap &pm = vol.PartitionMaps[pmIndex]; + if (pm.Type != 2) + continue; + + { + CLongAllocDesc lad; + lad.Len = vol.BlockSize; + lad.Location.Pos = pm.MetadataFileLocation; + // lad.Location.Pos = pm.MetadataMirrorFileLocation; + + lad.Location.PartitionRef = (UInt16)pmIndex; + + /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex. + so we can use pmIndex or find (Type==1) PartitionMap */ + FOR_VECTOR (pmIndex2, vol.PartitionMaps) + { + const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2]; + if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1) + { + lad.Location.PartitionRef = (UInt16)pmIndex2; + break; + } + } + + RINOK(ReadItem(volIndex, + -1, // (fsIndex = -1) means that it's metadata + lad, + false, // isDir + 1)) // numRecurseAllowed + } + { + const CItem &item = Items.Back(); + if (!CheckItemExtents(volIndex, item)) + return S_FALSE; + if (item.Extents.Size() != 1) + { + if (item.Extents.Size() < 1) + return S_FALSE; + /* Windows 10 writes empty record item.Extents[1]. + we ignore such extent here */ + for (unsigned k = 1; k < item.Extents.Size(); k++) + { + const CMyExtent &e = item.Extents[k]; + if (e.GetLen() != 0) + return S_FALSE; + } + } + + const CMyExtent &e = item.Extents[0]; + const CPartition &part = Partitions[pm.PartitionIndex]; + CPartition mp = part; + mp.IsMetadata = true; + // mp.Number = part.Number; + mp.Pos = part.Pos + e.Pos; + mp.Len = e.Len >> SecLogSize; + pm.PartitionIndex = Partitions.Add(mp); + } + // Items.DeleteBack(); // we can delete that metadata item + + /* + // short version of code to read metadata file. + RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf)); + CTag tag; + RINOK(tag.Parse(buf, 224)); + if (tag.Id != DESC_TYPE_ExtendedFile) + return S_FALSE; + CShortAllocDesc sad; + sad.Parse(buf + 216); + const CPartition &part = Partitions[pm.PartitionIndex]; + CPartition mp = part; + mp.IsMetadata = true; + // mp.Number = part.Number; + mp.Pos = part.Pos + sad.Pos; + mp.Len = sad.Len >> SecLogSize; + pm.PartitionIndex = Partitions.Add(mp); + */ + } + } + + RINOK(_progress->SetTotal(totalSize)) + + PRF(printf("\n Read files")); + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + + PRF(printf("\nLogVol %2d", volIndex)); + + CLongAllocDesc nextExtent = vol.FileSetLocation; + // while (nextExtent.ExtentLen != 0) + // for (int i = 0; i < 1; i++) + { + if (nextExtent.GetLen() < 512) + return S_FALSE; + CByteBuffer buf2(nextExtent.GetLen()); + RINOK(ReadLad(volIndex, nextExtent, buf2)) + const Byte *p = buf2; + const size_t size = nextExtent.GetLen(); + + CTag tag; + RINOK(tag.Parse(p, size)) + + /* + // commented in 22.01 + if (tag.Id == DESC_TYPE_ExtendedFile) + { + // ECMA 4 / 14.17 + // 2.60 ?? + return S_FALSE; + } + */ + + if (tag.Id != DESC_TYPE_FileSet) + return S_FALSE; + + PRF(printf("\n FileSet", volIndex)); + CFileSet fs; + fs.RecordingTime.Parse(p + 16); + // fs.InterchangeLevel = Get16(p + 18); + // fs.MaxInterchangeLevel = Get16(p + 20); + fs.FileSetNumber = Get32(p + 40); + fs.FileSetDescNumber = Get32(p + 44); + + fs.LogicalVolumeId.Parse(p + 112); + fs.Id.Parse(p + 304); + fs.CopyrightId.Parse(p + 336); + fs.AbstractId.Parse(p + 368); + + fs.RootDirICB.Parse(p + 400); + fs.DomainId.Parse(p + 416); + + // fs.SystemStreamDirICB.Parse(p + 464); + + vol.FileSets.Add(fs); + + // nextExtent.Parse(p + 448); + } + + FOR_VECTOR (fsIndex, vol.FileSets) + { + CFileSet &fs = vol.FileSets[fsIndex]; + const unsigned fileIndex = Files.Size(); + Files.AddNew(); + RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, + true, // isDir + kNumRecursionLevelsMax)) + RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax)) + } + } + + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + const CLogVol &vol = LogVols[volIndex]; + // bool showFileSetName = (vol.FileSets.Size() > 1); + FOR_VECTOR (fsIndex, vol.FileSets) + { + const CFileSet &fs = vol.FileSets[fsIndex]; + for (unsigned i = + // ((showVolName || showFileSetName) ? 0 : 1) + 0; i < fs.Refs.Size(); i++) + { + const CRef &ref = vol.FileSets[fsIndex].Refs[i]; + const CFile &file = Files[ref.FileIndex]; + const CItem &item = Items[file.ItemIndex]; + UInt64 size = item.Size; + + if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) + continue; + + FOR_VECTOR (extentIndex, item.Extents) + { + const CMyExtent &extent = item.Extents[extentIndex]; + const UInt32 len = extent.GetLen(); + if (len == 0) + continue; + if (size < len) + break; + + const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + const UInt32 logBlockNumber = extent.Pos; + const CPartition &partition = Partitions[partitionIndex]; + const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + + (UInt64)logBlockNumber * vol.BlockSize; + UpdatePhySize(offset + len); + } + } + } + } + + { + const UInt32 secMask = ((UInt32)1 << SecLogSize) - 1; + PhySize = (PhySize + secMask) & ~(UInt64)secMask; + } + + NoEndAnchor = true; + + if (PhySize < fileSize) + { + UInt64 rem = fileSize - PhySize; + const size_t secSize = (size_t)1 << SecLogSize; + + RINOK(InStream_SeekSet(_stream, PhySize)) + + // some UDF images contain ZEROs before "Anchor Volume Descriptor Pointer" at the end + + for (unsigned sec = 0; sec < 1024; sec++) + { + if (rem == 0) + break; + + size_t readSize = secSize; + if (readSize > rem) + readSize = (size_t)rem; + + RINOK(ReadStream(_stream, buf, &readSize)) + + if (readSize == 0) + break; + + // some udf contain many EndAnchors + if (readSize == secSize /* && NoEndAnchor */) + { + CTag tag; + if (tag.Parse(buf, readSize) == S_OK + && tag.Id == DESC_TYPE_AnchorVolPtr + && Get32(buf + 12) == (UInt32)((fileSize - rem) >> SecLogSize)) + { + NoEndAnchor = false; + rem -= readSize; + PhySize = fileSize - rem; + continue; + } + } + + size_t i; + for (i = 0; i < readSize && buf[i] == 0; i++); + if (i != readSize) + break; + rem -= readSize; + } + + if (rem == 0) + PhySize = fileSize; + } + + return S_OK; +} + + +HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress) +{ + _progress = progress; + _stream = inStream; + HRESULT res = Open2(); + if (res == S_FALSE && IsArc && !UnexpectedEnd) + Unsupported = true; + return res; + + /* + HRESULT res; + try + { + res = Open2(); + } + catch(...) + { + // Clear(); + // res = S_FALSE; + _stream.Release(); + throw; + } + _stream.Release(); + return res; + */ +} + +void CInArchive::Clear() +{ + IsArc = false; + Unsupported = false; + UnexpectedEnd = false; + NoEndAnchor = false; + + PhySize = 0; + FileSize = 0; + + Partitions.Clear(); + LogVols.Clear(); + PrimeVols.Clear(); + Items.Clear(); + Files.Clear(); + _fileNameLengthTotal = 0; + _numRefs = 0; + _numExtents = 0; + _inlineExtentsSize = 0; + _processedProgressBytes = 0; +} + + +static const char * const g_PartitionTypes[] = +{ + "Pseudo-Overwritable" // UDF + , "Read-Only" + , "Write-Once" + , "Rewritable" + , "Overwritable" +}; + + +static void AddComment_Align(UString &s) +{ + s += " "; +} + +static void AddComment_PropName(UString &s, const char *name) +{ + AddComment_Align(s); + s += name; + s += ": "; +} + +static void AddComment_UInt32(UString &s, const char *name, UInt32 val) +{ + AddComment_PropName(s, name); + s.Add_UInt32(val); + s.Add_LF(); +} + +static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val) +{ + AddComment_Align(s); + AddComment_UInt32(s, name, val); +} + + +static void AddComment_UInt64(UString &s, const char *name, UInt64 val) +{ + AddComment_PropName(s, name); + s.Add_UInt64(val); + s.Add_LF(); +} + +static void AddComment_RegId(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + s.Add_LF(); +} + +static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + UString s2; + ri.AddUdfVersionTo(s2); + if (!s2.IsEmpty()) + { + s += "::"; + s += s2; + } + } + s.Add_LF(); +} + + +// UDF 6.3.1 OS Class + +static const char * const g_OsClasses[] = +{ + NULL + , "DOS" + , "OS/2" + , "Macintosh OS" + , "UNIX" + , "Windows 9x" + , "Windows NT" + , "OS/400" + , "BeOS" + , "Windows CE" +}; + +// UDF 6.3.2 OS Identifier + +static const char * const g_OsIds_Unix[] = +{ + NULL // "Generic" + , "AIX" + , "SUN OS / Solaris" + , "HP/UX" + , "Silicon Graphics Irix" + , "Linux" + , "MKLinux" + , "FreeBSD" + , "NetBSD" +}; + +static void AddOs_Class_Id(UString &s, const Byte *p) +{ + // UDF 2.1.5.3 Implementation Identifier Suffix + // Appendix 6.3 Operating System Identifiers. + const Byte osClass = p[0]; + if (osClass != 0) + { + s += "::"; + s += TypeToString(g_OsClasses, Z7_ARRAY_SIZE(g_OsClasses), osClass); + } + const Byte osId = p[1]; + if (osId != 0) + { + s += "::"; + if (osClass == 4) // unix + { + s += TypeToString(g_OsIds_Unix, Z7_ARRAY_SIZE(g_OsIds_Unix), osId); + } + else + s.Add_UInt32(osId); + } +} + + +static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + AddOs_Class_Id(s, ri.Suffix); + } + s.Add_LF(); +} + + +static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + // UDF 2.1.5.3 + // UDF Identifier Suffix format + UString s2; + ri.AddUdfVersionTo(s2); + if (!s2.IsEmpty()) + { + s += "::"; + s += s2; + } + AddOs_Class_Id(s, &ri.Suffix[2]); + } + s.Add_LF(); +} + +static void AddComment_DString32(UString &s, const char *name, const CDString32 &d) +{ + AddComment_Align(s); + AddComment_PropName(s, name); + s += d.GetString(); + s.Add_LF(); +} + +UString CInArchive::GetComment() const +{ + UString s; + { + s += "Primary Volumes:"; + s.Add_LF(); + FOR_VECTOR (i, PrimeVols) + { + if (i != 0) + s.Add_LF(); + const CPrimeVol &pv = PrimeVols[i]; + // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber); + // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0) + AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber); + // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1) + AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber); + if (pv.MaximumVolumeSequenceNumber != 1) + AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber); + AddComment_PropName(s, "VolumeId"); + s += pv.VolumeId.GetString(); + s.Add_LF(); + AddComment_PropName(s, "VolumeSetId"); + s += pv.VolumeSetId.GetString(); + s.Add_LF(); + // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel); + // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel); + AddComment_RegId(s, "ApplicationId", pv.ApplicationId); + AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId); + } + } + { + s += "Partitions:"; + s.Add_LF(); + FOR_VECTOR (i, Partitions) + { + if (i != 0) + s.Add_LF(); + const CPartition &part = Partitions[i]; + AddComment_UInt32(s, "PartitionIndex", i); + AddComment_UInt32(s, "PartitionNumber", part.Number); + if (part.IsMetadata) + AddComment_UInt32(s, "IsMetadata", 1); + else + { + AddComment_RegId(s, "ContentsId", part.ContentsId); + AddComment_RegId_Impl(s, "ImplementationId", part.ImplId); + AddComment_PropName(s, "AccessType"); + s += TypeToString(g_PartitionTypes, Z7_ARRAY_SIZE(g_PartitionTypes), part.AccessType); + s.Add_LF(); + } + AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize); + AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize); + } + } + s += "Logical Volumes:"; + s.Add_LF(); + { + FOR_VECTOR (i, LogVols) + { + if (i != 0) + s.Add_LF(); + const CLogVol &vol = LogVols[i]; + if (LogVols.Size() != 1) + AddComment_UInt32(s, "Number", i); + AddComment_PropName(s, "Id"); + s += vol.Id.GetString(); + s.Add_LF(); + AddComment_UInt32(s, "BlockSize", vol.BlockSize); + AddComment_RegId_Domain(s, "DomainId", vol.DomainId); + AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId); + // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len); + // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize); + + s += " Partition Maps:"; + s.Add_LF(); + { + FOR_VECTOR (j, vol.PartitionMaps) + { + if (j != 0) + s.Add_LF(); + const CPartitionMap &pm = vol.PartitionMaps[j]; + AddComment_UInt32_2(s, "PartitionMap", j); + AddComment_UInt32_2(s, "Type", pm.Type); + AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber); + AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber); + if (pm.Type == 2) + { + AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation); + // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation); + // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation); + // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize); + // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize); + // AddComment_UInt32_2(s, "Flags", pm.Flags); + AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId); + } + } + } + s += " File Sets:"; + s.Add_LF(); + { + FOR_VECTOR (j, vol.FileSets) + { + if (j != 0) + s.Add_LF(); + const CFileSet &fs = vol.FileSets[j]; + AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber); + AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber); + + AddComment_Align(s); + AddComment_PropName(s, "LogicalVolumeId"); + s += fs.LogicalVolumeId.GetString(); + s.Add_LF(); + + AddComment_DString32(s, "Id", fs.Id); + AddComment_DString32(s, "CopyrightId", fs.CopyrightId); + AddComment_DString32(s, "AbstractId", fs.AbstractId); + + AddComment_Align(s); + AddComment_RegId_Domain(s, "DomainId", fs.DomainId); + } + } + } + } + return s; +} + +static UString GetSpecName(const UString &name) +{ + UString name2 = name; + name2.Trim(); + if (name2.IsEmpty()) + return UString("[]"); + return name; +} + +static void UpdateWithName(UString &res, const UString &addString) +{ + if (res.IsEmpty()) + res = addString; + else + res.Insert(0, addString + WCHAR_PATH_SEPARATOR); +} + +UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, + bool showVolName, bool showFsName) const +{ + // showVolName = true; + const CLogVol &vol = LogVols[volIndex]; + const CFileSet &fs = vol.FileSets[fsIndex]; + + UString name; + + for (;;) + { + const CRef &ref = fs.Refs[refIndex]; + // we break on root file (that probably has empty name) + if (ref.Parent < 0) + break; + refIndex = (unsigned)ref.Parent; + UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); + } + + if (showFsName) + { + UString newName ("File Set "); + newName.Add_UInt32(fsIndex); + UpdateWithName(name, newName); + } + + if (showVolName) + { + UString newName; + newName.Add_UInt32(volIndex); + UString newName2 = vol.GetName(); + if (newName2.IsEmpty()) + newName2 = "Volume"; + newName.Add_Minus(); + newName += newName2; + UpdateWithName(name, newName); + } + return name; +} + +}} diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h index 7d66c2c00..9ccbf7463 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.h +++ b/CPP/7zip/Archive/Udf/UdfIn.h @@ -1,507 +1,507 @@ -// Archive/UdfIn.h -- UDF / ECMA-167 - -#ifndef ZIP7_INC_ARCHIVE_UDF_IN_H -#define ZIP7_INC_ARCHIVE_UDF_IN_H - -#include "../../../Common/IntToString.h" -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyCom.h" -#include "../../../Common/MyMap.h" -#include "../../../Common/MyString.h" - -#include "../../IStream.h" - -namespace NArchive { -namespace NUdf { - -// ---------- ECMA Part 1 ---------- - -// ECMA 1/7.2.12 -// UDF 2.1.3 - -struct CDString32 -{ - Byte Data[32]; - - void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } - UString GetString() const; -}; - -struct CDString128 -{ - Byte Data[128]; - - void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } - UString GetString() const; -}; - -struct CDString -{ - CByteBuffer Data; - - void Parse(const Byte *p, unsigned size); - UString GetString() const; -}; - - -// ECMA 1/7.3 -// UDF 2.1.4 timestamp - -struct CTime -{ - Byte Data[12]; - - unsigned GetType() const { return Data[1] >> 4; } - bool IsLocal() const { return GetType() == 1; } - int GetMinutesOffset() const - { - int t = (Data[0] | ((unsigned)Data[1] << 8)) & 0xFFF; - if ((t >> 11) != 0) - t -= (1 << 12); - return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t; - } - unsigned GetYear() const { return (Data[2] | ((unsigned)Data[3] << 8)); } - void Parse(const Byte *buf); -}; - - -// ECMA 1/7.4 regid -// UDF 2.1.5 EntityID - -struct CRegId -{ - Byte Flags; - char Id[23]; - Byte Suffix[8]; - - void Parse(const Byte *buf); - void AddCommentTo(UString &s) const; - void AddUdfVersionTo(UString &s) const; -}; - - - -// ---------- ECMA Part 3: Volume Structure ---------- - -// ECMA 3/7.1 - -struct CExtent -{ - UInt32 Len; - UInt32 Pos; // logical sector number - - void Parse(const Byte *p); -}; - - -// ECMA 3/10.1 -// UDF 2.2.2 PrimaryVolumeDescriptor - -struct CPrimeVol -{ - // UInt32 VolumeDescriptorSequenceNumber; - UInt32 PrimaryVolumeDescriptorNumber; - CDString32 VolumeId; - UInt16 VolumeSequenceNumber; - UInt16 MaximumVolumeSequenceNumber; - // UInt16 InterchangeLevel; - // UInt16 MaximumInterchangeLevel; - // UInt32 CharacterSetList; - // UInt32 MaximumCharacterSetList; - CDString128 VolumeSetId; - // charspec DescriptorCharacterSet; // (1/7.2.1) - // charspec ExplanatoryCharacterSet; // (1/7.2.1) - // CExtent VolumeAbstract; - // CExtent VolumeCopyrightNotice; - CRegId ApplicationId; - CTime RecordingTime; - CRegId ImplId; - // bytes ImplementationUse - // UInt32 PredecessorVolumeDescriptorSequenceLocation; - // UInt16 Flags; - - void Parse(const Byte *p); -}; - - -// ECMA 3/10.5 -// UDF 2.2.14 PartitionDescriptor - -struct CPartition -{ - UInt32 Pos; - UInt32 Len; - - UInt16 Flags; - UInt16 Number; - CRegId ContentsId; - // Byte ContentsUse[128]; - UInt32 AccessType; - - CRegId ImplId; - // Byte ImplUse[128]; - - // int VolIndex; - CMap32 Map; - - bool IsMetadata; - - CPartition(): - // VolIndex(-1), - IsMetadata(false) {} - - // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } - // bool IsAllocated() const { return ((Flags & 1) != 0); } -}; - - -// ECMA 4/7.1 lb_addr - -struct CLogBlockAddr -{ - UInt32 Pos; - UInt16 PartitionRef; - - void Parse(const Byte *p); -}; - - -enum EShortAllocDescType -{ - SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, - SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1, - SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2, - SHORT_ALLOC_DESC_TYPE_NextExtent = 3 -}; - - -// ECMA 4/14.14.1 short_ad - -struct CShortAllocDesc -{ - UInt32 Len; - UInt32 Pos; - - // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } - // UInt32 GetType() const { return Len >> 30; } - // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *p); -}; - -/* -struct CADImpUse -{ - UInt16 Flags; - UInt32 UdfUniqueId; - void Parse(const Byte *p); -}; -*/ - -// ECMA 4/14.14.2 long_ad -// UDF 2.3.10.1 - -struct CLongAllocDesc -{ - UInt32 Len; - CLogBlockAddr Location; - - // Byte ImplUse[6]; - // CADImpUse adImpUse; // UDF - - UInt32 GetLen() const { return Len & 0x3FFFFFFF; } - UInt32 GetType() const { return Len >> 30; } - bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *p); -}; - - -// ECMA 3/10.7 Partition maps -// UDF 2.2.8-2.2.10 Partition Maps - -struct CPartitionMap -{ - unsigned PartitionIndex; - - Byte Type; - // Byte Len; - - // ECMA 10.7.2 - UInt16 VolumeSequenceNumber; - UInt16 PartitionNumber; - - CRegId PartitionTypeId; - - // UDF 2.2.10 Metadata Partition Map - UInt32 MetadataFileLocation; - // UInt32 MetadataMirrorFileLocation; - // UInt32 MetadataBitmapFileLocation; - // UInt32 AllocationUnitSize; // (Blocks) - // UInt16 AlignmentUnitSize; // (Blocks) - // Byte Flags; - - // Byte Data[256]; - // CPartitionMap(): PartitionIndex(-1) {} -}; - - -// ECMA 4/14.6.6 - -enum EIcbFileType -{ - ICB_FILE_TYPE_DIR = 4, - ICB_FILE_TYPE_FILE = 5, - - ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File - ICB_FILE_TYPE_METADATA_MIRROR = 251 -}; - -enum EIcbDescriptorType -{ - ICB_DESC_TYPE_SHORT = 0, - ICB_DESC_TYPE_LONG = 1, - ICB_DESC_TYPE_EXTENDED = 2, - ICB_DESC_TYPE_INLINE = 3 -}; - -// ECMA 4/14.6 -// UDF 3.3.2 - -struct CIcbTag -{ - // UInt32 PriorDirectNum; - // UInt16 StrategyType; - // UInt16 StrategyParam; - // UInt16 MaxNumOfEntries; - Byte FileType; - // CLogBlockAddr ParentIcb; - UInt16 Flags; - - bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; } - int GetDescriptorType() const { return Flags & 3; } - void Parse(const Byte *p); -}; - - -// ECMA 4/14.4.3 -// UDF 2.3.4.2 FileCharacteristics - -// const Byte FILEID_CHARACS_Existance = (1 << 0); -const Byte FILEID_CHARACS_Dir = (1 << 1); -const Byte FILEID_CHARACS_Deleted = (1 << 2); -const Byte FILEID_CHARACS_Parent = (1 << 3); -// const Byte FILEID_CHARACS_Metadata = (1 << 4); - -struct CFile -{ - int ItemIndex; - // UInt16 FileVersion; - // Byte FileCharacteristics; - // CByteBuffer ImplUse; - CDString Id; - - CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} - UString GetName() const { return Id.GetString(); } -}; - - -struct CMyExtent -{ - UInt32 Pos; - UInt32 Len; - unsigned PartitionRef; // index in CLogVol::PartitionMaps - - UInt32 GetLen() const { return Len & 0x3FFFFFFF; } - UInt32 GetType() const { return Len >> 30; } - bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } -}; - - -struct CItem -{ - CIcbTag IcbTag; - - // UInt32 Uid; - // UInt32 Gid; - // UInt32 Permissions; - UInt16 FileLinkCount; - // Byte RecordFormat; - // Byte RecordDisplayAttr; - // UInt32 RecordLen; - UInt64 Size; - UInt64 NumLogBlockRecorded; - // UInt64 ObjectSize; - - CTime ATime; - CTime MTime; - CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of. - CTime CreateTime; - // UInt32 CheckPoint; - // CLongAllocDesc ExtendedAttrIcb; - // CRegId ImplId; - // UInt64 UniqueId; - - bool IsExtended; - bool IsInline; - CByteBuffer InlineData; - CRecordVector Extents; - CUIntVector SubFiles; - - void Parse(const Byte *p); - - bool IsRecAndAlloc() const - { - FOR_VECTOR (i, Extents) - if (!Extents[i].IsRecAndAlloc()) - return false; - return true; - } - - UInt64 GetChunksSumSize() const - { - if (IsInline) - return InlineData.Size(); - UInt64 size = 0; - FOR_VECTOR (i, Extents) - size += Extents[i].GetLen(); - return size; - } - - bool CheckChunkSizes() const { return GetChunksSumSize() == Size; } - - bool IsDir() const { return IcbTag.IsDir(); } -}; - - -struct CRef -{ - unsigned FileIndex; - int Parent; -}; - - -// ECMA 4 / 14.1 -struct CFileSet -{ - CRecordVector Refs; - - CTime RecordingTime; - // UInt16 InterchangeLevel; - // UInt16 MaxInterchangeLevel; - UInt32 FileSetNumber; - UInt32 FileSetDescNumber; - CDString128 LogicalVolumeId; - CDString32 Id; - CDString32 CopyrightId; - CDString32 AbstractId; - - CLongAllocDesc RootDirICB; - CRegId DomainId; - // CLongAllocDesc SystemStreamDirICB; -}; - - -/* 8.3 Volume descriptors -8.4 -A Volume Descriptor Sequence: - shall contain one or more Primary Volume Descriptors. -*/ - -// ECMA 3/10.6 -// UDF 2.2.4 LogicalVolumeDescriptor - -struct CLogVol -{ - CObjectVector PartitionMaps; - CObjectVector FileSets; - - UInt32 BlockSize; - CDString128 Id; - CRegId DomainId; - - // Byte ContentsUse[16]; - CLongAllocDesc FileSetLocation; // UDF - - CRegId ImplId; - // Byte ImplUse[128]; - // CExtent IntegritySequenceExtent; - - UString GetName() const { return Id.GetString(); } -}; - - -Z7_PURE_INTERFACES_BEGIN -struct Z7_DECLSPEC_NOVTABLE CProgressVirt -{ - virtual HRESULT SetTotal(UInt64 numBytes) =0; \ - virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) =0; \ - virtual HRESULT SetCompleted() =0; \ -}; -Z7_PURE_INTERFACES_END - -class CInArchive -{ -public: - CObjectVector LogVols; - CObjectVector Items; - CObjectVector Files; - CObjectVector Partitions; - - unsigned SecLogSize; - UInt64 PhySize; - UInt64 FileSize; - - bool IsArc; - bool Unsupported; - bool UnexpectedEnd; - bool NoEndAnchor; - - CObjectVector PrimeVols; - - HRESULT Open(IInStream *inStream, CProgressVirt *progress); - void Clear(); - - UString GetComment() const; - UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, - bool showVolName, bool showFsName) const; - - bool CheckItemExtents(unsigned volIndex, const CItem &item) const; - -private: - IInStream *_stream; - CProgressVirt *_progress; - - HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); - HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf); - HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf); - - HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed); - HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed); - - HRESULT Open2(); - HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); - - UInt64 _processedProgressBytes; - - UInt64 _fileNameLengthTotal; - unsigned _numRefs; - UInt32 _numExtents; - UInt64 _inlineExtentsSize; - bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const; - - void UpdatePhySize(UInt64 val) - { - if (PhySize < val) - PhySize = val; - } - - void UpdatePhySize(const CExtent &e) - { - UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len); - } -}; - -API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); - -}} - -#endif +// Archive/UdfIn.h -- UDF / ECMA-167 + +#ifndef ZIP7_INC_ARCHIVE_UDF_IN_H +#define ZIP7_INC_ARCHIVE_UDF_IN_H + +#include "../../../Common/IntToString.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/MyMap.h" +#include "../../../Common/MyString.h" + +#include "../../IStream.h" + +namespace NArchive { +namespace NUdf { + +// ---------- ECMA Part 1 ---------- + +// ECMA 1/7.2.12 +// UDF 2.1.3 + +struct CDString32 +{ + Byte Data[32]; + + void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + UString GetString() const; +}; + +struct CDString128 +{ + Byte Data[128]; + + void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + UString GetString() const; +}; + +struct CDString +{ + CByteBuffer Data; + + void Parse(const Byte *p, unsigned size); + UString GetString() const; +}; + + +// ECMA 1/7.3 +// UDF 2.1.4 timestamp + +struct CTime +{ + Byte Data[12]; + + unsigned GetType() const { return Data[1] >> 4; } + bool IsLocal() const { return GetType() == 1; } + int GetMinutesOffset() const + { + int t = (Data[0] | ((unsigned)Data[1] << 8)) & 0xFFF; + if ((t >> 11) != 0) + t -= (1 << 12); + return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t; + } + unsigned GetYear() const { return (Data[2] | ((unsigned)Data[3] << 8)); } + void Parse(const Byte *buf); +}; + + +// ECMA 1/7.4 regid +// UDF 2.1.5 EntityID + +struct CRegId +{ + Byte Flags; + char Id[23]; + Byte Suffix[8]; + + void Parse(const Byte *buf); + void AddCommentTo(UString &s) const; + void AddUdfVersionTo(UString &s) const; +}; + + + +// ---------- ECMA Part 3: Volume Structure ---------- + +// ECMA 3/7.1 + +struct CExtent +{ + UInt32 Len; + UInt32 Pos; // logical sector number + + void Parse(const Byte *p); +}; + + +// ECMA 3/10.1 +// UDF 2.2.2 PrimaryVolumeDescriptor + +struct CPrimeVol +{ + // UInt32 VolumeDescriptorSequenceNumber; + UInt32 PrimaryVolumeDescriptorNumber; + CDString32 VolumeId; + UInt16 VolumeSequenceNumber; + UInt16 MaximumVolumeSequenceNumber; + // UInt16 InterchangeLevel; + // UInt16 MaximumInterchangeLevel; + // UInt32 CharacterSetList; + // UInt32 MaximumCharacterSetList; + CDString128 VolumeSetId; + // charspec DescriptorCharacterSet; // (1/7.2.1) + // charspec ExplanatoryCharacterSet; // (1/7.2.1) + // CExtent VolumeAbstract; + // CExtent VolumeCopyrightNotice; + CRegId ApplicationId; + CTime RecordingTime; + CRegId ImplId; + // bytes ImplementationUse + // UInt32 PredecessorVolumeDescriptorSequenceLocation; + // UInt16 Flags; + + void Parse(const Byte *p); +}; + + +// ECMA 3/10.5 +// UDF 2.2.14 PartitionDescriptor + +struct CPartition +{ + UInt32 Pos; + UInt32 Len; + + UInt16 Flags; + UInt16 Number; + CRegId ContentsId; + // Byte ContentsUse[128]; + UInt32 AccessType; + + CRegId ImplId; + // Byte ImplUse[128]; + + // int VolIndex; + CMap32 Map; + + bool IsMetadata; + + CPartition(): + // VolIndex(-1), + IsMetadata(false) {} + + // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } + // bool IsAllocated() const { return ((Flags & 1) != 0); } +}; + + +// ECMA 4/7.1 lb_addr + +struct CLogBlockAddr +{ + UInt32 Pos; + UInt16 PartitionRef; + + void Parse(const Byte *p); +}; + + +enum EShortAllocDescType +{ + SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, + SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1, + SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2, + SHORT_ALLOC_DESC_TYPE_NextExtent = 3 +}; + + +// ECMA 4/14.14.1 short_ad + +struct CShortAllocDesc +{ + UInt32 Len; + UInt32 Pos; + + // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } + // UInt32 GetType() const { return Len >> 30; } + // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } + void Parse(const Byte *p); +}; + +/* +struct CADImpUse +{ + UInt16 Flags; + UInt32 UdfUniqueId; + void Parse(const Byte *p); +}; +*/ + +// ECMA 4/14.14.2 long_ad +// UDF 2.3.10.1 + +struct CLongAllocDesc +{ + UInt32 Len; + CLogBlockAddr Location; + + // Byte ImplUse[6]; + // CADImpUse adImpUse; // UDF + + UInt32 GetLen() const { return Len & 0x3FFFFFFF; } + UInt32 GetType() const { return Len >> 30; } + bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } + void Parse(const Byte *p); +}; + + +// ECMA 3/10.7 Partition maps +// UDF 2.2.8-2.2.10 Partition Maps + +struct CPartitionMap +{ + unsigned PartitionIndex; + + Byte Type; + // Byte Len; + + // ECMA 10.7.2 + UInt16 VolumeSequenceNumber; + UInt16 PartitionNumber; + + CRegId PartitionTypeId; + + // UDF 2.2.10 Metadata Partition Map + UInt32 MetadataFileLocation; + // UInt32 MetadataMirrorFileLocation; + // UInt32 MetadataBitmapFileLocation; + // UInt32 AllocationUnitSize; // (Blocks) + // UInt16 AlignmentUnitSize; // (Blocks) + // Byte Flags; + + // Byte Data[256]; + // CPartitionMap(): PartitionIndex(-1) {} +}; + + +// ECMA 4/14.6.6 + +enum EIcbFileType +{ + ICB_FILE_TYPE_DIR = 4, + ICB_FILE_TYPE_FILE = 5, + + ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File + ICB_FILE_TYPE_METADATA_MIRROR = 251 +}; + +enum EIcbDescriptorType +{ + ICB_DESC_TYPE_SHORT = 0, + ICB_DESC_TYPE_LONG = 1, + ICB_DESC_TYPE_EXTENDED = 2, + ICB_DESC_TYPE_INLINE = 3 +}; + +// ECMA 4/14.6 +// UDF 3.3.2 + +struct CIcbTag +{ + // UInt32 PriorDirectNum; + // UInt16 StrategyType; + // UInt16 StrategyParam; + // UInt16 MaxNumOfEntries; + Byte FileType; + // CLogBlockAddr ParentIcb; + UInt16 Flags; + + bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; } + int GetDescriptorType() const { return Flags & 3; } + void Parse(const Byte *p); +}; + + +// ECMA 4/14.4.3 +// UDF 2.3.4.2 FileCharacteristics + +// const Byte FILEID_CHARACS_Existance = (1 << 0); +const Byte FILEID_CHARACS_Dir = (1 << 1); +const Byte FILEID_CHARACS_Deleted = (1 << 2); +const Byte FILEID_CHARACS_Parent = (1 << 3); +// const Byte FILEID_CHARACS_Metadata = (1 << 4); + +struct CFile +{ + int ItemIndex; + // UInt16 FileVersion; + // Byte FileCharacteristics; + // CByteBuffer ImplUse; + CDString Id; + + CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} + UString GetName() const { return Id.GetString(); } +}; + + +struct CMyExtent +{ + UInt32 Pos; + UInt32 Len; + unsigned PartitionRef; // index in CLogVol::PartitionMaps + + UInt32 GetLen() const { return Len & 0x3FFFFFFF; } + UInt32 GetType() const { return Len >> 30; } + bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } +}; + + +struct CItem +{ + CIcbTag IcbTag; + + // UInt32 Uid; + // UInt32 Gid; + // UInt32 Permissions; + UInt16 FileLinkCount; + // Byte RecordFormat; + // Byte RecordDisplayAttr; + // UInt32 RecordLen; + UInt64 Size; + UInt64 NumLogBlockRecorded; + // UInt64 ObjectSize; + + CTime ATime; + CTime MTime; + CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of. + CTime CreateTime; + // UInt32 CheckPoint; + // CLongAllocDesc ExtendedAttrIcb; + // CRegId ImplId; + // UInt64 UniqueId; + + bool IsExtended; + bool IsInline; + CByteBuffer InlineData; + CRecordVector Extents; + CUIntVector SubFiles; + + void Parse(const Byte *p); + + bool IsRecAndAlloc() const + { + FOR_VECTOR (i, Extents) + if (!Extents[i].IsRecAndAlloc()) + return false; + return true; + } + + UInt64 GetChunksSumSize() const + { + if (IsInline) + return InlineData.Size(); + UInt64 size = 0; + FOR_VECTOR (i, Extents) + size += Extents[i].GetLen(); + return size; + } + + bool CheckChunkSizes() const { return GetChunksSumSize() == Size; } + + bool IsDir() const { return IcbTag.IsDir(); } +}; + + +struct CRef +{ + unsigned FileIndex; + int Parent; +}; + + +// ECMA 4 / 14.1 +struct CFileSet +{ + CRecordVector Refs; + + CTime RecordingTime; + // UInt16 InterchangeLevel; + // UInt16 MaxInterchangeLevel; + UInt32 FileSetNumber; + UInt32 FileSetDescNumber; + CDString128 LogicalVolumeId; + CDString32 Id; + CDString32 CopyrightId; + CDString32 AbstractId; + + CLongAllocDesc RootDirICB; + CRegId DomainId; + // CLongAllocDesc SystemStreamDirICB; +}; + + +/* 8.3 Volume descriptors +8.4 +A Volume Descriptor Sequence: + shall contain one or more Primary Volume Descriptors. +*/ + +// ECMA 3/10.6 +// UDF 2.2.4 LogicalVolumeDescriptor + +struct CLogVol +{ + CObjectVector PartitionMaps; + CObjectVector FileSets; + + UInt32 BlockSize; + CDString128 Id; + CRegId DomainId; + + // Byte ContentsUse[16]; + CLongAllocDesc FileSetLocation; // UDF + + CRegId ImplId; + // Byte ImplUse[128]; + // CExtent IntegritySequenceExtent; + + UString GetName() const { return Id.GetString(); } +}; + + +Z7_PURE_INTERFACES_BEGIN +struct Z7_DECLSPEC_NOVTABLE CProgressVirt +{ + virtual HRESULT SetTotal(UInt64 numBytes) =0; \ + virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) =0; \ + virtual HRESULT SetCompleted() =0; \ +}; +Z7_PURE_INTERFACES_END + +class CInArchive +{ +public: + CObjectVector LogVols; + CObjectVector Items; + CObjectVector Files; + CObjectVector Partitions; + + unsigned SecLogSize; + UInt64 PhySize; + UInt64 FileSize; + + bool IsArc; + bool Unsupported; + bool UnexpectedEnd; + bool NoEndAnchor; + + CObjectVector PrimeVols; + + HRESULT Open(IInStream *inStream, CProgressVirt *progress); + void Clear(); + + UString GetComment() const; + UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, + bool showVolName, bool showFsName) const; + + bool CheckItemExtents(unsigned volIndex, const CItem &item) const; + +private: + IInStream *_stream; + CProgressVirt *_progress; + + HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); + HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf); + HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf); + + HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed); + HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed); + + HRESULT Open2(); + HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); + + UInt64 _processedProgressBytes; + + UInt64 _fileNameLengthTotal; + unsigned _numRefs; + UInt32 _numExtents; + UInt64 _inlineExtentsSize; + bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const; + + void UpdatePhySize(UInt64 val) + { + if (PhySize < val) + PhySize = val; + } + + void UpdatePhySize(const CExtent &e) + { + UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len); + } +}; + +API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); + +}} + +#endif diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp index 374d98d77..b224cdf26 100644 --- a/CPP/7zip/Archive/UefiHandler.cpp +++ b/CPP/7zip/Archive/UefiHandler.cpp @@ -1,1884 +1,1884 @@ -// UefiHandler.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "../../../C/7zCrc.h" -#include "../../../C/Alloc.h" -#include "../../../C/LzmaDec.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/AutoPtr.h" -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/StringConvert.h" - -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/LzhDecoder.h" - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) -#define Get24(p) (Get32(p) & 0xFFFFFF) - -namespace NArchive { -namespace NUefi { - -static const size_t kBufTotalSizeMax = 1 << 29; -static const unsigned kNumFilesMax = 1 << 18; -static const unsigned kLevelMax = 64; - -static const Byte k_IntelMeSignature[] = -{ - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x5A, 0xA5, 0xF0, 0x0F -}; - -static bool IsIntelMe(const Byte *p) -{ - return memcmp(p, k_IntelMeSignature, sizeof(k_IntelMeSignature)) == 0; -} - -static const unsigned kFvHeaderSize = 0x38; - -static const unsigned kGuidSize = 16; - -#define CAPSULE_SIGNATURE 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 -#define CAPSULE2_SIGNATURE 0x8B,0xA6,0x3C,0x4A,0x23,0x77,0xFB,0x48,0x80,0x3D,0x57,0x8C,0xC1,0xFE,0xC4,0x4D -#define CAPSULE_UEFI_SIGNATURE 0xB9,0x82,0x91,0x53,0xB5,0xAB,0x91,0x43,0xB6,0x9A,0xE3,0xA9,0x43,0xF7,0x2F,0xCC -/* - 6dcbd5ed-e82d-4c44-bda1-7194199ad92a : Firmware Management ` -*/ - -static const Byte k_Guids_Capsules[][kGuidSize] = -{ - { CAPSULE_SIGNATURE }, - { CAPSULE2_SIGNATURE }, - { CAPSULE_UEFI_SIGNATURE } -}; - - -static const unsigned kFfsGuidOffset = 16; - -#define FFS1_SIGNATURE 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF -#define FFS2_SIGNATURE 0x78,0xE5,0x8C,0x8C,0x3D,0x8A,0x1C,0x4F,0x99,0x35,0x89,0x61,0x85,0xC3,0x2D,0xD3 -#define MACFS_SIGNATURE 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A -// APPLE_BOOT -/* - "FFS3": "5473c07a-3dcb-4dca-bd6f-1e9689e7349a", - "NVRAM_EVSA": "fff12b8d-7696-4c8b-a985-2747075b4f50", - "NVRAM_NVAR": "cef5b9a3-476d-497f-9fdc-e98143e0422c", - "NVRAM_EVSA2": "00504624-8a59-4eeb-bd0f-6b36e96128e0", -static const Byte k_NVRAM_NVAR_Guid[kGuidSize] = - { 0xA3,0xB9,0xF5,0xCE,0x6D,0x47,0x7F,0x49,0x9F,0xDC,0xE9,0x81,0x43,0xE0,0x42,0x2C }; -*/ - -static const Byte k_Guids_FS[][kGuidSize] = -{ - { FFS1_SIGNATURE }, - { FFS2_SIGNATURE }, - { MACFS_SIGNATURE } -}; - - -static const UInt32 kFvSignature = 0x4856465F; // "_FVH" - -static const Byte kGuids[][kGuidSize] = -{ - { 0xB0,0xCD,0x1B,0xFC,0x31,0x7D,0xAA,0x49,0x93,0x6A,0xA4,0x60,0x0D,0x9D,0xD0,0x83 }, - { 0x2E,0x06,0xA0,0x1B,0x79,0xC7,0x82,0x45,0x85,0x66,0x33,0x6A,0xE8,0xF7,0x8F,0x09 }, - { 0x25,0x4E,0x37,0x7E,0x01,0x8E,0xEE,0x4F,0x87,0xf2,0x39,0x0C,0x23,0xC6,0x06,0xCD }, - { 0x97,0xE5,0x1B,0x16,0xC5,0xE9,0xDB,0x49,0xAE,0x50,0xC4,0x62,0xAB,0x54,0xEE,0xDA }, - { 0xDB,0x7F,0xAD,0x77,0x2A,0xDF,0x02,0x43,0x88,0x98,0xC7,0x2E,0x4C,0xDB,0xD0,0xF4 }, - { 0xAB,0x71,0xCF,0xF5,0x4B,0xB0,0x7E,0x4B,0x98,0x8A,0xD8,0xA0,0xD4,0x98,0xE6,0x92 }, - { 0x91,0x45,0x53,0x7A,0xCE,0x37,0x81,0x48,0xB3,0xC9,0x71,0x38,0x14,0xF4,0x5D,0x6B }, - { 0x84,0xE6,0x7A,0x36,0x5D,0x33,0x71,0x46,0xA1,0x6D,0x89,0x9D,0xBF,0xEA,0x6B,0x88 }, - { 0x98,0x07,0x40,0x24,0x07,0x38,0x42,0x4A,0xB4,0x13,0xA1,0xEC,0xEE,0x20,0x5D,0xD8 }, - { 0xEE,0xA2,0x3F,0x28,0x2C,0x53,0x4D,0x48,0x93,0x83,0x9F,0x93,0xB3,0x6F,0x0B,0x7E }, - { 0x9B,0xD5,0xB8,0x98,0xBA,0xE8,0xEE,0x48,0x98,0xDD,0xC2,0x95,0x39,0x2F,0x1E,0xDB }, - { 0x09,0x6D,0xE3,0xC3,0x94,0x82,0x97,0x4B,0xA8,0x57,0xD5,0x28,0x8F,0xE3,0x3E,0x28 }, - { 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 } -}; - -static const Byte k_Guid_LZMA_COMPRESSED[kGuidSize] = - { 0x98,0x58,0x4E,0xEE,0x14,0x39,0x59,0x42,0x9D,0x6E,0xDC,0x7B,0xD7,0x94,0x03,0xCF }; - -static const char * const kGuidNames[] = -{ - "CRC" - , "VolumeTopFile" - , "ACPI" - , "ACPI2" - , "Main" - , "Intel32" - , "Intel64" - , "Intel32c" - , "Intel64c" - , "MacVolume" - , "MacUpdate.txt" - , "MacName" - , "Insyde" -}; - -enum -{ - kGuidIndex_CRC = 0 -}; - -struct CSigExtPair -{ - const char *ext; - unsigned sigSize; - Byte sig[16]; -}; - -static const CSigExtPair g_Sigs[] = -{ - { "bmp", 2, { 'B','M' } }, - { "riff", 4, { 'R','I','F','F' } }, - { "pe", 2, { 'M','Z'} }, - { "gif", 6, { 'G','I','F','8','9', 'a' } }, - { "png", 8, { 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A } }, - { "jpg", 10, { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46 } }, - { "rom", 2, { 0x55,0xAA } } -}; - -enum -{ - kSig_BMP, - kSig_RIFF, - kSig_PE -}; - -static const char *FindExt(const Byte *p, size_t size) -{ - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(g_Sigs); i++) - { - const CSigExtPair &pair = g_Sigs[i]; - if (size >= pair.sigSize) - if (memcmp(p, pair.sig, pair.sigSize) == 0) - break; - } - if (i == Z7_ARRAY_SIZE(g_Sigs)) - return NULL; - switch (i) - { - case kSig_BMP: - if (GetUi32(p + 2) > size || GetUi32(p + 0xA) > size) - return NULL; - break; - case kSig_RIFF: - if (GetUi32(p + 8) == 0x45564157 || GetUi32(p + 0xC) == 0x20746D66 ) - return "wav"; - break; - case kSig_PE: - { - if (size < 512) - return NULL; - UInt32 peOffset = GetUi32(p + 0x3C); - if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) - return NULL; - if (GetUi32(p + peOffset) != 0x00004550) - return NULL; - break; - } - } - return g_Sigs[i].ext; -} - -static bool AreGuidsEq(const Byte *p1, const Byte *p2) -{ - return memcmp(p1, p2, kGuidSize) == 0; -} - -static int FindGuid(const Byte *p) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kGuids); i++) - if (AreGuidsEq(p, kGuids[i])) - return (int)i; - return -1; -} - -static bool IsFfs(const Byte *p) -{ - if (Get32(p + 0x28) != kFvSignature) - return false; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Guids_FS); i++) - if (AreGuidsEq(p + kFfsGuidOffset, k_Guids_FS[i])) - return true; - return false; -} - -#define FVB_ERASE_POLARITY (1 << 11) - -/* -static const CUInt32PCharPair g_FV_Attribs[] = -{ - { 0, "ReadDisabledCap" }, - { 1, "ReadEnabledCap" }, - { 2, "ReadEnabled" }, - { 3, "WriteDisabledCap" }, - { 4, "WriteEnabledCap" }, - { 5, "WriteEnabled" }, - { 6, "LockCap" }, - { 7, "Locked" }, - - { 9, "StickyWrite" }, - { 10, "MemoryMapped" }, - { 11, "ErasePolarity" }, - - { 12, "ReadLockCap" }, - { 13, "WriteLockCap" }, - { 14, "WriteLockCap" } -}; -*/ - -enum -{ - FV_FILETYPE_ALL, - FV_FILETYPE_RAW, - FV_FILETYPE_FREEFORM, - FV_FILETYPE_SECURITY_CORE, - FV_FILETYPE_PEI_CORE, - FV_FILETYPE_DXE_CORE, - FV_FILETYPE_PEIM, - FV_FILETYPE_DRIVER, - FV_FILETYPE_COMBINED_PEIM_DRIVER, - FV_FILETYPE_APPLICATION, - // The value 0x0A is reserved and should not be used - FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B, - // types 0xF0 - 0xFF are FFS file types - FV_FILETYPE_FFS_PAD = 0xF0 -}; - -static const char * const g_FileTypes[] = -{ - "ALL" - , "RAW" - , "FREEFORM" - , "SECURITY_CORE" - , "PEI_CORE" - , "DXE_CORE" - , "PEIM" - , "DRIVER" - , "COMBINED_PEIM_DRIVER" - , "APPLICATION" - , "0xA" - , "VOLUME" -}; - -// typedef Byte FFS_FILE_ATTRIBUTES; -// FFS File Attributes -#define FFS_ATTRIB_TAIL_PRESENT 0x01 -// #define FFS_ATTRIB_RECOVERY 0x02 -// #define FFS_ATTRIB_HEADER_EXTENSION 0x04 -// #define FFS_ATTRIB_DATA_ALIGNMENT 0x38 -#define FFS_ATTRIB_CHECKSUM 0x40 - -static const CUInt32PCharPair g_FFS_FILE_ATTRIBUTES[] = -{ - { 0, "" /* "TAIL" */ }, - { 1, "RECOVERY" }, - // { 2, "HEADER_EXTENSION" }, // reserved for future - { 6, "" /* "CHECKSUM" */ } -}; - -// static const Byte g_Allignment[8] = { 3, 4, 7, 9, 10, 12, 15, 16 }; - -// typedef Byte FFS_FILE_STATE; - -// Look also FVB_ERASE_POLARITY. -// Lower-order State bits are superceded by higher-order State bits. - -// #define FILE_HEADER_CONSTRUCTION 0x01 -// #define FILE_HEADER_VALID 0x02 -#define FILE_DATA_VALID 0x04 -// #define FILE_MARKED_FOR_UPDATE 0x08 -// #define FILE_DELETED 0x10 -// #define FILE_HEADER_INVALID 0x20 - -// SECTION_TYPE - -// #define SECTION_ALL 0x00 - -#define SECTION_COMPRESSION 0x01 -#define SECTION_GUID_DEFINED 0x02 - -// Leaf section Type values -// #define SECTION_PE32 0x10 -// #define SECTION_PIC 0x11 -// #define SECTION_TE 0x12 -#define SECTION_DXE_DEPEX 0x13 -#define SECTION_VERSION 0x14 -#define SECTION_USER_INTERFACE 0x15 -// #define SECTION_COMPATIBILITY16 0x16 -#define SECTION_FIRMWARE_VOLUME_IMAGE 0x17 -#define SECTION_FREEFORM_SUBTYPE_GUID 0x18 -#define SECTION_RAW 0x19 -#define SECTION_PEI_DEPEX 0x1B - - -// #define GUIDED_SECTION_PROCESSING_REQUIRED 0x01 -// #define GUIDED_SECTION_AUTH_STATUS_VALID 0x02 - -static const CUInt32PCharPair g_GUIDED_SECTION_ATTRIBUTES[] = -{ - { 0, "PROCESSING_REQUIRED" }, - { 1, "AUTH" } -}; - -static const CUInt32PCharPair g_SECTION_TYPE[] = -{ - { 0x01, "COMPRESSION" }, - { 0x02, "GUID" }, - { 0x10, "efi" }, - { 0x11, "PIC" }, - { 0x12, "te" }, - { 0x13, "DXE_DEPEX" }, - { 0x14, "VERSION" }, - { 0x15, "USER_INTERFACE" }, - { 0x16, "COMPATIBILITY16" }, - { 0x17, "VOLUME" }, - { 0x18, "FREEFORM_SUBTYPE_GUID" }, - { 0x19, "raw" }, - { 0x1B, "PEI_DEPEX" } -}; - -#define COMPRESSION_TYPE_NONE 0 -#define COMPRESSION_TYPE_LZH 1 -#define COMPRESSION_TYPE_LZMA 2 - -static const char * const g_Methods[] = -{ - "COPY" - , "LZH" - , "LZMA" -}; - - -static void AddGuid(AString &dest, const Byte *p, bool full) -{ - char s[64]; - ::RawLeGuidToString(p, s); - // MyStringUpper_Ascii(s); - if (!full) - s[8] = 0; - dest += s; -} - -static const char * const kExpressionCommands[] = -{ - "BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR" -}; - -static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res) -{ - res.Empty(); - for (UInt32 i = 0; i < size;) - { - unsigned command = p[i++]; - if (command > Z7_ARRAY_SIZE(kExpressionCommands)) - return false; - res += kExpressionCommands[command]; - if (command < 3) - { - if (i + kGuidSize > size) - return false; - res.Add_Space(); - AddGuid(res, p + i, false); - i += kGuidSize; - } - res += "; "; - } - return true; -} - -static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res) -{ - if ((size & 1) != 0) - return false; - res.Empty(); - UInt32 i; - for (i = 0; i < size; i += 2) - { - wchar_t c = Get16(p + i); - if (c == 0) - break; - res += c; - } - return (i == size - 2); -} - -static bool ParseUtf16zString2(const Byte *p, UInt32 size, AString &res) -{ - UString s; - if (!ParseUtf16zString(p, size, s)) - return false; - res = UnicodeStringToMultiByte(s); - return true; -} - -#define FLAGS_TO_STRING(pairs, value) FlagsToString(pairs, Z7_ARRAY_SIZE(pairs), value) -#define TYPE_TO_STRING(table, value) TypeToString(table, Z7_ARRAY_SIZE(table), value) -#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, Z7_ARRAY_SIZE(table), value) - -static const UInt32 kFileHeaderSize = 24; - -static void AddSpaceAndString(AString &res, const AString &newString) -{ - if (!newString.IsEmpty()) - { - res.Add_Space_if_NotEmpty(); - res += newString; - } -} - -class CFfsFileHeader -{ -PRF(public:) - Byte CheckHeader; - Byte CheckFile; - Byte Attrib; - Byte State; - - UInt16 GetTailReference() const { return (UInt16)(CheckHeader | ((UInt16)CheckFile << 8)); } - UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; } - bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; } - bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; } -public: - Byte GuidName[kGuidSize]; - Byte Type; - UInt32 Size; - - bool Parse(const Byte *p) - { - unsigned i; - for (i = 0; i < kFileHeaderSize; i++) - if (p[i] != 0xFF) - break; - if (i == kFileHeaderSize) - return false; - memcpy(GuidName, p, kGuidSize); - CheckHeader = p[0x10]; - CheckFile = p[0x11]; - Type = p[0x12]; - Attrib = p[0x13]; - Size = Get24(p + 0x14); - State = p[0x17]; - return true; - } - - UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); } - UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); } - - bool Check(const Byte *p, UInt32 size) - { - if (Size > size) - return false; - UInt32 tailSize = GetTailSize(); - if (Size < kFileHeaderSize + tailSize) - return false; - - { - unsigned checkSum = 0; - for (UInt32 i = 0; i < kFileHeaderSize; i++) - checkSum += p[i]; - checkSum -= p[0x17]; - checkSum -= p[0x11]; - if ((Byte)checkSum != 0) - return false; - } - - if (IsThereFileChecksum()) - { - unsigned checkSum = 0; - UInt32 checkSize = Size - tailSize; - for (UInt32 i = 0; i < checkSize; i++) - checkSum += p[i]; - checkSum -= p[0x17]; - if ((Byte)checkSum != 0) - return false; - } - - if (IsThereTail()) - if (GetTailReference() != (UInt16)~Get16(p + Size - 2)) - return false; - - int polarity = 0; - int i; - for (i = 5; i >= 0; i--) - if (((State >> i) & 1) == polarity) - { - // AddSpaceAndString(s, g_FFS_FILE_STATE_Flags[i]); - if ((1 << i) != FILE_DATA_VALID) - return false; - break; - } - if (i < 0) - return false; - - return true; - } - - AString GetCharacts() const - { - AString s; - if (Type == FV_FILETYPE_FFS_PAD) - s += "PAD"; - else - s += TYPE_TO_STRING(g_FileTypes, Type); - AddSpaceAndString(s, FLAGS_TO_STRING(g_FFS_FILE_ATTRIBUTES, Attrib & 0xC7)); - /* - int align = (Attrib >> 3) & 7; - if (align != 0) - { - s += " Align:"; - s.Add_UInt32((UInt32)1 << g_Allignment[align]); - } - */ - return s; - } -}; - -#define G32(_offs_, dest) dest = Get32(p + (_offs_)) -#define G16(_offs_, dest) dest = Get16(p + (_offs_)) - -struct CCapsuleHeader -{ - UInt32 HeaderSize; - UInt32 Flags; - UInt32 CapsuleImageSize; - UInt32 SequenceNumber; - // Guid InstanceId; - UInt32 OffsetToSplitInformation; - UInt32 OffsetToCapsuleBody; - UInt32 OffsetToOemDefinedHeader; - UInt32 OffsetToAuthorInformation; - UInt32 OffsetToRevisionInformation; - UInt32 OffsetToShortDescription; - UInt32 OffsetToLongDescription; - UInt32 OffsetToApplicableDevices; - - void Clear() { memset(this, 0, sizeof(*this)); } - - bool Parse(const Byte *p) - { - Clear(); - G32(0x10, HeaderSize); - G32(0x14, Flags); - G32(0x18, CapsuleImageSize); - if (HeaderSize < 0x1C) - return false; - if (AreGuidsEq(p, k_Guids_Capsules[0])) - { - const unsigned kHeaderSize = 80; - if (HeaderSize != kHeaderSize) - return false; - G32(0x1C, SequenceNumber); - G32(0x30, OffsetToSplitInformation); - G32(0x34, OffsetToCapsuleBody); - G32(0x38, OffsetToOemDefinedHeader); - G32(0x3C, OffsetToAuthorInformation); - G32(0x40, OffsetToRevisionInformation); - G32(0x44, OffsetToShortDescription); - G32(0x48, OffsetToLongDescription); - G32(0x4C, OffsetToApplicableDevices); - return true; - } - else if (AreGuidsEq(p, k_Guids_Capsules[1])) - { - // capsule v2 - G16(0x1C, OffsetToCapsuleBody); - G16(0x1E, OffsetToOemDefinedHeader); - return true; - } - else if (AreGuidsEq(p, k_Guids_Capsules[2])) - { - OffsetToCapsuleBody = HeaderSize; - return true; - } - else - { - // here we must check for another capsule types - return false; - } - } -}; - - -struct CItem -{ - AString Name; - AString Characts; - int Parent; - int Method; - int NameIndex; - unsigned NumChilds; - bool IsDir; - bool Skip; - bool ThereAreSubDirs; - bool ThereIsUniqueName; - bool KeepName; - - unsigned BufIndex; - UInt32 Offset; - UInt32 Size; - - CItem(): Parent(-1), Method(-1), NameIndex(-1), NumChilds(0), - IsDir(false), Skip(false), ThereAreSubDirs(false), ThereIsUniqueName(false), KeepName(true) {} - void SetGuid(const Byte *guidName, bool full = false); - AString GetName(int numChildsInParent) const; -}; - -void CItem::SetGuid(const Byte *guidName, bool full) -{ - ThereIsUniqueName = true; - int index = FindGuid(guidName); - if (index >= 0) - Name = kGuidNames[(unsigned)index]; - else - { - Name.Empty(); - AddGuid(Name, guidName, full); - } -} - -AString CItem::GetName(int numChildsInParent) const -{ - if (numChildsInParent <= 1 || NameIndex < 0) - return Name; - char sz[32]; - char sz2[32]; - ConvertUInt32ToString((unsigned)NameIndex, sz); - ConvertUInt32ToString((unsigned)numChildsInParent - 1, sz2); - const int numZeros = (int)strlen(sz2) - (int)strlen(sz); - AString res; - for (int i = 0; i < numZeros; i++) - res += '0'; - res += sz; - res.Add_Dot(); - res += Name; - return res; -} - -struct CItem2 -{ - AString Name; - AString Characts; - unsigned MainIndex; - int Parent; - - CItem2(): Parent(-1) {} -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) - CObjectVector _items; - CObjectVector _items2; - CObjectVector _bufs; - UString _comment; - UInt32 _methodsMask; - bool _capsuleMode; - bool _headersError; - - size_t _totalBufsSize; - CCapsuleHeader _h; - UInt64 _phySize; - - void AddCommentString(const char *name, UInt32 pos); - unsigned AddItem(const CItem &item); - unsigned AddFileItemWithIndex(CItem &item); - unsigned AddDirItem(CItem &item); - unsigned AddBuf(size_t size); - - HRESULT DecodeLzma(const Byte *data, size_t inputSize); - - HRESULT ParseSections(unsigned bufIndex, UInt32 pos, - UInt32 size, - int parent, int method, unsigned level, - bool &error); - - HRESULT ParseIntelMe(unsigned bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, unsigned level); - - HRESULT ParseVolume(unsigned bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, unsigned level); - - HRESULT OpenCapsule(IInStream *stream); - HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); - HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); -public: - CHandler(bool capsuleMode): _capsuleMode(capsuleMode) {} -}; - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - // kpidOffset, - kpidMethod, - kpidCharacts -}; - -static const Byte kArcProps[] = -{ - kpidComment, - kpidMethod, - kpidCharacts -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItem2 &item2 = _items2[index]; - const CItem &item = _items[item2.MainIndex]; - switch (propID) - { - case kpidPath: - { - AString path (item2.Name); - int cur = item2.Parent; - while (cur >= 0) - { - const CItem2 &item3 = _items2[cur]; - path.InsertAtFront(CHAR_PATH_SEPARATOR); - path.Insert(0, item3.Name); - cur = item3.Parent; - } - prop = path; - break; - } - case kpidIsDir: prop = item.IsDir; break; - case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break; - case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break; - case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break; - // case kpidOffset: if (!item.IsDir) prop = item.Offset; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -void CHandler::AddCommentString(const char *name, UInt32 pos) -{ - UString s; - if (pos < _h.HeaderSize) - return; - if (pos >= _h.OffsetToCapsuleBody) - return; - UInt32 limit = (_h.OffsetToCapsuleBody - pos) & ~(UInt32)1; - const Byte *buf = _bufs[0] + pos; - for (UInt32 i = 0;;) - { - if (s.Len() > (1 << 16) || i >= limit) - return; - wchar_t c = Get16(buf + i); - i += 2; - if (c == 0) - { - if (i >= limit) - return; - c = Get16(buf + i); - i += 2; - if (c == 0) - break; - s.Add_LF(); - } - s += c; - } - if (s.IsEmpty()) - return; - _comment.Add_LF(); - _comment += name; - _comment += ": "; - _comment += s; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidMethod: - { - AString s; - for (unsigned i = 0; i < 32; i++) - if ((_methodsMask & ((UInt32)1 << i)) != 0) - AddSpaceAndString(s, (AString)g_Methods[i]); - if (!s.IsEmpty()) - prop = s; - break; - } - case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break; - case kpidPhySize: prop = (UInt64)_phySize; break; - - case kpidErrorFlags: - { - UInt32 v = 0; - if (_headersError) v |= kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -#ifdef SHOW_DEBUG_INFO -static void PrintLevel(unsigned level) -{ - PRF(printf("\n")); - for (unsigned i = 0; i < level; i++) - PRF(printf(" ")); -} -static void MyPrint(UInt32 posBase, UInt32 size, unsigned level, const char *name) -{ - PrintLevel(level); - PRF(printf("%s, pos = %6x, size = %6x", name, posBase, size)); -} -#else -#define PrintLevel(level) -#define MyPrint(posBase, size, level, name) -#endif - - - -unsigned CHandler::AddItem(const CItem &item) -{ - if (_items.Size() >= kNumFilesMax) - throw 2; - return _items.Add(item); -} - -unsigned CHandler::AddFileItemWithIndex(CItem &item) -{ - unsigned nameIndex = _items.Size(); - if (item.Parent >= 0) - nameIndex = _items[item.Parent].NumChilds++; - item.NameIndex = (int)nameIndex; - return AddItem(item); -} - -unsigned CHandler::AddDirItem(CItem &item) -{ - if (item.Parent >= 0) - _items[item.Parent].ThereAreSubDirs = true; - item.IsDir = true; - item.Size = 0; - return AddItem(item); -} - -unsigned CHandler::AddBuf(size_t size) -{ - if (size > kBufTotalSizeMax - _totalBufsSize) - throw 1; - _totalBufsSize += size; - unsigned index = _bufs.Size(); - _bufs.AddNew().Alloc(size); - return index; -} - - -HRESULT CHandler::DecodeLzma(const Byte *data, size_t inputSize) -{ - if (inputSize < 5 + 8) - return S_FALSE; - const UInt64 unpackSize = Get64(data + 5); - if (unpackSize > ((UInt32)1 << 30)) - return S_FALSE; - SizeT destLen = (SizeT)unpackSize; - const unsigned newBufIndex = AddBuf((size_t)unpackSize); - CByteBuffer &buf = _bufs[newBufIndex]; - ELzmaStatus status; - SizeT srcLen = inputSize - (5 + 8); - const SizeT srcLen2 = srcLen; - SRes res = LzmaDecode(buf, &destLen, data + 13, &srcLen, - data, 5, LZMA_FINISH_END, &status, &g_Alloc); - if (res != 0) - return S_FALSE; - if (srcLen != srcLen2 || destLen != unpackSize || ( - status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) - return S_FALSE; - return S_OK; -} - - -HRESULT CHandler::ParseSections(unsigned bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level, bool &error) -{ - error = false; - - if (level > kLevelMax) - return S_FALSE; - MyPrint(posBase, size, level, "Sections"); - level++; - const Byte *bufData = _bufs[bufIndex]; - UInt32 pos = 0; - for (;;) - { - if (size == pos) - return S_OK; - PrintLevel(level); - PRF(printf("%s, abs = %6x, relat = %6x", "Sect", posBase + pos, pos)); - pos = (pos + 3) & ~(UInt32)3; - if (pos > size) - return S_FALSE; - UInt32 rem = size - pos; - if (rem == 0) - return S_OK; - if (rem < 4) - return S_FALSE; - - const Byte *p = bufData + posBase + pos; - - const UInt32 sectSize = Get24(p); - const Byte type = p[3]; - - // PrintLevel(level); - PRF(printf(" type = %2x, sectSize = %6x", type, sectSize)); - - if (sectSize > rem || sectSize < 4) - { - _headersError = true; - error = true; - return S_OK; - // return S_FALSE; - } - - CItem item; - item.Method = method; - item.BufIndex = bufIndex; - item.Parent = parent; - item.Offset = posBase + pos + 4; - UInt32 sectDataSize = sectSize - 4; - item.Size = sectDataSize; - item.Name = TYPE_PAIR_TO_STRING(g_SECTION_TYPE, type); - - if (type == SECTION_COMPRESSION) - { - if (sectSize < 4 + 5) - return S_FALSE; - const UInt32 uncompressedSize = Get32(p + 4); - const Byte compressionType = p[8]; - - UInt32 newSectSize = sectSize - 9; - UInt32 newOffset = posBase + pos + 9; - const Byte *pStart = p + 9; - - item.KeepName = false; - if (compressionType > 2) - { - // AddFileItemWithIndex(item); - return S_FALSE; - } - else - { - item.Name = g_Methods[compressionType]; - // int parent = AddDirItem(item); - if (compressionType == COMPRESSION_TYPE_NONE) - { - bool error2; - RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level, error2)) - } - else if (compressionType == COMPRESSION_TYPE_LZH) - { - const unsigned newBufIndex = AddBuf(uncompressedSize); - CByteBuffer &buf = _bufs[newBufIndex]; - CMyUniquePtr lzhDecoder; - lzhDecoder.Create_if_Empty(); - { - const Byte *src = pStart; - if (newSectSize < 8) - return S_FALSE; - UInt32 packSize = Get32(src); - const UInt32 unpackSize = Get32(src + 4); - - PRF(printf(" LZH packSize = %6x, unpackSize = %6x", packSize, unpackSize)); - - if (uncompressedSize != unpackSize || newSectSize - 8 != packSize) - return S_FALSE; - if (packSize < 1) - return S_FALSE; - packSize--; - src += 8; - if (src[packSize] != 0) - return S_FALSE; - - CMyComPtr2_Create inStream; - CMyComPtr2_Create outStream; - // const UInt64 uncompressedSize64 = uncompressedSize; - // lzhDecoder->FinishMode = true; - /* - EFI 1.1 probably used LZH with small dictionary and (pbit = 4). It was named "Efi compression". - New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary. - But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary. - We check both LZH versions: Tiano and then Efi. - */ - HRESULT res = S_FALSE; - for (unsigned m = 0 ; m < 2; m++) - { - inStream->Init(src, packSize); - outStream->Init(buf, uncompressedSize); - lzhDecoder->SetDictSize(m == 0 ? ((UInt32)1 << 19) : ((UInt32)1 << 14)); - res = lzhDecoder->Code(inStream, outStream, uncompressedSize, NULL); - if (res == S_OK) - break; - } - RINOK(res) - } - bool error2; - RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level, error2)) - } - else - { - if (newSectSize < 4 + 5 + 8) - return S_FALSE; - unsigned addSize = 4; - if (pStart[0] == 0x5d && pStart[1] == 0 && pStart[2] == 0 && pStart[3] == 0x80 && pStart[4] == 0) - { - addSize = 0; - // some archives have such header - } - else - { - // normal BIOS contains uncompressed size here - // UInt32 uncompressedSize2 = Get24(pStart); - // Byte firstSectType = p[9 + 3]; - // firstSectType can be 0 in some archives - } - pStart += addSize; - - RINOK(DecodeLzma(pStart, newSectSize - addSize)) - const size_t lzmaUncompressedSize = _bufs.Back().Size(); - // if (lzmaUncompressedSize != uncompressedSize) - if (lzmaUncompressedSize < uncompressedSize) - return S_FALSE; - bool error2; - RINOK(ParseSections(_bufs.Size() - 1, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level, error2)) - } - _methodsMask |= (1 << compressionType); - } - } - else if (type == SECTION_GUID_DEFINED) - { - const unsigned kHeaderSize = 4 + kGuidSize + 4; - if (sectSize < kHeaderSize) - return S_FALSE; - item.SetGuid(p + 4); - const UInt32 dataOffset = Get16(p + 4 + kGuidSize); - const UInt32 attrib = Get16(p + 4 + kGuidSize + 2); - if (dataOffset > sectSize || dataOffset < kHeaderSize) - return S_FALSE; - UInt32 newSectSize = sectSize - dataOffset; - item.Size = newSectSize; - UInt32 newOffset = posBase + pos + dataOffset; - item.Offset = newOffset; - const UInt32 propsSize = dataOffset - kHeaderSize; - AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib)); - - bool needDir = true; - unsigned newBufIndex = bufIndex; - int newMethod = method; - - if (AreGuidsEq(p + 0x4, k_Guid_LZMA_COMPRESSED)) - { - // item.Name = "guid.lzma"; - // AddItem(item); - const Byte *pStart = bufData + newOffset; - // do we need correct pStart here for lzma steram offset? - RINOK(DecodeLzma(pStart, newSectSize)) - _methodsMask |= (1 << COMPRESSION_TYPE_LZMA); - newBufIndex = _bufs.Size() - 1; - newOffset = 0; - newSectSize = (UInt32)_bufs.Back().Size(); - newMethod = COMPRESSION_TYPE_LZMA; - } - else if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4) - { - needDir = false; - item.KeepName = false; - if (CrcCalc(bufData + newOffset, newSectSize) != Get32(p + kHeaderSize)) - return S_FALSE; - } - else - { - if (propsSize != 0) - { - CItem item2 = item; - item2.Name += ".prop"; - item2.Size = propsSize; - item2.Offset = posBase + pos + kHeaderSize; - AddItem(item2); - } - } - - int newParent = parent; - if (needDir) - newParent = (int)AddDirItem(item); - bool error2; - RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2)) - } - else if (type == SECTION_FIRMWARE_VOLUME_IMAGE) - { - item.KeepName = false; - const int newParent = (int)AddDirItem(item); - RINOK(ParseVolume(bufIndex, posBase + pos + 4, - sectSize - 4, - sectSize - 4, - newParent, method, level)) - } - else - { - bool needAdd = true; - switch (type) - { - case SECTION_RAW: - { - const UInt32 kInsydeOffset = 12; - if (sectDataSize >= kFvHeaderSize + kInsydeOffset) - { - if (IsFfs(p + 4 + kInsydeOffset) && - sectDataSize - kInsydeOffset == Get64(p + 4 + kInsydeOffset + 0x20)) - { - needAdd = false; - item.Name = "vol"; - const unsigned newParent = AddDirItem(item); - RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, - sectDataSize - kInsydeOffset, - sectDataSize - kInsydeOffset, - (int)newParent, method, level)) - } - - if (needAdd) - { - const char *ext = FindExt(p + 4, sectDataSize); - if (ext) - item.Name = ext; - } - } - break; - } - case SECTION_DXE_DEPEX: - case SECTION_PEI_DEPEX: - { - AString s; - if (ParseDepedencyExpression(p + 4, sectDataSize, s)) - { - if (s.Len() < (1 << 9)) - { - s.InsertAtFront('['); - s += ']'; - AddSpaceAndString(_items[item.Parent].Characts, s); - needAdd = false; - } - else - { - item.BufIndex = AddBuf(s.Len()); - CByteBuffer &buf0 = _bufs[item.BufIndex]; - if (s.Len() != 0) - memcpy(buf0, s, s.Len()); - item.Offset = 0; - item.Size = s.Len(); - } - } - break; - } - case SECTION_VERSION: - { - if (sectDataSize > 2) - { - AString s; - if (ParseUtf16zString2(p + 6, sectDataSize - 2, s)) - { - AString s2 ("ver:"); - s2.Add_UInt32(Get16(p + 4)); - s2.Add_Space(); - s2 += s; - AddSpaceAndString(_items[item.Parent].Characts, s2); - needAdd = false; - } - } - break; - } - case SECTION_USER_INTERFACE: - { - AString s; - if (ParseUtf16zString2(p + 4, sectDataSize, s)) - { - _items[parent].Name = s; - needAdd = false; - } - break; - } - case SECTION_FREEFORM_SUBTYPE_GUID: - { - if (sectDataSize >= kGuidSize) - { - item.SetGuid(p + 4); - item.Size = sectDataSize - kGuidSize; - item.Offset = posBase + pos + 4 + kGuidSize; - } - break; - } - } - - if (needAdd) - AddFileItemWithIndex(item); - } - - pos += sectSize; - } -} - -static UInt32 Count_FF_Bytes(const Byte *p, UInt32 size) -{ - UInt32 i; - for (i = 0; i < size && p[i] == 0xFF; i++); - return i; -} - -static bool Is_FF_Stream(const Byte *p, UInt32 size) -{ - return (Count_FF_Bytes(p, size) == size); -} - -struct CVolFfsHeader -{ - UInt32 HeaderLen; - UInt64 VolSize; - - bool Parse(const Byte *p); -}; - -bool CVolFfsHeader::Parse(const Byte *p) -{ - if (Get32(p + 0x28) != kFvSignature) - return false; - - UInt32 attribs = Get32(p + 0x2C); - if ((attribs & FVB_ERASE_POLARITY) == 0) - return false; - VolSize = Get64(p + 0x20); - HeaderLen = Get16(p + 0x30); - if (HeaderLen < kFvHeaderSize || (HeaderLen & 0x7) != 0 || VolSize < HeaderLen) - return false; - return true; -} - - -HRESULT CHandler::ParseVolume( - unsigned bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, unsigned level) -{ - if (level > kLevelMax) - return S_FALSE; - MyPrint(posBase, exactSize, level, "Volume"); - level++; - if (exactSize < kFvHeaderSize) - return S_FALSE; - const Byte *p = _bufs[bufIndex] + posBase; - // first 16 bytes must be zeros, but they are not zeros sometimes. - if (!IsFfs(p)) - { - CItem item; - item.Method = method; - item.BufIndex = bufIndex; - item.Parent = parent; - item.Offset = posBase; - item.Size = exactSize; - if (!Is_FF_Stream(p + kFfsGuidOffset, 16)) - item.SetGuid(p + kFfsGuidOffset); - // if (item.Name.IsEmpty()) - item.Name += "[VOL]"; - AddItem(item); - return S_OK; - } - - CVolFfsHeader ffsHeader; - if (!ffsHeader.Parse(p)) - return S_FALSE; - // if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs)); - - // VolSize > exactSize (fh.Size) for some UEFI archives (is it correct UEFI?) - // so we check VolSize for limitSize instead. - - if (ffsHeader.HeaderLen > limitSize || ffsHeader.VolSize > limitSize) - return S_FALSE; - - { - UInt32 checkCalc = 0; - for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2) - checkCalc += Get16(p + i); - if ((checkCalc & 0xFFFF) != 0) - return S_FALSE; - } - - // 3 reserved bytes are not zeros sometimes. - // UInt16 ExtHeaderOffset; // in new SPECIFICATION? - // Byte revision = p[0x37]; - - UInt32 pos = kFvHeaderSize; - for (;;) - { - if (pos >= ffsHeader.HeaderLen) - return S_FALSE; - UInt32 numBlocks = Get32(p + pos); - UInt32 length = Get32(p + pos + 4); - pos += 8; - if (numBlocks == 0 && length == 0) - break; - } - if (pos != ffsHeader.HeaderLen) - return S_FALSE; - - CRecordVector guidsVector; - - for (;;) - { - UInt32 rem = (UInt32)ffsHeader.VolSize - pos; - if (rem < kFileHeaderSize) - break; - pos = (pos + 7) & ~7u; - rem = (UInt32)ffsHeader.VolSize - pos; - if (rem < kFileHeaderSize) - break; - - CItem item; - item.Method = method; - item.BufIndex = bufIndex; - item.Parent = parent; - - const Byte *pFile = p + pos; - CFfsFileHeader fh; - if (!fh.Parse(pFile)) - { - UInt32 num_FF_bytes = Count_FF_Bytes(pFile, rem); - if (num_FF_bytes != rem) - { - item.Name = "[junk]"; - item.Offset = posBase + pos + num_FF_bytes; - item.Size = rem - num_FF_bytes; - AddItem(item); - } - PrintLevel(level); PRF(printf("== FF FF reminder")); - - break; - } - - PrintLevel(level); PRF(printf("%s, type = %3d, pos = %7x, size = %7x", "FILE", fh.Type, posBase + pos, fh.Size)); - - if (!fh.Check(pFile, rem)) - return S_FALSE; - - UInt32 offset = posBase + pos + kFileHeaderSize; - UInt32 sectSize = fh.GetDataSize(); - item.Offset = offset; - item.Size = sectSize; - - pos += fh.Size; - - if (fh.Type == FV_FILETYPE_FFS_PAD) - if (Is_FF_Stream(pFile + kFileHeaderSize, sectSize)) - continue; - - UInt32 guid32 = Get32(fh.GuidName); - bool full = true; - if (guidsVector.FindInSorted(guid32) < 0) - { - guidsVector.AddToUniqueSorted(guid32); - full = false; - } - item.SetGuid(fh.GuidName, full); - - item.Characts = fh.GetCharacts(); - // PrintLevel(level); - PRF(printf(" : %s", item.Characts)); - - { - PRF(printf(" attrib = %2d State = %3d ", (unsigned)fh.Attrib, (unsigned)fh.State)); - PRF(char s[64]); - PRF(RawLeGuidToString(fh.GuidName, s)); - PRF(printf(" : %s ", s)); - } - - if (fh.Type == FV_FILETYPE_FFS_PAD || - fh.Type == FV_FILETYPE_RAW) - { - bool isVolume = false; - if (fh.Type == FV_FILETYPE_RAW) - { - if (sectSize >= kFvHeaderSize) - if (IsFfs(pFile + kFileHeaderSize)) - isVolume = true; - } - if (isVolume) - { - const unsigned newParent = AddDirItem(item); - const UInt32 limSize = fh.GetDataSize2(rem); - // volume.VolSize > fh.Size for some UEFI archives (is it correct UEFI?) - // so we will check VolSize for limitSize instead. - RINOK(ParseVolume(bufIndex, offset, sectSize, limSize, (int)newParent, method, level)) - } - else - AddItem(item); - } - else - { - /* - if (fh.Type == FV_FILETYPE_FREEFORM) - { - // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections) - // AddItem(item); - } - else - */ - { - const unsigned newParent = AddDirItem(item); - bool error2; - RINOK(ParseSections(bufIndex, offset, sectSize, (int)newParent, method, level + 1, error2)) - if (error2) - { - // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections) - item.IsDir = false; - item.Size = sectSize; - item.Name.Insert(0, "[ERROR]"); - AddItem(item); - } - } - } - } - - return S_OK; -} - - -static const char * const kRegionName[] = -{ - "Descriptor" - , "BIOS" - , "ME" - , "GbE" - , "PDR" - , "Region5" - , "Region6" - , "Region7" -}; - - -HRESULT CHandler::ParseIntelMe( - unsigned bufIndex, UInt32 posBase, - UInt32 exactSize, UInt32 limitSize, - int parent, int method, unsigned /* level */) -{ - UNUSED_VAR(limitSize) - // level++; - - const Byte *p = _bufs[bufIndex] + posBase; - if (exactSize < 16 + 16) - return S_FALSE; - if (!IsIntelMe(p)) - return S_FALSE; - - UInt32 v0 = GetUi32(p + 20); - // UInt32 numRegions = (v0 >> 24) & 0x7; - UInt32 regAddr = (v0 >> 12) & 0xFF0; - // UInt32 numComps = (v0 >> 8) & 0x3; - // UInt32 fcba = (v0 << 4) & 0xFF0; - - // (numRegions == 0) in header in some new images. - // So we don't use the value from header - UInt32 numRegions = 7; - - for (unsigned i = 0; i <= numRegions; i++) - { - UInt32 offset = regAddr + i * 4; - if (offset + 4 > exactSize) - break; - UInt32 val = GetUi32(p + offset); - - // only 12 bits probably are OK. - // How does it work for files larger than 16 MB? - const UInt32 kMask = 0xFFF; - // const UInt32 kMask = 0xFFFF; // 16-bit is more logical - const UInt32 lim = (val >> 16) & kMask; - const UInt32 base = (val & kMask); - - /* - strange combinations: - PDR: base = 0x1FFF lim = 0; - empty: base = 0xFFFF lim = 0xFFFF; - - PDR: base = 0x7FFF lim = 0; - empty: base = 0x7FFF lim = 0; - */ - if (base == kMask && lim == 0) - continue; // unused - - if (lim < base) - continue; // unused - - CItem item; - item.Name = kRegionName[i]; - item.Method = method; - item.BufIndex = bufIndex; - item.Parent = parent; - item.Offset = posBase + (base << 12); - if (item.Offset > exactSize) - continue; - item.Size = (lim + 1 - base) << 12; - // item.SetGuid(p + kFfsGuidOffset); - // item.Name += " [VOLUME]"; - AddItem(item); - } - return S_OK; -} - - -HRESULT CHandler::OpenCapsule(IInStream *stream) -{ - const unsigned kHeaderSize = 80; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) - if (!_h.Parse(buf)) - return S_FALSE; - if (_h.CapsuleImageSize < kHeaderSize - || _h.CapsuleImageSize < _h.HeaderSize - || _h.OffsetToCapsuleBody < _h.HeaderSize - || _h.OffsetToCapsuleBody > _h.CapsuleImageSize - || _h.CapsuleImageSize > (1u << 30) // to reduce false detection - || _h.HeaderSize > (1u << 28) // to reduce false detection - ) - return S_FALSE; - _phySize = _h.CapsuleImageSize; - - if (_h.SequenceNumber != 0 || - _h.OffsetToSplitInformation != 0 ) - return E_NOTIMPL; - - const unsigned bufIndex = AddBuf(_h.CapsuleImageSize); - CByteBuffer &buf0 = _bufs[bufIndex]; - memcpy(buf0, buf, kHeaderSize); - ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize); - - AddCommentString("Author", _h.OffsetToAuthorInformation); - AddCommentString("Revision", _h.OffsetToRevisionInformation); - AddCommentString("Short Description", _h.OffsetToShortDescription); - AddCommentString("Long Description", _h.OffsetToLongDescription); - - - const UInt32 size = _h.CapsuleImageSize - _h.OffsetToCapsuleBody; - - if (size >= 32 && IsIntelMe(buf0 + _h.OffsetToCapsuleBody)) - return ParseIntelMe(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0); - - return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0); -} - - -HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */) -{ - Byte buf[kFvHeaderSize]; - RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize)) - if (!IsFfs(buf)) - return S_FALSE; - CVolFfsHeader ffsHeader; - if (!ffsHeader.Parse(buf)) - return S_FALSE; - if (ffsHeader.VolSize > ((UInt32)1 << 30)) - return S_FALSE; - _phySize = ffsHeader.VolSize; - RINOK(InStream_SeekToBegin(stream)) - UInt32 fvSize32 = (UInt32)ffsHeader.VolSize; - unsigned bufIndex = AddBuf(fvSize32); - RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32)) - return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0); -} - - -HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) -{ - if (_capsuleMode) - { - RINOK(OpenCapsule(stream)) - } - else - { - RINOK(OpenFv(stream, maxCheckStartPosition, callback)) - } - - const unsigned num = _items.Size(); - CIntArr numChilds(num); - - unsigned i; - - for (i = 0; i < num; i++) - numChilds[i] = 0; - - for (i = 0; i < num; i++) - { - const int parent = _items[i].Parent; - if (parent >= 0) - numChilds[(unsigned)parent]++; - } - - for (i = 0; i < num; i++) - { - const CItem &item = _items[i]; - const int parent = item.Parent; - if (parent >= 0) - { - CItem &parentItem = _items[(unsigned)parent]; - if (numChilds[(unsigned)parent] == 1) - if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs) - parentItem.Skip = true; - } - } - - CUIntVector mainToReduced; - - for (i = 0; i < _items.Size(); i++) - { - mainToReduced.Add(_items2.Size()); - const CItem &item = _items[i]; - if (item.Skip) - continue; - AString name; - int numItems = -1; - int parent = item.Parent; - if (parent >= 0) - numItems = numChilds[(unsigned)parent]; - AString name2 (item.GetName(numItems)); - AString characts2 (item.Characts); - if (item.KeepName) - name = name2; - - while (parent >= 0) - { - const CItem &item3 = _items[(unsigned)parent]; - if (!item3.Skip) - break; - if (item3.KeepName) - { - AString name3 (item3.GetName(-1)); - if (name.IsEmpty()) - name = name3; - else - name = name3 + '.' + name; - } - AddSpaceAndString(characts2, item3.Characts); - parent = item3.Parent; - } - - if (name.IsEmpty()) - name = name2; - - CItem2 item2; - item2.MainIndex = i; - item2.Name = name; - item2.Characts = characts2; - if (parent >= 0) - item2.Parent = (int)mainToReduced[(unsigned)parent]; - _items2.Add(item2); - /* - CItem2 item2; - item2.MainIndex = i; - item2.Name = item.Name; - item2.Parent = item.Parent; - _items2.Add(item2); - */ - } - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - { - HRESULT res = Open2(inStream, maxCheckStartPosition, callback); - if (res == E_NOTIMPL) - res = S_FALSE; - return res; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - _totalBufsSize = 0; - _methodsMask = 0; - _items.Clear(); - _items2.Clear(); - _bufs.Clear(); - _comment.Empty(); - _headersError = false; - _h.Clear(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items2.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items2.Size(); - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[_items2[allFilesMode ? i : indices[i]].MainIndex].Size; - RINOK(extractCallback->SetTotal(totalSize)) - totalSize = 0; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CMyComPtr2_Create copyCoder; - - for (i = 0;; i++) - { - lps->InSize = lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CItem &item = _items[_items2[index].MainIndex]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - totalSize += item.Size; - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - if (testMode || item.IsDir) - opRes = NExtract::NOperationResult::kOK; - else - { - opRes = NExtract::NOperationResult::kDataError; - CMyComPtr inStream; - GetStream(index, &inStream); - if (inStream) - { - RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) - if (copyCoder->TotalSize == item.Size) - opRes = NExtract::NOperationResult::kOK; - } - } - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - const CItem &item = _items[_items2[index].MainIndex]; - if (item.IsDir) - return S_FALSE; - CBufInStream *streamSpec = new CBufInStream; - CMyComPtr streamTemp = streamSpec; - const CByteBuffer &buf = _bufs[item.BufIndex]; - if (item.Offset > buf.Size()) - return S_FALSE; - size_t size = buf.Size() - item.Offset; - if (size > item.Size) - size = item.Size; - streamSpec->Init(buf + item.Offset, size, (IInArchive *)this); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - -namespace UEFIc { - -static const Byte k_Capsule_Signatures[] = -{ - 16, CAPSULE_SIGNATURE, - 16, CAPSULE2_SIGNATURE, - 16, CAPSULE_UEFI_SIGNATURE -}; - -REGISTER_ARC_I_CLS( - CHandler(true), - "UEFIc", "scap", NULL, 0xD0, - k_Capsule_Signatures, - 0, - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kFindSignature, - NULL) - -} - -namespace UEFIf { - -static const Byte k_FFS_Signatures[] = -{ - 16, FFS1_SIGNATURE, - 16, FFS2_SIGNATURE -}; - - -REGISTER_ARC_I_CLS( - CHandler(false), - "UEFIf", "uefif", NULL, 0xD1, - k_FFS_Signatures, - kFfsGuidOffset, - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kFindSignature, - NULL) - -} - -}} +// UefiHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "../../../C/7zCrc.h" +#include "../../../C/Alloc.h" +#include "../../../C/LzmaDec.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/AutoPtr.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringConvert.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/LzhDecoder.h" + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) +#define Get24(p) (Get32(p) & 0xFFFFFF) + +namespace NArchive { +namespace NUefi { + +static const size_t kBufTotalSizeMax = 1 << 29; +static const unsigned kNumFilesMax = 1 << 18; +static const unsigned kLevelMax = 64; + +static const Byte k_IntelMeSignature[] = +{ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x5A, 0xA5, 0xF0, 0x0F +}; + +static bool IsIntelMe(const Byte *p) +{ + return memcmp(p, k_IntelMeSignature, sizeof(k_IntelMeSignature)) == 0; +} + +static const unsigned kFvHeaderSize = 0x38; + +static const unsigned kGuidSize = 16; + +#define CAPSULE_SIGNATURE 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0 +#define CAPSULE2_SIGNATURE 0x8B,0xA6,0x3C,0x4A,0x23,0x77,0xFB,0x48,0x80,0x3D,0x57,0x8C,0xC1,0xFE,0xC4,0x4D +#define CAPSULE_UEFI_SIGNATURE 0xB9,0x82,0x91,0x53,0xB5,0xAB,0x91,0x43,0xB6,0x9A,0xE3,0xA9,0x43,0xF7,0x2F,0xCC +/* + 6dcbd5ed-e82d-4c44-bda1-7194199ad92a : Firmware Management ` +*/ + +static const Byte k_Guids_Capsules[][kGuidSize] = +{ + { CAPSULE_SIGNATURE }, + { CAPSULE2_SIGNATURE }, + { CAPSULE_UEFI_SIGNATURE } +}; + + +static const unsigned kFfsGuidOffset = 16; + +#define FFS1_SIGNATURE 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF +#define FFS2_SIGNATURE 0x78,0xE5,0x8C,0x8C,0x3D,0x8A,0x1C,0x4F,0x99,0x35,0x89,0x61,0x85,0xC3,0x2D,0xD3 +#define MACFS_SIGNATURE 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A +// APPLE_BOOT +/* + "FFS3": "5473c07a-3dcb-4dca-bd6f-1e9689e7349a", + "NVRAM_EVSA": "fff12b8d-7696-4c8b-a985-2747075b4f50", + "NVRAM_NVAR": "cef5b9a3-476d-497f-9fdc-e98143e0422c", + "NVRAM_EVSA2": "00504624-8a59-4eeb-bd0f-6b36e96128e0", +static const Byte k_NVRAM_NVAR_Guid[kGuidSize] = + { 0xA3,0xB9,0xF5,0xCE,0x6D,0x47,0x7F,0x49,0x9F,0xDC,0xE9,0x81,0x43,0xE0,0x42,0x2C }; +*/ + +static const Byte k_Guids_FS[][kGuidSize] = +{ + { FFS1_SIGNATURE }, + { FFS2_SIGNATURE }, + { MACFS_SIGNATURE } +}; + + +static const UInt32 kFvSignature = 0x4856465F; // "_FVH" + +static const Byte kGuids[][kGuidSize] = +{ + { 0xB0,0xCD,0x1B,0xFC,0x31,0x7D,0xAA,0x49,0x93,0x6A,0xA4,0x60,0x0D,0x9D,0xD0,0x83 }, + { 0x2E,0x06,0xA0,0x1B,0x79,0xC7,0x82,0x45,0x85,0x66,0x33,0x6A,0xE8,0xF7,0x8F,0x09 }, + { 0x25,0x4E,0x37,0x7E,0x01,0x8E,0xEE,0x4F,0x87,0xf2,0x39,0x0C,0x23,0xC6,0x06,0xCD }, + { 0x97,0xE5,0x1B,0x16,0xC5,0xE9,0xDB,0x49,0xAE,0x50,0xC4,0x62,0xAB,0x54,0xEE,0xDA }, + { 0xDB,0x7F,0xAD,0x77,0x2A,0xDF,0x02,0x43,0x88,0x98,0xC7,0x2E,0x4C,0xDB,0xD0,0xF4 }, + { 0xAB,0x71,0xCF,0xF5,0x4B,0xB0,0x7E,0x4B,0x98,0x8A,0xD8,0xA0,0xD4,0x98,0xE6,0x92 }, + { 0x91,0x45,0x53,0x7A,0xCE,0x37,0x81,0x48,0xB3,0xC9,0x71,0x38,0x14,0xF4,0x5D,0x6B }, + { 0x84,0xE6,0x7A,0x36,0x5D,0x33,0x71,0x46,0xA1,0x6D,0x89,0x9D,0xBF,0xEA,0x6B,0x88 }, + { 0x98,0x07,0x40,0x24,0x07,0x38,0x42,0x4A,0xB4,0x13,0xA1,0xEC,0xEE,0x20,0x5D,0xD8 }, + { 0xEE,0xA2,0x3F,0x28,0x2C,0x53,0x4D,0x48,0x93,0x83,0x9F,0x93,0xB3,0x6F,0x0B,0x7E }, + { 0x9B,0xD5,0xB8,0x98,0xBA,0xE8,0xEE,0x48,0x98,0xDD,0xC2,0x95,0x39,0x2F,0x1E,0xDB }, + { 0x09,0x6D,0xE3,0xC3,0x94,0x82,0x97,0x4B,0xA8,0x57,0xD5,0x28,0x8F,0xE3,0x3E,0x28 }, + { 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 } +}; + +static const Byte k_Guid_LZMA_COMPRESSED[kGuidSize] = + { 0x98,0x58,0x4E,0xEE,0x14,0x39,0x59,0x42,0x9D,0x6E,0xDC,0x7B,0xD7,0x94,0x03,0xCF }; + +static const char * const kGuidNames[] = +{ + "CRC" + , "VolumeTopFile" + , "ACPI" + , "ACPI2" + , "Main" + , "Intel32" + , "Intel64" + , "Intel32c" + , "Intel64c" + , "MacVolume" + , "MacUpdate.txt" + , "MacName" + , "Insyde" +}; + +enum +{ + kGuidIndex_CRC = 0 +}; + +struct CSigExtPair +{ + const char *ext; + unsigned sigSize; + Byte sig[16]; +}; + +static const CSigExtPair g_Sigs[] = +{ + { "bmp", 2, { 'B','M' } }, + { "riff", 4, { 'R','I','F','F' } }, + { "pe", 2, { 'M','Z'} }, + { "gif", 6, { 'G','I','F','8','9', 'a' } }, + { "png", 8, { 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A } }, + { "jpg", 10, { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46 } }, + { "rom", 2, { 0x55,0xAA } } +}; + +enum +{ + kSig_BMP, + kSig_RIFF, + kSig_PE +}; + +static const char *FindExt(const Byte *p, size_t size) +{ + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(g_Sigs); i++) + { + const CSigExtPair &pair = g_Sigs[i]; + if (size >= pair.sigSize) + if (memcmp(p, pair.sig, pair.sigSize) == 0) + break; + } + if (i == Z7_ARRAY_SIZE(g_Sigs)) + return NULL; + switch (i) + { + case kSig_BMP: + if (GetUi32(p + 2) > size || GetUi32(p + 0xA) > size) + return NULL; + break; + case kSig_RIFF: + if (GetUi32(p + 8) == 0x45564157 || GetUi32(p + 0xC) == 0x20746D66 ) + return "wav"; + break; + case kSig_PE: + { + if (size < 512) + return NULL; + UInt32 peOffset = GetUi32(p + 0x3C); + if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) + return NULL; + if (GetUi32(p + peOffset) != 0x00004550) + return NULL; + break; + } + } + return g_Sigs[i].ext; +} + +static bool AreGuidsEq(const Byte *p1, const Byte *p2) +{ + return memcmp(p1, p2, kGuidSize) == 0; +} + +static int FindGuid(const Byte *p) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kGuids); i++) + if (AreGuidsEq(p, kGuids[i])) + return (int)i; + return -1; +} + +static bool IsFfs(const Byte *p) +{ + if (Get32(p + 0x28) != kFvSignature) + return false; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Guids_FS); i++) + if (AreGuidsEq(p + kFfsGuidOffset, k_Guids_FS[i])) + return true; + return false; +} + +#define FVB_ERASE_POLARITY (1 << 11) + +/* +static const CUInt32PCharPair g_FV_Attribs[] = +{ + { 0, "ReadDisabledCap" }, + { 1, "ReadEnabledCap" }, + { 2, "ReadEnabled" }, + { 3, "WriteDisabledCap" }, + { 4, "WriteEnabledCap" }, + { 5, "WriteEnabled" }, + { 6, "LockCap" }, + { 7, "Locked" }, + + { 9, "StickyWrite" }, + { 10, "MemoryMapped" }, + { 11, "ErasePolarity" }, + + { 12, "ReadLockCap" }, + { 13, "WriteLockCap" }, + { 14, "WriteLockCap" } +}; +*/ + +enum +{ + FV_FILETYPE_ALL, + FV_FILETYPE_RAW, + FV_FILETYPE_FREEFORM, + FV_FILETYPE_SECURITY_CORE, + FV_FILETYPE_PEI_CORE, + FV_FILETYPE_DXE_CORE, + FV_FILETYPE_PEIM, + FV_FILETYPE_DRIVER, + FV_FILETYPE_COMBINED_PEIM_DRIVER, + FV_FILETYPE_APPLICATION, + // The value 0x0A is reserved and should not be used + FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B, + // types 0xF0 - 0xFF are FFS file types + FV_FILETYPE_FFS_PAD = 0xF0 +}; + +static const char * const g_FileTypes[] = +{ + "ALL" + , "RAW" + , "FREEFORM" + , "SECURITY_CORE" + , "PEI_CORE" + , "DXE_CORE" + , "PEIM" + , "DRIVER" + , "COMBINED_PEIM_DRIVER" + , "APPLICATION" + , "0xA" + , "VOLUME" +}; + +// typedef Byte FFS_FILE_ATTRIBUTES; +// FFS File Attributes +#define FFS_ATTRIB_TAIL_PRESENT 0x01 +// #define FFS_ATTRIB_RECOVERY 0x02 +// #define FFS_ATTRIB_HEADER_EXTENSION 0x04 +// #define FFS_ATTRIB_DATA_ALIGNMENT 0x38 +#define FFS_ATTRIB_CHECKSUM 0x40 + +static const CUInt32PCharPair g_FFS_FILE_ATTRIBUTES[] = +{ + { 0, "" /* "TAIL" */ }, + { 1, "RECOVERY" }, + // { 2, "HEADER_EXTENSION" }, // reserved for future + { 6, "" /* "CHECKSUM" */ } +}; + +// static const Byte g_Allignment[8] = { 3, 4, 7, 9, 10, 12, 15, 16 }; + +// typedef Byte FFS_FILE_STATE; + +// Look also FVB_ERASE_POLARITY. +// Lower-order State bits are superceded by higher-order State bits. + +// #define FILE_HEADER_CONSTRUCTION 0x01 +// #define FILE_HEADER_VALID 0x02 +#define FILE_DATA_VALID 0x04 +// #define FILE_MARKED_FOR_UPDATE 0x08 +// #define FILE_DELETED 0x10 +// #define FILE_HEADER_INVALID 0x20 + +// SECTION_TYPE + +// #define SECTION_ALL 0x00 + +#define SECTION_COMPRESSION 0x01 +#define SECTION_GUID_DEFINED 0x02 + +// Leaf section Type values +// #define SECTION_PE32 0x10 +// #define SECTION_PIC 0x11 +// #define SECTION_TE 0x12 +#define SECTION_DXE_DEPEX 0x13 +#define SECTION_VERSION 0x14 +#define SECTION_USER_INTERFACE 0x15 +// #define SECTION_COMPATIBILITY16 0x16 +#define SECTION_FIRMWARE_VOLUME_IMAGE 0x17 +#define SECTION_FREEFORM_SUBTYPE_GUID 0x18 +#define SECTION_RAW 0x19 +#define SECTION_PEI_DEPEX 0x1B + + +// #define GUIDED_SECTION_PROCESSING_REQUIRED 0x01 +// #define GUIDED_SECTION_AUTH_STATUS_VALID 0x02 + +static const CUInt32PCharPair g_GUIDED_SECTION_ATTRIBUTES[] = +{ + { 0, "PROCESSING_REQUIRED" }, + { 1, "AUTH" } +}; + +static const CUInt32PCharPair g_SECTION_TYPE[] = +{ + { 0x01, "COMPRESSION" }, + { 0x02, "GUID" }, + { 0x10, "efi" }, + { 0x11, "PIC" }, + { 0x12, "te" }, + { 0x13, "DXE_DEPEX" }, + { 0x14, "VERSION" }, + { 0x15, "USER_INTERFACE" }, + { 0x16, "COMPATIBILITY16" }, + { 0x17, "VOLUME" }, + { 0x18, "FREEFORM_SUBTYPE_GUID" }, + { 0x19, "raw" }, + { 0x1B, "PEI_DEPEX" } +}; + +#define COMPRESSION_TYPE_NONE 0 +#define COMPRESSION_TYPE_LZH 1 +#define COMPRESSION_TYPE_LZMA 2 + +static const char * const g_Methods[] = +{ + "COPY" + , "LZH" + , "LZMA" +}; + + +static void AddGuid(AString &dest, const Byte *p, bool full) +{ + char s[64]; + ::RawLeGuidToString(p, s); + // MyStringUpper_Ascii(s); + if (!full) + s[8] = 0; + dest += s; +} + +static const char * const kExpressionCommands[] = +{ + "BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR" +}; + +static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res) +{ + res.Empty(); + for (UInt32 i = 0; i < size;) + { + unsigned command = p[i++]; + if (command > Z7_ARRAY_SIZE(kExpressionCommands)) + return false; + res += kExpressionCommands[command]; + if (command < 3) + { + if (i + kGuidSize > size) + return false; + res.Add_Space(); + AddGuid(res, p + i, false); + i += kGuidSize; + } + res += "; "; + } + return true; +} + +static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res) +{ + if ((size & 1) != 0) + return false; + res.Empty(); + UInt32 i; + for (i = 0; i < size; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + break; + res += c; + } + return (i == size - 2); +} + +static bool ParseUtf16zString2(const Byte *p, UInt32 size, AString &res) +{ + UString s; + if (!ParseUtf16zString(p, size, s)) + return false; + res = UnicodeStringToMultiByte(s); + return true; +} + +#define FLAGS_TO_STRING(pairs, value) FlagsToString(pairs, Z7_ARRAY_SIZE(pairs), value) +#define TYPE_TO_STRING(table, value) TypeToString(table, Z7_ARRAY_SIZE(table), value) +#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, Z7_ARRAY_SIZE(table), value) + +static const UInt32 kFileHeaderSize = 24; + +static void AddSpaceAndString(AString &res, const AString &newString) +{ + if (!newString.IsEmpty()) + { + res.Add_Space_if_NotEmpty(); + res += newString; + } +} + +class CFfsFileHeader +{ +PRF(public:) + Byte CheckHeader; + Byte CheckFile; + Byte Attrib; + Byte State; + + UInt16 GetTailReference() const { return (UInt16)(CheckHeader | ((UInt16)CheckFile << 8)); } + UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; } + bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; } + bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; } +public: + Byte GuidName[kGuidSize]; + Byte Type; + UInt32 Size; + + bool Parse(const Byte *p) + { + unsigned i; + for (i = 0; i < kFileHeaderSize; i++) + if (p[i] != 0xFF) + break; + if (i == kFileHeaderSize) + return false; + memcpy(GuidName, p, kGuidSize); + CheckHeader = p[0x10]; + CheckFile = p[0x11]; + Type = p[0x12]; + Attrib = p[0x13]; + Size = Get24(p + 0x14); + State = p[0x17]; + return true; + } + + UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); } + UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); } + + bool Check(const Byte *p, UInt32 size) + { + if (Size > size) + return false; + UInt32 tailSize = GetTailSize(); + if (Size < kFileHeaderSize + tailSize) + return false; + + { + unsigned checkSum = 0; + for (UInt32 i = 0; i < kFileHeaderSize; i++) + checkSum += p[i]; + checkSum -= p[0x17]; + checkSum -= p[0x11]; + if ((Byte)checkSum != 0) + return false; + } + + if (IsThereFileChecksum()) + { + unsigned checkSum = 0; + UInt32 checkSize = Size - tailSize; + for (UInt32 i = 0; i < checkSize; i++) + checkSum += p[i]; + checkSum -= p[0x17]; + if ((Byte)checkSum != 0) + return false; + } + + if (IsThereTail()) + if (GetTailReference() != (UInt16)~Get16(p + Size - 2)) + return false; + + int polarity = 0; + int i; + for (i = 5; i >= 0; i--) + if (((State >> i) & 1) == polarity) + { + // AddSpaceAndString(s, g_FFS_FILE_STATE_Flags[i]); + if ((1 << i) != FILE_DATA_VALID) + return false; + break; + } + if (i < 0) + return false; + + return true; + } + + AString GetCharacts() const + { + AString s; + if (Type == FV_FILETYPE_FFS_PAD) + s += "PAD"; + else + s += TYPE_TO_STRING(g_FileTypes, Type); + AddSpaceAndString(s, FLAGS_TO_STRING(g_FFS_FILE_ATTRIBUTES, Attrib & 0xC7)); + /* + int align = (Attrib >> 3) & 7; + if (align != 0) + { + s += " Align:"; + s.Add_UInt32((UInt32)1 << g_Allignment[align]); + } + */ + return s; + } +}; + +#define G32(_offs_, dest) dest = Get32(p + (_offs_)) +#define G16(_offs_, dest) dest = Get16(p + (_offs_)) + +struct CCapsuleHeader +{ + UInt32 HeaderSize; + UInt32 Flags; + UInt32 CapsuleImageSize; + UInt32 SequenceNumber; + // Guid InstanceId; + UInt32 OffsetToSplitInformation; + UInt32 OffsetToCapsuleBody; + UInt32 OffsetToOemDefinedHeader; + UInt32 OffsetToAuthorInformation; + UInt32 OffsetToRevisionInformation; + UInt32 OffsetToShortDescription; + UInt32 OffsetToLongDescription; + UInt32 OffsetToApplicableDevices; + + void Clear() { memset(this, 0, sizeof(*this)); } + + bool Parse(const Byte *p) + { + Clear(); + G32(0x10, HeaderSize); + G32(0x14, Flags); + G32(0x18, CapsuleImageSize); + if (HeaderSize < 0x1C) + return false; + if (AreGuidsEq(p, k_Guids_Capsules[0])) + { + const unsigned kHeaderSize = 80; + if (HeaderSize != kHeaderSize) + return false; + G32(0x1C, SequenceNumber); + G32(0x30, OffsetToSplitInformation); + G32(0x34, OffsetToCapsuleBody); + G32(0x38, OffsetToOemDefinedHeader); + G32(0x3C, OffsetToAuthorInformation); + G32(0x40, OffsetToRevisionInformation); + G32(0x44, OffsetToShortDescription); + G32(0x48, OffsetToLongDescription); + G32(0x4C, OffsetToApplicableDevices); + return true; + } + else if (AreGuidsEq(p, k_Guids_Capsules[1])) + { + // capsule v2 + G16(0x1C, OffsetToCapsuleBody); + G16(0x1E, OffsetToOemDefinedHeader); + return true; + } + else if (AreGuidsEq(p, k_Guids_Capsules[2])) + { + OffsetToCapsuleBody = HeaderSize; + return true; + } + else + { + // here we must check for another capsule types + return false; + } + } +}; + + +struct CItem +{ + AString Name; + AString Characts; + int Parent; + int Method; + int NameIndex; + unsigned NumChilds; + bool IsDir; + bool Skip; + bool ThereAreSubDirs; + bool ThereIsUniqueName; + bool KeepName; + + unsigned BufIndex; + UInt32 Offset; + UInt32 Size; + + CItem(): Parent(-1), Method(-1), NameIndex(-1), NumChilds(0), + IsDir(false), Skip(false), ThereAreSubDirs(false), ThereIsUniqueName(false), KeepName(true) {} + void SetGuid(const Byte *guidName, bool full = false); + AString GetName(int numChildsInParent) const; +}; + +void CItem::SetGuid(const Byte *guidName, bool full) +{ + ThereIsUniqueName = true; + int index = FindGuid(guidName); + if (index >= 0) + Name = kGuidNames[(unsigned)index]; + else + { + Name.Empty(); + AddGuid(Name, guidName, full); + } +} + +AString CItem::GetName(int numChildsInParent) const +{ + if (numChildsInParent <= 1 || NameIndex < 0) + return Name; + char sz[32]; + char sz2[32]; + ConvertUInt32ToString((unsigned)NameIndex, sz); + ConvertUInt32ToString((unsigned)numChildsInParent - 1, sz2); + const int numZeros = (int)strlen(sz2) - (int)strlen(sz); + AString res; + for (int i = 0; i < numZeros; i++) + res += '0'; + res += sz; + res.Add_Dot(); + res += Name; + return res; +} + +struct CItem2 +{ + AString Name; + AString Characts; + unsigned MainIndex; + int Parent; + + CItem2(): Parent(-1) {} +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) + CObjectVector _items; + CObjectVector _items2; + CObjectVector _bufs; + UString _comment; + UInt32 _methodsMask; + bool _capsuleMode; + bool _headersError; + + size_t _totalBufsSize; + CCapsuleHeader _h; + UInt64 _phySize; + + void AddCommentString(const char *name, UInt32 pos); + unsigned AddItem(const CItem &item); + unsigned AddFileItemWithIndex(CItem &item); + unsigned AddDirItem(CItem &item); + unsigned AddBuf(size_t size); + + HRESULT DecodeLzma(const Byte *data, size_t inputSize); + + HRESULT ParseSections(unsigned bufIndex, UInt32 pos, + UInt32 size, + int parent, int method, unsigned level, + bool &error); + + HRESULT ParseIntelMe(unsigned bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, unsigned level); + + HRESULT ParseVolume(unsigned bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, unsigned level); + + HRESULT OpenCapsule(IInStream *stream); + HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); + HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback); +public: + CHandler(bool capsuleMode): _capsuleMode(capsuleMode) {} +}; + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + // kpidOffset, + kpidMethod, + kpidCharacts +}; + +static const Byte kArcProps[] = +{ + kpidComment, + kpidMethod, + kpidCharacts +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItem2 &item2 = _items2[index]; + const CItem &item = _items[item2.MainIndex]; + switch (propID) + { + case kpidPath: + { + AString path (item2.Name); + int cur = item2.Parent; + while (cur >= 0) + { + const CItem2 &item3 = _items2[cur]; + path.InsertAtFront(CHAR_PATH_SEPARATOR); + path.Insert(0, item3.Name); + cur = item3.Parent; + } + prop = path; + break; + } + case kpidIsDir: prop = item.IsDir; break; + case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break; + case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break; + case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break; + // case kpidOffset: if (!item.IsDir) prop = item.Offset; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +void CHandler::AddCommentString(const char *name, UInt32 pos) +{ + UString s; + if (pos < _h.HeaderSize) + return; + if (pos >= _h.OffsetToCapsuleBody) + return; + UInt32 limit = (_h.OffsetToCapsuleBody - pos) & ~(UInt32)1; + const Byte *buf = _bufs[0] + pos; + for (UInt32 i = 0;;) + { + if (s.Len() > (1 << 16) || i >= limit) + return; + wchar_t c = Get16(buf + i); + i += 2; + if (c == 0) + { + if (i >= limit) + return; + c = Get16(buf + i); + i += 2; + if (c == 0) + break; + s.Add_LF(); + } + s += c; + } + if (s.IsEmpty()) + return; + _comment.Add_LF(); + _comment += name; + _comment += ": "; + _comment += s; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidMethod: + { + AString s; + for (unsigned i = 0; i < 32; i++) + if ((_methodsMask & ((UInt32)1 << i)) != 0) + AddSpaceAndString(s, (AString)g_Methods[i]); + if (!s.IsEmpty()) + prop = s; + break; + } + case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break; + case kpidPhySize: prop = (UInt64)_phySize; break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (_headersError) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +#ifdef SHOW_DEBUG_INFO +static void PrintLevel(unsigned level) +{ + PRF(printf("\n")); + for (unsigned i = 0; i < level; i++) + PRF(printf(" ")); +} +static void MyPrint(UInt32 posBase, UInt32 size, unsigned level, const char *name) +{ + PrintLevel(level); + PRF(printf("%s, pos = %6x, size = %6x", name, posBase, size)); +} +#else +#define PrintLevel(level) +#define MyPrint(posBase, size, level, name) +#endif + + + +unsigned CHandler::AddItem(const CItem &item) +{ + if (_items.Size() >= kNumFilesMax) + throw 2; + return _items.Add(item); +} + +unsigned CHandler::AddFileItemWithIndex(CItem &item) +{ + unsigned nameIndex = _items.Size(); + if (item.Parent >= 0) + nameIndex = _items[item.Parent].NumChilds++; + item.NameIndex = (int)nameIndex; + return AddItem(item); +} + +unsigned CHandler::AddDirItem(CItem &item) +{ + if (item.Parent >= 0) + _items[item.Parent].ThereAreSubDirs = true; + item.IsDir = true; + item.Size = 0; + return AddItem(item); +} + +unsigned CHandler::AddBuf(size_t size) +{ + if (size > kBufTotalSizeMax - _totalBufsSize) + throw 1; + _totalBufsSize += size; + unsigned index = _bufs.Size(); + _bufs.AddNew().Alloc(size); + return index; +} + + +HRESULT CHandler::DecodeLzma(const Byte *data, size_t inputSize) +{ + if (inputSize < 5 + 8) + return S_FALSE; + const UInt64 unpackSize = Get64(data + 5); + if (unpackSize > ((UInt32)1 << 30)) + return S_FALSE; + SizeT destLen = (SizeT)unpackSize; + const unsigned newBufIndex = AddBuf((size_t)unpackSize); + CByteBuffer &buf = _bufs[newBufIndex]; + ELzmaStatus status; + SizeT srcLen = inputSize - (5 + 8); + const SizeT srcLen2 = srcLen; + SRes res = LzmaDecode(buf, &destLen, data + 13, &srcLen, + data, 5, LZMA_FINISH_END, &status, &g_Alloc); + if (res != 0) + return S_FALSE; + if (srcLen != srcLen2 || destLen != unpackSize || ( + status != LZMA_STATUS_FINISHED_WITH_MARK && + status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + return S_FALSE; + return S_OK; +} + + +HRESULT CHandler::ParseSections(unsigned bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level, bool &error) +{ + error = false; + + if (level > kLevelMax) + return S_FALSE; + MyPrint(posBase, size, level, "Sections"); + level++; + const Byte *bufData = _bufs[bufIndex]; + UInt32 pos = 0; + for (;;) + { + if (size == pos) + return S_OK; + PrintLevel(level); + PRF(printf("%s, abs = %6x, relat = %6x", "Sect", posBase + pos, pos)); + pos = (pos + 3) & ~(UInt32)3; + if (pos > size) + return S_FALSE; + UInt32 rem = size - pos; + if (rem == 0) + return S_OK; + if (rem < 4) + return S_FALSE; + + const Byte *p = bufData + posBase + pos; + + const UInt32 sectSize = Get24(p); + const Byte type = p[3]; + + // PrintLevel(level); + PRF(printf(" type = %2x, sectSize = %6x", type, sectSize)); + + if (sectSize > rem || sectSize < 4) + { + _headersError = true; + error = true; + return S_OK; + // return S_FALSE; + } + + CItem item; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + item.Offset = posBase + pos + 4; + UInt32 sectDataSize = sectSize - 4; + item.Size = sectDataSize; + item.Name = TYPE_PAIR_TO_STRING(g_SECTION_TYPE, type); + + if (type == SECTION_COMPRESSION) + { + if (sectSize < 4 + 5) + return S_FALSE; + const UInt32 uncompressedSize = Get32(p + 4); + const Byte compressionType = p[8]; + + UInt32 newSectSize = sectSize - 9; + UInt32 newOffset = posBase + pos + 9; + const Byte *pStart = p + 9; + + item.KeepName = false; + if (compressionType > 2) + { + // AddFileItemWithIndex(item); + return S_FALSE; + } + else + { + item.Name = g_Methods[compressionType]; + // int parent = AddDirItem(item); + if (compressionType == COMPRESSION_TYPE_NONE) + { + bool error2; + RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level, error2)) + } + else if (compressionType == COMPRESSION_TYPE_LZH) + { + const unsigned newBufIndex = AddBuf(uncompressedSize); + CByteBuffer &buf = _bufs[newBufIndex]; + CMyUniquePtr lzhDecoder; + lzhDecoder.Create_if_Empty(); + { + const Byte *src = pStart; + if (newSectSize < 8) + return S_FALSE; + UInt32 packSize = Get32(src); + const UInt32 unpackSize = Get32(src + 4); + + PRF(printf(" LZH packSize = %6x, unpackSize = %6x", packSize, unpackSize)); + + if (uncompressedSize != unpackSize || newSectSize - 8 != packSize) + return S_FALSE; + if (packSize < 1) + return S_FALSE; + packSize--; + src += 8; + if (src[packSize] != 0) + return S_FALSE; + + CMyComPtr2_Create inStream; + CMyComPtr2_Create outStream; + // const UInt64 uncompressedSize64 = uncompressedSize; + // lzhDecoder->FinishMode = true; + /* + EFI 1.1 probably used LZH with small dictionary and (pbit = 4). It was named "Efi compression". + New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary. + But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary. + We check both LZH versions: Tiano and then Efi. + */ + HRESULT res = S_FALSE; + for (unsigned m = 0 ; m < 2; m++) + { + inStream->Init(src, packSize); + outStream->Init(buf, uncompressedSize); + lzhDecoder->SetDictSize(m == 0 ? ((UInt32)1 << 19) : ((UInt32)1 << 14)); + res = lzhDecoder->Code(inStream, outStream, uncompressedSize, NULL); + if (res == S_OK) + break; + } + RINOK(res) + } + bool error2; + RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level, error2)) + } + else + { + if (newSectSize < 4 + 5 + 8) + return S_FALSE; + unsigned addSize = 4; + if (pStart[0] == 0x5d && pStart[1] == 0 && pStart[2] == 0 && pStart[3] == 0x80 && pStart[4] == 0) + { + addSize = 0; + // some archives have such header + } + else + { + // normal BIOS contains uncompressed size here + // UInt32 uncompressedSize2 = Get24(pStart); + // Byte firstSectType = p[9 + 3]; + // firstSectType can be 0 in some archives + } + pStart += addSize; + + RINOK(DecodeLzma(pStart, newSectSize - addSize)) + const size_t lzmaUncompressedSize = _bufs.Back().Size(); + // if (lzmaUncompressedSize != uncompressedSize) + if (lzmaUncompressedSize < uncompressedSize) + return S_FALSE; + bool error2; + RINOK(ParseSections(_bufs.Size() - 1, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level, error2)) + } + _methodsMask |= (1 << compressionType); + } + } + else if (type == SECTION_GUID_DEFINED) + { + const unsigned kHeaderSize = 4 + kGuidSize + 4; + if (sectSize < kHeaderSize) + return S_FALSE; + item.SetGuid(p + 4); + const UInt32 dataOffset = Get16(p + 4 + kGuidSize); + const UInt32 attrib = Get16(p + 4 + kGuidSize + 2); + if (dataOffset > sectSize || dataOffset < kHeaderSize) + return S_FALSE; + UInt32 newSectSize = sectSize - dataOffset; + item.Size = newSectSize; + UInt32 newOffset = posBase + pos + dataOffset; + item.Offset = newOffset; + const UInt32 propsSize = dataOffset - kHeaderSize; + AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib)); + + bool needDir = true; + unsigned newBufIndex = bufIndex; + int newMethod = method; + + if (AreGuidsEq(p + 0x4, k_Guid_LZMA_COMPRESSED)) + { + // item.Name = "guid.lzma"; + // AddItem(item); + const Byte *pStart = bufData + newOffset; + // do we need correct pStart here for lzma steram offset? + RINOK(DecodeLzma(pStart, newSectSize)) + _methodsMask |= (1 << COMPRESSION_TYPE_LZMA); + newBufIndex = _bufs.Size() - 1; + newOffset = 0; + newSectSize = (UInt32)_bufs.Back().Size(); + newMethod = COMPRESSION_TYPE_LZMA; + } + else if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4) + { + needDir = false; + item.KeepName = false; + if (CrcCalc(bufData + newOffset, newSectSize) != Get32(p + kHeaderSize)) + return S_FALSE; + } + else + { + if (propsSize != 0) + { + CItem item2 = item; + item2.Name += ".prop"; + item2.Size = propsSize; + item2.Offset = posBase + pos + kHeaderSize; + AddItem(item2); + } + } + + int newParent = parent; + if (needDir) + newParent = (int)AddDirItem(item); + bool error2; + RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2)) + } + else if (type == SECTION_FIRMWARE_VOLUME_IMAGE) + { + item.KeepName = false; + const int newParent = (int)AddDirItem(item); + RINOK(ParseVolume(bufIndex, posBase + pos + 4, + sectSize - 4, + sectSize - 4, + newParent, method, level)) + } + else + { + bool needAdd = true; + switch (type) + { + case SECTION_RAW: + { + const UInt32 kInsydeOffset = 12; + if (sectDataSize >= kFvHeaderSize + kInsydeOffset) + { + if (IsFfs(p + 4 + kInsydeOffset) && + sectDataSize - kInsydeOffset == Get64(p + 4 + kInsydeOffset + 0x20)) + { + needAdd = false; + item.Name = "vol"; + const unsigned newParent = AddDirItem(item); + RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset, + sectDataSize - kInsydeOffset, + sectDataSize - kInsydeOffset, + (int)newParent, method, level)) + } + + if (needAdd) + { + const char *ext = FindExt(p + 4, sectDataSize); + if (ext) + item.Name = ext; + } + } + break; + } + case SECTION_DXE_DEPEX: + case SECTION_PEI_DEPEX: + { + AString s; + if (ParseDepedencyExpression(p + 4, sectDataSize, s)) + { + if (s.Len() < (1 << 9)) + { + s.InsertAtFront('['); + s += ']'; + AddSpaceAndString(_items[item.Parent].Characts, s); + needAdd = false; + } + else + { + item.BufIndex = AddBuf(s.Len()); + CByteBuffer &buf0 = _bufs[item.BufIndex]; + if (s.Len() != 0) + memcpy(buf0, s, s.Len()); + item.Offset = 0; + item.Size = s.Len(); + } + } + break; + } + case SECTION_VERSION: + { + if (sectDataSize > 2) + { + AString s; + if (ParseUtf16zString2(p + 6, sectDataSize - 2, s)) + { + AString s2 ("ver:"); + s2.Add_UInt32(Get16(p + 4)); + s2.Add_Space(); + s2 += s; + AddSpaceAndString(_items[item.Parent].Characts, s2); + needAdd = false; + } + } + break; + } + case SECTION_USER_INTERFACE: + { + AString s; + if (ParseUtf16zString2(p + 4, sectDataSize, s)) + { + _items[parent].Name = s; + needAdd = false; + } + break; + } + case SECTION_FREEFORM_SUBTYPE_GUID: + { + if (sectDataSize >= kGuidSize) + { + item.SetGuid(p + 4); + item.Size = sectDataSize - kGuidSize; + item.Offset = posBase + pos + 4 + kGuidSize; + } + break; + } + } + + if (needAdd) + AddFileItemWithIndex(item); + } + + pos += sectSize; + } +} + +static UInt32 Count_FF_Bytes(const Byte *p, UInt32 size) +{ + UInt32 i; + for (i = 0; i < size && p[i] == 0xFF; i++); + return i; +} + +static bool Is_FF_Stream(const Byte *p, UInt32 size) +{ + return (Count_FF_Bytes(p, size) == size); +} + +struct CVolFfsHeader +{ + UInt32 HeaderLen; + UInt64 VolSize; + + bool Parse(const Byte *p); +}; + +bool CVolFfsHeader::Parse(const Byte *p) +{ + if (Get32(p + 0x28) != kFvSignature) + return false; + + UInt32 attribs = Get32(p + 0x2C); + if ((attribs & FVB_ERASE_POLARITY) == 0) + return false; + VolSize = Get64(p + 0x20); + HeaderLen = Get16(p + 0x30); + if (HeaderLen < kFvHeaderSize || (HeaderLen & 0x7) != 0 || VolSize < HeaderLen) + return false; + return true; +} + + +HRESULT CHandler::ParseVolume( + unsigned bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, unsigned level) +{ + if (level > kLevelMax) + return S_FALSE; + MyPrint(posBase, exactSize, level, "Volume"); + level++; + if (exactSize < kFvHeaderSize) + return S_FALSE; + const Byte *p = _bufs[bufIndex] + posBase; + // first 16 bytes must be zeros, but they are not zeros sometimes. + if (!IsFfs(p)) + { + CItem item; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + item.Offset = posBase; + item.Size = exactSize; + if (!Is_FF_Stream(p + kFfsGuidOffset, 16)) + item.SetGuid(p + kFfsGuidOffset); + // if (item.Name.IsEmpty()) + item.Name += "[VOL]"; + AddItem(item); + return S_OK; + } + + CVolFfsHeader ffsHeader; + if (!ffsHeader.Parse(p)) + return S_FALSE; + // if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs)); + + // VolSize > exactSize (fh.Size) for some UEFI archives (is it correct UEFI?) + // so we check VolSize for limitSize instead. + + if (ffsHeader.HeaderLen > limitSize || ffsHeader.VolSize > limitSize) + return S_FALSE; + + { + UInt32 checkCalc = 0; + for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2) + checkCalc += Get16(p + i); + if ((checkCalc & 0xFFFF) != 0) + return S_FALSE; + } + + // 3 reserved bytes are not zeros sometimes. + // UInt16 ExtHeaderOffset; // in new SPECIFICATION? + // Byte revision = p[0x37]; + + UInt32 pos = kFvHeaderSize; + for (;;) + { + if (pos >= ffsHeader.HeaderLen) + return S_FALSE; + UInt32 numBlocks = Get32(p + pos); + UInt32 length = Get32(p + pos + 4); + pos += 8; + if (numBlocks == 0 && length == 0) + break; + } + if (pos != ffsHeader.HeaderLen) + return S_FALSE; + + CRecordVector guidsVector; + + for (;;) + { + UInt32 rem = (UInt32)ffsHeader.VolSize - pos; + if (rem < kFileHeaderSize) + break; + pos = (pos + 7) & ~7u; + rem = (UInt32)ffsHeader.VolSize - pos; + if (rem < kFileHeaderSize) + break; + + CItem item; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + + const Byte *pFile = p + pos; + CFfsFileHeader fh; + if (!fh.Parse(pFile)) + { + UInt32 num_FF_bytes = Count_FF_Bytes(pFile, rem); + if (num_FF_bytes != rem) + { + item.Name = "[junk]"; + item.Offset = posBase + pos + num_FF_bytes; + item.Size = rem - num_FF_bytes; + AddItem(item); + } + PrintLevel(level); PRF(printf("== FF FF reminder")); + + break; + } + + PrintLevel(level); PRF(printf("%s, type = %3d, pos = %7x, size = %7x", "FILE", fh.Type, posBase + pos, fh.Size)); + + if (!fh.Check(pFile, rem)) + return S_FALSE; + + UInt32 offset = posBase + pos + kFileHeaderSize; + UInt32 sectSize = fh.GetDataSize(); + item.Offset = offset; + item.Size = sectSize; + + pos += fh.Size; + + if (fh.Type == FV_FILETYPE_FFS_PAD) + if (Is_FF_Stream(pFile + kFileHeaderSize, sectSize)) + continue; + + UInt32 guid32 = Get32(fh.GuidName); + bool full = true; + if (guidsVector.FindInSorted(guid32) < 0) + { + guidsVector.AddToUniqueSorted(guid32); + full = false; + } + item.SetGuid(fh.GuidName, full); + + item.Characts = fh.GetCharacts(); + // PrintLevel(level); + PRF(printf(" : %s", item.Characts)); + + { + PRF(printf(" attrib = %2d State = %3d ", (unsigned)fh.Attrib, (unsigned)fh.State)); + PRF(char s[64]); + PRF(RawLeGuidToString(fh.GuidName, s)); + PRF(printf(" : %s ", s)); + } + + if (fh.Type == FV_FILETYPE_FFS_PAD || + fh.Type == FV_FILETYPE_RAW) + { + bool isVolume = false; + if (fh.Type == FV_FILETYPE_RAW) + { + if (sectSize >= kFvHeaderSize) + if (IsFfs(pFile + kFileHeaderSize)) + isVolume = true; + } + if (isVolume) + { + const unsigned newParent = AddDirItem(item); + const UInt32 limSize = fh.GetDataSize2(rem); + // volume.VolSize > fh.Size for some UEFI archives (is it correct UEFI?) + // so we will check VolSize for limitSize instead. + RINOK(ParseVolume(bufIndex, offset, sectSize, limSize, (int)newParent, method, level)) + } + else + AddItem(item); + } + else + { + /* + if (fh.Type == FV_FILETYPE_FREEFORM) + { + // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections) + // AddItem(item); + } + else + */ + { + const unsigned newParent = AddDirItem(item); + bool error2; + RINOK(ParseSections(bufIndex, offset, sectSize, (int)newParent, method, level + 1, error2)) + if (error2) + { + // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections) + item.IsDir = false; + item.Size = sectSize; + item.Name.Insert(0, "[ERROR]"); + AddItem(item); + } + } + } + } + + return S_OK; +} + + +static const char * const kRegionName[] = +{ + "Descriptor" + , "BIOS" + , "ME" + , "GbE" + , "PDR" + , "Region5" + , "Region6" + , "Region7" +}; + + +HRESULT CHandler::ParseIntelMe( + unsigned bufIndex, UInt32 posBase, + UInt32 exactSize, UInt32 limitSize, + int parent, int method, unsigned /* level */) +{ + UNUSED_VAR(limitSize) + // level++; + + const Byte *p = _bufs[bufIndex] + posBase; + if (exactSize < 16 + 16) + return S_FALSE; + if (!IsIntelMe(p)) + return S_FALSE; + + UInt32 v0 = GetUi32(p + 20); + // UInt32 numRegions = (v0 >> 24) & 0x7; + UInt32 regAddr = (v0 >> 12) & 0xFF0; + // UInt32 numComps = (v0 >> 8) & 0x3; + // UInt32 fcba = (v0 << 4) & 0xFF0; + + // (numRegions == 0) in header in some new images. + // So we don't use the value from header + UInt32 numRegions = 7; + + for (unsigned i = 0; i <= numRegions; i++) + { + UInt32 offset = regAddr + i * 4; + if (offset + 4 > exactSize) + break; + UInt32 val = GetUi32(p + offset); + + // only 12 bits probably are OK. + // How does it work for files larger than 16 MB? + const UInt32 kMask = 0xFFF; + // const UInt32 kMask = 0xFFFF; // 16-bit is more logical + const UInt32 lim = (val >> 16) & kMask; + const UInt32 base = (val & kMask); + + /* + strange combinations: + PDR: base = 0x1FFF lim = 0; + empty: base = 0xFFFF lim = 0xFFFF; + + PDR: base = 0x7FFF lim = 0; + empty: base = 0x7FFF lim = 0; + */ + if (base == kMask && lim == 0) + continue; // unused + + if (lim < base) + continue; // unused + + CItem item; + item.Name = kRegionName[i]; + item.Method = method; + item.BufIndex = bufIndex; + item.Parent = parent; + item.Offset = posBase + (base << 12); + if (item.Offset > exactSize) + continue; + item.Size = (lim + 1 - base) << 12; + // item.SetGuid(p + kFfsGuidOffset); + // item.Name += " [VOLUME]"; + AddItem(item); + } + return S_OK; +} + + +HRESULT CHandler::OpenCapsule(IInStream *stream) +{ + const unsigned kHeaderSize = 80; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) + if (!_h.Parse(buf)) + return S_FALSE; + if (_h.CapsuleImageSize < kHeaderSize + || _h.CapsuleImageSize < _h.HeaderSize + || _h.OffsetToCapsuleBody < _h.HeaderSize + || _h.OffsetToCapsuleBody > _h.CapsuleImageSize + || _h.CapsuleImageSize > (1u << 30) // to reduce false detection + || _h.HeaderSize > (1u << 28) // to reduce false detection + ) + return S_FALSE; + _phySize = _h.CapsuleImageSize; + + if (_h.SequenceNumber != 0 || + _h.OffsetToSplitInformation != 0 ) + return E_NOTIMPL; + + const unsigned bufIndex = AddBuf(_h.CapsuleImageSize); + CByteBuffer &buf0 = _bufs[bufIndex]; + memcpy(buf0, buf, kHeaderSize); + ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize); + + AddCommentString("Author", _h.OffsetToAuthorInformation); + AddCommentString("Revision", _h.OffsetToRevisionInformation); + AddCommentString("Short Description", _h.OffsetToShortDescription); + AddCommentString("Long Description", _h.OffsetToLongDescription); + + + const UInt32 size = _h.CapsuleImageSize - _h.OffsetToCapsuleBody; + + if (size >= 32 && IsIntelMe(buf0 + _h.OffsetToCapsuleBody)) + return ParseIntelMe(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0); + + return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0); +} + + +HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */) +{ + Byte buf[kFvHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize)) + if (!IsFfs(buf)) + return S_FALSE; + CVolFfsHeader ffsHeader; + if (!ffsHeader.Parse(buf)) + return S_FALSE; + if (ffsHeader.VolSize > ((UInt32)1 << 30)) + return S_FALSE; + _phySize = ffsHeader.VolSize; + RINOK(InStream_SeekToBegin(stream)) + UInt32 fvSize32 = (UInt32)ffsHeader.VolSize; + unsigned bufIndex = AddBuf(fvSize32); + RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32)) + return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0); +} + + +HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) +{ + if (_capsuleMode) + { + RINOK(OpenCapsule(stream)) + } + else + { + RINOK(OpenFv(stream, maxCheckStartPosition, callback)) + } + + const unsigned num = _items.Size(); + CIntArr numChilds(num); + + unsigned i; + + for (i = 0; i < num; i++) + numChilds[i] = 0; + + for (i = 0; i < num; i++) + { + const int parent = _items[i].Parent; + if (parent >= 0) + numChilds[(unsigned)parent]++; + } + + for (i = 0; i < num; i++) + { + const CItem &item = _items[i]; + const int parent = item.Parent; + if (parent >= 0) + { + CItem &parentItem = _items[(unsigned)parent]; + if (numChilds[(unsigned)parent] == 1) + if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs) + parentItem.Skip = true; + } + } + + CUIntVector mainToReduced; + + for (i = 0; i < _items.Size(); i++) + { + mainToReduced.Add(_items2.Size()); + const CItem &item = _items[i]; + if (item.Skip) + continue; + AString name; + int numItems = -1; + int parent = item.Parent; + if (parent >= 0) + numItems = numChilds[(unsigned)parent]; + AString name2 (item.GetName(numItems)); + AString characts2 (item.Characts); + if (item.KeepName) + name = name2; + + while (parent >= 0) + { + const CItem &item3 = _items[(unsigned)parent]; + if (!item3.Skip) + break; + if (item3.KeepName) + { + AString name3 (item3.GetName(-1)); + if (name.IsEmpty()) + name = name3; + else + name = name3 + '.' + name; + } + AddSpaceAndString(characts2, item3.Characts); + parent = item3.Parent; + } + + if (name.IsEmpty()) + name = name2; + + CItem2 item2; + item2.MainIndex = i; + item2.Name = name; + item2.Characts = characts2; + if (parent >= 0) + item2.Parent = (int)mainToReduced[(unsigned)parent]; + _items2.Add(item2); + /* + CItem2 item2; + item2.MainIndex = i; + item2.Name = item.Name; + item2.Parent = item.Parent; + _items2.Add(item2); + */ + } + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + { + HRESULT res = Open2(inStream, maxCheckStartPosition, callback); + if (res == E_NOTIMPL) + res = S_FALSE; + return res; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + _totalBufsSize = 0; + _methodsMask = 0; + _items.Clear(); + _items2.Clear(); + _bufs.Clear(); + _comment.Empty(); + _headersError = false; + _h.Clear(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items2.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items2.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[_items2[allFilesMode ? i : indices[i]].MainIndex].Size; + RINOK(extractCallback->SetTotal(totalSize)) + totalSize = 0; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CMyComPtr2_Create copyCoder; + + for (i = 0;; i++) + { + lps->InSize = lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CItem &item = _items[_items2[index].MainIndex]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + totalSize += item.Size; + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + if (testMode || item.IsDir) + opRes = NExtract::NOperationResult::kOK; + else + { + opRes = NExtract::NOperationResult::kDataError; + CMyComPtr inStream; + GetStream(index, &inStream); + if (inStream) + { + RINOK(copyCoder.Interface()->Code(inStream, realOutStream, NULL, NULL, lps)) + if (copyCoder->TotalSize == item.Size) + opRes = NExtract::NOperationResult::kOK; + } + } + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + const CItem &item = _items[_items2[index].MainIndex]; + if (item.IsDir) + return S_FALSE; + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + const CByteBuffer &buf = _bufs[item.BufIndex]; + if (item.Offset > buf.Size()) + return S_FALSE; + size_t size = buf.Size() - item.Offset; + if (size > item.Size) + size = item.Size; + streamSpec->Init(buf + item.Offset, size, (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +namespace UEFIc { + +static const Byte k_Capsule_Signatures[] = +{ + 16, CAPSULE_SIGNATURE, + 16, CAPSULE2_SIGNATURE, + 16, CAPSULE_UEFI_SIGNATURE +}; + +REGISTER_ARC_I_CLS( + CHandler(true), + "UEFIc", "scap", NULL, 0xD0, + k_Capsule_Signatures, + 0, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kFindSignature, + NULL) + +} + +namespace UEFIf { + +static const Byte k_FFS_Signatures[] = +{ + 16, FFS1_SIGNATURE, + 16, FFS2_SIGNATURE +}; + + +REGISTER_ARC_I_CLS( + CHandler(false), + "UEFIf", "uefif", NULL, 0xD1, + k_FFS_Signatures, + kFfsGuidOffset, + NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kFindSignature, + NULL) + +} + +}} diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp index 239d5d960..a5a9332b9 100644 --- a/CPP/7zip/Archive/VdiHandler.cpp +++ b/CPP/7zip/Archive/VdiHandler.cpp @@ -1,438 +1,438 @@ -// VdiHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/PropVariantUtils.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -using namespace NWindows; - -namespace NArchive { -namespace NVdi { - -static const Byte k_Signature[] = { 0x7F, 0x10, 0xDA, 0xBE }; - -static const unsigned k_ClusterBits = 20; -static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits; - - -/* -VDI_IMAGE_BLOCK_FREE = (~0) // returns any random data -VDI_IMAGE_BLOCK_ZERO = (~1) // returns zeros -*/ - -// static const UInt32 k_ClusterType_Free = 0xffffffff; -static const UInt32 k_ClusterType_Zero = 0xfffffffe; - -#define IS_CLUSTER_ALLOCATED(v) ((UInt32)(v) < k_ClusterType_Zero) - - -// static const UInt32 kDiskType_Dynamic = 1; -// static const UInt32 kDiskType_Static = 2; - -static const char * const kDiskTypes[] = -{ - "0" - , "Dynamic" - , "Static" - , "Undo" - , "Diff" -}; - - -enum EGuidType -{ - k_GuidType_Creat, - k_GuidType_Modif, - k_GuidType_Link, - k_GuidType_PModif -}; - -static const unsigned kNumGuids = 4; -static const char * const kGuidNames[kNumGuids] = -{ - "Creat " - , "Modif " - , "Link " - , "PModif" -}; - -static bool IsEmptyGuid(const Byte *data) -{ - for (unsigned i = 0; i < 16; i++) - if (data[i] != 0) - return false; - return true; -} - - - -Z7_class_CHandler_final: public CHandlerImg -{ - UInt32 _dataOffset; - CByteBuffer _table; - UInt64 _phySize; - UInt32 _imageType; - bool _isArc; - bool _unsupported; - - Byte Guids[kNumGuids][16]; - - HRESULT Seek2(UInt64 offset) - { - _posInArc = offset; - return InStream_SeekSet(Stream, offset); - } - - HRESULT InitAndSeek() - { - _virtPos = 0; - return Seek2(0); - } - - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; - -public: - Z7_IFACE_COM7_IMP(IInArchive_Img) - - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) -}; - - -Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= _size) - return S_OK; - { - UInt64 rem = _size - _virtPos; - if (size > rem) - size = (UInt32)rem; - if (size == 0) - return S_OK; - } - - { - UInt64 cluster = _virtPos >> k_ClusterBits; - UInt32 lowBits = (UInt32)_virtPos & (k_ClusterSize - 1); - { - UInt32 rem = k_ClusterSize - lowBits; - if (size > rem) - size = rem; - } - - cluster <<= 2; - if (cluster < _table.Size()) - { - const Byte *p = (const Byte *)_table + (size_t)cluster; - const UInt32 v = Get32(p); - if (IS_CLUSTER_ALLOCATED(v)) - { - UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits); - offset += lowBits; - if (offset != _posInArc) - { - RINOK(Seek2(offset)) - } - HRESULT res = Stream->Read(data, size, &size); - _posInArc += size; - _virtPos += size; - if (processedSize) - *processedSize = size; - return res; - } - } - - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } -} - - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidHeadersSize, - kpidMethod, - kpidComment, - kpidName -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - case kpidHeadersSize: prop = _dataOffset; break; - - case kpidMethod: - { - TYPE_TO_PROP(kDiskTypes, _imageType, prop); - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; - // if (_headerError) v |= kpv_ErrorFlags_HeadersError; - if (!Stream && v == 0 && _isArc) - v = kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - - case kpidComment: - { - AString s; - for (unsigned i = 0; i < kNumGuids; i++) - { - const Byte *guid = Guids[i]; - if (!IsEmptyGuid(guid)) - { - s.Add_LF(); - s += kGuidNames[i]; - s += " : "; - char temp[64]; - RawLeGuidToString_Braced(guid, temp); - MyStringLower_Ascii(temp); - s += temp; - } - } - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidName: - { - const Byte *guid = Guids[k_GuidType_Creat]; - if (!IsEmptyGuid(guid)) - { - char temp[64]; - RawLeGuidToString_Braced(guid, temp); - MyStringLower_Ascii(temp); - MyStringCat(temp, ".vdi"); - prop = temp; - } - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidSize: prop = _size; break; - case kpidPackSize: prop = _phySize - _dataOffset; break; - case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallback */) -{ - const unsigned kHeaderSize = 512; - Byte buf[kHeaderSize]; - RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) - - if (memcmp(buf + 0x40, k_Signature, sizeof(k_Signature)) != 0) - return S_FALSE; - - const UInt32 version = Get32(buf + 0x44); - if (version >= 0x20000) - return S_FALSE; - if (version < 0x10000) - { - _unsupported = true; - return S_FALSE; - } - - const unsigned kHeaderOffset = 0x48; - const unsigned kGuidsOffsets = 0x188; - const UInt32 headerSize = Get32(buf + kHeaderOffset); - if (headerSize < kGuidsOffsets - kHeaderOffset || headerSize > 0x200 - kHeaderOffset) - return S_FALSE; - - _imageType = Get32(buf + 0x4C); - // Int32 flags = Get32(buf + 0x50); - // Byte Comment[0x100] - - const UInt32 tableOffset = Get32(buf + 0x154); - if (tableOffset < 0x200) - return S_FALSE; - - _dataOffset = Get32(buf + 0x158); - - // UInt32 geometry[3]; - - const UInt32 sectorSize = Get32(buf + 0x168); - if (sectorSize != 0x200) - return S_FALSE; - - _size = Get64(buf + 0x170); - const UInt32 blockSize = Get32(buf + 0x178); - const UInt32 totalBlocks = Get32(buf + 0x180); - const UInt32 numAllocatedBlocks = Get32(buf + 0x184); - - _isArc = true; - - if (_dataOffset < tableOffset) - return S_FALSE; - - if (_imageType > 4) - _unsupported = true; - - if (blockSize != k_ClusterSize) - { - _unsupported = true; - return S_FALSE; - } - - if (headerSize >= kGuidsOffsets + kNumGuids * 16 - kHeaderOffset) - { - for (unsigned i = 0; i < kNumGuids; i++) - memcpy(Guids[i], buf + kGuidsOffsets + 16 * i, 16); - - if (!IsEmptyGuid(Guids[k_GuidType_Link]) || - !IsEmptyGuid(Guids[k_GuidType_PModif])) - _unsupported = true; - } - - { - UInt64 size2 = (UInt64)totalBlocks << k_ClusterBits; - if (size2 < _size) - { - _unsupported = true; - return S_FALSE; - } - /* - if (size2 > _size) - _size = size2; - */ - } - - { - UInt32 tableReserved = _dataOffset - tableOffset; - if ((tableReserved >> 2) < totalBlocks) - return S_FALSE; - } - - _phySize = _dataOffset + ((UInt64)numAllocatedBlocks << k_ClusterBits); - - const size_t numBytes = (size_t)totalBlocks * 4; - if ((numBytes >> 2) != totalBlocks) - { - _unsupported = true; - return E_OUTOFMEMORY; - } - - _table.Alloc(numBytes); - RINOK(InStream_SeekSet(stream, tableOffset)) - RINOK(ReadStream_FALSE(stream, _table, numBytes)) - - const Byte *data = _table; - for (UInt32 i = 0; i < totalBlocks; i++) - { - const UInt32 v = Get32(data + (size_t)i * 4); - if (!IS_CLUSTER_ALLOCATED(v)) - continue; - if (v >= numAllocatedBlocks) - { - _unsupported = true; - return S_FALSE; - } - } - - Stream = stream; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _table.Free(); - _phySize = 0; - _isArc = false; - _unsupported = false; - - for (unsigned i = 0; i < kNumGuids; i++) - memset(Guids[i], 0, 16); - - // CHandlerImg: - Clear_HandlerImg_Vars(); - Stream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - if (_unsupported) - return S_FALSE; - CMyComPtr streamTemp = this; - RINOK(InitAndSeek()) - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - -REGISTER_ARC_I( - "VDI", "vdi", NULL, 0xC9, - k_Signature, - 0x40, - 0, - NULL) - -}} +// VdiHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NVdi { + +static const Byte k_Signature[] = { 0x7F, 0x10, 0xDA, 0xBE }; + +static const unsigned k_ClusterBits = 20; +static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits; + + +/* +VDI_IMAGE_BLOCK_FREE = (~0) // returns any random data +VDI_IMAGE_BLOCK_ZERO = (~1) // returns zeros +*/ + +// static const UInt32 k_ClusterType_Free = 0xffffffff; +static const UInt32 k_ClusterType_Zero = 0xfffffffe; + +#define IS_CLUSTER_ALLOCATED(v) ((UInt32)(v) < k_ClusterType_Zero) + + +// static const UInt32 kDiskType_Dynamic = 1; +// static const UInt32 kDiskType_Static = 2; + +static const char * const kDiskTypes[] = +{ + "0" + , "Dynamic" + , "Static" + , "Undo" + , "Diff" +}; + + +enum EGuidType +{ + k_GuidType_Creat, + k_GuidType_Modif, + k_GuidType_Link, + k_GuidType_PModif +}; + +static const unsigned kNumGuids = 4; +static const char * const kGuidNames[kNumGuids] = +{ + "Creat " + , "Modif " + , "Link " + , "PModif" +}; + +static bool IsEmptyGuid(const Byte *data) +{ + for (unsigned i = 0; i < 16; i++) + if (data[i] != 0) + return false; + return true; +} + + + +Z7_class_CHandler_final: public CHandlerImg +{ + UInt32 _dataOffset; + CByteBuffer _table; + UInt64 _phySize; + UInt32 _imageType; + bool _isArc; + bool _unsupported; + + Byte Guids[kNumGuids][16]; + + HRESULT Seek2(UInt64 offset) + { + _posInArc = offset; + return InStream_SeekSet(Stream, offset); + } + + HRESULT InitAndSeek() + { + _virtPos = 0; + return Seek2(0); + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; + +public: + Z7_IFACE_COM7_IMP(IInArchive_Img) + + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) +}; + + +Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + return S_OK; + { + UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + { + UInt64 cluster = _virtPos >> k_ClusterBits; + UInt32 lowBits = (UInt32)_virtPos & (k_ClusterSize - 1); + { + UInt32 rem = k_ClusterSize - lowBits; + if (size > rem) + size = rem; + } + + cluster <<= 2; + if (cluster < _table.Size()) + { + const Byte *p = (const Byte *)_table + (size_t)cluster; + const UInt32 v = Get32(p); + if (IS_CLUSTER_ALLOCATED(v)) + { + UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits); + offset += lowBits; + if (offset != _posInArc) + { + RINOK(Seek2(offset)) + } + HRESULT res = Stream->Read(data, size, &size); + _posInArc += size; + _virtPos += size; + if (processedSize) + *processedSize = size; + return res; + } + } + + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidHeadersSize, + kpidMethod, + kpidComment, + kpidName +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidHeadersSize: prop = _dataOffset; break; + + case kpidMethod: + { + TYPE_TO_PROP(kDiskTypes, _imageType, prop); + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + // if (_headerError) v |= kpv_ErrorFlags_HeadersError; + if (!Stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + + case kpidComment: + { + AString s; + for (unsigned i = 0; i < kNumGuids; i++) + { + const Byte *guid = Guids[i]; + if (!IsEmptyGuid(guid)) + { + s.Add_LF(); + s += kGuidNames[i]; + s += " : "; + char temp[64]; + RawLeGuidToString_Braced(guid, temp); + MyStringLower_Ascii(temp); + s += temp; + } + } + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidName: + { + const Byte *guid = Guids[k_GuidType_Creat]; + if (!IsEmptyGuid(guid)) + { + char temp[64]; + RawLeGuidToString_Braced(guid, temp); + MyStringLower_Ascii(temp); + MyStringCat(temp, ".vdi"); + prop = temp; + } + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: prop = _phySize - _dataOffset; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallback */) +{ + const unsigned kHeaderSize = 512; + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)) + + if (memcmp(buf + 0x40, k_Signature, sizeof(k_Signature)) != 0) + return S_FALSE; + + const UInt32 version = Get32(buf + 0x44); + if (version >= 0x20000) + return S_FALSE; + if (version < 0x10000) + { + _unsupported = true; + return S_FALSE; + } + + const unsigned kHeaderOffset = 0x48; + const unsigned kGuidsOffsets = 0x188; + const UInt32 headerSize = Get32(buf + kHeaderOffset); + if (headerSize < kGuidsOffsets - kHeaderOffset || headerSize > 0x200 - kHeaderOffset) + return S_FALSE; + + _imageType = Get32(buf + 0x4C); + // Int32 flags = Get32(buf + 0x50); + // Byte Comment[0x100] + + const UInt32 tableOffset = Get32(buf + 0x154); + if (tableOffset < 0x200) + return S_FALSE; + + _dataOffset = Get32(buf + 0x158); + + // UInt32 geometry[3]; + + const UInt32 sectorSize = Get32(buf + 0x168); + if (sectorSize != 0x200) + return S_FALSE; + + _size = Get64(buf + 0x170); + const UInt32 blockSize = Get32(buf + 0x178); + const UInt32 totalBlocks = Get32(buf + 0x180); + const UInt32 numAllocatedBlocks = Get32(buf + 0x184); + + _isArc = true; + + if (_dataOffset < tableOffset) + return S_FALSE; + + if (_imageType > 4) + _unsupported = true; + + if (blockSize != k_ClusterSize) + { + _unsupported = true; + return S_FALSE; + } + + if (headerSize >= kGuidsOffsets + kNumGuids * 16 - kHeaderOffset) + { + for (unsigned i = 0; i < kNumGuids; i++) + memcpy(Guids[i], buf + kGuidsOffsets + 16 * i, 16); + + if (!IsEmptyGuid(Guids[k_GuidType_Link]) || + !IsEmptyGuid(Guids[k_GuidType_PModif])) + _unsupported = true; + } + + { + UInt64 size2 = (UInt64)totalBlocks << k_ClusterBits; + if (size2 < _size) + { + _unsupported = true; + return S_FALSE; + } + /* + if (size2 > _size) + _size = size2; + */ + } + + { + UInt32 tableReserved = _dataOffset - tableOffset; + if ((tableReserved >> 2) < totalBlocks) + return S_FALSE; + } + + _phySize = _dataOffset + ((UInt64)numAllocatedBlocks << k_ClusterBits); + + const size_t numBytes = (size_t)totalBlocks * 4; + if ((numBytes >> 2) != totalBlocks) + { + _unsupported = true; + return E_OUTOFMEMORY; + } + + _table.Alloc(numBytes); + RINOK(InStream_SeekSet(stream, tableOffset)) + RINOK(ReadStream_FALSE(stream, _table, numBytes)) + + const Byte *data = _table; + for (UInt32 i = 0; i < totalBlocks; i++) + { + const UInt32 v = Get32(data + (size_t)i * 4); + if (!IS_CLUSTER_ALLOCATED(v)) + continue; + if (v >= numAllocatedBlocks) + { + _unsupported = true; + return S_FALSE; + } + } + + Stream = stream; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _table.Free(); + _phySize = 0; + _isArc = false; + _unsupported = false; + + for (unsigned i = 0; i < kNumGuids; i++) + memset(Guids[i], 0, 16); + + // CHandlerImg: + Clear_HandlerImg_Vars(); + Stream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + if (_unsupported) + return S_FALSE; + CMyComPtr streamTemp = this; + RINOK(InitAndSeek()) + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "VDI", "vdi", NULL, 0xC9, + k_Signature, + 0x40, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index 11c716725..2fef079c6 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -1,966 +1,966 @@ -// VhdHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -#define G32(_offs_, dest) dest = Get32(p + (_offs_)) -#define G64(_offs_, dest) dest = Get64(p + (_offs_)) - -using namespace NWindows; - -namespace NArchive { -namespace NVhd { - -static const unsigned kSignatureSize = 10; -static const Byte kSignature[kSignatureSize] = - { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }; - -static const UInt32 kUnusedBlock = 0xFFFFFFFF; - -static const UInt32 kDiskType_Fixed = 2; -static const UInt32 kDiskType_Dynamic = 3; -static const UInt32 kDiskType_Diff = 4; - -static const char * const kDiskTypes[] = -{ - "0" - , "1" - , "Fixed" - , "Dynamic" - , "Differencing" -}; - -struct CFooter -{ - // UInt32 Features; - // UInt32 FormatVersion; - UInt64 DataOffset; - UInt32 CTime; - UInt32 CreatorApp; - UInt32 CreatorVersion; - UInt32 CreatorHostOS; - // UInt64 OriginalSize; - UInt64 CurrentSize; - UInt32 DiskGeometry; - UInt32 Type; - Byte Id[16]; - Byte SavedState; - - bool IsFixed() const { return Type == kDiskType_Fixed; } - bool ThereIsDynamic() const { return Type == kDiskType_Dynamic || Type == kDiskType_Diff; } - // bool IsSupported() const { return Type == kDiskType_Fixed || Type == kDiskType_Dynamic || Type == kDiskType_Diff; } - UInt32 NumCyls() const { return DiskGeometry >> 16; } - UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; } - UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; } - void AddTypeString(AString &s) const; - bool Parse(const Byte *p); -}; - -void CFooter::AddTypeString(AString &s) const -{ - if (Type < Z7_ARRAY_SIZE(kDiskTypes)) - s += kDiskTypes[Type]; - else - s.Add_UInt32(Type); -} - -static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset) -{ - UInt32 sum = 0; - unsigned i; - for (i = 0; i < checkSumOffset; i++) - sum += p[i]; - for (i = checkSumOffset + 4; i < size; i++) - sum += p[i]; - if (~sum != Get32(p + checkSumOffset)) - return false; - for (i = zeroOffset; i < size; i++) - if (p[i] != 0) - return false; - return true; -} - -static const unsigned kSectorSize_Log = 9; -static const unsigned kSectorSize = 1 << kSectorSize_Log; -static const unsigned kHeaderSize = 512; - -bool CFooter::Parse(const Byte *p) -{ - if (memcmp(p, kSignature, kSignatureSize) != 0) - return false; - // G32(0x08, Features); - // G32(0x0C, FormatVersion); - G64(0x10, DataOffset); - G32(0x18, CTime); - G32(0x1C, CreatorApp); - G32(0x20, CreatorVersion); - G32(0x24, CreatorHostOS); - // G64(0x28, OriginalSize); - G64(0x30, CurrentSize); - G32(0x38, DiskGeometry); - G32(0x3C, Type); - if (Type < kDiskType_Fixed || - Type > kDiskType_Diff) - return false; - memcpy(Id, p + 0x44, 16); - SavedState = p[0x54]; - // if (DataOffset > ((UInt64)1 << 62)) return false; - // if (CurrentSize > ((UInt64)1 << 62)) return false; - return CheckBlock(p, kHeaderSize, 0x40, 0x55); -} - -struct CParentLocatorEntry -{ - UInt32 Code; - UInt32 DataSpace; - UInt32 DataLen; - UInt64 DataOffset; - - bool Parse(const Byte *p) - { - G32(0x00, Code); - G32(0x04, DataSpace); - G32(0x08, DataLen); - G64(0x10, DataOffset); - return Get32(p + 0x0C) == 0; // Reserved - } -}; - -struct CDynHeader -{ - // UInt64 DataOffset; - UInt64 TableOffset; - // UInt32 HeaderVersion; - UInt32 NumBlocks; - unsigned BlockSizeLog; - UInt32 ParentTime; - Byte ParentId[16]; - bool RelativeNameWasUsed; - UString ParentName; - UString RelativeParentNameFromLocator; - CParentLocatorEntry ParentLocators[8]; - - bool Parse(const Byte *p); - UInt32 NumBitMapSectors() const - { - UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log)); - return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8); - } - void Clear() - { - RelativeNameWasUsed = false; - ParentName.Empty(); - RelativeParentNameFromLocator.Empty(); - } -}; - -bool CDynHeader::Parse(const Byte *p) -{ - if (memcmp(p, "cxsparse", 8) != 0) - return false; - // G64(0x08, DataOffset); - G64(0x10, TableOffset); - // G32(0x18, HeaderVersion); - G32(0x1C, NumBlocks); - { - UInt32 blockSize = Get32(p + 0x20); - unsigned i; - for (i = kSectorSize_Log;; i++) - { - if (i > 31) - return false; - if (((UInt32)1 << i) == blockSize) - break; - } - BlockSizeLog = i; - } - G32(0x38, ParentTime); - if (Get32(p + 0x3C) != 0) // reserved - return false; - memcpy(ParentId, p + 0x28, 16); - { - const unsigned kNameLen = 256; - wchar_t *s = ParentName.GetBuf(kNameLen); - unsigned i; - for (i = 0; i < kNameLen; i++) - { - wchar_t c = Get16(p + 0x40 + i * 2); - if (c == 0) - break; - s[i] = c; - } - s[i] = 0; - ParentName.ReleaseBuf_SetLen(i); - } - for (unsigned i = 0; i < 8; i++) - if (!ParentLocators[i].Parse(p + 0x240 + i * 24)) - return false; - return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24); -} - -Z7_class_CHandler_final: public CHandlerImg -{ - UInt64 _posInArcLimit; - UInt64 _startOffset; - UInt64 _phySize; - - CFooter Footer; - CDynHeader Dyn; - CRecordVector Bat; - CByteBuffer BitMap; - UInt32 BitMapTag; - UInt32 NumUsedBlocks; - CMyComPtr ParentStream; - CHandler *Parent; - UInt64 NumLevels; - UString _errorMessage; - // bool _unexpectedEnd; - - void AddErrorMessage(const char *message, const wchar_t *name = NULL) - { - if (!_errorMessage.IsEmpty()) - _errorMessage.Add_LF(); - _errorMessage += message; - if (name) - _errorMessage += name; - } - - void UpdatePhySize(UInt64 value) - { - if (_phySize < value) - _phySize = value; - } - - HRESULT Seek2(UInt64 offset); - HRESULT InitAndSeek(); - HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size); - - bool NeedParent() const { return Footer.Type == kDiskType_Diff; } - UInt64 GetPackSize() const - { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; } - - UString GetParentSequence() const - { - const CHandler *p = this; - UString res; - while (p && p->NeedParent()) - { - if (!res.IsEmpty()) - res += " -> "; - UString mainName; - UString anotherName; - if (Dyn.RelativeNameWasUsed) - { - mainName = p->Dyn.RelativeParentNameFromLocator; - anotherName = p->Dyn.ParentName; - } - else - { - mainName = p->Dyn.ParentName; - anotherName = p->Dyn.RelativeParentNameFromLocator; - } - res += mainName; - if (mainName != anotherName && !anotherName.IsEmpty()) - { - res.Add_Space(); - res.Add_Char('('); - res += anotherName; - res.Add_Char(')'); - } - p = p->Parent; - } - return res; - } - - bool AreParentsOK() const - { - const CHandler *p = this; - while (p->NeedParent()) - { - p = p->Parent; - if (!p) - return false; - } - return true; - } - - HRESULT Open3(); - HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level); - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override - { - return Open2(stream, NULL, openArchiveCallback, 0); - } - void CloseAtError() Z7_override; - -public: - Z7_IFACE_COM7_IMP(IInArchive_Img) - - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) -}; - -HRESULT CHandler::Seek2(UInt64 offset) { return InStream_SeekSet(Stream, _startOffset + offset); } - -HRESULT CHandler::InitAndSeek() -{ - if (ParentStream) - { - RINOK(Parent->InitAndSeek()) - } - _virtPos = _posInArc = 0; - BitMapTag = kUnusedBlock; - BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); - return Seek2(0); -} - -HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size) -{ - if (offset + size > _posInArcLimit) - return S_FALSE; - if (offset != _posInArc) - { - _posInArc = offset; - RINOK(Seek2(offset)) - } - HRESULT res = ReadStream_FALSE(Stream, data, size); - if (res == S_OK) - _posInArc += size; - else - Reset_PosInArc(); - return res; -} - -HRESULT CHandler::Open3() -{ - // Fixed archive uses only footer - - UInt64 startPos; - RINOK(InStream_GetPos(Stream, startPos)) - _startOffset = startPos; - Byte header[kHeaderSize]; - RINOK(ReadStream_FALSE(Stream, header, kHeaderSize)) - bool headerIsOK = Footer.Parse(header); - _size = Footer.CurrentSize; - - if (headerIsOK && !Footer.ThereIsDynamic()) - { - // fixed archive - if (startPos < Footer.CurrentSize) - return S_FALSE; - _posInArcLimit = Footer.CurrentSize; - _phySize = Footer.CurrentSize + kHeaderSize; - _startOffset = startPos - Footer.CurrentSize; - _posInArc = _phySize; - return S_OK; - } - - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(Stream, fileSize)) - if (fileSize < kHeaderSize) - return S_FALSE; - - const UInt32 kDynSize = 1024; - Byte buf[kDynSize]; - - RINOK(InStream_SeekSet(Stream, fileSize - kHeaderSize)) - RINOK(ReadStream_FALSE(Stream, buf, kHeaderSize)) - - if (!headerIsOK) - { - if (!Footer.Parse(buf)) - return S_FALSE; - _size = Footer.CurrentSize; - if (Footer.ThereIsDynamic()) - return S_FALSE; // we can't open Dynamic Archive backward. - // fixed archive - _posInArcLimit = Footer.CurrentSize; - _phySize = Footer.CurrentSize + kHeaderSize; - _startOffset = fileSize - kHeaderSize - Footer.CurrentSize; - _posInArc = _phySize; - return S_OK; - } - - _phySize = kHeaderSize; - _posInArc = fileSize - startPos; - _posInArcLimit = _posInArc - kHeaderSize; - - bool headerAndFooterAreEqual = false; - if (memcmp(header, buf, kHeaderSize) == 0) - { - headerAndFooterAreEqual = true; - _phySize = fileSize - _startOffset; - } - - RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize)) - if (!Dyn.Parse(buf)) - return S_FALSE; - - UpdatePhySize(Footer.DataOffset + kDynSize); - - for (int i = 0; i < 8; i++) - { - const CParentLocatorEntry &locator = Dyn.ParentLocators[i]; - const UInt32 kNameBufSizeMax = 1024; - if (locator.DataLen < kNameBufSizeMax && - locator.DataOffset < _posInArcLimit && - locator.DataOffset + locator.DataLen <= _posInArcLimit) - { - if (locator.Code == 0x57327275 && (locator.DataLen & 1) == 0) - { - // "W2ru" locator - // Path is encoded as little-endian UTF-16 - Byte nameBuf[kNameBufSizeMax]; - UString tempString; - unsigned len = (locator.DataLen >> 1); - { - wchar_t *s = tempString.GetBuf(len); - RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen)) - unsigned j; - for (j = 0; j < len; j++) - { - wchar_t c = GetUi16(nameBuf + j * 2); - if (c == 0) - break; - s[j] = c; - } - s[j] = 0; - tempString.ReleaseBuf_SetLen(j); - } - if (tempString[0] == L'.' && tempString[1] == L'\\') - tempString.DeleteFrontal(2); - Dyn.RelativeParentNameFromLocator = tempString; - } - } - if (locator.DataLen != 0) - UpdatePhySize(locator.DataOffset + locator.DataLen); - } - - if (Dyn.NumBlocks >= (UInt32)1 << 31) - return S_FALSE; - if (Footer.CurrentSize == 0) - { - if (Dyn.NumBlocks != 0) - return S_FALSE; - } - else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks) - return S_FALSE; - - Bat.ClearAndReserve(Dyn.NumBlocks); - - UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log; - - while ((UInt32)Bat.Size() < Dyn.NumBlocks) - { - RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, kSectorSize)) - UpdatePhySize(Dyn.TableOffset + kSectorSize); - for (UInt32 j = 0; j < kSectorSize; j += 4) - { - UInt32 v = Get32(buf + j); - if (v != kUnusedBlock) - { - UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; - UpdatePhySize(((UInt64)v << kSectorSize_Log) + bitmapSize + blockSize); - NumUsedBlocks++; - } - Bat.AddInReserved(v); - if ((UInt32)Bat.Size() >= Dyn.NumBlocks) - break; - } - } - - if (headerAndFooterAreEqual) - return S_OK; - - if (_startOffset + _phySize + kHeaderSize > fileSize) - { - // _unexpectedEnd = true; - _posInArcLimit = _phySize; - _phySize += kHeaderSize; - return S_OK; - } - - RINOK(ReadPhy(_phySize, buf, kHeaderSize)) - if (memcmp(header, buf, kHeaderSize) == 0) - { - _posInArcLimit = _phySize; - _phySize += kHeaderSize; - return S_OK; - } - - if (_phySize == 0x800) - { - /* WHY does empty archive contain additional empty sector? - We skip that sector and check footer again. */ - unsigned i; - for (i = 0; i < kSectorSize && buf[i] == 0; i++); - if (i == kSectorSize) - { - RINOK(ReadPhy(_phySize + kSectorSize, buf, kHeaderSize)) - if (memcmp(header, buf, kHeaderSize) == 0) - { - _phySize += kSectorSize; - _posInArcLimit = _phySize; - _phySize += kHeaderSize; - return S_OK; - } - } - } - _posInArcLimit = _phySize; - _phySize += kHeaderSize; - AddErrorMessage("Can't find footer"); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= Footer.CurrentSize) - return S_OK; - { - const UInt64 rem = Footer.CurrentSize - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - - if (Footer.IsFixed()) - { - if (_virtPos > _posInArcLimit) - return S_FALSE; - { - const UInt64 rem = _posInArcLimit - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - HRESULT res = S_OK; - if (_virtPos != _posInArc) - { - _posInArc = _virtPos; - res = Seek2(_virtPos); - } - if (res == S_OK) - { - UInt32 processedSize2 = 0; - res = Stream->Read(data, size, &processedSize2); - if (processedSize) - *processedSize = processedSize2; - _posInArc += processedSize2; - } - if (res != S_OK) - Reset_PosInArc(); - return res; - } - - const UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog); - if (blockIndex >= Bat.Size()) - return E_FAIL; // it's some unexpected case - const UInt32 blockSectIndex = Bat[blockIndex]; - const UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; - UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - size = MyMin(blockSize - offsetInBlock, size); - - HRESULT res = S_OK; - if (blockSectIndex == kUnusedBlock) - { - if (ParentStream) - { - RINOK(InStream_SeekSet(ParentStream, _virtPos)) - res = ParentStream->Read(data, size, &size); - } - else - memset(data, 0, size); - } - else - { - const UInt64 newPos = (UInt64)blockSectIndex << kSectorSize_Log; - if (BitMapTag != blockIndex) - { - RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.Size())) - BitMapTag = blockIndex; - } - RINOK(ReadPhy(newPos + BitMap.Size() + offsetInBlock, data, size)) - for (UInt32 cur = 0; cur < size;) - { - const UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur); - const UInt32 bmi = offsetInBlock >> kSectorSize_Log; - if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0) - { - if (ParentStream) - { - RINOK(InStream_SeekSet(ParentStream, _virtPos + cur)) - RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem)) - } - else - { - const Byte *p = (const Byte *)data + cur; - for (UInt32 i = 0; i < rem; i++) - if (p[i] != 0) - return S_FALSE; - } - } - offsetInBlock += rem; - cur += rem; - } - } - if (processedSize) - *processedSize = size; - _virtPos += size; - return res; -} - - -enum -{ - kpidParent = kpidUserDefined, - kpidSavedState -}; - -static const CStatProp kArcProps[] = -{ - { NULL, kpidOffset, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidClusterSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidNumVolumes, VT_UI4}, - { NULL, kpidTotalPhySize, VT_UI8}, - { "Parent", kpidParent, VT_BSTR}, - { NULL, kpidCreatorApp, VT_BSTR}, - { NULL, kpidHostOS, VT_BSTR}, - { "Saved State", kpidSavedState, VT_BOOL}, - { NULL, kpidId, VT_BSTR} - }; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, - kpidCTime - - /* - { kpidNumCyls, VT_UI4}, - { kpidNumHeads, VT_UI4}, - { kpidSectorsPerTrack, VT_UI4} - */ -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -// VHD start time: 2000-01-01 -static const UInt64 kVhdTimeStartValue = (UInt64)3600 * 24 * (399 * 365 + 24 * 4); - -static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop) -{ - FILETIME ft, utc; - UInt64 v = (kVhdTimeStartValue + vhdTime) * 10000000; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); - // specification says that it's UTC time, but Virtual PC 6 writes local time. Why? - LocalFileTimeToFileTime(&ft, &utc); - prop = utc; -} - -static void StringToAString(char *dest, UInt32 val) -{ - for (int i = 24; i >= 0; i -= 8) - { - const Byte b = (Byte)((val >> i) & 0xFF); - if (b < 0x20 || b > 0x7F) - break; - *dest++ = (char)b; - } - *dest = 0; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; - case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break; - case kpidShortComment: - case kpidMethod: - { - AString s; - Footer.AddTypeString(s); - if (NeedParent()) - { - s += " -> "; - const CHandler *p = this; - while (p && p->NeedParent()) - p = p->Parent; - if (!p) - s += '?'; - else - p->Footer.AddTypeString(s); - } - prop = s; - break; - } - case kpidCreatorApp: - { - char s[16]; - StringToAString(s, Footer.CreatorApp); - AString res (s); - res.Trim(); - res.Add_Space(); - res.Add_UInt32(Footer.CreatorVersion >> 16); - res.Add_Dot(); - res.Add_UInt32(Footer.CreatorVersion & 0xFFFF); - prop = res; - break; - } - case kpidHostOS: - { - if (Footer.CreatorHostOS == 0x5769326B) - prop = "Windows"; - else - { - char s[16]; - StringToAString(s, Footer.CreatorHostOS); - prop = s; - } - break; - } - case kpidId: - { - char s[sizeof(Footer.Id) * 2 + 2]; - ConvertDataToHex_Upper(s, Footer.Id, sizeof(Footer.Id)); - prop = s; - break; - } - case kpidSavedState: prop = Footer.SavedState ? true : false; break; - case kpidParent: if (NeedParent()) prop = GetParentSequence(); break; - case kpidOffset: prop = _startOffset; break; - case kpidPhySize: prop = _phySize; break; - case kpidTotalPhySize: - { - const CHandler *p = this; - UInt64 sum = 0; - do - { - sum += p->_phySize; - p = p->Parent; - } - while (p); - prop = sum; - break; - } - case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break; - - /* - case kpidErrorFlags: - { - UInt32 flags = 0; - if (_unexpectedEnd) - flags |= kpv_ErrorFlags_UnexpectedEndOfArc; - if (flags != 0) - prop = flags; - break; - } - */ - case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level) -{ - Close(); - Stream = stream; - if (level > (1 << 12)) // Maybe we need to increase that limit - return S_FALSE; - - RINOK(Open3()) - - NumLevels = 1; - if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0) - return S_FALSE; - if (Footer.Type != kDiskType_Diff) - return S_OK; - - bool useRelative; - UString name; - - if (!Dyn.RelativeParentNameFromLocator.IsEmpty()) - { - useRelative = true; - name = Dyn.RelativeParentNameFromLocator; - } - else - { - useRelative = false; - name = Dyn.ParentName; - } - - Dyn.RelativeNameWasUsed = useRelative; - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpenVolumeCallback, - openVolumeCallback, openArchiveCallback) - - if (openVolumeCallback) - { - CMyComPtr nextStream; - HRESULT res = openVolumeCallback->GetStream(name, &nextStream); - - if (res == S_FALSE) - { - if (useRelative && Dyn.ParentName != Dyn.RelativeParentNameFromLocator) - { - res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream); - if (res == S_OK) - Dyn.RelativeNameWasUsed = false; - } - } - - if (res != S_OK && res != S_FALSE) - return res; - - if (res == S_FALSE || !nextStream) - { - AddErrorMessage("Missing volume : ", name); - return S_OK; - } - - Parent = new CHandler; - ParentStream = Parent; - - res = Parent->Open2(nextStream, this, openArchiveCallback, level + 1); - - if (res != S_OK) - { - Parent = NULL; - ParentStream.Release(); - if (res == E_ABORT) - return res; - if (res != S_FALSE) - { - // we must show that error code - } - } - if (res == S_OK) - { - NumLevels = Parent->NumLevels + 1; - } - } - { - const CHandler *p = this; - while (p->NeedParent()) - { - p = p->Parent; - if (!p) - { - AddErrorMessage("Can't open parent VHD file : ", Dyn.ParentName); - break; - } - } - } - return S_OK; -} - - -void CHandler::CloseAtError() -{ - // CHandlerImg: - Stream.Release(); - Clear_HandlerImg_Vars(); - - _phySize = 0; - NumLevels = 0; - Bat.Clear(); - NumUsedBlocks = 0; - Parent = NULL; - ParentStream.Release(); - Dyn.Clear(); - _errorMessage.Empty(); - // _unexpectedEnd = false; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - CloseAtError(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidSize: prop = Footer.CurrentSize; break; - case kpidPackSize: prop = GetPackSize(); break; - case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; - case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; - - /* - case kpidNumCyls: prop = Footer.NumCyls(); break; - case kpidNumHeads: prop = Footer.NumHeads(); break; - case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break; - */ - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - if (Footer.IsFixed()) - { - CMyComPtr2 streamSpec; - streamSpec.Create_if_Empty(); - streamSpec->SetStream(Stream); - // fixme : check (startOffset = 0) - streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize); - RINOK(streamSpec->SeekToStart()) - *stream = streamSpec.Detach(); - return S_OK; - } - if (!Footer.ThereIsDynamic() || !AreParentsOK()) - return S_FALSE; - CMyComPtr streamTemp = this; - RINOK(InitAndSeek()) - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -REGISTER_ARC_I( - "VHD", "vhd", NULL, 0xDC, - kSignature, - 0, - NArcInfoFlags::kUseGlobalOffset, - NULL) - -}} +// VhdHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +#define G32(_offs_, dest) dest = Get32(p + (_offs_)) +#define G64(_offs_, dest) dest = Get64(p + (_offs_)) + +using namespace NWindows; + +namespace NArchive { +namespace NVhd { + +static const unsigned kSignatureSize = 10; +static const Byte kSignature[kSignatureSize] = + { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 }; + +static const UInt32 kUnusedBlock = 0xFFFFFFFF; + +static const UInt32 kDiskType_Fixed = 2; +static const UInt32 kDiskType_Dynamic = 3; +static const UInt32 kDiskType_Diff = 4; + +static const char * const kDiskTypes[] = +{ + "0" + , "1" + , "Fixed" + , "Dynamic" + , "Differencing" +}; + +struct CFooter +{ + // UInt32 Features; + // UInt32 FormatVersion; + UInt64 DataOffset; + UInt32 CTime; + UInt32 CreatorApp; + UInt32 CreatorVersion; + UInt32 CreatorHostOS; + // UInt64 OriginalSize; + UInt64 CurrentSize; + UInt32 DiskGeometry; + UInt32 Type; + Byte Id[16]; + Byte SavedState; + + bool IsFixed() const { return Type == kDiskType_Fixed; } + bool ThereIsDynamic() const { return Type == kDiskType_Dynamic || Type == kDiskType_Diff; } + // bool IsSupported() const { return Type == kDiskType_Fixed || Type == kDiskType_Dynamic || Type == kDiskType_Diff; } + UInt32 NumCyls() const { return DiskGeometry >> 16; } + UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; } + UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; } + void AddTypeString(AString &s) const; + bool Parse(const Byte *p); +}; + +void CFooter::AddTypeString(AString &s) const +{ + if (Type < Z7_ARRAY_SIZE(kDiskTypes)) + s += kDiskTypes[Type]; + else + s.Add_UInt32(Type); +} + +static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset) +{ + UInt32 sum = 0; + unsigned i; + for (i = 0; i < checkSumOffset; i++) + sum += p[i]; + for (i = checkSumOffset + 4; i < size; i++) + sum += p[i]; + if (~sum != Get32(p + checkSumOffset)) + return false; + for (i = zeroOffset; i < size; i++) + if (p[i] != 0) + return false; + return true; +} + +static const unsigned kSectorSize_Log = 9; +static const unsigned kSectorSize = 1 << kSectorSize_Log; +static const unsigned kHeaderSize = 512; + +bool CFooter::Parse(const Byte *p) +{ + if (memcmp(p, kSignature, kSignatureSize) != 0) + return false; + // G32(0x08, Features); + // G32(0x0C, FormatVersion); + G64(0x10, DataOffset); + G32(0x18, CTime); + G32(0x1C, CreatorApp); + G32(0x20, CreatorVersion); + G32(0x24, CreatorHostOS); + // G64(0x28, OriginalSize); + G64(0x30, CurrentSize); + G32(0x38, DiskGeometry); + G32(0x3C, Type); + if (Type < kDiskType_Fixed || + Type > kDiskType_Diff) + return false; + memcpy(Id, p + 0x44, 16); + SavedState = p[0x54]; + // if (DataOffset > ((UInt64)1 << 62)) return false; + // if (CurrentSize > ((UInt64)1 << 62)) return false; + return CheckBlock(p, kHeaderSize, 0x40, 0x55); +} + +struct CParentLocatorEntry +{ + UInt32 Code; + UInt32 DataSpace; + UInt32 DataLen; + UInt64 DataOffset; + + bool Parse(const Byte *p) + { + G32(0x00, Code); + G32(0x04, DataSpace); + G32(0x08, DataLen); + G64(0x10, DataOffset); + return Get32(p + 0x0C) == 0; // Reserved + } +}; + +struct CDynHeader +{ + // UInt64 DataOffset; + UInt64 TableOffset; + // UInt32 HeaderVersion; + UInt32 NumBlocks; + unsigned BlockSizeLog; + UInt32 ParentTime; + Byte ParentId[16]; + bool RelativeNameWasUsed; + UString ParentName; + UString RelativeParentNameFromLocator; + CParentLocatorEntry ParentLocators[8]; + + bool Parse(const Byte *p); + UInt32 NumBitMapSectors() const + { + UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log)); + return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8); + } + void Clear() + { + RelativeNameWasUsed = false; + ParentName.Empty(); + RelativeParentNameFromLocator.Empty(); + } +}; + +bool CDynHeader::Parse(const Byte *p) +{ + if (memcmp(p, "cxsparse", 8) != 0) + return false; + // G64(0x08, DataOffset); + G64(0x10, TableOffset); + // G32(0x18, HeaderVersion); + G32(0x1C, NumBlocks); + { + UInt32 blockSize = Get32(p + 0x20); + unsigned i; + for (i = kSectorSize_Log;; i++) + { + if (i > 31) + return false; + if (((UInt32)1 << i) == blockSize) + break; + } + BlockSizeLog = i; + } + G32(0x38, ParentTime); + if (Get32(p + 0x3C) != 0) // reserved + return false; + memcpy(ParentId, p + 0x28, 16); + { + const unsigned kNameLen = 256; + wchar_t *s = ParentName.GetBuf(kNameLen); + unsigned i; + for (i = 0; i < kNameLen; i++) + { + wchar_t c = Get16(p + 0x40 + i * 2); + if (c == 0) + break; + s[i] = c; + } + s[i] = 0; + ParentName.ReleaseBuf_SetLen(i); + } + for (unsigned i = 0; i < 8; i++) + if (!ParentLocators[i].Parse(p + 0x240 + i * 24)) + return false; + return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24); +} + +Z7_class_CHandler_final: public CHandlerImg +{ + UInt64 _posInArcLimit; + UInt64 _startOffset; + UInt64 _phySize; + + CFooter Footer; + CDynHeader Dyn; + CRecordVector Bat; + CByteBuffer BitMap; + UInt32 BitMapTag; + UInt32 NumUsedBlocks; + CMyComPtr ParentStream; + CHandler *Parent; + UInt64 NumLevels; + UString _errorMessage; + // bool _unexpectedEnd; + + void AddErrorMessage(const char *message, const wchar_t *name = NULL) + { + if (!_errorMessage.IsEmpty()) + _errorMessage.Add_LF(); + _errorMessage += message; + if (name) + _errorMessage += name; + } + + void UpdatePhySize(UInt64 value) + { + if (_phySize < value) + _phySize = value; + } + + HRESULT Seek2(UInt64 offset); + HRESULT InitAndSeek(); + HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size); + + bool NeedParent() const { return Footer.Type == kDiskType_Diff; } + UInt64 GetPackSize() const + { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; } + + UString GetParentSequence() const + { + const CHandler *p = this; + UString res; + while (p && p->NeedParent()) + { + if (!res.IsEmpty()) + res += " -> "; + UString mainName; + UString anotherName; + if (Dyn.RelativeNameWasUsed) + { + mainName = p->Dyn.RelativeParentNameFromLocator; + anotherName = p->Dyn.ParentName; + } + else + { + mainName = p->Dyn.ParentName; + anotherName = p->Dyn.RelativeParentNameFromLocator; + } + res += mainName; + if (mainName != anotherName && !anotherName.IsEmpty()) + { + res.Add_Space(); + res.Add_Char('('); + res += anotherName; + res.Add_Char(')'); + } + p = p->Parent; + } + return res; + } + + bool AreParentsOK() const + { + const CHandler *p = this; + while (p->NeedParent()) + { + p = p->Parent; + if (!p) + return false; + } + return true; + } + + HRESULT Open3(); + HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override + { + return Open2(stream, NULL, openArchiveCallback, 0); + } + void CloseAtError() Z7_override; + +public: + Z7_IFACE_COM7_IMP(IInArchive_Img) + + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) +}; + +HRESULT CHandler::Seek2(UInt64 offset) { return InStream_SeekSet(Stream, _startOffset + offset); } + +HRESULT CHandler::InitAndSeek() +{ + if (ParentStream) + { + RINOK(Parent->InitAndSeek()) + } + _virtPos = _posInArc = 0; + BitMapTag = kUnusedBlock; + BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); + return Seek2(0); +} + +HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size) +{ + if (offset + size > _posInArcLimit) + return S_FALSE; + if (offset != _posInArc) + { + _posInArc = offset; + RINOK(Seek2(offset)) + } + HRESULT res = ReadStream_FALSE(Stream, data, size); + if (res == S_OK) + _posInArc += size; + else + Reset_PosInArc(); + return res; +} + +HRESULT CHandler::Open3() +{ + // Fixed archive uses only footer + + UInt64 startPos; + RINOK(InStream_GetPos(Stream, startPos)) + _startOffset = startPos; + Byte header[kHeaderSize]; + RINOK(ReadStream_FALSE(Stream, header, kHeaderSize)) + bool headerIsOK = Footer.Parse(header); + _size = Footer.CurrentSize; + + if (headerIsOK && !Footer.ThereIsDynamic()) + { + // fixed archive + if (startPos < Footer.CurrentSize) + return S_FALSE; + _posInArcLimit = Footer.CurrentSize; + _phySize = Footer.CurrentSize + kHeaderSize; + _startOffset = startPos - Footer.CurrentSize; + _posInArc = _phySize; + return S_OK; + } + + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(Stream, fileSize)) + if (fileSize < kHeaderSize) + return S_FALSE; + + const UInt32 kDynSize = 1024; + Byte buf[kDynSize]; + + RINOK(InStream_SeekSet(Stream, fileSize - kHeaderSize)) + RINOK(ReadStream_FALSE(Stream, buf, kHeaderSize)) + + if (!headerIsOK) + { + if (!Footer.Parse(buf)) + return S_FALSE; + _size = Footer.CurrentSize; + if (Footer.ThereIsDynamic()) + return S_FALSE; // we can't open Dynamic Archive backward. + // fixed archive + _posInArcLimit = Footer.CurrentSize; + _phySize = Footer.CurrentSize + kHeaderSize; + _startOffset = fileSize - kHeaderSize - Footer.CurrentSize; + _posInArc = _phySize; + return S_OK; + } + + _phySize = kHeaderSize; + _posInArc = fileSize - startPos; + _posInArcLimit = _posInArc - kHeaderSize; + + bool headerAndFooterAreEqual = false; + if (memcmp(header, buf, kHeaderSize) == 0) + { + headerAndFooterAreEqual = true; + _phySize = fileSize - _startOffset; + } + + RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize)) + if (!Dyn.Parse(buf)) + return S_FALSE; + + UpdatePhySize(Footer.DataOffset + kDynSize); + + for (int i = 0; i < 8; i++) + { + const CParentLocatorEntry &locator = Dyn.ParentLocators[i]; + const UInt32 kNameBufSizeMax = 1024; + if (locator.DataLen < kNameBufSizeMax && + locator.DataOffset < _posInArcLimit && + locator.DataOffset + locator.DataLen <= _posInArcLimit) + { + if (locator.Code == 0x57327275 && (locator.DataLen & 1) == 0) + { + // "W2ru" locator + // Path is encoded as little-endian UTF-16 + Byte nameBuf[kNameBufSizeMax]; + UString tempString; + unsigned len = (locator.DataLen >> 1); + { + wchar_t *s = tempString.GetBuf(len); + RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen)) + unsigned j; + for (j = 0; j < len; j++) + { + wchar_t c = GetUi16(nameBuf + j * 2); + if (c == 0) + break; + s[j] = c; + } + s[j] = 0; + tempString.ReleaseBuf_SetLen(j); + } + if (tempString[0] == L'.' && tempString[1] == L'\\') + tempString.DeleteFrontal(2); + Dyn.RelativeParentNameFromLocator = tempString; + } + } + if (locator.DataLen != 0) + UpdatePhySize(locator.DataOffset + locator.DataLen); + } + + if (Dyn.NumBlocks >= (UInt32)1 << 31) + return S_FALSE; + if (Footer.CurrentSize == 0) + { + if (Dyn.NumBlocks != 0) + return S_FALSE; + } + else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks) + return S_FALSE; + + Bat.ClearAndReserve(Dyn.NumBlocks); + + UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log; + + while ((UInt32)Bat.Size() < Dyn.NumBlocks) + { + RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, kSectorSize)) + UpdatePhySize(Dyn.TableOffset + kSectorSize); + for (UInt32 j = 0; j < kSectorSize; j += 4) + { + UInt32 v = Get32(buf + j); + if (v != kUnusedBlock) + { + UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; + UpdatePhySize(((UInt64)v << kSectorSize_Log) + bitmapSize + blockSize); + NumUsedBlocks++; + } + Bat.AddInReserved(v); + if ((UInt32)Bat.Size() >= Dyn.NumBlocks) + break; + } + } + + if (headerAndFooterAreEqual) + return S_OK; + + if (_startOffset + _phySize + kHeaderSize > fileSize) + { + // _unexpectedEnd = true; + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + return S_OK; + } + + RINOK(ReadPhy(_phySize, buf, kHeaderSize)) + if (memcmp(header, buf, kHeaderSize) == 0) + { + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + return S_OK; + } + + if (_phySize == 0x800) + { + /* WHY does empty archive contain additional empty sector? + We skip that sector and check footer again. */ + unsigned i; + for (i = 0; i < kSectorSize && buf[i] == 0; i++); + if (i == kSectorSize) + { + RINOK(ReadPhy(_phySize + kSectorSize, buf, kHeaderSize)) + if (memcmp(header, buf, kHeaderSize) == 0) + { + _phySize += kSectorSize; + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + return S_OK; + } + } + } + _posInArcLimit = _phySize; + _phySize += kHeaderSize; + AddErrorMessage("Can't find footer"); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= Footer.CurrentSize) + return S_OK; + { + const UInt64 rem = Footer.CurrentSize - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + + if (Footer.IsFixed()) + { + if (_virtPos > _posInArcLimit) + return S_FALSE; + { + const UInt64 rem = _posInArcLimit - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + HRESULT res = S_OK; + if (_virtPos != _posInArc) + { + _posInArc = _virtPos; + res = Seek2(_virtPos); + } + if (res == S_OK) + { + UInt32 processedSize2 = 0; + res = Stream->Read(data, size, &processedSize2); + if (processedSize) + *processedSize = processedSize2; + _posInArc += processedSize2; + } + if (res != S_OK) + Reset_PosInArc(); + return res; + } + + const UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog); + if (blockIndex >= Bat.Size()) + return E_FAIL; // it's some unexpected case + const UInt32 blockSectIndex = Bat[blockIndex]; + const UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog; + UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + size = MyMin(blockSize - offsetInBlock, size); + + HRESULT res = S_OK; + if (blockSectIndex == kUnusedBlock) + { + if (ParentStream) + { + RINOK(InStream_SeekSet(ParentStream, _virtPos)) + res = ParentStream->Read(data, size, &size); + } + else + memset(data, 0, size); + } + else + { + const UInt64 newPos = (UInt64)blockSectIndex << kSectorSize_Log; + if (BitMapTag != blockIndex) + { + RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.Size())) + BitMapTag = blockIndex; + } + RINOK(ReadPhy(newPos + BitMap.Size() + offsetInBlock, data, size)) + for (UInt32 cur = 0; cur < size;) + { + const UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur); + const UInt32 bmi = offsetInBlock >> kSectorSize_Log; + if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0) + { + if (ParentStream) + { + RINOK(InStream_SeekSet(ParentStream, _virtPos + cur)) + RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem)) + } + else + { + const Byte *p = (const Byte *)data + cur; + for (UInt32 i = 0; i < rem; i++) + if (p[i] != 0) + return S_FALSE; + } + } + offsetInBlock += rem; + cur += rem; + } + } + if (processedSize) + *processedSize = size; + _virtPos += size; + return res; +} + + +enum +{ + kpidParent = kpidUserDefined, + kpidSavedState +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidOffset, VT_UI8}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidClusterSize, VT_UI8}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidNumVolumes, VT_UI4}, + { NULL, kpidTotalPhySize, VT_UI8}, + { "Parent", kpidParent, VT_BSTR}, + { NULL, kpidCreatorApp, VT_BSTR}, + { NULL, kpidHostOS, VT_BSTR}, + { "Saved State", kpidSavedState, VT_BOOL}, + { NULL, kpidId, VT_BSTR} + }; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, + kpidCTime + + /* + { kpidNumCyls, VT_UI4}, + { kpidNumHeads, VT_UI4}, + { kpidSectorsPerTrack, VT_UI4} + */ +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +// VHD start time: 2000-01-01 +static const UInt64 kVhdTimeStartValue = (UInt64)3600 * 24 * (399 * 365 + 24 * 4); + +static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop) +{ + FILETIME ft, utc; + UInt64 v = (kVhdTimeStartValue + vhdTime) * 10000000; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + // specification says that it's UTC time, but Virtual PC 6 writes local time. Why? + LocalFileTimeToFileTime(&ft, &utc); + prop = utc; +} + +static void StringToAString(char *dest, UInt32 val) +{ + for (int i = 24; i >= 0; i -= 8) + { + const Byte b = (Byte)((val >> i) & 0xFF); + if (b < 0x20 || b > 0x7F) + break; + *dest++ = (char)b; + } + *dest = 0; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; + case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break; + case kpidShortComment: + case kpidMethod: + { + AString s; + Footer.AddTypeString(s); + if (NeedParent()) + { + s += " -> "; + const CHandler *p = this; + while (p && p->NeedParent()) + p = p->Parent; + if (!p) + s += '?'; + else + p->Footer.AddTypeString(s); + } + prop = s; + break; + } + case kpidCreatorApp: + { + char s[16]; + StringToAString(s, Footer.CreatorApp); + AString res (s); + res.Trim(); + res.Add_Space(); + res.Add_UInt32(Footer.CreatorVersion >> 16); + res.Add_Dot(); + res.Add_UInt32(Footer.CreatorVersion & 0xFFFF); + prop = res; + break; + } + case kpidHostOS: + { + if (Footer.CreatorHostOS == 0x5769326B) + prop = "Windows"; + else + { + char s[16]; + StringToAString(s, Footer.CreatorHostOS); + prop = s; + } + break; + } + case kpidId: + { + char s[sizeof(Footer.Id) * 2 + 2]; + ConvertDataToHex_Upper(s, Footer.Id, sizeof(Footer.Id)); + prop = s; + break; + } + case kpidSavedState: prop = Footer.SavedState ? true : false; break; + case kpidParent: if (NeedParent()) prop = GetParentSequence(); break; + case kpidOffset: prop = _startOffset; break; + case kpidPhySize: prop = _phySize; break; + case kpidTotalPhySize: + { + const CHandler *p = this; + UInt64 sum = 0; + do + { + sum += p->_phySize; + p = p->Parent; + } + while (p); + prop = sum; + break; + } + case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break; + + /* + case kpidErrorFlags: + { + UInt32 flags = 0; + if (_unexpectedEnd) + flags |= kpv_ErrorFlags_UnexpectedEndOfArc; + if (flags != 0) + prop = flags; + break; + } + */ + case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level) +{ + Close(); + Stream = stream; + if (level > (1 << 12)) // Maybe we need to increase that limit + return S_FALSE; + + RINOK(Open3()) + + NumLevels = 1; + if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0) + return S_FALSE; + if (Footer.Type != kDiskType_Diff) + return S_OK; + + bool useRelative; + UString name; + + if (!Dyn.RelativeParentNameFromLocator.IsEmpty()) + { + useRelative = true; + name = Dyn.RelativeParentNameFromLocator; + } + else + { + useRelative = false; + name = Dyn.ParentName; + } + + Dyn.RelativeNameWasUsed = useRelative; + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpenVolumeCallback, + openVolumeCallback, openArchiveCallback) + + if (openVolumeCallback) + { + CMyComPtr nextStream; + HRESULT res = openVolumeCallback->GetStream(name, &nextStream); + + if (res == S_FALSE) + { + if (useRelative && Dyn.ParentName != Dyn.RelativeParentNameFromLocator) + { + res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream); + if (res == S_OK) + Dyn.RelativeNameWasUsed = false; + } + } + + if (res != S_OK && res != S_FALSE) + return res; + + if (res == S_FALSE || !nextStream) + { + AddErrorMessage("Missing volume : ", name); + return S_OK; + } + + Parent = new CHandler; + ParentStream = Parent; + + res = Parent->Open2(nextStream, this, openArchiveCallback, level + 1); + + if (res != S_OK) + { + Parent = NULL; + ParentStream.Release(); + if (res == E_ABORT) + return res; + if (res != S_FALSE) + { + // we must show that error code + } + } + if (res == S_OK) + { + NumLevels = Parent->NumLevels + 1; + } + } + { + const CHandler *p = this; + while (p->NeedParent()) + { + p = p->Parent; + if (!p) + { + AddErrorMessage("Can't open parent VHD file : ", Dyn.ParentName); + break; + } + } + } + return S_OK; +} + + +void CHandler::CloseAtError() +{ + // CHandlerImg: + Stream.Release(); + Clear_HandlerImg_Vars(); + + _phySize = 0; + NumLevels = 0; + Bat.Clear(); + NumUsedBlocks = 0; + Parent = NULL; + ParentStream.Release(); + Dyn.Clear(); + _errorMessage.Empty(); + // _unexpectedEnd = false; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + CloseAtError(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = Footer.CurrentSize; break; + case kpidPackSize: prop = GetPackSize(); break; + case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + + /* + case kpidNumCyls: prop = Footer.NumCyls(); break; + case kpidNumHeads: prop = Footer.NumHeads(); break; + case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break; + */ + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + if (Footer.IsFixed()) + { + CMyComPtr2 streamSpec; + streamSpec.Create_if_Empty(); + streamSpec->SetStream(Stream); + // fixme : check (startOffset = 0) + streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize); + RINOK(streamSpec->SeekToStart()) + *stream = streamSpec.Detach(); + return S_OK; + } + if (!Footer.ThereIsDynamic() || !AreParentsOK()) + return S_FALSE; + CMyComPtr streamTemp = this; + RINOK(InitAndSeek()) + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "VHD", "vhd", NULL, 0xDC, + kSignature, + 0, + NArcInfoFlags::kUseGlobalOffset, + NULL) + +}} diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp index d544de10e..ca450e5d5 100644 --- a/CPP/7zip/Archive/VhdxHandler.cpp +++ b/CPP/7zip/Archive/VhdxHandler.cpp @@ -1,2083 +1,2083 @@ -// VhdxHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringToInt.h" -#include "../../Common/MyBuffer.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "HandlerCont.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G32(_offs_, dest) dest = Get32(p + (_offs_)) -#define G64(_offs_, dest) dest = Get64(p + (_offs_)) - -using namespace NWindows; - - -EXTERN_C_BEGIN - -// CRC-32C (Castagnoli) : reversed for poly 0x1EDC6F41 -#define k_Crc32c_Poly 0x82f63b78 - -MY_ALIGN(64) -static UInt32 g_Crc32c_Table[256]; - -static void Z7_FASTCALL Crc32c_GenerateTable() -{ - UInt32 i; - for (i = 0; i < 256; i++) - { - UInt32 r = i; - unsigned j; - for (j = 0; j < 8; j++) - r = (r >> 1) ^ (k_Crc32c_Poly & ((UInt32)0 - (r & 1))); - g_Crc32c_Table[i] = r; - } -} - - -#define CRC32C_INIT_VAL 0xFFFFFFFF - -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - -// UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); -static UInt32 Z7_FASTCALL CrcUpdateT1_vhdx(UInt32 v, const void *data, size_t size, const UInt32 *table) -{ - const Byte *p = (const Byte *)data; - const Byte *pEnd = p + size; - for (; p != pEnd; p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; -} - -static UInt32 Z7_FASTCALL Crc32c_Calc(const void *data, size_t size) -{ - return CrcUpdateT1_vhdx(CRC32C_INIT_VAL, data, size, g_Crc32c_Table) ^ CRC32C_INIT_VAL; -} - -EXTERN_C_END - - -namespace NArchive { -namespace NVhdx { - -static struct C_CRC32c_TableInit { C_CRC32c_TableInit() { Crc32c_GenerateTable(); } } g_CRC32c_TableInit; - -static const unsigned kSignatureSize = 8; -static const Byte kSignature[kSignatureSize] = - { 'v', 'h', 'd', 'x', 'f', 'i', 'l', 'e' }; - -static const unsigned kBitmapSize_Log = 20; -static const size_t kBitmapSize = (size_t)1 << kBitmapSize_Log; - - -static bool IsZeroArr(const Byte *p, size_t size) -{ - for (size_t i = 0; i < size; i++) - if (p[i] != 0) - return false; - return true; -} - - - -Z7_FORCE_INLINE -static int DecodeFrom2HexChars(const wchar_t *s) -{ - unsigned v0 = (unsigned)s[0]; Z7_PARSE_HEX_DIGIT(v0, return -1;) - unsigned v1 = (unsigned)s[1]; Z7_PARSE_HEX_DIGIT(v1, return -1;) - return (int)((v0 << 4) | v1); -} - - -struct CGuid -{ - Byte Data[16]; - - bool IsZero() const { return IsZeroArr(Data, 16); } - bool IsEqualTo(const Byte *a) const { return memcmp(Data, a, 16) == 0; } - bool IsEqualTo(const CGuid &g) const { return IsEqualTo(g.Data); } - void AddHexToString(UString &s) const; - - void SetFrom(const Byte *p) { memcpy(Data, p, 16); } - - bool ParseFromFormatedHexString(const UString &s) - { - const unsigned kLen = 16 * 2 + 4 + 2; - if (s.Len() != kLen || s[0] != '{' || s[kLen - 1] != '}') - return false; - unsigned pos = 0; - for (unsigned i = 1; i < kLen - 1;) - { - if (i == 9 || i == 14 || i == 19 || i == 24) - { - if (s[i] != '-') - return false; - i++; - continue; - } - const int v = DecodeFrom2HexChars(s.Ptr(i)); - if (v < 0) - return false; - unsigned pos2 = pos; - if (pos < 8) - pos2 ^= (pos < 4 ? 3 : 1); - Data[pos2] = (Byte)v; - pos++; - i += 2; - } - return true; // pos == 16; - } -}; - -void CGuid::AddHexToString(UString &s) const -{ - char temp[sizeof(Data) * 2 + 2]; - ConvertDataToHex_Lower(temp, Data, sizeof(Data)); - s += temp; -} - - -#define IS_NON_ALIGNED(v) (((v) & 0xFFFFF) != 0) - -static const unsigned kHeader_GUID_Index_FileWriteGuid = 0; -static const unsigned kHeader_GUID_Index_DataWriteGuid = 1; -static const unsigned kHeader_GUID_Index_LogGuid = 2; - -struct CHeader -{ - UInt64 SequenceNumber; - // UInt16 LogVersion; - // UInt16 Version; - UInt32 LogLength; - UInt64 LogOffset; - CGuid Guids[3]; - - bool IsEqualTo(const CHeader &h) const - { - if (SequenceNumber != h.SequenceNumber) - return false; - if (LogLength != h.LogLength) - return false; - if (LogOffset != h.LogOffset) - return false; - for (unsigned i = 0; i < 3; i++) - if (!Guids[i].IsEqualTo(h.Guids[i])) - return false; - return true; - } - - bool Parse(Byte *p); -}; - -static const unsigned kHeader2Size = 1 << 12; - -bool CHeader::Parse(Byte *p) -{ - if (Get32(p) != 0x64616568) // "head" - return false; - const UInt32 crc = Get32(p + 4); - SetUi32(p + 4, 0) - if (Crc32c_Calc(p, kHeader2Size) != crc) - return false; - G64(8, SequenceNumber); - for (unsigned i = 0; i < 3; i++) - Guids[i].SetFrom(p + 0x10 + 0x10 * i); - // LogVersion = Get16(p + 0x40); - /* LogVersion MUST be set to zero, for known log format - but we don't parse log so we ignore it */ - G32(0x44, LogLength); - G64(0x48, LogOffset); - if (Get16(p + 0x42) != 1) // Header format Version - return false; - if (IS_NON_ALIGNED(LogLength)) - return false; - if (IS_NON_ALIGNED(LogOffset)) - return false; - return true; - // return IsZeroArr(p + 0x50, kHeader2Size - 0x50); -} - - - -static const Byte kBat[16] = - { 0x66,0x77,0xC2,0x2D,0x23,0xF6,0x00,0x42,0x9D,0x64,0x11,0x5E,0x9B,0xFD,0x4A,0x08 }; -static const Byte kMetadataRegion[16] = - { 0x06,0xA2,0x7C,0x8B,0x90,0x47,0x9A,0x4B,0xB8,0xFE,0x57,0x5F,0x05,0x0F,0x88,0x6E }; - -struct CRegionEntry -{ - // CGuid Guid; - UInt64 Offset; - UInt32 Len; - UInt32 Required; - - UInt64 GetEndPos() const { return Offset + Len; } - bool Parse(const Byte *p); -}; - -bool CRegionEntry::Parse(const Byte *p) -{ - // Guid.SetFrom(p); - G64(0x10, Offset); - G32(0x18, Len); - G32(0x1c, Required); - if (IS_NON_ALIGNED(Offset)) - return false; - if (IS_NON_ALIGNED(Len)) - return false; - if (Offset + Len < Offset) - return false; - return true; -} - - -struct CRegion -{ - bool Bat_Defined; - bool Meta_Defined; - UInt64 EndPos; - UInt64 DataSize; - - CRegionEntry BatEntry; - CRegionEntry MetaEntry; - - bool Parse(Byte *p); -}; - - -static const size_t kRegionSize = 1 << 16; -static const unsigned kNumRegionEntriesMax = (1 << 11) - 1; - -bool CRegion::Parse(Byte *p) -{ - Bat_Defined = false; - Meta_Defined = false; - EndPos = 0; - DataSize = 0; - - if (Get32(p) != 0x69676572) // "regi" - return false; - const UInt32 crc = Get32(p + 4); - SetUi32(p + 4, 0) - const UInt32 crc_calced = Crc32c_Calc(p, kRegionSize); - if (crc_calced != crc) - return false; - - const UInt32 EntryCount = Get32(p + 8); - if (Get32(p + 12) != 0) // reserved field must be set to 0. - return false; - if (EntryCount > kNumRegionEntriesMax) - return false; - for (UInt32 i = 0; i < EntryCount; i++) - { - CRegionEntry e; - const Byte *p2 = p + 0x10 + 0x20 * (size_t)i; - if (!e.Parse(p2)) - return false; - DataSize += e.Len; - const UInt64 endPos = e.GetEndPos(); - if (EndPos < endPos) - EndPos = endPos; - CGuid Guid; - Guid.SetFrom(p2); - if (Guid.IsEqualTo(kBat)) - { - if (Bat_Defined) - return false; - BatEntry = e; - Bat_Defined = true; - } - else if (Guid.IsEqualTo(kMetadataRegion)) - { - if (Meta_Defined) - return false; - MetaEntry = e; - Meta_Defined = true; - } - else - { - if (e.Required != 0) - return false; - // it's allowed to ignore unknown non-required region entries - } - } - /* - const size_t k = 0x10 + 0x20 * EntryCount; - return IsZeroArr(p + k, kRegionSize - k); - */ - return true; -} - - - - -struct CMetaEntry -{ - CGuid Guid; - UInt32 Offset; - UInt32 Len; - UInt32 Flags0; - // UInt32 Flags1; - - bool IsUser() const { return (Flags0 & 1) != 0; } - bool IsVirtualDisk() const { return (Flags0 & 2) != 0; } - bool IsRequired() const { return (Flags0 & 4) != 0; } - - bool CheckLimit(size_t regionSize) const - { - return Offset <= regionSize && Len <= regionSize - Offset; - } - - bool Parse(const Byte *p); -}; - - -bool CMetaEntry::Parse(const Byte *p) -{ - Guid.SetFrom(p); - - G32(0x10, Offset); - G32(0x14, Len); - G32(0x18, Flags0); - UInt32 Flags1; - G32(0x1C, Flags1); - - if (Offset != 0 && Offset < (1 << 16)) - return false; - if (Len > (1 << 20)) - return false; - if (Len == 0 && Offset != 0) - return false; - if ((Flags0 >> 3) != 0) // Reserved - return false; - if ((Flags1 & 3) != 0) // Reserved2 - return false; - return true; -} - - -struct CParentPair -{ - UString Key; - UString Value; -}; - - -struct CMetaHeader -{ - // UInt16 EntryCount; - bool Guid_Defined; - bool VirtualDiskSize_Defined; - bool Locator_Defined; - - unsigned BlockSize_Log; - unsigned LogicalSectorSize_Log; - unsigned PhysicalSectorSize_Log; - - UInt32 Flags; - UInt64 VirtualDiskSize; - CGuid Guid; - // CGuid LocatorType; - - CObjectVector ParentPairs; - - int FindParentKey(const char *name) const - { - FOR_VECTOR (i, ParentPairs) - { - const CParentPair &pair = ParentPairs[i]; - if (pair.Key.IsEqualTo(name)) - return (int)i; - } - return -1; - } - - bool Is_LeaveBlockAllocated() const { return (Flags & 1) != 0; } - bool Is_HasParent() const { return (Flags & 2) != 0; } - - void Clear() - { - Guid_Defined = false; - VirtualDiskSize_Defined = false; - Locator_Defined = false; - BlockSize_Log = 0; - LogicalSectorSize_Log = 0; - PhysicalSectorSize_Log = 0; - Flags = 0; - VirtualDiskSize = 0; - ParentPairs.Clear(); - } - - bool Parse(const Byte *p, size_t size); -}; - - -static unsigned GetLogSize(UInt32 size) -{ - unsigned k; - for (k = 0; k < 32; k++) - if (((UInt32)1 << k) == size) - return k; - return k; -} - - -static const unsigned kMetadataSize = 8; -static const Byte kMetadata[kMetadataSize] = - { 'm','e','t','a','d','a','t','a' }; - -static const unsigned k_Num_MetaEntries_Max = (1 << 11) - 1; - -static const Byte kFileParameters[16] = - { 0x37,0x67,0xa1,0xca,0x36,0xfa,0x43,0x4d,0xb3,0xb6,0x33,0xf0,0xaa,0x44,0xe7,0x6b }; -static const Byte kVirtualDiskSize[16] = - { 0x24,0x42,0xa5,0x2f,0x1b,0xcd,0x76,0x48,0xb2,0x11,0x5d,0xbe,0xd8,0x3b,0xf4,0xb8 }; -static const Byte kVirtualDiskID[16] = - { 0xab,0x12,0xca,0xbe,0xe6,0xb2,0x23,0x45,0x93,0xef,0xc3,0x09,0xe0,0x00,0xc7,0x46 }; -static const Byte kLogicalSectorSize[16] = - { 0x1d,0xbf,0x41,0x81,0x6f,0xa9,0x09,0x47,0xba,0x47,0xf2,0x33,0xa8,0xfa,0xab,0x5f }; -static const Byte kPhysicalSectorSize[16] = - { 0xc7,0x48,0xa3,0xcd,0x5d,0x44,0x71,0x44,0x9c,0xc9,0xe9,0x88,0x52,0x51,0xc5,0x56 }; -static const Byte kParentLocator[16] = - { 0x2d,0x5f,0xd3,0xa8,0x0b,0xb3,0x4d,0x45,0xab,0xf7,0xd3,0xd8,0x48,0x34,0xab,0x0c }; - -static bool GetString16(UString &s, const Byte *p, size_t size) -{ - s.Empty(); - if (size & 1) - return false; - for (size_t i = 0; i < size; i += 2) - { - const wchar_t c = Get16(p + i); - if (c == 0) - return false; - s += c; - } - return true; -} - - -bool CMetaHeader::Parse(const Byte *p, size_t size) -{ - if (memcmp(p, kMetadata, kMetadataSize) != 0) - return false; - if (Get16(p + 8) != 0) // Reserved - return false; - const UInt32 EntryCount = Get16(p + 10); - if (EntryCount > k_Num_MetaEntries_Max) - return false; - if (!IsZeroArr(p + 12, 20)) // Reserved - return false; - - for (unsigned i = 0; i < EntryCount; i++) - { - CMetaEntry e; - if (!e.Parse(p + 32 + 32 * (size_t)i)) - return false; - if (!e.CheckLimit(size)) - return false; - const Byte *p2 = p + e.Offset; - - if (e.Guid.IsEqualTo(kFileParameters)) - { - if (BlockSize_Log != 0) - return false; - if (e.Len != 8) - return false; - const UInt32 v = Get32(p2); - Flags = Get32(p2 + 4); - BlockSize_Log = GetLogSize(v); - if (BlockSize_Log < 20 || BlockSize_Log > 28) // specification from 1 MB to 256 MB - return false; - if ((Flags >> 2) != 0) // reserved - return false; - } - else if (e.Guid.IsEqualTo(kVirtualDiskSize)) - { - if (VirtualDiskSize_Defined) - return false; - if (e.Len != 8) - return false; - VirtualDiskSize = Get64(p2); - VirtualDiskSize_Defined = true; - } - else if (e.Guid.IsEqualTo(kVirtualDiskID)) - { - if (e.Len != 16) - return false; - Guid.SetFrom(p2); - Guid_Defined = true; - } - else if (e.Guid.IsEqualTo(kLogicalSectorSize)) - { - if (LogicalSectorSize_Log != 0) - return false; - if (e.Len != 4) - return false; - const UInt32 v = Get32(p2); - LogicalSectorSize_Log = GetLogSize(v); - if (LogicalSectorSize_Log != 9 && LogicalSectorSize_Log != 12) - return false; - } - else if (e.Guid.IsEqualTo(kPhysicalSectorSize)) - { - if (PhysicalSectorSize_Log != 0) - return false; - if (e.Len != 4) - return false; - const UInt32 v = Get32(p2); - PhysicalSectorSize_Log = GetLogSize(v); - if (PhysicalSectorSize_Log != 9 && PhysicalSectorSize_Log != 12) - return false; - } - else if (e.Guid.IsEqualTo(kParentLocator)) - { - if (Locator_Defined) - return false; - if (e.Len < 20) - return false; - // LocatorType.SetFrom(p2); - /* Specifies the type of the parent virtual disk. - is different for each type: VHDX, VHD or iSCSI. - only "B04AEFB7-D19E-4A81-B789-25B8E9445913" (for VHDX) is supported now - */ - Locator_Defined = true; - if (Get16(p2 + 16) != 0) // reserved - return false; - const UInt32 KeyValueCount = Get16(p2 + 18); - if (20 + (UInt32)KeyValueCount * 12 > e.Len) - return false; - for (unsigned k = 0; k < KeyValueCount; k++) - { - const Byte *p3 = p2 + 20 + (size_t)k * 12; - const UInt32 KeyOffset = Get32(p3); - const UInt32 ValueOffset = Get32(p3 + 4); - const UInt32 KeyLength = Get16(p3 + 8); - const UInt32 ValueLength = Get16(p3 + 10); - if (KeyOffset > e.Len || KeyLength > e.Len - KeyOffset) - return false; - if (ValueOffset > e.Len || ValueLength > e.Len - ValueOffset) - return false; - CParentPair pair; - if (!GetString16(pair.Key, p2 + KeyOffset, KeyLength)) - return false; - if (!GetString16(pair.Value, p2 + ValueOffset, ValueLength)) - return false; - ParentPairs.Add(pair); - } - } - else - { - if (e.IsRequired()) - return false; - // return false; // unknown metadata; - } - } - - // some properties are required for correct processing - - if (BlockSize_Log == 0) - return false; - if (LogicalSectorSize_Log == 0) - return false; - if (!VirtualDiskSize_Defined) - return false; - if (((UInt32)VirtualDiskSize & ((UInt32)1 << LogicalSectorSize_Log)) != 0) - return false; - - // vhdx specification sets limit for 64 TB. - // do we need to check over same limit ? - const UInt64 kVirtualDiskSize_Max = (UInt64)1 << 46; - if (VirtualDiskSize > kVirtualDiskSize_Max) - return false; - - return true; -} - - - -struct CBat -{ - CByteBuffer Data; - - void Clear() { Data.Free(); } - UInt64 GetItem(size_t n) const - { - return Get64(Data + n * 8); - } -}; - - - -Z7_class_CHandler_final: public CHandlerImg -{ - UInt64 _phySize; - - CBat Bat; - CObjectVector BitMaps; - - unsigned ChunkRatio_Log; - size_t ChunkRatio; - size_t TotalBatEntries; - - CMetaHeader Meta; - CHeader Header; - - UInt32 NumUsedBlocks; - UInt32 NumUsedBitMaps; - UInt64 HeadersSize; - - UInt32 NumLevels; - UInt64 PackSize_Total; - - /* - UInt64 NumUsed_1MB_Blocks; // data and bitmaps - bool NumUsed_1MB_Blocks_Defined; - */ - - CMyComPtr ParentStream; - CHandler *Parent; - UString _errorMessage; - UString _creator; - - bool _nonEmptyLog; - bool _isDataContiguous; - // bool _batOverlap; - - CGuid _parentGuid; - bool _parentGuid_IsDefined; - UStringVector ParentNames; - UString ParentName_Used; - - const CHandler *_child; - unsigned _level; - bool _isCyclic; - bool _isCyclic_or_CyclicParent; - - void AddErrorMessage(const char *message); - void AddErrorMessage(const char *message, const wchar_t *name); - - void UpdatePhySize(UInt64 value) - { - if (_phySize < value) - _phySize = value; - } - - HRESULT Seek2(UInt64 offset); - HRESULT Read_FALSE(Byte *data, size_t size) - { - return ReadStream_FALSE(Stream, data, size); - } - HRESULT ReadToBuf_FALSE(CByteBuffer &buf, size_t size) - { - buf.Alloc(size); - return ReadStream_FALSE(Stream, buf, size); - } - - void InitSeekPositions(); - HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); - - bool IsDiff() const - { - // here we suppose that only HasParent() flag is mandatory for Diff archive type - return Meta.Is_HasParent(); - // return _parentGuid_IsDefined; - } - - void AddTypeString(AString &s) const - { - if (IsDiff()) - s += "Differencing"; - else - { - if (Meta.Is_LeaveBlockAllocated()) - s += _isDataContiguous ? "fixed" : "fixed-non-cont"; - else - s += "dynamic"; - } - } - - void AddComment(UString &s) const; - - UInt64 GetPackSize() const - { - return (UInt64)NumUsedBlocks << Meta.BlockSize_Log; - } - - UString GetParentSequence() const - { - const CHandler *p = this; - UString res; - while (p && p->IsDiff()) - { - if (!res.IsEmpty()) - res += " -> "; - res += ParentName_Used; - p = p->Parent; - } - return res; - } - - bool AreParentsOK() const - { - if (_isCyclic_or_CyclicParent) - return false; - const CHandler *p = this; - while (p->IsDiff()) - { - p = p->Parent; - if (!p) - return false; - } - return true; - } - - // bool ParseLog(CByteBuffer &log); - bool ParseBat(); - bool CheckBat(); - - HRESULT Open3(); - HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override; - HRESULT OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen); - virtual void CloseAtError() Z7_override; - -public: - Z7_IFACE_COM7_IMP(IInArchive_Img) - - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) - - CHandler(): - _child(NULL), - _level(0), - _isCyclic(false), - _isCyclic_or_CyclicParent(false) - {} -}; - - -HRESULT CHandler::Seek2(UInt64 offset) -{ - return InStream_SeekSet(Stream, offset); -} - - -void CHandler::InitSeekPositions() -{ - /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). - So we must reset these variables before first call of Read() */ - Reset_VirtPos(); - Reset_PosInArc(); - if (ParentStream) - Parent->InitSeekPositions(); -} - - -HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) -{ - processed = 0; - if (offset > _phySize - || offset + size > _phySize) - { - // we don't expect these cases, if (_phySize) was set correctly. - return S_FALSE; - } - if (offset != _posInArc) - { - const HRESULT res = Seek2(offset); - if (res != S_OK) - { - Reset_PosInArc(); // we don't trust seek_pos in case of error - return res; - } - _posInArc = offset; - } - { - size_t size2 = size; - const HRESULT res = ReadStream(Stream, data, &size2); - processed = (UInt32)size2; - _posInArc += size2; - if (res != S_OK) - Reset_PosInArc(); // we don't trust seek_pos in case of reading error - return res; - } -} - - -#define PAYLOAD_BLOCK_NOT_PRESENT 0 -#define PAYLOAD_BLOCK_UNDEFINED 1 -#define PAYLOAD_BLOCK_ZERO 2 -#define PAYLOAD_BLOCK_UNMAPPED 3 -#define PAYLOAD_BLOCK_FULLY_PRESENT 6 -#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7 - -#define SB_BLOCK_NOT_PRESENT 0 -#define SB_BLOCK_PRESENT 6 - -#define BAT_GET_OFFSET(v) ((v) & ~(UInt64)0xFFFFF) -#define BAT_GET_STATE(v) ((UInt32)(v) & 7) - -/* The log contains only updates to metadata, bat and region tables - The log doesn't contain updates to start header, and 2 headers (first 192 KB of file). - The log is array of 4 KB blocks and each block has 4-byte signature. - So it's possible to scan whole log to find the latest entry sequence (and header for replay). -*/ - -/* -struct CLogEntry -{ - UInt32 EntryLength; - UInt32 Tail; - UInt64 SequenceNumber; - CGuid LogGuid; - UInt32 DescriptorCount; - UInt64 FlushedFileOffset; - UInt64 LastFileOffset; - - bool Parse(const Byte *p); -}; - -bool CLogEntry::Parse(const Byte *p) -{ - G32 (8, EntryLength); - G32 (12,Tail); - G64 (16, SequenceNumber); - G32 (24, DescriptorCount); // it's 32-bit, but specification says 64-bit - if (Get32(p + 28) != 0) // reserved - return false; - LogGuid.SetFrom(p + 32); - G64 (48, FlushedFileOffset); - G64 (56, LastFileOffset); - - if (SequenceNumber == 0) - return false; - if ((Tail & 0xfff) != 0) - return false; - if (IS_NON_ALIGNED(FlushedFileOffset)) - return false; - if (IS_NON_ALIGNED(LastFileOffset)) - return false; - return true; -} - - -bool CHandler::ParseLog(CByteBuffer &log) -{ - CLogEntry lastEntry; - lastEntry.SequenceNumber = 0; - bool lastEntry_found = false; - size_t lastEntry_Offset = 0; - for (size_t i = 0; i < log.Size(); i += 1 << 12) - { - Byte *p = (Byte *)(log + i); - - if (Get32(p) != 0x65676F6C) // "loge" - continue; - const UInt32 crc = Get32(p + 4); - - CLogEntry e; - if (!e.Parse(p)) - { - return false; - continue; - } - const UInt32 entryLength = Get32(p + 8); - if (e.EntryLength > log.Size() || (e.EntryLength & 0xFFF) != 0 || e.EntryLength == 0) - { - return false; - continue; - } - SetUi32(p + 4, 0); - const UInt32 crc_calced = Crc32c_Calc(p, entryLength); - SetUi32(p + 4, crc); // we must restore crc if we want same data in log - if (crc_calced != crc) - continue; - if (!lastEntry_found || lastEntry.SequenceNumber < e.SequenceNumber) - { - lastEntry = e; - lastEntry_found = true; - lastEntry_Offset = i; - } - } - - return true; -} -*/ - - -bool CHandler::ParseBat() -{ - ChunkRatio_Log = kBitmapSize_Log + 3 + Meta.LogicalSectorSize_Log - Meta.BlockSize_Log; - ChunkRatio = (size_t)1 << (ChunkRatio_Log); - - UInt64 totalBatEntries64; - const bool isDiff = IsDiff(); - const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log; - { - const UInt64 up = Meta.VirtualDiskSize + blockSize - 1; - if (up < Meta.VirtualDiskSize) - return false; - const UInt64 numDataBlocks = up >> Meta.BlockSize_Log; - - if (isDiff) - { - // differencing table must be finished with bitmap entry - const UInt64 numBitmaps = (numDataBlocks + ChunkRatio - 1) >> ChunkRatio_Log; - totalBatEntries64 = numBitmaps * (ChunkRatio + 1); - } - else - { - // we don't need last Bitmap entry - totalBatEntries64 = numDataBlocks + ((numDataBlocks - 1) >> ChunkRatio_Log); - } - } - - if (totalBatEntries64 > Bat.Data.Size() / 8) - return false; - - const size_t totalBatEntries = (size_t)totalBatEntries64; - TotalBatEntries = totalBatEntries; - - bool isCont = (!isDiff && Meta.Is_LeaveBlockAllocated()); - UInt64 prevBlockOffset = 0; - UInt64 maxBlockOffset = 0; - - size_t remEntries = ChunkRatio + 1; - - size_t i; - for (i = 0; i < totalBatEntries; i++) - { - const UInt64 v = Bat.GetItem(i); - if ((v & 0xFFFF8) != 0) - return false; - const UInt64 offset = BAT_GET_OFFSET(v); - const unsigned state = BAT_GET_STATE(v); - - /* - UInt64 index64 = v >> 20; - printf("\n%7d", i); - printf("%10d, ", (unsigned)index64); - printf("%4x, ", (unsigned)state); - */ - - remEntries--; - if (remEntries == 0) - { - // printf(" ========"); - // printf("\n"); - remEntries = ChunkRatio + 1; - if (state == SB_BLOCK_PRESENT) - { - isCont = false; - if (!isDiff) - return false; - if (offset == 0) - return false; - const UInt64 lim = offset + kBitmapSize; - if (lim < offset) - return false; - if (_phySize < lim) - _phySize = lim; - NumUsedBitMaps++; - } - else if (state != SB_BLOCK_NOT_PRESENT) - return false; - } - else - { - if (state == PAYLOAD_BLOCK_FULLY_PRESENT - || state == PAYLOAD_BLOCK_PARTIALLY_PRESENT) - { - if (offset == 0) - return false; - if (maxBlockOffset < offset) - maxBlockOffset = offset; - - if (state == PAYLOAD_BLOCK_PARTIALLY_PRESENT) - { - isCont = false; - if (!isDiff) - return false; - } - else if (isCont) - { - if (prevBlockOffset != 0 && prevBlockOffset + blockSize != offset) - isCont = false; - else - prevBlockOffset = offset; - } - - NumUsedBlocks++; - } - else if (state == PAYLOAD_BLOCK_UNMAPPED) - { - isCont = false; - // non-empty (offset) is allowed - } - else if (state == PAYLOAD_BLOCK_NOT_PRESENT - || state == PAYLOAD_BLOCK_UNDEFINED - || state == PAYLOAD_BLOCK_ZERO) - { - isCont = false; - /* (offset) is reserved and (offset == 0) is expected here, - but we ignore (offset) here */ - // if (offset != 0) return false; - } - else - return false; - } - } - - _isDataContiguous = isCont; - - if (maxBlockOffset != 0) - { - const UInt64 lim = maxBlockOffset + blockSize; - if (lim < maxBlockOffset) - return false; - if (_phySize < lim) - _phySize = lim; - const UInt64 kPhyLimit = (UInt64)1 << 62; - if (maxBlockOffset >= kPhyLimit) - return false; - } - return true; -} - - -bool CHandler::CheckBat() -{ - const UInt64 upSize = _phySize + kBitmapSize * 8 - 1; - if (upSize < _phySize) - return false; - const UInt64 useMapSize64 = upSize >> (kBitmapSize_Log + 3); - const size_t useMapSize = (size_t)useMapSize64; - - const UInt32 blockSizeMB = (UInt32)1 << (Meta.BlockSize_Log - kBitmapSize_Log); - - // we don't check useMap, if it's too big. - if (useMapSize != useMapSize64) - return true; - if (useMapSize == 0 || useMapSize > ((size_t)1 << 28)) - return true; - - CByteArr useMap; - useMap.Alloc(useMapSize); - memset(useMap, 0, useMapSize); - // useMap[0] = (Byte)(1 << 0); // first 1 MB is used by headers - // we can also update useMap for log, and region data. - - const size_t totalBatEntries = TotalBatEntries; - size_t remEntries = ChunkRatio + 1; - - size_t i; - for (i = 0; i < totalBatEntries; i++) - { - const UInt64 v = Bat.GetItem(i); - const UInt64 offset = BAT_GET_OFFSET(v); - const unsigned state = BAT_GET_STATE(v); - const UInt64 index = offset >> kBitmapSize_Log; - UInt32 numBlocks = 1; - remEntries--; - if (remEntries == 0) - { - remEntries = ChunkRatio + 1; - if (state != SB_BLOCK_PRESENT) - continue; - } - else - { - if (state != PAYLOAD_BLOCK_FULLY_PRESENT && - state != PAYLOAD_BLOCK_PARTIALLY_PRESENT) - continue; - numBlocks = blockSizeMB; - } - - for (unsigned k = 0; k < numBlocks; k++) - { - const UInt64 index2 = index + k; - const unsigned flag = (unsigned)1 << ((unsigned)index2 & 7); - const size_t byteIndex = (size_t)(index2 >> 3); - if (byteIndex >= useMapSize) - return false; - const unsigned m = useMap[byteIndex]; - if (m & flag) - return false; - useMap[byteIndex] = (Byte)(m | flag); - } - } - - /* - UInt64 num = 0; - for (i = 0; i < useMapSize; i++) - { - Byte b = useMap[i]; - unsigned t = 0; - t += (b & 1); b >>= 1; - t += (b & 1); b >>= 1; - t += (b & 1); b >>= 1; - t += (b & 1); b >>= 1; - t += (b & 1); b >>= 1; - t += (b & 1); b >>= 1; - t += (b & 1); b >>= 1; - t += (b & 1); - num += t; - } - NumUsed_1MB_Blocks = num; - NumUsed_1MB_Blocks_Defined = true; - */ - - return true; -} - - - -HRESULT CHandler::Open3() -{ - { - const unsigned kHeaderSize = 512; // + 8 - Byte header[kHeaderSize]; - - RINOK(Read_FALSE(header, kHeaderSize)) - - if (memcmp(header, kSignature, kSignatureSize) != 0) - return S_FALSE; - - const Byte *p = &header[0]; - for (unsigned i = kSignatureSize; i < kHeaderSize; i += 2) - { - const wchar_t c = Get16(p + i); - if (c < 0x20 || c > 0x7F) - break; - _creator += c; - } - } - - HeadersSize = (UInt32)1 << 20; - CHeader headers[2]; - { - Byte header[kHeader2Size]; - for (unsigned i = 0; i < 2; i++) - { - RINOK(Seek2((1 << 16) * (1 + i))) - RINOK(Read_FALSE(header, kHeader2Size)) - bool headerIsOK = headers[i].Parse(header); - if (!headerIsOK) - return S_FALSE; - } - } - unsigned mainIndex; - if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0; - else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1; - else - { - /* Disk2vhd v2.02 can create image with 2 full copies of headers. - It's violation of VHDX specification: - "A header is current if it is the only valid header - or if it is valid and its SequenceNumber field is - greater than the other header's SequenceNumber". - but we support such Disk2vhd archives. */ - if (!headers[0].IsEqualTo(headers[1])) - return S_FALSE; - mainIndex = 0; - } - - const CHeader &h = headers[mainIndex]; - Header = h; - if (h.LogLength != 0) - { - HeadersSize += h.LogLength; - UpdatePhySize(h.LogOffset + h.LogLength); - if (!h.Guids[kHeader_GUID_Index_LogGuid].IsZero()) - { - _nonEmptyLog = true; - AddErrorMessage("non-empty LOG was not replayed"); - /* - if (h.LogVersion != 0) - AddErrorMessage("unknown LogVresion"); - else - { - CByteBuffer log; - RINOK(Seek2(h.LogOffset)); - RINOK(ReadToBuf_FALSE(log, h.LogLength)); - if (!ParseLog(log)) - { - return S_FALSE; - } - } - */ - } - } - CRegion regions[2]; - int correctRegionIndex = -1; - - { - CByteBuffer temp; - temp.Alloc(kRegionSize * 2); - RINOK(Seek2((1 << 16) * 3)) - RINOK(Read_FALSE(temp, kRegionSize * 2)) - unsigned numTables = 1; - if (memcmp(temp, temp + kRegionSize, kRegionSize) != 0) - { - AddErrorMessage("Region tables mismatch"); - numTables = 2; - } - - for (unsigned i = 0; i < numTables; i++) - { - // RINOK(Seek2((1 << 16) * (3 + i))); - // RINOK(Read_FALSE(temp, kRegionSize)); - if (regions[i].Parse(temp)) - { - if (correctRegionIndex < 0) - correctRegionIndex = (int)i; - } - else - { - AddErrorMessage("Incorrect region table"); - } - } - if (correctRegionIndex < 0) - return S_FALSE; - /* - if (!regions[0].IsEqualTo(regions[1])) - return S_FALSE; - */ - } - - // UpdatePhySize((1 << 16) * 5); - UpdatePhySize(1 << 20); - - { - const CRegion ®ion = regions[correctRegionIndex]; - HeadersSize += region.DataSize; - UpdatePhySize(region.EndPos); - { - if (!region.Meta_Defined) - return S_FALSE; - const CRegionEntry &e = region.MetaEntry; - if (e.Len == 0) - return S_FALSE; - { - // static const kMetaTableSize = 1 << 16; - CByteBuffer temp; - { - RINOK(Seek2(e.Offset)) - RINOK(ReadToBuf_FALSE(temp, e.Len)) - } - if (!Meta.Parse(temp, temp.Size())) - return S_FALSE; - } - // UpdatePhySize(e.GetEndPos()); - } - { - if (!region.Bat_Defined) - return S_FALSE; - const CRegionEntry &e = region.BatEntry; - if (e.Len == 0) - return S_FALSE; - // UpdatePhySize(e.GetEndPos()); - { - RINOK(Seek2(e.Offset)) - RINOK(ReadToBuf_FALSE(Bat.Data, e.Len)) - } - if (!ParseBat()) - return S_FALSE; - if (!CheckBat()) - { - AddErrorMessage("BAT overlap"); - // _batOverlap = true; - // return S_FALSE; - } - } - } - - { - // do we need to check "parent_linkage2" also? - FOR_VECTOR (i, Meta.ParentPairs) - { - const CParentPair &pair = Meta.ParentPairs[i]; - if (pair.Key.IsEqualTo("parent_linkage")) - { - _parentGuid_IsDefined = _parentGuid.ParseFromFormatedHexString(pair.Value); - break; - } - } - } - - { - // absolute paths for parent stream can be rejected later in client callback - // the order of check by specification: - const char * const g_ParentKeys[] = - { - "relative_path" // "..\..\path2\sub3\parent.vhdx" - , "volume_path" // "\\?\Volume{26A21BDA-A627-11D7-9931-806E6F6E6963}\path2\sub3\parent.vhdx") - , "absolute_win32_path" // "d:\path2\sub3\parent.vhdx" - }; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ParentKeys); i++) - { - const int index = Meta.FindParentKey(g_ParentKeys[i]); - if (index < 0) - continue; - ParentNames.Add(Meta.ParentPairs[index].Value); - } - } - - if (Meta.Is_HasParent()) - { - if (!Meta.Locator_Defined) - AddErrorMessage("Parent locator is not defined"); - else - { - if (!_parentGuid_IsDefined) - AddErrorMessage("Parent GUID is not defined"); - if (ParentNames.IsEmpty()) - AddErrorMessage("Parent VHDX file name is not defined"); - } - } - else - { - if (Meta.Locator_Defined) - AddErrorMessage("Unexpected parent locator"); - } - - // here we suppose that and locator can be used only with HasParent flag - - // return S_FALSE; - - _size = Meta.VirtualDiskSize; // CHandlerImg - - // _posInArc = 0; - // Reset_PosInArc(); - // RINOK(InStream_SeekToBegin(Stream)) - - return S_OK; -} - - -/* -static UInt32 g_NumCalls = 0; -static UInt32 g_NumCalls2 = 0; -static struct CCounter { ~CCounter() -{ - printf("\nNumCalls = %10u\n", g_NumCalls); - printf("NumCalls2 = %10u\n", g_NumCalls2); -} } g_Counter; -*/ - -Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - // g_NumCalls++; - if (processedSize) - *processedSize = 0; - if (_virtPos >= Meta.VirtualDiskSize) - return S_OK; - { - const UInt64 rem = Meta.VirtualDiskSize - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - const size_t blockIndex = (size_t)(_virtPos >> Meta.BlockSize_Log); - const size_t chunkIndex = blockIndex >> ChunkRatio_Log; - const size_t chunkRatio = (size_t)1 << ChunkRatio_Log; - const size_t blockIndex2 = chunkIndex * (chunkRatio + 1) + (blockIndex & (chunkRatio - 1)); - const UInt64 blockSectVal = Bat.GetItem(blockIndex2); - const UInt64 blockOffset = BAT_GET_OFFSET(blockSectVal); - const UInt32 blockState = BAT_GET_STATE(blockSectVal); - - const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log; - const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - size = MyMin(blockSize - offsetInBlock, size); - - bool needParent = false; - bool needRead = false; - - if (blockState == PAYLOAD_BLOCK_FULLY_PRESENT) - needRead = true; - else if (blockState == PAYLOAD_BLOCK_NOT_PRESENT) - { - /* for a differencing VHDX: parent virtual disk SHOULD be - inspected to determine the associated contents (SPECIFICATION). - we suppose that we should not check BitMap. - for fixed or dynamic VHDX files: the block contents are undefined and - can contain arbitrary data (SPECIFICATION). NTFS::pagefile.sys can use such state. */ - if (IsDiff()) - needParent = true; - } - else if (blockState == PAYLOAD_BLOCK_PARTIALLY_PRESENT) - { - // only allowed for differencing VHDX files. - // associated sector bitmap block MUST be valid - if (chunkIndex >= BitMaps.Size()) - return S_FALSE; - // else - { - const CByteBuffer &bitmap = BitMaps[(unsigned)chunkIndex]; - const Byte *p = (const Byte *)bitmap; - if (!p) - return S_FALSE; - // else - { - // g_NumCalls2++; - const UInt64 sectorIndex = _virtPos >> Meta.LogicalSectorSize_Log; - - #define BIT_MAP_UNIT_LOG 3 // it's for small block (4 KB) - // #define BIT_MAP_UNIT_LOG 5 // speed optimization for large blocks (16 KB) - - const size_t offs = (size_t)(sectorIndex >> 3) & - ( - (kBitmapSize - 1) - & ~(((UInt32)1 << (BIT_MAP_UNIT_LOG - 3)) - 1) - ); - - unsigned sector2 = (unsigned)sectorIndex & ((1 << BIT_MAP_UNIT_LOG) - 1); - #if BIT_MAP_UNIT_LOG == 5 - UInt32 v = GetUi32(p + offs) >> sector2; - #else - unsigned v = (unsigned)p[offs] >> sector2; - #endif - // UInt32 v = GetUi32(p + offs) >> sector2; - const UInt32 sectorSize = (UInt32)1 << Meta.LogicalSectorSize_Log; - const UInt32 offsetInSector = (UInt32)_virtPos & (sectorSize - 1); - const unsigned bit = (unsigned)(v & 1); - if (bit) - needRead = true; - else - needParent = true; // zero - from the parent VHDX file - UInt32 rem = sectorSize - offsetInSector; - for (sector2++; sector2 < (1 << BIT_MAP_UNIT_LOG); sector2++) - { - v >>= 1; - if (bit != (v & 1)) - break; - rem += sectorSize; - } - if (size > rem) - size = rem; - } - } - } - - bool needZero = true; - - HRESULT res = S_OK; - - if (needParent) - { - if (!ParentStream) - return S_FALSE; - // if (ParentStream) - { - RINOK(InStream_SeekSet(ParentStream, _virtPos)) - size_t processed = size; - res = ReadStream(ParentStream, (Byte *)data, &processed); - size = (UInt32)processed; - needZero = false; - } - } - else if (needRead) - { - UInt32 processed = 0; - res = ReadPhy(blockOffset + offsetInBlock, data, size, processed); - size = processed; - needZero = false; - } - - if (needZero) - memset(data, 0, size); - - if (processedSize) - *processedSize = size; - - _virtPos += size; - return res; -} - - -enum -{ - kpidParent = kpidUserDefined -}; - -static const CStatProp kArcProps[] = -{ - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidSectorSize, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidNumVolumes, VT_UI4}, - { NULL, kpidTotalPhySize, VT_UI8}, - { "Parent", kpidParent, VT_BSTR}, - { NULL, kpidCreatorApp, VT_BSTR}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidId, VT_BSTR} - }; - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - - -void CHandler::AddErrorMessage(const char *message) -{ - if (!_errorMessage.IsEmpty()) - _errorMessage.Add_LF(); - _errorMessage += message; -} - -void CHandler::AddErrorMessage(const char *message, const wchar_t *name) -{ - AddErrorMessage(message); - _errorMessage += name; -} - - -static void AddComment_Name(UString &s, const char *name) -{ - s += name; - s += ": "; -} - -static void AddComment_Bool(UString &s, const char *name, bool val) -{ - AddComment_Name(s, name); - s.Add_Char(val ? '+' : '-'); - s.Add_LF(); -} - -static void AddComment_UInt64(UString &s, const char *name, UInt64 v, bool showMB = false) -{ - AddComment_Name(s, name); - s.Add_UInt64(v); - if (showMB) - { - s += " ("; - s.Add_UInt64(v >> 20); - s += " MiB)"; - } - s.Add_LF(); -} - -static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize) -{ - if (logSize != 0) - AddComment_UInt64(s, name, ((UInt64)1 << logSize)); -} - - -void CHandler::AddComment(UString &s) const -{ - AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize); - AddComment_UInt64(s, "PhysicalSize", _phySize); - - if (!_errorMessage.IsEmpty()) - { - AddComment_Name(s, "Error"); - s += _errorMessage; - s.Add_LF(); - } - - if (Meta.Guid_Defined) - { - AddComment_Name(s, "Id"); - Meta.Guid.AddHexToString(s); - s.Add_LF(); - } - - AddComment_UInt64(s, "SequenceNumber", Header.SequenceNumber); - AddComment_UInt64(s, "LogLength", Header.LogLength, true); - - for (unsigned i = 0; i < 3; i++) - { - const CGuid &g = Header.Guids[i]; - if (g.IsZero()) - continue; - if (i == 0) - s += "FileWrite"; - else if (i == 1) - s += "DataWrite"; - else - s += "Log"; - AddComment_Name(s, "Guid"); - g.AddHexToString(s); - s.Add_LF(); - } - - AddComment_Bool(s, "HasParent", Meta.Is_HasParent()); - AddComment_Bool(s, "Fixed", Meta.Is_LeaveBlockAllocated()); - if (Meta.Is_LeaveBlockAllocated()) - AddComment_Bool(s, "DataContiguous", _isDataContiguous); - - AddComment_BlockSize(s, "BlockSize", Meta.BlockSize_Log); - AddComment_BlockSize(s, "LogicalSectorSize", Meta.LogicalSectorSize_Log); - AddComment_BlockSize(s, "PhysicalSectorSize", Meta.PhysicalSectorSize_Log); - - { - const UInt64 packSize = GetPackSize(); - AddComment_UInt64(s, "PackSize", packSize, true); - const UInt64 headersSize = HeadersSize + ((UInt64)NumUsedBitMaps << kBitmapSize_Log); - AddComment_UInt64(s, "HeadersSize", headersSize, true); - AddComment_UInt64(s, "FreeSpace", _phySize - packSize - headersSize, true); - /* - if (NumUsed_1MB_Blocks_Defined) - AddComment_UInt64(s, "used2", (NumUsed_1MB_Blocks << 20)); - */ - } - - if (Meta.ParentPairs.Size() != 0) - { - s += "Parent:"; - s.Add_LF(); - FOR_VECTOR(i, Meta.ParentPairs) - { - const CParentPair &pair = Meta.ParentPairs[i]; - s += " "; - s += pair.Key; - s += ": "; - s += pair.Value; - s.Add_LF(); - } - s.Add_LF(); - } -} - - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidClusterSize: prop = (UInt32)1 << Meta.BlockSize_Log; break; - case kpidSectorSize: prop = (UInt32)1 << Meta.LogicalSectorSize_Log; break; - case kpidShortComment: - case kpidMethod: - { - AString s; - AddTypeString(s); - if (IsDiff()) - { - s += " -> "; - const CHandler *p = this; - while (p && p->IsDiff()) - p = p->Parent; - if (!p) - s += '?'; - else - p->AddTypeString(s); - } - prop = s; - break; - } - case kpidComment: - { - UString s; - { - if (NumLevels > 1) - { - AddComment_UInt64(s, "NumVolumeLevels", NumLevels); - AddComment_UInt64(s, "PackSizeTotal", PackSize_Total, true); - s += "----"; - s.Add_LF(); - } - - const CHandler *p = this; - for (;;) - { - if (p->_level != 0 || p->Parent) - AddComment_UInt64(s, "VolumeLevel", p->_level + 1); - p->AddComment(s); - if (!p->Parent) - break; - s += "----"; - s.Add_LF(); - { - s.Add_LF(); - if (!p->ParentName_Used.IsEmpty()) - { - AddComment_Name(s, "Name"); - s += p->ParentName_Used; - s.Add_LF(); - } - } - p = p->Parent; - } - } - prop = s; - break; - } - case kpidCreatorApp: - { - if (!_creator.IsEmpty()) - prop = _creator; - break; - } - case kpidId: - { - if (Meta.Guid_Defined) - { - UString s; - Meta.Guid.AddHexToString(s); - prop = s; - } - break; - } - case kpidName: - { - if (Meta.Guid_Defined) - { - UString s; - Meta.Guid.AddHexToString(s); - s += ".vhdx"; - prop = s; - } - break; - } - case kpidParent: if (IsDiff()) prop = GetParentSequence(); break; - case kpidPhySize: prop = _phySize; break; - case kpidTotalPhySize: - { - const CHandler *p = this; - UInt64 sum = 0; - do - { - sum += p->_phySize; - p = p->Parent; - } - while (p); - prop = sum; - break; - } - case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break; - case kpidError: - { - UString s; - const CHandler *p = this; - do - { - if (!p->_errorMessage.IsEmpty()) - { - if (!s.IsEmpty()) - s.Add_LF(); - s += p->_errorMessage; - } - p = p->Parent; - } - while (p); - if (!s.IsEmpty()) - prop = s; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) -{ - Stream = stream; - if (_level >= (1 << 20)) - return S_FALSE; - - RINOK(Open3()) - - NumLevels = 1; - PackSize_Total = GetPackSize(); - - if (_child) - { - if (!_child->_parentGuid.IsEqualTo(Header.Guids[kHeader_GUID_Index_DataWriteGuid])) - return S_FALSE; - const CHandler *child = _child; - do - { - /* We suppose that only FileWriteGuid is unique. - Another IDs must be identical in in difference and parent archives. */ - if (Header.Guids[kHeader_GUID_Index_FileWriteGuid].IsEqualTo( - child->Header.Guids[kHeader_GUID_Index_FileWriteGuid]) - && _phySize == child->_phySize) - { - _isCyclic = true; - _isCyclic_or_CyclicParent = true; - AddErrorMessage("Cyclic parent archive was blocked"); - return S_OK; - } - child = child->_child; - } - while (child); - } - - if (!Meta.Is_HasParent()) - return S_OK; - - if (!Meta.Locator_Defined - || !_parentGuid_IsDefined - || ParentNames.IsEmpty()) - { - return S_OK; - } - - ParentName_Used = ParentNames.Front(); - - HRESULT res; - const unsigned kNumLevelsMax = (1 << 8); // Maybe we need to increase that limit - if (_level >= kNumLevelsMax - 1) - { - AddErrorMessage("Too many parent levels"); - return S_OK; - } - - bool _parentFileWasOpen = false; - - if (!openArchiveCallback) - res = S_FALSE; - else - res = OpenParent(openArchiveCallback, _parentFileWasOpen); - - if (res != S_OK) - { - if (res != S_FALSE) - return res; - - if (_parentFileWasOpen) - AddErrorMessage("Can't parse parent VHDX file : ", ParentName_Used); - else - AddErrorMessage("Missing parent VHDX file : ", ParentName_Used); - } - - - return S_OK; -} - - -HRESULT CHandler::OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen) -{ - _parentFileWasOpen = false; - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpenVolumeCallback, - openVolumeCallback, openArchiveCallback) - if (!openVolumeCallback) - return S_FALSE; - { - CMyComPtr nextStream; - HRESULT res = S_FALSE; - UString name; - - FOR_VECTOR (i, ParentNames) - { - name = ParentNames[i]; - - // we remove prefix ".\\', but client already can support any variant - if (name[0] == L'.' && name[1] == L'\\') - name.DeleteFrontal(2); - - res = openVolumeCallback->GetStream(name, &nextStream); - - if (res == S_OK && nextStream) - break; - - if (res != S_OK && res != S_FALSE) - return res; - } - - if (res == S_FALSE || !nextStream) - return S_FALSE; - - ParentName_Used = name; - _parentFileWasOpen = true; - - Parent = new CHandler; - ParentStream = Parent; - - try - { - Parent->_level = _level + 1; - Parent->_child = this; - /* we could call CHandlerImg::Open() here. - but we don't need (_imgExt) in (Parent). So we call Open2() here */ - Parent->Close(); - res = Parent->Open2(nextStream, openArchiveCallback); - } - catch(...) - { - Parent = NULL; - ParentStream.Release(); - res = S_FALSE; - throw; - } - - if (res != S_OK) - { - Parent = NULL; - ParentStream.Release(); - if (res == E_ABORT) - return res; - if (res != S_FALSE) - { - // we must show that error code - } - } - - if (res == S_OK) - { - if (Parent->_isCyclic_or_CyclicParent) - _isCyclic_or_CyclicParent = true; - - NumLevels = Parent->NumLevels + 1; - PackSize_Total += Parent->GetPackSize(); - - // we read BitMaps only if Parent was open - - UInt64 numBytes = (UInt64)NumUsedBitMaps << kBitmapSize_Log; - if (openArchiveCallback && numBytes != 0) - { - RINOK(openArchiveCallback->SetTotal(NULL, &numBytes)) - } - numBytes = 0; - for (size_t i = ChunkRatio; i < TotalBatEntries; i += ChunkRatio + 1) - { - const UInt64 v = Bat.GetItem(i); - const UInt64 offset = BAT_GET_OFFSET(v); - const unsigned state = BAT_GET_STATE(v); - - CByteBuffer &buf = BitMaps.AddNew(); - if (state == SB_BLOCK_PRESENT) - { - if (openArchiveCallback) - { - RINOK(openArchiveCallback->SetCompleted(NULL, &numBytes)) - } - numBytes += kBitmapSize; - buf.Alloc(kBitmapSize); - RINOK(Seek2(offset)) - RINOK(Read_FALSE(buf, kBitmapSize)) - /* - for (unsigned i = 0; i < (1 << 20); i+=4) - { - UInt32 v = GetUi32(buf + i); - if (v != 0 && v != (UInt32)(Int32)-1) - printf("\n%7d %8x", i, v); - } - */ - } - } - } - } - - return S_OK; -} - - -void CHandler::CloseAtError() -{ - // CHandlerImg - Clear_HandlerImg_Vars(); - Stream.Release(); - - _phySize = 0; - Bat.Clear(); - BitMaps.Clear(); - NumUsedBlocks = 0; - NumUsedBitMaps = 0; - HeadersSize = 0; - /* - NumUsed_1MB_Blocks = 0; - NumUsed_1MB_Blocks_Defined = false; - */ - - Parent = NULL; - ParentStream.Release(); - _errorMessage.Empty(); - _creator.Empty(); - _nonEmptyLog = false; - _parentGuid_IsDefined = false; - _isDataContiguous = false; - // _batOverlap = false; - - ParentNames.Clear(); - ParentName_Used.Empty(); - - Meta.Clear(); - - ChunkRatio_Log = 0; - ChunkRatio = 0; - TotalBatEntries = 0; - NumLevels = 0; - PackSize_Total = 0; - - _isCyclic = false; - _isCyclic_or_CyclicParent = false; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - CloseAtError(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidSize: prop = Meta.VirtualDiskSize; break; - case kpidPackSize: prop = PackSize_Total; break; - case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - // if some prarent is not OK, we don't create stream - if (!AreParentsOK()) - return S_FALSE; - InitSeekPositions(); - CMyComPtr streamTemp = this; - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - -REGISTER_ARC_I( - "VHDX", "vhdx avhdx", NULL, 0xc4, - kSignature, - 0, - 0, - NULL) - -}} +// VhdxHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringToInt.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G32(_offs_, dest) dest = Get32(p + (_offs_)) +#define G64(_offs_, dest) dest = Get64(p + (_offs_)) + +using namespace NWindows; + + +EXTERN_C_BEGIN + +// CRC-32C (Castagnoli) : reversed for poly 0x1EDC6F41 +#define k_Crc32c_Poly 0x82f63b78 + +MY_ALIGN(64) +static UInt32 g_Crc32c_Table[256]; + +static void Z7_FASTCALL Crc32c_GenerateTable() +{ + UInt32 i; + for (i = 0; i < 256; i++) + { + UInt32 r = i; + unsigned j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (k_Crc32c_Poly & ((UInt32)0 - (r & 1))); + g_Crc32c_Table[i] = r; + } +} + + +#define CRC32C_INIT_VAL 0xFFFFFFFF + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +// UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); +static UInt32 Z7_FASTCALL CrcUpdateT1_vhdx(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + +static UInt32 Z7_FASTCALL Crc32c_Calc(const void *data, size_t size) +{ + return CrcUpdateT1_vhdx(CRC32C_INIT_VAL, data, size, g_Crc32c_Table) ^ CRC32C_INIT_VAL; +} + +EXTERN_C_END + + +namespace NArchive { +namespace NVhdx { + +static struct C_CRC32c_TableInit { C_CRC32c_TableInit() { Crc32c_GenerateTable(); } } g_CRC32c_TableInit; + +static const unsigned kSignatureSize = 8; +static const Byte kSignature[kSignatureSize] = + { 'v', 'h', 'd', 'x', 'f', 'i', 'l', 'e' }; + +static const unsigned kBitmapSize_Log = 20; +static const size_t kBitmapSize = (size_t)1 << kBitmapSize_Log; + + +static bool IsZeroArr(const Byte *p, size_t size) +{ + for (size_t i = 0; i < size; i++) + if (p[i] != 0) + return false; + return true; +} + + + +Z7_FORCE_INLINE +static int DecodeFrom2HexChars(const wchar_t *s) +{ + unsigned v0 = (unsigned)s[0]; Z7_PARSE_HEX_DIGIT(v0, return -1;) + unsigned v1 = (unsigned)s[1]; Z7_PARSE_HEX_DIGIT(v1, return -1;) + return (int)((v0 << 4) | v1); +} + + +struct CGuid +{ + Byte Data[16]; + + bool IsZero() const { return IsZeroArr(Data, 16); } + bool IsEqualTo(const Byte *a) const { return memcmp(Data, a, 16) == 0; } + bool IsEqualTo(const CGuid &g) const { return IsEqualTo(g.Data); } + void AddHexToString(UString &s) const; + + void SetFrom(const Byte *p) { memcpy(Data, p, 16); } + + bool ParseFromFormatedHexString(const UString &s) + { + const unsigned kLen = 16 * 2 + 4 + 2; + if (s.Len() != kLen || s[0] != '{' || s[kLen - 1] != '}') + return false; + unsigned pos = 0; + for (unsigned i = 1; i < kLen - 1;) + { + if (i == 9 || i == 14 || i == 19 || i == 24) + { + if (s[i] != '-') + return false; + i++; + continue; + } + const int v = DecodeFrom2HexChars(s.Ptr(i)); + if (v < 0) + return false; + unsigned pos2 = pos; + if (pos < 8) + pos2 ^= (pos < 4 ? 3 : 1); + Data[pos2] = (Byte)v; + pos++; + i += 2; + } + return true; // pos == 16; + } +}; + +void CGuid::AddHexToString(UString &s) const +{ + char temp[sizeof(Data) * 2 + 2]; + ConvertDataToHex_Lower(temp, Data, sizeof(Data)); + s += temp; +} + + +#define IS_NON_ALIGNED(v) (((v) & 0xFFFFF) != 0) + +static const unsigned kHeader_GUID_Index_FileWriteGuid = 0; +static const unsigned kHeader_GUID_Index_DataWriteGuid = 1; +static const unsigned kHeader_GUID_Index_LogGuid = 2; + +struct CHeader +{ + UInt64 SequenceNumber; + // UInt16 LogVersion; + // UInt16 Version; + UInt32 LogLength; + UInt64 LogOffset; + CGuid Guids[3]; + + bool IsEqualTo(const CHeader &h) const + { + if (SequenceNumber != h.SequenceNumber) + return false; + if (LogLength != h.LogLength) + return false; + if (LogOffset != h.LogOffset) + return false; + for (unsigned i = 0; i < 3; i++) + if (!Guids[i].IsEqualTo(h.Guids[i])) + return false; + return true; + } + + bool Parse(Byte *p); +}; + +static const unsigned kHeader2Size = 1 << 12; + +bool CHeader::Parse(Byte *p) +{ + if (Get32(p) != 0x64616568) // "head" + return false; + const UInt32 crc = Get32(p + 4); + SetUi32(p + 4, 0) + if (Crc32c_Calc(p, kHeader2Size) != crc) + return false; + G64(8, SequenceNumber); + for (unsigned i = 0; i < 3; i++) + Guids[i].SetFrom(p + 0x10 + 0x10 * i); + // LogVersion = Get16(p + 0x40); + /* LogVersion MUST be set to zero, for known log format + but we don't parse log so we ignore it */ + G32(0x44, LogLength); + G64(0x48, LogOffset); + if (Get16(p + 0x42) != 1) // Header format Version + return false; + if (IS_NON_ALIGNED(LogLength)) + return false; + if (IS_NON_ALIGNED(LogOffset)) + return false; + return true; + // return IsZeroArr(p + 0x50, kHeader2Size - 0x50); +} + + + +static const Byte kBat[16] = + { 0x66,0x77,0xC2,0x2D,0x23,0xF6,0x00,0x42,0x9D,0x64,0x11,0x5E,0x9B,0xFD,0x4A,0x08 }; +static const Byte kMetadataRegion[16] = + { 0x06,0xA2,0x7C,0x8B,0x90,0x47,0x9A,0x4B,0xB8,0xFE,0x57,0x5F,0x05,0x0F,0x88,0x6E }; + +struct CRegionEntry +{ + // CGuid Guid; + UInt64 Offset; + UInt32 Len; + UInt32 Required; + + UInt64 GetEndPos() const { return Offset + Len; } + bool Parse(const Byte *p); +}; + +bool CRegionEntry::Parse(const Byte *p) +{ + // Guid.SetFrom(p); + G64(0x10, Offset); + G32(0x18, Len); + G32(0x1c, Required); + if (IS_NON_ALIGNED(Offset)) + return false; + if (IS_NON_ALIGNED(Len)) + return false; + if (Offset + Len < Offset) + return false; + return true; +} + + +struct CRegion +{ + bool Bat_Defined; + bool Meta_Defined; + UInt64 EndPos; + UInt64 DataSize; + + CRegionEntry BatEntry; + CRegionEntry MetaEntry; + + bool Parse(Byte *p); +}; + + +static const size_t kRegionSize = 1 << 16; +static const unsigned kNumRegionEntriesMax = (1 << 11) - 1; + +bool CRegion::Parse(Byte *p) +{ + Bat_Defined = false; + Meta_Defined = false; + EndPos = 0; + DataSize = 0; + + if (Get32(p) != 0x69676572) // "regi" + return false; + const UInt32 crc = Get32(p + 4); + SetUi32(p + 4, 0) + const UInt32 crc_calced = Crc32c_Calc(p, kRegionSize); + if (crc_calced != crc) + return false; + + const UInt32 EntryCount = Get32(p + 8); + if (Get32(p + 12) != 0) // reserved field must be set to 0. + return false; + if (EntryCount > kNumRegionEntriesMax) + return false; + for (UInt32 i = 0; i < EntryCount; i++) + { + CRegionEntry e; + const Byte *p2 = p + 0x10 + 0x20 * (size_t)i; + if (!e.Parse(p2)) + return false; + DataSize += e.Len; + const UInt64 endPos = e.GetEndPos(); + if (EndPos < endPos) + EndPos = endPos; + CGuid Guid; + Guid.SetFrom(p2); + if (Guid.IsEqualTo(kBat)) + { + if (Bat_Defined) + return false; + BatEntry = e; + Bat_Defined = true; + } + else if (Guid.IsEqualTo(kMetadataRegion)) + { + if (Meta_Defined) + return false; + MetaEntry = e; + Meta_Defined = true; + } + else + { + if (e.Required != 0) + return false; + // it's allowed to ignore unknown non-required region entries + } + } + /* + const size_t k = 0x10 + 0x20 * EntryCount; + return IsZeroArr(p + k, kRegionSize - k); + */ + return true; +} + + + + +struct CMetaEntry +{ + CGuid Guid; + UInt32 Offset; + UInt32 Len; + UInt32 Flags0; + // UInt32 Flags1; + + bool IsUser() const { return (Flags0 & 1) != 0; } + bool IsVirtualDisk() const { return (Flags0 & 2) != 0; } + bool IsRequired() const { return (Flags0 & 4) != 0; } + + bool CheckLimit(size_t regionSize) const + { + return Offset <= regionSize && Len <= regionSize - Offset; + } + + bool Parse(const Byte *p); +}; + + +bool CMetaEntry::Parse(const Byte *p) +{ + Guid.SetFrom(p); + + G32(0x10, Offset); + G32(0x14, Len); + G32(0x18, Flags0); + UInt32 Flags1; + G32(0x1C, Flags1); + + if (Offset != 0 && Offset < (1 << 16)) + return false; + if (Len > (1 << 20)) + return false; + if (Len == 0 && Offset != 0) + return false; + if ((Flags0 >> 3) != 0) // Reserved + return false; + if ((Flags1 & 3) != 0) // Reserved2 + return false; + return true; +} + + +struct CParentPair +{ + UString Key; + UString Value; +}; + + +struct CMetaHeader +{ + // UInt16 EntryCount; + bool Guid_Defined; + bool VirtualDiskSize_Defined; + bool Locator_Defined; + + unsigned BlockSize_Log; + unsigned LogicalSectorSize_Log; + unsigned PhysicalSectorSize_Log; + + UInt32 Flags; + UInt64 VirtualDiskSize; + CGuid Guid; + // CGuid LocatorType; + + CObjectVector ParentPairs; + + int FindParentKey(const char *name) const + { + FOR_VECTOR (i, ParentPairs) + { + const CParentPair &pair = ParentPairs[i]; + if (pair.Key.IsEqualTo(name)) + return (int)i; + } + return -1; + } + + bool Is_LeaveBlockAllocated() const { return (Flags & 1) != 0; } + bool Is_HasParent() const { return (Flags & 2) != 0; } + + void Clear() + { + Guid_Defined = false; + VirtualDiskSize_Defined = false; + Locator_Defined = false; + BlockSize_Log = 0; + LogicalSectorSize_Log = 0; + PhysicalSectorSize_Log = 0; + Flags = 0; + VirtualDiskSize = 0; + ParentPairs.Clear(); + } + + bool Parse(const Byte *p, size_t size); +}; + + +static unsigned GetLogSize(UInt32 size) +{ + unsigned k; + for (k = 0; k < 32; k++) + if (((UInt32)1 << k) == size) + return k; + return k; +} + + +static const unsigned kMetadataSize = 8; +static const Byte kMetadata[kMetadataSize] = + { 'm','e','t','a','d','a','t','a' }; + +static const unsigned k_Num_MetaEntries_Max = (1 << 11) - 1; + +static const Byte kFileParameters[16] = + { 0x37,0x67,0xa1,0xca,0x36,0xfa,0x43,0x4d,0xb3,0xb6,0x33,0xf0,0xaa,0x44,0xe7,0x6b }; +static const Byte kVirtualDiskSize[16] = + { 0x24,0x42,0xa5,0x2f,0x1b,0xcd,0x76,0x48,0xb2,0x11,0x5d,0xbe,0xd8,0x3b,0xf4,0xb8 }; +static const Byte kVirtualDiskID[16] = + { 0xab,0x12,0xca,0xbe,0xe6,0xb2,0x23,0x45,0x93,0xef,0xc3,0x09,0xe0,0x00,0xc7,0x46 }; +static const Byte kLogicalSectorSize[16] = + { 0x1d,0xbf,0x41,0x81,0x6f,0xa9,0x09,0x47,0xba,0x47,0xf2,0x33,0xa8,0xfa,0xab,0x5f }; +static const Byte kPhysicalSectorSize[16] = + { 0xc7,0x48,0xa3,0xcd,0x5d,0x44,0x71,0x44,0x9c,0xc9,0xe9,0x88,0x52,0x51,0xc5,0x56 }; +static const Byte kParentLocator[16] = + { 0x2d,0x5f,0xd3,0xa8,0x0b,0xb3,0x4d,0x45,0xab,0xf7,0xd3,0xd8,0x48,0x34,0xab,0x0c }; + +static bool GetString16(UString &s, const Byte *p, size_t size) +{ + s.Empty(); + if (size & 1) + return false; + for (size_t i = 0; i < size; i += 2) + { + const wchar_t c = Get16(p + i); + if (c == 0) + return false; + s += c; + } + return true; +} + + +bool CMetaHeader::Parse(const Byte *p, size_t size) +{ + if (memcmp(p, kMetadata, kMetadataSize) != 0) + return false; + if (Get16(p + 8) != 0) // Reserved + return false; + const UInt32 EntryCount = Get16(p + 10); + if (EntryCount > k_Num_MetaEntries_Max) + return false; + if (!IsZeroArr(p + 12, 20)) // Reserved + return false; + + for (unsigned i = 0; i < EntryCount; i++) + { + CMetaEntry e; + if (!e.Parse(p + 32 + 32 * (size_t)i)) + return false; + if (!e.CheckLimit(size)) + return false; + const Byte *p2 = p + e.Offset; + + if (e.Guid.IsEqualTo(kFileParameters)) + { + if (BlockSize_Log != 0) + return false; + if (e.Len != 8) + return false; + const UInt32 v = Get32(p2); + Flags = Get32(p2 + 4); + BlockSize_Log = GetLogSize(v); + if (BlockSize_Log < 20 || BlockSize_Log > 28) // specification from 1 MB to 256 MB + return false; + if ((Flags >> 2) != 0) // reserved + return false; + } + else if (e.Guid.IsEqualTo(kVirtualDiskSize)) + { + if (VirtualDiskSize_Defined) + return false; + if (e.Len != 8) + return false; + VirtualDiskSize = Get64(p2); + VirtualDiskSize_Defined = true; + } + else if (e.Guid.IsEqualTo(kVirtualDiskID)) + { + if (e.Len != 16) + return false; + Guid.SetFrom(p2); + Guid_Defined = true; + } + else if (e.Guid.IsEqualTo(kLogicalSectorSize)) + { + if (LogicalSectorSize_Log != 0) + return false; + if (e.Len != 4) + return false; + const UInt32 v = Get32(p2); + LogicalSectorSize_Log = GetLogSize(v); + if (LogicalSectorSize_Log != 9 && LogicalSectorSize_Log != 12) + return false; + } + else if (e.Guid.IsEqualTo(kPhysicalSectorSize)) + { + if (PhysicalSectorSize_Log != 0) + return false; + if (e.Len != 4) + return false; + const UInt32 v = Get32(p2); + PhysicalSectorSize_Log = GetLogSize(v); + if (PhysicalSectorSize_Log != 9 && PhysicalSectorSize_Log != 12) + return false; + } + else if (e.Guid.IsEqualTo(kParentLocator)) + { + if (Locator_Defined) + return false; + if (e.Len < 20) + return false; + // LocatorType.SetFrom(p2); + /* Specifies the type of the parent virtual disk. + is different for each type: VHDX, VHD or iSCSI. + only "B04AEFB7-D19E-4A81-B789-25B8E9445913" (for VHDX) is supported now + */ + Locator_Defined = true; + if (Get16(p2 + 16) != 0) // reserved + return false; + const UInt32 KeyValueCount = Get16(p2 + 18); + if (20 + (UInt32)KeyValueCount * 12 > e.Len) + return false; + for (unsigned k = 0; k < KeyValueCount; k++) + { + const Byte *p3 = p2 + 20 + (size_t)k * 12; + const UInt32 KeyOffset = Get32(p3); + const UInt32 ValueOffset = Get32(p3 + 4); + const UInt32 KeyLength = Get16(p3 + 8); + const UInt32 ValueLength = Get16(p3 + 10); + if (KeyOffset > e.Len || KeyLength > e.Len - KeyOffset) + return false; + if (ValueOffset > e.Len || ValueLength > e.Len - ValueOffset) + return false; + CParentPair pair; + if (!GetString16(pair.Key, p2 + KeyOffset, KeyLength)) + return false; + if (!GetString16(pair.Value, p2 + ValueOffset, ValueLength)) + return false; + ParentPairs.Add(pair); + } + } + else + { + if (e.IsRequired()) + return false; + // return false; // unknown metadata; + } + } + + // some properties are required for correct processing + + if (BlockSize_Log == 0) + return false; + if (LogicalSectorSize_Log == 0) + return false; + if (!VirtualDiskSize_Defined) + return false; + if (((UInt32)VirtualDiskSize & ((UInt32)1 << LogicalSectorSize_Log)) != 0) + return false; + + // vhdx specification sets limit for 64 TB. + // do we need to check over same limit ? + const UInt64 kVirtualDiskSize_Max = (UInt64)1 << 46; + if (VirtualDiskSize > kVirtualDiskSize_Max) + return false; + + return true; +} + + + +struct CBat +{ + CByteBuffer Data; + + void Clear() { Data.Free(); } + UInt64 GetItem(size_t n) const + { + return Get64(Data + n * 8); + } +}; + + + +Z7_class_CHandler_final: public CHandlerImg +{ + UInt64 _phySize; + + CBat Bat; + CObjectVector BitMaps; + + unsigned ChunkRatio_Log; + size_t ChunkRatio; + size_t TotalBatEntries; + + CMetaHeader Meta; + CHeader Header; + + UInt32 NumUsedBlocks; + UInt32 NumUsedBitMaps; + UInt64 HeadersSize; + + UInt32 NumLevels; + UInt64 PackSize_Total; + + /* + UInt64 NumUsed_1MB_Blocks; // data and bitmaps + bool NumUsed_1MB_Blocks_Defined; + */ + + CMyComPtr ParentStream; + CHandler *Parent; + UString _errorMessage; + UString _creator; + + bool _nonEmptyLog; + bool _isDataContiguous; + // bool _batOverlap; + + CGuid _parentGuid; + bool _parentGuid_IsDefined; + UStringVector ParentNames; + UString ParentName_Used; + + const CHandler *_child; + unsigned _level; + bool _isCyclic; + bool _isCyclic_or_CyclicParent; + + void AddErrorMessage(const char *message); + void AddErrorMessage(const char *message, const wchar_t *name); + + void UpdatePhySize(UInt64 value) + { + if (_phySize < value) + _phySize = value; + } + + HRESULT Seek2(UInt64 offset); + HRESULT Read_FALSE(Byte *data, size_t size) + { + return ReadStream_FALSE(Stream, data, size); + } + HRESULT ReadToBuf_FALSE(CByteBuffer &buf, size_t size) + { + buf.Alloc(size); + return ReadStream_FALSE(Stream, buf, size); + } + + void InitSeekPositions(); + HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); + + bool IsDiff() const + { + // here we suppose that only HasParent() flag is mandatory for Diff archive type + return Meta.Is_HasParent(); + // return _parentGuid_IsDefined; + } + + void AddTypeString(AString &s) const + { + if (IsDiff()) + s += "Differencing"; + else + { + if (Meta.Is_LeaveBlockAllocated()) + s += _isDataContiguous ? "fixed" : "fixed-non-cont"; + else + s += "dynamic"; + } + } + + void AddComment(UString &s) const; + + UInt64 GetPackSize() const + { + return (UInt64)NumUsedBlocks << Meta.BlockSize_Log; + } + + UString GetParentSequence() const + { + const CHandler *p = this; + UString res; + while (p && p->IsDiff()) + { + if (!res.IsEmpty()) + res += " -> "; + res += ParentName_Used; + p = p->Parent; + } + return res; + } + + bool AreParentsOK() const + { + if (_isCyclic_or_CyclicParent) + return false; + const CHandler *p = this; + while (p->IsDiff()) + { + p = p->Parent; + if (!p) + return false; + } + return true; + } + + // bool ParseLog(CByteBuffer &log); + bool ParseBat(); + bool CheckBat(); + + HRESULT Open3(); + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override; + HRESULT OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen); + virtual void CloseAtError() Z7_override; + +public: + Z7_IFACE_COM7_IMP(IInArchive_Img) + + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) + + CHandler(): + _child(NULL), + _level(0), + _isCyclic(false), + _isCyclic_or_CyclicParent(false) + {} +}; + + +HRESULT CHandler::Seek2(UInt64 offset) +{ + return InStream_SeekSet(Stream, offset); +} + + +void CHandler::InitSeekPositions() +{ + /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). + So we must reset these variables before first call of Read() */ + Reset_VirtPos(); + Reset_PosInArc(); + if (ParentStream) + Parent->InitSeekPositions(); +} + + +HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) +{ + processed = 0; + if (offset > _phySize + || offset + size > _phySize) + { + // we don't expect these cases, if (_phySize) was set correctly. + return S_FALSE; + } + if (offset != _posInArc) + { + const HRESULT res = Seek2(offset); + if (res != S_OK) + { + Reset_PosInArc(); // we don't trust seek_pos in case of error + return res; + } + _posInArc = offset; + } + { + size_t size2 = size; + const HRESULT res = ReadStream(Stream, data, &size2); + processed = (UInt32)size2; + _posInArc += size2; + if (res != S_OK) + Reset_PosInArc(); // we don't trust seek_pos in case of reading error + return res; + } +} + + +#define PAYLOAD_BLOCK_NOT_PRESENT 0 +#define PAYLOAD_BLOCK_UNDEFINED 1 +#define PAYLOAD_BLOCK_ZERO 2 +#define PAYLOAD_BLOCK_UNMAPPED 3 +#define PAYLOAD_BLOCK_FULLY_PRESENT 6 +#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7 + +#define SB_BLOCK_NOT_PRESENT 0 +#define SB_BLOCK_PRESENT 6 + +#define BAT_GET_OFFSET(v) ((v) & ~(UInt64)0xFFFFF) +#define BAT_GET_STATE(v) ((UInt32)(v) & 7) + +/* The log contains only updates to metadata, bat and region tables + The log doesn't contain updates to start header, and 2 headers (first 192 KB of file). + The log is array of 4 KB blocks and each block has 4-byte signature. + So it's possible to scan whole log to find the latest entry sequence (and header for replay). +*/ + +/* +struct CLogEntry +{ + UInt32 EntryLength; + UInt32 Tail; + UInt64 SequenceNumber; + CGuid LogGuid; + UInt32 DescriptorCount; + UInt64 FlushedFileOffset; + UInt64 LastFileOffset; + + bool Parse(const Byte *p); +}; + +bool CLogEntry::Parse(const Byte *p) +{ + G32 (8, EntryLength); + G32 (12,Tail); + G64 (16, SequenceNumber); + G32 (24, DescriptorCount); // it's 32-bit, but specification says 64-bit + if (Get32(p + 28) != 0) // reserved + return false; + LogGuid.SetFrom(p + 32); + G64 (48, FlushedFileOffset); + G64 (56, LastFileOffset); + + if (SequenceNumber == 0) + return false; + if ((Tail & 0xfff) != 0) + return false; + if (IS_NON_ALIGNED(FlushedFileOffset)) + return false; + if (IS_NON_ALIGNED(LastFileOffset)) + return false; + return true; +} + + +bool CHandler::ParseLog(CByteBuffer &log) +{ + CLogEntry lastEntry; + lastEntry.SequenceNumber = 0; + bool lastEntry_found = false; + size_t lastEntry_Offset = 0; + for (size_t i = 0; i < log.Size(); i += 1 << 12) + { + Byte *p = (Byte *)(log + i); + + if (Get32(p) != 0x65676F6C) // "loge" + continue; + const UInt32 crc = Get32(p + 4); + + CLogEntry e; + if (!e.Parse(p)) + { + return false; + continue; + } + const UInt32 entryLength = Get32(p + 8); + if (e.EntryLength > log.Size() || (e.EntryLength & 0xFFF) != 0 || e.EntryLength == 0) + { + return false; + continue; + } + SetUi32(p + 4, 0); + const UInt32 crc_calced = Crc32c_Calc(p, entryLength); + SetUi32(p + 4, crc); // we must restore crc if we want same data in log + if (crc_calced != crc) + continue; + if (!lastEntry_found || lastEntry.SequenceNumber < e.SequenceNumber) + { + lastEntry = e; + lastEntry_found = true; + lastEntry_Offset = i; + } + } + + return true; +} +*/ + + +bool CHandler::ParseBat() +{ + ChunkRatio_Log = kBitmapSize_Log + 3 + Meta.LogicalSectorSize_Log - Meta.BlockSize_Log; + ChunkRatio = (size_t)1 << (ChunkRatio_Log); + + UInt64 totalBatEntries64; + const bool isDiff = IsDiff(); + const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log; + { + const UInt64 up = Meta.VirtualDiskSize + blockSize - 1; + if (up < Meta.VirtualDiskSize) + return false; + const UInt64 numDataBlocks = up >> Meta.BlockSize_Log; + + if (isDiff) + { + // differencing table must be finished with bitmap entry + const UInt64 numBitmaps = (numDataBlocks + ChunkRatio - 1) >> ChunkRatio_Log; + totalBatEntries64 = numBitmaps * (ChunkRatio + 1); + } + else + { + // we don't need last Bitmap entry + totalBatEntries64 = numDataBlocks + ((numDataBlocks - 1) >> ChunkRatio_Log); + } + } + + if (totalBatEntries64 > Bat.Data.Size() / 8) + return false; + + const size_t totalBatEntries = (size_t)totalBatEntries64; + TotalBatEntries = totalBatEntries; + + bool isCont = (!isDiff && Meta.Is_LeaveBlockAllocated()); + UInt64 prevBlockOffset = 0; + UInt64 maxBlockOffset = 0; + + size_t remEntries = ChunkRatio + 1; + + size_t i; + for (i = 0; i < totalBatEntries; i++) + { + const UInt64 v = Bat.GetItem(i); + if ((v & 0xFFFF8) != 0) + return false; + const UInt64 offset = BAT_GET_OFFSET(v); + const unsigned state = BAT_GET_STATE(v); + + /* + UInt64 index64 = v >> 20; + printf("\n%7d", i); + printf("%10d, ", (unsigned)index64); + printf("%4x, ", (unsigned)state); + */ + + remEntries--; + if (remEntries == 0) + { + // printf(" ========"); + // printf("\n"); + remEntries = ChunkRatio + 1; + if (state == SB_BLOCK_PRESENT) + { + isCont = false; + if (!isDiff) + return false; + if (offset == 0) + return false; + const UInt64 lim = offset + kBitmapSize; + if (lim < offset) + return false; + if (_phySize < lim) + _phySize = lim; + NumUsedBitMaps++; + } + else if (state != SB_BLOCK_NOT_PRESENT) + return false; + } + else + { + if (state == PAYLOAD_BLOCK_FULLY_PRESENT + || state == PAYLOAD_BLOCK_PARTIALLY_PRESENT) + { + if (offset == 0) + return false; + if (maxBlockOffset < offset) + maxBlockOffset = offset; + + if (state == PAYLOAD_BLOCK_PARTIALLY_PRESENT) + { + isCont = false; + if (!isDiff) + return false; + } + else if (isCont) + { + if (prevBlockOffset != 0 && prevBlockOffset + blockSize != offset) + isCont = false; + else + prevBlockOffset = offset; + } + + NumUsedBlocks++; + } + else if (state == PAYLOAD_BLOCK_UNMAPPED) + { + isCont = false; + // non-empty (offset) is allowed + } + else if (state == PAYLOAD_BLOCK_NOT_PRESENT + || state == PAYLOAD_BLOCK_UNDEFINED + || state == PAYLOAD_BLOCK_ZERO) + { + isCont = false; + /* (offset) is reserved and (offset == 0) is expected here, + but we ignore (offset) here */ + // if (offset != 0) return false; + } + else + return false; + } + } + + _isDataContiguous = isCont; + + if (maxBlockOffset != 0) + { + const UInt64 lim = maxBlockOffset + blockSize; + if (lim < maxBlockOffset) + return false; + if (_phySize < lim) + _phySize = lim; + const UInt64 kPhyLimit = (UInt64)1 << 62; + if (maxBlockOffset >= kPhyLimit) + return false; + } + return true; +} + + +bool CHandler::CheckBat() +{ + const UInt64 upSize = _phySize + kBitmapSize * 8 - 1; + if (upSize < _phySize) + return false; + const UInt64 useMapSize64 = upSize >> (kBitmapSize_Log + 3); + const size_t useMapSize = (size_t)useMapSize64; + + const UInt32 blockSizeMB = (UInt32)1 << (Meta.BlockSize_Log - kBitmapSize_Log); + + // we don't check useMap, if it's too big. + if (useMapSize != useMapSize64) + return true; + if (useMapSize == 0 || useMapSize > ((size_t)1 << 28)) + return true; + + CByteArr useMap; + useMap.Alloc(useMapSize); + memset(useMap, 0, useMapSize); + // useMap[0] = (Byte)(1 << 0); // first 1 MB is used by headers + // we can also update useMap for log, and region data. + + const size_t totalBatEntries = TotalBatEntries; + size_t remEntries = ChunkRatio + 1; + + size_t i; + for (i = 0; i < totalBatEntries; i++) + { + const UInt64 v = Bat.GetItem(i); + const UInt64 offset = BAT_GET_OFFSET(v); + const unsigned state = BAT_GET_STATE(v); + const UInt64 index = offset >> kBitmapSize_Log; + UInt32 numBlocks = 1; + remEntries--; + if (remEntries == 0) + { + remEntries = ChunkRatio + 1; + if (state != SB_BLOCK_PRESENT) + continue; + } + else + { + if (state != PAYLOAD_BLOCK_FULLY_PRESENT && + state != PAYLOAD_BLOCK_PARTIALLY_PRESENT) + continue; + numBlocks = blockSizeMB; + } + + for (unsigned k = 0; k < numBlocks; k++) + { + const UInt64 index2 = index + k; + const unsigned flag = (unsigned)1 << ((unsigned)index2 & 7); + const size_t byteIndex = (size_t)(index2 >> 3); + if (byteIndex >= useMapSize) + return false; + const unsigned m = useMap[byteIndex]; + if (m & flag) + return false; + useMap[byteIndex] = (Byte)(m | flag); + } + } + + /* + UInt64 num = 0; + for (i = 0; i < useMapSize; i++) + { + Byte b = useMap[i]; + unsigned t = 0; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); b >>= 1; + t += (b & 1); + num += t; + } + NumUsed_1MB_Blocks = num; + NumUsed_1MB_Blocks_Defined = true; + */ + + return true; +} + + + +HRESULT CHandler::Open3() +{ + { + const unsigned kHeaderSize = 512; // + 8 + Byte header[kHeaderSize]; + + RINOK(Read_FALSE(header, kHeaderSize)) + + if (memcmp(header, kSignature, kSignatureSize) != 0) + return S_FALSE; + + const Byte *p = &header[0]; + for (unsigned i = kSignatureSize; i < kHeaderSize; i += 2) + { + const wchar_t c = Get16(p + i); + if (c < 0x20 || c > 0x7F) + break; + _creator += c; + } + } + + HeadersSize = (UInt32)1 << 20; + CHeader headers[2]; + { + Byte header[kHeader2Size]; + for (unsigned i = 0; i < 2; i++) + { + RINOK(Seek2((1 << 16) * (1 + i))) + RINOK(Read_FALSE(header, kHeader2Size)) + bool headerIsOK = headers[i].Parse(header); + if (!headerIsOK) + return S_FALSE; + } + } + unsigned mainIndex; + if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0; + else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1; + else + { + /* Disk2vhd v2.02 can create image with 2 full copies of headers. + It's violation of VHDX specification: + "A header is current if it is the only valid header + or if it is valid and its SequenceNumber field is + greater than the other header's SequenceNumber". + but we support such Disk2vhd archives. */ + if (!headers[0].IsEqualTo(headers[1])) + return S_FALSE; + mainIndex = 0; + } + + const CHeader &h = headers[mainIndex]; + Header = h; + if (h.LogLength != 0) + { + HeadersSize += h.LogLength; + UpdatePhySize(h.LogOffset + h.LogLength); + if (!h.Guids[kHeader_GUID_Index_LogGuid].IsZero()) + { + _nonEmptyLog = true; + AddErrorMessage("non-empty LOG was not replayed"); + /* + if (h.LogVersion != 0) + AddErrorMessage("unknown LogVresion"); + else + { + CByteBuffer log; + RINOK(Seek2(h.LogOffset)); + RINOK(ReadToBuf_FALSE(log, h.LogLength)); + if (!ParseLog(log)) + { + return S_FALSE; + } + } + */ + } + } + CRegion regions[2]; + int correctRegionIndex = -1; + + { + CByteBuffer temp; + temp.Alloc(kRegionSize * 2); + RINOK(Seek2((1 << 16) * 3)) + RINOK(Read_FALSE(temp, kRegionSize * 2)) + unsigned numTables = 1; + if (memcmp(temp, temp + kRegionSize, kRegionSize) != 0) + { + AddErrorMessage("Region tables mismatch"); + numTables = 2; + } + + for (unsigned i = 0; i < numTables; i++) + { + // RINOK(Seek2((1 << 16) * (3 + i))); + // RINOK(Read_FALSE(temp, kRegionSize)); + if (regions[i].Parse(temp)) + { + if (correctRegionIndex < 0) + correctRegionIndex = (int)i; + } + else + { + AddErrorMessage("Incorrect region table"); + } + } + if (correctRegionIndex < 0) + return S_FALSE; + /* + if (!regions[0].IsEqualTo(regions[1])) + return S_FALSE; + */ + } + + // UpdatePhySize((1 << 16) * 5); + UpdatePhySize(1 << 20); + + { + const CRegion ®ion = regions[correctRegionIndex]; + HeadersSize += region.DataSize; + UpdatePhySize(region.EndPos); + { + if (!region.Meta_Defined) + return S_FALSE; + const CRegionEntry &e = region.MetaEntry; + if (e.Len == 0) + return S_FALSE; + { + // static const kMetaTableSize = 1 << 16; + CByteBuffer temp; + { + RINOK(Seek2(e.Offset)) + RINOK(ReadToBuf_FALSE(temp, e.Len)) + } + if (!Meta.Parse(temp, temp.Size())) + return S_FALSE; + } + // UpdatePhySize(e.GetEndPos()); + } + { + if (!region.Bat_Defined) + return S_FALSE; + const CRegionEntry &e = region.BatEntry; + if (e.Len == 0) + return S_FALSE; + // UpdatePhySize(e.GetEndPos()); + { + RINOK(Seek2(e.Offset)) + RINOK(ReadToBuf_FALSE(Bat.Data, e.Len)) + } + if (!ParseBat()) + return S_FALSE; + if (!CheckBat()) + { + AddErrorMessage("BAT overlap"); + // _batOverlap = true; + // return S_FALSE; + } + } + } + + { + // do we need to check "parent_linkage2" also? + FOR_VECTOR (i, Meta.ParentPairs) + { + const CParentPair &pair = Meta.ParentPairs[i]; + if (pair.Key.IsEqualTo("parent_linkage")) + { + _parentGuid_IsDefined = _parentGuid.ParseFromFormatedHexString(pair.Value); + break; + } + } + } + + { + // absolute paths for parent stream can be rejected later in client callback + // the order of check by specification: + const char * const g_ParentKeys[] = + { + "relative_path" // "..\..\path2\sub3\parent.vhdx" + , "volume_path" // "\\?\Volume{26A21BDA-A627-11D7-9931-806E6F6E6963}\path2\sub3\parent.vhdx") + , "absolute_win32_path" // "d:\path2\sub3\parent.vhdx" + }; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ParentKeys); i++) + { + const int index = Meta.FindParentKey(g_ParentKeys[i]); + if (index < 0) + continue; + ParentNames.Add(Meta.ParentPairs[index].Value); + } + } + + if (Meta.Is_HasParent()) + { + if (!Meta.Locator_Defined) + AddErrorMessage("Parent locator is not defined"); + else + { + if (!_parentGuid_IsDefined) + AddErrorMessage("Parent GUID is not defined"); + if (ParentNames.IsEmpty()) + AddErrorMessage("Parent VHDX file name is not defined"); + } + } + else + { + if (Meta.Locator_Defined) + AddErrorMessage("Unexpected parent locator"); + } + + // here we suppose that and locator can be used only with HasParent flag + + // return S_FALSE; + + _size = Meta.VirtualDiskSize; // CHandlerImg + + // _posInArc = 0; + // Reset_PosInArc(); + // RINOK(InStream_SeekToBegin(Stream)) + + return S_OK; +} + + +/* +static UInt32 g_NumCalls = 0; +static UInt32 g_NumCalls2 = 0; +static struct CCounter { ~CCounter() +{ + printf("\nNumCalls = %10u\n", g_NumCalls); + printf("NumCalls2 = %10u\n", g_NumCalls2); +} } g_Counter; +*/ + +Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + // g_NumCalls++; + if (processedSize) + *processedSize = 0; + if (_virtPos >= Meta.VirtualDiskSize) + return S_OK; + { + const UInt64 rem = Meta.VirtualDiskSize - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + const size_t blockIndex = (size_t)(_virtPos >> Meta.BlockSize_Log); + const size_t chunkIndex = blockIndex >> ChunkRatio_Log; + const size_t chunkRatio = (size_t)1 << ChunkRatio_Log; + const size_t blockIndex2 = chunkIndex * (chunkRatio + 1) + (blockIndex & (chunkRatio - 1)); + const UInt64 blockSectVal = Bat.GetItem(blockIndex2); + const UInt64 blockOffset = BAT_GET_OFFSET(blockSectVal); + const UInt32 blockState = BAT_GET_STATE(blockSectVal); + + const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log; + const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + size = MyMin(blockSize - offsetInBlock, size); + + bool needParent = false; + bool needRead = false; + + if (blockState == PAYLOAD_BLOCK_FULLY_PRESENT) + needRead = true; + else if (blockState == PAYLOAD_BLOCK_NOT_PRESENT) + { + /* for a differencing VHDX: parent virtual disk SHOULD be + inspected to determine the associated contents (SPECIFICATION). + we suppose that we should not check BitMap. + for fixed or dynamic VHDX files: the block contents are undefined and + can contain arbitrary data (SPECIFICATION). NTFS::pagefile.sys can use such state. */ + if (IsDiff()) + needParent = true; + } + else if (blockState == PAYLOAD_BLOCK_PARTIALLY_PRESENT) + { + // only allowed for differencing VHDX files. + // associated sector bitmap block MUST be valid + if (chunkIndex >= BitMaps.Size()) + return S_FALSE; + // else + { + const CByteBuffer &bitmap = BitMaps[(unsigned)chunkIndex]; + const Byte *p = (const Byte *)bitmap; + if (!p) + return S_FALSE; + // else + { + // g_NumCalls2++; + const UInt64 sectorIndex = _virtPos >> Meta.LogicalSectorSize_Log; + + #define BIT_MAP_UNIT_LOG 3 // it's for small block (4 KB) + // #define BIT_MAP_UNIT_LOG 5 // speed optimization for large blocks (16 KB) + + const size_t offs = (size_t)(sectorIndex >> 3) & + ( + (kBitmapSize - 1) + & ~(((UInt32)1 << (BIT_MAP_UNIT_LOG - 3)) - 1) + ); + + unsigned sector2 = (unsigned)sectorIndex & ((1 << BIT_MAP_UNIT_LOG) - 1); + #if BIT_MAP_UNIT_LOG == 5 + UInt32 v = GetUi32(p + offs) >> sector2; + #else + unsigned v = (unsigned)p[offs] >> sector2; + #endif + // UInt32 v = GetUi32(p + offs) >> sector2; + const UInt32 sectorSize = (UInt32)1 << Meta.LogicalSectorSize_Log; + const UInt32 offsetInSector = (UInt32)_virtPos & (sectorSize - 1); + const unsigned bit = (unsigned)(v & 1); + if (bit) + needRead = true; + else + needParent = true; // zero - from the parent VHDX file + UInt32 rem = sectorSize - offsetInSector; + for (sector2++; sector2 < (1 << BIT_MAP_UNIT_LOG); sector2++) + { + v >>= 1; + if (bit != (v & 1)) + break; + rem += sectorSize; + } + if (size > rem) + size = rem; + } + } + } + + bool needZero = true; + + HRESULT res = S_OK; + + if (needParent) + { + if (!ParentStream) + return S_FALSE; + // if (ParentStream) + { + RINOK(InStream_SeekSet(ParentStream, _virtPos)) + size_t processed = size; + res = ReadStream(ParentStream, (Byte *)data, &processed); + size = (UInt32)processed; + needZero = false; + } + } + else if (needRead) + { + UInt32 processed = 0; + res = ReadPhy(blockOffset + offsetInBlock, data, size, processed); + size = processed; + needZero = false; + } + + if (needZero) + memset(data, 0, size); + + if (processedSize) + *processedSize = size; + + _virtPos += size; + return res; +} + + +enum +{ + kpidParent = kpidUserDefined +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidSectorSize, VT_UI4}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidNumVolumes, VT_UI4}, + { NULL, kpidTotalPhySize, VT_UI8}, + { "Parent", kpidParent, VT_BSTR}, + { NULL, kpidCreatorApp, VT_BSTR}, + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidId, VT_BSTR} + }; + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + + +void CHandler::AddErrorMessage(const char *message) +{ + if (!_errorMessage.IsEmpty()) + _errorMessage.Add_LF(); + _errorMessage += message; +} + +void CHandler::AddErrorMessage(const char *message, const wchar_t *name) +{ + AddErrorMessage(message); + _errorMessage += name; +} + + +static void AddComment_Name(UString &s, const char *name) +{ + s += name; + s += ": "; +} + +static void AddComment_Bool(UString &s, const char *name, bool val) +{ + AddComment_Name(s, name); + s.Add_Char(val ? '+' : '-'); + s.Add_LF(); +} + +static void AddComment_UInt64(UString &s, const char *name, UInt64 v, bool showMB = false) +{ + AddComment_Name(s, name); + s.Add_UInt64(v); + if (showMB) + { + s += " ("; + s.Add_UInt64(v >> 20); + s += " MiB)"; + } + s.Add_LF(); +} + +static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize) +{ + if (logSize != 0) + AddComment_UInt64(s, name, ((UInt64)1 << logSize)); +} + + +void CHandler::AddComment(UString &s) const +{ + AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize); + AddComment_UInt64(s, "PhysicalSize", _phySize); + + if (!_errorMessage.IsEmpty()) + { + AddComment_Name(s, "Error"); + s += _errorMessage; + s.Add_LF(); + } + + if (Meta.Guid_Defined) + { + AddComment_Name(s, "Id"); + Meta.Guid.AddHexToString(s); + s.Add_LF(); + } + + AddComment_UInt64(s, "SequenceNumber", Header.SequenceNumber); + AddComment_UInt64(s, "LogLength", Header.LogLength, true); + + for (unsigned i = 0; i < 3; i++) + { + const CGuid &g = Header.Guids[i]; + if (g.IsZero()) + continue; + if (i == 0) + s += "FileWrite"; + else if (i == 1) + s += "DataWrite"; + else + s += "Log"; + AddComment_Name(s, "Guid"); + g.AddHexToString(s); + s.Add_LF(); + } + + AddComment_Bool(s, "HasParent", Meta.Is_HasParent()); + AddComment_Bool(s, "Fixed", Meta.Is_LeaveBlockAllocated()); + if (Meta.Is_LeaveBlockAllocated()) + AddComment_Bool(s, "DataContiguous", _isDataContiguous); + + AddComment_BlockSize(s, "BlockSize", Meta.BlockSize_Log); + AddComment_BlockSize(s, "LogicalSectorSize", Meta.LogicalSectorSize_Log); + AddComment_BlockSize(s, "PhysicalSectorSize", Meta.PhysicalSectorSize_Log); + + { + const UInt64 packSize = GetPackSize(); + AddComment_UInt64(s, "PackSize", packSize, true); + const UInt64 headersSize = HeadersSize + ((UInt64)NumUsedBitMaps << kBitmapSize_Log); + AddComment_UInt64(s, "HeadersSize", headersSize, true); + AddComment_UInt64(s, "FreeSpace", _phySize - packSize - headersSize, true); + /* + if (NumUsed_1MB_Blocks_Defined) + AddComment_UInt64(s, "used2", (NumUsed_1MB_Blocks << 20)); + */ + } + + if (Meta.ParentPairs.Size() != 0) + { + s += "Parent:"; + s.Add_LF(); + FOR_VECTOR(i, Meta.ParentPairs) + { + const CParentPair &pair = Meta.ParentPairs[i]; + s += " "; + s += pair.Key; + s += ": "; + s += pair.Value; + s.Add_LF(); + } + s.Add_LF(); + } +} + + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidClusterSize: prop = (UInt32)1 << Meta.BlockSize_Log; break; + case kpidSectorSize: prop = (UInt32)1 << Meta.LogicalSectorSize_Log; break; + case kpidShortComment: + case kpidMethod: + { + AString s; + AddTypeString(s); + if (IsDiff()) + { + s += " -> "; + const CHandler *p = this; + while (p && p->IsDiff()) + p = p->Parent; + if (!p) + s += '?'; + else + p->AddTypeString(s); + } + prop = s; + break; + } + case kpidComment: + { + UString s; + { + if (NumLevels > 1) + { + AddComment_UInt64(s, "NumVolumeLevels", NumLevels); + AddComment_UInt64(s, "PackSizeTotal", PackSize_Total, true); + s += "----"; + s.Add_LF(); + } + + const CHandler *p = this; + for (;;) + { + if (p->_level != 0 || p->Parent) + AddComment_UInt64(s, "VolumeLevel", p->_level + 1); + p->AddComment(s); + if (!p->Parent) + break; + s += "----"; + s.Add_LF(); + { + s.Add_LF(); + if (!p->ParentName_Used.IsEmpty()) + { + AddComment_Name(s, "Name"); + s += p->ParentName_Used; + s.Add_LF(); + } + } + p = p->Parent; + } + } + prop = s; + break; + } + case kpidCreatorApp: + { + if (!_creator.IsEmpty()) + prop = _creator; + break; + } + case kpidId: + { + if (Meta.Guid_Defined) + { + UString s; + Meta.Guid.AddHexToString(s); + prop = s; + } + break; + } + case kpidName: + { + if (Meta.Guid_Defined) + { + UString s; + Meta.Guid.AddHexToString(s); + s += ".vhdx"; + prop = s; + } + break; + } + case kpidParent: if (IsDiff()) prop = GetParentSequence(); break; + case kpidPhySize: prop = _phySize; break; + case kpidTotalPhySize: + { + const CHandler *p = this; + UInt64 sum = 0; + do + { + sum += p->_phySize; + p = p->Parent; + } + while (p); + prop = sum; + break; + } + case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break; + case kpidError: + { + UString s; + const CHandler *p = this; + do + { + if (!p->_errorMessage.IsEmpty()) + { + if (!s.IsEmpty()) + s.Add_LF(); + s += p->_errorMessage; + } + p = p->Parent; + } + while (p); + if (!s.IsEmpty()) + prop = s; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) +{ + Stream = stream; + if (_level >= (1 << 20)) + return S_FALSE; + + RINOK(Open3()) + + NumLevels = 1; + PackSize_Total = GetPackSize(); + + if (_child) + { + if (!_child->_parentGuid.IsEqualTo(Header.Guids[kHeader_GUID_Index_DataWriteGuid])) + return S_FALSE; + const CHandler *child = _child; + do + { + /* We suppose that only FileWriteGuid is unique. + Another IDs must be identical in in difference and parent archives. */ + if (Header.Guids[kHeader_GUID_Index_FileWriteGuid].IsEqualTo( + child->Header.Guids[kHeader_GUID_Index_FileWriteGuid]) + && _phySize == child->_phySize) + { + _isCyclic = true; + _isCyclic_or_CyclicParent = true; + AddErrorMessage("Cyclic parent archive was blocked"); + return S_OK; + } + child = child->_child; + } + while (child); + } + + if (!Meta.Is_HasParent()) + return S_OK; + + if (!Meta.Locator_Defined + || !_parentGuid_IsDefined + || ParentNames.IsEmpty()) + { + return S_OK; + } + + ParentName_Used = ParentNames.Front(); + + HRESULT res; + const unsigned kNumLevelsMax = (1 << 8); // Maybe we need to increase that limit + if (_level >= kNumLevelsMax - 1) + { + AddErrorMessage("Too many parent levels"); + return S_OK; + } + + bool _parentFileWasOpen = false; + + if (!openArchiveCallback) + res = S_FALSE; + else + res = OpenParent(openArchiveCallback, _parentFileWasOpen); + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + + if (_parentFileWasOpen) + AddErrorMessage("Can't parse parent VHDX file : ", ParentName_Used); + else + AddErrorMessage("Missing parent VHDX file : ", ParentName_Used); + } + + + return S_OK; +} + + +HRESULT CHandler::OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen) +{ + _parentFileWasOpen = false; + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpenVolumeCallback, + openVolumeCallback, openArchiveCallback) + if (!openVolumeCallback) + return S_FALSE; + { + CMyComPtr nextStream; + HRESULT res = S_FALSE; + UString name; + + FOR_VECTOR (i, ParentNames) + { + name = ParentNames[i]; + + // we remove prefix ".\\', but client already can support any variant + if (name[0] == L'.' && name[1] == L'\\') + name.DeleteFrontal(2); + + res = openVolumeCallback->GetStream(name, &nextStream); + + if (res == S_OK && nextStream) + break; + + if (res != S_OK && res != S_FALSE) + return res; + } + + if (res == S_FALSE || !nextStream) + return S_FALSE; + + ParentName_Used = name; + _parentFileWasOpen = true; + + Parent = new CHandler; + ParentStream = Parent; + + try + { + Parent->_level = _level + 1; + Parent->_child = this; + /* we could call CHandlerImg::Open() here. + but we don't need (_imgExt) in (Parent). So we call Open2() here */ + Parent->Close(); + res = Parent->Open2(nextStream, openArchiveCallback); + } + catch(...) + { + Parent = NULL; + ParentStream.Release(); + res = S_FALSE; + throw; + } + + if (res != S_OK) + { + Parent = NULL; + ParentStream.Release(); + if (res == E_ABORT) + return res; + if (res != S_FALSE) + { + // we must show that error code + } + } + + if (res == S_OK) + { + if (Parent->_isCyclic_or_CyclicParent) + _isCyclic_or_CyclicParent = true; + + NumLevels = Parent->NumLevels + 1; + PackSize_Total += Parent->GetPackSize(); + + // we read BitMaps only if Parent was open + + UInt64 numBytes = (UInt64)NumUsedBitMaps << kBitmapSize_Log; + if (openArchiveCallback && numBytes != 0) + { + RINOK(openArchiveCallback->SetTotal(NULL, &numBytes)) + } + numBytes = 0; + for (size_t i = ChunkRatio; i < TotalBatEntries; i += ChunkRatio + 1) + { + const UInt64 v = Bat.GetItem(i); + const UInt64 offset = BAT_GET_OFFSET(v); + const unsigned state = BAT_GET_STATE(v); + + CByteBuffer &buf = BitMaps.AddNew(); + if (state == SB_BLOCK_PRESENT) + { + if (openArchiveCallback) + { + RINOK(openArchiveCallback->SetCompleted(NULL, &numBytes)) + } + numBytes += kBitmapSize; + buf.Alloc(kBitmapSize); + RINOK(Seek2(offset)) + RINOK(Read_FALSE(buf, kBitmapSize)) + /* + for (unsigned i = 0; i < (1 << 20); i+=4) + { + UInt32 v = GetUi32(buf + i); + if (v != 0 && v != (UInt32)(Int32)-1) + printf("\n%7d %8x", i, v); + } + */ + } + } + } + } + + return S_OK; +} + + +void CHandler::CloseAtError() +{ + // CHandlerImg + Clear_HandlerImg_Vars(); + Stream.Release(); + + _phySize = 0; + Bat.Clear(); + BitMaps.Clear(); + NumUsedBlocks = 0; + NumUsedBitMaps = 0; + HeadersSize = 0; + /* + NumUsed_1MB_Blocks = 0; + NumUsed_1MB_Blocks_Defined = false; + */ + + Parent = NULL; + ParentStream.Release(); + _errorMessage.Empty(); + _creator.Empty(); + _nonEmptyLog = false; + _parentGuid_IsDefined = false; + _isDataContiguous = false; + // _batOverlap = false; + + ParentNames.Clear(); + ParentName_Used.Empty(); + + Meta.Clear(); + + ChunkRatio_Log = 0; + ChunkRatio = 0; + TotalBatEntries = 0; + NumLevels = 0; + PackSize_Total = 0; + + _isCyclic = false; + _isCyclic_or_CyclicParent = false; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + CloseAtError(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = Meta.VirtualDiskSize; break; + case kpidPackSize: prop = PackSize_Total; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + // if some prarent is not OK, we don't create stream + if (!AreParentsOK()) + return S_FALSE; + InitSeekPositions(); + CMyComPtr streamTemp = this; + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + +REGISTER_ARC_I( + "VHDX", "vhdx avhdx", NULL, 0xc4, + kSignature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp index 9b3d52968..9c293a3c7 100644 --- a/CPP/7zip/Archive/VmdkHandler.cpp +++ b/CPP/7zip/Archive/VmdkHandler.cpp @@ -1,1527 +1,1527 @@ -// VmdkHandler.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/IntToString.h" -#include "../../Common/StringConvert.h" -#include "../../Common/StringToInt.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/ZlibDecoder.h" - -#include "HandlerCont.h" - -using namespace NWindows; - -namespace NArchive { -namespace NVmdk { - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define LE_16(offs, dest) dest = Get16(p + (offs)) -#define LE_32(offs, dest) dest = Get32(p + (offs)) -#define LE_64(offs, dest) dest = Get64(p + (offs)) - - -static const Byte k_Signature[] = { 'K', 'D', 'M', 'V' }; - -static const UInt32 k_Flags_NL = (UInt32)1 << 0; -// static const UInt32 k_Flags_RGD = (UInt32)1 << 1; -static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2; -static const UInt32 k_Flags_Compressed = (UInt32)1 << 16; -static const UInt32 k_Flags_Marker = (UInt32)1 << 17; - -static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table - -struct CHeader -{ - UInt32 flags; - UInt32 version; - - UInt64 capacity; - UInt64 grainSize; - UInt64 descriptorOffset; - UInt64 descriptorSize; - - UInt32 numGTEsPerGT; - UInt16 algo; - // Byte uncleanShutdown; - // UInt64 rgdOffset; - UInt64 gdOffset; - UInt64 overHead; - - bool Is_NL() const { return (flags & k_Flags_NL) != 0; } - bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; } - bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; } - bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; } - - bool Parse(const Byte *p); - - bool IsSameImageFor(const CHeader &h) const - { - return flags == h.flags - && version == h.version - && capacity == h.capacity - && grainSize == h.grainSize - && algo == h.algo; - } -}; - -bool CHeader::Parse(const Byte *p) -{ - if (memcmp(p, k_Signature, sizeof(k_Signature)) != 0) - return false; - - LE_32 (0x04, version); - LE_32 (0x08, flags); - LE_64 (0x0C, capacity); - LE_64 (0x14, grainSize); - LE_64 (0x1C, descriptorOffset); - LE_64 (0x24, descriptorSize); - LE_32 (0x2C, numGTEsPerGT); - // LE_64 (0x30, rgdOffset); - LE_64 (0x38, gdOffset); - LE_64 (0x40, overHead); - // uncleanShutdown = buf[0x48]; - LE_16(0x4D, algo); - - if (Is_NL() && Get32(p + 0x49) != 0x0A0D200A) // do we need Is_NL() check here? - return false; - - return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3); -} - - -enum -{ - k_Marker_END_OF_STREAM = 0, - k_Marker_GRAIN_TABLE = 1, - k_Marker_GRAIN_DIR = 2, - k_Marker_FOOTER = 3 -}; - -struct CMarker -{ - UInt64 NumSectors; - UInt32 SpecSize; // = 0 for metadata sectors - UInt32 Type; - - void Parse(const Byte *p) - { - LE_64 (0, NumSectors); - LE_32 (8, SpecSize); - LE_32 (12, Type); - } -}; - - -static bool Str_to_ValName(const AString &s, AString &name, AString &val) -{ - name.Empty(); - val.Empty(); - int qu = s.Find('"'); - int eq = s.Find('='); - if (eq < 0 || (qu >= 0 && eq > qu)) - return false; - name.SetFrom(s.Ptr(), eq); - name.Trim(); - val = s.Ptr(eq + 1); - val.Trim(); - return true; -} - -static inline bool IsSpaceChar(char c) -{ - return (c == ' ' || c == '\t'); -} - -static const char *SkipSpaces(const char *s) -{ - for (;; s++) - { - char c = *s; - if (c == 0 || !IsSpaceChar(c)) - return s; - } -} - -#define SKIP_SPACES(s) s = SkipSpaces(s); - -static const char *GetNextWord(const char *s, AString &dest) -{ - dest.Empty(); - SKIP_SPACES(s) - const char *start = s; - for (;; s++) - { - char c = *s; - if (c == 0 || IsSpaceChar(c)) - { - dest.SetFrom(start, (unsigned)(s - start)); - return s; - } - } -} - -static const char *GetNextNumber(const char *s, UInt64 &val) -{ - SKIP_SPACES(s) - if (*s == 0) - return s; - const char *end; - val = ConvertStringToUInt64(s, &end); - char c = *end; - if (c != 0 && !IsSpaceChar(c)) - return NULL; - return end; -} - - -struct CExtentInfo -{ - AString Access; // RW, RDONLY, or NOACCESS - UInt64 NumSectors; // 512 bytes sectors - AString Type; // FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, VMFSRAW - AString FileName; - UInt64 StartSector; // used for FLAT - - // for VMWare Player 9: - // PartitionUUID - // DeviceIdentifier - - bool IsType_ZERO() const { return Type == "ZERO"; } - // bool IsType_FLAT() const { return Type == "FLAT"; } - bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; } - - bool Parse(const char *s); -}; - -bool CExtentInfo::Parse(const char *s) -{ - NumSectors = 0; - StartSector = 0; - Access.Empty(); - Type.Empty(); - FileName.Empty(); - - s = GetNextWord(s, Access); - s = GetNextNumber(s, NumSectors); - if (!s) - return false; - s = GetNextWord(s, Type); - - if (Type.IsEmpty()) - return false; - - SKIP_SPACES(s) - - if (IsType_ZERO()) - return (*s == 0); - - if (*s != '\"') - return false; - s++; - { - const char *s2 = strchr(s, '\"'); - if (!s2) - return false; - FileName.SetFrom(s, (unsigned)(s2 - s)); - s = s2 + 1; - } - SKIP_SPACES(s) - if (*s == 0) - return true; - - s = GetNextNumber(s, StartSector); - if (!s) - return false; - return true; - // SKIP_SPACES(s); - // return (*s == 0); -} - - -struct CDescriptor -{ - AString CID; - AString parentCID; - AString createType; - // AString encoding; // UTF-8, windows-1252 - default is UTF-8 - - CObjectVector Extents; - - static void GetUnicodeName(const AString &s, UString &res) - { - if (!ConvertUTF8ToUnicode(s, res)) - MultiByteToUnicodeString2(res, s); - } - - void Clear() - { - CID.Empty(); - parentCID.Empty(); - createType.Empty(); - Extents.Clear(); - } - - bool IsThere_Parent() const - { - return !parentCID.IsEmpty() && !parentCID.IsEqualTo_Ascii_NoCase("ffffffff"); - } - - bool Parse(const Byte *p, size_t size); -}; - - -bool CDescriptor::Parse(const Byte *p, size_t size) -{ - Clear(); - - AString s; - AString name; - AString val; - - for (;;) - { - Byte c = 0; - if (size != 0) - { - size--; - c = *p++; - } - if (c == 0 || c == 0xA || c == 0xD) - { - if (!s.IsEmpty() && s[0] != '#') - { - if (Str_to_ValName(s, name, val)) - { - if (name.IsEqualTo_Ascii_NoCase("CID")) - CID = val; - else if (name.IsEqualTo_Ascii_NoCase("parentCID")) - parentCID = val; - else if (name.IsEqualTo_Ascii_NoCase("createType")) - createType = val; - } - else - { - CExtentInfo ei; - if (!ei.Parse(s)) - return false; - Extents.Add(ei); - } - } - - s.Empty(); - if (c == 0) - return true; - } - else - s += (char)c; - } -} - - -struct CExtent -{ - bool IsOK; - bool IsArc; - bool NeedDeflate; - bool Unsupported; - bool IsZero; - bool IsFlat; - bool DescriptorOK; - bool HeadersError; - - unsigned ClusterBits; - UInt32 ZeroSector; - - CObjectVector Tables; - - CMyComPtr Stream; - UInt64 PosInArc; - - UInt64 PhySize; - UInt64 VirtSize; // from vmdk header of volume - - UInt64 StartOffset; // virtual offset of this extent - UInt64 NumBytes; // from main descriptor, if multi-vol - UInt64 FlatOffset; // in Stream - - CByteBuffer DescriptorBuf; - CDescriptor Descriptor; - - CHeader h; - - UInt64 GetEndOffset() const { return StartOffset + NumBytes; } - - bool IsVmdk() const { return !IsZero && !IsFlat; } - // if (IsOK && IsVmdk()), then VMDK header of this extent was read - - CExtent(): - IsOK(false), - IsArc(false), - NeedDeflate(false), - Unsupported(false), - IsZero(false), - IsFlat(false), - DescriptorOK(false), - HeadersError(false), - - ClusterBits(0), - ZeroSector(0), - - PosInArc(0), - - PhySize(0), - VirtSize(0), - - StartOffset(0), - NumBytes(0), - FlatOffset(0) - {} - - - HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors); - HRESULT Open3(IInStream *stream, IArchiveOpenCallback *openCallback, - unsigned numVols, unsigned volIndex, UInt64 &complexity); - - HRESULT Seek(UInt64 offset) - { - PosInArc = offset; - return InStream_SeekSet(Stream, offset); - } - - HRESULT InitAndSeek() - { - if (Stream) - return Seek(0); - return S_OK; - } - - HRESULT Read(void *data, size_t *size) - { - HRESULT res = ReadStream(Stream, data, size); - PosInArc += *size; - return res; - } -}; - - -Z7_class_CHandler_final: public CHandlerImg -{ - bool _isArc; - bool _unsupported; - bool _unsupportedSome; - bool _headerError; - bool _missingVol; - bool _isMultiVol; - bool _needDeflate; - - UInt64 _cacheCluster; - unsigned _cacheExtent; - CByteBuffer _cache; - CByteBuffer _cacheCompressed; - - unsigned _clusterBitsMax; - UInt64 _phySize; - - CObjectVector _extents; - - CBufInStream *_bufInStreamSpec; - CMyComPtr _bufInStream; - - CBufPtrSeqOutStream *_bufOutStreamSpec; - CMyComPtr _bufOutStream; - - NCompress::NZlib::CDecoder *_zlibDecoderSpec; - CMyComPtr _zlibDecoder; - - CByteBuffer _descriptorBuf; - CDescriptor _descriptor; - - UString _missingVolName; - - void InitAndSeekMain() - { - _virtPos = 0; - } - - virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; - virtual void CloseAtError() Z7_override; -public: - Z7_IFACE_COM7_IMP(IInArchive_Img) - - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) -}; - - -Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= _size) - return S_OK; - { - UInt64 rem = _size - _virtPos; - if (size > rem) - size = (UInt32)rem; - if (size == 0) - return S_OK; - } - - unsigned extentIndex; - { - unsigned left = 0, right = _extents.Size(); - for (;;) - { - unsigned mid = (left + right) / 2; - if (mid == left) - break; - if (_virtPos < _extents[mid].StartOffset) - right = mid; - else - left = mid; - } - extentIndex = left; - } - - CExtent &extent = _extents[extentIndex]; - - { - const UInt64 vir = _virtPos - extent.StartOffset; - if (vir >= extent.NumBytes) - { - return E_FAIL; - /* - if (vir > extent.NumBytes) - _stream_dataError = true; - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - */ - } - - { - const UInt64 rem = extent.NumBytes - vir; - if (size > rem) - size = (UInt32)rem; - } - - if (vir >= extent.VirtSize) - { - // if vmdk's VirtSize is smaller than VirtSize from main multi-volume descriptor - _stream_dataError = true; - return S_FALSE; - /* - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - */ - } - - { - const UInt64 rem = extent.VirtSize - vir; - if (size > rem) - size = (UInt32)rem; - } - - if (extent.IsZero || !extent.IsOK || !extent.Stream || extent.Unsupported) - { - if (extent.Unsupported) - { - _stream_unsupportedMethod = true; - return S_FALSE; - } - if (!extent.IsOK || !extent.Stream) - { - _stream_unavailData = true; - return S_FALSE; - } - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } - - if (extent.IsFlat) - { - UInt64 offset = extent.FlatOffset + vir; - if (offset != extent.PosInArc) - { - RINOK(extent.Seek(offset)) - } - UInt32 size2 = 0; - HRESULT res = extent.Stream->Read(data, size, &size2); - if (res == S_OK && size2 == 0) - { - _stream_unavailData = true; - /* - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - */ - } - // _stream_PackSize += size2; - extent.PosInArc += size2; - _virtPos += size2; - if (processedSize) - *processedSize = size2; - return res; - } - } - - - for (;;) - { - const UInt64 vir = _virtPos - extent.StartOffset; - const unsigned clusterBits = extent.ClusterBits; - const UInt64 cluster = vir >> clusterBits; - const size_t clusterSize = (size_t)1 << clusterBits; - const size_t lowBits = (size_t)vir & (clusterSize - 1); - { - size_t rem = clusterSize - lowBits; - if (size > rem) - size = (UInt32)rem; - } - - if (extentIndex == _cacheExtent && cluster == _cacheCluster) - { - memcpy(data, _cache + lowBits, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } - - const UInt64 high = cluster >> k_NumMidBits; - - if (high < extent.Tables.Size()) - { - const CByteBuffer &table = extent.Tables[(unsigned)high]; - - if (table.Size() != 0) - { - const size_t midBits = (size_t)cluster & ((1 << k_NumMidBits) - 1); - const Byte *p = (const Byte *)table + (midBits << 2); - const UInt32 v = Get32(p); - - if (v != 0 && v != extent.ZeroSector) - { - UInt64 offset = (UInt64)v << 9; - if (extent.NeedDeflate) - { - if (offset != extent.PosInArc) - { - // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc)); - RINOK(extent.Seek(offset)) - } - - const size_t kStartSize = 1 << 9; - { - size_t curSize = kStartSize; - RINOK(extent.Read(_cacheCompressed, &curSize)) - // _stream_PackSize += curSize; - if (curSize != kStartSize) - return S_FALSE; - } - - if (Get64(_cacheCompressed) != (cluster << (clusterBits - 9))) - return S_FALSE; - - UInt32 dataSize = Get32(_cacheCompressed + 8); - if (dataSize > ((UInt32)1 << 31)) - return S_FALSE; - - size_t dataSize2 = (size_t)dataSize + 12; - - if (dataSize2 > kStartSize) - { - dataSize2 = (dataSize2 + 511) & ~(size_t)511; - if (dataSize2 > _cacheCompressed.Size()) - return S_FALSE; - size_t curSize = dataSize2 - kStartSize; - const size_t curSize2 = curSize; - RINOK(extent.Read(_cacheCompressed + kStartSize, &curSize)) - // _stream_PackSize += curSize; - if (curSize != curSize2) - return S_FALSE; - } - - _bufInStreamSpec->Init(_cacheCompressed + 12, dataSize); - - _cacheCluster = (UInt64)(Int64)-1; - _cacheExtent = (unsigned)(int)-1; - - if (_cache.Size() < clusterSize) - return E_FAIL; - _bufOutStreamSpec->Init(_cache, clusterSize); - - // Do we need to use smaller block than clusterSize for last cluster? - const UInt64 blockSize64 = clusterSize; - HRESULT res = _zlibDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); - - /* - if (_bufOutStreamSpec->GetPos() != clusterSize) - { - _stream_dataError = true; - memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); - } - */ - - if (_bufOutStreamSpec->GetPos() != clusterSize - || _zlibDecoderSpec->GetInputProcessedSize() != dataSize) - { - _stream_dataError = true; - if (res == S_OK) - res = S_FALSE; - } - - RINOK(res) - - _cacheCluster = cluster; - _cacheExtent = extentIndex; - - continue; - /* - memcpy(data, _cache + lowBits, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - */ - } - { - offset += lowBits; - if (offset != extent.PosInArc) - { - // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc)); - RINOK(extent.Seek(offset)) - } - UInt32 size2 = 0; - HRESULT res = extent.Stream->Read(data, size, &size2); - if (res == S_OK && size2 == 0) - { - _stream_unavailData = true; - /* - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - */ - } - extent.PosInArc += size2; - // _stream_PackSize += size2; - _virtPos += size2; - if (processedSize) - *processedSize = size2; - return res; - } - } - } - } - - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } -} - - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumVolumes, - kpidTotalPhySize, - kpidMethod, - kpidClusterSize, - kpidHeadersSize, - kpidId, - kpidName, - kpidComment -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CExtent *e = NULL; - const CDescriptor *desc = NULL; - - if (_isMultiVol) - desc = &_descriptor; - else if (_extents.Size() == 1) - { - e = &_extents[0]; - desc = &e->Descriptor; - } - - switch (propID) - { - case kpidMainSubfile: prop = (UInt32)0; break; - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - case kpidTotalPhySize: - { - UInt64 sum = _phySize; - if (_isMultiVol) - { - FOR_VECTOR (i, _extents) - sum += _extents[i].PhySize; - } - prop = sum; - break; - } - case kpidClusterSize: prop = (UInt32)((UInt32)1 << _clusterBitsMax); break; - case kpidHeadersSize: if (e) prop = (e->h.overHead << 9); break; - case kpidMethod: - { - AString s; - - if (desc && !desc->createType.IsEmpty()) - s = desc->createType; - - bool zlib = false; - bool marker = false; - Int32 algo = -1; - - FOR_VECTOR (i, _extents) - { - const CExtent &extent = _extents[i]; - if (!extent.IsOK || !extent.IsVmdk()) - continue; - - const CHeader &h = extent.h; - - if (h.algo != 0) - { - if (h.algo == 1) - zlib = true; - else if (algo != h.algo) - { - s.Add_Space_if_NotEmpty(); - s.Add_UInt32(h.algo); - algo = h.algo; - } - } - - if (h.Is_Marker()) - marker = true; - } - - if (zlib) - s.Add_OptSpaced("zlib"); - - if (marker) - s.Add_OptSpaced("Marker"); - - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidComment: - { - if (e && e->DescriptorBuf.Size() != 0) - { - AString s; - s.SetFrom_CalcLen((const char *)(const Byte *)e->DescriptorBuf, (unsigned)e->DescriptorBuf.Size()); - if (!s.IsEmpty() && s.Len() <= (1 << 16)) - prop = s; - } - break; - } - - case kpidId: - { - if (desc && !desc->CID.IsEmpty()) - { - prop = desc->CID; - } - break; - } - - case kpidName: - { - if (!_isMultiVol && desc && desc->Extents.Size() == 1) - { - const CExtentInfo &ei = desc->Extents[0]; - if (!ei.FileName.IsEmpty()) - { - UString u; - CDescriptor::GetUnicodeName(ei.FileName, u); - if (!u.IsEmpty()) - prop = u; - } - } - break; - } - - case kpidNumVolumes: if (_isMultiVol) prop = (UInt32)_extents.Size(); break; - - case kpidError: - { - if (_missingVol || !_missingVolName.IsEmpty()) - { - UString s ("Missing volume : "); - if (!_missingVolName.IsEmpty()) - s += _missingVolName; - prop = s; - } - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; - if (_unsupportedSome) v |= kpv_ErrorFlags_UnsupportedMethod; - if (_headerError) v |= kpv_ErrorFlags_HeadersError; - // if (_missingVol) v |= kpv_ErrorFlags_UnexpectedEnd; - if (v != 0) - prop = v; - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - switch (propID) - { - case kpidSize: prop = _size; break; - case kpidPackSize: - { - UInt64 packSize = 0; - FOR_VECTOR (i, _extents) - { - const CExtent &e = _extents[i]; - if (!e.IsOK) - continue; - if (e.IsVmdk() && !_isMultiVol) - { - UInt64 ov = (e.h.overHead << 9); - if (e.PhySize >= ov) - packSize += e.PhySize - ov; - } - else - packSize += e.PhySize; - } - prop = packSize; - break; - } - case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -static int inline GetLog(UInt64 num) -{ - for (int i = 0; i < 64; i++) - if (((UInt64)1 << i) == num) - return i; - return -1; -} - - -HRESULT CExtent::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors) -{ - sector <<= 9; - RINOK(InStream_SeekSet(stream, sector)) - size_t size = numSectors << 9; - RINOK(ReadStream_FALSE(stream, data, size)) - UInt64 end = sector + size; - if (PhySize < end) - PhySize = end; - return S_OK; -} - - -void CHandler::CloseAtError() -{ - _extents.Clear(); - CHandlerImg::CloseAtError(); -} - - -static const char * const kSignature_Descriptor = "# Disk DescriptorFile"; - - -HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) -{ - const unsigned kSectoreSize = 512; - Byte buf[kSectoreSize]; - size_t headerSize = kSectoreSize; - RINOK(ReadStream(stream, buf, &headerSize)) - - if (headerSize < sizeof(k_Signature)) - return S_FALSE; - - CMyComPtr volumeCallback; - - if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) - { - const size_t k_SigDesc_Size = strlen(kSignature_Descriptor); - if (headerSize < k_SigDesc_Size) - return S_FALSE; - if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) != 0) - return S_FALSE; - - UInt64 endPos; - RINOK(InStream_GetSize_SeekToEnd(stream, endPos)) - if (endPos > (1 << 20)) - return S_FALSE; - const size_t numBytes = (size_t)endPos; - _descriptorBuf.Alloc(numBytes); - RINOK(InStream_SeekToBegin(stream)) - RINOK(ReadStream_FALSE(stream, _descriptorBuf, numBytes)) - - if (!_descriptor.Parse(_descriptorBuf, _descriptorBuf.Size())) - return S_FALSE; - _isMultiVol = true; - _isArc = true; - _phySize = numBytes; - if (_descriptor.IsThere_Parent()) - _unsupported = true; - - if (openCallback) - { - openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); - } - if (!volumeCallback) - { - _unsupported = true; - return E_NOTIMPL; - } - - /* - UInt64 totalVirtSize = 0; - FOR_VECTOR (i, _descriptor.Extents) - { - const CExtentInfo &ei = _descriptor.Extents[i]; - if (ei.NumSectors >= ((UInt64)1 << (63 - 9))) - return S_FALSE; - totalVirtSize += ei.NumSectors; - if (totalVirtSize >= ((UInt64)1 << (63 - 9))) - return S_FALSE; - } - totalVirtSize <<= 9; - */ - - if (_descriptor.Extents.Size() > 1) - { - const UInt64 numFiles = _descriptor.Extents.Size(); - RINOK(openCallback->SetTotal(&numFiles, NULL)) - } - } - - UInt64 complexity = 0; - - for (;;) - { - CExtent *e = NULL; - CMyComPtr nextStream; - - if (_isMultiVol) - { - const unsigned extentIndex = _extents.Size(); - if (extentIndex >= _descriptor.Extents.Size()) - break; - const CExtentInfo &ei = _descriptor.Extents[extentIndex]; - e = &_extents.AddNew(); - e->StartOffset = 0; - if (ei.NumSectors >= ((UInt64)1 << (62 - 9)) || - ei.StartSector >= ((UInt64)1 << (62 - 9))) - return S_FALSE; - e->NumBytes = ei.NumSectors << 9; - e->IsZero = ei.IsType_ZERO(); - if (extentIndex != 0) - e->StartOffset = _extents[extentIndex - 1].GetEndOffset(); - if (e->GetEndOffset() < e->StartOffset) - return S_FALSE; - - e->VirtSize = e->NumBytes; - if (e->IsZero) - { - e->IsOK = true; - continue; - } - - e->IsFlat = ei.IsType_Flat(); - e->FlatOffset = ei.StartSector << 9; - - UString u; - CDescriptor::GetUnicodeName(ei.FileName, u); - if (u.IsEmpty()) - { - _missingVol = true; - continue; - } - - HRESULT result = volumeCallback->GetStream(u, &nextStream); - - if (result != S_OK && result != S_FALSE) - return result; - - if (!nextStream || result != S_OK) - { - if (_missingVolName.IsEmpty()) - _missingVolName = u; - _missingVol = true; - continue; - } - - if (e->IsFlat) - { - e->IsOK = true; - e->Stream = nextStream; - e->PhySize = e->NumBytes; - continue; - } - - stream = nextStream; - - headerSize = kSectoreSize; - RINOK(ReadStream(stream, buf, &headerSize)) - - if (headerSize != kSectoreSize) - continue; - if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) - continue; - } - else - { - if (headerSize != kSectoreSize) - return S_FALSE; - e = &_extents.AddNew(); - e->StartOffset = 0; - } - - HRESULT res = S_FALSE; - if (e->h.Parse(buf)) - res = e->Open3(stream, openCallback, _isMultiVol ? _descriptor.Extents.Size() : 1, _extents.Size() - 1, complexity); - - if (!_isMultiVol) - { - _isArc = e->IsArc; - _phySize = e->PhySize; - _unsupported = e->Unsupported; - } - - if (e->Unsupported) - _unsupportedSome = true; - if (e->HeadersError) - _headerError = true; - - if (res != S_OK) - { - if (res != S_FALSE) - return res; - if (!_isMultiVol) - return res; - continue; - } - - e->Stream = stream; - e->IsOK = true; - - if (!_isMultiVol) - { - e->NumBytes = e->VirtSize; - break; - } - - if (e->NumBytes != e->VirtSize) - _headerError = true; - } - - if (!_extents.IsEmpty()) - _size = _extents.Back().GetEndOffset(); - - _needDeflate = false; - _clusterBitsMax = 0; - - // unsigned numOKs = 0; - unsigned numUnsupported = 0; - - FOR_VECTOR (i, _extents) - { - const CExtent &e = _extents[i]; - if (e.Unsupported) - numUnsupported++; - if (!e.IsOK) - continue; - // numOKs++; - if (e.IsVmdk()) - { - if (e.NeedDeflate) - _needDeflate = true; - if (_clusterBitsMax < e.ClusterBits) - _clusterBitsMax = e.ClusterBits; - } - } - - if (numUnsupported != 0 && numUnsupported == _extents.Size()) - _unsupported = true; - - return S_OK; -} - - -HRESULT CExtent::Open3(IInStream *stream, IArchiveOpenCallback *openCallback, - unsigned numVols, unsigned volIndex, UInt64 &complexity) -{ - if (h.descriptorSize != 0) - { - if (h.descriptorOffset == 0 || - h.descriptorSize > (1 << 10)) - return S_FALSE; - DescriptorBuf.Alloc((size_t)h.descriptorSize << 9); - RINOK(ReadForHeader(stream, h.descriptorOffset, DescriptorBuf, (size_t)h.descriptorSize)) - if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(DescriptorBuf) == 0) - { - // We check data as end marker. - // and if probably it's footer's copy of header, we don't want to open it. - return S_FALSE; - } - - DescriptorOK = Descriptor.Parse(DescriptorBuf, DescriptorBuf.Size()); - if (!DescriptorOK) - HeadersError = true; - if (Descriptor.IsThere_Parent()) - Unsupported = true; - } - - if (h.gdOffset == (UInt64)(Int64)-1) - { - // Grain Dir is at end of file - UInt64 endPos; - RINOK(InStream_GetSize_SeekToEnd(stream, endPos)) - if ((endPos & 511) != 0) - return S_FALSE; - - const size_t kEndSize = 512 * 3; - Byte buf2[kEndSize]; - if (endPos < kEndSize) - return S_FALSE; - RINOK(InStream_SeekSet(stream, endPos - kEndSize)) - RINOK(ReadStream_FALSE(stream, buf2, kEndSize)) - - CHeader h2; - if (!h2.Parse(buf2 + 512)) - return S_FALSE; - if (!h.IsSameImageFor(h2)) - return S_FALSE; - - h = h2; - - CMarker m; - m.Parse(buf2); - if (m.NumSectors != 1 || m.SpecSize != 0 || m.Type != k_Marker_FOOTER) - return S_FALSE; - m.Parse(buf2 + 512 * 2); - if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM) - return S_FALSE; - PhySize = endPos; - } - - const int grainSize_Log = GetLog(h.grainSize); - if (grainSize_Log < 3 || grainSize_Log > 30 - 9) // grain size must be >= 4 KB - return S_FALSE; - if (h.capacity >= ((UInt64)1 << (63 - 9))) - return S_FALSE; - if (h.overHead >= ((UInt64)1 << (63 - 9))) - return S_FALSE; - - IsArc = true; - ClusterBits = (9 + (unsigned)grainSize_Log); - VirtSize = h.capacity << 9; - NeedDeflate = (h.algo >= 1); - - if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0)) - { - Unsupported = true; - PhySize = 0; - return S_FALSE; - } - - { - const UInt64 overHeadBytes = h.overHead << 9; - if (PhySize < overHeadBytes) - PhySize = overHeadBytes; - } - - ZeroSector = 0; - if (h.Is_ZeroGrain()) - ZeroSector = 1; - - const UInt64 numSectorsPerGde = (UInt64)1 << ((unsigned)grainSize_Log + k_NumMidBits); - const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> ((unsigned)grainSize_Log + k_NumMidBits); - CByteBuffer table; - - if (numGdeEntries != 0) - { - if (h.gdOffset == 0) - return S_FALSE; - - size_t numSectors = (size_t)((numGdeEntries + ((1 << (9 - 2)) - 1)) >> (9 - 2)); - size_t t1SizeBytes = numSectors << 9; - if ((t1SizeBytes >> 2) < numGdeEntries) - return S_FALSE; - table.Alloc(t1SizeBytes); - - if (h.Is_Marker()) - { - Byte buf2[1 << 9]; - if (ReadForHeader(stream, h.gdOffset - 1, buf2, 1) != S_OK) - return S_FALSE; - { - CMarker m; - m.Parse(buf2); - if (m.Type != k_Marker_GRAIN_DIR - || m.NumSectors != numSectors - || m.SpecSize != 0) - return S_FALSE; - } - } - - RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors)) - } - - const size_t clusterSize = (size_t)1 << ClusterBits; - - const UInt64 complexityStart = complexity; - - if (openCallback) - { - complexity += (UInt64)numGdeEntries << (k_NumMidBits + 2); - { - const UInt64 numVols2 = numVols; - RINOK(openCallback->SetTotal((numVols == 1) ? NULL : &numVols2, &complexity)) - } - if (numVols != 1) - { - const UInt64 volIndex2 = volIndex; - RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &complexityStart)) - } - } - - UInt64 lastSector = 0; - UInt64 lastVirtCluster = 0; - size_t numProcessed_Prev = 0; - - for (size_t i = 0; i < numGdeEntries; i++) - { - const size_t k_NumSectors = (size_t)1 << (k_NumMidBits - 9 + 2); - const size_t k_NumMidItems = (size_t)1 << k_NumMidBits; - - CByteBuffer &buf = Tables.AddNew(); - - { - const UInt32 v = Get32((const Byte *)table + (size_t)i * 4); - if (v == 0 || v == ZeroSector) - continue; - if (openCallback && (i - numProcessed_Prev) >= 1024) - { - const UInt64 comp = complexityStart + ((UInt64)i << (k_NumMidBits + 2)); - const UInt64 volIndex2 = volIndex; - RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &comp)) - numProcessed_Prev = i; - } - - if (h.Is_Marker()) - { - Byte buf2[1 << 9]; - if (ReadForHeader(stream, v - 1, buf2, 1) != S_OK) - return S_FALSE; - { - CMarker m; - m.Parse(buf2); - if (m.Type != k_Marker_GRAIN_TABLE - || m.NumSectors != k_NumSectors - || m.SpecSize != 0) - return S_FALSE; - } - } - - buf.Alloc(k_NumMidItems * 4); - RINOK(ReadForHeader(stream, v, buf, k_NumSectors)) - } - - for (size_t k = 0; k < k_NumMidItems; k++) - { - const UInt32 v = Get32((const Byte *)buf + (size_t)k * 4); - if (v == 0 || v == ZeroSector) - continue; - if (v < h.overHead) - return S_FALSE; - if (lastSector < v) - { - lastSector = v; - if (NeedDeflate) - lastVirtCluster = ((UInt64)i << k_NumMidBits) + k; - } - } - } - - if (!NeedDeflate) - { - UInt64 end = ((UInt64)lastSector << 9) + clusterSize; - if (PhySize < end) - PhySize = end; - } - else if (lastSector != 0) - { - Byte buf[1 << 9]; - if (ReadForHeader(stream, lastSector, buf, 1) == S_OK) - { - UInt64 lba = Get64(buf); - if (lba == (lastVirtCluster << (ClusterBits - 9))) - { - UInt32 dataSize = Get32(buf + 8); - size_t dataSize2 = (size_t)dataSize + 12; - dataSize2 = (dataSize2 + 511) & ~(size_t)511; - UInt64 end = ((UInt64)lastSector << 9) + dataSize2; - if (PhySize < end) - PhySize = end; - } - } - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - - _cacheCluster = (UInt64)(Int64)-1; - _cacheExtent = (unsigned)(int)-1; - - _clusterBitsMax = 0; - - _isArc = false; - _unsupported = false; - _unsupportedSome = false; - _headerError = false; - _missingVol = false; - _isMultiVol = false; - _needDeflate = false; - - _missingVolName.Empty(); - - _descriptorBuf.Free(); - _descriptor.Clear(); - - // CHandlerImg: - Clear_HandlerImg_Vars(); - Stream.Release(); - - _extents.Clear(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - *stream = NULL; - - if (_unsupported) - return S_FALSE; - - ClearStreamVars(); - // _stream_UsePackSize = true; - - if (_needDeflate) - { - if (!_bufInStream) - { - _bufInStreamSpec = new CBufInStream; - _bufInStream = _bufInStreamSpec; - } - - if (!_bufOutStream) - { - _bufOutStreamSpec = new CBufPtrSeqOutStream(); - _bufOutStream = _bufOutStreamSpec; - } - - if (!_zlibDecoder) - { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder; - _zlibDecoder = _zlibDecoderSpec; - } - - const size_t clusterSize = (size_t)1 << _clusterBitsMax; - _cache.AllocAtLeast(clusterSize); - _cacheCompressed.AllocAtLeast(clusterSize * 2); - } - - FOR_VECTOR (i, _extents) - { - RINOK(_extents[i].InitAndSeek()) - } - - CMyComPtr streamTemp = this; - InitAndSeekMain(); - *stream = streamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - -REGISTER_ARC_I( - "VMDK", "vmdk", NULL, 0xC8, - k_Signature, - 0, - 0, - NULL) - -}} +// VmdkHandler.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/StringConvert.h" +#include "../../Common/StringToInt.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZlibDecoder.h" + +#include "HandlerCont.h" + +using namespace NWindows; + +namespace NArchive { +namespace NVmdk { + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define LE_16(offs, dest) dest = Get16(p + (offs)) +#define LE_32(offs, dest) dest = Get32(p + (offs)) +#define LE_64(offs, dest) dest = Get64(p + (offs)) + + +static const Byte k_Signature[] = { 'K', 'D', 'M', 'V' }; + +static const UInt32 k_Flags_NL = (UInt32)1 << 0; +// static const UInt32 k_Flags_RGD = (UInt32)1 << 1; +static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2; +static const UInt32 k_Flags_Compressed = (UInt32)1 << 16; +static const UInt32 k_Flags_Marker = (UInt32)1 << 17; + +static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table + +struct CHeader +{ + UInt32 flags; + UInt32 version; + + UInt64 capacity; + UInt64 grainSize; + UInt64 descriptorOffset; + UInt64 descriptorSize; + + UInt32 numGTEsPerGT; + UInt16 algo; + // Byte uncleanShutdown; + // UInt64 rgdOffset; + UInt64 gdOffset; + UInt64 overHead; + + bool Is_NL() const { return (flags & k_Flags_NL) != 0; } + bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; } + bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; } + bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; } + + bool Parse(const Byte *p); + + bool IsSameImageFor(const CHeader &h) const + { + return flags == h.flags + && version == h.version + && capacity == h.capacity + && grainSize == h.grainSize + && algo == h.algo; + } +}; + +bool CHeader::Parse(const Byte *p) +{ + if (memcmp(p, k_Signature, sizeof(k_Signature)) != 0) + return false; + + LE_32 (0x04, version); + LE_32 (0x08, flags); + LE_64 (0x0C, capacity); + LE_64 (0x14, grainSize); + LE_64 (0x1C, descriptorOffset); + LE_64 (0x24, descriptorSize); + LE_32 (0x2C, numGTEsPerGT); + // LE_64 (0x30, rgdOffset); + LE_64 (0x38, gdOffset); + LE_64 (0x40, overHead); + // uncleanShutdown = buf[0x48]; + LE_16(0x4D, algo); + + if (Is_NL() && Get32(p + 0x49) != 0x0A0D200A) // do we need Is_NL() check here? + return false; + + return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3); +} + + +enum +{ + k_Marker_END_OF_STREAM = 0, + k_Marker_GRAIN_TABLE = 1, + k_Marker_GRAIN_DIR = 2, + k_Marker_FOOTER = 3 +}; + +struct CMarker +{ + UInt64 NumSectors; + UInt32 SpecSize; // = 0 for metadata sectors + UInt32 Type; + + void Parse(const Byte *p) + { + LE_64 (0, NumSectors); + LE_32 (8, SpecSize); + LE_32 (12, Type); + } +}; + + +static bool Str_to_ValName(const AString &s, AString &name, AString &val) +{ + name.Empty(); + val.Empty(); + int qu = s.Find('"'); + int eq = s.Find('='); + if (eq < 0 || (qu >= 0 && eq > qu)) + return false; + name.SetFrom(s.Ptr(), eq); + name.Trim(); + val = s.Ptr(eq + 1); + val.Trim(); + return true; +} + +static inline bool IsSpaceChar(char c) +{ + return (c == ' ' || c == '\t'); +} + +static const char *SkipSpaces(const char *s) +{ + for (;; s++) + { + char c = *s; + if (c == 0 || !IsSpaceChar(c)) + return s; + } +} + +#define SKIP_SPACES(s) s = SkipSpaces(s); + +static const char *GetNextWord(const char *s, AString &dest) +{ + dest.Empty(); + SKIP_SPACES(s) + const char *start = s; + for (;; s++) + { + char c = *s; + if (c == 0 || IsSpaceChar(c)) + { + dest.SetFrom(start, (unsigned)(s - start)); + return s; + } + } +} + +static const char *GetNextNumber(const char *s, UInt64 &val) +{ + SKIP_SPACES(s) + if (*s == 0) + return s; + const char *end; + val = ConvertStringToUInt64(s, &end); + char c = *end; + if (c != 0 && !IsSpaceChar(c)) + return NULL; + return end; +} + + +struct CExtentInfo +{ + AString Access; // RW, RDONLY, or NOACCESS + UInt64 NumSectors; // 512 bytes sectors + AString Type; // FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, VMFSRAW + AString FileName; + UInt64 StartSector; // used for FLAT + + // for VMWare Player 9: + // PartitionUUID + // DeviceIdentifier + + bool IsType_ZERO() const { return Type == "ZERO"; } + // bool IsType_FLAT() const { return Type == "FLAT"; } + bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; } + + bool Parse(const char *s); +}; + +bool CExtentInfo::Parse(const char *s) +{ + NumSectors = 0; + StartSector = 0; + Access.Empty(); + Type.Empty(); + FileName.Empty(); + + s = GetNextWord(s, Access); + s = GetNextNumber(s, NumSectors); + if (!s) + return false; + s = GetNextWord(s, Type); + + if (Type.IsEmpty()) + return false; + + SKIP_SPACES(s) + + if (IsType_ZERO()) + return (*s == 0); + + if (*s != '\"') + return false; + s++; + { + const char *s2 = strchr(s, '\"'); + if (!s2) + return false; + FileName.SetFrom(s, (unsigned)(s2 - s)); + s = s2 + 1; + } + SKIP_SPACES(s) + if (*s == 0) + return true; + + s = GetNextNumber(s, StartSector); + if (!s) + return false; + return true; + // SKIP_SPACES(s); + // return (*s == 0); +} + + +struct CDescriptor +{ + AString CID; + AString parentCID; + AString createType; + // AString encoding; // UTF-8, windows-1252 - default is UTF-8 + + CObjectVector Extents; + + static void GetUnicodeName(const AString &s, UString &res) + { + if (!ConvertUTF8ToUnicode(s, res)) + MultiByteToUnicodeString2(res, s); + } + + void Clear() + { + CID.Empty(); + parentCID.Empty(); + createType.Empty(); + Extents.Clear(); + } + + bool IsThere_Parent() const + { + return !parentCID.IsEmpty() && !parentCID.IsEqualTo_Ascii_NoCase("ffffffff"); + } + + bool Parse(const Byte *p, size_t size); +}; + + +bool CDescriptor::Parse(const Byte *p, size_t size) +{ + Clear(); + + AString s; + AString name; + AString val; + + for (;;) + { + Byte c = 0; + if (size != 0) + { + size--; + c = *p++; + } + if (c == 0 || c == 0xA || c == 0xD) + { + if (!s.IsEmpty() && s[0] != '#') + { + if (Str_to_ValName(s, name, val)) + { + if (name.IsEqualTo_Ascii_NoCase("CID")) + CID = val; + else if (name.IsEqualTo_Ascii_NoCase("parentCID")) + parentCID = val; + else if (name.IsEqualTo_Ascii_NoCase("createType")) + createType = val; + } + else + { + CExtentInfo ei; + if (!ei.Parse(s)) + return false; + Extents.Add(ei); + } + } + + s.Empty(); + if (c == 0) + return true; + } + else + s += (char)c; + } +} + + +struct CExtent +{ + bool IsOK; + bool IsArc; + bool NeedDeflate; + bool Unsupported; + bool IsZero; + bool IsFlat; + bool DescriptorOK; + bool HeadersError; + + unsigned ClusterBits; + UInt32 ZeroSector; + + CObjectVector Tables; + + CMyComPtr Stream; + UInt64 PosInArc; + + UInt64 PhySize; + UInt64 VirtSize; // from vmdk header of volume + + UInt64 StartOffset; // virtual offset of this extent + UInt64 NumBytes; // from main descriptor, if multi-vol + UInt64 FlatOffset; // in Stream + + CByteBuffer DescriptorBuf; + CDescriptor Descriptor; + + CHeader h; + + UInt64 GetEndOffset() const { return StartOffset + NumBytes; } + + bool IsVmdk() const { return !IsZero && !IsFlat; } + // if (IsOK && IsVmdk()), then VMDK header of this extent was read + + CExtent(): + IsOK(false), + IsArc(false), + NeedDeflate(false), + Unsupported(false), + IsZero(false), + IsFlat(false), + DescriptorOK(false), + HeadersError(false), + + ClusterBits(0), + ZeroSector(0), + + PosInArc(0), + + PhySize(0), + VirtSize(0), + + StartOffset(0), + NumBytes(0), + FlatOffset(0) + {} + + + HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors); + HRESULT Open3(IInStream *stream, IArchiveOpenCallback *openCallback, + unsigned numVols, unsigned volIndex, UInt64 &complexity); + + HRESULT Seek(UInt64 offset) + { + PosInArc = offset; + return InStream_SeekSet(Stream, offset); + } + + HRESULT InitAndSeek() + { + if (Stream) + return Seek(0); + return S_OK; + } + + HRESULT Read(void *data, size_t *size) + { + HRESULT res = ReadStream(Stream, data, size); + PosInArc += *size; + return res; + } +}; + + +Z7_class_CHandler_final: public CHandlerImg +{ + bool _isArc; + bool _unsupported; + bool _unsupportedSome; + bool _headerError; + bool _missingVol; + bool _isMultiVol; + bool _needDeflate; + + UInt64 _cacheCluster; + unsigned _cacheExtent; + CByteBuffer _cache; + CByteBuffer _cacheCompressed; + + unsigned _clusterBitsMax; + UInt64 _phySize; + + CObjectVector _extents; + + CBufInStream *_bufInStreamSpec; + CMyComPtr _bufInStream; + + CBufPtrSeqOutStream *_bufOutStreamSpec; + CMyComPtr _bufOutStream; + + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + CByteBuffer _descriptorBuf; + CDescriptor _descriptor; + + UString _missingVolName; + + void InitAndSeekMain() + { + _virtPos = 0; + } + + virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override; + virtual void CloseAtError() Z7_override; +public: + Z7_IFACE_COM7_IMP(IInArchive_Img) + + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) +}; + + +Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + return S_OK; + { + UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + unsigned extentIndex; + { + unsigned left = 0, right = _extents.Size(); + for (;;) + { + unsigned mid = (left + right) / 2; + if (mid == left) + break; + if (_virtPos < _extents[mid].StartOffset) + right = mid; + else + left = mid; + } + extentIndex = left; + } + + CExtent &extent = _extents[extentIndex]; + + { + const UInt64 vir = _virtPos - extent.StartOffset; + if (vir >= extent.NumBytes) + { + return E_FAIL; + /* + if (vir > extent.NumBytes) + _stream_dataError = true; + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + + { + const UInt64 rem = extent.NumBytes - vir; + if (size > rem) + size = (UInt32)rem; + } + + if (vir >= extent.VirtSize) + { + // if vmdk's VirtSize is smaller than VirtSize from main multi-volume descriptor + _stream_dataError = true; + return S_FALSE; + /* + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + + { + const UInt64 rem = extent.VirtSize - vir; + if (size > rem) + size = (UInt32)rem; + } + + if (extent.IsZero || !extent.IsOK || !extent.Stream || extent.Unsupported) + { + if (extent.Unsupported) + { + _stream_unsupportedMethod = true; + return S_FALSE; + } + if (!extent.IsOK || !extent.Stream) + { + _stream_unavailData = true; + return S_FALSE; + } + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + if (extent.IsFlat) + { + UInt64 offset = extent.FlatOffset + vir; + if (offset != extent.PosInArc) + { + RINOK(extent.Seek(offset)) + } + UInt32 size2 = 0; + HRESULT res = extent.Stream->Read(data, size, &size2); + if (res == S_OK && size2 == 0) + { + _stream_unavailData = true; + /* + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + // _stream_PackSize += size2; + extent.PosInArc += size2; + _virtPos += size2; + if (processedSize) + *processedSize = size2; + return res; + } + } + + + for (;;) + { + const UInt64 vir = _virtPos - extent.StartOffset; + const unsigned clusterBits = extent.ClusterBits; + const UInt64 cluster = vir >> clusterBits; + const size_t clusterSize = (size_t)1 << clusterBits; + const size_t lowBits = (size_t)vir & (clusterSize - 1); + { + size_t rem = clusterSize - lowBits; + if (size > rem) + size = (UInt32)rem; + } + + if (extentIndex == _cacheExtent && cluster == _cacheCluster) + { + memcpy(data, _cache + lowBits, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + const UInt64 high = cluster >> k_NumMidBits; + + if (high < extent.Tables.Size()) + { + const CByteBuffer &table = extent.Tables[(unsigned)high]; + + if (table.Size() != 0) + { + const size_t midBits = (size_t)cluster & ((1 << k_NumMidBits) - 1); + const Byte *p = (const Byte *)table + (midBits << 2); + const UInt32 v = Get32(p); + + if (v != 0 && v != extent.ZeroSector) + { + UInt64 offset = (UInt64)v << 9; + if (extent.NeedDeflate) + { + if (offset != extent.PosInArc) + { + // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc)); + RINOK(extent.Seek(offset)) + } + + const size_t kStartSize = 1 << 9; + { + size_t curSize = kStartSize; + RINOK(extent.Read(_cacheCompressed, &curSize)) + // _stream_PackSize += curSize; + if (curSize != kStartSize) + return S_FALSE; + } + + if (Get64(_cacheCompressed) != (cluster << (clusterBits - 9))) + return S_FALSE; + + UInt32 dataSize = Get32(_cacheCompressed + 8); + if (dataSize > ((UInt32)1 << 31)) + return S_FALSE; + + size_t dataSize2 = (size_t)dataSize + 12; + + if (dataSize2 > kStartSize) + { + dataSize2 = (dataSize2 + 511) & ~(size_t)511; + if (dataSize2 > _cacheCompressed.Size()) + return S_FALSE; + size_t curSize = dataSize2 - kStartSize; + const size_t curSize2 = curSize; + RINOK(extent.Read(_cacheCompressed + kStartSize, &curSize)) + // _stream_PackSize += curSize; + if (curSize != curSize2) + return S_FALSE; + } + + _bufInStreamSpec->Init(_cacheCompressed + 12, dataSize); + + _cacheCluster = (UInt64)(Int64)-1; + _cacheExtent = (unsigned)(int)-1; + + if (_cache.Size() < clusterSize) + return E_FAIL; + _bufOutStreamSpec->Init(_cache, clusterSize); + + // Do we need to use smaller block than clusterSize for last cluster? + const UInt64 blockSize64 = clusterSize; + HRESULT res = _zlibDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL); + + /* + if (_bufOutStreamSpec->GetPos() != clusterSize) + { + _stream_dataError = true; + memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos()); + } + */ + + if (_bufOutStreamSpec->GetPos() != clusterSize + || _zlibDecoderSpec->GetInputProcessedSize() != dataSize) + { + _stream_dataError = true; + if (res == S_OK) + res = S_FALSE; + } + + RINOK(res) + + _cacheCluster = cluster; + _cacheExtent = extentIndex; + + continue; + /* + memcpy(data, _cache + lowBits, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + { + offset += lowBits; + if (offset != extent.PosInArc) + { + // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc)); + RINOK(extent.Seek(offset)) + } + UInt32 size2 = 0; + HRESULT res = extent.Stream->Read(data, size, &size2); + if (res == S_OK && size2 == 0) + { + _stream_unavailData = true; + /* + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + */ + } + extent.PosInArc += size2; + // _stream_PackSize += size2; + _virtPos += size2; + if (processedSize) + *processedSize = size2; + return res; + } + } + } + } + + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumVolumes, + kpidTotalPhySize, + kpidMethod, + kpidClusterSize, + kpidHeadersSize, + kpidId, + kpidName, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CExtent *e = NULL; + const CDescriptor *desc = NULL; + + if (_isMultiVol) + desc = &_descriptor; + else if (_extents.Size() == 1) + { + e = &_extents[0]; + desc = &e->Descriptor; + } + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + case kpidTotalPhySize: + { + UInt64 sum = _phySize; + if (_isMultiVol) + { + FOR_VECTOR (i, _extents) + sum += _extents[i].PhySize; + } + prop = sum; + break; + } + case kpidClusterSize: prop = (UInt32)((UInt32)1 << _clusterBitsMax); break; + case kpidHeadersSize: if (e) prop = (e->h.overHead << 9); break; + case kpidMethod: + { + AString s; + + if (desc && !desc->createType.IsEmpty()) + s = desc->createType; + + bool zlib = false; + bool marker = false; + Int32 algo = -1; + + FOR_VECTOR (i, _extents) + { + const CExtent &extent = _extents[i]; + if (!extent.IsOK || !extent.IsVmdk()) + continue; + + const CHeader &h = extent.h; + + if (h.algo != 0) + { + if (h.algo == 1) + zlib = true; + else if (algo != h.algo) + { + s.Add_Space_if_NotEmpty(); + s.Add_UInt32(h.algo); + algo = h.algo; + } + } + + if (h.Is_Marker()) + marker = true; + } + + if (zlib) + s.Add_OptSpaced("zlib"); + + if (marker) + s.Add_OptSpaced("Marker"); + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidComment: + { + if (e && e->DescriptorBuf.Size() != 0) + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)e->DescriptorBuf, (unsigned)e->DescriptorBuf.Size()); + if (!s.IsEmpty() && s.Len() <= (1 << 16)) + prop = s; + } + break; + } + + case kpidId: + { + if (desc && !desc->CID.IsEmpty()) + { + prop = desc->CID; + } + break; + } + + case kpidName: + { + if (!_isMultiVol && desc && desc->Extents.Size() == 1) + { + const CExtentInfo &ei = desc->Extents[0]; + if (!ei.FileName.IsEmpty()) + { + UString u; + CDescriptor::GetUnicodeName(ei.FileName, u); + if (!u.IsEmpty()) + prop = u; + } + } + break; + } + + case kpidNumVolumes: if (_isMultiVol) prop = (UInt32)_extents.Size(); break; + + case kpidError: + { + if (_missingVol || !_missingVolName.IsEmpty()) + { + UString s ("Missing volume : "); + if (!_missingVolName.IsEmpty()) + s += _missingVolName; + prop = s; + } + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (_unsupportedSome) v |= kpv_ErrorFlags_UnsupportedMethod; + if (_headerError) v |= kpv_ErrorFlags_HeadersError; + // if (_missingVol) v |= kpv_ErrorFlags_UnexpectedEnd; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: + { + UInt64 packSize = 0; + FOR_VECTOR (i, _extents) + { + const CExtent &e = _extents[i]; + if (!e.IsOK) + continue; + if (e.IsVmdk() && !_isMultiVol) + { + UInt64 ov = (e.h.overHead << 9); + if (e.PhySize >= ov) + packSize += e.PhySize - ov; + } + else + packSize += e.PhySize; + } + prop = packSize; + break; + } + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static int inline GetLog(UInt64 num) +{ + for (int i = 0; i < 64; i++) + if (((UInt64)1 << i) == num) + return i; + return -1; +} + + +HRESULT CExtent::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors) +{ + sector <<= 9; + RINOK(InStream_SeekSet(stream, sector)) + size_t size = numSectors << 9; + RINOK(ReadStream_FALSE(stream, data, size)) + UInt64 end = sector + size; + if (PhySize < end) + PhySize = end; + return S_OK; +} + + +void CHandler::CloseAtError() +{ + _extents.Clear(); + CHandlerImg::CloseAtError(); +} + + +static const char * const kSignature_Descriptor = "# Disk DescriptorFile"; + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) +{ + const unsigned kSectoreSize = 512; + Byte buf[kSectoreSize]; + size_t headerSize = kSectoreSize; + RINOK(ReadStream(stream, buf, &headerSize)) + + if (headerSize < sizeof(k_Signature)) + return S_FALSE; + + CMyComPtr volumeCallback; + + if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) + { + const size_t k_SigDesc_Size = strlen(kSignature_Descriptor); + if (headerSize < k_SigDesc_Size) + return S_FALSE; + if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) != 0) + return S_FALSE; + + UInt64 endPos; + RINOK(InStream_GetSize_SeekToEnd(stream, endPos)) + if (endPos > (1 << 20)) + return S_FALSE; + const size_t numBytes = (size_t)endPos; + _descriptorBuf.Alloc(numBytes); + RINOK(InStream_SeekToBegin(stream)) + RINOK(ReadStream_FALSE(stream, _descriptorBuf, numBytes)) + + if (!_descriptor.Parse(_descriptorBuf, _descriptorBuf.Size())) + return S_FALSE; + _isMultiVol = true; + _isArc = true; + _phySize = numBytes; + if (_descriptor.IsThere_Parent()) + _unsupported = true; + + if (openCallback) + { + openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback); + } + if (!volumeCallback) + { + _unsupported = true; + return E_NOTIMPL; + } + + /* + UInt64 totalVirtSize = 0; + FOR_VECTOR (i, _descriptor.Extents) + { + const CExtentInfo &ei = _descriptor.Extents[i]; + if (ei.NumSectors >= ((UInt64)1 << (63 - 9))) + return S_FALSE; + totalVirtSize += ei.NumSectors; + if (totalVirtSize >= ((UInt64)1 << (63 - 9))) + return S_FALSE; + } + totalVirtSize <<= 9; + */ + + if (_descriptor.Extents.Size() > 1) + { + const UInt64 numFiles = _descriptor.Extents.Size(); + RINOK(openCallback->SetTotal(&numFiles, NULL)) + } + } + + UInt64 complexity = 0; + + for (;;) + { + CExtent *e = NULL; + CMyComPtr nextStream; + + if (_isMultiVol) + { + const unsigned extentIndex = _extents.Size(); + if (extentIndex >= _descriptor.Extents.Size()) + break; + const CExtentInfo &ei = _descriptor.Extents[extentIndex]; + e = &_extents.AddNew(); + e->StartOffset = 0; + if (ei.NumSectors >= ((UInt64)1 << (62 - 9)) || + ei.StartSector >= ((UInt64)1 << (62 - 9))) + return S_FALSE; + e->NumBytes = ei.NumSectors << 9; + e->IsZero = ei.IsType_ZERO(); + if (extentIndex != 0) + e->StartOffset = _extents[extentIndex - 1].GetEndOffset(); + if (e->GetEndOffset() < e->StartOffset) + return S_FALSE; + + e->VirtSize = e->NumBytes; + if (e->IsZero) + { + e->IsOK = true; + continue; + } + + e->IsFlat = ei.IsType_Flat(); + e->FlatOffset = ei.StartSector << 9; + + UString u; + CDescriptor::GetUnicodeName(ei.FileName, u); + if (u.IsEmpty()) + { + _missingVol = true; + continue; + } + + HRESULT result = volumeCallback->GetStream(u, &nextStream); + + if (result != S_OK && result != S_FALSE) + return result; + + if (!nextStream || result != S_OK) + { + if (_missingVolName.IsEmpty()) + _missingVolName = u; + _missingVol = true; + continue; + } + + if (e->IsFlat) + { + e->IsOK = true; + e->Stream = nextStream; + e->PhySize = e->NumBytes; + continue; + } + + stream = nextStream; + + headerSize = kSectoreSize; + RINOK(ReadStream(stream, buf, &headerSize)) + + if (headerSize != kSectoreSize) + continue; + if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0) + continue; + } + else + { + if (headerSize != kSectoreSize) + return S_FALSE; + e = &_extents.AddNew(); + e->StartOffset = 0; + } + + HRESULT res = S_FALSE; + if (e->h.Parse(buf)) + res = e->Open3(stream, openCallback, _isMultiVol ? _descriptor.Extents.Size() : 1, _extents.Size() - 1, complexity); + + if (!_isMultiVol) + { + _isArc = e->IsArc; + _phySize = e->PhySize; + _unsupported = e->Unsupported; + } + + if (e->Unsupported) + _unsupportedSome = true; + if (e->HeadersError) + _headerError = true; + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + if (!_isMultiVol) + return res; + continue; + } + + e->Stream = stream; + e->IsOK = true; + + if (!_isMultiVol) + { + e->NumBytes = e->VirtSize; + break; + } + + if (e->NumBytes != e->VirtSize) + _headerError = true; + } + + if (!_extents.IsEmpty()) + _size = _extents.Back().GetEndOffset(); + + _needDeflate = false; + _clusterBitsMax = 0; + + // unsigned numOKs = 0; + unsigned numUnsupported = 0; + + FOR_VECTOR (i, _extents) + { + const CExtent &e = _extents[i]; + if (e.Unsupported) + numUnsupported++; + if (!e.IsOK) + continue; + // numOKs++; + if (e.IsVmdk()) + { + if (e.NeedDeflate) + _needDeflate = true; + if (_clusterBitsMax < e.ClusterBits) + _clusterBitsMax = e.ClusterBits; + } + } + + if (numUnsupported != 0 && numUnsupported == _extents.Size()) + _unsupported = true; + + return S_OK; +} + + +HRESULT CExtent::Open3(IInStream *stream, IArchiveOpenCallback *openCallback, + unsigned numVols, unsigned volIndex, UInt64 &complexity) +{ + if (h.descriptorSize != 0) + { + if (h.descriptorOffset == 0 || + h.descriptorSize > (1 << 10)) + return S_FALSE; + DescriptorBuf.Alloc((size_t)h.descriptorSize << 9); + RINOK(ReadForHeader(stream, h.descriptorOffset, DescriptorBuf, (size_t)h.descriptorSize)) + if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(DescriptorBuf) == 0) + { + // We check data as end marker. + // and if probably it's footer's copy of header, we don't want to open it. + return S_FALSE; + } + + DescriptorOK = Descriptor.Parse(DescriptorBuf, DescriptorBuf.Size()); + if (!DescriptorOK) + HeadersError = true; + if (Descriptor.IsThere_Parent()) + Unsupported = true; + } + + if (h.gdOffset == (UInt64)(Int64)-1) + { + // Grain Dir is at end of file + UInt64 endPos; + RINOK(InStream_GetSize_SeekToEnd(stream, endPos)) + if ((endPos & 511) != 0) + return S_FALSE; + + const size_t kEndSize = 512 * 3; + Byte buf2[kEndSize]; + if (endPos < kEndSize) + return S_FALSE; + RINOK(InStream_SeekSet(stream, endPos - kEndSize)) + RINOK(ReadStream_FALSE(stream, buf2, kEndSize)) + + CHeader h2; + if (!h2.Parse(buf2 + 512)) + return S_FALSE; + if (!h.IsSameImageFor(h2)) + return S_FALSE; + + h = h2; + + CMarker m; + m.Parse(buf2); + if (m.NumSectors != 1 || m.SpecSize != 0 || m.Type != k_Marker_FOOTER) + return S_FALSE; + m.Parse(buf2 + 512 * 2); + if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM) + return S_FALSE; + PhySize = endPos; + } + + const int grainSize_Log = GetLog(h.grainSize); + if (grainSize_Log < 3 || grainSize_Log > 30 - 9) // grain size must be >= 4 KB + return S_FALSE; + if (h.capacity >= ((UInt64)1 << (63 - 9))) + return S_FALSE; + if (h.overHead >= ((UInt64)1 << (63 - 9))) + return S_FALSE; + + IsArc = true; + ClusterBits = (9 + (unsigned)grainSize_Log); + VirtSize = h.capacity << 9; + NeedDeflate = (h.algo >= 1); + + if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0)) + { + Unsupported = true; + PhySize = 0; + return S_FALSE; + } + + { + const UInt64 overHeadBytes = h.overHead << 9; + if (PhySize < overHeadBytes) + PhySize = overHeadBytes; + } + + ZeroSector = 0; + if (h.Is_ZeroGrain()) + ZeroSector = 1; + + const UInt64 numSectorsPerGde = (UInt64)1 << ((unsigned)grainSize_Log + k_NumMidBits); + const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> ((unsigned)grainSize_Log + k_NumMidBits); + CByteBuffer table; + + if (numGdeEntries != 0) + { + if (h.gdOffset == 0) + return S_FALSE; + + size_t numSectors = (size_t)((numGdeEntries + ((1 << (9 - 2)) - 1)) >> (9 - 2)); + size_t t1SizeBytes = numSectors << 9; + if ((t1SizeBytes >> 2) < numGdeEntries) + return S_FALSE; + table.Alloc(t1SizeBytes); + + if (h.Is_Marker()) + { + Byte buf2[1 << 9]; + if (ReadForHeader(stream, h.gdOffset - 1, buf2, 1) != S_OK) + return S_FALSE; + { + CMarker m; + m.Parse(buf2); + if (m.Type != k_Marker_GRAIN_DIR + || m.NumSectors != numSectors + || m.SpecSize != 0) + return S_FALSE; + } + } + + RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors)) + } + + const size_t clusterSize = (size_t)1 << ClusterBits; + + const UInt64 complexityStart = complexity; + + if (openCallback) + { + complexity += (UInt64)numGdeEntries << (k_NumMidBits + 2); + { + const UInt64 numVols2 = numVols; + RINOK(openCallback->SetTotal((numVols == 1) ? NULL : &numVols2, &complexity)) + } + if (numVols != 1) + { + const UInt64 volIndex2 = volIndex; + RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &complexityStart)) + } + } + + UInt64 lastSector = 0; + UInt64 lastVirtCluster = 0; + size_t numProcessed_Prev = 0; + + for (size_t i = 0; i < numGdeEntries; i++) + { + const size_t k_NumSectors = (size_t)1 << (k_NumMidBits - 9 + 2); + const size_t k_NumMidItems = (size_t)1 << k_NumMidBits; + + CByteBuffer &buf = Tables.AddNew(); + + { + const UInt32 v = Get32((const Byte *)table + (size_t)i * 4); + if (v == 0 || v == ZeroSector) + continue; + if (openCallback && (i - numProcessed_Prev) >= 1024) + { + const UInt64 comp = complexityStart + ((UInt64)i << (k_NumMidBits + 2)); + const UInt64 volIndex2 = volIndex; + RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &comp)) + numProcessed_Prev = i; + } + + if (h.Is_Marker()) + { + Byte buf2[1 << 9]; + if (ReadForHeader(stream, v - 1, buf2, 1) != S_OK) + return S_FALSE; + { + CMarker m; + m.Parse(buf2); + if (m.Type != k_Marker_GRAIN_TABLE + || m.NumSectors != k_NumSectors + || m.SpecSize != 0) + return S_FALSE; + } + } + + buf.Alloc(k_NumMidItems * 4); + RINOK(ReadForHeader(stream, v, buf, k_NumSectors)) + } + + for (size_t k = 0; k < k_NumMidItems; k++) + { + const UInt32 v = Get32((const Byte *)buf + (size_t)k * 4); + if (v == 0 || v == ZeroSector) + continue; + if (v < h.overHead) + return S_FALSE; + if (lastSector < v) + { + lastSector = v; + if (NeedDeflate) + lastVirtCluster = ((UInt64)i << k_NumMidBits) + k; + } + } + } + + if (!NeedDeflate) + { + UInt64 end = ((UInt64)lastSector << 9) + clusterSize; + if (PhySize < end) + PhySize = end; + } + else if (lastSector != 0) + { + Byte buf[1 << 9]; + if (ReadForHeader(stream, lastSector, buf, 1) == S_OK) + { + UInt64 lba = Get64(buf); + if (lba == (lastVirtCluster << (ClusterBits - 9))) + { + UInt32 dataSize = Get32(buf + 8); + size_t dataSize2 = (size_t)dataSize + 12; + dataSize2 = (dataSize2 + 511) & ~(size_t)511; + UInt64 end = ((UInt64)lastSector << 9) + dataSize2; + if (PhySize < end) + PhySize = end; + } + } + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + + _cacheCluster = (UInt64)(Int64)-1; + _cacheExtent = (unsigned)(int)-1; + + _clusterBitsMax = 0; + + _isArc = false; + _unsupported = false; + _unsupportedSome = false; + _headerError = false; + _missingVol = false; + _isMultiVol = false; + _needDeflate = false; + + _missingVolName.Empty(); + + _descriptorBuf.Free(); + _descriptor.Clear(); + + // CHandlerImg: + Clear_HandlerImg_Vars(); + Stream.Release(); + + _extents.Clear(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + *stream = NULL; + + if (_unsupported) + return S_FALSE; + + ClearStreamVars(); + // _stream_UsePackSize = true; + + if (_needDeflate) + { + if (!_bufInStream) + { + _bufInStreamSpec = new CBufInStream; + _bufInStream = _bufInStreamSpec; + } + + if (!_bufOutStream) + { + _bufOutStreamSpec = new CBufPtrSeqOutStream(); + _bufOutStream = _bufOutStreamSpec; + } + + if (!_zlibDecoder) + { + _zlibDecoderSpec = new NCompress::NZlib::CDecoder; + _zlibDecoder = _zlibDecoderSpec; + } + + const size_t clusterSize = (size_t)1 << _clusterBitsMax; + _cache.AllocAtLeast(clusterSize); + _cacheCompressed.AllocAtLeast(clusterSize * 2); + } + + FOR_VECTOR (i, _extents) + { + RINOK(_extents[i].InitAndSeek()) + } + + CMyComPtr streamTemp = this; + InitAndSeekMain(); + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "VMDK", "vmdk", NULL, 0xC8, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/Wim/StdAfx.h b/CPP/7zip/Archive/Wim/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Wim/StdAfx.h +++ b/CPP/7zip/Archive/Wim/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index 7ffc75741..b21f673c0 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -1,1238 +1,1238 @@ -// WimHandler.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" - -#include "../../Common/MethodProps.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "WimHandler.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -using namespace NWindows; - -namespace NArchive { -namespace NWim { - -#define FILES_DIR_NAME "[DELETED]" - -// #define WIM_DETAILS - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidAttrib, - kpidMethod, - kpidSolid, - kpidShortName, - kpidINode, - kpidLinks, - kpidIsAltStream, - kpidNumAltStreams, - - #ifdef WIM_DETAILS - , kpidVolume - , kpidOffset - #endif -}; - -enum -{ - kpidNumImages = kpidUserDefined, - kpidBootImage -}; - -static const CStatProp kArcProps[] = -{ - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidClusterSize, VT_UI4}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidUnpackVer, VT_BSTR}, - { NULL, kpidIsVolume, VT_BOOL}, - { NULL, kpidVolume, VT_UI4}, - { NULL, kpidNumVolumes, VT_UI4}, - { "Images", kpidNumImages, VT_UI4}, - { "Boot Image", kpidBootImage, VT_UI4} -}; - - -static const char * const k_Methods[] = -{ - "Copy" - , "XPress" - , "LZX" - , "LZMS" -}; - - - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_WITH_NAME - -static void AddErrorMessage(AString &s, const char *message) -{ - if (!s.IsEmpty()) - s += ". "; - s += message; -} - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CImageInfo *image = NULL; - if (_xmls.Size() == 1) - { - const CWimXml &xml = _xmls[0]; - if (xml.Images.Size() == 1) - image = &xml.Images[0]; - } - - switch (propID) - { - case kpidPhySize: prop = _phySize; break; - case kpidSize: prop = _db.GetUnpackSize(); break; - case kpidPackSize: prop = _db.GetPackSize(); break; - - case kpidCTime: - if (_xmls.Size() == 1) - { - const CWimXml &xml = _xmls[0]; - int index = -1; - FOR_VECTOR (i, xml.Images) - { - const CImageInfo &image2 = xml.Images[i]; - if (image2.CTimeDefined) - if (index < 0 || ::CompareFileTime(&image2.CTime, &xml.Images[index].CTime) < 0) - index = (int)i; - } - if (index >= 0) - prop = xml.Images[index].CTime; - } - break; - - case kpidMTime: - if (_xmls.Size() == 1) - { - const CWimXml &xml = _xmls[0]; - int index = -1; - FOR_VECTOR (i, xml.Images) - { - const CImageInfo &image2 = xml.Images[i]; - if (image2.MTimeDefined) - if (index < 0 || ::CompareFileTime(&image2.MTime, &xml.Images[index].MTime) > 0) - index = (int)i; - } - if (index >= 0) - prop = xml.Images[index].MTime; - } - break; - - case kpidComment: - if (image) - { - if (_xmlInComments) - { - UString s; - _xmls[0].ToUnicode(s); - prop = s; - } - else if (image->NameDefined) - prop = image->Name; - } - break; - - case kpidUnpackVer: - { - UInt32 ver1 = _version >> 16; - UInt32 ver2 = (_version >> 8) & 0xFF; - UInt32 ver3 = (_version) & 0xFF; - - AString res; - res.Add_UInt32(ver1); - res.Add_Dot(); - res.Add_UInt32(ver2); - if (ver3 != 0) - { - res.Add_Dot(); - res.Add_UInt32(ver3); - } - prop = res; - break; - } - - case kpidIsVolume: - if (_xmls.Size() > 0) - { - UInt16 volIndex = _xmls[0].VolIndex; - if (volIndex < _volumes.Size()) - prop = (_volumes[volIndex].Header.NumParts > 1); - } - break; - case kpidVolume: - if (_xmls.Size() > 0) - { - UInt16 volIndex = _xmls[0].VolIndex; - if (volIndex < _volumes.Size()) - prop = (UInt32)_volumes[volIndex].Header.PartNumber; - } - break; - case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; - - case kpidClusterSize: - if (_xmls.Size() > 0) - { - UInt16 volIndex = _xmls[0].VolIndex; - if (volIndex < _volumes.Size()) - { - const CHeader &h = _volumes[volIndex].Header; - prop = (UInt32)1 << h.ChunkSizeBits; - } - } - break; - - case kpidName: - if (_firstVolumeIndex >= 0) - { - const CHeader &h = _volumes[_firstVolumeIndex].Header; - if (GetUi32(h.Guid) != 0) - { - char temp[64]; - RawLeGuidToString(h.Guid, temp); - temp[8] = 0; // for reduced GUID - AString s (temp); - const char *ext = ".wim"; - if (h.NumParts != 1) - { - s += '_'; - if (h.PartNumber != 1) - s.Add_UInt32(h.PartNumber); - ext = ".swm"; - } - s += ext; - prop = s; - } - } - break; - - case kpidExtension: - if (_firstVolumeIndex >= 0) - { - const CHeader &h = _volumes[_firstVolumeIndex].Header; - if (h.NumParts > 1) - { - AString s; - if (h.PartNumber != 1) - { - s.Add_UInt32(h.PartNumber); - s.Add_Dot(); - } - s += "swm"; - prop = s; - } - } - break; - - case kpidNumImages: prop = (UInt32)_db.Images.Size(); break; - case kpidBootImage: if (_bootIndex != 0) prop = (UInt32)_bootIndex; break; - - case kpidMethod: - { - UInt32 methodUnknown = 0; - UInt32 methodMask = 0; - unsigned chunkSizeBits = 0; - - { - FOR_VECTOR (i, _xmls) - { - const CHeader &header = _volumes[_xmls[i].VolIndex].Header; - unsigned method = header.GetMethod(); - if (method < Z7_ARRAY_SIZE(k_Methods)) - methodMask |= ((UInt32)1 << method); - else - methodUnknown = method; - if (chunkSizeBits < header.ChunkSizeBits) - chunkSizeBits = header.ChunkSizeBits; - } - } - - AString res; - - unsigned numMethods = 0; - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Methods); i++) - { - if (methodMask & ((UInt32)1 << i)) - { - res.Add_Space_if_NotEmpty(); - res += k_Methods[i]; - numMethods++; - } - } - - if (methodUnknown != 0) - { - res.Add_Space_if_NotEmpty(); - res.Add_UInt32(methodUnknown); - numMethods++; - } - - if (numMethods == 1 && chunkSizeBits != 0) - { - res.Add_Colon(); - res.Add_UInt32((UInt32)chunkSizeBits); - } - - prop = res; - break; - } - - case kpidIsTree: prop = true; break; - case kpidIsAltStream: prop = _db.ThereAreAltStreams; break; - case kpidIsAux: prop = true; break; - // WIM uses special prefix to represent deleted items - // case kpidIsDeleted: prop = _db.ThereAreDeletedStreams; break; - case kpidINode: prop = true; break; - - case kpidErrorFlags: - { - UInt32 flags = 0; - if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; - if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError; - if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod; - prop = flags; - break; - } - - case kpidWarning: - { - AString s; - if (_xmlError) - AddErrorMessage(s, "XML error"); - if (_db.RefCountError) - AddErrorMessage(s, "Some files have incorrect reference count"); - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidReadOnly: - { - bool readOnly = !IsUpdateSupported(); - if (readOnly) - prop = readOnly; - break; - } - } - - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -static void GetFileTime(const Byte *p, NCOM::CPropVariant &prop) -{ - prop.vt = VT_FILETIME; - prop.filetime.dwLowDateTime = Get32(p); - prop.filetime.dwHighDateTime = Get32(p + 4); - prop.Set_FtPrec(k_PropVar_TimePrec_100ns); -} - - -static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop) -{ - if (method >= 0) - { - char temp[32]; - - if ((unsigned)method < Z7_ARRAY_SIZE(k_Methods)) - MyStringCopy(temp, k_Methods[(unsigned)method]); - else - ConvertUInt32ToString((UInt32)(unsigned)method, temp); - - if (chunksSizeBits >= 0) - { - size_t pos = strlen(temp); - temp[pos++] = ':'; - ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos); - } - - prop = temp; - } -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - if (index < _db.SortedItems.Size()) - { - unsigned realIndex = _db.SortedItems[index]; - const CItem &item = _db.Items[realIndex]; - const CStreamInfo *si = NULL; - const CVolume *vol = NULL; - if (item.StreamIndex >= 0) - { - si = &_db.DataStreams[item.StreamIndex]; - vol = &_volumes[si->PartNumber]; - } - - const CItem *mainItem = &item; - if (item.IsAltStream) - mainItem = &_db.Items[item.Parent]; - const Byte *metadata = NULL; - if (mainItem->ImageIndex >= 0) - metadata = _db.Images[mainItem->ImageIndex].Meta + mainItem->Offset; - - switch (propID) - { - case kpidPath: - if (item.ImageIndex >= 0) - _db.GetItemPath(realIndex, _showImageNumber, prop); - else - { - /* - while (s.Len() < _nameLenForStreams) - s = '0' + s; - */ - /* - if (si->Resource.IsFree()) - s = (AString)("[Free]" STRING_PATH_SEPARATOR) + sz; - else - */ - AString s (FILES_DIR_NAME STRING_PATH_SEPARATOR); - s.Add_UInt32((UInt32)(Int32)item.StreamIndex); - prop = s; - } - break; - - case kpidName: - if (item.ImageIndex >= 0) - _db.GetItemName(realIndex, prop); - else - { - char sz[16]; - ConvertUInt32ToString((UInt32)(Int32)item.StreamIndex, sz); - /* - AString s = sz; - while (s.Len() < _nameLenForStreams) - s = '0' + s; - */ - prop = sz; - } - break; - - case kpidShortName: - if (item.ImageIndex >= 0 && !item.IsAltStream) - _db.GetShortName(realIndex, prop); - break; - - case kpidPackSize: - { - if (si) - { - if (!si->Resource.IsSolidSmall()) - prop = si->Resource.PackSize; - else - { - if (si->Resource.SolidIndex >= 0) - { - const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex]; - if (ss.FirstSmallStream == item.StreamIndex) - prop = _db.DataStreams[ss.StreamIndex].Resource.PackSize; - } - } - } - else if (!item.IsDir) - prop = (UInt64)0; - - break; - } - - case kpidSize: - { - if (si) - { - if (si->Resource.IsSolid()) - { - if (si->Resource.IsSolidBig()) - { - if (si->Resource.SolidIndex >= 0) - { - const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex]; - prop = ss.UnpackSize; - } - } - else - prop = si->Resource.PackSize; - } - else - prop = si->Resource.UnpackSize; - } - else if (!item.IsDir) - prop = (UInt64)0; - - break; - } - - case kpidIsDir: prop = item.IsDir; break; - case kpidIsAltStream: prop = item.IsAltStream; break; - case kpidNumAltStreams: - { - if (!item.IsAltStream && mainItem->HasMetadata()) - { - UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; - UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6); - if (numAltStreams != 0) - { - if (!item.IsDir) - numAltStreams--; - prop = numAltStreams; - } - } - break; - } - - case kpidAttrib: - if (!item.IsAltStream && mainItem->ImageIndex >= 0) - { - /* - if (fileNameLen == 0 && isDir && !item.HasStream()) - item.Attrib = 0x10; // some swm archives have system/hidden attributes for root - */ - prop = (UInt32)Get32(metadata + 8); - } - break; - case kpidCTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; - case kpidATime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; - case kpidMTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; - - case kpidINode: - if (mainItem->HasMetadata() && !_isOldVersion) - { - UInt32 attrib = (UInt32)Get32(metadata + 8); - if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) - { - // we don't know about that field in OLD WIM format - unsigned offset = 0x58; // (_db.IsOldVersion ? 0x30: 0x58); - UInt64 val = Get64(metadata + offset); - if (val != 0) - prop = val; - } - } - break; - - case kpidStreamId: - if (item.StreamIndex >= 0) - prop = (UInt32)item.StreamIndex; - break; - - case kpidMethod: - if (si) - { - const CResource &r = si->Resource; - if (r.IsSolid()) - { - if (r.SolidIndex >= 0) - { - CSolid &ss = _db.Solids[r.SolidIndex]; - MethodToProp(ss.Method, (int)ss.ChunkSizeBits, prop); - } - } - else - { - int method = 0; - int chunkSizeBits = -1; - if (r.IsCompressed()) - { - method = (int)vol->Header.GetMethod(); - chunkSizeBits = (int)vol->Header.ChunkSizeBits; - } - MethodToProp(method, chunkSizeBits, prop); - } - } - break; - - case kpidSolid: if (si) prop = si->Resource.IsSolid(); break; - case kpidLinks: if (si) prop = (UInt32)si->RefCount; break; - #ifdef WIM_DETAILS - case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break; - case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break; - #endif - } - } - else - { - index -= _db.SortedItems.Size(); - if (index < _numXmlItems) - { - switch (propID) - { - case kpidPath: - case kpidName: prop = _xmls[index].FileName; break; - case kpidIsDir: prop = false; break; - case kpidPackSize: - case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break; - case kpidMethod: /* prop = k_Method_Copy; */ break; - } - } - else - { - index -= _numXmlItems; - switch (propID) - { - case kpidPath: - case kpidName: - if (index < (UInt32)_db.VirtualRoots.Size()) - prop = _db.Images[_db.VirtualRoots[index]].RootName; - else - prop = FILES_DIR_NAME; - break; - case kpidIsDir: prop = true; break; - case kpidIsAux: prop = true; break; - } - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetRootProp(PROPID propID, PROPVARIANT *value)) -{ - // COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (_db.Images.Size() != 0 && _db.NumExcludededItems != 0) - { - const CImage &image = _db.Images[_db.IndexOfUserImage]; - const CItem &item = _db.Items[image.StartItem]; - if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage) - return E_FAIL; - const Byte *metadata = image.Meta + item.Offset; - - switch (propID) - { - case kpidIsDir: prop = true; break; - case kpidAttrib: prop = (UInt32)Get32(metadata + 8); break; - case kpidCTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; - case kpidATime: GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; - case kpidMTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; - } - } - prop.Detach(value); - return S_OK; - // COM_TRY_END -} - -HRESULT CHandler::GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType) -{ - const CItem &item = _db.Items[realIndex]; - if (item.IsAltStream || item.ImageIndex < 0) - return S_OK; - const CImage &image = _db.Images[item.ImageIndex]; - const Byte *metadata = image.Meta + item.Offset; - UInt32 securityId = Get32(metadata + 0xC); - if (securityId == (UInt32)(Int32)-1) - return S_OK; - if (securityId >= (UInt32)image.SecurOffsets.Size()) - return E_FAIL; - UInt32 offs = image.SecurOffsets[securityId]; - UInt32 len = image.SecurOffsets[securityId + 1] - offs; - const CByteBuffer &buf = image.Meta; - if (offs <= buf.Size() && buf.Size() - offs >= len) - { - *data = buf + offs; - *dataSize = len; - *propType = NPropDataType::kRaw; - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExcludededItems != 0) - { - const CImage &image = _db.Images[_db.IndexOfUserImage]; - const CItem &item = _db.Items[image.StartItem]; - if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage) - return E_FAIL; - return GetSecurity(image.StartItem, data, dataSize, propType); - } - return S_OK; -} - -static const Byte kRawProps[] = -{ - kpidSha1, - kpidNtReparse, - kpidNtSecure -}; - - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = Z7_ARRAY_SIZE(kRawProps); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) -{ - *propID = kRawProps[index]; - *name = NULL; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - if (index >= _db.SortedItems.Size()) - return S_OK; - - const CItem &item = _db.Items[_db.SortedItems[index]]; - - if (item.ImageIndex >= 0) - { - *parentType = item.IsAltStream ? NParentType::kAltStream : NParentType::kDir; - if (item.Parent >= 0) - { - if (_db.ExludedItem != item.Parent) - *parent = (unsigned)_db.Items[item.Parent].IndexInSorted; - } - else - { - CImage &image = _db.Images[item.ImageIndex]; - if (image.VirtualRootIndex >= 0) - *parent = _db.SortedItems.Size() + _numXmlItems + (unsigned)image.VirtualRootIndex; - } - } - else - *parent = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (propID == kpidName) - { - if (index < _db.SortedItems.Size()) - { - const CItem &item = _db.Items[_db.SortedItems[index]]; - if (item.ImageIndex < 0) - return S_OK; - const CImage &image = _db.Images[item.ImageIndex]; - *propType = NPropDataType::kUtf16z; - if (image.NumEmptyRootItems != 0 && item.Parent < 0) - { - const CByteBuffer &buf = _db.Images[item.ImageIndex].RootNameBuf; - *data = (void *)(const Byte *)buf; - *dataSize = (UInt32)buf.Size(); - return S_OK; - } - const Byte *meta = image.Meta + item.Offset + - (item.IsAltStream ? - (_isOldVersion ? 0x10 : 0x24) : - (_isOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2)); - *data = (const void *)(meta + 2); - *dataSize = (UInt32)Get16(meta) + 2; - return S_OK; - } - { - index -= _db.SortedItems.Size(); - if (index < _numXmlItems) - return S_OK; - index -= _numXmlItems; - if (index >= (UInt32)_db.VirtualRoots.Size()) - return S_OK; - const CByteBuffer &buf = _db.Images[_db.VirtualRoots[index]].RootNameBuf; - *data = (void *)(const Byte *)buf; - *dataSize = (UInt32)buf.Size(); - *propType = NPropDataType::kUtf16z; - return S_OK; - } - } - - if (index >= _db.SortedItems.Size()) - return S_OK; - - unsigned index2 = _db.SortedItems[index]; - - if (propID == kpidNtSecure) - { - return GetSecurity(index2, data, dataSize, propType); - } - - const CItem &item = _db.Items[index2]; - if (propID == kpidSha1) - { - if (item.StreamIndex >= 0) - *data = _db.DataStreams[item.StreamIndex].Hash; - else - { - if (_isOldVersion) - return S_OK; - const Byte *sha1 = _db.Images[item.ImageIndex].Meta + item.Offset + (item.IsAltStream ? 0x10 : 0x40); - if (IsEmptySha(sha1)) - return S_OK; - *data = sha1; - } - *dataSize = kHashSize; - *propType = NPropDataType::kRaw; - return S_OK; - } - - if (propID == kpidNtReparse && !_isOldVersion) - { - // we don't know about Reparse field in OLD WIM format - - if (item.StreamIndex < 0) - return S_OK; - if (index2 >= _db.ItemToReparse.Size()) - return S_OK; - int reparseIndex = _db.ItemToReparse[index2]; - if (reparseIndex < 0) - return S_OK; - const CByteBuffer &buf = _db.ReparseItems[reparseIndex]; - if (buf.Size() == 0) - return S_OK; - *data = buf; - *dataSize = (UInt32)buf.Size(); - *propType = NPropDataType::kRaw; - return S_OK; - } - - return S_OK; -} - -class CVolumeName -{ - UString _before; - UString _after; -public: - void InitName(const UString &name) - { - int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0) - dotPos = (int)name.Len(); - _before.SetFrom(name.Ptr(), (unsigned)dotPos); - _after = name.Ptr(dotPos); - } - - UString GetNextName(UInt32 index) const - { - UString s = _before; - s.Add_UInt32(index); - s += _after; - return s; - } -}; - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - - Close(); - { - CMyComPtr openVolumeCallback; - - CVolumeName seqName; - if (callback) - callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); - - UInt32 numVolumes = 1; - - for (UInt32 i = 1; i <= numVolumes; i++) - { - CMyComPtr curStream; - - if (i == 1) - curStream = inStream; - else - { - if (!openVolumeCallback) - continue; - const UString fullName = seqName.GetNextName(i); - const HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); - if (result == S_FALSE) - continue; - if (result != S_OK) - return result; - if (!curStream) - break; - } - - CHeader header; - HRESULT res = NWim::ReadHeader(curStream, header, _phySize); - - if (res != S_OK) - { - if (i != 1 && res == S_FALSE) - continue; - return res; - } - - _isArc = true; - _bootIndex = header.BootIndex; - _version = header.Version; - _isOldVersion = header.IsOldVersion(); - if (_firstVolumeIndex >= 0) - if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header)) - break; - if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream) - break; - CWimXml xml; - xml.VolIndex = header.PartNumber; - res = _db.OpenXml(curStream, header, xml.Data); - - if (res == S_OK) - { - if (!xml.Parse()) - _xmlError = true; - - if (xml.IsEncrypted) - { - _unsupported = true; - return S_FALSE; - } - - UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size(); - totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items - if (totalFiles >= ((UInt32)1 << 30)) - totalFiles = 0; - res = _db.Open(curStream, header, (unsigned)totalFiles, callback); - } - - if (res != S_OK) - { - if (i != 1 && res == S_FALSE) - continue; - return res; - } - - while (_volumes.Size() <= header.PartNumber) - _volumes.AddNew(); - CVolume &volume = _volumes[header.PartNumber]; - volume.Header = header; - volume.Stream = curStream; - - _firstVolumeIndex = header.PartNumber; - - if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data) - { - xml.FileName = '['; - xml.FileName.Add_UInt32(xml.VolIndex); - xml.FileName += "].xml"; - _xmls.Add(xml); - } - - if (i == 1) - { - if (header.PartNumber != 1) - break; - if (!openVolumeCallback) - break; - numVolumes = header.NumParts; - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) - if (prop.vt != VT_BSTR) - break; - seqName.InitName(prop.bstrVal); - } - } - } - - RINOK(_db.FillAndCheck(_volumes)) - int defaultImageIndex = (int)_defaultImageNumber - 1; - - bool showImageNumber = (_db.Images.Size() != 1 && defaultImageIndex < 0); - if (!showImageNumber && _set_use_ShowImageNumber) - showImageNumber = _set_showImageNumber; - - if (!showImageNumber && _keepMode_ShowImageNumber) - showImageNumber = true; - - _showImageNumber = showImageNumber; - - RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber)) - RINOK(_db.ExtractReparseStreams(_volumes, callback)) - - /* - wchar_t sz[16]; - ConvertUInt32ToString(_db.DataStreams.Size(), sz); - _nameLenForStreams = MyStringLen(sz); - */ - - _xmlInComments = !_showImageNumber; - _numXmlItems = (_xmlInComments ? 0 : _xmls.Size()); - _numIgnoreItems = _db.ThereAreDeletedStreams ? 1 : 0; - } - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _firstVolumeIndex = -1; - _phySize = 0; - _db.Clear(); - _volumes.Clear(); - _xmls.Clear(); - // _nameLenForStreams = 0; - _xmlInComments = false; - _numXmlItems = 0; - _numIgnoreItems = 0; - _xmlError = false; - _isArc = false; - _unsupported = false; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - - if (allFilesMode) - numItems = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size() + _numIgnoreItems; - if (numItems == 0) - return S_OK; - - UInt32 i; - UInt64 totalSize = 0; - - for (i = 0; i < numItems; i++) - { - UInt32 index = allFilesMode ? i : indices[i]; - if (index < _db.SortedItems.Size()) - { - int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex; - if (streamIndex >= 0) - { - const CStreamInfo &si = _db.DataStreams[streamIndex]; - totalSize += _db.Get_UnpackSize_of_Resource(si.Resource); - } - } - else - { - index -= _db.SortedItems.Size(); - if (index < _numXmlItems) - totalSize += _xmls[index].Data.Size(); - } - } - - RINOK(extractCallback->SetTotal(totalSize)) - - totalSize = 0; - UInt64 currentItemUnPacked; - - int prevSuccessStreamIndex = -1; - - CUnpacker unpacker; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - for (i = 0;; i++, - totalSize += currentItemUnPacked) - { - currentItemUnPacked = 0; - lps->InSize = unpacker.TotalPacked; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - UInt32 index = allFilesMode ? i : indices[i]; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (index >= _db.SortedItems.Size()) - { - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - index -= _db.SortedItems.Size(); - if (index < _numXmlItems) - { - const CByteBuffer &data = _xmls[index].Data; - currentItemUnPacked = data.Size(); - if (realOutStream) - { - RINOK(WriteStream(realOutStream, (const Byte *)data, data.Size())) - realOutStream.Release(); - } - } - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - - const CItem &item = _db.Items[_db.SortedItems[index]]; - const int streamIndex = item.StreamIndex; - if (streamIndex < 0) - { - if (!item.IsDir) - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(!item.IsDir && _db.ItemHasStream(item) ? - NExtract::NOperationResult::kDataError : - NExtract::NOperationResult::kOK)) - continue; - } - - const CStreamInfo &si = _db.DataStreams[streamIndex]; - currentItemUnPacked = _db.Get_UnpackSize_of_Resource(si.Resource); - // currentItemPacked = _db.Get_PackSize_of_Resource(streamIndex); - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - Int32 opRes = NExtract::NOperationResult::kOK; - - if (streamIndex != prevSuccessStreamIndex || realOutStream) - { - Byte digest[kHashSize]; - const CVolume &vol = _volumes[si.PartNumber]; - const bool needDigest = !si.IsEmptyHash() && !_disable_Sha1Check; - const HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header, &_db, - realOutStream, lps, needDigest ? digest : NULL); - - if (res == S_OK) - { - if (!needDigest || memcmp(digest, si.Hash, kHashSize) == 0) - prevSuccessStreamIndex = streamIndex; - else - opRes = NExtract::NOperationResult::kCRCError; - } - else if (res == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else if (res == E_NOTIMPL) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else - return res; - } - - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _db.SortedItems.Size() + - _numXmlItems + - _db.VirtualRoots.Size() + - _numIgnoreItems; - return S_OK; -} - -CHandler::CHandler() -{ - _keepMode_ShowImageNumber = false; - InitDefaults(); - _xmlError = false; -} - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - InitDefaults(); - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - const PROPVARIANT &prop = values[i]; - - if (name[0] == L'x') - { - // some clients write 'x' property. So we support it - UInt32 level = 0; - RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)) - } - else if (name.IsEqualTo("is")) - { - RINOK(PROPVARIANT_to_bool(prop, _set_showImageNumber)) - _set_use_ShowImageNumber = true; - } - else if (name.IsEqualTo("im")) - { - UInt32 image = 9; - RINOK(ParsePropToUInt32(L"", prop, image)) - _defaultImageNumber = (int)image; - } - else if (name.IsPrefixedBy_Ascii_NoCase("mt")) - { - } - else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) - { - } - else if (name.IsPrefixedBy_Ascii_NoCase("crc")) - { - name.Delete(0, 3); - UInt32 crcSize = 1; - RINOK(ParsePropToUInt32(name, prop, crcSize)) - _disable_Sha1Check = (crcSize == 0); - } - else - { - bool processed = false; - RINOK(_timeOptions.Parse(name, prop, processed)) - if (!processed) - return E_INVALIDARG; - } - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::KeepModeForNextOpen()) -{ - _keepMode_ShowImageNumber = _showImageNumber; - return S_OK; -} - -}} +// WimHandler.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" + +#include "../../Common/MethodProps.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "WimHandler.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +using namespace NWindows; + +namespace NArchive { +namespace NWim { + +#define FILES_DIR_NAME "[DELETED]" + +// #define WIM_DETAILS + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + kpidMethod, + kpidSolid, + kpidShortName, + kpidINode, + kpidLinks, + kpidIsAltStream, + kpidNumAltStreams, + + #ifdef WIM_DETAILS + , kpidVolume + , kpidOffset + #endif +}; + +enum +{ + kpidNumImages = kpidUserDefined, + kpidBootImage +}; + +static const CStatProp kArcProps[] = +{ + { NULL, kpidSize, VT_UI8}, + { NULL, kpidPackSize, VT_UI8}, + { NULL, kpidMethod, VT_BSTR}, + { NULL, kpidClusterSize, VT_UI4}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidUnpackVer, VT_BSTR}, + { NULL, kpidIsVolume, VT_BOOL}, + { NULL, kpidVolume, VT_UI4}, + { NULL, kpidNumVolumes, VT_UI4}, + { "Images", kpidNumImages, VT_UI4}, + { "Boot Image", kpidBootImage, VT_UI4} +}; + + +static const char * const k_Methods[] = +{ + "Copy" + , "XPress" + , "LZX" + , "LZMS" +}; + + + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_WITH_NAME + +static void AddErrorMessage(AString &s, const char *message) +{ + if (!s.IsEmpty()) + s += ". "; + s += message; +} + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CImageInfo *image = NULL; + if (_xmls.Size() == 1) + { + const CWimXml &xml = _xmls[0]; + if (xml.Images.Size() == 1) + image = &xml.Images[0]; + } + + switch (propID) + { + case kpidPhySize: prop = _phySize; break; + case kpidSize: prop = _db.GetUnpackSize(); break; + case kpidPackSize: prop = _db.GetPackSize(); break; + + case kpidCTime: + if (_xmls.Size() == 1) + { + const CWimXml &xml = _xmls[0]; + int index = -1; + FOR_VECTOR (i, xml.Images) + { + const CImageInfo &image2 = xml.Images[i]; + if (image2.CTimeDefined) + if (index < 0 || ::CompareFileTime(&image2.CTime, &xml.Images[index].CTime) < 0) + index = (int)i; + } + if (index >= 0) + prop = xml.Images[index].CTime; + } + break; + + case kpidMTime: + if (_xmls.Size() == 1) + { + const CWimXml &xml = _xmls[0]; + int index = -1; + FOR_VECTOR (i, xml.Images) + { + const CImageInfo &image2 = xml.Images[i]; + if (image2.MTimeDefined) + if (index < 0 || ::CompareFileTime(&image2.MTime, &xml.Images[index].MTime) > 0) + index = (int)i; + } + if (index >= 0) + prop = xml.Images[index].MTime; + } + break; + + case kpidComment: + if (image) + { + if (_xmlInComments) + { + UString s; + _xmls[0].ToUnicode(s); + prop = s; + } + else if (image->NameDefined) + prop = image->Name; + } + break; + + case kpidUnpackVer: + { + UInt32 ver1 = _version >> 16; + UInt32 ver2 = (_version >> 8) & 0xFF; + UInt32 ver3 = (_version) & 0xFF; + + AString res; + res.Add_UInt32(ver1); + res.Add_Dot(); + res.Add_UInt32(ver2); + if (ver3 != 0) + { + res.Add_Dot(); + res.Add_UInt32(ver3); + } + prop = res; + break; + } + + case kpidIsVolume: + if (_xmls.Size() > 0) + { + UInt16 volIndex = _xmls[0].VolIndex; + if (volIndex < _volumes.Size()) + prop = (_volumes[volIndex].Header.NumParts > 1); + } + break; + case kpidVolume: + if (_xmls.Size() > 0) + { + UInt16 volIndex = _xmls[0].VolIndex; + if (volIndex < _volumes.Size()) + prop = (UInt32)_volumes[volIndex].Header.PartNumber; + } + break; + case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; + + case kpidClusterSize: + if (_xmls.Size() > 0) + { + UInt16 volIndex = _xmls[0].VolIndex; + if (volIndex < _volumes.Size()) + { + const CHeader &h = _volumes[volIndex].Header; + prop = (UInt32)1 << h.ChunkSizeBits; + } + } + break; + + case kpidName: + if (_firstVolumeIndex >= 0) + { + const CHeader &h = _volumes[_firstVolumeIndex].Header; + if (GetUi32(h.Guid) != 0) + { + char temp[64]; + RawLeGuidToString(h.Guid, temp); + temp[8] = 0; // for reduced GUID + AString s (temp); + const char *ext = ".wim"; + if (h.NumParts != 1) + { + s += '_'; + if (h.PartNumber != 1) + s.Add_UInt32(h.PartNumber); + ext = ".swm"; + } + s += ext; + prop = s; + } + } + break; + + case kpidExtension: + if (_firstVolumeIndex >= 0) + { + const CHeader &h = _volumes[_firstVolumeIndex].Header; + if (h.NumParts > 1) + { + AString s; + if (h.PartNumber != 1) + { + s.Add_UInt32(h.PartNumber); + s.Add_Dot(); + } + s += "swm"; + prop = s; + } + } + break; + + case kpidNumImages: prop = (UInt32)_db.Images.Size(); break; + case kpidBootImage: if (_bootIndex != 0) prop = (UInt32)_bootIndex; break; + + case kpidMethod: + { + UInt32 methodUnknown = 0; + UInt32 methodMask = 0; + unsigned chunkSizeBits = 0; + + { + FOR_VECTOR (i, _xmls) + { + const CHeader &header = _volumes[_xmls[i].VolIndex].Header; + unsigned method = header.GetMethod(); + if (method < Z7_ARRAY_SIZE(k_Methods)) + methodMask |= ((UInt32)1 << method); + else + methodUnknown = method; + if (chunkSizeBits < header.ChunkSizeBits) + chunkSizeBits = header.ChunkSizeBits; + } + } + + AString res; + + unsigned numMethods = 0; + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Methods); i++) + { + if (methodMask & ((UInt32)1 << i)) + { + res.Add_Space_if_NotEmpty(); + res += k_Methods[i]; + numMethods++; + } + } + + if (methodUnknown != 0) + { + res.Add_Space_if_NotEmpty(); + res.Add_UInt32(methodUnknown); + numMethods++; + } + + if (numMethods == 1 && chunkSizeBits != 0) + { + res.Add_Colon(); + res.Add_UInt32((UInt32)chunkSizeBits); + } + + prop = res; + break; + } + + case kpidIsTree: prop = true; break; + case kpidIsAltStream: prop = _db.ThereAreAltStreams; break; + case kpidIsAux: prop = true; break; + // WIM uses special prefix to represent deleted items + // case kpidIsDeleted: prop = _db.ThereAreDeletedStreams; break; + case kpidINode: prop = true; break; + + case kpidErrorFlags: + { + UInt32 flags = 0; + if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; + if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod; + prop = flags; + break; + } + + case kpidWarning: + { + AString s; + if (_xmlError) + AddErrorMessage(s, "XML error"); + if (_db.RefCountError) + AddErrorMessage(s, "Some files have incorrect reference count"); + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidReadOnly: + { + bool readOnly = !IsUpdateSupported(); + if (readOnly) + prop = readOnly; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static void GetFileTime(const Byte *p, NCOM::CPropVariant &prop) +{ + prop.vt = VT_FILETIME; + prop.filetime.dwLowDateTime = Get32(p); + prop.filetime.dwHighDateTime = Get32(p + 4); + prop.Set_FtPrec(k_PropVar_TimePrec_100ns); +} + + +static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop) +{ + if (method >= 0) + { + char temp[32]; + + if ((unsigned)method < Z7_ARRAY_SIZE(k_Methods)) + MyStringCopy(temp, k_Methods[(unsigned)method]); + else + ConvertUInt32ToString((UInt32)(unsigned)method, temp); + + if (chunksSizeBits >= 0) + { + size_t pos = strlen(temp); + temp[pos++] = ':'; + ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos); + } + + prop = temp; + } +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + if (index < _db.SortedItems.Size()) + { + unsigned realIndex = _db.SortedItems[index]; + const CItem &item = _db.Items[realIndex]; + const CStreamInfo *si = NULL; + const CVolume *vol = NULL; + if (item.StreamIndex >= 0) + { + si = &_db.DataStreams[item.StreamIndex]; + vol = &_volumes[si->PartNumber]; + } + + const CItem *mainItem = &item; + if (item.IsAltStream) + mainItem = &_db.Items[item.Parent]; + const Byte *metadata = NULL; + if (mainItem->ImageIndex >= 0) + metadata = _db.Images[mainItem->ImageIndex].Meta + mainItem->Offset; + + switch (propID) + { + case kpidPath: + if (item.ImageIndex >= 0) + _db.GetItemPath(realIndex, _showImageNumber, prop); + else + { + /* + while (s.Len() < _nameLenForStreams) + s = '0' + s; + */ + /* + if (si->Resource.IsFree()) + s = (AString)("[Free]" STRING_PATH_SEPARATOR) + sz; + else + */ + AString s (FILES_DIR_NAME STRING_PATH_SEPARATOR); + s.Add_UInt32((UInt32)(Int32)item.StreamIndex); + prop = s; + } + break; + + case kpidName: + if (item.ImageIndex >= 0) + _db.GetItemName(realIndex, prop); + else + { + char sz[16]; + ConvertUInt32ToString((UInt32)(Int32)item.StreamIndex, sz); + /* + AString s = sz; + while (s.Len() < _nameLenForStreams) + s = '0' + s; + */ + prop = sz; + } + break; + + case kpidShortName: + if (item.ImageIndex >= 0 && !item.IsAltStream) + _db.GetShortName(realIndex, prop); + break; + + case kpidPackSize: + { + if (si) + { + if (!si->Resource.IsSolidSmall()) + prop = si->Resource.PackSize; + else + { + if (si->Resource.SolidIndex >= 0) + { + const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex]; + if (ss.FirstSmallStream == item.StreamIndex) + prop = _db.DataStreams[ss.StreamIndex].Resource.PackSize; + } + } + } + else if (!item.IsDir) + prop = (UInt64)0; + + break; + } + + case kpidSize: + { + if (si) + { + if (si->Resource.IsSolid()) + { + if (si->Resource.IsSolidBig()) + { + if (si->Resource.SolidIndex >= 0) + { + const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex]; + prop = ss.UnpackSize; + } + } + else + prop = si->Resource.PackSize; + } + else + prop = si->Resource.UnpackSize; + } + else if (!item.IsDir) + prop = (UInt64)0; + + break; + } + + case kpidIsDir: prop = item.IsDir; break; + case kpidIsAltStream: prop = item.IsAltStream; break; + case kpidNumAltStreams: + { + if (!item.IsAltStream && mainItem->HasMetadata()) + { + UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; + UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6); + if (numAltStreams != 0) + { + if (!item.IsDir) + numAltStreams--; + prop = numAltStreams; + } + } + break; + } + + case kpidAttrib: + if (!item.IsAltStream && mainItem->ImageIndex >= 0) + { + /* + if (fileNameLen == 0 && isDir && !item.HasStream()) + item.Attrib = 0x10; // some swm archives have system/hidden attributes for root + */ + prop = (UInt32)Get32(metadata + 8); + } + break; + case kpidCTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; + case kpidATime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; + case kpidMTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; + + case kpidINode: + if (mainItem->HasMetadata() && !_isOldVersion) + { + UInt32 attrib = (UInt32)Get32(metadata + 8); + if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + { + // we don't know about that field in OLD WIM format + unsigned offset = 0x58; // (_db.IsOldVersion ? 0x30: 0x58); + UInt64 val = Get64(metadata + offset); + if (val != 0) + prop = val; + } + } + break; + + case kpidStreamId: + if (item.StreamIndex >= 0) + prop = (UInt32)item.StreamIndex; + break; + + case kpidMethod: + if (si) + { + const CResource &r = si->Resource; + if (r.IsSolid()) + { + if (r.SolidIndex >= 0) + { + CSolid &ss = _db.Solids[r.SolidIndex]; + MethodToProp(ss.Method, (int)ss.ChunkSizeBits, prop); + } + } + else + { + int method = 0; + int chunkSizeBits = -1; + if (r.IsCompressed()) + { + method = (int)vol->Header.GetMethod(); + chunkSizeBits = (int)vol->Header.ChunkSizeBits; + } + MethodToProp(method, chunkSizeBits, prop); + } + } + break; + + case kpidSolid: if (si) prop = si->Resource.IsSolid(); break; + case kpidLinks: if (si) prop = (UInt32)si->RefCount; break; + #ifdef WIM_DETAILS + case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break; + case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break; + #endif + } + } + else + { + index -= _db.SortedItems.Size(); + if (index < _numXmlItems) + { + switch (propID) + { + case kpidPath: + case kpidName: prop = _xmls[index].FileName; break; + case kpidIsDir: prop = false; break; + case kpidPackSize: + case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break; + case kpidMethod: /* prop = k_Method_Copy; */ break; + } + } + else + { + index -= _numXmlItems; + switch (propID) + { + case kpidPath: + case kpidName: + if (index < (UInt32)_db.VirtualRoots.Size()) + prop = _db.Images[_db.VirtualRoots[index]].RootName; + else + prop = FILES_DIR_NAME; + break; + case kpidIsDir: prop = true; break; + case kpidIsAux: prop = true; break; + } + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetRootProp(PROPID propID, PROPVARIANT *value)) +{ + // COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (_db.Images.Size() != 0 && _db.NumExcludededItems != 0) + { + const CImage &image = _db.Images[_db.IndexOfUserImage]; + const CItem &item = _db.Items[image.StartItem]; + if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage) + return E_FAIL; + const Byte *metadata = image.Meta + item.Offset; + + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidAttrib: prop = (UInt32)Get32(metadata + 8); break; + case kpidCTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; + case kpidATime: GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; + case kpidMTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; + } + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + +HRESULT CHandler::GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + const CItem &item = _db.Items[realIndex]; + if (item.IsAltStream || item.ImageIndex < 0) + return S_OK; + const CImage &image = _db.Images[item.ImageIndex]; + const Byte *metadata = image.Meta + item.Offset; + UInt32 securityId = Get32(metadata + 0xC); + if (securityId == (UInt32)(Int32)-1) + return S_OK; + if (securityId >= (UInt32)image.SecurOffsets.Size()) + return E_FAIL; + UInt32 offs = image.SecurOffsets[securityId]; + UInt32 len = image.SecurOffsets[securityId + 1] - offs; + const CByteBuffer &buf = image.Meta; + if (offs <= buf.Size() && buf.Size() - offs >= len) + { + *data = buf + offs; + *dataSize = len; + *propType = NPropDataType::kRaw; + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExcludededItems != 0) + { + const CImage &image = _db.Images[_db.IndexOfUserImage]; + const CItem &item = _db.Items[image.StartItem]; + if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage) + return E_FAIL; + return GetSecurity(image.StartItem, data, dataSize, propType); + } + return S_OK; +} + +static const Byte kRawProps[] = +{ + kpidSha1, + kpidNtReparse, + kpidNtSecure +}; + + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = Z7_ARRAY_SIZE(kRawProps); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) +{ + *propID = kRawProps[index]; + *name = NULL; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + if (index >= _db.SortedItems.Size()) + return S_OK; + + const CItem &item = _db.Items[_db.SortedItems[index]]; + + if (item.ImageIndex >= 0) + { + *parentType = item.IsAltStream ? NParentType::kAltStream : NParentType::kDir; + if (item.Parent >= 0) + { + if (_db.ExludedItem != item.Parent) + *parent = (unsigned)_db.Items[item.Parent].IndexInSorted; + } + else + { + CImage &image = _db.Images[item.ImageIndex]; + if (image.VirtualRootIndex >= 0) + *parent = _db.SortedItems.Size() + _numXmlItems + (unsigned)image.VirtualRootIndex; + } + } + else + *parent = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidName) + { + if (index < _db.SortedItems.Size()) + { + const CItem &item = _db.Items[_db.SortedItems[index]]; + if (item.ImageIndex < 0) + return S_OK; + const CImage &image = _db.Images[item.ImageIndex]; + *propType = NPropDataType::kUtf16z; + if (image.NumEmptyRootItems != 0 && item.Parent < 0) + { + const CByteBuffer &buf = _db.Images[item.ImageIndex].RootNameBuf; + *data = (void *)(const Byte *)buf; + *dataSize = (UInt32)buf.Size(); + return S_OK; + } + const Byte *meta = image.Meta + item.Offset + + (item.IsAltStream ? + (_isOldVersion ? 0x10 : 0x24) : + (_isOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2)); + *data = (const void *)(meta + 2); + *dataSize = (UInt32)Get16(meta) + 2; + return S_OK; + } + { + index -= _db.SortedItems.Size(); + if (index < _numXmlItems) + return S_OK; + index -= _numXmlItems; + if (index >= (UInt32)_db.VirtualRoots.Size()) + return S_OK; + const CByteBuffer &buf = _db.Images[_db.VirtualRoots[index]].RootNameBuf; + *data = (void *)(const Byte *)buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kUtf16z; + return S_OK; + } + } + + if (index >= _db.SortedItems.Size()) + return S_OK; + + unsigned index2 = _db.SortedItems[index]; + + if (propID == kpidNtSecure) + { + return GetSecurity(index2, data, dataSize, propType); + } + + const CItem &item = _db.Items[index2]; + if (propID == kpidSha1) + { + if (item.StreamIndex >= 0) + *data = _db.DataStreams[item.StreamIndex].Hash; + else + { + if (_isOldVersion) + return S_OK; + const Byte *sha1 = _db.Images[item.ImageIndex].Meta + item.Offset + (item.IsAltStream ? 0x10 : 0x40); + if (IsEmptySha(sha1)) + return S_OK; + *data = sha1; + } + *dataSize = kHashSize; + *propType = NPropDataType::kRaw; + return S_OK; + } + + if (propID == kpidNtReparse && !_isOldVersion) + { + // we don't know about Reparse field in OLD WIM format + + if (item.StreamIndex < 0) + return S_OK; + if (index2 >= _db.ItemToReparse.Size()) + return S_OK; + int reparseIndex = _db.ItemToReparse[index2]; + if (reparseIndex < 0) + return S_OK; + const CByteBuffer &buf = _db.ReparseItems[reparseIndex]; + if (buf.Size() == 0) + return S_OK; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + return S_OK; + } + + return S_OK; +} + +class CVolumeName +{ + UString _before; + UString _after; +public: + void InitName(const UString &name) + { + int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0) + dotPos = (int)name.Len(); + _before.SetFrom(name.Ptr(), (unsigned)dotPos); + _after = name.Ptr(dotPos); + } + + UString GetNextName(UInt32 index) const + { + UString s = _before; + s.Add_UInt32(index); + s += _after; + return s; + } +}; + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + + Close(); + { + CMyComPtr openVolumeCallback; + + CVolumeName seqName; + if (callback) + callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); + + UInt32 numVolumes = 1; + + for (UInt32 i = 1; i <= numVolumes; i++) + { + CMyComPtr curStream; + + if (i == 1) + curStream = inStream; + else + { + if (!openVolumeCallback) + continue; + const UString fullName = seqName.GetNextName(i); + const HRESULT result = openVolumeCallback->GetStream(fullName, &curStream); + if (result == S_FALSE) + continue; + if (result != S_OK) + return result; + if (!curStream) + break; + } + + CHeader header; + HRESULT res = NWim::ReadHeader(curStream, header, _phySize); + + if (res != S_OK) + { + if (i != 1 && res == S_FALSE) + continue; + return res; + } + + _isArc = true; + _bootIndex = header.BootIndex; + _version = header.Version; + _isOldVersion = header.IsOldVersion(); + if (_firstVolumeIndex >= 0) + if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header)) + break; + if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream) + break; + CWimXml xml; + xml.VolIndex = header.PartNumber; + res = _db.OpenXml(curStream, header, xml.Data); + + if (res == S_OK) + { + if (!xml.Parse()) + _xmlError = true; + + if (xml.IsEncrypted) + { + _unsupported = true; + return S_FALSE; + } + + UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size(); + totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items + if (totalFiles >= ((UInt32)1 << 30)) + totalFiles = 0; + res = _db.Open(curStream, header, (unsigned)totalFiles, callback); + } + + if (res != S_OK) + { + if (i != 1 && res == S_FALSE) + continue; + return res; + } + + while (_volumes.Size() <= header.PartNumber) + _volumes.AddNew(); + CVolume &volume = _volumes[header.PartNumber]; + volume.Header = header; + volume.Stream = curStream; + + _firstVolumeIndex = header.PartNumber; + + if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data) + { + xml.FileName = '['; + xml.FileName.Add_UInt32(xml.VolIndex); + xml.FileName += "].xml"; + _xmls.Add(xml); + } + + if (i == 1) + { + if (header.PartNumber != 1) + break; + if (!openVolumeCallback) + break; + numVolumes = header.NumParts; + { + NCOM::CPropVariant prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) + if (prop.vt != VT_BSTR) + break; + seqName.InitName(prop.bstrVal); + } + } + } + + RINOK(_db.FillAndCheck(_volumes)) + int defaultImageIndex = (int)_defaultImageNumber - 1; + + bool showImageNumber = (_db.Images.Size() != 1 && defaultImageIndex < 0); + if (!showImageNumber && _set_use_ShowImageNumber) + showImageNumber = _set_showImageNumber; + + if (!showImageNumber && _keepMode_ShowImageNumber) + showImageNumber = true; + + _showImageNumber = showImageNumber; + + RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber)) + RINOK(_db.ExtractReparseStreams(_volumes, callback)) + + /* + wchar_t sz[16]; + ConvertUInt32ToString(_db.DataStreams.Size(), sz); + _nameLenForStreams = MyStringLen(sz); + */ + + _xmlInComments = !_showImageNumber; + _numXmlItems = (_xmlInComments ? 0 : _xmls.Size()); + _numIgnoreItems = _db.ThereAreDeletedStreams ? 1 : 0; + } + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _firstVolumeIndex = -1; + _phySize = 0; + _db.Clear(); + _volumes.Clear(); + _xmls.Clear(); + // _nameLenForStreams = 0; + _xmlInComments = false; + _numXmlItems = 0; + _numIgnoreItems = 0; + _xmlError = false; + _isArc = false; + _unsupported = false; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + + if (allFilesMode) + numItems = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size() + _numIgnoreItems; + if (numItems == 0) + return S_OK; + + UInt32 i; + UInt64 totalSize = 0; + + for (i = 0; i < numItems; i++) + { + UInt32 index = allFilesMode ? i : indices[i]; + if (index < _db.SortedItems.Size()) + { + int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex; + if (streamIndex >= 0) + { + const CStreamInfo &si = _db.DataStreams[streamIndex]; + totalSize += _db.Get_UnpackSize_of_Resource(si.Resource); + } + } + else + { + index -= _db.SortedItems.Size(); + if (index < _numXmlItems) + totalSize += _xmls[index].Data.Size(); + } + } + + RINOK(extractCallback->SetTotal(totalSize)) + + totalSize = 0; + UInt64 currentItemUnPacked; + + int prevSuccessStreamIndex = -1; + + CUnpacker unpacker; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + for (i = 0;; i++, + totalSize += currentItemUnPacked) + { + currentItemUnPacked = 0; + lps->InSize = unpacker.TotalPacked; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + UInt32 index = allFilesMode ? i : indices[i]; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (index >= _db.SortedItems.Size()) + { + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + index -= _db.SortedItems.Size(); + if (index < _numXmlItems) + { + const CByteBuffer &data = _xmls[index].Data; + currentItemUnPacked = data.Size(); + if (realOutStream) + { + RINOK(WriteStream(realOutStream, (const Byte *)data, data.Size())) + realOutStream.Release(); + } + } + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + + const CItem &item = _db.Items[_db.SortedItems[index]]; + const int streamIndex = item.StreamIndex; + if (streamIndex < 0) + { + if (!item.IsDir) + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(!item.IsDir && _db.ItemHasStream(item) ? + NExtract::NOperationResult::kDataError : + NExtract::NOperationResult::kOK)) + continue; + } + + const CStreamInfo &si = _db.DataStreams[streamIndex]; + currentItemUnPacked = _db.Get_UnpackSize_of_Resource(si.Resource); + // currentItemPacked = _db.Get_PackSize_of_Resource(streamIndex); + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + Int32 opRes = NExtract::NOperationResult::kOK; + + if (streamIndex != prevSuccessStreamIndex || realOutStream) + { + Byte digest[kHashSize]; + const CVolume &vol = _volumes[si.PartNumber]; + const bool needDigest = !si.IsEmptyHash() && !_disable_Sha1Check; + const HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header, &_db, + realOutStream, lps, needDigest ? digest : NULL); + + if (res == S_OK) + { + if (!needDigest || memcmp(digest, si.Hash, kHashSize) == 0) + prevSuccessStreamIndex = streamIndex; + else + opRes = NExtract::NOperationResult::kCRCError; + } + else if (res == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else if (res == E_NOTIMPL) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else + return res; + } + + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _db.SortedItems.Size() + + _numXmlItems + + _db.VirtualRoots.Size() + + _numIgnoreItems; + return S_OK; +} + +CHandler::CHandler() +{ + _keepMode_ShowImageNumber = false; + InitDefaults(); + _xmlError = false; +} + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + InitDefaults(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name[0] == L'x') + { + // some clients write 'x' property. So we support it + UInt32 level = 0; + RINOK(ParsePropToUInt32(name.Ptr(1), prop, level)) + } + else if (name.IsEqualTo("is")) + { + RINOK(PROPVARIANT_to_bool(prop, _set_showImageNumber)) + _set_use_ShowImageNumber = true; + } + else if (name.IsEqualTo("im")) + { + UInt32 image = 9; + RINOK(ParsePropToUInt32(L"", prop, image)) + _defaultImageNumber = (int)image; + } + else if (name.IsPrefixedBy_Ascii_NoCase("mt")) + { + } + else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) + { + } + else if (name.IsPrefixedBy_Ascii_NoCase("crc")) + { + name.Delete(0, 3); + UInt32 crcSize = 1; + RINOK(ParsePropToUInt32(name, prop, crcSize)) + _disable_Sha1Check = (crcSize == 0); + } + else + { + bool processed = false; + RINOK(_timeOptions.Parse(name, prop, processed)) + if (!processed) + return E_INVALIDARG; + } + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::KeepModeForNextOpen()) +{ + _keepMode_ShowImageNumber = _showImageNumber; + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index 44a7f402b..126d233cb 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -1,95 +1,95 @@ -// WimHandler.h - -#ifndef ZIP7_INC_ARCHIVE_WIM_HANDLER_H -#define ZIP7_INC_ARCHIVE_WIM_HANDLER_H - -#include "../../../Common/MyCom.h" - -#include "../Common/HandlerOut.h" - -#include "WimIn.h" - -namespace NArchive { -namespace NWim { - -const Int32 kNumImagesMaxUpdate = 1 << 10; - -Z7_CLASS_IMP_CHandler_IInArchive_5( - IArchiveGetRawProps - , IArchiveGetRootProps - , IArchiveKeepModeForNextOpen - , ISetProperties - , IOutArchive -) - CDatabase _db; - UInt32 _version; - UInt32 _bootIndex; - - CObjectVector _volumes; - CObjectVector _xmls; - // unsigned _nameLenForStreams; - - unsigned _numXmlItems; - unsigned _numIgnoreItems; - - bool _isOldVersion; - bool _xmlInComments; - - bool _xmlError; - bool _isArc; - bool _unsupported; - - bool _set_use_ShowImageNumber; - bool _set_showImageNumber; - int _defaultImageNumber; - - bool _showImageNumber; - bool _keepMode_ShowImageNumber; - bool _disable_Sha1Check; - - UInt64 _phySize; - Int32 _firstVolumeIndex; - - CHandlerTimeOptions _timeOptions; - - void InitDefaults() - { - _disable_Sha1Check = false; - _set_use_ShowImageNumber = false; - _set_showImageNumber = false; - _defaultImageNumber = -1; - _timeOptions.Init(); - } - - bool IsUpdateSupported() const - { - if (ThereIsError()) return false; - if (_db.Images.Size() > kNumImagesMaxUpdate) return false; - - // Solid format is complicated. So we disable updating now. - if (!_db.Solids.IsEmpty()) return false; - - if (_volumes.Size() == 0) - return true; - - if (_volumes.Size() != 2) return false; - if (_volumes[0].Stream) return false; - if (_version != k_Version_NonSolid - // && _version != k_Version_Solid - ) return false; - - return true; - } - - bool ThereIsError() const { return _xmlError || _db.ThereIsError(); } - HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType); - - HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); - HRESULT GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft); -public: - CHandler(); -}; - -}} - -#endif +// WimHandler.h + +#ifndef ZIP7_INC_ARCHIVE_WIM_HANDLER_H +#define ZIP7_INC_ARCHIVE_WIM_HANDLER_H + +#include "../../../Common/MyCom.h" + +#include "../Common/HandlerOut.h" + +#include "WimIn.h" + +namespace NArchive { +namespace NWim { + +const Int32 kNumImagesMaxUpdate = 1 << 10; + +Z7_CLASS_IMP_CHandler_IInArchive_5( + IArchiveGetRawProps + , IArchiveGetRootProps + , IArchiveKeepModeForNextOpen + , ISetProperties + , IOutArchive +) + CDatabase _db; + UInt32 _version; + UInt32 _bootIndex; + + CObjectVector _volumes; + CObjectVector _xmls; + // unsigned _nameLenForStreams; + + unsigned _numXmlItems; + unsigned _numIgnoreItems; + + bool _isOldVersion; + bool _xmlInComments; + + bool _xmlError; + bool _isArc; + bool _unsupported; + + bool _set_use_ShowImageNumber; + bool _set_showImageNumber; + int _defaultImageNumber; + + bool _showImageNumber; + bool _keepMode_ShowImageNumber; + bool _disable_Sha1Check; + + UInt64 _phySize; + Int32 _firstVolumeIndex; + + CHandlerTimeOptions _timeOptions; + + void InitDefaults() + { + _disable_Sha1Check = false; + _set_use_ShowImageNumber = false; + _set_showImageNumber = false; + _defaultImageNumber = -1; + _timeOptions.Init(); + } + + bool IsUpdateSupported() const + { + if (ThereIsError()) return false; + if (_db.Images.Size() > kNumImagesMaxUpdate) return false; + + // Solid format is complicated. So we disable updating now. + if (!_db.Solids.IsEmpty()) return false; + + if (_volumes.Size() == 0) + return true; + + if (_volumes.Size() != 2) return false; + if (_volumes[0].Stream) return false; + if (_version != k_Version_NonSolid + // && _version != k_Version_Solid + ) return false; + + return true; + } + + bool ThereIsError() const { return _xmlError || _db.ThereIsError(); } + HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType); + + HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); + HRESULT GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft); +public: + CHandler(); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp index 76a2a73fa..3b2cb316b 100644 --- a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp +++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp @@ -1,1971 +1,1971 @@ -// WimHandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/UTFConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" -#include "../../Common/UniqBlocks.h" - -#include "../../Crypto/RandGen.h" -#include "../../Crypto/Sha1Cls.h" - -#include "../Common/OutStreamWithSha1.h" - -#include "WimHandler.h" - -using namespace NWindows; - -namespace NArchive { -namespace NWim { - -static const unsigned k_NumSubVectors_Bits = 12; // must be <= 16 - -struct CSortedIndex -{ - CObjectVector Vectors; - - CSortedIndex() - { - const unsigned k_NumSubVectors = 1 << k_NumSubVectors_Bits; - Vectors.ClearAndReserve(k_NumSubVectors); - for (unsigned i = 0; i < k_NumSubVectors; i++) - Vectors.AddNew(); - } -}; - -static int AddUniqHash(const CStreamInfo *streams, CSortedIndex &sorted2, const Byte *h, int streamIndexForInsert) -{ - const unsigned hash = (((unsigned)h[0] << 8) | (unsigned)h[1]) >> (16 - k_NumSubVectors_Bits); - CUIntVector &sorted = sorted2.Vectors[hash]; - unsigned left = 0, right = sorted.Size(); - while (left != right) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned index = sorted[mid]; - const Byte *hash2 = streams[index].Hash; - - unsigned i; - for (i = 0; i < kHashSize; i++) - if (h[i] != hash2[i]) - break; - - if (i == kHashSize) - return (int)index; - - if (h[i] < hash2[i]) - right = mid; - else - left = mid + 1; - } - - if (streamIndexForInsert != -1) - sorted.Insert(left, (unsigned)streamIndexForInsert); - - return -1; -} - - -struct CAltStream -{ - int UpdateIndex; - int HashIndex; - UInt64 Size; - UString Name; - bool Skip; - - CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {} -}; - - -struct CMetaItem -{ - int UpdateIndex; - int HashIndex; - - UInt64 Size; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - UInt64 FileID; - UInt64 VolID; - - UString Name; - UString ShortName; - - UInt32 Attrib; - int SecurityId; // -1: means no secutity ID - bool IsDir; - bool Skip; - unsigned NumSkipAltStreams; - CObjectVector AltStreams; - - CByteBuffer Reparse; - - unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; } - CMetaItem(): - UpdateIndex(-1) - , HashIndex(-1) - , Size(0) - , FileID(0) - , VolID(0) - , Attrib(0) - , SecurityId(-1) - , IsDir(false) - , Skip(false) - , NumSkipAltStreams(0) - { - FILETIME_Clear(CTime); - FILETIME_Clear(ATime); - FILETIME_Clear(MTime); - } -}; - - -static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2) -{ - if (a1.VolID < a2.VolID) return -1; - if (a1.VolID > a2.VolID) return 1; - if (a1.FileID < a2.FileID) return -1; - if (a1.FileID > a2.FileID) return 1; - if (a1.Size < a2.Size) return -1; - if (a1.Size > a2.Size) return 1; - return ::CompareFileTime(&a1.MTime, &a2.MTime); -} - - -static int AddToHardLinkList(const CObjectVector &metaItems, unsigned indexOfItem, CUIntVector &indexes) -{ - const CMetaItem &mi = metaItems[indexOfItem]; - unsigned left = 0, right = indexes.Size(); - while (left != right) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned index = indexes[mid]; - const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); - if (comp == 0) - return (int)index; - if (comp < 0) - right = mid; - else - left = mid + 1; - } - indexes.Insert(left, indexOfItem); - return -1; -} - - -struct CUpdateItem -{ - unsigned CallbackIndex; // index in callback - - int MetaIndex; // index in in MetaItems[] - - int AltStreamIndex; // index in CMetaItem::AltStreams vector - // -1: if not alt stream? - - int InArcIndex; // >= 0, if we use OLD Data - // -1, if we use NEW Data - - CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {} -}; - - -struct CDir -{ - int MetaIndex; - CObjectVector Dirs; - CUIntVector Files; // indexes in MetaItems[] - - CDir(): MetaIndex(-1) {} - unsigned GetNumDirs() const; - unsigned GetNumFiles() const; - UInt64 GetTotalSize(const CObjectVector &metaItems) const; - bool FindDir(const CObjectVector &items, const UString &name, unsigned &index); -}; - -/* imagex counts Junctions as files (not as dirs). - We suppose that it's not correct */ - -unsigned CDir::GetNumDirs() const -{ - unsigned num = Dirs.Size(); - FOR_VECTOR (i, Dirs) - num += Dirs[i].GetNumDirs(); - return num; -} - -unsigned CDir::GetNumFiles() const -{ - unsigned num = Files.Size(); - FOR_VECTOR (i, Dirs) - num += Dirs[i].GetNumFiles(); - return num; -} - -UInt64 CDir::GetTotalSize(const CObjectVector &metaItems) const -{ - UInt64 sum = 0; - unsigned i; - for (i = 0; i < Files.Size(); i++) - sum += metaItems[Files[i]].Size; - for (i = 0; i < Dirs.Size(); i++) - sum += Dirs[i].GetTotalSize(metaItems); - return sum; -} - -bool CDir::FindDir(const CObjectVector &items, const UString &name, unsigned &index) -{ - unsigned left = 0, right = Dirs.Size(); - while (left != right) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); - if (comp == 0) - { - index = mid; - return true; - } - if (comp < 0) - right = mid; - else - left = mid + 1; - } - index = left; - return false; -} - - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) -{ - *type = NFileTimeType::kWindows; - return S_OK; -} - - -HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value) -{ - if (arcIndex != -1) - return GetProperty((UInt32)arcIndex, propID, value); - return callback->GetProperty(callbackIndex, propID, value); -} - - -HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft) -{ - ft.dwLowDateTime = ft.dwHighDateTime = 0; - NCOM::CPropVariant prop; - RINOK(GetOutProperty(callback, callbackIndex, arcIndex, propID, &prop)) - if (prop.vt == VT_FILETIME) - ft = prop.filetime; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - return S_OK; -} - - -static HRESULT GetRootTime( - IArchiveGetRootProps *callback, - IArchiveGetRootProps *arcRoot, - PROPID propID, FILETIME &ft) -{ - NCOM::CPropVariant prop; - if (callback) - { - RINOK(callback->GetRootProp(propID, &prop)) - if (prop.vt == VT_FILETIME) - { - ft = prop.filetime; - return S_OK; - } - if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - if (arcRoot) - { - RINOK(arcRoot->GetRootProp(propID, &prop)) - if (prop.vt == VT_FILETIME) - { - ft = prop.filetime; - return S_OK; - } - if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - return S_OK; -} - -#define Set16(p, d) SetUi16(p, d) -#define Set32(p, d) SetUi32(p, d) -#define Set64(p, d) SetUi64(p, d) - -void CResource::WriteTo(Byte *p) const -{ - Set64(p, PackSize) - p[7] = Flags; - Set64(p + 8, Offset) - Set64(p + 16, UnpackSize) -} - - -void CHeader::WriteTo(Byte *p) const -{ - memcpy(p, kSignature, kSignatureSize); - Set32(p + 8, kHeaderSizeMax) - Set32(p + 0xC, Version) - Set32(p + 0x10, Flags) - Set32(p + 0x14, ChunkSize) - memcpy(p + 0x18, Guid, 16); - Set16(p + 0x28, PartNumber) - Set16(p + 0x2A, NumParts) - Set32(p + 0x2C, NumImages) - OffsetResource.WriteTo(p + 0x30); - XmlResource.WriteTo(p + 0x48); - MetadataResource.WriteTo(p + 0x60); - IntegrityResource.WriteTo(p + 0x7C); - Set32(p + 0x78, BootIndex) - memset(p + 0x94, 0, 60); -} - - -void CStreamInfo::WriteTo(Byte *p) const -{ - Resource.WriteTo(p); - Set16(p + 0x18, PartNumber) - Set32(p + 0x1A, RefCount) - memcpy(p + 0x1E, Hash, kHashSize); -} - - -static void SetFileTimeToMem(Byte *p, const FILETIME &ft) -{ - Set32(p, ft.dwLowDateTime) - Set32(p + 4, ft.dwHighDateTime) -} - -static size_t WriteItem_Dummy(const CMetaItem &item) -{ - if (item.Skip) - return 0; - unsigned fileNameLen = item.Name.Len() * 2; - // we write fileNameLen + 2 + 2 to be same as original WIM. - unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2); - - const unsigned shortNameLen = item.ShortName.Len() * 2; - const unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); - - size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7); - if (item.GetNumAltStreams() != 0) - { - if (!item.IsDir) - { - const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7); - totalLen += curLen; - } - FOR_VECTOR (i, item.AltStreams) - { - const CAltStream &ss = item.AltStreams[i]; - if (ss.Skip) - continue; - fileNameLen = ss.Name.Len() * 2; - fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2); - const UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7); - totalLen += curLen; - } - } - return totalLen; -} - - -static size_t WriteItem(const CStreamInfo *streams, const CMetaItem &item, Byte *p) -{ - if (item.Skip) - return 0; - unsigned fileNameLen = item.Name.Len() * 2; - unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2); - unsigned shortNameLen = item.ShortName.Len() * 2; - unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); - - size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7); - - memset(p, 0, totalLen); - Set64(p, totalLen) - Set64(p + 8, item.Attrib) - Set32(p + 0xC, (UInt32)(Int32)item.SecurityId) - SetFileTimeToMem(p + 0x28, item.CTime); - SetFileTimeToMem(p + 0x30, item.ATime); - SetFileTimeToMem(p + 0x38, item.MTime); - - /* WIM format probably doesn't support hard links to symbolic links. - In these cases it just stores symbolic links (REPARSE TAGS). - Check it in new versions of WIM software form MS !!! - We also follow that scheme */ - - if (item.Reparse.Size() != 0) - { - UInt32 tag = GetUi32(item.Reparse); - Set32(p + 0x58, tag) - // Set32(p + 0x5C, 0); // probably it's always ZERO - } - else if (item.FileID != 0) - { - Set64(p + 0x58, item.FileID) - } - - Set16(p + 0x62, (UInt16)shortNameLen) - Set16(p + 0x64, (UInt16)fileNameLen) - unsigned i; - for (i = 0; i * 2 < fileNameLen; i++) - Set16(p + kDirRecordSize + i * 2, (UInt16)item.Name[i]) - for (i = 0; i * 2 < shortNameLen; i++) - Set16(p + kDirRecordSize + fileNameLen2 + i * 2, (UInt16)item.ShortName[i]) - - if (item.GetNumAltStreams() == 0) - { - if (item.HashIndex >= 0) - memcpy(p + 0x40, streams[item.HashIndex].Hash, kHashSize); - } - else - { - Set16(p + 0x60, (UInt16)(item.GetNumAltStreams() + (item.IsDir ? 0 : 1))) - p += totalLen; - - if (!item.IsDir) - { - const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7); - memset(p, 0, curLen); - Set64(p, curLen) - if (item.HashIndex >= 0) - memcpy(p + 0x10, streams[item.HashIndex].Hash, kHashSize); - totalLen += curLen; - p += curLen; - } - - FOR_VECTOR (si, item.AltStreams) - { - const CAltStream &ss = item.AltStreams[si]; - if (ss.Skip) - continue; - - fileNameLen = ss.Name.Len() * 2; - fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2); - UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7); - memset(p, 0, curLen); - - Set64(p, curLen) - if (ss.HashIndex >= 0) - memcpy(p + 0x10, streams[ss.HashIndex].Hash, kHashSize); - Set16(p + 0x24, (UInt16)fileNameLen) - for (i = 0; i * 2 < fileNameLen; i++) - Set16(p + 0x26 + i * 2, (UInt16)ss.Name[i]) - totalLen += curLen; - p += curLen; - } - } - - return totalLen; -} - - -struct CDb -{ - CMetaItem DefaultDirItem; - const CStreamInfo *Hashes; - CObjectVector MetaItems; - CRecordVector UpdateItems; - CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams - to disk (the order of tree items). */ - - size_t WriteTree_Dummy(const CDir &tree) const; - void WriteTree(const CDir &tree, Byte *dest, size_t &pos) const; - void WriteOrderList(const CDir &tree); -}; - - -size_t CDb::WriteTree_Dummy(const CDir &tree) const -{ - unsigned i; - size_t pos = 0; - for (i = 0; i < tree.Files.Size(); i++) - pos += WriteItem_Dummy(MetaItems[tree.Files[i]]); - for (i = 0; i < tree.Dirs.Size(); i++) - { - const CDir &subDir = tree.Dirs[i]; - pos += WriteItem_Dummy(MetaItems[subDir.MetaIndex]); - pos += WriteTree_Dummy(subDir); - } - return pos + 8; -} - - -void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const -{ - unsigned i; - for (i = 0; i < tree.Files.Size(); i++) - pos += WriteItem(Hashes, MetaItems[tree.Files[i]], dest + pos); - - size_t posStart = pos; - for (i = 0; i < tree.Dirs.Size(); i++) - pos += WriteItem_Dummy(MetaItems[tree.Dirs[i].MetaIndex]); - - Set64(dest + pos, 0) - - pos += 8; - - for (i = 0; i < tree.Dirs.Size(); i++) - { - const CDir &subDir = tree.Dirs[i]; - const CMetaItem &metaItem = MetaItems[subDir.MetaIndex]; - bool needCreateTree = (metaItem.Reparse.Size() == 0) - || !subDir.Files.IsEmpty() - || !subDir.Dirs.IsEmpty(); - size_t len = WriteItem(Hashes, metaItem, dest + posStart); - posStart += len; - if (needCreateTree) - { - Set64(dest + posStart - len + 0x10, pos) // subdirOffset - WriteTree(subDir, dest, pos); - } - } -} - - -void CDb::WriteOrderList(const CDir &tree) -{ - if (tree.MetaIndex >= 0) - { - const CMetaItem &mi = MetaItems[tree.MetaIndex]; - if (mi.UpdateIndex >= 0) - UpdateIndexes.Add((unsigned)mi.UpdateIndex); - FOR_VECTOR (si, mi.AltStreams) - UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex); - } - - unsigned i; - for (i = 0; i < tree.Files.Size(); i++) - { - const CMetaItem &mi = MetaItems[tree.Files[i]]; - UpdateIndexes.Add((unsigned)mi.UpdateIndex); - FOR_VECTOR (si, mi.AltStreams) - UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex); - } - - for (i = 0; i < tree.Dirs.Size(); i++) - WriteOrderList(tree.Dirs[i]); -} - - -static void AddTag_ToString(AString &s, const char *name, const char *value) -{ - s.Add_Char('<'); - s += name; - s.Add_Char('>'); - s += value; - s.Add_Char('<'); - s.Add_Slash(); - s += name; - s.Add_Char('>'); -} - - -static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value) -{ - char temp[32]; - ConvertUInt64ToString(value, temp); - AddTag_ToString(s, name, temp); -} - - -static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name) -{ - const int index = parentItem.FindSubTag(name); - if (index < 0) - { - CXmlItem &subItem = parentItem.SubItems.AddNew(); - subItem.IsTag = true; - subItem.Name = name; - return subItem; - } - CXmlItem &subItem = parentItem.SubItems[index]; - subItem.SubItems.Clear(); - return subItem; -} - - -static void AddTag_UInt64_2(CXmlItem &item, UInt64 value) -{ - CXmlItem &subItem = item.SubItems.AddNew(); - subItem.IsTag = false; - char temp[32]; - ConvertUInt64ToString(value, temp); - subItem.Name = temp; -} - - -static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value) -{ - AddTag_UInt64_2(AddUniqueTag(parentItem, name), value); -} - - -static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value) -{ - item.IsTag = true; - item.Name = name; - char temp[16]; - temp[0] = '0'; - temp[1] = 'x'; - ConvertUInt32ToHex8Digits(value, temp + 2); - CXmlItem &subItem = item.SubItems.AddNew(); - subItem.IsTag = false; - subItem.Name = temp; -} - - -static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft) -{ - AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime); - AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime); -} - - -static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft) -{ - AddTag_Time_2(AddUniqueTag(parentItem, name), ft); -} - - -static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value) -{ - if (parentItem.FindSubTag(name) >= 0) - return; - CXmlItem &tag = parentItem.SubItems.AddNew(); - tag.IsTag = true; - tag.Name = name; - CXmlItem &subItem = tag.SubItems.AddNew(); - subItem.IsTag = false; - subItem.Name = value; -} - - -void CHeader::SetDefaultFields(bool useLZX) -{ - Version = k_Version_NonSolid; - Flags = NHeaderFlags::kReparsePointFixup; - ChunkSize = 0; - if (useLZX) - { - Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX; - ChunkSize = kChunkSize; - ChunkSizeBits = kChunkSizeBits; - } - MY_RAND_GEN(Guid, 16); - PartNumber = 1; - NumParts = 1; - NumImages = 1; - BootIndex = 0; - OffsetResource.Clear(); - XmlResource.Clear(); - MetadataResource.Clear(); - IntegrityResource.Clear(); -} - - -static void AddTrees(CObjectVector &trees, CObjectVector &metaItems, const CMetaItem &ri, int curTreeIndex) -{ - while (curTreeIndex >= (int)trees.Size()) - trees.AddNew().Dirs.AddNew().MetaIndex = (int)metaItems.Add(ri); -} - - -#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) - - - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback)) -{ - COM_TRY_BEGIN - - if (!IsUpdateSupported()) - return E_NOTIMPL; - - bool isUpdate = (_volumes.Size() != 0); - int defaultImageIndex = _defaultImageNumber - 1; - bool showImageNumber; - - if (isUpdate) - { - showImageNumber = _showImageNumber; - if (!showImageNumber) - defaultImageIndex = _db.IndexOfUserImage; - } - else - { - showImageNumber = (_set_use_ShowImageNumber && _set_showImageNumber); - if (!showImageNumber) - defaultImageIndex = 0; - } - - if (defaultImageIndex >= kNumImagesMaxUpdate) - return E_NOTIMPL; - - CMyComPtr outStream; - RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream)) - if (!outStream) - return E_NOTIMPL; - if (!callback) - return E_FAIL; - - CDb db; - CObjectVector trees; - - CMetaItem ri; // default DIR item - FILETIME ftCur; - NTime::GetCurUtcFileTime(ftCur); - // ri.MTime = ri.ATime = ri.CTime = ftCur; - ri.Attrib = FILE_ATTRIBUTE_DIRECTORY; - ri.IsDir = true; - - - // ---------- Detect changed images ---------- - - unsigned i; - CBoolVector isChangedImage; - { - CUIntVector numUnchangedItemsInImage; - for (i = 0; i < _db.Images.Size(); i++) - { - numUnchangedItemsInImage.Add(0); - isChangedImage.Add(false); - } - - for (i = 0; i < numItems; i++) - { - UInt32 indexInArchive; - Int32 newData, newProps; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)) - if (newProps == 0) - { - if (indexInArchive >= _db.SortedItems.Size()) - continue; - const CItem &item = _db.Items[_db.SortedItems[indexInArchive]]; - if (newData == 0) - { - if (item.ImageIndex >= 0) - numUnchangedItemsInImage[item.ImageIndex]++; - } - else - { - // oldProps & newData. Current version of 7-Zip doesn't use it - if (item.ImageIndex >= 0) - isChangedImage[item.ImageIndex] = true; - } - } - else if (!showImageNumber) - { - if (defaultImageIndex >= 0 && defaultImageIndex < (int)isChangedImage.Size()) - isChangedImage[defaultImageIndex] = true; - } - else - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidPath, &prop)) - - if (prop.vt != VT_BSTR) - return E_INVALIDARG; - const wchar_t *path = prop.bstrVal; - if (!path) - return E_INVALIDARG; - - const wchar_t *end; - UInt64 val = ConvertStringToUInt64(path, &end); - if (end == path) - return E_INVALIDARG; - if (val == 0 || val > kNumImagesMaxUpdate) - return E_INVALIDARG; - wchar_t c = *end; - if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR) - return E_INVALIDARG; - unsigned imageIndex = (unsigned)val - 1; - if (imageIndex < _db.Images.Size()) - isChangedImage[imageIndex] = true; - if (_defaultImageNumber > 0 && val != (unsigned)_defaultImageNumber) - return E_INVALIDARG; - } - } - - for (i = 0; i < _db.Images.Size(); i++) - if (!isChangedImage[i]) - isChangedImage[i] = _db.GetNumUserItemsInImage(i) != numUnchangedItemsInImage[i]; - } - - if (defaultImageIndex >= 0) - { - for (i = 0; i < _db.Images.Size(); i++) - if ((int)i != defaultImageIndex) - isChangedImage[i] = false; - } - - CMyComPtr getRawProps; - callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); - - CMyComPtr getRootProps; - callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps); - - CObjectVector secureBlocks; - - if (!showImageNumber && (getRootProps || isUpdate) && - ( - defaultImageIndex >= (int)isChangedImage.Size() - || defaultImageIndex < 0 // test it - || isChangedImage[defaultImageIndex] - )) - { - // Fill Root Item: Metadata and security - CMetaItem rootItem = ri; - { - const void *data = NULL; - UInt32 dataSize = 0; - UInt32 propType = 0; - if (getRootProps) - { - RINOK(getRootProps->GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType)) - } - if (dataSize == 0 && isUpdate) - { - RINOK(GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType)) - } - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - while (defaultImageIndex >= (int)secureBlocks.Size()) - secureBlocks.AddNew(); - CUniqBlocks &secUniqBlocks = secureBlocks[defaultImageIndex]; - rootItem.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize); - } - } - - IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL; - - if (_timeOptions.Write_CTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime)) - if (_timeOptions.Write_ATime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime)) - if (_timeOptions.Write_MTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidMTime, rootItem.MTime)) - - { - NCOM::CPropVariant prop; - if (getRootProps) - { - RINOK(getRootProps->GetRootProp(kpidAttrib, &prop)) - if (prop.vt == VT_UI4) - rootItem.Attrib = prop.ulVal; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - if (prop.vt == VT_EMPTY && thisGetRoot) - { - RINOK(GetRootProp(kpidAttrib, &prop)) - if (prop.vt == VT_UI4) - rootItem.Attrib = prop.ulVal; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - rootItem.Attrib |= FILE_ATTRIBUTE_DIRECTORY; - } - - AddTrees(trees, db.MetaItems, ri, defaultImageIndex); - db.MetaItems[trees[defaultImageIndex].Dirs[0].MetaIndex] = rootItem; - } - - // ---------- Request Metadata for changed items ---------- - - UString fileName; - - for (i = 0; i < numItems; i++) - { - CUpdateItem ui; - UInt32 indexInArchive; - Int32 newData, newProps; - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)) - - if (newData == 0 || newProps == 0) - { - if (indexInArchive >= _db.SortedItems.Size()) - continue; - - const CItem &item = _db.Items[_db.SortedItems[indexInArchive]]; - - if (item.ImageIndex >= 0) - { - if (!isChangedImage[item.ImageIndex]) - { - if (newData == 0 && newProps == 0) - continue; - return E_FAIL; - } - } - else - { - // if deleted item was not renamed, we just skip it - if (newProps == 0) - continue; - if (item.StreamIndex >= 0) - { - // we don't support property change for SolidBig streams - if (_db.DataStreams[item.StreamIndex].Resource.IsSolidBig()) - return E_NOTIMPL; - } - } - - if (newData == 0) - ui.InArcIndex = (Int32)indexInArchive; - } - - // we set arcIndex only if we must use old props - const Int32 arcIndex = (newProps ? -1 : (Int32)indexInArchive); - - bool isDir = false; - { - NCOM::CPropVariant prop; - RINOK(GetOutProperty(callback, i, arcIndex, kpidIsDir, &prop)) - if (prop.vt == VT_BOOL) - isDir = (prop.boolVal != VARIANT_FALSE); - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - - bool isAltStream = false; - { - NCOM::CPropVariant prop; - RINOK(GetOutProperty(callback, i, arcIndex, kpidIsAltStream, &prop)) - if (prop.vt == VT_BOOL) - isAltStream = (prop.boolVal != VARIANT_FALSE); - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - - if (isDir && isAltStream) - return E_INVALIDARG; - - UInt64 size = 0; - UInt64 iNode = 0; - - if (!isDir) - { - if (!newData) - { - NCOM::CPropVariant prop; - GetProperty(indexInArchive, kpidINode, &prop); - if (prop.vt == VT_UI8) - iNode = prop.uhVal.QuadPart; - } - - NCOM::CPropVariant prop; - - if (newData) - { - RINOK(callback->GetProperty(i, kpidSize, &prop)) - } - else - { - RINOK(GetProperty(indexInArchive, kpidSize, &prop)) - } - - if (prop.vt == VT_UI8) - size = prop.uhVal.QuadPart; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - - { - NCOM::CPropVariant propPath; - const wchar_t *path = NULL; - RINOK(GetOutProperty(callback, i, arcIndex, kpidPath, &propPath)) - if (propPath.vt == VT_BSTR) - path = propPath.bstrVal; - else if (propPath.vt != VT_EMPTY) - return E_INVALIDARG; - - if (!path) - return E_INVALIDARG; - - CDir *curItem = NULL; - bool isRootImageDir = false; - fileName.Empty(); - - int imageIndex; - - if (!showImageNumber) - { - imageIndex = defaultImageIndex; - AddTrees(trees, db.MetaItems, ri, imageIndex); - curItem = &trees[imageIndex].Dirs[0]; - } - else - { - const wchar_t *end; - UInt64 val = ConvertStringToUInt64(path, &end); - if (end == path) - return E_INVALIDARG; - if (val == 0 || val > kNumImagesMaxUpdate) - return E_INVALIDARG; - - imageIndex = (int)val - 1; - if (imageIndex < (int)isChangedImage.Size()) - if (!isChangedImage[imageIndex]) - return E_FAIL; - - AddTrees(trees, db.MetaItems, ri, imageIndex); - curItem = &trees[imageIndex].Dirs[0]; - wchar_t c = *end; - - if (c == 0) - { - if (!isDir || isAltStream) - return E_INVALIDARG; - ui.MetaIndex = curItem->MetaIndex; - isRootImageDir = true; - } - else if (c == ':') - { - if (isDir || !isAltStream) - return E_INVALIDARG; - ui.MetaIndex = curItem->MetaIndex; - CAltStream ss; - ss.Size = size; - ss.Name = end + 1; - ss.UpdateIndex = (int)db.UpdateItems.Size(); - ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); - } - else if (c == WCHAR_PATH_SEPARATOR || c == L'/') - { - path = end + 1; - if (*path == 0) - return E_INVALIDARG; - } - else - return E_INVALIDARG; - } - - if (ui.MetaIndex < 0) - { - for (;;) - { - const wchar_t c = *path++; - if (c == 0) - break; - if (c == WCHAR_PATH_SEPARATOR || c == L'/') - { - unsigned indexOfDir; - if (!curItem->FindDir(db.MetaItems, fileName, indexOfDir)) - { - CDir &dir = curItem->Dirs.InsertNew(indexOfDir); - dir.MetaIndex = (int)db.MetaItems.Add(ri); - db.MetaItems.Back().Name = fileName; - } - curItem = &curItem->Dirs[indexOfDir]; - fileName.Empty(); - } - else - { - /* - #if WCHAR_MAX > 0xffff - if (c >= 0x10000) - { - c -= 0x10000; - - if (c < (1 << 20)) - { - wchar_t c0 = 0xd800 + ((c >> 10) & 0x3FF); - fileName += c0; - c = 0xdc00 + (c & 0x3FF); - } - else - c = '_'; // we change character unsupported by UTF16 - } - #endif - */ - - fileName += c; - } - } - - if (isAltStream) - { - int colonPos = fileName.Find(L':'); - if (colonPos < 0) - return E_INVALIDARG; - - // we want to support cases of c::substream, where c: is drive name - if (colonPos == 1 && fileName[2] == L':' && IS_LETTER_CHAR(fileName[0])) - colonPos = 2; - const UString mainName = fileName.Left((unsigned)colonPos); - unsigned indexOfDir; - - if (mainName.IsEmpty()) - ui.MetaIndex = curItem->MetaIndex; - else if (curItem->FindDir(db.MetaItems, mainName, indexOfDir)) - ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex; - else - { - for (int j = (int)curItem->Files.Size() - 1; j >= 0; j--) - { - const unsigned metaIndex = curItem->Files[j]; - const CMetaItem &mi = db.MetaItems[metaIndex]; - if (CompareFileNames(mainName, mi.Name) == 0) - { - ui.MetaIndex = (int)metaIndex; - break; - } - } - } - - if (ui.MetaIndex >= 0) - { - CAltStream ss; - ss.Size = size; - ss.Name = fileName.Ptr(colonPos + 1); - ss.UpdateIndex = (int)db.UpdateItems.Size(); - ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); - } - } - } - - - if (ui.MetaIndex < 0 || isRootImageDir) - { - if (!isRootImageDir) - { - ui.MetaIndex = (int)db.MetaItems.Size(); - db.MetaItems.AddNew(); - } - - CMetaItem &mi = db.MetaItems[ui.MetaIndex]; - mi.Size = size; - mi.IsDir = isDir; - mi.Name = fileName; - mi.UpdateIndex = (int)db.UpdateItems.Size(); - { - NCOM::CPropVariant prop; - RINOK(GetOutProperty(callback, i, arcIndex, kpidAttrib, &prop)) - if (prop.vt == VT_EMPTY) - mi.Attrib = 0; - else if (prop.vt == VT_UI4) - mi.Attrib = prop.ulVal; - else - return E_INVALIDARG; - if (isDir) - mi.Attrib |= FILE_ATTRIBUTE_DIRECTORY; - } - - if (arcIndex != -1 || _timeOptions.Write_CTime.Val) - RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime)) - if (arcIndex != -1 || _timeOptions.Write_ATime.Val) - RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime)) - if (arcIndex != -1 || _timeOptions.Write_MTime.Val) - RINOK(GetTime(callback, i, arcIndex, kpidMTime, mi.MTime)) - - { - NCOM::CPropVariant prop; - RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop)) - if (prop.vt == VT_BSTR) - mi.ShortName.SetFromBstr(prop.bstrVal); - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - - while (imageIndex >= (int)secureBlocks.Size()) - secureBlocks.AddNew(); - - if (!isAltStream && (getRawProps || arcIndex >= 0)) - { - CUniqBlocks &secUniqBlocks = secureBlocks[imageIndex]; - const void *data; - UInt32 dataSize; - UInt32 propType; - - data = NULL; - dataSize = 0; - propType = 0; - - if (arcIndex >= 0) - { - GetRawProp((UInt32)arcIndex, kpidNtSecure, &data, &dataSize, &propType); - } - else - { - getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); - } - - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - mi.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize); - } - - data = NULL; - dataSize = 0; - propType = 0; - - if (arcIndex >= 0) - { - GetRawProp((UInt32)arcIndex, kpidNtReparse, &data, &dataSize, &propType); - } - else - { - getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType); - } - - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - mi.Reparse.CopyFrom((const Byte *)data, dataSize); - } - } - - if (!isRootImageDir) - { - if (isDir) - { - unsigned indexOfDir; - if (curItem->FindDir(db.MetaItems, fileName, indexOfDir)) - curItem->Dirs[indexOfDir].MetaIndex = ui.MetaIndex; - else - curItem->Dirs.InsertNew(indexOfDir).MetaIndex = ui.MetaIndex; - } - else - curItem->Files.Add((unsigned)ui.MetaIndex); - } - } - - } - - if (iNode != 0 && ui.MetaIndex >= 0 && ui.AltStreamIndex < 0) - db.MetaItems[ui.MetaIndex].FileID = iNode; - - ui.CallbackIndex = i; - db.UpdateItems.Add(ui); - } - - unsigned numNewImages = trees.Size(); - for (i = numNewImages; i < isChangedImage.Size(); i++) - if (!isChangedImage[i]) - numNewImages = i + 1; - - AddTrees(trees, db.MetaItems, ri, (int)numNewImages - 1); - - for (i = 0; i < trees.Size(); i++) - if (i >= isChangedImage.Size() || isChangedImage[i]) - db.WriteOrderList(trees[i]); - - - UInt64 complexity = 0; - - unsigned numDataStreams = _db.DataStreams.Size(); - CUIntArr streamsRefs(numDataStreams); - for (i = 0; i < numDataStreams; i++) - streamsRefs[i] = 0; - - // ---------- Calculate Streams Refs Counts in unchanged images - - for (i = 0; i < _db.Images.Size(); i++) - { - if (isChangedImage[i]) - continue; - complexity += _db.MetaStreams[i].Resource.PackSize; - const CImage &image = _db.Images[i]; - unsigned endItem = image.StartItem + image.NumItems; - for (unsigned k = image.StartItem; k < endItem; k++) - { - const CItem &item = _db.Items[k]; - if (item.StreamIndex >= 0) - streamsRefs[(unsigned)item.StreamIndex]++; - } - } - - - // ---------- Update Streams Refs Counts in changed images - - for (i = 0; i < db.UpdateIndexes.Size(); i++) - { - const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; - - if (ui.InArcIndex >= 0) - { - if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) - continue; - const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; - if (item.StreamIndex >= 0) - streamsRefs[(unsigned)item.StreamIndex]++; - } - else - { - const CMetaItem &mi = db.MetaItems[ui.MetaIndex]; - UInt64 size; - if (ui.AltStreamIndex < 0) - size = mi.Size; - else - size = mi.AltStreams[ui.AltStreamIndex].Size; - complexity += size; - } - } - - // Clear ref counts for SolidBig streams - - for (i = 0; i < _db.DataStreams.Size(); i++) - if (_db.DataStreams[i].Resource.IsSolidBig()) - streamsRefs[i] = 0; - - // Set ref counts for SolidBig streams - - for (i = 0; i < _db.DataStreams.Size(); i++) - if (streamsRefs[i] != 0) - { - const CResource &rs = _db.DataStreams[i].Resource; - if (rs.IsSolidSmall()) - streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] = 1; - } - - for (i = 0; i < _db.DataStreams.Size(); i++) - if (streamsRefs[i] != 0) - { - const CResource &rs = _db.DataStreams[i].Resource; - if (!rs.IsSolidSmall()) - complexity += rs.PackSize; - } - - RINOK(callback->SetTotal(complexity)) - UInt64 totalComplexity = complexity; - - CMyComPtr2_Create lps; - lps->Init(callback, true); - CMyComPtr2_Create copyCoder; - - complexity = 0; - - // bool useResourceCompression = false; - // use useResourceCompression only if CHeader::Flags compression is also set - - CHeader header; - header.SetDefaultFields(false); - - if (isUpdate) - { - const CHeader &srcHeader = _volumes[1].Header; - header.Flags = srcHeader.Flags; - header.Version = srcHeader.Version; - header.ChunkSize = srcHeader.ChunkSize; - header.ChunkSizeBits = srcHeader.ChunkSizeBits; - } - - CMyComPtr setRestriction; - outSeqStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction); - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, kHeaderSizeMax)) - - { - Byte buf[kHeaderSizeMax]; - header.WriteTo(buf); - RINOK(WriteStream(outStream, buf, kHeaderSizeMax)) - } - - UInt64 curPos = kHeaderSizeMax; - - CMyComPtr2_Create inShaStream; - - CLimitedSequentialInStream *inStreamLimitedSpec = NULL; - CMyComPtr inStreamLimited; - if (_volumes.Size() == 2) - { - inStreamLimitedSpec = new CLimitedSequentialInStream; - inStreamLimited = inStreamLimitedSpec; - inStreamLimitedSpec->SetStream(_volumes[1].Stream); - } - - - CRecordVector streams; - CSortedIndex sortedHashes; // indexes to streams, sorted by SHA1 - - // ---------- Copy unchanged data streams ---------- - - UInt64 solidRunOffset = 0; - UInt64 curSolidSize = 0; - - for (i = 0; i < _db.DataStreams.Size(); i++) - { - const CStreamInfo &siOld = _db.DataStreams[i]; - const CResource &rs = siOld.Resource; - - const unsigned numRefs = streamsRefs[i]; - - if (numRefs == 0) - { - if (!rs.IsSolidSmall()) - continue; - if (streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] == 0) - continue; - } - - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()) - - const unsigned streamIndex = streams.Size(); - CStreamInfo s; - s.Resource = rs; - s.PartNumber = 1; - s.RefCount = numRefs; - - memcpy(s.Hash, siOld.Hash, kHashSize); - - if (rs.IsSolid()) - { - CSolid &ss = _db.Solids[rs.SolidIndex]; - if (rs.IsSolidSmall()) - { - UInt64 oldOffset = ss.SolidOffset; - if (rs.Offset < oldOffset) - return E_FAIL; - UInt64 relatOffset = rs.Offset - oldOffset; - s.Resource.Offset = solidRunOffset + relatOffset; - } - else - { - // IsSolidBig - solidRunOffset += curSolidSize; - curSolidSize = ss.UnpackSize; - } - } - else - { - solidRunOffset = 0; - curSolidSize = 0; - } - - if (!rs.IsSolid() || rs.IsSolidSmall()) - { - const int find = AddUniqHash(streams.ConstData(), sortedHashes, siOld.Hash, (int)streamIndex); - if (find != -1) - return E_FAIL; // two streams with same SHA-1 - } - - if (!rs.IsSolid() || rs.IsSolidBig()) - { - RINOK(InStream_SeekSet(_volumes[siOld.PartNumber].Stream, rs.Offset)) - inStreamLimitedSpec->Init(rs.PackSize); - RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != rs.PackSize) - return E_FAIL; - s.Resource.Offset = curPos; - curPos += rs.PackSize; - lps->ProgressOffset += rs.PackSize; - } - - streams.Add(s); - } - - - // ---------- Write new items ---------- - - CUIntVector hlIndexes; // sorted indexes for hard link items - - for (i = 0; i < db.UpdateIndexes.Size(); i++) - { - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()) - const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; - CMetaItem &mi = db.MetaItems[ui.MetaIndex]; - UInt64 size = 0; - - if (ui.AltStreamIndex >= 0) - { - if (mi.Skip) - continue; - size = mi.AltStreams[ui.AltStreamIndex].Size; - } - else - { - size = mi.Size; - if (mi.IsDir) - { - // we support LINK files here - if (mi.Reparse.Size() == 0) - continue; - } - } - - if (ui.InArcIndex >= 0) - { - // data streams with OLD Data were written already - // we just need to find HashIndex in hashes. - - if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) - return E_FAIL; - - const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; - - if (item.StreamIndex < 0) - { - if (size == 0) - continue; - // if (_db.ItemHasStream(item)) - return E_FAIL; - } - - // We support empty file (size = 0, but with stream and SHA-1) from old archive - - const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex]; - - const int index = AddUniqHash(streams.ConstData(), sortedHashes, siOld.Hash, -1); - // we must have written that stream already - if (index == -1) - return E_FAIL; - - if (ui.AltStreamIndex < 0) - mi.HashIndex = index; - else - mi.AltStreams[ui.AltStreamIndex].HashIndex = index; - - continue; - } - - CMyComPtr fileInStream; - HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream); - - if (res == S_FALSE) - { - if (ui.AltStreamIndex >= 0) - { - mi.NumSkipAltStreams++; - mi.AltStreams[ui.AltStreamIndex].Skip = true; - } - else - mi.Skip = true; - } - else - { - RINOK(res) - - int miIndex = -1; - - if (!fileInStream) - { - if (!mi.IsDir) - return E_INVALIDARG; - } - else if (ui.AltStreamIndex < 0) - { - CMyComPtr getProps2; - fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2); - if (getProps2) - { - CStreamFileProps props; - if (getProps2->GetProps2(&props) == S_OK) - { - mi.Attrib = props.Attrib; - if (_timeOptions.Write_CTime.Val) mi.CTime = props.CTime; - if (_timeOptions.Write_ATime.Val) mi.ATime = props.ATime; - if (_timeOptions.Write_MTime.Val) mi.MTime = props.MTime; - mi.FileID = props.FileID_Low; - if (props.NumLinks <= 1) - mi.FileID = 0; - mi.VolID = props.VolID; - if (mi.FileID != 0) - miIndex = AddToHardLinkList(db.MetaItems, (unsigned)ui.MetaIndex, hlIndexes); - - if (props.Size != size && props.Size != (UInt64)(Int64)-1) - { - const Int64 delta = (Int64)props.Size - (Int64)size; - const Int64 newComplexity = (Int64)totalComplexity + delta; - if (newComplexity > 0) - { - totalComplexity = (UInt64)newComplexity; - callback->SetTotal(totalComplexity); - } - mi.Size = props.Size; - size = props.Size; - } - } - } - } - - if (miIndex >= 0) - { - mi.HashIndex = db.MetaItems[miIndex].HashIndex; - if (mi.HashIndex >= 0) - streams[mi.HashIndex].RefCount++; - // fix for future: maybe we need to check also that real size is equal to size from IStreamGetProps2 - } - else if (ui.AltStreamIndex < 0 && mi.Reparse.Size() != 0) - { - if (mi.Reparse.Size() < 8) - return E_FAIL; - NCrypto::NSha1::CContext sha1; - sha1.Init(); - const size_t packSize = mi.Reparse.Size() - 8; - sha1.Update((const Byte *)mi.Reparse + 8, packSize); - Byte hash[kHashSize]; - sha1.Final(hash); - - int index = AddUniqHash(streams.ConstData(), sortedHashes, hash, (int)streams.Size()); - - if (index != -1) - streams[index].RefCount++; - else - { - index = (int)streams.Size(); - RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize)) - CStreamInfo s; - s.Resource.PackSize = packSize; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = packSize; - s.Resource.Flags = 0; // check it - /* - if (useResourceCompression) - s.Resource.Flags = NResourceFlags::Compressed; - */ - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, hash, kHashSize); - curPos += packSize; - - streams.Add(s); - } - - mi.HashIndex = index; - } - else - { - inShaStream->SetStream(fileInStream); - - CMyComPtr inSeekStream; - fileInStream.QueryInterface(IID_IInStream, (void **)&inSeekStream); - - fileInStream.Release(); - inShaStream->Init(); - UInt64 offsetBlockSize = 0; - /* - if (useResourceCompression) - { - for (UInt64 t = kChunkSize; t < size; t += kChunkSize) - { - Byte buf[8]; - SetUi32(buf, (UInt32)t); - RINOK(WriteStream(outStream, buf, 4)); - offsetBlockSize += 4; - } - } - */ - - // 22.02: we use additional read-only pass to calculate SHA-1 - bool needWritePass = true; - int index = -1; - - if (inSeekStream /* && !sortedHashes.IsEmpty() */) - { - RINOK(copyCoder.Interface()->Code(inShaStream, NULL, NULL, NULL, lps)) - size = copyCoder->TotalSize; - if (size == 0) - needWritePass = false; - else - { - Byte hash[kHashSize]; - inShaStream->Final(hash); - - index = AddUniqHash(streams.ConstData(), sortedHashes, hash, -1); - if (index != -1) - { - streams[index].RefCount++; - needWritePass = false; - } - else - { - RINOK(InStream_SeekToBegin(inSeekStream)) - inShaStream->Init(); - } - } - } - - if (needWritePass) - { - RINOK(copyCoder.Interface()->Code(inShaStream, outStream, NULL, NULL, lps)) - size = copyCoder->TotalSize; - } - - if (size != 0) - { - if (needWritePass) - { - Byte hash[kHashSize]; - const UInt64 packSize = offsetBlockSize + size; - inShaStream->Final(hash); - - index = AddUniqHash(streams.ConstData(), sortedHashes, hash, (int)streams.Size()); - - if (index != -1) - { - streams[index].RefCount++; - outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); - outStream->SetSize(curPos); - } - else - { - index = (int)streams.Size(); - CStreamInfo s; - s.Resource.PackSize = packSize; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = size; - s.Resource.Flags = 0; - /* - if (useResourceCompression) - s.Resource.Flags = NResourceFlags::Compressed; - */ - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, hash, kHashSize); - curPos += packSize; - - streams.Add(s); - } - } // needWritePass - if (ui.AltStreamIndex < 0) - mi.HashIndex = index; - else - mi.AltStreams[ui.AltStreamIndex].HashIndex = index; - } // (size != 0) - } - } - fileInStream.Release(); - complexity += size; - RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - } - - while (secureBlocks.Size() < numNewImages) - secureBlocks.AddNew(); - - - - // ---------- Write Images ---------- - - for (i = 0; i < numNewImages; i++) - { - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()) - if (i < isChangedImage.Size() && !isChangedImage[i]) - { - CStreamInfo s = _db.MetaStreams[i]; - - RINOK(InStream_SeekSet(_volumes[1].Stream, s.Resource.Offset)) - inStreamLimitedSpec->Init(s.Resource.PackSize); - RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps)) - if (copyCoder->TotalSize != s.Resource.PackSize) - return E_FAIL; - - s.Resource.Offset = curPos; - s.PartNumber = 1; - s.RefCount = 1; - streams.Add(s); - - if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) - { - header.MetadataResource = s.Resource; - header.BootIndex = _bootIndex; - } - - lps->ProgressOffset += s.Resource.PackSize; - curPos += s.Resource.PackSize; - // printf("\nWrite old image %x\n", i + 1); - continue; - } - - const CDir &tree = trees[i]; - const UInt32 kSecuritySize = 8; - - size_t pos = kSecuritySize; - - const CUniqBlocks &secUniqBlocks = secureBlocks[i]; - const CObjectVector &secBufs = secUniqBlocks.Bufs; - pos += (size_t)secUniqBlocks.GetTotalSizeInBytes(); - pos += secBufs.Size() * 8; - pos = (pos + 7) & ~(size_t)7; - - db.DefaultDirItem = ri; - pos += db.WriteTree_Dummy(tree); - - CByteArr meta(pos); - - Set32((Byte *)meta + 4, secBufs.Size()) // num security entries - pos = kSecuritySize; - - if (secBufs.Size() == 0) - { - // we can write 0 here only if there is no security data, imageX does it, - // but some programs expect size = 8 - Set32((Byte *)meta, 8) // size of security data - // Set32((Byte *)meta, 0); - } - else - { - unsigned k; - for (k = 0; k < secBufs.Size(); k++, pos += 8) - { - Set64(meta + pos, secBufs[k].Size()) - } - for (k = 0; k < secBufs.Size(); k++) - { - const CByteBuffer &buf = secBufs[k]; - size_t size = buf.Size(); - if (size != 0) - { - memcpy(meta + pos, buf, size); - pos += size; - } - } - while ((pos & 7) != 0) - meta[pos++] = 0; - Set32((Byte *)meta, (UInt32)pos) // size of security data - } - - db.Hashes = streams.ConstData(); - db.WriteTree(tree, (Byte *)meta, pos); - - { - NCrypto::NSha1::CContext sha; - sha.Init(); - sha.Update((const Byte *)meta, pos); - - Byte digest[kHashSize]; - sha.Final(digest); - - CStreamInfo s; - s.Resource.PackSize = pos; - s.Resource.Offset = curPos; - s.Resource.UnpackSize = pos; - s.Resource.Flags = NResourceFlags::kMetadata; - s.PartNumber = 1; - s.RefCount = 1; - memcpy(s.Hash, digest, kHashSize); - streams.Add(s); - - if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) - { - header.MetadataResource = s.Resource; - header.BootIndex = _bootIndex; - } - - RINOK(WriteStream(outStream, (const Byte *)meta, pos)) - meta.Free(); - curPos += pos; - } - } - - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()) - - header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize; - header.OffsetResource.Offset = curPos; - header.OffsetResource.Flags = NResourceFlags::kMetadata; - - - - // ---------- Write Streams Info Tables ---------- - - for (i = 0; i < streams.Size(); i++) - { - Byte buf[kStreamInfoSize]; - streams[i].WriteTo(buf); - RINOK(WriteStream(outStream, buf, kStreamInfoSize)) - curPos += kStreamInfoSize; - } - - AString xml (""); - AddTagUInt64_ToString(xml, "TOTALBYTES", curPos); - for (i = 0; i < trees.Size(); i++) - { - const CDir &tree = trees[i]; - - CXmlItem item; - if (_xmls.Size() == 1) - { - const CWimXml &_oldXml = _xmls[0]; - if (i < _oldXml.Images.Size()) - { - // int ttt = _oldXml.Images[i].ItemIndexInXml; - item = _oldXml.Xml.Root.SubItems[_oldXml.Images[i].ItemIndexInXml]; - } - } - if (i >= isChangedImage.Size() || isChangedImage[i]) - { - char temp[16]; - if (item.Name.IsEmpty()) - { - ConvertUInt32ToString(i + 1, temp); - item.Name = "IMAGE"; - item.IsTag = true; - CXmlProp &prop = item.Props.AddNew(); - prop.Name = "INDEX"; - prop.Value = temp; - } - - AddTag_String_IfEmpty(item, "NAME", temp); - AddTag_UInt64(item, "DIRCOUNT", tree.GetNumDirs() - 1); - AddTag_UInt64(item, "FILECOUNT", tree.GetNumFiles()); - AddTag_UInt64(item, "TOTALBYTES", tree.GetTotalSize(db.MetaItems)); - - AddTag_Time(item, "CREATIONTIME", ftCur); - AddTag_Time(item, "LASTMODIFICATIONTIME", ftCur); - } - - item.AppendTo(xml); - } - xml += ""; - - size_t xmlSize; - { - UString utf16; - if (!ConvertUTF8ToUnicode(xml, utf16)) - return S_FALSE; - xmlSize = ((size_t)utf16.Len() + 1) * 2; - - CByteArr xmlBuf(xmlSize); - Set16((Byte *)xmlBuf, 0xFEFF) - for (i = 0; i < (unsigned)utf16.Len(); i++) - { - Set16((Byte *)xmlBuf + 2 + (size_t)i * 2, (UInt16)utf16[i]) - } - RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize)) - } - - header.XmlResource.UnpackSize = - header.XmlResource.PackSize = xmlSize; - header.XmlResource.Offset = curPos; - header.XmlResource.Flags = NResourceFlags::kMetadata; - - outStream->Seek(0, STREAM_SEEK_SET, NULL); - header.NumImages = trees.Size(); - { - Byte buf[kHeaderSizeMax]; - header.WriteTo(buf); - RINOK(WriteStream(outStream, buf, kHeaderSizeMax)) - } - - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - - return S_OK; - - COM_TRY_END -} - -}} +// WimHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/UTFConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" +#include "../../Common/UniqBlocks.h" + +#include "../../Crypto/RandGen.h" +#include "../../Crypto/Sha1Cls.h" + +#include "../Common/OutStreamWithSha1.h" + +#include "WimHandler.h" + +using namespace NWindows; + +namespace NArchive { +namespace NWim { + +static const unsigned k_NumSubVectors_Bits = 12; // must be <= 16 + +struct CSortedIndex +{ + CObjectVector Vectors; + + CSortedIndex() + { + const unsigned k_NumSubVectors = 1 << k_NumSubVectors_Bits; + Vectors.ClearAndReserve(k_NumSubVectors); + for (unsigned i = 0; i < k_NumSubVectors; i++) + Vectors.AddNew(); + } +}; + +static int AddUniqHash(const CStreamInfo *streams, CSortedIndex &sorted2, const Byte *h, int streamIndexForInsert) +{ + const unsigned hash = (((unsigned)h[0] << 8) | (unsigned)h[1]) >> (16 - k_NumSubVectors_Bits); + CUIntVector &sorted = sorted2.Vectors[hash]; + unsigned left = 0, right = sorted.Size(); + while (left != right) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned index = sorted[mid]; + const Byte *hash2 = streams[index].Hash; + + unsigned i; + for (i = 0; i < kHashSize; i++) + if (h[i] != hash2[i]) + break; + + if (i == kHashSize) + return (int)index; + + if (h[i] < hash2[i]) + right = mid; + else + left = mid + 1; + } + + if (streamIndexForInsert != -1) + sorted.Insert(left, (unsigned)streamIndexForInsert); + + return -1; +} + + +struct CAltStream +{ + int UpdateIndex; + int HashIndex; + UInt64 Size; + UString Name; + bool Skip; + + CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {} +}; + + +struct CMetaItem +{ + int UpdateIndex; + int HashIndex; + + UInt64 Size; + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + UInt64 FileID; + UInt64 VolID; + + UString Name; + UString ShortName; + + UInt32 Attrib; + int SecurityId; // -1: means no secutity ID + bool IsDir; + bool Skip; + unsigned NumSkipAltStreams; + CObjectVector AltStreams; + + CByteBuffer Reparse; + + unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; } + CMetaItem(): + UpdateIndex(-1) + , HashIndex(-1) + , Size(0) + , FileID(0) + , VolID(0) + , Attrib(0) + , SecurityId(-1) + , IsDir(false) + , Skip(false) + , NumSkipAltStreams(0) + { + FILETIME_Clear(CTime); + FILETIME_Clear(ATime); + FILETIME_Clear(MTime); + } +}; + + +static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2) +{ + if (a1.VolID < a2.VolID) return -1; + if (a1.VolID > a2.VolID) return 1; + if (a1.FileID < a2.FileID) return -1; + if (a1.FileID > a2.FileID) return 1; + if (a1.Size < a2.Size) return -1; + if (a1.Size > a2.Size) return 1; + return ::CompareFileTime(&a1.MTime, &a2.MTime); +} + + +static int AddToHardLinkList(const CObjectVector &metaItems, unsigned indexOfItem, CUIntVector &indexes) +{ + const CMetaItem &mi = metaItems[indexOfItem]; + unsigned left = 0, right = indexes.Size(); + while (left != right) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned index = indexes[mid]; + const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); + if (comp == 0) + return (int)index; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + indexes.Insert(left, indexOfItem); + return -1; +} + + +struct CUpdateItem +{ + unsigned CallbackIndex; // index in callback + + int MetaIndex; // index in in MetaItems[] + + int AltStreamIndex; // index in CMetaItem::AltStreams vector + // -1: if not alt stream? + + int InArcIndex; // >= 0, if we use OLD Data + // -1, if we use NEW Data + + CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {} +}; + + +struct CDir +{ + int MetaIndex; + CObjectVector Dirs; + CUIntVector Files; // indexes in MetaItems[] + + CDir(): MetaIndex(-1) {} + unsigned GetNumDirs() const; + unsigned GetNumFiles() const; + UInt64 GetTotalSize(const CObjectVector &metaItems) const; + bool FindDir(const CObjectVector &items, const UString &name, unsigned &index); +}; + +/* imagex counts Junctions as files (not as dirs). + We suppose that it's not correct */ + +unsigned CDir::GetNumDirs() const +{ + unsigned num = Dirs.Size(); + FOR_VECTOR (i, Dirs) + num += Dirs[i].GetNumDirs(); + return num; +} + +unsigned CDir::GetNumFiles() const +{ + unsigned num = Files.Size(); + FOR_VECTOR (i, Dirs) + num += Dirs[i].GetNumFiles(); + return num; +} + +UInt64 CDir::GetTotalSize(const CObjectVector &metaItems) const +{ + UInt64 sum = 0; + unsigned i; + for (i = 0; i < Files.Size(); i++) + sum += metaItems[Files[i]].Size; + for (i = 0; i < Dirs.Size(); i++) + sum += Dirs[i].GetTotalSize(metaItems); + return sum; +} + +bool CDir::FindDir(const CObjectVector &items, const UString &name, unsigned &index) +{ + unsigned left = 0, right = Dirs.Size(); + while (left != right) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); + if (comp == 0) + { + index = mid; + return true; + } + if (comp < 0) + right = mid; + else + left = mid + 1; + } + index = left; + return false; +} + + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) +{ + *type = NFileTimeType::kWindows; + return S_OK; +} + + +HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value) +{ + if (arcIndex != -1) + return GetProperty((UInt32)arcIndex, propID, value); + return callback->GetProperty(callbackIndex, propID, value); +} + + +HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft) +{ + ft.dwLowDateTime = ft.dwHighDateTime = 0; + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, callbackIndex, arcIndex, propID, &prop)) + if (prop.vt == VT_FILETIME) + ft = prop.filetime; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + + +static HRESULT GetRootTime( + IArchiveGetRootProps *callback, + IArchiveGetRootProps *arcRoot, + PROPID propID, FILETIME &ft) +{ + NCOM::CPropVariant prop; + if (callback) + { + RINOK(callback->GetRootProp(propID, &prop)) + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime; + return S_OK; + } + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + if (arcRoot) + { + RINOK(arcRoot->GetRootProp(propID, &prop)) + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime; + return S_OK; + } + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + +#define Set16(p, d) SetUi16(p, d) +#define Set32(p, d) SetUi32(p, d) +#define Set64(p, d) SetUi64(p, d) + +void CResource::WriteTo(Byte *p) const +{ + Set64(p, PackSize) + p[7] = Flags; + Set64(p + 8, Offset) + Set64(p + 16, UnpackSize) +} + + +void CHeader::WriteTo(Byte *p) const +{ + memcpy(p, kSignature, kSignatureSize); + Set32(p + 8, kHeaderSizeMax) + Set32(p + 0xC, Version) + Set32(p + 0x10, Flags) + Set32(p + 0x14, ChunkSize) + memcpy(p + 0x18, Guid, 16); + Set16(p + 0x28, PartNumber) + Set16(p + 0x2A, NumParts) + Set32(p + 0x2C, NumImages) + OffsetResource.WriteTo(p + 0x30); + XmlResource.WriteTo(p + 0x48); + MetadataResource.WriteTo(p + 0x60); + IntegrityResource.WriteTo(p + 0x7C); + Set32(p + 0x78, BootIndex) + memset(p + 0x94, 0, 60); +} + + +void CStreamInfo::WriteTo(Byte *p) const +{ + Resource.WriteTo(p); + Set16(p + 0x18, PartNumber) + Set32(p + 0x1A, RefCount) + memcpy(p + 0x1E, Hash, kHashSize); +} + + +static void SetFileTimeToMem(Byte *p, const FILETIME &ft) +{ + Set32(p, ft.dwLowDateTime) + Set32(p + 4, ft.dwHighDateTime) +} + +static size_t WriteItem_Dummy(const CMetaItem &item) +{ + if (item.Skip) + return 0; + unsigned fileNameLen = item.Name.Len() * 2; + // we write fileNameLen + 2 + 2 to be same as original WIM. + unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2); + + const unsigned shortNameLen = item.ShortName.Len() * 2; + const unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); + + size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7); + if (item.GetNumAltStreams() != 0) + { + if (!item.IsDir) + { + const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7); + totalLen += curLen; + } + FOR_VECTOR (i, item.AltStreams) + { + const CAltStream &ss = item.AltStreams[i]; + if (ss.Skip) + continue; + fileNameLen = ss.Name.Len() * 2; + fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2); + const UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7); + totalLen += curLen; + } + } + return totalLen; +} + + +static size_t WriteItem(const CStreamInfo *streams, const CMetaItem &item, Byte *p) +{ + if (item.Skip) + return 0; + unsigned fileNameLen = item.Name.Len() * 2; + unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2); + unsigned shortNameLen = item.ShortName.Len() * 2; + unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4); + + size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7); + + memset(p, 0, totalLen); + Set64(p, totalLen) + Set64(p + 8, item.Attrib) + Set32(p + 0xC, (UInt32)(Int32)item.SecurityId) + SetFileTimeToMem(p + 0x28, item.CTime); + SetFileTimeToMem(p + 0x30, item.ATime); + SetFileTimeToMem(p + 0x38, item.MTime); + + /* WIM format probably doesn't support hard links to symbolic links. + In these cases it just stores symbolic links (REPARSE TAGS). + Check it in new versions of WIM software form MS !!! + We also follow that scheme */ + + if (item.Reparse.Size() != 0) + { + UInt32 tag = GetUi32(item.Reparse); + Set32(p + 0x58, tag) + // Set32(p + 0x5C, 0); // probably it's always ZERO + } + else if (item.FileID != 0) + { + Set64(p + 0x58, item.FileID) + } + + Set16(p + 0x62, (UInt16)shortNameLen) + Set16(p + 0x64, (UInt16)fileNameLen) + unsigned i; + for (i = 0; i * 2 < fileNameLen; i++) + Set16(p + kDirRecordSize + i * 2, (UInt16)item.Name[i]) + for (i = 0; i * 2 < shortNameLen; i++) + Set16(p + kDirRecordSize + fileNameLen2 + i * 2, (UInt16)item.ShortName[i]) + + if (item.GetNumAltStreams() == 0) + { + if (item.HashIndex >= 0) + memcpy(p + 0x40, streams[item.HashIndex].Hash, kHashSize); + } + else + { + Set16(p + 0x60, (UInt16)(item.GetNumAltStreams() + (item.IsDir ? 0 : 1))) + p += totalLen; + + if (!item.IsDir) + { + const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7); + memset(p, 0, curLen); + Set64(p, curLen) + if (item.HashIndex >= 0) + memcpy(p + 0x10, streams[item.HashIndex].Hash, kHashSize); + totalLen += curLen; + p += curLen; + } + + FOR_VECTOR (si, item.AltStreams) + { + const CAltStream &ss = item.AltStreams[si]; + if (ss.Skip) + continue; + + fileNameLen = ss.Name.Len() * 2; + fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2); + UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7); + memset(p, 0, curLen); + + Set64(p, curLen) + if (ss.HashIndex >= 0) + memcpy(p + 0x10, streams[ss.HashIndex].Hash, kHashSize); + Set16(p + 0x24, (UInt16)fileNameLen) + for (i = 0; i * 2 < fileNameLen; i++) + Set16(p + 0x26 + i * 2, (UInt16)ss.Name[i]) + totalLen += curLen; + p += curLen; + } + } + + return totalLen; +} + + +struct CDb +{ + CMetaItem DefaultDirItem; + const CStreamInfo *Hashes; + CObjectVector MetaItems; + CRecordVector UpdateItems; + CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams + to disk (the order of tree items). */ + + size_t WriteTree_Dummy(const CDir &tree) const; + void WriteTree(const CDir &tree, Byte *dest, size_t &pos) const; + void WriteOrderList(const CDir &tree); +}; + + +size_t CDb::WriteTree_Dummy(const CDir &tree) const +{ + unsigned i; + size_t pos = 0; + for (i = 0; i < tree.Files.Size(); i++) + pos += WriteItem_Dummy(MetaItems[tree.Files[i]]); + for (i = 0; i < tree.Dirs.Size(); i++) + { + const CDir &subDir = tree.Dirs[i]; + pos += WriteItem_Dummy(MetaItems[subDir.MetaIndex]); + pos += WriteTree_Dummy(subDir); + } + return pos + 8; +} + + +void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const +{ + unsigned i; + for (i = 0; i < tree.Files.Size(); i++) + pos += WriteItem(Hashes, MetaItems[tree.Files[i]], dest + pos); + + size_t posStart = pos; + for (i = 0; i < tree.Dirs.Size(); i++) + pos += WriteItem_Dummy(MetaItems[tree.Dirs[i].MetaIndex]); + + Set64(dest + pos, 0) + + pos += 8; + + for (i = 0; i < tree.Dirs.Size(); i++) + { + const CDir &subDir = tree.Dirs[i]; + const CMetaItem &metaItem = MetaItems[subDir.MetaIndex]; + bool needCreateTree = (metaItem.Reparse.Size() == 0) + || !subDir.Files.IsEmpty() + || !subDir.Dirs.IsEmpty(); + size_t len = WriteItem(Hashes, metaItem, dest + posStart); + posStart += len; + if (needCreateTree) + { + Set64(dest + posStart - len + 0x10, pos) // subdirOffset + WriteTree(subDir, dest, pos); + } + } +} + + +void CDb::WriteOrderList(const CDir &tree) +{ + if (tree.MetaIndex >= 0) + { + const CMetaItem &mi = MetaItems[tree.MetaIndex]; + if (mi.UpdateIndex >= 0) + UpdateIndexes.Add((unsigned)mi.UpdateIndex); + FOR_VECTOR (si, mi.AltStreams) + UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex); + } + + unsigned i; + for (i = 0; i < tree.Files.Size(); i++) + { + const CMetaItem &mi = MetaItems[tree.Files[i]]; + UpdateIndexes.Add((unsigned)mi.UpdateIndex); + FOR_VECTOR (si, mi.AltStreams) + UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex); + } + + for (i = 0; i < tree.Dirs.Size(); i++) + WriteOrderList(tree.Dirs[i]); +} + + +static void AddTag_ToString(AString &s, const char *name, const char *value) +{ + s.Add_Char('<'); + s += name; + s.Add_Char('>'); + s += value; + s.Add_Char('<'); + s.Add_Slash(); + s += name; + s.Add_Char('>'); +} + + +static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value) +{ + char temp[32]; + ConvertUInt64ToString(value, temp); + AddTag_ToString(s, name, temp); +} + + +static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name) +{ + const int index = parentItem.FindSubTag(name); + if (index < 0) + { + CXmlItem &subItem = parentItem.SubItems.AddNew(); + subItem.IsTag = true; + subItem.Name = name; + return subItem; + } + CXmlItem &subItem = parentItem.SubItems[index]; + subItem.SubItems.Clear(); + return subItem; +} + + +static void AddTag_UInt64_2(CXmlItem &item, UInt64 value) +{ + CXmlItem &subItem = item.SubItems.AddNew(); + subItem.IsTag = false; + char temp[32]; + ConvertUInt64ToString(value, temp); + subItem.Name = temp; +} + + +static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value) +{ + AddTag_UInt64_2(AddUniqueTag(parentItem, name), value); +} + + +static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value) +{ + item.IsTag = true; + item.Name = name; + char temp[16]; + temp[0] = '0'; + temp[1] = 'x'; + ConvertUInt32ToHex8Digits(value, temp + 2); + CXmlItem &subItem = item.SubItems.AddNew(); + subItem.IsTag = false; + subItem.Name = temp; +} + + +static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft) +{ + AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime); + AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime); +} + + +static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft) +{ + AddTag_Time_2(AddUniqueTag(parentItem, name), ft); +} + + +static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value) +{ + if (parentItem.FindSubTag(name) >= 0) + return; + CXmlItem &tag = parentItem.SubItems.AddNew(); + tag.IsTag = true; + tag.Name = name; + CXmlItem &subItem = tag.SubItems.AddNew(); + subItem.IsTag = false; + subItem.Name = value; +} + + +void CHeader::SetDefaultFields(bool useLZX) +{ + Version = k_Version_NonSolid; + Flags = NHeaderFlags::kReparsePointFixup; + ChunkSize = 0; + if (useLZX) + { + Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX; + ChunkSize = kChunkSize; + ChunkSizeBits = kChunkSizeBits; + } + MY_RAND_GEN(Guid, 16); + PartNumber = 1; + NumParts = 1; + NumImages = 1; + BootIndex = 0; + OffsetResource.Clear(); + XmlResource.Clear(); + MetadataResource.Clear(); + IntegrityResource.Clear(); +} + + +static void AddTrees(CObjectVector &trees, CObjectVector &metaItems, const CMetaItem &ri, int curTreeIndex) +{ + while (curTreeIndex >= (int)trees.Size()) + trees.AddNew().Dirs.AddNew().MetaIndex = (int)metaItems.Add(ri); +} + + +#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) + + + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback)) +{ + COM_TRY_BEGIN + + if (!IsUpdateSupported()) + return E_NOTIMPL; + + bool isUpdate = (_volumes.Size() != 0); + int defaultImageIndex = _defaultImageNumber - 1; + bool showImageNumber; + + if (isUpdate) + { + showImageNumber = _showImageNumber; + if (!showImageNumber) + defaultImageIndex = _db.IndexOfUserImage; + } + else + { + showImageNumber = (_set_use_ShowImageNumber && _set_showImageNumber); + if (!showImageNumber) + defaultImageIndex = 0; + } + + if (defaultImageIndex >= kNumImagesMaxUpdate) + return E_NOTIMPL; + + CMyComPtr outStream; + RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream)) + if (!outStream) + return E_NOTIMPL; + if (!callback) + return E_FAIL; + + CDb db; + CObjectVector trees; + + CMetaItem ri; // default DIR item + FILETIME ftCur; + NTime::GetCurUtcFileTime(ftCur); + // ri.MTime = ri.ATime = ri.CTime = ftCur; + ri.Attrib = FILE_ATTRIBUTE_DIRECTORY; + ri.IsDir = true; + + + // ---------- Detect changed images ---------- + + unsigned i; + CBoolVector isChangedImage; + { + CUIntVector numUnchangedItemsInImage; + for (i = 0; i < _db.Images.Size(); i++) + { + numUnchangedItemsInImage.Add(0); + isChangedImage.Add(false); + } + + for (i = 0; i < numItems; i++) + { + UInt32 indexInArchive; + Int32 newData, newProps; + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)) + if (newProps == 0) + { + if (indexInArchive >= _db.SortedItems.Size()) + continue; + const CItem &item = _db.Items[_db.SortedItems[indexInArchive]]; + if (newData == 0) + { + if (item.ImageIndex >= 0) + numUnchangedItemsInImage[item.ImageIndex]++; + } + else + { + // oldProps & newData. Current version of 7-Zip doesn't use it + if (item.ImageIndex >= 0) + isChangedImage[item.ImageIndex] = true; + } + } + else if (!showImageNumber) + { + if (defaultImageIndex >= 0 && defaultImageIndex < (int)isChangedImage.Size()) + isChangedImage[defaultImageIndex] = true; + } + else + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidPath, &prop)) + + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + const wchar_t *path = prop.bstrVal; + if (!path) + return E_INVALIDARG; + + const wchar_t *end; + UInt64 val = ConvertStringToUInt64(path, &end); + if (end == path) + return E_INVALIDARG; + if (val == 0 || val > kNumImagesMaxUpdate) + return E_INVALIDARG; + wchar_t c = *end; + if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR) + return E_INVALIDARG; + unsigned imageIndex = (unsigned)val - 1; + if (imageIndex < _db.Images.Size()) + isChangedImage[imageIndex] = true; + if (_defaultImageNumber > 0 && val != (unsigned)_defaultImageNumber) + return E_INVALIDARG; + } + } + + for (i = 0; i < _db.Images.Size(); i++) + if (!isChangedImage[i]) + isChangedImage[i] = _db.GetNumUserItemsInImage(i) != numUnchangedItemsInImage[i]; + } + + if (defaultImageIndex >= 0) + { + for (i = 0; i < _db.Images.Size(); i++) + if ((int)i != defaultImageIndex) + isChangedImage[i] = false; + } + + CMyComPtr getRawProps; + callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); + + CMyComPtr getRootProps; + callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps); + + CObjectVector secureBlocks; + + if (!showImageNumber && (getRootProps || isUpdate) && + ( + defaultImageIndex >= (int)isChangedImage.Size() + || defaultImageIndex < 0 // test it + || isChangedImage[defaultImageIndex] + )) + { + // Fill Root Item: Metadata and security + CMetaItem rootItem = ri; + { + const void *data = NULL; + UInt32 dataSize = 0; + UInt32 propType = 0; + if (getRootProps) + { + RINOK(getRootProps->GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType)) + } + if (dataSize == 0 && isUpdate) + { + RINOK(GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType)) + } + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + while (defaultImageIndex >= (int)secureBlocks.Size()) + secureBlocks.AddNew(); + CUniqBlocks &secUniqBlocks = secureBlocks[defaultImageIndex]; + rootItem.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize); + } + } + + IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL; + + if (_timeOptions.Write_CTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime)) + if (_timeOptions.Write_ATime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime)) + if (_timeOptions.Write_MTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidMTime, rootItem.MTime)) + + { + NCOM::CPropVariant prop; + if (getRootProps) + { + RINOK(getRootProps->GetRootProp(kpidAttrib, &prop)) + if (prop.vt == VT_UI4) + rootItem.Attrib = prop.ulVal; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + if (prop.vt == VT_EMPTY && thisGetRoot) + { + RINOK(GetRootProp(kpidAttrib, &prop)) + if (prop.vt == VT_UI4) + rootItem.Attrib = prop.ulVal; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + rootItem.Attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + + AddTrees(trees, db.MetaItems, ri, defaultImageIndex); + db.MetaItems[trees[defaultImageIndex].Dirs[0].MetaIndex] = rootItem; + } + + // ---------- Request Metadata for changed items ---------- + + UString fileName; + + for (i = 0; i < numItems; i++) + { + CUpdateItem ui; + UInt32 indexInArchive; + Int32 newData, newProps; + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)) + + if (newData == 0 || newProps == 0) + { + if (indexInArchive >= _db.SortedItems.Size()) + continue; + + const CItem &item = _db.Items[_db.SortedItems[indexInArchive]]; + + if (item.ImageIndex >= 0) + { + if (!isChangedImage[item.ImageIndex]) + { + if (newData == 0 && newProps == 0) + continue; + return E_FAIL; + } + } + else + { + // if deleted item was not renamed, we just skip it + if (newProps == 0) + continue; + if (item.StreamIndex >= 0) + { + // we don't support property change for SolidBig streams + if (_db.DataStreams[item.StreamIndex].Resource.IsSolidBig()) + return E_NOTIMPL; + } + } + + if (newData == 0) + ui.InArcIndex = (Int32)indexInArchive; + } + + // we set arcIndex only if we must use old props + const Int32 arcIndex = (newProps ? -1 : (Int32)indexInArchive); + + bool isDir = false; + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidIsDir, &prop)) + if (prop.vt == VT_BOOL) + isDir = (prop.boolVal != VARIANT_FALSE); + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + bool isAltStream = false; + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidIsAltStream, &prop)) + if (prop.vt == VT_BOOL) + isAltStream = (prop.boolVal != VARIANT_FALSE); + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + if (isDir && isAltStream) + return E_INVALIDARG; + + UInt64 size = 0; + UInt64 iNode = 0; + + if (!isDir) + { + if (!newData) + { + NCOM::CPropVariant prop; + GetProperty(indexInArchive, kpidINode, &prop); + if (prop.vt == VT_UI8) + iNode = prop.uhVal.QuadPart; + } + + NCOM::CPropVariant prop; + + if (newData) + { + RINOK(callback->GetProperty(i, kpidSize, &prop)) + } + else + { + RINOK(GetProperty(indexInArchive, kpidSize, &prop)) + } + + if (prop.vt == VT_UI8) + size = prop.uhVal.QuadPart; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + { + NCOM::CPropVariant propPath; + const wchar_t *path = NULL; + RINOK(GetOutProperty(callback, i, arcIndex, kpidPath, &propPath)) + if (propPath.vt == VT_BSTR) + path = propPath.bstrVal; + else if (propPath.vt != VT_EMPTY) + return E_INVALIDARG; + + if (!path) + return E_INVALIDARG; + + CDir *curItem = NULL; + bool isRootImageDir = false; + fileName.Empty(); + + int imageIndex; + + if (!showImageNumber) + { + imageIndex = defaultImageIndex; + AddTrees(trees, db.MetaItems, ri, imageIndex); + curItem = &trees[imageIndex].Dirs[0]; + } + else + { + const wchar_t *end; + UInt64 val = ConvertStringToUInt64(path, &end); + if (end == path) + return E_INVALIDARG; + if (val == 0 || val > kNumImagesMaxUpdate) + return E_INVALIDARG; + + imageIndex = (int)val - 1; + if (imageIndex < (int)isChangedImage.Size()) + if (!isChangedImage[imageIndex]) + return E_FAIL; + + AddTrees(trees, db.MetaItems, ri, imageIndex); + curItem = &trees[imageIndex].Dirs[0]; + wchar_t c = *end; + + if (c == 0) + { + if (!isDir || isAltStream) + return E_INVALIDARG; + ui.MetaIndex = curItem->MetaIndex; + isRootImageDir = true; + } + else if (c == ':') + { + if (isDir || !isAltStream) + return E_INVALIDARG; + ui.MetaIndex = curItem->MetaIndex; + CAltStream ss; + ss.Size = size; + ss.Name = end + 1; + ss.UpdateIndex = (int)db.UpdateItems.Size(); + ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); + } + else if (c == WCHAR_PATH_SEPARATOR || c == L'/') + { + path = end + 1; + if (*path == 0) + return E_INVALIDARG; + } + else + return E_INVALIDARG; + } + + if (ui.MetaIndex < 0) + { + for (;;) + { + const wchar_t c = *path++; + if (c == 0) + break; + if (c == WCHAR_PATH_SEPARATOR || c == L'/') + { + unsigned indexOfDir; + if (!curItem->FindDir(db.MetaItems, fileName, indexOfDir)) + { + CDir &dir = curItem->Dirs.InsertNew(indexOfDir); + dir.MetaIndex = (int)db.MetaItems.Add(ri); + db.MetaItems.Back().Name = fileName; + } + curItem = &curItem->Dirs[indexOfDir]; + fileName.Empty(); + } + else + { + /* + #if WCHAR_MAX > 0xffff + if (c >= 0x10000) + { + c -= 0x10000; + + if (c < (1 << 20)) + { + wchar_t c0 = 0xd800 + ((c >> 10) & 0x3FF); + fileName += c0; + c = 0xdc00 + (c & 0x3FF); + } + else + c = '_'; // we change character unsupported by UTF16 + } + #endif + */ + + fileName += c; + } + } + + if (isAltStream) + { + int colonPos = fileName.Find(L':'); + if (colonPos < 0) + return E_INVALIDARG; + + // we want to support cases of c::substream, where c: is drive name + if (colonPos == 1 && fileName[2] == L':' && IS_LETTER_CHAR(fileName[0])) + colonPos = 2; + const UString mainName = fileName.Left((unsigned)colonPos); + unsigned indexOfDir; + + if (mainName.IsEmpty()) + ui.MetaIndex = curItem->MetaIndex; + else if (curItem->FindDir(db.MetaItems, mainName, indexOfDir)) + ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex; + else + { + for (int j = (int)curItem->Files.Size() - 1; j >= 0; j--) + { + const unsigned metaIndex = curItem->Files[j]; + const CMetaItem &mi = db.MetaItems[metaIndex]; + if (CompareFileNames(mainName, mi.Name) == 0) + { + ui.MetaIndex = (int)metaIndex; + break; + } + } + } + + if (ui.MetaIndex >= 0) + { + CAltStream ss; + ss.Size = size; + ss.Name = fileName.Ptr(colonPos + 1); + ss.UpdateIndex = (int)db.UpdateItems.Size(); + ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss); + } + } + } + + + if (ui.MetaIndex < 0 || isRootImageDir) + { + if (!isRootImageDir) + { + ui.MetaIndex = (int)db.MetaItems.Size(); + db.MetaItems.AddNew(); + } + + CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + mi.Size = size; + mi.IsDir = isDir; + mi.Name = fileName; + mi.UpdateIndex = (int)db.UpdateItems.Size(); + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidAttrib, &prop)) + if (prop.vt == VT_EMPTY) + mi.Attrib = 0; + else if (prop.vt == VT_UI4) + mi.Attrib = prop.ulVal; + else + return E_INVALIDARG; + if (isDir) + mi.Attrib |= FILE_ATTRIBUTE_DIRECTORY; + } + + if (arcIndex != -1 || _timeOptions.Write_CTime.Val) + RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime)) + if (arcIndex != -1 || _timeOptions.Write_ATime.Val) + RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime)) + if (arcIndex != -1 || _timeOptions.Write_MTime.Val) + RINOK(GetTime(callback, i, arcIndex, kpidMTime, mi.MTime)) + + { + NCOM::CPropVariant prop; + RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop)) + if (prop.vt == VT_BSTR) + mi.ShortName.SetFromBstr(prop.bstrVal); + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + while (imageIndex >= (int)secureBlocks.Size()) + secureBlocks.AddNew(); + + if (!isAltStream && (getRawProps || arcIndex >= 0)) + { + CUniqBlocks &secUniqBlocks = secureBlocks[imageIndex]; + const void *data; + UInt32 dataSize; + UInt32 propType; + + data = NULL; + dataSize = 0; + propType = 0; + + if (arcIndex >= 0) + { + GetRawProp((UInt32)arcIndex, kpidNtSecure, &data, &dataSize, &propType); + } + else + { + getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); + } + + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + mi.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize); + } + + data = NULL; + dataSize = 0; + propType = 0; + + if (arcIndex >= 0) + { + GetRawProp((UInt32)arcIndex, kpidNtReparse, &data, &dataSize, &propType); + } + else + { + getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType); + } + + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + mi.Reparse.CopyFrom((const Byte *)data, dataSize); + } + } + + if (!isRootImageDir) + { + if (isDir) + { + unsigned indexOfDir; + if (curItem->FindDir(db.MetaItems, fileName, indexOfDir)) + curItem->Dirs[indexOfDir].MetaIndex = ui.MetaIndex; + else + curItem->Dirs.InsertNew(indexOfDir).MetaIndex = ui.MetaIndex; + } + else + curItem->Files.Add((unsigned)ui.MetaIndex); + } + } + + } + + if (iNode != 0 && ui.MetaIndex >= 0 && ui.AltStreamIndex < 0) + db.MetaItems[ui.MetaIndex].FileID = iNode; + + ui.CallbackIndex = i; + db.UpdateItems.Add(ui); + } + + unsigned numNewImages = trees.Size(); + for (i = numNewImages; i < isChangedImage.Size(); i++) + if (!isChangedImage[i]) + numNewImages = i + 1; + + AddTrees(trees, db.MetaItems, ri, (int)numNewImages - 1); + + for (i = 0; i < trees.Size(); i++) + if (i >= isChangedImage.Size() || isChangedImage[i]) + db.WriteOrderList(trees[i]); + + + UInt64 complexity = 0; + + unsigned numDataStreams = _db.DataStreams.Size(); + CUIntArr streamsRefs(numDataStreams); + for (i = 0; i < numDataStreams; i++) + streamsRefs[i] = 0; + + // ---------- Calculate Streams Refs Counts in unchanged images + + for (i = 0; i < _db.Images.Size(); i++) + { + if (isChangedImage[i]) + continue; + complexity += _db.MetaStreams[i].Resource.PackSize; + const CImage &image = _db.Images[i]; + unsigned endItem = image.StartItem + image.NumItems; + for (unsigned k = image.StartItem; k < endItem; k++) + { + const CItem &item = _db.Items[k]; + if (item.StreamIndex >= 0) + streamsRefs[(unsigned)item.StreamIndex]++; + } + } + + + // ---------- Update Streams Refs Counts in changed images + + for (i = 0; i < db.UpdateIndexes.Size(); i++) + { + const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; + + if (ui.InArcIndex >= 0) + { + if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) + continue; + const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; + if (item.StreamIndex >= 0) + streamsRefs[(unsigned)item.StreamIndex]++; + } + else + { + const CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + UInt64 size; + if (ui.AltStreamIndex < 0) + size = mi.Size; + else + size = mi.AltStreams[ui.AltStreamIndex].Size; + complexity += size; + } + } + + // Clear ref counts for SolidBig streams + + for (i = 0; i < _db.DataStreams.Size(); i++) + if (_db.DataStreams[i].Resource.IsSolidBig()) + streamsRefs[i] = 0; + + // Set ref counts for SolidBig streams + + for (i = 0; i < _db.DataStreams.Size(); i++) + if (streamsRefs[i] != 0) + { + const CResource &rs = _db.DataStreams[i].Resource; + if (rs.IsSolidSmall()) + streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] = 1; + } + + for (i = 0; i < _db.DataStreams.Size(); i++) + if (streamsRefs[i] != 0) + { + const CResource &rs = _db.DataStreams[i].Resource; + if (!rs.IsSolidSmall()) + complexity += rs.PackSize; + } + + RINOK(callback->SetTotal(complexity)) + UInt64 totalComplexity = complexity; + + CMyComPtr2_Create lps; + lps->Init(callback, true); + CMyComPtr2_Create copyCoder; + + complexity = 0; + + // bool useResourceCompression = false; + // use useResourceCompression only if CHeader::Flags compression is also set + + CHeader header; + header.SetDefaultFields(false); + + if (isUpdate) + { + const CHeader &srcHeader = _volumes[1].Header; + header.Flags = srcHeader.Flags; + header.Version = srcHeader.Version; + header.ChunkSize = srcHeader.ChunkSize; + header.ChunkSizeBits = srcHeader.ChunkSizeBits; + } + + CMyComPtr setRestriction; + outSeqStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction); + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, kHeaderSizeMax)) + + { + Byte buf[kHeaderSizeMax]; + header.WriteTo(buf); + RINOK(WriteStream(outStream, buf, kHeaderSizeMax)) + } + + UInt64 curPos = kHeaderSizeMax; + + CMyComPtr2_Create inShaStream; + + CLimitedSequentialInStream *inStreamLimitedSpec = NULL; + CMyComPtr inStreamLimited; + if (_volumes.Size() == 2) + { + inStreamLimitedSpec = new CLimitedSequentialInStream; + inStreamLimited = inStreamLimitedSpec; + inStreamLimitedSpec->SetStream(_volumes[1].Stream); + } + + + CRecordVector streams; + CSortedIndex sortedHashes; // indexes to streams, sorted by SHA1 + + // ---------- Copy unchanged data streams ---------- + + UInt64 solidRunOffset = 0; + UInt64 curSolidSize = 0; + + for (i = 0; i < _db.DataStreams.Size(); i++) + { + const CStreamInfo &siOld = _db.DataStreams[i]; + const CResource &rs = siOld.Resource; + + const unsigned numRefs = streamsRefs[i]; + + if (numRefs == 0) + { + if (!rs.IsSolidSmall()) + continue; + if (streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] == 0) + continue; + } + + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()) + + const unsigned streamIndex = streams.Size(); + CStreamInfo s; + s.Resource = rs; + s.PartNumber = 1; + s.RefCount = numRefs; + + memcpy(s.Hash, siOld.Hash, kHashSize); + + if (rs.IsSolid()) + { + CSolid &ss = _db.Solids[rs.SolidIndex]; + if (rs.IsSolidSmall()) + { + UInt64 oldOffset = ss.SolidOffset; + if (rs.Offset < oldOffset) + return E_FAIL; + UInt64 relatOffset = rs.Offset - oldOffset; + s.Resource.Offset = solidRunOffset + relatOffset; + } + else + { + // IsSolidBig + solidRunOffset += curSolidSize; + curSolidSize = ss.UnpackSize; + } + } + else + { + solidRunOffset = 0; + curSolidSize = 0; + } + + if (!rs.IsSolid() || rs.IsSolidSmall()) + { + const int find = AddUniqHash(streams.ConstData(), sortedHashes, siOld.Hash, (int)streamIndex); + if (find != -1) + return E_FAIL; // two streams with same SHA-1 + } + + if (!rs.IsSolid() || rs.IsSolidBig()) + { + RINOK(InStream_SeekSet(_volumes[siOld.PartNumber].Stream, rs.Offset)) + inStreamLimitedSpec->Init(rs.PackSize); + RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != rs.PackSize) + return E_FAIL; + s.Resource.Offset = curPos; + curPos += rs.PackSize; + lps->ProgressOffset += rs.PackSize; + } + + streams.Add(s); + } + + + // ---------- Write new items ---------- + + CUIntVector hlIndexes; // sorted indexes for hard link items + + for (i = 0; i < db.UpdateIndexes.Size(); i++) + { + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()) + const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]]; + CMetaItem &mi = db.MetaItems[ui.MetaIndex]; + UInt64 size = 0; + + if (ui.AltStreamIndex >= 0) + { + if (mi.Skip) + continue; + size = mi.AltStreams[ui.AltStreamIndex].Size; + } + else + { + size = mi.Size; + if (mi.IsDir) + { + // we support LINK files here + if (mi.Reparse.Size() == 0) + continue; + } + } + + if (ui.InArcIndex >= 0) + { + // data streams with OLD Data were written already + // we just need to find HashIndex in hashes. + + if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size()) + return E_FAIL; + + const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]]; + + if (item.StreamIndex < 0) + { + if (size == 0) + continue; + // if (_db.ItemHasStream(item)) + return E_FAIL; + } + + // We support empty file (size = 0, but with stream and SHA-1) from old archive + + const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex]; + + const int index = AddUniqHash(streams.ConstData(), sortedHashes, siOld.Hash, -1); + // we must have written that stream already + if (index == -1) + return E_FAIL; + + if (ui.AltStreamIndex < 0) + mi.HashIndex = index; + else + mi.AltStreams[ui.AltStreamIndex].HashIndex = index; + + continue; + } + + CMyComPtr fileInStream; + HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream); + + if (res == S_FALSE) + { + if (ui.AltStreamIndex >= 0) + { + mi.NumSkipAltStreams++; + mi.AltStreams[ui.AltStreamIndex].Skip = true; + } + else + mi.Skip = true; + } + else + { + RINOK(res) + + int miIndex = -1; + + if (!fileInStream) + { + if (!mi.IsDir) + return E_INVALIDARG; + } + else if (ui.AltStreamIndex < 0) + { + CMyComPtr getProps2; + fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2); + if (getProps2) + { + CStreamFileProps props; + if (getProps2->GetProps2(&props) == S_OK) + { + mi.Attrib = props.Attrib; + if (_timeOptions.Write_CTime.Val) mi.CTime = props.CTime; + if (_timeOptions.Write_ATime.Val) mi.ATime = props.ATime; + if (_timeOptions.Write_MTime.Val) mi.MTime = props.MTime; + mi.FileID = props.FileID_Low; + if (props.NumLinks <= 1) + mi.FileID = 0; + mi.VolID = props.VolID; + if (mi.FileID != 0) + miIndex = AddToHardLinkList(db.MetaItems, (unsigned)ui.MetaIndex, hlIndexes); + + if (props.Size != size && props.Size != (UInt64)(Int64)-1) + { + const Int64 delta = (Int64)props.Size - (Int64)size; + const Int64 newComplexity = (Int64)totalComplexity + delta; + if (newComplexity > 0) + { + totalComplexity = (UInt64)newComplexity; + callback->SetTotal(totalComplexity); + } + mi.Size = props.Size; + size = props.Size; + } + } + } + } + + if (miIndex >= 0) + { + mi.HashIndex = db.MetaItems[miIndex].HashIndex; + if (mi.HashIndex >= 0) + streams[mi.HashIndex].RefCount++; + // fix for future: maybe we need to check also that real size is equal to size from IStreamGetProps2 + } + else if (ui.AltStreamIndex < 0 && mi.Reparse.Size() != 0) + { + if (mi.Reparse.Size() < 8) + return E_FAIL; + NCrypto::NSha1::CContext sha1; + sha1.Init(); + const size_t packSize = mi.Reparse.Size() - 8; + sha1.Update((const Byte *)mi.Reparse + 8, packSize); + Byte hash[kHashSize]; + sha1.Final(hash); + + int index = AddUniqHash(streams.ConstData(), sortedHashes, hash, (int)streams.Size()); + + if (index != -1) + streams[index].RefCount++; + else + { + index = (int)streams.Size(); + RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize)) + CStreamInfo s; + s.Resource.PackSize = packSize; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = packSize; + s.Resource.Flags = 0; // check it + /* + if (useResourceCompression) + s.Resource.Flags = NResourceFlags::Compressed; + */ + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, hash, kHashSize); + curPos += packSize; + + streams.Add(s); + } + + mi.HashIndex = index; + } + else + { + inShaStream->SetStream(fileInStream); + + CMyComPtr inSeekStream; + fileInStream.QueryInterface(IID_IInStream, (void **)&inSeekStream); + + fileInStream.Release(); + inShaStream->Init(); + UInt64 offsetBlockSize = 0; + /* + if (useResourceCompression) + { + for (UInt64 t = kChunkSize; t < size; t += kChunkSize) + { + Byte buf[8]; + SetUi32(buf, (UInt32)t); + RINOK(WriteStream(outStream, buf, 4)); + offsetBlockSize += 4; + } + } + */ + + // 22.02: we use additional read-only pass to calculate SHA-1 + bool needWritePass = true; + int index = -1; + + if (inSeekStream /* && !sortedHashes.IsEmpty() */) + { + RINOK(copyCoder.Interface()->Code(inShaStream, NULL, NULL, NULL, lps)) + size = copyCoder->TotalSize; + if (size == 0) + needWritePass = false; + else + { + Byte hash[kHashSize]; + inShaStream->Final(hash); + + index = AddUniqHash(streams.ConstData(), sortedHashes, hash, -1); + if (index != -1) + { + streams[index].RefCount++; + needWritePass = false; + } + else + { + RINOK(InStream_SeekToBegin(inSeekStream)) + inShaStream->Init(); + } + } + } + + if (needWritePass) + { + RINOK(copyCoder.Interface()->Code(inShaStream, outStream, NULL, NULL, lps)) + size = copyCoder->TotalSize; + } + + if (size != 0) + { + if (needWritePass) + { + Byte hash[kHashSize]; + const UInt64 packSize = offsetBlockSize + size; + inShaStream->Final(hash); + + index = AddUniqHash(streams.ConstData(), sortedHashes, hash, (int)streams.Size()); + + if (index != -1) + { + streams[index].RefCount++; + outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos); + outStream->SetSize(curPos); + } + else + { + index = (int)streams.Size(); + CStreamInfo s; + s.Resource.PackSize = packSize; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = size; + s.Resource.Flags = 0; + /* + if (useResourceCompression) + s.Resource.Flags = NResourceFlags::Compressed; + */ + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, hash, kHashSize); + curPos += packSize; + + streams.Add(s); + } + } // needWritePass + if (ui.AltStreamIndex < 0) + mi.HashIndex = index; + else + mi.AltStreams[ui.AltStreamIndex].HashIndex = index; + } // (size != 0) + } + } + fileInStream.Release(); + complexity += size; + RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + } + + while (secureBlocks.Size() < numNewImages) + secureBlocks.AddNew(); + + + + // ---------- Write Images ---------- + + for (i = 0; i < numNewImages; i++) + { + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()) + if (i < isChangedImage.Size() && !isChangedImage[i]) + { + CStreamInfo s = _db.MetaStreams[i]; + + RINOK(InStream_SeekSet(_volumes[1].Stream, s.Resource.Offset)) + inStreamLimitedSpec->Init(s.Resource.PackSize); + RINOK(copyCoder.Interface()->Code(inStreamLimited, outStream, NULL, NULL, lps)) + if (copyCoder->TotalSize != s.Resource.PackSize) + return E_FAIL; + + s.Resource.Offset = curPos; + s.PartNumber = 1; + s.RefCount = 1; + streams.Add(s); + + if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) + { + header.MetadataResource = s.Resource; + header.BootIndex = _bootIndex; + } + + lps->ProgressOffset += s.Resource.PackSize; + curPos += s.Resource.PackSize; + // printf("\nWrite old image %x\n", i + 1); + continue; + } + + const CDir &tree = trees[i]; + const UInt32 kSecuritySize = 8; + + size_t pos = kSecuritySize; + + const CUniqBlocks &secUniqBlocks = secureBlocks[i]; + const CObjectVector &secBufs = secUniqBlocks.Bufs; + pos += (size_t)secUniqBlocks.GetTotalSizeInBytes(); + pos += secBufs.Size() * 8; + pos = (pos + 7) & ~(size_t)7; + + db.DefaultDirItem = ri; + pos += db.WriteTree_Dummy(tree); + + CByteArr meta(pos); + + Set32((Byte *)meta + 4, secBufs.Size()) // num security entries + pos = kSecuritySize; + + if (secBufs.Size() == 0) + { + // we can write 0 here only if there is no security data, imageX does it, + // but some programs expect size = 8 + Set32((Byte *)meta, 8) // size of security data + // Set32((Byte *)meta, 0); + } + else + { + unsigned k; + for (k = 0; k < secBufs.Size(); k++, pos += 8) + { + Set64(meta + pos, secBufs[k].Size()) + } + for (k = 0; k < secBufs.Size(); k++) + { + const CByteBuffer &buf = secBufs[k]; + size_t size = buf.Size(); + if (size != 0) + { + memcpy(meta + pos, buf, size); + pos += size; + } + } + while ((pos & 7) != 0) + meta[pos++] = 0; + Set32((Byte *)meta, (UInt32)pos) // size of security data + } + + db.Hashes = streams.ConstData(); + db.WriteTree(tree, (Byte *)meta, pos); + + { + NCrypto::NSha1::CContext sha; + sha.Init(); + sha.Update((const Byte *)meta, pos); + + Byte digest[kHashSize]; + sha.Final(digest); + + CStreamInfo s; + s.Resource.PackSize = pos; + s.Resource.Offset = curPos; + s.Resource.UnpackSize = pos; + s.Resource.Flags = NResourceFlags::kMetadata; + s.PartNumber = 1; + s.RefCount = 1; + memcpy(s.Hash, digest, kHashSize); + streams.Add(s); + + if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1) + { + header.MetadataResource = s.Resource; + header.BootIndex = _bootIndex; + } + + RINOK(WriteStream(outStream, (const Byte *)meta, pos)) + meta.Free(); + curPos += pos; + } + } + + lps->InSize = lps->OutSize = complexity; + RINOK(lps->SetCur()) + + header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize; + header.OffsetResource.Offset = curPos; + header.OffsetResource.Flags = NResourceFlags::kMetadata; + + + + // ---------- Write Streams Info Tables ---------- + + for (i = 0; i < streams.Size(); i++) + { + Byte buf[kStreamInfoSize]; + streams[i].WriteTo(buf); + RINOK(WriteStream(outStream, buf, kStreamInfoSize)) + curPos += kStreamInfoSize; + } + + AString xml (""); + AddTagUInt64_ToString(xml, "TOTALBYTES", curPos); + for (i = 0; i < trees.Size(); i++) + { + const CDir &tree = trees[i]; + + CXmlItem item; + if (_xmls.Size() == 1) + { + const CWimXml &_oldXml = _xmls[0]; + if (i < _oldXml.Images.Size()) + { + // int ttt = _oldXml.Images[i].ItemIndexInXml; + item = _oldXml.Xml.Root.SubItems[_oldXml.Images[i].ItemIndexInXml]; + } + } + if (i >= isChangedImage.Size() || isChangedImage[i]) + { + char temp[16]; + if (item.Name.IsEmpty()) + { + ConvertUInt32ToString(i + 1, temp); + item.Name = "IMAGE"; + item.IsTag = true; + CXmlProp &prop = item.Props.AddNew(); + prop.Name = "INDEX"; + prop.Value = temp; + } + + AddTag_String_IfEmpty(item, "NAME", temp); + AddTag_UInt64(item, "DIRCOUNT", tree.GetNumDirs() - 1); + AddTag_UInt64(item, "FILECOUNT", tree.GetNumFiles()); + AddTag_UInt64(item, "TOTALBYTES", tree.GetTotalSize(db.MetaItems)); + + AddTag_Time(item, "CREATIONTIME", ftCur); + AddTag_Time(item, "LASTMODIFICATIONTIME", ftCur); + } + + item.AppendTo(xml); + } + xml += ""; + + size_t xmlSize; + { + UString utf16; + if (!ConvertUTF8ToUnicode(xml, utf16)) + return S_FALSE; + xmlSize = ((size_t)utf16.Len() + 1) * 2; + + CByteArr xmlBuf(xmlSize); + Set16((Byte *)xmlBuf, 0xFEFF) + for (i = 0; i < (unsigned)utf16.Len(); i++) + { + Set16((Byte *)xmlBuf + 2 + (size_t)i * 2, (UInt16)utf16[i]) + } + RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize)) + } + + header.XmlResource.UnpackSize = + header.XmlResource.PackSize = xmlSize; + header.XmlResource.Offset = curPos; + header.XmlResource.Flags = NResourceFlags::kMetadata; + + outStream->Seek(0, STREAM_SEEK_SET, NULL); + header.NumImages = trees.Size(); + { + Byte buf[kHeaderSizeMax]; + header.WriteTo(buf); + RINOK(WriteStream(outStream, buf, kHeaderSizeMax)) + } + + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + + return S_OK; + + COM_TRY_END +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 8b23429a4..614755a72 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -1,1856 +1,1856 @@ -// Archive/WimIn.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/UTFConvert.h" - -#include "../../Common/LimitedStreams.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/XpressDecoder.h" - -#include "../Common/OutStreamWithSha1.h" - -#include "WimIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -namespace NArchive { -namespace NWim { - -static bool inline GetLog_val_min_dest(const UInt32 val, unsigned i, unsigned &dest) -{ - UInt32 v = (UInt32)1 << i; - for (; i < 32; i++) - { - if (v == val) - { - dest = i; - return true; - } - v += v; - } - return false; -} - - -HRESULT CUnpacker::UnpackChunk( - ISequentialInStream *inStream, - unsigned method, unsigned chunkSizeBits, - size_t inSize, size_t outSize, - ISequentialOutStream *outStream) -{ - if (inSize == outSize) - { - } - else if (method == NMethod::kXPRESS) - { - } - else if (method == NMethod::kLZX) - { - lzxDecoder.Create_if_Empty(); - lzxDecoder->Set_WimMode(true); - } - else if (method == NMethod::kLZMS) - { - lzmsDecoder.Create_if_Empty(); - } - else - return E_NOTIMPL; - - const size_t chunkSize = (size_t)1 << chunkSizeBits; - - { - const unsigned - kAdditionalOutputBufSize = MyMax(NCompress::NLzx:: - kAdditionalOutputBufSize, NCompress::NXpress:: - kAdditionalOutputBufSize); - unpackBuf.EnsureCapacity(chunkSize + kAdditionalOutputBufSize); - if (!unpackBuf.Data) - return E_OUTOFMEMORY; - } - - HRESULT res = S_FALSE; - size_t unpackedSize = 0; - - if (inSize == outSize) - { - unpackedSize = outSize; - res = ReadStream(inStream, unpackBuf.Data, &unpackedSize); - TotalPacked += unpackedSize; - } - else if (inSize < chunkSize) - { - const unsigned kAdditionalInputSize = 32; - packBuf.EnsureCapacity(chunkSize + kAdditionalInputSize); - if (!packBuf.Data) - return E_OUTOFMEMORY; - - RINOK(ReadStream_FALSE(inStream, packBuf.Data, inSize)) - memset(packBuf.Data + inSize, 0xff, kAdditionalInputSize); - - TotalPacked += inSize; - - if (method == NMethod::kXPRESS) - { - res = NCompress::NXpress::Decode_WithExceedWrite(packBuf.Data, inSize, unpackBuf.Data, outSize); - if (res == S_OK) - unpackedSize = outSize; - } - else if (method == NMethod::kLZX) - { - res = lzxDecoder->Set_ExternalWindow_DictBits(unpackBuf.Data, chunkSizeBits); - if (res != S_OK) - return E_NOTIMPL; - lzxDecoder->Set_KeepHistoryForNext(false); - lzxDecoder->Set_KeepHistory(false); - res = lzxDecoder->Code_WithExceedReadWrite(packBuf.Data, inSize, (UInt32)outSize); - unpackedSize = lzxDecoder->GetUnpackSize(); - if (res == S_OK && !lzxDecoder->WasBlockFinished()) - res = S_FALSE; - } - else - { - res = lzmsDecoder->Code(packBuf.Data, inSize, unpackBuf.Data, outSize); - unpackedSize = lzmsDecoder->GetUnpackSize(); - } - } - - if (unpackedSize != outSize) - { - if (res == S_OK) - res = S_FALSE; - - if (unpackedSize > outSize) - res = S_FALSE; - else - memset(unpackBuf.Data + unpackedSize, 0, outSize - unpackedSize); - } - - if (outStream) - { - RINOK(WriteStream(outStream, unpackBuf.Data, outSize)) - } - - return res; -} - - -HRESULT CUnpacker::Unpack2( - IInStream *inStream, - const CResource &resource, - const CHeader &header, - const CDatabase *db, - ISequentialOutStream *outStream, - ICompressProgressInfo *progress) -{ - if (!resource.IsCompressed() && !resource.IsSolid()) - { - copyCoder.Create_if_Empty(); - - CMyComPtr2_Create limitedStream; - limitedStream->SetStream(inStream); - - RINOK(InStream_SeekSet(inStream, resource.Offset)) - if (resource.PackSize != resource.UnpackSize) - return S_FALSE; - - limitedStream->Init(resource.PackSize); - TotalPacked += resource.PackSize; - - HRESULT res = copyCoder.Interface()->Code(limitedStream, outStream, NULL, NULL, progress); - - if (res == S_OK && copyCoder->TotalSize != resource.UnpackSize) - res = S_FALSE; - return res; - } - - if (resource.IsSolid()) - { - if (!db || resource.SolidIndex < 0) - return E_NOTIMPL; - if (resource.IsCompressed()) - return E_NOTIMPL; - - const CSolid &ss = db->Solids[resource.SolidIndex]; - - const unsigned chunkSizeBits = ss.ChunkSizeBits; - const size_t chunkSize = (size_t)1 << chunkSizeBits; - - size_t chunkIndex = 0; - UInt64 rem = ss.UnpackSize; - size_t offsetInChunk = 0; - - if (resource.IsSolidSmall()) - { - UInt64 offs = resource.Offset; - if (offs < ss.SolidOffset) - return E_NOTIMPL; - offs -= ss.SolidOffset; - if (offs > ss.UnpackSize) - return E_NOTIMPL; - rem = resource.PackSize; - if (rem > ss.UnpackSize - offs) - return E_NOTIMPL; - chunkIndex = (size_t)(offs >> chunkSizeBits); - offsetInChunk = (size_t)offs & (chunkSize - 1); - } - - UInt64 packProcessed = 0; - UInt64 outProcessed = 0; - - if (_solidIndex == resource.SolidIndex && _unpackedChunkIndex == chunkIndex) - { - size_t cur = chunkSize - offsetInChunk; - if (cur > rem) - cur = (size_t)rem; - RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur)) - outProcessed += cur; - rem -= cur; - offsetInChunk = 0; - chunkIndex++; - } - - for (;;) - { - if (rem == 0) - return S_OK; - - const UInt64 offset = ss.Chunks[chunkIndex]; - const UInt64 packSize = ss.GetChunkPackSize(chunkIndex); - const CResource &rs = db->DataStreams[ss.StreamIndex].Resource; - RINOK(InStream_SeekSet(inStream, rs.Offset + ss.HeadersSize + offset)) - - size_t cur = chunkSize; - const UInt64 unpackRem = ss.UnpackSize - ((UInt64)chunkIndex << chunkSizeBits); - if (cur > unpackRem) - cur = (size_t)unpackRem; - - _solidIndex = -1; - _unpackedChunkIndex = 0; - - const HRESULT res = UnpackChunk(inStream, (unsigned)ss.Method, chunkSizeBits, (size_t)packSize, cur, NULL); - - if (res != S_OK) - { - // We ignore data errors in solid stream. SHA will show what files are bad. - if (res != S_FALSE) - return res; - } - - _solidIndex = resource.SolidIndex; - _unpackedChunkIndex = chunkIndex; - - if (cur < offsetInChunk) - return E_FAIL; - - cur -= offsetInChunk; - - if (cur > rem) - cur = (size_t)rem; - - RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur)) - - if (progress) - { - RINOK(progress->SetRatioInfo(&packProcessed, &outProcessed)) - packProcessed += packSize; - outProcessed += cur; - } - - rem -= cur; - offsetInChunk = 0; - chunkIndex++; - } - } - - - // ---------- NON Solid ---------- - - const UInt64 unpackSize = resource.UnpackSize; - if (unpackSize == 0) - { - if (resource.PackSize == 0) - return S_OK; - return S_FALSE; - } - - if (unpackSize > ((UInt64)1 << 63)) - return E_NOTIMPL; - - const unsigned chunkSizeBits = header.ChunkSizeBits; - const unsigned entrySizeShifts = (resource.UnpackSize < ((UInt64)1 << 32) ? 2 : 3); - - UInt64 baseOffset = resource.Offset; - UInt64 packDataSize; - size_t numChunks; - { - const UInt64 numChunks64 = (unpackSize + (((UInt32)1 << chunkSizeBits) - 1)) >> chunkSizeBits; - const UInt64 sizesBufSize64 = (numChunks64 - 1) << entrySizeShifts; - if (sizesBufSize64 > resource.PackSize) - return S_FALSE; - packDataSize = resource.PackSize - sizesBufSize64; - const size_t sizesBufSize = (size_t)sizesBufSize64; - if (sizesBufSize != sizesBufSize64) - return E_OUTOFMEMORY; - sizesBuf.AllocAtLeast(sizesBufSize); - RINOK(InStream_SeekSet(inStream, baseOffset)) - RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize)) - baseOffset += sizesBufSize64; - numChunks = (size_t)numChunks64; - } - - _solidIndex = -1; - _unpackedChunkIndex = 0; - - UInt64 outProcessed = 0; - UInt64 offset = 0; - - for (size_t i = 0; i < numChunks; i++) - { - UInt64 nextOffset = packDataSize; - - if (i + 1 < numChunks) - { - const Byte *p = (const Byte *)sizesBuf + (i << entrySizeShifts); - nextOffset = (entrySizeShifts == 2) ? Get32(p): Get64(p); - } - - if (nextOffset < offset) - return S_FALSE; - - UInt64 inSize64 = nextOffset - offset; - size_t inSize = (size_t)inSize64; - if (inSize != inSize64) - return S_FALSE; - - RINOK(InStream_SeekSet(inStream, baseOffset + offset)) - - if (progress) - { - RINOK(progress->SetRatioInfo(&offset, &outProcessed)) - } - - size_t outSize = (size_t)1 << chunkSizeBits; - const UInt64 rem = unpackSize - outProcessed; - if (outSize > rem) - outSize = (size_t)rem; - - RINOK(UnpackChunk(inStream, header.GetMethod(), chunkSizeBits, inSize, outSize, outStream)) - - outProcessed += outSize; - offset = nextOffset; - } - - return S_OK; -} - - -HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, const CHeader &header, const CDatabase *db, - ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest) -{ - CMyComPtr2_Create shaStream; - // outStream can be NULL, so we use COutStreamWithSha1 even if sha1 is not required - shaStream->SetStream(outStream); - shaStream->Init(digest != NULL); - const HRESULT res = Unpack2(inStream, resource, header, db, shaStream, progress); - if (digest) - shaStream->Final(digest); - return res; -} - - -HRESULT CUnpacker::UnpackData(IInStream *inStream, - const CResource &resource, const CHeader &header, - const CDatabase *db, - CByteBuffer &buf, Byte *digest) -{ - // if (resource.IsSolid()) return E_NOTIMPL; - UInt64 unpackSize64 = resource.UnpackSize; - if (db) - unpackSize64 = db->Get_UnpackSize_of_Resource(resource); - const size_t size = (size_t)unpackSize64; - if (size != unpackSize64) - return E_OUTOFMEMORY; - buf.Alloc(size); - - CMyComPtr2_Create outStream; - outStream->Init((Byte *)buf, size); - return Unpack(inStream, resource, header, db, outStream, NULL, digest); -} - - -void CResource::Parse(const Byte *p) -{ - Flags = p[7]; - PackSize = Get64(p) & (((UInt64)1 << 56) - 1); - Offset = Get64(p + 8); - UnpackSize = Get64(p + 16); - KeepSolid = false; - SolidIndex = -1; -} - -#define GET_RESOURCE(_p_, res) res.ParseAndUpdatePhySize(_p_, phySize) - -static inline void ParseStream(bool oldVersion, const Byte *p, CStreamInfo &s) -{ - s.Resource.Parse(p); - if (oldVersion) - { - s.PartNumber = 1; - s.Id = Get32(p + 24); - p += 28; - } - else - { - s.PartNumber = Get16(p + 24); - p += 26; - } - s.RefCount = Get32(p); - memcpy(s.Hash, p + 4, kHashSize); -} - - -#define kLongPath "[LongPath]" - -void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) const -{ - const CItem &item = Items[index]; - const CImage &image = Images[item.ImageIndex]; - if (item.Parent < 0 && image.NumEmptyRootItems != 0) - { - name.Clear(); - return; - } - const Byte *meta = image.Meta + item.Offset + - (IsOldVersion ? kDirRecordSizeOld : kDirRecordSize); - UInt32 fileNameLen = Get16(meta - 2); - UInt32 shortLen = Get16(meta - 4) / 2; - wchar_t *s = name.AllocBstr(shortLen); - if (fileNameLen != 0) - meta += fileNameLen + 2; - for (UInt32 i = 0; i < shortLen; i++) - s[i] = Get16(meta + i * 2); - s[shortLen] = 0; - // empty shortName has no ZERO at the end ? -} - - -void CDatabase::GetItemName(unsigned index, NWindows::NCOM::CPropVariant &name) const -{ - const CItem &item = Items[index]; - const CImage &image = Images[item.ImageIndex]; - if (item.Parent < 0 && image.NumEmptyRootItems != 0) - { - name = image.RootName; - return; - } - const Byte *meta = image.Meta + item.Offset + - (item.IsAltStream ? - (IsOldVersion ? 0x10 : 0x24) : - (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2)); - UInt32 len = Get16(meta) / 2; - wchar_t *s = name.AllocBstr(len); - meta += 2; - len++; - for (UInt32 i = 0; i < len; i++) - s[i] = Get16(meta + i * 2); -} - - -void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCOM::CPropVariant &path) const -{ - unsigned size = 0; - int index = (int)index1; - const int imageIndex = Items[index].ImageIndex; - const CImage &image = Images[imageIndex]; - - unsigned newLevel = 0; - bool needColon = false; - - for (;;) - { - const CItem &item = Items[index]; - index = item.Parent; - if (index >= 0 || image.NumEmptyRootItems == 0) - { - const Byte *meta = image.Meta + item.Offset; - meta += item.IsAltStream ? - (IsOldVersion ? 0x10 : 0x24) : - (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); - needColon = item.IsAltStream; - size += Get16(meta) / 2; - size += newLevel; - newLevel = 1; - if (size >= ((UInt32)1 << 15)) - { - path = kLongPath; - return; - } - } - if (index < 0) - break; - } - - if (showImageNumber) - { - size += image.RootName.Len(); - size += newLevel; - } - else if (needColon) - size++; - - wchar_t *s = path.AllocBstr(size); - s[size] = 0; - - if (showImageNumber) - { - MyStringCopy(s, (const wchar_t *)image.RootName); - if (newLevel) - s[image.RootName.Len()] = (wchar_t)(needColon ? L':' : WCHAR_PATH_SEPARATOR); - } - else if (needColon) - s[0] = L':'; - - index = (int)index1; - wchar_t separator = 0; - - for (;;) - { - const CItem &item = Items[index]; - index = item.Parent; - if (index >= 0 || image.NumEmptyRootItems == 0) - { - if (separator != 0) - s[--size] = separator; - const Byte *meta = image.Meta + item.Offset; - meta += (item.IsAltStream) ? - (IsOldVersion ? 0x10: 0x24) : - (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); - unsigned len = Get16(meta) / 2; - size -= len; - wchar_t *dest = s + size; - meta += 2; - for (unsigned i = 0; i < len; i++) - { - wchar_t c = Get16(meta + i * 2); - if (c == L'/') - c = L'_'; - #if WCHAR_PATH_SEPARATOR != L'/' - else if (c == L'\\') - c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme - #endif - dest[i] = c; - } - } - if (index < 0) - return; - separator = item.IsAltStream ? L':' : WCHAR_PATH_SEPARATOR; - } -} - - -// if (ver <= 1.10), root folder contains real items. -// if (ver >= 1.12), root folder contains only one folder with empty name. - -HRESULT CDatabase::ParseDirItem(size_t pos, int parent) -{ - const unsigned align = GetDirAlignMask(); - if ((pos & align) != 0) - return S_FALSE; - - for (unsigned numItems = 0;; numItems++) - { - if (OpenCallback && (Items.Size() & 0xFFFF) == 0) - { - UInt64 numFiles = Items.Size(); - RINOK(OpenCallback->SetCompleted(&numFiles, NULL)) - } - - const size_t rem = DirSize - pos; - if (pos < DirStartOffset || pos > DirSize || rem < 8) - return S_FALSE; - - const Byte *p = DirData + pos; - - UInt64 len = Get64(p); - if (len == 0) - { - DirProcessed += 8; - return S_OK; - } - - if ((len & align) != 0 || rem < len) - return S_FALSE; - - DirProcessed += (size_t)len; - if (DirProcessed > DirSize) - return S_FALSE; - - const unsigned dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; - if (len < dirRecordSize) - return S_FALSE; - - CItem item; - UInt32 attrib = Get32(p + 8); - item.IsDir = ((attrib & 0x10) != 0); - UInt64 subdirOffset = Get64(p + 0x10); - - const UInt32 numAltStreams = Get16(p + dirRecordSize - 6); - const UInt32 shortNameLen = Get16(p + dirRecordSize - 4); - const UInt32 fileNameLen = Get16(p + dirRecordSize - 2); - if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) - return S_FALSE; - const UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); - const UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); - if (((dirRecordSize + fileNameLen2 + shortNameLen2 + align) & ~align) > len) - return S_FALSE; - - p += dirRecordSize; - - { - if (*(const UInt16 *)(const void *)(p + fileNameLen) != 0) - return S_FALSE; - for (UInt32 j = 0; j < fileNameLen; j += 2) - if (*(const UInt16 *)(const void *)(p + j) == 0) - return S_FALSE; - } - - // PRF(printf("\n%S", p)); - - if (shortNameLen != 0) - { - // empty shortName has no ZERO at the end ? - const Byte *p2 = p + fileNameLen2; - if (*(const UInt16 *)(const void *)(p2 + shortNameLen) != 0) - return S_FALSE; - for (UInt32 j = 0; j < shortNameLen; j += 2) - if (*(const UInt16 *)(const void *)(p2 + j) == 0) - return S_FALSE; - } - - item.Offset = pos; - item.Parent = parent; - item.ImageIndex = (int)Images.Size() - 1; - - const unsigned prevIndex = Items.Add(item); - - pos += (size_t)len; - - for (UInt32 i = 0; i < numAltStreams; i++) - { - const size_t rem2 = DirSize - pos; - if (pos < DirStartOffset || pos > DirSize || rem2 < 8) - return S_FALSE; - const Byte *p2 = DirData + pos; - const UInt64 len2 = Get64(p2); - if ((len2 & align) != 0 || rem2 < len2 - || len2 < (unsigned)(IsOldVersion ? 0x18 : 0x28)) - return S_FALSE; - - DirProcessed += (size_t)len2; - if (DirProcessed > DirSize) - return S_FALSE; - - unsigned extraOffset = 0; - - if (IsOldVersion) - extraOffset = 0x10; - else - { - if (Get64(p2 + 8) != 0) - return S_FALSE; - extraOffset = 0x24; - } - - const UInt32 fileNameLen111 = Get16(p2 + extraOffset); - if ((fileNameLen111 & 1) != 0) - return S_FALSE; - /* Probably different versions of ImageX can use different number of - additional ZEROs. So we don't use exact check. */ - const UInt32 fileNameLen222 = (fileNameLen111 == 0 ? fileNameLen111 : fileNameLen111 + 2); - if (((extraOffset + 2 + fileNameLen222 + align) & ~align) > len2) - return S_FALSE; - - { - const Byte *p3 = p2 + extraOffset + 2; - if (*(const UInt16 *)(const void *)(p3 + fileNameLen111) != 0) - return S_FALSE; - for (UInt32 j = 0; j < fileNameLen111; j += 2) - if (*(const UInt16 *)(const void *)(p3 + j) == 0) - return S_FALSE; - - // PRF(printf("\n %S", p3)); - } - - - /* wim uses alt sreams list, if there is at least one alt stream. - And alt stream without name is main stream. */ - - // Why wimlib writes two alt streams for REPARSE_POINT, with empty second alt stream? - - Byte *prevMeta = DirData + item.Offset; - - if (fileNameLen111 == 0 && - ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) || !item.IsDir) - && (IsOldVersion || IsEmptySha(prevMeta + 0x40))) - { - if (IsOldVersion) - memcpy(prevMeta + 0x10, p2 + 8, 4); // It's 32-bit Id - else if (!IsEmptySha(p2 + 0x10)) - { - // if (IsEmptySha(prevMeta + 0x40)) - memcpy(prevMeta + 0x40, p2 + 0x10, kHashSize); - // else HeadersError = true; - } - } - else - { - ThereAreAltStreams = true; - CItem item2; - item2.Offset = pos; - item2.IsAltStream = true; - item2.Parent = (int)prevIndex; - item2.ImageIndex = (int)Images.Size() - 1; - Items.Add(item2); - } - - pos += (size_t)len2; - } - - if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir) - { - const Byte *p2 = DirData + pos; - if (DirSize - pos >= 8 && Get64(p2) == 0) - { - CImage &image = Images.Back(); - image.NumEmptyRootItems = 1; - - if (subdirOffset != 0 - && DirSize - pos >= 16 - && Get64(p2 + 8) != 0 - && pos + 8 < subdirOffset) - { - // Longhorn.4093 contains hidden files after empty root folder and before items of next folder. Why? - // That code shows them. If we want to ignore them, we need to update DirProcessed. - // DirProcessed += (size_t)(subdirOffset - (pos + 8)); - // printf("\ndirOffset = %5d hiddenOffset = %5d\n", (int)subdirOffset, (int)pos + 8); - subdirOffset = pos + 8; - // return S_FALSE; - } - } - } - - if (item.IsDir && subdirOffset != 0) - { - RINOK(ParseDirItem((size_t)subdirOffset, (int)prevIndex)) - } - } -} - - -HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) -{ - DirData = buf; - DirSize = buf.Size(); - if (DirSize < 8) - return S_FALSE; - const Byte *p = DirData; - size_t pos = 0; - CImage &image = Images.Back(); - - if (IsOldVersion) - { - UInt32 numEntries = Get32(p + 4); - - if (numEntries > (1 << 28) || - numEntries > (DirSize >> 3)) - return S_FALSE; - - UInt32 sum = 8; - if (numEntries != 0) - sum = numEntries * 8; - - image.SecurOffsets.ClearAndReserve(numEntries + 1); - image.SecurOffsets.AddInReserved(sum); - - for (UInt32 i = 0; i < numEntries; i++) - { - const Byte *pp = p + (size_t)i * 8; - UInt32 len = Get32(pp); - if (i != 0 && Get32(pp + 4) != 0) - return S_FALSE; - if (len > DirSize - sum) - return S_FALSE; - sum += len; - if (sum < len) - return S_FALSE; - image.SecurOffsets.AddInReserved(sum); - } - - pos = sum; - - const size_t align = GetDirAlignMask(); - pos = (pos + align) & ~(size_t)align; - } - else - { - UInt32 totalLen = Get32(p); - if (totalLen == 0) - pos = 8; - else - { - if (totalLen < 8) - return S_FALSE; - UInt32 numEntries = Get32(p + 4); - pos = 8; - if (totalLen > DirSize || numEntries > ((totalLen - 8) >> 3)) - return S_FALSE; - UInt32 sum = (UInt32)pos + numEntries * 8; - image.SecurOffsets.ClearAndReserve(numEntries + 1); - image.SecurOffsets.AddInReserved(sum); - - for (UInt32 i = 0; i < numEntries; i++, pos += 8) - { - UInt64 len = Get64(p + pos); - if (len > totalLen - sum) - return S_FALSE; - sum += (UInt32)len; - image.SecurOffsets.AddInReserved(sum); - } - - pos = sum; - pos = (pos + 7) & ~(size_t)7; - if (pos != (((size_t)totalLen + 7) & ~(size_t)7)) - return S_FALSE; - } - } - - if (pos > DirSize) - return S_FALSE; - - DirStartOffset = DirProcessed = pos; - image.StartItem = Items.Size(); - - RINOK(ParseDirItem(pos, parent)) - - image.NumItems = Items.Size() - image.StartItem; - if (DirProcessed == DirSize) - return S_OK; - - /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), - but the reference to that folder is empty */ - - // we can't use DirProcessed - DirStartOffset == 112 check if there is alt stream in root - if (DirProcessed == DirSize - 8 && Get64(p + DirSize - 8) != 0) - return S_OK; - - // 18.06: we support cases, when some old dism can capture images - // where DirProcessed much smaller than DirSize - HeadersError = true; - return S_OK; - // return S_FALSE; -} - - -HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) -{ - UInt32 headerSize = Get32(p + 8); - phySize = headerSize; - Version = Get32(p + 0x0C); - Flags = Get32(p + 0x10); - if (!IsSupported()) - return S_FALSE; - - { - ChunkSize = Get32(p + 0x14); - ChunkSizeBits = kChunkSizeBits; - if (ChunkSize != 0) - { - if (!GetLog_val_min_dest(ChunkSize, 12, ChunkSizeBits)) - return S_FALSE; - } - } - - _isOldVersion = false; - _isNewVersion = false; - - if (IsSolidVersion()) - _isNewVersion = true; - else - { - if (Version < 0x010900) - return S_FALSE; - _isOldVersion = (Version <= 0x010A00); - // We don't know details about 1.11 version. So we use headerSize to guess exact features. - if (Version == 0x010B00 && headerSize == 0x60) - _isOldVersion = true; - _isNewVersion = (Version >= 0x010D00); - } - - unsigned offset; - - if (IsOldVersion()) - { - if (headerSize != 0x60) - return S_FALSE; - memset(Guid, 0, 16); - offset = 0x18; - PartNumber = 1; - NumParts = 1; - } - else - { - if (headerSize < 0x74) - return S_FALSE; - memcpy(Guid, p + 0x18, 16); - PartNumber = Get16(p + 0x28); - NumParts = Get16(p + 0x2A); - if (PartNumber == 0 || PartNumber > NumParts) - return S_FALSE; - offset = 0x2C; - if (IsNewVersion()) - { - // if (headerSize < 0xD0) - if (headerSize != 0xD0) - return S_FALSE; - NumImages = Get32(p + offset); - offset += 4; - } - } - - GET_RESOURCE(p + offset , OffsetResource); - GET_RESOURCE(p + offset + 0x18, XmlResource); - GET_RESOURCE(p + offset + 0x30, MetadataResource); - BootIndex = 0; - - if (IsNewVersion()) - { - BootIndex = Get32(p + offset + 0x48); - GET_RESOURCE(p + offset + 0x4C, IntegrityResource); - } - - return S_OK; -} - - -const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; - -HRESULT ReadHeader(IInStream *inStream, CHeader &h, UInt64 &phySize) -{ - Byte p[kHeaderSizeMax]; - RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax)) - if (memcmp(p, kSignature, kSignatureSize) != 0) - return S_FALSE; - return h.Parse(p, phySize); -} - - -static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) -{ - CByteBuffer offsetBuf; - - CUnpacker unpacker; - RINOK(unpacker.UnpackData(inStream, h.OffsetResource, h, NULL, offsetBuf, NULL)) - - const size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize; - { - const unsigned numItems = (unsigned)(offsetBuf.Size() / streamInfoSize); - if ((size_t)numItems * streamInfoSize != offsetBuf.Size()) - return S_FALSE; - const unsigned numItems2 = db.DataStreams.Size() + numItems; - if (numItems2 < numItems) - return S_FALSE; - db.DataStreams.Reserve(numItems2); - } - - bool keepSolid = false; - - for (size_t i = 0; i < offsetBuf.Size(); i += streamInfoSize) - { - CStreamInfo s; - ParseStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s); - - PRF(printf("\n")); - PRF(printf(s.Resource.IsMetadata() ? "### META" : " DATA")); - PRF(printf(" %2X", s.Resource.Flags)); - PRF(printf(" %9I64X", s.Resource.Offset)); - PRF(printf(" %9I64X", s.Resource.PackSize)); - PRF(printf(" %9I64X", s.Resource.UnpackSize)); - PRF(printf(" %d", s.RefCount)); - - if (s.PartNumber != h.PartNumber) - continue; - - if (s.Resource.IsSolid()) - { - s.Resource.KeepSolid = keepSolid; - keepSolid = true; - } - else - { - s.Resource.KeepSolid = false; - keepSolid = false; - } - - if (!s.Resource.IsMetadata()) - db.DataStreams.AddInReserved(s); - else - { - if (s.Resource.IsSolid()) - return E_NOTIMPL; - if (s.RefCount == 0) - { - // some wims have such (deleted?) metadata stream. - // examples: boot.wim in VistaBeta2, WinPE.wim from WAIK. - // db.DataStreams.Add(s); - // we can show these delete images, if we comment "continue" command; - continue; - } - - if (s.RefCount > 1) - { - return S_FALSE; - // s.RefCount--; - // db.DataStreams.Add(s); - } - - db.MetaStreams.Add(s); - } - } - - PRF(printf("\n")); - - return S_OK; -} - - -HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml) -{ - CUnpacker unpacker; - return unpacker.UnpackData(inStream, h.XmlResource, h, this, xml, NULL); -} - -static void SetRootNames(CImage &image, unsigned value) -{ - wchar_t temp[16]; - ConvertUInt32ToString(value, temp); - image.RootName = temp; - image.RootNameBuf.Alloc(image.RootName.Len() * 2 + 2); - Byte *p = image.RootNameBuf; - unsigned len = image.RootName.Len() + 1; - for (unsigned k = 0; k < len; k++) - { - p[k * 2] = (Byte)temp[k]; - p[k * 2 + 1] = 0; - } -} - - -HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback) -{ - OpenCallback = openCallback; - IsOldVersion = h.IsOldVersion(); - IsOldVersion9 = (h.Version == 0x10900); - - RINOK(ReadStreams(inStream, h, *this)) - - bool needBootMetadata = !h.MetadataResource.IsEmpty(); - unsigned numNonDeletedImages = 0; - - CUnpacker unpacker; - - FOR_VECTOR (i, MetaStreams) - { - const CStreamInfo &si = MetaStreams[i]; - - if (h.PartNumber != 1 || si.PartNumber != h.PartNumber) - continue; - - const unsigned userImage = Images.Size() + GetStartImageIndex(); - CImage &image = Images.AddNew(); - SetRootNames(image, userImage); - - CByteBuffer &metadata = image.Meta; - Byte hash[kHashSize]; - - RINOK(unpacker.UnpackData(inStream, si.Resource, h, this, metadata, hash)) - - if (memcmp(hash, si.Hash, kHashSize) != 0 && - !(h.IsOldVersion() && IsEmptySha(si.Hash))) - return S_FALSE; - - image.NumEmptyRootItems = 0; - - if (Items.IsEmpty()) - Items.ClearAndReserve(numItemsReserve); - - RINOK(ParseImageDirs(metadata, -1)) - - if (needBootMetadata) - { - bool sameRes = (h.MetadataResource.Offset == si.Resource.Offset); - if (sameRes) - needBootMetadata = false; - if (h.IsNewVersion()) - { - if (si.RefCount == 1) - { - numNonDeletedImages++; - bool isBootIndex = (h.BootIndex == numNonDeletedImages); - if (sameRes && !isBootIndex) - return S_FALSE; - if (isBootIndex && !sameRes) - return S_FALSE; - } - } - } - } - - if (needBootMetadata) - return S_FALSE; - return S_OK; -} - - -bool CDatabase::ItemHasStream(const CItem &item) const -{ - if (item.ImageIndex < 0) - return true; - const Byte *meta = Images[item.ImageIndex].Meta + item.Offset; - if (IsOldVersion) - { - // old wim use same field for file_id and dir_offset; - if (item.IsDir) - return false; - meta += (item.IsAltStream ? 0x8 : 0x10); - UInt32 id = GetUi32(meta); - return id != 0; - } - meta += (item.IsAltStream ? 0x10 : 0x40); - return !IsEmptySha(meta); -} - - -#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } - -static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) -{ - RINOZ(MyCompare(p1->PartNumber, p2->PartNumber)) - RINOZ(MyCompare(p1->Resource.Offset, p2->Resource.Offset)) - return MyCompare(p1->Resource.PackSize, p2->Resource.PackSize); -} - -static int CompareIDs(const unsigned *p1, const unsigned *p2, void *param) -{ - const CStreamInfo *streams = (const CStreamInfo *)param; - return MyCompare(streams[*p1].Id, streams[*p2].Id); -} - -static int CompareHashRefs(const unsigned *p1, const unsigned *p2, void *param) -{ - const CStreamInfo *streams = (const CStreamInfo *)param; - return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); -} - -static int FindId(const CStreamInfo *streams, const CUIntVector &sorted, UInt32 id) -{ - unsigned left = 0, right = sorted.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const unsigned streamIndex = sorted[mid]; - const UInt32 id2 = streams[streamIndex].Id; - if (id == id2) - return (int)streamIndex; - if (id < id2) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int FindHash(const CStreamInfo *streams, const CUIntVector &sorted, const Byte *hash) -{ - unsigned left = 0, right = sorted.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const unsigned streamIndex = sorted[mid]; - const Byte *hash2 = streams[streamIndex].Hash; - unsigned i; - for (i = 0; i < kHashSize; i++) - if (hash[i] != hash2[i]) - break; - if (i == kHashSize) - return (int)streamIndex; - if (hash[i] < hash2[i]) - right = mid; - else - left = mid + 1; - } - return -1; -} - -static int CompareItems(const unsigned *a1, const unsigned *a2, void *param) -{ - const CRecordVector &items = ((CDatabase *)param)->Items; - const CItem &i1 = items[*a1]; - const CItem &i2 = items[*a2]; - - if (i1.IsDir != i2.IsDir) - return i1.IsDir ? -1 : 1; - if (i1.IsAltStream != i2.IsAltStream) - return i1.IsAltStream ? 1 : -1; - RINOZ(MyCompare(i1.StreamIndex, i2.StreamIndex)) - RINOZ(MyCompare(i1.ImageIndex, i2.ImageIndex)) - return MyCompare(i1.Offset, i2.Offset); -} - - -HRESULT CDatabase::FillAndCheck(const CObjectVector &volumes) -{ - CUIntVector sortedByHash; - sortedByHash.Reserve(DataStreams.Size()); - { - CByteBuffer sizesBuf; - - for (unsigned iii = 0; iii < DataStreams.Size();) - { - { - const CResource &r = DataStreams[iii].Resource; - if (!r.IsSolid()) - { - sortedByHash.AddInReserved(iii++); - continue; - } - } - - UInt64 solidRunOffset = 0; - unsigned k; - unsigned numSolidsStart = Solids.Size(); - - for (k = iii; k < DataStreams.Size(); k++) - { - CStreamInfo &si = DataStreams[k]; - CResource &r = si.Resource; - - if (!r.IsSolid()) - break; - if (!r.KeepSolid && k != iii) - break; - - if (r.Flags != NResourceFlags::kSolid) - return S_FALSE; - - if (!r.IsSolidBig()) - continue; - - if (!si.IsEmptyHash()) - return S_FALSE; - if (si.RefCount != 1) - return S_FALSE; - - r.SolidIndex = (int)Solids.Size(); - - CSolid &ss = Solids.AddNew(); - ss.StreamIndex = k; - ss.SolidOffset = solidRunOffset; - { - const size_t kSolidHeaderSize = 8 + 4 + 4; - Byte header[kSolidHeaderSize]; - - if (si.PartNumber >= volumes.Size()) - return S_FALSE; - - const CVolume &vol = volumes[si.PartNumber]; - IInStream *inStream = vol.Stream; - RINOK(InStream_SeekSet(inStream, r.Offset)) - RINOK(ReadStream_FALSE(inStream, (Byte *)header, kSolidHeaderSize)) - - ss.UnpackSize = GetUi64(header); - - if (ss.UnpackSize > ((UInt64)1 << 63)) - return S_FALSE; - - solidRunOffset += ss.UnpackSize; - if (solidRunOffset < ss.UnpackSize) - return S_FALSE; - - const UInt32 solidChunkSize = GetUi32(header + 8); - if (!GetLog_val_min_dest(solidChunkSize, 8, ss.ChunkSizeBits)) - return S_FALSE; - ss.Method = (Int32)GetUi32(header + 12); - - const UInt64 numChunks64 = (ss.UnpackSize + (((UInt32)1 << ss.ChunkSizeBits) - 1)) >> ss.ChunkSizeBits; - const UInt64 sizesBufSize64 = 4 * numChunks64; - ss.HeadersSize = kSolidHeaderSize + sizesBufSize64; - const size_t sizesBufSize = (size_t)sizesBufSize64; - if (sizesBufSize != sizesBufSize64) - return E_OUTOFMEMORY; - sizesBuf.AllocAtLeast(sizesBufSize); - - RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize)) - - const size_t numChunks = (size_t)numChunks64; - ss.Chunks.Alloc(numChunks + 1); - - UInt64 offset = 0; - - size_t c; - for (c = 0; c < numChunks; c++) - { - ss.Chunks[c] = offset; - UInt32 packSize = GetUi32((const Byte *)sizesBuf + c * 4); - offset += packSize; - if (offset < packSize) - return S_FALSE; - } - ss.Chunks[c] = offset; - - if (ss.Chunks[0] != 0) - return S_FALSE; - if (ss.HeadersSize + offset != r.PackSize) - return S_FALSE; - } - } - - unsigned solidLim = k; - - for (k = iii; k < solidLim; k++) - { - CStreamInfo &si = DataStreams[k]; - CResource &r = si.Resource; - - if (!r.IsSolidSmall()) - continue; - - if (si.IsEmptyHash()) - return S_FALSE; - - unsigned solidIndex; - { - UInt64 offset = r.Offset; - for (solidIndex = numSolidsStart;; solidIndex++) - { - if (solidIndex == Solids.Size()) - return S_FALSE; - UInt64 unpackSize = Solids[solidIndex].UnpackSize; - if (offset < unpackSize) - break; - offset -= unpackSize; - } - } - CSolid &ss = Solids[solidIndex]; - if (r.Offset < ss.SolidOffset) - return S_FALSE; - const UInt64 relat = r.Offset - ss.SolidOffset; - if (relat > ss.UnpackSize) - return S_FALSE; - if (r.PackSize > ss.UnpackSize - relat) - return S_FALSE; - r.SolidIndex = (int)solidIndex; - if (ss.FirstSmallStream < 0) - ss.FirstSmallStream = (int)k; - - sortedByHash.AddInReserved(k); - // ss.NumRefs++; - } - - iii = solidLim; - } - } - - if (Solids.IsEmpty()) - { - /* We want to check that streams layout is OK. - So we need resources sorted by offset. - Another code can work with non-sorted streams. - NOTE: all WIM programs probably create wim archives with - sorted data streams. So it doesn't call Sort() here. */ - - { - unsigned i; - for (i = 1; i < DataStreams.Size(); i++) - { - const CStreamInfo &s0 = DataStreams[i - 1]; - const CStreamInfo &s1 = DataStreams[i]; - if (s0.PartNumber < s1.PartNumber) continue; - if (s0.PartNumber > s1.PartNumber) break; - if (s0.Resource.Offset < s1.Resource.Offset) continue; - if (s0.Resource.Offset > s1.Resource.Offset) break; - if (s0.Resource.PackSize > s1.Resource.PackSize) break; - } - - if (i < DataStreams.Size()) - { - // return E_FAIL; - DataStreams.Sort(CompareStreamsByPos, NULL); - } - } - - for (unsigned i = 1; i < DataStreams.Size(); i++) - { - const CStreamInfo &s0 = DataStreams[i - 1]; - const CStreamInfo &s1 = DataStreams[i]; - if (s0.PartNumber == s1.PartNumber) - if (s0.Resource.GetEndLimit() > s1.Resource.Offset) - return S_FALSE; - } - } - - { - { - const CStreamInfo *streams = DataStreams.ConstData(); - - if (IsOldVersion) - { - sortedByHash.Sort(CompareIDs, (void *)streams); - - for (unsigned i = 1; i < sortedByHash.Size(); i++) - if (streams[sortedByHash[i - 1]].Id >= - streams[sortedByHash[i]].Id) - return S_FALSE; - } - else - { - sortedByHash.Sort(CompareHashRefs, (void *)streams); - - if (!sortedByHash.IsEmpty()) - { - if (IsEmptySha(streams[sortedByHash[0]].Hash)) - HeadersError = true; - - for (unsigned i = 1; i < sortedByHash.Size(); i++) - if (memcmp( - streams[sortedByHash[i - 1]].Hash, - streams[sortedByHash[i]].Hash, - kHashSize) >= 0) - return S_FALSE; - } - } - } - - FOR_VECTOR (i, Items) - { - CItem &item = Items[i]; - item.StreamIndex = -1; - const Byte *hash = Images[item.ImageIndex].Meta + item.Offset; - if (IsOldVersion) - { - if (!item.IsDir) - { - hash += (item.IsAltStream ? 0x8 : 0x10); - UInt32 id = GetUi32(hash); - if (id != 0) - item.StreamIndex = FindId(DataStreams.ConstData(), sortedByHash, id); - } - } - /* - else if (item.IsDir) - { - // reparse points can have dirs some dir - } - */ - else - { - hash += (item.IsAltStream ? 0x10 : 0x40); - if (!IsEmptySha(hash)) - { - item.StreamIndex = FindHash(DataStreams.ConstData(), sortedByHash, hash); - } - } - } - } - { - CUIntVector refCounts; - refCounts.ClearAndSetSize(DataStreams.Size()); - unsigned i; - - for (i = 0; i < DataStreams.Size(); i++) - { - UInt32 startVal = 0; - // const CStreamInfo &s = DataStreams[i]; - /* - if (s.Resource.IsMetadata() && s.PartNumber == 1) - startVal = 1; - */ - refCounts[i] = startVal; - } - - for (i = 0; i < Items.Size(); i++) - { - const int streamIndex = Items[i].StreamIndex; - if (streamIndex >= 0) - refCounts[streamIndex]++; - } - - for (i = 0; i < DataStreams.Size(); i++) - { - const CStreamInfo &s = DataStreams[i]; - if (s.RefCount != refCounts[i] - && !s.Resource.IsSolidBig()) - { - /* - printf("\ni=%5d si.Ref=%2d realRefs=%2d size=%8d offset=%8x id=%4d ", - i, s.RefCount, refCounts[i], (unsigned)s.Resource.UnpackSize, (unsigned)s.Resource.Offset, s.Id); - */ - RefCountError = true; - } - - if (refCounts[i] == 0) - { - const CResource &r = DataStreams[i].Resource; - if (!r.IsSolidBig() || Solids[r.SolidIndex].FirstSmallStream < 0) - { - CItem item; - item.Offset = 0; - item.StreamIndex = (int)i; - item.ImageIndex = -1; - Items.Add(item); - ThereAreDeletedStreams = true; - } - } - } - } - - return S_OK; -} - - -HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) -{ - SortedItems.Clear(); - VirtualRoots.Clear(); - IndexOfUserImage = imageIndex; - NumExcludededItems = 0; - ExludedItem = -1; - - if (Images.Size() != 1 && imageIndex < 0) - showImageNumber = true; - - unsigned startItem = 0; - unsigned endItem = 0; - - if (imageIndex < 0) - { - endItem = Items.Size(); - if (Images.Size() == 1) - { - IndexOfUserImage = 0; - const CImage &image = Images[0]; - if (!showImageNumber) - NumExcludededItems = image.NumEmptyRootItems; - } - } - else if ((unsigned)imageIndex < Images.Size()) - { - const CImage &image = Images[imageIndex]; - startItem = image.StartItem; - endItem = startItem + image.NumItems; - if (!showImageNumber) - NumExcludededItems = image.NumEmptyRootItems; - } - - if (NumExcludededItems != 0) - { - ExludedItem = (int)startItem; - startItem += NumExcludededItems; - } - - unsigned num = endItem - startItem; - SortedItems.ClearAndSetSize(num); - unsigned i; - for (i = 0; i < num; i++) - SortedItems[i] = startItem + i; - - SortedItems.Sort(CompareItems, this); - for (i = 0; i < SortedItems.Size(); i++) - Items[SortedItems[i]].IndexInSorted = (int)i; - - if (showImageNumber) - for (i = 0; i < Images.Size(); i++) - { - CImage &image = Images[i]; - if (image.NumEmptyRootItems != 0) - continue; - image.VirtualRootIndex = (int)VirtualRoots.Size(); - VirtualRoots.Add(i); - } - - return S_OK; -} - - -static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size) -{ - if (v.Size() == size) - return; - v.ClearAndSetSize(size); - int *vals = &v[0]; - for (unsigned i = 0; i < size; i++) - vals[i] = -1; -} - - -HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback) -{ - ItemToReparse.Clear(); - ReparseItems.Clear(); - - // we don't know about Reparse field for OLD WIM format - if (IsOldVersion) - return S_OK; - - CIntVector streamToReparse; - CUnpacker unpacker; - UInt64 totalPackedPrev = 0; - - FOR_VECTOR(indexInSorted, SortedItems) - { - // we use sorted items for faster access - unsigned itemIndex = SortedItems[indexInSorted]; - const CItem &item = Items[itemIndex]; - - if (!item.HasMetadata() || item.IsAltStream) - continue; - - if (item.ImageIndex < 0) - continue; - - const Byte *metadata = Images[item.ImageIndex].Meta + item.Offset; - - const UInt32 attrib = Get32(metadata + 8); - if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) - continue; - - if (item.StreamIndex < 0) - continue; // it's ERROR - - const CStreamInfo &si = DataStreams[item.StreamIndex]; - if (si.Resource.UnpackSize >= (1 << 16)) - continue; // reparse data can not be larger than 64 KB - - IntVector_SetMinusOne_IfNeed(streamToReparse, DataStreams.Size()); - IntVector_SetMinusOne_IfNeed(ItemToReparse, Items.Size()); - - const unsigned offset = 0x58; // we don't know about Reparse field for OLD WIM format - UInt32 tag = Get32(metadata + offset); - int reparseIndex = streamToReparse[item.StreamIndex]; - CByteBuffer buf; - - if (openCallback) - { - if ((unpacker.TotalPacked - totalPackedPrev) >= ((UInt32)1 << 16)) - { - UInt64 numFiles = Items.Size(); - RINOK(openCallback->SetCompleted(&numFiles, &unpacker.TotalPacked)) - totalPackedPrev = unpacker.TotalPacked; - } - } - - if (reparseIndex >= 0) - { - const CByteBuffer &reparse = ReparseItems[reparseIndex]; - if (tag == Get32(reparse)) - { - ItemToReparse[itemIndex] = reparseIndex; - continue; - } - buf = reparse; - // we support that strange and unusual situation with different tags and same reparse data. - } - else - { - /* - if (si.PartNumber >= volumes.Size()) - continue; - */ - const CVolume &vol = volumes[si.PartNumber]; - /* - if (!vol.Stream) - continue; - */ - - Byte digest[kHashSize]; - HRESULT res = unpacker.UnpackData(vol.Stream, si.Resource, vol.Header, this, buf, digest); - - if (res == S_FALSE) - continue; - - RINOK(res) - - if (memcmp(digest, si.Hash, kHashSize) != 0 - // && !(h.IsOldVersion() && IsEmptySha(si.Hash)) - ) - { - // setErrorStatus; - continue; - } - } - - CByteBuffer &reparse = ReparseItems.AddNew(); - reparse.Alloc(8 + buf.Size()); - Byte *dest = (Byte *)reparse; - SetUi32(dest, tag) - SetUi32(dest + 4, (UInt32)buf.Size()) - if (buf.Size() != 0) - memcpy(dest + 8, buf, buf.Size()); - ItemToReparse[itemIndex] = (int)ReparseItems.Size() - 1; - } - - return S_OK; -} - - - -static bool ParseNumber64(const AString &s, UInt64 &res) -{ - const char *end; - if (s.IsPrefixedBy("0x")) - { - if (s.Len() == 2) - return false; - res = ConvertHexStringToUInt64(s.Ptr(2), &end); - } - else - { - if (s.IsEmpty()) - return false; - res = ConvertStringToUInt64(s, &end); - } - return *end == 0; -} - - -static bool ParseNumber32(const AString &s, UInt32 &res) -{ - UInt64 res64; - if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32)) - return false; - res = (UInt32)res64; - return true; -} - - -static bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) -{ - const CXmlItem *timeItem = item.FindSubTag_GetPtr(tag); - if (timeItem) - { - UInt32 low = 0, high = 0; - if (ParseNumber32(timeItem->GetSubStringForTag("LOWPART"), low) && - ParseNumber32(timeItem->GetSubStringForTag("HIGHPART"), high)) - { - ft.dwLowDateTime = low; - ft.dwHighDateTime = high; - return true; - } - } - return false; -} - - -void CImageInfo::Parse(const CXmlItem &item) -{ - CTimeDefined = ParseTime(item, CTime, "CREATIONTIME"); - MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME"); - NameDefined = true; - ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name); - - ParseNumber64(item.GetSubStringForTag("DIRCOUNT"), DirCount); - ParseNumber64(item.GetSubStringForTag("FILECOUNT"), FileCount); - IndexDefined = ParseNumber32(item.GetPropVal("INDEX"), Index); -} - -void CWimXml::ToUnicode(UString &s) -{ - size_t size = Data.Size(); - if (size < 2 || (size & 1) != 0 || size > (1 << 24)) - return; - const Byte *p = Data; - if (Get16(p) != 0xFEFF) - return; - wchar_t *chars = s.GetBuf((unsigned)(size / 2)); - for (size_t i = 2; i < size; i += 2) - { - wchar_t c = Get16(p + i); - if (c == 0) - break; - *chars++ = c; - } - *chars = 0; - s.ReleaseBuf_SetLen((unsigned)(chars - (const wchar_t *)s)); -} - - -bool CWimXml::Parse() -{ - IsEncrypted = false; - AString utf; - { - UString s; - ToUnicode(s); - // if (!ConvertUnicodeToUTF8(s, utf)) return false; - ConvertUnicodeToUTF8(s, utf); - } - - if (!Xml.Parse(utf)) - return false; - if (Xml.Root.Name != "WIM") - return false; - - FOR_VECTOR (i, Xml.Root.SubItems) - { - const CXmlItem &item = Xml.Root.SubItems[i]; - - if (item.IsTagged("IMAGE")) - { - CImageInfo imageInfo; - imageInfo.Parse(item); - if (!imageInfo.IndexDefined) - return false; - - if (imageInfo.Index != (UInt32)Images.Size() + 1) - { - // old wim (1.09) uses zero based image index - if (imageInfo.Index != (UInt32)Images.Size()) - return false; - } - - imageInfo.ItemIndexInXml = (int)i; - Images.Add(imageInfo); - } - - if (item.IsTagged("ESD")) - { - FOR_VECTOR (k, item.SubItems) - { - const CXmlItem &item2 = item.SubItems[k]; - if (item2.IsTagged("ENCRYPTED")) - IsEncrypted = true; - } - } - } - - return true; -} - -}} +// Archive/WimIn.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/UTFConvert.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/XpressDecoder.h" + +#include "../Common/OutStreamWithSha1.h" + +#include "WimIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +namespace NArchive { +namespace NWim { + +static bool inline GetLog_val_min_dest(const UInt32 val, unsigned i, unsigned &dest) +{ + UInt32 v = (UInt32)1 << i; + for (; i < 32; i++) + { + if (v == val) + { + dest = i; + return true; + } + v += v; + } + return false; +} + + +HRESULT CUnpacker::UnpackChunk( + ISequentialInStream *inStream, + unsigned method, unsigned chunkSizeBits, + size_t inSize, size_t outSize, + ISequentialOutStream *outStream) +{ + if (inSize == outSize) + { + } + else if (method == NMethod::kXPRESS) + { + } + else if (method == NMethod::kLZX) + { + lzxDecoder.Create_if_Empty(); + lzxDecoder->Set_WimMode(true); + } + else if (method == NMethod::kLZMS) + { + lzmsDecoder.Create_if_Empty(); + } + else + return E_NOTIMPL; + + const size_t chunkSize = (size_t)1 << chunkSizeBits; + + { + const unsigned + kAdditionalOutputBufSize = MyMax(NCompress::NLzx:: + kAdditionalOutputBufSize, NCompress::NXpress:: + kAdditionalOutputBufSize); + unpackBuf.EnsureCapacity(chunkSize + kAdditionalOutputBufSize); + if (!unpackBuf.Data) + return E_OUTOFMEMORY; + } + + HRESULT res = S_FALSE; + size_t unpackedSize = 0; + + if (inSize == outSize) + { + unpackedSize = outSize; + res = ReadStream(inStream, unpackBuf.Data, &unpackedSize); + TotalPacked += unpackedSize; + } + else if (inSize < chunkSize) + { + const unsigned kAdditionalInputSize = 32; + packBuf.EnsureCapacity(chunkSize + kAdditionalInputSize); + if (!packBuf.Data) + return E_OUTOFMEMORY; + + RINOK(ReadStream_FALSE(inStream, packBuf.Data, inSize)) + memset(packBuf.Data + inSize, 0xff, kAdditionalInputSize); + + TotalPacked += inSize; + + if (method == NMethod::kXPRESS) + { + res = NCompress::NXpress::Decode_WithExceedWrite(packBuf.Data, inSize, unpackBuf.Data, outSize); + if (res == S_OK) + unpackedSize = outSize; + } + else if (method == NMethod::kLZX) + { + res = lzxDecoder->Set_ExternalWindow_DictBits(unpackBuf.Data, chunkSizeBits); + if (res != S_OK) + return E_NOTIMPL; + lzxDecoder->Set_KeepHistoryForNext(false); + lzxDecoder->Set_KeepHistory(false); + res = lzxDecoder->Code_WithExceedReadWrite(packBuf.Data, inSize, (UInt32)outSize); + unpackedSize = lzxDecoder->GetUnpackSize(); + if (res == S_OK && !lzxDecoder->WasBlockFinished()) + res = S_FALSE; + } + else + { + res = lzmsDecoder->Code(packBuf.Data, inSize, unpackBuf.Data, outSize); + unpackedSize = lzmsDecoder->GetUnpackSize(); + } + } + + if (unpackedSize != outSize) + { + if (res == S_OK) + res = S_FALSE; + + if (unpackedSize > outSize) + res = S_FALSE; + else + memset(unpackBuf.Data + unpackedSize, 0, outSize - unpackedSize); + } + + if (outStream) + { + RINOK(WriteStream(outStream, unpackBuf.Data, outSize)) + } + + return res; +} + + +HRESULT CUnpacker::Unpack2( + IInStream *inStream, + const CResource &resource, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress) +{ + if (!resource.IsCompressed() && !resource.IsSolid()) + { + copyCoder.Create_if_Empty(); + + CMyComPtr2_Create limitedStream; + limitedStream->SetStream(inStream); + + RINOK(InStream_SeekSet(inStream, resource.Offset)) + if (resource.PackSize != resource.UnpackSize) + return S_FALSE; + + limitedStream->Init(resource.PackSize); + TotalPacked += resource.PackSize; + + HRESULT res = copyCoder.Interface()->Code(limitedStream, outStream, NULL, NULL, progress); + + if (res == S_OK && copyCoder->TotalSize != resource.UnpackSize) + res = S_FALSE; + return res; + } + + if (resource.IsSolid()) + { + if (!db || resource.SolidIndex < 0) + return E_NOTIMPL; + if (resource.IsCompressed()) + return E_NOTIMPL; + + const CSolid &ss = db->Solids[resource.SolidIndex]; + + const unsigned chunkSizeBits = ss.ChunkSizeBits; + const size_t chunkSize = (size_t)1 << chunkSizeBits; + + size_t chunkIndex = 0; + UInt64 rem = ss.UnpackSize; + size_t offsetInChunk = 0; + + if (resource.IsSolidSmall()) + { + UInt64 offs = resource.Offset; + if (offs < ss.SolidOffset) + return E_NOTIMPL; + offs -= ss.SolidOffset; + if (offs > ss.UnpackSize) + return E_NOTIMPL; + rem = resource.PackSize; + if (rem > ss.UnpackSize - offs) + return E_NOTIMPL; + chunkIndex = (size_t)(offs >> chunkSizeBits); + offsetInChunk = (size_t)offs & (chunkSize - 1); + } + + UInt64 packProcessed = 0; + UInt64 outProcessed = 0; + + if (_solidIndex == resource.SolidIndex && _unpackedChunkIndex == chunkIndex) + { + size_t cur = chunkSize - offsetInChunk; + if (cur > rem) + cur = (size_t)rem; + RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur)) + outProcessed += cur; + rem -= cur; + offsetInChunk = 0; + chunkIndex++; + } + + for (;;) + { + if (rem == 0) + return S_OK; + + const UInt64 offset = ss.Chunks[chunkIndex]; + const UInt64 packSize = ss.GetChunkPackSize(chunkIndex); + const CResource &rs = db->DataStreams[ss.StreamIndex].Resource; + RINOK(InStream_SeekSet(inStream, rs.Offset + ss.HeadersSize + offset)) + + size_t cur = chunkSize; + const UInt64 unpackRem = ss.UnpackSize - ((UInt64)chunkIndex << chunkSizeBits); + if (cur > unpackRem) + cur = (size_t)unpackRem; + + _solidIndex = -1; + _unpackedChunkIndex = 0; + + const HRESULT res = UnpackChunk(inStream, (unsigned)ss.Method, chunkSizeBits, (size_t)packSize, cur, NULL); + + if (res != S_OK) + { + // We ignore data errors in solid stream. SHA will show what files are bad. + if (res != S_FALSE) + return res; + } + + _solidIndex = resource.SolidIndex; + _unpackedChunkIndex = chunkIndex; + + if (cur < offsetInChunk) + return E_FAIL; + + cur -= offsetInChunk; + + if (cur > rem) + cur = (size_t)rem; + + RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur)) + + if (progress) + { + RINOK(progress->SetRatioInfo(&packProcessed, &outProcessed)) + packProcessed += packSize; + outProcessed += cur; + } + + rem -= cur; + offsetInChunk = 0; + chunkIndex++; + } + } + + + // ---------- NON Solid ---------- + + const UInt64 unpackSize = resource.UnpackSize; + if (unpackSize == 0) + { + if (resource.PackSize == 0) + return S_OK; + return S_FALSE; + } + + if (unpackSize > ((UInt64)1 << 63)) + return E_NOTIMPL; + + const unsigned chunkSizeBits = header.ChunkSizeBits; + const unsigned entrySizeShifts = (resource.UnpackSize < ((UInt64)1 << 32) ? 2 : 3); + + UInt64 baseOffset = resource.Offset; + UInt64 packDataSize; + size_t numChunks; + { + const UInt64 numChunks64 = (unpackSize + (((UInt32)1 << chunkSizeBits) - 1)) >> chunkSizeBits; + const UInt64 sizesBufSize64 = (numChunks64 - 1) << entrySizeShifts; + if (sizesBufSize64 > resource.PackSize) + return S_FALSE; + packDataSize = resource.PackSize - sizesBufSize64; + const size_t sizesBufSize = (size_t)sizesBufSize64; + if (sizesBufSize != sizesBufSize64) + return E_OUTOFMEMORY; + sizesBuf.AllocAtLeast(sizesBufSize); + RINOK(InStream_SeekSet(inStream, baseOffset)) + RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize)) + baseOffset += sizesBufSize64; + numChunks = (size_t)numChunks64; + } + + _solidIndex = -1; + _unpackedChunkIndex = 0; + + UInt64 outProcessed = 0; + UInt64 offset = 0; + + for (size_t i = 0; i < numChunks; i++) + { + UInt64 nextOffset = packDataSize; + + if (i + 1 < numChunks) + { + const Byte *p = (const Byte *)sizesBuf + (i << entrySizeShifts); + nextOffset = (entrySizeShifts == 2) ? Get32(p): Get64(p); + } + + if (nextOffset < offset) + return S_FALSE; + + UInt64 inSize64 = nextOffset - offset; + size_t inSize = (size_t)inSize64; + if (inSize != inSize64) + return S_FALSE; + + RINOK(InStream_SeekSet(inStream, baseOffset + offset)) + + if (progress) + { + RINOK(progress->SetRatioInfo(&offset, &outProcessed)) + } + + size_t outSize = (size_t)1 << chunkSizeBits; + const UInt64 rem = unpackSize - outProcessed; + if (outSize > rem) + outSize = (size_t)rem; + + RINOK(UnpackChunk(inStream, header.GetMethod(), chunkSizeBits, inSize, outSize, outStream)) + + outProcessed += outSize; + offset = nextOffset; + } + + return S_OK; +} + + +HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, const CHeader &header, const CDatabase *db, + ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest) +{ + CMyComPtr2_Create shaStream; + // outStream can be NULL, so we use COutStreamWithSha1 even if sha1 is not required + shaStream->SetStream(outStream); + shaStream->Init(digest != NULL); + const HRESULT res = Unpack2(inStream, resource, header, db, shaStream, progress); + if (digest) + shaStream->Final(digest); + return res; +} + + +HRESULT CUnpacker::UnpackData(IInStream *inStream, + const CResource &resource, const CHeader &header, + const CDatabase *db, + CByteBuffer &buf, Byte *digest) +{ + // if (resource.IsSolid()) return E_NOTIMPL; + UInt64 unpackSize64 = resource.UnpackSize; + if (db) + unpackSize64 = db->Get_UnpackSize_of_Resource(resource); + const size_t size = (size_t)unpackSize64; + if (size != unpackSize64) + return E_OUTOFMEMORY; + buf.Alloc(size); + + CMyComPtr2_Create outStream; + outStream->Init((Byte *)buf, size); + return Unpack(inStream, resource, header, db, outStream, NULL, digest); +} + + +void CResource::Parse(const Byte *p) +{ + Flags = p[7]; + PackSize = Get64(p) & (((UInt64)1 << 56) - 1); + Offset = Get64(p + 8); + UnpackSize = Get64(p + 16); + KeepSolid = false; + SolidIndex = -1; +} + +#define GET_RESOURCE(_p_, res) res.ParseAndUpdatePhySize(_p_, phySize) + +static inline void ParseStream(bool oldVersion, const Byte *p, CStreamInfo &s) +{ + s.Resource.Parse(p); + if (oldVersion) + { + s.PartNumber = 1; + s.Id = Get32(p + 24); + p += 28; + } + else + { + s.PartNumber = Get16(p + 24); + p += 26; + } + s.RefCount = Get32(p); + memcpy(s.Hash, p + 4, kHashSize); +} + + +#define kLongPath "[LongPath]" + +void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) const +{ + const CItem &item = Items[index]; + const CImage &image = Images[item.ImageIndex]; + if (item.Parent < 0 && image.NumEmptyRootItems != 0) + { + name.Clear(); + return; + } + const Byte *meta = image.Meta + item.Offset + + (IsOldVersion ? kDirRecordSizeOld : kDirRecordSize); + UInt32 fileNameLen = Get16(meta - 2); + UInt32 shortLen = Get16(meta - 4) / 2; + wchar_t *s = name.AllocBstr(shortLen); + if (fileNameLen != 0) + meta += fileNameLen + 2; + for (UInt32 i = 0; i < shortLen; i++) + s[i] = Get16(meta + i * 2); + s[shortLen] = 0; + // empty shortName has no ZERO at the end ? +} + + +void CDatabase::GetItemName(unsigned index, NWindows::NCOM::CPropVariant &name) const +{ + const CItem &item = Items[index]; + const CImage &image = Images[item.ImageIndex]; + if (item.Parent < 0 && image.NumEmptyRootItems != 0) + { + name = image.RootName; + return; + } + const Byte *meta = image.Meta + item.Offset + + (item.IsAltStream ? + (IsOldVersion ? 0x10 : 0x24) : + (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2)); + UInt32 len = Get16(meta) / 2; + wchar_t *s = name.AllocBstr(len); + meta += 2; + len++; + for (UInt32 i = 0; i < len; i++) + s[i] = Get16(meta + i * 2); +} + + +void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCOM::CPropVariant &path) const +{ + unsigned size = 0; + int index = (int)index1; + const int imageIndex = Items[index].ImageIndex; + const CImage &image = Images[imageIndex]; + + unsigned newLevel = 0; + bool needColon = false; + + for (;;) + { + const CItem &item = Items[index]; + index = item.Parent; + if (index >= 0 || image.NumEmptyRootItems == 0) + { + const Byte *meta = image.Meta + item.Offset; + meta += item.IsAltStream ? + (IsOldVersion ? 0x10 : 0x24) : + (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); + needColon = item.IsAltStream; + size += Get16(meta) / 2; + size += newLevel; + newLevel = 1; + if (size >= ((UInt32)1 << 15)) + { + path = kLongPath; + return; + } + } + if (index < 0) + break; + } + + if (showImageNumber) + { + size += image.RootName.Len(); + size += newLevel; + } + else if (needColon) + size++; + + wchar_t *s = path.AllocBstr(size); + s[size] = 0; + + if (showImageNumber) + { + MyStringCopy(s, (const wchar_t *)image.RootName); + if (newLevel) + s[image.RootName.Len()] = (wchar_t)(needColon ? L':' : WCHAR_PATH_SEPARATOR); + } + else if (needColon) + s[0] = L':'; + + index = (int)index1; + wchar_t separator = 0; + + for (;;) + { + const CItem &item = Items[index]; + index = item.Parent; + if (index >= 0 || image.NumEmptyRootItems == 0) + { + if (separator != 0) + s[--size] = separator; + const Byte *meta = image.Meta + item.Offset; + meta += (item.IsAltStream) ? + (IsOldVersion ? 0x10: 0x24) : + (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2); + unsigned len = Get16(meta) / 2; + size -= len; + wchar_t *dest = s + size; + meta += 2; + for (unsigned i = 0; i < len; i++) + { + wchar_t c = Get16(meta + i * 2); + if (c == L'/') + c = L'_'; + #if WCHAR_PATH_SEPARATOR != L'/' + else if (c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme + #endif + dest[i] = c; + } + } + if (index < 0) + return; + separator = item.IsAltStream ? L':' : WCHAR_PATH_SEPARATOR; + } +} + + +// if (ver <= 1.10), root folder contains real items. +// if (ver >= 1.12), root folder contains only one folder with empty name. + +HRESULT CDatabase::ParseDirItem(size_t pos, int parent) +{ + const unsigned align = GetDirAlignMask(); + if ((pos & align) != 0) + return S_FALSE; + + for (unsigned numItems = 0;; numItems++) + { + if (OpenCallback && (Items.Size() & 0xFFFF) == 0) + { + UInt64 numFiles = Items.Size(); + RINOK(OpenCallback->SetCompleted(&numFiles, NULL)) + } + + const size_t rem = DirSize - pos; + if (pos < DirStartOffset || pos > DirSize || rem < 8) + return S_FALSE; + + const Byte *p = DirData + pos; + + UInt64 len = Get64(p); + if (len == 0) + { + DirProcessed += 8; + return S_OK; + } + + if ((len & align) != 0 || rem < len) + return S_FALSE; + + DirProcessed += (size_t)len; + if (DirProcessed > DirSize) + return S_FALSE; + + const unsigned dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; + if (len < dirRecordSize) + return S_FALSE; + + CItem item; + UInt32 attrib = Get32(p + 8); + item.IsDir = ((attrib & 0x10) != 0); + UInt64 subdirOffset = Get64(p + 0x10); + + const UInt32 numAltStreams = Get16(p + dirRecordSize - 6); + const UInt32 shortNameLen = Get16(p + dirRecordSize - 4); + const UInt32 fileNameLen = Get16(p + dirRecordSize - 2); + if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0) + return S_FALSE; + const UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2); + const UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2); + if (((dirRecordSize + fileNameLen2 + shortNameLen2 + align) & ~align) > len) + return S_FALSE; + + p += dirRecordSize; + + { + if (*(const UInt16 *)(const void *)(p + fileNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < fileNameLen; j += 2) + if (*(const UInt16 *)(const void *)(p + j) == 0) + return S_FALSE; + } + + // PRF(printf("\n%S", p)); + + if (shortNameLen != 0) + { + // empty shortName has no ZERO at the end ? + const Byte *p2 = p + fileNameLen2; + if (*(const UInt16 *)(const void *)(p2 + shortNameLen) != 0) + return S_FALSE; + for (UInt32 j = 0; j < shortNameLen; j += 2) + if (*(const UInt16 *)(const void *)(p2 + j) == 0) + return S_FALSE; + } + + item.Offset = pos; + item.Parent = parent; + item.ImageIndex = (int)Images.Size() - 1; + + const unsigned prevIndex = Items.Add(item); + + pos += (size_t)len; + + for (UInt32 i = 0; i < numAltStreams; i++) + { + const size_t rem2 = DirSize - pos; + if (pos < DirStartOffset || pos > DirSize || rem2 < 8) + return S_FALSE; + const Byte *p2 = DirData + pos; + const UInt64 len2 = Get64(p2); + if ((len2 & align) != 0 || rem2 < len2 + || len2 < (unsigned)(IsOldVersion ? 0x18 : 0x28)) + return S_FALSE; + + DirProcessed += (size_t)len2; + if (DirProcessed > DirSize) + return S_FALSE; + + unsigned extraOffset = 0; + + if (IsOldVersion) + extraOffset = 0x10; + else + { + if (Get64(p2 + 8) != 0) + return S_FALSE; + extraOffset = 0x24; + } + + const UInt32 fileNameLen111 = Get16(p2 + extraOffset); + if ((fileNameLen111 & 1) != 0) + return S_FALSE; + /* Probably different versions of ImageX can use different number of + additional ZEROs. So we don't use exact check. */ + const UInt32 fileNameLen222 = (fileNameLen111 == 0 ? fileNameLen111 : fileNameLen111 + 2); + if (((extraOffset + 2 + fileNameLen222 + align) & ~align) > len2) + return S_FALSE; + + { + const Byte *p3 = p2 + extraOffset + 2; + if (*(const UInt16 *)(const void *)(p3 + fileNameLen111) != 0) + return S_FALSE; + for (UInt32 j = 0; j < fileNameLen111; j += 2) + if (*(const UInt16 *)(const void *)(p3 + j) == 0) + return S_FALSE; + + // PRF(printf("\n %S", p3)); + } + + + /* wim uses alt sreams list, if there is at least one alt stream. + And alt stream without name is main stream. */ + + // Why wimlib writes two alt streams for REPARSE_POINT, with empty second alt stream? + + Byte *prevMeta = DirData + item.Offset; + + if (fileNameLen111 == 0 && + ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) || !item.IsDir) + && (IsOldVersion || IsEmptySha(prevMeta + 0x40))) + { + if (IsOldVersion) + memcpy(prevMeta + 0x10, p2 + 8, 4); // It's 32-bit Id + else if (!IsEmptySha(p2 + 0x10)) + { + // if (IsEmptySha(prevMeta + 0x40)) + memcpy(prevMeta + 0x40, p2 + 0x10, kHashSize); + // else HeadersError = true; + } + } + else + { + ThereAreAltStreams = true; + CItem item2; + item2.Offset = pos; + item2.IsAltStream = true; + item2.Parent = (int)prevIndex; + item2.ImageIndex = (int)Images.Size() - 1; + Items.Add(item2); + } + + pos += (size_t)len2; + } + + if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir) + { + const Byte *p2 = DirData + pos; + if (DirSize - pos >= 8 && Get64(p2) == 0) + { + CImage &image = Images.Back(); + image.NumEmptyRootItems = 1; + + if (subdirOffset != 0 + && DirSize - pos >= 16 + && Get64(p2 + 8) != 0 + && pos + 8 < subdirOffset) + { + // Longhorn.4093 contains hidden files after empty root folder and before items of next folder. Why? + // That code shows them. If we want to ignore them, we need to update DirProcessed. + // DirProcessed += (size_t)(subdirOffset - (pos + 8)); + // printf("\ndirOffset = %5d hiddenOffset = %5d\n", (int)subdirOffset, (int)pos + 8); + subdirOffset = pos + 8; + // return S_FALSE; + } + } + } + + if (item.IsDir && subdirOffset != 0) + { + RINOK(ParseDirItem((size_t)subdirOffset, (int)prevIndex)) + } + } +} + + +HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent) +{ + DirData = buf; + DirSize = buf.Size(); + if (DirSize < 8) + return S_FALSE; + const Byte *p = DirData; + size_t pos = 0; + CImage &image = Images.Back(); + + if (IsOldVersion) + { + UInt32 numEntries = Get32(p + 4); + + if (numEntries > (1 << 28) || + numEntries > (DirSize >> 3)) + return S_FALSE; + + UInt32 sum = 8; + if (numEntries != 0) + sum = numEntries * 8; + + image.SecurOffsets.ClearAndReserve(numEntries + 1); + image.SecurOffsets.AddInReserved(sum); + + for (UInt32 i = 0; i < numEntries; i++) + { + const Byte *pp = p + (size_t)i * 8; + UInt32 len = Get32(pp); + if (i != 0 && Get32(pp + 4) != 0) + return S_FALSE; + if (len > DirSize - sum) + return S_FALSE; + sum += len; + if (sum < len) + return S_FALSE; + image.SecurOffsets.AddInReserved(sum); + } + + pos = sum; + + const size_t align = GetDirAlignMask(); + pos = (pos + align) & ~(size_t)align; + } + else + { + UInt32 totalLen = Get32(p); + if (totalLen == 0) + pos = 8; + else + { + if (totalLen < 8) + return S_FALSE; + UInt32 numEntries = Get32(p + 4); + pos = 8; + if (totalLen > DirSize || numEntries > ((totalLen - 8) >> 3)) + return S_FALSE; + UInt32 sum = (UInt32)pos + numEntries * 8; + image.SecurOffsets.ClearAndReserve(numEntries + 1); + image.SecurOffsets.AddInReserved(sum); + + for (UInt32 i = 0; i < numEntries; i++, pos += 8) + { + UInt64 len = Get64(p + pos); + if (len > totalLen - sum) + return S_FALSE; + sum += (UInt32)len; + image.SecurOffsets.AddInReserved(sum); + } + + pos = sum; + pos = (pos + 7) & ~(size_t)7; + if (pos != (((size_t)totalLen + 7) & ~(size_t)7)) + return S_FALSE; + } + } + + if (pos > DirSize) + return S_FALSE; + + DirStartOffset = DirProcessed = pos; + image.StartItem = Items.Size(); + + RINOK(ParseDirItem(pos, parent)) + + image.NumItems = Items.Size() - image.StartItem; + if (DirProcessed == DirSize) + return S_OK; + + /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER), + but the reference to that folder is empty */ + + // we can't use DirProcessed - DirStartOffset == 112 check if there is alt stream in root + if (DirProcessed == DirSize - 8 && Get64(p + DirSize - 8) != 0) + return S_OK; + + // 18.06: we support cases, when some old dism can capture images + // where DirProcessed much smaller than DirSize + HeadersError = true; + return S_OK; + // return S_FALSE; +} + + +HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize) +{ + UInt32 headerSize = Get32(p + 8); + phySize = headerSize; + Version = Get32(p + 0x0C); + Flags = Get32(p + 0x10); + if (!IsSupported()) + return S_FALSE; + + { + ChunkSize = Get32(p + 0x14); + ChunkSizeBits = kChunkSizeBits; + if (ChunkSize != 0) + { + if (!GetLog_val_min_dest(ChunkSize, 12, ChunkSizeBits)) + return S_FALSE; + } + } + + _isOldVersion = false; + _isNewVersion = false; + + if (IsSolidVersion()) + _isNewVersion = true; + else + { + if (Version < 0x010900) + return S_FALSE; + _isOldVersion = (Version <= 0x010A00); + // We don't know details about 1.11 version. So we use headerSize to guess exact features. + if (Version == 0x010B00 && headerSize == 0x60) + _isOldVersion = true; + _isNewVersion = (Version >= 0x010D00); + } + + unsigned offset; + + if (IsOldVersion()) + { + if (headerSize != 0x60) + return S_FALSE; + memset(Guid, 0, 16); + offset = 0x18; + PartNumber = 1; + NumParts = 1; + } + else + { + if (headerSize < 0x74) + return S_FALSE; + memcpy(Guid, p + 0x18, 16); + PartNumber = Get16(p + 0x28); + NumParts = Get16(p + 0x2A); + if (PartNumber == 0 || PartNumber > NumParts) + return S_FALSE; + offset = 0x2C; + if (IsNewVersion()) + { + // if (headerSize < 0xD0) + if (headerSize != 0xD0) + return S_FALSE; + NumImages = Get32(p + offset); + offset += 4; + } + } + + GET_RESOURCE(p + offset , OffsetResource); + GET_RESOURCE(p + offset + 0x18, XmlResource); + GET_RESOURCE(p + offset + 0x30, MetadataResource); + BootIndex = 0; + + if (IsNewVersion()) + { + BootIndex = Get32(p + offset + 0x48); + GET_RESOURCE(p + offset + 0x4C, IntegrityResource); + } + + return S_OK; +} + + +const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }; + +HRESULT ReadHeader(IInStream *inStream, CHeader &h, UInt64 &phySize) +{ + Byte p[kHeaderSizeMax]; + RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax)) + if (memcmp(p, kSignature, kSignatureSize) != 0) + return S_FALSE; + return h.Parse(p, phySize); +} + + +static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db) +{ + CByteBuffer offsetBuf; + + CUnpacker unpacker; + RINOK(unpacker.UnpackData(inStream, h.OffsetResource, h, NULL, offsetBuf, NULL)) + + const size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize; + { + const unsigned numItems = (unsigned)(offsetBuf.Size() / streamInfoSize); + if ((size_t)numItems * streamInfoSize != offsetBuf.Size()) + return S_FALSE; + const unsigned numItems2 = db.DataStreams.Size() + numItems; + if (numItems2 < numItems) + return S_FALSE; + db.DataStreams.Reserve(numItems2); + } + + bool keepSolid = false; + + for (size_t i = 0; i < offsetBuf.Size(); i += streamInfoSize) + { + CStreamInfo s; + ParseStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s); + + PRF(printf("\n")); + PRF(printf(s.Resource.IsMetadata() ? "### META" : " DATA")); + PRF(printf(" %2X", s.Resource.Flags)); + PRF(printf(" %9I64X", s.Resource.Offset)); + PRF(printf(" %9I64X", s.Resource.PackSize)); + PRF(printf(" %9I64X", s.Resource.UnpackSize)); + PRF(printf(" %d", s.RefCount)); + + if (s.PartNumber != h.PartNumber) + continue; + + if (s.Resource.IsSolid()) + { + s.Resource.KeepSolid = keepSolid; + keepSolid = true; + } + else + { + s.Resource.KeepSolid = false; + keepSolid = false; + } + + if (!s.Resource.IsMetadata()) + db.DataStreams.AddInReserved(s); + else + { + if (s.Resource.IsSolid()) + return E_NOTIMPL; + if (s.RefCount == 0) + { + // some wims have such (deleted?) metadata stream. + // examples: boot.wim in VistaBeta2, WinPE.wim from WAIK. + // db.DataStreams.Add(s); + // we can show these delete images, if we comment "continue" command; + continue; + } + + if (s.RefCount > 1) + { + return S_FALSE; + // s.RefCount--; + // db.DataStreams.Add(s); + } + + db.MetaStreams.Add(s); + } + } + + PRF(printf("\n")); + + return S_OK; +} + + +HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml) +{ + CUnpacker unpacker; + return unpacker.UnpackData(inStream, h.XmlResource, h, this, xml, NULL); +} + +static void SetRootNames(CImage &image, unsigned value) +{ + wchar_t temp[16]; + ConvertUInt32ToString(value, temp); + image.RootName = temp; + image.RootNameBuf.Alloc(image.RootName.Len() * 2 + 2); + Byte *p = image.RootNameBuf; + unsigned len = image.RootName.Len() + 1; + for (unsigned k = 0; k < len; k++) + { + p[k * 2] = (Byte)temp[k]; + p[k * 2 + 1] = 0; + } +} + + +HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback) +{ + OpenCallback = openCallback; + IsOldVersion = h.IsOldVersion(); + IsOldVersion9 = (h.Version == 0x10900); + + RINOK(ReadStreams(inStream, h, *this)) + + bool needBootMetadata = !h.MetadataResource.IsEmpty(); + unsigned numNonDeletedImages = 0; + + CUnpacker unpacker; + + FOR_VECTOR (i, MetaStreams) + { + const CStreamInfo &si = MetaStreams[i]; + + if (h.PartNumber != 1 || si.PartNumber != h.PartNumber) + continue; + + const unsigned userImage = Images.Size() + GetStartImageIndex(); + CImage &image = Images.AddNew(); + SetRootNames(image, userImage); + + CByteBuffer &metadata = image.Meta; + Byte hash[kHashSize]; + + RINOK(unpacker.UnpackData(inStream, si.Resource, h, this, metadata, hash)) + + if (memcmp(hash, si.Hash, kHashSize) != 0 && + !(h.IsOldVersion() && IsEmptySha(si.Hash))) + return S_FALSE; + + image.NumEmptyRootItems = 0; + + if (Items.IsEmpty()) + Items.ClearAndReserve(numItemsReserve); + + RINOK(ParseImageDirs(metadata, -1)) + + if (needBootMetadata) + { + bool sameRes = (h.MetadataResource.Offset == si.Resource.Offset); + if (sameRes) + needBootMetadata = false; + if (h.IsNewVersion()) + { + if (si.RefCount == 1) + { + numNonDeletedImages++; + bool isBootIndex = (h.BootIndex == numNonDeletedImages); + if (sameRes && !isBootIndex) + return S_FALSE; + if (isBootIndex && !sameRes) + return S_FALSE; + } + } + } + } + + if (needBootMetadata) + return S_FALSE; + return S_OK; +} + + +bool CDatabase::ItemHasStream(const CItem &item) const +{ + if (item.ImageIndex < 0) + return true; + const Byte *meta = Images[item.ImageIndex].Meta + item.Offset; + if (IsOldVersion) + { + // old wim use same field for file_id and dir_offset; + if (item.IsDir) + return false; + meta += (item.IsAltStream ? 0x8 : 0x10); + UInt32 id = GetUi32(meta); + return id != 0; + } + meta += (item.IsAltStream ? 0x10 : 0x40); + return !IsEmptySha(meta); +} + + +#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; } + +static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */) +{ + RINOZ(MyCompare(p1->PartNumber, p2->PartNumber)) + RINOZ(MyCompare(p1->Resource.Offset, p2->Resource.Offset)) + return MyCompare(p1->Resource.PackSize, p2->Resource.PackSize); +} + +static int CompareIDs(const unsigned *p1, const unsigned *p2, void *param) +{ + const CStreamInfo *streams = (const CStreamInfo *)param; + return MyCompare(streams[*p1].Id, streams[*p2].Id); +} + +static int CompareHashRefs(const unsigned *p1, const unsigned *p2, void *param) +{ + const CStreamInfo *streams = (const CStreamInfo *)param; + return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize); +} + +static int FindId(const CStreamInfo *streams, const CUIntVector &sorted, UInt32 id) +{ + unsigned left = 0, right = sorted.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const unsigned streamIndex = sorted[mid]; + const UInt32 id2 = streams[streamIndex].Id; + if (id == id2) + return (int)streamIndex; + if (id < id2) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int FindHash(const CStreamInfo *streams, const CUIntVector &sorted, const Byte *hash) +{ + unsigned left = 0, right = sorted.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const unsigned streamIndex = sorted[mid]; + const Byte *hash2 = streams[streamIndex].Hash; + unsigned i; + for (i = 0; i < kHashSize; i++) + if (hash[i] != hash2[i]) + break; + if (i == kHashSize) + return (int)streamIndex; + if (hash[i] < hash2[i]) + right = mid; + else + left = mid + 1; + } + return -1; +} + +static int CompareItems(const unsigned *a1, const unsigned *a2, void *param) +{ + const CRecordVector &items = ((CDatabase *)param)->Items; + const CItem &i1 = items[*a1]; + const CItem &i2 = items[*a2]; + + if (i1.IsDir != i2.IsDir) + return i1.IsDir ? -1 : 1; + if (i1.IsAltStream != i2.IsAltStream) + return i1.IsAltStream ? 1 : -1; + RINOZ(MyCompare(i1.StreamIndex, i2.StreamIndex)) + RINOZ(MyCompare(i1.ImageIndex, i2.ImageIndex)) + return MyCompare(i1.Offset, i2.Offset); +} + + +HRESULT CDatabase::FillAndCheck(const CObjectVector &volumes) +{ + CUIntVector sortedByHash; + sortedByHash.Reserve(DataStreams.Size()); + { + CByteBuffer sizesBuf; + + for (unsigned iii = 0; iii < DataStreams.Size();) + { + { + const CResource &r = DataStreams[iii].Resource; + if (!r.IsSolid()) + { + sortedByHash.AddInReserved(iii++); + continue; + } + } + + UInt64 solidRunOffset = 0; + unsigned k; + unsigned numSolidsStart = Solids.Size(); + + for (k = iii; k < DataStreams.Size(); k++) + { + CStreamInfo &si = DataStreams[k]; + CResource &r = si.Resource; + + if (!r.IsSolid()) + break; + if (!r.KeepSolid && k != iii) + break; + + if (r.Flags != NResourceFlags::kSolid) + return S_FALSE; + + if (!r.IsSolidBig()) + continue; + + if (!si.IsEmptyHash()) + return S_FALSE; + if (si.RefCount != 1) + return S_FALSE; + + r.SolidIndex = (int)Solids.Size(); + + CSolid &ss = Solids.AddNew(); + ss.StreamIndex = k; + ss.SolidOffset = solidRunOffset; + { + const size_t kSolidHeaderSize = 8 + 4 + 4; + Byte header[kSolidHeaderSize]; + + if (si.PartNumber >= volumes.Size()) + return S_FALSE; + + const CVolume &vol = volumes[si.PartNumber]; + IInStream *inStream = vol.Stream; + RINOK(InStream_SeekSet(inStream, r.Offset)) + RINOK(ReadStream_FALSE(inStream, (Byte *)header, kSolidHeaderSize)) + + ss.UnpackSize = GetUi64(header); + + if (ss.UnpackSize > ((UInt64)1 << 63)) + return S_FALSE; + + solidRunOffset += ss.UnpackSize; + if (solidRunOffset < ss.UnpackSize) + return S_FALSE; + + const UInt32 solidChunkSize = GetUi32(header + 8); + if (!GetLog_val_min_dest(solidChunkSize, 8, ss.ChunkSizeBits)) + return S_FALSE; + ss.Method = (Int32)GetUi32(header + 12); + + const UInt64 numChunks64 = (ss.UnpackSize + (((UInt32)1 << ss.ChunkSizeBits) - 1)) >> ss.ChunkSizeBits; + const UInt64 sizesBufSize64 = 4 * numChunks64; + ss.HeadersSize = kSolidHeaderSize + sizesBufSize64; + const size_t sizesBufSize = (size_t)sizesBufSize64; + if (sizesBufSize != sizesBufSize64) + return E_OUTOFMEMORY; + sizesBuf.AllocAtLeast(sizesBufSize); + + RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize)) + + const size_t numChunks = (size_t)numChunks64; + ss.Chunks.Alloc(numChunks + 1); + + UInt64 offset = 0; + + size_t c; + for (c = 0; c < numChunks; c++) + { + ss.Chunks[c] = offset; + UInt32 packSize = GetUi32((const Byte *)sizesBuf + c * 4); + offset += packSize; + if (offset < packSize) + return S_FALSE; + } + ss.Chunks[c] = offset; + + if (ss.Chunks[0] != 0) + return S_FALSE; + if (ss.HeadersSize + offset != r.PackSize) + return S_FALSE; + } + } + + unsigned solidLim = k; + + for (k = iii; k < solidLim; k++) + { + CStreamInfo &si = DataStreams[k]; + CResource &r = si.Resource; + + if (!r.IsSolidSmall()) + continue; + + if (si.IsEmptyHash()) + return S_FALSE; + + unsigned solidIndex; + { + UInt64 offset = r.Offset; + for (solidIndex = numSolidsStart;; solidIndex++) + { + if (solidIndex == Solids.Size()) + return S_FALSE; + UInt64 unpackSize = Solids[solidIndex].UnpackSize; + if (offset < unpackSize) + break; + offset -= unpackSize; + } + } + CSolid &ss = Solids[solidIndex]; + if (r.Offset < ss.SolidOffset) + return S_FALSE; + const UInt64 relat = r.Offset - ss.SolidOffset; + if (relat > ss.UnpackSize) + return S_FALSE; + if (r.PackSize > ss.UnpackSize - relat) + return S_FALSE; + r.SolidIndex = (int)solidIndex; + if (ss.FirstSmallStream < 0) + ss.FirstSmallStream = (int)k; + + sortedByHash.AddInReserved(k); + // ss.NumRefs++; + } + + iii = solidLim; + } + } + + if (Solids.IsEmpty()) + { + /* We want to check that streams layout is OK. + So we need resources sorted by offset. + Another code can work with non-sorted streams. + NOTE: all WIM programs probably create wim archives with + sorted data streams. So it doesn't call Sort() here. */ + + { + unsigned i; + for (i = 1; i < DataStreams.Size(); i++) + { + const CStreamInfo &s0 = DataStreams[i - 1]; + const CStreamInfo &s1 = DataStreams[i]; + if (s0.PartNumber < s1.PartNumber) continue; + if (s0.PartNumber > s1.PartNumber) break; + if (s0.Resource.Offset < s1.Resource.Offset) continue; + if (s0.Resource.Offset > s1.Resource.Offset) break; + if (s0.Resource.PackSize > s1.Resource.PackSize) break; + } + + if (i < DataStreams.Size()) + { + // return E_FAIL; + DataStreams.Sort(CompareStreamsByPos, NULL); + } + } + + for (unsigned i = 1; i < DataStreams.Size(); i++) + { + const CStreamInfo &s0 = DataStreams[i - 1]; + const CStreamInfo &s1 = DataStreams[i]; + if (s0.PartNumber == s1.PartNumber) + if (s0.Resource.GetEndLimit() > s1.Resource.Offset) + return S_FALSE; + } + } + + { + { + const CStreamInfo *streams = DataStreams.ConstData(); + + if (IsOldVersion) + { + sortedByHash.Sort(CompareIDs, (void *)streams); + + for (unsigned i = 1; i < sortedByHash.Size(); i++) + if (streams[sortedByHash[i - 1]].Id >= + streams[sortedByHash[i]].Id) + return S_FALSE; + } + else + { + sortedByHash.Sort(CompareHashRefs, (void *)streams); + + if (!sortedByHash.IsEmpty()) + { + if (IsEmptySha(streams[sortedByHash[0]].Hash)) + HeadersError = true; + + for (unsigned i = 1; i < sortedByHash.Size(); i++) + if (memcmp( + streams[sortedByHash[i - 1]].Hash, + streams[sortedByHash[i]].Hash, + kHashSize) >= 0) + return S_FALSE; + } + } + } + + FOR_VECTOR (i, Items) + { + CItem &item = Items[i]; + item.StreamIndex = -1; + const Byte *hash = Images[item.ImageIndex].Meta + item.Offset; + if (IsOldVersion) + { + if (!item.IsDir) + { + hash += (item.IsAltStream ? 0x8 : 0x10); + UInt32 id = GetUi32(hash); + if (id != 0) + item.StreamIndex = FindId(DataStreams.ConstData(), sortedByHash, id); + } + } + /* + else if (item.IsDir) + { + // reparse points can have dirs some dir + } + */ + else + { + hash += (item.IsAltStream ? 0x10 : 0x40); + if (!IsEmptySha(hash)) + { + item.StreamIndex = FindHash(DataStreams.ConstData(), sortedByHash, hash); + } + } + } + } + { + CUIntVector refCounts; + refCounts.ClearAndSetSize(DataStreams.Size()); + unsigned i; + + for (i = 0; i < DataStreams.Size(); i++) + { + UInt32 startVal = 0; + // const CStreamInfo &s = DataStreams[i]; + /* + if (s.Resource.IsMetadata() && s.PartNumber == 1) + startVal = 1; + */ + refCounts[i] = startVal; + } + + for (i = 0; i < Items.Size(); i++) + { + const int streamIndex = Items[i].StreamIndex; + if (streamIndex >= 0) + refCounts[streamIndex]++; + } + + for (i = 0; i < DataStreams.Size(); i++) + { + const CStreamInfo &s = DataStreams[i]; + if (s.RefCount != refCounts[i] + && !s.Resource.IsSolidBig()) + { + /* + printf("\ni=%5d si.Ref=%2d realRefs=%2d size=%8d offset=%8x id=%4d ", + i, s.RefCount, refCounts[i], (unsigned)s.Resource.UnpackSize, (unsigned)s.Resource.Offset, s.Id); + */ + RefCountError = true; + } + + if (refCounts[i] == 0) + { + const CResource &r = DataStreams[i].Resource; + if (!r.IsSolidBig() || Solids[r.SolidIndex].FirstSmallStream < 0) + { + CItem item; + item.Offset = 0; + item.StreamIndex = (int)i; + item.ImageIndex = -1; + Items.Add(item); + ThereAreDeletedStreams = true; + } + } + } + } + + return S_OK; +} + + +HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber) +{ + SortedItems.Clear(); + VirtualRoots.Clear(); + IndexOfUserImage = imageIndex; + NumExcludededItems = 0; + ExludedItem = -1; + + if (Images.Size() != 1 && imageIndex < 0) + showImageNumber = true; + + unsigned startItem = 0; + unsigned endItem = 0; + + if (imageIndex < 0) + { + endItem = Items.Size(); + if (Images.Size() == 1) + { + IndexOfUserImage = 0; + const CImage &image = Images[0]; + if (!showImageNumber) + NumExcludededItems = image.NumEmptyRootItems; + } + } + else if ((unsigned)imageIndex < Images.Size()) + { + const CImage &image = Images[imageIndex]; + startItem = image.StartItem; + endItem = startItem + image.NumItems; + if (!showImageNumber) + NumExcludededItems = image.NumEmptyRootItems; + } + + if (NumExcludededItems != 0) + { + ExludedItem = (int)startItem; + startItem += NumExcludededItems; + } + + unsigned num = endItem - startItem; + SortedItems.ClearAndSetSize(num); + unsigned i; + for (i = 0; i < num; i++) + SortedItems[i] = startItem + i; + + SortedItems.Sort(CompareItems, this); + for (i = 0; i < SortedItems.Size(); i++) + Items[SortedItems[i]].IndexInSorted = (int)i; + + if (showImageNumber) + for (i = 0; i < Images.Size(); i++) + { + CImage &image = Images[i]; + if (image.NumEmptyRootItems != 0) + continue; + image.VirtualRootIndex = (int)VirtualRoots.Size(); + VirtualRoots.Add(i); + } + + return S_OK; +} + + +static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size) +{ + if (v.Size() == size) + return; + v.ClearAndSetSize(size); + int *vals = &v[0]; + for (unsigned i = 0; i < size; i++) + vals[i] = -1; +} + + +HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback) +{ + ItemToReparse.Clear(); + ReparseItems.Clear(); + + // we don't know about Reparse field for OLD WIM format + if (IsOldVersion) + return S_OK; + + CIntVector streamToReparse; + CUnpacker unpacker; + UInt64 totalPackedPrev = 0; + + FOR_VECTOR(indexInSorted, SortedItems) + { + // we use sorted items for faster access + unsigned itemIndex = SortedItems[indexInSorted]; + const CItem &item = Items[itemIndex]; + + if (!item.HasMetadata() || item.IsAltStream) + continue; + + if (item.ImageIndex < 0) + continue; + + const Byte *metadata = Images[item.ImageIndex].Meta + item.Offset; + + const UInt32 attrib = Get32(metadata + 8); + if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) + continue; + + if (item.StreamIndex < 0) + continue; // it's ERROR + + const CStreamInfo &si = DataStreams[item.StreamIndex]; + if (si.Resource.UnpackSize >= (1 << 16)) + continue; // reparse data can not be larger than 64 KB + + IntVector_SetMinusOne_IfNeed(streamToReparse, DataStreams.Size()); + IntVector_SetMinusOne_IfNeed(ItemToReparse, Items.Size()); + + const unsigned offset = 0x58; // we don't know about Reparse field for OLD WIM format + UInt32 tag = Get32(metadata + offset); + int reparseIndex = streamToReparse[item.StreamIndex]; + CByteBuffer buf; + + if (openCallback) + { + if ((unpacker.TotalPacked - totalPackedPrev) >= ((UInt32)1 << 16)) + { + UInt64 numFiles = Items.Size(); + RINOK(openCallback->SetCompleted(&numFiles, &unpacker.TotalPacked)) + totalPackedPrev = unpacker.TotalPacked; + } + } + + if (reparseIndex >= 0) + { + const CByteBuffer &reparse = ReparseItems[reparseIndex]; + if (tag == Get32(reparse)) + { + ItemToReparse[itemIndex] = reparseIndex; + continue; + } + buf = reparse; + // we support that strange and unusual situation with different tags and same reparse data. + } + else + { + /* + if (si.PartNumber >= volumes.Size()) + continue; + */ + const CVolume &vol = volumes[si.PartNumber]; + /* + if (!vol.Stream) + continue; + */ + + Byte digest[kHashSize]; + HRESULT res = unpacker.UnpackData(vol.Stream, si.Resource, vol.Header, this, buf, digest); + + if (res == S_FALSE) + continue; + + RINOK(res) + + if (memcmp(digest, si.Hash, kHashSize) != 0 + // && !(h.IsOldVersion() && IsEmptySha(si.Hash)) + ) + { + // setErrorStatus; + continue; + } + } + + CByteBuffer &reparse = ReparseItems.AddNew(); + reparse.Alloc(8 + buf.Size()); + Byte *dest = (Byte *)reparse; + SetUi32(dest, tag) + SetUi32(dest + 4, (UInt32)buf.Size()) + if (buf.Size() != 0) + memcpy(dest + 8, buf, buf.Size()); + ItemToReparse[itemIndex] = (int)ReparseItems.Size() - 1; + } + + return S_OK; +} + + + +static bool ParseNumber64(const AString &s, UInt64 &res) +{ + const char *end; + if (s.IsPrefixedBy("0x")) + { + if (s.Len() == 2) + return false; + res = ConvertHexStringToUInt64(s.Ptr(2), &end); + } + else + { + if (s.IsEmpty()) + return false; + res = ConvertStringToUInt64(s, &end); + } + return *end == 0; +} + + +static bool ParseNumber32(const AString &s, UInt32 &res) +{ + UInt64 res64; + if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32)) + return false; + res = (UInt32)res64; + return true; +} + + +static bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag) +{ + const CXmlItem *timeItem = item.FindSubTag_GetPtr(tag); + if (timeItem) + { + UInt32 low = 0, high = 0; + if (ParseNumber32(timeItem->GetSubStringForTag("LOWPART"), low) && + ParseNumber32(timeItem->GetSubStringForTag("HIGHPART"), high)) + { + ft.dwLowDateTime = low; + ft.dwHighDateTime = high; + return true; + } + } + return false; +} + + +void CImageInfo::Parse(const CXmlItem &item) +{ + CTimeDefined = ParseTime(item, CTime, "CREATIONTIME"); + MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME"); + NameDefined = true; + ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name); + + ParseNumber64(item.GetSubStringForTag("DIRCOUNT"), DirCount); + ParseNumber64(item.GetSubStringForTag("FILECOUNT"), FileCount); + IndexDefined = ParseNumber32(item.GetPropVal("INDEX"), Index); +} + +void CWimXml::ToUnicode(UString &s) +{ + size_t size = Data.Size(); + if (size < 2 || (size & 1) != 0 || size > (1 << 24)) + return; + const Byte *p = Data; + if (Get16(p) != 0xFEFF) + return; + wchar_t *chars = s.GetBuf((unsigned)(size / 2)); + for (size_t i = 2; i < size; i += 2) + { + wchar_t c = Get16(p + i); + if (c == 0) + break; + *chars++ = c; + } + *chars = 0; + s.ReleaseBuf_SetLen((unsigned)(chars - (const wchar_t *)s)); +} + + +bool CWimXml::Parse() +{ + IsEncrypted = false; + AString utf; + { + UString s; + ToUnicode(s); + // if (!ConvertUnicodeToUTF8(s, utf)) return false; + ConvertUnicodeToUTF8(s, utf); + } + + if (!Xml.Parse(utf)) + return false; + if (Xml.Root.Name != "WIM") + return false; + + FOR_VECTOR (i, Xml.Root.SubItems) + { + const CXmlItem &item = Xml.Root.SubItems[i]; + + if (item.IsTagged("IMAGE")) + { + CImageInfo imageInfo; + imageInfo.Parse(item); + if (!imageInfo.IndexDefined) + return false; + + if (imageInfo.Index != (UInt32)Images.Size() + 1) + { + // old wim (1.09) uses zero based image index + if (imageInfo.Index != (UInt32)Images.Size()) + return false; + } + + imageInfo.ItemIndexInXml = (int)i; + Images.Add(imageInfo); + } + + if (item.IsTagged("ESD")) + { + FOR_VECTOR (k, item.SubItems) + { + const CXmlItem &item2 = item.SubItems[k]; + if (item2.IsTagged("ENCRYPTED")) + IsEncrypted = true; + } + } + } + + return true; +} + +}} diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index e8f64358e..71d0a3afa 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -1,655 +1,655 @@ -// Archive/WimIn.h - -#ifndef ZIP7_INC_ARCHIVE_WIM_IN_H -#define ZIP7_INC_ARCHIVE_WIM_IN_H - -#include "../../../../C/Alloc.h" - -#include "../../../Common/AutoPtr.h" -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyXml.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../Compress/CopyCoder.h" -#include "../../Compress/LzmsDecoder.h" -#include "../../Compress/LzxDecoder.h" - -#include "../IArchive.h" - -namespace NArchive { -namespace NWim { - -/* -WIM versions: -hexVer : headerSize : ver - : 1.07.01 - 1.08.01 : Longhorn.4001-4015 - another header, no signature, CAB compression -10900 : 60 : 1.09 : Longhorn.4029-4039 (2003) -10A00 : 60 : 1.10 : Longhorn.4083 (2004) image starting from 1 -10B00 : ?? : 1.11 : ?? -10C00 : 74 : 1.12 : Longhorn.4093 - VistaBeta1.5112 (2005) - (Multi-Part, SHA1) -10D00 : D0 : 1.13 : VistaBeta2 - Win10, (NumImages, BootIndex, IntegrityResource) -00E00 : D0 : 0.14 : LZMS, solid, esd, dism -*/ - -const unsigned kDirRecordSizeOld = 62; -const unsigned kDirRecordSize = 102; - -/* - There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields. - - Correct DIRENTRY structure: - { - hex offset - 0 UInt64 Len; - 8 UInt32 Attrib; - C UInt32 SecurityId; - - 10 UInt64 SubdirOffset; // = 0 for files - - 18 UInt64 unused1; // = 0? - 20 UInt64 unused2; // = 0? - - 28 UInt64 CTime; - 30 UInt64 ATime; - 38 UInt64 MTime; - - 40 Byte Sha1[20]; - - 54 UInt32 Unknown1; // is it 0 always? - - - union - { - 58 UInt64 NtNodeId; - { - 58 UInt32 ReparseTag; - 5C UInt32 ReparseFlags; // is it 0 always? Check with new imagex. - } - } - - 60 UInt16 Streams; - - 62 UInt16 ShortNameLen; - 64 UInt16 FileNameLen; - - 66 UInt16 Name[]; - UInt16 ShortName[]; - } - - // DIRENTRY for WIM_VERSION <= 1.10 - DIRENTRY_OLD structure: - { - hex offset - 0 UInt64 Len; - 8 UInt32 Attrib; - C UInt32 SecurityId; - - union - { - 10 UInt64 SubdirOffset; // - - 10 UInt32 OldWimFileId; // used for files in old WIMs - 14 UInt32 OldWimFileId_Reserved; // = 0 - } - - 18 UInt64 CTime; - 20 UInt64 ATime; - 28 UInt64 MTime; - - 30 UInt64 Unknown; // NtNodeId ? - - 38 UInt16 Streams; - 3A UInt16 ShortNameLen; - 3C UInt16 FileNameLen; - 3E UInt16 FileName[]; - UInt16 ShortName[]; - } - - ALT_STREAM structure: - { - hex offset - 0 UInt64 Len; - 8 UInt64 Unused; - 10 Byte Sha1[20]; - 24 UInt16 FileNameLen; - 26 UInt16 FileName[]; - } - - ALT_STREAM_OLD structure: - { - hex offset - 0 UInt64 Len; - 8 UInt64 StreamId; // 32-bit value - 10 UInt16 FileNameLen; - 12 UInt16 FileName[]; - } - - If item is file (not Directory) and there are alternative streams, - there is additional ALT_STREAM item of main "unnamed" stream in Streams array. - -*/ - - -namespace NResourceFlags -{ - // const Byte kFree = 1 << 0; - const Byte kMetadata = 1 << 1; - const Byte kCompressed = 1 << 2; - // const Byte kSpanned = 1 << 3; - const Byte kSolid = 1 << 4; -} - -const UInt64 k_SolidBig_Resource_Marker = (UInt64)1 << 32; - -struct CResource -{ - UInt64 PackSize; - UInt64 Offset; - UInt64 UnpackSize; - Byte Flags; - bool KeepSolid; - int SolidIndex; - - void Clear() - { - PackSize = 0; - Offset = 0; - UnpackSize = 0; - Flags = 0; - KeepSolid = false; - SolidIndex = -1; - } - - UInt64 GetEndLimit() const { return Offset + PackSize; } - void Parse(const Byte *p); - void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) - { - Parse(p); - UInt64 v = GetEndLimit(); - if (phySize < v) - phySize = v; - } - - void WriteTo(Byte *p) const; - - bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; } - bool IsCompressed() const { return (Flags & NResourceFlags::kCompressed) != 0; } - bool IsSolid() const { return (Flags & NResourceFlags::kSolid) != 0; } - bool IsSolidBig() const { return IsSolid() && UnpackSize == k_SolidBig_Resource_Marker; } - bool IsSolidSmall() const { return IsSolid() && UnpackSize == 0; } - - bool IsEmpty() const { return (UnpackSize == 0); } -}; - - -struct CSolid -{ - unsigned StreamIndex; - // unsigned NumRefs; - int FirstSmallStream; - - UInt64 SolidOffset; - - UInt64 UnpackSize; - int Method; - unsigned ChunkSizeBits; - - UInt64 HeadersSize; - // size_t NumChunks; - CObjArray Chunks; // [NumChunks + 1] (start offset) - - UInt64 GetChunkPackSize(size_t chunkIndex) const { return Chunks[chunkIndex + 1] - Chunks[chunkIndex]; } - - CSolid(): - FirstSmallStream(-1), - // NumRefs(0), - Method(-1) - {} -}; - - -namespace NHeaderFlags -{ - const UInt32 kCompression = 1 << 1; - const UInt32 kReadOnly = 1 << 2; - const UInt32 kSpanned = 1 << 3; - const UInt32 kResourceOnly = 1 << 4; - const UInt32 kMetadataOnly = 1 << 5; - const UInt32 kWriteInProgress = 1 << 6; - const UInt32 kReparsePointFixup = 1 << 7; - - const UInt32 kXPRESS = (UInt32)1 << 17; - const UInt32 kLZX = (UInt32)1 << 18; - const UInt32 kLZMS = (UInt32)1 << 19; - const UInt32 kXPRESS2 = (UInt32)1 << 21; // XPRESS with nonstandard chunk size ? - - const UInt32 kMethodMask = 0xFFFE0000; -} - - -namespace NMethod -{ - const UInt32 kXPRESS = 1; - const UInt32 kLZX = 2; - const UInt32 kLZMS = 3; -} - - -const UInt32 k_Version_NonSolid = 0x10D00; -const UInt32 k_Version_Solid = 0xE00; - -const unsigned kHeaderSizeMax = 0xD0; -const unsigned kSignatureSize = 8; -extern const Byte kSignature[kSignatureSize]; - -const unsigned kChunkSizeBits = 15; -const UInt32 kChunkSize = (UInt32)1 << kChunkSizeBits; - - -struct CHeader -{ - UInt32 Version; - UInt32 Flags; - UInt32 ChunkSize; - unsigned ChunkSizeBits; - Byte Guid[16]; - UInt16 PartNumber; - UInt16 NumParts; - UInt32 NumImages; - UInt32 BootIndex; - - bool _isOldVersion; // 1.10- - bool _isNewVersion; // 1.13+ or 0.14 - - CResource OffsetResource; - CResource XmlResource; - CResource MetadataResource; - CResource IntegrityResource; - - void SetDefaultFields(bool useLZX); - - void WriteTo(Byte *p) const; - HRESULT Parse(const Byte *p, UInt64 &phySize); - - bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; } - - bool IsSupported() const - { - return (!IsCompressed() - || (Flags & NHeaderFlags::kLZX) != 0 - || (Flags & NHeaderFlags::kXPRESS) != 0 - || (Flags & NHeaderFlags::kLZMS) != 0 - || (Flags & NHeaderFlags::kXPRESS2) != 0); - } - - unsigned GetMethod() const - { - if (!IsCompressed()) - return 0; - UInt32 mask = (Flags & NHeaderFlags::kMethodMask); - if (mask == 0) return 0; - if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS; - if (mask == NHeaderFlags::kLZX) return NMethod::kLZX; - if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS; - if (mask == NHeaderFlags::kXPRESS2) return NMethod::kXPRESS; - return mask; - } - - bool IsOldVersion() const { return _isOldVersion; } - bool IsNewVersion() const { return _isNewVersion; } - bool IsSolidVersion() const { return (Version == k_Version_Solid); } - - bool AreFromOnArchive(const CHeader &h) - { - return (memcmp(Guid, h.Guid, sizeof(Guid)) == 0) && (h.NumParts == NumParts); - } -}; - - -const unsigned kHashSize = 20; - -inline bool IsEmptySha(const Byte *data) -{ - for (unsigned i = 0; i < kHashSize; i++) - if (data[i] != 0) - return false; - return true; -} - -const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize; - -struct CStreamInfo -{ - CResource Resource; - UInt16 PartNumber; // for NEW WIM format, we set it to 1 for OLD WIM format - UInt32 RefCount; - UInt32 Id; // for OLD WIM format - Byte Hash[kHashSize]; - - bool IsEmptyHash() const { return IsEmptySha(Hash); } - - void WriteTo(Byte *p) const; -}; - - -struct CItem -{ - size_t Offset; - int IndexInSorted; - int StreamIndex; - int Parent; - int ImageIndex; // -1 means that file is unreferenced in Images (deleted item?) - bool IsDir; - bool IsAltStream; - - bool HasMetadata() const { return ImageIndex >= 0; } - - CItem(): - IndexInSorted(-1), - StreamIndex(-1), - Parent(-1), - IsDir(false), - IsAltStream(false) - {} -}; - -struct CImage -{ - CByteBuffer Meta; - CRecordVector SecurOffsets; - unsigned StartItem; - unsigned NumItems; - unsigned NumEmptyRootItems; - int VirtualRootIndex; // index in CDatabase::VirtualRoots[] - UString RootName; - CByteBuffer RootNameBuf; - - CImage(): VirtualRootIndex(-1) {} -}; - - -struct CImageInfo -{ - bool CTimeDefined; - bool MTimeDefined; - bool NameDefined; - bool IndexDefined; - - FILETIME CTime; - FILETIME MTime; - UString Name; - - UInt64 DirCount; - UInt64 FileCount; - UInt32 Index; - - int ItemIndexInXml; - - UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; } - - CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false), - IndexDefined(false), ItemIndexInXml(-1) {} - void Parse(const CXmlItem &item); -}; - - -struct CWimXml -{ - CByteBuffer Data; - CXml Xml; - - UInt16 VolIndex; - CObjectVector Images; - - UString FileName; - bool IsEncrypted; - - UInt64 GetTotalFilesAndDirs() const - { - UInt64 sum = 0; - FOR_VECTOR (i, Images) - sum += Images[i].GetTotalFilesAndDirs(); - return sum; - } - - void ToUnicode(UString &s); - bool Parse(); - - CWimXml(): IsEncrypted(false) {} -}; - - -struct CVolume -{ - CHeader Header; - CMyComPtr Stream; -}; - - -class CDatabase -{ - Byte *DirData; - size_t DirSize; - size_t DirProcessed; - size_t DirStartOffset; - IArchiveOpenCallback *OpenCallback; - - HRESULT ParseDirItem(size_t pos, int parent); - HRESULT ParseImageDirs(CByteBuffer &buf, int parent); - -public: - CRecordVector DataStreams; - CRecordVector MetaStreams; - - CObjectVector Solids; - - CRecordVector Items; - CObjectVector ReparseItems; - CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems - // -1 means no reparse; - - CObjectVector Images; - - bool IsOldVersion9; - bool IsOldVersion; - bool ThereAreDeletedStreams; - bool ThereAreAltStreams; - bool RefCountError; - bool HeadersError; - - unsigned GetStartImageIndex() const { return IsOldVersion9 ? 0 : 1; } - unsigned GetDirAlignMask() const { return IsOldVersion9 ? 3 : 7; } - - // User Items can contain all images or just one image from all. - CUIntVector SortedItems; - int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items - - unsigned NumExcludededItems; - int ExludedItem; // -1 : if there are no exclude items - CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives - - bool ThereIsError() const { return RefCountError || HeadersError; } - - unsigned GetNumUserItemsInImage(unsigned imageIndex) const - { - if (IndexOfUserImage >= 0 && imageIndex != (unsigned)IndexOfUserImage) - return 0; - if (imageIndex >= Images.Size()) - return 0; - return Images[imageIndex].NumItems - NumExcludededItems; - } - - bool ItemHasStream(const CItem &item) const; - - UInt64 Get_UnpackSize_of_Resource(const CResource &r) const - { - if (!r.IsSolid()) - return r.UnpackSize; - if (r.IsSolidSmall()) - return r.PackSize; - if (r.IsSolidBig() && r.SolidIndex >= 0) - return Solids[(unsigned)r.SolidIndex].UnpackSize; - return 0; - } - - UInt64 Get_PackSize_of_Resource(unsigned streamIndex) const - { - const CResource &r = DataStreams[streamIndex].Resource; - if (!r.IsSolidSmall()) - return r.PackSize; - if (r.SolidIndex >= 0) - { - const CSolid &ss = Solids[(unsigned)r.SolidIndex]; - if (ss.FirstSmallStream == (int)streamIndex) - return DataStreams[ss.StreamIndex].Resource.PackSize; - } - return 0; - } - - UInt64 GetUnpackSize() const - { - UInt64 res = 0; - FOR_VECTOR (i, DataStreams) - res += DataStreams[i].Resource.UnpackSize; - return res; - } - - UInt64 GetPackSize() const - { - UInt64 res = 0; - FOR_VECTOR (i, DataStreams) - res += DataStreams[i].Resource.PackSize; - return res; - } - - void Clear() - { - DataStreams.Clear(); - MetaStreams.Clear(); - Solids.Clear(); - - Items.Clear(); - ReparseItems.Clear(); - ItemToReparse.Clear(); - - SortedItems.Clear(); - - Images.Clear(); - VirtualRoots.Clear(); - - IsOldVersion = false; - ThereAreDeletedStreams = false; - ThereAreAltStreams = false; - RefCountError = false; - HeadersError = false; - } - - CDatabase(): - RefCountError(false), - HeadersError(false) - {} - - void GetShortName(unsigned index, NWindows::NCOM::CPropVariant &res) const; - void GetItemName(unsigned index1, NWindows::NCOM::CPropVariant &res) const; - void GetItemPath(unsigned index, bool showImageNumber, NWindows::NCOM::CPropVariant &res) const; - - HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml); - HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback); - HRESULT FillAndCheck(const CObjectVector &volumes); - - /* - imageIndex showImageNumber NumImages - * true * Show Image_Number - -1 * >1 Show Image_Number - -1 false 1 Don't show Image_Number - N false * Don't show Image_Number - */ - HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber); - - HRESULT ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback); -}; - -HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize); - - -struct CMidBuf -{ - Byte *Data; - size_t _size; - - CMidBuf(): Data(NULL), _size(0) {} - - void EnsureCapacity(size_t size) - { - if (size > _size) - { - ::z7_AlignedFree(Data); - _size = 0; - Data = (Byte *)::z7_AlignedAlloc(size); - if (Data) - _size = size; - } - } - - ~CMidBuf() { ::z7_AlignedFree(Data); } -}; - - -class CUnpacker -{ - CMyComPtr2 copyCoder; - CMyUniquePtr lzxDecoder; - CMyUniquePtr lzmsDecoder; - - CByteBuffer sizesBuf; - - CMidBuf packBuf; - CMidBuf unpackBuf; - - // solid resource - int _solidIndex; - size_t _unpackedChunkIndex; - - HRESULT UnpackChunk( - ISequentialInStream *inStream, - unsigned method, unsigned chunkSizeBits, - size_t inSize, size_t outSize, - ISequentialOutStream *outStream); - - HRESULT Unpack2( - IInStream *inStream, - const CResource &res, - const CHeader &header, - const CDatabase *db, - ISequentialOutStream *outStream, - ICompressProgressInfo *progress); - -public: - UInt64 TotalPacked; - - CUnpacker(): - lzmsDecoder(NULL), - _solidIndex(-1), - _unpackedChunkIndex(0), - TotalPacked(0) - {} - - HRESULT Unpack( - IInStream *inStream, - const CResource &res, - const CHeader &header, - const CDatabase *db, - ISequentialOutStream *outStream, - ICompressProgressInfo *progress, - Byte *digest); - - HRESULT UnpackData(IInStream *inStream, - const CResource &resource, const CHeader &header, - const CDatabase *db, - CByteBuffer &buf, Byte *digest); -}; - -}} - -#endif +// Archive/WimIn.h + +#ifndef ZIP7_INC_ARCHIVE_WIM_IN_H +#define ZIP7_INC_ARCHIVE_WIM_IN_H + +#include "../../../../C/Alloc.h" + +#include "../../../Common/AutoPtr.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyXml.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Compress/CopyCoder.h" +#include "../../Compress/LzmsDecoder.h" +#include "../../Compress/LzxDecoder.h" + +#include "../IArchive.h" + +namespace NArchive { +namespace NWim { + +/* +WIM versions: +hexVer : headerSize : ver + : 1.07.01 - 1.08.01 : Longhorn.4001-4015 - another header, no signature, CAB compression +10900 : 60 : 1.09 : Longhorn.4029-4039 (2003) +10A00 : 60 : 1.10 : Longhorn.4083 (2004) image starting from 1 +10B00 : ?? : 1.11 : ?? +10C00 : 74 : 1.12 : Longhorn.4093 - VistaBeta1.5112 (2005) - (Multi-Part, SHA1) +10D00 : D0 : 1.13 : VistaBeta2 - Win10, (NumImages, BootIndex, IntegrityResource) +00E00 : D0 : 0.14 : LZMS, solid, esd, dism +*/ + +const unsigned kDirRecordSizeOld = 62; +const unsigned kDirRecordSize = 102; + +/* + There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields. + + Correct DIRENTRY structure: + { + hex offset + 0 UInt64 Len; + 8 UInt32 Attrib; + C UInt32 SecurityId; + + 10 UInt64 SubdirOffset; // = 0 for files + + 18 UInt64 unused1; // = 0? + 20 UInt64 unused2; // = 0? + + 28 UInt64 CTime; + 30 UInt64 ATime; + 38 UInt64 MTime; + + 40 Byte Sha1[20]; + + 54 UInt32 Unknown1; // is it 0 always? + + + union + { + 58 UInt64 NtNodeId; + { + 58 UInt32 ReparseTag; + 5C UInt32 ReparseFlags; // is it 0 always? Check with new imagex. + } + } + + 60 UInt16 Streams; + + 62 UInt16 ShortNameLen; + 64 UInt16 FileNameLen; + + 66 UInt16 Name[]; + UInt16 ShortName[]; + } + + // DIRENTRY for WIM_VERSION <= 1.10 + DIRENTRY_OLD structure: + { + hex offset + 0 UInt64 Len; + 8 UInt32 Attrib; + C UInt32 SecurityId; + + union + { + 10 UInt64 SubdirOffset; // + + 10 UInt32 OldWimFileId; // used for files in old WIMs + 14 UInt32 OldWimFileId_Reserved; // = 0 + } + + 18 UInt64 CTime; + 20 UInt64 ATime; + 28 UInt64 MTime; + + 30 UInt64 Unknown; // NtNodeId ? + + 38 UInt16 Streams; + 3A UInt16 ShortNameLen; + 3C UInt16 FileNameLen; + 3E UInt16 FileName[]; + UInt16 ShortName[]; + } + + ALT_STREAM structure: + { + hex offset + 0 UInt64 Len; + 8 UInt64 Unused; + 10 Byte Sha1[20]; + 24 UInt16 FileNameLen; + 26 UInt16 FileName[]; + } + + ALT_STREAM_OLD structure: + { + hex offset + 0 UInt64 Len; + 8 UInt64 StreamId; // 32-bit value + 10 UInt16 FileNameLen; + 12 UInt16 FileName[]; + } + + If item is file (not Directory) and there are alternative streams, + there is additional ALT_STREAM item of main "unnamed" stream in Streams array. + +*/ + + +namespace NResourceFlags +{ + // const Byte kFree = 1 << 0; + const Byte kMetadata = 1 << 1; + const Byte kCompressed = 1 << 2; + // const Byte kSpanned = 1 << 3; + const Byte kSolid = 1 << 4; +} + +const UInt64 k_SolidBig_Resource_Marker = (UInt64)1 << 32; + +struct CResource +{ + UInt64 PackSize; + UInt64 Offset; + UInt64 UnpackSize; + Byte Flags; + bool KeepSolid; + int SolidIndex; + + void Clear() + { + PackSize = 0; + Offset = 0; + UnpackSize = 0; + Flags = 0; + KeepSolid = false; + SolidIndex = -1; + } + + UInt64 GetEndLimit() const { return Offset + PackSize; } + void Parse(const Byte *p); + void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) + { + Parse(p); + UInt64 v = GetEndLimit(); + if (phySize < v) + phySize = v; + } + + void WriteTo(Byte *p) const; + + bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; } + bool IsCompressed() const { return (Flags & NResourceFlags::kCompressed) != 0; } + bool IsSolid() const { return (Flags & NResourceFlags::kSolid) != 0; } + bool IsSolidBig() const { return IsSolid() && UnpackSize == k_SolidBig_Resource_Marker; } + bool IsSolidSmall() const { return IsSolid() && UnpackSize == 0; } + + bool IsEmpty() const { return (UnpackSize == 0); } +}; + + +struct CSolid +{ + unsigned StreamIndex; + // unsigned NumRefs; + int FirstSmallStream; + + UInt64 SolidOffset; + + UInt64 UnpackSize; + int Method; + unsigned ChunkSizeBits; + + UInt64 HeadersSize; + // size_t NumChunks; + CObjArray Chunks; // [NumChunks + 1] (start offset) + + UInt64 GetChunkPackSize(size_t chunkIndex) const { return Chunks[chunkIndex + 1] - Chunks[chunkIndex]; } + + CSolid(): + FirstSmallStream(-1), + // NumRefs(0), + Method(-1) + {} +}; + + +namespace NHeaderFlags +{ + const UInt32 kCompression = 1 << 1; + const UInt32 kReadOnly = 1 << 2; + const UInt32 kSpanned = 1 << 3; + const UInt32 kResourceOnly = 1 << 4; + const UInt32 kMetadataOnly = 1 << 5; + const UInt32 kWriteInProgress = 1 << 6; + const UInt32 kReparsePointFixup = 1 << 7; + + const UInt32 kXPRESS = (UInt32)1 << 17; + const UInt32 kLZX = (UInt32)1 << 18; + const UInt32 kLZMS = (UInt32)1 << 19; + const UInt32 kXPRESS2 = (UInt32)1 << 21; // XPRESS with nonstandard chunk size ? + + const UInt32 kMethodMask = 0xFFFE0000; +} + + +namespace NMethod +{ + const UInt32 kXPRESS = 1; + const UInt32 kLZX = 2; + const UInt32 kLZMS = 3; +} + + +const UInt32 k_Version_NonSolid = 0x10D00; +const UInt32 k_Version_Solid = 0xE00; + +const unsigned kHeaderSizeMax = 0xD0; +const unsigned kSignatureSize = 8; +extern const Byte kSignature[kSignatureSize]; + +const unsigned kChunkSizeBits = 15; +const UInt32 kChunkSize = (UInt32)1 << kChunkSizeBits; + + +struct CHeader +{ + UInt32 Version; + UInt32 Flags; + UInt32 ChunkSize; + unsigned ChunkSizeBits; + Byte Guid[16]; + UInt16 PartNumber; + UInt16 NumParts; + UInt32 NumImages; + UInt32 BootIndex; + + bool _isOldVersion; // 1.10- + bool _isNewVersion; // 1.13+ or 0.14 + + CResource OffsetResource; + CResource XmlResource; + CResource MetadataResource; + CResource IntegrityResource; + + void SetDefaultFields(bool useLZX); + + void WriteTo(Byte *p) const; + HRESULT Parse(const Byte *p, UInt64 &phySize); + + bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; } + + bool IsSupported() const + { + return (!IsCompressed() + || (Flags & NHeaderFlags::kLZX) != 0 + || (Flags & NHeaderFlags::kXPRESS) != 0 + || (Flags & NHeaderFlags::kLZMS) != 0 + || (Flags & NHeaderFlags::kXPRESS2) != 0); + } + + unsigned GetMethod() const + { + if (!IsCompressed()) + return 0; + UInt32 mask = (Flags & NHeaderFlags::kMethodMask); + if (mask == 0) return 0; + if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS; + if (mask == NHeaderFlags::kLZX) return NMethod::kLZX; + if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS; + if (mask == NHeaderFlags::kXPRESS2) return NMethod::kXPRESS; + return mask; + } + + bool IsOldVersion() const { return _isOldVersion; } + bool IsNewVersion() const { return _isNewVersion; } + bool IsSolidVersion() const { return (Version == k_Version_Solid); } + + bool AreFromOnArchive(const CHeader &h) + { + return (memcmp(Guid, h.Guid, sizeof(Guid)) == 0) && (h.NumParts == NumParts); + } +}; + + +const unsigned kHashSize = 20; + +inline bool IsEmptySha(const Byte *data) +{ + for (unsigned i = 0; i < kHashSize; i++) + if (data[i] != 0) + return false; + return true; +} + +const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize; + +struct CStreamInfo +{ + CResource Resource; + UInt16 PartNumber; // for NEW WIM format, we set it to 1 for OLD WIM format + UInt32 RefCount; + UInt32 Id; // for OLD WIM format + Byte Hash[kHashSize]; + + bool IsEmptyHash() const { return IsEmptySha(Hash); } + + void WriteTo(Byte *p) const; +}; + + +struct CItem +{ + size_t Offset; + int IndexInSorted; + int StreamIndex; + int Parent; + int ImageIndex; // -1 means that file is unreferenced in Images (deleted item?) + bool IsDir; + bool IsAltStream; + + bool HasMetadata() const { return ImageIndex >= 0; } + + CItem(): + IndexInSorted(-1), + StreamIndex(-1), + Parent(-1), + IsDir(false), + IsAltStream(false) + {} +}; + +struct CImage +{ + CByteBuffer Meta; + CRecordVector SecurOffsets; + unsigned StartItem; + unsigned NumItems; + unsigned NumEmptyRootItems; + int VirtualRootIndex; // index in CDatabase::VirtualRoots[] + UString RootName; + CByteBuffer RootNameBuf; + + CImage(): VirtualRootIndex(-1) {} +}; + + +struct CImageInfo +{ + bool CTimeDefined; + bool MTimeDefined; + bool NameDefined; + bool IndexDefined; + + FILETIME CTime; + FILETIME MTime; + UString Name; + + UInt64 DirCount; + UInt64 FileCount; + UInt32 Index; + + int ItemIndexInXml; + + UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; } + + CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false), + IndexDefined(false), ItemIndexInXml(-1) {} + void Parse(const CXmlItem &item); +}; + + +struct CWimXml +{ + CByteBuffer Data; + CXml Xml; + + UInt16 VolIndex; + CObjectVector Images; + + UString FileName; + bool IsEncrypted; + + UInt64 GetTotalFilesAndDirs() const + { + UInt64 sum = 0; + FOR_VECTOR (i, Images) + sum += Images[i].GetTotalFilesAndDirs(); + return sum; + } + + void ToUnicode(UString &s); + bool Parse(); + + CWimXml(): IsEncrypted(false) {} +}; + + +struct CVolume +{ + CHeader Header; + CMyComPtr Stream; +}; + + +class CDatabase +{ + Byte *DirData; + size_t DirSize; + size_t DirProcessed; + size_t DirStartOffset; + IArchiveOpenCallback *OpenCallback; + + HRESULT ParseDirItem(size_t pos, int parent); + HRESULT ParseImageDirs(CByteBuffer &buf, int parent); + +public: + CRecordVector DataStreams; + CRecordVector MetaStreams; + + CObjectVector Solids; + + CRecordVector Items; + CObjectVector ReparseItems; + CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems + // -1 means no reparse; + + CObjectVector Images; + + bool IsOldVersion9; + bool IsOldVersion; + bool ThereAreDeletedStreams; + bool ThereAreAltStreams; + bool RefCountError; + bool HeadersError; + + unsigned GetStartImageIndex() const { return IsOldVersion9 ? 0 : 1; } + unsigned GetDirAlignMask() const { return IsOldVersion9 ? 3 : 7; } + + // User Items can contain all images or just one image from all. + CUIntVector SortedItems; + int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items + + unsigned NumExcludededItems; + int ExludedItem; // -1 : if there are no exclude items + CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives + + bool ThereIsError() const { return RefCountError || HeadersError; } + + unsigned GetNumUserItemsInImage(unsigned imageIndex) const + { + if (IndexOfUserImage >= 0 && imageIndex != (unsigned)IndexOfUserImage) + return 0; + if (imageIndex >= Images.Size()) + return 0; + return Images[imageIndex].NumItems - NumExcludededItems; + } + + bool ItemHasStream(const CItem &item) const; + + UInt64 Get_UnpackSize_of_Resource(const CResource &r) const + { + if (!r.IsSolid()) + return r.UnpackSize; + if (r.IsSolidSmall()) + return r.PackSize; + if (r.IsSolidBig() && r.SolidIndex >= 0) + return Solids[(unsigned)r.SolidIndex].UnpackSize; + return 0; + } + + UInt64 Get_PackSize_of_Resource(unsigned streamIndex) const + { + const CResource &r = DataStreams[streamIndex].Resource; + if (!r.IsSolidSmall()) + return r.PackSize; + if (r.SolidIndex >= 0) + { + const CSolid &ss = Solids[(unsigned)r.SolidIndex]; + if (ss.FirstSmallStream == (int)streamIndex) + return DataStreams[ss.StreamIndex].Resource.PackSize; + } + return 0; + } + + UInt64 GetUnpackSize() const + { + UInt64 res = 0; + FOR_VECTOR (i, DataStreams) + res += DataStreams[i].Resource.UnpackSize; + return res; + } + + UInt64 GetPackSize() const + { + UInt64 res = 0; + FOR_VECTOR (i, DataStreams) + res += DataStreams[i].Resource.PackSize; + return res; + } + + void Clear() + { + DataStreams.Clear(); + MetaStreams.Clear(); + Solids.Clear(); + + Items.Clear(); + ReparseItems.Clear(); + ItemToReparse.Clear(); + + SortedItems.Clear(); + + Images.Clear(); + VirtualRoots.Clear(); + + IsOldVersion = false; + ThereAreDeletedStreams = false; + ThereAreAltStreams = false; + RefCountError = false; + HeadersError = false; + } + + CDatabase(): + RefCountError(false), + HeadersError(false) + {} + + void GetShortName(unsigned index, NWindows::NCOM::CPropVariant &res) const; + void GetItemName(unsigned index1, NWindows::NCOM::CPropVariant &res) const; + void GetItemPath(unsigned index, bool showImageNumber, NWindows::NCOM::CPropVariant &res) const; + + HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml); + HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback); + HRESULT FillAndCheck(const CObjectVector &volumes); + + /* + imageIndex showImageNumber NumImages + * true * Show Image_Number + -1 * >1 Show Image_Number + -1 false 1 Don't show Image_Number + N false * Don't show Image_Number + */ + HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber); + + HRESULT ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback); +}; + +HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize); + + +struct CMidBuf +{ + Byte *Data; + size_t _size; + + CMidBuf(): Data(NULL), _size(0) {} + + void EnsureCapacity(size_t size) + { + if (size > _size) + { + ::z7_AlignedFree(Data); + _size = 0; + Data = (Byte *)::z7_AlignedAlloc(size); + if (Data) + _size = size; + } + } + + ~CMidBuf() { ::z7_AlignedFree(Data); } +}; + + +class CUnpacker +{ + CMyComPtr2 copyCoder; + CMyUniquePtr lzxDecoder; + CMyUniquePtr lzmsDecoder; + + CByteBuffer sizesBuf; + + CMidBuf packBuf; + CMidBuf unpackBuf; + + // solid resource + int _solidIndex; + size_t _unpackedChunkIndex; + + HRESULT UnpackChunk( + ISequentialInStream *inStream, + unsigned method, unsigned chunkSizeBits, + size_t inSize, size_t outSize, + ISequentialOutStream *outStream); + + HRESULT Unpack2( + IInStream *inStream, + const CResource &res, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress); + +public: + UInt64 TotalPacked; + + CUnpacker(): + lzmsDecoder(NULL), + _solidIndex(-1), + _unpackedChunkIndex(0), + TotalPacked(0) + {} + + HRESULT Unpack( + IInStream *inStream, + const CResource &res, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress, + Byte *digest); + + HRESULT UnpackData(IInStream *inStream, + const CResource &resource, const CHeader &header, + const CDatabase *db, + CByteBuffer &buf, Byte *digest); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp index 7fa7cbf6a..e143f91ca 100644 --- a/CPP/7zip/Archive/Wim/WimRegister.cpp +++ b/CPP/7zip/Archive/Wim/WimRegister.cpp @@ -1,29 +1,29 @@ -// WimRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "WimHandler.h" - -namespace NArchive { -namespace NWim { - -REGISTER_ARC_IO( - "wim", "wim swm esd ppkg", NULL, 0xE6 - , kSignature, 0 - , NArcInfoFlags::kAltStreams - | NArcInfoFlags::kNtSecure - | NArcInfoFlags::kSymLinks - | NArcInfoFlags::kHardLinks - | NArcInfoFlags::kCTime - // | NArcInfoFlags::kCTime_Default - | NArcInfoFlags::kATime - // | NArcInfoFlags::kATime_Default - | NArcInfoFlags::kMTime - | NArcInfoFlags::kMTime_Default - , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) - | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows) - , NULL) - -}} +// WimRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "WimHandler.h" + +namespace NArchive { +namespace NWim { + +REGISTER_ARC_IO( + "wim", "wim swm esd ppkg", NULL, 0xE6 + , kSignature, 0 + , NArcInfoFlags::kAltStreams + | NArcInfoFlags::kNtSecure + | NArcInfoFlags::kSymLinks + | NArcInfoFlags::kHardLinks + | NArcInfoFlags::kCTime + // | NArcInfoFlags::kCTime_Default + | NArcInfoFlags::kATime + // | NArcInfoFlags::kATime_Default + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows) + , NULL) + +}} diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp index 73aa6cb3d..6ef8941ea 100644 --- a/CPP/7zip/Archive/XarHandler.cpp +++ b/CPP/7zip/Archive/XarHandler.cpp @@ -1,1273 +1,1315 @@ -// XarHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/Sha256.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyLinux.h" -#include "../../Common/MyXml.h" -#include "../../Common/StringToInt.h" -#include "../../Common/UTFConvert.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/TimeUtils.h" - -#include "../Common/LimitedStreams.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamObjects.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/BZip2Decoder.h" -#include "../Compress/CopyCoder.h" -#include "../Compress/ZlibDecoder.h" - -#include "Common/OutStreamWithSha1.h" - -using namespace NWindows; - -#define XAR_SHOW_RAW - -#define Get16(p) GetBe16(p) -#define Get32(p) GetBe32(p) -#define Get64(p) GetBe64(p) - -namespace NArchive { -namespace NXar { - -Z7_CLASS_IMP_NOQIB_1( - CInStreamWithSha256 - , ISequentialInStream -) - CMyComPtr _stream; - CAlignedBuffer1 _sha; - UInt64 _size; - - CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; } -public: - CInStreamWithSha256(): _sha(sizeof(CSha256)) {} - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void Init() - { - _size = 0; - Sha256_Init(Sha()); - } - void ReleaseStream() { _stream.Release(); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { Sha256_Final(Sha(), digest); } -}; - -Z7_COM7F_IMF(CInStreamWithSha256::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize; - const HRESULT result = _stream->Read(data, size, &realProcessedSize); - _size += realProcessedSize; - Sha256_Update(Sha(), (const Byte *)data, realProcessedSize); - if (processedSize) - *processedSize = realProcessedSize; - return result; -} - - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithSha256 - , ISequentialOutStream -) - // bool _calculate; - CMyComPtr _stream; - CAlignedBuffer1 _sha; - UInt64 _size; - - CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; } -public: - COutStreamWithSha256(): _sha(sizeof(CSha256)) {} - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(/* bool calculate = true */ ) - { - // _calculate = calculate; - _size = 0; - Sha256_Init(Sha()); - } - void InitSha256() { Sha256_Init(Sha()); } - UInt64 GetSize() const { return _size; } - void Final(Byte *digest) { Sha256_Final(Sha(), digest); } -}; - -Z7_COM7F_IMF(COutStreamWithSha256::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - // if (_calculate) - Sha256_Update(Sha(), (const Byte *)data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -// we limit supported xml sizes: -// ((size_t)1 << (sizeof(size_t) / 2 + 28)) - (1u << 14); -static const size_t kXmlSizeMax = ((size_t)1 << 30) - (1u << 14); -static const size_t kXmlPackSizeMax = kXmlSizeMax; - -#define XAR_CKSUM_NONE 0 -#define XAR_CKSUM_SHA1 1 -#define XAR_CKSUM_MD5 2 -#define XAR_CKSUM_SHA256 3 -#define XAR_CKSUM_SHA512 4 -// #define XAR_CKSUM_OTHER 3 -// fork version of xar can use (3) as special case, -// where name of hash is stored as string at the end of header -// we do not support such hash still. - -static const char * const k_ChecksumNames[] = -{ - "NONE" - , "SHA1" - , "MD5" - , "SHA256" - , "SHA512" -}; - -static unsigned GetHashSize(int algo) -{ - if (algo <= XAR_CKSUM_NONE || algo > XAR_CKSUM_SHA512) - return 0; - if (algo == XAR_CKSUM_SHA1) - return SHA1_DIGEST_SIZE; - return (16u >> XAR_CKSUM_MD5) << algo; -} - -#define METHOD_NAME_ZLIB "zlib" - -static int Find_ChecksumId_for_Name(const AString &style) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ChecksumNames); i++) - { - // old xars used upper case in "style" - // new xars use lower case in "style" - if (style.IsEqualTo_Ascii_NoCase(k_ChecksumNames[i])) - return (int)i; - } - return -1; -} - - -struct CCheckSum -{ - int AlgoNumber; - bool Error; - CByteBuffer Data; - AString Style; - - CCheckSum(): AlgoNumber(-1), Error(false) {} - void AddNameToString(AString &s) const; -}; - -void CCheckSum::AddNameToString(AString &s) const -{ - if (Style.IsEmpty()) - s.Add_OptSpaced("NO-CHECKSUM"); - else - { - s.Add_OptSpaced(Style); - if (Error) - s += "-ERROR"; - } -} - - -struct CFile -{ - bool IsDir; - bool Is_SymLink; - bool HasData; - bool Mode_Defined; - bool INode_Defined; - bool UserId_Defined; - bool GroupId_Defined; - // bool Device_Defined; - bool Id_Defined; - - int Parent; - UInt32 Mode; - - UInt64 Size; - UInt64 PackSize; - UInt64 Offset; - UInt64 MTime; - UInt64 CTime; - UInt64 ATime; - UInt64 INode; - UInt64 UserId; - UInt64 GroupId; - // UInt64 Device; - - AString Name; - AString Method; - AString User; - AString Group; - // AString Id; - AString Type; - AString Link; - // AString LinkType; - // AString LinkFrom; - - UInt64 Id; - CCheckSum extracted_checksum; - CCheckSum archived_checksum; - - CFile(int parent): - IsDir(false), - Is_SymLink(false), - HasData(false), - Mode_Defined(false), - INode_Defined(false), - UserId_Defined(false), - GroupId_Defined(false), - // Device_Defined(false), - Id_Defined(false), - Parent(parent), - Mode(0), - Size(0), PackSize(0), Offset(0), - MTime(0), CTime(0), ATime(0), - INode(0) - {} - - bool IsCopyMethod() const - { - return Method.IsEmpty() || Method == "octet-stream"; - } - - void UpdateTotalPackSize(UInt64 &totalSize) const - { - const UInt64 t = Offset + PackSize; - if (t >= Offset) - if (totalSize < t) - totalSize = t; - } -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_2( - IArchiveGetRawProps, - IInArchiveGetStream -) - bool _is_pkg; - bool _toc_CrcError; - CObjectVector _files; - CMyComPtr _inStream; - UInt64 _dataStartPos; - UInt64 _phySize; - CAlignedBuffer _xmlBuf; - size_t _xmlLen; - // UInt64 CreationTime; - AString CreationTime_String; - UInt32 _checkSumAlgo; - Int32 _mainSubfile; - - HRESULT Open2(IInStream *stream); -}; - - -static const Byte kArcProps[] = -{ - kpidSubType, - // kpidHeadersSize, - kpidMethod, - kpidCTime -}; - -// #define kpidLinkType 250 -// #define kpidLinkFrom 251 - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidPosixAttrib, - kpidType, - kpidUser, - kpidGroup, - kpidUserId, - kpidGroupId, - kpidINode, - // kpidDeviceMajor, - // kpidDeviceMinor, - kpidSymLink, - // kpidLinkType, - // kpidLinkFrom, - kpidMethod, - kpidId, - kpidOffset -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res) -{ - const AString s (item.GetSubStringForTag(name)); - if (s.IsEmpty()) - return false; - const char *end; - res = ConvertStringToUInt64(s, &end); - return *end == 0; -} - - -#define PARSE_NUM(_num_, _dest_) \ - { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \ - if ((unsigned)(end - p) != _num_) return 0; \ - p += _num_ + 1; } - -static UInt64 ParseTime(const CXmlItem &item, const char *name /* , bool z_isRequired */ ) -{ - const AString s (item.GetSubStringForTag(name)); - if (s.Len() < 20 /* (z_isRequired ? 20u : 19u) */) - return 0; - const char *p = s; - if (p[ 4] != '-' || - p[ 7] != '-' || - p[10] != 'T' || - p[13] != ':' || - p[16] != ':') - return 0; - // if (z_isRequired) - if (p[19] != 'Z') - return 0; - UInt32 year, month, day, hour, min, sec; - PARSE_NUM(4, year) - PARSE_NUM(2, month) - PARSE_NUM(2, day) - PARSE_NUM(2, hour) - PARSE_NUM(2, min) - PARSE_NUM(2, sec) - UInt64 numSecs; - if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs)) - return 0; - return numSecs * 10000000; -} - - -static void ParseChecksum(const CXmlItem &item, const char *name, CCheckSum &checksum) -{ - const CXmlItem *checkItem = item.FindSubTag_GetPtr(name); - if (!checkItem) - return; // false; - checksum.Style = checkItem->GetPropVal("style"); - const AString s (checkItem->GetSubString()); - if ((s.Len() & 1) == 0 && s.Len() <= (2u << 7)) // 1024-bit max - { - const size_t size = s.Len() / 2; - CByteBuffer temp(size); - if ((size_t)(ParseHexString(s, temp) - temp) == size) - { - checksum.Data = temp; - const int index = Find_ChecksumId_for_Name(checksum.Style); - if (index >= 0 && checksum.Data.Size() == GetHashSize(index)) - { - checksum.AlgoNumber = index; - return; - } - } - } - checksum.Error = true; -} - - -static bool AddItem(const CXmlItem &item, CObjectVector &files, int parent, int level) -{ - if (!item.IsTag) - return true; - if (level >= 1024) - return false; - if (item.Name == "file") - { - CFile file(parent); - parent = (int)files.Size(); - { - const AString id = item.GetPropVal("id"); - const char *end; - file.Id = ConvertStringToUInt64(id, &end); - if (*end == 0) - file.Id_Defined = true; - } - file.Name = item.GetSubStringForTag("name"); - z7_xml_DecodeString(file.Name); - { - const CXmlItem *typeItem = item.FindSubTag_GetPtr("type"); - if (typeItem) - { - file.Type = typeItem->GetSubString(); - // file.LinkFrom = typeItem->GetPropVal("link"); - if (file.Type == "directory") - file.IsDir = true; - else - { - // file.IsDir = false; - /* - else if (file.Type == "file") - {} - else if (file.Type == "hardlink") - {} - else - */ - if (file.Type == "symlink") - file.Is_SymLink = true; - // file.IsDir = false; - } - } - } - { - const CXmlItem *linkItem = item.FindSubTag_GetPtr("link"); - if (linkItem) - { - // file.LinkType = linkItem->GetPropVal("type"); - file.Link = linkItem->GetSubString(); - z7_xml_DecodeString(file.Link); - } - } - - const CXmlItem *dataItem = item.FindSubTag_GetPtr("data"); - if (dataItem && !file.IsDir) - { - file.HasData = true; - if (!ParseUInt64(*dataItem, "size", file.Size)) - return false; - if (!ParseUInt64(*dataItem, "length", file.PackSize)) - return false; - if (!ParseUInt64(*dataItem, "offset", file.Offset)) - return false; - ParseChecksum(*dataItem, "extracted-checksum", file.extracted_checksum); - ParseChecksum(*dataItem, "archived-checksum", file.archived_checksum); - const CXmlItem *encodingItem = dataItem->FindSubTag_GetPtr("encoding"); - if (encodingItem) - { - AString s (encodingItem->GetPropVal("style")); - if (!s.IsEmpty()) - { - const AString appl ("application/"); - if (s.IsPrefixedBy(appl)) - { - s.DeleteFrontal(appl.Len()); - const AString xx ("x-"); - if (s.IsPrefixedBy(xx)) - { - s.DeleteFrontal(xx.Len()); - if (s == "gzip") - s = METHOD_NAME_ZLIB; - } - } - file.Method = s; - } - } - } - - file.INode_Defined = ParseUInt64(item, "inode", file.INode); - file.UserId_Defined = ParseUInt64(item, "uid", file.UserId); - file.GroupId_Defined = ParseUInt64(item, "gid", file.GroupId); - // file.Device_Defined = ParseUInt64(item, "deviceno", file.Device); - file.MTime = ParseTime(item, "mtime"); // z_IsRequied = true - file.CTime = ParseTime(item, "ctime"); - file.ATime = ParseTime(item, "atime"); - { - const AString s (item.GetSubStringForTag("mode")); - if (s[0] == '0') - { - const char *end; - file.Mode = ConvertOctStringToUInt32(s, &end); - file.Mode_Defined = (*end == 0); - } - } - file.User = item.GetSubStringForTag("user"); - file.Group = item.GetSubStringForTag("group"); - - files.Add(file); - } - - FOR_VECTOR (i, item.SubItems) - if (!AddItem(item.SubItems[i], files, parent, level + 1)) - return false; - return true; -} - - - -struct CInStreamWithHash -{ - CMyComPtr2_Create inStreamSha1; - CMyComPtr2_Create inStreamSha256; - CMyComPtr2_Create inStreamLim; - - void SetStreamAndInit(ISequentialInStream *stream, int algo); - bool CheckHash(int algo, const Byte *digest_from_arc) const; -}; - - -void CInStreamWithHash::SetStreamAndInit(ISequentialInStream *stream, int algo) -{ - if (algo == XAR_CKSUM_SHA1) - { - inStreamSha1->SetStream(stream); - inStreamSha1->Init(); - stream = inStreamSha1; - } - else if (algo == XAR_CKSUM_SHA256) - { - inStreamSha256->SetStream(stream); - inStreamSha256->Init(); - stream = inStreamSha256; - } - inStreamLim->SetStream(stream); -} - -bool CInStreamWithHash::CheckHash(int algo, const Byte *digest_from_arc) const -{ - if (algo == XAR_CKSUM_SHA1) - { - Byte digest[SHA1_DIGEST_SIZE]; - inStreamSha1->Final(digest); - if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0) - return false; - } - else if (algo == XAR_CKSUM_SHA256) - { - Byte digest[SHA256_DIGEST_SIZE]; - inStreamSha256->Final(digest); - if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0) - return false; - } - return true; -} - - -HRESULT CHandler::Open2(IInStream *stream) -{ - const unsigned kHeaderSize = 28; - UInt32 buf32[kHeaderSize / sizeof(UInt32)]; - RINOK(ReadStream_FALSE(stream, buf32, kHeaderSize)) - const unsigned headerSize = Get16((const Byte *)(const void *)buf32 + 4); - // xar library now writes 1 to version field. - // some old xars could have version == 0 ? - // specification allows (headerSize != 28), - // but we don't expect big value in (headerSize). - // so we restrict (headerSize) with 64 bytes to reduce false open. - const unsigned kHeaderSize_MAX = 64; - if (Get32(buf32) != 0x78617221 // signature: "xar!" - || headerSize < kHeaderSize - || headerSize > kHeaderSize_MAX - || Get16((const Byte *)(const void *)buf32 + 6) > 1 // version - ) - return S_FALSE; - _checkSumAlgo = Get32(buf32 + 6); - const UInt64 packSize = Get64(buf32 + 2); - const UInt64 unpackSize = Get64(buf32 + 4); - if (packSize >= kXmlPackSizeMax || - unpackSize >= kXmlSizeMax) - return S_FALSE; - /* some xar archives can have padding bytes at offset 28, - or checksum algorithm name at offset 28 (in xar fork, if cksum_alg==3) - But we didn't see such xar archives. - */ - if (headerSize != kHeaderSize) - { - RINOK(InStream_SeekSet(stream, headerSize)) - } - _dataStartPos = headerSize + packSize; - _phySize = _dataStartPos; - - _xmlBuf.Alloc((size_t)unpackSize + 1); - if (!_xmlBuf.IsAllocated()) - return E_OUTOFMEMORY; - _xmlLen = (size_t)unpackSize; - - CInStreamWithHash hashStream; - { - CMyComPtr2_Create zlibCoder; - hashStream.SetStreamAndInit(stream, (int)(unsigned)_checkSumAlgo); - hashStream.inStreamLim->Init(packSize); - CMyComPtr2_Create outStreamLim; - outStreamLim->Init(_xmlBuf, (size_t)unpackSize); - RINOK(zlibCoder.Interface()->Code(hashStream.inStreamLim, outStreamLim, NULL, &unpackSize, NULL)) - if (outStreamLim->GetPos() != (size_t)unpackSize) - return S_FALSE; - } - _xmlBuf[(size_t)unpackSize] = 0; - if (strlen((const char *)(const Byte *)_xmlBuf) != (size_t)unpackSize) - return S_FALSE; - CXml xml; - if (!xml.Parse((const char *)(const Byte *)_xmlBuf)) - return S_FALSE; - - if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1) - return S_FALSE; - const CXmlItem &toc = xml.Root.SubItems[0]; - if (!toc.IsTagged("toc")) - return S_FALSE; - - // CreationTime = ParseTime(toc, "creation-time", false); // z_IsRequied - CreationTime_String = toc.GetSubStringForTag("creation-time"); - { - // we suppose that offset of checksum is always 0; - // but [TOC].xml contains exact offset value in block. - const UInt64 offset = 0; - const unsigned hashSize = GetHashSize((int)(unsigned)_checkSumAlgo); - if (hashSize) - { - /* - const CXmlItem *csItem = toc.FindSubTag_GetPtr("checksum"); - if (csItem) - { - const int checkSumAlgo2 = Find_ChecksumId_for_Name(csItem->GetPropVal("style")); - UInt64 csSize, csOffset; - if (ParseUInt64(*csItem, "size", csSize) && - ParseUInt64(*csItem, "offset", csOffset) && - csSize == hashSize && - (unsigned)checkSumAlgo2 == _checkSumAlgo) - offset = csOffset; - } - */ - CByteBuffer digest_from_arc(hashSize); - RINOK(InStream_SeekSet(stream, _dataStartPos + offset)) - RINOK(ReadStream_FALSE(stream, digest_from_arc, hashSize)) - if (!hashStream.CheckHash((int)(unsigned)_checkSumAlgo, digest_from_arc)) - _toc_CrcError = true; - } - } - - if (!AddItem(toc, _files, - -1, // parent - 0)) // level - return S_FALSE; - - UInt64 totalPackSize = 0; - unsigned numMainFiles = 0; - - FOR_VECTOR (i, _files) - { - const CFile &file = _files[i]; - file.UpdateTotalPackSize(totalPackSize); - if (file.Parent == -1) - { - if (file.Name == "Payload" || file.Name == "Content") - { - _mainSubfile = (Int32)(int)i; - numMainFiles++; - } - else if (file.Name == "PackageInfo") - _is_pkg = true; - } - } - - if (numMainFiles > 1) - _mainSubfile = -1; - - const UInt64 k_PhySizeLim = (UInt64)1 << 62; - _phySize = (totalPackSize > k_PhySizeLim - _dataStartPos) ? - k_PhySizeLim : - _dataStartPos + totalPackSize; - - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - { - Close(); - RINOK(Open2(stream)) - _inStream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _phySize = 0; - _dataStartPos = 0; - _inStream.Release(); - _files.Clear(); - _xmlLen = 0; - _xmlBuf.Free(); - _mainSubfile = -1; - _is_pkg = false; - _toc_CrcError = false; - _checkSumAlgo = 0; - // CreationTime = 0; - CreationTime_String.Empty(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _files.Size() -#ifdef XAR_SHOW_RAW - + 1 -#endif - ; - return S_OK; -} - -static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop) -{ - if (t != 0) - { - FILETIME ft; - ft.dwLowDateTime = (UInt32)(t); - ft.dwHighDateTime = (UInt32)(t >> 32); - prop = ft; - } -} - -static void Utf8StringToProp(const AString &s, NCOM::CPropVariant &prop) -{ - if (!s.IsEmpty()) - { - UString us; - ConvertUTF8ToUnicode(s, us); - prop = us; - } -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - // case kpidHeadersSize: prop = _dataStartPos; break; - case kpidPhySize: prop = _phySize; break; - case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; - case kpidSubType: if (_is_pkg) prop = "pkg"; break; - case kpidExtension: prop = _is_pkg ? "pkg" : "xar"; break; - case kpidCTime: - { - // it's local time. We can transfer it to UTC time, if we use FILETIME. - // TimeToProp(CreationTime, prop); break; - if (!CreationTime_String.IsEmpty()) - prop = CreationTime_String; - break; - } - case kpidMethod: - { - AString s; - if (_checkSumAlgo < Z7_ARRAY_SIZE(k_ChecksumNames)) - s = k_ChecksumNames[_checkSumAlgo]; - else - { - s += "Checksum"; - s.Add_UInt32(_checkSumAlgo); - } - prop = s; - break; - } - case kpidWarningFlags: - { - UInt32 v = 0; - if (_toc_CrcError) v |= kpv_ErrorFlags_CrcError; - prop = v; - break; - } - case kpidINode: prop = true; break; - case kpidIsTree: prop = true; break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -/* -inline UInt32 MY_dev_major(UInt64 dev) -{ - return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff); -} -inline UInt32 MY_dev_minor(UInt64 dev) -{ - return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~(UInt32)0xff); -} -*/ - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - { - switch (propID) - { - case kpidName: - case kpidPath: - prop = "[TOC].xml"; break; - case kpidSize: - case kpidPackSize: prop = (UInt64)_xmlLen; break; - } - } - else -#endif - { - const CFile &item = _files[index]; - switch (propID) - { - case kpidPath: - { - AString path; - unsigned cur = index; - for (;;) - { - const CFile &item2 = _files[cur]; - if (!path.IsEmpty()) - path.InsertAtFront(CHAR_PATH_SEPARATOR); -// #define XAR_EMPTY_NAME_REPLACEMENT "[]" - if (item2.Name.IsEmpty()) - { - AString s('['); - s.Add_UInt32(cur); - s.Add_Char(']'); - path.Insert(0, s); - } - else - path.Insert(0, item2.Name); - if (item2.Parent < 0) - break; - cur = (unsigned)item2.Parent; - } - Utf8StringToProp(path, prop); - break; - } - - case kpidName: - { - if (item.Name.IsEmpty()) - { - AString s('['); - s.Add_UInt32(index); - s.Add_Char(']'); - prop = s; - } - else - Utf8StringToProp(item.Name, prop); - break; - } - - case kpidIsDir: prop = item.IsDir; break; - - case kpidSize: if (item.HasData && !item.IsDir) prop = item.Size; break; - case kpidPackSize: if (item.HasData && !item.IsDir) prop = item.PackSize; break; - - case kpidMethod: - { - if (item.HasData) - { - AString s = item.Method; - item.extracted_checksum.AddNameToString(s); - item.archived_checksum.AddNameToString(s); - Utf8StringToProp(s, prop); - } - break; - } - - case kpidMTime: TimeToProp(item.MTime, prop); break; - case kpidCTime: TimeToProp(item.CTime, prop); break; - case kpidATime: TimeToProp(item.ATime, prop); break; - - case kpidPosixAttrib: - if (item.Mode_Defined) - { - UInt32 mode = item.Mode; - if ((mode & MY_LIN_S_IFMT) == 0) - mode |= ( - item.Is_SymLink ? MY_LIN_S_IFLNK : - item.IsDir ? MY_LIN_S_IFDIR : - MY_LIN_S_IFREG); - prop = mode; - } - break; - - case kpidType: Utf8StringToProp(item.Type, prop); break; - case kpidUser: Utf8StringToProp(item.User, prop); break; - case kpidGroup: Utf8StringToProp(item.Group, prop); break; - case kpidSymLink: if (item.Is_SymLink) Utf8StringToProp(item.Link, prop); break; - - case kpidUserId: if (item.UserId_Defined) prop = item.UserId; break; - case kpidGroupId: if (item.GroupId_Defined) prop = item.GroupId; break; - case kpidINode: if (item.INode_Defined) prop = item.INode; break; - case kpidId: if (item.Id_Defined) prop = item.Id; break; - // Utf8StringToProp(item.Id, prop); - /* - case kpidDeviceMajor: if (item.Device_Defined) prop = (UInt32)MY_dev_major(item.Device); break; - case kpidDeviceMinor: if (item.Device_Defined) prop = (UInt32)MY_dev_minor(item.Device); break; - case kpidLinkType: - if (!item.LinkType.IsEmpty()) - Utf8StringToProp(item.LinkType, prop); - break; - case kpidLinkFrom: - if (!item.LinkFrom.IsEmpty()) - Utf8StringToProp(item.LinkFrom, prop); - break; - */ - case kpidOffset: - if (item.HasData) - prop = _dataStartPos + item.Offset; - break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -// for debug: -// #define Z7_XAR_SHOW_CHECKSUM_PACK - -#ifdef Z7_XAR_SHOW_CHECKSUM_PACK -enum -{ - kpidChecksumPack = kpidUserDefined -}; -#endif - -static const Byte kRawProps[] = -{ - kpidChecksum -#ifdef Z7_XAR_SHOW_CHECKSUM_PACK - , kpidCRC // instead of kpidUserDefined / kpidCRC -#endif -}; - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = Z7_ARRAY_SIZE(kRawProps); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) -{ - *propID = kRawProps[index]; - *name = NULL; - -#ifdef Z7_XAR_SHOW_CHECKSUM_PACK - if (index != 0) - { - *propID = kpidChecksumPack; - *name = NWindows::NCOM::AllocBstrFromAscii("archived-checksum"); - } -#endif - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - return S_OK; -#endif - { - const CFile &item = _files[index]; - *parent = (UInt32)(Int32)item.Parent; - } - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - // COM_TRY_BEGIN - NCOM::CPropVariant prop; - - if (propID == kpidChecksum) - { -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - { - // case kpidPath: prop = "[TOC].xml"; break; - } - else -#endif - { - const CFile &item = _files[index]; - const size_t size = item.extracted_checksum.Data.Size(); - if (size != 0) - { - *dataSize = (UInt32)size; - *propType = NPropDataType::kRaw; - *data = item.extracted_checksum.Data; - } - } - } - -#ifdef Z7_XAR_SHOW_CHECKSUM_PACK - if (propID == kpidChecksumPack) - { -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - { - // we can show digest check sum here - } - else -#endif - { - const CFile &item = _files[index]; - const size_t size = (UInt32)item.archived_checksum.Data.Size(); - if (size != 0) - { - *dataSize = (UInt32)size; - *propType = NPropDataType::kRaw; - *data = item.archived_checksum.Data; - } - } - } -#endif - return S_OK; -} - - - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _files.Size() -#ifdef XAR_SHOW_RAW - + 1 -#endif - ; - if (numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - totalSize += _xmlLen; - else -#endif - totalSize += _files[index].Size; - } - RINOK(extractCallback->SetTotal(totalSize)) - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - CInStreamWithHash inHashStream; - CMyComPtr2_Create outStreamSha1; - CMyComPtr2_Create outStreamSha256; - CMyComPtr2_Create outStreamLim; - CMyComPtr2_Create copyCoder; - CMyComPtr2_Create zlibCoder; - CMyComPtr2_Create bzip2Coder; - bzip2Coder->FinishMode = true; - - UInt64 cur_PackSize, cur_UnpSize; - - for (i = 0;; i++, - lps->InSize += cur_PackSize, - lps->OutSize += cur_UnpSize) - { - cur_PackSize = 0; - cur_UnpSize = 0; - RINOK(lps->SetCur()) - if (i >= numItems) - break; - - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (index < _files.Size()) - { - const CFile &item = _files[index]; - if (item.IsDir) - { - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - } - - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - Int32 opRes = NExtract::NOperationResult::kOK; - -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - { - cur_PackSize = cur_UnpSize = _xmlLen; - if (realOutStream) - RINOK(WriteStream(realOutStream, _xmlBuf, _xmlLen)) - realOutStream.Release(); - } - else -#endif - { - const CFile &item = _files[index]; - if (!item.HasData) - realOutStream.Release(); - else - { - cur_PackSize = item.PackSize; - cur_UnpSize = item.Size; - - RINOK(InStream_SeekSet(_inStream, _dataStartPos + item.Offset)) - - inHashStream.SetStreamAndInit(_inStream, item.archived_checksum.AlgoNumber); - inHashStream.inStreamLim->Init(item.PackSize); - - const int checksum_method = item.extracted_checksum.AlgoNumber; - if (checksum_method == XAR_CKSUM_SHA1) - { - outStreamLim->SetStream(outStreamSha1); - outStreamSha1->SetStream(realOutStream); - outStreamSha1->Init(); - } - else if (checksum_method == XAR_CKSUM_SHA256) - { - outStreamLim->SetStream(outStreamSha256); - outStreamSha256->SetStream(realOutStream); - outStreamSha256->Init(); - } - else - outStreamLim->SetStream(realOutStream); - - realOutStream.Release(); - - // outStreamSha1->Init(item.Sha1IsDefined); - - outStreamLim->Init(item.Size); - HRESULT res = S_OK; - - ICompressCoder *coder = NULL; - if (item.IsCopyMethod()) - { - if (item.PackSize == item.Size) - coder = copyCoder; - else - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - else if (item.Method == METHOD_NAME_ZLIB) - coder = zlibCoder; - else if (item.Method == "bzip2") - coder = bzip2Coder; - else - opRes = NExtract::NOperationResult::kUnsupportedMethod; - - if (coder) - res = coder->Code(inHashStream.inStreamLim, outStreamLim, NULL, &item.Size, lps); - - if (res != S_OK) - { - if (!outStreamLim->IsFinishedOK()) - opRes = NExtract::NOperationResult::kDataError; - else if (res != S_FALSE) - return res; - if (opRes == NExtract::NOperationResult::kOK) - opRes = NExtract::NOperationResult::kDataError; - } - - if (opRes == NExtract::NOperationResult::kOK) - { - if (outStreamLim->IsFinishedOK()) - { - if (checksum_method == XAR_CKSUM_SHA1) - { - Byte digest[SHA1_DIGEST_SIZE]; - outStreamSha1->Final(digest); - if (memcmp(digest, item.extracted_checksum.Data, SHA1_DIGEST_SIZE) != 0) - opRes = NExtract::NOperationResult::kCRCError; - } - else if (checksum_method == XAR_CKSUM_SHA256) - { - Byte digest[SHA256_DIGEST_SIZE]; - outStreamSha256->Final(digest); - if (memcmp(digest, item.extracted_checksum.Data, SHA256_DIGEST_SIZE) != 0) - opRes = NExtract::NOperationResult::kCRCError; - } - if (opRes == NExtract::NOperationResult::kOK) - if (!inHashStream.CheckHash( - item.archived_checksum.AlgoNumber, - item.archived_checksum.Data)) - opRes = NExtract::NOperationResult::kCRCError; - } - else - opRes = NExtract::NOperationResult::kDataError; - } - if (checksum_method == XAR_CKSUM_SHA1) - outStreamSha1->ReleaseStream(); - else if (checksum_method == XAR_CKSUM_SHA256) - outStreamSha256->ReleaseStream(); - } - outStreamLim->ReleaseStream(); - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - *stream = NULL; - COM_TRY_BEGIN -#ifdef XAR_SHOW_RAW - if (index >= _files.Size()) - { - Create_BufInStream_WithNewBuffer(_xmlBuf, _xmlLen, stream); - return S_OK; - } - else -#endif - { - const CFile &item = _files[index]; - if (item.HasData && item.IsCopyMethod() && item.PackSize == item.Size) - return CreateLimitedInStream(_inStream, _dataStartPos + item.Offset, item.Size, stream); - } - return S_FALSE; - COM_TRY_END -} - -// 0x1c == 28 is expected header size value for most archives. -// but we want to support another (rare case) headers sizes. -// so we must reduce signature to 4 or 5 bytes. -static const Byte k_Signature[] = -// { 'x', 'a', 'r', '!', 0, 0x1C, 0 }; - { 'x', 'a', 'r', '!', 0 }; - -REGISTER_ARC_I( - "Xar", "xar pkg xip", NULL, 0xE1, - k_Signature, - 0, - 0, - NULL) - -}} +// XarHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Sha256.h" +#include "../../../C/Sha512.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyLinux.h" +#include "../../Common/MyXml.h" +#include "../../Common/StringToInt.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/BZip2Decoder.h" +#include "../Compress/CopyCoder.h" +#include "../Compress/ZlibDecoder.h" + +#include "Common/OutStreamWithSha1.h" + +using namespace NWindows; + +#define XAR_SHOW_RAW + +#define Get16(p) GetBe16(p) +#define Get32(p) GetBe32(p) +#define Get64(p) GetBe64(p) + +namespace NArchive { +namespace NXar { + +Z7_CLASS_IMP_NOQIB_1( + CInStreamWithSha256 + , ISequentialInStream +) + bool _sha512Mode; + CMyComPtr _stream; + CAlignedBuffer1 _sha256; + CAlignedBuffer1 _sha512; + UInt64 _size; + + CSha256 *Sha256() { return (CSha256 *)(void *)(Byte *)_sha256; } + CSha512 *Sha512() { return (CSha512 *)(void *)(Byte *)_sha512; } +public: + CInStreamWithSha256(): + _sha256(sizeof(CSha256)), + _sha512(sizeof(CSha512)) + {} + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void Init(bool sha512Mode) + { + _sha512Mode = sha512Mode; + _size = 0; + if (sha512Mode) + Sha512_Init(Sha512(), SHA512_DIGEST_SIZE); + else + Sha256_Init(Sha256()); + } + void ReleaseStream() { _stream.Release(); } + UInt64 GetSize() const { return _size; } + void Final256(Byte *digest) { Sha256_Final(Sha256(), digest); } + void Final512(Byte *digest) { Sha512_Final(Sha512(), digest, SHA512_DIGEST_SIZE); } +}; + +Z7_COM7F_IMF(CInStreamWithSha256::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize; + const HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + if (_sha512Mode) + Sha512_Update(Sha512(), (const Byte *)data, realProcessedSize); + else + Sha256_Update(Sha256(), (const Byte *)data, realProcessedSize); + if (processedSize) + *processedSize = realProcessedSize; + return result; +} + + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithSha256 + , ISequentialOutStream +) + bool _sha512Mode; + CMyComPtr _stream; + CAlignedBuffer1 _sha256; + CAlignedBuffer1 _sha512; + UInt64 _size; + + CSha256 *Sha256() { return (CSha256 *)(void *)(Byte *)_sha256; } + CSha512 *Sha512() { return (CSha512 *)(void *)(Byte *)_sha512; } +public: + COutStreamWithSha256(): + _sha256(sizeof(CSha256)), + _sha512(sizeof(CSha512)) + {} + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool sha512Mode) + { + _sha512Mode = sha512Mode; + _size = 0; + if (sha512Mode) + Sha512_Init(Sha512(), SHA512_DIGEST_SIZE); + else + Sha256_Init(Sha256()); + } + UInt64 GetSize() const { return _size; } + void Final256(Byte *digest) { Sha256_Final(Sha256(), digest); } + void Final512(Byte *digest) { Sha512_Final(Sha512(), digest, SHA512_DIGEST_SIZE); } +}; + +Z7_COM7F_IMF(COutStreamWithSha256::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + // if (_calculate) + if (_sha512Mode) + Sha512_Update(Sha512(), (const Byte *)data, size); + else + Sha256_Update(Sha256(), (const Byte *)data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +// we limit supported xml sizes: +// ((size_t)1 << (sizeof(size_t) / 2 + 28)) - (1u << 14); +static const size_t kXmlSizeMax = ((size_t)1 << 30) - (1u << 14); +static const size_t kXmlPackSizeMax = kXmlSizeMax; + +#define XAR_CKSUM_NONE 0 +#define XAR_CKSUM_SHA1 1 +#define XAR_CKSUM_MD5 2 +#define XAR_CKSUM_SHA256 3 +#define XAR_CKSUM_SHA512 4 +// #define XAR_CKSUM_OTHER 3 +// fork version of xar can use (3) as special case, +// where name of hash is stored as string at the end of header +// we do not support such hash still. + +static const char * const k_ChecksumNames[] = +{ + "NONE" + , "SHA1" + , "MD5" + , "SHA256" + , "SHA512" +}; + +static unsigned GetHashSize(int algo) +{ + if (algo <= XAR_CKSUM_NONE || algo > XAR_CKSUM_SHA512) + return 0; + if (algo == XAR_CKSUM_SHA1) + return SHA1_DIGEST_SIZE; + return (16u >> XAR_CKSUM_MD5) << algo; +} + +#define METHOD_NAME_ZLIB "zlib" + +static int Find_ChecksumId_for_Name(const AString &style) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ChecksumNames); i++) + { + // old xars used upper case in "style" + // new xars use lower case in "style" + if (style.IsEqualTo_Ascii_NoCase(k_ChecksumNames[i])) + return (int)i; + } + return -1; +} + + +struct CCheckSum +{ + int AlgoNumber; + bool Error; + CByteBuffer Data; + AString Style; + + CCheckSum(): AlgoNumber(-1), Error(false) {} + void AddNameToString(AString &s) const; +}; + +void CCheckSum::AddNameToString(AString &s) const +{ + if (Style.IsEmpty()) + s.Add_OptSpaced("NO-CHECKSUM"); + else + { + s.Add_OptSpaced(Style); + if (Error) + s += "-ERROR"; + } +} + + +struct CFile +{ + bool IsDir; + bool Is_SymLink; + bool HasData; + bool Mode_Defined; + bool INode_Defined; + bool UserId_Defined; + bool GroupId_Defined; + // bool Device_Defined; + bool Id_Defined; + + int Parent; + UInt32 Mode; + + UInt64 Size; + UInt64 PackSize; + UInt64 Offset; + UInt64 MTime; + UInt64 CTime; + UInt64 ATime; + UInt64 INode; + UInt64 UserId; + UInt64 GroupId; + // UInt64 Device; + + AString Name; + AString Method; + AString User; + AString Group; + // AString Id; + AString Type; + AString Link; + // AString LinkType; + // AString LinkFrom; + + UInt64 Id; + CCheckSum extracted_checksum; + CCheckSum archived_checksum; + + CFile(int parent): + IsDir(false), + Is_SymLink(false), + HasData(false), + Mode_Defined(false), + INode_Defined(false), + UserId_Defined(false), + GroupId_Defined(false), + // Device_Defined(false), + Id_Defined(false), + Parent(parent), + Mode(0), + Size(0), PackSize(0), Offset(0), + MTime(0), CTime(0), ATime(0), + INode(0) + {} + + bool IsCopyMethod() const + { + return Method.IsEmpty() || Method == "octet-stream"; + } + + void UpdateTotalPackSize(UInt64 &totalSize) const + { + const UInt64 t = Offset + PackSize; + if (t >= Offset) + if (totalSize < t) + totalSize = t; + } +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_2( + IArchiveGetRawProps, + IInArchiveGetStream +) + bool _is_pkg; + bool _toc_CrcError; + CObjectVector _files; + CMyComPtr _inStream; + UInt64 _dataStartPos; + UInt64 _phySize; + CAlignedBuffer _xmlBuf; + size_t _xmlLen; + // UInt64 CreationTime; + AString CreationTime_String; + UInt32 _checkSumAlgo; + Int32 _mainSubfile; + + HRESULT Open2(IInStream *stream); +}; + + +static const Byte kArcProps[] = +{ + kpidSubType, + // kpidHeadersSize, + kpidMethod, + kpidCTime +}; + +// #define kpidLinkType 250 +// #define kpidLinkFrom 251 + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidPosixAttrib, + kpidType, + kpidUser, + kpidGroup, + kpidUserId, + kpidGroupId, + kpidINode, + // kpidDeviceMajor, + // kpidDeviceMinor, + kpidSymLink, + // kpidLinkType, + // kpidLinkFrom, + kpidMethod, + kpidId, + kpidOffset +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res) +{ + const AString s (item.GetSubStringForTag(name)); + if (s.IsEmpty()) + return false; + const char *end; + res = ConvertStringToUInt64(s, &end); + return *end == 0; +} + + +#define PARSE_NUM(_num_, _dest_) \ + { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \ + if ((unsigned)(end - p) != _num_) return 0; \ + p += _num_ + 1; } + +static UInt64 ParseTime(const CXmlItem &item, const char *name /* , bool z_isRequired */ ) +{ + const AString s (item.GetSubStringForTag(name)); + if (s.Len() < 20 /* (z_isRequired ? 20u : 19u) */) + return 0; + const char *p = s; + if (p[ 4] != '-' || + p[ 7] != '-' || + p[10] != 'T' || + p[13] != ':' || + p[16] != ':') + return 0; + // if (z_isRequired) + if (p[19] != 'Z') + return 0; + UInt32 year, month, day, hour, min, sec; + PARSE_NUM(4, year) + PARSE_NUM(2, month) + PARSE_NUM(2, day) + PARSE_NUM(2, hour) + PARSE_NUM(2, min) + PARSE_NUM(2, sec) + UInt64 numSecs; + if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs)) + return 0; + return numSecs * 10000000; +} + + +static void ParseChecksum(const CXmlItem &item, const char *name, CCheckSum &checksum) +{ + const CXmlItem *checkItem = item.FindSubTag_GetPtr(name); + if (!checkItem) + return; // false; + checksum.Style = checkItem->GetPropVal("style"); + const AString s (checkItem->GetSubString()); + if ((s.Len() & 1) == 0 && s.Len() <= (2u << 7)) // 1024-bit max + { + const size_t size = s.Len() / 2; + CByteBuffer temp(size); + if ((size_t)(ParseHexString(s, temp) - temp) == size) + { + checksum.Data = temp; + const int index = Find_ChecksumId_for_Name(checksum.Style); + if (index >= 0 && checksum.Data.Size() == GetHashSize(index)) + { + checksum.AlgoNumber = index; + return; + } + } + } + checksum.Error = true; +} + + +static bool AddItem(const CXmlItem &item, CObjectVector &files, int parent, int level) +{ + if (!item.IsTag) + return true; + if (level >= 1024) + return false; + if (item.Name == "file") + { + CFile file(parent); + parent = (int)files.Size(); + { + const AString id = item.GetPropVal("id"); + const char *end; + file.Id = ConvertStringToUInt64(id, &end); + if (*end == 0) + file.Id_Defined = true; + } + file.Name = item.GetSubStringForTag("name"); + z7_xml_DecodeString(file.Name); + { + const CXmlItem *typeItem = item.FindSubTag_GetPtr("type"); + if (typeItem) + { + file.Type = typeItem->GetSubString(); + // file.LinkFrom = typeItem->GetPropVal("link"); + if (file.Type == "directory") + file.IsDir = true; + else + { + // file.IsDir = false; + /* + else if (file.Type == "file") + {} + else if (file.Type == "hardlink") + {} + else + */ + if (file.Type == "symlink") + file.Is_SymLink = true; + // file.IsDir = false; + } + } + } + { + const CXmlItem *linkItem = item.FindSubTag_GetPtr("link"); + if (linkItem) + { + // file.LinkType = linkItem->GetPropVal("type"); + file.Link = linkItem->GetSubString(); + z7_xml_DecodeString(file.Link); + } + } + + const CXmlItem *dataItem = item.FindSubTag_GetPtr("data"); + if (dataItem && !file.IsDir) + { + file.HasData = true; + if (!ParseUInt64(*dataItem, "size", file.Size)) + return false; + if (!ParseUInt64(*dataItem, "length", file.PackSize)) + return false; + if (!ParseUInt64(*dataItem, "offset", file.Offset)) + return false; + ParseChecksum(*dataItem, "extracted-checksum", file.extracted_checksum); + ParseChecksum(*dataItem, "archived-checksum", file.archived_checksum); + const CXmlItem *encodingItem = dataItem->FindSubTag_GetPtr("encoding"); + if (encodingItem) + { + AString s (encodingItem->GetPropVal("style")); + if (!s.IsEmpty()) + { + const AString appl ("application/"); + if (s.IsPrefixedBy(appl)) + { + s.DeleteFrontal(appl.Len()); + const AString xx ("x-"); + if (s.IsPrefixedBy(xx)) + { + s.DeleteFrontal(xx.Len()); + if (s == "gzip") + s = METHOD_NAME_ZLIB; + } + } + file.Method = s; + } + } + } + + file.INode_Defined = ParseUInt64(item, "inode", file.INode); + file.UserId_Defined = ParseUInt64(item, "uid", file.UserId); + file.GroupId_Defined = ParseUInt64(item, "gid", file.GroupId); + // file.Device_Defined = ParseUInt64(item, "deviceno", file.Device); + file.MTime = ParseTime(item, "mtime"); // z_IsRequied = true + file.CTime = ParseTime(item, "ctime"); + file.ATime = ParseTime(item, "atime"); + { + const AString s (item.GetSubStringForTag("mode")); + if (s[0] == '0') + { + const char *end; + file.Mode = ConvertOctStringToUInt32(s, &end); + file.Mode_Defined = (*end == 0); + } + } + file.User = item.GetSubStringForTag("user"); + file.Group = item.GetSubStringForTag("group"); + + files.Add(file); + } + + FOR_VECTOR (i, item.SubItems) + if (!AddItem(item.SubItems[i], files, parent, level + 1)) + return false; + return true; +} + + + +struct CInStreamWithHash +{ + CMyComPtr2_Create inStreamSha1; + CMyComPtr2_Create inStreamSha256; + CMyComPtr2_Create inStreamLim; + + void SetStreamAndInit(ISequentialInStream *stream, int algo); + bool CheckHash(int algo, const Byte *digest_from_arc) const; +}; + + +void CInStreamWithHash::SetStreamAndInit(ISequentialInStream *stream, int algo) +{ + if (algo == XAR_CKSUM_SHA1) + { + inStreamSha1->SetStream(stream); + inStreamSha1->Init(); + stream = inStreamSha1; + } + else if (algo == XAR_CKSUM_SHA256 + || algo == XAR_CKSUM_SHA512) + { + inStreamSha256->SetStream(stream); + inStreamSha256->Init(algo == XAR_CKSUM_SHA512); + stream = inStreamSha256; + } + inStreamLim->SetStream(stream); +} + +bool CInStreamWithHash::CheckHash(int algo, const Byte *digest_from_arc) const +{ + if (algo == XAR_CKSUM_SHA1) + { + Byte digest[SHA1_DIGEST_SIZE]; + inStreamSha1->Final(digest); + if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0) + return false; + } + else if (algo == XAR_CKSUM_SHA256) + { + Byte digest[SHA256_DIGEST_SIZE]; + inStreamSha256->Final256(digest); + if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0) + return false; + } + else if (algo == XAR_CKSUM_SHA512) + { + Byte digest[SHA512_DIGEST_SIZE]; + inStreamSha256->Final512(digest); + if (memcmp(digest, digest_from_arc, sizeof(digest)) != 0) + return false; + } + return true; +} + + +HRESULT CHandler::Open2(IInStream *stream) +{ + const unsigned kHeaderSize = 28; + UInt32 buf32[kHeaderSize / sizeof(UInt32)]; + RINOK(ReadStream_FALSE(stream, buf32, kHeaderSize)) + const unsigned headerSize = Get16((const Byte *)(const void *)buf32 + 4); + // xar library now writes 1 to version field. + // some old xars could have version == 0 ? + // specification allows (headerSize != 28), + // but we don't expect big value in (headerSize). + // so we restrict (headerSize) with 64 bytes to reduce false open. + const unsigned kHeaderSize_MAX = 64; + if (Get32(buf32) != 0x78617221 // signature: "xar!" + || headerSize < kHeaderSize + || headerSize > kHeaderSize_MAX + || Get16((const Byte *)(const void *)buf32 + 6) > 1 // version + ) + return S_FALSE; + _checkSumAlgo = Get32(buf32 + 6); + const UInt64 packSize = Get64(buf32 + 2); + const UInt64 unpackSize = Get64(buf32 + 4); + if (packSize >= kXmlPackSizeMax || + unpackSize >= kXmlSizeMax) + return S_FALSE; + /* some xar archives can have padding bytes at offset 28, + or checksum algorithm name at offset 28 (in xar fork, if cksum_alg==3) + But we didn't see such xar archives. + */ + if (headerSize != kHeaderSize) + { + RINOK(InStream_SeekSet(stream, headerSize)) + } + _dataStartPos = headerSize + packSize; + _phySize = _dataStartPos; + + _xmlBuf.Alloc((size_t)unpackSize + 1); + if (!_xmlBuf.IsAllocated()) + return E_OUTOFMEMORY; + _xmlLen = (size_t)unpackSize; + + CInStreamWithHash hashStream; + { + CMyComPtr2_Create zlibCoder; + hashStream.SetStreamAndInit(stream, (int)(unsigned)_checkSumAlgo); + hashStream.inStreamLim->Init(packSize); + CMyComPtr2_Create outStreamLim; + outStreamLim->Init(_xmlBuf, (size_t)unpackSize); + RINOK(zlibCoder.Interface()->Code(hashStream.inStreamLim, outStreamLim, NULL, &unpackSize, NULL)) + if (outStreamLim->GetPos() != (size_t)unpackSize) + return S_FALSE; + } + _xmlBuf[(size_t)unpackSize] = 0; + if (strlen((const char *)(const Byte *)_xmlBuf) != (size_t)unpackSize) + return S_FALSE; + CXml xml; + if (!xml.Parse((const char *)(const Byte *)_xmlBuf)) + return S_FALSE; + + if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1) + return S_FALSE; + const CXmlItem &toc = xml.Root.SubItems[0]; + if (!toc.IsTagged("toc")) + return S_FALSE; + + // CreationTime = ParseTime(toc, "creation-time", false); // z_IsRequied + CreationTime_String = toc.GetSubStringForTag("creation-time"); + { + // we suppose that offset of checksum is always 0; + // but [TOC].xml contains exact offset value in block. + const UInt64 offset = 0; + const unsigned hashSize = GetHashSize((int)(unsigned)_checkSumAlgo); + if (hashSize) + { + /* + const CXmlItem *csItem = toc.FindSubTag_GetPtr("checksum"); + if (csItem) + { + const int checkSumAlgo2 = Find_ChecksumId_for_Name(csItem->GetPropVal("style")); + UInt64 csSize, csOffset; + if (ParseUInt64(*csItem, "size", csSize) && + ParseUInt64(*csItem, "offset", csOffset) && + csSize == hashSize && + (unsigned)checkSumAlgo2 == _checkSumAlgo) + offset = csOffset; + } + */ + CByteBuffer digest_from_arc(hashSize); + RINOK(InStream_SeekSet(stream, _dataStartPos + offset)) + RINOK(ReadStream_FALSE(stream, digest_from_arc, hashSize)) + if (!hashStream.CheckHash((int)(unsigned)_checkSumAlgo, digest_from_arc)) + _toc_CrcError = true; + } + } + + if (!AddItem(toc, _files, + -1, // parent + 0)) // level + return S_FALSE; + + UInt64 totalPackSize = 0; + unsigned numMainFiles = 0; + + FOR_VECTOR (i, _files) + { + const CFile &file = _files[i]; + file.UpdateTotalPackSize(totalPackSize); + if (file.Parent == -1) + { + if (file.Name == "Payload" || file.Name == "Content") + { + _mainSubfile = (Int32)(int)i; + numMainFiles++; + } + else if (file.Name == "PackageInfo") + _is_pkg = true; + } + } + + if (numMainFiles > 1) + _mainSubfile = -1; + + const UInt64 k_PhySizeLim = (UInt64)1 << 62; + _phySize = (totalPackSize > k_PhySizeLim - _dataStartPos) ? + k_PhySizeLim : + _dataStartPos + totalPackSize; + + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + { + Close(); + RINOK(Open2(stream)) + _inStream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _phySize = 0; + _dataStartPos = 0; + _inStream.Release(); + _files.Clear(); + _xmlLen = 0; + _xmlBuf.Free(); + _mainSubfile = -1; + _is_pkg = false; + _toc_CrcError = false; + _checkSumAlgo = 0; + // CreationTime = 0; + CreationTime_String.Empty(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _files.Size() +#ifdef XAR_SHOW_RAW + + 1 +#endif + ; + return S_OK; +} + +static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop) +{ + if (t != 0) + { + FILETIME ft; + ft.dwLowDateTime = (UInt32)(t); + ft.dwHighDateTime = (UInt32)(t >> 32); + prop = ft; + } +} + +static void Utf8StringToProp(const AString &s, NCOM::CPropVariant &prop) +{ + if (!s.IsEmpty()) + { + UString us; + ConvertUTF8ToUnicode(s, us); + prop = us; + } +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + // case kpidHeadersSize: prop = _dataStartPos; break; + case kpidPhySize: prop = _phySize; break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + case kpidSubType: if (_is_pkg) prop = "pkg"; break; + case kpidExtension: prop = _is_pkg ? "pkg" : "xar"; break; + case kpidCTime: + { + // it's local time. We can transfer it to UTC time, if we use FILETIME. + // TimeToProp(CreationTime, prop); break; + if (!CreationTime_String.IsEmpty()) + prop = CreationTime_String; + break; + } + case kpidMethod: + { + AString s; + if (_checkSumAlgo < Z7_ARRAY_SIZE(k_ChecksumNames)) + s = k_ChecksumNames[_checkSumAlgo]; + else + { + s += "Checksum"; + s.Add_UInt32(_checkSumAlgo); + } + prop = s; + break; + } + case kpidWarningFlags: + { + UInt32 v = 0; + if (_toc_CrcError) v |= kpv_ErrorFlags_CrcError; + prop = v; + break; + } + case kpidINode: prop = true; break; + case kpidIsTree: prop = true; break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +/* +inline UInt32 MY_dev_major(UInt64 dev) +{ + return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff); +} +inline UInt32 MY_dev_minor(UInt64 dev) +{ + return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~(UInt32)0xff); +} +*/ + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + { + switch (propID) + { + case kpidName: + case kpidPath: + prop = "[TOC].xml"; break; + case kpidSize: + case kpidPackSize: prop = (UInt64)_xmlLen; break; + } + } + else +#endif + { + const CFile &item = _files[index]; + switch (propID) + { + case kpidPath: + { + AString path; + unsigned cur = index; + for (;;) + { + const CFile &item2 = _files[cur]; + if (!path.IsEmpty()) + path.InsertAtFront(CHAR_PATH_SEPARATOR); +// #define XAR_EMPTY_NAME_REPLACEMENT "[]" + if (item2.Name.IsEmpty()) + { + AString s('['); + s.Add_UInt32(cur); + s.Add_Char(']'); + path.Insert(0, s); + } + else + path.Insert(0, item2.Name); + if (item2.Parent < 0) + break; + cur = (unsigned)item2.Parent; + } + Utf8StringToProp(path, prop); + break; + } + + case kpidName: + { + if (item.Name.IsEmpty()) + { + AString s('['); + s.Add_UInt32(index); + s.Add_Char(']'); + prop = s; + } + else + Utf8StringToProp(item.Name, prop); + break; + } + + case kpidIsDir: prop = item.IsDir; break; + + case kpidSize: if (item.HasData && !item.IsDir) prop = item.Size; break; + case kpidPackSize: if (item.HasData && !item.IsDir) prop = item.PackSize; break; + + case kpidMethod: + { + if (item.HasData) + { + AString s = item.Method; + item.extracted_checksum.AddNameToString(s); + item.archived_checksum.AddNameToString(s); + Utf8StringToProp(s, prop); + } + break; + } + + case kpidMTime: TimeToProp(item.MTime, prop); break; + case kpidCTime: TimeToProp(item.CTime, prop); break; + case kpidATime: TimeToProp(item.ATime, prop); break; + + case kpidPosixAttrib: + if (item.Mode_Defined) + { + UInt32 mode = item.Mode; + if ((mode & MY_LIN_S_IFMT) == 0) + mode |= ( + item.Is_SymLink ? MY_LIN_S_IFLNK : + item.IsDir ? MY_LIN_S_IFDIR : + MY_LIN_S_IFREG); + prop = mode; + } + break; + + case kpidType: Utf8StringToProp(item.Type, prop); break; + case kpidUser: Utf8StringToProp(item.User, prop); break; + case kpidGroup: Utf8StringToProp(item.Group, prop); break; + case kpidSymLink: if (item.Is_SymLink) Utf8StringToProp(item.Link, prop); break; + + case kpidUserId: if (item.UserId_Defined) prop = item.UserId; break; + case kpidGroupId: if (item.GroupId_Defined) prop = item.GroupId; break; + case kpidINode: if (item.INode_Defined) prop = item.INode; break; + case kpidId: if (item.Id_Defined) prop = item.Id; break; + // Utf8StringToProp(item.Id, prop); + /* + case kpidDeviceMajor: if (item.Device_Defined) prop = (UInt32)MY_dev_major(item.Device); break; + case kpidDeviceMinor: if (item.Device_Defined) prop = (UInt32)MY_dev_minor(item.Device); break; + case kpidLinkType: + if (!item.LinkType.IsEmpty()) + Utf8StringToProp(item.LinkType, prop); + break; + case kpidLinkFrom: + if (!item.LinkFrom.IsEmpty()) + Utf8StringToProp(item.LinkFrom, prop); + break; + */ + case kpidOffset: + if (item.HasData) + prop = _dataStartPos + item.Offset; + break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +// for debug: +// #define Z7_XAR_SHOW_CHECKSUM_PACK + +#ifdef Z7_XAR_SHOW_CHECKSUM_PACK +enum +{ + kpidChecksumPack = kpidUserDefined +}; +#endif + +static const Byte kRawProps[] = +{ + kpidChecksum +#ifdef Z7_XAR_SHOW_CHECKSUM_PACK + , kpidCRC // instead of kpidUserDefined / kpidCRC +#endif +}; + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = Z7_ARRAY_SIZE(kRawProps); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) +{ + *propID = kRawProps[index]; + *name = NULL; + +#ifdef Z7_XAR_SHOW_CHECKSUM_PACK + if (index != 0) + { + *propID = kpidChecksumPack; + *name = NWindows::NCOM::AllocBstrFromAscii("archived-checksum"); + } +#endif + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + return S_OK; +#endif + { + const CFile &item = _files[index]; + *parent = (UInt32)(Int32)item.Parent; + } + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + // COM_TRY_BEGIN + NCOM::CPropVariant prop; + + if (propID == kpidChecksum) + { +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + { + // case kpidPath: prop = "[TOC].xml"; break; + } + else +#endif + { + const CFile &item = _files[index]; + const size_t size = item.extracted_checksum.Data.Size(); + if (size != 0) + { + *dataSize = (UInt32)size; + *propType = NPropDataType::kRaw; + *data = item.extracted_checksum.Data; + } + } + } + +#ifdef Z7_XAR_SHOW_CHECKSUM_PACK + if (propID == kpidChecksumPack) + { +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + { + // we can show digest check sum here + } + else +#endif + { + const CFile &item = _files[index]; + const size_t size = (UInt32)item.archived_checksum.Data.Size(); + if (size != 0) + { + *dataSize = (UInt32)size; + *propType = NPropDataType::kRaw; + *data = item.archived_checksum.Data; + } + } + } +#endif + return S_OK; +} + + + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _files.Size() +#ifdef XAR_SHOW_RAW + + 1 +#endif + ; + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + totalSize += _xmlLen; + else +#endif + totalSize += _files[index].Size; + } + RINOK(extractCallback->SetTotal(totalSize)) + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + CInStreamWithHash inHashStream; + CMyComPtr2_Create outStreamSha1; + CMyComPtr2_Create outStreamSha256; + CMyComPtr2_Create outStreamLim; + CMyComPtr2_Create copyCoder; + CMyComPtr2_Create zlibCoder; + CMyComPtr2_Create bzip2Coder; + bzip2Coder->FinishMode = true; + + UInt64 cur_PackSize, cur_UnpSize; + + for (i = 0;; i++, + lps->InSize += cur_PackSize, + lps->OutSize += cur_UnpSize) + { + cur_PackSize = 0; + cur_UnpSize = 0; + RINOK(lps->SetCur()) + if (i >= numItems) + break; + + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (index < _files.Size()) + { + const CFile &item = _files[index]; + if (item.IsDir) + { + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + continue; + } + } + + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + Int32 opRes = NExtract::NOperationResult::kOK; + +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + { + cur_PackSize = cur_UnpSize = _xmlLen; + if (realOutStream) + RINOK(WriteStream(realOutStream, _xmlBuf, _xmlLen)) + realOutStream.Release(); + } + else +#endif + { + const CFile &item = _files[index]; + if (!item.HasData) + realOutStream.Release(); + else + { + cur_PackSize = item.PackSize; + cur_UnpSize = item.Size; + + RINOK(InStream_SeekSet(_inStream, _dataStartPos + item.Offset)) + + inHashStream.SetStreamAndInit(_inStream, item.archived_checksum.AlgoNumber); + inHashStream.inStreamLim->Init(item.PackSize); + + const int checksum_method = item.extracted_checksum.AlgoNumber; + if (checksum_method == XAR_CKSUM_SHA1) + { + outStreamLim->SetStream(outStreamSha1); + outStreamSha1->SetStream(realOutStream); + outStreamSha1->Init(); + } + else if (checksum_method == XAR_CKSUM_SHA256 + || checksum_method == XAR_CKSUM_SHA512) + { + outStreamLim->SetStream(outStreamSha256); + outStreamSha256->SetStream(realOutStream); + outStreamSha256->Init(checksum_method == XAR_CKSUM_SHA512); + } + else + outStreamLim->SetStream(realOutStream); + + realOutStream.Release(); + + // outStreamSha1->Init(item.Sha1IsDefined); + + outStreamLim->Init(item.Size); + HRESULT res = S_OK; + + ICompressCoder *coder = NULL; + if (item.IsCopyMethod()) + { + if (item.PackSize == item.Size) + coder = copyCoder; + else + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else if (item.Method == METHOD_NAME_ZLIB) + coder = zlibCoder; + else if (item.Method == "bzip2") + coder = bzip2Coder; + else + opRes = NExtract::NOperationResult::kUnsupportedMethod; + + if (coder) + res = coder->Code(inHashStream.inStreamLim, outStreamLim, NULL, &item.Size, lps); + + if (res != S_OK) + { + if (!outStreamLim->IsFinishedOK()) + opRes = NExtract::NOperationResult::kDataError; + else if (res != S_FALSE) + return res; + if (opRes == NExtract::NOperationResult::kOK) + opRes = NExtract::NOperationResult::kDataError; + } + + if (opRes == NExtract::NOperationResult::kOK) + { + if (outStreamLim->IsFinishedOK()) + { + if (checksum_method == XAR_CKSUM_SHA1) + { + Byte digest[SHA1_DIGEST_SIZE]; + outStreamSha1->Final(digest); + if (memcmp(digest, item.extracted_checksum.Data, SHA1_DIGEST_SIZE) != 0) + opRes = NExtract::NOperationResult::kCRCError; + } + else if (checksum_method == XAR_CKSUM_SHA256) + { + Byte digest[SHA256_DIGEST_SIZE]; + outStreamSha256->Final256(digest); + if (memcmp(digest, item.extracted_checksum.Data, sizeof(digest)) != 0) + opRes = NExtract::NOperationResult::kCRCError; + } + else if (checksum_method == XAR_CKSUM_SHA512) + { + Byte digest[SHA512_DIGEST_SIZE]; + outStreamSha256->Final512(digest); + if (memcmp(digest, item.extracted_checksum.Data, sizeof(digest)) != 0) + opRes = NExtract::NOperationResult::kCRCError; + } + if (opRes == NExtract::NOperationResult::kOK) + if (!inHashStream.CheckHash( + item.archived_checksum.AlgoNumber, + item.archived_checksum.Data)) + opRes = NExtract::NOperationResult::kCRCError; + } + else + opRes = NExtract::NOperationResult::kDataError; + } + if (checksum_method == XAR_CKSUM_SHA1) + outStreamSha1->ReleaseStream(); + else if (checksum_method == XAR_CKSUM_SHA256) + outStreamSha256->ReleaseStream(); + } + outStreamLim->ReleaseStream(); + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + *stream = NULL; + COM_TRY_BEGIN +#ifdef XAR_SHOW_RAW + if (index >= _files.Size()) + { + Create_BufInStream_WithNewBuffer(_xmlBuf, _xmlLen, stream); + return S_OK; + } + else +#endif + { + const CFile &item = _files[index]; + if (item.HasData && item.IsCopyMethod() && item.PackSize == item.Size) + return CreateLimitedInStream(_inStream, _dataStartPos + item.Offset, item.Size, stream); + } + return S_FALSE; + COM_TRY_END +} + +// 0x1c == 28 is expected header size value for most archives. +// but we want to support another (rare case) headers sizes. +// so we must reduce signature to 4 or 5 bytes. +static const Byte k_Signature[] = +// { 'x', 'a', 'r', '!', 0, 0x1C, 0 }; + { 'x', 'a', 'r', '!', 0 }; + +REGISTER_ARC_I( + "Xar", "xar pkg xip", NULL, 0xE1, + k_Signature, + 0, + 0, + NULL) + +}} diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp index cce800a6a..907376c69 100644 --- a/CPP/7zip/Archive/XzHandler.cpp +++ b/CPP/7zip/Archive/XzHandler.cpp @@ -1,1440 +1,1440 @@ -// XzHandler.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../../Common/ComTry.h" -#include "../../Common/Defs.h" -#include "../../Common/IntToString.h" -#include "../../Common/MyBuffer.h" -#include "../../Common/StringToInt.h" - -#include "../../Windows/PropVariant.h" -#include "../../Windows/System.h" - -#include "../Common/CWrappers.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/XzDecoder.h" -#include "../Compress/XzEncoder.h" - -#include "IArchive.h" - -#include "Common/HandlerOut.h" - -using namespace NWindows; - -namespace NArchive { -namespace NXz { - -#define k_LZMA2_Name "LZMA2" - - -struct CBlockInfo -{ - unsigned StreamFlags; - UInt64 PackPos; - UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros - UInt64 UnpackPos; -}; - - -Z7_class_CHandler_final: - public IInArchive, - public IArchiveOpenSeq, - public IInArchiveGetStream, - public ISetProperties, - #ifndef Z7_EXTRACT_ONLY - public IOutArchive, - #endif - public CMyUnknownImp, - #ifndef Z7_EXTRACT_ONLY - public CMultiMethodProps - #else - public CCommonMethodProps - #endif -{ - Z7_COM_QI_BEGIN2(IInArchive) - Z7_COM_QI_ENTRY(IArchiveOpenSeq) - Z7_COM_QI_ENTRY(IInArchiveGetStream) - Z7_COM_QI_ENTRY(ISetProperties) - #ifndef Z7_EXTRACT_ONLY - Z7_COM_QI_ENTRY(IOutArchive) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInArchive) - Z7_IFACE_COM7_IMP(IArchiveOpenSeq) - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(ISetProperties) - #ifndef Z7_EXTRACT_ONLY - Z7_IFACE_COM7_IMP(IOutArchive) - #endif - - bool _stat_defined; - bool _stat2_defined; - bool _isArc; - bool _needSeekToStart; - bool _firstBlockWasRead; - SRes _stat2_decode_SRes; - - CXzStatInfo _stat; // it's stat from backward parsing - CXzStatInfo _stat2; // it's data from forward parsing, if the decoder was called - - const CXzStatInfo *GetStat() const - { - if (_stat_defined) return &_stat; - if (_stat2_defined) return &_stat2; - return NULL; - } - - AString _methodsString; - - - #ifndef Z7_EXTRACT_ONLY - - UInt32 _filterId; - UInt64 _numSolidBytes; - - void InitXz() - { - _filterId = 0; - _numSolidBytes = XZ_PROPS_BLOCK_SIZE_AUTO; - } - - #endif - - - void Init() - { - #ifndef Z7_EXTRACT_ONLY - InitXz(); - CMultiMethodProps::Init(); - #else - CCommonMethodProps::InitCommon(); - #endif - } - - HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); - - HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); - - HRESULT Decode(NCompress::NXz::CDecoder &decoder, - ISequentialInStream *seqInStream, - ISequentialOutStream *outStream, - ICompressProgressInfo *progress) - { - #ifndef Z7_ST - decoder._numThreads = _numThreads; - #endif - decoder._memUsage = _memUsage_Decompress; - - const HRESULT hres = decoder.Decode(seqInStream, outStream, - NULL, // *outSizeLimit - true, // finishStream - progress); - - if (decoder.MainDecodeSRes_wasUsed - && decoder.MainDecodeSRes != SZ_ERROR_MEM - && decoder.MainDecodeSRes != SZ_ERROR_UNSUPPORTED) - { - // if (!_stat2_defined) - { - _stat2_decode_SRes = decoder.MainDecodeSRes; - _stat2 = decoder.Stat; - _stat2_defined = true; - } - } - - if (hres == S_OK && progress) - { - // RINOK( - progress->SetRatioInfo(&decoder.Stat.InSize, &decoder.Stat.OutSize); - } - return hres; - } - -public: - CBlockInfo *_blocks; - size_t _blocksArraySize; - UInt64 _maxBlocksSize; - CMyComPtr _stream; - CMyComPtr _seqStream; - - CXzBlock _firstBlock; - - CHandler(); - ~CHandler(); - - HRESULT SeekToPackPos(UInt64 pos) - { - return InStream_SeekSet(_stream, pos); - } -}; - - -CHandler::CHandler(): - _blocks(NULL), - _blocksArraySize(0) -{ - #ifndef Z7_EXTRACT_ONLY - InitXz(); - #endif -} - -CHandler::~CHandler() -{ - MyFree(_blocks); -} - - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize, - kpidMethod -}; - -static const Byte kArcProps[] = -{ - kpidMethod, - kpidNumStreams, - kpidNumBlocks, - kpidClusterSize, - kpidCharacts -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -static void Lzma2PropToString(AString &s, unsigned prop) -{ - char c = 0; - UInt32 size; - if ((prop & 1) == 0) - size = prop / 2 + 12; - else - { - c = 'k'; - size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1); - if (prop > 17) - { - size >>= 10; - c = 'm'; - } - } - s.Add_UInt32(size); - if (c != 0) - s.Add_Char(c); -} - -struct CMethodNamePair -{ - UInt32 Id; - const char *Name; -}; - -static const CMethodNamePair g_NamePairs[] = -{ - { XZ_ID_Subblock, "SB" }, - { XZ_ID_Delta, "Delta" }, - { XZ_ID_X86, "BCJ" }, - { XZ_ID_PPC, "PPC" }, - { XZ_ID_IA64, "IA64" }, - { XZ_ID_ARM, "ARM" }, - { XZ_ID_ARMT, "ARMT" }, - { XZ_ID_SPARC, "SPARC" }, - { XZ_ID_ARM64, "ARM64" }, - { XZ_ID_RISCV, "RISCV" }, - { XZ_ID_LZMA2, "LZMA2" } -}; - -static void AddMethodString(AString &s, const CXzFilter &f) -{ - const char *p = NULL; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++) - if (g_NamePairs[i].Id == f.id) - { - p = g_NamePairs[i].Name; - break; - } - char temp[32]; - if (!p) - { - ::ConvertUInt64ToString(f.id, temp); - p = temp; - } - - s += p; - - if (f.propsSize > 0) - { - s.Add_Colon(); - if (f.id == XZ_ID_LZMA2 && f.propsSize == 1) - Lzma2PropToString(s, f.props[0]); - else if (f.id == XZ_ID_Delta && f.propsSize == 1) - s.Add_UInt32((UInt32)f.props[0] + 1); - else if (f.id == XZ_ID_ARM64 && f.propsSize == 1) - s.Add_UInt32((UInt32)f.props[0] + 16 + 2); - else - { - s.Add_Char('['); - for (UInt32 bi = 0; bi < f.propsSize; bi++) - { - const unsigned v = f.props[bi]; - s.Add_Char(GET_HEX_CHAR_UPPER(v >> 4)); - s.Add_Char(GET_HEX_CHAR_UPPER(v & 15)); - } - s.Add_Char(']'); - } - } -} - -static const char * const kChecks[] = -{ - "NoCheck" - , "CRC32" - , NULL - , NULL - , "CRC64" - , NULL - , NULL - , NULL - , NULL - , NULL - , "SHA256" - , NULL - , NULL - , NULL - , NULL - , NULL -}; - -static void AddCheckString(AString &s, const CXzs &xzs) -{ - size_t i; - UInt32 mask = 0; - for (i = 0; i < xzs.num; i++) - mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags)); - for (i = 0; i <= XZ_CHECK_MASK; i++) - if (((mask >> i) & 1) != 0) - { - s.Add_Space_if_NotEmpty(); - if (kChecks[i]) - s += kChecks[i]; - else - { - s += "Check-"; - s.Add_UInt32((UInt32)i); - } - } -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CXzStatInfo *stat = GetStat(); - - switch (propID) - { - case kpidPhySize: if (stat) prop = stat->InSize; break; - case kpidNumStreams: if (stat && stat->NumStreams_Defined) prop = stat->NumStreams; break; - case kpidNumBlocks: if (stat && stat->NumBlocks_Defined) prop = stat->NumBlocks; break; - case kpidUnpackSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break; - case kpidClusterSize: if (_stat_defined && _stat.NumBlocks_Defined && stat->NumBlocks > 1) prop = _maxBlocksSize; break; - case kpidCharacts: - if (_firstBlockWasRead) - { - AString s; - if (XzBlock_HasPackSize(&_firstBlock)) - s.Add_OptSpaced("BlockPackSize"); - if (XzBlock_HasUnpackSize(&_firstBlock)) - s.Add_OptSpaced("BlockUnpackSize"); - if (!s.IsEmpty()) - prop = s; - } - break; - - - case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; - case kpidErrorFlags: - { - UInt32 v = 0; - SRes sres = _stat2_decode_SRes; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - if (sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd; - if (_stat2_defined && _stat2.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; - if (sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError; - if (sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod; - if (sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError; - if (sres == SZ_ERROR_CRC) v |= kpv_ErrorFlags_CrcError; - if (v != 0) - prop = v; - break; - } - - case kpidMainSubfile: - { - // debug only, comment it: - // if (_blocks) prop = (UInt32)0; - break; - } - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - const CXzStatInfo *stat = GetStat(); - NCOM::CPropVariant prop; - switch (propID) - { - case kpidSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break; - case kpidPackSize: if (stat) prop = stat->InSize; break; - case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -struct COpenCallbackWrap -{ - ICompressProgress vt; - IArchiveOpenCallback *OpenCallback; - HRESULT Res; - - // new clang shows "non-POD" warning for offsetof(), if we use constructor instead of Init() - void Init(IArchiveOpenCallback *progress); -}; - -static SRes OpenCallbackProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 /* outSize */) -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(COpenCallbackWrap) - if (p->OpenCallback) - p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); - return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS); -} - -void COpenCallbackWrap::Init(IArchiveOpenCallback *callback) -{ - vt.Progress = OpenCallbackProgress; - OpenCallback = callback; - Res = SZ_OK; -} - - -struct CXzsCPP -{ - CXzs p; - CXzsCPP() { Xzs_Construct(&p); } - ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } -}; - -#define kInputBufSize ((size_t)1 << 10) - -struct CLookToRead2_CPP: public CLookToRead2 -{ - CLookToRead2_CPP() - { - buf = NULL; - LookToRead2_CreateVTable(this, - True // Lookahead ? - ); - } - void Alloc(size_t allocSize) - { - buf = (Byte *)MyAlloc(allocSize); - if (buf) - this->bufSize = allocSize; - } - ~CLookToRead2_CPP() - { - MyFree(buf); - } -}; - - -static HRESULT SRes_to_Open_HRESULT(SRes res) -{ - switch (res) - { - case SZ_OK: return S_OK; - case SZ_ERROR_MEM: return E_OUTOFMEMORY; - case SZ_ERROR_PROGRESS: return E_ABORT; - /* - case SZ_ERROR_UNSUPPORTED: - case SZ_ERROR_CRC: - case SZ_ERROR_DATA: - case SZ_ERROR_ARCHIVE: - case SZ_ERROR_NO_ARCHIVE: - return S_FALSE; - */ - default: break; - } - return S_FALSE; -} - - - -HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback) -{ - _needSeekToStart = true; - - { - CXzStreamFlags st; - CSeqInStreamWrap inStreamWrap; - - inStreamWrap.Init(inStream); - - SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt); - - if (inStreamWrap.Res != S_OK) - return inStreamWrap.Res; - if (res != SZ_OK) - return SRes_to_Open_HRESULT(res); - - { - CXzBlock block; - BoolInt isIndex; - UInt32 headerSizeRes; - - SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes); - - if (inStreamWrap.Res != S_OK) - return inStreamWrap.Res; - - if (res2 != SZ_OK) - { - if (res2 == SZ_ERROR_INPUT_EOF) - { - _stat2_decode_SRes = res2; - _stream = inStream; - _seqStream = inStream; - _isArc = true; - return S_OK; - } - - if (res2 == SZ_ERROR_ARCHIVE) - return S_FALSE; - } - else if (!isIndex) - { - _firstBlockWasRead = true; - _firstBlock = block; - - unsigned numFilters = XzBlock_GetNumFilters(&block); - for (unsigned i = 0; i < numFilters; i++) - { - _methodsString.Add_Space_if_NotEmpty(); - AddMethodString(_methodsString, block.filters[i]); - } - } - } - } - - RINOK(InStream_GetSize_SeekToEnd(inStream, _stat.InSize)) - if (callback) - { - RINOK(callback->SetTotal(NULL, &_stat.InSize)) - } - - CSeekInStreamWrap inStreamImp; - - inStreamImp.Init(inStream); - - CLookToRead2_CPP lookStream; - - lookStream.Alloc(kInputBufSize); - - if (!lookStream.buf) - return E_OUTOFMEMORY; - - lookStream.realStream = &inStreamImp.vt; - LookToRead2_INIT(&lookStream) - - COpenCallbackWrap openWrap; - openWrap.Init(callback); - - CXzsCPP xzs; - Int64 startPosition; - SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc); - if (res == SZ_ERROR_PROGRESS) - return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res; - /* - if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0) - res = SZ_OK; - */ - if (res == SZ_OK && startPosition == 0) - { - _stat_defined = true; - - _stat.OutSize = Xzs_GetUnpackSize(&xzs.p); - _stat.UnpackSize_Defined = true; - - _stat.NumStreams = xzs.p.num; - _stat.NumStreams_Defined = true; - - _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p); - _stat.NumBlocks_Defined = true; - - AddCheckString(_methodsString, xzs.p); - - const size_t numBlocks = (size_t)_stat.NumBlocks + 1; - const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo); - - if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1) - { - _blocks = (CBlockInfo *)MyAlloc(bytesAlloc); - if (_blocks) - { - unsigned blockIndex = 0; - UInt64 unpackPos = 0; - - for (size_t si = xzs.p.num; si != 0;) - { - si--; - const CXzStream &str = xzs.p.streams[si]; - UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE; - - for (size_t bi = 0; bi < str.numBlocks; bi++) - { - const CXzBlockSizes &bs = str.blocks[bi]; - const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3); - - if (bs.unpackSize != 0) - { - if (blockIndex >= _stat.NumBlocks) - return E_FAIL; - - CBlockInfo &block = _blocks[blockIndex++]; - block.StreamFlags = str.flags; - block.PackSize = bs.totalSize; // packSizeAligned; - block.PackPos = packPos; - block.UnpackPos = unpackPos; - } - packPos += packSizeAligned; - unpackPos += bs.unpackSize; - if (_maxBlocksSize < bs.unpackSize) - _maxBlocksSize = bs.unpackSize; - } - } - - /* - if (blockIndex != _stat.NumBlocks) - { - // there are Empty blocks; - } - */ - if (_stat.OutSize != unpackPos) - return E_FAIL; - CBlockInfo &block = _blocks[blockIndex++]; - block.StreamFlags = 0; - block.PackSize = 0; - block.PackPos = 0; - block.UnpackPos = unpackPos; - _blocksArraySize = blockIndex; - } - } - } - else - { - res = SZ_OK; - } - - RINOK(SRes_to_Open_HRESULT(res)) - - _stream = inStream; - _seqStream = inStream; - _isArc = true; - return S_OK; -} - - - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - { - Close(); - return Open2(inStream, callback); - } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - Close(); - _seqStream = stream; - _isArc = true; - _needSeekToStart = false; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - XzStatInfo_Clear(&_stat); - XzStatInfo_Clear(&_stat2); - _stat_defined = false; - _stat2_defined = false; - _stat2_decode_SRes = SZ_OK; - - _isArc = false; - _needSeekToStart = false; - _firstBlockWasRead = false; - - _methodsString.Empty(); - _stream.Release(); - _seqStream.Release(); - - MyFree(_blocks); - _blocks = NULL; - _blocksArraySize = 0; - _maxBlocksSize = 0; - - return S_OK; -} - - -struct CXzUnpackerCPP2 -{ - Byte *InBuf; - // Byte *OutBuf; - CXzUnpacker p; - - CXzUnpackerCPP2(); - ~CXzUnpackerCPP2(); -}; - -CXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL) - // , OutBuf(NULL) -{ - XzUnpacker_Construct(&p, &g_Alloc); -} - -CXzUnpackerCPP2::~CXzUnpackerCPP2() -{ - XzUnpacker_Free(&p); - MidFree(InBuf); - // MidFree(OutBuf); -} - - -Z7_CLASS_IMP_IInStream( - CInStream -) - - UInt64 _virtPos; -public: - UInt64 Size; - UInt64 _cacheStartPos; - size_t _cacheSize; - CByteBuffer _cache; - // UInt64 _startPos; - CXzUnpackerCPP2 xz; - - void InitAndSeek() - { - _virtPos = 0; - _cacheStartPos = 0; - _cacheSize = 0; - // _startPos = startPos; - } - - CMyComPtr2 _handlerSpec; - // ~CInStream(); -}; - -/* -CInStream::~CInStream() -{ - // _cache.Free(); -} -*/ - -static size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos) -{ - size_t left = 0, right = numBlocks; - for (;;) - { - size_t mid = (left + right) / 2; - if (mid == left) - return left; - if (pos < blocks[mid].UnpackPos) - right = mid; - else - left = mid; - } -} - - - -static HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu, - ISequentialInStream *seqInStream, - unsigned streamFlags, - UInt64 packSize, // pure size from Index record, it doesn't include pad zeros - size_t unpackSize, Byte *dest - // , ICompressProgressInfo *progress - ) -{ - const size_t kInBufSize = (size_t)1 << 16; - - XzUnpacker_Init(&xzu.p); - - if (!xzu.InBuf) - { - xzu.InBuf = (Byte *)MidAlloc(kInBufSize); - if (!xzu.InBuf) - return E_OUTOFMEMORY; - } - - xzu.p.streamFlags = (UInt16)streamFlags; - XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p); - - XzUnpacker_SetOutBuf(&xzu.p, dest, unpackSize); - - const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); - UInt64 packRem = packSizeAligned; - - UInt32 inSize = 0; - SizeT inPos = 0; - SizeT outPos = 0; - - HRESULT readRes = S_OK; - - for (;;) - { - if (inPos == inSize && readRes == S_OK) - { - inPos = 0; - inSize = 0; - UInt32 rem = kInBufSize; - if (rem > packRem) - rem = (UInt32)packRem; - if (rem != 0) - readRes = seqInStream->Read(xzu.InBuf, rem, &inSize); - } - - SizeT inLen = inSize - inPos; - SizeT outLen = unpackSize - outPos; - - ECoderStatus status; - - const SRes res = XzUnpacker_Code(&xzu.p, - // dest + outPos, - NULL, - &outLen, - xzu.InBuf + inPos, &inLen, - (inLen == 0), // srcFinished - CODER_FINISH_END, &status); - - // return E_OUTOFMEMORY; - // res = SZ_ERROR_CRC; - - if (res != SZ_OK) - { - if (res == SZ_ERROR_CRC) - return S_FALSE; - return SResToHRESULT(res); - } - - inPos += inLen; - outPos += outLen; - - packRem -= inLen; - - const BoolInt blockFinished = XzUnpacker_IsBlockFinished(&xzu.p); - - if ((inLen == 0 && outLen == 0) || blockFinished) - { - if (packRem != 0 || !blockFinished || unpackSize != outPos) - return S_FALSE; - if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize) - return S_FALSE; - return S_OK; - } - } -} - - -Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - COM_TRY_BEGIN - - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - - { - if (_virtPos >= Size) - return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL; - { - UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - } - - if (size == 0) - return S_OK; - - if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize) - { - const size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos); - const CBlockInfo &block = _handlerSpec->_blocks[bi]; - const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos; - if (_cache.Size() < unpackSize) - return E_FAIL; - - _cacheSize = 0; - - RINOK(_handlerSpec->SeekToPackPos(block.PackPos)) - RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize, - (size_t)unpackSize, _cache)) - _cacheStartPos = block.UnpackPos; - _cacheSize = (size_t)unpackSize; - } - - { - const size_t offset = (size_t)(_virtPos - _cacheStartPos); - const size_t rem = _cacheSize - offset; - if (size > rem) - size = (UInt32)rem; - memcpy(data, _cache.ConstData() + offset, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } - - COM_TRY_END -} - - -Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - - -static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40; - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - - *stream = NULL; - - if (index != 0) - return E_INVALIDARG; - - if (!_stat.UnpackSize_Defined - || _maxBlocksSize == 0 // 18.02 - || _maxBlocksSize > kMaxBlockSize_for_GetStream - || _maxBlocksSize != (size_t)_maxBlocksSize) - return S_FALSE; - - UInt64 memSize; - if (!NSystem::GetRamSize(memSize)) - memSize = (UInt64)(sizeof(size_t)) << 28; - { - if (_maxBlocksSize > memSize / 4) - return S_FALSE; - } - - CMyComPtr2 spec; - spec.Create_if_Empty(); - spec->_cache.Alloc((size_t)_maxBlocksSize); - spec->_handlerSpec.SetFromCls(this); - // spec->_handler = (IInArchive *)this; - spec->Size = _stat.OutSize; - spec->InitAndSeek(); - - *stream = spec.Detach(); - return S_OK; - - COM_TRY_END -} - - -static Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder) -{ - Int32 opRes; - SRes sres = decoder.MainDecodeSRes; - if (sres == SZ_ERROR_NO_ARCHIVE) // (!IsArc) - opRes = NExtract::NOperationResult::kIsNotArc; - else if (sres == SZ_ERROR_INPUT_EOF) // (UnexpectedEnd) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else if (decoder.Stat.DataAfterEnd) - opRes = NExtract::NOperationResult::kDataAfterEnd; - else if (sres == SZ_ERROR_CRC) // (CrcError) - opRes = NExtract::NOperationResult::kCRCError; - else if (sres == SZ_ERROR_UNSUPPORTED) // (Unsupported) - opRes = NExtract::NOperationResult::kUnsupportedMethod; - else if (sres == SZ_ERROR_ARCHIVE) // (HeadersError) - opRes = NExtract::NOperationResult::kDataError; - else if (sres == SZ_ERROR_DATA) // (DataError) - opRes = NExtract::NOperationResult::kDataError; - else if (sres != SZ_OK) - opRes = NExtract::NOperationResult::kDataError; - else - opRes = NExtract::NOperationResult::kOK; - return opRes; -} - - - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - - const CXzStatInfo *stat = GetStat(); - - if (stat) - RINOK(extractCallback->SetTotal(stat->InSize)) - - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)) - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(InStream_SeekToBegin(_stream)) - } - else - _needSeekToStart = true; - - - NCompress::NXz::CDecoder decoder; - - const HRESULT hres = Decode(decoder, _seqStream, realOutStream, lps); - - if (!decoder.MainDecodeSRes_wasUsed) - return hres == S_OK ? E_FAIL : hres; - - opRes = Get_Extract_OperationResult(decoder); - if (opRes == NExtract::NOperationResult::kOK - && hres != S_OK) - opRes = NExtract::NOperationResult::kDataError; - - // realOutStream.Release(); - } - return extractCallback->SetOperationResult(opRes); - COM_TRY_END -} - - - -#ifndef Z7_EXTRACT_ONLY - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) -{ - *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; - // *timeType = NFileTimeType::kUnix; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback)) -{ - COM_TRY_BEGIN - - if (numItems == 0) - { - CSeqOutStreamWrap seqOutStream; - seqOutStream.Init(outStream); - SRes res = Xz_EncodeEmpty(&seqOutStream.vt); - return SResToHRESULT(res); - } - - if (numItems != 1) - return E_INVALIDARG; - - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamSetRestriction, - setRestriction, outStream) - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - } - - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) - if (prop.vt != VT_EMPTY) - if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) - return E_INVALIDARG; - } - } - - if (IntToBool(newData)) - { - UInt64 dataSize; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - dataSize = prop.uhVal.QuadPart; - } - - CMyComPtr2_Create encoder; - - CXzProps &xzProps = encoder->xzProps; - CLzma2EncProps &lzma2Props = xzProps.lzma2Props; - - lzma2Props.lzmaProps.level = GetLevel(); - - xzProps.reduceSize = dataSize; - /* - { - NCOM::CPropVariant prop = (UInt64)dataSize; - RINOK(encoder->SetCoderProp(NCoderPropID::kReduceSize, prop)) - } - */ - - #ifndef Z7_ST - - UInt32 numThreads = _numThreads; - - const UInt32 kNumThreads_Max = 1024; - if (numThreads > kNumThreads_Max) - numThreads = kNumThreads_Max; - - if (!_numThreads_WasForced - && _numThreads >= 1 - && _memUsage_WasSet) - { - COneMethodInfo oneMethodInfo; - if (!_methods.IsEmpty()) - oneMethodInfo = _methods[0]; - - SetGlobalLevelTo(oneMethodInfo); - - const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); - if (!numThreads_WasSpecifiedInMethod) - { - // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already - CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads); - } - - UInt64 cs = _numSolidBytes; - if (cs != XZ_PROPS_BLOCK_SIZE_AUTO) - oneMethodInfo.AddProp_BlockSize2(cs); - cs = oneMethodInfo.Get_Xz_BlockSize(); - - if (cs != XZ_PROPS_BLOCK_SIZE_AUTO && - cs != XZ_PROPS_BLOCK_SIZE_SOLID) - { - const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); - const UInt32 numBlockThreads_Original = numThreads / lzmaThreads; - - if (numBlockThreads_Original > 1) - { - UInt32 numBlockThreads = numBlockThreads_Original; - { - const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); - for (; numBlockThreads > 1; numBlockThreads--) - { - UInt64 size = numBlockThreads * (lzmaMemUsage + cs); - UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; - if (cs < ((UInt32)1 << 26)) numPackChunks++; - if (cs < ((UInt32)1 << 24)) numPackChunks++; - if (cs < ((UInt32)1 << 22)) numPackChunks++; - size += numPackChunks * cs; - // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20)); - if (size <= _memUsage_Compress) - break; - } - } - if (numBlockThreads == 0) - numBlockThreads = 1; - if (numBlockThreads != numBlockThreads_Original) - numThreads = numBlockThreads * lzmaThreads; - } - } - } - xzProps.numTotalThreads = (int)numThreads; - - #endif // Z7_ST - - - xzProps.blockSize = _numSolidBytes; - if (_numSolidBytes == XZ_PROPS_BLOCK_SIZE_SOLID) - { - xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; - } - - RINOK(encoder->SetCheckSize(_crcSize)) - - { - CXzFilterProps &filter = xzProps.filterProps; - - if (_filterId == XZ_ID_Delta) - { - bool deltaDefined = false; - FOR_VECTOR (j, _filterMethod.Props) - { - const CProp &prop = _filterMethod.Props[j]; - if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4) - { - UInt32 delta = (UInt32)prop.Value.ulVal; - if (delta < 1 || delta > 256) - return E_INVALIDARG; - filter.delta = delta; - deltaDefined = true; - } - else - return E_INVALIDARG; - } - if (!deltaDefined) - return E_INVALIDARG; - } - filter.id = _filterId; - } - - FOR_VECTOR (i, _methods) - { - COneMethodInfo &m = _methods[i]; - - FOR_VECTOR (j, m.Props) - { - const CProp &prop = m.Props[j]; - RINOK(encoder->SetCoderProp(prop.Id, prop.Value)) - } - } - - { - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)) - if (!fileInStream) - return S_FALSE; - { - CMyComPtr streamGetSize; - fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize); - if (streamGetSize) - { - UInt64 size; - if (streamGetSize->GetSize(&size) == S_OK) - dataSize = size; - } - } - RINOK(updateCallback->SetTotal(dataSize)) - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) - } - - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveUpdateCallbackFile, - opCallback, updateCallback) - if (opCallback) - { - RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - { - const CXzStatInfo *stat = GetStat(); - if (stat) - { - RINOK(updateCallback->SetTotal(stat->InSize)) - } - RINOK(InStream_SeekToBegin(_stream)) - } - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - return NCompress::CopyStream(_stream, outStream, lps); - - COM_TRY_END -} - -#endif - - -HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) -{ - UString name = nameSpec; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - #ifndef Z7_EXTRACT_ONLY - - if (name[0] == L's') - { - const wchar_t *s = name.Ptr(1); - if (*s == 0) - { - bool useStr = false; - bool isSolid; - switch (value.vt) - { - case VT_EMPTY: isSolid = true; break; - case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; - case VT_BSTR: - if (!StringToBool(value.bstrVal, isSolid)) - useStr = true; - break; - default: return E_INVALIDARG; - } - if (!useStr) - { - _numSolidBytes = (isSolid ? XZ_PROPS_BLOCK_SIZE_SOLID : XZ_PROPS_BLOCK_SIZE_AUTO); - return S_OK; - } - } - return ParseSizeString(s, value, - 0, // percentsBase - _numSolidBytes) ? S_OK: E_INVALIDARG; - } - - return CMultiMethodProps::SetProperty(name, value); - - #else - - { - HRESULT hres; - if (SetCommonProperty(name, value, hres)) - return hres; - } - - return E_INVALIDARG; - - #endif -} - - - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - COM_TRY_BEGIN - - Init(); - - for (UInt32 i = 0; i < numProps; i++) - { - RINOK(SetProperty(names[i], values[i])) - } - - #ifndef Z7_EXTRACT_ONLY - - if (!_filterMethod.MethodName.IsEmpty()) - { - unsigned k; - for (k = 0; k < Z7_ARRAY_SIZE(g_NamePairs); k++) - { - const CMethodNamePair &pair = g_NamePairs[k]; - if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name)) - { - _filterId = pair.Id; - break; - } - } - if (k == Z7_ARRAY_SIZE(g_NamePairs)) - return E_INVALIDARG; - } - - _methods.DeleteFrontal(GetNumEmptyMethods()); - if (_methods.Size() > 1) - return E_INVALIDARG; - if (_methods.Size() == 1) - { - AString &methodName = _methods[0].MethodName; - if (methodName.IsEmpty()) - methodName = k_LZMA2_Name; - else if ( - !methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name) - && !methodName.IsEqualTo_Ascii_NoCase("xz")) - return E_INVALIDARG; - } - - #endif - - return S_OK; - - COM_TRY_END -} - - -REGISTER_ARC_IO( - "xz", "xz txz", "* .tar", 0xC, - XZ_SIG, 0 - , NArcInfoFlags::kKeepName - , 0 - , NULL) - -}} +// XzHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../../Common/ComTry.h" +#include "../../Common/Defs.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" +#include "../../Common/StringToInt.h" + +#include "../../Windows/PropVariant.h" +#include "../../Windows/System.h" + +#include "../Common/CWrappers.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/XzDecoder.h" +#include "../Compress/XzEncoder.h" + +#include "IArchive.h" + +#include "Common/HandlerOut.h" + +using namespace NWindows; + +namespace NArchive { +namespace NXz { + +#define k_LZMA2_Name "LZMA2" + + +struct CBlockInfo +{ + unsigned StreamFlags; + UInt64 PackPos; + UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros + UInt64 UnpackPos; +}; + + +Z7_class_CHandler_final: + public IInArchive, + public IArchiveOpenSeq, + public IInArchiveGetStream, + public ISetProperties, + #ifndef Z7_EXTRACT_ONLY + public IOutArchive, + #endif + public CMyUnknownImp, + #ifndef Z7_EXTRACT_ONLY + public CMultiMethodProps + #else + public CCommonMethodProps + #endif +{ + Z7_COM_QI_BEGIN2(IInArchive) + Z7_COM_QI_ENTRY(IArchiveOpenSeq) + Z7_COM_QI_ENTRY(IInArchiveGetStream) + Z7_COM_QI_ENTRY(ISetProperties) + #ifndef Z7_EXTRACT_ONLY + Z7_COM_QI_ENTRY(IOutArchive) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInArchive) + Z7_IFACE_COM7_IMP(IArchiveOpenSeq) + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(ISetProperties) + #ifndef Z7_EXTRACT_ONLY + Z7_IFACE_COM7_IMP(IOutArchive) + #endif + + bool _stat_defined; + bool _stat2_defined; + bool _isArc; + bool _needSeekToStart; + bool _firstBlockWasRead; + SRes _stat2_decode_SRes; + + CXzStatInfo _stat; // it's stat from backward parsing + CXzStatInfo _stat2; // it's data from forward parsing, if the decoder was called + + const CXzStatInfo *GetStat() const + { + if (_stat_defined) return &_stat; + if (_stat2_defined) return &_stat2; + return NULL; + } + + AString _methodsString; + + + #ifndef Z7_EXTRACT_ONLY + + UInt32 _filterId; + UInt64 _numSolidBytes; + + void InitXz() + { + _filterId = 0; + _numSolidBytes = XZ_PROPS_BLOCK_SIZE_AUTO; + } + + #endif + + + void Init() + { + #ifndef Z7_EXTRACT_ONLY + InitXz(); + CMultiMethodProps::Init(); + #else + CCommonMethodProps::InitCommon(); + #endif + } + + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value); + + HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback); + + HRESULT Decode(NCompress::NXz::CDecoder &decoder, + ISequentialInStream *seqInStream, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress) + { + #ifndef Z7_ST + decoder._numThreads = _numThreads; + #endif + decoder._memUsage = _memUsage_Decompress; + + const HRESULT hres = decoder.Decode(seqInStream, outStream, + NULL, // *outSizeLimit + true, // finishStream + progress); + + if (decoder.MainDecodeSRes_wasUsed + && decoder.MainDecodeSRes != SZ_ERROR_MEM + && decoder.MainDecodeSRes != SZ_ERROR_UNSUPPORTED) + { + // if (!_stat2_defined) + { + _stat2_decode_SRes = decoder.MainDecodeSRes; + _stat2 = decoder.Stat; + _stat2_defined = true; + } + } + + if (hres == S_OK && progress) + { + // RINOK( + progress->SetRatioInfo(&decoder.Stat.InSize, &decoder.Stat.OutSize); + } + return hres; + } + +public: + CBlockInfo *_blocks; + size_t _blocksArraySize; + UInt64 _maxBlocksSize; + CMyComPtr _stream; + CMyComPtr _seqStream; + + CXzBlock _firstBlock; + + CHandler(); + ~CHandler(); + + HRESULT SeekToPackPos(UInt64 pos) + { + return InStream_SeekSet(_stream, pos); + } +}; + + +CHandler::CHandler(): + _blocks(NULL), + _blocksArraySize(0) +{ + #ifndef Z7_EXTRACT_ONLY + InitXz(); + #endif +} + +CHandler::~CHandler() +{ + MyFree(_blocks); +} + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize, + kpidMethod +}; + +static const Byte kArcProps[] = +{ + kpidMethod, + kpidNumStreams, + kpidNumBlocks, + kpidClusterSize, + kpidCharacts +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +static void Lzma2PropToString(AString &s, unsigned prop) +{ + char c = 0; + UInt32 size; + if ((prop & 1) == 0) + size = prop / 2 + 12; + else + { + c = 'k'; + size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1); + if (prop > 17) + { + size >>= 10; + c = 'm'; + } + } + s.Add_UInt32(size); + if (c != 0) + s.Add_Char(c); +} + +struct CMethodNamePair +{ + UInt32 Id; + const char *Name; +}; + +static const CMethodNamePair g_NamePairs[] = +{ + { XZ_ID_Subblock, "SB" }, + { XZ_ID_Delta, "Delta" }, + { XZ_ID_X86, "BCJ" }, + { XZ_ID_PPC, "PPC" }, + { XZ_ID_IA64, "IA64" }, + { XZ_ID_ARM, "ARM" }, + { XZ_ID_ARMT, "ARMT" }, + { XZ_ID_SPARC, "SPARC" }, + { XZ_ID_ARM64, "ARM64" }, + { XZ_ID_RISCV, "RISCV" }, + { XZ_ID_LZMA2, "LZMA2" } +}; + +static void AddMethodString(AString &s, const CXzFilter &f) +{ + const char *p = NULL; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++) + if (g_NamePairs[i].Id == f.id) + { + p = g_NamePairs[i].Name; + break; + } + char temp[32]; + if (!p) + { + ::ConvertUInt64ToString(f.id, temp); + p = temp; + } + + s += p; + + if (f.propsSize > 0) + { + s.Add_Colon(); + if (f.id == XZ_ID_LZMA2 && f.propsSize == 1) + Lzma2PropToString(s, f.props[0]); + else if (f.id == XZ_ID_Delta && f.propsSize == 1) + s.Add_UInt32((UInt32)f.props[0] + 1); + else if (f.id == XZ_ID_ARM64 && f.propsSize == 1) + s.Add_UInt32((UInt32)f.props[0] + 16 + 2); + else + { + s.Add_Char('['); + for (UInt32 bi = 0; bi < f.propsSize; bi++) + { + const unsigned v = f.props[bi]; + s.Add_Char(GET_HEX_CHAR_UPPER(v >> 4)); + s.Add_Char(GET_HEX_CHAR_UPPER(v & 15)); + } + s.Add_Char(']'); + } + } +} + +static const char * const kChecks[] = +{ + "NoCheck" + , "CRC32" + , NULL + , NULL + , "CRC64" + , NULL + , NULL + , NULL + , NULL + , NULL + , "SHA256" + , NULL + , NULL + , NULL + , NULL + , NULL +}; + +static void AddCheckString(AString &s, const CXzs &xzs) +{ + size_t i; + UInt32 mask = 0; + for (i = 0; i < xzs.num; i++) + mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags)); + for (i = 0; i <= XZ_CHECK_MASK; i++) + if (((mask >> i) & 1) != 0) + { + s.Add_Space_if_NotEmpty(); + if (kChecks[i]) + s += kChecks[i]; + else + { + s += "Check-"; + s.Add_UInt32((UInt32)i); + } + } +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CXzStatInfo *stat = GetStat(); + + switch (propID) + { + case kpidPhySize: if (stat) prop = stat->InSize; break; + case kpidNumStreams: if (stat && stat->NumStreams_Defined) prop = stat->NumStreams; break; + case kpidNumBlocks: if (stat && stat->NumBlocks_Defined) prop = stat->NumBlocks; break; + case kpidUnpackSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break; + case kpidClusterSize: if (_stat_defined && _stat.NumBlocks_Defined && stat->NumBlocks > 1) prop = _maxBlocksSize; break; + case kpidCharacts: + if (_firstBlockWasRead) + { + AString s; + if (XzBlock_HasPackSize(&_firstBlock)) + s.Add_OptSpaced("BlockPackSize"); + if (XzBlock_HasUnpackSize(&_firstBlock)) + s.Add_OptSpaced("BlockUnpackSize"); + if (!s.IsEmpty()) + prop = s; + } + break; + + + case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; + case kpidErrorFlags: + { + UInt32 v = 0; + SRes sres = _stat2_decode_SRes; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_stat2_defined && _stat2.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + if (sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError; + if (sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod; + if (sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError; + if (sres == SZ_ERROR_CRC) v |= kpv_ErrorFlags_CrcError; + if (v != 0) + prop = v; + break; + } + + case kpidMainSubfile: + { + // debug only, comment it: + // if (_blocks) prop = (UInt32)0; + break; + } + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + const CXzStatInfo *stat = GetStat(); + NCOM::CPropVariant prop; + switch (propID) + { + case kpidSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break; + case kpidPackSize: if (stat) prop = stat->InSize; break; + case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break; + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +struct COpenCallbackWrap +{ + ICompressProgress vt; + IArchiveOpenCallback *OpenCallback; + HRESULT Res; + + // new clang shows "non-POD" warning for offsetof(), if we use constructor instead of Init() + void Init(IArchiveOpenCallback *progress); +}; + +static SRes OpenCallbackProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 /* outSize */) +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(COpenCallbackWrap) + if (p->OpenCallback) + p->Res = p->OpenCallback->SetCompleted(NULL, &inSize); + return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS); +} + +void COpenCallbackWrap::Init(IArchiveOpenCallback *callback) +{ + vt.Progress = OpenCallbackProgress; + OpenCallback = callback; + Res = SZ_OK; +} + + +struct CXzsCPP +{ + CXzs p; + CXzsCPP() { Xzs_Construct(&p); } + ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); } +}; + +#define kInputBufSize ((size_t)1 << 10) + +struct CLookToRead2_CPP: public CLookToRead2 +{ + CLookToRead2_CPP() + { + buf = NULL; + LookToRead2_CreateVTable(this, + True // Lookahead ? + ); + } + void Alloc(size_t allocSize) + { + buf = (Byte *)MyAlloc(allocSize); + if (buf) + this->bufSize = allocSize; + } + ~CLookToRead2_CPP() + { + MyFree(buf); + } +}; + + +static HRESULT SRes_to_Open_HRESULT(SRes res) +{ + switch (res) + { + case SZ_OK: return S_OK; + case SZ_ERROR_MEM: return E_OUTOFMEMORY; + case SZ_ERROR_PROGRESS: return E_ABORT; + /* + case SZ_ERROR_UNSUPPORTED: + case SZ_ERROR_CRC: + case SZ_ERROR_DATA: + case SZ_ERROR_ARCHIVE: + case SZ_ERROR_NO_ARCHIVE: + return S_FALSE; + */ + default: break; + } + return S_FALSE; +} + + + +HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback) +{ + _needSeekToStart = true; + + { + CXzStreamFlags st; + CSeqInStreamWrap inStreamWrap; + + inStreamWrap.Init(inStream); + + SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt); + + if (inStreamWrap.Res != S_OK) + return inStreamWrap.Res; + if (res != SZ_OK) + return SRes_to_Open_HRESULT(res); + + { + CXzBlock block; + BoolInt isIndex; + UInt32 headerSizeRes; + + SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes); + + if (inStreamWrap.Res != S_OK) + return inStreamWrap.Res; + + if (res2 != SZ_OK) + { + if (res2 == SZ_ERROR_INPUT_EOF) + { + _stat2_decode_SRes = res2; + _stream = inStream; + _seqStream = inStream; + _isArc = true; + return S_OK; + } + + if (res2 == SZ_ERROR_ARCHIVE) + return S_FALSE; + } + else if (!isIndex) + { + _firstBlockWasRead = true; + _firstBlock = block; + + unsigned numFilters = XzBlock_GetNumFilters(&block); + for (unsigned i = 0; i < numFilters; i++) + { + _methodsString.Add_Space_if_NotEmpty(); + AddMethodString(_methodsString, block.filters[i]); + } + } + } + } + + RINOK(InStream_GetSize_SeekToEnd(inStream, _stat.InSize)) + if (callback) + { + RINOK(callback->SetTotal(NULL, &_stat.InSize)) + } + + CSeekInStreamWrap inStreamImp; + + inStreamImp.Init(inStream); + + CLookToRead2_CPP lookStream; + + lookStream.Alloc(kInputBufSize); + + if (!lookStream.buf) + return E_OUTOFMEMORY; + + lookStream.realStream = &inStreamImp.vt; + LookToRead2_INIT(&lookStream) + + COpenCallbackWrap openWrap; + openWrap.Init(callback); + + CXzsCPP xzs; + Int64 startPosition; + SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc); + if (res == SZ_ERROR_PROGRESS) + return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res; + /* + if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0) + res = SZ_OK; + */ + if (res == SZ_OK && startPosition == 0) + { + _stat_defined = true; + + _stat.OutSize = Xzs_GetUnpackSize(&xzs.p); + _stat.UnpackSize_Defined = true; + + _stat.NumStreams = xzs.p.num; + _stat.NumStreams_Defined = true; + + _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p); + _stat.NumBlocks_Defined = true; + + AddCheckString(_methodsString, xzs.p); + + const size_t numBlocks = (size_t)_stat.NumBlocks + 1; + const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo); + + if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1) + { + _blocks = (CBlockInfo *)MyAlloc(bytesAlloc); + if (_blocks) + { + unsigned blockIndex = 0; + UInt64 unpackPos = 0; + + for (size_t si = xzs.p.num; si != 0;) + { + si--; + const CXzStream &str = xzs.p.streams[si]; + UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE; + + for (size_t bi = 0; bi < str.numBlocks; bi++) + { + const CXzBlockSizes &bs = str.blocks[bi]; + const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3); + + if (bs.unpackSize != 0) + { + if (blockIndex >= _stat.NumBlocks) + return E_FAIL; + + CBlockInfo &block = _blocks[blockIndex++]; + block.StreamFlags = str.flags; + block.PackSize = bs.totalSize; // packSizeAligned; + block.PackPos = packPos; + block.UnpackPos = unpackPos; + } + packPos += packSizeAligned; + unpackPos += bs.unpackSize; + if (_maxBlocksSize < bs.unpackSize) + _maxBlocksSize = bs.unpackSize; + } + } + + /* + if (blockIndex != _stat.NumBlocks) + { + // there are Empty blocks; + } + */ + if (_stat.OutSize != unpackPos) + return E_FAIL; + CBlockInfo &block = _blocks[blockIndex++]; + block.StreamFlags = 0; + block.PackSize = 0; + block.PackPos = 0; + block.UnpackPos = unpackPos; + _blocksArraySize = blockIndex; + } + } + } + else + { + res = SZ_OK; + } + + RINOK(SRes_to_Open_HRESULT(res)) + + _stream = inStream; + _seqStream = inStream; + _isArc = true; + return S_OK; +} + + + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + { + Close(); + return Open2(inStream, callback); + } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + Close(); + _seqStream = stream; + _isArc = true; + _needSeekToStart = false; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + XzStatInfo_Clear(&_stat); + XzStatInfo_Clear(&_stat2); + _stat_defined = false; + _stat2_defined = false; + _stat2_decode_SRes = SZ_OK; + + _isArc = false; + _needSeekToStart = false; + _firstBlockWasRead = false; + + _methodsString.Empty(); + _stream.Release(); + _seqStream.Release(); + + MyFree(_blocks); + _blocks = NULL; + _blocksArraySize = 0; + _maxBlocksSize = 0; + + return S_OK; +} + + +struct CXzUnpackerCPP2 +{ + Byte *InBuf; + // Byte *OutBuf; + CXzUnpacker p; + + CXzUnpackerCPP2(); + ~CXzUnpackerCPP2(); +}; + +CXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL) + // , OutBuf(NULL) +{ + XzUnpacker_Construct(&p, &g_Alloc); +} + +CXzUnpackerCPP2::~CXzUnpackerCPP2() +{ + XzUnpacker_Free(&p); + MidFree(InBuf); + // MidFree(OutBuf); +} + + +Z7_CLASS_IMP_IInStream( + CInStream +) + + UInt64 _virtPos; +public: + UInt64 Size; + UInt64 _cacheStartPos; + size_t _cacheSize; + CByteBuffer _cache; + // UInt64 _startPos; + CXzUnpackerCPP2 xz; + + void InitAndSeek() + { + _virtPos = 0; + _cacheStartPos = 0; + _cacheSize = 0; + // _startPos = startPos; + } + + CMyComPtr2 _handlerSpec; + // ~CInStream(); +}; + +/* +CInStream::~CInStream() +{ + // _cache.Free(); +} +*/ + +static size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos) +{ + size_t left = 0, right = numBlocks; + for (;;) + { + size_t mid = (left + right) / 2; + if (mid == left) + return left; + if (pos < blocks[mid].UnpackPos) + right = mid; + else + left = mid; + } +} + + + +static HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu, + ISequentialInStream *seqInStream, + unsigned streamFlags, + UInt64 packSize, // pure size from Index record, it doesn't include pad zeros + size_t unpackSize, Byte *dest + // , ICompressProgressInfo *progress + ) +{ + const size_t kInBufSize = (size_t)1 << 16; + + XzUnpacker_Init(&xzu.p); + + if (!xzu.InBuf) + { + xzu.InBuf = (Byte *)MidAlloc(kInBufSize); + if (!xzu.InBuf) + return E_OUTOFMEMORY; + } + + xzu.p.streamFlags = (UInt16)streamFlags; + XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p); + + XzUnpacker_SetOutBuf(&xzu.p, dest, unpackSize); + + const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3); + UInt64 packRem = packSizeAligned; + + UInt32 inSize = 0; + SizeT inPos = 0; + SizeT outPos = 0; + + HRESULT readRes = S_OK; + + for (;;) + { + if (inPos == inSize && readRes == S_OK) + { + inPos = 0; + inSize = 0; + UInt32 rem = kInBufSize; + if (rem > packRem) + rem = (UInt32)packRem; + if (rem != 0) + readRes = seqInStream->Read(xzu.InBuf, rem, &inSize); + } + + SizeT inLen = inSize - inPos; + SizeT outLen = unpackSize - outPos; + + ECoderStatus status; + + const SRes res = XzUnpacker_Code(&xzu.p, + // dest + outPos, + NULL, + &outLen, + xzu.InBuf + inPos, &inLen, + (inLen == 0), // srcFinished + CODER_FINISH_END, &status); + + // return E_OUTOFMEMORY; + // res = SZ_ERROR_CRC; + + if (res != SZ_OK) + { + if (res == SZ_ERROR_CRC) + return S_FALSE; + return SResToHRESULT(res); + } + + inPos += inLen; + outPos += outLen; + + packRem -= inLen; + + const BoolInt blockFinished = XzUnpacker_IsBlockFinished(&xzu.p); + + if ((inLen == 0 && outLen == 0) || blockFinished) + { + if (packRem != 0 || !blockFinished || unpackSize != outPos) + return S_FALSE; + if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize) + return S_FALSE; + return S_OK; + } + } +} + + +Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + COM_TRY_BEGIN + + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + + { + if (_virtPos >= Size) + return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL; + { + UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + } + + if (size == 0) + return S_OK; + + if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize) + { + const size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos); + const CBlockInfo &block = _handlerSpec->_blocks[bi]; + const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos; + if (_cache.Size() < unpackSize) + return E_FAIL; + + _cacheSize = 0; + + RINOK(_handlerSpec->SeekToPackPos(block.PackPos)) + RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize, + (size_t)unpackSize, _cache)) + _cacheStartPos = block.UnpackPos; + _cacheSize = (size_t)unpackSize; + } + + { + const size_t offset = (size_t)(_virtPos - _cacheStartPos); + const size_t rem = _cacheSize - offset; + if (size > rem) + size = (UInt32)rem; + memcpy(data, _cache.ConstData() + offset, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + COM_TRY_END +} + + +Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + + +static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40; + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + + *stream = NULL; + + if (index != 0) + return E_INVALIDARG; + + if (!_stat.UnpackSize_Defined + || _maxBlocksSize == 0 // 18.02 + || _maxBlocksSize > kMaxBlockSize_for_GetStream + || _maxBlocksSize != (size_t)_maxBlocksSize) + return S_FALSE; + + size_t memSize; + if (!NSystem::GetRamSize(memSize)) + memSize = (size_t)sizeof(size_t) << 28; + { + if (_maxBlocksSize > memSize / 4) + return S_FALSE; + } + + CMyComPtr2 spec; + spec.Create_if_Empty(); + spec->_cache.Alloc((size_t)_maxBlocksSize); + spec->_handlerSpec.SetFromCls(this); + // spec->_handler = (IInArchive *)this; + spec->Size = _stat.OutSize; + spec->InitAndSeek(); + + *stream = spec.Detach(); + return S_OK; + + COM_TRY_END +} + + +static Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder) +{ + Int32 opRes; + SRes sres = decoder.MainDecodeSRes; + if (sres == SZ_ERROR_NO_ARCHIVE) // (!IsArc) + opRes = NExtract::NOperationResult::kIsNotArc; + else if (sres == SZ_ERROR_INPUT_EOF) // (UnexpectedEnd) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else if (decoder.Stat.DataAfterEnd) + opRes = NExtract::NOperationResult::kDataAfterEnd; + else if (sres == SZ_ERROR_CRC) // (CrcError) + opRes = NExtract::NOperationResult::kCRCError; + else if (sres == SZ_ERROR_UNSUPPORTED) // (Unsupported) + opRes = NExtract::NOperationResult::kUnsupportedMethod; + else if (sres == SZ_ERROR_ARCHIVE) // (HeadersError) + opRes = NExtract::NOperationResult::kDataError; + else if (sres == SZ_ERROR_DATA) // (DataError) + opRes = NExtract::NOperationResult::kDataError; + else if (sres != SZ_OK) + opRes = NExtract::NOperationResult::kDataError; + else + opRes = NExtract::NOperationResult::kOK; + return opRes; +} + + + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + + const CXzStatInfo *stat = GetStat(); + + if (stat) + RINOK(extractCallback->SetTotal(stat->InSize)) + + UInt64 currentTotalPacked = 0; + RINOK(extractCallback->SetCompleted(¤tTotalPacked)) + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(InStream_SeekToBegin(_stream)) + } + else + _needSeekToStart = true; + + + NCompress::NXz::CDecoder decoder; + + const HRESULT hres = Decode(decoder, _seqStream, realOutStream, lps); + + if (!decoder.MainDecodeSRes_wasUsed) + return hres == S_OK ? E_FAIL : hres; + + opRes = Get_Extract_OperationResult(decoder); + if (opRes == NExtract::NOperationResult::kOK + && hres != S_OK) + opRes = NExtract::NOperationResult::kDataError; + + // realOutStream.Release(); + } + return extractCallback->SetOperationResult(opRes); + COM_TRY_END +} + + + +#ifndef Z7_EXTRACT_ONLY + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) +{ + *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // *timeType = NFileTimeType::kUnix; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback)) +{ + COM_TRY_BEGIN + + if (numItems == 0) + { + CSeqOutStreamWrap seqOutStream; + seqOutStream.Init(outStream); + SRes res = Xz_EncodeEmpty(&seqOutStream.vt); + return SResToHRESULT(res); + } + + if (numItems != 1) + return E_INVALIDARG; + + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamSetRestriction, + setRestriction, outStream) + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + } + + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) + if (prop.vt != VT_EMPTY) + if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 dataSize; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + dataSize = prop.uhVal.QuadPart; + } + + CMyComPtr2_Create encoder; + + CXzProps &xzProps = encoder->xzProps; + CLzma2EncProps &lzma2Props = xzProps.lzma2Props; + + lzma2Props.lzmaProps.level = GetLevel(); + + xzProps.reduceSize = dataSize; + /* + { + NCOM::CPropVariant prop = (UInt64)dataSize; + RINOK(encoder->SetCoderProp(NCoderPropID::kReduceSize, prop)) + } + */ + + #ifndef Z7_ST + + UInt32 numThreads = _numThreads; + + const UInt32 kNumThreads_Max = 1024; + if (numThreads > kNumThreads_Max) + numThreads = kNumThreads_Max; + + if (!_numThreads_WasForced + && _numThreads >= 1 + && _memUsage_WasSet) + { + COneMethodInfo oneMethodInfo; + if (!_methods.IsEmpty()) + oneMethodInfo = _methods[0]; + + SetGlobalLevelTo(oneMethodInfo); + + const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0); + if (!numThreads_WasSpecifiedInMethod) + { + // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already + CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads); + } + + UInt64 cs = _numSolidBytes; + if (cs != XZ_PROPS_BLOCK_SIZE_AUTO) + oneMethodInfo.AddProp_BlockSize2(cs); + cs = oneMethodInfo.Get_Xz_BlockSize(); + + if (cs != XZ_PROPS_BLOCK_SIZE_AUTO && + cs != XZ_PROPS_BLOCK_SIZE_SOLID) + { + const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads(); + const UInt32 numBlockThreads_Original = numThreads / lzmaThreads; + + if (numBlockThreads_Original > 1) + { + UInt32 numBlockThreads = numBlockThreads_Original; + { + const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); + for (; numBlockThreads > 1; numBlockThreads--) + { + UInt64 size = numBlockThreads * (lzmaMemUsage + cs); + UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; + if (cs < ((UInt32)1 << 26)) numPackChunks++; + if (cs < ((UInt32)1 << 24)) numPackChunks++; + if (cs < ((UInt32)1 << 22)) numPackChunks++; + size += numPackChunks * cs; + // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20)); + if (size <= _memUsage_Compress) + break; + } + } + if (numBlockThreads == 0) + numBlockThreads = 1; + if (numBlockThreads != numBlockThreads_Original) + numThreads = numBlockThreads * lzmaThreads; + } + } + } + xzProps.numTotalThreads = (int)numThreads; + + #endif // Z7_ST + + + xzProps.blockSize = _numSolidBytes; + if (_numSolidBytes == XZ_PROPS_BLOCK_SIZE_SOLID) + { + xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID; + } + + RINOK(encoder->SetCheckSize(_crcSize)) + + { + CXzFilterProps &filter = xzProps.filterProps; + + if (_filterId == XZ_ID_Delta) + { + bool deltaDefined = false; + FOR_VECTOR (j, _filterMethod.Props) + { + const CProp &prop = _filterMethod.Props[j]; + if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4) + { + UInt32 delta = (UInt32)prop.Value.ulVal; + if (delta < 1 || delta > 256) + return E_INVALIDARG; + filter.delta = delta; + deltaDefined = true; + } + else + return E_INVALIDARG; + } + if (!deltaDefined) + return E_INVALIDARG; + } + filter.id = _filterId; + } + + FOR_VECTOR (i, _methods) + { + COneMethodInfo &m = _methods[i]; + + FOR_VECTOR (j, m.Props) + { + const CProp &prop = m.Props[j]; + RINOK(encoder->SetCoderProp(prop.Id, prop.Value)) + } + } + + { + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)) + if (!fileInStream) + return S_FALSE; + { + CMyComPtr streamGetSize; + fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + UInt64 size; + if (streamGetSize->GetSize(&size) == S_OK) + dataSize = size; + } + } + RINOK(updateCallback->SetTotal(dataSize)) + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) + } + + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveUpdateCallbackFile, + opCallback, updateCallback) + if (opCallback) + { + RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + { + const CXzStatInfo *stat = GetStat(); + if (stat) + { + RINOK(updateCallback->SetTotal(stat->InSize)) + } + RINOK(InStream_SeekToBegin(_stream)) + } + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + return NCompress::CopyStream(_stream, outStream, lps); + + COM_TRY_END +} + +#endif + + +HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + #ifndef Z7_EXTRACT_ONLY + + if (name[0] == L's') + { + const wchar_t *s = name.Ptr(1); + if (*s == 0) + { + bool useStr = false; + bool isSolid; + switch (value.vt) + { + case VT_EMPTY: isSolid = true; break; + case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; + case VT_BSTR: + if (!StringToBool(value.bstrVal, isSolid)) + useStr = true; + break; + default: return E_INVALIDARG; + } + if (!useStr) + { + _numSolidBytes = (isSolid ? XZ_PROPS_BLOCK_SIZE_SOLID : XZ_PROPS_BLOCK_SIZE_AUTO); + return S_OK; + } + } + return ParseSizeString(s, value, + 0, // percentsBase + _numSolidBytes) ? S_OK: E_INVALIDARG; + } + + return CMultiMethodProps::SetProperty(name, value); + + #else + + { + HRESULT hres; + if (SetCommonProperty(name, value, hres)) + return hres; + } + + return E_INVALIDARG; + + #endif +} + + + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + COM_TRY_BEGIN + + Init(); + + for (UInt32 i = 0; i < numProps; i++) + { + RINOK(SetProperty(names[i], values[i])) + } + + #ifndef Z7_EXTRACT_ONLY + + if (!_filterMethod.MethodName.IsEmpty()) + { + unsigned k; + for (k = 0; k < Z7_ARRAY_SIZE(g_NamePairs); k++) + { + const CMethodNamePair &pair = g_NamePairs[k]; + if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name)) + { + _filterId = pair.Id; + break; + } + } + if (k == Z7_ARRAY_SIZE(g_NamePairs)) + return E_INVALIDARG; + } + + _methods.DeleteFrontal(GetNumEmptyMethods()); + if (_methods.Size() > 1) + return E_INVALIDARG; + if (_methods.Size() == 1) + { + AString &methodName = _methods[0].MethodName; + if (methodName.IsEmpty()) + methodName = k_LZMA2_Name; + else if ( + !methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name) + && !methodName.IsEqualTo_Ascii_NoCase("xz")) + return E_INVALIDARG; + } + + #endif + + return S_OK; + + COM_TRY_END +} + + +REGISTER_ARC_IO( + "xz", "xz txz", "* .tar", 0xC, + XZ_SIG, 0 + , NArcInfoFlags::kKeepName + , 0 + , NULL) + +}} diff --git a/CPP/7zip/Archive/XzHandler.h b/CPP/7zip/Archive/XzHandler.h index d6780787d..4d0995489 100644 --- a/CPP/7zip/Archive/XzHandler.h +++ b/CPP/7zip/Archive/XzHandler.h @@ -1,11 +1,11 @@ -// XzHandler.h - -#ifndef ZIP7_INC_XZ_HANDLER_H -#define ZIP7_INC_XZ_HANDLER_H - -namespace NArchive { -namespace NXz { - -}} - -#endif +// XzHandler.h + +#ifndef ZIP7_INC_XZ_HANDLER_H +#define ZIP7_INC_XZ_HANDLER_H + +namespace NArchive { +namespace NXz { + +}} + +#endif diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp index b95416c3e..1caef3450 100644 --- a/CPP/7zip/Archive/ZHandler.cpp +++ b/CPP/7zip/Archive/ZHandler.cpp @@ -1,225 +1,225 @@ -// ZHandler.cpp - -#include "StdAfx.h" - -#include "../../Common/ComTry.h" - -#include "../../Windows/PropVariant.h" - -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/ZDecoder.h" - -#include "Common/DummyOutStream.h" - -namespace NArchive { -namespace NZ { - -Z7_CLASS_IMP_CHandler_IInArchive_0 - - CMyComPtr _stream; - UInt64 _packSize; - // UInt64 _unpackSize; - // bool _unpackSize_Defined; -}; - -static const Byte kProps[] = -{ - kpidPackSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySizeCantBeDetected: prop = true; break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - // case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break; - case kpidPackSize: prop = _packSize; break; - } - prop.Detach(value); - return S_OK; -} - -/* -Z7_CLASS_IMP_COM_1( - CCompressProgressInfoImp - , ICompressProgressInfo -) - CMyComPtr Callback; -public: - void Init(IArchiveOpenCallback *callback) { Callback = callback; } -}; - -Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - outSize = outSize; - if (Callback) - { - const UInt64 files = 1; - return Callback->SetCompleted(&files, inSize); - } - return S_OK; -} -*/ - -API_FUNC_static_IsArc IsArc_Z(const Byte *p, size_t size) -{ - if (size < 3) - return k_IsArc_Res_NEED_MORE; - if (size > NCompress::NZ::kRecommendedCheckSize) - size = NCompress::NZ::kRecommendedCheckSize; - if (!NCompress::NZ::CheckStream(p, size)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; -} -} - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, - const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openCallback */)) -{ - COM_TRY_BEGIN - { - // RINOK(InStream_GetPos(stream, _streamStartPosition)); - Byte buffer[NCompress::NZ::kRecommendedCheckSize]; - // Byte buffer[1500]; - size_t size = NCompress::NZ::kRecommendedCheckSize; - // size = 700; - RINOK(ReadStream(stream, buffer, &size)) - if (!NCompress::NZ::CheckStream(buffer, size)) - return S_FALSE; - - UInt64 endPos; - RINOK(InStream_GetSize_SeekToEnd(stream, endPos)) - _packSize = endPos; - - /* - bool fullCheck = false; - if (fullCheck) - { - CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp; - CMyComPtr compressProgress = compressProgressSpec; - compressProgressSpec->Init(openCallback); - - NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; - CMyComPtr decoder = decoderSpec; - - CDummyOutStream *outStreamSpec = new CDummyOutStream; - CMyComPtr outStream(outStreamSpec); - outStreamSpec->SetStream(NULL); - outStreamSpec->Init(); - decoderSpec->SetProp(_prop); - if (openCallback) - { - UInt64 files = 1; - RINOK(openCallback->SetTotal(&files, &endPos)); - } - RINOK(InStream_SeekSet(stream, _streamStartPosition + kSignatureSize)) - HRESULT res = decoder->Code(stream, outStream, NULL, NULL, openCallback ? compressProgress : NULL); - if (res != S_OK) - return S_FALSE; - _packSize = decoderSpec->PackSize; - } - */ - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _packSize = 0; - // _unpackSize_Defined = false; - _stream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - RINOK(extractCallback->SetTotal(_packSize)) - UInt64 currentTotalPacked = 0; - RINOK(extractCallback->SetCompleted(¤tTotalPacked)) - - int opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - - if (!testMode && !realOutStream) - return S_OK; - - RINOK(extractCallback->PrepareOperation(askMode)) - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(); - // realOutStream.Release(); - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - - RINOK(InStream_SeekToBegin(_stream)) - - NCompress::NZ::CDecoder decoder; - { - const HRESULT hres = decoder.Code(_stream, outStream, lps); - if (hres == S_FALSE) - opRes = NExtract::NOperationResult::kDataError; - else - { - RINOK(hres) - opRes = NExtract::NOperationResult::kOK; - } - } - // _unpackSize = outStreamSpec->GetSize(); - // _unpackSize_Defined = true; - // outStream.Release(); - } - return extractCallback->SetOperationResult(opRes); - COM_TRY_END -} - -static const Byte k_Signature[] = { 0x1F, 0x9D }; - -REGISTER_ARC_I( - "Z", "z taz", "* .tar", 5, - k_Signature, - 0, - 0, - IsArc_Z) - -}} +// ZHandler.cpp + +#include "StdAfx.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariant.h" + +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/ZDecoder.h" + +#include "Common/DummyOutStream.h" + +namespace NArchive { +namespace NZ { + +Z7_CLASS_IMP_CHandler_IInArchive_0 + + CMyComPtr _stream; + UInt64 _packSize; + // UInt64 _unpackSize; + // bool _unpackSize_Defined; +}; + +static const Byte kProps[] = +{ + kpidPackSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO_Table + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySizeCantBeDetected: prop = true; break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + // case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidPackSize: prop = _packSize; break; + } + prop.Detach(value); + return S_OK; +} + +/* +Z7_CLASS_IMP_COM_1( + CCompressProgressInfoImp + , ICompressProgressInfo +) + CMyComPtr Callback; +public: + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + outSize = outSize; + if (Callback) + { + const UInt64 files = 1; + return Callback->SetCompleted(&files, inSize); + } + return S_OK; +} +*/ + +API_FUNC_static_IsArc IsArc_Z(const Byte *p, size_t size) +{ + if (size < 3) + return k_IsArc_Res_NEED_MORE; + if (size > NCompress::NZ::kRecommendedCheckSize) + size = NCompress::NZ::kRecommendedCheckSize; + if (!NCompress::NZ::CheckStream(p, size)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openCallback */)) +{ + COM_TRY_BEGIN + { + // RINOK(InStream_GetPos(stream, _streamStartPosition)); + Byte buffer[NCompress::NZ::kRecommendedCheckSize]; + // Byte buffer[1500]; + size_t size = NCompress::NZ::kRecommendedCheckSize; + // size = 700; + RINOK(ReadStream(stream, buffer, &size)) + if (!NCompress::NZ::CheckStream(buffer, size)) + return S_FALSE; + + UInt64 endPos; + RINOK(InStream_GetSize_SeekToEnd(stream, endPos)) + _packSize = endPos; + + /* + bool fullCheck = false; + if (fullCheck) + { + CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp; + CMyComPtr compressProgress = compressProgressSpec; + compressProgressSpec->Init(openCallback); + + NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder; + CMyComPtr decoder = decoderSpec; + + CDummyOutStream *outStreamSpec = new CDummyOutStream; + CMyComPtr outStream(outStreamSpec); + outStreamSpec->SetStream(NULL); + outStreamSpec->Init(); + decoderSpec->SetProp(_prop); + if (openCallback) + { + UInt64 files = 1; + RINOK(openCallback->SetTotal(&files, &endPos)); + } + RINOK(InStream_SeekSet(stream, _streamStartPosition + kSignatureSize)) + HRESULT res = decoder->Code(stream, outStream, NULL, NULL, openCallback ? compressProgress : NULL); + if (res != S_OK) + return S_FALSE; + _packSize = decoderSpec->PackSize; + } + */ + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _packSize = 0; + // _unpackSize_Defined = false; + _stream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + RINOK(extractCallback->SetTotal(_packSize)) + UInt64 currentTotalPacked = 0; + RINOK(extractCallback->SetCompleted(¤tTotalPacked)) + + int opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + + if (!testMode && !realOutStream) + return S_OK; + + RINOK(extractCallback->PrepareOperation(askMode)) + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(); + // realOutStream.Release(); + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + + RINOK(InStream_SeekToBegin(_stream)) + + NCompress::NZ::CDecoder decoder; + { + const HRESULT hres = decoder.Code(_stream, outStream, lps); + if (hres == S_FALSE) + opRes = NExtract::NOperationResult::kDataError; + else + { + RINOK(hres) + opRes = NExtract::NOperationResult::kOK; + } + } + // _unpackSize = outStreamSpec->GetSize(); + // _unpackSize_Defined = true; + // outStream.Release(); + } + return extractCallback->SetOperationResult(opRes); + COM_TRY_END +} + +static const Byte k_Signature[] = { 0x1F, 0x9D }; + +REGISTER_ARC_I( + "Z", "z taz", "* .tar", 5, + k_Signature, + 0, + 0, + IsArc_Z) + +}} diff --git a/CPP/7zip/Archive/Zip/StdAfx.h b/CPP/7zip/Archive/Zip/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Archive/Zip/StdAfx.h +++ b/CPP/7zip/Archive/Zip/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index b3d76e596..43d68c731 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -1,484 +1,484 @@ -// ZipAddCommon.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" -#include "../../../../C/Alloc.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../ICoder.h" -#include "../../IPassword.h" -#include "../../MyVersion.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/LzmaEncoder.h" -#include "../../Compress/PpmdZip.h" -#include "../../Compress/XzEncoder.h" - -#include "../Common/InStreamWithCRC.h" - -#include "ZipAddCommon.h" -#include "ZipHeader.h" - -namespace NArchive { -namespace NZip { - -using namespace NFileHeader; - - -static const unsigned kLzmaPropsSize = 5; -static const unsigned kLzmaHeaderSize = 4 + kLzmaPropsSize; - -Z7_CLASS_IMP_NOQIB_3( - CLzmaEncoder - , ICompressCoder - , ICompressSetCoderProperties - , ICompressSetCoderPropertiesOpt -) -public: - CMyComPtr2 Encoder; - Byte Header[kLzmaHeaderSize]; -}; - -Z7_COM7F_IMF(CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -{ - Encoder.Create_if_Empty(); - CMyComPtr2_Create outStream; - outStream->Init(Header + 4, kLzmaPropsSize); - RINOK(Encoder->SetCoderProperties(propIDs, props, numProps)) - RINOK(Encoder->WriteCoderProperties(outStream)) - if (outStream->GetPos() != kLzmaPropsSize) - return E_FAIL; - Header[0] = MY_VER_MAJOR; - Header[1] = MY_VER_MINOR; - Header[2] = kLzmaPropsSize; - Header[3] = 0; - return S_OK; -} - -Z7_COM7F_IMF(CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -{ - return Encoder->SetCoderPropertiesOpt(propIDs, props, numProps); -} - -Z7_COM7F_IMF(CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - RINOK(WriteStream(outStream, Header, kLzmaHeaderSize)) - return Encoder.Interface()->Code(inStream, outStream, inSize, outSize, progress); -} - - -CAddCommon::CAddCommon(): - _isLzmaEos(false), - _buf(NULL) - {} - -void CAddCommon::SetOptions(const CCompressionMethodMode &options) -{ - _options = options; -} - -CAddCommon::~CAddCommon() -{ - MidFree(_buf); -} - -static const UInt32 kBufSize = ((UInt32)1 << 16); - -HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) -{ - if (!_buf) - { - _buf = (Byte *)MidAlloc(kBufSize); - if (!_buf) - return E_OUTOFMEMORY; - } - - UInt32 crc = CRC_INIT_VAL; - for (;;) - { - UInt32 processed; - RINOK(inStream->Read(_buf, kBufSize, &processed)) - if (processed == 0) - { - resultCRC = CRC_GET_DIGEST(crc); - return S_OK; - } - crc = CrcUpdate(crc, _buf, (size_t)processed); - } -} - - -HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize, - CCompressingResult &opRes) const -{ - // We use Zip64, if unPackSize size is larger than 0xF8000000 to support - // cases when compressed size can be about 3% larger than uncompressed size - - const UInt32 kUnpackZip64Limit = 0xF8000000; - - opRes.UnpackSize = unpackSize; - opRes.PackSize = (UInt64)1 << 60; // we use big value to force Zip64 mode. - - if (unpackSize < kUnpackZip64Limit) - opRes.PackSize = (UInt32)0xFFFFFFFF - 1; // it will not use Zip64 for that size - - if (opRes.PackSize < unpackSize) - opRes.PackSize = unpackSize; - - const Byte method = _options.MethodSequence[0]; - - if (method == NCompressionMethod::kStore && !_options.Password_Defined) - opRes.PackSize = unpackSize; - - opRes.CRC = 0; - - opRes.LzmaEos = false; - - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; - opRes.DescriptorMode = outSeqMode; - - if (_options.Password_Defined) - { - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; - if (_options.IsAesMode) - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; - else - { - if (inSeqMode) - opRes.DescriptorMode = true; - } - } - - opRes.Method = method; - Byte ver = 0; - - switch (method) - { - case NCompressionMethod::kStore: break; - case NCompressionMethod::kDeflate: ver = NCompressionMethod::kExtractVersion_Deflate; break; - case NCompressionMethod::kDeflate64: ver = NCompressionMethod::kExtractVersion_Deflate64; break; - case NCompressionMethod::kXz : ver = NCompressionMethod::kExtractVersion_Xz; break; - case NCompressionMethod::kPPMd : ver = NCompressionMethod::kExtractVersion_PPMd; break; - case NCompressionMethod::kBZip2: ver = NCompressionMethod::kExtractVersion_BZip2; break; - case NCompressionMethod::kLZMA : - { - ver = NCompressionMethod::kExtractVersion_LZMA; - const COneMethodInfo *oneMethodMain = &_options._methods[0]; - opRes.LzmaEos = oneMethodMain->Get_Lzma_Eos(); - break; - } - default: break; - } - if (opRes.ExtractVersion < ver) - opRes.ExtractVersion = ver; - - return S_OK; -} - - -HRESULT CAddCommon::Compress( - DECL_EXTERNAL_CODECS_LOC_VARS - ISequentialInStream *inStream, IOutStream *outStream, - bool inSeqMode, bool outSeqMode, - UInt32 fileTime, - UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed, - ICompressProgressInfo *progress, CCompressingResult &opRes) -{ - // opRes.LzmaEos = false; - - if (!inStream) - { - // We can create empty stream here. But it was already implemented in caller code in 9.33+ - return E_INVALIDARG; - } - - CMyComPtr2_Create inCrcStream; - - CMyComPtr inStream2; - if (!inSeqMode) - { - inStream->QueryInterface(IID_IInStream, (void **)&inStream2); - if (!inStream2) - { - // inSeqMode = true; - // inSeqMode must be correct before - return E_FAIL; - } - } - - inCrcStream->SetStream(inStream); - inCrcStream->SetFullSize(expectedDataSize_IsConfirmed ? expectedDataSize : (UInt64)(Int64)-1); - // inCrcStream->Init(); - - unsigned numTestMethods = _options.MethodSequence.Size(); - // numTestMethods != 0 - - bool descriptorMode = outSeqMode; - - // ZipCrypto without descriptor requires additional reading pass for - // inStream to calculate CRC for password check field. - // The descriptor allows to use ZipCrypto check field without CRC (InfoZip's modification). - - if (!outSeqMode) - if (inSeqMode && _options.Password_Defined && !_options.IsAesMode) - descriptorMode = true; - opRes.DescriptorMode = descriptorMode; - - if (numTestMethods > 1) - if (inSeqMode || outSeqMode || !inStream2) - numTestMethods = 1; - - UInt32 crc = 0; - bool crc_IsCalculated = false; - - CFilterCoder::C_OutStream_Releaser outStreamReleaser; - // opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; - - for (unsigned i = 0; i < numTestMethods; i++) - { - inCrcStream->Init(); - - if (i != 0) - { - // if (inStream2) - { - RINOK(InStream_SeekToBegin(inStream2)) - } - RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)) - RINOK(outStream->SetSize(0)) - } - - opRes.LzmaEos = false; - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; - - const Byte method = _options.MethodSequence[i]; - if (method == NCompressionMethod::kStore && descriptorMode) - { - // we still can create descriptor_mode archives with "Store" method, but they are not good for 100% - return E_NOTIMPL; - } - - bool needCode = true; - - if (_options.Password_Defined) - { - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; - - if (!_cryptoStream.IsDefined()) - _cryptoStream.SetFromCls(new CFilterCoder(true)); - - if (_options.IsAesMode) - { - opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; - if (!_cryptoStream->Filter) - { - _cryptoStream->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder; - _filterAesSpec->SetKeyMode(_options.AesKeyMode); - RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len())) - } - RINOK(_filterAesSpec->WriteHeader(outStream)) - } - else - { - if (!_cryptoStream->Filter) - { - _cryptoStream->Filter = _filterSpec = new NCrypto::NZip::CEncoder; - _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()); - } - - UInt32 check; - - if (descriptorMode) - { - // it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set) - check = (fileTime & 0xFFFF); - } - else - { - if (!crc_IsCalculated) - { - RINOK(CalcStreamCRC(inStream, crc)) - crc_IsCalculated = true; - RINOK(InStream_SeekToBegin(inStream2)) - inCrcStream->Init(); - } - check = (crc >> 16); - } - - RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)) - } - - if (method == NCompressionMethod::kStore) - { - needCode = false; - RINOK(_cryptoStream->Code(inCrcStream, outStream, NULL, NULL, progress)) - } - else - { - RINOK(_cryptoStream->SetOutStream(outStream)) - RINOK(_cryptoStream->InitEncoder()) - outStreamReleaser.FilterCoder = _cryptoStream.ClsPtr(); - } - } - - if (needCode) - { - switch (method) - { - case NCompressionMethod::kStore: - { - _copyCoder.Create_if_Empty(); - CMyComPtr outStreamNew; - if (_options.Password_Defined) - outStreamNew = _cryptoStream; - else - outStreamNew = outStream; - RINOK(_copyCoder.Interface()->Code(inCrcStream, outStreamNew, NULL, NULL, progress)) - break; - } - - default: - { - if (!_compressEncoder) - { - CLzmaEncoder *_lzmaEncoder = NULL; - if (method == NCompressionMethod::kLZMA) - { - _compressExtractVersion = NCompressionMethod::kExtractVersion_LZMA; - _lzmaEncoder = new CLzmaEncoder(); - _compressEncoder = _lzmaEncoder; - } - else if (method == NCompressionMethod::kXz) - { - _compressExtractVersion = NCompressionMethod::kExtractVersion_Xz; - NCompress::NXz::CEncoder *encoder = new NCompress::NXz::CEncoder(); - _compressEncoder = encoder; - } - else if (method == NCompressionMethod::kPPMd) - { - _compressExtractVersion = NCompressionMethod::kExtractVersion_PPMd; - NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder(); - _compressEncoder = encoder; - } - else - { - CMethodId methodId; - switch (method) - { - case NCompressionMethod::kBZip2: - methodId = kMethodId_BZip2; - _compressExtractVersion = NCompressionMethod::kExtractVersion_BZip2; - break; - default: - _compressExtractVersion = ((method == NCompressionMethod::kDeflate64) ? - NCompressionMethod::kExtractVersion_Deflate64 : - NCompressionMethod::kExtractVersion_Deflate); - methodId = kMethodId_ZipBase + method; - break; - } - RINOK(CreateCoder_Id( - EXTERNAL_CODECS_LOC_VARS - methodId, true, _compressEncoder)) - if (!_compressEncoder) - return E_NOTIMPL; - - if (method == NCompressionMethod::kDeflate || - method == NCompressionMethod::kDeflate64) - { - } - else if (method == NCompressionMethod::kBZip2) - { - } - } - { - CMyComPtr setCoderProps; - _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps); - if (setCoderProps) - { - if (!_options._methods.IsEmpty()) - { - COneMethodInfo *oneMethodMain = &_options._methods[0]; - - RINOK(oneMethodMain->SetCoderProps(setCoderProps, - _options.DataSizeReduce_Defined ? &_options.DataSizeReduce : NULL)) - } - } - } - if (method == NCompressionMethod::kLZMA) - _isLzmaEos = _lzmaEncoder->Encoder->IsWriteEndMark(); - } - - if (method == NCompressionMethod::kLZMA) - opRes.LzmaEos = _isLzmaEos; - - CMyComPtr outStreamNew; - if (_options.Password_Defined) - outStreamNew = _cryptoStream; - else - outStreamNew = outStream; - if (_compressExtractVersion > opRes.ExtractVersion) - opRes.ExtractVersion = _compressExtractVersion; - - { - CMyComPtr optProps; - _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps); - if (optProps) - { - const PROPID propID = NCoderPropID::kExpectedDataSize; - NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; - RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)) - } - } - - try { - RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)) - } catch (...) { return E_FAIL; } - break; - } - } // switch end - - if (_options.Password_Defined) - { - RINOK(_cryptoStream->OutStreamFinish()) - } - } - - if (_options.Password_Defined) - { - if (_options.IsAesMode) - { - RINOK(_filterAesSpec->WriteFooter(outStream)) - } - } - - RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)) - - { - opRes.CRC = inCrcStream->GetCRC(); - opRes.UnpackSize = inCrcStream->GetSize(); - opRes.Method = method; - } - - if (!inCrcStream->WasFinished()) - return E_FAIL; - - if (_options.Password_Defined) - { - if (opRes.PackSize < opRes.UnpackSize + - (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize)) - break; - } - else if (opRes.PackSize < opRes.UnpackSize) - break; - } - - return S_OK; -} - -}} +// ZipAddCommon.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" +#include "../../../../C/Alloc.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../ICoder.h" +#include "../../IPassword.h" +#include "../../MyVersion.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/LzmaEncoder.h" +#include "../../Compress/PpmdZip.h" +#include "../../Compress/XzEncoder.h" + +#include "../Common/InStreamWithCRC.h" + +#include "ZipAddCommon.h" +#include "ZipHeader.h" + +namespace NArchive { +namespace NZip { + +using namespace NFileHeader; + + +static const unsigned kLzmaPropsSize = 5; +static const unsigned kLzmaHeaderSize = 4 + kLzmaPropsSize; + +Z7_CLASS_IMP_NOQIB_3( + CLzmaEncoder + , ICompressCoder + , ICompressSetCoderProperties + , ICompressSetCoderPropertiesOpt +) +public: + CMyComPtr2 Encoder; + Byte Header[kLzmaHeaderSize]; +}; + +Z7_COM7F_IMF(CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +{ + Encoder.Create_if_Empty(); + CMyComPtr2_Create outStream; + outStream->Init(Header + 4, kLzmaPropsSize); + RINOK(Encoder->SetCoderProperties(propIDs, props, numProps)) + RINOK(Encoder->WriteCoderProperties(outStream)) + if (outStream->GetPos() != kLzmaPropsSize) + return E_FAIL; + Header[0] = MY_VER_MAJOR; + Header[1] = MY_VER_MINOR; + Header[2] = kLzmaPropsSize; + Header[3] = 0; + return S_OK; +} + +Z7_COM7F_IMF(CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +{ + return Encoder->SetCoderPropertiesOpt(propIDs, props, numProps); +} + +Z7_COM7F_IMF(CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + RINOK(WriteStream(outStream, Header, kLzmaHeaderSize)) + return Encoder.Interface()->Code(inStream, outStream, inSize, outSize, progress); +} + + +CAddCommon::CAddCommon(): + _isLzmaEos(false), + _buf(NULL) + {} + +void CAddCommon::SetOptions(const CCompressionMethodMode &options) +{ + _options = options; +} + +CAddCommon::~CAddCommon() +{ + MidFree(_buf); +} + +static const UInt32 kBufSize = ((UInt32)1 << 16); + +HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC) +{ + if (!_buf) + { + _buf = (Byte *)MidAlloc(kBufSize); + if (!_buf) + return E_OUTOFMEMORY; + } + + UInt32 crc = CRC_INIT_VAL; + for (;;) + { + UInt32 processed; + RINOK(inStream->Read(_buf, kBufSize, &processed)) + if (processed == 0) + { + resultCRC = CRC_GET_DIGEST(crc); + return S_OK; + } + crc = CrcUpdate(crc, _buf, (size_t)processed); + } +} + + +HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize, + CCompressingResult &opRes) const +{ + // We use Zip64, if unPackSize size is larger than 0xF8000000 to support + // cases when compressed size can be about 3% larger than uncompressed size + + const UInt32 kUnpackZip64Limit = 0xF8000000; + + opRes.UnpackSize = unpackSize; + opRes.PackSize = (UInt64)1 << 60; // we use big value to force Zip64 mode. + + if (unpackSize < kUnpackZip64Limit) + opRes.PackSize = (UInt32)0xFFFFFFFF - 1; // it will not use Zip64 for that size + + if (opRes.PackSize < unpackSize) + opRes.PackSize = unpackSize; + + const Byte method = _options.MethodSequence[0]; + + if (method == NCompressionMethod::kStore && !_options.Password_Defined) + opRes.PackSize = unpackSize; + + opRes.CRC = 0; + + opRes.LzmaEos = false; + + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + opRes.DescriptorMode = outSeqMode; + + if (_options.Password_Defined) + { + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; + if (_options.IsAesMode) + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; + else + { + if (inSeqMode) + opRes.DescriptorMode = true; + } + } + + opRes.Method = method; + Byte ver = 0; + + switch (method) + { + case NCompressionMethod::kStore: break; + case NCompressionMethod::kDeflate: ver = NCompressionMethod::kExtractVersion_Deflate; break; + case NCompressionMethod::kDeflate64: ver = NCompressionMethod::kExtractVersion_Deflate64; break; + case NCompressionMethod::kXz : ver = NCompressionMethod::kExtractVersion_Xz; break; + case NCompressionMethod::kPPMd : ver = NCompressionMethod::kExtractVersion_PPMd; break; + case NCompressionMethod::kBZip2: ver = NCompressionMethod::kExtractVersion_BZip2; break; + case NCompressionMethod::kLZMA : + { + ver = NCompressionMethod::kExtractVersion_LZMA; + const COneMethodInfo *oneMethodMain = &_options._methods[0]; + opRes.LzmaEos = oneMethodMain->Get_Lzma_Eos(); + break; + } + default: break; + } + if (opRes.ExtractVersion < ver) + opRes.ExtractVersion = ver; + + return S_OK; +} + + +HRESULT CAddCommon::Compress( + DECL_EXTERNAL_CODECS_LOC_VARS + ISequentialInStream *inStream, IOutStream *outStream, + bool inSeqMode, bool outSeqMode, + UInt32 fileTime, + UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed, + ICompressProgressInfo *progress, CCompressingResult &opRes) +{ + // opRes.LzmaEos = false; + + if (!inStream) + { + // We can create empty stream here. But it was already implemented in caller code in 9.33+ + return E_INVALIDARG; + } + + CMyComPtr2_Create inCrcStream; + + CMyComPtr inStream2; + if (!inSeqMode) + { + inStream->QueryInterface(IID_IInStream, (void **)&inStream2); + if (!inStream2) + { + // inSeqMode = true; + // inSeqMode must be correct before + return E_FAIL; + } + } + + inCrcStream->SetStream(inStream); + inCrcStream->SetFullSize(expectedDataSize_IsConfirmed ? expectedDataSize : (UInt64)(Int64)-1); + // inCrcStream->Init(); + + unsigned numTestMethods = _options.MethodSequence.Size(); + // numTestMethods != 0 + + bool descriptorMode = outSeqMode; + + // ZipCrypto without descriptor requires additional reading pass for + // inStream to calculate CRC for password check field. + // The descriptor allows to use ZipCrypto check field without CRC (InfoZip's modification). + + if (!outSeqMode) + if (inSeqMode && _options.Password_Defined && !_options.IsAesMode) + descriptorMode = true; + opRes.DescriptorMode = descriptorMode; + + if (numTestMethods > 1) + if (inSeqMode || outSeqMode || !inStream2) + numTestMethods = 1; + + UInt32 crc = 0; + bool crc_IsCalculated = false; + + CFilterCoder::C_OutStream_Releaser outStreamReleaser; + // opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + + for (unsigned i = 0; i < numTestMethods; i++) + { + inCrcStream->Init(); + + if (i != 0) + { + // if (inStream2) + { + RINOK(InStream_SeekToBegin(inStream2)) + } + RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL)) + RINOK(outStream->SetSize(0)) + } + + opRes.LzmaEos = false; + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default; + + const Byte method = _options.MethodSequence[i]; + if (method == NCompressionMethod::kStore && descriptorMode) + { + // we still can create descriptor_mode archives with "Store" method, but they are not good for 100% + return E_NOTIMPL; + } + + bool needCode = true; + + if (_options.Password_Defined) + { + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto; + + if (!_cryptoStream.IsDefined()) + _cryptoStream.SetFromCls(new CFilterCoder(true)); + + if (_options.IsAesMode) + { + opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes; + if (!_cryptoStream->Filter) + { + _cryptoStream->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder; + _filterAesSpec->SetKeyMode(_options.AesKeyMode); + RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len())) + } + RINOK(_filterAesSpec->WriteHeader(outStream)) + } + else + { + if (!_cryptoStream->Filter) + { + _cryptoStream->Filter = _filterSpec = new NCrypto::NZip::CEncoder; + _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()); + } + + UInt32 check; + + if (descriptorMode) + { + // it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set) + check = (fileTime & 0xFFFF); + } + else + { + if (!crc_IsCalculated) + { + RINOK(CalcStreamCRC(inStream, crc)) + crc_IsCalculated = true; + RINOK(InStream_SeekToBegin(inStream2)) + inCrcStream->Init(); + } + check = (crc >> 16); + } + + RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check)) + } + + if (method == NCompressionMethod::kStore) + { + needCode = false; + RINOK(_cryptoStream->Code(inCrcStream, outStream, NULL, NULL, progress)) + } + else + { + RINOK(_cryptoStream->SetOutStream(outStream)) + RINOK(_cryptoStream->InitEncoder()) + outStreamReleaser.FilterCoder = _cryptoStream.ClsPtr(); + } + } + + if (needCode) + { + switch (method) + { + case NCompressionMethod::kStore: + { + _copyCoder.Create_if_Empty(); + CMyComPtr outStreamNew; + if (_options.Password_Defined) + outStreamNew = _cryptoStream; + else + outStreamNew = outStream; + RINOK(_copyCoder.Interface()->Code(inCrcStream, outStreamNew, NULL, NULL, progress)) + break; + } + + default: + { + if (!_compressEncoder) + { + CLzmaEncoder *_lzmaEncoder = NULL; + if (method == NCompressionMethod::kLZMA) + { + _compressExtractVersion = NCompressionMethod::kExtractVersion_LZMA; + _lzmaEncoder = new CLzmaEncoder(); + _compressEncoder = _lzmaEncoder; + } + else if (method == NCompressionMethod::kXz) + { + _compressExtractVersion = NCompressionMethod::kExtractVersion_Xz; + NCompress::NXz::CEncoder *encoder = new NCompress::NXz::CEncoder(); + _compressEncoder = encoder; + } + else if (method == NCompressionMethod::kPPMd) + { + _compressExtractVersion = NCompressionMethod::kExtractVersion_PPMd; + NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder(); + _compressEncoder = encoder; + } + else + { + CMethodId methodId; + switch (method) + { + case NCompressionMethod::kBZip2: + methodId = kMethodId_BZip2; + _compressExtractVersion = NCompressionMethod::kExtractVersion_BZip2; + break; + default: + _compressExtractVersion = ((method == NCompressionMethod::kDeflate64) ? + NCompressionMethod::kExtractVersion_Deflate64 : + NCompressionMethod::kExtractVersion_Deflate); + methodId = kMethodId_ZipBase + method; + break; + } + RINOK(CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + methodId, true, _compressEncoder)) + if (!_compressEncoder) + return E_NOTIMPL; + + if (method == NCompressionMethod::kDeflate || + method == NCompressionMethod::kDeflate64) + { + } + else if (method == NCompressionMethod::kBZip2) + { + } + } + { + CMyComPtr setCoderProps; + _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps); + if (setCoderProps) + { + if (!_options._methods.IsEmpty()) + { + COneMethodInfo *oneMethodMain = &_options._methods[0]; + + RINOK(oneMethodMain->SetCoderProps(setCoderProps, + _options.DataSizeReduce_Defined ? &_options.DataSizeReduce : NULL)) + } + } + } + if (method == NCompressionMethod::kLZMA) + _isLzmaEos = _lzmaEncoder->Encoder->IsWriteEndMark(); + } + + if (method == NCompressionMethod::kLZMA) + opRes.LzmaEos = _isLzmaEos; + + CMyComPtr outStreamNew; + if (_options.Password_Defined) + outStreamNew = _cryptoStream; + else + outStreamNew = outStream; + if (_compressExtractVersion > opRes.ExtractVersion) + opRes.ExtractVersion = _compressExtractVersion; + + { + CMyComPtr optProps; + _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps); + if (optProps) + { + const PROPID propID = NCoderPropID::kExpectedDataSize; + NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize; + RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)) + } + } + + try { + RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress)) + } catch (...) { return E_FAIL; } + break; + } + } // switch end + + if (_options.Password_Defined) + { + RINOK(_cryptoStream->OutStreamFinish()) + } + } + + if (_options.Password_Defined) + { + if (_options.IsAesMode) + { + RINOK(_filterAesSpec->WriteFooter(outStream)) + } + } + + RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize)) + + { + opRes.CRC = inCrcStream->GetCRC(); + opRes.UnpackSize = inCrcStream->GetSize(); + opRes.Method = method; + } + + if (!inCrcStream->WasFinished()) + return E_FAIL; + + if (_options.Password_Defined) + { + if (opRes.PackSize < opRes.UnpackSize + + (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize)) + break; + } + else if (opRes.PackSize < opRes.UnpackSize) + break; + } + + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h index 52ad727a5..e72ec7bce 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.h +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h @@ -1,76 +1,76 @@ -// ZipAddCommon.h - -#ifndef ZIP7_INC_ZIP_ADD_COMMON_H -#define ZIP7_INC_ZIP_ADD_COMMON_H - -#include "../../ICoder.h" -#include "../../IProgress.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/FilterCoder.h" - -#include "../../Compress/CopyCoder.h" - -#include "../../Crypto/ZipCrypto.h" -#include "../../Crypto/WzAes.h" - -#include "ZipCompressionMode.h" - -namespace NArchive { -namespace NZip { - -struct CCompressingResult -{ - UInt64 UnpackSize; - UInt64 PackSize; - UInt32 CRC; - UInt16 Method; - Byte ExtractVersion; - bool DescriptorMode; - bool LzmaEos; - - CCompressingResult() - { - // for GCC: - UnpackSize = 0; - } -}; - -class CAddCommon MY_UNCOPYABLE -{ - CCompressionMethodMode _options; - CMyComPtr2 _copyCoder; - - CMyComPtr _compressEncoder; - Byte _compressExtractVersion; - bool _isLzmaEos; - - CMyComPtr2 _cryptoStream; - - NCrypto::NZip::CEncoder *_filterSpec; - NCrypto::NWzAes::CEncoder *_filterAesSpec; - - Byte *_buf; - - HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC); -public: - // CAddCommon(const CCompressionMethodMode &options); - CAddCommon(); - void SetOptions(const CCompressionMethodMode &options); - ~CAddCommon(); - - HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize, - CCompressingResult &opRes) const; - - HRESULT Compress( - DECL_EXTERNAL_CODECS_LOC_VARS - ISequentialInStream *inStream, IOutStream *outStream, - bool inSeqMode, bool outSeqMode, - UInt32 fileTime, - UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed, - ICompressProgressInfo *progress, CCompressingResult &opRes); -}; - -}} - -#endif +// ZipAddCommon.h + +#ifndef ZIP7_INC_ZIP_ADD_COMMON_H +#define ZIP7_INC_ZIP_ADD_COMMON_H + +#include "../../ICoder.h" +#include "../../IProgress.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/FilterCoder.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Crypto/ZipCrypto.h" +#include "../../Crypto/WzAes.h" + +#include "ZipCompressionMode.h" + +namespace NArchive { +namespace NZip { + +struct CCompressingResult +{ + UInt64 UnpackSize; + UInt64 PackSize; + UInt32 CRC; + UInt16 Method; + Byte ExtractVersion; + bool DescriptorMode; + bool LzmaEos; + + CCompressingResult() + { + // for GCC: + UnpackSize = 0; + } +}; + +class CAddCommon MY_UNCOPYABLE +{ + CCompressionMethodMode _options; + CMyComPtr2 _copyCoder; + + CMyComPtr _compressEncoder; + Byte _compressExtractVersion; + bool _isLzmaEos; + + CMyComPtr2 _cryptoStream; + + NCrypto::NZip::CEncoder *_filterSpec; + NCrypto::NWzAes::CEncoder *_filterAesSpec; + + Byte *_buf; + + HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC); +public: + // CAddCommon(const CCompressionMethodMode &options); + CAddCommon(); + void SetOptions(const CCompressionMethodMode &options); + ~CAddCommon(); + + HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize, + CCompressingResult &opRes) const; + + HRESULT Compress( + DECL_EXTERNAL_CODECS_LOC_VARS + ISequentialInStream *inStream, IOutStream *outStream, + bool inSeqMode, bool outSeqMode, + UInt32 fileTime, + UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed, + ICompressProgressInfo *progress, CCompressingResult &opRes); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h index 2dd3c7e39..89742615b 100644 --- a/CPP/7zip/Archive/Zip/ZipCompressionMode.h +++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h @@ -1,62 +1,62 @@ -// CompressionMode.h - -#ifndef ZIP7_INC_ZIP_COMPRESSION_MODE_H -#define ZIP7_INC_ZIP_COMPRESSION_MODE_H - -#include "../../../Common/MyString.h" - -#ifndef Z7_ST -#include "../../../Windows/System.h" -#endif - -#include "../Common/HandlerOut.h" - -namespace NArchive { -namespace NZip { - -const CMethodId kMethodId_ZipBase = 0x040100; -const CMethodId kMethodId_BZip2 = 0x040202; - -struct CBaseProps: public CMultiMethodProps -{ - bool IsAesMode; - Byte AesKeyMode; - - void Init() - { - CMultiMethodProps::Init(); - - IsAesMode = false; - AesKeyMode = 3; - } -}; - -struct CCompressionMethodMode: public CBaseProps -{ - CRecordVector MethodSequence; - AString Password; // _Wipe - bool Password_Defined; - bool Force_SeqOutMode; - bool DataSizeReduce_Defined; - UInt64 DataSizeReduce; - - bool IsRealAesMode() const { return Password_Defined && IsAesMode; } - - CCompressionMethodMode() - { - Password_Defined = false; - Force_SeqOutMode = false; - DataSizeReduce_Defined = false; - DataSizeReduce = 0; - } - -#ifdef Z7_CPP_IS_SUPPORTED_default - CCompressionMethodMode(const CCompressionMethodMode &) = default; - CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default; -#endif - ~CCompressionMethodMode() { Password.Wipe_and_Empty(); } -}; - -}} - -#endif +// CompressionMode.h + +#ifndef ZIP7_INC_ZIP_COMPRESSION_MODE_H +#define ZIP7_INC_ZIP_COMPRESSION_MODE_H + +#include "../../../Common/MyString.h" + +#ifndef Z7_ST +#include "../../../Windows/System.h" +#endif + +#include "../Common/HandlerOut.h" + +namespace NArchive { +namespace NZip { + +const CMethodId kMethodId_ZipBase = 0x040100; +const CMethodId kMethodId_BZip2 = 0x040202; + +struct CBaseProps: public CMultiMethodProps +{ + bool IsAesMode; + Byte AesKeyMode; + + void Init() + { + CMultiMethodProps::Init(); + + IsAesMode = false; + AesKeyMode = 3; + } +}; + +struct CCompressionMethodMode: public CBaseProps +{ + CRecordVector MethodSequence; + AString Password; // _Wipe + bool Password_Defined; + bool Force_SeqOutMode; + bool DataSizeReduce_Defined; + UInt64 DataSizeReduce; + + bool IsRealAesMode() const { return Password_Defined && IsAesMode; } + + CCompressionMethodMode() + { + Password_Defined = false; + Force_SeqOutMode = false; + DataSizeReduce_Defined = false; + DataSizeReduce = 0; + } + +#ifdef Z7_CPP_IS_SUPPORTED_default + CCompressionMethodMode(const CCompressionMethodMode &) = default; + CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default; +#endif + ~CCompressionMethodMode() { Password.Wipe_and_Empty(); } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp index 553ac05bf..c6b6e3946 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp @@ -1,1679 +1,1679 @@ -// ZipHandler.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantUtils.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../IPassword.h" - -#include "../../Common/FilterCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" -#ifndef Z7_ZIP_LZFSE_DISABLE -#include "../../Compress/LzfseDecoder.h" -#endif -#include "../../Compress/LzmaDecoder.h" -#include "../../Compress/ImplodeDecoder.h" -#include "../../Compress/PpmdZip.h" -#include "../../Compress/ShrinkDecoder.h" -#include "../../Compress/XzDecoder.h" -#include "../../Compress/ZstdDecoder.h" - -#include "../../Crypto/WzAes.h" -#include "../../Crypto/ZipCrypto.h" -#include "../../Crypto/ZipStrong.h" - -#include "../Common/ItemNameUtils.h" -#include "../Common/OutStreamWithCRC.h" - - -#include "ZipHandler.h" - -using namespace NWindows; - -namespace NArchive { -namespace NZip { - -static const char * const kHostOS[] = -{ - "FAT" - , "AMIGA" - , "VMS" - , "Unix" - , "VM/CMS" - , "Atari" - , "HPFS" - , "Macintosh" - , "Z-System" - , "CP/M" - , "TOPS-20" - , "NTFS" - , "SMS/QDOS" - , "Acorn" - , "VFAT" - , "MVS" - , "BeOS" - , "Tandem" - , "OS/400" - , "OS/X" -}; - - -const char * const kMethodNames1[kNumMethodNames1] = -{ - "Store" - , "Shrink" - , "Reduce1" - , "Reduce2" - , "Reduce3" - , "Reduce4" - , "Implode" - , NULL // "Tokenize" - , "Deflate" - , "Deflate64" - , "PKImploding" - , NULL - , "BZip2" - , NULL - , "LZMA" - /* - , NULL - , NULL - , NULL - , NULL - , NULL - , "zstd-pk" // deprecated - */ -}; - - -const char * const kMethodNames2[kNumMethodNames2] = -{ - "zstd" - , "MP3" - , "xz" - , "Jpeg" - , "WavPack" - , "PPMd" - , "LZFSE" // , "WzAES" -}; - -#define kMethod_AES "AES" -#define kMethod_ZipCrypto "ZipCrypto" -#define kMethod_StrongCrypto "StrongCrypto" - -static const char * const kDeflateLevels[4] = -{ - "Normal" - , "Maximum" - , "Fast" - , "Fastest" -}; - - -static const CUInt32PCharPair g_HeaderCharacts[] = -{ - { 0, "Encrypt" }, - { 3, "Descriptor" }, - // { 4, "Enhanced" }, - // { 5, "Patched" }, - { 6, kMethod_StrongCrypto }, - { 11, "UTF8" }, - { 14, "Alt" } -}; - -struct CIdToNamePair -{ - unsigned Id; - const char *Name; -}; - - -static const CIdToNamePair k_StrongCryptoPairs[] = -{ - { NStrongCrypto_AlgId::kDES, "DES" }, - { NStrongCrypto_AlgId::kRC2old, "RC2a" }, - { NStrongCrypto_AlgId::k3DES168, "3DES-168" }, - { NStrongCrypto_AlgId::k3DES112, "3DES-112" }, - { NStrongCrypto_AlgId::kAES128, "pkAES-128" }, - { NStrongCrypto_AlgId::kAES192, "pkAES-192" }, - { NStrongCrypto_AlgId::kAES256, "pkAES-256" }, - { NStrongCrypto_AlgId::kRC2, "RC2" }, - { NStrongCrypto_AlgId::kBlowfish, "Blowfish" }, - { NStrongCrypto_AlgId::kTwofish, "Twofish" }, - { NStrongCrypto_AlgId::kRC4, "RC4" } -}; - -static const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) -{ - for (unsigned i = 0; i < num; i++) - { - const CIdToNamePair &pair = pairs[i]; - if (id == pair.Id) - return pair.Name; - } - return NULL; -} - - -static const Byte kProps[] = -{ - kpidPath, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidMTime, - kpidCTime, - kpidATime, - kpidAttrib, - // kpidPosixAttrib, - kpidEncrypted, - kpidComment, - kpidCRC, - kpidMethod, - kpidCharacts, - kpidHostOS, - kpidUnpackVer, - kpidVolumeIndex, - kpidOffset - // kpidIsAltStream - // , kpidChangeTime // for debug - // , 255 // for debug -}; - -static const Byte kArcProps[] = -{ - kpidEmbeddedStubSize, - kpidBit64, - kpidComment, - kpidCharacts, - kpidTotalPhySize, - kpidIsVolume, - kpidVolumeIndex, - kpidNumVolumes -}; - -CHandler::CHandler() -{ - InitMethodProps(); -} - -static AString BytesToString(const CByteBuffer &data) -{ - AString s; - s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size()); - return s; -} - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; - case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; - - case kpidPhySize: prop = m_Archive.GetPhySize(); break; - case kpidOffset: prop = m_Archive.GetOffset(); break; - - case kpidEmbeddedStubSize: - { - UInt64 stubSize = m_Archive.GetEmbeddedStubSize(); - if (stubSize != 0) - prop = stubSize; - break; - } - - case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.TotalBytesSize; break; - case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break; - case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break; - case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break; - - case kpidCharacts: - { - AString s; - - if (m_Archive.LocalsWereRead) - { - s.Add_OptSpaced("Local"); - - if (m_Archive.LocalsCenterMerged) - s.Add_OptSpaced("Central"); - } - - if (m_Archive.IsZip64) - s.Add_OptSpaced("Zip64"); - - if (m_Archive.IsCdUnsorted) - s.Add_OptSpaced("Unsorted_CD"); - - if (m_Archive.IsApk) - s.Add_OptSpaced("apk"); - - if (m_Archive.ExtraMinorError) - s.Add_OptSpaced("Minor_Extra_ERROR"); - - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidWarningFlags: - { - UInt32 v = 0; - // if (m_Archive.ExtraMinorError) v |= kpv_ErrorFlags_HeadersError; - if (m_Archive.HeadersWarning) v |= kpv_ErrorFlags_HeadersError; - if (v != 0) - prop = v; - break; - } - - case kpidWarning: - { - AString s; - if (m_Archive.Overflow32bit) - s.Add_OptSpaced("32-bit overflow in headers"); - if (m_Archive.Cd_NumEntries_Overflow_16bit) - s.Add_OptSpaced("16-bit overflow for number of files in headers"); - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidError: - { - if (!m_Archive.Vols.MissingName.IsEmpty()) - { - UString s("Missing volume : "); - s += m_Archive.Vols.MissingName; - prop = s; - } - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!m_Archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; - if (m_Archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; - if (m_Archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; - if (m_Archive.ArcInfo.Base < 0) - { - /* We try to support case when we have sfx-zip with embedded stub, - but the stream has access only to zip part. - In that case we ignore UnavailableStart error. - maybe we must show warning in that case. */ - UInt64 stubSize = m_Archive.GetEmbeddedStubSize(); - if (stubSize < (UInt64)-m_Archive.ArcInfo.Base) - v |= kpv_ErrorFlags_UnavailableStart; - } - if (m_Archive.NoCentralDir) v |= kpv_ErrorFlags_UnconfirmedStart; - prop = v; - break; - } - - case kpidReadOnly: - { - if (m_Archive.IsOpen()) - if (!m_Archive.CanUpdate()) - prop = true; - break; - } - - // case kpidIsAltStream: prop = true; break; - default: break; - } - return prop.Detach(value); - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = m_Items.Size(); - return S_OK; -} - - -static bool NtfsUnixTimeToProp(bool fromCentral, - const CExtraBlock &extra, - unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop) -{ - { - FILETIME ft; - if (extra.GetNtfsTime(ntfsIndex, ft)) - { - PropVariant_SetFrom_NtfsTime(prop, ft); - return true; - } - } - { - UInt32 unixTime = 0; - if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime)) - return false; - /* - // we allow unixTime == 0 - if (unixTime == 0) - return false; - */ - PropVariant_SetFrom_UnixTime(prop, unixTime); - return true; - } -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - const CItemEx &item = m_Items[index]; - const CExtraBlock &extra = item.GetMainExtra(); - - switch (propID) - { - case kpidPath: - { - UString res; - item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage); - NItemName::ReplaceToOsSlashes_Remove_TailSlash(res, - item.Is_MadeBy_Unix() // useBackslashReplacement - ); - /* - if (item.ParentOfAltStream >= 0) - { - const CItemEx &prevItem = m_Items[item.ParentOfAltStream]; - UString prevName; - prevItem.GetUnicodeString(prevName, prevItem.Name, false, _forceCodePage, _specifiedCodePage); - NItemName::ReplaceToOsSlashes_Remove_TailSlash(prevName); - if (res.IsPrefixedBy(prevName)) - if (IsString1PrefixedByString2(res.Ptr(prevName.Len()), k_SpecName_NTFS_STREAM)) - { - res.Delete(prevName.Len(), (unsigned)strlen(k_SpecName_NTFS_STREAM)); - res.Insert(prevName.Len(), L":"); - } - } - */ - prop = res; - break; - } - - case kpidIsDir: prop = item.IsDir(); break; - case kpidSize: - { - if (!item.IsBadDescriptor()) - prop = item.Size; - break; - } - - case kpidPackSize: prop = item.PackSize; break; - - case kpidCTime: - NtfsUnixTimeToProp(item.FromCentral, extra, - NFileHeader::NNtfsExtra::kCTime, - NFileHeader::NUnixTime::kCTime, prop); - break; - - case kpidATime: - NtfsUnixTimeToProp(item.FromCentral, extra, - NFileHeader::NNtfsExtra::kATime, - NFileHeader::NUnixTime::kATime, prop); - break; - - case kpidMTime: - { - if (!NtfsUnixTimeToProp(item.FromCentral, extra, - NFileHeader::NNtfsExtra::kMTime, - NFileHeader::NUnixTime::kMTime, prop)) - { - if (item.Time != 0) - PropVariant_SetFrom_DosTime(prop, item.Time); - } - break; - } - - case kpidTimeType: - { - FILETIME ft; - UInt32 unixTime; - UInt32 type; - if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) - type = NFileTimeType::kWindows; - else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime)) - type = NFileTimeType::kUnix; - else - type = NFileTimeType::kDOS; - prop = type; - break; - } - - /* - // for debug to get Dos time values: - case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break; - // for debug - // time difference (dos - utc) - case 255: - { - if (NtfsUnixTimeToProp(item.FromCentral, extra, - NFileHeader::NNtfsExtra::kMTime, - NFileHeader::NUnixTime::kMTime, prop)) - { - FILETIME localFileTime; - if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime)) - { - UInt64 t1 = FILETIME_To_UInt64(prop.filetime); - UInt64 t2 = FILETIME_To_UInt64(localFileTime); - prop.Set_Int64(t2 - t1); - } - } - break; - } - */ - - case kpidAttrib: prop = item.GetWinAttrib(); break; - - case kpidPosixAttrib: - { - UInt32 attrib; - if (item.GetPosixAttrib(attrib)) - prop = attrib; - break; - } - - case kpidEncrypted: prop = item.IsEncrypted(); break; - - case kpidComment: - { - if (item.Comment.Size() != 0) - { - UString res; - item.GetUnicodeString(res, BytesToString(item.Comment), true, _forceCodePage, _specifiedCodePage); - prop = res; - } - break; - } - - case kpidCRC: if (item.IsThereCrc()) prop = item.Crc; break; - - case kpidMethod: - { - AString m; - bool isWzAes = false; - unsigned id = item.Method; - - if (id == NFileHeader::NCompressionMethod::kWzAES) - { - CWzAesExtra aesField; - if (extra.GetWzAes(aesField)) - { - m += kMethod_AES; - m.Add_Minus(); - m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64); - id = aesField.Method; - isWzAes = true; - } - } - - if (item.IsEncrypted()) - if (!isWzAes) - { - if (item.IsStrongEncrypted()) - { - CStrongCryptoExtra f; - f.AlgId = 0; - if (extra.GetStrongCrypto(f)) - { - const char *s = FindNameForId(k_StrongCryptoPairs, Z7_ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId); - if (s) - m += s; - else - { - m += kMethod_StrongCrypto; - m.Add_Colon(); - m.Add_UInt32(f.AlgId); - } - if (f.CertificateIsUsed()) - m += "-Cert"; - } - else - m += kMethod_StrongCrypto; - } - else - m += kMethod_ZipCrypto; - } - - m.Add_Space_if_NotEmpty(); - - { - const char *s = NULL; - if (id < kNumMethodNames1) - s = kMethodNames1[id]; - else - { - const int id2 = (int)id - (int)kMethodNames2Start; - if (id2 >= 0 && (unsigned)id2 < kNumMethodNames2) - s = kMethodNames2[id2]; - } - if (s) - m += s; - else - m.Add_UInt32(id); - } - { - unsigned level = item.GetDeflateLevel(); - if (level != 0) - { - if (id == NFileHeader::NCompressionMethod::kLZMA) - { - if (level & 1) - m += ":eos"; - level &= ~(unsigned)1; - } - else if (id == NFileHeader::NCompressionMethod::kDeflate) - { - m.Add_Colon(); - m += kDeflateLevels[level]; - level = 0; - } - - if (level != 0) - { - m += ":v"; - m.Add_UInt32(level); - } - } - } - - prop = m; - break; - } - - case kpidCharacts: - { - AString s; - - if (item.FromLocal) - { - s.Add_OptSpaced("Local"); - - item.LocalExtra.PrintInfo(s); - - if (item.FromCentral) - { - s.Add_OptSpaced(":"); - s.Add_OptSpaced("Central"); - } - } - - if (item.FromCentral) - { - item.CentralExtra.PrintInfo(s); - } - - UInt32 flags = item.Flags; - flags &= ~(unsigned)6; // we don't need compression related bits here. - - if (flags != 0) - { - const AString s2 = FlagsToString(g_HeaderCharacts, Z7_ARRAY_SIZE(g_HeaderCharacts), flags); - if (!s2.IsEmpty()) - { - if (!s.IsEmpty()) - s.Add_OptSpaced(":"); - s.Add_OptSpaced(s2); - } - } - - if (item.IsBadDescriptor()) - s.Add_OptSpaced("Descriptor_ERROR"); - - if (!s.IsEmpty()) - prop = s; - break; - } - - case kpidHostOS: - { - if (item.FromCentral) - { - // 18.06: now we use HostOS only from Central::MadeByVersion - const Byte hostOS = item.MadeByVersion.HostOS; - TYPE_TO_PROP(kHostOS, hostOS, prop); - } - break; - } - - case kpidUnpackVer: - prop = (UInt32)item.ExtractVersion.Version; - break; - - case kpidVolumeIndex: - prop = item.Disk; - break; - - case kpidOffset: - prop = item.LocalHeaderPos; - break; - - /* - case kpidIsAltStream: - prop = (bool)(item.ParentOfAltStream >= 0); // item.IsAltStream(); - break; - - case kpidName: - if (item.ParentOfAltStream >= 0) - { - // extract name of stream here - } - break; - */ - default: break; - } - - return prop.Detach(value); - COM_TRY_END -} - - - -/* -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps) -{ - *numProps = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) -{ - UNUSED_VAR(index); - *propID = 0; - *name = 0; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - if (index >= m_Items.Size()) - return S_OK; - const CItemEx &item = m_Items[index]; - - if (item.ParentOfAltStream >= 0) - { - *parentType = NParentType::kAltStream; - *parent = item.ParentOfAltStream; - } - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) -{ - UNUSED_VAR(index); - UNUSED_VAR(propID); - *data = NULL; - *dataSize = 0; - *propType = 0; - return S_OK; -} - - -void CHandler::MarkAltStreams(CObjectVector &items) -{ - int prevIndex = -1; - UString prevName; - UString name; - - for (unsigned i = 0; i < items.Size(); i++) - { - CItemEx &item = m_Items[i]; - if (item.IsAltStream()) - { - if (prevIndex == -1) - continue; - if (prevName.IsEmpty()) - { - const CItemEx &prevItem = m_Items[prevIndex]; - prevItem.GetUnicodeString(prevName, prevItem.Name, false, _forceCodePage, _specifiedCodePage); - NItemName::ReplaceToOsSlashes_Remove_TailSlash(prevName); - } - name.Empty(); - item.GetUnicodeString(name, item.Name, false, _forceCodePage, _specifiedCodePage); - NItemName::ReplaceToOsSlashes_Remove_TailSlash(name); - - if (name.IsPrefixedBy(prevName)) - if (IsString1PrefixedByString2(name.Ptr(prevName.Len()), k_SpecName_NTFS_STREAM)) - item.ParentOfAltStream = prevIndex; - } - else - { - prevIndex = i; - prevName.Empty(); - } - } -} -*/ - -Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, - const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - try - { - Close(); - m_Archive.Force_ReadLocals_Mode = _force_OpenSeq; - // m_Archive.Disable_VolsRead = _force_OpenSeq; - // m_Archive.Disable_FindMarker = _force_OpenSeq; - HRESULT res = m_Archive.Open(inStream, maxCheckStartPosition, callback, m_Items); - if (res != S_OK) - { - m_Items.Clear(); - m_Archive.ClearRefs(); // we don't want to clear error flags - } - // MarkAltStreams(m_Items); - return res; - } - catch(...) { Close(); throw; } - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - m_Items.Clear(); - m_Archive.Close(); - return S_OK; -} - - -Z7_CLASS_IMP_NOQIB_3( - CLzmaDecoder - , ICompressCoder - , ICompressSetFinishMode - , ICompressGetInStreamProcessedSize -) -public: - CMyComPtr2_Create Decoder; -}; - -static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE; - -Z7_COM7F_IMF(CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - Byte buf[kZipLzmaPropsSize]; - RINOK(ReadStream_FALSE(inStream, buf, kZipLzmaPropsSize)) - if (buf[2] != LZMA_PROPS_SIZE || buf[3] != 0) - return E_NOTIMPL; - RINOK(Decoder->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE)) - UInt64 inSize2 = 0; - if (inSize) - { - inSize2 = *inSize; - if (inSize2 < kZipLzmaPropsSize) - return S_FALSE; - inSize2 -= kZipLzmaPropsSize; - } - return Decoder.Interface()->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress); -} - -Z7_COM7F_IMF(CLzmaDecoder::SetFinishMode(UInt32 finishMode)) -{ - Decoder->FinishStream = (finishMode != 0); - return S_OK; -} - -Z7_COM7F_IMF(CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = Decoder->GetInputProcessedSize() + kZipLzmaPropsSize; - return S_OK; -} - - - - - - - -struct CMethodItem -{ - unsigned ZipMethod; - CMyComPtr Coder; -}; - - - -class CZipDecoder -{ - CMyComPtr2 _zipCryptoDecoder; - CMyComPtr2 _pkAesDecoder; - CMyComPtr2 _wzAesDecoder; - - CMyComPtr2 filterStream; - CMyComPtr getTextPassword; - CObjectVector methodItems; - - CLzmaDecoder *lzmaDecoderSpec; -public: - CZipDecoder(): - lzmaDecoderSpec(NULL) - {} - - HRESULT Decode( - DECL_EXTERNAL_CODECS_LOC_VARS - CInArchive &archive, const CItemEx &item, - ISequentialOutStream *realOutStream, - IArchiveExtractCallback *extractCallback, - ICompressProgressInfo *compressProgress, - #ifndef Z7_ST - UInt32 numThreads, UInt64 memUsage, - #endif - Int32 &res); -}; - - -static HRESULT SkipStreamData(ISequentialInStream *stream, - ICompressProgressInfo *progress, UInt64 packSize, UInt64 unpackSize, - bool &thereAreData) -{ - thereAreData = false; - const size_t kBufSize = 1 << 12; - Byte buf[kBufSize]; - UInt64 prev = packSize; - for (;;) - { - size_t size = kBufSize; - RINOK(ReadStream(stream, buf, &size)) - if (size == 0) - return S_OK; - thereAreData = true; - packSize += size; - if ((packSize - prev) >= (1 << 22)) - { - prev = packSize; - RINOK(progress->SetRatioInfo(&packSize, &unpackSize)) - } - } -} - - - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithPadPKCS7 - , ISequentialOutStream -) - CMyComPtr _stream; - UInt64 _size; - UInt64 _padPos; - UInt32 _padSize; - bool _padFailure; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - - // padSize == 0 means (no_pad Mode) - void Init(UInt64 padPos, UInt32 padSize) - { - _padPos = padPos; - _padSize = padSize; - _size = 0; - _padFailure = false; - } - UInt64 GetSize() const { return _size; } - bool WasPadFailure() const { return _padFailure; } -}; - - -Z7_COM7F_IMF(COutStreamWithPadPKCS7::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 written = 0; - HRESULT result = S_OK; - if (_size < _padPos) - { - const UInt64 rem = _padPos - _size; - UInt32 num = size; - if (num > rem) - num = (UInt32)rem; - result = _stream->Write(data, num, &written); - _size += written; - if (processedSize) - *processedSize = written; - if (_size != _padPos || result != S_OK) - return result; - size -= written; - data = ((const Byte *)data) + written; - } - _size += size; - written += size; - if (processedSize) - *processedSize = written; - if (_padSize != 0) - for (; size != 0; size--) - { - if (*(const Byte *)data != _padSize) - _padFailure = true; - data = ((const Byte *)data) + 1; - } - return result; -} - - - -HRESULT CZipDecoder::Decode( - DECL_EXTERNAL_CODECS_LOC_VARS - CInArchive &archive, const CItemEx &item, - ISequentialOutStream *realOutStream, - IArchiveExtractCallback *extractCallback, - ICompressProgressInfo *compressProgress, - #ifndef Z7_ST - UInt32 numThreads, UInt64 memUsage, - #endif - Int32 &res) -{ - res = NExtract::NOperationResult::kHeadersError; - - CFilterCoder::C_InStream_Releaser inStreamReleaser; - CFilterCoder::C_Filter_Releaser filterReleaser; - - bool needCRC = true; - bool wzAesMode = false; - bool pkAesMode = false; - - bool badDescriptor = item.IsBadDescriptor(); - if (badDescriptor) - needCRC = false; - - - unsigned id = item.Method; - - CWzAesExtra aesField; - // LZFSE and WinZip's AES use same id - kWzAES. - - if (id == NFileHeader::NCompressionMethod::kWzAES) - { - if (item.GetMainExtra().GetWzAes(aesField)) - { - if (!item.IsEncrypted()) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - wzAesMode = true; - needCRC = aesField.NeedCrc(); - } - } - - if (!wzAesMode) - if (item.IsEncrypted()) - { - if (item.IsStrongEncrypted()) - { - CStrongCryptoExtra f; - if (!item.CentralExtra.GetStrongCrypto(f)) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - pkAesMode = true; - } - } - - CMyComPtr2_Create outStream; - outStream->SetStream(realOutStream); - outStream->Init(needCRC); - - CMyComPtr packStream; - CMyComPtr2_Create inStream; - - { - UInt64 packSize = item.PackSize; - if (wzAesMode) - { - if (packSize < NCrypto::NWzAes::kMacSize) - return S_OK; - packSize -= NCrypto::NWzAes::kMacSize; - } - RINOK(archive.GetItemStream(item, true, packStream)) - if (!packStream) - { - res = NExtract::NOperationResult::kUnavailable; - return S_OK; - } - inStream->SetStream(packStream); - inStream->Init(packSize); - } - - - res = NExtract::NOperationResult::kDataError; - - CMyComPtr cryptoFilter; - - if (item.IsEncrypted()) - { - if (wzAesMode) - { - id = aesField.Method; - _wzAesDecoder.Create_if_Empty(); - cryptoFilter = _wzAesDecoder; - if (!_wzAesDecoder->SetKeyMode(aesField.Strength)) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - } - else if (pkAesMode) - { - _pkAesDecoder.Create_if_Empty(); - cryptoFilter = _pkAesDecoder; - } - else - { - _zipCryptoDecoder.Create_if_Empty(); - cryptoFilter = _zipCryptoDecoder; - } - - CMyComPtr cryptoSetPassword; - RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)) - if (!cryptoSetPassword) - return E_FAIL; - - if (!getTextPassword) - extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); - - if (getTextPassword) - { - CMyComBSTR_Wipe password; - RINOK(getTextPassword->CryptoGetTextPassword(&password)) - AString_Wipe charPassword; - if (password) - { -#if 0 && defined(_WIN32) - // do we need UTF-8 passwords here ? - if (item.GetHostOS() == NFileHeader::NHostOS::kUnix // 24.05 - // || item.IsUtf8() // 22.00 - ) - { - // throw 1; - ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword); - } - else -#endif - { - UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP); - } - /* - if (wzAesMode || pkAesMode) - { - } - else - { - // PASSWORD encoding for ZipCrypto: - // pkzip25 / WinZip / Windows probably use ANSI - // 7-Zip < 4.43 creates ZIP archives with OEM encoding in password - // 7-Zip >= 4.43 creates ZIP archives only with ASCII characters in password - // 7-Zip < 17.00 uses CP_OEMCP for password decoding - // 7-Zip >= 17.00 uses CP_ACP for password decoding - } - */ - } - HRESULT result = cryptoSetPassword->CryptoSetPassword( - (const Byte *)(const char *)charPassword, charPassword.Len()); - if (result != S_OK) - { - res = NExtract::NOperationResult::kWrongPassword; - return S_OK; - } - } - else - { - res = NExtract::NOperationResult::kWrongPassword; - return S_OK; - // RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0)); - } - } - - unsigned m; - for (m = 0; m < methodItems.Size(); m++) - if (methodItems[m].ZipMethod == id) - break; - - if (m == methodItems.Size()) - { - CMethodItem mi; - mi.ZipMethod = id; - if (id == NFileHeader::NCompressionMethod::kStore) - mi.Coder = new NCompress::CCopyCoder; - else if (id == NFileHeader::NCompressionMethod::kShrink) - mi.Coder = new NCompress::NShrink::CDecoder; - else if (id == NFileHeader::NCompressionMethod::kImplode) - mi.Coder = new NCompress::NImplode::NDecoder::CCoder; - else if (id == NFileHeader::NCompressionMethod::kLZMA) - { - lzmaDecoderSpec = new CLzmaDecoder; - mi.Coder = lzmaDecoderSpec; - } - else if (id == NFileHeader::NCompressionMethod::kXz) - mi.Coder = new NCompress::NXz::CComDecoder; - else if (id == NFileHeader::NCompressionMethod::kPPMd) - mi.Coder = new NCompress::NPpmdZip::CDecoder(true); - else if (id == NFileHeader::NCompressionMethod::kZstdWz) - mi.Coder = new NCompress::NZstd::CDecoder(); -#ifndef Z7_ZIP_LZFSE_DISABLE - else if (id == NFileHeader::NCompressionMethod::kWzAES) - mi.Coder = new NCompress::NLzfse::CDecoder; -#endif - else - { - CMethodId szMethodID; - if (id == NFileHeader::NCompressionMethod::kBZip2) - szMethodID = kMethodId_BZip2; - else - { - if (id > 0xFF) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - szMethodID = kMethodId_ZipBase + (Byte)id; - } - - RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder)) - - if (!mi.Coder) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - } - m = methodItems.Add(mi); - } - - const CMethodItem &mi = methodItems[m]; - ICompressCoder *coder = mi.Coder; - - - #ifndef Z7_ST - { - CMyComPtr setCoderMt; - coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); - if (setCoderMt) - { - RINOK(setCoderMt->SetNumberOfThreads(numThreads)) - } - } - // if (memUsage != 0) - { - CMyComPtr setMemLimit; - coder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); - if (setMemLimit) - { - RINOK(setMemLimit->SetMemLimit(memUsage)) - } - } - #endif - - { - CMyComPtr setDecoderProperties; - coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); - if (setDecoderProperties) - { - Byte properties = (Byte)item.Flags; - RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)) - } - } - - - bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0); - bool needReminderCheck = false; - - bool dataAfterEnd = false; - bool truncatedError = false; - bool lzmaEosError = false; - bool headersError = false; - bool padError = false; - bool readFromFilter = false; - - const bool useUnpackLimit = (id == NFileHeader::NCompressionMethod::kStore - || !item.HasDescriptor() - || item.Size >= ((UInt64)1 << 32) - || item.LocalExtra.IsZip64 - || item.CentralExtra.IsZip64 - ); - - { - HRESULT result = S_OK; - if (item.IsEncrypted()) - { - if (!filterStream.IsDefined()) - filterStream.SetFromCls(new CFilterCoder(false)); - - filterReleaser.FilterCoder = filterStream.ClsPtr(); - filterStream->Filter = cryptoFilter; - - if (wzAesMode) - { - result = _wzAesDecoder->ReadHeader(inStream); - if (result == S_OK) - { - if (!_wzAesDecoder->Init_and_CheckPassword()) - { - res = NExtract::NOperationResult::kWrongPassword; - return S_OK; - } - } - } - else if (pkAesMode) - { - isFullStreamExpected = false; - result = _pkAesDecoder->ReadHeader(inStream, item.Crc, item.Size); - if (result == S_OK) - { - bool passwOK; - result = _pkAesDecoder->Init_and_CheckPassword(passwOK); - if (result == S_OK && !passwOK) - { - res = NExtract::NOperationResult::kWrongPassword; - return S_OK; - } - } - } - else - { - result = _zipCryptoDecoder->ReadHeader(inStream); - if (result == S_OK) - { - _zipCryptoDecoder->Init_BeforeDecode(); - - /* Info-ZIP modification to ZipCrypto format: - if bit 3 of the general purpose bit flag is set, - it uses high byte of 16-bit File Time. - Info-ZIP code probably writes 2 bytes of File Time. - We check only 1 byte. */ - - // UInt32 v1 = GetUi16(_zipCryptoDecoder->_header + NCrypto::NZip::kHeaderSize - 2); - // UInt32 v2 = (item.HasDescriptor() ? (item.Time & 0xFFFF) : (item.Crc >> 16)); - - Byte v1 = _zipCryptoDecoder->_header[NCrypto::NZip::kHeaderSize - 1]; - Byte v2 = (Byte)(item.HasDescriptor() ? (item.Time >> 8) : (item.Crc >> 24)); - - if (v1 != v2) - { - res = NExtract::NOperationResult::kWrongPassword; - return S_OK; - } - } - } - } - - if (result == S_OK) - { - CMyComPtr setFinishMode; - coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); - if (setFinishMode) - { - RINOK(setFinishMode->SetFinishMode(BoolToUInt(true))) - } - - const UInt64 coderPackSize = inStream->GetRem(); - - if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted()) - { - // for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter - // here we use filter without CopyCoder - readFromFilter = false; - - COutStreamWithPadPKCS7 *padStreamSpec = NULL; - CMyComPtr padStream; - UInt32 padSize = 0; - - if (pkAesMode) - { - padStreamSpec = new COutStreamWithPadPKCS7; - padStream = padStreamSpec; - padSize = _pkAesDecoder->GetPadSize((UInt32)item.Size); - padStreamSpec->SetStream(outStream); - padStreamSpec->Init(item.Size, padSize); - } - - // Here we decode minimal required size, including padding - const UInt64 expectedSize = item.Size + padSize; - UInt64 size = coderPackSize; - if (item.Size > coderPackSize) - headersError = true; - else if (expectedSize != coderPackSize) - { - headersError = true; - if (coderPackSize > expectedSize) - size = expectedSize; - } - - result = filterStream->Code(inStream, padStream ? - padStream.Interface() : - outStream.Interface(), - NULL, &size, compressProgress); - - if (outStream->GetSize() != item.Size) - truncatedError = true; - - if (pkAesMode) - { - if (padStreamSpec->GetSize() != size) - truncatedError = true; - if (padStreamSpec->WasPadFailure()) - padError = true; - } - } - else - { - if (item.IsEncrypted()) - { - readFromFilter = true; - inStreamReleaser.FilterCoder = filterStream.ClsPtr(); - RINOK(filterStream->SetInStream(inStream)) - - /* IFilter::Init() does nothing in all zip crypto filters. - So we can call any Initialize function in CFilterCoder. */ - - RINOK(filterStream->Init_NoSubFilterInit()) - // RINOK(filterStream->SetOutStreamSize(NULL)); - } - - try { - result = coder->Code(readFromFilter ? - filterStream.Interface() : - inStream.Interface(), - outStream, - isFullStreamExpected ? &coderPackSize : NULL, - // NULL, - useUnpackLimit ? &item.Size : NULL, - compressProgress); - } catch (...) { return E_FAIL; } - - if (result == S_OK) - { - CMyComPtr getInStreamProcessedSize; - coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); - if (getInStreamProcessedSize && setFinishMode) - { - UInt64 processed; - RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) - if (processed != (UInt64)(Int64)-1) - { - if (pkAesMode) - { - const UInt32 padSize = _pkAesDecoder->GetPadSize((UInt32)processed); - if (processed + padSize > coderPackSize) - truncatedError = true; - else if (processed + padSize < coderPackSize) - dataAfterEnd = true; - else - { - { - // here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder). - CMyComPtr readInStream; - coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream); - // CCopyCoder() for kStore doesn't read data outside of (item.Size) - if (readInStream || id == NFileHeader::NCompressionMethod::kStore) - { - // change pad size, if we support another block size in ZipStrong. - // here we request more data to detect error with data after end. - const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16; - Byte buf[kBufSize]; - UInt32 processedSize = 0; - if (readInStream) - { - RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize)) - } - if (processedSize > padSize) - dataAfterEnd = true; - else - { - size_t processedSize2 = kBufSize - processedSize; - result = ReadStream(filterStream, buf + processedSize, &processedSize2); - if (result == S_OK) - { - processedSize2 += processedSize; - if (processedSize2 > padSize) - dataAfterEnd = true; - else if (processedSize2 < padSize) - truncatedError = true; - else - for (unsigned i = 0; i < padSize; i++) - if (buf[i] != padSize) - padError = true; - } - } - } - } - } - } - else - { - if (processed < coderPackSize) - { - if (isFullStreamExpected) - dataAfterEnd = true; - } - else if (processed > coderPackSize) - { - // that case is additional check, that can show the bugs in code (coder) - truncatedError = true; - } - needReminderCheck = isFullStreamExpected; - } - } - } - } - } - - if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA) - if (!lzmaDecoderSpec->Decoder->CheckFinishStatus(item.IsLzmaEOS())) - lzmaEosError = true; - } - - if (result == S_FALSE) - return S_OK; - - if (result == E_NOTIMPL) - { - res = NExtract::NOperationResult::kUnsupportedMethod; - return S_OK; - } - - RINOK(result) - } - - bool crcOK = true; - bool authOk = true; - if (needCRC) - crcOK = (outStream->GetCRC() == item.Crc); - - if (useUnpackLimit) - if (outStream->GetSize() != item.Size) - truncatedError = true; - - if (wzAesMode) - { - const UInt64 unpackSize = outStream->GetSize(); - const UInt64 packSize = inStream->GetSize(); - bool thereAreData = false; - // read to the end from filter or from packed stream - if (SkipStreamData(readFromFilter ? - filterStream.Interface() : - inStream.Interface(), - compressProgress, packSize, unpackSize, thereAreData) != S_OK) - authOk = false; - if (needReminderCheck && thereAreData) - dataAfterEnd = true; - - if (inStream->GetRem() != 0) - truncatedError = true; - else - { - inStream->Init(NCrypto::NWzAes::kMacSize); - if (_wzAesDecoder->CheckMac(inStream, authOk) != S_OK) - authOk = false; - } - } - - res = NExtract::NOperationResult::kCRCError; - - if (crcOK && authOk) - { - res = NExtract::NOperationResult::kOK; - - if (dataAfterEnd) - res = NExtract::NOperationResult::kDataAfterEnd; - else if (padError) - res = NExtract::NOperationResult::kCRCError; - else if (truncatedError) - res = NExtract::NOperationResult::kUnexpectedEnd; - else if (headersError) - res = NExtract::NOperationResult::kHeadersError; - else if (lzmaEosError) - res = NExtract::NOperationResult::kHeadersError; - else if (badDescriptor) - res = NExtract::NOperationResult::kUnexpectedEnd; - - // CheckDescriptor() supports only data descriptor with signature and - // it doesn't support "old" pkzip's data descriptor without signature. - // So we disable that check. - /* - if (item.HasDescriptor() && archive.CheckDescriptor(item) != S_OK) - res = NExtract::NOperationResult::kHeadersError; - */ - } - - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = m_Items.Size(); - if (numItems == 0) - return S_OK; - UInt64 total = 0; // , totalPacked = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; - total += item.Size; - // totalPacked += item.PackSize; - } - RINOK(extractCallback->SetTotal(total)) - - CZipDecoder myDecoder; - UInt64 cur_Unpacked, cur_Packed; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - for (i = 0;; i++, - lps->OutSize += cur_Unpacked, - lps->InSize += cur_Packed) - { - RINOK(lps->SetCur()) - if (i >= numItems) - return S_OK; - const UInt32 index = allFilesMode ? i : indices[i]; - CItemEx item = m_Items[index]; - cur_Unpacked = item.Size; - cur_Packed = item.PackSize; - - const bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); - const bool skip = !isLocalOffsetOK && !item.IsDir(); - const Int32 askMode = skip ? - NExtract::NAskMode::kSkip : testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - - Int32 opRes; - { - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - if (!isLocalOffsetOK) - { - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)) - continue; - } - - bool headersError = false; - - if (!item.FromLocal) - { - bool isAvail = true; - const HRESULT hres = m_Archive.Read_LocalItem_After_CdItem(item, isAvail, headersError); - if (hres == S_FALSE) - { - if (item.IsDir() || realOutStream || testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult( - isAvail ? - NExtract::NOperationResult::kHeadersError : - NExtract::NOperationResult::kUnavailable)) - } - continue; - } - RINOK(hres) - } - - if (item.IsDir()) - { - // if (!testMode) - { - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - } - continue; - } - - if (!testMode && !realOutStream) - continue; - - RINOK(extractCallback->PrepareOperation(askMode)) - - const HRESULT hres = myDecoder.Decode( - EXTERNAL_CODECS_VARS - m_Archive, item, realOutStream, extractCallback, - lps, - #ifndef Z7_ST - _props._numThreads, _props._memUsage_Decompress, - #endif - opRes); - - RINOK(hres) - // realOutStream.Release(); - - if (opRes == NExtract::NOperationResult::kOK && headersError) - opRes = NExtract::NOperationResult::kHeadersError; - } - RINOK(extractCallback->SetOperationResult(opRes)) - } - - COM_TRY_END -} - -IMPL_ISetCompressCodecsInfo - -}} +// ZipHandler.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantUtils.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../IPassword.h" + +#include "../../Common/FilterCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" +#ifndef Z7_ZIP_LZFSE_DISABLE +#include "../../Compress/LzfseDecoder.h" +#endif +#include "../../Compress/LzmaDecoder.h" +#include "../../Compress/ImplodeDecoder.h" +#include "../../Compress/PpmdZip.h" +#include "../../Compress/ShrinkDecoder.h" +#include "../../Compress/XzDecoder.h" +#include "../../Compress/ZstdDecoder.h" + +#include "../../Crypto/WzAes.h" +#include "../../Crypto/ZipCrypto.h" +#include "../../Crypto/ZipStrong.h" + +#include "../Common/ItemNameUtils.h" +#include "../Common/OutStreamWithCRC.h" + + +#include "ZipHandler.h" + +using namespace NWindows; + +namespace NArchive { +namespace NZip { + +static const char * const kHostOS[] = +{ + "FAT" + , "AMIGA" + , "VMS" + , "Unix" + , "VM/CMS" + , "Atari" + , "HPFS" + , "Macintosh" + , "Z-System" + , "CP/M" + , "TOPS-20" + , "NTFS" + , "SMS/QDOS" + , "Acorn" + , "VFAT" + , "MVS" + , "BeOS" + , "Tandem" + , "OS/400" + , "OS/X" +}; + + +const char * const kMethodNames1[kNumMethodNames1] = +{ + "Store" + , "Shrink" + , "Reduce1" + , "Reduce2" + , "Reduce3" + , "Reduce4" + , "Implode" + , NULL // "Tokenize" + , "Deflate" + , "Deflate64" + , "PKImploding" + , NULL + , "BZip2" + , NULL + , "LZMA" + /* + , NULL + , NULL + , NULL + , NULL + , NULL + , "zstd-pk" // deprecated + */ +}; + + +const char * const kMethodNames2[kNumMethodNames2] = +{ + "zstd" + , "MP3" + , "xz" + , "Jpeg" + , "WavPack" + , "PPMd" + , "LZFSE" // , "WzAES" +}; + +#define kMethod_AES "AES" +#define kMethod_ZipCrypto "ZipCrypto" +#define kMethod_StrongCrypto "StrongCrypto" + +static const char * const kDeflateLevels[4] = +{ + "Normal" + , "Maximum" + , "Fast" + , "Fastest" +}; + + +static const CUInt32PCharPair g_HeaderCharacts[] = +{ + { 0, "Encrypt" }, + { 3, "Descriptor" }, + // { 4, "Enhanced" }, + // { 5, "Patched" }, + { 6, kMethod_StrongCrypto }, + { 11, "UTF8" }, + { 14, "Alt" } +}; + +struct CIdToNamePair +{ + unsigned Id; + const char *Name; +}; + + +static const CIdToNamePair k_StrongCryptoPairs[] = +{ + { NStrongCrypto_AlgId::kDES, "DES" }, + { NStrongCrypto_AlgId::kRC2old, "RC2a" }, + { NStrongCrypto_AlgId::k3DES168, "3DES-168" }, + { NStrongCrypto_AlgId::k3DES112, "3DES-112" }, + { NStrongCrypto_AlgId::kAES128, "pkAES-128" }, + { NStrongCrypto_AlgId::kAES192, "pkAES-192" }, + { NStrongCrypto_AlgId::kAES256, "pkAES-256" }, + { NStrongCrypto_AlgId::kRC2, "RC2" }, + { NStrongCrypto_AlgId::kBlowfish, "Blowfish" }, + { NStrongCrypto_AlgId::kTwofish, "Twofish" }, + { NStrongCrypto_AlgId::kRC4, "RC4" } +}; + +static const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id) +{ + for (unsigned i = 0; i < num; i++) + { + const CIdToNamePair &pair = pairs[i]; + if (id == pair.Id) + return pair.Name; + } + return NULL; +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidMTime, + kpidCTime, + kpidATime, + kpidAttrib, + // kpidPosixAttrib, + kpidEncrypted, + kpidComment, + kpidCRC, + kpidMethod, + kpidCharacts, + kpidHostOS, + kpidUnpackVer, + kpidVolumeIndex, + kpidOffset + // kpidIsAltStream + // , kpidChangeTime // for debug + // , 255 // for debug +}; + +static const Byte kArcProps[] = +{ + kpidEmbeddedStubSize, + kpidBit64, + kpidComment, + kpidCharacts, + kpidTotalPhySize, + kpidIsVolume, + kpidVolumeIndex, + kpidNumVolumes +}; + +CHandler::CHandler() +{ + InitMethodProps(); +} + +static AString BytesToString(const CByteBuffer &data) +{ + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size()); + return s; +} + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; + case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break; + + case kpidPhySize: prop = m_Archive.GetPhySize(); break; + case kpidOffset: prop = m_Archive.GetOffset(); break; + + case kpidEmbeddedStubSize: + { + UInt64 stubSize = m_Archive.GetEmbeddedStubSize(); + if (stubSize != 0) + prop = stubSize; + break; + } + + case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.TotalBytesSize; break; + case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break; + case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break; + case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break; + + case kpidCharacts: + { + AString s; + + if (m_Archive.LocalsWereRead) + { + s.Add_OptSpaced("Local"); + + if (m_Archive.LocalsCenterMerged) + s.Add_OptSpaced("Central"); + } + + if (m_Archive.IsZip64) + s.Add_OptSpaced("Zip64"); + + if (m_Archive.IsCdUnsorted) + s.Add_OptSpaced("Unsorted_CD"); + + if (m_Archive.IsApk) + s.Add_OptSpaced("apk"); + + if (m_Archive.ExtraMinorError) + s.Add_OptSpaced("Minor_Extra_ERROR"); + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidWarningFlags: + { + UInt32 v = 0; + // if (m_Archive.ExtraMinorError) v |= kpv_ErrorFlags_HeadersError; + if (m_Archive.HeadersWarning) v |= kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + + case kpidWarning: + { + AString s; + if (m_Archive.Overflow32bit) + s.Add_OptSpaced("32-bit overflow in headers"); + if (m_Archive.Cd_NumEntries_Overflow_16bit) + s.Add_OptSpaced("16-bit overflow for number of files in headers"); + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidError: + { + if (!m_Archive.Vols.MissingName.IsEmpty()) + { + UString s("Missing volume : "); + s += m_Archive.Vols.MissingName; + prop = s; + } + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!m_Archive.IsArc) v |= kpv_ErrorFlags_IsNotArc; + if (m_Archive.HeadersError) v |= kpv_ErrorFlags_HeadersError; + if (m_Archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + if (m_Archive.ArcInfo.Base < 0) + { + /* We try to support case when we have sfx-zip with embedded stub, + but the stream has access only to zip part. + In that case we ignore UnavailableStart error. + maybe we must show warning in that case. */ + UInt64 stubSize = m_Archive.GetEmbeddedStubSize(); + if (stubSize < (UInt64)-m_Archive.ArcInfo.Base) + v |= kpv_ErrorFlags_UnavailableStart; + } + if (m_Archive.NoCentralDir) v |= kpv_ErrorFlags_UnconfirmedStart; + prop = v; + break; + } + + case kpidReadOnly: + { + if (m_Archive.IsOpen()) + if (!m_Archive.CanUpdate()) + prop = true; + break; + } + + // case kpidIsAltStream: prop = true; break; + default: break; + } + return prop.Detach(value); + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = m_Items.Size(); + return S_OK; +} + + +static bool NtfsUnixTimeToProp(bool fromCentral, + const CExtraBlock &extra, + unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop) +{ + { + FILETIME ft; + if (extra.GetNtfsTime(ntfsIndex, ft)) + { + PropVariant_SetFrom_NtfsTime(prop, ft); + return true; + } + } + { + UInt32 unixTime = 0; + if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime)) + return false; + /* + // we allow unixTime == 0 + if (unixTime == 0) + return false; + */ + PropVariant_SetFrom_UnixTime(prop, unixTime); + return true; + } +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CItemEx &item = m_Items[index]; + const CExtraBlock &extra = item.GetMainExtra(); + + switch (propID) + { + case kpidPath: + { + UString res; + item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(res, + item.Is_MadeBy_Unix() // useBackslashReplacement + ); + /* + if (item.ParentOfAltStream >= 0) + { + const CItemEx &prevItem = m_Items[item.ParentOfAltStream]; + UString prevName; + prevItem.GetUnicodeString(prevName, prevItem.Name, false, _forceCodePage, _specifiedCodePage); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(prevName); + if (res.IsPrefixedBy(prevName)) + if (IsString1PrefixedByString2(res.Ptr(prevName.Len()), k_SpecName_NTFS_STREAM)) + { + res.Delete(prevName.Len(), (unsigned)strlen(k_SpecName_NTFS_STREAM)); + res.Insert(prevName.Len(), L":"); + } + } + */ + prop = res; + break; + } + + case kpidIsDir: prop = item.IsDir(); break; + case kpidSize: + { + if (!item.IsBadDescriptor()) + prop = item.Size; + break; + } + + case kpidPackSize: prop = item.PackSize; break; + + case kpidCTime: + NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kCTime, + NFileHeader::NUnixTime::kCTime, prop); + break; + + case kpidATime: + NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kATime, + NFileHeader::NUnixTime::kATime, prop); + break; + + case kpidMTime: + { + if (!NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kMTime, + NFileHeader::NUnixTime::kMTime, prop)) + { + if (item.Time != 0) + PropVariant_SetFrom_DosTime(prop, item.Time); + } + break; + } + + case kpidTimeType: + { + FILETIME ft; + UInt32 unixTime; + UInt32 type; + if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) + type = NFileTimeType::kWindows; + else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime)) + type = NFileTimeType::kUnix; + else + type = NFileTimeType::kDOS; + prop = type; + break; + } + + /* + // for debug to get Dos time values: + case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break; + // for debug + // time difference (dos - utc) + case 255: + { + if (NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kMTime, + NFileHeader::NUnixTime::kMTime, prop)) + { + FILETIME localFileTime; + if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime)) + { + UInt64 t1 = FILETIME_To_UInt64(prop.filetime); + UInt64 t2 = FILETIME_To_UInt64(localFileTime); + prop.Set_Int64(t2 - t1); + } + } + break; + } + */ + + case kpidAttrib: prop = item.GetWinAttrib(); break; + + case kpidPosixAttrib: + { + UInt32 attrib; + if (item.GetPosixAttrib(attrib)) + prop = attrib; + break; + } + + case kpidEncrypted: prop = item.IsEncrypted(); break; + + case kpidComment: + { + if (item.Comment.Size() != 0) + { + UString res; + item.GetUnicodeString(res, BytesToString(item.Comment), true, _forceCodePage, _specifiedCodePage); + prop = res; + } + break; + } + + case kpidCRC: if (item.IsThereCrc()) prop = item.Crc; break; + + case kpidMethod: + { + AString m; + bool isWzAes = false; + unsigned id = item.Method; + + if (id == NFileHeader::NCompressionMethod::kWzAES) + { + CWzAesExtra aesField; + if (extra.GetWzAes(aesField)) + { + m += kMethod_AES; + m.Add_Minus(); + m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64); + id = aesField.Method; + isWzAes = true; + } + } + + if (item.IsEncrypted()) + if (!isWzAes) + { + if (item.IsStrongEncrypted()) + { + CStrongCryptoExtra f; + f.AlgId = 0; + if (extra.GetStrongCrypto(f)) + { + const char *s = FindNameForId(k_StrongCryptoPairs, Z7_ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId); + if (s) + m += s; + else + { + m += kMethod_StrongCrypto; + m.Add_Colon(); + m.Add_UInt32(f.AlgId); + } + if (f.CertificateIsUsed()) + m += "-Cert"; + } + else + m += kMethod_StrongCrypto; + } + else + m += kMethod_ZipCrypto; + } + + m.Add_Space_if_NotEmpty(); + + { + const char *s = NULL; + if (id < kNumMethodNames1) + s = kMethodNames1[id]; + else + { + const int id2 = (int)id - (int)kMethodNames2Start; + if (id2 >= 0 && (unsigned)id2 < kNumMethodNames2) + s = kMethodNames2[id2]; + } + if (s) + m += s; + else + m.Add_UInt32(id); + } + { + unsigned level = item.GetDeflateLevel(); + if (level != 0) + { + if (id == NFileHeader::NCompressionMethod::kLZMA) + { + if (level & 1) + m += ":eos"; + level &= ~(unsigned)1; + } + else if (id == NFileHeader::NCompressionMethod::kDeflate) + { + m.Add_Colon(); + m += kDeflateLevels[level]; + level = 0; + } + + if (level != 0) + { + m += ":v"; + m.Add_UInt32(level); + } + } + } + + prop = m; + break; + } + + case kpidCharacts: + { + AString s; + + if (item.FromLocal) + { + s.Add_OptSpaced("Local"); + + item.LocalExtra.PrintInfo(s); + + if (item.FromCentral) + { + s.Add_OptSpaced(":"); + s.Add_OptSpaced("Central"); + } + } + + if (item.FromCentral) + { + item.CentralExtra.PrintInfo(s); + } + + UInt32 flags = item.Flags; + flags &= ~(unsigned)6; // we don't need compression related bits here. + + if (flags != 0) + { + const AString s2 = FlagsToString(g_HeaderCharacts, Z7_ARRAY_SIZE(g_HeaderCharacts), flags); + if (!s2.IsEmpty()) + { + if (!s.IsEmpty()) + s.Add_OptSpaced(":"); + s.Add_OptSpaced(s2); + } + } + + if (item.IsBadDescriptor()) + s.Add_OptSpaced("Descriptor_ERROR"); + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidHostOS: + { + if (item.FromCentral) + { + // 18.06: now we use HostOS only from Central::MadeByVersion + const Byte hostOS = item.MadeByVersion.HostOS; + TYPE_TO_PROP(kHostOS, hostOS, prop); + } + break; + } + + case kpidUnpackVer: + prop = (UInt32)item.ExtractVersion.Version; + break; + + case kpidVolumeIndex: + prop = item.Disk; + break; + + case kpidOffset: + prop = item.LocalHeaderPos; + break; + + /* + case kpidIsAltStream: + prop = (bool)(item.ParentOfAltStream >= 0); // item.IsAltStream(); + break; + + case kpidName: + if (item.ParentOfAltStream >= 0) + { + // extract name of stream here + } + break; + */ + default: break; + } + + return prop.Detach(value); + COM_TRY_END +} + + + +/* +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID) +{ + UNUSED_VAR(index); + *propID = 0; + *name = 0; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + if (index >= m_Items.Size()) + return S_OK; + const CItemEx &item = m_Items[index]; + + if (item.ParentOfAltStream >= 0) + { + *parentType = NParentType::kAltStream; + *parent = item.ParentOfAltStream; + } + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + UNUSED_VAR(index); + UNUSED_VAR(propID); + *data = NULL; + *dataSize = 0; + *propType = 0; + return S_OK; +} + + +void CHandler::MarkAltStreams(CObjectVector &items) +{ + int prevIndex = -1; + UString prevName; + UString name; + + for (unsigned i = 0; i < items.Size(); i++) + { + CItemEx &item = m_Items[i]; + if (item.IsAltStream()) + { + if (prevIndex == -1) + continue; + if (prevName.IsEmpty()) + { + const CItemEx &prevItem = m_Items[prevIndex]; + prevItem.GetUnicodeString(prevName, prevItem.Name, false, _forceCodePage, _specifiedCodePage); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(prevName); + } + name.Empty(); + item.GetUnicodeString(name, item.Name, false, _forceCodePage, _specifiedCodePage); + NItemName::ReplaceToOsSlashes_Remove_TailSlash(name); + + if (name.IsPrefixedBy(prevName)) + if (IsString1PrefixedByString2(name.Ptr(prevName.Len()), k_SpecName_NTFS_STREAM)) + item.ParentOfAltStream = prevIndex; + } + else + { + prevIndex = i; + prevName.Empty(); + } + } +} +*/ + +Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, + const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + try + { + Close(); + m_Archive.Force_ReadLocals_Mode = _force_OpenSeq; + // m_Archive.Disable_VolsRead = _force_OpenSeq; + // m_Archive.Disable_FindMarker = _force_OpenSeq; + HRESULT res = m_Archive.Open(inStream, maxCheckStartPosition, callback, m_Items); + if (res != S_OK) + { + m_Items.Clear(); + m_Archive.ClearRefs(); // we don't want to clear error flags + } + // MarkAltStreams(m_Items); + return res; + } + catch(...) { Close(); throw; } + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + m_Items.Clear(); + m_Archive.Close(); + return S_OK; +} + + +Z7_CLASS_IMP_NOQIB_3( + CLzmaDecoder + , ICompressCoder + , ICompressSetFinishMode + , ICompressGetInStreamProcessedSize +) +public: + CMyComPtr2_Create Decoder; +}; + +static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE; + +Z7_COM7F_IMF(CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + Byte buf[kZipLzmaPropsSize]; + RINOK(ReadStream_FALSE(inStream, buf, kZipLzmaPropsSize)) + if (buf[2] != LZMA_PROPS_SIZE || buf[3] != 0) + return E_NOTIMPL; + RINOK(Decoder->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE)) + UInt64 inSize2 = 0; + if (inSize) + { + inSize2 = *inSize; + if (inSize2 < kZipLzmaPropsSize) + return S_FALSE; + inSize2 -= kZipLzmaPropsSize; + } + return Decoder.Interface()->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress); +} + +Z7_COM7F_IMF(CLzmaDecoder::SetFinishMode(UInt32 finishMode)) +{ + Decoder->FinishStream = (finishMode != 0); + return S_OK; +} + +Z7_COM7F_IMF(CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = Decoder->GetInputProcessedSize() + kZipLzmaPropsSize; + return S_OK; +} + + + + + + + +struct CMethodItem +{ + unsigned ZipMethod; + CMyComPtr Coder; +}; + + + +class CZipDecoder +{ + CMyComPtr2 _zipCryptoDecoder; + CMyComPtr2 _pkAesDecoder; + CMyComPtr2 _wzAesDecoder; + + CMyComPtr2 filterStream; + CMyComPtr getTextPassword; + CObjectVector methodItems; + + CLzmaDecoder *lzmaDecoderSpec; +public: + CZipDecoder(): + lzmaDecoderSpec(NULL) + {} + + HRESULT Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + CInArchive &archive, const CItemEx &item, + ISequentialOutStream *realOutStream, + IArchiveExtractCallback *extractCallback, + ICompressProgressInfo *compressProgress, + #ifndef Z7_ST + UInt32 numThreads, UInt64 memUsage, + #endif + Int32 &res); +}; + + +static HRESULT SkipStreamData(ISequentialInStream *stream, + ICompressProgressInfo *progress, UInt64 packSize, UInt64 unpackSize, + bool &thereAreData) +{ + thereAreData = false; + const size_t kBufSize = 1 << 12; + Byte buf[kBufSize]; + UInt64 prev = packSize; + for (;;) + { + size_t size = kBufSize; + RINOK(ReadStream(stream, buf, &size)) + if (size == 0) + return S_OK; + thereAreData = true; + packSize += size; + if ((packSize - prev) >= (1 << 22)) + { + prev = packSize; + RINOK(progress->SetRatioInfo(&packSize, &unpackSize)) + } + } +} + + + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithPadPKCS7 + , ISequentialOutStream +) + CMyComPtr _stream; + UInt64 _size; + UInt64 _padPos; + UInt32 _padSize; + bool _padFailure; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + + // padSize == 0 means (no_pad Mode) + void Init(UInt64 padPos, UInt32 padSize) + { + _padPos = padPos; + _padSize = padSize; + _size = 0; + _padFailure = false; + } + UInt64 GetSize() const { return _size; } + bool WasPadFailure() const { return _padFailure; } +}; + + +Z7_COM7F_IMF(COutStreamWithPadPKCS7::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 written = 0; + HRESULT result = S_OK; + if (_size < _padPos) + { + const UInt64 rem = _padPos - _size; + UInt32 num = size; + if (num > rem) + num = (UInt32)rem; + result = _stream->Write(data, num, &written); + _size += written; + if (processedSize) + *processedSize = written; + if (_size != _padPos || result != S_OK) + return result; + size -= written; + data = ((const Byte *)data) + written; + } + _size += size; + written += size; + if (processedSize) + *processedSize = written; + if (_padSize != 0) + for (; size != 0; size--) + { + if (*(const Byte *)data != _padSize) + _padFailure = true; + data = ((const Byte *)data) + 1; + } + return result; +} + + + +HRESULT CZipDecoder::Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + CInArchive &archive, const CItemEx &item, + ISequentialOutStream *realOutStream, + IArchiveExtractCallback *extractCallback, + ICompressProgressInfo *compressProgress, + #ifndef Z7_ST + UInt32 numThreads, UInt64 memUsage, + #endif + Int32 &res) +{ + res = NExtract::NOperationResult::kHeadersError; + + CFilterCoder::C_InStream_Releaser inStreamReleaser; + CFilterCoder::C_Filter_Releaser filterReleaser; + + bool needCRC = true; + bool wzAesMode = false; + bool pkAesMode = false; + + bool badDescriptor = item.IsBadDescriptor(); + if (badDescriptor) + needCRC = false; + + + unsigned id = item.Method; + + CWzAesExtra aesField; + // LZFSE and WinZip's AES use same id - kWzAES. + + if (id == NFileHeader::NCompressionMethod::kWzAES) + { + if (item.GetMainExtra().GetWzAes(aesField)) + { + if (!item.IsEncrypted()) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + wzAesMode = true; + needCRC = aesField.NeedCrc(); + } + } + + if (!wzAesMode) + if (item.IsEncrypted()) + { + if (item.IsStrongEncrypted()) + { + CStrongCryptoExtra f; + if (!item.CentralExtra.GetStrongCrypto(f)) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + pkAesMode = true; + } + } + + CMyComPtr2_Create outStream; + outStream->SetStream(realOutStream); + outStream->Init(needCRC); + + CMyComPtr packStream; + CMyComPtr2_Create inStream; + + { + UInt64 packSize = item.PackSize; + if (wzAesMode) + { + if (packSize < NCrypto::NWzAes::kMacSize) + return S_OK; + packSize -= NCrypto::NWzAes::kMacSize; + } + RINOK(archive.GetItemStream(item, true, packStream)) + if (!packStream) + { + res = NExtract::NOperationResult::kUnavailable; + return S_OK; + } + inStream->SetStream(packStream); + inStream->Init(packSize); + } + + + res = NExtract::NOperationResult::kDataError; + + CMyComPtr cryptoFilter; + + if (item.IsEncrypted()) + { + if (wzAesMode) + { + id = aesField.Method; + _wzAesDecoder.Create_if_Empty(); + cryptoFilter = _wzAesDecoder; + if (!_wzAesDecoder->SetKeyMode(aesField.Strength)) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + } + else if (pkAesMode) + { + _pkAesDecoder.Create_if_Empty(); + cryptoFilter = _pkAesDecoder; + } + else + { + _zipCryptoDecoder.Create_if_Empty(); + cryptoFilter = _zipCryptoDecoder; + } + + CMyComPtr cryptoSetPassword; + RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)) + if (!cryptoSetPassword) + return E_FAIL; + + if (!getTextPassword) + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); + + if (getTextPassword) + { + CMyComBSTR_Wipe password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)) + AString_Wipe charPassword; + if (password) + { +#if 0 && defined(_WIN32) + // do we need UTF-8 passwords here ? + if (item.GetHostOS() == NFileHeader::NHostOS::kUnix // 24.05 + // || item.IsUtf8() // 22.00 + ) + { + // throw 1; + ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword); + } + else +#endif + { + UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP); + } + /* + if (wzAesMode || pkAesMode) + { + } + else + { + // PASSWORD encoding for ZipCrypto: + // pkzip25 / WinZip / Windows probably use ANSI + // 7-Zip < 4.43 creates ZIP archives with OEM encoding in password + // 7-Zip >= 4.43 creates ZIP archives only with ASCII characters in password + // 7-Zip < 17.00 uses CP_OEMCP for password decoding + // 7-Zip >= 17.00 uses CP_ACP for password decoding + } + */ + } + HRESULT result = cryptoSetPassword->CryptoSetPassword( + (const Byte *)(const char *)charPassword, charPassword.Len()); + if (result != S_OK) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } + else + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + // RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0)); + } + } + + unsigned m; + for (m = 0; m < methodItems.Size(); m++) + if (methodItems[m].ZipMethod == id) + break; + + if (m == methodItems.Size()) + { + CMethodItem mi; + mi.ZipMethod = id; + if (id == NFileHeader::NCompressionMethod::kStore) + mi.Coder = new NCompress::CCopyCoder; + else if (id == NFileHeader::NCompressionMethod::kShrink) + mi.Coder = new NCompress::NShrink::CDecoder; + else if (id == NFileHeader::NCompressionMethod::kImplode) + mi.Coder = new NCompress::NImplode::NDecoder::CCoder; + else if (id == NFileHeader::NCompressionMethod::kLZMA) + { + lzmaDecoderSpec = new CLzmaDecoder; + mi.Coder = lzmaDecoderSpec; + } + else if (id == NFileHeader::NCompressionMethod::kXz) + mi.Coder = new NCompress::NXz::CComDecoder; + else if (id == NFileHeader::NCompressionMethod::kPPMd) + mi.Coder = new NCompress::NPpmdZip::CDecoder(true); + else if (id == NFileHeader::NCompressionMethod::kZstdWz) + mi.Coder = new NCompress::NZstd::CDecoder(); +#ifndef Z7_ZIP_LZFSE_DISABLE + else if (id == NFileHeader::NCompressionMethod::kWzAES) + mi.Coder = new NCompress::NLzfse::CDecoder; +#endif + else + { + CMethodId szMethodID; + if (id == NFileHeader::NCompressionMethod::kBZip2) + szMethodID = kMethodId_BZip2; + else + { + if (id > 0xFF) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + szMethodID = kMethodId_ZipBase + (Byte)id; + } + + RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder)) + + if (!mi.Coder) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + } + m = methodItems.Add(mi); + } + + const CMethodItem &mi = methodItems[m]; + ICompressCoder *coder = mi.Coder; + + + #ifndef Z7_ST + { + CMyComPtr setCoderMt; + coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(numThreads)) + } + } + // if (memUsage != 0) + { + CMyComPtr setMemLimit; + coder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); + if (setMemLimit) + { + RINOK(setMemLimit->SetMemLimit(memUsage)) + } + } + #endif + + { + CMyComPtr setDecoderProperties; + coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); + if (setDecoderProperties) + { + Byte properties = (Byte)item.Flags; + RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)) + } + } + + + bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0); + bool needReminderCheck = false; + + bool dataAfterEnd = false; + bool truncatedError = false; + bool lzmaEosError = false; + bool headersError = false; + bool padError = false; + bool readFromFilter = false; + + const bool useUnpackLimit = (id == NFileHeader::NCompressionMethod::kStore + || !item.HasDescriptor() + || item.Size >= ((UInt64)1 << 32) + || item.LocalExtra.IsZip64 + || item.CentralExtra.IsZip64 + ); + + { + HRESULT result = S_OK; + if (item.IsEncrypted()) + { + if (!filterStream.IsDefined()) + filterStream.SetFromCls(new CFilterCoder(false)); + + filterReleaser.FilterCoder = filterStream.ClsPtr(); + filterStream->Filter = cryptoFilter; + + if (wzAesMode) + { + result = _wzAesDecoder->ReadHeader(inStream); + if (result == S_OK) + { + if (!_wzAesDecoder->Init_and_CheckPassword()) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } + } + else if (pkAesMode) + { + isFullStreamExpected = false; + result = _pkAesDecoder->ReadHeader(inStream, item.Crc, item.Size); + if (result == S_OK) + { + bool passwOK; + result = _pkAesDecoder->Init_and_CheckPassword(passwOK); + if (result == S_OK && !passwOK) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } + } + else + { + result = _zipCryptoDecoder->ReadHeader(inStream); + if (result == S_OK) + { + _zipCryptoDecoder->Init_BeforeDecode(); + + /* Info-ZIP modification to ZipCrypto format: + if bit 3 of the general purpose bit flag is set, + it uses high byte of 16-bit File Time. + Info-ZIP code probably writes 2 bytes of File Time. + We check only 1 byte. */ + + // UInt32 v1 = GetUi16(_zipCryptoDecoder->_header + NCrypto::NZip::kHeaderSize - 2); + // UInt32 v2 = (item.HasDescriptor() ? (item.Time & 0xFFFF) : (item.Crc >> 16)); + + Byte v1 = _zipCryptoDecoder->_header[NCrypto::NZip::kHeaderSize - 1]; + Byte v2 = (Byte)(item.HasDescriptor() ? (item.Time >> 8) : (item.Crc >> 24)); + + if (v1 != v2) + { + res = NExtract::NOperationResult::kWrongPassword; + return S_OK; + } + } + } + } + + if (result == S_OK) + { + CMyComPtr setFinishMode; + coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToUInt(true))) + } + + const UInt64 coderPackSize = inStream->GetRem(); + + if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted()) + { + // for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter + // here we use filter without CopyCoder + readFromFilter = false; + + COutStreamWithPadPKCS7 *padStreamSpec = NULL; + CMyComPtr padStream; + UInt32 padSize = 0; + + if (pkAesMode) + { + padStreamSpec = new COutStreamWithPadPKCS7; + padStream = padStreamSpec; + padSize = _pkAesDecoder->GetPadSize((UInt32)item.Size); + padStreamSpec->SetStream(outStream); + padStreamSpec->Init(item.Size, padSize); + } + + // Here we decode minimal required size, including padding + const UInt64 expectedSize = item.Size + padSize; + UInt64 size = coderPackSize; + if (item.Size > coderPackSize) + headersError = true; + else if (expectedSize != coderPackSize) + { + headersError = true; + if (coderPackSize > expectedSize) + size = expectedSize; + } + + result = filterStream->Code(inStream, padStream ? + padStream.Interface() : + outStream.Interface(), + NULL, &size, compressProgress); + + if (outStream->GetSize() != item.Size) + truncatedError = true; + + if (pkAesMode) + { + if (padStreamSpec->GetSize() != size) + truncatedError = true; + if (padStreamSpec->WasPadFailure()) + padError = true; + } + } + else + { + if (item.IsEncrypted()) + { + readFromFilter = true; + inStreamReleaser.FilterCoder = filterStream.ClsPtr(); + RINOK(filterStream->SetInStream(inStream)) + + /* IFilter::Init() does nothing in all zip crypto filters. + So we can call any Initialize function in CFilterCoder. */ + + RINOK(filterStream->Init_NoSubFilterInit()) + // RINOK(filterStream->SetOutStreamSize(NULL)); + } + + try { + result = coder->Code(readFromFilter ? + filterStream.Interface() : + inStream.Interface(), + outStream, + isFullStreamExpected ? &coderPackSize : NULL, + // NULL, + useUnpackLimit ? &item.Size : NULL, + compressProgress); + } catch (...) { return E_FAIL; } + + if (result == S_OK) + { + CMyComPtr getInStreamProcessedSize; + coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); + if (getInStreamProcessedSize && setFinishMode) + { + UInt64 processed; + RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) + if (processed != (UInt64)(Int64)-1) + { + if (pkAesMode) + { + const UInt32 padSize = _pkAesDecoder->GetPadSize((UInt32)processed); + if (processed + padSize > coderPackSize) + truncatedError = true; + else if (processed + padSize < coderPackSize) + dataAfterEnd = true; + else + { + { + // here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder). + CMyComPtr readInStream; + coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream); + // CCopyCoder() for kStore doesn't read data outside of (item.Size) + if (readInStream || id == NFileHeader::NCompressionMethod::kStore) + { + // change pad size, if we support another block size in ZipStrong. + // here we request more data to detect error with data after end. + const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16; + Byte buf[kBufSize]; + UInt32 processedSize = 0; + if (readInStream) + { + RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize)) + } + if (processedSize > padSize) + dataAfterEnd = true; + else + { + size_t processedSize2 = kBufSize - processedSize; + result = ReadStream(filterStream, buf + processedSize, &processedSize2); + if (result == S_OK) + { + processedSize2 += processedSize; + if (processedSize2 > padSize) + dataAfterEnd = true; + else if (processedSize2 < padSize) + truncatedError = true; + else + for (unsigned i = 0; i < padSize; i++) + if (buf[i] != padSize) + padError = true; + } + } + } + } + } + } + else + { + if (processed < coderPackSize) + { + if (isFullStreamExpected) + dataAfterEnd = true; + } + else if (processed > coderPackSize) + { + // that case is additional check, that can show the bugs in code (coder) + truncatedError = true; + } + needReminderCheck = isFullStreamExpected; + } + } + } + } + } + + if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA) + if (!lzmaDecoderSpec->Decoder->CheckFinishStatus(item.IsLzmaEOS())) + lzmaEosError = true; + } + + if (result == S_FALSE) + return S_OK; + + if (result == E_NOTIMPL) + { + res = NExtract::NOperationResult::kUnsupportedMethod; + return S_OK; + } + + RINOK(result) + } + + bool crcOK = true; + bool authOk = true; + if (needCRC) + crcOK = (outStream->GetCRC() == item.Crc); + + if (useUnpackLimit) + if (outStream->GetSize() != item.Size) + truncatedError = true; + + if (wzAesMode) + { + const UInt64 unpackSize = outStream->GetSize(); + const UInt64 packSize = inStream->GetSize(); + bool thereAreData = false; + // read to the end from filter or from packed stream + if (SkipStreamData(readFromFilter ? + filterStream.Interface() : + inStream.Interface(), + compressProgress, packSize, unpackSize, thereAreData) != S_OK) + authOk = false; + if (needReminderCheck && thereAreData) + dataAfterEnd = true; + + if (inStream->GetRem() != 0) + truncatedError = true; + else + { + inStream->Init(NCrypto::NWzAes::kMacSize); + if (_wzAesDecoder->CheckMac(inStream, authOk) != S_OK) + authOk = false; + } + } + + res = NExtract::NOperationResult::kCRCError; + + if (crcOK && authOk) + { + res = NExtract::NOperationResult::kOK; + + if (dataAfterEnd) + res = NExtract::NOperationResult::kDataAfterEnd; + else if (padError) + res = NExtract::NOperationResult::kCRCError; + else if (truncatedError) + res = NExtract::NOperationResult::kUnexpectedEnd; + else if (headersError) + res = NExtract::NOperationResult::kHeadersError; + else if (lzmaEosError) + res = NExtract::NOperationResult::kHeadersError; + else if (badDescriptor) + res = NExtract::NOperationResult::kUnexpectedEnd; + + // CheckDescriptor() supports only data descriptor with signature and + // it doesn't support "old" pkzip's data descriptor without signature. + // So we disable that check. + /* + if (item.HasDescriptor() && archive.CheckDescriptor(item) != S_OK) + res = NExtract::NOperationResult::kHeadersError; + */ + } + + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = m_Items.Size(); + if (numItems == 0) + return S_OK; + UInt64 total = 0; // , totalPacked = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; + total += item.Size; + // totalPacked += item.PackSize; + } + RINOK(extractCallback->SetTotal(total)) + + CZipDecoder myDecoder; + UInt64 cur_Unpacked, cur_Packed; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + for (i = 0;; i++, + lps->OutSize += cur_Unpacked, + lps->InSize += cur_Packed) + { + RINOK(lps->SetCur()) + if (i >= numItems) + return S_OK; + const UInt32 index = allFilesMode ? i : indices[i]; + CItemEx item = m_Items[index]; + cur_Unpacked = item.Size; + cur_Packed = item.PackSize; + + const bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item); + const bool skip = !isLocalOffsetOK && !item.IsDir(); + const Int32 askMode = skip ? + NExtract::NAskMode::kSkip : testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + + Int32 opRes; + { + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + if (!isLocalOffsetOK) + { + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)) + continue; + } + + bool headersError = false; + + if (!item.FromLocal) + { + bool isAvail = true; + const HRESULT hres = m_Archive.Read_LocalItem_After_CdItem(item, isAvail, headersError); + if (hres == S_FALSE) + { + if (item.IsDir() || realOutStream || testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult( + isAvail ? + NExtract::NOperationResult::kHeadersError : + NExtract::NOperationResult::kUnavailable)) + } + continue; + } + RINOK(hres) + } + + if (item.IsDir()) + { + // if (!testMode) + { + RINOK(extractCallback->PrepareOperation(askMode)) + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) + } + continue; + } + + if (!testMode && !realOutStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)) + + const HRESULT hres = myDecoder.Decode( + EXTERNAL_CODECS_VARS + m_Archive, item, realOutStream, extractCallback, + lps, + #ifndef Z7_ST + _props._numThreads, _props._memUsage_Decompress, + #endif + opRes); + + RINOK(hres) + // realOutStream.Release(); + + if (opRes == NExtract::NOperationResult::kOK && headersError) + opRes = NExtract::NOperationResult::kHeadersError; + } + RINOK(extractCallback->SetOperationResult(opRes)) + } + + COM_TRY_END +} + +IMPL_ISetCompressCodecsInfo + +}} diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h index ae2d33c12..1f38bfff2 100644 --- a/CPP/7zip/Archive/Zip/ZipHandler.h +++ b/CPP/7zip/Archive/Zip/ZipHandler.h @@ -1,94 +1,94 @@ -// Zip/Handler.h - -#ifndef ZIP7_INC_ZIP_HANDLER_H -#define ZIP7_INC_ZIP_HANDLER_H - -#include "../../../Common/DynamicBuffer.h" -#include "../../ICoder.h" -#include "../IArchive.h" - -#include "../../Common/CreateCoder.h" - -#include "ZipCompressionMode.h" -#include "ZipIn.h" - -namespace NArchive { -namespace NZip { - -const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kZstdPk + 1; -const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kZstdWz; -const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start; - -extern const char * const kMethodNames1[kNumMethodNames1]; -extern const char * const kMethodNames2[kNumMethodNames2]; - - -class CHandler Z7_final: - public IInArchive, - // public IArchiveGetRawProps, - public IOutArchive, - public ISetProperties, - Z7_PUBLIC_ISetCompressCodecsInfo_IFEC - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IInArchive) - // Z7_COM_QI_ENTRY(IArchiveGetRawProps) - Z7_COM_QI_ENTRY(IOutArchive) - Z7_COM_QI_ENTRY(ISetProperties) - Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInArchive) - // Z7_IFACE_COM7_IMP(IArchiveGetRawProps) - Z7_IFACE_COM7_IMP(IOutArchive) - Z7_IFACE_COM7_IMP(ISetProperties) - DECL_ISetCompressCodecsInfo - -private: - CObjectVector m_Items; - CInArchive m_Archive; - - CBaseProps _props; - CHandlerTimeOptions TimeOptions; - - int m_MainMethod; - bool m_ForceAesMode; - - bool _removeSfxBlock; - bool m_ForceLocal; - bool m_ForceUtf8; - bool _force_SeqOutMode; // for creation - bool _force_OpenSeq; - bool _forceCodePage; - UInt32 _specifiedCodePage; - - DECL_EXTERNAL_CODECS_VARS - - void InitMethodProps() - { - _props.Init(); - TimeOptions.Init(); - TimeOptions.Prec = k_PropVar_TimePrec_0; - m_MainMethod = -1; - m_ForceAesMode = false; - _removeSfxBlock = false; - m_ForceLocal = false; - m_ForceUtf8 = false; - _force_SeqOutMode = false; - _force_OpenSeq = false; - _forceCodePage = false; - _specifiedCodePage = CP_OEMCP; - } - - // void MarkAltStreams(CObjectVector &items); - - HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); - -public: - CHandler(); -}; - -}} - -#endif +// Zip/Handler.h + +#ifndef ZIP7_INC_ZIP_HANDLER_H +#define ZIP7_INC_ZIP_HANDLER_H + +#include "../../../Common/DynamicBuffer.h" +#include "../../ICoder.h" +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#include "ZipCompressionMode.h" +#include "ZipIn.h" + +namespace NArchive { +namespace NZip { + +const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kZstdPk + 1; +const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kZstdWz; +const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start; + +extern const char * const kMethodNames1[kNumMethodNames1]; +extern const char * const kMethodNames2[kNumMethodNames2]; + + +class CHandler Z7_final: + public IInArchive, + // public IArchiveGetRawProps, + public IOutArchive, + public ISetProperties, + Z7_PUBLIC_ISetCompressCodecsInfo_IFEC + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IInArchive) + // Z7_COM_QI_ENTRY(IArchiveGetRawProps) + Z7_COM_QI_ENTRY(IOutArchive) + Z7_COM_QI_ENTRY(ISetProperties) + Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInArchive) + // Z7_IFACE_COM7_IMP(IArchiveGetRawProps) + Z7_IFACE_COM7_IMP(IOutArchive) + Z7_IFACE_COM7_IMP(ISetProperties) + DECL_ISetCompressCodecsInfo + +private: + CObjectVector m_Items; + CInArchive m_Archive; + + CBaseProps _props; + CHandlerTimeOptions TimeOptions; + + int m_MainMethod; + bool m_ForceAesMode; + + bool _removeSfxBlock; + bool m_ForceLocal; + bool m_ForceUtf8; + bool _force_SeqOutMode; // for creation + bool _force_OpenSeq; + bool _forceCodePage; + UInt32 _specifiedCodePage; + + DECL_EXTERNAL_CODECS_VARS + + void InitMethodProps() + { + _props.Init(); + TimeOptions.Init(); + TimeOptions.Prec = k_PropVar_TimePrec_0; + m_MainMethod = -1; + m_ForceAesMode = false; + _removeSfxBlock = false; + m_ForceLocal = false; + m_ForceUtf8 = false; + _force_SeqOutMode = false; + _force_OpenSeq = false; + _forceCodePage = false; + _specifiedCodePage = CP_OEMCP; + } + + // void MarkAltStreams(CObjectVector &items); + + HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); + +public: + CHandler(); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp index aa9802e65..46ccf3d8b 100644 --- a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp @@ -1,626 +1,626 @@ -// ZipHandlerOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../IPassword.h" - -#include "../../Common/OutBuffer.h" - -#include "../../Crypto/WzAes.h" - -#include "../Common/ItemNameUtils.h" -#include "../Common/ParseProperties.h" - -#include "ZipHandler.h" -#include "ZipUpdate.h" - -using namespace NWindows; -using namespace NCOM; -using namespace NTime; - -namespace NArchive { -namespace NZip { - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) -{ - *timeType = TimeOptions.Prec; - return S_OK; -} - -static bool IsSimpleAsciiString(const wchar_t *s) -{ - for (;;) - { - wchar_t c = *s++; - if (c == 0) - return true; - if (c < 0x20 || c > 0x7F) - return false; - } -} - - -static int FindZipMethod(const char *s, const char * const *names, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - { - const char *name = names[i]; - if (name && StringsAreEqualNoCase_Ascii(s, name)) - return (int)i; - } - return -1; -} - -static int FindZipMethod(const char *s) -{ - int k = FindZipMethod(s, kMethodNames1, kNumMethodNames1); - if (k >= 0) - return k; - k = FindZipMethod(s, kMethodNames2, kNumMethodNames2); - if (k >= 0) - return (int)kMethodNames2Start + k; - return -1; -} - - -#define COM_TRY_BEGIN2 try { -#define COM_TRY_END2 } \ -catch(const CSystemException &e) { return e.ErrorCode; } \ -catch(...) { return E_OUTOFMEMORY; } - -static HRESULT GetTime(IArchiveUpdateCallback *callback, unsigned index, PROPID propID, FILETIME &filetime) -{ - filetime.dwHighDateTime = filetime.dwLowDateTime = 0; - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propID, &prop)) - if (prop.vt == VT_FILETIME) - filetime = prop.filetime; - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback)) -{ - COM_TRY_BEGIN2 - - if (m_Archive.IsOpen()) - { - if (!m_Archive.CanUpdate()) - return E_NOTIMPL; - } - - CObjectVector updateItems; - updateItems.ClearAndReserve(numItems); - - bool thereAreAesUpdates = false; - UInt64 largestSize = 0; - bool largestSizeDefined = false; - - #ifdef _WIN32 - const UINT oemCP = GetOEMCP(); - #endif - - UString name; - CUpdateItem ui; - - for (UInt32 i = 0; i < numItems; i++) - { - Int32 newData; - Int32 newProps; - UInt32 indexInArc; - - if (!callback) - return E_FAIL; - - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)) - - name.Empty(); - ui.Clear(); - - ui.NewProps = IntToBool(newProps); - ui.NewData = IntToBool(newData); - ui.IndexInArc = (int)indexInArc; - ui.IndexInClient = i; - - bool existInArchive = (indexInArc != (UInt32)(Int32)-1); - if (existInArchive) - { - const CItemEx &inputItem = m_Items[indexInArc]; - if (inputItem.IsAesEncrypted()) - thereAreAesUpdates = true; - if (!IntToBool(newProps)) - ui.IsDir = inputItem.IsDir(); - // ui.IsAltStream = inputItem.IsAltStream(); - } - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidAttrib, &prop)) - if (prop.vt == VT_EMPTY) - ui.Attrib = 0; - else if (prop.vt != VT_UI4) - return E_INVALIDARG; - else - ui.Attrib = prop.ulVal; - } - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidPath, &prop)) - if (prop.vt == VT_EMPTY) - { - // name.Empty(); - } - else if (prop.vt != VT_BSTR) - return E_INVALIDARG; - else - name = prop.bstrVal; - } - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidIsDir, &prop)) - if (prop.vt == VT_EMPTY) - ui.IsDir = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - ui.IsDir = (prop.boolVal != VARIANT_FALSE); - } - - /* - { - bool isAltStream = false; - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidIsAltStream, &prop)); - if (prop.vt == VT_BOOL) - isAltStream = (prop.boolVal != VARIANT_FALSE); - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - - if (isAltStream) - { - if (ui.IsDir) - return E_INVALIDARG; - int delim = name.ReverseFind(L':'); - if (delim >= 0) - { - name.Delete(delim, 1); - name.Insert(delim, UString(k_SpecName_NTFS_STREAM)); - ui.IsAltStream = true; - } - } - } - */ - - // 22.00 : kpidTimeType is useless here : the code was disabled - /* - { - CPropVariant prop; - RINOK(callback->GetProperty(i, kpidTimeType, &prop)); - if (prop.vt == VT_UI4) - ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows); - else - ui.NtfsTime_IsDefined = _Write_NtfsTime; - } - */ - - if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime)) - if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime)) - if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime)) - - if (TimeOptions.Prec != k_PropVar_TimePrec_DOS) - { - if (TimeOptions.Prec == k_PropVar_TimePrec_Unix || - TimeOptions.Prec == k_PropVar_TimePrec_Base) - ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime); - else - { - /* - // if we want to store zero timestamps as zero timestamp, use the following: - ui.Write_NtfsTime = - _Write_MTime || - _Write_ATime || - _Write_CTime; - */ - - // We treat zero timestamp as no timestamp - ui.Write_NtfsTime = - ! FILETIME_IsZero (ui.Ntfs_MTime) || - ! FILETIME_IsZero (ui.Ntfs_ATime) || - ! FILETIME_IsZero (ui.Ntfs_CTime); - } - } - - /* - how 0 in dos time works: - win10 explorer extract : some random date 1601-04-25. - winrar 6.10 : write time. - 7zip : MTime of archive is used - how 0 in tar works: - winrar 6.10 : 1970 - 0 in dos field can show that there is no timestamp. - we write correct 1970-01-01 in dos field, to support correct extraction in Win10. - */ - - UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time); - - NItemName::ReplaceSlashes_OsToUnix(name); - - bool needSlash = ui.IsDir; - const wchar_t kSlash = L'/'; - if (!name.IsEmpty()) - { - if (name.Back() == kSlash) - { - if (!ui.IsDir) - return E_INVALIDARG; - needSlash = false; - } - } - if (needSlash) - name += kSlash; - - const UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP; - bool tryUtf8 = true; - - /* - Windows 10 allows users to set UTF-8 in Region Settings via option: - "Beta: Use Unicode UTF-8 for worldwide language support" - In that case Windows uses CP_UTF8 when we use CP_OEMCP. - 21.02 fixed: - we set UTF-8 mark for non-latin files for such UTF-8 mode in Windows. - we write additional Info-Zip Utf-8 FileName Extra for non-latin names/ - */ - - if ((codePage != CP_UTF8) && - #ifdef _WIN32 - (m_ForceLocal || !m_ForceUtf8) && (oemCP != CP_UTF8) - #else - (m_ForceLocal && !m_ForceUtf8) - #endif - ) - { - bool defaultCharWasUsed; - ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed); - tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || - MultiByteToUnicodeString(ui.Name, codePage) != name)); - } - - const bool isNonLatin = !name.IsAscii(); - - if (tryUtf8) - { - ui.IsUtf8 = isNonLatin; - ConvertUnicodeToUTF8(name, ui.Name); - - #ifndef _WIN32 - if (ui.IsUtf8 && !CheckUTF8_AString(ui.Name)) - { - // if it's non-Windows and there are non-UTF8 characters we clear UTF8-flag - ui.IsUtf8 = false; - } - #endif - } - else if (isNonLatin) - Convert_Unicode_To_UTF8_Buf(name, ui.Name_Utf); - - if (ui.Name.Len() >= (1 << 16) - || ui.Name_Utf.Size() >= (1 << 16) - 128) - return E_INVALIDARG; - - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidComment, &prop)) - if (prop.vt == VT_EMPTY) - { - // ui.Comment.Free(); - } - else if (prop.vt != VT_BSTR) - return E_INVALIDARG; - else - { - UString s = prop.bstrVal; - AString a; - if (ui.IsUtf8) - ConvertUnicodeToUTF8(s, a); - else - { - bool defaultCharWasUsed; - a = UnicodeStringToMultiByte(s, codePage, '_', defaultCharWasUsed); - } - if (a.Len() >= (1 << 16)) - return E_INVALIDARG; - ui.Comment.CopyFrom((const Byte *)(const char *)a, a.Len()); - } - } - - - /* - if (existInArchive) - { - const CItemEx &itemInfo = m_Items[indexInArc]; - // ui.Commented = itemInfo.IsCommented(); - ui.Commented = false; - if (ui.Commented) - { - ui.CommentRange.Position = itemInfo.GetCommentPosition(); - ui.CommentRange.Size = itemInfo.CommentSize; - } - } - else - ui.Commented = false; - */ - } - - - if (IntToBool(newData)) - { - UInt64 size = 0; - if (!ui.IsDir) - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - if (largestSize < size) - largestSize = size; - largestSizeDefined = true; - } - ui.Size = size; - } - - updateItems.Add(ui); - } - - - CMyComPtr getTextPassword; - { - CMyComPtr udateCallBack2(callback); - udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword); - } - CCompressionMethodMode options; - (CBaseProps &)options = _props; - options.DataSizeReduce = largestSize; - options.DataSizeReduce_Defined = largestSizeDefined; - - options.Password_Defined = false; - options.Password.Wipe_and_Empty(); - if (getTextPassword) - { - CMyComBSTR_Wipe password; - Int32 passwordIsDefined; - RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password)) - options.Password_Defined = IntToBool(passwordIsDefined); - if (options.Password_Defined) - { - if (!m_ForceAesMode) - options.IsAesMode = thereAreAesUpdates; - - if (!IsSimpleAsciiString(password)) - return E_INVALIDARG; - if (password) - UnicodeStringToMultiByte2(options.Password, (LPCOLESTR)password, CP_OEMCP); - if (options.IsAesMode) - { - if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax) - return E_INVALIDARG; - } - } - } - - - int mainMethod = m_MainMethod; - - if (mainMethod < 0) - { - if (!_props._methods.IsEmpty()) - { - const AString &methodName = _props._methods.Front().MethodName; - if (!methodName.IsEmpty()) - { - mainMethod = FindZipMethod(methodName); - if (mainMethod < 0) - { - CMethodId methodId; - UInt32 numStreams; - bool isFilter; - if (FindMethod_Index(EXTERNAL_CODECS_VARS methodName, true, - methodId, numStreams, isFilter) < 0) - return E_NOTIMPL; - if (numStreams != 1) - return E_NOTIMPL; - if (methodId == kMethodId_BZip2) - mainMethod = NFileHeader::NCompressionMethod::kBZip2; - else - { - if (methodId < kMethodId_ZipBase) - return E_NOTIMPL; - methodId -= kMethodId_ZipBase; - if (methodId > 0xFF) - return E_NOTIMPL; - mainMethod = (int)methodId; - } - } - } - } - } - - if (mainMethod < 0) - mainMethod = (Byte)(((_props.GetLevel() == 0) ? - NFileHeader::NCompressionMethod::kStore : - NFileHeader::NCompressionMethod::kDeflate)); - else - mainMethod = (Byte)mainMethod; - - options.MethodSequence.Add((Byte)mainMethod); - - if (mainMethod != NFileHeader::NCompressionMethod::kStore) - options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore); - - options.Force_SeqOutMode = _force_SeqOutMode; - - CUpdateOptions uo; - uo.Write_MTime = TimeOptions.Write_MTime.Val; - uo.Write_ATime = TimeOptions.Write_ATime.Val; - uo.Write_CTime = TimeOptions.Write_CTime.Val; - /* - uo.Write_NtfsTime = _Write_NtfsTime && - (_Write_MTime || _Write_ATime || _Write_CTime); - uo.Write_UnixTime = _Write_UnixTime; - */ - - return Update( - EXTERNAL_CODECS_VARS - m_Items, updateItems, outStream, - m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, - uo, options, callback); - - COM_TRY_END2 -} - - - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - InitMethodProps(); - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - const PROPVARIANT &prop = values[i]; - - if (name.IsEqualTo_Ascii_NoCase("em")) - { - if (prop.vt != VT_BSTR) - return E_INVALIDARG; - { - const wchar_t *m = prop.bstrVal; - if (IsString1PrefixedByString2_NoCase_Ascii(m, "AES")) - { - m += 3; - UInt32 v = 3; - if (*m != 0) - { - if (*m == '-') - m++; - const wchar_t *end; - v = ConvertStringToUInt32(m, &end); - if (*end != 0 || v % 64 != 0) - return E_INVALIDARG; - v /= 64; - v -= 2; - if (v >= 3) - return E_INVALIDARG; - v++; - } - _props.AesKeyMode = (Byte)v; - _props.IsAesMode = true; - m_ForceAesMode = true; - } - else if (StringsAreEqualNoCase_Ascii(m, "ZipCrypto")) - { - _props.IsAesMode = false; - m_ForceAesMode = true; - } - else - return E_INVALIDARG; - } - } - - - - else if (name.IsEqualTo("cl")) - { - RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)) - if (m_ForceLocal) - m_ForceUtf8 = false; - } - else if (name.IsEqualTo("cu")) - { - RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8)) - if (m_ForceUtf8) - m_ForceLocal = false; - } - else if (name.IsEqualTo("cp")) - { - UInt32 cp = CP_OEMCP; - RINOK(ParsePropToUInt32(L"", prop, cp)) - _forceCodePage = true; - _specifiedCodePage = cp; - } - else if (name.IsEqualTo("rsfx")) - { - RINOK(PROPVARIANT_to_bool(prop, _removeSfxBlock)) - } - else if (name.IsEqualTo("rws")) - { - RINOK(PROPVARIANT_to_bool(prop, _force_SeqOutMode)) - } - else if (name.IsEqualTo("ros")) - { - RINOK(PROPVARIANT_to_bool(prop, _force_OpenSeq)) - } - else - { - if (name.IsEqualTo_Ascii_NoCase("m") && prop.vt == VT_UI4) - { - UInt32 id = prop.ulVal; - if (id > 0xFF) - return E_INVALIDARG; - m_MainMethod = (int)id; - } - else - { - bool processed = false; - RINOK(TimeOptions.Parse(name, prop, processed)) - if (!processed) - { - RINOK(_props.SetProperty(name, prop)) - } - } - // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); - } - } - - _props._methods.DeleteFrontal(_props.GetNumEmptyMethods()); - if (_props._methods.Size() > 1) - return E_INVALIDARG; - if (_props._methods.Size() == 1) - { - const AString &methodName = _props._methods[0].MethodName; - - if (!methodName.IsEmpty()) - { - const char *end; - UInt32 id = ConvertStringToUInt32(methodName, &end); - if (*end == 0 && id <= 0xFF) - m_MainMethod = (int)id; - else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store" - m_MainMethod = 0; - } - } - - return S_OK; -} - -}} +// ZipHandlerOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../IPassword.h" + +#include "../../Common/OutBuffer.h" + +#include "../../Crypto/WzAes.h" + +#include "../Common/ItemNameUtils.h" +#include "../Common/ParseProperties.h" + +#include "ZipHandler.h" +#include "ZipUpdate.h" + +using namespace NWindows; +using namespace NCOM; +using namespace NTime; + +namespace NArchive { +namespace NZip { + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) +{ + *timeType = TimeOptions.Prec; + return S_OK; +} + +static bool IsSimpleAsciiString(const wchar_t *s) +{ + for (;;) + { + wchar_t c = *s++; + if (c == 0) + return true; + if (c < 0x20 || c > 0x7F) + return false; + } +} + + +static int FindZipMethod(const char *s, const char * const *names, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + { + const char *name = names[i]; + if (name && StringsAreEqualNoCase_Ascii(s, name)) + return (int)i; + } + return -1; +} + +static int FindZipMethod(const char *s) +{ + int k = FindZipMethod(s, kMethodNames1, kNumMethodNames1); + if (k >= 0) + return k; + k = FindZipMethod(s, kMethodNames2, kNumMethodNames2); + if (k >= 0) + return (int)kMethodNames2Start + k; + return -1; +} + + +#define COM_TRY_BEGIN2 try { +#define COM_TRY_END2 } \ +catch(const CSystemException &e) { return e.ErrorCode; } \ +catch(...) { return E_OUTOFMEMORY; } + +static HRESULT GetTime(IArchiveUpdateCallback *callback, unsigned index, PROPID propID, FILETIME &filetime) +{ + filetime.dwHighDateTime = filetime.dwLowDateTime = 0; + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propID, &prop)) + if (prop.vt == VT_FILETIME) + filetime = prop.filetime; + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback)) +{ + COM_TRY_BEGIN2 + + if (m_Archive.IsOpen()) + { + if (!m_Archive.CanUpdate()) + return E_NOTIMPL; + } + + CObjectVector updateItems; + updateItems.ClearAndReserve(numItems); + + bool thereAreAesUpdates = false; + UInt64 largestSize = 0; + bool largestSizeDefined = false; + + #ifdef _WIN32 + const UINT oemCP = GetOEMCP(); + #endif + + UString name; + CUpdateItem ui; + + for (UInt32 i = 0; i < numItems; i++) + { + Int32 newData; + Int32 newProps; + UInt32 indexInArc; + + if (!callback) + return E_FAIL; + + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)) + + name.Empty(); + ui.Clear(); + + ui.NewProps = IntToBool(newProps); + ui.NewData = IntToBool(newData); + ui.IndexInArc = (int)indexInArc; + ui.IndexInClient = i; + + bool existInArchive = (indexInArc != (UInt32)(Int32)-1); + if (existInArchive) + { + const CItemEx &inputItem = m_Items[indexInArc]; + if (inputItem.IsAesEncrypted()) + thereAreAesUpdates = true; + if (!IntToBool(newProps)) + ui.IsDir = inputItem.IsDir(); + // ui.IsAltStream = inputItem.IsAltStream(); + } + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidAttrib, &prop)) + if (prop.vt == VT_EMPTY) + ui.Attrib = 0; + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + ui.Attrib = prop.ulVal; + } + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidPath, &prop)) + if (prop.vt == VT_EMPTY) + { + // name.Empty(); + } + else if (prop.vt != VT_BSTR) + return E_INVALIDARG; + else + name = prop.bstrVal; + } + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidIsDir, &prop)) + if (prop.vt == VT_EMPTY) + ui.IsDir = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + } + + /* + { + bool isAltStream = false; + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidIsAltStream, &prop)); + if (prop.vt == VT_BOOL) + isAltStream = (prop.boolVal != VARIANT_FALSE); + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + + if (isAltStream) + { + if (ui.IsDir) + return E_INVALIDARG; + int delim = name.ReverseFind(L':'); + if (delim >= 0) + { + name.Delete(delim, 1); + name.Insert(delim, UString(k_SpecName_NTFS_STREAM)); + ui.IsAltStream = true; + } + } + } + */ + + // 22.00 : kpidTimeType is useless here : the code was disabled + /* + { + CPropVariant prop; + RINOK(callback->GetProperty(i, kpidTimeType, &prop)); + if (prop.vt == VT_UI4) + ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows); + else + ui.NtfsTime_IsDefined = _Write_NtfsTime; + } + */ + + if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime)) + if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime)) + if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime)) + + if (TimeOptions.Prec != k_PropVar_TimePrec_DOS) + { + if (TimeOptions.Prec == k_PropVar_TimePrec_Unix || + TimeOptions.Prec == k_PropVar_TimePrec_Base) + ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime); + else + { + /* + // if we want to store zero timestamps as zero timestamp, use the following: + ui.Write_NtfsTime = + _Write_MTime || + _Write_ATime || + _Write_CTime; + */ + + // We treat zero timestamp as no timestamp + ui.Write_NtfsTime = + ! FILETIME_IsZero (ui.Ntfs_MTime) || + ! FILETIME_IsZero (ui.Ntfs_ATime) || + ! FILETIME_IsZero (ui.Ntfs_CTime); + } + } + + /* + how 0 in dos time works: + win10 explorer extract : some random date 1601-04-25. + winrar 6.10 : write time. + 7zip : MTime of archive is used + how 0 in tar works: + winrar 6.10 : 1970 + 0 in dos field can show that there is no timestamp. + we write correct 1970-01-01 in dos field, to support correct extraction in Win10. + */ + + UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time); + + NItemName::ReplaceSlashes_OsToUnix(name); + + bool needSlash = ui.IsDir; + const wchar_t kSlash = L'/'; + if (!name.IsEmpty()) + { + if (name.Back() == kSlash) + { + if (!ui.IsDir) + return E_INVALIDARG; + needSlash = false; + } + } + if (needSlash) + name += kSlash; + + const UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP; + bool tryUtf8 = true; + + /* + Windows 10 allows users to set UTF-8 in Region Settings via option: + "Beta: Use Unicode UTF-8 for worldwide language support" + In that case Windows uses CP_UTF8 when we use CP_OEMCP. + 21.02 fixed: + we set UTF-8 mark for non-latin files for such UTF-8 mode in Windows. + we write additional Info-Zip Utf-8 FileName Extra for non-latin names/ + */ + + if ((codePage != CP_UTF8) && + #ifdef _WIN32 + (m_ForceLocal || !m_ForceUtf8) && (oemCP != CP_UTF8) + #else + (m_ForceLocal && !m_ForceUtf8) + #endif + ) + { + bool defaultCharWasUsed; + ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed); + tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed || + MultiByteToUnicodeString(ui.Name, codePage) != name)); + } + + const bool isNonLatin = !name.IsAscii(); + + if (tryUtf8) + { + ui.IsUtf8 = isNonLatin; + ConvertUnicodeToUTF8(name, ui.Name); + + #ifndef _WIN32 + if (ui.IsUtf8 && !CheckUTF8_AString(ui.Name)) + { + // if it's non-Windows and there are non-UTF8 characters we clear UTF8-flag + ui.IsUtf8 = false; + } + #endif + } + else if (isNonLatin) + Convert_Unicode_To_UTF8_Buf(name, ui.Name_Utf); + + if (ui.Name.Len() >= (1 << 16) + || ui.Name_Utf.Size() >= (1 << 16) - 128) + return E_INVALIDARG; + + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidComment, &prop)) + if (prop.vt == VT_EMPTY) + { + // ui.Comment.Free(); + } + else if (prop.vt != VT_BSTR) + return E_INVALIDARG; + else + { + UString s = prop.bstrVal; + AString a; + if (ui.IsUtf8) + ConvertUnicodeToUTF8(s, a); + else + { + bool defaultCharWasUsed; + a = UnicodeStringToMultiByte(s, codePage, '_', defaultCharWasUsed); + } + if (a.Len() >= (1 << 16)) + return E_INVALIDARG; + ui.Comment.CopyFrom((const Byte *)(const char *)a, a.Len()); + } + } + + + /* + if (existInArchive) + { + const CItemEx &itemInfo = m_Items[indexInArc]; + // ui.Commented = itemInfo.IsCommented(); + ui.Commented = false; + if (ui.Commented) + { + ui.CommentRange.Position = itemInfo.GetCommentPosition(); + ui.CommentRange.Size = itemInfo.CommentSize; + } + } + else + ui.Commented = false; + */ + } + + + if (IntToBool(newData)) + { + UInt64 size = 0; + if (!ui.IsDir) + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + if (largestSize < size) + largestSize = size; + largestSizeDefined = true; + } + ui.Size = size; + } + + updateItems.Add(ui); + } + + + CMyComPtr getTextPassword; + { + CMyComPtr udateCallBack2(callback); + udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword); + } + CCompressionMethodMode options; + (CBaseProps &)options = _props; + options.DataSizeReduce = largestSize; + options.DataSizeReduce_Defined = largestSizeDefined; + + options.Password_Defined = false; + options.Password.Wipe_and_Empty(); + if (getTextPassword) + { + CMyComBSTR_Wipe password; + Int32 passwordIsDefined; + RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password)) + options.Password_Defined = IntToBool(passwordIsDefined); + if (options.Password_Defined) + { + if (!m_ForceAesMode) + options.IsAesMode = thereAreAesUpdates; + + if (!IsSimpleAsciiString(password)) + return E_INVALIDARG; + if (password) + UnicodeStringToMultiByte2(options.Password, (LPCOLESTR)password, CP_OEMCP); + if (options.IsAesMode) + { + if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax) + return E_INVALIDARG; + } + } + } + + + int mainMethod = m_MainMethod; + + if (mainMethod < 0) + { + if (!_props._methods.IsEmpty()) + { + const AString &methodName = _props._methods.Front().MethodName; + if (!methodName.IsEmpty()) + { + mainMethod = FindZipMethod(methodName); + if (mainMethod < 0) + { + CMethodId methodId; + UInt32 numStreams; + bool isFilter; + if (FindMethod_Index(EXTERNAL_CODECS_VARS methodName, true, + methodId, numStreams, isFilter) < 0) + return E_NOTIMPL; + if (numStreams != 1) + return E_NOTIMPL; + if (methodId == kMethodId_BZip2) + mainMethod = NFileHeader::NCompressionMethod::kBZip2; + else + { + if (methodId < kMethodId_ZipBase) + return E_NOTIMPL; + methodId -= kMethodId_ZipBase; + if (methodId > 0xFF) + return E_NOTIMPL; + mainMethod = (int)methodId; + } + } + } + } + } + + if (mainMethod < 0) + mainMethod = (Byte)(((_props.GetLevel() == 0) ? + NFileHeader::NCompressionMethod::kStore : + NFileHeader::NCompressionMethod::kDeflate)); + else + mainMethod = (Byte)mainMethod; + + options.MethodSequence.Add((Byte)mainMethod); + + if (mainMethod != NFileHeader::NCompressionMethod::kStore) + options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore); + + options.Force_SeqOutMode = _force_SeqOutMode; + + CUpdateOptions uo; + uo.Write_MTime = TimeOptions.Write_MTime.Val; + uo.Write_ATime = TimeOptions.Write_ATime.Val; + uo.Write_CTime = TimeOptions.Write_CTime.Val; + /* + uo.Write_NtfsTime = _Write_NtfsTime && + (_Write_MTime || _Write_ATime || _Write_CTime); + uo.Write_UnixTime = _Write_UnixTime; + */ + + return Update( + EXTERNAL_CODECS_VARS + m_Items, updateItems, outStream, + m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, + uo, options, callback); + + COM_TRY_END2 +} + + + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + InitMethodProps(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + const PROPVARIANT &prop = values[i]; + + if (name.IsEqualTo_Ascii_NoCase("em")) + { + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + { + const wchar_t *m = prop.bstrVal; + if (IsString1PrefixedByString2_NoCase_Ascii(m, "AES")) + { + m += 3; + UInt32 v = 3; + if (*m != 0) + { + if (*m == '-') + m++; + const wchar_t *end; + v = ConvertStringToUInt32(m, &end); + if (*end != 0 || v % 64 != 0) + return E_INVALIDARG; + v /= 64; + v -= 2; + if (v >= 3) + return E_INVALIDARG; + v++; + } + _props.AesKeyMode = (Byte)v; + _props.IsAesMode = true; + m_ForceAesMode = true; + } + else if (StringsAreEqualNoCase_Ascii(m, "ZipCrypto")) + { + _props.IsAesMode = false; + m_ForceAesMode = true; + } + else + return E_INVALIDARG; + } + } + + + + else if (name.IsEqualTo("cl")) + { + RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)) + if (m_ForceLocal) + m_ForceUtf8 = false; + } + else if (name.IsEqualTo("cu")) + { + RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8)) + if (m_ForceUtf8) + m_ForceLocal = false; + } + else if (name.IsEqualTo("cp")) + { + UInt32 cp = CP_OEMCP; + RINOK(ParsePropToUInt32(L"", prop, cp)) + _forceCodePage = true; + _specifiedCodePage = cp; + } + else if (name.IsEqualTo("rsfx")) + { + RINOK(PROPVARIANT_to_bool(prop, _removeSfxBlock)) + } + else if (name.IsEqualTo("rws")) + { + RINOK(PROPVARIANT_to_bool(prop, _force_SeqOutMode)) + } + else if (name.IsEqualTo("ros")) + { + RINOK(PROPVARIANT_to_bool(prop, _force_OpenSeq)) + } + else + { + if (name.IsEqualTo_Ascii_NoCase("m") && prop.vt == VT_UI4) + { + UInt32 id = prop.ulVal; + if (id > 0xFF) + return E_INVALIDARG; + m_MainMethod = (int)id; + } + else + { + bool processed = false; + RINOK(TimeOptions.Parse(name, prop, processed)) + if (!processed) + { + RINOK(_props.SetProperty(name, prop)) + } + } + // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); + } + } + + _props._methods.DeleteFrontal(_props.GetNumEmptyMethods()); + if (_props._methods.Size() > 1) + return E_INVALIDARG; + if (_props._methods.Size() == 1) + { + const AString &methodName = _props._methods[0].MethodName; + + if (!methodName.IsEmpty()) + { + const char *end; + UInt32 id = ConvertStringToUInt32(methodName, &end); + if (*end == 0 && id <= 0xFF) + m_MainMethod = (int)id; + else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store" + m_MainMethod = 0; + } + } + + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h index c4f9375a4..038d49d28 100644 --- a/CPP/7zip/Archive/Zip/ZipHeader.h +++ b/CPP/7zip/Archive/Zip/ZipHeader.h @@ -1,201 +1,201 @@ -// ZipHeader.h - -#ifndef ZIP7_INC_ARCHIVE_ZIP_HEADER_H -#define ZIP7_INC_ARCHIVE_ZIP_HEADER_H - -#include "../../../Common/MyTypes.h" - -namespace NArchive { -namespace NZip { - -const unsigned kMarkerSize = 4; - -namespace NSignature -{ - const UInt32 kLocalFileHeader = 0x04034B50; - const UInt32 kDataDescriptor = 0x08074B50; - const UInt32 kCentralFileHeader = 0x02014B50; - const UInt32 kEcd = 0x06054B50; - const UInt32 kEcd64 = 0x06064B50; - const UInt32 kEcd64Locator = 0x07064B50; - const UInt32 kSpan = 0x08074B50; - const UInt32 kNoSpan = 0x30304B50; // PK00, replaces kSpan, if there is only 1 segment -} - -const unsigned kLocalHeaderSize = 4 + 26; // including signature -const unsigned kDataDescriptorSize32 = 4 + 4 + 4 * 2; // including signature -const unsigned kDataDescriptorSize64 = 4 + 4 + 8 * 2; // including signature -const unsigned kCentralHeaderSize = 4 + 42; // including signature - -const unsigned kEcdSize = 22; // including signature -const unsigned kEcd64_MainSize = 44; -const unsigned kEcd64_FullSize = 12 + kEcd64_MainSize; -const unsigned kEcd64Locator_Size = 20; - -namespace NFileHeader -{ - namespace NCompressionMethod - { - enum EType - { - kStore = 0, - kShrink = 1, - kReduce1 = 2, - kReduce2 = 3, - kReduce3 = 4, - kReduce4 = 5, - kImplode = 6, - kTokenize = 7, - kDeflate = 8, - kDeflate64 = 9, - kPKImploding = 10, - - kBZip2 = 12, - - kLZMA = 14, - - kTerse = 18, - kLz77 = 19, - kZstdPk = 20, - - kZstdWz = 93, - kMP3 = 94, - kXz = 95, - kJpeg = 96, - kWavPack = 97, - kPPMd = 98, - kWzAES = 99 - }; - - const Byte kMadeByProgramVersion = 63; - - const Byte kExtractVersion_Default = 10; - const Byte kExtractVersion_Dir = 20; - const Byte kExtractVersion_ZipCrypto = 20; - const Byte kExtractVersion_Deflate = 20; - const Byte kExtractVersion_Deflate64 = 21; - const Byte kExtractVersion_Zip64 = 45; - const Byte kExtractVersion_BZip2 = 46; - const Byte kExtractVersion_Aes = 51; - const Byte kExtractVersion_LZMA = 63; - const Byte kExtractVersion_PPMd = 63; - const Byte kExtractVersion_Xz = 20; // test it - } - - namespace NExtraID - { - enum - { - kZip64 = 0x01, - kNTFS = 0x0A, - kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK - kStrongEncrypt = 0x17, - kIzNtSecurityDescriptor = 0x4453, - kUnixTime = 0x5455, // "UT" (time) Info-ZIP - kUnix1 = 0x5855, // Info-ZIP - kIzUnicodeComment = 0x6375, - kIzUnicodeName = 0x7075, - kUnix2 = 0x7855, // Info-ZIP - kUnixN = 0x7875, // Info-ZIP - kWzAES = 0x9901, - kApkAlign = 0xD935 - }; - } - - namespace NNtfsExtra - { - const UInt16 kTagTime = 1; - enum - { - kMTime = 0, - kATime, - kCTime - }; - } - - namespace NUnixTime - { - enum - { - kMTime = 0, - kATime, - kCTime - }; - } - - namespace NUnixExtra - { - enum - { - kATime = 0, - kMTime - }; - } - - namespace NFlags - { - const unsigned kEncrypted = 1 << 0; - const unsigned kLzmaEOS = 1 << 1; - const unsigned kDescriptorUsedMask = 1 << 3; - const unsigned kStrongEncrypted = 1 << 6; - const unsigned kUtf8 = 1 << 11; - const unsigned kAltStream = 1 << 14; - - const unsigned kImplodeDictionarySizeMask = 1 << 1; - const unsigned kImplodeLiteralsOnMask = 1 << 2; - - /* - const unsigned kDeflateTypeBitStart = 1; - const unsigned kNumDeflateTypeBits = 2; - const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits); - const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; - */ - } - - namespace NHostOS - { - enum EEnum - { - kFAT = 0, - kAMIGA = 1, - kVMS = 2, // VAX/VMS - kUnix = 3, - kVM_CMS = 4, - kAtari = 5, // what if it's a minix filesystem? [cjh] - kHPFS = 6, // filesystem used by OS/2 (and NT 3.x) - kMac = 7, - kZ_System = 8, - kCPM = 9, - kTOPS20 = 10, // pkzip 2.50 NTFS - kNTFS = 11, // filesystem used by Windows NT - kQDOS = 12, // SMS/QDOS - kAcorn = 13, // Archimedes Acorn RISC OS - kVFAT = 14, // filesystem used by Windows 95, NT - kMVS = 15, - kBeOS = 16, // hybrid POSIX/database filesystem - kTandem = 17, - kOS400 = 18, - kOSX = 19 - }; - } - - - namespace NAmigaAttrib - { - const UInt32 kIFMT = 06000; // Amiga file type mask - const UInt32 kIFDIR = 04000; // Amiga directory - const UInt32 kIFREG = 02000; // Amiga regular file - const UInt32 kIHIDDEN = 00200; // to be supported in AmigaDOS 3.x - const UInt32 kISCRIPT = 00100; // executable script (text command file) - const UInt32 kIPURE = 00040; // allow loading into resident memory - const UInt32 kIARCHIVE = 00020; // not modified since bit was last set - const UInt32 kIREAD = 00010; // can be opened for reading - const UInt32 kIWRITE = 00004; // can be opened for writing - const UInt32 kIEXECUTE = 00002; // executable image, a loadable runfile - const UInt32 kIDELETE = 00001; // can be deleted - } -} - -}} - -#endif +// ZipHeader.h + +#ifndef ZIP7_INC_ARCHIVE_ZIP_HEADER_H +#define ZIP7_INC_ARCHIVE_ZIP_HEADER_H + +#include "../../../Common/MyTypes.h" + +namespace NArchive { +namespace NZip { + +const unsigned kMarkerSize = 4; + +namespace NSignature +{ + const UInt32 kLocalFileHeader = 0x04034B50; + const UInt32 kDataDescriptor = 0x08074B50; + const UInt32 kCentralFileHeader = 0x02014B50; + const UInt32 kEcd = 0x06054B50; + const UInt32 kEcd64 = 0x06064B50; + const UInt32 kEcd64Locator = 0x07064B50; + const UInt32 kSpan = 0x08074B50; + const UInt32 kNoSpan = 0x30304B50; // PK00, replaces kSpan, if there is only 1 segment +} + +const unsigned kLocalHeaderSize = 4 + 26; // including signature +const unsigned kDataDescriptorSize32 = 4 + 4 + 4 * 2; // including signature +const unsigned kDataDescriptorSize64 = 4 + 4 + 8 * 2; // including signature +const unsigned kCentralHeaderSize = 4 + 42; // including signature + +const unsigned kEcdSize = 22; // including signature +const unsigned kEcd64_MainSize = 44; +const unsigned kEcd64_FullSize = 12 + kEcd64_MainSize; +const unsigned kEcd64Locator_Size = 20; + +namespace NFileHeader +{ + namespace NCompressionMethod + { + enum EType + { + kStore = 0, + kShrink = 1, + kReduce1 = 2, + kReduce2 = 3, + kReduce3 = 4, + kReduce4 = 5, + kImplode = 6, + kTokenize = 7, + kDeflate = 8, + kDeflate64 = 9, + kPKImploding = 10, + + kBZip2 = 12, + + kLZMA = 14, + + kTerse = 18, + kLz77 = 19, + kZstdPk = 20, + + kZstdWz = 93, + kMP3 = 94, + kXz = 95, + kJpeg = 96, + kWavPack = 97, + kPPMd = 98, + kWzAES = 99 + }; + + const Byte kMadeByProgramVersion = 63; + + const Byte kExtractVersion_Default = 10; + const Byte kExtractVersion_Dir = 20; + const Byte kExtractVersion_ZipCrypto = 20; + const Byte kExtractVersion_Deflate = 20; + const Byte kExtractVersion_Deflate64 = 21; + const Byte kExtractVersion_Zip64 = 45; + const Byte kExtractVersion_BZip2 = 46; + const Byte kExtractVersion_Aes = 51; + const Byte kExtractVersion_LZMA = 63; + const Byte kExtractVersion_PPMd = 63; + const Byte kExtractVersion_Xz = 20; // test it + } + + namespace NExtraID + { + enum + { + kZip64 = 0x01, + kNTFS = 0x0A, + kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK + kStrongEncrypt = 0x17, + kIzNtSecurityDescriptor = 0x4453, + kUnixTime = 0x5455, // "UT" (time) Info-ZIP + kUnix1 = 0x5855, // Info-ZIP + kIzUnicodeComment = 0x6375, + kIzUnicodeName = 0x7075, + kUnix2 = 0x7855, // Info-ZIP + kUnixN = 0x7875, // Info-ZIP + kWzAES = 0x9901, + kApkAlign = 0xD935 + }; + } + + namespace NNtfsExtra + { + const UInt16 kTagTime = 1; + enum + { + kMTime = 0, + kATime, + kCTime + }; + } + + namespace NUnixTime + { + enum + { + kMTime = 0, + kATime, + kCTime + }; + } + + namespace NUnixExtra + { + enum + { + kATime = 0, + kMTime + }; + } + + namespace NFlags + { + const unsigned kEncrypted = 1 << 0; + const unsigned kLzmaEOS = 1 << 1; + const unsigned kDescriptorUsedMask = 1 << 3; + const unsigned kStrongEncrypted = 1 << 6; + const unsigned kUtf8 = 1 << 11; + const unsigned kAltStream = 1 << 14; + + const unsigned kImplodeDictionarySizeMask = 1 << 1; + const unsigned kImplodeLiteralsOnMask = 1 << 2; + + /* + const unsigned kDeflateTypeBitStart = 1; + const unsigned kNumDeflateTypeBits = 2; + const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits); + const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1; + */ + } + + namespace NHostOS + { + enum EEnum + { + kFAT = 0, + kAMIGA = 1, + kVMS = 2, // VAX/VMS + kUnix = 3, + kVM_CMS = 4, + kAtari = 5, // what if it's a minix filesystem? [cjh] + kHPFS = 6, // filesystem used by OS/2 (and NT 3.x) + kMac = 7, + kZ_System = 8, + kCPM = 9, + kTOPS20 = 10, // pkzip 2.50 NTFS + kNTFS = 11, // filesystem used by Windows NT + kQDOS = 12, // SMS/QDOS + kAcorn = 13, // Archimedes Acorn RISC OS + kVFAT = 14, // filesystem used by Windows 95, NT + kMVS = 15, + kBeOS = 16, // hybrid POSIX/database filesystem + kTandem = 17, + kOS400 = 18, + kOSX = 19 + }; + } + + + namespace NAmigaAttrib + { + const UInt32 kIFMT = 06000; // Amiga file type mask + const UInt32 kIFDIR = 04000; // Amiga directory + const UInt32 kIFREG = 02000; // Amiga regular file + const UInt32 kIHIDDEN = 00200; // to be supported in AmigaDOS 3.x + const UInt32 kISCRIPT = 00100; // executable script (text command file) + const UInt32 kIPURE = 00040; // allow loading into resident memory + const UInt32 kIARCHIVE = 00020; // not modified since bit was last set + const UInt32 kIREAD = 00010; // can be opened for reading + const UInt32 kIWRITE = 00004; // can be opened for writing + const UInt32 kIEXECUTE = 00002; // executable image, a loadable runfile + const UInt32 kIDELETE = 00001; // can be deleted + } +} + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 6caeab1fe..788810f62 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -1,3485 +1,3485 @@ -// Archive/ZipIn.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../Common/DynamicBuffer.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyException.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/PropVariant.h" - -#include "../IArchive.h" - -#include "ZipIn.h" - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) -#define Get64(p) GetUi64(p) - -#define G16(offs, v) v = Get16(p + (offs)) -#define G32(offs, v) v = Get32(p + (offs)) -#define G64(offs, v) v = Get64(p + (offs)) - -namespace NArchive { -namespace NZip { - -/* we try to use same size of Buffer (1 << 17) for all tasks. - it allow to avoid reallocations and cache clearing. */ - -static const size_t kSeqBufferSize = (size_t)1 << 17; - -/* -Open() -{ - _inBufMode = false; - ReadVols() - FindCd(); - TryEcd64() - SeekToVol() - FindMarker() - _inBufMode = true; - ReadHeaders() - _inBufMode = false; - ReadCd() - FindCd() - TryEcd64() - TryReadCd() - { - SeekToVol(); - _inBufMode = true; - } - _inBufMode = true; - ReadLocals() - ReadCdItem() - .... -} -FindCd() writes to Buffer without touching (_inBufMode) -*/ - -/* - if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE - if ( defined ZIP_SELF_CHECK) : it always reads CD and LOCALS-CD-MODE - use ZIP_SELF_CHECK to check LOCALS-CD-MODE for any zip archive -*/ - -// #define ZIP_SELF_CHECK - - -struct CEcd -{ - UInt16 ThisDisk; - UInt16 CdDisk; - UInt16 NumEntries_in_ThisDisk; - UInt16 NumEntries; - UInt32 Size; - UInt32 Offset; - UInt16 CommentSize; - - bool IsEmptyArc() const - { - return ThisDisk == 0 - && CdDisk == 0 - && NumEntries_in_ThisDisk == 0 - && NumEntries == 0 - && Size == 0 - && Offset == 0 // test it - ; - } - - void Parse(const Byte *p); // (p) doesn't include signature -}; - -void CEcd::Parse(const Byte *p) -{ - // (p) doesn't include signature - G16(0, ThisDisk); - G16(2, CdDisk); - G16(4, NumEntries_in_ThisDisk); - G16(6, NumEntries); - G32(8, Size); - G32(12, Offset); - G16(16, CommentSize); -} - - -void CCdInfo::ParseEcd32(const Byte *p) -{ - IsFromEcd64 = false; - // (p) includes signature - p += 4; - G16(0, ThisDisk); - G16(2, CdDisk); - G16(4, NumEntries_in_ThisDisk); - G16(6, NumEntries); - G32(8, Size); - G32(12, Offset); - G16(16, CommentSize); -} - -void CCdInfo::ParseEcd64e(const Byte *p) -{ - IsFromEcd64 = true; - // (p) exclude signature - G16(0, VersionMade); - G16(2, VersionNeedExtract); - G32(4, ThisDisk); - G32(8, CdDisk); - - G64(12, NumEntries_in_ThisDisk); - G64(20, NumEntries); - G64(28, Size); - G64(36, Offset); -} - - -struct CLocator -{ - UInt32 Ecd64Disk; - UInt32 NumDisks; - UInt64 Ecd64Offset; - - CLocator(): Ecd64Disk(0), NumDisks(0), Ecd64Offset(0) {} - - void Parse(const Byte *p) - { - G32(0, Ecd64Disk); - G64(4, Ecd64Offset); - G32(12, NumDisks); - } - - bool IsEmptyArc() const - { - return Ecd64Disk == 0 && NumDisks == 0 && Ecd64Offset == 0; - } -}; - - - - -void CInArchive::ClearRefs() -{ - StreamRef.Release(); - Stream = NULL; - StartStream = NULL; - Callback = NULL; - - Vols.Clear(); -} - -void CInArchive::Close() -{ - _cnt = 0; - DisableBufMode(); - - IsArcOpen = false; - - IsArc = false; - IsZip64 = false; - - IsApk = false; - IsCdUnsorted = false; - - HeadersError = false; - HeadersWarning = false; - ExtraMinorError = false; - - UnexpectedEnd = false; - LocalsWereRead = false; - LocalsCenterMerged = false; - NoCentralDir = false; - Overflow32bit = false; - Cd_NumEntries_Overflow_16bit = false; - - MarkerIsFound = false; - MarkerIsSafe = false; - - IsMultiVol = false; - UseDisk_in_SingleVol = false; - EcdVolIndex = 0; - - ArcInfo.Clear(); - - ClearRefs(); -} - - - -HRESULT CInArchive::Seek_SavePos(UInt64 offset) -{ - // InitBuf(); - // if (!Stream) return S_FALSE; - return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos); -} - - -/* SeekToVol() will keep the cached mode, if new volIndex is - same Vols.StreamIndex volume, and offset doesn't go out of cached region */ - -HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) -{ - if (volIndex != Vols.StreamIndex) - { - if (IsMultiVol && volIndex >= 0) - { - if ((unsigned)volIndex >= Vols.Streams.Size()) - return S_FALSE; - if (!Vols.Streams[(unsigned)volIndex].Stream) - return S_FALSE; - Stream = Vols.Streams[(unsigned)volIndex].Stream; - } - else if (volIndex == -2) - { - if (!Vols.ZipStream) - return S_FALSE; - Stream = Vols.ZipStream; - } - else - Stream = StartStream; - Vols.StreamIndex = volIndex; - } - else - { - if (offset <= _streamPos) - { - const UInt64 back = _streamPos - offset; - if (back <= _bufCached) - { - _bufPos = _bufCached - (size_t)back; - return S_OK; - } - } - } - InitBuf(); - return Seek_SavePos(offset); -} - - -HRESULT CInArchive::AllocateBuffer(size_t size) -{ - if (size <= Buffer.Size()) - return S_OK; - /* in cached mode virtual_pos is not equal to phy_pos (_streamPos) - so we change _streamPos and do Seek() to virtual_pos before cache clearing */ - if (_bufPos != _bufCached) - { - RINOK(Seek_SavePos(GetVirtStreamPos())) - } - InitBuf(); - Buffer.AllocAtLeast(size); - if (!Buffer.IsAllocated()) - return E_OUTOFMEMORY; - return S_OK; -} - -// ---------- ReadFromCache ---------- -// reads from cache and from Stream -// move to next volume can be allowed if (CanStartNewVol) and only before first byte reading - -HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed) -{ - HRESULT result = S_OK; - processed = 0; - - for (;;) - { - if (size == 0) - return S_OK; - - const size_t avail = GetAvail(); - - if (avail != 0) - { - unsigned cur = size; - if (cur > avail) - cur = (unsigned)avail; - memcpy(data, (const Byte *)Buffer + _bufPos, cur); - - data += cur; - size -= cur; - processed += cur; - - _bufPos += cur; - _cnt += cur; - - CanStartNewVol = false; - - continue; - } - - InitBuf(); - - if (_inBufMode) - { - UInt32 cur = 0; - result = Stream->Read(Buffer, (UInt32)Buffer.Size(), &cur); - _bufPos = 0; - _bufCached = cur; - _streamPos += cur; - if (cur != 0) - CanStartNewVol = false; - if (result != S_OK) - break; - if (cur != 0) - continue; - } - else - { - size_t cur = size; - result = ReadStream(Stream, data, &cur); - data += cur; - size -= (unsigned)cur; - processed += (unsigned)cur; - _streamPos += cur; - _cnt += cur; - if (cur != 0) - { - CanStartNewVol = false; - break; - } - if (result != S_OK) - break; - } - - if ( !IsMultiVol - || !CanStartNewVol - || Vols.StreamIndex < 0 - || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) - break; - - const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1]; - if (!s.Stream) - break; - result = s.SeekToStart(); - if (result != S_OK) - break; - Vols.StreamIndex++; - _streamPos = 0; - // Vols.NeedSeek = false; - - Stream = s.Stream; - } - - return result; -} - - -HRESULT CInArchive::ReadFromCache_FALSE(Byte *data, unsigned size) -{ - unsigned processed; - HRESULT res = ReadFromCache(data, size, processed); - if (res == S_OK && size != processed) - return S_FALSE; - return res; -} - - -static bool CheckDosTime(UInt32 dosTime) -{ - if (dosTime == 0) - return true; - unsigned month = (dosTime >> 21) & 0xF; - unsigned day = (dosTime >> 16) & 0x1F; - unsigned hour = (dosTime >> 11) & 0x1F; - unsigned min = (dosTime >> 5) & 0x3F; - unsigned sec = (dosTime & 0x1F) * 2; - if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) - return false; - return true; -} - -API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) -{ - if (size < 8) - return k_IsArc_Res_NEED_MORE; - if (p[0] != 'P') - return k_IsArc_Res_NO; - - UInt32 sig = Get32(p); - - if (sig == NSignature::kNoSpan || sig == NSignature::kSpan) - { - p += 4; - size -= 4; - } - - sig = Get32(p); - - if (sig == NSignature::kEcd64) - { - if (size < kEcd64_FullSize) - return k_IsArc_Res_NEED_MORE; - - const UInt64 recordSize = Get64(p + 4); - if ( recordSize < kEcd64_MainSize - || recordSize > kEcd64_MainSize + (1 << 20)) - return k_IsArc_Res_NO; - CCdInfo cdInfo; - cdInfo.ParseEcd64e(p + 12); - if (!cdInfo.IsEmptyArc()) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; - } - - if (sig == NSignature::kEcd) - { - if (size < kEcdSize) - return k_IsArc_Res_NEED_MORE; - CEcd ecd; - ecd.Parse(p + 4); - // if (ecd.cdSize != 0) - if (!ecd.IsEmptyArc()) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; - } - - if (sig != NSignature::kLocalFileHeader) - return k_IsArc_Res_NO; - - if (size < kLocalHeaderSize) - return k_IsArc_Res_NEED_MORE; - - p += 4; - - { - const unsigned kPureHeaderSize = kLocalHeaderSize - 4; - unsigned i; - for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); - if (i == kPureHeaderSize) - return k_IsArc_Res_NEED_MORE; - } - - /* - if (p[0] >= 128) // ExtractVersion.Version; - return k_IsArc_Res_NO; - */ - - // ExtractVersion.Version = p[0]; - // ExtractVersion.HostOS = p[1]; - // Flags = Get16(p + 2); - // Method = Get16(p + 4); - /* - // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now - UInt32 dosTime = Get32(p + 6); - if (!CheckDosTime(dosTime)) - return k_IsArc_Res_NO; - */ - // Crc = Get32(p + 10); - // PackSize = Get32(p + 14); - // Size = Get32(p + 18); - const unsigned nameSize = Get16(p + 22); - unsigned extraSize = Get16(p + 24); - const UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize; - - /* - // 21.02: fixed. we don't use the following check - if (extraOffset + extraSize > (1 << 16)) - return k_IsArc_Res_NO; - */ - - p -= 4; - - { - size_t rem = size - kLocalHeaderSize; - if (rem > nameSize) - rem = nameSize; - const Byte *p2 = p + kLocalHeaderSize; - for (size_t i = 0; i < rem; i++) - if (p2[i] == 0) - { - // we support some "bad" zip archives that contain zeros after name - for (size_t k = i + 1; k < rem; k++) - if (p2[k] != 0) - return k_IsArc_Res_NO; - break; - /* - if (i != nameSize - 1) - return k_IsArc_Res_NO; - */ - } - } - - if (size < extraOffset) - return k_IsArc_Res_NEED_MORE; - - if (extraSize > 0) - { - p += extraOffset; - size -= extraOffset; - while (extraSize != 0) - { - if (extraSize < 4) - { - // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers. - // so we return k_IsArc_Res_YES to support such archives. - // return k_IsArc_Res_NO; // do we need to support such extra ? - return k_IsArc_Res_YES; - } - if (size < 4) - return k_IsArc_Res_NEED_MORE; - unsigned dataSize = Get16(p + 2); - size -= 4; - extraSize -= 4; - p += 4; - if (dataSize > extraSize) - { - // It can be error on header. - // We want to support such rare case bad archives. - // We use additional checks to reduce false-positive probability. - if (nameSize == 0 - || nameSize > (1 << 9) - || extraSize > (1 << 9)) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; - } - if (dataSize > size) - return k_IsArc_Res_NEED_MORE; - size -= dataSize; - extraSize -= dataSize; - p += dataSize; - } - } - - return k_IsArc_Res_YES; -} - -static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) -{ - UInt32 res = IsArc_Zip(p, size); - if (res == k_IsArc_Res_NEED_MORE && isFinal) - return k_IsArc_Res_NO; - return res; -} - - - -/* FindPK_4() is allowed to access data up to and including &limit[3]. - limit[4] access is not allowed. - return: - (return_ptr < limit) : "PK" was found at (return_ptr) - (return_ptr >= limit) : limit was reached or crossed. So no "PK" found before limit -*/ -Z7_NO_INLINE -static const Byte *FindPK_4(const Byte *p, const Byte *limit) -{ - for (;;) - { - for (;;) - { - if (p >= limit) - return limit; - Byte b = p[1]; - if (b == 0x4B) { if (p[0] == 0x50) { return p; } p += 1; break; } - if (b == 0x50) { if (p[2] == 0x4B) { return p + 1; } p += 2; break; } - b = p[3]; - p += 4; - if (b == 0x4B) { if (p[-2]== 0x50) { return p - 2; } p -= 1; break; } - if (b == 0x50) { if (p[0] == 0x4B) { return p - 1; } break; } - } - } - /* - for (;;) - { - for (;;) - { - if (p >= limit) - return limit; - if (*p++ == 0x50) break; - if (*p++ == 0x50) break; - if (*p++ == 0x50) break; - if (*p++ == 0x50) break; - } - if (*p == 0x4B) - return p - 1; - } - */ -} - - -/* ----------- FindMarker ---------- -returns: - S_OK: - ArcInfo.MarkerVolIndex : volume of marker - ArcInfo.MarkerPos : Pos of first signature - ArcInfo.MarkerPos2 : Pos of main signature (local item signature in most cases) - _streamPos : stream pos - _cnt : The number of virtal Bytes after start of search to offset after signature - _signature : main signature - - S_FALSE: can't find marker, or there is some non-zip data after marker - - Error code: stream reading error. -*/ - -HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) -{ - ArcInfo.MarkerPos = GetVirtStreamPos(); - ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; - ArcInfo.MarkerVolIndex = Vols.StreamIndex; - - _cnt = 0; - - CanStartNewVol = false; - - if (searchLimit && *searchLimit == 0) - { - Byte startBuf[kMarkerSize]; - RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)) - - UInt32 marker = Get32(startBuf); - _signature = marker; - - if ( marker == NSignature::kNoSpan - || marker == NSignature::kSpan) - { - RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)) - _signature = Get32(startBuf); - } - - if ( _signature != NSignature::kEcd - && _signature != NSignature::kEcd64 - && _signature != NSignature::kLocalFileHeader) - return S_FALSE; - - ArcInfo.MarkerPos2 = GetVirtStreamPos() - 4; - ArcInfo.IsSpanMode = (marker == NSignature::kSpan); - - // we use weak test in case of (*searchLimit == 0) - // since error will be detected later in Open function - return S_OK; - } - - // zip specification: (_zip_header_size < (1 << 16)) - // so we need such size to check header - const size_t kCheckSize = (size_t)1 << 16; - const size_t kBufSize = (size_t)1 << 17; // (kBufSize must be > kCheckSize) - - RINOK(AllocateBuffer(kBufSize)) - - _inBufMode = true; - - UInt64 progressPrev = 0; - - for (;;) - { - RINOK(LookAhead(kBufSize)) - - const size_t avail = GetAvail(); - - size_t limitPos; - // (avail > kBufSize) is possible, if (Buffer.Size() > kBufSize) - const bool isFinished = (avail < kBufSize); - if (isFinished) - { - const unsigned kMinAllowed = 4; - if (avail <= kMinAllowed) - { - if ( !IsMultiVol - || Vols.StreamIndex < 0 - || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) - break; - - SkipLookahed(avail); - - const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1]; - if (!s.Stream) - break; - - RINOK(s.SeekToStart()) - - InitBuf(); - Vols.StreamIndex++; - _streamPos = 0; - Stream = s.Stream; - continue; - } - limitPos = avail - kMinAllowed; - } - else - limitPos = (avail - kCheckSize); - - // we don't check at (limitPos) for good fast aligned operations - - if (searchLimit) - { - if (_cnt > *searchLimit) - break; - UInt64 rem = *searchLimit - _cnt; - if (limitPos > rem) - limitPos = (size_t)rem + 1; - } - - if (limitPos == 0) - break; - - const Byte * const pStart = Buffer + _bufPos; - const Byte * p = pStart; - const Byte * const limit = pStart + limitPos; - - for (;; p++) - { - p = FindPK_4(p, limit); - if (p >= limit) - break; - size_t rem = (size_t)(pStart + avail - p); - /* 22.02 : we limit check size with kCheckSize to be consistent for - any different combination of _bufPos in Buffer and size of Buffer. */ - if (rem > kCheckSize) - rem = kCheckSize; - const UInt32 res = IsArc_Zip_2(p, rem, isFinished); - if (res != k_IsArc_Res_NO) - { - if (rem < kMarkerSize) - return S_FALSE; - _signature = Get32(p); - SkipLookahed((size_t)(p - pStart)); - ArcInfo.MarkerVolIndex = Vols.StreamIndex; - ArcInfo.MarkerPos = GetVirtStreamPos(); - ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; - SkipLookahed(4); - if ( _signature == NSignature::kNoSpan - || _signature == NSignature::kSpan) - { - if (rem < kMarkerSize * 2) - return S_FALSE; - ArcInfo.IsSpanMode = (_signature == NSignature::kSpan); - _signature = Get32(p + 4); - ArcInfo.MarkerPos2 += 4; - SkipLookahed(4); - } - return S_OK; - } - } - - if (!IsMultiVol && isFinished) - break; - - SkipLookahed((size_t)(p - pStart)); - - if (Callback && (_cnt - progressPrev) >= ((UInt32)1 << 23)) - { - progressPrev = _cnt; - // const UInt64 numFiles64 = 0; - RINOK(Callback->SetCompleted(NULL, &_cnt)) - } - } - - return S_FALSE; -} - - -/* ----------- IncreaseRealPosition ---------- -moves virtual offset in virtual stream. -changing to new volumes is allowed -*/ - -HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished) -{ - isFinished = false; - - for (;;) - { - const size_t avail = GetAvail(); - - if (offset <= avail) - { - _bufPos += (size_t)offset; - _cnt += offset; - return S_OK; - } - - _cnt += avail; - offset -= avail; - - _bufCached = 0; - _bufPos = 0; - - if (!_inBufMode) - break; - - CanStartNewVol = true; - LookAhead(1); - - if (GetAvail() == 0) - return S_OK; - } - - // cache is empty - - if (!IsMultiVol) - { - _cnt += offset; - return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos); - } - - for (;;) - { - if (offset == 0) - return S_OK; - - if (Vols.StreamIndex < 0) - return S_FALSE; - if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) - { - isFinished = true; - return S_OK; - } - { - const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex]; - if (!s.Stream) - { - isFinished = true; - return S_OK; - } - if (_streamPos > s.Size) - return S_FALSE; - const UInt64 rem = s.Size - _streamPos; - if ((UInt64)offset <= rem) - { - _cnt += offset; - return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos); - } - RINOK(Seek_SavePos(s.Size)) - offset -= rem; - _cnt += rem; - } - - Stream = NULL; - _streamPos = 0; - Vols.StreamIndex++; - if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) - { - isFinished = true; - return S_OK; - } - const CVols::CSubStreamInfo &s2 = Vols.Streams[(unsigned)Vols.StreamIndex]; - if (!s2.Stream) - { - isFinished = true; - return S_OK; - } - Stream = s2.Stream; - RINOK(Seek_SavePos(0)) - } -} - - - -/* ----------- LookAhead ---------- -Reads data to buffer, if required. - -It can read from volumes as long as Buffer.Size(). -But it moves to new volume, only if it's required to provide minRequired bytes in buffer. - -in: - (minRequired <= Buffer.Size()) - -return: - S_OK : if (GetAvail() < minRequired) after function return, it's end of stream(s) data, or no new volume stream. - Error codes: IInStream::Read() error or IInStream::Seek() error for multivol -*/ - -HRESULT CInArchive::LookAhead(size_t minRequired) -{ - for (;;) - { - const size_t avail = GetAvail(); - - if (minRequired <= avail) - return S_OK; - - if (_bufPos != 0) - { - if (avail != 0) - memmove(Buffer, Buffer + _bufPos, avail); - _bufPos = 0; - _bufCached = avail; - } - - const size_t pos = _bufCached; - UInt32 processed = 0; - HRESULT res = Stream->Read(Buffer + pos, (UInt32)(Buffer.Size() - pos), &processed); - _streamPos += processed; - _bufCached += processed; - - if (res != S_OK) - return res; - - if (processed != 0) - continue; - - if ( !IsMultiVol - || !CanStartNewVol - || Vols.StreamIndex < 0 - || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) - return S_OK; - - const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1]; - if (!s.Stream) - return S_OK; - - RINOK(s.SeekToStart()) - - Vols.StreamIndex++; - _streamPos = 0; - Stream = s.Stream; - // Vols.NeedSeek = false; - } -} - - -class CUnexpectEnd {}; - - -/* ----------- SafeRead ---------- - -reads data of exact size from stream(s) - -in: - _inBufMode - if (CanStartNewVol) it can go to next volume before first byte reading, if there is end of volume data. - -in, out: - _streamPos : position in Stream - Stream - Vols : if (IsMultiVol) - _cnt - -out: - (CanStartNewVol == false), if some data was read - -return: - S_OK : success reading of requested data - -exceptions: - CSystemException() - stream reading error - CUnexpectEnd() : could not read data of requested size -*/ - -void CInArchive::SafeRead(Byte *data, unsigned size) -{ - unsigned processed; - HRESULT result = ReadFromCache(data, size, processed); - if (result != S_OK) - throw CSystemException(result); - if (size != processed) - throw CUnexpectEnd(); -} - -void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size) -{ - buffer.Alloc(size); - if (size != 0) - SafeRead(buffer, size); -} - -// Byte CInArchive::ReadByte () { Byte b; SafeRead(&b, 1); return b; } -// UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeRead(buf, 2); return Get16(buf); } -UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeRead(buf, 4); return Get32(buf); } -UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeRead(buf, 8); return Get64(buf); } - -void CInArchive::ReadSignature() -{ - CanStartNewVol = true; - _signature = ReadUInt32(); - // CanStartNewVol = false; // it's already changed in SafeRead -} - - -// we Skip() inside headers only, so no need for stream change in multivol. - -void CInArchive::Skip(size_t num) -{ - while (num != 0) - { - const unsigned kBufSize = (size_t)1 << 10; - Byte buf[kBufSize]; - unsigned step = kBufSize; - if (step > num) - step = (unsigned)num; - SafeRead(buf, step); - num -= step; - } -} - -/* -HRESULT CInArchive::Callback_Completed(unsigned numFiles) -{ - const UInt64 numFiles64 = numFiles; - return Callback->SetCompleted(&numFiles64, &_cnt); -} -*/ - -HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles) -{ - if (num == 0) - return S_OK; - - for (;;) - { - size_t step = (size_t)1 << 24; - if (step > num) - step = (size_t)num; - Skip(step); - num -= step; - if (num == 0) - return S_OK; - if (Callback) - { - const UInt64 numFiles64 = numFiles; - RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) - } - } -} - - -bool CInArchive::ReadFileName(unsigned size, AString &s) -{ - if (size == 0) - { - s.Empty(); - return true; - } - char *p = s.GetBuf(size); - SafeRead((Byte *)p, size); - unsigned i = size; - do - { - if (p[i - 1] != 0) - break; - } - while (--i); - s.ReleaseBuf_CalcLen(size); - return s.Len() == i; -} - - -#define ZIP64_IS_32_MAX(n) ((n) == 0xFFFFFFFF) -#define ZIP64_IS_16_MAX(n) ((n) == 0xFFFF) - - -bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, - UInt64 &unpackSize, UInt64 &packSize, - CItem *cdItem) -{ - extra.Clear(); - - while (extraSize >= 4) - { - CExtraSubBlock subBlock; - const UInt32 pair = ReadUInt32(); - subBlock.ID = (pair & 0xFFFF); - unsigned size = (unsigned)(pair >> 16); - // const unsigned origSize = size; - - extraSize -= 4; - - if (size > extraSize) - { - // it's error in extra - HeadersWarning = true; - extra.Error = true; - Skip(extraSize); - return false; - } - - extraSize -= size; - - if (subBlock.ID == NFileHeader::NExtraID::kZip64) - { - extra.IsZip64 = true; - bool isOK = true; - - if (!cdItem - && size == 16 - && !ZIP64_IS_32_MAX(unpackSize) - && !ZIP64_IS_32_MAX(packSize)) - { - /* Win10 Explorer's "Send to Zip" for big (3500 MiB) files - creates Zip64 Extra in local file header. - But if both uncompressed and compressed sizes are smaller than 4 GiB, - Win10 doesn't store 0xFFFFFFFF in 32-bit fields as expected by zip specification. - 21.04: we ignore these minor errors in Win10 zip archives. */ - if (ReadUInt64() != unpackSize) - isOK = false; - if (ReadUInt64() != packSize) - isOK = false; - size = 0; - } - else - { - if (ZIP64_IS_32_MAX(unpackSize)) - { if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }} - - if (isOK && ZIP64_IS_32_MAX(packSize)) - { if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }} - - if (cdItem) - { - if (isOK) - { - if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) - { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} - /* - else if (size == 8) - { - size -= 8; - const UInt64 v = ReadUInt64(); - // soong_zip, an AOSP tool (written in the Go) writes incorrect value. - // we can ignore that minor error here - if (v != cdItem->LocalHeaderPos) - isOK = false; // ignore error - // isOK = false; // force error - } - */ - } - - if (isOK && ZIP64_IS_16_MAX(cdItem->Disk)) - { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }} - } - } - - // we can ignore errors, when some zip archiver still write all fields to zip64 extra in local header - // if (&& (cdItem || !isOK || origSize != 8 * 3 + 4 || size != 8 * 1 + 4)) - if (!isOK || size != 0) - { - HeadersWarning = true; - extra.Error = true; - extra.IsZip64_Error = true; - } - Skip(size); - } - else - { - ReadBuffer(subBlock.Data, size); - extra.SubBlocks.Add(subBlock); - if (subBlock.ID == NFileHeader::NExtraID::kIzUnicodeName) - { - if (!subBlock.CheckIzUnicode(item.Name)) - extra.Error = true; - } - } - } - - if (extraSize != 0) - { - ExtraMinorError = true; - extra.MinorError = true; - // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers. - // so we don't return false, but just set warning flag - // return false; - Skip(extraSize); - } - - return true; -} - - -bool CInArchive::ReadLocalItem(CItemEx &item) -{ - item.Disk = 0; - if (IsMultiVol && Vols.StreamIndex >= 0) - item.Disk = (UInt32)Vols.StreamIndex; - const unsigned kPureHeaderSize = kLocalHeaderSize - 4; - Byte p[kPureHeaderSize]; - SafeRead(p, kPureHeaderSize); - { - unsigned i; - for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); - if (i == kPureHeaderSize) - return false; - } - - item.ExtractVersion.Version = p[0]; - item.ExtractVersion.HostOS = p[1]; - G16(2, item.Flags); - G16(4, item.Method); - G32(6, item.Time); - G32(10, item.Crc); - G32(14, item.PackSize); - G32(18, item.Size); - const unsigned nameSize = Get16(p + 22); - const unsigned extraSize = Get16(p + 24); - bool isOkName = ReadFileName(nameSize, item.Name); - item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; - item.DescriptorWasRead = false; - - /* - if (item.IsDir()) - item.Size = 0; // check It - */ - - if (extraSize > 0) - { - if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, NULL)) - { - /* Most of archives are OK for Extra. But there are some rare cases - that have error. And if error in first item, it can't open archive. - So we ignore that error */ - // return false; - } - } - - if (!CheckDosTime(item.Time)) - { - HeadersWarning = true; - // return false; - } - - if (item.Name.Len() != nameSize) - { - // we support some "bad" zip archives that contain zeros after name - if (!isOkName) - return false; - HeadersWarning = true; - } - - // return item.LocalFullHeaderSize <= ((UInt32)1 << 16); - return true; -} - - -static bool FlagsAreSame(const CItem &i1, const CItem &i2_cd) -{ - if (i1.Method != i2_cd.Method) - return false; - - UInt32 mask = i1.Flags ^ i2_cd.Flags; - if (mask == 0) - return true; - switch (i1.Method) - { - case NFileHeader::NCompressionMethod::kDeflate: - mask &= 0x7FF9; - break; - default: - if (i1.Method <= NFileHeader::NCompressionMethod::kImplode) - mask &= 0x7FFF; - } - - // we can ignore utf8 flag, if name is ascii, or if only cdItem has utf8 flag - if (mask & NFileHeader::NFlags::kUtf8) - if ((i1.Name.IsAscii() && i2_cd.Name.IsAscii()) - || (i2_cd.Flags & NFileHeader::NFlags::kUtf8)) - mask &= ~NFileHeader::NFlags::kUtf8; - - // some bad archive in rare case can use descriptor without descriptor flag in Central Dir - // if (i1.HasDescriptor()) - mask &= ~NFileHeader::NFlags::kDescriptorUsedMask; - - return (mask == 0); -} - - -// #ifdef _WIN32 -static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2) -{ - for (;;) - { - char c1 = *s1++; - char c2 = *s2++; - if (c1 == c2) - { - if (c1 == 0) - return true; - } - else - { - if (c1 == '\\') c1 = '/'; - if (c2 == '\\') c2 = '/'; - if (c1 != c2) - return false; - } - } -} -// #endif - - -static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) -{ - if (!FlagsAreSame(localItem, cdItem)) - return false; - if (!localItem.HasDescriptor()) - { - if (cdItem.PackSize != localItem.PackSize - || cdItem.Size != localItem.Size - || (cdItem.Crc != localItem.Crc && cdItem.Crc != 0)) // some program writes 0 to crc field in central directory - return false; - } - /* pkzip 2.50 creates incorrect archives. It uses - - WIN encoding for name in local header - - OEM encoding for name in central header - We don't support these strange items. */ - - /* if (cdItem.Name.Len() != localItem.Name.Len()) - return false; - */ - if (cdItem.Name != localItem.Name) - { - // #ifdef _WIN32 - // some xap files use backslash in central dir items. - // we can ignore such errors in windows, where all slashes are converted to backslashes - unsigned hostOs = cdItem.GetHostOS(); - - if (hostOs == NFileHeader::NHostOS::kFAT || - hostOs == NFileHeader::NHostOS::kNTFS) - { - if (!AreEqualPaths_IgnoreSlashes(cdItem.Name, localItem.Name)) - { - // pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header. - // so we ignore that error - if (hostOs != NFileHeader::NHostOS::kFAT - || cdItem.MadeByVersion.Version < 25 - || cdItem.MadeByVersion.Version > 40) - return false; - } - } - /* - else - #endif - return false; - */ - } - return true; -} - - -HRESULT CInArchive::Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError) -{ - isAvail = true; - headersError = false; - if (item.FromLocal) - return S_OK; - try - { - UInt64 offset = item.LocalHeaderPos; - - if (IsMultiVol) - { - if (item.Disk >= Vols.Streams.Size()) - { - isAvail = false; - return S_FALSE; - } - Stream = Vols.Streams[item.Disk].Stream; - Vols.StreamIndex = (int)item.Disk; - if (!Stream) - { - isAvail = false; - return S_FALSE; - } - } - else - { - if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex) - { - isAvail = false; - return S_FALSE; - } - Stream = StreamRef; - - offset = (UInt64)((Int64)offset + ArcInfo.Base); - if (ArcInfo.Base < 0 && (Int64)offset < 0) - { - isAvail = false; - return S_FALSE; - } - } - - _inBufMode = false; - RINOK(Seek_SavePos(offset)) - InitBuf(); - /* - // we can use buf mode with small buffer to reduce - // the number of Read() calls in ReadLocalItem() - _inBufMode = true; - Buffer.Alloc(1 << 10); - if (!Buffer.IsAllocated()) - return E_OUTOFMEMORY; - */ - - CItemEx localItem; - if (ReadUInt32() != NSignature::kLocalFileHeader) - return S_FALSE; - ReadLocalItem(localItem); - if (!AreItemsEqual(localItem, item)) - return S_FALSE; - item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; - item.LocalExtra = localItem.LocalExtra; - if (item.Crc != localItem.Crc && !localItem.HasDescriptor()) - { - item.Crc = localItem.Crc; - headersError = true; - } - if ((item.Flags ^ localItem.Flags) & NFileHeader::NFlags::kDescriptorUsedMask) - { - item.Flags = (UInt16)(item.Flags ^ NFileHeader::NFlags::kDescriptorUsedMask); - headersError = true; - } - item.FromLocal = true; - } - catch(...) { return S_FALSE; } - return S_OK; -} - - -/* ----------- FindDescriptor ---------- - -in: - _streamPos : position in Stream - Stream : - Vols : if (IsMultiVol) - -action: - searches descriptor in input stream(s). - sets - item.DescriptorWasRead = true; - item.Size - item.PackSize - item.Crc - if descriptor was found - -out: - S_OK: - if ( item.DescriptorWasRead) : if descriptor was found - if (!item.DescriptorWasRead) : if descriptor was not found : unexpected end of stream(s) - - S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive. - - another error code: Callback error. - -exceptions : - CSystemException() : stream reading error -*/ - -HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles) -{ - // const size_t kBufSize = (size_t)1 << 5; // don't increase it too much. It reads data look ahead. - - // Buffer.Alloc(kBufSize); - // Byte *buf = Buffer; - - UInt64 packedSize = 0; - - UInt64 progressPrev = _cnt; - - for (;;) - { - /* appnote specification claims that we must use 64-bit descriptor, if there is zip64 extra. - But some old third-party xps archives used 64-bit descriptor without zip64 extra. */ - // unsigned descriptorSize = kDataDescriptorSize64 + kNextSignatureSize; - - // const unsigned kNextSignatureSize = 0; // we can disable check for next signatuire - const unsigned kNextSignatureSize = 4; // we check also for signature for next File headear - - const unsigned descriptorSize4 = item.GetDescriptorSize() + kNextSignatureSize; - - if (descriptorSize4 > Buffer.Size()) return E_FAIL; - - // size_t processedSize; - CanStartNewVol = true; - RINOK(LookAhead(descriptorSize4)) - const size_t avail = GetAvail(); - - if (avail < descriptorSize4) - { - // we write to packSize all these available bytes. - // later it's simpler to work with such value than with 0 - // if (item.PackSize == 0) - item.PackSize = packedSize + avail; - if (item.Method == 0) - item.Size = item.PackSize; - SkipLookahed(avail); - return S_OK; - } - - const Byte * const pStart = Buffer + _bufPos; - const Byte * p = pStart; - const Byte * const limit = pStart + (avail - descriptorSize4); - - for (; p <= limit; p++) - { - // descriptor signature field is Info-ZIP's extension to pkware Zip specification. - // New ZIP specification also allows descriptorSignature. - - p = FindPK_4(p, limit + 1); - if (p > limit) - break; - - /* - if (*p != 0x50) - continue; - */ - - if (Get32(p) != NSignature::kDataDescriptor) - continue; - - // we check next signatuire after descriptor - // maybe we need check only 2 bytes "PK" instead of 4 bytes, if some another type of header is possible after descriptor - const UInt32 sig = Get32(p + descriptorSize4 - kNextSignatureSize); - if ( sig != NSignature::kLocalFileHeader - && sig != NSignature::kCentralFileHeader) - continue; - - const UInt64 packSizeCur = packedSize + (size_t)(p - pStart); - if (descriptorSize4 == kDataDescriptorSize64 + kNextSignatureSize) // if (item.LocalExtra.IsZip64) - { - const UInt64 descriptorPackSize = Get64(p + 8); - if (descriptorPackSize != packSizeCur) - continue; - item.Size = Get64(p + 16); - } - else - { - const UInt32 descriptorPackSize = Get32(p + 8); - if (descriptorPackSize != (UInt32)packSizeCur) - continue; - item.Size = Get32(p + 12); - // that item.Size can be truncated to 32-bit value here - } - // We write calculated 64-bit packSize, even if descriptor64 was not used - item.PackSize = packSizeCur; - - item.DescriptorWasRead = true; - item.Crc = Get32(p + 4); - - const size_t skip = (size_t)(p - pStart) + descriptorSize4 - kNextSignatureSize; - - SkipLookahed(skip); - - return S_OK; - } - - const size_t skip = (size_t)(p - pStart); - SkipLookahed(skip); - - packedSize += skip; - - if (Callback) - if (_cnt - progressPrev >= ((UInt32)1 << 22)) - { - progressPrev = _cnt; - const UInt64 numFiles64 = numFiles; - RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) - } - } -} - - -HRESULT CInArchive::CheckDescriptor(const CItemEx &item) -{ - if (!item.HasDescriptor()) - return S_OK; - - // pkzip's version without descriptor signature is not supported - - bool isFinished = false; - RINOK(IncreaseRealPosition(item.PackSize, isFinished)) - if (isFinished) - return S_FALSE; - - /* - if (!IsMultiVol) - { - RINOK(Seek_SavePos(ArcInfo.Base + item.GetDataPosition() + item.PackSize)); - } - */ - - Byte buf[kDataDescriptorSize64]; - try - { - CanStartNewVol = true; - SafeRead(buf, item.GetDescriptorSize()); - } - catch (const CSystemException &e) { return e.ErrorCode; } - // catch (const CUnexpectEnd &) - catch(...) - { - return S_FALSE; - } - // RINOK(ReadStream_FALSE(Stream, buf, item.GetDescriptorSize())); - - if (Get32(buf) != NSignature::kDataDescriptor) - return S_FALSE; - UInt32 crc = Get32(buf + 4); - UInt64 packSize, unpackSize; - - if (item.LocalExtra.IsZip64) - { - packSize = Get64(buf + 8); - unpackSize = Get64(buf + 16); - } - else - { - packSize = Get32(buf + 8); - unpackSize = Get32(buf + 12); - } - - if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize) - return S_FALSE; - return S_OK; -} - - -HRESULT CInArchive::Read_LocalItem_After_CdItem_Full(CItemEx &item) -{ - if (item.FromLocal) - return S_OK; - try - { - bool isAvail = true; - bool headersError = false; - RINOK(Read_LocalItem_After_CdItem(item, isAvail, headersError)) - if (headersError) - return S_FALSE; - if (item.HasDescriptor()) - return CheckDescriptor(item); - } - catch(...) { return S_FALSE; } - return S_OK; -} - - -HRESULT CInArchive::ReadCdItem(CItemEx &item) -{ - item.FromCentral = true; - Byte p[kCentralHeaderSize - 4]; - SafeRead(p, kCentralHeaderSize - 4); - - item.MadeByVersion.Version = p[0]; - item.MadeByVersion.HostOS = p[1]; - item.ExtractVersion.Version = p[2]; - item.ExtractVersion.HostOS = p[3]; - G16(4, item.Flags); - G16(6, item.Method); - G32(8, item.Time); - G32(12, item.Crc); - G32(16, item.PackSize); - G32(20, item.Size); - const unsigned nameSize = Get16(p + 24); - const unsigned extraSize = Get16(p + 26); - const unsigned commentSize = Get16(p + 28); - G16(30, item.Disk); - G16(32, item.InternalAttrib); - G32(34, item.ExternalAttrib); - G32(38, item.LocalHeaderPos); - ReadFileName(nameSize, item.Name); - - if (extraSize > 0) - ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, &item); - - // May be these strings must be deleted - /* - if (item.IsDir()) - item.Size = 0; - */ - - ReadBuffer(item.Comment, commentSize); - return S_OK; -} - - -/* -TryEcd64() - (_inBufMode == false) is expected here - so TryEcd64() can't change the Buffer. - if (Ecd64 is not covered by cached region), - TryEcd64() can change cached region ranges (_bufCached, _bufPos) and _streamPos. -*/ - -HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) -{ - if (offset >= ((UInt64)1 << 63)) - return S_FALSE; - Byte buf[kEcd64_FullSize]; - - RINOK(SeekToVol(Vols.StreamIndex, offset)) - RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize)) - - if (Get32(buf) != NSignature::kEcd64) - return S_FALSE; - UInt64 mainSize = Get64(buf + 4); - if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 40)) - return S_FALSE; - cdInfo.ParseEcd64e(buf + 12); - return S_OK; -} - - -/* FindCd() doesn't use previous cached region, - but it uses Buffer. So it sets new cached region */ - -HRESULT CInArchive::FindCd(bool checkOffsetMode) -{ - CCdInfo &cdInfo = Vols.ecd; - - UInt64 endPos; - - // There are no useful data in cache in most cases here. - // So here we don't use cache data from previous operations . - - InitBuf(); - RINOK(InStream_GetSize_SeekToEnd(Stream, endPos)) - _streamPos = endPos; - - // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; - const size_t kBufSizeMax = ((size_t)1 << 17); // must be larger than kBufSizeMax2 - - const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax; - if (bufSize < kEcdSize) - return S_FALSE; - // CByteArr byteBuffer(bufSize); - - RINOK(AllocateBuffer(kBufSizeMax)) - - RINOK(Seek_SavePos(endPos - bufSize)) - - size_t processed = bufSize; - HRESULT res = ReadStream(Stream, Buffer, &processed); - _streamPos += processed; - _bufCached = processed; - _bufPos = 0; - _cnt += processed; - if (res != S_OK) - return res; - if (processed != bufSize) - return S_FALSE; - - - for (size_t i = bufSize - kEcdSize + 1;;) - { - if (i == 0) - return S_FALSE; - - const Byte *buf = Buffer; - - for (;;) - { - i--; - if (buf[i] == 0x50) - break; - if (i == 0) - return S_FALSE; - } - - if (Get32(buf + i) != NSignature::kEcd) - continue; - - cdInfo.ParseEcd32(buf + i); - - if (i >= kEcd64Locator_Size) - { - const size_t locatorIndex = i - kEcd64Locator_Size; - if (Get32(buf + locatorIndex) == NSignature::kEcd64Locator) - { - CLocator locator; - locator.Parse(buf + locatorIndex + 4); - UInt32 numDisks = locator.NumDisks; - // we ignore the error, where some zip creators use (NumDisks == 0) - if (numDisks == 0) - numDisks = 1; - if ((cdInfo.ThisDisk == numDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk)) - && locator.Ecd64Disk < numDisks) - { - if (locator.Ecd64Disk != cdInfo.ThisDisk && !ZIP64_IS_16_MAX(cdInfo.ThisDisk)) - return E_NOTIMPL; - - // Most of the zip64 use fixed size Zip64 ECD - // we try relative backward reading. - - UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize); - - if (locatorIndex >= kEcd64_FullSize) - if (checkOffsetMode || absEcd64 == locator.Ecd64Offset) - { - const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize; - if (Get32(ecd64) == NSignature::kEcd64) - { - UInt64 mainEcd64Size = Get64(ecd64 + 4); - if (mainEcd64Size == kEcd64_MainSize) - { - cdInfo.ParseEcd64e(ecd64 + 12); - ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset); - // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; - return S_OK; - } - } - } - - // some zip64 use variable size Zip64 ECD. - // we try to use absolute offset from locator. - - if (absEcd64 != locator.Ecd64Offset) - { - if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK) - { - ArcInfo.Base = 0; - // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; - return S_OK; - } - } - - // for variable Zip64 ECD with for archives with offset != 0. - - if (checkOffsetMode - && ArcInfo.MarkerPos != 0 - && ArcInfo.MarkerPos + locator.Ecd64Offset != absEcd64) - { - if (TryEcd64(ArcInfo.MarkerPos + locator.Ecd64Offset, cdInfo) == S_OK) - { - ArcInfo.Base = (Int64)ArcInfo.MarkerPos; - // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; - return S_OK; - } - } - } - } - } - - // bool isVolMode = (Vols.EndVolIndex != -1); - // UInt32 searchDisk = (isVolMode ? Vols.EndVolIndex : 0); - - if (/* searchDisk == thisDisk && */ cdInfo.CdDisk <= cdInfo.ThisDisk) - { - // if (isVolMode) - { - if (cdInfo.CdDisk != cdInfo.ThisDisk) - return S_OK; - } - - UInt64 absEcdPos = endPos - bufSize + i; - UInt64 cdEnd = cdInfo.Size + cdInfo.Offset; - ArcInfo.Base = 0; - // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; - if (absEcdPos != cdEnd) - { - /* - if (cdInfo.Offset <= 16 && cdInfo.Size != 0) - { - // here we support some rare ZIP files with Central directory at the start - ArcInfo.Base = 0; - } - else - */ - ArcInfo.Base = (Int64)(absEcdPos - cdEnd); - } - return S_OK; - } - } -} - - -HRESULT CInArchive::TryReadCd(CObjectVector &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize) -{ - items.Clear(); - IsCdUnsorted = false; - - // _startLocalFromCd_Disk = (UInt32)(Int32)-1; - // _startLocalFromCd_Offset = (UInt64)(Int64)-1; - - RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset)) - - _inBufMode = true; - _cnt = 0; - - if (Callback) - { - RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL)) - } - UInt64 numFileExpected = cdInfo.NumEntries; - const UInt64 *totalFilesPtr = &numFileExpected; - bool isCorrect_NumEntries = (cdInfo.IsFromEcd64 || numFileExpected >= ((UInt32)1 << 16)); - - while (_cnt < cdSize) - { - CanStartNewVol = true; - if (ReadUInt32() != NSignature::kCentralFileHeader) - return S_FALSE; - CanStartNewVol = false; - { - CItemEx cdItem; - RINOK(ReadCdItem(cdItem)) - - /* - if (cdItem.Disk < _startLocalFromCd_Disk || - cdItem.Disk == _startLocalFromCd_Disk && - cdItem.LocalHeaderPos < _startLocalFromCd_Offset) - { - _startLocalFromCd_Disk = cdItem.Disk; - _startLocalFromCd_Offset = cdItem.LocalHeaderPos; - } - */ - - if (items.Size() > 0 && !IsCdUnsorted) - { - const CItemEx &prev = items.Back(); - if (cdItem.Disk < prev.Disk - || (cdItem.Disk == prev.Disk && - cdItem.LocalHeaderPos < prev.LocalHeaderPos)) - IsCdUnsorted = true; - } - - items.Add(cdItem); - } - if (Callback && (items.Size() & 0xFFF) == 0) - { - const UInt64 numFiles = items.Size(); - - if (numFiles > numFileExpected && totalFilesPtr) - { - if (isCorrect_NumEntries) - totalFilesPtr = NULL; - else - while (numFiles > numFileExpected) - numFileExpected += (UInt32)1 << 16; - RINOK(Callback->SetTotal(totalFilesPtr, NULL)) - } - - RINOK(Callback->SetCompleted(&numFiles, &_cnt)) - } - } - - CanStartNewVol = true; - - return (_cnt == cdSize) ? S_OK : S_FALSE; -} - - -/* -static int CompareCdItems(void *const *elem1, void *const *elem2, void *) -{ - const CItemEx *i1 = *(const CItemEx **)elem1; - const CItemEx *i2 = *(const CItemEx **)elem2; - - if (i1->Disk < i2->Disk) return -1; - if (i1->Disk > i2->Disk) return 1; - if (i1->LocalHeaderPos < i2->LocalHeaderPos) return -1; - if (i1->LocalHeaderPos > i2->LocalHeaderPos) return 1; - if (i1 < i2) return -1; - if (i1 > i2) return 1; - return 0; -} -*/ - -HRESULT CInArchive::ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize) -{ - bool checkOffsetMode = true; - - if (IsMultiVol) - { - if (Vols.EndVolIndex == -1) - return S_FALSE; - Stream = Vols.Streams[(unsigned)Vols.EndVolIndex].Stream; - if (!Vols.StartIsZip) - checkOffsetMode = false; - } - else - Stream = StartStream; - - if (!Vols.ecd_wasRead) - { - RINOK(FindCd(checkOffsetMode)) - } - - CCdInfo &cdInfo = Vols.ecd; - - HRESULT res = S_FALSE; - - cdSize = cdInfo.Size; - cdOffset = cdInfo.Offset; - cdDisk = cdInfo.CdDisk; - - if (!IsMultiVol) - { - if (cdInfo.ThisDisk != cdInfo.CdDisk) - return S_FALSE; - } - - const UInt64 base = (IsMultiVol ? 0 : (UInt64)ArcInfo.Base); - res = TryReadCd(items, cdInfo, base + cdOffset, cdSize); - - if (res == S_FALSE && !IsMultiVol && base != ArcInfo.MarkerPos) - { - // do we need that additional attempt to read cd? - res = TryReadCd(items, cdInfo, ArcInfo.MarkerPos + cdOffset, cdSize); - if (res == S_OK) - ArcInfo.Base = (Int64)ArcInfo.MarkerPos; - } - - // Some rare case files are unsorted - // items.Sort(CompareCdItems, NULL); - return res; -} - - -static int FindItem(const CObjectVector &items, const CItemEx &item) -{ - unsigned left = 0, right = items.Size(); - for (;;) - { - if (left >= right) - return -1; - const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2); - const CItemEx &item2 = items[index]; - if (item.Disk < item2.Disk) - right = index; - else if (item.Disk > item2.Disk) - left = index + 1; - else if (item.LocalHeaderPos == item2.LocalHeaderPos) - return (int)index; - else if (item.LocalHeaderPos < item2.LocalHeaderPos) - right = index; - else - left = index + 1; - } -} - -static bool IsStrangeItem(const CItem &item) -{ - return item.Name.Len() > (1 << 14) || item.Method > (1 << 8); -} - - - -/* - ---------- ReadLocals ---------- - -in: - (_signature == NSignature::kLocalFileHeader) - VirtStreamPos : after _signature : position in Stream - Stream : - Vols : if (IsMultiVol) - (_inBufMode == false) - -action: - it parses local items. - - if ( IsMultiVol) it writes absolute offsets to CItemEx::LocalHeaderPos - if (!IsMultiVol) it writes relative (from ArcInfo.Base) offsets to CItemEx::LocalHeaderPos - later we can correct CItemEx::LocalHeaderPos values, if - some new value for ArcInfo.Base will be detected -out: - S_OK: - (_signature != NSignature::kLocalFileHeade) - _streamPos : after _signature - - S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive. - - another error code: stream reading error or Callback error. - - CUnexpectEnd() exception : it's not fatal exception here. - It means that reading was interrupted by unexpected end of input stream, - but some CItemEx items were parsed OK. - We can stop further archive parsing. - But we can use all filled CItemEx items. -*/ - -HRESULT CInArchive::ReadLocals(CObjectVector &items) -{ - items.Clear(); - - UInt64 progressPrev = _cnt; - - if (Callback) - { - RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL)) - } - - while (_signature == NSignature::kLocalFileHeader) - { - CItemEx item; - - item.LocalHeaderPos = GetVirtStreamPos() - 4; - if (!IsMultiVol) - item.LocalHeaderPos = (UInt64)((Int64)item.LocalHeaderPos - ArcInfo.Base); - - try - { - ReadLocalItem(item); - item.FromLocal = true; - bool isFinished = false; - - if (item.HasDescriptor()) - { - RINOK(FindDescriptor(item, items.Size())) - isFinished = !item.DescriptorWasRead; - } - else - { - if (item.PackSize >= ((UInt64)1 << 62)) - throw CUnexpectEnd(); - RINOK(IncreaseRealPosition(item.PackSize, isFinished)) - } - - items.Add(item); - - if (isFinished) - throw CUnexpectEnd(); - - ReadSignature(); - } - catch (CUnexpectEnd &) - { - if (items.IsEmpty() || (items.Size() == 1 && IsStrangeItem(items[0]))) - return S_FALSE; - throw; - } - - - if (Callback) - if ((items.Size() & 0xFF) == 0 - || _cnt - progressPrev >= ((UInt32)1 << 22)) - { - progressPrev = _cnt; - const UInt64 numFiles = items.Size(); - RINOK(Callback->SetCompleted(&numFiles, &_cnt)) - } - } - - if (items.Size() == 1 && _signature != NSignature::kCentralFileHeader) - if (IsStrangeItem(items[0])) - return S_FALSE; - - return S_OK; -} - - - -HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) -{ - UString name; - { - NWindows::NCOM::CPropVariant prop; - RINOK(volCallback->GetProperty(kpidName, &prop)) - if (prop.vt != VT_BSTR) - return S_OK; - name = prop.bstrVal; - } - - const int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0) - return S_OK; - const UString ext = name.Ptr((unsigned)(dotPos + 1)); - name.DeleteFrom((unsigned)(dotPos + 1)); - - StartVolIndex = (Int32)(-1); - - if (ext.IsEmpty()) - return S_OK; - { - wchar_t c = ext[0]; - IsUpperCase = (c >= 'A' && c <= 'Z'); - if (ext.IsEqualTo_Ascii_NoCase("zip")) - { - BaseName = name; - StartIsZ = true; - StartIsZip = true; - return S_OK; - } - else if (ext.IsEqualTo_Ascii_NoCase("exe")) - { - /* possible cases: - - exe with zip inside - - sfx: a.exe, a.z02, a.z03,... , a.zip - a.exe is start volume. - - zip renamed to exe - */ - - StartIsExe = true; - BaseName = name; - StartVolIndex = 0; - /* sfx-zip can use both arc.exe and arc.zip - We can open arc.zip, if it was requesed to open arc.exe. - But it's possible that arc.exe and arc.zip are not parts of same archive. - So we can disable such operation */ - - // 18.04: we still want to open zip renamed to exe. - /* - { - UString volName = name; - volName += IsUpperCase ? "Z01" : "z01"; - { - CMyComPtr stream; - HRESULT res2 = volCallback->GetStream(volName, &stream); - if (res2 == S_OK) - DisableVolsSearch = true; - } - } - */ - DisableVolsSearch = true; - return S_OK; - } - else if (ext[0] == 'z' || ext[0] == 'Z') - { - if (ext.Len() < 3) - return S_OK; - const wchar_t *end = NULL; - UInt32 volNum = ConvertStringToUInt32(ext.Ptr(1), &end); - if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30)) - return S_OK; - StartVolIndex = (Int32)(volNum - 1); - BaseName = name; - StartIsZ = true; - } - else - return S_OK; - } - - UString volName = BaseName; - volName += (IsUpperCase ? "ZIP" : "zip"); - - HRESULT res = volCallback->GetStream(volName, &ZipStream); - - if (res == S_FALSE || !ZipStream) - { - if (MissingName.IsEmpty()) - { - MissingZip = true; - MissingName = volName; - } - return S_OK; - } - - return res; -} - - -HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, - unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols) -{ - if (Vols.DisableVolsSearch) - return S_OK; - - numMissingVols = 0; - - for (unsigned i = start;; i++) - { - if (lastDisk >= 0 && i >= (unsigned)lastDisk) - break; - - if (i < Vols.Streams.Size()) - if (Vols.Streams[i].Stream) - continue; - - CMyComPtr stream; - - if ((int)i == zipDisk) - { - stream = Vols.ZipStream; - } - else if ((int)i == Vols.StartVolIndex) - { - stream = StartStream; - } - else - { - UString volName = Vols.BaseName; - { - volName.Add_Char(Vols.IsUpperCase ? 'Z' : 'z'); - const unsigned v = i + 1; - if (v < 10) - volName.Add_Char('0'); - volName.Add_UInt32(v); - } - - HRESULT res = volCallback->GetStream(volName, &stream); - if (res != S_OK && res != S_FALSE) - return res; - if (res == S_FALSE || !stream) - { - if (i == 0) - { - UString volName_exe = Vols.BaseName; - volName_exe += (Vols.IsUpperCase ? "EXE" : "exe"); - - HRESULT res2 = volCallback->GetStream(volName_exe, &stream); - if (res2 != S_OK && res2 != S_FALSE) - return res2; - res = res2; - } - } - if (res == S_FALSE || !stream) - { - if (i == 1 && Vols.StartIsExe) - return S_OK; - if (Vols.MissingName.IsEmpty()) - Vols.MissingName = volName; - numMissingVols++; - if (numMissingVols > numMissingVolsMax) - return S_OK; - if (lastDisk == -1 && numMissingVols != 0) - return S_OK; - continue; - } - } - - UInt64 pos, size; - RINOK(InStream_GetPos_GetSize(stream, pos, size)) - - while (i >= Vols.Streams.Size()) - Vols.Streams.AddNew(); - - CVols::CSubStreamInfo &ss = Vols.Streams[i]; - Vols.NumVols++; - Vols.TotalBytesSize += size; - - ss.Stream = stream; - ss.Size = size; - - if ((int)i == zipDisk) - { - Vols.EndVolIndex = (int)(Vols.Streams.Size() - 1); - break; - } - } - - return S_OK; -} - - -HRESULT CInArchive::ReadVols() -{ - CMyComPtr volCallback; - - Callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volCallback); - if (!volCallback) - return S_OK; - - RINOK(Vols.ParseArcName(volCallback)) - - // const int startZIndex = Vols.StartVolIndex; - - if (!Vols.StartIsZ) - { - if (!Vols.StartIsExe) - return S_OK; - } - - int zipDisk = -1; - int cdDisk = -1; - - if (Vols.StartIsZip) - Vols.ZipStream = StartStream; - - if (Vols.ZipStream) - { - Stream = Vols.ZipStream; - - if (Vols.StartIsZip) - Vols.StreamIndex = -1; - else - { - Vols.StreamIndex = -2; - InitBuf(); - } - - HRESULT res = FindCd(true); - - CCdInfo &ecd = Vols.ecd; - if (res == S_OK) - { - zipDisk = (int)ecd.ThisDisk; - Vols.ecd_wasRead = true; - - // if is not multivol or bad multivol, we return to main single stream code - if (ecd.ThisDisk == 0 - || ecd.ThisDisk >= ((UInt32)1 << 30) - || ecd.ThisDisk < ecd.CdDisk) - return S_OK; - - cdDisk = (int)ecd.CdDisk; - if (Vols.StartVolIndex < 0) - Vols.StartVolIndex = (Int32)ecd.ThisDisk; - else if ((UInt32)Vols.StartVolIndex >= ecd.ThisDisk) - return S_OK; - - // Vols.StartVolIndex = ecd.ThisDisk; - // Vols.EndVolIndex = ecd.ThisDisk; - unsigned numMissingVols; - if (cdDisk != zipDisk) - { - // get volumes required for cd. - RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols)) - if (numMissingVols != 0) - { - // cdOK = false; - } - } - } - else if (res != S_FALSE) - return res; - } - - if (Vols.StartVolIndex < 0) - { - // is not mutivol; - return S_OK; - } - - /* - if (!Vols.Streams.IsEmpty()) - IsMultiVol = true; - */ - - unsigned numMissingVols; - - if (cdDisk != 0) - { - // get volumes that were no requested still - const unsigned kNumMissingVolsMax = 1 << 12; - RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols)) - } - - // if (Vols.StartVolIndex >= 0) - { - if (Vols.Streams.IsEmpty()) - if (Vols.StartVolIndex > (1 << 20)) - return S_OK; - if ((unsigned)Vols.StartVolIndex >= Vols.Streams.Size() - || !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream) - { - // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok) - RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols)) - } - } - - if (Vols.ZipStream) - { - // if there is no another volumes and volumeIndex is too big, we don't use multivol mode - if (Vols.Streams.IsEmpty()) - if (zipDisk > (1 << 10)) - return S_OK; - if (zipDisk >= 0) - { - // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok) - RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols)) - } - } - - if (!Vols.Streams.IsEmpty()) - { - IsMultiVol = true; - /* - if (cdDisk) - IsMultiVol = true; - */ - const int startZIndex = Vols.StartVolIndex; - if (startZIndex >= 0) - { - // if all volumes before start volume are OK, we can start parsing from 0 - // if there are missing volumes before startZIndex, we start parsing in current startZIndex - if ((unsigned)startZIndex < Vols.Streams.Size()) - { - for (unsigned i = 0; i <= (unsigned)startZIndex; i++) - if (!Vols.Streams[i].Stream) - { - Vols.StartParsingVol = startZIndex; - break; - } - } - } - } - - return S_OK; -} - - - -HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - - for (;;) - { - if (StreamIndex < 0) - return S_OK; - if ((unsigned)StreamIndex >= Streams.Size()) - return S_OK; - const CVols::CSubStreamInfo &s = Streams[(unsigned)StreamIndex]; - if (!s.Stream) - return S_FALSE; - if (NeedSeek) - { - RINOK(s.SeekToStart()) - NeedSeek = false; - } - UInt32 realProcessedSize = 0; - HRESULT res = s.Stream->Read(data, size, &realProcessedSize); - if (processedSize) - *processedSize = realProcessedSize; - if (res != S_OK) - return res; - if (realProcessedSize != 0) - return res; - StreamIndex++; - NeedSeek = true; - } -} - -Z7_COM7F_IMF(CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - return Vols->Read(data, size, processedSize); -} - - - - -#define COPY_ECD_ITEM_16(n) if (!isZip64 || !ZIP64_IS_16_MAX(ecd. n)) cdInfo. n = ecd. n; -#define COPY_ECD_ITEM_32(n) if (!isZip64 || !ZIP64_IS_32_MAX(ecd. n)) cdInfo. n = ecd. n; - - -HRESULT CInArchive::ReadHeaders(CObjectVector &items) -{ - // buffer that can be used for cd reading - RINOK(AllocateBuffer(kSeqBufferSize)) - - // here we can read small records. So we switch off _inBufMode. - _inBufMode = false; - - HRESULT res = S_OK; - - bool localsWereRead = false; - - /* we try to open archive with the following modes: - 1) CD-MODE : fast mode : we read backward ECD and CD, compare CD items with first Local item. - 2) LOCALS-CD-MODE : slow mode, if CD-MODE fails : we sequentially read all Locals and then CD. - Then we read sequentially ECD64, Locator, ECD again at the end. - - - in LOCALS-CD-MODE we use use the following - variables (with real cd properties) to set Base archive offset - and check real cd properties with values from ECD/ECD64. - */ - - UInt64 cdSize = 0; - UInt64 cdRelatOffset = 0; - UInt32 cdDisk = 0; - - UInt64 cdAbsOffset = 0; // absolute cd offset, for LOCALS-CD-MODE only. - -if (Force_ReadLocals_Mode) -{ - IsArc = true; - res = S_FALSE; // we will use LOCALS-CD-MODE mode -} -else -{ - if (!MarkerIsFound || !MarkerIsSafe) - { - IsArc = true; - res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); - if (res == S_OK) - ReadSignature(); - else if (res != S_FALSE) - return res; - } - else // (MarkerIsFound && MarkerIsSafe) - { - - // _signature must be kLocalFileHeader or kEcd or kEcd64 - - SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2 + 4); - - CanStartNewVol = false; - - if (_signature == NSignature::kEcd64) - { - // UInt64 ecd64Offset = GetVirtStreamPos() - 4; - IsZip64 = true; - - { - const UInt64 recordSize = ReadUInt64(); - if (recordSize < kEcd64_MainSize) - return S_FALSE; - if (recordSize >= ((UInt64)1 << 62)) - return S_FALSE; - - { - const unsigned kBufSize = kEcd64_MainSize; - Byte buf[kBufSize]; - SafeRead(buf, kBufSize); - CCdInfo cdInfo; - cdInfo.ParseEcd64e(buf); - if (!cdInfo.IsEmptyArc()) - return S_FALSE; - } - - RINOK(Skip64(recordSize - kEcd64_MainSize, 0)) - } - - ReadSignature(); - if (_signature != NSignature::kEcd64Locator) - return S_FALSE; - - { - const unsigned kBufSize = 16; - Byte buf[kBufSize]; - SafeRead(buf, kBufSize); - CLocator locator; - locator.Parse(buf); - if (!locator.IsEmptyArc()) - return S_FALSE; - } - - ReadSignature(); - if (_signature != NSignature::kEcd) - return S_FALSE; - } - - if (_signature == NSignature::kEcd) - { - // It must be empty archive or backware archive - // we don't support backware archive still - - const unsigned kBufSize = kEcdSize - 4; - Byte buf[kBufSize]; - SafeRead(buf, kBufSize); - CEcd ecd; - ecd.Parse(buf); - // if (ecd.cdSize != 0) - // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ?? - if (!ecd.IsEmptyArc()) - return S_FALSE; - - ArcInfo.Base = (Int64)ArcInfo.MarkerPos; - IsArc = true; // check it: we need more tests? - - RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)) - ReadSignature(); - } - else - { - CItemEx firstItem; - try - { - try - { - if (!ReadLocalItem(firstItem)) - return S_FALSE; - } - catch(CUnexpectEnd &) - { - return S_FALSE; - } - - IsArc = true; - res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); - if (res == S_OK) - ReadSignature(); - } - catch(CUnexpectEnd &) { res = S_FALSE; } - - if (res != S_FALSE && res != S_OK) - return res; - - if (res == S_OK && items.Size() == 0) - res = S_FALSE; - - if (res == S_OK) - { - // we can't read local items here to keep _inBufMode state - if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base) - res = S_FALSE; - else - { - firstItem.LocalHeaderPos = (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base); - int index = -1; - - UInt32 min_Disk = (UInt32)(Int32)-1; - UInt64 min_LocalHeaderPos = (UInt64)(Int64)-1; - - if (!IsCdUnsorted) - index = FindItem(items, firstItem); - else - { - FOR_VECTOR (i, items) - { - const CItemEx &cdItem = items[i]; - if (cdItem.Disk == firstItem.Disk - && (cdItem.LocalHeaderPos == firstItem.LocalHeaderPos)) - index = (int)i; - - if (i == 0 - || cdItem.Disk < min_Disk - || (cdItem.Disk == min_Disk && cdItem.LocalHeaderPos < min_LocalHeaderPos)) - { - min_Disk = cdItem.Disk; - min_LocalHeaderPos = cdItem.LocalHeaderPos; - } - } - } - - if (index == -1) - res = S_FALSE; - else if (!AreItemsEqual(firstItem, items[(unsigned)index])) - res = S_FALSE; - else - { - ArcInfo.CdWasRead = true; - if (IsCdUnsorted) - ArcInfo.FirstItemRelatOffset = min_LocalHeaderPos; - else - ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; - - // ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset; - } - } - } - } - } // (MarkerIsFound && MarkerIsSafe) - -} // (!onlyLocalsMode) - - - CObjectVector cdItems; - - bool needSetBase = false; // we set needSetBase only for LOCALS_CD_MODE - unsigned numCdItems = items.Size(); - - #ifdef ZIP_SELF_CHECK - res = S_FALSE; // if uncommented, it uses additional LOCALS-CD-MODE mode to check the code - #endif - - if (res != S_OK) - { - // ---------- LOCALS-CD-MODE ---------- - // CD doesn't match firstItem, - // so we clear items and read Locals and CD. - - items.Clear(); - localsWereRead = true; - - HeadersError = false; - HeadersWarning = false; - ExtraMinorError = false; - - /* we can use any mode: with buffer and without buffer - without buffer : skips packed data : fast for big files : slow for small files - with buffer : reads packed data : slow for big files : fast for small files - Buffer mode is more effective. */ - // _inBufMode = false; - _inBufMode = true; - // we could change the buffer size here, if we want smaller Buffer. - // RINOK(ReAllocateBuffer(kSeqBufferSize)); - // InitBuf() - - ArcInfo.Base = 0; - - if (!Disable_FindMarker) - { - if (!MarkerIsFound) - { - if (!IsMultiVol) - return S_FALSE; - if (Vols.StartParsingVol != 0) - return S_FALSE; - // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker. - // so we suppose that there is no sfx stub - RINOK(SeekToVol(0, ArcInfo.MarkerPos2)) - } - else - { - if (ArcInfo.MarkerPos != 0) - { - /* - If multi-vol or there is (No)Span-marker at start of stream, we set (Base) as 0. - In another caes: - (No)Span-marker is supposed as false positive. So we set (Base) as main marker (MarkerPos2). - The (Base) can be corrected later after ECD reading. - But sfx volume with stub and (No)Span-marker in (!IsMultiVol) mode will have incorrect (Base) here. - */ - ArcInfo.Base = (Int64)ArcInfo.MarkerPos2; - } - RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)) - } - } - _cnt = 0; - - ReadSignature(); - - LocalsWereRead = true; - - RINOK(ReadLocals(items)) - - if (_signature != NSignature::kCentralFileHeader) - { - // GetVirtStreamPos() - 4 - if (items.IsEmpty()) - return S_FALSE; - - bool isError = true; - - const UInt32 apkSize = _signature; - const unsigned kApkFooterSize = 16 + 8; - if (apkSize >= kApkFooterSize && apkSize <= (1 << 20)) - { - if (ReadUInt32() == 0) - { - CByteBuffer apk; - apk.Alloc(apkSize); - SafeRead(apk, apkSize); - ReadSignature(); - const Byte *footer = apk + apkSize - kApkFooterSize; - if (_signature == NSignature::kCentralFileHeader) - if (GetUi64(footer) == apkSize) - if (memcmp(footer + 8, "APK Sig Block 42", 16) == 0) - { - isError = false; - IsApk = true; - } - } - } - - if (isError) - { - NoCentralDir = true; - HeadersError = true; - return S_OK; - } - } - - _inBufMode = true; - - cdAbsOffset = GetVirtStreamPos() - 4; - cdDisk = (UInt32)Vols.StreamIndex; - - #ifdef ZIP_SELF_CHECK - if (!IsMultiVol && _cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2) - return E_FAIL; - #endif - - const UInt64 processedCnt_start = _cnt; - - for (;;) - { - CItemEx cdItem; - - RINOK(ReadCdItem(cdItem)) - - cdItems.Add(cdItem); - if (Callback && (cdItems.Size() & 0xFFF) == 0) - { - const UInt64 numFiles = items.Size(); - const UInt64 numBytes = _cnt; - RINOK(Callback->SetCompleted(&numFiles, &numBytes)) - } - ReadSignature(); - if (_signature != NSignature::kCentralFileHeader) - break; - } - - cdSize = _cnt - processedCnt_start; - - #ifdef ZIP_SELF_CHECK - if (!IsMultiVol) - { - if (_cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2) - return E_FAIL; - if (cdSize != (GetVirtStreamPos() - 4) - cdAbsOffset) - return E_FAIL; - } - #endif - - needSetBase = true; - numCdItems = cdItems.Size(); - cdRelatOffset = (UInt64)((Int64)cdAbsOffset - ArcInfo.Base); - - if (!cdItems.IsEmpty()) - { - ArcInfo.CdWasRead = true; - ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; - } - } - - - - CCdInfo cdInfo; - CLocator locator; - bool isZip64 = false; - const UInt64 ecd64AbsOffset = GetVirtStreamPos() - 4; - int ecd64Disk = -1; - - if (_signature == NSignature::kEcd64) - { - ecd64Disk = Vols.StreamIndex; - - IsZip64 = isZip64 = true; - - { - const UInt64 recordSize = ReadUInt64(); - if (recordSize < kEcd64_MainSize - || recordSize >= ((UInt64)1 << 62)) - { - HeadersError = true; - return S_OK; - } - - { - const unsigned kBufSize = kEcd64_MainSize; - Byte buf[kBufSize]; - SafeRead(buf, kBufSize); - cdInfo.ParseEcd64e(buf); - } - - RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size())) - } - - - ReadSignature(); - - if (_signature != NSignature::kEcd64Locator) - { - HeadersError = true; - return S_OK; - } - - { - const unsigned kBufSize = 16; - Byte buf[kBufSize]; - SafeRead(buf, kBufSize); - locator.Parse(buf); - // we ignore the error, where some zip creators use (NumDisks == 0) - // if (locator.NumDisks == 0) HeadersWarning = true; - } - - ReadSignature(); - } - - - if (_signature != NSignature::kEcd) - { - HeadersError = true; - return S_OK; - } - - - CanStartNewVol = false; - - // ---------- ECD ---------- - - CEcd ecd; - { - const unsigned kBufSize = kEcdSize - 4; - Byte buf[kBufSize]; - SafeRead(buf, kBufSize); - ecd.Parse(buf); - } - - COPY_ECD_ITEM_16(ThisDisk) - COPY_ECD_ITEM_16(CdDisk) - COPY_ECD_ITEM_16(NumEntries_in_ThisDisk) - COPY_ECD_ITEM_16(NumEntries) - COPY_ECD_ITEM_32(Size) - COPY_ECD_ITEM_32(Offset) - - bool cdOK = true; - - if ((UInt32)cdInfo.Size != (UInt32)cdSize) - { - // return S_FALSE; - cdOK = false; - } - - if (isZip64) - { - if (cdInfo.NumEntries != numCdItems - || cdInfo.Size != cdSize) - { - cdOK = false; - } - } - - - if (IsMultiVol) - { - if (cdDisk != cdInfo.CdDisk) - HeadersError = true; - } - else if (needSetBase && cdOK) - { - const UInt64 oldBase = (UInt64)ArcInfo.Base; - // localsWereRead == true - // ArcInfo.Base == ArcInfo.MarkerPos2 - // cdRelatOffset == (cdAbsOffset - ArcInfo.Base) - - if (isZip64) - { - if (ecd64Disk == Vols.StartVolIndex) - { - const Int64 newBase = (Int64)ecd64AbsOffset - (Int64)locator.Ecd64Offset; - if (newBase <= (Int64)ecd64AbsOffset) - { - if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) - { - ArcInfo.Base = newBase; - cdRelatOffset = (UInt64)((Int64)cdAbsOffset - newBase); - } - else - cdOK = false; - } - } - } - else if (numCdItems != 0) // we can't use ecd.Offset in empty archive? - { - if ((int)cdDisk == Vols.StartVolIndex) - { - const Int64 newBase = (Int64)cdAbsOffset - (Int64)cdInfo.Offset; - if (newBase <= (Int64)cdAbsOffset) - { - if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) - { - // cd can be more accurate, when it points before Locals - // so we change Base and cdRelatOffset - ArcInfo.Base = newBase; - cdRelatOffset = cdInfo.Offset; - } - else - { - // const UInt64 delta = ((UInt64)cdRelatOffset - cdInfo.Offset); - const UInt64 delta = ((UInt64)(newBase - ArcInfo.Base)); - if ((UInt32)delta == 0) - { - // we set Overflow32bit mode, only if there is (x<<32) offset - // between real_CD_offset_from_MarkerPos and CD_Offset_in_ECD. - // Base and cdRelatOffset unchanged - Overflow32bit = true; - } - else - cdOK = false; - } - } - else - cdOK = false; - } - } - // cdRelatOffset = cdAbsOffset - ArcInfo.Base; - - if (localsWereRead) - { - const UInt64 delta = (UInt64)((Int64)oldBase - ArcInfo.Base); - if (delta != 0) - { - FOR_VECTOR (i, items) - items[i].LocalHeaderPos += delta; - } - } - } - - if (!cdOK) - HeadersError = true; - - EcdVolIndex = cdInfo.ThisDisk; - - if (!IsMultiVol) - { - if (EcdVolIndex == 0 && Vols.MissingZip && Vols.StartIsExe) - { - Vols.MissingName.Empty(); - Vols.MissingZip = false; - } - - if (localsWereRead) - { - if (EcdVolIndex != 0) - { - FOR_VECTOR (i, items) - items[i].Disk = EcdVolIndex; - } - } - - UseDisk_in_SingleVol = true; - } - - if (isZip64) - { - if ((cdInfo.ThisDisk == 0 && ecd64AbsOffset != (UInt64)(ArcInfo.Base + (Int64)locator.Ecd64Offset)) - // || cdInfo.NumEntries_in_ThisDisk != numCdItems - || cdInfo.NumEntries != numCdItems - || cdInfo.Size != cdSize - || (cdInfo.Offset != cdRelatOffset && !items.IsEmpty())) - { - HeadersError = true; - return S_OK; - } - } - - if (cdOK && !cdItems.IsEmpty()) - { - // ---------- merge Central Directory Items ---------- - - CRecordVector items2; - - int nextLocalIndex = 0; - - LocalsCenterMerged = true; - - FOR_VECTOR (i, cdItems) - { - if (Callback) - if ((i & 0x3FFF) == 0) - { - const UInt64 numFiles64 = items.Size() + items2.Size(); - RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) - } - - const CItemEx &cdItem = cdItems[i]; - - int index = -1; - - if (nextLocalIndex != -1) - { - if ((unsigned)nextLocalIndex < items.Size()) - { - CItemEx &item = items[(unsigned)nextLocalIndex]; - if (item.Disk == cdItem.Disk && - (item.LocalHeaderPos == cdItem.LocalHeaderPos - || (Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos))) - index = nextLocalIndex++; - else - nextLocalIndex = -1; - } - } - - if (index == -1) - index = FindItem(items, cdItem); - - // index = -1; - - if (index == -1) - { - items2.Add(i); - HeadersError = true; - continue; - } - - CItemEx &item = items[(unsigned)index]; - if (item.Name != cdItem.Name - // || item.Name.Len() != cdItem.Name.Len() - || item.PackSize != cdItem.PackSize - || item.Size != cdItem.Size - // item.ExtractVersion != cdItem.ExtractVersion - || !FlagsAreSame(item, cdItem) - || item.Crc != cdItem.Crc) - { - HeadersError = true; - continue; - } - - // item.Name = cdItem.Name; - item.MadeByVersion = cdItem.MadeByVersion; - item.CentralExtra = cdItem.CentralExtra; - item.InternalAttrib = cdItem.InternalAttrib; - item.ExternalAttrib = cdItem.ExternalAttrib; - item.Comment = cdItem.Comment; - item.FromCentral = cdItem.FromCentral; - // 22.02: we force utf8 flag, if central header has utf8 flag - if (cdItem.Flags & NFileHeader::NFlags::kUtf8) - item.Flags |= NFileHeader::NFlags::kUtf8; - } - - FOR_VECTOR (k, items2) - items.Add(cdItems[items2[k]]); - } - - if (ecd.NumEntries < ecd.NumEntries_in_ThisDisk) - HeadersError = true; - - if (ecd.ThisDisk == 0) - { - // if (isZip64) - { - if (ecd.NumEntries != ecd.NumEntries_in_ThisDisk) - HeadersError = true; - } - } - - if (isZip64) - { - if (cdInfo.NumEntries != items.Size() - || (ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF)) - HeadersError = true; - } - else - { - // old 7-zip could store 32-bit number of CD items to 16-bit field. - // if (ecd.NumEntries != items.Size()) - if (ecd.NumEntries > items.Size()) - HeadersError = true; - - if (cdInfo.NumEntries != numCdItems) - { - if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems) - HeadersError = true; - else - Cd_NumEntries_Overflow_16bit = true; - } - } - - ReadBuffer(ArcInfo.Comment, ecd.CommentSize); - - _inBufMode = false; - - // DisableBufMode(); - // Buffer.Free(); - /* we can't clear buf varibles. we need them to calculate PhySize of archive */ - - if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems - || (UInt32)cdInfo.Size != (UInt32)cdSize - || ((UInt32)cdInfo.Offset != (UInt32)cdRelatOffset && !items.IsEmpty())) - { - // return S_FALSE; - HeadersError = true; - } - - #ifdef ZIP_SELF_CHECK - if (localsWereRead) - { - const UInt64 endPos = ArcInfo.MarkerPos2 + _cnt; - if (endPos != (IsMultiVol ? Vols.TotalBytesSize : ArcInfo.FileEndPos)) - { - // there are some data after the end of archive or error in code; - return E_FAIL; - } - } - #endif - - // printf("\nOpen OK"); - return S_OK; -} - - - -HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, - IArchiveOpenCallback *callback, CObjectVector &items) -{ - items.Clear(); - - Close(); - - UInt64 startPos; - RINOK(InStream_GetPos(stream, startPos)) - RINOK(InStream_GetSize_SeekToEnd(stream, ArcInfo.FileEndPos)) - _streamPos = ArcInfo.FileEndPos; - - StartStream = stream; - Stream = stream; - Callback = callback; - - DisableBufMode(); - - bool volWasRequested = false; - - if (!Disable_VolsRead) - if (callback - && (startPos == 0 || !searchLimit || *searchLimit != 0)) - { - // we try to read volumes only if it's first call (offset == 0) or scan is allowed. - volWasRequested = true; - RINOK(ReadVols()) - } - - if (Disable_FindMarker) - { - RINOK(SeekToVol(-1, startPos)) - StreamRef = stream; - Stream = stream; - MarkerIsFound = true; - MarkerIsSafe = true; - ArcInfo.MarkerPos = startPos; - ArcInfo.MarkerPos2 = startPos; - } - else - if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()) - { - // only StartParsingVol = 0 is safe search. - RINOK(SeekToVol(0, 0)) - // if (Stream) - { - // UInt64 limit = 1 << 22; // for sfx - UInt64 limit = 0; // without sfx - - HRESULT res = FindMarker(&limit); - - if (res == S_OK) - { - MarkerIsFound = true; - MarkerIsSafe = true; - } - else if (res != S_FALSE) - return res; - } - } - else - { - // printf("\nOpen offset = %u\n", (unsigned)startPos); - if (IsMultiVol - && (unsigned)Vols.StartParsingVol < Vols.Streams.Size() - && Vols.Streams[(unsigned)Vols.StartParsingVol].Stream) - { - RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0)) - } - else - { - RINOK(SeekToVol(-1, startPos)) - } - - // UInt64 limit = 1 << 22; - // HRESULT res = FindMarker(&limit); - - HRESULT res = FindMarker(searchLimit); - - // const UInt64 curPos = GetVirtStreamPos(); - const UInt64 curPos = ArcInfo.MarkerPos2 + 4; - - if (res == S_OK) - MarkerIsFound = true; - else if (!IsMultiVol) - { - /* - // if (startPos != 0), probably CD could be already tested with another call with (startPos == 0). - // so we don't want to try to open CD again in that case. - if (startPos != 0) - return res; - // we can try to open CD, if there is no Marker and (startPos == 0). - // is it OK to open such files as ZIP, or big number of false positive, when CD can be find in end of file ? - */ - return res; - } - - if (ArcInfo.IsSpanMode && !volWasRequested) - { - RINOK(ReadVols()) - if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0) - ArcInfo.MarkerVolIndex = Vols.StartVolIndex; - } - - MarkerIsSafe = !IsMultiVol - || (ArcInfo.MarkerVolIndex == 0 && ArcInfo.MarkerPos == 0) - ; - - - if (IsMultiVol) - { - if ((unsigned)Vols.StartVolIndex < Vols.Streams.Size()) - { - Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream; - if (Stream) - { - RINOK(Seek_SavePos(curPos)) - } - else - IsMultiVol = false; - } - else - IsMultiVol = false; - } - - if (!IsMultiVol) - { - if (Vols.StreamIndex != -1) - { - Stream = StartStream; - Vols.StreamIndex = -1; - InitBuf(); - RINOK(Seek_SavePos(curPos)) - } - - ArcInfo.MarkerVolIndex = -1; - StreamRef = stream; - Stream = stream; - } - } - - - if (!IsMultiVol) - Vols.ClearRefs(); - - { - HRESULT res; - try - { - res = ReadHeaders(items); - } - catch (const CSystemException &e) { res = e.ErrorCode; } - catch (const CUnexpectEnd &) - { - if (items.IsEmpty()) - return S_FALSE; - UnexpectedEnd = true; - res = S_OK; - } - catch (...) - { - DisableBufMode(); - throw; - } - - if (IsMultiVol) - { - ArcInfo.FinishPos = ArcInfo.FileEndPos; - if ((unsigned)Vols.StreamIndex < Vols.Streams.Size()) - if (GetVirtStreamPos() < Vols.Streams[(unsigned)Vols.StreamIndex].Size) - ArcInfo.ThereIsTail = true; - } - else - { - ArcInfo.FinishPos = GetVirtStreamPos(); - ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > ArcInfo.FinishPos); - } - - DisableBufMode(); - - IsArcOpen = true; - if (!IsMultiVol) - Vols.Streams.Clear(); - return res; - } -} - - -HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr &stream) -{ - stream.Release(); - - UInt64 pos = item.LocalHeaderPos; - if (seekPackData) - pos += item.LocalFullHeaderSize; - - if (!IsMultiVol) - { - if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex) - return S_OK; - pos = (UInt64)((Int64)pos + ArcInfo.Base); - RINOK(InStream_SeekSet(StreamRef, pos)) - stream = StreamRef; - return S_OK; - } - - if (item.Disk >= Vols.Streams.Size()) - return S_OK; - - IInStream *str2 = Vols.Streams[item.Disk].Stream; - if (!str2) - return S_OK; - RINOK(InStream_SeekSet(str2, pos)) - - Vols.NeedSeek = false; - Vols.StreamIndex = (int)item.Disk; - - CVolStream *volsStreamSpec = new CVolStream; - volsStreamSpec->Vols = &Vols; - stream = volsStreamSpec; - - return S_OK; -} - -}} +// Archive/ZipIn.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../Common/DynamicBuffer.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyException.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/PropVariant.h" + +#include "../IArchive.h" + +#include "ZipIn.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(offs, v) v = Get16(p + (offs)) +#define G32(offs, v) v = Get32(p + (offs)) +#define G64(offs, v) v = Get64(p + (offs)) + +namespace NArchive { +namespace NZip { + +/* we try to use same size of Buffer (1 << 17) for all tasks. + it allow to avoid reallocations and cache clearing. */ + +static const size_t kSeqBufferSize = (size_t)1 << 17; + +/* +Open() +{ + _inBufMode = false; + ReadVols() + FindCd(); + TryEcd64() + SeekToVol() + FindMarker() + _inBufMode = true; + ReadHeaders() + _inBufMode = false; + ReadCd() + FindCd() + TryEcd64() + TryReadCd() + { + SeekToVol(); + _inBufMode = true; + } + _inBufMode = true; + ReadLocals() + ReadCdItem() + .... +} +FindCd() writes to Buffer without touching (_inBufMode) +*/ + +/* + if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE + if ( defined ZIP_SELF_CHECK) : it always reads CD and LOCALS-CD-MODE + use ZIP_SELF_CHECK to check LOCALS-CD-MODE for any zip archive +*/ + +// #define ZIP_SELF_CHECK + + +struct CEcd +{ + UInt16 ThisDisk; + UInt16 CdDisk; + UInt16 NumEntries_in_ThisDisk; + UInt16 NumEntries; + UInt32 Size; + UInt32 Offset; + UInt16 CommentSize; + + bool IsEmptyArc() const + { + return ThisDisk == 0 + && CdDisk == 0 + && NumEntries_in_ThisDisk == 0 + && NumEntries == 0 + && Size == 0 + && Offset == 0 // test it + ; + } + + void Parse(const Byte *p); // (p) doesn't include signature +}; + +void CEcd::Parse(const Byte *p) +{ + // (p) doesn't include signature + G16(0, ThisDisk); + G16(2, CdDisk); + G16(4, NumEntries_in_ThisDisk); + G16(6, NumEntries); + G32(8, Size); + G32(12, Offset); + G16(16, CommentSize); +} + + +void CCdInfo::ParseEcd32(const Byte *p) +{ + IsFromEcd64 = false; + // (p) includes signature + p += 4; + G16(0, ThisDisk); + G16(2, CdDisk); + G16(4, NumEntries_in_ThisDisk); + G16(6, NumEntries); + G32(8, Size); + G32(12, Offset); + G16(16, CommentSize); +} + +void CCdInfo::ParseEcd64e(const Byte *p) +{ + IsFromEcd64 = true; + // (p) exclude signature + G16(0, VersionMade); + G16(2, VersionNeedExtract); + G32(4, ThisDisk); + G32(8, CdDisk); + + G64(12, NumEntries_in_ThisDisk); + G64(20, NumEntries); + G64(28, Size); + G64(36, Offset); +} + + +struct CLocator +{ + UInt32 Ecd64Disk; + UInt32 NumDisks; + UInt64 Ecd64Offset; + + CLocator(): Ecd64Disk(0), NumDisks(0), Ecd64Offset(0) {} + + void Parse(const Byte *p) + { + G32(0, Ecd64Disk); + G64(4, Ecd64Offset); + G32(12, NumDisks); + } + + bool IsEmptyArc() const + { + return Ecd64Disk == 0 && NumDisks == 0 && Ecd64Offset == 0; + } +}; + + + + +void CInArchive::ClearRefs() +{ + StreamRef.Release(); + Stream = NULL; + StartStream = NULL; + Callback = NULL; + + Vols.Clear(); +} + +void CInArchive::Close() +{ + _cnt = 0; + DisableBufMode(); + + IsArcOpen = false; + + IsArc = false; + IsZip64 = false; + + IsApk = false; + IsCdUnsorted = false; + + HeadersError = false; + HeadersWarning = false; + ExtraMinorError = false; + + UnexpectedEnd = false; + LocalsWereRead = false; + LocalsCenterMerged = false; + NoCentralDir = false; + Overflow32bit = false; + Cd_NumEntries_Overflow_16bit = false; + + MarkerIsFound = false; + MarkerIsSafe = false; + + IsMultiVol = false; + UseDisk_in_SingleVol = false; + EcdVolIndex = 0; + + ArcInfo.Clear(); + + ClearRefs(); +} + + + +HRESULT CInArchive::Seek_SavePos(UInt64 offset) +{ + // InitBuf(); + // if (!Stream) return S_FALSE; + return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos); +} + + +/* SeekToVol() will keep the cached mode, if new volIndex is + same Vols.StreamIndex volume, and offset doesn't go out of cached region */ + +HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset) +{ + if (volIndex != Vols.StreamIndex) + { + if (IsMultiVol && volIndex >= 0) + { + if ((unsigned)volIndex >= Vols.Streams.Size()) + return S_FALSE; + if (!Vols.Streams[(unsigned)volIndex].Stream) + return S_FALSE; + Stream = Vols.Streams[(unsigned)volIndex].Stream; + } + else if (volIndex == -2) + { + if (!Vols.ZipStream) + return S_FALSE; + Stream = Vols.ZipStream; + } + else + Stream = StartStream; + Vols.StreamIndex = volIndex; + } + else + { + if (offset <= _streamPos) + { + const UInt64 back = _streamPos - offset; + if (back <= _bufCached) + { + _bufPos = _bufCached - (size_t)back; + return S_OK; + } + } + } + InitBuf(); + return Seek_SavePos(offset); +} + + +HRESULT CInArchive::AllocateBuffer(size_t size) +{ + if (size <= Buffer.Size()) + return S_OK; + /* in cached mode virtual_pos is not equal to phy_pos (_streamPos) + so we change _streamPos and do Seek() to virtual_pos before cache clearing */ + if (_bufPos != _bufCached) + { + RINOK(Seek_SavePos(GetVirtStreamPos())) + } + InitBuf(); + Buffer.AllocAtLeast(size); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + return S_OK; +} + +// ---------- ReadFromCache ---------- +// reads from cache and from Stream +// move to next volume can be allowed if (CanStartNewVol) and only before first byte reading + +HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed) +{ + HRESULT result = S_OK; + processed = 0; + + for (;;) + { + if (size == 0) + return S_OK; + + const size_t avail = GetAvail(); + + if (avail != 0) + { + unsigned cur = size; + if (cur > avail) + cur = (unsigned)avail; + memcpy(data, (const Byte *)Buffer + _bufPos, cur); + + data += cur; + size -= cur; + processed += cur; + + _bufPos += cur; + _cnt += cur; + + CanStartNewVol = false; + + continue; + } + + InitBuf(); + + if (_inBufMode) + { + UInt32 cur = 0; + result = Stream->Read(Buffer, (UInt32)Buffer.Size(), &cur); + _bufPos = 0; + _bufCached = cur; + _streamPos += cur; + if (cur != 0) + CanStartNewVol = false; + if (result != S_OK) + break; + if (cur != 0) + continue; + } + else + { + size_t cur = size; + result = ReadStream(Stream, data, &cur); + data += cur; + size -= (unsigned)cur; + processed += (unsigned)cur; + _streamPos += cur; + _cnt += cur; + if (cur != 0) + { + CanStartNewVol = false; + break; + } + if (result != S_OK) + break; + } + + if ( !IsMultiVol + || !CanStartNewVol + || Vols.StreamIndex < 0 + || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) + break; + + const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1]; + if (!s.Stream) + break; + result = s.SeekToStart(); + if (result != S_OK) + break; + Vols.StreamIndex++; + _streamPos = 0; + // Vols.NeedSeek = false; + + Stream = s.Stream; + } + + return result; +} + + +HRESULT CInArchive::ReadFromCache_FALSE(Byte *data, unsigned size) +{ + unsigned processed; + HRESULT res = ReadFromCache(data, size, processed); + if (res == S_OK && size != processed) + return S_FALSE; + return res; +} + + +static bool CheckDosTime(UInt32 dosTime) +{ + if (dosTime == 0) + return true; + unsigned month = (dosTime >> 21) & 0xF; + unsigned day = (dosTime >> 16) & 0x1F; + unsigned hour = (dosTime >> 11) & 0x1F; + unsigned min = (dosTime >> 5) & 0x3F; + unsigned sec = (dosTime & 0x1F) * 2; + if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) + return false; + return true; +} + +API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size) +{ + if (size < 8) + return k_IsArc_Res_NEED_MORE; + if (p[0] != 'P') + return k_IsArc_Res_NO; + + UInt32 sig = Get32(p); + + if (sig == NSignature::kNoSpan || sig == NSignature::kSpan) + { + p += 4; + size -= 4; + } + + sig = Get32(p); + + if (sig == NSignature::kEcd64) + { + if (size < kEcd64_FullSize) + return k_IsArc_Res_NEED_MORE; + + const UInt64 recordSize = Get64(p + 4); + if ( recordSize < kEcd64_MainSize + || recordSize > kEcd64_MainSize + (1 << 20)) + return k_IsArc_Res_NO; + CCdInfo cdInfo; + cdInfo.ParseEcd64e(p + 12); + if (!cdInfo.IsEmptyArc()) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; + } + + if (sig == NSignature::kEcd) + { + if (size < kEcdSize) + return k_IsArc_Res_NEED_MORE; + CEcd ecd; + ecd.Parse(p + 4); + // if (ecd.cdSize != 0) + if (!ecd.IsEmptyArc()) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; // k_IsArc_Res_YES_2; + } + + if (sig != NSignature::kLocalFileHeader) + return k_IsArc_Res_NO; + + if (size < kLocalHeaderSize) + return k_IsArc_Res_NEED_MORE; + + p += 4; + + { + const unsigned kPureHeaderSize = kLocalHeaderSize - 4; + unsigned i; + for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); + if (i == kPureHeaderSize) + return k_IsArc_Res_NEED_MORE; + } + + /* + if (p[0] >= 128) // ExtractVersion.Version; + return k_IsArc_Res_NO; + */ + + // ExtractVersion.Version = p[0]; + // ExtractVersion.HostOS = p[1]; + // Flags = Get16(p + 2); + // Method = Get16(p + 4); + /* + // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now + UInt32 dosTime = Get32(p + 6); + if (!CheckDosTime(dosTime)) + return k_IsArc_Res_NO; + */ + // Crc = Get32(p + 10); + // PackSize = Get32(p + 14); + // Size = Get32(p + 18); + const unsigned nameSize = Get16(p + 22); + unsigned extraSize = Get16(p + 24); + const UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize; + + /* + // 21.02: fixed. we don't use the following check + if (extraOffset + extraSize > (1 << 16)) + return k_IsArc_Res_NO; + */ + + p -= 4; + + { + size_t rem = size - kLocalHeaderSize; + if (rem > nameSize) + rem = nameSize; + const Byte *p2 = p + kLocalHeaderSize; + for (size_t i = 0; i < rem; i++) + if (p2[i] == 0) + { + // we support some "bad" zip archives that contain zeros after name + for (size_t k = i + 1; k < rem; k++) + if (p2[k] != 0) + return k_IsArc_Res_NO; + break; + /* + if (i != nameSize - 1) + return k_IsArc_Res_NO; + */ + } + } + + if (size < extraOffset) + return k_IsArc_Res_NEED_MORE; + + if (extraSize > 0) + { + p += extraOffset; + size -= extraOffset; + while (extraSize != 0) + { + if (extraSize < 4) + { + // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers. + // so we return k_IsArc_Res_YES to support such archives. + // return k_IsArc_Res_NO; // do we need to support such extra ? + return k_IsArc_Res_YES; + } + if (size < 4) + return k_IsArc_Res_NEED_MORE; + unsigned dataSize = Get16(p + 2); + size -= 4; + extraSize -= 4; + p += 4; + if (dataSize > extraSize) + { + // It can be error on header. + // We want to support such rare case bad archives. + // We use additional checks to reduce false-positive probability. + if (nameSize == 0 + || nameSize > (1 << 9) + || extraSize > (1 << 9)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; + } + if (dataSize > size) + return k_IsArc_Res_NEED_MORE; + size -= dataSize; + extraSize -= dataSize; + p += dataSize; + } + } + + return k_IsArc_Res_YES; +} + +static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal) +{ + UInt32 res = IsArc_Zip(p, size); + if (res == k_IsArc_Res_NEED_MORE && isFinal) + return k_IsArc_Res_NO; + return res; +} + + + +/* FindPK_4() is allowed to access data up to and including &limit[3]. + limit[4] access is not allowed. + return: + (return_ptr < limit) : "PK" was found at (return_ptr) + (return_ptr >= limit) : limit was reached or crossed. So no "PK" found before limit +*/ +Z7_NO_INLINE +static const Byte *FindPK_4(const Byte *p, const Byte *limit) +{ + for (;;) + { + for (;;) + { + if (p >= limit) + return limit; + Byte b = p[1]; + if (b == 0x4B) { if (p[0] == 0x50) { return p; } p += 1; break; } + if (b == 0x50) { if (p[2] == 0x4B) { return p + 1; } p += 2; break; } + b = p[3]; + p += 4; + if (b == 0x4B) { if (p[-2]== 0x50) { return p - 2; } p -= 1; break; } + if (b == 0x50) { if (p[0] == 0x4B) { return p - 1; } break; } + } + } + /* + for (;;) + { + for (;;) + { + if (p >= limit) + return limit; + if (*p++ == 0x50) break; + if (*p++ == 0x50) break; + if (*p++ == 0x50) break; + if (*p++ == 0x50) break; + } + if (*p == 0x4B) + return p - 1; + } + */ +} + + +/* +---------- FindMarker ---------- +returns: + S_OK: + ArcInfo.MarkerVolIndex : volume of marker + ArcInfo.MarkerPos : Pos of first signature + ArcInfo.MarkerPos2 : Pos of main signature (local item signature in most cases) + _streamPos : stream pos + _cnt : The number of virtal Bytes after start of search to offset after signature + _signature : main signature + + S_FALSE: can't find marker, or there is some non-zip data after marker + + Error code: stream reading error. +*/ + +HRESULT CInArchive::FindMarker(const UInt64 *searchLimit) +{ + ArcInfo.MarkerPos = GetVirtStreamPos(); + ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; + ArcInfo.MarkerVolIndex = Vols.StreamIndex; + + _cnt = 0; + + CanStartNewVol = false; + + if (searchLimit && *searchLimit == 0) + { + Byte startBuf[kMarkerSize]; + RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)) + + UInt32 marker = Get32(startBuf); + _signature = marker; + + if ( marker == NSignature::kNoSpan + || marker == NSignature::kSpan) + { + RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize)) + _signature = Get32(startBuf); + } + + if ( _signature != NSignature::kEcd + && _signature != NSignature::kEcd64 + && _signature != NSignature::kLocalFileHeader) + return S_FALSE; + + ArcInfo.MarkerPos2 = GetVirtStreamPos() - 4; + ArcInfo.IsSpanMode = (marker == NSignature::kSpan); + + // we use weak test in case of (*searchLimit == 0) + // since error will be detected later in Open function + return S_OK; + } + + // zip specification: (_zip_header_size < (1 << 16)) + // so we need such size to check header + const size_t kCheckSize = (size_t)1 << 16; + const size_t kBufSize = (size_t)1 << 17; // (kBufSize must be > kCheckSize) + + RINOK(AllocateBuffer(kBufSize)) + + _inBufMode = true; + + UInt64 progressPrev = 0; + + for (;;) + { + RINOK(LookAhead(kBufSize)) + + const size_t avail = GetAvail(); + + size_t limitPos; + // (avail > kBufSize) is possible, if (Buffer.Size() > kBufSize) + const bool isFinished = (avail < kBufSize); + if (isFinished) + { + const unsigned kMinAllowed = 4; + if (avail <= kMinAllowed) + { + if ( !IsMultiVol + || Vols.StreamIndex < 0 + || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) + break; + + SkipLookahed(avail); + + const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1]; + if (!s.Stream) + break; + + RINOK(s.SeekToStart()) + + InitBuf(); + Vols.StreamIndex++; + _streamPos = 0; + Stream = s.Stream; + continue; + } + limitPos = avail - kMinAllowed; + } + else + limitPos = (avail - kCheckSize); + + // we don't check at (limitPos) for good fast aligned operations + + if (searchLimit) + { + if (_cnt > *searchLimit) + break; + UInt64 rem = *searchLimit - _cnt; + if (limitPos > rem) + limitPos = (size_t)rem + 1; + } + + if (limitPos == 0) + break; + + const Byte * const pStart = Buffer + _bufPos; + const Byte * p = pStart; + const Byte * const limit = pStart + limitPos; + + for (;; p++) + { + p = FindPK_4(p, limit); + if (p >= limit) + break; + size_t rem = (size_t)(pStart + avail - p); + /* 22.02 : we limit check size with kCheckSize to be consistent for + any different combination of _bufPos in Buffer and size of Buffer. */ + if (rem > kCheckSize) + rem = kCheckSize; + const UInt32 res = IsArc_Zip_2(p, rem, isFinished); + if (res != k_IsArc_Res_NO) + { + if (rem < kMarkerSize) + return S_FALSE; + _signature = Get32(p); + SkipLookahed((size_t)(p - pStart)); + ArcInfo.MarkerVolIndex = Vols.StreamIndex; + ArcInfo.MarkerPos = GetVirtStreamPos(); + ArcInfo.MarkerPos2 = ArcInfo.MarkerPos; + SkipLookahed(4); + if ( _signature == NSignature::kNoSpan + || _signature == NSignature::kSpan) + { + if (rem < kMarkerSize * 2) + return S_FALSE; + ArcInfo.IsSpanMode = (_signature == NSignature::kSpan); + _signature = Get32(p + 4); + ArcInfo.MarkerPos2 += 4; + SkipLookahed(4); + } + return S_OK; + } + } + + if (!IsMultiVol && isFinished) + break; + + SkipLookahed((size_t)(p - pStart)); + + if (Callback && (_cnt - progressPrev) >= ((UInt32)1 << 23)) + { + progressPrev = _cnt; + // const UInt64 numFiles64 = 0; + RINOK(Callback->SetCompleted(NULL, &_cnt)) + } + } + + return S_FALSE; +} + + +/* +---------- IncreaseRealPosition ---------- +moves virtual offset in virtual stream. +changing to new volumes is allowed +*/ + +HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished) +{ + isFinished = false; + + for (;;) + { + const size_t avail = GetAvail(); + + if (offset <= avail) + { + _bufPos += (size_t)offset; + _cnt += offset; + return S_OK; + } + + _cnt += avail; + offset -= avail; + + _bufCached = 0; + _bufPos = 0; + + if (!_inBufMode) + break; + + CanStartNewVol = true; + LookAhead(1); + + if (GetAvail() == 0) + return S_OK; + } + + // cache is empty + + if (!IsMultiVol) + { + _cnt += offset; + return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos); + } + + for (;;) + { + if (offset == 0) + return S_OK; + + if (Vols.StreamIndex < 0) + return S_FALSE; + if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) + { + isFinished = true; + return S_OK; + } + { + const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex]; + if (!s.Stream) + { + isFinished = true; + return S_OK; + } + if (_streamPos > s.Size) + return S_FALSE; + const UInt64 rem = s.Size - _streamPos; + if ((UInt64)offset <= rem) + { + _cnt += offset; + return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos); + } + RINOK(Seek_SavePos(s.Size)) + offset -= rem; + _cnt += rem; + } + + Stream = NULL; + _streamPos = 0; + Vols.StreamIndex++; + if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size()) + { + isFinished = true; + return S_OK; + } + const CVols::CSubStreamInfo &s2 = Vols.Streams[(unsigned)Vols.StreamIndex]; + if (!s2.Stream) + { + isFinished = true; + return S_OK; + } + Stream = s2.Stream; + RINOK(Seek_SavePos(0)) + } +} + + + +/* +---------- LookAhead ---------- +Reads data to buffer, if required. + +It can read from volumes as long as Buffer.Size(). +But it moves to new volume, only if it's required to provide minRequired bytes in buffer. + +in: + (minRequired <= Buffer.Size()) + +return: + S_OK : if (GetAvail() < minRequired) after function return, it's end of stream(s) data, or no new volume stream. + Error codes: IInStream::Read() error or IInStream::Seek() error for multivol +*/ + +HRESULT CInArchive::LookAhead(size_t minRequired) +{ + for (;;) + { + const size_t avail = GetAvail(); + + if (minRequired <= avail) + return S_OK; + + if (_bufPos != 0) + { + if (avail != 0) + memmove(Buffer, Buffer + _bufPos, avail); + _bufPos = 0; + _bufCached = avail; + } + + const size_t pos = _bufCached; + UInt32 processed = 0; + HRESULT res = Stream->Read(Buffer + pos, (UInt32)(Buffer.Size() - pos), &processed); + _streamPos += processed; + _bufCached += processed; + + if (res != S_OK) + return res; + + if (processed != 0) + continue; + + if ( !IsMultiVol + || !CanStartNewVol + || Vols.StreamIndex < 0 + || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size()) + return S_OK; + + const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1]; + if (!s.Stream) + return S_OK; + + RINOK(s.SeekToStart()) + + Vols.StreamIndex++; + _streamPos = 0; + Stream = s.Stream; + // Vols.NeedSeek = false; + } +} + + +class CUnexpectEnd {}; + + +/* +---------- SafeRead ---------- + +reads data of exact size from stream(s) + +in: + _inBufMode + if (CanStartNewVol) it can go to next volume before first byte reading, if there is end of volume data. + +in, out: + _streamPos : position in Stream + Stream + Vols : if (IsMultiVol) + _cnt + +out: + (CanStartNewVol == false), if some data was read + +return: + S_OK : success reading of requested data + +exceptions: + CSystemException() - stream reading error + CUnexpectEnd() : could not read data of requested size +*/ + +void CInArchive::SafeRead(Byte *data, unsigned size) +{ + unsigned processed; + HRESULT result = ReadFromCache(data, size, processed); + if (result != S_OK) + throw CSystemException(result); + if (size != processed) + throw CUnexpectEnd(); +} + +void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size) +{ + buffer.Alloc(size); + if (size != 0) + SafeRead(buffer, size); +} + +// Byte CInArchive::ReadByte () { Byte b; SafeRead(&b, 1); return b; } +// UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeRead(buf, 2); return Get16(buf); } +UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeRead(buf, 4); return Get32(buf); } +UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeRead(buf, 8); return Get64(buf); } + +void CInArchive::ReadSignature() +{ + CanStartNewVol = true; + _signature = ReadUInt32(); + // CanStartNewVol = false; // it's already changed in SafeRead +} + + +// we Skip() inside headers only, so no need for stream change in multivol. + +void CInArchive::Skip(size_t num) +{ + while (num != 0) + { + const unsigned kBufSize = (size_t)1 << 10; + Byte buf[kBufSize]; + unsigned step = kBufSize; + if (step > num) + step = (unsigned)num; + SafeRead(buf, step); + num -= step; + } +} + +/* +HRESULT CInArchive::Callback_Completed(unsigned numFiles) +{ + const UInt64 numFiles64 = numFiles; + return Callback->SetCompleted(&numFiles64, &_cnt); +} +*/ + +HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles) +{ + if (num == 0) + return S_OK; + + for (;;) + { + size_t step = (size_t)1 << 24; + if (step > num) + step = (size_t)num; + Skip(step); + num -= step; + if (num == 0) + return S_OK; + if (Callback) + { + const UInt64 numFiles64 = numFiles; + RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) + } + } +} + + +bool CInArchive::ReadFileName(unsigned size, AString &s) +{ + if (size == 0) + { + s.Empty(); + return true; + } + char *p = s.GetBuf(size); + SafeRead((Byte *)p, size); + unsigned i = size; + do + { + if (p[i - 1] != 0) + break; + } + while (--i); + s.ReleaseBuf_CalcLen(size); + return s.Len() == i; +} + + +#define ZIP64_IS_32_MAX(n) ((n) == 0xFFFFFFFF) +#define ZIP64_IS_16_MAX(n) ((n) == 0xFFFF) + + +bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, + UInt64 &unpackSize, UInt64 &packSize, + CItem *cdItem) +{ + extra.Clear(); + + while (extraSize >= 4) + { + CExtraSubBlock subBlock; + const UInt32 pair = ReadUInt32(); + subBlock.ID = (pair & 0xFFFF); + unsigned size = (unsigned)(pair >> 16); + // const unsigned origSize = size; + + extraSize -= 4; + + if (size > extraSize) + { + // it's error in extra + HeadersWarning = true; + extra.Error = true; + Skip(extraSize); + return false; + } + + extraSize -= size; + + if (subBlock.ID == NFileHeader::NExtraID::kZip64) + { + extra.IsZip64 = true; + bool isOK = true; + + if (!cdItem + && size == 16 + && !ZIP64_IS_32_MAX(unpackSize) + && !ZIP64_IS_32_MAX(packSize)) + { + /* Win10 Explorer's "Send to Zip" for big (3500 MiB) files + creates Zip64 Extra in local file header. + But if both uncompressed and compressed sizes are smaller than 4 GiB, + Win10 doesn't store 0xFFFFFFFF in 32-bit fields as expected by zip specification. + 21.04: we ignore these minor errors in Win10 zip archives. */ + if (ReadUInt64() != unpackSize) + isOK = false; + if (ReadUInt64() != packSize) + isOK = false; + size = 0; + } + else + { + if (ZIP64_IS_32_MAX(unpackSize)) + { if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }} + + if (isOK && ZIP64_IS_32_MAX(packSize)) + { if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }} + + if (cdItem) + { + if (isOK) + { + if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) + { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} + /* + else if (size == 8) + { + size -= 8; + const UInt64 v = ReadUInt64(); + // soong_zip, an AOSP tool (written in the Go) writes incorrect value. + // we can ignore that minor error here + if (v != cdItem->LocalHeaderPos) + isOK = false; // ignore error + // isOK = false; // force error + } + */ + } + + if (isOK && ZIP64_IS_16_MAX(cdItem->Disk)) + { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }} + } + } + + // we can ignore errors, when some zip archiver still write all fields to zip64 extra in local header + // if (&& (cdItem || !isOK || origSize != 8 * 3 + 4 || size != 8 * 1 + 4)) + if (!isOK || size != 0) + { + HeadersWarning = true; + extra.Error = true; + extra.IsZip64_Error = true; + } + Skip(size); + } + else + { + ReadBuffer(subBlock.Data, size); + extra.SubBlocks.Add(subBlock); + if (subBlock.ID == NFileHeader::NExtraID::kIzUnicodeName) + { + if (!subBlock.CheckIzUnicode(item.Name)) + extra.Error = true; + } + } + } + + if (extraSize != 0) + { + ExtraMinorError = true; + extra.MinorError = true; + // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers. + // so we don't return false, but just set warning flag + // return false; + Skip(extraSize); + } + + return true; +} + + +bool CInArchive::ReadLocalItem(CItemEx &item) +{ + item.Disk = 0; + if (IsMultiVol && Vols.StreamIndex >= 0) + item.Disk = (UInt32)Vols.StreamIndex; + const unsigned kPureHeaderSize = kLocalHeaderSize - 4; + Byte p[kPureHeaderSize]; + SafeRead(p, kPureHeaderSize); + { + unsigned i; + for (i = 0; i < kPureHeaderSize && p[i] == 0; i++); + if (i == kPureHeaderSize) + return false; + } + + item.ExtractVersion.Version = p[0]; + item.ExtractVersion.HostOS = p[1]; + G16(2, item.Flags); + G16(4, item.Method); + G32(6, item.Time); + G32(10, item.Crc); + G32(14, item.PackSize); + G32(18, item.Size); + const unsigned nameSize = Get16(p + 22); + const unsigned extraSize = Get16(p + 24); + bool isOkName = ReadFileName(nameSize, item.Name); + item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize; + item.DescriptorWasRead = false; + + /* + if (item.IsDir()) + item.Size = 0; // check It + */ + + if (extraSize > 0) + { + if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, NULL)) + { + /* Most of archives are OK for Extra. But there are some rare cases + that have error. And if error in first item, it can't open archive. + So we ignore that error */ + // return false; + } + } + + if (!CheckDosTime(item.Time)) + { + HeadersWarning = true; + // return false; + } + + if (item.Name.Len() != nameSize) + { + // we support some "bad" zip archives that contain zeros after name + if (!isOkName) + return false; + HeadersWarning = true; + } + + // return item.LocalFullHeaderSize <= ((UInt32)1 << 16); + return true; +} + + +static bool FlagsAreSame(const CItem &i1, const CItem &i2_cd) +{ + if (i1.Method != i2_cd.Method) + return false; + + UInt32 mask = i1.Flags ^ i2_cd.Flags; + if (mask == 0) + return true; + switch (i1.Method) + { + case NFileHeader::NCompressionMethod::kDeflate: + mask &= 0x7FF9; + break; + default: + if (i1.Method <= NFileHeader::NCompressionMethod::kImplode) + mask &= 0x7FFF; + } + + // we can ignore utf8 flag, if name is ascii, or if only cdItem has utf8 flag + if (mask & NFileHeader::NFlags::kUtf8) + if ((i1.Name.IsAscii() && i2_cd.Name.IsAscii()) + || (i2_cd.Flags & NFileHeader::NFlags::kUtf8)) + mask &= ~NFileHeader::NFlags::kUtf8; + + // some bad archive in rare case can use descriptor without descriptor flag in Central Dir + // if (i1.HasDescriptor()) + mask &= ~NFileHeader::NFlags::kDescriptorUsedMask; + + return (mask == 0); +} + + +// #ifdef _WIN32 +static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2) +{ + for (;;) + { + char c1 = *s1++; + char c2 = *s2++; + if (c1 == c2) + { + if (c1 == 0) + return true; + } + else + { + if (c1 == '\\') c1 = '/'; + if (c2 == '\\') c2 = '/'; + if (c1 != c2) + return false; + } + } +} +// #endif + + +static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem) +{ + if (!FlagsAreSame(localItem, cdItem)) + return false; + if (!localItem.HasDescriptor()) + { + if (cdItem.PackSize != localItem.PackSize + || cdItem.Size != localItem.Size + || (cdItem.Crc != localItem.Crc && cdItem.Crc != 0)) // some program writes 0 to crc field in central directory + return false; + } + /* pkzip 2.50 creates incorrect archives. It uses + - WIN encoding for name in local header + - OEM encoding for name in central header + We don't support these strange items. */ + + /* if (cdItem.Name.Len() != localItem.Name.Len()) + return false; + */ + if (cdItem.Name != localItem.Name) + { + // #ifdef _WIN32 + // some xap files use backslash in central dir items. + // we can ignore such errors in windows, where all slashes are converted to backslashes + unsigned hostOs = cdItem.GetHostOS(); + + if (hostOs == NFileHeader::NHostOS::kFAT || + hostOs == NFileHeader::NHostOS::kNTFS) + { + if (!AreEqualPaths_IgnoreSlashes(cdItem.Name, localItem.Name)) + { + // pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header. + // so we ignore that error + if (hostOs != NFileHeader::NHostOS::kFAT + || cdItem.MadeByVersion.Version < 25 + || cdItem.MadeByVersion.Version > 40) + return false; + } + } + /* + else + #endif + return false; + */ + } + return true; +} + + +HRESULT CInArchive::Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError) +{ + isAvail = true; + headersError = false; + if (item.FromLocal) + return S_OK; + try + { + UInt64 offset = item.LocalHeaderPos; + + if (IsMultiVol) + { + if (item.Disk >= Vols.Streams.Size()) + { + isAvail = false; + return S_FALSE; + } + Stream = Vols.Streams[item.Disk].Stream; + Vols.StreamIndex = (int)item.Disk; + if (!Stream) + { + isAvail = false; + return S_FALSE; + } + } + else + { + if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex) + { + isAvail = false; + return S_FALSE; + } + Stream = StreamRef; + + offset = (UInt64)((Int64)offset + ArcInfo.Base); + if (ArcInfo.Base < 0 && (Int64)offset < 0) + { + isAvail = false; + return S_FALSE; + } + } + + _inBufMode = false; + RINOK(Seek_SavePos(offset)) + InitBuf(); + /* + // we can use buf mode with small buffer to reduce + // the number of Read() calls in ReadLocalItem() + _inBufMode = true; + Buffer.Alloc(1 << 10); + if (!Buffer.IsAllocated()) + return E_OUTOFMEMORY; + */ + + CItemEx localItem; + if (ReadUInt32() != NSignature::kLocalFileHeader) + return S_FALSE; + ReadLocalItem(localItem); + if (!AreItemsEqual(localItem, item)) + return S_FALSE; + item.LocalFullHeaderSize = localItem.LocalFullHeaderSize; + item.LocalExtra = localItem.LocalExtra; + if (item.Crc != localItem.Crc && !localItem.HasDescriptor()) + { + item.Crc = localItem.Crc; + headersError = true; + } + if ((item.Flags ^ localItem.Flags) & NFileHeader::NFlags::kDescriptorUsedMask) + { + item.Flags = (UInt16)(item.Flags ^ NFileHeader::NFlags::kDescriptorUsedMask); + headersError = true; + } + item.FromLocal = true; + } + catch(...) { return S_FALSE; } + return S_OK; +} + + +/* +---------- FindDescriptor ---------- + +in: + _streamPos : position in Stream + Stream : + Vols : if (IsMultiVol) + +action: + searches descriptor in input stream(s). + sets + item.DescriptorWasRead = true; + item.Size + item.PackSize + item.Crc + if descriptor was found + +out: + S_OK: + if ( item.DescriptorWasRead) : if descriptor was found + if (!item.DescriptorWasRead) : if descriptor was not found : unexpected end of stream(s) + + S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive. + + another error code: Callback error. + +exceptions : + CSystemException() : stream reading error +*/ + +HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles) +{ + // const size_t kBufSize = (size_t)1 << 5; // don't increase it too much. It reads data look ahead. + + // Buffer.Alloc(kBufSize); + // Byte *buf = Buffer; + + UInt64 packedSize = 0; + + UInt64 progressPrev = _cnt; + + for (;;) + { + /* appnote specification claims that we must use 64-bit descriptor, if there is zip64 extra. + But some old third-party xps archives used 64-bit descriptor without zip64 extra. */ + // unsigned descriptorSize = kDataDescriptorSize64 + kNextSignatureSize; + + // const unsigned kNextSignatureSize = 0; // we can disable check for next signatuire + const unsigned kNextSignatureSize = 4; // we check also for signature for next File headear + + const unsigned descriptorSize4 = item.GetDescriptorSize() + kNextSignatureSize; + + if (descriptorSize4 > Buffer.Size()) return E_FAIL; + + // size_t processedSize; + CanStartNewVol = true; + RINOK(LookAhead(descriptorSize4)) + const size_t avail = GetAvail(); + + if (avail < descriptorSize4) + { + // we write to packSize all these available bytes. + // later it's simpler to work with such value than with 0 + // if (item.PackSize == 0) + item.PackSize = packedSize + avail; + if (item.Method == 0) + item.Size = item.PackSize; + SkipLookahed(avail); + return S_OK; + } + + const Byte * const pStart = Buffer + _bufPos; + const Byte * p = pStart; + const Byte * const limit = pStart + (avail - descriptorSize4); + + for (; p <= limit; p++) + { + // descriptor signature field is Info-ZIP's extension to pkware Zip specification. + // New ZIP specification also allows descriptorSignature. + + p = FindPK_4(p, limit + 1); + if (p > limit) + break; + + /* + if (*p != 0x50) + continue; + */ + + if (Get32(p) != NSignature::kDataDescriptor) + continue; + + // we check next signatuire after descriptor + // maybe we need check only 2 bytes "PK" instead of 4 bytes, if some another type of header is possible after descriptor + const UInt32 sig = Get32(p + descriptorSize4 - kNextSignatureSize); + if ( sig != NSignature::kLocalFileHeader + && sig != NSignature::kCentralFileHeader) + continue; + + const UInt64 packSizeCur = packedSize + (size_t)(p - pStart); + if (descriptorSize4 == kDataDescriptorSize64 + kNextSignatureSize) // if (item.LocalExtra.IsZip64) + { + const UInt64 descriptorPackSize = Get64(p + 8); + if (descriptorPackSize != packSizeCur) + continue; + item.Size = Get64(p + 16); + } + else + { + const UInt32 descriptorPackSize = Get32(p + 8); + if (descriptorPackSize != (UInt32)packSizeCur) + continue; + item.Size = Get32(p + 12); + // that item.Size can be truncated to 32-bit value here + } + // We write calculated 64-bit packSize, even if descriptor64 was not used + item.PackSize = packSizeCur; + + item.DescriptorWasRead = true; + item.Crc = Get32(p + 4); + + const size_t skip = (size_t)(p - pStart) + descriptorSize4 - kNextSignatureSize; + + SkipLookahed(skip); + + return S_OK; + } + + const size_t skip = (size_t)(p - pStart); + SkipLookahed(skip); + + packedSize += skip; + + if (Callback) + if (_cnt - progressPrev >= ((UInt32)1 << 22)) + { + progressPrev = _cnt; + const UInt64 numFiles64 = numFiles; + RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) + } + } +} + + +HRESULT CInArchive::CheckDescriptor(const CItemEx &item) +{ + if (!item.HasDescriptor()) + return S_OK; + + // pkzip's version without descriptor signature is not supported + + bool isFinished = false; + RINOK(IncreaseRealPosition(item.PackSize, isFinished)) + if (isFinished) + return S_FALSE; + + /* + if (!IsMultiVol) + { + RINOK(Seek_SavePos(ArcInfo.Base + item.GetDataPosition() + item.PackSize)); + } + */ + + Byte buf[kDataDescriptorSize64]; + try + { + CanStartNewVol = true; + SafeRead(buf, item.GetDescriptorSize()); + } + catch (const CSystemException &e) { return e.ErrorCode; } + // catch (const CUnexpectEnd &) + catch(...) + { + return S_FALSE; + } + // RINOK(ReadStream_FALSE(Stream, buf, item.GetDescriptorSize())); + + if (Get32(buf) != NSignature::kDataDescriptor) + return S_FALSE; + UInt32 crc = Get32(buf + 4); + UInt64 packSize, unpackSize; + + if (item.LocalExtra.IsZip64) + { + packSize = Get64(buf + 8); + unpackSize = Get64(buf + 16); + } + else + { + packSize = Get32(buf + 8); + unpackSize = Get32(buf + 12); + } + + if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize) + return S_FALSE; + return S_OK; +} + + +HRESULT CInArchive::Read_LocalItem_After_CdItem_Full(CItemEx &item) +{ + if (item.FromLocal) + return S_OK; + try + { + bool isAvail = true; + bool headersError = false; + RINOK(Read_LocalItem_After_CdItem(item, isAvail, headersError)) + if (headersError) + return S_FALSE; + if (item.HasDescriptor()) + return CheckDescriptor(item); + } + catch(...) { return S_FALSE; } + return S_OK; +} + + +HRESULT CInArchive::ReadCdItem(CItemEx &item) +{ + item.FromCentral = true; + Byte p[kCentralHeaderSize - 4]; + SafeRead(p, kCentralHeaderSize - 4); + + item.MadeByVersion.Version = p[0]; + item.MadeByVersion.HostOS = p[1]; + item.ExtractVersion.Version = p[2]; + item.ExtractVersion.HostOS = p[3]; + G16(4, item.Flags); + G16(6, item.Method); + G32(8, item.Time); + G32(12, item.Crc); + G32(16, item.PackSize); + G32(20, item.Size); + const unsigned nameSize = Get16(p + 24); + const unsigned extraSize = Get16(p + 26); + const unsigned commentSize = Get16(p + 28); + G16(30, item.Disk); + G16(32, item.InternalAttrib); + G32(34, item.ExternalAttrib); + G32(38, item.LocalHeaderPos); + ReadFileName(nameSize, item.Name); + + if (extraSize > 0) + ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, &item); + + // May be these strings must be deleted + /* + if (item.IsDir()) + item.Size = 0; + */ + + ReadBuffer(item.Comment, commentSize); + return S_OK; +} + + +/* +TryEcd64() + (_inBufMode == false) is expected here + so TryEcd64() can't change the Buffer. + if (Ecd64 is not covered by cached region), + TryEcd64() can change cached region ranges (_bufCached, _bufPos) and _streamPos. +*/ + +HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo) +{ + if (offset >= ((UInt64)1 << 63)) + return S_FALSE; + Byte buf[kEcd64_FullSize]; + + RINOK(SeekToVol(Vols.StreamIndex, offset)) + RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize)) + + if (Get32(buf) != NSignature::kEcd64) + return S_FALSE; + UInt64 mainSize = Get64(buf + 4); + if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 40)) + return S_FALSE; + cdInfo.ParseEcd64e(buf + 12); + return S_OK; +} + + +/* FindCd() doesn't use previous cached region, + but it uses Buffer. So it sets new cached region */ + +HRESULT CInArchive::FindCd(bool checkOffsetMode) +{ + CCdInfo &cdInfo = Vols.ecd; + + UInt64 endPos; + + // There are no useful data in cache in most cases here. + // So here we don't use cache data from previous operations . + + InitBuf(); + RINOK(InStream_GetSize_SeekToEnd(Stream, endPos)) + _streamPos = endPos; + + // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize; + const size_t kBufSizeMax = ((size_t)1 << 17); // must be larger than kBufSizeMax2 + + const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax; + if (bufSize < kEcdSize) + return S_FALSE; + // CByteArr byteBuffer(bufSize); + + RINOK(AllocateBuffer(kBufSizeMax)) + + RINOK(Seek_SavePos(endPos - bufSize)) + + size_t processed = bufSize; + HRESULT res = ReadStream(Stream, Buffer, &processed); + _streamPos += processed; + _bufCached = processed; + _bufPos = 0; + _cnt += processed; + if (res != S_OK) + return res; + if (processed != bufSize) + return S_FALSE; + + + for (size_t i = bufSize - kEcdSize + 1;;) + { + if (i == 0) + return S_FALSE; + + const Byte *buf = Buffer; + + for (;;) + { + i--; + if (buf[i] == 0x50) + break; + if (i == 0) + return S_FALSE; + } + + if (Get32(buf + i) != NSignature::kEcd) + continue; + + cdInfo.ParseEcd32(buf + i); + + if (i >= kEcd64Locator_Size) + { + const size_t locatorIndex = i - kEcd64Locator_Size; + if (Get32(buf + locatorIndex) == NSignature::kEcd64Locator) + { + CLocator locator; + locator.Parse(buf + locatorIndex + 4); + UInt32 numDisks = locator.NumDisks; + // we ignore the error, where some zip creators use (NumDisks == 0) + if (numDisks == 0) + numDisks = 1; + if ((cdInfo.ThisDisk == numDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk)) + && locator.Ecd64Disk < numDisks) + { + if (locator.Ecd64Disk != cdInfo.ThisDisk && !ZIP64_IS_16_MAX(cdInfo.ThisDisk)) + return E_NOTIMPL; + + // Most of the zip64 use fixed size Zip64 ECD + // we try relative backward reading. + + UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize); + + if (locatorIndex >= kEcd64_FullSize) + if (checkOffsetMode || absEcd64 == locator.Ecd64Offset) + { + const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize; + if (Get32(ecd64) == NSignature::kEcd64) + { + UInt64 mainEcd64Size = Get64(ecd64 + 4); + if (mainEcd64Size == kEcd64_MainSize) + { + cdInfo.ParseEcd64e(ecd64 + 12); + ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset); + // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; + return S_OK; + } + } + } + + // some zip64 use variable size Zip64 ECD. + // we try to use absolute offset from locator. + + if (absEcd64 != locator.Ecd64Offset) + { + if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK) + { + ArcInfo.Base = 0; + // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; + return S_OK; + } + } + + // for variable Zip64 ECD with for archives with offset != 0. + + if (checkOffsetMode + && ArcInfo.MarkerPos != 0 + && ArcInfo.MarkerPos + locator.Ecd64Offset != absEcd64) + { + if (TryEcd64(ArcInfo.MarkerPos + locator.Ecd64Offset, cdInfo) == S_OK) + { + ArcInfo.Base = (Int64)ArcInfo.MarkerPos; + // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; + return S_OK; + } + } + } + } + } + + // bool isVolMode = (Vols.EndVolIndex != -1); + // UInt32 searchDisk = (isVolMode ? Vols.EndVolIndex : 0); + + if (/* searchDisk == thisDisk && */ cdInfo.CdDisk <= cdInfo.ThisDisk) + { + // if (isVolMode) + { + if (cdInfo.CdDisk != cdInfo.ThisDisk) + return S_OK; + } + + UInt64 absEcdPos = endPos - bufSize + i; + UInt64 cdEnd = cdInfo.Size + cdInfo.Offset; + ArcInfo.Base = 0; + // ArcInfo.BaseVolIndex = cdInfo.ThisDisk; + if (absEcdPos != cdEnd) + { + /* + if (cdInfo.Offset <= 16 && cdInfo.Size != 0) + { + // here we support some rare ZIP files with Central directory at the start + ArcInfo.Base = 0; + } + else + */ + ArcInfo.Base = (Int64)(absEcdPos - cdEnd); + } + return S_OK; + } + } +} + + +HRESULT CInArchive::TryReadCd(CObjectVector &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize) +{ + items.Clear(); + IsCdUnsorted = false; + + // _startLocalFromCd_Disk = (UInt32)(Int32)-1; + // _startLocalFromCd_Offset = (UInt64)(Int64)-1; + + RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset)) + + _inBufMode = true; + _cnt = 0; + + if (Callback) + { + RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL)) + } + UInt64 numFileExpected = cdInfo.NumEntries; + const UInt64 *totalFilesPtr = &numFileExpected; + bool isCorrect_NumEntries = (cdInfo.IsFromEcd64 || numFileExpected >= ((UInt32)1 << 16)); + + while (_cnt < cdSize) + { + CanStartNewVol = true; + if (ReadUInt32() != NSignature::kCentralFileHeader) + return S_FALSE; + CanStartNewVol = false; + { + CItemEx cdItem; + RINOK(ReadCdItem(cdItem)) + + /* + if (cdItem.Disk < _startLocalFromCd_Disk || + cdItem.Disk == _startLocalFromCd_Disk && + cdItem.LocalHeaderPos < _startLocalFromCd_Offset) + { + _startLocalFromCd_Disk = cdItem.Disk; + _startLocalFromCd_Offset = cdItem.LocalHeaderPos; + } + */ + + if (items.Size() > 0 && !IsCdUnsorted) + { + const CItemEx &prev = items.Back(); + if (cdItem.Disk < prev.Disk + || (cdItem.Disk == prev.Disk && + cdItem.LocalHeaderPos < prev.LocalHeaderPos)) + IsCdUnsorted = true; + } + + items.Add(cdItem); + } + if (Callback && (items.Size() & 0xFFF) == 0) + { + const UInt64 numFiles = items.Size(); + + if (numFiles > numFileExpected && totalFilesPtr) + { + if (isCorrect_NumEntries) + totalFilesPtr = NULL; + else + while (numFiles > numFileExpected) + numFileExpected += (UInt32)1 << 16; + RINOK(Callback->SetTotal(totalFilesPtr, NULL)) + } + + RINOK(Callback->SetCompleted(&numFiles, &_cnt)) + } + } + + CanStartNewVol = true; + + return (_cnt == cdSize) ? S_OK : S_FALSE; +} + + +/* +static int CompareCdItems(void *const *elem1, void *const *elem2, void *) +{ + const CItemEx *i1 = *(const CItemEx **)elem1; + const CItemEx *i2 = *(const CItemEx **)elem2; + + if (i1->Disk < i2->Disk) return -1; + if (i1->Disk > i2->Disk) return 1; + if (i1->LocalHeaderPos < i2->LocalHeaderPos) return -1; + if (i1->LocalHeaderPos > i2->LocalHeaderPos) return 1; + if (i1 < i2) return -1; + if (i1 > i2) return 1; + return 0; +} +*/ + +HRESULT CInArchive::ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize) +{ + bool checkOffsetMode = true; + + if (IsMultiVol) + { + if (Vols.EndVolIndex == -1) + return S_FALSE; + Stream = Vols.Streams[(unsigned)Vols.EndVolIndex].Stream; + if (!Vols.StartIsZip) + checkOffsetMode = false; + } + else + Stream = StartStream; + + if (!Vols.ecd_wasRead) + { + RINOK(FindCd(checkOffsetMode)) + } + + CCdInfo &cdInfo = Vols.ecd; + + HRESULT res = S_FALSE; + + cdSize = cdInfo.Size; + cdOffset = cdInfo.Offset; + cdDisk = cdInfo.CdDisk; + + if (!IsMultiVol) + { + if (cdInfo.ThisDisk != cdInfo.CdDisk) + return S_FALSE; + } + + const UInt64 base = (IsMultiVol ? 0 : (UInt64)ArcInfo.Base); + res = TryReadCd(items, cdInfo, base + cdOffset, cdSize); + + if (res == S_FALSE && !IsMultiVol && base != ArcInfo.MarkerPos) + { + // do we need that additional attempt to read cd? + res = TryReadCd(items, cdInfo, ArcInfo.MarkerPos + cdOffset, cdSize); + if (res == S_OK) + ArcInfo.Base = (Int64)ArcInfo.MarkerPos; + } + + // Some rare case files are unsorted + // items.Sort(CompareCdItems, NULL); + return res; +} + + +static int FindItem(const CObjectVector &items, const CItemEx &item) +{ + unsigned left = 0, right = items.Size(); + for (;;) + { + if (left >= right) + return -1; + const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2); + const CItemEx &item2 = items[index]; + if (item.Disk < item2.Disk) + right = index; + else if (item.Disk > item2.Disk) + left = index + 1; + else if (item.LocalHeaderPos == item2.LocalHeaderPos) + return (int)index; + else if (item.LocalHeaderPos < item2.LocalHeaderPos) + right = index; + else + left = index + 1; + } +} + +static bool IsStrangeItem(const CItem &item) +{ + return item.Name.Len() > (1 << 14) || item.Method > (1 << 8); +} + + + +/* + ---------- ReadLocals ---------- + +in: + (_signature == NSignature::kLocalFileHeader) + VirtStreamPos : after _signature : position in Stream + Stream : + Vols : if (IsMultiVol) + (_inBufMode == false) + +action: + it parses local items. + + if ( IsMultiVol) it writes absolute offsets to CItemEx::LocalHeaderPos + if (!IsMultiVol) it writes relative (from ArcInfo.Base) offsets to CItemEx::LocalHeaderPos + later we can correct CItemEx::LocalHeaderPos values, if + some new value for ArcInfo.Base will be detected +out: + S_OK: + (_signature != NSignature::kLocalFileHeade) + _streamPos : after _signature + + S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive. + + another error code: stream reading error or Callback error. + + CUnexpectEnd() exception : it's not fatal exception here. + It means that reading was interrupted by unexpected end of input stream, + but some CItemEx items were parsed OK. + We can stop further archive parsing. + But we can use all filled CItemEx items. +*/ + +HRESULT CInArchive::ReadLocals(CObjectVector &items) +{ + items.Clear(); + + UInt64 progressPrev = _cnt; + + if (Callback) + { + RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL)) + } + + while (_signature == NSignature::kLocalFileHeader) + { + CItemEx item; + + item.LocalHeaderPos = GetVirtStreamPos() - 4; + if (!IsMultiVol) + item.LocalHeaderPos = (UInt64)((Int64)item.LocalHeaderPos - ArcInfo.Base); + + try + { + ReadLocalItem(item); + item.FromLocal = true; + bool isFinished = false; + + if (item.HasDescriptor()) + { + RINOK(FindDescriptor(item, items.Size())) + isFinished = !item.DescriptorWasRead; + } + else + { + if (item.PackSize >= ((UInt64)1 << 62)) + throw CUnexpectEnd(); + RINOK(IncreaseRealPosition(item.PackSize, isFinished)) + } + + items.Add(item); + + if (isFinished) + throw CUnexpectEnd(); + + ReadSignature(); + } + catch (CUnexpectEnd &) + { + if (items.IsEmpty() || (items.Size() == 1 && IsStrangeItem(items[0]))) + return S_FALSE; + throw; + } + + + if (Callback) + if ((items.Size() & 0xFF) == 0 + || _cnt - progressPrev >= ((UInt32)1 << 22)) + { + progressPrev = _cnt; + const UInt64 numFiles = items.Size(); + RINOK(Callback->SetCompleted(&numFiles, &_cnt)) + } + } + + if (items.Size() == 1 && _signature != NSignature::kCentralFileHeader) + if (IsStrangeItem(items[0])) + return S_FALSE; + + return S_OK; +} + + + +HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback) +{ + UString name; + { + NWindows::NCOM::CPropVariant prop; + RINOK(volCallback->GetProperty(kpidName, &prop)) + if (prop.vt != VT_BSTR) + return S_OK; + name = prop.bstrVal; + } + + const int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0) + return S_OK; + const UString ext = name.Ptr((unsigned)(dotPos + 1)); + name.DeleteFrom((unsigned)(dotPos + 1)); + + StartVolIndex = (Int32)(-1); + + if (ext.IsEmpty()) + return S_OK; + { + wchar_t c = ext[0]; + IsUpperCase = (c >= 'A' && c <= 'Z'); + if (ext.IsEqualTo_Ascii_NoCase("zip")) + { + BaseName = name; + StartIsZ = true; + StartIsZip = true; + return S_OK; + } + else if (ext.IsEqualTo_Ascii_NoCase("exe")) + { + /* possible cases: + - exe with zip inside + - sfx: a.exe, a.z02, a.z03,... , a.zip + a.exe is start volume. + - zip renamed to exe + */ + + StartIsExe = true; + BaseName = name; + StartVolIndex = 0; + /* sfx-zip can use both arc.exe and arc.zip + We can open arc.zip, if it was requesed to open arc.exe. + But it's possible that arc.exe and arc.zip are not parts of same archive. + So we can disable such operation */ + + // 18.04: we still want to open zip renamed to exe. + /* + { + UString volName = name; + volName += IsUpperCase ? "Z01" : "z01"; + { + CMyComPtr stream; + HRESULT res2 = volCallback->GetStream(volName, &stream); + if (res2 == S_OK) + DisableVolsSearch = true; + } + } + */ + DisableVolsSearch = true; + return S_OK; + } + else if (ext[0] == 'z' || ext[0] == 'Z') + { + if (ext.Len() < 3) + return S_OK; + const wchar_t *end = NULL; + UInt32 volNum = ConvertStringToUInt32(ext.Ptr(1), &end); + if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30)) + return S_OK; + StartVolIndex = (Int32)(volNum - 1); + BaseName = name; + StartIsZ = true; + } + else + return S_OK; + } + + UString volName = BaseName; + volName += (IsUpperCase ? "ZIP" : "zip"); + + HRESULT res = volCallback->GetStream(volName, &ZipStream); + + if (res == S_FALSE || !ZipStream) + { + if (MissingName.IsEmpty()) + { + MissingZip = true; + MissingName = volName; + } + return S_OK; + } + + return res; +} + + +HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback, + unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols) +{ + if (Vols.DisableVolsSearch) + return S_OK; + + numMissingVols = 0; + + for (unsigned i = start;; i++) + { + if (lastDisk >= 0 && i >= (unsigned)lastDisk) + break; + + if (i < Vols.Streams.Size()) + if (Vols.Streams[i].Stream) + continue; + + CMyComPtr stream; + + if ((int)i == zipDisk) + { + stream = Vols.ZipStream; + } + else if ((int)i == Vols.StartVolIndex) + { + stream = StartStream; + } + else + { + UString volName = Vols.BaseName; + { + volName.Add_Char(Vols.IsUpperCase ? 'Z' : 'z'); + const unsigned v = i + 1; + if (v < 10) + volName.Add_Char('0'); + volName.Add_UInt32(v); + } + + HRESULT res = volCallback->GetStream(volName, &stream); + if (res != S_OK && res != S_FALSE) + return res; + if (res == S_FALSE || !stream) + { + if (i == 0) + { + UString volName_exe = Vols.BaseName; + volName_exe += (Vols.IsUpperCase ? "EXE" : "exe"); + + HRESULT res2 = volCallback->GetStream(volName_exe, &stream); + if (res2 != S_OK && res2 != S_FALSE) + return res2; + res = res2; + } + } + if (res == S_FALSE || !stream) + { + if (i == 1 && Vols.StartIsExe) + return S_OK; + if (Vols.MissingName.IsEmpty()) + Vols.MissingName = volName; + numMissingVols++; + if (numMissingVols > numMissingVolsMax) + return S_OK; + if (lastDisk == -1 && numMissingVols != 0) + return S_OK; + continue; + } + } + + UInt64 pos, size; + RINOK(InStream_GetPos_GetSize(stream, pos, size)) + + while (i >= Vols.Streams.Size()) + Vols.Streams.AddNew(); + + CVols::CSubStreamInfo &ss = Vols.Streams[i]; + Vols.NumVols++; + Vols.TotalBytesSize += size; + + ss.Stream = stream; + ss.Size = size; + + if ((int)i == zipDisk) + { + Vols.EndVolIndex = (int)(Vols.Streams.Size() - 1); + break; + } + } + + return S_OK; +} + + +HRESULT CInArchive::ReadVols() +{ + CMyComPtr volCallback; + + Callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volCallback); + if (!volCallback) + return S_OK; + + RINOK(Vols.ParseArcName(volCallback)) + + // const int startZIndex = Vols.StartVolIndex; + + if (!Vols.StartIsZ) + { + if (!Vols.StartIsExe) + return S_OK; + } + + int zipDisk = -1; + int cdDisk = -1; + + if (Vols.StartIsZip) + Vols.ZipStream = StartStream; + + if (Vols.ZipStream) + { + Stream = Vols.ZipStream; + + if (Vols.StartIsZip) + Vols.StreamIndex = -1; + else + { + Vols.StreamIndex = -2; + InitBuf(); + } + + HRESULT res = FindCd(true); + + CCdInfo &ecd = Vols.ecd; + if (res == S_OK) + { + zipDisk = (int)ecd.ThisDisk; + Vols.ecd_wasRead = true; + + // if is not multivol or bad multivol, we return to main single stream code + if (ecd.ThisDisk == 0 + || ecd.ThisDisk >= ((UInt32)1 << 30) + || ecd.ThisDisk < ecd.CdDisk) + return S_OK; + + cdDisk = (int)ecd.CdDisk; + if (Vols.StartVolIndex < 0) + Vols.StartVolIndex = (Int32)ecd.ThisDisk; + else if ((UInt32)Vols.StartVolIndex >= ecd.ThisDisk) + return S_OK; + + // Vols.StartVolIndex = ecd.ThisDisk; + // Vols.EndVolIndex = ecd.ThisDisk; + unsigned numMissingVols; + if (cdDisk != zipDisk) + { + // get volumes required for cd. + RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols)) + if (numMissingVols != 0) + { + // cdOK = false; + } + } + } + else if (res != S_FALSE) + return res; + } + + if (Vols.StartVolIndex < 0) + { + // is not mutivol; + return S_OK; + } + + /* + if (!Vols.Streams.IsEmpty()) + IsMultiVol = true; + */ + + unsigned numMissingVols; + + if (cdDisk != 0) + { + // get volumes that were no requested still + const unsigned kNumMissingVolsMax = 1 << 12; + RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols)) + } + + // if (Vols.StartVolIndex >= 0) + { + if (Vols.Streams.IsEmpty()) + if (Vols.StartVolIndex > (1 << 20)) + return S_OK; + if ((unsigned)Vols.StartVolIndex >= Vols.Streams.Size() + || !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream) + { + // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok) + RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols)) + } + } + + if (Vols.ZipStream) + { + // if there is no another volumes and volumeIndex is too big, we don't use multivol mode + if (Vols.Streams.IsEmpty()) + if (zipDisk > (1 << 10)) + return S_OK; + if (zipDisk >= 0) + { + // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok) + RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols)) + } + } + + if (!Vols.Streams.IsEmpty()) + { + IsMultiVol = true; + /* + if (cdDisk) + IsMultiVol = true; + */ + const int startZIndex = Vols.StartVolIndex; + if (startZIndex >= 0) + { + // if all volumes before start volume are OK, we can start parsing from 0 + // if there are missing volumes before startZIndex, we start parsing in current startZIndex + if ((unsigned)startZIndex < Vols.Streams.Size()) + { + for (unsigned i = 0; i <= (unsigned)startZIndex; i++) + if (!Vols.Streams[i].Stream) + { + Vols.StartParsingVol = startZIndex; + break; + } + } + } + } + + return S_OK; +} + + + +HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + + for (;;) + { + if (StreamIndex < 0) + return S_OK; + if ((unsigned)StreamIndex >= Streams.Size()) + return S_OK; + const CVols::CSubStreamInfo &s = Streams[(unsigned)StreamIndex]; + if (!s.Stream) + return S_FALSE; + if (NeedSeek) + { + RINOK(s.SeekToStart()) + NeedSeek = false; + } + UInt32 realProcessedSize = 0; + HRESULT res = s.Stream->Read(data, size, &realProcessedSize); + if (processedSize) + *processedSize = realProcessedSize; + if (res != S_OK) + return res; + if (realProcessedSize != 0) + return res; + StreamIndex++; + NeedSeek = true; + } +} + +Z7_COM7F_IMF(CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + return Vols->Read(data, size, processedSize); +} + + + + +#define COPY_ECD_ITEM_16(n) if (!isZip64 || !ZIP64_IS_16_MAX(ecd. n)) cdInfo. n = ecd. n; +#define COPY_ECD_ITEM_32(n) if (!isZip64 || !ZIP64_IS_32_MAX(ecd. n)) cdInfo. n = ecd. n; + + +HRESULT CInArchive::ReadHeaders(CObjectVector &items) +{ + // buffer that can be used for cd reading + RINOK(AllocateBuffer(kSeqBufferSize)) + + // here we can read small records. So we switch off _inBufMode. + _inBufMode = false; + + HRESULT res = S_OK; + + bool localsWereRead = false; + + /* we try to open archive with the following modes: + 1) CD-MODE : fast mode : we read backward ECD and CD, compare CD items with first Local item. + 2) LOCALS-CD-MODE : slow mode, if CD-MODE fails : we sequentially read all Locals and then CD. + Then we read sequentially ECD64, Locator, ECD again at the end. + + - in LOCALS-CD-MODE we use use the following + variables (with real cd properties) to set Base archive offset + and check real cd properties with values from ECD/ECD64. + */ + + UInt64 cdSize = 0; + UInt64 cdRelatOffset = 0; + UInt32 cdDisk = 0; + + UInt64 cdAbsOffset = 0; // absolute cd offset, for LOCALS-CD-MODE only. + +if (Force_ReadLocals_Mode) +{ + IsArc = true; + res = S_FALSE; // we will use LOCALS-CD-MODE mode +} +else +{ + if (!MarkerIsFound || !MarkerIsSafe) + { + IsArc = true; + res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); + if (res == S_OK) + ReadSignature(); + else if (res != S_FALSE) + return res; + } + else // (MarkerIsFound && MarkerIsSafe) + { + + // _signature must be kLocalFileHeader or kEcd or kEcd64 + + SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2 + 4); + + CanStartNewVol = false; + + if (_signature == NSignature::kEcd64) + { + // UInt64 ecd64Offset = GetVirtStreamPos() - 4; + IsZip64 = true; + + { + const UInt64 recordSize = ReadUInt64(); + if (recordSize < kEcd64_MainSize) + return S_FALSE; + if (recordSize >= ((UInt64)1 << 62)) + return S_FALSE; + + { + const unsigned kBufSize = kEcd64_MainSize; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + CCdInfo cdInfo; + cdInfo.ParseEcd64e(buf); + if (!cdInfo.IsEmptyArc()) + return S_FALSE; + } + + RINOK(Skip64(recordSize - kEcd64_MainSize, 0)) + } + + ReadSignature(); + if (_signature != NSignature::kEcd64Locator) + return S_FALSE; + + { + const unsigned kBufSize = 16; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + CLocator locator; + locator.Parse(buf); + if (!locator.IsEmptyArc()) + return S_FALSE; + } + + ReadSignature(); + if (_signature != NSignature::kEcd) + return S_FALSE; + } + + if (_signature == NSignature::kEcd) + { + // It must be empty archive or backware archive + // we don't support backware archive still + + const unsigned kBufSize = kEcdSize - 4; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + CEcd ecd; + ecd.Parse(buf); + // if (ecd.cdSize != 0) + // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ?? + if (!ecd.IsEmptyArc()) + return S_FALSE; + + ArcInfo.Base = (Int64)ArcInfo.MarkerPos; + IsArc = true; // check it: we need more tests? + + RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)) + ReadSignature(); + } + else + { + CItemEx firstItem; + try + { + try + { + if (!ReadLocalItem(firstItem)) + return S_FALSE; + } + catch(CUnexpectEnd &) + { + return S_FALSE; + } + + IsArc = true; + res = ReadCd(items, cdDisk, cdRelatOffset, cdSize); + if (res == S_OK) + ReadSignature(); + } + catch(CUnexpectEnd &) { res = S_FALSE; } + + if (res != S_FALSE && res != S_OK) + return res; + + if (res == S_OK && items.Size() == 0) + res = S_FALSE; + + if (res == S_OK) + { + // we can't read local items here to keep _inBufMode state + if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base) + res = S_FALSE; + else + { + firstItem.LocalHeaderPos = (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base); + int index = -1; + + UInt32 min_Disk = (UInt32)(Int32)-1; + UInt64 min_LocalHeaderPos = (UInt64)(Int64)-1; + + if (!IsCdUnsorted) + index = FindItem(items, firstItem); + else + { + FOR_VECTOR (i, items) + { + const CItemEx &cdItem = items[i]; + if (cdItem.Disk == firstItem.Disk + && (cdItem.LocalHeaderPos == firstItem.LocalHeaderPos)) + index = (int)i; + + if (i == 0 + || cdItem.Disk < min_Disk + || (cdItem.Disk == min_Disk && cdItem.LocalHeaderPos < min_LocalHeaderPos)) + { + min_Disk = cdItem.Disk; + min_LocalHeaderPos = cdItem.LocalHeaderPos; + } + } + } + + if (index == -1) + res = S_FALSE; + else if (!AreItemsEqual(firstItem, items[(unsigned)index])) + res = S_FALSE; + else + { + ArcInfo.CdWasRead = true; + if (IsCdUnsorted) + ArcInfo.FirstItemRelatOffset = min_LocalHeaderPos; + else + ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos; + + // ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset; + } + } + } + } + } // (MarkerIsFound && MarkerIsSafe) + +} // (!onlyLocalsMode) + + + CObjectVector cdItems; + + bool needSetBase = false; // we set needSetBase only for LOCALS_CD_MODE + unsigned numCdItems = items.Size(); + + #ifdef ZIP_SELF_CHECK + res = S_FALSE; // if uncommented, it uses additional LOCALS-CD-MODE mode to check the code + #endif + + if (res != S_OK) + { + // ---------- LOCALS-CD-MODE ---------- + // CD doesn't match firstItem, + // so we clear items and read Locals and CD. + + items.Clear(); + localsWereRead = true; + + HeadersError = false; + HeadersWarning = false; + ExtraMinorError = false; + + /* we can use any mode: with buffer and without buffer + without buffer : skips packed data : fast for big files : slow for small files + with buffer : reads packed data : slow for big files : fast for small files + Buffer mode is more effective. */ + // _inBufMode = false; + _inBufMode = true; + // we could change the buffer size here, if we want smaller Buffer. + // RINOK(ReAllocateBuffer(kSeqBufferSize)); + // InitBuf() + + ArcInfo.Base = 0; + + if (!Disable_FindMarker) + { + if (!MarkerIsFound) + { + if (!IsMultiVol) + return S_FALSE; + if (Vols.StartParsingVol != 0) + return S_FALSE; + // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker. + // so we suppose that there is no sfx stub + RINOK(SeekToVol(0, ArcInfo.MarkerPos2)) + } + else + { + if (ArcInfo.MarkerPos != 0) + { + /* + If multi-vol or there is (No)Span-marker at start of stream, we set (Base) as 0. + In another caes: + (No)Span-marker is supposed as false positive. So we set (Base) as main marker (MarkerPos2). + The (Base) can be corrected later after ECD reading. + But sfx volume with stub and (No)Span-marker in (!IsMultiVol) mode will have incorrect (Base) here. + */ + ArcInfo.Base = (Int64)ArcInfo.MarkerPos2; + } + RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2)) + } + } + _cnt = 0; + + ReadSignature(); + + LocalsWereRead = true; + + RINOK(ReadLocals(items)) + + if (_signature != NSignature::kCentralFileHeader) + { + // GetVirtStreamPos() - 4 + if (items.IsEmpty()) + return S_FALSE; + + bool isError = true; + + const UInt32 apkSize = _signature; + const unsigned kApkFooterSize = 16 + 8; + if (apkSize >= kApkFooterSize && apkSize <= (1 << 20)) + { + if (ReadUInt32() == 0) + { + CByteBuffer apk; + apk.Alloc(apkSize); + SafeRead(apk, apkSize); + ReadSignature(); + const Byte *footer = apk + apkSize - kApkFooterSize; + if (_signature == NSignature::kCentralFileHeader) + if (GetUi64(footer) == apkSize) + if (memcmp(footer + 8, "APK Sig Block 42", 16) == 0) + { + isError = false; + IsApk = true; + } + } + } + + if (isError) + { + NoCentralDir = true; + HeadersError = true; + return S_OK; + } + } + + _inBufMode = true; + + cdAbsOffset = GetVirtStreamPos() - 4; + cdDisk = (UInt32)Vols.StreamIndex; + + #ifdef ZIP_SELF_CHECK + if (!IsMultiVol && _cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2) + return E_FAIL; + #endif + + const UInt64 processedCnt_start = _cnt; + + for (;;) + { + CItemEx cdItem; + + RINOK(ReadCdItem(cdItem)) + + cdItems.Add(cdItem); + if (Callback && (cdItems.Size() & 0xFFF) == 0) + { + const UInt64 numFiles = items.Size(); + const UInt64 numBytes = _cnt; + RINOK(Callback->SetCompleted(&numFiles, &numBytes)) + } + ReadSignature(); + if (_signature != NSignature::kCentralFileHeader) + break; + } + + cdSize = _cnt - processedCnt_start; + + #ifdef ZIP_SELF_CHECK + if (!IsMultiVol) + { + if (_cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2) + return E_FAIL; + if (cdSize != (GetVirtStreamPos() - 4) - cdAbsOffset) + return E_FAIL; + } + #endif + + needSetBase = true; + numCdItems = cdItems.Size(); + cdRelatOffset = (UInt64)((Int64)cdAbsOffset - ArcInfo.Base); + + if (!cdItems.IsEmpty()) + { + ArcInfo.CdWasRead = true; + ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos; + } + } + + + + CCdInfo cdInfo; + CLocator locator; + bool isZip64 = false; + const UInt64 ecd64AbsOffset = GetVirtStreamPos() - 4; + int ecd64Disk = -1; + + if (_signature == NSignature::kEcd64) + { + ecd64Disk = Vols.StreamIndex; + + IsZip64 = isZip64 = true; + + { + const UInt64 recordSize = ReadUInt64(); + if (recordSize < kEcd64_MainSize + || recordSize >= ((UInt64)1 << 62)) + { + HeadersError = true; + return S_OK; + } + + { + const unsigned kBufSize = kEcd64_MainSize; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + cdInfo.ParseEcd64e(buf); + } + + RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size())) + } + + + ReadSignature(); + + if (_signature != NSignature::kEcd64Locator) + { + HeadersError = true; + return S_OK; + } + + { + const unsigned kBufSize = 16; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + locator.Parse(buf); + // we ignore the error, where some zip creators use (NumDisks == 0) + // if (locator.NumDisks == 0) HeadersWarning = true; + } + + ReadSignature(); + } + + + if (_signature != NSignature::kEcd) + { + HeadersError = true; + return S_OK; + } + + + CanStartNewVol = false; + + // ---------- ECD ---------- + + CEcd ecd; + { + const unsigned kBufSize = kEcdSize - 4; + Byte buf[kBufSize]; + SafeRead(buf, kBufSize); + ecd.Parse(buf); + } + + COPY_ECD_ITEM_16(ThisDisk) + COPY_ECD_ITEM_16(CdDisk) + COPY_ECD_ITEM_16(NumEntries_in_ThisDisk) + COPY_ECD_ITEM_16(NumEntries) + COPY_ECD_ITEM_32(Size) + COPY_ECD_ITEM_32(Offset) + + bool cdOK = true; + + if ((UInt32)cdInfo.Size != (UInt32)cdSize) + { + // return S_FALSE; + cdOK = false; + } + + if (isZip64) + { + if (cdInfo.NumEntries != numCdItems + || cdInfo.Size != cdSize) + { + cdOK = false; + } + } + + + if (IsMultiVol) + { + if (cdDisk != cdInfo.CdDisk) + HeadersError = true; + } + else if (needSetBase && cdOK) + { + const UInt64 oldBase = (UInt64)ArcInfo.Base; + // localsWereRead == true + // ArcInfo.Base == ArcInfo.MarkerPos2 + // cdRelatOffset == (cdAbsOffset - ArcInfo.Base) + + if (isZip64) + { + if (ecd64Disk == Vols.StartVolIndex) + { + const Int64 newBase = (Int64)ecd64AbsOffset - (Int64)locator.Ecd64Offset; + if (newBase <= (Int64)ecd64AbsOffset) + { + if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) + { + ArcInfo.Base = newBase; + cdRelatOffset = (UInt64)((Int64)cdAbsOffset - newBase); + } + else + cdOK = false; + } + } + } + else if (numCdItems != 0) // we can't use ecd.Offset in empty archive? + { + if ((int)cdDisk == Vols.StartVolIndex) + { + const Int64 newBase = (Int64)cdAbsOffset - (Int64)cdInfo.Offset; + if (newBase <= (Int64)cdAbsOffset) + { + if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2) + { + // cd can be more accurate, when it points before Locals + // so we change Base and cdRelatOffset + ArcInfo.Base = newBase; + cdRelatOffset = cdInfo.Offset; + } + else + { + // const UInt64 delta = ((UInt64)cdRelatOffset - cdInfo.Offset); + const UInt64 delta = ((UInt64)(newBase - ArcInfo.Base)); + if ((UInt32)delta == 0) + { + // we set Overflow32bit mode, only if there is (x<<32) offset + // between real_CD_offset_from_MarkerPos and CD_Offset_in_ECD. + // Base and cdRelatOffset unchanged + Overflow32bit = true; + } + else + cdOK = false; + } + } + else + cdOK = false; + } + } + // cdRelatOffset = cdAbsOffset - ArcInfo.Base; + + if (localsWereRead) + { + const UInt64 delta = (UInt64)((Int64)oldBase - ArcInfo.Base); + if (delta != 0) + { + FOR_VECTOR (i, items) + items[i].LocalHeaderPos += delta; + } + } + } + + if (!cdOK) + HeadersError = true; + + EcdVolIndex = cdInfo.ThisDisk; + + if (!IsMultiVol) + { + if (EcdVolIndex == 0 && Vols.MissingZip && Vols.StartIsExe) + { + Vols.MissingName.Empty(); + Vols.MissingZip = false; + } + + if (localsWereRead) + { + if (EcdVolIndex != 0) + { + FOR_VECTOR (i, items) + items[i].Disk = EcdVolIndex; + } + } + + UseDisk_in_SingleVol = true; + } + + if (isZip64) + { + if ((cdInfo.ThisDisk == 0 && ecd64AbsOffset != (UInt64)(ArcInfo.Base + (Int64)locator.Ecd64Offset)) + // || cdInfo.NumEntries_in_ThisDisk != numCdItems + || cdInfo.NumEntries != numCdItems + || cdInfo.Size != cdSize + || (cdInfo.Offset != cdRelatOffset && !items.IsEmpty())) + { + HeadersError = true; + return S_OK; + } + } + + if (cdOK && !cdItems.IsEmpty()) + { + // ---------- merge Central Directory Items ---------- + + CRecordVector items2; + + int nextLocalIndex = 0; + + LocalsCenterMerged = true; + + FOR_VECTOR (i, cdItems) + { + if (Callback) + if ((i & 0x3FFF) == 0) + { + const UInt64 numFiles64 = items.Size() + items2.Size(); + RINOK(Callback->SetCompleted(&numFiles64, &_cnt)) + } + + const CItemEx &cdItem = cdItems[i]; + + int index = -1; + + if (nextLocalIndex != -1) + { + if ((unsigned)nextLocalIndex < items.Size()) + { + CItemEx &item = items[(unsigned)nextLocalIndex]; + if (item.Disk == cdItem.Disk && + (item.LocalHeaderPos == cdItem.LocalHeaderPos + || (Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos))) + index = nextLocalIndex++; + else + nextLocalIndex = -1; + } + } + + if (index == -1) + index = FindItem(items, cdItem); + + // index = -1; + + if (index == -1) + { + items2.Add(i); + HeadersError = true; + continue; + } + + CItemEx &item = items[(unsigned)index]; + if (item.Name != cdItem.Name + // || item.Name.Len() != cdItem.Name.Len() + || item.PackSize != cdItem.PackSize + || item.Size != cdItem.Size + // item.ExtractVersion != cdItem.ExtractVersion + || !FlagsAreSame(item, cdItem) + || item.Crc != cdItem.Crc) + { + HeadersError = true; + continue; + } + + // item.Name = cdItem.Name; + item.MadeByVersion = cdItem.MadeByVersion; + item.CentralExtra = cdItem.CentralExtra; + item.InternalAttrib = cdItem.InternalAttrib; + item.ExternalAttrib = cdItem.ExternalAttrib; + item.Comment = cdItem.Comment; + item.FromCentral = cdItem.FromCentral; + // 22.02: we force utf8 flag, if central header has utf8 flag + if (cdItem.Flags & NFileHeader::NFlags::kUtf8) + item.Flags |= NFileHeader::NFlags::kUtf8; + } + + FOR_VECTOR (k, items2) + items.Add(cdItems[items2[k]]); + } + + if (ecd.NumEntries < ecd.NumEntries_in_ThisDisk) + HeadersError = true; + + if (ecd.ThisDisk == 0) + { + // if (isZip64) + { + if (ecd.NumEntries != ecd.NumEntries_in_ThisDisk) + HeadersError = true; + } + } + + if (isZip64) + { + if (cdInfo.NumEntries != items.Size() + || (ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF)) + HeadersError = true; + } + else + { + // old 7-zip could store 32-bit number of CD items to 16-bit field. + // if (ecd.NumEntries != items.Size()) + if (ecd.NumEntries > items.Size()) + HeadersError = true; + + if (cdInfo.NumEntries != numCdItems) + { + if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems) + HeadersError = true; + else + Cd_NumEntries_Overflow_16bit = true; + } + } + + ReadBuffer(ArcInfo.Comment, ecd.CommentSize); + + _inBufMode = false; + + // DisableBufMode(); + // Buffer.Free(); + /* we can't clear buf varibles. we need them to calculate PhySize of archive */ + + if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems + || (UInt32)cdInfo.Size != (UInt32)cdSize + || ((UInt32)cdInfo.Offset != (UInt32)cdRelatOffset && !items.IsEmpty())) + { + // return S_FALSE; + HeadersError = true; + } + + #ifdef ZIP_SELF_CHECK + if (localsWereRead) + { + const UInt64 endPos = ArcInfo.MarkerPos2 + _cnt; + if (endPos != (IsMultiVol ? Vols.TotalBytesSize : ArcInfo.FileEndPos)) + { + // there are some data after the end of archive or error in code; + return E_FAIL; + } + } + #endif + + // printf("\nOpen OK"); + return S_OK; +} + + + +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit, + IArchiveOpenCallback *callback, CObjectVector &items) +{ + items.Clear(); + + Close(); + + UInt64 startPos; + RINOK(InStream_GetPos(stream, startPos)) + RINOK(InStream_GetSize_SeekToEnd(stream, ArcInfo.FileEndPos)) + _streamPos = ArcInfo.FileEndPos; + + StartStream = stream; + Stream = stream; + Callback = callback; + + DisableBufMode(); + + bool volWasRequested = false; + + if (!Disable_VolsRead) + if (callback + && (startPos == 0 || !searchLimit || *searchLimit != 0)) + { + // we try to read volumes only if it's first call (offset == 0) or scan is allowed. + volWasRequested = true; + RINOK(ReadVols()) + } + + if (Disable_FindMarker) + { + RINOK(SeekToVol(-1, startPos)) + StreamRef = stream; + Stream = stream; + MarkerIsFound = true; + MarkerIsSafe = true; + ArcInfo.MarkerPos = startPos; + ArcInfo.MarkerPos2 = startPos; + } + else + if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()) + { + // only StartParsingVol = 0 is safe search. + RINOK(SeekToVol(0, 0)) + // if (Stream) + { + // UInt64 limit = 1 << 22; // for sfx + UInt64 limit = 0; // without sfx + + HRESULT res = FindMarker(&limit); + + if (res == S_OK) + { + MarkerIsFound = true; + MarkerIsSafe = true; + } + else if (res != S_FALSE) + return res; + } + } + else + { + // printf("\nOpen offset = %u\n", (unsigned)startPos); + if (IsMultiVol + && (unsigned)Vols.StartParsingVol < Vols.Streams.Size() + && Vols.Streams[(unsigned)Vols.StartParsingVol].Stream) + { + RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0)) + } + else + { + RINOK(SeekToVol(-1, startPos)) + } + + // UInt64 limit = 1 << 22; + // HRESULT res = FindMarker(&limit); + + HRESULT res = FindMarker(searchLimit); + + // const UInt64 curPos = GetVirtStreamPos(); + const UInt64 curPos = ArcInfo.MarkerPos2 + 4; + + if (res == S_OK) + MarkerIsFound = true; + else if (!IsMultiVol) + { + /* + // if (startPos != 0), probably CD could be already tested with another call with (startPos == 0). + // so we don't want to try to open CD again in that case. + if (startPos != 0) + return res; + // we can try to open CD, if there is no Marker and (startPos == 0). + // is it OK to open such files as ZIP, or big number of false positive, when CD can be find in end of file ? + */ + return res; + } + + if (ArcInfo.IsSpanMode && !volWasRequested) + { + RINOK(ReadVols()) + if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0) + ArcInfo.MarkerVolIndex = Vols.StartVolIndex; + } + + MarkerIsSafe = !IsMultiVol + || (ArcInfo.MarkerVolIndex == 0 && ArcInfo.MarkerPos == 0) + ; + + + if (IsMultiVol) + { + if ((unsigned)Vols.StartVolIndex < Vols.Streams.Size()) + { + Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream; + if (Stream) + { + RINOK(Seek_SavePos(curPos)) + } + else + IsMultiVol = false; + } + else + IsMultiVol = false; + } + + if (!IsMultiVol) + { + if (Vols.StreamIndex != -1) + { + Stream = StartStream; + Vols.StreamIndex = -1; + InitBuf(); + RINOK(Seek_SavePos(curPos)) + } + + ArcInfo.MarkerVolIndex = -1; + StreamRef = stream; + Stream = stream; + } + } + + + if (!IsMultiVol) + Vols.ClearRefs(); + + { + HRESULT res; + try + { + res = ReadHeaders(items); + } + catch (const CSystemException &e) { res = e.ErrorCode; } + catch (const CUnexpectEnd &) + { + if (items.IsEmpty()) + return S_FALSE; + UnexpectedEnd = true; + res = S_OK; + } + catch (...) + { + DisableBufMode(); + throw; + } + + if (IsMultiVol) + { + ArcInfo.FinishPos = ArcInfo.FileEndPos; + if ((unsigned)Vols.StreamIndex < Vols.Streams.Size()) + if (GetVirtStreamPos() < Vols.Streams[(unsigned)Vols.StreamIndex].Size) + ArcInfo.ThereIsTail = true; + } + else + { + ArcInfo.FinishPos = GetVirtStreamPos(); + ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > ArcInfo.FinishPos); + } + + DisableBufMode(); + + IsArcOpen = true; + if (!IsMultiVol) + Vols.Streams.Clear(); + return res; + } +} + + +HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr &stream) +{ + stream.Release(); + + UInt64 pos = item.LocalHeaderPos; + if (seekPackData) + pos += item.LocalFullHeaderSize; + + if (!IsMultiVol) + { + if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex) + return S_OK; + pos = (UInt64)((Int64)pos + ArcInfo.Base); + RINOK(InStream_SeekSet(StreamRef, pos)) + stream = StreamRef; + return S_OK; + } + + if (item.Disk >= Vols.Streams.Size()) + return S_OK; + + IInStream *str2 = Vols.Streams[item.Disk].Stream; + if (!str2) + return S_OK; + RINOK(InStream_SeekSet(str2, pos)) + + Vols.NeedSeek = false; + Vols.StreamIndex = (int)item.Disk; + + CVolStream *volsStreamSpec = new CVolStream; + volsStreamSpec->Vols = &Vols; + stream = volsStreamSpec; + + return S_OK; +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h index 38f26d09b..bea26dc9a 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ b/CPP/7zip/Archive/Zip/ZipIn.h @@ -1,449 +1,449 @@ -// Archive/ZipIn.h - -#ifndef ZIP7_INC_ZIP_IN_H -#define ZIP7_INC_ZIP_IN_H - -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/MyCom.h" - -#include "../../Common/StreamUtils.h" -#include "../../IStream.h" - -#include "ZipHeader.h" -#include "ZipItem.h" - -API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size); - -namespace NArchive { -namespace NZip { - -class CItemEx: public CItem -{ -public: - UInt32 LocalFullHeaderSize; // including Name and Extra - // int ParentOfAltStream; // -1, if not AltStream - - bool DescriptorWasRead; - - CItemEx(): - // ParentOfAltStream(-1), - DescriptorWasRead(false) {} - - UInt64 GetLocalFullSize() const - { return LocalFullHeaderSize + GetPackSizeWithDescriptor(); } - UInt64 GetDataPosition() const - { return LocalHeaderPos + LocalFullHeaderSize; } - - bool IsBadDescriptor() const - { - return !FromCentral && FromLocal && HasDescriptor() && !DescriptorWasRead; - } -}; - - -struct CInArchiveInfo -{ - Int64 Base; /* Base offset of start of archive in stream. - Offsets in headers must be calculated from that Base. - Base is equal to MarkerPos for normal ZIPs. - Base can point to PE stub for some ZIP SFXs. - if CentralDir was read, - Base can be negative, if start of data is not available, - if CentralDirs was not read, - Base = ArcInfo.MarkerPos; */ - - /* The following *Pos variables contain absolute offsets in Stream */ - - UInt64 MarkerPos; /* Pos of first signature, it can point to kSpan/kNoSpan signature - = MarkerPos2 in most archives - = MarkerPos2 - 4 if there is kSpan/kNoSpan signature */ - UInt64 MarkerPos2; // Pos of first local item signature in stream - UInt64 FinishPos; // Finish pos of archive data in starting volume - UInt64 FileEndPos; // Finish pos of stream - - UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base). - = 0 in most archives - = size of stub for some SFXs */ - - - int MarkerVolIndex; - - bool CdWasRead; - bool IsSpanMode; - bool ThereIsTail; - - // UInt32 BaseVolIndex; - - CByteBuffer Comment; - - - CInArchiveInfo(): - Base(0), - MarkerPos(0), - MarkerPos2(0), - FinishPos(0), - FileEndPos(0), - FirstItemRelatOffset(0), - MarkerVolIndex(-1), - CdWasRead(false), - IsSpanMode(false), - ThereIsTail(false) - // BaseVolIndex(0) - {} - - void Clear() - { - // BaseVolIndex = 0; - Base = 0; - MarkerPos = 0; - MarkerPos2 = 0; - FinishPos = 0; - FileEndPos = 0; - MarkerVolIndex = -1; - ThereIsTail = false; - - FirstItemRelatOffset = 0; - - CdWasRead = false; - IsSpanMode = false; - - Comment.Free(); - } -}; - - -struct CCdInfo -{ - bool IsFromEcd64; - - UInt16 CommentSize; - - // 64 - UInt16 VersionMade; - UInt16 VersionNeedExtract; - - // old zip - UInt32 ThisDisk; - UInt32 CdDisk; - UInt64 NumEntries_in_ThisDisk; - UInt64 NumEntries; - UInt64 Size; - UInt64 Offset; - - CCdInfo() { memset(this, 0, sizeof(*this)); IsFromEcd64 = false; } - - void ParseEcd32(const Byte *p); // (p) includes signature - void ParseEcd64e(const Byte *p); // (p) exclude signature - - bool IsEmptyArc() const - { - return ThisDisk == 0 - && CdDisk == 0 - && NumEntries_in_ThisDisk == 0 - && NumEntries == 0 - && Size == 0 - && Offset == 0 // test it - ; - } -}; - - -struct CVols -{ - struct CSubStreamInfo - { - CMyComPtr Stream; - UInt64 Size; - - HRESULT SeekToStart() const { return InStream_SeekToBegin(Stream); } - - CSubStreamInfo(): Size(0) {} - }; - - CObjectVector Streams; - - int StreamIndex; // -1 for StartStream - // -2 for ZipStream at multivol detection code - // >=0 volume index in multivol - - bool NeedSeek; - - bool DisableVolsSearch; - bool StartIsExe; // is .exe - bool StartIsZ; // is .zip or .zNN - bool StartIsZip; // is .zip - bool IsUpperCase; - bool MissingZip; - - bool ecd_wasRead; - - Int32 StartVolIndex; // -1, if unknown vol index - // = (NN - 1), if StartStream is .zNN - // = 0, if start vol is exe - - Int32 StartParsingVol; // if we need local parsing, we must use that stream - unsigned NumVols; - - int EndVolIndex; // index of last volume (ecd volume), - // -1, if is not multivol - - UString BaseName; // name of archive including '.' - UString MissingName; - - CMyComPtr ZipStream; - - CCdInfo ecd; - - UInt64 TotalBytesSize; // for MultiVol only - - void ClearRefs() - { - Streams.Clear(); - ZipStream.Release(); - TotalBytesSize = 0; - } - - void Clear() - { - StreamIndex = -1; - NeedSeek = false; - - DisableVolsSearch = false; - StartIsExe = false; - StartIsZ = false; - StartIsZip = false; - IsUpperCase = false; - - StartVolIndex = -1; - StartParsingVol = 0; - NumVols = 0; - EndVolIndex = -1; - - BaseName.Empty(); - MissingName.Empty(); - - MissingZip = false; - ecd_wasRead = false; - - ClearRefs(); - } - - HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback); - - HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); -}; - - -Z7_CLASS_IMP_COM_1( - CVolStream - , ISequentialInStream -) -public: - CVols *Vols; -}; - - -class CInArchive -{ - CMidBuffer Buffer; - size_t _bufPos; - size_t _bufCached; - - UInt64 _streamPos; - UInt64 _cnt; - - // UInt32 _startLocalFromCd_Disk; - // UInt64 _startLocalFromCd_Offset; - - size_t GetAvail() const { return _bufCached - _bufPos; } - - void InitBuf() { _bufPos = 0; _bufCached = 0; } - void DisableBufMode() { InitBuf(); _inBufMode = false; } - - void SkipLookahed(size_t skip) - { - _bufPos += skip; - _cnt += skip; - } - - HRESULT AllocateBuffer(size_t size); - - UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; } - - bool _inBufMode; - - bool IsArcOpen; - bool CanStartNewVol; - - UInt32 _signature; - - CMyComPtr StreamRef; - IInStream *Stream; - IInStream *StartStream; - IArchiveOpenCallback *Callback; - - HRESULT Seek_SavePos(UInt64 offset); - HRESULT SeekToVol(int volIndex, UInt64 offset); - - HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed); - HRESULT ReadFromCache_FALSE(Byte *data, unsigned size); - - HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback, - unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols); - HRESULT ReadVols(); - - HRESULT FindMarker(const UInt64 *searchLimit); - HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished); - - HRESULT LookAhead(size_t minRequiredInBuffer); - void SafeRead(Byte *data, unsigned size); - void ReadBuffer(CByteBuffer &buffer, unsigned size); - // Byte ReadByte(); - // UInt16 ReadUInt16(); - UInt32 ReadUInt32(); - UInt64 ReadUInt64(); - - void ReadSignature(); - - void Skip(size_t num); - HRESULT Skip64(UInt64 num, unsigned numFiles); - - bool ReadFileName(unsigned nameSize, AString &dest); - - bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, - UInt64 &unpackSize, UInt64 &packSize, CItem *cdItem); - bool ReadLocalItem(CItemEx &item); - HRESULT FindDescriptor(CItemEx &item, unsigned numFiles); - HRESULT ReadCdItem(CItemEx &item); - HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo); - HRESULT FindCd(bool checkOffsetMode); - HRESULT TryReadCd(CObjectVector &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize); - HRESULT ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); - HRESULT ReadLocals(CObjectVector &localItems); - - HRESULT ReadHeaders(CObjectVector &items); - - HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr &stream); - -public: - CInArchiveInfo ArcInfo; - - bool IsArc; - bool IsZip64; - - bool IsApk; - bool IsCdUnsorted; - - bool HeadersError; - bool HeadersWarning; - bool ExtraMinorError; - bool UnexpectedEnd; - bool LocalsWereRead; - bool LocalsCenterMerged; - bool NoCentralDir; - bool Overflow32bit; // = true, if zip without Zip64 extension support and it has some fields values truncated to 32-bits. - bool Cd_NumEntries_Overflow_16bit; // = true, if no Zip64 and 16-bit ecd:NumEntries was overflowed. - - bool MarkerIsFound; - bool MarkerIsSafe; - - bool IsMultiVol; - bool UseDisk_in_SingleVol; - UInt32 EcdVolIndex; - - CVols Vols; - - bool Force_ReadLocals_Mode; - bool Disable_VolsRead; - bool Disable_FindMarker; - - CInArchive(): - IsArcOpen(false), - Stream(NULL), - StartStream(NULL), - Callback(NULL), - Force_ReadLocals_Mode(false), - Disable_VolsRead(false), - Disable_FindMarker(false) - {} - - UInt64 GetPhySize() const - { - if (IsMultiVol) - return ArcInfo.FinishPos; - else - return (UInt64)((Int64)ArcInfo.FinishPos - ArcInfo.Base); - } - - UInt64 GetOffset() const - { - if (IsMultiVol) - return 0; - else - return (UInt64)ArcInfo.Base; - } - - - void ClearRefs(); - void Close(); - HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector &items); - - bool IsOpen() const { return IsArcOpen; } - - bool AreThereErrors() const - { - return HeadersError - || UnexpectedEnd - || !Vols.MissingName.IsEmpty(); - } - - bool IsLocalOffsetOK(const CItemEx &item) const - { - if (item.FromLocal) - return true; - return (Int64)GetOffset() + (Int64)item.LocalHeaderPos >= 0; - } - - UInt64 GetEmbeddedStubSize() const - { - // it's possible that first item in CD doesn refers to first local item - // so FirstItemRelatOffset is not first local item - - if (ArcInfo.CdWasRead) - return ArcInfo.FirstItemRelatOffset; - if (IsMultiVol) - return 0; - return (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base); - } - - - HRESULT CheckDescriptor(const CItemEx &item); - HRESULT Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError); - HRESULT Read_LocalItem_After_CdItem_Full(CItemEx &item); - - HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr &stream); - - IInStream *GetBaseStream() { return StreamRef; } - - bool CanUpdate() const - { - if (AreThereErrors() - || IsMultiVol - || ArcInfo.Base < 0 - || (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base - || ArcInfo.ThereIsTail - || GetEmbeddedStubSize() != 0 - || IsApk - || IsCdUnsorted) - return false; - - // 7-zip probably can update archives with embedded stubs. - // we just disable that feature for more safety. - - return true; - } -}; - -}} - -#endif +// Archive/ZipIn.h + +#ifndef ZIP7_INC_ZIP_IN_H +#define ZIP7_INC_ZIP_IN_H + +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/MyCom.h" + +#include "../../Common/StreamUtils.h" +#include "../../IStream.h" + +#include "ZipHeader.h" +#include "ZipItem.h" + +API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size); + +namespace NArchive { +namespace NZip { + +class CItemEx: public CItem +{ +public: + UInt32 LocalFullHeaderSize; // including Name and Extra + // int ParentOfAltStream; // -1, if not AltStream + + bool DescriptorWasRead; + + CItemEx(): + // ParentOfAltStream(-1), + DescriptorWasRead(false) {} + + UInt64 GetLocalFullSize() const + { return LocalFullHeaderSize + GetPackSizeWithDescriptor(); } + UInt64 GetDataPosition() const + { return LocalHeaderPos + LocalFullHeaderSize; } + + bool IsBadDescriptor() const + { + return !FromCentral && FromLocal && HasDescriptor() && !DescriptorWasRead; + } +}; + + +struct CInArchiveInfo +{ + Int64 Base; /* Base offset of start of archive in stream. + Offsets in headers must be calculated from that Base. + Base is equal to MarkerPos for normal ZIPs. + Base can point to PE stub for some ZIP SFXs. + if CentralDir was read, + Base can be negative, if start of data is not available, + if CentralDirs was not read, + Base = ArcInfo.MarkerPos; */ + + /* The following *Pos variables contain absolute offsets in Stream */ + + UInt64 MarkerPos; /* Pos of first signature, it can point to kSpan/kNoSpan signature + = MarkerPos2 in most archives + = MarkerPos2 - 4 if there is kSpan/kNoSpan signature */ + UInt64 MarkerPos2; // Pos of first local item signature in stream + UInt64 FinishPos; // Finish pos of archive data in starting volume + UInt64 FileEndPos; // Finish pos of stream + + UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base). + = 0 in most archives + = size of stub for some SFXs */ + + + int MarkerVolIndex; + + bool CdWasRead; + bool IsSpanMode; + bool ThereIsTail; + + // UInt32 BaseVolIndex; + + CByteBuffer Comment; + + + CInArchiveInfo(): + Base(0), + MarkerPos(0), + MarkerPos2(0), + FinishPos(0), + FileEndPos(0), + FirstItemRelatOffset(0), + MarkerVolIndex(-1), + CdWasRead(false), + IsSpanMode(false), + ThereIsTail(false) + // BaseVolIndex(0) + {} + + void Clear() + { + // BaseVolIndex = 0; + Base = 0; + MarkerPos = 0; + MarkerPos2 = 0; + FinishPos = 0; + FileEndPos = 0; + MarkerVolIndex = -1; + ThereIsTail = false; + + FirstItemRelatOffset = 0; + + CdWasRead = false; + IsSpanMode = false; + + Comment.Free(); + } +}; + + +struct CCdInfo +{ + bool IsFromEcd64; + + UInt16 CommentSize; + + // 64 + UInt16 VersionMade; + UInt16 VersionNeedExtract; + + // old zip + UInt32 ThisDisk; + UInt32 CdDisk; + UInt64 NumEntries_in_ThisDisk; + UInt64 NumEntries; + UInt64 Size; + UInt64 Offset; + + CCdInfo() { memset(this, 0, sizeof(*this)); IsFromEcd64 = false; } + + void ParseEcd32(const Byte *p); // (p) includes signature + void ParseEcd64e(const Byte *p); // (p) exclude signature + + bool IsEmptyArc() const + { + return ThisDisk == 0 + && CdDisk == 0 + && NumEntries_in_ThisDisk == 0 + && NumEntries == 0 + && Size == 0 + && Offset == 0 // test it + ; + } +}; + + +struct CVols +{ + struct CSubStreamInfo + { + CMyComPtr Stream; + UInt64 Size; + + HRESULT SeekToStart() const { return InStream_SeekToBegin(Stream); } + + CSubStreamInfo(): Size(0) {} + }; + + CObjectVector Streams; + + int StreamIndex; // -1 for StartStream + // -2 for ZipStream at multivol detection code + // >=0 volume index in multivol + + bool NeedSeek; + + bool DisableVolsSearch; + bool StartIsExe; // is .exe + bool StartIsZ; // is .zip or .zNN + bool StartIsZip; // is .zip + bool IsUpperCase; + bool MissingZip; + + bool ecd_wasRead; + + Int32 StartVolIndex; // -1, if unknown vol index + // = (NN - 1), if StartStream is .zNN + // = 0, if start vol is exe + + Int32 StartParsingVol; // if we need local parsing, we must use that stream + unsigned NumVols; + + int EndVolIndex; // index of last volume (ecd volume), + // -1, if is not multivol + + UString BaseName; // name of archive including '.' + UString MissingName; + + CMyComPtr ZipStream; + + CCdInfo ecd; + + UInt64 TotalBytesSize; // for MultiVol only + + void ClearRefs() + { + Streams.Clear(); + ZipStream.Release(); + TotalBytesSize = 0; + } + + void Clear() + { + StreamIndex = -1; + NeedSeek = false; + + DisableVolsSearch = false; + StartIsExe = false; + StartIsZ = false; + StartIsZip = false; + IsUpperCase = false; + + StartVolIndex = -1; + StartParsingVol = 0; + NumVols = 0; + EndVolIndex = -1; + + BaseName.Empty(); + MissingName.Empty(); + + MissingZip = false; + ecd_wasRead = false; + + ClearRefs(); + } + + HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback); + + HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); +}; + + +Z7_CLASS_IMP_COM_1( + CVolStream + , ISequentialInStream +) +public: + CVols *Vols; +}; + + +class CInArchive +{ + CMidBuffer Buffer; + size_t _bufPos; + size_t _bufCached; + + UInt64 _streamPos; + UInt64 _cnt; + + // UInt32 _startLocalFromCd_Disk; + // UInt64 _startLocalFromCd_Offset; + + size_t GetAvail() const { return _bufCached - _bufPos; } + + void InitBuf() { _bufPos = 0; _bufCached = 0; } + void DisableBufMode() { InitBuf(); _inBufMode = false; } + + void SkipLookahed(size_t skip) + { + _bufPos += skip; + _cnt += skip; + } + + HRESULT AllocateBuffer(size_t size); + + UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; } + + bool _inBufMode; + + bool IsArcOpen; + bool CanStartNewVol; + + UInt32 _signature; + + CMyComPtr StreamRef; + IInStream *Stream; + IInStream *StartStream; + IArchiveOpenCallback *Callback; + + HRESULT Seek_SavePos(UInt64 offset); + HRESULT SeekToVol(int volIndex, UInt64 offset); + + HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed); + HRESULT ReadFromCache_FALSE(Byte *data, unsigned size); + + HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback, + unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols); + HRESULT ReadVols(); + + HRESULT FindMarker(const UInt64 *searchLimit); + HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished); + + HRESULT LookAhead(size_t minRequiredInBuffer); + void SafeRead(Byte *data, unsigned size); + void ReadBuffer(CByteBuffer &buffer, unsigned size); + // Byte ReadByte(); + // UInt16 ReadUInt16(); + UInt32 ReadUInt32(); + UInt64 ReadUInt64(); + + void ReadSignature(); + + void Skip(size_t num); + HRESULT Skip64(UInt64 num, unsigned numFiles); + + bool ReadFileName(unsigned nameSize, AString &dest); + + bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra, + UInt64 &unpackSize, UInt64 &packSize, CItem *cdItem); + bool ReadLocalItem(CItemEx &item); + HRESULT FindDescriptor(CItemEx &item, unsigned numFiles); + HRESULT ReadCdItem(CItemEx &item); + HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo); + HRESULT FindCd(bool checkOffsetMode); + HRESULT TryReadCd(CObjectVector &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize); + HRESULT ReadCd(CObjectVector &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize); + HRESULT ReadLocals(CObjectVector &localItems); + + HRESULT ReadHeaders(CObjectVector &items); + + HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr &stream); + +public: + CInArchiveInfo ArcInfo; + + bool IsArc; + bool IsZip64; + + bool IsApk; + bool IsCdUnsorted; + + bool HeadersError; + bool HeadersWarning; + bool ExtraMinorError; + bool UnexpectedEnd; + bool LocalsWereRead; + bool LocalsCenterMerged; + bool NoCentralDir; + bool Overflow32bit; // = true, if zip without Zip64 extension support and it has some fields values truncated to 32-bits. + bool Cd_NumEntries_Overflow_16bit; // = true, if no Zip64 and 16-bit ecd:NumEntries was overflowed. + + bool MarkerIsFound; + bool MarkerIsSafe; + + bool IsMultiVol; + bool UseDisk_in_SingleVol; + UInt32 EcdVolIndex; + + CVols Vols; + + bool Force_ReadLocals_Mode; + bool Disable_VolsRead; + bool Disable_FindMarker; + + CInArchive(): + IsArcOpen(false), + Stream(NULL), + StartStream(NULL), + Callback(NULL), + Force_ReadLocals_Mode(false), + Disable_VolsRead(false), + Disable_FindMarker(false) + {} + + UInt64 GetPhySize() const + { + if (IsMultiVol) + return ArcInfo.FinishPos; + else + return (UInt64)((Int64)ArcInfo.FinishPos - ArcInfo.Base); + } + + UInt64 GetOffset() const + { + if (IsMultiVol) + return 0; + else + return (UInt64)ArcInfo.Base; + } + + + void ClearRefs(); + void Close(); + HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector &items); + + bool IsOpen() const { return IsArcOpen; } + + bool AreThereErrors() const + { + return HeadersError + || UnexpectedEnd + || !Vols.MissingName.IsEmpty(); + } + + bool IsLocalOffsetOK(const CItemEx &item) const + { + if (item.FromLocal) + return true; + return (Int64)GetOffset() + (Int64)item.LocalHeaderPos >= 0; + } + + UInt64 GetEmbeddedStubSize() const + { + // it's possible that first item in CD doesn refers to first local item + // so FirstItemRelatOffset is not first local item + + if (ArcInfo.CdWasRead) + return ArcInfo.FirstItemRelatOffset; + if (IsMultiVol) + return 0; + return (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base); + } + + + HRESULT CheckDescriptor(const CItemEx &item); + HRESULT Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError); + HRESULT Read_LocalItem_After_CdItem_Full(CItemEx &item); + + HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr &stream); + + IInStream *GetBaseStream() { return StreamRef; } + + bool CanUpdate() const + { + if (AreThereErrors() + || IsMultiVol + || ArcInfo.Base < 0 + || (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base + || ArcInfo.ThereIsTail + || GetEmbeddedStubSize() != 0 + || IsApk + || IsCdUnsorted) + return false; + + // 7-zip probably can update archives with embedded stubs. + // we just disable that feature for more safety. + + return true; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp index 272e53b08..5684cac06 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ b/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -1,464 +1,464 @@ -// Archive/ZipItem.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" -#include "../../../../C/7zCrc.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/MyLinux.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/PropVariantUtils.h" - -#include "../Common/ItemNameUtils.h" - -#include "ZipItem.h" - -namespace NArchive { -namespace NZip { - -using namespace NFileHeader; - - -/* -const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@"; -const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@"; -*/ - -static const CUInt32PCharPair g_ExtraTypes[] = -{ - { NExtraID::kZip64, "Zip64" }, - { NExtraID::kNTFS, "NTFS" }, - { NExtraID::kUnix0, "UNIX" }, - { NExtraID::kStrongEncrypt, "StrongCrypto" }, - { NExtraID::kUnixTime, "UT" }, - { NExtraID::kUnix1, "UX" }, - { NExtraID::kUnix2, "Ux" }, - { NExtraID::kUnixN, "ux" }, - { NExtraID::kIzUnicodeComment, "uc" }, - { NExtraID::kIzUnicodeName, "up" }, - { NExtraID::kIzNtSecurityDescriptor, "SD" }, - { NExtraID::kWzAES, "WzAES" }, - { NExtraID::kApkAlign, "ApkAlign" } -}; - -void CExtraSubBlock::PrintInfo(AString &s) const -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTypes); i++) - { - const CUInt32PCharPair &pair = g_ExtraTypes[i]; - if (pair.Value == ID) - { - s += pair.Name; - if (ID == NExtraID::kUnixTime) - { - if (Data.Size() >= 1) - { - s.Add_Colon(); - const Byte flags = Data[0]; - if (flags & 1) s.Add_Char('M'); - if (flags & 2) s.Add_Char('A'); - if (flags & 4) s.Add_Char('C'); - const UInt32 size = (UInt32)(Data.Size()) - 1; - if (size % 4 == 0) - { - s.Add_Colon(); - s.Add_UInt32(size / 4); - } - } - } - /* - if (ID == NExtraID::kApkAlign && Data.Size() >= 2) - { - char sz[32]; - sz[0] = ':'; - ConvertUInt32ToHex(GetUi16(Data), sz + 1); - s += sz; - for (unsigned j = 2; j < Data.Size(); j++) - { - char sz[32]; - sz[0] = '-'; - ConvertUInt32ToHex(Data[j], sz + 1); - s += sz; - } - } - */ - return; - } - } - { - char sz[16]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt32ToHex(ID, sz + 2); - s += sz; - } -} - - -void CExtraBlock::PrintInfo(AString &s) const -{ - if (Error) - s.Add_OptSpaced("Extra_ERROR"); - - if (MinorError) - s.Add_OptSpaced("Minor_Extra_ERROR"); - - if (IsZip64 || IsZip64_Error) - { - s.Add_OptSpaced("Zip64"); - if (IsZip64_Error) - s += "_ERROR"; - } - - FOR_VECTOR (i, SubBlocks) - { - s.Add_Space_if_NotEmpty(); - SubBlocks[i].PrintInfo(s); - } -} - - -bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const -{ - ft.dwHighDateTime = ft.dwLowDateTime = 0; - UInt32 size = (UInt32)Data.Size(); - if (ID != NExtraID::kNTFS || size < 32) - return false; - const Byte *p = (const Byte *)Data; - p += 4; // for reserved - size -= 4; - while (size > 4) - { - UInt16 tag = GetUi16(p); - unsigned attrSize = GetUi16(p + 2); - p += 4; - size -= 4; - if (attrSize > size) - attrSize = size; - - if (tag == NNtfsExtra::kTagTime && attrSize >= 24) - { - p += 8 * index; - ft.dwLowDateTime = GetUi32(p); - ft.dwHighDateTime = GetUi32(p + 4); - return true; - } - p += attrSize; - size -= attrSize; - } - return false; -} - -bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const -{ - /* Info-Zip : - The central-header extra field contains the modification - time only, or no timestamp at all. - Size of Data is used to flag its presence or absence - If "Flags" indicates that Modtime is present in the local header - field, it MUST be present in the central header field, too - */ - - res = 0; - UInt32 size = (UInt32)Data.Size(); - if (ID != NExtraID::kUnixTime || size < 5) - return false; - const Byte *p = (const Byte *)Data; - const Byte flags = *p++; - size--; - if (isCentral) - { - if (index != NUnixTime::kMTime || - (flags & (1 << NUnixTime::kMTime)) == 0 || - size < 4) - return false; - res = GetUi32(p); - return true; - } - for (unsigned i = 0; i < 3; i++) - if ((flags & (1 << i)) != 0) - { - if (size < 4) - return false; - if (index == i) - { - res = GetUi32(p); - return true; - } - p += 4; - size -= 4; - } - return false; -} - - -// Info-ZIP's abandoned "Unix1 timestamps & owner ID info" - -bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const -{ - res = 0; - const unsigned offset = index * 4; - if (Data.Size() < offset + 4) - return false; - if (ID != NExtraID::kUnix0 && - ID != NExtraID::kUnix1) - return false; - const Byte *p = (const Byte *)Data + offset; - res = GetUi32(p); - return true; -} - -/* -// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps" -bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const -{ - res = 0; - const unsigned offset = index * 4; - if (ID != NExtraID::kUnix0 || Data.Size() < offset) - return false; - const Byte *p = (const Byte *)Data + offset; - res = GetUi32(p); - return true; -} -*/ - -bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const -{ - FOR_VECTOR (i, SubBlocks) - { - const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kNTFS) - return sb.ExtractNtfsTime(index, ft); - } - return false; -} - -bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const -{ - { - FOR_VECTOR (i, SubBlocks) - { - const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kUnixTime) - return sb.Extract_UnixTime(isCentral, index, res); - } - } - - switch (index) - { - case NUnixTime::kMTime: index = NUnixExtra::kMTime; break; - case NUnixTime::kATime: index = NUnixExtra::kATime; break; - default: return false; - } - - { - FOR_VECTOR (i, SubBlocks) - { - const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kUnix0 || - sb.ID == NFileHeader::NExtraID::kUnix1) - return sb.Extract_Unix01_Time(index, res); - } - } - return false; -} - - -bool CLocalItem::IsDir() const -{ - return NItemName::HasTailSlash(Name, GetCodePage()); -} - -bool CItem::IsDir() const -{ - // FIXME: we can check InfoZip UTF-8 name at first. - if (NItemName::HasTailSlash(Name, GetCodePage())) - return true; - - Byte hostOS = GetHostOS(); - - if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\') - { - // do we need to use CharPrevExA? - // .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers? - // so we support that case - switch (hostOS) - { - case NHostOS::kFAT: - case NHostOS::kNTFS: - case NHostOS::kHPFS: - case NHostOS::kVFAT: - return true; - default: break; - } - } - - if (!FromCentral) - return false; - - UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF); - - switch (hostOS) - { - case NHostOS::kAMIGA: - switch (highAttrib & NAmigaAttrib::kIFMT) - { - case NAmigaAttrib::kIFDIR: return true; - case NAmigaAttrib::kIFREG: return false; - default: return false; // change it throw kUnknownAttributes; - } - case NHostOS::kFAT: - case NHostOS::kNTFS: - case NHostOS::kHPFS: - case NHostOS::kVFAT: - return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0); - case NHostOS::kAtari: - case NHostOS::kMac: - case NHostOS::kVMS: - case NHostOS::kVM_CMS: - case NHostOS::kAcorn: - case NHostOS::kMVS: - return false; // change it throw kUnknownAttributes; - case NHostOS::kUnix: - return MY_LIN_S_ISDIR(highAttrib); - default: - return false; - } -} - -UInt32 CItem::GetWinAttrib() const -{ - UInt32 winAttrib = 0; - switch (GetHostOS()) - { - case NHostOS::kFAT: - case NHostOS::kNTFS: - if (FromCentral) - winAttrib = ExternalAttrib; - break; - case NHostOS::kUnix: - // do we need to clear 16 low bits in this case? - if (FromCentral) - { - /* - Some programs write posix attributes in high 16 bits of ExternalAttrib - Also some programs can write additional marker flag: - 0x8000 - p7zip - 0x4000 - Zip in MacOS - no marker - Info-Zip - - Client code has two options to detect posix field: - 1) check 0x8000 marker. In that case we must add 0x8000 marker here. - 2) check that high 4 bits (file type bits in posix field) of attributes are not zero. - */ - - winAttrib = ExternalAttrib & 0xFFFF0000; - - // #ifndef _WIN32 - winAttrib |= 0x8000; // add posix mode marker - // #endif - } - break; - default: break; - } - if (IsDir()) // test it; - winAttrib |= FILE_ATTRIBUTE_DIRECTORY; - return winAttrib; -} - -bool CItem::GetPosixAttrib(UInt32 &attrib) const -{ - // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT. - if (FromCentral && GetHostOS() == NHostOS::kUnix) - { - attrib = ExternalAttrib >> 16; - return (attrib != 0); - } - attrib = 0; - if (IsDir()) - attrib = MY_LIN_S_IFDIR; - return false; -} - - -bool CExtraSubBlock::CheckIzUnicode(const AString &s) const -{ - size_t size = Data.Size(); - if (size < 1 + 4) - return false; - const Byte *p = (const Byte *)Data; - if (p[0] > 1) - return false; - if (CrcCalc(s, s.Len()) != GetUi32(p + 1)) - return false; - size -= 5; - p += 5; - for (size_t i = 0; i < size; i++) - if (p[i] == 0) - return false; - return Check_UTF8_Buf((const char *)(const void *)p, size, false); -} - - -void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const -{ - bool isUtf8 = IsUtf8(); - // bool ignore_Utf8_Errors = true; - - if (!isUtf8) - { - { - const unsigned id = isComment ? - NFileHeader::NExtraID::kIzUnicodeComment: - NFileHeader::NExtraID::kIzUnicodeName; - const CObjectVector &subBlocks = GetMainExtra().SubBlocks; - - FOR_VECTOR (i, subBlocks) - { - const CExtraSubBlock &sb = subBlocks[i]; - if (sb.ID == id) - { - if (sb.CheckIzUnicode(s)) - { - // const unsigned kIzUnicodeHeaderSize = 5; - if (Convert_UTF8_Buf_To_Unicode( - (const char *)(const void *)(const Byte *)sb.Data + 5, - sb.Data.Size() - 5, res)) - return; - } - break; - } - } - } - - if (useSpecifiedCodePage) - isUtf8 = (codePage == CP_UTF8); - #ifdef _WIN32 - else if (GetHostOS() == NFileHeader::NHostOS::kUnix) - { - /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header. - We try to get name as UTF-8. - Do we need to do it in POSIX version also? */ - isUtf8 = true; - - /* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed - of UTF-8 and non-UTF-8 characters. */ - // ignore_Utf8_Errors = false; - // ignore_Utf8_Errors = true; - } - #endif - } - - - if (isUtf8) - { - ConvertUTF8ToUnicode(s, res); - return; - } - - MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); -} - -}} +// Archive/ZipItem.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" +#include "../../../../C/7zCrc.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/MyLinux.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/PropVariantUtils.h" + +#include "../Common/ItemNameUtils.h" + +#include "ZipItem.h" + +namespace NArchive { +namespace NZip { + +using namespace NFileHeader; + + +/* +const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@"; +const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@"; +*/ + +static const CUInt32PCharPair g_ExtraTypes[] = +{ + { NExtraID::kZip64, "Zip64" }, + { NExtraID::kNTFS, "NTFS" }, + { NExtraID::kUnix0, "UNIX" }, + { NExtraID::kStrongEncrypt, "StrongCrypto" }, + { NExtraID::kUnixTime, "UT" }, + { NExtraID::kUnix1, "UX" }, + { NExtraID::kUnix2, "Ux" }, + { NExtraID::kUnixN, "ux" }, + { NExtraID::kIzUnicodeComment, "uc" }, + { NExtraID::kIzUnicodeName, "up" }, + { NExtraID::kIzNtSecurityDescriptor, "SD" }, + { NExtraID::kWzAES, "WzAES" }, + { NExtraID::kApkAlign, "ApkAlign" } +}; + +void CExtraSubBlock::PrintInfo(AString &s) const +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTypes); i++) + { + const CUInt32PCharPair &pair = g_ExtraTypes[i]; + if (pair.Value == ID) + { + s += pair.Name; + if (ID == NExtraID::kUnixTime) + { + if (Data.Size() >= 1) + { + s.Add_Colon(); + const Byte flags = Data[0]; + if (flags & 1) s.Add_Char('M'); + if (flags & 2) s.Add_Char('A'); + if (flags & 4) s.Add_Char('C'); + const UInt32 size = (UInt32)(Data.Size()) - 1; + if (size % 4 == 0) + { + s.Add_Colon(); + s.Add_UInt32(size / 4); + } + } + } + /* + if (ID == NExtraID::kApkAlign && Data.Size() >= 2) + { + char sz[32]; + sz[0] = ':'; + ConvertUInt32ToHex(GetUi16(Data), sz + 1); + s += sz; + for (unsigned j = 2; j < Data.Size(); j++) + { + char sz[32]; + sz[0] = '-'; + ConvertUInt32ToHex(Data[j], sz + 1); + s += sz; + } + } + */ + return; + } + } + { + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(ID, sz + 2); + s += sz; + } +} + + +void CExtraBlock::PrintInfo(AString &s) const +{ + if (Error) + s.Add_OptSpaced("Extra_ERROR"); + + if (MinorError) + s.Add_OptSpaced("Minor_Extra_ERROR"); + + if (IsZip64 || IsZip64_Error) + { + s.Add_OptSpaced("Zip64"); + if (IsZip64_Error) + s += "_ERROR"; + } + + FOR_VECTOR (i, SubBlocks) + { + s.Add_Space_if_NotEmpty(); + SubBlocks[i].PrintInfo(s); + } +} + + +bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const +{ + ft.dwHighDateTime = ft.dwLowDateTime = 0; + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kNTFS || size < 32) + return false; + const Byte *p = (const Byte *)Data; + p += 4; // for reserved + size -= 4; + while (size > 4) + { + UInt16 tag = GetUi16(p); + unsigned attrSize = GetUi16(p + 2); + p += 4; + size -= 4; + if (attrSize > size) + attrSize = size; + + if (tag == NNtfsExtra::kTagTime && attrSize >= 24) + { + p += 8 * index; + ft.dwLowDateTime = GetUi32(p); + ft.dwHighDateTime = GetUi32(p + 4); + return true; + } + p += attrSize; + size -= attrSize; + } + return false; +} + +bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const +{ + /* Info-Zip : + The central-header extra field contains the modification + time only, or no timestamp at all. + Size of Data is used to flag its presence or absence + If "Flags" indicates that Modtime is present in the local header + field, it MUST be present in the central header field, too + */ + + res = 0; + UInt32 size = (UInt32)Data.Size(); + if (ID != NExtraID::kUnixTime || size < 5) + return false; + const Byte *p = (const Byte *)Data; + const Byte flags = *p++; + size--; + if (isCentral) + { + if (index != NUnixTime::kMTime || + (flags & (1 << NUnixTime::kMTime)) == 0 || + size < 4) + return false; + res = GetUi32(p); + return true; + } + for (unsigned i = 0; i < 3; i++) + if ((flags & (1 << i)) != 0) + { + if (size < 4) + return false; + if (index == i) + { + res = GetUi32(p); + return true; + } + p += 4; + size -= 4; + } + return false; +} + + +// Info-ZIP's abandoned "Unix1 timestamps & owner ID info" + +bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const +{ + res = 0; + const unsigned offset = index * 4; + if (Data.Size() < offset + 4) + return false; + if (ID != NExtraID::kUnix0 && + ID != NExtraID::kUnix1) + return false; + const Byte *p = (const Byte *)Data + offset; + res = GetUi32(p); + return true; +} + +/* +// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps" +bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const +{ + res = 0; + const unsigned offset = index * 4; + if (ID != NExtraID::kUnix0 || Data.Size() < offset) + return false; + const Byte *p = (const Byte *)Data + offset; + res = GetUi32(p); + return true; +} +*/ + +bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const +{ + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kNTFS) + return sb.ExtractNtfsTime(index, ft); + } + return false; +} + +bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const +{ + { + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kUnixTime) + return sb.Extract_UnixTime(isCentral, index, res); + } + } + + switch (index) + { + case NUnixTime::kMTime: index = NUnixExtra::kMTime; break; + case NUnixTime::kATime: index = NUnixExtra::kATime; break; + default: return false; + } + + { + FOR_VECTOR (i, SubBlocks) + { + const CExtraSubBlock &sb = SubBlocks[i]; + if (sb.ID == NFileHeader::NExtraID::kUnix0 || + sb.ID == NFileHeader::NExtraID::kUnix1) + return sb.Extract_Unix01_Time(index, res); + } + } + return false; +} + + +bool CLocalItem::IsDir() const +{ + return NItemName::HasTailSlash(Name, GetCodePage()); +} + +bool CItem::IsDir() const +{ + // FIXME: we can check InfoZip UTF-8 name at first. + if (NItemName::HasTailSlash(Name, GetCodePage())) + return true; + + Byte hostOS = GetHostOS(); + + if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\') + { + // do we need to use CharPrevExA? + // .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers? + // so we support that case + switch (hostOS) + { + case NHostOS::kFAT: + case NHostOS::kNTFS: + case NHostOS::kHPFS: + case NHostOS::kVFAT: + return true; + default: break; + } + } + + if (!FromCentral) + return false; + + UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF); + + switch (hostOS) + { + case NHostOS::kAMIGA: + switch (highAttrib & NAmigaAttrib::kIFMT) + { + case NAmigaAttrib::kIFDIR: return true; + case NAmigaAttrib::kIFREG: return false; + default: return false; // change it throw kUnknownAttributes; + } + case NHostOS::kFAT: + case NHostOS::kNTFS: + case NHostOS::kHPFS: + case NHostOS::kVFAT: + return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0); + case NHostOS::kAtari: + case NHostOS::kMac: + case NHostOS::kVMS: + case NHostOS::kVM_CMS: + case NHostOS::kAcorn: + case NHostOS::kMVS: + return false; // change it throw kUnknownAttributes; + case NHostOS::kUnix: + return MY_LIN_S_ISDIR(highAttrib); + default: + return false; + } +} + +UInt32 CItem::GetWinAttrib() const +{ + UInt32 winAttrib = 0; + switch (GetHostOS()) + { + case NHostOS::kFAT: + case NHostOS::kNTFS: + if (FromCentral) + winAttrib = ExternalAttrib; + break; + case NHostOS::kUnix: + // do we need to clear 16 low bits in this case? + if (FromCentral) + { + /* + Some programs write posix attributes in high 16 bits of ExternalAttrib + Also some programs can write additional marker flag: + 0x8000 - p7zip + 0x4000 - Zip in MacOS + no marker - Info-Zip + + Client code has two options to detect posix field: + 1) check 0x8000 marker. In that case we must add 0x8000 marker here. + 2) check that high 4 bits (file type bits in posix field) of attributes are not zero. + */ + + winAttrib = ExternalAttrib & 0xFFFF0000; + + // #ifndef _WIN32 + winAttrib |= 0x8000; // add posix mode marker + // #endif + } + break; + default: break; + } + if (IsDir()) // test it; + winAttrib |= FILE_ATTRIBUTE_DIRECTORY; + return winAttrib; +} + +bool CItem::GetPosixAttrib(UInt32 &attrib) const +{ + // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT. + if (FromCentral && GetHostOS() == NHostOS::kUnix) + { + attrib = ExternalAttrib >> 16; + return (attrib != 0); + } + attrib = 0; + if (IsDir()) + attrib = MY_LIN_S_IFDIR; + return false; +} + + +bool CExtraSubBlock::CheckIzUnicode(const AString &s) const +{ + size_t size = Data.Size(); + if (size < 1 + 4) + return false; + const Byte *p = (const Byte *)Data; + if (p[0] > 1) + return false; + if (CrcCalc(s, s.Len()) != GetUi32(p + 1)) + return false; + size -= 5; + p += 5; + for (size_t i = 0; i < size; i++) + if (p[i] == 0) + return false; + return Check_UTF8_Buf((const char *)(const void *)p, size, false); +} + + +void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const +{ + bool isUtf8 = IsUtf8(); + // bool ignore_Utf8_Errors = true; + + if (!isUtf8) + { + { + const unsigned id = isComment ? + NFileHeader::NExtraID::kIzUnicodeComment: + NFileHeader::NExtraID::kIzUnicodeName; + const CObjectVector &subBlocks = GetMainExtra().SubBlocks; + + FOR_VECTOR (i, subBlocks) + { + const CExtraSubBlock &sb = subBlocks[i]; + if (sb.ID == id) + { + if (sb.CheckIzUnicode(s)) + { + // const unsigned kIzUnicodeHeaderSize = 5; + if (Convert_UTF8_Buf_To_Unicode( + (const char *)(const void *)(const Byte *)sb.Data + 5, + sb.Data.Size() - 5, res)) + return; + } + break; + } + } + } + + if (useSpecifiedCodePage) + isUtf8 = (codePage == CP_UTF8); + #ifdef _WIN32 + else if (GetHostOS() == NFileHeader::NHostOS::kUnix) + { + /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header. + We try to get name as UTF-8. + Do we need to do it in POSIX version also? */ + isUtf8 = true; + + /* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed + of UTF-8 and non-UTF-8 characters. */ + // ignore_Utf8_Errors = false; + // ignore_Utf8_Errors = true; + } + #endif + } + + + if (isUtf8) + { + ConvertUTF8ToUnicode(s, res); + return; + } + + MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage()); +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h index c21b24196..4a25de3db 100644 --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ b/CPP/7zip/Archive/Zip/ZipItem.h @@ -1,356 +1,356 @@ -// Archive/ZipItem.h - -#ifndef ZIP7_INC_ARCHIVE_ZIP_ITEM_H -#define ZIP7_INC_ARCHIVE_ZIP_ITEM_H - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyString.h" -#include "../../../Common/UTFConvert.h" - -#include "ZipHeader.h" - -namespace NArchive { -namespace NZip { - -/* -extern const char *k_SpecName_NTFS_STREAM; -extern const char *k_SpecName_MAC_RESOURCE_FORK; -*/ - -struct CVersion -{ - Byte Version; - Byte HostOS; -}; - -struct CExtraSubBlock -{ - UInt32 ID; - CByteBuffer Data; - - bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; - bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const; - bool Extract_Unix01_Time(unsigned index, UInt32 &res) const; - // bool Extract_Unix_Time(unsigned index, UInt32 &res) const; - - bool CheckIzUnicode(const AString &s) const; - - void PrintInfo(AString &s) const; -}; - -const unsigned k_WzAesExtra_Size = 7; - -struct CWzAesExtra -{ - UInt16 VendorVersion; // 1: AE-1, 2: AE-2, - // UInt16 VendorId; // 'A' 'E' - Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit - UInt16 Method; - - CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {} - - bool NeedCrc() const { return (VendorVersion == 1); } - - bool ParseFromSubBlock(const CExtraSubBlock &sb) - { - if (sb.ID != NFileHeader::NExtraID::kWzAES) - return false; - if (sb.Data.Size() < k_WzAesExtra_Size) - return false; - const Byte *p = (const Byte *)sb.Data; - VendorVersion = GetUi16(p); - if (p[2] != 'A' || p[3] != 'E') - return false; - Strength = p[4]; - // 9.31: The BUG was fixed: - Method = GetUi16(p + 5); - return true; - } - - void SetSubBlock(CExtraSubBlock &sb) const - { - sb.Data.Alloc(k_WzAesExtra_Size); - sb.ID = NFileHeader::NExtraID::kWzAES; - Byte *p = (Byte *)sb.Data; - p[0] = (Byte)VendorVersion; - p[1] = (Byte)(VendorVersion >> 8); - p[2] = 'A'; - p[3] = 'E'; - p[4] = Strength; - p[5] = (Byte)Method; - p[6] = (Byte)(Method >> 8); - } -}; - -namespace NStrongCrypto_AlgId -{ - const UInt16 kDES = 0x6601; - const UInt16 kRC2old = 0x6602; - const UInt16 k3DES168 = 0x6603; - const UInt16 k3DES112 = 0x6609; - const UInt16 kAES128 = 0x660E; - const UInt16 kAES192 = 0x660F; - const UInt16 kAES256 = 0x6610; - const UInt16 kRC2 = 0x6702; - const UInt16 kBlowfish = 0x6720; - const UInt16 kTwofish = 0x6721; - const UInt16 kRC4 = 0x6801; -} - -struct CStrongCryptoExtra -{ - UInt16 Format; - UInt16 AlgId; - UInt16 BitLen; - UInt16 Flags; - - bool ParseFromSubBlock(const CExtraSubBlock &sb) - { - if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt) - return false; - const Byte *p = (const Byte *)sb.Data; - if (sb.Data.Size() < 8) - return false; - Format = GetUi16(p + 0); - AlgId = GetUi16(p + 2); - BitLen = GetUi16(p + 4); - Flags = GetUi16(p + 6); - return (Format == 2); - } - - bool CertificateIsUsed() const { return (Flags > 0x0001); } -}; - - -struct CExtraBlock -{ - CObjectVector SubBlocks; - bool Error; - bool MinorError; - bool IsZip64; - bool IsZip64_Error; - - CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {} - - void Clear() - { - SubBlocks.Clear(); - IsZip64 = false; - } - - size_t GetSize() const - { - size_t res = 0; - FOR_VECTOR (i, SubBlocks) - res += SubBlocks[i].Data.Size() + 2 + 2; - return res; - } - - bool GetWzAes(CWzAesExtra &e) const - { - FOR_VECTOR (i, SubBlocks) - if (e.ParseFromSubBlock(SubBlocks[i])) - return true; - return false; - } - - bool HasWzAes() const - { - CWzAesExtra e; - return GetWzAes(e); - } - - bool GetStrongCrypto(CStrongCryptoExtra &e) const - { - FOR_VECTOR (i, SubBlocks) - if (e.ParseFromSubBlock(SubBlocks[i])) - return true; - return false; - } - - /* - bool HasStrongCrypto() const - { - CStrongCryptoExtra e; - return GetStrongCrypto(e); - } - */ - - bool GetNtfsTime(unsigned index, FILETIME &ft) const; - bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const; - - void PrintInfo(AString &s) const; - - void RemoveUnknownSubBlocks() - { - for (unsigned i = SubBlocks.Size(); i != 0;) - { - i--; - switch (SubBlocks[i].ID) - { - case NFileHeader::NExtraID::kStrongEncrypt: - case NFileHeader::NExtraID::kWzAES: - break; - default: - SubBlocks.Delete(i); - } - } - } -}; - - -class CLocalItem -{ -public: - UInt16 Flags; - UInt16 Method; - - /* - Zip specification doesn't mention that ExtractVersion field uses HostOS subfield. - 18.06: 7-Zip now doesn't use ExtractVersion::HostOS to detect codePage - */ - - CVersion ExtractVersion; - - UInt64 Size; - UInt64 PackSize; - UInt32 Time; - UInt32 Crc; - - UInt32 Disk; - - AString Name; - - CExtraBlock LocalExtra; - - unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; } - - UInt64 GetPackSizeWithDescriptor() const - { return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); } - - bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; } - bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; } - bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; } - bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); } - bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; } - bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } - // bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; } - - unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; } - - bool IsDir() const; - - /* - void GetUnicodeString(const AString &s, UString &res) const - { - bool isUtf8 = IsUtf8(); - if (isUtf8) - if (ConvertUTF8ToUnicode(s, res)) - return; - MultiByteToUnicodeString2(res, s, GetCodePage()); - } - */ - -private: - - void SetFlag(unsigned bitMask, bool enable) - { - if (enable) - Flags = (UInt16)(Flags | bitMask); - else - Flags = (UInt16)(Flags & ~bitMask); - } - -public: - - void ClearFlags() { Flags = 0; } - void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } - void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } - // void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); } - void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); } - - UINT GetCodePage() const - { - if (IsUtf8()) - return CP_UTF8; - return CP_OEMCP; - } -}; - - -class CItem: public CLocalItem -{ -public: - CVersion MadeByVersion; - UInt16 InternalAttrib; - UInt32 ExternalAttrib; - - UInt64 LocalHeaderPos; - - CExtraBlock CentralExtra; - CByteBuffer Comment; - - bool FromLocal; - bool FromCentral; - - // CItem can be used as CLocalItem. So we must clear unused fields - CItem(): - InternalAttrib(0), - ExternalAttrib(0), - FromLocal(false), - FromCentral(false) - { - MadeByVersion.Version = 0; - MadeByVersion.HostOS = 0; - } - - const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); } - - bool IsDir() const; - UInt32 GetWinAttrib() const; - bool GetPosixAttrib(UInt32 &attrib) const; - - // 18.06: 0 instead of ExtractVersion.HostOS for local item - Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : (Byte)0; } - - void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const; - - bool IsThereCrc() const - { - if (Method == NFileHeader::NCompressionMethod::kWzAES) - { - CWzAesExtra aesField; - if (GetMainExtra().GetWzAes(aesField)) - return aesField.NeedCrc(); - } - return (Crc != 0 || !IsDir()); - } - - bool Is_MadeBy_Unix() const - { - if (!FromCentral) - return false; - return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix); - } - - UINT GetCodePage() const - { - // 18.06: now we use HostOS only from Central::MadeByVersion - if (IsUtf8()) - return CP_UTF8; - if (!FromCentral) - return CP_OEMCP; - Byte hostOS = MadeByVersion.HostOS; - return (UINT)(( - hostOS == NFileHeader::NHostOS::kFAT - || hostOS == NFileHeader::NHostOS::kNTFS - || hostOS == NFileHeader::NHostOS::kUnix // do we need it? - ) ? CP_OEMCP : CP_ACP); - } -}; - -}} - -#endif +// Archive/ZipItem.h + +#ifndef ZIP7_INC_ARCHIVE_ZIP_ITEM_H +#define ZIP7_INC_ARCHIVE_ZIP_ITEM_H + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyString.h" +#include "../../../Common/UTFConvert.h" + +#include "ZipHeader.h" + +namespace NArchive { +namespace NZip { + +/* +extern const char *k_SpecName_NTFS_STREAM; +extern const char *k_SpecName_MAC_RESOURCE_FORK; +*/ + +struct CVersion +{ + Byte Version; + Byte HostOS; +}; + +struct CExtraSubBlock +{ + UInt32 ID; + CByteBuffer Data; + + bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; + bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const; + bool Extract_Unix01_Time(unsigned index, UInt32 &res) const; + // bool Extract_Unix_Time(unsigned index, UInt32 &res) const; + + bool CheckIzUnicode(const AString &s) const; + + void PrintInfo(AString &s) const; +}; + +const unsigned k_WzAesExtra_Size = 7; + +struct CWzAesExtra +{ + UInt16 VendorVersion; // 1: AE-1, 2: AE-2, + // UInt16 VendorId; // 'A' 'E' + Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit + UInt16 Method; + + CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {} + + bool NeedCrc() const { return (VendorVersion == 1); } + + bool ParseFromSubBlock(const CExtraSubBlock &sb) + { + if (sb.ID != NFileHeader::NExtraID::kWzAES) + return false; + if (sb.Data.Size() < k_WzAesExtra_Size) + return false; + const Byte *p = (const Byte *)sb.Data; + VendorVersion = GetUi16(p); + if (p[2] != 'A' || p[3] != 'E') + return false; + Strength = p[4]; + // 9.31: The BUG was fixed: + Method = GetUi16(p + 5); + return true; + } + + void SetSubBlock(CExtraSubBlock &sb) const + { + sb.Data.Alloc(k_WzAesExtra_Size); + sb.ID = NFileHeader::NExtraID::kWzAES; + Byte *p = (Byte *)sb.Data; + p[0] = (Byte)VendorVersion; + p[1] = (Byte)(VendorVersion >> 8); + p[2] = 'A'; + p[3] = 'E'; + p[4] = Strength; + p[5] = (Byte)Method; + p[6] = (Byte)(Method >> 8); + } +}; + +namespace NStrongCrypto_AlgId +{ + const UInt16 kDES = 0x6601; + const UInt16 kRC2old = 0x6602; + const UInt16 k3DES168 = 0x6603; + const UInt16 k3DES112 = 0x6609; + const UInt16 kAES128 = 0x660E; + const UInt16 kAES192 = 0x660F; + const UInt16 kAES256 = 0x6610; + const UInt16 kRC2 = 0x6702; + const UInt16 kBlowfish = 0x6720; + const UInt16 kTwofish = 0x6721; + const UInt16 kRC4 = 0x6801; +} + +struct CStrongCryptoExtra +{ + UInt16 Format; + UInt16 AlgId; + UInt16 BitLen; + UInt16 Flags; + + bool ParseFromSubBlock(const CExtraSubBlock &sb) + { + if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt) + return false; + const Byte *p = (const Byte *)sb.Data; + if (sb.Data.Size() < 8) + return false; + Format = GetUi16(p + 0); + AlgId = GetUi16(p + 2); + BitLen = GetUi16(p + 4); + Flags = GetUi16(p + 6); + return (Format == 2); + } + + bool CertificateIsUsed() const { return (Flags > 0x0001); } +}; + + +struct CExtraBlock +{ + CObjectVector SubBlocks; + bool Error; + bool MinorError; + bool IsZip64; + bool IsZip64_Error; + + CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {} + + void Clear() + { + SubBlocks.Clear(); + IsZip64 = false; + } + + size_t GetSize() const + { + size_t res = 0; + FOR_VECTOR (i, SubBlocks) + res += SubBlocks[i].Data.Size() + 2 + 2; + return res; + } + + bool GetWzAes(CWzAesExtra &e) const + { + FOR_VECTOR (i, SubBlocks) + if (e.ParseFromSubBlock(SubBlocks[i])) + return true; + return false; + } + + bool HasWzAes() const + { + CWzAesExtra e; + return GetWzAes(e); + } + + bool GetStrongCrypto(CStrongCryptoExtra &e) const + { + FOR_VECTOR (i, SubBlocks) + if (e.ParseFromSubBlock(SubBlocks[i])) + return true; + return false; + } + + /* + bool HasStrongCrypto() const + { + CStrongCryptoExtra e; + return GetStrongCrypto(e); + } + */ + + bool GetNtfsTime(unsigned index, FILETIME &ft) const; + bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const; + + void PrintInfo(AString &s) const; + + void RemoveUnknownSubBlocks() + { + for (unsigned i = SubBlocks.Size(); i != 0;) + { + i--; + switch (SubBlocks[i].ID) + { + case NFileHeader::NExtraID::kStrongEncrypt: + case NFileHeader::NExtraID::kWzAES: + break; + default: + SubBlocks.Delete(i); + } + } + } +}; + + +class CLocalItem +{ +public: + UInt16 Flags; + UInt16 Method; + + /* + Zip specification doesn't mention that ExtractVersion field uses HostOS subfield. + 18.06: 7-Zip now doesn't use ExtractVersion::HostOS to detect codePage + */ + + CVersion ExtractVersion; + + UInt64 Size; + UInt64 PackSize; + UInt32 Time; + UInt32 Crc; + + UInt32 Disk; + + AString Name; + + CExtraBlock LocalExtra; + + unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; } + + UInt64 GetPackSizeWithDescriptor() const + { return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); } + + bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; } + bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; } + bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; } + bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); } + bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; } + bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; } + // bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; } + + unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; } + + bool IsDir() const; + + /* + void GetUnicodeString(const AString &s, UString &res) const + { + bool isUtf8 = IsUtf8(); + if (isUtf8) + if (ConvertUTF8ToUnicode(s, res)) + return; + MultiByteToUnicodeString2(res, s, GetCodePage()); + } + */ + +private: + + void SetFlag(unsigned bitMask, bool enable) + { + if (enable) + Flags = (UInt16)(Flags | bitMask); + else + Flags = (UInt16)(Flags & ~bitMask); + } + +public: + + void ClearFlags() { Flags = 0; } + void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); } + void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); } + // void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); } + void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); } + + UINT GetCodePage() const + { + if (IsUtf8()) + return CP_UTF8; + return CP_OEMCP; + } +}; + + +class CItem: public CLocalItem +{ +public: + CVersion MadeByVersion; + UInt16 InternalAttrib; + UInt32 ExternalAttrib; + + UInt64 LocalHeaderPos; + + CExtraBlock CentralExtra; + CByteBuffer Comment; + + bool FromLocal; + bool FromCentral; + + // CItem can be used as CLocalItem. So we must clear unused fields + CItem(): + InternalAttrib(0), + ExternalAttrib(0), + FromLocal(false), + FromCentral(false) + { + MadeByVersion.Version = 0; + MadeByVersion.HostOS = 0; + } + + const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); } + + bool IsDir() const; + UInt32 GetWinAttrib() const; + bool GetPosixAttrib(UInt32 &attrib) const; + + // 18.06: 0 instead of ExtractVersion.HostOS for local item + Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : (Byte)0; } + + void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const; + + bool IsThereCrc() const + { + if (Method == NFileHeader::NCompressionMethod::kWzAES) + { + CWzAesExtra aesField; + if (GetMainExtra().GetWzAes(aesField)) + return aesField.NeedCrc(); + } + return (Crc != 0 || !IsDir()); + } + + bool Is_MadeBy_Unix() const + { + if (!FromCentral) + return false; + return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix); + } + + UINT GetCodePage() const + { + // 18.06: now we use HostOS only from Central::MadeByVersion + if (IsUtf8()) + return CP_UTF8; + if (!FromCentral) + return CP_OEMCP; + Byte hostOS = MadeByVersion.HostOS; + return (UINT)(( + hostOS == NFileHeader::NHostOS::kFAT + || hostOS == NFileHeader::NHostOS::kNTFS + || hostOS == NFileHeader::NHostOS::kUnix // do we need it? + ) ? CP_OEMCP : CP_ACP); + } +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp index 9322a2027..63f1a7167 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -1,420 +1,420 @@ -// ZipOut.cpp - -#include "StdAfx.h" - -#include "../../../../C/7zCrc.h" - -#include "../../../Windows/TimeUtils.h" -#include "../../Common/OffsetStream.h" - -#include "ZipOut.h" - -namespace NArchive { -namespace NZip { - -HRESULT COutArchive::ClearRestriction() -{ - if (SetRestriction) - return SetRestriction->SetRestriction(0, 0); - return S_OK; -} - -HRESULT COutArchive::SetRestrictionFromCurrent() -{ - if (SetRestriction) - return SetRestriction->SetRestriction(m_Base + m_CurPos, (UInt64)(Int64)-1); - return S_OK; -} - -HRESULT COutArchive::Create(IOutStream *outStream) -{ - m_CurPos = 0; - if (!m_OutBuffer.Create(1 << 16)) - return E_OUTOFMEMORY; - m_Stream = outStream; - m_OutBuffer.SetStream(outStream); - m_OutBuffer.Init(); - - return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); -} - -void COutArchive::SeekToCurPos() -{ - HRESULT res = m_Stream->Seek((Int64)(m_Base + m_CurPos), STREAM_SEEK_SET, NULL); - if (res != S_OK) - throw CSystemException(res); -} - -#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF) -// #define DOES_NEED_ZIP64(v) (v >= 0) - - -void COutArchive::WriteBytes(const void *data, size_t size) -{ - m_OutBuffer.WriteBytes(data, size); - m_CurPos += size; -} - -void COutArchive::Write8(Byte b) -{ - m_OutBuffer.WriteByte(b); - m_CurPos++; -} - -void COutArchive::Write16(UInt16 val) -{ - Write8((Byte)val); - Write8((Byte)(val >> 8)); -} - -void COutArchive::Write32(UInt32 val) -{ - for (int i = 0; i < 4; i++) - { - Write8((Byte)val); - val >>= 8; - } -} - -void COutArchive::Write64(UInt64 val) -{ - for (int i = 0; i < 8; i++) - { - Write8((Byte)val); - val >>= 8; - } -} - -void COutArchive::WriteExtra(const CExtraBlock &extra) -{ - FOR_VECTOR (i, extra.SubBlocks) - { - const CExtraSubBlock &subBlock = extra.SubBlocks[i]; - Write16((UInt16)subBlock.ID); - Write16((UInt16)subBlock.Data.Size()); - WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size()); - } -} - -void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64) -{ - { - Byte ver = item.ExtractVersion.Version; - if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) - ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; - Write8(ver); - } - Write8(item.ExtractVersion.HostOS); - Write16(item.Flags); - Write16(item.Method); - Write32(item.Time); -} - - -#define WRITE_32_VAL_SPEC(_v_, _isZip64_) Write32((_isZip64_) ? 0xFFFFFFFF : (UInt32)(_v_)); - - -void COutArchive::WriteUtfName(const CItemOut &item) -{ - if (item.Name_Utf.Size() == 0) - return; - Write16(NFileHeader::NExtraID::kIzUnicodeName); - Write16((UInt16)(5 + item.Name_Utf.Size())); - Write8(1); // (1 = version) of that extra field - Write32(CrcCalc(item.Name.Ptr(), item.Name.Len())); - WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size()); -} - - -static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8); -static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4); - -void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs) -{ - if (writeNtfs) - { - // windows explorer ignores that extra - Write16(NFileHeader::NExtraID::kNTFS); - Write16(k_Ntfs_ExtraSize); - Write32(0); // reserved - Write16(NFileHeader::NNtfsExtra::kTagTime); - Write16(8 * 3); - WriteNtfsTime(item.Ntfs_MTime); - WriteNtfsTime(item.Ntfs_ATime); - WriteNtfsTime(item.Ntfs_CTime); - } - - if (item.Write_UnixTime) - { - // windows explorer ignores that extra - // by specification : should we write to local header also? - Write16(NFileHeader::NExtraID::kUnixTime); - Write16(k_UnixTime_ExtraSize); - const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime); - Write8(flags); - UInt32 unixTime; - NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime); - Write32(unixTime); - } -} - - -void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck) -{ - m_LocalHeaderPos = m_CurPos; - item.LocalHeaderPos = m_CurPos; - - bool isZip64 = - DOES_NEED_ZIP64(item.PackSize) || - DOES_NEED_ZIP64(item.Size); - - if (needCheck && m_IsZip64) - isZip64 = true; - - // Why don't we write NTFS timestamps to local header? - // Probably we want to reduce size of archive? - const bool writeNtfs = false; // do not write NTFS timestamp to local header - // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header - const UInt32 localExtraSize = (UInt32)( - (isZip64 ? (4 + 8 + 8): 0) - + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0) - + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0) - + item.Get_UtfName_ExtraSize() - + item.LocalExtra.GetSize()); - if ((UInt16)localExtraSize != localExtraSize) - throw CSystemException(E_FAIL); - if (needCheck && m_ExtraSize != localExtraSize) - throw CSystemException(E_FAIL); - - m_IsZip64 = isZip64; - m_ExtraSize = localExtraSize; - - item.LocalExtra.IsZip64 = isZip64; - - Write32(NSignature::kLocalFileHeader); - - WriteCommonItemInfo(item, isZip64); - - Write32(item.HasDescriptor() ? 0 : item.Crc); - - UInt64 packSize = item.PackSize; - UInt64 size = item.Size; - - if (item.HasDescriptor()) - { - packSize = 0; - size = 0; - } - - WRITE_32_VAL_SPEC(packSize, isZip64) - WRITE_32_VAL_SPEC(size, isZip64) - - Write16((UInt16)item.Name.Len()); - - Write16((UInt16)localExtraSize); - - WriteBytes((const char *)item.Name, (UInt16)item.Name.Len()); - - if (isZip64) - { - Write16(NFileHeader::NExtraID::kZip64); - Write16(8 + 8); - Write64(size); - Write64(packSize); - } - - WriteTimeExtra(item, writeNtfs); - - WriteUtfName(item); - - WriteExtra(item.LocalExtra); - - const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos); - if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) - throw CSystemException(E_FAIL); - m_LocalFileHeaderSize = localFileHeaderSize; - - m_OutBuffer.FlushWithCheck(); -} - - -void COutArchive::WriteLocalHeader_Replace(CItemOut &item) -{ - m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize; - - if (item.HasDescriptor()) - { - WriteDescriptor(item); - m_OutBuffer.FlushWithCheck(); - return; - // we don't replace local header, if we write Descriptor. - // so local header with Descriptor flag must be written to local header before. - } - - const UInt64 nextPos = m_CurPos; - m_CurPos = m_LocalHeaderPos; - SeekToCurPos(); - WriteLocalHeader(item, true); - m_CurPos = nextPos; - SeekToCurPos(); -} - - -void COutArchive::WriteDescriptor(const CItemOut &item) -{ - Byte buf[kDataDescriptorSize64]; - SetUi32(buf, NSignature::kDataDescriptor) - SetUi32(buf + 4, item.Crc) - unsigned descriptorSize; - if (m_IsZip64) - { - SetUi64(buf + 8, item.PackSize) - SetUi64(buf + 16, item.Size) - descriptorSize = kDataDescriptorSize64; - } - else - { - SetUi32(buf + 8, (UInt32)item.PackSize) - SetUi32(buf + 12, (UInt32)item.Size) - descriptorSize = kDataDescriptorSize32; - } - WriteBytes(buf, descriptorSize); -} - - - -void COutArchive::WriteCentralHeader(const CItemOut &item) -{ - const bool isUnPack64 = DOES_NEED_ZIP64(item.Size); - const bool isPack64 = DOES_NEED_ZIP64(item.PackSize); - const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); - const bool isZip64 = isPack64 || isUnPack64 || isPosition64; - - Write32(NSignature::kCentralFileHeader); - Write8(item.MadeByVersion.Version); - Write8(item.MadeByVersion.HostOS); - - WriteCommonItemInfo(item, isZip64); - Write32(item.Crc); - - WRITE_32_VAL_SPEC(item.PackSize, isPack64) - WRITE_32_VAL_SPEC(item.Size, isUnPack64) - - Write16((UInt16)item.Name.Len()); - - const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); - const bool writeNtfs = item.Write_NtfsTime; - const size_t centralExtraSize = - (isZip64 ? 4 + zip64ExtraSize : 0) - + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0) - + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0) - + item.Get_UtfName_ExtraSize() - + item.CentralExtra.GetSize(); - - const UInt16 centralExtraSize16 = (UInt16)centralExtraSize; - if (centralExtraSize16 != centralExtraSize) - throw CSystemException(E_FAIL); - - Write16(centralExtraSize16); - - const UInt16 commentSize = (UInt16)item.Comment.Size(); - - Write16(commentSize); - Write16(0); // DiskNumberStart - Write16(item.InternalAttrib); - Write32(item.ExternalAttrib); - WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64) - WriteBytes((const char *)item.Name, item.Name.Len()); - - if (isZip64) - { - Write16(NFileHeader::NExtraID::kZip64); - Write16(zip64ExtraSize); - if (isUnPack64) - Write64(item.Size); - if (isPack64) - Write64(item.PackSize); - if (isPosition64) - Write64(item.LocalHeaderPos); - } - - WriteTimeExtra(item, writeNtfs); - WriteUtfName(item); - - WriteExtra(item.CentralExtra); - if (commentSize != 0) - WriteBytes(item.Comment, commentSize); -} - -HRESULT COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) -{ - RINOK(ClearRestriction()) - - const UInt64 cdOffset = GetCurPos(); - FOR_VECTOR (i, items) - WriteCentralHeader(items[i]); - const UInt64 cd64EndOffset = GetCurPos(); - const UInt64 cdSize = cd64EndOffset - cdOffset; - const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); - const bool cdSize64 = DOES_NEED_ZIP64(cdSize); - const bool items64 = items.Size() >= 0xFFFF; - const bool isZip64 = (cdOffset64 || cdSize64 || items64); - - // isZip64 = true; // to test Zip64 - - if (isZip64) - { - Write32(NSignature::kEcd64); - Write64(kEcd64_MainSize); - - // to test extra block: - // const UInt32 extraSize = 1 << 26; - // Write64(kEcd64_MainSize + extraSize); - - Write16(45); // made by version - Write16(45); // extract version - Write32(0); // ThisDiskNumber - Write32(0); // StartCentralDirectoryDiskNumber - Write64((UInt64)items.Size()); - Write64((UInt64)items.Size()); - Write64((UInt64)cdSize); - Write64((UInt64)cdOffset); - - // for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1); - - Write32(NSignature::kEcd64Locator); - Write32(0); // number of the disk with the start of the zip64 end of central directory - Write64(cd64EndOffset); - Write32(1); // total number of disks - } - - Write32(NSignature::kEcd); - Write16(0); // ThisDiskNumber - Write16(0); // StartCentralDirectoryDiskNumber - Write16((UInt16)(items64 ? 0xFFFF: items.Size())); - Write16((UInt16)(items64 ? 0xFFFF: items.Size())); - - WRITE_32_VAL_SPEC(cdSize, cdSize64) - WRITE_32_VAL_SPEC(cdOffset, cdOffset64) - - const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0); - Write16((UInt16)commentSize); - if (commentSize != 0) - WriteBytes((const Byte *)*comment, commentSize); - m_OutBuffer.FlushWithCheck(); - return S_OK; -} - -void COutArchive::CreateStreamForCompressing(CMyComPtr &outStream) -{ - COffsetOutStream *streamSpec = new COffsetOutStream; - outStream = streamSpec; - streamSpec->Init(m_Stream, m_Base + m_CurPos); -} - -void COutArchive::CreateStreamForCopying(CMyComPtr &outStream) -{ - outStream = m_Stream; -} - -}} +// ZipOut.cpp + +#include "StdAfx.h" + +#include "../../../../C/7zCrc.h" + +#include "../../../Windows/TimeUtils.h" +#include "../../Common/OffsetStream.h" + +#include "ZipOut.h" + +namespace NArchive { +namespace NZip { + +HRESULT COutArchive::ClearRestriction() +{ + if (SetRestriction) + return SetRestriction->SetRestriction(0, 0); + return S_OK; +} + +HRESULT COutArchive::SetRestrictionFromCurrent() +{ + if (SetRestriction) + return SetRestriction->SetRestriction(m_Base + m_CurPos, (UInt64)(Int64)-1); + return S_OK; +} + +HRESULT COutArchive::Create(IOutStream *outStream) +{ + m_CurPos = 0; + if (!m_OutBuffer.Create(1 << 16)) + return E_OUTOFMEMORY; + m_Stream = outStream; + m_OutBuffer.SetStream(outStream); + m_OutBuffer.Init(); + + return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); +} + +void COutArchive::SeekToCurPos() +{ + HRESULT res = m_Stream->Seek((Int64)(m_Base + m_CurPos), STREAM_SEEK_SET, NULL); + if (res != S_OK) + throw CSystemException(res); +} + +#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF) +// #define DOES_NEED_ZIP64(v) (v >= 0) + + +void COutArchive::WriteBytes(const void *data, size_t size) +{ + m_OutBuffer.WriteBytes(data, size); + m_CurPos += size; +} + +void COutArchive::Write8(Byte b) +{ + m_OutBuffer.WriteByte(b); + m_CurPos++; +} + +void COutArchive::Write16(UInt16 val) +{ + Write8((Byte)val); + Write8((Byte)(val >> 8)); +} + +void COutArchive::Write32(UInt32 val) +{ + for (int i = 0; i < 4; i++) + { + Write8((Byte)val); + val >>= 8; + } +} + +void COutArchive::Write64(UInt64 val) +{ + for (int i = 0; i < 8; i++) + { + Write8((Byte)val); + val >>= 8; + } +} + +void COutArchive::WriteExtra(const CExtraBlock &extra) +{ + FOR_VECTOR (i, extra.SubBlocks) + { + const CExtraSubBlock &subBlock = extra.SubBlocks[i]; + Write16((UInt16)subBlock.ID); + Write16((UInt16)subBlock.Data.Size()); + WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size()); + } +} + +void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64) +{ + { + Byte ver = item.ExtractVersion.Version; + if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64) + ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64; + Write8(ver); + } + Write8(item.ExtractVersion.HostOS); + Write16(item.Flags); + Write16(item.Method); + Write32(item.Time); +} + + +#define WRITE_32_VAL_SPEC(_v_, _isZip64_) Write32((_isZip64_) ? 0xFFFFFFFF : (UInt32)(_v_)); + + +void COutArchive::WriteUtfName(const CItemOut &item) +{ + if (item.Name_Utf.Size() == 0) + return; + Write16(NFileHeader::NExtraID::kIzUnicodeName); + Write16((UInt16)(5 + item.Name_Utf.Size())); + Write8(1); // (1 = version) of that extra field + Write32(CrcCalc(item.Name.Ptr(), item.Name.Len())); + WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size()); +} + + +static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8); +static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4); + +void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs) +{ + if (writeNtfs) + { + // windows explorer ignores that extra + Write16(NFileHeader::NExtraID::kNTFS); + Write16(k_Ntfs_ExtraSize); + Write32(0); // reserved + Write16(NFileHeader::NNtfsExtra::kTagTime); + Write16(8 * 3); + WriteNtfsTime(item.Ntfs_MTime); + WriteNtfsTime(item.Ntfs_ATime); + WriteNtfsTime(item.Ntfs_CTime); + } + + if (item.Write_UnixTime) + { + // windows explorer ignores that extra + // by specification : should we write to local header also? + Write16(NFileHeader::NExtraID::kUnixTime); + Write16(k_UnixTime_ExtraSize); + const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime); + Write8(flags); + UInt32 unixTime; + NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime); + Write32(unixTime); + } +} + + +void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck) +{ + m_LocalHeaderPos = m_CurPos; + item.LocalHeaderPos = m_CurPos; + + bool isZip64 = + DOES_NEED_ZIP64(item.PackSize) || + DOES_NEED_ZIP64(item.Size); + + if (needCheck && m_IsZip64) + isZip64 = true; + + // Why don't we write NTFS timestamps to local header? + // Probably we want to reduce size of archive? + const bool writeNtfs = false; // do not write NTFS timestamp to local header + // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header + const UInt32 localExtraSize = (UInt32)( + (isZip64 ? (4 + 8 + 8): 0) + + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0) + + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0) + + item.Get_UtfName_ExtraSize() + + item.LocalExtra.GetSize()); + if ((UInt16)localExtraSize != localExtraSize) + throw CSystemException(E_FAIL); + if (needCheck && m_ExtraSize != localExtraSize) + throw CSystemException(E_FAIL); + + m_IsZip64 = isZip64; + m_ExtraSize = localExtraSize; + + item.LocalExtra.IsZip64 = isZip64; + + Write32(NSignature::kLocalFileHeader); + + WriteCommonItemInfo(item, isZip64); + + Write32(item.HasDescriptor() ? 0 : item.Crc); + + UInt64 packSize = item.PackSize; + UInt64 size = item.Size; + + if (item.HasDescriptor()) + { + packSize = 0; + size = 0; + } + + WRITE_32_VAL_SPEC(packSize, isZip64) + WRITE_32_VAL_SPEC(size, isZip64) + + Write16((UInt16)item.Name.Len()); + + Write16((UInt16)localExtraSize); + + WriteBytes((const char *)item.Name, (UInt16)item.Name.Len()); + + if (isZip64) + { + Write16(NFileHeader::NExtraID::kZip64); + Write16(8 + 8); + Write64(size); + Write64(packSize); + } + + WriteTimeExtra(item, writeNtfs); + + WriteUtfName(item); + + WriteExtra(item.LocalExtra); + + const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos); + if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) + throw CSystemException(E_FAIL); + m_LocalFileHeaderSize = localFileHeaderSize; + + m_OutBuffer.FlushWithCheck(); +} + + +void COutArchive::WriteLocalHeader_Replace(CItemOut &item) +{ + m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize; + + if (item.HasDescriptor()) + { + WriteDescriptor(item); + m_OutBuffer.FlushWithCheck(); + return; + // we don't replace local header, if we write Descriptor. + // so local header with Descriptor flag must be written to local header before. + } + + const UInt64 nextPos = m_CurPos; + m_CurPos = m_LocalHeaderPos; + SeekToCurPos(); + WriteLocalHeader(item, true); + m_CurPos = nextPos; + SeekToCurPos(); +} + + +void COutArchive::WriteDescriptor(const CItemOut &item) +{ + Byte buf[kDataDescriptorSize64]; + SetUi32(buf, NSignature::kDataDescriptor) + SetUi32(buf + 4, item.Crc) + unsigned descriptorSize; + if (m_IsZip64) + { + SetUi64(buf + 8, item.PackSize) + SetUi64(buf + 16, item.Size) + descriptorSize = kDataDescriptorSize64; + } + else + { + SetUi32(buf + 8, (UInt32)item.PackSize) + SetUi32(buf + 12, (UInt32)item.Size) + descriptorSize = kDataDescriptorSize32; + } + WriteBytes(buf, descriptorSize); +} + + + +void COutArchive::WriteCentralHeader(const CItemOut &item) +{ + const bool isUnPack64 = DOES_NEED_ZIP64(item.Size); + const bool isPack64 = DOES_NEED_ZIP64(item.PackSize); + const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); + const bool isZip64 = isPack64 || isUnPack64 || isPosition64; + + Write32(NSignature::kCentralFileHeader); + Write8(item.MadeByVersion.Version); + Write8(item.MadeByVersion.HostOS); + + WriteCommonItemInfo(item, isZip64); + Write32(item.Crc); + + WRITE_32_VAL_SPEC(item.PackSize, isPack64) + WRITE_32_VAL_SPEC(item.Size, isUnPack64) + + Write16((UInt16)item.Name.Len()); + + const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); + const bool writeNtfs = item.Write_NtfsTime; + const size_t centralExtraSize = + (isZip64 ? 4 + zip64ExtraSize : 0) + + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0) + + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0) + + item.Get_UtfName_ExtraSize() + + item.CentralExtra.GetSize(); + + const UInt16 centralExtraSize16 = (UInt16)centralExtraSize; + if (centralExtraSize16 != centralExtraSize) + throw CSystemException(E_FAIL); + + Write16(centralExtraSize16); + + const UInt16 commentSize = (UInt16)item.Comment.Size(); + + Write16(commentSize); + Write16(0); // DiskNumberStart + Write16(item.InternalAttrib); + Write32(item.ExternalAttrib); + WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64) + WriteBytes((const char *)item.Name, item.Name.Len()); + + if (isZip64) + { + Write16(NFileHeader::NExtraID::kZip64); + Write16(zip64ExtraSize); + if (isUnPack64) + Write64(item.Size); + if (isPack64) + Write64(item.PackSize); + if (isPosition64) + Write64(item.LocalHeaderPos); + } + + WriteTimeExtra(item, writeNtfs); + WriteUtfName(item); + + WriteExtra(item.CentralExtra); + if (commentSize != 0) + WriteBytes(item.Comment, commentSize); +} + +HRESULT COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) +{ + RINOK(ClearRestriction()) + + const UInt64 cdOffset = GetCurPos(); + FOR_VECTOR (i, items) + WriteCentralHeader(items[i]); + const UInt64 cd64EndOffset = GetCurPos(); + const UInt64 cdSize = cd64EndOffset - cdOffset; + const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); + const bool cdSize64 = DOES_NEED_ZIP64(cdSize); + const bool items64 = items.Size() >= 0xFFFF; + const bool isZip64 = (cdOffset64 || cdSize64 || items64); + + // isZip64 = true; // to test Zip64 + + if (isZip64) + { + Write32(NSignature::kEcd64); + Write64(kEcd64_MainSize); + + // to test extra block: + // const UInt32 extraSize = 1 << 26; + // Write64(kEcd64_MainSize + extraSize); + + Write16(45); // made by version + Write16(45); // extract version + Write32(0); // ThisDiskNumber + Write32(0); // StartCentralDirectoryDiskNumber + Write64((UInt64)items.Size()); + Write64((UInt64)items.Size()); + Write64((UInt64)cdSize); + Write64((UInt64)cdOffset); + + // for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1); + + Write32(NSignature::kEcd64Locator); + Write32(0); // number of the disk with the start of the zip64 end of central directory + Write64(cd64EndOffset); + Write32(1); // total number of disks + } + + Write32(NSignature::kEcd); + Write16(0); // ThisDiskNumber + Write16(0); // StartCentralDirectoryDiskNumber + Write16((UInt16)(items64 ? 0xFFFF: items.Size())); + Write16((UInt16)(items64 ? 0xFFFF: items.Size())); + + WRITE_32_VAL_SPEC(cdSize, cdSize64) + WRITE_32_VAL_SPEC(cdOffset, cdOffset64) + + const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0); + Write16((UInt16)commentSize); + if (commentSize != 0) + WriteBytes((const Byte *)*comment, commentSize); + m_OutBuffer.FlushWithCheck(); + return S_OK; +} + +void COutArchive::CreateStreamForCompressing(CMyComPtr &outStream) +{ + COffsetOutStream *streamSpec = new COffsetOutStream; + outStream = streamSpec; + streamSpec->Init(m_Stream, m_Base + m_CurPos); +} + +void COutArchive::CreateStreamForCopying(CMyComPtr &outStream) +{ + outStream = m_Stream; +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h index a88222838..e9b2abbc0 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ b/CPP/7zip/Archive/Zip/ZipOut.h @@ -1,103 +1,103 @@ -// ZipOut.h - -#ifndef ZIP7_INC_ZIP_OUT_H -#define ZIP7_INC_ZIP_OUT_H - -#include "../../../Common/MyCom.h" - -#include "../../Common/OutBuffer.h" - -#include "ZipItem.h" - -namespace NArchive { -namespace NZip { - -class CItemOut: public CItem -{ -public: - FILETIME Ntfs_MTime; - FILETIME Ntfs_ATime; - FILETIME Ntfs_CTime; - bool Write_NtfsTime; - bool Write_UnixTime; - - // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. - - CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra - - size_t Get_UtfName_ExtraSize() const - { - const size_t size = Name_Utf.Size(); - if (size == 0) - return 0; - return 4 + 5 + size; - } - - CItemOut(): - Write_NtfsTime(false), - Write_UnixTime(false) - {} -}; - - -// COutArchive can throw CSystemException and COutBufferException - -class COutArchive -{ - COutBuffer m_OutBuffer; - CMyComPtr m_Stream; - - UInt64 m_Base; // Base of archive (offset in output Stream) - UInt64 m_CurPos; // Curent position in archive (relative from m_Base) - UInt64 m_LocalHeaderPos; // LocalHeaderPos (relative from m_Base) for last WriteLocalHeader() call - - UInt32 m_LocalFileHeaderSize; - UInt32 m_ExtraSize; - bool m_IsZip64; - - void WriteBytes(const void *data, size_t size); - void Write8(Byte b); - void Write16(UInt16 val); - void Write32(UInt32 val); - void Write64(UInt64 val); - void WriteNtfsTime(const FILETIME &ft) - { - Write32(ft.dwLowDateTime); - Write32(ft.dwHighDateTime); - } - - void WriteTimeExtra(const CItemOut &item, bool writeNtfs); - void WriteUtfName(const CItemOut &item); - void WriteExtra(const CExtraBlock &extra); - void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); - void WriteCentralHeader(const CItemOut &item); - - void SeekToCurPos(); -public: - CMyComPtr SetRestriction; - - HRESULT ClearRestriction(); - HRESULT SetRestrictionFromCurrent(); - HRESULT Create(IOutStream *outStream); - - UInt64 GetCurPos() const { return m_CurPos; } - - void MoveCurPos(UInt64 distanceToMove) - { - m_CurPos += distanceToMove; - } - - void WriteLocalHeader(CItemOut &item, bool needCheck = false); - void WriteLocalHeader_Replace(CItemOut &item); - - void WriteDescriptor(const CItemOut &item); - - HRESULT WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment); - - void CreateStreamForCompressing(CMyComPtr &outStream); - void CreateStreamForCopying(CMyComPtr &outStream); -}; - -}} - -#endif +// ZipOut.h + +#ifndef ZIP7_INC_ZIP_OUT_H +#define ZIP7_INC_ZIP_OUT_H + +#include "../../../Common/MyCom.h" + +#include "../../Common/OutBuffer.h" + +#include "ZipItem.h" + +namespace NArchive { +namespace NZip { + +class CItemOut: public CItem +{ +public: + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; + bool Write_NtfsTime; + bool Write_UnixTime; + + // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. + + CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra + + size_t Get_UtfName_ExtraSize() const + { + const size_t size = Name_Utf.Size(); + if (size == 0) + return 0; + return 4 + 5 + size; + } + + CItemOut(): + Write_NtfsTime(false), + Write_UnixTime(false) + {} +}; + + +// COutArchive can throw CSystemException and COutBufferException + +class COutArchive +{ + COutBuffer m_OutBuffer; + CMyComPtr m_Stream; + + UInt64 m_Base; // Base of archive (offset in output Stream) + UInt64 m_CurPos; // Curent position in archive (relative from m_Base) + UInt64 m_LocalHeaderPos; // LocalHeaderPos (relative from m_Base) for last WriteLocalHeader() call + + UInt32 m_LocalFileHeaderSize; + UInt32 m_ExtraSize; + bool m_IsZip64; + + void WriteBytes(const void *data, size_t size); + void Write8(Byte b); + void Write16(UInt16 val); + void Write32(UInt32 val); + void Write64(UInt64 val); + void WriteNtfsTime(const FILETIME &ft) + { + Write32(ft.dwLowDateTime); + Write32(ft.dwHighDateTime); + } + + void WriteTimeExtra(const CItemOut &item, bool writeNtfs); + void WriteUtfName(const CItemOut &item); + void WriteExtra(const CExtraBlock &extra); + void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); + void WriteCentralHeader(const CItemOut &item); + + void SeekToCurPos(); +public: + CMyComPtr SetRestriction; + + HRESULT ClearRestriction(); + HRESULT SetRestrictionFromCurrent(); + HRESULT Create(IOutStream *outStream); + + UInt64 GetCurPos() const { return m_CurPos; } + + void MoveCurPos(UInt64 distanceToMove) + { + m_CurPos += distanceToMove; + } + + void WriteLocalHeader(CItemOut &item, bool needCheck = false); + void WriteLocalHeader_Replace(CItemOut &item); + + void WriteDescriptor(const CItemOut &item); + + HRESULT WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment); + + void CreateStreamForCompressing(CMyComPtr &outStream); + void CreateStreamForCopying(CMyComPtr &outStream); +}; + +}} + +#endif diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp index ad2ede0f3..c17a1a3d2 100644 --- a/CPP/7zip/Archive/Zip/ZipRegister.cpp +++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp @@ -1,38 +1,38 @@ -// ZipRegister.cpp - -#include "StdAfx.h" - -#include "../../Common/RegisterArc.h" - -#include "ZipHandler.h" - -namespace NArchive { -namespace NZip { - -static const Byte k_Signature[] = { - 4, 0x50, 0x4B, 0x03, 0x04, // Local - 4, 0x50, 0x4B, 0x05, 0x06, // Ecd - 4, 0x50, 0x4B, 0x06, 0x06, // Ecd64 - 6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, // Span / Descriptor - 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; // NoSpan - -REGISTER_ARC_IO( - "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", NULL, 1, - k_Signature, - 0, - NArcInfoFlags::kFindSignature - | NArcInfoFlags::kMultiSignature - | NArcInfoFlags::kUseGlobalOffset - | NArcInfoFlags::kCTime - // | NArcInfoFlags::kCTime_Default - | NArcInfoFlags::kATime - // | NArcInfoFlags::kATime_Default - | NArcInfoFlags::kMTime - | NArcInfoFlags::kMTime_Default - , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) - | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) - | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS) - | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows) - , IsArc_Zip) - -}} +// ZipRegister.cpp + +#include "StdAfx.h" + +#include "../../Common/RegisterArc.h" + +#include "ZipHandler.h" + +namespace NArchive { +namespace NZip { + +static const Byte k_Signature[] = { + 4, 0x50, 0x4B, 0x03, 0x04, // Local + 4, 0x50, 0x4B, 0x05, 0x06, // Ecd + 4, 0x50, 0x4B, 0x06, 0x06, // Ecd64 + 6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, // Span / Descriptor + 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; // NoSpan + +REGISTER_ARC_IO( + "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", NULL, 1, + k_Signature, + 0, + NArcInfoFlags::kFindSignature + | NArcInfoFlags::kMultiSignature + | NArcInfoFlags::kUseGlobalOffset + | NArcInfoFlags::kCTime + // | NArcInfoFlags::kCTime_Default + | NArcInfoFlags::kATime + // | NArcInfoFlags::kATime_Default + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows) + , IsArc_Zip) + +}} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp index 844fc06e0..bc047b768 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -1,2140 +1,2140 @@ -// ZipUpdate.cpp - -#include "StdAfx.h" - -// #define DEBUG_CACHE - -#ifdef DEBUG_CACHE -#include - #define PRF(x) x -#else - #define PRF(x) -#endif - -#include "../../../../C/Alloc.h" - -#include "../../../Common/AutoPtr.h" -#include "../../../Common/Defs.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/TimeUtils.h" -#include "../../../Windows/Thread.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/OutMemStream.h" -#include "../../Common/ProgressUtils.h" -#ifndef Z7_ST -#include "../../Common/ProgressMt.h" -#endif -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" -// #include "../../Compress/ZstdEncoderProps.h" - -#include "ZipAddCommon.h" -#include "ZipOut.h" -#include "ZipUpdate.h" - -using namespace NWindows; -using namespace NSynchronization; - -namespace NArchive { -namespace NZip { - -static const Byte kHostOS = - #ifdef _WIN32 - NFileHeader::NHostOS::kFAT; - #else - NFileHeader::NHostOS::kUnix; - #endif - -static const Byte kMadeByHostOS = kHostOS; - -// 18.06: now we always write zero to high byte of ExtractVersion field. -// Previous versions of p7zip wrote (NFileHeader::NHostOS::kUnix) there, that is not correct -static const Byte kExtractHostOS = 0; - -static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore; - - -static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method) -{ - CWzAesExtra wzAesField; - wzAesField.Strength = aesKeyMode; - wzAesField.Method = method; - item.Method = NFileHeader::NCompressionMethod::kWzAES; - item.Crc = 0; - CExtraSubBlock sb; - wzAesField.SetSubBlock(sb); - item.LocalExtra.SubBlocks.Add(sb); - item.CentralExtra.SubBlocks.Add(sb); -} - - -static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &item) -{ - item.Name = ui.Name; - item.Name_Utf = ui.Name_Utf; - item.Comment = ui.Comment; - item.SetUtf8(ui.IsUtf8); - // item.SetFlag_AltStream(ui.IsAltStream); - // item.ExternalAttrib = ui.Attrib; - item.Time = ui.Time; - item.Ntfs_MTime = ui.Ntfs_MTime; - item.Ntfs_ATime = ui.Ntfs_ATime; - item.Ntfs_CTime = ui.Ntfs_CTime; - - item.Write_UnixTime = ui.Write_UnixTime; - item.Write_NtfsTime = ui.Write_NtfsTime; -} - -static void SetFileHeader( - const CCompressionMethodMode &options, - const CUpdateItem &ui, - bool useDescriptor, - CItemOut &item) -{ - item.Size = ui.Size; - const bool isDir = ui.IsDir; - - item.ClearFlags(); - - if (ui.NewProps) - { - Copy_From_UpdateItem_To_ItemOut(ui, item); - // item.SetFlag_AltStream(ui.IsAltStream); - item.ExternalAttrib = ui.Attrib; - } - /* - else - isDir = item.IsDir(); - */ - - item.MadeByVersion.HostOS = kMadeByHostOS; - item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion; - - item.ExtractVersion.HostOS = kExtractHostOS; - - item.InternalAttrib = 0; // test it - item.SetEncrypted(!isDir && options.Password_Defined); - item.SetDescriptorMode(useDescriptor); - - if (isDir) - { - item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; - item.Method = kMethodForDirectory; - item.PackSize = 0; - item.Size = 0; - item.Crc = 0; - } - - item.LocalExtra.Clear(); - item.CentralExtra.Clear(); - - if (isDir) - { - item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; - item.Method = kMethodForDirectory; - item.PackSize = 0; - item.Size = 0; - item.Crc = 0; - } - else if (options.IsRealAesMode()) - AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0])); -} - - -// we call SetItemInfoFromCompressingResult() after SetFileHeader() - -static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult, - bool isAesMode, Byte aesKeyMode, CItem &item) -{ - item.ExtractVersion.Version = compressingResult.ExtractVersion; - item.Method = compressingResult.Method; - if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos) - item.Flags |= NFileHeader::NFlags::kLzmaEOS; - item.Crc = compressingResult.CRC; - item.Size = compressingResult.UnpackSize; - item.PackSize = compressingResult.PackSize; - - item.LocalExtra.Clear(); - item.CentralExtra.Clear(); - - if (isAesMode) - AddAesExtra(item, aesKeyMode, compressingResult.Method); -} - - -#ifndef Z7_ST - -struct CMtSem -{ - NWindows::NSynchronization::CSemaphore Semaphore; - NWindows::NSynchronization::CCriticalSection CS; - CIntVector Indexes; - int Head; - - void ReleaseItem(unsigned index) - { - { - CCriticalSectionLock lock(CS); - Indexes[index] = Head; - Head = (int)index; - } - Semaphore.Release(); - } - - int GetFreeItem() - { - int i; - { - CCriticalSectionLock lock(CS); - i = Head; - Head = Indexes[(unsigned)i]; - } - return i; - } -}; - -static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); - -struct CThreadInfo -{ - DECL_EXTERNAL_CODECS_LOC_VARS_DECL - - NWindows::CThread Thread; - NWindows::NSynchronization::CAutoResetEvent CompressEvent; - CMtSem *MtSem; - unsigned ThreadIndex; - - bool ExitThread; - - CMtCompressProgress *ProgressSpec; - CMyComPtr Progress; - - COutMemStream *OutStreamSpec; - CMyComPtr OutStream; - CMyComPtr InStream; - - CAddCommon Coder; - HRESULT Result; - CCompressingResult CompressingResult; - - bool IsFree; - bool InSeqMode; - bool OutSeqMode; - bool ExpectedDataSize_IsConfirmed; - - UInt32 UpdateIndex; - UInt32 FileTime; - UInt64 ExpectedDataSize; - - CThreadInfo(): - MtSem(NULL), - ExitThread(false), - ProgressSpec(NULL), - OutStreamSpec(NULL), - IsFree(true), - InSeqMode(false), - OutSeqMode(false), - ExpectedDataSize_IsConfirmed(false), - FileTime(0), - ExpectedDataSize((UInt64)(Int64)-1) - {} - - void SetOptions(const CCompressionMethodMode &options) - { - Coder.SetOptions(options); - } - - HRESULT CreateEvents() - { - WRes wres = CompressEvent.CreateIfNotCreated_Reset(); - return HRESULT_FROM_WIN32(wres); - } - - HRESULT CreateThread() - { - WRes wres = Thread.Create(CoderThread, this); - return HRESULT_FROM_WIN32(wres); - } - - void WaitAndCode(); - - void StopWait_Close() - { - ExitThread = true; - if (OutStreamSpec) - OutStreamSpec->StopWriting(E_ABORT); - if (CompressEvent.IsCreated()) - CompressEvent.Set(); - Thread.Wait_Close(); - } -}; - -void CThreadInfo::WaitAndCode() -{ - for (;;) - { - CompressEvent.Lock(); - if (ExitThread) - return; - - Result = Coder.Compress( - EXTERNAL_CODECS_LOC_VARS - InStream, OutStream, - InSeqMode, OutSeqMode, FileTime, ExpectedDataSize, - ExpectedDataSize_IsConfirmed, - Progress, CompressingResult); - - if (Result == S_OK && Progress) - Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); - - MtSem->ReleaseItem(ThreadIndex); - } -} - -static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo) -{ - ((CThreadInfo *)threadCoderInfo)->WaitAndCode(); - return 0; -} - -class CThreads -{ -public: - CObjectVector Threads; - ~CThreads() - { - FOR_VECTOR (i, Threads) - Threads[i].StopWait_Close(); - } -}; - -struct CMemBlocks2: public CMemLockBlocks -{ - bool Skip; - bool InSeqMode; - bool PreDescriptorMode; - bool Finished; - CCompressingResult CompressingResult; - - CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false), - CompressingResult() {} -}; - -class CMemRefs -{ -public: - CMemBlockManagerMt *Manager; - CObjectVector Refs; - CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} - ~CMemRefs() - { - FOR_VECTOR (i, Refs) - Refs[i].FreeOpt(Manager); - } -}; - - -Z7_CLASS_IMP_NOQIB_1( - CMtProgressMixer2 - , ICompressProgressInfo -) - UInt64 ProgressOffset; - UInt64 InSizes[2]; - UInt64 OutSizes[2]; - CMyComPtr Progress; - CMyComPtr RatioProgress; - bool _inSizeIsMain; -public: - NWindows::NSynchronization::CCriticalSection CriticalSection; - void Create(IProgress *progress, bool inSizeIsMain); - void SetProgressOffset(UInt64 progressOffset); - void SetProgressOffset_NoLock(UInt64 progressOffset); - HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize); -}; - -void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain) -{ - Progress = progress; - Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress); - _inSizeIsMain = inSizeIsMain; - ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0; -} - -void CMtProgressMixer2::SetProgressOffset_NoLock(UInt64 progressOffset) -{ - InSizes[1] = OutSizes[1] = 0; - ProgressOffset = progressOffset; -} - -void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset) -{ - CriticalSection.Enter(); - SetProgressOffset_NoLock(progressOffset); - CriticalSection.Leave(); -} - -HRESULT CMtProgressMixer2::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - if (index == 0 && RatioProgress) - { - RINOK(RatioProgress->SetRatioInfo(inSize, outSize)) - } - if (inSize) - InSizes[index] = *inSize; - if (outSize) - OutSizes[index] = *outSize; - UInt64 v = ProgressOffset + (_inSizeIsMain ? - (InSizes[0] + InSizes[1]) : - (OutSizes[0] + OutSizes[1])); - return Progress->SetCompleted(&v); -} - -Z7_COM7F_IMF(CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - return SetRatioInfo(0, inSize, outSize); -} - - -Z7_CLASS_IMP_NOQIB_1( - CMtProgressMixer - , ICompressProgressInfo -) -public: - CMtProgressMixer2 *Mixer2; - CMyComPtr RatioProgress; - void Create(IProgress *progress, bool inSizeIsMain); -}; - -void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain) -{ - Mixer2 = new CMtProgressMixer2; - RatioProgress = Mixer2; - Mixer2->Create(progress, inSizeIsMain); -} - -Z7_COM7F_IMF(CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - return Mixer2->SetRatioInfo(1, inSize, outSize); -} - - -#endif - -static HRESULT UpdateItemOldData( - COutArchive &archive, - CInArchive *inArchive, - const CItemEx &itemEx, - const CUpdateItem &ui, - CItemOut &item, - /* bool izZip64, */ - ICompressProgressInfo *progress, - IArchiveUpdateCallbackFile *opCallback, - UInt64 &complexity) -{ - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, - NUpdateNotifyOp::kReplicate)) - } - - UInt64 rangeSize; - - RINOK(archive.ClearRestriction()) - - if (ui.NewProps) - { - if (item.HasDescriptor()) - return E_NOTIMPL; - - // we keep ExternalAttrib and some another properties from old archive - // item.ExternalAttrib = ui.Attrib; - // if we don't change Comment, we keep Comment from OldProperties - Copy_From_UpdateItem_To_ItemOut(ui, item); - // item.SetFlag_AltStream(ui.IsAltStream); - - item.CentralExtra.RemoveUnknownSubBlocks(); - item.LocalExtra.RemoveUnknownSubBlocks(); - - archive.WriteLocalHeader(item); - rangeSize = item.GetPackSizeWithDescriptor(); - } - else - { - item.LocalHeaderPos = archive.GetCurPos(); - rangeSize = itemEx.GetLocalFullSize(); - } - - CMyComPtr packStream; - - RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)) - if (!packStream) - return E_NOTIMPL; - - complexity += rangeSize; - - CMyComPtr outStream; - archive.CreateStreamForCopying(outStream); - HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress); - archive.MoveCurPos(rangeSize); - return res; -} - - -static HRESULT WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, - const CUpdateItem &ui, CItemOut &item) -{ - SetFileHeader(*options, ui, false, item); - RINOK(archive.ClearRestriction()) - archive.WriteLocalHeader(item); - return S_OK; -} - - -static void UpdatePropsFromStream( - const CUpdateOptions &options, - CUpdateItem &item, ISequentialInStream *fileInStream, - IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) -{ - CMyComPtr getProps; - fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); - UInt64 size = (UInt64)(Int64)-1; - bool size_WasSet = false; - - if (getProps) - { - FILETIME cTime, aTime, mTime; - UInt32 attrib; - if (getProps->GetProps(&size, &cTime, &aTime, &mTime, &attrib) == S_OK) - { - if (options.Write_MTime) - if (!FILETIME_IsZero(mTime)) - { - item.Ntfs_MTime = mTime; - NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time); - } - - if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime; - if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime; - - item.Attrib = attrib; - size_WasSet = true; - } - } - - if (!size_WasSet) - { - CMyComPtr streamGetSize; - fileInStream->QueryInterface(IID_IStreamGetSize, (void **)&streamGetSize); - if (streamGetSize) - { - if (streamGetSize->GetSize(&size) == S_OK) - size_WasSet = true; - } - } - - if (size_WasSet && size != (UInt64)(Int64)-1) - { - item.Size_WasSetFromStream = true; - if (size != item.Size) - { - const Int64 newComplexity = (Int64)totalComplexity + ((Int64)size - (Int64)item.Size); - if (newComplexity > 0) - { - totalComplexity = (UInt64)newComplexity; - updateCallback->SetTotal(totalComplexity); - } - item.Size = size; - } - } -} - - -/* -static HRESULT ReportProps( - IArchiveUpdateCallbackArcProp *reportArcProp, - UInt32 index, - const CItemOut &item, - bool isAesMode) -{ - PROPVARIANT prop; - prop.vt = VT_EMPTY; - prop.wReserved1 = 0; - - NCOM::PropVarEm_Set_UInt64(&prop, item.Size); - RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop)); - - NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize); - RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop)); - - if (!isAesMode) - { - NCOM::PropVarEm_Set_UInt32(&prop, item.Crc); - RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop)); - } - - RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK)); - - // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished)) - - return S_OK; -} -*/ - -/* -struct CTotalStats -{ - UInt64 Size; - UInt64 PackSize; - - void UpdateWithItem(const CItemOut &item) - { - Size += item.Size; - PackSize += item.PackSize; - } -}; - -static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, - CTotalStats &st) -{ - PROPVARIANT prop; - prop.vt = VT_EMPTY; - prop.wReserved1 = 0; - { - NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size); - RINOK(reportArcProp->ReportProp( - NEventIndexType::kArcProp, 0, kpidSize, &prop)); - } - { - NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize); - RINOK(reportArcProp->ReportProp( - NEventIndexType::kArcProp, 0, kpidPackSize, &prop)); - } - return S_OK; -} -*/ - - -static HRESULT Update2St( - DECL_EXTERNAL_CODECS_LOC_VARS - COutArchive &archive, - CInArchive *inArchive, - const CObjectVector &inputItems, - CObjectVector &updateItems, - const CUpdateOptions &updateOptions, - const CCompressionMethodMode *options, bool outSeqMode, - const CByteBuffer *comment, - IArchiveUpdateCallback *updateCallback, - UInt64 &totalComplexity, - IArchiveUpdateCallbackFile *opCallback - // , IArchiveUpdateCallbackArcProp *reportArcProp - ) -{ - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - CAddCommon compressor; - compressor.SetOptions(*options); - - CObjectVector items; - UInt64 unpackSizeTotal = 0, packSizeTotal = 0; - - FOR_VECTOR (itemIndex, updateItems) - { - lps->InSize = unpackSizeTotal; - lps->OutSize = packSizeTotal; - RINOK(lps->SetCur()) - CUpdateItem &ui = updateItems[itemIndex]; - CItemEx itemEx; - CItemOut item; - - if (!ui.NewProps || !ui.NewData) - { - // Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive, - // But we will rewrite all important properties later. But we can keep some properties like Comment - itemEx = inputItems[(unsigned)ui.IndexInArc]; - if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK) - return E_NOTIMPL; - (CItem &)item = itemEx; - } - - if (ui.NewData) - { - // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); - bool isDir = ui.IsDir; - if (isDir) - { - RINOK(WriteDirHeader(archive, options, ui, item)) - } - else - { - CMyComPtr fileInStream; - { - HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); - if (res == S_FALSE) - { - lps->ProgressOffset += ui.Size; - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - continue; - } - RINOK(res) - if (!fileInStream) - return E_INVALIDARG; - - bool inSeqMode = false; - if (!inSeqMode) - { - CMyComPtr inStream2; - fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); - inSeqMode = (inStream2 == NULL); - } - // seqMode = true; // to test seqMode - - UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity); - - CCompressingResult compressingResult; - - RINOK(compressor.Set_Pre_CompressionResult( - inSeqMode, outSeqMode, - ui.Size, - compressingResult)) - - SetFileHeader(*options, ui, compressingResult.DescriptorMode, item); - - // file Size can be 64-bit !!! - - SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - - RINOK(archive.SetRestrictionFromCurrent()) - archive.WriteLocalHeader(item); - - CMyComPtr outStream; - archive.CreateStreamForCompressing(outStream); - - RINOK(compressor.Compress( - EXTERNAL_CODECS_LOC_VARS - fileInStream, outStream, - inSeqMode, outSeqMode, - ui.Time, - ui.Size, ui.Size_WasSetFromStream, - progress, compressingResult)) - - if (item.HasDescriptor() != compressingResult.DescriptorMode) - return E_FAIL; - - SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); - - archive.WriteLocalHeader_Replace(item); - } - // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode())) - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - unpackSizeTotal += item.Size; - packSizeTotal += item.PackSize; - } - } - else - { - UInt64 complexity = 0; - lps->SendRatio = false; - - RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)) - - lps->SendRatio = true; - lps->ProgressOffset += complexity; - } - - items.Add(item); - lps->ProgressOffset += kLocalHeaderSize; - } - - lps->InSize = unpackSizeTotal; - lps->OutSize = packSizeTotal; - RINOK(lps->SetCur()) - - RINOK(archive.WriteCentralDir(items, comment)) - - /* - CTotalStats stat; - stat.Size = unpackSizeTotal; - stat.PackSize = packSizeTotal; - if (reportArcProp) - RINOK(ReportArcProps(reportArcProp, stat)) - */ - - lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; - return lps->SetCur(); -} - -#ifndef Z7_ST - - -static const size_t kBlockSize = 1 << 16; -// kMemPerThread must be >= kBlockSize -// -static const size_t kMemPerThread = (size_t)sizeof(size_t) << 23; -// static const size_t kMemPerThread = (size_t)sizeof(size_t) << 16; // for debug -// static const size_t kMemPerThread = (size_t)1 << 16; // for debug - -/* -in: - nt_Zip >= 1: the starting maximum number of ZIP threads for search -out: - nt_Zip: calculated number of ZIP threads - returns: calculated number of ZSTD threads -*/ -/* -static UInt32 CalcThreads_for_ZipZstd(CZstdEncProps *zstdProps, - UInt64 memLimit, UInt32 totalThreads, - UInt32 &nt_Zip) -{ - for (; nt_Zip > 1; nt_Zip--) - { - UInt64 mem1 = memLimit / nt_Zip; - if (mem1 <= kMemPerThread) - continue; - mem1 -= kMemPerThread; - UInt32 n_ZSTD = ZstdEncProps_GetNumThreads_for_MemUsageLimit( - zstdProps, mem1, totalThreads / nt_Zip); - // we don't allow (nbWorkers == 1) here - if (n_ZSTD <= 1) - n_ZSTD = 0; - zstdProps->nbWorkers = n_ZSTD; - mem1 = ZstdEncProps_GetMemUsage(zstdProps); - if ((mem1 + kMemPerThread) * nt_Zip <= memLimit) - return n_ZSTD; - } - return ZstdEncProps_GetNumThreads_for_MemUsageLimit( - zstdProps, memLimit, totalThreads); -} - - -static UInt32 SetZstdThreads( - const CCompressionMethodMode &options, - COneMethodInfo *oneMethodMain, - UInt32 numThreads, - UInt32 numZipThreads_limit, - UInt64 numFilesToCompress, - UInt64 numBytesToCompress) -{ - NCompress::NZstd::CEncoderProps encoderProps; - RINOK(encoderProps.SetFromMethodProps(*oneMethodMain)); - CZstdEncProps &zstdProps = encoderProps.EncProps; - ZstdEncProps_NormalizeFull(&zstdProps); - if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) >= 0) - { - // threads for ZSTD are fixed - if (zstdProps.nbWorkers > 1) - numThreads /= zstdProps.nbWorkers; - if (numThreads > numZipThreads_limit) - numThreads = numZipThreads_limit; - if (options._memUsage_WasSet - && !options._numThreads_WasForced) - { - const UInt64 mem1 = ZstdEncProps_GetMemUsage(&zstdProps); - const UInt64 numZipThreads = options._memUsage_Compress / (mem1 + kMemPerThread); - if (numThreads > numZipThreads) - numThreads = (UInt32)numZipThreads; - } - return numThreads; - } - { - // threads for ZSTD are not fixed - - // calculate estimated required number of ZST threads per file size statistics - UInt32 t = MY_ZSTDMT_NBWORKERS_MAX; - { - UInt64 averageNumberOfBlocks = 0; - const UInt64 averageSize = numBytesToCompress / numFilesToCompress; - const UInt64 jobSize = zstdProps.jobSize; - if (jobSize != 0) - averageNumberOfBlocks = averageSize / jobSize + 0; - if (t > averageNumberOfBlocks) - t = (UInt32)averageNumberOfBlocks; - } - if (t > numThreads) - t = numThreads; - - // calculate the nuber of zip threads - UInt32 numZipThreads = numThreads; - if (t > 1) - numZipThreads = numThreads / t; - if (numZipThreads > numZipThreads_limit) - numZipThreads = numZipThreads_limit; - if (numZipThreads < 1) - numZipThreads = 1; - { - // recalculate the number of ZSTD threads via the number of ZIP threads - const UInt32 t2 = numThreads / numZipThreads; - if (t < t2) - t = t2; - } - - if (options._memUsage_WasSet - && !options._numThreads_WasForced) - { - t = CalcThreads_for_ZipZstd(&zstdProps, - options._memUsage_Compress, numThreads, numZipThreads); - numThreads = numZipThreads; - } - // we don't use (nbWorkers = 1) here - if (t <= 1) - t = 0; - oneMethodMain->AddProp_NumThreads(t); - return numThreads; - } -} -*/ - -#endif - - - - -static HRESULT Update2( - DECL_EXTERNAL_CODECS_LOC_VARS - COutArchive &archive, - CInArchive *inArchive, - const CObjectVector &inputItems, - CObjectVector &updateItems, - const CUpdateOptions &updateOptions, - const CCompressionMethodMode &options, bool outSeqMode, - const CByteBuffer *comment, - IArchiveUpdateCallback *updateCallback) -{ - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - - /* - CMyComPtr reportArcProp; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); - */ - - bool unknownComplexity = false; - UInt64 complexity = 0; - #ifndef Z7_ST - UInt64 numFilesToCompress = 0; - UInt64 numBytesToCompress = 0; - #endif - - unsigned i; - - for (i = 0; i < updateItems.Size(); i++) - { - const CUpdateItem &ui = updateItems[i]; - if (ui.NewData) - { - if (ui.Size == (UInt64)(Int64)-1) - unknownComplexity = true; - else - complexity += ui.Size; - #ifndef Z7_ST - numBytesToCompress += ui.Size; - numFilesToCompress++; - #endif - /* - if (ui.Commented) - complexity += ui.CommentRange.Size; - */ - } - else - { - CItemEx inputItem = inputItems[(unsigned)ui.IndexInArc]; - if (inArchive->Read_LocalItem_After_CdItem_Full(inputItem) != S_OK) - return E_NOTIMPL; - complexity += inputItem.GetLocalFullSize(); - // complexity += inputItem.GetCentralExtraPlusCommentSize(); - } - complexity += kLocalHeaderSize; - complexity += kCentralHeaderSize; - } - - if (comment) - complexity += comment->Size(); - complexity++; // end of central - - if (!unknownComplexity) - updateCallback->SetTotal(complexity); - - UInt64 totalComplexity = complexity; - - CCompressionMethodMode options2 = options; - - if (options2._methods.IsEmpty()) - { - // we need method item, if default method was used - options2._methods.AddNew(); - } - - CAddCommon compressor; - compressor.SetOptions(options2); - - complexity = 0; - - const Byte method = options.MethodSequence.FrontItem(); - - COneMethodInfo *oneMethodMain = NULL; - if (!options2._methods.IsEmpty()) - oneMethodMain = &options2._methods[0]; - - { - FOR_VECTOR (mi, options2._methods) - { - options2.SetGlobalLevelTo(options2._methods[mi]); - } - } - - if (oneMethodMain) - { - // appnote recommends to use EOS marker for LZMA. - if (method == NFileHeader::NCompressionMethod::kLZMA) - oneMethodMain->AddProp_EndMarker_if_NotFound(true); - } - - - #ifndef Z7_ST - - UInt32 numThreads = options._numThreads; - - UInt32 numZipThreads_limit = numThreads; - if (numZipThreads_limit > numFilesToCompress) - numZipThreads_limit = (UInt32)numFilesToCompress; - - if (numZipThreads_limit > 1) - { - const unsigned numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); - // printf("\nzip:numFiles_OPEN_MAX =%d\n", (unsigned)numFiles_OPEN_MAX); - if (numZipThreads_limit > numFiles_OPEN_MAX) - numZipThreads_limit = (UInt32)numFiles_OPEN_MAX; - } - - { - const UInt32 kNumMaxThreads = - #ifdef _WIN32 - 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here - #else - 128; - #endif - if (numThreads > kNumMaxThreads) - numThreads = kNumMaxThreads; - } - /* - if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows - numThreads = MAXIMUM_WAIT_OBJECTS; - */ - - - /* - // zstd supports (numThreads == 0); - if (numThreads < 1) - numThreads = 1; - */ - - bool mtMode = (numThreads > 1); - - if (numFilesToCompress <= 1) - mtMode = false; - - // mtMode = true; // debug: to test mtMode - - if (!mtMode) - { - // if (oneMethodMain) { - /* - if (method == NFileHeader::NCompressionMethod::kZstdWz) - { - if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) < 0) - { - // numZstdThreads was not forced in oneMethodMain - if (numThreads >= 1 - && options._memUsage_WasSet - && !options._numThreads_WasForced) - { - NCompress::NZstd::CEncoderProps encoderProps; - RINOK(encoderProps.SetFromMethodProps(*oneMethodMain)) - CZstdEncProps &zstdProps = encoderProps.EncProps; - ZstdEncProps_NormalizeFull(&zstdProps); - numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit( - &zstdProps, options._memUsage_Compress, numThreads); - // we allow (nbWorkers = 1) here. - } - oneMethodMain->AddProp_NumThreads(numThreads); - } - } // kZstdWz - */ - // } // oneMethodMain - - FOR_VECTOR (mi, options2._methods) - { - COneMethodInfo &onem = options2._methods[mi]; - - if (onem.FindProp(NCoderPropID::kNumThreads) < 0) - { - // fixme: we should check the number of threads for xz method also - // fixed for 9.31. bzip2 default is just one thread. - onem.AddProp_NumThreads(numThreads); - } - } - } - else // mtMode - { - if (method == NFileHeader::NCompressionMethod::kStore && !options.Password_Defined) - numThreads = 1; - - if (oneMethodMain) - { - - if (method == NFileHeader::NCompressionMethod::kBZip2) - { - bool fixedNumber; - UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber); - if (!fixedNumber) - { - const UInt64 averageSize = numBytesToCompress / numFilesToCompress; - const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize(); - const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; - numBZip2Threads = 64; - if (numBZip2Threads > averageNumberOfBlocks) - numBZip2Threads = (UInt32)averageNumberOfBlocks; - if (numBZip2Threads > numThreads) - numBZip2Threads = numThreads; - oneMethodMain->AddProp_NumThreads(numBZip2Threads); - } - numThreads /= numBZip2Threads; - } - else if (method == NFileHeader::NCompressionMethod::kXz) - { - UInt32 numLzmaThreads = 1; - int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads); - if (numXzThreads < 0) - { - // numXzThreads is unknown - const UInt64 averageSize = numBytesToCompress / numFilesToCompress; - const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize(); - UInt64 averageNumberOfBlocks = 1; - if (blockSize != (UInt64)(Int64)-1) - averageNumberOfBlocks = averageSize / blockSize + 1; - UInt32 t = 256; - if (t > averageNumberOfBlocks) - t = (UInt32)averageNumberOfBlocks; - t *= numLzmaThreads; - if (t > numThreads) - t = numThreads; - oneMethodMain->AddProp_NumThreads(t); - numXzThreads = (int)t; - } - numThreads /= (unsigned)numXzThreads; - } - /* - else if (method == NFileHeader::NCompressionMethod::kZstdWz) - { - numThreads = SetZstdThreads(options, - oneMethodMain, numThreads, - numZipThreads_limit, - numFilesToCompress, numBytesToCompress); - } - */ - else if ( - method == NFileHeader::NCompressionMethod::kDeflate - || method == NFileHeader::NCompressionMethod::kDeflate64 - || method == NFileHeader::NCompressionMethod::kPPMd) - { - if (numThreads > 1 - && options._memUsage_WasSet - && !options._numThreads_WasForced) - { - UInt64 methodMemUsage; - if (method == NFileHeader::NCompressionMethod::kPPMd) - methodMemUsage = oneMethodMain->Get_Ppmd_MemSize(); - else - methodMemUsage = (4 << 20); // for deflate - const UInt64 threadMemUsage = kMemPerThread + methodMemUsage; - const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage; - if (numThreads64 < numThreads) - numThreads = (UInt32)numThreads64; - } - } - else if (method == NFileHeader::NCompressionMethod::kLZMA) - { - // we suppose that default LZMA is 2 thread. So we don't change it - const UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); - numThreads /= numLZMAThreads; - - if (numThreads > 1 - && options._memUsage_WasSet - && !options._numThreads_WasForced) - { - const UInt64 methodMemUsage = oneMethodMain->Get_Lzma_MemUsage(true); - const UInt64 threadMemUsage = kMemPerThread + methodMemUsage; - const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage; - if (numThreads64 < numThreads) - numThreads = (UInt32)numThreads64; - } - } - } // (oneMethodMain) - - if (numThreads > numZipThreads_limit) - numThreads = numZipThreads_limit; - if (numThreads <= 1) - { - mtMode = false; - numThreads = 1; - } - } - - // mtMode = true; // to test mtMode for seqMode - - if (!mtMode) - #endif - return Update2St( - EXTERNAL_CODECS_LOC_VARS - archive, inArchive, - inputItems, updateItems, - updateOptions, - &options2, outSeqMode, - comment, updateCallback, totalComplexity, - opCallback - // , reportArcProp - ); - - - #ifndef Z7_ST - - /* - CTotalStats stat; - stat.Size = 0; - stat.PackSize = 0; - */ - if (numThreads < 1) - numThreads = 1; - - CObjectVector items; - - CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; - CMyComPtr progress = mtProgressMixerSpec; - mtProgressMixerSpec->Create(updateCallback, true); - - CMtCompressProgressMixer mtCompressProgressMixer; - mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress); - - CMemBlockManagerMt memManager(kBlockSize); - CMemRefs refs(&memManager); - - CMtSem mtSem; - CThreads threads; - mtSem.Head = -1; - mtSem.Indexes.ClearAndSetSize(numThreads); - { - WRes wres = mtSem.Semaphore.Create(0, numThreads); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - - CUIntVector threadIndices; // list threads in order of updateItems - - { - RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize))) - for (i = 0; i < updateItems.Size(); i++) - refs.Refs.Add(CMemBlocks2()); - - for (i = 0; i < numThreads; i++) - { - threads.Threads.AddNew(); - // mtSem.Indexes[i] = -1; // actually we don't use these values - } - - for (i = 0; i < numThreads; i++) - { - CThreadInfo &threadInfo = threads.Threads[i]; - threadInfo.ThreadIndex = i; - threadInfo.SetOptions(options2); - #ifdef Z7_EXTERNAL_CODECS - threadInfo._externalCodecs = _externalCodecs; - #endif - RINOK(threadInfo.CreateEvents()) - threadInfo.OutStreamSpec = new COutMemStream(&memManager); - RINOK(threadInfo.OutStreamSpec->CreateEvents(SYNC_WFMO(&memManager.Synchro))) - threadInfo.OutStream = threadInfo.OutStreamSpec; - threadInfo.ProgressSpec = new CMtCompressProgress(); - threadInfo.Progress = threadInfo.ProgressSpec; - threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i); - threadInfo.MtSem = &mtSem; - RINOK(threadInfo.CreateThread()) - } - } - - unsigned mtItemIndex = 0; - unsigned itemIndex = 0; - int lastRealStreamItemIndex = -1; - - - while (itemIndex < updateItems.Size()) - { - if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size()) - { - // we start ahead the threads for compressing - // also we set refs.Refs[itemIndex].SeqMode that is used later - // don't move that code block - - CUpdateItem &ui = updateItems[mtItemIndex++]; - if (!ui.NewData) - continue; - CItemEx itemEx; - CItemOut item; - - if (ui.NewProps) - { - if (ui.IsDir) - continue; - } - else - { - itemEx = inputItems[(unsigned)ui.IndexInArc]; - if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK) - return E_NOTIMPL; - (CItem &)item = itemEx; - if (item.IsDir() != ui.IsDir) - return E_NOTIMPL; - if (ui.IsDir) - continue; - } - - CMyComPtr fileInStream; - - CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1]; - - { - NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection); - const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); - if (res == S_FALSE) - { - complexity += ui.Size; - complexity += kLocalHeaderSize; - mtProgressMixerSpec->Mixer2->SetProgressOffset_NoLock(complexity); - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - memRef2.Skip = true; - continue; - } - RINOK(res) - if (!fileInStream) - return E_INVALIDARG; - UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity); - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - } - - UInt32 k; - for (k = 0; k < numThreads; k++) - if (threads.Threads[k].IsFree) - break; - - if (k == numThreads) - return E_FAIL; - { - { - CThreadInfo &threadInfo = threads.Threads[k]; - threadInfo.IsFree = false; - threadInfo.InStream = fileInStream; - - bool inSeqMode = false; - - if (!inSeqMode) - { - CMyComPtr inStream2; - fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); - inSeqMode = (inStream2 == NULL); - } - memRef2.InSeqMode = inSeqMode; - - // !!!!! we must release ref before sending event - // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time - fileInStream.Release(); - - threadInfo.OutStreamSpec->Init(); - threadInfo.ProgressSpec->Reinit(); - - threadInfo.UpdateIndex = mtItemIndex - 1; - threadInfo.InSeqMode = inSeqMode; - threadInfo.OutSeqMode = outSeqMode; - threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode - threadInfo.ExpectedDataSize = ui.Size; - threadInfo.ExpectedDataSize_IsConfirmed = ui.Size_WasSetFromStream; - - threadInfo.CompressEvent.Set(); - - threadIndices.Add(k); - } - } - - continue; - } - - if (refs.Refs[itemIndex].Skip) - { - itemIndex++; - continue; - } - - const CUpdateItem &ui = updateItems[itemIndex]; - - CItemEx itemEx; - CItemOut item; - - if (!ui.NewProps || !ui.NewData) - { - itemEx = inputItems[(unsigned)ui.IndexInArc]; - if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK) - return E_NOTIMPL; - (CItem &)item = itemEx; - } - - if (ui.NewData) - { - // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); - const bool isDir = ui.IsDir; - - if (isDir) - { - RINOK(WriteDirHeader(archive, &options, ui, item)) - } - else - { - CMemBlocks2 &memRef = refs.Refs[itemIndex]; - - if (memRef.Finished) - { - if (lastRealStreamItemIndex < (int)itemIndex) - lastRealStreamItemIndex = (int)itemIndex; - - SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, item); - - // the BUG was fixed in 9.26: - // SetItemInfoFromCompressingResult must be after SetFileHeader - // to write correct Size. - - SetItemInfoFromCompressingResult(memRef.CompressingResult, - options.IsRealAesMode(), options.AesKeyMode, item); - RINOK(archive.ClearRestriction()) - archive.WriteLocalHeader(item); - // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - CMyComPtr outStream; - archive.CreateStreamForCopying(outStream); - memRef.WriteToStream(memManager.GetBlockSize(), outStream); - // v23: we fixed the bug: we need to write descriptor also - if (item.HasDescriptor()) - { - /* that function doesn't rewrite local header, if item.HasDescriptor(). - it just writes descriptor */ - archive.WriteLocalHeader_Replace(item); - } - else - archive.MoveCurPos(item.PackSize); - memRef.FreeOpt(&memManager); - /* - if (reportArcProp) - { - stat.UpdateWithItem(item); - RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode())); - } - */ - } - else - { - // current file was not finished - - if (lastRealStreamItemIndex < (int)itemIndex) - { - // LocalHeader was not written for current itemIndex still - - lastRealStreamItemIndex = (int)itemIndex; - - // thread was started before for that item already, and memRef.SeqMode was set - - CCompressingResult compressingResult; - RINOK(compressor.Set_Pre_CompressionResult( - memRef.InSeqMode, outSeqMode, - ui.Size, - compressingResult)) - - memRef.PreDescriptorMode = compressingResult.DescriptorMode; - SetFileHeader(options, ui, compressingResult.DescriptorMode, item); - - SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item); - - // file Size can be 64-bit !!! - RINOK(archive.SetRestrictionFromCurrent()) - archive.WriteLocalHeader(item); - } - - { - CThreadInfo &thread = threads.Threads[threadIndices.FrontItem()]; - if (!thread.OutStreamSpec->WasUnlockEventSent()) - { - CMyComPtr outStream; - archive.CreateStreamForCompressing(outStream); - thread.OutStreamSpec->SetOutStream(outStream); - thread.OutStreamSpec->SetRealStreamMode(); - } - } - - const WRes wres = mtSem.Semaphore.Lock(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - - const int ti = mtSem.GetFreeItem(); - if (ti < 0) - return E_FAIL; - - CThreadInfo &threadInfo = threads.Threads[(unsigned)ti]; - threadInfo.InStream.Release(); - threadInfo.IsFree = true; - RINOK(threadInfo.Result) - - unsigned t = 0; - - for (;;) - { - if (t == threadIndices.Size()) - return E_FAIL; - if (threadIndices[t] == (unsigned)ti) - break; - t++; - } - threadIndices.Delete(t); - - if (t == 0) - { - // if thread for current file was finished. - if (threadInfo.UpdateIndex != itemIndex) - return E_FAIL; - - if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode) - return E_FAIL; - - RINOK(threadInfo.OutStreamSpec->WriteToRealStream()) - threadInfo.OutStreamSpec->ReleaseOutStream(); - SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item); - SetItemInfoFromCompressingResult(threadInfo.CompressingResult, - options.IsRealAesMode(), options.AesKeyMode, item); - - archive.WriteLocalHeader_Replace(item); - - /* - if (reportArcProp) - { - stat.UpdateWithItem(item); - RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode())); - } - */ - } - else - { - // it's not current file. So we must store information in array - CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex]; - threadInfo.OutStreamSpec->DetachData(memRef2); - memRef2.CompressingResult = threadInfo.CompressingResult; - // memRef2.SeqMode = threadInfo.SeqMode; // it was set before - memRef2.Finished = true; - continue; - } - } - } - } - else - { - RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)) - } - - items.Add(item); - complexity += kLocalHeaderSize; - mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); - itemIndex++; - } - - RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)) - - RINOK(archive.WriteCentralDir(items, comment)) - - /* - if (reportArcProp) - { - RINOK(ReportArcProps(reportArcProp, stat)); - } - */ - - complexity += kCentralHeaderSize * updateItems.Size() + 1; - mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); - return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); - - #endif -} - -/* -// we need CSeekOutStream, if we need Seek(0, STREAM_SEEK_CUR) for seqential stream -Z7_CLASS_IMP_COM_1( - CSeekOutStream - , IOutStream -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - CMyComPtr _seqStream; - UInt64 _size; -public: - void Init(ISequentialOutStream *seqStream) - { - _size = 0; - _seqStream = seqStream; - } -}; - -Z7_COM7F_IMF(CSeekOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize; - const HRESULT result = _seqStream->Write(data, size, &realProcessedSize); - _size += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return result; -} - -Z7_COM7F_IMF(CSeekOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - if (seekOrigin != STREAM_SEEK_CUR || offset != 0) - return E_NOTIMPL; - if (newPosition) - *newPosition = (UInt64)_size; - return S_OK; -} - -Z7_COM7F_IMF(CSeekOutStream::SetSize(UInt64 newSize)) -{ - UNUSED_VAR(newSize) - return E_NOTIMPL; -} -*/ - -static const size_t kCacheBlockSize = 1 << 20; -static const size_t kCacheSize = kCacheBlockSize << 2; -static const size_t kCacheMask = kCacheSize - 1; - -Z7_CLASS_IMP_NOQIB_2( - CCacheOutStream - , IOutStream - , IStreamSetRestriction -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - HRESULT _hres; - CMyComPtr _seqStream; - CMyComPtr _stream; - CMyComPtr _setRestriction; - Byte *_cache; - size_t _cachedSize; - UInt64 _cachedPos; - UInt64 _virtPos; - UInt64 _virtSize; - UInt64 _phyPos; - UInt64 _phySize; - UInt64 _restrict_begin; - UInt64 _restrict_end; - - HRESULT FlushFromCache(size_t size); - HRESULT FlushNonRestrictedBlocks(); - HRESULT FlushCache(); - HRESULT SetRestriction_ForWrite(size_t writeSize) const; - - HRESULT SeekPhy(UInt64 pos) - { - if (pos == _phyPos) - return S_OK; - if (!_stream) - return E_NOTIMPL; - _hres = _stream->Seek((Int64)pos, STREAM_SEEK_SET, &_phyPos); - if (_hres == S_OK && _phyPos != pos) - _hres = E_FAIL; - return _hres; - } - -public: - CCacheOutStream(): _cache(NULL) {} - ~CCacheOutStream(); - bool Allocate() - { - if (!_cache) - _cache = (Byte *)::MidAlloc(kCacheSize); - return _cache != NULL; - } - HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction); - HRESULT FinalFlush(); -}; - -CCacheOutStream::~CCacheOutStream() -{ - ::MidFree(_cache); -} - - -HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction) -{ - _hres = S_OK; - _cachedSize = 0; - _cachedPos = 0; - _virtPos = 0; - _virtSize = 0; - // by default we have no restriction - _restrict_begin = 0; - _restrict_end = 0; - _seqStream = seqStream; - _stream = stream; - _setRestriction = setRestriction; - if (_stream) - { - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)) - RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)) - RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, &_virtPos)) - } - _phyPos = _virtPos; - _phySize = _virtSize; - return S_OK; -} - - -/* we call SetRestriction_ForWrite() just before Write() from cache. - (_phyPos == _cachedPos) - (writeSize != 0) -*/ -HRESULT CCacheOutStream::SetRestriction_ForWrite(size_t writeSize) const -{ - if (!_setRestriction) - return S_OK; - PRF(printf("\n-- CCacheOutStream::SetRestriction_ForWrite _cachedPos = 0x%x, writeSize = %d\n", (unsigned)_cachedPos, (unsigned)writeSize)); - UInt64 begin = _restrict_begin; - UInt64 end = _restrict_end; - const UInt64 phyPos = _phyPos; - if (phyPos != _cachedPos) return E_FAIL; - if (phyPos == _phySize) - { - // The writing will be to the end of phy stream. - // So we will try to use non-restricted write, if possible. - if (begin == end) - begin = _virtPos; // _virtSize; // it's supposed that (_virtSize == _virtPos) - if (phyPos + writeSize <= begin) - { - // the write is not restricted - PRF(printf("\n+++ write is not restricted \n")); - begin = 0; - end = 0; - } - else - { - if (begin > phyPos) - begin = phyPos; - end = (UInt64)(Int64)-1; - } - } - else - { - // (phyPos != _phySize) - if (begin == end || begin > phyPos) - begin = phyPos; - end = (UInt64)(Int64)-1; - } - return _setRestriction->SetRestriction(begin, end); -} - - -/* it writes up to (size) bytes from cache. - (size > _cachedSize) is allowed -*/ -HRESULT CCacheOutStream::FlushFromCache(size_t size) -{ - PRF(printf("\n-- CCacheOutStream::FlushFromCache %u\n", (unsigned)size)); - if (_hres != S_OK) - return _hres; - if (size > _cachedSize) - size = _cachedSize; - // (size <= _cachedSize) - if (size == 0) - return S_OK; - RINOK(SeekPhy(_cachedPos)) - for (;;) - { - // (_phyPos == _cachedPos) - const size_t pos = (size_t)_cachedPos & kCacheMask; - const size_t cur = MyMin(kCacheSize - pos, size); - _hres = SetRestriction_ForWrite(cur); - RINOK(_hres) - PRF(printf("\n-- CCacheOutStream::WriteFromCache _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)cur)); - _hres = WriteStream(_seqStream, _cache + pos, cur); - RINOK(_hres) - _phyPos += cur; - if (_phySize < _phyPos) - _phySize = _phyPos; - _cachedPos += cur; - _cachedSize -= cur; - size -= cur; - if (size == 0) - return S_OK; - } -} - - -HRESULT CCacheOutStream::FlushNonRestrictedBlocks() -{ - for (;;) - { - const size_t size = kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)); - if (_cachedSize < size) - break; - UInt64 begin = _restrict_begin; - if (begin == _restrict_end) - begin = _virtPos; - // we don't flush the data to restricted area - if (_cachedPos + size > begin) - break; - RINOK(FlushFromCache(size)) - } - return S_OK; -} - - -HRESULT CCacheOutStream::FlushCache() -{ - return FlushFromCache(_cachedSize); -} - -HRESULT CCacheOutStream::FinalFlush() -{ - _restrict_begin = 0; - _restrict_end = 0; - RINOK(FlushCache()) - if (_stream && _hres == S_OK) - { - if (_virtSize != _phySize) - { - // it's unexpected - RINOK(_stream->SetSize(_virtSize)) - _phySize = _virtSize; - } - _hres = SeekPhy(_virtPos); - } - return _hres; -} - - -Z7_COM7F_IMF(CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - PRF(printf("\n==== CCacheOutStream::Write virtPos=0x%x, %u\n", (unsigned)_virtPos, (unsigned)size)); - - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_hres != S_OK) - return _hres; - - if (_cachedSize != 0) - if (_virtPos < _cachedPos || - _virtPos > _cachedPos + _cachedSize) - { - RINOK(FlushCache()) - } - - if (_cachedSize == 0) - _cachedPos = _virtPos; - - const size_t pos = (size_t)_virtPos & kCacheMask; - { - const size_t blockRem = kCacheBlockSize - ((size_t)_virtPos & (kCacheBlockSize - 1)); - if (size > blockRem) - size = (UInt32)blockRem; - } - // _cachedPos <= _virtPos <= _cachedPos + _cachedSize - const UInt64 cachedRem = _cachedPos + _cachedSize - _virtPos; - if (cachedRem) - { - // _virtPos < _cachedPos + _cachedSize - // we rewrite only existing data in cache. So _cachedSize will be not changed - if (size > cachedRem) - size = (UInt32)cachedRem; - } - else - { - // _virtPos == _cachedPos + _cachedSize - // so we need to add new data to the end of cache - if (_cachedSize == kCacheSize) - { - // cache is full. So we need to flush some part of cache. - // we flush only one block, but we are allowed to flush any size here - RINOK(FlushFromCache(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)))) - } - // _cachedSize != kCacheSize - // so we have some space for new data in cache - if (_cachedSize == 0) - { - /* this code is optional (for optimization): - we write data directly without cache, - if there is no restriction and we have full block. */ - if (_restrict_begin == _restrict_end - && size == kCacheBlockSize) - { - RINOK(SeekPhy(_virtPos)) - if (_setRestriction) - { - _hres = _setRestriction->SetRestriction(_restrict_begin, _restrict_end); - RINOK(_hres) - } - PRF(printf("\n-- CCacheOutStream::WriteDirectly _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)size)); - _hres = WriteStream(_seqStream, data, size); - RINOK(_hres) - if (processedSize) - *processedSize = size; - _virtPos += size; - if (_virtSize < _virtPos) - _virtSize = _virtPos; - _phyPos += size; - if (_phySize < _phyPos) - _phySize = _phyPos; - return S_OK; - } - } - else // (_cachedSize != 0) - { - const size_t startPos = (size_t)_cachedPos & kCacheMask; - // we don't allow new data to overwrite old start data in cache. - // (startPos == pos) here means that cache is empty. - // (startPos == pos) is not possible here. - if (startPos > pos) - size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos)); - } - // _virtPos == (_cachedPos + _cachedSize) still - _cachedSize += size; - } - - memcpy(_cache + pos, data, size); - if (processedSize) - *processedSize = size; - _virtPos += size; - if (_virtSize < _virtPos) - _virtSize = _virtPos; - return FlushNonRestrictedBlocks(); -} - - -Z7_COM7F_IMF(CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - PRF(printf("\n==== CCacheOutStream::Seek seekOrigin=%d Seek =%u\n", seekOrigin, (unsigned)offset)); - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += _virtSize; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - -Z7_COM7F_IMF(CCacheOutStream::SetSize(UInt64 newSize)) -{ - if (_hres != S_OK) - return _hres; - - if (newSize <= _cachedPos || _cachedSize == 0) - { - _cachedSize = 0; - _cachedPos = newSize; - } - else - { - // _cachedSize != 0 - // newSize > _cachedPos - const UInt64 offset = newSize - _cachedPos; - if (offset <= _cachedSize) - { - // newSize is inside cached block or is touching cached block. - // so we reduce cache - _cachedSize = (size_t)offset; - if (_phySize <= newSize) - { - // _phySize will be restored later after cache flush - _virtSize = newSize; - return S_OK; - } - // (_phySize > newSize) - // so we must reduce phyStream size to (newSize) or to (_cachedPos) - // newPhySize = _cachedPos; // optional reduce to _cachedPos - } - else - { - // newSize > _cachedPos + _cachedSize - /* It's possible that we need to write zeros, - if new size is larger than old size. - We don't optimize for possible cases here. - So we just flush the cache. */ - _hres = FlushCache(); - } - } - - _virtSize = newSize; - - if (_hres != S_OK) - return _hres; - - if (newSize != _phySize) - { - if (!_stream) - return E_NOTIMPL; - // if (_phyPos > newSize) - RINOK(SeekPhy(newSize)) - if (_setRestriction) - { - UInt64 begin = _restrict_begin; - UInt64 end = _restrict_end; - if (_cachedSize != 0) - { - if (begin > _cachedPos) - begin = _cachedPos; - end = (UInt64)(Int64)-1; - } - _hres = _setRestriction->SetRestriction(begin, end); - RINOK(_hres) - } - _hres = _stream->SetSize(newSize); - RINOK(_hres) - _phySize = newSize; - } - return S_OK; -} - - -Z7_COM7F_IMF(CCacheOutStream::SetRestriction(UInt64 begin, UInt64 end)) -{ - PRF(printf("\n============ CCacheOutStream::SetRestriction 0x%x, %u\n", (unsigned)begin, (unsigned)end)); - _restrict_begin = begin; - _restrict_end = end; - return FlushNonRestrictedBlocks(); -} - - - -HRESULT Update( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &inputItems, - CObjectVector &updateItems, - ISequentialOutStream *seqOutStream, - CInArchive *inArchive, bool removeSfx, - const CUpdateOptions &updateOptions, - const CCompressionMethodMode &compressionMethodMode, - IArchiveUpdateCallback *updateCallback) -{ - /* - // it was tested before - if (inArchive) - { - if (!inArchive->CanUpdate()) - return E_NOTIMPL; - } - */ - - CMyComPtr setRestriction; - seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction); - if (setRestriction) - { - RINOK(setRestriction->SetRestriction(0, 0)) - } - - CMyComPtr outStream; - CCacheOutStream *cacheStream; - bool outSeqMode; - - { - CMyComPtr outStreamReal; - - if (!compressionMethodMode.Force_SeqOutMode) - { - seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal); - /* - if (!outStreamReal) - return E_NOTIMPL; - */ - } - - if (inArchive) - { - if (!inArchive->IsMultiVol && inArchive->ArcInfo.Base > 0 && !removeSfx) - { - IInStream *baseStream = inArchive->GetBaseStream(); - RINOK(InStream_SeekToBegin(baseStream)) - RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, (UInt64)inArchive->ArcInfo.Base, NULL)) - } - } - - outSeqMode = (outStreamReal == NULL); - if (outSeqMode) - setRestriction.Release(); - /* CCacheOutStream works as non-restricted by default. - So we use (setRestriction == NULL) for outSeqMode */ - // bool use_cacheStream = true; - // if (use_cacheStream) - { - cacheStream = new CCacheOutStream(); - outStream = cacheStream; - if (!cacheStream->Allocate()) - return E_OUTOFMEMORY; - RINOK(cacheStream->Init(seqOutStream, outStreamReal, setRestriction)) - setRestriction.Release(); - if (!outSeqMode) - setRestriction = cacheStream; - } - /* - else if (!outStreamReal) - { - CSeekOutStream *seekOutStream = new CSeekOutStream(); - outStream = seekOutStream; - seekOutStream->Init(seqOutStream); - } - else - outStream = outStreamReal; - */ - } - - COutArchive outArchive; - outArchive.SetRestriction = setRestriction; - - RINOK(outArchive.Create(outStream)) - - if (inArchive) - { - if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base) - { - IInStream *baseStream = inArchive->GetBaseStream(); - RINOK(InStream_SeekSet(baseStream, (UInt64)inArchive->ArcInfo.Base)) - const UInt64 embStubSize = (UInt64)((Int64)inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base); - RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL)) - outArchive.MoveCurPos(embStubSize); - } - } - - RINOK (Update2( - EXTERNAL_CODECS_LOC_VARS - outArchive, inArchive, - inputItems, updateItems, - updateOptions, - compressionMethodMode, outSeqMode, - inArchive ? &inArchive->ArcInfo.Comment : NULL, - updateCallback)) - - return cacheStream->FinalFlush(); -} - -}} +// ZipUpdate.cpp + +#include "StdAfx.h" + +// #define DEBUG_CACHE + +#ifdef DEBUG_CACHE +#include + #define PRF(x) x +#else + #define PRF(x) +#endif + +#include "../../../../C/Alloc.h" + +#include "../../../Common/AutoPtr.h" +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/TimeUtils.h" +#include "../../../Windows/Thread.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/OutMemStream.h" +#include "../../Common/ProgressUtils.h" +#ifndef Z7_ST +#include "../../Common/ProgressMt.h" +#endif +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" +// #include "../../Compress/ZstdEncoderProps.h" + +#include "ZipAddCommon.h" +#include "ZipOut.h" +#include "ZipUpdate.h" + +using namespace NWindows; +using namespace NSynchronization; + +namespace NArchive { +namespace NZip { + +static const Byte kHostOS = + #ifdef _WIN32 + NFileHeader::NHostOS::kFAT; + #else + NFileHeader::NHostOS::kUnix; + #endif + +static const Byte kMadeByHostOS = kHostOS; + +// 18.06: now we always write zero to high byte of ExtractVersion field. +// Previous versions of p7zip wrote (NFileHeader::NHostOS::kUnix) there, that is not correct +static const Byte kExtractHostOS = 0; + +static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore; + + +static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method) +{ + CWzAesExtra wzAesField; + wzAesField.Strength = aesKeyMode; + wzAesField.Method = method; + item.Method = NFileHeader::NCompressionMethod::kWzAES; + item.Crc = 0; + CExtraSubBlock sb; + wzAesField.SetSubBlock(sb); + item.LocalExtra.SubBlocks.Add(sb); + item.CentralExtra.SubBlocks.Add(sb); +} + + +static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &item) +{ + item.Name = ui.Name; + item.Name_Utf = ui.Name_Utf; + item.Comment = ui.Comment; + item.SetUtf8(ui.IsUtf8); + // item.SetFlag_AltStream(ui.IsAltStream); + // item.ExternalAttrib = ui.Attrib; + item.Time = ui.Time; + item.Ntfs_MTime = ui.Ntfs_MTime; + item.Ntfs_ATime = ui.Ntfs_ATime; + item.Ntfs_CTime = ui.Ntfs_CTime; + + item.Write_UnixTime = ui.Write_UnixTime; + item.Write_NtfsTime = ui.Write_NtfsTime; +} + +static void SetFileHeader( + const CCompressionMethodMode &options, + const CUpdateItem &ui, + bool useDescriptor, + CItemOut &item) +{ + item.Size = ui.Size; + const bool isDir = ui.IsDir; + + item.ClearFlags(); + + if (ui.NewProps) + { + Copy_From_UpdateItem_To_ItemOut(ui, item); + // item.SetFlag_AltStream(ui.IsAltStream); + item.ExternalAttrib = ui.Attrib; + } + /* + else + isDir = item.IsDir(); + */ + + item.MadeByVersion.HostOS = kMadeByHostOS; + item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion; + + item.ExtractVersion.HostOS = kExtractHostOS; + + item.InternalAttrib = 0; // test it + item.SetEncrypted(!isDir && options.Password_Defined); + item.SetDescriptorMode(useDescriptor); + + if (isDir) + { + item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; + item.Method = kMethodForDirectory; + item.PackSize = 0; + item.Size = 0; + item.Crc = 0; + } + + item.LocalExtra.Clear(); + item.CentralExtra.Clear(); + + if (isDir) + { + item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir; + item.Method = kMethodForDirectory; + item.PackSize = 0; + item.Size = 0; + item.Crc = 0; + } + else if (options.IsRealAesMode()) + AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0])); +} + + +// we call SetItemInfoFromCompressingResult() after SetFileHeader() + +static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult, + bool isAesMode, Byte aesKeyMode, CItem &item) +{ + item.ExtractVersion.Version = compressingResult.ExtractVersion; + item.Method = compressingResult.Method; + if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos) + item.Flags |= NFileHeader::NFlags::kLzmaEOS; + item.Crc = compressingResult.CRC; + item.Size = compressingResult.UnpackSize; + item.PackSize = compressingResult.PackSize; + + item.LocalExtra.Clear(); + item.CentralExtra.Clear(); + + if (isAesMode) + AddAesExtra(item, aesKeyMode, compressingResult.Method); +} + + +#ifndef Z7_ST + +struct CMtSem +{ + NWindows::NSynchronization::CSemaphore Semaphore; + NWindows::NSynchronization::CCriticalSection CS; + CIntVector Indexes; + int Head; + + void ReleaseItem(unsigned index) + { + { + CCriticalSectionLock lock(CS); + Indexes[index] = Head; + Head = (int)index; + } + Semaphore.Release(); + } + + int GetFreeItem() + { + int i; + { + CCriticalSectionLock lock(CS); + i = Head; + Head = Indexes[(unsigned)i]; + } + return i; + } +}; + +static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo); + +struct CThreadInfo +{ + DECL_EXTERNAL_CODECS_LOC_VARS_DECL + + NWindows::CThread Thread; + NWindows::NSynchronization::CAutoResetEvent CompressEvent; + CMtSem *MtSem; + unsigned ThreadIndex; + + bool ExitThread; + + CMtCompressProgress *ProgressSpec; + CMyComPtr Progress; + + COutMemStream *OutStreamSpec; + CMyComPtr OutStream; + CMyComPtr InStream; + + CAddCommon Coder; + HRESULT Result; + CCompressingResult CompressingResult; + + bool IsFree; + bool InSeqMode; + bool OutSeqMode; + bool ExpectedDataSize_IsConfirmed; + + UInt32 UpdateIndex; + UInt32 FileTime; + UInt64 ExpectedDataSize; + + CThreadInfo(): + MtSem(NULL), + ExitThread(false), + ProgressSpec(NULL), + OutStreamSpec(NULL), + IsFree(true), + InSeqMode(false), + OutSeqMode(false), + ExpectedDataSize_IsConfirmed(false), + FileTime(0), + ExpectedDataSize((UInt64)(Int64)-1) + {} + + void SetOptions(const CCompressionMethodMode &options) + { + Coder.SetOptions(options); + } + + HRESULT CreateEvents() + { + WRes wres = CompressEvent.CreateIfNotCreated_Reset(); + return HRESULT_FROM_WIN32(wres); + } + + HRESULT CreateThread() + { + WRes wres = Thread.Create(CoderThread, this); + return HRESULT_FROM_WIN32(wres); + } + + void WaitAndCode(); + + void StopWait_Close() + { + ExitThread = true; + if (OutStreamSpec) + OutStreamSpec->StopWriting(E_ABORT); + if (CompressEvent.IsCreated()) + CompressEvent.Set(); + Thread.Wait_Close(); + } +}; + +void CThreadInfo::WaitAndCode() +{ + for (;;) + { + CompressEvent.Lock(); + if (ExitThread) + return; + + Result = Coder.Compress( + EXTERNAL_CODECS_LOC_VARS + InStream, OutStream, + InSeqMode, OutSeqMode, FileTime, ExpectedDataSize, + ExpectedDataSize_IsConfirmed, + Progress, CompressingResult); + + if (Result == S_OK && Progress) + Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize); + + MtSem->ReleaseItem(ThreadIndex); + } +} + +static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo) +{ + ((CThreadInfo *)threadCoderInfo)->WaitAndCode(); + return 0; +} + +class CThreads +{ +public: + CObjectVector Threads; + ~CThreads() + { + FOR_VECTOR (i, Threads) + Threads[i].StopWait_Close(); + } +}; + +struct CMemBlocks2: public CMemLockBlocks +{ + bool Skip; + bool InSeqMode; + bool PreDescriptorMode; + bool Finished; + CCompressingResult CompressingResult; + + CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false), + CompressingResult() {} +}; + +class CMemRefs +{ +public: + CMemBlockManagerMt *Manager; + CObjectVector Refs; + CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {} + ~CMemRefs() + { + FOR_VECTOR (i, Refs) + Refs[i].FreeOpt(Manager); + } +}; + + +Z7_CLASS_IMP_NOQIB_1( + CMtProgressMixer2 + , ICompressProgressInfo +) + UInt64 ProgressOffset; + UInt64 InSizes[2]; + UInt64 OutSizes[2]; + CMyComPtr Progress; + CMyComPtr RatioProgress; + bool _inSizeIsMain; +public: + NWindows::NSynchronization::CCriticalSection CriticalSection; + void Create(IProgress *progress, bool inSizeIsMain); + void SetProgressOffset(UInt64 progressOffset); + void SetProgressOffset_NoLock(UInt64 progressOffset); + HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize); +}; + +void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain) +{ + Progress = progress; + Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress); + _inSizeIsMain = inSizeIsMain; + ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0; +} + +void CMtProgressMixer2::SetProgressOffset_NoLock(UInt64 progressOffset) +{ + InSizes[1] = OutSizes[1] = 0; + ProgressOffset = progressOffset; +} + +void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset) +{ + CriticalSection.Enter(); + SetProgressOffset_NoLock(progressOffset); + CriticalSection.Leave(); +} + +HRESULT CMtProgressMixer2::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + if (index == 0 && RatioProgress) + { + RINOK(RatioProgress->SetRatioInfo(inSize, outSize)) + } + if (inSize) + InSizes[index] = *inSize; + if (outSize) + OutSizes[index] = *outSize; + UInt64 v = ProgressOffset + (_inSizeIsMain ? + (InSizes[0] + InSizes[1]) : + (OutSizes[0] + OutSizes[1])); + return Progress->SetCompleted(&v); +} + +Z7_COM7F_IMF(CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + return SetRatioInfo(0, inSize, outSize); +} + + +Z7_CLASS_IMP_NOQIB_1( + CMtProgressMixer + , ICompressProgressInfo +) +public: + CMtProgressMixer2 *Mixer2; + CMyComPtr RatioProgress; + void Create(IProgress *progress, bool inSizeIsMain); +}; + +void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain) +{ + Mixer2 = new CMtProgressMixer2; + RatioProgress = Mixer2; + Mixer2->Create(progress, inSizeIsMain); +} + +Z7_COM7F_IMF(CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + return Mixer2->SetRatioInfo(1, inSize, outSize); +} + + +#endif + +static HRESULT UpdateItemOldData( + COutArchive &archive, + CInArchive *inArchive, + const CItemEx &itemEx, + const CUpdateItem &ui, + CItemOut &item, + /* bool izZip64, */ + ICompressProgressInfo *progress, + IArchiveUpdateCallbackFile *opCallback, + UInt64 &complexity) +{ + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, + NUpdateNotifyOp::kReplicate)) + } + + UInt64 rangeSize; + + RINOK(archive.ClearRestriction()) + + if (ui.NewProps) + { + if (item.HasDescriptor()) + return E_NOTIMPL; + + // we keep ExternalAttrib and some another properties from old archive + // item.ExternalAttrib = ui.Attrib; + // if we don't change Comment, we keep Comment from OldProperties + Copy_From_UpdateItem_To_ItemOut(ui, item); + // item.SetFlag_AltStream(ui.IsAltStream); + + item.CentralExtra.RemoveUnknownSubBlocks(); + item.LocalExtra.RemoveUnknownSubBlocks(); + + archive.WriteLocalHeader(item); + rangeSize = item.GetPackSizeWithDescriptor(); + } + else + { + item.LocalHeaderPos = archive.GetCurPos(); + rangeSize = itemEx.GetLocalFullSize(); + } + + CMyComPtr packStream; + + RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream)) + if (!packStream) + return E_NOTIMPL; + + complexity += rangeSize; + + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress); + archive.MoveCurPos(rangeSize); + return res; +} + + +static HRESULT WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options, + const CUpdateItem &ui, CItemOut &item) +{ + SetFileHeader(*options, ui, false, item); + RINOK(archive.ClearRestriction()) + archive.WriteLocalHeader(item); + return S_OK; +} + + +static void UpdatePropsFromStream( + const CUpdateOptions &options, + CUpdateItem &item, ISequentialInStream *fileInStream, + IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) +{ + CMyComPtr getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + UInt64 size = (UInt64)(Int64)-1; + bool size_WasSet = false; + + if (getProps) + { + FILETIME cTime, aTime, mTime; + UInt32 attrib; + if (getProps->GetProps(&size, &cTime, &aTime, &mTime, &attrib) == S_OK) + { + if (options.Write_MTime) + if (!FILETIME_IsZero(mTime)) + { + item.Ntfs_MTime = mTime; + NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time); + } + + if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime; + if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime; + + item.Attrib = attrib; + size_WasSet = true; + } + } + + if (!size_WasSet) + { + CMyComPtr streamGetSize; + fileInStream->QueryInterface(IID_IStreamGetSize, (void **)&streamGetSize); + if (streamGetSize) + { + if (streamGetSize->GetSize(&size) == S_OK) + size_WasSet = true; + } + } + + if (size_WasSet && size != (UInt64)(Int64)-1) + { + item.Size_WasSetFromStream = true; + if (size != item.Size) + { + const Int64 newComplexity = (Int64)totalComplexity + ((Int64)size - (Int64)item.Size); + if (newComplexity > 0) + { + totalComplexity = (UInt64)newComplexity; + updateCallback->SetTotal(totalComplexity); + } + item.Size = size; + } + } +} + + +/* +static HRESULT ReportProps( + IArchiveUpdateCallbackArcProp *reportArcProp, + UInt32 index, + const CItemOut &item, + bool isAesMode) +{ + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + + NCOM::PropVarEm_Set_UInt64(&prop, item.Size); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop)); + + NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop)); + + if (!isAesMode) + { + NCOM::PropVarEm_Set_UInt32(&prop, item.Crc); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop)); + } + + RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK)); + + // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished)) + + return S_OK; +} +*/ + +/* +struct CTotalStats +{ + UInt64 Size; + UInt64 PackSize; + + void UpdateWithItem(const CItemOut &item) + { + Size += item.Size; + PackSize += item.PackSize; + } +}; + +static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, + CTotalStats &st) +{ + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kArcProp, 0, kpidSize, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kArcProp, 0, kpidPackSize, &prop)); + } + return S_OK; +} +*/ + + +static HRESULT Update2St( + DECL_EXTERNAL_CODECS_LOC_VARS + COutArchive &archive, + CInArchive *inArchive, + const CObjectVector &inputItems, + CObjectVector &updateItems, + const CUpdateOptions &updateOptions, + const CCompressionMethodMode *options, bool outSeqMode, + const CByteBuffer *comment, + IArchiveUpdateCallback *updateCallback, + UInt64 &totalComplexity, + IArchiveUpdateCallbackFile *opCallback + // , IArchiveUpdateCallbackArcProp *reportArcProp + ) +{ + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + + CAddCommon compressor; + compressor.SetOptions(*options); + + CObjectVector items; + UInt64 unpackSizeTotal = 0, packSizeTotal = 0; + + FOR_VECTOR (itemIndex, updateItems) + { + lps->InSize = unpackSizeTotal; + lps->OutSize = packSizeTotal; + RINOK(lps->SetCur()) + CUpdateItem &ui = updateItems[itemIndex]; + CItemEx itemEx; + CItemOut item; + + if (!ui.NewProps || !ui.NewData) + { + // Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive, + // But we will rewrite all important properties later. But we can keep some properties like Comment + itemEx = inputItems[(unsigned)ui.IndexInArc]; + if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK) + return E_NOTIMPL; + (CItem &)item = itemEx; + } + + if (ui.NewData) + { + // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + bool isDir = ui.IsDir; + if (isDir) + { + RINOK(WriteDirHeader(archive, options, ui, item)) + } + else + { + CMyComPtr fileInStream; + { + HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + if (res == S_FALSE) + { + lps->ProgressOffset += ui.Size; + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + continue; + } + RINOK(res) + if (!fileInStream) + return E_INVALIDARG; + + bool inSeqMode = false; + if (!inSeqMode) + { + CMyComPtr inStream2; + fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); + inSeqMode = (inStream2 == NULL); + } + // seqMode = true; // to test seqMode + + UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity); + + CCompressingResult compressingResult; + + RINOK(compressor.Set_Pre_CompressionResult( + inSeqMode, outSeqMode, + ui.Size, + compressingResult)) + + SetFileHeader(*options, ui, compressingResult.DescriptorMode, item); + + // file Size can be 64-bit !!! + + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); + + RINOK(archive.SetRestrictionFromCurrent()) + archive.WriteLocalHeader(item); + + CMyComPtr outStream; + archive.CreateStreamForCompressing(outStream); + + RINOK(compressor.Compress( + EXTERNAL_CODECS_LOC_VARS + fileInStream, outStream, + inSeqMode, outSeqMode, + ui.Time, + ui.Size, ui.Size_WasSetFromStream, + progress, compressingResult)) + + if (item.HasDescriptor() != compressingResult.DescriptorMode) + return E_FAIL; + + SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); + + archive.WriteLocalHeader_Replace(item); + } + // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode())) + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + unpackSizeTotal += item.Size; + packSizeTotal += item.PackSize; + } + } + else + { + UInt64 complexity = 0; + lps->SendRatio = false; + + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)) + + lps->SendRatio = true; + lps->ProgressOffset += complexity; + } + + items.Add(item); + lps->ProgressOffset += kLocalHeaderSize; + } + + lps->InSize = unpackSizeTotal; + lps->OutSize = packSizeTotal; + RINOK(lps->SetCur()) + + RINOK(archive.WriteCentralDir(items, comment)) + + /* + CTotalStats stat; + stat.Size = unpackSizeTotal; + stat.PackSize = packSizeTotal; + if (reportArcProp) + RINOK(ReportArcProps(reportArcProp, stat)) + */ + + lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; + return lps->SetCur(); +} + +#ifndef Z7_ST + + +static const size_t kBlockSize = 1 << 16; +// kMemPerThread must be >= kBlockSize +// +static const size_t kMemPerThread = (size_t)sizeof(size_t) << 23; +// static const size_t kMemPerThread = (size_t)sizeof(size_t) << 16; // for debug +// static const size_t kMemPerThread = (size_t)1 << 16; // for debug + +/* +in: + nt_Zip >= 1: the starting maximum number of ZIP threads for search +out: + nt_Zip: calculated number of ZIP threads + returns: calculated number of ZSTD threads +*/ +/* +static UInt32 CalcThreads_for_ZipZstd(CZstdEncProps *zstdProps, + UInt64 memLimit, UInt32 totalThreads, + UInt32 &nt_Zip) +{ + for (; nt_Zip > 1; nt_Zip--) + { + UInt64 mem1 = memLimit / nt_Zip; + if (mem1 <= kMemPerThread) + continue; + mem1 -= kMemPerThread; + UInt32 n_ZSTD = ZstdEncProps_GetNumThreads_for_MemUsageLimit( + zstdProps, mem1, totalThreads / nt_Zip); + // we don't allow (nbWorkers == 1) here + if (n_ZSTD <= 1) + n_ZSTD = 0; + zstdProps->nbWorkers = n_ZSTD; + mem1 = ZstdEncProps_GetMemUsage(zstdProps); + if ((mem1 + kMemPerThread) * nt_Zip <= memLimit) + return n_ZSTD; + } + return ZstdEncProps_GetNumThreads_for_MemUsageLimit( + zstdProps, memLimit, totalThreads); +} + + +static UInt32 SetZstdThreads( + const CCompressionMethodMode &options, + COneMethodInfo *oneMethodMain, + UInt32 numThreads, + UInt32 numZipThreads_limit, + UInt64 numFilesToCompress, + UInt64 numBytesToCompress) +{ + NCompress::NZstd::CEncoderProps encoderProps; + RINOK(encoderProps.SetFromMethodProps(*oneMethodMain)); + CZstdEncProps &zstdProps = encoderProps.EncProps; + ZstdEncProps_NormalizeFull(&zstdProps); + if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) >= 0) + { + // threads for ZSTD are fixed + if (zstdProps.nbWorkers > 1) + numThreads /= zstdProps.nbWorkers; + if (numThreads > numZipThreads_limit) + numThreads = numZipThreads_limit; + if (options._memUsage_WasSet + && !options._numThreads_WasForced) + { + const UInt64 mem1 = ZstdEncProps_GetMemUsage(&zstdProps); + const UInt64 numZipThreads = options._memUsage_Compress / (mem1 + kMemPerThread); + if (numThreads > numZipThreads) + numThreads = (UInt32)numZipThreads; + } + return numThreads; + } + { + // threads for ZSTD are not fixed + + // calculate estimated required number of ZST threads per file size statistics + UInt32 t = MY_ZSTDMT_NBWORKERS_MAX; + { + UInt64 averageNumberOfBlocks = 0; + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt64 jobSize = zstdProps.jobSize; + if (jobSize != 0) + averageNumberOfBlocks = averageSize / jobSize + 0; + if (t > averageNumberOfBlocks) + t = (UInt32)averageNumberOfBlocks; + } + if (t > numThreads) + t = numThreads; + + // calculate the nuber of zip threads + UInt32 numZipThreads = numThreads; + if (t > 1) + numZipThreads = numThreads / t; + if (numZipThreads > numZipThreads_limit) + numZipThreads = numZipThreads_limit; + if (numZipThreads < 1) + numZipThreads = 1; + { + // recalculate the number of ZSTD threads via the number of ZIP threads + const UInt32 t2 = numThreads / numZipThreads; + if (t < t2) + t = t2; + } + + if (options._memUsage_WasSet + && !options._numThreads_WasForced) + { + t = CalcThreads_for_ZipZstd(&zstdProps, + options._memUsage_Compress, numThreads, numZipThreads); + numThreads = numZipThreads; + } + // we don't use (nbWorkers = 1) here + if (t <= 1) + t = 0; + oneMethodMain->AddProp_NumThreads(t); + return numThreads; + } +} +*/ + +#endif + + + + +static HRESULT Update2( + DECL_EXTERNAL_CODECS_LOC_VARS + COutArchive &archive, + CInArchive *inArchive, + const CObjectVector &inputItems, + CObjectVector &updateItems, + const CUpdateOptions &updateOptions, + const CCompressionMethodMode &options, bool outSeqMode, + const CByteBuffer *comment, + IArchiveUpdateCallback *updateCallback) +{ + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + + /* + CMyComPtr reportArcProp; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); + */ + + bool unknownComplexity = false; + UInt64 complexity = 0; + #ifndef Z7_ST + UInt64 numFilesToCompress = 0; + UInt64 numBytesToCompress = 0; + #endif + + unsigned i; + + for (i = 0; i < updateItems.Size(); i++) + { + const CUpdateItem &ui = updateItems[i]; + if (ui.NewData) + { + if (ui.Size == (UInt64)(Int64)-1) + unknownComplexity = true; + else + complexity += ui.Size; + #ifndef Z7_ST + numBytesToCompress += ui.Size; + numFilesToCompress++; + #endif + /* + if (ui.Commented) + complexity += ui.CommentRange.Size; + */ + } + else + { + CItemEx inputItem = inputItems[(unsigned)ui.IndexInArc]; + if (inArchive->Read_LocalItem_After_CdItem_Full(inputItem) != S_OK) + return E_NOTIMPL; + complexity += inputItem.GetLocalFullSize(); + // complexity += inputItem.GetCentralExtraPlusCommentSize(); + } + complexity += kLocalHeaderSize; + complexity += kCentralHeaderSize; + } + + if (comment) + complexity += comment->Size(); + complexity++; // end of central + + if (!unknownComplexity) + updateCallback->SetTotal(complexity); + + UInt64 totalComplexity = complexity; + + CCompressionMethodMode options2 = options; + + if (options2._methods.IsEmpty()) + { + // we need method item, if default method was used + options2._methods.AddNew(); + } + + CAddCommon compressor; + compressor.SetOptions(options2); + + complexity = 0; + + const Byte method = options.MethodSequence.FrontItem(); + + COneMethodInfo *oneMethodMain = NULL; + if (!options2._methods.IsEmpty()) + oneMethodMain = &options2._methods[0]; + + { + FOR_VECTOR (mi, options2._methods) + { + options2.SetGlobalLevelTo(options2._methods[mi]); + } + } + + if (oneMethodMain) + { + // appnote recommends to use EOS marker for LZMA. + if (method == NFileHeader::NCompressionMethod::kLZMA) + oneMethodMain->AddProp_EndMarker_if_NotFound(true); + } + + + #ifndef Z7_ST + + UInt32 numThreads = options._numThreads; + + UInt32 numZipThreads_limit = numThreads; + if (numZipThreads_limit > numFilesToCompress) + numZipThreads_limit = (UInt32)numFilesToCompress; + + if (numZipThreads_limit > 1) + { + const unsigned numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); + // printf("\nzip:numFiles_OPEN_MAX =%d\n", (unsigned)numFiles_OPEN_MAX); + if (numZipThreads_limit > numFiles_OPEN_MAX) + numZipThreads_limit = (UInt32)numFiles_OPEN_MAX; + } + + { + const UInt32 kNumMaxThreads = + #ifdef _WIN32 + 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here + #else + 128; + #endif + if (numThreads > kNumMaxThreads) + numThreads = kNumMaxThreads; + } + /* + if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows + numThreads = MAXIMUM_WAIT_OBJECTS; + */ + + + /* + // zstd supports (numThreads == 0); + if (numThreads < 1) + numThreads = 1; + */ + + bool mtMode = (numThreads > 1); + + if (numFilesToCompress <= 1) + mtMode = false; + + // mtMode = true; // debug: to test mtMode + + if (!mtMode) + { + // if (oneMethodMain) { + /* + if (method == NFileHeader::NCompressionMethod::kZstdWz) + { + if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) < 0) + { + // numZstdThreads was not forced in oneMethodMain + if (numThreads >= 1 + && options._memUsage_WasSet + && !options._numThreads_WasForced) + { + NCompress::NZstd::CEncoderProps encoderProps; + RINOK(encoderProps.SetFromMethodProps(*oneMethodMain)) + CZstdEncProps &zstdProps = encoderProps.EncProps; + ZstdEncProps_NormalizeFull(&zstdProps); + numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit( + &zstdProps, options._memUsage_Compress, numThreads); + // we allow (nbWorkers = 1) here. + } + oneMethodMain->AddProp_NumThreads(numThreads); + } + } // kZstdWz + */ + // } // oneMethodMain + + FOR_VECTOR (mi, options2._methods) + { + COneMethodInfo &onem = options2._methods[mi]; + + if (onem.FindProp(NCoderPropID::kNumThreads) < 0) + { + // fixme: we should check the number of threads for xz method also + // fixed for 9.31. bzip2 default is just one thread. + onem.AddProp_NumThreads(numThreads); + } + } + } + else // mtMode + { + if (method == NFileHeader::NCompressionMethod::kStore && !options.Password_Defined) + numThreads = 1; + + if (oneMethodMain) + { + + if (method == NFileHeader::NCompressionMethod::kBZip2) + { + bool fixedNumber; + UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber); + if (!fixedNumber) + { + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize(); + const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1; + numBZip2Threads = 64; + if (numBZip2Threads > averageNumberOfBlocks) + numBZip2Threads = (UInt32)averageNumberOfBlocks; + if (numBZip2Threads > numThreads) + numBZip2Threads = numThreads; + oneMethodMain->AddProp_NumThreads(numBZip2Threads); + } + numThreads /= numBZip2Threads; + } + else if (method == NFileHeader::NCompressionMethod::kXz) + { + UInt32 numLzmaThreads = 1; + int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads); + if (numXzThreads < 0) + { + // numXzThreads is unknown + const UInt64 averageSize = numBytesToCompress / numFilesToCompress; + const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize(); + UInt64 averageNumberOfBlocks = 1; + if (blockSize != (UInt64)(Int64)-1) + averageNumberOfBlocks = averageSize / blockSize + 1; + UInt32 t = 256; + if (t > averageNumberOfBlocks) + t = (UInt32)averageNumberOfBlocks; + t *= numLzmaThreads; + if (t > numThreads) + t = numThreads; + oneMethodMain->AddProp_NumThreads(t); + numXzThreads = (int)t; + } + numThreads /= (unsigned)numXzThreads; + } + /* + else if (method == NFileHeader::NCompressionMethod::kZstdWz) + { + numThreads = SetZstdThreads(options, + oneMethodMain, numThreads, + numZipThreads_limit, + numFilesToCompress, numBytesToCompress); + } + */ + else if ( + method == NFileHeader::NCompressionMethod::kDeflate + || method == NFileHeader::NCompressionMethod::kDeflate64 + || method == NFileHeader::NCompressionMethod::kPPMd) + { + if (numThreads > 1 + && options._memUsage_WasSet + && !options._numThreads_WasForced) + { + UInt64 methodMemUsage; + if (method == NFileHeader::NCompressionMethod::kPPMd) + methodMemUsage = oneMethodMain->Get_Ppmd_MemSize(); + else + methodMemUsage = (4 << 20); // for deflate + const UInt64 threadMemUsage = kMemPerThread + methodMemUsage; + const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage; + if (numThreads64 < numThreads) + numThreads = (UInt32)numThreads64; + } + } + else if (method == NFileHeader::NCompressionMethod::kLZMA) + { + // we suppose that default LZMA is 2 thread. So we don't change it + const UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads(); + numThreads /= numLZMAThreads; + + if (numThreads > 1 + && options._memUsage_WasSet + && !options._numThreads_WasForced) + { + const UInt64 methodMemUsage = oneMethodMain->Get_Lzma_MemUsage(true); + const UInt64 threadMemUsage = kMemPerThread + methodMemUsage; + const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage; + if (numThreads64 < numThreads) + numThreads = (UInt32)numThreads64; + } + } + } // (oneMethodMain) + + if (numThreads > numZipThreads_limit) + numThreads = numZipThreads_limit; + if (numThreads <= 1) + { + mtMode = false; + numThreads = 1; + } + } + + // mtMode = true; // to test mtMode for seqMode + + if (!mtMode) + #endif + return Update2St( + EXTERNAL_CODECS_LOC_VARS + archive, inArchive, + inputItems, updateItems, + updateOptions, + &options2, outSeqMode, + comment, updateCallback, totalComplexity, + opCallback + // , reportArcProp + ); + + + #ifndef Z7_ST + + /* + CTotalStats stat; + stat.Size = 0; + stat.PackSize = 0; + */ + if (numThreads < 1) + numThreads = 1; + + CObjectVector items; + + CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; + CMyComPtr progress = mtProgressMixerSpec; + mtProgressMixerSpec->Create(updateCallback, true); + + CMtCompressProgressMixer mtCompressProgressMixer; + mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress); + + CMemBlockManagerMt memManager(kBlockSize); + CMemRefs refs(&memManager); + + CMtSem mtSem; + CThreads threads; + mtSem.Head = -1; + mtSem.Indexes.ClearAndSetSize(numThreads); + { + WRes wres = mtSem.Semaphore.Create(0, numThreads); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + + CUIntVector threadIndices; // list threads in order of updateItems + + { + RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize))) + for (i = 0; i < updateItems.Size(); i++) + refs.Refs.Add(CMemBlocks2()); + + for (i = 0; i < numThreads; i++) + { + threads.Threads.AddNew(); + // mtSem.Indexes[i] = -1; // actually we don't use these values + } + + for (i = 0; i < numThreads; i++) + { + CThreadInfo &threadInfo = threads.Threads[i]; + threadInfo.ThreadIndex = i; + threadInfo.SetOptions(options2); + #ifdef Z7_EXTERNAL_CODECS + threadInfo._externalCodecs = _externalCodecs; + #endif + RINOK(threadInfo.CreateEvents()) + threadInfo.OutStreamSpec = new COutMemStream(&memManager); + RINOK(threadInfo.OutStreamSpec->CreateEvents(SYNC_WFMO(&memManager.Synchro))) + threadInfo.OutStream = threadInfo.OutStreamSpec; + threadInfo.ProgressSpec = new CMtCompressProgress(); + threadInfo.Progress = threadInfo.ProgressSpec; + threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i); + threadInfo.MtSem = &mtSem; + RINOK(threadInfo.CreateThread()) + } + } + + unsigned mtItemIndex = 0; + unsigned itemIndex = 0; + int lastRealStreamItemIndex = -1; + + + while (itemIndex < updateItems.Size()) + { + if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size()) + { + // we start ahead the threads for compressing + // also we set refs.Refs[itemIndex].SeqMode that is used later + // don't move that code block + + CUpdateItem &ui = updateItems[mtItemIndex++]; + if (!ui.NewData) + continue; + CItemEx itemEx; + CItemOut item; + + if (ui.NewProps) + { + if (ui.IsDir) + continue; + } + else + { + itemEx = inputItems[(unsigned)ui.IndexInArc]; + if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK) + return E_NOTIMPL; + (CItem &)item = itemEx; + if (item.IsDir() != ui.IsDir) + return E_NOTIMPL; + if (ui.IsDir) + continue; + } + + CMyComPtr fileInStream; + + CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1]; + + { + NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection); + const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + if (res == S_FALSE) + { + complexity += ui.Size; + complexity += kLocalHeaderSize; + mtProgressMixerSpec->Mixer2->SetProgressOffset_NoLock(complexity); + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + memRef2.Skip = true; + continue; + } + RINOK(res) + if (!fileInStream) + return E_INVALIDARG; + UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity); + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + } + + UInt32 k; + for (k = 0; k < numThreads; k++) + if (threads.Threads[k].IsFree) + break; + + if (k == numThreads) + return E_FAIL; + { + { + CThreadInfo &threadInfo = threads.Threads[k]; + threadInfo.IsFree = false; + threadInfo.InStream = fileInStream; + + bool inSeqMode = false; + + if (!inSeqMode) + { + CMyComPtr inStream2; + fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2); + inSeqMode = (inStream2 == NULL); + } + memRef2.InSeqMode = inSeqMode; + + // !!!!! we must release ref before sending event + // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time + fileInStream.Release(); + + threadInfo.OutStreamSpec->Init(); + threadInfo.ProgressSpec->Reinit(); + + threadInfo.UpdateIndex = mtItemIndex - 1; + threadInfo.InSeqMode = inSeqMode; + threadInfo.OutSeqMode = outSeqMode; + threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode + threadInfo.ExpectedDataSize = ui.Size; + threadInfo.ExpectedDataSize_IsConfirmed = ui.Size_WasSetFromStream; + + threadInfo.CompressEvent.Set(); + + threadIndices.Add(k); + } + } + + continue; + } + + if (refs.Refs[itemIndex].Skip) + { + itemIndex++; + continue; + } + + const CUpdateItem &ui = updateItems[itemIndex]; + + CItemEx itemEx; + CItemOut item; + + if (!ui.NewProps || !ui.NewData) + { + itemEx = inputItems[(unsigned)ui.IndexInArc]; + if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK) + return E_NOTIMPL; + (CItem &)item = itemEx; + } + + if (ui.NewData) + { + // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir()); + const bool isDir = ui.IsDir; + + if (isDir) + { + RINOK(WriteDirHeader(archive, &options, ui, item)) + } + else + { + CMemBlocks2 &memRef = refs.Refs[itemIndex]; + + if (memRef.Finished) + { + if (lastRealStreamItemIndex < (int)itemIndex) + lastRealStreamItemIndex = (int)itemIndex; + + SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, item); + + // the BUG was fixed in 9.26: + // SetItemInfoFromCompressingResult must be after SetFileHeader + // to write correct Size. + + SetItemInfoFromCompressingResult(memRef.CompressingResult, + options.IsRealAesMode(), options.AesKeyMode, item); + RINOK(archive.ClearRestriction()) + archive.WriteLocalHeader(item); + // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + CMyComPtr outStream; + archive.CreateStreamForCopying(outStream); + memRef.WriteToStream(memManager.GetBlockSize(), outStream); + // v23: we fixed the bug: we need to write descriptor also + if (item.HasDescriptor()) + { + /* that function doesn't rewrite local header, if item.HasDescriptor(). + it just writes descriptor */ + archive.WriteLocalHeader_Replace(item); + } + else + archive.MoveCurPos(item.PackSize); + memRef.FreeOpt(&memManager); + /* + if (reportArcProp) + { + stat.UpdateWithItem(item); + RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode())); + } + */ + } + else + { + // current file was not finished + + if (lastRealStreamItemIndex < (int)itemIndex) + { + // LocalHeader was not written for current itemIndex still + + lastRealStreamItemIndex = (int)itemIndex; + + // thread was started before for that item already, and memRef.SeqMode was set + + CCompressingResult compressingResult; + RINOK(compressor.Set_Pre_CompressionResult( + memRef.InSeqMode, outSeqMode, + ui.Size, + compressingResult)) + + memRef.PreDescriptorMode = compressingResult.DescriptorMode; + SetFileHeader(options, ui, compressingResult.DescriptorMode, item); + + SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item); + + // file Size can be 64-bit !!! + RINOK(archive.SetRestrictionFromCurrent()) + archive.WriteLocalHeader(item); + } + + { + CThreadInfo &thread = threads.Threads[threadIndices.FrontItem()]; + if (!thread.OutStreamSpec->WasUnlockEventSent()) + { + CMyComPtr outStream; + archive.CreateStreamForCompressing(outStream); + thread.OutStreamSpec->SetOutStream(outStream); + thread.OutStreamSpec->SetRealStreamMode(); + } + } + + const WRes wres = mtSem.Semaphore.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + + const int ti = mtSem.GetFreeItem(); + if (ti < 0) + return E_FAIL; + + CThreadInfo &threadInfo = threads.Threads[(unsigned)ti]; + threadInfo.InStream.Release(); + threadInfo.IsFree = true; + RINOK(threadInfo.Result) + + unsigned t = 0; + + for (;;) + { + if (t == threadIndices.Size()) + return E_FAIL; + if (threadIndices[t] == (unsigned)ti) + break; + t++; + } + threadIndices.Delete(t); + + if (t == 0) + { + // if thread for current file was finished. + if (threadInfo.UpdateIndex != itemIndex) + return E_FAIL; + + if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode) + return E_FAIL; + + RINOK(threadInfo.OutStreamSpec->WriteToRealStream()) + threadInfo.OutStreamSpec->ReleaseOutStream(); + SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item); + SetItemInfoFromCompressingResult(threadInfo.CompressingResult, + options.IsRealAesMode(), options.AesKeyMode, item); + + archive.WriteLocalHeader_Replace(item); + + /* + if (reportArcProp) + { + stat.UpdateWithItem(item); + RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode())); + } + */ + } + else + { + // it's not current file. So we must store information in array + CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex]; + threadInfo.OutStreamSpec->DetachData(memRef2); + memRef2.CompressingResult = threadInfo.CompressingResult; + // memRef2.SeqMode = threadInfo.SeqMode; // it was set before + memRef2.Finished = true; + continue; + } + } + } + } + else + { + RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity)) + } + + items.Add(item); + complexity += kLocalHeaderSize; + mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); + itemIndex++; + } + + RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)) + + RINOK(archive.WriteCentralDir(items, comment)) + + /* + if (reportArcProp) + { + RINOK(ReportArcProps(reportArcProp, stat)); + } + */ + + complexity += kCentralHeaderSize * updateItems.Size() + 1; + mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); + return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); + + #endif +} + +/* +// we need CSeekOutStream, if we need Seek(0, STREAM_SEEK_CUR) for seqential stream +Z7_CLASS_IMP_COM_1( + CSeekOutStream + , IOutStream +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + CMyComPtr _seqStream; + UInt64 _size; +public: + void Init(ISequentialOutStream *seqStream) + { + _size = 0; + _seqStream = seqStream; + } +}; + +Z7_COM7F_IMF(CSeekOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize; + const HRESULT result = _seqStream->Write(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return result; +} + +Z7_COM7F_IMF(CSeekOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + if (seekOrigin != STREAM_SEEK_CUR || offset != 0) + return E_NOTIMPL; + if (newPosition) + *newPosition = (UInt64)_size; + return S_OK; +} + +Z7_COM7F_IMF(CSeekOutStream::SetSize(UInt64 newSize)) +{ + UNUSED_VAR(newSize) + return E_NOTIMPL; +} +*/ + +static const size_t kCacheBlockSize = 1 << 20; +static const size_t kCacheSize = kCacheBlockSize << 2; +static const size_t kCacheMask = kCacheSize - 1; + +Z7_CLASS_IMP_NOQIB_2( + CCacheOutStream + , IOutStream + , IStreamSetRestriction +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + HRESULT _hres; + CMyComPtr _seqStream; + CMyComPtr _stream; + CMyComPtr _setRestriction; + Byte *_cache; + size_t _cachedSize; + UInt64 _cachedPos; + UInt64 _virtPos; + UInt64 _virtSize; + UInt64 _phyPos; + UInt64 _phySize; + UInt64 _restrict_begin; + UInt64 _restrict_end; + + HRESULT FlushFromCache(size_t size); + HRESULT FlushNonRestrictedBlocks(); + HRESULT FlushCache(); + HRESULT SetRestriction_ForWrite(size_t writeSize) const; + + HRESULT SeekPhy(UInt64 pos) + { + if (pos == _phyPos) + return S_OK; + if (!_stream) + return E_NOTIMPL; + _hres = _stream->Seek((Int64)pos, STREAM_SEEK_SET, &_phyPos); + if (_hres == S_OK && _phyPos != pos) + _hres = E_FAIL; + return _hres; + } + +public: + CCacheOutStream(): _cache(NULL) {} + ~CCacheOutStream(); + bool Allocate() + { + if (!_cache) + _cache = (Byte *)::MidAlloc(kCacheSize); + return _cache != NULL; + } + HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction); + HRESULT FinalFlush(); +}; + +CCacheOutStream::~CCacheOutStream() +{ + ::MidFree(_cache); +} + + +HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction) +{ + _hres = S_OK; + _cachedSize = 0; + _cachedPos = 0; + _virtPos = 0; + _virtSize = 0; + // by default we have no restriction + _restrict_begin = 0; + _restrict_end = 0; + _seqStream = seqStream; + _stream = stream; + _setRestriction = setRestriction; + if (_stream) + { + RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos)) + RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize)) + RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, &_virtPos)) + } + _phyPos = _virtPos; + _phySize = _virtSize; + return S_OK; +} + + +/* we call SetRestriction_ForWrite() just before Write() from cache. + (_phyPos == _cachedPos) + (writeSize != 0) +*/ +HRESULT CCacheOutStream::SetRestriction_ForWrite(size_t writeSize) const +{ + if (!_setRestriction) + return S_OK; + PRF(printf("\n-- CCacheOutStream::SetRestriction_ForWrite _cachedPos = 0x%x, writeSize = %d\n", (unsigned)_cachedPos, (unsigned)writeSize)); + UInt64 begin = _restrict_begin; + UInt64 end = _restrict_end; + const UInt64 phyPos = _phyPos; + if (phyPos != _cachedPos) return E_FAIL; + if (phyPos == _phySize) + { + // The writing will be to the end of phy stream. + // So we will try to use non-restricted write, if possible. + if (begin == end) + begin = _virtPos; // _virtSize; // it's supposed that (_virtSize == _virtPos) + if (phyPos + writeSize <= begin) + { + // the write is not restricted + PRF(printf("\n+++ write is not restricted \n")); + begin = 0; + end = 0; + } + else + { + if (begin > phyPos) + begin = phyPos; + end = (UInt64)(Int64)-1; + } + } + else + { + // (phyPos != _phySize) + if (begin == end || begin > phyPos) + begin = phyPos; + end = (UInt64)(Int64)-1; + } + return _setRestriction->SetRestriction(begin, end); +} + + +/* it writes up to (size) bytes from cache. + (size > _cachedSize) is allowed +*/ +HRESULT CCacheOutStream::FlushFromCache(size_t size) +{ + PRF(printf("\n-- CCacheOutStream::FlushFromCache %u\n", (unsigned)size)); + if (_hres != S_OK) + return _hres; + if (size > _cachedSize) + size = _cachedSize; + // (size <= _cachedSize) + if (size == 0) + return S_OK; + RINOK(SeekPhy(_cachedPos)) + for (;;) + { + // (_phyPos == _cachedPos) + const size_t pos = (size_t)_cachedPos & kCacheMask; + const size_t cur = MyMin(kCacheSize - pos, size); + _hres = SetRestriction_ForWrite(cur); + RINOK(_hres) + PRF(printf("\n-- CCacheOutStream::WriteFromCache _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)cur)); + _hres = WriteStream(_seqStream, _cache + pos, cur); + RINOK(_hres) + _phyPos += cur; + if (_phySize < _phyPos) + _phySize = _phyPos; + _cachedPos += cur; + _cachedSize -= cur; + size -= cur; + if (size == 0) + return S_OK; + } +} + + +HRESULT CCacheOutStream::FlushNonRestrictedBlocks() +{ + for (;;) + { + const size_t size = kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)); + if (_cachedSize < size) + break; + UInt64 begin = _restrict_begin; + if (begin == _restrict_end) + begin = _virtPos; + // we don't flush the data to restricted area + if (_cachedPos + size > begin) + break; + RINOK(FlushFromCache(size)) + } + return S_OK; +} + + +HRESULT CCacheOutStream::FlushCache() +{ + return FlushFromCache(_cachedSize); +} + +HRESULT CCacheOutStream::FinalFlush() +{ + _restrict_begin = 0; + _restrict_end = 0; + RINOK(FlushCache()) + if (_stream && _hres == S_OK) + { + if (_virtSize != _phySize) + { + // it's unexpected + RINOK(_stream->SetSize(_virtSize)) + _phySize = _virtSize; + } + _hres = SeekPhy(_virtPos); + } + return _hres; +} + + +Z7_COM7F_IMF(CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + PRF(printf("\n==== CCacheOutStream::Write virtPos=0x%x, %u\n", (unsigned)_virtPos, (unsigned)size)); + + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_hres != S_OK) + return _hres; + + if (_cachedSize != 0) + if (_virtPos < _cachedPos || + _virtPos > _cachedPos + _cachedSize) + { + RINOK(FlushCache()) + } + + if (_cachedSize == 0) + _cachedPos = _virtPos; + + const size_t pos = (size_t)_virtPos & kCacheMask; + { + const size_t blockRem = kCacheBlockSize - ((size_t)_virtPos & (kCacheBlockSize - 1)); + if (size > blockRem) + size = (UInt32)blockRem; + } + // _cachedPos <= _virtPos <= _cachedPos + _cachedSize + const UInt64 cachedRem = _cachedPos + _cachedSize - _virtPos; + if (cachedRem) + { + // _virtPos < _cachedPos + _cachedSize + // we rewrite only existing data in cache. So _cachedSize will be not changed + if (size > cachedRem) + size = (UInt32)cachedRem; + } + else + { + // _virtPos == _cachedPos + _cachedSize + // so we need to add new data to the end of cache + if (_cachedSize == kCacheSize) + { + // cache is full. So we need to flush some part of cache. + // we flush only one block, but we are allowed to flush any size here + RINOK(FlushFromCache(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)))) + } + // _cachedSize != kCacheSize + // so we have some space for new data in cache + if (_cachedSize == 0) + { + /* this code is optional (for optimization): + we write data directly without cache, + if there is no restriction and we have full block. */ + if (_restrict_begin == _restrict_end + && size == kCacheBlockSize) + { + RINOK(SeekPhy(_virtPos)) + if (_setRestriction) + { + _hres = _setRestriction->SetRestriction(_restrict_begin, _restrict_end); + RINOK(_hres) + } + PRF(printf("\n-- CCacheOutStream::WriteDirectly _phyPos = 0x%x, size = %d\n", (unsigned)_phyPos, (unsigned)size)); + _hres = WriteStream(_seqStream, data, size); + RINOK(_hres) + if (processedSize) + *processedSize = size; + _virtPos += size; + if (_virtSize < _virtPos) + _virtSize = _virtPos; + _phyPos += size; + if (_phySize < _phyPos) + _phySize = _phyPos; + return S_OK; + } + } + else // (_cachedSize != 0) + { + const size_t startPos = (size_t)_cachedPos & kCacheMask; + // we don't allow new data to overwrite old start data in cache. + // (startPos == pos) here means that cache is empty. + // (startPos == pos) is not possible here. + if (startPos > pos) + size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos)); + } + // _virtPos == (_cachedPos + _cachedSize) still + _cachedSize += size; + } + + memcpy(_cache + pos, data, size); + if (processedSize) + *processedSize = size; + _virtPos += size; + if (_virtSize < _virtPos) + _virtSize = _virtPos; + return FlushNonRestrictedBlocks(); +} + + +Z7_COM7F_IMF(CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + PRF(printf("\n==== CCacheOutStream::Seek seekOrigin=%d Seek =%u\n", seekOrigin, (unsigned)offset)); + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _virtSize; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + +Z7_COM7F_IMF(CCacheOutStream::SetSize(UInt64 newSize)) +{ + if (_hres != S_OK) + return _hres; + + if (newSize <= _cachedPos || _cachedSize == 0) + { + _cachedSize = 0; + _cachedPos = newSize; + } + else + { + // _cachedSize != 0 + // newSize > _cachedPos + const UInt64 offset = newSize - _cachedPos; + if (offset <= _cachedSize) + { + // newSize is inside cached block or is touching cached block. + // so we reduce cache + _cachedSize = (size_t)offset; + if (_phySize <= newSize) + { + // _phySize will be restored later after cache flush + _virtSize = newSize; + return S_OK; + } + // (_phySize > newSize) + // so we must reduce phyStream size to (newSize) or to (_cachedPos) + // newPhySize = _cachedPos; // optional reduce to _cachedPos + } + else + { + // newSize > _cachedPos + _cachedSize + /* It's possible that we need to write zeros, + if new size is larger than old size. + We don't optimize for possible cases here. + So we just flush the cache. */ + _hres = FlushCache(); + } + } + + _virtSize = newSize; + + if (_hres != S_OK) + return _hres; + + if (newSize != _phySize) + { + if (!_stream) + return E_NOTIMPL; + // if (_phyPos > newSize) + RINOK(SeekPhy(newSize)) + if (_setRestriction) + { + UInt64 begin = _restrict_begin; + UInt64 end = _restrict_end; + if (_cachedSize != 0) + { + if (begin > _cachedPos) + begin = _cachedPos; + end = (UInt64)(Int64)-1; + } + _hres = _setRestriction->SetRestriction(begin, end); + RINOK(_hres) + } + _hres = _stream->SetSize(newSize); + RINOK(_hres) + _phySize = newSize; + } + return S_OK; +} + + +Z7_COM7F_IMF(CCacheOutStream::SetRestriction(UInt64 begin, UInt64 end)) +{ + PRF(printf("\n============ CCacheOutStream::SetRestriction 0x%x, %u\n", (unsigned)begin, (unsigned)end)); + _restrict_begin = begin; + _restrict_end = end; + return FlushNonRestrictedBlocks(); +} + + + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &inputItems, + CObjectVector &updateItems, + ISequentialOutStream *seqOutStream, + CInArchive *inArchive, bool removeSfx, + const CUpdateOptions &updateOptions, + const CCompressionMethodMode &compressionMethodMode, + IArchiveUpdateCallback *updateCallback) +{ + /* + // it was tested before + if (inArchive) + { + if (!inArchive->CanUpdate()) + return E_NOTIMPL; + } + */ + + CMyComPtr setRestriction; + seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction); + if (setRestriction) + { + RINOK(setRestriction->SetRestriction(0, 0)) + } + + CMyComPtr outStream; + CCacheOutStream *cacheStream; + bool outSeqMode; + + { + CMyComPtr outStreamReal; + + if (!compressionMethodMode.Force_SeqOutMode) + { + seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal); + /* + if (!outStreamReal) + return E_NOTIMPL; + */ + } + + if (inArchive) + { + if (!inArchive->IsMultiVol && inArchive->ArcInfo.Base > 0 && !removeSfx) + { + IInStream *baseStream = inArchive->GetBaseStream(); + RINOK(InStream_SeekToBegin(baseStream)) + RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, (UInt64)inArchive->ArcInfo.Base, NULL)) + } + } + + outSeqMode = (outStreamReal == NULL); + if (outSeqMode) + setRestriction.Release(); + /* CCacheOutStream works as non-restricted by default. + So we use (setRestriction == NULL) for outSeqMode */ + // bool use_cacheStream = true; + // if (use_cacheStream) + { + cacheStream = new CCacheOutStream(); + outStream = cacheStream; + if (!cacheStream->Allocate()) + return E_OUTOFMEMORY; + RINOK(cacheStream->Init(seqOutStream, outStreamReal, setRestriction)) + setRestriction.Release(); + if (!outSeqMode) + setRestriction = cacheStream; + } + /* + else if (!outStreamReal) + { + CSeekOutStream *seekOutStream = new CSeekOutStream(); + outStream = seekOutStream; + seekOutStream->Init(seqOutStream); + } + else + outStream = outStreamReal; + */ + } + + COutArchive outArchive; + outArchive.SetRestriction = setRestriction; + + RINOK(outArchive.Create(outStream)) + + if (inArchive) + { + if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base) + { + IInStream *baseStream = inArchive->GetBaseStream(); + RINOK(InStream_SeekSet(baseStream, (UInt64)inArchive->ArcInfo.Base)) + const UInt64 embStubSize = (UInt64)((Int64)inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base); + RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL)) + outArchive.MoveCurPos(embStubSize); + } + } + + RINOK (Update2( + EXTERNAL_CODECS_LOC_VARS + outArchive, inArchive, + inputItems, updateItems, + updateOptions, + compressionMethodMode, outSeqMode, + inArchive ? &inArchive->ArcInfo.Comment : NULL, + updateCallback)) + + return cacheStream->FinalFlush(); +} + +}} diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h index 6c0186733..13ecd9cb6 100644 --- a/CPP/7zip/Archive/Zip/ZipUpdate.h +++ b/CPP/7zip/Archive/Zip/ZipUpdate.h @@ -1,107 +1,107 @@ -// ZipUpdate.h - -#ifndef ZIP7_INC_ZIP_UPDATE_H -#define ZIP7_INC_ZIP_UPDATE_H - -#include "../../ICoder.h" -#include "../IArchive.h" - -#include "../../Common/CreateCoder.h" - -#include "ZipCompressionMode.h" -#include "ZipIn.h" - -namespace NArchive { -namespace NZip { - -/* -struct CUpdateRange -{ - UInt64 Position; - UInt64 Size; - - // CUpdateRange() {} - CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {} -}; -*/ - -struct CUpdateItem -{ - bool NewData; - bool NewProps; - bool IsDir; - bool Write_NtfsTime; - bool Write_UnixTime; - // bool Write_UnixTime_ATime; - bool IsUtf8; - bool Size_WasSetFromStream; - // bool IsAltStream; - int IndexInArc; - unsigned IndexInClient; - UInt32 Attrib; - UInt32 Time; - UInt64 Size; - AString Name; - CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra - CByteBuffer Comment; - // bool Commented; - // CUpdateRange CommentRange; - FILETIME Ntfs_MTime; - FILETIME Ntfs_ATime; - FILETIME Ntfs_CTime; - - void Clear() - { - IsDir = false; - - Write_NtfsTime = false; - Write_UnixTime = false; - - IsUtf8 = false; - Size_WasSetFromStream = false; - // IsAltStream = false; - Time = 0; - Size = 0; - Name.Empty(); - Name_Utf.Free(); - Comment.Free(); - - FILETIME_Clear(Ntfs_MTime); - FILETIME_Clear(Ntfs_ATime); - FILETIME_Clear(Ntfs_CTime); - } - - CUpdateItem(): - IsDir(false), - Write_NtfsTime(false), - Write_UnixTime(false), - IsUtf8(false), - Size_WasSetFromStream(false), - // IsAltStream(false), - Time(0), - Size(0) - {} -}; - - -struct CUpdateOptions -{ - bool Write_MTime; - bool Write_ATime; - bool Write_CTime; -}; - - -HRESULT Update( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &inputItems, - CObjectVector &updateItems, - ISequentialOutStream *seqOutStream, - CInArchive *inArchive, bool removeSfx, - const CUpdateOptions &updateOptions, - const CCompressionMethodMode &compressionMethodMode, - IArchiveUpdateCallback *updateCallback); - -}} - -#endif +// ZipUpdate.h + +#ifndef ZIP7_INC_ZIP_UPDATE_H +#define ZIP7_INC_ZIP_UPDATE_H + +#include "../../ICoder.h" +#include "../IArchive.h" + +#include "../../Common/CreateCoder.h" + +#include "ZipCompressionMode.h" +#include "ZipIn.h" + +namespace NArchive { +namespace NZip { + +/* +struct CUpdateRange +{ + UInt64 Position; + UInt64 Size; + + // CUpdateRange() {} + CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {} +}; +*/ + +struct CUpdateItem +{ + bool NewData; + bool NewProps; + bool IsDir; + bool Write_NtfsTime; + bool Write_UnixTime; + // bool Write_UnixTime_ATime; + bool IsUtf8; + bool Size_WasSetFromStream; + // bool IsAltStream; + int IndexInArc; + unsigned IndexInClient; + UInt32 Attrib; + UInt32 Time; + UInt64 Size; + AString Name; + CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra + CByteBuffer Comment; + // bool Commented; + // CUpdateRange CommentRange; + FILETIME Ntfs_MTime; + FILETIME Ntfs_ATime; + FILETIME Ntfs_CTime; + + void Clear() + { + IsDir = false; + + Write_NtfsTime = false; + Write_UnixTime = false; + + IsUtf8 = false; + Size_WasSetFromStream = false; + // IsAltStream = false; + Time = 0; + Size = 0; + Name.Empty(); + Name_Utf.Free(); + Comment.Free(); + + FILETIME_Clear(Ntfs_MTime); + FILETIME_Clear(Ntfs_ATime); + FILETIME_Clear(Ntfs_CTime); + } + + CUpdateItem(): + IsDir(false), + Write_NtfsTime(false), + Write_UnixTime(false), + IsUtf8(false), + Size_WasSetFromStream(false), + // IsAltStream(false), + Time(0), + Size(0) + {} +}; + + +struct CUpdateOptions +{ + bool Write_MTime; + bool Write_ATime; + bool Write_CTime; +}; + + +HRESULT Update( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &inputItems, + CObjectVector &updateItems, + ISequentialOutStream *seqOutStream, + CInArchive *inArchive, bool removeSfx, + const CUpdateOptions &updateOptions, + const CCompressionMethodMode &compressionMethodMode, + IArchiveUpdateCallback *updateCallback); + +}} + +#endif diff --git a/CPP/7zip/Archive/ZstdHandler.cpp b/CPP/7zip/Archive/ZstdHandler.cpp index e5d47c77c..b9c0fb7b6 100644 --- a/CPP/7zip/Archive/ZstdHandler.cpp +++ b/CPP/7zip/Archive/ZstdHandler.cpp @@ -1,1147 +1,1147 @@ -// ZstdHandler.cpp - -#include "StdAfx.h" - -// #define Z7_USE_ZSTD_ORIG_DECODER -// #define Z7_USE_ZSTD_COMPRESSION - -#include "../../Common/ComTry.h" - -#include "../Common/MethodProps.h" -#include "../Common/ProgressUtils.h" -#include "../Common/RegisterArc.h" -#include "../Common/StreamUtils.h" - -#include "../Compress/CopyCoder.h" -#include "../Compress/ZstdDecoder.h" -#ifdef Z7_USE_ZSTD_ORIG_DECODER -#include "../Compress/Zstd2Decoder.h" -#endif - -#ifdef Z7_USE_ZSTD_COMPRESSION -#include "../Compress/ZstdEncoder.h" -#include "../Compress/ZstdEncoderProps.h" -#include "Common/HandlerOut.h" -#endif - -#include "Common/DummyOutStream.h" - -#include "../../../C/CpuArch.h" - -using namespace NWindows; - -namespace NArchive { -namespace NZstd { - -#define DESCRIPTOR_Get_DictionaryId_Flag(d) ((d) & 3) -#define DESCRIPTOR_FLAG_CHECKSUM (1 << 2) -#define DESCRIPTOR_FLAG_RESERVED (1 << 3) -#define DESCRIPTOR_FLAG_UNUSED (1 << 4) -#define DESCRIPTOR_FLAG_SINGLE (1 << 5) -#define DESCRIPTOR_Get_ContentSize_Flag3(d) ((d) >> 5) -#define DESCRIPTOR_Is_ContentSize_Defined(d) (((d) & 0xe0) != 0) - -struct CFrameHeader -{ - Byte Descriptor; - Byte WindowDescriptor; - UInt32 DictionaryId; - UInt64 ContentSize; - - /* by zstd specification: - the decoder must check that (Is_Reserved() == false) - the decoder must ignore Unused_bit */ - bool Is_Reserved() const { return (Descriptor & DESCRIPTOR_FLAG_RESERVED) != 0; } - bool Is_Checksum() const { return (Descriptor & DESCRIPTOR_FLAG_CHECKSUM) != 0; } - bool Is_SingleSegment() const { return (Descriptor & DESCRIPTOR_FLAG_SINGLE) != 0; } - bool Is_ContentSize_Defined() const { return DESCRIPTOR_Is_ContentSize_Defined(Descriptor); } - unsigned Get_DictionaryId_Flag() const { return DESCRIPTOR_Get_DictionaryId_Flag(Descriptor); } - unsigned Get_ContentSize_Flag3() const { return DESCRIPTOR_Get_ContentSize_Flag3(Descriptor); } - - const Byte *Parse(const Byte *p, int size) - { - if ((unsigned)size < 2) - return NULL; - Descriptor = *p++; - size--; - { - Byte w = 0; - if (!Is_SingleSegment()) - { - w = *p++; - size--; - } - WindowDescriptor = w; - } - { - unsigned n = Get_DictionaryId_Flag(); - UInt32 d = 0; - if (n) - { - n = (unsigned)1 << (n - 1); - if ((size -= (int)n) < 0) - return NULL; - d = GetUi32(p) & ((UInt32)(Int32)-1 >> (32 - 8u * n)); - p += n; - } - DictionaryId = d; - } - { - unsigned n = Get_ContentSize_Flag3(); - UInt64 v = 0; - if (n) - { - n >>= 1; - if (n == 1) - v = 256; - n = (unsigned)1 << n; - if ((size -= (int)n) < 0) - return NULL; - v += GetUi64(p) & ((UInt64)(Int64)-1 >> (64 - 8u * n)); - p += n; - } - ContentSize = v; - } - return p; - } -}; - - - -class CHandler Z7_final: - public IInArchive, - public IArchiveOpenSeq, - public ISetProperties, -#ifdef Z7_USE_ZSTD_COMPRESSION - public IOutArchive, -#endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IInArchive) - Z7_COM_QI_ENTRY(IArchiveOpenSeq) - Z7_COM_QI_ENTRY(ISetProperties) -#ifdef Z7_USE_ZSTD_COMPRESSION - Z7_COM_QI_ENTRY(IOutArchive) -#endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInArchive) - Z7_IFACE_COM7_IMP(IArchiveOpenSeq) - Z7_IFACE_COM7_IMP(ISetProperties) -#ifdef Z7_USE_ZSTD_COMPRESSION - Z7_IFACE_COM7_IMP(IOutArchive) -#endif - - bool _isArc; - bool _needSeekToStart; - // bool _dataAfterEnd; - // bool _needMoreInput; - bool _unsupportedBlock; - - bool _wasParsed; - bool _phySize_Decoded_Defined; - bool _unpackSize_Defined; // decoded - bool _decoded_Info_Defined; - - bool _parseMode; - bool _disableHash; - // bool _smallMode; - - UInt64 _phySize; - UInt64 _phySize_Decoded; - UInt64 _unpackSize; - - CZstdDecInfo _parsed_Info; - CZstdDecInfo _decoded_Info; - - CMyComPtr _stream; - CMyComPtr _seqStream; - -#ifdef Z7_USE_ZSTD_COMPRESSION - CSingleMethodProps _props; -#endif - -public: - CHandler(): - _parseMode(false), - _disableHash(false) - // _smallMode(false) - {} -}; - - -static const Byte kProps[] = -{ - kpidSize, - kpidPackSize -}; - -static const Byte kArcProps[] = -{ - kpidNumStreams, - kpidNumBlocks, - kpidMethod, - // kpidChecksum - kpidCRC -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - - -// static const unsigned kBlockType_Raw = 0; -static const unsigned kBlockType_RLE = 1; -// static const unsigned kBlockType_Compressed = 2; -static const unsigned kBlockType_Reserved = 3; -/* -static const char * const kNames[] = -{ - "RAW" - , "RLE" - , "Compressed" - , "Reserved" -}; -*/ - -static void Add_UInt64(AString &s, const char *name, UInt64 v) -{ - s.Add_OptSpaced(name); - s.Add_Colon(); - s.Add_UInt64(v); -} - - -static void PrintSize(AString &s, UInt64 w) -{ - char c = 0; - if ((w & ((1 << 30) - 1)) == 0) { c = 'G'; w >>= 30; } - else if ((w & ((1 << 20) - 1)) == 0) { c = 'M'; w >>= 20; } - else if ((w & ((1 << 10) - 1)) == 0) { c = 'K'; w >>= 10; } - s.Add_UInt64(w); - if (c) - { - s.Add_Char(c); - s += "iB"; - } -} - - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - - CZstdDecInfo *p = NULL; - if (_wasParsed || !_decoded_Info_Defined) - p = &_parsed_Info; - else if (_decoded_Info_Defined) - p = &_decoded_Info; - - switch (propID) - { - case kpidPhySize: - if (_wasParsed) - prop = _phySize; - else if (_phySize_Decoded_Defined) - prop = _phySize_Decoded; - break; - - case kpidUnpackSize: - if (_unpackSize_Defined) - prop = _unpackSize; - break; - - case kpidNumStreams: - if (p) - if (_wasParsed || _decoded_Info_Defined) - prop = p->num_DataFrames; - break; - - case kpidNumBlocks: - if (p) - if (_wasParsed || _decoded_Info_Defined) - prop = p->num_Blocks; - break; - - // case kpidChecksum: - case kpidCRC: - if (p) - if (p->checksum_Defined && p->num_DataFrames == 1) - prop = p->checksum; // it's checksum from last frame - break; - - case kpidMethod: - { - AString s; - s.Add_OptSpaced(p == &_decoded_Info ? - "decoded:" : _wasParsed ? - "parsed:" : - "header-open-only:"); - - if (p->dictionaryId != 0) - { - if (p->are_DictionaryId_Different) - s.Add_OptSpaced("different-dictionary-IDs"); - s.Add_OptSpaced("dictionary-ID:"); - s.Add_UInt32(p->dictionaryId); - } - /* - if (ContentSize_Defined) - { - s.Add_OptSpaced("ContentSize="); - s.Add_UInt64(ContentSize_Total); - } - */ - // if (p->are_Checksums) - if (p->descriptor_OR & DESCRIPTOR_FLAG_CHECKSUM) - s.Add_OptSpaced("XXH64"); - if (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_CHECKSUM) - s.Add_OptSpaced("NO-XXH64"); - - if (p->descriptor_OR & DESCRIPTOR_FLAG_UNUSED) - s.Add_OptSpaced("unused_bit"); - - if (p->descriptor_OR & DESCRIPTOR_FLAG_SINGLE) - s.Add_OptSpaced("single-segments"); - - if (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_SINGLE) - { - // Add_UInt64(s, "wnd-descriptors", p->num_WindowDescriptors); - s.Add_OptSpaced("wnd-desc-log-MAX:"); - // WindowDescriptor_MAX = 16 << 3; // for debug - const unsigned e = p->windowDescriptor_MAX >> 3; - s.Add_UInt32(e + 10); - const unsigned m = p->windowDescriptor_MAX & 7; - if (m != 0) - { - s.Add_Dot(); - s.Add_UInt32(m); - } - } - - if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor_OR) || - (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_SINGLE)) - /* - if (p->are_ContentSize_Known || - p->are_WindowDescriptors) - */ - { - s.Add_OptSpaced("wnd-MAX:"); - PrintSize(s, p->windowSize_MAX); - if (p->windowSize_MAX != p->windowSize_Allocate_MAX) - { - s.Add_OptSpaced("wnd-use-MAX:"); - PrintSize(s, p->windowSize_Allocate_MAX); - } - } - - if (p->num_DataFrames != 1) - Add_UInt64(s, "data-frames", p->num_DataFrames); - if (p->num_SkipFrames != 0) - { - Add_UInt64(s, "skip-frames", p->num_SkipFrames); - Add_UInt64(s, "skip-frames-size-total", p->skipFrames_Size); - } - - if (p->are_ContentSize_Unknown) - s.Add_OptSpaced("unknown-content-size"); - - if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor_OR)) - { - Add_UInt64(s, "content-size-frame-max", p->contentSize_MAX); - Add_UInt64(s, "content-size-total", p->contentSize_Total); - } - - /* - for (unsigned i = 0; i < 4; i++) - { - const UInt64 n = p->num_Blocks_forType[i]; - if (n) - { - s.Add_OptSpaced(kNames[i]); - s += "-blocks:"; - s.Add_UInt64(n); - - s.Add_OptSpaced(kNames[i]); - s += "-block-bytes:"; - s.Add_UInt64(p->num_BlockBytes_forType[i]); - } - } - */ - prop = s; - break; - } - - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - // if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - // if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; - if (_unsupportedBlock) v |= kpv_ErrorFlags_UnsupportedMethod; - /* - if (_parsed_Info.numBlocks_forType[kBlockType_Reserved]) - v |= kpv_ErrorFlags_UnsupportedMethod; - */ - prop = v; - break; - } - - default: break; - } - prop.Detach(value); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = 1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPackSize: - if (_wasParsed) - prop = _phySize; - else if (_phySize_Decoded_Defined) - prop = _phySize_Decoded; - break; - - case kpidSize: - if (_wasParsed && !_parsed_Info.are_ContentSize_Unknown) - prop = _parsed_Info.contentSize_Total; - else if (_unpackSize_Defined) - prop = _unpackSize; - break; - - default: break; - } - prop.Detach(value); - return S_OK; -} - -static const unsigned kSignatureSize = 4; -static const Byte k_Signature[kSignatureSize] = { 0x28, 0xb5, 0x2f, 0xfd } ; - -static const UInt32 kDataFrameSignature32 = 0xfd2fb528; -static const UInt32 kSkipFrameSignature = 0x184d2a50; -static const UInt32 kSkipFrameSignature_Mask = 0xfffffff0; - -/* -API_FUNC_static_IsArc IsArc_Zstd(const Byte *p, size_t size) -{ - if (size < kSignatureSize) - return k_IsArc_Res_NEED_MORE; - if (memcmp(p, k_Signature, kSignatureSize) != 0) - { - const UInt32 v = GetUi32(p); - if ((v & kSkipFrameSignature_Mask) != kSkipFrameSignature) - return k_IsArc_Res_NO; - return k_IsArc_Res_YES; - } - p += 4; - // return k_IsArc_Res_YES; -} -} -*/ - -// kBufSize must be >= (ZSTD_FRAMEHEADERSIZE_MAX = 18) -// we use big buffer for fast parsing of worst case small blocks. -static const unsigned kBufSize = - 1 << 9; - // 1 << 14; // fastest in real file - -struct CStreamBuffer -{ - unsigned pos; - unsigned lim; - IInStream *Stream; - UInt64 StreamOffset; - Byte buf[kBufSize]; - - CStreamBuffer(): - pos(0), - lim(0), - StreamOffset(0) - {} - unsigned Avail() const { return lim - pos; } - const Byte *GetPtr() const { return &buf[pos]; } - UInt64 GetCurOffset() const { return StreamOffset - Avail(); } - void SkipInBuf(UInt32 size) { pos += size; } - HRESULT Skip(UInt32 size); - HRESULT Read(unsigned num); -}; - -HRESULT CStreamBuffer::Skip(UInt32 size) -{ - unsigned rem = lim - pos; - if (rem != 0) - { - if (rem > size) - rem = size; - pos += rem; - size -= rem; - if (pos != lim) - return S_OK; - } - if (size == 0) - return S_OK; - return Stream->Seek(size, STREAM_SEEK_CUR, &StreamOffset); -} - -HRESULT CStreamBuffer::Read(unsigned num) -{ - if (lim - pos >= num) - return S_OK; - if (pos != 0) - { - lim -= pos; - memmove(buf, buf + pos, lim); - pos = 0; - } - size_t processed = kBufSize - ((unsigned)StreamOffset & (kBufSize - 1)); - const unsigned avail = kBufSize - lim; - num -= lim; - if (avail < processed || processed < num) - processed = avail; - const HRESULT res = ReadStream(Stream, buf + lim, &processed); - StreamOffset += processed; - lim += (unsigned)processed; - return res; -} - - -static const unsigned k_ZSTD_FRAMEHEADERSIZE_MAX = 4 + 14; - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) -{ - COM_TRY_BEGIN - Close(); - - CZstdDecInfo *p = &_parsed_Info; - // p->are_ContentSize_Unknown = False; - CStreamBuffer sb; - sb.Stream = stream; - - for (;;) - { - RINOK(sb.Read(k_ZSTD_FRAMEHEADERSIZE_MAX)) - if (sb.Avail() < kSignatureSize) - break; - - if (callback && (ZstdDecInfo_GET_NUM_FRAMES(p) & 0xFFF) == 2) - { - const UInt64 numBytes = sb.GetCurOffset(); - RINOK(callback->SetCompleted(NULL, &numBytes)) - } - - const UInt32 v = GetUi32(sb.GetPtr()); - if (v != kDataFrameSignature32) - { - if ((v & kSkipFrameSignature_Mask) != kSkipFrameSignature) - break; - _phySize = sb.GetCurOffset() + 8; - p->num_SkipFrames++; - sb.SkipInBuf(4); - if (sb.Avail() < 4) - break; - const UInt32 size = GetUi32(sb.GetPtr()); - p->skipFrames_Size += size; - sb.SkipInBuf(4); - _phySize = sb.GetCurOffset() + size; - RINOK(sb.Skip(size)) - continue; - } - - p->num_DataFrames++; - // _numStreams_Defined = true; - sb.SkipInBuf(4); - CFrameHeader fh; - { - const Byte *data = fh.Parse(sb.GetPtr(), (int)sb.Avail()); - if (!data) - { - // _needMoreInput = true; - // we set size for one byte more to show that stream was truncated - _phySize = sb.StreamOffset + 1; - break; - } - if (fh.Is_Reserved()) - { - // we don't want false detection - if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1) - return S_FALSE; - // _phySize = sb.GetCurOffset(); - break; - } - sb.SkipInBuf((unsigned)(data - sb.GetPtr())); - } - - p->descriptor_OR = (Byte)(p->descriptor_OR | fh.Descriptor); - p->descriptor_NOT_OR = (Byte)(p->descriptor_NOT_OR | ~fh.Descriptor); - - // _numBlocks_Defined = true; - // if (fh.Get_DictionaryId_Flag()) - // p->dictionaryId_Cur = fh.DictionaryId; - if (fh.DictionaryId != 0) - { - if (p->dictionaryId == 0) - p->dictionaryId = fh.DictionaryId; - else if (p->dictionaryId != fh.DictionaryId) - p->are_DictionaryId_Different = True; - } - - UInt32 blockSizeAllowedMax = (UInt32)1 << 17; - { - UInt64 winSize = fh.ContentSize; - UInt64 winSize_forAllocate = fh.ContentSize; - if (!fh.Is_SingleSegment()) - { - if (p->windowDescriptor_MAX < fh.WindowDescriptor) - p->windowDescriptor_MAX = fh.WindowDescriptor; - const unsigned e = (fh.WindowDescriptor >> 3); - const unsigned m = (fh.WindowDescriptor & 7); - winSize = (UInt64)(8 + m) << (e + 10 - 3); - if (!fh.Is_ContentSize_Defined() - || fh.DictionaryId != 0 - || winSize_forAllocate > winSize) - winSize_forAllocate = winSize; - // p->are_WindowDescriptors = true; - } - else - { - // p->are_SingleSegments = True; - } - if (blockSizeAllowedMax > winSize) - blockSizeAllowedMax = (UInt32)winSize; - if (p->windowSize_MAX < winSize) - p->windowSize_MAX = winSize; - if (p->windowSize_Allocate_MAX < winSize_forAllocate) - p->windowSize_Allocate_MAX = winSize_forAllocate; - } - - if (fh.Is_ContentSize_Defined()) - { - // p->are_ContentSize_Known = True; - p->contentSize_Total += fh.ContentSize; - if (p->contentSize_MAX < fh.ContentSize) - p->contentSize_MAX = fh.ContentSize; - } - else - { - p->are_ContentSize_Unknown = True; - } - - p->checksum_Defined = false; - - // p->numBlocks_forType[3] += 99; // for debug - - if (!_parseMode) - { - if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1) - break; - } - - _wasParsed = true; - - bool blocksWereParsed = false; - - for (;;) - { - if (callback && (p->num_Blocks & 0xFFF) == 2) - { - // Sleep(10); - const UInt64 numBytes = sb.GetCurOffset(); - RINOK(callback->SetCompleted(NULL, &numBytes)) - } - _phySize = sb.GetCurOffset() + 3; - RINOK(sb.Read(3)) - if (sb.Avail() < 3) - { - // _needMoreInput = true; - // return S_FALSE; - break; // change it - } - const unsigned pos = sb.pos; - sb.pos = pos + 3; - UInt32 b = 0; - b += (UInt32)sb.buf[pos]; - b += (UInt32)sb.buf[pos + 1] << (8 * 1); - b += (UInt32)sb.buf[pos + 2] << (8 * 2); - p->num_Blocks++; - const unsigned blockType = (b >> 1) & 3; - UInt32 size = b >> 3; - // p->num_Blocks_forType[blockType]++; - // p->num_BlockBytes_forType[blockType] += size; - if (size > blockSizeAllowedMax - || blockType == kBlockType_Reserved) - { - _unsupportedBlock = true; - if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1 && p->num_Blocks == 1) - return S_FALSE; - break; - } - if (blockType == kBlockType_RLE) - size = 1; - _phySize = sb.GetCurOffset() + size; - RINOK(sb.Skip(size)) - if (b & 1) - { - // it's last block - blocksWereParsed = true; - break; - } - } - - if (!blocksWereParsed) - break; - - if (fh.Is_Checksum()) - { - _phySize = sb.GetCurOffset() + 4; - RINOK(sb.Read(4)) - if (sb.Avail() < 4) - break; - p->checksum_Defined = true; - // if (p->num_DataFrames == 1) - p->checksum = GetUi32(sb.GetPtr()); - sb.SkipInBuf(4); - } - } - - if (ZstdDecInfo_GET_NUM_FRAMES(p) == 0) - return S_FALSE; - - _needSeekToStart = true; - // } // _parseMode - _isArc = true; - _stream = stream; - _seqStream = stream; - - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) -{ - Close(); - _isArc = true; - _seqStream = stream; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - _isArc = false; - _needSeekToStart = false; - // _dataAfterEnd = false; - // _needMoreInput = false; - _unsupportedBlock = false; - - _wasParsed = false; - _phySize_Decoded_Defined = false; - _unpackSize_Defined = false; - _decoded_Info_Defined = false; - - ZstdDecInfo_CLEAR(&_parsed_Info) - ZstdDecInfo_CLEAR(&_decoded_Info) - - _phySize = 0; - _phySize_Decoded = 0; - _unpackSize = 0; - - _seqStream.Release(); - _stream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - if (numItems == 0) - return S_OK; - if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) - return E_INVALIDARG; - if (_wasParsed) - { - RINOK(extractCallback->SetTotal(_phySize)) - } - - Int32 opRes; - { - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) - if (!testMode && !realOutStream) - return S_OK; - - extractCallback->PrepareOperation(askMode); - - if (_needSeekToStart) - { - if (!_stream) - return E_FAIL; - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)) - } - else - _needSeekToStart = true; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, true); - -#ifdef Z7_USE_ZSTD_ORIG_DECODER - CMyComPtr2_Create decoder; -#else - CMyComPtr2_Create decoder; -#endif - - CMyComPtr2_Create outStreamSpec; - outStreamSpec->SetStream(realOutStream); - outStreamSpec->Init(); - // realOutStream.Release(); - - decoder->FinishMode = true; -#ifndef Z7_USE_ZSTD_ORIG_DECODER - decoder->DisableHash = _disableHash; -#endif - - // _dataAfterEnd = false; - // _needMoreInput = false; - const HRESULT hres = decoder.Interface()->Code(_seqStream, outStreamSpec, NULL, NULL, lps); - /* - { - UInt64 t1 = decoder->GetInputProcessedSize(); - // for debug - const UInt32 kTempSize = 64; - Byte buf[kTempSize]; - UInt32 processedSize = 0; - RINOK(decoder->ReadUnusedFromInBuf(buf, kTempSize, &processedSize)) - processedSize -= processedSize; - UInt64 t2 = decoder->GetInputProcessedSize(); - t2 = t2; - t1 = t1; - } - */ - const UInt64 outSize = outStreamSpec->GetSize(); - // } - - // if (hres == E_ABORT) return hres; - opRes = NExtract::NOperationResult::kDataError; - - if (hres == E_OUTOFMEMORY) - { - return hres; - // opRes = NExtract::NOperationResult::kMemError; - } - else if (hres == S_OK || hres == S_FALSE) - { -#ifndef Z7_USE_ZSTD_ORIG_DECODER - _decoded_Info_Defined = true; - _decoded_Info = decoder->_state.info; - // NumDataFrames_Decoded = decoder->_state.info.num_DataFrames; - // NumSkipFrames_Decoded = decoder->_state.info.num_SkipFrames; - const UInt64 inSize = decoder->_inProcessed; -#else - const UInt64 inSize = decoder->GetInputProcessedSize(); -#endif - _phySize_Decoded = inSize; - _phySize_Decoded_Defined = true; - - _unpackSize_Defined = true; - _unpackSize = outSize; - - // RINOK( - lps.Interface()->SetRatioInfo(&inSize, &outSize); - -#ifdef Z7_USE_ZSTD_ORIG_DECODER - if (hres == S_OK) - opRes = NExtract::NOperationResult::kOK; -#else - if (decoder->ResInfo.decode_SRes == SZ_ERROR_CRC) - { - opRes = NExtract::NOperationResult::kCRCError; - } - else if (decoder->ResInfo.decode_SRes == SZ_ERROR_NO_ARCHIVE) - { - _isArc = false; - opRes = NExtract::NOperationResult::kIsNotArc; - } - else if (decoder->ResInfo.decode_SRes == SZ_ERROR_INPUT_EOF) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - else - { - if (hres == S_OK && decoder->ResInfo.decode_SRes == SZ_OK) - opRes = NExtract::NOperationResult::kOK; - if (decoder->ResInfo.extraSize) - { - // if (inSize == 0) _isArc = false; - opRes = NExtract::NOperationResult::kDataAfterEnd; - } - /* - if (decoder->ResInfo.unexpededEnd) - opRes = NExtract::NOperationResult::kUnexpectedEnd; - */ - } -#endif - } - else if (hres == E_NOTIMPL) - { - opRes = NExtract::NOperationResult::kUnsupportedMethod; - } - else - return hres; - } - - return extractCallback->SetOperationResult(opRes); - - COM_TRY_END -} - - - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - // return _props.SetProperties(names, values, numProps); - // _smallMode = false; - _disableHash = false; - _parseMode = false; - // _parseMode = true; // for debug -#ifdef Z7_USE_ZSTD_COMPRESSION - _props.Init(); -#endif - - for (UInt32 i = 0; i < numProps; i++) - { - UString name = names[i]; - const PROPVARIANT &value = values[i]; - - if (name.IsEqualTo("parse")) - { - bool parseMode = true; - RINOK(PROPVARIANT_to_bool(value, parseMode)) - _parseMode = parseMode; - continue; - } - if (name.IsPrefixedBy_Ascii_NoCase("crc")) - { - name.Delete(0, 3); - UInt32 crcSize = 4; - RINOK(ParsePropToUInt32(name, value, crcSize)) - if (crcSize == 0) - _disableHash = true; - else if (crcSize == 4) - _disableHash = false; - else - return E_INVALIDARG; - continue; - } -#ifdef Z7_USE_ZSTD_COMPRESSION - /* - if (name.IsEqualTo("small")) - { - bool smallMode = true; - RINOK(PROPVARIANT_to_bool(value, smallMode)) - _smallMode = smallMode; - continue; - } - */ - RINOK(_props.SetProperty(names[i], value)) -#endif - } - return S_OK; -} - - - - -#ifdef Z7_USE_ZSTD_COMPRESSION - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) -{ - *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; - // *timeType = NFileTimeType::kUnix; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *updateCallback)) -{ - COM_TRY_BEGIN - - if (numItems != 1) - return E_INVALIDARG; - { - CMyComPtr setRestriction; - outStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction); - if (setRestriction) - RINOK(setRestriction->SetRestriction(0, 0)) - } - Int32 newData, newProps; - UInt32 indexInArchive; - if (!updateCallback) - return E_FAIL; - RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) - - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) - if (prop.vt != VT_EMPTY) - if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) - return E_INVALIDARG; - } - } - - if (IntToBool(newData)) - { - UInt64 size; - { - NCOM::CPropVariant prop; - RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - size = prop.uhVal.QuadPart; - } - - if (!_props.MethodName.IsEmpty() - && !_props.MethodName.IsEqualTo_Ascii_NoCase("zstd")) - return E_INVALIDARG; - - { - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)) - if (!fileInStream) - return S_FALSE; - { - CMyComPtr streamGetSize; - fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize); - if (streamGetSize) - { - UInt64 size2; - if (streamGetSize->GetSize(&size2) == S_OK) - size = size2; - } - } - RINOK(updateCallback->SetTotal(size)) - - CMethodProps props2 = _props; - -#ifndef Z7_ST - /* - CSingleMethodProps (_props) - derives from - CMethodProps (props2) - So we transfer additional variable (num Threads) to CMethodProps list of properties - */ - - UInt32 numThreads = _props._numThreads; - - if (numThreads > Z7_ZSTDMT_NBWORKERS_MAX) - numThreads = Z7_ZSTDMT_NBWORKERS_MAX; - - if (_props.FindProp(NCoderPropID::kNumThreads) < 0) - { - if (!_props._numThreads_WasForced - && numThreads >= 1 - && _props._memUsage_WasSet) - { - NCompress::NZstd::CEncoderProps zstdProps; - RINOK(zstdProps.SetFromMethodProps(_props)) - ZstdEncProps_NormalizeFull(&zstdProps.EncProps); - numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit( - &zstdProps.EncProps, _props._memUsage_Compress, numThreads); - } - props2.AddProp_NumThreads(numThreads); - } - -#endif // Z7_ST - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - { - CMyComPtr2_Create encoder; - // size = 1 << 24; // for debug - RINOK(props2.SetCoderProps(encoder.ClsPtr(), size != (UInt64)(Int64)-1 ? &size : NULL)) - // encoderSpec->_props.SmallFileOpt = _smallMode; - // we must set kExpectedDataSize just before Code(). - encoder->SrcSizeHint64 = size; - /* - CMyComPtr optProps; - _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void**)&optProps); - if (optProps) - { - PROPID propID = NCoderPropID::kExpectedDataSize; - NWindows::NCOM::CPropVariant prop = (UInt64)size; - // RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)) - RINOK(encoderSpec->SetCoderPropertiesOpt(&propID, &prop, 1)) - } - */ - RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) - } - } - return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); - } - - if (indexInArchive != 0) - return E_INVALIDARG; - - CMyComPtr2_Create lps; - lps->Init(updateCallback, true); - - CMyComPtr opCallback; - updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); - if (opCallback) - { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, 0, - NUpdateNotifyOp::kReplicate)) - } - - if (_stream) - RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)) - - return NCompress::CopyStream(_stream, outStream, lps); - - COM_TRY_END -} -#endif - - - -#ifndef Z7_USE_ZSTD_COMPRESSION -#undef IMP_CreateArcOut -#define IMP_CreateArcOut -#undef CreateArcOut -#define CreateArcOut NULL -#endif - -#ifdef Z7_USE_ZSTD_COMPRESSION -REGISTER_ARC_IO( - "zstd2", "zst tzst", "* .tar", 0xe + 1, - k_Signature, 0 - , NArcInfoFlags::kKeepName - , 0 - , NULL) -#else -REGISTER_ARC_IO( - "zstd", "zst tzst", "* .tar", 0xe, - k_Signature, 0 - , NArcInfoFlags::kKeepName - , 0 - , NULL) -#endif - -}} +// ZstdHandler.cpp + +#include "StdAfx.h" + +// #define Z7_USE_ZSTD_ORIG_DECODER +// #define Z7_USE_ZSTD_COMPRESSION + +#include "../../Common/ComTry.h" + +#include "../Common/MethodProps.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" +#include "../Compress/ZstdDecoder.h" +#ifdef Z7_USE_ZSTD_ORIG_DECODER +#include "../Compress/Zstd2Decoder.h" +#endif + +#ifdef Z7_USE_ZSTD_COMPRESSION +#include "../Compress/ZstdEncoder.h" +#include "../Compress/ZstdEncoderProps.h" +#include "Common/HandlerOut.h" +#endif + +#include "Common/DummyOutStream.h" + +#include "../../../C/CpuArch.h" + +using namespace NWindows; + +namespace NArchive { +namespace NZstd { + +#define DESCRIPTOR_Get_DictionaryId_Flag(d) ((d) & 3) +#define DESCRIPTOR_FLAG_CHECKSUM (1 << 2) +#define DESCRIPTOR_FLAG_RESERVED (1 << 3) +#define DESCRIPTOR_FLAG_UNUSED (1 << 4) +#define DESCRIPTOR_FLAG_SINGLE (1 << 5) +#define DESCRIPTOR_Get_ContentSize_Flag3(d) ((d) >> 5) +#define DESCRIPTOR_Is_ContentSize_Defined(d) (((d) & 0xe0) != 0) + +struct CFrameHeader +{ + Byte Descriptor; + Byte WindowDescriptor; + UInt32 DictionaryId; + UInt64 ContentSize; + + /* by zstd specification: + the decoder must check that (Is_Reserved() == false) + the decoder must ignore Unused_bit */ + bool Is_Reserved() const { return (Descriptor & DESCRIPTOR_FLAG_RESERVED) != 0; } + bool Is_Checksum() const { return (Descriptor & DESCRIPTOR_FLAG_CHECKSUM) != 0; } + bool Is_SingleSegment() const { return (Descriptor & DESCRIPTOR_FLAG_SINGLE) != 0; } + bool Is_ContentSize_Defined() const { return DESCRIPTOR_Is_ContentSize_Defined(Descriptor); } + unsigned Get_DictionaryId_Flag() const { return DESCRIPTOR_Get_DictionaryId_Flag(Descriptor); } + unsigned Get_ContentSize_Flag3() const { return DESCRIPTOR_Get_ContentSize_Flag3(Descriptor); } + + const Byte *Parse(const Byte *p, int size) + { + if ((unsigned)size < 2) + return NULL; + Descriptor = *p++; + size--; + { + Byte w = 0; + if (!Is_SingleSegment()) + { + w = *p++; + size--; + } + WindowDescriptor = w; + } + { + unsigned n = Get_DictionaryId_Flag(); + UInt32 d = 0; + if (n) + { + n = (unsigned)1 << (n - 1); + if ((size -= (int)n) < 0) + return NULL; + d = GetUi32(p) & ((UInt32)(Int32)-1 >> (32 - 8u * n)); + p += n; + } + DictionaryId = d; + } + { + unsigned n = Get_ContentSize_Flag3(); + UInt64 v = 0; + if (n) + { + n >>= 1; + if (n == 1) + v = 256; + n = (unsigned)1 << n; + if ((size -= (int)n) < 0) + return NULL; + v += GetUi64(p) & ((UInt64)(Int64)-1 >> (64 - 8u * n)); + p += n; + } + ContentSize = v; + } + return p; + } +}; + + + +class CHandler Z7_final: + public IInArchive, + public IArchiveOpenSeq, + public ISetProperties, +#ifdef Z7_USE_ZSTD_COMPRESSION + public IOutArchive, +#endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IInArchive) + Z7_COM_QI_ENTRY(IArchiveOpenSeq) + Z7_COM_QI_ENTRY(ISetProperties) +#ifdef Z7_USE_ZSTD_COMPRESSION + Z7_COM_QI_ENTRY(IOutArchive) +#endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInArchive) + Z7_IFACE_COM7_IMP(IArchiveOpenSeq) + Z7_IFACE_COM7_IMP(ISetProperties) +#ifdef Z7_USE_ZSTD_COMPRESSION + Z7_IFACE_COM7_IMP(IOutArchive) +#endif + + bool _isArc; + bool _needSeekToStart; + // bool _dataAfterEnd; + // bool _needMoreInput; + bool _unsupportedBlock; + + bool _wasParsed; + bool _phySize_Decoded_Defined; + bool _unpackSize_Defined; // decoded + bool _decoded_Info_Defined; + + bool _parseMode; + bool _disableHash; + // bool _smallMode; + + UInt64 _phySize; + UInt64 _phySize_Decoded; + UInt64 _unpackSize; + + CZstdDecInfo _parsed_Info; + CZstdDecInfo _decoded_Info; + + CMyComPtr _stream; + CMyComPtr _seqStream; + +#ifdef Z7_USE_ZSTD_COMPRESSION + CSingleMethodProps _props; +#endif + +public: + CHandler(): + _parseMode(false), + _disableHash(false) + // _smallMode(false) + {} +}; + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams, + kpidNumBlocks, + kpidMethod, + // kpidChecksum + kpidCRC +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + + +// static const unsigned kBlockType_Raw = 0; +static const unsigned kBlockType_RLE = 1; +// static const unsigned kBlockType_Compressed = 2; +static const unsigned kBlockType_Reserved = 3; +/* +static const char * const kNames[] = +{ + "RAW" + , "RLE" + , "Compressed" + , "Reserved" +}; +*/ + +static void Add_UInt64(AString &s, const char *name, UInt64 v) +{ + s.Add_OptSpaced(name); + s.Add_Colon(); + s.Add_UInt64(v); +} + + +static void PrintSize(AString &s, UInt64 w) +{ + char c = 0; + if ((w & ((1 << 30) - 1)) == 0) { c = 'G'; w >>= 30; } + else if ((w & ((1 << 20) - 1)) == 0) { c = 'M'; w >>= 20; } + else if ((w & ((1 << 10) - 1)) == 0) { c = 'K'; w >>= 10; } + s.Add_UInt64(w); + if (c) + { + s.Add_Char(c); + s += "iB"; + } +} + + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + + CZstdDecInfo *p = NULL; + if (_wasParsed || !_decoded_Info_Defined) + p = &_parsed_Info; + else if (_decoded_Info_Defined) + p = &_decoded_Info; + + switch (propID) + { + case kpidPhySize: + if (_wasParsed) + prop = _phySize; + else if (_phySize_Decoded_Defined) + prop = _phySize_Decoded; + break; + + case kpidUnpackSize: + if (_unpackSize_Defined) + prop = _unpackSize; + break; + + case kpidNumStreams: + if (p) + if (_wasParsed || _decoded_Info_Defined) + prop = p->num_DataFrames; + break; + + case kpidNumBlocks: + if (p) + if (_wasParsed || _decoded_Info_Defined) + prop = p->num_Blocks; + break; + + // case kpidChecksum: + case kpidCRC: + if (p) + if (p->checksum_Defined && p->num_DataFrames == 1) + prop = p->checksum; // it's checksum from last frame + break; + + case kpidMethod: + { + AString s; + s.Add_OptSpaced(p == &_decoded_Info ? + "decoded:" : _wasParsed ? + "parsed:" : + "header-open-only:"); + + if (p->dictionaryId != 0) + { + if (p->are_DictionaryId_Different) + s.Add_OptSpaced("different-dictionary-IDs"); + s.Add_OptSpaced("dictionary-ID:"); + s.Add_UInt32(p->dictionaryId); + } + /* + if (ContentSize_Defined) + { + s.Add_OptSpaced("ContentSize="); + s.Add_UInt64(ContentSize_Total); + } + */ + // if (p->are_Checksums) + if (p->descriptor_OR & DESCRIPTOR_FLAG_CHECKSUM) + s.Add_OptSpaced("XXH64"); + if (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_CHECKSUM) + s.Add_OptSpaced("NO-XXH64"); + + if (p->descriptor_OR & DESCRIPTOR_FLAG_UNUSED) + s.Add_OptSpaced("unused_bit"); + + if (p->descriptor_OR & DESCRIPTOR_FLAG_SINGLE) + s.Add_OptSpaced("single-segments"); + + if (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_SINGLE) + { + // Add_UInt64(s, "wnd-descriptors", p->num_WindowDescriptors); + s.Add_OptSpaced("wnd-desc-log-MAX:"); + // WindowDescriptor_MAX = 16 << 3; // for debug + const unsigned e = p->windowDescriptor_MAX >> 3; + s.Add_UInt32(e + 10); + const unsigned m = p->windowDescriptor_MAX & 7; + if (m != 0) + { + s.Add_Dot(); + s.Add_UInt32(m); + } + } + + if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor_OR) || + (p->descriptor_NOT_OR & DESCRIPTOR_FLAG_SINGLE)) + /* + if (p->are_ContentSize_Known || + p->are_WindowDescriptors) + */ + { + s.Add_OptSpaced("wnd-MAX:"); + PrintSize(s, p->windowSize_MAX); + if (p->windowSize_MAX != p->windowSize_Allocate_MAX) + { + s.Add_OptSpaced("wnd-use-MAX:"); + PrintSize(s, p->windowSize_Allocate_MAX); + } + } + + if (p->num_DataFrames != 1) + Add_UInt64(s, "data-frames", p->num_DataFrames); + if (p->num_SkipFrames != 0) + { + Add_UInt64(s, "skip-frames", p->num_SkipFrames); + Add_UInt64(s, "skip-frames-size-total", p->skipFrames_Size); + } + + if (p->are_ContentSize_Unknown) + s.Add_OptSpaced("unknown-content-size"); + + if (DESCRIPTOR_Is_ContentSize_Defined(p->descriptor_OR)) + { + Add_UInt64(s, "content-size-frame-max", p->contentSize_MAX); + Add_UInt64(s, "content-size-total", p->contentSize_Total); + } + + /* + for (unsigned i = 0; i < 4; i++) + { + const UInt64 n = p->num_Blocks_forType[i]; + if (n) + { + s.Add_OptSpaced(kNames[i]); + s += "-blocks:"; + s.Add_UInt64(n); + + s.Add_OptSpaced(kNames[i]); + s += "-block-bytes:"; + s.Add_UInt64(p->num_BlockBytes_forType[i]); + } + } + */ + prop = s; + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + // if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + // if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + if (_unsupportedBlock) v |= kpv_ErrorFlags_UnsupportedMethod; + /* + if (_parsed_Info.numBlocks_forType[kBlockType_Reserved]) + v |= kpv_ErrorFlags_UnsupportedMethod; + */ + prop = v; + break; + } + + default: break; + } + prop.Detach(value); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = 1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPackSize: + if (_wasParsed) + prop = _phySize; + else if (_phySize_Decoded_Defined) + prop = _phySize_Decoded; + break; + + case kpidSize: + if (_wasParsed && !_parsed_Info.are_ContentSize_Unknown) + prop = _parsed_Info.contentSize_Total; + else if (_unpackSize_Defined) + prop = _unpackSize; + break; + + default: break; + } + prop.Detach(value); + return S_OK; +} + +static const unsigned kSignatureSize = 4; +static const Byte k_Signature[kSignatureSize] = { 0x28, 0xb5, 0x2f, 0xfd } ; + +static const UInt32 kDataFrameSignature32 = 0xfd2fb528; +static const UInt32 kSkipFrameSignature = 0x184d2a50; +static const UInt32 kSkipFrameSignature_Mask = 0xfffffff0; + +/* +API_FUNC_static_IsArc IsArc_Zstd(const Byte *p, size_t size) +{ + if (size < kSignatureSize) + return k_IsArc_Res_NEED_MORE; + if (memcmp(p, k_Signature, kSignatureSize) != 0) + { + const UInt32 v = GetUi32(p); + if ((v & kSkipFrameSignature_Mask) != kSkipFrameSignature) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; + } + p += 4; + // return k_IsArc_Res_YES; +} +} +*/ + +// kBufSize must be >= (ZSTD_FRAMEHEADERSIZE_MAX = 18) +// we use big buffer for fast parsing of worst case small blocks. +static const unsigned kBufSize = + 1 << 9; + // 1 << 14; // fastest in real file + +struct CStreamBuffer +{ + unsigned pos; + unsigned lim; + IInStream *Stream; + UInt64 StreamOffset; + Byte buf[kBufSize]; + + CStreamBuffer(): + pos(0), + lim(0), + StreamOffset(0) + {} + unsigned Avail() const { return lim - pos; } + const Byte *GetPtr() const { return &buf[pos]; } + UInt64 GetCurOffset() const { return StreamOffset - Avail(); } + void SkipInBuf(UInt32 size) { pos += size; } + HRESULT Skip(UInt32 size); + HRESULT Read(unsigned num); +}; + +HRESULT CStreamBuffer::Skip(UInt32 size) +{ + unsigned rem = lim - pos; + if (rem != 0) + { + if (rem > size) + rem = size; + pos += rem; + size -= rem; + if (pos != lim) + return S_OK; + } + if (size == 0) + return S_OK; + return Stream->Seek(size, STREAM_SEEK_CUR, &StreamOffset); +} + +HRESULT CStreamBuffer::Read(unsigned num) +{ + if (lim - pos >= num) + return S_OK; + if (pos != 0) + { + lim -= pos; + memmove(buf, buf + pos, lim); + pos = 0; + } + size_t processed = kBufSize - ((unsigned)StreamOffset & (kBufSize - 1)); + const unsigned avail = kBufSize - lim; + num -= lim; + if (avail < processed || processed < num) + processed = avail; + const HRESULT res = ReadStream(Stream, buf + lim, &processed); + StreamOffset += processed; + lim += (unsigned)processed; + return res; +} + + +static const unsigned k_ZSTD_FRAMEHEADERSIZE_MAX = 4 + 14; + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)) +{ + COM_TRY_BEGIN + Close(); + + CZstdDecInfo *p = &_parsed_Info; + // p->are_ContentSize_Unknown = False; + CStreamBuffer sb; + sb.Stream = stream; + + for (;;) + { + RINOK(sb.Read(k_ZSTD_FRAMEHEADERSIZE_MAX)) + if (sb.Avail() < kSignatureSize) + break; + + if (callback && (ZstdDecInfo_GET_NUM_FRAMES(p) & 0xFFF) == 2) + { + const UInt64 numBytes = sb.GetCurOffset(); + RINOK(callback->SetCompleted(NULL, &numBytes)) + } + + const UInt32 v = GetUi32(sb.GetPtr()); + if (v != kDataFrameSignature32) + { + if ((v & kSkipFrameSignature_Mask) != kSkipFrameSignature) + break; + _phySize = sb.GetCurOffset() + 8; + p->num_SkipFrames++; + sb.SkipInBuf(4); + if (sb.Avail() < 4) + break; + const UInt32 size = GetUi32(sb.GetPtr()); + p->skipFrames_Size += size; + sb.SkipInBuf(4); + _phySize = sb.GetCurOffset() + size; + RINOK(sb.Skip(size)) + continue; + } + + p->num_DataFrames++; + // _numStreams_Defined = true; + sb.SkipInBuf(4); + CFrameHeader fh; + { + const Byte *data = fh.Parse(sb.GetPtr(), (int)sb.Avail()); + if (!data) + { + // _needMoreInput = true; + // we set size for one byte more to show that stream was truncated + _phySize = sb.StreamOffset + 1; + break; + } + if (fh.Is_Reserved()) + { + // we don't want false detection + if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1) + return S_FALSE; + // _phySize = sb.GetCurOffset(); + break; + } + sb.SkipInBuf((unsigned)(data - sb.GetPtr())); + } + + p->descriptor_OR = (Byte)(p->descriptor_OR | fh.Descriptor); + p->descriptor_NOT_OR = (Byte)(p->descriptor_NOT_OR | ~fh.Descriptor); + + // _numBlocks_Defined = true; + // if (fh.Get_DictionaryId_Flag()) + // p->dictionaryId_Cur = fh.DictionaryId; + if (fh.DictionaryId != 0) + { + if (p->dictionaryId == 0) + p->dictionaryId = fh.DictionaryId; + else if (p->dictionaryId != fh.DictionaryId) + p->are_DictionaryId_Different = True; + } + + UInt32 blockSizeAllowedMax = (UInt32)1 << 17; + { + UInt64 winSize = fh.ContentSize; + UInt64 winSize_forAllocate = fh.ContentSize; + if (!fh.Is_SingleSegment()) + { + if (p->windowDescriptor_MAX < fh.WindowDescriptor) + p->windowDescriptor_MAX = fh.WindowDescriptor; + const unsigned e = (fh.WindowDescriptor >> 3); + const unsigned m = (fh.WindowDescriptor & 7); + winSize = (UInt64)(8 + m) << (e + 10 - 3); + if (!fh.Is_ContentSize_Defined() + || fh.DictionaryId != 0 + || winSize_forAllocate > winSize) + winSize_forAllocate = winSize; + // p->are_WindowDescriptors = true; + } + else + { + // p->are_SingleSegments = True; + } + if (blockSizeAllowedMax > winSize) + blockSizeAllowedMax = (UInt32)winSize; + if (p->windowSize_MAX < winSize) + p->windowSize_MAX = winSize; + if (p->windowSize_Allocate_MAX < winSize_forAllocate) + p->windowSize_Allocate_MAX = winSize_forAllocate; + } + + if (fh.Is_ContentSize_Defined()) + { + // p->are_ContentSize_Known = True; + p->contentSize_Total += fh.ContentSize; + if (p->contentSize_MAX < fh.ContentSize) + p->contentSize_MAX = fh.ContentSize; + } + else + { + p->are_ContentSize_Unknown = True; + } + + p->checksum_Defined = false; + + // p->numBlocks_forType[3] += 99; // for debug + + if (!_parseMode) + { + if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1) + break; + } + + _wasParsed = true; + + bool blocksWereParsed = false; + + for (;;) + { + if (callback && (p->num_Blocks & 0xFFF) == 2) + { + // Sleep(10); + const UInt64 numBytes = sb.GetCurOffset(); + RINOK(callback->SetCompleted(NULL, &numBytes)) + } + _phySize = sb.GetCurOffset() + 3; + RINOK(sb.Read(3)) + if (sb.Avail() < 3) + { + // _needMoreInput = true; + // return S_FALSE; + break; // change it + } + const unsigned pos = sb.pos; + sb.pos = pos + 3; + UInt32 b = 0; + b += (UInt32)sb.buf[pos]; + b += (UInt32)sb.buf[pos + 1] << (8 * 1); + b += (UInt32)sb.buf[pos + 2] << (8 * 2); + p->num_Blocks++; + const unsigned blockType = (b >> 1) & 3; + UInt32 size = b >> 3; + // p->num_Blocks_forType[blockType]++; + // p->num_BlockBytes_forType[blockType] += size; + if (size > blockSizeAllowedMax + || blockType == kBlockType_Reserved) + { + _unsupportedBlock = true; + if (ZstdDecInfo_GET_NUM_FRAMES(p) == 1 && p->num_Blocks == 1) + return S_FALSE; + break; + } + if (blockType == kBlockType_RLE) + size = 1; + _phySize = sb.GetCurOffset() + size; + RINOK(sb.Skip(size)) + if (b & 1) + { + // it's last block + blocksWereParsed = true; + break; + } + } + + if (!blocksWereParsed) + break; + + if (fh.Is_Checksum()) + { + _phySize = sb.GetCurOffset() + 4; + RINOK(sb.Read(4)) + if (sb.Avail() < 4) + break; + p->checksum_Defined = true; + // if (p->num_DataFrames == 1) + p->checksum = GetUi32(sb.GetPtr()); + sb.SkipInBuf(4); + } + } + + if (ZstdDecInfo_GET_NUM_FRAMES(p) == 0) + return S_FALSE; + + _needSeekToStart = true; + // } // _parseMode + _isArc = true; + _stream = stream; + _seqStream = stream; + + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream)) +{ + Close(); + _isArc = true; + _seqStream = stream; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + _isArc = false; + _needSeekToStart = false; + // _dataAfterEnd = false; + // _needMoreInput = false; + _unsupportedBlock = false; + + _wasParsed = false; + _phySize_Decoded_Defined = false; + _unpackSize_Defined = false; + _decoded_Info_Defined = false; + + ZstdDecInfo_CLEAR(&_parsed_Info) + ZstdDecInfo_CLEAR(&_decoded_Info) + + _phySize = 0; + _phySize_Decoded = 0; + _unpackSize = 0; + + _seqStream.Release(); + _stream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + if (numItems == 0) + return S_OK; + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) + return E_INVALIDARG; + if (_wasParsed) + { + RINOK(extractCallback->SetTotal(_phySize)) + } + + Int32 opRes; + { + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(0, &realOutStream, askMode)) + if (!testMode && !realOutStream) + return S_OK; + + extractCallback->PrepareOperation(askMode); + + if (_needSeekToStart) + { + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)) + } + else + _needSeekToStart = true; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, true); + +#ifdef Z7_USE_ZSTD_ORIG_DECODER + CMyComPtr2_Create decoder; +#else + CMyComPtr2_Create decoder; +#endif + + CMyComPtr2_Create outStreamSpec; + outStreamSpec->SetStream(realOutStream); + outStreamSpec->Init(); + // realOutStream.Release(); + + decoder->FinishMode = true; +#ifndef Z7_USE_ZSTD_ORIG_DECODER + decoder->DisableHash = _disableHash; +#endif + + // _dataAfterEnd = false; + // _needMoreInput = false; + const HRESULT hres = decoder.Interface()->Code(_seqStream, outStreamSpec, NULL, NULL, lps); + /* + { + UInt64 t1 = decoder->GetInputProcessedSize(); + // for debug + const UInt32 kTempSize = 64; + Byte buf[kTempSize]; + UInt32 processedSize = 0; + RINOK(decoder->ReadUnusedFromInBuf(buf, kTempSize, &processedSize)) + processedSize -= processedSize; + UInt64 t2 = decoder->GetInputProcessedSize(); + t2 = t2; + t1 = t1; + } + */ + const UInt64 outSize = outStreamSpec->GetSize(); + // } + + // if (hres == E_ABORT) return hres; + opRes = NExtract::NOperationResult::kDataError; + + if (hres == E_OUTOFMEMORY) + { + return hres; + // opRes = NExtract::NOperationResult::kMemError; + } + else if (hres == S_OK || hres == S_FALSE) + { +#ifndef Z7_USE_ZSTD_ORIG_DECODER + _decoded_Info_Defined = true; + _decoded_Info = decoder->_state.info; + // NumDataFrames_Decoded = decoder->_state.info.num_DataFrames; + // NumSkipFrames_Decoded = decoder->_state.info.num_SkipFrames; + const UInt64 inSize = decoder->_inProcessed; +#else + const UInt64 inSize = decoder->GetInputProcessedSize(); +#endif + _phySize_Decoded = inSize; + _phySize_Decoded_Defined = true; + + _unpackSize_Defined = true; + _unpackSize = outSize; + + // RINOK( + lps.Interface()->SetRatioInfo(&inSize, &outSize); + +#ifdef Z7_USE_ZSTD_ORIG_DECODER + if (hres == S_OK) + opRes = NExtract::NOperationResult::kOK; +#else + if (decoder->ResInfo.decode_SRes == SZ_ERROR_CRC) + { + opRes = NExtract::NOperationResult::kCRCError; + } + else if (decoder->ResInfo.decode_SRes == SZ_ERROR_NO_ARCHIVE) + { + _isArc = false; + opRes = NExtract::NOperationResult::kIsNotArc; + } + else if (decoder->ResInfo.decode_SRes == SZ_ERROR_INPUT_EOF) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + else + { + if (hres == S_OK && decoder->ResInfo.decode_SRes == SZ_OK) + opRes = NExtract::NOperationResult::kOK; + if (decoder->ResInfo.extraSize) + { + // if (inSize == 0) _isArc = false; + opRes = NExtract::NOperationResult::kDataAfterEnd; + } + /* + if (decoder->ResInfo.unexpededEnd) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + */ + } +#endif + } + else if (hres == E_NOTIMPL) + { + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else + return hres; + } + + return extractCallback->SetOperationResult(opRes); + + COM_TRY_END +} + + + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + // return _props.SetProperties(names, values, numProps); + // _smallMode = false; + _disableHash = false; + _parseMode = false; + // _parseMode = true; // for debug +#ifdef Z7_USE_ZSTD_COMPRESSION + _props.Init(); +#endif + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + const PROPVARIANT &value = values[i]; + + if (name.IsEqualTo("parse")) + { + bool parseMode = true; + RINOK(PROPVARIANT_to_bool(value, parseMode)) + _parseMode = parseMode; + continue; + } + if (name.IsPrefixedBy_Ascii_NoCase("crc")) + { + name.Delete(0, 3); + UInt32 crcSize = 4; + RINOK(ParsePropToUInt32(name, value, crcSize)) + if (crcSize == 0) + _disableHash = true; + else if (crcSize == 4) + _disableHash = false; + else + return E_INVALIDARG; + continue; + } +#ifdef Z7_USE_ZSTD_COMPRESSION + /* + if (name.IsEqualTo("small")) + { + bool smallMode = true; + RINOK(PROPVARIANT_to_bool(value, smallMode)) + _smallMode = smallMode; + continue; + } + */ + RINOK(_props.SetProperty(names[i], value)) +#endif + } + return S_OK; +} + + + + +#ifdef Z7_USE_ZSTD_COMPRESSION + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType)) +{ + *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // *timeType = NFileTimeType::kUnix; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback)) +{ + COM_TRY_BEGIN + + if (numItems != 1) + return E_INVALIDARG; + { + CMyComPtr setRestriction; + outStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction); + if (setRestriction) + RINOK(setRestriction->SetRestriction(0, 0)) + } + Int32 newData, newProps; + UInt32 indexInArchive; + if (!updateCallback) + return E_FAIL; + RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)) + + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop)) + if (prop.vt != VT_EMPTY) + if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE) + return E_INVALIDARG; + } + } + + if (IntToBool(newData)) + { + UInt64 size; + { + NCOM::CPropVariant prop; + RINOK(updateCallback->GetProperty(0, kpidSize, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + size = prop.uhVal.QuadPart; + } + + if (!_props.MethodName.IsEmpty() + && !_props.MethodName.IsEqualTo_Ascii_NoCase("zstd")) + return E_INVALIDARG; + + { + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)) + if (!fileInStream) + return S_FALSE; + { + CMyComPtr streamGetSize; + fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + UInt64 size2; + if (streamGetSize->GetSize(&size2) == S_OK) + size = size2; + } + } + RINOK(updateCallback->SetTotal(size)) + + CMethodProps props2 = _props; + +#ifndef Z7_ST + /* + CSingleMethodProps (_props) + derives from + CMethodProps (props2) + So we transfer additional variable (num Threads) to CMethodProps list of properties + */ + + UInt32 numThreads = _props._numThreads; + + if (numThreads > Z7_ZSTDMT_NBWORKERS_MAX) + numThreads = Z7_ZSTDMT_NBWORKERS_MAX; + + if (_props.FindProp(NCoderPropID::kNumThreads) < 0) + { + if (!_props._numThreads_WasForced + && numThreads >= 1 + && _props._memUsage_WasSet) + { + NCompress::NZstd::CEncoderProps zstdProps; + RINOK(zstdProps.SetFromMethodProps(_props)) + ZstdEncProps_NormalizeFull(&zstdProps.EncProps); + numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit( + &zstdProps.EncProps, _props._memUsage_Compress, numThreads); + } + props2.AddProp_NumThreads(numThreads); + } + +#endif // Z7_ST + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + { + CMyComPtr2_Create encoder; + // size = 1 << 24; // for debug + RINOK(props2.SetCoderProps(encoder.ClsPtr(), size != (UInt64)(Int64)-1 ? &size : NULL)) + // encoderSpec->_props.SmallFileOpt = _smallMode; + // we must set kExpectedDataSize just before Code(). + encoder->SrcSizeHint64 = size; + /* + CMyComPtr optProps; + _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void**)&optProps); + if (optProps) + { + PROPID propID = NCoderPropID::kExpectedDataSize; + NWindows::NCOM::CPropVariant prop = (UInt64)size; + // RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1)) + RINOK(encoderSpec->SetCoderPropertiesOpt(&propID, &prop, 1)) + } + */ + RINOK(encoder.Interface()->Code(fileInStream, outStream, NULL, NULL, lps)) + } + } + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); + } + + if (indexInArchive != 0) + return E_INVALIDARG; + + CMyComPtr2_Create lps; + lps->Init(updateCallback, true); + + CMyComPtr opCallback; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, 0, + NUpdateNotifyOp::kReplicate)) + } + + if (_stream) + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)) + + return NCompress::CopyStream(_stream, outStream, lps); + + COM_TRY_END +} +#endif + + + +#ifndef Z7_USE_ZSTD_COMPRESSION +#undef IMP_CreateArcOut +#define IMP_CreateArcOut +#undef CreateArcOut +#define CreateArcOut NULL +#endif + +#ifdef Z7_USE_ZSTD_COMPRESSION +REGISTER_ARC_IO( + "zstd2", "zst tzst", "* .tar", 0xe + 1, + k_Signature, 0 + , NArcInfoFlags::kKeepName + , 0 + , NULL) +#else +REGISTER_ARC_IO( + "zstd", "zst tzst", "* .tar", 0xe, + k_Signature, 0 + , NArcInfoFlags::kKeepName + , 0 + , NULL) +#endif + +}} diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile index 96d8d782d..7512ad568 100644 --- a/CPP/7zip/Archive/makefile +++ b/CPP/7zip/Archive/makefile @@ -1,23 +1,23 @@ -DIRS = \ - 7z\~ \ - Arj\~ \ - BZip2\~ \ - Cab\~ \ - Chm\~ \ - Cpio\~ \ - Deb\~ \ - GZip\~ \ - Iso\~ \ - Lzh\~ \ - Nsis\~ \ - Rar\~ \ - RPM\~ \ - Split\~ \ - Tar\~ \ - Z\~ \ - Zip\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + 7z\~ \ + Arj\~ \ + BZip2\~ \ + Cab\~ \ + Chm\~ \ + Cpio\~ \ + Deb\~ \ + GZip\~ \ + Iso\~ \ + Lzh\~ \ + Nsis\~ \ + Rar\~ \ + RPM\~ \ + Split\~ \ + Tar\~ \ + Z\~ \ + Zip\~ \ + +all: $(DIRS) + +$(DIRS): +!include "../SubBuild.mak" diff --git a/CPP/7zip/Asm.mak b/CPP/7zip/Asm.mak index c2cdc8deb..4ee0823c8 100644 --- a/CPP/7zip/Asm.mak +++ b/CPP/7zip/Asm.mak @@ -1,12 +1,12 @@ -!IFDEF ASM_OBJS -!IF "$(PLATFORM)" == "arm64" -$(ASM_OBJS): ../../../../Asm/arm64/$(*B).S - $(COMPL_ASM_CLANG) -!ELSEIF "$(PLATFORM)" == "arm" -$(ASM_OBJS): ../../../../Asm/arm/$(*B).asm - $(COMPL_ASM) -!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" -$(ASM_OBJS): ../../../../Asm/x86/$(*B).asm - $(COMPL_ASM) -!ENDIF -!ENDIF +!IFDEF ASM_OBJS +!IF "$(PLATFORM)" == "arm64" +$(ASM_OBJS): ../../../../Asm/arm64/$(*B).S + $(COMPL_ASM_CLANG) +!ELSEIF "$(PLATFORM)" == "arm" +$(ASM_OBJS): ../../../../Asm/arm/$(*B).asm + $(COMPL_ASM) +!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" +$(ASM_OBJS): ../../../../Asm/x86/$(*B).asm + $(COMPL_ASM) +!ENDIF +!ENDIF diff --git a/CPP/7zip/Bundles/Alone/Alone.dsp b/CPP/7zip/Bundles/Alone/Alone.dsp index edf596d08..beed5a704 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsp +++ b/CPP/7zip/Bundles/Alone/Alone.dsp @@ -1,3344 +1,3344 @@ -# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=Alone - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Alone.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application") -!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Alone - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseU" -# PROP BASE Intermediate_Dir "ReleaseU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98 -# SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zan.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "DebugU" -# PROP BASE Intermediate_Dir "DebugU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c -# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zan.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "Alone - Win32 Release" -# Name "Alone - Win32 Debug" -# Name "Alone - Win32 ReleaseU" -# Name "Alone - Win32 DebugU" -# Begin Group "Console" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Console\ArError.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\BenchCon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\BenchCon.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\CompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ExtractCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\HashCon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\HashCon.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\List.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\List.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\Main.cpp -# ADD CPP /D "Z7_PROG_VARIANT_A" -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\MainAr.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\OpenCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\PercentPrinter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\PercentPrinter.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UpdateCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UserInputUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UserInputUtils.h -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\AutoPtr.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Buffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common0.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CrcReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynamicBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\LzFindPrepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyException.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyGuidDef.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyLinux.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyUnknown.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha1Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha1Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Xxh64Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Init.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Reg.cpp -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Device.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Handle.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MemBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MemBlocks.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutMemStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutMemStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressMt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterArc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterCodec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Group "BZip2" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\BZip2Const.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Crc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Crc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Decoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Encoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Encoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Register.cpp -# End Source File -# End Group -# Begin Group "Copy" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# End Group -# Begin Group "Deflate" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Deflate64Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateConst.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateDecoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateEncoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateRegister.cpp -# End Source File -# End Group -# Begin Group "Huffman" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\HuffmanDecoder.h -# End Source File -# End Group -# Begin Group "Implode" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\ImplodeDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ImplodeDecoder.h -# End Source File -# End Group -# Begin Group "LZMA" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# End Group -# Begin Group "PPMd" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdEncoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdZip.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdZip.h -# End Source File -# End Group -# Begin Group "RangeCoder" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\RangeCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RangeCoderBit.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RangeCoderBitTree.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RangeCoderOpt.h -# End Source File -# End Group -# Begin Group "Shrink" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\ShrinkDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ShrinkDecoder.h -# End Source File -# End Group -# Begin Group "BWT" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Mtf8.h -# End Source File -# End Group -# Begin Group "LZX" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Lzx.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzxDecoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzxDecoder.h -# End Source File -# End Group -# Begin Group "Quantum" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\QuantumDecoder.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\QuantumDecoder.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitlDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitlDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitlEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitmDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitmEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ByteSwap.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ByteSwap.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeltaFilter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzOutWindow.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzOutWindow.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZstdDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZstdDecoder.h -# End Source File -# End Group -# Begin Group "Archive" - -# PROP Default_Filter "" -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.h -# End Source File -# End Group -# Begin Group "tar" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarUpdate.h -# End Source File -# End Group -# Begin Group "zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipAddCommon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipAddCommon.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHandler.cpp -# ADD CPP /D "Z7_ZIP_LZFSE_DISABLE" -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipItem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipUpdate.h -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderLoader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\FindSignature.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\FindSignature.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.h -# End Source File -# End Group -# Begin Group "cab" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabBlockInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabBlockInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabRegister.cpp -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Archive\Bz2Handler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\DeflateProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\DeflateProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\GzHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\LzmaHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SplitHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\XzHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ZstdHandler.cpp -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveCommandLine.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\IFileExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Property.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\TempFiles.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\TempFiles.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Update.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Update.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateProduce.h -# End Source File -# End Group -# Begin Group "Crypto" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAesRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha1.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAesReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Pbkdf2HmacSha1.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Pbkdf2HmacSha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RandGen.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RandGen.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Sha1Cls.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\WzAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\WzAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipCrypto.cpp - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O1 - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O1 - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipCrypto.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipStrong.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipStrong.h -# End Source File -# End Group -# Begin Group "7-zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IMyUnknown.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\MyVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Group "Xz" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\Xz.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xz.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64Opt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzEnc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzIn.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\AesOpt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2Enc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BraIA64.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BwtSort.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BwtSort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\HuffEnc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\HuffEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindOpt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7Dec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7Enc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8Dec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8Enc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\RotateDefs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\SwapBytes.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\SwapBytes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xxh64.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xxh64.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\ZstdDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\ZstdDec.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Alone - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Alone.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application") +!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Alone - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98 +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zan.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c +# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zan.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Alone - Win32 Release" +# Name "Alone - Win32 Debug" +# Name "Alone - Win32 ReleaseU" +# Name "Alone - Win32 DebugU" +# Begin Group "Console" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Console\ArError.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\BenchCon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\BenchCon.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\CompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ExtractCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\HashCon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\HashCon.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\List.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\List.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\Main.cpp +# ADD CPP /D "Z7_PROG_VARIANT_A" +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\MainAr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\OpenCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\PercentPrinter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\PercentPrinter.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UpdateCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UserInputUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UserInputUtils.h +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\AutoPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common0.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CrcReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynamicBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\LzFindPrepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyException.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyGuidDef.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyLinux.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyUnknown.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Xxh64Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Reg.cpp +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Device.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Handle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MemBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MemBlocks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutMemStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutMemStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressMt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterArc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterCodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Group "BZip2" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\BZip2Const.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Crc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Crc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Decoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Encoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Encoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Register.cpp +# End Source File +# End Group +# Begin Group "Copy" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# End Group +# Begin Group "Deflate" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Deflate64Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateConst.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateDecoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateEncoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateRegister.cpp +# End Source File +# End Group +# Begin Group "Huffman" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\HuffmanDecoder.h +# End Source File +# End Group +# Begin Group "Implode" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\ImplodeDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ImplodeDecoder.h +# End Source File +# End Group +# Begin Group "LZMA" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# End Group +# Begin Group "PPMd" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdEncoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdZip.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdZip.h +# End Source File +# End Group +# Begin Group "RangeCoder" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\RangeCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\RangeCoderBit.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\RangeCoderBitTree.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\RangeCoderOpt.h +# End Source File +# End Group +# Begin Group "Shrink" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\ShrinkDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ShrinkDecoder.h +# End Source File +# End Group +# Begin Group "BWT" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Mtf8.h +# End Source File +# End Group +# Begin Group "LZX" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Lzx.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzxDecoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzxDecoder.h +# End Source File +# End Group +# Begin Group "Quantum" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\QuantumDecoder.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\QuantumDecoder.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitlDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitlDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitlEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitmDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitmEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ByteSwap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ByteSwap.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeltaFilter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzOutWindow.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzOutWindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZstdDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZstdDecoder.h +# End Source File +# End Group +# Begin Group "Archive" + +# PROP Default_Filter "" +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.h +# End Source File +# End Group +# Begin Group "tar" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarUpdate.h +# End Source File +# End Group +# Begin Group "zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipAddCommon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipAddCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHandler.cpp +# ADD CPP /D "Z7_ZIP_LZFSE_DISABLE" +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipItem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipUpdate.h +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderLoader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FindSignature.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FindSignature.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.h +# End Source File +# End Group +# Begin Group "cab" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabBlockInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabBlockInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabRegister.cpp +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Archive\Bz2Handler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\DeflateProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\DeflateProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\GzHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\LzmaHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SplitHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\XzHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ZstdHandler.cpp +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveCommandLine.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\IFileExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Property.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\TempFiles.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\TempFiles.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Update.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Update.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateProduce.h +# End Source File +# End Group +# Begin Group "Crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAesRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha1.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAesReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Pbkdf2HmacSha1.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Pbkdf2HmacSha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RandGen.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RandGen.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Sha1Cls.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\WzAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\WzAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipCrypto.cpp + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O1 + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O1 + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipCrypto.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipStrong.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipStrong.h +# End Source File +# End Group +# Begin Group "7-zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IMyUnknown.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\MyVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Group "Xz" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\Xz.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xz.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64Opt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzEnc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzIn.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\AesOpt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2Enc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BraIA64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BwtSort.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BwtSort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\HuffEnc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\HuffEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindOpt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7Dec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7Enc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8Dec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8Enc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\RotateDefs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\SwapBytes.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\SwapBytes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xxh64.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xxh64.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\ZstdDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\ZstdDec.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/Bundles/Alone/Alone.dsw b/CPP/7zip/Bundles/Alone/Alone.dsw index 036aab454..65eca43f6 100644 --- a/CPP/7zip/Bundles/Alone/Alone.dsw +++ b/CPP/7zip/Bundles/Alone/Alone.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Alone"=.\Alone.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Alone"=.\Alone.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/Alone/StdAfx.cpp b/CPP/7zip/Bundles/Alone/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Alone/StdAfx.cpp +++ b/CPP/7zip/Bundles/Alone/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Alone/StdAfx.h b/CPP/7zip/Bundles/Alone/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Alone/StdAfx.h +++ b/CPP/7zip/Bundles/Alone/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile index 0b0434f77..75475906e 100644 --- a/CPP/7zip/Bundles/Alone/makefile +++ b/CPP/7zip/Bundles/Alone/makefile @@ -1,244 +1,244 @@ -PROG = 7za.exe - -CFLAGS = $(CFLAGS) -DZ7_ZIP_LZFSE_DISABLE -# -DZ7_PROG_VARIANT_A -# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A -# ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE - -# USE_C_AES = 1 -# USE_C_SHA = 1 -# USE_C_LZFINDOPT = 1 - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\ListFileUtils.obj \ - $O\LzFindPrepare.obj \ - $O\NewHandler.obj \ - $O\StdInStream.obj \ - $O\StdOutStream.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - $O\Sha1Reg.obj \ - $O\Sha256Reg.obj \ - $O\Xxh64Reg.obj \ - $O\XzCrc64Init.obj \ - $O\XzCrc64Reg.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\FileSystem.obj \ - $O\MemoryLock.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\PropVariantUtils.obj \ - $O\Registry.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\SystemInfo.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\InBuffer.obj \ - $O\InOutTempBuffer.obj \ - $O\LimitedStreams.obj \ - $O\MemBlocks.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\MultiOutStream.obj \ - $O\OffsetStream.obj \ - $O\OutBuffer.obj \ - $O\OutMemStream.obj \ - $O\ProgressMt.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\Bz2Handler.obj \ - $O\DeflateProps.obj \ - $O\GzHandler.obj \ - $O\LzmaHandler.obj \ - $O\SplitHandler.obj \ - $O\XzHandler.obj \ - $O\ZstdHandler.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\DummyOutStream.obj \ - $O\FindSignature.obj \ - $O\HandlerOut.obj \ - $O\InStreamWithCRC.obj \ - $O\ItemNameUtils.obj \ - $O\MultiStream.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zEncode.obj \ - $O\7zExtract.obj \ - $O\7zFolderInStream.obj \ - $O\7zHandler.obj \ - $O\7zHandlerOut.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zOut.obj \ - $O\7zProperties.obj \ - $O\7zSpecStream.obj \ - $O\7zUpdate.obj \ - $O\7zRegister.obj \ - -CAB_OBJS = \ - $O\CabBlockInStream.obj \ - $O\CabHandler.obj \ - $O\CabHeader.obj \ - $O\CabIn.obj \ - $O\CabRegister.obj \ - -TAR_OBJS = \ - $O\TarHandler.obj \ - $O\TarHandlerOut.obj \ - $O\TarHeader.obj \ - $O\TarIn.obj \ - $O\TarOut.obj \ - $O\TarUpdate.obj \ - $O\TarRegister.obj \ - -ZIP_OBJS = \ - $O\ZipAddCommon.obj \ - $O\ZipHandler.obj \ - $O\ZipHandlerOut.obj \ - $O\ZipIn.obj \ - $O\ZipItem.obj \ - $O\ZipOut.obj \ - $O\ZipUpdate.obj \ - $O\ZipRegister.obj \ - - -COMPRESS_OBJS = \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BitlDecoder.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\BZip2Crc.obj \ - $O\BZip2Decoder.obj \ - $O\BZip2Encoder.obj \ - $O\BZip2Register.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\Deflate64Register.obj \ - $O\DeflateDecoder.obj \ - $O\DeflateEncoder.obj \ - $O\DeflateRegister.obj \ - $O\DeltaFilter.obj \ - $O\ImplodeDecoder.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Encoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaEncoder.obj \ - $O\LzmaRegister.obj \ - $O\LzOutWindow.obj \ - $O\LzxDecoder.obj \ - $O\PpmdDecoder.obj \ - $O\PpmdEncoder.obj \ - $O\PpmdRegister.obj \ - $O\PpmdZip.obj \ - $O\QuantumDecoder.obj \ - $O\ShrinkDecoder.obj \ - $O\XzDecoder.obj \ - $O\XzEncoder.obj \ - $O\ZstdDecoder.obj \ - -# $O\LzfseDecoder.obj \ -# $O\ZstdRegister.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\HmacSha1.obj \ - $O\MyAes.obj \ - $O\MyAesReg.obj \ - $O\Pbkdf2HmacSha1.obj \ - $O\RandGen.obj \ - $O\WzAes.obj \ - $O\ZipCrypto.obj \ - $O\ZipStrong.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bcj2Enc.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\BwtSort.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\HuffEnc.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\Lzma2Enc.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\MtCoder.obj \ - $O\MtDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - $O\Ppmd7Enc.obj \ - $O\Ppmd8.obj \ - $O\Ppmd8Dec.obj \ - $O\Ppmd8Enc.obj \ - $O\Sort.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - $O\Xxh64.obj \ - $O\Xz.obj \ - $O\XzDec.obj \ - $O\XzEnc.obj \ - $O\XzIn.obj \ - $O\ZstdDec.obj \ - -!include "../../UI/Console/Console.mak" - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../Crc64.mak" -!include "../../LzFindOpt.mak" -!include "../../LzmaDec.mak" -!include "../../Sha1.mak" -!include "../../Sha256.mak" - -!include "../../7zip.mak" +PROG = 7za.exe + +CFLAGS = $(CFLAGS) -DZ7_ZIP_LZFSE_DISABLE +# -DZ7_PROG_VARIANT_A +# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A +# ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE + +# USE_C_AES = 1 +# USE_C_SHA = 1 +# USE_C_LZFINDOPT = 1 + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\ListFileUtils.obj \ + $O\LzFindPrepare.obj \ + $O\NewHandler.obj \ + $O\StdInStream.obj \ + $O\StdOutStream.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + $O\Sha1Reg.obj \ + $O\Sha256Reg.obj \ + $O\Xxh64Reg.obj \ + $O\XzCrc64Init.obj \ + $O\XzCrc64Reg.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\FileSystem.obj \ + $O\MemoryLock.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\PropVariantUtils.obj \ + $O\Registry.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\SystemInfo.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\InBuffer.obj \ + $O\InOutTempBuffer.obj \ + $O\LimitedStreams.obj \ + $O\MemBlocks.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\MultiOutStream.obj \ + $O\OffsetStream.obj \ + $O\OutBuffer.obj \ + $O\OutMemStream.obj \ + $O\ProgressMt.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\Bz2Handler.obj \ + $O\DeflateProps.obj \ + $O\GzHandler.obj \ + $O\LzmaHandler.obj \ + $O\SplitHandler.obj \ + $O\XzHandler.obj \ + $O\ZstdHandler.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\DummyOutStream.obj \ + $O\FindSignature.obj \ + $O\HandlerOut.obj \ + $O\InStreamWithCRC.obj \ + $O\ItemNameUtils.obj \ + $O\MultiStream.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zEncode.obj \ + $O\7zExtract.obj \ + $O\7zFolderInStream.obj \ + $O\7zHandler.obj \ + $O\7zHandlerOut.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zOut.obj \ + $O\7zProperties.obj \ + $O\7zSpecStream.obj \ + $O\7zUpdate.obj \ + $O\7zRegister.obj \ + +CAB_OBJS = \ + $O\CabBlockInStream.obj \ + $O\CabHandler.obj \ + $O\CabHeader.obj \ + $O\CabIn.obj \ + $O\CabRegister.obj \ + +TAR_OBJS = \ + $O\TarHandler.obj \ + $O\TarHandlerOut.obj \ + $O\TarHeader.obj \ + $O\TarIn.obj \ + $O\TarOut.obj \ + $O\TarUpdate.obj \ + $O\TarRegister.obj \ + +ZIP_OBJS = \ + $O\ZipAddCommon.obj \ + $O\ZipHandler.obj \ + $O\ZipHandlerOut.obj \ + $O\ZipIn.obj \ + $O\ZipItem.obj \ + $O\ZipOut.obj \ + $O\ZipUpdate.obj \ + $O\ZipRegister.obj \ + + +COMPRESS_OBJS = \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BitlDecoder.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\BZip2Crc.obj \ + $O\BZip2Decoder.obj \ + $O\BZip2Encoder.obj \ + $O\BZip2Register.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\Deflate64Register.obj \ + $O\DeflateDecoder.obj \ + $O\DeflateEncoder.obj \ + $O\DeflateRegister.obj \ + $O\DeltaFilter.obj \ + $O\ImplodeDecoder.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Encoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaEncoder.obj \ + $O\LzmaRegister.obj \ + $O\LzOutWindow.obj \ + $O\LzxDecoder.obj \ + $O\PpmdDecoder.obj \ + $O\PpmdEncoder.obj \ + $O\PpmdRegister.obj \ + $O\PpmdZip.obj \ + $O\QuantumDecoder.obj \ + $O\ShrinkDecoder.obj \ + $O\XzDecoder.obj \ + $O\XzEncoder.obj \ + $O\ZstdDecoder.obj \ + +# $O\LzfseDecoder.obj \ +# $O\ZstdRegister.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\HmacSha1.obj \ + $O\MyAes.obj \ + $O\MyAesReg.obj \ + $O\Pbkdf2HmacSha1.obj \ + $O\RandGen.obj \ + $O\WzAes.obj \ + $O\ZipCrypto.obj \ + $O\ZipStrong.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bcj2Enc.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\BwtSort.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\HuffEnc.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\Lzma2Enc.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\MtCoder.obj \ + $O\MtDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + $O\Ppmd7Enc.obj \ + $O\Ppmd8.obj \ + $O\Ppmd8Dec.obj \ + $O\Ppmd8Enc.obj \ + $O\Sort.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + $O\Xxh64.obj \ + $O\Xz.obj \ + $O\XzDec.obj \ + $O\XzEnc.obj \ + $O\XzIn.obj \ + $O\ZstdDec.obj \ + +!include "../../UI/Console/Console.mak" + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../Crc64.mak" +!include "../../LzFindOpt.mak" +!include "../../LzmaDec.mak" +!include "../../Sha1.mak" +!include "../../Sha256.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Alone/makefile.gcc b/CPP/7zip/Bundles/Alone/makefile.gcc index 20696941b..621c0cebd 100644 --- a/CPP/7zip/Bundles/Alone/makefile.gcc +++ b/CPP/7zip/Bundles/Alone/makefile.gcc @@ -1,357 +1,357 @@ -PROG = 7za - -CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A -ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE - - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -include ../../LzmaDec_gcc.mak - - -LOCAL_FLAGS_ST = -MT_OBJS = - - -ifdef ST_MODE - -LOCAL_FLAGS_ST = -DZ7_ST - -ifdef IS_MINGW -MT_OBJS = \ - $O/Threads.o \ - -endif - -else - -MT_OBJS = \ - $O/LzFindMt.o \ - $O/LzFindOpt.o \ - $O/Threads.o \ - $O/MemBlocks.o \ - $O/OutMemStream.o \ - $O/ProgressMt.o \ - $O/StreamBinder.o \ - $O/Synchronization.o \ - $O/VirtThread.o \ - -endif - - - -LOCAL_FLAGS_SYS = - -ifdef IS_MINGW - -LOCAL_FLAGS_SYS = \ - -DZ7_DEVICE_FILE \ - -# -DZ7_LARGE_PAGES \ -# -DZ7_LONG_PATH \ - -SYS_OBJS = \ - $O/FileSystem.o \ - $O/Registry.o \ - $O/MemoryLock.o \ - $O/DLL.o \ - $O/DllSecur.o \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - -endif - -LOCAL_FLAGS = \ - $(LOCAL_FLAGS_ST) \ - $(LOCAL_FLAGS_SYS) \ - - -CONSOLE_OBJS = \ - $O/BenchCon.o \ - $O/ConsoleClose.o \ - $O/ExtractCallbackConsole.o \ - $O/HashCon.o \ - $O/List.o \ - $O/Main.o \ - $O/MainAr.o \ - $O/OpenCallbackConsole.o \ - $O/PercentPrinter.o \ - $O/UpdateCallbackConsole.o \ - $O/UserInputUtils.o \ - -UI_COMMON_OBJS = \ - $O/ArchiveCommandLine.o \ - $O/ArchiveExtractCallback.o \ - $O/ArchiveOpenCallback.o \ - $O/Bench.o \ - $O/DefaultName.o \ - $O/EnumDirItems.o \ - $O/Extract.o \ - $O/ExtractingFilePath.o \ - $O/HashCalc.o \ - $O/LoadCodecs.o \ - $O/OpenArchive.o \ - $O/PropIDUtils.o \ - $O/SetProperties.o \ - $O/SortUtils.o \ - $O/TempFiles.o \ - $O/Update.o \ - $O/UpdateAction.o \ - $O/UpdateCallback.o \ - $O/UpdatePair.o \ - $O/UpdateProduce.o \ - -COMMON_OBJS = \ - $O/CommandLineParser.o \ - $O/CRC.o \ - $O/CrcReg.o \ - $O/DynLimBuf.o \ - $O/IntToString.o \ - $O/ListFileUtils.o \ - $O/LzFindPrepare.o \ - $O/MyString.o \ - $O/MyVector.o \ - $O/NewHandler.o \ - $O/Sha1Prepare.o \ - $O/Sha1Reg.o \ - $O/Sha256Prepare.o \ - $O/Sha256Reg.o \ - $O/StdInStream.o \ - $O/StdOutStream.o \ - $O/StringConvert.o \ - $O/StringToInt.o \ - $O/UTFConvert.o \ - $O/Wildcard.o \ - $O/Xxh64Reg.o \ - $O/XzCrc64Init.o \ - $O/XzCrc64Reg.o \ - -WIN_OBJS = \ - $O/ErrorMsg.o \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileIO.o \ - $O/FileLink.o \ - $O/FileName.o \ - $O/PropVariant.o \ - $O/PropVariantConv.o \ - $O/PropVariantUtils.o \ - $O/System.o \ - $O/SystemInfo.o \ - $O/TimeUtils.o \ - -7ZIP_COMMON_OBJS = \ - $O/CreateCoder.o \ - $O/CWrappers.o \ - $O/FilePathAutoRename.o \ - $O/FileStreams.o \ - $O/InBuffer.o \ - $O/InOutTempBuffer.o \ - $O/FilterCoder.o \ - $O/LimitedStreams.o \ - $O/MethodId.o \ - $O/MethodProps.o \ - $O/MultiOutStream.o \ - $O/OffsetStream.o \ - $O/OutBuffer.o \ - $O/ProgressUtils.o \ - $O/PropId.o \ - $O/StreamObjects.o \ - $O/StreamUtils.o \ - $O/UniqBlocks.o \ - -AR_OBJS = \ - $O/Bz2Handler.o \ - $O/GzHandler.o \ - $O/LzmaHandler.o \ - $O/SplitHandler.o \ - $O/XzHandler.o \ - $O/ZstdHandler.o \ - -AR_COMMON_OBJS = \ - $O/CoderMixer2.o \ - $O/DummyOutStream.o \ - $O/HandlerOut.o \ - $O/InStreamWithCRC.o \ - $O/ItemNameUtils.o \ - $O/MultiStream.o \ - $O/OutStreamWithCRC.o \ - $O/ParseProperties.o \ - -7Z_OBJS = \ - $O/7zCompressionMode.o \ - $O/7zDecode.o \ - $O/7zEncode.o \ - $O/7zExtract.o \ - $O/7zFolderInStream.o \ - $O/7zHandler.o \ - $O/7zHandlerOut.o \ - $O/7zHeader.o \ - $O/7zIn.o \ - $O/7zOut.o \ - $O/7zProperties.o \ - $O/7zRegister.o \ - $O/7zSpecStream.o \ - $O/7zUpdate.o \ - -CAB_OBJS = \ - $O/CabBlockInStream.o \ - $O/CabHandler.o \ - $O/CabHeader.o \ - $O/CabIn.o \ - $O/CabRegister.o \ - -TAR_OBJS = \ - $O/TarHandler.o \ - $O/TarHandlerOut.o \ - $O/TarHeader.o \ - $O/TarIn.o \ - $O/TarOut.o \ - $O/TarUpdate.o \ - $O/TarRegister.o \ - -ZIP_OBJS = \ - $O/ZipAddCommon.o \ - $O/ZipHandler.o \ - $O/ZipHandlerOut.o \ - $O/ZipIn.o \ - $O/ZipItem.o \ - $O/ZipOut.o \ - $O/ZipUpdate.o \ - $O/ZipRegister.o \ - -COMPRESS_OBJS = \ - $O/Bcj2Coder.o \ - $O/Bcj2Register.o \ - $O/BcjCoder.o \ - $O/BcjRegister.o \ - $O/BitlDecoder.o \ - $O/BranchMisc.o \ - $O/BranchRegister.o \ - $O/ByteSwap.o \ - $O/BZip2Crc.o \ - $O/BZip2Decoder.o \ - $O/BZip2Encoder.o \ - $O/BZip2Register.o \ - $O/CopyCoder.o \ - $O/CopyRegister.o \ - $O/Deflate64Register.o \ - $O/DeflateDecoder.o \ - $O/DeflateEncoder.o \ - $O/DeflateRegister.o \ - $O/DeltaFilter.o \ - $O/ImplodeDecoder.o \ - $O/Lzma2Decoder.o \ - $O/Lzma2Encoder.o \ - $O/Lzma2Register.o \ - $O/LzmaDecoder.o \ - $O/LzmaEncoder.o \ - $O/LzmaRegister.o \ - $O/LzOutWindow.o \ - $O/LzxDecoder.o \ - $O/PpmdDecoder.o \ - $O/PpmdEncoder.o \ - $O/PpmdRegister.o \ - $O/PpmdZip.o \ - $O/QuantumDecoder.o \ - $O/ShrinkDecoder.o \ - $O/XzDecoder.o \ - $O/XzEncoder.o \ - $O/ZstdDecoder.o \ - -# $O/LzfseDecoder.o \ -# $O/ZstdRegister.o - -CRYPTO_OBJS = \ - $O/7zAes.o \ - $O/7zAesRegister.o \ - $O/HmacSha1.o \ - $O/MyAes.o \ - $O/MyAesReg.o \ - $O/Pbkdf2HmacSha1.o \ - $O/RandGen.o \ - $O/WzAes.o \ - $O/ZipCrypto.o \ - $O/ZipStrong.o \ - -C_OBJS = \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - $O/7zStream.o \ - $O/Aes.o \ - $O/AesOpt.o \ - $O/Alloc.o \ - $O/Bcj2.o \ - $O/Bcj2Enc.o \ - $O/Bra.o \ - $O/Bra86.o \ - $O/BraIA64.o \ - $O/BwtSort.o \ - $O/CpuArch.o \ - $O/Delta.o \ - $O/HuffEnc.o \ - $O/LzFind.o \ - $O/Lzma2Dec.o \ - $O/Lzma2DecMt.o \ - $O/Lzma2Enc.o \ - $O/LzmaDec.o \ - $O/LzmaEnc.o \ - $O/MtCoder.o \ - $O/MtDec.o \ - $O/Ppmd7.o \ - $O/Ppmd7Dec.o \ - $O/Ppmd7Enc.o \ - $O/Ppmd8.o \ - $O/Ppmd8Dec.o \ - $O/Ppmd8Enc.o \ - $O/Sha1.o \ - $O/Sha1Opt.o \ - $O/Sha256.o \ - $O/Sha256Opt.o \ - $O/Sort.o \ - $O/SwapBytes.o \ - $O/Xxh64.o \ - $O/Xz.o \ - $O/XzDec.o \ - $O/XzEnc.o \ - $O/XzIn.o \ - $O/XzCrc64.o \ - $O/XzCrc64Opt.o \ - $O/ZstdDec.o \ - - -OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $(C_OBJS) \ - $(MT_OBJS) \ - $(SYS_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(COMPRESS_OBJS) \ - $(CRYPTO_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(AR_OBJS) \ - $(AR_COMMON_OBJS) \ - $(7Z_OBJS) \ - $(CAB_OBJS) \ - $(TAR_OBJS) \ - $(ZIP_OBJS) \ - $(UI_COMMON_OBJS) \ - $(CONSOLE_OBJS) \ - -include ../../7zip_gcc.mak +PROG = 7za + +CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_A +ZIP_FLAGS=-DZ7_ZIP_LZFSE_DISABLE + + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +include ../../LzmaDec_gcc.mak + + +LOCAL_FLAGS_ST = +MT_OBJS = + + +ifdef ST_MODE + +LOCAL_FLAGS_ST = -DZ7_ST + +ifdef IS_MINGW +MT_OBJS = \ + $O/Threads.o \ + +endif + +else + +MT_OBJS = \ + $O/LzFindMt.o \ + $O/LzFindOpt.o \ + $O/Threads.o \ + $O/MemBlocks.o \ + $O/OutMemStream.o \ + $O/ProgressMt.o \ + $O/StreamBinder.o \ + $O/Synchronization.o \ + $O/VirtThread.o \ + +endif + + + +LOCAL_FLAGS_SYS = + +ifdef IS_MINGW + +LOCAL_FLAGS_SYS = \ + -DZ7_DEVICE_FILE \ + +# -DZ7_LARGE_PAGES \ +# -DZ7_LONG_PATH \ + +SYS_OBJS = \ + $O/FileSystem.o \ + $O/Registry.o \ + $O/MemoryLock.o \ + $O/DLL.o \ + $O/DllSecur.o \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + +endif + +LOCAL_FLAGS = \ + $(LOCAL_FLAGS_ST) \ + $(LOCAL_FLAGS_SYS) \ + + +CONSOLE_OBJS = \ + $O/BenchCon.o \ + $O/ConsoleClose.o \ + $O/ExtractCallbackConsole.o \ + $O/HashCon.o \ + $O/List.o \ + $O/Main.o \ + $O/MainAr.o \ + $O/OpenCallbackConsole.o \ + $O/PercentPrinter.o \ + $O/UpdateCallbackConsole.o \ + $O/UserInputUtils.o \ + +UI_COMMON_OBJS = \ + $O/ArchiveCommandLine.o \ + $O/ArchiveExtractCallback.o \ + $O/ArchiveOpenCallback.o \ + $O/Bench.o \ + $O/DefaultName.o \ + $O/EnumDirItems.o \ + $O/Extract.o \ + $O/ExtractingFilePath.o \ + $O/HashCalc.o \ + $O/LoadCodecs.o \ + $O/OpenArchive.o \ + $O/PropIDUtils.o \ + $O/SetProperties.o \ + $O/SortUtils.o \ + $O/TempFiles.o \ + $O/Update.o \ + $O/UpdateAction.o \ + $O/UpdateCallback.o \ + $O/UpdatePair.o \ + $O/UpdateProduce.o \ + +COMMON_OBJS = \ + $O/CommandLineParser.o \ + $O/CRC.o \ + $O/CrcReg.o \ + $O/DynLimBuf.o \ + $O/IntToString.o \ + $O/ListFileUtils.o \ + $O/LzFindPrepare.o \ + $O/MyString.o \ + $O/MyVector.o \ + $O/NewHandler.o \ + $O/Sha1Prepare.o \ + $O/Sha1Reg.o \ + $O/Sha256Prepare.o \ + $O/Sha256Reg.o \ + $O/StdInStream.o \ + $O/StdOutStream.o \ + $O/StringConvert.o \ + $O/StringToInt.o \ + $O/UTFConvert.o \ + $O/Wildcard.o \ + $O/Xxh64Reg.o \ + $O/XzCrc64Init.o \ + $O/XzCrc64Reg.o \ + +WIN_OBJS = \ + $O/ErrorMsg.o \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileIO.o \ + $O/FileLink.o \ + $O/FileName.o \ + $O/PropVariant.o \ + $O/PropVariantConv.o \ + $O/PropVariantUtils.o \ + $O/System.o \ + $O/SystemInfo.o \ + $O/TimeUtils.o \ + +7ZIP_COMMON_OBJS = \ + $O/CreateCoder.o \ + $O/CWrappers.o \ + $O/FilePathAutoRename.o \ + $O/FileStreams.o \ + $O/InBuffer.o \ + $O/InOutTempBuffer.o \ + $O/FilterCoder.o \ + $O/LimitedStreams.o \ + $O/MethodId.o \ + $O/MethodProps.o \ + $O/MultiOutStream.o \ + $O/OffsetStream.o \ + $O/OutBuffer.o \ + $O/ProgressUtils.o \ + $O/PropId.o \ + $O/StreamObjects.o \ + $O/StreamUtils.o \ + $O/UniqBlocks.o \ + +AR_OBJS = \ + $O/Bz2Handler.o \ + $O/GzHandler.o \ + $O/LzmaHandler.o \ + $O/SplitHandler.o \ + $O/XzHandler.o \ + $O/ZstdHandler.o \ + +AR_COMMON_OBJS = \ + $O/CoderMixer2.o \ + $O/DummyOutStream.o \ + $O/HandlerOut.o \ + $O/InStreamWithCRC.o \ + $O/ItemNameUtils.o \ + $O/MultiStream.o \ + $O/OutStreamWithCRC.o \ + $O/ParseProperties.o \ + +7Z_OBJS = \ + $O/7zCompressionMode.o \ + $O/7zDecode.o \ + $O/7zEncode.o \ + $O/7zExtract.o \ + $O/7zFolderInStream.o \ + $O/7zHandler.o \ + $O/7zHandlerOut.o \ + $O/7zHeader.o \ + $O/7zIn.o \ + $O/7zOut.o \ + $O/7zProperties.o \ + $O/7zRegister.o \ + $O/7zSpecStream.o \ + $O/7zUpdate.o \ + +CAB_OBJS = \ + $O/CabBlockInStream.o \ + $O/CabHandler.o \ + $O/CabHeader.o \ + $O/CabIn.o \ + $O/CabRegister.o \ + +TAR_OBJS = \ + $O/TarHandler.o \ + $O/TarHandlerOut.o \ + $O/TarHeader.o \ + $O/TarIn.o \ + $O/TarOut.o \ + $O/TarUpdate.o \ + $O/TarRegister.o \ + +ZIP_OBJS = \ + $O/ZipAddCommon.o \ + $O/ZipHandler.o \ + $O/ZipHandlerOut.o \ + $O/ZipIn.o \ + $O/ZipItem.o \ + $O/ZipOut.o \ + $O/ZipUpdate.o \ + $O/ZipRegister.o \ + +COMPRESS_OBJS = \ + $O/Bcj2Coder.o \ + $O/Bcj2Register.o \ + $O/BcjCoder.o \ + $O/BcjRegister.o \ + $O/BitlDecoder.o \ + $O/BranchMisc.o \ + $O/BranchRegister.o \ + $O/ByteSwap.o \ + $O/BZip2Crc.o \ + $O/BZip2Decoder.o \ + $O/BZip2Encoder.o \ + $O/BZip2Register.o \ + $O/CopyCoder.o \ + $O/CopyRegister.o \ + $O/Deflate64Register.o \ + $O/DeflateDecoder.o \ + $O/DeflateEncoder.o \ + $O/DeflateRegister.o \ + $O/DeltaFilter.o \ + $O/ImplodeDecoder.o \ + $O/Lzma2Decoder.o \ + $O/Lzma2Encoder.o \ + $O/Lzma2Register.o \ + $O/LzmaDecoder.o \ + $O/LzmaEncoder.o \ + $O/LzmaRegister.o \ + $O/LzOutWindow.o \ + $O/LzxDecoder.o \ + $O/PpmdDecoder.o \ + $O/PpmdEncoder.o \ + $O/PpmdRegister.o \ + $O/PpmdZip.o \ + $O/QuantumDecoder.o \ + $O/ShrinkDecoder.o \ + $O/XzDecoder.o \ + $O/XzEncoder.o \ + $O/ZstdDecoder.o \ + +# $O/LzfseDecoder.o \ +# $O/ZstdRegister.o + +CRYPTO_OBJS = \ + $O/7zAes.o \ + $O/7zAesRegister.o \ + $O/HmacSha1.o \ + $O/MyAes.o \ + $O/MyAesReg.o \ + $O/Pbkdf2HmacSha1.o \ + $O/RandGen.o \ + $O/WzAes.o \ + $O/ZipCrypto.o \ + $O/ZipStrong.o \ + +C_OBJS = \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + $O/7zStream.o \ + $O/Aes.o \ + $O/AesOpt.o \ + $O/Alloc.o \ + $O/Bcj2.o \ + $O/Bcj2Enc.o \ + $O/Bra.o \ + $O/Bra86.o \ + $O/BraIA64.o \ + $O/BwtSort.o \ + $O/CpuArch.o \ + $O/Delta.o \ + $O/HuffEnc.o \ + $O/LzFind.o \ + $O/Lzma2Dec.o \ + $O/Lzma2DecMt.o \ + $O/Lzma2Enc.o \ + $O/LzmaDec.o \ + $O/LzmaEnc.o \ + $O/MtCoder.o \ + $O/MtDec.o \ + $O/Ppmd7.o \ + $O/Ppmd7Dec.o \ + $O/Ppmd7Enc.o \ + $O/Ppmd8.o \ + $O/Ppmd8Dec.o \ + $O/Ppmd8Enc.o \ + $O/Sha1.o \ + $O/Sha1Opt.o \ + $O/Sha256.o \ + $O/Sha256Opt.o \ + $O/Sort.o \ + $O/SwapBytes.o \ + $O/Xxh64.o \ + $O/Xz.o \ + $O/XzDec.o \ + $O/XzEnc.o \ + $O/XzIn.o \ + $O/XzCrc64.o \ + $O/XzCrc64Opt.o \ + $O/ZstdDec.o \ + + +OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $(C_OBJS) \ + $(MT_OBJS) \ + $(SYS_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(COMPRESS_OBJS) \ + $(CRYPTO_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(AR_OBJS) \ + $(AR_COMMON_OBJS) \ + $(7Z_OBJS) \ + $(CAB_OBJS) \ + $(TAR_OBJS) \ + $(ZIP_OBJS) \ + $(UI_COMMON_OBJS) \ + $(CONSOLE_OBJS) \ + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/Bundles/Alone/resource.rc b/CPP/7zip/Bundles/Alone/resource.rc index 9b6a30847..c85acaa9c 100644 --- a/CPP/7zip/Bundles/Alone/resource.rc +++ b/CPP/7zip/Bundles/Alone/resource.rc @@ -1,7 +1,7 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("7-Zip Standalone Console", "7za") - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" -#endif +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("7-Zip Standalone Console", "7za") + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" +#endif diff --git a/CPP/7zip/Bundles/Alone2/StdAfx.cpp b/CPP/7zip/Bundles/Alone2/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Alone2/StdAfx.cpp +++ b/CPP/7zip/Bundles/Alone2/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Alone2/StdAfx.h b/CPP/7zip/Bundles/Alone2/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Alone2/StdAfx.h +++ b/CPP/7zip/Bundles/Alone2/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Alone2/makefile b/CPP/7zip/Bundles/Alone2/makefile index ea8904087..af89d6644 100644 --- a/CPP/7zip/Bundles/Alone2/makefile +++ b/CPP/7zip/Bundles/Alone2/makefile @@ -1,31 +1,31 @@ -PROG = 7zz.exe -# USE_C_AES = 1 -# USE_C_SHA = 1 - -CFLAGS = $(CFLAGS) -DZ7_PROG_VARIANT_Z -# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_Z - -!include "../Format7zF/Arc.mak" -!include "../../UI/Console/Console.mak" - -COMMON_OBJS = $(COMMON_OBJS) \ - $O\CommandLineParser.obj \ - $O\ListFileUtils.obj \ - $O\StdInStream.obj \ - $O\StdOutStream.obj \ - -WIN_OBJS = $(WIN_OBJS) \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileLink.obj \ - $O\FileSystem.obj \ - $O\MemoryLock.obj \ - $O\Registry.obj \ - $O\SystemInfo.obj \ - -7ZIP_COMMON_OBJS = $(7ZIP_COMMON_OBJS) \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\MultiOutStream.obj \ - -!include "../../7zip.mak" +PROG = 7zz.exe +# USE_C_AES = 1 +# USE_C_SHA = 1 + +CFLAGS = $(CFLAGS) -DZ7_PROG_VARIANT_Z +# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_Z + +!include "../Format7zF/Arc.mak" +!include "../../UI/Console/Console.mak" + +COMMON_OBJS = $(COMMON_OBJS) \ + $O\CommandLineParser.obj \ + $O\ListFileUtils.obj \ + $O\StdInStream.obj \ + $O\StdOutStream.obj \ + +WIN_OBJS = $(WIN_OBJS) \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileLink.obj \ + $O\FileSystem.obj \ + $O\MemoryLock.obj \ + $O\Registry.obj \ + $O\SystemInfo.obj \ + +7ZIP_COMMON_OBJS = $(7ZIP_COMMON_OBJS) \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\MultiOutStream.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Alone2/makefile.gcc b/CPP/7zip/Bundles/Alone2/makefile.gcc index 1fb09b96c..2785aeae1 100644 --- a/CPP/7zip/Bundles/Alone2/makefile.gcc +++ b/CPP/7zip/Bundles/Alone2/makefile.gcc @@ -1,111 +1,111 @@ -PROG = 7zz - -CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_Z - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - -include ../Format7zF/Arc_gcc.mak - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -LOCAL_FLAGS_SYS = - -ifdef IS_MINGW - -LOCAL_FLAGS_SYS = \ - -DZ7_DEVICE_FILE \ - -# -DZ7_LONG_PATH \ -# -DZ7_DEVICE_FILE \ - -SYS_OBJS = \ - $O/FileSystem.o \ - $O/Registry.o \ - $O/MemoryLock.o \ - $O/DLL.o \ - $O/DllSecur.o \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - -endif - - -LOCAL_FLAGS = \ - $(LOCAL_FLAGS_SYS) \ - $(LOCAL_FLAGS_ST) \ - - -UI_COMMON_OBJS = \ - $O/ArchiveCommandLine.o \ - $O/ArchiveExtractCallback.o \ - $O/ArchiveOpenCallback.o \ - $O/Bench.o \ - $O/DefaultName.o \ - $O/EnumDirItems.o \ - $O/Extract.o \ - $O/ExtractingFilePath.o \ - $O/HashCalc.o \ - $O/LoadCodecs.o \ - $O/OpenArchive.o \ - $O/PropIDUtils.o \ - $O/SetProperties.o \ - $O/SortUtils.o \ - $O/TempFiles.o \ - $O/Update.o \ - $O/UpdateAction.o \ - $O/UpdateCallback.o \ - $O/UpdatePair.o \ - $O/UpdateProduce.o \ - -CONSOLE_OBJS = \ - $O/BenchCon.o \ - $O/ConsoleClose.o \ - $O/ExtractCallbackConsole.o \ - $O/HashCon.o \ - $O/List.o \ - $O/Main.o \ - $O/MainAr.o \ - $O/OpenCallbackConsole.o \ - $O/PercentPrinter.o \ - $O/UpdateCallbackConsole.o \ - $O/UserInputUtils.o \ - -COMMON_OBJS_2 = \ - $O/CommandLineParser.o \ - $O/ListFileUtils.o \ - $O/StdInStream.o \ - $O/StdOutStream.o \ - -WIN_OBJS_2 = \ - $O/ErrorMsg.o \ - $O/FileLink.o \ - $O/SystemInfo.o \ - -7ZIP_COMMON_OBJS_2 = \ - $O/FilePathAutoRename.o \ - $O/FileStreams.o \ - $O/MultiOutStream.o \ - -OBJS = \ - $(ARC_OBJS) \ - $(SYS_OBJS) \ - $(COMMON_OBJS_2) \ - $(WIN_OBJS_2) \ - $(7ZIP_COMMON_OBJS_2) \ - $(UI_COMMON_OBJS) \ - $(CONSOLE_OBJS) \ - -include ../../7zip_gcc.mak +PROG = 7zz + +CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_Z + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + +include ../Format7zF/Arc_gcc.mak + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +LOCAL_FLAGS_SYS = + +ifdef IS_MINGW + +LOCAL_FLAGS_SYS = \ + -DZ7_DEVICE_FILE \ + +# -DZ7_LONG_PATH \ +# -DZ7_DEVICE_FILE \ + +SYS_OBJS = \ + $O/FileSystem.o \ + $O/Registry.o \ + $O/MemoryLock.o \ + $O/DLL.o \ + $O/DllSecur.o \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + +endif + + +LOCAL_FLAGS = \ + $(LOCAL_FLAGS_SYS) \ + $(LOCAL_FLAGS_ST) \ + + +UI_COMMON_OBJS = \ + $O/ArchiveCommandLine.o \ + $O/ArchiveExtractCallback.o \ + $O/ArchiveOpenCallback.o \ + $O/Bench.o \ + $O/DefaultName.o \ + $O/EnumDirItems.o \ + $O/Extract.o \ + $O/ExtractingFilePath.o \ + $O/HashCalc.o \ + $O/LoadCodecs.o \ + $O/OpenArchive.o \ + $O/PropIDUtils.o \ + $O/SetProperties.o \ + $O/SortUtils.o \ + $O/TempFiles.o \ + $O/Update.o \ + $O/UpdateAction.o \ + $O/UpdateCallback.o \ + $O/UpdatePair.o \ + $O/UpdateProduce.o \ + +CONSOLE_OBJS = \ + $O/BenchCon.o \ + $O/ConsoleClose.o \ + $O/ExtractCallbackConsole.o \ + $O/HashCon.o \ + $O/List.o \ + $O/Main.o \ + $O/MainAr.o \ + $O/OpenCallbackConsole.o \ + $O/PercentPrinter.o \ + $O/UpdateCallbackConsole.o \ + $O/UserInputUtils.o \ + +COMMON_OBJS_2 = \ + $O/CommandLineParser.o \ + $O/ListFileUtils.o \ + $O/StdInStream.o \ + $O/StdOutStream.o \ + +WIN_OBJS_2 = \ + $O/ErrorMsg.o \ + $O/FileLink.o \ + $O/SystemInfo.o \ + +7ZIP_COMMON_OBJS_2 = \ + $O/FilePathAutoRename.o \ + $O/FileStreams.o \ + $O/MultiOutStream.o \ + +OBJS = \ + $(ARC_OBJS) \ + $(SYS_OBJS) \ + $(COMMON_OBJS_2) \ + $(WIN_OBJS_2) \ + $(7ZIP_COMMON_OBJS_2) \ + $(UI_COMMON_OBJS) \ + $(CONSOLE_OBJS) \ + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/Bundles/Alone2/resource.rc b/CPP/7zip/Bundles/Alone2/resource.rc index 948963aff..af24c175a 100644 --- a/CPP/7zip/Bundles/Alone2/resource.rc +++ b/CPP/7zip/Bundles/Alone2/resource.rc @@ -1,7 +1,7 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("7-Zip Standalone 2 Console", "7zz") - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" -#endif +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("7-Zip Standalone 2 Console", "7zz") + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" +#endif diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsp b/CPP/7zip/Bundles/Alone7z/Alone.dsp index eebb21bc0..317a88fb8 100644 --- a/CPP/7zip/Bundles/Alone7z/Alone.dsp +++ b/CPP/7zip/Bundles/Alone7z/Alone.dsp @@ -1,2090 +1,2090 @@ -# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=Alone - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Alone.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application") -!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Alone - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseU" -# PROP BASE Intermediate_Dir "ReleaseU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gr /MD /W4 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98 -# SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "DebugU" -# PROP BASE Intermediate_Dir "DebugU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c -# ADD CPP /nologo /Gr /MDd /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "Alone - Win32 Release" -# Name "Alone - Win32 Debug" -# Name "Alone - Win32 ReleaseU" -# Name "Alone - Win32 DebugU" -# Begin Group "Console" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Console\BenchCon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\BenchCon.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\CompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ExtractCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\HashCon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\HashCon.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\List.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\List.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\Main.cpp -# ADD CPP /D "PROG_VARIANT_R" -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\MainAr.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\OpenCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\PercentPrinter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\PercentPrinter.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UpdateCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UserInputUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UserInputUtils.h -# End Source File -# End Group -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\AutoPtr.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Buffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common0.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CrcReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynamicBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\LzFindPrepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyException.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyGuidDef.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyLinux.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyUnknown.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\MyVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Types.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Init.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Reg.cpp -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Device.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Handle.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterArc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterCodec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ByteSwap.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeltaFilter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzEncoder.h -# End Source File -# End Group -# Begin Group "Archive" - -# PROP Default_Filter "" -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.h -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\LzmaHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SplitHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\XzHandler.cpp -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveCommandLine.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Property.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\TempFiles.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\TempFiles.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Update.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Update.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateProduce.h -# End Source File -# End Group -# Begin Group "7-zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Group "Xz" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\Xz.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xz.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64Opt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzEnc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzIn.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\AesOpt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2Enc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BraIA64.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindOpt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compress\Lz\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\RotateDefs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\SwapBytes.c - -!IF "$(CFG)" == "Alone - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\SwapBytes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "Crypto" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAesRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAesReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RandGen.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RandGen.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Alone - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Alone.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application") +!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Alone - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gr /MD /W4 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98 +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c +# ADD CPP /nologo /Gr /MDd /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Alone - Win32 Release" +# Name "Alone - Win32 Debug" +# Name "Alone - Win32 ReleaseU" +# Name "Alone - Win32 DebugU" +# Begin Group "Console" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Console\BenchCon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\BenchCon.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\CompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ExtractCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\HashCon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\HashCon.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\List.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\List.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\Main.cpp +# ADD CPP /D "PROG_VARIANT_R" +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\MainAr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\OpenCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\PercentPrinter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\PercentPrinter.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UpdateCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UserInputUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UserInputUtils.h +# End Source File +# End Group +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\AutoPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Buffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common0.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CrcReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynamicBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\LzFindPrepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyException.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyGuidDef.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyLinux.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyUnknown.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\MyVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Reg.cpp +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Device.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Handle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterArc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterCodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ByteSwap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeltaFilter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzEncoder.h +# End Source File +# End Group +# Begin Group "Archive" + +# PROP Default_Filter "" +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.h +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\LzmaHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SplitHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\XzHandler.cpp +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveCommandLine.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Property.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\TempFiles.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\TempFiles.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Update.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Update.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateProduce.h +# End Source File +# End Group +# Begin Group "7-zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Group "Xz" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\Xz.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xz.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64Opt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzEnc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzIn.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\AesOpt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2Enc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BraIA64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindOpt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compress\Lz\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\RotateDefs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\SwapBytes.c + +!IF "$(CFG)" == "Alone - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Alone - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\SwapBytes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "Crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAesRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAesReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RandGen.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RandGen.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsw b/CPP/7zip/Bundles/Alone7z/Alone.dsw index 036aab454..65eca43f6 100644 --- a/CPP/7zip/Bundles/Alone7z/Alone.dsw +++ b/CPP/7zip/Bundles/Alone7z/Alone.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Alone"=.\Alone.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Alone"=.\Alone.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/Alone7z/StdAfx.cpp b/CPP/7zip/Bundles/Alone7z/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Alone7z/StdAfx.cpp +++ b/CPP/7zip/Bundles/Alone7z/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Alone7z/StdAfx.h b/CPP/7zip/Bundles/Alone7z/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Alone7z/StdAfx.h +++ b/CPP/7zip/Bundles/Alone7z/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Alone7z/makefile b/CPP/7zip/Bundles/Alone7z/makefile index 296258ec0..89584e153 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile +++ b/CPP/7zip/Bundles/Alone7z/makefile @@ -1,168 +1,168 @@ -PROG = 7zr.exe - -# USE_C_AES = 1 -# USE_C_SHA = 1 -# USE_C_CRC64 = 1 -# USE_C_CRC = 1 -# NO_ASM_GNU=1 -# NO_ASM=1 - -CFLAGS = $(CFLAGS) -DZ7_PROG_VARIANT_R -# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_R - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\ListFileUtils.obj \ - $O\LzFindPrepare.obj \ - $O\NewHandler.obj \ - $O\StdInStream.obj \ - $O\StdOutStream.obj \ - $O\MyString.obj \ - $O\Sha256Reg.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - $O\XzCrc64Init.obj \ - $O\XzCrc64Reg.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\FileSystem.obj \ - $O\MemoryLock.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Registry.obj \ - $O\System.obj \ - $O\SystemInfo.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\InBuffer.obj \ - $O\InOutTempBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\MultiOutStream.obj \ - $O\OffsetStream.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\LzmaHandler.obj \ - $O\SplitHandler.obj \ - $O\XzHandler.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\DummyOutStream.obj \ - $O\HandlerOut.obj \ - $O\InStreamWithCRC.obj \ - $O\ItemNameUtils.obj \ - $O\MultiStream.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zEncode.obj \ - $O\7zExtract.obj \ - $O\7zFolderInStream.obj \ - $O\7zHandler.obj \ - $O\7zHandlerOut.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zOut.obj \ - $O\7zProperties.obj \ - $O\7zRegister.obj \ - $O\7zSpecStream.obj \ - $O\7zUpdate.obj \ - -COMPRESS_OBJS = \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Encoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaEncoder.obj \ - $O\LzmaRegister.obj \ - $O\XzDecoder.obj \ - $O\XzEncoder.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\MyAes.obj \ - $O\MyAesReg.obj \ - $O\RandGen.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bcj2Enc.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\Lzma2Enc.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\MtCoder.obj \ - $O\MtDec.obj \ - $O\Sort.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - $O\Xz.obj \ - $O\XzDec.obj \ - $O\XzEnc.obj \ - $O\XzIn.obj \ - -!include "../../UI/Console/Console.mak" - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../Crc64.mak" -!include "../../LzFindOpt.mak" -!include "../../LzmaDec.mak" -!include "../../Sha256.mak" - -!include "../../7zip.mak" +PROG = 7zr.exe + +# USE_C_AES = 1 +# USE_C_SHA = 1 +# USE_C_CRC64 = 1 +# USE_C_CRC = 1 +# NO_ASM_GNU=1 +# NO_ASM=1 + +CFLAGS = $(CFLAGS) -DZ7_PROG_VARIANT_R +# CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_R + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\ListFileUtils.obj \ + $O\LzFindPrepare.obj \ + $O\NewHandler.obj \ + $O\StdInStream.obj \ + $O\StdOutStream.obj \ + $O\MyString.obj \ + $O\Sha256Reg.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + $O\XzCrc64Init.obj \ + $O\XzCrc64Reg.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\FileSystem.obj \ + $O\MemoryLock.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Registry.obj \ + $O\System.obj \ + $O\SystemInfo.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\InBuffer.obj \ + $O\InOutTempBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\MultiOutStream.obj \ + $O\OffsetStream.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\LzmaHandler.obj \ + $O\SplitHandler.obj \ + $O\XzHandler.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\DummyOutStream.obj \ + $O\HandlerOut.obj \ + $O\InStreamWithCRC.obj \ + $O\ItemNameUtils.obj \ + $O\MultiStream.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zEncode.obj \ + $O\7zExtract.obj \ + $O\7zFolderInStream.obj \ + $O\7zHandler.obj \ + $O\7zHandlerOut.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zOut.obj \ + $O\7zProperties.obj \ + $O\7zRegister.obj \ + $O\7zSpecStream.obj \ + $O\7zUpdate.obj \ + +COMPRESS_OBJS = \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Encoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaEncoder.obj \ + $O\LzmaRegister.obj \ + $O\XzDecoder.obj \ + $O\XzEncoder.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\MyAes.obj \ + $O\MyAesReg.obj \ + $O\RandGen.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bcj2Enc.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\Lzma2Enc.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\MtCoder.obj \ + $O\MtDec.obj \ + $O\Sort.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + $O\Xz.obj \ + $O\XzDec.obj \ + $O\XzEnc.obj \ + $O\XzIn.obj \ + +!include "../../UI/Console/Console.mak" + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../Crc64.mak" +!include "../../LzFindOpt.mak" +!include "../../LzmaDec.mak" +!include "../../Sha256.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Alone7z/makefile.gcc b/CPP/7zip/Bundles/Alone7z/makefile.gcc index b5885b3a7..a31475e25 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile.gcc +++ b/CPP/7zip/Bundles/Alone7z/makefile.gcc @@ -1,279 +1,279 @@ -PROG = 7zr - -CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_R - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -include ../../LzmaDec_gcc.mak - - -LOCAL_FLAGS_ST = -MT_OBJS = - - -ifdef ST_MODE - -LOCAL_FLAGS_ST = -DZ7_ST - -ifdef IS_MINGW -MT_OBJS = \ - $O/Threads.o \ - -endif - -else - -MT_OBJS = \ - $O/LzFindMt.o \ - $O/LzFindOpt.o \ - $O/Threads.o \ - $O/StreamBinder.o \ - $O/VirtThread.o \ - - - - - -endif - - - -LOCAL_FLAGS_SYS = - -ifdef IS_MINGW - -LOCAL_FLAGS_SYS = \ - -DZ7_DEVICE_FILE \ - -# -DZ7_LARGE_PAGES \ -# -DZ7_LONG_PATH \ - -SYS_OBJS = \ - $O/FileSystem.o \ - $O/Registry.o \ - $O/MemoryLock.o \ - $O/DLL.o \ - $O/DllSecur.o \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - -endif - -LOCAL_FLAGS = \ - $(LOCAL_FLAGS_ST) \ - $(LOCAL_FLAGS_SYS) \ - - -CONSOLE_OBJS = \ - $O/BenchCon.o \ - $O/ConsoleClose.o \ - $O/ExtractCallbackConsole.o \ - $O/HashCon.o \ - $O/List.o \ - $O/Main.o \ - $O/MainAr.o \ - $O/OpenCallbackConsole.o \ - $O/PercentPrinter.o \ - $O/UpdateCallbackConsole.o \ - $O/UserInputUtils.o \ - -UI_COMMON_OBJS = \ - $O/ArchiveCommandLine.o \ - $O/ArchiveExtractCallback.o \ - $O/ArchiveOpenCallback.o \ - $O/Bench.o \ - $O/DefaultName.o \ - $O/EnumDirItems.o \ - $O/Extract.o \ - $O/ExtractingFilePath.o \ - $O/HashCalc.o \ - $O/LoadCodecs.o \ - $O/OpenArchive.o \ - $O/PropIDUtils.o \ - $O/SetProperties.o \ - $O/SortUtils.o \ - $O/TempFiles.o \ - $O/Update.o \ - $O/UpdateAction.o \ - $O/UpdateCallback.o \ - $O/UpdatePair.o \ - $O/UpdateProduce.o \ - -COMMON_OBJS = \ - $O/CommandLineParser.o \ - $O/CRC.o \ - $O/CrcReg.o \ - $O/DynLimBuf.o \ - $O/IntToString.o \ - $O/ListFileUtils.o \ - $O/LzFindPrepare.o \ - $O/MyString.o \ - $O/MyVector.o \ - $O/NewHandler.o \ - $O/Sha256Prepare.o \ - $O/Sha256Reg.o \ - $O/StdInStream.o \ - $O/StdOutStream.o \ - $O/StringConvert.o \ - $O/StringToInt.o \ - $O/UTFConvert.o \ - $O/Wildcard.o \ - $O/XzCrc64Init.o \ - $O/XzCrc64Reg.o \ - -WIN_OBJS = \ - $O/ErrorMsg.o \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileIO.o \ - $O/FileLink.o \ - $O/FileName.o \ - $O/PropVariant.o \ - $O/PropVariantConv.o \ - $O/System.o \ - $O/SystemInfo.o \ - $O/TimeUtils.o \ - -7ZIP_COMMON_OBJS = \ - $O/CreateCoder.o \ - $O/CWrappers.o \ - $O/FilePathAutoRename.o \ - $O/FileStreams.o \ - $O/InBuffer.o \ - $O/InOutTempBuffer.o \ - $O/FilterCoder.o \ - $O/LimitedStreams.o \ - $O/MethodId.o \ - $O/MethodProps.o \ - $O/MultiOutStream.o \ - $O/OffsetStream.o \ - $O/OutBuffer.o \ - $O/ProgressUtils.o \ - $O/PropId.o \ - $O/StreamObjects.o \ - $O/StreamUtils.o \ - $O/UniqBlocks.o \ - -AR_OBJS = \ - $O/LzmaHandler.o \ - $O/SplitHandler.o \ - $O/XzHandler.o \ - -AR_COMMON_OBJS = \ - $O/CoderMixer2.o \ - $O/DummyOutStream.o \ - $O/HandlerOut.o \ - $O/InStreamWithCRC.o \ - $O/ItemNameUtils.o \ - $O/MultiStream.o \ - $O/OutStreamWithCRC.o \ - $O/ParseProperties.o \ - -7Z_OBJS = \ - $O/7zCompressionMode.o \ - $O/7zDecode.o \ - $O/7zEncode.o \ - $O/7zExtract.o \ - $O/7zFolderInStream.o \ - $O/7zHandler.o \ - $O/7zHandlerOut.o \ - $O/7zHeader.o \ - $O/7zIn.o \ - $O/7zOut.o \ - $O/7zProperties.o \ - $O/7zRegister.o \ - $O/7zSpecStream.o \ - $O/7zUpdate.o \ - -COMPRESS_OBJS = \ - $O/Bcj2Coder.o \ - $O/Bcj2Register.o \ - $O/BcjCoder.o \ - $O/BcjRegister.o \ - $O/BranchMisc.o \ - $O/BranchRegister.o \ - $O/ByteSwap.o \ - $O/CopyCoder.o \ - $O/CopyRegister.o \ - $O/DeltaFilter.o \ - $O/Lzma2Decoder.o \ - $O/Lzma2Encoder.o \ - $O/Lzma2Register.o \ - $O/LzmaDecoder.o \ - $O/LzmaEncoder.o \ - $O/LzmaRegister.o \ - $O/XzDecoder.o \ - $O/XzEncoder.o \ - -CRYPTO_OBJS = \ - $O/7zAes.o \ - $O/7zAesRegister.o \ - $O/MyAes.o \ - $O/MyAesReg.o \ - $O/RandGen.o \ - -C_OBJS = \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - $O/7zStream.o \ - $O/Aes.o \ - $O/AesOpt.o \ - $O/Alloc.o \ - $O/Bcj2.o \ - $O/Bcj2Enc.o \ - $O/Bra.o \ - $O/Bra86.o \ - $O/BraIA64.o \ - $O/CpuArch.o \ - $O/Delta.o \ - $O/LzFind.o \ - $O/Lzma2Dec.o \ - $O/Lzma2DecMt.o \ - $O/Lzma2Enc.o \ - $O/LzmaDec.o \ - $O/LzmaEnc.o \ - $O/MtCoder.o \ - $O/MtDec.o \ - $O/Sha256.o \ - $O/Sha256Opt.o \ - $O/SwapBytes.o \ - $O/Xz.o \ - $O/XzDec.o \ - $O/XzEnc.o \ - $O/XzIn.o \ - $O/XzCrc64.o \ - $O/XzCrc64Opt.o \ - - -OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $(C_OBJS) \ - $(MT_OBJS) \ - $(SYS_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(COMPRESS_OBJS) \ - $(CRYPTO_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(AR_OBJS) \ - $(AR_COMMON_OBJS) \ - $(7Z_OBJS) \ - $(UI_COMMON_OBJS) \ - $(CONSOLE_OBJS) \ - -include ../../7zip_gcc.mak +PROG = 7zr + +CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_R + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +include ../../LzmaDec_gcc.mak + + +LOCAL_FLAGS_ST = +MT_OBJS = + + +ifdef ST_MODE + +LOCAL_FLAGS_ST = -DZ7_ST + +ifdef IS_MINGW +MT_OBJS = \ + $O/Threads.o \ + +endif + +else + +MT_OBJS = \ + $O/LzFindMt.o \ + $O/LzFindOpt.o \ + $O/Threads.o \ + $O/StreamBinder.o \ + $O/VirtThread.o \ + + + + + +endif + + + +LOCAL_FLAGS_SYS = + +ifdef IS_MINGW + +LOCAL_FLAGS_SYS = \ + -DZ7_DEVICE_FILE \ + +# -DZ7_LARGE_PAGES \ +# -DZ7_LONG_PATH \ + +SYS_OBJS = \ + $O/FileSystem.o \ + $O/Registry.o \ + $O/MemoryLock.o \ + $O/DLL.o \ + $O/DllSecur.o \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + +endif + +LOCAL_FLAGS = \ + $(LOCAL_FLAGS_ST) \ + $(LOCAL_FLAGS_SYS) \ + + +CONSOLE_OBJS = \ + $O/BenchCon.o \ + $O/ConsoleClose.o \ + $O/ExtractCallbackConsole.o \ + $O/HashCon.o \ + $O/List.o \ + $O/Main.o \ + $O/MainAr.o \ + $O/OpenCallbackConsole.o \ + $O/PercentPrinter.o \ + $O/UpdateCallbackConsole.o \ + $O/UserInputUtils.o \ + +UI_COMMON_OBJS = \ + $O/ArchiveCommandLine.o \ + $O/ArchiveExtractCallback.o \ + $O/ArchiveOpenCallback.o \ + $O/Bench.o \ + $O/DefaultName.o \ + $O/EnumDirItems.o \ + $O/Extract.o \ + $O/ExtractingFilePath.o \ + $O/HashCalc.o \ + $O/LoadCodecs.o \ + $O/OpenArchive.o \ + $O/PropIDUtils.o \ + $O/SetProperties.o \ + $O/SortUtils.o \ + $O/TempFiles.o \ + $O/Update.o \ + $O/UpdateAction.o \ + $O/UpdateCallback.o \ + $O/UpdatePair.o \ + $O/UpdateProduce.o \ + +COMMON_OBJS = \ + $O/CommandLineParser.o \ + $O/CRC.o \ + $O/CrcReg.o \ + $O/DynLimBuf.o \ + $O/IntToString.o \ + $O/ListFileUtils.o \ + $O/LzFindPrepare.o \ + $O/MyString.o \ + $O/MyVector.o \ + $O/NewHandler.o \ + $O/Sha256Prepare.o \ + $O/Sha256Reg.o \ + $O/StdInStream.o \ + $O/StdOutStream.o \ + $O/StringConvert.o \ + $O/StringToInt.o \ + $O/UTFConvert.o \ + $O/Wildcard.o \ + $O/XzCrc64Init.o \ + $O/XzCrc64Reg.o \ + +WIN_OBJS = \ + $O/ErrorMsg.o \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileIO.o \ + $O/FileLink.o \ + $O/FileName.o \ + $O/PropVariant.o \ + $O/PropVariantConv.o \ + $O/System.o \ + $O/SystemInfo.o \ + $O/TimeUtils.o \ + +7ZIP_COMMON_OBJS = \ + $O/CreateCoder.o \ + $O/CWrappers.o \ + $O/FilePathAutoRename.o \ + $O/FileStreams.o \ + $O/InBuffer.o \ + $O/InOutTempBuffer.o \ + $O/FilterCoder.o \ + $O/LimitedStreams.o \ + $O/MethodId.o \ + $O/MethodProps.o \ + $O/MultiOutStream.o \ + $O/OffsetStream.o \ + $O/OutBuffer.o \ + $O/ProgressUtils.o \ + $O/PropId.o \ + $O/StreamObjects.o \ + $O/StreamUtils.o \ + $O/UniqBlocks.o \ + +AR_OBJS = \ + $O/LzmaHandler.o \ + $O/SplitHandler.o \ + $O/XzHandler.o \ + +AR_COMMON_OBJS = \ + $O/CoderMixer2.o \ + $O/DummyOutStream.o \ + $O/HandlerOut.o \ + $O/InStreamWithCRC.o \ + $O/ItemNameUtils.o \ + $O/MultiStream.o \ + $O/OutStreamWithCRC.o \ + $O/ParseProperties.o \ + +7Z_OBJS = \ + $O/7zCompressionMode.o \ + $O/7zDecode.o \ + $O/7zEncode.o \ + $O/7zExtract.o \ + $O/7zFolderInStream.o \ + $O/7zHandler.o \ + $O/7zHandlerOut.o \ + $O/7zHeader.o \ + $O/7zIn.o \ + $O/7zOut.o \ + $O/7zProperties.o \ + $O/7zRegister.o \ + $O/7zSpecStream.o \ + $O/7zUpdate.o \ + +COMPRESS_OBJS = \ + $O/Bcj2Coder.o \ + $O/Bcj2Register.o \ + $O/BcjCoder.o \ + $O/BcjRegister.o \ + $O/BranchMisc.o \ + $O/BranchRegister.o \ + $O/ByteSwap.o \ + $O/CopyCoder.o \ + $O/CopyRegister.o \ + $O/DeltaFilter.o \ + $O/Lzma2Decoder.o \ + $O/Lzma2Encoder.o \ + $O/Lzma2Register.o \ + $O/LzmaDecoder.o \ + $O/LzmaEncoder.o \ + $O/LzmaRegister.o \ + $O/XzDecoder.o \ + $O/XzEncoder.o \ + +CRYPTO_OBJS = \ + $O/7zAes.o \ + $O/7zAesRegister.o \ + $O/MyAes.o \ + $O/MyAesReg.o \ + $O/RandGen.o \ + +C_OBJS = \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + $O/7zStream.o \ + $O/Aes.o \ + $O/AesOpt.o \ + $O/Alloc.o \ + $O/Bcj2.o \ + $O/Bcj2Enc.o \ + $O/Bra.o \ + $O/Bra86.o \ + $O/BraIA64.o \ + $O/CpuArch.o \ + $O/Delta.o \ + $O/LzFind.o \ + $O/Lzma2Dec.o \ + $O/Lzma2DecMt.o \ + $O/Lzma2Enc.o \ + $O/LzmaDec.o \ + $O/LzmaEnc.o \ + $O/MtCoder.o \ + $O/MtDec.o \ + $O/Sha256.o \ + $O/Sha256Opt.o \ + $O/SwapBytes.o \ + $O/Xz.o \ + $O/XzDec.o \ + $O/XzEnc.o \ + $O/XzIn.o \ + $O/XzCrc64.o \ + $O/XzCrc64Opt.o \ + + +OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $(C_OBJS) \ + $(MT_OBJS) \ + $(SYS_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(COMPRESS_OBJS) \ + $(CRYPTO_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(AR_OBJS) \ + $(AR_COMMON_OBJS) \ + $(7Z_OBJS) \ + $(UI_COMMON_OBJS) \ + $(CONSOLE_OBJS) \ + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/Bundles/Alone7z/resource.rc b/CPP/7zip/Bundles/Alone7z/resource.rc index 36d70e7d9..593785007 100644 --- a/CPP/7zip/Bundles/Alone7z/resource.rc +++ b/CPP/7zip/Bundles/Alone7z/resource.rc @@ -1,7 +1,7 @@ -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_APP("7-Zip Reduced Standalone Console", "7zr") - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" -#endif +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_APP("7-Zip Reduced Standalone Console", "7zr") + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" +#endif diff --git a/CPP/7zip/Bundles/Fm/FM.dsp b/CPP/7zip/Bundles/Fm/FM.dsp index d45b10149..6e55d9269 100644 --- a/CPP/7zip/Bundles/Fm/FM.dsp +++ b/CPP/7zip/Bundles/Fm/FM.dsp @@ -1,2275 +1,2275 @@ -# Microsoft Developer Studio Project File - Name="FM" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=FM - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "FM.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "FM.mak" CFG="FM - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "FM - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "FM - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE "FM - Win32 ReleaseU" (based on "Win32 (x86) Application") -!MESSAGE "FM - Win32 DebugU" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "FM - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "FM - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseU" -# PROP BASE Intermediate_Dir "ReleaseU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "FM - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "DebugU" -# PROP BASE Intermediate_Dir "DebugU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c -# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "FM - Win32 Release" -# Name "FM - Win32 Debug" -# Name "FM - Win32 ReleaseU" -# Name "FM - Win32 DebugU" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\7zipLogo.ico -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\add.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ClassDefs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Copy.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Delete.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Extract.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FM.ico -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Move.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Parent.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Properties.bmp -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\StdAfx.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Test.bmp -# End Source File -# End Group -# Begin Group "Archive" - -# PROP Default_Filter "" -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\FindSignature.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\FindSignature.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.h -# End Source File -# End Group -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# End Group -# Begin Group "Folders" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\AltStreamsFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\AltStreamsFolder.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FSDrives.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FSDrives.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FSFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FSFolder.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FSFolderCopy.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\IFolder.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\NetFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\NetFolder.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RootFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RootFolder.h -# End Source File -# End Group -# Begin Group "Registry" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\RegistryAssociations.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RegistryAssociations.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RegistryPlugins.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RegistryPlugins.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RegistryUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\RegistryUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ViewSettings.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ViewSettings.h -# End Source File -# End Group -# Begin Group "Panel" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\App.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\App.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\AppState.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\EnumFormatEtc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\EnumFormatEtc.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FileFolderPluginOpen.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FileFolderPluginOpen.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Panel.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Panel.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelCopy.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelCrc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelDrag.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelFolderChange.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelItemOpen.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelKey.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelListNotify.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelMenu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelOperations.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelSelect.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelSort.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PanelSplitFile.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\VerCtrl.cpp -# End Source File -# End Group -# Begin Group "Dialog" - -# PROP Default_Filter "" -# Begin Group "Options" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\EditPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\EditPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FoldersPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FoldersPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LangPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LangPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MenuPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MenuPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OptionsDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SettingsPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SettingsPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SystemPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SystemPage.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\UI\FileManager\AboutDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\AboutDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog2.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog2Res.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ComboDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ComboDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\CopyDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\CopyDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\DialogSize.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\EditDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\EditDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LinkDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LinkDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ListViewDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ListViewDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MemDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MemDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MemDialogRes.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MessagesDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MessagesDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OverwriteDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PasswordDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PasswordDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgressDialog2.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SplitDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SplitDialog.h -# End Source File -# End Group -# Begin Group "FM Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\ExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FormatUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FormatUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\HelpUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\HelpUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LangUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LangUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgramLocation.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgramLocation.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\UpdateCallback100.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\UpdateCallback100.h -# End Source File -# End Group -# Begin Group "7-Zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c - -!IF "$(CFG)" == "FM - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c - -!IF "$(CFG)" == "FM - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.c - -!IF "$(CFG)" == "FM - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "FM - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Group "Control" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\CommandBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Edit.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ImageList.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ProgressBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\PropertyPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\PropertyPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ReBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Static.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\StatusBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ToolBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Trackbar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Window2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Window2.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\COM.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Device.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Handle.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Menu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Menu.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Net.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Net.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ProcessUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ProcessUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CrcReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynamicBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Exception.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\LzFindPrepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Random.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Random.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha1Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha1Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Types.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Init.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Reg.cpp -# End Source File -# End Group -# Begin Group "UI" - -# PROP Default_Filter "" -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\CompressCall.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\CompressCall2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\IFileExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Property.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\StdAfx.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\TempFiles.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\TempFiles.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Update.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Update.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\UpdateProduce.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\WorkDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\WorkDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ZipRegistry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ZipRegistry.h -# End Source File -# End Group -# Begin Group "Agent" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Agent\Agent.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\Agent.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\AgentOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\AgentProxy.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\AgentProxy.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\ArchiveFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\ArchiveFolderOpen.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\ArchiveFolderOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\IFolderArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\UpdateCallbackAgent.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Agent\UpdateCallbackAgent.h -# End Source File -# End Group -# Begin Group "Explorer" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Explorer\ContextMenu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\ContextMenu.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\MyMessages.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\MyMessages.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\RegistryContextMenu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\RegistryContextMenu.h -# End Source File -# End Group -# Begin Group "GUI" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\GUI\BenchmarkDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\BenchmarkDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\BenchmarkDialogRes.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\CompressDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\CompressDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractGUI.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractGUI.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\HashGUI.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\HashGUI.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\UpdateCallbackGUI.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\UpdateCallbackGUI.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\UpdateCallbackGUI2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\UpdateCallbackGUI2.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\UpdateGUI.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\UpdateGUI.h -# End Source File -# End Group -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# End Group -# Begin Group "Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\UI\FileManager\7zFM.exe.manifest -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\7zipLogo.ico -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Add2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Copy2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Delete2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Extract2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FilePlugins.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FilePlugins.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FM.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Info.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Info2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Move2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MyCom2.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MyLoadMenu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\MyLoadMenu.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PluginInterface.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PluginLoader.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PropertyName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PropertyName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\resource.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SplitUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SplitUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\StringUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\StringUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SysIconUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SysIconUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\Test2.bmp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\TextPairs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\TextPairs.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="FM" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=FM - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "FM.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "FM.mak" CFG="FM - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FM - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "FM - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "FM - Win32 ReleaseU" (based on "Win32 (x86) Application") +!MESSAGE "FM - Win32 DebugU" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FM - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "FM - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "FM - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c +# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "FM - Win32 Release" +# Name "FM - Win32 Debug" +# Name "FM - Win32 ReleaseU" +# Name "FM - Win32 DebugU" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\7zipLogo.ico +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\add.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ClassDefs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Copy.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Delete.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Extract.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FM.ico +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Move.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Parent.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Properties.bmp +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Test.bmp +# End Source File +# End Group +# Begin Group "Archive" + +# PROP Default_Filter "" +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FindSignature.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FindSignature.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.h +# End Source File +# End Group +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# End Group +# Begin Group "Folders" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\AltStreamsFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\AltStreamsFolder.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FSDrives.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FSDrives.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FSFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FSFolder.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FSFolderCopy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\IFolder.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\NetFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\NetFolder.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RootFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RootFolder.h +# End Source File +# End Group +# Begin Group "Registry" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\RegistryAssociations.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RegistryAssociations.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RegistryPlugins.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RegistryPlugins.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RegistryUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\RegistryUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ViewSettings.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ViewSettings.h +# End Source File +# End Group +# Begin Group "Panel" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\App.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\App.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\AppState.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\EnumFormatEtc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\EnumFormatEtc.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FileFolderPluginOpen.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FileFolderPluginOpen.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Panel.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Panel.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelCopy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelCrc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelDrag.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelFolderChange.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelItemOpen.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelKey.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelListNotify.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelOperations.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelSelect.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelSort.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PanelSplitFile.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\VerCtrl.cpp +# End Source File +# End Group +# Begin Group "Dialog" + +# PROP Default_Filter "" +# Begin Group "Options" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\EditPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\EditPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FoldersPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FoldersPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LangPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LangPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MenuPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MenuPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OptionsDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SettingsPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SettingsPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SystemPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SystemPage.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\UI\FileManager\AboutDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\AboutDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog2.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog2Res.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ComboDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ComboDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\CopyDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\CopyDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\DialogSize.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\EditDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\EditDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LinkDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LinkDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ListViewDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ListViewDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MemDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MemDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MemDialogRes.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MessagesDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MessagesDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OverwriteDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PasswordDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PasswordDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgressDialog2.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SplitDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SplitDialog.h +# End Source File +# End Group +# Begin Group "FM Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\ExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FormatUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\HelpUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\HelpUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LangUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LangUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgramLocation.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgramLocation.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\UpdateCallback100.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\UpdateCallback100.h +# End Source File +# End Group +# Begin Group "7-Zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c + +!IF "$(CFG)" == "FM - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c + +!IF "$(CFG)" == "FM - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.c + +!IF "$(CFG)" == "FM - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "FM - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\CommandBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Edit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ImageList.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ProgressBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\PropertyPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\PropertyPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ReBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Static.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\StatusBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ToolBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Trackbar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Window2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Window2.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\COM.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Device.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Handle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Menu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Menu.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Net.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Net.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ProcessUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ProcessUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CrcReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynamicBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Exception.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\LzFindPrepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Reg.cpp +# End Source File +# End Group +# Begin Group "UI" + +# PROP Default_Filter "" +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\CompressCall.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\CompressCall2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\IFileExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Property.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\TempFiles.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\TempFiles.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Update.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Update.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\UpdateProduce.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\WorkDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\WorkDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ZipRegistry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ZipRegistry.h +# End Source File +# End Group +# Begin Group "Agent" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Agent\Agent.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\Agent.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\AgentOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\AgentProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\AgentProxy.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\ArchiveFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\ArchiveFolderOpen.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\ArchiveFolderOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\IFolderArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\UpdateCallbackAgent.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Agent\UpdateCallbackAgent.h +# End Source File +# End Group +# Begin Group "Explorer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Explorer\ContextMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\ContextMenu.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\RegistryContextMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\RegistryContextMenu.h +# End Source File +# End Group +# Begin Group "GUI" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\GUI\BenchmarkDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\BenchmarkDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\BenchmarkDialogRes.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\CompressDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\CompressDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractGUI.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\HashGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\HashGUI.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\UpdateCallbackGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\UpdateCallbackGUI.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\UpdateCallbackGUI2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\UpdateCallbackGUI2.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\UpdateGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\UpdateGUI.h +# End Source File +# End Group +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\UI\FileManager\7zFM.exe.manifest +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\7zipLogo.ico +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Add2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Copy2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Delete2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Extract2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FilePlugins.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FilePlugins.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FM.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Info.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Info2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Move2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MyCom2.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MyLoadMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\MyLoadMenu.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PluginInterface.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PluginLoader.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PropertyName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PropertyName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\resource.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SplitUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SplitUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\StringUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\StringUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SysIconUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SysIconUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\Test2.bmp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\TextPairs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\TextPairs.h +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/Bundles/Fm/FM.dsw b/CPP/7zip/Bundles/Fm/FM.dsw index 38f65d224..1c955d956 100644 --- a/CPP/7zip/Bundles/Fm/FM.dsw +++ b/CPP/7zip/Bundles/Fm/FM.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "FM"=.\FM.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "FM"=.\FM.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/Fm/StdAfx.cpp b/CPP/7zip/Bundles/Fm/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Fm/StdAfx.cpp +++ b/CPP/7zip/Bundles/Fm/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Fm/StdAfx.h b/CPP/7zip/Bundles/Fm/StdAfx.h index bff4fd711..4f27255c6 100644 --- a/CPP/7zip/Bundles/Fm/StdAfx.h +++ b/CPP/7zip/Bundles/Fm/StdAfx.h @@ -1,6 +1,6 @@ -// StdAfx.h - -#if _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../UI/FileManager/StdAfx.h" +// StdAfx.h + +#if _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../UI/FileManager/StdAfx.h" diff --git a/CPP/7zip/Bundles/Fm/makefile b/CPP/7zip/Bundles/Fm/makefile index e502f3b6e..de74f7627 100644 --- a/CPP/7zip/Bundles/Fm/makefile +++ b/CPP/7zip/Bundles/Fm/makefile @@ -1,84 +1,84 @@ -PROG = 7zFM.exe - -# CFLAGS = $(CFLAGS) -DZ7_LARGE_PAGES - -!include "../Format7zF/Arc.mak" - -!include "../../UI/FileManager/FM.mak" - -COMMON_OBJS = $(COMMON_OBJS) \ - $O\CommandLineParser.obj \ - $O\Lang.obj \ - $O\ListFileUtils.obj \ - $O\Random.obj \ - -WIN_OBJS = $(WIN_OBJS) \ - $O\Clipboard.obj \ - $O\CommonDialog.obj \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileLink.obj \ - $O\MemoryGlobal.obj \ - $O\MemoryLock.obj \ - $O\Menu.obj \ - $O\ProcessUtils.obj \ - $O\Registry.obj \ - $O\ResourceString.obj \ - $O\SystemInfo.obj \ - $O\Shell.obj \ - $O\Window.obj \ - -WIN_CTRL_OBJS = \ - $O\ComboBox.obj \ - $O\Dialog.obj \ - $O\ListView.obj \ - $O\PropertyPage.obj \ - $O\Window2.obj \ - -7ZIP_COMMON_OBJS = $(7ZIP_COMMON_OBJS) \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\MultiOutStream.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveName.obj \ - $O\ArchiveOpenCallback.obj \ - $O\Bench.obj \ - $O\CompressCall2.obj \ - $O\DefaultName.obj \ - $O\EnumDirItems.obj \ - $O\Extract.obj \ - $O\ExtractingFilePath.obj \ - $O\HashCalc.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - $O\PropIDUtils.obj \ - $O\SetProperties.obj \ - $O\SortUtils.obj \ - $O\TempFiles.obj \ - $O\Update.obj \ - $O\UpdateAction.obj \ - $O\UpdateCallback.obj \ - $O\UpdatePair.obj \ - $O\UpdateProduce.obj \ - $O\WorkDir.obj \ - $O\ZipRegistry.obj \ - -EXPLORER_OBJS = \ - $O\ContextMenu.obj \ - $O\MyMessages.obj \ - $O\RegistryContextMenu.obj \ - -GUI_OBJS = \ - $O\BenchmarkDialog.obj \ - $O\CompressDialog.obj \ - $O\ExtractDialog.obj \ - $O\ExtractGUI.obj \ - $O\HashGUI.obj \ - $O\UpdateCallbackGUI.obj \ - $O\UpdateCallbackGUI2.obj \ - $O\UpdateGUI.obj \ - - -!include "../../7zip.mak" +PROG = 7zFM.exe + +# CFLAGS = $(CFLAGS) -DZ7_LARGE_PAGES + +!include "../Format7zF/Arc.mak" + +!include "../../UI/FileManager/FM.mak" + +COMMON_OBJS = $(COMMON_OBJS) \ + $O\CommandLineParser.obj \ + $O\Lang.obj \ + $O\ListFileUtils.obj \ + $O\Random.obj \ + +WIN_OBJS = $(WIN_OBJS) \ + $O\Clipboard.obj \ + $O\CommonDialog.obj \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileLink.obj \ + $O\MemoryGlobal.obj \ + $O\MemoryLock.obj \ + $O\Menu.obj \ + $O\ProcessUtils.obj \ + $O\Registry.obj \ + $O\ResourceString.obj \ + $O\SystemInfo.obj \ + $O\Shell.obj \ + $O\Window.obj \ + +WIN_CTRL_OBJS = \ + $O\ComboBox.obj \ + $O\Dialog.obj \ + $O\ListView.obj \ + $O\PropertyPage.obj \ + $O\Window2.obj \ + +7ZIP_COMMON_OBJS = $(7ZIP_COMMON_OBJS) \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\MultiOutStream.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveName.obj \ + $O\ArchiveOpenCallback.obj \ + $O\Bench.obj \ + $O\CompressCall2.obj \ + $O\DefaultName.obj \ + $O\EnumDirItems.obj \ + $O\Extract.obj \ + $O\ExtractingFilePath.obj \ + $O\HashCalc.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + $O\PropIDUtils.obj \ + $O\SetProperties.obj \ + $O\SortUtils.obj \ + $O\TempFiles.obj \ + $O\Update.obj \ + $O\UpdateAction.obj \ + $O\UpdateCallback.obj \ + $O\UpdatePair.obj \ + $O\UpdateProduce.obj \ + $O\WorkDir.obj \ + $O\ZipRegistry.obj \ + +EXPLORER_OBJS = \ + $O\ContextMenu.obj \ + $O\MyMessages.obj \ + $O\RegistryContextMenu.obj \ + +GUI_OBJS = \ + $O\BenchmarkDialog.obj \ + $O\CompressDialog.obj \ + $O\ExtractDialog.obj \ + $O\ExtractGUI.obj \ + $O\HashGUI.obj \ + $O\UpdateCallbackGUI.obj \ + $O\UpdateCallbackGUI2.obj \ + $O\UpdateGUI.obj \ + + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Fm/resource.rc b/CPP/7zip/Bundles/Fm/resource.rc index b4830d6f0..ebc2f74bc 100644 --- a/CPP/7zip/Bundles/Fm/resource.rc +++ b/CPP/7zip/Bundles/Fm/resource.rc @@ -1,7 +1,7 @@ -#include "../../UI/FileManager/resource.rc" -#include "../../UI/GUI/resource2.rc" - -STRINGTABLE -BEGIN - 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs apfs" -END +#include "../../UI/FileManager/resource.rc" +#include "../../UI/GUI/resource2.rc" + +STRINGTABLE +BEGIN + 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs apfs" +END diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.cpp b/CPP/7zip/Bundles/Format7z/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7z/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7z/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.h b/CPP/7zip/Bundles/Format7z/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Format7z/StdAfx.h +++ b/CPP/7zip/Bundles/Format7z/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7z/makefile b/CPP/7zip/Bundles/Format7z/makefile index 032da526a..fe6f94dc2 100644 --- a/CPP/7zip/Bundles/Format7z/makefile +++ b/CPP/7zip/Bundles/Format7z/makefile @@ -1,148 +1,148 @@ -PROG = 7za.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) \ - -DZ7_DEFLATE_EXTRACT_ONLY \ - -DZ7_BZIP2_EXTRACT_ONLY \ - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\IntToString.obj \ - $O\LzFindPrepare.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\Sha256Reg.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\InBuffer.obj \ - $O\InOutTempBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\HandlerOut.obj \ - $O\InStreamWithCRC.obj \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zEncode.obj \ - $O\7zExtract.obj \ - $O\7zFolderInStream.obj \ - $O\7zHandler.obj \ - $O\7zHandlerOut.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zOut.obj \ - $O\7zProperties.obj \ - $O\7zSpecStream.obj \ - $O\7zUpdate.obj \ - $O\7zRegister.obj \ - - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BitlDecoder.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\BZip2Crc.obj \ - $O\BZip2Decoder.obj \ - $O\BZip2Register.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeflateDecoder.obj \ - $O\DeflateRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Encoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaEncoder.obj \ - $O\LzmaRegister.obj \ - $O\LzOutWindow.obj \ - $O\PpmdDecoder.obj \ - $O\PpmdEncoder.obj \ - $O\PpmdRegister.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\MyAes.obj \ - $O\MyAesReg.obj \ - $O\RandGen.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bcj2Enc.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\BwtSort.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\HuffEnc.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\Lzma2Enc.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\MtCoder.obj \ - $O\MtDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - $O\Ppmd7Enc.obj \ - $O\Sort.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../LzFindOpt.mak" -!include "../../LzmaDec.mak" -!include "../../Sha256.mak" - -!include "../../7zip.mak" +PROG = 7za.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) \ + -DZ7_DEFLATE_EXTRACT_ONLY \ + -DZ7_BZIP2_EXTRACT_ONLY \ + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\IntToString.obj \ + $O\LzFindPrepare.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\Sha256Reg.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\InBuffer.obj \ + $O\InOutTempBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\HandlerOut.obj \ + $O\InStreamWithCRC.obj \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zEncode.obj \ + $O\7zExtract.obj \ + $O\7zFolderInStream.obj \ + $O\7zHandler.obj \ + $O\7zHandlerOut.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zOut.obj \ + $O\7zProperties.obj \ + $O\7zSpecStream.obj \ + $O\7zUpdate.obj \ + $O\7zRegister.obj \ + + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BitlDecoder.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\BZip2Crc.obj \ + $O\BZip2Decoder.obj \ + $O\BZip2Register.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeflateDecoder.obj \ + $O\DeflateRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Encoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaEncoder.obj \ + $O\LzmaRegister.obj \ + $O\LzOutWindow.obj \ + $O\PpmdDecoder.obj \ + $O\PpmdEncoder.obj \ + $O\PpmdRegister.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\MyAes.obj \ + $O\MyAesReg.obj \ + $O\RandGen.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bcj2Enc.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\BwtSort.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\HuffEnc.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\Lzma2Enc.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\MtCoder.obj \ + $O\MtDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + $O\Ppmd7Enc.obj \ + $O\Sort.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../LzFindOpt.mak" +!include "../../LzmaDec.mak" +!include "../../Sha256.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7z/resource.rc b/CPP/7zip/Bundles/Format7z/resource.rc index 53d6be065..2f2b42aee 100644 --- a/CPP/7zip/Bundles/Format7z/resource.rc +++ b/CPP/7zip/Bundles/Format7z/resource.rc @@ -1,5 +1,5 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Standalone Plugin", "7za") - -101 ICON "../../Archive/Icons/7z.ico" +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_DLL("7z Standalone Plugin", "7za") + +101 ICON "../../Archive/Icons/7z.ico" diff --git a/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp b/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7zExtract/StdAfx.h b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Format7zExtract/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zExtract/makefile b/CPP/7zip/Bundles/Format7zExtract/makefile index 2850ef39a..4e2ed3e80 100644 --- a/CPP/7zip/Bundles/Format7zExtract/makefile +++ b/CPP/7zip/Bundles/Format7zExtract/makefile @@ -1,116 +1,116 @@ -PROG = 7zxa.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) \ - -DZ7_EXTRACT_ONLY \ - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\IntToString.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\NewHandler.obj \ - $O\Sha256Reg.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\PropVariant.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\InBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\HandlerOut.obj \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zExtract.obj \ - $O\7zHandler.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zProperties.obj \ - $O\7zRegister.obj \ - - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BitlDecoder.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\BZip2Crc.obj \ - $O\BZip2Decoder.obj \ - $O\BZip2Register.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeflateDecoder.obj \ - $O\DeflateRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaRegister.obj \ - $O\LzOutWindow.obj \ - $O\PpmdDecoder.obj \ - $O\PpmdRegister.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\MyAes.obj \ - $O\MyAesReg.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\LzmaDec.obj \ - $O\MtDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../LzmaDec.mak" -!include "../../Sha256.mak" - -!include "../../7zip.mak" +PROG = 7zxa.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) \ + -DZ7_EXTRACT_ONLY \ + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\IntToString.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\NewHandler.obj \ + $O\Sha256Reg.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\PropVariant.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\InBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\HandlerOut.obj \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zExtract.obj \ + $O\7zHandler.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zProperties.obj \ + $O\7zRegister.obj \ + + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BitlDecoder.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\BZip2Crc.obj \ + $O\BZip2Decoder.obj \ + $O\BZip2Register.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeflateDecoder.obj \ + $O\DeflateRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaRegister.obj \ + $O\LzOutWindow.obj \ + $O\PpmdDecoder.obj \ + $O\PpmdRegister.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\MyAes.obj \ + $O\MyAesReg.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\LzmaDec.obj \ + $O\MtDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../LzmaDec.mak" +!include "../../Sha256.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7zExtract/resource.rc b/CPP/7zip/Bundles/Format7zExtract/resource.rc index e85e7e95e..6a654615c 100644 --- a/CPP/7zip/Bundles/Format7zExtract/resource.rc +++ b/CPP/7zip/Bundles/Format7zExtract/resource.rc @@ -1,5 +1,5 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Standalone Extracting Plugin", "7zxa") - -101 ICON "../../Archive/Icons/7z.ico" +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_DLL("7z Standalone Extracting Plugin", "7zxa") + +101 ICON "../../Archive/Icons/7z.ico" diff --git a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zExtractR/makefile b/CPP/7zip/Bundles/Format7zExtractR/makefile index 8ba33c227..50b84d879 100644 --- a/CPP/7zip/Bundles/Format7zExtractR/makefile +++ b/CPP/7zip/Bundles/Format7zExtractR/makefile @@ -1,98 +1,98 @@ -PROG = 7zxr.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) \ - -DZ7_EXTRACT_ONLY \ - -DZ7_NO_CRYPTO - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\IntToString.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\PropVariant.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\InBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\HandlerOut.obj \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zExtract.obj \ - $O\7zHandler.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zProperties.obj \ - $O\7zRegister.obj \ - - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaRegister.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\LzmaDec.obj \ - $O\MtDec.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" -!include "../../LzmaDec.mak" - -!include "../../7zip.mak" +PROG = 7zxr.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) \ + -DZ7_EXTRACT_ONLY \ + -DZ7_NO_CRYPTO + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\PropVariant.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\InBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\HandlerOut.obj \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zExtract.obj \ + $O\7zHandler.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zProperties.obj \ + $O\7zRegister.obj \ + + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaRegister.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\LzmaDec.obj \ + $O\MtDec.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" +!include "../../LzmaDec.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7zExtractR/resource.rc b/CPP/7zip/Bundles/Format7zExtractR/resource.rc index dac02a676..149f58c48 100644 --- a/CPP/7zip/Bundles/Format7zExtractR/resource.rc +++ b/CPP/7zip/Bundles/Format7zExtractR/resource.rc @@ -1,5 +1,5 @@ -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7z Extracting Reduced Standalone Plugin", "7zxr") - -101 ICON "../../Archive/Icons/7z.ico" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7z Extracting Reduced Standalone Plugin", "7zxr") + +101 ICON "../../Archive/Icons/7z.ico" diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak index d143c4ebf..7166ab3b3 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc.mak @@ -1,302 +1,310 @@ -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\LzFindPrepare.obj \ - $O\MyMap.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\MyXml.obj \ - $O\NewHandler.obj \ - $O\Sha1Reg.obj \ - $O\Sha256Reg.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - $O\Xxh64Reg.obj \ - $O\XzCrc64Init.obj \ - $O\XzCrc64Reg.obj \ - -WIN_OBJS = \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\PropVariantUtils.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\InBuffer.obj \ - $O\InOutTempBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\LockedStream.obj \ - $O\MemBlocks.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\OffsetStream.obj \ - $O\OutBuffer.obj \ - $O\OutMemStream.obj \ - $O\ProgressMt.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\ApfsHandler.obj \ - $O\ApmHandler.obj \ - $O\ArHandler.obj \ - $O\ArjHandler.obj \ - $O\Base64Handler.obj \ - $O\Bz2Handler.obj \ - $O\ComHandler.obj \ - $O\CpioHandler.obj \ - $O\CramfsHandler.obj \ - $O\DeflateProps.obj \ - $O\DmgHandler.obj \ - $O\ElfHandler.obj \ - $O\ExtHandler.obj \ - $O\FatHandler.obj \ - $O\FlvHandler.obj \ - $O\GzHandler.obj \ - $O\GptHandler.obj \ - $O\HandlerCont.obj \ - $O\HfsHandler.obj \ - $O\IhexHandler.obj \ - $O\LpHandler.obj \ - $O\LzhHandler.obj \ - $O\LzmaHandler.obj \ - $O\MachoHandler.obj \ - $O\MbrHandler.obj \ - $O\MslzHandler.obj \ - $O\MubHandler.obj \ - $O\NtfsHandler.obj \ - $O\PeHandler.obj \ - $O\PpmdHandler.obj \ - $O\QcowHandler.obj \ - $O\RpmHandler.obj \ - $O\SparseHandler.obj \ - $O\SplitHandler.obj \ - $O\SquashfsHandler.obj \ - $O\SwfHandler.obj \ - $O\UefiHandler.obj \ - $O\VdiHandler.obj \ - $O\VhdHandler.obj \ - $O\VhdxHandler.obj \ - $O\VmdkHandler.obj \ - $O\XarHandler.obj \ - $O\XzHandler.obj \ - $O\ZHandler.obj \ - $O\ZstdHandler.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\DummyOutStream.obj \ - $O\FindSignature.obj \ - $O\InStreamWithCRC.obj \ - $O\ItemNameUtils.obj \ - $O\MultiStream.obj \ - $O\OutStreamWithCRC.obj \ - $O\OutStreamWithSha1.obj \ - $O\HandlerOut.obj \ - $O\ParseProperties.obj \ - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zEncode.obj \ - $O\7zExtract.obj \ - $O\7zFolderInStream.obj \ - $O\7zHandler.obj \ - $O\7zHandlerOut.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zOut.obj \ - $O\7zProperties.obj \ - $O\7zSpecStream.obj \ - $O\7zUpdate.obj \ - $O\7zRegister.obj \ - -CAB_OBJS = \ - $O\CabBlockInStream.obj \ - $O\CabHandler.obj \ - $O\CabHeader.obj \ - $O\CabIn.obj \ - $O\CabRegister.obj \ - -CHM_OBJS = \ - $O\ChmHandler.obj \ - $O\ChmIn.obj \ - -ISO_OBJS = \ - $O\IsoHandler.obj \ - $O\IsoHeader.obj \ - $O\IsoIn.obj \ - $O\IsoRegister.obj \ - -NSIS_OBJS = \ - $O\NsisDecode.obj \ - $O\NsisHandler.obj \ - $O\NsisIn.obj \ - $O\NsisRegister.obj \ - -RAR_OBJS = \ - $O\RarHandler.obj \ - $O\Rar5Handler.obj \ - -TAR_OBJS = \ - $O\TarHandler.obj \ - $O\TarHandlerOut.obj \ - $O\TarHeader.obj \ - $O\TarIn.obj \ - $O\TarOut.obj \ - $O\TarUpdate.obj \ - $O\TarRegister.obj \ - -UDF_OBJS = \ - $O\UdfHandler.obj \ - $O\UdfIn.obj \ - -WIM_OBJS = \ - $O\WimHandler.obj \ - $O\WimHandlerOut.obj \ - $O\WimIn.obj \ - $O\WimRegister.obj \ - -ZIP_OBJS = \ - $O\ZipAddCommon.obj \ - $O\ZipHandler.obj \ - $O\ZipHandlerOut.obj \ - $O\ZipIn.obj \ - $O\ZipItem.obj \ - $O\ZipOut.obj \ - $O\ZipUpdate.obj \ - $O\ZipRegister.obj \ - -COMPRESS_OBJS = \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BitlDecoder.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\BZip2Crc.obj \ - $O\BZip2Decoder.obj \ - $O\BZip2Encoder.obj \ - $O\BZip2Register.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\Deflate64Register.obj \ - $O\DeflateDecoder.obj \ - $O\DeflateEncoder.obj \ - $O\DeflateRegister.obj \ - $O\DeltaFilter.obj \ - $O\ImplodeDecoder.obj \ - $O\LzfseDecoder.obj \ - $O\LzhDecoder.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Encoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaEncoder.obj \ - $O\LzmaRegister.obj \ - $O\LzmsDecoder.obj \ - $O\LzOutWindow.obj \ - $O\LzxDecoder.obj \ - $O\PpmdDecoder.obj \ - $O\PpmdEncoder.obj \ - $O\PpmdRegister.obj \ - $O\PpmdZip.obj \ - $O\QuantumDecoder.obj \ - $O\Rar1Decoder.obj \ - $O\Rar2Decoder.obj \ - $O\Rar3Decoder.obj \ - $O\Rar3Vm.obj \ - $O\Rar5Decoder.obj \ - $O\RarCodecsRegister.obj \ - $O\ShrinkDecoder.obj \ - $O\XpressDecoder.obj \ - $O\XzDecoder.obj \ - $O\XzEncoder.obj \ - $O\ZlibDecoder.obj \ - $O\ZlibEncoder.obj \ - $O\ZDecoder.obj \ - $O\ZstdDecoder.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\HmacSha1.obj \ - $O\HmacSha256.obj \ - $O\MyAes.obj \ - $O\MyAesReg.obj \ - $O\Pbkdf2HmacSha1.obj \ - $O\RandGen.obj \ - $O\Rar20Crypto.obj \ - $O\Rar5Aes.obj \ - $O\RarAes.obj \ - $O\WzAes.obj \ - $O\ZipCrypto.obj \ - $O\ZipStrong.obj \ - -C_OBJS = \ - $O\7zBuf2.obj \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bcj2Enc.obj \ - $O\Blake2s.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\BwtSort.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\HuffEnc.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\Lzma2Enc.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\MtCoder.obj \ - $O\MtDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - $O\Ppmd7aDec.obj \ - $O\Ppmd7Enc.obj \ - $O\Ppmd8.obj \ - $O\Ppmd8Dec.obj \ - $O\Ppmd8Enc.obj \ - $O\Sort.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - $O\Xxh64.obj \ - $O\Xz.obj \ - $O\XzDec.obj \ - $O\XzEnc.obj \ - $O\XzIn.obj \ - $O\ZstdDec.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../Crc64.mak" -!include "../../LzFindOpt.mak" -!include "../../LzmaDec.mak" -!include "../../Sha1.mak" -!include "../../Sha256.mak" +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\LzFindPrepare.obj \ + $O\Md5Reg.obj \ + $O\MyMap.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\MyXml.obj \ + $O\NewHandler.obj \ + $O\Sha1Reg.obj \ + $O\Sha256Reg.obj \ + $O\Sha3Reg.obj \ + $O\Sha512Reg.obj \ + $O\Sha512Prepare.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + $O\Xxh64Reg.obj \ + $O\XzCrc64Init.obj \ + $O\XzCrc64Reg.obj \ + +WIN_OBJS = \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\PropVariantUtils.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\InBuffer.obj \ + $O\InOutTempBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\LockedStream.obj \ + $O\MemBlocks.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\OffsetStream.obj \ + $O\OutBuffer.obj \ + $O\OutMemStream.obj \ + $O\ProgressMt.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\ApfsHandler.obj \ + $O\ApmHandler.obj \ + $O\ArHandler.obj \ + $O\ArjHandler.obj \ + $O\Base64Handler.obj \ + $O\Bz2Handler.obj \ + $O\ComHandler.obj \ + $O\CpioHandler.obj \ + $O\CramfsHandler.obj \ + $O\DeflateProps.obj \ + $O\DmgHandler.obj \ + $O\ElfHandler.obj \ + $O\ExtHandler.obj \ + $O\FatHandler.obj \ + $O\FlvHandler.obj \ + $O\GzHandler.obj \ + $O\GptHandler.obj \ + $O\HandlerCont.obj \ + $O\HfsHandler.obj \ + $O\IhexHandler.obj \ + $O\LpHandler.obj \ + $O\LzhHandler.obj \ + $O\LzmaHandler.obj \ + $O\MachoHandler.obj \ + $O\MbrHandler.obj \ + $O\MslzHandler.obj \ + $O\MubHandler.obj \ + $O\NtfsHandler.obj \ + $O\PeHandler.obj \ + $O\PpmdHandler.obj \ + $O\QcowHandler.obj \ + $O\RpmHandler.obj \ + $O\SparseHandler.obj \ + $O\SplitHandler.obj \ + $O\SquashfsHandler.obj \ + $O\SwfHandler.obj \ + $O\UefiHandler.obj \ + $O\VdiHandler.obj \ + $O\VhdHandler.obj \ + $O\VhdxHandler.obj \ + $O\VmdkHandler.obj \ + $O\XarHandler.obj \ + $O\XzHandler.obj \ + $O\ZHandler.obj \ + $O\ZstdHandler.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\DummyOutStream.obj \ + $O\FindSignature.obj \ + $O\InStreamWithCRC.obj \ + $O\ItemNameUtils.obj \ + $O\MultiStream.obj \ + $O\OutStreamWithCRC.obj \ + $O\OutStreamWithSha1.obj \ + $O\HandlerOut.obj \ + $O\ParseProperties.obj \ + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zEncode.obj \ + $O\7zExtract.obj \ + $O\7zFolderInStream.obj \ + $O\7zHandler.obj \ + $O\7zHandlerOut.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zOut.obj \ + $O\7zProperties.obj \ + $O\7zSpecStream.obj \ + $O\7zUpdate.obj \ + $O\7zRegister.obj \ + +CAB_OBJS = \ + $O\CabBlockInStream.obj \ + $O\CabHandler.obj \ + $O\CabHeader.obj \ + $O\CabIn.obj \ + $O\CabRegister.obj \ + +CHM_OBJS = \ + $O\ChmHandler.obj \ + $O\ChmIn.obj \ + +ISO_OBJS = \ + $O\IsoHandler.obj \ + $O\IsoHeader.obj \ + $O\IsoIn.obj \ + $O\IsoRegister.obj \ + +NSIS_OBJS = \ + $O\NsisDecode.obj \ + $O\NsisHandler.obj \ + $O\NsisIn.obj \ + $O\NsisRegister.obj \ + +RAR_OBJS = \ + $O\RarHandler.obj \ + $O\Rar5Handler.obj \ + +TAR_OBJS = \ + $O\TarHandler.obj \ + $O\TarHandlerOut.obj \ + $O\TarHeader.obj \ + $O\TarIn.obj \ + $O\TarOut.obj \ + $O\TarUpdate.obj \ + $O\TarRegister.obj \ + +UDF_OBJS = \ + $O\UdfHandler.obj \ + $O\UdfIn.obj \ + +WIM_OBJS = \ + $O\WimHandler.obj \ + $O\WimHandlerOut.obj \ + $O\WimIn.obj \ + $O\WimRegister.obj \ + +ZIP_OBJS = \ + $O\ZipAddCommon.obj \ + $O\ZipHandler.obj \ + $O\ZipHandlerOut.obj \ + $O\ZipIn.obj \ + $O\ZipItem.obj \ + $O\ZipOut.obj \ + $O\ZipUpdate.obj \ + $O\ZipRegister.obj \ + +COMPRESS_OBJS = \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BitlDecoder.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\BZip2Crc.obj \ + $O\BZip2Decoder.obj \ + $O\BZip2Encoder.obj \ + $O\BZip2Register.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\Deflate64Register.obj \ + $O\DeflateDecoder.obj \ + $O\DeflateEncoder.obj \ + $O\DeflateRegister.obj \ + $O\DeltaFilter.obj \ + $O\ImplodeDecoder.obj \ + $O\LzfseDecoder.obj \ + $O\LzhDecoder.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Encoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaEncoder.obj \ + $O\LzmaRegister.obj \ + $O\LzmsDecoder.obj \ + $O\LzOutWindow.obj \ + $O\LzxDecoder.obj \ + $O\PpmdDecoder.obj \ + $O\PpmdEncoder.obj \ + $O\PpmdRegister.obj \ + $O\PpmdZip.obj \ + $O\QuantumDecoder.obj \ + $O\Rar1Decoder.obj \ + $O\Rar2Decoder.obj \ + $O\Rar3Decoder.obj \ + $O\Rar3Vm.obj \ + $O\Rar5Decoder.obj \ + $O\RarCodecsRegister.obj \ + $O\ShrinkDecoder.obj \ + $O\XpressDecoder.obj \ + $O\XzDecoder.obj \ + $O\XzEncoder.obj \ + $O\ZlibDecoder.obj \ + $O\ZlibEncoder.obj \ + $O\ZDecoder.obj \ + $O\ZstdDecoder.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\HmacSha1.obj \ + $O\HmacSha256.obj \ + $O\MyAes.obj \ + $O\MyAesReg.obj \ + $O\Pbkdf2HmacSha1.obj \ + $O\RandGen.obj \ + $O\Rar20Crypto.obj \ + $O\Rar5Aes.obj \ + $O\RarAes.obj \ + $O\WzAes.obj \ + $O\ZipCrypto.obj \ + $O\ZipStrong.obj \ + +C_OBJS = \ + $O\7zBuf2.obj \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bcj2Enc.obj \ + $O\Blake2s.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\BwtSort.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\HuffEnc.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\Lzma2Enc.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\Md5.obj \ + $O\MtCoder.obj \ + $O\MtDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + $O\Ppmd7aDec.obj \ + $O\Ppmd7Enc.obj \ + $O\Ppmd8.obj \ + $O\Ppmd8Dec.obj \ + $O\Ppmd8Enc.obj \ + $O\Sha3.obj \ + $O\Sha512.obj \ + $O\Sha512Opt.obj \ + $O\Sort.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + $O\Xxh64.obj \ + $O\Xz.obj \ + $O\XzDec.obj \ + $O\XzEnc.obj \ + $O\XzIn.obj \ + $O\ZstdDec.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../Crc64.mak" +!include "../../LzFindOpt.mak" +!include "../../LzmaDec.mak" +!include "../../Sha1.mak" +!include "../../Sha256.mak" diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak index 66b225502..746aaff29 100644 --- a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak +++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak @@ -1,387 +1,395 @@ -include ../../LzmaDec_gcc.mak - -LOCAL_FLAGS_ST = -MT_OBJS = - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -ifdef ST_MODE - -LOCAL_FLAGS_ST = -DZ7_ST - -ifdef IS_MINGW -MT_OBJS = \ - $O/Threads.o \ - -endif - -else - -MT_OBJS = \ - $O/LzFindMt.o \ - $O/LzFindOpt.o \ - $O/Threads.o \ - $O/MemBlocks.o \ - $O/OutMemStream.o \ - $O/ProgressMt.o \ - $O/StreamBinder.o \ - $O/Synchronization.o \ - $O/VirtThread.o \ - -endif - - - -COMMON_OBJS = \ - $O/CRC.o \ - $O/CrcReg.o \ - $O/DynLimBuf.o \ - $O/IntToString.o \ - $O/LzFindPrepare.o \ - $O/MyMap.o \ - $O/MyString.o \ - $O/MyVector.o \ - $O/MyXml.o \ - $O/NewHandler.o \ - $O/Sha1Prepare.o \ - $O/Sha1Reg.o \ - $O/Sha256Prepare.o \ - $O/Sha256Reg.o \ - $O/StringConvert.o \ - $O/StringToInt.o \ - $O/UTFConvert.o \ - $O/Wildcard.o \ - $O/Xxh64Reg.o \ - $O/XzCrc64Init.o \ - $O/XzCrc64Reg.o \ - -WIN_OBJS = \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileIO.o \ - $O/FileName.o \ - $O/PropVariant.o \ - $O/PropVariantConv.o \ - $O/PropVariantUtils.o \ - $O/System.o \ - $O/TimeUtils.o \ - -7ZIP_COMMON_OBJS = \ - $O/CreateCoder.o \ - $O/CWrappers.o \ - $O/InBuffer.o \ - $O/InOutTempBuffer.o \ - $O/FilterCoder.o \ - $O/LimitedStreams.o \ - $O/LockedStream.o \ - $O/MethodId.o \ - $O/MethodProps.o \ - $O/OffsetStream.o \ - $O/OutBuffer.o \ - $O/ProgressUtils.o \ - $O/PropId.o \ - $O/StreamObjects.o \ - $O/StreamUtils.o \ - $O/UniqBlocks.o \ - -AR_OBJS = \ - $O/ApfsHandler.o \ - $O/ApmHandler.o \ - $O/ArHandler.o \ - $O/ArjHandler.o \ - $O/Base64Handler.o \ - $O/Bz2Handler.o \ - $O/ComHandler.o \ - $O/CpioHandler.o \ - $O/CramfsHandler.o \ - $O/DeflateProps.o \ - $O/DmgHandler.o \ - $O/ElfHandler.o \ - $O/ExtHandler.o \ - $O/FatHandler.o \ - $O/FlvHandler.o \ - $O/GzHandler.o \ - $O/GptHandler.o \ - $O/HandlerCont.o \ - $O/HfsHandler.o \ - $O/IhexHandler.o \ - $O/LpHandler.o \ - $O/LzhHandler.o \ - $O/LzmaHandler.o \ - $O/MachoHandler.o \ - $O/MbrHandler.o \ - $O/MslzHandler.o \ - $O/MubHandler.o \ - $O/NtfsHandler.o \ - $O/PeHandler.o \ - $O/PpmdHandler.o \ - $O/QcowHandler.o \ - $O/RpmHandler.o \ - $O/SparseHandler.o \ - $O/SplitHandler.o \ - $O/SquashfsHandler.o \ - $O/SwfHandler.o \ - $O/UefiHandler.o \ - $O/VdiHandler.o \ - $O/VhdHandler.o \ - $O/VhdxHandler.o \ - $O/VmdkHandler.o \ - $O/XarHandler.o \ - $O/XzHandler.o \ - $O/ZHandler.o \ - $O/ZstdHandler.o \ - -# $O/AvbHandler.o -# $O/LvmHandler.o - -AR_COMMON_OBJS = \ - $O/CoderMixer2.o \ - $O/DummyOutStream.o \ - $O/FindSignature.o \ - $O/InStreamWithCRC.o \ - $O/ItemNameUtils.o \ - $O/MultiStream.o \ - $O/OutStreamWithCRC.o \ - $O/OutStreamWithSha1.o \ - $O/HandlerOut.o \ - $O/ParseProperties.o \ - - -7Z_OBJS = \ - $O/7zCompressionMode.o \ - $O/7zDecode.o \ - $O/7zEncode.o \ - $O/7zExtract.o \ - $O/7zFolderInStream.o \ - $O/7zHandler.o \ - $O/7zHandlerOut.o \ - $O/7zHeader.o \ - $O/7zIn.o \ - $O/7zOut.o \ - $O/7zProperties.o \ - $O/7zSpecStream.o \ - $O/7zUpdate.o \ - $O/7zRegister.o \ - -CAB_OBJS = \ - $O/CabBlockInStream.o \ - $O/CabHandler.o \ - $O/CabHeader.o \ - $O/CabIn.o \ - $O/CabRegister.o \ - -CHM_OBJS = \ - $O/ChmHandler.o \ - $O/ChmIn.o \ - -ISO_OBJS = \ - $O/IsoHandler.o \ - $O/IsoHeader.o \ - $O/IsoIn.o \ - $O/IsoRegister.o \ - -NSIS_OBJS = \ - $O/NsisDecode.o \ - $O/NsisHandler.o \ - $O/NsisIn.o \ - $O/NsisRegister.o \ - -ifndef DISABLE_RAR -RAR_OBJS = \ - $O/RarHandler.o \ - $O/Rar5Handler.o \ - -endif - - -TAR_OBJS = \ - $O/TarHandler.o \ - $O/TarHandlerOut.o \ - $O/TarHeader.o \ - $O/TarIn.o \ - $O/TarOut.o \ - $O/TarUpdate.o \ - $O/TarRegister.o \ - -UDF_OBJS = \ - $O/UdfHandler.o \ - $O/UdfIn.o \ - -WIM_OBJS = \ - $O/WimHandler.o \ - $O/WimHandlerOut.o \ - $O/WimIn.o \ - $O/WimRegister.o \ - -ZIP_OBJS = \ - $O/ZipAddCommon.o \ - $O/ZipHandler.o \ - $O/ZipHandlerOut.o \ - $O/ZipIn.o \ - $O/ZipItem.o \ - $O/ZipOut.o \ - $O/ZipUpdate.o \ - $O/ZipRegister.o \ - -COMPRESS_OBJS = \ - $O/Bcj2Coder.o \ - $O/Bcj2Register.o \ - $O/BcjCoder.o \ - $O/BcjRegister.o \ - $O/BitlDecoder.o \ - $O/BranchMisc.o \ - $O/BranchRegister.o \ - $O/ByteSwap.o \ - $O/BZip2Crc.o \ - $O/BZip2Decoder.o \ - $O/BZip2Encoder.o \ - $O/BZip2Register.o \ - $O/CopyCoder.o \ - $O/CopyRegister.o \ - $O/Deflate64Register.o \ - $O/DeflateDecoder.o \ - $O/DeflateEncoder.o \ - $O/DeflateRegister.o \ - $O/DeltaFilter.o \ - $O/ImplodeDecoder.o \ - $O/LzfseDecoder.o \ - $O/LzhDecoder.o \ - $O/Lzma2Decoder.o \ - $O/Lzma2Encoder.o \ - $O/Lzma2Register.o \ - $O/LzmaDecoder.o \ - $O/LzmaEncoder.o \ - $O/LzmaRegister.o \ - $O/LzmsDecoder.o \ - $O/LzOutWindow.o \ - $O/LzxDecoder.o \ - $O/PpmdDecoder.o \ - $O/PpmdEncoder.o \ - $O/PpmdRegister.o \ - $O/PpmdZip.o \ - $O/QuantumDecoder.o \ - $O/ShrinkDecoder.o \ - $O/XpressDecoder.o \ - $O/XzDecoder.o \ - $O/XzEncoder.o \ - $O/ZlibDecoder.o \ - $O/ZlibEncoder.o \ - $O/ZDecoder.o \ - $O/ZstdDecoder.o \ - -ifdef DISABLE_RAR -DISABLE_RAR_COMPRESS=1 -endif - -ifndef DISABLE_RAR_COMPRESS -COMPRESS_OBJS += \ - $O/Rar1Decoder.o \ - $O/Rar2Decoder.o \ - $O/Rar3Decoder.o \ - $O/Rar3Vm.o \ - $O/Rar5Decoder.o \ - $O/RarCodecsRegister.o \ - -endif - -CRYPTO_OBJS = \ - $O/7zAes.o \ - $O/7zAesRegister.o \ - $O/HmacSha1.o \ - $O/HmacSha256.o \ - $O/MyAes.o \ - $O/MyAesReg.o \ - $O/Pbkdf2HmacSha1.o \ - $O/RandGen.o \ - $O/WzAes.o \ - $O/ZipCrypto.o \ - $O/ZipStrong.o \ - -ifndef DISABLE_RAR -CRYPTO_OBJS += \ - $O/Rar20Crypto.o \ - $O/Rar5Aes.o \ - $O/RarAes.o \ - -endif - - -C_OBJS = \ - $O/7zBuf2.o \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - $O/7zStream.o \ - $O/Aes.o \ - $O/AesOpt.o \ - $O/Alloc.o \ - $O/Bcj2.o \ - $O/Bcj2Enc.o \ - $O/Blake2s.o \ - $O/Bra.o \ - $O/Bra86.o \ - $O/BraIA64.o \ - $O/BwtSort.o \ - $O/CpuArch.o \ - $O/Delta.o \ - $O/HuffEnc.o \ - $O/LzFind.o \ - $O/Lzma2Dec.o \ - $O/Lzma2DecMt.o \ - $O/Lzma2Enc.o \ - $O/LzmaDec.o \ - $O/LzmaEnc.o \ - $O/MtCoder.o \ - $O/MtDec.o \ - $O/Ppmd7.o \ - $O/Ppmd7Dec.o \ - $O/Ppmd7aDec.o \ - $O/Ppmd7Enc.o \ - $O/Ppmd8.o \ - $O/Ppmd8Dec.o \ - $O/Ppmd8Enc.o \ - $O/Sha1.o \ - $O/Sha1Opt.o \ - $O/Sha256.o \ - $O/Sha256Opt.o \ - $O/Sort.o \ - $O/SwapBytes.o \ - $O/Xxh64.o \ - $O/Xz.o \ - $O/XzDec.o \ - $O/XzEnc.o \ - $O/XzIn.o \ - $O/XzCrc64.o \ - $O/XzCrc64Opt.o \ - $O/ZstdDec.o \ - -ARC_OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $(C_OBJS) \ - $(MT_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(AR_OBJS) \ - $(AR_COMMON_OBJS) \ - $(7Z_OBJS) \ - $(CAB_OBJS) \ - $(CHM_OBJS) \ - $(COM_OBJS) \ - $(ISO_OBJS) \ - $(NSIS_OBJS) \ - $(RAR_OBJS) \ - $(TAR_OBJS) \ - $(UDF_OBJS) \ - $(WIM_OBJS) \ - $(ZIP_OBJS) \ - $(COMPRESS_OBJS) \ - $(CRYPTO_OBJS) \ - -# we need empty line after last line above +include ../../LzmaDec_gcc.mak + +LOCAL_FLAGS_ST = +MT_OBJS = + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef ST_MODE + +LOCAL_FLAGS_ST = -DZ7_ST + +ifdef IS_MINGW +MT_OBJS = \ + $O/Threads.o \ + +endif + +else + +MT_OBJS = \ + $O/LzFindMt.o \ + $O/LzFindOpt.o \ + $O/Threads.o \ + $O/MemBlocks.o \ + $O/OutMemStream.o \ + $O/ProgressMt.o \ + $O/StreamBinder.o \ + $O/Synchronization.o \ + $O/VirtThread.o \ + +endif + + + +COMMON_OBJS = \ + $O/CRC.o \ + $O/CrcReg.o \ + $O/DynLimBuf.o \ + $O/IntToString.o \ + $O/LzFindPrepare.o \ + $O/Md5Reg.o \ + $O/MyMap.o \ + $O/MyString.o \ + $O/MyVector.o \ + $O/MyXml.o \ + $O/NewHandler.o \ + $O/Sha1Prepare.o \ + $O/Sha1Reg.o \ + $O/Sha256Prepare.o \ + $O/Sha256Reg.o \ + $O/Sha3Reg.o \ + $O/Sha512Prepare.o \ + $O/Sha512Reg.o \ + $O/StringConvert.o \ + $O/StringToInt.o \ + $O/UTFConvert.o \ + $O/Wildcard.o \ + $O/Xxh64Reg.o \ + $O/XzCrc64Init.o \ + $O/XzCrc64Reg.o \ + +WIN_OBJS = \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileIO.o \ + $O/FileName.o \ + $O/PropVariant.o \ + $O/PropVariantConv.o \ + $O/PropVariantUtils.o \ + $O/System.o \ + $O/TimeUtils.o \ + +7ZIP_COMMON_OBJS = \ + $O/CreateCoder.o \ + $O/CWrappers.o \ + $O/InBuffer.o \ + $O/InOutTempBuffer.o \ + $O/FilterCoder.o \ + $O/LimitedStreams.o \ + $O/LockedStream.o \ + $O/MethodId.o \ + $O/MethodProps.o \ + $O/OffsetStream.o \ + $O/OutBuffer.o \ + $O/ProgressUtils.o \ + $O/PropId.o \ + $O/StreamObjects.o \ + $O/StreamUtils.o \ + $O/UniqBlocks.o \ + +AR_OBJS = \ + $O/ApfsHandler.o \ + $O/ApmHandler.o \ + $O/ArHandler.o \ + $O/ArjHandler.o \ + $O/Base64Handler.o \ + $O/Bz2Handler.o \ + $O/ComHandler.o \ + $O/CpioHandler.o \ + $O/CramfsHandler.o \ + $O/DeflateProps.o \ + $O/DmgHandler.o \ + $O/ElfHandler.o \ + $O/ExtHandler.o \ + $O/FatHandler.o \ + $O/FlvHandler.o \ + $O/GzHandler.o \ + $O/GptHandler.o \ + $O/HandlerCont.o \ + $O/HfsHandler.o \ + $O/IhexHandler.o \ + $O/LpHandler.o \ + $O/LzhHandler.o \ + $O/LzmaHandler.o \ + $O/MachoHandler.o \ + $O/MbrHandler.o \ + $O/MslzHandler.o \ + $O/MubHandler.o \ + $O/NtfsHandler.o \ + $O/PeHandler.o \ + $O/PpmdHandler.o \ + $O/QcowHandler.o \ + $O/RpmHandler.o \ + $O/SparseHandler.o \ + $O/SplitHandler.o \ + $O/SquashfsHandler.o \ + $O/SwfHandler.o \ + $O/UefiHandler.o \ + $O/VdiHandler.o \ + $O/VhdHandler.o \ + $O/VhdxHandler.o \ + $O/VmdkHandler.o \ + $O/XarHandler.o \ + $O/XzHandler.o \ + $O/ZHandler.o \ + $O/ZstdHandler.o \ + +# $O/AvbHandler.o +# $O/LvmHandler.o + +AR_COMMON_OBJS = \ + $O/CoderMixer2.o \ + $O/DummyOutStream.o \ + $O/FindSignature.o \ + $O/InStreamWithCRC.o \ + $O/ItemNameUtils.o \ + $O/MultiStream.o \ + $O/OutStreamWithCRC.o \ + $O/OutStreamWithSha1.o \ + $O/HandlerOut.o \ + $O/ParseProperties.o \ + + +7Z_OBJS = \ + $O/7zCompressionMode.o \ + $O/7zDecode.o \ + $O/7zEncode.o \ + $O/7zExtract.o \ + $O/7zFolderInStream.o \ + $O/7zHandler.o \ + $O/7zHandlerOut.o \ + $O/7zHeader.o \ + $O/7zIn.o \ + $O/7zOut.o \ + $O/7zProperties.o \ + $O/7zSpecStream.o \ + $O/7zUpdate.o \ + $O/7zRegister.o \ + +CAB_OBJS = \ + $O/CabBlockInStream.o \ + $O/CabHandler.o \ + $O/CabHeader.o \ + $O/CabIn.o \ + $O/CabRegister.o \ + +CHM_OBJS = \ + $O/ChmHandler.o \ + $O/ChmIn.o \ + +ISO_OBJS = \ + $O/IsoHandler.o \ + $O/IsoHeader.o \ + $O/IsoIn.o \ + $O/IsoRegister.o \ + +NSIS_OBJS = \ + $O/NsisDecode.o \ + $O/NsisHandler.o \ + $O/NsisIn.o \ + $O/NsisRegister.o \ + +ifndef DISABLE_RAR +RAR_OBJS = \ + $O/RarHandler.o \ + $O/Rar5Handler.o \ + +endif + + +TAR_OBJS = \ + $O/TarHandler.o \ + $O/TarHandlerOut.o \ + $O/TarHeader.o \ + $O/TarIn.o \ + $O/TarOut.o \ + $O/TarUpdate.o \ + $O/TarRegister.o \ + +UDF_OBJS = \ + $O/UdfHandler.o \ + $O/UdfIn.o \ + +WIM_OBJS = \ + $O/WimHandler.o \ + $O/WimHandlerOut.o \ + $O/WimIn.o \ + $O/WimRegister.o \ + +ZIP_OBJS = \ + $O/ZipAddCommon.o \ + $O/ZipHandler.o \ + $O/ZipHandlerOut.o \ + $O/ZipIn.o \ + $O/ZipItem.o \ + $O/ZipOut.o \ + $O/ZipUpdate.o \ + $O/ZipRegister.o \ + +COMPRESS_OBJS = \ + $O/Bcj2Coder.o \ + $O/Bcj2Register.o \ + $O/BcjCoder.o \ + $O/BcjRegister.o \ + $O/BitlDecoder.o \ + $O/BranchMisc.o \ + $O/BranchRegister.o \ + $O/ByteSwap.o \ + $O/BZip2Crc.o \ + $O/BZip2Decoder.o \ + $O/BZip2Encoder.o \ + $O/BZip2Register.o \ + $O/CopyCoder.o \ + $O/CopyRegister.o \ + $O/Deflate64Register.o \ + $O/DeflateDecoder.o \ + $O/DeflateEncoder.o \ + $O/DeflateRegister.o \ + $O/DeltaFilter.o \ + $O/ImplodeDecoder.o \ + $O/LzfseDecoder.o \ + $O/LzhDecoder.o \ + $O/Lzma2Decoder.o \ + $O/Lzma2Encoder.o \ + $O/Lzma2Register.o \ + $O/LzmaDecoder.o \ + $O/LzmaEncoder.o \ + $O/LzmaRegister.o \ + $O/LzmsDecoder.o \ + $O/LzOutWindow.o \ + $O/LzxDecoder.o \ + $O/PpmdDecoder.o \ + $O/PpmdEncoder.o \ + $O/PpmdRegister.o \ + $O/PpmdZip.o \ + $O/QuantumDecoder.o \ + $O/ShrinkDecoder.o \ + $O/XpressDecoder.o \ + $O/XzDecoder.o \ + $O/XzEncoder.o \ + $O/ZlibDecoder.o \ + $O/ZlibEncoder.o \ + $O/ZDecoder.o \ + $O/ZstdDecoder.o \ + +ifdef DISABLE_RAR +DISABLE_RAR_COMPRESS=1 +endif + +ifndef DISABLE_RAR_COMPRESS +COMPRESS_OBJS += \ + $O/Rar1Decoder.o \ + $O/Rar2Decoder.o \ + $O/Rar3Decoder.o \ + $O/Rar3Vm.o \ + $O/Rar5Decoder.o \ + $O/RarCodecsRegister.o \ + +endif + +CRYPTO_OBJS = \ + $O/7zAes.o \ + $O/7zAesRegister.o \ + $O/HmacSha1.o \ + $O/HmacSha256.o \ + $O/MyAes.o \ + $O/MyAesReg.o \ + $O/Pbkdf2HmacSha1.o \ + $O/RandGen.o \ + $O/WzAes.o \ + $O/ZipCrypto.o \ + $O/ZipStrong.o \ + +ifndef DISABLE_RAR +CRYPTO_OBJS += \ + $O/Rar20Crypto.o \ + $O/Rar5Aes.o \ + $O/RarAes.o \ + +endif + + +C_OBJS = \ + $O/7zBuf2.o \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + $O/7zStream.o \ + $O/Aes.o \ + $O/AesOpt.o \ + $O/Alloc.o \ + $O/Bcj2.o \ + $O/Bcj2Enc.o \ + $O/Blake2s.o \ + $O/Bra.o \ + $O/Bra86.o \ + $O/BraIA64.o \ + $O/BwtSort.o \ + $O/CpuArch.o \ + $O/Delta.o \ + $O/HuffEnc.o \ + $O/LzFind.o \ + $O/Lzma2Dec.o \ + $O/Lzma2DecMt.o \ + $O/Lzma2Enc.o \ + $O/LzmaDec.o \ + $O/LzmaEnc.o \ + $O/Md5.o \ + $O/MtCoder.o \ + $O/MtDec.o \ + $O/Ppmd7.o \ + $O/Ppmd7Dec.o \ + $O/Ppmd7aDec.o \ + $O/Ppmd7Enc.o \ + $O/Ppmd8.o \ + $O/Ppmd8Dec.o \ + $O/Ppmd8Enc.o \ + $O/Sha1.o \ + $O/Sha1Opt.o \ + $O/Sha256.o \ + $O/Sha256Opt.o \ + $O/Sha3.o \ + $O/Sha512.o \ + $O/Sha512Opt.o \ + $O/Sort.o \ + $O/SwapBytes.o \ + $O/Xxh64.o \ + $O/Xz.o \ + $O/XzDec.o \ + $O/XzEnc.o \ + $O/XzIn.o \ + $O/XzCrc64.o \ + $O/XzCrc64Opt.o \ + $O/ZstdDec.o \ + +ARC_OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $(C_OBJS) \ + $(MT_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(AR_OBJS) \ + $(AR_COMMON_OBJS) \ + $(7Z_OBJS) \ + $(CAB_OBJS) \ + $(CHM_OBJS) \ + $(COM_OBJS) \ + $(ISO_OBJS) \ + $(NSIS_OBJS) \ + $(RAR_OBJS) \ + $(TAR_OBJS) \ + $(UDF_OBJS) \ + $(WIM_OBJS) \ + $(ZIP_OBJS) \ + $(COMPRESS_OBJS) \ + $(CRYPTO_OBJS) \ + +# we need empty line after last line above diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp index d1b09cc16..0bf976c7f 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsp +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp @@ -1,3334 +1,3426 @@ -# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=7z - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Format7z.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Format7z.mak" CFG="7z - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "7z - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_ST_9" /FAcs /Yu"StdAfx.h" /FD /GF /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\7z.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none /debug - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\SDK" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_ST_9" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7z.dll" /pdbtype:sept /ignore:4033 -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "7z - Win32 Release" -# Name "7z - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Group "Icons" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Icons\7z.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\arj.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\bz2.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\cab.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\cpio.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\deb.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\dmg.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\fat.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\gz.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\hfs.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\iso.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\lzh.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\lzma.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\ntfs.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\rar.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\rpm.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\split.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\squashfs.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\tar.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\vhd.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\wim.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\xar.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\xz.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\z.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\zip.ico -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Icons\zst.ico -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Archive\Archive2.def -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ArchiveExports.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CodecExports.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\DllExports2.cpp -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\AutoPtr.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common0.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CrcReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynamicBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\LzFindPrepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyException.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyLinux.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyMap.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyMap.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyUnknown.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyXml.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyXml.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha1Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha1Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Xxh64Reg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Init.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\XzCrc64Reg.cpp -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Group "Bit Coder" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\BitlDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitlDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitlEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitmDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BitmEncoder.h -# End Source File -# End Group -# Begin Group "Rar Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Rar1Decoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar1Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar2Decoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar3Decoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar3Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar3Vm.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar3Vm.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar5Decoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Rar5Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\RarCodecsRegister.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# End Group -# Begin Group "BZip2 Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\BZip2Const.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Crc.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Crc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Decoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Encoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Encoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BZip2Register.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Mtf8.h -# End Source File -# End Group -# Begin Group "Zip Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Deflate64Register.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateConst.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateEncoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeflateRegister.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ImplodeDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ImplodeDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdZip.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdZip.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ShrinkDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ShrinkDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZlibDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZlibDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZlibEncoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZlibEncoder.h -# End Source File -# End Group -# Begin Group "7z Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ByteSwap.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeltaFilter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Encoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdEncoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdRegister.cpp -# End Source File -# End Group -# Begin Group "Cab Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Lzx.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzxDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzxDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\QuantumDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\QuantumDecoder.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Compress\HuffmanDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzfseDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzfseDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzhDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzhDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmsDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmsDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzOutWindow.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzOutWindow.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XpressDecoder.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XpressDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\XzEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZstdDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\ZstdDecoder.h -# End Source File -# End Group -# Begin Group "Crypto" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAesRegister.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha1.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha256.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\HmacSha256.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAesReg.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Pbkdf2HmacSha1.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Pbkdf2HmacSha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RandGen.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RandGen.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Rar20Crypto.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Rar20Crypto.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Rar5Aes.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Rar5Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RarAes.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\RarAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\Sha1Cls.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\WzAes.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\WzAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipCrypto.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipCrypto.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipStrong.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\ZipStrong.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InOutTempBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MemBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MemBlocks.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodId.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutMemStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutMemStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressMt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterArc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterCodec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Group "xz" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\Xz.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /W4 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# ADD CPP /W4 /WX -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xz.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /W4 /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# ADD CPP /W4 /WX -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzCrc64Opt.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzDec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /W4 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# ADD CPP /W4 /WX -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzEnc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\XzIn.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /W4 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# ADD CPP /W4 /WX -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\..\C\7zBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zBuf2.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2Enc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Blake2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Blake2s.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BraIA64.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BwtSort.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BwtSort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\HuffEnc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\HuffEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindOpt.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Enc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7aDec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7Dec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7Enc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8Dec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd8Enc.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\RotateDefs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\SwapBytes.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\SwapBytes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xxh64.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Xxh64.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\ZstdDec.c - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\ZstdDec.h -# End Source File -# End Group -# Begin Group "Archive" - -# PROP Default_Filter "" -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zEncode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zFolderInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zProperties.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zSpecStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdate.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zUpdateItem.h -# End Source File -# End Group -# Begin Group "Rar" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Rar\Rar5Handler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Rar\Rar5Handler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Rar\RarHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Rar\RarHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Rar\RarHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Rar\RarItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Rar\RarVol.h -# End Source File -# End Group -# Begin Group "Cab" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabBlockInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabBlockInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Cab\CabRegister.cpp -# End Source File -# End Group -# Begin Group "Chm" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Chm\ChmHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Chm\ChmHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Chm\ChmIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Chm\ChmIn.h -# End Source File -# End Group -# Begin Group "Archive common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\DummyOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\FindSignature.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\FindSignature.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\InStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithSha1.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithSha1.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ParseProperties.h -# End Source File -# End Group -# Begin Group "Iso" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Iso\IsoRegister.cpp -# End Source File -# End Group -# Begin Group "Nsis" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Nsis\NsisRegister.cpp -# End Source File -# End Group -# Begin Group "Tar" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHeader.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Tar\TarUpdate.h -# End Source File -# End Group -# Begin Group "Zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipAddCommon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipAddCommon.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipCompressionMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipItem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipUpdate.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Zip\ZipUpdate.h -# End Source File -# End Group -# Begin Group "Wim" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Wim\WimHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Wim\WimHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Wim\WimHandlerOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Wim\WimIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Wim\WimIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Wim\WimRegister.cpp -# End Source File -# End Group -# Begin Group "Udf" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Udf\UdfHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Udf\UdfHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Udf\UdfIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Udf\UdfIn.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\Archive\ApfsHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ApmHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ArHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ArjHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Base64Handler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Bz2Handler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ComHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\CpioHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\CramfsHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\DeflateProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\DeflateProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\DmgHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ElfHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ExtHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\FatHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\FlvHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\GptHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\GzHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\HandlerCont.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\HandlerCont.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\HfsHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\HfsHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\IhexHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\LpHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\LzhHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\LzmaHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\MachoHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\MbrHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\MslzHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\MubHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\NtfsHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\PeHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\PpmdHandler.cpp - -!IF "$(CFG)" == "7z - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\QcowHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\RpmHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SparseHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SplitHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SquashfsHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SwfHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\UefiHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\VdiHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\VhdHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\VhdxHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\VmdkHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\XarHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\XzHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\XzHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ZHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\ZstdHandler.cpp -# End Source File -# End Group -# Begin Group "7zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\MyVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Handle.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "Asm" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\7zAsm.asm -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\7zCrcOpt.asm - -!IF "$(CFG)" == "7z - Win32 Release" - -# Begin Custom Build -OutDir=.\Release -InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm -InputName=7zCrcOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# Begin Custom Build -OutDir=.\Debug -InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm -InputName=7zCrcOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\AesOpt.asm - -!IF "$(CFG)" == "7z - Win32 Release" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build -OutDir=.\Release -InputPath=..\..\..\..\Asm\x86\AesOpt.asm -InputName=AesOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build -OutDir=.\Debug -InputPath=..\..\..\..\Asm\x86\AesOpt.asm -InputName=AesOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -omf -WX -W3 -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\Sha1Opt.asm - -!IF "$(CFG)" == "7z - Win32 Release" - -# Begin Custom Build -OutDir=.\Release -InputPath=..\..\..\..\Asm\x86\Sha1Opt.asm -InputName=Sha1Opt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# Begin Custom Build -OutDir=.\Debug -InputPath=..\..\..\..\Asm\x86\Sha1Opt.asm -InputName=Sha1Opt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\Sha256Opt.asm - -!IF "$(CFG)" == "7z - Win32 Release" - -# Begin Custom Build -OutDir=.\Release -InputPath=..\..\..\..\Asm\x86\Sha256Opt.asm -InputName=Sha256Opt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "7z - Win32 Debug" - -# Begin Custom Build -OutDir=.\Debug -InputPath=..\..\..\..\Asm\x86\Sha256Opt.asm -InputName=Sha256Opt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=7z - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Format7z.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Format7z.mak" CFG="7z - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "7z - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_ST_9" /FAcs /Yu"StdAfx.h" /FD /GF /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\7z.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none /debug + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\SDK" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_ST_9" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7z.dll" /pdbtype:sept /ignore:4033 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "7z - Win32 Release" +# Name "7z - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Group "Icons" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Icons\7z.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\arj.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\bz2.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\cab.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\cpio.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\deb.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\dmg.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\fat.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\gz.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\hfs.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\iso.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\lzh.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\lzma.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\ntfs.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\rar.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\rpm.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\split.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\squashfs.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\tar.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\vhd.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\wim.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\xar.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\xz.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\z.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\zip.ico +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Icons\zst.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Archive\Archive2.def +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ArchiveExports.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CodecExports.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\DllExports2.cpp +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\AutoPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common0.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CrcReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynamicBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\LzFindPrepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Md5Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyException.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyLinux.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyMap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyMap.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyUnknown.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyXml.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyXml.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha1Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha3Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha512Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha512Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Xxh64Reg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Init.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\XzCrc64Reg.cpp +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Group "Bit Coder" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\BitlDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitlDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitlEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitmDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BitmEncoder.h +# End Source File +# End Group +# Begin Group "Rar Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Rar1Decoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar1Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar2Decoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar3Decoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar3Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar3Vm.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar3Vm.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar5Decoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Rar5Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\RarCodecsRegister.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# End Group +# Begin Group "BZip2 Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\BZip2Const.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Crc.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Crc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Decoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Encoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Encoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BZip2Register.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Mtf8.h +# End Source File +# End Group +# Begin Group "Zip Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Deflate64Register.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateConst.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateEncoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeflateRegister.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ImplodeDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ImplodeDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdZip.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdZip.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ShrinkDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ShrinkDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZlibDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZlibDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZlibEncoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZlibEncoder.h +# End Source File +# End Group +# Begin Group "7z Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ByteSwap.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeltaFilter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Encoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdEncoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdRegister.cpp +# End Source File +# End Group +# Begin Group "Cab Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Lzx.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzxDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzxDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\QuantumDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\QuantumDecoder.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Compress\HuffmanDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzfseDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzfseDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzhDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzhDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmsDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmsDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzOutWindow.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzOutWindow.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XpressDecoder.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XpressDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\XzEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZstdDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\ZstdDecoder.h +# End Source File +# End Group +# Begin Group "Crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAesRegister.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha1.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha256.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\HmacSha256.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAesReg.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Pbkdf2HmacSha1.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Pbkdf2HmacSha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RandGen.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RandGen.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Rar20Crypto.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Rar20Crypto.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Rar5Aes.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Rar5Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RarAes.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\RarAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\Sha1Cls.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\WzAes.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\WzAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipCrypto.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipCrypto.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipStrong.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\ZipStrong.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InOutTempBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MemBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MemBlocks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodId.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutMemStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutMemStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressMt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterArc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterCodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Group "xz" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\Xz.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /W4 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# ADD CPP /W4 /WX +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xz.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /W4 /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# ADD CPP /W4 /WX +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzCrc64Opt.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzDec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /W4 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# ADD CPP /W4 /WX +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzEnc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\XzIn.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /W4 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# ADD CPP /W4 /WX +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\..\C\7zBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zBuf2.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2Enc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Blake2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Blake2s.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BraIA64.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BwtSort.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BwtSort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\HuffEnc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\HuffEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindOpt.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Enc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Md5.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Md5.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7aDec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7Dec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7Enc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8Dec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd8Enc.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\RotateDefs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha3.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha3.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha512.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha512.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha512Opt.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\SwapBytes.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\SwapBytes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xxh64.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Xxh64.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\ZstdDec.c + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\ZstdDec.h +# End Source File +# End Group +# Begin Group "Archive" + +# PROP Default_Filter "" +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zEncode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zProperties.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zSpecStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdate.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zUpdateItem.h +# End Source File +# End Group +# Begin Group "Rar" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Rar\Rar5Handler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Rar\Rar5Handler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Rar\RarHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Rar\RarHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Rar\RarHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Rar\RarItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Rar\RarVol.h +# End Source File +# End Group +# Begin Group "Cab" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabBlockInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabBlockInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Cab\CabRegister.cpp +# End Source File +# End Group +# Begin Group "Chm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Chm\ChmHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Chm\ChmHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Chm\ChmIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Chm\ChmIn.h +# End Source File +# End Group +# Begin Group "Archive common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\DummyOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FindSignature.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FindSignature.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\InStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithSha1.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithSha1.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ParseProperties.h +# End Source File +# End Group +# Begin Group "Iso" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Iso\IsoRegister.cpp +# End Source File +# End Group +# Begin Group "Nsis" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Nsis\NsisRegister.cpp +# End Source File +# End Group +# Begin Group "Tar" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Tar\TarUpdate.h +# End Source File +# End Group +# Begin Group "Zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipAddCommon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipAddCommon.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipCompressionMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipItem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipUpdate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Zip\ZipUpdate.h +# End Source File +# End Group +# Begin Group "Wim" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Wim\WimHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Wim\WimHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Wim\WimHandlerOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Wim\WimIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Wim\WimIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Wim\WimRegister.cpp +# End Source File +# End Group +# Begin Group "Udf" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Udf\UdfHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Udf\UdfHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Udf\UdfIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Udf\UdfIn.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\Archive\ApfsHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ApmHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ArHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ArjHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Base64Handler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Bz2Handler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ComHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\CpioHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\CramfsHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\DeflateProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\DeflateProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\DmgHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ElfHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ExtHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\FatHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\FlvHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\GptHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\GzHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\HandlerCont.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\HandlerCont.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\HfsHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\HfsHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\IhexHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\LpHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\LzhHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\LzmaHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\MachoHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\MbrHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\MslzHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\MubHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\NtfsHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\PeHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\PpmdHandler.cpp + +!IF "$(CFG)" == "7z - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\QcowHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\RpmHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SparseHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SplitHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SquashfsHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SwfHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\UefiHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\VdiHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\VhdHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\VhdxHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\VmdkHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\XarHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\XzHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\XzHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ZHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\ZstdHandler.cpp +# End Source File +# End Group +# Begin Group "7zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\MyVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Handle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "Asm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\7zAsm.asm +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\7zCrcOpt.asm + +!IF "$(CFG)" == "7z - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm +InputName=7zCrcOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# Begin Custom Build +OutDir=.\Debug +InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm +InputName=7zCrcOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\AesOpt.asm + +!IF "$(CFG)" == "7z - Win32 Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build +OutDir=.\Release +InputPath=..\..\..\..\Asm\x86\AesOpt.asm +InputName=AesOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build +OutDir=.\Debug +InputPath=..\..\..\..\Asm\x86\AesOpt.asm +InputName=AesOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -omf -WX -W3 -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\Sha1Opt.asm + +!IF "$(CFG)" == "7z - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=..\..\..\..\Asm\x86\Sha1Opt.asm +InputName=Sha1Opt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# Begin Custom Build +OutDir=.\Debug +InputPath=..\..\..\..\Asm\x86\Sha1Opt.asm +InputName=Sha1Opt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\Sha256Opt.asm + +!IF "$(CFG)" == "7z - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=..\..\..\..\Asm\x86\Sha256Opt.asm +InputName=Sha256Opt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "7z - Win32 Debug" + +# Begin Custom Build +OutDir=.\Debug +InputPath=..\..\..\..\Asm\x86\Sha256Opt.asm +InputName=Sha256Opt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsw b/CPP/7zip/Bundles/Format7zF/Format7z.dsw index bb68d2596..324dab1ff 100644 --- a/CPP/7zip/Bundles/Format7zF/Format7z.dsw +++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "7z"=.\Format7z.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "7z"=.\Format7z.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.cpp b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7zF/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.h b/CPP/7zip/Bundles/Format7zF/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Format7zF/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zF/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zF/makefile b/CPP/7zip/Bundles/Format7zF/makefile index 3765e7059..521c8cff1 100644 --- a/CPP/7zip/Bundles/Format7zF/makefile +++ b/CPP/7zip/Bundles/Format7zF/makefile @@ -1,21 +1,21 @@ -PROG = 7z.dll -# USE_C_LZFINDOPT = 1 -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) \ - -DZ7_EXTERNAL_CODECS \ - -!IFNDEF UNDER_CE -# CFLAGS = $(CFLAGS) -DZ7_LARGE_PAGES -!ENDIF - -!include "Arc.mak" - -COMPRESS_OBJS = $(COMPRESS_OBJS) \ - $O\CodecExports.obj \ - -AR_OBJS = $(AR_OBJS) \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - - -!include "../../7zip.mak" +PROG = 7z.dll +# USE_C_LZFINDOPT = 1 +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) \ + -DZ7_EXTERNAL_CODECS \ + +!IFNDEF UNDER_CE +# CFLAGS = $(CFLAGS) -DZ7_LARGE_PAGES +!ENDIF + +!include "Arc.mak" + +COMPRESS_OBJS = $(COMPRESS_OBJS) \ + $O\CodecExports.obj \ + +AR_OBJS = $(AR_OBJS) \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7zF/makefile.gcc b/CPP/7zip/Bundles/Format7zF/makefile.gcc index 63bc9ece1..cc23d0b14 100644 --- a/CPP/7zip/Bundles/Format7zF/makefile.gcc +++ b/CPP/7zip/Bundles/Format7zF/makefile.gcc @@ -1,57 +1,57 @@ -PROG = 7z -DEF_FILE = ../../Archive/Archive2.def - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - -include Arc_gcc.mak - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -LOCAL_FLAGS_SYS = - -ifdef IS_MINGW - -LOCAL_FLAGS_SYS = \ - $(LOCAL_FLAGS_ST) \ - -# -DZ7_LARGE_PAGES \ - -SYS_OBJS = \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - -endif - -LOCAL_FLAGS = \ - -DZ7_EXTERNAL_CODECS \ - $(LOCAL_FLAGS_SYS) \ - $(LOCAL_FLAGS_ST) \ - - -COMPRESS_OBJS_2 = \ - $O/CodecExports.o \ - -AR_OBJS_2 = \ - $O/ArchiveExports.o \ - $O/DllExports2.o \ - -OBJS = \ - $(ARC_OBJS) \ - $(AR_OBJS_2) \ - $(COMPRESS_OBJS_2) \ - $(SYS_OBJS) \ - -include ../../7zip_gcc.mak +PROG = 7z +DEF_FILE = ../../Archive/Archive2.def + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + +include Arc_gcc.mak + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +LOCAL_FLAGS_SYS = + +ifdef IS_MINGW + +LOCAL_FLAGS_SYS = \ + $(LOCAL_FLAGS_ST) \ + +# -DZ7_LARGE_PAGES \ + +SYS_OBJS = \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + +endif + +LOCAL_FLAGS = \ + -DZ7_EXTERNAL_CODECS \ + $(LOCAL_FLAGS_SYS) \ + $(LOCAL_FLAGS_ST) \ + + +COMPRESS_OBJS_2 = \ + $O/CodecExports.o \ + +AR_OBJS_2 = \ + $O/ArchiveExports.o \ + $O/DllExports2.o \ + +OBJS = \ + $(ARC_OBJS) \ + $(AR_OBJS_2) \ + $(COMPRESS_OBJS_2) \ + $(SYS_OBJS) \ + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/Bundles/Format7zF/resource.rc b/CPP/7zip/Bundles/Format7zF/resource.rc index 9391ce253..f2950c019 100644 --- a/CPP/7zip/Bundles/Format7zF/resource.rc +++ b/CPP/7zip/Bundles/Format7zF/resource.rc @@ -1,39 +1,39 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7z Plugin" , "7z") - - -0 ICON "../../Archive/Icons/7z.ico" -1 ICON "../../Archive/Icons/zip.ico" -2 ICON "../../Archive/Icons/bz2.ico" -3 ICON "../../Archive/Icons/rar.ico" -4 ICON "../../Archive/Icons/arj.ico" -5 ICON "../../Archive/Icons/z.ico" -6 ICON "../../Archive/Icons/lzh.ico" -7 ICON "../../Archive/Icons/cab.ico" -8 ICON "../../Archive/Icons/iso.ico" -9 ICON "../../Archive/Icons/split.ico" -10 ICON "../../Archive/Icons/rpm.ico" -11 ICON "../../Archive/Icons/deb.ico" -12 ICON "../../Archive/Icons/cpio.ico" -13 ICON "../../Archive/Icons/tar.ico" -14 ICON "../../Archive/Icons/gz.ico" -15 ICON "../../Archive/Icons/wim.ico" -16 ICON "../../Archive/Icons/lzma.ico" -17 ICON "../../Archive/Icons/dmg.ico" -18 ICON "../../Archive/Icons/hfs.ico" -19 ICON "../../Archive/Icons/xar.ico" -20 ICON "../../Archive/Icons/vhd.ico" -21 ICON "../../Archive/Icons/fat.ico" -22 ICON "../../Archive/Icons/ntfs.ico" -23 ICON "../../Archive/Icons/xz.ico" -24 ICON "../../Archive/Icons/squashfs.ico" -25 ICON "../../Archive/Icons/apfs.ico" -26 ICON "../../Archive/Icons/zst.ico" - - - -STRINGTABLE -BEGIN - 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 zst:26 tzst:26 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 apfs:25" -END +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_DLL("7z Plugin" , "7z") + + +0 ICON "../../Archive/Icons/7z.ico" +1 ICON "../../Archive/Icons/zip.ico" +2 ICON "../../Archive/Icons/bz2.ico" +3 ICON "../../Archive/Icons/rar.ico" +4 ICON "../../Archive/Icons/arj.ico" +5 ICON "../../Archive/Icons/z.ico" +6 ICON "../../Archive/Icons/lzh.ico" +7 ICON "../../Archive/Icons/cab.ico" +8 ICON "../../Archive/Icons/iso.ico" +9 ICON "../../Archive/Icons/split.ico" +10 ICON "../../Archive/Icons/rpm.ico" +11 ICON "../../Archive/Icons/deb.ico" +12 ICON "../../Archive/Icons/cpio.ico" +13 ICON "../../Archive/Icons/tar.ico" +14 ICON "../../Archive/Icons/gz.ico" +15 ICON "../../Archive/Icons/wim.ico" +16 ICON "../../Archive/Icons/lzma.ico" +17 ICON "../../Archive/Icons/dmg.ico" +18 ICON "../../Archive/Icons/hfs.ico" +19 ICON "../../Archive/Icons/xar.ico" +20 ICON "../../Archive/Icons/vhd.ico" +21 ICON "../../Archive/Icons/fat.ico" +22 ICON "../../Archive/Icons/ntfs.ico" +23 ICON "../../Archive/Icons/xz.ico" +24 ICON "../../Archive/Icons/squashfs.ico" +25 ICON "../../Archive/Icons/apfs.ico" +26 ICON "../../Archive/Icons/zst.ico" + + + +STRINGTABLE +BEGIN + 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 zst:26 tzst:26 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 apfs:25" +END diff --git a/CPP/7zip/Bundles/Format7zR/StdAfx.cpp b/CPP/7zip/Bundles/Format7zR/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/Format7zR/StdAfx.cpp +++ b/CPP/7zip/Bundles/Format7zR/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/Format7zR/StdAfx.h b/CPP/7zip/Bundles/Format7zR/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/Format7zR/StdAfx.h +++ b/CPP/7zip/Bundles/Format7zR/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/Format7zR/makefile b/CPP/7zip/Bundles/Format7zR/makefile index 9ab801489..326d043d6 100644 --- a/CPP/7zip/Bundles/Format7zR/makefile +++ b/CPP/7zip/Bundles/Format7zR/makefile @@ -1,121 +1,121 @@ -PROG = 7zra.dll -DEF_FILE = ../../Archive/Archive2.def -CFLAGS = $(CFLAGS) \ - -DZ7_NO_CRYPTO - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\IntToString.obj \ - $O\LzFindPrepare.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\InBuffer.obj \ - $O\InOutTempBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodId.obj \ - $O\MethodProps.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - $O\VirtThread.obj \ - -AR_OBJS = \ - $O\ArchiveExports.obj \ - $O\DllExports2.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\HandlerOut.obj \ - $O\InStreamWithCRC.obj \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - $O\ParseProperties.obj \ - - -7Z_OBJS = \ - $O\7zCompressionMode.obj \ - $O\7zDecode.obj \ - $O\7zEncode.obj \ - $O\7zExtract.obj \ - $O\7zFolderInStream.obj \ - $O\7zHandler.obj \ - $O\7zHandlerOut.obj \ - $O\7zHeader.obj \ - $O\7zIn.obj \ - $O\7zOut.obj \ - $O\7zProperties.obj \ - $O\7zSpecStream.obj \ - $O\7zUpdate.obj \ - $O\7zRegister.obj \ - - -COMPRESS_OBJS = \ - $O\CodecExports.obj \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\ByteSwap.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Encoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaEncoder.obj \ - $O\LzmaRegister.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bcj2Enc.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\Lzma2Enc.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\MtCoder.obj \ - $O\MtDec.obj \ - $O\SwapBytes.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" -!include "../../LzFindOpt.mak" -!include "../../LzmaDec.mak" - -!include "../../7zip.mak" +PROG = 7zra.dll +DEF_FILE = ../../Archive/Archive2.def +CFLAGS = $(CFLAGS) \ + -DZ7_NO_CRYPTO + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\IntToString.obj \ + $O\LzFindPrepare.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\InBuffer.obj \ + $O\InOutTempBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodId.obj \ + $O\MethodProps.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + $O\VirtThread.obj \ + +AR_OBJS = \ + $O\ArchiveExports.obj \ + $O\DllExports2.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\HandlerOut.obj \ + $O\InStreamWithCRC.obj \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + $O\ParseProperties.obj \ + + +7Z_OBJS = \ + $O\7zCompressionMode.obj \ + $O\7zDecode.obj \ + $O\7zEncode.obj \ + $O\7zExtract.obj \ + $O\7zFolderInStream.obj \ + $O\7zHandler.obj \ + $O\7zHandlerOut.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zOut.obj \ + $O\7zProperties.obj \ + $O\7zSpecStream.obj \ + $O\7zUpdate.obj \ + $O\7zRegister.obj \ + + +COMPRESS_OBJS = \ + $O\CodecExports.obj \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\ByteSwap.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Encoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaEncoder.obj \ + $O\LzmaRegister.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bcj2Enc.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\Lzma2Enc.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\MtCoder.obj \ + $O\MtDec.obj \ + $O\SwapBytes.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" +!include "../../LzFindOpt.mak" +!include "../../LzmaDec.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/Format7zR/resource.rc b/CPP/7zip/Bundles/Format7zR/resource.rc index 262125c12..a8baa596a 100644 --- a/CPP/7zip/Bundles/Format7zR/resource.rc +++ b/CPP/7zip/Bundles/Format7zR/resource.rc @@ -1,5 +1,5 @@ -#include "../../../../C/7zVersion.rc" - -MY_VERSION_INFO_DLL("7z Reduced Standalone Plugin", "7zr") - -101 ICON "../../Archive/Icons/7z.ico" +#include "../../../../C/7zVersion.rc" + +MY_VERSION_INFO_DLL("7z Reduced Standalone Plugin", "7zr") + +101 ICON "../../Archive/Icons/7z.ico" diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp index 8e7df552c..e43e8b1a3 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp @@ -1,808 +1,817 @@ - // LzmaAlone.cpp - -#include "StdAfx.h" - -// #include - -#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE) -#include -#include -#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY) -#else -#define MY_SET_BINARY_MODE(file) -#endif - -#include "../../../../C/CpuArch.h" -#include "../../../../C/7zVersion.h" -#include "../../../../C/Alloc.h" -#include "../../../../C/Lzma86.h" - -#include "../../../Common/MyWindows.h" -#include "../../../Common/MyInitGuid.h" - -#include "../../../Windows/NtCheck.h" - -#ifndef Z7_ST -#include "../../../Windows/System.h" -#endif - -#include "../../../Common/IntToString.h" -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/LzmaDecoder.h" -#include "../../Compress/LzmaEncoder.h" - -#include "../../UI/Console/BenchCon.h" -#include "../../UI/Console/ConsoleClose.h" - -extern -bool g_LargePagesMode; -bool g_LargePagesMode = false; - -using namespace NCommandLineParser; - -static const unsigned kDictSizeLog = 24; - -#define kCopyrightString "\nLZMA " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n" - -static const char * const kHelpString = - "Usage: lzma [inputFile] [outputFile] [...]\n" - "\n" - "\n" - " e : Encode file\n" - " d : Decode file\n" - " b : Benchmark\n" - "\n" - " -a{N} : set compression mode : [0, 1] : default = 1 (max)\n" - " -d{N} : set dictionary size : [12, 30] : default = 24 (16 MiB)\n" - " -fb{N} : set number of fast bytes : [5, 273] : default = 128\n" - " -mc{N} : set number of cycles for match finder\n" - " -lc{N} : set number of literal context bits : [0, 8] : default = 3\n" - " -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n" - " -pb{N} : set number of pos bits : [0, 4] : default = 2\n" - " -mf{M} : set match finder: [hc4, bt2, bt3, bt4] : default = bt4\n" - " -mt{N} : set number of CPU threads\n" - " -eos : write end of stream marker\n" - " -si : read data from stdin\n" - " -so : write data to stdout\n"; - - -static const char * const kCantAllocate = "Cannot allocate memory"; -static const char * const kReadError = "Read error"; -static const char * const kWriteError = "Write error"; - - -namespace NKey { -enum Enum -{ - kHelp1 = 0, - kHelp2, - kMethod, - kLevel, - kAlgo, - kDict, - kFb, - kMc, - kLc, - kLp, - kPb, - kMatchFinder, - kMultiThread, - kEOS, - kStdIn, - kStdOut, - kFilter86 -}; -} - -#define SWFRM_3(t, mu, mi) t, mu, mi, NULL - -#define SWFRM_1(t) SWFRM_3(t, false, 0) -#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple) -#define SWFRM_STRING SWFRM_1(NSwitchType::kString) - -#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi) - -static const CSwitchForm kSwitchForms[] = -{ - { "?", SWFRM_SIMPLE }, - { "H", SWFRM_SIMPLE }, - { "MM", SWFRM_STRING_SINGL(1) }, - { "X", SWFRM_STRING_SINGL(1) }, - { "A", SWFRM_STRING_SINGL(1) }, - { "D", SWFRM_STRING_SINGL(1) }, - { "FB", SWFRM_STRING_SINGL(1) }, - { "MC", SWFRM_STRING_SINGL(1) }, - { "LC", SWFRM_STRING_SINGL(1) }, - { "LP", SWFRM_STRING_SINGL(1) }, - { "PB", SWFRM_STRING_SINGL(1) }, - { "MF", SWFRM_STRING_SINGL(1) }, - { "MT", SWFRM_STRING }, - { "EOS", SWFRM_SIMPLE }, - { "SI", SWFRM_SIMPLE }, - { "SO", SWFRM_SIMPLE }, - { "F86", NSwitchType::kChar, false, 0, "+" } -}; - - -static void Convert_UString_to_AString(const UString &s, AString &temp) -{ - int codePage = CP_OEMCP; - /* - int g_CodePage = -1; - int codePage = g_CodePage; - if (codePage == -1) - codePage = CP_OEMCP; - if (codePage == CP_UTF8) - ConvertUnicodeToUTF8(s, temp); - else - */ - UnicodeStringToMultiByte2(temp, s, (UINT)codePage); -} - -static void PrintErr(const char *s) -{ - fputs(s, stderr); -} - -static void PrintErr_LF(const char *s) -{ - PrintErr(s); - fputc('\n', stderr); -} - - -static void PrintError(const char *s) -{ - PrintErr("\nERROR: "); - PrintErr_LF(s); -} - -static void PrintError2(const char *s1, const UString &s2) -{ - PrintError(s1); - AString a; - Convert_UString_to_AString(s2, a); - PrintErr_LF(a); -} - -static void PrintError_int(const char *s, int code) -{ - PrintError(s); - char temp[32]; - ConvertInt64ToString(code, temp); - PrintErr("Error code = "); - PrintErr_LF(temp); -} - - - -static void Print(const char *s) -{ - fputs(s, stdout); -} - -static void Print_UInt64(UInt64 v) -{ - char temp[32]; - ConvertUInt64ToString(v, temp); - Print(temp); -} - -static void Print_MB(UInt64 v) -{ - Print_UInt64(v); - Print(" MiB"); -} - -static void Print_Size(const char *s, UInt64 v) -{ - Print(s); - Print_UInt64(v); - Print(" ("); - Print_MB(v >> 20); - Print(")\n"); -} - -static void PrintTitle() -{ - Print(kCopyrightString); -} - -static void PrintHelp() -{ - PrintTitle(); - Print(kHelpString); -} - - -Z7_CLASS_IMP_COM_1( - CProgressPrint, - ICompressProgressInfo -) - UInt64 _size1; - UInt64 _size2; -public: - CProgressPrint(): _size1(0), _size2(0) {} - - void ClosePrint(); -}; - -#define BACK_STR \ -"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" -static const char * const kBackSpaces = -BACK_STR -" " -BACK_STR; - - -void CProgressPrint::ClosePrint() -{ - Print(kBackSpaces); -} - -Z7_COM7F_IMF(CProgressPrint::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - if (NConsoleClose::TestBreakSignal()) - return E_ABORT; - if (inSize) - { - UInt64 v1 = *inSize >> 20; - UInt64 v2 = _size2; - if (outSize) - v2 = *outSize >> 20; - if (v1 != _size1 || v2 != _size2) - { - _size1 = v1; - _size2 = v2; - ClosePrint(); - Print_MB(_size1); - Print(" -> "); - Print_MB(_size2); - } - } - return S_OK; -} - - -Z7_ATTR_NORETURN -static void IncorrectCommand() -{ - throw "Incorrect command"; -} - -static UInt32 GetNumber(const wchar_t *s) -{ - const wchar_t *end; - UInt32 v = ConvertStringToUInt32(s, &end); - if (*end != 0) - IncorrectCommand(); - return v; -} - -static void ParseUInt32(const CParser &parser, unsigned index, UInt32 &res) -{ - if (parser[index].ThereIs) - res = GetNumber(parser[index].PostStrings[0]); -} - - -static int Error_HRESULT(const char *s, HRESULT res) -{ - if (res == E_ABORT) - { - Print("\n\nBreak signaled\n"); - return 255; - } - - PrintError(s); - - if (res == E_OUTOFMEMORY) - { - PrintErr_LF(kCantAllocate); - return 8; - } - if (res == E_INVALIDARG) - { - PrintErr_LF("Ununsupported parameter"); - } - else - { - char temp[32]; - ConvertUInt32ToHex((UInt32)res, temp); - PrintErr("Error code = 0x"); - PrintErr_LF(temp); - } - return 1; -} - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1; -#endif - -static void AddProp(CObjectVector &props2, const char *name, const wchar_t *val) -{ - CProperty &prop = props2.AddNew(); - prop.Name = name; - prop.Value = val; -} - -static int main2(int numArgs, const char *args[]) -{ - NT_CHECK - - if (numArgs == 1) - { - PrintHelp(); - return 0; - } - - /* - bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 8); - if (unsupportedTypes) - throw "Unsupported base types. Edit Common/Types.h and recompile"; - */ - - UStringVector commandStrings; - for (int i = 1; i < numArgs; i++) - commandStrings.Add(MultiByteToUnicodeString(args[i])); - - CParser parser; - try - { - if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings)) - { - PrintError2(parser.ErrorMessage, parser.ErrorLine); - return 1; - } - } - catch(...) - { - IncorrectCommand(); - } - - if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) - { - PrintHelp(); - return 0; - } - - bool stdInMode = parser[NKey::kStdIn].ThereIs; - bool stdOutMode = parser[NKey::kStdOut].ThereIs; - - if (!stdOutMode) - PrintTitle(); - - const UStringVector ¶ms = parser.NonSwitchStrings; - - unsigned paramIndex = 0; - if (paramIndex >= params.Size()) - IncorrectCommand(); - const UString &command = params[paramIndex++]; - - CObjectVector props2; - bool dictDefined = false; - UInt32 dict = (UInt32)(Int32)-1; - - if (parser[NKey::kDict].ThereIs) - { - UInt32 dictLog; - const UString &s = parser[NKey::kDict].PostStrings[0]; - dictLog = GetNumber(s); - dict = 1 << dictLog; - dictDefined = true; - AddProp(props2, "d", s); - } - - if (parser[NKey::kLevel].ThereIs) - { - const UString &s = parser[NKey::kLevel].PostStrings[0]; - /* UInt32 level = */ GetNumber(s); - AddProp(props2, "x", s); - } - - UString mf ("BT4"); - if (parser[NKey::kMatchFinder].ThereIs) - mf = parser[NKey::kMatchFinder].PostStrings[0]; - - UInt32 numThreads = (UInt32)(Int32)-1; - - #ifndef Z7_ST - - if (parser[NKey::kMultiThread].ThereIs) - { - const UString &s = parser[NKey::kMultiThread].PostStrings[0]; - if (s.IsEmpty()) - numThreads = NWindows::NSystem::GetNumberOfProcessors(); - else - numThreads = GetNumber(s); - AddProp(props2, "mt", s); - } - - #endif - - - if (parser[NKey::kMethod].ThereIs) - { - const UString &s = parser[NKey::kMethod].PostStrings[0]; - if (s.IsEmpty() || s[0] != '=') - IncorrectCommand(); - AddProp(props2, "m", s.Ptr(1)); - } - - if (StringsAreEqualNoCase_Ascii(command, "b")) - { - UInt32 numIterations = 1; - if (paramIndex < params.Size()) - numIterations = GetNumber(params[paramIndex++]); - if (params.Size() != paramIndex) - IncorrectCommand(); - - HRESULT res = BenchCon(props2, numIterations, stdout); - - if (res == S_OK) - return 0; - return Error_HRESULT("Benchmark error", res); - } - - { - UInt32 needParams = 3; - if (stdInMode) needParams--; - if (stdOutMode) needParams--; - if (needParams != params.Size()) - IncorrectCommand(); - } - - if (numThreads == (UInt32)(Int32)-1) - numThreads = 1; - - bool encodeMode = false; - - if (StringsAreEqualNoCase_Ascii(command, "e")) - encodeMode = true; - else if (!StringsAreEqualNoCase_Ascii(command, "d")) - IncorrectCommand(); - - CMyComPtr inStream; - CInFileStream *inStreamSpec = NULL; - - if (stdInMode) - { - inStream = new CStdInFileStream; - MY_SET_BINARY_MODE(stdin); - } - else - { - const UString &inputName = params[paramIndex++]; - inStreamSpec = new CInFileStream; - inStream = inStreamSpec; - if (!inStreamSpec->Open(us2fs(inputName))) - { - PrintError2("Cannot open input file", inputName); - return 1; - } - } - - CMyComPtr outStream; - COutFileStream *outStreamSpec = NULL; - - if (stdOutMode) - { - outStream = new CStdOutFileStream; - MY_SET_BINARY_MODE(stdout); - } - else - { - const UString &outputName = params[paramIndex++]; - outStreamSpec = new COutFileStream; - outStream = outStreamSpec; - if (!outStreamSpec->Create_ALWAYS(us2fs(outputName))) - { - PrintError2("Cannot open output file", outputName); - return 1; - } - } - - bool fileSizeDefined = false; - UInt64 fileSize = 0; - - if (inStreamSpec) - { - if (!inStreamSpec->GetLength(fileSize)) - throw "Cannot get file length"; - fileSizeDefined = true; - if (!stdOutMode) - Print_Size("Input size: ", fileSize); - } - - if (encodeMode && !dictDefined) - { - dict = 1 << kDictSizeLog; - if (fileSizeDefined) - { - unsigned i; - for (i = 16; i < kDictSizeLog; i++) - if ((UInt32)((UInt32)1 << i) >= fileSize) - break; - dict = (UInt32)1 << i; - } - } - - if (parser[NKey::kFilter86].ThereIs) - { - /* -f86 switch is for x86 filtered mode: BCJ + LZMA. - It uses modified header format. - It's not recommended to use -f86 mode now. - You can use xz format instead, if you want to use filters */ - - if (parser[NKey::kEOS].ThereIs || stdInMode) - throw "Cannot use stdin in this mode"; - - size_t inSize = (size_t)fileSize; - - if (inSize != fileSize) - throw "File is too big"; - - Byte *inBuffer = NULL; - - if (inSize != 0) - { - inBuffer = (Byte *)MyAlloc((size_t)inSize); - if (!inBuffer) - throw kCantAllocate; - } - - if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK) - throw "Cannot read"; - - Byte *outBuffer = NULL; - size_t outSize; - - if (encodeMode) - { - // we allocate 105% of original size for output buffer - UInt64 outSize64 = fileSize / 20 * 21 + (1 << 16); - - outSize = (size_t)outSize64; - - if (outSize != outSize64) - throw "File is too big"; - - if (outSize != 0) - { - outBuffer = (Byte *)MyAlloc((size_t)outSize); - if (!outBuffer) - throw kCantAllocate; - } - - int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize, - 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO); - - if (res != 0) - { - PrintError_int("Encode error", (int)res); - return 1; - } - } - else - { - UInt64 outSize64; - - if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0) - throw "data error"; - - outSize = (size_t)outSize64; - if (outSize != outSize64) - throw "Unpack size is too big"; - if (outSize != 0) - { - outBuffer = (Byte *)MyAlloc(outSize); - if (!outBuffer) - throw kCantAllocate; - } - - int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize); - - if (inSize != (size_t)fileSize) - throw "incorrect processed size"; - if (res != 0) - { - PrintError_int("Decode error", (int)res); - return 1; - } - } - - if (WriteStream(outStream, outBuffer, outSize) != S_OK) - throw kWriteError; - - MyFree(outBuffer); - MyFree(inBuffer); - } - else - { - - CProgressPrint *progressSpec = NULL; - CMyComPtr progress; - - if (!stdOutMode) - { - progressSpec = new CProgressPrint; - progress = progressSpec; - } - - if (encodeMode) - { - NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder; - CMyComPtr encoder = encoderSpec; - - UInt32 pb = 2; - UInt32 lc = 3; // = 0; for 32-bit data - UInt32 lp = 0; // = 2; for 32-bit data - UInt32 algo = 1; - UInt32 fb = 128; - UInt32 mc = 16 + fb / 2; - bool mcDefined = false; - - bool eos = parser[NKey::kEOS].ThereIs || stdInMode; - - ParseUInt32(parser, NKey::kAlgo, algo); - ParseUInt32(parser, NKey::kFb, fb); - ParseUInt32(parser, NKey::kLc, lc); - ParseUInt32(parser, NKey::kLp, lp); - ParseUInt32(parser, NKey::kPb, pb); - - mcDefined = parser[NKey::kMc].ThereIs; - if (mcDefined) - mc = GetNumber(parser[NKey::kMc].PostStrings[0]); - - const PROPID propIDs[] = - { - NCoderPropID::kDictionarySize, - NCoderPropID::kPosStateBits, - NCoderPropID::kLitContextBits, - NCoderPropID::kLitPosBits, - NCoderPropID::kAlgorithm, - NCoderPropID::kNumFastBytes, - NCoderPropID::kMatchFinder, - NCoderPropID::kEndMarker, - NCoderPropID::kNumThreads, - NCoderPropID::kMatchFinderCycles, - }; - - const unsigned kNumPropsMax = Z7_ARRAY_SIZE(propIDs); - - PROPVARIANT props[kNumPropsMax]; - for (int p = 0; p < 6; p++) - props[p].vt = VT_UI4; - - props[0].ulVal = (UInt32)dict; - props[1].ulVal = (UInt32)pb; - props[2].ulVal = (UInt32)lc; - props[3].ulVal = (UInt32)lp; - props[4].ulVal = (UInt32)algo; - props[5].ulVal = (UInt32)fb; - - props[6].vt = VT_BSTR; - props[6].bstrVal = const_cast((const wchar_t *)mf); - - props[7].vt = VT_BOOL; - props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE; - - props[8].vt = VT_UI4; - props[8].ulVal = (UInt32)numThreads; - - // it must be last in property list - props[9].vt = VT_UI4; - props[9].ulVal = (UInt32)mc; - - unsigned numProps = kNumPropsMax; - if (!mcDefined) - numProps--; - - HRESULT res = encoderSpec->SetCoderProperties(propIDs, props, numProps); - if (res != S_OK) - return Error_HRESULT("incorrect encoder properties", res); - - if (encoderSpec->WriteCoderProperties(outStream) != S_OK) - throw kWriteError; - - bool fileSizeWasUsed = true; - if (eos || stdInMode) - { - fileSize = (UInt64)(Int64)-1; - fileSizeWasUsed = false; - } - - { - Byte temp[8]; - for (int i = 0; i < 8; i++) - temp[i]= (Byte)(fileSize >> (8 * i)); - if (WriteStream(outStream, temp, 8) != S_OK) - throw kWriteError; - } - - res = encoder->Code(inStream, outStream, NULL, NULL, progress); - if (progressSpec) - progressSpec->ClosePrint(); - - if (res != S_OK) - return Error_HRESULT("Encoding error", res); - - UInt64 processedSize = encoderSpec->GetInputProcessedSize(); - - if (fileSizeWasUsed && processedSize != fileSize) - throw "Incorrect size of processed data"; - } - else - { - NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder; - CMyComPtr decoder = decoderSpec; - - decoderSpec->FinishStream = true; - - const unsigned kPropertiesSize = 5; - Byte header[kPropertiesSize + 8]; - - if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK) - throw kReadError; - - if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK) - throw "SetDecoderProperties error"; - - UInt64 unpackSize = 0; - for (unsigned i = 0; i < 8; i++) - unpackSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i); - - bool unpackSizeDefined = (unpackSize != (UInt64)(Int64)-1); - - HRESULT res = decoder->Code(inStream, outStream, NULL, unpackSizeDefined ? &unpackSize : NULL, progress); - if (progressSpec) - progressSpec->ClosePrint(); - - if (res != S_OK) - { - if (res == S_FALSE) - { - PrintError("Decoding error"); - return 1; - } - return Error_HRESULT("Decoding error", res); - } - - if (unpackSizeDefined && unpackSize != decoderSpec->GetOutputProcessedSize()) - throw "incorrect uncompressed size in header"; - } - } - - if (outStreamSpec) - { - if (!stdOutMode) - Print_Size("Output size: ", outStreamSpec->ProcessedSize); - if (outStreamSpec->Close() != S_OK) - throw "File closing error"; - } - - return 0; -} - -int Z7_CDECL main(int numArgs, const char *args[]) -{ - NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter; - - try { return main2(numArgs, args); } - catch (const char *s) - { - PrintError(s); - return 1; - } - catch(...) - { - PrintError("Unknown Error"); - return 1; - } -} + // LzmaAlone.cpp + +#include "StdAfx.h" + +// #include + +#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE) +#include +#include +#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY) +#else +#define MY_SET_BINARY_MODE(file) +#endif + +#include "../../../../C/CpuArch.h" +#include "../../../../C/7zVersion.h" +#include "../../../../C/Alloc.h" +#include "../../../../C/Lzma86.h" + +#include "../../../Common/MyWindows.h" +#include "../../../Common/MyInitGuid.h" + +#include "../../../Windows/NtCheck.h" + +#ifndef Z7_ST +#include "../../../Windows/System.h" +#endif + +#include "../../../Common/IntToString.h" +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/LzmaDecoder.h" +#include "../../Compress/LzmaEncoder.h" + +#include "../../UI/Console/BenchCon.h" +#include "../../UI/Console/ConsoleClose.h" + +extern +bool g_LargePagesMode; +bool g_LargePagesMode = false; + +using namespace NCommandLineParser; + +static const unsigned kDictSizeLog = 24; + +#define kCopyrightString "\nLZMA " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n" + +static const char * const kHelpString = + "Usage: lzma [inputFile] [outputFile] [...]\n" + "\n" + "\n" + " e : Encode file\n" + " d : Decode file\n" + " b : Benchmark\n" + "\n" + " -a{N} : set compression mode : [0, 1] : default = 1 (max)\n" + " -d{N} : set dictionary size : [12, 31] : default = 24 (16 MiB)\n" + " -fb{N} : set number of fast bytes : [5, 273] : default = 128\n" + " -mc{N} : set number of cycles for match finder\n" + " -lc{N} : set number of literal context bits : [0, 8] : default = 3\n" + " -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n" + " -pb{N} : set number of pos bits : [0, 4] : default = 2\n" + " -mf{M} : set match finder: [hc4, hc5, bt2, bt3, bt4, bt5] : default = bt4\n" + " -mt{N} : set number of CPU threads\n" + " -eos : write end of stream marker\n" + " -si : read data from stdin\n" + " -so : write data to stdout\n"; + + +static const char * const kCantAllocate = "Cannot allocate memory"; +static const char * const kReadError = "Read error"; +static const char * const kWriteError = "Write error"; + + +namespace NKey { +enum Enum +{ + kHelp1 = 0, + kHelp2, + kMethod, + kLevel, + kAlgo, + kDict, + kFb, + kMc, + kLc, + kLp, + kPb, + kMatchFinder, + kMultiThread, + kEOS, + kStdIn, + kStdOut, + kFilter86 +}; +} + +#define SWFRM_3(t, mu, mi) t, mu, mi, NULL + +#define SWFRM_1(t) SWFRM_3(t, false, 0) +#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple) +#define SWFRM_STRING SWFRM_1(NSwitchType::kString) + +#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi) + +static const CSwitchForm kSwitchForms[] = +{ + { "?", SWFRM_SIMPLE }, + { "H", SWFRM_SIMPLE }, + { "MM", SWFRM_STRING_SINGL(1) }, + { "X", SWFRM_STRING_SINGL(1) }, + { "A", SWFRM_STRING_SINGL(1) }, + { "D", SWFRM_STRING_SINGL(1) }, + { "FB", SWFRM_STRING_SINGL(1) }, + { "MC", SWFRM_STRING_SINGL(1) }, + { "LC", SWFRM_STRING_SINGL(1) }, + { "LP", SWFRM_STRING_SINGL(1) }, + { "PB", SWFRM_STRING_SINGL(1) }, + { "MF", SWFRM_STRING_SINGL(1) }, + { "MT", SWFRM_STRING }, + { "EOS", SWFRM_SIMPLE }, + { "SI", SWFRM_SIMPLE }, + { "SO", SWFRM_SIMPLE }, + { "F86", NSwitchType::kChar, false, 0, "+" } +}; + + +static void Convert_UString_to_AString(const UString &s, AString &temp) +{ + int codePage = CP_OEMCP; + /* + int g_CodePage = -1; + int codePage = g_CodePage; + if (codePage == -1) + codePage = CP_OEMCP; + if (codePage == CP_UTF8) + ConvertUnicodeToUTF8(s, temp); + else + */ + UnicodeStringToMultiByte2(temp, s, (UINT)codePage); +} + +static void PrintErr(const char *s) +{ + fputs(s, stderr); +} + +static void PrintErr_LF(const char *s) +{ + PrintErr(s); + fputc('\n', stderr); +} + + +static void PrintError(const char *s) +{ + PrintErr("\nERROR: "); + PrintErr_LF(s); +} + +static void PrintError2(const char *s1, const UString &s2) +{ + PrintError(s1); + AString a; + Convert_UString_to_AString(s2, a); + PrintErr_LF(a); +} + +static void PrintError_int(const char *s, int code) +{ + PrintError(s); + char temp[32]; + ConvertInt64ToString(code, temp); + PrintErr("Error code = "); + PrintErr_LF(temp); +} + + + +static void Print(const char *s) +{ + fputs(s, stdout); +} + +static void Print_UInt64(UInt64 v) +{ + char temp[32]; + ConvertUInt64ToString(v, temp); + Print(temp); +} + +static void Print_MB(UInt64 v) +{ + Print_UInt64(v); + Print(" MiB"); +} + +static void Print_Size(const char *s, UInt64 v) +{ + Print(s); + Print_UInt64(v); + Print(" ("); + Print_MB(v >> 20); + Print(")\n"); +} + +static void PrintTitle() +{ + Print(kCopyrightString); +} + +static void PrintHelp() +{ + PrintTitle(); + Print(kHelpString); +} + + +Z7_CLASS_IMP_COM_1( + CProgressPrint, + ICompressProgressInfo +) + UInt64 _size1; + UInt64 _size2; +public: + CProgressPrint(): _size1(0), _size2(0) {} + + void ClosePrint(); +}; + +#define BACK_STR \ +"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" +static const char * const kBackSpaces = +BACK_STR +" " +BACK_STR; + + +void CProgressPrint::ClosePrint() +{ + Print(kBackSpaces); +} + +Z7_COM7F_IMF(CProgressPrint::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + if (NConsoleClose::TestBreakSignal()) + return E_ABORT; + if (inSize) + { + UInt64 v1 = *inSize >> 20; + UInt64 v2 = _size2; + if (outSize) + v2 = *outSize >> 20; + if (v1 != _size1 || v2 != _size2) + { + _size1 = v1; + _size2 = v2; + ClosePrint(); + Print_MB(_size1); + Print(" -> "); + Print_MB(_size2); + } + } + return S_OK; +} + + +Z7_ATTR_NORETURN +static void IncorrectCommand() +{ + throw "Incorrect command"; +} + +static UInt32 GetNumber(const wchar_t *s) +{ + const wchar_t *end; + UInt32 v = ConvertStringToUInt32(s, &end); + if (*end != 0) + IncorrectCommand(); + return v; +} + +static void ParseUInt32(const CParser &parser, unsigned index, UInt32 &res) +{ + if (parser[index].ThereIs) + res = GetNumber(parser[index].PostStrings[0]); +} + + +static int Error_HRESULT(const char *s, HRESULT res) +{ + if (res == E_ABORT) + { + Print("\n\nBreak signaled\n"); + return 255; + } + + PrintError(s); + + if (res == E_OUTOFMEMORY) + { + PrintErr_LF(kCantAllocate); + return 8; + } + if (res == E_INVALIDARG) + { + PrintErr_LF("Ununsupported parameter"); + } + else + { + char temp[32]; + ConvertUInt32ToHex((UInt32)res, temp); + PrintErr("Error code = 0x"); + PrintErr_LF(temp); + } + return 1; +} + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1; +#endif + +static void AddProp(CObjectVector &props2, const char *name, const wchar_t *val) +{ + CProperty &prop = props2.AddNew(); + prop.Name = name; + prop.Value = val; +} + +static int main2(int numArgs, const char *args[]) +{ + NT_CHECK + + if (numArgs == 1) + { + PrintHelp(); + return 0; + } + + /* + bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 8); + if (unsupportedTypes) + throw "Unsupported base types. Edit Common/Types.h and recompile"; + */ + + UStringVector commandStrings; + for (int i = 1; i < numArgs; i++) + commandStrings.Add(MultiByteToUnicodeString(args[i])); + + CParser parser; + try + { + if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings)) + { + PrintError2(parser.ErrorMessage, parser.ErrorLine); + return 1; + } + } + catch(...) + { + IncorrectCommand(); + } + + if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) + { + PrintHelp(); + return 0; + } + + const bool stdInMode = parser[NKey::kStdIn].ThereIs; + const bool stdOutMode = parser[NKey::kStdOut].ThereIs; + + if (!stdOutMode) + PrintTitle(); + + const UStringVector ¶ms = parser.NonSwitchStrings; + + unsigned paramIndex = 0; + if (paramIndex >= params.Size()) + IncorrectCommand(); + const UString &command = params[paramIndex++]; + + CObjectVector props2; + bool dictDefined = false; + UInt32 dict = (UInt32)(Int32)-1; + + if (parser[NKey::kDict].ThereIs) + { + UInt32 dictLog; + const UString &s = parser[NKey::kDict].PostStrings[0]; + dictLog = GetNumber(s); + if (dictLog >= 32) + throw "unsupported dictionary size"; + // we only want to use dictionary sizes that are powers of 2, + // because 7-zip only recognizes such dictionary sizes in the lzma header.#if 0 +#if 0 + if (dictLog == 32) + dict = (UInt32)3840 << 20; + else +#endif + dict = (UInt32)1 << dictLog; + dictDefined = true; + AddProp(props2, "d", s); + } + + if (parser[NKey::kLevel].ThereIs) + { + const UString &s = parser[NKey::kLevel].PostStrings[0]; + /* UInt32 level = */ GetNumber(s); + AddProp(props2, "x", s); + } + + UString mf ("BT4"); + if (parser[NKey::kMatchFinder].ThereIs) + mf = parser[NKey::kMatchFinder].PostStrings[0]; + + UInt32 numThreads = (UInt32)(Int32)-1; + + #ifndef Z7_ST + + if (parser[NKey::kMultiThread].ThereIs) + { + const UString &s = parser[NKey::kMultiThread].PostStrings[0]; + if (s.IsEmpty()) + numThreads = NWindows::NSystem::GetNumberOfProcessors(); + else + numThreads = GetNumber(s); + AddProp(props2, "mt", s); + } + + #endif + + + if (parser[NKey::kMethod].ThereIs) + { + const UString &s = parser[NKey::kMethod].PostStrings[0]; + if (s.IsEmpty() || s[0] != '=') + IncorrectCommand(); + AddProp(props2, "m", s.Ptr(1)); + } + + if (StringsAreEqualNoCase_Ascii(command, "b")) + { + UInt32 numIterations = 1; + if (paramIndex < params.Size()) + numIterations = GetNumber(params[paramIndex++]); + if (params.Size() != paramIndex) + IncorrectCommand(); + + HRESULT res = BenchCon(props2, numIterations, stdout); + + if (res == S_OK) + return 0; + return Error_HRESULT("Benchmark error", res); + } + + { + UInt32 needParams = 3; + if (stdInMode) needParams--; + if (stdOutMode) needParams--; + if (needParams != params.Size()) + IncorrectCommand(); + } + + if (numThreads == (UInt32)(Int32)-1) + numThreads = 1; + + bool encodeMode = false; + + if (StringsAreEqualNoCase_Ascii(command, "e")) + encodeMode = true; + else if (!StringsAreEqualNoCase_Ascii(command, "d")) + IncorrectCommand(); + + CMyComPtr inStream; + CInFileStream *inStreamSpec = NULL; + + if (stdInMode) + { + inStream = new CStdInFileStream; + MY_SET_BINARY_MODE(stdin); + } + else + { + const UString &inputName = params[paramIndex++]; + inStreamSpec = new CInFileStream; + inStream = inStreamSpec; + if (!inStreamSpec->Open(us2fs(inputName))) + { + PrintError2("Cannot open input file", inputName); + return 1; + } + } + + CMyComPtr outStream; + COutFileStream *outStreamSpec = NULL; + + if (stdOutMode) + { + outStream = new CStdOutFileStream; + MY_SET_BINARY_MODE(stdout); + } + else + { + const UString &outputName = params[paramIndex++]; + outStreamSpec = new COutFileStream; + outStream = outStreamSpec; + if (!outStreamSpec->Create_ALWAYS(us2fs(outputName))) + { + PrintError2("Cannot open output file", outputName); + return 1; + } + } + + bool fileSizeDefined = false; + UInt64 fileSize = 0; + + if (inStreamSpec) + { + if (!inStreamSpec->GetLength(fileSize)) + throw "Cannot get file length"; + fileSizeDefined = true; + if (!stdOutMode) + Print_Size("Input size: ", fileSize); + } + + if (encodeMode && !dictDefined) + { + dict = (UInt32)1 << kDictSizeLog; + if (fileSizeDefined) + { + unsigned i; + for (i = 16; i < kDictSizeLog; i++) + if ((UInt32)((UInt32)1 << i) >= fileSize) + break; + dict = (UInt32)1 << i; + } + } + + if (parser[NKey::kFilter86].ThereIs) + { + /* -f86 switch is for x86 filtered mode: BCJ + LZMA. + It uses modified header format. + It's not recommended to use -f86 mode now. + You can use xz format instead, if you want to use filters */ + + if (parser[NKey::kEOS].ThereIs || stdInMode) + throw "Cannot use stdin in this mode"; + + size_t inSize = (size_t)fileSize; + + if (inSize != fileSize) + throw "File is too big"; + + Byte *inBuffer = NULL; + + if (inSize != 0) + { + inBuffer = (Byte *)MyAlloc((size_t)inSize); + if (!inBuffer) + throw kCantAllocate; + } + + if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK) + throw "Cannot read"; + + Byte *outBuffer = NULL; + size_t outSize; + + if (encodeMode) + { + // we allocate 105% of original size for output buffer + UInt64 outSize64 = fileSize / 20 * 21 + (1 << 16); + + outSize = (size_t)outSize64; + + if (outSize != outSize64) + throw "File is too big"; + + if (outSize != 0) + { + outBuffer = (Byte *)MyAlloc((size_t)outSize); + if (!outBuffer) + throw kCantAllocate; + } + + int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize, + 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO); + + if (res != 0) + { + PrintError_int("Encode error", (int)res); + return 1; + } + } + else + { + UInt64 outSize64; + + if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0) + throw "data error"; + + outSize = (size_t)outSize64; + if (outSize != outSize64) + throw "Unpack size is too big"; + if (outSize != 0) + { + outBuffer = (Byte *)MyAlloc(outSize); + if (!outBuffer) + throw kCantAllocate; + } + + int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize); + + if (inSize != (size_t)fileSize) + throw "incorrect processed size"; + if (res != 0) + { + PrintError_int("Decode error", (int)res); + return 1; + } + } + + if (WriteStream(outStream, outBuffer, outSize) != S_OK) + throw kWriteError; + + MyFree(outBuffer); + MyFree(inBuffer); + } + else + { + + CProgressPrint *progressSpec = NULL; + CMyComPtr progress; + + if (!stdOutMode) + { + progressSpec = new CProgressPrint; + progress = progressSpec; + } + + if (encodeMode) + { + NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder; + CMyComPtr encoder = encoderSpec; + + UInt32 pb = 2; + UInt32 lc = 3; // = 0; for 32-bit data + UInt32 lp = 0; // = 2; for 32-bit data + UInt32 algo = 1; + UInt32 fb = 128; + UInt32 mc = 16 + fb / 2; + bool mcDefined = false; + + bool eos = parser[NKey::kEOS].ThereIs || stdInMode; + + ParseUInt32(parser, NKey::kAlgo, algo); + ParseUInt32(parser, NKey::kFb, fb); + ParseUInt32(parser, NKey::kLc, lc); + ParseUInt32(parser, NKey::kLp, lp); + ParseUInt32(parser, NKey::kPb, pb); + + mcDefined = parser[NKey::kMc].ThereIs; + if (mcDefined) + mc = GetNumber(parser[NKey::kMc].PostStrings[0]); + + const PROPID propIDs[] = + { + NCoderPropID::kDictionarySize, + NCoderPropID::kPosStateBits, + NCoderPropID::kLitContextBits, + NCoderPropID::kLitPosBits, + NCoderPropID::kAlgorithm, + NCoderPropID::kNumFastBytes, + NCoderPropID::kMatchFinder, + NCoderPropID::kEndMarker, + NCoderPropID::kNumThreads, + NCoderPropID::kMatchFinderCycles, + }; + + const unsigned kNumPropsMax = Z7_ARRAY_SIZE(propIDs); + + PROPVARIANT props[kNumPropsMax]; + for (int p = 0; p < 6; p++) + props[p].vt = VT_UI4; + + props[0].ulVal = (UInt32)dict; + props[1].ulVal = (UInt32)pb; + props[2].ulVal = (UInt32)lc; + props[3].ulVal = (UInt32)lp; + props[4].ulVal = (UInt32)algo; + props[5].ulVal = (UInt32)fb; + + props[6].vt = VT_BSTR; + props[6].bstrVal = const_cast((const wchar_t *)mf); + + props[7].vt = VT_BOOL; + props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE; + + props[8].vt = VT_UI4; + props[8].ulVal = (UInt32)numThreads; + + // it must be last in property list + props[9].vt = VT_UI4; + props[9].ulVal = (UInt32)mc; + + unsigned numProps = kNumPropsMax; + if (!mcDefined) + numProps--; + + HRESULT res = encoderSpec->SetCoderProperties(propIDs, props, numProps); + if (res != S_OK) + return Error_HRESULT("incorrect encoder properties", res); + + if (encoderSpec->WriteCoderProperties(outStream) != S_OK) + throw kWriteError; + + bool fileSizeWasUsed = true; + if (eos || stdInMode) + { + fileSize = (UInt64)(Int64)-1; + fileSizeWasUsed = false; + } + + { + Byte temp[8]; + for (int i = 0; i < 8; i++) + temp[i]= (Byte)(fileSize >> (8 * i)); + if (WriteStream(outStream, temp, 8) != S_OK) + throw kWriteError; + } + + res = encoder->Code(inStream, outStream, NULL, NULL, progress); + if (progressSpec) + progressSpec->ClosePrint(); + + if (res != S_OK) + return Error_HRESULT("Encoding error", res); + + UInt64 processedSize = encoderSpec->GetInputProcessedSize(); + + if (fileSizeWasUsed && processedSize != fileSize) + throw "Incorrect size of processed data"; + } + else + { + NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder; + CMyComPtr decoder = decoderSpec; + + decoderSpec->FinishStream = true; + + const unsigned kPropertiesSize = 5; + Byte header[kPropertiesSize + 8]; + + if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK) + throw kReadError; + + if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK) + throw "SetDecoderProperties error"; + + UInt64 unpackSize = 0; + for (unsigned i = 0; i < 8; i++) + unpackSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i); + + bool unpackSizeDefined = (unpackSize != (UInt64)(Int64)-1); + + HRESULT res = decoder->Code(inStream, outStream, NULL, unpackSizeDefined ? &unpackSize : NULL, progress); + if (progressSpec) + progressSpec->ClosePrint(); + + if (res != S_OK) + { + if (res == S_FALSE) + { + PrintError("Decoding error"); + return 1; + } + return Error_HRESULT("Decoding error", res); + } + + if (unpackSizeDefined && unpackSize != decoderSpec->GetOutputProcessedSize()) + throw "incorrect uncompressed size in header"; + } + } + + if (outStreamSpec) + { + if (!stdOutMode) + Print_Size("Output size: ", outStreamSpec->ProcessedSize); + if (outStreamSpec->Close() != S_OK) + throw "File closing error"; + } + + return 0; +} + +int Z7_CDECL main(int numArgs, const char *args[]) +{ + NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter; + + try { return main2(numArgs, args); } + catch (const char *s) + { + PrintError(s); + return 1; + } + catch(...) + { + PrintError("Unknown Error"); + return 1; + } +} diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp index 6a9ccc3b6..258bb6d72 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp @@ -1,540 +1,540 @@ -# Microsoft Developer Studio Project File - Name="LzmaCon" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=LzmaCon - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "LzmaCon.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "LzmaCon.mak" CFG="LzmaCon - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "LzmaCon - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "LzmaCon - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "LzmaCon - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_NO_LONG_PATH" /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\lzma.exe" - -!ELSEIF "$(CFG)" == "LzmaCon - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_NO_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\lzma.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "LzmaCon - Win32 Release" -# Name "LzmaCon - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaEncoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CrcReg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\LzFindPrepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyLinux.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyUnknown.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Types.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Bench.h -# End Source File -# End Group -# Begin Group "Console" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Console\BenchCon.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\BenchCon.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzFindOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzHash.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma86.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma86Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma86Enc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaEnc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "7zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\LzmaAlone.cpp -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="LzmaCon" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=LzmaCon - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "LzmaCon.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "LzmaCon.mak" CFG="LzmaCon - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "LzmaCon - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "LzmaCon - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "LzmaCon - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_NO_LONG_PATH" /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\lzma.exe" + +!ELSEIF "$(CFG)" == "LzmaCon - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_NO_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\lzma.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "LzmaCon - Win32 Release" +# Name "LzmaCon - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaEncoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CrcReg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\LzFindPrepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyLinux.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyUnknown.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Bench.h +# End Source File +# End Group +# Begin Group "Console" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Console\BenchCon.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\BenchCon.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzFindOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzHash.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma86.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma86Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma86Enc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaEnc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "7zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\LzmaAlone.cpp +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw index c6a666276..e62c9d2f1 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw +++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "LzmaCon"=.\LzmaCon.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "LzmaCon"=.\LzmaCon.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp b/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp +++ b/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/LzmaCon/StdAfx.h b/CPP/7zip/Bundles/LzmaCon/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/LzmaCon/StdAfx.h +++ b/CPP/7zip/Bundles/LzmaCon/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/LzmaCon/makefile b/CPP/7zip/Bundles/LzmaCon/makefile index 65e7c00fe..4aef25248 100644 --- a/CPP/7zip/Bundles/LzmaCon/makefile +++ b/CPP/7zip/Bundles/LzmaCon/makefile @@ -1,68 +1,68 @@ -PROG = lzma.exe -MY_CONSOLE = 1 - -CFLAGS = $(CFLAGS) -DZ7_NO_LONG_PATH -# CFLAGS = $(CFLAGS) -DZ7_ST - - -CURRENT_OBJS = \ - $O\LzmaAlone.obj \ - -COMPRESS_OBJS = \ - $O\LzmaDecoder.obj \ - $O\LzmaEncoder.obj \ - $O\LzmaRegister.obj \ - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\CrcReg.obj \ - $O\IntToString.obj \ - $O\LzFindPrepare.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\NewHandler.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\FileIO.obj \ - $O\PropVariant.obj \ - $O\Registry.obj \ - $O\System.obj \ - $O\SystemInfo.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\MethodProps.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - -UI_COMMON_OBJS = \ - $O\Bench.obj \ - -CONSOLE_OBJS = \ - $O\ConsoleClose.obj \ - $O\BenchCon.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\Bra86.obj \ - $O\CpuArch.obj \ - $O\LzFind.obj \ - $O\LzFindMt.obj \ - $O\Lzma86Dec.obj \ - $O\Lzma86Enc.obj \ - $O\LzmaDec.obj \ - $O\LzmaEnc.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" -!include "../../LzFindOpt.mak" -!include "../../LzmaDec.mak" - -!include "../../7zip.mak" +PROG = lzma.exe +MY_CONSOLE = 1 + +CFLAGS = $(CFLAGS) -DZ7_NO_LONG_PATH +# CFLAGS = $(CFLAGS) -DZ7_ST + + +CURRENT_OBJS = \ + $O\LzmaAlone.obj \ + +COMPRESS_OBJS = \ + $O\LzmaDecoder.obj \ + $O\LzmaEncoder.obj \ + $O\LzmaRegister.obj \ + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\CrcReg.obj \ + $O\IntToString.obj \ + $O\LzFindPrepare.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\NewHandler.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\FileIO.obj \ + $O\PropVariant.obj \ + $O\Registry.obj \ + $O\System.obj \ + $O\SystemInfo.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\MethodProps.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + +UI_COMMON_OBJS = \ + $O\Bench.obj \ + +CONSOLE_OBJS = \ + $O\ConsoleClose.obj \ + $O\BenchCon.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\Bra86.obj \ + $O\CpuArch.obj \ + $O\LzFind.obj \ + $O\LzFindMt.obj \ + $O\Lzma86Dec.obj \ + $O\Lzma86Enc.obj \ + $O\LzmaDec.obj \ + $O\LzmaEnc.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" +!include "../../LzFindOpt.mak" +!include "../../LzmaDec.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/LzmaCon/makefile.gcc b/CPP/7zip/Bundles/LzmaCon/makefile.gcc index b7a88818e..67c789278 100644 --- a/CPP/7zip/Bundles/LzmaCon/makefile.gcc +++ b/CPP/7zip/Bundles/LzmaCon/makefile.gcc @@ -1,131 +1,131 @@ -PROG = lzma - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -include ../../LzmaDec_gcc.mak - - -LOCAL_FLAGS_ST = -MT_OBJS = - - -ifdef ST_MODE - -LOCAL_FLAGS_ST = -DZ7_ST - -else - -MT_OBJS = \ - $O/LzFindMt.o \ - $O/LzFindOpt.o \ - $O/Threads.o \ - $O/Synchronization.o \ - - - -endif - - - -LOCAL_FLAGS_SYS = - -ifdef IS_MINGW - -SYS_OBJS = \ - $O/Registry.o \ - $O/resource.o \ - -LOCAL_FLAGS_SYS = \ - -DZ7_NO_LONG_PATH \ - -else - -SYS_OBJS = \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileName.o \ - $O/MyWindows.o \ - $O/TimeUtils.o \ - -endif - -LOCAL_FLAGS = \ - $(LOCAL_FLAGS_ST) \ - $(LOCAL_FLAGS_SYS) \ - - -COMMON_OBJS = \ - $O/CommandLineParser.o \ - $O/CRC.o \ - $O/CrcReg.o \ - $O/IntToString.o \ - $O/LzFindPrepare.o \ - $O/MyString.o \ - $O/MyVector.o \ - $O/NewHandler.o \ - $O/StringConvert.o \ - $O/StringToInt.o \ - $O/UTFConvert.o \ - $O/Wildcard.o \ - -WIN_OBJS = \ - $O/FileIO.o \ - $O/PropVariant.o \ - $O/System.o \ - $O/SystemInfo.o \ - -COMPRESS_OBJS = \ - $O/LzmaDecoder.o \ - $O/LzmaEncoder.o \ - $O/LzmaRegister.o \ - -CONSOLE_OBJS = \ - $O/BenchCon.o \ - $O/ConsoleClose.o \ - -7ZIP_COMMON_OBJS = \ - $O/CreateCoder.o \ - $O/CWrappers.o \ - $O/FileStreams.o \ - $O/FilterCoder.o \ - $O/MethodProps.o \ - $O/StreamObjects.o \ - $O/StreamUtils.o \ - -C_OBJS = \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - $O/Alloc.o \ - $O/Bra86.o \ - $O/CpuArch.o \ - $O/LzFind.o \ - $O/LzmaDec.o \ - $O/LzmaEnc.o \ - $O/Lzma86Dec.o \ - $O/Lzma86Enc.o \ - -OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $(C_OBJS) \ - $(MT_OBJS) \ - $(SYS_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(COMPRESS_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(CONSOLE_OBJS) \ - $O/LzmaAlone.o \ - $O/Bench.o \ - -include ../../7zip_gcc.mak +PROG = lzma + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +include ../../LzmaDec_gcc.mak + + +LOCAL_FLAGS_ST = +MT_OBJS = + + +ifdef ST_MODE + +LOCAL_FLAGS_ST = -DZ7_ST + +else + +MT_OBJS = \ + $O/LzFindMt.o \ + $O/LzFindOpt.o \ + $O/Threads.o \ + $O/Synchronization.o \ + + + +endif + + + +LOCAL_FLAGS_SYS = + +ifdef IS_MINGW + +SYS_OBJS = \ + $O/Registry.o \ + $O/resource.o \ + +LOCAL_FLAGS_SYS = \ + -DZ7_NO_LONG_PATH \ + +else + +SYS_OBJS = \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileName.o \ + $O/MyWindows.o \ + $O/TimeUtils.o \ + +endif + +LOCAL_FLAGS = \ + $(LOCAL_FLAGS_ST) \ + $(LOCAL_FLAGS_SYS) \ + + +COMMON_OBJS = \ + $O/CommandLineParser.o \ + $O/CRC.o \ + $O/CrcReg.o \ + $O/IntToString.o \ + $O/LzFindPrepare.o \ + $O/MyString.o \ + $O/MyVector.o \ + $O/NewHandler.o \ + $O/StringConvert.o \ + $O/StringToInt.o \ + $O/UTFConvert.o \ + $O/Wildcard.o \ + +WIN_OBJS = \ + $O/FileIO.o \ + $O/PropVariant.o \ + $O/System.o \ + $O/SystemInfo.o \ + +COMPRESS_OBJS = \ + $O/LzmaDecoder.o \ + $O/LzmaEncoder.o \ + $O/LzmaRegister.o \ + +CONSOLE_OBJS = \ + $O/BenchCon.o \ + $O/ConsoleClose.o \ + +7ZIP_COMMON_OBJS = \ + $O/CreateCoder.o \ + $O/CWrappers.o \ + $O/FileStreams.o \ + $O/FilterCoder.o \ + $O/MethodProps.o \ + $O/StreamObjects.o \ + $O/StreamUtils.o \ + +C_OBJS = \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + $O/Alloc.o \ + $O/Bra86.o \ + $O/CpuArch.o \ + $O/LzFind.o \ + $O/LzmaDec.o \ + $O/LzmaEnc.o \ + $O/Lzma86Dec.o \ + $O/Lzma86Enc.o \ + +OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $(C_OBJS) \ + $(MT_OBJS) \ + $(SYS_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(COMPRESS_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(CONSOLE_OBJS) \ + $O/LzmaAlone.o \ + $O/Bench.o \ + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/Bundles/LzmaCon/resource.rc b/CPP/7zip/Bundles/LzmaCon/resource.rc index 9b54fa80a..43b50738e 100644 --- a/CPP/7zip/Bundles/LzmaCon/resource.rc +++ b/CPP/7zip/Bundles/LzmaCon/resource.rc @@ -1,3 +1,3 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("LZMA", "lzma") +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("LZMA", "lzma") diff --git a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp index 6a922451d..d49093266 100644 --- a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp +++ b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp @@ -1,1017 +1,1017 @@ -# Microsoft Developer Studio Project File - Name="SFXCon" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=SFXCon - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SFXCon.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SFXCon.mak" CFG="SFXCon - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SFXCon - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "SFXCon - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SFXCon - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_SFX" /D "Z7_NO_READ_FROM_CODER" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /FAcs /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\7zCon.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_SFX" /D "Z7_NO_READ_FROM_CODER" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\7zCon.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "SFXCon - Win32 Release" -# Name "SFXCon - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\HandlerOut.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# Begin Group "Console" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ConsoleClose.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\ExtractCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\List.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\List.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\MainAr.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\OpenCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\PercentPrinter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\PercentPrinter.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UserInputUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Console\UserInputUtils.h -# End Source File -# End Group -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SplitHandler.cpp -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeltaFilter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdRegister.cpp -# End Source File -# End Group -# Begin Group "Crypto" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAesRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OffsetStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterArc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterCodec.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "UI" - -# PROP Default_Filter "" -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\PropIDUtils.h -# End Source File -# End Group -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\AesOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BraIA64.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c - -!IF "$(CFG)" == "SFXCon - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "7zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7z.ico -# End Source File -# Begin Source File - -SOURCE=.\SfxCon.cpp -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="SFXCon" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=SFXCon - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SFXCon.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SFXCon.mak" CFG="SFXCon - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SFXCon - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "SFXCon - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SFXCon - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_SFX" /D "Z7_NO_READ_FROM_CODER" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /FAcs /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\7zCon.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_SFX" /D "Z7_NO_READ_FROM_CODER" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\7zCon.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "SFXCon - Win32 Release" +# Name "SFXCon - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\HandlerOut.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "Console" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ConsoleClose.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\ExtractCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\List.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\List.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\MainAr.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\OpenCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\PercentPrinter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\PercentPrinter.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UserInputUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Console\UserInputUtils.h +# End Source File +# End Group +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SplitHandler.cpp +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeltaFilter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdRegister.cpp +# End Source File +# End Group +# Begin Group "Crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAesRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OffsetStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterArc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterCodec.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "UI" + +# PROP Default_Filter "" +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\PropIDUtils.h +# End Source File +# End Group +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\AesOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BraIA64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c + +!IF "$(CFG)" == "SFXCon - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "7zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7z.ico +# End Source File +# Begin Source File + +SOURCE=.\SfxCon.cpp +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/Bundles/SFXCon/SFXCon.dsw b/CPP/7zip/Bundles/SFXCon/SFXCon.dsw index bfbc2b7f0..27bf7e6d1 100644 --- a/CPP/7zip/Bundles/SFXCon/SFXCon.dsw +++ b/CPP/7zip/Bundles/SFXCon/SFXCon.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SFXCon"=.\SFXCon.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SFXCon"=.\SFXCon.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp index 34ab28a11..aac4e2888 100644 --- a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp +++ b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp @@ -1,521 +1,521 @@ -// Main.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" -#include "../../../../C/DllSecur.h" - -#include "../../../Common/MyWindows.h" -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/MyException.h" - -#ifdef _WIN32 -#include "../../../Windows/DLL.h" -#else -#include "../../../Common/StringConvert.h" -#endif -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" - -#include "../../UI/Common/ExitCode.h" -#include "../../UI/Common/Extract.h" - -#include "../../UI/Console/ExtractCallbackConsole.h" -#include "../../UI/Console/List.h" -#include "../../UI/Console/OpenCallbackConsole.h" - -#include "../../MyVersion.h" - - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NCommandLineParser; - -#ifdef _WIN32 -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance = NULL; -#endif -extern -int g_CodePage; -int g_CodePage = -1; -extern CStdOutStream *g_StdStream; - -static const char * const kCopyrightString = -"\n7-Zip SFX " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n"; - -static const int kNumSwitches = 6; - -namespace NKey { -enum Enum -{ - kHelp1 = 0, - kHelp2, - kDisablePercents, - kYes, - kPassword, - kOutputDir -}; - -} - -namespace NRecursedType { -enum EEnum -{ - kRecursed, - kWildcardOnlyRecursed, - kNonRecursed -}; -} -/* -static const char kRecursedIDChar = 'R'; - -namespace NRecursedPostCharIndex { - enum EEnum - { - kWildcardRecursionOnly = 0, - kNoRecursion = 1 - }; -} - -static const char kFileListID = '@'; -static const char kImmediateNameID = '!'; - -static const char kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be -static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be -*/ - -#define SWFRM_3(t, mu, mi) t, mu, mi, NULL -#define SWFRM_1(t) SWFRM_3(t, false, 0) -#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple) -#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi) - -static const CSwitchForm kSwitchForms[kNumSwitches] = -{ - { "?", SWFRM_SIMPLE }, - { "H", SWFRM_SIMPLE }, - { "BD", SWFRM_SIMPLE }, - { "Y", SWFRM_SIMPLE }, - { "P", SWFRM_STRING_SINGL(1) }, - { "O", SWFRM_STRING_SINGL(1) }, -}; - -static const int kNumCommandForms = 3; - -static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] = -{ - NRecursedType::kRecursed -}; - -// static const bool kTestExtractRecursedDefault = true; -// static const bool kAddRecursedDefault = false; - -static const char * const kUniversalWildcard = "*"; - -static const char * const kHelpString = - "\nUsage: 7zSFX [] [...] [...]\n" - "\n" - "\n" - // " l: List contents of archive\n" - " t: Test integrity of archive\n" - " x: eXtract files with full pathname (default)\n" - "\n" - // " -bd Disable percentage indicator\n" - " -o{Directory}: set Output directory\n" - " -p{Password}: set Password\n" - " -y: assume Yes on all queries\n"; - - -// --------------------------- -// exception messages - -static const char * const kUserErrorMessage = "Incorrect command line"; // NExitCode::kUserError -// static const char * const kIncorrectListFile = "Incorrect wildcard in listfile"; -static const char * const kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line"; - -// static const CSysString kFileIsNotArchiveMessageBefore = "File \""; -// static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive"; - -// static const char * const kProcessArchiveMessage = " archive: "; - -static const char * const kCantFindSFX = " cannot find sfx"; - -namespace NCommandType -{ - enum EEnum - { - kTest = 0, - kFullExtract, - kList - }; -} - -static const char *g_Commands = "txl"; - -struct CArchiveCommand -{ - NCommandType::EEnum CommandType; - - NRecursedType::EEnum DefaultRecursedType() const; -}; - -static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command) -{ - UString s = commandString; - s.MakeLower_Ascii(); - if (s.Len() != 1) - return false; - if (s[0] >= 0x80) - return false; - int index = FindCharPosInString(g_Commands, (char)s[0]); - if (index < 0) - return false; - command.CommandType = (NCommandType::EEnum)index; - return true; -} - -NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const -{ - return kCommandRecursedDefault[CommandType]; -} - -static void PrintHelp(void) -{ - g_StdOut << kHelpString; -} - -Z7_ATTR_NORETURN -static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code) -{ - g_StdOut << message << endl; - throw code; -} - -Z7_ATTR_NORETURN -static void PrintHelpAndExit() // yyy -{ - PrintHelp(); - ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError); -} - -// ------------------------------------------------------------------ -// filenames functions - -static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, - const UString &name, bool include, NRecursedType::EEnum type) -{ - /* - if (!IsWildcardFilePathLegal(name)) - return false; - */ - const bool isWildcard = DoesNameContainWildcard(name); - bool recursed = false; - - switch (type) - { - case NRecursedType::kWildcardOnlyRecursed: - recursed = isWildcard; - break; - case NRecursedType::kRecursed: - recursed = true; - break; - case NRecursedType::kNonRecursed: - recursed = false; - break; - } - - NWildcard::CCensorPathProps props; - props.Recursive = recursed; - wildcardCensor.AddPreItem(include, name, props); - return true; -} - -static void AddCommandLineWildcardToCensor(NWildcard::CCensor &wildcardCensor, - const UString &name, bool include, NRecursedType::EEnum type) -{ - if (!AddNameToCensor(wildcardCensor, name, include, type)) - ShowMessageAndThrowException(kIncorrectWildcardInCommandLine, NExitCode::kUserError); -} - - -#ifndef _WIN32 -static void GetArguments(int numArgs, char *args[], UStringVector &parts) -{ - parts.Clear(); - for (int i = 0; i < numArgs; i++) - { - UString s = MultiByteToUnicodeString(args[i]); - parts.Add(s); - } -} -#endif - - -int Main2( - #ifndef _WIN32 - int numArgs, char *args[] - #endif -); -int Main2( - #ifndef _WIN32 - int numArgs, char *args[] - #endif -) -{ - #ifdef _WIN32 - // do we need load Security DLLs for console program? - LoadSecurityDlls(); - #endif - - #if defined(_WIN32) && !defined(UNDER_CE) - SetFileApisToOEM(); - #endif - - #ifdef ENV_HAVE_LOCALE - MY_SetLocale(); - #endif - - g_StdOut << kCopyrightString; - - UStringVector commandStrings; - #ifdef _WIN32 - NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); - #else - GetArguments(numArgs, args, commandStrings); - #endif - - #ifdef _WIN32 - - FString arcPath; - { - FString path; - NDLL::MyGetModuleFileName(path); - if (!MyGetFullPathName(path, arcPath)) - { - g_StdOut << "GetFullPathName Error"; - return NExitCode::kFatalError; - } - } - - #else - - if (commandStrings.IsEmpty()) - return NExitCode::kFatalError; - - const FString arcPath = us2fs(commandStrings.Front()); - - #endif - - #ifndef UNDER_CE - if (commandStrings.Size() > 0) - commandStrings.Delete(0); - #endif - - NCommandLineParser::CParser parser; - - try - { - if (!parser.ParseStrings(kSwitchForms, kNumSwitches, commandStrings)) - { - g_StdOut << "Command line error:" << endl - << parser.ErrorMessage << endl - << parser.ErrorLine << endl; - return NExitCode::kUserError; - } - } - catch(...) - { - PrintHelpAndExit(); - } - - if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) - { - PrintHelp(); - return 0; - } - - const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; - - unsigned curCommandIndex = 0; - - CArchiveCommand command; - if (nonSwitchStrings.IsEmpty()) - command.CommandType = NCommandType::kFullExtract; - else - { - const UString &cmd = nonSwitchStrings[curCommandIndex]; - if (!ParseArchiveCommand(cmd, command)) - { - g_StdOut << "ERROR: Unknown command:" << endl << cmd << endl; - return NExitCode::kUserError; - } - curCommandIndex = 1; - } - - - NRecursedType::EEnum recursedType; - recursedType = command.DefaultRecursedType(); - - NWildcard::CCensor wildcardCensor; - - { - if (nonSwitchStrings.Size() == curCommandIndex) - AddCommandLineWildcardToCensor(wildcardCensor, (UString)kUniversalWildcard, true, recursedType); - for (; curCommandIndex < nonSwitchStrings.Size(); curCommandIndex++) - { - const UString &s = nonSwitchStrings[curCommandIndex]; - if (s.IsEmpty()) - throw "Empty file path"; - AddCommandLineWildcardToCensor(wildcardCensor, s, true, recursedType); - } - } - - const bool yesToAll = parser[NKey::kYes].ThereIs; - - // NExtractMode::EEnum extractMode; - // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode); - - const bool passwordEnabled = parser[NKey::kPassword].ThereIs; - - UString password; - if (passwordEnabled) - password = parser[NKey::kPassword].PostStrings[0]; - - if (!NFind::DoesFileExist_FollowLink(arcPath)) - throw kCantFindSFX; - - FString outputDir; - if (parser[NKey::kOutputDir].ThereIs) - { - outputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); - NName::NormalizeDirPathPrefix(outputDir); - } - - - wildcardCensor.AddPathsToCensor(NWildcard::k_RelatPath); - - { - UStringVector v1, v2; - v1.Add(fs2us(arcPath)); - v2.Add(fs2us(arcPath)); - const NWildcard::CCensorNode &wildcardCensorHead = - wildcardCensor.Pairs.Front().Head; - - CCodecs *codecs = new CCodecs; - CMyComPtr< - #ifdef Z7_EXTERNAL_CODECS - ICompressCodecsInfo - #else - IUnknown - #endif - > compressCodecsInfo = codecs; - { - HRESULT result = codecs->Load(); - if (result != S_OK) - throw CSystemException(result); - } - - if (command.CommandType != NCommandType::kList) - { - CExtractCallbackConsole *ecs = new CExtractCallbackConsole; - CMyComPtr extractCallback = ecs; - ecs->Init(g_StdStream, &g_StdErr, g_StdStream, false); - - #ifndef Z7_NO_CRYPTO - ecs->PasswordIsDefined = passwordEnabled; - ecs->Password = password; - #endif - - /* - COpenCallbackConsole openCallback; - openCallback.Init(g_StdStream, g_StdStream); - - #ifndef Z7_NO_CRYPTO - openCallback.PasswordIsDefined = passwordEnabled; - openCallback.Password = password; - #endif - */ - - CExtractOptions eo; - eo.StdOutMode = false; - eo.YesToAll = yesToAll; - eo.TestMode = command.CommandType == NCommandType::kTest; - eo.PathMode = NExtract::NPathMode::kFullPaths; - eo.OverwriteMode = yesToAll ? - NExtract::NOverwriteMode::kOverwrite : - NExtract::NOverwriteMode::kAsk; - eo.OutputDir = outputDir; - - UString errorMessage; - CDecompressStat stat; - HRESULT result = Extract( - codecs, CObjectVector(), CIntVector(), - v1, v2, - wildcardCensorHead, - eo, - ecs, ecs, ecs, - // NULL, // hash - errorMessage, stat); - - ecs->ClosePercents(); - - if (!errorMessage.IsEmpty()) - { - (*g_StdStream) << endl << "Error: " << errorMessage; - if (result == S_OK) - result = E_FAIL; - } - - if ( 0 != ecs->NumCantOpenArcs - || 0 != ecs->NumArcsWithError - || 0 != ecs->NumFileErrors - || 0 != ecs->NumOpenArcErrors) - { - if (ecs->NumCantOpenArcs != 0) - (*g_StdStream) << endl << "Can't open as archive" << endl; - if (ecs->NumArcsWithError != 0) - (*g_StdStream) << endl << "Archive Errors" << endl; - if (ecs->NumFileErrors != 0) - (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << endl; - if (ecs->NumOpenArcErrors != 0) - (*g_StdStream) << endl << "Open Errors: " << ecs->NumOpenArcErrors << endl; - return NExitCode::kFatalError; - } - if (result != S_OK) - throw CSystemException(result); - } - else - { - throw CSystemException(E_NOTIMPL); - - /* - UInt64 numErrors = 0; - UInt64 numWarnings = 0; - HRESULT result = ListArchives( - codecs, CObjectVector(), CIntVector(), - false, // stdInMode - v1, v2, - true, // processAltStreams - false, // showAltStreams - wildcardCensorHead, - true, // enableHeaders - false, // techMode - #ifndef Z7_NO_CRYPTO - passwordEnabled, password, - #endif - numErrors, numWarnings); - if (numErrors > 0) - { - g_StdOut << endl << "Errors: " << numErrors; - return NExitCode::kFatalError; - } - if (result != S_OK) - throw CSystemException(result); - */ - } - } - return 0; -} +// Main.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" +#include "../../../../C/DllSecur.h" + +#include "../../../Common/MyWindows.h" +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/MyException.h" + +#ifdef _WIN32 +#include "../../../Windows/DLL.h" +#else +#include "../../../Common/StringConvert.h" +#endif +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" + +#include "../../UI/Common/ExitCode.h" +#include "../../UI/Common/Extract.h" + +#include "../../UI/Console/ExtractCallbackConsole.h" +#include "../../UI/Console/List.h" +#include "../../UI/Console/OpenCallbackConsole.h" + +#include "../../MyVersion.h" + + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NCommandLineParser; + +#ifdef _WIN32 +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance = NULL; +#endif +extern +int g_CodePage; +int g_CodePage = -1; +extern CStdOutStream *g_StdStream; + +static const char * const kCopyrightString = +"\n7-Zip SFX " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n"; + +static const int kNumSwitches = 6; + +namespace NKey { +enum Enum +{ + kHelp1 = 0, + kHelp2, + kDisablePercents, + kYes, + kPassword, + kOutputDir +}; + +} + +namespace NRecursedType { +enum EEnum +{ + kRecursed, + kWildcardOnlyRecursed, + kNonRecursed +}; +} +/* +static const char kRecursedIDChar = 'R'; + +namespace NRecursedPostCharIndex { + enum EEnum + { + kWildcardRecursionOnly = 0, + kNoRecursion = 1 + }; +} + +static const char kFileListID = '@'; +static const char kImmediateNameID = '!'; + +static const char kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be +static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be +*/ + +#define SWFRM_3(t, mu, mi) t, mu, mi, NULL +#define SWFRM_1(t) SWFRM_3(t, false, 0) +#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple) +#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi) + +static const CSwitchForm kSwitchForms[kNumSwitches] = +{ + { "?", SWFRM_SIMPLE }, + { "H", SWFRM_SIMPLE }, + { "BD", SWFRM_SIMPLE }, + { "Y", SWFRM_SIMPLE }, + { "P", SWFRM_STRING_SINGL(1) }, + { "O", SWFRM_STRING_SINGL(1) }, +}; + +static const int kNumCommandForms = 3; + +static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] = +{ + NRecursedType::kRecursed +}; + +// static const bool kTestExtractRecursedDefault = true; +// static const bool kAddRecursedDefault = false; + +static const char * const kUniversalWildcard = "*"; + +static const char * const kHelpString = + "\nUsage: 7zSFX [] [...] [...]\n" + "\n" + "\n" + // " l: List contents of archive\n" + " t: Test integrity of archive\n" + " x: eXtract files with full pathname (default)\n" + "\n" + // " -bd Disable percentage indicator\n" + " -o{Directory}: set Output directory\n" + " -p{Password}: set Password\n" + " -y: assume Yes on all queries\n"; + + +// --------------------------- +// exception messages + +static const char * const kUserErrorMessage = "Incorrect command line"; // NExitCode::kUserError +// static const char * const kIncorrectListFile = "Incorrect wildcard in listfile"; +static const char * const kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line"; + +// static const CSysString kFileIsNotArchiveMessageBefore = "File \""; +// static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive"; + +// static const char * const kProcessArchiveMessage = " archive: "; + +static const char * const kCantFindSFX = " cannot find sfx"; + +namespace NCommandType +{ + enum EEnum + { + kTest = 0, + kFullExtract, + kList + }; +} + +static const char *g_Commands = "txl"; + +struct CArchiveCommand +{ + NCommandType::EEnum CommandType; + + NRecursedType::EEnum DefaultRecursedType() const; +}; + +static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command) +{ + UString s = commandString; + s.MakeLower_Ascii(); + if (s.Len() != 1) + return false; + if (s[0] >= 0x80) + return false; + int index = FindCharPosInString(g_Commands, (char)s[0]); + if (index < 0) + return false; + command.CommandType = (NCommandType::EEnum)index; + return true; +} + +NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const +{ + return kCommandRecursedDefault[CommandType]; +} + +static void PrintHelp(void) +{ + g_StdOut << kHelpString; +} + +Z7_ATTR_NORETURN +static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code) +{ + g_StdOut << message << endl; + throw code; +} + +Z7_ATTR_NORETURN +static void PrintHelpAndExit() // yyy +{ + PrintHelp(); + ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError); +} + +// ------------------------------------------------------------------ +// filenames functions + +static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, + const UString &name, bool include, NRecursedType::EEnum type) +{ + /* + if (!IsWildcardFilePathLegal(name)) + return false; + */ + const bool isWildcard = DoesNameContainWildcard(name); + bool recursed = false; + + switch (type) + { + case NRecursedType::kWildcardOnlyRecursed: + recursed = isWildcard; + break; + case NRecursedType::kRecursed: + recursed = true; + break; + case NRecursedType::kNonRecursed: + recursed = false; + break; + } + + NWildcard::CCensorPathProps props; + props.Recursive = recursed; + wildcardCensor.AddPreItem(include, name, props); + return true; +} + +static void AddCommandLineWildcardToCensor(NWildcard::CCensor &wildcardCensor, + const UString &name, bool include, NRecursedType::EEnum type) +{ + if (!AddNameToCensor(wildcardCensor, name, include, type)) + ShowMessageAndThrowException(kIncorrectWildcardInCommandLine, NExitCode::kUserError); +} + + +#ifndef _WIN32 +static void GetArguments(int numArgs, char *args[], UStringVector &parts) +{ + parts.Clear(); + for (int i = 0; i < numArgs; i++) + { + UString s = MultiByteToUnicodeString(args[i]); + parts.Add(s); + } +} +#endif + + +int Main2( + #ifndef _WIN32 + int numArgs, char *args[] + #endif +); +int Main2( + #ifndef _WIN32 + int numArgs, char *args[] + #endif +) +{ + #ifdef _WIN32 + // do we need load Security DLLs for console program? + LoadSecurityDlls(); + #endif + + #if defined(_WIN32) && !defined(UNDER_CE) + SetFileApisToOEM(); + #endif + + #ifdef ENV_HAVE_LOCALE + MY_SetLocale(); + #endif + + g_StdOut << kCopyrightString; + + UStringVector commandStrings; + #ifdef _WIN32 + NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); + #else + GetArguments(numArgs, args, commandStrings); + #endif + + #ifdef _WIN32 + + FString arcPath; + { + FString path; + NDLL::MyGetModuleFileName(path); + if (!MyGetFullPathName(path, arcPath)) + { + g_StdOut << "GetFullPathName Error"; + return NExitCode::kFatalError; + } + } + + #else + + if (commandStrings.IsEmpty()) + return NExitCode::kFatalError; + + const FString arcPath = us2fs(commandStrings.Front()); + + #endif + + #ifndef UNDER_CE + if (commandStrings.Size() > 0) + commandStrings.Delete(0); + #endif + + NCommandLineParser::CParser parser; + + try + { + if (!parser.ParseStrings(kSwitchForms, kNumSwitches, commandStrings)) + { + g_StdOut << "Command line error:" << endl + << parser.ErrorMessage << endl + << parser.ErrorLine << endl; + return NExitCode::kUserError; + } + } + catch(...) + { + PrintHelpAndExit(); + } + + if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) + { + PrintHelp(); + return 0; + } + + const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; + + unsigned curCommandIndex = 0; + + CArchiveCommand command; + if (nonSwitchStrings.IsEmpty()) + command.CommandType = NCommandType::kFullExtract; + else + { + const UString &cmd = nonSwitchStrings[curCommandIndex]; + if (!ParseArchiveCommand(cmd, command)) + { + g_StdOut << "ERROR: Unknown command:" << endl << cmd << endl; + return NExitCode::kUserError; + } + curCommandIndex = 1; + } + + + NRecursedType::EEnum recursedType; + recursedType = command.DefaultRecursedType(); + + NWildcard::CCensor wildcardCensor; + + { + if (nonSwitchStrings.Size() == curCommandIndex) + AddCommandLineWildcardToCensor(wildcardCensor, (UString)kUniversalWildcard, true, recursedType); + for (; curCommandIndex < nonSwitchStrings.Size(); curCommandIndex++) + { + const UString &s = nonSwitchStrings[curCommandIndex]; + if (s.IsEmpty()) + throw "Empty file path"; + AddCommandLineWildcardToCensor(wildcardCensor, s, true, recursedType); + } + } + + const bool yesToAll = parser[NKey::kYes].ThereIs; + + // NExtractMode::EEnum extractMode; + // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode); + + const bool passwordEnabled = parser[NKey::kPassword].ThereIs; + + UString password; + if (passwordEnabled) + password = parser[NKey::kPassword].PostStrings[0]; + + if (!NFind::DoesFileExist_FollowLink(arcPath)) + throw kCantFindSFX; + + FString outputDir; + if (parser[NKey::kOutputDir].ThereIs) + { + outputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); + NName::NormalizeDirPathPrefix(outputDir); + } + + + wildcardCensor.AddPathsToCensor(NWildcard::k_RelatPath); + + { + UStringVector v1, v2; + v1.Add(fs2us(arcPath)); + v2.Add(fs2us(arcPath)); + const NWildcard::CCensorNode &wildcardCensorHead = + wildcardCensor.Pairs.Front().Head; + + CCodecs *codecs = new CCodecs; + CMyComPtr< + #ifdef Z7_EXTERNAL_CODECS + ICompressCodecsInfo + #else + IUnknown + #endif + > compressCodecsInfo = codecs; + { + HRESULT result = codecs->Load(); + if (result != S_OK) + throw CSystemException(result); + } + + if (command.CommandType != NCommandType::kList) + { + CExtractCallbackConsole *ecs = new CExtractCallbackConsole; + CMyComPtr extractCallback = ecs; + ecs->Init(g_StdStream, &g_StdErr, g_StdStream, false); + + #ifndef Z7_NO_CRYPTO + ecs->PasswordIsDefined = passwordEnabled; + ecs->Password = password; + #endif + + /* + COpenCallbackConsole openCallback; + openCallback.Init(g_StdStream, g_StdStream); + + #ifndef Z7_NO_CRYPTO + openCallback.PasswordIsDefined = passwordEnabled; + openCallback.Password = password; + #endif + */ + + CExtractOptions eo; + eo.StdOutMode = false; + eo.YesToAll = yesToAll; + eo.TestMode = command.CommandType == NCommandType::kTest; + eo.PathMode = NExtract::NPathMode::kFullPaths; + eo.OverwriteMode = yesToAll ? + NExtract::NOverwriteMode::kOverwrite : + NExtract::NOverwriteMode::kAsk; + eo.OutputDir = outputDir; + + UString errorMessage; + CDecompressStat stat; + HRESULT result = Extract( + codecs, CObjectVector(), CIntVector(), + v1, v2, + wildcardCensorHead, + eo, + ecs, ecs, ecs, + // NULL, // hash + errorMessage, stat); + + ecs->ClosePercents(); + + if (!errorMessage.IsEmpty()) + { + (*g_StdStream) << endl << "Error: " << errorMessage; + if (result == S_OK) + result = E_FAIL; + } + + if ( 0 != ecs->NumCantOpenArcs + || 0 != ecs->NumArcsWithError + || 0 != ecs->NumFileErrors + || 0 != ecs->NumOpenArcErrors) + { + if (ecs->NumCantOpenArcs != 0) + (*g_StdStream) << endl << "Can't open as archive" << endl; + if (ecs->NumArcsWithError != 0) + (*g_StdStream) << endl << "Archive Errors" << endl; + if (ecs->NumFileErrors != 0) + (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << endl; + if (ecs->NumOpenArcErrors != 0) + (*g_StdStream) << endl << "Open Errors: " << ecs->NumOpenArcErrors << endl; + return NExitCode::kFatalError; + } + if (result != S_OK) + throw CSystemException(result); + } + else + { + throw CSystemException(E_NOTIMPL); + + /* + UInt64 numErrors = 0; + UInt64 numWarnings = 0; + HRESULT result = ListArchives( + codecs, CObjectVector(), CIntVector(), + false, // stdInMode + v1, v2, + true, // processAltStreams + false, // showAltStreams + wildcardCensorHead, + true, // enableHeaders + false, // techMode + #ifndef Z7_NO_CRYPTO + passwordEnabled, password, + #endif + numErrors, numWarnings); + if (numErrors > 0) + { + g_StdOut << endl << "Errors: " << numErrors; + return NExitCode::kFatalError; + } + if (result != S_OK) + throw CSystemException(result); + */ + } + } + return 0; +} diff --git a/CPP/7zip/Bundles/SFXCon/StdAfx.cpp b/CPP/7zip/Bundles/SFXCon/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/SFXCon/StdAfx.cpp +++ b/CPP/7zip/Bundles/SFXCon/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/SFXCon/StdAfx.h b/CPP/7zip/Bundles/SFXCon/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/Bundles/SFXCon/StdAfx.h +++ b/CPP/7zip/Bundles/SFXCon/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Bundles/SFXCon/makefile b/CPP/7zip/Bundles/SFXCon/makefile index fdaee7c0f..a72e3f8fb 100644 --- a/CPP/7zip/Bundles/SFXCon/makefile +++ b/CPP/7zip/Bundles/SFXCon/makefile @@ -1,137 +1,137 @@ -PROG = 7zCon.sfx -MY_CONSOLE = 1 -MY_FIXED = 1 - -CFLAGS = $(CFLAGS) \ - -DZ7_EXTRACT_ONLY \ - -DZ7_NO_READ_FROM_CODER \ - -DZ7_SFX \ - -DZ7_NO_LONG_PATH \ - -DZ7_NO_LARGE_PAGES \ - -CURRENT_OBJS = \ - $O\SfxCon.obj \ - -CONSOLE_OBJS = \ - $O\ConsoleClose.obj \ - $O\ExtractCallbackConsole.obj \ - $O\List.obj \ - $O\MainAr.obj \ - $O\OpenCallbackConsole.obj \ - $O\PercentPrinter.obj \ - $O\UserInputUtils.obj \ - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\IntToString.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\NewHandler.obj \ - $O\StdInStream.obj \ - $O\StdOutStream.obj \ - $O\StringConvert.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\InBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\VirtThread.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveOpenCallback.obj \ - $O\DefaultName.obj \ - $O\Extract.obj \ - $O\ExtractingFilePath.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - $O\PropIDUtils.obj \ - -AR_OBJS = \ - $O\SplitHandler.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\ItemNameUtils.obj \ - $O\MultiStream.obj \ - $O\OutStreamWithCRC.obj \ - -7Z_OBJS = \ - $O\7zDecode.obj \ - $O\7zExtract.obj \ - $O\7zHandler.obj \ - $O\7zIn.obj \ - $O\7zRegister.obj \ - -COMPRESS_OBJS = \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaRegister.obj \ - $O\PpmdDecoder.obj \ - $O\PpmdRegister.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\MyAes.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\DllSecur.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\LzmaDec.obj \ - $O\MtDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - $O\Threads.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../LzmaDec.mak" -!include "../../Sha256.mak" - -!include "../../7zip.mak" +PROG = 7zCon.sfx +MY_CONSOLE = 1 +MY_FIXED = 1 + +CFLAGS = $(CFLAGS) \ + -DZ7_EXTRACT_ONLY \ + -DZ7_NO_READ_FROM_CODER \ + -DZ7_SFX \ + -DZ7_NO_LONG_PATH \ + -DZ7_NO_LARGE_PAGES \ + +CURRENT_OBJS = \ + $O\SfxCon.obj \ + +CONSOLE_OBJS = \ + $O\ConsoleClose.obj \ + $O\ExtractCallbackConsole.obj \ + $O\List.obj \ + $O\MainAr.obj \ + $O\OpenCallbackConsole.obj \ + $O\PercentPrinter.obj \ + $O\UserInputUtils.obj \ + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\IntToString.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\NewHandler.obj \ + $O\StdInStream.obj \ + $O\StdOutStream.obj \ + $O\StringConvert.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\InBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\VirtThread.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveOpenCallback.obj \ + $O\DefaultName.obj \ + $O\Extract.obj \ + $O\ExtractingFilePath.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + $O\PropIDUtils.obj \ + +AR_OBJS = \ + $O\SplitHandler.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\ItemNameUtils.obj \ + $O\MultiStream.obj \ + $O\OutStreamWithCRC.obj \ + +7Z_OBJS = \ + $O\7zDecode.obj \ + $O\7zExtract.obj \ + $O\7zHandler.obj \ + $O\7zIn.obj \ + $O\7zRegister.obj \ + +COMPRESS_OBJS = \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaRegister.obj \ + $O\PpmdDecoder.obj \ + $O\PpmdRegister.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\MyAes.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\DllSecur.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\LzmaDec.obj \ + $O\MtDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + $O\Threads.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../LzmaDec.mak" +!include "../../Sha256.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/SFXCon/makefile.gcc b/CPP/7zip/Bundles/SFXCon/makefile.gcc index db34c1edc..87d78a9e7 100644 --- a/CPP/7zip/Bundles/SFXCon/makefile.gcc +++ b/CPP/7zip/Bundles/SFXCon/makefile.gcc @@ -1,215 +1,215 @@ -PROG = 7zCon - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - -include ../../LzmaDec_gcc.mak - - -LOCAL_FLAGS_ST = -MT_OBJS = - - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -ifdef ST_MODE - -LOCAL_FLAGS_ST = -DZ7_ST - -ifdef IS_MINGW -MT_OBJS = \ - $O/Threads.o \ - -endif - -else - -MT_OBJS = \ - $O/StreamBinder.o \ - $O/Synchronization.o \ - $O/VirtThread.o \ - $O/Threads.o \ - -endif - - - -LOCAL_FLAGS_SYS = - -ifdef IS_MINGW - -LOCAL_FLAGS_SYS = \ - -DZ7_NO_LONG_PATH \ - -DZ7_NO_LARGE_PAGES \ - -SYS_OBJS = \ - $O/DLL.o \ - $O/DllSecur.o \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - -endif - -LOCAL_FLAGS = \ - -DZ7_EXTRACT_ONLY \ - -DZ7_NO_READ_FROM_CODER \ - -DZ7_SFX \ - $(LOCAL_FLAGS_ST) \ - $(LOCAL_FLAGS_SYS) \ - - -CURRENT_OBJS = \ - $O/SfxCon.o \ - -CONSOLE_OBJS = \ - $O/ConsoleClose.o \ - $O/ExtractCallbackConsole.o \ - $O/List.o \ - $O/MainAr.o \ - $O/OpenCallbackConsole.o \ - $O/PercentPrinter.o \ - $O/UserInputUtils.o \ - -COMMON_OBJS = \ - $O/CommandLineParser.o \ - $O/CRC.o \ - $O/IntToString.o \ - $O/MyString.o \ - $O/MyVector.o \ - $O/NewHandler.o \ - $O/Sha256Prepare.o \ - $O/StdInStream.o \ - $O/StdOutStream.o \ - $O/StringConvert.o \ - $O/UTFConvert.o \ - $O/Wildcard.o \ - -WIN_OBJS = \ - \ - $O/ErrorMsg.o \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileIO.o \ - $O/FileName.o \ - $O/PropVariant.o \ - $O/PropVariantConv.o \ - \ - $O/System.o \ - $O/TimeUtils.o \ - -7ZIP_COMMON_OBJS = \ - $O/CreateCoder.o \ - $O/CWrappers.o \ - $O/FilePathAutoRename.o \ - $O/FileStreams.o \ - $O/InBuffer.o \ - $O/FilterCoder.o \ - $O/LimitedStreams.o \ - $O/OutBuffer.o \ - $O/ProgressUtils.o \ - $O/PropId.o \ - \ - $O/StreamObjects.o \ - $O/StreamUtils.o \ - \ - -UI_COMMON_OBJS = \ - $O/ArchiveExtractCallback.o \ - $O/ArchiveOpenCallback.o \ - $O/DefaultName.o \ - $O/Extract.o \ - $O/ExtractingFilePath.o \ - $O/LoadCodecs.o \ - $O/OpenArchive.o \ - $O/PropIDUtils.o \ - -AR_OBJS = \ - $O/SplitHandler.o \ - -AR_COMMON_OBJS = \ - $O/CoderMixer2.o \ - $O/ItemNameUtils.o \ - $O/MultiStream.o \ - $O/OutStreamWithCRC.o \ - -7Z_OBJS = \ - $O/7zDecode.o \ - $O/7zExtract.o \ - $O/7zHandler.o \ - $O/7zIn.o \ - $O/7zRegister.o \ - -COMPRESS_OBJS = \ - $O/Bcj2Coder.o \ - $O/Bcj2Register.o \ - $O/BcjCoder.o \ - $O/BcjRegister.o \ - $O/BranchMisc.o \ - $O/BranchRegister.o \ - $O/CopyCoder.o \ - $O/CopyRegister.o \ - $O/DeltaFilter.o \ - $O/Lzma2Decoder.o \ - $O/Lzma2Register.o \ - $O/LzmaDecoder.o \ - $O/LzmaRegister.o \ - $O/PpmdDecoder.o \ - $O/PpmdRegister.o \ - -CRYPTO_OBJS = \ - $O/7zAes.o \ - $O/7zAesRegister.o \ - $O/MyAes.o \ - -C_OBJS = \ - $O/7zStream.o \ - $O/Alloc.o \ - $O/Bcj2.o \ - $O/Bra.o \ - $O/Bra86.o \ - $O/BraIA64.o \ - $O/CpuArch.o \ - $O/Delta.o \ - $O/Lzma2Dec.o \ - $O/Lzma2DecMt.o \ - $O/LzmaDec.o \ - $O/MtDec.o \ - $O/Ppmd7.o \ - $O/Ppmd7Dec.o \ - $O/Sha256.o \ - $O/Sha256Opt.o \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - $O/Aes.o \ - $O/AesOpt.o \ - -OBJS = \ - $(LZMA_DEC_OPT_OBJS) \ - $(C_OBJS) \ - $(MT_OBJS) \ - $(SYS_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(COMPRESS_OBJS) \ - $(CRYPTO_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(AR_OBJS) \ - $(AR_COMMON_OBJS) \ - $(7Z_OBJS) \ - $(UI_COMMON_OBJS) \ - $(CONSOLE_OBJS) \ - $(CURRENT_OBJS) \ - -include ../../7zip_gcc.mak +PROG = 7zCon + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + +include ../../LzmaDec_gcc.mak + + +LOCAL_FLAGS_ST = +MT_OBJS = + + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef ST_MODE + +LOCAL_FLAGS_ST = -DZ7_ST + +ifdef IS_MINGW +MT_OBJS = \ + $O/Threads.o \ + +endif + +else + +MT_OBJS = \ + $O/StreamBinder.o \ + $O/Synchronization.o \ + $O/VirtThread.o \ + $O/Threads.o \ + +endif + + + +LOCAL_FLAGS_SYS = + +ifdef IS_MINGW + +LOCAL_FLAGS_SYS = \ + -DZ7_NO_LONG_PATH \ + -DZ7_NO_LARGE_PAGES \ + +SYS_OBJS = \ + $O/DLL.o \ + $O/DllSecur.o \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + +endif + +LOCAL_FLAGS = \ + -DZ7_EXTRACT_ONLY \ + -DZ7_NO_READ_FROM_CODER \ + -DZ7_SFX \ + $(LOCAL_FLAGS_ST) \ + $(LOCAL_FLAGS_SYS) \ + + +CURRENT_OBJS = \ + $O/SfxCon.o \ + +CONSOLE_OBJS = \ + $O/ConsoleClose.o \ + $O/ExtractCallbackConsole.o \ + $O/List.o \ + $O/MainAr.o \ + $O/OpenCallbackConsole.o \ + $O/PercentPrinter.o \ + $O/UserInputUtils.o \ + +COMMON_OBJS = \ + $O/CommandLineParser.o \ + $O/CRC.o \ + $O/IntToString.o \ + $O/MyString.o \ + $O/MyVector.o \ + $O/NewHandler.o \ + $O/Sha256Prepare.o \ + $O/StdInStream.o \ + $O/StdOutStream.o \ + $O/StringConvert.o \ + $O/UTFConvert.o \ + $O/Wildcard.o \ + +WIN_OBJS = \ + \ + $O/ErrorMsg.o \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileIO.o \ + $O/FileName.o \ + $O/PropVariant.o \ + $O/PropVariantConv.o \ + \ + $O/System.o \ + $O/TimeUtils.o \ + +7ZIP_COMMON_OBJS = \ + $O/CreateCoder.o \ + $O/CWrappers.o \ + $O/FilePathAutoRename.o \ + $O/FileStreams.o \ + $O/InBuffer.o \ + $O/FilterCoder.o \ + $O/LimitedStreams.o \ + $O/OutBuffer.o \ + $O/ProgressUtils.o \ + $O/PropId.o \ + \ + $O/StreamObjects.o \ + $O/StreamUtils.o \ + \ + +UI_COMMON_OBJS = \ + $O/ArchiveExtractCallback.o \ + $O/ArchiveOpenCallback.o \ + $O/DefaultName.o \ + $O/Extract.o \ + $O/ExtractingFilePath.o \ + $O/LoadCodecs.o \ + $O/OpenArchive.o \ + $O/PropIDUtils.o \ + +AR_OBJS = \ + $O/SplitHandler.o \ + +AR_COMMON_OBJS = \ + $O/CoderMixer2.o \ + $O/ItemNameUtils.o \ + $O/MultiStream.o \ + $O/OutStreamWithCRC.o \ + +7Z_OBJS = \ + $O/7zDecode.o \ + $O/7zExtract.o \ + $O/7zHandler.o \ + $O/7zIn.o \ + $O/7zRegister.o \ + +COMPRESS_OBJS = \ + $O/Bcj2Coder.o \ + $O/Bcj2Register.o \ + $O/BcjCoder.o \ + $O/BcjRegister.o \ + $O/BranchMisc.o \ + $O/BranchRegister.o \ + $O/CopyCoder.o \ + $O/CopyRegister.o \ + $O/DeltaFilter.o \ + $O/Lzma2Decoder.o \ + $O/Lzma2Register.o \ + $O/LzmaDecoder.o \ + $O/LzmaRegister.o \ + $O/PpmdDecoder.o \ + $O/PpmdRegister.o \ + +CRYPTO_OBJS = \ + $O/7zAes.o \ + $O/7zAesRegister.o \ + $O/MyAes.o \ + +C_OBJS = \ + $O/7zStream.o \ + $O/Alloc.o \ + $O/Bcj2.o \ + $O/Bra.o \ + $O/Bra86.o \ + $O/BraIA64.o \ + $O/CpuArch.o \ + $O/Delta.o \ + $O/Lzma2Dec.o \ + $O/Lzma2DecMt.o \ + $O/LzmaDec.o \ + $O/MtDec.o \ + $O/Ppmd7.o \ + $O/Ppmd7Dec.o \ + $O/Sha256.o \ + $O/Sha256Opt.o \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + $O/Aes.o \ + $O/AesOpt.o \ + +OBJS = \ + $(LZMA_DEC_OPT_OBJS) \ + $(C_OBJS) \ + $(MT_OBJS) \ + $(SYS_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(COMPRESS_OBJS) \ + $(CRYPTO_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(AR_OBJS) \ + $(AR_COMMON_OBJS) \ + $(7Z_OBJS) \ + $(UI_COMMON_OBJS) \ + $(CONSOLE_OBJS) \ + $(CURRENT_OBJS) \ + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/Bundles/SFXCon/resource.rc b/CPP/7zip/Bundles/SFXCon/resource.rc index 04b8d6d73..65762125a 100644 --- a/CPP/7zip/Bundles/SFXCon/resource.rc +++ b/CPP/7zip/Bundles/SFXCon/resource.rc @@ -1,9 +1,9 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx") - -101 ICON "7z.ico" - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" -#endif +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx") + +101 ICON "7z.ico" + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "../../UI/Console/Console.manifest" +#endif diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp index eeebb23c9..14dd2ecd9 100644 --- a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp +++ b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp @@ -1,246 +1,246 @@ -// ExtractCallbackSfx.h - -#include "StdAfx.h" - -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "ExtractCallbackSfx.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static LPCSTR const kCantDeleteFile = "Cannot delete output file"; -static LPCSTR const kCantOpenFile = "Cannot open output file"; -static LPCSTR const kUnsupportedMethod = "Unsupported Method"; - -void CExtractCallbackImp::Init(IInArchive *archiveHandler, - const FString &directoryPath, - const UString &itemDefaultName, - const FILETIME &defaultMTime, - UInt32 defaultAttributes) -{ - _message.Empty(); - _isCorrupt = false; - _itemDefaultName = itemDefaultName; - _defaultMTime = defaultMTime; - _defaultAttributes = defaultAttributes; - _archiveHandler = archiveHandler; - _directoryPath = directoryPath; - NName::NormalizeDirPathPrefix(_directoryPath); -} - -HRESULT CExtractCallbackImp::Open_CheckBreak() -{ - #ifndef _NO_PROGRESS - return ProgressDialog.Sync.ProcessStopAndPause(); - #else - return S_OK; - #endif -} - -HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) -{ - return S_OK; -} - -HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) -{ - #ifndef _NO_PROGRESS - return ProgressDialog.Sync.ProcessStopAndPause(); - #else - return S_OK; - #endif -} - -HRESULT CExtractCallbackImp::Open_Finished() -{ - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 size)) -{ - #ifndef _NO_PROGRESS - ProgressDialog.Sync.SetProgress(size, 0); - #endif - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)) -{ - #ifndef _NO_PROGRESS - RINOK(ProgressDialog.Sync.ProcessStopAndPause()) - if (completeValue != NULL) - ProgressDialog.Sync.SetPos(*completeValue); - #endif - return S_OK; -} - -void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts) -{ - FString fullPath = _directoryPath; - FOR_VECTOR (i, dirPathParts) - { - fullPath += us2fs(dirPathParts[i]); - CreateDir(fullPath); - fullPath.Add_PathSepar(); - } -} - -Z7_COM7F_IMF(CExtractCallbackImp::GetStream(UInt32 index, - ISequentialOutStream **outStream, Int32 askExtractMode)) -{ - #ifndef _NO_PROGRESS - if (ProgressDialog.Sync.GetStopped()) - return E_ABORT; - #endif - _outFileStream.Release(); - - UString fullPath; - { - NCOM::CPropVariant prop; - RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop)) - if (prop.vt == VT_EMPTY) - fullPath = _itemDefaultName; - else - { - if (prop.vt != VT_BSTR) - return E_FAIL; - fullPath.SetFromBstr(prop.bstrVal); - } - _filePath = fullPath; - } - - if (askExtractMode == NArchive::NExtract::NAskMode::kExtract) - { - NCOM::CPropVariant prop; - RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop)) - if (prop.vt == VT_EMPTY) - _processedFileInfo.Attributes = _defaultAttributes; - else - { - if (prop.vt != VT_UI4) - return E_FAIL; - _processedFileInfo.Attributes = prop.ulVal; - } - - RINOK(_archiveHandler->GetProperty(index, kpidIsDir, &prop)) - _processedFileInfo.IsDir = VARIANT_BOOLToBool(prop.boolVal); - - bool isAnti = false; - { - NCOM::CPropVariant propTemp; - RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &propTemp)) - if (propTemp.vt == VT_BOOL) - isAnti = VARIANT_BOOLToBool(propTemp.boolVal); - } - - RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)) - switch (prop.vt) - { - case VT_EMPTY: _processedFileInfo.MTime = _defaultMTime; break; - case VT_FILETIME: _processedFileInfo.MTime = prop.filetime; break; - default: return E_FAIL; - } - - UStringVector pathParts; - SplitPathToParts(fullPath, pathParts); - if (pathParts.IsEmpty()) - return E_FAIL; - - UString processedPath = fullPath; - - if (!_processedFileInfo.IsDir) - pathParts.DeleteBack(); - if (!pathParts.IsEmpty()) - { - if (!isAnti) - CreateComplexDirectory(pathParts); - } - - FString fullProcessedPath = _directoryPath + us2fs(processedPath); - - if (_processedFileInfo.IsDir) - { - _diskFilePath = fullProcessedPath; - - if (isAnti) - RemoveDir(_diskFilePath); - else - SetDirTime(_diskFilePath, NULL, NULL, &_processedFileInfo.MTime); - return S_OK; - } - - NFind::CFileInfo fileInfo; - if (fileInfo.Find(fullProcessedPath)) - { - if (!DeleteFileAlways(fullProcessedPath)) - { - _message = kCantDeleteFile; - return E_FAIL; - } - } - - if (!isAnti) - { - _outFileStreamSpec = new COutFileStream; - CMyComPtr outStreamLoc(_outFileStreamSpec); - if (!_outFileStreamSpec->Create_ALWAYS(fullProcessedPath)) - { - _message = kCantOpenFile; - return E_FAIL; - } - _outFileStream = outStreamLoc; - *outStream = outStreamLoc.Detach(); - } - _diskFilePath = fullProcessedPath; - } - else - { - *outStream = NULL; - } - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)) -{ - _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract); - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult)) -{ - switch (resultEOperationResult) - { - case NArchive::NExtract::NOperationResult::kOK: - break; - - default: - { - _outFileStream.Release(); - switch (resultEOperationResult) - { - case NArchive::NExtract::NOperationResult::kUnsupportedMethod: - _message = kUnsupportedMethod; - break; - default: - _isCorrupt = true; - } - return E_FAIL; - } - } - if (_outFileStream != NULL) - { - _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); - RINOK(_outFileStreamSpec->Close()) - } - _outFileStream.Release(); - if (_extractMode) - SetFileAttrib(_diskFilePath, _processedFileInfo.Attributes); - return S_OK; -} +// ExtractCallbackSfx.h + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "ExtractCallbackSfx.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static LPCSTR const kCantDeleteFile = "Cannot delete output file"; +static LPCSTR const kCantOpenFile = "Cannot open output file"; +static LPCSTR const kUnsupportedMethod = "Unsupported Method"; + +void CExtractCallbackImp::Init(IInArchive *archiveHandler, + const FString &directoryPath, + const UString &itemDefaultName, + const FILETIME &defaultMTime, + UInt32 defaultAttributes) +{ + _message.Empty(); + _isCorrupt = false; + _itemDefaultName = itemDefaultName; + _defaultMTime = defaultMTime; + _defaultAttributes = defaultAttributes; + _archiveHandler = archiveHandler; + _directoryPath = directoryPath; + NName::NormalizeDirPathPrefix(_directoryPath); +} + +HRESULT CExtractCallbackImp::Open_CheckBreak() +{ + #ifndef _NO_PROGRESS + return ProgressDialog.Sync.ProcessStopAndPause(); + #else + return S_OK; + #endif +} + +HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) +{ + return S_OK; +} + +HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) +{ + #ifndef _NO_PROGRESS + return ProgressDialog.Sync.ProcessStopAndPause(); + #else + return S_OK; + #endif +} + +HRESULT CExtractCallbackImp::Open_Finished() +{ + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 size)) +{ + #ifndef _NO_PROGRESS + ProgressDialog.Sync.SetProgress(size, 0); + #endif + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)) +{ + #ifndef _NO_PROGRESS + RINOK(ProgressDialog.Sync.ProcessStopAndPause()) + if (completeValue != NULL) + ProgressDialog.Sync.SetPos(*completeValue); + #endif + return S_OK; +} + +void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts) +{ + FString fullPath = _directoryPath; + FOR_VECTOR (i, dirPathParts) + { + fullPath += us2fs(dirPathParts[i]); + CreateDir(fullPath); + fullPath.Add_PathSepar(); + } +} + +Z7_COM7F_IMF(CExtractCallbackImp::GetStream(UInt32 index, + ISequentialOutStream **outStream, Int32 askExtractMode)) +{ + #ifndef _NO_PROGRESS + if (ProgressDialog.Sync.GetStopped()) + return E_ABORT; + #endif + _outFileStream.Release(); + + UString fullPath; + { + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop)) + if (prop.vt == VT_EMPTY) + fullPath = _itemDefaultName; + else + { + if (prop.vt != VT_BSTR) + return E_FAIL; + fullPath.SetFromBstr(prop.bstrVal); + } + _filePath = fullPath; + } + + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract) + { + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop)) + if (prop.vt == VT_EMPTY) + _processedFileInfo.Attributes = _defaultAttributes; + else + { + if (prop.vt != VT_UI4) + return E_FAIL; + _processedFileInfo.Attributes = prop.ulVal; + } + + RINOK(_archiveHandler->GetProperty(index, kpidIsDir, &prop)) + _processedFileInfo.IsDir = VARIANT_BOOLToBool(prop.boolVal); + + bool isAnti = false; + { + NCOM::CPropVariant propTemp; + RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &propTemp)) + if (propTemp.vt == VT_BOOL) + isAnti = VARIANT_BOOLToBool(propTemp.boolVal); + } + + RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)) + switch (prop.vt) + { + case VT_EMPTY: _processedFileInfo.MTime = _defaultMTime; break; + case VT_FILETIME: _processedFileInfo.MTime = prop.filetime; break; + default: return E_FAIL; + } + + UStringVector pathParts; + SplitPathToParts(fullPath, pathParts); + if (pathParts.IsEmpty()) + return E_FAIL; + + UString processedPath = fullPath; + + if (!_processedFileInfo.IsDir) + pathParts.DeleteBack(); + if (!pathParts.IsEmpty()) + { + if (!isAnti) + CreateComplexDirectory(pathParts); + } + + FString fullProcessedPath = _directoryPath + us2fs(processedPath); + + if (_processedFileInfo.IsDir) + { + _diskFilePath = fullProcessedPath; + + if (isAnti) + RemoveDir(_diskFilePath); + else + SetDirTime(_diskFilePath, NULL, NULL, &_processedFileInfo.MTime); + return S_OK; + } + + NFind::CFileInfo fileInfo; + if (fileInfo.Find(fullProcessedPath)) + { + if (!DeleteFileAlways(fullProcessedPath)) + { + _message = kCantDeleteFile; + return E_FAIL; + } + } + + if (!isAnti) + { + _outFileStreamSpec = new COutFileStream; + CMyComPtr outStreamLoc(_outFileStreamSpec); + if (!_outFileStreamSpec->Create_ALWAYS(fullProcessedPath)) + { + _message = kCantOpenFile; + return E_FAIL; + } + _outFileStream = outStreamLoc; + *outStream = outStreamLoc.Detach(); + } + _diskFilePath = fullProcessedPath; + } + else + { + *outStream = NULL; + } + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)) +{ + _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract); + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult)) +{ + switch (resultEOperationResult) + { + case NArchive::NExtract::NOperationResult::kOK: + break; + + default: + { + _outFileStream.Release(); + switch (resultEOperationResult) + { + case NArchive::NExtract::NOperationResult::kUnsupportedMethod: + _message = kUnsupportedMethod; + break; + default: + _isCorrupt = true; + } + return E_FAIL; + } + } + if (_outFileStream != NULL) + { + _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); + RINOK(_outFileStreamSpec->Close()) + } + _outFileStream.Release(); + if (_extractMode) + SetFileAttrib(_diskFilePath, _processedFileInfo.Attributes); + return S_OK; +} diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h index 08ff6cc08..b9377ae65 100644 --- a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h +++ b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h @@ -1,83 +1,83 @@ -// ExtractCallbackSfx.h - -#ifndef ZIP7_INC_EXTRACT_CALLBACK_SFX_H -#define ZIP7_INC_EXTRACT_CALLBACK_SFX_H - -#include "resource.h" - -#include "../../../Windows/ResourceString.h" - -#include "../../Archive/IArchive.h" - -#include "../../Common/FileStreams.h" -#include "../../ICoder.h" - -#include "../../UI/FileManager/LangUtils.h" - -#ifndef _NO_PROGRESS -#include "../../UI/FileManager/ProgressDialog.h" -#endif -#include "../../UI/Common/ArchiveOpenCallback.h" - -class CExtractCallbackImp Z7_final: - public IArchiveExtractCallback, - public IOpenCallbackUI, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IArchiveExtractCallback) - Z7_IFACE_IMP(IOpenCallbackUI) - - CMyComPtr _archiveHandler; - FString _directoryPath; - UString _filePath; - FString _diskFilePath; - - bool _extractMode; - struct CProcessedFileInfo - { - FILETIME MTime; - bool IsDir; - UInt32 Attributes; - } _processedFileInfo; - - COutFileStream *_outFileStreamSpec; - CMyComPtr _outFileStream; - - UString _itemDefaultName; - FILETIME _defaultMTime; - UInt32 _defaultAttributes; - - void CreateComplexDirectory(const UStringVector &dirPathParts); -public: - #ifndef _NO_PROGRESS - CProgressDialog ProgressDialog; - #endif - - bool _isCorrupt; - UString _message; - - void Init(IInArchive *archiveHandler, - const FString &directoryPath, - const UString &itemDefaultName, - const FILETIME &defaultMTime, - UInt32 defaultAttributes); - - #ifndef _NO_PROGRESS - HRESULT StartProgressDialog(const UString &title, NWindows::CThread &thread) - { - ProgressDialog.Create(title, thread, NULL); - { - ProgressDialog.SetText(LangString(IDS_PROGRESS_EXTRACTING)); - } - - ProgressDialog.Show(SW_SHOWNORMAL); - return S_OK; - } - ~CExtractCallbackImp() { ProgressDialog.Destroy(); } - #endif - -}; - -#endif +// ExtractCallbackSfx.h + +#ifndef ZIP7_INC_EXTRACT_CALLBACK_SFX_H +#define ZIP7_INC_EXTRACT_CALLBACK_SFX_H + +#include "resource.h" + +#include "../../../Windows/ResourceString.h" + +#include "../../Archive/IArchive.h" + +#include "../../Common/FileStreams.h" +#include "../../ICoder.h" + +#include "../../UI/FileManager/LangUtils.h" + +#ifndef _NO_PROGRESS +#include "../../UI/FileManager/ProgressDialog.h" +#endif +#include "../../UI/Common/ArchiveOpenCallback.h" + +class CExtractCallbackImp Z7_final: + public IArchiveExtractCallback, + public IOpenCallbackUI, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IArchiveExtractCallback) + Z7_IFACE_IMP(IOpenCallbackUI) + + CMyComPtr _archiveHandler; + FString _directoryPath; + UString _filePath; + FString _diskFilePath; + + bool _extractMode; + struct CProcessedFileInfo + { + FILETIME MTime; + bool IsDir; + UInt32 Attributes; + } _processedFileInfo; + + COutFileStream *_outFileStreamSpec; + CMyComPtr _outFileStream; + + UString _itemDefaultName; + FILETIME _defaultMTime; + UInt32 _defaultAttributes; + + void CreateComplexDirectory(const UStringVector &dirPathParts); +public: + #ifndef _NO_PROGRESS + CProgressDialog ProgressDialog; + #endif + + bool _isCorrupt; + UString _message; + + void Init(IInArchive *archiveHandler, + const FString &directoryPath, + const UString &itemDefaultName, + const FILETIME &defaultMTime, + UInt32 defaultAttributes); + + #ifndef _NO_PROGRESS + HRESULT StartProgressDialog(const UString &title, NWindows::CThread &thread) + { + ProgressDialog.Create(title, thread, NULL); + { + ProgressDialog.SetText(LangString(IDS_PROGRESS_EXTRACTING)); + } + + ProgressDialog.Show(SW_SHOWNORMAL); + return S_OK; + } + ~CExtractCallbackImp() { ProgressDialog.Destroy(); } + #endif + +}; + +#endif diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp index 356528794..73ccff1b7 100644 --- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp +++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp @@ -1,135 +1,135 @@ -// ExtractEngine.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Thread.h" - -#include "../../UI/Common/OpenArchive.h" - -#include "../../UI/FileManager/FormatUtils.h" -#include "../../UI/FileManager/LangUtils.h" - -#include "ExtractCallbackSfx.h" -#include "ExtractEngine.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static LPCSTR const kCantFindArchive = "Cannot find archive file"; -static LPCSTR const kCantOpenArchive = "Cannot open the file as archive"; - -struct CThreadExtracting -{ - CCodecs *Codecs; - FString FileName; - FString DestFolder; - - CExtractCallbackImp *ExtractCallbackSpec; - CMyComPtr ExtractCallback; - - CArchiveLink ArchiveLink; - HRESULT Result; - UString ErrorMessage; - - void Process2() - { - NFind::CFileInfo fi; - if (!fi.Find(FileName)) - { - ErrorMessage = kCantFindArchive; - Result = E_FAIL; - return; - } - - CObjectVector incl; - CIntVector excl; - COpenOptions options; - options.codecs = Codecs; - options.types = &incl; - options.excludedFormats = ! - options.filePath = fs2us(FileName); - - Result = ArchiveLink.Open2(options, ExtractCallbackSpec); - if (Result != S_OK) - { - ErrorMessage = kCantOpenArchive; - return; - } - - FString dirPath = DestFolder; - NName::NormalizeDirPathPrefix(dirPath); - - if (!CreateComplexDir(dirPath)) - { - ErrorMessage = MyFormatNew(IDS_CANNOT_CREATE_FOLDER, fs2us(dirPath)); - Result = E_FAIL; - return; - } - - ExtractCallbackSpec->Init(ArchiveLink.GetArchive(), dirPath, (UString)"Default", fi.MTime, 0); - - Result = ArchiveLink.GetArchive()->Extract(NULL, (UInt32)(Int32)-1 , BoolToInt(false), ExtractCallback); - } - - void Process() - { - try - { - #ifndef _NO_PROGRESS - CProgressCloser closer(ExtractCallbackSpec->ProgressDialog); - #endif - Process2(); - } - catch(...) { Result = E_FAIL; } - } - - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - ((CThreadExtracting *)param)->Process(); - return 0; - } -}; - -HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder, - bool showProgress, bool &isCorrupt, UString &errorMessage) -{ - isCorrupt = false; - CThreadExtracting t; - - t.Codecs = codecs; - t.FileName = fileName; - t.DestFolder = destFolder; - - t.ExtractCallbackSpec = new CExtractCallbackImp; - t.ExtractCallback = t.ExtractCallbackSpec; - - #ifndef _NO_PROGRESS - - if (showProgress) - { - t.ExtractCallbackSpec->ProgressDialog.IconID = IDI_ICON; - NWindows::CThread thread; - const WRes wres = thread.Create(CThreadExtracting::MyThreadFunction, &t); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - - UString title; - LangString(IDS_PROGRESS_EXTRACTING, title); - t.ExtractCallbackSpec->StartProgressDialog(title, thread); - } - else - - #endif - { - t.Process2(); - } - - errorMessage = t.ErrorMessage; - if (errorMessage.IsEmpty()) - errorMessage = t.ExtractCallbackSpec->_message; - isCorrupt = t.ExtractCallbackSpec->_isCorrupt; - return t.Result; -} +// ExtractEngine.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Thread.h" + +#include "../../UI/Common/OpenArchive.h" + +#include "../../UI/FileManager/FormatUtils.h" +#include "../../UI/FileManager/LangUtils.h" + +#include "ExtractCallbackSfx.h" +#include "ExtractEngine.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static LPCSTR const kCantFindArchive = "Cannot find archive file"; +static LPCSTR const kCantOpenArchive = "Cannot open the file as archive"; + +struct CThreadExtracting +{ + CCodecs *Codecs; + FString FileName; + FString DestFolder; + + CExtractCallbackImp *ExtractCallbackSpec; + CMyComPtr ExtractCallback; + + CArchiveLink ArchiveLink; + HRESULT Result; + UString ErrorMessage; + + void Process2() + { + NFind::CFileInfo fi; + if (!fi.Find(FileName)) + { + ErrorMessage = kCantFindArchive; + Result = E_FAIL; + return; + } + + CObjectVector incl; + CIntVector excl; + COpenOptions options; + options.codecs = Codecs; + options.types = &incl; + options.excludedFormats = ! + options.filePath = fs2us(FileName); + + Result = ArchiveLink.Open2(options, ExtractCallbackSpec); + if (Result != S_OK) + { + ErrorMessage = kCantOpenArchive; + return; + } + + FString dirPath = DestFolder; + NName::NormalizeDirPathPrefix(dirPath); + + if (!CreateComplexDir(dirPath)) + { + ErrorMessage = MyFormatNew(IDS_CANNOT_CREATE_FOLDER, fs2us(dirPath)); + Result = E_FAIL; + return; + } + + ExtractCallbackSpec->Init(ArchiveLink.GetArchive(), dirPath, (UString)"Default", fi.MTime, 0); + + Result = ArchiveLink.GetArchive()->Extract(NULL, (UInt32)(Int32)-1 , BoolToInt(false), ExtractCallback); + } + + void Process() + { + try + { + #ifndef _NO_PROGRESS + CProgressCloser closer(ExtractCallbackSpec->ProgressDialog); + #endif + Process2(); + } + catch(...) { Result = E_FAIL; } + } + + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + ((CThreadExtracting *)param)->Process(); + return 0; + } +}; + +HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder, + bool showProgress, bool &isCorrupt, UString &errorMessage) +{ + isCorrupt = false; + CThreadExtracting t; + + t.Codecs = codecs; + t.FileName = fileName; + t.DestFolder = destFolder; + + t.ExtractCallbackSpec = new CExtractCallbackImp; + t.ExtractCallback = t.ExtractCallbackSpec; + + #ifndef _NO_PROGRESS + + if (showProgress) + { + t.ExtractCallbackSpec->ProgressDialog.IconID = IDI_ICON; + NWindows::CThread thread; + const WRes wres = thread.Create(CThreadExtracting::MyThreadFunction, &t); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + + UString title; + LangString(IDS_PROGRESS_EXTRACTING, title); + t.ExtractCallbackSpec->StartProgressDialog(title, thread); + } + else + + #endif + { + t.Process2(); + } + + errorMessage = t.ErrorMessage; + if (errorMessage.IsEmpty()) + errorMessage = t.ExtractCallbackSpec->_message; + isCorrupt = t.ExtractCallbackSpec->_isCorrupt; + return t.Result; +} diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h index 7245a2c91..b7f796579 100644 --- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h +++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h @@ -1,11 +1,11 @@ -// ExtractEngine.h - -#ifndef ZIP7_INC_EXTRACT_ENGINE_H -#define ZIP7_INC_EXTRACT_ENGINE_H - -#include "../../UI/Common/LoadCodecs.h" - -HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder, - bool showProgress, bool &isCorrupt, UString &errorMessage); - -#endif +// ExtractEngine.h + +#ifndef ZIP7_INC_EXTRACT_ENGINE_H +#define ZIP7_INC_EXTRACT_ENGINE_H + +#include "../../UI/Common/LoadCodecs.h" + +HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder, + bool showProgress, bool &isCorrupt, UString &errorMessage); + +#endif diff --git a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp index 900361e2f..09683e28f 100644 --- a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp +++ b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp @@ -1,872 +1,872 @@ -# Microsoft Developer Studio Project File - Name="SFXSetup" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=SFXSetup - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SFXSetup.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SFXSetup.mak" CFG="SFXSetup - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SFXSetup - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "SFXSetup - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE "SFXSetup - Win32 ReleaseD" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SFXSetup - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gz /MT /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "SFXSetup - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "SFXSetup - Win32 ReleaseD" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseD" -# PROP BASE Intermediate_Dir "ReleaseD" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseD" -# PROP Intermediate_Dir "ReleaseD" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe" -# SUBTRACT BASE LINK32 /debug /nodefaultlib -# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zSD.sfx" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "SFXSetup - Win32 Release" -# Name "SFXSetup - Win32 Debug" -# Name "SFXSetup - Win32 ReleaseD" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Interface" - -# PROP Default_Filter "" -# End Group -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zItem.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeltaFilter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\TextConfig.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\TextConfig.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Group "Control" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "UI" - -# PROP Default_Filter "" -# Begin Group "Explorer" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Explorer\MyMessages.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\MyMessages.h -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.h -# End Source File -# End Group -# End Group -# Begin Group "File Manager" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\FormatUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FormatUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\LangUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgressDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgressDialog.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BraIA64.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "7zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\ExtractCallbackSfx.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractCallbackSfx.h -# End Source File -# Begin Source File - -SOURCE=.\ExtractEngine.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractEngine.h -# End Source File -# Begin Source File - -SOURCE=.\setup.ico -# End Source File -# Begin Source File - -SOURCE=.\SfxSetup.cpp -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="SFXSetup" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=SFXSetup - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SFXSetup.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SFXSetup.mak" CFG="SFXSetup - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SFXSetup - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "SFXSetup - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "SFXSetup - Win32 ReleaseD" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SFXSetup - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gz /MT /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "SFXSetup - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "SFXSetup - Win32 ReleaseD" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseD" +# PROP BASE Intermediate_Dir "ReleaseD" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseD" +# PROP Intermediate_Dir "ReleaseD" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe" +# SUBTRACT BASE LINK32 /debug /nodefaultlib +# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zSD.sfx" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "SFXSetup - Win32 Release" +# Name "SFXSetup - Win32 Debug" +# Name "SFXSetup - Win32 ReleaseD" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# End Group +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeltaFilter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\TextConfig.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\TextConfig.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "UI" + +# PROP Default_Filter "" +# Begin Group "Explorer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# End Group +# End Group +# Begin Group "File Manager" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FormatUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\LangUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgressDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgressDialog.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BraIA64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "7zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ExtractCallbackSfx.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractCallbackSfx.h +# End Source File +# Begin Source File + +SOURCE=.\ExtractEngine.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractEngine.h +# End Source File +# Begin Source File + +SOURCE=.\setup.ico +# End Source File +# Begin Source File + +SOURCE=.\SfxSetup.cpp +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw index 297037014..f563b21f2 100644 --- a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw +++ b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SFXSetup"=.\SFXSetup.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SFXSetup"=.\SFXSetup.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp index 452fb243f..eb28f5d99 100644 --- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp +++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp @@ -1,371 +1,371 @@ -// Main.cpp - -#include "StdAfx.h" - -#include "../../../../C/DllSecur.h" - -#include "../../../Common/MyWindows.h" -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/TextConfig.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/NtCheck.h" -#include "../../../Windows/ResourceString.h" - -#include "../../UI/Explorer/MyMessages.h" - -#include "ExtractEngine.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance; -extern -bool g_DisableUserQuestions; -bool g_DisableUserQuestions; - -static CFSTR const kTempDirPrefix = FTEXT("7zS"); - -#define MY_SHELL_EXECUTE - -static bool ReadDataString(CFSTR fileName, LPCSTR startID, - LPCSTR endID, AString &stringResult) -{ - stringResult.Empty(); - NIO::CInFile inFile; - if (!inFile.Open(fileName)) - return false; - const size_t kBufferSize = (1 << 12); - - Byte buffer[kBufferSize]; - const unsigned signatureStartSize = MyStringLen(startID); - const unsigned signatureEndSize = MyStringLen(endID); - - size_t numBytesPrev = 0; - bool writeMode = false; - UInt64 posTotal = 0; - for (;;) - { - if (posTotal > (1 << 20)) - return (stringResult.IsEmpty()); - const size_t numReadBytes = kBufferSize - numBytesPrev; - size_t processedSize; - if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize)) - return false; - if (processedSize == 0) - return true; - const size_t numBytesInBuffer = numBytesPrev + processedSize; - UInt32 pos = 0; - for (;;) - { - if (writeMode) - { - if (pos + signatureEndSize > numBytesInBuffer) - break; - if (memcmp(buffer + pos, endID, signatureEndSize) == 0) - return true; - const Byte b = buffer[pos]; - if (b == 0) - return false; - stringResult += (char)b; - pos++; - } - else - { - if (pos + signatureStartSize > numBytesInBuffer) - break; - if (memcmp(buffer + pos, startID, signatureStartSize) == 0) - { - writeMode = true; - pos += signatureStartSize; - } - else - pos++; - } - } - numBytesPrev = numBytesInBuffer - pos; - posTotal += pos; - memmove(buffer, buffer + pos, numBytesPrev); - } -} - -static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 }; -static char kEndID[] = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 }; - -static struct CInstallIDInit -{ - CInstallIDInit() - { - kStartID[0] = ';'; - kEndID[0] = ';'; - } -} g_CInstallIDInit; - - -#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1; -#endif - -static void ShowErrorMessageSpec(const UString &name) -{ - UString message = NError::MyFormatMessage(::GetLastError()); - const int pos = message.Find(L"%1"); - if (pos >= 0) - { - message.Delete((unsigned)pos, 2); - message.Insert((unsigned)pos, name); - } - ShowErrorMessage(NULL, message); -} - -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - /* lpCmdLine */,int /* nCmdShow */) -{ - g_hInstance = (HINSTANCE)hInstance; - - NT_CHECK - - #ifdef _WIN32 - LoadSecurityDlls(); - #endif - - // InitCommonControls(); - - UString archiveName, switches; - #ifdef MY_SHELL_EXECUTE - UString executeFile, executeParameters; - #endif - NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches); - - FString fullPath; - NDLL::MyGetModuleFileName(fullPath); - - switches.Trim(); - bool assumeYes = false; - if (switches.IsPrefixedBy_Ascii_NoCase("-y")) - { - assumeYes = true; - switches = switches.Ptr(2); - switches.Trim(); - } - - AString config; - if (!ReadDataString(fullPath, kStartID, kEndID, config)) - { - if (!assumeYes) - ShowErrorMessage(L"Can't load config info"); - return 1; - } - - UString dirPrefix ("." STRING_PATH_SEPARATOR); - UString appLaunched; - bool showProgress = true; - if (!config.IsEmpty()) - { - CObjectVector pairs; - if (!GetTextConfig(config, pairs)) - { - if (!assumeYes) - ShowErrorMessage(L"Config failed"); - return 1; - } - const UString friendlyName = GetTextConfigValue(pairs, "Title"); - const UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt"); - const UString progress = GetTextConfigValue(pairs, "Progress"); - if (progress.IsEqualTo_Ascii_NoCase("no")) - showProgress = false; - const int index = FindTextConfigItem(pairs, "Directory"); - if (index >= 0) - dirPrefix = pairs[index].String; - if (!installPrompt.IsEmpty() && !assumeYes) - { - if (MessageBoxW(NULL, installPrompt, friendlyName, MB_YESNO | - MB_ICONQUESTION) != IDYES) - return 0; - } - appLaunched = GetTextConfigValue(pairs, "RunProgram"); - - #ifdef MY_SHELL_EXECUTE - executeFile = GetTextConfigValue(pairs, "ExecuteFile"); - executeParameters = GetTextConfigValue(pairs, "ExecuteParameters"); - #endif - } - - CTempDir tempDir; - if (!tempDir.Create(kTempDirPrefix)) - { - if (!assumeYes) - ShowErrorMessage(L"Cannot create temp folder archive"); - return 1; - } - - CCodecs *codecs = new CCodecs; - CMyComPtr compressCodecsInfo = codecs; - { - const HRESULT result = codecs->Load(); - if (result != S_OK) - { - ShowErrorMessage(L"Cannot load codecs"); - return 1; - } - } - - const FString tempDirPath = tempDir.GetPath(); - // tempDirPath = L"M:\\1\\"; // to test low disk space - { - bool isCorrupt = false; - UString errorMessage; - HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress, - isCorrupt, errorMessage); - - if (result != S_OK) - { - if (!assumeYes) - { - if (result == S_FALSE || isCorrupt) - { - NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage); - result = E_FAIL; - } - if (result != E_ABORT) - { - if (errorMessage.IsEmpty()) - errorMessage = NError::MyFormatMessage(result); - ::MessageBoxW(NULL, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR); - } - } - return 1; - } - } - - #ifndef UNDER_CE - CCurrentDirRestorer currentDirRestorer; - if (!SetCurrentDir(tempDirPath)) - return 1; - #endif - - HANDLE hProcess = NULL; -#ifdef MY_SHELL_EXECUTE - if (!executeFile.IsEmpty()) - { - CSysString filePath (GetSystemString(executeFile)); - SHELLEXECUTEINFO execInfo; - execInfo.cbSize = sizeof(execInfo); - execInfo.fMask = SEE_MASK_NOCLOSEPROCESS - #ifndef UNDER_CE - | SEE_MASK_FLAG_DDEWAIT - #endif - ; - execInfo.hwnd = NULL; - execInfo.lpVerb = NULL; - execInfo.lpFile = filePath; - - if (!switches.IsEmpty()) - { - executeParameters.Add_Space_if_NotEmpty(); - executeParameters += switches; - } - - const CSysString parametersSys (GetSystemString(executeParameters)); - if (parametersSys.IsEmpty()) - execInfo.lpParameters = NULL; - else - execInfo.lpParameters = parametersSys; - - execInfo.lpDirectory = NULL; - execInfo.nShow = SW_SHOWNORMAL; - execInfo.hProcess = NULL; - /* BOOL success = */ ::ShellExecuteEx(&execInfo); - UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp; - if (result <= 32) - { - if (!assumeYes) - ShowErrorMessage(L"Cannot open file"); - return 1; - } - hProcess = execInfo.hProcess; - } - else -#endif - { - if (appLaunched.IsEmpty()) - { - appLaunched = L"setup.exe"; - if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched))) - { - if (!assumeYes) - ShowErrorMessage(L"Cannot find setup.exe"); - return 1; - } - } - - { - FString s2 = tempDirPath; - NName::NormalizeDirPathPrefix(s2); - appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2)); - } - - const UString appNameForError = appLaunched; // actually we need to rtemove parameters also - - appLaunched.Replace(L"%%T", fs2us(tempDirPath)); - - if (!switches.IsEmpty()) - { - appLaunched.Add_Space(); - appLaunched += switches; - } - STARTUPINFO startupInfo; - startupInfo.cb = sizeof(startupInfo); - startupInfo.lpReserved = NULL; - startupInfo.lpDesktop = NULL; - startupInfo.lpTitle = NULL; - startupInfo.dwFlags = 0; - startupInfo.cbReserved2 = 0; - startupInfo.lpReserved2 = NULL; - - PROCESS_INFORMATION processInformation; - - const CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched)); - - const BOOL createResult = CreateProcess(NULL, - appLaunchedSys.Ptr_non_const(), - NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, - &startupInfo, &processInformation); - if (createResult == 0) - { - if (!assumeYes) - { - // we print name of exe file, if error message is - // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application". - ShowErrorMessageSpec(appNameForError); - } - return 1; - } - ::CloseHandle(processInformation.hThread); - hProcess = processInformation.hProcess; - } - if (hProcess) - { - WaitForSingleObject(hProcess, INFINITE); - ::CloseHandle(hProcess); - } - return 0; -} +// Main.cpp + +#include "StdAfx.h" + +#include "../../../../C/DllSecur.h" + +#include "../../../Common/MyWindows.h" +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/TextConfig.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/NtCheck.h" +#include "../../../Windows/ResourceString.h" + +#include "../../UI/Explorer/MyMessages.h" + +#include "ExtractEngine.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance; +extern +bool g_DisableUserQuestions; +bool g_DisableUserQuestions; + +static CFSTR const kTempDirPrefix = FTEXT("7zS"); + +#define MY_SHELL_EXECUTE + +static bool ReadDataString(CFSTR fileName, LPCSTR startID, + LPCSTR endID, AString &stringResult) +{ + stringResult.Empty(); + NIO::CInFile inFile; + if (!inFile.Open(fileName)) + return false; + const size_t kBufferSize = (1 << 12); + + Byte buffer[kBufferSize]; + const unsigned signatureStartSize = MyStringLen(startID); + const unsigned signatureEndSize = MyStringLen(endID); + + size_t numBytesPrev = 0; + bool writeMode = false; + UInt64 posTotal = 0; + for (;;) + { + if (posTotal > (1 << 20)) + return (stringResult.IsEmpty()); + const size_t numReadBytes = kBufferSize - numBytesPrev; + size_t processedSize; + if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize)) + return false; + if (processedSize == 0) + return true; + const size_t numBytesInBuffer = numBytesPrev + processedSize; + UInt32 pos = 0; + for (;;) + { + if (writeMode) + { + if (pos + signatureEndSize > numBytesInBuffer) + break; + if (memcmp(buffer + pos, endID, signatureEndSize) == 0) + return true; + const Byte b = buffer[pos]; + if (b == 0) + return false; + stringResult += (char)b; + pos++; + } + else + { + if (pos + signatureStartSize > numBytesInBuffer) + break; + if (memcmp(buffer + pos, startID, signatureStartSize) == 0) + { + writeMode = true; + pos += signatureStartSize; + } + else + pos++; + } + } + numBytesPrev = numBytesInBuffer - pos; + posTotal += pos; + memmove(buffer, buffer + pos, numBytesPrev); + } +} + +static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 }; +static char kEndID[] = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 }; + +static struct CInstallIDInit +{ + CInstallIDInit() + { + kStartID[0] = ';'; + kEndID[0] = ';'; + } +} g_CInstallIDInit; + + +#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1; +#endif + +static void ShowErrorMessageSpec(const UString &name) +{ + UString message = NError::MyFormatMessage(::GetLastError()); + const int pos = message.Find(L"%1"); + if (pos >= 0) + { + message.Delete((unsigned)pos, 2); + message.Insert((unsigned)pos, name); + } + ShowErrorMessage(NULL, message); +} + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + /* lpCmdLine */,int /* nCmdShow */) +{ + g_hInstance = (HINSTANCE)hInstance; + + NT_CHECK + + #ifdef _WIN32 + LoadSecurityDlls(); + #endif + + // InitCommonControls(); + + UString archiveName, switches; + #ifdef MY_SHELL_EXECUTE + UString executeFile, executeParameters; + #endif + NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches); + + FString fullPath; + NDLL::MyGetModuleFileName(fullPath); + + switches.Trim(); + bool assumeYes = false; + if (switches.IsPrefixedBy_Ascii_NoCase("-y")) + { + assumeYes = true; + switches = switches.Ptr(2); + switches.Trim(); + } + + AString config; + if (!ReadDataString(fullPath, kStartID, kEndID, config)) + { + if (!assumeYes) + ShowErrorMessage(L"Can't load config info"); + return 1; + } + + UString dirPrefix ("." STRING_PATH_SEPARATOR); + UString appLaunched; + bool showProgress = true; + if (!config.IsEmpty()) + { + CObjectVector pairs; + if (!GetTextConfig(config, pairs)) + { + if (!assumeYes) + ShowErrorMessage(L"Config failed"); + return 1; + } + const UString friendlyName = GetTextConfigValue(pairs, "Title"); + const UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt"); + const UString progress = GetTextConfigValue(pairs, "Progress"); + if (progress.IsEqualTo_Ascii_NoCase("no")) + showProgress = false; + const int index = FindTextConfigItem(pairs, "Directory"); + if (index >= 0) + dirPrefix = pairs[index].String; + if (!installPrompt.IsEmpty() && !assumeYes) + { + if (MessageBoxW(NULL, installPrompt, friendlyName, MB_YESNO | + MB_ICONQUESTION) != IDYES) + return 0; + } + appLaunched = GetTextConfigValue(pairs, "RunProgram"); + + #ifdef MY_SHELL_EXECUTE + executeFile = GetTextConfigValue(pairs, "ExecuteFile"); + executeParameters = GetTextConfigValue(pairs, "ExecuteParameters"); + #endif + } + + CTempDir tempDir; + if (!tempDir.Create(kTempDirPrefix)) + { + if (!assumeYes) + ShowErrorMessage(L"Cannot create temp folder archive"); + return 1; + } + + CCodecs *codecs = new CCodecs; + CMyComPtr compressCodecsInfo = codecs; + { + const HRESULT result = codecs->Load(); + if (result != S_OK) + { + ShowErrorMessage(L"Cannot load codecs"); + return 1; + } + } + + const FString tempDirPath = tempDir.GetPath(); + // tempDirPath = L"M:\\1\\"; // to test low disk space + { + bool isCorrupt = false; + UString errorMessage; + HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress, + isCorrupt, errorMessage); + + if (result != S_OK) + { + if (!assumeYes) + { + if (result == S_FALSE || isCorrupt) + { + NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage); + result = E_FAIL; + } + if (result != E_ABORT) + { + if (errorMessage.IsEmpty()) + errorMessage = NError::MyFormatMessage(result); + ::MessageBoxW(NULL, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR); + } + } + return 1; + } + } + + #ifndef UNDER_CE + CCurrentDirRestorer currentDirRestorer; + if (!SetCurrentDir(tempDirPath)) + return 1; + #endif + + HANDLE hProcess = NULL; +#ifdef MY_SHELL_EXECUTE + if (!executeFile.IsEmpty()) + { + CSysString filePath (GetSystemString(executeFile)); + SHELLEXECUTEINFO execInfo; + execInfo.cbSize = sizeof(execInfo); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS + #ifndef UNDER_CE + | SEE_MASK_FLAG_DDEWAIT + #endif + ; + execInfo.hwnd = NULL; + execInfo.lpVerb = NULL; + execInfo.lpFile = filePath; + + if (!switches.IsEmpty()) + { + executeParameters.Add_Space_if_NotEmpty(); + executeParameters += switches; + } + + const CSysString parametersSys (GetSystemString(executeParameters)); + if (parametersSys.IsEmpty()) + execInfo.lpParameters = NULL; + else + execInfo.lpParameters = parametersSys; + + execInfo.lpDirectory = NULL; + execInfo.nShow = SW_SHOWNORMAL; + execInfo.hProcess = NULL; + /* BOOL success = */ ::ShellExecuteEx(&execInfo); + UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp; + if (result <= 32) + { + if (!assumeYes) + ShowErrorMessage(L"Cannot open file"); + return 1; + } + hProcess = execInfo.hProcess; + } + else +#endif + { + if (appLaunched.IsEmpty()) + { + appLaunched = L"setup.exe"; + if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched))) + { + if (!assumeYes) + ShowErrorMessage(L"Cannot find setup.exe"); + return 1; + } + } + + { + FString s2 = tempDirPath; + NName::NormalizeDirPathPrefix(s2); + appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2)); + } + + const UString appNameForError = appLaunched; // actually we need to rtemove parameters also + + appLaunched.Replace(L"%%T", fs2us(tempDirPath)); + + if (!switches.IsEmpty()) + { + appLaunched.Add_Space(); + appLaunched += switches; + } + STARTUPINFO startupInfo; + startupInfo.cb = sizeof(startupInfo); + startupInfo.lpReserved = NULL; + startupInfo.lpDesktop = NULL; + startupInfo.lpTitle = NULL; + startupInfo.dwFlags = 0; + startupInfo.cbReserved2 = 0; + startupInfo.lpReserved2 = NULL; + + PROCESS_INFORMATION processInformation; + + const CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched)); + + const BOOL createResult = CreateProcess(NULL, + appLaunchedSys.Ptr_non_const(), + NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, + &startupInfo, &processInformation); + if (createResult == 0) + { + if (!assumeYes) + { + // we print name of exe file, if error message is + // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application". + ShowErrorMessageSpec(appNameForError); + } + return 1; + } + ::CloseHandle(processInformation.hThread); + hProcess = processInformation.hProcess; + } + if (hProcess) + { + WaitForSingleObject(hProcess, INFINITE); + ::CloseHandle(hProcess); + } + return 0; +} diff --git a/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp b/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp +++ b/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/SFXSetup/StdAfx.h b/CPP/7zip/Bundles/SFXSetup/StdAfx.h index bff4fd711..4f27255c6 100644 --- a/CPP/7zip/Bundles/SFXSetup/StdAfx.h +++ b/CPP/7zip/Bundles/SFXSetup/StdAfx.h @@ -1,6 +1,6 @@ -// StdAfx.h - -#if _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../UI/FileManager/StdAfx.h" +// StdAfx.h + +#if _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../UI/FileManager/StdAfx.h" diff --git a/CPP/7zip/Bundles/SFXSetup/makefile b/CPP/7zip/Bundles/SFXSetup/makefile index d031d0316..4f6c5fcca 100644 --- a/CPP/7zip/Bundles/SFXSetup/makefile +++ b/CPP/7zip/Bundles/SFXSetup/makefile @@ -1,121 +1,121 @@ -PROG = 7zS.sfx -MY_FIXED = 1 - -CFLAGS = $(CFLAGS) \ - -DZ7_NO_REGISTRY \ - -DZ7_EXTRACT_ONLY \ - -DZ7_NO_READ_FROM_CODER \ - -DZ7_SFX \ - -DZ7_NO_CRYPTO \ - -DZ7_NO_LONG_PATH \ - -DZ7_NO_LARGE_PAGES \ - -CURRENT_OBJS = \ - $O\SfxSetup.obj \ - $O\ExtractCallbackSfx.obj \ - $O\ExtractEngine.obj \ - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\IntToString.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\TextConfig.obj \ - $O\UTFConvert.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\ResourceString.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - $O\Window.obj \ - -WIN_CTRL_OBJS = \ - $O\Dialog.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\FileStreams.obj \ - $O\InBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\VirtThread.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveOpenCallback.obj \ - $O\DefaultName.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - -EXPLORER_OBJS = \ - $O\MyMessages.obj \ - -FM_OBJS = \ - $O\FormatUtils.obj \ - $O\ProgressDialog.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - -7Z_OBJS = \ - $O\7zDecode.obj \ - $O\7zExtract.obj \ - $O\7zHandler.obj \ - $O\7zIn.obj \ - $O\7zRegister.obj \ - -COMPRESS_OBJS = \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaRegister.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\DllSecur.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\LzmaDec.obj \ - $O\MtDec.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" -!include "../../LzmaDec.mak" - -!include "../../7zip.mak" +PROG = 7zS.sfx +MY_FIXED = 1 + +CFLAGS = $(CFLAGS) \ + -DZ7_NO_REGISTRY \ + -DZ7_EXTRACT_ONLY \ + -DZ7_NO_READ_FROM_CODER \ + -DZ7_SFX \ + -DZ7_NO_CRYPTO \ + -DZ7_NO_LONG_PATH \ + -DZ7_NO_LARGE_PAGES \ + +CURRENT_OBJS = \ + $O\SfxSetup.obj \ + $O\ExtractCallbackSfx.obj \ + $O\ExtractEngine.obj \ + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\TextConfig.obj \ + $O\UTFConvert.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\ResourceString.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + $O\Window.obj \ + +WIN_CTRL_OBJS = \ + $O\Dialog.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\FileStreams.obj \ + $O\InBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\VirtThread.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveOpenCallback.obj \ + $O\DefaultName.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + +EXPLORER_OBJS = \ + $O\MyMessages.obj \ + +FM_OBJS = \ + $O\FormatUtils.obj \ + $O\ProgressDialog.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + +7Z_OBJS = \ + $O\7zDecode.obj \ + $O\7zExtract.obj \ + $O\7zHandler.obj \ + $O\7zIn.obj \ + $O\7zRegister.obj \ + +COMPRESS_OBJS = \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaRegister.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\DllSecur.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\LzmaDec.obj \ + $O\MtDec.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" +!include "../../LzmaDec.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/SFXSetup/resource.h b/CPP/7zip/Bundles/SFXSetup/resource.h index 533197e91..d5f440bb8 100644 --- a/CPP/7zip/Bundles/SFXSetup/resource.h +++ b/CPP/7zip/Bundles/SFXSetup/resource.h @@ -1,6 +1,6 @@ -#define IDI_ICON 1 - -#define IDS_EXTRACTION_ERROR_TITLE 7 -#define IDS_EXTRACTION_ERROR_MESSAGE 8 -#define IDS_CANNOT_CREATE_FOLDER 3003 -#define IDS_PROGRESS_EXTRACTING 3300 +#define IDI_ICON 1 + +#define IDS_EXTRACTION_ERROR_TITLE 7 +#define IDS_EXTRACTION_ERROR_MESSAGE 8 +#define IDS_CANNOT_CREATE_FOLDER 3003 +#define IDS_PROGRESS_EXTRACTING 3300 diff --git a/CPP/7zip/Bundles/SFXSetup/resource.rc b/CPP/7zip/Bundles/SFXSetup/resource.rc index 9e88fd4d0..47e1b7620 100644 --- a/CPP/7zip/Bundles/SFXSetup/resource.rc +++ b/CPP/7zip/Bundles/SFXSetup/resource.rc @@ -1,16 +1,16 @@ -#include "../../MyVersionInfo.rc" -#include "resource.h" - -MY_VERSION_INFO_APP("7z Setup SFX", "7zS.sfx") - -IDI_ICON ICON "setup.ico" - -STRINGTABLE -BEGIN - IDS_EXTRACTION_ERROR_TITLE "Extraction Failed" - IDS_EXTRACTION_ERROR_MESSAGE "File is corrupt" - IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'" - IDS_PROGRESS_EXTRACTING "Extracting" -END - -#include "../../UI/FileManager/ProgressDialog.rc" +#include "../../MyVersionInfo.rc" +#include "resource.h" + +MY_VERSION_INFO_APP("7z Setup SFX", "7zS.sfx") + +IDI_ICON ICON "setup.ico" + +STRINGTABLE +BEGIN + IDS_EXTRACTION_ERROR_TITLE "Extraction Failed" + IDS_EXTRACTION_ERROR_MESSAGE "File is corrupt" + IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'" + IDS_PROGRESS_EXTRACTING "Extracting" +END + +#include "../../UI/FileManager/ProgressDialog.rc" diff --git a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp index 5032cd89c..18db7f834 100644 --- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp +++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp @@ -1,1074 +1,1074 @@ -# Microsoft Developer Studio Project File - Name="SFXWin" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=SFXWin - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SFXWin.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SFXWin.mak" CFG="SFXWin - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SFXWin - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "SFXWin - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE "SFXWin - Win32 ReleaseD" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SFXWin - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "SFXWin - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zsfx.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "SFXWin - Win32 ReleaseD" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "SFXWin___Win32_ReleaseD" -# PROP BASE Intermediate_Dir "SFXWin___Win32_ReleaseD" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "SFXWin___Win32_ReleaseD" -# PROP Intermediate_Dir "SFXWin___Win32_ReleaseD" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98 -# SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zD.sfx" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ENDIF - -# Begin Target - -# Name "SFXWin - Win32 Release" -# Name "SFXWin - Win32 Debug" -# Name "SFXWin - Win32 ReleaseD" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "7z" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zDecode.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zExtract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zHeader.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zIn.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\7z\7zRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\SplitHandler.cpp -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\CoderMixer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\MultiStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Coder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Bcj2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BcjRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchMisc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\BranchRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\DeltaFilter.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Decoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\Lzma2Register.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\LzmaRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdDecoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\PpmdRegister.cpp -# End Source File -# End Group -# Begin Group "Crypto" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAes.h -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\7zAesRegister.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Crypto\MyAes.h -# End Source File -# End Group -# Begin Group "Dialogs" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\BrowseDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ComboDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ComboDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\OverwriteDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PasswordDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PasswordDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ProgressDialog2.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CWrappers.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\InBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LockedStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\OutBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamBinder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\VirtThread.h -# End Source File -# End Group -# Begin Group "File Manager" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\FileManager\ExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\ExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FormatUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\FormatUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PropertyName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\PropertyName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SysIconUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\FileManager\SysIconUtils.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Group "Control" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Sha256Prepare.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "UI" - -# PROP Default_Filter "" -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Common\OpenArchive.h -# End Source File -# End Group -# Begin Group "GUI" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractGUI.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\GUI\ExtractGUI.h -# End Source File -# End Group -# Begin Group "Explorer" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\UI\Explorer\MyMessages.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\UI\Explorer\MyMessages.h -# End Source File -# End Group -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zStream.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Aes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\AesOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bcj2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Bra86.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\BraIA64.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Delta.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2Dec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Lzma2DecMt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\LzmaDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\MtDec.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Ppmd7Dec.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sha256Opt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "7zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7z.ico -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\SfxWin.cpp -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="SFXWin" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=SFXWin - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SFXWin.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SFXWin.mak" CFG="SFXWin - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SFXWin - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "SFXWin - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "SFXWin - Win32 ReleaseD" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SFXWin - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "SFXWin - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zsfx.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "SFXWin - Win32 ReleaseD" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "SFXWin___Win32_ReleaseD" +# PROP BASE Intermediate_Dir "SFXWin___Win32_ReleaseD" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "SFXWin___Win32_ReleaseD" +# PROP Intermediate_Dir "SFXWin___Win32_ReleaseD" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /D "Z7_NO_LONG_PATH" /D "Z7_NO_LARGE_PAGES" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98 +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zD.sfx" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "SFXWin - Win32 Release" +# Name "SFXWin - Win32 Debug" +# Name "SFXWin - Win32 ReleaseD" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\SplitHandler.cpp +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\MultiStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Coder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Bcj2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BcjRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchMisc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\BranchRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\DeltaFilter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Decoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Lzma2Register.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LzmaRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdDecoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\PpmdRegister.cpp +# End Source File +# End Group +# Begin Group "Crypto" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAes.h +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\7zAesRegister.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Crypto\MyAes.h +# End Source File +# End Group +# Begin Group "Dialogs" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\BrowseDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ComboDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ComboDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\OverwriteDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PasswordDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PasswordDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ProgressDialog2.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CWrappers.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\VirtThread.h +# End Source File +# End Group +# Begin Group "File Manager" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\FileManager\ExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\ExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\FormatUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PropertyName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\PropertyName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SysIconUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\FileManager\SysIconUtils.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Sha256Prepare.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "UI" + +# PROP Default_Filter "" +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# End Group +# Begin Group "GUI" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\ExtractGUI.h +# End Source File +# End Group +# Begin Group "Explorer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.h +# End Source File +# End Group +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zStream.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Aes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\AesOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bcj2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Bra86.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\BraIA64.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Delta.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2Dec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Lzma2DecMt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\LzmaDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\MtDec.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Ppmd7Dec.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sha256Opt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "7zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7z.ico +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\SfxWin.cpp +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/Bundles/SFXWin/SFXWin.dsw b/CPP/7zip/Bundles/SFXWin/SFXWin.dsw index 66958036b..a9926c719 100644 --- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsw +++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SFXWin"=.\SFXWin.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SFXWin"=.\SFXWin.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp index 69de3cb39..de2ffa4b8 100644 --- a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp +++ b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp @@ -1,268 +1,268 @@ -// Main.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../../C/DllSecur.h" - -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/NtCheck.h" -#include "../../../Windows/ResourceString.h" - -#include "../../ICoder.h" -#include "../../IPassword.h" -#include "../../Archive/IArchive.h" -#include "../../UI/Common/Extract.h" -#include "../../UI/Common/ExitCode.h" -#include "../../UI/Explorer/MyMessages.h" -#include "../../UI/FileManager/MyWindowsNew.h" -#include "../../UI/GUI/ExtractGUI.h" -#include "../../UI/GUI/ExtractRes.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance; -extern -bool g_DisableUserQuestions; -bool g_DisableUserQuestions; - -#ifndef UNDER_CE - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // win2000 -#define Z7_USE_DYN_ComCtl32Version -#endif - -#ifdef Z7_USE_DYN_ComCtl32Version -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -static DWORD GetDllVersion(LPCTSTR dllName) -{ - DWORD dwVersion = 0; - const HINSTANCE hinstDll = LoadLibrary(dllName); - if (hinstDll) - { - const - DLLGETVERSIONPROC func_DllGetVersion = Z7_GET_PROC_ADDRESS( - DLLGETVERSIONPROC, hinstDll, "DllGetVersion"); - if (func_DllGetVersion) - { - DLLVERSIONINFO dvi; - ZeroMemory(&dvi, sizeof(dvi)); - dvi.cbSize = sizeof(dvi); - const HRESULT hr = func_DllGetVersion(&dvi); - if (SUCCEEDED(hr)) - dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); - } - FreeLibrary(hinstDll); - } - return dwVersion; -} - -#endif -#endif - -extern -bool g_LVN_ITEMACTIVATE_Support; -bool g_LVN_ITEMACTIVATE_Support = true; - -static const wchar_t * const kUnknownExceptionMessage = L"ERROR: Unknown Error!"; - -static void ErrorMessageForHRESULT(HRESULT res) -{ - ShowErrorMessage(HResultToMessage(res)); -} - -static int APIENTRY WinMain2() -{ - // OleInitialize is required for ProgressBar in TaskBar. -#ifndef UNDER_CE - OleInitialize(NULL); -#endif - -#ifndef UNDER_CE -#ifdef Z7_USE_DYN_ComCtl32Version - { - const DWORD g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); - g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); - } -#endif -#endif - - UString password; - bool assumeYes = false; - bool outputFolderDefined = false; - FString outputFolder; - UStringVector commandStrings; - NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); - - #ifndef UNDER_CE - if (commandStrings.Size() > 0) - commandStrings.Delete(0); - #endif - - FOR_VECTOR (i, commandStrings) - { - const UString &s = commandStrings[i]; - if (s.Len() > 1 && s[0] == '-') - { - const wchar_t c = MyCharLower_Ascii(s[1]); - if (c == 'y') - { - assumeYes = true; - if (s.Len() != 2) - { - ShowErrorMessage(L"Bad command"); - return 1; - } - } - else if (c == 'o') - { - outputFolder = us2fs(s.Ptr(2)); - NName::NormalizeDirPathPrefix(outputFolder); - outputFolderDefined = !outputFolder.IsEmpty(); - } - else if (c == 'p') - { - password = s.Ptr(2); - } - } - } - - g_DisableUserQuestions = assumeYes; - - FString path; - NDLL::MyGetModuleFileName(path); - - FString fullPath; - if (!MyGetFullPathName(path, fullPath)) - { - ShowErrorMessage(L"Error 1329484"); - return 1; - } - - CCodecs *codecs = new CCodecs; - CMyComPtr compressCodecsInfo = codecs; - HRESULT result = codecs->Load(); - if (result != S_OK) - { - ErrorMessageForHRESULT(result); - return 1; - } - - // COpenCallbackGUI openCallback; - - // openCallback.PasswordIsDefined = !password.IsEmpty(); - // openCallback.Password = password; - - CExtractCallbackImp *ecs = new CExtractCallbackImp; - CMyComPtr extractCallback = ecs; - ecs->Init(); - - #ifndef Z7_NO_CRYPTO - ecs->PasswordIsDefined = !password.IsEmpty(); - ecs->Password = password; - #endif - - CExtractOptions eo; - - FString dirPrefix; - if (!GetOnlyDirPrefix(path, dirPrefix)) - { - ShowErrorMessage(L"Error 1329485"); - return 1; - } - - eo.OutputDir = outputFolderDefined ? outputFolder : dirPrefix; - eo.YesToAll = assumeYes; - eo.OverwriteMode = assumeYes ? - NExtract::NOverwriteMode::kOverwrite : - NExtract::NOverwriteMode::kAsk; - eo.PathMode = NExtract::NPathMode::kFullPaths; - eo.TestMode = false; - - UStringVector v1, v2; - v1.Add(fs2us(fullPath)); - v2.Add(fs2us(fullPath)); - NWildcard::CCensorNode wildcardCensor; - wildcardCensor.Add_Wildcard(); - - bool messageWasDisplayed = false; - result = ExtractGUI(codecs, - CObjectVector(), CIntVector(), - v1, v2, - wildcardCensor, eo, (assumeYes ? false: true), messageWasDisplayed, ecs); - - if (result == S_OK) - { - if (!ecs->IsOK()) - return NExitCode::kFatalError; - return 0; - } - if (result == E_ABORT) - return NExitCode::kUserBreak; - if (!messageWasDisplayed) - { - if (result == S_FALSE) - ShowErrorMessage(L"Error in archive"); - else - ErrorMessageForHRESULT(result); - } - if (result == E_OUTOFMEMORY) - return NExitCode::kMemoryError; - return NExitCode::kFatalError; -} - -#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return NExitCode::kFatalError; -#endif - -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - /* lpCmdLine */, int /* nCmdShow */) -{ - g_hInstance = (HINSTANCE)hInstance; - - NT_CHECK - - try - { - #ifdef _WIN32 - LoadSecurityDlls(); - #endif - - return WinMain2(); - } - catch(const CNewException &) - { - ErrorMessageForHRESULT(E_OUTOFMEMORY); - return NExitCode::kMemoryError; - } - catch(...) - { - ShowErrorMessage(kUnknownExceptionMessage); - return NExitCode::kFatalError; - } -} +// Main.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../../C/DllSecur.h" + +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/NtCheck.h" +#include "../../../Windows/ResourceString.h" + +#include "../../ICoder.h" +#include "../../IPassword.h" +#include "../../Archive/IArchive.h" +#include "../../UI/Common/Extract.h" +#include "../../UI/Common/ExitCode.h" +#include "../../UI/Explorer/MyMessages.h" +#include "../../UI/FileManager/MyWindowsNew.h" +#include "../../UI/GUI/ExtractGUI.h" +#include "../../UI/GUI/ExtractRes.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance; +extern +bool g_DisableUserQuestions; +bool g_DisableUserQuestions; + +#ifndef UNDER_CE + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // win2000 +#define Z7_USE_DYN_ComCtl32Version +#endif + +#ifdef Z7_USE_DYN_ComCtl32Version +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +static DWORD GetDllVersion(LPCTSTR dllName) +{ + DWORD dwVersion = 0; + const HINSTANCE hinstDll = LoadLibrary(dllName); + if (hinstDll) + { + const + DLLGETVERSIONPROC func_DllGetVersion = Z7_GET_PROC_ADDRESS( + DLLGETVERSIONPROC, hinstDll, "DllGetVersion"); + if (func_DllGetVersion) + { + DLLVERSIONINFO dvi; + ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + const HRESULT hr = func_DllGetVersion(&dvi); + if (SUCCEEDED(hr)) + dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); + } + FreeLibrary(hinstDll); + } + return dwVersion; +} + +#endif +#endif + +extern +bool g_LVN_ITEMACTIVATE_Support; +bool g_LVN_ITEMACTIVATE_Support = true; + +static const wchar_t * const kUnknownExceptionMessage = L"ERROR: Unknown Error!"; + +static void ErrorMessageForHRESULT(HRESULT res) +{ + ShowErrorMessage(HResultToMessage(res)); +} + +static int APIENTRY WinMain2() +{ + // OleInitialize is required for ProgressBar in TaskBar. +#ifndef UNDER_CE + OleInitialize(NULL); +#endif + +#ifndef UNDER_CE +#ifdef Z7_USE_DYN_ComCtl32Version + { + const DWORD g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); + g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); + } +#endif +#endif + + UString password; + bool assumeYes = false; + bool outputFolderDefined = false; + FString outputFolder; + UStringVector commandStrings; + NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); + + #ifndef UNDER_CE + if (commandStrings.Size() > 0) + commandStrings.Delete(0); + #endif + + FOR_VECTOR (i, commandStrings) + { + const UString &s = commandStrings[i]; + if (s.Len() > 1 && s[0] == '-') + { + const wchar_t c = MyCharLower_Ascii(s[1]); + if (c == 'y') + { + assumeYes = true; + if (s.Len() != 2) + { + ShowErrorMessage(L"Bad command"); + return 1; + } + } + else if (c == 'o') + { + outputFolder = us2fs(s.Ptr(2)); + NName::NormalizeDirPathPrefix(outputFolder); + outputFolderDefined = !outputFolder.IsEmpty(); + } + else if (c == 'p') + { + password = s.Ptr(2); + } + } + } + + g_DisableUserQuestions = assumeYes; + + FString path; + NDLL::MyGetModuleFileName(path); + + FString fullPath; + if (!MyGetFullPathName(path, fullPath)) + { + ShowErrorMessage(L"Error 1329484"); + return 1; + } + + CCodecs *codecs = new CCodecs; + CMyComPtr compressCodecsInfo = codecs; + HRESULT result = codecs->Load(); + if (result != S_OK) + { + ErrorMessageForHRESULT(result); + return 1; + } + + // COpenCallbackGUI openCallback; + + // openCallback.PasswordIsDefined = !password.IsEmpty(); + // openCallback.Password = password; + + CExtractCallbackImp *ecs = new CExtractCallbackImp; + CMyComPtr extractCallback = ecs; + ecs->Init(); + + #ifndef Z7_NO_CRYPTO + ecs->PasswordIsDefined = !password.IsEmpty(); + ecs->Password = password; + #endif + + CExtractOptions eo; + + FString dirPrefix; + if (!GetOnlyDirPrefix(path, dirPrefix)) + { + ShowErrorMessage(L"Error 1329485"); + return 1; + } + + eo.OutputDir = outputFolderDefined ? outputFolder : dirPrefix; + eo.YesToAll = assumeYes; + eo.OverwriteMode = assumeYes ? + NExtract::NOverwriteMode::kOverwrite : + NExtract::NOverwriteMode::kAsk; + eo.PathMode = NExtract::NPathMode::kFullPaths; + eo.TestMode = false; + + UStringVector v1, v2; + v1.Add(fs2us(fullPath)); + v2.Add(fs2us(fullPath)); + NWildcard::CCensorNode wildcardCensor; + wildcardCensor.Add_Wildcard(); + + bool messageWasDisplayed = false; + result = ExtractGUI(codecs, + CObjectVector(), CIntVector(), + v1, v2, + wildcardCensor, eo, (assumeYes ? false: true), messageWasDisplayed, ecs); + + if (result == S_OK) + { + if (!ecs->IsOK()) + return NExitCode::kFatalError; + return 0; + } + if (result == E_ABORT) + return NExitCode::kUserBreak; + if (!messageWasDisplayed) + { + if (result == S_FALSE) + ShowErrorMessage(L"Error in archive"); + else + ErrorMessageForHRESULT(result); + } + if (result == E_OUTOFMEMORY) + return NExitCode::kMemoryError; + return NExitCode::kFatalError; +} + +#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return NExitCode::kFatalError; +#endif + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + /* lpCmdLine */, int /* nCmdShow */) +{ + g_hInstance = (HINSTANCE)hInstance; + + NT_CHECK + + try + { + #ifdef _WIN32 + LoadSecurityDlls(); + #endif + + return WinMain2(); + } + catch(const CNewException &) + { + ErrorMessageForHRESULT(E_OUTOFMEMORY); + return NExitCode::kMemoryError; + } + catch(...) + { + ShowErrorMessage(kUnknownExceptionMessage); + return NExitCode::kFatalError; + } +} diff --git a/CPP/7zip/Bundles/SFXWin/StdAfx.cpp b/CPP/7zip/Bundles/SFXWin/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/Bundles/SFXWin/StdAfx.cpp +++ b/CPP/7zip/Bundles/SFXWin/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Bundles/SFXWin/StdAfx.h b/CPP/7zip/Bundles/SFXWin/StdAfx.h index bff4fd711..4f27255c6 100644 --- a/CPP/7zip/Bundles/SFXWin/StdAfx.h +++ b/CPP/7zip/Bundles/SFXWin/StdAfx.h @@ -1,6 +1,6 @@ -// StdAfx.h - -#if _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../UI/FileManager/StdAfx.h" +// StdAfx.h + +#if _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../UI/FileManager/StdAfx.h" diff --git a/CPP/7zip/Bundles/SFXWin/makefile b/CPP/7zip/Bundles/SFXWin/makefile index 0e1ec331c..806bd0739 100644 --- a/CPP/7zip/Bundles/SFXWin/makefile +++ b/CPP/7zip/Bundles/SFXWin/makefile @@ -1,159 +1,159 @@ -PROG = 7z.sfx -MY_FIXED = 1 - -CFLAGS = $(CFLAGS) \ - -DZ7_NO_REGISTRY \ - -DZ7_EXTRACT_ONLY \ - -DZ7_NO_READ_FROM_CODER \ - -DZ7_SFX \ - -DZ7_NO_LONG_PATH \ - -DZ7_NO_LARGE_PAGES \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) ceshell.lib Commctrl.lib -!ELSE -LIBS = $(LIBS) comctl32.lib comdlg32.lib -!ENDIF - -CURRENT_OBJS = \ - $O\SfxWin.obj \ - -GUI_OBJS = \ - $O\ExtractDialog.obj \ - $O\ExtractGUI.obj \ - -COMMON_OBJS = \ - $O\CRC.obj \ - $O\CommandLineParser.obj \ - $O\IntToString.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\Clipboard.obj \ - $O\CommonDialog.obj \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\MemoryGlobal.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\ResourceString.obj \ - $O\Shell.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - $O\Window.obj \ - -WIN_CTRL_OBJS = \ - $O\ComboBox.obj \ - $O\Dialog.obj \ - $O\ListView.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\CWrappers.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\InBuffer.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\OutBuffer.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamBinder.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\VirtThread.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveOpenCallback.obj \ - $O\DefaultName.obj \ - $O\Extract.obj \ - $O\ExtractingFilePath.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - -EXPLORER_OBJS = \ - $O\MyMessages.obj \ - -FM_OBJS = \ - $O\BrowseDialog.obj \ - $O\ComboDialog.obj \ - $O\ExtractCallback.obj \ - $O\FormatUtils.obj \ - $O\OverwriteDialog.obj \ - $O\PasswordDialog.obj \ - $O\ProgressDialog2.obj \ - $O\PropertyName.obj \ - $O\SysIconUtils.obj \ - -AR_OBJS = \ - $O\SplitHandler.obj \ - -AR_COMMON_OBJS = \ - $O\CoderMixer2.obj \ - $O\ItemNameUtils.obj \ - $O\MultiStream.obj \ - $O\OutStreamWithCRC.obj \ - -7Z_OBJS = \ - $O\7zDecode.obj \ - $O\7zExtract.obj \ - $O\7zHandler.obj \ - $O\7zIn.obj \ - $O\7zRegister.obj \ - -COMPRESS_OBJS = \ - $O\Bcj2Coder.obj \ - $O\Bcj2Register.obj \ - $O\BcjCoder.obj \ - $O\BcjRegister.obj \ - $O\BranchMisc.obj \ - $O\BranchRegister.obj \ - $O\CopyCoder.obj \ - $O\CopyRegister.obj \ - $O\DeltaFilter.obj \ - $O\Lzma2Decoder.obj \ - $O\Lzma2Register.obj \ - $O\LzmaDecoder.obj \ - $O\LzmaRegister.obj \ - $O\PpmdDecoder.obj \ - $O\PpmdRegister.obj \ - -CRYPTO_OBJS = \ - $O\7zAes.obj \ - $O\7zAesRegister.obj \ - $O\MyAes.obj \ - -C_OBJS = \ - $O\7zStream.obj \ - $O\Alloc.obj \ - $O\Bcj2.obj \ - $O\Bra.obj \ - $O\Bra86.obj \ - $O\BraIA64.obj \ - $O\CpuArch.obj \ - $O\Delta.obj \ - $O\DllSecur.obj \ - $O\Lzma2Dec.obj \ - $O\Lzma2DecMt.obj \ - $O\LzmaDec.obj \ - $O\MtDec.obj \ - $O\Ppmd7.obj \ - $O\Ppmd7Dec.obj \ - $O\Threads.obj \ - -!include "../../Aes.mak" -!include "../../Crc.mak" -!include "../../LzmaDec.mak" -!include "../../Sha256.mak" - -!include "../../7zip.mak" +PROG = 7z.sfx +MY_FIXED = 1 + +CFLAGS = $(CFLAGS) \ + -DZ7_NO_REGISTRY \ + -DZ7_EXTRACT_ONLY \ + -DZ7_NO_READ_FROM_CODER \ + -DZ7_SFX \ + -DZ7_NO_LONG_PATH \ + -DZ7_NO_LARGE_PAGES \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) ceshell.lib Commctrl.lib +!ELSE +LIBS = $(LIBS) comctl32.lib comdlg32.lib +!ENDIF + +CURRENT_OBJS = \ + $O\SfxWin.obj \ + +GUI_OBJS = \ + $O\ExtractDialog.obj \ + $O\ExtractGUI.obj \ + +COMMON_OBJS = \ + $O\CRC.obj \ + $O\CommandLineParser.obj \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\Clipboard.obj \ + $O\CommonDialog.obj \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\MemoryGlobal.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\ResourceString.obj \ + $O\Shell.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + $O\Window.obj \ + +WIN_CTRL_OBJS = \ + $O\ComboBox.obj \ + $O\Dialog.obj \ + $O\ListView.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\CWrappers.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\InBuffer.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\VirtThread.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveOpenCallback.obj \ + $O\DefaultName.obj \ + $O\Extract.obj \ + $O\ExtractingFilePath.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + +EXPLORER_OBJS = \ + $O\MyMessages.obj \ + +FM_OBJS = \ + $O\BrowseDialog.obj \ + $O\ComboDialog.obj \ + $O\ExtractCallback.obj \ + $O\FormatUtils.obj \ + $O\OverwriteDialog.obj \ + $O\PasswordDialog.obj \ + $O\ProgressDialog2.obj \ + $O\PropertyName.obj \ + $O\SysIconUtils.obj \ + +AR_OBJS = \ + $O\SplitHandler.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\ItemNameUtils.obj \ + $O\MultiStream.obj \ + $O\OutStreamWithCRC.obj \ + +7Z_OBJS = \ + $O\7zDecode.obj \ + $O\7zExtract.obj \ + $O\7zHandler.obj \ + $O\7zIn.obj \ + $O\7zRegister.obj \ + +COMPRESS_OBJS = \ + $O\Bcj2Coder.obj \ + $O\Bcj2Register.obj \ + $O\BcjCoder.obj \ + $O\BcjRegister.obj \ + $O\BranchMisc.obj \ + $O\BranchRegister.obj \ + $O\CopyCoder.obj \ + $O\CopyRegister.obj \ + $O\DeltaFilter.obj \ + $O\Lzma2Decoder.obj \ + $O\Lzma2Register.obj \ + $O\LzmaDecoder.obj \ + $O\LzmaRegister.obj \ + $O\PpmdDecoder.obj \ + $O\PpmdRegister.obj \ + +CRYPTO_OBJS = \ + $O\7zAes.obj \ + $O\7zAesRegister.obj \ + $O\MyAes.obj \ + +C_OBJS = \ + $O\7zStream.obj \ + $O\Alloc.obj \ + $O\Bcj2.obj \ + $O\Bra.obj \ + $O\Bra86.obj \ + $O\BraIA64.obj \ + $O\CpuArch.obj \ + $O\Delta.obj \ + $O\DllSecur.obj \ + $O\Lzma2Dec.obj \ + $O\Lzma2DecMt.obj \ + $O\LzmaDec.obj \ + $O\MtDec.obj \ + $O\Ppmd7.obj \ + $O\Ppmd7Dec.obj \ + $O\Threads.obj \ + +!include "../../Aes.mak" +!include "../../Crc.mak" +!include "../../LzmaDec.mak" +!include "../../Sha256.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/Bundles/SFXWin/resource.h b/CPP/7zip/Bundles/SFXWin/resource.h index d9fae1ba6..30fe2030e 100644 --- a/CPP/7zip/Bundles/SFXWin/resource.h +++ b/CPP/7zip/Bundles/SFXWin/resource.h @@ -1 +1 @@ -#define IDI_ICON 1 +#define IDI_ICON 1 diff --git a/CPP/7zip/Bundles/SFXWin/resource.rc b/CPP/7zip/Bundles/SFXWin/resource.rc index e2f89c412..3b2217a58 100644 --- a/CPP/7zip/Bundles/SFXWin/resource.rc +++ b/CPP/7zip/Bundles/SFXWin/resource.rc @@ -1,55 +1,55 @@ -#include "../../MyVersionInfo.rc" -#include "../../GuiCommon.rc" -#include "../../UI/GUI/ExtractDialogRes.h" -#include "../../UI/FileManager/PropertyNameRes.h" - -#include "resource.h" - -MY_VERSION_INFO_APP("7z SFX", "7z.sfx") - -#define xc 240 -#define yc 64 - -IDI_ICON ICON "7z.ico" - -IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "7-Zip self-extracting archive" -BEGIN - LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 - EDITTEXT IDC_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP - DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -END - -#ifdef UNDER_CE - -#undef xc -#define xc 144 - -IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "7-Zip self-extracting archive" -BEGIN - LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 12, 8 - EDITTEXT IDC_EXTRACT_PATH, m, m + bys + 4, xc, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m, bxsDots, bys, WS_GROUP - DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -END - -#endif - -#include "../../UI/FileManager/OverwriteDialog.rc" -#include "../../UI/FileManager/PasswordDialog.rc" -#include "../../UI/FileManager/ProgressDialog2.rc" -#include "../../UI/GUI/Extract.rc" - -STRINGTABLE DISCARDABLE -BEGIN - IDS_PROP_MTIME "Modified" -END - - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "../../UI/GUI/7zG.exe.manifest" -#endif +#include "../../MyVersionInfo.rc" +#include "../../GuiCommon.rc" +#include "../../UI/GUI/ExtractDialogRes.h" +#include "../../UI/FileManager/PropertyNameRes.h" + +#include "resource.h" + +MY_VERSION_INFO_APP("7z SFX", "7z.sfx") + +#define xc 240 +#define yc 64 + +IDI_ICON ICON "7z.ico" + +IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "7-Zip self-extracting archive" +BEGIN + LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 + EDITTEXT IDC_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP + DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys +END + +#ifdef UNDER_CE + +#undef xc +#define xc 144 + +IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "7-Zip self-extracting archive" +BEGIN + LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 12, 8 + EDITTEXT IDC_EXTRACT_PATH, m, m + bys + 4, xc, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m, bxsDots, bys, WS_GROUP + DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys +END + +#endif + +#include "../../UI/FileManager/OverwriteDialog.rc" +#include "../../UI/FileManager/PasswordDialog.rc" +#include "../../UI/FileManager/ProgressDialog2.rc" +#include "../../UI/GUI/Extract.rc" + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROP_MTIME "Modified" +END + + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "../../UI/GUI/7zG.exe.manifest" +#endif diff --git a/CPP/7zip/Bundles/makefile b/CPP/7zip/Bundles/makefile index 9ec86bcee..0651da541 100644 --- a/CPP/7zip/Bundles/makefile +++ b/CPP/7zip/Bundles/makefile @@ -1,19 +1,19 @@ -DIRS = \ - Alone\~ \ - Alone2\~ \ - Alone7z\~ \ - Fm\~ \ - Format7z\~ \ - Format7zF\~ \ - Format7zR\~ \ - Format7zExtract\~ \ - Format7zExtractR\~ \ - LzmaCon\~ \ - SFXCon\~ \ - SFXSetup\~ \ - SFXWin\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + Alone\~ \ + Alone2\~ \ + Alone7z\~ \ + Fm\~ \ + Format7z\~ \ + Format7zF\~ \ + Format7zR\~ \ + Format7zExtract\~ \ + Format7zExtractR\~ \ + LzmaCon\~ \ + SFXCon\~ \ + SFXSetup\~ \ + SFXWin\~ \ + +all: $(DIRS) + +$(DIRS): +!include "../SubBuild.mak" diff --git a/CPP/7zip/Common/CWrappers.cpp b/CPP/7zip/Common/CWrappers.cpp index c47105a69..d3676b728 100644 --- a/CPP/7zip/Common/CWrappers.cpp +++ b/CPP/7zip/Common/CWrappers.cpp @@ -1,358 +1,358 @@ -// CWrappers.c - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "CWrappers.h" - -#include "StreamUtils.h" - -SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw() -{ - switch (res) - { - case S_OK: return SZ_OK; - case E_OUTOFMEMORY: return SZ_ERROR_MEM; - case E_INVALIDARG: return SZ_ERROR_PARAM; - case E_ABORT: return SZ_ERROR_PROGRESS; - case S_FALSE: return SZ_ERROR_DATA; - case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED; - default: break; - } - return defaultRes; -} - - -HRESULT SResToHRESULT(SRes res) throw() -{ - switch (res) - { - case SZ_OK: return S_OK; - - case SZ_ERROR_DATA: - case SZ_ERROR_CRC: - case SZ_ERROR_INPUT_EOF: - case SZ_ERROR_ARCHIVE: - case SZ_ERROR_NO_ARCHIVE: - return S_FALSE; - - case SZ_ERROR_MEM: return E_OUTOFMEMORY; - case SZ_ERROR_PARAM: return E_INVALIDARG; - case SZ_ERROR_PROGRESS: return E_ABORT; - case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; - // case SZ_ERROR_OUTPUT_EOF: - // case SZ_ERROR_READ: - // case SZ_ERROR_WRITE: - // case SZ_ERROR_THREAD: - // case SZ_ERROR_ARCHIVE: - // case SZ_ERROR_NO_ARCHIVE: - // return E_FAIL; - default: break; - } - if (res < 0) - return res; - return E_FAIL; -} - - -#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1) - -#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x) - - -static SRes CompressProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) throw() -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CCompressProgressWrap) - p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize)); - return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS); -} - -void CCompressProgressWrap::Init(ICompressProgressInfo *progress) throw() -{ - vt.Progress = CompressProgress; - Progress = progress; - Res = SZ_OK; -} - -static const UInt32 kStreamStepSize = (UInt32)1 << 31; - -static SRes MyRead(ISeqInStreamPtr pp, void *data, size_t *size) throw() -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInStreamWrap) - UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); - p->Res = (p->Stream->Read(data, curSize, &curSize)); - *size = curSize; - p->Processed += curSize; - if (p->Res == S_OK) - return SZ_OK; - return HRESULT_To_SRes(p->Res, SZ_ERROR_READ); -} - -static size_t MyWrite(ISeqOutStreamPtr pp, const void *data, size_t size) throw() -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqOutStreamWrap) - if (p->Stream) - { - p->Res = WriteStream(p->Stream, data, size); - if (p->Res != 0) - return 0; - } - else - p->Res = S_OK; - p->Processed += size; - return size; -} - - -void CSeqInStreamWrap::Init(ISequentialInStream *stream) throw() -{ - vt.Read = MyRead; - Stream = stream; - Processed = 0; - Res = S_OK; -} - -void CSeqOutStreamWrap::Init(ISequentialOutStream *stream) throw() -{ - vt.Write = MyWrite; - Stream = stream; - Res = SZ_OK; - Processed = 0; -} - - -static SRes InStreamWrap_Read(ISeekInStreamPtr pp, void *data, size_t *size) throw() -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap) - UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); - p->Res = p->Stream->Read(data, curSize, &curSize); - *size = curSize; - return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; -} - -static SRes InStreamWrap_Seek(ISeekInStreamPtr pp, Int64 *offset, ESzSeek origin) throw() -{ - Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap) - UInt32 moveMethod; - /* we need (int)origin to eliminate the clang warning: - default label in switch which covers all enumeration values - [-Wcovered-switch-default */ - switch ((int)origin) - { - case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break; - case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break; - case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break; - default: return SZ_ERROR_PARAM; - } - UInt64 newPosition; - p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition); - *offset = (Int64)newPosition; - return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; -} - -void CSeekInStreamWrap::Init(IInStream *stream) throw() -{ - Stream = stream; - vt.Read = InStreamWrap_Read; - vt.Seek = InStreamWrap_Seek; - Res = S_OK; -} - - -/* ---------- CByteInBufWrap ---------- */ - -void CByteInBufWrap::Free() throw() -{ - ::MidFree(Buf); - Buf = NULL; -} - -bool CByteInBufWrap::Alloc(UInt32 size) throw() -{ - if (!Buf || size != Size) - { - Free(); - Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size); - Size = size; - } - return (Buf != NULL); -} - -Byte CByteInBufWrap::ReadByteFromNewBlock() throw() -{ - if (!Extra && Res == S_OK) - { - UInt32 avail; - Res = Stream->Read(Buf, Size, &avail); - Processed += (size_t)(Cur - Buf); - Cur = Buf; - Lim = Buf + avail; - if (avail != 0) - return *Cur++; - } - Extra = true; - return 0; -} - -// #pragma GCC diagnostic ignored "-Winvalid-offsetof" - -static Byte Wrap_ReadByte(IByteInPtr pp) throw() -{ - CByteInBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteInBufWrap, vt); - // Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInBufWrap) - if (p->Cur != p->Lim) - return *p->Cur++; - return p->ReadByteFromNewBlock(); -} - -CByteInBufWrap::CByteInBufWrap() throw(): Buf(NULL) -{ - vt.Read = Wrap_ReadByte; -} - - - -/* ---------- CByteOutBufWrap ---------- */ - -/* -void CLookToSequentialWrap::Free() throw() -{ - ::MidFree(BufBase); - BufBase = NULL; -} - -bool CLookToSequentialWrap::Alloc(UInt32 size) throw() -{ - if (!BufBase || size != Size) - { - Free(); - BufBase = (Byte *)::MidAlloc((size_t)size); - Size = size; - } - return (BufBase != NULL); -} -*/ - -/* -EXTERN_C_BEGIN - -void CLookToSequentialWrap_Look(ILookInSeqStreamPtr pp) -{ - CLookToSequentialWrap *p = (CLookToSequentialWrap *)pp->Obj; - - if (p->Extra || p->Res != S_OK) - return; - { - UInt32 avail; - p->Res = p->Stream->Read(p->BufBase, p->Size, &avail); - p->Processed += avail; - pp->Buf = p->BufBase; - pp->Limit = pp->Buf + avail; - if (avail == 0) - p->Extra = true; - } -} - -EXTERN_C_END -*/ - - -/* ---------- CByteOutBufWrap ---------- */ - -void CByteOutBufWrap::Free() throw() -{ - ::MidFree(Buf); - Buf = NULL; -} - -bool CByteOutBufWrap::Alloc(size_t size) throw() -{ - if (!Buf || size != Size) - { - Free(); - Buf = (Byte *)::MidAlloc(size); - Size = size; - } - return (Buf != NULL); -} - -HRESULT CByteOutBufWrap::Flush() throw() -{ - if (Res == S_OK) - { - const size_t size = (size_t)(Cur - Buf); - Res = WriteStream(Stream, Buf, size); - if (Res == S_OK) - Processed += size; - // else throw 11; - } - Cur = Buf; // reset pointer for later Wrap_WriteByte() - return Res; -} - -static void Wrap_WriteByte(IByteOutPtr pp, Byte b) throw() -{ - CByteOutBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteOutBufWrap, vt); - // Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteOutBufWrap) - Byte *dest = p->Cur; - *dest = b; - p->Cur = ++dest; - if (dest == p->Lim) - p->Flush(); -} - -CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(NULL), Size(0) -{ - vt.Write = Wrap_WriteByte; -} - - -/* ---------- CLookOutWrap ---------- */ - -/* -void CLookOutWrap::Free() throw() -{ - ::MidFree(Buf); - Buf = NULL; -} - -bool CLookOutWrap::Alloc(size_t size) throw() -{ - if (!Buf || size != Size) - { - Free(); - Buf = (Byte *)::MidAlloc(size); - Size = size; - } - return (Buf != NULL); -} - -static size_t LookOutWrap_GetOutBuf(ILookOutStreamPtr pp, void **buf) throw() -{ - CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt); - *buf = p->Buf; - return p->Size; -} - -static size_t LookOutWrap_Write(ILookOutStreamPtr pp, size_t size) throw() -{ - CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt); - if (p->Res == S_OK && size != 0) - { - p->Res = WriteStream(p->Stream, p->Buf, size); - if (p->Res == S_OK) - { - p->Processed += size; - return size; - } - } - return 0; -} - -CLookOutWrap::CLookOutWrap() throw(): Buf(NULL), Size(0) -{ - vt.GetOutBuf = LookOutWrap_GetOutBuf; - vt.Write = LookOutWrap_Write; -} -*/ +// CWrappers.c + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "CWrappers.h" + +#include "StreamUtils.h" + +SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw() +{ + switch (res) + { + case S_OK: return SZ_OK; + case E_OUTOFMEMORY: return SZ_ERROR_MEM; + case E_INVALIDARG: return SZ_ERROR_PARAM; + case E_ABORT: return SZ_ERROR_PROGRESS; + case S_FALSE: return SZ_ERROR_DATA; + case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED; + default: break; + } + return defaultRes; +} + + +HRESULT SResToHRESULT(SRes res) throw() +{ + switch (res) + { + case SZ_OK: return S_OK; + + case SZ_ERROR_DATA: + case SZ_ERROR_CRC: + case SZ_ERROR_INPUT_EOF: + case SZ_ERROR_ARCHIVE: + case SZ_ERROR_NO_ARCHIVE: + return S_FALSE; + + case SZ_ERROR_MEM: return E_OUTOFMEMORY; + case SZ_ERROR_PARAM: return E_INVALIDARG; + case SZ_ERROR_PROGRESS: return E_ABORT; + case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; + // case SZ_ERROR_OUTPUT_EOF: + // case SZ_ERROR_READ: + // case SZ_ERROR_WRITE: + // case SZ_ERROR_THREAD: + // case SZ_ERROR_ARCHIVE: + // case SZ_ERROR_NO_ARCHIVE: + // return E_FAIL; + default: break; + } + if (res < 0) + return res; + return E_FAIL; +} + + +#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1) + +#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x) + + +static SRes CompressProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) throw() +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CCompressProgressWrap) + p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize)); + return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS); +} + +void CCompressProgressWrap::Init(ICompressProgressInfo *progress) throw() +{ + vt.Progress = CompressProgress; + Progress = progress; + Res = SZ_OK; +} + +static const UInt32 kStreamStepSize = (UInt32)1 << 31; + +static SRes MyRead(ISeqInStreamPtr pp, void *data, size_t *size) throw() +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInStreamWrap) + UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); + p->Res = (p->Stream->Read(data, curSize, &curSize)); + *size = curSize; + p->Processed += curSize; + if (p->Res == S_OK) + return SZ_OK; + return HRESULT_To_SRes(p->Res, SZ_ERROR_READ); +} + +static size_t MyWrite(ISeqOutStreamPtr pp, const void *data, size_t size) throw() +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqOutStreamWrap) + if (p->Stream) + { + p->Res = WriteStream(p->Stream, data, size); + if (p->Res != 0) + return 0; + } + else + p->Res = S_OK; + p->Processed += size; + return size; +} + + +void CSeqInStreamWrap::Init(ISequentialInStream *stream) throw() +{ + vt.Read = MyRead; + Stream = stream; + Processed = 0; + Res = S_OK; +} + +void CSeqOutStreamWrap::Init(ISequentialOutStream *stream) throw() +{ + vt.Write = MyWrite; + Stream = stream; + Res = SZ_OK; + Processed = 0; +} + + +static SRes InStreamWrap_Read(ISeekInStreamPtr pp, void *data, size_t *size) throw() +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap) + UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize); + p->Res = p->Stream->Read(data, curSize, &curSize); + *size = curSize; + return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; +} + +static SRes InStreamWrap_Seek(ISeekInStreamPtr pp, Int64 *offset, ESzSeek origin) throw() +{ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap) + UInt32 moveMethod; + /* we need (int)origin to eliminate the clang warning: + default label in switch which covers all enumeration values + [-Wcovered-switch-default */ + switch ((int)origin) + { + case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break; + case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break; + case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break; + default: return SZ_ERROR_PARAM; + } + UInt64 newPosition; + p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition); + *offset = (Int64)newPosition; + return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ; +} + +void CSeekInStreamWrap::Init(IInStream *stream) throw() +{ + Stream = stream; + vt.Read = InStreamWrap_Read; + vt.Seek = InStreamWrap_Seek; + Res = S_OK; +} + + +/* ---------- CByteInBufWrap ---------- */ + +void CByteInBufWrap::Free() throw() +{ + ::MidFree(Buf); + Buf = NULL; +} + +bool CByteInBufWrap::Alloc(UInt32 size) throw() +{ + if (!Buf || size != Size) + { + Free(); + Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size); + Size = size; + } + return (Buf != NULL); +} + +Byte CByteInBufWrap::ReadByteFromNewBlock() throw() +{ + if (!Extra && Res == S_OK) + { + UInt32 avail; + Res = Stream->Read(Buf, Size, &avail); + Processed += (size_t)(Cur - Buf); + Cur = Buf; + Lim = Buf + avail; + if (avail != 0) + return *Cur++; + } + Extra = true; + return 0; +} + +// #pragma GCC diagnostic ignored "-Winvalid-offsetof" + +static Byte Wrap_ReadByte(IByteInPtr pp) throw() +{ + CByteInBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteInBufWrap, vt); + // Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInBufWrap) + if (p->Cur != p->Lim) + return *p->Cur++; + return p->ReadByteFromNewBlock(); +} + +CByteInBufWrap::CByteInBufWrap() throw(): Buf(NULL) +{ + vt.Read = Wrap_ReadByte; +} + + + +/* ---------- CByteOutBufWrap ---------- */ + +/* +void CLookToSequentialWrap::Free() throw() +{ + ::MidFree(BufBase); + BufBase = NULL; +} + +bool CLookToSequentialWrap::Alloc(UInt32 size) throw() +{ + if (!BufBase || size != Size) + { + Free(); + BufBase = (Byte *)::MidAlloc((size_t)size); + Size = size; + } + return (BufBase != NULL); +} +*/ + +/* +EXTERN_C_BEGIN + +void CLookToSequentialWrap_Look(ILookInSeqStreamPtr pp) +{ + CLookToSequentialWrap *p = (CLookToSequentialWrap *)pp->Obj; + + if (p->Extra || p->Res != S_OK) + return; + { + UInt32 avail; + p->Res = p->Stream->Read(p->BufBase, p->Size, &avail); + p->Processed += avail; + pp->Buf = p->BufBase; + pp->Limit = pp->Buf + avail; + if (avail == 0) + p->Extra = true; + } +} + +EXTERN_C_END +*/ + + +/* ---------- CByteOutBufWrap ---------- */ + +void CByteOutBufWrap::Free() throw() +{ + ::MidFree(Buf); + Buf = NULL; +} + +bool CByteOutBufWrap::Alloc(size_t size) throw() +{ + if (!Buf || size != Size) + { + Free(); + Buf = (Byte *)::MidAlloc(size); + Size = size; + } + return (Buf != NULL); +} + +HRESULT CByteOutBufWrap::Flush() throw() +{ + if (Res == S_OK) + { + const size_t size = (size_t)(Cur - Buf); + Res = WriteStream(Stream, Buf, size); + if (Res == S_OK) + Processed += size; + // else throw 11; + } + Cur = Buf; // reset pointer for later Wrap_WriteByte() + return Res; +} + +static void Wrap_WriteByte(IByteOutPtr pp, Byte b) throw() +{ + CByteOutBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteOutBufWrap, vt); + // Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteOutBufWrap) + Byte *dest = p->Cur; + *dest = b; + p->Cur = ++dest; + if (dest == p->Lim) + p->Flush(); +} + +CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(NULL), Size(0) +{ + vt.Write = Wrap_WriteByte; +} + + +/* ---------- CLookOutWrap ---------- */ + +/* +void CLookOutWrap::Free() throw() +{ + ::MidFree(Buf); + Buf = NULL; +} + +bool CLookOutWrap::Alloc(size_t size) throw() +{ + if (!Buf || size != Size) + { + Free(); + Buf = (Byte *)::MidAlloc(size); + Size = size; + } + return (Buf != NULL); +} + +static size_t LookOutWrap_GetOutBuf(ILookOutStreamPtr pp, void **buf) throw() +{ + CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt); + *buf = p->Buf; + return p->Size; +} + +static size_t LookOutWrap_Write(ILookOutStreamPtr pp, size_t size) throw() +{ + CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt); + if (p->Res == S_OK && size != 0) + { + p->Res = WriteStream(p->Stream, p->Buf, size); + if (p->Res == S_OK) + { + p->Processed += size; + return size; + } + } + return 0; +} + +CLookOutWrap::CLookOutWrap() throw(): Buf(NULL), Size(0) +{ + vt.GetOutBuf = LookOutWrap_GetOutBuf; + vt.Write = LookOutWrap_Write; +} +*/ diff --git a/CPP/7zip/Common/CWrappers.h b/CPP/7zip/Common/CWrappers.h index e4683e419..6c10a5c25 100644 --- a/CPP/7zip/Common/CWrappers.h +++ b/CPP/7zip/Common/CWrappers.h @@ -1,182 +1,182 @@ -// CWrappers.h - -#ifndef ZIP7_INC_C_WRAPPERS_H -#define ZIP7_INC_C_WRAPPERS_H - -#include "../ICoder.h" -#include "../../Common/MyCom.h" - -SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw(); -HRESULT SResToHRESULT(SRes res) throw(); - -struct CCompressProgressWrap -{ - ICompressProgress vt; - ICompressProgressInfo *Progress; - HRESULT Res; - - void Init(ICompressProgressInfo *progress) throw(); -}; - - -struct CSeqInStreamWrap -{ - ISeqInStream vt; - ISequentialInStream *Stream; - HRESULT Res; - UInt64 Processed; - - void Init(ISequentialInStream *stream) throw(); -}; - - -struct CSeekInStreamWrap -{ - ISeekInStream vt; - IInStream *Stream; - HRESULT Res; - - void Init(IInStream *stream) throw(); -}; - - -struct CSeqOutStreamWrap -{ - ISeqOutStream vt; - ISequentialOutStream *Stream; - HRESULT Res; - UInt64 Processed; - - void Init(ISequentialOutStream *stream) throw(); -}; - - -struct CByteInBufWrap -{ - IByteIn vt; - const Byte *Cur; - const Byte *Lim; - Byte *Buf; - UInt32 Size; - ISequentialInStream *Stream; - UInt64 Processed; - bool Extra; - HRESULT Res; - - CByteInBufWrap() throw(); - ~CByteInBufWrap() { Free(); } - void Free() throw(); - bool Alloc(UInt32 size) throw(); - void Init() - { - Lim = Cur = Buf; - Processed = 0; - Extra = false; - Res = S_OK; - } - UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); } - Byte ReadByteFromNewBlock() throw(); - Byte ReadByte() - { - if (Cur != Lim) - return *Cur++; - return ReadByteFromNewBlock(); - } -}; - - -/* -struct CLookToSequentialWrap -{ - Byte *BufBase; - UInt32 Size; - ISequentialInStream *Stream; - UInt64 Processed; - bool Extra; - HRESULT Res; - - CLookToSequentialWrap(): BufBase(NULL) {} - ~CLookToSequentialWrap() { Free(); } - void Free() throw(); - bool Alloc(UInt32 size) throw(); - void Init() - { - // Lim = Cur = Buf; - Processed = 0; - Extra = false; - Res = S_OK; - } - // UInt64 GetProcessed() const { return Processed + (Cur - Buf); } - - Byte ReadByteFromNewBlock() throw(); - Byte ReadByte() - { - if (Cur != Lim) - return *Cur++; - return ReadByteFromNewBlock(); - } -}; - -EXTERN_C_BEGIN -// void CLookToSequentialWrap_Look(ILookInSeqStream *pp); -EXTERN_C_END -*/ - - - -struct CByteOutBufWrap -{ - IByteOut vt; - Byte *Cur; - const Byte *Lim; - Byte *Buf; - size_t Size; - ISequentialOutStream *Stream; - UInt64 Processed; - HRESULT Res; - - CByteOutBufWrap() throw(); - ~CByteOutBufWrap() { Free(); } - void Free() throw(); - bool Alloc(size_t size) throw(); - void Init() - { - Cur = Buf; - Lim = Buf + Size; - Processed = 0; - Res = S_OK; - } - UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); } - HRESULT Flush() throw(); - void WriteByte(Byte b) - { - *Cur++ = b; - if (Cur == Lim) - Flush(); - } -}; - - -/* -struct CLookOutWrap -{ - ILookOutStream vt; - Byte *Buf; - size_t Size; - ISequentialOutStream *Stream; - UInt64 Processed; - HRESULT Res; - - CLookOutWrap() throw(); - ~CLookOutWrap() { Free(); } - void Free() throw(); - bool Alloc(size_t size) throw(); - void Init() - { - Processed = 0; - Res = S_OK; - } -}; -*/ - -#endif +// CWrappers.h + +#ifndef ZIP7_INC_C_WRAPPERS_H +#define ZIP7_INC_C_WRAPPERS_H + +#include "../ICoder.h" +#include "../../Common/MyCom.h" + +SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw(); +HRESULT SResToHRESULT(SRes res) throw(); + +struct CCompressProgressWrap +{ + ICompressProgress vt; + ICompressProgressInfo *Progress; + HRESULT Res; + + void Init(ICompressProgressInfo *progress) throw(); +}; + + +struct CSeqInStreamWrap +{ + ISeqInStream vt; + ISequentialInStream *Stream; + HRESULT Res; + UInt64 Processed; + + void Init(ISequentialInStream *stream) throw(); +}; + + +struct CSeekInStreamWrap +{ + ISeekInStream vt; + IInStream *Stream; + HRESULT Res; + + void Init(IInStream *stream) throw(); +}; + + +struct CSeqOutStreamWrap +{ + ISeqOutStream vt; + ISequentialOutStream *Stream; + HRESULT Res; + UInt64 Processed; + + void Init(ISequentialOutStream *stream) throw(); +}; + + +struct CByteInBufWrap +{ + IByteIn vt; + const Byte *Cur; + const Byte *Lim; + Byte *Buf; + UInt32 Size; + ISequentialInStream *Stream; + UInt64 Processed; + bool Extra; + HRESULT Res; + + CByteInBufWrap() throw(); + ~CByteInBufWrap() { Free(); } + void Free() throw(); + bool Alloc(UInt32 size) throw(); + void Init() + { + Lim = Cur = Buf; + Processed = 0; + Extra = false; + Res = S_OK; + } + UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); } + Byte ReadByteFromNewBlock() throw(); + Byte ReadByte() + { + if (Cur != Lim) + return *Cur++; + return ReadByteFromNewBlock(); + } +}; + + +/* +struct CLookToSequentialWrap +{ + Byte *BufBase; + UInt32 Size; + ISequentialInStream *Stream; + UInt64 Processed; + bool Extra; + HRESULT Res; + + CLookToSequentialWrap(): BufBase(NULL) {} + ~CLookToSequentialWrap() { Free(); } + void Free() throw(); + bool Alloc(UInt32 size) throw(); + void Init() + { + // Lim = Cur = Buf; + Processed = 0; + Extra = false; + Res = S_OK; + } + // UInt64 GetProcessed() const { return Processed + (Cur - Buf); } + + Byte ReadByteFromNewBlock() throw(); + Byte ReadByte() + { + if (Cur != Lim) + return *Cur++; + return ReadByteFromNewBlock(); + } +}; + +EXTERN_C_BEGIN +// void CLookToSequentialWrap_Look(ILookInSeqStream *pp); +EXTERN_C_END +*/ + + + +struct CByteOutBufWrap +{ + IByteOut vt; + Byte *Cur; + const Byte *Lim; + Byte *Buf; + size_t Size; + ISequentialOutStream *Stream; + UInt64 Processed; + HRESULT Res; + + CByteOutBufWrap() throw(); + ~CByteOutBufWrap() { Free(); } + void Free() throw(); + bool Alloc(size_t size) throw(); + void Init() + { + Cur = Buf; + Lim = Buf + Size; + Processed = 0; + Res = S_OK; + } + UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); } + HRESULT Flush() throw(); + void WriteByte(Byte b) + { + *Cur++ = b; + if (Cur == Lim) + Flush(); + } +}; + + +/* +struct CLookOutWrap +{ + ILookOutStream vt; + Byte *Buf; + size_t Size; + ISequentialOutStream *Stream; + UInt64 Processed; + HRESULT Res; + + CLookOutWrap() throw(); + ~CLookOutWrap() { Free(); } + void Free() throw(); + bool Alloc(size_t size) throw(); + void Init() + { + Processed = 0; + Res = S_OK; + } +}; +*/ + +#endif diff --git a/CPP/7zip/Common/CreateCoder.cpp b/CPP/7zip/Common/CreateCoder.cpp index d068879f0..93113a0aa 100644 --- a/CPP/7zip/Common/CreateCoder.cpp +++ b/CPP/7zip/Common/CreateCoder.cpp @@ -1,548 +1,548 @@ -// CreateCoder.cpp - -#include "StdAfx.h" - -#include "../../Windows/Defs.h" -#include "../../Windows/PropVariant.h" - -#include "CreateCoder.h" - -#include "FilterCoder.h" -#include "RegisterCodec.h" - -static const unsigned kNumCodecsMax = 64; -extern -unsigned g_NumCodecs; -unsigned g_NumCodecs = 0; -extern -const CCodecInfo *g_Codecs[]; -const CCodecInfo *g_Codecs[kNumCodecsMax]; - -// We use g_ExternalCodecs in other stages. -#ifdef Z7_EXTERNAL_CODECS -/* -extern CExternalCodecs g_ExternalCodecs; -#define CHECK_GLOBAL_CODECS \ - if (!_externalCodecs || !_externalCodecs->IsSet()) _externalCodecs = &g_ExternalCodecs; -*/ -#define CHECK_GLOBAL_CODECS -#endif - - -void RegisterCodec(const CCodecInfo *codecInfo) throw() -{ - if (g_NumCodecs < kNumCodecsMax) - g_Codecs[g_NumCodecs++] = codecInfo; -} - -static const unsigned kNumHashersMax = 16; -extern -unsigned g_NumHashers; -unsigned g_NumHashers = 0; -extern -const CHasherInfo *g_Hashers[]; -const CHasherInfo *g_Hashers[kNumHashersMax]; - -void RegisterHasher(const CHasherInfo *hashInfo) throw() -{ - if (g_NumHashers < kNumHashersMax) - g_Hashers[g_NumHashers++] = hashInfo; -} - - -#ifdef Z7_EXTERNAL_CODECS - -static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res) -{ - NWindows::NCOM::CPropVariant prop; - RINOK(codecsInfo->GetProperty(index, propID, &prop)) - if (prop.vt == VT_EMPTY) - res = 1; - else if (prop.vt == VT_UI4) - res = prop.ulVal; - else - return E_INVALIDARG; - return S_OK; -} - -static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res) -{ - NWindows::NCOM::CPropVariant prop; - RINOK(codecsInfo->GetProperty(index, propID, &prop)) - if (prop.vt == VT_EMPTY) - res = true; - else if (prop.vt == VT_BOOL) - res = VARIANT_BOOLToBool(prop.boolVal); - else - return E_INVALIDARG; - return S_OK; -} - -HRESULT CExternalCodecs::Load() -{ - Codecs.Clear(); - Hashers.Clear(); - - if (GetCodecs) - { - CCodecInfoEx info; - - UString s; - UInt32 num; - RINOK(GetCodecs->GetNumMethods(&num)) - - for (UInt32 i = 0; i < num; i++) - { - NWindows::NCOM::CPropVariant prop; - - RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop)) - if (prop.vt != VT_UI8) - continue; // old Interface - info.Id = prop.uhVal.QuadPart; - - prop.Clear(); - - info.Name.Empty(); - RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop)) - if (prop.vt == VT_BSTR) - info.Name.SetFromWStr_if_Ascii(prop.bstrVal); - else if (prop.vt != VT_EMPTY) - continue; - - RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams)) - { - UInt32 numUnpackStreams = 1; - RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams)) - if (numUnpackStreams != 1) - continue; - } - RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)) - RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)) - RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kIsFilter, info.IsFilter)) - - Codecs.Add(info); - } - } - - if (GetHashers) - { - UInt32 num = GetHashers->GetNumHashers(); - CHasherInfoEx info; - - for (UInt32 i = 0; i < num; i++) - { - NWindows::NCOM::CPropVariant prop; - - RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop)) - if (prop.vt != VT_UI8) - continue; - info.Id = prop.uhVal.QuadPart; - - prop.Clear(); - - info.Name.Empty(); - RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop)) - if (prop.vt == VT_BSTR) - info.Name.SetFromWStr_if_Ascii(prop.bstrVal); - else if (prop.vt != VT_EMPTY) - continue; - - Hashers.Add(info); - } - } - - return S_OK; -} - -#endif - - -int FindMethod_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - const AString &name, - bool encode, - CMethodId &methodId, - UInt32 &numStreams, - bool &isFilter) -{ - unsigned i; - for (i = 0; i < g_NumCodecs; i++) - { - const CCodecInfo &codec = *g_Codecs[i]; - if ((encode ? codec.CreateEncoder : codec.CreateDecoder) - && StringsAreEqualNoCase_Ascii(name, codec.Name)) - { - methodId = codec.Id; - numStreams = codec.NumStreams; - isFilter = codec.IsFilter; - return (int)i; - } - } - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (_externalCodecs) - for (i = 0; i < _externalCodecs->Codecs.Size(); i++) - { - const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; - if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned) - && StringsAreEqualNoCase_Ascii(name, codec.Name)) - { - methodId = codec.Id; - numStreams = codec.NumStreams; - isFilter = codec.IsFilter; - return (int)(g_NumCodecs + i); - } - } - - #endif - - return -1; -} - - -static int FindMethod_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode) -{ - unsigned i; - for (i = 0; i < g_NumCodecs; i++) - { - const CCodecInfo &codec = *g_Codecs[i]; - if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder)) - return (int)i; - } - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (_externalCodecs) - for (i = 0; i < _externalCodecs->Codecs.Size(); i++) - { - const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; - if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)) - return (int)(g_NumCodecs + i); - } - - #endif - - return -1; -} - - -bool FindMethod( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, - AString &name) -{ - name.Empty(); - - unsigned i; - for (i = 0; i < g_NumCodecs; i++) - { - const CCodecInfo &codec = *g_Codecs[i]; - if (methodId == codec.Id) - { - name = codec.Name; - return true; - } - } - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (_externalCodecs) - for (i = 0; i < _externalCodecs->Codecs.Size(); i++) - { - const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; - if (methodId == codec.Id) - { - name = codec.Name; - return true; - } - } - - #endif - - return false; -} - -bool FindHashMethod( - DECL_EXTERNAL_CODECS_LOC_VARS - const AString &name, - CMethodId &methodId) -{ - unsigned i; - for (i = 0; i < g_NumHashers; i++) - { - const CHasherInfo &codec = *g_Hashers[i]; - if (StringsAreEqualNoCase_Ascii(name, codec.Name)) - { - methodId = codec.Id; - return true; - } - } - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (_externalCodecs) - for (i = 0; i < _externalCodecs->Hashers.Size(); i++) - { - const CHasherInfoEx &codec = _externalCodecs->Hashers[i]; - if (StringsAreEqualNoCase_Ascii(name, codec.Name)) - { - methodId = codec.Id; - return true; - } - } - - #endif - - return false; -} - -void GetHashMethods( - DECL_EXTERNAL_CODECS_LOC_VARS - CRecordVector &methods) -{ - methods.ClearAndSetSize(g_NumHashers); - unsigned i; - for (i = 0; i < g_NumHashers; i++) - methods[i] = (*g_Hashers[i]).Id; - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (_externalCodecs) - for (i = 0; i < _externalCodecs->Hashers.Size(); i++) - methods.Add(_externalCodecs->Hashers[i].Id); - - #endif -} - - - -HRESULT CreateCoder_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - unsigned i, bool encode, - CMyComPtr &filter, - CCreatedCoder &cod) -{ - cod.IsExternal = false; - cod.IsFilter = false; - cod.NumStreams = 1; - - if (i < g_NumCodecs) - { - const CCodecInfo &codec = *g_Codecs[i]; - // if (codec.Id == methodId) - { - if (encode) - { - if (codec.CreateEncoder) - { - void *p = codec.CreateEncoder(); - if (codec.IsFilter) filter = (ICompressFilter *)p; - else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p; - else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; } - return S_OK; - } - } - else - if (codec.CreateDecoder) - { - void *p = codec.CreateDecoder(); - if (codec.IsFilter) filter = (ICompressFilter *)p; - else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p; - else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; } - return S_OK; - } - } - } - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (_externalCodecs) - { - i -= g_NumCodecs; - cod.IsExternal = true; - if (i < _externalCodecs->Codecs.Size()) - { - const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; - // if (codec.Id == methodId) - { - if (encode) - { - if (codec.EncoderIsAssigned) - { - if (codec.NumStreams == 1) - { - const HRESULT res = _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder); - if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE) - return res; - if (cod.Coder) - return res; - return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter); - } - cod.NumStreams = codec.NumStreams; - return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2); - } - } - else - if (codec.DecoderIsAssigned) - { - if (codec.NumStreams == 1) - { - const HRESULT res = _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder); - if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE) - return res; - if (cod.Coder) - return res; - return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter); - } - cod.NumStreams = codec.NumStreams; - return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2); - } - } - } - } - #endif - - return S_OK; -} - - -HRESULT CreateCoder_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - unsigned index, bool encode, - CCreatedCoder &cod) -{ - CMyComPtr filter; - const HRESULT res = CreateCoder_Index( - EXTERNAL_CODECS_LOC_VARS - index, encode, - filter, cod); - - if (filter) - { - cod.IsFilter = true; - CFilterCoder *coderSpec = new CFilterCoder(encode); - cod.Coder = coderSpec; - coderSpec->Filter = filter; - } - - return res; -} - - -HRESULT CreateCoder_Id( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &filter, - CCreatedCoder &cod) -{ - const int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode); - if (index < 0) - return S_OK; - return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)index, encode, filter, cod); -} - - -HRESULT CreateCoder_Id( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CCreatedCoder &cod) -{ - CMyComPtr filter; - const HRESULT res = CreateCoder_Id( - EXTERNAL_CODECS_LOC_VARS - methodId, encode, - filter, cod); - - if (filter) - { - cod.IsFilter = true; - CFilterCoder *coderSpec = new CFilterCoder(encode); - cod.Coder = coderSpec; - coderSpec->Filter = filter; - } - - return res; -} - - -HRESULT CreateCoder_Id( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &coder) -{ - CCreatedCoder cod; - const HRESULT res = CreateCoder_Id( - EXTERNAL_CODECS_LOC_VARS - methodId, encode, - cod); - coder = cod.Coder; - return res; -} - -HRESULT CreateFilter( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &filter) -{ - CCreatedCoder cod; - return CreateCoder_Id( - EXTERNAL_CODECS_LOC_VARS - methodId, encode, - filter, cod); -} - - -HRESULT CreateHasher( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, - AString &name, - CMyComPtr &hasher) -{ - name.Empty(); - - unsigned i; - for (i = 0; i < g_NumHashers; i++) - { - const CHasherInfo &codec = *g_Hashers[i]; - if (codec.Id == methodId) - { - hasher = codec.CreateHasher(); - name = codec.Name; - break; - } - } - - #ifdef Z7_EXTERNAL_CODECS - - CHECK_GLOBAL_CODECS - - if (!hasher && _externalCodecs) - for (i = 0; i < _externalCodecs->Hashers.Size(); i++) - { - const CHasherInfoEx &codec = _externalCodecs->Hashers[i]; - if (codec.Id == methodId) - { - name = codec.Name; - return _externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher); - } - } - - #endif - - return S_OK; -} +// CreateCoder.cpp + +#include "StdAfx.h" + +#include "../../Windows/Defs.h" +#include "../../Windows/PropVariant.h" + +#include "CreateCoder.h" + +#include "FilterCoder.h" +#include "RegisterCodec.h" + +static const unsigned kNumCodecsMax = 64; +extern +unsigned g_NumCodecs; +unsigned g_NumCodecs = 0; +extern +const CCodecInfo *g_Codecs[]; +const CCodecInfo *g_Codecs[kNumCodecsMax]; + +// We use g_ExternalCodecs in other stages. +#ifdef Z7_EXTERNAL_CODECS +/* +extern CExternalCodecs g_ExternalCodecs; +#define CHECK_GLOBAL_CODECS \ + if (!_externalCodecs || !_externalCodecs->IsSet()) _externalCodecs = &g_ExternalCodecs; +*/ +#define CHECK_GLOBAL_CODECS +#endif + + +void RegisterCodec(const CCodecInfo *codecInfo) throw() +{ + if (g_NumCodecs < kNumCodecsMax) + g_Codecs[g_NumCodecs++] = codecInfo; +} + +static const unsigned kNumHashersMax = 32; +extern +unsigned g_NumHashers; +unsigned g_NumHashers = 0; +extern +const CHasherInfo *g_Hashers[]; +const CHasherInfo *g_Hashers[kNumHashersMax]; + +void RegisterHasher(const CHasherInfo *hashInfo) throw() +{ + if (g_NumHashers < kNumHashersMax) + g_Hashers[g_NumHashers++] = hashInfo; +} + + +#ifdef Z7_EXTERNAL_CODECS + +static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res) +{ + NWindows::NCOM::CPropVariant prop; + RINOK(codecsInfo->GetProperty(index, propID, &prop)) + if (prop.vt == VT_EMPTY) + res = 1; + else if (prop.vt == VT_UI4) + res = prop.ulVal; + else + return E_INVALIDARG; + return S_OK; +} + +static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res) +{ + NWindows::NCOM::CPropVariant prop; + RINOK(codecsInfo->GetProperty(index, propID, &prop)) + if (prop.vt == VT_EMPTY) + res = true; + else if (prop.vt == VT_BOOL) + res = VARIANT_BOOLToBool(prop.boolVal); + else + return E_INVALIDARG; + return S_OK; +} + +HRESULT CExternalCodecs::Load() +{ + Codecs.Clear(); + Hashers.Clear(); + + if (GetCodecs) + { + CCodecInfoEx info; + + UString s; + UInt32 num; + RINOK(GetCodecs->GetNumMethods(&num)) + + for (UInt32 i = 0; i < num; i++) + { + NWindows::NCOM::CPropVariant prop; + + RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop)) + if (prop.vt != VT_UI8) + continue; // old Interface + info.Id = prop.uhVal.QuadPart; + + prop.Clear(); + + info.Name.Empty(); + RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop)) + if (prop.vt == VT_BSTR) + info.Name.SetFromWStr_if_Ascii(prop.bstrVal); + else if (prop.vt != VT_EMPTY) + continue; + + RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams)) + { + UInt32 numUnpackStreams = 1; + RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams)) + if (numUnpackStreams != 1) + continue; + } + RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)) + RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)) + RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kIsFilter, info.IsFilter)) + + Codecs.Add(info); + } + } + + if (GetHashers) + { + UInt32 num = GetHashers->GetNumHashers(); + CHasherInfoEx info; + + for (UInt32 i = 0; i < num; i++) + { + NWindows::NCOM::CPropVariant prop; + + RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop)) + if (prop.vt != VT_UI8) + continue; + info.Id = prop.uhVal.QuadPart; + + prop.Clear(); + + info.Name.Empty(); + RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop)) + if (prop.vt == VT_BSTR) + info.Name.SetFromWStr_if_Ascii(prop.bstrVal); + else if (prop.vt != VT_EMPTY) + continue; + + Hashers.Add(info); + } + } + + return S_OK; +} + +#endif + + +int FindMethod_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + const AString &name, + bool encode, + CMethodId &methodId, + UInt32 &numStreams, + bool &isFilter) +{ + unsigned i; + for (i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &codec = *g_Codecs[i]; + if ((encode ? codec.CreateEncoder : codec.CreateDecoder) + && StringsAreEqualNoCase_Ascii(name, codec.Name)) + { + methodId = codec.Id; + numStreams = codec.NumStreams; + isFilter = codec.IsFilter; + return (int)i; + } + } + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (_externalCodecs) + for (i = 0; i < _externalCodecs->Codecs.Size(); i++) + { + const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; + if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned) + && StringsAreEqualNoCase_Ascii(name, codec.Name)) + { + methodId = codec.Id; + numStreams = codec.NumStreams; + isFilter = codec.IsFilter; + return (int)(g_NumCodecs + i); + } + } + + #endif + + return -1; +} + + +static int FindMethod_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode) +{ + unsigned i; + for (i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &codec = *g_Codecs[i]; + if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder)) + return (int)i; + } + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (_externalCodecs) + for (i = 0; i < _externalCodecs->Codecs.Size(); i++) + { + const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; + if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)) + return (int)(g_NumCodecs + i); + } + + #endif + + return -1; +} + + +bool FindMethod( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, + AString &name) +{ + name.Empty(); + + unsigned i; + for (i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &codec = *g_Codecs[i]; + if (methodId == codec.Id) + { + name = codec.Name; + return true; + } + } + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (_externalCodecs) + for (i = 0; i < _externalCodecs->Codecs.Size(); i++) + { + const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; + if (methodId == codec.Id) + { + name = codec.Name; + return true; + } + } + + #endif + + return false; +} + +bool FindHashMethod( + DECL_EXTERNAL_CODECS_LOC_VARS + const AString &name, + CMethodId &methodId) +{ + unsigned i; + for (i = 0; i < g_NumHashers; i++) + { + const CHasherInfo &codec = *g_Hashers[i]; + if (StringsAreEqualNoCase_Ascii(name, codec.Name)) + { + methodId = codec.Id; + return true; + } + } + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (_externalCodecs) + for (i = 0; i < _externalCodecs->Hashers.Size(); i++) + { + const CHasherInfoEx &codec = _externalCodecs->Hashers[i]; + if (StringsAreEqualNoCase_Ascii(name, codec.Name)) + { + methodId = codec.Id; + return true; + } + } + + #endif + + return false; +} + +void GetHashMethods( + DECL_EXTERNAL_CODECS_LOC_VARS + CRecordVector &methods) +{ + methods.ClearAndSetSize(g_NumHashers); + unsigned i; + for (i = 0; i < g_NumHashers; i++) + methods[i] = (*g_Hashers[i]).Id; + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (_externalCodecs) + for (i = 0; i < _externalCodecs->Hashers.Size(); i++) + methods.Add(_externalCodecs->Hashers[i].Id); + + #endif +} + + + +HRESULT CreateCoder_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + unsigned i, bool encode, + CMyComPtr &filter, + CCreatedCoder &cod) +{ + cod.IsExternal = false; + cod.IsFilter = false; + cod.NumStreams = 1; + + if (i < g_NumCodecs) + { + const CCodecInfo &codec = *g_Codecs[i]; + // if (codec.Id == methodId) + { + if (encode) + { + if (codec.CreateEncoder) + { + void *p = codec.CreateEncoder(); + if (codec.IsFilter) filter = (ICompressFilter *)p; + else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p; + else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; } + return S_OK; + } + } + else + if (codec.CreateDecoder) + { + void *p = codec.CreateDecoder(); + if (codec.IsFilter) filter = (ICompressFilter *)p; + else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p; + else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; } + return S_OK; + } + } + } + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (_externalCodecs) + { + i -= g_NumCodecs; + cod.IsExternal = true; + if (i < _externalCodecs->Codecs.Size()) + { + const CCodecInfoEx &codec = _externalCodecs->Codecs[i]; + // if (codec.Id == methodId) + { + if (encode) + { + if (codec.EncoderIsAssigned) + { + if (codec.NumStreams == 1) + { + const HRESULT res = _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder); + if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE) + return res; + if (cod.Coder) + return res; + return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter); + } + cod.NumStreams = codec.NumStreams; + return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2); + } + } + else + if (codec.DecoderIsAssigned) + { + if (codec.NumStreams == 1) + { + const HRESULT res = _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder); + if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE) + return res; + if (cod.Coder) + return res; + return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter); + } + cod.NumStreams = codec.NumStreams; + return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2); + } + } + } + } + #endif + + return S_OK; +} + + +HRESULT CreateCoder_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + unsigned index, bool encode, + CCreatedCoder &cod) +{ + CMyComPtr filter; + const HRESULT res = CreateCoder_Index( + EXTERNAL_CODECS_LOC_VARS + index, encode, + filter, cod); + + if (filter) + { + cod.IsFilter = true; + CFilterCoder *coderSpec = new CFilterCoder(encode); + cod.Coder = coderSpec; + coderSpec->Filter = filter; + } + + return res; +} + + +HRESULT CreateCoder_Id( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &filter, + CCreatedCoder &cod) +{ + const int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode); + if (index < 0) + return S_OK; + return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)index, encode, filter, cod); +} + + +HRESULT CreateCoder_Id( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CCreatedCoder &cod) +{ + CMyComPtr filter; + const HRESULT res = CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + methodId, encode, + filter, cod); + + if (filter) + { + cod.IsFilter = true; + CFilterCoder *coderSpec = new CFilterCoder(encode); + cod.Coder = coderSpec; + coderSpec->Filter = filter; + } + + return res; +} + + +HRESULT CreateCoder_Id( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &coder) +{ + CCreatedCoder cod; + const HRESULT res = CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + methodId, encode, + cod); + coder = cod.Coder; + return res; +} + +HRESULT CreateFilter( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &filter) +{ + CCreatedCoder cod; + return CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + methodId, encode, + filter, cod); +} + + +HRESULT CreateHasher( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, + AString &name, + CMyComPtr &hasher) +{ + name.Empty(); + + unsigned i; + for (i = 0; i < g_NumHashers; i++) + { + const CHasherInfo &codec = *g_Hashers[i]; + if (codec.Id == methodId) + { + hasher = codec.CreateHasher(); + name = codec.Name; + break; + } + } + + #ifdef Z7_EXTERNAL_CODECS + + CHECK_GLOBAL_CODECS + + if (!hasher && _externalCodecs) + for (i = 0; i < _externalCodecs->Hashers.Size(); i++) + { + const CHasherInfoEx &codec = _externalCodecs->Hashers[i]; + if (codec.Id == methodId) + { + name = codec.Name; + return _externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher); + } + } + + #endif + + return S_OK; +} diff --git a/CPP/7zip/Common/CreateCoder.h b/CPP/7zip/Common/CreateCoder.h index b305f7a64..709fe83c1 100644 --- a/CPP/7zip/Common/CreateCoder.h +++ b/CPP/7zip/Common/CreateCoder.h @@ -1,200 +1,200 @@ -// CreateCoder.h - -#ifndef ZIP7_INC_CREATE_CODER_H -#define ZIP7_INC_CREATE_CODER_H - -#include "../../Common/MyCom.h" -#include "../../Common/MyString.h" - -#include "../ICoder.h" - -#include "MethodId.h" - -/* - if Z7_EXTERNAL_CODECS is not defined, the code supports only codecs that - are statically linked at compile-time and link-time. - - if Z7_EXTERNAL_CODECS is defined, the code supports also codecs from another - executable modules, that can be linked dynamically at run-time: - - EXE module can use codecs from external DLL files. - - DLL module can use codecs from external EXE and DLL files. - - CExternalCodecs contains information about codecs and interfaces to create them. - - The order of codecs: - 1) Internal codecs - 2) External codecs -*/ - -#ifdef Z7_EXTERNAL_CODECS - -struct CCodecInfoEx -{ - CMethodId Id; - AString Name; - UInt32 NumStreams; - bool EncoderIsAssigned; - bool DecoderIsAssigned; - bool IsFilter; // it's unused - - CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false), IsFilter(false) {} -}; - -struct CHasherInfoEx -{ - CMethodId Id; - AString Name; -}; - -#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC \ - public ISetCompressCodecsInfo, -#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC \ - Z7_COM_QI_ENTRY(ISetCompressCodecsInfo) -#define DECL_ISetCompressCodecsInfo \ - Z7_COM7F_IMP(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) -#define IMPL_ISetCompressCodecsInfo2(cls) \ - Z7_COM7F_IMF(cls::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) \ - { COM_TRY_BEGIN _externalCodecs.GetCodecs = compressCodecsInfo; \ - return _externalCodecs.Load(); COM_TRY_END } -#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler) - -struct CExternalCodecs -{ - CMyComPtr GetCodecs; - CMyComPtr GetHashers; - - CObjectVector Codecs; - CObjectVector Hashers; - - bool IsSet() const { return GetCodecs != NULL || GetHashers != NULL; } - - HRESULT Load(); - - void ClearAndRelease() - { - Hashers.Clear(); - Codecs.Clear(); - GetHashers.Release(); - GetCodecs.Release(); - } - - ~CExternalCodecs() - { - GetHashers.Release(); - GetCodecs.Release(); - } -}; - -extern CExternalCodecs g_ExternalCodecs; - -#define EXTERNAL_CODECS_VARS2 (_externalCodecs.IsSet() ? &_externalCodecs : &g_ExternalCodecs) -#define EXTERNAL_CODECS_VARS2_L (&_externalCodecs) -#define EXTERNAL_CODECS_VARS2_G (&g_ExternalCodecs) - -#define DECL_EXTERNAL_CODECS_VARS CExternalCodecs _externalCodecs; - -#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2, -#define EXTERNAL_CODECS_VARS_L EXTERNAL_CODECS_VARS2_L, -#define EXTERNAL_CODECS_VARS_G EXTERNAL_CODECS_VARS2_G, - -#define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *_externalCodecs -#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2, -#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL DECL_EXTERNAL_CODECS_LOC_VARS2; - -#define EXTERNAL_CODECS_LOC_VARS2 _externalCodecs -#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2, - -#else - -#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC -#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC -#define DECL_ISetCompressCodecsInfo -#define IMPL_ISetCompressCodecsInfo -#define EXTERNAL_CODECS_VARS2 -#define DECL_EXTERNAL_CODECS_VARS -#define EXTERNAL_CODECS_VARS -#define EXTERNAL_CODECS_VARS_L -#define EXTERNAL_CODECS_VARS_G -#define DECL_EXTERNAL_CODECS_LOC_VARS2 -#define DECL_EXTERNAL_CODECS_LOC_VARS -#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL -#define EXTERNAL_CODECS_LOC_VARS2 -#define EXTERNAL_CODECS_LOC_VARS - -#endif - -int FindMethod_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - const AString &name, - bool encode, - CMethodId &methodId, - UInt32 &numStreams, - bool &isFilter); - -bool FindMethod( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, - AString &name); - -bool FindHashMethod( - DECL_EXTERNAL_CODECS_LOC_VARS - const AString &name, - CMethodId &methodId); - -void GetHashMethods( - DECL_EXTERNAL_CODECS_LOC_VARS - CRecordVector &methods); - - -struct CCreatedCoder -{ - CMyComPtr Coder; - CMyComPtr Coder2; - - bool IsExternal; - bool IsFilter; // = true, if Coder was created from filter - UInt32 NumStreams; - - // CCreatedCoder(): IsExternal(false), IsFilter(false), NumStreams(1) {} -}; - - -HRESULT CreateCoder_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - unsigned codecIndex, bool encode, - CMyComPtr &filter, - CCreatedCoder &cod); - -HRESULT CreateCoder_Index( - DECL_EXTERNAL_CODECS_LOC_VARS - unsigned index, bool encode, - CCreatedCoder &cod); - -HRESULT CreateCoder_Id( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &filter, - CCreatedCoder &cod); - -HRESULT CreateCoder_Id( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CCreatedCoder &cod); - -HRESULT CreateCoder_Id( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &coder); - -HRESULT CreateFilter( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, bool encode, - CMyComPtr &filter); - -HRESULT CreateHasher( - DECL_EXTERNAL_CODECS_LOC_VARS - CMethodId methodId, - AString &name, - CMyComPtr &hasher); - -#endif +// CreateCoder.h + +#ifndef ZIP7_INC_CREATE_CODER_H +#define ZIP7_INC_CREATE_CODER_H + +#include "../../Common/MyCom.h" +#include "../../Common/MyString.h" + +#include "../ICoder.h" + +#include "MethodId.h" + +/* + if Z7_EXTERNAL_CODECS is not defined, the code supports only codecs that + are statically linked at compile-time and link-time. + + if Z7_EXTERNAL_CODECS is defined, the code supports also codecs from another + executable modules, that can be linked dynamically at run-time: + - EXE module can use codecs from external DLL files. + - DLL module can use codecs from external EXE and DLL files. + + CExternalCodecs contains information about codecs and interfaces to create them. + + The order of codecs: + 1) Internal codecs + 2) External codecs +*/ + +#ifdef Z7_EXTERNAL_CODECS + +struct CCodecInfoEx +{ + CMethodId Id; + AString Name; + UInt32 NumStreams; + bool EncoderIsAssigned; + bool DecoderIsAssigned; + bool IsFilter; // it's unused + + CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false), IsFilter(false) {} +}; + +struct CHasherInfoEx +{ + CMethodId Id; + AString Name; +}; + +#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC \ + public ISetCompressCodecsInfo, +#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC \ + Z7_COM_QI_ENTRY(ISetCompressCodecsInfo) +#define DECL_ISetCompressCodecsInfo \ + Z7_COM7F_IMP(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) +#define IMPL_ISetCompressCodecsInfo2(cls) \ + Z7_COM7F_IMF(cls::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) \ + { COM_TRY_BEGIN _externalCodecs.GetCodecs = compressCodecsInfo; \ + return _externalCodecs.Load(); COM_TRY_END } +#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler) + +struct CExternalCodecs +{ + CMyComPtr GetCodecs; + CMyComPtr GetHashers; + + CObjectVector Codecs; + CObjectVector Hashers; + + bool IsSet() const { return GetCodecs != NULL || GetHashers != NULL; } + + HRESULT Load(); + + void ClearAndRelease() + { + Hashers.Clear(); + Codecs.Clear(); + GetHashers.Release(); + GetCodecs.Release(); + } + + ~CExternalCodecs() + { + GetHashers.Release(); + GetCodecs.Release(); + } +}; + +extern CExternalCodecs g_ExternalCodecs; + +#define EXTERNAL_CODECS_VARS2 (_externalCodecs.IsSet() ? &_externalCodecs : &g_ExternalCodecs) +#define EXTERNAL_CODECS_VARS2_L (&_externalCodecs) +#define EXTERNAL_CODECS_VARS2_G (&g_ExternalCodecs) + +#define DECL_EXTERNAL_CODECS_VARS CExternalCodecs _externalCodecs; + +#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2, +#define EXTERNAL_CODECS_VARS_L EXTERNAL_CODECS_VARS2_L, +#define EXTERNAL_CODECS_VARS_G EXTERNAL_CODECS_VARS2_G, + +#define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *_externalCodecs +#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2, +#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL DECL_EXTERNAL_CODECS_LOC_VARS2; + +#define EXTERNAL_CODECS_LOC_VARS2 _externalCodecs +#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2, + +#else + +#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC +#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC +#define DECL_ISetCompressCodecsInfo +#define IMPL_ISetCompressCodecsInfo +#define EXTERNAL_CODECS_VARS2 +#define DECL_EXTERNAL_CODECS_VARS +#define EXTERNAL_CODECS_VARS +#define EXTERNAL_CODECS_VARS_L +#define EXTERNAL_CODECS_VARS_G +#define DECL_EXTERNAL_CODECS_LOC_VARS2 +#define DECL_EXTERNAL_CODECS_LOC_VARS +#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL +#define EXTERNAL_CODECS_LOC_VARS2 +#define EXTERNAL_CODECS_LOC_VARS + +#endif + +int FindMethod_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + const AString &name, + bool encode, + CMethodId &methodId, + UInt32 &numStreams, + bool &isFilter); + +bool FindMethod( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, + AString &name); + +bool FindHashMethod( + DECL_EXTERNAL_CODECS_LOC_VARS + const AString &name, + CMethodId &methodId); + +void GetHashMethods( + DECL_EXTERNAL_CODECS_LOC_VARS + CRecordVector &methods); + + +struct CCreatedCoder +{ + CMyComPtr Coder; + CMyComPtr Coder2; + + bool IsExternal; + bool IsFilter; // = true, if Coder was created from filter + UInt32 NumStreams; + + // CCreatedCoder(): IsExternal(false), IsFilter(false), NumStreams(1) {} +}; + + +HRESULT CreateCoder_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + unsigned codecIndex, bool encode, + CMyComPtr &filter, + CCreatedCoder &cod); + +HRESULT CreateCoder_Index( + DECL_EXTERNAL_CODECS_LOC_VARS + unsigned index, bool encode, + CCreatedCoder &cod); + +HRESULT CreateCoder_Id( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &filter, + CCreatedCoder &cod); + +HRESULT CreateCoder_Id( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CCreatedCoder &cod); + +HRESULT CreateCoder_Id( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &coder); + +HRESULT CreateFilter( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, bool encode, + CMyComPtr &filter); + +HRESULT CreateHasher( + DECL_EXTERNAL_CODECS_LOC_VARS + CMethodId methodId, + AString &name, + CMyComPtr &hasher); + +#endif diff --git a/CPP/7zip/Common/FilePathAutoRename.cpp b/CPP/7zip/Common/FilePathAutoRename.cpp index 6db74cc26..81172d565 100644 --- a/CPP/7zip/Common/FilePathAutoRename.cpp +++ b/CPP/7zip/Common/FilePathAutoRename.cpp @@ -1,46 +1,46 @@ -// FilePathAutoRename.cpp - -#include "StdAfx.h" - -#include "../../Windows/FileFind.h" - -#include "FilePathAutoRename.h" - -using namespace NWindows; - -static bool MakeAutoName(const FString &name, - const FString &extension, UInt32 value, FString &path) -{ - path = name; - path.Add_UInt32(value); - path += extension; - return NFile::NFind::DoesFileOrDirExist(path); -} - -bool AutoRenamePath(FString &path) -{ - const int dotPos = path.ReverseFind_Dot(); - const int slashPos = path.ReverseFind_PathSepar(); - - FString name = path; - FString extension; - if (dotPos > slashPos + 1) - { - name.DeleteFrom((unsigned)dotPos); - extension = path.Ptr((unsigned)dotPos); - } - name.Add_Char('_'); - - FString temp; - - UInt32 left = 1, right = (UInt32)1 << 30; - while (left != right) - { - const UInt32 mid = (left + right) / 2; - if (MakeAutoName(name, extension, mid, temp)) - left = mid + 1; - else - right = mid; - } - return !MakeAutoName(name, extension, right, path); -} +// FilePathAutoRename.cpp + +#include "StdAfx.h" + +#include "../../Windows/FileFind.h" + +#include "FilePathAutoRename.h" + +using namespace NWindows; + +static bool MakeAutoName(const FString &name, + const FString &extension, UInt32 value, FString &path) +{ + path = name; + path.Add_UInt32(value); + path += extension; + return NFile::NFind::DoesFileOrDirExist(path); +} + +bool AutoRenamePath(FString &path) +{ + const int dotPos = path.ReverseFind_Dot(); + const int slashPos = path.ReverseFind_PathSepar(); + + FString name = path; + FString extension; + if (dotPos > slashPos + 1) + { + name.DeleteFrom((unsigned)dotPos); + extension = path.Ptr((unsigned)dotPos); + } + name.Add_Char('_'); + + FString temp; + + UInt32 left = 1, right = (UInt32)1 << 30; + while (left != right) + { + const UInt32 mid = (left + right) / 2; + if (MakeAutoName(name, extension, mid, temp)) + left = mid + 1; + else + right = mid; + } + return !MakeAutoName(name, extension, right, path); +} diff --git a/CPP/7zip/Common/FilePathAutoRename.h b/CPP/7zip/Common/FilePathAutoRename.h index 0d1d5b346..ac3688231 100644 --- a/CPP/7zip/Common/FilePathAutoRename.h +++ b/CPP/7zip/Common/FilePathAutoRename.h @@ -1,10 +1,10 @@ -// FilePathAutoRename.h - -#ifndef ZIP7_INC_FILE_PATH_AUTO_RENAME_H -#define ZIP7_INC_FILE_PATH_AUTO_RENAME_H - -#include "../../Common/MyString.h" - -bool AutoRenamePath(FString &fullProcessedPath); - -#endif +// FilePathAutoRename.h + +#ifndef ZIP7_INC_FILE_PATH_AUTO_RENAME_H +#define ZIP7_INC_FILE_PATH_AUTO_RENAME_H + +#include "../../Common/MyString.h" + +bool AutoRenamePath(FString &fullProcessedPath); + +#endif diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp index 8b377dc5b..f90e2805c 100644 --- a/CPP/7zip/Common/FileStreams.cpp +++ b/CPP/7zip/Common/FileStreams.cpp @@ -1,923 +1,923 @@ -// FileStreams.cpp - -#include "StdAfx.h" - -// #include - -#ifndef _WIN32 -#include -#include -#include -#include -#include - -/* -inclusion of by is deprecated since glibc 2.25. -Since glibc 2.3.3, macros have been aliases for three GNU-specific -functions: gnu_dev_makedev(), gnu_dev_major(), and gnu_dev_minor() - -Warning in GCC: -In the GNU C Library, "major" is defined by . -For historical compatibility, it is currently defined by - as well, but we plan to remove this soon. -To use "major", include directly. -If you did not intend to use a system-defined macro "major", -you should undefine it after including -*/ -// for major()/minor(): -#if defined(__APPLE__) || defined(__DragonFly__) || \ - defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#else -#include -#endif - -#endif // _WIN32 - -#include "../../Windows/FileFind.h" - -#ifdef Z7_DEVICE_FILE -#include "../../../C/Alloc.h" -#include "../../Common/Defs.h" -#endif - -#include "../PropID.h" - -#include "FileStreams.h" - -static inline HRESULT GetLastError_HRESULT() -{ - DWORD lastError = ::GetLastError(); - if (lastError == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(lastError); -} - -static inline HRESULT ConvertBoolToHRESULT(bool result) -{ - if (result) - return S_OK; - return GetLastError_HRESULT(); -} - - -#ifdef Z7_DEVICE_FILE -static const UInt32 kClusterSize = 1 << 18; -#endif - -CInFileStream::CInFileStream(): - #ifdef Z7_DEVICE_FILE - VirtPos(0), - PhyPos(0), - Buf(NULL), - BufSize(0), - #endif - #ifndef _WIN32 - _uid(0), - _gid(0), - StoreOwnerId(false), - StoreOwnerName(false), - #endif - _info_WasLoaded(false), - SupportHardLinks(false), - Callback(NULL), - CallbackRef(0) -{ -} - -CInFileStream::~CInFileStream() -{ - #ifdef Z7_DEVICE_FILE - MidFree(Buf); - #endif - - if (Callback) - Callback->InFileStream_On_Destroy(this, CallbackRef); -} - -Z7_COM7F_IMF(CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - // printf("\nCInFileStream::Read size=%d, VirtPos=%8d\n", (unsigned)size, (int)VirtPos); - - #ifdef Z7_FILE_STREAMS_USE_WIN_FILE - - #ifdef Z7_DEVICE_FILE - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (File.IsDeviceFile) - { - if (File.SizeDefined) - { - if (VirtPos >= File.Size) - return VirtPos == File.Size ? S_OK : E_FAIL; - const UInt64 rem = File.Size - VirtPos; - if (size > rem) - size = (UInt32)rem; - } - for (;;) - { - const UInt32 mask = kClusterSize - 1; - const UInt64 mask2 = ~(UInt64)mask; - const UInt64 alignedPos = VirtPos & mask2; - if (BufSize > 0 && BufStartPos == alignedPos) - { - const UInt32 pos = (UInt32)VirtPos & mask; - if (pos >= BufSize) - return S_OK; - const UInt32 rem = MyMin(BufSize - pos, size); - memcpy(data, Buf + pos, rem); - VirtPos += rem; - if (processedSize) - *processedSize += rem; - return S_OK; - } - - bool useBuf = false; - if ((VirtPos & mask) != 0 || ((size_t)(ptrdiff_t)data & mask) != 0 ) - useBuf = true; - else - { - UInt64 end = VirtPos + size; - if ((end & mask) != 0) - { - end &= mask2; - if (end <= VirtPos) - useBuf = true; - else - size = (UInt32)(end - VirtPos); - } - } - if (!useBuf) - break; - if (alignedPos != PhyPos) - { - UInt64 realNewPosition; - const bool result = File.Seek((Int64)alignedPos, FILE_BEGIN, realNewPosition); - if (!result) - return ConvertBoolToHRESULT(result); - PhyPos = realNewPosition; - } - - BufStartPos = alignedPos; - UInt32 readSize = kClusterSize; - if (File.SizeDefined) - readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize); - - if (!Buf) - { - Buf = (Byte *)MidAlloc(kClusterSize); - if (!Buf) - return E_OUTOFMEMORY; - } - const bool result = File.Read1(Buf, readSize, BufSize); - if (!result) - return ConvertBoolToHRESULT(result); - - if (BufSize == 0) - return S_OK; - PhyPos += BufSize; - } - - if (VirtPos != PhyPos) - { - UInt64 realNewPosition; - bool result = File.Seek((Int64)VirtPos, FILE_BEGIN, realNewPosition); - if (!result) - return ConvertBoolToHRESULT(result); - PhyPos = VirtPos = realNewPosition; - } - } - #endif - - UInt32 realProcessedSize; - const bool result = File.ReadPart(data, size, realProcessedSize); - if (processedSize) - *processedSize = realProcessedSize; - - #ifdef Z7_DEVICE_FILE - VirtPos += realProcessedSize; - PhyPos += realProcessedSize; - #endif - - if (result) - return S_OK; - - #else // Z7_FILE_STREAMS_USE_WIN_FILE - - if (processedSize) - *processedSize = 0; - const ssize_t res = File.read_part(data, (size_t)size); - if (res != -1) - { - if (processedSize) - *processedSize = (UInt32)res; - return S_OK; - } - #endif // Z7_FILE_STREAMS_USE_WIN_FILE - - { - const DWORD error = ::GetLastError(); -#if 0 - if (File.IsStdStream && error == ERROR_BROKEN_PIPE) - return S_OK; // end of stream -#endif - if (Callback) - return Callback->InFileStream_On_Error(CallbackRef, error); - if (error == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(error); - } -} - -#ifdef UNDER_CE -Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - size_t s2 = fread(data, 1, size, stdin); - int error = ferror(stdin); - if (processedSize) - *processedSize = s2; - if (s2 <= size && error == 0) - return S_OK; - return E_FAIL; -} -#else -Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - // printf("\nCStdInFileStream::Read size = %d\n", (unsigned)size); - #ifdef _WIN32 - - DWORD realProcessedSize; - UInt32 sizeTemp = (1 << 20); - if (sizeTemp > size) - sizeTemp = size; - /* in GUI mode : GetStdHandle(STD_INPUT_HANDLE) returns NULL, - and it doesn't set LastError. */ - /* - SetLastError(0); - const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); - if (!h || h == INVALID_HANDLE_VALUE) - { - if (processedSize) - *processedSize = 0; - if (GetLastError() == 0) - SetLastError(ERROR_INVALID_HANDLE); - return GetLastError_noZero_HRESULT(); - } - */ - BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL); - - /* - printf("\nCInFileStream::Read: size=%d, processed=%8d res=%d 4rror=%3d\n", - (unsigned)size, (int)realProcessedSize, - (int)res, GetLastError()); - */ - - if (processedSize) - *processedSize = realProcessedSize; - if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) - return S_OK; - return ConvertBoolToHRESULT(res != FALSE); - - #else - - if (processedSize) - *processedSize = 0; - ssize_t res; - do - { - res = read(0, data, (size_t)size); - } - while (res < 0 && (errno == EINTR)); - if (res == -1) - return GetLastError_HRESULT(); - if (processedSize) - *processedSize = (UInt32)res; - return S_OK; - - #endif -} - -#endif - - -/* -bool CreateStdInStream(CMyComPtr &str) -{ -#if 0 - CInFileStream *inStreamSpec = new CInFileStream; - CMyComPtr inStreamLoc(inStreamSpec);; - if (!inStreamSpec->OpenStdIn()) - return false; - if (!inStreamSpec->File.IsStdPipeStream) - str = inStreamLoc.Detach(); - else -#endif - str = new CStdInFileStream; - return true; -} -*/ - -#if 0 -bool CInFileStream::OpenStdIn() -{ - _info_WasLoaded = false; - // Sleep(100); - bool res = File.AttachStdIn(); - if (!res) - return false; -#if 1 - CStreamFileProps props; - if (GetProps2(&props) != S_OK) - { - // we can ignore that error - return false; - } - // we can't use Size, because Size can be set for pipe streams for some value. - // Seek() sees only current chunk in pipe buffer. - // So Seek() can move across only current unread chunk. - // But after reading that chunk. it can't move position back. - // We need safe check that shows that we can use seek (non-pipe mode) - // Is it safe check that shows that pipe mode was used? - File.IsStdPipeStream = (props.VolID == 0); - // && FILETIME_IsZero(props.CTime) - // && FILETIME_IsZero(props.ATime) - // && FILETIME_IsZero(props.MTime); -#endif - // printf("\n######## pipe=%d", (unsigned)File.IsStdPipeStream); - return true; -} -#endif - - -Z7_COM7F_IMF(CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - /* - printf("\nCInFileStream::Seek seekOrigin=%d, offset=%8d, VirtPos=%8d\n", - (unsigned)seekOrigin, (int)offset, (int)VirtPos); - */ - if (seekOrigin >= 3) - return STG_E_INVALIDFUNCTION; - - #ifdef Z7_FILE_STREAMS_USE_WIN_FILE - - #ifdef Z7_DEVICE_FILE - if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END)) - { - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += VirtPos; break; - case STREAM_SEEK_END: offset += File.Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - VirtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; - } - #endif - - UInt64 realNewPosition = 0; - const bool result = File.Seek(offset, seekOrigin, realNewPosition); - const HRESULT hres = ConvertBoolToHRESULT(result); - - /* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition) - in case of error. So we don't need additional code below */ - // if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); } - - #ifdef Z7_DEVICE_FILE - PhyPos = VirtPos = realNewPosition; - #endif - - if (newPosition) - *newPosition = realNewPosition; - - return hres; - - #else - - const off_t res = File.seek((off_t)offset, (int)seekOrigin); - if (res == -1) - { - const HRESULT hres = GetLastError_HRESULT(); - if (newPosition) - *newPosition = (UInt64)File.seekToCur(); - return hres; - } - if (newPosition) - *newPosition = (UInt64)res; - return S_OK; - - #endif -} - -Z7_COM7F_IMF(CInFileStream::GetSize(UInt64 *size)) -{ - return ConvertBoolToHRESULT(File.GetLength(*size)); -} - -#ifdef Z7_FILE_STREAMS_USE_WIN_FILE - -Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) -{ - if (!_info_WasLoaded) - { - RINOK(ReloadProps()) - } - const BY_HANDLE_FILE_INFORMATION &info = _info; - /* - BY_HANDLE_FILE_INFORMATION info; - if (!File.GetFileInformation(&info)) - return GetLastError_HRESULT(); - */ - { - if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; - if (cTime) *cTime = info.ftCreationTime; - if (aTime) *aTime = info.ftLastAccessTime; - if (mTime) *mTime = info.ftLastWriteTime; - if (attrib) *attrib = info.dwFileAttributes; - return S_OK; - } -} - -Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props)) -{ - if (!_info_WasLoaded) - { - RINOK(ReloadProps()) - } - const BY_HANDLE_FILE_INFORMATION &info = _info; - /* - BY_HANDLE_FILE_INFORMATION info; - if (!File.GetFileInformation(&info)) - return GetLastError_HRESULT(); - */ - { - props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; - props->VolID = info.dwVolumeSerialNumber; - props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; - props->FileID_High = 0; - props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1; - props->Attrib = info.dwFileAttributes; - props->CTime = info.ftCreationTime; - props->ATime = info.ftLastAccessTime; - props->MTime = info.ftLastWriteTime; - return S_OK; - } -} - -Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)) -{ - if (!_info_WasLoaded) - { - RINOK(ReloadProps()) - } - - if (!_info_WasLoaded) - return S_OK; - - NWindows::NCOM::CPropVariant prop; - - #ifdef Z7_DEVICE_FILE - if (File.IsDeviceFile) - { - switch (propID) - { - case kpidSize: - if (File.SizeDefined) - prop = File.Size; - break; - // case kpidAttrib: prop = (UInt32)0; break; - case kpidPosixAttrib: - { - prop = (UInt32)NWindows::NFile::NFind::NAttributes:: - Get_PosixMode_From_WinAttrib(0); - /* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute - so we don't use MY_LIN_S_IFBLK here */ - // prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug - break; - } - /* - case kpidDeviceMajor: - prop = (UInt32)8; // id for SCSI type device (sda) - break; - case kpidDeviceMinor: - prop = (UInt32)0; - break; - */ - } - } - else - #endif - { - switch (propID) - { - case kpidSize: - { - const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow; - prop = size; - break; - } - case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break; - case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break; - case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break; - case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break; - case kpidPosixAttrib: - prop = (UInt32)NWindows::NFile::NFind::NAttributes:: - Get_PosixMode_From_WinAttrib(_info.dwFileAttributes); - // | (UInt32)(1 << 21); // for debug - break; - } - } - prop.Detach(value); - return S_OK; -} - - -Z7_COM7F_IMF(CInFileStream::ReloadProps()) -{ - #ifdef Z7_DEVICE_FILE - if (File.IsDeviceFile) - { - memset(&_info, 0, sizeof(_info)); - if (File.SizeDefined) - { - _info.nFileSizeHigh = (DWORD)(File.Size >> 32); - _info.nFileSizeLow = (DWORD)(File.Size); - } - _info.nNumberOfLinks = 1; - _info_WasLoaded = true; - return S_OK; - } - #endif - _info_WasLoaded = File.GetFileInformation(&_info); - if (!_info_WasLoaded) - return GetLastError_HRESULT(); -#ifdef _WIN32 -#if 0 - printf( - "\ndwFileAttributes = %8x" - "\nftCreationTime = %8x" - "\nftLastAccessTime = %8x" - "\nftLastWriteTime = %8x" - "\ndwVolumeSerialNumber = %8x" - "\nnFileSizeHigh = %8x" - "\nnFileSizeLow = %8x" - "\nnNumberOfLinks = %8x" - "\nnFileIndexHigh = %8x" - "\nnFileIndexLow = %8x \n", - (unsigned)_info.dwFileAttributes, - (unsigned)_info.ftCreationTime.dwHighDateTime, - (unsigned)_info.ftLastAccessTime.dwHighDateTime, - (unsigned)_info.ftLastWriteTime.dwHighDateTime, - (unsigned)_info.dwVolumeSerialNumber, - (unsigned)_info.nFileSizeHigh, - (unsigned)_info.nFileSizeLow, - (unsigned)_info.nNumberOfLinks, - (unsigned)_info.nFileIndexHigh, - (unsigned)_info.nFileIndexLow); -#endif -#endif - return S_OK; -} - - -#elif !defined(_WIN32) - -Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) -{ - // printf("\nCInFileStream::GetProps VirtPos = %8d\n", (int)VirtPos); - if (!_info_WasLoaded) - { - RINOK(ReloadProps()) - } - const struct stat &st = _info; - /* - struct stat st; - if (File.my_fstat(&st) != 0) - return GetLastError_HRESULT(); - */ - - if (size) *size = (UInt64)st.st_size; - if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime); - if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime); - if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime); - if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); - - return S_OK; -} - -// #include - -Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props)) -{ - // printf("\nCInFileStream::GetProps2 VirtPos = %8d\n", (int)VirtPos); - if (!_info_WasLoaded) - { - RINOK(ReloadProps()) - } - const struct stat &st = _info; - /* - struct stat st; - if (File.my_fstat(&st) != 0) - return GetLastError_HRESULT(); - */ - - props->Size = (UInt64)st.st_size; - /* - dev_t stat::st_dev: - GCC:Linux long unsigned int : __dev_t - Mac: int - */ - props->VolID = (UInt64)(Int64)st.st_dev; - props->FileID_Low = st.st_ino; - props->FileID_High = 0; - props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long) - props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); - - FiTime_To_FILETIME (ST_CTIME(st), props->CTime); - FiTime_To_FILETIME (ST_ATIME(st), props->ATime); - FiTime_To_FILETIME (ST_MTIME(st), props->MTime); - - /* - printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n" - , (unsigned)(props->NumLinks) - , (unsigned)(st.st_dev) - , (unsigned)(st.st_ino) - ); - */ - - return S_OK; -} - -Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)) -{ - // printf("\nCInFileStream::GetProperty VirtPos = %8d propID = %3d\n", (int)VirtPos, propID); - if (!_info_WasLoaded) - { - RINOK(ReloadProps()) - } - - if (!_info_WasLoaded) - return S_OK; - - const struct stat &st = _info; - - NWindows::NCOM::CPropVariant prop; - { - switch (propID) - { - case kpidSize: prop = (UInt64)st.st_size; break; - case kpidAttrib: - prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); - break; - case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break; - case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break; - case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break; - case kpidPosixAttrib: prop = (UInt32)st.st_mode; break; - - #if defined(__APPLE__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wsign-conversion" - #endif - - case kpidDeviceMajor: - { - // printf("\nst.st_rdev = %d\n", st.st_rdev); - if (S_ISCHR(st.st_mode) || - S_ISBLK(st.st_mode)) - prop = (UInt32)(major(st.st_rdev)); // + 1000); - // prop = (UInt32)12345678; // for debug - break; - } - - case kpidDeviceMinor: - if (S_ISCHR(st.st_mode) || - S_ISBLK(st.st_mode)) - prop = (UInt32)(minor(st.st_rdev)); // + 100); - // prop = (UInt32)(st.st_rdev); // for debug - // printf("\nst.st_rdev = %d\n", st.st_rdev); - // prop = (UInt32)123456789; // for debug - break; - - #if defined(__APPLE__) - #pragma GCC diagnostic pop - #endif - - /* - case kpidDevice: - if (S_ISCHR(st.st_mode) || - S_ISBLK(st.st_mode)) - prop = (UInt64)(st.st_rdev); - break; - */ - - case kpidUserId: - { - if (StoreOwnerId) - prop = (UInt32)st.st_uid; - break; - } - case kpidGroupId: - { - if (StoreOwnerId) - prop = (UInt32)st.st_gid; - break; - } - case kpidUser: - { - if (StoreOwnerName) - { - const uid_t uid = st.st_uid; - { - if (!OwnerName.IsEmpty() && _uid == uid) - prop = OwnerName; - else - { - const passwd *pw = getpwuid(uid); - if (pw) - { - // we can use utf-8 here. - // prop = pw->pw_name; - } - } - } - } - break; - } - case kpidGroup: - { - if (StoreOwnerName) - { - const uid_t gid = st.st_gid; - { - if (!OwnerGroup.IsEmpty() && _gid == gid) - prop = OwnerGroup; - else - { - const group *gr = getgrgid(gid); - if (gr) - { - // we can use utf-8 here. - // prop = gr->gr_name; - } - } - } - } - break; - } - default: break; - } - } - prop.Detach(value); - return S_OK; -} - - -Z7_COM7F_IMF(CInFileStream::ReloadProps()) -{ - _info_WasLoaded = (File.my_fstat(&_info) == 0); - if (!_info_WasLoaded) - return GetLastError_HRESULT(); - return S_OK; -} - -#endif - - - - -////////////////////////// -// COutFileStream - -HRESULT COutFileStream::Close() -{ - return ConvertBoolToHRESULT(File.Close()); -} - -Z7_COM7F_IMF(COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - #ifdef Z7_FILE_STREAMS_USE_WIN_FILE - - UInt32 realProcessedSize; - const bool result = File.Write(data, size, realProcessedSize); - ProcessedSize += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return ConvertBoolToHRESULT(result); - - #else - - if (processedSize) - *processedSize = 0; - size_t realProcessedSize; - const ssize_t res = File.write_full(data, (size_t)size, realProcessedSize); - ProcessedSize += realProcessedSize; - if (processedSize) - *processedSize = (UInt32)realProcessedSize; - if (res == -1) - return GetLastError_HRESULT(); - return S_OK; - - #endif -} - -Z7_COM7F_IMF(COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - if (seekOrigin >= 3) - return STG_E_INVALIDFUNCTION; - - #ifdef Z7_FILE_STREAMS_USE_WIN_FILE - - UInt64 realNewPosition = 0; - const bool result = File.Seek(offset, seekOrigin, realNewPosition); - if (newPosition) - *newPosition = realNewPosition; - return ConvertBoolToHRESULT(result); - - #else - - const off_t res = File.seek((off_t)offset, (int)seekOrigin); - if (res == -1) - return GetLastError_HRESULT(); - if (newPosition) - *newPosition = (UInt64)res; - return S_OK; - - #endif -} - -Z7_COM7F_IMF(COutFileStream::SetSize(UInt64 newSize)) -{ - return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize)); -} - -HRESULT COutFileStream::GetSize(UInt64 *size) -{ - return ConvertBoolToHRESULT(File.GetLength(*size)); -} - -#ifdef UNDER_CE - -Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - size_t s2 = fwrite(data, 1, size, stdout); - if (processedSize) - *processedSize = s2; - return (s2 == size) ? S_OK : E_FAIL; -} - -#else - -Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - #ifdef _WIN32 - - UInt32 realProcessedSize; - BOOL res = TRUE; - if (size > 0) - { - // Seems that Windows doesn't like big amounts writing to stdout. - // So we limit portions by 32KB. - UInt32 sizeTemp = (1 << 15); - if (sizeTemp > size) - sizeTemp = size; - res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), - data, sizeTemp, (DWORD *)&realProcessedSize, NULL); - _size += realProcessedSize; - size -= realProcessedSize; - data = (const void *)((const Byte *)data + realProcessedSize); - if (processedSize) - *processedSize += realProcessedSize; - } - return ConvertBoolToHRESULT(res != FALSE); - - #else - - ssize_t res; - - do - { - res = write(1, data, (size_t)size); - } - while (res < 0 && (errno == EINTR)); - - if (res == -1) - return GetLastError_HRESULT(); - - _size += (size_t)res; - if (processedSize) - *processedSize = (UInt32)res; - return S_OK; - - #endif -} - -#endif +// FileStreams.cpp + +#include "StdAfx.h" + +// #include + +#ifndef _WIN32 +#include +#include +#include +#include +#include + +/* +inclusion of by is deprecated since glibc 2.25. +Since glibc 2.3.3, macros have been aliases for three GNU-specific +functions: gnu_dev_makedev(), gnu_dev_major(), and gnu_dev_minor() + +Warning in GCC: +In the GNU C Library, "major" is defined by . +For historical compatibility, it is currently defined by + as well, but we plan to remove this soon. +To use "major", include directly. +If you did not intend to use a system-defined macro "major", +you should undefine it after including +*/ +// for major()/minor(): +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include +#else +#include +#endif + +#endif // _WIN32 + +#include "../../Windows/FileFind.h" + +#ifdef Z7_DEVICE_FILE +#include "../../../C/Alloc.h" +#include "../../Common/Defs.h" +#endif + +#include "../PropID.h" + +#include "FileStreams.h" + +static inline HRESULT GetLastError_HRESULT() +{ + DWORD lastError = ::GetLastError(); + if (lastError == 0) + return E_FAIL; + return HRESULT_FROM_WIN32(lastError); +} + +static inline HRESULT ConvertBoolToHRESULT(bool result) +{ + if (result) + return S_OK; + return GetLastError_HRESULT(); +} + + +#ifdef Z7_DEVICE_FILE +static const UInt32 kClusterSize = 1 << 18; +#endif + +CInFileStream::CInFileStream(): + #ifdef Z7_DEVICE_FILE + VirtPos(0), + PhyPos(0), + Buf(NULL), + BufSize(0), + #endif + #ifndef _WIN32 + _uid(0), + _gid(0), + StoreOwnerId(false), + StoreOwnerName(false), + #endif + _info_WasLoaded(false), + SupportHardLinks(false), + Callback(NULL), + CallbackRef(0) +{ +} + +CInFileStream::~CInFileStream() +{ + #ifdef Z7_DEVICE_FILE + MidFree(Buf); + #endif + + if (Callback) + Callback->InFileStream_On_Destroy(this, CallbackRef); +} + +Z7_COM7F_IMF(CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + // printf("\nCInFileStream::Read size=%d, VirtPos=%8d\n", (unsigned)size, (int)VirtPos); + + #ifdef Z7_FILE_STREAMS_USE_WIN_FILE + + #ifdef Z7_DEVICE_FILE + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (File.IsDeviceFile) + { + if (File.SizeDefined) + { + if (VirtPos >= File.Size) + return VirtPos == File.Size ? S_OK : E_FAIL; + const UInt64 rem = File.Size - VirtPos; + if (size > rem) + size = (UInt32)rem; + } + for (;;) + { + const UInt32 mask = kClusterSize - 1; + const UInt64 mask2 = ~(UInt64)mask; + const UInt64 alignedPos = VirtPos & mask2; + if (BufSize > 0 && BufStartPos == alignedPos) + { + const UInt32 pos = (UInt32)VirtPos & mask; + if (pos >= BufSize) + return S_OK; + const UInt32 rem = MyMin(BufSize - pos, size); + memcpy(data, Buf + pos, rem); + VirtPos += rem; + if (processedSize) + *processedSize += rem; + return S_OK; + } + + bool useBuf = false; + if ((VirtPos & mask) != 0 || ((size_t)(ptrdiff_t)data & mask) != 0 ) + useBuf = true; + else + { + UInt64 end = VirtPos + size; + if ((end & mask) != 0) + { + end &= mask2; + if (end <= VirtPos) + useBuf = true; + else + size = (UInt32)(end - VirtPos); + } + } + if (!useBuf) + break; + if (alignedPos != PhyPos) + { + UInt64 realNewPosition; + const bool result = File.Seek((Int64)alignedPos, FILE_BEGIN, realNewPosition); + if (!result) + return ConvertBoolToHRESULT(result); + PhyPos = realNewPosition; + } + + BufStartPos = alignedPos; + UInt32 readSize = kClusterSize; + if (File.SizeDefined) + readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize); + + if (!Buf) + { + Buf = (Byte *)MidAlloc(kClusterSize); + if (!Buf) + return E_OUTOFMEMORY; + } + const bool result = File.Read1(Buf, readSize, BufSize); + if (!result) + return ConvertBoolToHRESULT(result); + + if (BufSize == 0) + return S_OK; + PhyPos += BufSize; + } + + if (VirtPos != PhyPos) + { + UInt64 realNewPosition; + bool result = File.Seek((Int64)VirtPos, FILE_BEGIN, realNewPosition); + if (!result) + return ConvertBoolToHRESULT(result); + PhyPos = VirtPos = realNewPosition; + } + } + #endif + + UInt32 realProcessedSize; + const bool result = File.ReadPart(data, size, realProcessedSize); + if (processedSize) + *processedSize = realProcessedSize; + + #ifdef Z7_DEVICE_FILE + VirtPos += realProcessedSize; + PhyPos += realProcessedSize; + #endif + + if (result) + return S_OK; + + #else // Z7_FILE_STREAMS_USE_WIN_FILE + + if (processedSize) + *processedSize = 0; + const ssize_t res = File.read_part(data, (size_t)size); + if (res != -1) + { + if (processedSize) + *processedSize = (UInt32)res; + return S_OK; + } + #endif // Z7_FILE_STREAMS_USE_WIN_FILE + + { + const DWORD error = ::GetLastError(); +#if 0 + if (File.IsStdStream && error == ERROR_BROKEN_PIPE) + return S_OK; // end of stream +#endif + if (Callback) + return Callback->InFileStream_On_Error(CallbackRef, error); + if (error == 0) + return E_FAIL; + return HRESULT_FROM_WIN32(error); + } +} + +#ifdef UNDER_CE +Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + size_t s2 = fread(data, 1, size, stdin); + int error = ferror(stdin); + if (processedSize) + *processedSize = s2; + if (s2 <= size && error == 0) + return S_OK; + return E_FAIL; +} +#else +Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + // printf("\nCStdInFileStream::Read size = %d\n", (unsigned)size); + #ifdef _WIN32 + + DWORD realProcessedSize; + UInt32 sizeTemp = (1 << 20); + if (sizeTemp > size) + sizeTemp = size; + /* in GUI mode : GetStdHandle(STD_INPUT_HANDLE) returns NULL, + and it doesn't set LastError. */ + /* + SetLastError(0); + const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + if (!h || h == INVALID_HANDLE_VALUE) + { + if (processedSize) + *processedSize = 0; + if (GetLastError() == 0) + SetLastError(ERROR_INVALID_HANDLE); + return GetLastError_noZero_HRESULT(); + } + */ + BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL); + + /* + printf("\nCInFileStream::Read: size=%d, processed=%8d res=%d 4rror=%3d\n", + (unsigned)size, (int)realProcessedSize, + (int)res, GetLastError()); + */ + + if (processedSize) + *processedSize = realProcessedSize; + if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) + return S_OK; + return ConvertBoolToHRESULT(res != FALSE); + + #else + + if (processedSize) + *processedSize = 0; + ssize_t res; + do + { + res = read(0, data, (size_t)size); + } + while (res < 0 && (errno == EINTR)); + if (res == -1) + return GetLastError_HRESULT(); + if (processedSize) + *processedSize = (UInt32)res; + return S_OK; + + #endif +} + +#endif + + +/* +bool CreateStdInStream(CMyComPtr &str) +{ +#if 0 + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStreamLoc(inStreamSpec);; + if (!inStreamSpec->OpenStdIn()) + return false; + if (!inStreamSpec->File.IsStdPipeStream) + str = inStreamLoc.Detach(); + else +#endif + str = new CStdInFileStream; + return true; +} +*/ + +#if 0 +bool CInFileStream::OpenStdIn() +{ + _info_WasLoaded = false; + // Sleep(100); + bool res = File.AttachStdIn(); + if (!res) + return false; +#if 1 + CStreamFileProps props; + if (GetProps2(&props) != S_OK) + { + // we can ignore that error + return false; + } + // we can't use Size, because Size can be set for pipe streams for some value. + // Seek() sees only current chunk in pipe buffer. + // So Seek() can move across only current unread chunk. + // But after reading that chunk. it can't move position back. + // We need safe check that shows that we can use seek (non-pipe mode) + // Is it safe check that shows that pipe mode was used? + File.IsStdPipeStream = (props.VolID == 0); + // && FILETIME_IsZero(props.CTime) + // && FILETIME_IsZero(props.ATime) + // && FILETIME_IsZero(props.MTime); +#endif + // printf("\n######## pipe=%d", (unsigned)File.IsStdPipeStream); + return true; +} +#endif + + +Z7_COM7F_IMF(CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + /* + printf("\nCInFileStream::Seek seekOrigin=%d, offset=%8d, VirtPos=%8d\n", + (unsigned)seekOrigin, (int)offset, (int)VirtPos); + */ + if (seekOrigin >= 3) + return STG_E_INVALIDFUNCTION; + + #ifdef Z7_FILE_STREAMS_USE_WIN_FILE + + #ifdef Z7_DEVICE_FILE + if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END)) + { + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += VirtPos; break; + case STREAM_SEEK_END: offset += File.Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + VirtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; + } + #endif + + UInt64 realNewPosition = 0; + const bool result = File.Seek(offset, seekOrigin, realNewPosition); + const HRESULT hres = ConvertBoolToHRESULT(result); + + /* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition) + in case of error. So we don't need additional code below */ + // if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); } + + #ifdef Z7_DEVICE_FILE + PhyPos = VirtPos = realNewPosition; + #endif + + if (newPosition) + *newPosition = realNewPosition; + + return hres; + + #else + + const off_t res = File.seek((off_t)offset, (int)seekOrigin); + if (res == -1) + { + const HRESULT hres = GetLastError_HRESULT(); + if (newPosition) + *newPosition = (UInt64)File.seekToCur(); + return hres; + } + if (newPosition) + *newPosition = (UInt64)res; + return S_OK; + + #endif +} + +Z7_COM7F_IMF(CInFileStream::GetSize(UInt64 *size)) +{ + return ConvertBoolToHRESULT(File.GetLength(*size)); +} + +#ifdef Z7_FILE_STREAMS_USE_WIN_FILE + +Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) +{ + if (!_info_WasLoaded) + { + RINOK(ReloadProps()) + } + const BY_HANDLE_FILE_INFORMATION &info = _info; + /* + BY_HANDLE_FILE_INFORMATION info; + if (!File.GetFileInformation(&info)) + return GetLastError_HRESULT(); + */ + { + if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + if (cTime) *cTime = info.ftCreationTime; + if (aTime) *aTime = info.ftLastAccessTime; + if (mTime) *mTime = info.ftLastWriteTime; + if (attrib) *attrib = info.dwFileAttributes; + return S_OK; + } +} + +Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props)) +{ + if (!_info_WasLoaded) + { + RINOK(ReloadProps()) + } + const BY_HANDLE_FILE_INFORMATION &info = _info; + /* + BY_HANDLE_FILE_INFORMATION info; + if (!File.GetFileInformation(&info)) + return GetLastError_HRESULT(); + */ + { + props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + props->VolID = info.dwVolumeSerialNumber; + props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; + props->FileID_High = 0; + props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1; + props->Attrib = info.dwFileAttributes; + props->CTime = info.ftCreationTime; + props->ATime = info.ftLastAccessTime; + props->MTime = info.ftLastWriteTime; + return S_OK; + } +} + +Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)) +{ + if (!_info_WasLoaded) + { + RINOK(ReloadProps()) + } + + if (!_info_WasLoaded) + return S_OK; + + NWindows::NCOM::CPropVariant prop; + + #ifdef Z7_DEVICE_FILE + if (File.IsDeviceFile) + { + switch (propID) + { + case kpidSize: + if (File.SizeDefined) + prop = File.Size; + break; + // case kpidAttrib: prop = (UInt32)0; break; + case kpidPosixAttrib: + { + prop = (UInt32)NWindows::NFile::NFind::NAttributes:: + Get_PosixMode_From_WinAttrib(0); + /* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute + so we don't use MY_LIN_S_IFBLK here */ + // prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug + break; + } + /* + case kpidDeviceMajor: + prop = (UInt32)8; // id for SCSI type device (sda) + break; + case kpidDeviceMinor: + prop = (UInt32)0; + break; + */ + } + } + else + #endif + { + switch (propID) + { + case kpidSize: + { + const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow; + prop = size; + break; + } + case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break; + case kpidPosixAttrib: + prop = (UInt32)NWindows::NFile::NFind::NAttributes:: + Get_PosixMode_From_WinAttrib(_info.dwFileAttributes); + // | (UInt32)(1 << 21); // for debug + break; + } + } + prop.Detach(value); + return S_OK; +} + + +Z7_COM7F_IMF(CInFileStream::ReloadProps()) +{ + #ifdef Z7_DEVICE_FILE + if (File.IsDeviceFile) + { + memset(&_info, 0, sizeof(_info)); + if (File.SizeDefined) + { + _info.nFileSizeHigh = (DWORD)(File.Size >> 32); + _info.nFileSizeLow = (DWORD)(File.Size); + } + _info.nNumberOfLinks = 1; + _info_WasLoaded = true; + return S_OK; + } + #endif + _info_WasLoaded = File.GetFileInformation(&_info); + if (!_info_WasLoaded) + return GetLastError_HRESULT(); +#ifdef _WIN32 +#if 0 + printf( + "\ndwFileAttributes = %8x" + "\nftCreationTime = %8x" + "\nftLastAccessTime = %8x" + "\nftLastWriteTime = %8x" + "\ndwVolumeSerialNumber = %8x" + "\nnFileSizeHigh = %8x" + "\nnFileSizeLow = %8x" + "\nnNumberOfLinks = %8x" + "\nnFileIndexHigh = %8x" + "\nnFileIndexLow = %8x \n", + (unsigned)_info.dwFileAttributes, + (unsigned)_info.ftCreationTime.dwHighDateTime, + (unsigned)_info.ftLastAccessTime.dwHighDateTime, + (unsigned)_info.ftLastWriteTime.dwHighDateTime, + (unsigned)_info.dwVolumeSerialNumber, + (unsigned)_info.nFileSizeHigh, + (unsigned)_info.nFileSizeLow, + (unsigned)_info.nNumberOfLinks, + (unsigned)_info.nFileIndexHigh, + (unsigned)_info.nFileIndexLow); +#endif +#endif + return S_OK; +} + + +#elif !defined(_WIN32) + +Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) +{ + // printf("\nCInFileStream::GetProps VirtPos = %8d\n", (int)VirtPos); + if (!_info_WasLoaded) + { + RINOK(ReloadProps()) + } + const struct stat &st = _info; + /* + struct stat st; + if (File.my_fstat(&st) != 0) + return GetLastError_HRESULT(); + */ + + if (size) *size = (UInt64)st.st_size; + if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime); + if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime); + if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime); + if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); + + return S_OK; +} + +// #include + +Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props)) +{ + // printf("\nCInFileStream::GetProps2 VirtPos = %8d\n", (int)VirtPos); + if (!_info_WasLoaded) + { + RINOK(ReloadProps()) + } + const struct stat &st = _info; + /* + struct stat st; + if (File.my_fstat(&st) != 0) + return GetLastError_HRESULT(); + */ + + props->Size = (UInt64)st.st_size; + /* + dev_t stat::st_dev: + GCC:Linux long unsigned int : __dev_t + Mac: int + */ + props->VolID = (UInt64)(Int64)st.st_dev; + props->FileID_Low = st.st_ino; + props->FileID_High = 0; + props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long) + props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); + + FiTime_To_FILETIME (ST_CTIME(st), props->CTime); + FiTime_To_FILETIME (ST_ATIME(st), props->ATime); + FiTime_To_FILETIME (ST_MTIME(st), props->MTime); + + /* + printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n" + , (unsigned)(props->NumLinks) + , (unsigned)(st.st_dev) + , (unsigned)(st.st_ino) + ); + */ + + return S_OK; +} + +Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)) +{ + // printf("\nCInFileStream::GetProperty VirtPos = %8d propID = %3d\n", (int)VirtPos, propID); + if (!_info_WasLoaded) + { + RINOK(ReloadProps()) + } + + if (!_info_WasLoaded) + return S_OK; + + const struct stat &st = _info; + + NWindows::NCOM::CPropVariant prop; + { + switch (propID) + { + case kpidSize: prop = (UInt64)st.st_size; break; + case kpidAttrib: + prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); + break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break; + case kpidPosixAttrib: prop = (UInt32)st.st_mode; break; + + #if defined(__APPLE__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsign-conversion" + #endif + + case kpidDeviceMajor: + { + // printf("\nst.st_rdev = %d\n", st.st_rdev); + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode)) + prop = (UInt32)(major(st.st_rdev)); // + 1000); + // prop = (UInt32)12345678; // for debug + break; + } + + case kpidDeviceMinor: + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode)) + prop = (UInt32)(minor(st.st_rdev)); // + 100); + // prop = (UInt32)(st.st_rdev); // for debug + // printf("\nst.st_rdev = %d\n", st.st_rdev); + // prop = (UInt32)123456789; // for debug + break; + + #if defined(__APPLE__) + #pragma GCC diagnostic pop + #endif + + /* + case kpidDevice: + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode)) + prop = (UInt64)(st.st_rdev); + break; + */ + + case kpidUserId: + { + if (StoreOwnerId) + prop = (UInt32)st.st_uid; + break; + } + case kpidGroupId: + { + if (StoreOwnerId) + prop = (UInt32)st.st_gid; + break; + } + case kpidUser: + { + if (StoreOwnerName) + { + const uid_t uid = st.st_uid; + { + if (!OwnerName.IsEmpty() && _uid == uid) + prop = OwnerName; + else + { + const passwd *pw = getpwuid(uid); + if (pw) + { + // we can use utf-8 here. + // prop = pw->pw_name; + } + } + } + } + break; + } + case kpidGroup: + { + if (StoreOwnerName) + { + const uid_t gid = st.st_gid; + { + if (!OwnerGroup.IsEmpty() && _gid == gid) + prop = OwnerGroup; + else + { + const group *gr = getgrgid(gid); + if (gr) + { + // we can use utf-8 here. + // prop = gr->gr_name; + } + } + } + } + break; + } + default: break; + } + } + prop.Detach(value); + return S_OK; +} + + +Z7_COM7F_IMF(CInFileStream::ReloadProps()) +{ + _info_WasLoaded = (File.my_fstat(&_info) == 0); + if (!_info_WasLoaded) + return GetLastError_HRESULT(); + return S_OK; +} + +#endif + + + + +////////////////////////// +// COutFileStream + +HRESULT COutFileStream::Close() +{ + return ConvertBoolToHRESULT(File.Close()); +} + +Z7_COM7F_IMF(COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + #ifdef Z7_FILE_STREAMS_USE_WIN_FILE + + UInt32 realProcessedSize; + const bool result = File.Write(data, size, realProcessedSize); + ProcessedSize += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return ConvertBoolToHRESULT(result); + + #else + + if (processedSize) + *processedSize = 0; + size_t realProcessedSize; + const ssize_t res = File.write_full(data, (size_t)size, realProcessedSize); + ProcessedSize += realProcessedSize; + if (processedSize) + *processedSize = (UInt32)realProcessedSize; + if (res == -1) + return GetLastError_HRESULT(); + return S_OK; + + #endif +} + +Z7_COM7F_IMF(COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + if (seekOrigin >= 3) + return STG_E_INVALIDFUNCTION; + + #ifdef Z7_FILE_STREAMS_USE_WIN_FILE + + UInt64 realNewPosition = 0; + const bool result = File.Seek(offset, seekOrigin, realNewPosition); + if (newPosition) + *newPosition = realNewPosition; + return ConvertBoolToHRESULT(result); + + #else + + const off_t res = File.seek((off_t)offset, (int)seekOrigin); + if (res == -1) + return GetLastError_HRESULT(); + if (newPosition) + *newPosition = (UInt64)res; + return S_OK; + + #endif +} + +Z7_COM7F_IMF(COutFileStream::SetSize(UInt64 newSize)) +{ + return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize)); +} + +HRESULT COutFileStream::GetSize(UInt64 *size) +{ + return ConvertBoolToHRESULT(File.GetLength(*size)); +} + +#ifdef UNDER_CE + +Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + size_t s2 = fwrite(data, 1, size, stdout); + if (processedSize) + *processedSize = s2; + return (s2 == size) ? S_OK : E_FAIL; +} + +#else + +Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + #ifdef _WIN32 + + UInt32 realProcessedSize; + BOOL res = TRUE; + if (size > 0) + { + // Seems that Windows doesn't like big amounts writing to stdout. + // So we limit portions by 32KB. + UInt32 sizeTemp = (1 << 15); + if (sizeTemp > size) + sizeTemp = size; + res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), + data, sizeTemp, (DWORD *)&realProcessedSize, NULL); + _size += realProcessedSize; + size -= realProcessedSize; + data = (const void *)((const Byte *)data + realProcessedSize); + if (processedSize) + *processedSize += realProcessedSize; + } + return ConvertBoolToHRESULT(res != FALSE); + + #else + + ssize_t res; + + do + { + res = write(1, data, (size_t)size); + } + while (res < 0 && (errno == EINTR)); + + if (res == -1) + return GetLastError_HRESULT(); + + _size += (size_t)res; + if (processedSize) + *processedSize = (UInt32)res; + return S_OK; + + #endif +} + +#endif diff --git a/CPP/7zip/Common/FileStreams.h b/CPP/7zip/Common/FileStreams.h index b9c6fccb1..212d4f0f8 100644 --- a/CPP/7zip/Common/FileStreams.h +++ b/CPP/7zip/Common/FileStreams.h @@ -1,205 +1,205 @@ -// FileStreams.h - -#ifndef ZIP7_INC_FILE_STREAMS_H -#define ZIP7_INC_FILE_STREAMS_H - -#ifdef _WIN32 -#define Z7_FILE_STREAMS_USE_WIN_FILE -#endif - -#include "../../Common/MyCom.h" -#include "../../Common/MyString.h" - -#include "../../Windows/FileIO.h" - -#include "../IStream.h" - -#include "UniqBlocks.h" - - -class CInFileStream; - -Z7_PURE_INTERFACES_BEGIN -DECLARE_INTERFACE(IInFileStream_Callback) -{ - virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0; - virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0; -}; -Z7_PURE_INTERFACES_END - - -/* -Z7_CLASS_IMP_COM_5( - CInFileStream - , IInStream - , IStreamGetSize - , IStreamGetProps - , IStreamGetProps2 - , IStreamGetProp -) -*/ -Z7_class_final(CInFileStream) : - public IInStream, - public IStreamGetSize, - public IStreamGetProps, - public IStreamGetProps2, - public IStreamGetProp, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_6( - IInStream, - ISequentialInStream, - IStreamGetSize, - IStreamGetProps, - IStreamGetProps2, - IStreamGetProp) - - Z7_IFACE_COM7_IMP(ISequentialInStream) - Z7_IFACE_COM7_IMP(IInStream) -public: - Z7_IFACE_COM7_IMP(IStreamGetSize) -private: - Z7_IFACE_COM7_IMP(IStreamGetProps) -public: - Z7_IFACE_COM7_IMP(IStreamGetProps2) - Z7_IFACE_COM7_IMP(IStreamGetProp) - -private: - NWindows::NFile::NIO::CInFile File; -public: - - #ifdef Z7_FILE_STREAMS_USE_WIN_FILE - - #ifdef Z7_DEVICE_FILE - UInt64 VirtPos; - UInt64 PhyPos; - UInt64 BufStartPos; - Byte *Buf; - UInt32 BufSize; - #endif - - #endif - - #ifdef _WIN32 - BY_HANDLE_FILE_INFORMATION _info; - #else - struct stat _info; - UInt32 _uid; - UInt32 _gid; - UString OwnerName; - UString OwnerGroup; - bool StoreOwnerId; - bool StoreOwnerName; - #endif - - bool _info_WasLoaded; - bool SupportHardLinks; - IInFileStream_Callback *Callback; - UINT_PTR CallbackRef; - - CInFileStream(); - ~CInFileStream(); - - void Set_PreserveATime(bool v) - { - File.PreserveATime = v; - } - - bool GetLength(UInt64 &length) const throw() - { - return File.GetLength(length); - } - -#if 0 - bool OpenStdIn(); -#endif - - bool Open(CFSTR fileName) - { - _info_WasLoaded = false; - return File.Open(fileName); - } - - bool OpenShared(CFSTR fileName, bool shareForWrite) - { - _info_WasLoaded = false; - return File.OpenShared(fileName, shareForWrite); - } -}; - -// bool CreateStdInStream(CMyComPtr &str); - -Z7_CLASS_IMP_NOQIB_1( - CStdInFileStream - , ISequentialInStream -) -}; - - -Z7_CLASS_IMP_COM_1( - COutFileStream - , IOutStream -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) -public: - - NWindows::NFile::NIO::COutFile File; - - bool Create_NEW(CFSTR fileName) - { - ProcessedSize = 0; - return File.Create_NEW(fileName); - } - - bool Create_ALWAYS(CFSTR fileName) - { - ProcessedSize = 0; - return File.Create_ALWAYS(fileName); - } - - bool Open_EXISTING(CFSTR fileName) - { - ProcessedSize = 0; - return File.Open_EXISTING(fileName); - } - - bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways) - { - ProcessedSize = 0; - return File.Create_ALWAYS_or_Open_ALWAYS(fileName, createAlways); - } - - HRESULT Close(); - - UInt64 ProcessedSize; - - bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) - { - return File.SetTime(cTime, aTime, mTime); - } - bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); } - - bool SeekToBegin_bool() - { - #ifdef Z7_FILE_STREAMS_USE_WIN_FILE - return File.SeekToBegin(); - #else - return File.seekToBegin() == 0; - #endif - } - - HRESULT GetSize(UInt64 *size); -}; - - -Z7_CLASS_IMP_NOQIB_1( - CStdOutFileStream - , ISequentialOutStream -) - UInt64 _size; -public: - UInt64 GetSize() const { return _size; } - CStdOutFileStream(): _size(0) {} -}; - -#endif +// FileStreams.h + +#ifndef ZIP7_INC_FILE_STREAMS_H +#define ZIP7_INC_FILE_STREAMS_H + +#ifdef _WIN32 +#define Z7_FILE_STREAMS_USE_WIN_FILE +#endif + +#include "../../Common/MyCom.h" +#include "../../Common/MyString.h" + +#include "../../Windows/FileIO.h" + +#include "../IStream.h" + +#include "UniqBlocks.h" + + +class CInFileStream; + +Z7_PURE_INTERFACES_BEGIN +DECLARE_INTERFACE(IInFileStream_Callback) +{ + virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0; + virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0; +}; +Z7_PURE_INTERFACES_END + + +/* +Z7_CLASS_IMP_COM_5( + CInFileStream + , IInStream + , IStreamGetSize + , IStreamGetProps + , IStreamGetProps2 + , IStreamGetProp +) +*/ +Z7_class_final(CInFileStream) : + public IInStream, + public IStreamGetSize, + public IStreamGetProps, + public IStreamGetProps2, + public IStreamGetProp, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_6( + IInStream, + ISequentialInStream, + IStreamGetSize, + IStreamGetProps, + IStreamGetProps2, + IStreamGetProp) + + Z7_IFACE_COM7_IMP(ISequentialInStream) + Z7_IFACE_COM7_IMP(IInStream) +public: + Z7_IFACE_COM7_IMP(IStreamGetSize) +private: + Z7_IFACE_COM7_IMP(IStreamGetProps) +public: + Z7_IFACE_COM7_IMP(IStreamGetProps2) + Z7_IFACE_COM7_IMP(IStreamGetProp) + +private: + NWindows::NFile::NIO::CInFile File; +public: + + #ifdef Z7_FILE_STREAMS_USE_WIN_FILE + + #ifdef Z7_DEVICE_FILE + UInt64 VirtPos; + UInt64 PhyPos; + UInt64 BufStartPos; + Byte *Buf; + UInt32 BufSize; + #endif + + #endif + + #ifdef _WIN32 + BY_HANDLE_FILE_INFORMATION _info; + #else + struct stat _info; + UInt32 _uid; + UInt32 _gid; + UString OwnerName; + UString OwnerGroup; + bool StoreOwnerId; + bool StoreOwnerName; + #endif + + bool _info_WasLoaded; + bool SupportHardLinks; + IInFileStream_Callback *Callback; + UINT_PTR CallbackRef; + + CInFileStream(); + ~CInFileStream(); + + void Set_PreserveATime(bool v) + { + File.PreserveATime = v; + } + + bool GetLength(UInt64 &length) const throw() + { + return File.GetLength(length); + } + +#if 0 + bool OpenStdIn(); +#endif + + bool Open(CFSTR fileName) + { + _info_WasLoaded = false; + return File.Open(fileName); + } + + bool OpenShared(CFSTR fileName, bool shareForWrite) + { + _info_WasLoaded = false; + return File.OpenShared(fileName, shareForWrite); + } +}; + +// bool CreateStdInStream(CMyComPtr &str); + +Z7_CLASS_IMP_NOQIB_1( + CStdInFileStream + , ISequentialInStream +) +}; + + +Z7_CLASS_IMP_COM_1( + COutFileStream + , IOutStream +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) +public: + + NWindows::NFile::NIO::COutFile File; + + bool Create_NEW(CFSTR fileName) + { + ProcessedSize = 0; + return File.Create_NEW(fileName); + } + + bool Create_ALWAYS(CFSTR fileName) + { + ProcessedSize = 0; + return File.Create_ALWAYS(fileName); + } + + bool Open_EXISTING(CFSTR fileName) + { + ProcessedSize = 0; + return File.Open_EXISTING(fileName); + } + + bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways) + { + ProcessedSize = 0; + return File.Create_ALWAYS_or_Open_ALWAYS(fileName, createAlways); + } + + HRESULT Close(); + + UInt64 ProcessedSize; + + bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) + { + return File.SetTime(cTime, aTime, mTime); + } + bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); } + + bool SeekToBegin_bool() + { + #ifdef Z7_FILE_STREAMS_USE_WIN_FILE + return File.SeekToBegin(); + #else + return File.seekToBegin() == 0; + #endif + } + + HRESULT GetSize(UInt64 *size); +}; + + +Z7_CLASS_IMP_NOQIB_1( + CStdOutFileStream + , ISequentialOutStream +) + UInt64 _size; +public: + UInt64 GetSize() const { return _size; } + CStdOutFileStream(): _size(0) {} +}; + +#endif diff --git a/CPP/7zip/Common/FilterCoder.cpp b/CPP/7zip/Common/FilterCoder.cpp index ad59f0a80..8d7e0dccf 100644 --- a/CPP/7zip/Common/FilterCoder.cpp +++ b/CPP/7zip/Common/FilterCoder.cpp @@ -1,577 +1,577 @@ -// FilterCoder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../Common/Defs.h" - -#include "FilterCoder.h" -#include "StreamUtils.h" - -#ifdef _WIN32 - #define alignedMidBuffer_Alloc g_MidAlloc -#else - #define alignedMidBuffer_Alloc g_AlignedAlloc -#endif - -CAlignedMidBuffer::~CAlignedMidBuffer() -{ - ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf); -} - -void CAlignedMidBuffer::AllocAligned(size_t size) -{ - ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf); - _buf = (Byte *)ISzAlloc_Alloc(&alignedMidBuffer_Alloc, size); -} - -/* - AES filters need 16-bytes alignment for HARDWARE-AES instructions. - So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block. - - AES-CBC filters need data size aligned for 16-bytes. - So the encoder can add zeros to the end of original stream. - - Some filters (BCJ and others) don't process data at the end of stream in some cases. - So the encoder and decoder write such last bytes without change. - - Most filters process all data, if we send aligned size to filter. - But BCJ filter can process up 4 bytes less than sent size. - And ARMT filter can process 2 bytes less than sent size. -*/ - - -static const UInt32 kBufSize = 1 << 21; - -Z7_COM7F_IMF(CFilterCoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; } -Z7_COM7F_IMF(CFilterCoder::SetOutBufSize(UInt32 , UInt32 size)) { _outBufSize = size; return S_OK; } - -HRESULT CFilterCoder::Alloc() -{ - UInt32 size = MyMin(_inBufSize, _outBufSize); - /* minimal bufSize is 16 bytes for AES and IA64 filter. - bufSize for AES must be aligned for 16 bytes. - We use (1 << 12) min size to support future aligned filters. */ - const UInt32 kMinSize = 1 << 12; - size &= ~(UInt32)(kMinSize - 1); - if (size < kMinSize) - size = kMinSize; - // size = (1 << 12); // + 117; // for debug - if (!_buf || _bufSize != size) - { - AllocAligned(size); - if (!_buf) - return E_OUTOFMEMORY; - _bufSize = size; - } - return S_OK; -} - -HRESULT CFilterCoder::Init_and_Alloc() -{ - RINOK(Filter->Init()) - return Alloc(); -} - -CFilterCoder::CFilterCoder(bool encodeMode): - _bufSize(0), - _inBufSize(kBufSize), - _outBufSize(kBufSize), - _encodeMode(encodeMode), - _outSize_Defined(false), - _outSize(0), - _nowPos64(0) - {} - - -Z7_COM7F_IMF(CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - RINOK(Init_and_Alloc()) - - /* - It's expected that BCJ/ARMT filter can process up to 4 bytes less - than sent data size. For such BCJ/ARMT cases with non-filtered data we: - - write some filtered data to output stream - - move non-written data (filtered and non-filtered data) to start of buffer - - read more new data from input stream to position after end of non-filtered data - - call Filter() for concatenated data in buffer. - - For all cases, even for cases with partial filtering (BCJ/ARMT), - we try to keep real/virtual alignment for all operations - (memmove, Read(), Filter(), Write()). - We use (kAlignSize=64) alignmnent that is larger than (16-bytes) - required for AES filter alignment. - - AES-CBC uses 16-bytes blocks, that is simple case for processing here, - if we call Filter() for aligned size for all calls except of last call (last block). - And now there are no filters that use blocks with non-power2 size, - but we try to support such non-power2 filters too here at Code(). - */ - - UInt64 prev = 0; - UInt64 nowPos64 = 0; - bool inputFinished = false; - UInt32 readPos = 0; - UInt32 filterPos = 0; - - while (!outSize || nowPos64 < *outSize) - { - HRESULT hres = S_OK; - if (!inputFinished) - { - size_t processedSize = _bufSize - readPos; - /* for AES filters we need at least max(16, kAlignSize) bytes in buffer. - But we try to read full buffer to reduce the number of Filter() and Write() calls. - */ - hres = ReadStream(inStream, _buf + readPos, &processedSize); - readPos += (UInt32)processedSize; - inputFinished = (readPos != _bufSize); - if (hres != S_OK) - { - // do we need to stop encoding after reading error? - // if (_encodeMode) return hres; - inputFinished = true; - } - } - - if (readPos == 0) - return hres; - - /* we set (needMoreInput = true), if it's block-filter (like AES-CBC) - that needs more data for current block filtering: - We read full input buffer with Read(), and _bufSize is aligned, - So the possible cases when we set (needMoreInput = true) are: - 1) decode : filter needs more data after the end of input stream. - another cases are possible for non-power2-block-filter, - because buffer size is not aligned for filter_non_power2_block_size: - 2) decode/encode : filter needs more data from non-finished input stream - 3) encode : filter needs more space for zeros after the end of input stream - */ - bool needMoreInput = false; - - while (readPos != filterPos) - { - /* Filter() is allowed to process part of data. - Here we use the loop to filter as max as possible. - when we call Filter(data, size): - if (size < 16), AES-CTR filter uses internal 16-byte buffer. - new (since v23.00) AES-CTR filter allows (size < 16) for non-last block, - but it will work less efficiently than calls with aligned (size). - We still support old (before v23.00) AES-CTR filters here. - We have aligned (size) for AES-CTR, if it's not last block. - We have aligned (readPos) for any filter, if (!inputFinished). - We also meet the requirements for (data) pointer in Filter() call: - { - (virtual_stream_offset % aligment_size) == (data_ptr % aligment_size) - (aligment_size == 2^N) - (aligment_size >= 16) - } - */ - const UInt32 cur = Filter->Filter(_buf + filterPos, readPos - filterPos); - if (cur == 0) - break; - const UInt32 f = filterPos + cur; - if (cur > readPos - filterPos) - { - // AES-CBC - if (hres != S_OK) - break; - - if (!_encodeMode - || cur > _bufSize - filterPos - || !inputFinished) - { - /* (cur > _bufSize - filterPos) is unexpected for AES filter, if _bufSize is multiply of 16. - But we support this case, if some future filter will use block with non-power2-size. - */ - needMoreInput = true; - break; - } - - /* (_encodeMode && inputFinished). - We add zero bytes as pad in current block after the end of read data. */ - Byte *buf = _buf; - do - buf[readPos] = 0; - while (++readPos != f); - // (readPos) now is (size_of_real_input_data + size_of_zero_pad) - if (cur != Filter->Filter(buf + filterPos, cur)) - return E_FAIL; - } - filterPos = f; - } - - UInt32 size = filterPos; - if (hres == S_OK) - { - /* If we need more Read() or Filter() calls, then we need to Write() - some data and move unwritten data to get additional space in buffer. - We try to keep alignment for data moves, Read(), Filter() and Write() calls. - */ - const UInt32 kAlignSize = 1 << 6; - const UInt32 alignedFiltered = filterPos & ~(kAlignSize - 1); - if (inputFinished) - { - if (!needMoreInput) - size = readPos; // for risc/bcj filters in last block we write data after filterPos. - else if (_encodeMode) - size = alignedFiltered; // for non-power2-block-encode-filter - } - else - size = alignedFiltered; - } - - { - UInt32 writeSize = size; - if (outSize) - { - const UInt64 rem = *outSize - nowPos64; - if (writeSize > rem) - writeSize = (UInt32)rem; - } - RINOK(WriteStream(outStream, _buf, writeSize)) - nowPos64 += writeSize; - } - - if (hres != S_OK) - return hres; - - if (inputFinished) - { - if (readPos == size) - return hres; - if (!_encodeMode) - { - // block-decode-filter (AES-CBS) has non-full last block - // we don't want unaligned data move for more iterations with this error case. - return S_FALSE; - } - } - - if (size == 0) - { - // it's unexpected that we have no any move in this iteration. - return E_FAIL; - } - // if (size != 0) - { - if (filterPos < size) - return E_FAIL; // filterPos = 0; else - filterPos -= size; - readPos -= size; - if (readPos != 0) - memmove(_buf, _buf + size, readPos); - } - // printf("\nnowPos64=%x, readPos=%x, filterPos=%x\n", (unsigned)nowPos64, (unsigned)readPos, (unsigned)filterPos); - - if (progress && (nowPos64 - prev) >= (1 << 22)) - { - prev = nowPos64; - RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64)) - } - } - - return S_OK; -} - - - -// ---------- Write to Filter ---------- - -Z7_COM7F_IMF(CFilterCoder::SetOutStream(ISequentialOutStream *outStream)) -{ - _outStream = outStream; - return S_OK; -} - -Z7_COM7F_IMF(CFilterCoder::ReleaseOutStream()) -{ - _outStream.Release(); - return S_OK; -} - -HRESULT CFilterCoder::Flush2() -{ - while (_convSize != 0) - { - UInt32 num = _convSize; - if (_outSize_Defined) - { - const UInt64 rem = _outSize - _nowPos64; - if (num > rem) - num = (UInt32)rem; - if (num == 0) - return k_My_HRESULT_WritingWasCut; - } - - UInt32 processed = 0; - const HRESULT res = _outStream->Write(_buf + _convPos, num, &processed); - if (processed == 0) - return res != S_OK ? res : E_FAIL; - - _convPos += processed; - _convSize -= processed; - _nowPos64 += processed; - RINOK(res) - } - - const UInt32 convPos = _convPos; - if (convPos != 0) - { - const UInt32 num = _bufPos - convPos; - Byte *buf = _buf; - for (UInt32 i = 0; i < num; i++) - buf[i] = buf[convPos + i]; - _bufPos = num; - _convPos = 0; - } - - return S_OK; -} - -Z7_COM7F_IMF(CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - RINOK(Flush2()) - - // _convSize is 0 - // _convPos is 0 - // _bufPos is small - - if (_bufPos != _bufSize) - { - UInt32 num = MyMin(size, _bufSize - _bufPos); - memcpy(_buf + _bufPos, data, num); - size -= num; - data = (const Byte *)data + num; - if (processedSize) - *processedSize += num; - _bufPos += num; - if (_bufPos != _bufSize) - continue; - } - - // _bufPos == _bufSize - _convSize = Filter->Filter(_buf, _bufPos); - - if (_convSize == 0) - break; - if (_convSize > _bufPos) - { - // that case is not possible. - _convSize = 0; - return E_FAIL; - } - } - - return S_OK; -} - -Z7_COM7F_IMF(CFilterCoder::OutStreamFinish()) -{ - for (;;) - { - RINOK(Flush2()) - if (_bufPos == 0) - break; - const UInt32 convSize = Filter->Filter(_buf, _bufPos); - _convSize = convSize; - UInt32 bufPos = _bufPos; - if (convSize == 0) - _convSize = bufPos; - else if (convSize > bufPos) - { - // AES - if (convSize > _bufSize) - { - _convSize = 0; - return E_FAIL; - } - if (!_encodeMode) - { - _convSize = 0; - return S_FALSE; - } - Byte *buf = _buf; - for (; bufPos < convSize; bufPos++) - buf[bufPos] = 0; - _bufPos = bufPos; - _convSize = Filter->Filter(_buf, bufPos); - if (_convSize != _bufPos) - return E_FAIL; - } - } - - CMyComPtr finish; - _outStream.QueryInterface(IID_IOutStreamFinish, &finish); - if (finish) - return finish->OutStreamFinish(); - return S_OK; -} - -// ---------- Init functions ---------- - -Z7_COM7F_IMF(CFilterCoder::InitEncoder()) -{ - InitSpecVars(); - return Init_and_Alloc(); -} - -HRESULT CFilterCoder::Init_NoSubFilterInit() -{ - InitSpecVars(); - return Alloc(); -} - -Z7_COM7F_IMF(CFilterCoder::SetOutStreamSize(const UInt64 *outSize)) -{ - InitSpecVars(); - if (outSize) - { - _outSize = *outSize; - _outSize_Defined = true; - } - return Init_and_Alloc(); -} - -// ---------- Read from Filter ---------- - -Z7_COM7F_IMF(CFilterCoder::SetInStream(ISequentialInStream *inStream)) -{ - _inStream = inStream; - return S_OK; -} - -Z7_COM7F_IMF(CFilterCoder::ReleaseInStream()) -{ - _inStream.Release(); - return S_OK; -} - - -Z7_COM7F_IMF(CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - while (size != 0) - { - if (_convSize != 0) - { - if (size > _convSize) - size = _convSize; - if (_outSize_Defined) - { - const UInt64 rem = _outSize - _nowPos64; - if (size > rem) - size = (UInt32)rem; - } - memcpy(data, _buf + _convPos, size); - _convPos += size; - _convSize -= size; - _nowPos64 += size; - if (processedSize) - *processedSize = size; - break; - } - - const UInt32 convPos = _convPos; - if (convPos != 0) - { - const UInt32 num = _bufPos - convPos; - Byte *buf = _buf; - for (UInt32 i = 0; i < num; i++) - buf[i] = buf[convPos + i]; - _bufPos = num; - _convPos = 0; - } - - { - size_t readSize = _bufSize - _bufPos; - const HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize); - _bufPos += (UInt32)readSize; - RINOK(res) - } - - const UInt32 convSize = Filter->Filter(_buf, _bufPos); - _convSize = convSize; - - UInt32 bufPos = _bufPos; - - if (convSize == 0) - { - if (bufPos == 0) - break; - // BCJ - _convSize = bufPos; - continue; - } - - if (convSize > bufPos) - { - // AES - if (convSize > _bufSize) - return E_FAIL; - if (!_encodeMode) - return S_FALSE; - Byte *buf = _buf; - do - buf[bufPos] = 0; - while (++bufPos != convSize); - _bufPos = bufPos; - _convSize = Filter->Filter(_buf, convSize); - if (_convSize != _bufPos) - return E_FAIL; - } - } - - return S_OK; -} - - -#ifndef Z7_NO_CRYPTO - -Z7_COM7F_IMF(CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)) - { return _setPassword->CryptoSetPassword(data, size); } - -Z7_COM7F_IMF(CFilterCoder::SetKey(const Byte *data, UInt32 size)) - { return _cryptoProperties->SetKey(data, size); } - -Z7_COM7F_IMF(CFilterCoder::SetInitVector(const Byte *data, UInt32 size)) - { return _cryptoProperties->SetInitVector(data, size); } - -#endif - - -#ifndef Z7_EXTRACT_ONLY - -Z7_COM7F_IMF(CFilterCoder::SetCoderProperties(const PROPID *propIDs, - const PROPVARIANT *properties, UInt32 numProperties)) - { return _setCoderProperties->SetCoderProperties(propIDs, properties, numProperties); } - -Z7_COM7F_IMF(CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)) - { return _writeCoderProperties->WriteCoderProperties(outStream); } - -Z7_COM7F_IMF(CFilterCoder::SetCoderPropertiesOpt(const PROPID *propIDs, - const PROPVARIANT *properties, UInt32 numProperties)) - { return _setCoderPropertiesOpt->SetCoderPropertiesOpt(propIDs, properties, numProperties); } - -/* -Z7_COM7F_IMF(CFilterCoder::ResetSalt() - { return _cryptoResetSalt->ResetSalt(); } -*/ - -Z7_COM7F_IMF(CFilterCoder::ResetInitVector()) - { return _cryptoResetInitVector->ResetInitVector(); } - -#endif - - -Z7_COM7F_IMF(CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)) - { return _setDecoderProperties2->SetDecoderProperties2(data, size); } +// FilterCoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../Common/Defs.h" + +#include "FilterCoder.h" +#include "StreamUtils.h" + +#ifdef _WIN32 + #define alignedMidBuffer_Alloc g_MidAlloc +#else + #define alignedMidBuffer_Alloc g_AlignedAlloc +#endif + +CAlignedMidBuffer::~CAlignedMidBuffer() +{ + ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf); +} + +void CAlignedMidBuffer::AllocAligned(size_t size) +{ + ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf); + _buf = (Byte *)ISzAlloc_Alloc(&alignedMidBuffer_Alloc, size); +} + +/* + AES filters need 16-bytes alignment for HARDWARE-AES instructions. + So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block. + + AES-CBC filters need data size aligned for 16-bytes. + So the encoder can add zeros to the end of original stream. + + Some filters (BCJ and others) don't process data at the end of stream in some cases. + So the encoder and decoder write such last bytes without change. + + Most filters process all data, if we send aligned size to filter. + But BCJ filter can process up 4 bytes less than sent size. + And ARMT filter can process 2 bytes less than sent size. +*/ + + +static const UInt32 kBufSize = 1 << 21; + +Z7_COM7F_IMF(CFilterCoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; } +Z7_COM7F_IMF(CFilterCoder::SetOutBufSize(UInt32 , UInt32 size)) { _outBufSize = size; return S_OK; } + +HRESULT CFilterCoder::Alloc() +{ + UInt32 size = MyMin(_inBufSize, _outBufSize); + /* minimal bufSize is 16 bytes for AES and IA64 filter. + bufSize for AES must be aligned for 16 bytes. + We use (1 << 12) min size to support future aligned filters. */ + const UInt32 kMinSize = 1 << 12; + size &= ~(UInt32)(kMinSize - 1); + if (size < kMinSize) + size = kMinSize; + // size = (1 << 12); // + 117; // for debug + if (!_buf || _bufSize != size) + { + AllocAligned(size); + if (!_buf) + return E_OUTOFMEMORY; + _bufSize = size; + } + return S_OK; +} + +HRESULT CFilterCoder::Init_and_Alloc() +{ + RINOK(Filter->Init()) + return Alloc(); +} + +CFilterCoder::CFilterCoder(bool encodeMode): + _bufSize(0), + _inBufSize(kBufSize), + _outBufSize(kBufSize), + _encodeMode(encodeMode), + _outSize_Defined(false), + _outSize(0), + _nowPos64(0) + {} + + +Z7_COM7F_IMF(CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + RINOK(Init_and_Alloc()) + + /* + It's expected that BCJ/ARMT filter can process up to 4 bytes less + than sent data size. For such BCJ/ARMT cases with non-filtered data we: + - write some filtered data to output stream + - move non-written data (filtered and non-filtered data) to start of buffer + - read more new data from input stream to position after end of non-filtered data + - call Filter() for concatenated data in buffer. + + For all cases, even for cases with partial filtering (BCJ/ARMT), + we try to keep real/virtual alignment for all operations + (memmove, Read(), Filter(), Write()). + We use (kAlignSize=64) alignmnent that is larger than (16-bytes) + required for AES filter alignment. + + AES-CBC uses 16-bytes blocks, that is simple case for processing here, + if we call Filter() for aligned size for all calls except of last call (last block). + And now there are no filters that use blocks with non-power2 size, + but we try to support such non-power2 filters too here at Code(). + */ + + UInt64 prev = 0; + UInt64 nowPos64 = 0; + bool inputFinished = false; + UInt32 readPos = 0; + UInt32 filterPos = 0; + + while (!outSize || nowPos64 < *outSize) + { + HRESULT hres = S_OK; + if (!inputFinished) + { + size_t processedSize = _bufSize - readPos; + /* for AES filters we need at least max(16, kAlignSize) bytes in buffer. + But we try to read full buffer to reduce the number of Filter() and Write() calls. + */ + hres = ReadStream(inStream, _buf + readPos, &processedSize); + readPos += (UInt32)processedSize; + inputFinished = (readPos != _bufSize); + if (hres != S_OK) + { + // do we need to stop encoding after reading error? + // if (_encodeMode) return hres; + inputFinished = true; + } + } + + if (readPos == 0) + return hres; + + /* we set (needMoreInput = true), if it's block-filter (like AES-CBC) + that needs more data for current block filtering: + We read full input buffer with Read(), and _bufSize is aligned, + So the possible cases when we set (needMoreInput = true) are: + 1) decode : filter needs more data after the end of input stream. + another cases are possible for non-power2-block-filter, + because buffer size is not aligned for filter_non_power2_block_size: + 2) decode/encode : filter needs more data from non-finished input stream + 3) encode : filter needs more space for zeros after the end of input stream + */ + bool needMoreInput = false; + + while (readPos != filterPos) + { + /* Filter() is allowed to process part of data. + Here we use the loop to filter as max as possible. + when we call Filter(data, size): + if (size < 16), AES-CTR filter uses internal 16-byte buffer. + new (since v23.00) AES-CTR filter allows (size < 16) for non-last block, + but it will work less efficiently than calls with aligned (size). + We still support old (before v23.00) AES-CTR filters here. + We have aligned (size) for AES-CTR, if it's not last block. + We have aligned (readPos) for any filter, if (!inputFinished). + We also meet the requirements for (data) pointer in Filter() call: + { + (virtual_stream_offset % aligment_size) == (data_ptr % aligment_size) + (aligment_size == 2^N) + (aligment_size >= 16) + } + */ + const UInt32 cur = Filter->Filter(_buf + filterPos, readPos - filterPos); + if (cur == 0) + break; + const UInt32 f = filterPos + cur; + if (cur > readPos - filterPos) + { + // AES-CBC + if (hres != S_OK) + break; + + if (!_encodeMode + || cur > _bufSize - filterPos + || !inputFinished) + { + /* (cur > _bufSize - filterPos) is unexpected for AES filter, if _bufSize is multiply of 16. + But we support this case, if some future filter will use block with non-power2-size. + */ + needMoreInput = true; + break; + } + + /* (_encodeMode && inputFinished). + We add zero bytes as pad in current block after the end of read data. */ + Byte *buf = _buf; + do + buf[readPos] = 0; + while (++readPos != f); + // (readPos) now is (size_of_real_input_data + size_of_zero_pad) + if (cur != Filter->Filter(buf + filterPos, cur)) + return E_FAIL; + } + filterPos = f; + } + + UInt32 size = filterPos; + if (hres == S_OK) + { + /* If we need more Read() or Filter() calls, then we need to Write() + some data and move unwritten data to get additional space in buffer. + We try to keep alignment for data moves, Read(), Filter() and Write() calls. + */ + const UInt32 kAlignSize = 1 << 6; + const UInt32 alignedFiltered = filterPos & ~(kAlignSize - 1); + if (inputFinished) + { + if (!needMoreInput) + size = readPos; // for risc/bcj filters in last block we write data after filterPos. + else if (_encodeMode) + size = alignedFiltered; // for non-power2-block-encode-filter + } + else + size = alignedFiltered; + } + + { + UInt32 writeSize = size; + if (outSize) + { + const UInt64 rem = *outSize - nowPos64; + if (writeSize > rem) + writeSize = (UInt32)rem; + } + RINOK(WriteStream(outStream, _buf, writeSize)) + nowPos64 += writeSize; + } + + if (hres != S_OK) + return hres; + + if (inputFinished) + { + if (readPos == size) + return hres; + if (!_encodeMode) + { + // block-decode-filter (AES-CBS) has non-full last block + // we don't want unaligned data move for more iterations with this error case. + return S_FALSE; + } + } + + if (size == 0) + { + // it's unexpected that we have no any move in this iteration. + return E_FAIL; + } + // if (size != 0) + { + if (filterPos < size) + return E_FAIL; // filterPos = 0; else + filterPos -= size; + readPos -= size; + if (readPos != 0) + memmove(_buf, _buf + size, readPos); + } + // printf("\nnowPos64=%x, readPos=%x, filterPos=%x\n", (unsigned)nowPos64, (unsigned)readPos, (unsigned)filterPos); + + if (progress && (nowPos64 - prev) >= (1 << 22)) + { + prev = nowPos64; + RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64)) + } + } + + return S_OK; +} + + + +// ---------- Write to Filter ---------- + +Z7_COM7F_IMF(CFilterCoder::SetOutStream(ISequentialOutStream *outStream)) +{ + _outStream = outStream; + return S_OK; +} + +Z7_COM7F_IMF(CFilterCoder::ReleaseOutStream()) +{ + _outStream.Release(); + return S_OK; +} + +HRESULT CFilterCoder::Flush2() +{ + while (_convSize != 0) + { + UInt32 num = _convSize; + if (_outSize_Defined) + { + const UInt64 rem = _outSize - _nowPos64; + if (num > rem) + num = (UInt32)rem; + if (num == 0) + return k_My_HRESULT_WritingWasCut; + } + + UInt32 processed = 0; + const HRESULT res = _outStream->Write(_buf + _convPos, num, &processed); + if (processed == 0) + return res != S_OK ? res : E_FAIL; + + _convPos += processed; + _convSize -= processed; + _nowPos64 += processed; + RINOK(res) + } + + const UInt32 convPos = _convPos; + if (convPos != 0) + { + const UInt32 num = _bufPos - convPos; + Byte *buf = _buf; + for (UInt32 i = 0; i < num; i++) + buf[i] = buf[convPos + i]; + _bufPos = num; + _convPos = 0; + } + + return S_OK; +} + +Z7_COM7F_IMF(CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + RINOK(Flush2()) + + // _convSize is 0 + // _convPos is 0 + // _bufPos is small + + if (_bufPos != _bufSize) + { + UInt32 num = MyMin(size, _bufSize - _bufPos); + memcpy(_buf + _bufPos, data, num); + size -= num; + data = (const Byte *)data + num; + if (processedSize) + *processedSize += num; + _bufPos += num; + if (_bufPos != _bufSize) + continue; + } + + // _bufPos == _bufSize + _convSize = Filter->Filter(_buf, _bufPos); + + if (_convSize == 0) + break; + if (_convSize > _bufPos) + { + // that case is not possible. + _convSize = 0; + return E_FAIL; + } + } + + return S_OK; +} + +Z7_COM7F_IMF(CFilterCoder::OutStreamFinish()) +{ + for (;;) + { + RINOK(Flush2()) + if (_bufPos == 0) + break; + const UInt32 convSize = Filter->Filter(_buf, _bufPos); + _convSize = convSize; + UInt32 bufPos = _bufPos; + if (convSize == 0) + _convSize = bufPos; + else if (convSize > bufPos) + { + // AES + if (convSize > _bufSize) + { + _convSize = 0; + return E_FAIL; + } + if (!_encodeMode) + { + _convSize = 0; + return S_FALSE; + } + Byte *buf = _buf; + for (; bufPos < convSize; bufPos++) + buf[bufPos] = 0; + _bufPos = bufPos; + _convSize = Filter->Filter(_buf, bufPos); + if (_convSize != _bufPos) + return E_FAIL; + } + } + + CMyComPtr finish; + _outStream.QueryInterface(IID_IOutStreamFinish, &finish); + if (finish) + return finish->OutStreamFinish(); + return S_OK; +} + +// ---------- Init functions ---------- + +Z7_COM7F_IMF(CFilterCoder::InitEncoder()) +{ + InitSpecVars(); + return Init_and_Alloc(); +} + +HRESULT CFilterCoder::Init_NoSubFilterInit() +{ + InitSpecVars(); + return Alloc(); +} + +Z7_COM7F_IMF(CFilterCoder::SetOutStreamSize(const UInt64 *outSize)) +{ + InitSpecVars(); + if (outSize) + { + _outSize = *outSize; + _outSize_Defined = true; + } + return Init_and_Alloc(); +} + +// ---------- Read from Filter ---------- + +Z7_COM7F_IMF(CFilterCoder::SetInStream(ISequentialInStream *inStream)) +{ + _inStream = inStream; + return S_OK; +} + +Z7_COM7F_IMF(CFilterCoder::ReleaseInStream()) +{ + _inStream.Release(); + return S_OK; +} + + +Z7_COM7F_IMF(CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + while (size != 0) + { + if (_convSize != 0) + { + if (size > _convSize) + size = _convSize; + if (_outSize_Defined) + { + const UInt64 rem = _outSize - _nowPos64; + if (size > rem) + size = (UInt32)rem; + } + memcpy(data, _buf + _convPos, size); + _convPos += size; + _convSize -= size; + _nowPos64 += size; + if (processedSize) + *processedSize = size; + break; + } + + const UInt32 convPos = _convPos; + if (convPos != 0) + { + const UInt32 num = _bufPos - convPos; + Byte *buf = _buf; + for (UInt32 i = 0; i < num; i++) + buf[i] = buf[convPos + i]; + _bufPos = num; + _convPos = 0; + } + + { + size_t readSize = _bufSize - _bufPos; + const HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize); + _bufPos += (UInt32)readSize; + RINOK(res) + } + + const UInt32 convSize = Filter->Filter(_buf, _bufPos); + _convSize = convSize; + + UInt32 bufPos = _bufPos; + + if (convSize == 0) + { + if (bufPos == 0) + break; + // BCJ + _convSize = bufPos; + continue; + } + + if (convSize > bufPos) + { + // AES + if (convSize > _bufSize) + return E_FAIL; + if (!_encodeMode) + return S_FALSE; + Byte *buf = _buf; + do + buf[bufPos] = 0; + while (++bufPos != convSize); + _bufPos = bufPos; + _convSize = Filter->Filter(_buf, convSize); + if (_convSize != _bufPos) + return E_FAIL; + } + } + + return S_OK; +} + + +#ifndef Z7_NO_CRYPTO + +Z7_COM7F_IMF(CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)) + { return _setPassword->CryptoSetPassword(data, size); } + +Z7_COM7F_IMF(CFilterCoder::SetKey(const Byte *data, UInt32 size)) + { return _cryptoProperties->SetKey(data, size); } + +Z7_COM7F_IMF(CFilterCoder::SetInitVector(const Byte *data, UInt32 size)) + { return _cryptoProperties->SetInitVector(data, size); } + +#endif + + +#ifndef Z7_EXTRACT_ONLY + +Z7_COM7F_IMF(CFilterCoder::SetCoderProperties(const PROPID *propIDs, + const PROPVARIANT *properties, UInt32 numProperties)) + { return _setCoderProperties->SetCoderProperties(propIDs, properties, numProperties); } + +Z7_COM7F_IMF(CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)) + { return _writeCoderProperties->WriteCoderProperties(outStream); } + +Z7_COM7F_IMF(CFilterCoder::SetCoderPropertiesOpt(const PROPID *propIDs, + const PROPVARIANT *properties, UInt32 numProperties)) + { return _setCoderPropertiesOpt->SetCoderPropertiesOpt(propIDs, properties, numProperties); } + +/* +Z7_COM7F_IMF(CFilterCoder::ResetSalt() + { return _cryptoResetSalt->ResetSalt(); } +*/ + +Z7_COM7F_IMF(CFilterCoder::ResetInitVector()) + { return _cryptoResetInitVector->ResetInitVector(); } + +#endif + + +Z7_COM7F_IMF(CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)) + { return _setDecoderProperties2->SetDecoderProperties2(data, size); } diff --git a/CPP/7zip/Common/FilterCoder.h b/CPP/7zip/Common/FilterCoder.h index a5be6401c..3a588fd52 100644 --- a/CPP/7zip/Common/FilterCoder.h +++ b/CPP/7zip/Common/FilterCoder.h @@ -1,201 +1,201 @@ -// FilterCoder.h - -#ifndef ZIP7_INC_FILTER_CODER_H -#define ZIP7_INC_FILTER_CODER_H - -#include "../../../C/Alloc.h" - -#include "../../Common/MyCom.h" -#include "../ICoder.h" - -#ifndef Z7_NO_CRYPTO -#include "../IPassword.h" -#endif - -#define Z7_COM_QI_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \ - { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ - *outObject = (void *)(i *)this; } - - -struct CAlignedMidBuffer -{ - Byte *_buf; - - CAlignedMidBuffer(): _buf(NULL) {} - ~CAlignedMidBuffer(); - void AllocAligned(size_t size); -}; - - -class CFilterCoder Z7_final : - public ICompressCoder, - - public ICompressSetOutStreamSize, - public ICompressInitEncoder, - - public ICompressSetInStream, - public ISequentialInStream, - - public ICompressSetOutStream, - public ISequentialOutStream, - public IOutStreamFinish, - - public ICompressSetBufSize, - - #ifndef Z7_NO_CRYPTO - public ICryptoSetPassword, - public ICryptoProperties, - #endif - - #ifndef Z7_EXTRACT_ONLY - public ICompressSetCoderProperties, - public ICompressWriteCoderProperties, - public ICompressSetCoderPropertiesOpt, - // public ICryptoResetSalt, - public ICryptoResetInitVector, - #endif - - public ICompressSetDecoderProperties2, - public CMyUnknownImp, - public CAlignedMidBuffer -{ - UInt32 _bufSize; - UInt32 _inBufSize; - UInt32 _outBufSize; - - bool _encodeMode; - bool _outSize_Defined; - UInt64 _outSize; - UInt64 _nowPos64; - - CMyComPtr _inStream; - CMyComPtr _outStream; - UInt32 _bufPos; - UInt32 _convPos; // current pos in buffer for converted data - UInt32 _convSize; // size of converted data starting from _convPos - - void InitSpecVars() - { - _bufPos = 0; - _convPos = 0; - _convSize = 0; - - _outSize_Defined = false; - _outSize = 0; - _nowPos64 = 0; - } - - HRESULT Alloc(); - HRESULT Init_and_Alloc(); - HRESULT Flush2(); - - #ifndef Z7_NO_CRYPTO - CMyComPtr _setPassword; - CMyComPtr _cryptoProperties; - #endif - - #ifndef Z7_EXTRACT_ONLY - CMyComPtr _setCoderProperties; - CMyComPtr _writeCoderProperties; - CMyComPtr _setCoderPropertiesOpt; - // CMyComPtr _cryptoResetSalt; - CMyComPtr _cryptoResetInitVector; - #endif - - CMyComPtr _setDecoderProperties2; - -public: - CMyComPtr Filter; - - CFilterCoder(bool encodeMode); - - struct C_InStream_Releaser - { - CFilterCoder *FilterCoder; - C_InStream_Releaser(): FilterCoder(NULL) {} - ~C_InStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); } - }; - - struct C_OutStream_Releaser - { - CFilterCoder *FilterCoder; - C_OutStream_Releaser(): FilterCoder(NULL) {} - ~C_OutStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); } - }; - - struct C_Filter_Releaser - { - CFilterCoder *FilterCoder; - C_Filter_Releaser(): FilterCoder(NULL) {} - ~C_Filter_Releaser() { if (FilterCoder) FilterCoder->Filter.Release(); } - }; - -private: - Z7_COM_QI_BEGIN2(ICompressCoder) - - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ICompressInitEncoder) - - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ISequentialInStream) - - Z7_COM_QI_ENTRY(ICompressSetOutStream) - Z7_COM_QI_ENTRY(ISequentialOutStream) - Z7_COM_QI_ENTRY(IOutStreamFinish) - - Z7_COM_QI_ENTRY(ICompressSetBufSize) - - #ifndef Z7_NO_CRYPTO - Z7_COM_QI_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword) - Z7_COM_QI_ENTRY_AG(ICryptoProperties, Filter, _cryptoProperties) - #endif - - #ifndef Z7_EXTRACT_ONLY - Z7_COM_QI_ENTRY_AG(ICompressSetCoderProperties, Filter, _setCoderProperties) - Z7_COM_QI_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties) - Z7_COM_QI_ENTRY_AG(ICompressSetCoderPropertiesOpt, Filter, _setCoderPropertiesOpt) - // Z7_COM_QI_ENTRY_AG(ICryptoResetSalt, Filter, _cryptoResetSalt) - Z7_COM_QI_ENTRY_AG(ICryptoResetInitVector, Filter, _cryptoResetInitVector) - #endif - - Z7_COM_QI_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties2) - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - -public: - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - Z7_IFACE_COM7_IMP(ICompressInitEncoder) - Z7_IFACE_COM7_IMP(ICompressSetInStream) -private: - Z7_IFACE_COM7_IMP(ISequentialInStream) -public: - Z7_IFACE_COM7_IMP(ICompressSetOutStream) -private: - Z7_IFACE_COM7_IMP(ISequentialOutStream) -public: - Z7_IFACE_COM7_IMP(IOutStreamFinish) -private: - - Z7_IFACE_COM7_IMP(ICompressSetBufSize) - - #ifndef Z7_NO_CRYPTO - Z7_IFACE_COM7_IMP(ICryptoSetPassword) - Z7_IFACE_COM7_IMP(ICryptoProperties) - #endif - - #ifndef Z7_EXTRACT_ONLY - Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) - Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties) - Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt) - // Z7_IFACE_COM7_IMP(ICryptoResetSalt) - Z7_IFACE_COM7_IMP(ICryptoResetInitVector) - #endif - -public: - Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) - - HRESULT Init_NoSubFilterInit(); -}; - -#endif +// FilterCoder.h + +#ifndef ZIP7_INC_FILTER_CODER_H +#define ZIP7_INC_FILTER_CODER_H + +#include "../../../C/Alloc.h" + +#include "../../Common/MyCom.h" +#include "../ICoder.h" + +#ifndef Z7_NO_CRYPTO +#include "../IPassword.h" +#endif + +#define Z7_COM_QI_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \ + { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ + *outObject = (void *)(i *)this; } + + +struct CAlignedMidBuffer +{ + Byte *_buf; + + CAlignedMidBuffer(): _buf(NULL) {} + ~CAlignedMidBuffer(); + void AllocAligned(size_t size); +}; + + +class CFilterCoder Z7_final : + public ICompressCoder, + + public ICompressSetOutStreamSize, + public ICompressInitEncoder, + + public ICompressSetInStream, + public ISequentialInStream, + + public ICompressSetOutStream, + public ISequentialOutStream, + public IOutStreamFinish, + + public ICompressSetBufSize, + + #ifndef Z7_NO_CRYPTO + public ICryptoSetPassword, + public ICryptoProperties, + #endif + + #ifndef Z7_EXTRACT_ONLY + public ICompressSetCoderProperties, + public ICompressWriteCoderProperties, + public ICompressSetCoderPropertiesOpt, + // public ICryptoResetSalt, + public ICryptoResetInitVector, + #endif + + public ICompressSetDecoderProperties2, + public CMyUnknownImp, + public CAlignedMidBuffer +{ + UInt32 _bufSize; + UInt32 _inBufSize; + UInt32 _outBufSize; + + bool _encodeMode; + bool _outSize_Defined; + UInt64 _outSize; + UInt64 _nowPos64; + + CMyComPtr _inStream; + CMyComPtr _outStream; + UInt32 _bufPos; + UInt32 _convPos; // current pos in buffer for converted data + UInt32 _convSize; // size of converted data starting from _convPos + + void InitSpecVars() + { + _bufPos = 0; + _convPos = 0; + _convSize = 0; + + _outSize_Defined = false; + _outSize = 0; + _nowPos64 = 0; + } + + HRESULT Alloc(); + HRESULT Init_and_Alloc(); + HRESULT Flush2(); + + #ifndef Z7_NO_CRYPTO + CMyComPtr _setPassword; + CMyComPtr _cryptoProperties; + #endif + + #ifndef Z7_EXTRACT_ONLY + CMyComPtr _setCoderProperties; + CMyComPtr _writeCoderProperties; + CMyComPtr _setCoderPropertiesOpt; + // CMyComPtr _cryptoResetSalt; + CMyComPtr _cryptoResetInitVector; + #endif + + CMyComPtr _setDecoderProperties2; + +public: + CMyComPtr Filter; + + CFilterCoder(bool encodeMode); + + struct C_InStream_Releaser + { + CFilterCoder *FilterCoder; + C_InStream_Releaser(): FilterCoder(NULL) {} + ~C_InStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); } + }; + + struct C_OutStream_Releaser + { + CFilterCoder *FilterCoder; + C_OutStream_Releaser(): FilterCoder(NULL) {} + ~C_OutStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); } + }; + + struct C_Filter_Releaser + { + CFilterCoder *FilterCoder; + C_Filter_Releaser(): FilterCoder(NULL) {} + ~C_Filter_Releaser() { if (FilterCoder) FilterCoder->Filter.Release(); } + }; + +private: + Z7_COM_QI_BEGIN2(ICompressCoder) + + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ICompressInitEncoder) + + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ISequentialInStream) + + Z7_COM_QI_ENTRY(ICompressSetOutStream) + Z7_COM_QI_ENTRY(ISequentialOutStream) + Z7_COM_QI_ENTRY(IOutStreamFinish) + + Z7_COM_QI_ENTRY(ICompressSetBufSize) + + #ifndef Z7_NO_CRYPTO + Z7_COM_QI_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword) + Z7_COM_QI_ENTRY_AG(ICryptoProperties, Filter, _cryptoProperties) + #endif + + #ifndef Z7_EXTRACT_ONLY + Z7_COM_QI_ENTRY_AG(ICompressSetCoderProperties, Filter, _setCoderProperties) + Z7_COM_QI_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties) + Z7_COM_QI_ENTRY_AG(ICompressSetCoderPropertiesOpt, Filter, _setCoderPropertiesOpt) + // Z7_COM_QI_ENTRY_AG(ICryptoResetSalt, Filter, _cryptoResetSalt) + Z7_COM_QI_ENTRY_AG(ICryptoResetInitVector, Filter, _cryptoResetInitVector) + #endif + + Z7_COM_QI_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties2) + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + +public: + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + Z7_IFACE_COM7_IMP(ICompressInitEncoder) + Z7_IFACE_COM7_IMP(ICompressSetInStream) +private: + Z7_IFACE_COM7_IMP(ISequentialInStream) +public: + Z7_IFACE_COM7_IMP(ICompressSetOutStream) +private: + Z7_IFACE_COM7_IMP(ISequentialOutStream) +public: + Z7_IFACE_COM7_IMP(IOutStreamFinish) +private: + + Z7_IFACE_COM7_IMP(ICompressSetBufSize) + + #ifndef Z7_NO_CRYPTO + Z7_IFACE_COM7_IMP(ICryptoSetPassword) + Z7_IFACE_COM7_IMP(ICryptoProperties) + #endif + + #ifndef Z7_EXTRACT_ONLY + Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) + Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties) + Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt) + // Z7_IFACE_COM7_IMP(ICryptoResetSalt) + Z7_IFACE_COM7_IMP(ICryptoResetInitVector) + #endif + +public: + Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) + + HRESULT Init_NoSubFilterInit(); +}; + +#endif diff --git a/CPP/7zip/Common/InBuffer.cpp b/CPP/7zip/Common/InBuffer.cpp index 1e1fcb72c..ae004fbdc 100644 --- a/CPP/7zip/Common/InBuffer.cpp +++ b/CPP/7zip/Common/InBuffer.cpp @@ -1,182 +1,182 @@ -// InBuffer.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "InBuffer.h" - -CInBufferBase::CInBufferBase() throw(): - _buf(NULL), - _bufLim(NULL), - _bufBase(NULL), - _stream(NULL), - _processedSize(0), - _bufSize(0), - _wasFinished(false), - NumExtraBytes(0) -{} - -bool CInBuffer::Create(size_t bufSize) throw() -{ - const unsigned kMinBlockSize = 1; - if (bufSize < kMinBlockSize) - bufSize = kMinBlockSize; - if (_bufBase != NULL && _bufSize == bufSize) - return true; - Free(); - _bufSize = bufSize; - _bufBase = (Byte *)::MidAlloc(bufSize); - return (_bufBase != NULL); -} - -void CInBuffer::Free() throw() -{ - ::MidFree(_bufBase); - _bufBase = NULL; -} - -void CInBufferBase::Init() throw() -{ - _processedSize = 0; - _buf = _bufBase; - _bufLim = _buf; - _wasFinished = false; - #ifdef Z7_NO_EXCEPTIONS - ErrorCode = S_OK; - #endif - NumExtraBytes = 0; -} - -bool CInBufferBase::ReadBlock() -{ - #ifdef Z7_NO_EXCEPTIONS - if (ErrorCode != S_OK) - return false; - #endif - if (_wasFinished) - return false; - _processedSize += (size_t)(_buf - _bufBase); - _buf = _bufBase; - _bufLim = _bufBase; - UInt32 processed; - // FIX_ME: we can improve it to support (_bufSize >= (1 << 32)) - const HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed); - #ifdef Z7_NO_EXCEPTIONS - ErrorCode = result; - #else - if (result != S_OK) - throw CInBufferException(result); - #endif - _bufLim = _buf + processed; - _wasFinished = (processed == 0); - return !_wasFinished; -} - -bool CInBufferBase::ReadByte_FromNewBlock(Byte &b) -{ - if (!ReadBlock()) - { - // 22.00: we don't increment (NumExtraBytes) here - // NumExtraBytes++; - b = 0xFF; - return false; - } - b = *_buf++; - return true; -} - -Byte CInBufferBase::ReadByte_FromNewBlock() -{ - if (!ReadBlock()) - { - NumExtraBytes++; - return 0xFF; - } - return *_buf++; -} - -size_t CInBufferBase::ReadBytesPart(Byte *buf, size_t size) -{ - if (size == 0) - return 0; - size_t rem = (size_t)(_bufLim - _buf); - if (rem == 0) - { - if (!ReadBlock()) - return 0; - rem = (size_t)(_bufLim - _buf); - } - if (size > rem) - size = rem; - memcpy(buf, _buf, size); - _buf += size; - return size; -} - -size_t CInBufferBase::ReadBytes(Byte *buf, size_t size) -{ - size_t num = 0; - for (;;) - { - const size_t rem = (size_t)(_bufLim - _buf); - if (size <= rem) - { - if (size != 0) - { - memcpy(buf, _buf, size); - _buf += size; - num += size; - } - return num; - } - if (rem != 0) - { - memcpy(buf, _buf, rem); - _buf += rem; - buf += rem; - num += rem; - size -= rem; - } - if (!ReadBlock()) - return num; - } - - /* - if ((size_t)(_bufLim - _buf) >= size) - { - const Byte *src = _buf; - for (size_t i = 0; i < size; i++) - buf[i] = src[i]; - _buf += size; - return size; - } - for (size_t i = 0; i < size; i++) - { - if (_buf >= _bufLim) - if (!ReadBlock()) - return i; - buf[i] = *_buf++; - } - return size; - */ -} - -size_t CInBufferBase::Skip(size_t size) -{ - size_t processed = 0; - for (;;) - { - const size_t rem = (size_t)(_bufLim - _buf); - if (rem >= size) - { - _buf += size; - return processed + size; - } - _buf += rem; - processed += rem; - size -= rem; - if (!ReadBlock()) - return processed; - } -} +// InBuffer.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "InBuffer.h" + +CInBufferBase::CInBufferBase() throw(): + _buf(NULL), + _bufLim(NULL), + _bufBase(NULL), + _stream(NULL), + _processedSize(0), + _bufSize(0), + _wasFinished(false), + NumExtraBytes(0) +{} + +bool CInBuffer::Create(size_t bufSize) throw() +{ + const unsigned kMinBlockSize = 1; + if (bufSize < kMinBlockSize) + bufSize = kMinBlockSize; + if (_bufBase != NULL && _bufSize == bufSize) + return true; + Free(); + _bufSize = bufSize; + _bufBase = (Byte *)::MidAlloc(bufSize); + return (_bufBase != NULL); +} + +void CInBuffer::Free() throw() +{ + ::MidFree(_bufBase); + _bufBase = NULL; +} + +void CInBufferBase::Init() throw() +{ + _processedSize = 0; + _buf = _bufBase; + _bufLim = _buf; + _wasFinished = false; + #ifdef Z7_NO_EXCEPTIONS + ErrorCode = S_OK; + #endif + NumExtraBytes = 0; +} + +bool CInBufferBase::ReadBlock() +{ + #ifdef Z7_NO_EXCEPTIONS + if (ErrorCode != S_OK) + return false; + #endif + if (_wasFinished) + return false; + _processedSize += (size_t)(_buf - _bufBase); + _buf = _bufBase; + _bufLim = _bufBase; + UInt32 processed; + // FIX_ME: we can improve it to support (_bufSize >= (1 << 32)) + const HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed); + #ifdef Z7_NO_EXCEPTIONS + ErrorCode = result; + #else + if (result != S_OK) + throw CInBufferException(result); + #endif + _bufLim = _buf + processed; + _wasFinished = (processed == 0); + return !_wasFinished; +} + +bool CInBufferBase::ReadByte_FromNewBlock(Byte &b) +{ + if (!ReadBlock()) + { + // 22.00: we don't increment (NumExtraBytes) here + // NumExtraBytes++; + b = 0xFF; + return false; + } + b = *_buf++; + return true; +} + +Byte CInBufferBase::ReadByte_FromNewBlock() +{ + if (!ReadBlock()) + { + NumExtraBytes++; + return 0xFF; + } + return *_buf++; +} + +size_t CInBufferBase::ReadBytesPart(Byte *buf, size_t size) +{ + if (size == 0) + return 0; + size_t rem = (size_t)(_bufLim - _buf); + if (rem == 0) + { + if (!ReadBlock()) + return 0; + rem = (size_t)(_bufLim - _buf); + } + if (size > rem) + size = rem; + memcpy(buf, _buf, size); + _buf += size; + return size; +} + +size_t CInBufferBase::ReadBytes(Byte *buf, size_t size) +{ + size_t num = 0; + for (;;) + { + const size_t rem = (size_t)(_bufLim - _buf); + if (size <= rem) + { + if (size != 0) + { + memcpy(buf, _buf, size); + _buf += size; + num += size; + } + return num; + } + if (rem != 0) + { + memcpy(buf, _buf, rem); + _buf += rem; + buf += rem; + num += rem; + size -= rem; + } + if (!ReadBlock()) + return num; + } + + /* + if ((size_t)(_bufLim - _buf) >= size) + { + const Byte *src = _buf; + for (size_t i = 0; i < size; i++) + buf[i] = src[i]; + _buf += size; + return size; + } + for (size_t i = 0; i < size; i++) + { + if (_buf >= _bufLim) + if (!ReadBlock()) + return i; + buf[i] = *_buf++; + } + return size; + */ +} + +size_t CInBufferBase::Skip(size_t size) +{ + size_t processed = 0; + for (;;) + { + const size_t rem = (size_t)(_bufLim - _buf); + if (rem >= size) + { + _buf += size; + return processed + size; + } + _buf += rem; + processed += rem; + size -= rem; + if (!ReadBlock()) + return processed; + } +} diff --git a/CPP/7zip/Common/InBuffer.h b/CPP/7zip/Common/InBuffer.h index 21afd9f55..a8ccb40f4 100644 --- a/CPP/7zip/Common/InBuffer.h +++ b/CPP/7zip/Common/InBuffer.h @@ -1,111 +1,111 @@ -// InBuffer.h - -#ifndef ZIP7_INC_IN_BUFFER_H -#define ZIP7_INC_IN_BUFFER_H - -#include "../../Common/MyException.h" -#include "../IStream.h" - -#ifndef Z7_NO_EXCEPTIONS -struct CInBufferException: public CSystemException -{ - CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} -}; -#endif - -class CInBufferBase -{ -protected: - Byte *_buf; - Byte *_bufLim; - Byte *_bufBase; - - ISequentialInStream *_stream; - UInt64 _processedSize; - size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger - // only up to 32-bits values now are supported! - bool _wasFinished; - - bool ReadBlock(); - bool ReadByte_FromNewBlock(Byte &b); - Byte ReadByte_FromNewBlock(); - -public: - #ifdef Z7_NO_EXCEPTIONS - HRESULT ErrorCode; - #endif - UInt32 NumExtraBytes; - - CInBufferBase() throw(); - - // the size of portion of data in real stream that was already read from this object - // it doesn't include unused data in buffer - // it doesn't include virtual Extra bytes after the end of real stream data - UInt64 GetStreamSize() const { return _processedSize + (size_t)(_buf - _bufBase); } - - // the size of virtual data that was read from this object - // it doesn't include unused data in buffers - // it includes any virtual Extra bytes after the end of real data - UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (size_t)(_buf - _bufBase); } - - bool WasFinished() const { return _wasFinished; } - - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void ClearStreamPtr() { _stream = NULL; } - - void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos) - { - _bufBase = buf; - _bufSize = bufSize; - _processedSize = 0; - _buf = buf + pos; - _bufLim = buf + end; - _wasFinished = false; - #ifdef Z7_NO_EXCEPTIONS - ErrorCode = S_OK; - #endif - NumExtraBytes = 0; - } - - void Init() throw(); - - Z7_FORCE_INLINE - bool ReadByte(Byte &b) - { - if (_buf >= _bufLim) - return ReadByte_FromNewBlock(b); - b = *_buf++; - return true; - } - - Z7_FORCE_INLINE - bool ReadByte_FromBuf(Byte &b) - { - if (_buf >= _bufLim) - return false; - b = *_buf++; - return true; - } - - Z7_FORCE_INLINE - Byte ReadByte() - { - if (_buf >= _bufLim) - return ReadByte_FromNewBlock(); - return *_buf++; - } - - size_t ReadBytesPart(Byte *buf, size_t size); - size_t ReadBytes(Byte *buf, size_t size); - size_t Skip(size_t size); -}; - -class CInBuffer: public CInBufferBase -{ -public: - ~CInBuffer() { Free(); } - bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported! - void Free() throw(); -}; - -#endif +// InBuffer.h + +#ifndef ZIP7_INC_IN_BUFFER_H +#define ZIP7_INC_IN_BUFFER_H + +#include "../../Common/MyException.h" +#include "../IStream.h" + +#ifndef Z7_NO_EXCEPTIONS +struct CInBufferException: public CSystemException +{ + CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} +}; +#endif + +class CInBufferBase +{ +protected: + Byte *_buf; + Byte *_bufLim; + Byte *_bufBase; + + ISequentialInStream *_stream; + UInt64 _processedSize; + size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger + // only up to 32-bits values now are supported! + bool _wasFinished; + + bool ReadBlock(); + bool ReadByte_FromNewBlock(Byte &b); + Byte ReadByte_FromNewBlock(); + +public: + #ifdef Z7_NO_EXCEPTIONS + HRESULT ErrorCode; + #endif + UInt32 NumExtraBytes; + + CInBufferBase() throw(); + + // the size of portion of data in real stream that was already read from this object + // it doesn't include unused data in buffer + // it doesn't include virtual Extra bytes after the end of real stream data + UInt64 GetStreamSize() const { return _processedSize + (size_t)(_buf - _bufBase); } + + // the size of virtual data that was read from this object + // it doesn't include unused data in buffers + // it includes any virtual Extra bytes after the end of real data + UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (size_t)(_buf - _bufBase); } + + bool WasFinished() const { return _wasFinished; } + + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void ClearStreamPtr() { _stream = NULL; } + + void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos) + { + _bufBase = buf; + _bufSize = bufSize; + _processedSize = 0; + _buf = buf + pos; + _bufLim = buf + end; + _wasFinished = false; + #ifdef Z7_NO_EXCEPTIONS + ErrorCode = S_OK; + #endif + NumExtraBytes = 0; + } + + void Init() throw(); + + Z7_FORCE_INLINE + bool ReadByte(Byte &b) + { + if (_buf >= _bufLim) + return ReadByte_FromNewBlock(b); + b = *_buf++; + return true; + } + + Z7_FORCE_INLINE + bool ReadByte_FromBuf(Byte &b) + { + if (_buf >= _bufLim) + return false; + b = *_buf++; + return true; + } + + Z7_FORCE_INLINE + Byte ReadByte() + { + if (_buf >= _bufLim) + return ReadByte_FromNewBlock(); + return *_buf++; + } + + size_t ReadBytesPart(Byte *buf, size_t size); + size_t ReadBytes(Byte *buf, size_t size); + size_t Skip(size_t size); +}; + +class CInBuffer: public CInBufferBase +{ +public: + ~CInBuffer() { Free(); } + bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported! + void Free() throw(); +}; + +#endif diff --git a/CPP/7zip/Common/InOutTempBuffer.cpp b/CPP/7zip/Common/InOutTempBuffer.cpp index 45c868b44..3f7272ef8 100644 --- a/CPP/7zip/Common/InOutTempBuffer.cpp +++ b/CPP/7zip/Common/InOutTempBuffer.cpp @@ -1,237 +1,237 @@ -// InOutTempBuffer.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "InOutTempBuffer.h" - -#include "StreamUtils.h" - -#ifdef USE_InOutTempBuffer_FILE - -#include "../../../C/7zCrc.h" - -#define kTempFilePrefixString FTEXT("7zt") -/* - Total buffer size limit, if we use temp file scheme: - 32-bit: 16 MiB = 1 MiB * 16 buffers - 64-bit: 4 GiB = 1 MiB * 4096 buffers -*/ -static const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4); - -#endif - -static const size_t kBufSize = (size_t)1 << 20; - - -CInOutTempBuffer::CInOutTempBuffer(): - _size(0), - _bufs(NULL), - _numBufs(0), - _numFilled(0) -{ - #ifdef USE_InOutTempBuffer_FILE - _tempFile_Created = false; - _useMemOnly = false; - _crc = CRC_INIT_VAL; - #endif -} - -CInOutTempBuffer::~CInOutTempBuffer() -{ - for (size_t i = 0; i < _numBufs; i++) - MyFree(_bufs[i]); - MyFree(_bufs); -} - - -void *CInOutTempBuffer::GetBuf(size_t index) -{ - if (index >= _numBufs) - { - const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2); - void **p = (void **)MyRealloc(_bufs, num * sizeof(void *)); - if (!p) - return NULL; - _bufs = p; - memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *)); - _numBufs = num; - } - - void *buf = _bufs[index]; - if (!buf) - { - buf = MyAlloc(kBufSize); - if (buf) - _bufs[index] = buf; - } - return buf; -} - - -HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size) -{ - if (size == 0) - return S_OK; - - #ifdef USE_InOutTempBuffer_FILE - if (!_tempFile_Created) - #endif - for (;;) // loop for additional attemp to allocate memory after file creation error - { - #ifdef USE_InOutTempBuffer_FILE - bool allocError = false; - #endif - - for (;;) // loop for writing to buffers - { - const size_t index = (size_t)(_size / kBufSize); - - #ifdef USE_InOutTempBuffer_FILE - if (index >= kNumBufsMax && !_useMemOnly) - break; - #endif - - void *buf = GetBuf(index); - if (!buf) - { - #ifdef USE_InOutTempBuffer_FILE - if (!_useMemOnly) - { - allocError = true; - break; - } - #endif - return E_OUTOFMEMORY; - } - - const size_t offset = (size_t)(_size) & (kBufSize - 1); - size_t cur = kBufSize - offset; - if (cur > size) - cur = size; - memcpy((Byte *)buf + offset, data, cur); - _size += cur; - if (index >= _numFilled) - _numFilled = index + 1; - data = (const void *)((const Byte *)data + cur); - size -= (UInt32)cur; - if (size == 0) - return S_OK; - } - - #ifdef USE_InOutTempBuffer_FILE - #ifndef _WIN32 - _outFile.mode_for_Create = 0600; // only owner will have the rights to access this file - #endif - if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile)) - { - _tempFile_Created = true; - break; - } - _useMemOnly = true; - if (allocError) - return GetLastError_noZero_HRESULT(); - #endif - } - - #ifdef USE_InOutTempBuffer_FILE - if (!_outFile.WriteFull(data, size)) - return GetLastError_noZero_HRESULT(); - _crc = CrcUpdate(_crc, data, size); - _size += size; - return S_OK; - #endif -} - - -HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream) -{ - UInt64 rem = _size; - // if (rem == 0) return S_OK; - - const size_t numFilled = _numFilled; - _numFilled = 0; - - for (size_t i = 0; i < numFilled; i++) - { - if (rem == 0) - return E_FAIL; - size_t cur = kBufSize; - if (cur > rem) - cur = (size_t)rem; - RINOK(WriteStream(stream, _bufs[i], cur)) - rem -= cur; - #ifdef USE_InOutTempBuffer_FILE - // we will use _bufs[0] later for writing from temp file - if (i != 0 || !_tempFile_Created) - #endif - { - MyFree(_bufs[i]); - _bufs[i] = NULL; - } - } - - - #ifdef USE_InOutTempBuffer_FILE - - if (rem == 0) - return _tempFile_Created ? E_FAIL : S_OK; - - if (!_tempFile_Created) - return E_FAIL; - - if (!_outFile.Close()) - return GetLastError_noZero_HRESULT(); - - HRESULT hres; - void *buf = GetBuf(0); // index - if (!buf) - hres = E_OUTOFMEMORY; - else - { - NWindows::NFile::NIO::CInFile inFile; - if (!inFile.Open(_tempFile.GetPath())) - hres = GetLastError_noZero_HRESULT(); - else - { - UInt32 crc = CRC_INIT_VAL; - for (;;) - { - size_t processed; - if (!inFile.ReadFull(buf, kBufSize, processed)) - { - hres = GetLastError_noZero_HRESULT(); - break; - } - if (processed == 0) - { - // we compare crc without CRC_GET_DIGEST - hres = (_crc == crc ? S_OK : E_FAIL); - break; - } - size_t n = processed; - if (n > rem) - n = (size_t)rem; - hres = WriteStream(stream, buf, n); - if (hres != S_OK) - break; - crc = CrcUpdate(crc, buf, n); - rem -= n; - if (n != processed) - { - hres = E_FAIL; - break; - } - } - } - } - - // _tempFile.DisableDeleting(); // for debug - _tempFile.Remove(); - RINOK(hres) - - #endif - - return rem == 0 ? S_OK : E_FAIL; -} +// InOutTempBuffer.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "InOutTempBuffer.h" + +#include "StreamUtils.h" + +#ifdef USE_InOutTempBuffer_FILE + +#include "../../../C/7zCrc.h" + +#define kTempFilePrefixString FTEXT("7zt") +/* + Total buffer size limit, if we use temp file scheme: + 32-bit: 16 MiB = 1 MiB * 16 buffers + 64-bit: 4 GiB = 1 MiB * 4096 buffers +*/ +static const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4); + +#endif + +static const size_t kBufSize = (size_t)1 << 20; + + +CInOutTempBuffer::CInOutTempBuffer(): + _size(0), + _bufs(NULL), + _numBufs(0), + _numFilled(0) +{ + #ifdef USE_InOutTempBuffer_FILE + _tempFile_Created = false; + _useMemOnly = false; + _crc = CRC_INIT_VAL; + #endif +} + +CInOutTempBuffer::~CInOutTempBuffer() +{ + for (size_t i = 0; i < _numBufs; i++) + MyFree(_bufs[i]); + MyFree(_bufs); +} + + +void *CInOutTempBuffer::GetBuf(size_t index) +{ + if (index >= _numBufs) + { + const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2); + void **p = (void **)MyRealloc(_bufs, num * sizeof(void *)); + if (!p) + return NULL; + _bufs = p; + memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *)); + _numBufs = num; + } + + void *buf = _bufs[index]; + if (!buf) + { + buf = MyAlloc(kBufSize); + if (buf) + _bufs[index] = buf; + } + return buf; +} + + +HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size) +{ + if (size == 0) + return S_OK; + + #ifdef USE_InOutTempBuffer_FILE + if (!_tempFile_Created) + #endif + for (;;) // loop for additional attemp to allocate memory after file creation error + { + #ifdef USE_InOutTempBuffer_FILE + bool allocError = false; + #endif + + for (;;) // loop for writing to buffers + { + const size_t index = (size_t)(_size / kBufSize); + + #ifdef USE_InOutTempBuffer_FILE + if (index >= kNumBufsMax && !_useMemOnly) + break; + #endif + + void *buf = GetBuf(index); + if (!buf) + { + #ifdef USE_InOutTempBuffer_FILE + if (!_useMemOnly) + { + allocError = true; + break; + } + #endif + return E_OUTOFMEMORY; + } + + const size_t offset = (size_t)(_size) & (kBufSize - 1); + size_t cur = kBufSize - offset; + if (cur > size) + cur = size; + memcpy((Byte *)buf + offset, data, cur); + _size += cur; + if (index >= _numFilled) + _numFilled = index + 1; + data = (const void *)((const Byte *)data + cur); + size -= (UInt32)cur; + if (size == 0) + return S_OK; + } + + #ifdef USE_InOutTempBuffer_FILE + #ifndef _WIN32 + _outFile.mode_for_Create = 0600; // only owner will have the rights to access this file + #endif + if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile)) + { + _tempFile_Created = true; + break; + } + _useMemOnly = true; + if (allocError) + return GetLastError_noZero_HRESULT(); + #endif + } + + #ifdef USE_InOutTempBuffer_FILE + if (!_outFile.WriteFull(data, size)) + return GetLastError_noZero_HRESULT(); + _crc = CrcUpdate(_crc, data, size); + _size += size; + return S_OK; + #endif +} + + +HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream) +{ + UInt64 rem = _size; + // if (rem == 0) return S_OK; + + const size_t numFilled = _numFilled; + _numFilled = 0; + + for (size_t i = 0; i < numFilled; i++) + { + if (rem == 0) + return E_FAIL; + size_t cur = kBufSize; + if (cur > rem) + cur = (size_t)rem; + RINOK(WriteStream(stream, _bufs[i], cur)) + rem -= cur; + #ifdef USE_InOutTempBuffer_FILE + // we will use _bufs[0] later for writing from temp file + if (i != 0 || !_tempFile_Created) + #endif + { + MyFree(_bufs[i]); + _bufs[i] = NULL; + } + } + + + #ifdef USE_InOutTempBuffer_FILE + + if (rem == 0) + return _tempFile_Created ? E_FAIL : S_OK; + + if (!_tempFile_Created) + return E_FAIL; + + if (!_outFile.Close()) + return GetLastError_noZero_HRESULT(); + + HRESULT hres; + void *buf = GetBuf(0); // index + if (!buf) + hres = E_OUTOFMEMORY; + else + { + NWindows::NFile::NIO::CInFile inFile; + if (!inFile.Open(_tempFile.GetPath())) + hres = GetLastError_noZero_HRESULT(); + else + { + UInt32 crc = CRC_INIT_VAL; + for (;;) + { + size_t processed; + if (!inFile.ReadFull(buf, kBufSize, processed)) + { + hres = GetLastError_noZero_HRESULT(); + break; + } + if (processed == 0) + { + // we compare crc without CRC_GET_DIGEST + hres = (_crc == crc ? S_OK : E_FAIL); + break; + } + size_t n = processed; + if (n > rem) + n = (size_t)rem; + hres = WriteStream(stream, buf, n); + if (hres != S_OK) + break; + crc = CrcUpdate(crc, buf, n); + rem -= n; + if (n != processed) + { + hres = E_FAIL; + break; + } + } + } + } + + // _tempFile.DisableDeleting(); // for debug + _tempFile.Remove(); + RINOK(hres) + + #endif + + return rem == 0 ? S_OK : E_FAIL; +} diff --git a/CPP/7zip/Common/InOutTempBuffer.h b/CPP/7zip/Common/InOutTempBuffer.h index 221fde19f..345c3863c 100644 --- a/CPP/7zip/Common/InOutTempBuffer.h +++ b/CPP/7zip/Common/InOutTempBuffer.h @@ -1,45 +1,45 @@ -// InOutTempBuffer.h - -#ifndef ZIP7_INC_IN_OUT_TEMP_BUFFER_H -#define ZIP7_INC_IN_OUT_TEMP_BUFFER_H - -// #ifdef _WIN32 -#define USE_InOutTempBuffer_FILE -// #endif - -#ifdef USE_InOutTempBuffer_FILE -#include "../../Windows/FileDir.h" -#endif - -#include "../IStream.h" - -class CInOutTempBuffer -{ - UInt64 _size; - void **_bufs; - size_t _numBufs; - size_t _numFilled; - - #ifdef USE_InOutTempBuffer_FILE - - bool _tempFile_Created; - bool _useMemOnly; - UInt32 _crc; - // COutFile object must be declared after CTempFile object for correct destructor order - NWindows::NFile::NDir::CTempFile _tempFile; - NWindows::NFile::NIO::COutFile _outFile; - - #endif - - void *GetBuf(size_t index); - - Z7_CLASS_NO_COPY(CInOutTempBuffer) -public: - CInOutTempBuffer(); - ~CInOutTempBuffer(); - HRESULT Write_HRESULT(const void *data, UInt32 size); - HRESULT WriteToStream(ISequentialOutStream *stream); - UInt64 GetDataSize() const { return _size; } -}; - -#endif +// InOutTempBuffer.h + +#ifndef ZIP7_INC_IN_OUT_TEMP_BUFFER_H +#define ZIP7_INC_IN_OUT_TEMP_BUFFER_H + +// #ifdef _WIN32 +#define USE_InOutTempBuffer_FILE +// #endif + +#ifdef USE_InOutTempBuffer_FILE +#include "../../Windows/FileDir.h" +#endif + +#include "../IStream.h" + +class CInOutTempBuffer +{ + UInt64 _size; + void **_bufs; + size_t _numBufs; + size_t _numFilled; + + #ifdef USE_InOutTempBuffer_FILE + + bool _tempFile_Created; + bool _useMemOnly; + UInt32 _crc; + // COutFile object must be declared after CTempFile object for correct destructor order + NWindows::NFile::NDir::CTempFile _tempFile; + NWindows::NFile::NIO::COutFile _outFile; + + #endif + + void *GetBuf(size_t index); + + Z7_CLASS_NO_COPY(CInOutTempBuffer) +public: + CInOutTempBuffer(); + ~CInOutTempBuffer(); + HRESULT Write_HRESULT(const void *data, UInt32 size); + HRESULT WriteToStream(ISequentialOutStream *stream); + UInt64 GetDataSize() const { return _size; } +}; + +#endif diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp index 2d8a0007b..664cd0c4b 100644 --- a/CPP/7zip/Common/LimitedStreams.cpp +++ b/CPP/7zip/Common/LimitedStreams.cpp @@ -1,393 +1,393 @@ -// LimitedStreams.cpp - -#include "StdAfx.h" - -#include - -#include "LimitedStreams.h" - -Z7_COM7F_IMF(CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize = 0; - { - const UInt64 rem = _size - _pos; - if (size > rem) - size = (UInt32)rem; - } - HRESULT result = S_OK; - if (size != 0) - { - result = _stream->Read(data, size, &realProcessedSize); - _pos += realProcessedSize; - if (realProcessedSize == 0) - _wasFinished = true; - } - if (processedSize) - *processedSize = realProcessedSize; - return result; -} - -Z7_COM7F_IMF(CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= _size) - { - // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. - return S_OK; - // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF - } - { - const UInt64 rem = _size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - UInt64 newPos = _startOffset + _virtPos; - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()) - } - HRESULT res = _stream->Read(data, size, &size); - if (processedSize) - *processedSize = size; - _physPos += size; - _virtPos += size; - return res; -} - -Z7_COM7F_IMF(CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += _size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - -HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream) -{ - *resStream = NULL; - CLimitedInStream *streamSpec = new CLimitedInStream; - CMyComPtr streamTemp = streamSpec; - streamSpec->SetStream(inStream); - RINOK(streamSpec->InitAndSeek(pos, size)) - streamSpec->SeekToStart(); - *resStream = streamTemp.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= Size) - return S_OK; - { - UInt64 rem = Size - _virtPos; - if (size > rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - - if (_curRem == 0) - { - const UInt32 blockSize = (UInt32)1 << BlockSizeLog; - const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); - const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - const UInt32 phyBlock = Vector[virtBlock]; - - UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()) - } - - _curRem = blockSize - offsetInBlock; - - for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) - _curRem += (UInt32)1 << BlockSizeLog; - } - - if (size > _curRem) - size = _curRem; - HRESULT res = Stream->Read(data, size, &size); - if (processedSize) - *processedSize = size; - _physPos += size; - _virtPos += size; - _curRem -= size; - return res; -} - -Z7_COM7F_IMF(CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - if (_virtPos != (UInt64)offset) - _curRem = 0; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - -Z7_COM7F_IMF(CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - const UInt64 virt = _virtPos; - if (virt >= Extents.Back().Virt) - return S_OK; - if (size == 0) - return S_OK; - - unsigned left = _prevExtentIndex; - if (virt < Extents[left].Virt || - virt >= Extents[left + 1].Virt) - { - left = 0; - unsigned right = Extents.Size() - 1; - for (;;) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - if (mid == left) - break; - if (virt < Extents[mid].Virt) - right = mid; - else - left = mid; - } - _prevExtentIndex = left; - } - - { - const UInt64 rem = Extents[left + 1].Virt - virt; - if (size > rem) - size = (UInt32)rem; - } - - const CSeekExtent &extent = Extents[left]; - - if (extent.Is_ZeroFill()) - { - memset(data, 0, size); - _virtPos += size; - if (processedSize) - *processedSize = size; - return S_OK; - } - - { - const UInt64 phy = extent.Phy + (virt - extent.Virt); - if (_phyPos != phy) - { - _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error - RINOK(InStream_SeekSet(Stream, phy)) - _phyPos = phy; - } - } - - const HRESULT res = Stream->Read(data, size, &size); - _virtPos += size; - if (res == S_OK) - _phyPos += size; - else - _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error - if (processedSize) - *processedSize = size; - return res; -} - - -Z7_COM7F_IMF(CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += Extents.Back().Virt; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - - -Z7_COM7F_IMF(CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (processedSize) - *processedSize = 0; - if (size > _size) - { - if (_size == 0) - { - _overflow = true; - if (!_overflowIsAllowed) - return E_FAIL; - if (processedSize) - *processedSize = size; - return S_OK; - } - size = (UInt32)_size; - } - if (_stream) - result = _stream->Write(data, size, &size); - _size -= size; - if (processedSize) - *processedSize = size; - return result; -} - - -Z7_COM7F_IMF(CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 cur; - HRESULT res = Stream->Read(data, size, &cur); - if (processedSize) - *processedSize = cur; - _virtPos += cur; - return res; -} - -Z7_COM7F_IMF(CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: - { - UInt64 pos = 0; - RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos)) - if (pos < Offset) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = pos - Offset; - if (newPosition) - *newPosition = _virtPos; - return S_OK; - } - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = _virtPos; - return InStream_SeekSet(Stream, Offset + _virtPos); -} - -Z7_COM7F_IMF(CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (_virtPos >= _size) - { - // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. - return S_OK; - // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF - } - UInt64 rem = _size - _virtPos; - if (rem < size) - size = (UInt32)rem; - - UInt64 newPos = _startOffset + _virtPos; - UInt64 offsetInCache = newPos - _cachePhyPos; - HRESULT res = S_OK; - if (newPos >= _cachePhyPos && - offsetInCache <= _cacheSize && - size <= _cacheSize - (size_t)offsetInCache) - { - if (size != 0) - memcpy(data, _cache + (size_t)offsetInCache, size); - } - else - { - if (newPos != _physPos) - { - _physPos = newPos; - RINOK(SeekToPhys()) - } - res = _stream->Read(data, size, &size); - _physPos += size; - } - if (processedSize) - *processedSize = size; - _virtPos += size; - return res; -} - -Z7_COM7F_IMF(CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += _size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = _virtPos; - return S_OK; -} - -Z7_COM7F_IMF(CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 cur; - HRESULT res = Stream->Write(data, size, &cur); - if (processedSize) - *processedSize = cur; - _virtPos += cur; - if (_virtSize < _virtPos) - _virtSize = _virtPos; - return res; -} - -Z7_COM7F_IMF(CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _virtPos; break; - case STREAM_SEEK_END: offset += _virtSize; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _virtPos = (UInt64)offset; - if (newPosition) - *newPosition = _virtPos; - return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL); -} - -Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize)) -{ - _virtSize = newSize; - return Stream->SetSize(Offset + newSize); -} +// LimitedStreams.cpp + +#include "StdAfx.h" + +#include + +#include "LimitedStreams.h" + +Z7_COM7F_IMF(CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize = 0; + { + const UInt64 rem = _size - _pos; + if (size > rem) + size = (UInt32)rem; + } + HRESULT result = S_OK; + if (size != 0) + { + result = _stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + if (realProcessedSize == 0) + _wasFinished = true; + } + if (processedSize) + *processedSize = realProcessedSize; + return result; +} + +Z7_COM7F_IMF(CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + { + // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. + return S_OK; + // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF + } + { + const UInt64 rem = _size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + UInt64 newPos = _startOffset + _virtPos; + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()) + } + HRESULT res = _stream->Read(data, size, &size); + if (processedSize) + *processedSize = size; + _physPos += size; + _virtPos += size; + return res; +} + +Z7_COM7F_IMF(CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + +HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream) +{ + *resStream = NULL; + CLimitedInStream *streamSpec = new CLimitedInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->SetStream(inStream); + RINOK(streamSpec->InitAndSeek(pos, size)) + streamSpec->SeekToStart(); + *resStream = streamTemp.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= Size) + return S_OK; + { + UInt64 rem = Size - _virtPos; + if (size > rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + + if (_curRem == 0) + { + const UInt32 blockSize = (UInt32)1 << BlockSizeLog; + const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); + const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + const UInt32 phyBlock = Vector[virtBlock]; + + UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()) + } + + _curRem = blockSize - offsetInBlock; + + for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) + _curRem += (UInt32)1 << BlockSizeLog; + } + + if (size > _curRem) + size = _curRem; + HRESULT res = Stream->Read(data, size, &size); + if (processedSize) + *processedSize = size; + _physPos += size; + _virtPos += size; + _curRem -= size; + return res; +} + +Z7_COM7F_IMF(CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + if (_virtPos != (UInt64)offset) + _curRem = 0; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + +Z7_COM7F_IMF(CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + const UInt64 virt = _virtPos; + if (virt >= Extents.Back().Virt) + return S_OK; + if (size == 0) + return S_OK; + + unsigned left = _prevExtentIndex; + if (virt < Extents[left].Virt || + virt >= Extents[left + 1].Virt) + { + left = 0; + unsigned right = Extents.Size() - 1; + for (;;) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + if (mid == left) + break; + if (virt < Extents[mid].Virt) + right = mid; + else + left = mid; + } + _prevExtentIndex = left; + } + + { + const UInt64 rem = Extents[left + 1].Virt - virt; + if (size > rem) + size = (UInt32)rem; + } + + const CSeekExtent &extent = Extents[left]; + + if (extent.Is_ZeroFill()) + { + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + { + const UInt64 phy = extent.Phy + (virt - extent.Virt); + if (_phyPos != phy) + { + _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error + RINOK(InStream_SeekSet(Stream, phy)) + _phyPos = phy; + } + } + + const HRESULT res = Stream->Read(data, size, &size); + _virtPos += size; + if (res == S_OK) + _phyPos += size; + else + _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error + if (processedSize) + *processedSize = size; + return res; +} + + +Z7_COM7F_IMF(CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += Extents.Back().Virt; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + + +Z7_COM7F_IMF(CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (processedSize) + *processedSize = 0; + if (size > _size) + { + if (_size == 0) + { + _overflow = true; + if (!_overflowIsAllowed) + return E_FAIL; + if (processedSize) + *processedSize = size; + return S_OK; + } + size = (UInt32)_size; + } + if (_stream) + result = _stream->Write(data, size, &size); + _size -= size; + if (processedSize) + *processedSize = size; + return result; +} + + +Z7_COM7F_IMF(CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 cur; + HRESULT res = Stream->Read(data, size, &cur); + if (processedSize) + *processedSize = cur; + _virtPos += cur; + return res; +} + +Z7_COM7F_IMF(CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: + { + UInt64 pos = 0; + RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos)) + if (pos < Offset) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = pos - Offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; + } + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = _virtPos; + return InStream_SeekSet(Stream, Offset + _virtPos); +} + +Z7_COM7F_IMF(CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (_virtPos >= _size) + { + // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case. + return S_OK; + // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF + } + UInt64 rem = _size - _virtPos; + if (rem < size) + size = (UInt32)rem; + + UInt64 newPos = _startOffset + _virtPos; + UInt64 offsetInCache = newPos - _cachePhyPos; + HRESULT res = S_OK; + if (newPos >= _cachePhyPos && + offsetInCache <= _cacheSize && + size <= _cacheSize - (size_t)offsetInCache) + { + if (size != 0) + memcpy(data, _cache + (size_t)offsetInCache, size); + } + else + { + if (newPos != _physPos) + { + _physPos = newPos; + RINOK(SeekToPhys()) + } + res = _stream->Read(data, size, &size); + _physPos += size; + } + if (processedSize) + *processedSize = size; + _virtPos += size; + return res; +} + +Z7_COM7F_IMF(CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = _virtPos; + return S_OK; +} + +Z7_COM7F_IMF(CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 cur; + HRESULT res = Stream->Write(data, size, &cur); + if (processedSize) + *processedSize = cur; + _virtPos += cur; + if (_virtSize < _virtPos) + _virtSize = _virtPos; + return res; +} + +Z7_COM7F_IMF(CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _virtPos; break; + case STREAM_SEEK_END: offset += _virtSize; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _virtPos = (UInt64)offset; + if (newPosition) + *newPosition = _virtPos; + return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL); +} + +Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize)) +{ + _virtSize = newSize; + return Stream->SetSize(Offset + newSize); +} diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h index 3ee72fa46..69fcdcdb0 100644 --- a/CPP/7zip/Common/LimitedStreams.h +++ b/CPP/7zip/Common/LimitedStreams.h @@ -1,221 +1,221 @@ -// LimitedStreams.h - -#ifndef ZIP7_INC_LIMITED_STREAMS_H -#define ZIP7_INC_LIMITED_STREAMS_H - -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" -#include "../../Common/MyVector.h" -#include "../IStream.h" - -#include "StreamUtils.h" - -Z7_CLASS_IMP_COM_1( - CLimitedSequentialInStream - , ISequentialInStream -) - CMyComPtr _stream; - UInt64 _size; - UInt64 _pos; - bool _wasFinished; -public: - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(UInt64 streamSize) - { - _size = streamSize; - _pos = 0; - _wasFinished = false; - } - UInt64 GetSize() const { return _pos; } - UInt64 GetRem() const { return _size - _pos; } - bool WasFinished() const { return _wasFinished; } -}; - - -Z7_CLASS_IMP_IInStream( - CLimitedInStream -) - CMyComPtr _stream; - UInt64 _virtPos; - UInt64 _physPos; - UInt64 _size; - UInt64 _startOffset; - - HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); } -public: - void SetStream(IInStream *stream) { _stream = stream; } - HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) - { - _startOffset = startOffset; - _physPos = startOffset; - _virtPos = 0; - _size = size; - return SeekToPhys(); - } - HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } -}; - -HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream); - - -Z7_CLASS_IMP_IInStream( - CClusterInStream -) - UInt64 _virtPos; - UInt64 _physPos; - UInt32 _curRem; -public: - unsigned BlockSizeLog; - UInt64 Size; - CMyComPtr Stream; - CRecordVector Vector; - UInt64 StartOffset; - - HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); } - - HRESULT InitAndSeek() - { - _curRem = 0; - _virtPos = 0; - _physPos = StartOffset; - if (Vector.Size() > 0) - { - _physPos = StartOffset + (Vector[0] << BlockSizeLog); - return SeekToPhys(); - } - return S_OK; - } -}; - - - -const UInt64 k_SeekExtent_Phy_Type_ZeroFill = (UInt64)(Int64)-1; - -struct CSeekExtent -{ - UInt64 Virt; - UInt64 Phy; - - void SetAs_ZeroFill() { Phy = k_SeekExtent_Phy_Type_ZeroFill; } - bool Is_ZeroFill() const { return Phy == k_SeekExtent_Phy_Type_ZeroFill; } -}; - - -Z7_CLASS_IMP_IInStream( - CExtentsStream -) - UInt64 _virtPos; - UInt64 _phyPos; - unsigned _prevExtentIndex; -public: - CMyComPtr Stream; - CRecordVector Extents; - - void ReleaseStream() { Stream.Release(); } - void Init() - { - _virtPos = 0; - _phyPos = (UInt64)0 - 1; // we need Seek() for Stream - _prevExtentIndex = 0; - } -}; - - - -Z7_CLASS_IMP_COM_1( - CLimitedSequentialOutStream - , ISequentialOutStream -) - CMyComPtr _stream; - UInt64 _size; - bool _overflow; - bool _overflowIsAllowed; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(UInt64 size, bool overflowIsAllowed = false) - { - _size = size; - _overflow = false; - _overflowIsAllowed = overflowIsAllowed; - } - bool IsFinishedOK() const { return (_size == 0 && !_overflow); } - UInt64 GetRem() const { return _size; } -}; - - -Z7_CLASS_IMP_IInStream( - CTailInStream -) - UInt64 _virtPos; -public: - CMyComPtr Stream; - UInt64 Offset; - - void Init() - { - _virtPos = 0; - } - HRESULT SeekToStart() { return InStream_SeekSet(Stream, Offset); } -}; - - -Z7_CLASS_IMP_IInStream( - CLimitedCachedInStream -) - CMyComPtr _stream; - UInt64 _virtPos; - UInt64 _physPos; - UInt64 _size; - UInt64 _startOffset; - - const Byte *_cache; - size_t _cacheSize; - size_t _cachePhyPos; - - HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); } -public: - CByteBuffer Buffer; - - void SetStream(IInStream *stream) { _stream = stream; } - void SetCache(size_t cacheSize, size_t cachePos) - { - _cache = Buffer; - _cacheSize = cacheSize; - _cachePhyPos = cachePos; - } - - HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) - { - _startOffset = startOffset; - _physPos = startOffset; - _virtPos = 0; - _size = size; - return SeekToPhys(); - } - - HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } -}; - - -class CTailOutStream Z7_final : - public IOutStream, - public CMyUnknownImp -{ - Z7_IFACES_IMP_UNK_2(ISequentialOutStream, IOutStream) - - UInt64 _virtPos; - UInt64 _virtSize; -public: - CMyComPtr Stream; - UInt64 Offset; - - void Init() - { - _virtPos = 0; - _virtSize = 0; - } -}; - -#endif +// LimitedStreams.h + +#ifndef ZIP7_INC_LIMITED_STREAMS_H +#define ZIP7_INC_LIMITED_STREAMS_H + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyVector.h" +#include "../IStream.h" + +#include "StreamUtils.h" + +Z7_CLASS_IMP_COM_1( + CLimitedSequentialInStream + , ISequentialInStream +) + CMyComPtr _stream; + UInt64 _size; + UInt64 _pos; + bool _wasFinished; +public: + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(UInt64 streamSize) + { + _size = streamSize; + _pos = 0; + _wasFinished = false; + } + UInt64 GetSize() const { return _pos; } + UInt64 GetRem() const { return _size - _pos; } + bool WasFinished() const { return _wasFinished; } +}; + + +Z7_CLASS_IMP_IInStream( + CLimitedInStream +) + CMyComPtr _stream; + UInt64 _virtPos; + UInt64 _physPos; + UInt64 _size; + UInt64 _startOffset; + + HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); } +public: + void SetStream(IInStream *stream) { _stream = stream; } + HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) + { + _startOffset = startOffset; + _physPos = startOffset; + _virtPos = 0; + _size = size; + return SeekToPhys(); + } + HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } +}; + +HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream); + + +Z7_CLASS_IMP_IInStream( + CClusterInStream +) + UInt64 _virtPos; + UInt64 _physPos; + UInt32 _curRem; +public: + unsigned BlockSizeLog; + UInt64 Size; + CMyComPtr Stream; + CRecordVector Vector; + UInt64 StartOffset; + + HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); } + + HRESULT InitAndSeek() + { + _curRem = 0; + _virtPos = 0; + _physPos = StartOffset; + if (Vector.Size() > 0) + { + _physPos = StartOffset + (Vector[0] << BlockSizeLog); + return SeekToPhys(); + } + return S_OK; + } +}; + + + +const UInt64 k_SeekExtent_Phy_Type_ZeroFill = (UInt64)(Int64)-1; + +struct CSeekExtent +{ + UInt64 Virt; + UInt64 Phy; + + void SetAs_ZeroFill() { Phy = k_SeekExtent_Phy_Type_ZeroFill; } + bool Is_ZeroFill() const { return Phy == k_SeekExtent_Phy_Type_ZeroFill; } +}; + + +Z7_CLASS_IMP_IInStream( + CExtentsStream +) + UInt64 _virtPos; + UInt64 _phyPos; + unsigned _prevExtentIndex; +public: + CMyComPtr Stream; + CRecordVector Extents; + + void ReleaseStream() { Stream.Release(); } + void Init() + { + _virtPos = 0; + _phyPos = (UInt64)0 - 1; // we need Seek() for Stream + _prevExtentIndex = 0; + } +}; + + + +Z7_CLASS_IMP_COM_1( + CLimitedSequentialOutStream + , ISequentialOutStream +) + CMyComPtr _stream; + UInt64 _size; + bool _overflow; + bool _overflowIsAllowed; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(UInt64 size, bool overflowIsAllowed = false) + { + _size = size; + _overflow = false; + _overflowIsAllowed = overflowIsAllowed; + } + bool IsFinishedOK() const { return (_size == 0 && !_overflow); } + UInt64 GetRem() const { return _size; } +}; + + +Z7_CLASS_IMP_IInStream( + CTailInStream +) + UInt64 _virtPos; +public: + CMyComPtr Stream; + UInt64 Offset; + + void Init() + { + _virtPos = 0; + } + HRESULT SeekToStart() { return InStream_SeekSet(Stream, Offset); } +}; + + +Z7_CLASS_IMP_IInStream( + CLimitedCachedInStream +) + CMyComPtr _stream; + UInt64 _virtPos; + UInt64 _physPos; + UInt64 _size; + UInt64 _startOffset; + + const Byte *_cache; + size_t _cacheSize; + size_t _cachePhyPos; + + HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); } +public: + CByteBuffer Buffer; + + void SetStream(IInStream *stream) { _stream = stream; } + void SetCache(size_t cacheSize, size_t cachePos) + { + _cache = Buffer; + _cacheSize = cacheSize; + _cachePhyPos = cachePos; + } + + HRESULT InitAndSeek(UInt64 startOffset, UInt64 size) + { + _startOffset = startOffset; + _physPos = startOffset; + _virtPos = 0; + _size = size; + return SeekToPhys(); + } + + HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); } +}; + + +class CTailOutStream Z7_final : + public IOutStream, + public CMyUnknownImp +{ + Z7_IFACES_IMP_UNK_2(ISequentialOutStream, IOutStream) + + UInt64 _virtPos; + UInt64 _virtSize; +public: + CMyComPtr Stream; + UInt64 Offset; + + void Init() + { + _virtPos = 0; + _virtSize = 0; + } +}; + +#endif diff --git a/CPP/7zip/Common/LockedStream.cpp b/CPP/7zip/Common/LockedStream.cpp index 1223efe85..ca39fb455 100644 --- a/CPP/7zip/Common/LockedStream.cpp +++ b/CPP/7zip/Common/LockedStream.cpp @@ -1,3 +1,3 @@ -// LockedStream.cpp - -#include "StdAfx.h" +// LockedStream.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Common/LockedStream.h b/CPP/7zip/Common/LockedStream.h index 46d8410f7..99ee8055c 100644 --- a/CPP/7zip/Common/LockedStream.h +++ b/CPP/7zip/Common/LockedStream.h @@ -1,6 +1,6 @@ -// LockedStream.h - -#ifndef ZIP7_INC_LOCKED_STREAM_H -#define ZIP7_INC_LOCKED_STREAM_H - -#endif +// LockedStream.h + +#ifndef ZIP7_INC_LOCKED_STREAM_H +#define ZIP7_INC_LOCKED_STREAM_H + +#endif diff --git a/CPP/7zip/Common/MemBlocks.cpp b/CPP/7zip/Common/MemBlocks.cpp index 21c056028..6165c7e5f 100644 --- a/CPP/7zip/Common/MemBlocks.cpp +++ b/CPP/7zip/Common/MemBlocks.cpp @@ -1,215 +1,215 @@ -// MemBlocks.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "MemBlocks.h" -#include "StreamUtils.h" - -bool CMemBlockManager::AllocateSpace_bool(size_t numBlocks) -{ - FreeSpace(); - if (numBlocks == 0) - { - return true; - // return false; - } - if (_blockSize < sizeof(void *)) - return false; - const size_t totalSize = numBlocks * _blockSize; - if (totalSize / _blockSize != numBlocks) - return false; - _data = ::MidAlloc(totalSize); - if (!_data) - return false; - Byte *p = (Byte *)_data; - for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize) - *(Byte **)(void *)p = (p + _blockSize); - *(Byte **)(void *)p = NULL; - _headFree = _data; - return true; -} - -void CMemBlockManager::FreeSpace() -{ - ::MidFree(_data); - _data = NULL; - _headFree= NULL; -} - -void *CMemBlockManager::AllocateBlock() -{ - void *p = _headFree; - if (p) - _headFree = *(void **)p; - return p; -} - -void CMemBlockManager::FreeBlock(void *p) -{ - if (!p) - return; - *(void **)p = _headFree; - _headFree = p; -} - - -// #include - -HRESULT CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks) -{ - if (numNoLockBlocks > numBlocks) - return E_INVALIDARG; - const size_t numLockBlocks = numBlocks - numNoLockBlocks; - UInt32 maxCount = (UInt32)numLockBlocks; - if (maxCount != numLockBlocks) - return E_OUTOFMEMORY; - if (!CMemBlockManager::AllocateSpace_bool(numBlocks)) - return E_OUTOFMEMORY; - // we need (maxCount = 1), if we want to create non-use empty Semaphore - if (maxCount == 0) - maxCount = 1; - - // printf("\n Synchro.Create() \n"); - WRes wres; - #ifndef _WIN32 - Semaphore.Close(); - wres = Synchro.Create(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - wres = Semaphore.Create(&Synchro, (UInt32)numLockBlocks, maxCount); - #else - wres = Semaphore.OptCreateInit((UInt32)numLockBlocks, maxCount); - #endif - - return HRESULT_FROM_WIN32(wres); -} - - -HRESULT CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks) -{ - // desiredNumberOfBlocks = 0; // for debug - if (numNoLockBlocks > desiredNumberOfBlocks) - return E_INVALIDARG; - for (;;) - { - // if (desiredNumberOfBlocks == 0) return E_OUTOFMEMORY; - const HRESULT hres = AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks); - if (hres != E_OUTOFMEMORY) - return hres; - if (desiredNumberOfBlocks == numNoLockBlocks) - return E_OUTOFMEMORY; - desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1); - } -} - -void CMemBlockManagerMt::FreeSpace() -{ - Semaphore.Close(); - CMemBlockManager::FreeSpace(); -} - -void *CMemBlockManagerMt::AllocateBlock() -{ - // Semaphore.Lock(); - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - return CMemBlockManager::AllocateBlock(); -} - -void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode) -{ - if (!p) - return; - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - CMemBlockManager::FreeBlock(p); - } - if (lockMode) - Semaphore.Release(); -} - - - -void CMemBlocks::Free(CMemBlockManagerMt *manager) -{ - while (Blocks.Size() > 0) - { - manager->FreeBlock(Blocks.Back()); - Blocks.DeleteBack(); - } - TotalSize = 0; -} - -void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager) -{ - Free(manager); - Blocks.ClearAndFree(); -} - -HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const -{ - UInt64 totalSize = TotalSize; - for (unsigned blockIndex = 0; totalSize > 0; blockIndex++) - { - size_t curSize = blockSize; - if (curSize > totalSize) - curSize = (size_t)totalSize; - if (blockIndex >= Blocks.Size()) - return E_FAIL; - RINOK(WriteStream(outStream, Blocks[blockIndex], curSize)) - totalSize -= curSize; - } - return S_OK; -} - - -void CMemLockBlocks::FreeBlock(unsigned index, CMemBlockManagerMt *memManager) -{ - memManager->FreeBlock(Blocks[index], LockMode); - Blocks[index] = NULL; -} - -void CMemLockBlocks::Free(CMemBlockManagerMt *memManager) -{ - while (Blocks.Size() > 0) - { - FreeBlock(Blocks.Size() - 1, memManager); - Blocks.DeleteBack(); - } - TotalSize = 0; -} - -/* -HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager) -{ - if (LockMode) - { - if (Blocks.Size() > 0) - { - RINOK(memManager->ReleaseLockedBlocks(Blocks.Size())); - } - LockMode = false; - } - return 0; -} -*/ - -void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager) -{ - blocks.Free(memManager); - blocks.LockMode = LockMode; - UInt64 totalSize = 0; - const size_t blockSize = memManager->GetBlockSize(); - FOR_VECTOR (i, Blocks) - { - if (totalSize < TotalSize) - blocks.Blocks.Add(Blocks[i]); - else - FreeBlock(i, memManager); - Blocks[i] = NULL; - totalSize += blockSize; - } - blocks.TotalSize = TotalSize; - Free(memManager); -} +// MemBlocks.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "MemBlocks.h" +#include "StreamUtils.h" + +bool CMemBlockManager::AllocateSpace_bool(size_t numBlocks) +{ + FreeSpace(); + if (numBlocks == 0) + { + return true; + // return false; + } + if (_blockSize < sizeof(void *)) + return false; + const size_t totalSize = numBlocks * _blockSize; + if (totalSize / _blockSize != numBlocks) + return false; + _data = ::MidAlloc(totalSize); + if (!_data) + return false; + Byte *p = (Byte *)_data; + for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize) + *(Byte **)(void *)p = (p + _blockSize); + *(Byte **)(void *)p = NULL; + _headFree = _data; + return true; +} + +void CMemBlockManager::FreeSpace() +{ + ::MidFree(_data); + _data = NULL; + _headFree= NULL; +} + +void *CMemBlockManager::AllocateBlock() +{ + void *p = _headFree; + if (p) + _headFree = *(void **)p; + return p; +} + +void CMemBlockManager::FreeBlock(void *p) +{ + if (!p) + return; + *(void **)p = _headFree; + _headFree = p; +} + + +// #include + +HRESULT CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks) +{ + if (numNoLockBlocks > numBlocks) + return E_INVALIDARG; + const size_t numLockBlocks = numBlocks - numNoLockBlocks; + UInt32 maxCount = (UInt32)numLockBlocks; + if (maxCount != numLockBlocks) + return E_OUTOFMEMORY; + if (!CMemBlockManager::AllocateSpace_bool(numBlocks)) + return E_OUTOFMEMORY; + // we need (maxCount = 1), if we want to create non-use empty Semaphore + if (maxCount == 0) + maxCount = 1; + + // printf("\n Synchro.Create() \n"); + WRes wres; + #ifndef _WIN32 + Semaphore.Close(); + wres = Synchro.Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + wres = Semaphore.Create(&Synchro, (UInt32)numLockBlocks, maxCount); + #else + wres = Semaphore.OptCreateInit((UInt32)numLockBlocks, maxCount); + #endif + + return HRESULT_FROM_WIN32(wres); +} + + +HRESULT CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks) +{ + // desiredNumberOfBlocks = 0; // for debug + if (numNoLockBlocks > desiredNumberOfBlocks) + return E_INVALIDARG; + for (;;) + { + // if (desiredNumberOfBlocks == 0) return E_OUTOFMEMORY; + const HRESULT hres = AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks); + if (hres != E_OUTOFMEMORY) + return hres; + if (desiredNumberOfBlocks == numNoLockBlocks) + return E_OUTOFMEMORY; + desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1); + } +} + +void CMemBlockManagerMt::FreeSpace() +{ + Semaphore.Close(); + CMemBlockManager::FreeSpace(); +} + +void *CMemBlockManagerMt::AllocateBlock() +{ + // Semaphore.Lock(); + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + return CMemBlockManager::AllocateBlock(); +} + +void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode) +{ + if (!p) + return; + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + CMemBlockManager::FreeBlock(p); + } + if (lockMode) + Semaphore.Release(); +} + + + +void CMemBlocks::Free(CMemBlockManagerMt *manager) +{ + while (Blocks.Size() > 0) + { + manager->FreeBlock(Blocks.Back()); + Blocks.DeleteBack(); + } + TotalSize = 0; +} + +void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager) +{ + Free(manager); + Blocks.ClearAndFree(); +} + +HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const +{ + UInt64 totalSize = TotalSize; + for (unsigned blockIndex = 0; totalSize > 0; blockIndex++) + { + size_t curSize = blockSize; + if (curSize > totalSize) + curSize = (size_t)totalSize; + if (blockIndex >= Blocks.Size()) + return E_FAIL; + RINOK(WriteStream(outStream, Blocks[blockIndex], curSize)) + totalSize -= curSize; + } + return S_OK; +} + + +void CMemLockBlocks::FreeBlock(unsigned index, CMemBlockManagerMt *memManager) +{ + memManager->FreeBlock(Blocks[index], LockMode); + Blocks[index] = NULL; +} + +void CMemLockBlocks::Free(CMemBlockManagerMt *memManager) +{ + while (Blocks.Size() > 0) + { + FreeBlock(Blocks.Size() - 1, memManager); + Blocks.DeleteBack(); + } + TotalSize = 0; +} + +/* +HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager) +{ + if (LockMode) + { + if (Blocks.Size() > 0) + { + RINOK(memManager->ReleaseLockedBlocks(Blocks.Size())); + } + LockMode = false; + } + return 0; +} +*/ + +void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager) +{ + blocks.Free(memManager); + blocks.LockMode = LockMode; + UInt64 totalSize = 0; + const size_t blockSize = memManager->GetBlockSize(); + FOR_VECTOR (i, Blocks) + { + if (totalSize < TotalSize) + blocks.Blocks.Add(Blocks[i]); + else + FreeBlock(i, memManager); + Blocks[i] = NULL; + totalSize += blockSize; + } + blocks.TotalSize = TotalSize; + Free(memManager); +} diff --git a/CPP/7zip/Common/MemBlocks.h b/CPP/7zip/Common/MemBlocks.h index d60eed42d..201f3bc7d 100644 --- a/CPP/7zip/Common/MemBlocks.h +++ b/CPP/7zip/Common/MemBlocks.h @@ -1,72 +1,72 @@ -// MemBlocks.h - -#ifndef ZIP7_INC_MEM_BLOCKS_H -#define ZIP7_INC_MEM_BLOCKS_H - -#include "../../Common/MyVector.h" - -#include "../../Windows/Synchronization.h" - -#include "../IStream.h" - -class CMemBlockManager -{ - void *_data; - size_t _blockSize; - void *_headFree; -public: - CMemBlockManager(size_t blockSize = (1 << 20)): _data(NULL), _blockSize(blockSize), _headFree(NULL) {} - ~CMemBlockManager() { FreeSpace(); } - - bool AllocateSpace_bool(size_t numBlocks); - void FreeSpace(); - size_t GetBlockSize() const { return _blockSize; } - void *AllocateBlock(); - void FreeBlock(void *p); -}; - - -class CMemBlockManagerMt: public CMemBlockManager -{ - NWindows::NSynchronization::CCriticalSection _criticalSection; -public: - SYNC_OBJ_DECL(Synchro) - NWindows::NSynchronization::CSemaphore_WFMO Semaphore; - - CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {} - ~CMemBlockManagerMt() { FreeSpace(); } - - HRESULT AllocateSpace(size_t numBlocks, size_t numNoLockBlocks); - HRESULT AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0); - void FreeSpace(); - void *AllocateBlock(); - void FreeBlock(void *p, bool lockMode = true); - // WRes ReleaseLockedBlocks_WRes(unsigned number) { return Semaphore.Release(number); } -}; - - -class CMemBlocks -{ - void Free(CMemBlockManagerMt *manager); -public: - CRecordVector Blocks; - UInt64 TotalSize; - - CMemBlocks(): TotalSize(0) {} - - void FreeOpt(CMemBlockManagerMt *manager); - HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const; -}; - -struct CMemLockBlocks: public CMemBlocks -{ - bool LockMode; - - CMemLockBlocks(): LockMode(true) {} - void Free(CMemBlockManagerMt *memManager); - void FreeBlock(unsigned index, CMemBlockManagerMt *memManager); - // HRESULT SwitchToNoLockMode(CMemBlockManagerMt *memManager); - void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager); -}; - -#endif +// MemBlocks.h + +#ifndef ZIP7_INC_MEM_BLOCKS_H +#define ZIP7_INC_MEM_BLOCKS_H + +#include "../../Common/MyVector.h" + +#include "../../Windows/Synchronization.h" + +#include "../IStream.h" + +class CMemBlockManager +{ + void *_data; + size_t _blockSize; + void *_headFree; +public: + CMemBlockManager(size_t blockSize = (1 << 20)): _data(NULL), _blockSize(blockSize), _headFree(NULL) {} + ~CMemBlockManager() { FreeSpace(); } + + bool AllocateSpace_bool(size_t numBlocks); + void FreeSpace(); + size_t GetBlockSize() const { return _blockSize; } + void *AllocateBlock(); + void FreeBlock(void *p); +}; + + +class CMemBlockManagerMt: public CMemBlockManager +{ + NWindows::NSynchronization::CCriticalSection _criticalSection; +public: + SYNC_OBJ_DECL(Synchro) + NWindows::NSynchronization::CSemaphore_WFMO Semaphore; + + CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {} + ~CMemBlockManagerMt() { FreeSpace(); } + + HRESULT AllocateSpace(size_t numBlocks, size_t numNoLockBlocks); + HRESULT AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0); + void FreeSpace(); + void *AllocateBlock(); + void FreeBlock(void *p, bool lockMode = true); + // WRes ReleaseLockedBlocks_WRes(unsigned number) { return Semaphore.Release(number); } +}; + + +class CMemBlocks +{ + void Free(CMemBlockManagerMt *manager); +public: + CRecordVector Blocks; + UInt64 TotalSize; + + CMemBlocks(): TotalSize(0) {} + + void FreeOpt(CMemBlockManagerMt *manager); + HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const; +}; + +struct CMemLockBlocks: public CMemBlocks +{ + bool LockMode; + + CMemLockBlocks(): LockMode(true) {} + void Free(CMemBlockManagerMt *memManager); + void FreeBlock(unsigned index, CMemBlockManagerMt *memManager); + // HRESULT SwitchToNoLockMode(CMemBlockManagerMt *memManager); + void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager); +}; + +#endif diff --git a/CPP/7zip/Common/MethodId.cpp b/CPP/7zip/Common/MethodId.cpp index 9a07e4c9a..1566c97c1 100644 --- a/CPP/7zip/Common/MethodId.cpp +++ b/CPP/7zip/Common/MethodId.cpp @@ -1,3 +1,3 @@ -// MethodId.cpp - -#include "StdAfx.h" +// MethodId.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Common/MethodId.h b/CPP/7zip/Common/MethodId.h index a2c453d2e..19b1f10d5 100644 --- a/CPP/7zip/Common/MethodId.h +++ b/CPP/7zip/Common/MethodId.h @@ -1,10 +1,10 @@ -// MethodId.h - -#ifndef ZIP7_INC_7Z_METHOD_ID_H -#define ZIP7_INC_7Z_METHOD_ID_H - -#include "../../Common/MyTypes.h" - -typedef UInt64 CMethodId; - -#endif +// MethodId.h + +#ifndef ZIP7_INC_7Z_METHOD_ID_H +#define ZIP7_INC_7Z_METHOD_ID_H + +#include "../../Common/MyTypes.h" + +typedef UInt64 CMethodId; + +#endif diff --git a/CPP/7zip/Common/MethodProps.cpp b/CPP/7zip/Common/MethodProps.cpp index 70aab9ff1..d87884c29 100644 --- a/CPP/7zip/Common/MethodProps.cpp +++ b/CPP/7zip/Common/MethodProps.cpp @@ -1,739 +1,739 @@ -// MethodProps.cpp - -#include "StdAfx.h" - -#include "../../Common/StringToInt.h" - -#include "MethodProps.h" - -using namespace NWindows; - -UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents) -{ - // if (percents == 0) return 0; - const UInt64 q = percents / 100; - const UInt32 r = (UInt32)(percents % 100); - UInt64 res = 0; - - if (q != 0) - { - if (val > (UInt64)(Int64)-1 / q) - return (UInt64)(Int64)-1; - res = val * q; - } - - if (r != 0) - { - UInt64 v2; - if (val <= (UInt64)(Int64)-1 / r) - v2 = val * r / 100; - else - v2 = val / 100 * r; - res += v2; - if (res < v2) - return (UInt64)(Int64)-1; - } - - return res; -} - - -bool StringToBool(const wchar_t *s, bool &res) -{ - if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON")) - { - res = true; - return true; - } - if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF")) - { - res = false; - return true; - } - return false; -} - -HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest) -{ - switch (prop.vt) - { - case VT_EMPTY: dest = true; return S_OK; - case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK; - case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG; - default: break; - } - return E_INVALIDARG; -} - -unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number) -{ - const wchar_t *start = srcString; - const wchar_t *end; - number = ConvertStringToUInt32(start, &end); - return (unsigned)(end - start); -} - -static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number) -{ - const wchar_t *start = srcString; - const wchar_t *end; - number = ConvertStringToUInt64(start, &end); - return (unsigned)(end - start); -} - -HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) -{ - // =VT_UI4 - // =VT_EMPTY : it doesn't change (resValue), and returns S_OK - // {stringUInt32}=VT_EMPTY - - if (prop.vt == VT_UI4) - { - if (!name.IsEmpty()) - return E_INVALIDARG; - resValue = prop.ulVal; - return S_OK; - } - if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - if (name.IsEmpty()) - return S_OK; - UInt32 v; - if (ParseStringToUInt32(name, v) != name.Len()) - return E_INVALIDARG; - resValue = v; - return S_OK; -} - - - -HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force) -{ - force = false; - UString s; - if (name.IsEmpty()) - { - if (prop.vt == VT_UI4) - { - numThreads = prop.ulVal; - force = true; - return S_OK; - } - bool val; - HRESULT res = PROPVARIANT_to_bool(prop, val); - if (res == S_OK) - { - if (!val) - { - numThreads = 1; - force = true; - } - // force = true; for debug - // "(VT_BOOL = VARIANT_TRUE)" set "force = false" and doesn't change numThreads - return S_OK; - } - if (prop.vt != VT_BSTR) - return res; - s.SetFromBstr(prop.bstrVal); - if (s.IsEmpty()) - return E_INVALIDARG; - } - else - { - if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - s = name; - } - - s.MakeLower_Ascii(); - const wchar_t *start = s; - UInt32 v = numThreads; - - /* we force up, if threads number specified - only `d` will force it down */ - bool force_loc = true; - for (;;) - { - const wchar_t c = *start; - if (!c) - break; - if (c == 'd') - { - force_loc = false; // force down - start++; - continue; - } - if (c == 'u') - { - force_loc = true; // force up - start++; - continue; - } - bool isPercent = false; - if (c == 'p') - { - isPercent = true; - start++; - } - const wchar_t *end; - v = ConvertStringToUInt32(start, &end); - if (end == start) - return E_INVALIDARG; - if (isPercent) - v = numThreads * v / 100; - start = end; - } - - numThreads = v; - force = force_loc; - return S_OK; -} - - - -static HRESULT SetLogSizeProp(UInt64 number, NCOM::CPropVariant &destProp) -{ - if (number >= 64) - return E_INVALIDARG; - UInt32 val32; - if (number < 32) - val32 = (UInt32)1 << (unsigned)number; - /* - else if (number == 32 && reduce_4GB_to_32bits) - val32 = (UInt32)(Int32)-1; - */ - else - { - destProp = (UInt64)((UInt64)1 << (unsigned)number); - return S_OK; - } - destProp = (UInt32)val32; - return S_OK; -} - - -static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp) -{ - /* if (reduce_4GB_to_32bits) we can reduce (4 GiB) property to (4 GiB - 1). - to fit the value to UInt32 for clients that do not support 64-bit values */ - - const wchar_t *end; - const UInt64 number = ConvertStringToUInt64(s, &end); - const unsigned numDigits = (unsigned)(end - s.Ptr()); - if (numDigits == 0 || s.Len() > numDigits + 1) - return E_INVALIDARG; - - if (s.Len() == numDigits) - return SetLogSizeProp(number, destProp); - - unsigned numBits; - - switch (MyCharLower_Ascii(s[numDigits])) - { - case 'b': numBits = 0; break; - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - default: return E_INVALIDARG; - } - - const UInt64 range4g = ((UInt64)1 << (32 - numBits)); - if (number < range4g) - destProp = (UInt32)((UInt32)number << numBits); - /* - else if (number == range4g && reduce_4GB_to_32bits) - destProp = (UInt32)(Int32)-1; - */ - else if (numBits == 0) - destProp = (UInt64)number; - else if (number >= ((UInt64)1 << (64 - numBits))) - return E_INVALIDARG; - else - destProp = (UInt64)((UInt64)number << numBits); - return S_OK; -} - - -static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp) -{ - if (prop.vt == VT_UI4) - return SetLogSizeProp(prop.ulVal, destProp); - - if (prop.vt == VT_BSTR) - { - UString s; - s = prop.bstrVal; - return StringToDictSize(s, destProp); - } - return E_INVALIDARG; -} - - -void CProps::AddProp32(PROPID propid, UInt32 val) -{ - CProp &prop = Props.AddNew(); - prop.IsOptional = true; - prop.Id = propid; - prop.Value = (UInt32)val; -} - -void CProps::AddPropBool(PROPID propid, bool val) -{ - CProp &prop = Props.AddNew(); - prop.IsOptional = true; - prop.Id = propid; - prop.Value = val; -} - -class CCoderProps -{ - PROPID *_propIDs; - NCOM::CPropVariant *_props; - unsigned _numProps; - unsigned _numPropsMax; -public: - CCoderProps(unsigned numPropsMax): - _propIDs(NULL), - _props(NULL), - _numProps(0), - _numPropsMax(numPropsMax) - { - _propIDs = new PROPID[numPropsMax]; - _props = new NCOM::CPropVariant[numPropsMax]; - } - ~CCoderProps() - { - delete []_propIDs; - delete []_props; - } - void AddProp(const CProp &prop); - HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties) - { - return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps); - } -}; - -void CCoderProps::AddProp(const CProp &prop) -{ - if (_numProps >= _numPropsMax) - throw 1; - _propIDs[_numProps] = prop.Id; - _props[_numProps] = prop.Value; - _numProps++; -} - -HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const -{ - return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL); -} - -HRESULT CProps::SetCoderProps_DSReduce_Aff( - ICompressSetCoderProperties *scp, - const UInt64 *dataSizeReduce, - const UInt64 *affinity) const -{ - CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) ); - FOR_VECTOR (i, Props) - coderProps.AddProp(Props[i]); - if (dataSizeReduce) - { - CProp prop; - prop.Id = NCoderPropID::kReduceSize; - prop.Value = *dataSizeReduce; - coderProps.AddProp(prop); - } - if (affinity) - { - CProp prop; - prop.Id = NCoderPropID::kAffinity; - prop.Value = *affinity; - coderProps.AddProp(prop); - } - return coderProps.SetProps(scp); -} - - -int CMethodProps::FindProp(PROPID id) const -{ - for (unsigned i = Props.Size(); i != 0;) - if (Props[--i].Id == id) - return (int)i; - return -1; -} - -unsigned CMethodProps::GetLevel() const -{ - int i = FindProp(NCoderPropID::kLevel); - if (i < 0) - return 5; - if (Props[(unsigned)i].Value.vt != VT_UI4) - return 9; - UInt32 level = Props[(unsigned)i].Value.ulVal; - return level > 9 ? 9 : (unsigned)level; -} - -struct CNameToPropID -{ - VARTYPE VarType; - const char *Name; -}; - - -// the following are related to NCoderPropID::EEnum values -// NCoderPropID::k_NUM_DEFINED -static const CNameToPropID g_NameToPropID[] = -{ - { VT_UI4, "" }, - { VT_UI4, "d" }, - { VT_UI4, "mem" }, - { VT_UI4, "o" }, - { VT_UI8, "c" }, - { VT_UI4, "pb" }, - { VT_UI4, "lc" }, - { VT_UI4, "lp" }, - { VT_UI4, "fb" }, - { VT_BSTR, "mf" }, - { VT_UI4, "mc" }, - { VT_UI4, "pass" }, - { VT_UI4, "a" }, - { VT_UI4, "mt" }, - { VT_BOOL, "eos" }, - { VT_UI4, "x" }, - { VT_UI8, "reduce" }, - { VT_UI8, "expect" }, - { VT_UI8, "cc" }, // "cc" in v23, "b" in v22.01 - { VT_UI4, "check" }, - { VT_BSTR, "filter" }, - { VT_UI8, "memuse" }, - { VT_UI8, "aff" }, - { VT_UI4, "offset" }, - { VT_UI4, "zhb" } - /* - , - // { VT_UI4, "zhc" }, - // { VT_UI4, "zhd" }, - // { VT_UI4, "zcb" }, - { VT_UI4, "dc" }, - { VT_UI4, "zx" }, - { VT_UI4, "zf" }, - { VT_UI4, "zmml" }, - { VT_UI4, "zov" }, - { VT_BOOL, "zmfr" }, - { VT_BOOL, "zle" }, // long enable - // { VT_UI4, "zldb" }, - { VT_UI4, "zld" }, - { VT_UI4, "zlhb" }, - { VT_UI4, "zlmml" }, - { VT_UI4, "zlbb" }, - { VT_UI4, "zlhrb" }, - { VT_BOOL, "zwus" }, - { VT_BOOL, "zshp" }, - { VT_BOOL, "zshs" }, - { VT_BOOL, "zshe" }, - { VT_BOOL, "zshg" }, - { VT_UI4, "zpsm" } - */ - // { VT_UI4, "mcb" }, // mc log version - // { VT_UI4, "ztlen" }, // fb ? -}; - -/* -#if defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 200410L) || (defined(_MSC_VER) && _MSC_VER >= 1600) - -#if (defined(__cplusplus) && __cplusplus < 201103L) \ - && defined(__clang__) && __clang_major__ >= 4 -#pragma GCC diagnostic ignored "-Wc11-extensions" -#endif - static_assert(Z7_ARRAY_SIZE(g_NameToPropID) == NCoderPropID::k_NUM_DEFINED, - "g_NameToPropID doesn't match NCoderPropID enum"); -#endif -*/ - -static int FindPropIdExact(const UString &name) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NameToPropID); i++) - if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name)) - return (int)i; - return -1; -} - -static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) -{ - if (varType == srcProp.vt) - { - destProp = srcProp; - return true; - } - - if (varType == VT_UI8 && srcProp.vt == VT_UI4) - { - destProp = (UInt64)srcProp.ulVal; - return true; - } - - if (varType == VT_BOOL) - { - bool res; - if (PROPVARIANT_to_bool(srcProp, res) != S_OK) - return false; - destProp = res; - return true; - } - if (srcProp.vt == VT_EMPTY) - { - destProp = srcProp; - return true; - } - return false; -} - -static void SplitParams(const UString &srcString, UStringVector &subStrings) -{ - subStrings.Clear(); - UString s; - unsigned len = srcString.Len(); - if (len == 0) - return; - for (unsigned i = 0; i < len; i++) - { - wchar_t c = srcString[i]; - if (c == L':') - { - subStrings.Add(s); - s.Empty(); - } - else - s += c; - } - subStrings.Add(s); -} - -static void SplitParam(const UString ¶m, UString &name, UString &value) -{ - int eqPos = param.Find(L'='); - if (eqPos >= 0) - { - name.SetFrom(param, (unsigned)eqPos); - value = param.Ptr((unsigned)(eqPos + 1)); - return; - } - unsigned i; - for (i = 0; i < param.Len(); i++) - { - wchar_t c = param[i]; - if (c >= L'0' && c <= L'9') - break; - } - name.SetFrom(param, i); - value = param.Ptr(i); -} - -static bool IsLogSizeProp(PROPID propid) -{ - switch (propid) - { - case NCoderPropID::kDictionarySize: - case NCoderPropID::kUsedMemorySize: - case NCoderPropID::kBlockSize: - case NCoderPropID::kBlockSize2: - /* - case NCoderPropID::kChainSize: - case NCoderPropID::kLdmWindowSize: - */ - // case NCoderPropID::kReduceSize: - return true; - default: break; - } - return false; -} - -HRESULT CMethodProps::SetParam(const UString &name, const UString &value) -{ - int index = FindPropIdExact(name); - if (index < 0) - { - // 'b' was used as NCoderPropID::kBlockSize2 before v23 - if (!name.IsEqualTo_Ascii_NoCase("b") || value.Find(L':') >= 0) - return E_INVALIDARG; - index = NCoderPropID::kBlockSize2; - } - const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index]; - CProp prop; - prop.Id = (unsigned)index; - - if (IsLogSizeProp(prop.Id)) - { - RINOK(StringToDictSize(value, prop.Value)) - } - else - { - NCOM::CPropVariant propValue; - if (nameToPropID.VarType == VT_BSTR) - propValue = value; - else if (nameToPropID.VarType == VT_BOOL) - { - bool res; - if (!StringToBool(value, res)) - return E_INVALIDARG; - propValue = res; - } - else if (!value.IsEmpty()) - { - if (nameToPropID.VarType == VT_UI4) - { - UInt32 number; - if (ParseStringToUInt32(value, number) == value.Len()) - propValue = number; - else - propValue = value; - } - else if (nameToPropID.VarType == VT_UI8) - { - UInt64 number; - if (ParseStringToUInt64(value, number) == value.Len()) - propValue = number; - else - propValue = value; - } - else - propValue = value; - } - if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) - return E_INVALIDARG; - } - Props.Add(prop); - return S_OK; -} - -HRESULT CMethodProps::ParseParamsFromString(const UString &srcString) -{ - UStringVector params; - SplitParams(srcString, params); - FOR_VECTOR (i, params) - { - const UString ¶m = params[i]; - UString name, value; - SplitParam(param, name, value); - RINOK(SetParam(name, value)) - } - return S_OK; -} - -HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) -{ - if (realName.Len() == 0) - { - // [empty]=method - return E_INVALIDARG; - } - if (value.vt == VT_EMPTY) - { - // {realName}=[empty] - UString name, valueStr; - SplitParam(realName, name, valueStr); - return SetParam(name, valueStr); - } - - // {realName}=value - const int index = FindPropIdExact(realName); - if (index < 0) - return E_INVALIDARG; - const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index]; - CProp prop; - prop.Id = (unsigned)index; - - if (IsLogSizeProp(prop.Id)) - { - RINOK(PROPVARIANT_to_DictSize(value, prop.Value)) - } - else - { - if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) - return E_INVALIDARG; - } - Props.Add(prop); - return S_OK; -} - - -static UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads) -{ - UInt32 hs = dict - 1; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - hs >>= 1; - if (hs >= (1 << 24)) - hs >>= 1; - hs |= (1 << 16) - 1; - // if (numHashBytes >= 5) - if (!isBt) - hs |= (256 << 10) - 1; - hs++; - UInt64 size1 = (UInt64)hs * 4; - size1 += (UInt64)dict * 4; - if (isBt) - size1 += (UInt64)dict * 4; - size1 += (2 << 20); - - if (numThreads > 1 && isBt) - size1 += (2 << 20) + (4 << 20); - return size1; -} - -static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28; - -UInt64 CMethodProps::Get_Lzma_MemUsage(bool addSlidingWindowSize) const -{ - const UInt64 dicSize = Get_Lzma_DicSize(); - const bool isBt = Get_Lzma_MatchFinder_IsBt(); - const UInt32 dict32 = (dicSize >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dicSize); - const UInt32 numThreads = Get_Lzma_NumThreads(); - UInt64 size = GetMemoryUsage_LZMA(dict32, isBt, numThreads); - - if (addSlidingWindowSize) - { - const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); - UInt64 blockSize = (UInt64)dict32 + (1 << 16) - + (numThreads > 1 ? (1 << 20) : 0); - blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); - if (blockSize >= kBlockSizeMax) - blockSize = kBlockSizeMax; - size += blockSize; - } - return size; -} - - - - -HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) -{ - MethodName.Empty(); - int splitPos = s.Find(L':'); - { - UString temp = s; - if (splitPos >= 0) - temp.DeleteFrom((unsigned)splitPos); - if (!temp.IsAscii()) - return E_INVALIDARG; - MethodName.SetFromWStr_if_Ascii(temp); - } - if (splitPos < 0) - return S_OK; - PropsString = s.Ptr((unsigned)(splitPos + 1)); - return ParseParamsFromString(PropsString); -} - -HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) -{ - if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m")) - return ParseParamsFromPROPVARIANT(realName, value); - // -m{N}=method - if (value.vt != VT_BSTR) - return E_INVALIDARG; - UString s; - s = value.bstrVal; - return ParseMethodFromString(s); -} +// MethodProps.cpp + +#include "StdAfx.h" + +#include "../../Common/StringToInt.h" + +#include "MethodProps.h" + +using namespace NWindows; + +UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents) +{ + // if (percents == 0) return 0; + const UInt64 q = percents / 100; + const UInt32 r = (UInt32)(percents % 100); + UInt64 res = 0; + + if (q != 0) + { + if (val > (UInt64)(Int64)-1 / q) + return (UInt64)(Int64)-1; + res = val * q; + } + + if (r != 0) + { + UInt64 v2; + if (val <= (UInt64)(Int64)-1 / r) + v2 = val * r / 100; + else + v2 = val / 100 * r; + res += v2; + if (res < v2) + return (UInt64)(Int64)-1; + } + + return res; +} + + +bool StringToBool(const wchar_t *s, bool &res) +{ + if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON")) + { + res = true; + return true; + } + if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF")) + { + res = false; + return true; + } + return false; +} + +HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest) +{ + switch (prop.vt) + { + case VT_EMPTY: dest = true; return S_OK; + case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK; + case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG; + default: break; + } + return E_INVALIDARG; +} + +unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number) +{ + const wchar_t *start = srcString; + const wchar_t *end; + number = ConvertStringToUInt32(start, &end); + return (unsigned)(end - start); +} + +static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number) +{ + const wchar_t *start = srcString; + const wchar_t *end; + number = ConvertStringToUInt64(start, &end); + return (unsigned)(end - start); +} + +HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) +{ + // =VT_UI4 + // =VT_EMPTY : it doesn't change (resValue), and returns S_OK + // {stringUInt32}=VT_EMPTY + + if (prop.vt == VT_UI4) + { + if (!name.IsEmpty()) + return E_INVALIDARG; + resValue = prop.ulVal; + return S_OK; + } + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + if (name.IsEmpty()) + return S_OK; + UInt32 v; + if (ParseStringToUInt32(name, v) != name.Len()) + return E_INVALIDARG; + resValue = v; + return S_OK; +} + + + +HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force) +{ + force = false; + UString s; + if (name.IsEmpty()) + { + if (prop.vt == VT_UI4) + { + numThreads = prop.ulVal; + force = true; + return S_OK; + } + bool val; + HRESULT res = PROPVARIANT_to_bool(prop, val); + if (res == S_OK) + { + if (!val) + { + numThreads = 1; + force = true; + } + // force = true; for debug + // "(VT_BOOL = VARIANT_TRUE)" set "force = false" and doesn't change numThreads + return S_OK; + } + if (prop.vt != VT_BSTR) + return res; + s.SetFromBstr(prop.bstrVal); + if (s.IsEmpty()) + return E_INVALIDARG; + } + else + { + if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + s = name; + } + + s.MakeLower_Ascii(); + const wchar_t *start = s; + UInt32 v = numThreads; + + /* we force up, if threads number specified + only `d` will force it down */ + bool force_loc = true; + for (;;) + { + const wchar_t c = *start; + if (!c) + break; + if (c == 'd') + { + force_loc = false; // force down + start++; + continue; + } + if (c == 'u') + { + force_loc = true; // force up + start++; + continue; + } + bool isPercent = false; + if (c == 'p') + { + isPercent = true; + start++; + } + const wchar_t *end; + v = ConvertStringToUInt32(start, &end); + if (end == start) + return E_INVALIDARG; + if (isPercent) + v = numThreads * v / 100; + start = end; + } + + numThreads = v; + force = force_loc; + return S_OK; +} + + + +static HRESULT SetLogSizeProp(UInt64 number, NCOM::CPropVariant &destProp) +{ + if (number >= 64) + return E_INVALIDARG; + UInt32 val32; + if (number < 32) + val32 = (UInt32)1 << (unsigned)number; + /* + else if (number == 32 && reduce_4GB_to_32bits) + val32 = (UInt32)(Int32)-1; + */ + else + { + destProp = (UInt64)((UInt64)1 << (unsigned)number); + return S_OK; + } + destProp = (UInt32)val32; + return S_OK; +} + + +static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp) +{ + /* if (reduce_4GB_to_32bits) we can reduce (4 GiB) property to (4 GiB - 1). + to fit the value to UInt32 for clients that do not support 64-bit values */ + + const wchar_t *end; + const UInt64 number = ConvertStringToUInt64(s, &end); + const unsigned numDigits = (unsigned)(end - s.Ptr()); + if (numDigits == 0 || s.Len() > numDigits + 1) + return E_INVALIDARG; + + if (s.Len() == numDigits) + return SetLogSizeProp(number, destProp); + + unsigned numBits; + + switch (MyCharLower_Ascii(s[numDigits])) + { + case 'b': numBits = 0; break; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + default: return E_INVALIDARG; + } + + const UInt64 range4g = ((UInt64)1 << (32 - numBits)); + if (number < range4g) + destProp = (UInt32)((UInt32)number << numBits); + /* + else if (number == range4g && reduce_4GB_to_32bits) + destProp = (UInt32)(Int32)-1; + */ + else if (numBits == 0) + destProp = (UInt64)number; + else if (number >= ((UInt64)1 << (64 - numBits))) + return E_INVALIDARG; + else + destProp = (UInt64)((UInt64)number << numBits); + return S_OK; +} + + +static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp) +{ + if (prop.vt == VT_UI4) + return SetLogSizeProp(prop.ulVal, destProp); + + if (prop.vt == VT_BSTR) + { + UString s; + s = prop.bstrVal; + return StringToDictSize(s, destProp); + } + return E_INVALIDARG; +} + + +void CProps::AddProp32(PROPID propid, UInt32 val) +{ + CProp &prop = Props.AddNew(); + prop.IsOptional = true; + prop.Id = propid; + prop.Value = (UInt32)val; +} + +void CProps::AddPropBool(PROPID propid, bool val) +{ + CProp &prop = Props.AddNew(); + prop.IsOptional = true; + prop.Id = propid; + prop.Value = val; +} + +class CCoderProps +{ + PROPID *_propIDs; + NCOM::CPropVariant *_props; + unsigned _numProps; + unsigned _numPropsMax; +public: + CCoderProps(unsigned numPropsMax): + _propIDs(NULL), + _props(NULL), + _numProps(0), + _numPropsMax(numPropsMax) + { + _propIDs = new PROPID[numPropsMax]; + _props = new NCOM::CPropVariant[numPropsMax]; + } + ~CCoderProps() + { + delete []_propIDs; + delete []_props; + } + void AddProp(const CProp &prop); + HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties) + { + return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps); + } +}; + +void CCoderProps::AddProp(const CProp &prop) +{ + if (_numProps >= _numPropsMax) + throw 1; + _propIDs[_numProps] = prop.Id; + _props[_numProps] = prop.Value; + _numProps++; +} + +HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const +{ + return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL); +} + +HRESULT CProps::SetCoderProps_DSReduce_Aff( + ICompressSetCoderProperties *scp, + const UInt64 *dataSizeReduce, + const UInt64 *affinity) const +{ + CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) ); + FOR_VECTOR (i, Props) + coderProps.AddProp(Props[i]); + if (dataSizeReduce) + { + CProp prop; + prop.Id = NCoderPropID::kReduceSize; + prop.Value = *dataSizeReduce; + coderProps.AddProp(prop); + } + if (affinity) + { + CProp prop; + prop.Id = NCoderPropID::kAffinity; + prop.Value = *affinity; + coderProps.AddProp(prop); + } + return coderProps.SetProps(scp); +} + + +int CMethodProps::FindProp(PROPID id) const +{ + for (unsigned i = Props.Size(); i != 0;) + if (Props[--i].Id == id) + return (int)i; + return -1; +} + +unsigned CMethodProps::GetLevel() const +{ + int i = FindProp(NCoderPropID::kLevel); + if (i < 0) + return 5; + if (Props[(unsigned)i].Value.vt != VT_UI4) + return 9; + UInt32 level = Props[(unsigned)i].Value.ulVal; + return level > 9 ? 9 : (unsigned)level; +} + +struct CNameToPropID +{ + VARTYPE VarType; + const char *Name; +}; + + +// the following are related to NCoderPropID::EEnum values +// NCoderPropID::k_NUM_DEFINED +static const CNameToPropID g_NameToPropID[] = +{ + { VT_UI4, "" }, + { VT_UI4, "d" }, + { VT_UI4, "mem" }, + { VT_UI4, "o" }, + { VT_UI8, "c" }, + { VT_UI4, "pb" }, + { VT_UI4, "lc" }, + { VT_UI4, "lp" }, + { VT_UI4, "fb" }, + { VT_BSTR, "mf" }, + { VT_UI4, "mc" }, + { VT_UI4, "pass" }, + { VT_UI4, "a" }, + { VT_UI4, "mt" }, + { VT_BOOL, "eos" }, + { VT_UI4, "x" }, + { VT_UI8, "reduce" }, + { VT_UI8, "expect" }, + { VT_UI8, "cc" }, // "cc" in v23, "b" in v22.01 + { VT_UI4, "check" }, + { VT_BSTR, "filter" }, + { VT_UI8, "memuse" }, + { VT_UI8, "aff" }, + { VT_UI4, "offset" }, + { VT_UI4, "zhb" } + /* + , + // { VT_UI4, "zhc" }, + // { VT_UI4, "zhd" }, + // { VT_UI4, "zcb" }, + { VT_UI4, "dc" }, + { VT_UI4, "zx" }, + { VT_UI4, "zf" }, + { VT_UI4, "zmml" }, + { VT_UI4, "zov" }, + { VT_BOOL, "zmfr" }, + { VT_BOOL, "zle" }, // long enable + // { VT_UI4, "zldb" }, + { VT_UI4, "zld" }, + { VT_UI4, "zlhb" }, + { VT_UI4, "zlmml" }, + { VT_UI4, "zlbb" }, + { VT_UI4, "zlhrb" }, + { VT_BOOL, "zwus" }, + { VT_BOOL, "zshp" }, + { VT_BOOL, "zshs" }, + { VT_BOOL, "zshe" }, + { VT_BOOL, "zshg" }, + { VT_UI4, "zpsm" } + */ + // { VT_UI4, "mcb" }, // mc log version + // { VT_UI4, "ztlen" }, // fb ? +}; + +/* +#if defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 200410L) || (defined(_MSC_VER) && _MSC_VER >= 1600) + +#if (defined(__cplusplus) && __cplusplus < 201103L) \ + && defined(__clang__) && __clang_major__ >= 4 +#pragma GCC diagnostic ignored "-Wc11-extensions" +#endif + static_assert(Z7_ARRAY_SIZE(g_NameToPropID) == NCoderPropID::k_NUM_DEFINED, + "g_NameToPropID doesn't match NCoderPropID enum"); +#endif +*/ + +static int FindPropIdExact(const UString &name) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NameToPropID); i++) + if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name)) + return (int)i; + return -1; +} + +static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) +{ + if (varType == srcProp.vt) + { + destProp = srcProp; + return true; + } + + if (varType == VT_UI8 && srcProp.vt == VT_UI4) + { + destProp = (UInt64)srcProp.ulVal; + return true; + } + + if (varType == VT_BOOL) + { + bool res; + if (PROPVARIANT_to_bool(srcProp, res) != S_OK) + return false; + destProp = res; + return true; + } + if (srcProp.vt == VT_EMPTY) + { + destProp = srcProp; + return true; + } + return false; +} + +static void SplitParams(const UString &srcString, UStringVector &subStrings) +{ + subStrings.Clear(); + UString s; + unsigned len = srcString.Len(); + if (len == 0) + return; + for (unsigned i = 0; i < len; i++) + { + wchar_t c = srcString[i]; + if (c == L':') + { + subStrings.Add(s); + s.Empty(); + } + else + s += c; + } + subStrings.Add(s); +} + +static void SplitParam(const UString ¶m, UString &name, UString &value) +{ + int eqPos = param.Find(L'='); + if (eqPos >= 0) + { + name.SetFrom(param, (unsigned)eqPos); + value = param.Ptr((unsigned)(eqPos + 1)); + return; + } + unsigned i; + for (i = 0; i < param.Len(); i++) + { + wchar_t c = param[i]; + if (c >= L'0' && c <= L'9') + break; + } + name.SetFrom(param, i); + value = param.Ptr(i); +} + +static bool IsLogSizeProp(PROPID propid) +{ + switch (propid) + { + case NCoderPropID::kDictionarySize: + case NCoderPropID::kUsedMemorySize: + case NCoderPropID::kBlockSize: + case NCoderPropID::kBlockSize2: + /* + case NCoderPropID::kChainSize: + case NCoderPropID::kLdmWindowSize: + */ + // case NCoderPropID::kReduceSize: + return true; + default: break; + } + return false; +} + +HRESULT CMethodProps::SetParam(const UString &name, const UString &value) +{ + int index = FindPropIdExact(name); + if (index < 0) + { + // 'b' was used as NCoderPropID::kBlockSize2 before v23 + if (!name.IsEqualTo_Ascii_NoCase("b") || value.Find(L':') >= 0) + return E_INVALIDARG; + index = NCoderPropID::kBlockSize2; + } + const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index]; + CProp prop; + prop.Id = (unsigned)index; + + if (IsLogSizeProp(prop.Id)) + { + RINOK(StringToDictSize(value, prop.Value)) + } + else + { + NCOM::CPropVariant propValue; + if (nameToPropID.VarType == VT_BSTR) + propValue = value; + else if (nameToPropID.VarType == VT_BOOL) + { + bool res; + if (!StringToBool(value, res)) + return E_INVALIDARG; + propValue = res; + } + else if (!value.IsEmpty()) + { + if (nameToPropID.VarType == VT_UI4) + { + UInt32 number; + if (ParseStringToUInt32(value, number) == value.Len()) + propValue = number; + else + propValue = value; + } + else if (nameToPropID.VarType == VT_UI8) + { + UInt64 number; + if (ParseStringToUInt64(value, number) == value.Len()) + propValue = number; + else + propValue = value; + } + else + propValue = value; + } + if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) + return E_INVALIDARG; + } + Props.Add(prop); + return S_OK; +} + +HRESULT CMethodProps::ParseParamsFromString(const UString &srcString) +{ + UStringVector params; + SplitParams(srcString, params); + FOR_VECTOR (i, params) + { + const UString ¶m = params[i]; + UString name, value; + SplitParam(param, name, value); + RINOK(SetParam(name, value)) + } + return S_OK; +} + +HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) +{ + if (realName.Len() == 0) + { + // [empty]=method + return E_INVALIDARG; + } + if (value.vt == VT_EMPTY) + { + // {realName}=[empty] + UString name, valueStr; + SplitParam(realName, name, valueStr); + return SetParam(name, valueStr); + } + + // {realName}=value + const int index = FindPropIdExact(realName); + if (index < 0) + return E_INVALIDARG; + const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index]; + CProp prop; + prop.Id = (unsigned)index; + + if (IsLogSizeProp(prop.Id)) + { + RINOK(PROPVARIANT_to_DictSize(value, prop.Value)) + } + else + { + if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) + return E_INVALIDARG; + } + Props.Add(prop); + return S_OK; +} + + +static UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads) +{ + UInt32 hs = dict - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + if (hs >= (1 << 24)) + hs >>= 1; + hs |= (1 << 16) - 1; + // if (numHashBytes >= 5) + if (!isBt) + hs |= (256 << 10) - 1; + hs++; + UInt64 size1 = (UInt64)hs * 4; + size1 += (UInt64)dict * 4; + if (isBt) + size1 += (UInt64)dict * 4; + size1 += (2 << 20); + + if (numThreads > 1 && isBt) + size1 += (2 << 20) + (4 << 20); + return size1; +} + +static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28; + +UInt64 CMethodProps::Get_Lzma_MemUsage(bool addSlidingWindowSize) const +{ + const UInt64 dicSize = Get_Lzma_DicSize(); + const bool isBt = Get_Lzma_MatchFinder_IsBt(); + const UInt32 dict32 = (dicSize >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dicSize); + const UInt32 numThreads = Get_Lzma_NumThreads(); + UInt64 size = GetMemoryUsage_LZMA(dict32, isBt, numThreads); + + if (addSlidingWindowSize) + { + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); + UInt64 blockSize = (UInt64)dict32 + (1 << 16) + + (numThreads > 1 ? (1 << 20) : 0); + blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); + if (blockSize >= kBlockSizeMax) + blockSize = kBlockSizeMax; + size += blockSize; + } + return size; +} + + + + +HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) +{ + MethodName.Empty(); + int splitPos = s.Find(L':'); + { + UString temp = s; + if (splitPos >= 0) + temp.DeleteFrom((unsigned)splitPos); + if (!temp.IsAscii()) + return E_INVALIDARG; + MethodName.SetFromWStr_if_Ascii(temp); + } + if (splitPos < 0) + return S_OK; + PropsString = s.Ptr((unsigned)(splitPos + 1)); + return ParseParamsFromString(PropsString); +} + +HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) +{ + if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m")) + return ParseParamsFromPROPVARIANT(realName, value); + // -m{N}=method + if (value.vt != VT_BSTR) + return E_INVALIDARG; + UString s; + s = value.bstrVal; + return ParseMethodFromString(s); +} diff --git a/CPP/7zip/Common/MethodProps.h b/CPP/7zip/Common/MethodProps.h index d0b0e4585..a52f4bcd0 100644 --- a/CPP/7zip/Common/MethodProps.h +++ b/CPP/7zip/Common/MethodProps.h @@ -1,345 +1,345 @@ -// MethodProps.h - -#ifndef ZIP7_INC_7Z_METHOD_PROPS_H -#define ZIP7_INC_7Z_METHOD_PROPS_H - -#include "../../Common/MyString.h" -#include "../../Common/Defs.h" - -#include "../../Windows/Defs.h" - -#include "../../Windows/PropVariant.h" - -#include "../ICoder.h" - -// UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads); - -inline UInt64 Calc_From_Val_Percents_Less100(UInt64 val, UInt64 percents) -{ - if (percents == 0) - return 0; - if (val <= (UInt64)(Int64)-1 / percents) - return val * percents / 100; - return val / 100 * percents; -} - -UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents); - -bool StringToBool(const wchar_t *s, bool &res); -HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest); -unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number); - -/* -if (name.IsEmpty() && prop.vt == VT_EMPTY), it doesn't change (resValue) and returns S_OK. - So you must set (resValue) for default value before calling */ -HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); - -/* input: (numThreads = the_number_of_processors) */ -HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force); - -inline HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 numCPUs, UInt32 &numThreads) -{ - bool forced = false; - numThreads = numCPUs; - return ParseMtProp2(name, prop, numThreads, forced); -} - - -struct CProp -{ - PROPID Id; - bool IsOptional; - NWindows::NCOM::CPropVariant Value; - CProp(): IsOptional(false) {} -}; - -struct CProps -{ - CObjectVector Props; - - void Clear() { Props.Clear(); } - - bool AreThereNonOptionalProps() const - { - FOR_VECTOR (i, Props) - if (!Props[i].IsOptional) - return true; - return false; - } - - void AddProp32(PROPID propid, UInt32 val); - - void AddPropBool(PROPID propid, bool val); - - void AddProp_Ascii(PROPID propid, const char *s) - { - CProp &prop = Props.AddNew(); - prop.IsOptional = true; - prop.Id = propid; - prop.Value = s; - } - - HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const; - HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce, const UInt64 *affinity) const; -}; - -class CMethodProps: public CProps -{ - HRESULT SetParam(const UString &name, const UString &value); -public: - unsigned GetLevel() const; - int Get_NumThreads() const - { - const int i = FindProp(NCoderPropID::kNumThreads); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_UI4) - return (int)val.ulVal; - } - return -1; - } - - bool Get_DicSize(UInt64 &res) const - { - res = 0; - const int i = FindProp(NCoderPropID::kDictionarySize); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_UI4) - { - res = val.ulVal; - return true; - } - if (val.vt == VT_UI8) - { - res = val.uhVal.QuadPart; - return true; - } - } - return false; - } - - int FindProp(PROPID id) const; - - UInt32 Get_Lzma_Algo() const - { - int i = FindProp(NCoderPropID::kAlgorithm); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_UI4) - return val.ulVal; - } - return GetLevel() >= 5 ? 1 : 0; - } - - UInt64 Get_Lzma_DicSize() const - { - UInt64 v; - if (Get_DicSize(v)) - return v; - const unsigned level = GetLevel(); - const UInt32 dictSize = - ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : - ( level <= 6 ? ((UInt32)1 << (level + 19)) : - ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) - ))); - return dictSize; - } - - bool Get_Lzma_MatchFinder_IsBt() const - { - const int i = FindProp(NCoderPropID::kMatchFinder); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_BSTR) - return ((val.bstrVal[0] | 0x20) != 'h'); // check for "hc" - } - return GetLevel() >= 5; - } - - bool Get_Lzma_Eos() const - { - const int i = FindProp(NCoderPropID::kEndMarker); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_BOOL) - return VARIANT_BOOLToBool(val.boolVal); - } - return false; - } - - bool Are_Lzma_Model_Props_Defined() const - { - if (FindProp(NCoderPropID::kPosStateBits) >= 0) return true; - if (FindProp(NCoderPropID::kLitContextBits) >= 0) return true; - if (FindProp(NCoderPropID::kLitPosBits) >= 0) return true; - return false; - } - - UInt32 Get_Lzma_NumThreads() const - { - if (Get_Lzma_Algo() == 0) - return 1; - int numThreads = Get_NumThreads(); - if (numThreads >= 0) - return numThreads < 2 ? 1 : 2; - return 2; - } - - UInt64 Get_Lzma_MemUsage(bool addSlidingWindowSize) const; - - /* returns -1, if numThreads is unknown */ - int Get_Xz_NumThreads(UInt32 &lzmaThreads) const - { - lzmaThreads = 1; - int numThreads = Get_NumThreads(); - if (numThreads >= 0 && numThreads <= 1) - return 1; - if (Get_Lzma_Algo() != 0) - lzmaThreads = 2; - return numThreads; - } - - UInt64 GetProp_BlockSize(PROPID id) const - { - const int i = FindProp(id); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_UI4) { return val.ulVal; } - if (val.vt == VT_UI8) { return val.uhVal.QuadPart; } - } - return 0; - } - - UInt64 Get_Xz_BlockSize() const - { - { - UInt64 blockSize1 = GetProp_BlockSize(NCoderPropID::kBlockSize); - UInt64 blockSize2 = GetProp_BlockSize(NCoderPropID::kBlockSize2); - UInt64 minSize = MyMin(blockSize1, blockSize2); - if (minSize != 0) - return minSize; - UInt64 maxSize = MyMax(blockSize1, blockSize2); - if (maxSize != 0) - return maxSize; - } - const UInt32 kMinSize = (UInt32)1 << 20; - const UInt32 kMaxSize = (UInt32)1 << 28; - const UInt64 dictSize = Get_Lzma_DicSize(); - /* lzma2 code uses fake 4 GiB to calculate ChunkSize. So we do same */ - UInt64 blockSize = (UInt64)dictSize << 2; - if (blockSize < kMinSize) blockSize = kMinSize; - if (blockSize > kMaxSize) blockSize = kMaxSize; - if (blockSize < dictSize) blockSize = dictSize; - blockSize += (kMinSize - 1); - blockSize &= ~(UInt64)(kMinSize - 1); - return blockSize; - } - - - UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const - { - fixedNumber = false; - int numThreads = Get_NumThreads(); - if (numThreads >= 0) - { - fixedNumber = true; - if (numThreads < 1) return 1; - const unsigned kNumBZip2ThreadsMax = 64; - if ((unsigned)numThreads > kNumBZip2ThreadsMax) return kNumBZip2ThreadsMax; - return (unsigned)numThreads; - } - return 1; - } - - UInt32 Get_BZip2_BlockSize() const - { - const int i = FindProp(NCoderPropID::kDictionarySize); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_UI4) - { - UInt32 blockSize = val.ulVal; - const UInt32 kDicSizeMin = 100000; - const UInt32 kDicSizeMax = 900000; - if (blockSize < kDicSizeMin) blockSize = kDicSizeMin; - if (blockSize > kDicSizeMax) blockSize = kDicSizeMax; - return blockSize; - } - } - const unsigned level = GetLevel(); - return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1)); - } - - UInt64 Get_Ppmd_MemSize() const - { - const int i = FindProp(NCoderPropID::kUsedMemorySize); - if (i >= 0) - { - const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; - if (val.vt == VT_UI4) - return val.ulVal; - if (val.vt == VT_UI8) - return val.uhVal.QuadPart; - } - const unsigned level = GetLevel(); - const UInt32 mem = (UInt32)1 << (level + 19); - return mem; - } - - void AddProp_Level(UInt32 level) - { - AddProp32(NCoderPropID::kLevel, level); - } - - void AddProp_NumThreads(UInt32 numThreads) - { - AddProp32(NCoderPropID::kNumThreads, numThreads); - } - - void AddProp_EndMarker_if_NotFound(bool eos) - { - if (FindProp(NCoderPropID::kEndMarker) < 0) - AddPropBool(NCoderPropID::kEndMarker, eos); - } - - void AddProp_BlockSize2(UInt64 blockSize2) - { - if (FindProp(NCoderPropID::kBlockSize2) < 0) - { - CProp &prop = Props.AddNew(); - prop.IsOptional = true; - prop.Id = NCoderPropID::kBlockSize2; - prop.Value = blockSize2; - } - } - - HRESULT ParseParamsFromString(const UString &srcString); - HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); -}; - -class COneMethodInfo: public CMethodProps -{ -public: - AString MethodName; - UString PropsString; - - void Clear() - { - CMethodProps::Clear(); - MethodName.Empty(); - PropsString.Empty(); - } - bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); } - HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); - HRESULT ParseMethodFromString(const UString &s); -}; - -#endif +// MethodProps.h + +#ifndef ZIP7_INC_7Z_METHOD_PROPS_H +#define ZIP7_INC_7Z_METHOD_PROPS_H + +#include "../../Common/MyString.h" +#include "../../Common/Defs.h" + +#include "../../Windows/Defs.h" + +#include "../../Windows/PropVariant.h" + +#include "../ICoder.h" + +// UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads); + +inline UInt64 Calc_From_Val_Percents_Less100(UInt64 val, UInt64 percents) +{ + if (percents == 0) + return 0; + if (val <= (UInt64)(Int64)-1 / percents) + return val * percents / 100; + return val / 100 * percents; +} + +UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents); + +bool StringToBool(const wchar_t *s, bool &res); +HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest); +unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number); + +/* +if (name.IsEmpty() && prop.vt == VT_EMPTY), it doesn't change (resValue) and returns S_OK. + So you must set (resValue) for default value before calling */ +HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue); + +/* input: (numThreads = the_number_of_processors) */ +HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force); + +inline HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 numCPUs, UInt32 &numThreads) +{ + bool forced = false; + numThreads = numCPUs; + return ParseMtProp2(name, prop, numThreads, forced); +} + + +struct CProp +{ + PROPID Id; + bool IsOptional; + NWindows::NCOM::CPropVariant Value; + CProp(): IsOptional(false) {} +}; + +struct CProps +{ + CObjectVector Props; + + void Clear() { Props.Clear(); } + + bool AreThereNonOptionalProps() const + { + FOR_VECTOR (i, Props) + if (!Props[i].IsOptional) + return true; + return false; + } + + void AddProp32(PROPID propid, UInt32 val); + + void AddPropBool(PROPID propid, bool val); + + void AddProp_Ascii(PROPID propid, const char *s) + { + CProp &prop = Props.AddNew(); + prop.IsOptional = true; + prop.Id = propid; + prop.Value = s; + } + + HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const; + HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce, const UInt64 *affinity) const; +}; + +class CMethodProps: public CProps +{ + HRESULT SetParam(const UString &name, const UString &value); +public: + unsigned GetLevel() const; + int Get_NumThreads() const + { + const int i = FindProp(NCoderPropID::kNumThreads); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_UI4) + return (int)val.ulVal; + } + return -1; + } + + bool Get_DicSize(UInt64 &res) const + { + res = 0; + const int i = FindProp(NCoderPropID::kDictionarySize); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_UI4) + { + res = val.ulVal; + return true; + } + if (val.vt == VT_UI8) + { + res = val.uhVal.QuadPart; + return true; + } + } + return false; + } + + int FindProp(PROPID id) const; + + UInt32 Get_Lzma_Algo() const + { + const int i = FindProp(NCoderPropID::kAlgorithm); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_UI4) + return val.ulVal; + } + return GetLevel() >= 5 ? 1 : 0; + } + + UInt64 Get_Lzma_DicSize() const + { + UInt64 v; + if (Get_DicSize(v)) + return v; + const unsigned level = GetLevel(); + const UInt32 dictSize = level <= 4 ? + (UInt32)1 << (level * 2 + 16) : + level <= sizeof(size_t) / 2 + 4 ? + (UInt32)1 << (level + 20) : + (UInt32)1 << (sizeof(size_t) / 2 + 24); + return dictSize; + } + + bool Get_Lzma_MatchFinder_IsBt() const + { + const int i = FindProp(NCoderPropID::kMatchFinder); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_BSTR) + return ((val.bstrVal[0] | 0x20) != 'h'); // check for "hc" + } + return GetLevel() >= 5; + } + + bool Get_Lzma_Eos() const + { + const int i = FindProp(NCoderPropID::kEndMarker); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_BOOL) + return VARIANT_BOOLToBool(val.boolVal); + } + return false; + } + + bool Are_Lzma_Model_Props_Defined() const + { + if (FindProp(NCoderPropID::kPosStateBits) >= 0) return true; + if (FindProp(NCoderPropID::kLitContextBits) >= 0) return true; + if (FindProp(NCoderPropID::kLitPosBits) >= 0) return true; + return false; + } + + UInt32 Get_Lzma_NumThreads() const + { + if (Get_Lzma_Algo() == 0) + return 1; + int numThreads = Get_NumThreads(); + if (numThreads >= 0) + return numThreads < 2 ? 1 : 2; + return 2; + } + + UInt64 Get_Lzma_MemUsage(bool addSlidingWindowSize) const; + + /* returns -1, if numThreads is unknown */ + int Get_Xz_NumThreads(UInt32 &lzmaThreads) const + { + lzmaThreads = 1; + int numThreads = Get_NumThreads(); + if (numThreads >= 0 && numThreads <= 1) + return 1; + if (Get_Lzma_Algo() != 0) + lzmaThreads = 2; + return numThreads; + } + + UInt64 GetProp_BlockSize(PROPID id) const + { + const int i = FindProp(id); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_UI4) { return val.ulVal; } + if (val.vt == VT_UI8) { return val.uhVal.QuadPart; } + } + return 0; + } + + UInt64 Get_Xz_BlockSize() const + { + { + UInt64 blockSize1 = GetProp_BlockSize(NCoderPropID::kBlockSize); + UInt64 blockSize2 = GetProp_BlockSize(NCoderPropID::kBlockSize2); + UInt64 minSize = MyMin(blockSize1, blockSize2); + if (minSize != 0) + return minSize; + UInt64 maxSize = MyMax(blockSize1, blockSize2); + if (maxSize != 0) + return maxSize; + } + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + const UInt64 dictSize = Get_Lzma_DicSize(); + /* lzma2 code uses fake 4 GiB to calculate ChunkSize. So we do same */ + UInt64 blockSize = (UInt64)dictSize << 2; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + blockSize += (kMinSize - 1); + blockSize &= ~(UInt64)(kMinSize - 1); + return blockSize; + } + + + UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const + { + fixedNumber = false; + int numThreads = Get_NumThreads(); + if (numThreads >= 0) + { + fixedNumber = true; + if (numThreads < 1) return 1; + const unsigned kNumBZip2ThreadsMax = 64; + if ((unsigned)numThreads > kNumBZip2ThreadsMax) return kNumBZip2ThreadsMax; + return (unsigned)numThreads; + } + return 1; + } + + UInt32 Get_BZip2_BlockSize() const + { + const int i = FindProp(NCoderPropID::kDictionarySize); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_UI4) + { + UInt32 blockSize = val.ulVal; + const UInt32 kDicSizeMin = 100000; + const UInt32 kDicSizeMax = 900000; + if (blockSize < kDicSizeMin) blockSize = kDicSizeMin; + if (blockSize > kDicSizeMax) blockSize = kDicSizeMax; + return blockSize; + } + } + const unsigned level = GetLevel(); + return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1)); + } + + UInt64 Get_Ppmd_MemSize() const + { + const int i = FindProp(NCoderPropID::kUsedMemorySize); + if (i >= 0) + { + const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value; + if (val.vt == VT_UI4) + return val.ulVal; + if (val.vt == VT_UI8) + return val.uhVal.QuadPart; + } + const unsigned level = GetLevel(); + const UInt32 mem = (UInt32)1 << (level + 19); + return mem; + } + + void AddProp_Level(UInt32 level) + { + AddProp32(NCoderPropID::kLevel, level); + } + + void AddProp_NumThreads(UInt32 numThreads) + { + AddProp32(NCoderPropID::kNumThreads, numThreads); + } + + void AddProp_EndMarker_if_NotFound(bool eos) + { + if (FindProp(NCoderPropID::kEndMarker) < 0) + AddPropBool(NCoderPropID::kEndMarker, eos); + } + + void AddProp_BlockSize2(UInt64 blockSize2) + { + if (FindProp(NCoderPropID::kBlockSize2) < 0) + { + CProp &prop = Props.AddNew(); + prop.IsOptional = true; + prop.Id = NCoderPropID::kBlockSize2; + prop.Value = blockSize2; + } + } + + HRESULT ParseParamsFromString(const UString &srcString); + HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); +}; + +class COneMethodInfo: public CMethodProps +{ +public: + AString MethodName; + UString PropsString; + + void Clear() + { + CMethodProps::Clear(); + MethodName.Empty(); + PropsString.Empty(); + } + bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); } + HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value); + HRESULT ParseMethodFromString(const UString &s); +}; + +#endif diff --git a/CPP/7zip/Common/MultiOutStream.cpp b/CPP/7zip/Common/MultiOutStream.cpp index 357b9a44d..19543119f 100644 --- a/CPP/7zip/Common/MultiOutStream.cpp +++ b/CPP/7zip/Common/MultiOutStream.cpp @@ -1,855 +1,855 @@ -// MultiOutStream.cpp - -#include "StdAfx.h" - -// #define DEBUG_VOLUMES - -#ifdef DEBUG_VOLUMES -#include - #define PRF(x) x; -#else - #define PRF(x) -#endif - -#include "../../Common/ComTry.h" - -#include "../../Windows/FileDir.h" -#include "../../Windows/FileFind.h" -#include "../../Windows/System.h" - -#include "MultiOutStream.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static const unsigned k_NumVols_MAX = k_VectorSizeMax - 1; - // 2; // for debug - -/* -#define UPDATE_HRES(hres, x) \ - { const HRESULT res2 = (x); if (hres == SZ_OK) hres = res2; } -*/ - -HRESULT CMultiOutStream::Destruct() -{ - COM_TRY_BEGIN - HRESULT hres = S_OK; - HRESULT hres3 = S_OK; - - while (!Streams.IsEmpty()) - { - try - { - HRESULT hres2; - if (NeedDelete) - { - /* we could call OptReOpen_and_SetSize() to test that we try to delete correct file, - but we cannot guarantee that (RealSize) will be correct after Write() or another failures. - And we still want to delete files even for such cases. - So we don't check for OptReOpen_and_SetSize() here: */ - // if (OptReOpen_and_SetSize(Streams.Size() - 1, 0) == S_OK) - hres2 = CloseStream_and_DeleteFile(Streams.Size() - 1); - } - else - { - hres2 = CloseStream(Streams.Size() - 1); - } - if (hres == S_OK) - hres = hres2; - } - catch(...) - { - hres3 = E_OUTOFMEMORY; - } - - { - /* Stream was released in CloseStream_*() above already, and it was removed from linked list - it's some unexpected case, if Stream is still attached here. - So the following code is optional: */ - CVolStream &s = Streams.Back(); - if (s.Stream) - { - if (hres3 == S_OK) - hres3 = E_FAIL; - s.Stream.Detach(); - /* it will be not failure, even if we call RemoveFromLinkedList() - twice for same CVolStream in this Destruct() function */ - RemoveFromLinkedList(Streams.Size() - 1); - } - } - Streams.DeleteBack(); - // Delete_LastStream_Records(); - } - - if (hres == S_OK) - hres = hres3; - if (hres == S_OK && NumListItems != 0) - hres = E_FAIL; - return hres; - COM_TRY_END -} - - -CMultiOutStream::~CMultiOutStream() -{ - // we try to avoid exception in destructors - Destruct(); -} - - -void CMultiOutStream::Init(const CRecordVector &sizes) -{ - Streams.Clear(); - InitLinkedList(); - Sizes = sizes; - NeedDelete = true; - MTime_Defined = false; - FinalVol_WasReopen = false; - NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); - - _streamIndex = 0; - _offsetPos = 0; - _absPos = 0; - _length = 0; - _absLimit = (UInt64)(Int64)-1; - - _restrict_Begin = 0; - _restrict_End = (UInt64)(Int64)-1; - _restrict_Global = 0; - - UInt64 sum = 0; - unsigned i = 0; - for (i = 0; i < Sizes.Size(); i++) - { - if (i >= k_NumVols_MAX) - { - _absLimit = sum; - break; - } - const UInt64 size = Sizes[i]; - const UInt64 next = sum + size; - if (next < sum) - break; - sum = next; - } - - // if (Sizes.IsEmpty()) throw "no volume sizes"; - const UInt64 size = Sizes.Back(); - if (size == 0) - throw "zero size last volume"; - - if (i == Sizes.Size()) - if ((_absLimit - sum) / size >= (k_NumVols_MAX - i)) - _absLimit = sum + (k_NumVols_MAX - i) * size; -} - - -/* IsRestricted(): - we must call only if volume is full (s.RealSize==VolSize) or finished. - the function doesn't use VolSize and it uses s.RealSize instead. - it returns true : if stream is restricted, and we can't close that stream - it returns false : if there is no restriction, and we can close that stream - Note: (RealSize == 0) (empty volume) on restriction bounds are supposed as non-restricted -*/ -bool CMultiOutStream::IsRestricted(const CVolStream &s) const -{ - if (s.Start < _restrict_Global) - return true; - if (_restrict_Begin == _restrict_End) - return false; - if (_restrict_Begin <= s.Start) - return _restrict_End > s.Start; - return _restrict_Begin < s.Start + s.RealSize; -} - -/* -// this function check also _length and volSize -bool CMultiOutStream::IsRestricted_for_Close(unsigned index) const -{ - const CVolStream &s = Streams[index]; - if (_length <= s.Start) // we don't close streams after the end, because we still can write them later - return true; - // (_length > s.Start) - const UInt64 volSize = GetVolSize_for_Stream(index); - if (volSize == 0) - return IsRestricted_Empty(s); - if (_length - s.Start < volSize) - return true; - return IsRestricted(s); -} -*/ - -FString CMultiOutStream::GetFilePath(unsigned index) -{ - FString name; - name.Add_UInt32((UInt32)(index + 1)); - while (name.Len() < 3) - name.InsertAtFront(FTEXT('0')); - name.Insert(0, Prefix); - return name; -} - - -// we close stream, but we still keep item in Streams[] vector -HRESULT CMultiOutStream::CloseStream(unsigned index) -{ - CVolStream &s = Streams[index]; - if (s.Stream) - { - RINOK(s.StreamSpec->Close()) - // the following two commands must be called together: - s.Stream.Release(); - RemoveFromLinkedList(index); - } - return S_OK; -} - - -// we close stream and delete file, but we still keep item in Streams[] vector -HRESULT CMultiOutStream::CloseStream_and_DeleteFile(unsigned index) -{ - PRF(printf("\n====== %u, CloseStream_AndDelete \n", index)) - RINOK(CloseStream(index)) - FString path = GetFilePath(index); - path += Streams[index].Postfix; - // we can checki that file exist - // if (NFind::DoesFileExist_Raw(path)) - if (!DeleteFileAlways(path)) - return GetLastError_noZero_HRESULT(); - return S_OK; -} - - -HRESULT CMultiOutStream::CloseStream_and_FinalRename(unsigned index) -{ - PRF(printf("\n====== %u, CloseStream_and_FinalRename \n", index)) - CVolStream &s = Streams[index]; - // HRESULT res = S_OK; - bool mtime_WasSet = false; - if (MTime_Defined && s.Stream) - { - if (s.StreamSpec->SetMTime(&MTime)) - mtime_WasSet = true; - // else res = GetLastError_noZero_HRESULT(); - } - - RINOK(CloseStream(index)) - if (s.Postfix.IsEmpty()) // if Postfix is empty, the path is already final - return S_OK; - const FString path = GetFilePath(index); - FString tempPath = path; - tempPath += s.Postfix; - - if (MTime_Defined && !mtime_WasSet) - { - if (!SetDirTime(tempPath, NULL, NULL, &MTime)) - { - // res = GetLastError_noZero_HRESULT(); - } - } - if (!MyMoveFile(tempPath, path)) - return GetLastError_noZero_HRESULT(); - /* we clear CVolStream::Postfix. So we will not use Temp path - anymore for this stream, and we will work only with final path */ - s.Postfix.Empty(); - // we can ignore set_mtime error or we can return it - return S_OK; - // return res; -} - - -HRESULT CMultiOutStream::PrepareToOpenNew() -{ - PRF(printf("PrepareToOpenNew NumListItems =%u, NumOpenFiles_AllowedMax = %u \n", NumListItems, NumOpenFiles_AllowedMax)) - - if (NumListItems < NumOpenFiles_AllowedMax) - return S_OK; - /* when we create zip archive: in most cases we need only starting - data of restricted region for rewriting zip's local header. - So here we close latest created volume (from Head), and we try to - keep oldest volumes that will be used for header rewriting later. */ - const int index = Head; - if (index == -1) - return E_FAIL; - PRF(printf("\n== %u, PrepareToOpenNew::CloseStream, NumListItems =%u \n", index, NumListItems)) - /* we don't expect non-restricted stream here in normal cases (if _restrict_Global was not changed). - if there was non-restricted stream, it should be closed before */ - // if (!IsRestricted_for_Close(index)) return CloseStream_and_FinalRename(index); - return CloseStream((unsigned)index); -} - - -HRESULT CMultiOutStream::CreateNewStream(UInt64 newSize) -{ - PRF(printf("\n== %u, CreateNewStream, size =%u \n", Streams.Size(), (unsigned)newSize)) - - if (Streams.Size() >= k_NumVols_MAX) - return E_INVALIDARG; // E_OUTOFMEMORY - - RINOK(PrepareToOpenNew()) - CVolStream s; - s.StreamSpec = new COutFileStream; - s.Stream = s.StreamSpec; - const FString path = GetFilePath(Streams.Size()); - - if (NFind::DoesFileExist_Raw(path)) - return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); - if (!CreateTempFile2(path, false, s.Postfix, &s.StreamSpec->File)) - return GetLastError_noZero_HRESULT(); - - s.Start = GetGlobalOffset_for_NewStream(); - s.Pos = 0; - s.RealSize = 0; - - const unsigned index = Streams.Add(s); - InsertToLinkedList(index); - - if (newSize != 0) - return s.SetSize2(newSize); - return S_OK; -} - - -HRESULT CMultiOutStream::CreateStreams_If_Required(unsigned streamIndex) -{ - // UInt64 lastStreamSize = 0; - for (;;) - { - const unsigned numStreamsBefore = Streams.Size(); - if (streamIndex < numStreamsBefore) - return S_OK; - UInt64 newSize; - if (streamIndex == numStreamsBefore) - { - // it's final volume that will be used for real writing. - /* SetSize(_offsetPos) is not required, - because the file Size will be set later by calling Seek() with Write() */ - newSize = 0; // lastStreamSize; - } - else - { - // it's intermediate volume. So we need full volume size - newSize = GetVolSize_for_Stream(numStreamsBefore); - } - - RINOK(CreateNewStream(newSize)) - - // optional check - if (numStreamsBefore + 1 != Streams.Size()) return E_FAIL; - - if (streamIndex != numStreamsBefore) - { - // it's intermediate volume. So we can close it, if it's non-restricted - bool isRestricted; - { - const CVolStream &s = Streams[numStreamsBefore]; - if (newSize == 0) - isRestricted = IsRestricted_Empty(s); - else - isRestricted = IsRestricted(s); - } - if (!isRestricted) - { - RINOK(CloseStream_and_FinalRename(numStreamsBefore)) - } - } - } -} - - -HRESULT CMultiOutStream::ReOpenStream(unsigned streamIndex) -{ - PRF(printf("\n====== %u, ReOpenStream \n", streamIndex)) - RINOK(PrepareToOpenNew()) - CVolStream &s = Streams[streamIndex]; - - FString path = GetFilePath(streamIndex); - path += s.Postfix; - - s.StreamSpec = new COutFileStream; - s.Stream = s.StreamSpec; - s.Pos = 0; - - HRESULT hres; - if (s.StreamSpec->Open_EXISTING(path)) - { - if (s.Postfix.IsEmpty()) - { - /* it's unexpected case that we open finished volume. - It can mean that the code for restriction is incorrect */ - FinalVol_WasReopen = true; - } - UInt64 realSize = 0; - hres = s.StreamSpec->GetSize(&realSize); - if (hres == S_OK) - { - if (realSize == s.RealSize) - { - PRF(printf("\n ReOpenStream OK realSize = %u\n", (unsigned)realSize)) - InsertToLinkedList(streamIndex); - return S_OK; - } - // file size was changed between Close() and ReOpen() - // we must release Stream to be consistent with linked list - hres = E_FAIL; - } - } - else - hres = GetLastError_noZero_HRESULT(); - s.Stream.Release(); - s.StreamSpec = NULL; - return hres; -} - - -/* Sets size of stream, if new size is not equal to old size (RealSize). - If stream was closed and size change is required, it reopens the stream. */ - -HRESULT CMultiOutStream::OptReOpen_and_SetSize(unsigned index, UInt64 size) -{ - CVolStream &s = Streams[index]; - if (size == s.RealSize) - return S_OK; - if (!s.Stream) - { - RINOK(ReOpenStream(index)) - } - PRF(printf("\n== %u, OptReOpen_and_SetSize, size =%u RealSize = %u\n", index, (unsigned)size, (unsigned)s.RealSize)) - // comment it to debug tail after data - return s.SetSize2(size); -} - - -/* -call Normalize_finalMode(false), if _length was changed. - for all streams starting after _length: - - it sets zero size - - it still keeps file open - Note: after _length reducing with CMultiOutStream::SetSize() we can - have very big number of empty streams at the end of Streams[] list. - And Normalize_finalMode() will runs all these empty streams of Streams[] vector. - So it can be ineffective, if we call Normalize_finalMode() many - times after big reducing of (_length). - -call Normalize_finalMode(true) to set final presentations of all streams - for all streams starting after _length: - - it sets zero size - - it removes file - - it removes CVolStream object from Streams[] vector - -Note: we don't remove zero sized first volume, if (_length == 0) -*/ - -HRESULT CMultiOutStream::Normalize_finalMode(bool finalMode) -{ - PRF(printf("\n== Normalize_finalMode: _length =%d \n", (unsigned)_length)) - - unsigned i = Streams.Size(); - - UInt64 offset = 0; - - /* At first we normalize (reduce or increase) the sizes of all existing - streams in Streams[] that can be affected by changed _length. - And we remove tailing zero-size streams, if (finalMode == true) */ - while (i != 0) - { - offset = Streams[--i].Start; // it's last item in Streams[] - // we don't want to remove first volume - if (offset < _length || i == 0) - { - const UInt64 volSize = GetVolSize_for_Stream(i); - UInt64 size = _length - offset; // (size != 0) here - if (size > volSize) - size = volSize; - RINOK(OptReOpen_and_SetSize(i, size)) - if (_length - offset <= volSize) - return S_OK; - // _length - offset > volSize - offset += volSize; - // _length > offset - break; - // UPDATE_HRES(res, OptReOpen_and_SetSize(i, size)); - } - - /* we Set Size of stream to zero even for (finalMode==true), although - that stream will be deleted in next commands */ - // UPDATE_HRES(res, OptReOpen_and_SetSize(i, 0)); - RINOK(OptReOpen_and_SetSize(i, 0)) - if (finalMode) - { - RINOK(CloseStream_and_DeleteFile(i)) - /* CVolStream::Stream was released above already, and it was - removed from linked list. So we don't need to update linked list - structure, when we delete last item in Streams[] */ - Streams.DeleteBack(); - // Delete_LastStream_Records(); - } - } - - /* now we create new zero-filled streams to cover all data up to _length */ - - if (_length == 0) - return S_OK; - - // (offset) is start offset of next stream after existing Streams[] - - for (;;) - { - // _length > offset - const UInt64 volSize = GetVolSize_for_Stream(Streams.Size()); - UInt64 size = _length - offset; // (size != 0) here - if (size > volSize) - size = volSize; - RINOK(CreateNewStream(size)) - if (_length - offset <= volSize) - return S_OK; - // _length - offset > volSize) - offset += volSize; - // _length > offset - } -} - - -HRESULT CMultiOutStream::FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes) -{ - // at first we remove unused zero-sized streams after _length - HRESULT res = Normalize_finalMode(true); - numTotalVolumesRes = Streams.Size(); - FOR_VECTOR (i, Streams) - { - const HRESULT res2 = CloseStream_and_FinalRename(i); - if (res == S_OK) - res = res2; - } - if (NumListItems != 0 && res == S_OK) - res = E_FAIL; - return res; -} - - -bool CMultiOutStream::SetMTime_Final(const CFiTime &mTime) -{ - // we will set mtime only if new value differs from previous - if (!FinalVol_WasReopen && MTime_Defined && Compare_FiTime(&MTime, &mTime) == 0) - return true; - bool res = true; - FOR_VECTOR (i, Streams) - { - CVolStream &s = Streams[i]; - if (s.Stream) - { - if (!s.StreamSpec->SetMTime(&mTime)) - res = false; - } - else - { - if (!SetDirTime(GetFilePath(i), NULL, NULL, &mTime)) - res = false; - } - } - return res; -} - - -Z7_COM7F_IMF(CMultiOutStream::SetSize(UInt64 newSize)) -{ - COM_TRY_BEGIN - if ((Int64)newSize < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - if (newSize > _absLimit) - { - /* big seek value was sent to SetSize() or to Seek()+Write(). - It can mean one of two situations: - 1) some incorrect code called it with big seek value. - 2) volume size was small, and we have too big number of volumes - */ - /* in Windows SetEndOfFile() can return: - ERROR_NEGATIVE_SEEK: for >= (1 << 63) - ERROR_INVALID_PARAMETER: for > (16 TiB - 64 KiB) - ERROR_DISK_FULL: for <= (16 TiB - 64 KiB) - */ - // return E_FAIL; - // return E_OUTOFMEMORY; - return E_INVALIDARG; - } - - if (newSize > _length) - { - // we don't expect such case. So we just define global restriction */ - _restrict_Global = newSize; - } - else if (newSize < _restrict_Global) - _restrict_Global = newSize; - - PRF(printf("\n== CMultiOutStream::SetSize, size =%u \n", (unsigned)newSize)) - - _length = newSize; - return Normalize_finalMode(false); - - COM_TRY_END -} - - -Z7_COM7F_IMF(CMultiOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - COM_TRY_BEGIN - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - - PRF(printf("\n -- CMultiOutStream::Write() : _absPos = %6u, size =%6u \n", - (unsigned)_absPos, (unsigned)size)) - - if (_absPos > _length) - { - // it create data only up to _absPos. - // but we still can need additional new streams, if _absPos at range of volume - RINOK(SetSize(_absPos)) - } - - while (size != 0) - { - UInt64 volSize; - { - if (_streamIndex < Sizes.Size() - 1) - { - volSize = Sizes[_streamIndex]; - if (_offsetPos >= volSize) - { - _offsetPos -= volSize; - _streamIndex++; - continue; - } - } - else - { - volSize = Sizes[Sizes.Size() - 1]; - if (_offsetPos >= volSize) - { - const UInt64 v = _offsetPos / volSize; - if (v >= ((UInt32)(Int32)-1) - _streamIndex) - return E_INVALIDARG; - // throw 202208; - _streamIndex += (unsigned)v; - _offsetPos -= (unsigned)v * volSize; - } - if (_streamIndex >= k_NumVols_MAX) - return E_INVALIDARG; - } - } - - // (_offsetPos < volSize) here - - /* we can need to create one or more streams here, - vol_size for some streams is allowed to be 0. - Also we close some new created streams, if they are non-restricted */ - // file Size will be set later by calling Seek() with Write() - - /* the case (_absPos > _length) was processed above with SetSize(_absPos), - so here it's expected. that we can create optional zero-size streams and then _streamIndex */ - RINOK(CreateStreams_If_Required(_streamIndex)) - - CVolStream &s = Streams[_streamIndex]; - - PRF(printf("\n%d, == Write : Pos = %u, RealSize = %u size =%u \n", - _streamIndex, (unsigned)s.Pos, (unsigned)s.RealSize, size)) - - if (!s.Stream) - { - RINOK(ReOpenStream(_streamIndex)) - } - if (_offsetPos != s.Pos) - { - RINOK(s.Stream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL)) - s.Pos = _offsetPos; - } - - UInt32 curSize = size; - { - const UInt64 rem = volSize - _offsetPos; - if (curSize > rem) - curSize = (UInt32)rem; - } - // curSize != 0 - UInt32 realProcessed = 0; - - HRESULT hres = s.Stream->Write(data, curSize, &realProcessed); - - data = (const void *)((const Byte *)data + realProcessed); - size -= realProcessed; - s.Pos += realProcessed; - _offsetPos += realProcessed; - _absPos += realProcessed; - if (_length < _absPos) - _length = _absPos; - if (s.RealSize < _offsetPos) - s.RealSize = _offsetPos; - if (processedSize) - *processedSize += realProcessed; - - if (s.Pos == volSize) - { - bool isRestricted; - if (volSize == 0) - isRestricted = IsRestricted_Empty(s); - else - isRestricted = IsRestricted(s); - if (!isRestricted) - { - const HRESULT res2 = CloseStream_and_FinalRename(_streamIndex); - if (hres == S_OK) - hres = res2; - } - _streamIndex++; - _offsetPos = 0; - } - - RINOK(hres) - if (realProcessed == 0 && curSize != 0) - return E_FAIL; - // break; - } - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CMultiOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - PRF(printf("\n-- CMultiOutStream::Seek seekOrigin=%u Seek =%u\n", seekOrigin, (unsigned)offset)) - - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _absPos; break; - case STREAM_SEEK_END: offset += _length; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - if ((UInt64)offset != _absPos) - { - _absPos = (UInt64)offset; - _offsetPos = (UInt64)offset; - _streamIndex = 0; - } - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - - -// result value will be saturated to (UInt32)(Int32)-1 - -unsigned CMultiOutStream::GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const -{ - const unsigned last = Sizes.Size() - 1; - for (unsigned i = 0; i < last; i++) - { - const UInt64 size = Sizes[i]; - if (offset < size) - { - relOffset = offset; - return i; - } - offset -= size; - } - const UInt64 size = Sizes[last]; - const UInt64 v = offset / size; - if (v >= ((UInt32)(Int32)-1) - last) - return (unsigned)(int)-1; // saturation - relOffset = offset - (unsigned)v * size; - return last + (unsigned)(v); -} - - -Z7_COM7F_IMF(CMultiOutStream::SetRestriction(UInt64 begin, UInt64 end)) -{ - COM_TRY_BEGIN - - // begin = end = 0; // for debug - - PRF(printf("\n==================== CMultiOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end)) - if (begin > end) - { - // these value are FAILED values. - return E_FAIL; - // return E_INVALIDARG; - /* - // or we can ignore error with 3 ways: no change, non-restricted, saturation: - end = begin; // non-restricted - end = (UInt64)(Int64)-1; // saturation: - return S_OK; - */ - } - UInt64 b = _restrict_Begin; - UInt64 e = _restrict_End; - _restrict_Begin = begin; - _restrict_End = end; - - if (b == e) // if there were no restriction before - return S_OK; // no work to derestrict now. - - /* [b, e) is previous restricted region. So all volumes that - intersect that [b, e) region are candidats for derestriction */ - - if (begin != end) // if there is new non-empty restricted region - { - /* Now we will try to reduce or change (b) and (e) bounds - to reduce main loop that checks volumes for derestriction. - We still use one big derestriction region in main loop, although - in some cases we could have two smaller derestriction regions. - Also usually restriction region cannot move back from previous start position, - so (b <= begin) is expected here for normal cases */ - if (b == begin) // if same low bounds - b = end; // we need to derestrict only after the end of new restricted region - if (e == end) // if same high bounds - e = begin; // we need to derestrict only before the begin of new restricted region - } - - if (b > e) // || b == (UInt64)(Int64)-1 - return S_OK; - - /* Here we close finished volumes that are not restricted anymore. - We close (low number) volumes at first. */ - - UInt64 offset; - unsigned index = GetStreamIndex_for_Offset(b, offset); - - for (; index < Streams.Size(); index++) - { - { - const CVolStream &s = Streams[index]; - if (_length <= s.Start) - break; // we don't close streams after _length - // (_length > s.Start) - const UInt64 volSize = GetVolSize_for_Stream(index); - if (volSize == 0) - { - if (e < s.Start) - break; - // we don't close empty stream, if next byte [s.Start, s.Start] is restricted - if (IsRestricted_Empty(s)) - continue; - } - else - { - if (e <= s.Start) - break; - // we don't close non full streams - if (_length - s.Start < volSize) - break; - // (volSize == s.RealSize) is expected here. So no need to check it - // if (volSize != s.RealSize) break; - if (IsRestricted(s)) - continue; - } - } - RINOK(CloseStream_and_FinalRename(index)) - } - - return S_OK; - COM_TRY_END -} +// MultiOutStream.cpp + +#include "StdAfx.h" + +// #define DEBUG_VOLUMES + +#ifdef DEBUG_VOLUMES +#include + #define PRF(x) x; +#else + #define PRF(x) +#endif + +#include "../../Common/ComTry.h" + +#include "../../Windows/FileDir.h" +#include "../../Windows/FileFind.h" +#include "../../Windows/System.h" + +#include "MultiOutStream.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static const unsigned k_NumVols_MAX = k_VectorSizeMax - 1; + // 2; // for debug + +/* +#define UPDATE_HRES(hres, x) \ + { const HRESULT res2 = (x); if (hres == SZ_OK) hres = res2; } +*/ + +HRESULT CMultiOutStream::Destruct() +{ + COM_TRY_BEGIN + HRESULT hres = S_OK; + HRESULT hres3 = S_OK; + + while (!Streams.IsEmpty()) + { + try + { + HRESULT hres2; + if (NeedDelete) + { + /* we could call OptReOpen_and_SetSize() to test that we try to delete correct file, + but we cannot guarantee that (RealSize) will be correct after Write() or another failures. + And we still want to delete files even for such cases. + So we don't check for OptReOpen_and_SetSize() here: */ + // if (OptReOpen_and_SetSize(Streams.Size() - 1, 0) == S_OK) + hres2 = CloseStream_and_DeleteFile(Streams.Size() - 1); + } + else + { + hres2 = CloseStream(Streams.Size() - 1); + } + if (hres == S_OK) + hres = hres2; + } + catch(...) + { + hres3 = E_OUTOFMEMORY; + } + + { + /* Stream was released in CloseStream_*() above already, and it was removed from linked list + it's some unexpected case, if Stream is still attached here. + So the following code is optional: */ + CVolStream &s = Streams.Back(); + if (s.Stream) + { + if (hres3 == S_OK) + hres3 = E_FAIL; + s.Stream.Detach(); + /* it will be not failure, even if we call RemoveFromLinkedList() + twice for same CVolStream in this Destruct() function */ + RemoveFromLinkedList(Streams.Size() - 1); + } + } + Streams.DeleteBack(); + // Delete_LastStream_Records(); + } + + if (hres == S_OK) + hres = hres3; + if (hres == S_OK && NumListItems != 0) + hres = E_FAIL; + return hres; + COM_TRY_END +} + + +CMultiOutStream::~CMultiOutStream() +{ + // we try to avoid exception in destructors + Destruct(); +} + + +void CMultiOutStream::Init(const CRecordVector &sizes) +{ + Streams.Clear(); + InitLinkedList(); + Sizes = sizes; + NeedDelete = true; + MTime_Defined = false; + FinalVol_WasReopen = false; + NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); + + _streamIndex = 0; + _offsetPos = 0; + _absPos = 0; + _length = 0; + _absLimit = (UInt64)(Int64)-1; + + _restrict_Begin = 0; + _restrict_End = (UInt64)(Int64)-1; + _restrict_Global = 0; + + UInt64 sum = 0; + unsigned i = 0; + for (i = 0; i < Sizes.Size(); i++) + { + if (i >= k_NumVols_MAX) + { + _absLimit = sum; + break; + } + const UInt64 size = Sizes[i]; + const UInt64 next = sum + size; + if (next < sum) + break; + sum = next; + } + + // if (Sizes.IsEmpty()) throw "no volume sizes"; + const UInt64 size = Sizes.Back(); + if (size == 0) + throw "zero size last volume"; + + if (i == Sizes.Size()) + if ((_absLimit - sum) / size >= (k_NumVols_MAX - i)) + _absLimit = sum + (k_NumVols_MAX - i) * size; +} + + +/* IsRestricted(): + we must call only if volume is full (s.RealSize==VolSize) or finished. + the function doesn't use VolSize and it uses s.RealSize instead. + it returns true : if stream is restricted, and we can't close that stream + it returns false : if there is no restriction, and we can close that stream + Note: (RealSize == 0) (empty volume) on restriction bounds are supposed as non-restricted +*/ +bool CMultiOutStream::IsRestricted(const CVolStream &s) const +{ + if (s.Start < _restrict_Global) + return true; + if (_restrict_Begin == _restrict_End) + return false; + if (_restrict_Begin <= s.Start) + return _restrict_End > s.Start; + return _restrict_Begin < s.Start + s.RealSize; +} + +/* +// this function check also _length and volSize +bool CMultiOutStream::IsRestricted_for_Close(unsigned index) const +{ + const CVolStream &s = Streams[index]; + if (_length <= s.Start) // we don't close streams after the end, because we still can write them later + return true; + // (_length > s.Start) + const UInt64 volSize = GetVolSize_for_Stream(index); + if (volSize == 0) + return IsRestricted_Empty(s); + if (_length - s.Start < volSize) + return true; + return IsRestricted(s); +} +*/ + +FString CMultiOutStream::GetFilePath(unsigned index) +{ + FString name; + name.Add_UInt32((UInt32)(index + 1)); + while (name.Len() < 3) + name.InsertAtFront(FTEXT('0')); + name.Insert(0, Prefix); + return name; +} + + +// we close stream, but we still keep item in Streams[] vector +HRESULT CMultiOutStream::CloseStream(unsigned index) +{ + CVolStream &s = Streams[index]; + if (s.Stream) + { + RINOK(s.StreamSpec->Close()) + // the following two commands must be called together: + s.Stream.Release(); + RemoveFromLinkedList(index); + } + return S_OK; +} + + +// we close stream and delete file, but we still keep item in Streams[] vector +HRESULT CMultiOutStream::CloseStream_and_DeleteFile(unsigned index) +{ + PRF(printf("\n====== %u, CloseStream_AndDelete \n", index)) + RINOK(CloseStream(index)) + FString path = GetFilePath(index); + path += Streams[index].Postfix; + // we can checki that file exist + // if (NFind::DoesFileExist_Raw(path)) + if (!DeleteFileAlways(path)) + return GetLastError_noZero_HRESULT(); + return S_OK; +} + + +HRESULT CMultiOutStream::CloseStream_and_FinalRename(unsigned index) +{ + PRF(printf("\n====== %u, CloseStream_and_FinalRename \n", index)) + CVolStream &s = Streams[index]; + // HRESULT res = S_OK; + bool mtime_WasSet = false; + if (MTime_Defined && s.Stream) + { + if (s.StreamSpec->SetMTime(&MTime)) + mtime_WasSet = true; + // else res = GetLastError_noZero_HRESULT(); + } + + RINOK(CloseStream(index)) + if (s.Postfix.IsEmpty()) // if Postfix is empty, the path is already final + return S_OK; + const FString path = GetFilePath(index); + FString tempPath = path; + tempPath += s.Postfix; + + if (MTime_Defined && !mtime_WasSet) + { + if (!SetDirTime(tempPath, NULL, NULL, &MTime)) + { + // res = GetLastError_noZero_HRESULT(); + } + } + if (!MyMoveFile(tempPath, path)) + return GetLastError_noZero_HRESULT(); + /* we clear CVolStream::Postfix. So we will not use Temp path + anymore for this stream, and we will work only with final path */ + s.Postfix.Empty(); + // we can ignore set_mtime error or we can return it + return S_OK; + // return res; +} + + +HRESULT CMultiOutStream::PrepareToOpenNew() +{ + PRF(printf("PrepareToOpenNew NumListItems =%u, NumOpenFiles_AllowedMax = %u \n", NumListItems, NumOpenFiles_AllowedMax)) + + if (NumListItems < NumOpenFiles_AllowedMax) + return S_OK; + /* when we create zip archive: in most cases we need only starting + data of restricted region for rewriting zip's local header. + So here we close latest created volume (from Head), and we try to + keep oldest volumes that will be used for header rewriting later. */ + const int index = Head; + if (index == -1) + return E_FAIL; + PRF(printf("\n== %u, PrepareToOpenNew::CloseStream, NumListItems =%u \n", index, NumListItems)) + /* we don't expect non-restricted stream here in normal cases (if _restrict_Global was not changed). + if there was non-restricted stream, it should be closed before */ + // if (!IsRestricted_for_Close(index)) return CloseStream_and_FinalRename(index); + return CloseStream((unsigned)index); +} + + +HRESULT CMultiOutStream::CreateNewStream(UInt64 newSize) +{ + PRF(printf("\n== %u, CreateNewStream, size =%u \n", Streams.Size(), (unsigned)newSize)) + + if (Streams.Size() >= k_NumVols_MAX) + return E_INVALIDARG; // E_OUTOFMEMORY + + RINOK(PrepareToOpenNew()) + CVolStream s; + s.StreamSpec = new COutFileStream; + s.Stream = s.StreamSpec; + const FString path = GetFilePath(Streams.Size()); + + if (NFind::DoesFileExist_Raw(path)) + return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); + if (!CreateTempFile2(path, false, s.Postfix, &s.StreamSpec->File)) + return GetLastError_noZero_HRESULT(); + + s.Start = GetGlobalOffset_for_NewStream(); + s.Pos = 0; + s.RealSize = 0; + + const unsigned index = Streams.Add(s); + InsertToLinkedList(index); + + if (newSize != 0) + return s.SetSize2(newSize); + return S_OK; +} + + +HRESULT CMultiOutStream::CreateStreams_If_Required(unsigned streamIndex) +{ + // UInt64 lastStreamSize = 0; + for (;;) + { + const unsigned numStreamsBefore = Streams.Size(); + if (streamIndex < numStreamsBefore) + return S_OK; + UInt64 newSize; + if (streamIndex == numStreamsBefore) + { + // it's final volume that will be used for real writing. + /* SetSize(_offsetPos) is not required, + because the file Size will be set later by calling Seek() with Write() */ + newSize = 0; // lastStreamSize; + } + else + { + // it's intermediate volume. So we need full volume size + newSize = GetVolSize_for_Stream(numStreamsBefore); + } + + RINOK(CreateNewStream(newSize)) + + // optional check + if (numStreamsBefore + 1 != Streams.Size()) return E_FAIL; + + if (streamIndex != numStreamsBefore) + { + // it's intermediate volume. So we can close it, if it's non-restricted + bool isRestricted; + { + const CVolStream &s = Streams[numStreamsBefore]; + if (newSize == 0) + isRestricted = IsRestricted_Empty(s); + else + isRestricted = IsRestricted(s); + } + if (!isRestricted) + { + RINOK(CloseStream_and_FinalRename(numStreamsBefore)) + } + } + } +} + + +HRESULT CMultiOutStream::ReOpenStream(unsigned streamIndex) +{ + PRF(printf("\n====== %u, ReOpenStream \n", streamIndex)) + RINOK(PrepareToOpenNew()) + CVolStream &s = Streams[streamIndex]; + + FString path = GetFilePath(streamIndex); + path += s.Postfix; + + s.StreamSpec = new COutFileStream; + s.Stream = s.StreamSpec; + s.Pos = 0; + + HRESULT hres; + if (s.StreamSpec->Open_EXISTING(path)) + { + if (s.Postfix.IsEmpty()) + { + /* it's unexpected case that we open finished volume. + It can mean that the code for restriction is incorrect */ + FinalVol_WasReopen = true; + } + UInt64 realSize = 0; + hres = s.StreamSpec->GetSize(&realSize); + if (hres == S_OK) + { + if (realSize == s.RealSize) + { + PRF(printf("\n ReOpenStream OK realSize = %u\n", (unsigned)realSize)) + InsertToLinkedList(streamIndex); + return S_OK; + } + // file size was changed between Close() and ReOpen() + // we must release Stream to be consistent with linked list + hres = E_FAIL; + } + } + else + hres = GetLastError_noZero_HRESULT(); + s.Stream.Release(); + s.StreamSpec = NULL; + return hres; +} + + +/* Sets size of stream, if new size is not equal to old size (RealSize). + If stream was closed and size change is required, it reopens the stream. */ + +HRESULT CMultiOutStream::OptReOpen_and_SetSize(unsigned index, UInt64 size) +{ + CVolStream &s = Streams[index]; + if (size == s.RealSize) + return S_OK; + if (!s.Stream) + { + RINOK(ReOpenStream(index)) + } + PRF(printf("\n== %u, OptReOpen_and_SetSize, size =%u RealSize = %u\n", index, (unsigned)size, (unsigned)s.RealSize)) + // comment it to debug tail after data + return s.SetSize2(size); +} + + +/* +call Normalize_finalMode(false), if _length was changed. + for all streams starting after _length: + - it sets zero size + - it still keeps file open + Note: after _length reducing with CMultiOutStream::SetSize() we can + have very big number of empty streams at the end of Streams[] list. + And Normalize_finalMode() will runs all these empty streams of Streams[] vector. + So it can be ineffective, if we call Normalize_finalMode() many + times after big reducing of (_length). + +call Normalize_finalMode(true) to set final presentations of all streams + for all streams starting after _length: + - it sets zero size + - it removes file + - it removes CVolStream object from Streams[] vector + +Note: we don't remove zero sized first volume, if (_length == 0) +*/ + +HRESULT CMultiOutStream::Normalize_finalMode(bool finalMode) +{ + PRF(printf("\n== Normalize_finalMode: _length =%d \n", (unsigned)_length)) + + unsigned i = Streams.Size(); + + UInt64 offset = 0; + + /* At first we normalize (reduce or increase) the sizes of all existing + streams in Streams[] that can be affected by changed _length. + And we remove tailing zero-size streams, if (finalMode == true) */ + while (i != 0) + { + offset = Streams[--i].Start; // it's last item in Streams[] + // we don't want to remove first volume + if (offset < _length || i == 0) + { + const UInt64 volSize = GetVolSize_for_Stream(i); + UInt64 size = _length - offset; // (size != 0) here + if (size > volSize) + size = volSize; + RINOK(OptReOpen_and_SetSize(i, size)) + if (_length - offset <= volSize) + return S_OK; + // _length - offset > volSize + offset += volSize; + // _length > offset + break; + // UPDATE_HRES(res, OptReOpen_and_SetSize(i, size)); + } + + /* we Set Size of stream to zero even for (finalMode==true), although + that stream will be deleted in next commands */ + // UPDATE_HRES(res, OptReOpen_and_SetSize(i, 0)); + RINOK(OptReOpen_and_SetSize(i, 0)) + if (finalMode) + { + RINOK(CloseStream_and_DeleteFile(i)) + /* CVolStream::Stream was released above already, and it was + removed from linked list. So we don't need to update linked list + structure, when we delete last item in Streams[] */ + Streams.DeleteBack(); + // Delete_LastStream_Records(); + } + } + + /* now we create new zero-filled streams to cover all data up to _length */ + + if (_length == 0) + return S_OK; + + // (offset) is start offset of next stream after existing Streams[] + + for (;;) + { + // _length > offset + const UInt64 volSize = GetVolSize_for_Stream(Streams.Size()); + UInt64 size = _length - offset; // (size != 0) here + if (size > volSize) + size = volSize; + RINOK(CreateNewStream(size)) + if (_length - offset <= volSize) + return S_OK; + // _length - offset > volSize) + offset += volSize; + // _length > offset + } +} + + +HRESULT CMultiOutStream::FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes) +{ + // at first we remove unused zero-sized streams after _length + HRESULT res = Normalize_finalMode(true); + numTotalVolumesRes = Streams.Size(); + FOR_VECTOR (i, Streams) + { + const HRESULT res2 = CloseStream_and_FinalRename(i); + if (res == S_OK) + res = res2; + } + if (NumListItems != 0 && res == S_OK) + res = E_FAIL; + return res; +} + + +bool CMultiOutStream::SetMTime_Final(const CFiTime &mTime) +{ + // we will set mtime only if new value differs from previous + if (!FinalVol_WasReopen && MTime_Defined && Compare_FiTime(&MTime, &mTime) == 0) + return true; + bool res = true; + FOR_VECTOR (i, Streams) + { + CVolStream &s = Streams[i]; + if (s.Stream) + { + if (!s.StreamSpec->SetMTime(&mTime)) + res = false; + } + else + { + if (!SetDirTime(GetFilePath(i), NULL, NULL, &mTime)) + res = false; + } + } + return res; +} + + +Z7_COM7F_IMF(CMultiOutStream::SetSize(UInt64 newSize)) +{ + COM_TRY_BEGIN + if ((Int64)newSize < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + if (newSize > _absLimit) + { + /* big seek value was sent to SetSize() or to Seek()+Write(). + It can mean one of two situations: + 1) some incorrect code called it with big seek value. + 2) volume size was small, and we have too big number of volumes + */ + /* in Windows SetEndOfFile() can return: + ERROR_NEGATIVE_SEEK: for >= (1 << 63) + ERROR_INVALID_PARAMETER: for > (16 TiB - 64 KiB) + ERROR_DISK_FULL: for <= (16 TiB - 64 KiB) + */ + // return E_FAIL; + // return E_OUTOFMEMORY; + return E_INVALIDARG; + } + + if (newSize > _length) + { + // we don't expect such case. So we just define global restriction */ + _restrict_Global = newSize; + } + else if (newSize < _restrict_Global) + _restrict_Global = newSize; + + PRF(printf("\n== CMultiOutStream::SetSize, size =%u \n", (unsigned)newSize)) + + _length = newSize; + return Normalize_finalMode(false); + + COM_TRY_END +} + + +Z7_COM7F_IMF(CMultiOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + COM_TRY_BEGIN + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + + PRF(printf("\n -- CMultiOutStream::Write() : _absPos = %6u, size =%6u \n", + (unsigned)_absPos, (unsigned)size)) + + if (_absPos > _length) + { + // it create data only up to _absPos. + // but we still can need additional new streams, if _absPos at range of volume + RINOK(SetSize(_absPos)) + } + + while (size != 0) + { + UInt64 volSize; + { + if (_streamIndex < Sizes.Size() - 1) + { + volSize = Sizes[_streamIndex]; + if (_offsetPos >= volSize) + { + _offsetPos -= volSize; + _streamIndex++; + continue; + } + } + else + { + volSize = Sizes[Sizes.Size() - 1]; + if (_offsetPos >= volSize) + { + const UInt64 v = _offsetPos / volSize; + if (v >= ((UInt32)(Int32)-1) - _streamIndex) + return E_INVALIDARG; + // throw 202208; + _streamIndex += (unsigned)v; + _offsetPos -= (unsigned)v * volSize; + } + if (_streamIndex >= k_NumVols_MAX) + return E_INVALIDARG; + } + } + + // (_offsetPos < volSize) here + + /* we can need to create one or more streams here, + vol_size for some streams is allowed to be 0. + Also we close some new created streams, if they are non-restricted */ + // file Size will be set later by calling Seek() with Write() + + /* the case (_absPos > _length) was processed above with SetSize(_absPos), + so here it's expected. that we can create optional zero-size streams and then _streamIndex */ + RINOK(CreateStreams_If_Required(_streamIndex)) + + CVolStream &s = Streams[_streamIndex]; + + PRF(printf("\n%d, == Write : Pos = %u, RealSize = %u size =%u \n", + _streamIndex, (unsigned)s.Pos, (unsigned)s.RealSize, size)) + + if (!s.Stream) + { + RINOK(ReOpenStream(_streamIndex)) + } + if (_offsetPos != s.Pos) + { + RINOK(s.Stream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL)) + s.Pos = _offsetPos; + } + + UInt32 curSize = size; + { + const UInt64 rem = volSize - _offsetPos; + if (curSize > rem) + curSize = (UInt32)rem; + } + // curSize != 0 + UInt32 realProcessed = 0; + + HRESULT hres = s.Stream->Write(data, curSize, &realProcessed); + + data = (const void *)((const Byte *)data + realProcessed); + size -= realProcessed; + s.Pos += realProcessed; + _offsetPos += realProcessed; + _absPos += realProcessed; + if (_length < _absPos) + _length = _absPos; + if (s.RealSize < _offsetPos) + s.RealSize = _offsetPos; + if (processedSize) + *processedSize += realProcessed; + + if (s.Pos == volSize) + { + bool isRestricted; + if (volSize == 0) + isRestricted = IsRestricted_Empty(s); + else + isRestricted = IsRestricted(s); + if (!isRestricted) + { + const HRESULT res2 = CloseStream_and_FinalRename(_streamIndex); + if (hres == S_OK) + hres = res2; + } + _streamIndex++; + _offsetPos = 0; + } + + RINOK(hres) + if (realProcessed == 0 && curSize != 0) + return E_FAIL; + // break; + } + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CMultiOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + PRF(printf("\n-- CMultiOutStream::Seek seekOrigin=%u Seek =%u\n", seekOrigin, (unsigned)offset)) + + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _absPos; break; + case STREAM_SEEK_END: offset += _length; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + if ((UInt64)offset != _absPos) + { + _absPos = (UInt64)offset; + _offsetPos = (UInt64)offset; + _streamIndex = 0; + } + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + + +// result value will be saturated to (UInt32)(Int32)-1 + +unsigned CMultiOutStream::GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const +{ + const unsigned last = Sizes.Size() - 1; + for (unsigned i = 0; i < last; i++) + { + const UInt64 size = Sizes[i]; + if (offset < size) + { + relOffset = offset; + return i; + } + offset -= size; + } + const UInt64 size = Sizes[last]; + const UInt64 v = offset / size; + if (v >= ((UInt32)(Int32)-1) - last) + return (unsigned)(int)-1; // saturation + relOffset = offset - (unsigned)v * size; + return last + (unsigned)(v); +} + + +Z7_COM7F_IMF(CMultiOutStream::SetRestriction(UInt64 begin, UInt64 end)) +{ + COM_TRY_BEGIN + + // begin = end = 0; // for debug + + PRF(printf("\n==================== CMultiOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end)) + if (begin > end) + { + // these value are FAILED values. + return E_FAIL; + // return E_INVALIDARG; + /* + // or we can ignore error with 3 ways: no change, non-restricted, saturation: + end = begin; // non-restricted + end = (UInt64)(Int64)-1; // saturation: + return S_OK; + */ + } + UInt64 b = _restrict_Begin; + UInt64 e = _restrict_End; + _restrict_Begin = begin; + _restrict_End = end; + + if (b == e) // if there were no restriction before + return S_OK; // no work to derestrict now. + + /* [b, e) is previous restricted region. So all volumes that + intersect that [b, e) region are candidats for derestriction */ + + if (begin != end) // if there is new non-empty restricted region + { + /* Now we will try to reduce or change (b) and (e) bounds + to reduce main loop that checks volumes for derestriction. + We still use one big derestriction region in main loop, although + in some cases we could have two smaller derestriction regions. + Also usually restriction region cannot move back from previous start position, + so (b <= begin) is expected here for normal cases */ + if (b == begin) // if same low bounds + b = end; // we need to derestrict only after the end of new restricted region + if (e == end) // if same high bounds + e = begin; // we need to derestrict only before the begin of new restricted region + } + + if (b > e) // || b == (UInt64)(Int64)-1 + return S_OK; + + /* Here we close finished volumes that are not restricted anymore. + We close (low number) volumes at first. */ + + UInt64 offset; + unsigned index = GetStreamIndex_for_Offset(b, offset); + + for (; index < Streams.Size(); index++) + { + { + const CVolStream &s = Streams[index]; + if (_length <= s.Start) + break; // we don't close streams after _length + // (_length > s.Start) + const UInt64 volSize = GetVolSize_for_Stream(index); + if (volSize == 0) + { + if (e < s.Start) + break; + // we don't close empty stream, if next byte [s.Start, s.Start] is restricted + if (IsRestricted_Empty(s)) + continue; + } + else + { + if (e <= s.Start) + break; + // we don't close non full streams + if (_length - s.Start < volSize) + break; + // (volSize == s.RealSize) is expected here. So no need to check it + // if (volSize != s.RealSize) break; + if (IsRestricted(s)) + continue; + } + } + RINOK(CloseStream_and_FinalRename(index)) + } + + return S_OK; + COM_TRY_END +} diff --git a/CPP/7zip/Common/MultiOutStream.h b/CPP/7zip/Common/MultiOutStream.h index 90482d7ff..2fb78112e 100644 --- a/CPP/7zip/Common/MultiOutStream.h +++ b/CPP/7zip/Common/MultiOutStream.h @@ -1,160 +1,160 @@ -// MultiOutStream.h - -#ifndef ZIP7_INC_MULTI_OUT_STREAM_H -#define ZIP7_INC_MULTI_OUT_STREAM_H - -#include "FileStreams.h" - -Z7_CLASS_IMP_COM_2( - CMultiOutStream - , IOutStream - , IStreamSetRestriction -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - Z7_CLASS_NO_COPY(CMultiOutStream) - - struct CVolStream - { - COutFileStream *StreamSpec; - CMyComPtr Stream; - UInt64 Start; // start pos of current Stream in global stream - UInt64 Pos; // pos in current Stream - UInt64 RealSize; - int Next; // next older - int Prev; // prev newer - AString Postfix; - - HRESULT SetSize2(UInt64 size) - { - const HRESULT res = Stream->SetSize(size); - if (res == SZ_OK) - RealSize = size; - return res; - } - }; - - unsigned _streamIndex; // (_streamIndex >= Stream.Size()) is allowed in some internal code - UInt64 _offsetPos; // offset relative to Streams[_streamIndex] volume. (_offsetPos >= volSize is allowed) - UInt64 _absPos; - UInt64 _length; // virtual Length - UInt64 _absLimit; - - CObjectVector Streams; - CRecordVector Sizes; - - UInt64 _restrict_Begin; - UInt64 _restrict_End; - UInt64 _restrict_Global; - - unsigned NumOpenFiles_AllowedMax; - - // ----- Double Linked List ----- - - unsigned NumListItems; - int Head; // newest - int Tail; // oldest - - void InitLinkedList() - { - Head = -1; - Tail = -1; - NumListItems = 0; - } - - void InsertToLinkedList(unsigned index) - { - { - CVolStream &node = Streams[index]; - node.Next = Head; - node.Prev = -1; - } - if (Head != -1) - Streams[(unsigned)Head].Prev = (int)index; - else - { - // if (Tail != -1) throw 1; - Tail = (int)index; - } - Head = (int)index; - NumListItems++; - } - - void RemoveFromLinkedList(unsigned index) - { - CVolStream &s = Streams[index]; - if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev; - if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next; - s.Next = -1; // optional - s.Prev = -1; // optional - NumListItems--; - } - - /* - void Delete_LastStream_Records() - { - if (Streams.Back().Stream) - RemoveFromLinkedList(Streams.Size() - 1); - Streams.DeleteBack(); - } - */ - - UInt64 GetVolSize_for_Stream(unsigned i) const - { - const unsigned last = Sizes.Size() - 1; - return Sizes[i < last ? i : last]; - } - UInt64 GetGlobalOffset_for_NewStream() const - { - return Streams.Size() == 0 ? 0: - Streams.Back().Start + - GetVolSize_for_Stream(Streams.Size() - 1); - } - unsigned GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const; - bool IsRestricted(const CVolStream &s) const; - bool IsRestricted_Empty(const CVolStream &s) const - { - // (s) must be stream that has (VolSize == 0). - // we treat empty stream as restricted, if next byte is restricted. - if (s.Start < _restrict_Global) - return true; - return - (_restrict_Begin != _restrict_End) - && (_restrict_Begin <= s.Start) - && (_restrict_Begin == s.Start || _restrict_End > s.Start); - } - // bool IsRestricted_for_Close(unsigned index) const; - FString GetFilePath(unsigned index); - - HRESULT CloseStream(unsigned index); - HRESULT CloseStream_and_DeleteFile(unsigned index); - HRESULT CloseStream_and_FinalRename(unsigned index); - - HRESULT PrepareToOpenNew(); - HRESULT CreateNewStream(UInt64 newSize); - HRESULT CreateStreams_If_Required(unsigned streamIndex); - HRESULT ReOpenStream(unsigned streamIndex); - HRESULT OptReOpen_and_SetSize(unsigned index, UInt64 size); - - HRESULT Normalize_finalMode(bool finalMode); -public: - FString Prefix; - CFiTime MTime; - bool MTime_Defined; - bool FinalVol_WasReopen; - bool NeedDelete; - - CMultiOutStream() {} - ~CMultiOutStream(); - void Init(const CRecordVector &sizes); - bool SetMTime_Final(const CFiTime &mTime); - UInt64 GetSize() const { return _length; } - /* it makes final flushing, closes open files and renames to final name if required - but it still keeps Streams array of all closed files. - So we still can delete all files later, if required */ - HRESULT FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes); - // Destruct object without exceptions - HRESULT Destruct(); -}; - -#endif +// MultiOutStream.h + +#ifndef ZIP7_INC_MULTI_OUT_STREAM_H +#define ZIP7_INC_MULTI_OUT_STREAM_H + +#include "FileStreams.h" + +Z7_CLASS_IMP_COM_2( + CMultiOutStream + , IOutStream + , IStreamSetRestriction +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + Z7_CLASS_NO_COPY(CMultiOutStream) + + struct CVolStream + { + COutFileStream *StreamSpec; + CMyComPtr Stream; + UInt64 Start; // start pos of current Stream in global stream + UInt64 Pos; // pos in current Stream + UInt64 RealSize; + int Next; // next older + int Prev; // prev newer + AString Postfix; + + HRESULT SetSize2(UInt64 size) + { + const HRESULT res = Stream->SetSize(size); + if (res == SZ_OK) + RealSize = size; + return res; + } + }; + + unsigned _streamIndex; // (_streamIndex >= Stream.Size()) is allowed in some internal code + UInt64 _offsetPos; // offset relative to Streams[_streamIndex] volume. (_offsetPos >= volSize is allowed) + UInt64 _absPos; + UInt64 _length; // virtual Length + UInt64 _absLimit; + + CObjectVector Streams; + CRecordVector Sizes; + + UInt64 _restrict_Begin; + UInt64 _restrict_End; + UInt64 _restrict_Global; + + unsigned NumOpenFiles_AllowedMax; + + // ----- Double Linked List ----- + + unsigned NumListItems; + int Head; // newest + int Tail; // oldest + + void InitLinkedList() + { + Head = -1; + Tail = -1; + NumListItems = 0; + } + + void InsertToLinkedList(unsigned index) + { + { + CVolStream &node = Streams[index]; + node.Next = Head; + node.Prev = -1; + } + if (Head != -1) + Streams[(unsigned)Head].Prev = (int)index; + else + { + // if (Tail != -1) throw 1; + Tail = (int)index; + } + Head = (int)index; + NumListItems++; + } + + void RemoveFromLinkedList(unsigned index) + { + CVolStream &s = Streams[index]; + if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev; + if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next; + s.Next = -1; // optional + s.Prev = -1; // optional + NumListItems--; + } + + /* + void Delete_LastStream_Records() + { + if (Streams.Back().Stream) + RemoveFromLinkedList(Streams.Size() - 1); + Streams.DeleteBack(); + } + */ + + UInt64 GetVolSize_for_Stream(unsigned i) const + { + const unsigned last = Sizes.Size() - 1; + return Sizes[i < last ? i : last]; + } + UInt64 GetGlobalOffset_for_NewStream() const + { + return Streams.Size() == 0 ? 0: + Streams.Back().Start + + GetVolSize_for_Stream(Streams.Size() - 1); + } + unsigned GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const; + bool IsRestricted(const CVolStream &s) const; + bool IsRestricted_Empty(const CVolStream &s) const + { + // (s) must be stream that has (VolSize == 0). + // we treat empty stream as restricted, if next byte is restricted. + if (s.Start < _restrict_Global) + return true; + return + (_restrict_Begin != _restrict_End) + && (_restrict_Begin <= s.Start) + && (_restrict_Begin == s.Start || _restrict_End > s.Start); + } + // bool IsRestricted_for_Close(unsigned index) const; + FString GetFilePath(unsigned index); + + HRESULT CloseStream(unsigned index); + HRESULT CloseStream_and_DeleteFile(unsigned index); + HRESULT CloseStream_and_FinalRename(unsigned index); + + HRESULT PrepareToOpenNew(); + HRESULT CreateNewStream(UInt64 newSize); + HRESULT CreateStreams_If_Required(unsigned streamIndex); + HRESULT ReOpenStream(unsigned streamIndex); + HRESULT OptReOpen_and_SetSize(unsigned index, UInt64 size); + + HRESULT Normalize_finalMode(bool finalMode); +public: + FString Prefix; + CFiTime MTime; + bool MTime_Defined; + bool FinalVol_WasReopen; + bool NeedDelete; + + CMultiOutStream() {} + ~CMultiOutStream(); + void Init(const CRecordVector &sizes); + bool SetMTime_Final(const CFiTime &mTime); + UInt64 GetSize() const { return _length; } + /* it makes final flushing, closes open files and renames to final name if required + but it still keeps Streams array of all closed files. + So we still can delete all files later, if required */ + HRESULT FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes); + // Destruct object without exceptions + HRESULT Destruct(); +}; + +#endif diff --git a/CPP/7zip/Common/OffsetStream.cpp b/CPP/7zip/Common/OffsetStream.cpp index de7a8adf8..a6b005e4f 100644 --- a/CPP/7zip/Common/OffsetStream.cpp +++ b/CPP/7zip/Common/OffsetStream.cpp @@ -1,37 +1,37 @@ -// OffsetStream.cpp - -#include "StdAfx.h" - -#include "OffsetStream.h" - -HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset) -{ - _offset = offset; - _stream = stream; - return _stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL); -} - -Z7_COM7F_IMF(COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - return _stream->Write(data, size, processedSize); -} - -Z7_COM7F_IMF(COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - if (seekOrigin == STREAM_SEEK_SET) - { - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - offset += _offset; - } - UInt64 absoluteNewPosition = 0; // =0 for gcc-10 - const HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition); - if (newPosition) - *newPosition = absoluteNewPosition - _offset; - return result; -} - -Z7_COM7F_IMF(COffsetOutStream::SetSize(UInt64 newSize)) -{ - return _stream->SetSize(_offset + newSize); -} +// OffsetStream.cpp + +#include "StdAfx.h" + +#include "OffsetStream.h" + +HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset) +{ + _offset = offset; + _stream = stream; + return _stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL); +} + +Z7_COM7F_IMF(COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + return _stream->Write(data, size, processedSize); +} + +Z7_COM7F_IMF(COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + if (seekOrigin == STREAM_SEEK_SET) + { + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + offset += _offset; + } + UInt64 absoluteNewPosition = 0; // =0 for gcc-10 + const HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition); + if (newPosition) + *newPosition = absoluteNewPosition - _offset; + return result; +} + +Z7_COM7F_IMF(COffsetOutStream::SetSize(UInt64 newSize)) +{ + return _stream->SetSize(_offset + newSize); +} diff --git a/CPP/7zip/Common/OffsetStream.h b/CPP/7zip/Common/OffsetStream.h index 37ebdb410..9bd554cc8 100644 --- a/CPP/7zip/Common/OffsetStream.h +++ b/CPP/7zip/Common/OffsetStream.h @@ -1,22 +1,22 @@ -// OffsetStream.h - -#ifndef ZIP7_INC_OFFSET_STREAM_H -#define ZIP7_INC_OFFSET_STREAM_H - -#include "../../Common/MyCom.h" - -#include "../IStream.h" - -Z7_CLASS_IMP_NOQIB_1( - COffsetOutStream - , IOutStream -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - CMyComPtr _stream; - UInt64 _offset; -public: - HRESULT Init(IOutStream *stream, UInt64 offset); -}; - -#endif +// OffsetStream.h + +#ifndef ZIP7_INC_OFFSET_STREAM_H +#define ZIP7_INC_OFFSET_STREAM_H + +#include "../../Common/MyCom.h" + +#include "../IStream.h" + +Z7_CLASS_IMP_NOQIB_1( + COffsetOutStream + , IOutStream +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + CMyComPtr _stream; + UInt64 _offset; +public: + HRESULT Init(IOutStream *stream, UInt64 offset); +}; + +#endif diff --git a/CPP/7zip/Common/OutBuffer.cpp b/CPP/7zip/Common/OutBuffer.cpp index 151aa34c4..197b3767e 100644 --- a/CPP/7zip/Common/OutBuffer.cpp +++ b/CPP/7zip/Common/OutBuffer.cpp @@ -1,111 +1,111 @@ -// OutBuffer.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "OutBuffer.h" - -bool COutBuffer::Create(UInt32 bufSize) throw() -{ - const UInt32 kMinBlockSize = 1; - if (bufSize < kMinBlockSize) - bufSize = kMinBlockSize; - if (_buf && _bufSize == bufSize) - return true; - Free(); - _bufSize = bufSize; - _buf = (Byte *)::MidAlloc(bufSize); - return (_buf != NULL); -} - -void COutBuffer::Free() throw() -{ - ::MidFree(_buf); - _buf = NULL; -} - -void COutBuffer::Init() throw() -{ - _streamPos = 0; - _limitPos = _bufSize; - _pos = 0; - _processedSize = 0; - _overDict = false; - #ifdef Z7_NO_EXCEPTIONS - ErrorCode = S_OK; - #endif -} - -UInt64 COutBuffer::GetProcessedSize() const throw() -{ - UInt64 res = _processedSize + _pos - _streamPos; - if (_streamPos > _pos) - res += _bufSize; - return res; -} - - -HRESULT COutBuffer::FlushPart() throw() -{ - // _streamPos < _bufSize - UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos); - HRESULT result = S_OK; - #ifdef Z7_NO_EXCEPTIONS - result = ErrorCode; - #endif - if (_buf2) - { - memcpy(_buf2, _buf + _streamPos, size); - _buf2 += size; - } - - if (_stream - #ifdef Z7_NO_EXCEPTIONS - && (ErrorCode == S_OK) - #endif - ) - { - UInt32 processedSize = 0; - result = _stream->Write(_buf + _streamPos, size, &processedSize); - size = processedSize; - } - _streamPos += size; - if (_streamPos == _bufSize) - _streamPos = 0; - if (_pos == _bufSize) - { - _overDict = true; - _pos = 0; - } - _limitPos = (_streamPos > _pos) ? _streamPos : _bufSize; - _processedSize += size; - return result; -} - -HRESULT COutBuffer::Flush() throw() -{ - #ifdef Z7_NO_EXCEPTIONS - if (ErrorCode != S_OK) - return ErrorCode; - #endif - - while (_streamPos != _pos) - { - const HRESULT result = FlushPart(); - if (result != S_OK) - return result; - } - return S_OK; -} - -void COutBuffer::FlushWithCheck() -{ - const HRESULT result = Flush(); - #ifdef Z7_NO_EXCEPTIONS - ErrorCode = result; - #else - if (result != S_OK) - throw COutBufferException(result); - #endif -} +// OutBuffer.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "OutBuffer.h" + +bool COutBuffer::Create(UInt32 bufSize) throw() +{ + const UInt32 kMinBlockSize = 1; + if (bufSize < kMinBlockSize) + bufSize = kMinBlockSize; + if (_buf && _bufSize == bufSize) + return true; + Free(); + _bufSize = bufSize; + _buf = (Byte *)::MidAlloc(bufSize); + return (_buf != NULL); +} + +void COutBuffer::Free() throw() +{ + ::MidFree(_buf); + _buf = NULL; +} + +void COutBuffer::Init() throw() +{ + _streamPos = 0; + _limitPos = _bufSize; + _pos = 0; + _processedSize = 0; + _overDict = false; + #ifdef Z7_NO_EXCEPTIONS + ErrorCode = S_OK; + #endif +} + +UInt64 COutBuffer::GetProcessedSize() const throw() +{ + UInt64 res = _processedSize + _pos - _streamPos; + if (_streamPos > _pos) + res += _bufSize; + return res; +} + + +HRESULT COutBuffer::FlushPart() throw() +{ + // _streamPos < _bufSize + UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos); + HRESULT result = S_OK; + #ifdef Z7_NO_EXCEPTIONS + result = ErrorCode; + #endif + if (_buf2) + { + memcpy(_buf2, _buf + _streamPos, size); + _buf2 += size; + } + + if (_stream + #ifdef Z7_NO_EXCEPTIONS + && (ErrorCode == S_OK) + #endif + ) + { + UInt32 processedSize = 0; + result = _stream->Write(_buf + _streamPos, size, &processedSize); + size = processedSize; + } + _streamPos += size; + if (_streamPos == _bufSize) + _streamPos = 0; + if (_pos == _bufSize) + { + _overDict = true; + _pos = 0; + } + _limitPos = (_streamPos > _pos) ? _streamPos : _bufSize; + _processedSize += size; + return result; +} + +HRESULT COutBuffer::Flush() throw() +{ + #ifdef Z7_NO_EXCEPTIONS + if (ErrorCode != S_OK) + return ErrorCode; + #endif + + while (_streamPos != _pos) + { + const HRESULT result = FlushPart(); + if (result != S_OK) + return result; + } + return S_OK; +} + +void COutBuffer::FlushWithCheck() +{ + const HRESULT result = Flush(); + #ifdef Z7_NO_EXCEPTIONS + ErrorCode = result; + #else + if (result != S_OK) + throw COutBufferException(result); + #endif +} diff --git a/CPP/7zip/Common/OutBuffer.h b/CPP/7zip/Common/OutBuffer.h index 6564eca04..88f578771 100644 --- a/CPP/7zip/Common/OutBuffer.h +++ b/CPP/7zip/Common/OutBuffer.h @@ -1,108 +1,108 @@ -// OutBuffer.h - -#ifndef ZIP7_INC_OUT_BUFFER_H -#define ZIP7_INC_OUT_BUFFER_H - -#include "../IStream.h" -#include "../../Common/MyCom.h" -#include "../../Common/MyException.h" - -#ifndef Z7_NO_EXCEPTIONS -struct COutBufferException: public CSystemException -{ - COutBufferException(HRESULT errorCode): CSystemException(errorCode) {} -}; -#endif - -class COutBuffer -{ -protected: - Byte *_buf; - UInt32 _pos; - UInt32 _limitPos; - UInt32 _streamPos; - UInt32 _bufSize; - ISequentialOutStream *_stream; - UInt64 _processedSize; - Byte *_buf2; - bool _overDict; - - HRESULT FlushPart() throw(); -public: - #ifdef Z7_NO_EXCEPTIONS - HRESULT ErrorCode; - #endif - - COutBuffer(): _buf(NULL), _pos(0), _stream(NULL), _buf2(NULL) {} - ~COutBuffer() { Free(); } - - bool Create(UInt32 bufSize) throw(); - void Free() throw(); - - void SetMemStream(Byte *buf) { _buf2 = buf; } - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void Init() throw(); - HRESULT Flush() throw(); - void FlushWithCheck(); - - void WriteByte(Byte b) - { - UInt32 pos = _pos; - _buf[pos] = b; - pos++; - _pos = pos; - if (pos == _limitPos) - FlushWithCheck(); - } - void WriteBytes(const void *data, size_t size) - { - for (size_t i = 0; i < size; i++) - WriteByte(((const Byte *)data)[i]); - } - - Byte *GetOutBuffer(size_t &avail) - { - const UInt32 pos = _pos; - avail = (size_t)(_limitPos - pos); - return _buf + pos; - } - - void SkipWrittenBytes(size_t num) - { - const UInt32 pos = _pos; - const UInt32 rem = _limitPos - pos; - if (rem > num) - { - _pos = pos + (UInt32)num; - return; - } - // (rem <= num) - // the caller must not call it with (rem < num) - // so (rem == num) - _pos = _limitPos; - FlushWithCheck(); - } - /* - void WriteBytesBig(const void *data, size_t size) - { - while (size) - { - UInt32 pos = _pos; - UInt32 rem = _limitPos - pos; - if (rem > size) - { - _pos = pos + size; - memcpy(_buf + pos, data, size); - return; - } - memcpy(_buf + pos, data, rem); - _pos = pos + rem; - FlushWithCheck(); - } - } - */ - - UInt64 GetProcessedSize() const throw(); -}; - -#endif +// OutBuffer.h + +#ifndef ZIP7_INC_OUT_BUFFER_H +#define ZIP7_INC_OUT_BUFFER_H + +#include "../IStream.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyException.h" + +#ifndef Z7_NO_EXCEPTIONS +struct COutBufferException: public CSystemException +{ + COutBufferException(HRESULT errorCode): CSystemException(errorCode) {} +}; +#endif + +class COutBuffer +{ +protected: + Byte *_buf; + UInt32 _pos; + UInt32 _limitPos; + UInt32 _streamPos; + UInt32 _bufSize; + ISequentialOutStream *_stream; + UInt64 _processedSize; + Byte *_buf2; + bool _overDict; + + HRESULT FlushPart() throw(); +public: + #ifdef Z7_NO_EXCEPTIONS + HRESULT ErrorCode; + #endif + + COutBuffer(): _buf(NULL), _pos(0), _stream(NULL), _buf2(NULL) {} + ~COutBuffer() { Free(); } + + bool Create(UInt32 bufSize) throw(); + void Free() throw(); + + void SetMemStream(Byte *buf) { _buf2 = buf; } + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void Init() throw(); + HRESULT Flush() throw(); + void FlushWithCheck(); + + void WriteByte(Byte b) + { + UInt32 pos = _pos; + _buf[pos] = b; + pos++; + _pos = pos; + if (pos == _limitPos) + FlushWithCheck(); + } + void WriteBytes(const void *data, size_t size) + { + for (size_t i = 0; i < size; i++) + WriteByte(((const Byte *)data)[i]); + } + + Byte *GetOutBuffer(size_t &avail) + { + const UInt32 pos = _pos; + avail = (size_t)(_limitPos - pos); + return _buf + pos; + } + + void SkipWrittenBytes(size_t num) + { + const UInt32 pos = _pos; + const UInt32 rem = _limitPos - pos; + if (rem > num) + { + _pos = pos + (UInt32)num; + return; + } + // (rem <= num) + // the caller must not call it with (rem < num) + // so (rem == num) + _pos = _limitPos; + FlushWithCheck(); + } + /* + void WriteBytesBig(const void *data, size_t size) + { + while (size) + { + UInt32 pos = _pos; + UInt32 rem = _limitPos - pos; + if (rem > size) + { + _pos = pos + size; + memcpy(_buf + pos, data, size); + return; + } + memcpy(_buf + pos, data, rem); + _pos = pos + rem; + FlushWithCheck(); + } + } + */ + + UInt64 GetProcessedSize() const throw(); +}; + +#endif diff --git a/CPP/7zip/Common/OutMemStream.cpp b/CPP/7zip/Common/OutMemStream.cpp index 29773e7df..29a23941f 100644 --- a/CPP/7zip/Common/OutMemStream.cpp +++ b/CPP/7zip/Common/OutMemStream.cpp @@ -1,158 +1,158 @@ -// OutMemStream.cpp - -#include "StdAfx.h" - -// #include - -#include "OutMemStream.h" - -void COutMemStream::Free() -{ - Blocks.Free(_memManager); - Blocks.LockMode = true; -} - -void COutMemStream::Init() -{ - WriteToRealStreamEvent.Reset(); - _unlockEventWasSent = false; - _realStreamMode = false; - Free(); - _curBlockPos = 0; - _curBlockIndex = 0; -} - -void COutMemStream::DetachData(CMemLockBlocks &blocks) -{ - Blocks.Detach(blocks, _memManager); - Free(); -} - - -HRESULT COutMemStream::WriteToRealStream() -{ - RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream)) - Blocks.Free(_memManager); - return S_OK; -} - - -Z7_COM7F_IMF(COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (_realStreamMode) - return OutSeqStream->Write(data, size, processedSize); - if (processedSize) - *processedSize = 0; - while (size != 0) - { - if (_curBlockIndex < Blocks.Blocks.Size()) - { - Byte *p = (Byte *)Blocks.Blocks[_curBlockIndex] + _curBlockPos; - size_t curSize = _memManager->GetBlockSize() - _curBlockPos; - if (size < curSize) - curSize = size; - memcpy(p, data, curSize); - if (processedSize) - *processedSize += (UInt32)curSize; - data = (const void *)((const Byte *)data + curSize); - size -= (UInt32)curSize; - _curBlockPos += curSize; - - const UInt64 pos64 = GetPos(); - if (pos64 > Blocks.TotalSize) - Blocks.TotalSize = pos64; - if (_curBlockPos == _memManager->GetBlockSize()) - { - _curBlockIndex++; - _curBlockPos = 0; - } - continue; - } - - const NWindows::NSynchronization::CHandle_WFMO events[3] = - { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore }; - const DWORD waitResult = NWindows::NSynchronization::WaitForMultiObj_Any_Infinite( - ((Blocks.LockMode /* && _memManager->Semaphore.IsCreated() */) ? 3 : 2), events); - - // printf("\n 1- outMemStream %d\n", waitResult - WAIT_OBJECT_0); - - switch (waitResult) - { - case (WAIT_OBJECT_0 + 0): - return StopWriteResult; - case (WAIT_OBJECT_0 + 1): - { - _realStreamMode = true; - RINOK(WriteToRealStream()) - UInt32 processedSize2; - const HRESULT res = OutSeqStream->Write(data, size, &processedSize2); - if (processedSize) - *processedSize += processedSize2; - return res; - } - case (WAIT_OBJECT_0 + 2): - { - // it has bug: no write. - /* - if (!Blocks.SwitchToNoLockMode(_memManager)) - return E_FAIL; - */ - break; - } - default: - { - if (waitResult == WAIT_FAILED) - { - const DWORD res = ::GetLastError(); - if (res != 0) - return HRESULT_FROM_WIN32(res); - } - return E_FAIL; - } - } - void *p = _memManager->AllocateBlock(); - if (!p) - return E_FAIL; - Blocks.Blocks.Add(p); - } - return S_OK; -} - -Z7_COM7F_IMF(COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - if (_realStreamMode) - { - if (!OutStream) - return E_FAIL; - return OutStream->Seek(offset, seekOrigin, newPosition); - } - if (seekOrigin == STREAM_SEEK_CUR) - { - if (offset != 0) - return E_NOTIMPL; - } - else if (seekOrigin == STREAM_SEEK_SET) - { - if (offset != 0) - return E_NOTIMPL; - _curBlockIndex = 0; - _curBlockPos = 0; - } - else - return E_NOTIMPL; - if (newPosition) - *newPosition = GetPos(); - return S_OK; -} - -Z7_COM7F_IMF(COutMemStream::SetSize(UInt64 newSize)) -{ - if (_realStreamMode) - { - if (!OutStream) - return E_FAIL; - return OutStream->SetSize(newSize); - } - Blocks.TotalSize = newSize; - return S_OK; -} +// OutMemStream.cpp + +#include "StdAfx.h" + +// #include + +#include "OutMemStream.h" + +void COutMemStream::Free() +{ + Blocks.Free(_memManager); + Blocks.LockMode = true; +} + +void COutMemStream::Init() +{ + WriteToRealStreamEvent.Reset(); + _unlockEventWasSent = false; + _realStreamMode = false; + Free(); + _curBlockPos = 0; + _curBlockIndex = 0; +} + +void COutMemStream::DetachData(CMemLockBlocks &blocks) +{ + Blocks.Detach(blocks, _memManager); + Free(); +} + + +HRESULT COutMemStream::WriteToRealStream() +{ + RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream)) + Blocks.Free(_memManager); + return S_OK; +} + + +Z7_COM7F_IMF(COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (_realStreamMode) + return OutSeqStream->Write(data, size, processedSize); + if (processedSize) + *processedSize = 0; + while (size != 0) + { + if (_curBlockIndex < Blocks.Blocks.Size()) + { + Byte *p = (Byte *)Blocks.Blocks[_curBlockIndex] + _curBlockPos; + size_t curSize = _memManager->GetBlockSize() - _curBlockPos; + if (size < curSize) + curSize = size; + memcpy(p, data, curSize); + if (processedSize) + *processedSize += (UInt32)curSize; + data = (const void *)((const Byte *)data + curSize); + size -= (UInt32)curSize; + _curBlockPos += curSize; + + const UInt64 pos64 = GetPos(); + if (pos64 > Blocks.TotalSize) + Blocks.TotalSize = pos64; + if (_curBlockPos == _memManager->GetBlockSize()) + { + _curBlockIndex++; + _curBlockPos = 0; + } + continue; + } + + const NWindows::NSynchronization::CHandle_WFMO events[3] = + { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore }; + const DWORD waitResult = NWindows::NSynchronization::WaitForMultiObj_Any_Infinite( + ((Blocks.LockMode /* && _memManager->Semaphore.IsCreated() */) ? 3 : 2), events); + + // printf("\n 1- outMemStream %d\n", waitResult - WAIT_OBJECT_0); + + switch (waitResult) + { + case (WAIT_OBJECT_0 + 0): + return StopWriteResult; + case (WAIT_OBJECT_0 + 1): + { + _realStreamMode = true; + RINOK(WriteToRealStream()) + UInt32 processedSize2; + const HRESULT res = OutSeqStream->Write(data, size, &processedSize2); + if (processedSize) + *processedSize += processedSize2; + return res; + } + case (WAIT_OBJECT_0 + 2): + { + // it has bug: no write. + /* + if (!Blocks.SwitchToNoLockMode(_memManager)) + return E_FAIL; + */ + break; + } + default: + { + if (waitResult == WAIT_FAILED) + { + const DWORD res = ::GetLastError(); + if (res != 0) + return HRESULT_FROM_WIN32(res); + } + return E_FAIL; + } + } + void *p = _memManager->AllocateBlock(); + if (!p) + return E_FAIL; + Blocks.Blocks.Add(p); + } + return S_OK; +} + +Z7_COM7F_IMF(COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + if (_realStreamMode) + { + if (!OutStream) + return E_FAIL; + return OutStream->Seek(offset, seekOrigin, newPosition); + } + if (seekOrigin == STREAM_SEEK_CUR) + { + if (offset != 0) + return E_NOTIMPL; + } + else if (seekOrigin == STREAM_SEEK_SET) + { + if (offset != 0) + return E_NOTIMPL; + _curBlockIndex = 0; + _curBlockPos = 0; + } + else + return E_NOTIMPL; + if (newPosition) + *newPosition = GetPos(); + return S_OK; +} + +Z7_COM7F_IMF(COutMemStream::SetSize(UInt64 newSize)) +{ + if (_realStreamMode) + { + if (!OutStream) + return E_FAIL; + return OutStream->SetSize(newSize); + } + Blocks.TotalSize = newSize; + return S_OK; +} diff --git a/CPP/7zip/Common/OutMemStream.h b/CPP/7zip/Common/OutMemStream.h index 33e497608..a58fb91bf 100644 --- a/CPP/7zip/Common/OutMemStream.h +++ b/CPP/7zip/Common/OutMemStream.h @@ -1,104 +1,104 @@ -// OutMemStream.h - -#ifndef ZIP7_INC_OUT_MEM_STREAM_H -#define ZIP7_INC_OUT_MEM_STREAM_H - -#include "../../Common/MyCom.h" - -#include "MemBlocks.h" - -Z7_CLASS_IMP_NOQIB_1( - COutMemStream - , IOutStream -) - Z7_IFACE_COM7_IMP(ISequentialOutStream) - - CMemBlockManagerMt *_memManager; - size_t _curBlockPos; - unsigned _curBlockIndex; - bool _realStreamMode; - - bool _unlockEventWasSent; - NWindows::NSynchronization::CAutoResetEvent_WFMO StopWritingEvent; - NWindows::NSynchronization::CAutoResetEvent_WFMO WriteToRealStreamEvent; - // NWindows::NSynchronization::CAutoResetEvent NoLockEvent; - - HRESULT StopWriteResult; - CMemLockBlocks Blocks; - - CMyComPtr OutSeqStream; - CMyComPtr OutStream; - - UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; } - -public: - - HRESULT CreateEvents(SYNC_PARAM_DECL(synchro)) - { - WRes wres = StopWritingEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro)); - if (wres == 0) - wres = WriteToRealStreamEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro)); - return HRESULT_FROM_WIN32(wres); - } - - void SetOutStream(IOutStream *outStream) - { - OutStream = outStream; - OutSeqStream = outStream; - } - - void SetSeqOutStream(ISequentialOutStream *outStream) - { - OutStream = NULL; - OutSeqStream = outStream; - } - - void ReleaseOutStream() - { - OutStream.Release(); - OutSeqStream.Release(); - } - - COutMemStream(CMemBlockManagerMt *memManager): - _memManager(memManager) - { - /* - #ifndef _WIN32 - StopWritingEvent._sync = - WriteToRealStreamEvent._sync = &memManager->Synchro; - #endif - */ - } - - ~COutMemStream() { Free(); } - void Free(); - - void Init(); - HRESULT WriteToRealStream(); - - void DetachData(CMemLockBlocks &blocks); - - bool WasUnlockEventSent() const { return _unlockEventWasSent; } - - void SetRealStreamMode() - { - _unlockEventWasSent = true; - WriteToRealStreamEvent.Set(); - } - - /* - void SetNoLockMode() - { - _unlockEventWasSent = true; - NoLockEvent.Set(); - } - */ - - void StopWriting(HRESULT res) - { - StopWriteResult = res; - StopWritingEvent.Set(); - } -}; - -#endif +// OutMemStream.h + +#ifndef ZIP7_INC_OUT_MEM_STREAM_H +#define ZIP7_INC_OUT_MEM_STREAM_H + +#include "../../Common/MyCom.h" + +#include "MemBlocks.h" + +Z7_CLASS_IMP_NOQIB_1( + COutMemStream + , IOutStream +) + Z7_IFACE_COM7_IMP(ISequentialOutStream) + + CMemBlockManagerMt *_memManager; + size_t _curBlockPos; + unsigned _curBlockIndex; + bool _realStreamMode; + + bool _unlockEventWasSent; + NWindows::NSynchronization::CAutoResetEvent_WFMO StopWritingEvent; + NWindows::NSynchronization::CAutoResetEvent_WFMO WriteToRealStreamEvent; + // NWindows::NSynchronization::CAutoResetEvent NoLockEvent; + + HRESULT StopWriteResult; + CMemLockBlocks Blocks; + + CMyComPtr OutSeqStream; + CMyComPtr OutStream; + + UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; } + +public: + + HRESULT CreateEvents(SYNC_PARAM_DECL(synchro)) + { + WRes wres = StopWritingEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro)); + if (wres == 0) + wres = WriteToRealStreamEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro)); + return HRESULT_FROM_WIN32(wres); + } + + void SetOutStream(IOutStream *outStream) + { + OutStream = outStream; + OutSeqStream = outStream; + } + + void SetSeqOutStream(ISequentialOutStream *outStream) + { + OutStream = NULL; + OutSeqStream = outStream; + } + + void ReleaseOutStream() + { + OutStream.Release(); + OutSeqStream.Release(); + } + + COutMemStream(CMemBlockManagerMt *memManager): + _memManager(memManager) + { + /* + #ifndef _WIN32 + StopWritingEvent._sync = + WriteToRealStreamEvent._sync = &memManager->Synchro; + #endif + */ + } + + ~COutMemStream() { Free(); } + void Free(); + + void Init(); + HRESULT WriteToRealStream(); + + void DetachData(CMemLockBlocks &blocks); + + bool WasUnlockEventSent() const { return _unlockEventWasSent; } + + void SetRealStreamMode() + { + _unlockEventWasSent = true; + WriteToRealStreamEvent.Set(); + } + + /* + void SetNoLockMode() + { + _unlockEventWasSent = true; + NoLockEvent.Set(); + } + */ + + void StopWriting(HRESULT res) + { + StopWriteResult = res; + StopWritingEvent.Set(); + } +}; + +#endif diff --git a/CPP/7zip/Common/ProgressMt.cpp b/CPP/7zip/Common/ProgressMt.cpp index d4f114472..ee21ab3e0 100644 --- a/CPP/7zip/Common/ProgressMt.cpp +++ b/CPP/7zip/Common/ProgressMt.cpp @@ -1,53 +1,53 @@ -// ProgressMt.h - -#include "StdAfx.h" - -#include "ProgressMt.h" - -void CMtCompressProgressMixer::Init(unsigned numItems, ICompressProgressInfo *progress) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - InSizes.Clear(); - OutSizes.Clear(); - for (unsigned i = 0; i < numItems; i++) - { - InSizes.Add(0); - OutSizes.Add(0); - } - TotalInSize = 0; - TotalOutSize = 0; - _progress = progress; -} - -void CMtCompressProgressMixer::Reinit(unsigned index) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - InSizes[index] = 0; - OutSizes[index] = 0; -} - -HRESULT CMtCompressProgressMixer::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize) -{ - NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); - if (inSize) - { - const UInt64 diff = *inSize - InSizes[index]; - InSizes[index] = *inSize; - TotalInSize += diff; - } - if (outSize) - { - const UInt64 diff = *outSize - OutSizes[index]; - OutSizes[index] = *outSize; - TotalOutSize += diff; - } - if (_progress) - return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize); - return S_OK; -} - - -Z7_COM7F_IMF(CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - return _progress->SetRatioInfo(_index, inSize, outSize); -} +// ProgressMt.h + +#include "StdAfx.h" + +#include "ProgressMt.h" + +void CMtCompressProgressMixer::Init(unsigned numItems, ICompressProgressInfo *progress) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + InSizes.Clear(); + OutSizes.Clear(); + for (unsigned i = 0; i < numItems; i++) + { + InSizes.Add(0); + OutSizes.Add(0); + } + TotalInSize = 0; + TotalOutSize = 0; + _progress = progress; +} + +void CMtCompressProgressMixer::Reinit(unsigned index) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + InSizes[index] = 0; + OutSizes[index] = 0; +} + +HRESULT CMtCompressProgressMixer::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection); + if (inSize) + { + const UInt64 diff = *inSize - InSizes[index]; + InSizes[index] = *inSize; + TotalInSize += diff; + } + if (outSize) + { + const UInt64 diff = *outSize - OutSizes[index]; + OutSizes[index] = *outSize; + TotalOutSize += diff; + } + if (_progress) + return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize); + return S_OK; +} + + +Z7_COM7F_IMF(CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + return _progress->SetRatioInfo(_index, inSize, outSize); +} diff --git a/CPP/7zip/Common/ProgressMt.h b/CPP/7zip/Common/ProgressMt.h index 23784e52c..78c806c5b 100644 --- a/CPP/7zip/Common/ProgressMt.h +++ b/CPP/7zip/Common/ProgressMt.h @@ -1,43 +1,43 @@ -// ProgressMt.h - -#ifndef ZIP7_INC_PROGRESSMT_H -#define ZIP7_INC_PROGRESSMT_H - -#include "../../Common/MyCom.h" -#include "../../Common/MyVector.h" -#include "../../Windows/Synchronization.h" - -#include "../ICoder.h" -#include "../IProgress.h" - -class CMtCompressProgressMixer -{ - CMyComPtr _progress; - CRecordVector InSizes; - CRecordVector OutSizes; - UInt64 TotalInSize; - UInt64 TotalOutSize; -public: - NWindows::NSynchronization::CCriticalSection CriticalSection; - void Init(unsigned numItems, ICompressProgressInfo *progress); - void Reinit(unsigned index); - HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize); -}; - - -Z7_CLASS_IMP_NOQIB_1( - CMtCompressProgress - , ICompressProgressInfo -) - unsigned _index; - CMtCompressProgressMixer *_progress; -public: - void Init(CMtCompressProgressMixer *progress, unsigned index) - { - _progress = progress; - _index = index; - } - void Reinit() { _progress->Reinit(_index); } -}; - -#endif +// ProgressMt.h + +#ifndef ZIP7_INC_PROGRESSMT_H +#define ZIP7_INC_PROGRESSMT_H + +#include "../../Common/MyCom.h" +#include "../../Common/MyVector.h" +#include "../../Windows/Synchronization.h" + +#include "../ICoder.h" +#include "../IProgress.h" + +class CMtCompressProgressMixer +{ + CMyComPtr _progress; + CRecordVector InSizes; + CRecordVector OutSizes; + UInt64 TotalInSize; + UInt64 TotalOutSize; +public: + NWindows::NSynchronization::CCriticalSection CriticalSection; + void Init(unsigned numItems, ICompressProgressInfo *progress); + void Reinit(unsigned index); + HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize); +}; + + +Z7_CLASS_IMP_NOQIB_1( + CMtCompressProgress + , ICompressProgressInfo +) + unsigned _index; + CMtCompressProgressMixer *_progress; +public: + void Init(CMtCompressProgressMixer *progress, unsigned index) + { + _progress = progress; + _index = index; + } + void Reinit() { _progress->Reinit(_index); } +}; + +#endif diff --git a/CPP/7zip/Common/ProgressUtils.cpp b/CPP/7zip/Common/ProgressUtils.cpp index f7c4792c6..fb81f29b5 100644 --- a/CPP/7zip/Common/ProgressUtils.cpp +++ b/CPP/7zip/Common/ProgressUtils.cpp @@ -1,51 +1,51 @@ -// ProgressUtils.cpp - -#include "StdAfx.h" - -#include "ProgressUtils.h" - -CLocalProgress::CLocalProgress(): - SendRatio(true), - SendProgress(true), - ProgressOffset(0), - InSize(0), - OutSize(0) - {} - -void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain) -{ - _ratioProgress.Release(); - _progress = progress; - _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress); - _inSizeIsMain = inSizeIsMain; -} - -Z7_COM7F_IMF(CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - UInt64 inSize2 = InSize; - UInt64 outSize2 = OutSize; - - if (inSize) - inSize2 += (*inSize); - if (outSize) - outSize2 += (*outSize); - - if (SendRatio && _ratioProgress) - { - RINOK(_ratioProgress->SetRatioInfo(&inSize2, &outSize2)) - } - - if (SendProgress) - { - inSize2 += ProgressOffset; - outSize2 += ProgressOffset; - return _progress->SetCompleted(_inSizeIsMain ? &inSize2 : &outSize2); - } - - return S_OK; -} - -HRESULT CLocalProgress::SetCur() -{ - return SetRatioInfo(NULL, NULL); -} +// ProgressUtils.cpp + +#include "StdAfx.h" + +#include "ProgressUtils.h" + +CLocalProgress::CLocalProgress(): + SendRatio(true), + SendProgress(true), + ProgressOffset(0), + InSize(0), + OutSize(0) + {} + +void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain) +{ + _ratioProgress.Release(); + _progress = progress; + _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress); + _inSizeIsMain = inSizeIsMain; +} + +Z7_COM7F_IMF(CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + UInt64 inSize2 = InSize; + UInt64 outSize2 = OutSize; + + if (inSize) + inSize2 += (*inSize); + if (outSize) + outSize2 += (*outSize); + + if (SendRatio && _ratioProgress) + { + RINOK(_ratioProgress->SetRatioInfo(&inSize2, &outSize2)) + } + + if (SendProgress) + { + inSize2 += ProgressOffset; + outSize2 += ProgressOffset; + return _progress->SetCompleted(_inSizeIsMain ? &inSize2 : &outSize2); + } + + return S_OK; +} + +HRESULT CLocalProgress::SetCur() +{ + return SetRatioInfo(NULL, NULL); +} diff --git a/CPP/7zip/Common/ProgressUtils.h b/CPP/7zip/Common/ProgressUtils.h index 05396b2d3..dad5fccfa 100644 --- a/CPP/7zip/Common/ProgressUtils.h +++ b/CPP/7zip/Common/ProgressUtils.h @@ -1,33 +1,33 @@ -// ProgressUtils.h - -#ifndef ZIP7_INC_PROGRESS_UTILS_H -#define ZIP7_INC_PROGRESS_UTILS_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" -#include "../IProgress.h" - -Z7_CLASS_IMP_COM_1( - CLocalProgress - , ICompressProgressInfo -) -public: - bool SendRatio; - bool SendProgress; -private: - bool _inSizeIsMain; - CMyComPtr _progress; - CMyComPtr _ratioProgress; -public: - UInt64 ProgressOffset; - UInt64 InSize; - UInt64 OutSize; - - CLocalProgress(); - - void Init(IProgress *progress, bool inSizeIsMain); - HRESULT SetCur(); -}; - -#endif +// ProgressUtils.h + +#ifndef ZIP7_INC_PROGRESS_UTILS_H +#define ZIP7_INC_PROGRESS_UTILS_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" +#include "../IProgress.h" + +Z7_CLASS_IMP_COM_1( + CLocalProgress + , ICompressProgressInfo +) +public: + bool SendRatio; + bool SendProgress; +private: + bool _inSizeIsMain; + CMyComPtr _progress; + CMyComPtr _ratioProgress; +public: + UInt64 ProgressOffset; + UInt64 InSize; + UInt64 OutSize; + + CLocalProgress(); + + void Init(IProgress *progress, bool inSizeIsMain); + HRESULT SetCur(); +}; + +#endif diff --git a/CPP/7zip/Common/PropId.cpp b/CPP/7zip/Common/PropId.cpp index 603ef01d5..6117b0e21 100644 --- a/CPP/7zip/Common/PropId.cpp +++ b/CPP/7zip/Common/PropId.cpp @@ -1,117 +1,117 @@ -// PropId.cpp - -#include "StdAfx.h" - -#include "../../Common/MyWindows.h" - -#include "../PropID.h" - -// VARTYPE -const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] = -{ - VT_EMPTY, - VT_UI4, - VT_UI4, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_BOOL, - VT_UI8, - VT_UI8, - VT_UI4, - VT_FILETIME, - VT_FILETIME, - VT_FILETIME, - VT_BOOL, - VT_BOOL, - VT_BOOL, - VT_BOOL, - VT_BOOL, - VT_UI4, - VT_UI4, - VT_BSTR, - VT_BOOL, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_UI8, - VT_BSTR, - VT_UI8, - VT_BSTR, - VT_UI8, - VT_UI8, - VT_BSTR, // or VT_UI8 kpidUnpackVer - VT_UI4, // or VT_UI8 kpidVolume - VT_BOOL, - VT_UI8, - VT_UI8, - VT_UI8, - VT_UI8, - VT_UI4, - VT_BOOL, - VT_BOOL, - VT_BSTR, - VT_UI8, - VT_UI8, - VT_UI4, // kpidChecksum - VT_BSTR, - VT_UI8, - VT_BSTR, // or VT_UI8 kpidId - VT_BSTR, - VT_BSTR, - VT_UI4, - VT_UI4, - VT_BSTR, - VT_BSTR, - VT_UI8, - VT_UI8, - VT_UI4, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_BSTR, // kpidNtSecure - VT_BOOL, - VT_BOOL, - VT_BOOL, - VT_BOOL, - VT_BSTR, // SHA-1 - VT_BSTR, // SHA-256 - VT_BSTR, - VT_UI8, - VT_UI4, - VT_UI4, - VT_BSTR, - VT_UI8, - VT_UI8, - VT_UI8, - VT_UI8, - VT_UI8, - VT_UI8, - VT_UI8, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_BOOL, - VT_BOOL, - VT_BOOL, - VT_UI8, - VT_UI8, - VT_BSTR, // kpidNtReparse - VT_BSTR, - VT_UI8, - VT_UI8, - VT_BOOL, - VT_BSTR, - VT_BSTR, - VT_BSTR, - VT_BOOL, - VT_FILETIME, // kpidChangeTime - VT_UI4, - VT_UI4, - VT_UI4, - VT_UI4, - VT_UI4, - VT_UI4 // kpidDevMinor -}; +// PropId.cpp + +#include "StdAfx.h" + +#include "../../Common/MyWindows.h" + +#include "../PropID.h" + +// VARTYPE +const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] = +{ + VT_EMPTY, + VT_UI4, + VT_UI4, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_BOOL, + VT_UI8, + VT_UI8, + VT_UI4, + VT_FILETIME, + VT_FILETIME, + VT_FILETIME, + VT_BOOL, + VT_BOOL, + VT_BOOL, + VT_BOOL, + VT_BOOL, + VT_UI4, + VT_UI4, + VT_BSTR, + VT_BOOL, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_UI8, + VT_BSTR, + VT_UI8, + VT_BSTR, + VT_UI8, + VT_UI8, + VT_BSTR, // or VT_UI8 kpidUnpackVer + VT_UI4, // or VT_UI8 kpidVolume + VT_BOOL, + VT_UI8, + VT_UI8, + VT_UI8, + VT_UI8, + VT_UI4, + VT_BOOL, + VT_BOOL, + VT_BSTR, + VT_UI8, + VT_UI8, + VT_UI4, // kpidChecksum + VT_BSTR, + VT_UI8, + VT_BSTR, // or VT_UI8 kpidId + VT_BSTR, + VT_BSTR, + VT_UI4, + VT_UI4, + VT_BSTR, + VT_BSTR, + VT_UI8, + VT_UI8, + VT_UI4, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_BSTR, // kpidNtSecure + VT_BOOL, + VT_BOOL, + VT_BOOL, + VT_BOOL, + VT_BSTR, // SHA-1 + VT_BSTR, // SHA-256 + VT_BSTR, + VT_UI8, + VT_UI4, + VT_UI4, + VT_BSTR, + VT_UI8, + VT_UI8, + VT_UI8, + VT_UI8, + VT_UI8, + VT_UI8, + VT_UI8, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_BOOL, + VT_BOOL, + VT_BOOL, + VT_UI8, + VT_UI8, + VT_BSTR, // kpidNtReparse + VT_BSTR, + VT_UI8, + VT_UI8, + VT_BOOL, + VT_BSTR, + VT_BSTR, + VT_BSTR, + VT_BOOL, + VT_FILETIME, // kpidChangeTime + VT_UI4, + VT_UI4, + VT_UI4, + VT_UI4, + VT_UI4, + VT_UI4 // kpidDevMinor +}; diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h index 71d8aa67b..55c1483f2 100644 --- a/CPP/7zip/Common/RegisterArc.h +++ b/CPP/7zip/Common/RegisterArc.h @@ -1,80 +1,80 @@ -// RegisterArc.h - -#ifndef ZIP7_INC_REGISTER_ARC_H -#define ZIP7_INC_REGISTER_ARC_H - -#include "../Archive/IArchive.h" - -struct CArcInfo -{ - UInt32 Flags; - Byte Id; - Byte SignatureSize; - UInt16 SignatureOffset; - - const Byte *Signature; - const char *Name; - const char *Ext; - const char *AddExt; - - UInt32 TimeFlags; - - Func_CreateInArchive CreateInArchive; - Func_CreateOutArchive CreateOutArchive; - Func_IsArc IsArc; - - bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; } -}; - -void RegisterArc(const CArcInfo *arcInfo) throw(); - - -#define IMP_CreateArcIn_2(c) \ - static IInArchive *CreateArc() { return new c; } - -#define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler()) - -#ifdef Z7_EXTRACT_ONLY - #define IMP_CreateArcOut - #define CreateArcOut NULL -#else - #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); } -#endif - -#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ - static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, tf, crIn, crOut, isArc } ; \ - -#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ - REGISTER_ARC_V (n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ - struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \ - static CRegisterArc g_RegisterArc; - - -#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \ - IMP_CreateArcIn_2(cls) \ - REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, 0, CreateArc, NULL, isArc) - -#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \ - IMP_CreateArcIn_2(cls) \ - REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, 0, CreateArc, NULL, isArc) - -#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \ - REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc) - -#define REGISTER_ARC_I_NO_SIG(n, e, ae, id, offs, flags, isArc) \ - REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc) - - -#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, tf, isArc) \ - IMP_CreateArcIn \ - IMP_CreateArcOut \ - REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) - -#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, tf, isArc) \ - IMP_CreateArcIn \ - IMP_CreateArcOut \ - REGISTER_ARC_V(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) \ - struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \ - static CRegisterArcDecSig g_RegisterArc; - -#endif +// RegisterArc.h + +#ifndef ZIP7_INC_REGISTER_ARC_H +#define ZIP7_INC_REGISTER_ARC_H + +#include "../Archive/IArchive.h" + +struct CArcInfo +{ + UInt32 Flags; + Byte Id; + Byte SignatureSize; + UInt16 SignatureOffset; + + const Byte *Signature; + const char *Name; + const char *Ext; + const char *AddExt; + + UInt32 TimeFlags; + + Func_CreateInArchive CreateInArchive; + Func_CreateOutArchive CreateOutArchive; + Func_IsArc IsArc; + + bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; } +}; + +void RegisterArc(const CArcInfo *arcInfo) throw(); + + +#define IMP_CreateArcIn_2(c) \ + static IInArchive *CreateArc() { return new c; } + +#define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler()) + +#ifdef Z7_EXTRACT_ONLY + #define IMP_CreateArcOut + #define CreateArcOut NULL +#else + #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); } +#endif + +#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ + static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, tf, crIn, crOut, isArc } ; \ + +#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ + REGISTER_ARC_V (n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ + struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \ + static CRegisterArc g_RegisterArc; + + +#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \ + IMP_CreateArcIn_2(cls) \ + REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, 0, CreateArc, NULL, isArc) + +#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \ + IMP_CreateArcIn_2(cls) \ + REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, 0, CreateArc, NULL, isArc) + +#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \ + REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc) + +#define REGISTER_ARC_I_NO_SIG(n, e, ae, id, offs, flags, isArc) \ + REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc) + + +#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, tf, isArc) \ + IMP_CreateArcIn \ + IMP_CreateArcOut \ + REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) + +#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, tf, isArc) \ + IMP_CreateArcIn \ + IMP_CreateArcOut \ + REGISTER_ARC_V(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) \ + struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \ + static CRegisterArcDecSig g_RegisterArc; + +#endif diff --git a/CPP/7zip/Common/RegisterCodec.h b/CPP/7zip/Common/RegisterCodec.h index 81a3f7991..cf94998ac 100644 --- a/CPP/7zip/Common/RegisterCodec.h +++ b/CPP/7zip/Common/RegisterCodec.h @@ -1,106 +1,106 @@ -// RegisterCodec.h - -#ifndef ZIP7_INC_REGISTER_CODEC_H -#define ZIP7_INC_REGISTER_CODEC_H - -#include "../Common/MethodId.h" - -#include "../ICoder.h" - -typedef void * (*CreateCodecP)(); - -struct CCodecInfo -{ - CreateCodecP CreateDecoder; - CreateCodecP CreateEncoder; - CMethodId Id; - const char *Name; - UInt32 NumStreams; - bool IsFilter; -}; - -void RegisterCodec(const CCodecInfo *codecInfo) throw(); - - -#define REGISTER_CODEC_CREATE_2(name, cls, i) static void *name() { return (void *)(i *)(new cls); } -#define REGISTER_CODEC_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressCoder) - -#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x -#define REGISTER_CODEC_VAR(x) static const CCodecInfo g_CodecInfo_ ## x = - -#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \ - REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo_ ## x); }}; \ - static REGISTER_CODEC_NAME(x) g_RegisterCodec_ ## x; - - -#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x -#define REGISTER_CODECS_VAR static const CCodecInfo g_CodecsInfo[] = - -#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \ - REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CodecsInfo); i++) \ - RegisterCodec(&g_CodecsInfo[i]); }}; \ - static REGISTER_CODECS_NAME(x) g_RegisterCodecs; - - -#define REGISTER_CODEC_2(x, crDec, crEnc, id, name) \ - REGISTER_CODEC_VAR(x) \ - { crDec, crEnc, id, name, 1, false }; \ - REGISTER_CODEC(x) - - -#ifdef Z7_EXTRACT_ONLY - #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \ - REGISTER_CODEC_CREATE(CreateDec, clsDec) \ - REGISTER_CODEC_2(x, CreateDec, NULL, id, name) -#else - #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \ - REGISTER_CODEC_CREATE(CreateDec, clsDec) \ - REGISTER_CODEC_CREATE(CreateEnc, clsEnc) \ - REGISTER_CODEC_2(x, CreateDec, CreateEnc, id, name) -#endif - - - -#define REGISTER_FILTER_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressFilter) - -#define REGISTER_FILTER_ITEM(crDec, crEnc, id, name) \ - { crDec, crEnc, id, name, 1, true } - -#define REGISTER_FILTER(x, crDec, crEnc, id, name) \ - REGISTER_CODEC_VAR(x) \ - REGISTER_FILTER_ITEM(crDec, crEnc, id, name); \ - REGISTER_CODEC(x) - -#ifdef Z7_EXTRACT_ONLY - #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \ - REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \ - REGISTER_FILTER(x, x ## _CreateDec, NULL, id, name) -#else - #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \ - REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \ - REGISTER_FILTER_CREATE(x ## _CreateEnc, clsEnc) \ - REGISTER_FILTER(x, x ## _CreateDec, x ## _CreateEnc, id, name) -#endif - - - -struct CHasherInfo -{ - IHasher * (*CreateHasher)(); - CMethodId Id; - const char *Name; - UInt32 DigestSize; -}; - -void RegisterHasher(const CHasherInfo *hasher) throw(); - -#define REGISTER_HASHER_NAME(x) CRegHasher_ ## x - -#define REGISTER_HASHER(cls, id, name, size) \ - Z7_COM7F_IMF2(UInt32, cls::GetDigestSize()) { return size; } \ - static IHasher *CreateHasherSpec() { return new cls(); } \ - static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \ - struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ - static REGISTER_HASHER_NAME(cls) g_RegisterHasher; - -#endif +// RegisterCodec.h + +#ifndef ZIP7_INC_REGISTER_CODEC_H +#define ZIP7_INC_REGISTER_CODEC_H + +#include "../Common/MethodId.h" + +#include "../ICoder.h" + +typedef void * (*CreateCodecP)(); + +struct CCodecInfo +{ + CreateCodecP CreateDecoder; + CreateCodecP CreateEncoder; + CMethodId Id; + const char *Name; + UInt32 NumStreams; + bool IsFilter; +}; + +void RegisterCodec(const CCodecInfo *codecInfo) throw(); + + +#define REGISTER_CODEC_CREATE_2(name, cls, i) static void *name() { return (void *)(i *)(new cls); } +#define REGISTER_CODEC_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressCoder) + +#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x +#define REGISTER_CODEC_VAR(x) static const CCodecInfo g_CodecInfo_ ## x = + +#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \ + REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo_ ## x); }}; \ + static REGISTER_CODEC_NAME(x) g_RegisterCodec_ ## x; + + +#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x +#define REGISTER_CODECS_VAR static const CCodecInfo g_CodecsInfo[] = + +#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \ + REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CodecsInfo); i++) \ + RegisterCodec(&g_CodecsInfo[i]); }}; \ + static REGISTER_CODECS_NAME(x) g_RegisterCodecs; + + +#define REGISTER_CODEC_2(x, crDec, crEnc, id, name) \ + REGISTER_CODEC_VAR(x) \ + { crDec, crEnc, id, name, 1, false }; \ + REGISTER_CODEC(x) + + +#ifdef Z7_EXTRACT_ONLY + #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \ + REGISTER_CODEC_CREATE(CreateDec, clsDec) \ + REGISTER_CODEC_2(x, CreateDec, NULL, id, name) +#else + #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \ + REGISTER_CODEC_CREATE(CreateDec, clsDec) \ + REGISTER_CODEC_CREATE(CreateEnc, clsEnc) \ + REGISTER_CODEC_2(x, CreateDec, CreateEnc, id, name) +#endif + + + +#define REGISTER_FILTER_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressFilter) + +#define REGISTER_FILTER_ITEM(crDec, crEnc, id, name) \ + { crDec, crEnc, id, name, 1, true } + +#define REGISTER_FILTER(x, crDec, crEnc, id, name) \ + REGISTER_CODEC_VAR(x) \ + REGISTER_FILTER_ITEM(crDec, crEnc, id, name); \ + REGISTER_CODEC(x) + +#ifdef Z7_EXTRACT_ONLY + #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \ + REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \ + REGISTER_FILTER(x, x ## _CreateDec, NULL, id, name) +#else + #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \ + REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \ + REGISTER_FILTER_CREATE(x ## _CreateEnc, clsEnc) \ + REGISTER_FILTER(x, x ## _CreateDec, x ## _CreateEnc, id, name) +#endif + + + +struct CHasherInfo +{ + IHasher * (*CreateHasher)(); + CMethodId Id; + const char *Name; + UInt32 DigestSize; +}; + +void RegisterHasher(const CHasherInfo *hasher) throw(); + +#define REGISTER_HASHER_NAME(x) CRegHasher_ ## x + +#define REGISTER_HASHER(cls, id, name, size) \ + Z7_COM7F_IMF2(UInt32, cls::GetDigestSize()) { return size; } \ + static IHasher *CreateHasherSpec() { return new cls(); } \ + static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \ + struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ + static REGISTER_HASHER_NAME(cls) g_RegisterHasher; + +#endif diff --git a/CPP/7zip/Common/StdAfx.h b/CPP/7zip/Common/StdAfx.h index aa6fe0328..80866550d 100644 --- a/CPP/7zip/Common/StdAfx.h +++ b/CPP/7zip/Common/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Common/StreamBinder.cpp b/CPP/7zip/Common/StreamBinder.cpp index 33e95e832..38334af96 100644 --- a/CPP/7zip/Common/StreamBinder.cpp +++ b/CPP/7zip/Common/StreamBinder.cpp @@ -1,151 +1,151 @@ -// StreamBinder.cpp - -#include "StdAfx.h" - -#include "../../Common/MyCom.h" - -#include "StreamBinder.h" - -Z7_CLASS_IMP_COM_1( - CBinderInStream - , ISequentialInStream -) - CStreamBinder *_binder; -public: - ~CBinderInStream() { _binder->CloseRead_CallOnce(); } - CBinderInStream(CStreamBinder *binder): _binder(binder) {} -}; - -Z7_COM7F_IMF(CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) - { return _binder->Read(data, size, processedSize); } - - -Z7_CLASS_IMP_COM_1( - CBinderOutStream - , ISequentialOutStream -) - CStreamBinder *_binder; -public: - ~CBinderOutStream() { _binder->CloseWrite(); } - CBinderOutStream(CStreamBinder *binder): _binder(binder) {} -}; - -Z7_COM7F_IMF(CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) - { return _binder->Write(data, size, processedSize); } - - -static HRESULT Event_Create_or_Reset(NWindows::NSynchronization::CAutoResetEvent &event) -{ - const WRes wres = event.CreateIfNotCreated_Reset(); - return HRESULT_FROM_WIN32(wres); -} - -HRESULT CStreamBinder::Create_ReInit() -{ - RINOK(Event_Create_or_Reset(_canRead_Event)) - // RINOK(Event_Create_or_Reset(_canWrite_Event)) - - // _canWrite_Semaphore.Close(); - // we need at least 3 items of maxCount: 1 for normal unlock in Read(), 2 items for unlock in CloseRead_CallOnce() - _canWrite_Semaphore.OptCreateInit(0, 3); - - // _readingWasClosed = false; - _readingWasClosed2 = false; - - _waitWrite = true; - _bufSize = 0; - _buf = NULL; - ProcessedSize = 0; - // WritingWasCut = false; - return S_OK; -} - - -void CStreamBinder::CreateStreams2(CMyComPtr &inStream, CMyComPtr &outStream) -{ - inStream = new CBinderInStream(this); - outStream = new CBinderOutStream(this); -} - -// (_canRead_Event && _bufSize == 0) means that stream is finished. - -HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (size != 0) - { - if (_waitWrite) - { - WRes wres = _canRead_Event.Lock(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - _waitWrite = false; - } - if (size > _bufSize) - size = _bufSize; - if (size != 0) - { - memcpy(data, _buf, size); - _buf = ((const Byte *)_buf) + size; - ProcessedSize += size; - if (processedSize) - *processedSize = size; - _bufSize -= size; - - /* - if (_bufSize == 0), then we have read whole buffer - we have two ways here: - - if we check (_bufSize == 0) here, we unlock Write only after full data Reading - it reduces the number of syncs - - if we don't check (_bufSize == 0) here, we unlock Write after partial data Reading - */ - if (_bufSize == 0) - { - _waitWrite = true; - // _canWrite_Event.Set(); - _canWrite_Semaphore.Release(); - } - } - } - return S_OK; -} - - -HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - - if (!_readingWasClosed2) - { - _buf = data; - _bufSize = size; - _canRead_Event.Set(); - - /* - _canWrite_Event.Lock(); - if (_readingWasClosed) - _readingWasClosed2 = true; - */ - - _canWrite_Semaphore.Lock(); - - // _bufSize : is remain size that was not read - size -= _bufSize; - - // size : is size of data that was read - if (size != 0) - { - // if some data was read, then we report that size and return - if (processedSize) - *processedSize = size; - return S_OK; - } - _readingWasClosed2 = true; - } - - // WritingWasCut = true; - return k_My_HRESULT_WritingWasCut; -} +// StreamBinder.cpp + +#include "StdAfx.h" + +#include "../../Common/MyCom.h" + +#include "StreamBinder.h" + +Z7_CLASS_IMP_COM_1( + CBinderInStream + , ISequentialInStream +) + CStreamBinder *_binder; +public: + ~CBinderInStream() { _binder->CloseRead_CallOnce(); } + CBinderInStream(CStreamBinder *binder): _binder(binder) {} +}; + +Z7_COM7F_IMF(CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) + { return _binder->Read(data, size, processedSize); } + + +Z7_CLASS_IMP_COM_1( + CBinderOutStream + , ISequentialOutStream +) + CStreamBinder *_binder; +public: + ~CBinderOutStream() { _binder->CloseWrite(); } + CBinderOutStream(CStreamBinder *binder): _binder(binder) {} +}; + +Z7_COM7F_IMF(CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) + { return _binder->Write(data, size, processedSize); } + + +static HRESULT Event_Create_or_Reset(NWindows::NSynchronization::CAutoResetEvent &event) +{ + const WRes wres = event.CreateIfNotCreated_Reset(); + return HRESULT_FROM_WIN32(wres); +} + +HRESULT CStreamBinder::Create_ReInit() +{ + RINOK(Event_Create_or_Reset(_canRead_Event)) + // RINOK(Event_Create_or_Reset(_canWrite_Event)) + + // _canWrite_Semaphore.Close(); + // we need at least 3 items of maxCount: 1 for normal unlock in Read(), 2 items for unlock in CloseRead_CallOnce() + _canWrite_Semaphore.OptCreateInit(0, 3); + + // _readingWasClosed = false; + _readingWasClosed2 = false; + + _waitWrite = true; + _bufSize = 0; + _buf = NULL; + ProcessedSize = 0; + // WritingWasCut = false; + return S_OK; +} + + +void CStreamBinder::CreateStreams2(CMyComPtr &inStream, CMyComPtr &outStream) +{ + inStream = new CBinderInStream(this); + outStream = new CBinderOutStream(this); +} + +// (_canRead_Event && _bufSize == 0) means that stream is finished. + +HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size != 0) + { + if (_waitWrite) + { + WRes wres = _canRead_Event.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + _waitWrite = false; + } + if (size > _bufSize) + size = _bufSize; + if (size != 0) + { + memcpy(data, _buf, size); + _buf = ((const Byte *)_buf) + size; + ProcessedSize += size; + if (processedSize) + *processedSize = size; + _bufSize -= size; + + /* + if (_bufSize == 0), then we have read whole buffer + we have two ways here: + - if we check (_bufSize == 0) here, we unlock Write only after full data Reading - it reduces the number of syncs + - if we don't check (_bufSize == 0) here, we unlock Write after partial data Reading + */ + if (_bufSize == 0) + { + _waitWrite = true; + // _canWrite_Event.Set(); + _canWrite_Semaphore.Release(); + } + } + } + return S_OK; +} + + +HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + + if (!_readingWasClosed2) + { + _buf = data; + _bufSize = size; + _canRead_Event.Set(); + + /* + _canWrite_Event.Lock(); + if (_readingWasClosed) + _readingWasClosed2 = true; + */ + + _canWrite_Semaphore.Lock(); + + // _bufSize : is remain size that was not read + size -= _bufSize; + + // size : is size of data that was read + if (size != 0) + { + // if some data was read, then we report that size and return + if (processedSize) + *processedSize = size; + return S_OK; + } + _readingWasClosed2 = true; + } + + // WritingWasCut = true; + return k_My_HRESULT_WritingWasCut; +} diff --git a/CPP/7zip/Common/StreamBinder.h b/CPP/7zip/Common/StreamBinder.h index c592f7688..c0a70793c 100644 --- a/CPP/7zip/Common/StreamBinder.h +++ b/CPP/7zip/Common/StreamBinder.h @@ -1,78 +1,78 @@ -// StreamBinder.h - -#ifndef ZIP7_INC_STREAM_BINDER_H -#define ZIP7_INC_STREAM_BINDER_H - -#include "../../Windows/Synchronization.h" - -#include "../IStream.h" - -/* -We can use one from two code versions here: with Event or with Semaphore to unlock Writer thread -The difference for cases where Reading must be closed before Writing closing - -1) Event Version: _canWrite_Event - We call _canWrite_Event.Set() without waiting _canRead_Event in CloseRead() function. - The writer thread can get (_readingWasClosed) status in one from two iterations. - It's ambiguity of processing flow. But probably it's SAFE to use, if Event functions provide memory barriers. - reader thread: - _canWrite_Event.Set(); - _readingWasClosed = true; - _canWrite_Event.Set(); - writer thread: - _canWrite_Event.Wait() - if (_readingWasClosed) - -2) Semaphore Version: _canWrite_Semaphore - writer thread always will detect closing of reading in latest iteration after all data processing iterations -*/ - -class CStreamBinder -{ - NWindows::NSynchronization::CAutoResetEvent _canRead_Event; - // NWindows::NSynchronization::CAutoResetEvent _canWrite_Event; - NWindows::NSynchronization::CSemaphore _canWrite_Semaphore; - - // bool _readingWasClosed; // set it in reader thread and check it in write thread - bool _readingWasClosed2; // use it in writer thread - // bool WritingWasCut; - bool _waitWrite; // use it in reader thread - UInt32 _bufSize; - const void *_buf; -public: - UInt64 ProcessedSize; // the size that was read by reader thread - - void CreateStreams2(CMyComPtr &inStream, CMyComPtr &outStream); - - HRESULT Create_ReInit(); - - HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); - HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize); - - void CloseRead_CallOnce() - { - // call it only once: for example, in destructor - - /* - _readingWasClosed = true; - _canWrite_Event.Set(); - */ - - /* - We must relase Semaphore only once !!! - we must release at least 2 items of Semaphore: - one item to unlock partial Write(), if Read() have read some items - then additional item to stop writing (_bufSize will be 0) - */ - _canWrite_Semaphore.Release(2); - } - - void CloseWrite() - { - _buf = NULL; - _bufSize = 0; - _canRead_Event.Set(); - } -}; - -#endif +// StreamBinder.h + +#ifndef ZIP7_INC_STREAM_BINDER_H +#define ZIP7_INC_STREAM_BINDER_H + +#include "../../Windows/Synchronization.h" + +#include "../IStream.h" + +/* +We can use one from two code versions here: with Event or with Semaphore to unlock Writer thread +The difference for cases where Reading must be closed before Writing closing + +1) Event Version: _canWrite_Event + We call _canWrite_Event.Set() without waiting _canRead_Event in CloseRead() function. + The writer thread can get (_readingWasClosed) status in one from two iterations. + It's ambiguity of processing flow. But probably it's SAFE to use, if Event functions provide memory barriers. + reader thread: + _canWrite_Event.Set(); + _readingWasClosed = true; + _canWrite_Event.Set(); + writer thread: + _canWrite_Event.Wait() + if (_readingWasClosed) + +2) Semaphore Version: _canWrite_Semaphore + writer thread always will detect closing of reading in latest iteration after all data processing iterations +*/ + +class CStreamBinder +{ + NWindows::NSynchronization::CAutoResetEvent _canRead_Event; + // NWindows::NSynchronization::CAutoResetEvent _canWrite_Event; + NWindows::NSynchronization::CSemaphore _canWrite_Semaphore; + + // bool _readingWasClosed; // set it in reader thread and check it in write thread + bool _readingWasClosed2; // use it in writer thread + // bool WritingWasCut; + bool _waitWrite; // use it in reader thread + UInt32 _bufSize; + const void *_buf; +public: + UInt64 ProcessedSize; // the size that was read by reader thread + + void CreateStreams2(CMyComPtr &inStream, CMyComPtr &outStream); + + HRESULT Create_ReInit(); + + HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); + HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize); + + void CloseRead_CallOnce() + { + // call it only once: for example, in destructor + + /* + _readingWasClosed = true; + _canWrite_Event.Set(); + */ + + /* + We must relase Semaphore only once !!! + we must release at least 2 items of Semaphore: + one item to unlock partial Write(), if Read() have read some items + then additional item to stop writing (_bufSize will be 0) + */ + _canWrite_Semaphore.Release(2); + } + + void CloseWrite() + { + _buf = NULL; + _bufSize = 0; + _canRead_Event.Set(); + } +}; + +#endif diff --git a/CPP/7zip/Common/StreamObjects.cpp b/CPP/7zip/Common/StreamObjects.cpp index 1305addb7..b54f42373 100644 --- a/CPP/7zip/Common/StreamObjects.cpp +++ b/CPP/7zip/Common/StreamObjects.cpp @@ -1,290 +1,290 @@ -// StreamObjects.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "StreamObjects.h" - -Z7_COM7F_IMF(CBufferInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_pos >= Buf.Size()) - return S_OK; - size_t rem = Buf.Size() - (size_t)_pos; - if (rem > size) - rem = (size_t)size; - memcpy(data, (const Byte *)Buf + (size_t)_pos, rem); - _pos += rem; - if (processedSize) - *processedSize = (UInt32)rem; - return S_OK; -} - -Z7_COM7F_IMF(CBufferInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _pos; break; - case STREAM_SEEK_END: offset += Buf.Size(); break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _pos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - -Z7_COM7F_IMF(CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_pos >= _size) - return S_OK; - size_t rem = _size - (size_t)_pos; - if (rem > size) - rem = (size_t)size; - memcpy(data, _data + (size_t)_pos, rem); - _pos += rem; - if (processedSize) - *processedSize = (UInt32)rem; - return S_OK; -} - -Z7_COM7F_IMF(CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _pos; break; - case STREAM_SEEK_END: offset += _size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _pos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} - -void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream) -{ - *stream = NULL; - CBufInStream *inStreamSpec = new CBufInStream; - CMyComPtr streamTemp = inStreamSpec; - inStreamSpec->Init((const Byte *)data, size, ref); - *stream = streamTemp.Detach(); -} - -void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream) -{ - *stream = NULL; - CBufferInStream *inStreamSpec = new CBufferInStream; - CMyComPtr streamTemp = inStreamSpec; - inStreamSpec->Buf.CopyFrom((const Byte *)data, size); - inStreamSpec->Init(); - *stream = streamTemp.Detach(); -} - -void CByteDynBuffer::Free() throw() -{ - MyFree(_buf); - _buf = NULL; - _capacity = 0; -} - -bool CByteDynBuffer::EnsureCapacity(size_t cap) throw() -{ - if (cap <= _capacity) - return true; - const size_t cap2 = _capacity + _capacity / 4; - if (cap < cap2) - cap = cap2; - Byte *buf = (Byte *)MyRealloc(_buf, cap); - if (!buf) - return false; - _buf = buf; - _capacity = cap; - return true; -} - -Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) -{ - addSize += _size; - if (addSize < _size) - return NULL; - if (!_buffer.EnsureCapacity(addSize)) - return NULL; - return (Byte *)_buffer + _size; -} - -void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const -{ - dest.CopyFrom((const Byte *)_buffer, _size); -} - -Z7_COM7F_IMF(CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - Byte *buf = GetBufPtrForWriting(size); - if (!buf) - return E_OUTOFMEMORY; - memcpy(buf, data, size); - UpdateSize(size); - if (processedSize) - *processedSize = size; - return S_OK; -} - -Z7_COM7F_IMF(CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - size_t rem = _size - _pos; - if (rem > size) - rem = (size_t)size; - if (rem != 0) - { - memcpy(_buffer + _pos, data, rem); - _pos += rem; - } - if (processedSize) - *processedSize = (UInt32)rem; - return (rem != 0 || size == 0) ? S_OK : E_FAIL; -} - -Z7_COM7F_IMF(CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize; - HRESULT result = _stream->Write(data, size, &realProcessedSize); - _size += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return result; -} - -static const UInt64 kEmptyTag = (UInt64)(Int64)-1; - -void CCachedInStream::Free() throw() -{ - MyFree(_tags); - _tags = NULL; - MidFree(_data); - _data = NULL; -} - -bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw() -{ - unsigned sizeLog = blockSizeLog + numBlocksLog; - if (sizeLog >= sizeof(size_t) * 8) - return false; - size_t dataSize = (size_t)1 << sizeLog; - if (!_data || dataSize != _dataSize) - { - MidFree(_data); - _data = (Byte *)MidAlloc(dataSize); - if (!_data) - return false; - _dataSize = dataSize; - } - if (!_tags || numBlocksLog != _numBlocksLog) - { - MyFree(_tags); - _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); - if (!_tags) - return false; - _numBlocksLog = numBlocksLog; - } - _blockSizeLog = blockSizeLog; - return true; -} - -void CCachedInStream::Init(UInt64 size) throw() -{ - _size = size; - _pos = 0; - const size_t numBlocks = (size_t)1 << _numBlocksLog; - for (size_t i = 0; i < numBlocks; i++) - _tags[i] = kEmptyTag; -} - -Z7_COM7F_IMF(CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_pos >= _size) - return S_OK; - - { - const UInt64 rem = _size - _pos; - if (size > rem) - size = (UInt32)rem; - } - - while (size != 0) - { - const UInt64 cacheTag = _pos >> _blockSizeLog; - const size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); - Byte *p = _data + (cacheIndex << _blockSizeLog); - - if (_tags[cacheIndex] != cacheTag) - { - _tags[cacheIndex] = kEmptyTag; - const UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); - size_t blockSize = (size_t)1 << _blockSizeLog; - if (blockSize > remInBlock) - blockSize = (size_t)remInBlock; - - RINOK(ReadBlock(cacheTag, p, blockSize)) - - _tags[cacheIndex] = cacheTag; - } - - const size_t kBlockSize = (size_t)1 << _blockSizeLog; - const size_t offset = (size_t)_pos & (kBlockSize - 1); - UInt32 cur = size; - const size_t rem = kBlockSize - offset; - if (cur > rem) - cur = (UInt32)rem; - - memcpy(data, p + offset, cur); - - if (processedSize) - *processedSize += cur; - data = (void *)((const Byte *)data + cur); - _pos += cur; - size -= cur; - } - - return S_OK; -} - - -Z7_COM7F_IMF(CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - switch (seekOrigin) - { - case STREAM_SEEK_SET: break; - case STREAM_SEEK_CUR: offset += _pos; break; - case STREAM_SEEK_END: offset += _size; break; - default: return STG_E_INVALIDFUNCTION; - } - if (offset < 0) - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - _pos = (UInt64)offset; - if (newPosition) - *newPosition = (UInt64)offset; - return S_OK; -} +// StreamObjects.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "StreamObjects.h" + +Z7_COM7F_IMF(CBufferInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_pos >= Buf.Size()) + return S_OK; + size_t rem = Buf.Size() - (size_t)_pos; + if (rem > size) + rem = (size_t)size; + memcpy(data, (const Byte *)Buf + (size_t)_pos, rem); + _pos += rem; + if (processedSize) + *processedSize = (UInt32)rem; + return S_OK; +} + +Z7_COM7F_IMF(CBufferInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _pos; break; + case STREAM_SEEK_END: offset += Buf.Size(); break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _pos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + +Z7_COM7F_IMF(CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_pos >= _size) + return S_OK; + size_t rem = _size - (size_t)_pos; + if (rem > size) + rem = (size_t)size; + memcpy(data, _data + (size_t)_pos, rem); + _pos += rem; + if (processedSize) + *processedSize = (UInt32)rem; + return S_OK; +} + +Z7_COM7F_IMF(CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _pos; break; + case STREAM_SEEK_END: offset += _size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _pos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} + +void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream) +{ + *stream = NULL; + CBufInStream *inStreamSpec = new CBufInStream; + CMyComPtr streamTemp = inStreamSpec; + inStreamSpec->Init((const Byte *)data, size, ref); + *stream = streamTemp.Detach(); +} + +void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream) +{ + *stream = NULL; + CBufferInStream *inStreamSpec = new CBufferInStream; + CMyComPtr streamTemp = inStreamSpec; + inStreamSpec->Buf.CopyFrom((const Byte *)data, size); + inStreamSpec->Init(); + *stream = streamTemp.Detach(); +} + +void CByteDynBuffer::Free() throw() +{ + MyFree(_buf); + _buf = NULL; + _capacity = 0; +} + +bool CByteDynBuffer::EnsureCapacity(size_t cap) throw() +{ + if (cap <= _capacity) + return true; + const size_t cap2 = _capacity + _capacity / 4; + if (cap < cap2) + cap = cap2; + Byte *buf = (Byte *)MyRealloc(_buf, cap); + if (!buf) + return false; + _buf = buf; + _capacity = cap; + return true; +} + +Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize) +{ + addSize += _size; + if (addSize < _size) + return NULL; + if (!_buffer.EnsureCapacity(addSize)) + return NULL; + return (Byte *)_buffer + _size; +} + +void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const +{ + dest.CopyFrom((const Byte *)_buffer, _size); +} + +Z7_COM7F_IMF(CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + Byte *buf = GetBufPtrForWriting(size); + if (!buf) + return E_OUTOFMEMORY; + memcpy(buf, data, size); + UpdateSize(size); + if (processedSize) + *processedSize = size; + return S_OK; +} + +Z7_COM7F_IMF(CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + size_t rem = _size - _pos; + if (rem > size) + rem = (size_t)size; + if (rem != 0) + { + memcpy(_buffer + _pos, data, rem); + _pos += rem; + } + if (processedSize) + *processedSize = (UInt32)rem; + return (rem != 0 || size == 0) ? S_OK : E_FAIL; +} + +Z7_COM7F_IMF(CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize; + HRESULT result = _stream->Write(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return result; +} + +static const UInt64 kEmptyTag = (UInt64)(Int64)-1; + +void CCachedInStream::Free() throw() +{ + MyFree(_tags); + _tags = NULL; + MidFree(_data); + _data = NULL; +} + +bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw() +{ + unsigned sizeLog = blockSizeLog + numBlocksLog; + if (sizeLog >= sizeof(size_t) * 8) + return false; + size_t dataSize = (size_t)1 << sizeLog; + if (!_data || dataSize != _dataSize) + { + MidFree(_data); + _data = (Byte *)MidAlloc(dataSize); + if (!_data) + return false; + _dataSize = dataSize; + } + if (!_tags || numBlocksLog != _numBlocksLog) + { + MyFree(_tags); + _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog); + if (!_tags) + return false; + _numBlocksLog = numBlocksLog; + } + _blockSizeLog = blockSizeLog; + return true; +} + +void CCachedInStream::Init(UInt64 size) throw() +{ + _size = size; + _pos = 0; + const size_t numBlocks = (size_t)1 << _numBlocksLog; + for (size_t i = 0; i < numBlocks; i++) + _tags[i] = kEmptyTag; +} + +Z7_COM7F_IMF(CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (_pos >= _size) + return S_OK; + + { + const UInt64 rem = _size - _pos; + if (size > rem) + size = (UInt32)rem; + } + + while (size != 0) + { + const UInt64 cacheTag = _pos >> _blockSizeLog; + const size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1); + Byte *p = _data + (cacheIndex << _blockSizeLog); + + if (_tags[cacheIndex] != cacheTag) + { + _tags[cacheIndex] = kEmptyTag; + const UInt64 remInBlock = _size - (cacheTag << _blockSizeLog); + size_t blockSize = (size_t)1 << _blockSizeLog; + if (blockSize > remInBlock) + blockSize = (size_t)remInBlock; + + RINOK(ReadBlock(cacheTag, p, blockSize)) + + _tags[cacheIndex] = cacheTag; + } + + const size_t kBlockSize = (size_t)1 << _blockSizeLog; + const size_t offset = (size_t)_pos & (kBlockSize - 1); + UInt32 cur = size; + const size_t rem = kBlockSize - offset; + if (cur > rem) + cur = (UInt32)rem; + + memcpy(data, p + offset, cur); + + if (processedSize) + *processedSize += cur; + data = (void *)((const Byte *)data + cur); + _pos += cur; + size -= cur; + } + + return S_OK; +} + + +Z7_COM7F_IMF(CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + switch (seekOrigin) + { + case STREAM_SEEK_SET: break; + case STREAM_SEEK_CUR: offset += _pos; break; + case STREAM_SEEK_END: offset += _size; break; + default: return STG_E_INVALIDFUNCTION; + } + if (offset < 0) + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + _pos = (UInt64)offset; + if (newPosition) + *newPosition = (UInt64)offset; + return S_OK; +} diff --git a/CPP/7zip/Common/StreamObjects.h b/CPP/7zip/Common/StreamObjects.h index f221e2946..2c0ebea9d 100644 --- a/CPP/7zip/Common/StreamObjects.h +++ b/CPP/7zip/Common/StreamObjects.h @@ -1,146 +1,146 @@ -// StreamObjects.h - -#ifndef ZIP7_INC_STREAM_OBJECTS_H -#define ZIP7_INC_STREAM_OBJECTS_H - -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" -#include "../../Common/MyVector.h" - -#include "../IStream.h" - -Z7_CLASS_IMP_IInStream( - CBufferInStream -) - UInt64 _pos; -public: - CByteBuffer Buf; - void Init() { _pos = 0; } -}; - - -Z7_CLASS_IMP_COM_0( - CReferenceBuf -) -public: - CByteBuffer Buf; -}; - - -Z7_CLASS_IMP_IInStream( - CBufInStream -) - const Byte *_data; - UInt64 _pos; - size_t _size; - CMyComPtr _ref; -public: - void Init(const Byte *data, size_t size, IUnknown *ref = NULL) - { - _data = data; - _size = size; - _pos = 0; - _ref = ref; - } - void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); } - - // Seek() is allowed here. So reading order could be changed - bool WasFinished() const { return _pos == _size; } -}; - - -void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream); -void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream); -inline void Create_BufInStream_WithNewBuffer(const CByteBuffer &buf, ISequentialInStream **stream) - { Create_BufInStream_WithNewBuffer(buf, buf.Size(), stream); } - - -class CByteDynBuffer Z7_final -{ - size_t _capacity; - Byte *_buf; - Z7_CLASS_NO_COPY(CByteDynBuffer) -public: - CByteDynBuffer(): _capacity(0), _buf(NULL) {} - // there is no copy constructor. So don't copy this object. - ~CByteDynBuffer() { Free(); } - void Free() throw(); - size_t GetCapacity() const { return _capacity; } - operator Byte*() const { return _buf; } - operator const Byte*() const { return _buf; } - bool EnsureCapacity(size_t capacity) throw(); -}; - - -Z7_CLASS_IMP_COM_1( - CDynBufSeqOutStream - , ISequentialOutStream -) - CByteDynBuffer _buffer; - size_t _size; -public: - CDynBufSeqOutStream(): _size(0) {} - void Init() { _size = 0; } - size_t GetSize() const { return _size; } - const Byte *GetBuffer() const { return _buffer; } - void CopyToBuffer(CByteBuffer &dest) const; - Byte *GetBufPtrForWriting(size_t addSize); - void UpdateSize(size_t addSize) { _size += addSize; } -}; - - -Z7_CLASS_IMP_COM_1( - CBufPtrSeqOutStream - , ISequentialOutStream -) - Byte *_buffer; - size_t _size; - size_t _pos; -public: - void Init(Byte *buffer, size_t size) - { - _buffer = buffer; - _pos = 0; - _size = size; - } - size_t GetPos() const { return _pos; } -}; - - -Z7_CLASS_IMP_COM_1( - CSequentialOutStreamSizeCount - , ISequentialOutStream -) - CMyComPtr _stream; - UInt64 _size; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void Init() { _size = 0; } - UInt64 GetSize() const { return _size; } -}; - - -class CCachedInStream: - public IInStream, - public CMyUnknownImp -{ - Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) - - UInt64 *_tags; - Byte *_data; - size_t _dataSize; - unsigned _blockSizeLog; - unsigned _numBlocksLog; - UInt64 _size; - UInt64 _pos; -protected: - virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0; -public: - CCachedInStream(): _tags(NULL), _data(NULL) {} - virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (Release() calls it) !!! - void Free() throw(); - bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw(); - void Init(UInt64 size) throw(); -}; - -#endif +// StreamObjects.h + +#ifndef ZIP7_INC_STREAM_OBJECTS_H +#define ZIP7_INC_STREAM_OBJECTS_H + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyVector.h" + +#include "../IStream.h" + +Z7_CLASS_IMP_IInStream( + CBufferInStream +) + UInt64 _pos; +public: + CByteBuffer Buf; + void Init() { _pos = 0; } +}; + + +Z7_CLASS_IMP_COM_0( + CReferenceBuf +) +public: + CByteBuffer Buf; +}; + + +Z7_CLASS_IMP_IInStream( + CBufInStream +) + const Byte *_data; + UInt64 _pos; + size_t _size; + CMyComPtr _ref; +public: + void Init(const Byte *data, size_t size, IUnknown *ref = NULL) + { + _data = data; + _size = size; + _pos = 0; + _ref = ref; + } + void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); } + + // Seek() is allowed here. So reading order could be changed + bool WasFinished() const { return _pos == _size; } +}; + + +void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream); +void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream); +inline void Create_BufInStream_WithNewBuffer(const CByteBuffer &buf, ISequentialInStream **stream) + { Create_BufInStream_WithNewBuffer(buf, buf.Size(), stream); } + + +class CByteDynBuffer Z7_final +{ + size_t _capacity; + Byte *_buf; + Z7_CLASS_NO_COPY(CByteDynBuffer) +public: + CByteDynBuffer(): _capacity(0), _buf(NULL) {} + // there is no copy constructor. So don't copy this object. + ~CByteDynBuffer() { Free(); } + void Free() throw(); + size_t GetCapacity() const { return _capacity; } + operator Byte*() const { return _buf; } + operator const Byte*() const { return _buf; } + bool EnsureCapacity(size_t capacity) throw(); +}; + + +Z7_CLASS_IMP_COM_1( + CDynBufSeqOutStream + , ISequentialOutStream +) + CByteDynBuffer _buffer; + size_t _size; +public: + CDynBufSeqOutStream(): _size(0) {} + void Init() { _size = 0; } + size_t GetSize() const { return _size; } + const Byte *GetBuffer() const { return _buffer; } + void CopyToBuffer(CByteBuffer &dest) const; + Byte *GetBufPtrForWriting(size_t addSize); + void UpdateSize(size_t addSize) { _size += addSize; } +}; + + +Z7_CLASS_IMP_COM_1( + CBufPtrSeqOutStream + , ISequentialOutStream +) + Byte *_buffer; + size_t _size; + size_t _pos; +public: + void Init(Byte *buffer, size_t size) + { + _buffer = buffer; + _pos = 0; + _size = size; + } + size_t GetPos() const { return _pos; } +}; + + +Z7_CLASS_IMP_COM_1( + CSequentialOutStreamSizeCount + , ISequentialOutStream +) + CMyComPtr _stream; + UInt64 _size; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void Init() { _size = 0; } + UInt64 GetSize() const { return _size; } +}; + + +class CCachedInStream: + public IInStream, + public CMyUnknownImp +{ + Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) + + UInt64 *_tags; + Byte *_data; + size_t _dataSize; + unsigned _blockSizeLog; + unsigned _numBlocksLog; + UInt64 _size; + UInt64 _pos; +protected: + virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0; +public: + CCachedInStream(): _tags(NULL), _data(NULL) {} + virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (Release() calls it) !!! + void Free() throw(); + bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw(); + void Init(UInt64 size) throw(); +}; + +#endif diff --git a/CPP/7zip/Common/StreamUtils.cpp b/CPP/7zip/Common/StreamUtils.cpp index 300c83cd9..24eed36c5 100644 --- a/CPP/7zip/Common/StreamUtils.cpp +++ b/CPP/7zip/Common/StreamUtils.cpp @@ -1,101 +1,101 @@ -// StreamUtils.cpp - -#include "StdAfx.h" - -#include "../../Common/MyCom.h" - -#include "StreamUtils.h" - -static const UInt32 kBlockSize = ((UInt32)1 << 31); - - -HRESULT InStream_SeekToBegin(IInStream *stream) throw() -{ - return InStream_SeekSet(stream, 0); -} - - -HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &sizeRes) throw() -{ -#ifdef _WIN32 - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamGetSize, - streamGetSize, stream) - if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK) - return S_OK; - } -#endif - const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes); - const HRESULT hres2 = InStream_SeekToBegin(stream); - return hres != S_OK ? hres : hres2; -} - - -HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw() -{ - RINOK(InStream_GetPos(stream, curPosRes)) -#ifdef _WIN32 - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamGetSize, - streamGetSize, stream) - if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK) - return S_OK; - } -#endif - const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes); - const HRESULT hres2 = InStream_SeekSet(stream, curPosRes); - return hres != S_OK ? hres : hres2; -} - - - -HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw() -{ - size_t size = *processedSize; - *processedSize = 0; - while (size != 0) - { - UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; - UInt32 processedSizeLoc; - HRESULT res = stream->Read(data, curSize, &processedSizeLoc); - *processedSize += processedSizeLoc; - data = (void *)((Byte *)data + processedSizeLoc); - size -= processedSizeLoc; - RINOK(res) - if (processedSizeLoc == 0) - return S_OK; - } - return S_OK; -} - -HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw() -{ - size_t processedSize = size; - RINOK(ReadStream(stream, data, &processedSize)) - return (size == processedSize) ? S_OK : S_FALSE; -} - -HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw() -{ - size_t processedSize = size; - RINOK(ReadStream(stream, data, &processedSize)) - return (size == processedSize) ? S_OK : E_FAIL; -} - -HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw() -{ - while (size != 0) - { - UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; - UInt32 processedSizeLoc; - HRESULT res = stream->Write(data, curSize, &processedSizeLoc); - data = (const void *)((const Byte *)data + processedSizeLoc); - size -= processedSizeLoc; - RINOK(res) - if (processedSizeLoc == 0) - return E_FAIL; - } - return S_OK; -} +// StreamUtils.cpp + +#include "StdAfx.h" + +#include "../../Common/MyCom.h" + +#include "StreamUtils.h" + +static const UInt32 kBlockSize = ((UInt32)1 << 31); + + +HRESULT InStream_SeekToBegin(IInStream *stream) throw() +{ + return InStream_SeekSet(stream, 0); +} + + +HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &sizeRes) throw() +{ +#ifdef _WIN32 + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamGetSize, + streamGetSize, stream) + if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK) + return S_OK; + } +#endif + const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes); + const HRESULT hres2 = InStream_SeekToBegin(stream); + return hres != S_OK ? hres : hres2; +} + + +HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw() +{ + RINOK(InStream_GetPos(stream, curPosRes)) +#ifdef _WIN32 + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamGetSize, + streamGetSize, stream) + if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK) + return S_OK; + } +#endif + const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes); + const HRESULT hres2 = InStream_SeekSet(stream, curPosRes); + return hres != S_OK ? hres : hres2; +} + + + +HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw() +{ + size_t size = *processedSize; + *processedSize = 0; + while (size != 0) + { + UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; + UInt32 processedSizeLoc; + HRESULT res = stream->Read(data, curSize, &processedSizeLoc); + *processedSize += processedSizeLoc; + data = (void *)((Byte *)data + processedSizeLoc); + size -= processedSizeLoc; + RINOK(res) + if (processedSizeLoc == 0) + return S_OK; + } + return S_OK; +} + +HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw() +{ + size_t processedSize = size; + RINOK(ReadStream(stream, data, &processedSize)) + return (size == processedSize) ? S_OK : S_FALSE; +} + +HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw() +{ + size_t processedSize = size; + RINOK(ReadStream(stream, data, &processedSize)) + return (size == processedSize) ? S_OK : E_FAIL; +} + +HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw() +{ + while (size != 0) + { + UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize; + UInt32 processedSizeLoc; + HRESULT res = stream->Write(data, curSize, &processedSizeLoc); + data = (const void *)((const Byte *)data + processedSizeLoc); + size -= processedSizeLoc; + RINOK(res) + if (processedSizeLoc == 0) + return E_FAIL; + } + return S_OK; +} diff --git a/CPP/7zip/Common/StreamUtils.h b/CPP/7zip/Common/StreamUtils.h index c429a0115..35a62ed3e 100644 --- a/CPP/7zip/Common/StreamUtils.h +++ b/CPP/7zip/Common/StreamUtils.h @@ -1,31 +1,31 @@ -// StreamUtils.h - -#ifndef ZIP7_INC_STREAM_UTILS_H -#define ZIP7_INC_STREAM_UTILS_H - -#include "../IStream.h" - -inline HRESULT InStream_SeekSet(IInStream *stream, UInt64 offset) throw() - { return stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL); } -inline HRESULT InStream_GetPos(IInStream *stream, UInt64 &curPosRes) throw() - { return stream->Seek(0, STREAM_SEEK_CUR, &curPosRes); } -inline HRESULT InStream_GetSize_SeekToEnd(IInStream *stream, UInt64 &sizeRes) throw() - { return stream->Seek(0, STREAM_SEEK_END, &sizeRes); } - -HRESULT InStream_SeekToBegin(IInStream *stream) throw(); -HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &size) throw(); -HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw(); - -inline HRESULT InStream_GetSize_SeekToBegin(IInStream *stream, UInt64 &sizeRes) throw() -{ - RINOK(InStream_SeekToBegin(stream)) - return InStream_AtBegin_GetSize(stream, sizeRes); -} - - -HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw(); -HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw(); -HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw(); -HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw(); - -#endif +// StreamUtils.h + +#ifndef ZIP7_INC_STREAM_UTILS_H +#define ZIP7_INC_STREAM_UTILS_H + +#include "../IStream.h" + +inline HRESULT InStream_SeekSet(IInStream *stream, UInt64 offset) throw() + { return stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL); } +inline HRESULT InStream_GetPos(IInStream *stream, UInt64 &curPosRes) throw() + { return stream->Seek(0, STREAM_SEEK_CUR, &curPosRes); } +inline HRESULT InStream_GetSize_SeekToEnd(IInStream *stream, UInt64 &sizeRes) throw() + { return stream->Seek(0, STREAM_SEEK_END, &sizeRes); } + +HRESULT InStream_SeekToBegin(IInStream *stream) throw(); +HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &size) throw(); +HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw(); + +inline HRESULT InStream_GetSize_SeekToBegin(IInStream *stream, UInt64 &sizeRes) throw() +{ + RINOK(InStream_SeekToBegin(stream)) + return InStream_AtBegin_GetSize(stream, sizeRes); +} + + +HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw(); +HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw(); +HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw(); +HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw(); + +#endif diff --git a/CPP/7zip/Common/UniqBlocks.cpp b/CPP/7zip/Common/UniqBlocks.cpp index a8fee9027..32dc27626 100644 --- a/CPP/7zip/Common/UniqBlocks.cpp +++ b/CPP/7zip/Common/UniqBlocks.cpp @@ -1,57 +1,57 @@ -// UniqBlocks.cpp - -#include "StdAfx.h" - -#include - -#include "UniqBlocks.h" - -unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size) -{ - unsigned left = 0, right = Sorted.Size(); - while (left != right) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned index = Sorted[mid]; - const CByteBuffer &buf = Bufs[index]; - const size_t sizeMid = buf.Size(); - if (size < sizeMid) - right = mid; - else if (size > sizeMid) - left = mid + 1; - else - { - if (size == 0) - return index; - const int cmp = memcmp(data, buf, size); - if (cmp == 0) - return index; - if (cmp < 0) - right = mid; - else - left = mid + 1; - } - } - unsigned index = Bufs.Size(); - Sorted.Insert(left, index); - Bufs.AddNew().CopyFrom(data, size); - return index; -} - -UInt64 CUniqBlocks::GetTotalSizeInBytes() const -{ - UInt64 size = 0; - FOR_VECTOR (i, Bufs) - size += Bufs[i].Size(); - return size; -} - -void CUniqBlocks::GetReverseMap() -{ - unsigned num = Sorted.Size(); - BufIndexToSortedIndex.ClearAndSetSize(num); - unsigned *p = &BufIndexToSortedIndex[0]; - const unsigned *sorted = &Sorted[0]; - for (unsigned i = 0; i < num; i++) - p[sorted[i]] = i; -} +// UniqBlocks.cpp + +#include "StdAfx.h" + +#include + +#include "UniqBlocks.h" + +unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size) +{ + unsigned left = 0, right = Sorted.Size(); + while (left != right) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned index = Sorted[mid]; + const CByteBuffer &buf = Bufs[index]; + const size_t sizeMid = buf.Size(); + if (size < sizeMid) + right = mid; + else if (size > sizeMid) + left = mid + 1; + else + { + if (size == 0) + return index; + const int cmp = memcmp(data, buf, size); + if (cmp == 0) + return index; + if (cmp < 0) + right = mid; + else + left = mid + 1; + } + } + unsigned index = Bufs.Size(); + Sorted.Insert(left, index); + Bufs.AddNew().CopyFrom(data, size); + return index; +} + +UInt64 CUniqBlocks::GetTotalSizeInBytes() const +{ + UInt64 size = 0; + FOR_VECTOR (i, Bufs) + size += Bufs[i].Size(); + return size; +} + +void CUniqBlocks::GetReverseMap() +{ + unsigned num = Sorted.Size(); + BufIndexToSortedIndex.ClearAndSetSize(num); + unsigned *p = &BufIndexToSortedIndex[0]; + const unsigned *sorted = &Sorted[0]; + for (unsigned i = 0; i < num; i++) + p[sorted[i]] = i; +} diff --git a/CPP/7zip/Common/UniqBlocks.h b/CPP/7zip/Common/UniqBlocks.h index 261734225..66c7fa21b 100644 --- a/CPP/7zip/Common/UniqBlocks.h +++ b/CPP/7zip/Common/UniqBlocks.h @@ -1,41 +1,41 @@ -// UniqBlocks.h - -#ifndef ZIP7_INC_UNIQ_BLOCKS_H -#define ZIP7_INC_UNIQ_BLOCKS_H - -#include "../../Common/MyBuffer.h" -#include "../../Common/MyString.h" - -struct C_UInt32_UString_Map -{ - CRecordVector Numbers; - UStringVector Strings; - - void Add_UInt32(const UInt32 n) - { - Numbers.AddToUniqueSorted(n); - } - int Find(const UInt32 n) - { - return Numbers.FindInSorted(n); - } -}; - - -struct CUniqBlocks -{ - CObjectVector Bufs; - CUIntVector Sorted; - CUIntVector BufIndexToSortedIndex; - - unsigned AddUniq(const Byte *data, size_t size); - UInt64 GetTotalSizeInBytes() const; - void GetReverseMap(); - - bool IsOnlyEmpty() const - { - return (Bufs.Size() == 0 || (Bufs.Size() == 1 && Bufs[0].Size() == 0)); - } -}; - -#endif +// UniqBlocks.h + +#ifndef ZIP7_INC_UNIQ_BLOCKS_H +#define ZIP7_INC_UNIQ_BLOCKS_H + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyString.h" + +struct C_UInt32_UString_Map +{ + CRecordVector Numbers; + UStringVector Strings; + + void Add_UInt32(const UInt32 n) + { + Numbers.AddToUniqueSorted(n); + } + int Find(const UInt32 n) + { + return Numbers.FindInSorted(n); + } +}; + + +struct CUniqBlocks +{ + CObjectVector Bufs; + CUIntVector Sorted; + CUIntVector BufIndexToSortedIndex; + + unsigned AddUniq(const Byte *data, size_t size); + UInt64 GetTotalSizeInBytes() const; + void GetReverseMap(); + + bool IsOnlyEmpty() const + { + return (Bufs.Size() == 0 || (Bufs.Size() == 1 && Bufs[0].Size() == 0)); + } +}; + +#endif diff --git a/CPP/7zip/Common/VirtThread.cpp b/CPP/7zip/Common/VirtThread.cpp index 285007888..3cf7296c2 100644 --- a/CPP/7zip/Common/VirtThread.cpp +++ b/CPP/7zip/Common/VirtThread.cpp @@ -1,47 +1,47 @@ -// VirtThread.cpp - -#include "StdAfx.h" - -#include "VirtThread.h" - -static THREAD_FUNC_DECL CoderThread(void *p) -{ - for (;;) - { - CVirtThread *t = (CVirtThread *)p; - t->StartEvent.Lock(); - if (t->Exit) - return THREAD_FUNC_RET_ZERO; - t->Execute(); - t->FinishedEvent.Set(); - } -} - -WRes CVirtThread::Create() -{ - RINOK_WRes(StartEvent.CreateIfNotCreated_Reset()) - RINOK_WRes(FinishedEvent.CreateIfNotCreated_Reset()) - // StartEvent.Reset(); - // FinishedEvent.Reset(); - Exit = false; - if (Thread.IsCreated()) - return S_OK; - return Thread.Create(CoderThread, this); -} - -WRes CVirtThread::Start() -{ - Exit = false; - return StartEvent.Set(); -} - -void CVirtThread::WaitThreadFinish() -{ - Exit = true; - if (StartEvent.IsCreated()) - StartEvent.Set(); - if (Thread.IsCreated()) - { - Thread.Wait_Close(); - } -} +// VirtThread.cpp + +#include "StdAfx.h" + +#include "VirtThread.h" + +static THREAD_FUNC_DECL CoderThread(void *p) +{ + for (;;) + { + CVirtThread *t = (CVirtThread *)p; + t->StartEvent.Lock(); + if (t->Exit) + return THREAD_FUNC_RET_ZERO; + t->Execute(); + t->FinishedEvent.Set(); + } +} + +WRes CVirtThread::Create() +{ + RINOK_WRes(StartEvent.CreateIfNotCreated_Reset()) + RINOK_WRes(FinishedEvent.CreateIfNotCreated_Reset()) + // StartEvent.Reset(); + // FinishedEvent.Reset(); + Exit = false; + if (Thread.IsCreated()) + return S_OK; + return Thread.Create(CoderThread, this); +} + +WRes CVirtThread::Start() +{ + Exit = false; + return StartEvent.Set(); +} + +void CVirtThread::WaitThreadFinish() +{ + Exit = true; + if (StartEvent.IsCreated()) + StartEvent.Set(); + if (Thread.IsCreated()) + { + Thread.Wait_Close(); + } +} diff --git a/CPP/7zip/Common/VirtThread.h b/CPP/7zip/Common/VirtThread.h index 692ce1990..809b35689 100644 --- a/CPP/7zip/Common/VirtThread.h +++ b/CPP/7zip/Common/VirtThread.h @@ -1,24 +1,24 @@ -// VirtThread.h - -#ifndef ZIP7_INC_VIRT_THREAD_H -#define ZIP7_INC_VIRT_THREAD_H - -#include "../../Windows/Synchronization.h" -#include "../../Windows/Thread.h" - -struct CVirtThread -{ - NWindows::NSynchronization::CAutoResetEvent StartEvent; - NWindows::NSynchronization::CAutoResetEvent FinishedEvent; - NWindows::CThread Thread; - bool Exit; - - virtual ~CVirtThread() { WaitThreadFinish(); } - void WaitThreadFinish(); // call it in destructor of child class ! - WRes Create(); - WRes Start(); - virtual void Execute() = 0; - WRes WaitExecuteFinish() { return FinishedEvent.Lock(); } -}; - -#endif +// VirtThread.h + +#ifndef ZIP7_INC_VIRT_THREAD_H +#define ZIP7_INC_VIRT_THREAD_H + +#include "../../Windows/Synchronization.h" +#include "../../Windows/Thread.h" + +struct CVirtThread +{ + NWindows::NSynchronization::CAutoResetEvent StartEvent; + NWindows::NSynchronization::CAutoResetEvent FinishedEvent; + NWindows::CThread Thread; + bool Exit; + + virtual ~CVirtThread() { WaitThreadFinish(); } + void WaitThreadFinish(); // call it in destructor of child class ! + WRes Create(); + WRes Start(); + virtual void Execute() = 0; + WRes WaitExecuteFinish() { return FinishedEvent.Lock(); } +}; + +#endif diff --git a/CPP/7zip/Compress/BZip2Const.h b/CPP/7zip/Compress/BZip2Const.h index 18bd03317..0dfcfe546 100644 --- a/CPP/7zip/Compress/BZip2Const.h +++ b/CPP/7zip/Compress/BZip2Const.h @@ -1,71 +1,71 @@ -// Compress/BZip2Const.h - -#ifndef ZIP7_INC_COMPRESS_BZIP2_CONST_H -#define ZIP7_INC_COMPRESS_BZIP2_CONST_H - -namespace NCompress { -namespace NBZip2 { - -const Byte kArSig0 = 'B'; -const Byte kArSig1 = 'Z'; -const Byte kArSig2 = 'h'; -const Byte kArSig3 = '0'; - -const Byte kFinSig0 = 0x17; -const Byte kFinSig1 = 0x72; -const Byte kFinSig2 = 0x45; -const Byte kFinSig3 = 0x38; -const Byte kFinSig4 = 0x50; -const Byte kFinSig5 = 0x90; - -const Byte kBlockSig0 = 0x31; -const Byte kBlockSig1 = 0x41; -const Byte kBlockSig2 = 0x59; -const Byte kBlockSig3 = 0x26; -const Byte kBlockSig4 = 0x53; -const Byte kBlockSig5 = 0x59; - -const unsigned kNumOrigBits = 24; - -const unsigned kNumTablesBits = 3; -const unsigned kNumTablesMin = 2; -const unsigned kNumTablesMax = 6; - -const unsigned kNumLevelsBits = 5; - -const unsigned kMaxHuffmanLen = 20; // Check it - -const unsigned kMaxAlphaSize = 258; - -const unsigned kGroupSize = 50; - -const unsigned kBlockSizeMultMin = 1; -const unsigned kBlockSizeMultMax = 9; - -const UInt32 kBlockSizeStep = 100000; -const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep; - -const unsigned kNumSelectorsBits = 15; -const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize)); - -const unsigned kRleModeRepSize = 4; - -/* -The number of selectors stored in bzip2 block: -(numSelectors <= 18001) - must work with any decoder. -(numSelectors == 18002) - works with bzip2 1.0.6 decoder and all derived decoders. -(numSelectors > 18002) - lbzip2 2.5: encoder can write up to (18001 + 7) selectors. - - 7-Zip before 19.03: decoder doesn't support it. - 7-Zip 19.03: decoder allows 8 additional selector records for lbzip2 compatibility. - - bzip2 1.0.6: decoder can overflow selector[18002] arrays. But there are another - arrays after selector arrays. So the compiled code works. - bzip2 1.0.7: decoder doesn't support it. - bzip2 1.0.8: decoder allows additional selector records for lbzip2 compatibility. -*/ - -}} - -#endif +// Compress/BZip2Const.h + +#ifndef ZIP7_INC_COMPRESS_BZIP2_CONST_H +#define ZIP7_INC_COMPRESS_BZIP2_CONST_H + +namespace NCompress { +namespace NBZip2 { + +const Byte kArSig0 = 'B'; +const Byte kArSig1 = 'Z'; +const Byte kArSig2 = 'h'; +const Byte kArSig3 = '0'; + +const Byte kFinSig0 = 0x17; +const Byte kFinSig1 = 0x72; +const Byte kFinSig2 = 0x45; +const Byte kFinSig3 = 0x38; +const Byte kFinSig4 = 0x50; +const Byte kFinSig5 = 0x90; + +const Byte kBlockSig0 = 0x31; +const Byte kBlockSig1 = 0x41; +const Byte kBlockSig2 = 0x59; +const Byte kBlockSig3 = 0x26; +const Byte kBlockSig4 = 0x53; +const Byte kBlockSig5 = 0x59; + +const unsigned kNumOrigBits = 24; + +const unsigned kNumTablesBits = 3; +const unsigned kNumTablesMin = 2; +const unsigned kNumTablesMax = 6; + +const unsigned kNumLevelsBits = 5; + +const unsigned kMaxHuffmanLen = 20; // Check it + +const unsigned kMaxAlphaSize = 258; + +const unsigned kGroupSize = 50; + +const unsigned kBlockSizeMultMin = 1; +const unsigned kBlockSizeMultMax = 9; + +const UInt32 kBlockSizeStep = 100000; +const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep; + +const unsigned kNumSelectorsBits = 15; +const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize)); + +const unsigned kRleModeRepSize = 4; + +/* +The number of selectors stored in bzip2 block: +(numSelectors <= 18001) - must work with any decoder. +(numSelectors == 18002) - works with bzip2 1.0.6 decoder and all derived decoders. +(numSelectors > 18002) + lbzip2 2.5: encoder can write up to (18001 + 7) selectors. + + 7-Zip before 19.03: decoder doesn't support it. + 7-Zip 19.03: decoder allows 8 additional selector records for lbzip2 compatibility. + + bzip2 1.0.6: decoder can overflow selector[18002] arrays. But there are another + arrays after selector arrays. So the compiled code works. + bzip2 1.0.7: decoder doesn't support it. + bzip2 1.0.8: decoder allows additional selector records for lbzip2 compatibility. +*/ + +}} + +#endif diff --git a/CPP/7zip/Compress/BZip2Crc.cpp b/CPP/7zip/Compress/BZip2Crc.cpp index c1709170b..1c62253ff 100644 --- a/CPP/7zip/Compress/BZip2Crc.cpp +++ b/CPP/7zip/Compress/BZip2Crc.cpp @@ -1,28 +1,28 @@ -// BZip2Crc.cpp - -#include "StdAfx.h" - -#include "BZip2Crc.h" - -MY_ALIGN(64) -UInt32 CBZip2Crc::Table[256]; - -static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */ - -void CBZip2Crc::InitTable() -{ - for (UInt32 i = 0; i < 256; i++) - { - UInt32 r = i << 24; - for (unsigned j = 0; j < 8; j++) - r = (r << 1) ^ (kBZip2CrcPoly & ((UInt32)0 - (r >> 31))); - Table[i] = r; - } -} - -static -class CBZip2CrcTableInit -{ -public: - CBZip2CrcTableInit() { CBZip2Crc::InitTable(); } -} g_BZip2CrcTableInit; +// BZip2Crc.cpp + +#include "StdAfx.h" + +#include "BZip2Crc.h" + +MY_ALIGN(64) +UInt32 CBZip2Crc::Table[256]; + +static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */ + +void CBZip2Crc::InitTable() +{ + for (UInt32 i = 0; i < 256; i++) + { + UInt32 r = i << 24; + for (unsigned j = 0; j < 8; j++) + r = (r << 1) ^ (kBZip2CrcPoly & ((UInt32)0 - (r >> 31))); + Table[i] = r; + } +} + +static +class CBZip2CrcTableInit +{ +public: + CBZip2CrcTableInit() { CBZip2Crc::InitTable(); } +} g_BZip2CrcTableInit; diff --git a/CPP/7zip/Compress/BZip2Crc.h b/CPP/7zip/Compress/BZip2Crc.h index ed631d80d..10e147bc3 100644 --- a/CPP/7zip/Compress/BZip2Crc.h +++ b/CPP/7zip/Compress/BZip2Crc.h @@ -1,31 +1,31 @@ -// BZip2Crc.h - -#ifndef ZIP7_INC_BZIP2_CRC_H -#define ZIP7_INC_BZIP2_CRC_H - -#include "../../Common/MyTypes.h" - -class CBZip2Crc -{ - UInt32 _value; - static UInt32 Table[256]; -public: - static void InitTable(); - CBZip2Crc(UInt32 initVal = 0xFFFFFFFF): _value(initVal) {} - void Init(UInt32 initVal = 0xFFFFFFFF) { _value = initVal; } - void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } - void UpdateByte(unsigned b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } - UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; } -}; - -class CBZip2CombinedCrc -{ - UInt32 _value; -public: - CBZip2CombinedCrc(): _value(0) {} - void Init() { _value = 0; } - void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; } - UInt32 GetDigest() const { return _value ; } -}; - -#endif +// BZip2Crc.h + +#ifndef ZIP7_INC_BZIP2_CRC_H +#define ZIP7_INC_BZIP2_CRC_H + +#include "../../Common/MyTypes.h" + +class CBZip2Crc +{ + UInt32 _value; + static UInt32 Table[256]; +public: + static void InitTable(); + CBZip2Crc(UInt32 initVal = 0xFFFFFFFF): _value(initVal) {} + void Init(UInt32 initVal = 0xFFFFFFFF) { _value = initVal; } + void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } + void UpdateByte(unsigned b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); } + UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; } +}; + +class CBZip2CombinedCrc +{ + UInt32 _value; +public: + CBZip2CombinedCrc(): _value(0) {} + void Init() { _value = 0; } + void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; } + UInt32 GetDigest() const { return _value ; } +}; + +#endif diff --git a/CPP/7zip/Compress/BZip2Decoder.cpp b/CPP/7zip/Compress/BZip2Decoder.cpp index 6d25945a2..f44faa2e4 100644 --- a/CPP/7zip/Compress/BZip2Decoder.cpp +++ b/CPP/7zip/Compress/BZip2Decoder.cpp @@ -1,1777 +1,1777 @@ -// BZip2Decoder.cpp - -#include "StdAfx.h" - -// #include "CopyCoder.h" - -/* -#include -#include "../../../C/CpuTicks.h" -*/ -#define TICKS_START -#define TICKS_UPDATE(n) - - -/* -#define PRIN(s) printf(s "\n"); fflush(stdout); -#define PRIN_VAL(s, val) printf(s " = %u \n", val); fflush(stdout); -*/ - -#define PRIN(s) -#define PRIN_VAL(s, val) - - -#include "../../../C/Alloc.h" - -#include "../Common/StreamUtils.h" - -#include "BZip2Decoder.h" - - -namespace NCompress { -namespace NBZip2 { - -// #undef NO_INLINE -#define NO_INLINE Z7_NO_INLINE - -#define BZIP2_BYTE_MODE - - -static const UInt32 kInBufSize = (UInt32)1 << 17; -static const size_t kOutBufSize = (size_t)1 << 20; - -static const UInt32 kProgressStep = (UInt32)1 << 16; - -MY_ALIGN(64) -static const UInt16 kRandNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - - -enum EState -{ - STATE_STREAM_SIGNATURE, - STATE_BLOCK_SIGNATURE, - - STATE_BLOCK_START, - STATE_ORIG_BITS, - STATE_IN_USE, - STATE_IN_USE2, - STATE_NUM_TABLES, - STATE_NUM_SELECTORS, - STATE_SELECTORS, - STATE_LEVELS, - - STATE_BLOCK_SYMBOLS, - - STATE_STREAM_FINISHED -}; - - -#define UPDATE_VAL_2(val, num_bits) { \ - val |= (UInt32)(*_buf) << (24 - num_bits); \ - num_bits += 8; \ - _buf++; \ -} - -#define UPDATE_VAL UPDATE_VAL_2(VAL, NUM_BITS) - -#define READ_BITS(res, num) { \ - while (_numBits < num) { \ - if (_buf == _lim) return SZ_OK; \ - UPDATE_VAL_2(_value, _numBits) } \ - res = _value >> (32 - num); \ - _value <<= num; \ - _numBits -= num; \ -} - -#define READ_BITS_8(res, num) { \ - if (_numBits < num) { \ - if (_buf == _lim) return SZ_OK; \ - UPDATE_VAL_2(_value, _numBits) } \ - res = _value >> (32 - num); \ - _value <<= num; \ - _numBits -= num; \ -} - -#define READ_BIT(res) READ_BITS_8(res, 1) - - - -#define VAL _value2 -// #define NUM_BITS _numBits2 -#define NUM_BITS _numBits -#define BLOCK_SIZE blockSize2 -#define RUN_COUNTER runCounter2 - -#define LOAD_LOCAL \ - UInt32 VAL = this->_value; \ - /* unsigned NUM_BITS = this->_numBits; */ \ - UInt32 BLOCK_SIZE = this->blockSize; \ - UInt32 RUN_COUNTER = this->runCounter; \ - -#define SAVE_LOCAL \ - this->_value = VAL; \ - /* this->_numBits = NUM_BITS; */ \ - this->blockSize = BLOCK_SIZE; \ - this->runCounter = RUN_COUNTER; \ - - - -SRes CBitDecoder::ReadByte(int &b) -{ - b = -1; - READ_BITS_8(b, 8) - return SZ_OK; -} - - -NO_INLINE -SRes CBase::ReadStreamSignature2() -{ - for (;;) - { - unsigned b; - READ_BITS_8(b, 8) - - if ( (state2 == 0 && b != kArSig0) - || (state2 == 1 && b != kArSig1) - || (state2 == 2 && b != kArSig2) - || (state2 == 3 && (b <= kArSig3 || b > kArSig3 + kBlockSizeMultMax))) - return SZ_ERROR_DATA; - state2++; - - if (state2 == 4) - { - blockSizeMax = (UInt32)(b - kArSig3) * kBlockSizeStep; - CombinedCrc.Init(); - state = STATE_BLOCK_SIGNATURE; - state2 = 0; - return SZ_OK; - } - } -} - - -bool IsEndSig(const Byte *p) throw() -{ - return - p[0] == kFinSig0 && - p[1] == kFinSig1 && - p[2] == kFinSig2 && - p[3] == kFinSig3 && - p[4] == kFinSig4 && - p[5] == kFinSig5; -} - -bool IsBlockSig(const Byte *p) throw() -{ - return - p[0] == kBlockSig0 && - p[1] == kBlockSig1 && - p[2] == kBlockSig2 && - p[3] == kBlockSig3 && - p[4] == kBlockSig4 && - p[5] == kBlockSig5; -} - - -NO_INLINE -SRes CBase::ReadBlockSignature2() -{ - while (state2 < 10) - { - unsigned b; - READ_BITS_8(b, 8) - temp[state2] = (Byte)b; - state2++; - } - - crc = 0; - for (unsigned i = 0; i < 4; i++) - { - crc <<= 8; - crc |= temp[6 + i]; - } - - if (IsBlockSig(temp)) - { - if (!IsBz) - NumStreams++; - NumBlocks++; - IsBz = true; - CombinedCrc.Update(crc); - state = STATE_BLOCK_START; - return SZ_OK; - } - - if (!IsEndSig(temp)) - return SZ_ERROR_DATA; - - if (!IsBz) - NumStreams++; - IsBz = true; - - if (_value != 0) - MinorError = true; - - AlignToByte(); - - state = STATE_STREAM_FINISHED; - if (crc != CombinedCrc.GetDigest()) - { - StreamCrcError = true; - return SZ_ERROR_DATA; - } - return SZ_OK; -} - - -NO_INLINE -SRes CBase::ReadBlock2() -{ - if (state != STATE_BLOCK_SYMBOLS) { - PRIN("ReadBlock2") - - if (state == STATE_BLOCK_START) - { - if (Props.randMode) - { - READ_BIT(Props.randMode) - } - state = STATE_ORIG_BITS; - // g_Tick = GetCpuTicks(); - } - - if (state == STATE_ORIG_BITS) - { - READ_BITS(Props.origPtr, kNumOrigBits) - if (Props.origPtr >= blockSizeMax) - return SZ_ERROR_DATA; - state = STATE_IN_USE; - } - - // why original code compares origPtr to (UInt32)(10 + blockSizeMax)) ? - - if (state == STATE_IN_USE) - { - READ_BITS(state2, 16) - state = STATE_IN_USE2; - state3 = 0; - numInUse = 0; - mtf.StartInit(); - } - - if (state == STATE_IN_USE2) - { - for (; state3 < 256; state3++) - if (state2 & ((UInt32)0x8000 >> (state3 >> 4))) - { - unsigned b; - READ_BIT(b) - if (b) - mtf.Add(numInUse++, (Byte)state3); - } - if (numInUse == 0) - return SZ_ERROR_DATA; - state = STATE_NUM_TABLES; - } - - - if (state == STATE_NUM_TABLES) - { - READ_BITS_8(numTables, kNumTablesBits) - state = STATE_NUM_SELECTORS; - if (numTables < kNumTablesMin || numTables > kNumTablesMax) - return SZ_ERROR_DATA; - } - - if (state == STATE_NUM_SELECTORS) - { - READ_BITS(numSelectors, kNumSelectorsBits) - state = STATE_SELECTORS; - state2 = 0x543210; - state3 = 0; - state4 = 0; - // lbzip2 can write small number of additional selectors, - // 20.01: we allow big number of selectors here like bzip2-1.0.8 - if (numSelectors == 0 - // || numSelectors > kNumSelectorsMax_Decoder - ) - return SZ_ERROR_DATA; - } - - if (state == STATE_SELECTORS) - { - const unsigned kMtfBits = 4; - const UInt32 kMtfMask = (1 << kMtfBits) - 1; - do - { - for (;;) - { - unsigned b; - READ_BIT(b) - if (!b) - break; - if (++state4 >= numTables) - return SZ_ERROR_DATA; - } - const UInt32 tmp = (state2 >> (kMtfBits * state4)) & kMtfMask; - const UInt32 mask = ((UInt32)1 << ((state4 + 1) * kMtfBits)) - 1; - state4 = 0; - state2 = ((state2 << kMtfBits) & mask) | (state2 & ~mask) | tmp; - // 20.01: here we keep compatibility with bzip2-1.0.8 decoder: - if (state3 < kNumSelectorsMax) - selectors[state3] = (Byte)tmp; - } - while (++state3 < numSelectors); - - // we allowed additional dummy selector records filled above to support lbzip2's archives. - // but we still don't allow to use these additional dummy selectors in the code bellow - // bzip2 1.0.8 decoder also has similar restriction. - - if (numSelectors > kNumSelectorsMax) - numSelectors = kNumSelectorsMax; - - state = STATE_LEVELS; - state2 = 0; - state3 = 0; - } - - if (state == STATE_LEVELS) - { - do - { - if (state3 == 0) - { - READ_BITS_8(state3, kNumLevelsBits) - state4 = 0; - state5 = 0; - } - const unsigned alphaSize = numInUse + 2; - for (; state4 < alphaSize; state4++) - { - for (;;) - { - if (state3 < 1 || state3 > kMaxHuffmanLen) - return SZ_ERROR_DATA; - - if (state5 == 0) - { - unsigned b; - READ_BIT(b) - if (!b) - break; - } - - state5 = 1; - unsigned b; - READ_BIT(b) - - state5 = 0; - state3++; - state3 -= (b << 1); - } - lens[state4] = (Byte)state3; - state5 = 0; - } - - // 19.03: we use non-full Build() to support lbzip2 archives. - // lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen - for (unsigned i = state4; i < kMaxAlphaSize; i++) - lens[i] = 0; - if (!huffs[state2].Build(lens)) // k_BuildMode_Partial - return SZ_ERROR_DATA; - state3 = 0; - } - while (++state2 < numTables); - - { - UInt32 *counters = this->Counters; - for (unsigned i = 0; i < 256; i++) - counters[i] = 0; - } - - state = STATE_BLOCK_SYMBOLS; - - groupIndex = 0; - groupSize = kGroupSize; - runPower = 0; - runCounter = 0; - blockSize = 0; - } - - if (state != STATE_BLOCK_SYMBOLS) - return SZ_ERROR_DATA; - - // g_Ticks[3] += GetCpuTicks() - g_Tick; - - } - - { - LOAD_LOCAL - const CHuffmanDecoder *huf = &huffs[selectors[groupIndex]]; - - for (;;) - { - if (groupSize == 0) - { - if (++groupIndex >= numSelectors) - return SZ_ERROR_DATA; - huf = &huffs[selectors[groupIndex]]; - groupSize = kGroupSize; - } - - if (NUM_BITS < kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL - if (NUM_BITS < kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL - if (NUM_BITS < kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL }}} - - unsigned sym; - - #define MOV_POS(bs, len) \ - { \ - if (NUM_BITS < len) \ - { \ - SAVE_LOCAL \ - return SZ_OK; \ - } \ - VAL <<= len; \ - NUM_BITS -= (unsigned)len; \ - } - - Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huf, kMaxHuffmanLen, kNumTableBits, - VAL, - Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, - { return SZ_ERROR_DATA; }, - MOV_POS, {}, bs) - - groupSize--; - - if (sym < 2) - { - RUN_COUNTER += (UInt32)(sym + 1) << runPower; - runPower++; - if (blockSizeMax - BLOCK_SIZE < RUN_COUNTER) - return SZ_ERROR_DATA; - continue; - } - - UInt32 *counters = this->Counters; - if (RUN_COUNTER != 0) - { - UInt32 b = (UInt32)(mtf.Buf[0] & 0xFF); - counters[b] += RUN_COUNTER; - runPower = 0; - #ifdef BZIP2_BYTE_MODE - Byte *dest = (Byte *)(&counters[256 + kBlockSizeMax]) + BLOCK_SIZE; - const Byte *limit = dest + RUN_COUNTER; - BLOCK_SIZE += RUN_COUNTER; - RUN_COUNTER = 0; - do - { - dest[0] = (Byte)b; - dest[1] = (Byte)b; - dest[2] = (Byte)b; - dest[3] = (Byte)b; - dest += 4; - } - while (dest < limit); - #else - UInt32 *dest = &counters[256 + BLOCK_SIZE]; - const UInt32 *limit = dest + RUN_COUNTER; - BLOCK_SIZE += RUN_COUNTER; - RUN_COUNTER = 0; - do - { - dest[0] = b; - dest[1] = b; - dest[2] = b; - dest[3] = b; - dest += 4; - } - while (dest < limit); - #endif - } - - sym -= 1; - if (sym < numInUse) - { - if (BLOCK_SIZE >= blockSizeMax) - return SZ_ERROR_DATA; - - // UInt32 b = (UInt32)mtf.GetAndMove((unsigned)sym); - - const unsigned lim = sym >> Z7_MTF_MOVS; - const unsigned pos = (sym & Z7_MTF_MASK) << 3; - CMtfVar next = mtf.Buf[lim]; - CMtfVar prev = (next >> pos) & 0xFF; - - #ifdef BZIP2_BYTE_MODE - ((Byte *)(counters + 256 + kBlockSizeMax))[BLOCK_SIZE++] = (Byte)prev; - #else - (counters + 256)[BLOCK_SIZE++] = (UInt32)prev; - #endif - counters[prev]++; - - CMtfVar *m = mtf.Buf; - CMtfVar *mLim = m + lim; - if (lim != 0) - { - do - { - CMtfVar n0 = *m; - *m = (n0 << 8) | prev; - prev = (n0 >> (Z7_MTF_MASK << 3)); - } - while (++m != mLim); - } - - CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); - *mLim = (next & ~mask) | (((next << 8) | prev) & mask); - continue; - } - - if (sym != numInUse) - return SZ_ERROR_DATA; - break; - } - - // we write additional item that will be read in DecodeBlock1 for prefetching - #ifdef BZIP2_BYTE_MODE - ((Byte *)(Counters + 256 + kBlockSizeMax))[BLOCK_SIZE] = 0; - #else - (counters + 256)[BLOCK_SIZE] = 0; - #endif - - SAVE_LOCAL - Props.blockSize = blockSize; - state = STATE_BLOCK_SIGNATURE; - state2 = 0; - - PRIN_VAL("origPtr", Props.origPtr); - PRIN_VAL("blockSize", Props.blockSize); - - return (Props.origPtr < Props.blockSize) ? SZ_OK : SZ_ERROR_DATA; - } -} - - -NO_INLINE -static void DecodeBlock1(UInt32 *counters, UInt32 blockSize) -{ - { - UInt32 sum = 0; - for (UInt32 i = 0; i < 256; i++) - { - const UInt32 v = counters[i]; - counters[i] = sum; - sum += v; - } - } - - UInt32 *tt = counters + 256; - // Compute the T^(-1) vector - - // blockSize--; - - #ifdef BZIP2_BYTE_MODE - - unsigned c = ((const Byte *)(tt + kBlockSizeMax))[0]; - - for (UInt32 i = 0; i < blockSize; i++) - { - unsigned c1 = c; - const UInt32 pos = counters[c]; - c = ((const Byte *)(tt + kBlockSizeMax))[(size_t)i + 1]; - counters[c1] = pos + 1; - tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; - } - - /* - // last iteration without next character prefetching - { - const UInt32 pos = counters[c]; - counters[c] = pos + 1; - tt[pos] = (blockSize << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; - } - */ - - #else - - unsigned c = (unsigned)(tt[0] & 0xFF); - - for (UInt32 i = 0; i < blockSize; i++) - { - unsigned c1 = c; - const UInt32 pos = counters[c]; - c = (unsigned)(tt[(size_t)i + 1] & 0xFF); - counters[c1] = pos + 1; - tt[pos] |= (i << 8); - } - - /* - { - const UInt32 pos = counters[c]; - counters[c] = pos + 1; - tt[pos] |= (blockSize << 8); - } - */ - - #endif - - - /* - for (UInt32 i = 0; i < blockSize; i++) - { - #ifdef BZIP2_BYTE_MODE - const unsigned c = ((const Byte *)(tt + kBlockSizeMax))[i]; - const UInt32 pos = counters[c]++; - tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; - #else - const unsigned c = (unsigned)(tt[i] & 0xFF); - const UInt32 pos = counters[c]++; - tt[pos] |= (i << 8); - #endif - } - */ -} - - -void CSpecState::Init(UInt32 origPtr, unsigned randMode) throw() -{ - _tPos = _tt[_tt[origPtr] >> 8]; - _prevByte = (unsigned)(_tPos & 0xFF); - _reps = 0; - _randIndex = 0; - _randToGo = -1; - if (randMode) - { - _randIndex = 1; - _randToGo = kRandNums[0] - 2; - } - _crc.Init(); -} - - - -NO_INLINE -Byte * CSpecState::Decode(Byte *data, size_t size) throw() -{ - if (size == 0) - return data; - - unsigned prevByte = _prevByte; - int reps = _reps; - CBZip2Crc crc = _crc; - const Byte *lim = data + size; - - while (reps > 0) - { - reps--; - *data++ = (Byte)prevByte; - crc.UpdateByte(prevByte); - if (data == lim) - break; - } - - UInt32 tPos = _tPos; - UInt32 blockSize = _blockSize; - const UInt32 *tt = _tt; - - if (data != lim && blockSize) - - for (;;) - { - unsigned b = (unsigned)(tPos & 0xFF); - tPos = tt[tPos >> 8]; - blockSize--; - - if (_randToGo >= 0) - { - if (_randToGo == 0) - { - b ^= 1; - _randToGo = kRandNums[_randIndex]; - _randIndex++; - _randIndex &= 0x1FF; - } - _randToGo--; - } - - if (reps != -(int)kRleModeRepSize) - { - if (b != prevByte) - reps = 0; - reps--; - prevByte = b; - *data++ = (Byte)b; - crc.UpdateByte(b); - if (data == lim || blockSize == 0) - break; - continue; - } - - reps = (int)b; - while (reps) - { - reps--; - *data++ = (Byte)prevByte; - crc.UpdateByte(prevByte); - if (data == lim) - break; - } - if (data == lim) - break; - if (blockSize == 0) - break; - } - - if (blockSize == 1 && reps == -(int)kRleModeRepSize) - { - unsigned b = (unsigned)(tPos & 0xFF); - tPos = tt[tPos >> 8]; - blockSize--; - - if (_randToGo >= 0) - { - if (_randToGo == 0) - { - b ^= 1; - _randToGo = kRandNums[_randIndex]; - _randIndex++; - _randIndex &= 0x1FF; - } - _randToGo--; - } - - reps = (int)b; - } - - _tPos = tPos; - _prevByte = prevByte; - _reps = reps; - _crc = crc; - _blockSize = blockSize; - - return data; -} - - -HRESULT CDecoder::Flush() -{ - if (_writeRes == S_OK) - { - _writeRes = WriteStream(_outStream, _outBuf, _outPos); - _outWritten += _outPos; - _outPos = 0; - } - return _writeRes; -} - - -NO_INLINE -HRESULT CDecoder::DecodeBlock(const CBlockProps &props) -{ - _calcedBlockCrc = 0; - _blockFinished = false; - - CSpecState block; - - block._blockSize = props.blockSize; - block._tt = _counters + 256; - - block.Init(props.origPtr, props.randMode); - - for (;;) - { - Byte *data = _outBuf + _outPos; - size_t size = kOutBufSize - _outPos; - - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _outPosTotal; - if (size >= rem) - { - size = (size_t)rem; - if (size == 0) - return FinishMode ? S_FALSE : S_OK; - } - } - - TICKS_START - const size_t processed = (size_t)(block.Decode(data, size) - data); - TICKS_UPDATE(2) - - _outPosTotal += processed; - _outPos += processed; - - if (processed >= size) - { - RINOK(Flush()) - } - - if (block.Finished()) - { - _blockFinished = true; - _calcedBlockCrc = block._crc.GetDigest(); - return S_OK; - } - } -} - - -CDecoder::CDecoder(): - _outBuf(NULL), - FinishMode(false), - _outSizeDefined(false), - _counters(NULL), - _inBuf(NULL), - _inProcessed(0) -{ - #ifndef Z7_ST - MtMode = false; - NeedWaitScout = false; - // ScoutRes = S_OK; - #endif -} - - -CDecoder::~CDecoder() -{ - PRIN("\n~CDecoder()"); - - #ifndef Z7_ST - - if (Thread.IsCreated()) - { - WaitScout(); - - _block.StopScout = true; - - PRIN("\nScoutEvent.Set()"); - ScoutEvent.Set(); - - PRIN("\nThread.Wait()()"); - Thread.Wait_Close(); - PRIN("\n after Thread.Wait()()"); - - // if (ScoutRes != S_OK) throw ScoutRes; - } - - #endif - - BigFree(_counters); - MidFree(_outBuf); - MidFree(_inBuf); -} - - -HRESULT CDecoder::ReadInput() -{ - if (Base._buf != Base._lim || _inputFinished || _inputRes != S_OK) - return _inputRes; - - _inProcessed += (size_t)(Base._buf - _inBuf); - Base._buf = _inBuf; - Base._lim = _inBuf; - UInt32 size = 0; - _inputRes = Base.InStream->Read(_inBuf, kInBufSize, &size); - _inputFinished = (size == 0); - Base._lim = _inBuf + size; - return _inputRes; -} - - -void CDecoder::StartNewStream() -{ - Base.state = STATE_STREAM_SIGNATURE; - Base.state2 = 0; - Base.IsBz = false; -} - - -HRESULT CDecoder::ReadStreamSignature() -{ - for (;;) - { - RINOK(ReadInput()) - SRes res = Base.ReadStreamSignature2(); - if (res != SZ_OK) - return S_FALSE; - if (Base.state == STATE_BLOCK_SIGNATURE) - return S_OK; - if (_inputFinished) - { - Base.NeedMoreInput = true; - return S_FALSE; - } - } -} - - -HRESULT CDecoder::StartRead() -{ - StartNewStream(); - return ReadStreamSignature(); -} - - -HRESULT CDecoder::ReadBlockSignature() -{ - for (;;) - { - RINOK(ReadInput()) - - SRes res = Base.ReadBlockSignature2(); - - if (Base.state == STATE_STREAM_FINISHED) - Base.FinishedPackSize = GetInputProcessedSize(); - if (res != SZ_OK) - return S_FALSE; - if (Base.state != STATE_BLOCK_SIGNATURE) - return S_OK; - if (_inputFinished) - { - Base.NeedMoreInput = true; - return S_FALSE; - } - } -} - - -HRESULT CDecoder::ReadBlock() -{ - for (;;) - { - RINOK(ReadInput()) - - SRes res = Base.ReadBlock2(); - - if (res != SZ_OK) - return S_FALSE; - if (Base.state == STATE_BLOCK_SIGNATURE) - return S_OK; - if (_inputFinished) - { - Base.NeedMoreInput = true; - return S_FALSE; - } - } -} - - - -HRESULT CDecoder::DecodeStreams(ICompressProgressInfo *progress) -{ - { - #ifndef Z7_ST - _block.StopScout = false; - #endif - } - - RINOK(StartRead()) - - UInt64 inPrev = 0; - UInt64 outPrev = 0; - - { - #ifndef Z7_ST - CWaitScout_Releaser waitScout_Releaser(this); - - bool useMt = false; - #endif - - bool wasFinished = false; - - UInt32 crc = 0; - UInt32 nextCrc = 0; - HRESULT nextRes = S_OK; - - UInt64 packPos = 0; - - CBlockProps props; - - props.blockSize = 0; - - for (;;) - { - if (progress) - { - const UInt64 outCur = GetOutProcessedSize(); - if (packPos - inPrev >= kProgressStep || outCur - outPrev >= kProgressStep) - { - RINOK(progress->SetRatioInfo(&packPos, &outCur)) - inPrev = packPos; - outPrev = outCur; - } - } - - if (props.blockSize == 0) - if (wasFinished || nextRes != S_OK) - return nextRes; - - if ( - #ifndef Z7_ST - !useMt && - #endif - !wasFinished && Base.state == STATE_BLOCK_SIGNATURE) - { - nextRes = ReadBlockSignature(); - nextCrc = Base.crc; - packPos = GetInputProcessedSize(); - - wasFinished = true; - - if (nextRes != S_OK) - continue; - - if (Base.state == STATE_STREAM_FINISHED) - { - if (!Base.DecodeAllStreams) - { - wasFinished = true; - continue; - } - - nextRes = StartRead(); - - if (Base.NeedMoreInput) - { - if (Base.state2 == 0) - Base.NeedMoreInput = false; - wasFinished = true; - nextRes = S_OK; - continue; - } - - if (nextRes != S_OK) - continue; - - wasFinished = false; - continue; - } - - wasFinished = false; - - #ifndef Z7_ST - if (MtMode) - if (props.blockSize != 0) - { - // we start multithreading, if next block is big enough. - const UInt32 k_Mt_BlockSize_Threshold = (1 << 12); // (1 << 13) - if (props.blockSize > k_Mt_BlockSize_Threshold) - { - if (!Thread.IsCreated()) - { - PRIN("=== MT_MODE"); - RINOK(CreateThread()) - } - useMt = true; - } - } - #endif - } - - if (props.blockSize == 0) - { - crc = nextCrc; - - #ifndef Z7_ST - if (useMt) - { - PRIN("DecoderEvent.Lock()"); - { - WRes wres = DecoderEvent.Lock(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - NeedWaitScout = false; - PRIN("-- DecoderEvent.Lock()"); - props = _block.Props; - nextCrc = _block.NextCrc; - if (_block.Crc_Defined) - crc = _block.Crc; - packPos = _block.PackPos; - wasFinished = _block.WasFinished; - RINOK(_block.Res) - } - else - #endif - { - if (Base.state != STATE_BLOCK_START) - return E_FAIL; - - TICKS_START - Base.Props.randMode = 1; - RINOK(ReadBlock()) - TICKS_UPDATE(0) - - props = Base.Props; - continue; - } - } - - if (props.blockSize != 0) - { - TICKS_START - DecodeBlock1(_counters, props.blockSize); - TICKS_UPDATE(1) - } - - #ifndef Z7_ST - if (useMt && !wasFinished) - { - /* - if (props.blockSize == 0) - { - // this codes switches back to single-threadMode - useMt = false; - PRIN("=== ST_MODE"); - continue; - } - */ - - PRIN("ScoutEvent.Set()"); - { - WRes wres = ScoutEvent.Set(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - NeedWaitScout = true; - } - #endif - - if (props.blockSize == 0) - continue; - - RINOK(DecodeBlock(props)) - - if (!_blockFinished) - return nextRes; - - props.blockSize = 0; - if (_calcedBlockCrc != crc) - { - BlockCrcError = true; - return S_FALSE; - } - } - } -} - - - - -bool CDecoder::CreateInputBufer() -{ - if (!_inBuf) - { - _inBuf = (Byte *)MidAlloc(kInBufSize); - if (!_inBuf) - return false; - Base._buf = _inBuf; - Base._lim = _inBuf; - } - if (!_counters) - { - const size_t size = (256 + kBlockSizeMax) * sizeof(UInt32) - #ifdef BZIP2_BYTE_MODE - + kBlockSizeMax - #endif - + 256; - _counters = (UInt32 *)::BigAlloc(size); - if (!_counters) - return false; - Base.Counters = _counters; - } - return true; -} - - -void CDecoder::InitOutSize(const UInt64 *outSize) -{ - _outPosTotal = 0; - - _outSizeDefined = false; - _outSize = 0; - if (outSize) - { - _outSize = *outSize; - _outSizeDefined = true; - } - - BlockCrcError = false; - - Base.InitNumStreams2(); -} - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - /* - { - RINOK(SetInStream(inStream)); - RINOK(SetOutStreamSize(outSize)); - - RINOK(CopyStream(this, outStream, progress)); - return ReleaseInStream(); - } - */ - - _inputFinished = false; - _inputRes = S_OK; - _writeRes = S_OK; - - try { - - InitOutSize(outSize); - - // we can request data from InputBuffer after Code(). - // so we init InputBuffer before any function return. - - InitInputBuffer(); - - if (!CreateInputBufer()) - return E_OUTOFMEMORY; - - if (!_outBuf) - { - _outBuf = (Byte *)MidAlloc(kOutBufSize); - if (!_outBuf) - return E_OUTOFMEMORY; - } - - Base.InStream = inStream; - - // InitInputBuffer(); - - _outStream = outStream; - _outWritten = 0; - _outPos = 0; - - HRESULT res = DecodeStreams(progress); - - Flush(); - - Base.InStream = NULL; - _outStream = NULL; - - /* - if (res == S_OK) - if (FinishMode && inSize && *inSize != GetInputProcessedSize()) - res = S_FALSE; - */ - - if (res != S_OK) - return res; - - } catch(...) { return E_FAIL; } - - return _writeRes; -} - - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - FinishMode = (finishMode != 0); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = GetInStreamSize(); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) -{ - Base.AlignToByte(); - UInt32 i; - for (i = 0; i < size; i++) - { - int b; - Base.ReadByte(b); - if (b < 0) - break; - ((Byte *)data)[i] = (Byte)b; - } - if (processedSize) - *processedSize = i; - return S_OK; -} - - -#ifndef Z7_ST - -#define PRIN_MT(s) PRIN(" " s) - -// #define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; } - -static THREAD_FUNC_DECL RunScout2(void *p) { ((CDecoder *)p)->RunScout(); return 0; } - -HRESULT CDecoder::CreateThread() -{ - WRes wres = DecoderEvent.CreateIfNotCreated_Reset(); - if (wres == 0) { wres = ScoutEvent.CreateIfNotCreated_Reset(); - if (wres == 0) { wres = Thread.Create(RunScout2, this); }} - return HRESULT_FROM_WIN32(wres); -} - -void CDecoder::RunScout() -{ - for (;;) - { - { - PRIN_MT("ScoutEvent.Lock()") - WRes wres = ScoutEvent.Lock(); - PRIN_MT("-- ScoutEvent.Lock()") - if (wres != 0) - { - // ScoutRes = wres; - return; - } - } - - CBlock &block = _block; - - if (block.StopScout) - { - // ScoutRes = S_OK; - return; - } - - block.Res = S_OK; - block.WasFinished = false; - - HRESULT res = S_OK; - - try - { - UInt64 packPos = GetInputProcessedSize(); - - block.Props.blockSize = 0; - block.Crc_Defined = false; - // block.NextCrc_Defined = false; - block.NextCrc = 0; - - for (;;) - { - if (Base.state == STATE_BLOCK_SIGNATURE) - { - res = ReadBlockSignature(); - - if (res != S_OK) - break; - - if (block.Props.blockSize == 0) - { - block.Crc = Base.crc; - block.Crc_Defined = true; - } - else - { - block.NextCrc = Base.crc; - // block.NextCrc_Defined = true; - } - - continue; - } - - if (Base.state == STATE_BLOCK_START) - { - if (block.Props.blockSize != 0) - break; - - Base.Props.randMode = 1; - - res = ReadBlock(); - - PRIN_MT("-- Base.ReadBlock") - if (res != S_OK) - break; - block.Props = Base.Props; - continue; - } - - if (Base.state == STATE_STREAM_FINISHED) - { - if (!Base.DecodeAllStreams) - { - block.WasFinished = true; - break; - } - - res = StartRead(); - - if (Base.NeedMoreInput) - { - if (Base.state2 == 0) - Base.NeedMoreInput = false; - block.WasFinished = true; - res = S_OK; - break; - } - - if (res != S_OK) - break; - - if (GetInputProcessedSize() - packPos > 0) // kProgressStep - break; - continue; - } - - // throw 1; - res = E_FAIL; - break; - } - } - - catch (...) { res = E_FAIL; } - - if (res != S_OK) - { - PRIN_MT("error") - block.Res = res; - block.WasFinished = true; - } - - block.PackPos = GetInputProcessedSize(); - PRIN_MT("DecoderEvent.Set()") - WRes wres = DecoderEvent.Set(); - if (wres != 0) - { - // ScoutRes = wres; - return; - } - } -} - - -Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads)) -{ - MtMode = (numThreads > 1); - - #ifndef BZIP2_BYTE_MODE - MtMode = false; - #endif - - // MtMode = false; - return S_OK; -} - -#endif - - - -#ifndef Z7_NO_READ_FROM_CODER - - -Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) -{ - Base.InStreamRef = inStream; - Base.InStream = inStream; - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::ReleaseInStream()) -{ - Base.InStreamRef.Release(); - Base.InStream = NULL; - return S_OK; -} - - - -Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) -{ - InitOutSize(outSize); - - InitInputBuffer(); - - if (!CreateInputBufer()) - return E_OUTOFMEMORY; - - // InitInputBuffer(); - - StartNewStream(); - - _blockFinished = true; - - ErrorResult = S_OK; - - _inputFinished = false; - _inputRes = S_OK; - - return S_OK; -} - - - -Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - *processedSize = 0; - - try { - - if (ErrorResult != S_OK) - return ErrorResult; - - for (;;) - { - if (Base.state == STATE_STREAM_FINISHED) - { - if (!Base.DecodeAllStreams) - return ErrorResult; - StartNewStream(); - continue; - } - - if (Base.state == STATE_STREAM_SIGNATURE) - { - ErrorResult = ReadStreamSignature(); - - if (Base.NeedMoreInput) - if (Base.state2 == 0 && Base.NumStreams != 0) - { - Base.NeedMoreInput = false; - ErrorResult = S_OK; - return S_OK; - } - if (ErrorResult != S_OK) - return ErrorResult; - continue; - } - - if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE) - { - ErrorResult = ReadBlockSignature(); - - if (ErrorResult != S_OK) - return ErrorResult; - - continue; - } - - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _outPosTotal; - if (size >= rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - - if (_blockFinished) - { - if (Base.state != STATE_BLOCK_START) - { - ErrorResult = E_FAIL; - return ErrorResult; - } - - Base.Props.randMode = 1; - ErrorResult = ReadBlock(); - - if (ErrorResult != S_OK) - return ErrorResult; - - DecodeBlock1(_counters, Base.Props.blockSize); - - _spec._blockSize = Base.Props.blockSize; - _spec._tt = _counters + 256; - _spec.Init(Base.Props.origPtr, Base.Props.randMode); - - _blockFinished = false; - } - - { - Byte *ptr = _spec.Decode((Byte *)data, size); - - const UInt32 processed = (UInt32)(ptr - (Byte *)data); - data = ptr; - size -= processed; - (*processedSize) += processed; - _outPosTotal += processed; - - if (_spec.Finished()) - { - _blockFinished = true; - if (Base.crc != _spec._crc.GetDigest()) - { - BlockCrcError = true; - ErrorResult = S_FALSE; - return ErrorResult; - } - } - } - } - - } catch(...) { ErrorResult = S_FALSE; return S_FALSE; } -} - - - -// ---------- NSIS ---------- - -Z7_COM7F_IMF(CNsisDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - *processedSize = 0; - - try { - - if (ErrorResult != S_OK) - return ErrorResult; - - if (Base.state == STATE_STREAM_FINISHED) - return S_OK; - - if (Base.state == STATE_STREAM_SIGNATURE) - { - Base.blockSizeMax = 9 * kBlockSizeStep; - Base.state = STATE_BLOCK_SIGNATURE; - // Base.state2 = 0; - } - - for (;;) - { - if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE) - { - ErrorResult = ReadInput(); - if (ErrorResult != S_OK) - return ErrorResult; - - int b; - Base.ReadByte(b); - if (b < 0) - { - ErrorResult = S_FALSE; - return ErrorResult; - } - - if (b == kFinSig0) - { - /* - if (!Base.AreRemainByteBitsEmpty()) - ErrorResult = S_FALSE; - */ - Base.state = STATE_STREAM_FINISHED; - return ErrorResult; - } - - if (b != kBlockSig0) - { - ErrorResult = S_FALSE; - return ErrorResult; - } - - Base.state = STATE_BLOCK_START; - } - - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _outPosTotal; - if (size >= rem) - size = (UInt32)rem; - } - if (size == 0) - return S_OK; - - if (_blockFinished) - { - if (Base.state != STATE_BLOCK_START) - { - ErrorResult = E_FAIL; - return ErrorResult; - } - - Base.Props.randMode = 0; - ErrorResult = ReadBlock(); - - if (ErrorResult != S_OK) - return ErrorResult; - - DecodeBlock1(_counters, Base.Props.blockSize); - - _spec._blockSize = Base.Props.blockSize; - _spec._tt = _counters + 256; - _spec.Init(Base.Props.origPtr, Base.Props.randMode); - - _blockFinished = false; - } - - { - Byte *ptr = _spec.Decode((Byte *)data, size); - - const UInt32 processed = (UInt32)(ptr - (Byte *)data); - data = ptr; - size -= processed; - (*processedSize) += processed; - _outPosTotal += processed; - - if (_spec.Finished()) - _blockFinished = true; - } - } - - } catch(...) { ErrorResult = S_FALSE; return S_FALSE; } -} - -#endif - -}} +// BZip2Decoder.cpp + +#include "StdAfx.h" + +// #include "CopyCoder.h" + +/* +#include +#include "../../../C/CpuTicks.h" +*/ +#define TICKS_START +#define TICKS_UPDATE(n) + + +/* +#define PRIN(s) printf(s "\n"); fflush(stdout); +#define PRIN_VAL(s, val) printf(s " = %u \n", val); fflush(stdout); +*/ + +#define PRIN(s) +#define PRIN_VAL(s, val) + + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "BZip2Decoder.h" + + +namespace NCompress { +namespace NBZip2 { + +// #undef NO_INLINE +#define NO_INLINE Z7_NO_INLINE + +#define BZIP2_BYTE_MODE + + +static const UInt32 kInBufSize = (UInt32)1 << 17; +static const size_t kOutBufSize = (size_t)1 << 20; + +static const UInt32 kProgressStep = (UInt32)1 << 16; + +MY_ALIGN(64) +static const UInt16 kRandNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + + +enum EState +{ + STATE_STREAM_SIGNATURE, + STATE_BLOCK_SIGNATURE, + + STATE_BLOCK_START, + STATE_ORIG_BITS, + STATE_IN_USE, + STATE_IN_USE2, + STATE_NUM_TABLES, + STATE_NUM_SELECTORS, + STATE_SELECTORS, + STATE_LEVELS, + + STATE_BLOCK_SYMBOLS, + + STATE_STREAM_FINISHED +}; + + +#define UPDATE_VAL_2(val, num_bits) { \ + val |= (UInt32)(*_buf) << (24 - num_bits); \ + num_bits += 8; \ + _buf++; \ +} + +#define UPDATE_VAL UPDATE_VAL_2(VAL, NUM_BITS) + +#define READ_BITS(res, num) { \ + while (_numBits < num) { \ + if (_buf == _lim) return SZ_OK; \ + UPDATE_VAL_2(_value, _numBits) } \ + res = _value >> (32 - num); \ + _value <<= num; \ + _numBits -= num; \ +} + +#define READ_BITS_8(res, num) { \ + if (_numBits < num) { \ + if (_buf == _lim) return SZ_OK; \ + UPDATE_VAL_2(_value, _numBits) } \ + res = _value >> (32 - num); \ + _value <<= num; \ + _numBits -= num; \ +} + +#define READ_BIT(res) READ_BITS_8(res, 1) + + + +#define VAL _value2 +// #define NUM_BITS _numBits2 +#define NUM_BITS _numBits +#define BLOCK_SIZE blockSize2 +#define RUN_COUNTER runCounter2 + +#define LOAD_LOCAL \ + UInt32 VAL = this->_value; \ + /* unsigned NUM_BITS = this->_numBits; */ \ + UInt32 BLOCK_SIZE = this->blockSize; \ + UInt32 RUN_COUNTER = this->runCounter; \ + +#define SAVE_LOCAL \ + this->_value = VAL; \ + /* this->_numBits = NUM_BITS; */ \ + this->blockSize = BLOCK_SIZE; \ + this->runCounter = RUN_COUNTER; \ + + + +SRes CBitDecoder::ReadByte(int &b) +{ + b = -1; + READ_BITS_8(b, 8) + return SZ_OK; +} + + +NO_INLINE +SRes CBase::ReadStreamSignature2() +{ + for (;;) + { + unsigned b; + READ_BITS_8(b, 8) + + if ( (state2 == 0 && b != kArSig0) + || (state2 == 1 && b != kArSig1) + || (state2 == 2 && b != kArSig2) + || (state2 == 3 && (b <= kArSig3 || b > kArSig3 + kBlockSizeMultMax))) + return SZ_ERROR_DATA; + state2++; + + if (state2 == 4) + { + blockSizeMax = (UInt32)(b - kArSig3) * kBlockSizeStep; + CombinedCrc.Init(); + state = STATE_BLOCK_SIGNATURE; + state2 = 0; + return SZ_OK; + } + } +} + + +bool IsEndSig(const Byte *p) throw() +{ + return + p[0] == kFinSig0 && + p[1] == kFinSig1 && + p[2] == kFinSig2 && + p[3] == kFinSig3 && + p[4] == kFinSig4 && + p[5] == kFinSig5; +} + +bool IsBlockSig(const Byte *p) throw() +{ + return + p[0] == kBlockSig0 && + p[1] == kBlockSig1 && + p[2] == kBlockSig2 && + p[3] == kBlockSig3 && + p[4] == kBlockSig4 && + p[5] == kBlockSig5; +} + + +NO_INLINE +SRes CBase::ReadBlockSignature2() +{ + while (state2 < 10) + { + unsigned b; + READ_BITS_8(b, 8) + temp[state2] = (Byte)b; + state2++; + } + + crc = 0; + for (unsigned i = 0; i < 4; i++) + { + crc <<= 8; + crc |= temp[6 + i]; + } + + if (IsBlockSig(temp)) + { + if (!IsBz) + NumStreams++; + NumBlocks++; + IsBz = true; + CombinedCrc.Update(crc); + state = STATE_BLOCK_START; + return SZ_OK; + } + + if (!IsEndSig(temp)) + return SZ_ERROR_DATA; + + if (!IsBz) + NumStreams++; + IsBz = true; + + if (_value != 0) + MinorError = true; + + AlignToByte(); + + state = STATE_STREAM_FINISHED; + if (crc != CombinedCrc.GetDigest()) + { + StreamCrcError = true; + return SZ_ERROR_DATA; + } + return SZ_OK; +} + + +NO_INLINE +SRes CBase::ReadBlock2() +{ + if (state != STATE_BLOCK_SYMBOLS) { + PRIN("ReadBlock2") + + if (state == STATE_BLOCK_START) + { + if (Props.randMode) + { + READ_BIT(Props.randMode) + } + state = STATE_ORIG_BITS; + // g_Tick = GetCpuTicks(); + } + + if (state == STATE_ORIG_BITS) + { + READ_BITS(Props.origPtr, kNumOrigBits) + if (Props.origPtr >= blockSizeMax) + return SZ_ERROR_DATA; + state = STATE_IN_USE; + } + + // why original code compares origPtr to (UInt32)(10 + blockSizeMax)) ? + + if (state == STATE_IN_USE) + { + READ_BITS(state2, 16) + state = STATE_IN_USE2; + state3 = 0; + numInUse = 0; + mtf.StartInit(); + } + + if (state == STATE_IN_USE2) + { + for (; state3 < 256; state3++) + if (state2 & ((UInt32)0x8000 >> (state3 >> 4))) + { + unsigned b; + READ_BIT(b) + if (b) + mtf.Add(numInUse++, (Byte)state3); + } + if (numInUse == 0) + return SZ_ERROR_DATA; + state = STATE_NUM_TABLES; + } + + + if (state == STATE_NUM_TABLES) + { + READ_BITS_8(numTables, kNumTablesBits) + state = STATE_NUM_SELECTORS; + if (numTables < kNumTablesMin || numTables > kNumTablesMax) + return SZ_ERROR_DATA; + } + + if (state == STATE_NUM_SELECTORS) + { + READ_BITS(numSelectors, kNumSelectorsBits) + state = STATE_SELECTORS; + state2 = 0x543210; + state3 = 0; + state4 = 0; + // lbzip2 can write small number of additional selectors, + // 20.01: we allow big number of selectors here like bzip2-1.0.8 + if (numSelectors == 0 + // || numSelectors > kNumSelectorsMax_Decoder + ) + return SZ_ERROR_DATA; + } + + if (state == STATE_SELECTORS) + { + const unsigned kMtfBits = 4; + const UInt32 kMtfMask = (1 << kMtfBits) - 1; + do + { + for (;;) + { + unsigned b; + READ_BIT(b) + if (!b) + break; + if (++state4 >= numTables) + return SZ_ERROR_DATA; + } + const UInt32 tmp = (state2 >> (kMtfBits * state4)) & kMtfMask; + const UInt32 mask = ((UInt32)1 << ((state4 + 1) * kMtfBits)) - 1; + state4 = 0; + state2 = ((state2 << kMtfBits) & mask) | (state2 & ~mask) | tmp; + // 20.01: here we keep compatibility with bzip2-1.0.8 decoder: + if (state3 < kNumSelectorsMax) + selectors[state3] = (Byte)tmp; + } + while (++state3 < numSelectors); + + // we allowed additional dummy selector records filled above to support lbzip2's archives. + // but we still don't allow to use these additional dummy selectors in the code bellow + // bzip2 1.0.8 decoder also has similar restriction. + + if (numSelectors > kNumSelectorsMax) + numSelectors = kNumSelectorsMax; + + state = STATE_LEVELS; + state2 = 0; + state3 = 0; + } + + if (state == STATE_LEVELS) + { + do + { + if (state3 == 0) + { + READ_BITS_8(state3, kNumLevelsBits) + state4 = 0; + state5 = 0; + } + const unsigned alphaSize = numInUse + 2; + for (; state4 < alphaSize; state4++) + { + for (;;) + { + if (state3 < 1 || state3 > kMaxHuffmanLen) + return SZ_ERROR_DATA; + + if (state5 == 0) + { + unsigned b; + READ_BIT(b) + if (!b) + break; + } + + state5 = 1; + unsigned b; + READ_BIT(b) + + state5 = 0; + state3++; + state3 -= (b << 1); + } + lens[state4] = (Byte)state3; + state5 = 0; + } + + // 19.03: we use non-full Build() to support lbzip2 archives. + // lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen + for (unsigned i = state4; i < kMaxAlphaSize; i++) + lens[i] = 0; + if (!huffs[state2].Build(lens)) // k_BuildMode_Partial + return SZ_ERROR_DATA; + state3 = 0; + } + while (++state2 < numTables); + + { + UInt32 *counters = this->Counters; + for (unsigned i = 0; i < 256; i++) + counters[i] = 0; + } + + state = STATE_BLOCK_SYMBOLS; + + groupIndex = 0; + groupSize = kGroupSize; + runPower = 0; + runCounter = 0; + blockSize = 0; + } + + if (state != STATE_BLOCK_SYMBOLS) + return SZ_ERROR_DATA; + + // g_Ticks[3] += GetCpuTicks() - g_Tick; + + } + + { + LOAD_LOCAL + const CHuffmanDecoder *huf = &huffs[selectors[groupIndex]]; + + for (;;) + { + if (groupSize == 0) + { + if (++groupIndex >= numSelectors) + return SZ_ERROR_DATA; + huf = &huffs[selectors[groupIndex]]; + groupSize = kGroupSize; + } + + if (NUM_BITS < kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL + if (NUM_BITS < kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL + if (NUM_BITS < kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL }}} + + unsigned sym; + + #define MOV_POS(bs, len) \ + { \ + if (NUM_BITS < len) \ + { \ + SAVE_LOCAL \ + return SZ_OK; \ + } \ + VAL <<= len; \ + NUM_BITS -= (unsigned)len; \ + } + + Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huf, kMaxHuffmanLen, kNumTableBits, + VAL, + Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, + { return SZ_ERROR_DATA; }, + MOV_POS, {}, bs) + + groupSize--; + + if (sym < 2) + { + RUN_COUNTER += (UInt32)(sym + 1) << runPower; + runPower++; + if (blockSizeMax - BLOCK_SIZE < RUN_COUNTER) + return SZ_ERROR_DATA; + continue; + } + + UInt32 *counters = this->Counters; + if (RUN_COUNTER != 0) + { + UInt32 b = (UInt32)(mtf.Buf[0] & 0xFF); + counters[b] += RUN_COUNTER; + runPower = 0; + #ifdef BZIP2_BYTE_MODE + Byte *dest = (Byte *)(&counters[256 + kBlockSizeMax]) + BLOCK_SIZE; + const Byte *limit = dest + RUN_COUNTER; + BLOCK_SIZE += RUN_COUNTER; + RUN_COUNTER = 0; + do + { + dest[0] = (Byte)b; + dest[1] = (Byte)b; + dest[2] = (Byte)b; + dest[3] = (Byte)b; + dest += 4; + } + while (dest < limit); + #else + UInt32 *dest = &counters[256 + BLOCK_SIZE]; + const UInt32 *limit = dest + RUN_COUNTER; + BLOCK_SIZE += RUN_COUNTER; + RUN_COUNTER = 0; + do + { + dest[0] = b; + dest[1] = b; + dest[2] = b; + dest[3] = b; + dest += 4; + } + while (dest < limit); + #endif + } + + sym -= 1; + if (sym < numInUse) + { + if (BLOCK_SIZE >= blockSizeMax) + return SZ_ERROR_DATA; + + // UInt32 b = (UInt32)mtf.GetAndMove((unsigned)sym); + + const unsigned lim = sym >> Z7_MTF_MOVS; + const unsigned pos = (sym & Z7_MTF_MASK) << 3; + CMtfVar next = mtf.Buf[lim]; + CMtfVar prev = (next >> pos) & 0xFF; + + #ifdef BZIP2_BYTE_MODE + ((Byte *)(counters + 256 + kBlockSizeMax))[BLOCK_SIZE++] = (Byte)prev; + #else + (counters + 256)[BLOCK_SIZE++] = (UInt32)prev; + #endif + counters[prev]++; + + CMtfVar *m = mtf.Buf; + CMtfVar *mLim = m + lim; + if (lim != 0) + { + do + { + CMtfVar n0 = *m; + *m = (n0 << 8) | prev; + prev = (n0 >> (Z7_MTF_MASK << 3)); + } + while (++m != mLim); + } + + CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); + *mLim = (next & ~mask) | (((next << 8) | prev) & mask); + continue; + } + + if (sym != numInUse) + return SZ_ERROR_DATA; + break; + } + + // we write additional item that will be read in DecodeBlock1 for prefetching + #ifdef BZIP2_BYTE_MODE + ((Byte *)(Counters + 256 + kBlockSizeMax))[BLOCK_SIZE] = 0; + #else + (counters + 256)[BLOCK_SIZE] = 0; + #endif + + SAVE_LOCAL + Props.blockSize = blockSize; + state = STATE_BLOCK_SIGNATURE; + state2 = 0; + + PRIN_VAL("origPtr", Props.origPtr); + PRIN_VAL("blockSize", Props.blockSize); + + return (Props.origPtr < Props.blockSize) ? SZ_OK : SZ_ERROR_DATA; + } +} + + +NO_INLINE +static void DecodeBlock1(UInt32 *counters, UInt32 blockSize) +{ + { + UInt32 sum = 0; + for (UInt32 i = 0; i < 256; i++) + { + const UInt32 v = counters[i]; + counters[i] = sum; + sum += v; + } + } + + UInt32 *tt = counters + 256; + // Compute the T^(-1) vector + + // blockSize--; + + #ifdef BZIP2_BYTE_MODE + + unsigned c = ((const Byte *)(tt + kBlockSizeMax))[0]; + + for (UInt32 i = 0; i < blockSize; i++) + { + unsigned c1 = c; + const UInt32 pos = counters[c]; + c = ((const Byte *)(tt + kBlockSizeMax))[(size_t)i + 1]; + counters[c1] = pos + 1; + tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; + } + + /* + // last iteration without next character prefetching + { + const UInt32 pos = counters[c]; + counters[c] = pos + 1; + tt[pos] = (blockSize << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; + } + */ + + #else + + unsigned c = (unsigned)(tt[0] & 0xFF); + + for (UInt32 i = 0; i < blockSize; i++) + { + unsigned c1 = c; + const UInt32 pos = counters[c]; + c = (unsigned)(tt[(size_t)i + 1] & 0xFF); + counters[c1] = pos + 1; + tt[pos] |= (i << 8); + } + + /* + { + const UInt32 pos = counters[c]; + counters[c] = pos + 1; + tt[pos] |= (blockSize << 8); + } + */ + + #endif + + + /* + for (UInt32 i = 0; i < blockSize; i++) + { + #ifdef BZIP2_BYTE_MODE + const unsigned c = ((const Byte *)(tt + kBlockSizeMax))[i]; + const UInt32 pos = counters[c]++; + tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos]; + #else + const unsigned c = (unsigned)(tt[i] & 0xFF); + const UInt32 pos = counters[c]++; + tt[pos] |= (i << 8); + #endif + } + */ +} + + +void CSpecState::Init(UInt32 origPtr, unsigned randMode) throw() +{ + _tPos = _tt[_tt[origPtr] >> 8]; + _prevByte = (unsigned)(_tPos & 0xFF); + _reps = 0; + _randIndex = 0; + _randToGo = -1; + if (randMode) + { + _randIndex = 1; + _randToGo = kRandNums[0] - 2; + } + _crc.Init(); +} + + + +NO_INLINE +Byte * CSpecState::Decode(Byte *data, size_t size) throw() +{ + if (size == 0) + return data; + + unsigned prevByte = _prevByte; + int reps = _reps; + CBZip2Crc crc = _crc; + const Byte *lim = data + size; + + while (reps > 0) + { + reps--; + *data++ = (Byte)prevByte; + crc.UpdateByte(prevByte); + if (data == lim) + break; + } + + UInt32 tPos = _tPos; + UInt32 blockSize = _blockSize; + const UInt32 *tt = _tt; + + if (data != lim && blockSize) + + for (;;) + { + unsigned b = (unsigned)(tPos & 0xFF); + tPos = tt[tPos >> 8]; + blockSize--; + + if (_randToGo >= 0) + { + if (_randToGo == 0) + { + b ^= 1; + _randToGo = kRandNums[_randIndex]; + _randIndex++; + _randIndex &= 0x1FF; + } + _randToGo--; + } + + if (reps != -(int)kRleModeRepSize) + { + if (b != prevByte) + reps = 0; + reps--; + prevByte = b; + *data++ = (Byte)b; + crc.UpdateByte(b); + if (data == lim || blockSize == 0) + break; + continue; + } + + reps = (int)b; + while (reps) + { + reps--; + *data++ = (Byte)prevByte; + crc.UpdateByte(prevByte); + if (data == lim) + break; + } + if (data == lim) + break; + if (blockSize == 0) + break; + } + + if (blockSize == 1 && reps == -(int)kRleModeRepSize) + { + unsigned b = (unsigned)(tPos & 0xFF); + tPos = tt[tPos >> 8]; + blockSize--; + + if (_randToGo >= 0) + { + if (_randToGo == 0) + { + b ^= 1; + _randToGo = kRandNums[_randIndex]; + _randIndex++; + _randIndex &= 0x1FF; + } + _randToGo--; + } + + reps = (int)b; + } + + _tPos = tPos; + _prevByte = prevByte; + _reps = reps; + _crc = crc; + _blockSize = blockSize; + + return data; +} + + +HRESULT CDecoder::Flush() +{ + if (_writeRes == S_OK) + { + _writeRes = WriteStream(_outStream, _outBuf, _outPos); + _outWritten += _outPos; + _outPos = 0; + } + return _writeRes; +} + + +NO_INLINE +HRESULT CDecoder::DecodeBlock(const CBlockProps &props) +{ + _calcedBlockCrc = 0; + _blockFinished = false; + + CSpecState block; + + block._blockSize = props.blockSize; + block._tt = _counters + 256; + + block.Init(props.origPtr, props.randMode); + + for (;;) + { + Byte *data = _outBuf + _outPos; + size_t size = kOutBufSize - _outPos; + + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outPosTotal; + if (size >= rem) + { + size = (size_t)rem; + if (size == 0) + return FinishMode ? S_FALSE : S_OK; + } + } + + TICKS_START + const size_t processed = (size_t)(block.Decode(data, size) - data); + TICKS_UPDATE(2) + + _outPosTotal += processed; + _outPos += processed; + + if (processed >= size) + { + RINOK(Flush()) + } + + if (block.Finished()) + { + _blockFinished = true; + _calcedBlockCrc = block._crc.GetDigest(); + return S_OK; + } + } +} + + +CDecoder::CDecoder(): + _outBuf(NULL), + FinishMode(false), + _outSizeDefined(false), + _counters(NULL), + _inBuf(NULL), + _inProcessed(0) +{ + #ifndef Z7_ST + MtMode = false; + NeedWaitScout = false; + // ScoutRes = S_OK; + #endif +} + + +CDecoder::~CDecoder() +{ + PRIN("\n~CDecoder()"); + + #ifndef Z7_ST + + if (Thread.IsCreated()) + { + WaitScout(); + + _block.StopScout = true; + + PRIN("\nScoutEvent.Set()"); + ScoutEvent.Set(); + + PRIN("\nThread.Wait()()"); + Thread.Wait_Close(); + PRIN("\n after Thread.Wait()()"); + + // if (ScoutRes != S_OK) throw ScoutRes; + } + + #endif + + BigFree(_counters); + MidFree(_outBuf); + MidFree(_inBuf); +} + + +HRESULT CDecoder::ReadInput() +{ + if (Base._buf != Base._lim || _inputFinished || _inputRes != S_OK) + return _inputRes; + + _inProcessed += (size_t)(Base._buf - _inBuf); + Base._buf = _inBuf; + Base._lim = _inBuf; + UInt32 size = 0; + _inputRes = Base.InStream->Read(_inBuf, kInBufSize, &size); + _inputFinished = (size == 0); + Base._lim = _inBuf + size; + return _inputRes; +} + + +void CDecoder::StartNewStream() +{ + Base.state = STATE_STREAM_SIGNATURE; + Base.state2 = 0; + Base.IsBz = false; +} + + +HRESULT CDecoder::ReadStreamSignature() +{ + for (;;) + { + RINOK(ReadInput()) + SRes res = Base.ReadStreamSignature2(); + if (res != SZ_OK) + return S_FALSE; + if (Base.state == STATE_BLOCK_SIGNATURE) + return S_OK; + if (_inputFinished) + { + Base.NeedMoreInput = true; + return S_FALSE; + } + } +} + + +HRESULT CDecoder::StartRead() +{ + StartNewStream(); + return ReadStreamSignature(); +} + + +HRESULT CDecoder::ReadBlockSignature() +{ + for (;;) + { + RINOK(ReadInput()) + + SRes res = Base.ReadBlockSignature2(); + + if (Base.state == STATE_STREAM_FINISHED) + Base.FinishedPackSize = GetInputProcessedSize(); + if (res != SZ_OK) + return S_FALSE; + if (Base.state != STATE_BLOCK_SIGNATURE) + return S_OK; + if (_inputFinished) + { + Base.NeedMoreInput = true; + return S_FALSE; + } + } +} + + +HRESULT CDecoder::ReadBlock() +{ + for (;;) + { + RINOK(ReadInput()) + + SRes res = Base.ReadBlock2(); + + if (res != SZ_OK) + return S_FALSE; + if (Base.state == STATE_BLOCK_SIGNATURE) + return S_OK; + if (_inputFinished) + { + Base.NeedMoreInput = true; + return S_FALSE; + } + } +} + + + +HRESULT CDecoder::DecodeStreams(ICompressProgressInfo *progress) +{ + { + #ifndef Z7_ST + _block.StopScout = false; + #endif + } + + RINOK(StartRead()) + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + + { + #ifndef Z7_ST + CWaitScout_Releaser waitScout_Releaser(this); + + bool useMt = false; + #endif + + bool wasFinished = false; + + UInt32 crc = 0; + UInt32 nextCrc = 0; + HRESULT nextRes = S_OK; + + UInt64 packPos = 0; + + CBlockProps props; + + props.blockSize = 0; + + for (;;) + { + if (progress) + { + const UInt64 outCur = GetOutProcessedSize(); + if (packPos - inPrev >= kProgressStep || outCur - outPrev >= kProgressStep) + { + RINOK(progress->SetRatioInfo(&packPos, &outCur)) + inPrev = packPos; + outPrev = outCur; + } + } + + if (props.blockSize == 0) + if (wasFinished || nextRes != S_OK) + return nextRes; + + if ( + #ifndef Z7_ST + !useMt && + #endif + !wasFinished && Base.state == STATE_BLOCK_SIGNATURE) + { + nextRes = ReadBlockSignature(); + nextCrc = Base.crc; + packPos = GetInputProcessedSize(); + + wasFinished = true; + + if (nextRes != S_OK) + continue; + + if (Base.state == STATE_STREAM_FINISHED) + { + if (!Base.DecodeAllStreams) + { + wasFinished = true; + continue; + } + + nextRes = StartRead(); + + if (Base.NeedMoreInput) + { + if (Base.state2 == 0) + Base.NeedMoreInput = false; + wasFinished = true; + nextRes = S_OK; + continue; + } + + if (nextRes != S_OK) + continue; + + wasFinished = false; + continue; + } + + wasFinished = false; + + #ifndef Z7_ST + if (MtMode) + if (props.blockSize != 0) + { + // we start multithreading, if next block is big enough. + const UInt32 k_Mt_BlockSize_Threshold = (1 << 12); // (1 << 13) + if (props.blockSize > k_Mt_BlockSize_Threshold) + { + if (!Thread.IsCreated()) + { + PRIN("=== MT_MODE"); + RINOK(CreateThread()) + } + useMt = true; + } + } + #endif + } + + if (props.blockSize == 0) + { + crc = nextCrc; + + #ifndef Z7_ST + if (useMt) + { + PRIN("DecoderEvent.Lock()"); + { + WRes wres = DecoderEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + NeedWaitScout = false; + PRIN("-- DecoderEvent.Lock()"); + props = _block.Props; + nextCrc = _block.NextCrc; + if (_block.Crc_Defined) + crc = _block.Crc; + packPos = _block.PackPos; + wasFinished = _block.WasFinished; + RINOK(_block.Res) + } + else + #endif + { + if (Base.state != STATE_BLOCK_START) + return E_FAIL; + + TICKS_START + Base.Props.randMode = 1; + RINOK(ReadBlock()) + TICKS_UPDATE(0) + + props = Base.Props; + continue; + } + } + + if (props.blockSize != 0) + { + TICKS_START + DecodeBlock1(_counters, props.blockSize); + TICKS_UPDATE(1) + } + + #ifndef Z7_ST + if (useMt && !wasFinished) + { + /* + if (props.blockSize == 0) + { + // this codes switches back to single-threadMode + useMt = false; + PRIN("=== ST_MODE"); + continue; + } + */ + + PRIN("ScoutEvent.Set()"); + { + WRes wres = ScoutEvent.Set(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + NeedWaitScout = true; + } + #endif + + if (props.blockSize == 0) + continue; + + RINOK(DecodeBlock(props)) + + if (!_blockFinished) + return nextRes; + + props.blockSize = 0; + if (_calcedBlockCrc != crc) + { + BlockCrcError = true; + return S_FALSE; + } + } + } +} + + + + +bool CDecoder::CreateInputBufer() +{ + if (!_inBuf) + { + _inBuf = (Byte *)MidAlloc(kInBufSize); + if (!_inBuf) + return false; + Base._buf = _inBuf; + Base._lim = _inBuf; + } + if (!_counters) + { + const size_t size = (256 + kBlockSizeMax) * sizeof(UInt32) + #ifdef BZIP2_BYTE_MODE + + kBlockSizeMax + #endif + + 256; + _counters = (UInt32 *)::BigAlloc(size); + if (!_counters) + return false; + Base.Counters = _counters; + } + return true; +} + + +void CDecoder::InitOutSize(const UInt64 *outSize) +{ + _outPosTotal = 0; + + _outSizeDefined = false; + _outSize = 0; + if (outSize) + { + _outSize = *outSize; + _outSizeDefined = true; + } + + BlockCrcError = false; + + Base.InitNumStreams2(); +} + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + /* + { + RINOK(SetInStream(inStream)); + RINOK(SetOutStreamSize(outSize)); + + RINOK(CopyStream(this, outStream, progress)); + return ReleaseInStream(); + } + */ + + _inputFinished = false; + _inputRes = S_OK; + _writeRes = S_OK; + + try { + + InitOutSize(outSize); + + // we can request data from InputBuffer after Code(). + // so we init InputBuffer before any function return. + + InitInputBuffer(); + + if (!CreateInputBufer()) + return E_OUTOFMEMORY; + + if (!_outBuf) + { + _outBuf = (Byte *)MidAlloc(kOutBufSize); + if (!_outBuf) + return E_OUTOFMEMORY; + } + + Base.InStream = inStream; + + // InitInputBuffer(); + + _outStream = outStream; + _outWritten = 0; + _outPos = 0; + + HRESULT res = DecodeStreams(progress); + + Flush(); + + Base.InStream = NULL; + _outStream = NULL; + + /* + if (res == S_OK) + if (FinishMode && inSize && *inSize != GetInputProcessedSize()) + res = S_FALSE; + */ + + if (res != S_OK) + return res; + + } catch(...) { return E_FAIL; } + + return _writeRes; +} + + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + FinishMode = (finishMode != 0); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = GetInStreamSize(); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) +{ + Base.AlignToByte(); + UInt32 i; + for (i = 0; i < size; i++) + { + int b; + Base.ReadByte(b); + if (b < 0) + break; + ((Byte *)data)[i] = (Byte)b; + } + if (processedSize) + *processedSize = i; + return S_OK; +} + + +#ifndef Z7_ST + +#define PRIN_MT(s) PRIN(" " s) + +// #define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; } + +static THREAD_FUNC_DECL RunScout2(void *p) { ((CDecoder *)p)->RunScout(); return 0; } + +HRESULT CDecoder::CreateThread() +{ + WRes wres = DecoderEvent.CreateIfNotCreated_Reset(); + if (wres == 0) { wres = ScoutEvent.CreateIfNotCreated_Reset(); + if (wres == 0) { wres = Thread.Create(RunScout2, this); }} + return HRESULT_FROM_WIN32(wres); +} + +void CDecoder::RunScout() +{ + for (;;) + { + { + PRIN_MT("ScoutEvent.Lock()") + WRes wres = ScoutEvent.Lock(); + PRIN_MT("-- ScoutEvent.Lock()") + if (wres != 0) + { + // ScoutRes = wres; + return; + } + } + + CBlock &block = _block; + + if (block.StopScout) + { + // ScoutRes = S_OK; + return; + } + + block.Res = S_OK; + block.WasFinished = false; + + HRESULT res = S_OK; + + try + { + UInt64 packPos = GetInputProcessedSize(); + + block.Props.blockSize = 0; + block.Crc_Defined = false; + // block.NextCrc_Defined = false; + block.NextCrc = 0; + + for (;;) + { + if (Base.state == STATE_BLOCK_SIGNATURE) + { + res = ReadBlockSignature(); + + if (res != S_OK) + break; + + if (block.Props.blockSize == 0) + { + block.Crc = Base.crc; + block.Crc_Defined = true; + } + else + { + block.NextCrc = Base.crc; + // block.NextCrc_Defined = true; + } + + continue; + } + + if (Base.state == STATE_BLOCK_START) + { + if (block.Props.blockSize != 0) + break; + + Base.Props.randMode = 1; + + res = ReadBlock(); + + PRIN_MT("-- Base.ReadBlock") + if (res != S_OK) + break; + block.Props = Base.Props; + continue; + } + + if (Base.state == STATE_STREAM_FINISHED) + { + if (!Base.DecodeAllStreams) + { + block.WasFinished = true; + break; + } + + res = StartRead(); + + if (Base.NeedMoreInput) + { + if (Base.state2 == 0) + Base.NeedMoreInput = false; + block.WasFinished = true; + res = S_OK; + break; + } + + if (res != S_OK) + break; + + if (GetInputProcessedSize() - packPos > 0) // kProgressStep + break; + continue; + } + + // throw 1; + res = E_FAIL; + break; + } + } + + catch (...) { res = E_FAIL; } + + if (res != S_OK) + { + PRIN_MT("error") + block.Res = res; + block.WasFinished = true; + } + + block.PackPos = GetInputProcessedSize(); + PRIN_MT("DecoderEvent.Set()") + WRes wres = DecoderEvent.Set(); + if (wres != 0) + { + // ScoutRes = wres; + return; + } + } +} + + +Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads)) +{ + MtMode = (numThreads > 1); + + #ifndef BZIP2_BYTE_MODE + MtMode = false; + #endif + + // MtMode = false; + return S_OK; +} + +#endif + + + +#ifndef Z7_NO_READ_FROM_CODER + + +Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) +{ + Base.InStreamRef = inStream; + Base.InStream = inStream; + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::ReleaseInStream()) +{ + Base.InStreamRef.Release(); + Base.InStream = NULL; + return S_OK; +} + + + +Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) +{ + InitOutSize(outSize); + + InitInputBuffer(); + + if (!CreateInputBufer()) + return E_OUTOFMEMORY; + + // InitInputBuffer(); + + StartNewStream(); + + _blockFinished = true; + + ErrorResult = S_OK; + + _inputFinished = false; + _inputRes = S_OK; + + return S_OK; +} + + + +Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + *processedSize = 0; + + try { + + if (ErrorResult != S_OK) + return ErrorResult; + + for (;;) + { + if (Base.state == STATE_STREAM_FINISHED) + { + if (!Base.DecodeAllStreams) + return ErrorResult; + StartNewStream(); + continue; + } + + if (Base.state == STATE_STREAM_SIGNATURE) + { + ErrorResult = ReadStreamSignature(); + + if (Base.NeedMoreInput) + if (Base.state2 == 0 && Base.NumStreams != 0) + { + Base.NeedMoreInput = false; + ErrorResult = S_OK; + return S_OK; + } + if (ErrorResult != S_OK) + return ErrorResult; + continue; + } + + if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE) + { + ErrorResult = ReadBlockSignature(); + + if (ErrorResult != S_OK) + return ErrorResult; + + continue; + } + + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outPosTotal; + if (size >= rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + + if (_blockFinished) + { + if (Base.state != STATE_BLOCK_START) + { + ErrorResult = E_FAIL; + return ErrorResult; + } + + Base.Props.randMode = 1; + ErrorResult = ReadBlock(); + + if (ErrorResult != S_OK) + return ErrorResult; + + DecodeBlock1(_counters, Base.Props.blockSize); + + _spec._blockSize = Base.Props.blockSize; + _spec._tt = _counters + 256; + _spec.Init(Base.Props.origPtr, Base.Props.randMode); + + _blockFinished = false; + } + + { + Byte *ptr = _spec.Decode((Byte *)data, size); + + const UInt32 processed = (UInt32)(ptr - (Byte *)data); + data = ptr; + size -= processed; + (*processedSize) += processed; + _outPosTotal += processed; + + if (_spec.Finished()) + { + _blockFinished = true; + if (Base.crc != _spec._crc.GetDigest()) + { + BlockCrcError = true; + ErrorResult = S_FALSE; + return ErrorResult; + } + } + } + } + + } catch(...) { ErrorResult = S_FALSE; return S_FALSE; } +} + + + +// ---------- NSIS ---------- + +Z7_COM7F_IMF(CNsisDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + *processedSize = 0; + + try { + + if (ErrorResult != S_OK) + return ErrorResult; + + if (Base.state == STATE_STREAM_FINISHED) + return S_OK; + + if (Base.state == STATE_STREAM_SIGNATURE) + { + Base.blockSizeMax = 9 * kBlockSizeStep; + Base.state = STATE_BLOCK_SIGNATURE; + // Base.state2 = 0; + } + + for (;;) + { + if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE) + { + ErrorResult = ReadInput(); + if (ErrorResult != S_OK) + return ErrorResult; + + int b; + Base.ReadByte(b); + if (b < 0) + { + ErrorResult = S_FALSE; + return ErrorResult; + } + + if (b == kFinSig0) + { + /* + if (!Base.AreRemainByteBitsEmpty()) + ErrorResult = S_FALSE; + */ + Base.state = STATE_STREAM_FINISHED; + return ErrorResult; + } + + if (b != kBlockSig0) + { + ErrorResult = S_FALSE; + return ErrorResult; + } + + Base.state = STATE_BLOCK_START; + } + + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outPosTotal; + if (size >= rem) + size = (UInt32)rem; + } + if (size == 0) + return S_OK; + + if (_blockFinished) + { + if (Base.state != STATE_BLOCK_START) + { + ErrorResult = E_FAIL; + return ErrorResult; + } + + Base.Props.randMode = 0; + ErrorResult = ReadBlock(); + + if (ErrorResult != S_OK) + return ErrorResult; + + DecodeBlock1(_counters, Base.Props.blockSize); + + _spec._blockSize = Base.Props.blockSize; + _spec._tt = _counters + 256; + _spec.Init(Base.Props.origPtr, Base.Props.randMode); + + _blockFinished = false; + } + + { + Byte *ptr = _spec.Decode((Byte *)data, size); + + const UInt32 processed = (UInt32)(ptr - (Byte *)data); + data = ptr; + size -= processed; + (*processedSize) += processed; + _outPosTotal += processed; + + if (_spec.Finished()) + _blockFinished = true; + } + } + + } catch(...) { ErrorResult = S_FALSE; return S_FALSE; } +} + +#endif + +}} diff --git a/CPP/7zip/Compress/BZip2Decoder.h b/CPP/7zip/Compress/BZip2Decoder.h index e737fd179..4adc564c8 100644 --- a/CPP/7zip/Compress/BZip2Decoder.h +++ b/CPP/7zip/Compress/BZip2Decoder.h @@ -1,388 +1,388 @@ -// Compress/BZip2Decoder.h - -#ifndef ZIP7_INC_COMPRESS_BZIP2_DECODER_H -#define ZIP7_INC_COMPRESS_BZIP2_DECODER_H - -#include "../../Common/MyCom.h" - -// #define Z7_NO_READ_FROM_CODER -// #define Z7_ST - -#ifndef Z7_ST -#include "../../Windows/Synchronization.h" -#include "../../Windows/Thread.h" -#endif - -#include "../ICoder.h" - -#include "BZip2Const.h" -#include "BZip2Crc.h" -#include "HuffmanDecoder.h" -#include "Mtf8.h" - -namespace NCompress { -namespace NBZip2 { - -bool IsEndSig(const Byte *p) throw(); -bool IsBlockSig(const Byte *p) throw(); - -const unsigned kNumTableBits = 9; - -typedef NHuffman::CDecoder CHuffmanDecoder; - - -struct CBlockProps -{ - UInt32 blockSize; - UInt32 origPtr; - unsigned randMode; - - CBlockProps(): blockSize(0), origPtr(0), randMode(0) {} -}; - - -struct CBitDecoder -{ - unsigned _numBits; - UInt32 _value; - const Byte *_buf; - const Byte *_lim; - - void InitBitDecoder() - { - _numBits = 0; - _value = 0; - } - - void AlignToByte() - { - unsigned bits = _numBits & 7; - _numBits -= bits; - _value <<= bits; - } - - /* - bool AreRemainByteBitsEmpty() const - { - unsigned bits = _numBits & 7; - if (bits != 0) - return (_value >> (32 - bits)) == 0; - return true; - } - */ - - SRes ReadByte(int &b); - - CBitDecoder(): - _buf(NULL), - _lim(NULL) - { - InitBitDecoder(); - } -}; - - -// 19.03: we allow additional 8 selectors to support files created by lbzip2. -const UInt32 kNumSelectorsMax_Decoder = kNumSelectorsMax + 8; - -struct CBase: public CBitDecoder -{ - unsigned numInUse; - UInt32 groupIndex; - UInt32 groupSize; - unsigned runPower; - UInt32 runCounter; - UInt32 blockSize; - - UInt32 *Counters; - UInt32 blockSizeMax; - - unsigned state; - UInt32 state2; - unsigned state3; - unsigned state4; - unsigned state5; - unsigned numTables; - UInt32 numSelectors; - - CBlockProps Props; - -private: - CMtf8Decoder mtf; - Byte selectors[kNumSelectorsMax_Decoder]; - CHuffmanDecoder huffs[kNumTablesMax]; - - Byte lens[kMaxAlphaSize]; - - Byte temp[10]; - -public: - UInt32 crc; - CBZip2CombinedCrc CombinedCrc; - - bool IsBz; - bool StreamCrcError; - bool MinorError; - bool NeedMoreInput; - - bool DecodeAllStreams; - - UInt64 NumStreams; - UInt64 NumBlocks; - UInt64 FinishedPackSize; - - ISequentialInStream *InStream; - - #ifndef Z7_NO_READ_FROM_CODER - CMyComPtr InStreamRef; - #endif - - CBase(): - StreamCrcError(false), - MinorError(false), - NeedMoreInput(false), - - DecodeAllStreams(false), - - NumStreams(0), - NumBlocks(0), - FinishedPackSize(0) - {} - - void InitNumStreams2() - { - StreamCrcError = false; - MinorError = false; - NeedMoreInput = 0; - NumStreams = 0; - NumBlocks = 0; - FinishedPackSize = 0; - } - - SRes ReadStreamSignature2(); - SRes ReadBlockSignature2(); - - /* ReadBlock2() : Props->randMode: - in: need read randMode bit - out: randMode status */ - SRes ReadBlock2(); -}; - - -class CSpecState -{ - UInt32 _tPos; - unsigned _prevByte; - int _reps; - -public: - CBZip2Crc _crc; - UInt32 _blockSize; - UInt32 *_tt; - - int _randToGo; - unsigned _randIndex; - - void Init(UInt32 origPtr, unsigned randMode) throw(); - - bool Finished() const { return _reps <= 0 && _blockSize == 0; } - - Byte *Decode(Byte *data, size_t size) throw(); -}; - - - - -class CDecoder: - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public ICompressReadUnusedFromInBuf, -#ifndef Z7_NO_READ_FROM_CODER - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, -#endif -#ifndef Z7_ST - public ICompressSetCoderMt, -#endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf) -#ifndef Z7_NO_READ_FROM_CODER - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ISequentialInStream) -#endif -#ifndef Z7_ST - Z7_COM_QI_ENTRY(ICompressSetCoderMt) -#endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) - Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf) -#ifndef Z7_NO_READ_FROM_CODER - Z7_IFACE_COM7_IMP(ICompressSetInStream) - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - Z7_IFACE_COM7_IMP_NONFINAL(ISequentialInStream) -#endif -public: -#ifndef Z7_ST - Z7_IFACE_COM7_IMP(ICompressSetCoderMt) -#endif - -private: - Byte *_outBuf; - size_t _outPos; - UInt64 _outWritten; - ISequentialOutStream *_outStream; - HRESULT _writeRes; - -protected: - HRESULT ErrorResult; // for ISequentialInStream::Read mode only - -public: - - UInt32 _calcedBlockCrc; - bool _blockFinished; - bool BlockCrcError; - - bool FinishMode; - bool _outSizeDefined; - UInt64 _outSize; - UInt64 _outPosTotal; - - CSpecState _spec; - UInt32 *_counters; - - #ifndef Z7_ST - - struct CBlock - { - bool StopScout; - - bool WasFinished; - bool Crc_Defined; - // bool NextCrc_Defined; - - UInt32 Crc; - UInt32 NextCrc; - HRESULT Res; - UInt64 PackPos; - - CBlockProps Props; - }; - - CBlock _block; - - bool NeedWaitScout; - bool MtMode; - - NWindows::CThread Thread; - NWindows::NSynchronization::CAutoResetEvent DecoderEvent; - NWindows::NSynchronization::CAutoResetEvent ScoutEvent; - // HRESULT ScoutRes; - - Byte MtPad[1 << 7]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. - - - void RunScout(); - - void WaitScout() - { - if (NeedWaitScout) - { - DecoderEvent.Lock(); - NeedWaitScout = false; - } - } - - class CWaitScout_Releaser - { - CDecoder *_decoder; - public: - CWaitScout_Releaser(CDecoder *decoder): _decoder(decoder) {} - ~CWaitScout_Releaser() { _decoder->WaitScout(); } - }; - - HRESULT CreateThread(); - - #endif - - Byte *_inBuf; - UInt64 _inProcessed; - bool _inputFinished; - HRESULT _inputRes; - - CBase Base; - - bool GetCrcError() const { return BlockCrcError || Base.StreamCrcError; } - - void InitOutSize(const UInt64 *outSize); - - bool CreateInputBufer(); - - void InitInputBuffer() - { - // We use InitInputBuffer() before stream init. - // So don't read from stream here - _inProcessed = 0; - Base._buf = _inBuf; - Base._lim = _inBuf; - Base.InitBitDecoder(); - } - - UInt64 GetInputProcessedSize() const - { - // for NSIS case : we need also look the number of bits in bitDecoder - return _inProcessed + (size_t)(Base._buf - _inBuf); - } - - UInt64 GetInStreamSize() const - { - return _inProcessed + (size_t)(Base._buf - _inBuf) - (Base._numBits >> 3); - } - - UInt64 GetOutProcessedSize() const { return _outWritten + _outPos; } - - HRESULT ReadInput(); - - void StartNewStream(); - - HRESULT ReadStreamSignature(); - HRESULT StartRead(); - - HRESULT ReadBlockSignature(); - HRESULT ReadBlock(); - - HRESULT Flush(); - HRESULT DecodeBlock(const CBlockProps &props); - HRESULT DecodeStreams(ICompressProgressInfo *progress); - - UInt64 GetNumStreams() const { return Base.NumStreams; } - UInt64 GetNumBlocks() const { return Base.NumBlocks; } - - CDecoder(); - virtual ~CDecoder(); -}; - - - -#ifndef Z7_NO_READ_FROM_CODER - -class CNsisDecoder Z7_final: public CDecoder -{ - Z7_IFACE_COM7_IMP(ISequentialInStream) -}; - -#endif - -}} - -#endif +// Compress/BZip2Decoder.h + +#ifndef ZIP7_INC_COMPRESS_BZIP2_DECODER_H +#define ZIP7_INC_COMPRESS_BZIP2_DECODER_H + +#include "../../Common/MyCom.h" + +// #define Z7_NO_READ_FROM_CODER +// #define Z7_ST + +#ifndef Z7_ST +#include "../../Windows/Synchronization.h" +#include "../../Windows/Thread.h" +#endif + +#include "../ICoder.h" + +#include "BZip2Const.h" +#include "BZip2Crc.h" +#include "HuffmanDecoder.h" +#include "Mtf8.h" + +namespace NCompress { +namespace NBZip2 { + +bool IsEndSig(const Byte *p) throw(); +bool IsBlockSig(const Byte *p) throw(); + +const unsigned kNumTableBits = 9; + +typedef NHuffman::CDecoder CHuffmanDecoder; + + +struct CBlockProps +{ + UInt32 blockSize; + UInt32 origPtr; + unsigned randMode; + + CBlockProps(): blockSize(0), origPtr(0), randMode(0) {} +}; + + +struct CBitDecoder +{ + unsigned _numBits; + UInt32 _value; + const Byte *_buf; + const Byte *_lim; + + void InitBitDecoder() + { + _numBits = 0; + _value = 0; + } + + void AlignToByte() + { + unsigned bits = _numBits & 7; + _numBits -= bits; + _value <<= bits; + } + + /* + bool AreRemainByteBitsEmpty() const + { + unsigned bits = _numBits & 7; + if (bits != 0) + return (_value >> (32 - bits)) == 0; + return true; + } + */ + + SRes ReadByte(int &b); + + CBitDecoder(): + _buf(NULL), + _lim(NULL) + { + InitBitDecoder(); + } +}; + + +// 19.03: we allow additional 8 selectors to support files created by lbzip2. +const UInt32 kNumSelectorsMax_Decoder = kNumSelectorsMax + 8; + +struct CBase: public CBitDecoder +{ + unsigned numInUse; + UInt32 groupIndex; + UInt32 groupSize; + unsigned runPower; + UInt32 runCounter; + UInt32 blockSize; + + UInt32 *Counters; + UInt32 blockSizeMax; + + unsigned state; + UInt32 state2; + unsigned state3; + unsigned state4; + unsigned state5; + unsigned numTables; + UInt32 numSelectors; + + CBlockProps Props; + +private: + CMtf8Decoder mtf; + Byte selectors[kNumSelectorsMax_Decoder]; + CHuffmanDecoder huffs[kNumTablesMax]; + + Byte lens[kMaxAlphaSize]; + + Byte temp[10]; + +public: + UInt32 crc; + CBZip2CombinedCrc CombinedCrc; + + bool IsBz; + bool StreamCrcError; + bool MinorError; + bool NeedMoreInput; + + bool DecodeAllStreams; + + UInt64 NumStreams; + UInt64 NumBlocks; + UInt64 FinishedPackSize; + + ISequentialInStream *InStream; + + #ifndef Z7_NO_READ_FROM_CODER + CMyComPtr InStreamRef; + #endif + + CBase(): + StreamCrcError(false), + MinorError(false), + NeedMoreInput(false), + + DecodeAllStreams(false), + + NumStreams(0), + NumBlocks(0), + FinishedPackSize(0) + {} + + void InitNumStreams2() + { + StreamCrcError = false; + MinorError = false; + NeedMoreInput = 0; + NumStreams = 0; + NumBlocks = 0; + FinishedPackSize = 0; + } + + SRes ReadStreamSignature2(); + SRes ReadBlockSignature2(); + + /* ReadBlock2() : Props->randMode: + in: need read randMode bit + out: randMode status */ + SRes ReadBlock2(); +}; + + +class CSpecState +{ + UInt32 _tPos; + unsigned _prevByte; + int _reps; + +public: + CBZip2Crc _crc; + UInt32 _blockSize; + UInt32 *_tt; + + int _randToGo; + unsigned _randIndex; + + void Init(UInt32 origPtr, unsigned randMode) throw(); + + bool Finished() const { return _reps <= 0 && _blockSize == 0; } + + Byte *Decode(Byte *data, size_t size) throw(); +}; + + + + +class CDecoder: + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public ICompressReadUnusedFromInBuf, +#ifndef Z7_NO_READ_FROM_CODER + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, +#endif +#ifndef Z7_ST + public ICompressSetCoderMt, +#endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf) +#ifndef Z7_NO_READ_FROM_CODER + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ISequentialInStream) +#endif +#ifndef Z7_ST + Z7_COM_QI_ENTRY(ICompressSetCoderMt) +#endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) + Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf) +#ifndef Z7_NO_READ_FROM_CODER + Z7_IFACE_COM7_IMP(ICompressSetInStream) + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + Z7_IFACE_COM7_IMP_NONFINAL(ISequentialInStream) +#endif +public: +#ifndef Z7_ST + Z7_IFACE_COM7_IMP(ICompressSetCoderMt) +#endif + +private: + Byte *_outBuf; + size_t _outPos; + UInt64 _outWritten; + ISequentialOutStream *_outStream; + HRESULT _writeRes; + +protected: + HRESULT ErrorResult; // for ISequentialInStream::Read mode only + +public: + + UInt32 _calcedBlockCrc; + bool _blockFinished; + bool BlockCrcError; + + bool FinishMode; + bool _outSizeDefined; + UInt64 _outSize; + UInt64 _outPosTotal; + + CSpecState _spec; + UInt32 *_counters; + + #ifndef Z7_ST + + struct CBlock + { + bool StopScout; + + bool WasFinished; + bool Crc_Defined; + // bool NextCrc_Defined; + + UInt32 Crc; + UInt32 NextCrc; + HRESULT Res; + UInt64 PackPos; + + CBlockProps Props; + }; + + CBlock _block; + + bool NeedWaitScout; + bool MtMode; + + NWindows::CThread Thread; + NWindows::NSynchronization::CAutoResetEvent DecoderEvent; + NWindows::NSynchronization::CAutoResetEvent ScoutEvent; + // HRESULT ScoutRes; + + Byte MtPad[1 << 7]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. + + + void RunScout(); + + void WaitScout() + { + if (NeedWaitScout) + { + DecoderEvent.Lock(); + NeedWaitScout = false; + } + } + + class CWaitScout_Releaser + { + CDecoder *_decoder; + public: + CWaitScout_Releaser(CDecoder *decoder): _decoder(decoder) {} + ~CWaitScout_Releaser() { _decoder->WaitScout(); } + }; + + HRESULT CreateThread(); + + #endif + + Byte *_inBuf; + UInt64 _inProcessed; + bool _inputFinished; + HRESULT _inputRes; + + CBase Base; + + bool GetCrcError() const { return BlockCrcError || Base.StreamCrcError; } + + void InitOutSize(const UInt64 *outSize); + + bool CreateInputBufer(); + + void InitInputBuffer() + { + // We use InitInputBuffer() before stream init. + // So don't read from stream here + _inProcessed = 0; + Base._buf = _inBuf; + Base._lim = _inBuf; + Base.InitBitDecoder(); + } + + UInt64 GetInputProcessedSize() const + { + // for NSIS case : we need also look the number of bits in bitDecoder + return _inProcessed + (size_t)(Base._buf - _inBuf); + } + + UInt64 GetInStreamSize() const + { + return _inProcessed + (size_t)(Base._buf - _inBuf) - (Base._numBits >> 3); + } + + UInt64 GetOutProcessedSize() const { return _outWritten + _outPos; } + + HRESULT ReadInput(); + + void StartNewStream(); + + HRESULT ReadStreamSignature(); + HRESULT StartRead(); + + HRESULT ReadBlockSignature(); + HRESULT ReadBlock(); + + HRESULT Flush(); + HRESULT DecodeBlock(const CBlockProps &props); + HRESULT DecodeStreams(ICompressProgressInfo *progress); + + UInt64 GetNumStreams() const { return Base.NumStreams; } + UInt64 GetNumBlocks() const { return Base.NumBlocks; } + + CDecoder(); + virtual ~CDecoder(); +}; + + + +#ifndef Z7_NO_READ_FROM_CODER + +class CNsisDecoder Z7_final: public CDecoder +{ + Z7_IFACE_COM7_IMP(ISequentialInStream) +}; + +#endif + +}} + +#endif diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp index f9cc113c5..ef2555a01 100644 --- a/CPP/7zip/Compress/BZip2Encoder.cpp +++ b/CPP/7zip/Compress/BZip2Encoder.cpp @@ -1,919 +1,919 @@ -// BZip2Encoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/BwtSort.h" -#include "../../../C/HuffEnc.h" - -#include "BZip2Crc.h" -#include "BZip2Encoder.h" -#include "Mtf8.h" - -namespace NCompress { -namespace NBZip2 { - -const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20 - -static const UInt32 kBufferSize = (1 << 17); -static const unsigned kNumHuffPasses = 4; - -bool CThreadInfo::Alloc() -{ - if (!m_BlockSorterIndex) - { - m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32)); - if (!m_BlockSorterIndex) - return false; - } - - if (!m_Block) - { - m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); - if (!m_Block) - return false; - m_MtfArray = m_Block + kBlockSizeMax; - m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; - } - return true; -} - -void CThreadInfo::Free() -{ - ::BigFree(m_BlockSorterIndex); - m_BlockSorterIndex = NULL; - ::MidFree(m_Block); - m_Block = NULL; -} - -#ifndef Z7_ST - -static THREAD_FUNC_DECL MFThread(void *threadCoderInfo) -{ - return ((CThreadInfo *)threadCoderInfo)->ThreadFunc(); -} - -HRESULT CThreadInfo::Create() -{ - WRes wres = StreamWasFinishedEvent.Create(); - if (wres == 0) { wres = WaitingWasStartedEvent.Create(); - if (wres == 0) { wres = CanWriteEvent.Create(); - if (wres == 0) - { - if (Encoder->_props.Affinity != 0) - wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); - else - wres = Thread.Create(MFThread, this); - }}} - return HRESULT_FROM_WIN32(wres); -} - -void CThreadInfo::FinishStream(bool needLeave) -{ - Encoder->StreamWasFinished = true; - StreamWasFinishedEvent.Set(); - if (needLeave) - Encoder->CS.Leave(); - Encoder->CanStartWaitingEvent.Lock(); - WaitingWasStartedEvent.Set(); -} - -THREAD_FUNC_RET_TYPE CThreadInfo::ThreadFunc() -{ - for (;;) - { - Encoder->CanProcessEvent.Lock(); - Encoder->CS.Enter(); - if (Encoder->CloseThreads) - { - Encoder->CS.Leave(); - return 0; - } - if (Encoder->StreamWasFinished) - { - FinishStream(true); - continue; - } - HRESULT res = S_OK; - bool needLeave = true; - try - { - const UInt32 blockSize = Encoder->ReadRleBlock(m_Block); - m_UnpackSize = Encoder->m_InStream.GetProcessedSize(); - m_BlockIndex = Encoder->NextBlockIndex; - if (++Encoder->NextBlockIndex == Encoder->NumThreads) - Encoder->NextBlockIndex = 0; - if (blockSize == 0) - { - FinishStream(true); - continue; - } - Encoder->CS.Leave(); - needLeave = false; - res = EncodeBlock3(blockSize); - } - catch(const CInBufferException &e) { res = e.ErrorCode; } - catch(const COutBufferException &e) { res = e.ErrorCode; } - catch(...) { res = E_FAIL; } - if (res != S_OK) - { - Encoder->Result = res; - FinishStream(needLeave); - continue; - } - } -} - -#endif - -void CEncProps::Normalize(int level) -{ - if (level < 0) level = 5; - if (level > 9) level = 9; - - if (NumPasses == (UInt32)(Int32)-1) - NumPasses = (level >= 9 ? 7 : (level >= 7 ? 2 : 1)); - if (NumPasses < 1) NumPasses = 1; - if (NumPasses > kNumPassesMax) NumPasses = kNumPassesMax; - - if (BlockSizeMult == (UInt32)(Int32)-1) - BlockSizeMult = (level >= 5 ? 9 : (level >= 1 ? (unsigned)level * 2 - 1: 1)); - if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin; - if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax; -} - -CEncoder::CEncoder() -{ - _props.Normalize(-1); - - #ifndef Z7_ST - ThreadsInfo = NULL; - m_NumThreadsPrev = 0; - NumThreads = 1; - #endif -} - -#ifndef Z7_ST -CEncoder::~CEncoder() -{ - Free(); -} - -HRESULT CEncoder::Create() -{ - { - WRes wres = CanProcessEvent.CreateIfNotCreated_Reset(); - if (wres == 0) { wres = CanStartWaitingEvent.CreateIfNotCreated_Reset(); } - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - - if (ThreadsInfo && m_NumThreadsPrev == NumThreads) - return S_OK; - try - { - Free(); - MtMode = (NumThreads > 1); - m_NumThreadsPrev = NumThreads; - ThreadsInfo = new CThreadInfo[NumThreads]; - if (!ThreadsInfo) - return E_OUTOFMEMORY; - } - catch(...) { return E_OUTOFMEMORY; } - for (UInt32 t = 0; t < NumThreads; t++) - { - CThreadInfo &ti = ThreadsInfo[t]; - ti.Encoder = this; - if (MtMode) - { - HRESULT res = ti.Create(); - if (res != S_OK) - { - NumThreads = t; - Free(); - return res; - } - } - } - return S_OK; -} - -void CEncoder::Free() -{ - if (!ThreadsInfo) - return; - CloseThreads = true; - CanProcessEvent.Set(); - for (UInt32 t = 0; t < NumThreads; t++) - { - CThreadInfo &ti = ThreadsInfo[t]; - if (MtMode) - ti.Thread.Wait_Close(); - ti.Free(); - } - delete []ThreadsInfo; - ThreadsInfo = NULL; -} -#endif - -UInt32 CEncoder::ReadRleBlock(Byte *buffer) -{ - UInt32 i = 0; - Byte prevByte; - if (m_InStream.ReadByte(prevByte)) - { - NumBlocks++; - const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; - unsigned numReps = 1; - buffer[i++] = prevByte; - while (i < blockSize) // "- 1" to support RLE - { - Byte b; - if (!m_InStream.ReadByte(b)) - break; - if (b != prevByte) - { - if (numReps >= kRleModeRepSize) - buffer[i++] = (Byte)(numReps - kRleModeRepSize); - buffer[i++] = b; - numReps = 1; - prevByte = b; - continue; - } - numReps++; - if (numReps <= kRleModeRepSize) - buffer[i++] = b; - else if (numReps == kRleModeRepSize + 255) - { - buffer[i++] = (Byte)(numReps - kRleModeRepSize); - numReps = 0; - } - } - // it's to support original BZip2 decoder - if (numReps >= kRleModeRepSize) - buffer[i++] = (Byte)(numReps - kRleModeRepSize); - } - return i; -} - -void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); } -void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); } -void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); } -void CThreadInfo::WriteCrc2(UInt32 v) -{ - for (unsigned i = 0; i < 4; i++) - WriteByte2(((Byte)(v >> (24 - i * 8)))); -} - -void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); } -void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); } -// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); } -void CEncoder::WriteCrc(UInt32 v) -{ - for (unsigned i = 0; i < 4; i++) - WriteByte(((Byte)(v >> (24 - i * 8)))); -} - - -// blockSize > 0 -void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) -{ - WriteBit2(0); // Randomised = false - - { - UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize); - // if (m_BlockSorterIndex[origPtr] != 0) throw 1; - m_BlockSorterIndex[origPtr] = blockSize; - WriteBits2(origPtr, kNumOrigBits); - } - - CMtf8Encoder mtf; - unsigned numInUse = 0; - { - Byte inUse[256]; - Byte inUse16[16]; - UInt32 i; - for (i = 0; i < 256; i++) - inUse[i] = 0; - for (i = 0; i < 16; i++) - inUse16[i] = 0; - for (i = 0; i < blockSize; i++) - inUse[block[i]] = 1; - for (i = 0; i < 256; i++) - if (inUse[i]) - { - inUse16[i >> 4] = 1; - mtf.Buf[numInUse++] = (Byte)i; - } - for (i = 0; i < 16; i++) - WriteBit2(inUse16[i]); - for (i = 0; i < 256; i++) - if (inUse16[i >> 4]) - WriteBit2(inUse[i]); - } - unsigned alphaSize = numInUse + 2; - - Byte *mtfs = m_MtfArray; - UInt32 mtfArraySize = 0; - UInt32 symbolCounts[kMaxAlphaSize]; - { - for (unsigned i = 0; i < kMaxAlphaSize; i++) - symbolCounts[i] = 0; - } - - { - UInt32 rleSize = 0; - UInt32 i = 0; - const UInt32 *bsIndex = m_BlockSorterIndex; - block--; - do - { - unsigned pos = mtf.FindAndMove(block[bsIndex[i]]); - if (pos == 0) - rleSize++; - else - { - while (rleSize != 0) - { - rleSize--; - mtfs[mtfArraySize++] = (Byte)(rleSize & 1); - symbolCounts[rleSize & 1]++; - rleSize >>= 1; - } - if (pos >= 0xFE) - { - mtfs[mtfArraySize++] = 0xFF; - mtfs[mtfArraySize++] = (Byte)(pos - 0xFE); - } - else - mtfs[mtfArraySize++] = (Byte)(pos + 1); - symbolCounts[(size_t)pos + 1]++; - } - } - while (++i < blockSize); - - while (rleSize != 0) - { - rleSize--; - mtfs[mtfArraySize++] = (Byte)(rleSize & 1); - symbolCounts[rleSize & 1]++; - rleSize >>= 1; - } - - if (alphaSize < 256) - mtfs[mtfArraySize++] = (Byte)(alphaSize - 1); - else - { - mtfs[mtfArraySize++] = 0xFF; - mtfs[mtfArraySize++] = (Byte)(alphaSize - 256); - } - symbolCounts[(size_t)alphaSize - 1]++; - } - - UInt32 numSymbols = 0; - { - for (unsigned i = 0; i < kMaxAlphaSize; i++) - numSymbols += symbolCounts[i]; - } - - unsigned bestNumTables = kNumTablesMin; - UInt32 bestPrice = 0xFFFFFFFF; - UInt32 startPos = m_OutStreamCurrent->GetPos(); - Byte startCurByte = m_OutStreamCurrent->GetCurByte(); - for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) - { - unsigned numTables; - - if (m_OptimizeNumTables) - { - m_OutStreamCurrent->SetPos(startPos); - m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); - if (nt <= kNumTablesMax) - numTables = nt; - else - numTables = bestNumTables; - } - else - { - if (numSymbols < 200) numTables = 2; - else if (numSymbols < 600) numTables = 3; - else if (numSymbols < 1200) numTables = 4; - else if (numSymbols < 2400) numTables = 5; - else numTables = 6; - } - - WriteBits2(numTables, kNumTablesBits); - - UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; - WriteBits2(numSelectors, kNumSelectorsBits); - - { - UInt32 remFreq = numSymbols; - unsigned gs = 0; - unsigned t = numTables; - do - { - UInt32 tFreq = remFreq / t; - unsigned ge = gs; - UInt32 aFreq = 0; - while (aFreq < tFreq) // && ge < alphaSize) - aFreq += symbolCounts[ge++]; - - if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1)) - aFreq -= symbolCounts[--ge]; - - Byte *lens = Lens[(size_t)t - 1]; - unsigned i = 0; - do - lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1); - while (++i < alphaSize); - gs = ge; - remFreq -= aFreq; - } - while (--t != 0); - } - - - for (unsigned pass = 0; pass < kNumHuffPasses; pass++) - { - { - unsigned t = 0; - do - memset(Freqs[t], 0, sizeof(Freqs[t])); - while (++t < numTables); - } - - { - UInt32 mtfPos = 0; - UInt32 g = 0; - do - { - UInt32 symbols[kGroupSize]; - unsigned i = 0; - do - { - UInt32 symbol = mtfs[mtfPos++]; - if (symbol >= 0xFF) - symbol += mtfs[mtfPos++]; - symbols[i] = symbol; - } - while (++i < kGroupSize && mtfPos < mtfArraySize); - - UInt32 bestPrice2 = 0xFFFFFFFF; - unsigned t = 0; - do - { - const Byte *lens = Lens[t]; - UInt32 price = 0; - unsigned j = 0; - do - price += lens[symbols[j]]; - while (++j < i); - if (price < bestPrice2) - { - m_Selectors[g] = (Byte)t; - bestPrice2 = price; - } - } - while (++t < numTables); - UInt32 *freqs = Freqs[m_Selectors[g++]]; - unsigned j = 0; - do - freqs[symbols[j]]++; - while (++j < i); - } - while (mtfPos < mtfArraySize); - } - - unsigned t = 0; - do - { - UInt32 *freqs = Freqs[t]; - unsigned i = 0; - do - if (freqs[i] == 0) - freqs[i] = 1; - while (++i < alphaSize); - Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding); - } - while (++t < numTables); - } - - { - Byte mtfSel[kNumTablesMax]; - { - unsigned t = 0; - do - mtfSel[t] = (Byte)t; - while (++t < numTables); - } - - UInt32 i = 0; - do - { - Byte sel = m_Selectors[i]; - unsigned pos; - for (pos = 0; mtfSel[pos] != sel; pos++) - WriteBit2(1); - WriteBit2(0); - for (; pos > 0; pos--) - mtfSel[pos] = mtfSel[(size_t)pos - 1]; - mtfSel[0] = sel; - } - while (++i < numSelectors); - } - - { - unsigned t = 0; - do - { - const Byte *lens = Lens[t]; - UInt32 len = lens[0]; - WriteBits2(len, kNumLevelsBits); - unsigned i = 0; - do - { - UInt32 level = lens[i]; - while (len != level) - { - WriteBit2(1); - if (len < level) - { - WriteBit2(0); - len++; - } - else - { - WriteBit2(1); - len--; - } - } - WriteBit2(0); - } - while (++i < alphaSize); - } - while (++t < numTables); - } - - { - UInt32 groupSize = 0; - UInt32 groupIndex = 0; - const Byte *lens = NULL; - const UInt32 *codes = NULL; - UInt32 mtfPos = 0; - do - { - UInt32 symbol = mtfs[mtfPos++]; - if (symbol >= 0xFF) - symbol += mtfs[mtfPos++]; - if (groupSize == 0) - { - groupSize = kGroupSize; - unsigned t = m_Selectors[groupIndex++]; - lens = Lens[t]; - codes = Codes[t]; - } - groupSize--; - m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]); - } - while (mtfPos < mtfArraySize); - } - - if (!m_OptimizeNumTables) - break; - UInt32 price = m_OutStreamCurrent->GetPos() - startPos; - if (price <= bestPrice) - { - if (nt == kNumTablesMax) - break; - bestPrice = price; - bestNumTables = nt; - } - } -} - -// blockSize > 0 -UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) -{ - WriteByte2(kBlockSig0); - WriteByte2(kBlockSig1); - WriteByte2(kBlockSig2); - WriteByte2(kBlockSig3); - WriteByte2(kBlockSig4); - WriteByte2(kBlockSig5); - - CBZip2Crc crc; - unsigned numReps = 0; - Byte prevByte = block[0]; - UInt32 i = 0; - do - { - Byte b = block[i]; - if (numReps == kRleModeRepSize) - { - for (; b > 0; b--) - crc.UpdateByte(prevByte); - numReps = 0; - continue; - } - if (prevByte == b) - numReps++; - else - { - numReps = 1; - prevByte = b; - } - crc.UpdateByte(b); - } - while (++i < blockSize); - UInt32 crcRes = crc.GetDigest(); - WriteCrc2(crcRes); - EncodeBlock(block, blockSize); - return crcRes; -} - -void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses) -{ - UInt32 numCrcs = m_NumCrcs; - bool needCompare = false; - - UInt32 startBytePos = m_OutStreamCurrent->GetBytePos(); - UInt32 startPos = m_OutStreamCurrent->GetPos(); - Byte startCurByte = m_OutStreamCurrent->GetCurByte(); - Byte endCurByte = 0; - UInt32 endPos = 0; - if (numPasses > 1 && blockSize >= (1 << 10)) - { - UInt32 blockSize0 = blockSize / 2; // ???? - - for (; (block[blockSize0] == block[(size_t)blockSize0 - 1] - || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2]) - && blockSize0 < blockSize; - blockSize0++); - - if (blockSize0 < blockSize) - { - EncodeBlock2(block, blockSize0, numPasses - 1); - EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1); - endPos = m_OutStreamCurrent->GetPos(); - endCurByte = m_OutStreamCurrent->GetCurByte(); - if ((endPos & 7) > 0) - WriteBits2(0, 8 - (endPos & 7)); - m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); - needCompare = true; - } - } - - UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos(); - UInt32 startPos2 = m_OutStreamCurrent->GetPos(); - UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize); - UInt32 endPos2 = m_OutStreamCurrent->GetPos(); - - if (needCompare) - { - UInt32 size2 = endPos2 - startPos2; - if (size2 < endPos - startPos) - { - UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2; - Byte *buffer = m_OutStreamCurrent->GetStream(); - for (UInt32 i = 0; i < numBytes; i++) - buffer[startBytePos + i] = buffer[startBytePos2 + i]; - m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2); - m_NumCrcs = numCrcs; - m_CRCs[m_NumCrcs++] = crcVal; - } - else - { - m_OutStreamCurrent->SetPos(endPos); - m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte); - } - } - else - { - m_NumCrcs = numCrcs; - m_CRCs[m_NumCrcs++] = crcVal; - } -} - -HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize) -{ - CMsbfEncoderTemp outStreamTemp; - outStreamTemp.SetStream(m_TempArray); - outStreamTemp.Init(); - m_OutStreamCurrent = &outStreamTemp; - - m_NumCrcs = 0; - - EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses); - - #ifndef Z7_ST - if (Encoder->MtMode) - Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); - #endif - for (UInt32 i = 0; i < m_NumCrcs; i++) - Encoder->CombinedCrc.Update(m_CRCs[i]); - Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); - HRESULT res = S_OK; - #ifndef Z7_ST - if (Encoder->MtMode) - { - UInt32 blockIndex = m_BlockIndex + 1; - if (blockIndex == Encoder->NumThreads) - blockIndex = 0; - - if (Encoder->Progress) - { - const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); - res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); - } - - Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); - } - #endif - return res; -} - -void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) -{ - UInt32 bytesSize = (sizeInBits >> 3); - for (UInt32 i = 0; i < bytesSize; i++) - m_OutStream.WriteBits(data[i], 8); - WriteBits(lastByte, (sizeInBits & 7)); -} - - -HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) -{ - NumBlocks = 0; - #ifndef Z7_ST - Progress = progress; - RINOK(Create()) - for (UInt32 t = 0; t < NumThreads; t++) - #endif - { - #ifndef Z7_ST - CThreadInfo &ti = ThreadsInfo[t]; - if (MtMode) - { - WRes wres = ti.StreamWasFinishedEvent.Reset(); - if (wres == 0) { wres = ti.WaitingWasStartedEvent.Reset(); - if (wres == 0) { wres = ti.CanWriteEvent.Reset(); }} - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - #else - CThreadInfo &ti = ThreadsInfo; - ti.Encoder = this; - #endif - - ti.m_OptimizeNumTables = _props.DoOptimizeNumTables(); - - if (!ti.Alloc()) - return E_OUTOFMEMORY; - } - - - if (!m_InStream.Create(kBufferSize)) - return E_OUTOFMEMORY; - if (!m_OutStream.Create(kBufferSize)) - return E_OUTOFMEMORY; - - - m_InStream.SetStream(inStream); - m_InStream.Init(); - - m_OutStream.SetStream(outStream); - m_OutStream.Init(); - - CombinedCrc.Init(); - #ifndef Z7_ST - NextBlockIndex = 0; - StreamWasFinished = false; - CloseThreads = false; - CanStartWaitingEvent.Reset(); - #endif - - WriteByte(kArSig0); - WriteByte(kArSig1); - WriteByte(kArSig2); - WriteByte((Byte)(kArSig3 + _props.BlockSizeMult)); - - #ifndef Z7_ST - - if (MtMode) - { - ThreadsInfo[0].CanWriteEvent.Set(); - Result = S_OK; - CanProcessEvent.Set(); - UInt32 t; - for (t = 0; t < NumThreads; t++) - ThreadsInfo[t].StreamWasFinishedEvent.Lock(); - CanProcessEvent.Reset(); - CanStartWaitingEvent.Set(); - for (t = 0; t < NumThreads; t++) - ThreadsInfo[t].WaitingWasStartedEvent.Lock(); - CanStartWaitingEvent.Reset(); - RINOK(Result) - } - else - #endif - { - for (;;) - { - CThreadInfo &ti = - #ifndef Z7_ST - ThreadsInfo[0]; - #else - ThreadsInfo; - #endif - UInt32 blockSize = ReadRleBlock(ti.m_Block); - if (blockSize == 0) - break; - RINOK(ti.EncodeBlock3(blockSize)) - if (progress) - { - const UInt64 unpackSize = m_InStream.GetProcessedSize(); - const UInt64 packSize = m_OutStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&unpackSize, &packSize)) - } - } - } - WriteByte(kFinSig0); - WriteByte(kFinSig1); - WriteByte(kFinSig2); - WriteByte(kFinSig3); - WriteByte(kFinSig4); - WriteByte(kFinSig5); - - WriteCrc(CombinedCrc.GetDigest()); - RINOK(Flush()) - if (!m_InStream.WasFinished()) - return E_FAIL; - return S_OK; -} - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const COutBufferException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - int level = -1; - CEncProps props; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - PROPID propID = propIDs[i]; - - if (propID == NCoderPropID::kAffinity) - { - if (prop.vt == VT_UI8) - props.Affinity = prop.uhVal.QuadPart; - else - return E_INVALIDARG; - continue; - } - - if (propID >= NCoderPropID::kReduceSize) - continue; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - UInt32 v = (UInt32)prop.ulVal; - switch (propID) - { - case NCoderPropID::kNumPasses: props.NumPasses = v; break; - case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break; - case NCoderPropID::kLevel: level = (int)v; break; - case NCoderPropID::kNumThreads: - { - #ifndef Z7_ST - SetNumberOfThreads(v); - #endif - break; - } - default: return E_INVALIDARG; - } - } - props.Normalize(level); - _props = props; - return S_OK; -} - -#ifndef Z7_ST -Z7_COM7F_IMF(CEncoder::SetNumberOfThreads(UInt32 numThreads)) -{ - const UInt32 kNumThreadsMax = 64; - if (numThreads < 1) numThreads = 1; - if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax; - NumThreads = numThreads; - return S_OK; -} -#endif - -}} +// BZip2Encoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/BwtSort.h" +#include "../../../C/HuffEnc.h" + +#include "BZip2Crc.h" +#include "BZip2Encoder.h" +#include "Mtf8.h" + +namespace NCompress { +namespace NBZip2 { + +const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20 + +static const UInt32 kBufferSize = (1 << 17); +static const unsigned kNumHuffPasses = 4; + +bool CThreadInfo::Alloc() +{ + if (!m_BlockSorterIndex) + { + m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32)); + if (!m_BlockSorterIndex) + return false; + } + + if (!m_Block) + { + m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10)); + if (!m_Block) + return false; + m_MtfArray = m_Block + kBlockSizeMax; + m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2; + } + return true; +} + +void CThreadInfo::Free() +{ + ::BigFree(m_BlockSorterIndex); + m_BlockSorterIndex = NULL; + ::MidFree(m_Block); + m_Block = NULL; +} + +#ifndef Z7_ST + +static THREAD_FUNC_DECL MFThread(void *threadCoderInfo) +{ + return ((CThreadInfo *)threadCoderInfo)->ThreadFunc(); +} + +HRESULT CThreadInfo::Create() +{ + WRes wres = StreamWasFinishedEvent.Create(); + if (wres == 0) { wres = WaitingWasStartedEvent.Create(); + if (wres == 0) { wres = CanWriteEvent.Create(); + if (wres == 0) + { + if (Encoder->_props.Affinity != 0) + wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity); + else + wres = Thread.Create(MFThread, this); + }}} + return HRESULT_FROM_WIN32(wres); +} + +void CThreadInfo::FinishStream(bool needLeave) +{ + Encoder->StreamWasFinished = true; + StreamWasFinishedEvent.Set(); + if (needLeave) + Encoder->CS.Leave(); + Encoder->CanStartWaitingEvent.Lock(); + WaitingWasStartedEvent.Set(); +} + +THREAD_FUNC_RET_TYPE CThreadInfo::ThreadFunc() +{ + for (;;) + { + Encoder->CanProcessEvent.Lock(); + Encoder->CS.Enter(); + if (Encoder->CloseThreads) + { + Encoder->CS.Leave(); + return 0; + } + if (Encoder->StreamWasFinished) + { + FinishStream(true); + continue; + } + HRESULT res = S_OK; + bool needLeave = true; + try + { + const UInt32 blockSize = Encoder->ReadRleBlock(m_Block); + m_UnpackSize = Encoder->m_InStream.GetProcessedSize(); + m_BlockIndex = Encoder->NextBlockIndex; + if (++Encoder->NextBlockIndex == Encoder->NumThreads) + Encoder->NextBlockIndex = 0; + if (blockSize == 0) + { + FinishStream(true); + continue; + } + Encoder->CS.Leave(); + needLeave = false; + res = EncodeBlock3(blockSize); + } + catch(const CInBufferException &e) { res = e.ErrorCode; } + catch(const COutBufferException &e) { res = e.ErrorCode; } + catch(...) { res = E_FAIL; } + if (res != S_OK) + { + Encoder->Result = res; + FinishStream(needLeave); + continue; + } + } +} + +#endif + +void CEncProps::Normalize(int level) +{ + if (level < 0) level = 5; + if (level > 9) level = 9; + + if (NumPasses == (UInt32)(Int32)-1) + NumPasses = (level >= 9 ? 7 : (level >= 7 ? 2 : 1)); + if (NumPasses < 1) NumPasses = 1; + if (NumPasses > kNumPassesMax) NumPasses = kNumPassesMax; + + if (BlockSizeMult == (UInt32)(Int32)-1) + BlockSizeMult = (level >= 5 ? 9 : (level >= 1 ? (unsigned)level * 2 - 1: 1)); + if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin; + if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax; +} + +CEncoder::CEncoder() +{ + _props.Normalize(-1); + + #ifndef Z7_ST + ThreadsInfo = NULL; + m_NumThreadsPrev = 0; + NumThreads = 1; + #endif +} + +#ifndef Z7_ST +CEncoder::~CEncoder() +{ + Free(); +} + +HRESULT CEncoder::Create() +{ + { + WRes wres = CanProcessEvent.CreateIfNotCreated_Reset(); + if (wres == 0) { wres = CanStartWaitingEvent.CreateIfNotCreated_Reset(); } + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + + if (ThreadsInfo && m_NumThreadsPrev == NumThreads) + return S_OK; + try + { + Free(); + MtMode = (NumThreads > 1); + m_NumThreadsPrev = NumThreads; + ThreadsInfo = new CThreadInfo[NumThreads]; + if (!ThreadsInfo) + return E_OUTOFMEMORY; + } + catch(...) { return E_OUTOFMEMORY; } + for (UInt32 t = 0; t < NumThreads; t++) + { + CThreadInfo &ti = ThreadsInfo[t]; + ti.Encoder = this; + if (MtMode) + { + HRESULT res = ti.Create(); + if (res != S_OK) + { + NumThreads = t; + Free(); + return res; + } + } + } + return S_OK; +} + +void CEncoder::Free() +{ + if (!ThreadsInfo) + return; + CloseThreads = true; + CanProcessEvent.Set(); + for (UInt32 t = 0; t < NumThreads; t++) + { + CThreadInfo &ti = ThreadsInfo[t]; + if (MtMode) + ti.Thread.Wait_Close(); + ti.Free(); + } + delete []ThreadsInfo; + ThreadsInfo = NULL; +} +#endif + +UInt32 CEncoder::ReadRleBlock(Byte *buffer) +{ + UInt32 i = 0; + Byte prevByte; + if (m_InStream.ReadByte(prevByte)) + { + NumBlocks++; + const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; + unsigned numReps = 1; + buffer[i++] = prevByte; + while (i < blockSize) // "- 1" to support RLE + { + Byte b; + if (!m_InStream.ReadByte(b)) + break; + if (b != prevByte) + { + if (numReps >= kRleModeRepSize) + buffer[i++] = (Byte)(numReps - kRleModeRepSize); + buffer[i++] = b; + numReps = 1; + prevByte = b; + continue; + } + numReps++; + if (numReps <= kRleModeRepSize) + buffer[i++] = b; + else if (numReps == kRleModeRepSize + 255) + { + buffer[i++] = (Byte)(numReps - kRleModeRepSize); + numReps = 0; + } + } + // it's to support original BZip2 decoder + if (numReps >= kRleModeRepSize) + buffer[i++] = (Byte)(numReps - kRleModeRepSize); + } + return i; +} + +void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); } +void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); } +void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); } +void CThreadInfo::WriteCrc2(UInt32 v) +{ + for (unsigned i = 0; i < 4; i++) + WriteByte2(((Byte)(v >> (24 - i * 8)))); +} + +void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); } +void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); } +// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); } +void CEncoder::WriteCrc(UInt32 v) +{ + for (unsigned i = 0; i < 4; i++) + WriteByte(((Byte)(v >> (24 - i * 8)))); +} + + +// blockSize > 0 +void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) +{ + WriteBit2(0); // Randomised = false + + { + UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize); + // if (m_BlockSorterIndex[origPtr] != 0) throw 1; + m_BlockSorterIndex[origPtr] = blockSize; + WriteBits2(origPtr, kNumOrigBits); + } + + CMtf8Encoder mtf; + unsigned numInUse = 0; + { + Byte inUse[256]; + Byte inUse16[16]; + UInt32 i; + for (i = 0; i < 256; i++) + inUse[i] = 0; + for (i = 0; i < 16; i++) + inUse16[i] = 0; + for (i = 0; i < blockSize; i++) + inUse[block[i]] = 1; + for (i = 0; i < 256; i++) + if (inUse[i]) + { + inUse16[i >> 4] = 1; + mtf.Buf[numInUse++] = (Byte)i; + } + for (i = 0; i < 16; i++) + WriteBit2(inUse16[i]); + for (i = 0; i < 256; i++) + if (inUse16[i >> 4]) + WriteBit2(inUse[i]); + } + unsigned alphaSize = numInUse + 2; + + Byte *mtfs = m_MtfArray; + UInt32 mtfArraySize = 0; + UInt32 symbolCounts[kMaxAlphaSize]; + { + for (unsigned i = 0; i < kMaxAlphaSize; i++) + symbolCounts[i] = 0; + } + + { + UInt32 rleSize = 0; + UInt32 i = 0; + const UInt32 *bsIndex = m_BlockSorterIndex; + block--; + do + { + unsigned pos = mtf.FindAndMove(block[bsIndex[i]]); + if (pos == 0) + rleSize++; + else + { + while (rleSize != 0) + { + rleSize--; + mtfs[mtfArraySize++] = (Byte)(rleSize & 1); + symbolCounts[rleSize & 1]++; + rleSize >>= 1; + } + if (pos >= 0xFE) + { + mtfs[mtfArraySize++] = 0xFF; + mtfs[mtfArraySize++] = (Byte)(pos - 0xFE); + } + else + mtfs[mtfArraySize++] = (Byte)(pos + 1); + symbolCounts[(size_t)pos + 1]++; + } + } + while (++i < blockSize); + + while (rleSize != 0) + { + rleSize--; + mtfs[mtfArraySize++] = (Byte)(rleSize & 1); + symbolCounts[rleSize & 1]++; + rleSize >>= 1; + } + + if (alphaSize < 256) + mtfs[mtfArraySize++] = (Byte)(alphaSize - 1); + else + { + mtfs[mtfArraySize++] = 0xFF; + mtfs[mtfArraySize++] = (Byte)(alphaSize - 256); + } + symbolCounts[(size_t)alphaSize - 1]++; + } + + UInt32 numSymbols = 0; + { + for (unsigned i = 0; i < kMaxAlphaSize; i++) + numSymbols += symbolCounts[i]; + } + + unsigned bestNumTables = kNumTablesMin; + UInt32 bestPrice = 0xFFFFFFFF; + UInt32 startPos = m_OutStreamCurrent->GetPos(); + Byte startCurByte = m_OutStreamCurrent->GetCurByte(); + for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++) + { + unsigned numTables; + + if (m_OptimizeNumTables) + { + m_OutStreamCurrent->SetPos(startPos); + m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); + if (nt <= kNumTablesMax) + numTables = nt; + else + numTables = bestNumTables; + } + else + { + if (numSymbols < 200) numTables = 2; + else if (numSymbols < 600) numTables = 3; + else if (numSymbols < 1200) numTables = 4; + else if (numSymbols < 2400) numTables = 5; + else numTables = 6; + } + + WriteBits2(numTables, kNumTablesBits); + + UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize; + WriteBits2(numSelectors, kNumSelectorsBits); + + { + UInt32 remFreq = numSymbols; + unsigned gs = 0; + unsigned t = numTables; + do + { + UInt32 tFreq = remFreq / t; + unsigned ge = gs; + UInt32 aFreq = 0; + while (aFreq < tFreq) // && ge < alphaSize) + aFreq += symbolCounts[ge++]; + + if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1)) + aFreq -= symbolCounts[--ge]; + + Byte *lens = Lens[(size_t)t - 1]; + unsigned i = 0; + do + lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1); + while (++i < alphaSize); + gs = ge; + remFreq -= aFreq; + } + while (--t != 0); + } + + + for (unsigned pass = 0; pass < kNumHuffPasses; pass++) + { + { + unsigned t = 0; + do + memset(Freqs[t], 0, sizeof(Freqs[t])); + while (++t < numTables); + } + + { + UInt32 mtfPos = 0; + UInt32 g = 0; + do + { + UInt32 symbols[kGroupSize]; + unsigned i = 0; + do + { + UInt32 symbol = mtfs[mtfPos++]; + if (symbol >= 0xFF) + symbol += mtfs[mtfPos++]; + symbols[i] = symbol; + } + while (++i < kGroupSize && mtfPos < mtfArraySize); + + UInt32 bestPrice2 = 0xFFFFFFFF; + unsigned t = 0; + do + { + const Byte *lens = Lens[t]; + UInt32 price = 0; + unsigned j = 0; + do + price += lens[symbols[j]]; + while (++j < i); + if (price < bestPrice2) + { + m_Selectors[g] = (Byte)t; + bestPrice2 = price; + } + } + while (++t < numTables); + UInt32 *freqs = Freqs[m_Selectors[g++]]; + unsigned j = 0; + do + freqs[symbols[j]]++; + while (++j < i); + } + while (mtfPos < mtfArraySize); + } + + unsigned t = 0; + do + { + UInt32 *freqs = Freqs[t]; + unsigned i = 0; + do + if (freqs[i] == 0) + freqs[i] = 1; + while (++i < alphaSize); + Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding); + } + while (++t < numTables); + } + + { + Byte mtfSel[kNumTablesMax]; + { + unsigned t = 0; + do + mtfSel[t] = (Byte)t; + while (++t < numTables); + } + + UInt32 i = 0; + do + { + Byte sel = m_Selectors[i]; + unsigned pos; + for (pos = 0; mtfSel[pos] != sel; pos++) + WriteBit2(1); + WriteBit2(0); + for (; pos > 0; pos--) + mtfSel[pos] = mtfSel[(size_t)pos - 1]; + mtfSel[0] = sel; + } + while (++i < numSelectors); + } + + { + unsigned t = 0; + do + { + const Byte *lens = Lens[t]; + UInt32 len = lens[0]; + WriteBits2(len, kNumLevelsBits); + unsigned i = 0; + do + { + UInt32 level = lens[i]; + while (len != level) + { + WriteBit2(1); + if (len < level) + { + WriteBit2(0); + len++; + } + else + { + WriteBit2(1); + len--; + } + } + WriteBit2(0); + } + while (++i < alphaSize); + } + while (++t < numTables); + } + + { + UInt32 groupSize = 0; + UInt32 groupIndex = 0; + const Byte *lens = NULL; + const UInt32 *codes = NULL; + UInt32 mtfPos = 0; + do + { + UInt32 symbol = mtfs[mtfPos++]; + if (symbol >= 0xFF) + symbol += mtfs[mtfPos++]; + if (groupSize == 0) + { + groupSize = kGroupSize; + unsigned t = m_Selectors[groupIndex++]; + lens = Lens[t]; + codes = Codes[t]; + } + groupSize--; + m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]); + } + while (mtfPos < mtfArraySize); + } + + if (!m_OptimizeNumTables) + break; + UInt32 price = m_OutStreamCurrent->GetPos() - startPos; + if (price <= bestPrice) + { + if (nt == kNumTablesMax) + break; + bestPrice = price; + bestNumTables = nt; + } + } +} + +// blockSize > 0 +UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize) +{ + WriteByte2(kBlockSig0); + WriteByte2(kBlockSig1); + WriteByte2(kBlockSig2); + WriteByte2(kBlockSig3); + WriteByte2(kBlockSig4); + WriteByte2(kBlockSig5); + + CBZip2Crc crc; + unsigned numReps = 0; + Byte prevByte = block[0]; + UInt32 i = 0; + do + { + Byte b = block[i]; + if (numReps == kRleModeRepSize) + { + for (; b > 0; b--) + crc.UpdateByte(prevByte); + numReps = 0; + continue; + } + if (prevByte == b) + numReps++; + else + { + numReps = 1; + prevByte = b; + } + crc.UpdateByte(b); + } + while (++i < blockSize); + UInt32 crcRes = crc.GetDigest(); + WriteCrc2(crcRes); + EncodeBlock(block, blockSize); + return crcRes; +} + +void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses) +{ + UInt32 numCrcs = m_NumCrcs; + bool needCompare = false; + + UInt32 startBytePos = m_OutStreamCurrent->GetBytePos(); + UInt32 startPos = m_OutStreamCurrent->GetPos(); + Byte startCurByte = m_OutStreamCurrent->GetCurByte(); + Byte endCurByte = 0; + UInt32 endPos = 0; + if (numPasses > 1 && blockSize >= (1 << 10)) + { + UInt32 blockSize0 = blockSize / 2; // ???? + + for (; (block[blockSize0] == block[(size_t)blockSize0 - 1] + || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2]) + && blockSize0 < blockSize; + blockSize0++); + + if (blockSize0 < blockSize) + { + EncodeBlock2(block, blockSize0, numPasses - 1); + EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1); + endPos = m_OutStreamCurrent->GetPos(); + endCurByte = m_OutStreamCurrent->GetCurByte(); + if ((endPos & 7) > 0) + WriteBits2(0, 8 - (endPos & 7)); + m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte); + needCompare = true; + } + } + + UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos(); + UInt32 startPos2 = m_OutStreamCurrent->GetPos(); + UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize); + UInt32 endPos2 = m_OutStreamCurrent->GetPos(); + + if (needCompare) + { + UInt32 size2 = endPos2 - startPos2; + if (size2 < endPos - startPos) + { + UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2; + Byte *buffer = m_OutStreamCurrent->GetStream(); + for (UInt32 i = 0; i < numBytes; i++) + buffer[startBytePos + i] = buffer[startBytePos2 + i]; + m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2); + m_NumCrcs = numCrcs; + m_CRCs[m_NumCrcs++] = crcVal; + } + else + { + m_OutStreamCurrent->SetPos(endPos); + m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte); + } + } + else + { + m_NumCrcs = numCrcs; + m_CRCs[m_NumCrcs++] = crcVal; + } +} + +HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize) +{ + CMsbfEncoderTemp outStreamTemp; + outStreamTemp.SetStream(m_TempArray); + outStreamTemp.Init(); + m_OutStreamCurrent = &outStreamTemp; + + m_NumCrcs = 0; + + EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses); + + #ifndef Z7_ST + if (Encoder->MtMode) + Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock(); + #endif + for (UInt32 i = 0; i < m_NumCrcs; i++) + Encoder->CombinedCrc.Update(m_CRCs[i]); + Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte()); + HRESULT res = S_OK; + #ifndef Z7_ST + if (Encoder->MtMode) + { + UInt32 blockIndex = m_BlockIndex + 1; + if (blockIndex == Encoder->NumThreads) + blockIndex = 0; + + if (Encoder->Progress) + { + const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); + res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); + } + + Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); + } + #endif + return res; +} + +void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte) +{ + UInt32 bytesSize = (sizeInBits >> 3); + for (UInt32 i = 0; i < bytesSize; i++) + m_OutStream.WriteBits(data[i], 8); + WriteBits(lastByte, (sizeInBits & 7)); +} + + +HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) +{ + NumBlocks = 0; + #ifndef Z7_ST + Progress = progress; + RINOK(Create()) + for (UInt32 t = 0; t < NumThreads; t++) + #endif + { + #ifndef Z7_ST + CThreadInfo &ti = ThreadsInfo[t]; + if (MtMode) + { + WRes wres = ti.StreamWasFinishedEvent.Reset(); + if (wres == 0) { wres = ti.WaitingWasStartedEvent.Reset(); + if (wres == 0) { wres = ti.CanWriteEvent.Reset(); }} + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + #else + CThreadInfo &ti = ThreadsInfo; + ti.Encoder = this; + #endif + + ti.m_OptimizeNumTables = _props.DoOptimizeNumTables(); + + if (!ti.Alloc()) + return E_OUTOFMEMORY; + } + + + if (!m_InStream.Create(kBufferSize)) + return E_OUTOFMEMORY; + if (!m_OutStream.Create(kBufferSize)) + return E_OUTOFMEMORY; + + + m_InStream.SetStream(inStream); + m_InStream.Init(); + + m_OutStream.SetStream(outStream); + m_OutStream.Init(); + + CombinedCrc.Init(); + #ifndef Z7_ST + NextBlockIndex = 0; + StreamWasFinished = false; + CloseThreads = false; + CanStartWaitingEvent.Reset(); + #endif + + WriteByte(kArSig0); + WriteByte(kArSig1); + WriteByte(kArSig2); + WriteByte((Byte)(kArSig3 + _props.BlockSizeMult)); + + #ifndef Z7_ST + + if (MtMode) + { + ThreadsInfo[0].CanWriteEvent.Set(); + Result = S_OK; + CanProcessEvent.Set(); + UInt32 t; + for (t = 0; t < NumThreads; t++) + ThreadsInfo[t].StreamWasFinishedEvent.Lock(); + CanProcessEvent.Reset(); + CanStartWaitingEvent.Set(); + for (t = 0; t < NumThreads; t++) + ThreadsInfo[t].WaitingWasStartedEvent.Lock(); + CanStartWaitingEvent.Reset(); + RINOK(Result) + } + else + #endif + { + for (;;) + { + CThreadInfo &ti = + #ifndef Z7_ST + ThreadsInfo[0]; + #else + ThreadsInfo; + #endif + UInt32 blockSize = ReadRleBlock(ti.m_Block); + if (blockSize == 0) + break; + RINOK(ti.EncodeBlock3(blockSize)) + if (progress) + { + const UInt64 unpackSize = m_InStream.GetProcessedSize(); + const UInt64 packSize = m_OutStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&unpackSize, &packSize)) + } + } + } + WriteByte(kFinSig0); + WriteByte(kFinSig1); + WriteByte(kFinSig2); + WriteByte(kFinSig3); + WriteByte(kFinSig4); + WriteByte(kFinSig5); + + WriteCrc(CombinedCrc.GetDigest()); + RINOK(Flush()) + if (!m_InStream.WasFinished()) + return E_FAIL; + return S_OK; +} + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + int level = -1; + CEncProps props; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + PROPID propID = propIDs[i]; + + if (propID == NCoderPropID::kAffinity) + { + if (prop.vt == VT_UI8) + props.Affinity = prop.uhVal.QuadPart; + else + return E_INVALIDARG; + continue; + } + + if (propID >= NCoderPropID::kReduceSize) + continue; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + UInt32 v = (UInt32)prop.ulVal; + switch (propID) + { + case NCoderPropID::kNumPasses: props.NumPasses = v; break; + case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break; + case NCoderPropID::kLevel: level = (int)v; break; + case NCoderPropID::kNumThreads: + { + #ifndef Z7_ST + SetNumberOfThreads(v); + #endif + break; + } + default: return E_INVALIDARG; + } + } + props.Normalize(level); + _props = props; + return S_OK; +} + +#ifndef Z7_ST +Z7_COM7F_IMF(CEncoder::SetNumberOfThreads(UInt32 numThreads)) +{ + const UInt32 kNumThreadsMax = 64; + if (numThreads < 1) numThreads = 1; + if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax; + NumThreads = numThreads; + return S_OK; +} +#endif + +}} diff --git a/CPP/7zip/Compress/BZip2Encoder.h b/CPP/7zip/Compress/BZip2Encoder.h index 19bf63714..4a04fbd61 100644 --- a/CPP/7zip/Compress/BZip2Encoder.h +++ b/CPP/7zip/Compress/BZip2Encoder.h @@ -1,247 +1,247 @@ -// BZip2Encoder.h - -#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H -#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H - -#include "../../Common/Defs.h" -#include "../../Common/MyCom.h" - -#ifndef Z7_ST -#include "../../Windows/Synchronization.h" -#include "../../Windows/Thread.h" -#endif - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" -#include "../Common/OutBuffer.h" - -#include "BitmEncoder.h" -#include "BZip2Const.h" -#include "BZip2Crc.h" - -namespace NCompress { -namespace NBZip2 { - -class CMsbfEncoderTemp -{ - UInt32 _pos; - unsigned _bitPos; - Byte _curByte; - Byte *_buf; -public: - void SetStream(Byte *buf) { _buf = buf; } - Byte *GetStream() const { return _buf; } - - void Init() - { - _pos = 0; - _bitPos = 8; - _curByte = 0; - } - - void Flush() - { - if (_bitPos < 8) - WriteBits(0, _bitPos); - } - - void WriteBits(UInt32 value, unsigned numBits) - { - while (numBits > 0) - { - unsigned numNewBits = MyMin(numBits, _bitPos); - numBits -= numNewBits; - - _curByte = (Byte)(_curByte << numNewBits); - UInt32 newBits = value >> numBits; - _curByte |= Byte(newBits); - value -= (newBits << numBits); - - _bitPos -= numNewBits; - - if (_bitPos == 0) - { - _buf[_pos++] = _curByte; - _bitPos = 8; - } - } - } - - UInt32 GetBytePos() const { return _pos ; } - UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); } - Byte GetCurByte() const { return _curByte; } - void SetPos(UInt32 bitPos) - { - _pos = bitPos >> 3; - _bitPos = 8 - ((unsigned)bitPos & 7); - } - void SetCurState(unsigned bitPos, Byte curByte) - { - _bitPos = 8 - bitPos; - _curByte = curByte; - } -}; - -class CEncoder; - -const unsigned kNumPassesMax = 10; - -class CThreadInfo -{ -public: - Byte *m_Block; -private: - Byte *m_MtfArray; - Byte *m_TempArray; - UInt32 *m_BlockSorterIndex; - - CMsbfEncoderTemp *m_OutStreamCurrent; - - Byte Lens[kNumTablesMax][kMaxAlphaSize]; - UInt32 Freqs[kNumTablesMax][kMaxAlphaSize]; - UInt32 Codes[kNumTablesMax][kMaxAlphaSize]; - - Byte m_Selectors[kNumSelectorsMax]; - - UInt32 m_CRCs[1 << kNumPassesMax]; - UInt32 m_NumCrcs; - - void WriteBits2(UInt32 value, unsigned numBits); - void WriteByte2(Byte b); - void WriteBit2(Byte v); - void WriteCrc2(UInt32 v); - - void EncodeBlock(const Byte *block, UInt32 blockSize); - UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize); - void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses); -public: - bool m_OptimizeNumTables; - CEncoder *Encoder; - #ifndef Z7_ST - NWindows::CThread Thread; - - NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; - NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent; - - // it's not member of this thread. We just need one event per thread - NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; - -private: - UInt32 m_BlockIndex; - UInt64 m_UnpackSize; -public: - Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. - HRESULT Create(); - void FinishStream(bool needLeave); - THREAD_FUNC_RET_TYPE ThreadFunc(); - #endif - - CThreadInfo(): m_Block(NULL), m_BlockSorterIndex(NULL) {} - ~CThreadInfo() { Free(); } - bool Alloc(); - void Free(); - - HRESULT EncodeBlock3(UInt32 blockSize); -}; - -struct CEncProps -{ - UInt32 BlockSizeMult; - UInt32 NumPasses; - UInt64 Affinity; - - CEncProps() - { - BlockSizeMult = (UInt32)(Int32)-1; - NumPasses = (UInt32)(Int32)-1; - Affinity = 0; - } - void Normalize(int level); - bool DoOptimizeNumTables() const { return NumPasses > 1; } -}; - -class CEncoder Z7_final: - public ICompressCoder, - public ICompressSetCoderProperties, - #ifndef Z7_ST - public ICompressSetCoderMt, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetCoderProperties) - #ifndef Z7_ST - Z7_COM_QI_ENTRY(ICompressSetCoderMt) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) - #ifndef Z7_ST - Z7_IFACE_COM7_IMP(ICompressSetCoderMt) - #endif - - #ifndef Z7_ST - UInt32 m_NumThreadsPrev; - #endif -public: - CInBuffer m_InStream; - #ifndef Z7_ST - Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. - #endif - CBitmEncoder m_OutStream; - CEncProps _props; - CBZip2CombinedCrc CombinedCrc; - - #ifndef Z7_ST - CThreadInfo *ThreadsInfo; - NWindows::NSynchronization::CManualResetEvent CanProcessEvent; - NWindows::NSynchronization::CCriticalSection CS; - UInt32 NumThreads; - bool MtMode; - UInt32 NextBlockIndex; - - bool CloseThreads; - bool StreamWasFinished; - NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; - - HRESULT Result; - ICompressProgressInfo *Progress; - #else - CThreadInfo ThreadsInfo; - #endif - - UInt64 NumBlocks; - - UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); } - - UInt32 ReadRleBlock(Byte *buf); - void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); - - void WriteBits(UInt32 value, unsigned numBits); - void WriteByte(Byte b); - // void WriteBit(Byte v); - void WriteCrc(UInt32 v); - - #ifndef Z7_ST - HRESULT Create(); - void Free(); - #endif - -public: - CEncoder(); - #ifndef Z7_ST - ~CEncoder(); - #endif - - HRESULT Flush() { return m_OutStream.Flush(); } - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -}; - -}} - -#endif +// BZip2Encoder.h + +#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H +#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H + +#include "../../Common/Defs.h" +#include "../../Common/MyCom.h" + +#ifndef Z7_ST +#include "../../Windows/Synchronization.h" +#include "../../Windows/Thread.h" +#endif + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" +#include "../Common/OutBuffer.h" + +#include "BitmEncoder.h" +#include "BZip2Const.h" +#include "BZip2Crc.h" + +namespace NCompress { +namespace NBZip2 { + +class CMsbfEncoderTemp +{ + UInt32 _pos; + unsigned _bitPos; + Byte _curByte; + Byte *_buf; +public: + void SetStream(Byte *buf) { _buf = buf; } + Byte *GetStream() const { return _buf; } + + void Init() + { + _pos = 0; + _bitPos = 8; + _curByte = 0; + } + + void Flush() + { + if (_bitPos < 8) + WriteBits(0, _bitPos); + } + + void WriteBits(UInt32 value, unsigned numBits) + { + while (numBits > 0) + { + unsigned numNewBits = MyMin(numBits, _bitPos); + numBits -= numNewBits; + + _curByte = (Byte)(_curByte << numNewBits); + UInt32 newBits = value >> numBits; + _curByte |= Byte(newBits); + value -= (newBits << numBits); + + _bitPos -= numNewBits; + + if (_bitPos == 0) + { + _buf[_pos++] = _curByte; + _bitPos = 8; + } + } + } + + UInt32 GetBytePos() const { return _pos ; } + UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); } + Byte GetCurByte() const { return _curByte; } + void SetPos(UInt32 bitPos) + { + _pos = bitPos >> 3; + _bitPos = 8 - ((unsigned)bitPos & 7); + } + void SetCurState(unsigned bitPos, Byte curByte) + { + _bitPos = 8 - bitPos; + _curByte = curByte; + } +}; + +class CEncoder; + +const unsigned kNumPassesMax = 10; + +class CThreadInfo +{ +public: + Byte *m_Block; +private: + Byte *m_MtfArray; + Byte *m_TempArray; + UInt32 *m_BlockSorterIndex; + + CMsbfEncoderTemp *m_OutStreamCurrent; + + Byte Lens[kNumTablesMax][kMaxAlphaSize]; + UInt32 Freqs[kNumTablesMax][kMaxAlphaSize]; + UInt32 Codes[kNumTablesMax][kMaxAlphaSize]; + + Byte m_Selectors[kNumSelectorsMax]; + + UInt32 m_CRCs[1 << kNumPassesMax]; + UInt32 m_NumCrcs; + + void WriteBits2(UInt32 value, unsigned numBits); + void WriteByte2(Byte b); + void WriteBit2(Byte v); + void WriteCrc2(UInt32 v); + + void EncodeBlock(const Byte *block, UInt32 blockSize); + UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize); + void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses); +public: + bool m_OptimizeNumTables; + CEncoder *Encoder; + #ifndef Z7_ST + NWindows::CThread Thread; + + NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent; + NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent; + + // it's not member of this thread. We just need one event per thread + NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; + +private: + UInt32 m_BlockIndex; + UInt64 m_UnpackSize; +public: + Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. + HRESULT Create(); + void FinishStream(bool needLeave); + THREAD_FUNC_RET_TYPE ThreadFunc(); + #endif + + CThreadInfo(): m_Block(NULL), m_BlockSorterIndex(NULL) {} + ~CThreadInfo() { Free(); } + bool Alloc(); + void Free(); + + HRESULT EncodeBlock3(UInt32 blockSize); +}; + +struct CEncProps +{ + UInt32 BlockSizeMult; + UInt32 NumPasses; + UInt64 Affinity; + + CEncProps() + { + BlockSizeMult = (UInt32)(Int32)-1; + NumPasses = (UInt32)(Int32)-1; + Affinity = 0; + } + void Normalize(int level); + bool DoOptimizeNumTables() const { return NumPasses > 1; } +}; + +class CEncoder Z7_final: + public ICompressCoder, + public ICompressSetCoderProperties, + #ifndef Z7_ST + public ICompressSetCoderMt, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetCoderProperties) + #ifndef Z7_ST + Z7_COM_QI_ENTRY(ICompressSetCoderMt) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) + #ifndef Z7_ST + Z7_IFACE_COM7_IMP(ICompressSetCoderMt) + #endif + + #ifndef Z7_ST + UInt32 m_NumThreadsPrev; + #endif +public: + CInBuffer m_InStream; + #ifndef Z7_ST + Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. + #endif + CBitmEncoder m_OutStream; + CEncProps _props; + CBZip2CombinedCrc CombinedCrc; + + #ifndef Z7_ST + CThreadInfo *ThreadsInfo; + NWindows::NSynchronization::CManualResetEvent CanProcessEvent; + NWindows::NSynchronization::CCriticalSection CS; + UInt32 NumThreads; + bool MtMode; + UInt32 NextBlockIndex; + + bool CloseThreads; + bool StreamWasFinished; + NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent; + + HRESULT Result; + ICompressProgressInfo *Progress; + #else + CThreadInfo ThreadsInfo; + #endif + + UInt64 NumBlocks; + + UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); } + + UInt32 ReadRleBlock(Byte *buf); + void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); + + void WriteBits(UInt32 value, unsigned numBits); + void WriteByte(Byte b); + // void WriteBit(Byte v); + void WriteCrc(UInt32 v); + + #ifndef Z7_ST + HRESULT Create(); + void Free(); + #endif + +public: + CEncoder(); + #ifndef Z7_ST + ~CEncoder(); + #endif + + HRESULT Flush() { return m_OutStream.Flush(); } + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/BZip2Register.cpp b/CPP/7zip/Compress/BZip2Register.cpp index 199b78039..83b911de9 100644 --- a/CPP/7zip/Compress/BZip2Register.cpp +++ b/CPP/7zip/Compress/BZip2Register.cpp @@ -1,25 +1,25 @@ -// BZip2Register.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "BZip2Decoder.h" -#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY) -#include "BZip2Encoder.h" -#endif - -namespace NCompress { -namespace NBZip2 { - -REGISTER_CODEC_CREATE(CreateDec, CDecoder) - -#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY) -REGISTER_CODEC_CREATE(CreateEnc, CEncoder) -#else -#define CreateEnc NULL -#endif - -REGISTER_CODEC_2(BZip2, CreateDec, CreateEnc, 0x40202, "BZip2") - -}} +// BZip2Register.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "BZip2Decoder.h" +#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY) +#include "BZip2Encoder.h" +#endif + +namespace NCompress { +namespace NBZip2 { + +REGISTER_CODEC_CREATE(CreateDec, CDecoder) + +#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY) +REGISTER_CODEC_CREATE(CreateEnc, CEncoder) +#else +#define CreateEnc NULL +#endif + +REGISTER_CODEC_2(BZip2, CreateDec, CreateEnc, 0x40202, "BZip2") + +}} diff --git a/CPP/7zip/Compress/Bcj2Coder.cpp b/CPP/7zip/Compress/Bcj2Coder.cpp index 9fb9f5d0b..4fa42a5a2 100644 --- a/CPP/7zip/Compress/Bcj2Coder.cpp +++ b/CPP/7zip/Compress/Bcj2Coder.cpp @@ -1,867 +1,867 @@ -// Bcj2Coder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/Alloc.h" - -#include "../Common/StreamUtils.h" - -#include "Bcj2Coder.h" - -namespace NCompress { -namespace NBcj2 { - -CBaseCoder::CBaseCoder() -{ - for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++) - { - _bufs[i] = NULL; - _bufsSizes[i] = 0; - _bufsSizes_New[i] = (1 << 18); - } -} - -CBaseCoder::~CBaseCoder() -{ - for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++) - ::MidFree(_bufs[i]); -} - -HRESULT CBaseCoder::Alloc(bool allocForOrig) -{ - const unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS; - for (unsigned i = 0; i < num; i++) - { - UInt32 size = _bufsSizes_New[i]; - /* buffer sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams - must be aligned for 4 */ - size &= ~(UInt32)3; - const UInt32 kMinBufSize = 4; - if (size < kMinBufSize) - size = kMinBufSize; - // size = 4 * 100; // for debug - // if (BCJ2_IS_32BIT_STREAM(i) == 1) size = 4 * 1; // for debug - if (!_bufs[i] || size != _bufsSizes[i]) - { - if (_bufs[i]) - { - ::MidFree(_bufs[i]); - _bufs[i] = NULL; - } - _bufsSizes[i] = 0; - Byte *buf = (Byte *)::MidAlloc(size); - if (!buf) - return E_OUTOFMEMORY; - _bufs[i] = buf; - _bufsSizes[i] = size; - } - } - return S_OK; -} - - - -#ifndef Z7_EXTRACT_ONLY - -CEncoder::CEncoder(): - _relatLim(BCJ2_ENC_RELAT_LIMIT_DEFAULT) - // , _excludeRangeBits(BCJ2_RELAT_EXCLUDE_NUM_BITS) - {} -CEncoder::~CEncoder() {} - -Z7_COM7F_IMF(CEncoder::SetInBufSize(UInt32, UInt32 size)) - { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; } -Z7_COM7F_IMF(CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size)) - { _bufsSizes_New[streamIndex] = size; return S_OK; } - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -{ - UInt32 relatLim = BCJ2_ENC_RELAT_LIMIT_DEFAULT; - // UInt32 excludeRangeBits = BCJ2_RELAT_EXCLUDE_NUM_BITS; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = props[i]; - const PROPID propID = propIDs[i]; - if (propID >= NCoderPropID::kReduceSize - // && propID != NCoderPropID::kHashBits - ) - continue; - switch (propID) - { - /* - case NCoderPropID::kDefaultProp: - { - if (prop.vt != VT_UI4) - return E_INVALIDARG; - UInt32 v = prop.ulVal; - if (v > 31) - return E_INVALIDARG; - relatLim = (UInt32)1 << v; - break; - } - case NCoderPropID::kHashBits: - { - if (prop.vt != VT_UI4) - return E_INVALIDARG; - UInt32 v = prop.ulVal; - if (v > 31) - return E_INVALIDARG; - excludeRangeBits = v; - break; - } - */ - case NCoderPropID::kDictionarySize: - { - if (prop.vt != VT_UI4) - return E_INVALIDARG; - relatLim = prop.ulVal; - if (relatLim > BCJ2_ENC_RELAT_LIMIT_MAX) - return E_INVALIDARG; - break; - } - case NCoderPropID::kNumThreads: - case NCoderPropID::kLevel: - continue; - default: return E_INVALIDARG; - } - } - _relatLim = relatLim; - // _excludeRangeBits = excludeRangeBits; - return S_OK; -} - - -HRESULT CEncoder::CodeReal( - ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, - ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams, - ICompressProgressInfo *progress) -{ - if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS) - return E_INVALIDARG; - - RINOK(Alloc()) - - CBcj2Enc_ip_unsigned fileSize_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED; - if (inSizes && inSizes[0]) - { - const UInt64 inSize = *inSizes[0]; - #ifdef BCJ2_ENC_FileSize_MAX - if (inSize <= BCJ2_ENC_FileSize_MAX) - #endif - fileSize_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(inSize); - } - - Z7_DECL_CMyComPtr_QI_FROM(ICompressGetSubStreamSize, getSubStreamSize, inStreams[0]) - - CBcj2Enc enc; - enc.src = _bufs[BCJ2_NUM_STREAMS]; - enc.srcLim = enc.src; - { - for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) - { - enc.bufs[i] = _bufs[i]; - enc.lims[i] = _bufs[i] + _bufsSizes[i]; - } - } - Bcj2Enc_Init(&enc); - enc.fileIp64 = 0; - enc.fileSize64_minus1 = fileSize_minus1; - enc.relatLimit = _relatLim; - // enc.relatExcludeBits = _excludeRangeBits; - enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - - // Varibales that correspond processed data in input stream: - UInt64 inPos_without_Temp = 0; // it doesn't include data in enc.temp[] - UInt64 inPos_with_Temp = 0; // it includes data in enc.temp[] - - UInt64 prevProgress = 0; - UInt64 totalRead = 0; // size read from input stream - UInt64 outSizeRc = 0; - UInt64 subStream_Index = 0; - UInt64 subStream_StartPos = 0; // global start offset of subStreams[subStream_Index] - UInt64 subStream_Size = 0; - const Byte *srcLim_Read = _bufs[BCJ2_NUM_STREAMS]; - bool readWasFinished = false; - bool isAccurate = false; - bool wasUnknownSize = false; - - for (;;) - { - if (readWasFinished && enc.srcLim == srcLim_Read) - enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM; - - // for debug: - // for (int y=0;y<100;y++) { CBcj2Enc enc2 = enc; Bcj2Enc_Encode(&enc2); } - - Bcj2Enc_Encode(&enc); - - inPos_with_Temp = totalRead - (size_t)(srcLim_Read - enc.src); - inPos_without_Temp = inPos_with_Temp - Bcj2Enc_Get_AvailInputSize_in_Temp(&enc); - - // if (inPos_without_Temp != enc.ip64) return E_FAIL; - - if (Bcj2Enc_IsFinished(&enc)) - break; - - if (enc.state < BCJ2_NUM_STREAMS) - { - if (enc.bufs[enc.state] != enc.lims[enc.state]) - return E_FAIL; - const size_t curSize = (size_t)(enc.bufs[enc.state] - _bufs[enc.state]); - // printf("Write stream = %2d %6d\n", enc.state, curSize); - RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize)) - if (enc.state == BCJ2_STREAM_RC) - outSizeRc += curSize; - enc.bufs[enc.state] = _bufs[enc.state]; - enc.lims[enc.state] = _bufs[enc.state] + _bufsSizes[enc.state]; - } - else - { - if (enc.state != BCJ2_ENC_STATE_ORIG) - return E_FAIL; - // (enc.state == BCJ2_ENC_STATE_ORIG) - if (enc.src != enc.srcLim) - return E_FAIL; - if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE - && Bcj2Enc_Get_AvailInputSize_in_Temp(&enc) != 0) - return E_FAIL; - - if (enc.src == srcLim_Read) - { - if (readWasFinished) - return E_FAIL; - UInt32 curSize = _bufsSizes[BCJ2_NUM_STREAMS]; - RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize)) - // printf("Read %6u bytes\n", curSize); - if (curSize == 0) - readWasFinished = true; - totalRead += curSize; - enc.src = _bufs[BCJ2_NUM_STREAMS]; - srcLim_Read = _bufs[BCJ2_NUM_STREAMS] + curSize; - } - enc.srcLim = srcLim_Read; - - if (getSubStreamSize) - { - /* we set base default conversions options that will be used, - if subStream related options will be not OK */ - enc.fileIp64 = 0; - enc.fileSize64_minus1 = fileSize_minus1; - for (;;) - { - UInt64 nextPos; - if (isAccurate) - nextPos = subStream_StartPos + subStream_Size; - else - { - const HRESULT hres = getSubStreamSize->GetSubStreamSize(subStream_Index, &subStream_Size); - if (hres != S_OK) - { - enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - /* if sub-stream size is unknown, we use default settings. - We still can recover to normal mode for next sub-stream, - if GetSubStreamSize() will return S_OK, when current - sub-stream will be finished. - */ - if (hres == S_FALSE) - { - wasUnknownSize = true; - break; - } - if (hres == E_NOTIMPL) - { - getSubStreamSize.Release(); - break; - } - return hres; - } - // printf("GetSubStreamSize %6u : %6u \n", (unsigned)subStream_Index, (unsigned)subStream_Size); - nextPos = subStream_StartPos + subStream_Size; - if ((Int64)subStream_Size == -1) - { - /* it's not expected, but (-1) can mean unknown size. */ - enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - wasUnknownSize = true; - break; - } - if (nextPos < subStream_StartPos) - return E_FAIL; - isAccurate = - (nextPos < totalRead - || (nextPos <= totalRead && readWasFinished)); - } - - /* (nextPos) is estimated end position of current sub_stream. - But only (totalRead) and (readWasFinished) values - can confirm that this estimated end position is accurate. - That end position is accurate, if it can't be changed in - further calls of GetSubStreamSize() */ - - /* (nextPos < inPos_with_Temp) is unexpected case here, that we - can get if from some incorrect ICompressGetSubStreamSize object, - where new GetSubStreamSize() call returns smaller size than - confirmed by Read() size from previous GetSubStreamSize() call. - */ - if (nextPos < inPos_with_Temp) - { - if (wasUnknownSize) - { - /* that case can be complicated for recovering. - so we disable sub-streams requesting. */ - enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - getSubStreamSize.Release(); - break; - } - return E_FAIL; // to stop after failure - } - - if (nextPos <= inPos_with_Temp) - { - // (nextPos == inPos_with_Temp) - /* CBcj2Enc encoder requires to finish each [non-empty] block (sub-stream) - with BCJ2_ENC_FINISH_MODE_END_BLOCK - or with BCJ2_ENC_FINISH_MODE_END_STREAM for last block: - And we send data of new block to CBcj2Enc, only if previous block was finished. - So we switch to next sub-stream if after Bcj2Enc_Encode() call we have - && (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE) - && (nextPos == inPos_with_Temp) - && (enc.state == BCJ2_ENC_STATE_ORIG) - */ - if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE) - { - /* subStream_StartPos is increased only here. - (subStream_StartPos == inPos_with_Temp) : at start - (subStream_StartPos <= inPos_with_Temp) : will be later - */ - subStream_StartPos = nextPos; - subStream_Size = 0; - wasUnknownSize = false; - subStream_Index++; - isAccurate = false; - // we don't change finishMode here - continue; - } - } - - enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; - /* for (!isAccurate) case: - (totalRead <= real_end_of_subStream) - so we can use BCJ2_ENC_FINISH_MODE_CONTINUE up to (totalRead) - // we don't change settings at the end of substream, if settings were unknown, - */ - - /* if (wasUnknownSize) then we can't trust size of that sub-stream. - so we use default settings instead */ - if (!wasUnknownSize) - #ifdef BCJ2_ENC_FileSize_MAX - if (subStream_Size <= BCJ2_ENC_FileSize_MAX) - #endif - { - enc.fileIp64 = - (CBcj2Enc_ip_unsigned)( - (CBcj2Enc_ip_signed)enc.ip64 + - (CBcj2Enc_ip_signed)(subStream_StartPos - inPos_without_Temp)); - Bcj2Enc_SET_FileSize(&enc, subStream_Size) - } - - if (isAccurate) - { - /* (real_end_of_subStream == nextPos <= totalRead) - So we can use BCJ2_ENC_FINISH_MODE_END_BLOCK up to (nextPos). */ - const size_t rem = (size_t)(totalRead - nextPos); - if ((size_t)(enc.srcLim - enc.src) < rem) - return E_FAIL; - enc.srcLim -= rem; - enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK; - } - - break; - } // for() loop - } // getSubStreamSize - } - - if (progress && inPos_without_Temp - prevProgress >= (1 << 22)) - { - prevProgress = inPos_without_Temp; - const UInt64 outSize2 = inPos_without_Temp + outSizeRc + - (size_t)(enc.bufs[BCJ2_STREAM_RC] - _bufs[BCJ2_STREAM_RC]); - // printf("progress %8u, %8u\n", (unsigned)inSize2, (unsigned)outSize2); - RINOK(progress->SetRatioInfo(&inPos_without_Temp, &outSize2)) - } - } - - for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) - { - RINOK(WriteStream(outStreams[i], _bufs[i], (size_t)(enc.bufs[i] - _bufs[i]))) - } - // if (inPos_without_Temp != subStream_StartPos + subStream_Size) return E_FAIL; - return S_OK; -} - - -Z7_COM7F_IMF(CEncoder::Code( - ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, - ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, - ICompressProgressInfo *progress)) -{ - try - { - return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); - } - catch(...) { return E_FAIL; } -} - -#endif - - - - - - -CDecoder::CDecoder(): - _finishMode(false) -#ifndef Z7_NO_READ_FROM_CODER - , _outSizeDefined(false) - , _outSize(0) - , _outSize_Processed(0) -#endif -{} - -Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size)) - { _bufsSizes_New[streamIndex] = size; return S_OK; } -Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32, UInt32 size)) - { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; } - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - _finishMode = (finishMode != 0); - return S_OK; -} - -void CBaseDecoder::InitCommon() -{ - for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) - { - dec.lims[i] = dec.bufs[i] = _bufs[i]; - _readRes[i] = S_OK; - _extraSizes[i] = 0; - _readSizes[i] = 0; - } - Bcj2Dec_Init(&dec); -} - - -/* call ReadInStream() only after Bcj2Dec_Decode(). - input requirement: - (dec.state < BCJ2_NUM_STREAMS) -*/ -void CBaseDecoder::ReadInStream(ISequentialInStream *inStream) -{ - const unsigned state = dec.state; - UInt32 total; - { - Byte *buf = _bufs[state]; - const Byte *cur = dec.bufs[state]; - // if (cur != dec.lims[state]) throw 1; // unexpected case - dec.lims[state] = - dec.bufs[state] = buf; - total = (UInt32)_extraSizes[state]; - for (UInt32 i = 0; i < total; i++) - buf[i] = cur[i]; - } - - if (_readRes[state] != S_OK) - return; - - do - { - UInt32 curSize = _bufsSizes[state] - total; - // if (state == 0) curSize = 0; // for debug - // curSize = 7; // for debug - /* even if we have reached provided inSizes[state] limit, - we call Read() with (curSize != 0), because - we want the called handler of stream->Read() could - execute required Init/Flushing code even for empty stream. - In another way we could call Read() with (curSize == 0) for - finished streams, but some Read() handlers can ignore Read(size=0) calls. - */ - const HRESULT hres = inStream->Read(_bufs[state] + total, curSize, &curSize); - _readRes[state] = hres; - if (curSize == 0) - break; - _readSizes[state] += curSize; - total += curSize; - if (hres != S_OK) - break; - } - while (total < 4 && BCJ2_IS_32BIT_STREAM(state)); - - /* we exit from decoding loop here, if we can't - provide new data for input stream. - Usually it's normal exit after full stream decoding. */ - if (total == 0) - return; - - if (BCJ2_IS_32BIT_STREAM(state)) - { - const unsigned extra = (unsigned)total & 3; - _extraSizes[state] = extra; - if (total < 4) - { - if (_readRes[state] == S_OK) - _readRes[state] = S_FALSE; // actually it's stream error. So maybe we need another error code. - return; - } - total -= (UInt32)extra; - } - - dec.lims[state] += total; // = _bufs[state] + total; -} - - -Z7_COM7F_IMF(CDecoder::Code( - ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, - ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, - ICompressProgressInfo *progress)) -{ - if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1) - return E_INVALIDARG; - - RINOK(Alloc()) - InitCommon(); - - dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS]; - - UInt64 outSizeWritten = 0; - UInt64 prevProgress = 0; - - HRESULT hres_Crit = S_OK; // critical hres status (mostly from input stream reading) - HRESULT hres_Weak = S_OK; // first non-critical error code from input stream reading - - for (;;) - { - if (Bcj2Dec_Decode(&dec) != SZ_OK) - { - /* it's possible only at start (first 5 bytes in RC stream) */ - hres_Crit = S_FALSE; - break; - } - if (dec.state < BCJ2_NUM_STREAMS) - { - ReadInStream(inStreams[dec.state]); - const unsigned state = dec.state; - const HRESULT hres = _readRes[state]; - if (dec.lims[state] == _bufs[state]) - { - // we break decoding, if there are no new data in input stream - hres_Crit = hres; - break; - } - if (hres != S_OK && hres_Weak == S_OK) - hres_Weak = hres; - } - else // (BCJ2_DEC_STATE_ORIG_0 <= state <= BCJ2_STATE_ORIG) - { - { - const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]); - if (curSize != 0) - { - outSizeWritten += curSize; - RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize)) - } - } - { - UInt32 rem = _bufsSizes[BCJ2_NUM_STREAMS]; - if (outSizes && outSizes[0]) - { - const UInt64 outSize = *outSizes[0] - outSizeWritten; - if (rem > outSize) - rem = (UInt32)outSize; - } - dec.dest = _bufs[BCJ2_NUM_STREAMS]; - dec.destLim = dec.dest + rem; - /* we exit from decoding loop here, - if (outSizes[0]) limit for output stream was reached */ - if (rem == 0) - break; - } - } - - if (progress) - { - // here we don't count additional data in dec.temp (up to 4 bytes for output stream) - const UInt64 processed = outSizeWritten + (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]); - if (processed - prevProgress >= (1 << 24)) - { - prevProgress = processed; - const UInt64 inSize = processed + - _readSizes[BCJ2_STREAM_RC] - (size_t)( - dec.lims[BCJ2_STREAM_RC] - - dec.bufs[BCJ2_STREAM_RC]); - RINOK(progress->SetRatioInfo(&inSize, &prevProgress)) - } - } - } - - { - const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]); - if (curSize != 0) - { - outSizeWritten += curSize; - RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize)) - } - } - - if (hres_Crit == S_OK) hres_Crit = hres_Weak; - if (hres_Crit != S_OK) return hres_Crit; - - if (_finishMode) - { - if (!Bcj2Dec_IsMaybeFinished_code(&dec)) - return S_FALSE; - - /* here we support two correct ways to finish full stream decoding - with one of the following conditions: - - the end of input stream MAIN was reached - - the end of output stream ORIG was reached - Currently 7-Zip/7z code ends with (state == BCJ2_STREAM_MAIN), - because the sizes of MAIN and ORIG streams are known and these - sizes are stored in 7z archive headers. - And Bcj2Dec_Decode() exits with (state == BCJ2_STREAM_MAIN), - if both MAIN and ORIG streams have reached buffers limits. - But if the size of MAIN stream is not known or if the - size of MAIN stream includes some padding after payload data, - then we still can correctly finish decoding with - (state == BCJ2_DEC_STATE_ORIG), if we know the exact size - of output ORIG stream. - */ - if (dec.state != BCJ2_STREAM_MAIN) - if (dec.state != BCJ2_DEC_STATE_ORIG) - return S_FALSE; - - /* the caller also will know written size. - So the following check is optional: */ - if (outSizes && outSizes[0] && *outSizes[0] != outSizeWritten) - return S_FALSE; - - if (inSizes) - { - for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) - { - /* if (inSizes[i]) is defined, we do full check for processed stream size. */ - if (inSizes[i] && *inSizes[i] != GetProcessedSize_ForInStream(i)) - return S_FALSE; - } - } - - /* v23.02: we call Read(0) for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams, - if there were no Read() calls for such stream. - So the handlers of these input streams objects can do - Init/Flushing even for case when stream is empty: - */ - for (unsigned i = BCJ2_STREAM_CALL; i < BCJ2_STREAM_CALL + 2; i++) - { - if (_readSizes[i]) - continue; - Byte b; - UInt32 processed; - RINOK(inStreams[i]->Read(&b, 0, &processed)) - } - } - - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)) -{ - *value = GetProcessedSize_ForInStream(streamIndex); - return S_OK; -} - - -#ifndef Z7_NO_READ_FROM_CODER - -Z7_COM7F_IMF(CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)) -{ - _inStreams[streamIndex] = inStream; - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::ReleaseInStream2(UInt32 streamIndex)) -{ - _inStreams[streamIndex].Release(); - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) -{ - _outSizeDefined = (outSize != NULL); - _outSize = 0; - if (_outSizeDefined) - _outSize = *outSize; - _outSize_Processed = 0; - - const HRESULT res = Alloc(false); // allocForOrig - InitCommon(); - dec.destLim = dec.dest = NULL; - return res; -} - - -Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - /* Note the case: - The output (ORIG) stream can be empty. - But BCJ2_STREAM_RC stream always is not empty. - And we want to support full data processing for all streams. - We disable check (size == 0) here. - So if the caller calls this CDecoder::Read() with (size == 0), - we execute required Init/Flushing code in this CDecoder object. - Also this CDecoder::Read() function will call Read() for input streams. - So the handlers of input streams objects also can do Init/Flushing. - */ - // if (size == 0) return S_OK; // disabled to allow (size == 0) processing - - UInt32 totalProcessed = 0; - - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _outSize_Processed; - if (size > rem) - size = (UInt32)rem; - } - dec.dest = (Byte *)data; - dec.destLim = (const Byte *)data + size; - - HRESULT res = S_OK; - - for (;;) - { - if (Bcj2Dec_Decode(&dec) != SZ_OK) - return S_FALSE; // this error can be only at start of stream - { - const UInt32 curSize = (UInt32)(size_t)(dec.dest - (Byte *)data); - if (curSize != 0) - { - data = (void *)((Byte *)data + curSize); - size -= curSize; - _outSize_Processed += curSize; - totalProcessed += curSize; - if (processedSize) - *processedSize = totalProcessed; - } - } - if (dec.state >= BCJ2_NUM_STREAMS) - break; - ReadInStream(_inStreams[dec.state]); - if (dec.lims[dec.state] == _bufs[dec.state]) - { - /* we break decoding, if there are no new data in input stream. - and we ignore error code, if some data were written to output buffer. */ - if (totalProcessed == 0) - res = _readRes[dec.state]; - break; - } - } - - if (res == S_OK) - if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed) - { - if (!Bcj2Dec_IsMaybeFinished_code(&dec)) - return S_FALSE; - if (dec.state != BCJ2_STREAM_MAIN) - if (dec.state != BCJ2_DEC_STATE_ORIG) - return S_FALSE; - } - - return res; -} - -#endif - -}} - - -/* -extern "C" -{ -extern UInt32 bcj2_stats[256 + 2][2]; -} - -static class CBcj2Stat -{ -public: - ~CBcj2Stat() - { - printf("\nBCJ2 stat:"); - unsigned sums[2] = { 0, 0 }; - int i; - for (i = 2; i < 256 + 2; i++) - { - sums[0] += bcj2_stats[i][0]; - sums[1] += bcj2_stats[i][1]; - } - const unsigned sums2 = sums[0] + sums[1]; - for (int vi = 0; vi < 256 + 3; vi++) - { - printf("\n"); - UInt32 n0, n1; - if (vi < 4) - printf("\n"); - - if (vi < 2) - i = vi; - else if (vi == 2) - i = -1; - else - i = vi - 1; - - if (i < 0) - { - n0 = sums[0]; - n1 = sums[1]; - printf("calls :"); - } - else - { - if (i == 0) - printf("jcc :"); - else if (i == 1) - printf("jump :"); - else - printf("call %02x :", i - 2); - n0 = bcj2_stats[i][0]; - n1 = bcj2_stats[i][1]; - } - - const UInt32 sum = n0 + n1; - printf(" %10u", sum); - - #define PRINT_PERC(val, sum) \ - { UInt32 _sum = sum; if (_sum == 0) _sum = 1; \ - printf(" %7.3f %%", (double)((double)val * (double)100 / (double)_sum )); } - - if (i >= 2 || i < 0) - { - PRINT_PERC(sum, sums2); - } - else - printf("%10s", ""); - - printf(" :%10u", n0); - PRINT_PERC(n0, sum); - - printf(" :%10u", n1); - PRINT_PERC(n1, sum); - } - printf("\n\n"); - fflush(stdout); - } -} g_CBcjStat; -*/ +// Bcj2Coder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "Bcj2Coder.h" + +namespace NCompress { +namespace NBcj2 { + +CBaseCoder::CBaseCoder() +{ + for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++) + { + _bufs[i] = NULL; + _bufsSizes[i] = 0; + _bufsSizes_New[i] = (1 << 18); + } +} + +CBaseCoder::~CBaseCoder() +{ + for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++) + ::MidFree(_bufs[i]); +} + +HRESULT CBaseCoder::Alloc(bool allocForOrig) +{ + const unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS; + for (unsigned i = 0; i < num; i++) + { + UInt32 size = _bufsSizes_New[i]; + /* buffer sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams + must be aligned for 4 */ + size &= ~(UInt32)3; + const UInt32 kMinBufSize = 4; + if (size < kMinBufSize) + size = kMinBufSize; + // size = 4 * 100; // for debug + // if (BCJ2_IS_32BIT_STREAM(i) == 1) size = 4 * 1; // for debug + if (!_bufs[i] || size != _bufsSizes[i]) + { + if (_bufs[i]) + { + ::MidFree(_bufs[i]); + _bufs[i] = NULL; + } + _bufsSizes[i] = 0; + Byte *buf = (Byte *)::MidAlloc(size); + if (!buf) + return E_OUTOFMEMORY; + _bufs[i] = buf; + _bufsSizes[i] = size; + } + } + return S_OK; +} + + + +#ifndef Z7_EXTRACT_ONLY + +CEncoder::CEncoder(): + _relatLim(BCJ2_ENC_RELAT_LIMIT_DEFAULT) + // , _excludeRangeBits(BCJ2_RELAT_EXCLUDE_NUM_BITS) + {} +CEncoder::~CEncoder() {} + +Z7_COM7F_IMF(CEncoder::SetInBufSize(UInt32, UInt32 size)) + { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; } +Z7_COM7F_IMF(CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size)) + { _bufsSizes_New[streamIndex] = size; return S_OK; } + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +{ + UInt32 relatLim = BCJ2_ENC_RELAT_LIMIT_DEFAULT; + // UInt32 excludeRangeBits = BCJ2_RELAT_EXCLUDE_NUM_BITS; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = props[i]; + const PROPID propID = propIDs[i]; + if (propID >= NCoderPropID::kReduceSize + // && propID != NCoderPropID::kHashBits + ) + continue; + switch (propID) + { + /* + case NCoderPropID::kDefaultProp: + { + if (prop.vt != VT_UI4) + return E_INVALIDARG; + UInt32 v = prop.ulVal; + if (v > 31) + return E_INVALIDARG; + relatLim = (UInt32)1 << v; + break; + } + case NCoderPropID::kHashBits: + { + if (prop.vt != VT_UI4) + return E_INVALIDARG; + UInt32 v = prop.ulVal; + if (v > 31) + return E_INVALIDARG; + excludeRangeBits = v; + break; + } + */ + case NCoderPropID::kDictionarySize: + { + if (prop.vt != VT_UI4) + return E_INVALIDARG; + relatLim = prop.ulVal; + if (relatLim > BCJ2_ENC_RELAT_LIMIT_MAX) + return E_INVALIDARG; + break; + } + case NCoderPropID::kNumThreads: + case NCoderPropID::kLevel: + continue; + default: return E_INVALIDARG; + } + } + _relatLim = relatLim; + // _excludeRangeBits = excludeRangeBits; + return S_OK; +} + + +HRESULT CEncoder::CodeReal( + ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, + ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS) + return E_INVALIDARG; + + RINOK(Alloc()) + + CBcj2Enc_ip_unsigned fileSize_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED; + if (inSizes && inSizes[0]) + { + const UInt64 inSize = *inSizes[0]; + #ifdef BCJ2_ENC_FileSize_MAX + if (inSize <= BCJ2_ENC_FileSize_MAX) + #endif + fileSize_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(inSize); + } + + Z7_DECL_CMyComPtr_QI_FROM(ICompressGetSubStreamSize, getSubStreamSize, inStreams[0]) + + CBcj2Enc enc; + enc.src = _bufs[BCJ2_NUM_STREAMS]; + enc.srcLim = enc.src; + { + for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) + { + enc.bufs[i] = _bufs[i]; + enc.lims[i] = _bufs[i] + _bufsSizes[i]; + } + } + Bcj2Enc_Init(&enc); + enc.fileIp64 = 0; + enc.fileSize64_minus1 = fileSize_minus1; + enc.relatLimit = _relatLim; + // enc.relatExcludeBits = _excludeRangeBits; + enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + // Varibales that correspond processed data in input stream: + UInt64 inPos_without_Temp = 0; // it doesn't include data in enc.temp[] + UInt64 inPos_with_Temp = 0; // it includes data in enc.temp[] + + UInt64 prevProgress = 0; + UInt64 totalRead = 0; // size read from input stream + UInt64 outSizeRc = 0; + UInt64 subStream_Index = 0; + UInt64 subStream_StartPos = 0; // global start offset of subStreams[subStream_Index] + UInt64 subStream_Size = 0; + const Byte *srcLim_Read = _bufs[BCJ2_NUM_STREAMS]; + bool readWasFinished = false; + bool isAccurate = false; + bool wasUnknownSize = false; + + for (;;) + { + if (readWasFinished && enc.srcLim == srcLim_Read) + enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM; + + // for debug: + // for (int y=0;y<100;y++) { CBcj2Enc enc2 = enc; Bcj2Enc_Encode(&enc2); } + + Bcj2Enc_Encode(&enc); + + inPos_with_Temp = totalRead - (size_t)(srcLim_Read - enc.src); + inPos_without_Temp = inPos_with_Temp - Bcj2Enc_Get_AvailInputSize_in_Temp(&enc); + + // if (inPos_without_Temp != enc.ip64) return E_FAIL; + + if (Bcj2Enc_IsFinished(&enc)) + break; + + if (enc.state < BCJ2_NUM_STREAMS) + { + if (enc.bufs[enc.state] != enc.lims[enc.state]) + return E_FAIL; + const size_t curSize = (size_t)(enc.bufs[enc.state] - _bufs[enc.state]); + // printf("Write stream = %2d %6d\n", enc.state, curSize); + RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize)) + if (enc.state == BCJ2_STREAM_RC) + outSizeRc += curSize; + enc.bufs[enc.state] = _bufs[enc.state]; + enc.lims[enc.state] = _bufs[enc.state] + _bufsSizes[enc.state]; + } + else + { + if (enc.state != BCJ2_ENC_STATE_ORIG) + return E_FAIL; + // (enc.state == BCJ2_ENC_STATE_ORIG) + if (enc.src != enc.srcLim) + return E_FAIL; + if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE + && Bcj2Enc_Get_AvailInputSize_in_Temp(&enc) != 0) + return E_FAIL; + + if (enc.src == srcLim_Read) + { + if (readWasFinished) + return E_FAIL; + UInt32 curSize = _bufsSizes[BCJ2_NUM_STREAMS]; + RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize)) + // printf("Read %6u bytes\n", curSize); + if (curSize == 0) + readWasFinished = true; + totalRead += curSize; + enc.src = _bufs[BCJ2_NUM_STREAMS]; + srcLim_Read = _bufs[BCJ2_NUM_STREAMS] + curSize; + } + enc.srcLim = srcLim_Read; + + if (getSubStreamSize) + { + /* we set base default conversions options that will be used, + if subStream related options will be not OK */ + enc.fileIp64 = 0; + enc.fileSize64_minus1 = fileSize_minus1; + for (;;) + { + UInt64 nextPos; + if (isAccurate) + nextPos = subStream_StartPos + subStream_Size; + else + { + const HRESULT hres = getSubStreamSize->GetSubStreamSize(subStream_Index, &subStream_Size); + if (hres != S_OK) + { + enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + /* if sub-stream size is unknown, we use default settings. + We still can recover to normal mode for next sub-stream, + if GetSubStreamSize() will return S_OK, when current + sub-stream will be finished. + */ + if (hres == S_FALSE) + { + wasUnknownSize = true; + break; + } + if (hres == E_NOTIMPL) + { + getSubStreamSize.Release(); + break; + } + return hres; + } + // printf("GetSubStreamSize %6u : %6u \n", (unsigned)subStream_Index, (unsigned)subStream_Size); + nextPos = subStream_StartPos + subStream_Size; + if ((Int64)subStream_Size == -1) + { + /* it's not expected, but (-1) can mean unknown size. */ + enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + wasUnknownSize = true; + break; + } + if (nextPos < subStream_StartPos) + return E_FAIL; + isAccurate = + (nextPos < totalRead + || (nextPos <= totalRead && readWasFinished)); + } + + /* (nextPos) is estimated end position of current sub_stream. + But only (totalRead) and (readWasFinished) values + can confirm that this estimated end position is accurate. + That end position is accurate, if it can't be changed in + further calls of GetSubStreamSize() */ + + /* (nextPos < inPos_with_Temp) is unexpected case here, that we + can get if from some incorrect ICompressGetSubStreamSize object, + where new GetSubStreamSize() call returns smaller size than + confirmed by Read() size from previous GetSubStreamSize() call. + */ + if (nextPos < inPos_with_Temp) + { + if (wasUnknownSize) + { + /* that case can be complicated for recovering. + so we disable sub-streams requesting. */ + enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + getSubStreamSize.Release(); + break; + } + return E_FAIL; // to stop after failure + } + + if (nextPos <= inPos_with_Temp) + { + // (nextPos == inPos_with_Temp) + /* CBcj2Enc encoder requires to finish each [non-empty] block (sub-stream) + with BCJ2_ENC_FINISH_MODE_END_BLOCK + or with BCJ2_ENC_FINISH_MODE_END_STREAM for last block: + And we send data of new block to CBcj2Enc, only if previous block was finished. + So we switch to next sub-stream if after Bcj2Enc_Encode() call we have + && (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE) + && (nextPos == inPos_with_Temp) + && (enc.state == BCJ2_ENC_STATE_ORIG) + */ + if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE) + { + /* subStream_StartPos is increased only here. + (subStream_StartPos == inPos_with_Temp) : at start + (subStream_StartPos <= inPos_with_Temp) : will be later + */ + subStream_StartPos = nextPos; + subStream_Size = 0; + wasUnknownSize = false; + subStream_Index++; + isAccurate = false; + // we don't change finishMode here + continue; + } + } + + enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + /* for (!isAccurate) case: + (totalRead <= real_end_of_subStream) + so we can use BCJ2_ENC_FINISH_MODE_CONTINUE up to (totalRead) + // we don't change settings at the end of substream, if settings were unknown, + */ + + /* if (wasUnknownSize) then we can't trust size of that sub-stream. + so we use default settings instead */ + if (!wasUnknownSize) + #ifdef BCJ2_ENC_FileSize_MAX + if (subStream_Size <= BCJ2_ENC_FileSize_MAX) + #endif + { + enc.fileIp64 = + (CBcj2Enc_ip_unsigned)( + (CBcj2Enc_ip_signed)enc.ip64 + + (CBcj2Enc_ip_signed)(subStream_StartPos - inPos_without_Temp)); + Bcj2Enc_SET_FileSize(&enc, subStream_Size) + } + + if (isAccurate) + { + /* (real_end_of_subStream == nextPos <= totalRead) + So we can use BCJ2_ENC_FINISH_MODE_END_BLOCK up to (nextPos). */ + const size_t rem = (size_t)(totalRead - nextPos); + if ((size_t)(enc.srcLim - enc.src) < rem) + return E_FAIL; + enc.srcLim -= rem; + enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK; + } + + break; + } // for() loop + } // getSubStreamSize + } + + if (progress && inPos_without_Temp - prevProgress >= (1 << 22)) + { + prevProgress = inPos_without_Temp; + const UInt64 outSize2 = inPos_without_Temp + outSizeRc + + (size_t)(enc.bufs[BCJ2_STREAM_RC] - _bufs[BCJ2_STREAM_RC]); + // printf("progress %8u, %8u\n", (unsigned)inSize2, (unsigned)outSize2); + RINOK(progress->SetRatioInfo(&inPos_without_Temp, &outSize2)) + } + } + + for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) + { + RINOK(WriteStream(outStreams[i], _bufs[i], (size_t)(enc.bufs[i] - _bufs[i]))) + } + // if (inPos_without_Temp != subStream_StartPos + subStream_Size) return E_FAIL; + return S_OK; +} + + +Z7_COM7F_IMF(CEncoder::Code( + ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, + ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, + ICompressProgressInfo *progress)) +{ + try + { + return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress); + } + catch(...) { return E_FAIL; } +} + +#endif + + + + + + +CDecoder::CDecoder(): + _finishMode(false) +#ifndef Z7_NO_READ_FROM_CODER + , _outSizeDefined(false) + , _outSize(0) + , _outSize_Processed(0) +#endif +{} + +Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size)) + { _bufsSizes_New[streamIndex] = size; return S_OK; } +Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32, UInt32 size)) + { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; } + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + _finishMode = (finishMode != 0); + return S_OK; +} + +void CBaseDecoder::InitCommon() +{ + for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) + { + dec.lims[i] = dec.bufs[i] = _bufs[i]; + _readRes[i] = S_OK; + _extraSizes[i] = 0; + _readSizes[i] = 0; + } + Bcj2Dec_Init(&dec); +} + + +/* call ReadInStream() only after Bcj2Dec_Decode(). + input requirement: + (dec.state < BCJ2_NUM_STREAMS) +*/ +void CBaseDecoder::ReadInStream(ISequentialInStream *inStream) +{ + const unsigned state = dec.state; + UInt32 total; + { + Byte *buf = _bufs[state]; + const Byte *cur = dec.bufs[state]; + // if (cur != dec.lims[state]) throw 1; // unexpected case + dec.lims[state] = + dec.bufs[state] = buf; + total = (UInt32)_extraSizes[state]; + for (UInt32 i = 0; i < total; i++) + buf[i] = cur[i]; + } + + if (_readRes[state] != S_OK) + return; + + do + { + UInt32 curSize = _bufsSizes[state] - total; + // if (state == 0) curSize = 0; // for debug + // curSize = 7; // for debug + /* even if we have reached provided inSizes[state] limit, + we call Read() with (curSize != 0), because + we want the called handler of stream->Read() could + execute required Init/Flushing code even for empty stream. + In another way we could call Read() with (curSize == 0) for + finished streams, but some Read() handlers can ignore Read(size=0) calls. + */ + const HRESULT hres = inStream->Read(_bufs[state] + total, curSize, &curSize); + _readRes[state] = hres; + if (curSize == 0) + break; + _readSizes[state] += curSize; + total += curSize; + if (hres != S_OK) + break; + } + while (total < 4 && BCJ2_IS_32BIT_STREAM(state)); + + /* we exit from decoding loop here, if we can't + provide new data for input stream. + Usually it's normal exit after full stream decoding. */ + if (total == 0) + return; + + if (BCJ2_IS_32BIT_STREAM(state)) + { + const unsigned extra = (unsigned)total & 3; + _extraSizes[state] = extra; + if (total < 4) + { + if (_readRes[state] == S_OK) + _readRes[state] = S_FALSE; // actually it's stream error. So maybe we need another error code. + return; + } + total -= (UInt32)extra; + } + + dec.lims[state] += total; // = _bufs[state] + total; +} + + +Z7_COM7F_IMF(CDecoder::Code( + ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, + ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, + ICompressProgressInfo *progress)) +{ + if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1) + return E_INVALIDARG; + + RINOK(Alloc()) + InitCommon(); + + dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS]; + + UInt64 outSizeWritten = 0; + UInt64 prevProgress = 0; + + HRESULT hres_Crit = S_OK; // critical hres status (mostly from input stream reading) + HRESULT hres_Weak = S_OK; // first non-critical error code from input stream reading + + for (;;) + { + if (Bcj2Dec_Decode(&dec) != SZ_OK) + { + /* it's possible only at start (first 5 bytes in RC stream) */ + hres_Crit = S_FALSE; + break; + } + if (dec.state < BCJ2_NUM_STREAMS) + { + ReadInStream(inStreams[dec.state]); + const unsigned state = dec.state; + const HRESULT hres = _readRes[state]; + if (dec.lims[state] == _bufs[state]) + { + // we break decoding, if there are no new data in input stream + hres_Crit = hres; + break; + } + if (hres != S_OK && hres_Weak == S_OK) + hres_Weak = hres; + } + else // (BCJ2_DEC_STATE_ORIG_0 <= state <= BCJ2_STATE_ORIG) + { + { + const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]); + if (curSize != 0) + { + outSizeWritten += curSize; + RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize)) + } + } + { + UInt32 rem = _bufsSizes[BCJ2_NUM_STREAMS]; + if (outSizes && outSizes[0]) + { + const UInt64 outSize = *outSizes[0] - outSizeWritten; + if (rem > outSize) + rem = (UInt32)outSize; + } + dec.dest = _bufs[BCJ2_NUM_STREAMS]; + dec.destLim = dec.dest + rem; + /* we exit from decoding loop here, + if (outSizes[0]) limit for output stream was reached */ + if (rem == 0) + break; + } + } + + if (progress) + { + // here we don't count additional data in dec.temp (up to 4 bytes for output stream) + const UInt64 processed = outSizeWritten + (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]); + if (processed - prevProgress >= (1 << 24)) + { + prevProgress = processed; + const UInt64 inSize = processed + + _readSizes[BCJ2_STREAM_RC] - (size_t)( + dec.lims[BCJ2_STREAM_RC] - + dec.bufs[BCJ2_STREAM_RC]); + RINOK(progress->SetRatioInfo(&inSize, &prevProgress)) + } + } + } + + { + const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]); + if (curSize != 0) + { + outSizeWritten += curSize; + RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize)) + } + } + + if (hres_Crit == S_OK) hres_Crit = hres_Weak; + if (hres_Crit != S_OK) return hres_Crit; + + if (_finishMode) + { + if (!Bcj2Dec_IsMaybeFinished_code(&dec)) + return S_FALSE; + + /* here we support two correct ways to finish full stream decoding + with one of the following conditions: + - the end of input stream MAIN was reached + - the end of output stream ORIG was reached + Currently 7-Zip/7z code ends with (state == BCJ2_STREAM_MAIN), + because the sizes of MAIN and ORIG streams are known and these + sizes are stored in 7z archive headers. + And Bcj2Dec_Decode() exits with (state == BCJ2_STREAM_MAIN), + if both MAIN and ORIG streams have reached buffers limits. + But if the size of MAIN stream is not known or if the + size of MAIN stream includes some padding after payload data, + then we still can correctly finish decoding with + (state == BCJ2_DEC_STATE_ORIG), if we know the exact size + of output ORIG stream. + */ + if (dec.state != BCJ2_STREAM_MAIN) + if (dec.state != BCJ2_DEC_STATE_ORIG) + return S_FALSE; + + /* the caller also will know written size. + So the following check is optional: */ + if (outSizes && outSizes[0] && *outSizes[0] != outSizeWritten) + return S_FALSE; + + if (inSizes) + { + for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++) + { + /* if (inSizes[i]) is defined, we do full check for processed stream size. */ + if (inSizes[i] && *inSizes[i] != GetProcessedSize_ForInStream(i)) + return S_FALSE; + } + } + + /* v23.02: we call Read(0) for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams, + if there were no Read() calls for such stream. + So the handlers of these input streams objects can do + Init/Flushing even for case when stream is empty: + */ + for (unsigned i = BCJ2_STREAM_CALL; i < BCJ2_STREAM_CALL + 2; i++) + { + if (_readSizes[i]) + continue; + Byte b; + UInt32 processed; + RINOK(inStreams[i]->Read(&b, 0, &processed)) + } + } + + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)) +{ + *value = GetProcessedSize_ForInStream(streamIndex); + return S_OK; +} + + +#ifndef Z7_NO_READ_FROM_CODER + +Z7_COM7F_IMF(CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)) +{ + _inStreams[streamIndex] = inStream; + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::ReleaseInStream2(UInt32 streamIndex)) +{ + _inStreams[streamIndex].Release(); + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) +{ + _outSizeDefined = (outSize != NULL); + _outSize = 0; + if (_outSizeDefined) + _outSize = *outSize; + _outSize_Processed = 0; + + const HRESULT res = Alloc(false); // allocForOrig + InitCommon(); + dec.destLim = dec.dest = NULL; + return res; +} + + +Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + /* Note the case: + The output (ORIG) stream can be empty. + But BCJ2_STREAM_RC stream always is not empty. + And we want to support full data processing for all streams. + We disable check (size == 0) here. + So if the caller calls this CDecoder::Read() with (size == 0), + we execute required Init/Flushing code in this CDecoder object. + Also this CDecoder::Read() function will call Read() for input streams. + So the handlers of input streams objects also can do Init/Flushing. + */ + // if (size == 0) return S_OK; // disabled to allow (size == 0) processing + + UInt32 totalProcessed = 0; + + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outSize_Processed; + if (size > rem) + size = (UInt32)rem; + } + dec.dest = (Byte *)data; + dec.destLim = (const Byte *)data + size; + + HRESULT res = S_OK; + + for (;;) + { + if (Bcj2Dec_Decode(&dec) != SZ_OK) + return S_FALSE; // this error can be only at start of stream + { + const UInt32 curSize = (UInt32)(size_t)(dec.dest - (Byte *)data); + if (curSize != 0) + { + data = (void *)((Byte *)data + curSize); + size -= curSize; + _outSize_Processed += curSize; + totalProcessed += curSize; + if (processedSize) + *processedSize = totalProcessed; + } + } + if (dec.state >= BCJ2_NUM_STREAMS) + break; + ReadInStream(_inStreams[dec.state]); + if (dec.lims[dec.state] == _bufs[dec.state]) + { + /* we break decoding, if there are no new data in input stream. + and we ignore error code, if some data were written to output buffer. */ + if (totalProcessed == 0) + res = _readRes[dec.state]; + break; + } + } + + if (res == S_OK) + if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed) + { + if (!Bcj2Dec_IsMaybeFinished_code(&dec)) + return S_FALSE; + if (dec.state != BCJ2_STREAM_MAIN) + if (dec.state != BCJ2_DEC_STATE_ORIG) + return S_FALSE; + } + + return res; +} + +#endif + +}} + + +/* +extern "C" +{ +extern UInt32 bcj2_stats[256 + 2][2]; +} + +static class CBcj2Stat +{ +public: + ~CBcj2Stat() + { + printf("\nBCJ2 stat:"); + unsigned sums[2] = { 0, 0 }; + int i; + for (i = 2; i < 256 + 2; i++) + { + sums[0] += bcj2_stats[i][0]; + sums[1] += bcj2_stats[i][1]; + } + const unsigned sums2 = sums[0] + sums[1]; + for (int vi = 0; vi < 256 + 3; vi++) + { + printf("\n"); + UInt32 n0, n1; + if (vi < 4) + printf("\n"); + + if (vi < 2) + i = vi; + else if (vi == 2) + i = -1; + else + i = vi - 1; + + if (i < 0) + { + n0 = sums[0]; + n1 = sums[1]; + printf("calls :"); + } + else + { + if (i == 0) + printf("jcc :"); + else if (i == 1) + printf("jump :"); + else + printf("call %02x :", i - 2); + n0 = bcj2_stats[i][0]; + n1 = bcj2_stats[i][1]; + } + + const UInt32 sum = n0 + n1; + printf(" %10u", sum); + + #define PRINT_PERC(val, sum) \ + { UInt32 _sum = sum; if (_sum == 0) _sum = 1; \ + printf(" %7.3f %%", (double)((double)val * (double)100 / (double)_sum )); } + + if (i >= 2 || i < 0) + { + PRINT_PERC(sum, sums2); + } + else + printf("%10s", ""); + + printf(" :%10u", n0); + PRINT_PERC(n0, sum); + + printf(" :%10u", n1); + PRINT_PERC(n1, sum); + } + printf("\n\n"); + fflush(stdout); + } +} g_CBcjStat; +*/ diff --git a/CPP/7zip/Compress/Bcj2Coder.h b/CPP/7zip/Compress/Bcj2Coder.h index dadf11316..2ab91bc87 100644 --- a/CPP/7zip/Compress/Bcj2Coder.h +++ b/CPP/7zip/Compress/Bcj2Coder.h @@ -1,127 +1,127 @@ -// Bcj2Coder.h - -#ifndef ZIP7_INC_COMPRESS_BCJ2_CODER_H -#define ZIP7_INC_COMPRESS_BCJ2_CODER_H - -#include "../../../C/Bcj2.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NBcj2 { - -class CBaseCoder -{ -protected: - Byte *_bufs[BCJ2_NUM_STREAMS + 1]; - UInt32 _bufsSizes[BCJ2_NUM_STREAMS + 1]; - UInt32 _bufsSizes_New[BCJ2_NUM_STREAMS + 1]; - - HRESULT Alloc(bool allocForOrig = true); -public: - CBaseCoder(); - ~CBaseCoder(); -}; - - -#ifndef Z7_EXTRACT_ONLY - -class CEncoder Z7_final: - public ICompressCoder2, - public ICompressSetCoderProperties, - public ICompressSetBufSize, - public CMyUnknownImp, - public CBaseCoder -{ - Z7_IFACES_IMP_UNK_3( - ICompressCoder2, - ICompressSetCoderProperties, - ICompressSetBufSize) - - UInt32 _relatLim; - // UInt32 _excludeRangeBits; - - HRESULT CodeReal( - ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, - ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, - ICompressProgressInfo *progress); -public: - CEncoder(); - ~CEncoder(); -}; - -#endif - - - -class CBaseDecoder: public CBaseCoder -{ -protected: - HRESULT _readRes[BCJ2_NUM_STREAMS]; - unsigned _extraSizes[BCJ2_NUM_STREAMS]; - UInt64 _readSizes[BCJ2_NUM_STREAMS]; - - CBcj2Dec dec; - - UInt64 GetProcessedSize_ForInStream(unsigned i) const - { - return _readSizes[i] - ((size_t)(dec.lims[i] - dec.bufs[i]) + _extraSizes[i]); - } - void InitCommon(); - void ReadInStream(ISequentialInStream *inStream); -}; - - -class CDecoder Z7_final: - public ICompressCoder2, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize2, - public ICompressSetBufSize, -#ifndef Z7_NO_READ_FROM_CODER - public ICompressSetInStream2, - public ICompressSetOutStreamSize, - public ISequentialInStream, -#endif - public CMyUnknownImp, - public CBaseDecoder -{ - Z7_COM_QI_BEGIN2(ICompressCoder2) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize2) - Z7_COM_QI_ENTRY(ICompressSetBufSize) - #ifndef Z7_NO_READ_FROM_CODER - Z7_COM_QI_ENTRY(ICompressSetInStream2) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ISequentialInStream) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder2) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize2) - Z7_IFACE_COM7_IMP(ICompressSetBufSize) -#ifndef Z7_NO_READ_FROM_CODER - Z7_IFACE_COM7_IMP(ICompressSetInStream2) - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - Z7_IFACE_COM7_IMP(ISequentialInStream) -#endif - - bool _finishMode; - -#ifndef Z7_NO_READ_FROM_CODER - bool _outSizeDefined; - UInt64 _outSize; - UInt64 _outSize_Processed; - CMyComPtr _inStreams[BCJ2_NUM_STREAMS]; -#endif - -public: - CDecoder(); -}; - -}} - -#endif +// Bcj2Coder.h + +#ifndef ZIP7_INC_COMPRESS_BCJ2_CODER_H +#define ZIP7_INC_COMPRESS_BCJ2_CODER_H + +#include "../../../C/Bcj2.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NBcj2 { + +class CBaseCoder +{ +protected: + Byte *_bufs[BCJ2_NUM_STREAMS + 1]; + UInt32 _bufsSizes[BCJ2_NUM_STREAMS + 1]; + UInt32 _bufsSizes_New[BCJ2_NUM_STREAMS + 1]; + + HRESULT Alloc(bool allocForOrig = true); +public: + CBaseCoder(); + ~CBaseCoder(); +}; + + +#ifndef Z7_EXTRACT_ONLY + +class CEncoder Z7_final: + public ICompressCoder2, + public ICompressSetCoderProperties, + public ICompressSetBufSize, + public CMyUnknownImp, + public CBaseCoder +{ + Z7_IFACES_IMP_UNK_3( + ICompressCoder2, + ICompressSetCoderProperties, + ICompressSetBufSize) + + UInt32 _relatLim; + // UInt32 _excludeRangeBits; + + HRESULT CodeReal( + ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams, + ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams, + ICompressProgressInfo *progress); +public: + CEncoder(); + ~CEncoder(); +}; + +#endif + + + +class CBaseDecoder: public CBaseCoder +{ +protected: + HRESULT _readRes[BCJ2_NUM_STREAMS]; + unsigned _extraSizes[BCJ2_NUM_STREAMS]; + UInt64 _readSizes[BCJ2_NUM_STREAMS]; + + CBcj2Dec dec; + + UInt64 GetProcessedSize_ForInStream(unsigned i) const + { + return _readSizes[i] - ((size_t)(dec.lims[i] - dec.bufs[i]) + _extraSizes[i]); + } + void InitCommon(); + void ReadInStream(ISequentialInStream *inStream); +}; + + +class CDecoder Z7_final: + public ICompressCoder2, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize2, + public ICompressSetBufSize, +#ifndef Z7_NO_READ_FROM_CODER + public ICompressSetInStream2, + public ICompressSetOutStreamSize, + public ISequentialInStream, +#endif + public CMyUnknownImp, + public CBaseDecoder +{ + Z7_COM_QI_BEGIN2(ICompressCoder2) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize2) + Z7_COM_QI_ENTRY(ICompressSetBufSize) + #ifndef Z7_NO_READ_FROM_CODER + Z7_COM_QI_ENTRY(ICompressSetInStream2) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ISequentialInStream) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder2) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize2) + Z7_IFACE_COM7_IMP(ICompressSetBufSize) +#ifndef Z7_NO_READ_FROM_CODER + Z7_IFACE_COM7_IMP(ICompressSetInStream2) + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + Z7_IFACE_COM7_IMP(ISequentialInStream) +#endif + + bool _finishMode; + +#ifndef Z7_NO_READ_FROM_CODER + bool _outSizeDefined; + UInt64 _outSize; + UInt64 _outSize_Processed; + CMyComPtr _inStreams[BCJ2_NUM_STREAMS]; +#endif + +public: + CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Bcj2Register.cpp b/CPP/7zip/Compress/Bcj2Register.cpp index 12d9cac68..1ce4decb2 100644 --- a/CPP/7zip/Compress/Bcj2Register.cpp +++ b/CPP/7zip/Compress/Bcj2Register.cpp @@ -1,24 +1,24 @@ -// Bcj2Register.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "Bcj2Coder.h" - -namespace NCompress { -namespace NBcj2 { - -REGISTER_CODEC_CREATE_2(CreateCodec, CDecoder(), ICompressCoder2) -#ifndef Z7_EXTRACT_ONLY -REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2) -#else -#define CreateCodecOut NULL -#endif - -REGISTER_CODEC_VAR(BCJ2) - { CreateCodec, CreateCodecOut, 0x303011B, "BCJ2", 4, false }; - -REGISTER_CODEC(BCJ2) - -}} +// Bcj2Register.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "Bcj2Coder.h" + +namespace NCompress { +namespace NBcj2 { + +REGISTER_CODEC_CREATE_2(CreateCodec, CDecoder(), ICompressCoder2) +#ifndef Z7_EXTRACT_ONLY +REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2) +#else +#define CreateCodecOut NULL +#endif + +REGISTER_CODEC_VAR(BCJ2) + { CreateCodec, CreateCodecOut, 0x303011B, "BCJ2", 4, false }; + +REGISTER_CODEC(BCJ2) + +}} diff --git a/CPP/7zip/Compress/BcjCoder.cpp b/CPP/7zip/Compress/BcjCoder.cpp index c48b7f5dc..004787474 100644 --- a/CPP/7zip/Compress/BcjCoder.cpp +++ b/CPP/7zip/Compress/BcjCoder.cpp @@ -1,24 +1,24 @@ -// BcjCoder.cpp - -#include "StdAfx.h" - -#include "BcjCoder.h" - -namespace NCompress { -namespace NBcj { - -Z7_COM7F_IMF(CCoder2::Init()) -{ - _pc = 0; - _state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; - return S_OK; -} - -Z7_COM7F_IMF2(UInt32, CCoder2::Filter(Byte *data, UInt32 size)) -{ - const UInt32 processed = (UInt32)(size_t)(_convFunc(data, size, _pc, &_state) - data); - _pc += processed; - return processed; -} - -}} +// BcjCoder.cpp + +#include "StdAfx.h" + +#include "BcjCoder.h" + +namespace NCompress { +namespace NBcj { + +Z7_COM7F_IMF(CCoder2::Init()) +{ + _pc = 0; + _state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL; + return S_OK; +} + +Z7_COM7F_IMF2(UInt32, CCoder2::Filter(Byte *data, UInt32 size)) +{ + const UInt32 processed = (UInt32)(size_t)(_convFunc(data, size, _pc, &_state) - data); + _pc += processed; + return processed; +} + +}} diff --git a/CPP/7zip/Compress/BcjCoder.h b/CPP/7zip/Compress/BcjCoder.h index 229ab4e2f..734a27866 100644 --- a/CPP/7zip/Compress/BcjCoder.h +++ b/CPP/7zip/Compress/BcjCoder.h @@ -1,37 +1,37 @@ -// BcjCoder.h - -#ifndef ZIP7_INC_COMPRESS_BCJ_CODER_H -#define ZIP7_INC_COMPRESS_BCJ_CODER_H - -#include "../../../C/Bra.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NBcj { - -/* CCoder in old versions used another constructor parameter CCoder(int encode). - And some code called it as CCoder(0). - We have changed constructor parameter type. - So we have changed the name of class also to CCoder2. */ - -Z7_CLASS_IMP_COM_1( - CCoder2 - , ICompressFilter -) - UInt32 _pc; - UInt32 _state; - z7_Func_BranchConvSt _convFunc; -public: - CCoder2(z7_Func_BranchConvSt convFunc): - _pc(0), - _state(Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL), - _convFunc(convFunc) - {} -}; - -}} - -#endif +// BcjCoder.h + +#ifndef ZIP7_INC_COMPRESS_BCJ_CODER_H +#define ZIP7_INC_COMPRESS_BCJ_CODER_H + +#include "../../../C/Bra.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NBcj { + +/* CCoder in old versions used another constructor parameter CCoder(int encode). + And some code called it as CCoder(0). + We have changed constructor parameter type. + So we have changed the name of class also to CCoder2. */ + +Z7_CLASS_IMP_COM_1( + CCoder2 + , ICompressFilter +) + UInt32 _pc; + UInt32 _state; + z7_Func_BranchConvSt _convFunc; +public: + CCoder2(z7_Func_BranchConvSt convFunc): + _pc(0), + _state(Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL), + _convFunc(convFunc) + {} +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/BcjRegister.cpp b/CPP/7zip/Compress/BcjRegister.cpp index 9bbae6b25..0348f641f 100644 --- a/CPP/7zip/Compress/BcjRegister.cpp +++ b/CPP/7zip/Compress/BcjRegister.cpp @@ -1,17 +1,17 @@ -// BcjRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "BcjCoder.h" - -namespace NCompress { -namespace NBcj { - -REGISTER_FILTER_E(BCJ, - CCoder2(z7_BranchConvSt_X86_Dec), - CCoder2(z7_BranchConvSt_X86_Enc), - 0x3030103, "BCJ") - -}} +// BcjRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "BcjCoder.h" + +namespace NCompress { +namespace NBcj { + +REGISTER_FILTER_E(BCJ, + CCoder2(z7_BranchConvSt_X86_Dec), + CCoder2(z7_BranchConvSt_X86_Enc), + 0x3030103, "BCJ") + +}} diff --git a/CPP/7zip/Compress/BitlDecoder.cpp b/CPP/7zip/Compress/BitlDecoder.cpp index 1236bab4b..bf1e5ba34 100644 --- a/CPP/7zip/Compress/BitlDecoder.cpp +++ b/CPP/7zip/Compress/BitlDecoder.cpp @@ -1,32 +1,32 @@ -// BitlDecoder.cpp - -#include "StdAfx.h" - -#include "BitlDecoder.h" - -namespace NBitl { - -#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) - -MY_ALIGN(64) -Byte kReverseTable[256]; - -static -struct CReverseerTableInitializer -{ - CReverseerTableInitializer() - { - for (unsigned i = 0; i < 256; i++) - { - unsigned - x = ((i & 0x55) << 1) | ((i >> 1) & 0x55); - x = ((x & 0x33) << 2) | ((x >> 2) & 0x33); - kReverseTable[i] = (Byte)((x << 4) | (x >> 4)); - } - } -} g_ReverseerTableInitializer; - -#elif 0 -unsigned ReverseBits8test(unsigned i) { return ReverseBits8(i); } -#endif -} +// BitlDecoder.cpp + +#include "StdAfx.h" + +#include "BitlDecoder.h" + +namespace NBitl { + +#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) + +MY_ALIGN(64) +Byte kReverseTable[256]; + +static +struct CReverseerTableInitializer +{ + CReverseerTableInitializer() + { + for (unsigned i = 0; i < 256; i++) + { + unsigned + x = ((i & 0x55) << 1) | ((i >> 1) & 0x55); + x = ((x & 0x33) << 2) | ((x >> 2) & 0x33); + kReverseTable[i] = (Byte)((x << 4) | (x >> 4)); + } + } +} g_ReverseerTableInitializer; + +#elif 0 +unsigned ReverseBits8test(unsigned i) { return ReverseBits8(i); } +#endif +} diff --git a/CPP/7zip/Compress/BitlDecoder.h b/CPP/7zip/Compress/BitlDecoder.h index c4e5a69a4..465c4d3d4 100644 --- a/CPP/7zip/Compress/BitlDecoder.h +++ b/CPP/7zip/Compress/BitlDecoder.h @@ -1,225 +1,225 @@ -// BitlDecoder.h -- the Least Significant Bit of byte is First - -#ifndef ZIP7_INC_BITL_DECODER_H -#define ZIP7_INC_BITL_DECODER_H - -#include "../../../C/CpuArch.h" - -#include "../IStream.h" - -namespace NBitl { - -const unsigned kNumBigValueBits = 8 * 4; -const unsigned kNumValueBytes = 3; -const unsigned kNumValueBits = 8 * kNumValueBytes; -const UInt32 kMask = (1 << kNumValueBits) - 1; - -#if !defined(Z7_BITL_USE_REVERSE_BITS_TABLE) -#if 1 && defined(MY_CPU_ARM_OR_ARM64) \ - && (defined(MY_CPU_ARM64) || defined(__ARM_ARCH_6T2__) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \ - && (defined(__GNUC__) && (__GNUC__ >= 4) \ - || defined(__clang__) && (__clang_major__ >= 4)) - #define Z7_BITL_USE_REVERSE_BITS_INSTRUCTION -#elif 1 - #define Z7_BITL_USE_REVERSE_BITS_TABLE -#endif -#endif - -#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) -extern Byte kReverseTable[256]; -#endif - -inline unsigned ReverseBits8(unsigned i) -{ -#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) - return kReverseTable[i]; -#elif defined(Z7_BITL_USE_REVERSE_BITS_INSTRUCTION) - // rbit is available in ARMv6T2 and above - asm ("rbit " -#if defined(MY_CPU_ARM) - "%0,%0" // it uses default register size, - // but we need 32-bit register here. - // we must use it only if default register size is 32-bit. - // it will work incorrectly for ARM64. -#else - "%w0,%w0" // it uses 32-bit registers in ARM64. - // compiler for (MY_CPU_ARM) can't compile it. -#endif - : "+r" (i)); - return i >> 24; -#else - unsigned - x = ((i & 0x55) << 1) | ((i >> 1) & 0x55); - x = ((x & 0x33) << 2) | ((x >> 2) & 0x33); - return ((x & 0x0f) << 4) | (x >> 4); -#endif -} - - -/* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream - TInByte::ReadByte() returns 0xFF after the end of stream - TInByte::NumExtraBytes contains the number "Extra Bytes" - - Bitl decoder can read up to 4 bytes ahead to internal buffer. */ - -template -class CBaseDecoder -{ -protected: - unsigned _bitPos; - UInt32 _value; - TInByte _stream; -public: - bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } - void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); } - void ClearStreamPtr() { _stream.ClearStreamPtr(); } - void Init() - { - _stream.Init(); - _bitPos = kNumBigValueBits; - _value = 0; - } - - // the size of portion data in real stream that was already read from this object. - // it doesn't include unused data in BitStream object buffer (up to 4 bytes) - // it doesn't include unused data in TInByte buffers - // it doesn't include virtual Extra bytes after the end of real stream data - UInt64 GetStreamSize() const - { - return ExtraBitsWereRead() ? - _stream.GetStreamSize(): - GetProcessedSize(); - } - - // the size of virtual data that was read from this object. - UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } - - bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; } - - Z7_FORCE_INLINE - void Normalize() - { - for (; _bitPos >= 8; _bitPos -= 8) - _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value; - } - - Z7_FORCE_INLINE - UInt32 ReadBits(unsigned numBits) - { - Normalize(); - UInt32 res = _value & ((1 << numBits) - 1); - _bitPos += numBits; - _value >>= numBits; - return res; - } - - bool ExtraBitsWereRead() const - { - return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); - } - - bool ExtraBitsWereRead_Fast() const - { - // full version is not inlined in vc6. - // return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); - - // (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that - // it doesn't return true, if small number of extra bits were read. - return (_stream.NumExtraBytes > 4); - } - - // it must be fixed !!! with extra bits - // UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; } -}; - -template -class CDecoder: public CBaseDecoder -{ - UInt32 _normalValue; - -public: - void Init() - { - CBaseDecoder::Init(); - _normalValue = 0; - } - - Z7_FORCE_INLINE - void Normalize() - { - for (; this->_bitPos >= 8; this->_bitPos -= 8) - { - const unsigned b = this->_stream.ReadByte(); - _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue; - this->_value = (this->_value << 8) | ReverseBits8(b); - } - } - - Z7_FORCE_INLINE - UInt32 GetValue(unsigned numBits) - { - Normalize(); - return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits); - } - - Z7_FORCE_INLINE - UInt32 GetValue_InHigh32bits() - { - Normalize(); - return this->_value << this->_bitPos; - } - - Z7_FORCE_INLINE - void MovePos(size_t numBits) - { - this->_bitPos += (unsigned)numBits; - _normalValue >>= numBits; - } - - Z7_FORCE_INLINE - UInt32 ReadBits(unsigned numBits) - { - Normalize(); - UInt32 res = _normalValue & ((1 << numBits) - 1); - MovePos(numBits); - return res; - } - - void AlignToByte() { MovePos((32 - this->_bitPos) & 7); } - - Z7_FORCE_INLINE - Byte ReadDirectByte() { return this->_stream.ReadByte(); } - - Z7_FORCE_INLINE - size_t ReadDirectBytesPart(Byte *buf, size_t size) { return this->_stream.ReadBytesPart(buf, size); } - - Z7_FORCE_INLINE - Byte ReadAlignedByte() - { - if (this->_bitPos == kNumBigValueBits) - return this->_stream.ReadByte(); - Byte b = (Byte)(_normalValue & 0xFF); - MovePos(8); - return b; - } - - // call it only if the object is aligned for byte. - Z7_FORCE_INLINE - bool ReadAlignedByte_FromBuf(Byte &b) - { - if (this->_stream.NumExtraBytes != 0) - if (this->_stream.NumExtraBytes >= 4 - || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3)) - return false; - if (this->_bitPos == kNumBigValueBits) - return this->_stream.ReadByte_FromBuf(b); - b = (Byte)(_normalValue & 0xFF); - MovePos(8); - return true; - } -}; - -} - -#endif +// BitlDecoder.h -- the Least Significant Bit of byte is First + +#ifndef ZIP7_INC_BITL_DECODER_H +#define ZIP7_INC_BITL_DECODER_H + +#include "../../../C/CpuArch.h" + +#include "../IStream.h" + +namespace NBitl { + +const unsigned kNumBigValueBits = 8 * 4; +const unsigned kNumValueBytes = 3; +const unsigned kNumValueBits = 8 * kNumValueBytes; +const UInt32 kMask = (1 << kNumValueBits) - 1; + +#if !defined(Z7_BITL_USE_REVERSE_BITS_TABLE) +#if 1 && defined(MY_CPU_ARM_OR_ARM64) \ + && (defined(MY_CPU_ARM64) || defined(__ARM_ARCH_6T2__) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \ + && (defined(__GNUC__) && (__GNUC__ >= 4) \ + || defined(__clang__) && (__clang_major__ >= 4)) + #define Z7_BITL_USE_REVERSE_BITS_INSTRUCTION +#elif 1 + #define Z7_BITL_USE_REVERSE_BITS_TABLE +#endif +#endif + +#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) +extern Byte kReverseTable[256]; +#endif + +inline unsigned ReverseBits8(unsigned i) +{ +#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) + return kReverseTable[i]; +#elif defined(Z7_BITL_USE_REVERSE_BITS_INSTRUCTION) + // rbit is available in ARMv6T2 and above + asm ("rbit " +#if defined(MY_CPU_ARM) + "%0,%0" // it uses default register size, + // but we need 32-bit register here. + // we must use it only if default register size is 32-bit. + // it will work incorrectly for ARM64. +#else + "%w0,%w0" // it uses 32-bit registers in ARM64. + // compiler for (MY_CPU_ARM) can't compile it. +#endif + : "+r" (i)); + return i >> 24; +#else + unsigned + x = ((i & 0x55) << 1) | ((i >> 1) & 0x55); + x = ((x & 0x33) << 2) | ((x >> 2) & 0x33); + return ((x & 0x0f) << 4) | (x >> 4); +#endif +} + + +/* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream + TInByte::ReadByte() returns 0xFF after the end of stream + TInByte::NumExtraBytes contains the number "Extra Bytes" + + Bitl decoder can read up to 4 bytes ahead to internal buffer. */ + +template +class CBaseDecoder +{ +protected: + unsigned _bitPos; + UInt32 _value; + TInByte _stream; +public: + bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } + void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); } + void ClearStreamPtr() { _stream.ClearStreamPtr(); } + void Init() + { + _stream.Init(); + _bitPos = kNumBigValueBits; + _value = 0; + } + + // the size of portion data in real stream that was already read from this object. + // it doesn't include unused data in BitStream object buffer (up to 4 bytes) + // it doesn't include unused data in TInByte buffers + // it doesn't include virtual Extra bytes after the end of real stream data + UInt64 GetStreamSize() const + { + return ExtraBitsWereRead() ? + _stream.GetStreamSize(): + GetProcessedSize(); + } + + // the size of virtual data that was read from this object. + UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } + + bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; } + + Z7_FORCE_INLINE + void Normalize() + { + for (; _bitPos >= 8; _bitPos -= 8) + _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value; + } + + Z7_FORCE_INLINE + UInt32 ReadBits(unsigned numBits) + { + Normalize(); + UInt32 res = _value & ((1 << numBits) - 1); + _bitPos += numBits; + _value >>= numBits; + return res; + } + + bool ExtraBitsWereRead() const + { + return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); + } + + bool ExtraBitsWereRead_Fast() const + { + // full version is not inlined in vc6. + // return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); + + // (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that + // it doesn't return true, if small number of extra bits were read. + return (_stream.NumExtraBytes > 4); + } + + // it must be fixed !!! with extra bits + // UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; } +}; + +template +class CDecoder: public CBaseDecoder +{ + UInt32 _normalValue; + +public: + void Init() + { + CBaseDecoder::Init(); + _normalValue = 0; + } + + Z7_FORCE_INLINE + void Normalize() + { + for (; this->_bitPos >= 8; this->_bitPos -= 8) + { + const unsigned b = this->_stream.ReadByte(); + _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue; + this->_value = (this->_value << 8) | ReverseBits8(b); + } + } + + Z7_FORCE_INLINE + UInt32 GetValue(unsigned numBits) + { + Normalize(); + return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits); + } + + Z7_FORCE_INLINE + UInt32 GetValue_InHigh32bits() + { + Normalize(); + return this->_value << this->_bitPos; + } + + Z7_FORCE_INLINE + void MovePos(size_t numBits) + { + this->_bitPos += (unsigned)numBits; + _normalValue >>= numBits; + } + + Z7_FORCE_INLINE + UInt32 ReadBits(unsigned numBits) + { + Normalize(); + UInt32 res = _normalValue & ((1 << numBits) - 1); + MovePos(numBits); + return res; + } + + void AlignToByte() { MovePos((32 - this->_bitPos) & 7); } + + Z7_FORCE_INLINE + Byte ReadDirectByte() { return this->_stream.ReadByte(); } + + Z7_FORCE_INLINE + size_t ReadDirectBytesPart(Byte *buf, size_t size) { return this->_stream.ReadBytesPart(buf, size); } + + Z7_FORCE_INLINE + Byte ReadAlignedByte() + { + if (this->_bitPos == kNumBigValueBits) + return this->_stream.ReadByte(); + Byte b = (Byte)(_normalValue & 0xFF); + MovePos(8); + return b; + } + + // call it only if the object is aligned for byte. + Z7_FORCE_INLINE + bool ReadAlignedByte_FromBuf(Byte &b) + { + if (this->_stream.NumExtraBytes != 0) + if (this->_stream.NumExtraBytes >= 4 + || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3)) + return false; + if (this->_bitPos == kNumBigValueBits) + return this->_stream.ReadByte_FromBuf(b); + b = (Byte)(_normalValue & 0xFF); + MovePos(8); + return true; + } +}; + +} + +#endif diff --git a/CPP/7zip/Compress/BitlEncoder.h b/CPP/7zip/Compress/BitlEncoder.h index 8b67ee063..67b142884 100644 --- a/CPP/7zip/Compress/BitlEncoder.h +++ b/CPP/7zip/Compress/BitlEncoder.h @@ -1,56 +1,56 @@ -// BitlEncoder.h -- the Least Significant Bit of byte is First - -#ifndef ZIP7_INC_BITL_ENCODER_H -#define ZIP7_INC_BITL_ENCODER_H - -#include "../Common/OutBuffer.h" - -class CBitlEncoder -{ - COutBuffer _stream; - unsigned _bitPos; - Byte _curByte; -public: - bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } - void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream); } - // unsigned GetBitPosition() const { return (8 - _bitPos); } - UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); } - void Init() - { - _stream.Init(); - _bitPos = 8; - _curByte = 0; - } - HRESULT Flush() - { - FlushByte(); - return _stream.Flush(); - } - void FlushByte() - { - if (_bitPos < 8) - _stream.WriteByte(_curByte); - _bitPos = 8; - _curByte = 0; - } - void WriteBits(UInt32 value, unsigned numBits) - { - while (numBits > 0) - { - if (numBits < _bitPos) - { - _curByte |= (Byte)((value & ((1 << numBits) - 1)) << (8 - _bitPos)); - _bitPos -= numBits; - return; - } - numBits -= _bitPos; - _stream.WriteByte((Byte)(_curByte | (value << (8 - _bitPos)))); - value >>= _bitPos; - _bitPos = 8; - _curByte = 0; - } - } - void WriteByte(Byte b) { _stream.WriteByte(b);} -}; - -#endif +// BitlEncoder.h -- the Least Significant Bit of byte is First + +#ifndef ZIP7_INC_BITL_ENCODER_H +#define ZIP7_INC_BITL_ENCODER_H + +#include "../Common/OutBuffer.h" + +class CBitlEncoder +{ + COutBuffer _stream; + unsigned _bitPos; + Byte _curByte; +public: + bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } + void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream); } + // unsigned GetBitPosition() const { return (8 - _bitPos); } + UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); } + void Init() + { + _stream.Init(); + _bitPos = 8; + _curByte = 0; + } + HRESULT Flush() + { + FlushByte(); + return _stream.Flush(); + } + void FlushByte() + { + if (_bitPos < 8) + _stream.WriteByte(_curByte); + _bitPos = 8; + _curByte = 0; + } + void WriteBits(UInt32 value, unsigned numBits) + { + while (numBits > 0) + { + if (numBits < _bitPos) + { + _curByte |= (Byte)((value & ((1 << numBits) - 1)) << (8 - _bitPos)); + _bitPos -= numBits; + return; + } + numBits -= _bitPos; + _stream.WriteByte((Byte)(_curByte | (value << (8 - _bitPos)))); + value >>= _bitPos; + _bitPos = 8; + _curByte = 0; + } + } + void WriteByte(Byte b) { _stream.WriteByte(b);} +}; + +#endif diff --git a/CPP/7zip/Compress/BitmDecoder.h b/CPP/7zip/Compress/BitmDecoder.h index 455d5a258..21c83dbd7 100644 --- a/CPP/7zip/Compress/BitmDecoder.h +++ b/CPP/7zip/Compress/BitmDecoder.h @@ -1,106 +1,106 @@ -// BitmDecoder.h -- the Most Significant Bit of byte is First - -#ifndef ZIP7_INC_BITM_DECODER_H -#define ZIP7_INC_BITM_DECODER_H - -#include "../IStream.h" - -namespace NBitm { - -const unsigned kNumBigValueBits = 8 * 4; -const unsigned kNumValueBytes = 3; -const unsigned kNumValueBits = 8 * kNumValueBytes; - -const UInt32 kMask = (1 << kNumValueBits) - 1; - -// _bitPos - the number of free bits (high bits in _value) -// (kNumBigValueBits - _bitPos) = (32 - _bitPos) == the number of ready to read bits (low bits of _value) - -template -class CDecoder -{ - unsigned _bitPos; - UInt32 _value; - TInByte _stream; -public: - bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } - void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream);} - - void Init() - { - _stream.Init(); - _bitPos = kNumBigValueBits; - _value = 0; - Normalize(); - } - - UInt64 GetStreamSize() const { return _stream.GetStreamSize(); } - UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } - - bool ExtraBitsWereRead() const - { - return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); - } - - bool ExtraBitsWereRead_Fast() const - { - return (_stream.NumExtraBytes > 4); - } - - Z7_FORCE_INLINE - void Normalize() - { - for (; _bitPos >= 8; _bitPos -= 8) - _value = (_value << 8) | _stream.ReadByte(); - } - - Z7_FORCE_INLINE - UInt32 GetValue(unsigned numBits) const - { - // return (_value << _bitPos) >> (kNumBigValueBits - numBits); - return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits); - } - - Z7_FORCE_INLINE - UInt32 GetValue_InHigh32bits() const - { - return this->_value << this->_bitPos; - } - - Z7_FORCE_INLINE - void MovePos(unsigned numBits) - { - _bitPos += numBits; - Normalize(); - } - - Z7_FORCE_INLINE - UInt32 ReadBits(unsigned numBits) - { - UInt32 res = GetValue(numBits); - MovePos(numBits); - return res; - } - - /* - unsigned ReadBit() - { - UInt32 res = ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - 1); - if (++_bitPos >= 8) - { - _value = (_value << 8) | _stream.ReadByte(); - _bitPos -= 8; - } - return (unsigned)res; - } - */ - - void AlignToByte() { MovePos((kNumBigValueBits - _bitPos) & 7); } - - Z7_FORCE_INLINE - UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); } -}; - -} - -#endif +// BitmDecoder.h -- the Most Significant Bit of byte is First + +#ifndef ZIP7_INC_BITM_DECODER_H +#define ZIP7_INC_BITM_DECODER_H + +#include "../IStream.h" + +namespace NBitm { + +const unsigned kNumBigValueBits = 8 * 4; +const unsigned kNumValueBytes = 3; +const unsigned kNumValueBits = 8 * kNumValueBytes; + +const UInt32 kMask = (1 << kNumValueBits) - 1; + +// _bitPos - the number of free bits (high bits in _value) +// (kNumBigValueBits - _bitPos) = (32 - _bitPos) == the number of ready to read bits (low bits of _value) + +template +class CDecoder +{ + unsigned _bitPos; + UInt32 _value; + TInByte _stream; +public: + bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } + void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream);} + + void Init() + { + _stream.Init(); + _bitPos = kNumBigValueBits; + _value = 0; + Normalize(); + } + + UInt64 GetStreamSize() const { return _stream.GetStreamSize(); } + UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } + + bool ExtraBitsWereRead() const + { + return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); + } + + bool ExtraBitsWereRead_Fast() const + { + return (_stream.NumExtraBytes > 4); + } + + Z7_FORCE_INLINE + void Normalize() + { + for (; _bitPos >= 8; _bitPos -= 8) + _value = (_value << 8) | _stream.ReadByte(); + } + + Z7_FORCE_INLINE + UInt32 GetValue(unsigned numBits) const + { + // return (_value << _bitPos) >> (kNumBigValueBits - numBits); + return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits); + } + + Z7_FORCE_INLINE + UInt32 GetValue_InHigh32bits() const + { + return this->_value << this->_bitPos; + } + + Z7_FORCE_INLINE + void MovePos(unsigned numBits) + { + _bitPos += numBits; + Normalize(); + } + + Z7_FORCE_INLINE + UInt32 ReadBits(unsigned numBits) + { + UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; + } + + /* + unsigned ReadBit() + { + UInt32 res = ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - 1); + if (++_bitPos >= 8) + { + _value = (_value << 8) | _stream.ReadByte(); + _bitPos -= 8; + } + return (unsigned)res; + } + */ + + void AlignToByte() { MovePos((kNumBigValueBits - _bitPos) & 7); } + + Z7_FORCE_INLINE + UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); } +}; + +} + +#endif diff --git a/CPP/7zip/Compress/BitmEncoder.h b/CPP/7zip/Compress/BitmEncoder.h index f0ae0d981..978ee1c06 100644 --- a/CPP/7zip/Compress/BitmEncoder.h +++ b/CPP/7zip/Compress/BitmEncoder.h @@ -1,49 +1,49 @@ -// BitmEncoder.h -- the Most Significant Bit of byte is First - -#ifndef ZIP7_INC_BITM_ENCODER_H -#define ZIP7_INC_BITM_ENCODER_H - -#include "../IStream.h" - -template -class CBitmEncoder -{ - unsigned _bitPos; - Byte _curByte; - TOutByte _stream; -public: - bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); } - void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream);} - UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); } - void Init() - { - _stream.Init(); - _bitPos = 8; - _curByte = 0; - } - HRESULT Flush() - { - if (_bitPos < 8) - WriteBits(0, _bitPos); - return _stream.Flush(); - } - void WriteBits(UInt32 value, unsigned numBits) - { - while (numBits > 0) - { - if (numBits < _bitPos) - { - _curByte = (Byte)(_curByte | (value << (_bitPos -= numBits))); - return; - } - numBits -= _bitPos; - UInt32 newBits = (value >> numBits); - value -= (newBits << numBits); - _stream.WriteByte((Byte)(_curByte | newBits)); - _bitPos = 8; - _curByte = 0; - } - } -}; - -#endif +// BitmEncoder.h -- the Most Significant Bit of byte is First + +#ifndef ZIP7_INC_BITM_ENCODER_H +#define ZIP7_INC_BITM_ENCODER_H + +#include "../IStream.h" + +template +class CBitmEncoder +{ + unsigned _bitPos; + Byte _curByte; + TOutByte _stream; +public: + bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); } + void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream);} + UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); } + void Init() + { + _stream.Init(); + _bitPos = 8; + _curByte = 0; + } + HRESULT Flush() + { + if (_bitPos < 8) + WriteBits(0, _bitPos); + return _stream.Flush(); + } + void WriteBits(UInt32 value, unsigned numBits) + { + while (numBits > 0) + { + if (numBits < _bitPos) + { + _curByte = (Byte)(_curByte | (value << (_bitPos -= numBits))); + return; + } + numBits -= _bitPos; + UInt32 newBits = (value >> numBits); + value -= (newBits << numBits); + _stream.WriteByte((Byte)(_curByte | newBits)); + _bitPos = 8; + _curByte = 0; + } + } +}; + +#endif diff --git a/CPP/7zip/Compress/BranchMisc.cpp b/CPP/7zip/Compress/BranchMisc.cpp index 6333fb99a..2098bebb3 100644 --- a/CPP/7zip/Compress/BranchMisc.cpp +++ b/CPP/7zip/Compress/BranchMisc.cpp @@ -1,106 +1,106 @@ -// BranchMisc.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../Common/StreamUtils.h" - -#include "BranchMisc.h" - -namespace NCompress { -namespace NBranch { - -Z7_COM7F_IMF(CCoder::Init()) -{ - _pc = 0; - return S_OK; -} - - -Z7_COM7F_IMF2(UInt32, CCoder::Filter(Byte *data, UInt32 size)) -{ - const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data); - _pc += processed; - return processed; -} - - -#ifndef Z7_EXTRACT_ONLY - -Z7_COM7F_IMF(CEncoder::Init()) -{ - _pc = _pc_Init; - return S_OK; -} - -Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) -{ - const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data); - _pc += processed; - return processed; -} - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -{ - UInt32 pc = 0; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPID propID = propIDs[i]; - if (propID == NCoderPropID::kDefaultProp || - propID == NCoderPropID::kBranchOffset) - { - const PROPVARIANT &prop = props[i]; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - pc = prop.ulVal; - if (pc & _alignment) - return E_INVALIDARG; - } - } - _pc_Init = pc; - return S_OK; -} - - -Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) -{ - if (_pc_Init == 0) - return S_OK; - UInt32 buf32[1]; - SetUi32(buf32, _pc_Init) - return WriteStream(outStream, buf32, 4); -} - -#endif - - -Z7_COM7F_IMF(CDecoder::Init()) -{ - _pc = _pc_Init; - return S_OK; -} - -Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) -{ - const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data); - _pc += processed; - return processed; -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) -{ - UInt32 val = 0; - if (size != 0) - { - if (size != 4) - return E_NOTIMPL; - val = GetUi32(props); - if (val & _alignment) - return E_NOTIMPL; - } - _pc_Init = val; - return S_OK; -} - -}} +// BranchMisc.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "BranchMisc.h" + +namespace NCompress { +namespace NBranch { + +Z7_COM7F_IMF(CCoder::Init()) +{ + _pc = 0; + return S_OK; +} + + +Z7_COM7F_IMF2(UInt32, CCoder::Filter(Byte *data, UInt32 size)) +{ + const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data); + _pc += processed; + return processed; +} + + +#ifndef Z7_EXTRACT_ONLY + +Z7_COM7F_IMF(CEncoder::Init()) +{ + _pc = _pc_Init; + return S_OK; +} + +Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) +{ + const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data); + _pc += processed; + return processed; +} + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +{ + UInt32 pc = 0; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPID propID = propIDs[i]; + if (propID == NCoderPropID::kDefaultProp || + propID == NCoderPropID::kBranchOffset) + { + const PROPVARIANT &prop = props[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + pc = prop.ulVal; + if (pc & _alignment) + return E_INVALIDARG; + } + } + _pc_Init = pc; + return S_OK; +} + + +Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) +{ + if (_pc_Init == 0) + return S_OK; + UInt32 buf32[1]; + SetUi32(buf32, _pc_Init) + return WriteStream(outStream, buf32, 4); +} + +#endif + + +Z7_COM7F_IMF(CDecoder::Init()) +{ + _pc = _pc_Init; + return S_OK; +} + +Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) +{ + const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data); + _pc += processed; + return processed; +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) +{ + UInt32 val = 0; + if (size != 0) + { + if (size != 4) + return E_NOTIMPL; + val = GetUi32(props); + if (val & _alignment) + return E_NOTIMPL; + } + _pc_Init = val; + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/BranchMisc.h b/CPP/7zip/Compress/BranchMisc.h index d12dd5fd1..2b5cc4208 100644 --- a/CPP/7zip/Compress/BranchMisc.h +++ b/CPP/7zip/Compress/BranchMisc.h @@ -1,59 +1,59 @@ -// BranchMisc.h - -#ifndef ZIP7_INC_COMPRESS_BRANCH_MISC_H -#define ZIP7_INC_COMPRESS_BRANCH_MISC_H -#include "../../../C/Bra.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NBranch { - -Z7_CLASS_IMP_COM_1( - CCoder - , ICompressFilter -) - UInt32 _pc; - z7_Func_BranchConv BraFunc; -public: - CCoder(z7_Func_BranchConv bra): _pc(0), BraFunc(bra) {} -}; - -#ifndef Z7_EXTRACT_ONLY - -Z7_CLASS_IMP_COM_3( - CEncoder - , ICompressFilter - , ICompressSetCoderProperties - , ICompressWriteCoderProperties -) - UInt32 _pc; - UInt32 _pc_Init; - UInt32 _alignment; - z7_Func_BranchConv BraFunc; -public: - CEncoder(z7_Func_BranchConv bra, UInt32 alignment): - _pc(0), _pc_Init(0), _alignment(alignment), BraFunc(bra) {} -}; - -#endif - -Z7_CLASS_IMP_COM_2( - CDecoder - , ICompressFilter - , ICompressSetDecoderProperties2 -) - UInt32 _pc; - UInt32 _pc_Init; - UInt32 _alignment; - z7_Func_BranchConv BraFunc; -public: - CDecoder(z7_Func_BranchConv bra, UInt32 alignment): - _pc(0), _pc_Init(0), _alignment(alignment), BraFunc(bra) {} -}; - -}} - -#endif +// BranchMisc.h + +#ifndef ZIP7_INC_COMPRESS_BRANCH_MISC_H +#define ZIP7_INC_COMPRESS_BRANCH_MISC_H +#include "../../../C/Bra.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NBranch { + +Z7_CLASS_IMP_COM_1( + CCoder + , ICompressFilter +) + UInt32 _pc; + z7_Func_BranchConv BraFunc; +public: + CCoder(z7_Func_BranchConv bra): _pc(0), BraFunc(bra) {} +}; + +#ifndef Z7_EXTRACT_ONLY + +Z7_CLASS_IMP_COM_3( + CEncoder + , ICompressFilter + , ICompressSetCoderProperties + , ICompressWriteCoderProperties +) + UInt32 _pc; + UInt32 _pc_Init; + UInt32 _alignment; + z7_Func_BranchConv BraFunc; +public: + CEncoder(z7_Func_BranchConv bra, UInt32 alignment): + _pc(0), _pc_Init(0), _alignment(alignment), BraFunc(bra) {} +}; + +#endif + +Z7_CLASS_IMP_COM_2( + CDecoder + , ICompressFilter + , ICompressSetDecoderProperties2 +) + UInt32 _pc; + UInt32 _pc_Init; + UInt32 _alignment; + z7_Func_BranchConv BraFunc; +public: + CDecoder(z7_Func_BranchConv bra, UInt32 alignment): + _pc(0), _pc_Init(0), _alignment(alignment), BraFunc(bra) {} +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/BranchRegister.cpp b/CPP/7zip/Compress/BranchRegister.cpp index c4da77f2e..20385ffde 100644 --- a/CPP/7zip/Compress/BranchRegister.cpp +++ b/CPP/7zip/Compress/BranchRegister.cpp @@ -1,58 +1,58 @@ -// BranchRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "BranchMisc.h" - -namespace NCompress { -namespace NBranch { - -#ifdef Z7_EXTRACT_ONLY -#define GET_CREATE_FUNC(x) NULL -#define CREATE_BRA_E(n) -#else -#define GET_CREATE_FUNC(x) x -#define CREATE_BRA_E(n) \ - REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(Z7_BRANCH_CONV_ENC_2(n))) -#endif - -#define CREATE_BRA(n) \ - REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(Z7_BRANCH_CONV_DEC_2(n))) \ - CREATE_BRA_E(n) - -CREATE_BRA(BranchConv_PPC) -CREATE_BRA(BranchConv_IA64) -CREATE_BRA(BranchConv_ARM) -CREATE_BRA(BranchConv_ARMT) -CREATE_BRA(BranchConv_SPARC) - -#define METHOD_ITEM(n, id, name) \ - REGISTER_FILTER_ITEM( \ - CreateBra_Decoder_ ## n, GET_CREATE_FUNC( \ - CreateBra_Encoder_ ## n), \ - 0x3030000 + id, name) - -REGISTER_CODECS_VAR -{ - METHOD_ITEM(BranchConv_PPC, 0x205, "PPC"), - METHOD_ITEM(BranchConv_IA64, 0x401, "IA64"), - METHOD_ITEM(BranchConv_ARM, 0x501, "ARM"), - METHOD_ITEM(BranchConv_ARMT, 0x701, "ARMT"), - METHOD_ITEM(BranchConv_SPARC, 0x805, "SPARC") -}; - -REGISTER_CODECS(Branch) - - -#define REGISTER_FILTER_E_BRANCH(id, n, name, alignment) \ - REGISTER_FILTER_E(n, \ - CDecoder(Z7_BRANCH_CONV_DEC(n), alignment), \ - CEncoder(Z7_BRANCH_CONV_ENC(n), alignment), \ - id, name) - -REGISTER_FILTER_E_BRANCH(0xa, ARM64, "ARM64", 3) -REGISTER_FILTER_E_BRANCH(0xb, RISCV, "RISCV", 1) - -}} +// BranchRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "BranchMisc.h" + +namespace NCompress { +namespace NBranch { + +#ifdef Z7_EXTRACT_ONLY +#define GET_CREATE_FUNC(x) NULL +#define CREATE_BRA_E(n) +#else +#define GET_CREATE_FUNC(x) x +#define CREATE_BRA_E(n) \ + REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(Z7_BRANCH_CONV_ENC_2(n))) +#endif + +#define CREATE_BRA(n) \ + REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(Z7_BRANCH_CONV_DEC_2(n))) \ + CREATE_BRA_E(n) + +CREATE_BRA(BranchConv_PPC) +CREATE_BRA(BranchConv_IA64) +CREATE_BRA(BranchConv_ARM) +CREATE_BRA(BranchConv_ARMT) +CREATE_BRA(BranchConv_SPARC) + +#define METHOD_ITEM(n, id, name) \ + REGISTER_FILTER_ITEM( \ + CreateBra_Decoder_ ## n, GET_CREATE_FUNC( \ + CreateBra_Encoder_ ## n), \ + 0x3030000 + id, name) + +REGISTER_CODECS_VAR +{ + METHOD_ITEM(BranchConv_PPC, 0x205, "PPC"), + METHOD_ITEM(BranchConv_IA64, 0x401, "IA64"), + METHOD_ITEM(BranchConv_ARM, 0x501, "ARM"), + METHOD_ITEM(BranchConv_ARMT, 0x701, "ARMT"), + METHOD_ITEM(BranchConv_SPARC, 0x805, "SPARC") +}; + +REGISTER_CODECS(Branch) + + +#define REGISTER_FILTER_E_BRANCH(id, n, name, alignment) \ + REGISTER_FILTER_E(n, \ + CDecoder(Z7_BRANCH_CONV_DEC(n), alignment), \ + CEncoder(Z7_BRANCH_CONV_ENC(n), alignment), \ + id, name) + +REGISTER_FILTER_E_BRANCH(0xa, ARM64, "ARM64", 3) +REGISTER_FILTER_E_BRANCH(0xb, RISCV, "RISCV", 1) + +}} diff --git a/CPP/7zip/Compress/ByteSwap.cpp b/CPP/7zip/Compress/ByteSwap.cpp index d8a784c64..cc28d8b90 100644 --- a/CPP/7zip/Compress/ByteSwap.cpp +++ b/CPP/7zip/Compress/ByteSwap.cpp @@ -1,91 +1,91 @@ -// ByteSwap.cpp - -#include "StdAfx.h" - -#include "../../../C/SwapBytes.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/RegisterCodec.h" - -namespace NCompress { -namespace NByteSwap { - -Z7_CLASS_IMP_COM_1(CByteSwap2, ICompressFilter) }; -Z7_CLASS_IMP_COM_1(CByteSwap4, ICompressFilter) }; - -Z7_COM7F_IMF(CByteSwap2::Init()) { return S_OK; } - -Z7_COM7F_IMF2(UInt32, CByteSwap2::Filter(Byte *data, UInt32 size)) -{ - const UInt32 kMask = 2 - 1; - size &= ~kMask; - /* - if ((unsigned)(ptrdiff_t)data & kMask) - { - if (size == 0) - return 0; - const Byte *end = data + (size_t)size; - do - { - const Byte b0 = data[0]; - data[0] = data[1]; - data[1] = b0; - data += kStep; - } - while (data != end); - } - else - */ - z7_SwapBytes2((UInt16 *)(void *)data, size >> 1); - return size; -} - - -Z7_COM7F_IMF(CByteSwap4::Init()) { return S_OK; } - -Z7_COM7F_IMF2(UInt32, CByteSwap4::Filter(Byte *data, UInt32 size)) -{ - const UInt32 kMask = 4 - 1; - size &= ~kMask; - /* - if ((unsigned)(ptrdiff_t)data & kMask) - { - if (size == 0) - return 0; - const Byte *end = data + (size_t)size; - do - { - const Byte b0 = data[0]; - const Byte b1 = data[1]; - data[0] = data[3]; - data[1] = data[2]; - data[2] = b1; - data[3] = b0; - data += kStep; - } - while (data != end); - } - else - */ - z7_SwapBytes4((UInt32 *)(void *)data, size >> 2); - return size; -} - -static struct C_SwapBytesPrepare { C_SwapBytesPrepare() { z7_SwapBytesPrepare(); } } g_SwapBytesPrepare; - - -REGISTER_FILTER_CREATE(CreateFilter2, CByteSwap2()) -REGISTER_FILTER_CREATE(CreateFilter4, CByteSwap4()) - -REGISTER_CODECS_VAR -{ - REGISTER_FILTER_ITEM(CreateFilter2, CreateFilter2, 0x20302, "Swap2"), - REGISTER_FILTER_ITEM(CreateFilter4, CreateFilter4, 0x20304, "Swap4"), -}; - -REGISTER_CODECS(ByteSwap) - -}} +// ByteSwap.cpp + +#include "StdAfx.h" + +#include "../../../C/SwapBytes.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/RegisterCodec.h" + +namespace NCompress { +namespace NByteSwap { + +Z7_CLASS_IMP_COM_1(CByteSwap2, ICompressFilter) }; +Z7_CLASS_IMP_COM_1(CByteSwap4, ICompressFilter) }; + +Z7_COM7F_IMF(CByteSwap2::Init()) { return S_OK; } + +Z7_COM7F_IMF2(UInt32, CByteSwap2::Filter(Byte *data, UInt32 size)) +{ + const UInt32 kMask = 2 - 1; + size &= ~kMask; + /* + if ((unsigned)(ptrdiff_t)data & kMask) + { + if (size == 0) + return 0; + const Byte *end = data + (size_t)size; + do + { + const Byte b0 = data[0]; + data[0] = data[1]; + data[1] = b0; + data += kStep; + } + while (data != end); + } + else + */ + z7_SwapBytes2((UInt16 *)(void *)data, size >> 1); + return size; +} + + +Z7_COM7F_IMF(CByteSwap4::Init()) { return S_OK; } + +Z7_COM7F_IMF2(UInt32, CByteSwap4::Filter(Byte *data, UInt32 size)) +{ + const UInt32 kMask = 4 - 1; + size &= ~kMask; + /* + if ((unsigned)(ptrdiff_t)data & kMask) + { + if (size == 0) + return 0; + const Byte *end = data + (size_t)size; + do + { + const Byte b0 = data[0]; + const Byte b1 = data[1]; + data[0] = data[3]; + data[1] = data[2]; + data[2] = b1; + data[3] = b0; + data += kStep; + } + while (data != end); + } + else + */ + z7_SwapBytes4((UInt32 *)(void *)data, size >> 2); + return size; +} + +static struct C_SwapBytesPrepare { C_SwapBytesPrepare() { z7_SwapBytesPrepare(); } } g_SwapBytesPrepare; + + +REGISTER_FILTER_CREATE(CreateFilter2, CByteSwap2()) +REGISTER_FILTER_CREATE(CreateFilter4, CByteSwap4()) + +REGISTER_CODECS_VAR +{ + REGISTER_FILTER_ITEM(CreateFilter2, CreateFilter2, 0x20302, "Swap2"), + REGISTER_FILTER_ITEM(CreateFilter4, CreateFilter4, 0x20304, "Swap4"), +}; + +REGISTER_CODECS(ByteSwap) + +}} diff --git a/CPP/7zip/Compress/Codec.def b/CPP/7zip/Compress/Codec.def index 3e88fd9e6..e2bc0dfdb 100644 --- a/CPP/7zip/Compress/Codec.def +++ b/CPP/7zip/Compress/Codec.def @@ -1,7 +1,7 @@ -EXPORTS - CreateObject PRIVATE - GetNumberOfMethods PRIVATE - GetMethodProperty PRIVATE - CreateDecoder PRIVATE - CreateEncoder PRIVATE - GetModuleProp PRIVATE +EXPORTS + CreateObject PRIVATE + GetNumberOfMethods PRIVATE + GetMethodProperty PRIVATE + CreateDecoder PRIVATE + CreateEncoder PRIVATE + GetModuleProp PRIVATE diff --git a/CPP/7zip/Compress/CodecExports.cpp b/CPP/7zip/Compress/CodecExports.cpp index 6b0572e8d..e37ae143b 100644 --- a/CPP/7zip/Compress/CodecExports.cpp +++ b/CPP/7zip/Compress/CodecExports.cpp @@ -1,378 +1,378 @@ -// CodecExports.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/7zVersion.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyCom.h" - -#include "../../Windows/Defs.h" -#include "../../Windows/PropVariant.h" - -#include "../ICoder.h" - -#include "../Common/RegisterCodec.h" - -extern unsigned g_NumCodecs; -extern const CCodecInfo *g_Codecs[]; - -extern unsigned g_NumHashers; -extern const CHasherInfo *g_Hashers[]; - -static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw() -{ - const UINT len = (UINT)strlen(s); - BSTR dest = ::SysAllocStringLen(NULL, len); - if (dest) - { - for (UINT i = 0; i <= len; i++) - dest[i] = (Byte)s[i]; - prop->bstrVal = dest; - prop->vt = VT_BSTR; - } -} - -static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw() -{ - if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL) - value->vt = VT_BSTR; - return S_OK; -} - -static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw() -{ - GUID clsId; - clsId.Data1 = k_7zip_GUID_Data1; - clsId.Data2 = k_7zip_GUID_Data2; - clsId.Data3 = typeId; - SetUi64(clsId.Data4, id) - return SetPropGUID(clsId, value); -} - -static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw() -{ - index = -1; - if (clsid->Data1 != k_7zip_GUID_Data1 || - clsid->Data2 != k_7zip_GUID_Data2) - return S_OK; - - encode = true; - - if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false; - else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK; - - const UInt64 id = GetUi64(clsid->Data4); - - for (unsigned i = 0; i < g_NumCodecs; i++) - { - const CCodecInfo &codec = *g_Codecs[i]; - - if (id != codec.Id - || (encode ? !codec.CreateEncoder : !codec.CreateDecoder) - || (isFilter ? !codec.IsFilter : codec.IsFilter)) - continue; - - if (codec.NumStreams == 1 ? isCoder2 : !isCoder2) - return E_NOINTERFACE; - - index = (int)i; - return S_OK; - } - - return S_OK; -} - -/* -#ifdef __GNUC__ -#ifndef __clang__ -#pragma GCC diagnostic ignored "-Wduplicated-branches" -#endif -#endif -*/ - -static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder) -{ - COM_TRY_BEGIN - - const CCodecInfo &codec = *g_Codecs[index]; - - void *c; - if (encode) - c = codec.CreateEncoder(); - else - c = codec.CreateDecoder(); - - if (c) - { - IUnknown *unk; - unk = (IUnknown *)c; - /* - if (codec.IsFilter) - unk = (IUnknown *)(ICompressFilter *)c; - else if (codec.NumStreams != 1) - unk = (IUnknown *)(ICompressCoder2 *)c; - else - unk = (IUnknown *)(ICompressCoder *)c; - */ - unk->AddRef(); - *coder = c; - } - return S_OK; - - COM_TRY_END -} - -static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject) -{ - *outObject = NULL; - - const CCodecInfo &codec = *g_Codecs[index]; - - if (encode ? !codec.CreateEncoder : !codec.CreateDecoder) - return CLASS_E_CLASSNOTAVAILABLE; - - if (codec.IsFilter) - { - if (*iid != IID_ICompressFilter) return E_NOINTERFACE; - } - else if (codec.NumStreams != 1) - { - if (*iid != IID_ICompressCoder2) return E_NOINTERFACE; - } - else - { - if (*iid != IID_ICompressCoder) return E_NOINTERFACE; - } - - return CreateCoderMain(index, encode, outObject); -} - - -STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject); -STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject) -{ - return CreateCoder2(false, index, iid, outObject); -} - - -STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject); -STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject) -{ - return CreateCoder2(true, index, iid, outObject); -} - - -STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); -STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject) -{ - *outObject = NULL; - - bool isFilter = false; - bool isCoder2 = false; - const bool isCoder = (*iid == IID_ICompressCoder) != 0; - if (!isCoder) - { - isFilter = (*iid == IID_ICompressFilter) != 0; - if (!isFilter) - { - isCoder2 = (*iid == IID_ICompressCoder2) != 0; - if (!isCoder2) - return E_NOINTERFACE; - } - } - - bool encode; - int codecIndex; - const HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex); - if (res != S_OK) - return res; - if (codecIndex < 0) - return CLASS_E_CLASSNOTAVAILABLE; - - return CreateCoderMain((unsigned)codecIndex, encode, outObject); -} - - -STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); -STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) -{ - ::VariantClear((VARIANTARG *)value); - const CCodecInfo &codec = *g_Codecs[codecIndex]; - switch (propID) - { - case NMethodPropID::kID: - value->uhVal.QuadPart = (UInt64)codec.Id; - value->vt = VT_UI8; - break; - case NMethodPropID::kName: - SetPropFromAscii(codec.Name, value); - break; - case NMethodPropID::kDecoder: - if (codec.CreateDecoder) - return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value); - break; - case NMethodPropID::kEncoder: - if (codec.CreateEncoder) - return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value); - break; - case NMethodPropID::kDecoderIsAssigned: - value->vt = VT_BOOL; - value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL); - break; - case NMethodPropID::kEncoderIsAssigned: - value->vt = VT_BOOL; - value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL); - break; - case NMethodPropID::kPackStreams: - if (codec.NumStreams != 1) - { - value->vt = VT_UI4; - value->ulVal = (ULONG)codec.NumStreams; - } - break; - case NMethodPropID::kIsFilter: - { - value->vt = VT_BOOL; - value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter); - } - break; - /* - case NMethodPropID::kDecoderFlags: - { - value->vt = VT_UI4; - value->ulVal = (ULONG)codec.DecoderFlags; - } - break; - case NMethodPropID::kEncoderFlags: - { - value->vt = VT_UI4; - value->ulVal = (ULONG)codec.EncoderFlags; - } - break; - */ - } - return S_OK; -} - - -STDAPI GetNumberOfMethods(UInt32 *numCodecs); -STDAPI GetNumberOfMethods(UInt32 *numCodecs) -{ - *numCodecs = g_NumCodecs; - return S_OK; -} - - -// ---------- Hashers ---------- - -static int FindHasherClassId(const GUID *clsid) throw() -{ - if (clsid->Data1 != k_7zip_GUID_Data1 || - clsid->Data2 != k_7zip_GUID_Data2 || - clsid->Data3 != k_7zip_GUID_Data3_Hasher) - return -1; - const UInt64 id = GetUi64(clsid->Data4); - for (unsigned i = 0; i < g_NumCodecs; i++) - if (id == g_Hashers[i]->Id) - return (int)i; - return -1; -} - -static HRESULT CreateHasher2(UInt32 index, IHasher **hasher) -{ - COM_TRY_BEGIN - *hasher = g_Hashers[index]->CreateHasher(); - if (*hasher) - (*hasher)->AddRef(); - return S_OK; - COM_TRY_END -} - -STDAPI CreateHasher(const GUID *clsid, IHasher **outObject); -STDAPI CreateHasher(const GUID *clsid, IHasher **outObject) -{ - COM_TRY_BEGIN - *outObject = NULL; - const int index = FindHasherClassId(clsid); - if (index < 0) - return CLASS_E_CLASSNOTAVAILABLE; - return CreateHasher2((UInt32)(unsigned)index, outObject); - COM_TRY_END -} - -STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); -STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) -{ - ::VariantClear((VARIANTARG *)value); - const CHasherInfo &codec = *g_Hashers[codecIndex]; - switch (propID) - { - case NMethodPropID::kID: - value->uhVal.QuadPart = (UInt64)codec.Id; - value->vt = VT_UI8; - break; - case NMethodPropID::kName: - SetPropFromAscii(codec.Name, value); - break; - case NMethodPropID::kEncoder: - if (codec.CreateHasher) - return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value); - break; - case NMethodPropID::kDigestSize: - value->ulVal = (ULONG)codec.DigestSize; - value->vt = VT_UI4; - break; - } - return S_OK; -} - -Z7_CLASS_IMP_COM_1(CHashers, IHashers) }; - -STDAPI GetHashers(IHashers **hashers); -STDAPI GetHashers(IHashers **hashers) -{ - COM_TRY_BEGIN - *hashers = new CHashers; - if (*hashers) - (*hashers)->AddRef(); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF2(UInt32, CHashers::GetNumHashers()) -{ - return g_NumHashers; -} - -Z7_COM7F_IMF(CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - return ::GetHasherProp(index, propID, value); -} - -Z7_COM7F_IMF(CHashers::CreateHasher(UInt32 index, IHasher **hasher)) -{ - return ::CreateHasher2(index, hasher); -} - - -STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value); -STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value) -{ - ::VariantClear((VARIANTARG *)value); - switch (propID) - { - case NModulePropID::kInterfaceType: - { - NWindows::NCOM::PropVarEm_Set_UInt32(value, NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule); - break; - } - case NModulePropID::kVersion: - { - NWindows::NCOM::PropVarEm_Set_UInt32(value, (MY_VER_MAJOR << 16) | MY_VER_MINOR); - break; - } - } - return S_OK; -} +// CodecExports.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/7zVersion.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyCom.h" + +#include "../../Windows/Defs.h" +#include "../../Windows/PropVariant.h" + +#include "../ICoder.h" + +#include "../Common/RegisterCodec.h" + +extern unsigned g_NumCodecs; +extern const CCodecInfo *g_Codecs[]; + +extern unsigned g_NumHashers; +extern const CHasherInfo *g_Hashers[]; + +static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw() +{ + const UINT len = (UINT)strlen(s); + BSTR dest = ::SysAllocStringLen(NULL, len); + if (dest) + { + for (UINT i = 0; i <= len; i++) + dest[i] = (Byte)s[i]; + prop->bstrVal = dest; + prop->vt = VT_BSTR; + } +} + +static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw() +{ + if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL) + value->vt = VT_BSTR; + return S_OK; +} + +static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw() +{ + GUID clsId; + clsId.Data1 = k_7zip_GUID_Data1; + clsId.Data2 = k_7zip_GUID_Data2; + clsId.Data3 = typeId; + SetUi64(clsId.Data4, id) + return SetPropGUID(clsId, value); +} + +static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw() +{ + index = -1; + if (clsid->Data1 != k_7zip_GUID_Data1 || + clsid->Data2 != k_7zip_GUID_Data2) + return S_OK; + + encode = true; + + if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false; + else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK; + + const UInt64 id = GetUi64(clsid->Data4); + + for (unsigned i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &codec = *g_Codecs[i]; + + if (id != codec.Id + || (encode ? !codec.CreateEncoder : !codec.CreateDecoder) + || (isFilter ? !codec.IsFilter : codec.IsFilter)) + continue; + + if (codec.NumStreams == 1 ? isCoder2 : !isCoder2) + return E_NOINTERFACE; + + index = (int)i; + return S_OK; + } + + return S_OK; +} + +/* +#ifdef __GNUC__ +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wduplicated-branches" +#endif +#endif +*/ + +static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder) +{ + COM_TRY_BEGIN + + const CCodecInfo &codec = *g_Codecs[index]; + + void *c; + if (encode) + c = codec.CreateEncoder(); + else + c = codec.CreateDecoder(); + + if (c) + { + IUnknown *unk; + unk = (IUnknown *)c; + /* + if (codec.IsFilter) + unk = (IUnknown *)(ICompressFilter *)c; + else if (codec.NumStreams != 1) + unk = (IUnknown *)(ICompressCoder2 *)c; + else + unk = (IUnknown *)(ICompressCoder *)c; + */ + unk->AddRef(); + *coder = c; + } + return S_OK; + + COM_TRY_END +} + +static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject) +{ + *outObject = NULL; + + const CCodecInfo &codec = *g_Codecs[index]; + + if (encode ? !codec.CreateEncoder : !codec.CreateDecoder) + return CLASS_E_CLASSNOTAVAILABLE; + + if (codec.IsFilter) + { + if (*iid != IID_ICompressFilter) return E_NOINTERFACE; + } + else if (codec.NumStreams != 1) + { + if (*iid != IID_ICompressCoder2) return E_NOINTERFACE; + } + else + { + if (*iid != IID_ICompressCoder) return E_NOINTERFACE; + } + + return CreateCoderMain(index, encode, outObject); +} + + +STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject); +STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject) +{ + return CreateCoder2(false, index, iid, outObject); +} + + +STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject); +STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject) +{ + return CreateCoder2(true, index, iid, outObject); +} + + +STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject) +{ + *outObject = NULL; + + bool isFilter = false; + bool isCoder2 = false; + const bool isCoder = (*iid == IID_ICompressCoder) != 0; + if (!isCoder) + { + isFilter = (*iid == IID_ICompressFilter) != 0; + if (!isFilter) + { + isCoder2 = (*iid == IID_ICompressCoder2) != 0; + if (!isCoder2) + return E_NOINTERFACE; + } + } + + bool encode; + int codecIndex; + const HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex); + if (res != S_OK) + return res; + if (codecIndex < 0) + return CLASS_E_CLASSNOTAVAILABLE; + + return CreateCoderMain((unsigned)codecIndex, encode, outObject); +} + + +STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) +{ + ::VariantClear((VARIANTARG *)value); + const CCodecInfo &codec = *g_Codecs[codecIndex]; + switch (propID) + { + case NMethodPropID::kID: + value->uhVal.QuadPart = (UInt64)codec.Id; + value->vt = VT_UI8; + break; + case NMethodPropID::kName: + SetPropFromAscii(codec.Name, value); + break; + case NMethodPropID::kDecoder: + if (codec.CreateDecoder) + return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value); + break; + case NMethodPropID::kEncoder: + if (codec.CreateEncoder) + return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value); + break; + case NMethodPropID::kDecoderIsAssigned: + value->vt = VT_BOOL; + value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL); + break; + case NMethodPropID::kEncoderIsAssigned: + value->vt = VT_BOOL; + value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL); + break; + case NMethodPropID::kPackStreams: + if (codec.NumStreams != 1) + { + value->vt = VT_UI4; + value->ulVal = (ULONG)codec.NumStreams; + } + break; + case NMethodPropID::kIsFilter: + { + value->vt = VT_BOOL; + value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter); + } + break; + /* + case NMethodPropID::kDecoderFlags: + { + value->vt = VT_UI4; + value->ulVal = (ULONG)codec.DecoderFlags; + } + break; + case NMethodPropID::kEncoderFlags: + { + value->vt = VT_UI4; + value->ulVal = (ULONG)codec.EncoderFlags; + } + break; + */ + } + return S_OK; +} + + +STDAPI GetNumberOfMethods(UInt32 *numCodecs); +STDAPI GetNumberOfMethods(UInt32 *numCodecs) +{ + *numCodecs = g_NumCodecs; + return S_OK; +} + + +// ---------- Hashers ---------- + +static int FindHasherClassId(const GUID *clsid) throw() +{ + if (clsid->Data1 != k_7zip_GUID_Data1 || + clsid->Data2 != k_7zip_GUID_Data2 || + clsid->Data3 != k_7zip_GUID_Data3_Hasher) + return -1; + const UInt64 id = GetUi64(clsid->Data4); + for (unsigned i = 0; i < g_NumCodecs; i++) + if (id == g_Hashers[i]->Id) + return (int)i; + return -1; +} + +static HRESULT CreateHasher2(UInt32 index, IHasher **hasher) +{ + COM_TRY_BEGIN + *hasher = g_Hashers[index]->CreateHasher(); + if (*hasher) + (*hasher)->AddRef(); + return S_OK; + COM_TRY_END +} + +STDAPI CreateHasher(const GUID *clsid, IHasher **outObject); +STDAPI CreateHasher(const GUID *clsid, IHasher **outObject) +{ + COM_TRY_BEGIN + *outObject = NULL; + const int index = FindHasherClassId(clsid); + if (index < 0) + return CLASS_E_CLASSNOTAVAILABLE; + return CreateHasher2((UInt32)(unsigned)index, outObject); + COM_TRY_END +} + +STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value) +{ + ::VariantClear((VARIANTARG *)value); + const CHasherInfo &codec = *g_Hashers[codecIndex]; + switch (propID) + { + case NMethodPropID::kID: + value->uhVal.QuadPart = (UInt64)codec.Id; + value->vt = VT_UI8; + break; + case NMethodPropID::kName: + SetPropFromAscii(codec.Name, value); + break; + case NMethodPropID::kEncoder: + if (codec.CreateHasher) + return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value); + break; + case NMethodPropID::kDigestSize: + value->ulVal = (ULONG)codec.DigestSize; + value->vt = VT_UI4; + break; + } + return S_OK; +} + +Z7_CLASS_IMP_COM_1(CHashers, IHashers) }; + +STDAPI GetHashers(IHashers **hashers); +STDAPI GetHashers(IHashers **hashers) +{ + COM_TRY_BEGIN + *hashers = new CHashers; + if (*hashers) + (*hashers)->AddRef(); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF2(UInt32, CHashers::GetNumHashers()) +{ + return g_NumHashers; +} + +Z7_COM7F_IMF(CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + return ::GetHasherProp(index, propID, value); +} + +Z7_COM7F_IMF(CHashers::CreateHasher(UInt32 index, IHasher **hasher)) +{ + return ::CreateHasher2(index, hasher); +} + + +STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value); +STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value) +{ + ::VariantClear((VARIANTARG *)value); + switch (propID) + { + case NModulePropID::kInterfaceType: + { + NWindows::NCOM::PropVarEm_Set_UInt32(value, NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule); + break; + } + case NModulePropID::kVersion: + { + NWindows::NCOM::PropVarEm_Set_UInt32(value, (MY_VER_MAJOR << 16) | MY_VER_MINOR); + break; + } + } + return S_OK; +} diff --git a/CPP/7zip/Compress/CopyCoder.cpp b/CPP/7zip/Compress/CopyCoder.cpp index d4e8acee8..b779e08b5 100644 --- a/CPP/7zip/Compress/CopyCoder.cpp +++ b/CPP/7zip/Compress/CopyCoder.cpp @@ -1,153 +1,153 @@ -// Compress/CopyCoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "CopyCoder.h" - -namespace NCompress { - -static const UInt32 kBufSize = 1 << 17; - -CCopyCoder::~CCopyCoder() -{ - ::MidFree(_buf); -} - -Z7_COM7F_IMF(CCopyCoder::SetFinishMode(UInt32 /* finishMode */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CCopyCoder::Code(ISequentialInStream *inStream, - ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, - ICompressProgressInfo *progress)) -{ - if (!_buf) - { - _buf = (Byte *)::MidAlloc(kBufSize); - if (!_buf) - return E_OUTOFMEMORY; - } - - TotalSize = 0; - - for (;;) - { - UInt32 size = kBufSize; - if (outSize) - { - const UInt64 rem = *outSize - TotalSize; - if (size > rem) - { - size = (UInt32)rem; - if (size == 0) - { - /* if we enable the following check, - we will make one call of Read(_buf, 0) for empty stream */ - // if (TotalSize != 0) - return S_OK; - } - } - } - - HRESULT readRes; - { - UInt32 pos = 0; - do - { - const UInt32 curSize = size - pos; - UInt32 processed = 0; - readRes = inStream->Read(_buf + pos, curSize, &processed); - if (processed > curSize) - return E_FAIL; // internal code failure - pos += processed; - if (readRes != S_OK || processed == 0) - break; - } - while (pos < kBufSize); - size = pos; - } - - if (size == 0) - return readRes; - - if (outStream) - { - UInt32 pos = 0; - do - { - const UInt32 curSize = size - pos; - UInt32 processed = 0; - const HRESULT res = outStream->Write(_buf + pos, curSize, &processed); - if (processed > curSize) - return E_FAIL; // internal code failure - pos += processed; - TotalSize += processed; - RINOK(res) - if (processed == 0) - return E_FAIL; - } - while (pos < size); - } - else - TotalSize += size; - - RINOK(readRes) - - if (size != kBufSize) - return S_OK; - - if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0) - { - RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)) - } - } -} - -Z7_COM7F_IMF(CCopyCoder::SetInStream(ISequentialInStream *inStream)) -{ - _inStream = inStream; - TotalSize = 0; - return S_OK; -} - -Z7_COM7F_IMF(CCopyCoder::ReleaseInStream()) -{ - _inStream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - UInt32 realProcessedSize = 0; - HRESULT res = _inStream->Read(data, size, &realProcessedSize); - TotalSize += realProcessedSize; - if (processedSize) - *processedSize = realProcessedSize; - return res; -} - -Z7_COM7F_IMF(CCopyCoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = TotalSize; - return S_OK; -} - -HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - CMyComPtr copyCoder = new CCopyCoder; - return copyCoder->Code(inStream, outStream, NULL, NULL, progress); -} - -HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) -{ - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; - RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)) - return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; -} - -} +// Compress/CopyCoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "CopyCoder.h" + +namespace NCompress { + +static const UInt32 kBufSize = 1 << 17; + +CCopyCoder::~CCopyCoder() +{ + ::MidFree(_buf); +} + +Z7_COM7F_IMF(CCopyCoder::SetFinishMode(UInt32 /* finishMode */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CCopyCoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, + ICompressProgressInfo *progress)) +{ + if (!_buf) + { + _buf = (Byte *)::MidAlloc(kBufSize); + if (!_buf) + return E_OUTOFMEMORY; + } + + TotalSize = 0; + + for (;;) + { + UInt32 size = kBufSize; + if (outSize) + { + const UInt64 rem = *outSize - TotalSize; + if (size > rem) + { + size = (UInt32)rem; + if (size == 0) + { + /* if we enable the following check, + we will make one call of Read(_buf, 0) for empty stream */ + // if (TotalSize != 0) + return S_OK; + } + } + } + + HRESULT readRes; + { + UInt32 pos = 0; + do + { + const UInt32 curSize = size - pos; + UInt32 processed = 0; + readRes = inStream->Read(_buf + pos, curSize, &processed); + if (processed > curSize) + return E_FAIL; // internal code failure + pos += processed; + if (readRes != S_OK || processed == 0) + break; + } + while (pos < kBufSize); + size = pos; + } + + if (size == 0) + return readRes; + + if (outStream) + { + UInt32 pos = 0; + do + { + const UInt32 curSize = size - pos; + UInt32 processed = 0; + const HRESULT res = outStream->Write(_buf + pos, curSize, &processed); + if (processed > curSize) + return E_FAIL; // internal code failure + pos += processed; + TotalSize += processed; + RINOK(res) + if (processed == 0) + return E_FAIL; + } + while (pos < size); + } + else + TotalSize += size; + + RINOK(readRes) + + if (size != kBufSize) + return S_OK; + + if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0) + { + RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)) + } + } +} + +Z7_COM7F_IMF(CCopyCoder::SetInStream(ISequentialInStream *inStream)) +{ + _inStream = inStream; + TotalSize = 0; + return S_OK; +} + +Z7_COM7F_IMF(CCopyCoder::ReleaseInStream()) +{ + _inStream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + UInt32 realProcessedSize = 0; + HRESULT res = _inStream->Read(data, size, &realProcessedSize); + TotalSize += realProcessedSize; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} + +Z7_COM7F_IMF(CCopyCoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = TotalSize; + return S_OK; +} + +HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + CMyComPtr copyCoder = new CCopyCoder; + return copyCoder->Code(inStream, outStream, NULL, NULL, progress); +} + +HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress) +{ + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; + CMyComPtr copyCoder = copyCoderSpec; + RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress)) + return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL; +} + +} diff --git a/CPP/7zip/Compress/CopyCoder.h b/CPP/7zip/Compress/CopyCoder.h index 8c49a876b..cb93e4eea 100644 --- a/CPP/7zip/Compress/CopyCoder.h +++ b/CPP/7zip/Compress/CopyCoder.h @@ -1,34 +1,34 @@ -// Compress/CopyCoder.h - -#ifndef ZIP7_INC_COMPRESS_COPY_CODER_H -#define ZIP7_INC_COMPRESS_COPY_CODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { - -Z7_CLASS_IMP_COM_5( - CCopyCoder - , ICompressCoder - , ICompressSetInStream - , ISequentialInStream - , ICompressSetFinishMode - , ICompressGetInStreamProcessedSize -) - Byte *_buf; - CMyComPtr _inStream; -public: - UInt64 TotalSize; - - CCopyCoder(): _buf(NULL), TotalSize(0) {} - ~CCopyCoder(); -}; - -HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); -HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress); - -} - -#endif +// Compress/CopyCoder.h + +#ifndef ZIP7_INC_COMPRESS_COPY_CODER_H +#define ZIP7_INC_COMPRESS_COPY_CODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { + +Z7_CLASS_IMP_COM_5( + CCopyCoder + , ICompressCoder + , ICompressSetInStream + , ISequentialInStream + , ICompressSetFinishMode + , ICompressGetInStreamProcessedSize +) + Byte *_buf; + CMyComPtr _inStream; +public: + UInt64 TotalSize; + + CCopyCoder(): _buf(NULL), TotalSize(0) {} + ~CCopyCoder(); +}; + +HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); +HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress); + +} + +#endif diff --git a/CPP/7zip/Compress/CopyRegister.cpp b/CPP/7zip/Compress/CopyRegister.cpp index 1c59fe0c0..7141ab580 100644 --- a/CPP/7zip/Compress/CopyRegister.cpp +++ b/CPP/7zip/Compress/CopyRegister.cpp @@ -1,15 +1,15 @@ -// CopyRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "CopyCoder.h" - -namespace NCompress { - -REGISTER_CODEC_CREATE(CreateCodec, CCopyCoder()) - -REGISTER_CODEC_2(Copy, CreateCodec, CreateCodec, 0, "Copy") - -} +// CopyRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "CopyCoder.h" + +namespace NCompress { + +REGISTER_CODEC_CREATE(CreateCodec, CCopyCoder()) + +REGISTER_CODEC_2(Copy, CreateCodec, CreateCodec, 0, "Copy") + +} diff --git a/CPP/7zip/Compress/Deflate64Register.cpp b/CPP/7zip/Compress/Deflate64Register.cpp index f531e10cc..7f6bae0e7 100644 --- a/CPP/7zip/Compress/Deflate64Register.cpp +++ b/CPP/7zip/Compress/Deflate64Register.cpp @@ -1,25 +1,25 @@ -// Deflate64Register.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "DeflateDecoder.h" -#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) -#include "DeflateEncoder.h" -#endif - -namespace NCompress { -namespace NDeflate { - -REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64()) - -#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) -REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder64()) -#else -#define CreateEnc NULL -#endif - -REGISTER_CODEC_2(Deflate64, CreateDec, CreateEnc, 0x40109, "Deflate64") - -}} +// Deflate64Register.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "DeflateDecoder.h" +#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) +#include "DeflateEncoder.h" +#endif + +namespace NCompress { +namespace NDeflate { + +REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64()) + +#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) +REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder64()) +#else +#define CreateEnc NULL +#endif + +REGISTER_CODEC_2(Deflate64, CreateDec, CreateEnc, 0x40109, "Deflate64") + +}} diff --git a/CPP/7zip/Compress/DeflateConst.h b/CPP/7zip/Compress/DeflateConst.h index 84b9c643e..a73d8ff0c 100644 --- a/CPP/7zip/Compress/DeflateConst.h +++ b/CPP/7zip/Compress/DeflateConst.h @@ -1,131 +1,131 @@ -// DeflateConst.h - -#ifndef ZIP7_INC_DEFLATE_CONST_H -#define ZIP7_INC_DEFLATE_CONST_H - -namespace NCompress { -namespace NDeflate { - -const unsigned kNumHuffmanBits = 15; - -const UInt32 kHistorySize32 = (1 << 15); -const UInt32 kHistorySize64 = (1 << 16); - -const unsigned kDistTableSize32 = 30; -const unsigned kDistTableSize64 = 32; - -const unsigned kNumLenSymbols32 = 256; -const unsigned kNumLenSymbols64 = 255; // don't change it. It must be <= 255. -const unsigned kNumLenSymbolsMax = kNumLenSymbols32; - -const unsigned kNumLenSlots = 29; - -const unsigned kFixedDistTableSize = 32; -const unsigned kFixedLenTableSize = 31; - -const unsigned kSymbolEndOfBlock = 0x100; -const unsigned kSymbolMatch = kSymbolEndOfBlock + 1; - -const unsigned kMainTableSize = kSymbolMatch + kNumLenSlots; -const unsigned kFixedMainTableSize = kSymbolMatch + kFixedLenTableSize; - -const unsigned kLevelTableSize = 19; - -const unsigned kTableDirectLevels = 16; -const unsigned kTableLevelRepNumber = kTableDirectLevels; -const unsigned kTableLevel0Number = kTableLevelRepNumber + 1; -const unsigned kTableLevel0Number2 = kTableLevel0Number + 1; - -const unsigned kLevelMask = 0xF; - -const Byte kLenStart32[kFixedLenTableSize] = - {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 255, 0, 0}; -const Byte kLenStart64[kFixedLenTableSize] = - {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 0, 0, 0}; - -const Byte kLenDirectBits32[kFixedLenTableSize] = - {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; -const Byte kLenDirectBits64[kFixedLenTableSize] = - {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, 0, 0}; - -const UInt32 kDistStart[kDistTableSize64] = - {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768, - 1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152}; -const Byte kDistDirectBits[kDistTableSize64] = - {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14}; - -const Byte kLevelDirectBits[3] = {2, 3, 7}; - -const Byte kCodeLengthAlphabetOrder[kLevelTableSize] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -const unsigned kMatchMinLen = 3; -const unsigned kMatchMaxLen32 = kNumLenSymbols32 + kMatchMinLen - 1; // 256 + 2 -const unsigned kMatchMaxLen64 = kNumLenSymbols64 + kMatchMinLen - 1; // 255 + 2 -const unsigned kMatchMaxLen = kMatchMaxLen32; - -const unsigned kFinalBlockFieldSize = 1; - -namespace NFinalBlockField -{ - enum - { - kNotFinalBlock = 0, - kFinalBlock = 1 - }; -} - -const unsigned kBlockTypeFieldSize = 2; - -namespace NBlockType -{ - enum - { - kStored = 0, - kFixedHuffman = 1, - kDynamicHuffman = 2 - }; -} - -const unsigned kNumLenCodesFieldSize = 5; -const unsigned kNumDistCodesFieldSize = 5; -const unsigned kNumLevelCodesFieldSize = 4; - -const unsigned kNumLitLenCodesMin = 257; -const unsigned kNumDistCodesMin = 1; -const unsigned kNumLevelCodesMin = 4; - -const unsigned kLevelFieldSize = 3; - -const unsigned kStoredBlockLengthFieldSize = 16; - -struct CLevels -{ - Byte litLenLevels[kFixedMainTableSize]; - Byte distLevels[kFixedDistTableSize]; - - void SubClear() - { - unsigned i; - for (i = kNumLitLenCodesMin; i < kFixedMainTableSize; i++) - litLenLevels[i] = 0; - for (i = 0; i < kFixedDistTableSize; i++) - distLevels[i] = 0; - } - - void SetFixedLevels() - { - unsigned i = 0; - - for (; i < 144; i++) litLenLevels[i] = 8; - for (; i < 256; i++) litLenLevels[i] = 9; - for (; i < 280; i++) litLenLevels[i] = 7; - for (; i < 288; i++) litLenLevels[i] = 8; - - for (i = 0; i < kFixedDistTableSize; i++) // test it: InfoZip only uses kDistTableSize - distLevels[i] = 5; - } -}; - -}} - -#endif +// DeflateConst.h + +#ifndef ZIP7_INC_DEFLATE_CONST_H +#define ZIP7_INC_DEFLATE_CONST_H + +namespace NCompress { +namespace NDeflate { + +const unsigned kNumHuffmanBits = 15; + +const UInt32 kHistorySize32 = (1 << 15); +const UInt32 kHistorySize64 = (1 << 16); + +const unsigned kDistTableSize32 = 30; +const unsigned kDistTableSize64 = 32; + +const unsigned kNumLenSymbols32 = 256; +const unsigned kNumLenSymbols64 = 255; // don't change it. It must be <= 255. +const unsigned kNumLenSymbolsMax = kNumLenSymbols32; + +const unsigned kNumLenSlots = 29; + +const unsigned kFixedDistTableSize = 32; +const unsigned kFixedLenTableSize = 31; + +const unsigned kSymbolEndOfBlock = 0x100; +const unsigned kSymbolMatch = kSymbolEndOfBlock + 1; + +const unsigned kMainTableSize = kSymbolMatch + kNumLenSlots; +const unsigned kFixedMainTableSize = kSymbolMatch + kFixedLenTableSize; + +const unsigned kLevelTableSize = 19; + +const unsigned kTableDirectLevels = 16; +const unsigned kTableLevelRepNumber = kTableDirectLevels; +const unsigned kTableLevel0Number = kTableLevelRepNumber + 1; +const unsigned kTableLevel0Number2 = kTableLevel0Number + 1; + +const unsigned kLevelMask = 0xF; + +const Byte kLenStart32[kFixedLenTableSize] = + {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 255, 0, 0}; +const Byte kLenStart64[kFixedLenTableSize] = + {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 0, 0, 0}; + +const Byte kLenDirectBits32[kFixedLenTableSize] = + {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; +const Byte kLenDirectBits64[kFixedLenTableSize] = + {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, 0, 0}; + +const UInt32 kDistStart[kDistTableSize64] = + {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768, + 1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152}; +const Byte kDistDirectBits[kDistTableSize64] = + {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14}; + +const Byte kLevelDirectBits[3] = {2, 3, 7}; + +const Byte kCodeLengthAlphabetOrder[kLevelTableSize] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +const unsigned kMatchMinLen = 3; +const unsigned kMatchMaxLen32 = kNumLenSymbols32 + kMatchMinLen - 1; // 256 + 2 +const unsigned kMatchMaxLen64 = kNumLenSymbols64 + kMatchMinLen - 1; // 255 + 2 +const unsigned kMatchMaxLen = kMatchMaxLen32; + +const unsigned kFinalBlockFieldSize = 1; + +namespace NFinalBlockField +{ + enum + { + kNotFinalBlock = 0, + kFinalBlock = 1 + }; +} + +const unsigned kBlockTypeFieldSize = 2; + +namespace NBlockType +{ + enum + { + kStored = 0, + kFixedHuffman = 1, + kDynamicHuffman = 2 + }; +} + +const unsigned kNumLenCodesFieldSize = 5; +const unsigned kNumDistCodesFieldSize = 5; +const unsigned kNumLevelCodesFieldSize = 4; + +const unsigned kNumLitLenCodesMin = 257; +const unsigned kNumDistCodesMin = 1; +const unsigned kNumLevelCodesMin = 4; + +const unsigned kLevelFieldSize = 3; + +const unsigned kStoredBlockLengthFieldSize = 16; + +struct CLevels +{ + Byte litLenLevels[kFixedMainTableSize]; + Byte distLevels[kFixedDistTableSize]; + + void SubClear() + { + unsigned i; + for (i = kNumLitLenCodesMin; i < kFixedMainTableSize; i++) + litLenLevels[i] = 0; + for (i = 0; i < kFixedDistTableSize; i++) + distLevels[i] = 0; + } + + void SetFixedLevels() + { + unsigned i = 0; + + for (; i < 144; i++) litLenLevels[i] = 8; + for (; i < 256; i++) litLenLevels[i] = 9; + for (; i < 280; i++) litLenLevels[i] = 7; + for (; i < 288; i++) litLenLevels[i] = 8; + + for (i = 0; i < kFixedDistTableSize; i++) // test it: InfoZip only uses kDistTableSize + distLevels[i] = 5; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp index 832676a85..73895fe8c 100644 --- a/CPP/7zip/Compress/DeflateDecoder.cpp +++ b/CPP/7zip/Compress/DeflateDecoder.cpp @@ -1,568 +1,568 @@ -// DeflateDecoder.cpp - -#include "StdAfx.h" - -#include "DeflateDecoder.h" - -namespace NCompress { -namespace NDeflate { -namespace NDecoder { - -CCoder::CCoder(bool deflate64Mode): - _deflateNSIS(false), - _deflate64Mode(deflate64Mode), - _keepHistory(false), - _needFinishInput(false), - _needInitInStream(true), - _outSizeDefined(false), - _outStartPos(0) - {} - -UInt32 CCoder::ReadBits(unsigned numBits) -{ - return m_InBitStream.ReadBits(numBits); -} - -Byte CCoder::ReadAlignedByte() -{ - return m_InBitStream.ReadAlignedByte(); -} - -bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols) -{ - unsigned i = 0; - - do - { - unsigned sym = m_LevelDecoder.Decode(&m_InBitStream); - if (sym < kTableDirectLevels) - levels[i++] = (Byte)sym; - else - { - if (sym >= kLevelTableSize) - return false; - - unsigned num; - unsigned numBits; - Byte symbol; - - if (sym == kTableLevelRepNumber) - { - if (i == 0) - return false; - numBits = 2; - num = 0; - symbol = levels[(size_t)i - 1]; - } - else - { - sym -= kTableLevel0Number; - sym <<= 2; - numBits = 3 + (unsigned)sym; - num = ((unsigned)sym << 1); - symbol = 0; - } - - num += i + 3 + ReadBits(numBits); - if (num > numSymbols) - return false; - do - levels[i++] = symbol; - while (i < num); - } - } - while (i < numSymbols); - - return true; -} - -#define RIF(x) { if (!(x)) return false; } - -bool CCoder::ReadTables(void) -{ - m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock); - if (m_InBitStream.ExtraBitsWereRead()) - return false; - const UInt32 blockType = ReadBits(kBlockTypeFieldSize); - if (blockType > NBlockType::kDynamicHuffman) - return false; - if (m_InBitStream.ExtraBitsWereRead()) - return false; - - if (blockType == NBlockType::kStored) - { - m_StoredMode = true; - m_InBitStream.AlignToByte(); - m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize) - if (_deflateNSIS) - return true; - return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16()); - } - - m_StoredMode = false; - - CLevels levels; - if (blockType == NBlockType::kFixedHuffman) - { - levels.SetFixedLevels(); - _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32; - } - else - { - const unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin; - _numDistLevels = (unsigned)ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin; - const unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin; - - if (!_deflate64Mode) - if (_numDistLevels > kDistTableSize32) - return false; - - Byte levelLevels[kLevelTableSize]; - for (unsigned i = 0; i < kLevelTableSize; i++) - { - const unsigned position = kCodeLengthAlphabetOrder[i]; - if (i < numLevelCodes) - levelLevels[position] = (Byte)ReadBits(kLevelFieldSize); - else - levelLevels[position] = 0; - } - - if (m_InBitStream.ExtraBitsWereRead()) - return false; - - RIF(m_LevelDecoder.Build(levelLevels, false)) // full - - Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize]; - if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels)) - return false; - - if (m_InBitStream.ExtraBitsWereRead()) - return false; - - levels.SubClear(); - memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels); - memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels); - } - RIF(m_MainDecoder.Build(levels.litLenLevels)) - return m_DistDecoder.Build(levels.distLevels); -} - - -HRESULT CCoder::InitInStream(bool needInit) -{ - if (needInit) - { - // for HDD-Windows: - // (1 << 15) - best for reading only prefetch - // (1 << 22) - best for real reading / writing - if (!m_InBitStream.Create(1 << 20)) - return E_OUTOFMEMORY; - m_InBitStream.Init(); - _needInitInStream = false; - } - return S_OK; -} - - -HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit) -{ - if (_remainLen == kLenIdFinished) - return S_OK; - - if (_remainLen == kLenIdNeedInit) - { - if (!_keepHistory) - if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32)) - return E_OUTOFMEMORY; - RINOK(InitInStream(_needInitInStream)) - m_OutWindowStream.Init(_keepHistory); - - m_FinalBlock = false; - _remainLen = 0; - _needReadTable = true; - } - - // _remainLen >= 0 - while (_remainLen && curSize) - { - _remainLen--; - const Byte b = m_OutWindowStream.GetByte(_rep0); - m_OutWindowStream.PutByte(b); - curSize--; - } - - UInt64 inputStart = 0; - if (inputProgressLimit != 0) - inputStart = m_InBitStream.GetProcessedSize(); - - while (curSize || finishInputStream) - { - if (m_InBitStream.ExtraBitsWereRead()) - return S_FALSE; - - if (_needReadTable) - { - if (m_FinalBlock) - { - _remainLen = kLenIdFinished; - break; - } - - if (inputProgressLimit != 0) - if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit) - return S_OK; - - if (!ReadTables()) - return S_FALSE; - if (m_InBitStream.ExtraBitsWereRead()) - return S_FALSE; - _needReadTable = false; - } - - if (m_StoredMode) - { - if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0) - return S_FALSE; - /* NSIS version contains some bits in bitl bits buffer. - So we must read some first bytes via ReadAlignedByte */ - UInt32 num = m_StoredBlockSize; - if (num > curSize) - num = curSize; - m_StoredBlockSize -= num; - curSize -= num; - for (; num && m_InBitStream.ThereAreDataInBitsBuffer(); num--) - m_OutWindowStream.PutByte(ReadAlignedByte()); - if (num) - { -#if 1 - // fast code - do - { - size_t a; - Byte *buf = m_OutWindowStream.GetOutBuffer(a); - // a != 0 - if (a > num) - a = num; - // a != 0 - a = m_InBitStream.ReadDirectBytesPart(buf, a); - if (a == 0) - return S_FALSE; - m_OutWindowStream.SkipWrittenBytes(a); - num -= (UInt32)a; - } - while (num); -#else - // slow code: - do - m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte()); - while (--num); -#endif - } - _needReadTable = (m_StoredBlockSize == 0); - continue; - } - - while (curSize) - { - if (m_InBitStream.ExtraBitsWereRead_Fast()) - return S_FALSE; - unsigned sym; -#if 0 - sym = m_MainDecoder.Decode(&m_InBitStream); -#else - Z7_HUFF_DECODE_CHECK(sym, &m_MainDecoder, kNumHuffmanBits, kNumTableBits_Main, &m_InBitStream, { return S_FALSE; }) -#endif - - if (sym < 0x100) - { - m_OutWindowStream.PutByte((Byte)sym); - curSize--; - continue; - } - if (sym == kSymbolEndOfBlock) - { - _needReadTable = true; - break; - } -#if 0 - if (sym >= kMainTableSize) - return S_FALSE; -#endif - { - sym -= kSymbolMatch; - UInt32 len; - { - unsigned numBits; - if (_deflate64Mode) - { - len = kLenStart64[sym]; - numBits = kLenDirectBits64[sym]; - } - else - { - len = kLenStart32[sym]; - numBits = kLenDirectBits32[sym]; - } - len += kMatchMinLen + m_InBitStream.ReadBits(numBits); - } - -#if 0 - sym = m_DistDecoder.Decode(&m_InBitStream); - if (sym >= _numDistLevels) - return S_FALSE; -#else - Z7_HUFF_DECODE_CHECK(sym, &m_DistDecoder, kNumHuffmanBits, kNumTableBits_Dist, &m_InBitStream, { return S_FALSE; }) -#endif - -#if 1 - sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); -#else - if (sym >= 4) - { - // sym &= 31; - const unsigned numDirectBits = (sym - 2) >> 1; - sym = (2u | (sym & 1)) << numDirectBits; - sym += m_InBitStream.ReadBits(numDirectBits); - } -#endif - UInt32 locLen = len; - if (locLen > curSize) - locLen = (UInt32)curSize; - if (!m_OutWindowStream.CopyBlock(sym, locLen)) - return S_FALSE; - curSize -= locLen; - len -= locLen; - if (len != 0) - { - _remainLen = (Int32)len; - _rep0 = sym; - break; - } - } - } - - if (finishInputStream && curSize == 0) - { - if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock) - return S_FALSE; - _needReadTable = true; - } - } - - if (m_InBitStream.ExtraBitsWereRead()) - return S_FALSE; - - return S_OK; -} - - -#ifdef Z7_NO_EXCEPTIONS - -#define DEFLATE_TRY_BEGIN -#define DEFLATE_TRY_END(res) - -#else - -#define DEFLATE_TRY_BEGIN try { -#define DEFLATE_TRY_END(res) } \ - catch(const CSystemException &e) { res = e.ErrorCode; } \ - catch(...) { res = S_FALSE; } - - // catch(const CInBufferException &e) { res = e.ErrorCode; } - // catch(const CLzOutWindowException &e) { res = e.ErrorCode; } - -#endif - - -HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - HRESULT res; - - DEFLATE_TRY_BEGIN - - m_OutWindowStream.SetStream(outStream); - CCoderReleaser flusher(this); - - const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize(); - - for (;;) - { - const UInt32 kInputProgressLimit = 1 << 21; - UInt32 curSize = 1 << 20; - bool finishInputStream = false; - if (_outSizeDefined) - { - const UInt64 rem = _outSize - GetOutProcessedCur(); - if (curSize >= rem) - { - curSize = (UInt32)rem; - if (_needFinishInput) - finishInputStream = true; - else if (curSize == 0) - break; - } - } - - RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0)) - - if (_remainLen == kLenIdFinished) - break; - - if (progress) - { - const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart; - const UInt64 nowPos64 = GetOutProcessedCur(); - RINOK(progress->SetRatioInfo(&inSize, &nowPos64)) - } - } - - flusher.NeedFlush = false; - res = Flush(); - if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError()) - return S_FALSE; - - DEFLATE_TRY_END(res) - - return res; -} - - -Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - SetInStream(inStream); - SetOutStreamSize(outSize); - const HRESULT res = CodeReal(outStream, progress); - ReleaseInStream(); - /* - if (res == S_OK) - if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize()) - res = S_FALSE; - */ - return res; -} - - -Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode)) -{ - Set_NeedFinishInput(finishMode != 0); - return S_OK; -} - - -Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = m_InBitStream.GetStreamSize(); - return S_OK; -} - - -Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) -{ - AlignToByte(); - UInt32 i = 0; - { - for (i = 0; i < size; i++) - { - if (!m_InBitStream.ReadAlignedByte_FromBuf(((Byte *)data)[i])) - break; - } - } - if (processedSize) - *processedSize = i; - return S_OK; -} - - -Z7_COM7F_IMF(CCoder::SetInStream(ISequentialInStream *inStream)) -{ - m_InStreamRef = inStream; - m_InBitStream.SetStream(inStream); - return S_OK; -} - - -Z7_COM7F_IMF(CCoder::ReleaseInStream()) -{ - m_InStreamRef.Release(); - m_InBitStream.ClearStreamPtr(); - return S_OK; -} - - -void CCoder::SetOutStreamSizeResume(const UInt64 *outSize) -{ - _outSizeDefined = (outSize != NULL); - _outSize = 0; - if (_outSizeDefined) - _outSize = *outSize; - m_OutWindowStream.Init(_keepHistory); - _outStartPos = m_OutWindowStream.GetProcessedSize(); - _remainLen = kLenIdNeedInit; -} - - -Z7_COM7F_IMF(CCoder::SetOutStreamSize(const UInt64 *outSize)) -{ - /* - 18.06: - We want to support GetInputProcessedSize() before CCoder::Read() - So we call m_InBitStream.Init() even before buffer allocations - m_InBitStream.Init() just sets variables to default values - But later we will call m_InBitStream.Init() again with real buffer pointers - */ - m_InBitStream.Init(); - _needInitInStream = true; - SetOutStreamSizeResume(outSize); - return S_OK; -} - - -#ifndef Z7_NO_READ_FROM_CODER - -Z7_COM7F_IMF(CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - const UInt64 outPos = GetOutProcessedCur(); - - bool finishInputStream = false; - if (_outSizeDefined) - { - const UInt64 rem = _outSize - outPos; - if (size >= rem) - { - size = (UInt32)rem; - if (_needFinishInput) - finishInputStream = true; - } - } - if (!finishInputStream && size == 0) - return S_OK; - - HRESULT res; - DEFLATE_TRY_BEGIN - m_OutWindowStream.SetMemStream((Byte *)data); - res = CodeSpec(size, finishInputStream); - DEFLATE_TRY_END(res) - { - const HRESULT res2 = Flush(); - if (res2 != S_OK) - res = res2; - } - if (processedSize) - *processedSize = (UInt32)(GetOutProcessedCur() - outPos); - m_OutWindowStream.SetMemStream(NULL); - return res; -} - -#endif - - -HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - SetOutStreamSizeResume(outSize); - return CodeReal(outStream, progress); -} - -}}} +// DeflateDecoder.cpp + +#include "StdAfx.h" + +#include "DeflateDecoder.h" + +namespace NCompress { +namespace NDeflate { +namespace NDecoder { + +CCoder::CCoder(bool deflate64Mode): + _deflateNSIS(false), + _deflate64Mode(deflate64Mode), + _keepHistory(false), + _needFinishInput(false), + _needInitInStream(true), + _outSizeDefined(false), + _outStartPos(0) + {} + +UInt32 CCoder::ReadBits(unsigned numBits) +{ + return m_InBitStream.ReadBits(numBits); +} + +Byte CCoder::ReadAlignedByte() +{ + return m_InBitStream.ReadAlignedByte(); +} + +bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols) +{ + unsigned i = 0; + + do + { + unsigned sym = m_LevelDecoder.Decode(&m_InBitStream); + if (sym < kTableDirectLevels) + levels[i++] = (Byte)sym; + else + { + if (sym >= kLevelTableSize) + return false; + + unsigned num; + unsigned numBits; + Byte symbol; + + if (sym == kTableLevelRepNumber) + { + if (i == 0) + return false; + numBits = 2; + num = 0; + symbol = levels[(size_t)i - 1]; + } + else + { + sym -= kTableLevel0Number; + sym <<= 2; + numBits = 3 + (unsigned)sym; + num = ((unsigned)sym << 1); + symbol = 0; + } + + num += i + 3 + ReadBits(numBits); + if (num > numSymbols) + return false; + do + levels[i++] = symbol; + while (i < num); + } + } + while (i < numSymbols); + + return true; +} + +#define RIF(x) { if (!(x)) return false; } + +bool CCoder::ReadTables(void) +{ + m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock); + if (m_InBitStream.ExtraBitsWereRead()) + return false; + const UInt32 blockType = ReadBits(kBlockTypeFieldSize); + if (blockType > NBlockType::kDynamicHuffman) + return false; + if (m_InBitStream.ExtraBitsWereRead()) + return false; + + if (blockType == NBlockType::kStored) + { + m_StoredMode = true; + m_InBitStream.AlignToByte(); + m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize) + if (_deflateNSIS) + return true; + return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16()); + } + + m_StoredMode = false; + + CLevels levels; + if (blockType == NBlockType::kFixedHuffman) + { + levels.SetFixedLevels(); + _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32; + } + else + { + const unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin; + _numDistLevels = (unsigned)ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin; + const unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin; + + if (!_deflate64Mode) + if (_numDistLevels > kDistTableSize32) + return false; + + Byte levelLevels[kLevelTableSize]; + for (unsigned i = 0; i < kLevelTableSize; i++) + { + const unsigned position = kCodeLengthAlphabetOrder[i]; + if (i < numLevelCodes) + levelLevels[position] = (Byte)ReadBits(kLevelFieldSize); + else + levelLevels[position] = 0; + } + + if (m_InBitStream.ExtraBitsWereRead()) + return false; + + RIF(m_LevelDecoder.Build(levelLevels, false)) // full + + Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize]; + if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels)) + return false; + + if (m_InBitStream.ExtraBitsWereRead()) + return false; + + levels.SubClear(); + memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels); + memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels); + } + RIF(m_MainDecoder.Build(levels.litLenLevels)) + return m_DistDecoder.Build(levels.distLevels); +} + + +HRESULT CCoder::InitInStream(bool needInit) +{ + if (needInit) + { + // for HDD-Windows: + // (1 << 15) - best for reading only prefetch + // (1 << 22) - best for real reading / writing + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + m_InBitStream.Init(); + _needInitInStream = false; + } + return S_OK; +} + + +HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit) +{ + if (_remainLen == kLenIdFinished) + return S_OK; + + if (_remainLen == kLenIdNeedInit) + { + if (!_keepHistory) + if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32)) + return E_OUTOFMEMORY; + RINOK(InitInStream(_needInitInStream)) + m_OutWindowStream.Init(_keepHistory); + + m_FinalBlock = false; + _remainLen = 0; + _needReadTable = true; + } + + // _remainLen >= 0 + while (_remainLen && curSize) + { + _remainLen--; + const Byte b = m_OutWindowStream.GetByte(_rep0); + m_OutWindowStream.PutByte(b); + curSize--; + } + + UInt64 inputStart = 0; + if (inputProgressLimit != 0) + inputStart = m_InBitStream.GetProcessedSize(); + + while (curSize || finishInputStream) + { + if (m_InBitStream.ExtraBitsWereRead()) + return S_FALSE; + + if (_needReadTable) + { + if (m_FinalBlock) + { + _remainLen = kLenIdFinished; + break; + } + + if (inputProgressLimit != 0) + if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit) + return S_OK; + + if (!ReadTables()) + return S_FALSE; + if (m_InBitStream.ExtraBitsWereRead()) + return S_FALSE; + _needReadTable = false; + } + + if (m_StoredMode) + { + if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0) + return S_FALSE; + /* NSIS version contains some bits in bitl bits buffer. + So we must read some first bytes via ReadAlignedByte */ + UInt32 num = m_StoredBlockSize; + if (num > curSize) + num = curSize; + m_StoredBlockSize -= num; + curSize -= num; + for (; num && m_InBitStream.ThereAreDataInBitsBuffer(); num--) + m_OutWindowStream.PutByte(ReadAlignedByte()); + if (num) + { +#if 1 + // fast code + do + { + size_t a; + Byte *buf = m_OutWindowStream.GetOutBuffer(a); + // a != 0 + if (a > num) + a = num; + // a != 0 + a = m_InBitStream.ReadDirectBytesPart(buf, a); + if (a == 0) + return S_FALSE; + m_OutWindowStream.SkipWrittenBytes(a); + num -= (UInt32)a; + } + while (num); +#else + // slow code: + do + m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte()); + while (--num); +#endif + } + _needReadTable = (m_StoredBlockSize == 0); + continue; + } + + while (curSize) + { + if (m_InBitStream.ExtraBitsWereRead_Fast()) + return S_FALSE; + unsigned sym; +#if 0 + sym = m_MainDecoder.Decode(&m_InBitStream); +#else + Z7_HUFF_DECODE_CHECK(sym, &m_MainDecoder, kNumHuffmanBits, kNumTableBits_Main, &m_InBitStream, { return S_FALSE; }) +#endif + + if (sym < 0x100) + { + m_OutWindowStream.PutByte((Byte)sym); + curSize--; + continue; + } + if (sym == kSymbolEndOfBlock) + { + _needReadTable = true; + break; + } +#if 0 + if (sym >= kMainTableSize) + return S_FALSE; +#endif + { + sym -= kSymbolMatch; + UInt32 len; + { + unsigned numBits; + if (_deflate64Mode) + { + len = kLenStart64[sym]; + numBits = kLenDirectBits64[sym]; + } + else + { + len = kLenStart32[sym]; + numBits = kLenDirectBits32[sym]; + } + len += kMatchMinLen + m_InBitStream.ReadBits(numBits); + } + +#if 0 + sym = m_DistDecoder.Decode(&m_InBitStream); + if (sym >= _numDistLevels) + return S_FALSE; +#else + Z7_HUFF_DECODE_CHECK(sym, &m_DistDecoder, kNumHuffmanBits, kNumTableBits_Dist, &m_InBitStream, { return S_FALSE; }) +#endif + +#if 1 + sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); +#else + if (sym >= 4) + { + // sym &= 31; + const unsigned numDirectBits = (sym - 2) >> 1; + sym = (2u | (sym & 1)) << numDirectBits; + sym += m_InBitStream.ReadBits(numDirectBits); + } +#endif + UInt32 locLen = len; + if (locLen > curSize) + locLen = (UInt32)curSize; + if (!m_OutWindowStream.CopyBlock(sym, locLen)) + return S_FALSE; + curSize -= locLen; + len -= locLen; + if (len != 0) + { + _remainLen = (Int32)len; + _rep0 = sym; + break; + } + } + } + + if (finishInputStream && curSize == 0) + { + if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock) + return S_FALSE; + _needReadTable = true; + } + } + + if (m_InBitStream.ExtraBitsWereRead()) + return S_FALSE; + + return S_OK; +} + + +#ifdef Z7_NO_EXCEPTIONS + +#define DEFLATE_TRY_BEGIN +#define DEFLATE_TRY_END(res) + +#else + +#define DEFLATE_TRY_BEGIN try { +#define DEFLATE_TRY_END(res) } \ + catch(const CSystemException &e) { res = e.ErrorCode; } \ + catch(...) { res = S_FALSE; } + + // catch(const CInBufferException &e) { res = e.ErrorCode; } + // catch(const CLzOutWindowException &e) { res = e.ErrorCode; } + +#endif + + +HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + HRESULT res; + + DEFLATE_TRY_BEGIN + + m_OutWindowStream.SetStream(outStream); + CCoderReleaser flusher(this); + + const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize(); + + for (;;) + { + const UInt32 kInputProgressLimit = 1 << 21; + UInt32 curSize = 1 << 20; + bool finishInputStream = false; + if (_outSizeDefined) + { + const UInt64 rem = _outSize - GetOutProcessedCur(); + if (curSize >= rem) + { + curSize = (UInt32)rem; + if (_needFinishInput) + finishInputStream = true; + else if (curSize == 0) + break; + } + } + + RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0)) + + if (_remainLen == kLenIdFinished) + break; + + if (progress) + { + const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart; + const UInt64 nowPos64 = GetOutProcessedCur(); + RINOK(progress->SetRatioInfo(&inSize, &nowPos64)) + } + } + + flusher.NeedFlush = false; + res = Flush(); + if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError()) + return S_FALSE; + + DEFLATE_TRY_END(res) + + return res; +} + + +Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + SetInStream(inStream); + SetOutStreamSize(outSize); + const HRESULT res = CodeReal(outStream, progress); + ReleaseInStream(); + /* + if (res == S_OK) + if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize()) + res = S_FALSE; + */ + return res; +} + + +Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode)) +{ + Set_NeedFinishInput(finishMode != 0); + return S_OK; +} + + +Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = m_InBitStream.GetStreamSize(); + return S_OK; +} + + +Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) +{ + AlignToByte(); + UInt32 i = 0; + { + for (i = 0; i < size; i++) + { + if (!m_InBitStream.ReadAlignedByte_FromBuf(((Byte *)data)[i])) + break; + } + } + if (processedSize) + *processedSize = i; + return S_OK; +} + + +Z7_COM7F_IMF(CCoder::SetInStream(ISequentialInStream *inStream)) +{ + m_InStreamRef = inStream; + m_InBitStream.SetStream(inStream); + return S_OK; +} + + +Z7_COM7F_IMF(CCoder::ReleaseInStream()) +{ + m_InStreamRef.Release(); + m_InBitStream.ClearStreamPtr(); + return S_OK; +} + + +void CCoder::SetOutStreamSizeResume(const UInt64 *outSize) +{ + _outSizeDefined = (outSize != NULL); + _outSize = 0; + if (_outSizeDefined) + _outSize = *outSize; + m_OutWindowStream.Init(_keepHistory); + _outStartPos = m_OutWindowStream.GetProcessedSize(); + _remainLen = kLenIdNeedInit; +} + + +Z7_COM7F_IMF(CCoder::SetOutStreamSize(const UInt64 *outSize)) +{ + /* + 18.06: + We want to support GetInputProcessedSize() before CCoder::Read() + So we call m_InBitStream.Init() even before buffer allocations + m_InBitStream.Init() just sets variables to default values + But later we will call m_InBitStream.Init() again with real buffer pointers + */ + m_InBitStream.Init(); + _needInitInStream = true; + SetOutStreamSizeResume(outSize); + return S_OK; +} + + +#ifndef Z7_NO_READ_FROM_CODER + +Z7_COM7F_IMF(CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + const UInt64 outPos = GetOutProcessedCur(); + + bool finishInputStream = false; + if (_outSizeDefined) + { + const UInt64 rem = _outSize - outPos; + if (size >= rem) + { + size = (UInt32)rem; + if (_needFinishInput) + finishInputStream = true; + } + } + if (!finishInputStream && size == 0) + return S_OK; + + HRESULT res; + DEFLATE_TRY_BEGIN + m_OutWindowStream.SetMemStream((Byte *)data); + res = CodeSpec(size, finishInputStream); + DEFLATE_TRY_END(res) + { + const HRESULT res2 = Flush(); + if (res2 != S_OK) + res = res2; + } + if (processedSize) + *processedSize = (UInt32)(GetOutProcessedCur() - outPos); + m_OutWindowStream.SetMemStream(NULL); + return res; +} + +#endif + + +HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + SetOutStreamSizeResume(outSize); + return CodeReal(outStream, progress); +} + +}}} diff --git a/CPP/7zip/Compress/DeflateDecoder.h b/CPP/7zip/Compress/DeflateDecoder.h index 864d00f05..4e0ae616d 100644 --- a/CPP/7zip/Compress/DeflateDecoder.h +++ b/CPP/7zip/Compress/DeflateDecoder.h @@ -1,154 +1,154 @@ -// DeflateDecoder.h - -#ifndef ZIP7_INC_DEFLATE_DECODER_H -#define ZIP7_INC_DEFLATE_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitlDecoder.h" -#include "DeflateConst.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NDeflate { -namespace NDecoder { - -const int kLenIdFinished = -1; -const int kLenIdNeedInit = -2; - -const unsigned kNumTableBits_Main = 10; -const unsigned kNumTableBits_Dist = 6; - -class CCoder: - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public ICompressReadUnusedFromInBuf, - public ICompressSetInStream, - public ICompressSetOutStreamSize, -#ifndef Z7_NO_READ_FROM_CODER - public ISequentialInStream, -#endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf) - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) -#ifndef Z7_NO_READ_FROM_CODER - Z7_COM_QI_ENTRY(ISequentialInStream) -#endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) -public: - Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf) - Z7_IFACE_COM7_IMP(ICompressSetInStream) -private: - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) -#ifndef Z7_NO_READ_FROM_CODER - Z7_IFACE_COM7_IMP(ISequentialInStream) -#endif - - CLzOutWindow m_OutWindowStream; - NBitl::CDecoder m_InBitStream; - NCompress::NHuffman::CDecoder m_MainDecoder; - NCompress::NHuffman::CDecoder256 m_DistDecoder; - NCompress::NHuffman::CDecoder7b m_LevelDecoder; - - UInt32 m_StoredBlockSize; - - unsigned _numDistLevels; - bool m_FinalBlock; - bool m_StoredMode; - - bool _deflateNSIS; - bool _deflate64Mode; - bool _keepHistory; - bool _needFinishInput; - - bool _needInitInStream; - bool _needReadTable; - Int32 _remainLen; - UInt32 _rep0; - - bool _outSizeDefined; - CMyComPtr m_InStreamRef; - UInt64 _outSize; - UInt64 _outStartPos; - - void SetOutStreamSizeResume(const UInt64 *outSize); - UInt64 GetOutProcessedCur() const { return m_OutWindowStream.GetProcessedSize() - _outStartPos; } - - UInt32 ReadBits(unsigned numBits); - - bool DecodeLevels(Byte *levels, unsigned numSymbols); - bool ReadTables(); - - HRESULT Flush() { return m_OutWindowStream.Flush(); } - class CCoderReleaser - { - CCoder *_coder; - public: - bool NeedFlush; - CCoderReleaser(CCoder *coder): _coder(coder), NeedFlush(true) {} - ~CCoderReleaser() - { - if (NeedFlush) - _coder->Flush(); - } - }; - friend class CCoderReleaser; - - HRESULT CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit = 0); -public: - - CCoder(bool deflate64Mode); - virtual ~CCoder() {} - - void SetNsisMode(bool nsisMode) { _deflateNSIS = nsisMode; } - - void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; } - void Set_NeedFinishInput(bool needFinishInput) { _needFinishInput = needFinishInput; } - - bool IsFinished() const { return _remainLen == kLenIdFinished; } - bool IsFinalBlock() const { return m_FinalBlock; } - - HRESULT CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress); - -public: - HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress); - HRESULT InitInStream(bool needInit); - - void AlignToByte() { m_InBitStream.AlignToByte(); } - Byte ReadAlignedByte(); - UInt32 ReadAligned_UInt16() // aligned for Byte range - { - const UInt32 v = m_InBitStream.ReadAlignedByte(); - return v | ((UInt32)m_InBitStream.ReadAlignedByte() << 8); - } - bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); } - - // size of used real data from input stream - UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); } - - // size of virtual input stream processed - UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); } -}; - -class CCOMCoder : public CCoder { public: CCOMCoder(): CCoder(false) {} }; -class CCOMCoder64 : public CCoder { public: CCOMCoder64(): CCoder(true) {} }; - -}}} - -#endif +// DeflateDecoder.h + +#ifndef ZIP7_INC_DEFLATE_DECODER_H +#define ZIP7_INC_DEFLATE_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitlDecoder.h" +#include "DeflateConst.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NDeflate { +namespace NDecoder { + +const int kLenIdFinished = -1; +const int kLenIdNeedInit = -2; + +const unsigned kNumTableBits_Main = 10; +const unsigned kNumTableBits_Dist = 6; + +class CCoder: + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public ICompressReadUnusedFromInBuf, + public ICompressSetInStream, + public ICompressSetOutStreamSize, +#ifndef Z7_NO_READ_FROM_CODER + public ISequentialInStream, +#endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf) + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) +#ifndef Z7_NO_READ_FROM_CODER + Z7_COM_QI_ENTRY(ISequentialInStream) +#endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) +public: + Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf) + Z7_IFACE_COM7_IMP(ICompressSetInStream) +private: + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) +#ifndef Z7_NO_READ_FROM_CODER + Z7_IFACE_COM7_IMP(ISequentialInStream) +#endif + + CLzOutWindow m_OutWindowStream; + NBitl::CDecoder m_InBitStream; + NCompress::NHuffman::CDecoder m_MainDecoder; + NCompress::NHuffman::CDecoder256 m_DistDecoder; + NCompress::NHuffman::CDecoder7b m_LevelDecoder; + + UInt32 m_StoredBlockSize; + + unsigned _numDistLevels; + bool m_FinalBlock; + bool m_StoredMode; + + bool _deflateNSIS; + bool _deflate64Mode; + bool _keepHistory; + bool _needFinishInput; + + bool _needInitInStream; + bool _needReadTable; + Int32 _remainLen; + UInt32 _rep0; + + bool _outSizeDefined; + CMyComPtr m_InStreamRef; + UInt64 _outSize; + UInt64 _outStartPos; + + void SetOutStreamSizeResume(const UInt64 *outSize); + UInt64 GetOutProcessedCur() const { return m_OutWindowStream.GetProcessedSize() - _outStartPos; } + + UInt32 ReadBits(unsigned numBits); + + bool DecodeLevels(Byte *levels, unsigned numSymbols); + bool ReadTables(); + + HRESULT Flush() { return m_OutWindowStream.Flush(); } + class CCoderReleaser + { + CCoder *_coder; + public: + bool NeedFlush; + CCoderReleaser(CCoder *coder): _coder(coder), NeedFlush(true) {} + ~CCoderReleaser() + { + if (NeedFlush) + _coder->Flush(); + } + }; + friend class CCoderReleaser; + + HRESULT CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit = 0); +public: + + CCoder(bool deflate64Mode); + virtual ~CCoder() {} + + void SetNsisMode(bool nsisMode) { _deflateNSIS = nsisMode; } + + void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; } + void Set_NeedFinishInput(bool needFinishInput) { _needFinishInput = needFinishInput; } + + bool IsFinished() const { return _remainLen == kLenIdFinished; } + bool IsFinalBlock() const { return m_FinalBlock; } + + HRESULT CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress); + +public: + HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress); + HRESULT InitInStream(bool needInit); + + void AlignToByte() { m_InBitStream.AlignToByte(); } + Byte ReadAlignedByte(); + UInt32 ReadAligned_UInt16() // aligned for Byte range + { + const UInt32 v = m_InBitStream.ReadAlignedByte(); + return v | ((UInt32)m_InBitStream.ReadAlignedByte() << 8); + } + bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); } + + // size of used real data from input stream + UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); } + + // size of virtual input stream processed + UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); } +}; + +class CCOMCoder : public CCoder { public: CCOMCoder(): CCoder(false) {} }; +class CCOMCoder64 : public CCoder { public: CCOMCoder64(): CCoder(true) {} }; + +}}} + +#endif diff --git a/CPP/7zip/Compress/DeflateEncoder.cpp b/CPP/7zip/Compress/DeflateEncoder.cpp index 03abc2718..87b4f8374 100644 --- a/CPP/7zip/Compress/DeflateEncoder.cpp +++ b/CPP/7zip/Compress/DeflateEncoder.cpp @@ -1,1021 +1,1021 @@ -// DeflateEncoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/HuffEnc.h" - -#include "../../Common/ComTry.h" - -#include "../Common/CWrappers.h" - -#include "DeflateEncoder.h" - -#undef NO_INLINE - -#ifdef _MSC_VER -#define NO_INLINE Z7_NO_INLINE -#else -#define NO_INLINE -#endif - -namespace NCompress { -namespace NDeflate { -namespace NEncoder { - -static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio. -static const UInt32 kNumTables = (1 << kNumDivPassesMax); - -static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio. -static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. -static const UInt32 kDivideBlockSizeMin = (1 << 6); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. - -static const UInt32 kMaxUncompressedBlockSize = ((1 << 16) - 1) * 1; // [1, (1 << 32)) -static const UInt32 kMatchArraySize = kMaxUncompressedBlockSize * 10; // [kMatchMaxLen * 2, (1 << 32)) -static const UInt32 kMatchArrayLimit = kMatchArraySize - kMatchMaxLen * 4 * sizeof(UInt16); -static const UInt32 kBlockUncompressedSizeThreshold = kMaxUncompressedBlockSize - - kMatchMaxLen - kNumOpts; - -// static const unsigned kMaxCodeBitLength = 11; -static const unsigned kMaxLevelBitLength = 7; - -static const Byte kNoLiteralStatPrice = 11; -static const Byte kNoLenStatPrice = 11; -static const Byte kNoPosStatPrice = 6; - -MY_ALIGN(64) -static Byte g_LenSlots[kNumLenSymbolsMax]; - -#define kNumLogBits 9 // do not change it -MY_ALIGN(64) -static Byte g_FastPos[1 << kNumLogBits]; - -class CFastPosInit -{ -public: - CFastPosInit() - { - unsigned i; - for (i = 0; i < kNumLenSlots; i++) - { - unsigned c = kLenStart32[i]; - const unsigned j = 1u << kLenDirectBits32[i]; - for (unsigned k = 0; k < j; k++, c++) - g_LenSlots[c] = (Byte)i; - } - - const unsigned kFastSlots = kNumLogBits * 2; - unsigned c = 0; - for (Byte slotFast = 0; slotFast < kFastSlots; slotFast++) - { - const unsigned k = 1u << kDistDirectBits[slotFast]; - for (unsigned j = 0; j < k; j++, c++) - g_FastPos[c] = slotFast; - } - } -}; - -static CFastPosInit g_FastPosInit; - -inline UInt32 GetPosSlot(UInt32 pos) -{ - /* - if (pos < 0x200) - return g_FastPos[pos]; - return g_FastPos[pos >> 8] + 16; - */ - // const unsigned zz = (pos < ((UInt32)1 << (kNumLogBits))) ? 0 : 8; - /* - const unsigned zz = (kNumLogBits - 1) & - ((UInt32)0 - (((((UInt32)1 << kNumLogBits) - 1) - pos) >> 31)); - */ - const unsigned zz = (kNumLogBits - 1) & - (((((UInt32)1 << kNumLogBits) - 1) - pos) >> (31 - 3)); - return g_FastPos[pos >> zz] + (zz * 2); -} - - -void CEncProps::Normalize() -{ - int level = Level; - if (level < 0) level = 5; - Level = level; - if (algo < 0) algo = (level < 5 ? 0 : 1); - if (fb < 0) fb = (level < 7 ? 32 : (level < 9 ? 64 : 128)); - if (btMode < 0) btMode = (algo == 0 ? 0 : 1); - if (mc == 0) mc = (16 + ((unsigned)fb >> 1)); - if (numPasses == (UInt32)(Int32)-1) numPasses = (level < 7 ? 1 : (level < 9 ? 3 : 10)); -} - -void CCoder::SetProps(const CEncProps *props2) -{ - CEncProps props = *props2; - props.Normalize(); - - m_MatchFinderCycles = props.mc; - { - unsigned fb = (unsigned)props.fb; - if (fb < kMatchMinLen) - fb = kMatchMinLen; - if (fb > m_MatchMaxLen) - fb = m_MatchMaxLen; - m_NumFastBytes = fb; - } - _fastMode = (props.algo == 0); - _btMode = (props.btMode != 0); - - m_NumDivPasses = props.numPasses; - if (m_NumDivPasses == 0) - m_NumDivPasses = 1; - if (m_NumDivPasses == 1) - m_NumPasses = 1; - else if (m_NumDivPasses <= kNumDivPassesMax) - m_NumPasses = 2; - else - { - m_NumPasses = 2 + (m_NumDivPasses - kNumDivPassesMax); - m_NumDivPasses = kNumDivPassesMax; - } -} - -CCoder::CCoder(bool deflate64Mode): - m_Values(NULL), - m_OnePosMatchesMemory(NULL), - m_DistanceMemory(NULL), - m_Created(false), - m_Deflate64Mode(deflate64Mode), - m_Tables(NULL) -{ - m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32; - m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32; - m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32; - m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32; - { - CEncProps props; - SetProps(&props); - } - MatchFinder_Construct(&_lzInWindow); -} - -HRESULT CCoder::Create() -{ - // COM_TRY_BEGIN - if (!m_Values) - { - m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue)); - if (!m_Values) - return E_OUTOFMEMORY; - } - if (!m_Tables) - { - m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables)); - if (!m_Tables) - return E_OUTOFMEMORY; - } - - if (m_IsMultiPass) - { - if (!m_OnePosMatchesMemory) - { - m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16)); - if (!m_OnePosMatchesMemory) - return E_OUTOFMEMORY; - } - } - else - { - if (!m_DistanceMemory) - { - m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16)); - if (!m_DistanceMemory) - return E_OUTOFMEMORY; - m_MatchDistances = m_DistanceMemory; - } - } - - if (!m_Created) - { - _lzInWindow.btMode = (Byte)(_btMode ? 1 : 0); - _lzInWindow.numHashBytes = 3; - _lzInWindow.numHashBytes_Min = 3; - if (!MatchFinder_Create(&_lzInWindow, - m_Deflate64Mode ? kHistorySize64 : kHistorySize32, - kNumOpts + kMaxUncompressedBlockSize, - m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_AlignedAlloc)) - return E_OUTOFMEMORY; - if (!m_OutStream.Create(1 << 20)) - return E_OUTOFMEMORY; - } - if (m_MatchFinderCycles != 0) - _lzInWindow.cutValue = m_MatchFinderCycles; - m_Created = true; - return S_OK; - // COM_TRY_END -} - -HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) -{ - CEncProps props; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - PROPID propID = propIDs[i]; - if (propID >= NCoderPropID::kReduceSize) - continue; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - UInt32 v = (UInt32)prop.ulVal; - switch (propID) - { - case NCoderPropID::kNumPasses: props.numPasses = v; break; - case NCoderPropID::kNumFastBytes: props.fb = (int)v; break; - case NCoderPropID::kMatchFinderCycles: props.mc = v; break; - case NCoderPropID::kAlgorithm: props.algo = (int)v; break; - case NCoderPropID::kLevel: props.Level = (int)v; break; - case NCoderPropID::kNumThreads: break; - default: return E_INVALIDARG; - } - } - SetProps(&props); - return S_OK; -} - -void CCoder::Free() -{ - ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = NULL; - ::MyFree(m_DistanceMemory); m_DistanceMemory = NULL; - ::MyFree(m_Values); m_Values = NULL; - ::MyFree(m_Tables); m_Tables = NULL; -} - -CCoder::~CCoder() -{ - Free(); - MatchFinder_Free(&_lzInWindow, &g_AlignedAlloc); -} - -NO_INLINE void CCoder::GetMatches() -{ - if (m_IsMultiPass) - { - m_MatchDistances = m_OnePosMatchesMemory + m_Pos; - if (m_SecondPass) - { - m_Pos += *m_MatchDistances + 1; - return; - } - } - - UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; - - const UInt32 numPairs = (UInt32)((_btMode ? - Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): - Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp); - - *m_MatchDistances = (UInt16)numPairs; - - if (numPairs != 0) - { - UInt32 i; - for (i = 0; i < numPairs; i += 2) - { - m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i]; - m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1]; - } - UInt32 len = distanceTmp[(size_t)numPairs - 2]; - if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen) - { - UInt32 numAvail = Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) + 1; - const Byte *pby = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - 1; - const Byte *pby2 = pby - (distanceTmp[(size_t)numPairs - 1] + 1); - if (numAvail > m_MatchMaxLen) - numAvail = m_MatchMaxLen; - for (; len < numAvail && pby[len] == pby2[len]; len++); - m_MatchDistances[(size_t)i - 1] = (UInt16)len; - } - } - if (m_IsMultiPass) - m_Pos += numPairs + 1; - if (!m_SecondPass) - m_AdditionalOffset++; -} - -void CCoder::MovePos(UInt32 num) -{ - if (!m_SecondPass && num > 0) - { - if (_btMode) - Bt3Zip_MatchFinder_Skip(&_lzInWindow, num); - else - Hc3Zip_MatchFinder_Skip(&_lzInWindow, num); - m_AdditionalOffset += num; - } -} - -static const UInt32 kIfinityPrice = 0xFFFFFFF; - -NO_INLINE UInt32 CCoder::Backward(UInt32 &backRes, UInt32 cur) -{ - m_OptimumEndIndex = cur; - UInt32 posMem = m_Optimum[cur].PosPrev; - UInt16 backMem = m_Optimum[cur].BackPrev; - do - { - UInt32 posPrev = posMem; - UInt16 backCur = backMem; - backMem = m_Optimum[posPrev].BackPrev; - posMem = m_Optimum[posPrev].PosPrev; - m_Optimum[posPrev].BackPrev = backCur; - m_Optimum[posPrev].PosPrev = (UInt16)cur; - cur = posPrev; - } - while (cur > 0); - backRes = m_Optimum[0].BackPrev; - m_OptimumCurrentIndex = m_Optimum[0].PosPrev; - return m_OptimumCurrentIndex; -} - -NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes) -{ - if (m_OptimumEndIndex != m_OptimumCurrentIndex) - { - UInt32 len = m_Optimum[m_OptimumCurrentIndex].PosPrev - m_OptimumCurrentIndex; - backRes = m_Optimum[m_OptimumCurrentIndex].BackPrev; - m_OptimumCurrentIndex = m_Optimum[m_OptimumCurrentIndex].PosPrev; - return len; - } - m_OptimumCurrentIndex = m_OptimumEndIndex = 0; - - GetMatches(); - - UInt32 lenEnd; - { - const UInt32 numDistancePairs = m_MatchDistances[0]; - if (numDistancePairs == 0) - return 1; - const UInt16 *matchDistances = m_MatchDistances + 1; - lenEnd = matchDistances[(size_t)numDistancePairs - 2]; - - if (lenEnd > m_NumFastBytes) - { - backRes = matchDistances[(size_t)numDistancePairs - 1]; - MovePos(lenEnd - 1); - return lenEnd; - } - - m_Optimum[1].Price = m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset)]; - m_Optimum[1].PosPrev = 0; - - m_Optimum[2].Price = kIfinityPrice; - m_Optimum[2].PosPrev = 1; - - UInt32 offs = 0; - - for (UInt32 i = kMatchMinLen; i <= lenEnd; i++) - { - UInt32 distance = matchDistances[(size_t)offs + 1]; - m_Optimum[i].PosPrev = 0; - m_Optimum[i].BackPrev = (UInt16)distance; - m_Optimum[i].Price = m_LenPrices[(size_t)i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)]; - if (i == matchDistances[offs]) - offs += 2; - } - } - - UInt32 cur = 0; - - for (;;) - { - ++cur; - if (cur == lenEnd || cur == kNumOptsBase || m_Pos >= kMatchArrayLimit) - return Backward(backRes, cur); - GetMatches(); - const UInt16 *matchDistances = m_MatchDistances + 1; - const UInt32 numDistancePairs = m_MatchDistances[0]; - UInt32 newLen = 0; - if (numDistancePairs != 0) - { - newLen = matchDistances[(size_t)numDistancePairs - 2]; - if (newLen > m_NumFastBytes) - { - UInt32 len = Backward(backRes, cur); - m_Optimum[cur].BackPrev = matchDistances[(size_t)numDistancePairs - 1]; - m_OptimumEndIndex = cur + newLen; - m_Optimum[cur].PosPrev = (UInt16)m_OptimumEndIndex; - MovePos(newLen - 1); - return len; - } - } - UInt32 curPrice = m_Optimum[cur].Price; - { - const UInt32 curAnd1Price = curPrice + m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) + cur - m_AdditionalOffset)]; - COptimal &optimum = m_Optimum[(size_t)cur + 1]; - if (curAnd1Price < optimum.Price) - { - optimum.Price = curAnd1Price; - optimum.PosPrev = (UInt16)cur; - } - } - if (numDistancePairs == 0) - continue; - while (lenEnd < cur + newLen) - m_Optimum[++lenEnd].Price = kIfinityPrice; - UInt32 offs = 0; - UInt32 distance = matchDistances[(size_t)offs + 1]; - curPrice += m_PosPrices[GetPosSlot(distance)]; - for (UInt32 lenTest = kMatchMinLen; ; lenTest++) - { - UInt32 curAndLenPrice = curPrice + m_LenPrices[(size_t)lenTest - kMatchMinLen]; - COptimal &optimum = m_Optimum[cur + lenTest]; - if (curAndLenPrice < optimum.Price) - { - optimum.Price = curAndLenPrice; - optimum.PosPrev = (UInt16)cur; - optimum.BackPrev = (UInt16)distance; - } - if (lenTest == matchDistances[offs]) - { - offs += 2; - if (offs == numDistancePairs) - break; - curPrice -= m_PosPrices[GetPosSlot(distance)]; - distance = matchDistances[(size_t)offs + 1]; - curPrice += m_PosPrices[GetPosSlot(distance)]; - } - } - } -} - -UInt32 CCoder::GetOptimalFast(UInt32 &backRes) -{ - GetMatches(); - UInt32 numDistancePairs = m_MatchDistances[0]; - if (numDistancePairs == 0) - return 1; - UInt32 lenMain = m_MatchDistances[(size_t)numDistancePairs - 1]; - backRes = m_MatchDistances[numDistancePairs]; - MovePos(lenMain - 1); - return lenMain; -} - -void CTables::InitStructures() -{ - UInt32 i; - for (i = 0; i < 256; i++) - litLenLevels[i] = 8; - litLenLevels[i++] = 13; - for (;i < kFixedMainTableSize; i++) - litLenLevels[i] = 5; - for (i = 0; i < kFixedDistTableSize; i++) - distLevels[i] = 5; -} - -NO_INLINE void CCoder::LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs) -{ - unsigned prevLen = 0xFF; - unsigned nextLen = levels[0]; - unsigned count = 0; - unsigned maxCount = 7; - unsigned minCount = 4; - - if (nextLen == 0) - { - maxCount = 138; - minCount = 3; - } - - for (unsigned n = 0; n < numLevels; n++) - { - unsigned curLen = nextLen; - nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF; - count++; - if (count < maxCount && curLen == nextLen) - continue; - - if (count < minCount) - freqs[curLen] += (UInt32)count; - else if (curLen != 0) - { - if (curLen != prevLen) - { - freqs[curLen]++; - count--; - } - freqs[kTableLevelRepNumber]++; - } - else if (count <= 10) - freqs[kTableLevel0Number]++; - else - freqs[kTableLevel0Number2]++; - - count = 0; - prevLen = curLen; - - if (nextLen == 0) - { - maxCount = 138; - minCount = 3; - } - else if (curLen == nextLen) - { - maxCount = 6; - minCount = 3; - } - else - { - maxCount = 7; - minCount = 4; - } - } -} - -NO_INLINE void CCoder::WriteBits(UInt32 value, unsigned numBits) -{ - m_OutStream.WriteBits(value, numBits); -} - -#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i]) -#define WRITE_HF(i) WriteBits(codes[i], lens[i]) - -NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes) -{ - unsigned prevLen = 0xFF; - unsigned nextLen = levels[0]; - unsigned count = 0; - unsigned maxCount = 7; - unsigned minCount = 4; - - if (nextLen == 0) - { - maxCount = 138; - minCount = 3; - } - - for (unsigned n = 0; n < numLevels; n++) - { - unsigned curLen = nextLen; - nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF; - count++; - if (count < maxCount && curLen == nextLen) - continue; - - if (count < minCount) - for (unsigned i = 0; i < count; i++) - WRITE_HF(curLen); - else if (curLen != 0) - { - if (curLen != prevLen) - { - WRITE_HF(curLen); - count--; - } - WRITE_HF(kTableLevelRepNumber); - WriteBits(count - 3, 2); - } - else if (count <= 10) - { - WRITE_HF(kTableLevel0Number); - WriteBits(count - 3, 3); - } - else - { - WRITE_HF(kTableLevel0Number2); - WriteBits(count - 11, 7); - } - - count = 0; - prevLen = curLen; - - if (nextLen == 0) - { - maxCount = 138; - minCount = 3; - } - else if (curLen == nextLen) - { - maxCount = 6; - minCount = 3; - } - else - { - maxCount = 7; - minCount = 4; - } - } -} - -NO_INLINE void CCoder::MakeTables(unsigned maxHuffLen) -{ - Huffman_Generate(mainFreqs, mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize, maxHuffLen); - Huffman_Generate(distFreqs, distCodes, m_NewLevels.distLevels, kDistTableSize64, maxHuffLen); -} - -static NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num) -{ - UInt32 price = 0; - UInt32 i; - for (i = 0; i < num; i++) - price += lens[i] * freqs[i]; - return price; -} - -static NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase) -{ - return Huffman_GetPrice(freqs, lens, num) + - Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); -} - -NO_INLINE UInt32 CCoder::GetLzBlockPrice() const -{ - return - Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + - Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0); -} - -NO_INLINE void CCoder::TryBlock() -{ - memset(mainFreqs, 0, sizeof(mainFreqs)); - memset(distFreqs, 0, sizeof(distFreqs)); - - m_ValueIndex = 0; - UInt32 blockSize = BlockSizeRes; - BlockSizeRes = 0; - for (;;) - { - if (m_OptimumCurrentIndex == m_OptimumEndIndex) - { - if (m_Pos >= kMatchArrayLimit - || BlockSizeRes >= blockSize - || (!m_SecondPass && ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize))) - break; - } - UInt32 pos; - UInt32 len; - if (_fastMode) - len = GetOptimalFast(pos); - else - len = GetOptimal(pos); - CCodeValue &codeValue = m_Values[m_ValueIndex++]; - if (len >= kMatchMinLen) - { - UInt32 newLen = len - kMatchMinLen; - codeValue.Len = (UInt16)newLen; - mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++; - codeValue.Pos = (UInt16)pos; - distFreqs[GetPosSlot(pos)]++; - } - else - { - Byte b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset); - mainFreqs[b]++; - codeValue.SetAsLiteral(); - codeValue.Pos = b; - } - m_AdditionalOffset -= len; - BlockSizeRes += len; - } - mainFreqs[kSymbolEndOfBlock]++; - m_AdditionalOffset += BlockSizeRes; - m_SecondPass = true; -} - -NO_INLINE void CCoder::SetPrices(const CLevels &levels) -{ - if (_fastMode) - return; - UInt32 i; - for (i = 0; i < 256; i++) - { - Byte price = levels.litLenLevels[i]; - m_LiteralPrices[i] = ((price != 0) ? price : kNoLiteralStatPrice); - } - - for (i = 0; i < m_NumLenCombinations; i++) - { - UInt32 slot = g_LenSlots[i]; - Byte price = levels.litLenLevels[kSymbolMatch + (size_t)slot]; - m_LenPrices[i] = (Byte)(((price != 0) ? price : kNoLenStatPrice) + m_LenDirectBits[slot]); - } - - for (i = 0; i < kDistTableSize64; i++) - { - Byte price = levels.distLevels[i]; - m_PosPrices[i] = (Byte)(((price != 0) ? price: kNoPosStatPrice) + kDistDirectBits[i]); - } -} - -static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num) -{ - for (UInt32 i = 0; i < num; i++) - { - UInt32 x = codes[i]; - x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1); - x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2); - x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4); - codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]); - } -} - -NO_INLINE void CCoder::WriteBlock() -{ - Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize); - Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64); - - for (UInt32 i = 0; i < m_ValueIndex; i++) - { - const CCodeValue &codeValue = m_Values[i]; - if (codeValue.IsLiteral()) - WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos); - else - { - UInt32 len = codeValue.Len; - UInt32 lenSlot = g_LenSlots[len]; - WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot); - m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]); - UInt32 dist = codeValue.Pos; - UInt32 posSlot = GetPosSlot(dist); - WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot); - m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]); - } - } - WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock); -} - -static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition) -{ - UInt32 price = 0; - do - { - UInt32 nextBitPosition = (bitPosition + kFinalBlockFieldSize + kBlockTypeFieldSize) & 7; - unsigned numBitsForAlign = nextBitPosition > 0 ? (8 - nextBitPosition): 0; - UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1; - price += kFinalBlockFieldSize + kBlockTypeFieldSize + numBitsForAlign + (2 + 2) * 8 + curBlockSize * 8; - bitPosition = 0; - blockSize -= curBlockSize; - } - while (blockSize != 0); - return price; -} - -void CCoder::WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock) -{ - do - { - UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1; - blockSize -= curBlockSize; - WriteBits((finalBlock && (blockSize == 0) ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize); - WriteBits(NBlockType::kStored, kBlockTypeFieldSize); - m_OutStream.FlushByte(); - WriteBits((UInt16)curBlockSize, kStoredBlockLengthFieldSize); - WriteBits((UInt16)~curBlockSize, kStoredBlockLengthFieldSize); - const Byte *data = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow)- additionalOffset; - for (UInt32 i = 0; i < curBlockSize; i++) - m_OutStream.WriteByte(data[i]); - additionalOffset -= curBlockSize; - } - while (blockSize != 0); -} - -NO_INLINE UInt32 CCoder::TryDynBlock(unsigned tableIndex, UInt32 numPasses) -{ - CTables &t = m_Tables[tableIndex]; - BlockSizeRes = t.BlockSizeRes; - UInt32 posTemp = t.m_Pos; - SetPrices(t); - - for (UInt32 p = 0; p < numPasses; p++) - { - m_Pos = posTemp; - TryBlock(); - unsigned numHuffBits = - (m_ValueIndex > 18000 ? 12 : - (m_ValueIndex > 7000 ? 11 : - (m_ValueIndex > 2000 ? 10 : 9))); - MakeTables(numHuffBits); - SetPrices(m_NewLevels); - } - - (CLevels &)t = m_NewLevels; - - m_NumLitLenLevels = kMainTableSize; - while (m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[(size_t)m_NumLitLenLevels - 1] == 0) - m_NumLitLenLevels--; - - m_NumDistLevels = kDistTableSize64; - while (m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[(size_t)m_NumDistLevels - 1] == 0) - m_NumDistLevels--; - - UInt32 levelFreqs[kLevelTableSize]; - memset(levelFreqs, 0, sizeof(levelFreqs)); - - LevelTableDummy(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelFreqs); - LevelTableDummy(m_NewLevels.distLevels, m_NumDistLevels, levelFreqs); - - Huffman_Generate(levelFreqs, levelCodes, levelLens, kLevelTableSize, kMaxLevelBitLength); - - m_NumLevelCodes = kNumLevelCodesMin; - for (UInt32 i = 0; i < kLevelTableSize; i++) - { - Byte level = levelLens[kCodeLengthAlphabetOrder[i]]; - if (level > 0 && i >= m_NumLevelCodes) - m_NumLevelCodes = i + 1; - m_LevelLevels[i] = level; - } - - return GetLzBlockPrice() + - Huffman_GetPrice_Spec(levelFreqs, levelLens, kLevelTableSize, kLevelDirectBits, kTableDirectLevels) + - kNumLenCodesFieldSize + kNumDistCodesFieldSize + kNumLevelCodesFieldSize + - m_NumLevelCodes * kLevelFieldSize + kFinalBlockFieldSize + kBlockTypeFieldSize; -} - -NO_INLINE UInt32 CCoder::TryFixedBlock(unsigned tableIndex) -{ - CTables &t = m_Tables[tableIndex]; - BlockSizeRes = t.BlockSizeRes; - m_Pos = t.m_Pos; - m_NewLevels.SetFixedLevels(); - SetPrices(m_NewLevels); - TryBlock(); - return kFinalBlockFieldSize + kBlockTypeFieldSize + GetLzBlockPrice(); -} - -NO_INLINE UInt32 CCoder::GetBlockPrice(unsigned tableIndex, unsigned numDivPasses) -{ - CTables &t = m_Tables[tableIndex]; - t.StaticMode = false; - UInt32 price = TryDynBlock(tableIndex, m_NumPasses); - t.BlockSizeRes = BlockSizeRes; - UInt32 numValues = m_ValueIndex; - UInt32 posTemp = m_Pos; - UInt32 additionalOffsetEnd = m_AdditionalOffset; - - if (m_CheckStatic && m_ValueIndex <= kFixedHuffmanCodeBlockSizeMax) - { - const UInt32 fixedPrice = TryFixedBlock(tableIndex); - t.StaticMode = (fixedPrice < price); - if (t.StaticMode) - price = fixedPrice; - } - - const UInt32 storePrice = GetStorePrice(BlockSizeRes, 0); // bitPosition - t.StoreMode = (storePrice <= price); - if (t.StoreMode) - price = storePrice; - - t.UseSubBlocks = false; - - if (numDivPasses > 1 && numValues >= kDivideCodeBlockSizeMin) - { - CTables &t0 = m_Tables[(tableIndex << 1)]; - (CLevels &)t0 = t; - t0.BlockSizeRes = t.BlockSizeRes >> 1; - t0.m_Pos = t.m_Pos; - UInt32 subPrice = GetBlockPrice((tableIndex << 1), numDivPasses - 1); - - UInt32 blockSize2 = t.BlockSizeRes - t0.BlockSizeRes; - if (t0.BlockSizeRes >= kDivideBlockSizeMin && blockSize2 >= kDivideBlockSizeMin) - { - CTables &t1 = m_Tables[(tableIndex << 1) + 1]; - (CLevels &)t1 = t; - t1.BlockSizeRes = blockSize2; - t1.m_Pos = m_Pos; - m_AdditionalOffset -= t0.BlockSizeRes; - subPrice += GetBlockPrice((tableIndex << 1) + 1, numDivPasses - 1); - t.UseSubBlocks = (subPrice < price); - if (t.UseSubBlocks) - price = subPrice; - } - } - - m_AdditionalOffset = additionalOffsetEnd; - m_Pos = posTemp; - return price; -} - -void CCoder::CodeBlock(unsigned tableIndex, bool finalBlock) -{ - CTables &t = m_Tables[tableIndex]; - if (t.UseSubBlocks) - { - CodeBlock((tableIndex << 1), false); - CodeBlock((tableIndex << 1) + 1, finalBlock); - } - else - { - if (t.StoreMode) - WriteStoreBlock(t.BlockSizeRes, m_AdditionalOffset, finalBlock); - else - { - WriteBits((finalBlock ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize); - if (t.StaticMode) - { - WriteBits(NBlockType::kFixedHuffman, kBlockTypeFieldSize); - TryFixedBlock(tableIndex); - unsigned i; - const unsigned kMaxStaticHuffLen = 9; - for (i = 0; i < kFixedMainTableSize; i++) - mainFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.litLenLevels[i]); - for (i = 0; i < kFixedDistTableSize; i++) - distFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.distLevels[i]); - MakeTables(kMaxStaticHuffLen); - } - else - { - if (m_NumDivPasses > 1 || m_CheckStatic) - TryDynBlock(tableIndex, 1); - WriteBits(NBlockType::kDynamicHuffman, kBlockTypeFieldSize); - WriteBits(m_NumLitLenLevels - kNumLitLenCodesMin, kNumLenCodesFieldSize); - WriteBits(m_NumDistLevels - kNumDistCodesMin, kNumDistCodesFieldSize); - WriteBits(m_NumLevelCodes - kNumLevelCodesMin, kNumLevelCodesFieldSize); - - for (UInt32 i = 0; i < m_NumLevelCodes; i++) - WriteBits(m_LevelLevels[i], kLevelFieldSize); - - Huffman_ReverseBits(levelCodes, levelLens, kLevelTableSize); - LevelTableCode(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelLens, levelCodes); - LevelTableCode(m_NewLevels.distLevels, m_NumDistLevels, levelLens, levelCodes); - } - WriteBlock(); - } - m_AdditionalOffset -= t.BlockSizeRes; - } -} - - -HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */ , const UInt64 * /* outSize */ , ICompressProgressInfo *progress) -{ - m_CheckStatic = (m_NumPasses != 1 || m_NumDivPasses != 1); - m_IsMultiPass = (m_CheckStatic || (m_NumPasses != 1 || m_NumDivPasses != 1)); - - /* we can set stream mode before MatchFinder_Create - if default MatchFinder mode was not STREAM_MODE) */ - // MatchFinder_SET_STREAM_MODE(&_lzInWindow); - - CSeqInStreamWrap _seqInStream; - _seqInStream.Init(inStream); - MatchFinder_SET_STREAM(&_lzInWindow, &_seqInStream.vt) - - RINOK(Create()) - - m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses; - - UInt64 nowPos = 0; - - MatchFinder_Init(&_lzInWindow); - m_OutStream.SetStream(outStream); - m_OutStream.Init(); - - m_OptimumEndIndex = m_OptimumCurrentIndex = 0; - - CTables &t = m_Tables[1]; - t.m_Pos = 0; - t.InitStructures(); - - m_AdditionalOffset = 0; - do - { - t.BlockSizeRes = kBlockUncompressedSizeThreshold; - m_SecondPass = false; - GetBlockPrice(1, m_NumDivPasses); - CodeBlock(1, Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0); - nowPos += m_Tables[1].BlockSizeRes; - if (progress != NULL) - { - UInt64 packSize = m_OutStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&nowPos, &packSize)) - } - } - while (Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) != 0); - - if (_seqInStream.Res != S_OK) - return _seqInStream.Res; - - if (_lzInWindow.result != SZ_OK) - return SResToHRESULT(_lzInWindow.result); - return m_OutStream.Flush(); -} - -HRESULT CCoder::BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const COutBufferException &e) { return e.ErrorCode; } - catch(...) { return E_FAIL; } -} - -Z7_COM7F_IMF(CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) - { return BaseCode(inStream, outStream, inSize, outSize, progress); } - -Z7_COM7F_IMF(CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) - { return BaseSetEncoderProperties2(propIDs, props, numProps); } - -Z7_COM7F_IMF(CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) - { return BaseCode(inStream, outStream, inSize, outSize, progress); } - -Z7_COM7F_IMF(CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) - { return BaseSetEncoderProperties2(propIDs, props, numProps); } - -}}} +// DeflateEncoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/HuffEnc.h" + +#include "../../Common/ComTry.h" + +#include "../Common/CWrappers.h" + +#include "DeflateEncoder.h" + +#undef NO_INLINE + +#ifdef _MSC_VER +#define NO_INLINE Z7_NO_INLINE +#else +#define NO_INLINE +#endif + +namespace NCompress { +namespace NDeflate { +namespace NEncoder { + +static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio. +static const UInt32 kNumTables = (1 << kNumDivPassesMax); + +static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio. +static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. +static const UInt32 kDivideBlockSizeMin = (1 << 6); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio. + +static const UInt32 kMaxUncompressedBlockSize = ((1 << 16) - 1) * 1; // [1, (1 << 32)) +static const UInt32 kMatchArraySize = kMaxUncompressedBlockSize * 10; // [kMatchMaxLen * 2, (1 << 32)) +static const UInt32 kMatchArrayLimit = kMatchArraySize - kMatchMaxLen * 4 * sizeof(UInt16); +static const UInt32 kBlockUncompressedSizeThreshold = kMaxUncompressedBlockSize - + kMatchMaxLen - kNumOpts; + +// static const unsigned kMaxCodeBitLength = 11; +static const unsigned kMaxLevelBitLength = 7; + +static const Byte kNoLiteralStatPrice = 11; +static const Byte kNoLenStatPrice = 11; +static const Byte kNoPosStatPrice = 6; + +MY_ALIGN(64) +static Byte g_LenSlots[kNumLenSymbolsMax]; + +#define kNumLogBits 9 // do not change it +MY_ALIGN(64) +static Byte g_FastPos[1 << kNumLogBits]; + +class CFastPosInit +{ +public: + CFastPosInit() + { + unsigned i; + for (i = 0; i < kNumLenSlots; i++) + { + unsigned c = kLenStart32[i]; + const unsigned j = 1u << kLenDirectBits32[i]; + for (unsigned k = 0; k < j; k++, c++) + g_LenSlots[c] = (Byte)i; + } + + const unsigned kFastSlots = kNumLogBits * 2; + unsigned c = 0; + for (Byte slotFast = 0; slotFast < kFastSlots; slotFast++) + { + const unsigned k = 1u << kDistDirectBits[slotFast]; + for (unsigned j = 0; j < k; j++, c++) + g_FastPos[c] = slotFast; + } + } +}; + +static CFastPosInit g_FastPosInit; + +inline UInt32 GetPosSlot(UInt32 pos) +{ + /* + if (pos < 0x200) + return g_FastPos[pos]; + return g_FastPos[pos >> 8] + 16; + */ + // const unsigned zz = (pos < ((UInt32)1 << (kNumLogBits))) ? 0 : 8; + /* + const unsigned zz = (kNumLogBits - 1) & + ((UInt32)0 - (((((UInt32)1 << kNumLogBits) - 1) - pos) >> 31)); + */ + const unsigned zz = (kNumLogBits - 1) & + (((((UInt32)1 << kNumLogBits) - 1) - pos) >> (31 - 3)); + return g_FastPos[pos >> zz] + (zz * 2); +} + + +void CEncProps::Normalize() +{ + int level = Level; + if (level < 0) level = 5; + Level = level; + if (algo < 0) algo = (level < 5 ? 0 : 1); + if (fb < 0) fb = (level < 7 ? 32 : (level < 9 ? 64 : 128)); + if (btMode < 0) btMode = (algo == 0 ? 0 : 1); + if (mc == 0) mc = (16 + ((unsigned)fb >> 1)); + if (numPasses == (UInt32)(Int32)-1) numPasses = (level < 7 ? 1 : (level < 9 ? 3 : 10)); +} + +void CCoder::SetProps(const CEncProps *props2) +{ + CEncProps props = *props2; + props.Normalize(); + + m_MatchFinderCycles = props.mc; + { + unsigned fb = (unsigned)props.fb; + if (fb < kMatchMinLen) + fb = kMatchMinLen; + if (fb > m_MatchMaxLen) + fb = m_MatchMaxLen; + m_NumFastBytes = fb; + } + _fastMode = (props.algo == 0); + _btMode = (props.btMode != 0); + + m_NumDivPasses = props.numPasses; + if (m_NumDivPasses == 0) + m_NumDivPasses = 1; + if (m_NumDivPasses == 1) + m_NumPasses = 1; + else if (m_NumDivPasses <= kNumDivPassesMax) + m_NumPasses = 2; + else + { + m_NumPasses = 2 + (m_NumDivPasses - kNumDivPassesMax); + m_NumDivPasses = kNumDivPassesMax; + } +} + +CCoder::CCoder(bool deflate64Mode): + m_Values(NULL), + m_OnePosMatchesMemory(NULL), + m_DistanceMemory(NULL), + m_Created(false), + m_Deflate64Mode(deflate64Mode), + m_Tables(NULL) +{ + m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32; + m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32; + m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32; + m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32; + { + CEncProps props; + SetProps(&props); + } + MatchFinder_Construct(&_lzInWindow); +} + +HRESULT CCoder::Create() +{ + // COM_TRY_BEGIN + if (!m_Values) + { + m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue)); + if (!m_Values) + return E_OUTOFMEMORY; + } + if (!m_Tables) + { + m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables)); + if (!m_Tables) + return E_OUTOFMEMORY; + } + + if (m_IsMultiPass) + { + if (!m_OnePosMatchesMemory) + { + m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16)); + if (!m_OnePosMatchesMemory) + return E_OUTOFMEMORY; + } + } + else + { + if (!m_DistanceMemory) + { + m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16)); + if (!m_DistanceMemory) + return E_OUTOFMEMORY; + m_MatchDistances = m_DistanceMemory; + } + } + + if (!m_Created) + { + _lzInWindow.btMode = (Byte)(_btMode ? 1 : 0); + _lzInWindow.numHashBytes = 3; + _lzInWindow.numHashBytes_Min = 3; + if (!MatchFinder_Create(&_lzInWindow, + m_Deflate64Mode ? kHistorySize64 : kHistorySize32, + kNumOpts + kMaxUncompressedBlockSize, + m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_AlignedAlloc)) + return E_OUTOFMEMORY; + if (!m_OutStream.Create(1 << 20)) + return E_OUTOFMEMORY; + } + if (m_MatchFinderCycles != 0) + _lzInWindow.cutValue = m_MatchFinderCycles; + m_Created = true; + return S_OK; + // COM_TRY_END +} + +HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) +{ + CEncProps props; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + PROPID propID = propIDs[i]; + if (propID >= NCoderPropID::kReduceSize) + continue; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + UInt32 v = (UInt32)prop.ulVal; + switch (propID) + { + case NCoderPropID::kNumPasses: props.numPasses = v; break; + case NCoderPropID::kNumFastBytes: props.fb = (int)v; break; + case NCoderPropID::kMatchFinderCycles: props.mc = v; break; + case NCoderPropID::kAlgorithm: props.algo = (int)v; break; + case NCoderPropID::kLevel: props.Level = (int)v; break; + case NCoderPropID::kNumThreads: break; + default: return E_INVALIDARG; + } + } + SetProps(&props); + return S_OK; +} + +void CCoder::Free() +{ + ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = NULL; + ::MyFree(m_DistanceMemory); m_DistanceMemory = NULL; + ::MyFree(m_Values); m_Values = NULL; + ::MyFree(m_Tables); m_Tables = NULL; +} + +CCoder::~CCoder() +{ + Free(); + MatchFinder_Free(&_lzInWindow, &g_AlignedAlloc); +} + +NO_INLINE void CCoder::GetMatches() +{ + if (m_IsMultiPass) + { + m_MatchDistances = m_OnePosMatchesMemory + m_Pos; + if (m_SecondPass) + { + m_Pos += *m_MatchDistances + 1; + return; + } + } + + UInt32 distanceTmp[kMatchMaxLen * 2 + 3]; + + const UInt32 numPairs = (UInt32)((_btMode ? + Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp): + Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp); + + *m_MatchDistances = (UInt16)numPairs; + + if (numPairs != 0) + { + UInt32 i; + for (i = 0; i < numPairs; i += 2) + { + m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i]; + m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1]; + } + UInt32 len = distanceTmp[(size_t)numPairs - 2]; + if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen) + { + UInt32 numAvail = Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) + 1; + const Byte *pby = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - 1; + const Byte *pby2 = pby - (distanceTmp[(size_t)numPairs - 1] + 1); + if (numAvail > m_MatchMaxLen) + numAvail = m_MatchMaxLen; + for (; len < numAvail && pby[len] == pby2[len]; len++); + m_MatchDistances[(size_t)i - 1] = (UInt16)len; + } + } + if (m_IsMultiPass) + m_Pos += numPairs + 1; + if (!m_SecondPass) + m_AdditionalOffset++; +} + +void CCoder::MovePos(UInt32 num) +{ + if (!m_SecondPass && num > 0) + { + if (_btMode) + Bt3Zip_MatchFinder_Skip(&_lzInWindow, num); + else + Hc3Zip_MatchFinder_Skip(&_lzInWindow, num); + m_AdditionalOffset += num; + } +} + +static const UInt32 kIfinityPrice = 0xFFFFFFF; + +NO_INLINE UInt32 CCoder::Backward(UInt32 &backRes, UInt32 cur) +{ + m_OptimumEndIndex = cur; + UInt32 posMem = m_Optimum[cur].PosPrev; + UInt16 backMem = m_Optimum[cur].BackPrev; + do + { + UInt32 posPrev = posMem; + UInt16 backCur = backMem; + backMem = m_Optimum[posPrev].BackPrev; + posMem = m_Optimum[posPrev].PosPrev; + m_Optimum[posPrev].BackPrev = backCur; + m_Optimum[posPrev].PosPrev = (UInt16)cur; + cur = posPrev; + } + while (cur > 0); + backRes = m_Optimum[0].BackPrev; + m_OptimumCurrentIndex = m_Optimum[0].PosPrev; + return m_OptimumCurrentIndex; +} + +NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes) +{ + if (m_OptimumEndIndex != m_OptimumCurrentIndex) + { + UInt32 len = m_Optimum[m_OptimumCurrentIndex].PosPrev - m_OptimumCurrentIndex; + backRes = m_Optimum[m_OptimumCurrentIndex].BackPrev; + m_OptimumCurrentIndex = m_Optimum[m_OptimumCurrentIndex].PosPrev; + return len; + } + m_OptimumCurrentIndex = m_OptimumEndIndex = 0; + + GetMatches(); + + UInt32 lenEnd; + { + const UInt32 numDistancePairs = m_MatchDistances[0]; + if (numDistancePairs == 0) + return 1; + const UInt16 *matchDistances = m_MatchDistances + 1; + lenEnd = matchDistances[(size_t)numDistancePairs - 2]; + + if (lenEnd > m_NumFastBytes) + { + backRes = matchDistances[(size_t)numDistancePairs - 1]; + MovePos(lenEnd - 1); + return lenEnd; + } + + m_Optimum[1].Price = m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset)]; + m_Optimum[1].PosPrev = 0; + + m_Optimum[2].Price = kIfinityPrice; + m_Optimum[2].PosPrev = 1; + + UInt32 offs = 0; + + for (UInt32 i = kMatchMinLen; i <= lenEnd; i++) + { + UInt32 distance = matchDistances[(size_t)offs + 1]; + m_Optimum[i].PosPrev = 0; + m_Optimum[i].BackPrev = (UInt16)distance; + m_Optimum[i].Price = m_LenPrices[(size_t)i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)]; + if (i == matchDistances[offs]) + offs += 2; + } + } + + UInt32 cur = 0; + + for (;;) + { + ++cur; + if (cur == lenEnd || cur == kNumOptsBase || m_Pos >= kMatchArrayLimit) + return Backward(backRes, cur); + GetMatches(); + const UInt16 *matchDistances = m_MatchDistances + 1; + const UInt32 numDistancePairs = m_MatchDistances[0]; + UInt32 newLen = 0; + if (numDistancePairs != 0) + { + newLen = matchDistances[(size_t)numDistancePairs - 2]; + if (newLen > m_NumFastBytes) + { + UInt32 len = Backward(backRes, cur); + m_Optimum[cur].BackPrev = matchDistances[(size_t)numDistancePairs - 1]; + m_OptimumEndIndex = cur + newLen; + m_Optimum[cur].PosPrev = (UInt16)m_OptimumEndIndex; + MovePos(newLen - 1); + return len; + } + } + UInt32 curPrice = m_Optimum[cur].Price; + { + const UInt32 curAnd1Price = curPrice + m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) + cur - m_AdditionalOffset)]; + COptimal &optimum = m_Optimum[(size_t)cur + 1]; + if (curAnd1Price < optimum.Price) + { + optimum.Price = curAnd1Price; + optimum.PosPrev = (UInt16)cur; + } + } + if (numDistancePairs == 0) + continue; + while (lenEnd < cur + newLen) + m_Optimum[++lenEnd].Price = kIfinityPrice; + UInt32 offs = 0; + UInt32 distance = matchDistances[(size_t)offs + 1]; + curPrice += m_PosPrices[GetPosSlot(distance)]; + for (UInt32 lenTest = kMatchMinLen; ; lenTest++) + { + UInt32 curAndLenPrice = curPrice + m_LenPrices[(size_t)lenTest - kMatchMinLen]; + COptimal &optimum = m_Optimum[cur + lenTest]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = (UInt16)cur; + optimum.BackPrev = (UInt16)distance; + } + if (lenTest == matchDistances[offs]) + { + offs += 2; + if (offs == numDistancePairs) + break; + curPrice -= m_PosPrices[GetPosSlot(distance)]; + distance = matchDistances[(size_t)offs + 1]; + curPrice += m_PosPrices[GetPosSlot(distance)]; + } + } + } +} + +UInt32 CCoder::GetOptimalFast(UInt32 &backRes) +{ + GetMatches(); + UInt32 numDistancePairs = m_MatchDistances[0]; + if (numDistancePairs == 0) + return 1; + UInt32 lenMain = m_MatchDistances[(size_t)numDistancePairs - 1]; + backRes = m_MatchDistances[numDistancePairs]; + MovePos(lenMain - 1); + return lenMain; +} + +void CTables::InitStructures() +{ + UInt32 i; + for (i = 0; i < 256; i++) + litLenLevels[i] = 8; + litLenLevels[i++] = 13; + for (;i < kFixedMainTableSize; i++) + litLenLevels[i] = 5; + for (i = 0; i < kFixedDistTableSize; i++) + distLevels[i] = 5; +} + +NO_INLINE void CCoder::LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs) +{ + unsigned prevLen = 0xFF; + unsigned nextLen = levels[0]; + unsigned count = 0; + unsigned maxCount = 7; + unsigned minCount = 4; + + if (nextLen == 0) + { + maxCount = 138; + minCount = 3; + } + + for (unsigned n = 0; n < numLevels; n++) + { + unsigned curLen = nextLen; + nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF; + count++; + if (count < maxCount && curLen == nextLen) + continue; + + if (count < minCount) + freqs[curLen] += (UInt32)count; + else if (curLen != 0) + { + if (curLen != prevLen) + { + freqs[curLen]++; + count--; + } + freqs[kTableLevelRepNumber]++; + } + else if (count <= 10) + freqs[kTableLevel0Number]++; + else + freqs[kTableLevel0Number2]++; + + count = 0; + prevLen = curLen; + + if (nextLen == 0) + { + maxCount = 138; + minCount = 3; + } + else if (curLen == nextLen) + { + maxCount = 6; + minCount = 3; + } + else + { + maxCount = 7; + minCount = 4; + } + } +} + +NO_INLINE void CCoder::WriteBits(UInt32 value, unsigned numBits) +{ + m_OutStream.WriteBits(value, numBits); +} + +#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i]) +#define WRITE_HF(i) WriteBits(codes[i], lens[i]) + +NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes) +{ + unsigned prevLen = 0xFF; + unsigned nextLen = levels[0]; + unsigned count = 0; + unsigned maxCount = 7; + unsigned minCount = 4; + + if (nextLen == 0) + { + maxCount = 138; + minCount = 3; + } + + for (unsigned n = 0; n < numLevels; n++) + { + unsigned curLen = nextLen; + nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF; + count++; + if (count < maxCount && curLen == nextLen) + continue; + + if (count < minCount) + for (unsigned i = 0; i < count; i++) + WRITE_HF(curLen); + else if (curLen != 0) + { + if (curLen != prevLen) + { + WRITE_HF(curLen); + count--; + } + WRITE_HF(kTableLevelRepNumber); + WriteBits(count - 3, 2); + } + else if (count <= 10) + { + WRITE_HF(kTableLevel0Number); + WriteBits(count - 3, 3); + } + else + { + WRITE_HF(kTableLevel0Number2); + WriteBits(count - 11, 7); + } + + count = 0; + prevLen = curLen; + + if (nextLen == 0) + { + maxCount = 138; + minCount = 3; + } + else if (curLen == nextLen) + { + maxCount = 6; + minCount = 3; + } + else + { + maxCount = 7; + minCount = 4; + } + } +} + +NO_INLINE void CCoder::MakeTables(unsigned maxHuffLen) +{ + Huffman_Generate(mainFreqs, mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize, maxHuffLen); + Huffman_Generate(distFreqs, distCodes, m_NewLevels.distLevels, kDistTableSize64, maxHuffLen); +} + +static NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num) +{ + UInt32 price = 0; + UInt32 i; + for (i = 0; i < num; i++) + price += lens[i] * freqs[i]; + return price; +} + +static NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase) +{ + return Huffman_GetPrice(freqs, lens, num) + + Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase); +} + +NO_INLINE UInt32 CCoder::GetLzBlockPrice() const +{ + return + Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) + + Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0); +} + +NO_INLINE void CCoder::TryBlock() +{ + memset(mainFreqs, 0, sizeof(mainFreqs)); + memset(distFreqs, 0, sizeof(distFreqs)); + + m_ValueIndex = 0; + UInt32 blockSize = BlockSizeRes; + BlockSizeRes = 0; + for (;;) + { + if (m_OptimumCurrentIndex == m_OptimumEndIndex) + { + if (m_Pos >= kMatchArrayLimit + || BlockSizeRes >= blockSize + || (!m_SecondPass && ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize))) + break; + } + UInt32 pos; + UInt32 len; + if (_fastMode) + len = GetOptimalFast(pos); + else + len = GetOptimal(pos); + CCodeValue &codeValue = m_Values[m_ValueIndex++]; + if (len >= kMatchMinLen) + { + UInt32 newLen = len - kMatchMinLen; + codeValue.Len = (UInt16)newLen; + mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++; + codeValue.Pos = (UInt16)pos; + distFreqs[GetPosSlot(pos)]++; + } + else + { + Byte b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset); + mainFreqs[b]++; + codeValue.SetAsLiteral(); + codeValue.Pos = b; + } + m_AdditionalOffset -= len; + BlockSizeRes += len; + } + mainFreqs[kSymbolEndOfBlock]++; + m_AdditionalOffset += BlockSizeRes; + m_SecondPass = true; +} + +NO_INLINE void CCoder::SetPrices(const CLevels &levels) +{ + if (_fastMode) + return; + UInt32 i; + for (i = 0; i < 256; i++) + { + Byte price = levels.litLenLevels[i]; + m_LiteralPrices[i] = ((price != 0) ? price : kNoLiteralStatPrice); + } + + for (i = 0; i < m_NumLenCombinations; i++) + { + UInt32 slot = g_LenSlots[i]; + Byte price = levels.litLenLevels[kSymbolMatch + (size_t)slot]; + m_LenPrices[i] = (Byte)(((price != 0) ? price : kNoLenStatPrice) + m_LenDirectBits[slot]); + } + + for (i = 0; i < kDistTableSize64; i++) + { + Byte price = levels.distLevels[i]; + m_PosPrices[i] = (Byte)(((price != 0) ? price: kNoPosStatPrice) + kDistDirectBits[i]); + } +} + +static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num) +{ + for (UInt32 i = 0; i < num; i++) + { + UInt32 x = codes[i]; + x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1); + x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2); + x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4); + codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]); + } +} + +NO_INLINE void CCoder::WriteBlock() +{ + Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize); + Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64); + + for (UInt32 i = 0; i < m_ValueIndex; i++) + { + const CCodeValue &codeValue = m_Values[i]; + if (codeValue.IsLiteral()) + WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos); + else + { + UInt32 len = codeValue.Len; + UInt32 lenSlot = g_LenSlots[len]; + WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot); + m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]); + UInt32 dist = codeValue.Pos; + UInt32 posSlot = GetPosSlot(dist); + WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot); + m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]); + } + } + WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock); +} + +static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition) +{ + UInt32 price = 0; + do + { + UInt32 nextBitPosition = (bitPosition + kFinalBlockFieldSize + kBlockTypeFieldSize) & 7; + unsigned numBitsForAlign = nextBitPosition > 0 ? (8 - nextBitPosition): 0; + UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1; + price += kFinalBlockFieldSize + kBlockTypeFieldSize + numBitsForAlign + (2 + 2) * 8 + curBlockSize * 8; + bitPosition = 0; + blockSize -= curBlockSize; + } + while (blockSize != 0); + return price; +} + +void CCoder::WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock) +{ + do + { + UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1; + blockSize -= curBlockSize; + WriteBits((finalBlock && (blockSize == 0) ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize); + WriteBits(NBlockType::kStored, kBlockTypeFieldSize); + m_OutStream.FlushByte(); + WriteBits((UInt16)curBlockSize, kStoredBlockLengthFieldSize); + WriteBits((UInt16)~curBlockSize, kStoredBlockLengthFieldSize); + const Byte *data = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow)- additionalOffset; + for (UInt32 i = 0; i < curBlockSize; i++) + m_OutStream.WriteByte(data[i]); + additionalOffset -= curBlockSize; + } + while (blockSize != 0); +} + +NO_INLINE UInt32 CCoder::TryDynBlock(unsigned tableIndex, UInt32 numPasses) +{ + CTables &t = m_Tables[tableIndex]; + BlockSizeRes = t.BlockSizeRes; + UInt32 posTemp = t.m_Pos; + SetPrices(t); + + for (UInt32 p = 0; p < numPasses; p++) + { + m_Pos = posTemp; + TryBlock(); + unsigned numHuffBits = + (m_ValueIndex > 18000 ? 12 : + (m_ValueIndex > 7000 ? 11 : + (m_ValueIndex > 2000 ? 10 : 9))); + MakeTables(numHuffBits); + SetPrices(m_NewLevels); + } + + (CLevels &)t = m_NewLevels; + + m_NumLitLenLevels = kMainTableSize; + while (m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[(size_t)m_NumLitLenLevels - 1] == 0) + m_NumLitLenLevels--; + + m_NumDistLevels = kDistTableSize64; + while (m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[(size_t)m_NumDistLevels - 1] == 0) + m_NumDistLevels--; + + UInt32 levelFreqs[kLevelTableSize]; + memset(levelFreqs, 0, sizeof(levelFreqs)); + + LevelTableDummy(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelFreqs); + LevelTableDummy(m_NewLevels.distLevels, m_NumDistLevels, levelFreqs); + + Huffman_Generate(levelFreqs, levelCodes, levelLens, kLevelTableSize, kMaxLevelBitLength); + + m_NumLevelCodes = kNumLevelCodesMin; + for (UInt32 i = 0; i < kLevelTableSize; i++) + { + Byte level = levelLens[kCodeLengthAlphabetOrder[i]]; + if (level > 0 && i >= m_NumLevelCodes) + m_NumLevelCodes = i + 1; + m_LevelLevels[i] = level; + } + + return GetLzBlockPrice() + + Huffman_GetPrice_Spec(levelFreqs, levelLens, kLevelTableSize, kLevelDirectBits, kTableDirectLevels) + + kNumLenCodesFieldSize + kNumDistCodesFieldSize + kNumLevelCodesFieldSize + + m_NumLevelCodes * kLevelFieldSize + kFinalBlockFieldSize + kBlockTypeFieldSize; +} + +NO_INLINE UInt32 CCoder::TryFixedBlock(unsigned tableIndex) +{ + CTables &t = m_Tables[tableIndex]; + BlockSizeRes = t.BlockSizeRes; + m_Pos = t.m_Pos; + m_NewLevels.SetFixedLevels(); + SetPrices(m_NewLevels); + TryBlock(); + return kFinalBlockFieldSize + kBlockTypeFieldSize + GetLzBlockPrice(); +} + +NO_INLINE UInt32 CCoder::GetBlockPrice(unsigned tableIndex, unsigned numDivPasses) +{ + CTables &t = m_Tables[tableIndex]; + t.StaticMode = false; + UInt32 price = TryDynBlock(tableIndex, m_NumPasses); + t.BlockSizeRes = BlockSizeRes; + UInt32 numValues = m_ValueIndex; + UInt32 posTemp = m_Pos; + UInt32 additionalOffsetEnd = m_AdditionalOffset; + + if (m_CheckStatic && m_ValueIndex <= kFixedHuffmanCodeBlockSizeMax) + { + const UInt32 fixedPrice = TryFixedBlock(tableIndex); + t.StaticMode = (fixedPrice < price); + if (t.StaticMode) + price = fixedPrice; + } + + const UInt32 storePrice = GetStorePrice(BlockSizeRes, 0); // bitPosition + t.StoreMode = (storePrice <= price); + if (t.StoreMode) + price = storePrice; + + t.UseSubBlocks = false; + + if (numDivPasses > 1 && numValues >= kDivideCodeBlockSizeMin) + { + CTables &t0 = m_Tables[(tableIndex << 1)]; + (CLevels &)t0 = t; + t0.BlockSizeRes = t.BlockSizeRes >> 1; + t0.m_Pos = t.m_Pos; + UInt32 subPrice = GetBlockPrice((tableIndex << 1), numDivPasses - 1); + + UInt32 blockSize2 = t.BlockSizeRes - t0.BlockSizeRes; + if (t0.BlockSizeRes >= kDivideBlockSizeMin && blockSize2 >= kDivideBlockSizeMin) + { + CTables &t1 = m_Tables[(tableIndex << 1) + 1]; + (CLevels &)t1 = t; + t1.BlockSizeRes = blockSize2; + t1.m_Pos = m_Pos; + m_AdditionalOffset -= t0.BlockSizeRes; + subPrice += GetBlockPrice((tableIndex << 1) + 1, numDivPasses - 1); + t.UseSubBlocks = (subPrice < price); + if (t.UseSubBlocks) + price = subPrice; + } + } + + m_AdditionalOffset = additionalOffsetEnd; + m_Pos = posTemp; + return price; +} + +void CCoder::CodeBlock(unsigned tableIndex, bool finalBlock) +{ + CTables &t = m_Tables[tableIndex]; + if (t.UseSubBlocks) + { + CodeBlock((tableIndex << 1), false); + CodeBlock((tableIndex << 1) + 1, finalBlock); + } + else + { + if (t.StoreMode) + WriteStoreBlock(t.BlockSizeRes, m_AdditionalOffset, finalBlock); + else + { + WriteBits((finalBlock ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize); + if (t.StaticMode) + { + WriteBits(NBlockType::kFixedHuffman, kBlockTypeFieldSize); + TryFixedBlock(tableIndex); + unsigned i; + const unsigned kMaxStaticHuffLen = 9; + for (i = 0; i < kFixedMainTableSize; i++) + mainFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.litLenLevels[i]); + for (i = 0; i < kFixedDistTableSize; i++) + distFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.distLevels[i]); + MakeTables(kMaxStaticHuffLen); + } + else + { + if (m_NumDivPasses > 1 || m_CheckStatic) + TryDynBlock(tableIndex, 1); + WriteBits(NBlockType::kDynamicHuffman, kBlockTypeFieldSize); + WriteBits(m_NumLitLenLevels - kNumLitLenCodesMin, kNumLenCodesFieldSize); + WriteBits(m_NumDistLevels - kNumDistCodesMin, kNumDistCodesFieldSize); + WriteBits(m_NumLevelCodes - kNumLevelCodesMin, kNumLevelCodesFieldSize); + + for (UInt32 i = 0; i < m_NumLevelCodes; i++) + WriteBits(m_LevelLevels[i], kLevelFieldSize); + + Huffman_ReverseBits(levelCodes, levelLens, kLevelTableSize); + LevelTableCode(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelLens, levelCodes); + LevelTableCode(m_NewLevels.distLevels, m_NumDistLevels, levelLens, levelCodes); + } + WriteBlock(); + } + m_AdditionalOffset -= t.BlockSizeRes; + } +} + + +HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */ , const UInt64 * /* outSize */ , ICompressProgressInfo *progress) +{ + m_CheckStatic = (m_NumPasses != 1 || m_NumDivPasses != 1); + m_IsMultiPass = (m_CheckStatic || (m_NumPasses != 1 || m_NumDivPasses != 1)); + + /* we can set stream mode before MatchFinder_Create + if default MatchFinder mode was not STREAM_MODE) */ + // MatchFinder_SET_STREAM_MODE(&_lzInWindow); + + CSeqInStreamWrap _seqInStream; + _seqInStream.Init(inStream); + MatchFinder_SET_STREAM(&_lzInWindow, &_seqInStream.vt) + + RINOK(Create()) + + m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses; + + UInt64 nowPos = 0; + + MatchFinder_Init(&_lzInWindow); + m_OutStream.SetStream(outStream); + m_OutStream.Init(); + + m_OptimumEndIndex = m_OptimumCurrentIndex = 0; + + CTables &t = m_Tables[1]; + t.m_Pos = 0; + t.InitStructures(); + + m_AdditionalOffset = 0; + do + { + t.BlockSizeRes = kBlockUncompressedSizeThreshold; + m_SecondPass = false; + GetBlockPrice(1, m_NumDivPasses); + CodeBlock(1, Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0); + nowPos += m_Tables[1].BlockSizeRes; + if (progress != NULL) + { + UInt64 packSize = m_OutStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&nowPos, &packSize)) + } + } + while (Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) != 0); + + if (_seqInStream.Res != S_OK) + return _seqInStream.Res; + + if (_lzInWindow.result != SZ_OK) + return SResToHRESULT(_lzInWindow.result); + return m_OutStream.Flush(); +} + +HRESULT CCoder::BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return E_FAIL; } +} + +Z7_COM7F_IMF(CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) + { return BaseCode(inStream, outStream, inSize, outSize, progress); } + +Z7_COM7F_IMF(CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) + { return BaseSetEncoderProperties2(propIDs, props, numProps); } + +Z7_COM7F_IMF(CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) + { return BaseCode(inStream, outStream, inSize, outSize, progress); } + +Z7_COM7F_IMF(CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) + { return BaseSetEncoderProperties2(propIDs, props, numProps); } + +}}} diff --git a/CPP/7zip/Compress/DeflateEncoder.h b/CPP/7zip/Compress/DeflateEncoder.h index 4b7129341..be181e15b 100644 --- a/CPP/7zip/Compress/DeflateEncoder.h +++ b/CPP/7zip/Compress/DeflateEncoder.h @@ -1,203 +1,203 @@ -// DeflateEncoder.h - -#ifndef ZIP7_INC_DEFLATE_ENCODER_H -#define ZIP7_INC_DEFLATE_ENCODER_H - -#include "../../../C/LzFind.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "BitlEncoder.h" -#include "DeflateConst.h" - -namespace NCompress { -namespace NDeflate { -namespace NEncoder { - -struct CCodeValue -{ - UInt16 Len; - UInt16 Pos; - void SetAsLiteral() { Len = (1 << 15); } - bool IsLiteral() const { return (Len >= (1 << 15)); } -}; - -struct COptimal -{ - UInt32 Price; - UInt16 PosPrev; - UInt16 BackPrev; -}; - -const UInt32 kNumOptsBase = 1 << 12; -const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen; - -class CCoder; - -struct CTables: public CLevels -{ - bool UseSubBlocks; - bool StoreMode; - bool StaticMode; - UInt32 BlockSizeRes; - UInt32 m_Pos; - void InitStructures(); -}; - - -struct CEncProps -{ - int Level; - int algo; - int fb; - int btMode; - UInt32 mc; - UInt32 numPasses; - - CEncProps() - { - Level = -1; - mc = 0; - algo = fb = btMode = -1; - numPasses = (UInt32)(Int32)-1; - } - void Normalize(); -}; - -class CCoder -{ - CMatchFinder _lzInWindow; - CBitlEncoder m_OutStream; - -public: - CCodeValue *m_Values; - - UInt16 *m_MatchDistances; - UInt32 m_NumFastBytes; - bool _fastMode; - bool _btMode; - - UInt16 *m_OnePosMatchesMemory; - UInt16 *m_DistanceMemory; - - UInt32 m_Pos; - - unsigned m_NumPasses; - unsigned m_NumDivPasses; - bool m_CheckStatic; - bool m_IsMultiPass; - UInt32 m_ValueBlockSize; - - UInt32 m_NumLenCombinations; - UInt32 m_MatchMaxLen; - const Byte *m_LenStart; - const Byte *m_LenDirectBits; - - bool m_Created; - bool m_Deflate64Mode; - - Byte m_LevelLevels[kLevelTableSize]; - unsigned m_NumLitLenLevels; - unsigned m_NumDistLevels; - UInt32 m_NumLevelCodes; - UInt32 m_ValueIndex; - - bool m_SecondPass; - UInt32 m_AdditionalOffset; - - UInt32 m_OptimumEndIndex; - UInt32 m_OptimumCurrentIndex; - - Byte m_LiteralPrices[256]; - Byte m_LenPrices[kNumLenSymbolsMax]; - Byte m_PosPrices[kDistTableSize64]; - - CLevels m_NewLevels; - UInt32 mainFreqs[kFixedMainTableSize]; - UInt32 distFreqs[kDistTableSize64]; - UInt32 mainCodes[kFixedMainTableSize]; - UInt32 distCodes[kDistTableSize64]; - UInt32 levelCodes[kLevelTableSize]; - Byte levelLens[kLevelTableSize]; - - UInt32 BlockSizeRes; - - CTables *m_Tables; - COptimal m_Optimum[kNumOpts]; - - UInt32 m_MatchFinderCycles; - - void GetMatches(); - void MovePos(UInt32 num); - UInt32 Backward(UInt32 &backRes, UInt32 cur); - UInt32 GetOptimal(UInt32 &backRes); - UInt32 GetOptimalFast(UInt32 &backRes); - - void LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs); - - void WriteBits(UInt32 value, unsigned numBits); - void LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes); - - void MakeTables(unsigned maxHuffLen); - UInt32 GetLzBlockPrice() const; - void TryBlock(); - UInt32 TryDynBlock(unsigned tableIndex, UInt32 numPasses); - - UInt32 TryFixedBlock(unsigned tableIndex); - - void SetPrices(const CLevels &levels); - void WriteBlock(); - - HRESULT Create(); - void Free(); - - void WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock); - void WriteTables(bool writeMode, bool finalBlock); - - void WriteBlockData(bool writeMode, bool finalBlock); - - UInt32 GetBlockPrice(unsigned tableIndex, unsigned numDivPasses); - void CodeBlock(unsigned tableIndex, bool finalBlock); - - void SetProps(const CEncProps *props2); -public: - CCoder(bool deflate64Mode = false); - ~CCoder(); - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - HRESULT BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - - HRESULT BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); -}; - - -class CCOMCoder Z7_final: - public ICompressCoder, - public ICompressSetCoderProperties, - public CMyUnknownImp, - public CCoder -{ - Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties) -public: - CCOMCoder(): CCoder(false) {} -}; - -class CCOMCoder64 Z7_final: - public ICompressCoder, - public ICompressSetCoderProperties, - public CMyUnknownImp, - public CCoder -{ - Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties) -public: - CCOMCoder64(): CCoder(true) {} -}; - -}}} - -#endif +// DeflateEncoder.h + +#ifndef ZIP7_INC_DEFLATE_ENCODER_H +#define ZIP7_INC_DEFLATE_ENCODER_H + +#include "../../../C/LzFind.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "BitlEncoder.h" +#include "DeflateConst.h" + +namespace NCompress { +namespace NDeflate { +namespace NEncoder { + +struct CCodeValue +{ + UInt16 Len; + UInt16 Pos; + void SetAsLiteral() { Len = (1 << 15); } + bool IsLiteral() const { return (Len >= (1 << 15)); } +}; + +struct COptimal +{ + UInt32 Price; + UInt16 PosPrev; + UInt16 BackPrev; +}; + +const UInt32 kNumOptsBase = 1 << 12; +const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen; + +class CCoder; + +struct CTables: public CLevels +{ + bool UseSubBlocks; + bool StoreMode; + bool StaticMode; + UInt32 BlockSizeRes; + UInt32 m_Pos; + void InitStructures(); +}; + + +struct CEncProps +{ + int Level; + int algo; + int fb; + int btMode; + UInt32 mc; + UInt32 numPasses; + + CEncProps() + { + Level = -1; + mc = 0; + algo = fb = btMode = -1; + numPasses = (UInt32)(Int32)-1; + } + void Normalize(); +}; + +class CCoder +{ + CMatchFinder _lzInWindow; + CBitlEncoder m_OutStream; + +public: + CCodeValue *m_Values; + + UInt16 *m_MatchDistances; + UInt32 m_NumFastBytes; + bool _fastMode; + bool _btMode; + + UInt16 *m_OnePosMatchesMemory; + UInt16 *m_DistanceMemory; + + UInt32 m_Pos; + + unsigned m_NumPasses; + unsigned m_NumDivPasses; + bool m_CheckStatic; + bool m_IsMultiPass; + UInt32 m_ValueBlockSize; + + UInt32 m_NumLenCombinations; + UInt32 m_MatchMaxLen; + const Byte *m_LenStart; + const Byte *m_LenDirectBits; + + bool m_Created; + bool m_Deflate64Mode; + + Byte m_LevelLevels[kLevelTableSize]; + unsigned m_NumLitLenLevels; + unsigned m_NumDistLevels; + UInt32 m_NumLevelCodes; + UInt32 m_ValueIndex; + + bool m_SecondPass; + UInt32 m_AdditionalOffset; + + UInt32 m_OptimumEndIndex; + UInt32 m_OptimumCurrentIndex; + + Byte m_LiteralPrices[256]; + Byte m_LenPrices[kNumLenSymbolsMax]; + Byte m_PosPrices[kDistTableSize64]; + + CLevels m_NewLevels; + UInt32 mainFreqs[kFixedMainTableSize]; + UInt32 distFreqs[kDistTableSize64]; + UInt32 mainCodes[kFixedMainTableSize]; + UInt32 distCodes[kDistTableSize64]; + UInt32 levelCodes[kLevelTableSize]; + Byte levelLens[kLevelTableSize]; + + UInt32 BlockSizeRes; + + CTables *m_Tables; + COptimal m_Optimum[kNumOpts]; + + UInt32 m_MatchFinderCycles; + + void GetMatches(); + void MovePos(UInt32 num); + UInt32 Backward(UInt32 &backRes, UInt32 cur); + UInt32 GetOptimal(UInt32 &backRes); + UInt32 GetOptimalFast(UInt32 &backRes); + + void LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs); + + void WriteBits(UInt32 value, unsigned numBits); + void LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes); + + void MakeTables(unsigned maxHuffLen); + UInt32 GetLzBlockPrice() const; + void TryBlock(); + UInt32 TryDynBlock(unsigned tableIndex, UInt32 numPasses); + + UInt32 TryFixedBlock(unsigned tableIndex); + + void SetPrices(const CLevels &levels); + void WriteBlock(); + + HRESULT Create(); + void Free(); + + void WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock); + void WriteTables(bool writeMode, bool finalBlock); + + void WriteBlockData(bool writeMode, bool finalBlock); + + UInt32 GetBlockPrice(unsigned tableIndex, unsigned numDivPasses); + void CodeBlock(unsigned tableIndex, bool finalBlock); + + void SetProps(const CEncProps *props2); +public: + CCoder(bool deflate64Mode = false); + ~CCoder(); + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + HRESULT BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + HRESULT BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); +}; + + +class CCOMCoder Z7_final: + public ICompressCoder, + public ICompressSetCoderProperties, + public CMyUnknownImp, + public CCoder +{ + Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties) +public: + CCOMCoder(): CCoder(false) {} +}; + +class CCOMCoder64 Z7_final: + public ICompressCoder, + public ICompressSetCoderProperties, + public CMyUnknownImp, + public CCoder +{ + Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties) +public: + CCOMCoder64(): CCoder(true) {} +}; + +}}} + +#endif diff --git a/CPP/7zip/Compress/DeflateRegister.cpp b/CPP/7zip/Compress/DeflateRegister.cpp index 22a8aa623..eaedb84ab 100644 --- a/CPP/7zip/Compress/DeflateRegister.cpp +++ b/CPP/7zip/Compress/DeflateRegister.cpp @@ -1,25 +1,25 @@ -// DeflateRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "DeflateDecoder.h" -#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) -#include "DeflateEncoder.h" -#endif - -namespace NCompress { -namespace NDeflate { - -REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder) - -#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) -REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder) -#else -#define CreateEnc NULL -#endif - -REGISTER_CODEC_2(Deflate, CreateDec, CreateEnc, 0x40108, "Deflate") - -}} +// DeflateRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "DeflateDecoder.h" +#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) +#include "DeflateEncoder.h" +#endif + +namespace NCompress { +namespace NDeflate { + +REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder) + +#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY) +REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder) +#else +#define CreateEnc NULL +#endif + +REGISTER_CODEC_2(Deflate, CreateDec, CreateEnc, 0x40108, "Deflate") + +}} diff --git a/CPP/7zip/Compress/DeltaFilter.cpp b/CPP/7zip/Compress/DeltaFilter.cpp index 0ddf2cd62..c234b7a6c 100644 --- a/CPP/7zip/Compress/DeltaFilter.cpp +++ b/CPP/7zip/Compress/DeltaFilter.cpp @@ -1,126 +1,126 @@ -// DeltaFilter.cpp - -#include "StdAfx.h" - -#include "../../../C/Delta.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/RegisterCodec.h" - -namespace NCompress { -namespace NDelta { - -struct CDelta -{ - unsigned _delta; - Byte _state[DELTA_STATE_SIZE]; - - CDelta(): _delta(1) {} - void DeltaInit() { Delta_Init(_state); } -}; - - -#ifndef Z7_EXTRACT_ONLY - -class CEncoder Z7_final: - public ICompressFilter, - public ICompressSetCoderProperties, - public ICompressWriteCoderProperties, - public CMyUnknownImp, - CDelta -{ - Z7_IFACES_IMP_UNK_3( - ICompressFilter, - ICompressSetCoderProperties, - ICompressWriteCoderProperties) -}; - -Z7_COM7F_IMF(CEncoder::Init()) -{ - DeltaInit(); - return S_OK; -} - -Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) -{ - Delta_Encode(_state, _delta, data, size); - return size; -} - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -{ - unsigned delta = _delta; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = props[i]; - const PROPID propID = propIDs[i]; - if (propID >= NCoderPropID::kReduceSize) - continue; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - switch (propID) - { - case NCoderPropID::kDefaultProp: - if (prop.ulVal < 1 || prop.ulVal > 256) - return E_INVALIDARG; - delta = prop.ulVal; - break; - case NCoderPropID::kNumThreads: break; - case NCoderPropID::kLevel: break; - default: return E_INVALIDARG; - } - } - _delta = delta; - return S_OK; -} - -Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) -{ - const Byte prop = (Byte)(_delta - 1); - return outStream->Write(&prop, 1, NULL); -} - -#endif - - -class CDecoder Z7_final: - public ICompressFilter, - public ICompressSetDecoderProperties2, - public CMyUnknownImp, - CDelta -{ - Z7_IFACES_IMP_UNK_2( - ICompressFilter, - ICompressSetDecoderProperties2) -}; - -Z7_COM7F_IMF(CDecoder::Init()) -{ - DeltaInit(); - return S_OK; -} - -Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) -{ - Delta_Decode(_state, _delta, data, size); - return size; -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) -{ - if (size != 1) - return E_INVALIDARG; - _delta = (unsigned)props[0] + 1; - return S_OK; -} - - -REGISTER_FILTER_E(Delta, - CDecoder(), - CEncoder(), - 3, "Delta") - -}} +// DeltaFilter.cpp + +#include "StdAfx.h" + +#include "../../../C/Delta.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/RegisterCodec.h" + +namespace NCompress { +namespace NDelta { + +struct CDelta +{ + unsigned _delta; + Byte _state[DELTA_STATE_SIZE]; + + CDelta(): _delta(1) {} + void DeltaInit() { Delta_Init(_state); } +}; + + +#ifndef Z7_EXTRACT_ONLY + +class CEncoder Z7_final: + public ICompressFilter, + public ICompressSetCoderProperties, + public ICompressWriteCoderProperties, + public CMyUnknownImp, + CDelta +{ + Z7_IFACES_IMP_UNK_3( + ICompressFilter, + ICompressSetCoderProperties, + ICompressWriteCoderProperties) +}; + +Z7_COM7F_IMF(CEncoder::Init()) +{ + DeltaInit(); + return S_OK; +} + +Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) +{ + Delta_Encode(_state, _delta, data, size); + return size; +} + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +{ + unsigned delta = _delta; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = props[i]; + const PROPID propID = propIDs[i]; + if (propID >= NCoderPropID::kReduceSize) + continue; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + switch (propID) + { + case NCoderPropID::kDefaultProp: + if (prop.ulVal < 1 || prop.ulVal > 256) + return E_INVALIDARG; + delta = prop.ulVal; + break; + case NCoderPropID::kNumThreads: break; + case NCoderPropID::kLevel: break; + default: return E_INVALIDARG; + } + } + _delta = delta; + return S_OK; +} + +Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) +{ + const Byte prop = (Byte)(_delta - 1); + return outStream->Write(&prop, 1, NULL); +} + +#endif + + +class CDecoder Z7_final: + public ICompressFilter, + public ICompressSetDecoderProperties2, + public CMyUnknownImp, + CDelta +{ + Z7_IFACES_IMP_UNK_2( + ICompressFilter, + ICompressSetDecoderProperties2) +}; + +Z7_COM7F_IMF(CDecoder::Init()) +{ + DeltaInit(); + return S_OK; +} + +Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) +{ + Delta_Decode(_state, _delta, data, size); + return size; +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) +{ + if (size != 1) + return E_INVALIDARG; + _delta = (unsigned)props[0] + 1; + return S_OK; +} + + +REGISTER_FILTER_E(Delta, + CDecoder(), + CEncoder(), + 3, "Delta") + +}} diff --git a/CPP/7zip/Compress/DllExports2Compress.cpp b/CPP/7zip/Compress/DllExports2Compress.cpp index 21bf7bb41..f3b862d12 100644 --- a/CPP/7zip/Compress/DllExports2Compress.cpp +++ b/CPP/7zip/Compress/DllExports2Compress.cpp @@ -1,38 +1,38 @@ -// DllExports2Compress.cpp - -#include "StdAfx.h" - -#include "../../Common/MyInitGuid.h" - -#include "../ICoder.h" - -#include "../Common/RegisterCodec.h" - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/); - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/) -{ - return TRUE; -} - -STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); - -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) -{ - return CreateCoder(clsid, iid, outObject); -} +// DllExports2Compress.cpp + +#include "StdAfx.h" + +#include "../../Common/MyInitGuid.h" + +#include "../ICoder.h" + +#include "../Common/RegisterCodec.h" + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/); + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/) +{ + return TRUE; +} + +STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); + +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) +{ + return CreateCoder(clsid, iid, outObject); +} diff --git a/CPP/7zip/Compress/DllExportsCompress.cpp b/CPP/7zip/Compress/DllExportsCompress.cpp index 5c59dc5b1..24749d276 100644 --- a/CPP/7zip/Compress/DllExportsCompress.cpp +++ b/CPP/7zip/Compress/DllExportsCompress.cpp @@ -1,59 +1,59 @@ -// DllExportsCompress.cpp - -#include "StdAfx.h" - -#include "../../Common/MyInitGuid.h" - -#include "../ICoder.h" - -#include "../Common/RegisterCodec.h" - -static const unsigned kNumCodecsMax = 48; -unsigned g_NumCodecs = 0; -const CCodecInfo *g_Codecs[kNumCodecsMax]; -void RegisterCodec(const CCodecInfo *codecInfo) throw() -{ - if (g_NumCodecs < kNumCodecsMax) - g_Codecs[g_NumCodecs++] = codecInfo; -} - -static const unsigned kNumHashersMax = 16; -unsigned g_NumHashers = 0; -const CHasherInfo *g_Hashers[kNumHashersMax]; -void RegisterHasher(const CHasherInfo *hashInfo) throw() -{ - if (g_NumHashers < kNumHashersMax) - g_Hashers[g_NumHashers++] = hashInfo; -} - -#ifdef _WIN32 - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - , DWORD /* dwReason */, LPVOID /*lpReserved*/); - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - , DWORD /* dwReason */, LPVOID /*lpReserved*/) -{ - return TRUE; -} -#endif - -STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); - -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); -STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) -{ - return CreateCoder(clsid, iid, outObject); -} +// DllExportsCompress.cpp + +#include "StdAfx.h" + +#include "../../Common/MyInitGuid.h" + +#include "../ICoder.h" + +#include "../Common/RegisterCodec.h" + +static const unsigned kNumCodecsMax = 48; +unsigned g_NumCodecs = 0; +const CCodecInfo *g_Codecs[kNumCodecsMax]; +void RegisterCodec(const CCodecInfo *codecInfo) throw() +{ + if (g_NumCodecs < kNumCodecsMax) + g_Codecs[g_NumCodecs++] = codecInfo; +} + +static const unsigned kNumHashersMax = 16; +unsigned g_NumHashers = 0; +const CHasherInfo *g_Hashers[kNumHashersMax]; +void RegisterHasher(const CHasherInfo *hashInfo) throw() +{ + if (g_NumHashers < kNumHashersMax) + g_Hashers[g_NumHashers++] = hashInfo; +} + +#ifdef _WIN32 + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + , DWORD /* dwReason */, LPVOID /*lpReserved*/); + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + , DWORD /* dwReason */, LPVOID /*lpReserved*/) +{ + return TRUE; +} +#endif + +STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject); + +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject); +STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject) +{ + return CreateCoder(clsid, iid, outObject); +} diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h index 10cf5c256..318190d4e 100644 --- a/CPP/7zip/Compress/HuffmanDecoder.h +++ b/CPP/7zip/Compress/HuffmanDecoder.h @@ -1,527 +1,527 @@ -// Compress/HuffmanDecoder.h - -#ifndef ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H -#define ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H - -#include "../../../C/CpuArch.h" -#include "../../Common/MyTypes.h" - -namespace NCompress { -namespace NHuffman { - -// const unsigned kNumTableBits_Default = 9; - -#if 0 || 0 && defined(MY_CPU_64BIT) -// for debug or optimization: -// 64-BIT limit array can be faster for some compilers. -// for debug or optimization: -#define Z7_HUFF_USE_64BIT_LIMIT -#else -// sizet value variable allows to eliminate some move operation in some compilers. -// for debug or optimization: -// #define Z7_HUFF_USE_SIZET_VALUE -#endif - -// v0 must normalized to (32 bits) : (v0 < ((UInt64)1 << 32)) - -#ifdef Z7_HUFF_USE_64BIT_LIMIT - typedef UInt64 CLimitInt; - typedef UInt64 CValueInt; - // all _limits[*] are normalized and limited by ((UInt64)1 << 32). - // we don't use (v1) in this branch - #define Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) 32 - #define Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1) \ - ((NCompress::NHuffman::CLimitInt)v0 >= (huf)->_limits[0]) - #define Z7_HUFF_GET_VAL_FOR_LIMITS(v0, v1, kNumBitsMax, kNumTableBits) (v0) - #define Z7_HUFF_GET_VAL_FOR_TABLE( v0, v1, kNumBitsMax, kNumTableBits) ((v0) >> (32 - kNumTableBits)) - #define Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1) -#else - typedef UInt32 CLimitInt; - typedef - #ifdef Z7_HUFF_USE_SIZET_VALUE - size_t - #else - UInt32 - #endif - CValueInt; - // v1 must be precalculated from v0 in this branch - // _limits[0] and (v1) are normalized and limited by (1 << kNumTableBits). - // _limits[non_0] are normalized and limited by (1 << kNumBitsMax). - #define Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) (kNumBitsMax) - #define Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1) \ - ((NCompress::NHuffman::CLimitInt)v1 >= (huf)->_limits[0]) - #define Z7_HUFF_GET_VAL_FOR_LIMITS(v0, v1, kNumBitsMax, kNumTableBits) ((v0) >> (32 - kNumBitsMax)) - #define Z7_HUFF_GET_VAL_FOR_TABLE( v0, v1, kNumBitsMax, kNumTableBits) (v1) - #define Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1) const UInt32 v1 = ((v0) >> (32 - kNumTableBits)); -#endif - - -enum enum_BuildMode -{ - k_BuildMode_Partial = 0, - k_BuildMode_Full = 1, - k_BuildMode_Full_or_Empty = 2 -}; - - -template -struct CDecoderBase -{ - CLimitInt _limits[kNumBitsMax + 2 - kNumTableBits]; - UInt32 _poses[kNumBitsMax - kNumTableBits]; // unsigned -union -{ - // if defined(MY_CPU_64BIT), we need 64-bit alignment for _symbols. - // if !defined(MY_CPU_64BIT), we need 32-bit alignment for _symbols - // but we provide alignment for _lens. - // _symbols also will be aligned, if _lens are aligned - #if defined(MY_CPU_64BIT) - UInt64 - #else - UInt32 - #endif - _pad_align[m_NumSymbols < (1u << sizeof(symType) * 8) ? 1 : -1]; - /* if symType is Byte, we use 16-bytes padding to avoid cache - bank conflict between _lens and _symbols: */ - Byte _lens[(1 << kNumTableBits) + (sizeof(symType) == 1 ? 16 : 0)]; -} _u; - symType _symbols[(1 << kNumTableBits) + m_NumSymbols - (kNumTableBits + 1)]; - - /* - Z7_FORCE_INLINE - bool IsFull() const - { - return _limits[kNumBitsMax - kNumTableBits] == - (CLimitInt)1u << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax); - } - Z7_FORCE_INLINE - bool IsEmpty() const - { - return _limits[kNumBitsMax - kNumTableBits] == 0; - } - Z7_FORCE_INLINE - bool Is_Full_or_Empty() const - { - return 0 == (_limits[kNumBitsMax - kNumTableBits] & - ~((CLimitInt)1 << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax))); - } - */ - - Z7_FORCE_INLINE - bool Build(const Byte *lens, enum_BuildMode buidMode = k_BuildMode_Partial) throw() - { - unsigned counts[kNumBitsMax + 1]; - size_t i; - for (i = 0; i <= kNumBitsMax; i++) - counts[i] = 0; - for (i = 0; i < m_NumSymbols; i++) - counts[lens[i]]++; - - UInt32 sum = 0; - for (i = 1; i <= kNumTableBits; i++) - { - sum <<= 1; - sum += counts[i]; - } - - CLimitInt startPos = (CLimitInt)sum; - _limits[0] = - #ifdef Z7_HUFF_USE_64BIT_LIMIT - startPos << (Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - kNumTableBits); - #else - startPos; - #endif - - for (i = kNumTableBits + 1; i <= kNumBitsMax; i++) - { - startPos <<= 1; - _poses[i - (kNumTableBits + 1)] = (UInt32)(startPos - sum); - const unsigned cnt = counts[i]; - counts[i] = sum; - sum += cnt; - startPos += cnt; - _limits[i - kNumTableBits] = startPos << (Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - i); - } - - _limits[kNumBitsMax + 1 - kNumTableBits] = - (CLimitInt)1 << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax); - - if (buidMode == k_BuildMode_Partial) - { - if (startPos > (1u << kNumBitsMax)) return false; - } - else - { - if (buidMode != k_BuildMode_Full && startPos == 0) return true; - if (startPos != (1u << kNumBitsMax)) return false; - } - size_t sum2 = 0; - for (i = 1; i <= kNumTableBits; i++) - { - const unsigned cnt = counts[i] << (kNumTableBits - i); - counts[i] = (unsigned)sum2 >> (kNumTableBits - i); - memset(_u._lens + sum2, (int)i, cnt); - sum2 += cnt; - } - -#ifdef MY_CPU_64BIT - symType4 - // UInt64 // for symType = UInt16 - // UInt32 // for symType = Byte -#else - UInt32 -#endif - v = 0; - for (i = 0; i < m_NumSymbols; i++, - v += - 1 - + ( (UInt32)1 << (sizeof(symType) * 8 * 1)) - // 0x00010001 // for symType = UInt16 - // 0x00000101 // for symType = Byte -#ifdef MY_CPU_64BIT - + ((symType4)1 << (sizeof(symType) * 8 * 2)) - + ((symType4)1 << (sizeof(symType) * 8 * 3)) - // 0x0001000100010001 // for symType = UInt16 - // 0x0000000001010101 // for symType = Byte -#endif - ) - { - const unsigned len = lens[i]; - if (len == 0) - continue; - const size_t offset = counts[len]; - counts[len] = (unsigned)offset + 1; - if (len >= kNumTableBits) - _symbols[offset] = (symType)v; - else - { - Byte *s2 = (Byte *)(void *)_symbols + (offset << - (kNumTableBits + sizeof(symType) / 2 - len)); - Byte *lim = s2 + ((size_t)1 << - (kNumTableBits + sizeof(symType) / 2 - len)); - if (len >= kNumTableBits - 2) - { - *(symType2 *)(void *)(s2 ) = (symType2)v; - *(symType2 *)(void *)(lim - sizeof(symType) * 2) = (symType2)v; - } - else - { -#ifdef MY_CPU_64BIT - symType4 *s = (symType4 *)(void *)s2; - do - { - s[0] = v; s[1] = v; s += 2; - } - while (s != (const symType4 *)(const void *)lim); -#else - symType2 *s = (symType2 *)(void *)s2; - do - { - s[0] = (symType2)v; s[1] = (symType2)v; s += 2; - s[0] = (symType2)v; s[1] = (symType2)v; s += 2; - } - while (s != (const symType2 *)(const void *)lim); -#endif - } - } - } - return true; - } - - -#define Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES(_numBits_, kNumBitsMax, error_op) if (_numBits_ > kNumBitsMax) { error_op } -#define Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO( _numBits_, kNumBitsMax, error_op) - - -#define Z7_HUFF_DECODE_BASE_TREE_BRANCH(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - get_val_for_limits, \ - check_op, error_op, _numBits_) \ -{ \ - const NHuffman::CValueInt _val = get_val_for_limits(v0, v1, kNumBitsMax, kNumTableBits); \ - _numBits_ = kNumTableBits + 1; \ - if ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[1]) \ - do { _numBits_++; } \ - while ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[_numBits_ - kNumTableBits]); \ - check_op(_numBits_, kNumBitsMax, error_op) \ - sym = (huf)->_symbols[(/* (UInt32) */ (_val >> ((Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - (unsigned)_numBits_)))) \ - - (huf)->_poses[_numBits_ - (kNumTableBits + 1)]]; \ -} - -/* - Z7_HUFF_DECODE_BASE_TREE_BRANCH(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - get_val_for_limits, \ - check_op, error_op, _numBits_) \ - -*/ - -#define Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - get_val_for_table, get_val_for_limits, \ - check_op, error_op, move_pos_op, after_op, bs) \ -{ \ - if (Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1)) \ - { \ - const NHuffman::CValueInt _val = get_val_for_limits(v0, v1, kNumBitsMax, kNumTableBits); \ - size_t _numBits_ = kNumTableBits + 1; \ - if ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[1]) \ - do { _numBits_++; } \ - while ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[_numBits_ - kNumTableBits]); \ - check_op(_numBits_, kNumBitsMax, error_op) \ - sym = (huf)->_symbols[(/* (UInt32) */ (_val >> ((Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - (unsigned)_numBits_)))) \ - - (huf)->_poses[_numBits_ - (kNumTableBits + 1)]]; \ - move_pos_op(bs, _numBits_); \ - } \ - else \ - { \ - const size_t _val = get_val_for_table(v0, v1, kNumBitsMax, kNumTableBits); \ - const size_t _numBits_ = (huf)->_u._lens[_val]; \ - sym = (huf)->_symbols[_val]; \ - move_pos_op(bs, _numBits_); \ - } \ - after_op \ -} - -#define Z7_HUFF_DECODE_10(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - check_op, error_op, move_pos_op, after_op, bs) \ - Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - Z7_HUFF_GET_VAL_FOR_TABLE, \ - Z7_HUFF_GET_VAL_FOR_LIMITS, \ - check_op, error_op, move_pos_op, after_op, bs) \ - - -#define Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, \ - check_op, error_op, move_pos_op, after_op, bs) \ -{ \ - Z7_HUFF_PRECALC_V1(kNumTableBits, v0, _v1_temp) \ - Z7_HUFF_DECODE_10(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, _v1_temp, \ - check_op, error_op, move_pos_op, after_op, bs) \ -} - -#if 0 || defined(Z7_HUFF_USE_64BIT_LIMIT) -// this branch uses bitStream->GetValue_InHigh32bits(). -#define Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, \ - check_op, error_op, move_pos_op) \ -{ \ - const UInt32 v0 = (bitStream)->GetValue_InHigh32bits(); \ - Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1); \ - Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - Z7_HUFF_GET_VAL_FOR_TABLE, \ - Z7_HUFF_GET_VAL_FOR_LIMITS, \ - check_op, error_op, move_pos_op, {}, bitStream) \ -} -#else -/* -this branch uses bitStream->GetValue(). -So we use SIMPLE versions for v0, v1 calculation: - v0 is normalized for kNumBitsMax - v1 is normalized for kNumTableBits -*/ -#define Z7_HUFF_GET_VAL_FOR_LIMITS_SIMPLE(v0, v1, kNumBitsMax, kNumTableBits) v0 -#define Z7_HUFF_GET_VAL_FOR_TABLE_SIMPLE( v0, v1, kNumBitsMax, kNumTableBits) v1 -#define Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, move_pos_op) \ -{ \ - const UInt32 v0 = (bitStream)->GetValue(kNumBitsMax); \ - const UInt32 v1 = v0 >> (kNumBitsMax - kNumTableBits); \ - Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ - v0, v1, \ - Z7_HUFF_GET_VAL_FOR_TABLE_SIMPLE, \ - Z7_HUFF_GET_VAL_FOR_LIMITS_SIMPLE, \ - check_op, error_op, move_pos_op, {}, bitStream) \ -} -#endif - -#define Z7_HUFF_bitStream_MovePos(bitStream, numBits) (bitStream)->MovePos((unsigned)(numBits)) - -#define Z7_HUFF_DECODE_1(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op) \ - Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, \ - Z7_HUFF_bitStream_MovePos) - -// MovePosCheck - -#define Z7_HUFF_DECODE_2(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op) \ - Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, \ - Z7_HUFF_bitStream_MovePos) - -// MovePosCheck - -#define Z7_HUFF_DECODE_CHECK(sym, huf, kNumBitsMax, kNumTableBits, bitStream, error_op) \ - Z7_HUFF_DECODE_1( sym, huf, kNumBitsMax, kNumTableBits, bitStream, \ - Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, error_op) - - template - Z7_FORCE_INLINE - bool Decode2(TBitDecoder *bitStream, unsigned &sym) const - { - Z7_HUFF_DECODE_CHECK(sym, this, kNumBitsMax, kNumTableBits, bitStream, - { return false; } - ) - return true; - } - - template - Z7_FORCE_INLINE - bool Decode_SymCheck_MovePosCheck(TBitDecoder *bitStream, unsigned &sym) const - { - Z7_HUFF_DECODE_0(sym, this, kNumBitsMax, kNumTableBits, bitStream, - Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, - { return false; }, - { return (bitStream)->MovePosCheck; } - ) - } - - template - Z7_FORCE_INLINE - unsigned Decode(TBitDecoder *bitStream) const - { - unsigned sym; - Z7_HUFF_DECODE_CHECK(sym, this, kNumBitsMax, kNumTableBits, bitStream, - { return (unsigned)(int)(Int32)0xffffffff; } - ) - return sym; - } - - - template - Z7_FORCE_INLINE - unsigned DecodeFull(TBitDecoder *bitStream) const - { - /* - const UInt32 val = bitStream->GetValue(kNumBitsMax); - if (val < _limits[kNumTableBits]) - { - const unsigned pair = _u._lens[(size_t)(val >> (kNumBitsMax - kNumTableBits))]; - bitStream->MovePos(pair & kPairLenMask); - return pair >> kNumPairLenBits; - } - - unsigned numBits; - for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++); - - bitStream->MovePos(numBits); - return _symbols[_poses[numBits] + (unsigned) - ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits))]; - */ - unsigned sym; - Z7_HUFF_DECODE_2(sym, this, kNumBitsMax, kNumTableBits, bitStream, - Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {} - ) - return sym; - } -}; - - -template -struct CDecoder: public CDecoderBase - {}; - -template -struct CDecoder256: public CDecoderBase - {}; - - -template -class CDecoder7b -{ -public: - Byte _lens[1 << 7]; - - bool Build(const Byte *lens, bool full) throw() - { - const unsigned kNumBitsMax = 7; - - unsigned counts[kNumBitsMax + 1]; - unsigned _poses[kNumBitsMax + 1]; - unsigned _limits[kNumBitsMax + 1]; - unsigned i; - for (i = 0; i <= kNumBitsMax; i++) - counts[i] = 0; - for (i = 0; i < numSymbols; i++) - counts[lens[i]]++; - - _limits[0] = 0; - const unsigned kMaxValue = 1u << kNumBitsMax; - unsigned startPos = 0; - unsigned sum = 0; - - for (i = 1; i <= kNumBitsMax; i++) - { - const unsigned cnt = counts[i]; - startPos += cnt << (kNumBitsMax - i); - _limits[i] = startPos; - counts[i] = sum; - _poses[i] = sum; - sum += cnt; - } - - counts[0] = sum; - _poses[0] = sum; - - if (full) - { - if (startPos != kMaxValue) - return false; - } - else - { - if (startPos > kMaxValue) - return false; - } - - - for (i = 0; i < numSymbols; i++) - { - const unsigned len = lens[i]; - if (len == 0) - continue; - const unsigned offset = counts[len]++; - { - Byte *dest = _lens + _limits[(size_t)len - 1] - + ((offset - _poses[len]) << (kNumBitsMax - len)); - const unsigned num = (unsigned)1 << (kNumBitsMax - len); - const unsigned val = (i << 3) + len; - for (unsigned k = 0; k < num; k++) - dest[k] = (Byte)val; - } - } - - if (!full) - { - const unsigned limit = _limits[kNumBitsMax]; - const unsigned num = ((unsigned)1 << kNumBitsMax) - limit; - Byte *dest = _lens + limit; - for (unsigned k = 0; k < num; k++) - dest[k] = (Byte) - // (0x1f << 3); - ((0x1f << 3) + 0x7); - } - - return true; - } - -#define Z7_HUFF_DECODER_7B_DECODE(dest, huf, get_val, move_pos, bs) \ - { \ - const unsigned pair = huf->_lens[(size_t)get_val(7)]; \ - const unsigned numBits = pair & 0x7; \ - move_pos(bs, numBits); \ - dest = pair >> 3; \ - } - - template - unsigned Decode(TBitDecoder *bitStream) const - { - const unsigned pair = _lens[(size_t)bitStream->GetValue(7)]; - bitStream->MovePos(pair & 0x7); - return pair >> 3; - } -}; - -}} - -#endif +// Compress/HuffmanDecoder.h + +#ifndef ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H +#define ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H + +#include "../../../C/CpuArch.h" +#include "../../Common/MyTypes.h" + +namespace NCompress { +namespace NHuffman { + +// const unsigned kNumTableBits_Default = 9; + +#if 0 || 0 && defined(MY_CPU_64BIT) +// for debug or optimization: +// 64-BIT limit array can be faster for some compilers. +// for debug or optimization: +#define Z7_HUFF_USE_64BIT_LIMIT +#else +// sizet value variable allows to eliminate some move operation in some compilers. +// for debug or optimization: +// #define Z7_HUFF_USE_SIZET_VALUE +#endif + +// v0 must normalized to (32 bits) : (v0 < ((UInt64)1 << 32)) + +#ifdef Z7_HUFF_USE_64BIT_LIMIT + typedef UInt64 CLimitInt; + typedef UInt64 CValueInt; + // all _limits[*] are normalized and limited by ((UInt64)1 << 32). + // we don't use (v1) in this branch + #define Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) 32 + #define Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1) \ + ((NCompress::NHuffman::CLimitInt)v0 >= (huf)->_limits[0]) + #define Z7_HUFF_GET_VAL_FOR_LIMITS(v0, v1, kNumBitsMax, kNumTableBits) (v0) + #define Z7_HUFF_GET_VAL_FOR_TABLE( v0, v1, kNumBitsMax, kNumTableBits) ((v0) >> (32 - kNumTableBits)) + #define Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1) +#else + typedef UInt32 CLimitInt; + typedef + #ifdef Z7_HUFF_USE_SIZET_VALUE + size_t + #else + UInt32 + #endif + CValueInt; + // v1 must be precalculated from v0 in this branch + // _limits[0] and (v1) are normalized and limited by (1 << kNumTableBits). + // _limits[non_0] are normalized and limited by (1 << kNumBitsMax). + #define Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) (kNumBitsMax) + #define Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1) \ + ((NCompress::NHuffman::CLimitInt)v1 >= (huf)->_limits[0]) + #define Z7_HUFF_GET_VAL_FOR_LIMITS(v0, v1, kNumBitsMax, kNumTableBits) ((v0) >> (32 - kNumBitsMax)) + #define Z7_HUFF_GET_VAL_FOR_TABLE( v0, v1, kNumBitsMax, kNumTableBits) (v1) + #define Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1) const UInt32 v1 = ((v0) >> (32 - kNumTableBits)); +#endif + + +enum enum_BuildMode +{ + k_BuildMode_Partial = 0, + k_BuildMode_Full = 1, + k_BuildMode_Full_or_Empty = 2 +}; + + +template +struct CDecoderBase +{ + CLimitInt _limits[kNumBitsMax + 2 - kNumTableBits]; + UInt32 _poses[kNumBitsMax - kNumTableBits]; // unsigned +union +{ + // if defined(MY_CPU_64BIT), we need 64-bit alignment for _symbols. + // if !defined(MY_CPU_64BIT), we need 32-bit alignment for _symbols + // but we provide alignment for _lens. + // _symbols also will be aligned, if _lens are aligned + #if defined(MY_CPU_64BIT) + UInt64 + #else + UInt32 + #endif + _pad_align[m_NumSymbols < (1u << sizeof(symType) * 8) ? 1 : -1]; + /* if symType is Byte, we use 16-bytes padding to avoid cache + bank conflict between _lens and _symbols: */ + Byte _lens[(1 << kNumTableBits) + (sizeof(symType) == 1 ? 16 : 0)]; +} _u; + symType _symbols[(1 << kNumTableBits) + m_NumSymbols - (kNumTableBits + 1)]; + + /* + Z7_FORCE_INLINE + bool IsFull() const + { + return _limits[kNumBitsMax - kNumTableBits] == + (CLimitInt)1u << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax); + } + Z7_FORCE_INLINE + bool IsEmpty() const + { + return _limits[kNumBitsMax - kNumTableBits] == 0; + } + Z7_FORCE_INLINE + bool Is_Full_or_Empty() const + { + return 0 == (_limits[kNumBitsMax - kNumTableBits] & + ~((CLimitInt)1 << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax))); + } + */ + + Z7_FORCE_INLINE + bool Build(const Byte *lens, enum_BuildMode buidMode = k_BuildMode_Partial) throw() + { + unsigned counts[kNumBitsMax + 1]; + size_t i; + for (i = 0; i <= kNumBitsMax; i++) + counts[i] = 0; + for (i = 0; i < m_NumSymbols; i++) + counts[lens[i]]++; + + UInt32 sum = 0; + for (i = 1; i <= kNumTableBits; i++) + { + sum <<= 1; + sum += counts[i]; + } + + CLimitInt startPos = (CLimitInt)sum; + _limits[0] = + #ifdef Z7_HUFF_USE_64BIT_LIMIT + startPos << (Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - kNumTableBits); + #else + startPos; + #endif + + for (i = kNumTableBits + 1; i <= kNumBitsMax; i++) + { + startPos <<= 1; + _poses[i - (kNumTableBits + 1)] = (UInt32)(startPos - sum); + const unsigned cnt = counts[i]; + counts[i] = sum; + sum += cnt; + startPos += cnt; + _limits[i - kNumTableBits] = startPos << (Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - i); + } + + _limits[kNumBitsMax + 1 - kNumTableBits] = + (CLimitInt)1 << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax); + + if (buidMode == k_BuildMode_Partial) + { + if (startPos > (1u << kNumBitsMax)) return false; + } + else + { + if (buidMode != k_BuildMode_Full && startPos == 0) return true; + if (startPos != (1u << kNumBitsMax)) return false; + } + size_t sum2 = 0; + for (i = 1; i <= kNumTableBits; i++) + { + const unsigned cnt = counts[i] << (kNumTableBits - i); + counts[i] = (unsigned)sum2 >> (kNumTableBits - i); + memset(_u._lens + sum2, (int)i, cnt); + sum2 += cnt; + } + +#ifdef MY_CPU_64BIT + symType4 + // UInt64 // for symType = UInt16 + // UInt32 // for symType = Byte +#else + UInt32 +#endif + v = 0; + for (i = 0; i < m_NumSymbols; i++, + v += + 1 + + ( (UInt32)1 << (sizeof(symType) * 8 * 1)) + // 0x00010001 // for symType = UInt16 + // 0x00000101 // for symType = Byte +#ifdef MY_CPU_64BIT + + ((symType4)1 << (sizeof(symType) * 8 * 2)) + + ((symType4)1 << (sizeof(symType) * 8 * 3)) + // 0x0001000100010001 // for symType = UInt16 + // 0x0000000001010101 // for symType = Byte +#endif + ) + { + const unsigned len = lens[i]; + if (len == 0) + continue; + const size_t offset = counts[len]; + counts[len] = (unsigned)offset + 1; + if (len >= kNumTableBits) + _symbols[offset] = (symType)v; + else + { + Byte *s2 = (Byte *)(void *)_symbols + (offset << + (kNumTableBits + sizeof(symType) / 2 - len)); + Byte *lim = s2 + ((size_t)1 << + (kNumTableBits + sizeof(symType) / 2 - len)); + if (len >= kNumTableBits - 2) + { + *(symType2 *)(void *)(s2 ) = (symType2)v; + *(symType2 *)(void *)(lim - sizeof(symType) * 2) = (symType2)v; + } + else + { +#ifdef MY_CPU_64BIT + symType4 *s = (symType4 *)(void *)s2; + do + { + s[0] = v; s[1] = v; s += 2; + } + while (s != (const symType4 *)(const void *)lim); +#else + symType2 *s = (symType2 *)(void *)s2; + do + { + s[0] = (symType2)v; s[1] = (symType2)v; s += 2; + s[0] = (symType2)v; s[1] = (symType2)v; s += 2; + } + while (s != (const symType2 *)(const void *)lim); +#endif + } + } + } + return true; + } + + +#define Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES(_numBits_, kNumBitsMax, error_op) if (_numBits_ > kNumBitsMax) { error_op } +#define Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO( _numBits_, kNumBitsMax, error_op) + + +#define Z7_HUFF_DECODE_BASE_TREE_BRANCH(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + get_val_for_limits, \ + check_op, error_op, _numBits_) \ +{ \ + const NHuffman::CValueInt _val = get_val_for_limits(v0, v1, kNumBitsMax, kNumTableBits); \ + _numBits_ = kNumTableBits + 1; \ + if ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[1]) \ + do { _numBits_++; } \ + while ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[_numBits_ - kNumTableBits]); \ + check_op(_numBits_, kNumBitsMax, error_op) \ + sym = (huf)->_symbols[(/* (UInt32) */ (_val >> ((Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - (unsigned)_numBits_)))) \ + - (huf)->_poses[_numBits_ - (kNumTableBits + 1)]]; \ +} + +/* + Z7_HUFF_DECODE_BASE_TREE_BRANCH(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + get_val_for_limits, \ + check_op, error_op, _numBits_) \ + +*/ + +#define Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + get_val_for_table, get_val_for_limits, \ + check_op, error_op, move_pos_op, after_op, bs) \ +{ \ + if (Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1)) \ + { \ + const NHuffman::CValueInt _val = get_val_for_limits(v0, v1, kNumBitsMax, kNumTableBits); \ + size_t _numBits_ = kNumTableBits + 1; \ + if ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[1]) \ + do { _numBits_++; } \ + while ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[_numBits_ - kNumTableBits]); \ + check_op(_numBits_, kNumBitsMax, error_op) \ + sym = (huf)->_symbols[(/* (UInt32) */ (_val >> ((Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - (unsigned)_numBits_)))) \ + - (huf)->_poses[_numBits_ - (kNumTableBits + 1)]]; \ + move_pos_op(bs, _numBits_); \ + } \ + else \ + { \ + const size_t _val = get_val_for_table(v0, v1, kNumBitsMax, kNumTableBits); \ + const size_t _numBits_ = (huf)->_u._lens[_val]; \ + sym = (huf)->_symbols[_val]; \ + move_pos_op(bs, _numBits_); \ + } \ + after_op \ +} + +#define Z7_HUFF_DECODE_10(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + check_op, error_op, move_pos_op, after_op, bs) \ + Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + Z7_HUFF_GET_VAL_FOR_TABLE, \ + Z7_HUFF_GET_VAL_FOR_LIMITS, \ + check_op, error_op, move_pos_op, after_op, bs) \ + + +#define Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, \ + check_op, error_op, move_pos_op, after_op, bs) \ +{ \ + Z7_HUFF_PRECALC_V1(kNumTableBits, v0, _v1_temp) \ + Z7_HUFF_DECODE_10(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, _v1_temp, \ + check_op, error_op, move_pos_op, after_op, bs) \ +} + +#if 0 || defined(Z7_HUFF_USE_64BIT_LIMIT) +// this branch uses bitStream->GetValue_InHigh32bits(). +#define Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, \ + check_op, error_op, move_pos_op) \ +{ \ + const UInt32 v0 = (bitStream)->GetValue_InHigh32bits(); \ + Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1); \ + Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + Z7_HUFF_GET_VAL_FOR_TABLE, \ + Z7_HUFF_GET_VAL_FOR_LIMITS, \ + check_op, error_op, move_pos_op, {}, bitStream) \ +} +#else +/* +this branch uses bitStream->GetValue(). +So we use SIMPLE versions for v0, v1 calculation: + v0 is normalized for kNumBitsMax + v1 is normalized for kNumTableBits +*/ +#define Z7_HUFF_GET_VAL_FOR_LIMITS_SIMPLE(v0, v1, kNumBitsMax, kNumTableBits) v0 +#define Z7_HUFF_GET_VAL_FOR_TABLE_SIMPLE( v0, v1, kNumBitsMax, kNumTableBits) v1 +#define Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, move_pos_op) \ +{ \ + const UInt32 v0 = (bitStream)->GetValue(kNumBitsMax); \ + const UInt32 v1 = v0 >> (kNumBitsMax - kNumTableBits); \ + Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \ + v0, v1, \ + Z7_HUFF_GET_VAL_FOR_TABLE_SIMPLE, \ + Z7_HUFF_GET_VAL_FOR_LIMITS_SIMPLE, \ + check_op, error_op, move_pos_op, {}, bitStream) \ +} +#endif + +#define Z7_HUFF_bitStream_MovePos(bitStream, numBits) (bitStream)->MovePos((unsigned)(numBits)) + +#define Z7_HUFF_DECODE_1(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op) \ + Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, \ + Z7_HUFF_bitStream_MovePos) + +// MovePosCheck + +#define Z7_HUFF_DECODE_2(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op) \ + Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, \ + Z7_HUFF_bitStream_MovePos) + +// MovePosCheck + +#define Z7_HUFF_DECODE_CHECK(sym, huf, kNumBitsMax, kNumTableBits, bitStream, error_op) \ + Z7_HUFF_DECODE_1( sym, huf, kNumBitsMax, kNumTableBits, bitStream, \ + Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, error_op) + + template + Z7_FORCE_INLINE + bool Decode2(TBitDecoder *bitStream, unsigned &sym) const + { + Z7_HUFF_DECODE_CHECK(sym, this, kNumBitsMax, kNumTableBits, bitStream, + { return false; } + ) + return true; + } + + template + Z7_FORCE_INLINE + bool Decode_SymCheck_MovePosCheck(TBitDecoder *bitStream, unsigned &sym) const + { + Z7_HUFF_DECODE_0(sym, this, kNumBitsMax, kNumTableBits, bitStream, + Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, + { return false; }, + { return (bitStream)->MovePosCheck; } + ) + } + + template + Z7_FORCE_INLINE + unsigned Decode(TBitDecoder *bitStream) const + { + unsigned sym; + Z7_HUFF_DECODE_CHECK(sym, this, kNumBitsMax, kNumTableBits, bitStream, + { return (unsigned)(int)(Int32)0xffffffff; } + ) + return sym; + } + + + template + Z7_FORCE_INLINE + unsigned DecodeFull(TBitDecoder *bitStream) const + { + /* + const UInt32 val = bitStream->GetValue(kNumBitsMax); + if (val < _limits[kNumTableBits]) + { + const unsigned pair = _u._lens[(size_t)(val >> (kNumBitsMax - kNumTableBits))]; + bitStream->MovePos(pair & kPairLenMask); + return pair >> kNumPairLenBits; + } + + unsigned numBits; + for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++); + + bitStream->MovePos(numBits); + return _symbols[_poses[numBits] + (unsigned) + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits))]; + */ + unsigned sym; + Z7_HUFF_DECODE_2(sym, this, kNumBitsMax, kNumTableBits, bitStream, + Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {} + ) + return sym; + } +}; + + +template +struct CDecoder: public CDecoderBase + {}; + +template +struct CDecoder256: public CDecoderBase + {}; + + +template +class CDecoder7b +{ +public: + Byte _lens[1 << 7]; + + bool Build(const Byte *lens, bool full) throw() + { + const unsigned kNumBitsMax = 7; + + unsigned counts[kNumBitsMax + 1]; + unsigned _poses[kNumBitsMax + 1]; + unsigned _limits[kNumBitsMax + 1]; + unsigned i; + for (i = 0; i <= kNumBitsMax; i++) + counts[i] = 0; + for (i = 0; i < numSymbols; i++) + counts[lens[i]]++; + + _limits[0] = 0; + const unsigned kMaxValue = 1u << kNumBitsMax; + unsigned startPos = 0; + unsigned sum = 0; + + for (i = 1; i <= kNumBitsMax; i++) + { + const unsigned cnt = counts[i]; + startPos += cnt << (kNumBitsMax - i); + _limits[i] = startPos; + counts[i] = sum; + _poses[i] = sum; + sum += cnt; + } + + counts[0] = sum; + _poses[0] = sum; + + if (full) + { + if (startPos != kMaxValue) + return false; + } + else + { + if (startPos > kMaxValue) + return false; + } + + + for (i = 0; i < numSymbols; i++) + { + const unsigned len = lens[i]; + if (len == 0) + continue; + const unsigned offset = counts[len]++; + { + Byte *dest = _lens + _limits[(size_t)len - 1] + + ((offset - _poses[len]) << (kNumBitsMax - len)); + const unsigned num = (unsigned)1 << (kNumBitsMax - len); + const unsigned val = (i << 3) + len; + for (unsigned k = 0; k < num; k++) + dest[k] = (Byte)val; + } + } + + if (!full) + { + const unsigned limit = _limits[kNumBitsMax]; + const unsigned num = ((unsigned)1 << kNumBitsMax) - limit; + Byte *dest = _lens + limit; + for (unsigned k = 0; k < num; k++) + dest[k] = (Byte) + // (0x1f << 3); + ((0x1f << 3) + 0x7); + } + + return true; + } + +#define Z7_HUFF_DECODER_7B_DECODE(dest, huf, get_val, move_pos, bs) \ + { \ + const unsigned pair = huf->_lens[(size_t)get_val(7)]; \ + const unsigned numBits = pair & 0x7; \ + move_pos(bs, numBits); \ + dest = pair >> 3; \ + } + + template + unsigned Decode(TBitDecoder *bitStream) const + { + const unsigned pair = _lens[(size_t)bitStream->GetValue(7)]; + bitStream->MovePos(pair & 0x7); + return pair >> 3; + } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/ImplodeDecoder.cpp b/CPP/7zip/Compress/ImplodeDecoder.cpp index fc720f708..bcf5d4f6c 100644 --- a/CPP/7zip/Compress/ImplodeDecoder.cpp +++ b/CPP/7zip/Compress/ImplodeDecoder.cpp @@ -1,250 +1,250 @@ -// ImplodeDecoder.cpp - -#include "StdAfx.h" - -#include "../../Common/Defs.h" - -#include "ImplodeDecoder.h" - -namespace NCompress { -namespace NImplode { -namespace NDecoder { - -bool CHuffmanDecoder::Build(const Byte *lens, unsigned numSymbols) throw() -{ - unsigned counts[kNumHuffmanBits + 1]; - unsigned i; - for (i = 0; i <= kNumHuffmanBits; i++) - counts[i] = 0; - for (i = 0; i < numSymbols; i++) - counts[lens[i]]++; - - const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits; - // _limits[0] = kMaxValue; - UInt32 startPos = kMaxValue; - unsigned sum = 0; - - for (i = 1; i <= kNumHuffmanBits; i++) - { - const unsigned cnt = counts[i]; - const UInt32 range = (UInt32)cnt << (kNumHuffmanBits - i); - if (startPos < range) - return false; - startPos -= range; - _limits[i] = startPos; - _poses[i] = sum; - sum += cnt; - counts[i] = sum; - } - // counts[0] += sum; - if (startPos != 0) - return false; - for (i = 0; i < numSymbols; i++) - { - const unsigned len = lens[i]; - if (len != 0) - _symbols[--counts[len]] = (Byte)i; - } - return true; -} - - -unsigned CHuffmanDecoder::Decode(CInBit *inStream) const throw() -{ - const UInt32 val = inStream->GetValue(kNumHuffmanBits); - size_t numBits; - for (numBits = 1; val < _limits[numBits]; numBits++); - const unsigned sym = _symbols[_poses[numBits] - + (unsigned)((val - _limits[numBits]) >> (kNumHuffmanBits - numBits))]; - inStream->MovePos(numBits); - return sym; -} - - - -static const unsigned kNumLenDirectBits = 8; - -static const unsigned kNumDistDirectBitsSmall = 6; -static const unsigned kNumDistDirectBitsBig = 7; - -static const unsigned kLitTableSize = (1 << 8); -static const unsigned kDistTableSize = 64; -static const unsigned kLenTableSize = 64; - -static const UInt32 kHistorySize = (1 << kNumDistDirectBitsBig) * kDistTableSize; // 8 KB - - -CCoder::CCoder(): - _flags(0), - _fullStreamMode(false) -{} - - -bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols) -{ - Byte levels[kMaxHuffTableSize]; - unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1; - unsigned index = 0; - do - { - const unsigned b = (unsigned)_inBitStream.ReadAlignedByte(); - const unsigned level = (b & 0xF) + 1; - const unsigned rep = ((unsigned)b >> 4) + 1; - if (index + rep > numSymbols) - return false; - for (unsigned j = 0; j < rep; j++) - levels[index++] = (Byte)level; - } - while (--numRecords); - - if (index != numSymbols) - return false; - return decoder.Build(levels, numSymbols); -} - - -HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - if (!_inBitStream.Create(1 << 18)) - return E_OUTOFMEMORY; - if (!_outWindowStream.Create(kHistorySize << 1)) // 16 KB - return E_OUTOFMEMORY; - if (!outSize) - return E_INVALIDARG; - - _outWindowStream.SetStream(outStream); - _outWindowStream.Init(false); - _inBitStream.SetStream(inStream); - _inBitStream.Init(); - - const unsigned numDistDirectBits = (_flags & 2) ? - kNumDistDirectBitsBig: - kNumDistDirectBitsSmall; - const bool literalsOn = ((_flags & 4) != 0); - const UInt32 minMatchLen = (literalsOn ? 3 : 2); - - if (literalsOn) - if (!BuildHuff(_litDecoder, kLitTableSize)) - return S_FALSE; - if (!BuildHuff(_lenDecoder, kLenTableSize)) - return S_FALSE; - if (!BuildHuff(_distDecoder, kDistTableSize)) - return S_FALSE; - - UInt64 prevProgress = 0; - bool moreOut = false; - UInt64 pos = 0, unPackSize = *outSize; - - while (pos < unPackSize) - { - if (pos - prevProgress >= (1u << 18) && progress) - { - prevProgress = pos; - const UInt64 packSize = _inBitStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &pos)) - } - - if (_inBitStream.ReadBits(1) != 0) - { - Byte b; - if (literalsOn) - { - const unsigned sym = _litDecoder.Decode(&_inBitStream); - // if (sym >= kLitTableSize) break; - b = (Byte)sym; - } - else - b = (Byte)_inBitStream.ReadBits(8); - _outWindowStream.PutByte(b); - pos++; - } - else - { - const UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits); - UInt32 dist = (UInt32)_distDecoder.Decode(&_inBitStream); - // if (dist >= kDistTableSize) break; - dist = (dist << numDistDirectBits) + lowDistBits; - unsigned len = _lenDecoder.Decode(&_inBitStream); - // if (len >= kLenTableSize) break; - if (len == kLenTableSize - 1) - len += _inBitStream.ReadBits(kNumLenDirectBits); - len += minMatchLen; - { - const UInt64 limit = unPackSize - pos; - // limit != 0 - if (len > limit) - { - moreOut = true; - len = (UInt32)limit; - } - } - do - { - // len != 0 - if (dist < pos) - { - _outWindowStream.CopyBlock(dist, len); - pos += len; - break; - } - _outWindowStream.PutByte(0); - pos++; - } - while (--len); - } - } - - HRESULT res = _outWindowStream.Flush(); - - if (res == S_OK) - { - if (_fullStreamMode) - { - if (moreOut) - res = S_FALSE; - if (inSize && *inSize != _inBitStream.GetProcessedSize()) - res = S_FALSE; - } - if (pos != unPackSize) - res = S_FALSE; - } - - return res; -} - - -Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - // catch(const CInBufferException &e) { return e.ErrorCode; } - // catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(const CSystemException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - -Z7_COM7F_IMF(CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - if (size == 0) - return E_NOTIMPL; - _flags = data[0]; - return S_OK; -} - - -Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode)) -{ - _fullStreamMode = (finishMode != 0); - return S_OK; -} - - -Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inBitStream.GetProcessedSize(); - return S_OK; -} - -}}} +// ImplodeDecoder.cpp + +#include "StdAfx.h" + +#include "../../Common/Defs.h" + +#include "ImplodeDecoder.h" + +namespace NCompress { +namespace NImplode { +namespace NDecoder { + +bool CHuffmanDecoder::Build(const Byte *lens, unsigned numSymbols) throw() +{ + unsigned counts[kNumHuffmanBits + 1]; + unsigned i; + for (i = 0; i <= kNumHuffmanBits; i++) + counts[i] = 0; + for (i = 0; i < numSymbols; i++) + counts[lens[i]]++; + + const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits; + // _limits[0] = kMaxValue; + UInt32 startPos = kMaxValue; + unsigned sum = 0; + + for (i = 1; i <= kNumHuffmanBits; i++) + { + const unsigned cnt = counts[i]; + const UInt32 range = (UInt32)cnt << (kNumHuffmanBits - i); + if (startPos < range) + return false; + startPos -= range; + _limits[i] = startPos; + _poses[i] = sum; + sum += cnt; + counts[i] = sum; + } + // counts[0] += sum; + if (startPos != 0) + return false; + for (i = 0; i < numSymbols; i++) + { + const unsigned len = lens[i]; + if (len != 0) + _symbols[--counts[len]] = (Byte)i; + } + return true; +} + + +unsigned CHuffmanDecoder::Decode(CInBit *inStream) const throw() +{ + const UInt32 val = inStream->GetValue(kNumHuffmanBits); + size_t numBits; + for (numBits = 1; val < _limits[numBits]; numBits++); + const unsigned sym = _symbols[_poses[numBits] + + (unsigned)((val - _limits[numBits]) >> (kNumHuffmanBits - numBits))]; + inStream->MovePos(numBits); + return sym; +} + + + +static const unsigned kNumLenDirectBits = 8; + +static const unsigned kNumDistDirectBitsSmall = 6; +static const unsigned kNumDistDirectBitsBig = 7; + +static const unsigned kLitTableSize = (1 << 8); +static const unsigned kDistTableSize = 64; +static const unsigned kLenTableSize = 64; + +static const UInt32 kHistorySize = (1 << kNumDistDirectBitsBig) * kDistTableSize; // 8 KB + + +CCoder::CCoder(): + _flags(0), + _fullStreamMode(false) +{} + + +bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols) +{ + Byte levels[kMaxHuffTableSize]; + unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1; + unsigned index = 0; + do + { + const unsigned b = (unsigned)_inBitStream.ReadAlignedByte(); + const unsigned level = (b & 0xF) + 1; + const unsigned rep = ((unsigned)b >> 4) + 1; + if (index + rep > numSymbols) + return false; + for (unsigned j = 0; j < rep; j++) + levels[index++] = (Byte)level; + } + while (--numRecords); + + if (index != numSymbols) + return false; + return decoder.Build(levels, numSymbols); +} + + +HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + if (!_inBitStream.Create(1 << 18)) + return E_OUTOFMEMORY; + if (!_outWindowStream.Create(kHistorySize << 1)) // 16 KB + return E_OUTOFMEMORY; + if (!outSize) + return E_INVALIDARG; + + _outWindowStream.SetStream(outStream); + _outWindowStream.Init(false); + _inBitStream.SetStream(inStream); + _inBitStream.Init(); + + const unsigned numDistDirectBits = (_flags & 2) ? + kNumDistDirectBitsBig: + kNumDistDirectBitsSmall; + const bool literalsOn = ((_flags & 4) != 0); + const UInt32 minMatchLen = (literalsOn ? 3 : 2); + + if (literalsOn) + if (!BuildHuff(_litDecoder, kLitTableSize)) + return S_FALSE; + if (!BuildHuff(_lenDecoder, kLenTableSize)) + return S_FALSE; + if (!BuildHuff(_distDecoder, kDistTableSize)) + return S_FALSE; + + UInt64 prevProgress = 0; + bool moreOut = false; + UInt64 pos = 0, unPackSize = *outSize; + + while (pos < unPackSize) + { + if (pos - prevProgress >= (1u << 18) && progress) + { + prevProgress = pos; + const UInt64 packSize = _inBitStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)) + } + + if (_inBitStream.ReadBits(1) != 0) + { + Byte b; + if (literalsOn) + { + const unsigned sym = _litDecoder.Decode(&_inBitStream); + // if (sym >= kLitTableSize) break; + b = (Byte)sym; + } + else + b = (Byte)_inBitStream.ReadBits(8); + _outWindowStream.PutByte(b); + pos++; + } + else + { + const UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits); + UInt32 dist = (UInt32)_distDecoder.Decode(&_inBitStream); + // if (dist >= kDistTableSize) break; + dist = (dist << numDistDirectBits) + lowDistBits; + unsigned len = _lenDecoder.Decode(&_inBitStream); + // if (len >= kLenTableSize) break; + if (len == kLenTableSize - 1) + len += _inBitStream.ReadBits(kNumLenDirectBits); + len += minMatchLen; + { + const UInt64 limit = unPackSize - pos; + // limit != 0 + if (len > limit) + { + moreOut = true; + len = (UInt32)limit; + } + } + do + { + // len != 0 + if (dist < pos) + { + _outWindowStream.CopyBlock(dist, len); + pos += len; + break; + } + _outWindowStream.PutByte(0); + pos++; + } + while (--len); + } + } + + HRESULT res = _outWindowStream.Flush(); + + if (res == S_OK) + { + if (_fullStreamMode) + { + if (moreOut) + res = S_FALSE; + if (inSize && *inSize != _inBitStream.GetProcessedSize()) + res = S_FALSE; + } + if (pos != unPackSize) + res = S_FALSE; + } + + return res; +} + + +Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + // catch(const CInBufferException &e) { return e.ErrorCode; } + // catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + +Z7_COM7F_IMF(CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + if (size == 0) + return E_NOTIMPL; + _flags = data[0]; + return S_OK; +} + + +Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode)) +{ + _fullStreamMode = (finishMode != 0); + return S_OK; +} + + +Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inBitStream.GetProcessedSize(); + return S_OK; +} + +}}} diff --git a/CPP/7zip/Compress/ImplodeDecoder.h b/CPP/7zip/Compress/ImplodeDecoder.h index d3c7f5d45..603251500 100644 --- a/CPP/7zip/Compress/ImplodeDecoder.h +++ b/CPP/7zip/Compress/ImplodeDecoder.h @@ -1,61 +1,61 @@ -// ImplodeDecoder.h - -#ifndef ZIP7_INC_COMPRESS_IMPLODE_DECODER_H -#define ZIP7_INC_COMPRESS_IMPLODE_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitlDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NImplode { -namespace NDecoder { - -typedef NBitl::CDecoder CInBit; - -const unsigned kNumHuffmanBits = 16; -const unsigned kMaxHuffTableSize = 1 << 8; - -class CHuffmanDecoder -{ - UInt32 _limits[kNumHuffmanBits + 1]; - UInt32 _poses[kNumHuffmanBits + 1]; - Byte _symbols[kMaxHuffTableSize]; -public: - bool Build(const Byte *lens, unsigned numSymbols) throw(); - unsigned Decode(CInBit *inStream) const throw(); -}; - - -Z7_CLASS_IMP_NOQIB_4( - CCoder - , ICompressCoder - , ICompressSetDecoderProperties2 - , ICompressSetFinishMode - , ICompressGetInStreamProcessedSize -) - Byte _flags; - bool _fullStreamMode; - - CLzOutWindow _outWindowStream; - CInBit _inBitStream; - - CHuffmanDecoder _litDecoder; - CHuffmanDecoder _lenDecoder; - CHuffmanDecoder _distDecoder; - - bool BuildHuff(CHuffmanDecoder &table, unsigned numSymbols); - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -public: - CCoder(); -}; - -}}} - -#endif +// ImplodeDecoder.h + +#ifndef ZIP7_INC_COMPRESS_IMPLODE_DECODER_H +#define ZIP7_INC_COMPRESS_IMPLODE_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitlDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NImplode { +namespace NDecoder { + +typedef NBitl::CDecoder CInBit; + +const unsigned kNumHuffmanBits = 16; +const unsigned kMaxHuffTableSize = 1 << 8; + +class CHuffmanDecoder +{ + UInt32 _limits[kNumHuffmanBits + 1]; + UInt32 _poses[kNumHuffmanBits + 1]; + Byte _symbols[kMaxHuffTableSize]; +public: + bool Build(const Byte *lens, unsigned numSymbols) throw(); + unsigned Decode(CInBit *inStream) const throw(); +}; + + +Z7_CLASS_IMP_NOQIB_4( + CCoder + , ICompressCoder + , ICompressSetDecoderProperties2 + , ICompressSetFinishMode + , ICompressGetInStreamProcessedSize +) + Byte _flags; + bool _fullStreamMode; + + CLzOutWindow _outWindowStream; + CInBit _inBitStream; + + CHuffmanDecoder _litDecoder; + CHuffmanDecoder _lenDecoder; + CHuffmanDecoder _distDecoder; + + bool BuildHuff(CHuffmanDecoder &table, unsigned numSymbols); + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); +public: + CCoder(); +}; + +}}} + +#endif diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp index c0af85f7a..7d31bb941 100644 --- a/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp +++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp @@ -1,3 +1,3 @@ -// ImplodeHuffmanDecoder.cpp - -#include "StdAfx.h" +// ImplodeHuffmanDecoder.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.h b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h index c7024a29d..dcf8ac6be 100644 --- a/CPP/7zip/Compress/ImplodeHuffmanDecoder.h +++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h @@ -1,6 +1,6 @@ -// ImplodeHuffmanDecoder.h - -#ifndef ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H -#define ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H - -#endif +// ImplodeHuffmanDecoder.h + +#ifndef ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H +#define ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H + +#endif diff --git a/CPP/7zip/Compress/LzOutWindow.cpp b/CPP/7zip/Compress/LzOutWindow.cpp index 213e0a69c..aae02eb85 100644 --- a/CPP/7zip/Compress/LzOutWindow.cpp +++ b/CPP/7zip/Compress/LzOutWindow.cpp @@ -1,14 +1,14 @@ -// LzOutWindow.cpp - -#include "StdAfx.h" - -#include "LzOutWindow.h" - -void CLzOutWindow::Init(bool solid) throw() -{ - if (!solid) - COutBuffer::Init(); - #ifdef Z7_NO_EXCEPTIONS - ErrorCode = S_OK; - #endif -} +// LzOutWindow.cpp + +#include "StdAfx.h" + +#include "LzOutWindow.h" + +void CLzOutWindow::Init(bool solid) throw() +{ + if (!solid) + COutBuffer::Init(); + #ifdef Z7_NO_EXCEPTIONS + ErrorCode = S_OK; + #endif +} diff --git a/CPP/7zip/Compress/LzOutWindow.h b/CPP/7zip/Compress/LzOutWindow.h index 6be151583..599b124e9 100644 --- a/CPP/7zip/Compress/LzOutWindow.h +++ b/CPP/7zip/Compress/LzOutWindow.h @@ -1,102 +1,102 @@ -// LzOutWindow.h - -#ifndef ZIP7_INC_LZ_OUT_WINDOW_H -#define ZIP7_INC_LZ_OUT_WINDOW_H - -#include "../Common/OutBuffer.h" - -#ifndef Z7_NO_EXCEPTIONS -typedef COutBufferException CLzOutWindowException; -#endif - -class CLzOutWindow: public COutBuffer -{ -public: - void Init(bool solid = false) throw(); - - // distance >= 0, len > 0, - bool CopyBlock(UInt32 distance, UInt32 len) - { - UInt32 pos = _pos - distance - 1; - if (distance >= _pos) - { - if (!_overDict || distance >= _bufSize) - return false; - pos += _bufSize; - } - if (_limitPos - _pos > len && _bufSize - pos > len) - { - const Byte *src = _buf + pos; - Byte *dest = _buf + _pos; - _pos += len; - do - *dest++ = *src++; - while (--len != 0); - } - else do - { - UInt32 pos2; - if (pos == _bufSize) - pos = 0; - pos2 = _pos; - _buf[pos2++] = _buf[pos++]; - _pos = pos2; - if (pos2 == _limitPos) - FlushWithCheck(); - } - while (--len != 0); - return true; - } - - void PutByte(Byte b) - { - UInt32 pos = _pos; - _buf[pos++] = b; - _pos = pos; - if (pos == _limitPos) - FlushWithCheck(); - } - - void PutBytes(const Byte *data, UInt32 size) - { - if (size == 0) - return; - UInt32 pos = _pos; - Byte *buf = _buf; - buf[pos++] = *data++; - size--; - for (;;) - { - UInt32 limitPos = _limitPos; - UInt32 rem = limitPos - pos; - if (rem == 0) - { - _pos = pos; - FlushWithCheck(); - pos = _pos; - continue; - } - - if (size == 0) - break; - - if (rem > size) - rem = size; - size -= rem; - do - buf[pos++] = *data++; - while (--rem); - } - _pos = pos; - } - - Byte GetByte(UInt32 distance) const - { - UInt32 pos = _pos - distance - 1; - if (distance >= _pos) - pos += _bufSize; - return _buf[pos]; - } -}; - -#endif +// LzOutWindow.h + +#ifndef ZIP7_INC_LZ_OUT_WINDOW_H +#define ZIP7_INC_LZ_OUT_WINDOW_H + +#include "../Common/OutBuffer.h" + +#ifndef Z7_NO_EXCEPTIONS +typedef COutBufferException CLzOutWindowException; +#endif + +class CLzOutWindow: public COutBuffer +{ +public: + void Init(bool solid = false) throw(); + + // distance >= 0, len > 0, + bool CopyBlock(UInt32 distance, UInt32 len) + { + UInt32 pos = _pos - distance - 1; + if (distance >= _pos) + { + if (!_overDict || distance >= _bufSize) + return false; + pos += _bufSize; + } + if (_limitPos - _pos > len && _bufSize - pos > len) + { + const Byte *src = _buf + pos; + Byte *dest = _buf + _pos; + _pos += len; + do + *dest++ = *src++; + while (--len != 0); + } + else do + { + UInt32 pos2; + if (pos == _bufSize) + pos = 0; + pos2 = _pos; + _buf[pos2++] = _buf[pos++]; + _pos = pos2; + if (pos2 == _limitPos) + FlushWithCheck(); + } + while (--len != 0); + return true; + } + + void PutByte(Byte b) + { + UInt32 pos = _pos; + _buf[pos++] = b; + _pos = pos; + if (pos == _limitPos) + FlushWithCheck(); + } + + void PutBytes(const Byte *data, UInt32 size) + { + if (size == 0) + return; + UInt32 pos = _pos; + Byte *buf = _buf; + buf[pos++] = *data++; + size--; + for (;;) + { + UInt32 limitPos = _limitPos; + UInt32 rem = limitPos - pos; + if (rem == 0) + { + _pos = pos; + FlushWithCheck(); + pos = _pos; + continue; + } + + if (size == 0) + break; + + if (rem > size) + rem = size; + size -= rem; + do + buf[pos++] = *data++; + while (--rem); + } + _pos = pos; + } + + Byte GetByte(UInt32 distance) const + { + UInt32 pos = _pos - distance - 1; + if (distance >= _pos) + pos += _bufSize; + return _buf[pos]; + } +}; + +#endif diff --git a/CPP/7zip/Compress/LzfseDecoder.cpp b/CPP/7zip/Compress/LzfseDecoder.cpp index 1a3919879..b224a3398 100644 --- a/CPP/7zip/Compress/LzfseDecoder.cpp +++ b/CPP/7zip/Compress/LzfseDecoder.cpp @@ -1,950 +1,950 @@ -// LzfseDecoder.cpp - -/* -This code implements LZFSE data decompressing. -The code from "LZFSE compression library" was used. - -2018 : Igor Pavlov : BSD 3-clause License : the code in this file -2015-2017 : Apple Inc : BSD 3-clause License : original "LZFSE compression library" code - -The code in the "LZFSE compression library" is licensed under the "BSD 3-clause License": ----- -Copyright (c) 2015-2016, Apple Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----- -*/ - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif - -#include "../../../C/CpuArch.h" - -#include "LzfseDecoder.h" - -namespace NCompress { -namespace NLzfse { - -static const Byte kSignature_LZFSE_V1 = 0x31; // '1' -static const Byte kSignature_LZFSE_V2 = 0x32; // '2' - - -HRESULT CDecoder::GetUInt32(UInt32 &val) -{ - Byte b[4]; - for (unsigned i = 0; i < 4; i++) - if (!m_InStream.ReadByte(b[i])) - return S_FALSE; - val = GetUi32(b); - return S_OK; -} - - - -HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize) -{ - PRF(printf("\nUncompressed %7u\n", unpackSize)); - - const unsigned kBufSize = 1 << 8; - Byte buf[kBufSize]; - for (;;) - { - if (unpackSize == 0) - return S_OK; - UInt32 cur = unpackSize; - if (cur > kBufSize) - cur = kBufSize; - const UInt32 cur2 = (UInt32)m_InStream.ReadBytes(buf, cur); - m_OutWindowStream.PutBytes(buf, cur2); - if (cur != cur2) - return S_FALSE; - } -} - - - -HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize) -{ - PRF(printf("\nLZVN 0x%07x 0x%07x\n", unpackSize, packSize)); - - UInt32 D = 0; - - for (;;) - { - if (packSize == 0) - return S_FALSE; - Byte b; - if (!m_InStream.ReadByte(b)) - return S_FALSE; - packSize--; - - UInt32 M; - UInt32 L; - - if (b >= 0xE0) - { - /* - large L - 11100000 LLLLLLLL - small L - 1110LLLL - - large Rep - 11110000 MMMMMMMM - small Rep - 1111MMMM - */ - - M = b & 0xF; - if (M == 0) - { - if (packSize == 0) - return S_FALSE; - Byte b1; - if (!m_InStream.ReadByte(b1)) - return S_FALSE; - packSize--; - M = (UInt32)b1 + 16; - } - L = 0; - if ((b & 0x10) == 0) - { - // Literals only - L = M; - M = 0; - } - } - - // ERROR codes - else if ((b & 0xF0) == 0x70) // 0111xxxx - return S_FALSE; - else if ((b & 0xF0) == 0xD0) // 1101xxxx - return S_FALSE; - - else - { - if ((b & 0xE0) == 0xA0) - { - // medium - 101LLMMM DDDDDDMM DDDDDDDD - if (packSize < 2) - return S_FALSE; - Byte b1; - if (!m_InStream.ReadByte(b1)) - return S_FALSE; - packSize--; - - Byte b2; - if (!m_InStream.ReadByte(b2)) - return S_FALSE; - packSize--; - L = (((UInt32)b >> 3) & 3); - M = (((UInt32)b & 7) << 2) + (b1 & 3); - D = ((UInt32)b1 >> 2) + ((UInt32)b2 << 6); - } - else - { - L = (UInt32)b >> 6; - M = ((UInt32)b >> 3) & 7; - if ((b & 0x7) == 6) - { - // REP - LLMMM110 - if (L == 0) - { - // spec - if (M == 0) - break; // EOS - if (M <= 2) - continue; // NOP - return S_FALSE; // UNDEFINED - } - } - else - { - if (packSize == 0) - return S_FALSE; - Byte b1; - if (!m_InStream.ReadByte(b1)) - return S_FALSE; - packSize--; - - // large - LLMMM111 DDDDDDDD DDDDDDDD - // small - LLMMMDDD DDDDDDDD - D = ((UInt32)b & 7); - if (D == 7) - { - if (packSize == 0) - return S_FALSE; - Byte b2; - if (!m_InStream.ReadByte(b2)) - return S_FALSE; - packSize--; - D = b2; - } - D = (D << 8) + b1; - } - } - - M += 3; - } - { - for (unsigned i = 0; i < L; i++) - { - if (packSize == 0 || unpackSize == 0) - return S_FALSE; - Byte b1; - if (!m_InStream.ReadByte(b1)) - return S_FALSE; - packSize--; - m_OutWindowStream.PutByte(b1); - unpackSize--; - } - } - - if (M != 0) - { - if (unpackSize == 0 || D == 0) - return S_FALSE; - unsigned cur = M; - if (cur > unpackSize) - cur = (unsigned)unpackSize; - if (!m_OutWindowStream.CopyBlock(D - 1, cur)) - return S_FALSE; - unpackSize -= cur; - if (cur != M) - return S_FALSE; - } - } - - if (unpackSize != 0) - return S_FALSE; - - // LZVN encoder writes 7 additional zero bytes - if (packSize < 7) - return S_FALSE; - for (unsigned i = 0; i < 7; i++) - { - Byte b; - if (!m_InStream.ReadByte(b)) - return S_FALSE; - if (b != 0) - return S_FALSE; - } - packSize -= 7; - if (packSize) - { - PRF(printf("packSize after unused = %u\n", packSize)); - // if (packSize <= 0x100) { Byte buf[0x100]; m_InStream.ReadBytes(buf, packSize); } - /* Lzvn block that is used in HFS can contain junk data - (at least 256 bytes) after payload data. Why? - We ignore that junk data, if it's HFS (LzvnMode) mode. */ - if (!LzvnMode) - return S_FALSE; - } - return S_OK; -} - - - -// ---------- LZFSE ---------- - -#define MATCHES_PER_BLOCK 10000 -#define LITERALS_PER_BLOCK (4 * MATCHES_PER_BLOCK) - -#define NUM_L_SYMBOLS 20 -#define NUM_M_SYMBOLS 20 -#define NUM_D_SYMBOLS 64 -#define NUM_LIT_SYMBOLS 256 - -#define NUM_SYMBOLS ( \ - NUM_L_SYMBOLS + \ - NUM_M_SYMBOLS + \ - NUM_D_SYMBOLS + \ - NUM_LIT_SYMBOLS) - -#define NUM_L_STATES (1 << 6) -#define NUM_M_STATES (1 << 6) -#define NUM_D_STATES (1 << 8) -#define NUM_LIT_STATES (1 << 10) - - -typedef UInt32 CFseState; - - -static UInt32 SumFreqs(const UInt16 *freqs, unsigned num) -{ - UInt32 sum = 0; - for (unsigned i = 0; i < num; i++) - sum += (UInt32)freqs[i]; - return sum; -} - - -static Z7_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask) -{ - for (unsigned i = 0;;) - { - if (val & mask) - return i; - i++; - mask >>= 1; - } -} - - -static Z7_FORCE_INLINE void InitLitTable(const UInt16 *freqs, UInt32 *table) -{ - for (unsigned i = 0; i < NUM_LIT_SYMBOLS; i++) - { - unsigned f = freqs[i]; - if (f == 0) - continue; - - // 0 < f <= numStates - // 0 <= k <= numStatesLog - // numStates <= (f<> k) - f; - - /* - CEntry - { - Byte k; - Byte symbol; - UInt16 delta; - }; - */ - - UInt32 e = ((UInt32)i << 8) + k; - k += 16; - UInt32 d = e + ((UInt32)f << k) - ((UInt32)NUM_LIT_STATES << 16); - UInt32 step = (UInt32)1 << k; - - unsigned j = 0; - do - { - *table++ = d; - d += step; - } - while (++j < j0); - - e--; - step >>= 1; - - for (j = j0; j < f; j++) - { - *table++ = e; - e += step; - } - } -} - - -typedef struct -{ - Byte totalBits; - Byte extraBits; - UInt16 delta; - UInt32 vbase; -} CExtraEntry; - - -static void InitExtraDecoderTable(unsigned numStates, - unsigned numSymbols, - const UInt16 *freqs, - const Byte *vbits, - CExtraEntry *table) -{ - UInt32 vbase = 0; - - for (unsigned i = 0; i < numSymbols; i++) - { - unsigned f = freqs[i]; - unsigned extraBits = vbits[i]; - - if (f != 0) - { - unsigned k = CountZeroBits(f, numStates); - unsigned j0 = ((2 * numStates) >> k) - f; - - unsigned j = 0; - do - { - CExtraEntry *e = table++; - e->totalBits = (Byte)(k + extraBits); - e->extraBits = (Byte)extraBits; - e->delta = (UInt16)(((f + j) << k) - numStates); - e->vbase = vbase; - } - while (++j < j0); - - f -= j0; - k--; - - for (j = 0; j < f; j++) - { - CExtraEntry *e = table++; - e->totalBits = (Byte)(k + extraBits); - e->extraBits = (Byte)extraBits; - e->delta = (UInt16)(j << k); - e->vbase = vbase; - } - } - - vbase += ((UInt32)1 << extraBits); - } -} - - -static const Byte k_L_extra[NUM_L_SYMBOLS] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 8 -}; - -static const Byte k_M_extra[NUM_M_SYMBOLS] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11 -}; - -static const Byte k_D_extra[NUM_D_SYMBOLS] = -{ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, - 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, - 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15 -}; - - - -// ---------- CBitStream ---------- - -typedef struct -{ - UInt32 accum; - unsigned numBits; // [0, 31] - Number of valid bits in (accum), other bits are 0 -} CBitStream; - - -static Z7_FORCE_INLINE int FseInStream_Init(CBitStream *s, - int n, // [-7, 0], (-n == number_of_unused_bits) in last byte - const Byte **pbuf) -{ - *pbuf -= 4; - s->accum = GetUi32(*pbuf); - if (n) - { - s->numBits = (unsigned)(n + 32); - if ((s->accum >> s->numBits) != 0) - return -1; // ERROR, encoder should have zeroed the upper bits - } - else - { - *pbuf += 1; - s->accum >>= 8; - s->numBits = 24; - } - return 0; // OK -} - - -// 0 <= numBits < 32 -#define mask31(x, numBits) ((x) & (((UInt32)1 << (numBits)) - 1)) - -#define FseInStream_FLUSH \ - { const unsigned nbits = (31 - in.numBits) & (unsigned)-8; \ - if (nbits) { \ - buf -= (nbits >> 3); \ - if (buf < buf_check) return S_FALSE; \ - UInt32 v = GetUi32(buf); \ - in.accum = (in.accum << nbits) | mask31(v, nbits); \ - in.numBits += nbits; }} - - - -static Z7_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits) -{ - s->numBits -= numBits; - const UInt32 v = s->accum >> s->numBits; - s->accum = mask31(s->accum, s->numBits); - return v; -} - - -#define DECODE_LIT(dest, pstate) { \ - UInt32 e = lit_decoder[pstate]; \ - pstate = (CFseState)((e >> 16) + BitStream_Pull(&in, e & 0xff)); \ - dest = (Byte)(e >> 8); } - - -static Z7_FORCE_INLINE UInt32 FseDecodeExtra(CFseState *pstate, - const CExtraEntry *table, - CBitStream *s) -{ - const CExtraEntry *e = &table[*pstate]; - UInt32 v = BitStream_Pull(s, e->totalBits); - unsigned extraBits = e->extraBits; - *pstate = (CFseState)(e->delta + (v >> extraBits)); - return e->vbase + mask31(v, extraBits); -} - - -#define freqs_L (freqs) -#define freqs_M (freqs_L + NUM_L_SYMBOLS) -#define freqs_D (freqs_M + NUM_M_SYMBOLS) -#define freqs_LIT (freqs_D + NUM_D_SYMBOLS) - -#define GET_BITS_64(v, offset, num, dest) dest = (UInt32) ((v >> (offset)) & ((1 << (num)) - 1)); -#define GET_BITS_64_Int32(v, offset, num, dest) dest = (Int32)((v >> (offset)) & ((1 << (num)) - 1)); -#define GET_BITS_32(v, offset, num, dest) dest = (CFseState)((v >> (offset)) & ((1 << (num)) - 1)); - - -HRESULT CDecoder::DecodeLzfse(UInt32 unpackSize, Byte version) -{ - PRF(printf("\nLZFSE-%d %7u", version - '0', unpackSize)); - - UInt32 numLiterals; - UInt32 litPayloadSize; - Int32 literal_bits; - - UInt32 lit_state_0; - UInt32 lit_state_1; - UInt32 lit_state_2; - UInt32 lit_state_3; - - UInt32 numMatches; - UInt32 lmdPayloadSize; - Int32 lmd_bits; - - CFseState l_state; - CFseState m_state; - CFseState d_state; - - UInt16 freqs[NUM_SYMBOLS]; - - if (version == kSignature_LZFSE_V1) - { - return E_NOTIMPL; - // we need examples to test LZFSE-V1 code - /* - const unsigned k_v1_SubHeaderSize = 7 * 4 + 7 * 2; - const unsigned k_v1_HeaderSize = k_v1_SubHeaderSize + NUM_SYMBOLS * 2; - _buffer.AllocAtLeast(k_v1_HeaderSize); - if (m_InStream.ReadBytes(_buffer, k_v1_HeaderSize) != k_v1_HeaderSize) - return S_FALSE; - - const Byte *buf = _buffer; - #define GET_32(offs, dest) dest = GetUi32(buf + offs) - #define GET_16(offs, dest) dest = GetUi16(buf + offs) - - UInt32 payload_bytes; - GET_32(0, payload_bytes); - GET_32(4, numLiterals); - GET_32(8, numMatches); - GET_32(12, litPayloadSize); - GET_32(16, lmdPayloadSize); - if (litPayloadSize > (1 << 20) || lmdPayloadSize > (1 << 20)) - return S_FALSE; - GET_32(20, literal_bits); - if (literal_bits < -7 || literal_bits > 0) - return S_FALSE; - - GET_16(24, lit_state_0); - GET_16(26, lit_state_1); - GET_16(28, lit_state_2); - GET_16(30, lit_state_3); - - GET_32(32, lmd_bits); - if (lmd_bits < -7 || lmd_bits > 0) - return S_FALSE; - - GET_16(36, l_state); - GET_16(38, m_state); - GET_16(40, d_state); - - for (unsigned i = 0; i < NUM_SYMBOLS; i++) - freqs[i] = GetUi16(buf + k_v1_SubHeaderSize + i * 2); - */ - } - else - { - UInt32 headerSize; - { - const unsigned kPreHeaderSize = 4 * 2; // signature and upackSize - const unsigned kHeaderSize = 8 * 3; - Byte temp[kHeaderSize]; - if (m_InStream.ReadBytes(temp, kHeaderSize) != kHeaderSize) - return S_FALSE; - - UInt64 v; - - v = GetUi64(temp); - GET_BITS_64(v, 0, 20, numLiterals) - GET_BITS_64(v, 20, 20, litPayloadSize) - GET_BITS_64(v, 40, 20, numMatches) - GET_BITS_64_Int32(v, 60, 3 + 1, literal_bits) // (NumberOfUsedBits - 1) - literal_bits -= 7; // (-NumberOfUnusedBits) - if (literal_bits > 0) - return S_FALSE; - // GET_BITS_64(v, 63, 1, unused); - - v = GetUi64(temp + 8); - GET_BITS_64(v, 0, 10, lit_state_0) - GET_BITS_64(v, 10, 10, lit_state_1) - GET_BITS_64(v, 20, 10, lit_state_2) - GET_BITS_64(v, 30, 10, lit_state_3) - GET_BITS_64(v, 40, 20, lmdPayloadSize) - GET_BITS_64_Int32(v, 60, 3 + 1, lmd_bits) - lmd_bits -= 7; - if (lmd_bits > 0) - return S_FALSE; - // GET_BITS_64(v, 63, 1, unused) - - UInt32 v32 = GetUi32(temp + 20); - // (total header size in bytes; this does not - // correspond to a field in the uncompressed header version, - // but is required; we wouldn't know the size of the - // compresssed header otherwise. - GET_BITS_32(v32, 0, 10, l_state) - GET_BITS_32(v32, 10, 10, m_state) - GET_BITS_32(v32, 20, 10 + 2, d_state) - // GET_BITS_64(v, 62, 2, unused) - - headerSize = GetUi32(temp + 16); - if (headerSize <= kPreHeaderSize + kHeaderSize) - return S_FALSE; - headerSize -= kPreHeaderSize + kHeaderSize; - } - - // no freqs case is not allowed ? - // memset(freqs, 0, sizeof(freqs)); - // if (headerSize != 0) - { - static const Byte numBitsTable[32] = - { - 2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14, - 2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14 - }; - - static const Byte valueTable[32] = - { - 0, 2, 1, 4, 0, 3, 1, 8, 0, 2, 1, 5, 0, 3, 1, 24, - 0, 2, 1, 6, 0, 3, 1, 8, 0, 2, 1, 7, 0, 3, 1, 24 - }; - - UInt32 accum = 0; - unsigned numBits = 0; - - for (unsigned i = 0; i < NUM_SYMBOLS; i++) - { - while (numBits <= 14 && headerSize != 0) - { - Byte b; - if (!m_InStream.ReadByte(b)) - return S_FALSE; - accum |= (UInt32)b << numBits; - numBits += 8; - headerSize--; - } - - unsigned b = (unsigned)accum & 31; - unsigned n = numBitsTable[b]; - if (numBits < n) - return S_FALSE; - numBits -= n; - UInt32 f = valueTable[b]; - if (n >= 8) - f += ((accum >> 4) & (0x3ff >> (14 - n))); - accum >>= n; - freqs[i] = (UInt16)f; - } - - if (numBits >= 8 || headerSize != 0) - return S_FALSE; - } - } - - PRF(printf(" Literals=%6u Matches=%6u", numLiterals, numMatches)); - - if (numLiterals > LITERALS_PER_BLOCK - || (numLiterals & 3) != 0 - || numMatches > MATCHES_PER_BLOCK - || lit_state_0 >= NUM_LIT_STATES - || lit_state_1 >= NUM_LIT_STATES - || lit_state_2 >= NUM_LIT_STATES - || lit_state_3 >= NUM_LIT_STATES - || l_state >= NUM_L_STATES - || m_state >= NUM_M_STATES - || d_state >= NUM_D_STATES) - return S_FALSE; - - // only full table is allowed ? - if ( SumFreqs(freqs_L, NUM_L_SYMBOLS) != NUM_L_STATES - || SumFreqs(freqs_M, NUM_M_SYMBOLS) != NUM_M_STATES - || SumFreqs(freqs_D, NUM_D_SYMBOLS) != NUM_D_STATES - || SumFreqs(freqs_LIT, NUM_LIT_SYMBOLS) != NUM_LIT_STATES) - return S_FALSE; - - - const unsigned kPad = 16; - - // ---------- Decode literals ---------- - - { - _literals.AllocAtLeast(LITERALS_PER_BLOCK + 16); - _buffer.AllocAtLeast(kPad + litPayloadSize); - memset(_buffer, 0, kPad); - - if (m_InStream.ReadBytes(_buffer + kPad, litPayloadSize) != litPayloadSize) - return S_FALSE; - - UInt32 lit_decoder[NUM_LIT_STATES]; - InitLitTable(freqs_LIT, lit_decoder); - - const Byte *buf_start = _buffer + kPad; - const Byte *buf_check = buf_start - 4; - const Byte *buf = buf_start + litPayloadSize; - CBitStream in; - if (FseInStream_Init(&in, literal_bits, &buf) != 0) - return S_FALSE; - - Byte *lit = _literals; - const Byte *lit_limit = lit + numLiterals; - for (; lit < lit_limit; lit += 4) - { - FseInStream_FLUSH - DECODE_LIT (lit[0], lit_state_0) - DECODE_LIT (lit[1], lit_state_1) - FseInStream_FLUSH - DECODE_LIT (lit[2], lit_state_2) - DECODE_LIT (lit[3], lit_state_3) - } - - if ((buf_start - buf) * 8 != (int)in.numBits) - return S_FALSE; - } - - - // ---------- Decode LMD ---------- - - _buffer.AllocAtLeast(kPad + lmdPayloadSize); - memset(_buffer, 0, kPad); - if (m_InStream.ReadBytes(_buffer + kPad, lmdPayloadSize) != lmdPayloadSize) - return S_FALSE; - - CExtraEntry l_decoder[NUM_L_STATES]; - CExtraEntry m_decoder[NUM_M_STATES]; - CExtraEntry d_decoder[NUM_D_STATES]; - - InitExtraDecoderTable(NUM_L_STATES, NUM_L_SYMBOLS, freqs_L, k_L_extra, l_decoder); - InitExtraDecoderTable(NUM_M_STATES, NUM_M_SYMBOLS, freqs_M, k_M_extra, m_decoder); - InitExtraDecoderTable(NUM_D_STATES, NUM_D_SYMBOLS, freqs_D, k_D_extra, d_decoder); - - const Byte *buf_start = _buffer + kPad; - const Byte *buf_check = buf_start - 4; - const Byte *buf = buf_start + lmdPayloadSize; - CBitStream in; - if (FseInStream_Init(&in, lmd_bits, &buf)) - return S_FALSE; - - const Byte *lit = _literals; - const Byte *lit_limit = lit + numLiterals; - - UInt32 D = 0; - - for (;;) - { - if (numMatches == 0) - break; - numMatches--; - - FseInStream_FLUSH - - unsigned L = (unsigned)FseDecodeExtra(&l_state, l_decoder, &in); - - FseInStream_FLUSH - - unsigned M = (unsigned)FseDecodeExtra(&m_state, m_decoder, &in); - - FseInStream_FLUSH - - { - UInt32 new_D = FseDecodeExtra(&d_state, d_decoder, &in); - if (new_D) - D = new_D; - } - - if (L != 0) - { - if (L > (size_t)(lit_limit - lit)) - return S_FALSE; - unsigned cur = L; - if (cur > unpackSize) - cur = (unsigned)unpackSize; - m_OutWindowStream.PutBytes(lit, cur); - unpackSize -= cur; - lit += cur; - if (cur != L) - return S_FALSE; - } - - if (M != 0) - { - if (unpackSize == 0 || D == 0) - return S_FALSE; - unsigned cur = M; - if (cur > unpackSize) - cur = (unsigned)unpackSize; - if (!m_OutWindowStream.CopyBlock(D - 1, cur)) - return S_FALSE; - unpackSize -= cur; - if (cur != M) - return S_FALSE; - } - } - - if (unpackSize != 0) - return S_FALSE; - - // LZFSE encoder writes 8 additional zero bytes before LMD payload - // We test it: - if ((size_t)(buf - buf_start) * 8 + in.numBits != 64) - return S_FALSE; - if (GetUi64(buf_start) != 0) - return S_FALSE; - - return S_OK; -} - - -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - PRF(printf("\n\nLzfseDecoder %7u %7u\n", (unsigned)*outSize, (unsigned)*inSize)); - - const UInt32 kLzfseDictSize = 1 << 18; - if (!m_OutWindowStream.Create(kLzfseDictSize)) - return E_OUTOFMEMORY; - if (!m_InStream.Create(1 << 18)) - return E_OUTOFMEMORY; - - m_OutWindowStream.SetStream(outStream); - m_OutWindowStream.Init(false); - m_InStream.SetStream(inStream); - m_InStream.Init(); - - CCoderReleaser coderReleaser(this); - - UInt64 prevOut = 0; - UInt64 prevIn = 0; - - if (LzvnMode) - { - if (!outSize || !inSize) - return E_NOTIMPL; - const UInt64 unpackSize = *outSize; - const UInt64 packSize = *inSize; - if (unpackSize > (UInt32)(Int32)-1 - || packSize > (UInt32)(Int32)-1) - return S_FALSE; - RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize)) - } - else - for (;;) - { - const UInt64 pos = m_OutWindowStream.GetProcessedSize(); - const UInt64 packPos = m_InStream.GetProcessedSize(); - - if (progress && ((pos - prevOut) >= (1 << 22) || (packPos - prevIn) >= (1 << 22))) - { - RINOK(progress->SetRatioInfo(&packPos, &pos)) - prevIn = packPos; - prevOut = pos; - } - - UInt32 v; - RINOK(GetUInt32(v)) - if ((v & 0xFFFFFF) != 0x787662) // bvx - return S_FALSE; - v >>= 24; - - if (v == 0x24) // '$', end of stream - break; - - UInt32 unpackSize; - RINOK(GetUInt32(unpackSize)) - - UInt32 cur = unpackSize; - if (outSize) - { - const UInt64 rem = *outSize - pos; - if (cur > rem) - cur = (UInt32)rem; - } - unpackSize -= cur; - - HRESULT res; - if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2) - res = DecodeLzfse(cur, (Byte)v); - else if (v == 0x6E) // 'n' - { - UInt32 packSize; - res = GetUInt32(packSize); - if (res == S_OK) - res = DecodeLzvn(cur, packSize); - } - else if (v == 0x2D) // '-' - res = DecodeUncompressed(cur); - else - return E_NOTIMPL; - - if (res != S_OK) - return res; - - if (unpackSize != 0) - return S_FALSE; - } - - coderReleaser.NeedFlush = false; - HRESULT res = m_OutWindowStream.Flush(); - if (res == S_OK) - if ((!LzvnMode && inSize && *inSize != m_InStream.GetProcessedSize()) - || (outSize && *outSize != m_OutWindowStream.GetProcessedSize())) - res = S_FALSE; - return res; -} - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return E_OUTOFMEMORY; } - // catch(...) { return S_FALSE; } -} - -}} +// LzfseDecoder.cpp + +/* +This code implements LZFSE data decompressing. +The code from "LZFSE compression library" was used. + +2018 : Igor Pavlov : BSD 3-clause License : the code in this file +2015-2017 : Apple Inc : BSD 3-clause License : original "LZFSE compression library" code + +The code in the "LZFSE compression library" is licensed under the "BSD 3-clause License": +---- +Copyright (c) 2015-2016, Apple Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +---- +*/ + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../C/CpuArch.h" + +#include "LzfseDecoder.h" + +namespace NCompress { +namespace NLzfse { + +static const Byte kSignature_LZFSE_V1 = 0x31; // '1' +static const Byte kSignature_LZFSE_V2 = 0x32; // '2' + + +HRESULT CDecoder::GetUInt32(UInt32 &val) +{ + Byte b[4]; + for (unsigned i = 0; i < 4; i++) + if (!m_InStream.ReadByte(b[i])) + return S_FALSE; + val = GetUi32(b); + return S_OK; +} + + + +HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize) +{ + PRF(printf("\nUncompressed %7u\n", unpackSize)); + + const unsigned kBufSize = 1 << 8; + Byte buf[kBufSize]; + for (;;) + { + if (unpackSize == 0) + return S_OK; + UInt32 cur = unpackSize; + if (cur > kBufSize) + cur = kBufSize; + const UInt32 cur2 = (UInt32)m_InStream.ReadBytes(buf, cur); + m_OutWindowStream.PutBytes(buf, cur2); + if (cur != cur2) + return S_FALSE; + } +} + + + +HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize) +{ + PRF(printf("\nLZVN 0x%07x 0x%07x\n", unpackSize, packSize)); + + UInt32 D = 0; + + for (;;) + { + if (packSize == 0) + return S_FALSE; + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + packSize--; + + UInt32 M; + UInt32 L; + + if (b >= 0xE0) + { + /* + large L - 11100000 LLLLLLLL + small L - 1110LLLL + + large Rep - 11110000 MMMMMMMM + small Rep - 1111MMMM + */ + + M = b & 0xF; + if (M == 0) + { + if (packSize == 0) + return S_FALSE; + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + packSize--; + M = (UInt32)b1 + 16; + } + L = 0; + if ((b & 0x10) == 0) + { + // Literals only + L = M; + M = 0; + } + } + + // ERROR codes + else if ((b & 0xF0) == 0x70) // 0111xxxx + return S_FALSE; + else if ((b & 0xF0) == 0xD0) // 1101xxxx + return S_FALSE; + + else + { + if ((b & 0xE0) == 0xA0) + { + // medium - 101LLMMM DDDDDDMM DDDDDDDD + if (packSize < 2) + return S_FALSE; + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + packSize--; + + Byte b2; + if (!m_InStream.ReadByte(b2)) + return S_FALSE; + packSize--; + L = (((UInt32)b >> 3) & 3); + M = (((UInt32)b & 7) << 2) + (b1 & 3); + D = ((UInt32)b1 >> 2) + ((UInt32)b2 << 6); + } + else + { + L = (UInt32)b >> 6; + M = ((UInt32)b >> 3) & 7; + if ((b & 0x7) == 6) + { + // REP - LLMMM110 + if (L == 0) + { + // spec + if (M == 0) + break; // EOS + if (M <= 2) + continue; // NOP + return S_FALSE; // UNDEFINED + } + } + else + { + if (packSize == 0) + return S_FALSE; + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + packSize--; + + // large - LLMMM111 DDDDDDDD DDDDDDDD + // small - LLMMMDDD DDDDDDDD + D = ((UInt32)b & 7); + if (D == 7) + { + if (packSize == 0) + return S_FALSE; + Byte b2; + if (!m_InStream.ReadByte(b2)) + return S_FALSE; + packSize--; + D = b2; + } + D = (D << 8) + b1; + } + } + + M += 3; + } + { + for (unsigned i = 0; i < L; i++) + { + if (packSize == 0 || unpackSize == 0) + return S_FALSE; + Byte b1; + if (!m_InStream.ReadByte(b1)) + return S_FALSE; + packSize--; + m_OutWindowStream.PutByte(b1); + unpackSize--; + } + } + + if (M != 0) + { + if (unpackSize == 0 || D == 0) + return S_FALSE; + unsigned cur = M; + if (cur > unpackSize) + cur = (unsigned)unpackSize; + if (!m_OutWindowStream.CopyBlock(D - 1, cur)) + return S_FALSE; + unpackSize -= cur; + if (cur != M) + return S_FALSE; + } + } + + if (unpackSize != 0) + return S_FALSE; + + // LZVN encoder writes 7 additional zero bytes + if (packSize < 7) + return S_FALSE; + for (unsigned i = 0; i < 7; i++) + { + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + if (b != 0) + return S_FALSE; + } + packSize -= 7; + if (packSize) + { + PRF(printf("packSize after unused = %u\n", packSize)); + // if (packSize <= 0x100) { Byte buf[0x100]; m_InStream.ReadBytes(buf, packSize); } + /* Lzvn block that is used in HFS can contain junk data + (at least 256 bytes) after payload data. Why? + We ignore that junk data, if it's HFS (LzvnMode) mode. */ + if (!LzvnMode) + return S_FALSE; + } + return S_OK; +} + + + +// ---------- LZFSE ---------- + +#define MATCHES_PER_BLOCK 10000 +#define LITERALS_PER_BLOCK (4 * MATCHES_PER_BLOCK) + +#define NUM_L_SYMBOLS 20 +#define NUM_M_SYMBOLS 20 +#define NUM_D_SYMBOLS 64 +#define NUM_LIT_SYMBOLS 256 + +#define NUM_SYMBOLS ( \ + NUM_L_SYMBOLS + \ + NUM_M_SYMBOLS + \ + NUM_D_SYMBOLS + \ + NUM_LIT_SYMBOLS) + +#define NUM_L_STATES (1 << 6) +#define NUM_M_STATES (1 << 6) +#define NUM_D_STATES (1 << 8) +#define NUM_LIT_STATES (1 << 10) + + +typedef UInt32 CFseState; + + +static UInt32 SumFreqs(const UInt16 *freqs, unsigned num) +{ + UInt32 sum = 0; + for (unsigned i = 0; i < num; i++) + sum += (UInt32)freqs[i]; + return sum; +} + + +static Z7_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask) +{ + for (unsigned i = 0;;) + { + if (val & mask) + return i; + i++; + mask >>= 1; + } +} + + +static Z7_FORCE_INLINE void InitLitTable(const UInt16 *freqs, UInt32 *table) +{ + for (unsigned i = 0; i < NUM_LIT_SYMBOLS; i++) + { + unsigned f = freqs[i]; + if (f == 0) + continue; + + // 0 < f <= numStates + // 0 <= k <= numStatesLog + // numStates <= (f<> k) - f; + + /* + CEntry + { + Byte k; + Byte symbol; + UInt16 delta; + }; + */ + + UInt32 e = ((UInt32)i << 8) + k; + k += 16; + UInt32 d = e + ((UInt32)f << k) - ((UInt32)NUM_LIT_STATES << 16); + UInt32 step = (UInt32)1 << k; + + unsigned j = 0; + do + { + *table++ = d; + d += step; + } + while (++j < j0); + + e--; + step >>= 1; + + for (j = j0; j < f; j++) + { + *table++ = e; + e += step; + } + } +} + + +typedef struct +{ + Byte totalBits; + Byte extraBits; + UInt16 delta; + UInt32 vbase; +} CExtraEntry; + + +static void InitExtraDecoderTable(unsigned numStates, + unsigned numSymbols, + const UInt16 *freqs, + const Byte *vbits, + CExtraEntry *table) +{ + UInt32 vbase = 0; + + for (unsigned i = 0; i < numSymbols; i++) + { + unsigned f = freqs[i]; + unsigned extraBits = vbits[i]; + + if (f != 0) + { + unsigned k = CountZeroBits(f, numStates); + unsigned j0 = ((2 * numStates) >> k) - f; + + unsigned j = 0; + do + { + CExtraEntry *e = table++; + e->totalBits = (Byte)(k + extraBits); + e->extraBits = (Byte)extraBits; + e->delta = (UInt16)(((f + j) << k) - numStates); + e->vbase = vbase; + } + while (++j < j0); + + f -= j0; + k--; + + for (j = 0; j < f; j++) + { + CExtraEntry *e = table++; + e->totalBits = (Byte)(k + extraBits); + e->extraBits = (Byte)extraBits; + e->delta = (UInt16)(j << k); + e->vbase = vbase; + } + } + + vbase += ((UInt32)1 << extraBits); + } +} + + +static const Byte k_L_extra[NUM_L_SYMBOLS] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 8 +}; + +static const Byte k_M_extra[NUM_M_SYMBOLS] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11 +}; + +static const Byte k_D_extra[NUM_D_SYMBOLS] = +{ + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15 +}; + + + +// ---------- CBitStream ---------- + +typedef struct +{ + UInt32 accum; + unsigned numBits; // [0, 31] - Number of valid bits in (accum), other bits are 0 +} CBitStream; + + +static Z7_FORCE_INLINE int FseInStream_Init(CBitStream *s, + int n, // [-7, 0], (-n == number_of_unused_bits) in last byte + const Byte **pbuf) +{ + *pbuf -= 4; + s->accum = GetUi32(*pbuf); + if (n) + { + s->numBits = (unsigned)(n + 32); + if ((s->accum >> s->numBits) != 0) + return -1; // ERROR, encoder should have zeroed the upper bits + } + else + { + *pbuf += 1; + s->accum >>= 8; + s->numBits = 24; + } + return 0; // OK +} + + +// 0 <= numBits < 32 +#define mask31(x, numBits) ((x) & (((UInt32)1 << (numBits)) - 1)) + +#define FseInStream_FLUSH \ + { const unsigned nbits = (31 - in.numBits) & (unsigned)-8; \ + if (nbits) { \ + buf -= (nbits >> 3); \ + if (buf < buf_check) return S_FALSE; \ + UInt32 v = GetUi32(buf); \ + in.accum = (in.accum << nbits) | mask31(v, nbits); \ + in.numBits += nbits; }} + + + +static Z7_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits) +{ + s->numBits -= numBits; + const UInt32 v = s->accum >> s->numBits; + s->accum = mask31(s->accum, s->numBits); + return v; +} + + +#define DECODE_LIT(dest, pstate) { \ + UInt32 e = lit_decoder[pstate]; \ + pstate = (CFseState)((e >> 16) + BitStream_Pull(&in, e & 0xff)); \ + dest = (Byte)(e >> 8); } + + +static Z7_FORCE_INLINE UInt32 FseDecodeExtra(CFseState *pstate, + const CExtraEntry *table, + CBitStream *s) +{ + const CExtraEntry *e = &table[*pstate]; + UInt32 v = BitStream_Pull(s, e->totalBits); + unsigned extraBits = e->extraBits; + *pstate = (CFseState)(e->delta + (v >> extraBits)); + return e->vbase + mask31(v, extraBits); +} + + +#define freqs_L (freqs) +#define freqs_M (freqs_L + NUM_L_SYMBOLS) +#define freqs_D (freqs_M + NUM_M_SYMBOLS) +#define freqs_LIT (freqs_D + NUM_D_SYMBOLS) + +#define GET_BITS_64(v, offset, num, dest) dest = (UInt32) ((v >> (offset)) & ((1 << (num)) - 1)); +#define GET_BITS_64_Int32(v, offset, num, dest) dest = (Int32)((v >> (offset)) & ((1 << (num)) - 1)); +#define GET_BITS_32(v, offset, num, dest) dest = (CFseState)((v >> (offset)) & ((1 << (num)) - 1)); + + +HRESULT CDecoder::DecodeLzfse(UInt32 unpackSize, Byte version) +{ + PRF(printf("\nLZFSE-%d %7u", version - '0', unpackSize)); + + UInt32 numLiterals; + UInt32 litPayloadSize; + Int32 literal_bits; + + UInt32 lit_state_0; + UInt32 lit_state_1; + UInt32 lit_state_2; + UInt32 lit_state_3; + + UInt32 numMatches; + UInt32 lmdPayloadSize; + Int32 lmd_bits; + + CFseState l_state; + CFseState m_state; + CFseState d_state; + + UInt16 freqs[NUM_SYMBOLS]; + + if (version == kSignature_LZFSE_V1) + { + return E_NOTIMPL; + // we need examples to test LZFSE-V1 code + /* + const unsigned k_v1_SubHeaderSize = 7 * 4 + 7 * 2; + const unsigned k_v1_HeaderSize = k_v1_SubHeaderSize + NUM_SYMBOLS * 2; + _buffer.AllocAtLeast(k_v1_HeaderSize); + if (m_InStream.ReadBytes(_buffer, k_v1_HeaderSize) != k_v1_HeaderSize) + return S_FALSE; + + const Byte *buf = _buffer; + #define GET_32(offs, dest) dest = GetUi32(buf + offs) + #define GET_16(offs, dest) dest = GetUi16(buf + offs) + + UInt32 payload_bytes; + GET_32(0, payload_bytes); + GET_32(4, numLiterals); + GET_32(8, numMatches); + GET_32(12, litPayloadSize); + GET_32(16, lmdPayloadSize); + if (litPayloadSize > (1 << 20) || lmdPayloadSize > (1 << 20)) + return S_FALSE; + GET_32(20, literal_bits); + if (literal_bits < -7 || literal_bits > 0) + return S_FALSE; + + GET_16(24, lit_state_0); + GET_16(26, lit_state_1); + GET_16(28, lit_state_2); + GET_16(30, lit_state_3); + + GET_32(32, lmd_bits); + if (lmd_bits < -7 || lmd_bits > 0) + return S_FALSE; + + GET_16(36, l_state); + GET_16(38, m_state); + GET_16(40, d_state); + + for (unsigned i = 0; i < NUM_SYMBOLS; i++) + freqs[i] = GetUi16(buf + k_v1_SubHeaderSize + i * 2); + */ + } + else + { + UInt32 headerSize; + { + const unsigned kPreHeaderSize = 4 * 2; // signature and upackSize + const unsigned kHeaderSize = 8 * 3; + Byte temp[kHeaderSize]; + if (m_InStream.ReadBytes(temp, kHeaderSize) != kHeaderSize) + return S_FALSE; + + UInt64 v; + + v = GetUi64(temp); + GET_BITS_64(v, 0, 20, numLiterals) + GET_BITS_64(v, 20, 20, litPayloadSize) + GET_BITS_64(v, 40, 20, numMatches) + GET_BITS_64_Int32(v, 60, 3 + 1, literal_bits) // (NumberOfUsedBits - 1) + literal_bits -= 7; // (-NumberOfUnusedBits) + if (literal_bits > 0) + return S_FALSE; + // GET_BITS_64(v, 63, 1, unused); + + v = GetUi64(temp + 8); + GET_BITS_64(v, 0, 10, lit_state_0) + GET_BITS_64(v, 10, 10, lit_state_1) + GET_BITS_64(v, 20, 10, lit_state_2) + GET_BITS_64(v, 30, 10, lit_state_3) + GET_BITS_64(v, 40, 20, lmdPayloadSize) + GET_BITS_64_Int32(v, 60, 3 + 1, lmd_bits) + lmd_bits -= 7; + if (lmd_bits > 0) + return S_FALSE; + // GET_BITS_64(v, 63, 1, unused) + + UInt32 v32 = GetUi32(temp + 20); + // (total header size in bytes; this does not + // correspond to a field in the uncompressed header version, + // but is required; we wouldn't know the size of the + // compresssed header otherwise. + GET_BITS_32(v32, 0, 10, l_state) + GET_BITS_32(v32, 10, 10, m_state) + GET_BITS_32(v32, 20, 10 + 2, d_state) + // GET_BITS_64(v, 62, 2, unused) + + headerSize = GetUi32(temp + 16); + if (headerSize <= kPreHeaderSize + kHeaderSize) + return S_FALSE; + headerSize -= kPreHeaderSize + kHeaderSize; + } + + // no freqs case is not allowed ? + // memset(freqs, 0, sizeof(freqs)); + // if (headerSize != 0) + { + static const Byte numBitsTable[32] = + { + 2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14, + 2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14 + }; + + static const Byte valueTable[32] = + { + 0, 2, 1, 4, 0, 3, 1, 8, 0, 2, 1, 5, 0, 3, 1, 24, + 0, 2, 1, 6, 0, 3, 1, 8, 0, 2, 1, 7, 0, 3, 1, 24 + }; + + UInt32 accum = 0; + unsigned numBits = 0; + + for (unsigned i = 0; i < NUM_SYMBOLS; i++) + { + while (numBits <= 14 && headerSize != 0) + { + Byte b; + if (!m_InStream.ReadByte(b)) + return S_FALSE; + accum |= (UInt32)b << numBits; + numBits += 8; + headerSize--; + } + + unsigned b = (unsigned)accum & 31; + unsigned n = numBitsTable[b]; + if (numBits < n) + return S_FALSE; + numBits -= n; + UInt32 f = valueTable[b]; + if (n >= 8) + f += ((accum >> 4) & (0x3ff >> (14 - n))); + accum >>= n; + freqs[i] = (UInt16)f; + } + + if (numBits >= 8 || headerSize != 0) + return S_FALSE; + } + } + + PRF(printf(" Literals=%6u Matches=%6u", numLiterals, numMatches)); + + if (numLiterals > LITERALS_PER_BLOCK + || (numLiterals & 3) != 0 + || numMatches > MATCHES_PER_BLOCK + || lit_state_0 >= NUM_LIT_STATES + || lit_state_1 >= NUM_LIT_STATES + || lit_state_2 >= NUM_LIT_STATES + || lit_state_3 >= NUM_LIT_STATES + || l_state >= NUM_L_STATES + || m_state >= NUM_M_STATES + || d_state >= NUM_D_STATES) + return S_FALSE; + + // only full table is allowed ? + if ( SumFreqs(freqs_L, NUM_L_SYMBOLS) != NUM_L_STATES + || SumFreqs(freqs_M, NUM_M_SYMBOLS) != NUM_M_STATES + || SumFreqs(freqs_D, NUM_D_SYMBOLS) != NUM_D_STATES + || SumFreqs(freqs_LIT, NUM_LIT_SYMBOLS) != NUM_LIT_STATES) + return S_FALSE; + + + const unsigned kPad = 16; + + // ---------- Decode literals ---------- + + { + _literals.AllocAtLeast(LITERALS_PER_BLOCK + 16); + _buffer.AllocAtLeast(kPad + litPayloadSize); + memset(_buffer, 0, kPad); + + if (m_InStream.ReadBytes(_buffer + kPad, litPayloadSize) != litPayloadSize) + return S_FALSE; + + UInt32 lit_decoder[NUM_LIT_STATES]; + InitLitTable(freqs_LIT, lit_decoder); + + const Byte *buf_start = _buffer + kPad; + const Byte *buf_check = buf_start - 4; + const Byte *buf = buf_start + litPayloadSize; + CBitStream in; + if (FseInStream_Init(&in, literal_bits, &buf) != 0) + return S_FALSE; + + Byte *lit = _literals; + const Byte *lit_limit = lit + numLiterals; + for (; lit < lit_limit; lit += 4) + { + FseInStream_FLUSH + DECODE_LIT (lit[0], lit_state_0) + DECODE_LIT (lit[1], lit_state_1) + FseInStream_FLUSH + DECODE_LIT (lit[2], lit_state_2) + DECODE_LIT (lit[3], lit_state_3) + } + + if ((buf_start - buf) * 8 != (int)in.numBits) + return S_FALSE; + } + + + // ---------- Decode LMD ---------- + + _buffer.AllocAtLeast(kPad + lmdPayloadSize); + memset(_buffer, 0, kPad); + if (m_InStream.ReadBytes(_buffer + kPad, lmdPayloadSize) != lmdPayloadSize) + return S_FALSE; + + CExtraEntry l_decoder[NUM_L_STATES]; + CExtraEntry m_decoder[NUM_M_STATES]; + CExtraEntry d_decoder[NUM_D_STATES]; + + InitExtraDecoderTable(NUM_L_STATES, NUM_L_SYMBOLS, freqs_L, k_L_extra, l_decoder); + InitExtraDecoderTable(NUM_M_STATES, NUM_M_SYMBOLS, freqs_M, k_M_extra, m_decoder); + InitExtraDecoderTable(NUM_D_STATES, NUM_D_SYMBOLS, freqs_D, k_D_extra, d_decoder); + + const Byte *buf_start = _buffer + kPad; + const Byte *buf_check = buf_start - 4; + const Byte *buf = buf_start + lmdPayloadSize; + CBitStream in; + if (FseInStream_Init(&in, lmd_bits, &buf)) + return S_FALSE; + + const Byte *lit = _literals; + const Byte *lit_limit = lit + numLiterals; + + UInt32 D = 0; + + for (;;) + { + if (numMatches == 0) + break; + numMatches--; + + FseInStream_FLUSH + + unsigned L = (unsigned)FseDecodeExtra(&l_state, l_decoder, &in); + + FseInStream_FLUSH + + unsigned M = (unsigned)FseDecodeExtra(&m_state, m_decoder, &in); + + FseInStream_FLUSH + + { + UInt32 new_D = FseDecodeExtra(&d_state, d_decoder, &in); + if (new_D) + D = new_D; + } + + if (L != 0) + { + if (L > (size_t)(lit_limit - lit)) + return S_FALSE; + unsigned cur = L; + if (cur > unpackSize) + cur = (unsigned)unpackSize; + m_OutWindowStream.PutBytes(lit, cur); + unpackSize -= cur; + lit += cur; + if (cur != L) + return S_FALSE; + } + + if (M != 0) + { + if (unpackSize == 0 || D == 0) + return S_FALSE; + unsigned cur = M; + if (cur > unpackSize) + cur = (unsigned)unpackSize; + if (!m_OutWindowStream.CopyBlock(D - 1, cur)) + return S_FALSE; + unpackSize -= cur; + if (cur != M) + return S_FALSE; + } + } + + if (unpackSize != 0) + return S_FALSE; + + // LZFSE encoder writes 8 additional zero bytes before LMD payload + // We test it: + if ((size_t)(buf - buf_start) * 8 + in.numBits != 64) + return S_FALSE; + if (GetUi64(buf_start) != 0) + return S_FALSE; + + return S_OK; +} + + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + PRF(printf("\n\nLzfseDecoder %7u %7u\n", (unsigned)*outSize, (unsigned)*inSize)); + + const UInt32 kLzfseDictSize = 1 << 18; + if (!m_OutWindowStream.Create(kLzfseDictSize)) + return E_OUTOFMEMORY; + if (!m_InStream.Create(1 << 18)) + return E_OUTOFMEMORY; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(false); + m_InStream.SetStream(inStream); + m_InStream.Init(); + + CCoderReleaser coderReleaser(this); + + UInt64 prevOut = 0; + UInt64 prevIn = 0; + + if (LzvnMode) + { + if (!outSize || !inSize) + return E_NOTIMPL; + const UInt64 unpackSize = *outSize; + const UInt64 packSize = *inSize; + if (unpackSize > (UInt32)(Int32)-1 + || packSize > (UInt32)(Int32)-1) + return S_FALSE; + RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize)) + } + else + for (;;) + { + const UInt64 pos = m_OutWindowStream.GetProcessedSize(); + const UInt64 packPos = m_InStream.GetProcessedSize(); + + if (progress && ((pos - prevOut) >= (1 << 22) || (packPos - prevIn) >= (1 << 22))) + { + RINOK(progress->SetRatioInfo(&packPos, &pos)) + prevIn = packPos; + prevOut = pos; + } + + UInt32 v; + RINOK(GetUInt32(v)) + if ((v & 0xFFFFFF) != 0x787662) // bvx + return S_FALSE; + v >>= 24; + + if (v == 0x24) // '$', end of stream + break; + + UInt32 unpackSize; + RINOK(GetUInt32(unpackSize)) + + UInt32 cur = unpackSize; + if (outSize) + { + const UInt64 rem = *outSize - pos; + if (cur > rem) + cur = (UInt32)rem; + } + unpackSize -= cur; + + HRESULT res; + if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2) + res = DecodeLzfse(cur, (Byte)v); + else if (v == 0x6E) // 'n' + { + UInt32 packSize; + res = GetUInt32(packSize); + if (res == S_OK) + res = DecodeLzvn(cur, packSize); + } + else if (v == 0x2D) // '-' + res = DecodeUncompressed(cur); + else + return E_NOTIMPL; + + if (res != S_OK) + return res; + + if (unpackSize != 0) + return S_FALSE; + } + + coderReleaser.NeedFlush = false; + HRESULT res = m_OutWindowStream.Flush(); + if (res == S_OK) + if ((!LzvnMode && inSize && *inSize != m_InStream.GetProcessedSize()) + || (outSize && *outSize != m_OutWindowStream.GetProcessedSize())) + res = S_FALSE; + return res; +} + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return E_OUTOFMEMORY; } + // catch(...) { return S_FALSE; } +} + +}} diff --git a/CPP/7zip/Compress/LzfseDecoder.h b/CPP/7zip/Compress/LzfseDecoder.h index 67681ed50..b7227dc26 100644 --- a/CPP/7zip/Compress/LzfseDecoder.h +++ b/CPP/7zip/Compress/LzfseDecoder.h @@ -1,63 +1,63 @@ -// LzfseDecoder.h - -#ifndef ZIP7_INC_LZFSE_DECODER_H -#define ZIP7_INC_LZFSE_DECODER_H - -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "LzOutWindow.h" - -namespace NCompress { -namespace NLzfse { - -Z7_CLASS_IMP_NOQIB_1( - CDecoder - , ICompressCoder -) - CLzOutWindow m_OutWindowStream; - CInBuffer m_InStream; - CByteBuffer _literals; - CByteBuffer _buffer; - - class CCoderReleaser - { - CDecoder *m_Coder; - public: - bool NeedFlush; - CCoderReleaser(CDecoder *coder): m_Coder(coder), NeedFlush(true) {} - ~CCoderReleaser() - { - if (NeedFlush) - m_Coder->m_OutWindowStream.Flush(); - } - }; - friend class CCoderReleaser; - - HRESULT GetUInt32(UInt32 &val); - - HRESULT DecodeUncompressed(UInt32 unpackSize); - HRESULT DecodeLzvn(UInt32 unpackSize, UInt32 packSize); - HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -public: - bool LzvnMode; - - CDecoder(): - LzvnMode(false) - {} - - // sizes are checked in Code() - // UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); } - // UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); } -}; - -}} - -#endif +// LzfseDecoder.h + +#ifndef ZIP7_INC_LZFSE_DECODER_H +#define ZIP7_INC_LZFSE_DECODER_H + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "LzOutWindow.h" + +namespace NCompress { +namespace NLzfse { + +Z7_CLASS_IMP_NOQIB_1( + CDecoder + , ICompressCoder +) + CLzOutWindow m_OutWindowStream; + CInBuffer m_InStream; + CByteBuffer _literals; + CByteBuffer _buffer; + + class CCoderReleaser + { + CDecoder *m_Coder; + public: + bool NeedFlush; + CCoderReleaser(CDecoder *coder): m_Coder(coder), NeedFlush(true) {} + ~CCoderReleaser() + { + if (NeedFlush) + m_Coder->m_OutWindowStream.Flush(); + } + }; + friend class CCoderReleaser; + + HRESULT GetUInt32(UInt32 &val); + + HRESULT DecodeUncompressed(UInt32 unpackSize); + HRESULT DecodeLzvn(UInt32 unpackSize, UInt32 packSize); + HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); +public: + bool LzvnMode; + + CDecoder(): + LzvnMode(false) + {} + + // sizes are checked in Code() + // UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); } + // UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/LzhDecoder.cpp b/CPP/7zip/Compress/LzhDecoder.cpp index f83390bbb..fb115da6c 100644 --- a/CPP/7zip/Compress/LzhDecoder.cpp +++ b/CPP/7zip/Compress/LzhDecoder.cpp @@ -1,220 +1,220 @@ -// LzhDecoder.cpp - -#include "StdAfx.h" - -#include "LzhDecoder.h" - -namespace NCompress{ -namespace NLzh { -namespace NDecoder { - -static const UInt32 kWindowSizeMin = 1 << 16; - -bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec) -{ - _symbolT = -1; - - const unsigned n = (unsigned)_inBitStream.ReadBits(numBits); - if (n == 0) - { - const unsigned s = (unsigned)_inBitStream.ReadBits(numBits); - _symbolT = (int)s; - return (s < num); - } - if (n > num) - return false; - - { - Byte lens[NPT]; - unsigned i; - for (i = 0; i < NPT; i++) - lens[i] = 0; - i = 0; - do - { - unsigned val = (unsigned)_inBitStream.GetValue(16); - unsigned c = val >> 13; - unsigned mov = 3; - if (c == 7) - { - while (val & (1 << 12)) - { - val += val; - c++; - } - if (c > 16) - return false; - mov = c - 3; - } - lens[i++] = (Byte)c; - _inBitStream.MovePos(mov); - if ((int)i == spec) - i += _inBitStream.ReadBits(2); - } - while (i < n); - - return _decoderT.Build(lens, NHuffman::k_BuildMode_Full); - } -} - -static const unsigned NUM_C_BITS = 9; - -bool CCoder::ReadC() -{ - _symbolC = -1; - - const unsigned n = (unsigned)_inBitStream.ReadBits(NUM_C_BITS); - if (n == 0) - { - const unsigned s = (unsigned)_inBitStream.ReadBits(NUM_C_BITS); - _symbolC = (int)s; - return (s < NC); - } - if (n > NC) - return false; - - { - Byte lens[NC]; - unsigned i = 0; - do - { - unsigned c = (unsigned)_symbolT; - if (_symbolT < 0) - c = _decoderT.DecodeFull(&_inBitStream); - - if (c <= 2) - { - if (c == 0) - c = 1; - else if (c == 1) - c = _inBitStream.ReadBits(4) + 3; - else - c = _inBitStream.ReadBits(NUM_C_BITS) + 20; - - if (i + c > n) - return false; - - do - lens[i++] = 0; - while (--c); - } - else - lens[i++] = (Byte)(c - 2); - } - while (i < n); - - while (i < NC) lens[i++] = 0; - return _decoderC.Build(lens, /* n, */ NHuffman::k_BuildMode_Full); - } -} - -HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress) -{ - UInt32 blockSize = 0; - - while (rem != 0) - { - if (blockSize == 0) - { - if (_inBitStream.ExtraBitsWereRead()) - return S_FALSE; - if (progress) - { - const UInt64 packSize = _inBitStream.GetProcessedSize(); - const UInt64 pos = _outWindow.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &pos)) - } - - blockSize = _inBitStream.ReadBits(16); - if (blockSize == 0) - return S_FALSE; - - if (!ReadTP(NT, 5, 3)) - return S_FALSE; - if (!ReadC()) - return S_FALSE; - const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5); - if (!ReadTP(NP, pbit, -1)) - return S_FALSE; - } - - blockSize--; - - unsigned number = (unsigned)_symbolC; - if (_symbolC < 0) - number = _decoderC.DecodeFull(&_inBitStream); - - if (number < 256) - { - _outWindow.PutByte((Byte)number); - rem--; - } - else - { - const unsigned len = number - 256 + kMatchMinLen; - - UInt32 dist = (UInt32)(unsigned)_symbolT; - if (_symbolT < 0) - dist = (UInt32)_decoderT.DecodeFull(&_inBitStream); - - if (dist > 1) - { - dist--; - dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist); - } - - if (dist >= DictSize) - return S_FALSE; - - if (len > rem) - { - // if (FinishMode) - return S_FALSE; - // len = (unsigned)rem; - } - - if (!_outWindow.CopyBlock(dist, len)) - return S_FALSE; - rem -= len; - } - } - - // if (FinishMode) - { - if (blockSize != 0) - return S_FALSE; - if (_inBitStream.ReadAlignBits() != 0) - return S_FALSE; - } - if (_inBitStream.ExtraBitsWereRead()) - return S_FALSE; - return S_OK; -} - - -HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt32 outSize, ICompressProgressInfo *progress) -{ - try - { - if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin)) - return E_OUTOFMEMORY; - if (!_inBitStream.Create(1 << 17)) - return E_OUTOFMEMORY; - _outWindow.SetStream(outStream); - _outWindow.Init(false); - _inBitStream.SetStream(inStream); - _inBitStream.Init(); - { - CCoderReleaser coderReleaser(this); - RINOK(CodeReal(outSize, progress)) - coderReleaser.Disable(); - } - return _outWindow.Flush(); - } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -}}} +// LzhDecoder.cpp + +#include "StdAfx.h" + +#include "LzhDecoder.h" + +namespace NCompress{ +namespace NLzh { +namespace NDecoder { + +static const UInt32 kWindowSizeMin = 1 << 16; + +bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec) +{ + _symbolT = -1; + + const unsigned n = (unsigned)_inBitStream.ReadBits(numBits); + if (n == 0) + { + const unsigned s = (unsigned)_inBitStream.ReadBits(numBits); + _symbolT = (int)s; + return (s < num); + } + if (n > num) + return false; + + { + Byte lens[NPT]; + unsigned i; + for (i = 0; i < NPT; i++) + lens[i] = 0; + i = 0; + do + { + unsigned val = (unsigned)_inBitStream.GetValue(16); + unsigned c = val >> 13; + unsigned mov = 3; + if (c == 7) + { + while (val & (1 << 12)) + { + val += val; + c++; + } + if (c > 16) + return false; + mov = c - 3; + } + lens[i++] = (Byte)c; + _inBitStream.MovePos(mov); + if ((int)i == spec) + i += _inBitStream.ReadBits(2); + } + while (i < n); + + return _decoderT.Build(lens, NHuffman::k_BuildMode_Full); + } +} + +static const unsigned NUM_C_BITS = 9; + +bool CCoder::ReadC() +{ + _symbolC = -1; + + const unsigned n = (unsigned)_inBitStream.ReadBits(NUM_C_BITS); + if (n == 0) + { + const unsigned s = (unsigned)_inBitStream.ReadBits(NUM_C_BITS); + _symbolC = (int)s; + return (s < NC); + } + if (n > NC) + return false; + + { + Byte lens[NC]; + unsigned i = 0; + do + { + unsigned c = (unsigned)_symbolT; + if (_symbolT < 0) + c = _decoderT.DecodeFull(&_inBitStream); + + if (c <= 2) + { + if (c == 0) + c = 1; + else if (c == 1) + c = _inBitStream.ReadBits(4) + 3; + else + c = _inBitStream.ReadBits(NUM_C_BITS) + 20; + + if (i + c > n) + return false; + + do + lens[i++] = 0; + while (--c); + } + else + lens[i++] = (Byte)(c - 2); + } + while (i < n); + + while (i < NC) lens[i++] = 0; + return _decoderC.Build(lens, /* n, */ NHuffman::k_BuildMode_Full); + } +} + +HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress) +{ + UInt32 blockSize = 0; + + while (rem != 0) + { + if (blockSize == 0) + { + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + if (progress) + { + const UInt64 packSize = _inBitStream.GetProcessedSize(); + const UInt64 pos = _outWindow.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)) + } + + blockSize = _inBitStream.ReadBits(16); + if (blockSize == 0) + return S_FALSE; + + if (!ReadTP(NT, 5, 3)) + return S_FALSE; + if (!ReadC()) + return S_FALSE; + const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5); + if (!ReadTP(NP, pbit, -1)) + return S_FALSE; + } + + blockSize--; + + unsigned number = (unsigned)_symbolC; + if (_symbolC < 0) + number = _decoderC.DecodeFull(&_inBitStream); + + if (number < 256) + { + _outWindow.PutByte((Byte)number); + rem--; + } + else + { + const unsigned len = number - 256 + kMatchMinLen; + + UInt32 dist = (UInt32)(unsigned)_symbolT; + if (_symbolT < 0) + dist = (UInt32)_decoderT.DecodeFull(&_inBitStream); + + if (dist > 1) + { + dist--; + dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist); + } + + if (dist >= DictSize) + return S_FALSE; + + if (len > rem) + { + // if (FinishMode) + return S_FALSE; + // len = (unsigned)rem; + } + + if (!_outWindow.CopyBlock(dist, len)) + return S_FALSE; + rem -= len; + } + } + + // if (FinishMode) + { + if (blockSize != 0) + return S_FALSE; + if (_inBitStream.ReadAlignBits() != 0) + return S_FALSE; + } + if (_inBitStream.ExtraBitsWereRead()) + return S_FALSE; + return S_OK; +} + + +HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt32 outSize, ICompressProgressInfo *progress) +{ + try + { + if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin)) + return E_OUTOFMEMORY; + if (!_inBitStream.Create(1 << 17)) + return E_OUTOFMEMORY; + _outWindow.SetStream(outStream); + _outWindow.Init(false); + _inBitStream.SetStream(inStream); + _inBitStream.Init(); + { + CCoderReleaser coderReleaser(this); + RINOK(CodeReal(outSize, progress)) + coderReleaser.Disable(); + } + return _outWindow.Flush(); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +}}} diff --git a/CPP/7zip/Compress/LzhDecoder.h b/CPP/7zip/Compress/LzhDecoder.h index 1721b86de..204c52c94 100644 --- a/CPP/7zip/Compress/LzhDecoder.h +++ b/CPP/7zip/Compress/LzhDecoder.h @@ -1,68 +1,68 @@ -// LzhDecoder.h - -#ifndef ZIP7_INC_COMPRESS_LZH_DECODER_H -#define ZIP7_INC_COMPRESS_LZH_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NLzh { -namespace NDecoder { - -const unsigned kMatchMinLen = 3; -const unsigned kMatchMaxLen = 256; -const unsigned NC = 256 + kMatchMaxLen - kMatchMinLen + 1; -const unsigned NUM_CODE_BITS = 16; -const unsigned NUM_DIC_BITS_MAX = 25; -const unsigned NT = NUM_CODE_BITS + 3; -const unsigned NP = NUM_DIC_BITS_MAX + 1; -const unsigned NPT = NP; // Max(NT, NP) - -class CCoder -{ - CLzOutWindow _outWindow; - NBitm::CDecoder _inBitStream; - - int _symbolT; - int _symbolC; - UInt32 DictSize; - // bool FinishMode; - - NHuffman::CDecoder256 _decoderT; - NHuffman::CDecoder _decoderC; - - class CCoderReleaser - { - CCoder *_coder; - public: - CCoderReleaser(CCoder *coder): _coder(coder) {} - void Disable() { _coder = NULL; } - ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); } - }; - friend class CCoderReleaser; - - bool ReadTP(unsigned num, unsigned numBits, int spec); - bool ReadC(); - - HRESULT CodeReal(UInt32 outSize, ICompressProgressInfo *progress); -public: - CCoder(): DictSize(1 << 16) - // , FinishMode(true) - {} - void SetDictSize(UInt32 dictSize) { DictSize = dictSize; } - UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); } - HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - UInt32 outSize, ICompressProgressInfo *progress); -}; - -}}} - -#endif +// LzhDecoder.h + +#ifndef ZIP7_INC_COMPRESS_LZH_DECODER_H +#define ZIP7_INC_COMPRESS_LZH_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NLzh { +namespace NDecoder { + +const unsigned kMatchMinLen = 3; +const unsigned kMatchMaxLen = 256; +const unsigned NC = 256 + kMatchMaxLen - kMatchMinLen + 1; +const unsigned NUM_CODE_BITS = 16; +const unsigned NUM_DIC_BITS_MAX = 25; +const unsigned NT = NUM_CODE_BITS + 3; +const unsigned NP = NUM_DIC_BITS_MAX + 1; +const unsigned NPT = NP; // Max(NT, NP) + +class CCoder +{ + CLzOutWindow _outWindow; + NBitm::CDecoder _inBitStream; + + int _symbolT; + int _symbolC; + UInt32 DictSize; + // bool FinishMode; + + NHuffman::CDecoder256 _decoderT; + NHuffman::CDecoder _decoderC; + + class CCoderReleaser + { + CCoder *_coder; + public: + CCoderReleaser(CCoder *coder): _coder(coder) {} + void Disable() { _coder = NULL; } + ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); } + }; + friend class CCoderReleaser; + + bool ReadTP(unsigned num, unsigned numBits, int spec); + bool ReadC(); + + HRESULT CodeReal(UInt32 outSize, ICompressProgressInfo *progress); +public: + CCoder(): DictSize(1 << 16) + // , FinishMode(true) + {} + void SetDictSize(UInt32 dictSize) { DictSize = dictSize; } + UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); } + HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt32 outSize, ICompressProgressInfo *progress); +}; + +}}} + +#endif diff --git a/CPP/7zip/Compress/Lzma2Decoder.cpp b/CPP/7zip/Compress/Lzma2Decoder.cpp index d32686ec1..eab780002 100644 --- a/CPP/7zip/Compress/Lzma2Decoder.cpp +++ b/CPP/7zip/Compress/Lzma2Decoder.cpp @@ -1,267 +1,267 @@ -// Lzma2Decoder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/Alloc.h" -// #include "../../../C/CpuTicks.h" - -#include "../Common/StreamUtils.h" - -#include "Lzma2Decoder.h" - -namespace NCompress { -namespace NLzma2 { - -CDecoder::CDecoder(): - _dec(NULL) - , _inProcessed(0) - , _prop(0xFF) - , _finishMode(false) - , _inBufSize(1 << 20) - , _outStep(1 << 20) - #ifndef Z7_ST - , _tryMt(1) - , _numThreads(1) - , _memUsage((UInt64)(sizeof(size_t)) << 28) - #endif -{} - -CDecoder::~CDecoder() -{ - if (_dec) - Lzma2DecMt_Destroy(_dec); -} - -Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; } -Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) { _outStep = size; return S_OK; } - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)) -{ - if (size != 1) - return E_NOTIMPL; - if (prop[0] > 40) - return E_NOTIMPL; - _prop = prop[0]; - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - _finishMode = (finishMode != 0); - return S_OK; -} - - - -#ifndef Z7_ST - -static UInt64 Get_ExpectedBlockSize_From_Dict(UInt32 dictSize) -{ - const UInt32 kMinSize = (UInt32)1 << 20; - const UInt32 kMaxSize = (UInt32)1 << 28; - UInt64 blockSize = (UInt64)dictSize << 2; - if (blockSize < kMinSize) blockSize = kMinSize; - if (blockSize > kMaxSize) blockSize = kMaxSize; - if (blockSize < dictSize) blockSize = dictSize; - blockSize += (kMinSize - 1); - blockSize &= ~(UInt64)(kMinSize - 1); - return blockSize; -} - -#define LZMA2_DIC_SIZE_FROM_PROP_FULL(p) ((p) == 40 ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))) - -#endif - -#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes; - -#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - _inProcessed = 0; - - if (!_dec) - { - _dec = Lzma2DecMt_Create( - // &g_AlignedAlloc, - &g_Alloc, - &g_MidAlloc); - if (!_dec) - return E_OUTOFMEMORY; - } - - CLzma2DecMtProps props; - Lzma2DecMtProps_Init(&props); - - props.inBufSize_ST = _inBufSize; - props.outStep_ST = _outStep; - - #ifndef Z7_ST - { - props.numThreads = 1; - UInt32 numThreads = _numThreads; - - if (_tryMt && numThreads >= 1) - { - const UInt64 useLimit = _memUsage; - const UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop); - const UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize); - const size_t expectedBlockSize = (size_t)expectedBlockSize64; - const size_t inBlockMax = expectedBlockSize + expectedBlockSize / 16; - if (expectedBlockSize == expectedBlockSize64 && inBlockMax >= expectedBlockSize) - { - props.outBlockMax = expectedBlockSize; - props.inBlockMax = inBlockMax; - const size_t kOverheadSize = props.inBufSize_MT + (1 << 16); - const UInt64 okThreads = useLimit / (props.outBlockMax + props.inBlockMax + kOverheadSize); - if (numThreads > okThreads) - numThreads = (UInt32)okThreads; - if (numThreads == 0) - numThreads = 1; - props.numThreads = numThreads; - } - } - } - #endif - - CSeqInStreamWrap inWrap; - CSeqOutStreamWrap outWrap; - CCompressProgressWrap progressWrap; - - inWrap.Init(inStream); - outWrap.Init(outStream); - progressWrap.Init(progress); - - SRes res; - - UInt64 inProcessed = 0; - int isMT = False; - - #ifndef Z7_ST - isMT = _tryMt; - #endif - - // UInt64 cpuTicks = GetCpuTicks(); - - res = Lzma2DecMt_Decode(_dec, _prop, &props, - &outWrap.vt, outSize, _finishMode, - &inWrap.vt, - &inProcessed, - &isMT, - progress ? &progressWrap.vt : NULL); - - /* - cpuTicks = GetCpuTicks() - cpuTicks; - printf("\n ticks = %10I64u\n", cpuTicks / 1000000); - */ - - - #ifndef Z7_ST - /* we reset _tryMt, only if p->props.numThreads was changed */ - if (props.numThreads > 1) - _tryMt = isMT; - #endif - - _inProcessed = inProcessed; - - RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) - RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) - RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ) - - if (res == SZ_OK && _finishMode) - { - if (inSize && *inSize != inProcessed) - res = SZ_ERROR_DATA; - if (outSize && *outSize != outWrap.Processed) - res = SZ_ERROR_DATA; - } - - return SResToHRESULT(res); -} - - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inProcessed; - return S_OK; -} - - -#ifndef Z7_ST - -Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads)) -{ - _numThreads = numThreads; - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::SetMemLimit(UInt64 memUsage)) -{ - _memUsage = memUsage; - return S_OK; -} - -#endif - - -#ifndef Z7_NO_READ_FROM_CODER - -Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) -{ - CLzma2DecMtProps props; - Lzma2DecMtProps_Init(&props); - props.inBufSize_ST = _inBufSize; - props.outStep_ST = _outStep; - - _inProcessed = 0; - - if (!_dec) - { - _dec = Lzma2DecMt_Create(&g_AlignedAlloc, &g_MidAlloc); - if (!_dec) - return E_OUTOFMEMORY; - } - - _inWrap.Init(_inStream); - - const SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt); - - if (res != SZ_OK) - return SResToHRESULT(res); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) - { _inStream = inStream; return S_OK; } -Z7_COM7F_IMF(CDecoder::ReleaseInStream()) - { _inStream.Release(); return S_OK; } - - -Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - size_t size2 = size; - UInt64 inProcessed = 0; - - const SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed); - - _inProcessed += inProcessed; - if (processedSize) - *processedSize = (UInt32)size2; - if (res != SZ_OK) - return SResToHRESULT(res); - return S_OK; -} - -#endif - -}} +// Lzma2Decoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/Alloc.h" +// #include "../../../C/CpuTicks.h" + +#include "../Common/StreamUtils.h" + +#include "Lzma2Decoder.h" + +namespace NCompress { +namespace NLzma2 { + +CDecoder::CDecoder(): + _dec(NULL) + , _inProcessed(0) + , _prop(0xFF) + , _finishMode(false) + , _inBufSize(1 << 20) + , _outStep(1 << 20) + #ifndef Z7_ST + , _tryMt(1) + , _numThreads(1) + , _memUsage((UInt64)(sizeof(size_t)) << 28) + #endif +{} + +CDecoder::~CDecoder() +{ + if (_dec) + Lzma2DecMt_Destroy(_dec); +} + +Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; } +Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) { _outStep = size; return S_OK; } + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)) +{ + if (size != 1) + return E_NOTIMPL; + if (prop[0] > 40) + return E_NOTIMPL; + _prop = prop[0]; + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + _finishMode = (finishMode != 0); + return S_OK; +} + + + +#ifndef Z7_ST + +static UInt64 Get_ExpectedBlockSize_From_Dict(UInt32 dictSize) +{ + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + UInt64 blockSize = (UInt64)dictSize << 2; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + if (blockSize < dictSize) blockSize = dictSize; + blockSize += (kMinSize - 1); + blockSize &= ~(UInt64)(kMinSize - 1); + return blockSize; +} + +#define LZMA2_DIC_SIZE_FROM_PROP_FULL(p) ((p) == 40 ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))) + +#endif + +#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes; + +#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + _inProcessed = 0; + + if (!_dec) + { + _dec = Lzma2DecMt_Create( + // &g_AlignedAlloc, + &g_Alloc, + &g_MidAlloc); + if (!_dec) + return E_OUTOFMEMORY; + } + + CLzma2DecMtProps props; + Lzma2DecMtProps_Init(&props); + + props.inBufSize_ST = _inBufSize; + props.outStep_ST = _outStep; + + #ifndef Z7_ST + { + props.numThreads = 1; + UInt32 numThreads = _numThreads; + + if (_tryMt && numThreads >= 1) + { + const UInt64 useLimit = _memUsage; + const UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop); + const UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize); + const size_t expectedBlockSize = (size_t)expectedBlockSize64; + const size_t inBlockMax = expectedBlockSize + expectedBlockSize / 16; + if (expectedBlockSize == expectedBlockSize64 && inBlockMax >= expectedBlockSize) + { + props.outBlockMax = expectedBlockSize; + props.inBlockMax = inBlockMax; + const size_t kOverheadSize = props.inBufSize_MT + (1 << 16); + const UInt64 okThreads = useLimit / (props.outBlockMax + props.inBlockMax + kOverheadSize); + if (numThreads > okThreads) + numThreads = (UInt32)okThreads; + if (numThreads == 0) + numThreads = 1; + props.numThreads = numThreads; + } + } + } + #endif + + CSeqInStreamWrap inWrap; + CSeqOutStreamWrap outWrap; + CCompressProgressWrap progressWrap; + + inWrap.Init(inStream); + outWrap.Init(outStream); + progressWrap.Init(progress); + + SRes res; + + UInt64 inProcessed = 0; + int isMT = False; + + #ifndef Z7_ST + isMT = _tryMt; + #endif + + // UInt64 cpuTicks = GetCpuTicks(); + + res = Lzma2DecMt_Decode(_dec, _prop, &props, + &outWrap.vt, outSize, _finishMode, + &inWrap.vt, + &inProcessed, + &isMT, + progress ? &progressWrap.vt : NULL); + + /* + cpuTicks = GetCpuTicks() - cpuTicks; + printf("\n ticks = %10I64u\n", cpuTicks / 1000000); + */ + + + #ifndef Z7_ST + /* we reset _tryMt, only if p->props.numThreads was changed */ + if (props.numThreads > 1) + _tryMt = isMT; + #endif + + _inProcessed = inProcessed; + + RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) + RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) + RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ) + + if (res == SZ_OK && _finishMode) + { + if (inSize && *inSize != inProcessed) + res = SZ_ERROR_DATA; + if (outSize && *outSize != outWrap.Processed) + res = SZ_ERROR_DATA; + } + + return SResToHRESULT(res); +} + + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inProcessed; + return S_OK; +} + + +#ifndef Z7_ST + +Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads)) +{ + _numThreads = numThreads; + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::SetMemLimit(UInt64 memUsage)) +{ + _memUsage = memUsage; + return S_OK; +} + +#endif + + +#ifndef Z7_NO_READ_FROM_CODER + +Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) +{ + CLzma2DecMtProps props; + Lzma2DecMtProps_Init(&props); + props.inBufSize_ST = _inBufSize; + props.outStep_ST = _outStep; + + _inProcessed = 0; + + if (!_dec) + { + _dec = Lzma2DecMt_Create(&g_AlignedAlloc, &g_MidAlloc); + if (!_dec) + return E_OUTOFMEMORY; + } + + _inWrap.Init(_inStream); + + const SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt); + + if (res != SZ_OK) + return SResToHRESULT(res); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) + { _inStream = inStream; return S_OK; } +Z7_COM7F_IMF(CDecoder::ReleaseInStream()) + { _inStream.Release(); return S_OK; } + + +Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + size_t size2 = size; + UInt64 inProcessed = 0; + + const SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed); + + _inProcessed += inProcessed; + if (processedSize) + *processedSize = (UInt32)size2; + if (res != SZ_OK) + return SResToHRESULT(res); + return S_OK; +} + +#endif + +}} diff --git a/CPP/7zip/Compress/Lzma2Decoder.h b/CPP/7zip/Compress/Lzma2Decoder.h index 91ad4be85..7ca717e7f 100644 --- a/CPP/7zip/Compress/Lzma2Decoder.h +++ b/CPP/7zip/Compress/Lzma2Decoder.h @@ -1,87 +1,87 @@ -// Lzma2Decoder.h - -#ifndef ZIP7_INC_LZMA2_DECODER_H -#define ZIP7_INC_LZMA2_DECODER_H - -#include "../../../C/Lzma2DecMt.h" - -#include "../Common/CWrappers.h" - -namespace NCompress { -namespace NLzma2 { - -class CDecoder Z7_final: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public ICompressSetBufSize, - #ifndef Z7_NO_READ_FROM_CODER - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, - #endif - #ifndef Z7_ST - public ICompressSetCoderMt, - public ICompressSetMemLimit, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - Z7_COM_QI_ENTRY(ICompressSetBufSize) - #ifndef Z7_NO_READ_FROM_CODER - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ISequentialInStream) - #endif - #ifndef Z7_ST - Z7_COM_QI_ENTRY(ICompressSetCoderMt) - Z7_COM_QI_ENTRY(ICompressSetMemLimit) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) - Z7_IFACE_COM7_IMP(ICompressSetBufSize) - #ifndef Z7_NO_READ_FROM_CODER - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - Z7_IFACE_COM7_IMP(ICompressSetInStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) - #endif - #ifndef Z7_ST - Z7_IFACE_COM7_IMP(ICompressSetCoderMt) - Z7_IFACE_COM7_IMP(ICompressSetMemLimit) - #endif - - CLzma2DecMtHandle _dec; - UInt64 _inProcessed; - Byte _prop; - int _finishMode; - UInt32 _inBufSize; - UInt32 _outStep; - - #ifndef Z7_ST - int _tryMt; - UInt32 _numThreads; - UInt64 _memUsage; - #endif - - #ifndef Z7_NO_READ_FROM_CODER - CMyComPtr _inStream; - CSeqInStreamWrap _inWrap; - #endif - -public: - CDecoder(); - ~CDecoder(); -}; - -}} - -#endif +// Lzma2Decoder.h + +#ifndef ZIP7_INC_LZMA2_DECODER_H +#define ZIP7_INC_LZMA2_DECODER_H + +#include "../../../C/Lzma2DecMt.h" + +#include "../Common/CWrappers.h" + +namespace NCompress { +namespace NLzma2 { + +class CDecoder Z7_final: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public ICompressSetBufSize, + #ifndef Z7_NO_READ_FROM_CODER + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + #ifndef Z7_ST + public ICompressSetCoderMt, + public ICompressSetMemLimit, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + Z7_COM_QI_ENTRY(ICompressSetBufSize) + #ifndef Z7_NO_READ_FROM_CODER + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ISequentialInStream) + #endif + #ifndef Z7_ST + Z7_COM_QI_ENTRY(ICompressSetCoderMt) + Z7_COM_QI_ENTRY(ICompressSetMemLimit) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) + Z7_IFACE_COM7_IMP(ICompressSetBufSize) + #ifndef Z7_NO_READ_FROM_CODER + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + Z7_IFACE_COM7_IMP(ICompressSetInStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) + #endif + #ifndef Z7_ST + Z7_IFACE_COM7_IMP(ICompressSetCoderMt) + Z7_IFACE_COM7_IMP(ICompressSetMemLimit) + #endif + + CLzma2DecMtHandle _dec; + UInt64 _inProcessed; + Byte _prop; + int _finishMode; + UInt32 _inBufSize; + UInt32 _outStep; + + #ifndef Z7_ST + int _tryMt; + UInt32 _numThreads; + UInt64 _memUsage; + #endif + + #ifndef Z7_NO_READ_FROM_CODER + CMyComPtr _inStream; + CSeqInStreamWrap _inWrap; + #endif + +public: + CDecoder(); + ~CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp index 20af349b7..0dc7e23b4 100644 --- a/CPP/7zip/Compress/Lzma2Encoder.cpp +++ b/CPP/7zip/Compress/Lzma2Encoder.cpp @@ -1,126 +1,126 @@ -// Lzma2Encoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/CWrappers.h" -#include "../Common/StreamUtils.h" - -#include "Lzma2Encoder.h" - -namespace NCompress { - -namespace NLzma { - -HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); - -} - -namespace NLzma2 { - -CEncoder::CEncoder() -{ - _encoder = NULL; - _encoder = Lzma2Enc_Create(&g_AlignedAlloc, &g_BigAlloc); - if (!_encoder) - throw 1; -} - -CEncoder::~CEncoder() -{ - if (_encoder) - Lzma2Enc_Destroy(_encoder); -} - - -HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); -HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props) -{ - switch (propID) - { - case NCoderPropID::kBlockSize: - { - if (prop.vt == VT_UI4) - lzma2Props.blockSize = prop.ulVal; - else if (prop.vt == VT_UI8) - lzma2Props.blockSize = prop.uhVal.QuadPart; - else - return E_INVALIDARG; - break; - } - case NCoderPropID::kNumThreads: - if (prop.vt != VT_UI4) - return E_INVALIDARG; - lzma2Props.numTotalThreads = (int)(prop.ulVal); - break; - default: - RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)) - } - return S_OK; -} - - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps)) -{ - CLzma2EncProps lzma2Props; - Lzma2EncProps_Init(&lzma2Props); - - for (UInt32 i = 0; i < numProps; i++) - { - RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props)) - } - return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props)); -} - - -Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps)) -{ - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - const PROPID propID = propIDs[i]; - if (propID == NCoderPropID::kExpectedDataSize) - if (prop.vt == VT_UI8) - Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart); - } - return S_OK; -} - - -Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) -{ - const Byte prop = Lzma2Enc_WriteProperties(_encoder); - return WriteStream(outStream, &prop, 1); -} - - -#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) -{ - CSeqInStreamWrap inWrap; - CSeqOutStreamWrap outWrap; - CCompressProgressWrap progressWrap; - - inWrap.Init(inStream); - outWrap.Init(outStream); - progressWrap.Init(progress); - - SRes res = Lzma2Enc_Encode2(_encoder, - &outWrap.vt, NULL, NULL, - &inWrap.vt, NULL, 0, - progress ? &progressWrap.vt : NULL); - - RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) - RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) - RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) - - return SResToHRESULT(res); -} - -}} +// Lzma2Encoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/CWrappers.h" +#include "../Common/StreamUtils.h" + +#include "Lzma2Encoder.h" + +namespace NCompress { + +namespace NLzma { + +HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); + +} + +namespace NLzma2 { + +CEncoder::CEncoder() +{ + _encoder = NULL; + _encoder = Lzma2Enc_Create(&g_AlignedAlloc, &g_BigAlloc); + if (!_encoder) + throw 1; +} + +CEncoder::~CEncoder() +{ + if (_encoder) + Lzma2Enc_Destroy(_encoder); +} + + +HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); +HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props) +{ + switch (propID) + { + case NCoderPropID::kBlockSize: + { + if (prop.vt == VT_UI4) + lzma2Props.blockSize = prop.ulVal; + else if (prop.vt == VT_UI8) + lzma2Props.blockSize = prop.uhVal.QuadPart; + else + return E_INVALIDARG; + break; + } + case NCoderPropID::kNumThreads: + if (prop.vt != VT_UI4) + return E_INVALIDARG; + lzma2Props.numTotalThreads = (int)(prop.ulVal); + break; + default: + RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps)) + } + return S_OK; +} + + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps)) +{ + CLzma2EncProps lzma2Props; + Lzma2EncProps_Init(&lzma2Props); + + for (UInt32 i = 0; i < numProps; i++) + { + RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props)) + } + return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props)); +} + + +Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps)) +{ + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + const PROPID propID = propIDs[i]; + if (propID == NCoderPropID::kExpectedDataSize) + if (prop.vt == VT_UI8) + Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart); + } + return S_OK; +} + + +Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) +{ + const Byte prop = Lzma2Enc_WriteProperties(_encoder); + return WriteStream(outStream, &prop, 1); +} + + +#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) +{ + CSeqInStreamWrap inWrap; + CSeqOutStreamWrap outWrap; + CCompressProgressWrap progressWrap; + + inWrap.Init(inStream); + outWrap.Init(outStream); + progressWrap.Init(progress); + + SRes res = Lzma2Enc_Encode2(_encoder, + &outWrap.vt, NULL, NULL, + &inWrap.vt, NULL, 0, + progress ? &progressWrap.vt : NULL); + + RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) + RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) + RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) + + return SResToHRESULT(res); +} + +}} diff --git a/CPP/7zip/Compress/Lzma2Encoder.h b/CPP/7zip/Compress/Lzma2Encoder.h index 1f139fdf1..18c29e120 100644 --- a/CPP/7zip/Compress/Lzma2Encoder.h +++ b/CPP/7zip/Compress/Lzma2Encoder.h @@ -1,30 +1,30 @@ -// Lzma2Encoder.h - -#ifndef ZIP7_INC_LZMA2_ENCODER_H -#define ZIP7_INC_LZMA2_ENCODER_H - -#include "../../../C/Lzma2Enc.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NLzma2 { - -Z7_CLASS_IMP_COM_4( - CEncoder - , ICompressCoder - , ICompressSetCoderProperties - , ICompressWriteCoderProperties - , ICompressSetCoderPropertiesOpt -) - CLzma2EncHandle _encoder; -public: - CEncoder(); - ~CEncoder(); -}; - -}} - -#endif +// Lzma2Encoder.h + +#ifndef ZIP7_INC_LZMA2_ENCODER_H +#define ZIP7_INC_LZMA2_ENCODER_H + +#include "../../../C/Lzma2Enc.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NLzma2 { + +Z7_CLASS_IMP_COM_4( + CEncoder + , ICompressCoder + , ICompressSetCoderProperties + , ICompressWriteCoderProperties + , ICompressSetCoderPropertiesOpt +) + CLzma2EncHandle _encoder; +public: + CEncoder(); + ~CEncoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Lzma2Register.cpp b/CPP/7zip/Compress/Lzma2Register.cpp index 4a86e1ecc..fe5334638 100644 --- a/CPP/7zip/Compress/Lzma2Register.cpp +++ b/CPP/7zip/Compress/Lzma2Register.cpp @@ -1,22 +1,22 @@ -// Lzma2Register.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "Lzma2Decoder.h" - -#ifndef Z7_EXTRACT_ONLY -#include "Lzma2Encoder.h" -#endif - -namespace NCompress { -namespace NLzma2 { - -REGISTER_CODEC_E(LZMA2, - CDecoder(), - CEncoder(), - 0x21, - "LZMA2") - -}} +// Lzma2Register.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "Lzma2Decoder.h" + +#ifndef Z7_EXTRACT_ONLY +#include "Lzma2Encoder.h" +#endif + +namespace NCompress { +namespace NLzma2 { + +REGISTER_CODEC_E(LZMA2, + CDecoder(), + CEncoder(), + 0x21, + "LZMA2") + +}} diff --git a/CPP/7zip/Compress/LzmaDecoder.cpp b/CPP/7zip/Compress/LzmaDecoder.cpp index d0010c17c..4b67c8e90 100644 --- a/CPP/7zip/Compress/LzmaDecoder.cpp +++ b/CPP/7zip/Compress/LzmaDecoder.cpp @@ -1,350 +1,350 @@ -// LzmaDecoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/StreamUtils.h" - -#include "LzmaDecoder.h" - -static HRESULT SResToHRESULT(SRes res) -{ - switch (res) - { - case SZ_OK: return S_OK; - case SZ_ERROR_MEM: return E_OUTOFMEMORY; - case SZ_ERROR_PARAM: return E_INVALIDARG; - case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; - case SZ_ERROR_DATA: return S_FALSE; - default: break; - } - return E_FAIL; -} - -namespace NCompress { -namespace NLzma { - -CDecoder::CDecoder(): - FinishStream(false), - _propsWereSet(false), - _outSizeDefined(false), - _outStep(1 << 20), - _inBufSize(0), - _inBufSizeNew(1 << 20), - _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED), - _inBuf(NULL) -{ - _inProcessed = 0; - _inPos = _inLim = 0; - - /* - AlignOffsetAlloc_CreateVTable(&_alloc); - _alloc.numAlignBits = 7; - _alloc.offset = 0; - */ - LzmaDec_CONSTRUCT(&_state) -} - -CDecoder::~CDecoder() -{ - LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt - MyFree(_inBuf); -} - -Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) - { _inBufSizeNew = size; return S_OK; } -Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) - { _outStep = size; return S_OK; } - -HRESULT CDecoder::CreateInputBuffer() -{ - if (!_inBuf || _inBufSizeNew != _inBufSize) - { - MyFree(_inBuf); - _inBufSize = 0; - _inBuf = (Byte *)MyAlloc(_inBufSizeNew); - if (!_inBuf) - return E_OUTOFMEMORY; - _inBufSize = _inBufSizeNew; - } - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)) -{ - RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt - _propsWereSet = true; - return CreateInputBuffer(); -} - - -void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize) -{ - _outSizeDefined = (outSize != NULL); - _outSize = 0; - if (_outSizeDefined) - _outSize = *outSize; - _outProcessed = 0; - _lzmaStatus = LZMA_STATUS_NOT_SPECIFIED; - - LzmaDec_Init(&_state); -} - - -Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) -{ - _inProcessed = 0; - _inPos = _inLim = 0; - SetOutStreamSizeResume(outSize); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - FinishStream = (finishMode != 0); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inProcessed; - return S_OK; -} - - -HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) -{ - if (!_inBuf || !_propsWereSet) - return S_FALSE; - - const UInt64 startInProgress = _inProcessed; - SizeT wrPos = _state.dicPos; - HRESULT readRes = S_OK; - - for (;;) - { - if (_inPos == _inLim && readRes == S_OK) - { - _inPos = _inLim = 0; - readRes = inStream->Read(_inBuf, _inBufSize, &_inLim); - } - - const SizeT dicPos = _state.dicPos; - SizeT size; - { - SizeT next = _state.dicBufSize; - if (next - wrPos > _outStep) - next = wrPos + _outStep; - size = next - dicPos; - } - - ELzmaFinishMode finishMode = LZMA_FINISH_ANY; - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _outProcessed; - if (size >= rem) - { - size = (SizeT)rem; - if (FinishStream) - finishMode = LZMA_FINISH_END; - } - } - - SizeT inProcessed = _inLim - _inPos; - ELzmaStatus status; - - const SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status); - - _lzmaStatus = status; - _inPos += (UInt32)inProcessed; - _inProcessed += inProcessed; - const SizeT outProcessed = _state.dicPos - dicPos; - _outProcessed += outProcessed; - - // we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0) - const bool outFinished = (_outSizeDefined && _outProcessed >= _outSize); - - const bool needStop = (res != 0 - || (inProcessed == 0 && outProcessed == 0) - || status == LZMA_STATUS_FINISHED_WITH_MARK - || (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)); - - if (needStop || outProcessed >= size) - { - const HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos); - - if (_state.dicPos == _state.dicBufSize) - _state.dicPos = 0; - wrPos = _state.dicPos; - - RINOK(res2) - - if (needStop) - { - if (res != 0) - { - // return SResToHRESULT(res); - return S_FALSE; - } - - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - { - if (FinishStream) - if (_outSizeDefined && _outSize != _outProcessed) - return S_FALSE; - return readRes; - } - - if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT) - if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - return readRes; - - return S_FALSE; - } - } - - if (progress) - { - const UInt64 inSize = _inProcessed - startInProgress; - RINOK(progress->SetRatioInfo(&inSize, &_outProcessed)) - } - } -} - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - if (!_inBuf) - return E_INVALIDARG; - SetOutStreamSize(outSize); - HRESULT res = CodeSpec(inStream, outStream, progress); - if (res == S_OK) - if (FinishStream && inSize && *inSize != _inProcessed) - res = S_FALSE; - return res; -} - - -#ifndef Z7_NO_READ_FROM_CODER - -Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) - { _inStream = inStream; return S_OK; } -Z7_COM7F_IMF(CDecoder::ReleaseInStream()) - { _inStream.Release(); return S_OK; } - -Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - ELzmaFinishMode finishMode = LZMA_FINISH_ANY; - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _outProcessed; - if (size >= rem) - { - size = (UInt32)rem; - if (FinishStream) - finishMode = LZMA_FINISH_END; - } - } - - HRESULT readRes = S_OK; - - for (;;) - { - if (_inPos == _inLim && readRes == S_OK) - { - _inPos = _inLim = 0; - readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim); - } - - SizeT inProcessed = _inLim - _inPos; - SizeT outProcessed = size; - ELzmaStatus status; - - const SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, - _inBuf + _inPos, &inProcessed, finishMode, &status); - - _lzmaStatus = status; - _inPos += (UInt32)inProcessed; - _inProcessed += inProcessed; - _outProcessed += outProcessed; - size -= (UInt32)outProcessed; - data = (Byte *)data + outProcessed; - if (processedSize) - *processedSize += (UInt32)outProcessed; - - if (res != 0) - return S_FALSE; - - /* - if (status == LZMA_STATUS_FINISHED_WITH_MARK) - return readRes; - - if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) - { - if (FinishStream - && _outSizeDefined && _outProcessed >= _outSize - && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) - return S_FALSE; - return readRes; - } - */ - - if (inProcessed == 0 && outProcessed == 0) - return readRes; - } -} - - -HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - SetOutStreamSizeResume(outSize); - return CodeSpec(_inStream, outStream, progress); -} - - -HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize) -{ - RINOK(CreateInputBuffer()) - - if (processedSize) - *processedSize = 0; - - HRESULT readRes = S_OK; - - while (size != 0) - { - if (_inPos == _inLim) - { - _inPos = _inLim = 0; - if (readRes == S_OK) - readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim); - if (_inLim == 0) - break; - } - - UInt32 cur = _inLim - _inPos; - if (cur > size) - cur = size; - memcpy(data, _inBuf + _inPos, cur); - _inPos += cur; - _inProcessed += cur; - size -= cur; - data = (Byte *)data + cur; - if (processedSize) - *processedSize += cur; - } - - return readRes; -} - -#endif - -}} +// LzmaDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "LzmaDecoder.h" + +static HRESULT SResToHRESULT(SRes res) +{ + switch (res) + { + case SZ_OK: return S_OK; + case SZ_ERROR_MEM: return E_OUTOFMEMORY; + case SZ_ERROR_PARAM: return E_INVALIDARG; + case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; + case SZ_ERROR_DATA: return S_FALSE; + default: break; + } + return E_FAIL; +} + +namespace NCompress { +namespace NLzma { + +CDecoder::CDecoder(): + FinishStream(false), + _propsWereSet(false), + _outSizeDefined(false), + _outStep(1 << 20), + _inBufSize(0), + _inBufSizeNew(1 << 20), + _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED), + _inBuf(NULL) +{ + _inProcessed = 0; + _inPos = _inLim = 0; + + /* + AlignOffsetAlloc_CreateVTable(&_alloc); + _alloc.numAlignBits = 7; + _alloc.offset = 0; + */ + LzmaDec_CONSTRUCT(&_state) +} + +CDecoder::~CDecoder() +{ + LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt + MyFree(_inBuf); +} + +Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) + { _inBufSizeNew = size; return S_OK; } +Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) + { _outStep = size; return S_OK; } + +HRESULT CDecoder::CreateInputBuffer() +{ + if (!_inBuf || _inBufSizeNew != _inBufSize) + { + MyFree(_inBuf); + _inBufSize = 0; + _inBuf = (Byte *)MyAlloc(_inBufSizeNew); + if (!_inBuf) + return E_OUTOFMEMORY; + _inBufSize = _inBufSizeNew; + } + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)) +{ + RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt + _propsWereSet = true; + return CreateInputBuffer(); +} + + +void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize) +{ + _outSizeDefined = (outSize != NULL); + _outSize = 0; + if (_outSizeDefined) + _outSize = *outSize; + _outProcessed = 0; + _lzmaStatus = LZMA_STATUS_NOT_SPECIFIED; + + LzmaDec_Init(&_state); +} + + +Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) +{ + _inProcessed = 0; + _inPos = _inLim = 0; + SetOutStreamSizeResume(outSize); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + FinishStream = (finishMode != 0); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inProcessed; + return S_OK; +} + + +HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress) +{ + if (!_inBuf || !_propsWereSet) + return S_FALSE; + + const UInt64 startInProgress = _inProcessed; + SizeT wrPos = _state.dicPos; + HRESULT readRes = S_OK; + + for (;;) + { + if (_inPos == _inLim && readRes == S_OK) + { + _inPos = _inLim = 0; + readRes = inStream->Read(_inBuf, _inBufSize, &_inLim); + } + + const SizeT dicPos = _state.dicPos; + SizeT size; + { + SizeT next = _state.dicBufSize; + if (next - wrPos > _outStep) + next = wrPos + _outStep; + size = next - dicPos; + } + + ELzmaFinishMode finishMode = LZMA_FINISH_ANY; + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outProcessed; + if (size >= rem) + { + size = (SizeT)rem; + if (FinishStream) + finishMode = LZMA_FINISH_END; + } + } + + SizeT inProcessed = _inLim - _inPos; + ELzmaStatus status; + + const SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status); + + _lzmaStatus = status; + _inPos += (UInt32)inProcessed; + _inProcessed += inProcessed; + const SizeT outProcessed = _state.dicPos - dicPos; + _outProcessed += outProcessed; + + // we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0) + const bool outFinished = (_outSizeDefined && _outProcessed >= _outSize); + + const bool needStop = (res != 0 + || (inProcessed == 0 && outProcessed == 0) + || status == LZMA_STATUS_FINISHED_WITH_MARK + || (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)); + + if (needStop || outProcessed >= size) + { + const HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos); + + if (_state.dicPos == _state.dicBufSize) + _state.dicPos = 0; + wrPos = _state.dicPos; + + RINOK(res2) + + if (needStop) + { + if (res != 0) + { + // return SResToHRESULT(res); + return S_FALSE; + } + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + { + if (FinishStream) + if (_outSizeDefined && _outSize != _outProcessed) + return S_FALSE; + return readRes; + } + + if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT) + if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + return readRes; + + return S_FALSE; + } + } + + if (progress) + { + const UInt64 inSize = _inProcessed - startInProgress; + RINOK(progress->SetRatioInfo(&inSize, &_outProcessed)) + } + } +} + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + if (!_inBuf) + return E_INVALIDARG; + SetOutStreamSize(outSize); + HRESULT res = CodeSpec(inStream, outStream, progress); + if (res == S_OK) + if (FinishStream && inSize && *inSize != _inProcessed) + res = S_FALSE; + return res; +} + + +#ifndef Z7_NO_READ_FROM_CODER + +Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) + { _inStream = inStream; return S_OK; } +Z7_COM7F_IMF(CDecoder::ReleaseInStream()) + { _inStream.Release(); return S_OK; } + +Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + ELzmaFinishMode finishMode = LZMA_FINISH_ANY; + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outProcessed; + if (size >= rem) + { + size = (UInt32)rem; + if (FinishStream) + finishMode = LZMA_FINISH_END; + } + } + + HRESULT readRes = S_OK; + + for (;;) + { + if (_inPos == _inLim && readRes == S_OK) + { + _inPos = _inLim = 0; + readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim); + } + + SizeT inProcessed = _inLim - _inPos; + SizeT outProcessed = size; + ELzmaStatus status; + + const SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed, + _inBuf + _inPos, &inProcessed, finishMode, &status); + + _lzmaStatus = status; + _inPos += (UInt32)inProcessed; + _inProcessed += inProcessed; + _outProcessed += outProcessed; + size -= (UInt32)outProcessed; + data = (Byte *)data + outProcessed; + if (processedSize) + *processedSize += (UInt32)outProcessed; + + if (res != 0) + return S_FALSE; + + /* + if (status == LZMA_STATUS_FINISHED_WITH_MARK) + return readRes; + + if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT) + { + if (FinishStream + && _outSizeDefined && _outProcessed >= _outSize + && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + return S_FALSE; + return readRes; + } + */ + + if (inProcessed == 0 && outProcessed == 0) + return readRes; + } +} + + +HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + SetOutStreamSizeResume(outSize); + return CodeSpec(_inStream, outStream, progress); +} + + +HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize) +{ + RINOK(CreateInputBuffer()) + + if (processedSize) + *processedSize = 0; + + HRESULT readRes = S_OK; + + while (size != 0) + { + if (_inPos == _inLim) + { + _inPos = _inLim = 0; + if (readRes == S_OK) + readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim); + if (_inLim == 0) + break; + } + + UInt32 cur = _inLim - _inPos; + if (cur > size) + cur = size; + memcpy(data, _inBuf + _inPos, cur); + _inPos += cur; + _inProcessed += cur; + size -= cur; + data = (Byte *)data + cur; + if (processedSize) + *processedSize += cur; + } + + return readRes; +} + +#endif + +}} diff --git a/CPP/7zip/Compress/LzmaDecoder.h b/CPP/7zip/Compress/LzmaDecoder.h index bc5c961df..095e76ff3 100644 --- a/CPP/7zip/Compress/LzmaDecoder.h +++ b/CPP/7zip/Compress/LzmaDecoder.h @@ -1,113 +1,113 @@ -// LzmaDecoder.h - -#ifndef ZIP7_INC_LZMA_DECODER_H -#define ZIP7_INC_LZMA_DECODER_H - -// #include "../../../C/Alloc.h" -#include "../../../C/LzmaDec.h" - -#include "../../Common/MyCom.h" -#include "../ICoder.h" - -namespace NCompress { -namespace NLzma { - -class CDecoder Z7_final: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public ICompressSetBufSize, - #ifndef Z7_NO_READ_FROM_CODER - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - Z7_COM_QI_ENTRY(ICompressSetBufSize) - #ifndef Z7_NO_READ_FROM_CODER - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ISequentialInStream) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) -public: - Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) -private: - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) - // Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - - Z7_IFACE_COM7_IMP(ICompressSetBufSize) - - #ifndef Z7_NO_READ_FROM_CODER -public: - Z7_IFACE_COM7_IMP(ICompressSetInStream) -private: - Z7_IFACE_COM7_IMP(ISequentialInStream) - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - #else - Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize)); - #endif - -public: - bool FinishStream; // set it before decoding, if you need to decode full LZMA stream -private: - bool _propsWereSet; - bool _outSizeDefined; - - UInt32 _outStep; - UInt32 _inBufSize; - UInt32 _inBufSizeNew; - - ELzmaStatus _lzmaStatus; - UInt32 _inPos; - UInt32 _inLim; - Byte *_inBuf; - - UInt64 _outSize; - UInt64 _inProcessed; - UInt64 _outProcessed; - - // CAlignOffsetAlloc _alloc; - - CLzmaDec _state; - - HRESULT CreateInputBuffer(); - HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); - void SetOutStreamSizeResume(const UInt64 *outSize); - - #ifndef Z7_NO_READ_FROM_CODER -private: - CMyComPtr _inStream; -public: - HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress); - HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize); - #endif - -public: - CDecoder(); - ~CDecoder(); - - UInt64 GetInputProcessedSize() const { return _inProcessed; } - UInt64 GetOutputProcessedSize() const { return _outProcessed; } - bool NeedsMoreInput() const { return _lzmaStatus == LZMA_STATUS_NEEDS_MORE_INPUT; } - bool CheckFinishStatus(bool withEndMark) const - { - return _lzmaStatus == (withEndMark ? - LZMA_STATUS_FINISHED_WITH_MARK : - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK); - } -}; - -}} - -#endif +// LzmaDecoder.h + +#ifndef ZIP7_INC_LZMA_DECODER_H +#define ZIP7_INC_LZMA_DECODER_H + +// #include "../../../C/Alloc.h" +#include "../../../C/LzmaDec.h" + +#include "../../Common/MyCom.h" +#include "../ICoder.h" + +namespace NCompress { +namespace NLzma { + +class CDecoder Z7_final: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public ICompressSetBufSize, + #ifndef Z7_NO_READ_FROM_CODER + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + Z7_COM_QI_ENTRY(ICompressSetBufSize) + #ifndef Z7_NO_READ_FROM_CODER + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ISequentialInStream) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) +public: + Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) +private: + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) + // Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + + Z7_IFACE_COM7_IMP(ICompressSetBufSize) + + #ifndef Z7_NO_READ_FROM_CODER +public: + Z7_IFACE_COM7_IMP(ICompressSetInStream) +private: + Z7_IFACE_COM7_IMP(ISequentialInStream) + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + #else + Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize)); + #endif + +public: + bool FinishStream; // set it before decoding, if you need to decode full LZMA stream +private: + bool _propsWereSet; + bool _outSizeDefined; + + UInt32 _outStep; + UInt32 _inBufSize; + UInt32 _inBufSizeNew; + + ELzmaStatus _lzmaStatus; + UInt32 _inPos; + UInt32 _inLim; + Byte *_inBuf; + + UInt64 _outSize; + UInt64 _inProcessed; + UInt64 _outProcessed; + + // CAlignOffsetAlloc _alloc; + + CLzmaDec _state; + + HRESULT CreateInputBuffer(); + HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress); + void SetOutStreamSizeResume(const UInt64 *outSize); + + #ifndef Z7_NO_READ_FROM_CODER +private: + CMyComPtr _inStream; +public: + HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress); + HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize); + #endif + +public: + CDecoder(); + ~CDecoder(); + + UInt64 GetInputProcessedSize() const { return _inProcessed; } + UInt64 GetOutputProcessedSize() const { return _outProcessed; } + bool NeedsMoreInput() const { return _lzmaStatus == LZMA_STATUS_NEEDS_MORE_INPUT; } + bool CheckFinishStatus(bool withEndMark) const + { + return _lzmaStatus == (withEndMark ? + LZMA_STATUS_FINISHED_WITH_MARK : + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK); + } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp index 7ca03f174..08e3ba53f 100644 --- a/CPP/7zip/Compress/LzmaEncoder.cpp +++ b/CPP/7zip/Compress/LzmaEncoder.cpp @@ -1,356 +1,356 @@ -// LzmaEncoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/CWrappers.h" -#include "../Common/StreamUtils.h" - -#include "LzmaEncoder.h" - -// #define LOG_LZMA_THREADS - -#ifdef LOG_LZMA_THREADS - -#include - -#include "../../Common/IntToString.h" -#include "../../Windows/TimeUtils.h" - -EXTERN_C_BEGIN -void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]); -EXTERN_C_END - -#endif - -namespace NCompress { -namespace NLzma { - -CEncoder::CEncoder() -{ - _encoder = NULL; - _encoder = LzmaEnc_Create(&g_AlignedAlloc); - if (!_encoder) - throw 1; -} - -CEncoder::~CEncoder() -{ - if (_encoder) - LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc); -} - -static inline wchar_t GetLowCharFast(wchar_t c) -{ - return c |= 0x20; -} - -static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) -{ - const wchar_t c = GetLowCharFast(*s++); - if (c == 'h') - { - if (GetLowCharFast(*s++) != 'c') - return 0; - const int num = (int)(*s++ - L'0'); - if (num < 4 || num > 5) - return 0; - if (*s != 0) - return 0; - *btMode = 0; - *numHashBytes = num; - return 1; - } - - if (c != 'b') - return 0; - { - if (GetLowCharFast(*s++) != 't') - return 0; - const int num = (int)(*s++ - L'0'); - if (num < 2 || num > 5) - return 0; - if (*s != 0) - return 0; - *btMode = 1; - *numHashBytes = num; - return 1; - } -} - -#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = (int)v; break; -#define SET_PROP_32U(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break; - -HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); -HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) -{ - if (propID == NCoderPropID::kMatchFinder) - { - if (prop.vt != VT_BSTR) - return E_INVALIDARG; - return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG; - } - - if (propID == NCoderPropID::kAffinity) - { - if (prop.vt == VT_UI8) - ep.affinity = prop.uhVal.QuadPart; - else - return E_INVALIDARG; - return S_OK; - } - - if (propID == NCoderPropID::kHashBits) - { - if (prop.vt == VT_UI4) - ep.numHashOutBits = prop.ulVal; - else - return E_INVALIDARG; - return S_OK; - } - - if (propID > NCoderPropID::kReduceSize) - return S_OK; - - if (propID == NCoderPropID::kReduceSize) - { - if (prop.vt == VT_UI8) - ep.reduceSize = prop.uhVal.QuadPart; - else - return E_INVALIDARG; - return S_OK; - } - - if (propID == NCoderPropID::kDictionarySize) - { - if (prop.vt == VT_UI8) - { - // 21.03 : we support 64-bit VT_UI8 for dictionary and (dict == 4 GiB) - const UInt64 v = prop.uhVal.QuadPart; - if (v > ((UInt64)1 << 32)) - return E_INVALIDARG; - UInt32 dict; - if (v == ((UInt64)1 << 32)) - dict = (UInt32)(Int32)-1; - else - dict = (UInt32)v; - ep.dictSize = dict; - return S_OK; - } - } - - if (prop.vt != VT_UI4) - return E_INVALIDARG; - const UInt32 v = prop.ulVal; - switch (propID) - { - case NCoderPropID::kDefaultProp: - if (v > 32) - return E_INVALIDARG; - ep.dictSize = (v == 32) ? (UInt32)(Int32)-1 : (UInt32)1 << (unsigned)v; - break; - SET_PROP_32(kLevel, level) - SET_PROP_32(kNumFastBytes, fb) - SET_PROP_32U(kMatchFinderCycles, mc) - SET_PROP_32(kAlgorithm, algo) - SET_PROP_32U(kDictionarySize, dictSize) - SET_PROP_32(kPosStateBits, pb) - SET_PROP_32(kLitPosBits, lp) - SET_PROP_32(kLitContextBits, lc) - SET_PROP_32(kNumThreads, numThreads) - default: return E_INVALIDARG; - } - return S_OK; -} - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps)) -{ - CLzmaEncProps props; - LzmaEncProps_Init(&props); - - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - const PROPID propID = propIDs[i]; - switch (propID) - { - case NCoderPropID::kEndMarker: - if (prop.vt != VT_BOOL) - return E_INVALIDARG; - props.writeEndMark = (prop.boolVal != VARIANT_FALSE); - break; - default: - RINOK(SetLzmaProp(propID, prop, props)) - } - } - return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props)); -} - - -Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps)) -{ - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - const PROPID propID = propIDs[i]; - if (propID == NCoderPropID::kExpectedDataSize) - if (prop.vt == VT_UI8) - LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart); - } - return S_OK; -} - - -Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) -{ - Byte props[LZMA_PROPS_SIZE]; - SizeT size = LZMA_PROPS_SIZE; - RINOK(LzmaEnc_WriteProperties(_encoder, props, &size)) - return WriteStream(outStream, props, size); -} - - -#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; - - - -#ifdef LOG_LZMA_THREADS - -static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } - -static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ') -{ - char temp[64]; - char *p = temp + 32; - ConvertUInt64ToString(val, p); - unsigned len = (unsigned)strlen(p); - for (; len < numDigits; len++) - *--p = c; - printf("%s", p); -} - -static void PrintTime(const char *s, UInt64 val, UInt64 total) -{ - printf(" %s :", s); - const UInt32 kFreq = 10000000; - UInt64 sec = val / kFreq; - PrintNum(sec, 6); - printf(" ."); - UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000); - PrintNum(ms, 3, '0'); - - while (val > ((UInt64)1 << 56)) - { - val >>= 1; - total >>= 1; - } - - UInt64 percent = 0; - if (total != 0) - percent = val * 100 / total; - printf(" ="); - PrintNum(percent, 4); - printf("%%"); -} - - -struct CBaseStat -{ - UInt64 kernelTime, userTime; - - BOOL Get(HANDLE thread, const CBaseStat *prevStat) - { - FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT; - BOOL res = GetThreadTimes(thread - , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT); - if (res) - { - kernelTime = GetTime64(kernelTimeFT); - userTime = GetTime64(userTimeFT); - if (prevStat) - { - kernelTime -= prevStat->kernelTime; - userTime -= prevStat->userTime; - } - } - return res; - } -}; - - -static void PrintStat(HANDLE thread, UInt64 totalTime, const CBaseStat *prevStat) -{ - CBaseStat newStat; - if (!newStat.Get(thread, prevStat)) - return; - - PrintTime("K", newStat.kernelTime, totalTime); - - const UInt64 processTime = newStat.kernelTime + newStat.userTime; - - PrintTime("U", newStat.userTime, totalTime); - PrintTime("S", processTime, totalTime); - printf("\n"); - // PrintTime("G ", totalTime, totalTime); -} - -#endif - - - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) -{ - CSeqInStreamWrap inWrap; - CSeqOutStreamWrap outWrap; - CCompressProgressWrap progressWrap; - - inWrap.Init(inStream); - outWrap.Init(outStream); - progressWrap.Init(progress); - - #ifdef LOG_LZMA_THREADS - - FILETIME startTimeFT; - NWindows::NTime::GetCurUtcFileTime(startTimeFT); - UInt64 totalTime = GetTime64(startTimeFT); - CBaseStat oldStat; - if (!oldStat.Get(GetCurrentThread(), NULL)) - return E_FAIL; - - #endif - - - SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, - progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc); - - _inputProcessed = inWrap.Processed; - - RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) - RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) - RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) - - - #ifdef LOG_LZMA_THREADS - - NWindows::NTime::GetCurUtcFileTime(startTimeFT); - totalTime = GetTime64(startTimeFT) - totalTime; - HANDLE lz_threads[2]; - LzmaEnc_GetLzThreads(_encoder, lz_threads); - printf("\n"); - printf("Main: "); PrintStat(GetCurrentThread(), totalTime, &oldStat); - printf("Hash: "); PrintStat(lz_threads[0], totalTime, NULL); - printf("BinT: "); PrintStat(lz_threads[1], totalTime, NULL); - // PrintTime("Total: ", totalTime, totalTime); - printf("\n"); - - #endif - - return SResToHRESULT(res); -} - -}} +// LzmaEncoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/CWrappers.h" +#include "../Common/StreamUtils.h" + +#include "LzmaEncoder.h" + +// #define LOG_LZMA_THREADS + +#ifdef LOG_LZMA_THREADS + +#include + +#include "../../Common/IntToString.h" +#include "../../Windows/TimeUtils.h" + +EXTERN_C_BEGIN +void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]); +EXTERN_C_END + +#endif + +namespace NCompress { +namespace NLzma { + +CEncoder::CEncoder() +{ + _encoder = NULL; + _encoder = LzmaEnc_Create(&g_AlignedAlloc); + if (!_encoder) + throw 1; +} + +CEncoder::~CEncoder() +{ + if (_encoder) + LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc); +} + +static inline wchar_t GetLowCharFast(wchar_t c) +{ + return c |= 0x20; +} + +static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) +{ + const wchar_t c = GetLowCharFast(*s++); + if (c == 'h') + { + if (GetLowCharFast(*s++) != 'c') + return 0; + const int num = (int)(*s++ - L'0'); + if (num < 4 || num > 5) + return 0; + if (*s != 0) + return 0; + *btMode = 0; + *numHashBytes = num; + return 1; + } + + if (c != 'b') + return 0; + { + if (GetLowCharFast(*s++) != 't') + return 0; + const int num = (int)(*s++ - L'0'); + if (num < 2 || num > 5) + return 0; + if (*s != 0) + return 0; + *btMode = 1; + *numHashBytes = num; + return 1; + } +} + +#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = (int)v; break; +#define SET_PROP_32U(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break; + +HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep); +HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep) +{ + if (propID == NCoderPropID::kMatchFinder) + { + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG; + } + + if (propID == NCoderPropID::kAffinity) + { + if (prop.vt == VT_UI8) + ep.affinity = prop.uhVal.QuadPart; + else + return E_INVALIDARG; + return S_OK; + } + + if (propID == NCoderPropID::kHashBits) + { + if (prop.vt == VT_UI4) + ep.numHashOutBits = prop.ulVal; + else + return E_INVALIDARG; + return S_OK; + } + + if (propID > NCoderPropID::kReduceSize) + return S_OK; + + if (propID == NCoderPropID::kReduceSize) + { + if (prop.vt == VT_UI8) + ep.reduceSize = prop.uhVal.QuadPart; + else + return E_INVALIDARG; + return S_OK; + } + + if (propID == NCoderPropID::kDictionarySize) + { + if (prop.vt == VT_UI8) + { + // 21.03 : we support 64-bit VT_UI8 for dictionary and (dict == 4 GiB) + const UInt64 v = prop.uhVal.QuadPart; + if (v > ((UInt64)1 << 32)) + return E_INVALIDARG; + UInt32 dict; + if (v == ((UInt64)1 << 32)) + dict = (UInt32)(Int32)-1; + else + dict = (UInt32)v; + ep.dictSize = dict; + return S_OK; + } + } + + if (prop.vt != VT_UI4) + return E_INVALIDARG; + const UInt32 v = prop.ulVal; + switch (propID) + { + case NCoderPropID::kDefaultProp: + if (v > 32) + return E_INVALIDARG; + ep.dictSize = (v == 32) ? (UInt32)(Int32)-1 : (UInt32)1 << (unsigned)v; + break; + SET_PROP_32(kLevel, level) + SET_PROP_32(kNumFastBytes, fb) + SET_PROP_32U(kMatchFinderCycles, mc) + SET_PROP_32(kAlgorithm, algo) + SET_PROP_32U(kDictionarySize, dictSize) + SET_PROP_32(kPosStateBits, pb) + SET_PROP_32(kLitPosBits, lp) + SET_PROP_32(kLitContextBits, lc) + SET_PROP_32(kNumThreads, numThreads) + default: return E_INVALIDARG; + } + return S_OK; +} + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps)) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + const PROPID propID = propIDs[i]; + switch (propID) + { + case NCoderPropID::kEndMarker: + if (prop.vt != VT_BOOL) + return E_INVALIDARG; + props.writeEndMark = (prop.boolVal != VARIANT_FALSE); + break; + default: + RINOK(SetLzmaProp(propID, prop, props)) + } + } + return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props)); +} + + +Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps)) +{ + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + const PROPID propID = propIDs[i]; + if (propID == NCoderPropID::kExpectedDataSize) + if (prop.vt == VT_UI8) + LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart); + } + return S_OK; +} + + +Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) +{ + Byte props[LZMA_PROPS_SIZE]; + SizeT size = LZMA_PROPS_SIZE; + RINOK(LzmaEnc_WriteProperties(_encoder, props, &size)) + return WriteStream(outStream, props, size); +} + + +#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; + + + +#ifdef LOG_LZMA_THREADS + +static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } + +static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ') +{ + char temp[64]; + char *p = temp + 32; + ConvertUInt64ToString(val, p); + unsigned len = (unsigned)strlen(p); + for (; len < numDigits; len++) + *--p = c; + printf("%s", p); +} + +static void PrintTime(const char *s, UInt64 val, UInt64 total) +{ + printf(" %s :", s); + const UInt32 kFreq = 10000000; + UInt64 sec = val / kFreq; + PrintNum(sec, 6); + printf(" ."); + UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000); + PrintNum(ms, 3, '0'); + + while (val > ((UInt64)1 << 56)) + { + val >>= 1; + total >>= 1; + } + + UInt64 percent = 0; + if (total != 0) + percent = val * 100 / total; + printf(" ="); + PrintNum(percent, 4); + printf("%%"); +} + + +struct CBaseStat +{ + UInt64 kernelTime, userTime; + + BOOL Get(HANDLE thread, const CBaseStat *prevStat) + { + FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT; + BOOL res = GetThreadTimes(thread + , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT); + if (res) + { + kernelTime = GetTime64(kernelTimeFT); + userTime = GetTime64(userTimeFT); + if (prevStat) + { + kernelTime -= prevStat->kernelTime; + userTime -= prevStat->userTime; + } + } + return res; + } +}; + + +static void PrintStat(HANDLE thread, UInt64 totalTime, const CBaseStat *prevStat) +{ + CBaseStat newStat; + if (!newStat.Get(thread, prevStat)) + return; + + PrintTime("K", newStat.kernelTime, totalTime); + + const UInt64 processTime = newStat.kernelTime + newStat.userTime; + + PrintTime("U", newStat.userTime, totalTime); + PrintTime("S", processTime, totalTime); + printf("\n"); + // PrintTime("G ", totalTime, totalTime); +} + +#endif + + + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) +{ + CSeqInStreamWrap inWrap; + CSeqOutStreamWrap outWrap; + CCompressProgressWrap progressWrap; + + inWrap.Init(inStream); + outWrap.Init(outStream); + progressWrap.Init(progress); + + #ifdef LOG_LZMA_THREADS + + FILETIME startTimeFT; + NWindows::NTime::GetCurUtcFileTime(startTimeFT); + UInt64 totalTime = GetTime64(startTimeFT); + CBaseStat oldStat; + if (!oldStat.Get(GetCurrentThread(), NULL)) + return E_FAIL; + + #endif + + + SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, + progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc); + + _inputProcessed = inWrap.Processed; + + RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) + RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) + RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) + + + #ifdef LOG_LZMA_THREADS + + NWindows::NTime::GetCurUtcFileTime(startTimeFT); + totalTime = GetTime64(startTimeFT) - totalTime; + HANDLE lz_threads[2]; + LzmaEnc_GetLzThreads(_encoder, lz_threads); + printf("\n"); + printf("Main: "); PrintStat(GetCurrentThread(), totalTime, &oldStat); + printf("Hash: "); PrintStat(lz_threads[0], totalTime, NULL); + printf("BinT: "); PrintStat(lz_threads[1], totalTime, NULL); + // PrintTime("Total: ", totalTime, totalTime); + printf("\n"); + + #endif + + return SResToHRESULT(res); +} + +}} diff --git a/CPP/7zip/Compress/LzmaEncoder.h b/CPP/7zip/Compress/LzmaEncoder.h index 856f13d41..2836d7df5 100644 --- a/CPP/7zip/Compress/LzmaEncoder.h +++ b/CPP/7zip/Compress/LzmaEncoder.h @@ -1,45 +1,45 @@ -// LzmaEncoder.h - -#ifndef ZIP7_INC_LZMA_ENCODER_H -#define ZIP7_INC_LZMA_ENCODER_H - -#include "../../../C/LzmaEnc.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NLzma { - -class CEncoder Z7_final: - public ICompressCoder, - public ICompressSetCoderProperties, - public ICompressWriteCoderProperties, - public ICompressSetCoderPropertiesOpt, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_4( - ICompressCoder, - ICompressSetCoderProperties, - ICompressWriteCoderProperties, - ICompressSetCoderPropertiesOpt) - Z7_IFACE_COM7_IMP(ICompressCoder) -public: - Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) - Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties) - Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt) - - CLzmaEncHandle _encoder; - UInt64 _inputProcessed; - - CEncoder(); - ~CEncoder(); - - UInt64 GetInputProcessedSize() const { return _inputProcessed; } - bool IsWriteEndMark() const { return LzmaEnc_IsWriteEndMark(_encoder) != 0; } -}; - -}} - -#endif +// LzmaEncoder.h + +#ifndef ZIP7_INC_LZMA_ENCODER_H +#define ZIP7_INC_LZMA_ENCODER_H + +#include "../../../C/LzmaEnc.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NLzma { + +class CEncoder Z7_final: + public ICompressCoder, + public ICompressSetCoderProperties, + public ICompressWriteCoderProperties, + public ICompressSetCoderPropertiesOpt, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_4( + ICompressCoder, + ICompressSetCoderProperties, + ICompressWriteCoderProperties, + ICompressSetCoderPropertiesOpt) + Z7_IFACE_COM7_IMP(ICompressCoder) +public: + Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) + Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties) + Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt) + + CLzmaEncHandle _encoder; + UInt64 _inputProcessed; + + CEncoder(); + ~CEncoder(); + + UInt64 GetInputProcessedSize() const { return _inputProcessed; } + bool IsWriteEndMark() const { return LzmaEnc_IsWriteEndMark(_encoder) != 0; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/LzmaRegister.cpp b/CPP/7zip/Compress/LzmaRegister.cpp index 026b400fa..887f7a2db 100644 --- a/CPP/7zip/Compress/LzmaRegister.cpp +++ b/CPP/7zip/Compress/LzmaRegister.cpp @@ -1,22 +1,22 @@ -// LzmaRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "LzmaDecoder.h" - -#ifndef Z7_EXTRACT_ONLY -#include "LzmaEncoder.h" -#endif - -namespace NCompress { -namespace NLzma { - -REGISTER_CODEC_E(LZMA, - CDecoder(), - CEncoder(), - 0x30101, - "LZMA") - -}} +// LzmaRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "LzmaDecoder.h" + +#ifndef Z7_EXTRACT_ONLY +#include "LzmaEncoder.h" +#endif + +namespace NCompress { +namespace NLzma { + +REGISTER_CODEC_E(LZMA, + CDecoder(), + CEncoder(), + 0x30101, + "LZMA") + +}} diff --git a/CPP/7zip/Compress/LzmsDecoder.cpp b/CPP/7zip/Compress/LzmsDecoder.cpp index 18ccb1ca7..353798a01 100644 --- a/CPP/7zip/Compress/LzmsDecoder.cpp +++ b/CPP/7zip/Compress/LzmsDecoder.cpp @@ -1,619 +1,619 @@ -// LzmsDecoder.cpp -// The code is based on LZMS description from wimlib code - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "LzmsDecoder.h" - -namespace NCompress { -namespace NLzms { - -class CBitDecoder -{ -public: - const Byte *_buf; - unsigned _bitPos; - - void Init(const Byte *buf, size_t size) throw() - { - _buf = buf + size; - _bitPos = 0; - } - - Z7_FORCE_INLINE - UInt32 GetValue(unsigned numBits) const - { - UInt32 v = - ((UInt32)_buf[-1] << 16) | - ((UInt32)_buf[-2] << 8) | - (UInt32)_buf[-3]; - v >>= 24 - numBits - _bitPos; - return v & ((1u << numBits) - 1); - } - - Z7_FORCE_INLINE - UInt32 GetValue_InHigh32bits() - { - return GetUi32(_buf - 4) << _bitPos; - } - - void MovePos(unsigned numBits) - { - _bitPos += numBits; - _buf -= (_bitPos >> 3); - _bitPos &= 7; - } - - UInt32 ReadBits32(unsigned numBits) - { - UInt32 mask = (((UInt32)1 << numBits) - 1); - numBits += _bitPos; - const Byte *buf = _buf; - UInt32 v = GetUi32(buf - 4); - if (numBits > 32) - { - v <<= (numBits - 32); - v |= (UInt32)buf[-5] >> (40 - numBits); - } - else - v >>= (32 - numBits); - _buf = buf - (numBits >> 3); - _bitPos = numBits & 7; - return v & mask; - } -}; - -static UInt32 g_PosBases[k_NumPosSyms /* + 1 */]; - -static Byte g_PosDirectBits[k_NumPosSyms]; - -static const Byte k_PosRuns[31] = -{ - 8, 0, 9, 7, 10, 15, 15, 20, 20, 30, 33, 40, 42, 45, 60, 73, - 80, 85, 95, 105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 -}; - -static UInt32 g_LenBases[k_NumLenSyms]; - -static const Byte k_LenDirectBits[k_NumLenSyms] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, - 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, - 7, 8, 9, 10, 16, 30, -}; - -static struct CInit -{ - CInit() - { - { - unsigned sum = 0; - for (unsigned i = 0; i < sizeof(k_PosRuns); i++) - { - unsigned t = k_PosRuns[i]; - for (unsigned y = 0; y < t; y++) - g_PosDirectBits[sum + y] = (Byte)i; - sum += t; - } - } - { - UInt32 sum = 1; - for (unsigned i = 0; i < k_NumPosSyms; i++) - { - g_PosBases[i] = sum; - sum += (UInt32)1 << g_PosDirectBits[i]; - } - // g_PosBases[k_NumPosSyms] = sum; - } - { - UInt32 sum = 1; - for (unsigned i = 0; i < k_NumLenSyms; i++) - { - g_LenBases[i] = sum; - sum += (UInt32)1 << k_LenDirectBits[i]; - } - } - } -} g_Init; - -static unsigned GetNumPosSlots(size_t size) -{ - if (size < 2) - return 0; - - size--; - - if (size >= g_PosBases[k_NumPosSyms - 1]) - return k_NumPosSyms; - unsigned left = 0; - unsigned right = k_NumPosSyms; - for (;;) - { - const unsigned m = (left + right) / 2; - if (left == m) - return m + 1; - if (size >= g_PosBases[m]) - left = m; - else - right = m; - } -} - - -static const Int32 k_x86_WindowSize = 65535; -static const Int32 k_x86_TransOffset = 1023; - -static const size_t k_x86_HistorySize = 1 << 16; - -static void x86_Filter(Byte *data, UInt32 size, Int32 *history) -{ - if (size <= 17) - return; - - Byte isCode[256]; - memset(isCode, 0, 256); - isCode[0x48] = 1; - isCode[0x4C] = 1; - isCode[0xE8] = 1; - isCode[0xE9] = 1; - isCode[0xF0] = 1; - isCode[0xFF] = 1; - - { - for (size_t i = 0; i < k_x86_HistorySize; i++) - history[i] = -(Int32)k_x86_WindowSize - 1; - } - - size -= 16; - const unsigned kSave = 6; - const Byte savedByte = data[(size_t)size + kSave]; - data[(size_t)size + kSave] = 0xE8; - Int32 last_x86_pos = -k_x86_TransOffset - 1; - - // first byte is ignored - Int32 i = 0; - - for (;;) - { - Byte *p = data + (UInt32)i; - - for (;;) - { - if (isCode[*(++p)]) break; - if (isCode[*(++p)]) break; - } - - i = (Int32)(p - data); - if ((UInt32)i >= size) - break; - - UInt32 codeLen; - - Int32 maxTransOffset = k_x86_TransOffset; - - const Byte b = p[0]; - - if ((b & 0x80) == 0) // REX (0x48 or 0x4c) - { - const unsigned b2 = p[2] - 0x5; // [RIP + disp32] - if (b2 & 0x7) - continue; - if (p[1] != 0x8d) // LEA - { - if (p[1] != 0x8b || b != 0x48 || (b2 & 0xf7)) - continue; - // MOV RAX / RCX, [RIP + disp32] - } - codeLen = 3; - } - else if (b == 0xE8) - { - // CALL - codeLen = 1; - maxTransOffset /= 2; - } - else if (b == 0xE9) - { - // JUMP - i += 4; - continue; - } - else if (b == 0xF0) - { - if (p[1] != 0x83 || p[2] != 0x05) - continue; - // LOCK ADD [RIP + disp32], imm8 - // LOCK ADD [disp32], imm8 - codeLen = 3; - } - else - // if (b == 0xFF) - { - if (p[1] != 0x15) - continue; - // CALL [RIP + disp32]; - // CALL [disp32]; - codeLen = 2; - } - - Int32 *target; - { - Byte *p2 = p + codeLen; - UInt32 n = GetUi32(p2); - if (i - last_x86_pos <= maxTransOffset) - { - n = (UInt32)((Int32)n - i); - SetUi32(p2, n) - } - target = history + (((UInt32)i + n) & 0xFFFF); - } - - i += (Int32)(codeLen + sizeof(UInt32) - 1); - - if (i - *target <= k_x86_WindowSize) - last_x86_pos = i; - *target = i; - } - - data[(size_t)size + kSave] = savedByte; -} - - - -// static const int kLenIdNeedInit = -2; - -CDecoder::CDecoder(): - _x86_history(NULL) -{ -} - -CDecoder::~CDecoder() -{ - ::MidFree(_x86_history); -} - -// #define RIF(x) { if (!(x)) return false; } - -#define LIMIT_CHECK if (_bs._buf < _rc.cur) return S_FALSE; -// #define LIMIT_CHECK - -#define READ_BITS_CHECK(numDirectBits) \ - if (_bs._buf < _rc.cur) return S_FALSE; \ - if ((size_t)(_bs._buf - _rc.cur) < (numDirectBits >> 3)) return S_FALSE; - - -#define HUFF_DEC(sym, pp) \ - sym = pp.DecodeFull(&_bs); \ - pp.Freqs[sym]++; \ - if (--pp.RebuildRem == 0) pp.Rebuild(); - - -HRESULT CDecoder::CodeReal(const Byte *in, size_t inSize, Byte *_win, size_t outSize) -{ - // size_t inSizeT = (size_t)(inSize); - // Byte *_win; - // size_t _pos; - _pos = 0; - - CBitDecoder _bs; - CRangeDecoder _rc; - - if (inSize < 8 || (inSize & 1) != 0) - return S_FALSE; - _rc.Init(in, inSize); - if (_rc.code >= _rc.range) - return S_FALSE; - _bs.Init(in, inSize); - - { - { - { - for (unsigned i = 0 ; i < k_NumReps + 1; i++) - _reps[i] = i + 1; - } - - { - for (unsigned i = 0 ; i < k_NumReps + 1; i++) - _deltaReps[i] = i + 1; - } - - mainState = 0; - matchState = 0; - - { for (size_t i = 0; i < k_NumMainProbs; i++) mainProbs[i].Init(); } - { for (size_t i = 0; i < k_NumMatchProbs; i++) matchProbs[i].Init(); } - - { - for (size_t k = 0; k < k_NumReps; k++) - { - lzRepStates[k] = 0; - for (size_t i = 0; i < k_NumRepProbs; i++) - lzRepProbs[k][i].Init(); - } - } - { - for (size_t k = 0; k < k_NumReps; k++) - { - deltaRepStates[k] = 0; - for (size_t i = 0; i < k_NumRepProbs; i++) - deltaRepProbs[k][i].Init(); - } - } - - m_LitDecoder.Init(); - m_LenDecoder.Init(); - m_PowerDecoder.Init(); - unsigned numPosSyms = GetNumPosSlots(outSize); - if (numPosSyms < 2) - numPosSyms = 2; - m_PosDecoder.Init(numPosSyms); - m_DeltaDecoder.Init(numPosSyms); - } - } - - { - unsigned prevType = 0; - - while (_pos < outSize) - { - if (_rc.Decode(&mainState, k_NumMainProbs, mainProbs) == 0) - { - unsigned number; - HUFF_DEC(number, m_LitDecoder) - LIMIT_CHECK - _win[_pos++] = (Byte)number; - prevType = 0; - } - else if (_rc.Decode(&matchState, k_NumMatchProbs, matchProbs) == 0) - { - UInt32 distance; - - if (_rc.Decode(&lzRepStates[0], k_NumRepProbs, lzRepProbs[0]) == 0) - { - unsigned number; - HUFF_DEC(number, m_PosDecoder) - LIMIT_CHECK - - const unsigned numDirectBits = g_PosDirectBits[number]; - distance = g_PosBases[number]; - READ_BITS_CHECK(numDirectBits) - distance += _bs.ReadBits32(numDirectBits); - // LIMIT_CHECK - _reps[3] = _reps[2]; - _reps[2] = _reps[1]; - _reps[1] = _reps[0]; - _reps[0] = distance; - } - else - { - if (_rc.Decode(&lzRepStates[1], k_NumRepProbs, lzRepProbs[1]) == 0) - { - if (prevType != 1) - distance = _reps[0]; - else - { - distance = _reps[1]; - _reps[1] = _reps[0]; - _reps[0] = distance; - } - } - else if (_rc.Decode(&lzRepStates[2], k_NumRepProbs, lzRepProbs[2]) == 0) - { - if (prevType != 1) - { - distance = _reps[1]; - _reps[1] = _reps[0]; - _reps[0] = distance; - } - else - { - distance = _reps[2]; - _reps[2] = _reps[1]; - _reps[1] = _reps[0]; - _reps[0] = distance; - } - } - else - { - if (prevType != 1) - { - distance = _reps[2]; - _reps[2] = _reps[1]; - _reps[1] = _reps[0]; - _reps[0] = distance; - } - else - { - distance = _reps[3]; - _reps[3] = _reps[2]; - _reps[2] = _reps[1]; - _reps[1] = _reps[0]; - _reps[0] = distance; - } - } - } - - unsigned lenSlot; - HUFF_DEC(lenSlot, m_LenDecoder) - LIMIT_CHECK - - UInt32 len = g_LenBases[lenSlot]; - { - const unsigned numDirectBits = k_LenDirectBits[lenSlot]; - READ_BITS_CHECK(numDirectBits) - len += _bs.ReadBits32(numDirectBits); - } - // LIMIT_CHECK - - if (len > outSize - _pos) - return S_FALSE; - - if (distance > _pos) - return S_FALSE; - - Byte *dest = _win + _pos; - const Byte *src = dest - distance; - _pos += len; - do - *dest++ = *src++; - while (--len); - - prevType = 1; - } - else - { - UInt64 distance; - - unsigned power; - UInt32 distance32; - - if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0) - { - HUFF_DEC(power, m_PowerDecoder) - LIMIT_CHECK - - unsigned number; - HUFF_DEC(number, m_DeltaDecoder) - LIMIT_CHECK - - const unsigned numDirectBits = g_PosDirectBits[number]; - distance32 = g_PosBases[number]; - READ_BITS_CHECK(numDirectBits) - distance32 += _bs.ReadBits32(numDirectBits); - // LIMIT_CHECK - - distance = ((UInt64)power << 32) | distance32; - - _deltaReps[3] = _deltaReps[2]; - _deltaReps[2] = _deltaReps[1]; - _deltaReps[1] = _deltaReps[0]; - _deltaReps[0] = distance; - } - else - { - if (_rc.Decode(&deltaRepStates[1], k_NumRepProbs, deltaRepProbs[1]) == 0) - { - if (prevType != 2) - distance = _deltaReps[0]; - else - { - distance = _deltaReps[1]; - _deltaReps[1] = _deltaReps[0]; - _deltaReps[0] = distance; - } - } - else if (_rc.Decode(&deltaRepStates[2], k_NumRepProbs, deltaRepProbs[2]) == 0) - { - if (prevType != 2) - { - distance = _deltaReps[1]; - _deltaReps[1] = _deltaReps[0]; - _deltaReps[0] = distance; - } - else - { - distance = _deltaReps[2]; - _deltaReps[2] = _deltaReps[1]; - _deltaReps[1] = _deltaReps[0]; - _deltaReps[0] = distance; - } - } - else - { - if (prevType != 2) - { - distance = _deltaReps[2]; - _deltaReps[2] = _deltaReps[1]; - _deltaReps[1] = _deltaReps[0]; - _deltaReps[0] = distance; - } - else - { - distance = _deltaReps[3]; - _deltaReps[3] = _deltaReps[2]; - _deltaReps[2] = _deltaReps[1]; - _deltaReps[1] = _deltaReps[0]; - _deltaReps[0] = distance; - } - } - distance32 = (UInt32)_deltaReps[0] & 0xFFFFFFFF; - power = (UInt32)(_deltaReps[0] >> 32); - } - - const UInt32 dist = (distance32 << power); - - unsigned lenSlot; - HUFF_DEC(lenSlot, m_LenDecoder) - LIMIT_CHECK - - UInt32 len = g_LenBases[lenSlot]; - { - const unsigned numDirectBits = k_LenDirectBits[lenSlot]; - READ_BITS_CHECK(numDirectBits) - len += _bs.ReadBits32(numDirectBits); - } - // LIMIT_CHECK - - if (len > outSize - _pos) - return S_FALSE; - - size_t span = (size_t)1 << power; - if ((UInt64)dist + span > _pos) - return S_FALSE; - Byte *dest = _win + _pos - span; - const Byte *src = dest - dist; - _pos += len; - do - { - *(dest + span) = (Byte)(*(dest) + *(src + span) - *(src)); - src++; - dest++; - } - while (--len); - - prevType = 2; - } - } - } - - _rc.Normalize(); - if (_rc.code != 0) - return S_FALSE; - if (_rc.cur > _bs._buf - || (_rc.cur == _bs._buf && _bs._bitPos != 0)) - return S_FALSE; - - /* - int delta = (int)(_bs._buf - _rc.cur); - if (_bs._bitPos != 0) - delta--; - if ((delta & 1)) - delta--; - printf("%d ", delta); - */ - - return S_OK; -} - -HRESULT CDecoder::Code(const Byte *in, size_t inSize, Byte *out, size_t outSize) -{ - if (!_x86_history) - { - _x86_history = (Int32 *)::MidAlloc(sizeof(Int32) * k_x86_HistorySize); - if (!_x86_history) - return E_OUTOFMEMORY; - } - HRESULT res; - // try - { - res = CodeReal(in, inSize, out, outSize); - } - // catch (...) { res = S_FALSE; } - x86_Filter(out, (UInt32)_pos, _x86_history); - return res; -} - -}} +// LzmsDecoder.cpp +// The code is based on LZMS description from wimlib code + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "LzmsDecoder.h" + +namespace NCompress { +namespace NLzms { + +class CBitDecoder +{ +public: + const Byte *_buf; + unsigned _bitPos; + + void Init(const Byte *buf, size_t size) throw() + { + _buf = buf + size; + _bitPos = 0; + } + + Z7_FORCE_INLINE + UInt32 GetValue(unsigned numBits) const + { + UInt32 v = + ((UInt32)_buf[-1] << 16) | + ((UInt32)_buf[-2] << 8) | + (UInt32)_buf[-3]; + v >>= 24 - numBits - _bitPos; + return v & ((1u << numBits) - 1); + } + + Z7_FORCE_INLINE + UInt32 GetValue_InHigh32bits() + { + return GetUi32(_buf - 4) << _bitPos; + } + + void MovePos(unsigned numBits) + { + _bitPos += numBits; + _buf -= (_bitPos >> 3); + _bitPos &= 7; + } + + UInt32 ReadBits32(unsigned numBits) + { + UInt32 mask = (((UInt32)1 << numBits) - 1); + numBits += _bitPos; + const Byte *buf = _buf; + UInt32 v = GetUi32(buf - 4); + if (numBits > 32) + { + v <<= (numBits - 32); + v |= (UInt32)buf[-5] >> (40 - numBits); + } + else + v >>= (32 - numBits); + _buf = buf - (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; + } +}; + +static UInt32 g_PosBases[k_NumPosSyms /* + 1 */]; + +static Byte g_PosDirectBits[k_NumPosSyms]; + +static const Byte k_PosRuns[31] = +{ + 8, 0, 9, 7, 10, 15, 15, 20, 20, 30, 33, 40, 42, 45, 60, 73, + 80, 85, 95, 105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +static UInt32 g_LenBases[k_NumLenSyms]; + +static const Byte k_LenDirectBits[k_NumLenSyms] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, + 7, 8, 9, 10, 16, 30, +}; + +static struct CInit +{ + CInit() + { + { + unsigned sum = 0; + for (unsigned i = 0; i < sizeof(k_PosRuns); i++) + { + unsigned t = k_PosRuns[i]; + for (unsigned y = 0; y < t; y++) + g_PosDirectBits[sum + y] = (Byte)i; + sum += t; + } + } + { + UInt32 sum = 1; + for (unsigned i = 0; i < k_NumPosSyms; i++) + { + g_PosBases[i] = sum; + sum += (UInt32)1 << g_PosDirectBits[i]; + } + // g_PosBases[k_NumPosSyms] = sum; + } + { + UInt32 sum = 1; + for (unsigned i = 0; i < k_NumLenSyms; i++) + { + g_LenBases[i] = sum; + sum += (UInt32)1 << k_LenDirectBits[i]; + } + } + } +} g_Init; + +static unsigned GetNumPosSlots(size_t size) +{ + if (size < 2) + return 0; + + size--; + + if (size >= g_PosBases[k_NumPosSyms - 1]) + return k_NumPosSyms; + unsigned left = 0; + unsigned right = k_NumPosSyms; + for (;;) + { + const unsigned m = (left + right) / 2; + if (left == m) + return m + 1; + if (size >= g_PosBases[m]) + left = m; + else + right = m; + } +} + + +static const Int32 k_x86_WindowSize = 65535; +static const Int32 k_x86_TransOffset = 1023; + +static const size_t k_x86_HistorySize = 1 << 16; + +static void x86_Filter(Byte *data, UInt32 size, Int32 *history) +{ + if (size <= 17) + return; + + Byte isCode[256]; + memset(isCode, 0, 256); + isCode[0x48] = 1; + isCode[0x4C] = 1; + isCode[0xE8] = 1; + isCode[0xE9] = 1; + isCode[0xF0] = 1; + isCode[0xFF] = 1; + + { + for (size_t i = 0; i < k_x86_HistorySize; i++) + history[i] = -(Int32)k_x86_WindowSize - 1; + } + + size -= 16; + const unsigned kSave = 6; + const Byte savedByte = data[(size_t)size + kSave]; + data[(size_t)size + kSave] = 0xE8; + Int32 last_x86_pos = -k_x86_TransOffset - 1; + + // first byte is ignored + Int32 i = 0; + + for (;;) + { + Byte *p = data + (UInt32)i; + + for (;;) + { + if (isCode[*(++p)]) break; + if (isCode[*(++p)]) break; + } + + i = (Int32)(p - data); + if ((UInt32)i >= size) + break; + + UInt32 codeLen; + + Int32 maxTransOffset = k_x86_TransOffset; + + const Byte b = p[0]; + + if ((b & 0x80) == 0) // REX (0x48 or 0x4c) + { + const unsigned b2 = p[2] - 0x5; // [RIP + disp32] + if (b2 & 0x7) + continue; + if (p[1] != 0x8d) // LEA + { + if (p[1] != 0x8b || b != 0x48 || (b2 & 0xf7)) + continue; + // MOV RAX / RCX, [RIP + disp32] + } + codeLen = 3; + } + else if (b == 0xE8) + { + // CALL + codeLen = 1; + maxTransOffset /= 2; + } + else if (b == 0xE9) + { + // JUMP + i += 4; + continue; + } + else if (b == 0xF0) + { + if (p[1] != 0x83 || p[2] != 0x05) + continue; + // LOCK ADD [RIP + disp32], imm8 + // LOCK ADD [disp32], imm8 + codeLen = 3; + } + else + // if (b == 0xFF) + { + if (p[1] != 0x15) + continue; + // CALL [RIP + disp32]; + // CALL [disp32]; + codeLen = 2; + } + + Int32 *target; + { + Byte *p2 = p + codeLen; + UInt32 n = GetUi32(p2); + if (i - last_x86_pos <= maxTransOffset) + { + n = (UInt32)((Int32)n - i); + SetUi32(p2, n) + } + target = history + (((UInt32)i + n) & 0xFFFF); + } + + i += (Int32)(codeLen + sizeof(UInt32) - 1); + + if (i - *target <= k_x86_WindowSize) + last_x86_pos = i; + *target = i; + } + + data[(size_t)size + kSave] = savedByte; +} + + + +// static const int kLenIdNeedInit = -2; + +CDecoder::CDecoder(): + _x86_history(NULL) +{ +} + +CDecoder::~CDecoder() +{ + ::MidFree(_x86_history); +} + +// #define RIF(x) { if (!(x)) return false; } + +#define LIMIT_CHECK if (_bs._buf < _rc.cur) return S_FALSE; +// #define LIMIT_CHECK + +#define READ_BITS_CHECK(numDirectBits) \ + if (_bs._buf < _rc.cur) return S_FALSE; \ + if ((size_t)(_bs._buf - _rc.cur) < (numDirectBits >> 3)) return S_FALSE; + + +#define HUFF_DEC(sym, pp) \ + sym = pp.DecodeFull(&_bs); \ + pp.Freqs[sym]++; \ + if (--pp.RebuildRem == 0) pp.Rebuild(); + + +HRESULT CDecoder::CodeReal(const Byte *in, size_t inSize, Byte *_win, size_t outSize) +{ + // size_t inSizeT = (size_t)(inSize); + // Byte *_win; + // size_t _pos; + _pos = 0; + + CBitDecoder _bs; + CRangeDecoder _rc; + + if (inSize < 8 || (inSize & 1) != 0) + return S_FALSE; + _rc.Init(in, inSize); + if (_rc.code >= _rc.range) + return S_FALSE; + _bs.Init(in, inSize); + + { + { + { + for (unsigned i = 0 ; i < k_NumReps + 1; i++) + _reps[i] = i + 1; + } + + { + for (unsigned i = 0 ; i < k_NumReps + 1; i++) + _deltaReps[i] = i + 1; + } + + mainState = 0; + matchState = 0; + + { for (size_t i = 0; i < k_NumMainProbs; i++) mainProbs[i].Init(); } + { for (size_t i = 0; i < k_NumMatchProbs; i++) matchProbs[i].Init(); } + + { + for (size_t k = 0; k < k_NumReps; k++) + { + lzRepStates[k] = 0; + for (size_t i = 0; i < k_NumRepProbs; i++) + lzRepProbs[k][i].Init(); + } + } + { + for (size_t k = 0; k < k_NumReps; k++) + { + deltaRepStates[k] = 0; + for (size_t i = 0; i < k_NumRepProbs; i++) + deltaRepProbs[k][i].Init(); + } + } + + m_LitDecoder.Init(); + m_LenDecoder.Init(); + m_PowerDecoder.Init(); + unsigned numPosSyms = GetNumPosSlots(outSize); + if (numPosSyms < 2) + numPosSyms = 2; + m_PosDecoder.Init(numPosSyms); + m_DeltaDecoder.Init(numPosSyms); + } + } + + { + unsigned prevType = 0; + + while (_pos < outSize) + { + if (_rc.Decode(&mainState, k_NumMainProbs, mainProbs) == 0) + { + unsigned number; + HUFF_DEC(number, m_LitDecoder) + LIMIT_CHECK + _win[_pos++] = (Byte)number; + prevType = 0; + } + else if (_rc.Decode(&matchState, k_NumMatchProbs, matchProbs) == 0) + { + UInt32 distance; + + if (_rc.Decode(&lzRepStates[0], k_NumRepProbs, lzRepProbs[0]) == 0) + { + unsigned number; + HUFF_DEC(number, m_PosDecoder) + LIMIT_CHECK + + const unsigned numDirectBits = g_PosDirectBits[number]; + distance = g_PosBases[number]; + READ_BITS_CHECK(numDirectBits) + distance += _bs.ReadBits32(numDirectBits); + // LIMIT_CHECK + _reps[3] = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + else + { + if (_rc.Decode(&lzRepStates[1], k_NumRepProbs, lzRepProbs[1]) == 0) + { + if (prevType != 1) + distance = _reps[0]; + else + { + distance = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + } + else if (_rc.Decode(&lzRepStates[2], k_NumRepProbs, lzRepProbs[2]) == 0) + { + if (prevType != 1) + { + distance = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + else + { + distance = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + } + else + { + if (prevType != 1) + { + distance = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + else + { + distance = _reps[3]; + _reps[3] = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = _reps[0]; + _reps[0] = distance; + } + } + } + + unsigned lenSlot; + HUFF_DEC(lenSlot, m_LenDecoder) + LIMIT_CHECK + + UInt32 len = g_LenBases[lenSlot]; + { + const unsigned numDirectBits = k_LenDirectBits[lenSlot]; + READ_BITS_CHECK(numDirectBits) + len += _bs.ReadBits32(numDirectBits); + } + // LIMIT_CHECK + + if (len > outSize - _pos) + return S_FALSE; + + if (distance > _pos) + return S_FALSE; + + Byte *dest = _win + _pos; + const Byte *src = dest - distance; + _pos += len; + do + *dest++ = *src++; + while (--len); + + prevType = 1; + } + else + { + UInt64 distance; + + unsigned power; + UInt32 distance32; + + if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0) + { + HUFF_DEC(power, m_PowerDecoder) + LIMIT_CHECK + + unsigned number; + HUFF_DEC(number, m_DeltaDecoder) + LIMIT_CHECK + + const unsigned numDirectBits = g_PosDirectBits[number]; + distance32 = g_PosBases[number]; + READ_BITS_CHECK(numDirectBits) + distance32 += _bs.ReadBits32(numDirectBits); + // LIMIT_CHECK + + distance = ((UInt64)power << 32) | distance32; + + _deltaReps[3] = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + else + { + if (_rc.Decode(&deltaRepStates[1], k_NumRepProbs, deltaRepProbs[1]) == 0) + { + if (prevType != 2) + distance = _deltaReps[0]; + else + { + distance = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + } + else if (_rc.Decode(&deltaRepStates[2], k_NumRepProbs, deltaRepProbs[2]) == 0) + { + if (prevType != 2) + { + distance = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + else + { + distance = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + } + else + { + if (prevType != 2) + { + distance = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + else + { + distance = _deltaReps[3]; + _deltaReps[3] = _deltaReps[2]; + _deltaReps[2] = _deltaReps[1]; + _deltaReps[1] = _deltaReps[0]; + _deltaReps[0] = distance; + } + } + distance32 = (UInt32)_deltaReps[0] & 0xFFFFFFFF; + power = (UInt32)(_deltaReps[0] >> 32); + } + + const UInt32 dist = (distance32 << power); + + unsigned lenSlot; + HUFF_DEC(lenSlot, m_LenDecoder) + LIMIT_CHECK + + UInt32 len = g_LenBases[lenSlot]; + { + const unsigned numDirectBits = k_LenDirectBits[lenSlot]; + READ_BITS_CHECK(numDirectBits) + len += _bs.ReadBits32(numDirectBits); + } + // LIMIT_CHECK + + if (len > outSize - _pos) + return S_FALSE; + + size_t span = (size_t)1 << power; + if ((UInt64)dist + span > _pos) + return S_FALSE; + Byte *dest = _win + _pos - span; + const Byte *src = dest - dist; + _pos += len; + do + { + *(dest + span) = (Byte)(*(dest) + *(src + span) - *(src)); + src++; + dest++; + } + while (--len); + + prevType = 2; + } + } + } + + _rc.Normalize(); + if (_rc.code != 0) + return S_FALSE; + if (_rc.cur > _bs._buf + || (_rc.cur == _bs._buf && _bs._bitPos != 0)) + return S_FALSE; + + /* + int delta = (int)(_bs._buf - _rc.cur); + if (_bs._bitPos != 0) + delta--; + if ((delta & 1)) + delta--; + printf("%d ", delta); + */ + + return S_OK; +} + +HRESULT CDecoder::Code(const Byte *in, size_t inSize, Byte *out, size_t outSize) +{ + if (!_x86_history) + { + _x86_history = (Int32 *)::MidAlloc(sizeof(Int32) * k_x86_HistorySize); + if (!_x86_history) + return E_OUTOFMEMORY; + } + HRESULT res; + // try + { + res = CodeReal(in, inSize, out, outSize); + } + // catch (...) { res = S_FALSE; } + x86_Filter(out, (UInt32)_pos, _x86_history); + return res; +} + +}} diff --git a/CPP/7zip/Compress/LzmsDecoder.h b/CPP/7zip/Compress/LzmsDecoder.h index 565108564..bb21262d5 100644 --- a/CPP/7zip/Compress/LzmsDecoder.h +++ b/CPP/7zip/Compress/LzmsDecoder.h @@ -1,209 +1,209 @@ -// LzmsDecoder.h -// The code is based on LZMS description from wimlib code - -#ifndef ZIP7_INC_LZMS_DECODER_H -#define ZIP7_INC_LZMS_DECODER_H - -#include "../../../C/CpuArch.h" -#include "../../../C/HuffEnc.h" - -#include "HuffmanDecoder.h" - -namespace NCompress { -namespace NLzms { - -const unsigned k_NumLitSyms = 256; -const unsigned k_NumLenSyms = 54; -const unsigned k_NumPosSyms = 799; -const unsigned k_NumPowerSyms = 8; - -const unsigned k_NumProbBits = 6; -const unsigned k_ProbLimit = 1 << k_NumProbBits; -const unsigned k_InitialProb = 48; -const UInt32 k_InitialHist = 0x55555555; - -const unsigned k_NumReps = 3; - -const unsigned k_NumMainProbs = 16; -const unsigned k_NumMatchProbs = 32; -const unsigned k_NumRepProbs = 64; - -const unsigned k_NumHuffmanBits = 15; - -template -class CHuffDecoder: public NCompress::NHuffman::CDecoder -{ -public: - UInt32 RebuildRem; - UInt32 NumSyms; - UInt32 Freqs[m_NumSyms]; - - void Generate() throw() - { - UInt32 vals[m_NumSyms]; - Byte levels[m_NumSyms]; - - // We need to check that our algorithm is OK, when optimal Huffman tree uses more than 15 levels !!! - Huffman_Generate(Freqs, vals, levels, NumSyms, k_NumHuffmanBits); - - for (UInt32 i = NumSyms; i < m_NumSyms; i++) - levels[i] = 0; - - this->Build(levels, /* NumSyms, */ NHuffman::k_BuildMode_Full); - } - - void Rebuild() throw() - { - Generate(); - RebuildRem = m_RebuildFreq; - const UInt32 num = NumSyms; - for (UInt32 i = 0; i < num; i++) - Freqs[i] = (Freqs[i] >> 1) + 1; - } - -public: - void Init(UInt32 numSyms = m_NumSyms) throw() - { - RebuildRem = m_RebuildFreq; - NumSyms = numSyms; - for (UInt32 i = 0; i < numSyms; i++) - Freqs[i] = 1; - // for (; i < m_NumSyms; i++) Freqs[i] = 0; - Generate(); - } -}; - - -struct CProbEntry -{ - UInt32 Prob; - UInt64 Hist; - - void Init() - { - Prob = k_InitialProb; - Hist = k_InitialHist; - } - - UInt32 GetProb() const throw() - { - UInt32 prob = Prob; - if (prob == 0) - prob = 1; - else if (prob == k_ProbLimit) - prob = k_ProbLimit - 1; - return prob; - } - - void Update(unsigned bit) throw() - { - Prob += (UInt32)((Int32)(Hist >> (k_ProbLimit - 1)) - (Int32)bit); - Hist = (Hist << 1) | bit; - } -}; - - -struct CRangeDecoder -{ - UInt32 range; - UInt32 code; - const Byte *cur; - // const Byte *end; - - void Init(const Byte *data, size_t /* size */) throw() - { - range = 0xFFFFFFFF; - code = (((UInt32)GetUi16(data)) << 16) | GetUi16(data + 2); - cur = data + 4; - // end = data + size; - } - - void Normalize() - { - if (range <= 0xFFFF) - { - range <<= 16; - code <<= 16; - // if (cur >= end) throw 1; - code |= GetUi16(cur); - cur += 2; - } - } - - unsigned Decode(UInt32 *state, UInt32 numStates, struct CProbEntry *probs) - { - UInt32 st = *state; - CProbEntry *entry = &probs[st]; - st = (st << 1) & (numStates - 1); - - const UInt32 prob = entry->GetProb(); - - if (range <= 0xFFFF) - { - range <<= 16; - code <<= 16; - // if (cur >= end) throw 1; - code |= GetUi16(cur); - cur += 2; - } - - const UInt32 bound = (range >> k_NumProbBits) * prob; - - if (code < bound) - { - range = bound; - *state = st; - entry->Update(0); - return 0; - } - else - { - range -= bound; - code -= bound; - *state = st | 1; - entry->Update(1); - return 1; - } - } -}; - - -class CDecoder -{ - // CRangeDecoder _rc; - size_t _pos; - - UInt32 _reps[k_NumReps + 1]; - UInt64 _deltaReps[k_NumReps + 1]; - - UInt32 mainState; - UInt32 matchState; - UInt32 lzRepStates[k_NumReps]; - UInt32 deltaRepStates[k_NumReps]; - - struct CProbEntry mainProbs[k_NumMainProbs]; - struct CProbEntry matchProbs[k_NumMatchProbs]; - - struct CProbEntry lzRepProbs[k_NumReps][k_NumRepProbs]; - struct CProbEntry deltaRepProbs[k_NumReps][k_NumRepProbs]; - - CHuffDecoder m_LitDecoder; - CHuffDecoder m_PosDecoder; - CHuffDecoder m_LenDecoder; - CHuffDecoder m_PowerDecoder; - CHuffDecoder m_DeltaDecoder; - - Int32 *_x86_history; - - HRESULT CodeReal(const Byte *in, size_t inSize, Byte *out, size_t outSize); -public: - CDecoder(); - ~CDecoder(); - - HRESULT Code(const Byte *in, size_t inSize, Byte *out, size_t outSize); - size_t GetUnpackSize() const { return _pos; } -}; - -}} - -#endif +// LzmsDecoder.h +// The code is based on LZMS description from wimlib code + +#ifndef ZIP7_INC_LZMS_DECODER_H +#define ZIP7_INC_LZMS_DECODER_H + +#include "../../../C/CpuArch.h" +#include "../../../C/HuffEnc.h" + +#include "HuffmanDecoder.h" + +namespace NCompress { +namespace NLzms { + +const unsigned k_NumLitSyms = 256; +const unsigned k_NumLenSyms = 54; +const unsigned k_NumPosSyms = 799; +const unsigned k_NumPowerSyms = 8; + +const unsigned k_NumProbBits = 6; +const unsigned k_ProbLimit = 1 << k_NumProbBits; +const unsigned k_InitialProb = 48; +const UInt32 k_InitialHist = 0x55555555; + +const unsigned k_NumReps = 3; + +const unsigned k_NumMainProbs = 16; +const unsigned k_NumMatchProbs = 32; +const unsigned k_NumRepProbs = 64; + +const unsigned k_NumHuffmanBits = 15; + +template +class CHuffDecoder: public NCompress::NHuffman::CDecoder +{ +public: + UInt32 RebuildRem; + UInt32 NumSyms; + UInt32 Freqs[m_NumSyms]; + + void Generate() throw() + { + UInt32 vals[m_NumSyms]; + Byte levels[m_NumSyms]; + + // We need to check that our algorithm is OK, when optimal Huffman tree uses more than 15 levels !!! + Huffman_Generate(Freqs, vals, levels, NumSyms, k_NumHuffmanBits); + + for (UInt32 i = NumSyms; i < m_NumSyms; i++) + levels[i] = 0; + + this->Build(levels, /* NumSyms, */ NHuffman::k_BuildMode_Full); + } + + void Rebuild() throw() + { + Generate(); + RebuildRem = m_RebuildFreq; + const UInt32 num = NumSyms; + for (UInt32 i = 0; i < num; i++) + Freqs[i] = (Freqs[i] >> 1) + 1; + } + +public: + void Init(UInt32 numSyms = m_NumSyms) throw() + { + RebuildRem = m_RebuildFreq; + NumSyms = numSyms; + for (UInt32 i = 0; i < numSyms; i++) + Freqs[i] = 1; + // for (; i < m_NumSyms; i++) Freqs[i] = 0; + Generate(); + } +}; + + +struct CProbEntry +{ + UInt32 Prob; + UInt64 Hist; + + void Init() + { + Prob = k_InitialProb; + Hist = k_InitialHist; + } + + UInt32 GetProb() const throw() + { + UInt32 prob = Prob; + if (prob == 0) + prob = 1; + else if (prob == k_ProbLimit) + prob = k_ProbLimit - 1; + return prob; + } + + void Update(unsigned bit) throw() + { + Prob += (UInt32)((Int32)(Hist >> (k_ProbLimit - 1)) - (Int32)bit); + Hist = (Hist << 1) | bit; + } +}; + + +struct CRangeDecoder +{ + UInt32 range; + UInt32 code; + const Byte *cur; + // const Byte *end; + + void Init(const Byte *data, size_t /* size */) throw() + { + range = 0xFFFFFFFF; + code = (((UInt32)GetUi16(data)) << 16) | GetUi16(data + 2); + cur = data + 4; + // end = data + size; + } + + void Normalize() + { + if (range <= 0xFFFF) + { + range <<= 16; + code <<= 16; + // if (cur >= end) throw 1; + code |= GetUi16(cur); + cur += 2; + } + } + + unsigned Decode(UInt32 *state, UInt32 numStates, struct CProbEntry *probs) + { + UInt32 st = *state; + CProbEntry *entry = &probs[st]; + st = (st << 1) & (numStates - 1); + + const UInt32 prob = entry->GetProb(); + + if (range <= 0xFFFF) + { + range <<= 16; + code <<= 16; + // if (cur >= end) throw 1; + code |= GetUi16(cur); + cur += 2; + } + + const UInt32 bound = (range >> k_NumProbBits) * prob; + + if (code < bound) + { + range = bound; + *state = st; + entry->Update(0); + return 0; + } + else + { + range -= bound; + code -= bound; + *state = st | 1; + entry->Update(1); + return 1; + } + } +}; + + +class CDecoder +{ + // CRangeDecoder _rc; + size_t _pos; + + UInt32 _reps[k_NumReps + 1]; + UInt64 _deltaReps[k_NumReps + 1]; + + UInt32 mainState; + UInt32 matchState; + UInt32 lzRepStates[k_NumReps]; + UInt32 deltaRepStates[k_NumReps]; + + struct CProbEntry mainProbs[k_NumMainProbs]; + struct CProbEntry matchProbs[k_NumMatchProbs]; + + struct CProbEntry lzRepProbs[k_NumReps][k_NumRepProbs]; + struct CProbEntry deltaRepProbs[k_NumReps][k_NumRepProbs]; + + CHuffDecoder m_LitDecoder; + CHuffDecoder m_PosDecoder; + CHuffDecoder m_LenDecoder; + CHuffDecoder m_PowerDecoder; + CHuffDecoder m_DeltaDecoder; + + Int32 *_x86_history; + + HRESULT CodeReal(const Byte *in, size_t inSize, Byte *out, size_t outSize); +public: + CDecoder(); + ~CDecoder(); + + HRESULT Code(const Byte *in, size_t inSize, Byte *out, size_t outSize); + size_t GetUnpackSize() const { return _pos; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Lzx.h b/CPP/7zip/Compress/Lzx.h index 93cb15c26..39fca0c83 100644 --- a/CPP/7zip/Compress/Lzx.h +++ b/CPP/7zip/Compress/Lzx.h @@ -1,61 +1,61 @@ -// Lzx.h - -#ifndef ZIP7_INC_COMPRESS_LZX_H -#define ZIP7_INC_COMPRESS_LZX_H - -#include "../../Common/MyTypes.h" - -namespace NCompress { -namespace NLzx { - -const unsigned kBlockType_NumBits = 3; -const unsigned kBlockType_Verbatim = 1; -const unsigned kBlockType_Aligned = 2; -const unsigned kBlockType_Uncompressed = 3; - -const unsigned kNumHuffmanBits = 16; -const unsigned kNumReps = 3; - -const unsigned kNumLenSlots = 8; -const unsigned kMatchMinLen = 2; -const unsigned kNumLenSymbols = 249; -const unsigned kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1; - -const unsigned kNumAlignLevelBits = 3; -const unsigned kNumAlignBits = 3; -const unsigned kAlignTableSize = 1 << kNumAlignBits; - -const unsigned kNumPosSlots = 50; -const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots; - -const unsigned kMainTableSize = 256 + kNumPosLenSlots; -const unsigned kLevelTableSize = 20; -const unsigned kMaxTableSize = kMainTableSize; - -const unsigned kNumLevelBits = 4; - -const unsigned kLevelSym_Zero1 = 17; -const unsigned kLevelSym_Zero2 = 18; -const unsigned kLevelSym_Same = 19; - -const unsigned kLevelSym_Zero1_Start = 4; -const unsigned kLevelSym_Zero1_NumBits = 4; - -const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits); -const unsigned kLevelSym_Zero2_NumBits = 5; - -const unsigned kLevelSym_Same_NumBits = 1; -const unsigned kLevelSym_Same_Start = 4; - -const unsigned kNumDictBits_Min = 15; -const unsigned kNumDictBits_Max = 21; -const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max; - -const unsigned kNumLinearPosSlotBits = 17; -// const unsigned kNumPowerPosSlots = 38; -// const unsigned kNumPowerPosSlots = (kNumLinearPosSlotBits + 1) * 2; // non-including two first linear slots. -const unsigned kNumPowerPosSlots = (kNumLinearPosSlotBits + 2) * 2; // including two first linear slots. - -}} - -#endif +// Lzx.h + +#ifndef ZIP7_INC_COMPRESS_LZX_H +#define ZIP7_INC_COMPRESS_LZX_H + +#include "../../Common/MyTypes.h" + +namespace NCompress { +namespace NLzx { + +const unsigned kBlockType_NumBits = 3; +const unsigned kBlockType_Verbatim = 1; +const unsigned kBlockType_Aligned = 2; +const unsigned kBlockType_Uncompressed = 3; + +const unsigned kNumHuffmanBits = 16; +const unsigned kNumReps = 3; + +const unsigned kNumLenSlots = 8; +const unsigned kMatchMinLen = 2; +const unsigned kNumLenSymbols = 249; +const unsigned kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1; + +const unsigned kNumAlignLevelBits = 3; +const unsigned kNumAlignBits = 3; +const unsigned kAlignTableSize = 1 << kNumAlignBits; + +const unsigned kNumPosSlots = 50; +const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots; + +const unsigned kMainTableSize = 256 + kNumPosLenSlots; +const unsigned kLevelTableSize = 20; +const unsigned kMaxTableSize = kMainTableSize; + +const unsigned kNumLevelBits = 4; + +const unsigned kLevelSym_Zero1 = 17; +const unsigned kLevelSym_Zero2 = 18; +const unsigned kLevelSym_Same = 19; + +const unsigned kLevelSym_Zero1_Start = 4; +const unsigned kLevelSym_Zero1_NumBits = 4; + +const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits); +const unsigned kLevelSym_Zero2_NumBits = 5; + +const unsigned kLevelSym_Same_NumBits = 1; +const unsigned kLevelSym_Same_Start = 4; + +const unsigned kNumDictBits_Min = 15; +const unsigned kNumDictBits_Max = 21; +const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max; + +const unsigned kNumLinearPosSlotBits = 17; +// const unsigned kNumPowerPosSlots = 38; +// const unsigned kNumPowerPosSlots = (kNumLinearPosSlotBits + 1) * 2; // non-including two first linear slots. +const unsigned kNumPowerPosSlots = (kNumLinearPosSlotBits + 2) * 2; // including two first linear slots. + +}} + +#endif diff --git a/CPP/7zip/Compress/LzxDecoder.cpp b/CPP/7zip/Compress/LzxDecoder.cpp index 583db067a..a7b9986c1 100644 --- a/CPP/7zip/Compress/LzxDecoder.cpp +++ b/CPP/7zip/Compress/LzxDecoder.cpp @@ -1,1517 +1,1517 @@ -// LzxDecoder.cpp - -#include "StdAfx.h" - -#include -// #include - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#define PRF(x) x -#else -#define PRF(x) -#endif - -#include "../../../C/Alloc.h" -#include "../../../C/RotateDefs.h" -#include "../../../C/CpuArch.h" - -#include "LzxDecoder.h" - - -#ifdef MY_CPU_X86_OR_AMD64 -#if defined(MY_CPU_AMD64) \ - || defined(__SSE2__) \ - || defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ - || 0 && defined(_MSC_VER) && (_MSC_VER >= 1400) // set (1 &&) for debug - -#if defined(__clang__) && (__clang_major__ >= 2) \ - || defined(__GNUC__) && (__GNUC__ >= 4) \ - || defined(_MSC_VER) && (_MSC_VER >= 1400) -#define Z7_LZX_X86_FILTER_USE_SSE2 -#endif -#endif -#endif - - -#ifdef Z7_LZX_X86_FILTER_USE_SSE2 -// #ifdef MY_CPU_X86_OR_AMD64 -#include // SSE2 -// #endif - #if defined(__clang__) || defined(__GNUC__) - typedef int ctz_type; - #define MY_CTZ(dest, mask) dest = __builtin_ctz((UInt32)(mask)) - #else // #if defined(_MSC_VER) - #if (_MSC_VER >= 1600) - // #include - #endif - typedef unsigned long ctz_type; - #define MY_CTZ(dest, mask) _BitScanForward(&dest, (mask)); - #endif // _MSC_VER -#endif - -// when window buffer is filled, we must wrap position to zero, -// and we want to wrap at same points where original-lzx must wrap. -// But the wrapping is possible in point where chunk is finished. -// Usually (chunk_size == 32KB), but (chunk_size != 32KB) also is allowed. -// So we don't use additional buffer space over required (winSize). -// And we can't use large overwrite after (len) in CopyLzMatch(). -// But we are allowed to write 3 bytes after (len), because -// (delta <= _winSize - 3). - -// #define k_Lz_OverwriteSize 0 // for debug : to disable overwrite -#define k_Lz_OverwriteSize 3 // = kNumReps -#if k_Lz_OverwriteSize > 0 -// (k_Lz_OutBufSize_Add >= k_Lz_OverwriteSize) is required -// we use value 4 to simplify memset() code. -#define k_Lz_OutBufSize_Add (k_Lz_OverwriteSize + 1) // == 4 -#else -#define k_Lz_OutBufSize_Add 0 -#endif - -// (len != 0) -// (0 < delta <= _winSize - 3) -Z7_FORCE_INLINE -void CopyLzMatch(Byte *dest, const Byte *src, UInt32 len, UInt32 delta) -{ - if (delta >= 4) - { -#if k_Lz_OverwriteSize >= 3 - // optimized code with overwrite to reduce the number of branches - #ifdef MY_CPU_LE_UNALIGN - *(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src); - #else - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; - dest[3] = src[3]; - #endif - len--; - src++; - dest++; - { -#else - // no overwrite in out buffer - dest[0] = src[0]; - { - const unsigned m = (unsigned)len & 1; - src += m; - dest += m; - } - if (len &= ~(unsigned)1) - { - dest[0] = src[0]; - dest[1] = src[1]; -#endif - // len == 0 is allowed here - { - const unsigned m = (unsigned)len & 3; - src += m; - dest += m; - } - if (len &= ~(unsigned)3) - { -#ifdef MY_CPU_LE_UNALIGN - #if 1 - *(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src); - { - const unsigned m = (unsigned)len & 7; - dest += m; - src += m; - } - if (len &= ~(unsigned)7) - do - { - *(UInt32 *)(void *)(dest ) = *(const UInt32 *)(const void *)(src); - *(UInt32 *)(void *)(dest + 4) = *(const UInt32 *)(const void *)(src + 4); - src += 8; - dest += 8; - } - while (len -= 8); - #else - // gcc-11 -O3 for x64 generates incorrect code here - do - { - *(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src); - src += 4; - dest += 4; - } - while (len -= 4); - #endif -#else - do - { - const Byte b0 = src[0]; - const Byte b1 = src[1]; - dest[0] = b0; - dest[1] = b1; - const Byte b2 = src[2]; - const Byte b3 = src[3]; - dest[2] = b2; - dest[3] = b3; - src += 4; - dest += 4; - } - while (len -= 4); -#endif - } - } - } - else // (delta < 4) - { - const unsigned b0 = *src; - *dest = (Byte)b0; - if (len >= 2) - { - if (delta < 2) - { - dest += (unsigned)len & 1; - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += (unsigned)len & 2; - if (len &= ~(unsigned)3) - { -#ifdef MY_CPU_LE_UNALIGN - #ifdef MY_CPU_64BIT - const UInt64 a = (UInt64)b0 * 0x101010101010101; - *(UInt32 *)(void *)dest = (UInt32)a; - dest += (unsigned)len & 7; - if (len &= ~(unsigned)7) - { - // *(UInt64 *)(void *)dest = a; - // dest += 8; - // len -= 8; - // if (len) - { - // const ptrdiff_t delta = (ptrdiff_t)dest & 7; - // dest -= delta; - do - { - *(UInt64 *)(void *)dest = a; - dest += 8; - } - while (len -= 8); - // dest += delta - 8; - // *(UInt64 *)(void *)dest = a; - } - } - #else - const UInt32 a = (UInt32)b0 * 0x1010101; - do - { - *(UInt32 *)(void *)dest = a; - dest += 4; - } - while (len -= 4); - #endif -#else - do - { - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest[2] = (Byte)b0; - dest[3] = (Byte)b0; - dest += 4; - } - while (len -= 4); -#endif - } - } - else if (delta == 2) - { - const unsigned m = (unsigned)len & 1; - len &= ~(unsigned)1; - src += m; - dest += m; - { - const Byte a0 = src[0]; - const Byte a1 = src[1]; - do - { - dest[0] = a0; - dest[1] = a1; - dest += 2; - } - while (len -= 2); - } - } - else /* if (delta == 3) */ - { - const unsigned b1 = src[1]; - dest[1] = (Byte)b1; - if (len -= 2) - { - const unsigned b2 = src[2]; - dest += 2; - do - { - dest[0] = (Byte)b2; if (--len == 0) break; - dest[1] = (Byte)b0; if (--len == 0) break; - dest[2] = (Byte)b1; - dest += 3; - } - while (--len); - } - } - } - } -} - -// #define Z7_LZX_SHOW_STAT -#ifdef Z7_LZX_SHOW_STAT -#include -#endif - -namespace NCompress { -namespace NLzx { - -// #define Z7_LZX_SHOW_STAT -#ifdef Z7_LZX_SHOW_STAT -static UInt32 g_stats_Num_x86[3]; -static UInt32 g_stats_NumTables; -static UInt32 g_stats_NumLits; -static UInt32 g_stats_NumAlign; -static UInt32 g_stats_main[kMainTableSize]; -static UInt32 g_stats_len[kNumLenSymbols]; -static UInt32 g_stats_main_levels[kNumHuffmanBits + 1]; -static UInt32 g_stats_len_levels[kNumHuffmanBits + 1]; -#define UPDATE_STAT(a) a -static void PrintVal(UInt32 v) -{ - printf("\n : %9u", v); -} -static void PrintStat(const char *name, const UInt32 *a, size_t num) -{ - printf("\n\n==== %s:", name); - UInt32 sum = 0; - size_t i; - for (i = 0; i < num; i++) - sum += a[i]; - PrintVal(sum); - if (sum != 0) - { - for (i = 0; i < num; i++) - { - if (i % 8 == 0) - printf("\n"); - printf("\n%3x : %9u : %5.2f", (unsigned)i, (unsigned)a[i], (double)a[i] * 100 / sum); - } - } - printf("\n"); -} - -static struct CStat -{ - ~CStat() - { - PrintStat("x86_filter", g_stats_Num_x86, Z7_ARRAY_SIZE(g_stats_Num_x86)); - printf("\nTables:"); PrintVal(g_stats_NumTables); - printf("\nLits:"); PrintVal(g_stats_NumLits); - printf("\nAlign:"); PrintVal(g_stats_NumAlign); - PrintStat("Main", g_stats_main, Z7_ARRAY_SIZE(g_stats_main)); - PrintStat("Len", g_stats_len, Z7_ARRAY_SIZE(g_stats_len)); - PrintStat("Main Levels", g_stats_main_levels, Z7_ARRAY_SIZE(g_stats_main_levels)); - PrintStat("Len Levels", g_stats_len_levels, Z7_ARRAY_SIZE(g_stats_len_levels)); - } -} g_stat; -#else -#define UPDATE_STAT(a) -#endif - - - -/* -3 p015 : ivb- : or r32,r32 / add r32,r32 -4 p0156 : hsw+ -5 p0156b: adl+ -2 p0_5 : ivb- : shl r32,i8 -2 p0__6 : hsw+ -1 p5 : ivb- : jb -2 p0__6 : hsw+ -2 p0_5 : wsm- : SSE2 : pcmpeqb : _mm_cmpeq_epi8 -2 p_15 : snb-bdw -2 p01 : skl+ -1 p0 : SSE2 : pmovmskb : _mm_movemask_epi8 -*/ -/* - v24.00: the code was fixed for more compatibility with original-ms-cab-decoder. - for ((Int32)translationSize >= 0) : LZX specification shows the code with signed Int32. - for ((Int32)translationSize < 0) : no specification for that case, but we support that case. - We suppose our code now is compatible with original-ms-cab-decoder. - - Starting byte of data stream (real_pos == 0) is special corner case, - where we don't need any conversion (as in original-ms-cab-decoder). - Our optimization: we use unsigned (UInt32 pos) (pos = -1 - real_pos). - So (pos) is always negative: ((Int32)pos < 0). - It allows us to use simple comparison (v > pos) instead of more complex comparisons. -*/ -// (p) will point 5 bytes after 0xe8 byte: -// pos == -1 - (p - 5 - data_start) == 4 + data_start - p -// (FILTER_PROCESSED_SIZE_DELTA == 4) is optimized value for better speed in some compilers: -#define FILTER_PROCESSED_SIZE_DELTA 4 - -#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_OR_ARM64) - // optimized branch: - // size_t must be at least 32-bit for this branch. - #if 1 // use 1 for simpler code - // use integer (low 32 bits of pointer) instead of pointer - #define X86_FILTER_PREPARE processedSize4 = (UInt32)(size_t)(ptrdiff_t)data + \ - (UInt32)(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4; - #define X86_FILTER_CALC_pos(p) const UInt32 pos = processedSize4 - (UInt32)(size_t)(ptrdiff_t)p; - #else - // note: (dataStart) pointer can point out of array ranges: - #define X86_FILTER_PREPARE const Byte *dataStart = data + \ - (4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4; - #define X86_FILTER_CALC_pos(p) const UInt32 pos = (UInt32)(size_t)(dataStart - p); - #endif -#else - // non-optimized branch for unusual platforms (16-bit size_t or unusual size_t): - #define X86_FILTER_PREPARE processedSize4 = \ - (UInt32)(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4; - #define X86_FILTER_CALC_pos(p) const UInt32 pos = processedSize4 - (UInt32)(size_t)(p - data); -#endif - -#define X86_TRANSLATE_PRE(p) \ - UInt32 v = GetUi32((p) - 4); - -#define X86_TRANSLATE_POST(p) \ - { \ - X86_FILTER_CALC_pos(p) \ - if (v < translationSize) { \ - UPDATE_STAT(g_stats_Num_x86[0]++;) \ - v += pos + 1; \ - SetUi32((p) - 4, v) \ - } \ - else if (v > pos) { \ - UPDATE_STAT(g_stats_Num_x86[1]++;) \ - v += translationSize; \ - SetUi32((p) - 4, v) \ - } else { UPDATE_STAT(g_stats_Num_x86[2]++;) } \ - } - - -/* - if ( defined(Z7_LZX_X86_FILTER_USE_SSE2) - && defined(Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED)) - the function can read up to aligned_for_32_up_from(size) bytes in (data). -*/ -// processedSize < (1 << 30) -Z7_NO_INLINE -static void x86_Filter4(Byte *data, size_t size, UInt32 processedSize4, UInt32 translationSize) -{ - const size_t kResidue = 10; - if (size <= kResidue) - return; - Byte * const lim = data + size - kResidue + 4; - const Byte save = lim[0]; - lim[0] = 0xe8; - X86_FILTER_PREPARE - Byte *p = data; - -#define FILTER_RETURN_IF_LIM(_p_) if (_p_ > lim) { lim[0] = save; return; } - -#ifdef Z7_LZX_X86_FILTER_USE_SSE2 - -// sse2-aligned/sse2-unaligned provide same speed on real data. -// but the code is smaller for sse2-unaligned version. -// for debug : define it to get alternative version with aligned 128-bit reads: -// #define Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED - -#define FILTER_MASK_INT UInt32 -#define FILTER_NUM_VECTORS_IN_CHUNK 2 -#define FILTER_CHUNK_BYTES_OFFSET (16 * FILTER_NUM_VECTORS_IN_CHUNK - 5) - -#ifdef Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED - // aligned version doesn't uses additional space if buf size is aligned for 32 - #define k_Filter_OutBufSize_Add 0 - #define k_Filter_OutBufSize_AlignMask (16 * FILTER_NUM_VECTORS_IN_CHUNK - 1) - #define FILTER_LOAD_128(p) _mm_load_si128 ((const __m128i *)(const void *)(p)) -#else - #define k_Filter_OutBufSize_Add (16 * FILTER_NUM_VECTORS_IN_CHUNK) - #define k_Filter_OutBufSize_AlignMask 0 - #define FILTER_LOAD_128(p) _mm_loadu_si128((const __m128i *)(const void *)(p)) -#endif - -#define GET_E8_MASK(dest, dest1, p) \ -{ \ - __m128i v0 = FILTER_LOAD_128(p); \ - __m128i v1 = FILTER_LOAD_128(p + 16); \ - p += 16 * FILTER_NUM_VECTORS_IN_CHUNK; \ - v0 = _mm_cmpeq_epi8(v0, k_e8_Vector); \ - v1 = _mm_cmpeq_epi8(v1, k_e8_Vector); \ - dest = (unsigned)_mm_movemask_epi8(v0); \ - dest1 = (unsigned)_mm_movemask_epi8(v1); \ -} - - const __m128i k_e8_Vector = _mm_set1_epi32((Int32)(UInt32)0xe8e8e8e8); - for (;;) - { - // for debug: define it for smaller code: - // #define Z7_LZX_X86_FILTER_CALC_IN_LOOP - // without Z7_LZX_X86_FILTER_CALC_IN_LOOP, we can get faster and simpler loop - FILTER_MASK_INT mask; - { - FILTER_MASK_INT mask1; - do - { - GET_E8_MASK(mask, mask1, p) - #ifndef Z7_LZX_X86_FILTER_CALC_IN_LOOP - mask += mask1; - #else - mask |= mask1 << 16; - #endif - } - while (!mask); - - #ifndef Z7_LZX_X86_FILTER_CALC_IN_LOOP - mask -= mask1; - mask |= mask1 << 16; - #endif - } - -#ifdef Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED - for (;;) - { - ctz_type index; - typedef - #ifdef MY_CPU_64BIT - UInt64 - #else - UInt32 - #endif - SUPER_MASK_INT; - SUPER_MASK_INT superMask; - { - MY_CTZ(index, mask); - Byte *p2 = p - FILTER_CHUNK_BYTES_OFFSET + (unsigned)index; - X86_TRANSLATE_PRE(p2) - superMask = ~(SUPER_MASK_INT)0x1f << index; - FILTER_RETURN_IF_LIM(p2) - X86_TRANSLATE_POST(p2) - mask &= (UInt32)superMask; - } - if (mask) - continue; - if (index <= FILTER_CHUNK_BYTES_OFFSET) - break; - { - FILTER_MASK_INT mask1; - GET_E8_MASK(mask, mask1, p) - mask &= - #ifdef MY_CPU_64BIT - (UInt32)(superMask >> 32); - #else - ((FILTER_MASK_INT)0 - 1) << ((int)index - FILTER_CHUNK_BYTES_OFFSET); - #endif - mask |= mask1 << 16; - } - if (!mask) - break; - } -#else // ! Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED - { - // we use simplest version without loop: - // for (;;) - { - ctz_type index; - MY_CTZ(index, mask); - /* - printf("\np=%p, mask=%8x, index = %2d, p + index = %x\n", - (p - 16 * FILTER_NUM_VECTORS_IN_CHUNK), (unsigned)mask, - (unsigned)index, (unsigned)((unsigned)(ptrdiff_t)(p - 16 * FILTER_NUM_VECTORS_IN_CHUNK) + index)); - */ - p += (size_t)(unsigned)index - FILTER_CHUNK_BYTES_OFFSET; - FILTER_RETURN_IF_LIM(p) - // mask &= ~(FILTER_MASK_INT)0x1f << index; mask >>= index; - X86_TRANSLATE_PRE(p) - X86_TRANSLATE_POST(p) - // if (!mask) break; // p += 16 * FILTER_NUM_VECTORS_IN_CHUNK; - } - } -#endif // ! Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED - } - -#else // ! Z7_LZX_X86_FILTER_USE_SSE2 - -#define k_Filter_OutBufSize_Add 0 -#define k_Filter_OutBufSize_AlignMask 0 - - - for (;;) - { - for (;;) - { - if (p[0] == 0xe8) { p += 5; break; } - if (p[1] == 0xe8) { p += 6; break; } - if (p[2] == 0xe8) { p += 7; break; } - p += 4; - if (p[-1] == 0xe8) { p += 4; break; } - } - FILTER_RETURN_IF_LIM(p) - X86_TRANSLATE_PRE(p) - X86_TRANSLATE_POST(p) - } - -#endif // ! Z7_LZX_X86_FILTER_USE_SSE2 -} - - -CDecoder::CDecoder() throw(): - _win(NULL), - _isUncompressedBlock(false), - _skipByte(false), - _keepHistory(false), - _keepHistoryForNext(true), - _needAlloc(true), - _wimMode(false), - _numDictBits(15), - _unpackBlockSize(0), - _x86_translationSize(0), - _x86_buf(NULL), - _unpackedData(NULL) -{ - { - // it's better to get empty virtual entries, if mispredicted value can be used: - memset(_reps, 0, kPosSlotOffset * sizeof(_reps[0])); - memset(_extra, 0, kPosSlotOffset); -#define SET_NUM_BITS(i) i // #define NUM_BITS_DELTA 31 - _extra[kPosSlotOffset + 0] = SET_NUM_BITS(0); - _extra[kPosSlotOffset + 1] = SET_NUM_BITS(0); - // reps[0] = 0 - (kNumReps - 1); - // reps[1] = 1 - (kNumReps - 1); - UInt32 a = 2 - (kNumReps - 1); - UInt32 delta = 1; - unsigned i; - for (i = 0; i < kNumLinearPosSlotBits; i++) - { - _extra[(size_t)i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); - _extra[(size_t)i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); - _reps [(size_t)i * 2 + 2 + kPosSlotOffset] = a; a += delta; - _reps [(size_t)i * 2 + 3 + kPosSlotOffset] = a; a += delta; - delta += delta; - } - for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++) - { - _extra[(size_t)i + kPosSlotOffset] = SET_NUM_BITS(kNumLinearPosSlotBits); - _reps [(size_t)i + kPosSlotOffset] = a; - a += (UInt32)1 << kNumLinearPosSlotBits; - } - } -} - -CDecoder::~CDecoder() throw() -{ - if (_needAlloc) - // BigFree - z7_AlignedFree - (_win); - z7_AlignedFree(_x86_buf); -} - -HRESULT CDecoder::Flush() throw() -{ - // UInt32 t = _x86_processedSize; for (int y = 0; y < 50; y++) { _x86_processedSize = t; // benchmark: (branch predicted) - if (_x86_translationSize != 0) - { - Byte *destData = _win + _writePos; - const UInt32 curSize = _pos - _writePos; - if (_keepHistoryForNext) - { - const size_t kChunkSize = (size_t)1 << 15; - if (curSize > kChunkSize) - return E_NOTIMPL; - if (!_x86_buf) - { - // (kChunkSize % 32 == 0) is required in some cases, because - // the filter can read data by 32-bytes chunks in some cases. - // if (chunk_size > (1 << 15)) is possible, then we must the code: - const size_t kAllocSize = kChunkSize + k_Filter_OutBufSize_Add; - _x86_buf = (Byte *)z7_AlignedAlloc(kAllocSize); - if (!_x86_buf) - return E_OUTOFMEMORY; - #if 0 != k_Filter_OutBufSize_Add || \ - 0 != k_Filter_OutBufSize_AlignMask - // x86_Filter4() can read after curSize. - // So we set all data to zero to prevent reading of uninitialized data: - memset(_x86_buf, 0, kAllocSize); // optional - #endif - } - // for (int yy = 0; yy < 1; yy++) // for debug - memcpy(_x86_buf, destData, curSize); - _unpackedData = _x86_buf; - destData = _x86_buf; - } - else - { - // x86_Filter4() can overread after (curSize), - // so we can do memset() after (curSize): - // k_Filter_OutBufSize_AlignMask also can be used - // if (!_overDict) memset(destData + curSize, 0, k_Filter_OutBufSize_Add); - } - x86_Filter4(destData, curSize, _x86_processedSize - FILTER_PROCESSED_SIZE_DELTA, _x86_translationSize); - _x86_processedSize += (UInt32)curSize; - if (_x86_processedSize >= ((UInt32)1 << 30)) - _x86_translationSize = 0; - } - // } - return S_OK; -} - - - -// (NUM_DELTA_BYTES == 2) reduces the code in main loop. -#if 1 - #define NUM_DELTA_BYTES 2 -#else - #define NUM_DELTA_BYTES 0 -#endif - -#define NUM_DELTA_BIT_OFFSET_BITS (NUM_DELTA_BYTES * 8) - -#if NUM_DELTA_BIT_OFFSET_BITS > 0 - #define DECODE_ERROR_CODE 0 - #define IS_OVERFLOW_bitOffset(bo) ((bo) >= 0) - // ( >= 0) comparison after bitOffset change gives simpler commands than ( > 0) comparison -#else - #define DECODE_ERROR_CODE 1 - #define IS_OVERFLOW_bitOffset(bo) ((bo) > 0) -#endif - -// (numBits != 0) -#define GET_VAL_BASE(numBits) (_value >> (32 - (numBits))) - -#define Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, check_op, error_op) \ - Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huff, kNumHuffmanBits, kNumTableBits, \ - _value, check_op, error_op, move_pos_op, NORMALIZE, bs) - -#define Z7_LZX_HUFF_DECODE_CHECK_YES(sym, huff, kNumTableBits, move_pos_op) \ - Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, \ - Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, { return DECODE_ERROR_CODE; }) - -#define Z7_LZX_HUFF_DECODE_CHECK_NO( sym, huff, kNumTableBits, move_pos_op) \ - Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, \ - Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}) - -#define NORMALIZE \ -{ \ - const Byte *ptr = _buf + (_bitOffset >> 4) * 2; \ - /* _value = (((UInt32)GetUi16(ptr) << 16) | GetUi16(ptr + 2)) << (_bitOffset & 15); */ \ - const UInt32 v = GetUi32(ptr); \ - _value = rotlFixed (v, ((int)_bitOffset & 15) + 16); \ -} - -#define MOVE_POS(bs, numBits) \ -{ \ - _bitOffset += numBits; \ -} - -#define MOVE_POS_STAT(bs, numBits) \ -{ \ - UPDATE_STAT(g_stats_len_levels[numBits]++;) \ - MOVE_POS(bs, numBits); \ -} - -#define MOVE_POS_CHECK(bs, numBits) \ -{ \ - if (IS_OVERFLOW_bitOffset(_bitOffset += numBits)) return DECODE_ERROR_CODE; \ -} - -#define MOVE_POS_CHECK_STAT(bs, numBits) \ -{ \ - UPDATE_STAT(g_stats_main_levels[numBits]++;) \ - MOVE_POS_CHECK(bs, numBits) \ -} - - -// (numBits == 0) is supported - -#ifdef Z7_HUFF_USE_64BIT_LIMIT - -#define MACRO_ReadBitsBig_pre(numBits) \ -{ \ - _bitOffset += (numBits); \ - _value >>= 32 - (numBits); \ -} - -#else - -#define MACRO_ReadBitsBig_pre(numBits) \ -{ \ - _bitOffset += (numBits); \ - _value = (UInt32)((UInt32)_value >> 1 >> (31 ^ (numBits))); \ -} - -#endif - - -#define MACRO_ReadBitsBig_add(dest) \ - { dest += (UInt32)_value; } - -#define MACRO_ReadBitsBig_add3(dest) \ - { dest += (UInt32)(_value) << 3; } - - -// (numBits != 0) -#define MACRO_ReadBits_NonZero(val, numBits) \ -{ \ - val = (UInt32)(_value >> (32 - (numBits))); \ - MOVE_POS(bs, numBits); \ - NORMALIZE \ -} - - -struct CBitDecoder -{ - ptrdiff_t _bitOffset; - const Byte *_buf; - - Z7_FORCE_INLINE - UInt32 GetVal() const - { - const Byte *ptr = _buf + (_bitOffset >> 4) * 2; - const UInt32 v = GetUi32(ptr); - return rotlFixed (v, ((int)_bitOffset & 15) + 16); - } - - Z7_FORCE_INLINE - bool IsOverRead() const - { - return _bitOffset > (int)(0 - NUM_DELTA_BIT_OFFSET_BITS); - } - - - Z7_FORCE_INLINE - bool WasBitStreamFinishedOK() const - { - // we check that all 0-15 unused bits are zeros: - if (_bitOffset == 0 - NUM_DELTA_BIT_OFFSET_BITS) - return true; - if ((_bitOffset + NUM_DELTA_BIT_OFFSET_BITS + 15) & ~(ptrdiff_t)15) - return false; - const Byte *ptr = _buf - NUM_DELTA_BYTES - 2; - if ((UInt16)(GetUi16(ptr) << (_bitOffset & 15))) - return false; - return true; - } - - // (numBits != 0) - Z7_FORCE_INLINE - UInt32 ReadBits_NonZero(unsigned numBits) throw() - { - const UInt32 val = GetVal() >> (32 - numBits); - _bitOffset += numBits; - return val; - } -}; - - -class CBitByteDecoder: public CBitDecoder -{ - size_t _size; -public: - - Z7_FORCE_INLINE - void Init_ByteMode(const Byte *data, size_t size) - { - _buf = data; - _size = size; - } - - Z7_FORCE_INLINE - void Init_BitMode(const Byte *data, size_t size) - { - _size = size & 1; - size &= ~(size_t)1; - _buf = data + size + NUM_DELTA_BYTES; - _bitOffset = 0 - (ptrdiff_t)(size * 8) - NUM_DELTA_BIT_OFFSET_BITS; - } - - Z7_FORCE_INLINE - void Switch_To_BitMode() - { - Init_BitMode(_buf, _size); - } - - Z7_FORCE_INLINE - bool Switch_To_ByteMode() - { - /* here we check that unused bits in high 16-bits word are zeros. - If high word is full (all 16-bits are unused), - we check that all 16-bits are zeros. - So we check and skip (1-16 bits) unused bits */ - if ((GetVal() >> (16 + (_bitOffset & 15))) != 0) - return false; - _bitOffset += 16; - _bitOffset &= ~(ptrdiff_t)15; - if (_bitOffset > 0 - NUM_DELTA_BIT_OFFSET_BITS) - return false; - const ptrdiff_t delta = _bitOffset >> 3; - _size = (size_t)((ptrdiff_t)(_size) - delta - NUM_DELTA_BYTES); - _buf += delta; - // _bitOffset = 0; // optional - return true; - } - - Z7_FORCE_INLINE - size_t GetRem() const { return _size; } - - Z7_FORCE_INLINE - UInt32 ReadUInt32() - { - const Byte *ptr = _buf; - const UInt32 v = GetUi32(ptr); - _buf += 4; - _size -= 4; - return v; - } - - Z7_FORCE_INLINE - void CopyTo(Byte *dest, size_t size) - { - memcpy(dest, _buf, size); - _buf += size; - _size -= size; - } - - Z7_FORCE_INLINE - bool IsOneDirectByteLeft() const - { - return GetRem() == 1; - } - - Z7_FORCE_INLINE - Byte DirectReadByte() - { - _size--; - return *_buf++; - } -}; - - -// numBits != 0 -// Z7_FORCE_INLINE -Z7_NO_INLINE -static -UInt32 ReadBits(CBitDecoder &_bitStream, unsigned numBits) -{ - return _bitStream.ReadBits_NonZero(numBits); -} - -#define RIF(x) { if (!(x)) return false; } - - -/* -MSVC compiler adds extra move operation, - if we access array with 32-bit index - array[calc_index_32_bit(32-bit_var)] - where calc_index_32_bit operations are: ((unsigned)a>>cnt), &, ^, | - clang is also affected for ((unsigned)a>>cnt) in byte array. -*/ - -// it can overread input buffer for 7-17 bytes. -// (levels != levelsEnd) -Z7_NO_INLINE -static ptrdiff_t ReadTable(ptrdiff_t _bitOffset, const Byte *_buf, Byte *levels, const Byte *levelsEnd) -{ - const unsigned kNumTableBits_Level = 7; - NHuffman::CDecoder256 _levelDecoder; - NHuffman::CValueInt _value; - // optional check to reduce size of overread zone: - if (_bitOffset > (int)0 - (int)NUM_DELTA_BIT_OFFSET_BITS - (int)(kLevelTableSize * kNumLevelBits)) - return DECODE_ERROR_CODE; - NORMALIZE - { - Byte levels2[kLevelTableSize / 4 * 4]; - for (size_t i = 0; i < kLevelTableSize / 4 * 4; i += 4) - { - UInt32 val; - MACRO_ReadBits_NonZero(val, kNumLevelBits * 4) - levels2[i + 0] = (Byte)((val >> (3 * kNumLevelBits))); - levels2[i + 1] = (Byte)((val >> (2 * kNumLevelBits)) & ((1u << kNumLevelBits) - 1)); - levels2[i + 2] = (Byte)((Byte)val >> (1 * kNumLevelBits)); - levels2[i + 3] = (Byte)((val) & ((1u << kNumLevelBits) - 1)); - } - RIF(_levelDecoder.Build(levels2, NHuffman::k_BuildMode_Full)) - } - - do - { - unsigned sym; - Z7_LZX_HUFF_DECODE_CHECK_NO(sym, &_levelDecoder, kNumTableBits_Level, MOVE_POS_CHECK) - // Z7_HUFF_DECODE_CHECK(sym, &_levelDecoder, kNumHuffmanBits, kNumTableBits_Level, &bitStream, return false) - // sym = _levelDecoder.Decode(&bitStream); - // if (!_levelDecoder.Decode_SymCheck_MovePosCheck(&bitStream, sym)) return false; - - if (sym <= kNumHuffmanBits) - { - int delta = (int)*levels - (int)sym; - delta += delta < 0 ? kNumHuffmanBits + 1 : 0; - *levels++ = (Byte)delta; - continue; - } - - unsigned num; - int symbol; - - if (sym < kLevelSym_Same) - { - // sym -= kLevelSym_Zero1; - MACRO_ReadBits_NonZero(num, kLevelSym_Zero1_NumBits + (sym - kLevelSym_Zero1)) - num += (sym << kLevelSym_Zero1_NumBits) - (kLevelSym_Zero1 << kLevelSym_Zero1_NumBits) + kLevelSym_Zero1_Start; - symbol = 0; - } - // else if (sym != kLevelSym_Same) return DECODE_ERROR_CODE; - else // (sym == kLevelSym_Same) - { - MACRO_ReadBits_NonZero(num, kLevelSym_Same_NumBits) - num += kLevelSym_Same_Start; - // + (unsigned)bitStream.ReadBitsSmall(kLevelSym_Same_NumBits); - // Z7_HUFF_DECODE_CHECK(sym, &_levelDecoder, kNumHuffmanBits, kNumTableBits_Level, &bitStream, return DECODE_ERROR_CODE) - // if (!_levelDecoder.Decode2(&bitStream, sym)) return DECODE_ERROR_CODE; - // sym = _levelDecoder.Decode(&bitStream); - - Z7_LZX_HUFF_DECODE_CHECK_NO(sym, &_levelDecoder, kNumTableBits_Level, MOVE_POS) - - if (sym > kNumHuffmanBits) return DECODE_ERROR_CODE; - symbol = *levels - (int)sym; - symbol += symbol < 0 ? kNumHuffmanBits + 1 : 0; - } - - if (num > (size_t)(levelsEnd - levels)) - return false; - const Byte *limit = levels + num; - do - *levels++ = (Byte)symbol; - while (levels != limit); - } - while (levels != levelsEnd); - - return _bitOffset; -} - - -static const unsigned kPosSlotDelta = 256 / kNumLenSlots - kPosSlotOffset; - - -#define READ_TABLE(_bitStream, levels, levelsEnd) \ -{ \ - _bitStream._bitOffset = ReadTable(_bitStream._bitOffset, _bitStream._buf, levels, levelsEnd); \ - if (_bitStream.IsOverRead()) return false; \ -} - -// can over-read input buffer for less than 32 bytes -bool CDecoder::ReadTables(CBitByteDecoder &_bitStream) throw() -{ - UPDATE_STAT(g_stats_NumTables++;) - { - const unsigned blockType = (unsigned)ReadBits(_bitStream, kBlockType_NumBits); - // if (blockType > kBlockType_Uncompressed || blockType == 0) - if ((unsigned)(blockType - 1) > kBlockType_Uncompressed - 1) - return false; - _unpackBlockSize = 1u << 15; - if (!_wimMode || ReadBits(_bitStream, 1) == 0) - { - _unpackBlockSize = ReadBits(_bitStream, 16); - // wimlib supports chunks larger than 32KB (unsupported my MS wim). - if (!_wimMode || _numDictBits >= 16) - { - _unpackBlockSize <<= 8; - _unpackBlockSize |= ReadBits(_bitStream, 8); - } - } - - PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " ")); - - _isUncompressedBlock = (blockType == kBlockType_Uncompressed); - _skipByte = false; - - if (_isUncompressedBlock) - { - _skipByte = ((_unpackBlockSize & 1) != 0); - // printf("\n UncompressedBlock %d", _unpackBlockSize); - PRF(printf(" UncompressedBlock ");) - // if (_unpackBlockSize & 1) { PRF(printf(" ######### ")); } - if (!_bitStream.Switch_To_ByteMode()) - return false; - if (_bitStream.GetRem() < kNumReps * 4) - return false; - for (unsigned i = 0; i < kNumReps; i++) - { - const UInt32 rep = _bitStream.ReadUInt32(); - // here we allow only such values for (rep) that can be set also by LZ code: - if (rep == 0 || rep > _winSize - kNumReps) - return false; - _reps[(size_t)i + kPosSlotOffset] = rep; - } - // printf("\n"); - return true; - } - - // _numAlignBits = 64; - // const UInt32 k_numAlignBits_PosSlots_MAX = 64 + kPosSlotDelta; - // _numAlignBits_PosSlots = k_numAlignBits_PosSlots_MAX; - const UInt32 k_numAlignBits_Dist_MAX = (UInt32)(Int32)-1; - _numAlignBits_Dist = k_numAlignBits_Dist_MAX; - if (blockType == kBlockType_Aligned) - { - Byte levels[kAlignTableSize]; - // unsigned not0 = 0; - unsigned not3 = 0; - for (unsigned i = 0; i < kAlignTableSize; i++) - { - const unsigned val = ReadBits(_bitStream, kNumAlignLevelBits); - levels[i] = (Byte)val; - // not0 |= val; - not3 |= (val ^ 3); - } - // static unsigned number = 0, all = 0; all++; - // if (!not0) return false; // Build(true) will test this case - if (not3) - { - // _numAlignBits_PosSlots = (kNumAlignBits + 1) * 2 + kPosSlotDelta; - // _numAlignBits = kNumAlignBits; - _numAlignBits_Dist = (1u << (kNumAlignBits + 1)) - (kNumReps - 1); - RIF(_alignDecoder.Build(levels, true)) // full - } - // else { number++; if (number % 4 == 0) printf("\nnumber= %u : %u%%", number, number * 100 / all); } - } - // if (_numAlignBits_PosSlots == k_numAlignBits_PosSlots_MAX) - if (_numAlignBits_Dist == k_numAlignBits_Dist_MAX) - { - size_t i; - for (i = 3; i < kNumLinearPosSlotBits; i++) - { - _extra[i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); - _extra[i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); - } - for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++) - _extra[i + kPosSlotOffset] = (Byte)SET_NUM_BITS(kNumLinearPosSlotBits); - } - else - { - size_t i; - for (i = 3; i < kNumLinearPosSlotBits; i++) - { - _extra[i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i) - 3); - _extra[i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i) - 3); - } - for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++) - _extra[i + kPosSlotOffset] = (Byte)(SET_NUM_BITS(kNumLinearPosSlotBits) - 3); - } - } - - READ_TABLE(_bitStream, _mainLevels, _mainLevels + 256) - READ_TABLE(_bitStream, _mainLevels + 256, _mainLevels + 256 + _numPosLenSlots) - const unsigned end = 256 + _numPosLenSlots; - memset(_mainLevels + end, 0, kMainTableSize - end); - // #define NUM_CYC 1 - // unsigned j; for (j = 0; j < NUM_CYC; j++) - RIF(_mainDecoder.Build(_mainLevels, NHuffman::k_BuildMode_Full)) - // if (kNumLenSymols_Big_Start) - memset(_lenLevels, 0, kNumLenSymols_Big_Start); - READ_TABLE(_bitStream, - _lenLevels + kNumLenSymols_Big_Start, - _lenLevels + kNumLenSymols_Big_Start + kNumLenSymbols) - // for (j = 0; j < NUM_CYC; j++) - RIF(_lenDecoder.Build(_lenLevels, NHuffman::k_BuildMode_Full_or_Empty)) - return true; -} - - - -static ptrdiff_t CodeLz(CDecoder *dec, size_t next, ptrdiff_t _bitOffset, const Byte *_buf) throw() -{ - { - Byte *const win = dec->_win; - const UInt32 winSize = dec->_winSize; - Byte *pos = win + dec->_pos; - const Byte * const posEnd = pos + next; - NHuffman::CValueInt _value; - - NORMALIZE - -#if 1 - #define HUFF_DEC_PREFIX dec-> -#else - const NHuffman::CDecoder _mainDecoder = dec->_mainDecoder; - const NHuffman::CDecoder256 _lenDecoder = dec->_lenDecoder; - const NHuffman::CDecoder7b _alignDecoder = dec->_alignDecoder; - #define HUFF_DEC_PREFIX -#endif - - do - { - unsigned sym; - // printf("\npos = %6u", pos - win); - { - const NHuffman::CDecoder - *mainDecoder = & HUFF_DEC_PREFIX _mainDecoder; - Z7_LZX_HUFF_DECODE_CHECK_NO(sym, mainDecoder, kNumTableBits_Main, MOVE_POS_CHECK_STAT) - } - // if (!_mainDecoder.Decode_SymCheck_MovePosCheck(&bitStream, sym)) return DECODE_ERROR_CODE; - // sym = _mainDecoder.Decode(&bitStream); - // if (bitStream.WasExtraReadError_Fast()) return DECODE_ERROR_CODE; - - // printf(" sym = %3x", sym); - UPDATE_STAT(g_stats_main[sym]++;) - - if (sym < 256) - { - UPDATE_STAT(g_stats_NumLits++;) - *pos++ = (Byte)sym; - } - else - { - // sym -= 256; - // if (sym >= _numPosLenSlots) return DECODE_ERROR_CODE; - const unsigned posSlot = sym / kNumLenSlots; - unsigned len = sym % kNumLenSlots + kMatchMinLen; - if (len == kNumLenSlots - 1 + kMatchMinLen) - { - const NHuffman::CDecoder256 - *lenDecoder = & HUFF_DEC_PREFIX _lenDecoder; - Z7_LZX_HUFF_DECODE_CHECK_YES(len, lenDecoder, kNumTableBits_Len, MOVE_POS_STAT) - // if (!_lenDecoder.Decode2(&bitStream, len)) return DECODE_ERROR_CODE; - // len = _lenDecoder.Decode(&bitStream); - // if (len >= kNumLenSymbols) return DECODE_ERROR_CODE; - UPDATE_STAT(g_stats_len[len - kNumLenSymols_Big_Start]++;) - len += kNumLenSlots - 1 + kMatchMinLen - kNumLenSymols_Big_Start; - } - /* - if ((next -= len) < 0) - return DECODE_ERROR_CODE; - */ - UInt32 dist; - - dist = dec->_reps[(size_t)posSlot - kPosSlotDelta]; - if (posSlot < kNumReps + 256 / kNumLenSlots) - { - // if (posSlot != kNumReps + kPosSlotDelta) - // if (posSlot - (kNumReps + kPosSlotDelta + 1) < 2) - dec->_reps[(size_t)posSlot - kPosSlotDelta] = dec->_reps[kPosSlotOffset]; - /* - if (posSlot != kPosSlotDelta) - { - UInt32 temp = dist; - if (posSlot == kPosSlotDelta + 1) - { - dist = reps[1]; - reps[1] = temp; - } - else - { - dist = reps[2]; - reps[2] = temp; - } - // dist = reps[(size_t)(posSlot) - kPosSlotDelta]; - // reps[(size_t)(posSlot) - kPosSlotDelta] = reps[0]; - // reps[(size_t)(posSlot) - kPosSlotDelta] = temp; - } - */ - } - else // if (posSlot != kNumReps + kPosSlotDelta) - { - unsigned numDirectBits; -#if 0 - if (posSlot < kNumPowerPosSlots + kPosSlotDelta) - { - numDirectBits = (posSlot - 2 - kPosSlotDelta) >> 1; - dist = (UInt32)(2 | (posSlot & 1)) << numDirectBits; - } - else - { - numDirectBits = kNumLinearPosSlotBits; - dist = (UInt32)(posSlot - 0x22 - kPosSlotDelta) << kNumLinearPosSlotBits; - } - dist -= kNumReps - 1; -#else - numDirectBits = dec->_extra[(size_t)posSlot - kPosSlotDelta]; - // dist = reps[(size_t)(posSlot) - kPosSlotDelta]; -#endif - dec->_reps[kPosSlotOffset + 2] = - dec->_reps[kPosSlotOffset + 1]; - dec->_reps[kPosSlotOffset + 1] = - dec->_reps[kPosSlotOffset + 0]; - - // dist += val; dist += bitStream.ReadBitsBig(numDirectBits); - // if (posSlot >= _numAlignBits_PosSlots) - // if (numDirectBits >= _numAlignBits) - // if (val >= _numAlignBits_Dist) - // UInt32 val; MACRO_ReadBitsBig(val , numDirectBits) - // dist += val; - // dist += (UInt32)((UInt32)_value >> 1 >> (/* 31 ^ */ (numDirectBits))); - // MOVE_POS((numDirectBits ^ 31)) - MACRO_ReadBitsBig_pre(numDirectBits) - // dist += (UInt32)_value; - if (dist >= dec->_numAlignBits_Dist) - { - // if (numDirectBits != _numAlignBits) - { - // UInt32 val; - // dist -= (UInt32)_value; - MACRO_ReadBitsBig_add3(dist) - NORMALIZE - // dist += (val << kNumAlignBits); - // dist += bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits; - } - { - // const unsigned alignTemp = _alignDecoder.Decode(&bitStream); - const NHuffman::CDecoder7b *alignDecoder = & HUFF_DEC_PREFIX _alignDecoder; - unsigned alignTemp; - UPDATE_STAT(g_stats_NumAlign++;) - Z7_HUFF_DECODER_7B_DECODE(alignTemp, alignDecoder, GET_VAL_BASE, MOVE_POS, bs) - // NORMALIZE - // if (alignTemp >= kAlignTableSize) return DECODE_ERROR_CODE; - dist += alignTemp; - } - } - else - { - { - MACRO_ReadBitsBig_add(dist) - // dist += bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits; - } - } - NORMALIZE - /* - else - { - UInt32 val; - MACRO_ReadBitsBig(val, numDirectBits) - dist += val; - // dist += bitStream.ReadBitsBig(numDirectBits); - } - */ - } - dec->_reps[kPosSlotOffset + 0] = dist; - - Byte *dest = pos; - if (len > (size_t)(posEnd - pos)) - return DECODE_ERROR_CODE; - Int32 srcPos = (Int32)(pos - win); - pos += len; - srcPos -= (Int32)dist; - if (srcPos < 0) // fast version - { - if (!dec->_overDict) - return DECODE_ERROR_CODE; - srcPos &= winSize - 1; - UInt32 rem = winSize - (UInt32)srcPos; - if (len > rem) - { - len -= rem; - const Byte *src = win + (UInt32)srcPos; - do - *dest++ = *src++; - while (--rem); - srcPos = 0; - } - } - CopyLzMatch(dest, win + (UInt32)srcPos, len, dist); - } - } - while (pos != posEnd); - - return _bitOffset; - } -} - - - - -// inSize != 0 -// outSize != 0 ??? -HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) throw() -{ - // ((inSize & 1) != 0) case is possible, if current call will be finished with Uncompressed Block. - CBitByteDecoder _bitStream; - if (_keepHistory && _isUncompressedBlock) - _bitStream.Init_ByteMode(inData, inSize); - else - _bitStream.Init_BitMode(inData, inSize); - - if (!_keepHistory) - { - _isUncompressedBlock = false; - _skipByte = false; - _unpackBlockSize = 0; - memset(_mainLevels, 0, sizeof(_mainLevels)); - memset(_lenLevels, 0, sizeof(_lenLevels)); - { - _x86_translationSize = 12000000; - if (!_wimMode) - { - _x86_translationSize = 0; - if (ReadBits(_bitStream, 1) != 0) - { - UInt32 v = ReadBits(_bitStream, 16) << 16; - v |= ReadBits(_bitStream, 16); - _x86_translationSize = v; - } - } - _x86_processedSize = 0; - } - _reps[0 + kPosSlotOffset] = 1; - _reps[1 + kPosSlotOffset] = 1; - _reps[2 + kPosSlotOffset] = 1; - } - - while (outSize) - { - /* - // check it for bit mode only: - if (_bitStream.WasExtraReadError_Fast()) - return S_FALSE; - */ - if (_unpackBlockSize == 0) - { - if (_skipByte) - { - if (_bitStream.GetRem() < 1) - return S_FALSE; - if (_bitStream.DirectReadByte() != 0) - return S_FALSE; - } - if (_isUncompressedBlock) - _bitStream.Switch_To_BitMode(); - if (!ReadTables(_bitStream)) - return S_FALSE; - continue; - } - - // _unpackBlockSize != 0 - UInt32 next = _unpackBlockSize; - if (next > outSize) - next = outSize; - // next != 0 - - // PRF(printf("\nnext = %d", (unsigned)next);) - - if (_isUncompressedBlock) - { - if (_bitStream.GetRem() < next) - return S_FALSE; - _bitStream.CopyTo(_win + _pos, next); - _pos += next; - _unpackBlockSize -= next; - } - else - { - _unpackBlockSize -= next; - _bitStream._bitOffset = CodeLz(this, next, _bitStream._bitOffset, _bitStream._buf); - if (_bitStream.IsOverRead()) - return S_FALSE; - _pos += next; - } - outSize -= next; - } - - // outSize == 0 - - if (_isUncompressedBlock) - { - /* we don't know where skipByte can be placed, if it's end of chunk: - 1) in current chunk - there are such cab archives, if chunk is last - 2) in next chunk - are there such archives ? */ - if (_unpackBlockSize == 0 - && _skipByte - // && outSize == 0 - && _bitStream.IsOneDirectByteLeft()) - { - _skipByte = false; - if (_bitStream.DirectReadByte() != 0) - return S_FALSE; - } - } - - if (_bitStream.GetRem() != 0) - return S_FALSE; - if (!_isUncompressedBlock) - if (!_bitStream.WasBitStreamFinishedOK()) - return S_FALSE; - return S_OK; -} - - -#if k_Filter_OutBufSize_Add > k_Lz_OutBufSize_Add - #define k_OutBufSize_Add k_Filter_OutBufSize_Add -#else - #define k_OutBufSize_Add k_Lz_OutBufSize_Add -#endif - -HRESULT CDecoder::Code_WithExceedReadWrite(const Byte *inData, size_t inSize, UInt32 outSize) throw() -{ - if (!_keepHistory) - { - _pos = 0; - _overDict = false; - } - else if (_pos == _winSize) - { - _pos = 0; - _overDict = true; -#if k_OutBufSize_Add > 0 - // data after (_winSize) can be used, because we can use overwrite. - // memset(_win + _winSize, 0, k_OutBufSize_Add); -#endif - } - _writePos = _pos; - _unpackedData = _win + _pos; - - if (outSize > _winSize - _pos) - return S_FALSE; - - PRF(printf("\ninSize = %d", (unsigned)inSize);) - PRF(if ((inSize & 1) != 0) printf("---------");) - - if (inSize == 0) - return S_FALSE; - const HRESULT res = CodeSpec(inData, inSize, outSize); - const HRESULT res2 = Flush(); - return (res == S_OK ? res2 : res); -} - - -HRESULT CDecoder::SetParams2(unsigned numDictBits) throw() -{ - if (numDictBits < kNumDictBits_Min || - numDictBits > kNumDictBits_Max) - return E_INVALIDARG; - _numDictBits = (Byte)numDictBits; - const unsigned numPosSlots2 = (numDictBits < 20) ? - numDictBits : 17 + (1u << (numDictBits - 18)); - _numPosLenSlots = numPosSlots2 * (kNumLenSlots * 2); - return S_OK; -} - - -HRESULT CDecoder::Set_DictBits_and_Alloc(unsigned numDictBits) throw() -{ - RINOK(SetParams2(numDictBits)) - const UInt32 newWinSize = (UInt32)1 << numDictBits; - if (_needAlloc) - { - if (!_win || newWinSize != _winSize) - { - // BigFree - z7_AlignedFree - (_win); - _winSize = 0; - const size_t alloc_size = newWinSize + k_OutBufSize_Add; - _win = (Byte *) - // BigAlloc - z7_AlignedAlloc - (alloc_size); - if (!_win) - return E_OUTOFMEMORY; - // optional: - memset(_win, 0, alloc_size); - } - } - _winSize = newWinSize; - return S_OK; -} - -}} +// LzxDecoder.cpp + +#include "StdAfx.h" + +#include +// #include + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../C/Alloc.h" +#include "../../../C/RotateDefs.h" +#include "../../../C/CpuArch.h" + +#include "LzxDecoder.h" + + +#ifdef MY_CPU_X86_OR_AMD64 +#if defined(MY_CPU_AMD64) \ + || defined(__SSE2__) \ + || defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ + || 0 && defined(_MSC_VER) && (_MSC_VER >= 1400) // set (1 &&) for debug + +#if defined(__clang__) && (__clang_major__ >= 2) \ + || defined(__GNUC__) && (__GNUC__ >= 4) \ + || defined(_MSC_VER) && (_MSC_VER >= 1400) +#define Z7_LZX_X86_FILTER_USE_SSE2 +#endif +#endif +#endif + + +#ifdef Z7_LZX_X86_FILTER_USE_SSE2 +// #ifdef MY_CPU_X86_OR_AMD64 +#include // SSE2 +// #endif + #if defined(__clang__) || defined(__GNUC__) + typedef int ctz_type; + #define MY_CTZ(dest, mask) dest = __builtin_ctz((UInt32)(mask)) + #else // #if defined(_MSC_VER) + #if (_MSC_VER >= 1600) + // #include + #endif + typedef unsigned long ctz_type; + #define MY_CTZ(dest, mask) _BitScanForward(&dest, (mask)); + #endif // _MSC_VER +#endif + +// when window buffer is filled, we must wrap position to zero, +// and we want to wrap at same points where original-lzx must wrap. +// But the wrapping is possible in point where chunk is finished. +// Usually (chunk_size == 32KB), but (chunk_size != 32KB) also is allowed. +// So we don't use additional buffer space over required (winSize). +// And we can't use large overwrite after (len) in CopyLzMatch(). +// But we are allowed to write 3 bytes after (len), because +// (delta <= _winSize - 3). + +// #define k_Lz_OverwriteSize 0 // for debug : to disable overwrite +#define k_Lz_OverwriteSize 3 // = kNumReps +#if k_Lz_OverwriteSize > 0 +// (k_Lz_OutBufSize_Add >= k_Lz_OverwriteSize) is required +// we use value 4 to simplify memset() code. +#define k_Lz_OutBufSize_Add (k_Lz_OverwriteSize + 1) // == 4 +#else +#define k_Lz_OutBufSize_Add 0 +#endif + +// (len != 0) +// (0 < delta <= _winSize - 3) +Z7_FORCE_INLINE +void CopyLzMatch(Byte *dest, const Byte *src, UInt32 len, UInt32 delta) +{ + if (delta >= 4) + { +#if k_Lz_OverwriteSize >= 3 + // optimized code with overwrite to reduce the number of branches + #ifdef MY_CPU_LE_UNALIGN + *(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src); + #else + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + #endif + len--; + src++; + dest++; + { +#else + // no overwrite in out buffer + dest[0] = src[0]; + { + const unsigned m = (unsigned)len & 1; + src += m; + dest += m; + } + if (len &= ~(unsigned)1) + { + dest[0] = src[0]; + dest[1] = src[1]; +#endif + // len == 0 is allowed here + { + const unsigned m = (unsigned)len & 3; + src += m; + dest += m; + } + if (len &= ~(unsigned)3) + { +#ifdef MY_CPU_LE_UNALIGN + #if 1 + *(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src); + { + const unsigned m = (unsigned)len & 7; + dest += m; + src += m; + } + if (len &= ~(unsigned)7) + do + { + *(UInt32 *)(void *)(dest ) = *(const UInt32 *)(const void *)(src); + *(UInt32 *)(void *)(dest + 4) = *(const UInt32 *)(const void *)(src + 4); + src += 8; + dest += 8; + } + while (len -= 8); + #else + // gcc-11 -O3 for x64 generates incorrect code here + do + { + *(UInt32 *)(void *)(dest) = *(const UInt32 *)(const void *)(src); + src += 4; + dest += 4; + } + while (len -= 4); + #endif +#else + do + { + const Byte b0 = src[0]; + const Byte b1 = src[1]; + dest[0] = b0; + dest[1] = b1; + const Byte b2 = src[2]; + const Byte b3 = src[3]; + dest[2] = b2; + dest[3] = b3; + src += 4; + dest += 4; + } + while (len -= 4); +#endif + } + } + } + else // (delta < 4) + { + const unsigned b0 = *src; + *dest = (Byte)b0; + if (len >= 2) + { + if (delta < 2) + { + dest += (unsigned)len & 1; + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += (unsigned)len & 2; + if (len &= ~(unsigned)3) + { +#ifdef MY_CPU_LE_UNALIGN + #ifdef MY_CPU_64BIT + const UInt64 a = (UInt64)b0 * 0x101010101010101; + *(UInt32 *)(void *)dest = (UInt32)a; + dest += (unsigned)len & 7; + if (len &= ~(unsigned)7) + { + // *(UInt64 *)(void *)dest = a; + // dest += 8; + // len -= 8; + // if (len) + { + // const ptrdiff_t delta = (ptrdiff_t)dest & 7; + // dest -= delta; + do + { + *(UInt64 *)(void *)dest = a; + dest += 8; + } + while (len -= 8); + // dest += delta - 8; + // *(UInt64 *)(void *)dest = a; + } + } + #else + const UInt32 a = (UInt32)b0 * 0x1010101; + do + { + *(UInt32 *)(void *)dest = a; + dest += 4; + } + while (len -= 4); + #endif +#else + do + { + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest[2] = (Byte)b0; + dest[3] = (Byte)b0; + dest += 4; + } + while (len -= 4); +#endif + } + } + else if (delta == 2) + { + const unsigned m = (unsigned)len & 1; + len &= ~(unsigned)1; + src += m; + dest += m; + { + const Byte a0 = src[0]; + const Byte a1 = src[1]; + do + { + dest[0] = a0; + dest[1] = a1; + dest += 2; + } + while (len -= 2); + } + } + else /* if (delta == 3) */ + { + const unsigned b1 = src[1]; + dest[1] = (Byte)b1; + if (len -= 2) + { + const unsigned b2 = src[2]; + dest += 2; + do + { + dest[0] = (Byte)b2; if (--len == 0) break; + dest[1] = (Byte)b0; if (--len == 0) break; + dest[2] = (Byte)b1; + dest += 3; + } + while (--len); + } + } + } + } +} + +// #define Z7_LZX_SHOW_STAT +#ifdef Z7_LZX_SHOW_STAT +#include +#endif + +namespace NCompress { +namespace NLzx { + +// #define Z7_LZX_SHOW_STAT +#ifdef Z7_LZX_SHOW_STAT +static UInt32 g_stats_Num_x86[3]; +static UInt32 g_stats_NumTables; +static UInt32 g_stats_NumLits; +static UInt32 g_stats_NumAlign; +static UInt32 g_stats_main[kMainTableSize]; +static UInt32 g_stats_len[kNumLenSymbols]; +static UInt32 g_stats_main_levels[kNumHuffmanBits + 1]; +static UInt32 g_stats_len_levels[kNumHuffmanBits + 1]; +#define UPDATE_STAT(a) a +static void PrintVal(UInt32 v) +{ + printf("\n : %9u", v); +} +static void PrintStat(const char *name, const UInt32 *a, size_t num) +{ + printf("\n\n==== %s:", name); + UInt32 sum = 0; + size_t i; + for (i = 0; i < num; i++) + sum += a[i]; + PrintVal(sum); + if (sum != 0) + { + for (i = 0; i < num; i++) + { + if (i % 8 == 0) + printf("\n"); + printf("\n%3x : %9u : %5.2f", (unsigned)i, (unsigned)a[i], (double)a[i] * 100 / sum); + } + } + printf("\n"); +} + +static struct CStat +{ + ~CStat() + { + PrintStat("x86_filter", g_stats_Num_x86, Z7_ARRAY_SIZE(g_stats_Num_x86)); + printf("\nTables:"); PrintVal(g_stats_NumTables); + printf("\nLits:"); PrintVal(g_stats_NumLits); + printf("\nAlign:"); PrintVal(g_stats_NumAlign); + PrintStat("Main", g_stats_main, Z7_ARRAY_SIZE(g_stats_main)); + PrintStat("Len", g_stats_len, Z7_ARRAY_SIZE(g_stats_len)); + PrintStat("Main Levels", g_stats_main_levels, Z7_ARRAY_SIZE(g_stats_main_levels)); + PrintStat("Len Levels", g_stats_len_levels, Z7_ARRAY_SIZE(g_stats_len_levels)); + } +} g_stat; +#else +#define UPDATE_STAT(a) +#endif + + + +/* +3 p015 : ivb- : or r32,r32 / add r32,r32 +4 p0156 : hsw+ +5 p0156b: adl+ +2 p0_5 : ivb- : shl r32,i8 +2 p0__6 : hsw+ +1 p5 : ivb- : jb +2 p0__6 : hsw+ +2 p0_5 : wsm- : SSE2 : pcmpeqb : _mm_cmpeq_epi8 +2 p_15 : snb-bdw +2 p01 : skl+ +1 p0 : SSE2 : pmovmskb : _mm_movemask_epi8 +*/ +/* + v24.00: the code was fixed for more compatibility with original-ms-cab-decoder. + for ((Int32)translationSize >= 0) : LZX specification shows the code with signed Int32. + for ((Int32)translationSize < 0) : no specification for that case, but we support that case. + We suppose our code now is compatible with original-ms-cab-decoder. + + Starting byte of data stream (real_pos == 0) is special corner case, + where we don't need any conversion (as in original-ms-cab-decoder). + Our optimization: we use unsigned (UInt32 pos) (pos = -1 - real_pos). + So (pos) is always negative: ((Int32)pos < 0). + It allows us to use simple comparison (v > pos) instead of more complex comparisons. +*/ +// (p) will point 5 bytes after 0xe8 byte: +// pos == -1 - (p - 5 - data_start) == 4 + data_start - p +// (FILTER_PROCESSED_SIZE_DELTA == 4) is optimized value for better speed in some compilers: +#define FILTER_PROCESSED_SIZE_DELTA 4 + +#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_OR_ARM64) + // optimized branch: + // size_t must be at least 32-bit for this branch. + #if 1 // use 1 for simpler code + // use integer (low 32 bits of pointer) instead of pointer + #define X86_FILTER_PREPARE processedSize4 = (UInt32)(size_t)(ptrdiff_t)data + \ + (UInt32)(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4; + #define X86_FILTER_CALC_pos(p) const UInt32 pos = processedSize4 - (UInt32)(size_t)(ptrdiff_t)p; + #else + // note: (dataStart) pointer can point out of array ranges: + #define X86_FILTER_PREPARE const Byte *dataStart = data + \ + (4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4; + #define X86_FILTER_CALC_pos(p) const UInt32 pos = (UInt32)(size_t)(dataStart - p); + #endif +#else + // non-optimized branch for unusual platforms (16-bit size_t or unusual size_t): + #define X86_FILTER_PREPARE processedSize4 = \ + (UInt32)(4 - FILTER_PROCESSED_SIZE_DELTA) - processedSize4; + #define X86_FILTER_CALC_pos(p) const UInt32 pos = processedSize4 - (UInt32)(size_t)(p - data); +#endif + +#define X86_TRANSLATE_PRE(p) \ + UInt32 v = GetUi32((p) - 4); + +#define X86_TRANSLATE_POST(p) \ + { \ + X86_FILTER_CALC_pos(p) \ + if (v < translationSize) { \ + UPDATE_STAT(g_stats_Num_x86[0]++;) \ + v += pos + 1; \ + SetUi32((p) - 4, v) \ + } \ + else if (v > pos) { \ + UPDATE_STAT(g_stats_Num_x86[1]++;) \ + v += translationSize; \ + SetUi32((p) - 4, v) \ + } else { UPDATE_STAT(g_stats_Num_x86[2]++;) } \ + } + + +/* + if ( defined(Z7_LZX_X86_FILTER_USE_SSE2) + && defined(Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED)) + the function can read up to aligned_for_32_up_from(size) bytes in (data). +*/ +// processedSize < (1 << 30) +Z7_NO_INLINE +static void x86_Filter4(Byte *data, size_t size, UInt32 processedSize4, UInt32 translationSize) +{ + const size_t kResidue = 10; + if (size <= kResidue) + return; + Byte * const lim = data + size - kResidue + 4; + const Byte save = lim[0]; + lim[0] = 0xe8; + X86_FILTER_PREPARE + Byte *p = data; + +#define FILTER_RETURN_IF_LIM(_p_) if (_p_ > lim) { lim[0] = save; return; } + +#ifdef Z7_LZX_X86_FILTER_USE_SSE2 + +// sse2-aligned/sse2-unaligned provide same speed on real data. +// but the code is smaller for sse2-unaligned version. +// for debug : define it to get alternative version with aligned 128-bit reads: +// #define Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED + +#define FILTER_MASK_INT UInt32 +#define FILTER_NUM_VECTORS_IN_CHUNK 2 +#define FILTER_CHUNK_BYTES_OFFSET (16 * FILTER_NUM_VECTORS_IN_CHUNK - 5) + +#ifdef Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED + // aligned version doesn't uses additional space if buf size is aligned for 32 + #define k_Filter_OutBufSize_Add 0 + #define k_Filter_OutBufSize_AlignMask (16 * FILTER_NUM_VECTORS_IN_CHUNK - 1) + #define FILTER_LOAD_128(p) _mm_load_si128 ((const __m128i *)(const void *)(p)) +#else + #define k_Filter_OutBufSize_Add (16 * FILTER_NUM_VECTORS_IN_CHUNK) + #define k_Filter_OutBufSize_AlignMask 0 + #define FILTER_LOAD_128(p) _mm_loadu_si128((const __m128i *)(const void *)(p)) +#endif + +#define GET_E8_MASK(dest, dest1, p) \ +{ \ + __m128i v0 = FILTER_LOAD_128(p); \ + __m128i v1 = FILTER_LOAD_128(p + 16); \ + p += 16 * FILTER_NUM_VECTORS_IN_CHUNK; \ + v0 = _mm_cmpeq_epi8(v0, k_e8_Vector); \ + v1 = _mm_cmpeq_epi8(v1, k_e8_Vector); \ + dest = (unsigned)_mm_movemask_epi8(v0); \ + dest1 = (unsigned)_mm_movemask_epi8(v1); \ +} + + const __m128i k_e8_Vector = _mm_set1_epi32((Int32)(UInt32)0xe8e8e8e8); + for (;;) + { + // for debug: define it for smaller code: + // #define Z7_LZX_X86_FILTER_CALC_IN_LOOP + // without Z7_LZX_X86_FILTER_CALC_IN_LOOP, we can get faster and simpler loop + FILTER_MASK_INT mask; + { + FILTER_MASK_INT mask1; + do + { + GET_E8_MASK(mask, mask1, p) + #ifndef Z7_LZX_X86_FILTER_CALC_IN_LOOP + mask += mask1; + #else + mask |= mask1 << 16; + #endif + } + while (!mask); + + #ifndef Z7_LZX_X86_FILTER_CALC_IN_LOOP + mask -= mask1; + mask |= mask1 << 16; + #endif + } + +#ifdef Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED + for (;;) + { + ctz_type index; + typedef + #ifdef MY_CPU_64BIT + UInt64 + #else + UInt32 + #endif + SUPER_MASK_INT; + SUPER_MASK_INT superMask; + { + MY_CTZ(index, mask); + Byte *p2 = p - FILTER_CHUNK_BYTES_OFFSET + (unsigned)index; + X86_TRANSLATE_PRE(p2) + superMask = ~(SUPER_MASK_INT)0x1f << index; + FILTER_RETURN_IF_LIM(p2) + X86_TRANSLATE_POST(p2) + mask &= (UInt32)superMask; + } + if (mask) + continue; + if (index <= FILTER_CHUNK_BYTES_OFFSET) + break; + { + FILTER_MASK_INT mask1; + GET_E8_MASK(mask, mask1, p) + mask &= + #ifdef MY_CPU_64BIT + (UInt32)(superMask >> 32); + #else + ((FILTER_MASK_INT)0 - 1) << ((int)index - FILTER_CHUNK_BYTES_OFFSET); + #endif + mask |= mask1 << 16; + } + if (!mask) + break; + } +#else // ! Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED + { + // we use simplest version without loop: + // for (;;) + { + ctz_type index; + MY_CTZ(index, mask); + /* + printf("\np=%p, mask=%8x, index = %2d, p + index = %x\n", + (p - 16 * FILTER_NUM_VECTORS_IN_CHUNK), (unsigned)mask, + (unsigned)index, (unsigned)((unsigned)(ptrdiff_t)(p - 16 * FILTER_NUM_VECTORS_IN_CHUNK) + index)); + */ + p += (size_t)(unsigned)index - FILTER_CHUNK_BYTES_OFFSET; + FILTER_RETURN_IF_LIM(p) + // mask &= ~(FILTER_MASK_INT)0x1f << index; mask >>= index; + X86_TRANSLATE_PRE(p) + X86_TRANSLATE_POST(p) + // if (!mask) break; // p += 16 * FILTER_NUM_VECTORS_IN_CHUNK; + } + } +#endif // ! Z7_LZX_X86_FILTER_USE_SSE2_ALIGNED + } + +#else // ! Z7_LZX_X86_FILTER_USE_SSE2 + +#define k_Filter_OutBufSize_Add 0 +#define k_Filter_OutBufSize_AlignMask 0 + + + for (;;) + { + for (;;) + { + if (p[0] == 0xe8) { p += 5; break; } + if (p[1] == 0xe8) { p += 6; break; } + if (p[2] == 0xe8) { p += 7; break; } + p += 4; + if (p[-1] == 0xe8) { p += 4; break; } + } + FILTER_RETURN_IF_LIM(p) + X86_TRANSLATE_PRE(p) + X86_TRANSLATE_POST(p) + } + +#endif // ! Z7_LZX_X86_FILTER_USE_SSE2 +} + + +CDecoder::CDecoder() throw(): + _win(NULL), + _isUncompressedBlock(false), + _skipByte(false), + _keepHistory(false), + _keepHistoryForNext(true), + _needAlloc(true), + _wimMode(false), + _numDictBits(15), + _unpackBlockSize(0), + _x86_translationSize(0), + _x86_buf(NULL), + _unpackedData(NULL) +{ + { + // it's better to get empty virtual entries, if mispredicted value can be used: + memset(_reps, 0, kPosSlotOffset * sizeof(_reps[0])); + memset(_extra, 0, kPosSlotOffset); +#define SET_NUM_BITS(i) i // #define NUM_BITS_DELTA 31 + _extra[kPosSlotOffset + 0] = SET_NUM_BITS(0); + _extra[kPosSlotOffset + 1] = SET_NUM_BITS(0); + // reps[0] = 0 - (kNumReps - 1); + // reps[1] = 1 - (kNumReps - 1); + UInt32 a = 2 - (kNumReps - 1); + UInt32 delta = 1; + unsigned i; + for (i = 0; i < kNumLinearPosSlotBits; i++) + { + _extra[(size_t)i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); + _extra[(size_t)i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); + _reps [(size_t)i * 2 + 2 + kPosSlotOffset] = a; a += delta; + _reps [(size_t)i * 2 + 3 + kPosSlotOffset] = a; a += delta; + delta += delta; + } + for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++) + { + _extra[(size_t)i + kPosSlotOffset] = SET_NUM_BITS(kNumLinearPosSlotBits); + _reps [(size_t)i + kPosSlotOffset] = a; + a += (UInt32)1 << kNumLinearPosSlotBits; + } + } +} + +CDecoder::~CDecoder() throw() +{ + if (_needAlloc) + // BigFree + z7_AlignedFree + (_win); + z7_AlignedFree(_x86_buf); +} + +HRESULT CDecoder::Flush() throw() +{ + // UInt32 t = _x86_processedSize; for (int y = 0; y < 50; y++) { _x86_processedSize = t; // benchmark: (branch predicted) + if (_x86_translationSize != 0) + { + Byte *destData = _win + _writePos; + const UInt32 curSize = _pos - _writePos; + if (_keepHistoryForNext) + { + const size_t kChunkSize = (size_t)1 << 15; + if (curSize > kChunkSize) + return E_NOTIMPL; + if (!_x86_buf) + { + // (kChunkSize % 32 == 0) is required in some cases, because + // the filter can read data by 32-bytes chunks in some cases. + // if (chunk_size > (1 << 15)) is possible, then we must the code: + const size_t kAllocSize = kChunkSize + k_Filter_OutBufSize_Add; + _x86_buf = (Byte *)z7_AlignedAlloc(kAllocSize); + if (!_x86_buf) + return E_OUTOFMEMORY; + #if 0 != k_Filter_OutBufSize_Add || \ + 0 != k_Filter_OutBufSize_AlignMask + // x86_Filter4() can read after curSize. + // So we set all data to zero to prevent reading of uninitialized data: + memset(_x86_buf, 0, kAllocSize); // optional + #endif + } + // for (int yy = 0; yy < 1; yy++) // for debug + memcpy(_x86_buf, destData, curSize); + _unpackedData = _x86_buf; + destData = _x86_buf; + } + else + { + // x86_Filter4() can overread after (curSize), + // so we can do memset() after (curSize): + // k_Filter_OutBufSize_AlignMask also can be used + // if (!_overDict) memset(destData + curSize, 0, k_Filter_OutBufSize_Add); + } + x86_Filter4(destData, curSize, _x86_processedSize - FILTER_PROCESSED_SIZE_DELTA, _x86_translationSize); + _x86_processedSize += (UInt32)curSize; + if (_x86_processedSize >= ((UInt32)1 << 30)) + _x86_translationSize = 0; + } + // } + return S_OK; +} + + + +// (NUM_DELTA_BYTES == 2) reduces the code in main loop. +#if 1 + #define NUM_DELTA_BYTES 2 +#else + #define NUM_DELTA_BYTES 0 +#endif + +#define NUM_DELTA_BIT_OFFSET_BITS (NUM_DELTA_BYTES * 8) + +#if NUM_DELTA_BIT_OFFSET_BITS > 0 + #define DECODE_ERROR_CODE 0 + #define IS_OVERFLOW_bitOffset(bo) ((bo) >= 0) + // ( >= 0) comparison after bitOffset change gives simpler commands than ( > 0) comparison +#else + #define DECODE_ERROR_CODE 1 + #define IS_OVERFLOW_bitOffset(bo) ((bo) > 0) +#endif + +// (numBits != 0) +#define GET_VAL_BASE(numBits) (_value >> (32 - (numBits))) + +#define Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, check_op, error_op) \ + Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huff, kNumHuffmanBits, kNumTableBits, \ + _value, check_op, error_op, move_pos_op, NORMALIZE, bs) + +#define Z7_LZX_HUFF_DECODE_CHECK_YES(sym, huff, kNumTableBits, move_pos_op) \ + Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, \ + Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, { return DECODE_ERROR_CODE; }) + +#define Z7_LZX_HUFF_DECODE_CHECK_NO( sym, huff, kNumTableBits, move_pos_op) \ + Z7_LZX_HUFF_DECODE( sym, huff, kNumTableBits, move_pos_op, \ + Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}) + +#define NORMALIZE \ +{ \ + const Byte *ptr = _buf + (_bitOffset >> 4) * 2; \ + /* _value = (((UInt32)GetUi16(ptr) << 16) | GetUi16(ptr + 2)) << (_bitOffset & 15); */ \ + const UInt32 v = GetUi32(ptr); \ + _value = rotlFixed (v, ((int)_bitOffset & 15) + 16); \ +} + +#define MOVE_POS(bs, numBits) \ +{ \ + _bitOffset += numBits; \ +} + +#define MOVE_POS_STAT(bs, numBits) \ +{ \ + UPDATE_STAT(g_stats_len_levels[numBits]++;) \ + MOVE_POS(bs, numBits); \ +} + +#define MOVE_POS_CHECK(bs, numBits) \ +{ \ + if (IS_OVERFLOW_bitOffset(_bitOffset += numBits)) return DECODE_ERROR_CODE; \ +} + +#define MOVE_POS_CHECK_STAT(bs, numBits) \ +{ \ + UPDATE_STAT(g_stats_main_levels[numBits]++;) \ + MOVE_POS_CHECK(bs, numBits) \ +} + + +// (numBits == 0) is supported + +#ifdef Z7_HUFF_USE_64BIT_LIMIT + +#define MACRO_ReadBitsBig_pre(numBits) \ +{ \ + _bitOffset += (numBits); \ + _value >>= 32 - (numBits); \ +} + +#else + +#define MACRO_ReadBitsBig_pre(numBits) \ +{ \ + _bitOffset += (numBits); \ + _value = (UInt32)((UInt32)_value >> 1 >> (31 ^ (numBits))); \ +} + +#endif + + +#define MACRO_ReadBitsBig_add(dest) \ + { dest += (UInt32)_value; } + +#define MACRO_ReadBitsBig_add3(dest) \ + { dest += (UInt32)(_value) << 3; } + + +// (numBits != 0) +#define MACRO_ReadBits_NonZero(val, numBits) \ +{ \ + val = (UInt32)(_value >> (32 - (numBits))); \ + MOVE_POS(bs, numBits); \ + NORMALIZE \ +} + + +struct CBitDecoder +{ + ptrdiff_t _bitOffset; + const Byte *_buf; + + Z7_FORCE_INLINE + UInt32 GetVal() const + { + const Byte *ptr = _buf + (_bitOffset >> 4) * 2; + const UInt32 v = GetUi32(ptr); + return rotlFixed (v, ((int)_bitOffset & 15) + 16); + } + + Z7_FORCE_INLINE + bool IsOverRead() const + { + return _bitOffset > (int)(0 - NUM_DELTA_BIT_OFFSET_BITS); + } + + + Z7_FORCE_INLINE + bool WasBitStreamFinishedOK() const + { + // we check that all 0-15 unused bits are zeros: + if (_bitOffset == 0 - NUM_DELTA_BIT_OFFSET_BITS) + return true; + if ((_bitOffset + NUM_DELTA_BIT_OFFSET_BITS + 15) & ~(ptrdiff_t)15) + return false; + const Byte *ptr = _buf - NUM_DELTA_BYTES - 2; + if ((UInt16)(GetUi16(ptr) << (_bitOffset & 15))) + return false; + return true; + } + + // (numBits != 0) + Z7_FORCE_INLINE + UInt32 ReadBits_NonZero(unsigned numBits) throw() + { + const UInt32 val = GetVal() >> (32 - numBits); + _bitOffset += numBits; + return val; + } +}; + + +class CBitByteDecoder: public CBitDecoder +{ + size_t _size; +public: + + Z7_FORCE_INLINE + void Init_ByteMode(const Byte *data, size_t size) + { + _buf = data; + _size = size; + } + + Z7_FORCE_INLINE + void Init_BitMode(const Byte *data, size_t size) + { + _size = size & 1; + size &= ~(size_t)1; + _buf = data + size + NUM_DELTA_BYTES; + _bitOffset = 0 - (ptrdiff_t)(size * 8) - NUM_DELTA_BIT_OFFSET_BITS; + } + + Z7_FORCE_INLINE + void Switch_To_BitMode() + { + Init_BitMode(_buf, _size); + } + + Z7_FORCE_INLINE + bool Switch_To_ByteMode() + { + /* here we check that unused bits in high 16-bits word are zeros. + If high word is full (all 16-bits are unused), + we check that all 16-bits are zeros. + So we check and skip (1-16 bits) unused bits */ + if ((GetVal() >> (16 + (_bitOffset & 15))) != 0) + return false; + _bitOffset += 16; + _bitOffset &= ~(ptrdiff_t)15; + if (_bitOffset > 0 - NUM_DELTA_BIT_OFFSET_BITS) + return false; + const ptrdiff_t delta = _bitOffset >> 3; + _size = (size_t)((ptrdiff_t)(_size) - delta - NUM_DELTA_BYTES); + _buf += delta; + // _bitOffset = 0; // optional + return true; + } + + Z7_FORCE_INLINE + size_t GetRem() const { return _size; } + + Z7_FORCE_INLINE + UInt32 ReadUInt32() + { + const Byte *ptr = _buf; + const UInt32 v = GetUi32(ptr); + _buf += 4; + _size -= 4; + return v; + } + + Z7_FORCE_INLINE + void CopyTo(Byte *dest, size_t size) + { + memcpy(dest, _buf, size); + _buf += size; + _size -= size; + } + + Z7_FORCE_INLINE + bool IsOneDirectByteLeft() const + { + return GetRem() == 1; + } + + Z7_FORCE_INLINE + Byte DirectReadByte() + { + _size--; + return *_buf++; + } +}; + + +// numBits != 0 +// Z7_FORCE_INLINE +Z7_NO_INLINE +static +UInt32 ReadBits(CBitDecoder &_bitStream, unsigned numBits) +{ + return _bitStream.ReadBits_NonZero(numBits); +} + +#define RIF(x) { if (!(x)) return false; } + + +/* +MSVC compiler adds extra move operation, + if we access array with 32-bit index + array[calc_index_32_bit(32-bit_var)] + where calc_index_32_bit operations are: ((unsigned)a>>cnt), &, ^, | + clang is also affected for ((unsigned)a>>cnt) in byte array. +*/ + +// it can overread input buffer for 7-17 bytes. +// (levels != levelsEnd) +Z7_NO_INLINE +static ptrdiff_t ReadTable(ptrdiff_t _bitOffset, const Byte *_buf, Byte *levels, const Byte *levelsEnd) +{ + const unsigned kNumTableBits_Level = 7; + NHuffman::CDecoder256 _levelDecoder; + NHuffman::CValueInt _value; + // optional check to reduce size of overread zone: + if (_bitOffset > (int)0 - (int)NUM_DELTA_BIT_OFFSET_BITS - (int)(kLevelTableSize * kNumLevelBits)) + return DECODE_ERROR_CODE; + NORMALIZE + { + Byte levels2[kLevelTableSize / 4 * 4]; + for (size_t i = 0; i < kLevelTableSize / 4 * 4; i += 4) + { + UInt32 val; + MACRO_ReadBits_NonZero(val, kNumLevelBits * 4) + levels2[i + 0] = (Byte)((val >> (3 * kNumLevelBits))); + levels2[i + 1] = (Byte)((val >> (2 * kNumLevelBits)) & ((1u << kNumLevelBits) - 1)); + levels2[i + 2] = (Byte)((Byte)val >> (1 * kNumLevelBits)); + levels2[i + 3] = (Byte)((val) & ((1u << kNumLevelBits) - 1)); + } + RIF(_levelDecoder.Build(levels2, NHuffman::k_BuildMode_Full)) + } + + do + { + unsigned sym; + Z7_LZX_HUFF_DECODE_CHECK_NO(sym, &_levelDecoder, kNumTableBits_Level, MOVE_POS_CHECK) + // Z7_HUFF_DECODE_CHECK(sym, &_levelDecoder, kNumHuffmanBits, kNumTableBits_Level, &bitStream, return false) + // sym = _levelDecoder.Decode(&bitStream); + // if (!_levelDecoder.Decode_SymCheck_MovePosCheck(&bitStream, sym)) return false; + + if (sym <= kNumHuffmanBits) + { + int delta = (int)*levels - (int)sym; + delta += delta < 0 ? kNumHuffmanBits + 1 : 0; + *levels++ = (Byte)delta; + continue; + } + + unsigned num; + int symbol; + + if (sym < kLevelSym_Same) + { + // sym -= kLevelSym_Zero1; + MACRO_ReadBits_NonZero(num, kLevelSym_Zero1_NumBits + (sym - kLevelSym_Zero1)) + num += (sym << kLevelSym_Zero1_NumBits) - (kLevelSym_Zero1 << kLevelSym_Zero1_NumBits) + kLevelSym_Zero1_Start; + symbol = 0; + } + // else if (sym != kLevelSym_Same) return DECODE_ERROR_CODE; + else // (sym == kLevelSym_Same) + { + MACRO_ReadBits_NonZero(num, kLevelSym_Same_NumBits) + num += kLevelSym_Same_Start; + // + (unsigned)bitStream.ReadBitsSmall(kLevelSym_Same_NumBits); + // Z7_HUFF_DECODE_CHECK(sym, &_levelDecoder, kNumHuffmanBits, kNumTableBits_Level, &bitStream, return DECODE_ERROR_CODE) + // if (!_levelDecoder.Decode2(&bitStream, sym)) return DECODE_ERROR_CODE; + // sym = _levelDecoder.Decode(&bitStream); + + Z7_LZX_HUFF_DECODE_CHECK_NO(sym, &_levelDecoder, kNumTableBits_Level, MOVE_POS) + + if (sym > kNumHuffmanBits) return DECODE_ERROR_CODE; + symbol = *levels - (int)sym; + symbol += symbol < 0 ? kNumHuffmanBits + 1 : 0; + } + + if (num > (size_t)(levelsEnd - levels)) + return false; + const Byte *limit = levels + num; + do + *levels++ = (Byte)symbol; + while (levels != limit); + } + while (levels != levelsEnd); + + return _bitOffset; +} + + +static const unsigned kPosSlotDelta = 256 / kNumLenSlots - kPosSlotOffset; + + +#define READ_TABLE(_bitStream, levels, levelsEnd) \ +{ \ + _bitStream._bitOffset = ReadTable(_bitStream._bitOffset, _bitStream._buf, levels, levelsEnd); \ + if (_bitStream.IsOverRead()) return false; \ +} + +// can over-read input buffer for less than 32 bytes +bool CDecoder::ReadTables(CBitByteDecoder &_bitStream) throw() +{ + UPDATE_STAT(g_stats_NumTables++;) + { + const unsigned blockType = (unsigned)ReadBits(_bitStream, kBlockType_NumBits); + // if (blockType > kBlockType_Uncompressed || blockType == 0) + if ((unsigned)(blockType - 1) > kBlockType_Uncompressed - 1) + return false; + _unpackBlockSize = 1u << 15; + if (!_wimMode || ReadBits(_bitStream, 1) == 0) + { + _unpackBlockSize = ReadBits(_bitStream, 16); + // wimlib supports chunks larger than 32KB (unsupported my MS wim). + if (!_wimMode || _numDictBits >= 16) + { + _unpackBlockSize <<= 8; + _unpackBlockSize |= ReadBits(_bitStream, 8); + } + } + + PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " ")); + + _isUncompressedBlock = (blockType == kBlockType_Uncompressed); + _skipByte = false; + + if (_isUncompressedBlock) + { + _skipByte = ((_unpackBlockSize & 1) != 0); + // printf("\n UncompressedBlock %d", _unpackBlockSize); + PRF(printf(" UncompressedBlock ");) + // if (_unpackBlockSize & 1) { PRF(printf(" ######### ")); } + if (!_bitStream.Switch_To_ByteMode()) + return false; + if (_bitStream.GetRem() < kNumReps * 4) + return false; + for (unsigned i = 0; i < kNumReps; i++) + { + const UInt32 rep = _bitStream.ReadUInt32(); + // here we allow only such values for (rep) that can be set also by LZ code: + if (rep == 0 || rep > _winSize - kNumReps) + return false; + _reps[(size_t)i + kPosSlotOffset] = rep; + } + // printf("\n"); + return true; + } + + // _numAlignBits = 64; + // const UInt32 k_numAlignBits_PosSlots_MAX = 64 + kPosSlotDelta; + // _numAlignBits_PosSlots = k_numAlignBits_PosSlots_MAX; + const UInt32 k_numAlignBits_Dist_MAX = (UInt32)(Int32)-1; + _numAlignBits_Dist = k_numAlignBits_Dist_MAX; + if (blockType == kBlockType_Aligned) + { + Byte levels[kAlignTableSize]; + // unsigned not0 = 0; + unsigned not3 = 0; + for (unsigned i = 0; i < kAlignTableSize; i++) + { + const unsigned val = ReadBits(_bitStream, kNumAlignLevelBits); + levels[i] = (Byte)val; + // not0 |= val; + not3 |= (val ^ 3); + } + // static unsigned number = 0, all = 0; all++; + // if (!not0) return false; // Build(true) will test this case + if (not3) + { + // _numAlignBits_PosSlots = (kNumAlignBits + 1) * 2 + kPosSlotDelta; + // _numAlignBits = kNumAlignBits; + _numAlignBits_Dist = (1u << (kNumAlignBits + 1)) - (kNumReps - 1); + RIF(_alignDecoder.Build(levels, true)) // full + } + // else { number++; if (number % 4 == 0) printf("\nnumber= %u : %u%%", number, number * 100 / all); } + } + // if (_numAlignBits_PosSlots == k_numAlignBits_PosSlots_MAX) + if (_numAlignBits_Dist == k_numAlignBits_Dist_MAX) + { + size_t i; + for (i = 3; i < kNumLinearPosSlotBits; i++) + { + _extra[i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); + _extra[i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i)); + } + for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++) + _extra[i + kPosSlotOffset] = (Byte)SET_NUM_BITS(kNumLinearPosSlotBits); + } + else + { + size_t i; + for (i = 3; i < kNumLinearPosSlotBits; i++) + { + _extra[i * 2 + 2 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i) - 3); + _extra[i * 2 + 3 + kPosSlotOffset] = (Byte)(SET_NUM_BITS(i) - 3); + } + for (i = kNumLinearPosSlotBits * 2 + 2; i < kNumPosSlots; i++) + _extra[i + kPosSlotOffset] = (Byte)(SET_NUM_BITS(kNumLinearPosSlotBits) - 3); + } + } + + READ_TABLE(_bitStream, _mainLevels, _mainLevels + 256) + READ_TABLE(_bitStream, _mainLevels + 256, _mainLevels + 256 + _numPosLenSlots) + const unsigned end = 256 + _numPosLenSlots; + memset(_mainLevels + end, 0, kMainTableSize - end); + // #define NUM_CYC 1 + // unsigned j; for (j = 0; j < NUM_CYC; j++) + RIF(_mainDecoder.Build(_mainLevels, NHuffman::k_BuildMode_Full)) + // if (kNumLenSymols_Big_Start) + memset(_lenLevels, 0, kNumLenSymols_Big_Start); + READ_TABLE(_bitStream, + _lenLevels + kNumLenSymols_Big_Start, + _lenLevels + kNumLenSymols_Big_Start + kNumLenSymbols) + // for (j = 0; j < NUM_CYC; j++) + RIF(_lenDecoder.Build(_lenLevels, NHuffman::k_BuildMode_Full_or_Empty)) + return true; +} + + + +static ptrdiff_t CodeLz(CDecoder *dec, size_t next, ptrdiff_t _bitOffset, const Byte *_buf) throw() +{ + { + Byte *const win = dec->_win; + const UInt32 winSize = dec->_winSize; + Byte *pos = win + dec->_pos; + const Byte * const posEnd = pos + next; + NHuffman::CValueInt _value; + + NORMALIZE + +#if 1 + #define HUFF_DEC_PREFIX dec-> +#else + const NHuffman::CDecoder _mainDecoder = dec->_mainDecoder; + const NHuffman::CDecoder256 _lenDecoder = dec->_lenDecoder; + const NHuffman::CDecoder7b _alignDecoder = dec->_alignDecoder; + #define HUFF_DEC_PREFIX +#endif + + do + { + unsigned sym; + // printf("\npos = %6u", pos - win); + { + const NHuffman::CDecoder + *mainDecoder = & HUFF_DEC_PREFIX _mainDecoder; + Z7_LZX_HUFF_DECODE_CHECK_NO(sym, mainDecoder, kNumTableBits_Main, MOVE_POS_CHECK_STAT) + } + // if (!_mainDecoder.Decode_SymCheck_MovePosCheck(&bitStream, sym)) return DECODE_ERROR_CODE; + // sym = _mainDecoder.Decode(&bitStream); + // if (bitStream.WasExtraReadError_Fast()) return DECODE_ERROR_CODE; + + // printf(" sym = %3x", sym); + UPDATE_STAT(g_stats_main[sym]++;) + + if (sym < 256) + { + UPDATE_STAT(g_stats_NumLits++;) + *pos++ = (Byte)sym; + } + else + { + // sym -= 256; + // if (sym >= _numPosLenSlots) return DECODE_ERROR_CODE; + const unsigned posSlot = sym / kNumLenSlots; + unsigned len = sym % kNumLenSlots + kMatchMinLen; + if (len == kNumLenSlots - 1 + kMatchMinLen) + { + const NHuffman::CDecoder256 + *lenDecoder = & HUFF_DEC_PREFIX _lenDecoder; + Z7_LZX_HUFF_DECODE_CHECK_YES(len, lenDecoder, kNumTableBits_Len, MOVE_POS_STAT) + // if (!_lenDecoder.Decode2(&bitStream, len)) return DECODE_ERROR_CODE; + // len = _lenDecoder.Decode(&bitStream); + // if (len >= kNumLenSymbols) return DECODE_ERROR_CODE; + UPDATE_STAT(g_stats_len[len - kNumLenSymols_Big_Start]++;) + len += kNumLenSlots - 1 + kMatchMinLen - kNumLenSymols_Big_Start; + } + /* + if ((next -= len) < 0) + return DECODE_ERROR_CODE; + */ + UInt32 dist; + + dist = dec->_reps[(size_t)posSlot - kPosSlotDelta]; + if (posSlot < kNumReps + 256 / kNumLenSlots) + { + // if (posSlot != kNumReps + kPosSlotDelta) + // if (posSlot - (kNumReps + kPosSlotDelta + 1) < 2) + dec->_reps[(size_t)posSlot - kPosSlotDelta] = dec->_reps[kPosSlotOffset]; + /* + if (posSlot != kPosSlotDelta) + { + UInt32 temp = dist; + if (posSlot == kPosSlotDelta + 1) + { + dist = reps[1]; + reps[1] = temp; + } + else + { + dist = reps[2]; + reps[2] = temp; + } + // dist = reps[(size_t)(posSlot) - kPosSlotDelta]; + // reps[(size_t)(posSlot) - kPosSlotDelta] = reps[0]; + // reps[(size_t)(posSlot) - kPosSlotDelta] = temp; + } + */ + } + else // if (posSlot != kNumReps + kPosSlotDelta) + { + unsigned numDirectBits; +#if 0 + if (posSlot < kNumPowerPosSlots + kPosSlotDelta) + { + numDirectBits = (posSlot - 2 - kPosSlotDelta) >> 1; + dist = (UInt32)(2 | (posSlot & 1)) << numDirectBits; + } + else + { + numDirectBits = kNumLinearPosSlotBits; + dist = (UInt32)(posSlot - 0x22 - kPosSlotDelta) << kNumLinearPosSlotBits; + } + dist -= kNumReps - 1; +#else + numDirectBits = dec->_extra[(size_t)posSlot - kPosSlotDelta]; + // dist = reps[(size_t)(posSlot) - kPosSlotDelta]; +#endif + dec->_reps[kPosSlotOffset + 2] = + dec->_reps[kPosSlotOffset + 1]; + dec->_reps[kPosSlotOffset + 1] = + dec->_reps[kPosSlotOffset + 0]; + + // dist += val; dist += bitStream.ReadBitsBig(numDirectBits); + // if (posSlot >= _numAlignBits_PosSlots) + // if (numDirectBits >= _numAlignBits) + // if (val >= _numAlignBits_Dist) + // UInt32 val; MACRO_ReadBitsBig(val , numDirectBits) + // dist += val; + // dist += (UInt32)((UInt32)_value >> 1 >> (/* 31 ^ */ (numDirectBits))); + // MOVE_POS((numDirectBits ^ 31)) + MACRO_ReadBitsBig_pre(numDirectBits) + // dist += (UInt32)_value; + if (dist >= dec->_numAlignBits_Dist) + { + // if (numDirectBits != _numAlignBits) + { + // UInt32 val; + // dist -= (UInt32)_value; + MACRO_ReadBitsBig_add3(dist) + NORMALIZE + // dist += (val << kNumAlignBits); + // dist += bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits; + } + { + // const unsigned alignTemp = _alignDecoder.Decode(&bitStream); + const NHuffman::CDecoder7b *alignDecoder = & HUFF_DEC_PREFIX _alignDecoder; + unsigned alignTemp; + UPDATE_STAT(g_stats_NumAlign++;) + Z7_HUFF_DECODER_7B_DECODE(alignTemp, alignDecoder, GET_VAL_BASE, MOVE_POS, bs) + // NORMALIZE + // if (alignTemp >= kAlignTableSize) return DECODE_ERROR_CODE; + dist += alignTemp; + } + } + else + { + { + MACRO_ReadBitsBig_add(dist) + // dist += bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits; + } + } + NORMALIZE + /* + else + { + UInt32 val; + MACRO_ReadBitsBig(val, numDirectBits) + dist += val; + // dist += bitStream.ReadBitsBig(numDirectBits); + } + */ + } + dec->_reps[kPosSlotOffset + 0] = dist; + + Byte *dest = pos; + if (len > (size_t)(posEnd - pos)) + return DECODE_ERROR_CODE; + Int32 srcPos = (Int32)(pos - win); + pos += len; + srcPos -= (Int32)dist; + if (srcPos < 0) // fast version + { + if (!dec->_overDict) + return DECODE_ERROR_CODE; + srcPos &= winSize - 1; + UInt32 rem = winSize - (UInt32)srcPos; + if (len > rem) + { + len -= rem; + const Byte *src = win + (UInt32)srcPos; + do + *dest++ = *src++; + while (--rem); + srcPos = 0; + } + } + CopyLzMatch(dest, win + (UInt32)srcPos, len, dist); + } + } + while (pos != posEnd); + + return _bitOffset; + } +} + + + + +// inSize != 0 +// outSize != 0 ??? +HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) throw() +{ + // ((inSize & 1) != 0) case is possible, if current call will be finished with Uncompressed Block. + CBitByteDecoder _bitStream; + if (_keepHistory && _isUncompressedBlock) + _bitStream.Init_ByteMode(inData, inSize); + else + _bitStream.Init_BitMode(inData, inSize); + + if (!_keepHistory) + { + _isUncompressedBlock = false; + _skipByte = false; + _unpackBlockSize = 0; + memset(_mainLevels, 0, sizeof(_mainLevels)); + memset(_lenLevels, 0, sizeof(_lenLevels)); + { + _x86_translationSize = 12000000; + if (!_wimMode) + { + _x86_translationSize = 0; + if (ReadBits(_bitStream, 1) != 0) + { + UInt32 v = ReadBits(_bitStream, 16) << 16; + v |= ReadBits(_bitStream, 16); + _x86_translationSize = v; + } + } + _x86_processedSize = 0; + } + _reps[0 + kPosSlotOffset] = 1; + _reps[1 + kPosSlotOffset] = 1; + _reps[2 + kPosSlotOffset] = 1; + } + + while (outSize) + { + /* + // check it for bit mode only: + if (_bitStream.WasExtraReadError_Fast()) + return S_FALSE; + */ + if (_unpackBlockSize == 0) + { + if (_skipByte) + { + if (_bitStream.GetRem() < 1) + return S_FALSE; + if (_bitStream.DirectReadByte() != 0) + return S_FALSE; + } + if (_isUncompressedBlock) + _bitStream.Switch_To_BitMode(); + if (!ReadTables(_bitStream)) + return S_FALSE; + continue; + } + + // _unpackBlockSize != 0 + UInt32 next = _unpackBlockSize; + if (next > outSize) + next = outSize; + // next != 0 + + // PRF(printf("\nnext = %d", (unsigned)next);) + + if (_isUncompressedBlock) + { + if (_bitStream.GetRem() < next) + return S_FALSE; + _bitStream.CopyTo(_win + _pos, next); + _pos += next; + _unpackBlockSize -= next; + } + else + { + _unpackBlockSize -= next; + _bitStream._bitOffset = CodeLz(this, next, _bitStream._bitOffset, _bitStream._buf); + if (_bitStream.IsOverRead()) + return S_FALSE; + _pos += next; + } + outSize -= next; + } + + // outSize == 0 + + if (_isUncompressedBlock) + { + /* we don't know where skipByte can be placed, if it's end of chunk: + 1) in current chunk - there are such cab archives, if chunk is last + 2) in next chunk - are there such archives ? */ + if (_unpackBlockSize == 0 + && _skipByte + // && outSize == 0 + && _bitStream.IsOneDirectByteLeft()) + { + _skipByte = false; + if (_bitStream.DirectReadByte() != 0) + return S_FALSE; + } + } + + if (_bitStream.GetRem() != 0) + return S_FALSE; + if (!_isUncompressedBlock) + if (!_bitStream.WasBitStreamFinishedOK()) + return S_FALSE; + return S_OK; +} + + +#if k_Filter_OutBufSize_Add > k_Lz_OutBufSize_Add + #define k_OutBufSize_Add k_Filter_OutBufSize_Add +#else + #define k_OutBufSize_Add k_Lz_OutBufSize_Add +#endif + +HRESULT CDecoder::Code_WithExceedReadWrite(const Byte *inData, size_t inSize, UInt32 outSize) throw() +{ + if (!_keepHistory) + { + _pos = 0; + _overDict = false; + } + else if (_pos == _winSize) + { + _pos = 0; + _overDict = true; +#if k_OutBufSize_Add > 0 + // data after (_winSize) can be used, because we can use overwrite. + // memset(_win + _winSize, 0, k_OutBufSize_Add); +#endif + } + _writePos = _pos; + _unpackedData = _win + _pos; + + if (outSize > _winSize - _pos) + return S_FALSE; + + PRF(printf("\ninSize = %d", (unsigned)inSize);) + PRF(if ((inSize & 1) != 0) printf("---------");) + + if (inSize == 0) + return S_FALSE; + const HRESULT res = CodeSpec(inData, inSize, outSize); + const HRESULT res2 = Flush(); + return (res == S_OK ? res2 : res); +} + + +HRESULT CDecoder::SetParams2(unsigned numDictBits) throw() +{ + if (numDictBits < kNumDictBits_Min || + numDictBits > kNumDictBits_Max) + return E_INVALIDARG; + _numDictBits = (Byte)numDictBits; + const unsigned numPosSlots2 = (numDictBits < 20) ? + numDictBits : 17 + (1u << (numDictBits - 18)); + _numPosLenSlots = numPosSlots2 * (kNumLenSlots * 2); + return S_OK; +} + + +HRESULT CDecoder::Set_DictBits_and_Alloc(unsigned numDictBits) throw() +{ + RINOK(SetParams2(numDictBits)) + const UInt32 newWinSize = (UInt32)1 << numDictBits; + if (_needAlloc) + { + if (!_win || newWinSize != _winSize) + { + // BigFree + z7_AlignedFree + (_win); + _winSize = 0; + const size_t alloc_size = newWinSize + k_OutBufSize_Add; + _win = (Byte *) + // BigAlloc + z7_AlignedAlloc + (alloc_size); + if (!_win) + return E_OUTOFMEMORY; + // optional: + memset(_win, 0, alloc_size); + } + } + _winSize = newWinSize; + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/LzxDecoder.h b/CPP/7zip/Compress/LzxDecoder.h index 3ee45d19f..b4556a6a7 100644 --- a/CPP/7zip/Compress/LzxDecoder.h +++ b/CPP/7zip/Compress/LzxDecoder.h @@ -1,106 +1,106 @@ -// LzxDecoder.h - -#ifndef ZIP7_INC_LZX_DECODER_H -#define ZIP7_INC_LZX_DECODER_H - -#include "HuffmanDecoder.h" -#include "Lzx.h" - -namespace NCompress { -namespace NLzx { - -const unsigned kAdditionalOutputBufSize = 32 * 2; - -const unsigned kNumTableBits_Main = 11; -const unsigned kNumTableBits_Len = 8; - -// if (kNumLenSymols_Big <= 256) we can use NHuffman::CDecoder256 -// if (kNumLenSymols_Big > 256) we must use NHuffman::CDecoder -// const unsigned kNumLenSymols_Big_Start = kNumLenSlots - 1 + kMatchMinLen; // 8 - 1 + 2 -const unsigned kNumLenSymols_Big_Start = 0; -// const unsigned kNumLenSymols_Big_Start = 0; -const unsigned kNumLenSymols_Big = kNumLenSymols_Big_Start + kNumLenSymbols; - -#if 1 - // for smallest structure size: - const unsigned kPosSlotOffset = 0; -#else - // use virtual entries for mispredicted branches: - const unsigned kPosSlotOffset = 256 / kNumLenSlots; -#endif - -class CBitByteDecoder; - -class CDecoder -{ -public: - UInt32 _pos; - UInt32 _winSize; - Byte *_win; - - bool _overDict; - bool _isUncompressedBlock; - bool _skipByte; - bool _keepHistory; - bool _keepHistoryForNext; - bool _needAlloc; - bool _wimMode; - Byte _numDictBits; - - // unsigned _numAlignBits_PosSlots; - // unsigned _numAlignBits; - UInt32 _numAlignBits_Dist; -private: - unsigned _numPosLenSlots; - UInt32 _unpackBlockSize; - - UInt32 _writePos; - - UInt32 _x86_translationSize; - UInt32 _x86_processedSize; - Byte *_x86_buf; - - Byte *_unpackedData; -public: - Byte _extra[kPosSlotOffset + kNumPosSlots]; - UInt32 _reps[kPosSlotOffset + kNumPosSlots]; - - NHuffman::CDecoder _mainDecoder; - NHuffman::CDecoder256 _lenDecoder; - NHuffman::CDecoder7b _alignDecoder; -private: - Byte _mainLevels[kMainTableSize]; - Byte _lenLevels[kNumLenSymols_Big]; - - HRESULT Flush() throw(); - bool ReadTables(CBitByteDecoder &_bitStream) throw(); - - HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) throw(); - HRESULT SetParams2(unsigned numDictBits) throw(); -public: - CDecoder() throw(); - ~CDecoder() throw(); - - void Set_WimMode(bool wimMode) { _wimMode = wimMode; } - void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; } - void Set_KeepHistoryForNext(bool keepHistoryForNext) { _keepHistoryForNext = keepHistoryForNext; } - - HRESULT Set_ExternalWindow_DictBits(Byte *win, unsigned numDictBits) - { - _needAlloc = false; - _win = win; - _winSize = (UInt32)1 << numDictBits; - return SetParams2(numDictBits); - } - HRESULT Set_DictBits_and_Alloc(unsigned numDictBits) throw(); - - HRESULT Code_WithExceedReadWrite(const Byte *inData, size_t inSize, UInt32 outSize) throw(); - - bool WasBlockFinished() const { return _unpackBlockSize == 0; } - const Byte *GetUnpackData() const { return _unpackedData; } - UInt32 GetUnpackSize() const { return _pos - _writePos; } -}; - -}} - -#endif +// LzxDecoder.h + +#ifndef ZIP7_INC_LZX_DECODER_H +#define ZIP7_INC_LZX_DECODER_H + +#include "HuffmanDecoder.h" +#include "Lzx.h" + +namespace NCompress { +namespace NLzx { + +const unsigned kAdditionalOutputBufSize = 32 * 2; + +const unsigned kNumTableBits_Main = 11; +const unsigned kNumTableBits_Len = 8; + +// if (kNumLenSymols_Big <= 256) we can use NHuffman::CDecoder256 +// if (kNumLenSymols_Big > 256) we must use NHuffman::CDecoder +// const unsigned kNumLenSymols_Big_Start = kNumLenSlots - 1 + kMatchMinLen; // 8 - 1 + 2 +const unsigned kNumLenSymols_Big_Start = 0; +// const unsigned kNumLenSymols_Big_Start = 0; +const unsigned kNumLenSymols_Big = kNumLenSymols_Big_Start + kNumLenSymbols; + +#if 1 + // for smallest structure size: + const unsigned kPosSlotOffset = 0; +#else + // use virtual entries for mispredicted branches: + const unsigned kPosSlotOffset = 256 / kNumLenSlots; +#endif + +class CBitByteDecoder; + +class CDecoder +{ +public: + UInt32 _pos; + UInt32 _winSize; + Byte *_win; + + bool _overDict; + bool _isUncompressedBlock; + bool _skipByte; + bool _keepHistory; + bool _keepHistoryForNext; + bool _needAlloc; + bool _wimMode; + Byte _numDictBits; + + // unsigned _numAlignBits_PosSlots; + // unsigned _numAlignBits; + UInt32 _numAlignBits_Dist; +private: + unsigned _numPosLenSlots; + UInt32 _unpackBlockSize; + + UInt32 _writePos; + + UInt32 _x86_translationSize; + UInt32 _x86_processedSize; + Byte *_x86_buf; + + Byte *_unpackedData; +public: + Byte _extra[kPosSlotOffset + kNumPosSlots]; + UInt32 _reps[kPosSlotOffset + kNumPosSlots]; + + NHuffman::CDecoder _mainDecoder; + NHuffman::CDecoder256 _lenDecoder; + NHuffman::CDecoder7b _alignDecoder; +private: + Byte _mainLevels[kMainTableSize]; + Byte _lenLevels[kNumLenSymols_Big]; + + HRESULT Flush() throw(); + bool ReadTables(CBitByteDecoder &_bitStream) throw(); + + HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) throw(); + HRESULT SetParams2(unsigned numDictBits) throw(); +public: + CDecoder() throw(); + ~CDecoder() throw(); + + void Set_WimMode(bool wimMode) { _wimMode = wimMode; } + void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; } + void Set_KeepHistoryForNext(bool keepHistoryForNext) { _keepHistoryForNext = keepHistoryForNext; } + + HRESULT Set_ExternalWindow_DictBits(Byte *win, unsigned numDictBits) + { + _needAlloc = false; + _win = win; + _winSize = (UInt32)1 << numDictBits; + return SetParams2(numDictBits); + } + HRESULT Set_DictBits_and_Alloc(unsigned numDictBits) throw(); + + HRESULT Code_WithExceedReadWrite(const Byte *inData, size_t inSize, UInt32 outSize) throw(); + + bool WasBlockFinished() const { return _unpackBlockSize == 0; } + const Byte *GetUnpackData() const { return _unpackedData; } + UInt32 GetUnpackSize() const { return _pos - _writePos; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Mtf8.h b/CPP/7zip/Compress/Mtf8.h index 7f68f7f67..1b44d00f8 100644 --- a/CPP/7zip/Compress/Mtf8.h +++ b/CPP/7zip/Compress/Mtf8.h @@ -1,212 +1,212 @@ -// Mtf8.h - -#ifndef ZIP7_INC_COMPRESS_MTF8_H -#define ZIP7_INC_COMPRESS_MTF8_H - -#include "../../../C/CpuArch.h" - -namespace NCompress { - -struct CMtf8Encoder -{ - Byte Buf[256]; - - unsigned FindAndMove(Byte v) throw() - { - size_t pos; - for (pos = 0; Buf[pos] != v; pos++); - const unsigned resPos = (unsigned)pos; - for (; pos >= 8; pos -= 8) - { - Buf[pos] = Buf[pos - 1]; - Buf[pos - 1] = Buf[pos - 2]; - Buf[pos - 2] = Buf[pos - 3]; - Buf[pos - 3] = Buf[pos - 4]; - Buf[pos - 4] = Buf[pos - 5]; - Buf[pos - 5] = Buf[pos - 6]; - Buf[pos - 6] = Buf[pos - 7]; - Buf[pos - 7] = Buf[pos - 8]; - } - for (; pos != 0; pos--) - Buf[pos] = Buf[pos - 1]; - Buf[0] = v; - return resPos; - } -}; - -/* -struct CMtf8Decoder -{ - Byte Buf[256]; - - void StartInit() { memset(Buf, 0, sizeof(Buf)); } - void Add(unsigned pos, Byte val) { Buf[pos] = val; } - Byte GetHead() const { return Buf[0]; } - Byte GetAndMove(unsigned pos) - { - Byte res = Buf[pos]; - for (; pos >= 8; pos -= 8) - { - Buf[pos] = Buf[pos - 1]; - Buf[pos - 1] = Buf[pos - 2]; - Buf[pos - 2] = Buf[pos - 3]; - Buf[pos - 3] = Buf[pos - 4]; - Buf[pos - 4] = Buf[pos - 5]; - Buf[pos - 5] = Buf[pos - 6]; - Buf[pos - 6] = Buf[pos - 7]; - Buf[pos - 7] = Buf[pos - 8]; - } - for (; pos > 0; pos--) - Buf[pos] = Buf[pos - 1]; - Buf[0] = res; - return res; - } -}; -*/ - -#ifdef MY_CPU_64BIT - typedef UInt64 CMtfVar; - #define Z7_MTF_MOVS 3 -#else - typedef UInt32 CMtfVar; - #define Z7_MTF_MOVS 2 -#endif - -#define Z7_MTF_MASK ((1 << Z7_MTF_MOVS) - 1) - - -struct CMtf8Decoder -{ - CMtfVar Buf[256 >> Z7_MTF_MOVS]; - - void StartInit() { memset(Buf, 0, sizeof(Buf)); } - void Add(unsigned pos, Byte val) { Buf[pos >> Z7_MTF_MOVS] |= ((CMtfVar)val << ((pos & Z7_MTF_MASK) << 3)); } - Byte GetHead() const { return (Byte)Buf[0]; } - - Z7_FORCE_INLINE - Byte GetAndMove(unsigned pos) throw() - { - const UInt32 lim = ((UInt32)pos >> Z7_MTF_MOVS); - pos = (pos & Z7_MTF_MASK) << 3; - CMtfVar prev = (Buf[lim] >> pos) & 0xFF; - - UInt32 i = 0; - - - /* - if ((lim & 1) != 0) - { - CMtfVar next = Buf[0]; - Buf[0] = (next << 8) | prev; - prev = (next >> (Z7_MTF_MASK << 3)); - i = 1; - lim -= 1; - } - for (; i < lim; i += 2) - { - CMtfVar n0 = Buf[i]; - CMtfVar n1 = Buf[i + 1]; - Buf[i ] = (n0 << 8) | prev; - Buf[i + 1] = (n1 << 8) | (n0 >> (Z7_MTF_MASK << 3)); - prev = (n1 >> (Z7_MTF_MASK << 3)); - } - */ - - for (; i < lim; i++) - { - const CMtfVar n0 = Buf[i]; - Buf[i ] = (n0 << 8) | prev; - prev = (n0 >> (Z7_MTF_MASK << 3)); - } - - - const CMtfVar next = Buf[i]; - const CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); - Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask); - return (Byte)Buf[0]; - } -}; - -/* -const int kSmallSize = 64; -class CMtf8Decoder -{ - Byte SmallBuffer[kSmallSize]; - int SmallSize; - int Counts[16]; - int Size; -public: - Byte Buf[256]; - - Byte GetHead() const - { - if (SmallSize > 0) - return SmallBuffer[kSmallSize - SmallSize]; - return Buf[0]; - } - - void Init(int size) - { - Size = size; - SmallSize = 0; - for (int i = 0; i < 16; i++) - { - Counts[i] = ((size >= 16) ? 16 : size); - size -= Counts[i]; - } - } - - void Add(unsigned pos, Byte val) - { - Buf[pos] = val; - } - - Byte GetAndMove(int pos) - { - if (pos < SmallSize) - { - Byte *p = SmallBuffer + kSmallSize - SmallSize; - Byte res = p[pos]; - for (; pos > 0; pos--) - p[pos] = p[pos - 1]; - SmallBuffer[kSmallSize - SmallSize] = res; - return res; - } - if (SmallSize == kSmallSize) - { - int i = Size - 1; - int g = 16; - do - { - g--; - int offset = (g << 4); - for (int t = Counts[g] - 1; t >= 0; t--, i--) - Buf[i] = Buf[offset + t]; - } - while (g != 0); - - for (i = kSmallSize - 1; i >= 0; i--) - Buf[i] = SmallBuffer[i]; - Init(Size); - } - pos -= SmallSize; - int g; - for (g = 0; pos >= Counts[g]; g++) - pos -= Counts[g]; - int offset = (g << 4); - Byte res = Buf[offset + pos]; - for (pos; pos < 16 - 1; pos++) - Buf[offset + pos] = Buf[offset + pos + 1]; - - SmallSize++; - SmallBuffer[kSmallSize - SmallSize] = res; - - Counts[g]--; - return res; - } -}; -*/ - -} - -#endif +// Mtf8.h + +#ifndef ZIP7_INC_COMPRESS_MTF8_H +#define ZIP7_INC_COMPRESS_MTF8_H + +#include "../../../C/CpuArch.h" + +namespace NCompress { + +struct CMtf8Encoder +{ + Byte Buf[256]; + + unsigned FindAndMove(Byte v) throw() + { + size_t pos; + for (pos = 0; Buf[pos] != v; pos++); + const unsigned resPos = (unsigned)pos; + for (; pos >= 8; pos -= 8) + { + Buf[pos] = Buf[pos - 1]; + Buf[pos - 1] = Buf[pos - 2]; + Buf[pos - 2] = Buf[pos - 3]; + Buf[pos - 3] = Buf[pos - 4]; + Buf[pos - 4] = Buf[pos - 5]; + Buf[pos - 5] = Buf[pos - 6]; + Buf[pos - 6] = Buf[pos - 7]; + Buf[pos - 7] = Buf[pos - 8]; + } + for (; pos != 0; pos--) + Buf[pos] = Buf[pos - 1]; + Buf[0] = v; + return resPos; + } +}; + +/* +struct CMtf8Decoder +{ + Byte Buf[256]; + + void StartInit() { memset(Buf, 0, sizeof(Buf)); } + void Add(unsigned pos, Byte val) { Buf[pos] = val; } + Byte GetHead() const { return Buf[0]; } + Byte GetAndMove(unsigned pos) + { + Byte res = Buf[pos]; + for (; pos >= 8; pos -= 8) + { + Buf[pos] = Buf[pos - 1]; + Buf[pos - 1] = Buf[pos - 2]; + Buf[pos - 2] = Buf[pos - 3]; + Buf[pos - 3] = Buf[pos - 4]; + Buf[pos - 4] = Buf[pos - 5]; + Buf[pos - 5] = Buf[pos - 6]; + Buf[pos - 6] = Buf[pos - 7]; + Buf[pos - 7] = Buf[pos - 8]; + } + for (; pos > 0; pos--) + Buf[pos] = Buf[pos - 1]; + Buf[0] = res; + return res; + } +}; +*/ + +#ifdef MY_CPU_64BIT + typedef UInt64 CMtfVar; + #define Z7_MTF_MOVS 3 +#else + typedef UInt32 CMtfVar; + #define Z7_MTF_MOVS 2 +#endif + +#define Z7_MTF_MASK ((1 << Z7_MTF_MOVS) - 1) + + +struct CMtf8Decoder +{ + CMtfVar Buf[256 >> Z7_MTF_MOVS]; + + void StartInit() { memset(Buf, 0, sizeof(Buf)); } + void Add(unsigned pos, Byte val) { Buf[pos >> Z7_MTF_MOVS] |= ((CMtfVar)val << ((pos & Z7_MTF_MASK) << 3)); } + Byte GetHead() const { return (Byte)Buf[0]; } + + Z7_FORCE_INLINE + Byte GetAndMove(unsigned pos) throw() + { + const UInt32 lim = ((UInt32)pos >> Z7_MTF_MOVS); + pos = (pos & Z7_MTF_MASK) << 3; + CMtfVar prev = (Buf[lim] >> pos) & 0xFF; + + UInt32 i = 0; + + + /* + if ((lim & 1) != 0) + { + CMtfVar next = Buf[0]; + Buf[0] = (next << 8) | prev; + prev = (next >> (Z7_MTF_MASK << 3)); + i = 1; + lim -= 1; + } + for (; i < lim; i += 2) + { + CMtfVar n0 = Buf[i]; + CMtfVar n1 = Buf[i + 1]; + Buf[i ] = (n0 << 8) | prev; + Buf[i + 1] = (n1 << 8) | (n0 >> (Z7_MTF_MASK << 3)); + prev = (n1 >> (Z7_MTF_MASK << 3)); + } + */ + + for (; i < lim; i++) + { + const CMtfVar n0 = Buf[i]; + Buf[i ] = (n0 << 8) | prev; + prev = (n0 >> (Z7_MTF_MASK << 3)); + } + + + const CMtfVar next = Buf[i]; + const CMtfVar mask = (((CMtfVar)0x100 << pos) - 1); + Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask); + return (Byte)Buf[0]; + } +}; + +/* +const int kSmallSize = 64; +class CMtf8Decoder +{ + Byte SmallBuffer[kSmallSize]; + int SmallSize; + int Counts[16]; + int Size; +public: + Byte Buf[256]; + + Byte GetHead() const + { + if (SmallSize > 0) + return SmallBuffer[kSmallSize - SmallSize]; + return Buf[0]; + } + + void Init(int size) + { + Size = size; + SmallSize = 0; + for (int i = 0; i < 16; i++) + { + Counts[i] = ((size >= 16) ? 16 : size); + size -= Counts[i]; + } + } + + void Add(unsigned pos, Byte val) + { + Buf[pos] = val; + } + + Byte GetAndMove(int pos) + { + if (pos < SmallSize) + { + Byte *p = SmallBuffer + kSmallSize - SmallSize; + Byte res = p[pos]; + for (; pos > 0; pos--) + p[pos] = p[pos - 1]; + SmallBuffer[kSmallSize - SmallSize] = res; + return res; + } + if (SmallSize == kSmallSize) + { + int i = Size - 1; + int g = 16; + do + { + g--; + int offset = (g << 4); + for (int t = Counts[g] - 1; t >= 0; t--, i--) + Buf[i] = Buf[offset + t]; + } + while (g != 0); + + for (i = kSmallSize - 1; i >= 0; i--) + Buf[i] = SmallBuffer[i]; + Init(Size); + } + pos -= SmallSize; + int g; + for (g = 0; pos >= Counts[g]; g++) + pos -= Counts[g]; + int offset = (g << 4); + Byte res = Buf[offset + pos]; + for (pos; pos < 16 - 1; pos++) + Buf[offset + pos] = Buf[offset + pos + 1]; + + SmallSize++; + SmallBuffer[kSmallSize - SmallSize] = res; + + Counts[g]--; + return res; + } +}; +*/ + +} + +#endif diff --git a/CPP/7zip/Compress/PpmdDecoder.cpp b/CPP/7zip/Compress/PpmdDecoder.cpp index e2399dc4b..3dbde751b 100644 --- a/CPP/7zip/Compress/PpmdDecoder.cpp +++ b/CPP/7zip/Compress/PpmdDecoder.cpp @@ -1,219 +1,219 @@ -// PpmdDecoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" - -#include "../Common/StreamUtils.h" - -#include "PpmdDecoder.h" - -namespace NCompress { -namespace NPpmd { - -static const UInt32 kBufSize = (1 << 16); - -enum -{ - kStatus_NeedInit, - kStatus_Normal, - kStatus_Finished_With_Mark, - kStatus_Error -}; - -CDecoder::~CDecoder() -{ - ::MidFree(_outBuf); - Ppmd7_Free(&_ppmd, &g_BigAlloc); -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) -{ - if (size < 5) - return E_INVALIDARG; - _order = props[0]; - const UInt32 memSize = GetUi32(props + 1); - if (_order < PPMD7_MIN_ORDER || - _order > PPMD7_MAX_ORDER || - memSize < PPMD7_MIN_MEM_SIZE || - memSize > PPMD7_MAX_MEM_SIZE) - return E_NOTIMPL; - if (!_inStream.Alloc(1 << 20)) - return E_OUTOFMEMORY; - if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc)) - return E_OUTOFMEMORY; - return S_OK; -} - -#define MY_rangeDec _ppmd.rc.dec - -#define CHECK_EXTRA_ERROR \ - if (_inStream.Extra) { \ - _status = kStatus_Error; \ - return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); } - - -HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size) -{ - if (_res != S_OK) - return _res; - - switch (_status) - { - case kStatus_Finished_With_Mark: return S_OK; - case kStatus_Error: return S_FALSE; - case kStatus_NeedInit: - _inStream.Init(); - if (!Ppmd7z_RangeDec_Init(&MY_rangeDec)) - { - _status = kStatus_Error; - return (_res = S_FALSE); - } - CHECK_EXTRA_ERROR - _status = kStatus_Normal; - Ppmd7_Init(&_ppmd, _order); - break; - default: break; - } - - if (_outSizeDefined) - { - const UInt64 rem = _outSize - _processedSize; - if (size > rem) - size = (UInt32)rem; - } - - int sym = 0; - { - Byte *buf = memStream; - const Byte *lim = buf + size; - for (; buf != lim; buf++) - { - sym = Ppmd7z_DecodeSymbol(&_ppmd); - if (_inStream.Extra || sym < 0) - break; - *buf = (Byte)sym; - } - /* - buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim); - sym = _ppmd.LastSymbol; - */ - _processedSize += (size_t)(buf - memStream); - } - - CHECK_EXTRA_ERROR - - if (sym >= 0) - { - if (!FinishStream - || !_outSizeDefined - || _outSize != _processedSize - || MY_rangeDec.Code == 0) - return S_OK; - /* - // We can decode additional End Marker here: - sym = Ppmd7z_DecodeSymbol(&_ppmd); - CHECK_EXTRA_ERROR - */ - } - - if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0) - { - _status = kStatus_Error; - return (_res = S_FALSE); - } - - _status = kStatus_Finished_With_Mark; - return S_OK; -} - - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - if (!_outBuf) - { - _outBuf = (Byte *)::MidAlloc(kBufSize); - if (!_outBuf) - return E_OUTOFMEMORY; - } - - _inStream.Stream = inStream; - SetOutStreamSize(outSize); - - do - { - const UInt64 startPos = _processedSize; - const HRESULT res = CodeSpec(_outBuf, kBufSize); - const size_t processed = (size_t)(_processedSize - startPos); - RINOK(WriteStream(outStream, _outBuf, processed)) - RINOK(res) - if (_status == kStatus_Finished_With_Mark) - break; - if (progress) - { - const UInt64 inProcessed = _inStream.GetProcessed(); - RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize)) - } - } - while (!_outSizeDefined || _processedSize < _outSize); - - if (FinishStream && inSize && *inSize != _inStream.GetProcessed()) - return S_FALSE; - - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) -{ - _outSizeDefined = (outSize != NULL); - if (_outSizeDefined) - _outSize = *outSize; - _processedSize = 0; - _status = kStatus_NeedInit; - _res = SZ_OK; - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - FinishStream = (finishMode != 0); - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inStream.GetProcessed(); - return S_OK; -} - -#ifndef Z7_NO_READ_FROM_CODER - -Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) -{ - InSeqStream = inStream; - _inStream.Stream = inStream; - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::ReleaseInStream()) -{ - InSeqStream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - const UInt64 startPos = _processedSize; - const HRESULT res = CodeSpec((Byte *)data, size); - if (processedSize) - *processedSize = (UInt32)(_processedSize - startPos); - return res; -} - -#endif - -}} +// PpmdDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "PpmdDecoder.h" + +namespace NCompress { +namespace NPpmd { + +static const UInt32 kBufSize = (1 << 16); + +enum +{ + kStatus_NeedInit, + kStatus_Normal, + kStatus_Finished_With_Mark, + kStatus_Error +}; + +CDecoder::~CDecoder() +{ + ::MidFree(_outBuf); + Ppmd7_Free(&_ppmd, &g_BigAlloc); +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)) +{ + if (size < 5) + return E_INVALIDARG; + _order = props[0]; + const UInt32 memSize = GetUi32(props + 1); + if (_order < PPMD7_MIN_ORDER || + _order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return E_NOTIMPL; + if (!_inStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc)) + return E_OUTOFMEMORY; + return S_OK; +} + +#define MY_rangeDec _ppmd.rc.dec + +#define CHECK_EXTRA_ERROR \ + if (_inStream.Extra) { \ + _status = kStatus_Error; \ + return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); } + + +HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size) +{ + if (_res != S_OK) + return _res; + + switch (_status) + { + case kStatus_Finished_With_Mark: return S_OK; + case kStatus_Error: return S_FALSE; + case kStatus_NeedInit: + _inStream.Init(); + if (!Ppmd7z_RangeDec_Init(&MY_rangeDec)) + { + _status = kStatus_Error; + return (_res = S_FALSE); + } + CHECK_EXTRA_ERROR + _status = kStatus_Normal; + Ppmd7_Init(&_ppmd, _order); + break; + default: break; + } + + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _processedSize; + if (size > rem) + size = (UInt32)rem; + } + + int sym = 0; + { + Byte *buf = memStream; + const Byte *lim = buf + size; + for (; buf != lim; buf++) + { + sym = Ppmd7z_DecodeSymbol(&_ppmd); + if (_inStream.Extra || sym < 0) + break; + *buf = (Byte)sym; + } + /* + buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim); + sym = _ppmd.LastSymbol; + */ + _processedSize += (size_t)(buf - memStream); + } + + CHECK_EXTRA_ERROR + + if (sym >= 0) + { + if (!FinishStream + || !_outSizeDefined + || _outSize != _processedSize + || MY_rangeDec.Code == 0) + return S_OK; + /* + // We can decode additional End Marker here: + sym = Ppmd7z_DecodeSymbol(&_ppmd); + CHECK_EXTRA_ERROR + */ + } + + if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0) + { + _status = kStatus_Error; + return (_res = S_FALSE); + } + + _status = kStatus_Finished_With_Mark; + return S_OK; +} + + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + if (!_outBuf) + { + _outBuf = (Byte *)::MidAlloc(kBufSize); + if (!_outBuf) + return E_OUTOFMEMORY; + } + + _inStream.Stream = inStream; + SetOutStreamSize(outSize); + + do + { + const UInt64 startPos = _processedSize; + const HRESULT res = CodeSpec(_outBuf, kBufSize); + const size_t processed = (size_t)(_processedSize - startPos); + RINOK(WriteStream(outStream, _outBuf, processed)) + RINOK(res) + if (_status == kStatus_Finished_With_Mark) + break; + if (progress) + { + const UInt64 inProcessed = _inStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize)) + } + } + while (!_outSizeDefined || _processedSize < _outSize); + + if (FinishStream && inSize && *inSize != _inStream.GetProcessed()) + return S_FALSE; + + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) +{ + _outSizeDefined = (outSize != NULL); + if (_outSizeDefined) + _outSize = *outSize; + _processedSize = 0; + _status = kStatus_NeedInit; + _res = SZ_OK; + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + FinishStream = (finishMode != 0); + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inStream.GetProcessed(); + return S_OK; +} + +#ifndef Z7_NO_READ_FROM_CODER + +Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) +{ + InSeqStream = inStream; + _inStream.Stream = inStream; + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::ReleaseInStream()) +{ + InSeqStream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + const UInt64 startPos = _processedSize; + const HRESULT res = CodeSpec((Byte *)data, size); + if (processedSize) + *processedSize = (UInt32)(_processedSize - startPos); + return res; +} + +#endif + +}} diff --git a/CPP/7zip/Compress/PpmdDecoder.h b/CPP/7zip/Compress/PpmdDecoder.h index c4e703d8e..22e5bd495 100644 --- a/CPP/7zip/Compress/PpmdDecoder.h +++ b/CPP/7zip/Compress/PpmdDecoder.h @@ -1,87 +1,87 @@ -// PpmdDecoder.h - -#ifndef ZIP7_INC_COMPRESS_PPMD_DECODER_H -#define ZIP7_INC_COMPRESS_PPMD_DECODER_H - -#include "../../../C/Ppmd7.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/CWrappers.h" - -namespace NCompress { -namespace NPpmd { - -class CDecoder Z7_final: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - #ifndef Z7_NO_READ_FROM_CODER - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - #ifndef Z7_NO_READ_FROM_CODER - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ISequentialInStream) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) - #ifndef Z7_NO_READ_FROM_CODER - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - Z7_IFACE_COM7_IMP(ICompressSetInStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) - #else - Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize)); - #endif - - Byte *_outBuf; - CByteInBufWrap _inStream; - CPpmd7 _ppmd; - - Byte _order; - bool FinishStream; - bool _outSizeDefined; - HRESULT _res; - int _status; - UInt64 _outSize; - UInt64 _processedSize; - - HRESULT CodeSpec(Byte *memStream, UInt32 size); - -public: - - #ifndef Z7_NO_READ_FROM_CODER - CMyComPtr InSeqStream; - #endif - - CDecoder(): - _outBuf(NULL), - FinishStream(false), - _outSizeDefined(false) - { - Ppmd7_Construct(&_ppmd); - _ppmd.rc.dec.Stream = &_inStream.vt; - } - - ~CDecoder(); -}; - -}} - -#endif +// PpmdDecoder.h + +#ifndef ZIP7_INC_COMPRESS_PPMD_DECODER_H +#define ZIP7_INC_COMPRESS_PPMD_DECODER_H + +#include "../../../C/Ppmd7.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/CWrappers.h" + +namespace NCompress { +namespace NPpmd { + +class CDecoder Z7_final: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + #ifndef Z7_NO_READ_FROM_CODER + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + #ifndef Z7_NO_READ_FROM_CODER + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ISequentialInStream) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) + #ifndef Z7_NO_READ_FROM_CODER + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + Z7_IFACE_COM7_IMP(ICompressSetInStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) + #else + Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize)); + #endif + + Byte *_outBuf; + CByteInBufWrap _inStream; + CPpmd7 _ppmd; + + Byte _order; + bool FinishStream; + bool _outSizeDefined; + HRESULT _res; + int _status; + UInt64 _outSize; + UInt64 _processedSize; + + HRESULT CodeSpec(Byte *memStream, UInt32 size); + +public: + + #ifndef Z7_NO_READ_FROM_CODER + CMyComPtr InSeqStream; + #endif + + CDecoder(): + _outBuf(NULL), + FinishStream(false), + _outSizeDefined(false) + { + Ppmd7_Construct(&_ppmd); + _ppmd.rc.dec.Stream = &_inStream.vt; + } + + ~CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/PpmdEncoder.cpp b/CPP/7zip/Compress/PpmdEncoder.cpp index 16a40d69f..2dfca6df6 100644 --- a/CPP/7zip/Compress/PpmdEncoder.cpp +++ b/CPP/7zip/Compress/PpmdEncoder.cpp @@ -1,193 +1,193 @@ -// PpmdEncoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/StreamUtils.h" - -#include "PpmdEncoder.h" - -namespace NCompress { -namespace NPpmd { - -static const UInt32 kBufSize = (1 << 20); - -static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 }; - -void CEncProps::Normalize(int level) -{ - if (level < 0) level = 5; - if (level > 9) level = 9; - if (MemSize == (UInt32)(Int32)-1) - MemSize = (UInt32)1 << (level + 19); - const unsigned kMult = 16; - if (MemSize / kMult > ReduceSize) - { - for (unsigned i = 16; i < 32; i++) - { - UInt32 m = (UInt32)1 << i; - if (ReduceSize <= m / kMult) - { - if (MemSize > m) - MemSize = m; - break; - } - } - } - if (Order == -1) Order = kOrders[(unsigned)level]; -} - -CEncoder::CEncoder(): - _inBuf(NULL) -{ - _props.Normalize(-1); - Ppmd7_Construct(&_ppmd); - _ppmd.rc.enc.Stream = &_outStream.vt; -} - -CEncoder::~CEncoder() -{ - ::MidFree(_inBuf); - Ppmd7_Free(&_ppmd, &g_BigAlloc); -} - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - int level = -1; - CEncProps props; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - const PROPID propID = propIDs[i]; - if (propID > NCoderPropID::kReduceSize) - continue; - if (propID == NCoderPropID::kReduceSize) - { - if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1) - props.ReduceSize = (UInt32)prop.uhVal.QuadPart; - continue; - } - - if (propID == NCoderPropID::kUsedMemorySize) - { - // here we have selected (4 GiB - 1 KiB) as replacement for (4 GiB) MEM_SIZE. - const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10); - UInt32 v; - if (prop.vt == VT_UI8) - { - // 21.03 : we support 64-bit values (for 4 GiB value) - const UInt64 v64 = prop.uhVal.QuadPart; - if (v64 > ((UInt64)1 << 32)) - return E_INVALIDARG; - if (v64 == ((UInt64)1 << 32)) - v = kPpmd_Default_4g; - else - v = (UInt32)v64; - } - else if (prop.vt == VT_UI4) - v = (UInt32)prop.ulVal; - else - return E_INVALIDARG; - if (v > PPMD7_MAX_MEM_SIZE) - v = kPpmd_Default_4g; - - /* here we restrict MEM_SIZE for Encoder. - It's for better performance of encoding and decoding. - The Decoder still supports more MEM_SIZE values. */ - if (v < ((UInt32)1 << 16) || (v & 3) != 0) - return E_INVALIDARG; - // if (v < PPMD7_MIN_MEM_SIZE) return E_INVALIDARG; // (1 << 11) - /* - Supported MEM_SIZE range : - [ (1 << 11) , 0xFFFFFFFF - 12 * 3 ] - current 7-Zip's Ppmd7 constants - [ 1824 , 0xFFFFFFFF ] - real limits of Ppmd7 code - */ - props.MemSize = v; - continue; - } - - if (prop.vt != VT_UI4) - return E_INVALIDARG; - const UInt32 v = (UInt32)prop.ulVal; - switch (propID) - { - case NCoderPropID::kOrder: - if (v < 2 || v > 32) - return E_INVALIDARG; - props.Order = (Byte)v; - break; - case NCoderPropID::kNumThreads: break; - case NCoderPropID::kLevel: level = (int)v; break; - default: return E_INVALIDARG; - } - } - props.Normalize(level); - _props = props; - return S_OK; -} - -Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) -{ - const UInt32 kPropSize = 5; - Byte props[kPropSize]; - props[0] = (Byte)_props.Order; - SetUi32(props + 1, _props.MemSize) - return WriteStream(outStream, props, kPropSize); -} - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) -{ - if (!_inBuf) - { - _inBuf = (Byte *)::MidAlloc(kBufSize); - if (!_inBuf) - return E_OUTOFMEMORY; - } - if (!_outStream.Alloc(1 << 20)) - return E_OUTOFMEMORY; - if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc)) - return E_OUTOFMEMORY; - - _outStream.Stream = outStream; - _outStream.Init(); - - Ppmd7z_Init_RangeEnc(&_ppmd); - Ppmd7_Init(&_ppmd, (unsigned)_props.Order); - - UInt64 processed = 0; - for (;;) - { - UInt32 size; - RINOK(inStream->Read(_inBuf, kBufSize, &size)) - if (size == 0) - { - // We don't write EndMark in PPMD-7z. - // Ppmd7z_EncodeSymbol(&_ppmd, -1); - Ppmd7z_Flush_RangeEnc(&_ppmd); - return _outStream.Flush(); - } - const Byte *buf = _inBuf; - const Byte *lim = buf + size; - /* - for (; buf < lim; buf++) - { - Ppmd7z_EncodeSymbol(&_ppmd, *buf); - RINOK(_outStream.Res); - } - */ - - Ppmd7z_EncodeSymbols(&_ppmd, buf, lim); - RINOK(_outStream.Res) - - processed += size; - if (progress) - { - const UInt64 outSize = _outStream.GetProcessed(); - RINOK(progress->SetRatioInfo(&processed, &outSize)) - } - } -} - -}} +// PpmdEncoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "PpmdEncoder.h" + +namespace NCompress { +namespace NPpmd { + +static const UInt32 kBufSize = (1 << 20); + +static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 }; + +void CEncProps::Normalize(int level) +{ + if (level < 0) level = 5; + if (level > 9) level = 9; + if (MemSize == (UInt32)(Int32)-1) + MemSize = (UInt32)1 << (level + 19); + const unsigned kMult = 16; + if (MemSize / kMult > ReduceSize) + { + for (unsigned i = 16; i < 32; i++) + { + UInt32 m = (UInt32)1 << i; + if (ReduceSize <= m / kMult) + { + if (MemSize > m) + MemSize = m; + break; + } + } + } + if (Order == -1) Order = kOrders[(unsigned)level]; +} + +CEncoder::CEncoder(): + _inBuf(NULL) +{ + _props.Normalize(-1); + Ppmd7_Construct(&_ppmd); + _ppmd.rc.enc.Stream = &_outStream.vt; +} + +CEncoder::~CEncoder() +{ + ::MidFree(_inBuf); + Ppmd7_Free(&_ppmd, &g_BigAlloc); +} + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + int level = -1; + CEncProps props; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + const PROPID propID = propIDs[i]; + if (propID > NCoderPropID::kReduceSize) + continue; + if (propID == NCoderPropID::kReduceSize) + { + if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1) + props.ReduceSize = (UInt32)prop.uhVal.QuadPart; + continue; + } + + if (propID == NCoderPropID::kUsedMemorySize) + { + // here we have selected (4 GiB - 1 KiB) as replacement for (4 GiB) MEM_SIZE. + const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10); + UInt32 v; + if (prop.vt == VT_UI8) + { + // 21.03 : we support 64-bit values (for 4 GiB value) + const UInt64 v64 = prop.uhVal.QuadPart; + if (v64 > ((UInt64)1 << 32)) + return E_INVALIDARG; + if (v64 == ((UInt64)1 << 32)) + v = kPpmd_Default_4g; + else + v = (UInt32)v64; + } + else if (prop.vt == VT_UI4) + v = (UInt32)prop.ulVal; + else + return E_INVALIDARG; + if (v > PPMD7_MAX_MEM_SIZE) + v = kPpmd_Default_4g; + + /* here we restrict MEM_SIZE for Encoder. + It's for better performance of encoding and decoding. + The Decoder still supports more MEM_SIZE values. */ + if (v < ((UInt32)1 << 16) || (v & 3) != 0) + return E_INVALIDARG; + // if (v < PPMD7_MIN_MEM_SIZE) return E_INVALIDARG; // (1 << 11) + /* + Supported MEM_SIZE range : + [ (1 << 11) , 0xFFFFFFFF - 12 * 3 ] - current 7-Zip's Ppmd7 constants + [ 1824 , 0xFFFFFFFF ] - real limits of Ppmd7 code + */ + props.MemSize = v; + continue; + } + + if (prop.vt != VT_UI4) + return E_INVALIDARG; + const UInt32 v = (UInt32)prop.ulVal; + switch (propID) + { + case NCoderPropID::kOrder: + if (v < 2 || v > 32) + return E_INVALIDARG; + props.Order = (Byte)v; + break; + case NCoderPropID::kNumThreads: break; + case NCoderPropID::kLevel: level = (int)v; break; + default: return E_INVALIDARG; + } + } + props.Normalize(level); + _props = props; + return S_OK; +} + +Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) +{ + const UInt32 kPropSize = 5; + Byte props[kPropSize]; + props[0] = (Byte)_props.Order; + SetUi32(props + 1, _props.MemSize) + return WriteStream(outStream, props, kPropSize); +} + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) +{ + if (!_inBuf) + { + _inBuf = (Byte *)::MidAlloc(kBufSize); + if (!_inBuf) + return E_OUTOFMEMORY; + } + if (!_outStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc)) + return E_OUTOFMEMORY; + + _outStream.Stream = outStream; + _outStream.Init(); + + Ppmd7z_Init_RangeEnc(&_ppmd); + Ppmd7_Init(&_ppmd, (unsigned)_props.Order); + + UInt64 processed = 0; + for (;;) + { + UInt32 size; + RINOK(inStream->Read(_inBuf, kBufSize, &size)) + if (size == 0) + { + // We don't write EndMark in PPMD-7z. + // Ppmd7z_EncodeSymbol(&_ppmd, -1); + Ppmd7z_Flush_RangeEnc(&_ppmd); + return _outStream.Flush(); + } + const Byte *buf = _inBuf; + const Byte *lim = buf + size; + /* + for (; buf < lim; buf++) + { + Ppmd7z_EncodeSymbol(&_ppmd, *buf); + RINOK(_outStream.Res); + } + */ + + Ppmd7z_EncodeSymbols(&_ppmd, buf, lim); + RINOK(_outStream.Res) + + processed += size; + if (progress) + { + const UInt64 outSize = _outStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&processed, &outSize)) + } + } +} + +}} diff --git a/CPP/7zip/Compress/PpmdEncoder.h b/CPP/7zip/Compress/PpmdEncoder.h index 990c4c8a1..057cccbec 100644 --- a/CPP/7zip/Compress/PpmdEncoder.h +++ b/CPP/7zip/Compress/PpmdEncoder.h @@ -1,49 +1,49 @@ -// PpmdEncoder.h - -#ifndef ZIP7_INC_COMPRESS_PPMD_ENCODER_H -#define ZIP7_INC_COMPRESS_PPMD_ENCODER_H - -#include "../../../C/Ppmd7.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/CWrappers.h" - -namespace NCompress { -namespace NPpmd { - -struct CEncProps -{ - UInt32 MemSize; - UInt32 ReduceSize; - int Order; - - CEncProps() - { - MemSize = (UInt32)(Int32)-1; - ReduceSize = (UInt32)(Int32)-1; - Order = -1; - } - void Normalize(int level); -}; - -Z7_CLASS_IMP_COM_3( - CEncoder - , ICompressCoder - , ICompressSetCoderProperties - , ICompressWriteCoderProperties -) - Byte *_inBuf; - CByteOutBufWrap _outStream; - CPpmd7 _ppmd; - CEncProps _props; -public: - CEncoder(); - ~CEncoder(); -}; - -}} - -#endif +// PpmdEncoder.h + +#ifndef ZIP7_INC_COMPRESS_PPMD_ENCODER_H +#define ZIP7_INC_COMPRESS_PPMD_ENCODER_H + +#include "../../../C/Ppmd7.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/CWrappers.h" + +namespace NCompress { +namespace NPpmd { + +struct CEncProps +{ + UInt32 MemSize; + UInt32 ReduceSize; + int Order; + + CEncProps() + { + MemSize = (UInt32)(Int32)-1; + ReduceSize = (UInt32)(Int32)-1; + Order = -1; + } + void Normalize(int level); +}; + +Z7_CLASS_IMP_COM_3( + CEncoder + , ICompressCoder + , ICompressSetCoderProperties + , ICompressWriteCoderProperties +) + Byte *_inBuf; + CByteOutBufWrap _outStream; + CPpmd7 _ppmd; + CEncProps _props; +public: + CEncoder(); + ~CEncoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/PpmdRegister.cpp b/CPP/7zip/Compress/PpmdRegister.cpp index 4950d7cbf..fb5619c96 100644 --- a/CPP/7zip/Compress/PpmdRegister.cpp +++ b/CPP/7zip/Compress/PpmdRegister.cpp @@ -1,22 +1,22 @@ -// PpmdRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "PpmdDecoder.h" - -#ifndef Z7_EXTRACT_ONLY -#include "PpmdEncoder.h" -#endif - -namespace NCompress { -namespace NPpmd { - -REGISTER_CODEC_E(PPMD, - CDecoder(), - CEncoder(), - 0x30401, - "PPMD") - -}} +// PpmdRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "PpmdDecoder.h" + +#ifndef Z7_EXTRACT_ONLY +#include "PpmdEncoder.h" +#endif + +namespace NCompress { +namespace NPpmd { + +REGISTER_CODEC_E(PPMD, + CDecoder(), + CEncoder(), + 0x30401, + "PPMD") + +}} diff --git a/CPP/7zip/Compress/PpmdZip.cpp b/CPP/7zip/Compress/PpmdZip.cpp index 0ef8cde24..e59e52f13 100644 --- a/CPP/7zip/Compress/PpmdZip.cpp +++ b/CPP/7zip/Compress/PpmdZip.cpp @@ -1,309 +1,309 @@ -// PpmdZip.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../Common/RegisterCodec.h" -#include "../Common/StreamUtils.h" - -#include "PpmdZip.h" - -namespace NCompress { -namespace NPpmdZip { - -static const UInt32 kBufSize = 1 << 20; - -bool CBuf::Alloc() -{ - if (!Buf) - Buf = (Byte *)::MidAlloc(kBufSize); - return (Buf != NULL); -} - -CDecoder::CDecoder(bool fullFileMode): - _fullFileMode(fullFileMode) -{ - Ppmd8_Construct(&_ppmd); - _ppmd.Stream.In = &_inStream.vt; -} - -CDecoder::~CDecoder() -{ - Ppmd8_Free(&_ppmd, &g_BigAlloc); -} - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - // try { - - if (!_outStream.Alloc()) - return E_OUTOFMEMORY; - if (!_inStream.Alloc(1 << 20)) - return E_OUTOFMEMORY; - - _inStream.Stream = inStream; - _inStream.Init(); - - { - Byte buf[2]; - for (int i = 0; i < 2; i++) - buf[i] = _inStream.ReadByte(); - if (_inStream.Extra) - return S_FALSE; - - const UInt32 val = GetUi16(buf); - const unsigned order = (val & 0xF) + 1; - const UInt32 mem = ((val >> 4) & 0xFF) + 1; - const unsigned restor = (val >> 12); - if (order < 2 || restor > 2) - return S_FALSE; - - #ifndef PPMD8_FREEZE_SUPPORT - if (restor == 2) - return E_NOTIMPL; - #endif - - if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc)) - return E_OUTOFMEMORY; - - if (!Ppmd8_Init_RangeDec(&_ppmd)) - return S_FALSE; - Ppmd8_Init(&_ppmd, order, restor); - } - - bool wasFinished = false; - UInt64 processedSize = 0; - - for (;;) - { - size_t size = kBufSize; - if (outSize) - { - const UInt64 rem = *outSize - processedSize; - if (size > rem) - { - size = (size_t)rem; - if (size == 0) - break; - } - } - - int sym; - Byte *buf = _outStream.Buf; - const Byte *lim = buf + size; - - do - { - sym = Ppmd8_DecodeSymbol(&_ppmd); - if (_inStream.Extra || sym < 0) - break; - *buf++ = (Byte)sym; - } - while (buf != lim); - - const size_t cur = (size_t)(buf - _outStream.Buf); - processedSize += cur; - - RINOK(WriteStream(outStream, _outStream.Buf, cur)) - - RINOK(_inStream.Res) - if (_inStream.Extra) - return S_FALSE; - - if (sym < 0) - { - if (sym != -1) - return S_FALSE; - wasFinished = true; - break; - } - - if (progress) - { - const UInt64 inProccessed = _inStream.GetProcessed(); - RINOK(progress->SetRatioInfo(&inProccessed, &processedSize)) - } - } - - RINOK(_inStream.Res) - - if (_fullFileMode) - { - if (!wasFinished) - { - const int res = Ppmd8_DecodeSymbol(&_ppmd); - RINOK(_inStream.Res) - if (_inStream.Extra || res != -1) - return S_FALSE; - } - if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd)) - return S_FALSE; - - if (inSize && *inSize != _inStream.GetProcessed()) - return S_FALSE; - } - - return S_OK; - - // } catch (...) { return E_FAIL; } -} - - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - _fullFileMode = (finishMode != 0); - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inStream.GetProcessed(); - return S_OK; -} - - - -// ---------- Encoder ---------- - -void CEncProps::Normalize(int level) -{ - if (level < 0) level = 5; - if (level == 0) level = 1; - if (level > 9) level = 9; - if (MemSizeMB == (UInt32)(Int32)-1) - MemSizeMB = 1 << (level - 1); - const unsigned kMult = 16; - for (UInt32 m = 1; m < MemSizeMB; m <<= 1) - if (ReduceSize <= (m << 20) / kMult) - { - MemSizeMB = m; - break; - } - if (Order == -1) Order = 3 + level; - if (Restor == -1) - Restor = level < 7 ? - PPMD8_RESTORE_METHOD_RESTART : - PPMD8_RESTORE_METHOD_CUT_OFF; -} - -CEncoder::~CEncoder() -{ - Ppmd8_Free(&_ppmd, &g_BigAlloc); -} - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - int level = -1; - CEncProps props; - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - const PROPID propID = propIDs[i]; - if (propID > NCoderPropID::kReduceSize) - continue; - if (propID == NCoderPropID::kReduceSize) - { - props.ReduceSize = (UInt32)(Int32)-1; - if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1) - props.ReduceSize = (UInt32)prop.uhVal.QuadPart; - continue; - } - if (prop.vt != VT_UI4) - return E_INVALIDARG; - const UInt32 v = (UInt32)prop.ulVal; - switch (propID) - { - case NCoderPropID::kUsedMemorySize: - if (v < (1 << 20) || v > (1 << 28)) - return E_INVALIDARG; - props.MemSizeMB = v >> 20; - break; - case NCoderPropID::kOrder: - if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER) - return E_INVALIDARG; - props.Order = (Byte)v; - break; - case NCoderPropID::kNumThreads: break; - case NCoderPropID::kLevel: level = (int)v; break; - case NCoderPropID::kAlgorithm: - if (v >= PPMD8_RESTORE_METHOD_UNSUPPPORTED) - return E_INVALIDARG; - props.Restor = (int)v; - break; - default: return E_INVALIDARG; - } - } - props.Normalize(level); - _props = props; - return S_OK; -} - -CEncoder::CEncoder() -{ - _props.Normalize(-1); - _ppmd.Stream.Out = &_outStream.vt; - Ppmd8_Construct(&_ppmd); -} - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) -{ - if (!_inStream.Alloc()) - return E_OUTOFMEMORY; - if (!_outStream.Alloc(1 << 20)) - return E_OUTOFMEMORY; - if (!Ppmd8_Alloc(&_ppmd, _props.MemSizeMB << 20, &g_BigAlloc)) - return E_OUTOFMEMORY; - - _outStream.Stream = outStream; - _outStream.Init(); - - Ppmd8_Init_RangeEnc(&_ppmd) - Ppmd8_Init(&_ppmd, (unsigned)_props.Order, (unsigned)_props.Restor); - - { - const unsigned val = - ((unsigned)_props.Order - 1) - + (((unsigned)_props.MemSizeMB - 1) << 4) - + ((unsigned)_props.Restor << 12); - _outStream.WriteByte((Byte)(val & 0xFF)); - _outStream.WriteByte((Byte)(val >> 8)); - } - RINOK(_outStream.Res) - - UInt64 processed = 0; - for (;;) - { - UInt32 size; - RINOK(inStream->Read(_inStream.Buf, kBufSize, &size)) - if (size == 0) - { - Ppmd8_EncodeSymbol(&_ppmd, -1); - Ppmd8_Flush_RangeEnc(&_ppmd); - return _outStream.Flush(); - } - - processed += size; - const Byte *buf = _inStream.Buf; - const Byte *lim = buf + size; - do - { - Ppmd8_EncodeSymbol(&_ppmd, *buf); - if (_outStream.Res != S_OK) - break; - } - while (++buf != lim); - - RINOK(_outStream.Res) - - if (progress) - { - const UInt64 outProccessed = _outStream.GetProcessed(); - RINOK(progress->SetRatioInfo(&processed, &outProccessed)) - } - } -} - -}} +// PpmdZip.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../Common/RegisterCodec.h" +#include "../Common/StreamUtils.h" + +#include "PpmdZip.h" + +namespace NCompress { +namespace NPpmdZip { + +static const UInt32 kBufSize = 1 << 20; + +bool CBuf::Alloc() +{ + if (!Buf) + Buf = (Byte *)::MidAlloc(kBufSize); + return (Buf != NULL); +} + +CDecoder::CDecoder(bool fullFileMode): + _fullFileMode(fullFileMode) +{ + Ppmd8_Construct(&_ppmd); + _ppmd.Stream.In = &_inStream.vt; +} + +CDecoder::~CDecoder() +{ + Ppmd8_Free(&_ppmd, &g_BigAlloc); +} + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + // try { + + if (!_outStream.Alloc()) + return E_OUTOFMEMORY; + if (!_inStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + + _inStream.Stream = inStream; + _inStream.Init(); + + { + Byte buf[2]; + for (int i = 0; i < 2; i++) + buf[i] = _inStream.ReadByte(); + if (_inStream.Extra) + return S_FALSE; + + const UInt32 val = GetUi16(buf); + const unsigned order = (val & 0xF) + 1; + const UInt32 mem = ((val >> 4) & 0xFF) + 1; + const unsigned restor = (val >> 12); + if (order < 2 || restor > 2) + return S_FALSE; + + #ifndef PPMD8_FREEZE_SUPPORT + if (restor == 2) + return E_NOTIMPL; + #endif + + if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + + if (!Ppmd8_Init_RangeDec(&_ppmd)) + return S_FALSE; + Ppmd8_Init(&_ppmd, order, restor); + } + + bool wasFinished = false; + UInt64 processedSize = 0; + + for (;;) + { + size_t size = kBufSize; + if (outSize) + { + const UInt64 rem = *outSize - processedSize; + if (size > rem) + { + size = (size_t)rem; + if (size == 0) + break; + } + } + + int sym; + Byte *buf = _outStream.Buf; + const Byte *lim = buf + size; + + do + { + sym = Ppmd8_DecodeSymbol(&_ppmd); + if (_inStream.Extra || sym < 0) + break; + *buf++ = (Byte)sym; + } + while (buf != lim); + + const size_t cur = (size_t)(buf - _outStream.Buf); + processedSize += cur; + + RINOK(WriteStream(outStream, _outStream.Buf, cur)) + + RINOK(_inStream.Res) + if (_inStream.Extra) + return S_FALSE; + + if (sym < 0) + { + if (sym != -1) + return S_FALSE; + wasFinished = true; + break; + } + + if (progress) + { + const UInt64 inProccessed = _inStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&inProccessed, &processedSize)) + } + } + + RINOK(_inStream.Res) + + if (_fullFileMode) + { + if (!wasFinished) + { + const int res = Ppmd8_DecodeSymbol(&_ppmd); + RINOK(_inStream.Res) + if (_inStream.Extra || res != -1) + return S_FALSE; + } + if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd)) + return S_FALSE; + + if (inSize && *inSize != _inStream.GetProcessed()) + return S_FALSE; + } + + return S_OK; + + // } catch (...) { return E_FAIL; } +} + + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + _fullFileMode = (finishMode != 0); + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inStream.GetProcessed(); + return S_OK; +} + + + +// ---------- Encoder ---------- + +void CEncProps::Normalize(int level) +{ + if (level < 0) level = 5; + if (level == 0) level = 1; + if (level > 9) level = 9; + if (MemSizeMB == (UInt32)(Int32)-1) + MemSizeMB = 1 << (level - 1); + const unsigned kMult = 16; + for (UInt32 m = 1; m < MemSizeMB; m <<= 1) + if (ReduceSize <= (m << 20) / kMult) + { + MemSizeMB = m; + break; + } + if (Order == -1) Order = 3 + level; + if (Restor == -1) + Restor = level < 7 ? + PPMD8_RESTORE_METHOD_RESTART : + PPMD8_RESTORE_METHOD_CUT_OFF; +} + +CEncoder::~CEncoder() +{ + Ppmd8_Free(&_ppmd, &g_BigAlloc); +} + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + int level = -1; + CEncProps props; + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + const PROPID propID = propIDs[i]; + if (propID > NCoderPropID::kReduceSize) + continue; + if (propID == NCoderPropID::kReduceSize) + { + props.ReduceSize = (UInt32)(Int32)-1; + if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1) + props.ReduceSize = (UInt32)prop.uhVal.QuadPart; + continue; + } + if (prop.vt != VT_UI4) + return E_INVALIDARG; + const UInt32 v = (UInt32)prop.ulVal; + switch (propID) + { + case NCoderPropID::kUsedMemorySize: + if (v < (1 << 20) || v > (1 << 28)) + return E_INVALIDARG; + props.MemSizeMB = v >> 20; + break; + case NCoderPropID::kOrder: + if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER) + return E_INVALIDARG; + props.Order = (Byte)v; + break; + case NCoderPropID::kNumThreads: break; + case NCoderPropID::kLevel: level = (int)v; break; + case NCoderPropID::kAlgorithm: + if (v >= PPMD8_RESTORE_METHOD_UNSUPPPORTED) + return E_INVALIDARG; + props.Restor = (int)v; + break; + default: return E_INVALIDARG; + } + } + props.Normalize(level); + _props = props; + return S_OK; +} + +CEncoder::CEncoder() +{ + _props.Normalize(-1); + _ppmd.Stream.Out = &_outStream.vt; + Ppmd8_Construct(&_ppmd); +} + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) +{ + if (!_inStream.Alloc()) + return E_OUTOFMEMORY; + if (!_outStream.Alloc(1 << 20)) + return E_OUTOFMEMORY; + if (!Ppmd8_Alloc(&_ppmd, _props.MemSizeMB << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + + _outStream.Stream = outStream; + _outStream.Init(); + + Ppmd8_Init_RangeEnc(&_ppmd) + Ppmd8_Init(&_ppmd, (unsigned)_props.Order, (unsigned)_props.Restor); + + { + const unsigned val = + ((unsigned)_props.Order - 1) + + (((unsigned)_props.MemSizeMB - 1) << 4) + + ((unsigned)_props.Restor << 12); + _outStream.WriteByte((Byte)(val & 0xFF)); + _outStream.WriteByte((Byte)(val >> 8)); + } + RINOK(_outStream.Res) + + UInt64 processed = 0; + for (;;) + { + UInt32 size; + RINOK(inStream->Read(_inStream.Buf, kBufSize, &size)) + if (size == 0) + { + Ppmd8_EncodeSymbol(&_ppmd, -1); + Ppmd8_Flush_RangeEnc(&_ppmd); + return _outStream.Flush(); + } + + processed += size; + const Byte *buf = _inStream.Buf; + const Byte *lim = buf + size; + do + { + Ppmd8_EncodeSymbol(&_ppmd, *buf); + if (_outStream.Res != S_OK) + break; + } + while (++buf != lim); + + RINOK(_outStream.Res) + + if (progress) + { + const UInt64 outProccessed = _outStream.GetProcessed(); + RINOK(progress->SetRatioInfo(&processed, &outProccessed)) + } + } +} + +}} diff --git a/CPP/7zip/Compress/PpmdZip.h b/CPP/7zip/Compress/PpmdZip.h index d8f1540ca..6cc6af12f 100644 --- a/CPP/7zip/Compress/PpmdZip.h +++ b/CPP/7zip/Compress/PpmdZip.h @@ -1,78 +1,78 @@ -// PpmdZip.h - -#ifndef ZIP7_INC_COMPRESS_PPMD_ZIP_H -#define ZIP7_INC_COMPRESS_PPMD_ZIP_H - -#include "../../../C/Alloc.h" -#include "../../../C/Ppmd8.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/CWrappers.h" - -namespace NCompress { -namespace NPpmdZip { - -struct CBuf -{ - Byte *Buf; - - CBuf(): Buf(NULL) {} - ~CBuf() { ::MidFree(Buf); } - bool Alloc(); -}; - - -Z7_CLASS_IMP_NOQIB_3( - CDecoder - , ICompressCoder - , ICompressSetFinishMode - , ICompressGetInStreamProcessedSize -) - bool _fullFileMode; - CByteInBufWrap _inStream; - CBuf _outStream; - CPpmd8 _ppmd; -public: - CDecoder(bool fullFileMode = true); - ~CDecoder(); -}; - - -struct CEncProps -{ - UInt32 MemSizeMB; - UInt32 ReduceSize; - int Order; - int Restor; - - CEncProps() - { - MemSizeMB = (UInt32)(Int32)-1; - ReduceSize = (UInt32)(Int32)-1; - Order = -1; - Restor = -1; - } - void Normalize(int level); -}; - - -Z7_CLASS_IMP_NOQIB_2( - CEncoder - , ICompressCoder - , ICompressSetCoderProperties -) - CByteOutBufWrap _outStream; - CBuf _inStream; - CPpmd8 _ppmd; - CEncProps _props; -public: - CEncoder(); - ~CEncoder(); -}; - -}} - -#endif +// PpmdZip.h + +#ifndef ZIP7_INC_COMPRESS_PPMD_ZIP_H +#define ZIP7_INC_COMPRESS_PPMD_ZIP_H + +#include "../../../C/Alloc.h" +#include "../../../C/Ppmd8.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/CWrappers.h" + +namespace NCompress { +namespace NPpmdZip { + +struct CBuf +{ + Byte *Buf; + + CBuf(): Buf(NULL) {} + ~CBuf() { ::MidFree(Buf); } + bool Alloc(); +}; + + +Z7_CLASS_IMP_NOQIB_3( + CDecoder + , ICompressCoder + , ICompressSetFinishMode + , ICompressGetInStreamProcessedSize +) + bool _fullFileMode; + CByteInBufWrap _inStream; + CBuf _outStream; + CPpmd8 _ppmd; +public: + CDecoder(bool fullFileMode = true); + ~CDecoder(); +}; + + +struct CEncProps +{ + UInt32 MemSizeMB; + UInt32 ReduceSize; + int Order; + int Restor; + + CEncProps() + { + MemSizeMB = (UInt32)(Int32)-1; + ReduceSize = (UInt32)(Int32)-1; + Order = -1; + Restor = -1; + } + void Normalize(int level); +}; + + +Z7_CLASS_IMP_NOQIB_2( + CEncoder + , ICompressCoder + , ICompressSetCoderProperties +) + CByteOutBufWrap _outStream; + CBuf _inStream; + CPpmd8 _ppmd; + CEncProps _props; +public: + CEncoder(); + ~CEncoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/QuantumDecoder.cpp b/CPP/7zip/Compress/QuantumDecoder.cpp index 1812a9492..98817a402 100644 --- a/CPP/7zip/Compress/QuantumDecoder.cpp +++ b/CPP/7zip/Compress/QuantumDecoder.cpp @@ -1,355 +1,355 @@ -// QuantumDecoder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/Alloc.h" -#include "../../../C/CpuArch.h" - -#include "../../Common/Defs.h" - -#include "QuantumDecoder.h" - -namespace NCompress { -namespace NQuantum { - -static const unsigned kNumLenSymbols = 27; -static const unsigned kMatchMinLen = 3; -static const unsigned kNumSimpleLenSlots = 6; - -static const unsigned kUpdateStep = 8; -static const unsigned kFreqSumMax = 3800; -static const unsigned kReorderCount_Start = 4; -static const unsigned kReorderCount = 50; - - -class CRangeDecoder -{ - UInt32 Low; - UInt32 Range; - UInt32 Code; - - unsigned _bitOffset; - const Byte *_buf; - const Byte *_bufLim; - -public: - - Z7_FORCE_INLINE - void Init(const Byte *inData, size_t inSize) - { - Code = ((UInt32)*inData << 8) | inData[1]; - _buf = inData + 2; - _bufLim = inData + inSize; - _bitOffset = 0; - Low = 0; - Range = 0x10000; - } - - Z7_FORCE_INLINE - bool WasExtraRead() const - { - return _buf > _bufLim; - } - - Z7_FORCE_INLINE - UInt32 ReadBits(unsigned numBits) // numBits > 0 - { - unsigned bitOffset = _bitOffset; - const Byte *buf = _buf; - const UInt32 res = GetBe32(buf) << bitOffset; - bitOffset += numBits; - _buf = buf + (bitOffset >> 3); - _bitOffset = bitOffset & 7; - return res >> (32 - numBits); - } - - // ---------- Range Decoder functions ---------- - - Z7_FORCE_INLINE - bool Finish() - { - const unsigned numBits = 2 + ((16 - 2 - _bitOffset) & 7); - if (ReadBits(numBits) != 0) - return false; - return _buf == _bufLim; - } - - Z7_FORCE_INLINE - UInt32 GetThreshold(UInt32 total) const - { - return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required; - } - - Z7_FORCE_INLINE - void Decode(UInt32 start, UInt32 end, UInt32 total) - { - // UInt32 hi = ~(Low + end * Range / total - 1); - UInt32 hi = 0 - (Low + end * Range / total); - const UInt32 offset = start * Range / total; - UInt32 lo = Low + offset; - Code -= offset; - UInt32 numBits = 0; - lo ^= hi; - while (lo & (1u << 15)) - { - lo <<= 1; - hi <<= 1; - numBits++; - } - lo ^= hi; - UInt32 an = lo & hi; - while (an & (1u << 14)) - { - an <<= 1; - lo <<= 1; - hi <<= 1; - numBits++; - } - Low = lo; - Range = ((~hi - lo) & 0xffff) + 1; - if (numBits) - Code = (Code << numBits) + ReadBits(numBits); - } -}; - - -// Z7_FORCE_INLINE -Z7_NO_INLINE -unsigned CModelDecoder::Decode(CRangeDecoder *rc) -// Z7_NO_INLINE void CModelDecoder::Normalize() -{ - if (Freqs[0] > kFreqSumMax) - { - if (--ReorderCount == 0) - { - ReorderCount = kReorderCount; - { - unsigned i = NumItems; - unsigned next = 0; - UInt16 *freqs = &Freqs[i]; - do - { - const unsigned freq = *--freqs; - *freqs = (UInt16)((freq - next + 1) >> 1); - next = freq; - } - while (--i); - } - { - for (unsigned i = 0; i < NumItems - 1; i++) - { - UInt16 freq = Freqs[i]; - for (unsigned k = i + 1; k < NumItems; k++) - if (freq < Freqs[k]) - { - const UInt16 freq2 = Freqs[k]; - Freqs[k] = freq; - Freqs[i] = freq2; - freq = freq2; - const Byte val = Vals[i]; - Vals[i] = Vals[k]; - Vals[k] = val; - } - } - } - unsigned i = NumItems; - unsigned freq = 0; - UInt16 *freqs = &Freqs[i]; - do - { - freq += *--freqs; - *freqs = (UInt16)freq; - } - while (--i); - } - else - { - unsigned i = NumItems; - unsigned next = 1; - UInt16 *freqs = &Freqs[i]; - do - { - unsigned freq = *--freqs >> 1; - if (freq < next) - freq = next; - *freqs = (UInt16)freq; - next = freq + 1; - } - while (--i); - } - } - unsigned res; - { - const unsigned freq0 = Freqs[0]; - Freqs[0] = (UInt16)(freq0 + kUpdateStep); - const unsigned threshold = rc->GetThreshold(freq0); - UInt16 *freqs = &Freqs[1]; - unsigned freq = *freqs; - while (freq > threshold) - { - *freqs++ = (UInt16)(freq + kUpdateStep); - freq = *freqs; - } - res = Vals[freqs - Freqs - 1]; - rc->Decode(freq, freqs[-1] - kUpdateStep, freq0); - } - return res; -} - - -Z7_NO_INLINE -void CModelDecoder::Init(unsigned numItems, unsigned startVal) -{ - NumItems = numItems; - ReorderCount = kReorderCount_Start; - UInt16 *freqs = Freqs; - freqs[numItems] = 0; - Byte *vals = Vals; - do - { - *freqs++ = (UInt16)numItems; - *vals++ = (Byte)startVal; - startVal++; - } - while (--numItems); -} - - -HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize, bool keepHistory) -{ - if (inSize < 2) - return S_FALSE; - if (!keepHistory) - { - _winPos = 0; - m_Selector.Init(kNumSelectors, 0); - unsigned i; - for (i = 0; i < kNumLitSelectors; i++) - m_Literals[i].Init(kNumLitSymbols, i * kNumLitSymbols); - const unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1)); - // const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 }; - for (i = 0; i < kNumMatchSelectors; i++) - { - const unsigned num = 24 + i * 6 + ((i + 1) & 2) * 3; - m_PosSlot[i].Init(MyMin(numItems, num), 0); - } - m_LenSlot.Init(kNumLenSymbols, kMatchMinLen + kNumMatchSelectors - 1); - } - - CRangeDecoder rc; - rc.Init(inData, inSize); - const UInt32 winSize = _winSize; - Byte *pos; - { - UInt32 winPos = _winPos; - if (winPos == winSize) - { - winPos = 0; - _winPos = winPos; - _overWin = true; - } - if (outSize > winSize - winPos) - return S_FALSE; - pos = _win + winPos; - } - - while (outSize != 0) - { - if (rc.WasExtraRead()) - return S_FALSE; - - const unsigned selector = m_Selector.Decode(&rc); - - if (selector < kNumLitSelectors) - { - const unsigned b = m_Literals[selector].Decode(&rc); - *pos++ = (Byte)b; - --outSize; - // if (--outSize == 0) break; - } - else - { - unsigned len = selector - kNumLitSelectors + kMatchMinLen; - - if (selector == kNumLitSelectors + kNumMatchSelectors - 1) - { - len = m_LenSlot.Decode(&rc); - if (len >= kNumSimpleLenSlots + kMatchMinLen + kNumMatchSelectors - 1) - { - len -= kNumSimpleLenSlots - 4 + kMatchMinLen + kNumMatchSelectors - 1; - const unsigned numDirectBits = (unsigned)(len >> 2); - len = ((4 | (len & 3)) << numDirectBits) - (4 << 1) - + kNumSimpleLenSlots - + kMatchMinLen + kNumMatchSelectors - 1; - if (numDirectBits < 6) - len += rc.ReadBits(numDirectBits); - } - } - - UInt32 dist = m_PosSlot[(size_t)selector - kNumLitSelectors].Decode(&rc); - - if (dist >= 4) - { - const unsigned numDirectBits = (unsigned)((dist >> 1) - 1); - dist = ((2 | (dist & 1)) << numDirectBits) + rc.ReadBits(numDirectBits); - } - - if ((Int32)(outSize -= len) < 0) - return S_FALSE; - - ptrdiff_t srcPos = (ptrdiff_t)(Int32)((pos - _win) - (ptrdiff_t)dist - 1); - if (srcPos < 0) - { - if (!_overWin) - return S_FALSE; - UInt32 rem = (UInt32)-srcPos; - srcPos += winSize; - if (rem < len) - { - const Byte *src = _win + srcPos; - len -= rem; - do - *pos++ = *src++; - while (--rem); - srcPos = 0; - } - } - const Byte *src = _win + srcPos; - do - *pos++ = *src++; - while (--len); - // if (outSize == 0) break; - } - } - - _winPos = (UInt32)(size_t)(pos - _win); - return rc.Finish() ? S_OK : S_FALSE; -} - - -HRESULT CDecoder::SetParams(unsigned numDictBits) -{ - if (numDictBits > 21) - return E_INVALIDARG; - _numDictBits = numDictBits; - _winPos = 0; - _overWin = false; - - if (numDictBits < 15) - numDictBits = 15; - _winSize = (UInt32)1 << numDictBits; - if (!_win || _winSize > _winSize_allocated) - { - MidFree(_win); - _win = NULL; - _win = (Byte *)MidAlloc(_winSize); - if (!_win) - return E_OUTOFMEMORY; - _winSize_allocated = _winSize; - } - return S_OK; -} - -}} +// QuantumDecoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/Alloc.h" +#include "../../../C/CpuArch.h" + +#include "../../Common/Defs.h" + +#include "QuantumDecoder.h" + +namespace NCompress { +namespace NQuantum { + +static const unsigned kNumLenSymbols = 27; +static const unsigned kMatchMinLen = 3; +static const unsigned kNumSimpleLenSlots = 6; + +static const unsigned kUpdateStep = 8; +static const unsigned kFreqSumMax = 3800; +static const unsigned kReorderCount_Start = 4; +static const unsigned kReorderCount = 50; + + +class CRangeDecoder +{ + UInt32 Low; + UInt32 Range; + UInt32 Code; + + unsigned _bitOffset; + const Byte *_buf; + const Byte *_bufLim; + +public: + + Z7_FORCE_INLINE + void Init(const Byte *inData, size_t inSize) + { + Code = ((UInt32)*inData << 8) | inData[1]; + _buf = inData + 2; + _bufLim = inData + inSize; + _bitOffset = 0; + Low = 0; + Range = 0x10000; + } + + Z7_FORCE_INLINE + bool WasExtraRead() const + { + return _buf > _bufLim; + } + + Z7_FORCE_INLINE + UInt32 ReadBits(unsigned numBits) // numBits > 0 + { + unsigned bitOffset = _bitOffset; + const Byte *buf = _buf; + const UInt32 res = GetBe32(buf) << bitOffset; + bitOffset += numBits; + _buf = buf + (bitOffset >> 3); + _bitOffset = bitOffset & 7; + return res >> (32 - numBits); + } + + // ---------- Range Decoder functions ---------- + + Z7_FORCE_INLINE + bool Finish() + { + const unsigned numBits = 2 + ((16 - 2 - _bitOffset) & 7); + if (ReadBits(numBits) != 0) + return false; + return _buf == _bufLim; + } + + Z7_FORCE_INLINE + UInt32 GetThreshold(UInt32 total) const + { + return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required; + } + + Z7_FORCE_INLINE + void Decode(UInt32 start, UInt32 end, UInt32 total) + { + // UInt32 hi = ~(Low + end * Range / total - 1); + UInt32 hi = 0 - (Low + end * Range / total); + const UInt32 offset = start * Range / total; + UInt32 lo = Low + offset; + Code -= offset; + UInt32 numBits = 0; + lo ^= hi; + while (lo & (1u << 15)) + { + lo <<= 1; + hi <<= 1; + numBits++; + } + lo ^= hi; + UInt32 an = lo & hi; + while (an & (1u << 14)) + { + an <<= 1; + lo <<= 1; + hi <<= 1; + numBits++; + } + Low = lo; + Range = ((~hi - lo) & 0xffff) + 1; + if (numBits) + Code = (Code << numBits) + ReadBits(numBits); + } +}; + + +// Z7_FORCE_INLINE +Z7_NO_INLINE +unsigned CModelDecoder::Decode(CRangeDecoder *rc) +// Z7_NO_INLINE void CModelDecoder::Normalize() +{ + if (Freqs[0] > kFreqSumMax) + { + if (--ReorderCount == 0) + { + ReorderCount = kReorderCount; + { + unsigned i = NumItems; + unsigned next = 0; + UInt16 *freqs = &Freqs[i]; + do + { + const unsigned freq = *--freqs; + *freqs = (UInt16)((freq - next + 1) >> 1); + next = freq; + } + while (--i); + } + { + for (unsigned i = 0; i < NumItems - 1; i++) + { + UInt16 freq = Freqs[i]; + for (unsigned k = i + 1; k < NumItems; k++) + if (freq < Freqs[k]) + { + const UInt16 freq2 = Freqs[k]; + Freqs[k] = freq; + Freqs[i] = freq2; + freq = freq2; + const Byte val = Vals[i]; + Vals[i] = Vals[k]; + Vals[k] = val; + } + } + } + unsigned i = NumItems; + unsigned freq = 0; + UInt16 *freqs = &Freqs[i]; + do + { + freq += *--freqs; + *freqs = (UInt16)freq; + } + while (--i); + } + else + { + unsigned i = NumItems; + unsigned next = 1; + UInt16 *freqs = &Freqs[i]; + do + { + unsigned freq = *--freqs >> 1; + if (freq < next) + freq = next; + *freqs = (UInt16)freq; + next = freq + 1; + } + while (--i); + } + } + unsigned res; + { + const unsigned freq0 = Freqs[0]; + Freqs[0] = (UInt16)(freq0 + kUpdateStep); + const unsigned threshold = rc->GetThreshold(freq0); + UInt16 *freqs = &Freqs[1]; + unsigned freq = *freqs; + while (freq > threshold) + { + *freqs++ = (UInt16)(freq + kUpdateStep); + freq = *freqs; + } + res = Vals[freqs - Freqs - 1]; + rc->Decode(freq, freqs[-1] - kUpdateStep, freq0); + } + return res; +} + + +Z7_NO_INLINE +void CModelDecoder::Init(unsigned numItems, unsigned startVal) +{ + NumItems = numItems; + ReorderCount = kReorderCount_Start; + UInt16 *freqs = Freqs; + freqs[numItems] = 0; + Byte *vals = Vals; + do + { + *freqs++ = (UInt16)numItems; + *vals++ = (Byte)startVal; + startVal++; + } + while (--numItems); +} + + +HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize, bool keepHistory) +{ + if (inSize < 2) + return S_FALSE; + if (!keepHistory) + { + _winPos = 0; + m_Selector.Init(kNumSelectors, 0); + unsigned i; + for (i = 0; i < kNumLitSelectors; i++) + m_Literals[i].Init(kNumLitSymbols, i * kNumLitSymbols); + const unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1)); + // const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 }; + for (i = 0; i < kNumMatchSelectors; i++) + { + const unsigned num = 24 + i * 6 + ((i + 1) & 2) * 3; + m_PosSlot[i].Init(MyMin(numItems, num), 0); + } + m_LenSlot.Init(kNumLenSymbols, kMatchMinLen + kNumMatchSelectors - 1); + } + + CRangeDecoder rc; + rc.Init(inData, inSize); + const UInt32 winSize = _winSize; + Byte *pos; + { + UInt32 winPos = _winPos; + if (winPos == winSize) + { + winPos = 0; + _winPos = winPos; + _overWin = true; + } + if (outSize > winSize - winPos) + return S_FALSE; + pos = _win + winPos; + } + + while (outSize != 0) + { + if (rc.WasExtraRead()) + return S_FALSE; + + const unsigned selector = m_Selector.Decode(&rc); + + if (selector < kNumLitSelectors) + { + const unsigned b = m_Literals[selector].Decode(&rc); + *pos++ = (Byte)b; + --outSize; + // if (--outSize == 0) break; + } + else + { + unsigned len = selector - kNumLitSelectors + kMatchMinLen; + + if (selector == kNumLitSelectors + kNumMatchSelectors - 1) + { + len = m_LenSlot.Decode(&rc); + if (len >= kNumSimpleLenSlots + kMatchMinLen + kNumMatchSelectors - 1) + { + len -= kNumSimpleLenSlots - 4 + kMatchMinLen + kNumMatchSelectors - 1; + const unsigned numDirectBits = (unsigned)(len >> 2); + len = ((4 | (len & 3)) << numDirectBits) - (4 << 1) + + kNumSimpleLenSlots + + kMatchMinLen + kNumMatchSelectors - 1; + if (numDirectBits < 6) + len += rc.ReadBits(numDirectBits); + } + } + + UInt32 dist = m_PosSlot[(size_t)selector - kNumLitSelectors].Decode(&rc); + + if (dist >= 4) + { + const unsigned numDirectBits = (unsigned)((dist >> 1) - 1); + dist = ((2 | (dist & 1)) << numDirectBits) + rc.ReadBits(numDirectBits); + } + + if ((Int32)(outSize -= len) < 0) + return S_FALSE; + + ptrdiff_t srcPos = (ptrdiff_t)(Int32)((pos - _win) - (ptrdiff_t)dist - 1); + if (srcPos < 0) + { + if (!_overWin) + return S_FALSE; + UInt32 rem = (UInt32)-srcPos; + srcPos += winSize; + if (rem < len) + { + const Byte *src = _win + srcPos; + len -= rem; + do + *pos++ = *src++; + while (--rem); + srcPos = 0; + } + } + const Byte *src = _win + srcPos; + do + *pos++ = *src++; + while (--len); + // if (outSize == 0) break; + } + } + + _winPos = (UInt32)(size_t)(pos - _win); + return rc.Finish() ? S_OK : S_FALSE; +} + + +HRESULT CDecoder::SetParams(unsigned numDictBits) +{ + if (numDictBits > 21) + return E_INVALIDARG; + _numDictBits = numDictBits; + _winPos = 0; + _overWin = false; + + if (numDictBits < 15) + numDictBits = 15; + _winSize = (UInt32)1 << numDictBits; + if (!_win || _winSize > _winSize_allocated) + { + MidFree(_win); + _win = NULL; + _win = (Byte *)MidAlloc(_winSize); + if (!_win) + return E_OUTOFMEMORY; + _winSize_allocated = _winSize; + } + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/QuantumDecoder.h b/CPP/7zip/Compress/QuantumDecoder.h index e2215a15c..fd5baea70 100644 --- a/CPP/7zip/Compress/QuantumDecoder.h +++ b/CPP/7zip/Compress/QuantumDecoder.h @@ -1,60 +1,60 @@ -// QuantumDecoder.h - -#ifndef ZIP7_INC_COMPRESS_QUANTUM_DECODER_H -#define ZIP7_INC_COMPRESS_QUANTUM_DECODER_H - -#include "../../Common/MyTypes.h" - -namespace NCompress { -namespace NQuantum { - -const unsigned kNumLitSelectorBits = 2; -const unsigned kNumLitSelectors = 1 << kNumLitSelectorBits; -const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits); -const unsigned kNumMatchSelectors = 3; -const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors; -const unsigned kNumSymbolsMax = kNumLitSymbols; // 64 - -class CRangeDecoder; - -class CModelDecoder -{ - unsigned NumItems; - unsigned ReorderCount; - Byte Vals[kNumSymbolsMax]; - UInt16 Freqs[kNumSymbolsMax + 1]; -public: - Byte _pad[64 - 10]; // for structure size alignment - - void Init(unsigned numItems, unsigned startVal); - unsigned Decode(CRangeDecoder *rc); -}; - - -class CDecoder -{ - UInt32 _winSize; - UInt32 _winPos; - UInt32 _winSize_allocated; - bool _overWin; - Byte *_win; - unsigned _numDictBits; - - CModelDecoder m_Selector; - CModelDecoder m_Literals[kNumLitSelectors]; - CModelDecoder m_PosSlot[kNumMatchSelectors]; - CModelDecoder m_LenSlot; - - void Init(); - HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize); -public: - HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize, bool keepHistory); - HRESULT SetParams(unsigned numDictBits); - - CDecoder(): _win(NULL), _numDictBits(0) {} - const Byte * GetDataPtr() const { return _win + _winPos; } -}; - -}} - -#endif +// QuantumDecoder.h + +#ifndef ZIP7_INC_COMPRESS_QUANTUM_DECODER_H +#define ZIP7_INC_COMPRESS_QUANTUM_DECODER_H + +#include "../../Common/MyTypes.h" + +namespace NCompress { +namespace NQuantum { + +const unsigned kNumLitSelectorBits = 2; +const unsigned kNumLitSelectors = 1 << kNumLitSelectorBits; +const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits); +const unsigned kNumMatchSelectors = 3; +const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors; +const unsigned kNumSymbolsMax = kNumLitSymbols; // 64 + +class CRangeDecoder; + +class CModelDecoder +{ + unsigned NumItems; + unsigned ReorderCount; + Byte Vals[kNumSymbolsMax]; + UInt16 Freqs[kNumSymbolsMax + 1]; +public: + Byte _pad[64 - 10]; // for structure size alignment + + void Init(unsigned numItems, unsigned startVal); + unsigned Decode(CRangeDecoder *rc); +}; + + +class CDecoder +{ + UInt32 _winSize; + UInt32 _winPos; + UInt32 _winSize_allocated; + bool _overWin; + Byte *_win; + unsigned _numDictBits; + + CModelDecoder m_Selector; + CModelDecoder m_Literals[kNumLitSelectors]; + CModelDecoder m_PosSlot[kNumMatchSelectors]; + CModelDecoder m_LenSlot; + + void Init(); + HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize); +public: + HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize, bool keepHistory); + HRESULT SetParams(unsigned numDictBits); + + CDecoder(): _win(NULL), _numDictBits(0) {} + const Byte * GetDataPtr() const { return _win + _winPos; } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar1Decoder.cpp index d33578fd1..050cde21c 100644 --- a/CPP/7zip/Compress/Rar1Decoder.cpp +++ b/CPP/7zip/Compress/Rar1Decoder.cpp @@ -1,518 +1,518 @@ -// Rar1Decoder.cpp -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#include "StdAfx.h" - -#include "Rar1Decoder.h" - -namespace NCompress { -namespace NRar1 { - -static const unsigned kNumBits = 12; - -static const Byte kShortLen1[16 * 3] = -{ - 0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, - 1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0, - 1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0 -}; - -static const Byte kShortLen2[16 * 3] = -{ - 0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, - 2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0, - 2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0 -}; - -static const Byte PosL1[kNumBits + 1] = { 0,0,2,1,2,2,4,5,4,4,8,0,224 }; -static const Byte PosL2[kNumBits + 1] = { 0,0,0,5,2,2,4,5,4,4,8,2,220 }; - -static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 }; -static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 }; -static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 }; -static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 }; -static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 }; - -static const UInt32 kHistorySize = (1 << 16); - -CDecoder::CDecoder(): - _isSolid(false), - _solidAllowed(false) - {} - -UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } - -HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len) -{ - if (len == 0) - return S_FALSE; - if (m_UnpackSize < len) - return S_FALSE; - m_UnpackSize -= len; - return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE; -} - - -UInt32 CDecoder::DecodeNum(const Byte *numTab) -{ - /* - { - // we can check that tables are correct - UInt32 sum = 0; - for (unsigned i = 0; i <= kNumBits; i++) - sum += ((UInt32)numTab[i] << (kNumBits - i)); - if (sum != (1 << kNumBits)) - throw 111; - } - */ - - UInt32 val = m_InBitStream.GetValue(kNumBits); - UInt32 sum = 0; - unsigned i = 2; - - for (;;) - { - const UInt32 num = numTab[i]; - const UInt32 cur = num << (kNumBits - i); - if (val < cur) - break; - i++; - val -= cur; - sum += num; - } - m_InBitStream.MovePos(i); - return ((val >> (kNumBits - i)) + sum); -} - - -HRESULT CDecoder::ShortLZ() -{ - NumHuf = 0; - - if (LCount == 2) - { - if (ReadBits(1)) - return CopyBlock(LastDist, LastLength); - LCount = 0; - } - - UInt32 bitField = m_InBitStream.GetValue(8); - - UInt32 len, dist; - { - const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2; - const Byte *lens = xors + 16 + Buf60; - for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++); - m_InBitStream.MovePos(lens[len]); - } - - if (len >= 9) - { - if (len == 9) - { - LCount++; - return CopyBlock(LastDist, LastLength); - } - - LCount = 0; - - if (len == 14) - { - len = DecodeNum(PosL2) + 5; - dist = 0x8000 + ReadBits(15) - 1; - LastLength = len; - LastDist = dist; - return CopyBlock(dist, len); - } - - const UInt32 saveLen = len; - dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3]; - - len = DecodeNum(PosL1); - - if (len == 0xff && saveLen == 10) - { - Buf60 ^= 16; - return S_OK; - } - if (dist >= 256) - { - len++; - if (dist >= MaxDist3 - 1) - len++; - } - } - else - { - LCount = 0; - AvrLn1 += len; - AvrLn1 -= AvrLn1 >> 4; - - unsigned distancePlace = DecodeNum(PosHf2) & 0xff; - - dist = ChSetA[distancePlace]; - - if (distancePlace != 0) - { - PlaceA[dist]--; - UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1]; - PlaceA[lastDistance]++; - ChSetA[distancePlace] = lastDistance; - ChSetA[(size_t)distancePlace - 1] = dist; - } - } - - m_RepDists[m_RepDistPtr++] = dist; - m_RepDistPtr &= 3; - len += 2; - LastLength = len; - LastDist = dist; - return CopyBlock(dist, len); -} - - -HRESULT CDecoder::LongLZ() -{ - UInt32 len; - UInt32 dist; - UInt32 distancePlace, newDistancePlace; - UInt32 oldAvr2, oldAvr3; - - NumHuf = 0; - Nlzb += 16; - if (Nlzb > 0xff) - { - Nlzb = 0x90; - Nhfb >>= 1; - } - oldAvr2 = AvrLn2; - - if (AvrLn2 >= 64) - len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2); - else - { - UInt32 bitField = m_InBitStream.GetValue(16); - if (bitField < 0x100) - { - len = bitField; - m_InBitStream.MovePos(16); - } - else - { - for (len = 0; ((bitField << len) & 0x8000) == 0; len++); - - m_InBitStream.MovePos(len + 1); - } - } - - AvrLn2 += len; - AvrLn2 -= AvrLn2 >> 5; - - { - const Byte *tab; - if (AvrPlcB >= 0x2900) tab = PosHf2; - else if (AvrPlcB >= 0x0700) tab = PosHf1; - else tab = PosHf0; - distancePlace = DecodeNum(tab); // [0, 256] - } - - AvrPlcB += distancePlace; - AvrPlcB -= AvrPlcB >> 8; - - distancePlace &= 0xff; - - for (;;) - { - dist = ChSetB[distancePlace]; - newDistancePlace = NToPlB[dist++ & 0xff]++; - if (dist & 0xff) - break; - CorrHuff(ChSetB,NToPlB); - } - - ChSetB[distancePlace] = ChSetB[newDistancePlace]; - ChSetB[newDistancePlace] = dist; - - dist = ((dist & 0xff00) >> 1) | ReadBits(7); - - oldAvr3 = AvrLn3; - - if (len != 1 && len != 4) - { - if (len == 0 && dist <= MaxDist3) - { - AvrLn3++; - AvrLn3 -= AvrLn3 >> 8; - } - else if (AvrLn3 > 0) - AvrLn3--; - } - - len += 3; - - if (dist >= MaxDist3) - len++; - if (dist <= 256) - len += 8; - - if (oldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && oldAvr2 < 0x40)) - MaxDist3 = 0x7f00; - else - MaxDist3 = 0x2001; - - m_RepDists[m_RepDistPtr++] = --dist; - m_RepDistPtr &= 3; - LastLength = len; - LastDist = dist; - - return CopyBlock(dist, len); -} - - -HRESULT CDecoder::HuffDecode() -{ - UInt32 curByte, newBytePlace; - UInt32 len; - UInt32 dist; - unsigned bytePlace; - { - const Byte *tab; - - if (AvrPlc >= 0x7600) tab = PosHf4; - else if (AvrPlc >= 0x5e00) tab = PosHf3; - else if (AvrPlc >= 0x3600) tab = PosHf2; - else if (AvrPlc >= 0x0e00) tab = PosHf1; - else tab = PosHf0; - - bytePlace = DecodeNum(tab); // [0, 256] - } - - if (StMode) - { - if (bytePlace == 0) - { - if (ReadBits(1)) - { - NumHuf = 0; - StMode = false; - return S_OK; - } - len = ReadBits(1) + 3; - dist = DecodeNum(PosHf2); - dist = (dist << 5) | ReadBits(5); - if (dist == 0) - return S_FALSE; - return CopyBlock(dist - 1, len); - } - bytePlace--; // bytePlace is [0, 255] - } - else if (NumHuf++ >= 16 && FlagsCnt == 0) - StMode = true; - - bytePlace &= 0xff; - AvrPlc += bytePlace; - AvrPlc -= AvrPlc >> 8; - Nhfb += 16; - - if (Nhfb > 0xff) - { - Nhfb = 0x90; - Nlzb >>= 1; - } - - m_UnpackSize--; - m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8)); - - for (;;) - { - curByte = ChSet[bytePlace]; - newBytePlace = NToPl[curByte++ & 0xff]++; - if ((curByte & 0xff) <= 0xa1) - break; - CorrHuff(ChSet, NToPl); - } - - ChSet[bytePlace] = ChSet[newBytePlace]; - ChSet[newBytePlace] = curByte; - return S_OK; -} - - -void CDecoder::GetFlagsBuf() -{ - UInt32 flags, newFlagsPlace; - const UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256] - - if (flagsPlace >= Z7_ARRAY_SIZE(ChSetC)) - return; - - for (;;) - { - flags = ChSetC[flagsPlace]; - FlagBuf = flags >> 8; - newFlagsPlace = NToPlC[flags++ & 0xff]++; - if ((flags & 0xff) != 0) - break; - CorrHuff(ChSetC, NToPlC); - } - - ChSetC[flagsPlace] = ChSetC[newFlagsPlace]; - ChSetC[newFlagsPlace] = flags; -} - - -void CDecoder::CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace) -{ - int i; - for (i = 7; i >= 0; i--) - for (unsigned j = 0; j < 32; j++, CharSet++) - *CharSet = (*CharSet & ~(UInt32)0xff) | (unsigned)i; - memset(NumToPlace, 0, sizeof(NToPl)); - for (i = 6; i >= 0; i--) - NumToPlace[i] = (7 - (unsigned)i) * 32; -} - - - -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */) -{ - if (!inSize || !outSize) - return E_INVALIDARG; - - if (_isSolid && !_solidAllowed) - return S_FALSE; - - _solidAllowed = false; - - if (!m_OutWindowStream.Create(kHistorySize)) - return E_OUTOFMEMORY; - if (!m_InBitStream.Create(1 << 20)) - return E_OUTOFMEMORY; - - m_UnpackSize = *outSize; - - m_OutWindowStream.SetStream(outStream); - m_OutWindowStream.Init(_isSolid); - m_InBitStream.SetStream(inStream); - m_InBitStream.Init(); - - // InitData - - FlagsCnt = 0; - FlagBuf = 0; - StMode = false; - LCount = 0; - - if (!_isSolid) - { - AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; - AvrPlc = 0x3500; - MaxDist3 = 0x2001; - Nhfb = Nlzb = 0x80; - - { - // InitStructures - for (unsigned i = 0; i < kNumRepDists; i++) - m_RepDists[i] = 0; - m_RepDistPtr = 0; - LastLength = 0; - LastDist = 0; - } - - // InitHuff - - for (UInt32 i = 0; i < 256; i++) - { - Place[i] = PlaceA[i] = PlaceB[i] = i; - UInt32 c = (~i + 1) & 0xff; - PlaceC[i] = c; - ChSet[i] = ChSetB[i] = i << 8; - ChSetA[i] = i; - ChSetC[i] = c << 8; - } - memset(NToPl, 0, sizeof(NToPl)); - memset(NToPlB, 0, sizeof(NToPlB)); - memset(NToPlC, 0, sizeof(NToPlC)); - CorrHuff(ChSetB, NToPlB); - } - - if (m_UnpackSize > 0) - { - GetFlagsBuf(); - FlagsCnt = 8; - } - - while (m_UnpackSize != 0) - { - if (!StMode) - { - if (--FlagsCnt < 0) - { - GetFlagsBuf(); - FlagsCnt = 7; - } - - if (FlagBuf & 0x80) - { - FlagBuf <<= 1; - if (Nlzb > Nhfb) - { - RINOK(LongLZ()) - continue; - } - } - else - { - FlagBuf <<= 1; - - if (--FlagsCnt < 0) - { - GetFlagsBuf(); - FlagsCnt = 7; - } - - if ((FlagBuf & 0x80) == 0) - { - FlagBuf <<= 1; - RINOK(ShortLZ()) - continue; - } - - FlagBuf <<= 1; - - if (Nlzb <= Nhfb) - { - RINOK(LongLZ()) - continue; - } - } - } - - RINOK(HuffDecode()) - } - - _solidAllowed = true; - return m_OutWindowStream.Flush(); -} - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - if (size < 1) - return E_INVALIDARG; - _isSolid = ((data[0] & 1) != 0); - return S_OK; -} - -}} +// Rar1Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +#include "Rar1Decoder.h" + +namespace NCompress { +namespace NRar1 { + +static const unsigned kNumBits = 12; + +static const Byte kShortLen1[16 * 3] = +{ + 0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, + 1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0, + 1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0 +}; + +static const Byte kShortLen2[16 * 3] = +{ + 0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, + 2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0, + 2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0 +}; + +static const Byte PosL1[kNumBits + 1] = { 0,0,2,1,2,2,4,5,4,4,8,0,224 }; +static const Byte PosL2[kNumBits + 1] = { 0,0,0,5,2,2,4,5,4,4,8,2,220 }; + +static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 }; +static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 }; +static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 }; +static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 }; +static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 }; + +static const UInt32 kHistorySize = (1 << 16); + +CDecoder::CDecoder(): + _isSolid(false), + _solidAllowed(false) + {} + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } + +HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len) +{ + if (len == 0) + return S_FALSE; + if (m_UnpackSize < len) + return S_FALSE; + m_UnpackSize -= len; + return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE; +} + + +UInt32 CDecoder::DecodeNum(const Byte *numTab) +{ + /* + { + // we can check that tables are correct + UInt32 sum = 0; + for (unsigned i = 0; i <= kNumBits; i++) + sum += ((UInt32)numTab[i] << (kNumBits - i)); + if (sum != (1 << kNumBits)) + throw 111; + } + */ + + UInt32 val = m_InBitStream.GetValue(kNumBits); + UInt32 sum = 0; + unsigned i = 2; + + for (;;) + { + const UInt32 num = numTab[i]; + const UInt32 cur = num << (kNumBits - i); + if (val < cur) + break; + i++; + val -= cur; + sum += num; + } + m_InBitStream.MovePos(i); + return ((val >> (kNumBits - i)) + sum); +} + + +HRESULT CDecoder::ShortLZ() +{ + NumHuf = 0; + + if (LCount == 2) + { + if (ReadBits(1)) + return CopyBlock(LastDist, LastLength); + LCount = 0; + } + + UInt32 bitField = m_InBitStream.GetValue(8); + + UInt32 len, dist; + { + const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2; + const Byte *lens = xors + 16 + Buf60; + for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++); + m_InBitStream.MovePos(lens[len]); + } + + if (len >= 9) + { + if (len == 9) + { + LCount++; + return CopyBlock(LastDist, LastLength); + } + + LCount = 0; + + if (len == 14) + { + len = DecodeNum(PosL2) + 5; + dist = 0x8000 + ReadBits(15) - 1; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); + } + + const UInt32 saveLen = len; + dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3]; + + len = DecodeNum(PosL1); + + if (len == 0xff && saveLen == 10) + { + Buf60 ^= 16; + return S_OK; + } + if (dist >= 256) + { + len++; + if (dist >= MaxDist3 - 1) + len++; + } + } + else + { + LCount = 0; + AvrLn1 += len; + AvrLn1 -= AvrLn1 >> 4; + + unsigned distancePlace = DecodeNum(PosHf2) & 0xff; + + dist = ChSetA[distancePlace]; + + if (distancePlace != 0) + { + PlaceA[dist]--; + UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1]; + PlaceA[lastDistance]++; + ChSetA[distancePlace] = lastDistance; + ChSetA[(size_t)distancePlace - 1] = dist; + } + } + + m_RepDists[m_RepDistPtr++] = dist; + m_RepDistPtr &= 3; + len += 2; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); +} + + +HRESULT CDecoder::LongLZ() +{ + UInt32 len; + UInt32 dist; + UInt32 distancePlace, newDistancePlace; + UInt32 oldAvr2, oldAvr3; + + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb >>= 1; + } + oldAvr2 = AvrLn2; + + if (AvrLn2 >= 64) + len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2); + else + { + UInt32 bitField = m_InBitStream.GetValue(16); + if (bitField < 0x100) + { + len = bitField; + m_InBitStream.MovePos(16); + } + else + { + for (len = 0; ((bitField << len) & 0x8000) == 0; len++); + + m_InBitStream.MovePos(len + 1); + } + } + + AvrLn2 += len; + AvrLn2 -= AvrLn2 >> 5; + + { + const Byte *tab; + if (AvrPlcB >= 0x2900) tab = PosHf2; + else if (AvrPlcB >= 0x0700) tab = PosHf1; + else tab = PosHf0; + distancePlace = DecodeNum(tab); // [0, 256] + } + + AvrPlcB += distancePlace; + AvrPlcB -= AvrPlcB >> 8; + + distancePlace &= 0xff; + + for (;;) + { + dist = ChSetB[distancePlace]; + newDistancePlace = NToPlB[dist++ & 0xff]++; + if (dist & 0xff) + break; + CorrHuff(ChSetB,NToPlB); + } + + ChSetB[distancePlace] = ChSetB[newDistancePlace]; + ChSetB[newDistancePlace] = dist; + + dist = ((dist & 0xff00) >> 1) | ReadBits(7); + + oldAvr3 = AvrLn3; + + if (len != 1 && len != 4) + { + if (len == 0 && dist <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else if (AvrLn3 > 0) + AvrLn3--; + } + + len += 3; + + if (dist >= MaxDist3) + len++; + if (dist <= 256) + len += 8; + + if (oldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && oldAvr2 < 0x40)) + MaxDist3 = 0x7f00; + else + MaxDist3 = 0x2001; + + m_RepDists[m_RepDistPtr++] = --dist; + m_RepDistPtr &= 3; + LastLength = len; + LastDist = dist; + + return CopyBlock(dist, len); +} + + +HRESULT CDecoder::HuffDecode() +{ + UInt32 curByte, newBytePlace; + UInt32 len; + UInt32 dist; + unsigned bytePlace; + { + const Byte *tab; + + if (AvrPlc >= 0x7600) tab = PosHf4; + else if (AvrPlc >= 0x5e00) tab = PosHf3; + else if (AvrPlc >= 0x3600) tab = PosHf2; + else if (AvrPlc >= 0x0e00) tab = PosHf1; + else tab = PosHf0; + + bytePlace = DecodeNum(tab); // [0, 256] + } + + if (StMode) + { + if (bytePlace == 0) + { + if (ReadBits(1)) + { + NumHuf = 0; + StMode = false; + return S_OK; + } + len = ReadBits(1) + 3; + dist = DecodeNum(PosHf2); + dist = (dist << 5) | ReadBits(5); + if (dist == 0) + return S_FALSE; + return CopyBlock(dist - 1, len); + } + bytePlace--; // bytePlace is [0, 255] + } + else if (NumHuf++ >= 16 && FlagsCnt == 0) + StMode = true; + + bytePlace &= 0xff; + AvrPlc += bytePlace; + AvrPlc -= AvrPlc >> 8; + Nhfb += 16; + + if (Nhfb > 0xff) + { + Nhfb = 0x90; + Nlzb >>= 1; + } + + m_UnpackSize--; + m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8)); + + for (;;) + { + curByte = ChSet[bytePlace]; + newBytePlace = NToPl[curByte++ & 0xff]++; + if ((curByte & 0xff) <= 0xa1) + break; + CorrHuff(ChSet, NToPl); + } + + ChSet[bytePlace] = ChSet[newBytePlace]; + ChSet[newBytePlace] = curByte; + return S_OK; +} + + +void CDecoder::GetFlagsBuf() +{ + UInt32 flags, newFlagsPlace; + const UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256] + + if (flagsPlace >= Z7_ARRAY_SIZE(ChSetC)) + return; + + for (;;) + { + flags = ChSetC[flagsPlace]; + FlagBuf = flags >> 8; + newFlagsPlace = NToPlC[flags++ & 0xff]++; + if ((flags & 0xff) != 0) + break; + CorrHuff(ChSetC, NToPlC); + } + + ChSetC[flagsPlace] = ChSetC[newFlagsPlace]; + ChSetC[newFlagsPlace] = flags; +} + + +void CDecoder::CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace) +{ + int i; + for (i = 7; i >= 0; i--) + for (unsigned j = 0; j < 32; j++, CharSet++) + *CharSet = (*CharSet & ~(UInt32)0xff) | (unsigned)i; + memset(NumToPlace, 0, sizeof(NToPl)); + for (i = 6; i >= 0; i--) + NumToPlace[i] = (7 - (unsigned)i) * 32; +} + + + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */) +{ + if (!inSize || !outSize) + return E_INVALIDARG; + + if (_isSolid && !_solidAllowed) + return S_FALSE; + + _solidAllowed = false; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + m_UnpackSize = *outSize; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(_isSolid); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + // InitData + + FlagsCnt = 0; + FlagBuf = 0; + StMode = false; + LCount = 0; + + if (!_isSolid) + { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + + { + // InitStructures + for (unsigned i = 0; i < kNumRepDists; i++) + m_RepDists[i] = 0; + m_RepDistPtr = 0; + LastLength = 0; + LastDist = 0; + } + + // InitHuff + + for (UInt32 i = 0; i < 256; i++) + { + Place[i] = PlaceA[i] = PlaceB[i] = i; + UInt32 c = (~i + 1) & 0xff; + PlaceC[i] = c; + ChSet[i] = ChSetB[i] = i << 8; + ChSetA[i] = i; + ChSetC[i] = c << 8; + } + memset(NToPl, 0, sizeof(NToPl)); + memset(NToPlB, 0, sizeof(NToPlB)); + memset(NToPlC, 0, sizeof(NToPlC)); + CorrHuff(ChSetB, NToPlB); + } + + if (m_UnpackSize > 0) + { + GetFlagsBuf(); + FlagsCnt = 8; + } + + while (m_UnpackSize != 0) + { + if (!StMode) + { + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt = 7; + } + + if (FlagBuf & 0x80) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + RINOK(LongLZ()) + continue; + } + } + else + { + FlagBuf <<= 1; + + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt = 7; + } + + if ((FlagBuf & 0x80) == 0) + { + FlagBuf <<= 1; + RINOK(ShortLZ()) + continue; + } + + FlagBuf <<= 1; + + if (Nlzb <= Nhfb) + { + RINOK(LongLZ()) + continue; + } + } + } + + RINOK(HuffDecode()) + } + + _solidAllowed = true; + return m_OutWindowStream.Flush(); +} + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar1Decoder.h b/CPP/7zip/Compress/Rar1Decoder.h index 81a67a1be..e1e22e2ae 100644 --- a/CPP/7zip/Compress/Rar1Decoder.h +++ b/CPP/7zip/Compress/Rar1Decoder.h @@ -1,70 +1,70 @@ -// Rar1Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef ZIP7_INC_COMPRESS_RAR1_DECODER_H -#define ZIP7_INC_COMPRESS_RAR1_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NRar1 { - -const unsigned kNumRepDists = 4; - -Z7_CLASS_IMP_COM_2( - CDecoder - , ICompressCoder - , ICompressSetDecoderProperties2 -) - bool _isSolid; - bool _solidAllowed; - bool StMode; - - CLzOutWindow m_OutWindowStream; - NBitm::CDecoder m_InBitStream; - - UInt64 m_UnpackSize; - - UInt32 LastDist; - UInt32 LastLength; - - UInt32 m_RepDistPtr; - UInt32 m_RepDists[kNumRepDists]; - - int FlagsCnt; - UInt32 FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; - unsigned Buf60, NumHuf, LCount; - UInt32 Nhfb, Nlzb, MaxDist3; - - UInt32 ChSet[256], ChSetA[256], ChSetB[256], ChSetC[256]; - UInt32 Place[256], PlaceA[256], PlaceB[256], PlaceC[256]; - UInt32 NToPl[256], NToPlB[256], NToPlC[256]; - - UInt32 ReadBits(unsigned numBits); - HRESULT CopyBlock(UInt32 distance, UInt32 len); - UInt32 DecodeNum(const Byte *numTab); - HRESULT ShortLZ(); - HRESULT LongLZ(); - HRESULT HuffDecode(); - void GetFlagsBuf(); - void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace); - void OldUnpWriteBuf(); - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - -public: - CDecoder(); -}; - -}} - -#endif +// Rar1Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef ZIP7_INC_COMPRESS_RAR1_DECODER_H +#define ZIP7_INC_COMPRESS_RAR1_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NRar1 { + +const unsigned kNumRepDists = 4; + +Z7_CLASS_IMP_COM_2( + CDecoder + , ICompressCoder + , ICompressSetDecoderProperties2 +) + bool _isSolid; + bool _solidAllowed; + bool StMode; + + CLzOutWindow m_OutWindowStream; + NBitm::CDecoder m_InBitStream; + + UInt64 m_UnpackSize; + + UInt32 LastDist; + UInt32 LastLength; + + UInt32 m_RepDistPtr; + UInt32 m_RepDists[kNumRepDists]; + + int FlagsCnt; + UInt32 FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + unsigned Buf60, NumHuf, LCount; + UInt32 Nhfb, Nlzb, MaxDist3; + + UInt32 ChSet[256], ChSetA[256], ChSetB[256], ChSetC[256]; + UInt32 Place[256], PlaceA[256], PlaceB[256], PlaceC[256]; + UInt32 NToPl[256], NToPlB[256], NToPlC[256]; + + UInt32 ReadBits(unsigned numBits); + HRESULT CopyBlock(UInt32 distance, UInt32 len); + UInt32 DecodeNum(const Byte *numTab); + HRESULT ShortLZ(); + HRESULT LongLZ(); + HRESULT HuffDecode(); + void GetFlagsBuf(); + void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace); + void OldUnpWriteBuf(); + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + +public: + CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar2Decoder.cpp index 18e7a79fc..63c04a16e 100644 --- a/CPP/7zip/Compress/Rar2Decoder.cpp +++ b/CPP/7zip/Compress/Rar2Decoder.cpp @@ -1,472 +1,472 @@ -// Rar2Decoder.cpp -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#include "StdAfx.h" - -#include - -#include "Rar2Decoder.h" - -namespace NCompress { -namespace NRar2 { - -namespace NMultimedia { - -#define my_abs(x) (unsigned)abs(x) - -Byte CFilter::Decode(int &channelDelta, Byte deltaByte) -{ - D4 = D3; - D3 = D2; - D2 = LastDelta - D1; - D1 = LastDelta; - const int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); - - const Byte realValue = (Byte)(predictedValue - deltaByte); - - { - const int i = ((int)(signed char)deltaByte) << 3; - - Dif[0] += my_abs(i); - Dif[1] += my_abs(i - D1); - Dif[2] += my_abs(i + D1); - Dif[3] += my_abs(i - D2); - Dif[4] += my_abs(i + D2); - Dif[5] += my_abs(i - D3); - Dif[6] += my_abs(i + D3); - Dif[7] += my_abs(i - D4); - Dif[8] += my_abs(i + D4); - Dif[9] += my_abs(i - channelDelta); - Dif[10] += my_abs(i + channelDelta); - } - - channelDelta = LastDelta = (signed char)(realValue - LastChar); - LastChar = realValue; - - if (((++ByteCount) & 0x1F) == 0) - { - UInt32 minDif = Dif[0]; - UInt32 numMinDif = 0; - Dif[0] = 0; - - for (unsigned i = 1; i < Z7_ARRAY_SIZE(Dif); i++) - { - if (Dif[i] < minDif) - { - minDif = Dif[i]; - numMinDif = i; - } - Dif[i] = 0; - } - - switch (numMinDif) - { - case 1: if (K1 >= -16) K1--; break; - case 2: if (K1 < 16) K1++; break; - case 3: if (K2 >= -16) K2--; break; - case 4: if (K2 < 16) K2++; break; - case 5: if (K3 >= -16) K3--; break; - case 6: if (K3 < 16) K3++; break; - case 7: if (K4 >= -16) K4--; break; - case 8: if (K4 < 16) K4++; break; - case 9: if (K5 >= -16) K5--; break; - case 10:if (K5 < 16) K5++; break; - } - } - - return realValue; -} -} - -static const UInt32 kHistorySize = 1 << 20; - -// static const UInt32 kWindowReservSize = (1 << 22) + 256; - -CDecoder::CDecoder(): - _isSolid(false), - _solidAllowed(false), - m_TablesOK(false) -{ -} - -void CDecoder::InitStructures() -{ - m_MmFilter.Init(); - for (unsigned i = 0; i < kNumReps; i++) - m_RepDists[i] = 0; - m_RepDistPtr = 0; - m_LastLength = 0; - memset(m_LastLevels, 0, kMaxTableSize); -} - -UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } - -#define RIF(x) { if (!(x)) return false; } - -static const unsigned kRepBothNumber = 256; -static const unsigned kRepNumber = kRepBothNumber + 1; -static const unsigned kLen2Number = kRepNumber + kNumReps; -static const unsigned kReadTableNumber = kLen2Number + kNumLen2Symbols; -static const unsigned kMatchNumber = kReadTableNumber + 1; - -// static const unsigned kDistTableStart = kMainTableSize; -// static const unsigned kLenTableStart = kDistTableStart + kDistTableSize; - -static const UInt32 kDistStart [kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; -static const Byte kDistDirectBits[kDistTableSize] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; - -static const Byte kLen2DistStarts [kNumLen2Symbols]={0,4,8,16,32,64,128,192}; -static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6}; - -static const UInt32 kDistLimit2 = 0x101 - 1; -static const UInt32 kDistLimit3 = 0x2000 - 1; -static const UInt32 kDistLimit4 = 0x40000 - 1; - -// static const UInt32 kMatchMaxLen = 255 + 2; -// static const UInt32 kMatchMaxLenMax = 255 + 5; - - -bool CDecoder::ReadTables(void) -{ - m_TablesOK = false; - - const unsigned kLevelTableSize = 19; - Byte levelLevels[kLevelTableSize]; - Byte lens[kMaxTableSize]; - - m_AudioMode = (ReadBits(1) == 1); - - if (ReadBits(1) == 0) - memset(m_LastLevels, 0, kMaxTableSize); - - unsigned numLevels; - - if (m_AudioMode) - { - m_NumChannels = ReadBits(2) + 1; - if (m_MmFilter.CurrentChannel >= m_NumChannels) - m_MmFilter.CurrentChannel = 0; - numLevels = m_NumChannels * k_MM_TableSize; - } - else - numLevels = kHeapTablesSizesSum; - - unsigned i; - for (i = 0; i < kLevelTableSize; i++) - levelLevels[i] = (Byte)ReadBits(4); - NHuffman::CDecoder256 m_LevelDecoder; - RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full)) - - i = 0; - do - { - const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream); - if (sym < 16) - { - lens[i] = (Byte)((sym + m_LastLevels[i]) & 15); - i++; - } -#if 0 - else if (sym >= kLevelTableSize) - return false; -#endif - else - { - unsigned num; - Byte v; - if (sym == 16) - { - if (i == 0) - return false; - num = ReadBits(2) + 3; - v = lens[(size_t)i - 1]; - } - else - { - num = (sym - 17) * 4; - num += num + 3 + ReadBits(3 + num); - v = 0; - } - num += i; - if (num > numLevels) - { - // return false; - num = numLevels; // original unRAR - } - do - lens[i++] = v; - while (i < num); - } - } - while (i < numLevels); - - if (m_InBitStream.ExtraBitsWereRead()) - return false; - - if (m_AudioMode) - for (i = 0; i < m_NumChannels; i++) - { - RIF(m_MMDecoders[i].Build(&lens[(size_t)i * k_MM_TableSize])) - } - else - { - RIF(m_MainDecoder.Build(&lens[0])) - RIF(m_DistDecoder.Build(&lens[kMainTableSize])) - RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize])) - } - - memcpy(m_LastLevels, lens, kMaxTableSize); - - m_TablesOK = true; - return true; -} - - -bool CDecoder::ReadLastTables() -{ - // it differs a little from pure RAR sources; - // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2; - // + 2 works for: return 0xFF; in CInBuffer::ReadByte. - if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect; - // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; - { - if (m_AudioMode) - { - const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); - if (symbol == 256) - return ReadTables(); - if (symbol >= k_MM_TableSize) - return false; - } - else - { - const unsigned sym = m_MainDecoder.Decode(&m_InBitStream); - if (sym == kReadTableNumber) - return ReadTables(); - if (sym >= kMainTableSize) - return false; - } - } - return true; -} - - -bool CDecoder::DecodeMm(UInt32 pos) -{ - while (pos-- != 0) - { - const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); - if (m_InBitStream.ExtraBitsWereRead()) - return false; - if (symbol >= 256) - return symbol == 256; - /* - Byte byPredict = m_Predictor.Predict(); - Byte byReal = (Byte)(byPredict - (Byte)symbol); - m_Predictor.Update(byReal, byPredict); - */ - const Byte byReal = m_MmFilter.Decode((Byte)symbol); - m_OutWindowStream.PutByte(byReal); - if (++m_MmFilter.CurrentChannel == m_NumChannels) - m_MmFilter.CurrentChannel = 0; - } - return true; -} - - -typedef unsigned CLenType; - -static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot) -{ - const unsigned numBits = ((unsigned)slot >> 2) - 1; - return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits(numBits); -} - -bool CDecoder::DecodeLz(Int32 pos) -{ - while (pos > 0) - { - unsigned sym = m_MainDecoder.Decode(&m_InBitStream); - if (m_InBitStream.ExtraBitsWereRead()) - return false; - UInt32 len, distance; - if (sym < 256) - { - m_OutWindowStream.PutByte(Byte(sym)); - pos--; - continue; - } - else if (sym >= kMatchNumber) - { - if (sym >= kMainTableSize) - return false; - len = sym - kMatchNumber; - if (len >= 8) - len = SlotToLen(m_InBitStream, len); - len += 3; - - sym = m_DistDecoder.Decode(&m_InBitStream); - if (sym >= kDistTableSize) - return false; - distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); - if (distance >= kDistLimit3) - { - len += 2 - ((distance - kDistLimit4) >> 31); - // len++; - // if (distance >= kDistLimit4) - // len++; - } - } - else if (sym == kRepBothNumber) - { - len = m_LastLength; - if (len == 0) - return false; - distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3]; - } - else if (sym < kLen2Number) - { - distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3]; - len = m_LenDecoder.Decode(&m_InBitStream); - if (len >= kLenTableSize) - return false; - if (len >= 8) - len = SlotToLen(m_InBitStream, len); - len += 2; - - if (distance >= kDistLimit2) - { - len++; - if (distance >= kDistLimit3) - { - len += 2 - ((distance - kDistLimit4) >> 31); - // len++; - // if (distance >= kDistLimit4) - // len++; - } - } - } - else if (sym < kReadTableNumber) - { - sym -= kLen2Number; - distance = kLen2DistStarts[sym] + - m_InBitStream.ReadBits(kLen2DistDirectBits[sym]); - len = 2; - } - else // (sym == kReadTableNumber) - return true; - - m_RepDists[m_RepDistPtr++ & 3] = distance; - m_LastLength = len; - if (!m_OutWindowStream.CopyBlock(distance, len)) - return false; - pos -= len; - } - return true; -} - -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - if (!inSize || !outSize) - return E_INVALIDARG; - - if (_isSolid && !_solidAllowed) - return S_FALSE; - _solidAllowed = false; - - if (!m_OutWindowStream.Create(kHistorySize)) - return E_OUTOFMEMORY; - if (!m_InBitStream.Create(1 << 20)) - return E_OUTOFMEMORY; - - m_PackSize = *inSize; - - UInt64 pos = 0, unPackSize = *outSize; - - m_OutWindowStream.SetStream(outStream); - m_OutWindowStream.Init(_isSolid); - m_InBitStream.SetStream(inStream); - m_InBitStream.Init(); - - // CCoderReleaser coderReleaser(this); - if (!_isSolid) - { - InitStructures(); - if (unPackSize == 0) - { - if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; - if (!ReadTables()) - return S_FALSE; - _solidAllowed = true; - return S_OK; - } - ReadTables(); - } - - if (!m_TablesOK) - return S_FALSE; - - const UInt64 startPos = m_OutWindowStream.GetProcessedSize(); - while (pos < unPackSize) - { - UInt32 blockSize = 1 << 20; - if (blockSize > unPackSize - pos) - blockSize = (UInt32)(unPackSize - pos); - UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize(); - if (m_AudioMode) - { - if (!DecodeMm(blockSize)) - return S_FALSE; - } - else - { - if (!DecodeLz((Int32)blockSize)) - return S_FALSE; - } - - if (m_InBitStream.ExtraBitsWereRead()) - return S_FALSE; - - const UInt64 globalPos = m_OutWindowStream.GetProcessedSize(); - pos = globalPos - blockStartPos; - if (pos < blockSize) - if (!ReadTables()) - return S_FALSE; - pos = globalPos - startPos; - if (progress) - { - const UInt64 packSize = m_InBitStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &pos)) - } - } - if (pos > unPackSize) - return S_FALSE; - - if (!ReadLastTables()) - return S_FALSE; - - _solidAllowed = true; - - return m_OutWindowStream.Flush(); -} - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - if (size < 1) - return E_INVALIDARG; - _isSolid = ((data[0] & 1) != 0); - return S_OK; -} - -}} +// Rar2Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +#include + +#include "Rar2Decoder.h" + +namespace NCompress { +namespace NRar2 { + +namespace NMultimedia { + +#define my_abs(x) (unsigned)abs(x) + +Byte CFilter::Decode(int &channelDelta, Byte deltaByte) +{ + D4 = D3; + D3 = D2; + D2 = LastDelta - D1; + D1 = LastDelta; + const int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); + + const Byte realValue = (Byte)(predictedValue - deltaByte); + + { + const int i = ((int)(signed char)deltaByte) << 3; + + Dif[0] += my_abs(i); + Dif[1] += my_abs(i - D1); + Dif[2] += my_abs(i + D1); + Dif[3] += my_abs(i - D2); + Dif[4] += my_abs(i + D2); + Dif[5] += my_abs(i - D3); + Dif[6] += my_abs(i + D3); + Dif[7] += my_abs(i - D4); + Dif[8] += my_abs(i + D4); + Dif[9] += my_abs(i - channelDelta); + Dif[10] += my_abs(i + channelDelta); + } + + channelDelta = LastDelta = (signed char)(realValue - LastChar); + LastChar = realValue; + + if (((++ByteCount) & 0x1F) == 0) + { + UInt32 minDif = Dif[0]; + UInt32 numMinDif = 0; + Dif[0] = 0; + + for (unsigned i = 1; i < Z7_ARRAY_SIZE(Dif); i++) + { + if (Dif[i] < minDif) + { + minDif = Dif[i]; + numMinDif = i; + } + Dif[i] = 0; + } + + switch (numMinDif) + { + case 1: if (K1 >= -16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2 >= -16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3 >= -16) K3--; break; + case 6: if (K3 < 16) K3++; break; + case 7: if (K4 >= -16) K4--; break; + case 8: if (K4 < 16) K4++; break; + case 9: if (K5 >= -16) K5--; break; + case 10:if (K5 < 16) K5++; break; + } + } + + return realValue; +} +} + +static const UInt32 kHistorySize = 1 << 20; + +// static const UInt32 kWindowReservSize = (1 << 22) + 256; + +CDecoder::CDecoder(): + _isSolid(false), + _solidAllowed(false), + m_TablesOK(false) +{ +} + +void CDecoder::InitStructures() +{ + m_MmFilter.Init(); + for (unsigned i = 0; i < kNumReps; i++) + m_RepDists[i] = 0; + m_RepDistPtr = 0; + m_LastLength = 0; + memset(m_LastLevels, 0, kMaxTableSize); +} + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } + +#define RIF(x) { if (!(x)) return false; } + +static const unsigned kRepBothNumber = 256; +static const unsigned kRepNumber = kRepBothNumber + 1; +static const unsigned kLen2Number = kRepNumber + kNumReps; +static const unsigned kReadTableNumber = kLen2Number + kNumLen2Symbols; +static const unsigned kMatchNumber = kReadTableNumber + 1; + +// static const unsigned kDistTableStart = kMainTableSize; +// static const unsigned kLenTableStart = kDistTableStart + kDistTableSize; + +static const UInt32 kDistStart [kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; +static const Byte kDistDirectBits[kDistTableSize] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; + +static const Byte kLen2DistStarts [kNumLen2Symbols]={0,4,8,16,32,64,128,192}; +static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6}; + +static const UInt32 kDistLimit2 = 0x101 - 1; +static const UInt32 kDistLimit3 = 0x2000 - 1; +static const UInt32 kDistLimit4 = 0x40000 - 1; + +// static const UInt32 kMatchMaxLen = 255 + 2; +// static const UInt32 kMatchMaxLenMax = 255 + 5; + + +bool CDecoder::ReadTables(void) +{ + m_TablesOK = false; + + const unsigned kLevelTableSize = 19; + Byte levelLevels[kLevelTableSize]; + Byte lens[kMaxTableSize]; + + m_AudioMode = (ReadBits(1) == 1); + + if (ReadBits(1) == 0) + memset(m_LastLevels, 0, kMaxTableSize); + + unsigned numLevels; + + if (m_AudioMode) + { + m_NumChannels = ReadBits(2) + 1; + if (m_MmFilter.CurrentChannel >= m_NumChannels) + m_MmFilter.CurrentChannel = 0; + numLevels = m_NumChannels * k_MM_TableSize; + } + else + numLevels = kHeapTablesSizesSum; + + unsigned i; + for (i = 0; i < kLevelTableSize; i++) + levelLevels[i] = (Byte)ReadBits(4); + NHuffman::CDecoder256 m_LevelDecoder; + RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full)) + + i = 0; + do + { + const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream); + if (sym < 16) + { + lens[i] = (Byte)((sym + m_LastLevels[i]) & 15); + i++; + } +#if 0 + else if (sym >= kLevelTableSize) + return false; +#endif + else + { + unsigned num; + Byte v; + if (sym == 16) + { + if (i == 0) + return false; + num = ReadBits(2) + 3; + v = lens[(size_t)i - 1]; + } + else + { + num = (sym - 17) * 4; + num += num + 3 + ReadBits(3 + num); + v = 0; + } + num += i; + if (num > numLevels) + { + // return false; + num = numLevels; // original unRAR + } + do + lens[i++] = v; + while (i < num); + } + } + while (i < numLevels); + + if (m_InBitStream.ExtraBitsWereRead()) + return false; + + if (m_AudioMode) + for (i = 0; i < m_NumChannels; i++) + { + RIF(m_MMDecoders[i].Build(&lens[(size_t)i * k_MM_TableSize])) + } + else + { + RIF(m_MainDecoder.Build(&lens[0])) + RIF(m_DistDecoder.Build(&lens[kMainTableSize])) + RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize])) + } + + memcpy(m_LastLevels, lens, kMaxTableSize); + + m_TablesOK = true; + return true; +} + + +bool CDecoder::ReadLastTables() +{ + // it differs a little from pure RAR sources; + // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2; + // + 2 works for: return 0xFF; in CInBuffer::ReadByte. + if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect; + // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; + { + if (m_AudioMode) + { + const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); + if (symbol == 256) + return ReadTables(); + if (symbol >= k_MM_TableSize) + return false; + } + else + { + const unsigned sym = m_MainDecoder.Decode(&m_InBitStream); + if (sym == kReadTableNumber) + return ReadTables(); + if (sym >= kMainTableSize) + return false; + } + } + return true; +} + + +bool CDecoder::DecodeMm(UInt32 pos) +{ + while (pos-- != 0) + { + const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); + if (m_InBitStream.ExtraBitsWereRead()) + return false; + if (symbol >= 256) + return symbol == 256; + /* + Byte byPredict = m_Predictor.Predict(); + Byte byReal = (Byte)(byPredict - (Byte)symbol); + m_Predictor.Update(byReal, byPredict); + */ + const Byte byReal = m_MmFilter.Decode((Byte)symbol); + m_OutWindowStream.PutByte(byReal); + if (++m_MmFilter.CurrentChannel == m_NumChannels) + m_MmFilter.CurrentChannel = 0; + } + return true; +} + + +typedef unsigned CLenType; + +static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot) +{ + const unsigned numBits = ((unsigned)slot >> 2) - 1; + return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits(numBits); +} + +bool CDecoder::DecodeLz(Int32 pos) +{ + while (pos > 0) + { + unsigned sym = m_MainDecoder.Decode(&m_InBitStream); + if (m_InBitStream.ExtraBitsWereRead()) + return false; + UInt32 len, distance; + if (sym < 256) + { + m_OutWindowStream.PutByte(Byte(sym)); + pos--; + continue; + } + else if (sym >= kMatchNumber) + { + if (sym >= kMainTableSize) + return false; + len = sym - kMatchNumber; + if (len >= 8) + len = SlotToLen(m_InBitStream, len); + len += 3; + + sym = m_DistDecoder.Decode(&m_InBitStream); + if (sym >= kDistTableSize) + return false; + distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); + if (distance >= kDistLimit3) + { + len += 2 - ((distance - kDistLimit4) >> 31); + // len++; + // if (distance >= kDistLimit4) + // len++; + } + } + else if (sym == kRepBothNumber) + { + len = m_LastLength; + if (len == 0) + return false; + distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3]; + } + else if (sym < kLen2Number) + { + distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3]; + len = m_LenDecoder.Decode(&m_InBitStream); + if (len >= kLenTableSize) + return false; + if (len >= 8) + len = SlotToLen(m_InBitStream, len); + len += 2; + + if (distance >= kDistLimit2) + { + len++; + if (distance >= kDistLimit3) + { + len += 2 - ((distance - kDistLimit4) >> 31); + // len++; + // if (distance >= kDistLimit4) + // len++; + } + } + } + else if (sym < kReadTableNumber) + { + sym -= kLen2Number; + distance = kLen2DistStarts[sym] + + m_InBitStream.ReadBits(kLen2DistDirectBits[sym]); + len = 2; + } + else // (sym == kReadTableNumber) + return true; + + m_RepDists[m_RepDistPtr++ & 3] = distance; + m_LastLength = len; + if (!m_OutWindowStream.CopyBlock(distance, len)) + return false; + pos -= len; + } + return true; +} + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + if (!inSize || !outSize) + return E_INVALIDARG; + + if (_isSolid && !_solidAllowed) + return S_FALSE; + _solidAllowed = false; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + m_PackSize = *inSize; + + UInt64 pos = 0, unPackSize = *outSize; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(_isSolid); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + // CCoderReleaser coderReleaser(this); + if (!_isSolid) + { + InitStructures(); + if (unPackSize == 0) + { + if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; + if (!ReadTables()) + return S_FALSE; + _solidAllowed = true; + return S_OK; + } + ReadTables(); + } + + if (!m_TablesOK) + return S_FALSE; + + const UInt64 startPos = m_OutWindowStream.GetProcessedSize(); + while (pos < unPackSize) + { + UInt32 blockSize = 1 << 20; + if (blockSize > unPackSize - pos) + blockSize = (UInt32)(unPackSize - pos); + UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize(); + if (m_AudioMode) + { + if (!DecodeMm(blockSize)) + return S_FALSE; + } + else + { + if (!DecodeLz((Int32)blockSize)) + return S_FALSE; + } + + if (m_InBitStream.ExtraBitsWereRead()) + return S_FALSE; + + const UInt64 globalPos = m_OutWindowStream.GetProcessedSize(); + pos = globalPos - blockStartPos; + if (pos < blockSize) + if (!ReadTables()) + return S_FALSE; + pos = globalPos - startPos; + if (progress) + { + const UInt64 packSize = m_InBitStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)) + } + } + if (pos > unPackSize) + return S_FALSE; + + if (!ReadLastTables()) + return S_FALSE; + + _solidAllowed = true; + + return m_OutWindowStream.Flush(); +} + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const CLzOutWindowException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar2Decoder.h b/CPP/7zip/Compress/Rar2Decoder.h index 97c7dd86c..c9ddedbea 100644 --- a/CPP/7zip/Compress/Rar2Decoder.h +++ b/CPP/7zip/Compress/Rar2Decoder.h @@ -1,111 +1,111 @@ -// Rar2Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef ZIP7_INC_COMPRESS_RAR2_DECODER_H -#define ZIP7_INC_COMPRESS_RAR2_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "LzOutWindow.h" - -namespace NCompress { -namespace NRar2 { - -const unsigned kNumReps = 4; -const unsigned kDistTableSize = 48; -const unsigned kNumLen2Symbols = 8; -const unsigned kLenTableSize = 28; -const unsigned kMainTableSize = 256 + 2 + kNumReps + kNumLen2Symbols + kLenTableSize; -const unsigned kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize; -const unsigned k_MM_TableSize = 256 + 1; -const unsigned k_MM_NumChanelsMax = 4; -const unsigned k_MM_TablesSizesSum = k_MM_TableSize * k_MM_NumChanelsMax; -const unsigned kMaxTableSize = k_MM_TablesSizesSum; - -namespace NMultimedia { - -struct CFilter -{ - int K1,K2,K3,K4,K5; - int D1,D2,D3,D4; - int LastDelta; - UInt32 Dif[11]; - UInt32 ByteCount; - int LastChar; - - void Init() { memset(this, 0, sizeof(*this)); } - Byte Decode(int &channelDelta, Byte delta); -}; - -struct CFilter2 -{ - CFilter m_Filters[k_MM_NumChanelsMax]; - int m_ChannelDelta; - unsigned CurrentChannel; - - void Init() { memset(this, 0, sizeof(*this)); } - Byte Decode(Byte delta) - { - return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta); - } -}; - -} - -typedef NBitm::CDecoder CBitDecoder; - -const unsigned kNumHufBits = 15; - -Z7_CLASS_IMP_NOQIB_2( - CDecoder - , ICompressCoder - , ICompressSetDecoderProperties2 -) - bool _isSolid; - bool _solidAllowed; - bool m_TablesOK; - bool m_AudioMode; - - CLzOutWindow m_OutWindowStream; - CBitDecoder m_InBitStream; - - UInt32 m_RepDistPtr; - UInt32 m_RepDists[kNumReps]; - UInt32 m_LastLength; - unsigned m_NumChannels; - - NHuffman::CDecoder m_MainDecoder; - NHuffman::CDecoder256 m_DistDecoder; - NHuffman::CDecoder256 m_LenDecoder; - NHuffman::CDecoder m_MMDecoders[k_MM_NumChanelsMax]; - - UInt64 m_PackSize; - - NMultimedia::CFilter2 m_MmFilter; - Byte m_LastLevels[kMaxTableSize]; - - void InitStructures(); - UInt32 ReadBits(unsigned numBits); - bool ReadTables(); - bool ReadLastTables(); - - bool DecodeMm(UInt32 pos); - bool DecodeLz(Int32 pos); - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); - -public: - CDecoder(); -}; - -}} - -#endif +// Rar2Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef ZIP7_INC_COMPRESS_RAR2_DECODER_H +#define ZIP7_INC_COMPRESS_RAR2_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NRar2 { + +const unsigned kNumReps = 4; +const unsigned kDistTableSize = 48; +const unsigned kNumLen2Symbols = 8; +const unsigned kLenTableSize = 28; +const unsigned kMainTableSize = 256 + 2 + kNumReps + kNumLen2Symbols + kLenTableSize; +const unsigned kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize; +const unsigned k_MM_TableSize = 256 + 1; +const unsigned k_MM_NumChanelsMax = 4; +const unsigned k_MM_TablesSizesSum = k_MM_TableSize * k_MM_NumChanelsMax; +const unsigned kMaxTableSize = k_MM_TablesSizesSum; + +namespace NMultimedia { + +struct CFilter +{ + int K1,K2,K3,K4,K5; + int D1,D2,D3,D4; + int LastDelta; + UInt32 Dif[11]; + UInt32 ByteCount; + int LastChar; + + void Init() { memset(this, 0, sizeof(*this)); } + Byte Decode(int &channelDelta, Byte delta); +}; + +struct CFilter2 +{ + CFilter m_Filters[k_MM_NumChanelsMax]; + int m_ChannelDelta; + unsigned CurrentChannel; + + void Init() { memset(this, 0, sizeof(*this)); } + Byte Decode(Byte delta) + { + return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta); + } +}; + +} + +typedef NBitm::CDecoder CBitDecoder; + +const unsigned kNumHufBits = 15; + +Z7_CLASS_IMP_NOQIB_2( + CDecoder + , ICompressCoder + , ICompressSetDecoderProperties2 +) + bool _isSolid; + bool _solidAllowed; + bool m_TablesOK; + bool m_AudioMode; + + CLzOutWindow m_OutWindowStream; + CBitDecoder m_InBitStream; + + UInt32 m_RepDistPtr; + UInt32 m_RepDists[kNumReps]; + UInt32 m_LastLength; + unsigned m_NumChannels; + + NHuffman::CDecoder m_MainDecoder; + NHuffman::CDecoder256 m_DistDecoder; + NHuffman::CDecoder256 m_LenDecoder; + NHuffman::CDecoder m_MMDecoders[k_MM_NumChanelsMax]; + + UInt64 m_PackSize; + + NMultimedia::CFilter2 m_MmFilter; + Byte m_LastLevels[kMaxTableSize]; + + void InitStructures(); + UInt32 ReadBits(unsigned numBits); + bool ReadTables(); + bool ReadLastTables(); + + bool DecodeMm(UInt32 pos); + bool DecodeLz(Int32 pos); + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + +public: + CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp index 541b7f899..c17d46dc4 100644 --- a/CPP/7zip/Compress/Rar3Decoder.cpp +++ b/CPP/7zip/Compress/Rar3Decoder.cpp @@ -1,939 +1,939 @@ -// Rar3Decoder.cpp -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/StreamUtils.h" - -#include "Rar3Decoder.h" - -namespace NCompress { -namespace NRar3 { - -static const UInt32 kNumAlignReps = 15; - -static const unsigned kSymbolReadTable = 256; -static const unsigned kSymbolRep = 259; - -static const Byte kDistDirectBits[kDistTableSize] = - {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 18,18,18,18,18,18,18,18,18,18,18,18}; - -static const Byte kLen2DistStarts[kNumLen2Symbols] = {0,4,8,16,32,64,128,192}; -static const Byte kLen2DistDirectBits[kNumLen2Symbols] = {2,2,3, 4, 5, 6, 6, 6}; - -static const UInt32 kDistLimit3 = 0x2000 - 2; -static const UInt32 kDistLimit4 = 0x40000 - 2; - -static const UInt32 kNormalMatchMinLen = 3; - -static const UInt32 kVmDataSizeMax = 1 << 16; -static const UInt32 kVmCodeSizeMax = 1 << 16; - -extern "C" { - -static Byte Wrap_ReadByte(IByteInPtr pp) throw() -{ - CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj); - return p->BitDecoder.Stream.ReadByte(); -} - -static Byte Wrap_ReadBits8(IByteInPtr pp) throw() -{ - CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj); - return (Byte)p->BitDecoder.ReadByteFromAligned(); -} - -} - - -CDecoder::CDecoder(): - _isSolid(false), - _solidAllowed(false), - _window(NULL), - _winPos(0), - _wrPtr(0), - _lzSize(0), - _writtenFileSize(0), - _vmData(NULL), - _vmCode(NULL) -{ - Ppmd7_Construct(&_ppmd); - - UInt32 start = 0; - for (UInt32 i = 0; i < kDistTableSize; i++) - { - kDistStart[i] = start; - start += ((UInt32)1 << kDistDirectBits[i]); - } -} - -CDecoder::~CDecoder() -{ - InitFilters(); - ::MidFree(_vmData); - ::MidFree(_window); - Ppmd7_Free(&_ppmd, &g_BigAlloc); -} - -HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size) -{ - return WriteStream(_outStream, data, size); -} - -HRESULT CDecoder::WriteData(const Byte *data, UInt32 size) -{ - HRESULT res = S_OK; - if (_writtenFileSize < _unpackSize) - { - UInt32 curSize = size; - UInt64 remain = _unpackSize - _writtenFileSize; - if (remain < curSize) - curSize = (UInt32)remain; - res = WriteDataToStream(data, curSize); - } - _writtenFileSize += size; - return res; -} - -HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) -{ - if (startPtr <= endPtr) - return WriteData(_window + startPtr, endPtr - startPtr); - RINOK(WriteData(_window + startPtr, kWindowSize - startPtr)) - return WriteData(_window, endPtr); -} - -void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef) -{ - CTempFilter *tempFilter = _tempFilters[tempFilterIndex]; - tempFilter->InitR[6] = (UInt32)_writtenFileSize; - NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize); - NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32)); - CFilter *filter = _filters[tempFilter->FilterIndex]; - if (!filter->IsSupported) - _unsupportedFilter = true; - if (!_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData)) - _unsupportedFilter = true; - delete tempFilter; - _tempFilters[tempFilterIndex] = NULL; - _numEmptyTempFilters++; -} - -HRESULT CDecoder::WriteBuf() -{ - UInt32 writtenBorder = _wrPtr; - UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask; - FOR_VECTOR (i, _tempFilters) - { - CTempFilter *filter = _tempFilters[i]; - if (!filter) - continue; - if (filter->NextWindow) - { - filter->NextWindow = false; - continue; - } - UInt32 blockStart = filter->BlockStart; - UInt32 blockSize = filter->BlockSize; - if (((blockStart - writtenBorder) & kWindowMask) < writeSize) - { - if (writtenBorder != blockStart) - { - RINOK(WriteArea(writtenBorder, blockStart)) - writtenBorder = blockStart; - writeSize = (_winPos - writtenBorder) & kWindowMask; - } - if (blockSize <= writeSize) - { - UInt32 blockEnd = (blockStart + blockSize) & kWindowMask; - if (blockStart < blockEnd || blockEnd == 0) - _vm.SetMemory(0, _window + blockStart, blockSize); - else - { - UInt32 tailSize = kWindowSize - blockStart; - _vm.SetMemory(0, _window + blockStart, tailSize); - _vm.SetMemory(tailSize, _window, blockEnd); - } - NVm::CBlockRef outBlockRef; - ExecuteFilter(i, outBlockRef); - while (i + 1 < _tempFilters.Size()) - { - CTempFilter *nextFilter = _tempFilters[i + 1]; - if (!nextFilter - || nextFilter->BlockStart != blockStart - || nextFilter->BlockSize != outBlockRef.Size - || nextFilter->NextWindow) - break; - _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); - ExecuteFilter(++i, outBlockRef); - } - WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); - _writtenFileSize += outBlockRef.Size; - writtenBorder = blockEnd; - writeSize = (_winPos - writtenBorder) & kWindowMask; - } - else - { - for (unsigned j = i; j < _tempFilters.Size(); j++) - { - CTempFilter *filter2 = _tempFilters[j]; - if (filter2 && filter2->NextWindow) - filter2->NextWindow = false; - } - _wrPtr = writtenBorder; - return S_OK; // check it - } - } - } - - _wrPtr = _winPos; - return WriteArea(writtenBorder, _winPos); -} - -void CDecoder::InitFilters() -{ - _lastFilter = 0; - _numEmptyTempFilters = 0; - unsigned i; - for (i = 0; i < _tempFilters.Size(); i++) - delete _tempFilters[i]; - _tempFilters.Clear(); - for (i = 0; i < _filters.Size(); i++) - delete _filters[i]; - _filters.Clear(); -} - -static const unsigned MAX_UNPACK_FILTERS = 8192; - -bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize) -{ - CMemBitDecoder inp; - inp.Init(_vmData, codeSize); - - UInt32 filterIndex; - - if (firstByte & 0x80) - { - filterIndex = inp.ReadEncodedUInt32(); - if (filterIndex == 0) - InitFilters(); - else - filterIndex--; - } - else - filterIndex = _lastFilter; - - if (filterIndex > (UInt32)_filters.Size()) - return false; - _lastFilter = filterIndex; - bool newFilter = (filterIndex == (UInt32)_filters.Size()); - - CFilter *filter; - if (newFilter) - { - // check if too many filters - if (filterIndex > MAX_UNPACK_FILTERS) - return false; - filter = new CFilter; - _filters.Add(filter); - } - else - { - filter = _filters[filterIndex]; - filter->ExecCount++; - } - - if (_numEmptyTempFilters != 0) - { - const unsigned num = _tempFilters.Size(); - CTempFilter **tempFilters = _tempFilters.NonConstData(); - - unsigned w = 0; - for (unsigned i = 0; i < num; i++) - { - CTempFilter *tf = tempFilters[i]; - if (tf) - tempFilters[w++] = tf; - } - - _tempFilters.DeleteFrom(w); - _numEmptyTempFilters = 0; - } - - if (_tempFilters.Size() > MAX_UNPACK_FILTERS) - return false; - CTempFilter *tempFilter = new CTempFilter; - _tempFilters.Add(tempFilter); - tempFilter->FilterIndex = filterIndex; - - UInt32 blockStart = inp.ReadEncodedUInt32(); - if (firstByte & 0x40) - blockStart += 258; - tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask; - if (firstByte & 0x20) - filter->BlockSize = inp.ReadEncodedUInt32(); - tempFilter->BlockSize = filter->BlockSize; - tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart; - - memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR)); - tempFilter->InitR[3] = NVm::kGlobalOffset; - tempFilter->InitR[4] = tempFilter->BlockSize; - tempFilter->InitR[5] = filter->ExecCount; - if (firstByte & 0x10) - { - UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs); - for (unsigned i = 0; i < NVm::kNumGpRegs; i++) - if (initMask & (1 << i)) - tempFilter->InitR[i] = inp.ReadEncodedUInt32(); - } - - bool isOK = true; - if (newFilter) - { - UInt32 vmCodeSize = inp.ReadEncodedUInt32(); - if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0) - return false; - for (UInt32 i = 0; i < vmCodeSize; i++) - _vmCode[i] = (Byte)inp.ReadBits(8); - isOK = filter->PrepareProgram(_vmCode, vmCodeSize); - } - - { - Byte *globalData = &tempFilter->GlobalData[0]; - for (unsigned i = 0; i < NVm::kNumGpRegs; i++) - NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]); - NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize); - NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why? - NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], filter->ExecCount); - } - - if (firstByte & 8) - { - UInt32 dataSize = inp.ReadEncodedUInt32(); - if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize) - return false; - CRecordVector &globalData = tempFilter->GlobalData; - unsigned requiredSize = (unsigned)(dataSize + NVm::kFixedGlobalSize); - if (globalData.Size() < requiredSize) - globalData.ChangeSize_KeepData(requiredSize); - Byte *dest = &globalData[NVm::kFixedGlobalSize]; - for (UInt32 i = 0; i < dataSize; i++) - dest[i] = (Byte)inp.ReadBits(8); - } - - return isOK; -} - -bool CDecoder::ReadVmCodeLZ() -{ - UInt32 firstByte = ReadBits(8); - UInt32 len = (firstByte & 7) + 1; - if (len == 7) - len = ReadBits(8) + 7; - else if (len == 8) - len = ReadBits(16); - if (len > kVmDataSizeMax) - return false; - for (UInt32 i = 0; i < len; i++) - _vmData[i] = (Byte)ReadBits(8); - return AddVmCode(firstByte, len); -} - - -// int CDecoder::DecodePpmSymbol() { return Ppmd7a_DecodeSymbol(&_ppmd); } -#define DecodePpmSymbol() Ppmd7a_DecodeSymbol(&_ppmd) - - -bool CDecoder::ReadVmCodePPM() -{ - const int firstByte = DecodePpmSymbol(); - if (firstByte < 0) - return false; - UInt32 len = (firstByte & 7) + 1; - if (len == 7) - { - const int b1 = DecodePpmSymbol(); - if (b1 < 0) - return false; - len = (unsigned)b1 + 7; - } - else if (len == 8) - { - const int b1 = DecodePpmSymbol(); - if (b1 < 0) - return false; - const int b2 = DecodePpmSymbol(); - if (b2 < 0) - return false; - len = (unsigned)b1 * 256 + (unsigned)b2; - } - if (len > kVmDataSizeMax) - return false; - if (InputEofError_Fast()) - return false; - for (UInt32 i = 0; i < len; i++) - { - const int b = DecodePpmSymbol(); - if (b < 0) - return false; - _vmData[i] = (Byte)b; - } - return AddVmCode((unsigned)firstByte, len); -} - -#define RIF(x) { if (!(x)) return S_FALSE; } - -UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } - -// ---------- PPM ---------- - -HRESULT CDecoder::InitPPM() -{ - unsigned maxOrder = (unsigned)ReadBits(7); - - const bool reset = ((maxOrder & 0x20) != 0); - UInt32 maxMB = 0; - if (reset) - maxMB = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj); - else - { - if (PpmError || !Ppmd7_WasAllocated(&_ppmd)) - return S_FALSE; - } - if (maxOrder & 0x40) - PpmEscChar = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj); - - _ppmd.rc.dec.Stream = &m_InBitStream.IByteIn_obj; - m_InBitStream.IByteIn_obj.Read = Wrap_ReadBits8; - - Ppmd7a_RangeDec_Init(&_ppmd.rc.dec); - - m_InBitStream.IByteIn_obj.Read = Wrap_ReadByte; - - if (reset) - { - PpmError = true; - maxOrder = (maxOrder & 0x1F) + 1; - if (maxOrder > 16) - maxOrder = 16 + (maxOrder - 16) * 3; - if (maxOrder == 1) - { - Ppmd7_Free(&_ppmd, &g_BigAlloc); - return S_FALSE; - } - if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc)) - return E_OUTOFMEMORY; - Ppmd7_Init(&_ppmd, maxOrder); - PpmError = false; - } - return S_OK; -} - - -HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing) -{ - keepDecompressing = false; - if (PpmError) - return S_FALSE; - do - { - if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) - { - RINOK(WriteBuf()) - if (_writtenFileSize > _unpackSize) - { - keepDecompressing = false; - return S_OK; - } - } - if (InputEofError_Fast()) - return false; - const int c = DecodePpmSymbol(); - if (c < 0) - { - PpmError = true; - return S_FALSE; - } - if (c == PpmEscChar) - { - const int nextCh = DecodePpmSymbol(); - if (nextCh < 0) - { - PpmError = true; - return S_FALSE; - } - if (nextCh == 0) - return ReadTables(keepDecompressing); - if (nextCh == 2 || nextCh == -1) - return S_OK; - if (nextCh == 3) - { - if (!ReadVmCodePPM()) - { - PpmError = true; - return S_FALSE; - } - continue; - } - if (nextCh == 4 || nextCh == 5) - { - UInt32 dist = 0; - UInt32 len = 4; - if (nextCh == 4) - { - for (int i = 0; i < 3; i++) - { - const int c2 = DecodePpmSymbol(); - if (c2 < 0) - { - PpmError = true; - return S_FALSE; - } - dist = (dist << 8) + (Byte)c2; - } - dist++; - len += 28; - } - const int c2 = DecodePpmSymbol(); - if (c2 < 0) - { - PpmError = true; - return S_FALSE; - } - len += (unsigned)c2; - if (dist >= _lzSize) - return S_FALSE; - CopyBlock(dist, len); - num -= (Int32)len; - continue; - } - } - PutByte((Byte)c); - num--; - } - while (num >= 0); - keepDecompressing = true; - return S_OK; -} - -// ---------- LZ ---------- - -HRESULT CDecoder::ReadTables(bool &keepDecompressing) -{ - keepDecompressing = true; - m_InBitStream.BitDecoder.AlignToByte(); - if (ReadBits(1) != 0) - { - _lzMode = false; - return InitPPM(); - } - - TablesRead = false; - TablesOK = false; - - _lzMode = true; - PrevAlignBits = 0; - PrevAlignCount = 0; - - const unsigned kLevelTableSize = 20; - Byte levelLevels[kLevelTableSize]; - Byte lens[kTablesSizesSum]; - - if (ReadBits(1) == 0) - memset(m_LastLevels, 0, kTablesSizesSum); - - unsigned i; - - for (i = 0; i < kLevelTableSize; i++) - { - const UInt32 len = ReadBits(4); - if (len == 15) - { - UInt32 zeroCount = ReadBits(4); - if (zeroCount != 0) - { - zeroCount += 2; - while (zeroCount-- > 0 && i < kLevelTableSize) - levelLevels[i++]=0; - i--; - continue; - } - } - levelLevels[i] = (Byte)len; - } - - NHuffman::CDecoder256 m_LevelDecoder; - RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full)) - - i = 0; - - do - { - const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream.BitDecoder); - if (sym < 16) - { - lens[i] = Byte((sym + m_LastLevels[i]) & 15); - i++; - } -#if 0 - else if (sym > kLevelTableSize) - return S_FALSE; -#endif - else - { - unsigned num = ((sym /* - 16 */) & 1) * 4; - num += num + 3 + (unsigned)ReadBits(num + 3); - num += i; - if (num > kTablesSizesSum) - num = kTablesSizesSum; - Byte v = 0; - if (sym < 16 + 2) - { - if (i == 0) - return S_FALSE; - v = lens[(size_t)i - 1]; - } - do - lens[i++] = v; - while (i < num); - } - } - while (i < kTablesSizesSum); - - if (InputEofError()) - return S_FALSE; - - TablesRead = true; - - // original code has check here: - /* - if (InAddr > ReadTop) - { - keepDecompressing = false; - return true; - } - */ - - RIF(m_MainDecoder.Build(&lens[0])) - RIF(m_DistDecoder.Build(&lens[kMainTableSize])) - RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize])) - RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize])) - - memcpy(m_LastLevels, lens, kTablesSizesSum); - - TablesOK = true; - - return S_OK; -} - -/* -class CCoderReleaser -{ - CDecoder *m_Coder; -public: - CCoderReleaser(CDecoder *coder): m_Coder(coder) {} - ~CCoderReleaser() - { - m_Coder->ReleaseStreams(); - } -}; -*/ - -HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing) -{ - if (ReadBits(1) == 0) - { - // new file - keepDecompressing = false; - TablesRead = (ReadBits(1) == 0); - return S_OK; - } - TablesRead = false; - return ReadTables(keepDecompressing); -} - - -HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) -{ - UInt32 rep0 = _reps[0]; - UInt32 rep1 = _reps[1]; - UInt32 rep2 = _reps[2]; - UInt32 rep3 = _reps[3]; - UInt32 len = _lastLength; - for (;;) - { - if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) - { - RINOK(WriteBuf()) - if (_writtenFileSize > _unpackSize) - { - keepDecompressing = false; - return S_OK; - } - } - - if (InputEofError_Fast()) - return S_FALSE; - - unsigned sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder); - if (sym < 256) - { - PutByte((Byte)sym); - continue; - } - else if (sym == kSymbolReadTable) - { - RINOK(ReadEndOfBlock(keepDecompressing)) - break; - } - else if (sym == 257) - { - if (!ReadVmCodeLZ()) - return S_FALSE; - continue; - } - else if (sym == 258) - { - if (len == 0) - return S_FALSE; - } - else if (sym < kSymbolRep + 4) - { - if (sym != kSymbolRep) - { - UInt32 dist; - if (sym == kSymbolRep + 1) - dist = rep1; - else - { - if (sym == kSymbolRep + 2) - dist = rep2; - else - { - dist = rep3; - rep3 = rep2; - } - rep2 = rep1; - } - rep1 = rep0; - rep0 = dist; - } - - const unsigned sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder); - if (sym2 >= kLenTableSize) - return S_FALSE; - len = 2 + sym2; - if (sym2 >= 8) - { - const unsigned num = (sym2 >> 2) - 1; - len = 2 + (UInt32)((4 + (sym2 & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num); - } - } - else - { - rep3 = rep2; - rep2 = rep1; - rep1 = rep0; - if (sym < 271) - { - sym -= 263; - rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits_upto8(kLen2DistDirectBits[sym]); - len = 2; - } - else if (sym < 299) - { - sym -= 271; - len = kNormalMatchMinLen + sym; - if (sym >= 8) - { - const unsigned num = (sym >> 2) - 1; - len = kNormalMatchMinLen + (UInt32)((4 + (sym & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num); - } - const unsigned sym2 = m_DistDecoder.Decode(&m_InBitStream.BitDecoder); - if (sym2 >= kDistTableSize) - return S_FALSE; - rep0 = kDistStart[sym2]; - unsigned numBits = kDistDirectBits[sym2]; - if (sym2 >= (kNumAlignBits * 2) + 2) - { - if (numBits > kNumAlignBits) - rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits); - if (PrevAlignCount > 0) - { - PrevAlignCount--; - rep0 += PrevAlignBits; - } - else - { - const unsigned sym3 = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder); - if (sym3 < (1 << kNumAlignBits)) - { - rep0 += sym3; - PrevAlignBits = sym3; - } - else if (sym3 == (1 << kNumAlignBits)) - { - PrevAlignCount = kNumAlignReps; - rep0 += PrevAlignBits; - } - else - return S_FALSE; - } - } - else - rep0 += m_InBitStream.BitDecoder.ReadBits_upto8(numBits); - len += ((UInt32)(kDistLimit4 - rep0) >> 31) + ((UInt32)(kDistLimit3 - rep0) >> 31); - } - else - return S_FALSE; - } - if (rep0 >= _lzSize) - return S_FALSE; - CopyBlock(rep0, len); - } - _reps[0] = rep0; - _reps[1] = rep1; - _reps[2] = rep2; - _reps[3] = rep3; - _lastLength = len; - - return S_OK; -} - - -HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) -{ - _writtenFileSize = 0; - _unsupportedFilter = false; - - if (!_isSolid) - { - _lzSize = 0; - _winPos = 0; - _wrPtr = 0; - for (unsigned i = 0; i < kNumReps; i++) - _reps[i] = 0; - _lastLength = 0; - memset(m_LastLevels, 0, kTablesSizesSum); - TablesRead = false; - PpmEscChar = 2; - PpmError = true; - InitFilters(); - // _errorMode = false; - } - - /* - if (_errorMode) - return S_FALSE; - */ - - if (!_isSolid || !TablesRead) - { - bool keepDecompressing; - RINOK(ReadTables(keepDecompressing)) - if (!keepDecompressing) - { - _solidAllowed = true; - return S_OK; - } - } - - for (;;) - { - bool keepDecompressing; - if (_lzMode) - { - if (!TablesOK) - return S_FALSE; - RINOK(DecodeLZ(keepDecompressing)) - } - else - { - RINOK(DecodePPM(1 << 18, keepDecompressing)) - } - - if (InputEofError()) - return S_FALSE; - - const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)) - if (!keepDecompressing) - break; - } - - _solidAllowed = true; - - RINOK(WriteBuf()) - const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)) - if (_writtenFileSize < _unpackSize) - return S_FALSE; - - if (_unsupportedFilter) - return E_NOTIMPL; - - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try - { - if (!inSize) - return E_INVALIDARG; - - if (_isSolid && !_solidAllowed) - return S_FALSE; - _solidAllowed = false; - - if (!_vmData) - { - _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax); - if (!_vmData) - return E_OUTOFMEMORY; - _vmCode = _vmData + kVmDataSizeMax; - } - - if (!_window) - { - _window = (Byte *)::MidAlloc(kWindowSize); - if (!_window) - return E_OUTOFMEMORY; - } - if (!m_InBitStream.BitDecoder.Create(1 << 20)) - return E_OUTOFMEMORY; - if (!_vm.Create()) - return E_OUTOFMEMORY; - - - m_InBitStream.BitDecoder.SetStream(inStream); - m_InBitStream.BitDecoder.Init(); - _outStream = outStream; - - // CCoderReleaser coderReleaser(this); - _unpackSize = outSize ? *outSize : (UInt64)(Int64)-1; - return CodeReal(progress); - } - catch(const CInBufferException &e) { /* _errorMode = true; */ return e.ErrorCode; } - catch(...) { /* _errorMode = true; */ return S_FALSE; } - // CNewException is possible here. But probably CNewException is caused - // by error in data stream. -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - if (size < 1) - return E_INVALIDARG; - _isSolid = ((data[0] & 1) != 0); - return S_OK; -} - -}} +// Rar3Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "Rar3Decoder.h" + +namespace NCompress { +namespace NRar3 { + +static const UInt32 kNumAlignReps = 15; + +static const unsigned kSymbolReadTable = 256; +static const unsigned kSymbolRep = 259; + +static const Byte kDistDirectBits[kDistTableSize] = + {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 18,18,18,18,18,18,18,18,18,18,18,18}; + +static const Byte kLen2DistStarts[kNumLen2Symbols] = {0,4,8,16,32,64,128,192}; +static const Byte kLen2DistDirectBits[kNumLen2Symbols] = {2,2,3, 4, 5, 6, 6, 6}; + +static const UInt32 kDistLimit3 = 0x2000 - 2; +static const UInt32 kDistLimit4 = 0x40000 - 2; + +static const UInt32 kNormalMatchMinLen = 3; + +static const UInt32 kVmDataSizeMax = 1 << 16; +static const UInt32 kVmCodeSizeMax = 1 << 16; + +extern "C" { + +static Byte Wrap_ReadByte(IByteInPtr pp) throw() +{ + CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj); + return p->BitDecoder.Stream.ReadByte(); +} + +static Byte Wrap_ReadBits8(IByteInPtr pp) throw() +{ + CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj); + return (Byte)p->BitDecoder.ReadByteFromAligned(); +} + +} + + +CDecoder::CDecoder(): + _isSolid(false), + _solidAllowed(false), + _window(NULL), + _winPos(0), + _wrPtr(0), + _lzSize(0), + _writtenFileSize(0), + _vmData(NULL), + _vmCode(NULL) +{ + Ppmd7_Construct(&_ppmd); + + UInt32 start = 0; + for (UInt32 i = 0; i < kDistTableSize; i++) + { + kDistStart[i] = start; + start += ((UInt32)1 << kDistDirectBits[i]); + } +} + +CDecoder::~CDecoder() +{ + InitFilters(); + ::MidFree(_vmData); + ::MidFree(_window); + Ppmd7_Free(&_ppmd, &g_BigAlloc); +} + +HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size) +{ + return WriteStream(_outStream, data, size); +} + +HRESULT CDecoder::WriteData(const Byte *data, UInt32 size) +{ + HRESULT res = S_OK; + if (_writtenFileSize < _unpackSize) + { + UInt32 curSize = size; + UInt64 remain = _unpackSize - _writtenFileSize; + if (remain < curSize) + curSize = (UInt32)remain; + res = WriteDataToStream(data, curSize); + } + _writtenFileSize += size; + return res; +} + +HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) +{ + if (startPtr <= endPtr) + return WriteData(_window + startPtr, endPtr - startPtr); + RINOK(WriteData(_window + startPtr, kWindowSize - startPtr)) + return WriteData(_window, endPtr); +} + +void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef) +{ + CTempFilter *tempFilter = _tempFilters[tempFilterIndex]; + tempFilter->InitR[6] = (UInt32)_writtenFileSize; + NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize); + NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32)); + CFilter *filter = _filters[tempFilter->FilterIndex]; + if (!filter->IsSupported) + _unsupportedFilter = true; + if (!_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData)) + _unsupportedFilter = true; + delete tempFilter; + _tempFilters[tempFilterIndex] = NULL; + _numEmptyTempFilters++; +} + +HRESULT CDecoder::WriteBuf() +{ + UInt32 writtenBorder = _wrPtr; + UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask; + FOR_VECTOR (i, _tempFilters) + { + CTempFilter *filter = _tempFilters[i]; + if (!filter) + continue; + if (filter->NextWindow) + { + filter->NextWindow = false; + continue; + } + UInt32 blockStart = filter->BlockStart; + UInt32 blockSize = filter->BlockSize; + if (((blockStart - writtenBorder) & kWindowMask) < writeSize) + { + if (writtenBorder != blockStart) + { + RINOK(WriteArea(writtenBorder, blockStart)) + writtenBorder = blockStart; + writeSize = (_winPos - writtenBorder) & kWindowMask; + } + if (blockSize <= writeSize) + { + UInt32 blockEnd = (blockStart + blockSize) & kWindowMask; + if (blockStart < blockEnd || blockEnd == 0) + _vm.SetMemory(0, _window + blockStart, blockSize); + else + { + UInt32 tailSize = kWindowSize - blockStart; + _vm.SetMemory(0, _window + blockStart, tailSize); + _vm.SetMemory(tailSize, _window, blockEnd); + } + NVm::CBlockRef outBlockRef; + ExecuteFilter(i, outBlockRef); + while (i + 1 < _tempFilters.Size()) + { + CTempFilter *nextFilter = _tempFilters[i + 1]; + if (!nextFilter + || nextFilter->BlockStart != blockStart + || nextFilter->BlockSize != outBlockRef.Size + || nextFilter->NextWindow) + break; + _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); + ExecuteFilter(++i, outBlockRef); + } + WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); + _writtenFileSize += outBlockRef.Size; + writtenBorder = blockEnd; + writeSize = (_winPos - writtenBorder) & kWindowMask; + } + else + { + for (unsigned j = i; j < _tempFilters.Size(); j++) + { + CTempFilter *filter2 = _tempFilters[j]; + if (filter2 && filter2->NextWindow) + filter2->NextWindow = false; + } + _wrPtr = writtenBorder; + return S_OK; // check it + } + } + } + + _wrPtr = _winPos; + return WriteArea(writtenBorder, _winPos); +} + +void CDecoder::InitFilters() +{ + _lastFilter = 0; + _numEmptyTempFilters = 0; + unsigned i; + for (i = 0; i < _tempFilters.Size(); i++) + delete _tempFilters[i]; + _tempFilters.Clear(); + for (i = 0; i < _filters.Size(); i++) + delete _filters[i]; + _filters.Clear(); +} + +static const unsigned MAX_UNPACK_FILTERS = 8192; + +bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize) +{ + CMemBitDecoder inp; + inp.Init(_vmData, codeSize); + + UInt32 filterIndex; + + if (firstByte & 0x80) + { + filterIndex = inp.ReadEncodedUInt32(); + if (filterIndex == 0) + InitFilters(); + else + filterIndex--; + } + else + filterIndex = _lastFilter; + + if (filterIndex > (UInt32)_filters.Size()) + return false; + _lastFilter = filterIndex; + bool newFilter = (filterIndex == (UInt32)_filters.Size()); + + CFilter *filter; + if (newFilter) + { + // check if too many filters + if (filterIndex > MAX_UNPACK_FILTERS) + return false; + filter = new CFilter; + _filters.Add(filter); + } + else + { + filter = _filters[filterIndex]; + filter->ExecCount++; + } + + if (_numEmptyTempFilters != 0) + { + const unsigned num = _tempFilters.Size(); + CTempFilter **tempFilters = _tempFilters.NonConstData(); + + unsigned w = 0; + for (unsigned i = 0; i < num; i++) + { + CTempFilter *tf = tempFilters[i]; + if (tf) + tempFilters[w++] = tf; + } + + _tempFilters.DeleteFrom(w); + _numEmptyTempFilters = 0; + } + + if (_tempFilters.Size() > MAX_UNPACK_FILTERS) + return false; + CTempFilter *tempFilter = new CTempFilter; + _tempFilters.Add(tempFilter); + tempFilter->FilterIndex = filterIndex; + + UInt32 blockStart = inp.ReadEncodedUInt32(); + if (firstByte & 0x40) + blockStart += 258; + tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask; + if (firstByte & 0x20) + filter->BlockSize = inp.ReadEncodedUInt32(); + tempFilter->BlockSize = filter->BlockSize; + tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart; + + memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR)); + tempFilter->InitR[3] = NVm::kGlobalOffset; + tempFilter->InitR[4] = tempFilter->BlockSize; + tempFilter->InitR[5] = filter->ExecCount; + if (firstByte & 0x10) + { + UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs); + for (unsigned i = 0; i < NVm::kNumGpRegs; i++) + if (initMask & (1 << i)) + tempFilter->InitR[i] = inp.ReadEncodedUInt32(); + } + + bool isOK = true; + if (newFilter) + { + UInt32 vmCodeSize = inp.ReadEncodedUInt32(); + if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0) + return false; + for (UInt32 i = 0; i < vmCodeSize; i++) + _vmCode[i] = (Byte)inp.ReadBits(8); + isOK = filter->PrepareProgram(_vmCode, vmCodeSize); + } + + { + Byte *globalData = &tempFilter->GlobalData[0]; + for (unsigned i = 0; i < NVm::kNumGpRegs; i++) + NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]); + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize); + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why? + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], filter->ExecCount); + } + + if (firstByte & 8) + { + UInt32 dataSize = inp.ReadEncodedUInt32(); + if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize) + return false; + CRecordVector &globalData = tempFilter->GlobalData; + unsigned requiredSize = (unsigned)(dataSize + NVm::kFixedGlobalSize); + if (globalData.Size() < requiredSize) + globalData.ChangeSize_KeepData(requiredSize); + Byte *dest = &globalData[NVm::kFixedGlobalSize]; + for (UInt32 i = 0; i < dataSize; i++) + dest[i] = (Byte)inp.ReadBits(8); + } + + return isOK; +} + +bool CDecoder::ReadVmCodeLZ() +{ + UInt32 firstByte = ReadBits(8); + UInt32 len = (firstByte & 7) + 1; + if (len == 7) + len = ReadBits(8) + 7; + else if (len == 8) + len = ReadBits(16); + if (len > kVmDataSizeMax) + return false; + for (UInt32 i = 0; i < len; i++) + _vmData[i] = (Byte)ReadBits(8); + return AddVmCode(firstByte, len); +} + + +// int CDecoder::DecodePpmSymbol() { return Ppmd7a_DecodeSymbol(&_ppmd); } +#define DecodePpmSymbol() Ppmd7a_DecodeSymbol(&_ppmd) + + +bool CDecoder::ReadVmCodePPM() +{ + const int firstByte = DecodePpmSymbol(); + if (firstByte < 0) + return false; + UInt32 len = (firstByte & 7) + 1; + if (len == 7) + { + const int b1 = DecodePpmSymbol(); + if (b1 < 0) + return false; + len = (unsigned)b1 + 7; + } + else if (len == 8) + { + const int b1 = DecodePpmSymbol(); + if (b1 < 0) + return false; + const int b2 = DecodePpmSymbol(); + if (b2 < 0) + return false; + len = (unsigned)b1 * 256 + (unsigned)b2; + } + if (len > kVmDataSizeMax) + return false; + if (InputEofError_Fast()) + return false; + for (UInt32 i = 0; i < len; i++) + { + const int b = DecodePpmSymbol(); + if (b < 0) + return false; + _vmData[i] = (Byte)b; + } + return AddVmCode((unsigned)firstByte, len); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } + +// ---------- PPM ---------- + +HRESULT CDecoder::InitPPM() +{ + unsigned maxOrder = (unsigned)ReadBits(7); + + const bool reset = ((maxOrder & 0x20) != 0); + UInt32 maxMB = 0; + if (reset) + maxMB = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj); + else + { + if (PpmError || !Ppmd7_WasAllocated(&_ppmd)) + return S_FALSE; + } + if (maxOrder & 0x40) + PpmEscChar = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj); + + _ppmd.rc.dec.Stream = &m_InBitStream.IByteIn_obj; + m_InBitStream.IByteIn_obj.Read = Wrap_ReadBits8; + + Ppmd7a_RangeDec_Init(&_ppmd.rc.dec); + + m_InBitStream.IByteIn_obj.Read = Wrap_ReadByte; + + if (reset) + { + PpmError = true; + maxOrder = (maxOrder & 0x1F) + 1; + if (maxOrder > 16) + maxOrder = 16 + (maxOrder - 16) * 3; + if (maxOrder == 1) + { + Ppmd7_Free(&_ppmd, &g_BigAlloc); + return S_FALSE; + } + if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + Ppmd7_Init(&_ppmd, maxOrder); + PpmError = false; + } + return S_OK; +} + + +HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing) +{ + keepDecompressing = false; + if (PpmError) + return S_FALSE; + do + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()) + if (_writtenFileSize > _unpackSize) + { + keepDecompressing = false; + return S_OK; + } + } + if (InputEofError_Fast()) + return false; + const int c = DecodePpmSymbol(); + if (c < 0) + { + PpmError = true; + return S_FALSE; + } + if (c == PpmEscChar) + { + const int nextCh = DecodePpmSymbol(); + if (nextCh < 0) + { + PpmError = true; + return S_FALSE; + } + if (nextCh == 0) + return ReadTables(keepDecompressing); + if (nextCh == 2 || nextCh == -1) + return S_OK; + if (nextCh == 3) + { + if (!ReadVmCodePPM()) + { + PpmError = true; + return S_FALSE; + } + continue; + } + if (nextCh == 4 || nextCh == 5) + { + UInt32 dist = 0; + UInt32 len = 4; + if (nextCh == 4) + { + for (int i = 0; i < 3; i++) + { + const int c2 = DecodePpmSymbol(); + if (c2 < 0) + { + PpmError = true; + return S_FALSE; + } + dist = (dist << 8) + (Byte)c2; + } + dist++; + len += 28; + } + const int c2 = DecodePpmSymbol(); + if (c2 < 0) + { + PpmError = true; + return S_FALSE; + } + len += (unsigned)c2; + if (dist >= _lzSize) + return S_FALSE; + CopyBlock(dist, len); + num -= (Int32)len; + continue; + } + } + PutByte((Byte)c); + num--; + } + while (num >= 0); + keepDecompressing = true; + return S_OK; +} + +// ---------- LZ ---------- + +HRESULT CDecoder::ReadTables(bool &keepDecompressing) +{ + keepDecompressing = true; + m_InBitStream.BitDecoder.AlignToByte(); + if (ReadBits(1) != 0) + { + _lzMode = false; + return InitPPM(); + } + + TablesRead = false; + TablesOK = false; + + _lzMode = true; + PrevAlignBits = 0; + PrevAlignCount = 0; + + const unsigned kLevelTableSize = 20; + Byte levelLevels[kLevelTableSize]; + Byte lens[kTablesSizesSum]; + + if (ReadBits(1) == 0) + memset(m_LastLevels, 0, kTablesSizesSum); + + unsigned i; + + for (i = 0; i < kLevelTableSize; i++) + { + const UInt32 len = ReadBits(4); + if (len == 15) + { + UInt32 zeroCount = ReadBits(4); + if (zeroCount != 0) + { + zeroCount += 2; + while (zeroCount-- > 0 && i < kLevelTableSize) + levelLevels[i++]=0; + i--; + continue; + } + } + levelLevels[i] = (Byte)len; + } + + NHuffman::CDecoder256 m_LevelDecoder; + RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full)) + + i = 0; + + do + { + const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream.BitDecoder); + if (sym < 16) + { + lens[i] = Byte((sym + m_LastLevels[i]) & 15); + i++; + } +#if 0 + else if (sym > kLevelTableSize) + return S_FALSE; +#endif + else + { + unsigned num = ((sym /* - 16 */) & 1) * 4; + num += num + 3 + (unsigned)ReadBits(num + 3); + num += i; + if (num > kTablesSizesSum) + num = kTablesSizesSum; + Byte v = 0; + if (sym < 16 + 2) + { + if (i == 0) + return S_FALSE; + v = lens[(size_t)i - 1]; + } + do + lens[i++] = v; + while (i < num); + } + } + while (i < kTablesSizesSum); + + if (InputEofError()) + return S_FALSE; + + TablesRead = true; + + // original code has check here: + /* + if (InAddr > ReadTop) + { + keepDecompressing = false; + return true; + } + */ + + RIF(m_MainDecoder.Build(&lens[0])) + RIF(m_DistDecoder.Build(&lens[kMainTableSize])) + RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize])) + RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize])) + + memcpy(m_LastLevels, lens, kTablesSizesSum); + + TablesOK = true; + + return S_OK; +} + +/* +class CCoderReleaser +{ + CDecoder *m_Coder; +public: + CCoderReleaser(CDecoder *coder): m_Coder(coder) {} + ~CCoderReleaser() + { + m_Coder->ReleaseStreams(); + } +}; +*/ + +HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing) +{ + if (ReadBits(1) == 0) + { + // new file + keepDecompressing = false; + TablesRead = (ReadBits(1) == 0); + return S_OK; + } + TablesRead = false; + return ReadTables(keepDecompressing); +} + + +HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) +{ + UInt32 rep0 = _reps[0]; + UInt32 rep1 = _reps[1]; + UInt32 rep2 = _reps[2]; + UInt32 rep3 = _reps[3]; + UInt32 len = _lastLength; + for (;;) + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()) + if (_writtenFileSize > _unpackSize) + { + keepDecompressing = false; + return S_OK; + } + } + + if (InputEofError_Fast()) + return S_FALSE; + + unsigned sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym < 256) + { + PutByte((Byte)sym); + continue; + } + else if (sym == kSymbolReadTable) + { + RINOK(ReadEndOfBlock(keepDecompressing)) + break; + } + else if (sym == 257) + { + if (!ReadVmCodeLZ()) + return S_FALSE; + continue; + } + else if (sym == 258) + { + if (len == 0) + return S_FALSE; + } + else if (sym < kSymbolRep + 4) + { + if (sym != kSymbolRep) + { + UInt32 dist; + if (sym == kSymbolRep + 1) + dist = rep1; + else + { + if (sym == kSymbolRep + 2) + dist = rep2; + else + { + dist = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = dist; + } + + const unsigned sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym2 >= kLenTableSize) + return S_FALSE; + len = 2 + sym2; + if (sym2 >= 8) + { + const unsigned num = (sym2 >> 2) - 1; + len = 2 + (UInt32)((4 + (sym2 & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num); + } + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + if (sym < 271) + { + sym -= 263; + rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits_upto8(kLen2DistDirectBits[sym]); + len = 2; + } + else if (sym < 299) + { + sym -= 271; + len = kNormalMatchMinLen + sym; + if (sym >= 8) + { + const unsigned num = (sym >> 2) - 1; + len = kNormalMatchMinLen + (UInt32)((4 + (sym & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num); + } + const unsigned sym2 = m_DistDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym2 >= kDistTableSize) + return S_FALSE; + rep0 = kDistStart[sym2]; + unsigned numBits = kDistDirectBits[sym2]; + if (sym2 >= (kNumAlignBits * 2) + 2) + { + if (numBits > kNumAlignBits) + rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits); + if (PrevAlignCount > 0) + { + PrevAlignCount--; + rep0 += PrevAlignBits; + } + else + { + const unsigned sym3 = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym3 < (1 << kNumAlignBits)) + { + rep0 += sym3; + PrevAlignBits = sym3; + } + else if (sym3 == (1 << kNumAlignBits)) + { + PrevAlignCount = kNumAlignReps; + rep0 += PrevAlignBits; + } + else + return S_FALSE; + } + } + else + rep0 += m_InBitStream.BitDecoder.ReadBits_upto8(numBits); + len += ((UInt32)(kDistLimit4 - rep0) >> 31) + ((UInt32)(kDistLimit3 - rep0) >> 31); + } + else + return S_FALSE; + } + if (rep0 >= _lzSize) + return S_FALSE; + CopyBlock(rep0, len); + } + _reps[0] = rep0; + _reps[1] = rep1; + _reps[2] = rep2; + _reps[3] = rep3; + _lastLength = len; + + return S_OK; +} + + +HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) +{ + _writtenFileSize = 0; + _unsupportedFilter = false; + + if (!_isSolid) + { + _lzSize = 0; + _winPos = 0; + _wrPtr = 0; + for (unsigned i = 0; i < kNumReps; i++) + _reps[i] = 0; + _lastLength = 0; + memset(m_LastLevels, 0, kTablesSizesSum); + TablesRead = false; + PpmEscChar = 2; + PpmError = true; + InitFilters(); + // _errorMode = false; + } + + /* + if (_errorMode) + return S_FALSE; + */ + + if (!_isSolid || !TablesRead) + { + bool keepDecompressing; + RINOK(ReadTables(keepDecompressing)) + if (!keepDecompressing) + { + _solidAllowed = true; + return S_OK; + } + } + + for (;;) + { + bool keepDecompressing; + if (_lzMode) + { + if (!TablesOK) + return S_FALSE; + RINOK(DecodeLZ(keepDecompressing)) + } + else + { + RINOK(DecodePPM(1 << 18, keepDecompressing)) + } + + if (InputEofError()) + return S_FALSE; + + const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)) + if (!keepDecompressing) + break; + } + + _solidAllowed = true; + + RINOK(WriteBuf()) + const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)) + if (_writtenFileSize < _unpackSize) + return S_FALSE; + + if (_unsupportedFilter) + return E_NOTIMPL; + + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try + { + if (!inSize) + return E_INVALIDARG; + + if (_isSolid && !_solidAllowed) + return S_FALSE; + _solidAllowed = false; + + if (!_vmData) + { + _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax); + if (!_vmData) + return E_OUTOFMEMORY; + _vmCode = _vmData + kVmDataSizeMax; + } + + if (!_window) + { + _window = (Byte *)::MidAlloc(kWindowSize); + if (!_window) + return E_OUTOFMEMORY; + } + if (!m_InBitStream.BitDecoder.Create(1 << 20)) + return E_OUTOFMEMORY; + if (!_vm.Create()) + return E_OUTOFMEMORY; + + + m_InBitStream.BitDecoder.SetStream(inStream); + m_InBitStream.BitDecoder.Init(); + _outStream = outStream; + + // CCoderReleaser coderReleaser(this); + _unpackSize = outSize ? *outSize : (UInt64)(Int64)-1; + return CodeReal(progress); + } + catch(const CInBufferException &e) { /* _errorMode = true; */ return e.ErrorCode; } + catch(...) { /* _errorMode = true; */ return S_FALSE; } + // CNewException is possible here. But probably CNewException is caused + // by error in data stream. +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar3Decoder.h b/CPP/7zip/Compress/Rar3Decoder.h index a3ab09430..48fc21240 100644 --- a/CPP/7zip/Compress/Rar3Decoder.h +++ b/CPP/7zip/Compress/Rar3Decoder.h @@ -1,283 +1,283 @@ -// Rar3Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ - -#ifndef ZIP7_INC_COMPRESS_RAR3_DECODER_H -#define ZIP7_INC_COMPRESS_RAR3_DECODER_H - -#include "../../../C/Ppmd7.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "../Common/InBuffer.h" - -#include "BitmDecoder.h" -#include "HuffmanDecoder.h" -#include "Rar3Vm.h" - -namespace NCompress { -namespace NRar3 { - -const unsigned kNumHuffmanBits = 15; - -const UInt32 kWindowSize = 1 << 22; -const UInt32 kWindowMask = kWindowSize - 1; - -const unsigned kNumReps = 4; -const unsigned kNumLen2Symbols = 8; -const unsigned kLenTableSize = 28; -const unsigned kMainTableSize = 256 + 3 + kNumReps + kNumLen2Symbols + kLenTableSize; -const unsigned kDistTableSize = 60; - -const unsigned kNumAlignBits = 4; -const unsigned kAlignTableSize = (1 << kNumAlignBits) + 1; - -const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; - -class CBitDecoder -{ - UInt32 _value; - unsigned _bitPos; -public: - CInBuffer Stream; - - bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } - void SetStream(ISequentialInStream *inStream) { Stream.SetStream(inStream);} - - void Init() - { - Stream.Init(); - _bitPos = 0; - _value = 0; - } - - bool ExtraBitsWereRead() const - { - return (Stream.NumExtraBytes > 4 || _bitPos < (Stream.NumExtraBytes << 3)); - } - - UInt64 GetProcessedSize() const { return Stream.GetProcessedSize() - (_bitPos >> 3); } - - void AlignToByte() - { - _bitPos &= ~(unsigned)7; - _value = _value & ((1 << _bitPos) - 1); - } - - Z7_FORCE_INLINE - UInt32 GetValue(unsigned numBits) - { - if (_bitPos < numBits) - { - _bitPos += 8; - _value = (_value << 8) | Stream.ReadByte(); - if (_bitPos < numBits) - { - _bitPos += 8; - _value = (_value << 8) | Stream.ReadByte(); - } - } - return _value >> (_bitPos - numBits); - } - - Z7_FORCE_INLINE - UInt32 GetValue_InHigh32bits() - { - return GetValue(kNumHuffmanBits) << (32 - kNumHuffmanBits); - } - - - Z7_FORCE_INLINE - void MovePos(unsigned numBits) - { - _bitPos -= numBits; - _value = _value & ((1 << _bitPos) - 1); - } - - UInt32 ReadBits(unsigned numBits) - { - const UInt32 res = GetValue(numBits); - MovePos(numBits); - return res; - } - - UInt32 ReadBits_upto8(unsigned numBits) - { - if (_bitPos < numBits) - { - _bitPos += 8; - _value = (_value << 8) | Stream.ReadByte(); - } - _bitPos -= numBits; - const UInt32 res = _value >> _bitPos; - _value = _value & ((1 << _bitPos) - 1); - return res; - } - - Byte ReadByteFromAligned() - { - if (_bitPos == 0) - return Stream.ReadByte(); - const unsigned bitsPos = _bitPos - 8; - const Byte b = (Byte)(_value >> bitsPos); - _value = _value & ((1 << bitsPos) - 1); - _bitPos = bitsPos; - return b; - } -}; - - -struct CByteIn -{ - IByteIn IByteIn_obj; - CBitDecoder BitDecoder; -}; - - -struct CFilter: public NVm::CProgram -{ - CRecordVector GlobalData; - UInt32 BlockStart; - UInt32 BlockSize; - UInt32 ExecCount; - - CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {} -}; - -struct CTempFilter: public NVm::CProgramInitState -{ - UInt32 BlockStart; - UInt32 BlockSize; - bool NextWindow; - - UInt32 FilterIndex; - - CTempFilter() - { - // all filters must contain at least FixedGlobal block - AllocateEmptyFixedGlobal(); - } -}; - - -Z7_CLASS_IMP_NOQIB_2( - CDecoder - , ICompressCoder - , ICompressSetDecoderProperties2 -) - bool _isSolid; - bool _solidAllowed; - // bool _errorMode; - - bool _lzMode; - bool _unsupportedFilter; - - CByteIn m_InBitStream; - Byte *_window; - UInt32 _winPos; - UInt32 _wrPtr; - UInt64 _lzSize; - UInt64 _unpackSize; - UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written - ISequentialOutStream *_outStream; - - NHuffman::CDecoder m_MainDecoder; - UInt32 kDistStart[kDistTableSize]; - NHuffman::CDecoder256 m_DistDecoder; - NHuffman::CDecoder256 m_AlignDecoder; - NHuffman::CDecoder256 m_LenDecoder; - - UInt32 _reps[kNumReps]; - UInt32 _lastLength; - - Byte m_LastLevels[kTablesSizesSum]; - - Byte *_vmData; - Byte *_vmCode; - NVm::CVm _vm; - CRecordVector _filters; - CRecordVector _tempFilters; - unsigned _numEmptyTempFilters; - UInt32 _lastFilter; - - UInt32 PrevAlignBits; - UInt32 PrevAlignCount; - - bool TablesRead; - bool TablesOK; - bool PpmError; - - int PpmEscChar; - CPpmd7 _ppmd; - - HRESULT WriteDataToStream(const Byte *data, UInt32 size); - HRESULT WriteData(const Byte *data, UInt32 size); - HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr); - void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef); - HRESULT WriteBuf(); - - void InitFilters(); - bool AddVmCode(UInt32 firstByte, UInt32 codeSize); - bool ReadVmCodeLZ(); - bool ReadVmCodePPM(); - - UInt32 ReadBits(unsigned numBits); - - HRESULT InitPPM(); - // int DecodePpmSymbol(); - HRESULT DecodePPM(Int32 num, bool &keepDecompressing); - - HRESULT ReadTables(bool &keepDecompressing); - HRESULT ReadEndOfBlock(bool &keepDecompressing); - HRESULT DecodeLZ(bool &keepDecompressing); - HRESULT CodeReal(ICompressProgressInfo *progress); - - bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); } - bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); } - - void CopyBlock(UInt32 dist, UInt32 len) - { - _lzSize += len; - UInt32 pos = (_winPos - dist - 1) & kWindowMask; - Byte *window = _window; - UInt32 winPos = _winPos; - if (kWindowSize - winPos > len && kWindowSize - pos > len) - { - const Byte *src = window + pos; - Byte *dest = window + winPos; - _winPos += len; - do - *dest++ = *src++; - while (--len != 0); - return; - } - do - { - window[winPos] = window[pos]; - winPos = (winPos + 1) & kWindowMask; - pos = (pos + 1) & kWindowMask; - } - while (--len != 0); - _winPos = winPos; - } - - void PutByte(Byte b) - { - const UInt32 wp = _winPos; - _window[wp] = b; - _winPos = (wp + 1) & kWindowMask; - _lzSize++; - } - -public: - CDecoder(); - ~CDecoder(); -}; - -}} - -#endif +// Rar3Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef ZIP7_INC_COMPRESS_RAR3_DECODER_H +#define ZIP7_INC_COMPRESS_RAR3_DECODER_H + +#include "../../../C/Ppmd7.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "Rar3Vm.h" + +namespace NCompress { +namespace NRar3 { + +const unsigned kNumHuffmanBits = 15; + +const UInt32 kWindowSize = 1 << 22; +const UInt32 kWindowMask = kWindowSize - 1; + +const unsigned kNumReps = 4; +const unsigned kNumLen2Symbols = 8; +const unsigned kLenTableSize = 28; +const unsigned kMainTableSize = 256 + 3 + kNumReps + kNumLen2Symbols + kLenTableSize; +const unsigned kDistTableSize = 60; + +const unsigned kNumAlignBits = 4; +const unsigned kAlignTableSize = (1 << kNumAlignBits) + 1; + +const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; + +class CBitDecoder +{ + UInt32 _value; + unsigned _bitPos; +public: + CInBuffer Stream; + + bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } + void SetStream(ISequentialInStream *inStream) { Stream.SetStream(inStream);} + + void Init() + { + Stream.Init(); + _bitPos = 0; + _value = 0; + } + + bool ExtraBitsWereRead() const + { + return (Stream.NumExtraBytes > 4 || _bitPos < (Stream.NumExtraBytes << 3)); + } + + UInt64 GetProcessedSize() const { return Stream.GetProcessedSize() - (_bitPos >> 3); } + + void AlignToByte() + { + _bitPos &= ~(unsigned)7; + _value = _value & ((1 << _bitPos) - 1); + } + + Z7_FORCE_INLINE + UInt32 GetValue(unsigned numBits) + { + if (_bitPos < numBits) + { + _bitPos += 8; + _value = (_value << 8) | Stream.ReadByte(); + if (_bitPos < numBits) + { + _bitPos += 8; + _value = (_value << 8) | Stream.ReadByte(); + } + } + return _value >> (_bitPos - numBits); + } + + Z7_FORCE_INLINE + UInt32 GetValue_InHigh32bits() + { + return GetValue(kNumHuffmanBits) << (32 - kNumHuffmanBits); + } + + + Z7_FORCE_INLINE + void MovePos(unsigned numBits) + { + _bitPos -= numBits; + _value = _value & ((1 << _bitPos) - 1); + } + + UInt32 ReadBits(unsigned numBits) + { + const UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; + } + + UInt32 ReadBits_upto8(unsigned numBits) + { + if (_bitPos < numBits) + { + _bitPos += 8; + _value = (_value << 8) | Stream.ReadByte(); + } + _bitPos -= numBits; + const UInt32 res = _value >> _bitPos; + _value = _value & ((1 << _bitPos) - 1); + return res; + } + + Byte ReadByteFromAligned() + { + if (_bitPos == 0) + return Stream.ReadByte(); + const unsigned bitsPos = _bitPos - 8; + const Byte b = (Byte)(_value >> bitsPos); + _value = _value & ((1 << bitsPos) - 1); + _bitPos = bitsPos; + return b; + } +}; + + +struct CByteIn +{ + IByteIn IByteIn_obj; + CBitDecoder BitDecoder; +}; + + +struct CFilter: public NVm::CProgram +{ + CRecordVector GlobalData; + UInt32 BlockStart; + UInt32 BlockSize; + UInt32 ExecCount; + + CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {} +}; + +struct CTempFilter: public NVm::CProgramInitState +{ + UInt32 BlockStart; + UInt32 BlockSize; + bool NextWindow; + + UInt32 FilterIndex; + + CTempFilter() + { + // all filters must contain at least FixedGlobal block + AllocateEmptyFixedGlobal(); + } +}; + + +Z7_CLASS_IMP_NOQIB_2( + CDecoder + , ICompressCoder + , ICompressSetDecoderProperties2 +) + bool _isSolid; + bool _solidAllowed; + // bool _errorMode; + + bool _lzMode; + bool _unsupportedFilter; + + CByteIn m_InBitStream; + Byte *_window; + UInt32 _winPos; + UInt32 _wrPtr; + UInt64 _lzSize; + UInt64 _unpackSize; + UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written + ISequentialOutStream *_outStream; + + NHuffman::CDecoder m_MainDecoder; + UInt32 kDistStart[kDistTableSize]; + NHuffman::CDecoder256 m_DistDecoder; + NHuffman::CDecoder256 m_AlignDecoder; + NHuffman::CDecoder256 m_LenDecoder; + + UInt32 _reps[kNumReps]; + UInt32 _lastLength; + + Byte m_LastLevels[kTablesSizesSum]; + + Byte *_vmData; + Byte *_vmCode; + NVm::CVm _vm; + CRecordVector _filters; + CRecordVector _tempFilters; + unsigned _numEmptyTempFilters; + UInt32 _lastFilter; + + UInt32 PrevAlignBits; + UInt32 PrevAlignCount; + + bool TablesRead; + bool TablesOK; + bool PpmError; + + int PpmEscChar; + CPpmd7 _ppmd; + + HRESULT WriteDataToStream(const Byte *data, UInt32 size); + HRESULT WriteData(const Byte *data, UInt32 size); + HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr); + void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef); + HRESULT WriteBuf(); + + void InitFilters(); + bool AddVmCode(UInt32 firstByte, UInt32 codeSize); + bool ReadVmCodeLZ(); + bool ReadVmCodePPM(); + + UInt32 ReadBits(unsigned numBits); + + HRESULT InitPPM(); + // int DecodePpmSymbol(); + HRESULT DecodePPM(Int32 num, bool &keepDecompressing); + + HRESULT ReadTables(bool &keepDecompressing); + HRESULT ReadEndOfBlock(bool &keepDecompressing); + HRESULT DecodeLZ(bool &keepDecompressing); + HRESULT CodeReal(ICompressProgressInfo *progress); + + bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); } + bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); } + + void CopyBlock(UInt32 dist, UInt32 len) + { + _lzSize += len; + UInt32 pos = (_winPos - dist - 1) & kWindowMask; + Byte *window = _window; + UInt32 winPos = _winPos; + if (kWindowSize - winPos > len && kWindowSize - pos > len) + { + const Byte *src = window + pos; + Byte *dest = window + winPos; + _winPos += len; + do + *dest++ = *src++; + while (--len != 0); + return; + } + do + { + window[winPos] = window[pos]; + winPos = (winPos + 1) & kWindowMask; + pos = (pos + 1) & kWindowMask; + } + while (--len != 0); + _winPos = winPos; + } + + void PutByte(Byte b) + { + const UInt32 wp = _winPos; + _window[wp] = b; + _winPos = (wp + 1) & kWindowMask; + _lzSize++; + } + +public: + CDecoder(); + ~CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/Rar3Vm.cpp b/CPP/7zip/Compress/Rar3Vm.cpp index e6bfd7ea6..f4ca50043 100644 --- a/CPP/7zip/Compress/Rar3Vm.cpp +++ b/CPP/7zip/Compress/Rar3Vm.cpp @@ -1,1153 +1,1153 @@ -// Rar3Vm.cpp -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -/* -Note: - Due to performance considerations Rar VM may set Flags C incorrectly - for some operands (SHL x, 0, ... ). - Check implementation of concrete VM command - to see if it sets flags right. -*/ - -#include "StdAfx.h" - -#include - -#include "../../../C/7zCrc.h" -#include "../../../C/Alloc.h" - -#include "../../Common/Defs.h" - -#include "Rar3Vm.h" - -namespace NCompress { -namespace NRar3 { - -UInt32 CMemBitDecoder::ReadBits(unsigned numBits) -{ - UInt32 res = 0; - for (;;) - { - const unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0; - const unsigned avail = (unsigned)(8 - (_bitPos & 7)); - if (numBits <= avail) - { - _bitPos += numBits; - return res | ((b >> (avail - numBits)) & ((1 << numBits) - 1)); - } - numBits -= avail; - res |= (UInt32)(b & ((1 << avail) - 1)) << numBits; - _bitPos += avail; - } -} - -UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); } - -UInt32 CMemBitDecoder::ReadEncodedUInt32() -{ - const unsigned v = (unsigned)ReadBits(2); - UInt32 res = ReadBits(4u << v); - if (v == 1 && res < 16) - res = 0xFFFFFF00 | (res << 4) | ReadBits(4); - return res; -} - -namespace NVm { - -static const UInt32 kStackRegIndex = kNumRegs - 1; - -#ifdef Z7_RARVM_VM_ENABLE - -#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \ - || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000) -// enumeration values not explicitly handled in switch -#pragma GCC diagnostic ignored "-Wswitch-enum" -#endif - -static const UInt32 FLAG_C = 1; -static const UInt32 FLAG_Z = 2; -static const UInt32 FLAG_S = 0x80000000; - -static const Byte CF_OP0 = 0; -static const Byte CF_OP1 = 1; -static const Byte CF_OP2 = 2; -static const Byte CF_OPMASK = 3; -static const Byte CF_BYTEMODE = 4; -static const Byte CF_JUMP = 8; -static const Byte CF_PROC = 16; -static const Byte CF_USEFLAGS = 32; -static const Byte CF_CHFLAGS = 64; - -static const Byte kCmdFlags[]= -{ - /* CMD_MOV */ CF_OP2 | CF_BYTEMODE, - /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_JMP */ CF_OP1 | CF_JUMP, - /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, - /* CMD_PUSH */ CF_OP1, - /* CMD_POP */ CF_OP1, - /* CMD_CALL */ CF_OP1 | CF_PROC, - /* CMD_RET */ CF_OP0 | CF_PROC, - /* CMD_NOT */ CF_OP1 | CF_BYTEMODE, - /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, - /* CMD_PUSHA */ CF_OP0, - /* CMD_POPA */ CF_OP0, - /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS, - /* CMD_POPF */ CF_OP0 | CF_CHFLAGS, - /* CMD_MOVZX */ CF_OP2, - /* CMD_MOVSX */ CF_OP2, - /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE, - /* CMD_MUL */ CF_OP2 | CF_BYTEMODE, - /* CMD_DIV */ CF_OP2 | CF_BYTEMODE, - /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , - /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , - /* CMD_PRINT */ CF_OP0 -}; - -#endif - - -CVm::CVm(): Mem(NULL) {} - -bool CVm::Create() -{ - if (!Mem) - Mem = (Byte *)::MyAlloc(kSpaceSize + 4); - return (Mem != NULL); -} - -CVm::~CVm() -{ - ::MyFree(Mem); -} - -// CVm::Execute can change CProgram object: it clears progarm if VM returns error. - -bool CVm::Execute(CProgram *prg, const CProgramInitState *initState, - CBlockRef &outBlockRef, CRecordVector &outGlobalData) -{ - memcpy(R, initState->InitR, sizeof(initState->InitR)); - R[kStackRegIndex] = kSpaceSize; - R[kNumRegs] = 0; - Flags = 0; - - const UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize); - if (globalSize != 0) - memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize); - UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize); - if (staticSize != 0) - memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize); - - bool res = true; - - #ifdef Z7_RARVM_STANDARD_FILTERS - if (prg->StandardFilterIndex >= 0) - res = ExecuteStandardFilter((unsigned)prg->StandardFilterIndex); - else - #endif - { - #ifdef Z7_RARVM_VM_ENABLE - res = ExecuteCode(prg); - if (!res) - { - prg->Commands.Clear(); - prg->Commands.Add(CCommand()); - prg->Commands.Back().OpCode = CMD_RET; - } - #else - res = false; - #endif - } - - UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask; - UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask; - if (newBlockPos + newBlockSize >= kSpaceSize) - newBlockPos = newBlockSize = 0; - outBlockRef.Offset = newBlockPos; - outBlockRef.Size = newBlockSize; - - outGlobalData.Clear(); - UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize); - dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize); - if (dataSize != 0) - { - dataSize += kFixedGlobalSize; - outGlobalData.ClearAndSetSize(dataSize); - memcpy(&outGlobalData[0], Mem + kGlobalOffset, dataSize); - } - - return res; -} - -#ifdef Z7_RARVM_VM_ENABLE - -#define SET_IP(IP) \ - if ((IP) >= numCommands) return true; \ - if (--maxOpCount <= 0) return false; \ - cmd = commands + (IP); - -#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0) -#define SET_IP_OP1 { const UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val) } -#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S -#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res) - -UInt32 CVm::GetOperand32(const COperand *op) const -{ - switch (op->Type) - { - case OP_TYPE_REG: return R[op->Data]; - case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]); - default: return op->Data; - } -} - -void CVm::SetOperand32(const COperand *op, UInt32 val) -{ - switch (op->Type) - { - case OP_TYPE_REG: R[op->Data] = val; return; - case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return; - default: break; - } -} - -Byte CVm::GetOperand8(const COperand *op) const -{ - switch (op->Type) - { - case OP_TYPE_REG: return (Byte)R[op->Data]; - case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask]; - default: return (Byte)op->Data; - } -} - -void CVm::SetOperand8(const COperand *op, Byte val) -{ - switch (op->Type) - { - case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return; - case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return; - default: break; - } -} - -UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const -{ - if (byteMode) - return GetOperand8(op); - return GetOperand32(op); -} - -void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val) -{ - if (byteMode) - SetOperand8(op, (Byte)(val & 0xFF)); - else - SetOperand32(op, val); -} - -bool CVm::ExecuteCode(const CProgram *prg) -{ - Int32 maxOpCount = 25000000; - const CCommand *commands = &prg->Commands[0]; - const CCommand *cmd = commands; - const UInt32 numCommands = prg->Commands.Size(); - if (numCommands == 0) - return false; - - for (;;) - { - switch (cmd->OpCode) - { - case CMD_MOV: - SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2)); - break; - case CMD_MOVB: - SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2)); - break; - case CMD_CMP: - { - const UInt32 v1 = GetOperand32(&cmd->Op1); - const UInt32 res = v1 - GetOperand32(&cmd->Op2); - Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); - } - break; - case CMD_CMPB: - { - const Byte v1 = GetOperand8(&cmd->Op1); - const Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF); - Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res); - } - break; - case CMD_ADD: - { - const UInt32 v1 = GetOperand32(&cmd->Op1); - const UInt32 res = v1 + GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S)); - } - break; - case CMD_ADDB: - { - const Byte v1 = GetOperand8(&cmd->Op1); - const Byte res = (Byte)((v1 + GetOperand8(&cmd->Op2)) & 0xFF); - SetOperand8(&cmd->Op1, (Byte)res); - Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)); - } - break; - case CMD_ADC: - { - const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); - const UInt32 FC = (Flags & FLAG_C); - UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC; - if (cmd->ByteMode) - res &= 0xFF; - SetOperand(cmd->ByteMode, &cmd->Op1, res); - Flags = (res < v1 || (res == v1 && FC)) | (res == 0 ? FLAG_Z : (res & FLAG_S)); - } - break; - case CMD_SUB: - { - const UInt32 v1 = GetOperand32(&cmd->Op1); - const UInt32 res = v1 - GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); - } - break; - case CMD_SUBB: - { - const UInt32 v1 = GetOperand8(&cmd->Op1); - const UInt32 res = v1 - GetOperand8(&cmd->Op2); - SetOperand8(&cmd->Op1, (Byte)res); - Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); - } - break; - case CMD_SBB: - { - const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); - const UInt32 FC = (Flags & FLAG_C); - UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC; - // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S); - if (cmd->ByteMode) - res &= 0xFF; - SetOperand(cmd->ByteMode, &cmd->Op1, res); - Flags = (res > v1 || (res == v1 && FC)) | (res == 0 ? FLAG_Z : (res & FLAG_S)); - } - break; - case CMD_INC: - { - const UInt32 res = GetOperand32(&cmd->Op1) + 1; - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_INCB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_DEC: - { - const UInt32 res = GetOperand32(&cmd->Op1) - 1; - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_DECB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_XOR: - { - const UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_XORB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_AND: - { - const UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_ANDB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_OR: - { - const UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - FLAGS_UPDATE_SZ; - } - break; - case CMD_ORB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_TEST: - { - const UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); - FLAGS_UPDATE_SZ; - } - break; - case CMD_TESTB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); - FLAGS_UPDATE_SZ_B; - } - break; - case CMD_NOT: - SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1)); - break; - case CMD_NEG: - { - const UInt32 res = 0 - GetOperand32(&cmd->Op1); - SetOperand32(&cmd->Op1, res); - Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S); - } - break; - case CMD_NEGB: - { - const Byte res = (Byte)(0 - GetOperand8(&cmd->Op1)); - SetOperand8(&cmd->Op1, res); - Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res); - } - break; - - case CMD_SHL: - { - const UInt32 v1 = GetOperand32(&cmd->Op1); - const int v2 = (int)GetOperand32(&cmd->Op2); - const UInt32 res = v1 << v2; - SetOperand32(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0); - } - break; - case CMD_SHLB: - { - const Byte v1 = GetOperand8(&cmd->Op1); - const int v2 = (int)GetOperand8(&cmd->Op2); - const Byte res = (Byte)(v1 << v2); - SetOperand8(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0); - } - break; - case CMD_SHR: - { - const UInt32 v1 = GetOperand32(&cmd->Op1); - const int v2 = (int)GetOperand32(&cmd->Op2); - const UInt32 res = v1 >> v2; - SetOperand32(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - case CMD_SHRB: - { - const Byte v1 = GetOperand8(&cmd->Op1); - const int v2 = (int)GetOperand8(&cmd->Op2); - const Byte res = (Byte)(v1 >> v2); - SetOperand8(&cmd->Op1, res); - Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - case CMD_SAR: - { - const UInt32 v1 = GetOperand32(&cmd->Op1); - const int v2 = (int)GetOperand32(&cmd->Op2); - const UInt32 res = UInt32(((Int32)v1) >> v2); - SetOperand32(&cmd->Op1, res); - Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - case CMD_SARB: - { - const Byte v1 = GetOperand8(&cmd->Op1); - const int v2 = (int)GetOperand8(&cmd->Op2); - const Byte res = (Byte)(((signed char)v1) >> v2); - SetOperand8(&cmd->Op1, res); - Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); - } - break; - - case CMD_JMP: - SET_IP_OP1 - continue; - case CMD_JZ: - if ((Flags & FLAG_Z) != 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JNZ: - if ((Flags & FLAG_Z) == 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JS: - if ((Flags & FLAG_S) != 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JNS: - if ((Flags & FLAG_S) == 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JB: - if ((Flags & FLAG_C) != 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JBE: - if ((Flags & (FLAG_C | FLAG_Z)) != 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JA: - if ((Flags & (FLAG_C | FLAG_Z)) == 0) - { - SET_IP_OP1 - continue; - } - break; - case CMD_JAE: - if ((Flags & FLAG_C) == 0) - { - SET_IP_OP1 - continue; - } - break; - - case CMD_PUSH: - R[kStackRegIndex] -= 4; - SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1)); - break; - case CMD_POP: - SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask])); - R[kStackRegIndex] += 4; - break; - case CMD_CALL: - R[kStackRegIndex] -= 4; - SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1)); - SET_IP_OP1 - continue; - - case CMD_PUSHA: - { - for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4) - SetValue32(&Mem[SP & kSpaceMask], R[i]); - R[kStackRegIndex] -= kNumRegs * 4; - } - break; - case CMD_POPA: - { - for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4) - R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]); - } - break; - case CMD_PUSHF: - R[kStackRegIndex] -= 4; - SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags); - break; - case CMD_POPF: - Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); - R[kStackRegIndex] += 4; - break; - - case CMD_MOVZX: - SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2)); - break; - case CMD_MOVSX: - SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2)); - break; - case CMD_XCHG: - { - const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); - SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2)); - SetOperand(cmd->ByteMode, &cmd->Op2, v1); - } - break; - case CMD_MUL: - { - const UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2); - SetOperand32(&cmd->Op1, res); - } - break; - case CMD_MULB: - { - const Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2)); - SetOperand8(&cmd->Op1, res); - } - break; - case CMD_DIV: - { - const UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2); - if (divider != 0) - { - const UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider; - SetOperand(cmd->ByteMode, &cmd->Op1, res); - } - } - break; - - case CMD_RET: - { - if (R[kStackRegIndex] >= kSpaceSize) - return true; - const UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); - SET_IP(ip) - R[kStackRegIndex] += 4; - continue; - } - case CMD_PRINT: - break; - } - cmd++; - --maxOpCount; - } -} - -////////////////////////////////////////////////////// -// Read program - -static void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode) -{ - if (inp.ReadBit()) - { - op.Type = OP_TYPE_REG; - op.Data = inp.ReadBits(kNumRegBits); - } - else if (inp.ReadBit() == 0) - { - op.Type = OP_TYPE_INT; - if (byteMode) - op.Data = inp.ReadBits(8); - else - op.Data = inp.ReadEncodedUInt32(); - } - else - { - op.Type = OP_TYPE_REGMEM; - if (inp.ReadBit() == 0) - { - op.Data = inp.ReadBits(kNumRegBits); - op.Base = 0; - } - else - { - if (inp.ReadBit() == 0) - op.Data = inp.ReadBits(kNumRegBits); - else - op.Data = kNumRegs; - op.Base = inp.ReadEncodedUInt32(); - } - } -} - -void CProgram::ReadProgram(const Byte *code, UInt32 codeSize) -{ - CMemBitDecoder inp; - inp.Init(code, codeSize); - - StaticData.Clear(); - - if (inp.ReadBit()) - { - const UInt32 dataSize = inp.ReadEncodedUInt32() + 1; - for (UInt32 i = 0; inp.Avail() && i < dataSize; i++) - StaticData.Add((Byte)inp.ReadBits(8)); - } - - while (inp.Avail()) - { - Commands.Add(CCommand()); - CCommand *cmd = &Commands.Back(); - - unsigned opCode; - if (inp.ReadBit() == 0) - opCode = inp.ReadBits(3); - else - opCode = 8 + inp.ReadBits(5); - cmd->OpCode = (ECommand)opCode; - const unsigned cmdFlags = kCmdFlags[opCode]; - if (cmdFlags & CF_BYTEMODE) - cmd->ByteMode = (inp.ReadBit()) ? true : false; - else - cmd->ByteMode = 0; - - const unsigned opNum = (cmdFlags & CF_OPMASK); - - if (opNum) - { - DecodeArg(inp, cmd->Op1, cmd->ByteMode); - if (opNum == 2) - DecodeArg(inp, cmd->Op2, cmd->ByteMode); - else - { - if (cmd->Op1.Type == OP_TYPE_INT && (cmdFlags & (CF_JUMP | CF_PROC))) - { - Int32 dist = (Int32)cmd->Op1.Data; - if (dist >= 256) - dist -= 256; - else - { - if (dist >= 136) - dist -= 264; - else if (dist >= 16) - dist -= 8; - else if (dist >= 8) - dist -= 16; - dist += Commands.Size() - 1; - } - cmd->Op1.Data = (UInt32)dist; - } - } - } - - if (cmd->ByteMode) - { - switch (cmd->OpCode) - { - case CMD_MOV: cmd->OpCode = CMD_MOVB; break; - case CMD_CMP: cmd->OpCode = CMD_CMPB; break; - case CMD_ADD: cmd->OpCode = CMD_ADDB; break; - case CMD_SUB: cmd->OpCode = CMD_SUBB; break; - case CMD_INC: cmd->OpCode = CMD_INCB; break; - case CMD_DEC: cmd->OpCode = CMD_DECB; break; - case CMD_XOR: cmd->OpCode = CMD_XORB; break; - case CMD_AND: cmd->OpCode = CMD_ANDB; break; - case CMD_OR: cmd->OpCode = CMD_ORB; break; - case CMD_TEST: cmd->OpCode = CMD_TESTB; break; - case CMD_NEG: cmd->OpCode = CMD_NEGB; break; - case CMD_SHL: cmd->OpCode = CMD_SHLB; break; - case CMD_SHR: cmd->OpCode = CMD_SHRB; break; - case CMD_SAR: cmd->OpCode = CMD_SARB; break; - case CMD_MUL: cmd->OpCode = CMD_MULB; break; - default: break; - } - } - } -} - -#endif - - -#ifdef Z7_RARVM_STANDARD_FILTERS - -enum EStandardFilter -{ - SF_E8, - SF_E8E9, - SF_ITANIUM, - SF_RGB, - SF_AUDIO, - SF_DELTA - // SF_UPCASE -}; - -static const struct CStandardFilterSignature -{ - UInt32 Length; - UInt32 CRC; - EStandardFilter Type; -} -kStdFilters[]= -{ - { 53, 0xad576887, SF_E8 }, - { 57, 0x3cd7e57e, SF_E8E9 }, - { 120, 0x3769893f, SF_ITANIUM }, - { 29, 0x0e06077d, SF_DELTA }, - { 149, 0x1c2c5dc8, SF_RGB }, - { 216, 0xbc85e701, SF_AUDIO } - // { 40, 0x46b9c560, SF_UPCASE } -}; - -static int FindStandardFilter(const Byte *code, UInt32 codeSize) -{ - // return -1; // for debug VM execution - const UInt32 crc = CrcCalc(code, codeSize); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kStdFilters); i++) - { - const CStandardFilterSignature &sfs = kStdFilters[i]; - if (sfs.CRC == crc && sfs.Length == codeSize) - return (int)i; - } - return -1; -} - -#endif - - -bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize) -{ - IsSupported = false; - - #ifdef Z7_RARVM_VM_ENABLE - Commands.Clear(); - #endif - - #ifdef Z7_RARVM_STANDARD_FILTERS - StandardFilterIndex = -1; - #endif - - bool isOK = false; - - Byte xorSum = 0; - for (UInt32 i = 0; i < codeSize; i++) - xorSum ^= code[i]; - - if (xorSum == 0 && codeSize != 0) - { - IsSupported = true; - isOK = true; - #ifdef Z7_RARVM_STANDARD_FILTERS - StandardFilterIndex = FindStandardFilter(code, codeSize); - if (StandardFilterIndex >= 0) - return true; - #endif - - #ifdef Z7_RARVM_VM_ENABLE - ReadProgram(code + 1, codeSize - 1); - #else - IsSupported = false; - #endif - } - - #ifdef Z7_RARVM_VM_ENABLE - Commands.Add(CCommand()); - Commands.Back().OpCode = CMD_RET; - #endif - - return isOK; -} - -void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize) -{ - if (pos < kSpaceSize && data != Mem + pos) - memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos)); -} - -#ifdef Z7_RARVM_STANDARD_FILTERS - -static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9) -{ - if (dataSize <= 4) - return; - dataSize -= 4; - const UInt32 kFileSize = 0x1000000; - const Byte cmpMask = (Byte)(e9 ? 0xFE : 0xFF); - for (UInt32 curPos = 0; curPos < dataSize;) - { - curPos++; - if (((*data++) & cmpMask) == 0xE8) - { - UInt32 offset = curPos + fileOffset; - UInt32 addr = GetValue32(data); - if (addr < kFileSize) - SetValue32(data, addr - offset); - else if ((addr & 0x80000000) != 0 && ((addr + offset) & 0x80000000) == 0) - SetValue32(data, addr + kFileSize); - data += 4; - curPos += 4; - } - } -} - - -static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset) -{ - if (dataSize <= 21) - return; - fileOffset >>= 4; - dataSize -= 21; - dataSize += 15; - dataSize >>= 4; - dataSize += fileOffset; - do - { - unsigned m = ((UInt32)0x334B0000 >> (data[0] & 0x1E)) & 3; - if (m) - { - m++; - do - { - Byte *p = data + ((size_t)m * 5 - 8); - if (((p[3] >> m) & 15) == 5) - { - const UInt32 kMask = 0xFFFFF; - // UInt32 raw = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16); - UInt32 raw = GetUi32(p); - UInt32 v = raw >> m; - v -= fileOffset; - v &= kMask; - raw &= ~(kMask << m); - raw |= (v << m); - // p[0] = (Byte)raw; p[1] = (Byte)(raw >> 8); p[2] = (Byte)(raw >> 16); - SetUi32(p, raw) - } - } - while (++m <= 4); - } - data += 16; - } - while (++fileOffset != dataSize); -} - - -static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels) -{ - UInt32 srcPos = 0; - const UInt32 border = dataSize * 2; - for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) - { - Byte prevByte = 0; - for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels) - data[destPos] = (prevByte = (Byte)(prevByte - data[srcPos++])); - } -} - -static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR) -{ - Byte *destData = srcData + dataSize; - const UInt32 kNumChannels = 3; - - for (UInt32 curChannel = 0; curChannel < kNumChannels; curChannel++) - { - Byte prevByte = 0; - - for (UInt32 i = curChannel; i < dataSize; i += kNumChannels) - { - unsigned predicted; - if (i < width) - predicted = prevByte; - else - { - const unsigned upperLeftByte = destData[i - width]; - const unsigned upperByte = destData[i - width + 3]; - predicted = prevByte + upperByte - upperLeftByte; - const int pa = abs((int)(predicted - prevByte)); - const int pb = abs((int)(predicted - upperByte)); - const int pc = abs((int)(predicted - upperLeftByte)); - if (pa <= pb && pa <= pc) - predicted = prevByte; - else - if (pb <= pc) - predicted = upperByte; - else - predicted = upperLeftByte; - } - destData[i] = prevByte = (Byte)(predicted - *(srcData++)); - } - } - if (dataSize < 3) - return; - const UInt32 border = dataSize - 2; - for (UInt32 i = posR; i < border; i += 3) - { - const Byte g = destData[i + 1]; - destData[i ] = (Byte)(destData[i ] + g); - destData[i + 2] = (Byte)(destData[i + 2] + g); - } -} - -#define my_abs(x) (unsigned)abs(x) - -static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels) -{ - Byte *destData = srcData + dataSize; - for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) - { - UInt32 prevByte = 0, prevDelta = 0, dif[7]; - Int32 D1 = 0, D2 = 0, D3; - Int32 K1 = 0, K2 = 0, K3 = 0; - memset(dif, 0, sizeof(dif)); - - for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++) - { - D3 = D2; - D2 = (Int32)prevDelta - D1; - D1 = (Int32)prevDelta; - - UInt32 predicted = (UInt32)((Int32)(8 * prevByte) + K1 * D1 + K2 * D2 + K3 * D3); - predicted = (predicted >> 3) & 0xFF; - - const UInt32 curByte = *(srcData++); - - predicted -= curByte; - destData[i] = (Byte)predicted; - prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte); - prevByte = predicted; - - const Int32 D = ((Int32)(signed char)curByte) << 3; - - dif[0] += my_abs(D); - dif[1] += my_abs(D - D1); - dif[2] += my_abs(D + D1); - dif[3] += my_abs(D - D2); - dif[4] += my_abs(D + D2); - dif[5] += my_abs(D - D3); - dif[6] += my_abs(D + D3); - - if ((byteCount & 0x1F) == 0) - { - UInt32 minDif = dif[0], numMinDif = 0; - dif[0] = 0; - for (unsigned j = 1; j < Z7_ARRAY_SIZE(dif); j++) - { - if (dif[j] < minDif) - { - minDif = dif[j]; - numMinDif = j; - } - dif[j] = 0; - } - switch (numMinDif) - { - case 1: if (K1 >= -16) K1--; break; - case 2: if (K1 < 16) K1++; break; - case 3: if (K2 >= -16) K2--; break; - case 4: if (K2 < 16) K2++; break; - case 5: if (K3 >= -16) K3--; break; - case 6: if (K3 < 16) K3++; break; - } - } - } - } -} - -/* -static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize) -{ - UInt32 srcPos = 0, destPos = dataSize; - while (srcPos < dataSize) - { - Byte curByte = data[srcPos++]; - if (curByte == 2 && (curByte = data[srcPos++]) != 2) - curByte -= 32; - data[destPos++] = curByte; - } - return destPos - dataSize; -} -*/ - -bool CVm::ExecuteStandardFilter(unsigned filterIndex) -{ - const UInt32 dataSize = R[4]; - if (dataSize >= kGlobalOffset) - return false; - EStandardFilter filterType = kStdFilters[filterIndex].Type; - - switch (filterType) - { - case SF_E8: - case SF_E8E9: - E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9)); - break; - - case SF_ITANIUM: - ItaniumDecode(Mem, dataSize, R[6]); - break; - - case SF_DELTA: - { - if (dataSize >= kGlobalOffset / 2) - return false; - const UInt32 numChannels = R[0]; - if (numChannels == 0 || numChannels > 1024) // unrar 5.5.5 - return false; - SetBlockPos(dataSize); - DeltaDecode(Mem, dataSize, numChannels); - break; - } - - case SF_RGB: - { - if (dataSize >= kGlobalOffset / 2 || dataSize < 3) // unrar 5.5.5 - return false; - const UInt32 width = R[0]; - const UInt32 posR = R[1]; - if (width < 3 || width - 3 > dataSize || posR > 2) // unrar 5.5.5 - return false; - SetBlockPos(dataSize); - RgbDecode(Mem, dataSize, width, posR); - break; - } - - case SF_AUDIO: - { - if (dataSize >= kGlobalOffset / 2) - return false; - const UInt32 numChannels = R[0]; - if (numChannels == 0 || numChannels > 128) // unrar 5.5.5 - return false; - SetBlockPos(dataSize); - AudioDecode(Mem, dataSize, numChannels); - break; - } - - /* - case SF_UPCASE: - if (dataSize >= kGlobalOffset / 2) - return false; - UInt32 destSize = UpCaseDecode(Mem, dataSize); - SetBlockSize(destSize); - SetBlockPos(dataSize); - break; - */ - } - return true; -} - -#endif - -}}} +// Rar3Vm.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* +Note: + Due to performance considerations Rar VM may set Flags C incorrectly + for some operands (SHL x, 0, ... ). + Check implementation of concrete VM command + to see if it sets flags right. +*/ + +#include "StdAfx.h" + +#include + +#include "../../../C/7zCrc.h" +#include "../../../C/Alloc.h" + +#include "../../Common/Defs.h" + +#include "Rar3Vm.h" + +namespace NCompress { +namespace NRar3 { + +UInt32 CMemBitDecoder::ReadBits(unsigned numBits) +{ + UInt32 res = 0; + for (;;) + { + const unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0; + const unsigned avail = (unsigned)(8 - (_bitPos & 7)); + if (numBits <= avail) + { + _bitPos += numBits; + return res | ((b >> (avail - numBits)) & ((1 << numBits) - 1)); + } + numBits -= avail; + res |= (UInt32)(b & ((1 << avail) - 1)) << numBits; + _bitPos += avail; + } +} + +UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); } + +UInt32 CMemBitDecoder::ReadEncodedUInt32() +{ + const unsigned v = (unsigned)ReadBits(2); + UInt32 res = ReadBits(4u << v); + if (v == 1 && res < 16) + res = 0xFFFFFF00 | (res << 4) | ReadBits(4); + return res; +} + +namespace NVm { + +static const UInt32 kStackRegIndex = kNumRegs - 1; + +#ifdef Z7_RARVM_VM_ENABLE + +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \ + || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000) +// enumeration values not explicitly handled in switch +#pragma GCC diagnostic ignored "-Wswitch-enum" +#endif + +static const UInt32 FLAG_C = 1; +static const UInt32 FLAG_Z = 2; +static const UInt32 FLAG_S = 0x80000000; + +static const Byte CF_OP0 = 0; +static const Byte CF_OP1 = 1; +static const Byte CF_OP2 = 2; +static const Byte CF_OPMASK = 3; +static const Byte CF_BYTEMODE = 4; +static const Byte CF_JUMP = 8; +static const Byte CF_PROC = 16; +static const Byte CF_USEFLAGS = 32; +static const Byte CF_CHFLAGS = 64; + +static const Byte kCmdFlags[]= +{ + /* CMD_MOV */ CF_OP2 | CF_BYTEMODE, + /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JMP */ CF_OP1 | CF_JUMP, + /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_PUSH */ CF_OP1, + /* CMD_POP */ CF_OP1, + /* CMD_CALL */ CF_OP1 | CF_PROC, + /* CMD_RET */ CF_OP0 | CF_PROC, + /* CMD_NOT */ CF_OP1 | CF_BYTEMODE, + /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_PUSHA */ CF_OP0, + /* CMD_POPA */ CF_OP0, + /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS, + /* CMD_POPF */ CF_OP0 | CF_CHFLAGS, + /* CMD_MOVZX */ CF_OP2, + /* CMD_MOVSX */ CF_OP2, + /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE, + /* CMD_MUL */ CF_OP2 | CF_BYTEMODE, + /* CMD_DIV */ CF_OP2 | CF_BYTEMODE, + /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , + /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , + /* CMD_PRINT */ CF_OP0 +}; + +#endif + + +CVm::CVm(): Mem(NULL) {} + +bool CVm::Create() +{ + if (!Mem) + Mem = (Byte *)::MyAlloc(kSpaceSize + 4); + return (Mem != NULL); +} + +CVm::~CVm() +{ + ::MyFree(Mem); +} + +// CVm::Execute can change CProgram object: it clears progarm if VM returns error. + +bool CVm::Execute(CProgram *prg, const CProgramInitState *initState, + CBlockRef &outBlockRef, CRecordVector &outGlobalData) +{ + memcpy(R, initState->InitR, sizeof(initState->InitR)); + R[kStackRegIndex] = kSpaceSize; + R[kNumRegs] = 0; + Flags = 0; + + const UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize); + if (globalSize != 0) + memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize); + UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize); + if (staticSize != 0) + memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize); + + bool res = true; + + #ifdef Z7_RARVM_STANDARD_FILTERS + if (prg->StandardFilterIndex >= 0) + res = ExecuteStandardFilter((unsigned)prg->StandardFilterIndex); + else + #endif + { + #ifdef Z7_RARVM_VM_ENABLE + res = ExecuteCode(prg); + if (!res) + { + prg->Commands.Clear(); + prg->Commands.Add(CCommand()); + prg->Commands.Back().OpCode = CMD_RET; + } + #else + res = false; + #endif + } + + UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask; + UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask; + if (newBlockPos + newBlockSize >= kSpaceSize) + newBlockPos = newBlockSize = 0; + outBlockRef.Offset = newBlockPos; + outBlockRef.Size = newBlockSize; + + outGlobalData.Clear(); + UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize); + dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize); + if (dataSize != 0) + { + dataSize += kFixedGlobalSize; + outGlobalData.ClearAndSetSize(dataSize); + memcpy(&outGlobalData[0], Mem + kGlobalOffset, dataSize); + } + + return res; +} + +#ifdef Z7_RARVM_VM_ENABLE + +#define SET_IP(IP) \ + if ((IP) >= numCommands) return true; \ + if (--maxOpCount <= 0) return false; \ + cmd = commands + (IP); + +#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0) +#define SET_IP_OP1 { const UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val) } +#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S +#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res) + +UInt32 CVm::GetOperand32(const COperand *op) const +{ + switch (op->Type) + { + case OP_TYPE_REG: return R[op->Data]; + case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]); + default: return op->Data; + } +} + +void CVm::SetOperand32(const COperand *op, UInt32 val) +{ + switch (op->Type) + { + case OP_TYPE_REG: R[op->Data] = val; return; + case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return; + default: break; + } +} + +Byte CVm::GetOperand8(const COperand *op) const +{ + switch (op->Type) + { + case OP_TYPE_REG: return (Byte)R[op->Data]; + case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask]; + default: return (Byte)op->Data; + } +} + +void CVm::SetOperand8(const COperand *op, Byte val) +{ + switch (op->Type) + { + case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return; + case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return; + default: break; + } +} + +UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const +{ + if (byteMode) + return GetOperand8(op); + return GetOperand32(op); +} + +void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val) +{ + if (byteMode) + SetOperand8(op, (Byte)(val & 0xFF)); + else + SetOperand32(op, val); +} + +bool CVm::ExecuteCode(const CProgram *prg) +{ + Int32 maxOpCount = 25000000; + const CCommand *commands = &prg->Commands[0]; + const CCommand *cmd = commands; + const UInt32 numCommands = prg->Commands.Size(); + if (numCommands == 0) + return false; + + for (;;) + { + switch (cmd->OpCode) + { + case CMD_MOV: + SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2)); + break; + case CMD_MOVB: + SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_CMP: + { + const UInt32 v1 = GetOperand32(&cmd->Op1); + const UInt32 res = v1 - GetOperand32(&cmd->Op2); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_CMPB: + { + const Byte v1 = GetOperand8(&cmd->Op1); + const Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF); + Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res); + } + break; + case CMD_ADD: + { + const UInt32 v1 = GetOperand32(&cmd->Op1); + const UInt32 res = v1 + GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_ADDB: + { + const Byte v1 = GetOperand8(&cmd->Op1); + const Byte res = (Byte)((v1 + GetOperand8(&cmd->Op2)) & 0xFF); + SetOperand8(&cmd->Op1, (Byte)res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)); + } + break; + case CMD_ADC: + { + const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + const UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC; + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res < v1 || (res == v1 && FC)) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_SUB: + { + const UInt32 v1 = GetOperand32(&cmd->Op1); + const UInt32 res = v1 - GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SUBB: + { + const UInt32 v1 = GetOperand8(&cmd->Op1); + const UInt32 res = v1 - GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, (Byte)res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SBB: + { + const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + const UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC; + // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S); + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res > v1 || (res == v1 && FC)) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_INC: + { + const UInt32 res = GetOperand32(&cmd->Op1) + 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_INCB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_DEC: + { + const UInt32 res = GetOperand32(&cmd->Op1) - 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_DECB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_XOR: + { + const UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_XORB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_AND: + { + const UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ANDB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_OR: + { + const UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ORB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_TEST: + { + const UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + FLAGS_UPDATE_SZ; + } + break; + case CMD_TESTB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_NOT: + SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1)); + break; + case CMD_NEG: + { + const UInt32 res = 0 - GetOperand32(&cmd->Op1); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S); + } + break; + case CMD_NEGB: + { + const Byte res = (Byte)(0 - GetOperand8(&cmd->Op1)); + SetOperand8(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res); + } + break; + + case CMD_SHL: + { + const UInt32 v1 = GetOperand32(&cmd->Op1); + const int v2 = (int)GetOperand32(&cmd->Op2); + const UInt32 res = v1 << v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0); + } + break; + case CMD_SHLB: + { + const Byte v1 = GetOperand8(&cmd->Op1); + const int v2 = (int)GetOperand8(&cmd->Op2); + const Byte res = (Byte)(v1 << v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0); + } + break; + case CMD_SHR: + { + const UInt32 v1 = GetOperand32(&cmd->Op1); + const int v2 = (int)GetOperand32(&cmd->Op2); + const UInt32 res = v1 >> v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SHRB: + { + const Byte v1 = GetOperand8(&cmd->Op1); + const int v2 = (int)GetOperand8(&cmd->Op2); + const Byte res = (Byte)(v1 >> v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SAR: + { + const UInt32 v1 = GetOperand32(&cmd->Op1); + const int v2 = (int)GetOperand32(&cmd->Op2); + const UInt32 res = UInt32(((Int32)v1) >> v2); + SetOperand32(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SARB: + { + const Byte v1 = GetOperand8(&cmd->Op1); + const int v2 = (int)GetOperand8(&cmd->Op2); + const Byte res = (Byte)(((signed char)v1) >> v2); + SetOperand8(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + + case CMD_JMP: + SET_IP_OP1 + continue; + case CMD_JZ: + if ((Flags & FLAG_Z) != 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JNZ: + if ((Flags & FLAG_Z) == 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JS: + if ((Flags & FLAG_S) != 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JNS: + if ((Flags & FLAG_S) == 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JB: + if ((Flags & FLAG_C) != 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JBE: + if ((Flags & (FLAG_C | FLAG_Z)) != 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JA: + if ((Flags & (FLAG_C | FLAG_Z)) == 0) + { + SET_IP_OP1 + continue; + } + break; + case CMD_JAE: + if ((Flags & FLAG_C) == 0) + { + SET_IP_OP1 + continue; + } + break; + + case CMD_PUSH: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1)); + break; + case CMD_POP: + SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask])); + R[kStackRegIndex] += 4; + break; + case CMD_CALL: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1)); + SET_IP_OP1 + continue; + + case CMD_PUSHA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4) + SetValue32(&Mem[SP & kSpaceMask], R[i]); + R[kStackRegIndex] -= kNumRegs * 4; + } + break; + case CMD_POPA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4) + R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]); + } + break; + case CMD_PUSHF: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags); + break; + case CMD_POPF: + Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + R[kStackRegIndex] += 4; + break; + + case CMD_MOVZX: + SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_MOVSX: + SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2)); + break; + case CMD_XCHG: + { + const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2)); + SetOperand(cmd->ByteMode, &cmd->Op2, v1); + } + break; + case CMD_MUL: + { + const UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + } + break; + case CMD_MULB: + { + const Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + } + break; + case CMD_DIV: + { + const UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2); + if (divider != 0) + { + const UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + } + } + break; + + case CMD_RET: + { + if (R[kStackRegIndex] >= kSpaceSize) + return true; + const UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + SET_IP(ip) + R[kStackRegIndex] += 4; + continue; + } + case CMD_PRINT: + break; + } + cmd++; + --maxOpCount; + } +} + +////////////////////////////////////////////////////// +// Read program + +static void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode) +{ + if (inp.ReadBit()) + { + op.Type = OP_TYPE_REG; + op.Data = inp.ReadBits(kNumRegBits); + } + else if (inp.ReadBit() == 0) + { + op.Type = OP_TYPE_INT; + if (byteMode) + op.Data = inp.ReadBits(8); + else + op.Data = inp.ReadEncodedUInt32(); + } + else + { + op.Type = OP_TYPE_REGMEM; + if (inp.ReadBit() == 0) + { + op.Data = inp.ReadBits(kNumRegBits); + op.Base = 0; + } + else + { + if (inp.ReadBit() == 0) + op.Data = inp.ReadBits(kNumRegBits); + else + op.Data = kNumRegs; + op.Base = inp.ReadEncodedUInt32(); + } + } +} + +void CProgram::ReadProgram(const Byte *code, UInt32 codeSize) +{ + CMemBitDecoder inp; + inp.Init(code, codeSize); + + StaticData.Clear(); + + if (inp.ReadBit()) + { + const UInt32 dataSize = inp.ReadEncodedUInt32() + 1; + for (UInt32 i = 0; inp.Avail() && i < dataSize; i++) + StaticData.Add((Byte)inp.ReadBits(8)); + } + + while (inp.Avail()) + { + Commands.Add(CCommand()); + CCommand *cmd = &Commands.Back(); + + unsigned opCode; + if (inp.ReadBit() == 0) + opCode = inp.ReadBits(3); + else + opCode = 8 + inp.ReadBits(5); + cmd->OpCode = (ECommand)opCode; + const unsigned cmdFlags = kCmdFlags[opCode]; + if (cmdFlags & CF_BYTEMODE) + cmd->ByteMode = (inp.ReadBit()) ? true : false; + else + cmd->ByteMode = 0; + + const unsigned opNum = (cmdFlags & CF_OPMASK); + + if (opNum) + { + DecodeArg(inp, cmd->Op1, cmd->ByteMode); + if (opNum == 2) + DecodeArg(inp, cmd->Op2, cmd->ByteMode); + else + { + if (cmd->Op1.Type == OP_TYPE_INT && (cmdFlags & (CF_JUMP | CF_PROC))) + { + Int32 dist = (Int32)cmd->Op1.Data; + if (dist >= 256) + dist -= 256; + else + { + if (dist >= 136) + dist -= 264; + else if (dist >= 16) + dist -= 8; + else if (dist >= 8) + dist -= 16; + dist += Commands.Size() - 1; + } + cmd->Op1.Data = (UInt32)dist; + } + } + } + + if (cmd->ByteMode) + { + switch (cmd->OpCode) + { + case CMD_MOV: cmd->OpCode = CMD_MOVB; break; + case CMD_CMP: cmd->OpCode = CMD_CMPB; break; + case CMD_ADD: cmd->OpCode = CMD_ADDB; break; + case CMD_SUB: cmd->OpCode = CMD_SUBB; break; + case CMD_INC: cmd->OpCode = CMD_INCB; break; + case CMD_DEC: cmd->OpCode = CMD_DECB; break; + case CMD_XOR: cmd->OpCode = CMD_XORB; break; + case CMD_AND: cmd->OpCode = CMD_ANDB; break; + case CMD_OR: cmd->OpCode = CMD_ORB; break; + case CMD_TEST: cmd->OpCode = CMD_TESTB; break; + case CMD_NEG: cmd->OpCode = CMD_NEGB; break; + case CMD_SHL: cmd->OpCode = CMD_SHLB; break; + case CMD_SHR: cmd->OpCode = CMD_SHRB; break; + case CMD_SAR: cmd->OpCode = CMD_SARB; break; + case CMD_MUL: cmd->OpCode = CMD_MULB; break; + default: break; + } + } + } +} + +#endif + + +#ifdef Z7_RARVM_STANDARD_FILTERS + +enum EStandardFilter +{ + SF_E8, + SF_E8E9, + SF_ITANIUM, + SF_RGB, + SF_AUDIO, + SF_DELTA + // SF_UPCASE +}; + +static const struct CStandardFilterSignature +{ + UInt32 Length; + UInt32 CRC; + EStandardFilter Type; +} +kStdFilters[]= +{ + { 53, 0xad576887, SF_E8 }, + { 57, 0x3cd7e57e, SF_E8E9 }, + { 120, 0x3769893f, SF_ITANIUM }, + { 29, 0x0e06077d, SF_DELTA }, + { 149, 0x1c2c5dc8, SF_RGB }, + { 216, 0xbc85e701, SF_AUDIO } + // { 40, 0x46b9c560, SF_UPCASE } +}; + +static int FindStandardFilter(const Byte *code, UInt32 codeSize) +{ + // return -1; // for debug VM execution + const UInt32 crc = CrcCalc(code, codeSize); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kStdFilters); i++) + { + const CStandardFilterSignature &sfs = kStdFilters[i]; + if (sfs.CRC == crc && sfs.Length == codeSize) + return (int)i; + } + return -1; +} + +#endif + + +bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize) +{ + IsSupported = false; + + #ifdef Z7_RARVM_VM_ENABLE + Commands.Clear(); + #endif + + #ifdef Z7_RARVM_STANDARD_FILTERS + StandardFilterIndex = -1; + #endif + + bool isOK = false; + + Byte xorSum = 0; + for (UInt32 i = 0; i < codeSize; i++) + xorSum ^= code[i]; + + if (xorSum == 0 && codeSize != 0) + { + IsSupported = true; + isOK = true; + #ifdef Z7_RARVM_STANDARD_FILTERS + StandardFilterIndex = FindStandardFilter(code, codeSize); + if (StandardFilterIndex >= 0) + return true; + #endif + + #ifdef Z7_RARVM_VM_ENABLE + ReadProgram(code + 1, codeSize - 1); + #else + IsSupported = false; + #endif + } + + #ifdef Z7_RARVM_VM_ENABLE + Commands.Add(CCommand()); + Commands.Back().OpCode = CMD_RET; + #endif + + return isOK; +} + +void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize) +{ + if (pos < kSpaceSize && data != Mem + pos) + memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos)); +} + +#ifdef Z7_RARVM_STANDARD_FILTERS + +static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9) +{ + if (dataSize <= 4) + return; + dataSize -= 4; + const UInt32 kFileSize = 0x1000000; + const Byte cmpMask = (Byte)(e9 ? 0xFE : 0xFF); + for (UInt32 curPos = 0; curPos < dataSize;) + { + curPos++; + if (((*data++) & cmpMask) == 0xE8) + { + UInt32 offset = curPos + fileOffset; + UInt32 addr = GetValue32(data); + if (addr < kFileSize) + SetValue32(data, addr - offset); + else if ((addr & 0x80000000) != 0 && ((addr + offset) & 0x80000000) == 0) + SetValue32(data, addr + kFileSize); + data += 4; + curPos += 4; + } + } +} + + +static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset) +{ + if (dataSize <= 21) + return; + fileOffset >>= 4; + dataSize -= 21; + dataSize += 15; + dataSize >>= 4; + dataSize += fileOffset; + do + { + unsigned m = ((UInt32)0x334B0000 >> (data[0] & 0x1E)) & 3; + if (m) + { + m++; + do + { + Byte *p = data + ((size_t)m * 5 - 8); + if (((p[3] >> m) & 15) == 5) + { + const UInt32 kMask = 0xFFFFF; + // UInt32 raw = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16); + UInt32 raw = GetUi32(p); + UInt32 v = raw >> m; + v -= fileOffset; + v &= kMask; + raw &= ~(kMask << m); + raw |= (v << m); + // p[0] = (Byte)raw; p[1] = (Byte)(raw >> 8); p[2] = (Byte)(raw >> 16); + SetUi32(p, raw) + } + } + while (++m <= 4); + } + data += 16; + } + while (++fileOffset != dataSize); +} + + +static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels) +{ + UInt32 srcPos = 0; + const UInt32 border = dataSize * 2; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + Byte prevByte = 0; + for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels) + data[destPos] = (prevByte = (Byte)(prevByte - data[srcPos++])); + } +} + +static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR) +{ + Byte *destData = srcData + dataSize; + const UInt32 kNumChannels = 3; + + for (UInt32 curChannel = 0; curChannel < kNumChannels; curChannel++) + { + Byte prevByte = 0; + + for (UInt32 i = curChannel; i < dataSize; i += kNumChannels) + { + unsigned predicted; + if (i < width) + predicted = prevByte; + else + { + const unsigned upperLeftByte = destData[i - width]; + const unsigned upperByte = destData[i - width + 3]; + predicted = prevByte + upperByte - upperLeftByte; + const int pa = abs((int)(predicted - prevByte)); + const int pb = abs((int)(predicted - upperByte)); + const int pc = abs((int)(predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + predicted = prevByte; + else + if (pb <= pc) + predicted = upperByte; + else + predicted = upperLeftByte; + } + destData[i] = prevByte = (Byte)(predicted - *(srcData++)); + } + } + if (dataSize < 3) + return; + const UInt32 border = dataSize - 2; + for (UInt32 i = posR; i < border; i += 3) + { + const Byte g = destData[i + 1]; + destData[i ] = (Byte)(destData[i ] + g); + destData[i + 2] = (Byte)(destData[i + 2] + g); + } +} + +#define my_abs(x) (unsigned)abs(x) + +static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels) +{ + Byte *destData = srcData + dataSize; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + UInt32 prevByte = 0, prevDelta = 0, dif[7]; + Int32 D1 = 0, D2 = 0, D3; + Int32 K1 = 0, K2 = 0, K3 = 0; + memset(dif, 0, sizeof(dif)); + + for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++) + { + D3 = D2; + D2 = (Int32)prevDelta - D1; + D1 = (Int32)prevDelta; + + UInt32 predicted = (UInt32)((Int32)(8 * prevByte) + K1 * D1 + K2 * D2 + K3 * D3); + predicted = (predicted >> 3) & 0xFF; + + const UInt32 curByte = *(srcData++); + + predicted -= curByte; + destData[i] = (Byte)predicted; + prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte); + prevByte = predicted; + + const Int32 D = ((Int32)(signed char)curByte) << 3; + + dif[0] += my_abs(D); + dif[1] += my_abs(D - D1); + dif[2] += my_abs(D + D1); + dif[3] += my_abs(D - D2); + dif[4] += my_abs(D + D2); + dif[5] += my_abs(D - D3); + dif[6] += my_abs(D + D3); + + if ((byteCount & 0x1F) == 0) + { + UInt32 minDif = dif[0], numMinDif = 0; + dif[0] = 0; + for (unsigned j = 1; j < Z7_ARRAY_SIZE(dif); j++) + { + if (dif[j] < minDif) + { + minDif = dif[j]; + numMinDif = j; + } + dif[j] = 0; + } + switch (numMinDif) + { + case 1: if (K1 >= -16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2 >= -16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3 >= -16) K3--; break; + case 6: if (K3 < 16) K3++; break; + } + } + } + } +} + +/* +static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize) +{ + UInt32 srcPos = 0, destPos = dataSize; + while (srcPos < dataSize) + { + Byte curByte = data[srcPos++]; + if (curByte == 2 && (curByte = data[srcPos++]) != 2) + curByte -= 32; + data[destPos++] = curByte; + } + return destPos - dataSize; +} +*/ + +bool CVm::ExecuteStandardFilter(unsigned filterIndex) +{ + const UInt32 dataSize = R[4]; + if (dataSize >= kGlobalOffset) + return false; + EStandardFilter filterType = kStdFilters[filterIndex].Type; + + switch (filterType) + { + case SF_E8: + case SF_E8E9: + E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9)); + break; + + case SF_ITANIUM: + ItaniumDecode(Mem, dataSize, R[6]); + break; + + case SF_DELTA: + { + if (dataSize >= kGlobalOffset / 2) + return false; + const UInt32 numChannels = R[0]; + if (numChannels == 0 || numChannels > 1024) // unrar 5.5.5 + return false; + SetBlockPos(dataSize); + DeltaDecode(Mem, dataSize, numChannels); + break; + } + + case SF_RGB: + { + if (dataSize >= kGlobalOffset / 2 || dataSize < 3) // unrar 5.5.5 + return false; + const UInt32 width = R[0]; + const UInt32 posR = R[1]; + if (width < 3 || width - 3 > dataSize || posR > 2) // unrar 5.5.5 + return false; + SetBlockPos(dataSize); + RgbDecode(Mem, dataSize, width, posR); + break; + } + + case SF_AUDIO: + { + if (dataSize >= kGlobalOffset / 2) + return false; + const UInt32 numChannels = R[0]; + if (numChannels == 0 || numChannels > 128) // unrar 5.5.5 + return false; + SetBlockPos(dataSize); + AudioDecode(Mem, dataSize, numChannels); + break; + } + + /* + case SF_UPCASE: + if (dataSize >= kGlobalOffset / 2) + return false; + UInt32 destSize = UpCaseDecode(Mem, dataSize); + SetBlockSize(destSize); + SetBlockPos(dataSize); + break; + */ + } + return true; +} + +#endif + +}}} diff --git a/CPP/7zip/Compress/Rar3Vm.h b/CPP/7zip/Compress/Rar3Vm.h index 50345d013..fde7e95ee 100644 --- a/CPP/7zip/Compress/Rar3Vm.h +++ b/CPP/7zip/Compress/Rar3Vm.h @@ -1,195 +1,195 @@ -// Rar3Vm.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef ZIP7_INC_COMPRESS_RAR3_VM_H -#define ZIP7_INC_COMPRESS_RAR3_VM_H - -#include "../../../C/CpuArch.h" - -#include "../../Common/MyVector.h" - -#define Z7_RARVM_STANDARD_FILTERS -// #define Z7_RARVM_VM_ENABLE - -namespace NCompress { -namespace NRar3 { - -class CMemBitDecoder -{ - const Byte *_data; - UInt32 _bitSize; - UInt32 _bitPos; -public: - void Init(const Byte *data, UInt32 byteSize) - { - _data = data; - _bitSize = (byteSize << 3); - _bitPos = 0; - } - UInt32 ReadBits(unsigned numBits); - UInt32 ReadBit(); - bool Avail() const { return (_bitPos < _bitSize); } - - UInt32 ReadEncodedUInt32(); -}; - -namespace NVm { - -inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); } -inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value) } - -const unsigned kNumRegBits = 3; -const UInt32 kNumRegs = 1 << kNumRegBits; -const UInt32 kNumGpRegs = kNumRegs - 1; - -const UInt32 kSpaceSize = 0x40000; -const UInt32 kSpaceMask = kSpaceSize - 1; -const UInt32 kGlobalOffset = 0x3C000; -const UInt32 kGlobalSize = 0x2000; -const UInt32 kFixedGlobalSize = 64; - -namespace NGlobalOffset -{ - const UInt32 kBlockSize = 0x1C; - const UInt32 kBlockPos = 0x20; - const UInt32 kExecCount = 0x2C; - const UInt32 kGlobalMemOutSize = 0x30; -} - - -#ifdef Z7_RARVM_VM_ENABLE - -enum ECommand -{ - CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC, - CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB, - CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT, - CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF, - CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT, - - CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB, - CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB, - CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB -}; - -enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE}; - -// Addr in COperand object can link (point) to CVm object!!! - -struct COperand -{ - EOpType Type; - UInt32 Data; - UInt32 Base; - COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {} -}; - -struct CCommand -{ - ECommand OpCode; - bool ByteMode; - COperand Op1, Op2; -}; - -#endif - - -struct CBlockRef -{ - UInt32 Offset; - UInt32 Size; -}; - - -class CProgram -{ - #ifdef Z7_RARVM_VM_ENABLE - void ReadProgram(const Byte *code, UInt32 codeSize); -public: - CRecordVector Commands; - #endif - -public: - #ifdef Z7_RARVM_STANDARD_FILTERS - int StandardFilterIndex; - #endif - - bool IsSupported; - CRecordVector StaticData; - - bool PrepareProgram(const Byte *code, UInt32 codeSize); -}; - - -struct CProgramInitState -{ - UInt32 InitR[kNumGpRegs]; - CRecordVector GlobalData; - - void AllocateEmptyFixedGlobal() - { - GlobalData.ClearAndSetSize(NVm::kFixedGlobalSize); - memset(&GlobalData[0], 0, NVm::kFixedGlobalSize); - } -}; - - -class CVm -{ - static UInt32 GetValue(bool byteMode, const void *addr) - { - if (byteMode) - return(*(const Byte *)addr); - else - return GetUi32(addr); - } - - static void SetValue(bool byteMode, void *addr, UInt32 value) - { - if (byteMode) - *(Byte *)addr = (Byte)value; - else - SetUi32(addr, value) - } - - UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); } - - void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); } - void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); } -public: - static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); } - -private: - - #ifdef Z7_RARVM_VM_ENABLE - UInt32 GetOperand32(const COperand *op) const; - void SetOperand32(const COperand *op, UInt32 val); - Byte GetOperand8(const COperand *op) const; - void SetOperand8(const COperand *op, Byte val); - UInt32 GetOperand(bool byteMode, const COperand *op) const; - void SetOperand(bool byteMode, const COperand *op, UInt32 val); - bool ExecuteCode(const CProgram *prg); - #endif - - #ifdef Z7_RARVM_STANDARD_FILTERS - bool ExecuteStandardFilter(unsigned filterIndex); - #endif - - Byte *Mem; - UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization) - UInt32 Flags; - -public: - CVm(); - ~CVm(); - bool Create(); - void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize); - bool Execute(CProgram *prg, const CProgramInitState *initState, - CBlockRef &outBlockRef, CRecordVector &outGlobalData); - const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; } -}; - -#endif - -}}} +// Rar3Vm.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef ZIP7_INC_COMPRESS_RAR3_VM_H +#define ZIP7_INC_COMPRESS_RAR3_VM_H + +#include "../../../C/CpuArch.h" + +#include "../../Common/MyVector.h" + +#define Z7_RARVM_STANDARD_FILTERS +// #define Z7_RARVM_VM_ENABLE + +namespace NCompress { +namespace NRar3 { + +class CMemBitDecoder +{ + const Byte *_data; + UInt32 _bitSize; + UInt32 _bitPos; +public: + void Init(const Byte *data, UInt32 byteSize) + { + _data = data; + _bitSize = (byteSize << 3); + _bitPos = 0; + } + UInt32 ReadBits(unsigned numBits); + UInt32 ReadBit(); + bool Avail() const { return (_bitPos < _bitSize); } + + UInt32 ReadEncodedUInt32(); +}; + +namespace NVm { + +inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); } +inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value) } + +const unsigned kNumRegBits = 3; +const UInt32 kNumRegs = 1 << kNumRegBits; +const UInt32 kNumGpRegs = kNumRegs - 1; + +const UInt32 kSpaceSize = 0x40000; +const UInt32 kSpaceMask = kSpaceSize - 1; +const UInt32 kGlobalOffset = 0x3C000; +const UInt32 kGlobalSize = 0x2000; +const UInt32 kFixedGlobalSize = 64; + +namespace NGlobalOffset +{ + const UInt32 kBlockSize = 0x1C; + const UInt32 kBlockPos = 0x20; + const UInt32 kExecCount = 0x2C; + const UInt32 kGlobalMemOutSize = 0x30; +} + + +#ifdef Z7_RARVM_VM_ENABLE + +enum ECommand +{ + CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC, + CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB, + CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT, + CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF, + CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT, + + CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB, + CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB, + CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB +}; + +enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE}; + +// Addr in COperand object can link (point) to CVm object!!! + +struct COperand +{ + EOpType Type; + UInt32 Data; + UInt32 Base; + COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {} +}; + +struct CCommand +{ + ECommand OpCode; + bool ByteMode; + COperand Op1, Op2; +}; + +#endif + + +struct CBlockRef +{ + UInt32 Offset; + UInt32 Size; +}; + + +class CProgram +{ + #ifdef Z7_RARVM_VM_ENABLE + void ReadProgram(const Byte *code, UInt32 codeSize); +public: + CRecordVector Commands; + #endif + +public: + #ifdef Z7_RARVM_STANDARD_FILTERS + int StandardFilterIndex; + #endif + + bool IsSupported; + CRecordVector StaticData; + + bool PrepareProgram(const Byte *code, UInt32 codeSize); +}; + + +struct CProgramInitState +{ + UInt32 InitR[kNumGpRegs]; + CRecordVector GlobalData; + + void AllocateEmptyFixedGlobal() + { + GlobalData.ClearAndSetSize(NVm::kFixedGlobalSize); + memset(&GlobalData[0], 0, NVm::kFixedGlobalSize); + } +}; + + +class CVm +{ + static UInt32 GetValue(bool byteMode, const void *addr) + { + if (byteMode) + return(*(const Byte *)addr); + else + return GetUi32(addr); + } + + static void SetValue(bool byteMode, void *addr, UInt32 value) + { + if (byteMode) + *(Byte *)addr = (Byte)value; + else + SetUi32(addr, value) + } + + UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); } + + void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); } + void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); } +public: + static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); } + +private: + + #ifdef Z7_RARVM_VM_ENABLE + UInt32 GetOperand32(const COperand *op) const; + void SetOperand32(const COperand *op, UInt32 val); + Byte GetOperand8(const COperand *op) const; + void SetOperand8(const COperand *op, Byte val); + UInt32 GetOperand(bool byteMode, const COperand *op) const; + void SetOperand(bool byteMode, const COperand *op, UInt32 val); + bool ExecuteCode(const CProgram *prg); + #endif + + #ifdef Z7_RARVM_STANDARD_FILTERS + bool ExecuteStandardFilter(unsigned filterIndex); + #endif + + Byte *Mem; + UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization) + UInt32 Flags; + +public: + CVm(); + ~CVm(); + bool Create(); + void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize); + bool Execute(CProgram *prg, const CProgramInitState *initState, + CBlockRef &outBlockRef, CRecordVector &outGlobalData); + const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; } +}; + +#endif + +}}} diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp index 1a241a2f5..8be24e26d 100644 --- a/CPP/7zip/Compress/Rar5Decoder.cpp +++ b/CPP/7zip/Compress/Rar5Decoder.cpp @@ -1,2023 +1,2023 @@ -// Rar5Decoder.cpp -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#include "StdAfx.h" - -#define DICT_SIZE_MAX ((UInt64)1 << DICT_SIZE_BITS_MAX) - -// #include // SSE2 -// #endif - -#include "../../../C/CpuArch.h" -#if 0 -#include "../../../C/Bra.h" -#endif - -#if defined(MY_CPU_ARM64) -#include -#endif - -// #define Z7_RAR5_SHOW_STAT -// #include -#ifdef Z7_RAR5_SHOW_STAT -#include -#endif - -#include "../Common/StreamUtils.h" - -#include "Rar5Decoder.h" - -/* -Note: original-unrar claims that encoder has limitation for Distance: - (Distance <= MaxWinSize - MAX_INC_LZ_MATCH) - MAX_INC_LZ_MATCH = 0x1001 + 3; -*/ - -#define LZ_ERROR_TYPE_NO 0 -#define LZ_ERROR_TYPE_HEADER 1 -// #define LZ_ERROR_TYPE_SYM 1 -#define LZ_ERROR_TYPE_DIST 2 - -static -void My_ZeroMemory(void *p, size_t size) -{ - #if defined(MY_CPU_AMD64) && !defined(_M_ARM64EC) \ - && defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL <= 1400) - // __stosq((UInt64 *)(void *)win, 0, size / 8); - /* - printf("\n__stosb \n"); - #define STEP_BIG (1 << 28) - for (size_t i = 0; i < ((UInt64)1 << 50); i += STEP_BIG) - { - printf("\n__stosb end %p\n", (void *)i); - __stosb((Byte *)p + i, 0, STEP_BIG); - } - */ - // __stosb((Byte *)p, 0, 0); - __stosb((Byte *)p, 0, size); - #else - // SecureZeroMemory (win, STEP); - // ZeroMemory(win, STEP); - // memset(win, 0, STEP); - memset(p, 0, size); - #endif -} - - - -#ifdef MY_CPU_LE_UNALIGN - #define Z7_RAR5_DEC_USE_UNALIGNED_COPY -#endif - -#ifdef Z7_RAR5_DEC_USE_UNALIGNED_COPY - - #define COPY_CHUNK_SIZE 16 - - #define COPY_CHUNK_4_2(dest, src) \ - { \ - ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \ - ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \ - src += 4 * 2; \ - dest += 4 * 2; \ - } - - /* sse2 doesn't help here in GCC and CLANG. - so we disabled sse2 here */ -#if 0 - #if defined(MY_CPU_AMD64) - #define Z7_RAR5_DEC_USE_SSE2 - #elif defined(MY_CPU_X86) - #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ - || defined(__SSE2__) \ - // || 1 == 1 // for debug only - #define Z7_RAR5_DEC_USE_SSE2 - #endif - #endif -#endif - - #if defined(MY_CPU_ARM64) - - #define COPY_OFFSET_MIN 16 - #define COPY_CHUNK1(dest, src) \ - { \ - vst1q_u8((uint8_t *)(void *)dest, \ - vld1q_u8((const uint8_t *)(const void *)src)); \ - src += 16; \ - dest += 16; \ - } - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK1(dest, src) \ - if (dest >= lim) break; \ - COPY_CHUNK1(dest, src) \ - } - - #elif defined(Z7_RAR5_DEC_USE_SSE2) - #include // sse2 - #define COPY_OFFSET_MIN 16 - - #define COPY_CHUNK1(dest, src) \ - { \ - _mm_storeu_si128((__m128i *)(void *)dest, \ - _mm_loadu_si128((const __m128i *)(const void *)src)); \ - src += 16; \ - dest += 16; \ - } - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK1(dest, src) \ - if (dest >= lim) break; \ - COPY_CHUNK1(dest, src) \ - } - - #elif defined(MY_CPU_64BIT) - #define COPY_OFFSET_MIN 8 - - #define COPY_CHUNK(dest, src) \ - { \ - ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ - src += 8 * 1; dest += 8 * 1; \ - ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ - src += 8 * 1; dest += 8 * 1; \ - } - - #else - #define COPY_OFFSET_MIN 4 - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK_4_2(dest, src); \ - COPY_CHUNK_4_2(dest, src); \ - } - - #endif -#endif - - -#ifndef COPY_CHUNK_SIZE - #define COPY_OFFSET_MIN 4 - #define COPY_CHUNK_SIZE 8 - #define COPY_CHUNK_2(dest, src) \ - { \ - const Byte a0 = src[0]; \ - const Byte a1 = src[1]; \ - dest[0] = a0; \ - dest[1] = a1; \ - src += 2; \ - dest += 2; \ - } - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - } -#endif - - -#define COPY_CHUNKS \ -{ \ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ - do { COPY_CHUNK(dest, src) } \ - while (dest < lim); \ -} - -namespace NCompress { -namespace NRar5 { - -typedef -#if 1 - unsigned -#else - size_t -#endif - CLenType; - -// (len != 0) -static -Z7_FORCE_INLINE -// Z7_ATTRIB_NO_VECTOR -void CopyMatch(size_t offset, Byte *dest, const Byte *src, const Byte *lim) -{ - { - // (COPY_OFFSET_MIN >= 4) - if (offset >= COPY_OFFSET_MIN) - { - COPY_CHUNKS - // return; - } - else - #if (COPY_OFFSET_MIN > 4) - #if COPY_CHUNK_SIZE < 8 - #error Stop_Compiling_Bad_COPY_CHUNK_SIZE - #endif - if (offset >= 4) - { - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - COPY_CHUNK_4_2(dest, src) - #if COPY_CHUNK_SIZE < 16 - if (dest >= lim) break; - #endif - COPY_CHUNK_4_2(dest, src) - } - while (dest < lim); - // return; - } - else - #endif - { - // (offset < 4) - const unsigned b0 = src[0]; - if (offset < 2) - { - #if defined(Z7_RAR5_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16) - #if defined(MY_CPU_64BIT) - { - const UInt64 v64 = (UInt64)b0 * 0x0101010101010101; - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - ((UInt64 *)(void *)dest)[0] = v64; - ((UInt64 *)(void *)dest)[1] = v64; - dest += 16; - } - while (dest < lim); - } - #else - { - UInt32 v = b0; - v |= v << 8; - v |= v << 16; - do - { - ((UInt32 *)(void *)dest)[0] = v; - ((UInt32 *)(void *)dest)[1] = v; - dest += 8; - ((UInt32 *)(void *)dest)[0] = v; - ((UInt32 *)(void *)dest)[1] = v; - dest += 8; - } - while (dest < lim); - } - #endif - #else - do - { - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += 2; - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += 2; - } - while (dest < lim); - #endif - } - else if (offset == 2) - { - const Byte b1 = src[1]; - { - do - { - dest[0] = (Byte)b0; - dest[1] = b1; - dest += 2; - } - while (dest < lim); - } - } - else // (offset == 3) - { - const Byte b1 = src[1]; - const Byte b2 = src[2]; - do - { - dest[0] = (Byte)b0; - dest[1] = b1; - dest[2] = b2; - dest += 3; - } - while (dest < lim); - } - } - } -} - -static const size_t kInputBufSize = 1 << 20; -static const UInt32 k_Filter_BlockSize_MAX = 1 << 22; -static const unsigned k_Filter_AfterPad_Size = 64; - -#ifdef Z7_RAR5_SHOW_STAT -static const unsigned kNumStats1 = 10; -static const unsigned kNumStats2 = (1 << 12) + 16; -static UInt32 g_stats1[kNumStats1]; -static UInt32 g_stats2[kNumStats1][kNumStats2]; -#endif - -#if 1 -MY_ALIGN(32) -// DICT_SIZE_BITS_MAX-1 are required -static const Byte k_LenPlusTable[DICT_SIZE_BITS_MAX] = - { 0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }; -#endif - - - -class CBitDecoder -{ -public: - const Byte *_buf; - const Byte *_bufCheck_Block; // min(ptr for _blockEnd, _bufCheck) - unsigned _bitPos; // = [0 ... 7] - bool _wasFinished; - bool _minorError; - unsigned _blockEndBits7; // = [0 ... 7] : the number of additional bits in (_blockEnd) poisition. - HRESULT _hres; - const Byte *_bufCheck; // relaxed limit (16 bytes before real end of input data in buffer) - Byte *_bufLim; // end if input data - Byte *_bufBase; - ISequentialInStream *_stream; - - UInt64 _processedSize; - UInt64 _blockEnd; // absolute end of current block - // but it doesn't include additional _blockEndBits7 [0 ... 7] bits - - Z7_FORCE_INLINE - void CopyFrom(const CBitDecoder &a) - { - _buf = a._buf; - _bufCheck_Block = a._bufCheck_Block; - _bitPos = a._bitPos; - _wasFinished = a._wasFinished; - _blockEndBits7 = a._blockEndBits7; - _bufCheck = a._bufCheck; - _bufLim = a._bufLim; - _bufBase = a._bufBase; - - _processedSize = a._processedSize; - _blockEnd = a._blockEnd; - } - - Z7_FORCE_INLINE - void RestoreFrom2(const CBitDecoder &a) - { - _buf = a._buf; - _bitPos = a._bitPos; - } - - Z7_FORCE_INLINE - void SetCheck_forBlock() - { - _bufCheck_Block = _bufCheck; - if (_bufCheck > _buf) - { - const UInt64 processed = GetProcessedSize_Round(); - if (_blockEnd < processed) - _bufCheck_Block = _buf; - else - { - const UInt64 delta = _blockEnd - processed; - if ((size_t)(_bufCheck - _buf) > delta) - _bufCheck_Block = _buf + (size_t)delta; - } - } - } - - Z7_FORCE_INLINE - bool IsBlockOverRead() const - { - const UInt64 v = GetProcessedSize_Round(); - if (v < _blockEnd) return false; - if (v > _blockEnd) return true; - return _bitPos > _blockEndBits7; - } - - /* - CBitDecoder() throw(): - _buf(0), - _bufLim(0), - _bufBase(0), - _stream(0), - _processedSize(0), - _wasFinished(false) - {} - */ - - Z7_FORCE_INLINE - void Init() throw() - { - _blockEnd = 0; - _blockEndBits7 = 0; - - _bitPos = 0; - _processedSize = 0; - _buf = _bufBase; - _bufLim = _bufBase; - _bufCheck = _buf; - _bufCheck_Block = _buf; - _wasFinished = false; - _minorError = false; - } - - void Prepare2() throw(); - - Z7_FORCE_INLINE - void Prepare() throw() - { - if (_buf >= _bufCheck) - Prepare2(); - } - - Z7_FORCE_INLINE - bool ExtraBitsWereRead() const - { - return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0); - } - - Z7_FORCE_INLINE bool InputEofError() const { return ExtraBitsWereRead(); } - - Z7_FORCE_INLINE unsigned GetProcessedBits7() const { return _bitPos; } - Z7_FORCE_INLINE UInt64 GetProcessedSize_Round() const { return _processedSize + (size_t)(_buf - _bufBase); } - Z7_FORCE_INLINE UInt64 GetProcessedSize() const { return _processedSize + (size_t)(_buf - _bufBase) + ((_bitPos + 7) >> 3); } - - Z7_FORCE_INLINE - void AlignToByte() - { - if (_bitPos != 0) - { -#if 1 - // optional check of unused bits for strict checking: - // original-unrar doesn't check it: - const unsigned b = (unsigned)*_buf << _bitPos; - if (b & 0xff) - _minorError = true; -#endif - _buf++; - _bitPos = 0; - } - // _buf += (_bitPos + 7) >> 3; - // _bitPos = 0; - } - - Z7_FORCE_INLINE - Byte ReadByte_InAligned() - { - return *_buf++; - } - - Z7_FORCE_INLINE - UInt32 GetValue(unsigned numBits) const - { - // 0 < numBits <= 17 : supported values -#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE_UNALIGN) - UInt32 v = GetBe32(_buf); -#if 1 - return (v >> (32 - numBits - _bitPos)) & ((1u << numBits) - 1); -#else - return (v << _bitPos) >> (32 - numBits); -#endif -#else - UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2]; - v >>= 24 - numBits - _bitPos; - return v & ((1 << numBits) - 1); -#endif - } - - Z7_FORCE_INLINE - UInt32 GetValue_InHigh32bits() const - { - // 0 < numBits <= 17 : supported vales -#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE_UNALIGN) - return GetBe32(_buf) << _bitPos; -#else - const UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2]; - return v << (_bitPos + 8); -#endif - } - - - Z7_FORCE_INLINE - void MovePos(unsigned numBits) - { - numBits += _bitPos; - _buf += numBits >> 3; - _bitPos = numBits & 7; - } - - - Z7_FORCE_INLINE - UInt32 ReadBits9(unsigned numBits) - { - const Byte *buf = _buf; - UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; - v &= (UInt32)0xFFFF >> _bitPos; - numBits += _bitPos; - v >>= 16 - numBits; - _buf = buf + (numBits >> 3); - _bitPos = numBits & 7; - return v; - } - - Z7_FORCE_INLINE - UInt32 ReadBits_9fix(unsigned numBits) - { - const Byte *buf = _buf; - UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; - const UInt32 mask = (1u << numBits) - 1; - numBits += _bitPos; - v >>= 16 - numBits; - _buf = buf + (numBits >> 3); - _bitPos = numBits & 7; - return v & mask; - } - -#if 1 && defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 8) -#define Z7_RAR5_USE_64BIT -#endif - -#ifdef Z7_RAR5_USE_64BIT -#define MAX_DICT_LOG (sizeof(size_t) / 8 * 5 + 31) -#else -#define MAX_DICT_LOG 31 -#endif - -#ifdef Z7_RAR5_USE_64BIT - - Z7_FORCE_INLINE - size_t ReadBits_Big(unsigned numBits, UInt64 v) - { - const UInt64 mask = ((UInt64)1 << numBits) - 1; - numBits += _bitPos; - const Byte *buf = _buf; - // UInt64 v = GetBe64(buf); - v >>= 64 - numBits; - _buf = buf + (numBits >> 3); - _bitPos = numBits & 7; - return (size_t)(v & mask); - } - #define ReadBits_Big25 ReadBits_Big - -#else - - // (numBits <= 25) for 32-bit mode - Z7_FORCE_INLINE - size_t ReadBits_Big25(unsigned numBits, UInt32 v) - { - const UInt32 mask = ((UInt32)1 << numBits) - 1; - numBits += _bitPos; - v >>= 32 - numBits; - _buf += numBits >> 3; - _bitPos = numBits & 7; - return v & mask; - } - - // numBits != 0 - Z7_FORCE_INLINE - size_t ReadBits_Big(unsigned numBits, UInt32 v) - { - const Byte *buf = _buf; - // UInt32 v = GetBe32(buf); -#if 0 - const UInt32 mask = ((UInt32)1 << numBits) - 1; - numBits += _bitPos; - if (numBits > 32) - { - v <<= numBits - 32; - v |= (UInt32)buf[4] >> (40 - numBits); - } - else - v >>= 32 - numBits; - _buf = buf + (numBits >> 3); - _bitPos = numBits & 7; - return v & mask; -#else - v <<= _bitPos; - v |= (UInt32)buf[4] >> (8 - _bitPos); - v >>= 32 - numBits; - numBits += _bitPos; - _buf = buf + (numBits >> 3); - _bitPos = numBits & 7; - return v; -#endif - } -#endif -}; - - -static const unsigned kLookaheadSize = 16; -static const unsigned kInputBufferPadZone = kLookaheadSize; - -Z7_NO_INLINE -void CBitDecoder::Prepare2() throw() -{ - if (_buf > _bufLim) - return; - - size_t rem = (size_t)(_bufLim - _buf); - if (rem != 0) - memmove(_bufBase, _buf, rem); - - _bufLim = _bufBase + rem; - _processedSize += (size_t)(_buf - _bufBase); - _buf = _bufBase; - - // we do not look ahead more than 16 bytes before limit checks. - - if (!_wasFinished) - { - while (rem <= kLookaheadSize) - { - UInt32 processed = (UInt32)(kInputBufSize - rem); - // processed = 33; // for debug - _hres = _stream->Read(_bufLim, processed, &processed); - _bufLim += processed; - rem += processed; - if (processed == 0 || _hres != S_OK) - { - _wasFinished = true; - // if (_hres != S_OK) throw CInBufferException(result); - break; - } - } - } - - // we always fill pad zone here. - // so we don't need to call Prepare2() if (_wasFinished == true) - memset(_bufLim, 0xFF, kLookaheadSize); - - if (rem < kLookaheadSize) - { - _bufCheck = _buf; - // memset(_bufLim, 0xFF, kLookaheadSize - rem); - } - else - _bufCheck = _bufLim - kLookaheadSize; - - SetCheck_forBlock(); -} - - -enum FilterType -{ - FILTER_DELTA = 0, - FILTER_E8, - FILTER_E8E9, - FILTER_ARM -}; - -static const size_t kWriteStep = (size_t)1 << 18; - // (size_t)1 << 22; // original-unrar - -// Original unRAR claims that maximum possible filter block size is (1 << 16) now, -// and (1 << 17) is minimum win size required to support filter. -// Original unRAR uses (1u << 18) for "extra safety and possible filter area size expansion" -// We can use any win size, but we use same (1u << 18) for compatibility -// with WinRar - -// static const unsigned kWinSize_Log_Min = 17; -static const size_t kWinSize_Min = 1u << 18; - -CDecoder::CDecoder(): - _isSolid(false), - _is_v7(false), - _wasInit(false), - // _dictSizeLog(0), - _dictSize(kWinSize_Min), - _window(NULL), - _winPos(0), - _winSize(0), - _dictSize_forCheck(0), - _lzSize(0), - _lzEnd(0), - _writtenFileSize(0), - _filters(NULL), - _winSize_Allocated(0), - _inputBuf(NULL) -{ -#if 1 - memcpy(m_LenPlusTable, k_LenPlusTable, sizeof(k_LenPlusTable)); -#endif - // printf("\nsizeof(CDecoder) == %d\n", sizeof(CDecoder)); -} - -CDecoder::~CDecoder() -{ -#ifdef Z7_RAR5_SHOW_STAT - printf("\n%4d :", 0); - for (unsigned k = 0; k < kNumStats1; k++) - printf(" %8u", (unsigned)g_stats1[k]); - printf("\n"); - for (unsigned i = 0; i < kNumStats2; i++) - { - printf("\n%4d :", i); - for (unsigned k = 0; k < kNumStats1; k++) - printf(" %8u", (unsigned)g_stats2[k][i]); - } - printf("\n"); -#endif - -#define Z7_RAR_FREE_WINDOW ::BigFree(_window); - - Z7_RAR_FREE_WINDOW - z7_AlignedFree(_inputBuf); - z7_AlignedFree(_filters); -} - -Z7_NO_INLINE -void CDecoder::DeleteUnusedFilters() -{ - if (_numUnusedFilters != 0) - { - // printf("\nDeleteUnusedFilters _numFilters = %6u\n", _numFilters); - const unsigned n = _numFilters - _numUnusedFilters; - _numFilters = n; - memmove(_filters, _filters + _numUnusedFilters, n * sizeof(CFilter)); - _numUnusedFilters = 0; - } -} - - -Z7_NO_INLINE -HRESULT CDecoder::WriteData(const Byte *data, size_t size) -{ - HRESULT res = S_OK; - if (!_unpackSize_Defined || _writtenFileSize < _unpackSize) - { - size_t cur = size; - if (_unpackSize_Defined) - { - const UInt64 rem = _unpackSize - _writtenFileSize; - if (cur > rem) - cur = (size_t)rem; - } - res = WriteStream(_outStream, data, cur); - if (res != S_OK) - _writeError = true; - } - _writtenFileSize += size; - return res; -} - - -#if defined(MY_CPU_SIZEOF_POINTER) \ - && ( MY_CPU_SIZEOF_POINTER == 4 \ - || MY_CPU_SIZEOF_POINTER == 8) - #define BR_CONV_USE_OPT_PC_PTR -#endif - -#ifdef BR_CONV_USE_OPT_PC_PTR -#define BR_PC_INIT(lim_back) pc -= (UInt32)(SizeT)data; -#define BR_PC_GET (pc + (UInt32)(SizeT)data) -#else -#define BR_PC_INIT(lim_back) pc += (UInt32)dataSize - (lim_back); -#define BR_PC_GET (pc - (UInt32)(SizeT)(data_lim - data)) -#endif - -#ifdef MY_CPU_LE_UNALIGN -#define Z7_RAR5_FILTER_USE_LE_UNALIGN -#endif - -#ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN -#define RAR_E8_FILT(mask) \ -{ \ - for (;;) \ - { UInt32 v; \ - do { \ - v = GetUi32(data) ^ (UInt32)0xe8e8e8e8; \ - data += 4; \ - if ((v & ((UInt32)(mask) << (8 * 0))) == 0) { data -= 3; break; } \ - if ((v & ((UInt32)(mask) << (8 * 1))) == 0) { data -= 2; break; } \ - if ((v & ((UInt32)(mask) << (8 * 2))) == 0) { data -= 1; break; } } \ - while((v & ((UInt32)(mask) << (8 * 3)))); \ - if (data > data_lim) break; \ - const UInt32 offset = BR_PC_GET & (kFileSize - 1); \ - const UInt32 addr = GetUi32(data); \ - data += 4; \ - if (addr < kFileSize) \ - SetUi32(data - 4, addr - offset) \ - else if (addr > ~offset) /* if (addr > ((UInt32)0xFFFFFFFF - offset)) */ \ - SetUi32(data - 4, addr + kFileSize) \ - } \ -} -#else -#define RAR_E8_FILT(get_byte) \ -{ \ - for (;;) \ - { \ - if ((get_byte) != 0xe8) \ - if ((get_byte) != 0xe8) \ - if ((get_byte) != 0xe8) \ - if ((get_byte) != 0xe8) \ - continue; \ - { if (data > data_lim) break; \ - const UInt32 offset = BR_PC_GET & (kFileSize - 1); \ - const UInt32 addr = GetUi32(data); \ - data += 4; \ - if (addr < kFileSize) \ - SetUi32(data - 4, addr - offset) \ - else if (addr > ~offset) /* if (addr > ((UInt32)0xFFFFFFFF - offset)) */ \ - SetUi32(data - 4, addr + kFileSize) \ - } \ - } \ -} -#endif - -HRESULT CDecoder::ExecuteFilter(const CFilter &f) -{ - Byte *data = _filterSrc; - UInt32 dataSize = f.Size; - // printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize); - - if (f.Type == FILTER_DELTA) - { - // static unsigned g1 = 0, g2 = 0; g1 += dataSize; - // if (g2++ % 100 == 0) printf("DELTA num %8u, size %8u MiB, channels = %2u curSize=%8u\n", g2, (g1 >> 20), f.Channels, dataSize); - _filterDst.AllocAtLeast_max((size_t)dataSize, k_Filter_BlockSize_MAX); - if (!_filterDst.IsAllocated()) - return E_OUTOFMEMORY; - - Byte *dest = _filterDst; - const unsigned numChannels = f.Channels; - unsigned curChannel = 0; - do - { - Byte prevByte = 0; - Byte *dest2 = dest + curChannel; - const Byte *dest_lim = dest + dataSize; - for (; dest2 < dest_lim; dest2 += numChannels) - *dest2 = (prevByte = (Byte)(prevByte - *data++)); - } - while (++curChannel != numChannels); - // return WriteData(dest, dataSize); - data = dest; - } - else if (f.Type < FILTER_ARM) - { - // FILTER_E8 or FILTER_E8E9 - if (dataSize > 4) - { - UInt32 pc = (UInt32)(f.Start - _lzFileStart); - const UInt32 kFileSize = (UInt32)1 << 24; - const Byte *data_lim = data + dataSize - 4; - BR_PC_INIT(4) // because (data_lim) was moved back for 4 bytes - data[dataSize] = 0xe8; - if (f.Type == FILTER_E8) - { - // static unsigned g1 = 0; g1 += dataSize; printf("\n FILTER_E8 %u", (g1 >> 20)); -#ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN - RAR_E8_FILT (0xff) -#else - RAR_E8_FILT (*data++) -#endif - } - else - { - // static unsigned g1 = 0; g1 += dataSize; printf("\n FILTER_E8_E9 %u", (g1 >> 20)); -#ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN - RAR_E8_FILT (0xfe) -#else - RAR_E8_FILT (*data++ & 0xfe) -#endif - } - } - data = _filterSrc; - } - else if (f.Type == FILTER_ARM) - { - UInt32 pc = (UInt32)(f.Start - _lzFileStart); -#if 0 - // z7_BranchConv_ARM_Dec expects that (fileOffset & 3) == 0; - // but even if (fileOffset & 3) then current code - // in z7_BranchConv_ARM_Dec works same way as unrar's code still. - z7_BranchConv_ARM_Dec(data, dataSize, pc - 8); -#else - dataSize &= ~(UInt32)3; - if (dataSize) - { - Byte *data_lim = data + dataSize; - data_lim[3] = 0xeb; - BR_PC_INIT(0) - pc -= 4; // because (data) will point to next instruction - for (;;) // do - { - data += 4; - if (data[-1] != 0xeb) - continue; - if (data > data_lim) - break; - { - UInt32 v = GetUi32a(data - 4) - (BR_PC_GET >> 2); - v &= 0x00ffffff; - v |= 0xeb000000; - SetUi32a(data - 4, v) - } - } - } -#endif - data = _filterSrc; - } - else - { - _unsupportedFilter = true; - My_ZeroMemory(data, dataSize); - // return S_OK; // unrar - } - // return WriteData(_filterSrc, (size_t)f.Size); - return WriteData(data, (size_t)f.Size); -} - - -HRESULT CDecoder::WriteBuf() -{ - DeleteUnusedFilters(); - - const UInt64 lzSize = _lzSize + _winPos; - - for (unsigned i = 0; i < _numFilters;) - { - const CFilter &f = _filters[i]; - const UInt64 blockStart = f.Start; - const size_t lzAvail = (size_t)(lzSize - _lzWritten); - if (lzAvail == 0) - break; - - if (blockStart > _lzWritten) - { - const UInt64 rem = blockStart - _lzWritten; - size_t size = lzAvail; - if (size > rem) - size = (size_t)rem; - if (size != 0) // is it true always ? - { - RINOK(WriteData(_window + _winPos - lzAvail, size)) - _lzWritten += size; - } - continue; - } - - const UInt32 blockSize = f.Size; - size_t offset = (size_t)(_lzWritten - blockStart); - if (offset == 0) - { - _filterSrc.AllocAtLeast_max( - (size_t)blockSize + k_Filter_AfterPad_Size, - k_Filter_BlockSize_MAX + k_Filter_AfterPad_Size); - if (!_filterSrc.IsAllocated()) - return E_OUTOFMEMORY; - } - - const size_t blockRem = (size_t)blockSize - offset; - size_t size = lzAvail; - if (size > blockRem) - size = blockRem; - memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size); - _lzWritten += size; - offset += size; - if (offset != blockSize) - return S_OK; - - _numUnusedFilters = ++i; - RINOK(ExecuteFilter(f)) - } - - DeleteUnusedFilters(); - - if (_numFilters) - return S_OK; - - const size_t lzAvail = (size_t)(lzSize - _lzWritten); - RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)) - _lzWritten += lzAvail; - return S_OK; -} - - -Z7_NO_INLINE -static UInt32 ReadUInt32(CBitDecoder &bi) -{ - const unsigned numBits = (unsigned)bi.ReadBits_9fix(2) * 8 + 8; - UInt32 v = 0; - unsigned i = 0; - do - { - v += (UInt32)bi.ReadBits_9fix(8) << i; - i += 8; - } - while (i != numBits); - return v; -} - - -static const unsigned MAX_UNPACK_FILTERS = 8192; - -HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream) -{ - DeleteUnusedFilters(); - - if (_numFilters >= MAX_UNPACK_FILTERS) - { - RINOK(WriteBuf()) - DeleteUnusedFilters(); - if (_numFilters >= MAX_UNPACK_FILTERS) - { - _unsupportedFilter = true; - InitFilters(); - } - } - - _bitStream.Prepare(); - - CFilter f; - const UInt32 blockStart = ReadUInt32(_bitStream); - f.Size = ReadUInt32(_bitStream); - - if (f.Size > k_Filter_BlockSize_MAX) - { - _unsupportedFilter = true; - f.Size = 0; // unrar 5.5.5 - } - - f.Type = (Byte)_bitStream.ReadBits_9fix(3); - f.Channels = 0; - if (f.Type == FILTER_DELTA) - f.Channels = (Byte)(_bitStream.ReadBits_9fix(5) + 1); - f.Start = _lzSize + _winPos + blockStart; - -#if 0 - static unsigned z_cnt = 0; if (z_cnt++ % 100 == 0) - printf ("\nFilter %7u : %4u : %8p, st=%8x, size=%8x, type=%u ch=%2u", - z_cnt, (unsigned)_filters.Size(), (void *)(size_t)(_lzSize + _winPos), - (unsigned)blockStart, (unsigned)f.Size, (unsigned)f.Type, (unsigned)f.Channels); -#endif - - if (f.Start < _filterEnd) - _unsupportedFilter = true; - else - { - _filterEnd = f.Start + f.Size; - if (f.Size != 0) - { - if (!_filters) - { - _filters = (CFilter *)z7_AlignedAlloc(MAX_UNPACK_FILTERS * sizeof(CFilter)); - if (!_filters) - return E_OUTOFMEMORY; - } - // printf("\n_numFilters = %6u\n", _numFilters); - const unsigned i = _numFilters++; - _filters[i] = f; - } - } - - return S_OK; -} - - -#define RIF(x) { if (!(x)) return S_FALSE; } - -#if 1 -#define PRINT_CNT(name, skip) -#else -#define PRINT_CNT(name, skip) \ - { static unsigned g_cnt = 0; if (g_cnt++ % skip == 0) printf("\n%16s: %8u", name, g_cnt); } -#endif - -HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) -{ - if (_progress) - { - const UInt64 packSize = _bitStream.GetProcessedSize(); - if (packSize - _progress_Pack >= (1u << 24) - || _writtenFileSize - _progress_Unpack >= (1u << 26)) - { - _progress_Pack = packSize; - _progress_Unpack = _writtenFileSize; - RINOK(_progress->SetRatioInfo(&_progress_Pack, &_writtenFileSize)) - } - // printf("\ntable read pos=%p packSize=%p _writtenFileSize = %p\n", (size_t)_winPos, (size_t)packSize, (size_t)_writtenFileSize); - } - - // _bitStream is aligned already - _bitStream.Prepare(); - { - const unsigned flags = _bitStream.ReadByte_InAligned(); - /* ((flags & 20) == 0) in all rar archives now, - but (flags & 20) flag can be used as some decoding hint in future versions of original rar. - So we ignore that bit here. */ - unsigned checkSum = _bitStream.ReadByte_InAligned(); - checkSum ^= flags; - const unsigned num = (flags >> 3) & 3; - if (num >= 3) - return S_FALSE; - UInt32 blockSize = _bitStream.ReadByte_InAligned(); - checkSum ^= blockSize; - if (num != 0) - { - { - const unsigned b = _bitStream.ReadByte_InAligned(); - checkSum ^= b; - blockSize += (UInt32)b << 8; - } - if (num > 1) - { - const unsigned b = _bitStream.ReadByte_InAligned(); - checkSum ^= b; - blockSize += (UInt32)b << 16; - } - } - if (checkSum != 0x5A) - return S_FALSE; - unsigned blockSizeBits7 = (flags & 7) + 1; - blockSize += (UInt32)(blockSizeBits7 >> 3); - if (blockSize == 0) - { - // it's error in data stream - // but original-unrar ignores that error - _bitStream._minorError = true; -#if 1 - // we ignore that error as original-unrar: - blockSizeBits7 = 0; - blockSize = 1; -#else - // we can stop decoding: - return S_FALSE; -#endif - } - blockSize--; - blockSizeBits7 &= 7; - PRINT_CNT("Blocks", 100) - /* - { - static unsigned g_prev = 0; - static unsigned g_cnt = 0; - unsigned proc = unsigned(_winPos); - if (g_cnt++ % 100 == 0) printf(" c_size = %8u ", blockSize); - if (g_cnt++ % 100 == 1) printf(" unp_size = %8u", proc - g_prev); - g_prev = proc; - } - */ - _bitStream._blockEndBits7 = blockSizeBits7; - _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize; - _bitStream.SetCheck_forBlock(); - _isLastBlock = ((flags & 0x40) != 0); - if ((flags & 0x80) == 0) - { - if (!_tableWasFilled) - // if (blockSize != 0 || blockSizeBits7 != 0) - if (blockSize + blockSizeBits7 != 0) - return S_FALSE; - return S_OK; - } - _tableWasFilled = false; - } - - PRINT_CNT("Tables", 100); - - const unsigned kLevelTableSize = 20; - const unsigned k_NumHufTableBits_Level = 6; - NHuffman::CDecoder256 m_LevelDecoder; - const unsigned kTablesSizesSum_MAX = kMainTableSize + kDistTableSize_MAX + kAlignTableSize + kLenTableSize; - Byte lens[kTablesSizesSum_MAX]; - { - // (kLevelTableSize + 16 < kTablesSizesSum). So we use lens[] array for (Level) table - // Byte lens2[kLevelTableSize + 16]; - unsigned i = 0; - do - { - if (_bitStream._buf >= _bitStream._bufCheck_Block) - { - _bitStream.Prepare(); - if (_bitStream.IsBlockOverRead()) - return S_FALSE; - } - const unsigned len = (unsigned)_bitStream.ReadBits_9fix(4); - if (len == 15) - { - unsigned num = (unsigned)_bitStream.ReadBits_9fix(4); - if (num != 0) - { - num += 2; - num += i; - // we are allowed to overwrite to lens[] for extra 16 bytes after kLevelTableSize -#if 0 - if (num > kLevelTableSize) - { - // we ignore this error as original-unrar - num = kLevelTableSize; - // return S_FALSE; - } -#endif - do - lens[i++] = 0; - while (i < num); - continue; - } - } - lens[i++] = (Byte)len; - } - while (i < kLevelTableSize); - if (_bitStream.IsBlockOverRead()) - return S_FALSE; - RIF(m_LevelDecoder.Build(lens, NHuffman::k_BuildMode_Full)) - } - - unsigned i = 0; - const unsigned tableSize = _is_v7 ? - kTablesSizesSum_MAX : - kTablesSizesSum_MAX - kExtraDistSymbols_v7; - do - { - if (_bitStream._buf >= _bitStream._bufCheck_Block) - { - // if (_bitStream._buf >= _bitStream._bufCheck) - _bitStream.Prepare(); - if (_bitStream.IsBlockOverRead()) - return S_FALSE; - } - const unsigned sym = m_LevelDecoder.DecodeFull(&_bitStream); - if (sym < 16) - lens[i++] = (Byte)sym; -#if 0 - else if (sym > kLevelTableSize) - return S_FALSE; -#endif - else - { - unsigned num = ((sym /* - 16 */) & 1) * 4; - num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3); - num += i; - if (num > tableSize) - { - // we ignore this error as original-unrar - num = tableSize; - // return S_FALSE; - } - unsigned v = 0; - if (sym < 16 + 2) - { - if (i == 0) - return S_FALSE; - v = lens[(size_t)i - 1]; - } - do - lens[i++] = (Byte)v; - while (i < num); - } - } - while (i < tableSize); - - if (_bitStream.IsBlockOverRead()) - return S_FALSE; - if (_bitStream.InputEofError()) - return S_FALSE; - - /* We suppose that original-rar encoder can create only two cases for Huffman: - 1) Empty Huffman tree (if num_used_symbols == 0) - 2) Full Huffman tree (if num_used_symbols != 0) - Usually the block contains at least one symbol for m_MainDecoder. - So original-rar-encoder creates full Huffman tree for m_MainDecoder. - But we suppose that (num_used_symbols == 0) is possible for m_MainDecoder, - because file must be finished with (_isLastBlock) flag, - even if there are no symbols in m_MainDecoder. - So we use k_BuildMode_Full_or_Empty for m_MainDecoder. - */ - const NHuffman::enum_BuildMode buildMode = NHuffman:: - k_BuildMode_Full_or_Empty; // strict check - // k_BuildMode_Partial; // non-strict check (ignore errors) - - RIF(m_MainDecoder.Build(&lens[0], buildMode)) - if (!_is_v7) - { -#if 1 - /* we use this manual loop to avoid compiler BUG. - GCC 4.9.2 compiler has BUG with overlapping memmove() to right in local array. */ - Byte *dest = lens + kMainTableSize + kDistTableSize_v6 + - kAlignTableSize + kLenTableSize - 1; - unsigned num = kAlignTableSize + kLenTableSize; - do - { - dest[kExtraDistSymbols_v7] = dest[0]; - dest--; - } - while (--num); -#else - memmove(lens + kMainTableSize + kDistTableSize_v6 + kExtraDistSymbols_v7, - lens + kMainTableSize + kDistTableSize_v6, - kAlignTableSize + kLenTableSize); -#endif - memset(lens + kMainTableSize + kDistTableSize_v6, 0, kExtraDistSymbols_v7); - } - - RIF(m_DistDecoder.Build(&lens[kMainTableSize], buildMode)) - RIF( m_LenDecoder.Build(&lens[kMainTableSize - + kDistTableSize_MAX + kAlignTableSize], buildMode)) - - _useAlignBits = false; - for (i = 0; i < kAlignTableSize; i++) - if (lens[kMainTableSize + kDistTableSize_MAX + (size_t)i] != kNumAlignBits) - { - RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize_MAX], buildMode)) - _useAlignBits = true; - break; - } - - _tableWasFilled = true; - return S_OK; -} - -static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot) -{ - const unsigned numBits = ((unsigned)slot >> 2) - 1; - return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits9(numBits); -} - - -static const unsigned kSymbolRep = 258; -static const unsigned kMaxMatchLen = 0x1001 + 3; - -enum enum_exit_type -{ - Z7_RAR_EXIT_TYPE_NONE, - Z7_RAR_EXIT_TYPE_ADD_FILTER -}; - - -#define LZ_RESTORE \ -{ \ - _reps[0] = rep0; \ - _winPos = (size_t)(winPos - _window); \ - _buf_Res = _bitStream._buf; \ - _bitPos_Res = _bitStream._bitPos; \ -} - -#define LZ_LOOP_BREAK_OK { break; } -// #define LZ_LOOP_BREAK_ERROR { _lzError = LZ_ERROR_TYPE_SYM; break; } -// #define LZ_LOOP_BREAK_ERROR { LZ_RESTORE; return S_FALSE; } -#define LZ_LOOP_BREAK_ERROR { goto decode_error; } -// goto decode_error; } -// #define LZ_LOOP_BREAK_ERROR { break; } - -#define Z7_RAR_HUFF_DECODE_CHECK_break(sym, huf, kNumTableBits, bitStream) \ - Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR }) - - -HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw() -{ -#if 0 - Byte k_LenPlusTable_LOC[DICT_SIZE_BITS_MAX]; - memcpy(k_LenPlusTable_LOC, k_LenPlusTable, sizeof(k_LenPlusTable)); -#endif - - PRINT_CNT("DecodeLZ2", 2000); - - CBitDecoder _bitStream; - _bitStream.CopyFrom(bitStream); - // _bitStream._stream = _inStream; - // _bitStream._bufBase = _inputBuf; - // _bitStream.Init(); - - // _reps[*] can be larger than _winSize, if _winSize was reduced in solid stream. - size_t rep0 = _reps[0]; - // size_t rep1 = _reps[1]; - // Byte *win = _window; - Byte *winPos = _window + _winPos; - const Byte *limit = _window + _limit; - _exitType = Z7_RAR_EXIT_TYPE_NONE; - - for (;;) - { - if (winPos >= limit) - LZ_LOOP_BREAK_OK - // (winPos < limit) - if (_bitStream._buf >= _bitStream._bufCheck_Block) - { - if (_bitStream.InputEofError()) - LZ_LOOP_BREAK_OK - if (_bitStream._buf >= _bitStream._bufCheck) - { - if (!_bitStream._wasFinished) - LZ_LOOP_BREAK_OK - // _bitStream._wasFinished == true - // we don't need Prepare() here, because all data was read - // and PadZone (16 bytes) after data was filled. - } - const UInt64 processed = _bitStream.GetProcessedSize_Round(); - // some cases are error, but the caller will process such error cases. - if (processed >= _bitStream._blockEnd && - (processed > _bitStream._blockEnd - || _bitStream.GetProcessedBits7() >= _bitStream._blockEndBits7)) - LZ_LOOP_BREAK_OK - // that check is not required, but it can help, if there is BUG in another code - if (!_tableWasFilled) - LZ_LOOP_BREAK_ERROR - } - -#if 0 - const unsigned sym = m_MainDecoder.Decode(&_bitStream); -#else - unsigned sym; - Z7_RAR_HUFF_DECODE_CHECK_break(sym, &m_MainDecoder, k_NumHufTableBits_Main, &_bitStream) -#endif - - if (sym < 256) - { - *winPos++ = (Byte)sym; - // _lzSize++; - continue; - } - - CLenType len; - - if (sym < kSymbolRep + kNumReps) - { - if (sym >= kSymbolRep) - { - if (sym != kSymbolRep) - { - size_t dist = _reps[1]; - _reps[1] = rep0; - rep0 = dist; - if (sym >= kSymbolRep + 2) - { - #if 1 - rep0 = _reps[(size_t)sym - kSymbolRep]; - _reps[(size_t)sym - kSymbolRep] = _reps[2]; - _reps[2] = dist; - #else - if (sym != kSymbolRep + 2) - { - rep0 = _reps[3]; - _reps[3] = _reps[2]; - _reps[2] = dist; - } - else - { - rep0 = _reps[2]; - _reps[2] = dist; - } - #endif - } - } -#if 0 - len = m_LenDecoder.Decode(&_bitStream); - if (len >= kLenTableSize) - LZ_LOOP_BREAK_ERROR -#else - Z7_RAR_HUFF_DECODE_CHECK_break(len, &m_LenDecoder, k_NumHufTableBits_Len, &_bitStream) -#endif - if (len >= 8) - len = SlotToLen(_bitStream, len); - len += 2; - // _lastLen = (UInt32)len; - } - else if (sym != 256) - { - len = (CLenType)_lastLen; - if (len == 0) - { - // we ignore (_lastLen == 0) case, like original-unrar. - // that case can mean error in stream. - // lzError = true; - // return S_FALSE; - continue; - } - } - else - { - _exitType = Z7_RAR_EXIT_TYPE_ADD_FILTER; - LZ_LOOP_BREAK_OK - } - } -#if 0 - else if (sym >= kMainTableSize) - LZ_LOOP_BREAK_ERROR -#endif - else - { - _reps[3] = _reps[2]; - _reps[2] = _reps[1]; - _reps[1] = rep0; - len = sym - (kSymbolRep + kNumReps); - if (len >= 8) - len = SlotToLen(_bitStream, len); - len += 2; - // _lastLen = (UInt32)len; - -#if 0 - rep0 = (UInt32)m_DistDecoder.Decode(&_bitStream); -#else - Z7_RAR_HUFF_DECODE_CHECK_break(rep0, &m_DistDecoder, k_NumHufTableBits_Dist, &_bitStream) -#endif - - if (rep0 >= 4) - { -#if 0 - if (rep0 >= kDistTableSize_MAX) - LZ_LOOP_BREAK_ERROR -#endif - const unsigned numBits = ((unsigned)rep0 - 2) >> 1; - rep0 = (2 | (rep0 & 1)) << numBits; - - const Byte *buf = _bitStream._buf; -#ifdef Z7_RAR5_USE_64BIT - const UInt64 v = GetBe64(buf); -#else - const UInt32 v = GetBe32(buf); -#endif - - // _lastLen = (UInt32)len; - if (numBits < kNumAlignBits) - { - rep0 += // _bitStream.ReadBits9(numBits); - _bitStream.ReadBits_Big25(numBits, v); - } - else - { - #if !defined(MY_CPU_AMD64) - len += k_LenPlusTable[numBits]; - #elif 0 - len += k_LenPlusTable_LOC[numBits]; - #elif 1 - len += m_LenPlusTable[numBits]; - #elif 1 && defined(MY_CPU_64BIT) && defined(MY_CPU_AMD64) - // len += (unsigned)((UInt64)0xfffffffeaa554000 >> (numBits * 2)) & 3; - len += (unsigned)((UInt64)0xfffffffffeaa5540 >> (numBits * 2 - 8)) & 3; - #elif 1 - len += 3; - len -= (unsigned)(numBits - 7) >> (sizeof(unsigned) * 8 - 1); - len -= (unsigned)(numBits - 12) >> (sizeof(unsigned) * 8 - 1); - len -= (unsigned)(numBits - 17) >> (sizeof(unsigned) * 8 - 1); - #elif 1 - len += 3; - len -= (0x155aabf >> (numBits - 4) >> (numBits - 4)) & 3; - #elif 1 - len += (numBits >= 7); - len += (numBits >= 12); - len += (numBits >= 17); - #endif - // _lastLen = (UInt32)len; - if (_useAlignBits) - { - // if (numBits > kNumAlignBits) - rep0 += (_bitStream.ReadBits_Big25(numBits - kNumAlignBits, v) << kNumAlignBits); -#if 0 - const unsigned a = m_AlignDecoder.Decode(&_bitStream); - if (a >= kAlignTableSize) - LZ_LOOP_BREAK_ERROR -#else - unsigned a; - Z7_RAR_HUFF_DECODE_CHECK_break(a, &m_AlignDecoder, k_NumHufTableBits_Align, &_bitStream) -#endif - rep0 += a; - } - else - rep0 += _bitStream.ReadBits_Big(numBits, v); -#ifndef Z7_RAR5_USE_64BIT - if (numBits >= 30) // we don't want 32-bit overflow case - rep0 = (size_t)0 - 1 - 1; -#endif - } - } - rep0++; - } - - { - _lastLen = (UInt32)len; - // len != 0 - -#ifdef Z7_RAR5_SHOW_STAT - { - size_t index = rep0; - if (index >= kNumStats1) - index = kNumStats1 - 1; - g_stats1[index]++; - g_stats2[index][len]++; - } -#endif - - Byte *dest = winPos; - winPos += len; - if (rep0 <= _dictSize_forCheck) - { - const Byte *src; - const size_t winPos_temp = (size_t)(dest - _window); - if (rep0 > winPos_temp) - { - if (_lzSize == 0) - goto error_dist; - size_t back = rep0 - winPos_temp; - // STAT_INC(g_NumOver) - src = dest + (_winSize - rep0); - if (back < len) - { - // len -= (CLenType)back; - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - *dest++ = *src++; - while (--back); - src = dest - rep0; - } - } - else - src = dest - rep0; - CopyMatch(rep0, dest, src, winPos); - continue; - } - -error_dist: - // LZ_LOOP_BREAK_ERROR; - _lzError = LZ_ERROR_TYPE_DIST; - do - *dest++ = 0; - while (dest < winPos); - continue; - } - } - - LZ_RESTORE - return S_OK; - -#if 1 -decode_error: - /* - if (_bitStream._hres != S_OK) - return _bitStream._hres; - */ - LZ_RESTORE - return S_FALSE; -#endif -} - - - -HRESULT CDecoder::DecodeLZ() -{ - CBitDecoder _bitStream; - _bitStream._stream = _inStream; - _bitStream._bufBase = _inputBuf; - _bitStream.Init(); - - // _reps[*] can be larger than _winSize, if _winSize was reduced in solid stream. - size_t winPos = _winPos; - Byte *win = _window; - size_t limit; - { - size_t rem = _winSize - winPos; - if (rem > kWriteStep) - rem = kWriteStep; - limit = winPos + rem; - } - - for (;;) - { - if (winPos >= limit) - { - _winPos = winPos < _winSize ? winPos : _winSize; - RINOK(WriteBuf()) - if (_unpackSize_Defined && _writtenFileSize > _unpackSize) - break; // return S_FALSE; - const size_t wp = _winPos; - size_t rem = _winSize - wp; - if (rem == 0) - { - _lzSize += wp; - winPos -= wp; - // (winPos < kMaxMatchLen < _winSize) - // so memmove is not required here - if (winPos) - memcpy(win, win + _winSize, winPos); - limit = _winSize; - if (limit >= kWriteStep) - { - limit = kWriteStep; - continue; - } - rem = _winSize - winPos; - } - if (rem > kWriteStep) - rem = kWriteStep; - limit = winPos + rem; - continue; - } - - // (winPos < limit) - - if (_bitStream._buf >= _bitStream._bufCheck_Block) - { - _winPos = winPos; - if (_bitStream.InputEofError()) - break; // return S_FALSE; - _bitStream.Prepare(); - - const UInt64 processed = _bitStream.GetProcessedSize_Round(); - if (processed >= _bitStream._blockEnd) - { - if (processed > _bitStream._blockEnd) - break; // return S_FALSE; - { - const unsigned bits7 = _bitStream.GetProcessedBits7(); - if (bits7 >= _bitStream._blockEndBits7) - { - if (bits7 > _bitStream._blockEndBits7) - { -#if 1 - // we ignore thar error as original unrar - _bitStream._minorError = true; -#else - break; // return S_FALSE; -#endif - } - _bitStream.AlignToByte(); - // if (!_bitStream.AlignToByte()) break; - if (_isLastBlock) - { - if (_bitStream.InputEofError()) - break; - /* - // packSize can be 15 bytes larger for encrypted archive - if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize()) - break; - */ - if (_bitStream._minorError) - return S_FALSE; - return _bitStream._hres; - // break; - } - RINOK(ReadTables(_bitStream)) - continue; - } - } - } - - // end of block was not reached. - // so we must decode more symbols - // that check is not required, but it can help, if there is BUG in another code - if (!_tableWasFilled) - break; // return S_FALSE; - } - - _limit = limit; - _winPos = winPos; - RINOK(DecodeLZ2(_bitStream)) - _bitStream._buf = _buf_Res; - _bitStream._bitPos = _bitPos_Res; - - winPos = _winPos; - if (_exitType == Z7_RAR_EXIT_TYPE_ADD_FILTER) - { - RINOK(AddFilter(_bitStream)) - continue; - } - } - - _winPos = winPos; - - if (_bitStream._hres != S_OK) - return _bitStream._hres; - - return S_FALSE; -} - - - -HRESULT CDecoder::CodeReal() -{ - _unsupportedFilter = false; - _writeError = false; - /* - if (!_isSolid || !_wasInit) - { - _wasInit = true; - // _lzSize = 0; - _lzWritten = 0; - _winPos = 0; - for (unsigned i = 0; i < kNumReps; i++) - _reps[i] = (size_t)0 - 1; - _lastLen = 0; - _tableWasFilled = false; - } - */ - _isLastBlock = false; - - InitFilters(); - - _filterEnd = 0; - _writtenFileSize = 0; - const UInt64 lzSize = _lzSize + _winPos; - _lzFileStart = lzSize; - _lzWritten = lzSize; - - HRESULT res = DecodeLZ(); - - HRESULT res2 = S_OK; - if (!_writeError && res != E_OUTOFMEMORY) - res2 = WriteBuf(); - /* - if (res == S_OK) - if (InputEofError()) - res = S_FALSE; - */ - if (res == S_OK) - { - // _solidAllowed = true; - res = res2; - } - if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize) - return S_FALSE; - return res; -} - - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - _lzError = LZ_ERROR_TYPE_NO; -/* - if file is soild, but decoding of previous file was not finished, - we still try to decode new file. - We need correct huffman table at starting block. - And rar encoder probably writes huffman table at start block, if file is big. - So we have good chance to get correct huffman table in some file after corruption. - Also we try to recover window by filling zeros, if previous file - was decoded to smaller size than required. - But if filling size is big, we do full reset of window instead. -*/ - #define Z7_RAR_RECOVER_SOLID_LIMIT (1 << 20) - // #define Z7_RAR_RECOVER_SOLID_LIMIT 0 // do not fill zeros - { - // if (_winPos > 100) _winPos -= 100; // for debug: corruption - const UInt64 lzSize = _lzSize + _winPos; - if (!_isSolid || !_wasInit - || (lzSize < _lzEnd -#if Z7_RAR_RECOVER_SOLID_LIMIT != 0 - && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd -#endif - )) - { - if (_isSolid) - _lzError = LZ_ERROR_TYPE_HEADER; - _lzEnd = 0; - _lzSize = 0; - _lzWritten = 0; - _winPos = 0; - for (unsigned i = 0; i < kNumReps; i++) - _reps[i] = (size_t)0 - 1; - _lastLen = 0; - _tableWasFilled = false; - _wasInit = true; - } -#if Z7_RAR_RECOVER_SOLID_LIMIT != 0 - else if (lzSize < _lzEnd) - { -#if 0 - return S_FALSE; -#else - // we can report that recovering was made: - // _lzError = LZ_ERROR_TYPE_HEADER; - // We write zeros to area after corruption: - if (_window) - { - UInt64 rem = _lzEnd - lzSize; - const size_t ws = _winSize; - if (rem >= ws) - { - My_ZeroMemory(_window, ws); - _lzSize = ws; - _winPos = 0; - } - else - { - const size_t cur = ws - _winPos; - if (cur <= rem) - { - rem -= cur; - My_ZeroMemory(_window + _winPos, cur); - _lzSize += _winPos; - _winPos = 0; - } - My_ZeroMemory(_window + _winPos, (size_t)rem); - _winPos += (size_t)rem; - } - } - // else return S_FALSE; -#endif - } -#endif - } - - // we don't want _lzSize overflow - if (_lzSize >= DICT_SIZE_MAX) - _lzSize = DICT_SIZE_MAX; - _lzEnd = _lzSize + _winPos; - // _lzSize <= DICT_SIZE_MAX - // _lzEnd <= DICT_SIZE_MAX * 2 - - size_t newSize = _dictSize; - if (newSize < kWinSize_Min) - newSize = kWinSize_Min; - - _unpackSize = 0; - _unpackSize_Defined = (outSize != NULL); - if (_unpackSize_Defined) - _unpackSize = *outSize; - - if ((Int64)_unpackSize >= 0) - _lzEnd += _unpackSize; // known end after current file - else - _lzEnd = 0; // unknown end - - if (_isSolid && _window) - { - // If dictionary was decreased in solid, we use old dictionary. - if (newSize > _dictSize_forCheck) - { - // If dictionary was increased in solid, we don't want grow. - return S_FALSE; // E_OUTOFMEMORY - } - // (newSize <= _winSize) - } - else - { - _dictSize_forCheck = newSize; - { - size_t newSize_small = newSize; - const size_t k_Win_AlignSize = 1u << 18; - /* here we add (1 << 7) instead of (COPY_CHUNK_SIZE - 1), because - we want to get same (_winSize) for different COPY_CHUNK_SIZE values. */ - // newSize += (COPY_CHUNK_SIZE - 1) + (k_Win_AlignSize - 1); // for debug : we can get smallest (_winSize) - newSize += (1 << 7) + k_Win_AlignSize; - newSize &= ~(size_t)(k_Win_AlignSize - 1); - if (newSize < newSize_small) - return E_OUTOFMEMORY; - } - // (!_isSolid || !_window) - const size_t allocSize = newSize + kMaxMatchLen + 64; - if (allocSize < newSize) - return E_OUTOFMEMORY; - if (!_window || allocSize > _winSize_Allocated) - { - Z7_RAR_FREE_WINDOW - _window = NULL; - _winSize_Allocated = 0; - Byte *win = (Byte *)::BigAlloc(allocSize); - if (!win) - return E_OUTOFMEMORY; - _window = win; - _winSize_Allocated = allocSize; - } - _winSize = newSize; - } - - if (!_inputBuf) - { - _inputBuf = (Byte *)z7_AlignedAlloc(kInputBufSize + kInputBufferPadZone); - if (!_inputBuf) - return E_OUTOFMEMORY; - } - - _inStream = inStream; - _outStream = outStream; - _progress = progress; - _progress_Pack = 0; - _progress_Unpack = 0; - - const HRESULT res = CodeReal(); - - if (res != S_OK) - return res; - // _lzError = LZ_ERROR_TYPE_HEADER; // for debug - if (_lzError) - return S_FALSE; - if (_unsupportedFilter) - return E_NOTIMPL; - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - if (size != 2) - return E_INVALIDARG; - const unsigned pow = data[0]; - const unsigned b1 = data[1]; - const unsigned frac = b1 >> 3; - // unsigned pow = 15 + 8; - // unsigned frac = 1; - if (pow + ((frac + 31) >> 5) > MAX_DICT_LOG - 17) - // if (frac + (pow << 8) >= ((8 * 2 + 7) << 5) + 8 / 8) - return E_NOTIMPL; - _dictSize = (size_t)(frac + 32) << (pow + 12); - _isSolid = (b1 & 1) != 0; - _is_v7 = (b1 & 2) != 0; - // printf("\ndict size = %p\n", (void *)(size_t)_dictSize); - return S_OK; -} - -}} +// Rar5Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +#define DICT_SIZE_MAX ((UInt64)1 << DICT_SIZE_BITS_MAX) + +// #include // SSE2 +// #endif + +#include "../../../C/CpuArch.h" +#if 0 +#include "../../../C/Bra.h" +#endif + +#if defined(MY_CPU_ARM64) +#include +#endif + +// #define Z7_RAR5_SHOW_STAT +// #include +#ifdef Z7_RAR5_SHOW_STAT +#include +#endif + +#include "../Common/StreamUtils.h" + +#include "Rar5Decoder.h" + +/* +Note: original-unrar claims that encoder has limitation for Distance: + (Distance <= MaxWinSize - MAX_INC_LZ_MATCH) + MAX_INC_LZ_MATCH = 0x1001 + 3; +*/ + +#define LZ_ERROR_TYPE_NO 0 +#define LZ_ERROR_TYPE_HEADER 1 +// #define LZ_ERROR_TYPE_SYM 1 +#define LZ_ERROR_TYPE_DIST 2 + +static +void My_ZeroMemory(void *p, size_t size) +{ + #if defined(MY_CPU_AMD64) && !defined(_M_ARM64EC) \ + && defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL <= 1400) + // __stosq((UInt64 *)(void *)win, 0, size / 8); + /* + printf("\n__stosb \n"); + #define STEP_BIG (1 << 28) + for (size_t i = 0; i < ((UInt64)1 << 50); i += STEP_BIG) + { + printf("\n__stosb end %p\n", (void *)i); + __stosb((Byte *)p + i, 0, STEP_BIG); + } + */ + // __stosb((Byte *)p, 0, 0); + __stosb((Byte *)p, 0, size); + #else + // SecureZeroMemory (win, STEP); + // ZeroMemory(win, STEP); + // memset(win, 0, STEP); + memset(p, 0, size); + #endif +} + + + +#ifdef MY_CPU_LE_UNALIGN + #define Z7_RAR5_DEC_USE_UNALIGNED_COPY +#endif + +#ifdef Z7_RAR5_DEC_USE_UNALIGNED_COPY + + #define COPY_CHUNK_SIZE 16 + + #define COPY_CHUNK_4_2(dest, src) \ + { \ + ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \ + ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \ + src += 4 * 2; \ + dest += 4 * 2; \ + } + + /* sse2 doesn't help here in GCC and CLANG. + so we disabled sse2 here */ +#if 0 + #if defined(MY_CPU_AMD64) + #define Z7_RAR5_DEC_USE_SSE2 + #elif defined(MY_CPU_X86) + #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ + || defined(__SSE2__) \ + // || 1 == 1 // for debug only + #define Z7_RAR5_DEC_USE_SSE2 + #endif + #endif +#endif + + #if defined(MY_CPU_ARM64) + + #define COPY_OFFSET_MIN 16 + #define COPY_CHUNK1(dest, src) \ + { \ + vst1q_u8((uint8_t *)(void *)dest, \ + vld1q_u8((const uint8_t *)(const void *)src)); \ + src += 16; \ + dest += 16; \ + } + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK1(dest, src) \ + if (dest >= lim) break; \ + COPY_CHUNK1(dest, src) \ + } + + #elif defined(Z7_RAR5_DEC_USE_SSE2) + #include // sse2 + #define COPY_OFFSET_MIN 16 + + #define COPY_CHUNK1(dest, src) \ + { \ + _mm_storeu_si128((__m128i *)(void *)dest, \ + _mm_loadu_si128((const __m128i *)(const void *)src)); \ + src += 16; \ + dest += 16; \ + } + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK1(dest, src) \ + if (dest >= lim) break; \ + COPY_CHUNK1(dest, src) \ + } + + #elif defined(MY_CPU_64BIT) + #define COPY_OFFSET_MIN 8 + + #define COPY_CHUNK(dest, src) \ + { \ + ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ + src += 8 * 1; dest += 8 * 1; \ + ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ + src += 8 * 1; dest += 8 * 1; \ + } + + #else + #define COPY_OFFSET_MIN 4 + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK_4_2(dest, src); \ + COPY_CHUNK_4_2(dest, src); \ + } + + #endif +#endif + + +#ifndef COPY_CHUNK_SIZE + #define COPY_OFFSET_MIN 4 + #define COPY_CHUNK_SIZE 8 + #define COPY_CHUNK_2(dest, src) \ + { \ + const Byte a0 = src[0]; \ + const Byte a1 = src[1]; \ + dest[0] = a0; \ + dest[1] = a1; \ + src += 2; \ + dest += 2; \ + } + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + } +#endif + + +#define COPY_CHUNKS \ +{ \ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + do { COPY_CHUNK(dest, src) } \ + while (dest < lim); \ +} + +namespace NCompress { +namespace NRar5 { + +typedef +#if 1 + unsigned +#else + size_t +#endif + CLenType; + +// (len != 0) +static +Z7_FORCE_INLINE +// Z7_ATTRIB_NO_VECTOR +void CopyMatch(size_t offset, Byte *dest, const Byte *src, const Byte *lim) +{ + { + // (COPY_OFFSET_MIN >= 4) + if (offset >= COPY_OFFSET_MIN) + { + COPY_CHUNKS + // return; + } + else + #if (COPY_OFFSET_MIN > 4) + #if COPY_CHUNK_SIZE < 8 + #error Stop_Compiling_Bad_COPY_CHUNK_SIZE + #endif + if (offset >= 4) + { + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + COPY_CHUNK_4_2(dest, src) + #if COPY_CHUNK_SIZE < 16 + if (dest >= lim) break; + #endif + COPY_CHUNK_4_2(dest, src) + } + while (dest < lim); + // return; + } + else + #endif + { + // (offset < 4) + const unsigned b0 = src[0]; + if (offset < 2) + { + #if defined(Z7_RAR5_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16) + #if defined(MY_CPU_64BIT) + { + const UInt64 v64 = (UInt64)b0 * 0x0101010101010101; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + ((UInt64 *)(void *)dest)[0] = v64; + ((UInt64 *)(void *)dest)[1] = v64; + dest += 16; + } + while (dest < lim); + } + #else + { + UInt32 v = b0; + v |= v << 8; + v |= v << 16; + do + { + ((UInt32 *)(void *)dest)[0] = v; + ((UInt32 *)(void *)dest)[1] = v; + dest += 8; + ((UInt32 *)(void *)dest)[0] = v; + ((UInt32 *)(void *)dest)[1] = v; + dest += 8; + } + while (dest < lim); + } + #endif + #else + do + { + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += 2; + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += 2; + } + while (dest < lim); + #endif + } + else if (offset == 2) + { + const Byte b1 = src[1]; + { + do + { + dest[0] = (Byte)b0; + dest[1] = b1; + dest += 2; + } + while (dest < lim); + } + } + else // (offset == 3) + { + const Byte b1 = src[1]; + const Byte b2 = src[2]; + do + { + dest[0] = (Byte)b0; + dest[1] = b1; + dest[2] = b2; + dest += 3; + } + while (dest < lim); + } + } + } +} + +static const size_t kInputBufSize = 1 << 20; +static const UInt32 k_Filter_BlockSize_MAX = 1 << 22; +static const unsigned k_Filter_AfterPad_Size = 64; + +#ifdef Z7_RAR5_SHOW_STAT +static const unsigned kNumStats1 = 10; +static const unsigned kNumStats2 = (1 << 12) + 16; +static UInt32 g_stats1[kNumStats1]; +static UInt32 g_stats2[kNumStats1][kNumStats2]; +#endif + +#if 1 +MY_ALIGN(32) +// DICT_SIZE_BITS_MAX-1 are required +static const Byte k_LenPlusTable[DICT_SIZE_BITS_MAX] = + { 0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }; +#endif + + + +class CBitDecoder +{ +public: + const Byte *_buf; + const Byte *_bufCheck_Block; // min(ptr for _blockEnd, _bufCheck) + unsigned _bitPos; // = [0 ... 7] + bool _wasFinished; + bool _minorError; + unsigned _blockEndBits7; // = [0 ... 7] : the number of additional bits in (_blockEnd) poisition. + HRESULT _hres; + const Byte *_bufCheck; // relaxed limit (16 bytes before real end of input data in buffer) + Byte *_bufLim; // end if input data + Byte *_bufBase; + ISequentialInStream *_stream; + + UInt64 _processedSize; + UInt64 _blockEnd; // absolute end of current block + // but it doesn't include additional _blockEndBits7 [0 ... 7] bits + + Z7_FORCE_INLINE + void CopyFrom(const CBitDecoder &a) + { + _buf = a._buf; + _bufCheck_Block = a._bufCheck_Block; + _bitPos = a._bitPos; + _wasFinished = a._wasFinished; + _blockEndBits7 = a._blockEndBits7; + _bufCheck = a._bufCheck; + _bufLim = a._bufLim; + _bufBase = a._bufBase; + + _processedSize = a._processedSize; + _blockEnd = a._blockEnd; + } + + Z7_FORCE_INLINE + void RestoreFrom2(const CBitDecoder &a) + { + _buf = a._buf; + _bitPos = a._bitPos; + } + + Z7_FORCE_INLINE + void SetCheck_forBlock() + { + _bufCheck_Block = _bufCheck; + if (_bufCheck > _buf) + { + const UInt64 processed = GetProcessedSize_Round(); + if (_blockEnd < processed) + _bufCheck_Block = _buf; + else + { + const UInt64 delta = _blockEnd - processed; + if ((size_t)(_bufCheck - _buf) > delta) + _bufCheck_Block = _buf + (size_t)delta; + } + } + } + + Z7_FORCE_INLINE + bool IsBlockOverRead() const + { + const UInt64 v = GetProcessedSize_Round(); + if (v < _blockEnd) return false; + if (v > _blockEnd) return true; + return _bitPos > _blockEndBits7; + } + + /* + CBitDecoder() throw(): + _buf(0), + _bufLim(0), + _bufBase(0), + _stream(0), + _processedSize(0), + _wasFinished(false) + {} + */ + + Z7_FORCE_INLINE + void Init() throw() + { + _blockEnd = 0; + _blockEndBits7 = 0; + + _bitPos = 0; + _processedSize = 0; + _buf = _bufBase; + _bufLim = _bufBase; + _bufCheck = _buf; + _bufCheck_Block = _buf; + _wasFinished = false; + _minorError = false; + } + + void Prepare2() throw(); + + Z7_FORCE_INLINE + void Prepare() throw() + { + if (_buf >= _bufCheck) + Prepare2(); + } + + Z7_FORCE_INLINE + bool ExtraBitsWereRead() const + { + return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0); + } + + Z7_FORCE_INLINE bool InputEofError() const { return ExtraBitsWereRead(); } + + Z7_FORCE_INLINE unsigned GetProcessedBits7() const { return _bitPos; } + Z7_FORCE_INLINE UInt64 GetProcessedSize_Round() const { return _processedSize + (size_t)(_buf - _bufBase); } + Z7_FORCE_INLINE UInt64 GetProcessedSize() const { return _processedSize + (size_t)(_buf - _bufBase) + ((_bitPos + 7) >> 3); } + + Z7_FORCE_INLINE + void AlignToByte() + { + if (_bitPos != 0) + { +#if 1 + // optional check of unused bits for strict checking: + // original-unrar doesn't check it: + const unsigned b = (unsigned)*_buf << _bitPos; + if (b & 0xff) + _minorError = true; +#endif + _buf++; + _bitPos = 0; + } + // _buf += (_bitPos + 7) >> 3; + // _bitPos = 0; + } + + Z7_FORCE_INLINE + Byte ReadByte_InAligned() + { + return *_buf++; + } + + Z7_FORCE_INLINE + UInt32 GetValue(unsigned numBits) const + { + // 0 < numBits <= 17 : supported values +#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE_UNALIGN) + UInt32 v = GetBe32(_buf); +#if 1 + return (v >> (32 - numBits - _bitPos)) & ((1u << numBits) - 1); +#else + return (v << _bitPos) >> (32 - numBits); +#endif +#else + UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2]; + v >>= 24 - numBits - _bitPos; + return v & ((1 << numBits) - 1); +#endif + } + + Z7_FORCE_INLINE + UInt32 GetValue_InHigh32bits() const + { + // 0 < numBits <= 17 : supported vales +#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED) && defined(MY_CPU_LE_UNALIGN) + return GetBe32(_buf) << _bitPos; +#else + const UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2]; + return v << (_bitPos + 8); +#endif + } + + + Z7_FORCE_INLINE + void MovePos(unsigned numBits) + { + numBits += _bitPos; + _buf += numBits >> 3; + _bitPos = numBits & 7; + } + + + Z7_FORCE_INLINE + UInt32 ReadBits9(unsigned numBits) + { + const Byte *buf = _buf; + UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; + v &= (UInt32)0xFFFF >> _bitPos; + numBits += _bitPos; + v >>= 16 - numBits; + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v; + } + + Z7_FORCE_INLINE + UInt32 ReadBits_9fix(unsigned numBits) + { + const Byte *buf = _buf; + UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; + const UInt32 mask = (1u << numBits) - 1; + numBits += _bitPos; + v >>= 16 - numBits; + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; + } + +#if 1 && defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 8) +#define Z7_RAR5_USE_64BIT +#endif + +#ifdef Z7_RAR5_USE_64BIT +#define MAX_DICT_LOG (sizeof(size_t) / 8 * 5 + 31) +#else +#define MAX_DICT_LOG 31 +#endif + +#ifdef Z7_RAR5_USE_64BIT + + Z7_FORCE_INLINE + size_t ReadBits_Big(unsigned numBits, UInt64 v) + { + const UInt64 mask = ((UInt64)1 << numBits) - 1; + numBits += _bitPos; + const Byte *buf = _buf; + // UInt64 v = GetBe64(buf); + v >>= 64 - numBits; + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return (size_t)(v & mask); + } + #define ReadBits_Big25 ReadBits_Big + +#else + + // (numBits <= 25) for 32-bit mode + Z7_FORCE_INLINE + size_t ReadBits_Big25(unsigned numBits, UInt32 v) + { + const UInt32 mask = ((UInt32)1 << numBits) - 1; + numBits += _bitPos; + v >>= 32 - numBits; + _buf += numBits >> 3; + _bitPos = numBits & 7; + return v & mask; + } + + // numBits != 0 + Z7_FORCE_INLINE + size_t ReadBits_Big(unsigned numBits, UInt32 v) + { + const Byte *buf = _buf; + // UInt32 v = GetBe32(buf); +#if 0 + const UInt32 mask = ((UInt32)1 << numBits) - 1; + numBits += _bitPos; + if (numBits > 32) + { + v <<= numBits - 32; + v |= (UInt32)buf[4] >> (40 - numBits); + } + else + v >>= 32 - numBits; + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; +#else + v <<= _bitPos; + v |= (UInt32)buf[4] >> (8 - _bitPos); + v >>= 32 - numBits; + numBits += _bitPos; + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v; +#endif + } +#endif +}; + + +static const unsigned kLookaheadSize = 16; +static const unsigned kInputBufferPadZone = kLookaheadSize; + +Z7_NO_INLINE +void CBitDecoder::Prepare2() throw() +{ + if (_buf > _bufLim) + return; + + size_t rem = (size_t)(_bufLim - _buf); + if (rem != 0) + memmove(_bufBase, _buf, rem); + + _bufLim = _bufBase + rem; + _processedSize += (size_t)(_buf - _bufBase); + _buf = _bufBase; + + // we do not look ahead more than 16 bytes before limit checks. + + if (!_wasFinished) + { + while (rem <= kLookaheadSize) + { + UInt32 processed = (UInt32)(kInputBufSize - rem); + // processed = 33; // for debug + _hres = _stream->Read(_bufLim, processed, &processed); + _bufLim += processed; + rem += processed; + if (processed == 0 || _hres != S_OK) + { + _wasFinished = true; + // if (_hres != S_OK) throw CInBufferException(result); + break; + } + } + } + + // we always fill pad zone here. + // so we don't need to call Prepare2() if (_wasFinished == true) + memset(_bufLim, 0xFF, kLookaheadSize); + + if (rem < kLookaheadSize) + { + _bufCheck = _buf; + // memset(_bufLim, 0xFF, kLookaheadSize - rem); + } + else + _bufCheck = _bufLim - kLookaheadSize; + + SetCheck_forBlock(); +} + + +enum FilterType +{ + FILTER_DELTA = 0, + FILTER_E8, + FILTER_E8E9, + FILTER_ARM +}; + +static const size_t kWriteStep = (size_t)1 << 18; + // (size_t)1 << 22; // original-unrar + +// Original unRAR claims that maximum possible filter block size is (1 << 16) now, +// and (1 << 17) is minimum win size required to support filter. +// Original unRAR uses (1u << 18) for "extra safety and possible filter area size expansion" +// We can use any win size, but we use same (1u << 18) for compatibility +// with WinRar + +// static const unsigned kWinSize_Log_Min = 17; +static const size_t kWinSize_Min = 1u << 18; + +CDecoder::CDecoder(): + _isSolid(false), + _is_v7(false), + _wasInit(false), + // _dictSizeLog(0), + _dictSize(kWinSize_Min), + _window(NULL), + _winPos(0), + _winSize(0), + _dictSize_forCheck(0), + _lzSize(0), + _lzEnd(0), + _writtenFileSize(0), + _filters(NULL), + _winSize_Allocated(0), + _inputBuf(NULL) +{ +#if 1 + memcpy(m_LenPlusTable, k_LenPlusTable, sizeof(k_LenPlusTable)); +#endif + // printf("\nsizeof(CDecoder) == %d\n", sizeof(CDecoder)); +} + +CDecoder::~CDecoder() +{ +#ifdef Z7_RAR5_SHOW_STAT + printf("\n%4d :", 0); + for (unsigned k = 0; k < kNumStats1; k++) + printf(" %8u", (unsigned)g_stats1[k]); + printf("\n"); + for (unsigned i = 0; i < kNumStats2; i++) + { + printf("\n%4d :", i); + for (unsigned k = 0; k < kNumStats1; k++) + printf(" %8u", (unsigned)g_stats2[k][i]); + } + printf("\n"); +#endif + +#define Z7_RAR_FREE_WINDOW ::BigFree(_window); + + Z7_RAR_FREE_WINDOW + z7_AlignedFree(_inputBuf); + z7_AlignedFree(_filters); +} + +Z7_NO_INLINE +void CDecoder::DeleteUnusedFilters() +{ + if (_numUnusedFilters != 0) + { + // printf("\nDeleteUnusedFilters _numFilters = %6u\n", _numFilters); + const unsigned n = _numFilters - _numUnusedFilters; + _numFilters = n; + memmove(_filters, _filters + _numUnusedFilters, n * sizeof(CFilter)); + _numUnusedFilters = 0; + } +} + + +Z7_NO_INLINE +HRESULT CDecoder::WriteData(const Byte *data, size_t size) +{ + HRESULT res = S_OK; + if (!_unpackSize_Defined || _writtenFileSize < _unpackSize) + { + size_t cur = size; + if (_unpackSize_Defined) + { + const UInt64 rem = _unpackSize - _writtenFileSize; + if (cur > rem) + cur = (size_t)rem; + } + res = WriteStream(_outStream, data, cur); + if (res != S_OK) + _writeError = true; + } + _writtenFileSize += size; + return res; +} + + +#if defined(MY_CPU_SIZEOF_POINTER) \ + && ( MY_CPU_SIZEOF_POINTER == 4 \ + || MY_CPU_SIZEOF_POINTER == 8) + #define BR_CONV_USE_OPT_PC_PTR +#endif + +#ifdef BR_CONV_USE_OPT_PC_PTR +#define BR_PC_INIT(lim_back) pc -= (UInt32)(SizeT)data; +#define BR_PC_GET (pc + (UInt32)(SizeT)data) +#else +#define BR_PC_INIT(lim_back) pc += (UInt32)dataSize - (lim_back); +#define BR_PC_GET (pc - (UInt32)(SizeT)(data_lim - data)) +#endif + +#ifdef MY_CPU_LE_UNALIGN +#define Z7_RAR5_FILTER_USE_LE_UNALIGN +#endif + +#ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN +#define RAR_E8_FILT(mask) \ +{ \ + for (;;) \ + { UInt32 v; \ + do { \ + v = GetUi32(data) ^ (UInt32)0xe8e8e8e8; \ + data += 4; \ + if ((v & ((UInt32)(mask) << (8 * 0))) == 0) { data -= 3; break; } \ + if ((v & ((UInt32)(mask) << (8 * 1))) == 0) { data -= 2; break; } \ + if ((v & ((UInt32)(mask) << (8 * 2))) == 0) { data -= 1; break; } } \ + while((v & ((UInt32)(mask) << (8 * 3)))); \ + if (data > data_lim) break; \ + const UInt32 offset = BR_PC_GET & (kFileSize - 1); \ + const UInt32 addr = GetUi32(data); \ + data += 4; \ + if (addr < kFileSize) \ + SetUi32(data - 4, addr - offset) \ + else if (addr > ~offset) /* if (addr > ((UInt32)0xFFFFFFFF - offset)) */ \ + SetUi32(data - 4, addr + kFileSize) \ + } \ +} +#else +#define RAR_E8_FILT(get_byte) \ +{ \ + for (;;) \ + { \ + if ((get_byte) != 0xe8) \ + if ((get_byte) != 0xe8) \ + if ((get_byte) != 0xe8) \ + if ((get_byte) != 0xe8) \ + continue; \ + { if (data > data_lim) break; \ + const UInt32 offset = BR_PC_GET & (kFileSize - 1); \ + const UInt32 addr = GetUi32(data); \ + data += 4; \ + if (addr < kFileSize) \ + SetUi32(data - 4, addr - offset) \ + else if (addr > ~offset) /* if (addr > ((UInt32)0xFFFFFFFF - offset)) */ \ + SetUi32(data - 4, addr + kFileSize) \ + } \ + } \ +} +#endif + +HRESULT CDecoder::ExecuteFilter(const CFilter &f) +{ + Byte *data = _filterSrc; + UInt32 dataSize = f.Size; + // printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize); + + if (f.Type == FILTER_DELTA) + { + // static unsigned g1 = 0, g2 = 0; g1 += dataSize; + // if (g2++ % 100 == 0) printf("DELTA num %8u, size %8u MiB, channels = %2u curSize=%8u\n", g2, (g1 >> 20), f.Channels, dataSize); + _filterDst.AllocAtLeast_max((size_t)dataSize, k_Filter_BlockSize_MAX); + if (!_filterDst.IsAllocated()) + return E_OUTOFMEMORY; + + Byte *dest = _filterDst; + const unsigned numChannels = f.Channels; + unsigned curChannel = 0; + do + { + Byte prevByte = 0; + Byte *dest2 = dest + curChannel; + const Byte *dest_lim = dest + dataSize; + for (; dest2 < dest_lim; dest2 += numChannels) + *dest2 = (prevByte = (Byte)(prevByte - *data++)); + } + while (++curChannel != numChannels); + // return WriteData(dest, dataSize); + data = dest; + } + else if (f.Type < FILTER_ARM) + { + // FILTER_E8 or FILTER_E8E9 + if (dataSize > 4) + { + UInt32 pc = (UInt32)(f.Start - _lzFileStart); + const UInt32 kFileSize = (UInt32)1 << 24; + const Byte *data_lim = data + dataSize - 4; + BR_PC_INIT(4) // because (data_lim) was moved back for 4 bytes + data[dataSize] = 0xe8; + if (f.Type == FILTER_E8) + { + // static unsigned g1 = 0; g1 += dataSize; printf("\n FILTER_E8 %u", (g1 >> 20)); +#ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN + RAR_E8_FILT (0xff) +#else + RAR_E8_FILT (*data++) +#endif + } + else + { + // static unsigned g1 = 0; g1 += dataSize; printf("\n FILTER_E8_E9 %u", (g1 >> 20)); +#ifdef Z7_RAR5_FILTER_USE_LE_UNALIGN + RAR_E8_FILT (0xfe) +#else + RAR_E8_FILT (*data++ & 0xfe) +#endif + } + } + data = _filterSrc; + } + else if (f.Type == FILTER_ARM) + { + UInt32 pc = (UInt32)(f.Start - _lzFileStart); +#if 0 + // z7_BranchConv_ARM_Dec expects that (fileOffset & 3) == 0; + // but even if (fileOffset & 3) then current code + // in z7_BranchConv_ARM_Dec works same way as unrar's code still. + z7_BranchConv_ARM_Dec(data, dataSize, pc - 8); +#else + dataSize &= ~(UInt32)3; + if (dataSize) + { + Byte *data_lim = data + dataSize; + data_lim[3] = 0xeb; + BR_PC_INIT(0) + pc -= 4; // because (data) will point to next instruction + for (;;) // do + { + data += 4; + if (data[-1] != 0xeb) + continue; + if (data > data_lim) + break; + { + UInt32 v = GetUi32a(data - 4) - (BR_PC_GET >> 2); + v &= 0x00ffffff; + v |= 0xeb000000; + SetUi32a(data - 4, v) + } + } + } +#endif + data = _filterSrc; + } + else + { + _unsupportedFilter = true; + My_ZeroMemory(data, dataSize); + // return S_OK; // unrar + } + // return WriteData(_filterSrc, (size_t)f.Size); + return WriteData(data, (size_t)f.Size); +} + + +HRESULT CDecoder::WriteBuf() +{ + DeleteUnusedFilters(); + + const UInt64 lzSize = _lzSize + _winPos; + + for (unsigned i = 0; i < _numFilters;) + { + const CFilter &f = _filters[i]; + const UInt64 blockStart = f.Start; + const size_t lzAvail = (size_t)(lzSize - _lzWritten); + if (lzAvail == 0) + break; + + if (blockStart > _lzWritten) + { + const UInt64 rem = blockStart - _lzWritten; + size_t size = lzAvail; + if (size > rem) + size = (size_t)rem; + if (size != 0) // is it true always ? + { + RINOK(WriteData(_window + _winPos - lzAvail, size)) + _lzWritten += size; + } + continue; + } + + const UInt32 blockSize = f.Size; + size_t offset = (size_t)(_lzWritten - blockStart); + if (offset == 0) + { + _filterSrc.AllocAtLeast_max( + (size_t)blockSize + k_Filter_AfterPad_Size, + k_Filter_BlockSize_MAX + k_Filter_AfterPad_Size); + if (!_filterSrc.IsAllocated()) + return E_OUTOFMEMORY; + } + + const size_t blockRem = (size_t)blockSize - offset; + size_t size = lzAvail; + if (size > blockRem) + size = blockRem; + memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size); + _lzWritten += size; + offset += size; + if (offset != blockSize) + return S_OK; + + _numUnusedFilters = ++i; + RINOK(ExecuteFilter(f)) + } + + DeleteUnusedFilters(); + + if (_numFilters) + return S_OK; + + const size_t lzAvail = (size_t)(lzSize - _lzWritten); + RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)) + _lzWritten += lzAvail; + return S_OK; +} + + +Z7_NO_INLINE +static UInt32 ReadUInt32(CBitDecoder &bi) +{ + const unsigned numBits = (unsigned)bi.ReadBits_9fix(2) * 8 + 8; + UInt32 v = 0; + unsigned i = 0; + do + { + v += (UInt32)bi.ReadBits_9fix(8) << i; + i += 8; + } + while (i != numBits); + return v; +} + + +static const unsigned MAX_UNPACK_FILTERS = 8192; + +HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream) +{ + DeleteUnusedFilters(); + + if (_numFilters >= MAX_UNPACK_FILTERS) + { + RINOK(WriteBuf()) + DeleteUnusedFilters(); + if (_numFilters >= MAX_UNPACK_FILTERS) + { + _unsupportedFilter = true; + InitFilters(); + } + } + + _bitStream.Prepare(); + + CFilter f; + const UInt32 blockStart = ReadUInt32(_bitStream); + f.Size = ReadUInt32(_bitStream); + + if (f.Size > k_Filter_BlockSize_MAX) + { + _unsupportedFilter = true; + f.Size = 0; // unrar 5.5.5 + } + + f.Type = (Byte)_bitStream.ReadBits_9fix(3); + f.Channels = 0; + if (f.Type == FILTER_DELTA) + f.Channels = (Byte)(_bitStream.ReadBits_9fix(5) + 1); + f.Start = _lzSize + _winPos + blockStart; + +#if 0 + static unsigned z_cnt = 0; if (z_cnt++ % 100 == 0) + printf ("\nFilter %7u : %4u : %8p, st=%8x, size=%8x, type=%u ch=%2u", + z_cnt, (unsigned)_filters.Size(), (void *)(size_t)(_lzSize + _winPos), + (unsigned)blockStart, (unsigned)f.Size, (unsigned)f.Type, (unsigned)f.Channels); +#endif + + if (f.Start < _filterEnd) + _unsupportedFilter = true; + else + { + _filterEnd = f.Start + f.Size; + if (f.Size != 0) + { + if (!_filters) + { + _filters = (CFilter *)z7_AlignedAlloc(MAX_UNPACK_FILTERS * sizeof(CFilter)); + if (!_filters) + return E_OUTOFMEMORY; + } + // printf("\n_numFilters = %6u\n", _numFilters); + const unsigned i = _numFilters++; + _filters[i] = f; + } + } + + return S_OK; +} + + +#define RIF(x) { if (!(x)) return S_FALSE; } + +#if 1 +#define PRINT_CNT(name, skip) +#else +#define PRINT_CNT(name, skip) \ + { static unsigned g_cnt = 0; if (g_cnt++ % skip == 0) printf("\n%16s: %8u", name, g_cnt); } +#endif + +HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) +{ + if (_progress) + { + const UInt64 packSize = _bitStream.GetProcessedSize(); + if (packSize - _progress_Pack >= (1u << 24) + || _writtenFileSize - _progress_Unpack >= (1u << 26)) + { + _progress_Pack = packSize; + _progress_Unpack = _writtenFileSize; + RINOK(_progress->SetRatioInfo(&_progress_Pack, &_writtenFileSize)) + } + // printf("\ntable read pos=%p packSize=%p _writtenFileSize = %p\n", (size_t)_winPos, (size_t)packSize, (size_t)_writtenFileSize); + } + + // _bitStream is aligned already + _bitStream.Prepare(); + { + const unsigned flags = _bitStream.ReadByte_InAligned(); + /* ((flags & 20) == 0) in all rar archives now, + but (flags & 20) flag can be used as some decoding hint in future versions of original rar. + So we ignore that bit here. */ + unsigned checkSum = _bitStream.ReadByte_InAligned(); + checkSum ^= flags; + const unsigned num = (flags >> 3) & 3; + if (num >= 3) + return S_FALSE; + UInt32 blockSize = _bitStream.ReadByte_InAligned(); + checkSum ^= blockSize; + if (num != 0) + { + { + const unsigned b = _bitStream.ReadByte_InAligned(); + checkSum ^= b; + blockSize += (UInt32)b << 8; + } + if (num > 1) + { + const unsigned b = _bitStream.ReadByte_InAligned(); + checkSum ^= b; + blockSize += (UInt32)b << 16; + } + } + if (checkSum != 0x5A) + return S_FALSE; + unsigned blockSizeBits7 = (flags & 7) + 1; + blockSize += (UInt32)(blockSizeBits7 >> 3); + if (blockSize == 0) + { + // it's error in data stream + // but original-unrar ignores that error + _bitStream._minorError = true; +#if 1 + // we ignore that error as original-unrar: + blockSizeBits7 = 0; + blockSize = 1; +#else + // we can stop decoding: + return S_FALSE; +#endif + } + blockSize--; + blockSizeBits7 &= 7; + PRINT_CNT("Blocks", 100) + /* + { + static unsigned g_prev = 0; + static unsigned g_cnt = 0; + unsigned proc = unsigned(_winPos); + if (g_cnt++ % 100 == 0) printf(" c_size = %8u ", blockSize); + if (g_cnt++ % 100 == 1) printf(" unp_size = %8u", proc - g_prev); + g_prev = proc; + } + */ + _bitStream._blockEndBits7 = blockSizeBits7; + _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize; + _bitStream.SetCheck_forBlock(); + _isLastBlock = ((flags & 0x40) != 0); + if ((flags & 0x80) == 0) + { + if (!_tableWasFilled) + // if (blockSize != 0 || blockSizeBits7 != 0) + if (blockSize + blockSizeBits7 != 0) + return S_FALSE; + return S_OK; + } + _tableWasFilled = false; + } + + PRINT_CNT("Tables", 100); + + const unsigned kLevelTableSize = 20; + const unsigned k_NumHufTableBits_Level = 6; + NHuffman::CDecoder256 m_LevelDecoder; + const unsigned kTablesSizesSum_MAX = kMainTableSize + kDistTableSize_MAX + kAlignTableSize + kLenTableSize; + Byte lens[kTablesSizesSum_MAX]; + { + // (kLevelTableSize + 16 < kTablesSizesSum). So we use lens[] array for (Level) table + // Byte lens2[kLevelTableSize + 16]; + unsigned i = 0; + do + { + if (_bitStream._buf >= _bitStream._bufCheck_Block) + { + _bitStream.Prepare(); + if (_bitStream.IsBlockOverRead()) + return S_FALSE; + } + const unsigned len = (unsigned)_bitStream.ReadBits_9fix(4); + if (len == 15) + { + unsigned num = (unsigned)_bitStream.ReadBits_9fix(4); + if (num != 0) + { + num += 2; + num += i; + // we are allowed to overwrite to lens[] for extra 16 bytes after kLevelTableSize +#if 0 + if (num > kLevelTableSize) + { + // we ignore this error as original-unrar + num = kLevelTableSize; + // return S_FALSE; + } +#endif + do + lens[i++] = 0; + while (i < num); + continue; + } + } + lens[i++] = (Byte)len; + } + while (i < kLevelTableSize); + if (_bitStream.IsBlockOverRead()) + return S_FALSE; + RIF(m_LevelDecoder.Build(lens, NHuffman::k_BuildMode_Full)) + } + + unsigned i = 0; + const unsigned tableSize = _is_v7 ? + kTablesSizesSum_MAX : + kTablesSizesSum_MAX - kExtraDistSymbols_v7; + do + { + if (_bitStream._buf >= _bitStream._bufCheck_Block) + { + // if (_bitStream._buf >= _bitStream._bufCheck) + _bitStream.Prepare(); + if (_bitStream.IsBlockOverRead()) + return S_FALSE; + } + const unsigned sym = m_LevelDecoder.DecodeFull(&_bitStream); + if (sym < 16) + lens[i++] = (Byte)sym; +#if 0 + else if (sym > kLevelTableSize) + return S_FALSE; +#endif + else + { + unsigned num = ((sym /* - 16 */) & 1) * 4; + num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3); + num += i; + if (num > tableSize) + { + // we ignore this error as original-unrar + num = tableSize; + // return S_FALSE; + } + unsigned v = 0; + if (sym < 16 + 2) + { + if (i == 0) + return S_FALSE; + v = lens[(size_t)i - 1]; + } + do + lens[i++] = (Byte)v; + while (i < num); + } + } + while (i < tableSize); + + if (_bitStream.IsBlockOverRead()) + return S_FALSE; + if (_bitStream.InputEofError()) + return S_FALSE; + + /* We suppose that original-rar encoder can create only two cases for Huffman: + 1) Empty Huffman tree (if num_used_symbols == 0) + 2) Full Huffman tree (if num_used_symbols != 0) + Usually the block contains at least one symbol for m_MainDecoder. + So original-rar-encoder creates full Huffman tree for m_MainDecoder. + But we suppose that (num_used_symbols == 0) is possible for m_MainDecoder, + because file must be finished with (_isLastBlock) flag, + even if there are no symbols in m_MainDecoder. + So we use k_BuildMode_Full_or_Empty for m_MainDecoder. + */ + const NHuffman::enum_BuildMode buildMode = NHuffman:: + k_BuildMode_Full_or_Empty; // strict check + // k_BuildMode_Partial; // non-strict check (ignore errors) + + RIF(m_MainDecoder.Build(&lens[0], buildMode)) + if (!_is_v7) + { +#if 1 + /* we use this manual loop to avoid compiler BUG. + GCC 4.9.2 compiler has BUG with overlapping memmove() to right in local array. */ + Byte *dest = lens + kMainTableSize + kDistTableSize_v6 + + kAlignTableSize + kLenTableSize - 1; + unsigned num = kAlignTableSize + kLenTableSize; + do + { + dest[kExtraDistSymbols_v7] = dest[0]; + dest--; + } + while (--num); +#else + memmove(lens + kMainTableSize + kDistTableSize_v6 + kExtraDistSymbols_v7, + lens + kMainTableSize + kDistTableSize_v6, + kAlignTableSize + kLenTableSize); +#endif + memset(lens + kMainTableSize + kDistTableSize_v6, 0, kExtraDistSymbols_v7); + } + + RIF(m_DistDecoder.Build(&lens[kMainTableSize], buildMode)) + RIF( m_LenDecoder.Build(&lens[kMainTableSize + + kDistTableSize_MAX + kAlignTableSize], buildMode)) + + _useAlignBits = false; + for (i = 0; i < kAlignTableSize; i++) + if (lens[kMainTableSize + kDistTableSize_MAX + (size_t)i] != kNumAlignBits) + { + RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize_MAX], buildMode)) + _useAlignBits = true; + break; + } + + _tableWasFilled = true; + return S_OK; +} + +static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot) +{ + const unsigned numBits = ((unsigned)slot >> 2) - 1; + return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits9(numBits); +} + + +static const unsigned kSymbolRep = 258; +static const unsigned kMaxMatchLen = 0x1001 + 3; + +enum enum_exit_type +{ + Z7_RAR_EXIT_TYPE_NONE, + Z7_RAR_EXIT_TYPE_ADD_FILTER +}; + + +#define LZ_RESTORE \ +{ \ + _reps[0] = rep0; \ + _winPos = (size_t)(winPos - _window); \ + _buf_Res = _bitStream._buf; \ + _bitPos_Res = _bitStream._bitPos; \ +} + +#define LZ_LOOP_BREAK_OK { break; } +// #define LZ_LOOP_BREAK_ERROR { _lzError = LZ_ERROR_TYPE_SYM; break; } +// #define LZ_LOOP_BREAK_ERROR { LZ_RESTORE; return S_FALSE; } +#define LZ_LOOP_BREAK_ERROR { goto decode_error; } +// goto decode_error; } +// #define LZ_LOOP_BREAK_ERROR { break; } + +#define Z7_RAR_HUFF_DECODE_CHECK_break(sym, huf, kNumTableBits, bitStream) \ + Z7_HUFF_DECODE_CHECK(sym, huf, kNumHufBits, kNumTableBits, bitStream, { LZ_LOOP_BREAK_ERROR }) + + +HRESULT CDecoder::DecodeLZ2(const CBitDecoder &bitStream) throw() +{ +#if 0 + Byte k_LenPlusTable_LOC[DICT_SIZE_BITS_MAX]; + memcpy(k_LenPlusTable_LOC, k_LenPlusTable, sizeof(k_LenPlusTable)); +#endif + + PRINT_CNT("DecodeLZ2", 2000); + + CBitDecoder _bitStream; + _bitStream.CopyFrom(bitStream); + // _bitStream._stream = _inStream; + // _bitStream._bufBase = _inputBuf; + // _bitStream.Init(); + + // _reps[*] can be larger than _winSize, if _winSize was reduced in solid stream. + size_t rep0 = _reps[0]; + // size_t rep1 = _reps[1]; + // Byte *win = _window; + Byte *winPos = _window + _winPos; + const Byte *limit = _window + _limit; + _exitType = Z7_RAR_EXIT_TYPE_NONE; + + for (;;) + { + if (winPos >= limit) + LZ_LOOP_BREAK_OK + // (winPos < limit) + if (_bitStream._buf >= _bitStream._bufCheck_Block) + { + if (_bitStream.InputEofError()) + LZ_LOOP_BREAK_OK + if (_bitStream._buf >= _bitStream._bufCheck) + { + if (!_bitStream._wasFinished) + LZ_LOOP_BREAK_OK + // _bitStream._wasFinished == true + // we don't need Prepare() here, because all data was read + // and PadZone (16 bytes) after data was filled. + } + const UInt64 processed = _bitStream.GetProcessedSize_Round(); + // some cases are error, but the caller will process such error cases. + if (processed >= _bitStream._blockEnd && + (processed > _bitStream._blockEnd + || _bitStream.GetProcessedBits7() >= _bitStream._blockEndBits7)) + LZ_LOOP_BREAK_OK + // that check is not required, but it can help, if there is BUG in another code + if (!_tableWasFilled) + LZ_LOOP_BREAK_ERROR + } + +#if 0 + const unsigned sym = m_MainDecoder.Decode(&_bitStream); +#else + unsigned sym; + Z7_RAR_HUFF_DECODE_CHECK_break(sym, &m_MainDecoder, k_NumHufTableBits_Main, &_bitStream) +#endif + + if (sym < 256) + { + *winPos++ = (Byte)sym; + // _lzSize++; + continue; + } + + CLenType len; + + if (sym < kSymbolRep + kNumReps) + { + if (sym >= kSymbolRep) + { + if (sym != kSymbolRep) + { + size_t dist = _reps[1]; + _reps[1] = rep0; + rep0 = dist; + if (sym >= kSymbolRep + 2) + { + #if 1 + rep0 = _reps[(size_t)sym - kSymbolRep]; + _reps[(size_t)sym - kSymbolRep] = _reps[2]; + _reps[2] = dist; + #else + if (sym != kSymbolRep + 2) + { + rep0 = _reps[3]; + _reps[3] = _reps[2]; + _reps[2] = dist; + } + else + { + rep0 = _reps[2]; + _reps[2] = dist; + } + #endif + } + } +#if 0 + len = m_LenDecoder.Decode(&_bitStream); + if (len >= kLenTableSize) + LZ_LOOP_BREAK_ERROR +#else + Z7_RAR_HUFF_DECODE_CHECK_break(len, &m_LenDecoder, k_NumHufTableBits_Len, &_bitStream) +#endif + if (len >= 8) + len = SlotToLen(_bitStream, len); + len += 2; + // _lastLen = (UInt32)len; + } + else if (sym != 256) + { + len = (CLenType)_lastLen; + if (len == 0) + { + // we ignore (_lastLen == 0) case, like original-unrar. + // that case can mean error in stream. + // lzError = true; + // return S_FALSE; + continue; + } + } + else + { + _exitType = Z7_RAR_EXIT_TYPE_ADD_FILTER; + LZ_LOOP_BREAK_OK + } + } +#if 0 + else if (sym >= kMainTableSize) + LZ_LOOP_BREAK_ERROR +#endif + else + { + _reps[3] = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = rep0; + len = sym - (kSymbolRep + kNumReps); + if (len >= 8) + len = SlotToLen(_bitStream, len); + len += 2; + // _lastLen = (UInt32)len; + +#if 0 + rep0 = (UInt32)m_DistDecoder.Decode(&_bitStream); +#else + Z7_RAR_HUFF_DECODE_CHECK_break(rep0, &m_DistDecoder, k_NumHufTableBits_Dist, &_bitStream) +#endif + + if (rep0 >= 4) + { +#if 0 + if (rep0 >= kDistTableSize_MAX) + LZ_LOOP_BREAK_ERROR +#endif + const unsigned numBits = ((unsigned)rep0 - 2) >> 1; + rep0 = (2 | (rep0 & 1)) << numBits; + + const Byte *buf = _bitStream._buf; +#ifdef Z7_RAR5_USE_64BIT + const UInt64 v = GetBe64(buf); +#else + const UInt32 v = GetBe32(buf); +#endif + + // _lastLen = (UInt32)len; + if (numBits < kNumAlignBits) + { + rep0 += // _bitStream.ReadBits9(numBits); + _bitStream.ReadBits_Big25(numBits, v); + } + else + { + #if !defined(MY_CPU_AMD64) + len += k_LenPlusTable[numBits]; + #elif 0 + len += k_LenPlusTable_LOC[numBits]; + #elif 1 + len += m_LenPlusTable[numBits]; + #elif 1 && defined(MY_CPU_64BIT) && defined(MY_CPU_AMD64) + // len += (unsigned)((UInt64)0xfffffffeaa554000 >> (numBits * 2)) & 3; + len += (unsigned)((UInt64)0xfffffffffeaa5540 >> (numBits * 2 - 8)) & 3; + #elif 1 + len += 3; + len -= (unsigned)(numBits - 7) >> (sizeof(unsigned) * 8 - 1); + len -= (unsigned)(numBits - 12) >> (sizeof(unsigned) * 8 - 1); + len -= (unsigned)(numBits - 17) >> (sizeof(unsigned) * 8 - 1); + #elif 1 + len += 3; + len -= (0x155aabf >> (numBits - 4) >> (numBits - 4)) & 3; + #elif 1 + len += (numBits >= 7); + len += (numBits >= 12); + len += (numBits >= 17); + #endif + // _lastLen = (UInt32)len; + if (_useAlignBits) + { + // if (numBits > kNumAlignBits) + rep0 += (_bitStream.ReadBits_Big25(numBits - kNumAlignBits, v) << kNumAlignBits); +#if 0 + const unsigned a = m_AlignDecoder.Decode(&_bitStream); + if (a >= kAlignTableSize) + LZ_LOOP_BREAK_ERROR +#else + unsigned a; + Z7_RAR_HUFF_DECODE_CHECK_break(a, &m_AlignDecoder, k_NumHufTableBits_Align, &_bitStream) +#endif + rep0 += a; + } + else + rep0 += _bitStream.ReadBits_Big(numBits, v); +#ifndef Z7_RAR5_USE_64BIT + if (numBits >= 30) // we don't want 32-bit overflow case + rep0 = (size_t)0 - 1 - 1; +#endif + } + } + rep0++; + } + + { + _lastLen = (UInt32)len; + // len != 0 + +#ifdef Z7_RAR5_SHOW_STAT + { + size_t index = rep0; + if (index >= kNumStats1) + index = kNumStats1 - 1; + g_stats1[index]++; + g_stats2[index][len]++; + } +#endif + + Byte *dest = winPos; + winPos += len; + if (rep0 <= _dictSize_forCheck) + { + const Byte *src; + const size_t winPos_temp = (size_t)(dest - _window); + if (rep0 > winPos_temp) + { + if (_lzSize == 0) + goto error_dist; + size_t back = rep0 - winPos_temp; + // STAT_INC(g_NumOver) + src = dest + (_winSize - rep0); + if (back < len) + { + // len -= (CLenType)back; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + *dest++ = *src++; + while (--back); + src = dest - rep0; + } + } + else + src = dest - rep0; + CopyMatch(rep0, dest, src, winPos); + continue; + } + +error_dist: + // LZ_LOOP_BREAK_ERROR; + _lzError = LZ_ERROR_TYPE_DIST; + do + *dest++ = 0; + while (dest < winPos); + continue; + } + } + + LZ_RESTORE + return S_OK; + +#if 1 +decode_error: + /* + if (_bitStream._hres != S_OK) + return _bitStream._hres; + */ + LZ_RESTORE + return S_FALSE; +#endif +} + + + +HRESULT CDecoder::DecodeLZ() +{ + CBitDecoder _bitStream; + _bitStream._stream = _inStream; + _bitStream._bufBase = _inputBuf; + _bitStream.Init(); + + // _reps[*] can be larger than _winSize, if _winSize was reduced in solid stream. + size_t winPos = _winPos; + Byte *win = _window; + size_t limit; + { + size_t rem = _winSize - winPos; + if (rem > kWriteStep) + rem = kWriteStep; + limit = winPos + rem; + } + + for (;;) + { + if (winPos >= limit) + { + _winPos = winPos < _winSize ? winPos : _winSize; + RINOK(WriteBuf()) + if (_unpackSize_Defined && _writtenFileSize > _unpackSize) + break; // return S_FALSE; + const size_t wp = _winPos; + size_t rem = _winSize - wp; + if (rem == 0) + { + _lzSize += wp; + winPos -= wp; + // (winPos < kMaxMatchLen < _winSize) + // so memmove is not required here + if (winPos) + memcpy(win, win + _winSize, winPos); + limit = _winSize; + if (limit >= kWriteStep) + { + limit = kWriteStep; + continue; + } + rem = _winSize - winPos; + } + if (rem > kWriteStep) + rem = kWriteStep; + limit = winPos + rem; + continue; + } + + // (winPos < limit) + + if (_bitStream._buf >= _bitStream._bufCheck_Block) + { + _winPos = winPos; + if (_bitStream.InputEofError()) + break; // return S_FALSE; + _bitStream.Prepare(); + + const UInt64 processed = _bitStream.GetProcessedSize_Round(); + if (processed >= _bitStream._blockEnd) + { + if (processed > _bitStream._blockEnd) + break; // return S_FALSE; + { + const unsigned bits7 = _bitStream.GetProcessedBits7(); + if (bits7 >= _bitStream._blockEndBits7) + { + if (bits7 > _bitStream._blockEndBits7) + { +#if 1 + // we ignore thar error as original unrar + _bitStream._minorError = true; +#else + break; // return S_FALSE; +#endif + } + _bitStream.AlignToByte(); + // if (!_bitStream.AlignToByte()) break; + if (_isLastBlock) + { + if (_bitStream.InputEofError()) + break; + /* + // packSize can be 15 bytes larger for encrypted archive + if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize()) + break; + */ + if (_bitStream._minorError) + return S_FALSE; + return _bitStream._hres; + // break; + } + RINOK(ReadTables(_bitStream)) + continue; + } + } + } + + // end of block was not reached. + // so we must decode more symbols + // that check is not required, but it can help, if there is BUG in another code + if (!_tableWasFilled) + break; // return S_FALSE; + } + + _limit = limit; + _winPos = winPos; + RINOK(DecodeLZ2(_bitStream)) + _bitStream._buf = _buf_Res; + _bitStream._bitPos = _bitPos_Res; + + winPos = _winPos; + if (_exitType == Z7_RAR_EXIT_TYPE_ADD_FILTER) + { + RINOK(AddFilter(_bitStream)) + continue; + } + } + + _winPos = winPos; + + if (_bitStream._hres != S_OK) + return _bitStream._hres; + + return S_FALSE; +} + + + +HRESULT CDecoder::CodeReal() +{ + _unsupportedFilter = false; + _writeError = false; + /* + if (!_isSolid || !_wasInit) + { + _wasInit = true; + // _lzSize = 0; + _lzWritten = 0; + _winPos = 0; + for (unsigned i = 0; i < kNumReps; i++) + _reps[i] = (size_t)0 - 1; + _lastLen = 0; + _tableWasFilled = false; + } + */ + _isLastBlock = false; + + InitFilters(); + + _filterEnd = 0; + _writtenFileSize = 0; + const UInt64 lzSize = _lzSize + _winPos; + _lzFileStart = lzSize; + _lzWritten = lzSize; + + HRESULT res = DecodeLZ(); + + HRESULT res2 = S_OK; + if (!_writeError && res != E_OUTOFMEMORY) + res2 = WriteBuf(); + /* + if (res == S_OK) + if (InputEofError()) + res = S_FALSE; + */ + if (res == S_OK) + { + // _solidAllowed = true; + res = res2; + } + if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize) + return S_FALSE; + return res; +} + + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + _lzError = LZ_ERROR_TYPE_NO; +/* + if file is soild, but decoding of previous file was not finished, + we still try to decode new file. + We need correct huffman table at starting block. + And rar encoder probably writes huffman table at start block, if file is big. + So we have good chance to get correct huffman table in some file after corruption. + Also we try to recover window by filling zeros, if previous file + was decoded to smaller size than required. + But if filling size is big, we do full reset of window instead. +*/ + #define Z7_RAR_RECOVER_SOLID_LIMIT (1 << 20) + // #define Z7_RAR_RECOVER_SOLID_LIMIT 0 // do not fill zeros + { + // if (_winPos > 100) _winPos -= 100; // for debug: corruption + const UInt64 lzSize = _lzSize + _winPos; + if (!_isSolid || !_wasInit + || (lzSize < _lzEnd +#if Z7_RAR_RECOVER_SOLID_LIMIT != 0 + && lzSize + Z7_RAR_RECOVER_SOLID_LIMIT < _lzEnd +#endif + )) + { + if (_isSolid) + _lzError = LZ_ERROR_TYPE_HEADER; + _lzEnd = 0; + _lzSize = 0; + _lzWritten = 0; + _winPos = 0; + for (unsigned i = 0; i < kNumReps; i++) + _reps[i] = (size_t)0 - 1; + _lastLen = 0; + _tableWasFilled = false; + _wasInit = true; + } +#if Z7_RAR_RECOVER_SOLID_LIMIT != 0 + else if (lzSize < _lzEnd) + { +#if 0 + return S_FALSE; +#else + // we can report that recovering was made: + // _lzError = LZ_ERROR_TYPE_HEADER; + // We write zeros to area after corruption: + if (_window) + { + UInt64 rem = _lzEnd - lzSize; + const size_t ws = _winSize; + if (rem >= ws) + { + My_ZeroMemory(_window, ws); + _lzSize = ws; + _winPos = 0; + } + else + { + const size_t cur = ws - _winPos; + if (cur <= rem) + { + rem -= cur; + My_ZeroMemory(_window + _winPos, cur); + _lzSize += _winPos; + _winPos = 0; + } + My_ZeroMemory(_window + _winPos, (size_t)rem); + _winPos += (size_t)rem; + } + } + // else return S_FALSE; +#endif + } +#endif + } + + // we don't want _lzSize overflow + if (_lzSize >= DICT_SIZE_MAX) + _lzSize = DICT_SIZE_MAX; + _lzEnd = _lzSize + _winPos; + // _lzSize <= DICT_SIZE_MAX + // _lzEnd <= DICT_SIZE_MAX * 2 + + size_t newSize = _dictSize; + if (newSize < kWinSize_Min) + newSize = kWinSize_Min; + + _unpackSize = 0; + _unpackSize_Defined = (outSize != NULL); + if (_unpackSize_Defined) + _unpackSize = *outSize; + + if ((Int64)_unpackSize >= 0) + _lzEnd += _unpackSize; // known end after current file + else + _lzEnd = 0; // unknown end + + if (_isSolid && _window) + { + // If dictionary was decreased in solid, we use old dictionary. + if (newSize > _dictSize_forCheck) + { + // If dictionary was increased in solid, we don't want grow. + return S_FALSE; // E_OUTOFMEMORY + } + // (newSize <= _winSize) + } + else + { + _dictSize_forCheck = newSize; + { + size_t newSize_small = newSize; + const size_t k_Win_AlignSize = 1u << 18; + /* here we add (1 << 7) instead of (COPY_CHUNK_SIZE - 1), because + we want to get same (_winSize) for different COPY_CHUNK_SIZE values. */ + // newSize += (COPY_CHUNK_SIZE - 1) + (k_Win_AlignSize - 1); // for debug : we can get smallest (_winSize) + newSize += (1 << 7) + k_Win_AlignSize; + newSize &= ~(size_t)(k_Win_AlignSize - 1); + if (newSize < newSize_small) + return E_OUTOFMEMORY; + } + // (!_isSolid || !_window) + const size_t allocSize = newSize + kMaxMatchLen + 64; + if (allocSize < newSize) + return E_OUTOFMEMORY; + if (!_window || allocSize > _winSize_Allocated) + { + Z7_RAR_FREE_WINDOW + _window = NULL; + _winSize_Allocated = 0; + Byte *win = (Byte *)::BigAlloc(allocSize); + if (!win) + return E_OUTOFMEMORY; + _window = win; + _winSize_Allocated = allocSize; + } + _winSize = newSize; + } + + if (!_inputBuf) + { + _inputBuf = (Byte *)z7_AlignedAlloc(kInputBufSize + kInputBufferPadZone); + if (!_inputBuf) + return E_OUTOFMEMORY; + } + + _inStream = inStream; + _outStream = outStream; + _progress = progress; + _progress_Pack = 0; + _progress_Unpack = 0; + + const HRESULT res = CodeReal(); + + if (res != S_OK) + return res; + // _lzError = LZ_ERROR_TYPE_HEADER; // for debug + if (_lzError) + return S_FALSE; + if (_unsupportedFilter) + return E_NOTIMPL; + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + if (size != 2) + return E_INVALIDARG; + const unsigned pow = data[0]; + const unsigned b1 = data[1]; + const unsigned frac = b1 >> 3; + // unsigned pow = 15 + 8; + // unsigned frac = 1; + if (pow + ((frac + 31) >> 5) > MAX_DICT_LOG - 17) + // if (frac + (pow << 8) >= ((8 * 2 + 7) << 5) + 8 / 8) + return E_NOTIMPL; + _dictSize = (size_t)(frac + 32) << (pow + 12); + _isSolid = (b1 & 1) != 0; + _is_v7 = (b1 & 2) != 0; + // printf("\ndict size = %p\n", (void *)(size_t)_dictSize); + return S_OK; +} + +}} diff --git a/CPP/7zip/Compress/Rar5Decoder.h b/CPP/7zip/Compress/Rar5Decoder.h index 16d956924..66c1c3c28 100644 --- a/CPP/7zip/Compress/Rar5Decoder.h +++ b/CPP/7zip/Compress/Rar5Decoder.h @@ -1,132 +1,132 @@ -// Rar5Decoder.h -// According to unRAR license, this code may not be used to develop -// a program that creates RAR archives - -#ifndef ZIP7_INC_COMPRESS_RAR5_DECODER_H -#define ZIP7_INC_COMPRESS_RAR5_DECODER_H - -#include "../../Common/MyBuffer2.h" -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -#include "HuffmanDecoder.h" - -namespace NCompress { -namespace NRar5 { - -class CBitDecoder; - -struct CFilter -{ - Byte Type; - Byte Channels; - UInt32 Size; - UInt64 Start; -}; - - -const unsigned kNumReps = 4; -const unsigned kLenTableSize = 11 * 4; -const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize; -const unsigned kExtraDistSymbols_v7 = 16; -const unsigned kDistTableSize_v6 = 64; -const unsigned kDistTableSize_MAX = 64 + kExtraDistSymbols_v7; -const unsigned kNumAlignBits = 4; -const unsigned kAlignTableSize = 1 << kNumAlignBits; - -const unsigned kNumHufBits = 15; - -const unsigned k_NumHufTableBits_Main = 10; -const unsigned k_NumHufTableBits_Dist = 7; -const unsigned k_NumHufTableBits_Len = 7; -const unsigned k_NumHufTableBits_Align = 6; - -const unsigned DICT_SIZE_BITS_MAX = 40; - -Z7_CLASS_IMP_NOQIB_2( - CDecoder - , ICompressCoder - , ICompressSetDecoderProperties2 -) - bool _useAlignBits; - bool _isLastBlock; - bool _unpackSize_Defined; - // bool _packSize_Defined; - - bool _unsupportedFilter; - Byte _lzError; - bool _writeError; - - bool _isSolid; - // bool _solidAllowed; - bool _is_v7; - bool _tableWasFilled; - bool _wasInit; - - Byte _exitType; - - // Byte _dictSizeLog; - size_t _dictSize; - Byte *_window; - size_t _winPos; - size_t _winSize; - size_t _dictSize_forCheck; - size_t _limit; - const Byte *_buf_Res; - UInt64 _lzSize; - size_t _reps[kNumReps]; - unsigned _bitPos_Res; - UInt32 _lastLen; - - // unsigned _numCorrectDistSymbols; - unsigned _numUnusedFilters; - unsigned _numFilters; - - UInt64 _lzWritten; - UInt64 _lzFileStart; - UInt64 _unpackSize; - // UInt64 _packSize; - UInt64 _lzEnd; - UInt64 _writtenFileSize; - UInt64 _filterEnd; - UInt64 _progress_Pack; - UInt64 _progress_Unpack; - CAlignedBuffer _filterSrc; - CAlignedBuffer _filterDst; - - CFilter *_filters; - size_t _winSize_Allocated; - ISequentialInStream *_inStream; - ISequentialOutStream *_outStream; - ICompressProgressInfo *_progress; - Byte *_inputBuf; - - NHuffman::CDecoder m_MainDecoder; - NHuffman::CDecoder256 m_DistDecoder; - NHuffman::CDecoder256 m_AlignDecoder; - NHuffman::CDecoder256 m_LenDecoder; - Byte m_LenPlusTable[DICT_SIZE_BITS_MAX]; - - void InitFilters() - { - _numUnusedFilters = 0; - _numFilters = 0; - } - void DeleteUnusedFilters(); - HRESULT WriteData(const Byte *data, size_t size); - HRESULT ExecuteFilter(const CFilter &f); - HRESULT WriteBuf(); - HRESULT AddFilter(CBitDecoder &_bitStream); - HRESULT ReadTables(CBitDecoder &_bitStream); - HRESULT DecodeLZ2(const CBitDecoder &_bitStream) throw(); - HRESULT DecodeLZ(); - HRESULT CodeReal(); -public: - CDecoder(); - ~CDecoder(); -}; - -}} - -#endif +// Rar5Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef ZIP7_INC_COMPRESS_RAR5_DECODER_H +#define ZIP7_INC_COMPRESS_RAR5_DECODER_H + +#include "../../Common/MyBuffer2.h" +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "HuffmanDecoder.h" + +namespace NCompress { +namespace NRar5 { + +class CBitDecoder; + +struct CFilter +{ + Byte Type; + Byte Channels; + UInt32 Size; + UInt64 Start; +}; + + +const unsigned kNumReps = 4; +const unsigned kLenTableSize = 11 * 4; +const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize; +const unsigned kExtraDistSymbols_v7 = 16; +const unsigned kDistTableSize_v6 = 64; +const unsigned kDistTableSize_MAX = 64 + kExtraDistSymbols_v7; +const unsigned kNumAlignBits = 4; +const unsigned kAlignTableSize = 1 << kNumAlignBits; + +const unsigned kNumHufBits = 15; + +const unsigned k_NumHufTableBits_Main = 10; +const unsigned k_NumHufTableBits_Dist = 7; +const unsigned k_NumHufTableBits_Len = 7; +const unsigned k_NumHufTableBits_Align = 6; + +const unsigned DICT_SIZE_BITS_MAX = 40; + +Z7_CLASS_IMP_NOQIB_2( + CDecoder + , ICompressCoder + , ICompressSetDecoderProperties2 +) + bool _useAlignBits; + bool _isLastBlock; + bool _unpackSize_Defined; + // bool _packSize_Defined; + + bool _unsupportedFilter; + Byte _lzError; + bool _writeError; + + bool _isSolid; + // bool _solidAllowed; + bool _is_v7; + bool _tableWasFilled; + bool _wasInit; + + Byte _exitType; + + // Byte _dictSizeLog; + size_t _dictSize; + Byte *_window; + size_t _winPos; + size_t _winSize; + size_t _dictSize_forCheck; + size_t _limit; + const Byte *_buf_Res; + UInt64 _lzSize; + size_t _reps[kNumReps]; + unsigned _bitPos_Res; + UInt32 _lastLen; + + // unsigned _numCorrectDistSymbols; + unsigned _numUnusedFilters; + unsigned _numFilters; + + UInt64 _lzWritten; + UInt64 _lzFileStart; + UInt64 _unpackSize; + // UInt64 _packSize; + UInt64 _lzEnd; + UInt64 _writtenFileSize; + UInt64 _filterEnd; + UInt64 _progress_Pack; + UInt64 _progress_Unpack; + CAlignedBuffer _filterSrc; + CAlignedBuffer _filterDst; + + CFilter *_filters; + size_t _winSize_Allocated; + ISequentialInStream *_inStream; + ISequentialOutStream *_outStream; + ICompressProgressInfo *_progress; + Byte *_inputBuf; + + NHuffman::CDecoder m_MainDecoder; + NHuffman::CDecoder256 m_DistDecoder; + NHuffman::CDecoder256 m_AlignDecoder; + NHuffman::CDecoder256 m_LenDecoder; + Byte m_LenPlusTable[DICT_SIZE_BITS_MAX]; + + void InitFilters() + { + _numUnusedFilters = 0; + _numFilters = 0; + } + void DeleteUnusedFilters(); + HRESULT WriteData(const Byte *data, size_t size); + HRESULT ExecuteFilter(const CFilter &f); + HRESULT WriteBuf(); + HRESULT AddFilter(CBitDecoder &_bitStream); + HRESULT ReadTables(CBitDecoder &_bitStream); + HRESULT DecodeLZ2(const CBitDecoder &_bitStream) throw(); + HRESULT DecodeLZ(); + HRESULT CodeReal(); +public: + CDecoder(); + ~CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/RarCodecsRegister.cpp b/CPP/7zip/Compress/RarCodecsRegister.cpp index 9679b6e5e..e1bc3d9b3 100644 --- a/CPP/7zip/Compress/RarCodecsRegister.cpp +++ b/CPP/7zip/Compress/RarCodecsRegister.cpp @@ -1,33 +1,33 @@ -// RarCodecsRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "Rar1Decoder.h" -#include "Rar2Decoder.h" -#include "Rar3Decoder.h" -#include "Rar5Decoder.h" - -namespace NCompress { - -#define CREATE_CODEC(x) REGISTER_CODEC_CREATE(CreateCodec ## x, NRar ## x::CDecoder()) - -CREATE_CODEC(1) -CREATE_CODEC(2) -CREATE_CODEC(3) -CREATE_CODEC(5) - -#define RAR_CODEC(x, name) { CreateCodec ## x, NULL, 0x40300 + x, "Rar" name, 1, false } - -REGISTER_CODECS_VAR -{ - RAR_CODEC(1, "1"), - RAR_CODEC(2, "2"), - RAR_CODEC(3, "3"), - RAR_CODEC(5, "5"), -}; - -REGISTER_CODECS(Rar) - -} +// RarCodecsRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "Rar1Decoder.h" +#include "Rar2Decoder.h" +#include "Rar3Decoder.h" +#include "Rar5Decoder.h" + +namespace NCompress { + +#define CREATE_CODEC(x) REGISTER_CODEC_CREATE(CreateCodec ## x, NRar ## x::CDecoder()) + +CREATE_CODEC(1) +CREATE_CODEC(2) +CREATE_CODEC(3) +CREATE_CODEC(5) + +#define RAR_CODEC(x, name) { CreateCodec ## x, NULL, 0x40300 + x, "Rar" name, 1, false } + +REGISTER_CODECS_VAR +{ + RAR_CODEC(1, "1"), + RAR_CODEC(2, "2"), + RAR_CODEC(3, "3"), + RAR_CODEC(5, "5"), +}; + +REGISTER_CODECS(Rar) + +} diff --git a/CPP/7zip/Compress/ShrinkDecoder.cpp b/CPP/7zip/Compress/ShrinkDecoder.cpp index 84968b5e9..c8e2083c3 100644 --- a/CPP/7zip/Compress/ShrinkDecoder.cpp +++ b/CPP/7zip/Compress/ShrinkDecoder.cpp @@ -1,244 +1,244 @@ -// ShrinkDecoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/InBuffer.h" -#include "../Common/OutBuffer.h" - -#include "BitlDecoder.h" -#include "ShrinkDecoder.h" - -namespace NCompress { -namespace NShrink { - -static const UInt32 kEmpty = 256; // kNumItems; -static const UInt32 kBufferSize = (1 << 18); -static const unsigned kNumMinBits = 9; - -HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) -{ - NBitl::CBaseDecoder inBuffer; - COutBuffer outBuffer; - - if (!inBuffer.Create(kBufferSize)) - return E_OUTOFMEMORY; - if (!outBuffer.Create(kBufferSize)) - return E_OUTOFMEMORY; - - inBuffer.SetStream(inStream); - inBuffer.Init(); - - outBuffer.SetStream(outStream); - outBuffer.Init(); - - { - for (unsigned i = 0; i < kNumItems; i++) - _parents[i] = kEmpty; - } - - UInt64 outPrev = 0, inPrev = 0; - unsigned numBits = kNumMinBits; - unsigned head = 257; - int lastSym = -1; - Byte lastChar = 0; - bool moreOut = false; - - HRESULT res = S_FALSE; - - for (;;) - { - _inProcessed = inBuffer.GetProcessedSize(); - const UInt64 nowPos = outBuffer.GetProcessedSize(); - - bool eofCheck = false; - - if (outSize && nowPos >= *outSize) - { - if (!_fullStreamMode || moreOut) - { - res = S_OK; - break; - } - eofCheck = true; - // Is specSym(=256) allowed after end of stream ? - // Do we need to read it here ? - } - - if (progress) - { - if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20)) - { - outPrev = nowPos; - inPrev = _inProcessed; - res = progress->SetRatioInfo(&_inProcessed, &nowPos); - if (res != SZ_OK) - { - // break; - return res; - } - } - } - - UInt32 sym = inBuffer.ReadBits(numBits); - - if (inBuffer.ExtraBitsWereRead()) - { - res = S_OK; - break; - } - - if (sym == 256) - { - sym = inBuffer.ReadBits(numBits); - - if (inBuffer.ExtraBitsWereRead()) - break; - - if (sym == 1) - { - if (numBits >= kNumMaxBits) - break; - numBits++; - continue; - } - if (sym != 2) - { - break; - // continue; // info-zip just ignores such code - } - { - /* - ---------- Free leaf nodes ---------- - Note : that code can mark _parents[lastSym] as free, and next - inserted node will be Orphan in that case. - */ - - unsigned i; - for (i = 256; i < kNumItems; i++) - _stack[i] = 0; - for (i = 257; i < kNumItems; i++) - { - unsigned par = _parents[i]; - if (par != kEmpty) - _stack[par] = 1; - } - for (i = 257; i < kNumItems; i++) - if (_stack[i] == 0) - _parents[i] = kEmpty; - head = 257; - continue; - } - } - - if (eofCheck) - { - // It's can be error case. - // That error can be detected later in (*inSize != _inProcessed) check. - res = S_OK; - break; - } - - bool needPrev = false; - if (head < kNumItems && lastSym >= 0) - { - while (head < kNumItems && _parents[head] != kEmpty) - head++; - if (head < kNumItems) - { - /* - if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems: - 1) we must check _stack[i++] overflow in code that walks tree nodes. - 2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items. - */ - needPrev = true; - _parents[head] = (UInt16)lastSym; - _suffixes[head] = (Byte)lastChar; - head++; - } - } - - lastSym = (int)sym; - unsigned cur = sym; - unsigned i = 0; - - while (cur >= 256) - { - _stack[i++] = _suffixes[cur]; - cur = _parents[cur]; - // don't change that code: - // Orphan Check and self-linked Orphan check (_stack overflow check); - if (cur == kEmpty || i >= kNumItems) - break; - } - - if (cur == kEmpty || i >= kNumItems) - break; - - _stack[i++] = (Byte)cur; - lastChar = (Byte)cur; - - if (needPrev) - _suffixes[(size_t)head - 1] = (Byte)cur; - - if (outSize) - { - const UInt64 limit = *outSize - nowPos; - if (i > limit) - { - moreOut = true; - i = (unsigned)limit; - } - } - - do - outBuffer.WriteByte(_stack[--i]); - while (i); - } - - RINOK(outBuffer.Flush()) - - if (res == S_OK) - if (_fullStreamMode) - { - if (moreOut) - res = S_FALSE; - const UInt64 nowPos = outBuffer.GetProcessedSize(); - if (outSize && *outSize != nowPos) - res = S_FALSE; - if (inSize && *inSize != _inProcessed) - res = S_FALSE; - } - - return res; -} - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - // catch(const CInBufferException &e) { return e.ErrorCode; } - // catch(const COutBufferException &e) { return e.ErrorCode; } - catch(const CSystemException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - _fullStreamMode = (finishMode != 0); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inProcessed; - return S_OK; -} - - -}} +// ShrinkDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/InBuffer.h" +#include "../Common/OutBuffer.h" + +#include "BitlDecoder.h" +#include "ShrinkDecoder.h" + +namespace NCompress { +namespace NShrink { + +static const UInt32 kEmpty = 256; // kNumItems; +static const UInt32 kBufferSize = (1 << 18); +static const unsigned kNumMinBits = 9; + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + NBitl::CBaseDecoder inBuffer; + COutBuffer outBuffer; + + if (!inBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + if (!outBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + + inBuffer.SetStream(inStream); + inBuffer.Init(); + + outBuffer.SetStream(outStream); + outBuffer.Init(); + + { + for (unsigned i = 0; i < kNumItems; i++) + _parents[i] = kEmpty; + } + + UInt64 outPrev = 0, inPrev = 0; + unsigned numBits = kNumMinBits; + unsigned head = 257; + int lastSym = -1; + Byte lastChar = 0; + bool moreOut = false; + + HRESULT res = S_FALSE; + + for (;;) + { + _inProcessed = inBuffer.GetProcessedSize(); + const UInt64 nowPos = outBuffer.GetProcessedSize(); + + bool eofCheck = false; + + if (outSize && nowPos >= *outSize) + { + if (!_fullStreamMode || moreOut) + { + res = S_OK; + break; + } + eofCheck = true; + // Is specSym(=256) allowed after end of stream ? + // Do we need to read it here ? + } + + if (progress) + { + if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20)) + { + outPrev = nowPos; + inPrev = _inProcessed; + res = progress->SetRatioInfo(&_inProcessed, &nowPos); + if (res != SZ_OK) + { + // break; + return res; + } + } + } + + UInt32 sym = inBuffer.ReadBits(numBits); + + if (inBuffer.ExtraBitsWereRead()) + { + res = S_OK; + break; + } + + if (sym == 256) + { + sym = inBuffer.ReadBits(numBits); + + if (inBuffer.ExtraBitsWereRead()) + break; + + if (sym == 1) + { + if (numBits >= kNumMaxBits) + break; + numBits++; + continue; + } + if (sym != 2) + { + break; + // continue; // info-zip just ignores such code + } + { + /* + ---------- Free leaf nodes ---------- + Note : that code can mark _parents[lastSym] as free, and next + inserted node will be Orphan in that case. + */ + + unsigned i; + for (i = 256; i < kNumItems; i++) + _stack[i] = 0; + for (i = 257; i < kNumItems; i++) + { + unsigned par = _parents[i]; + if (par != kEmpty) + _stack[par] = 1; + } + for (i = 257; i < kNumItems; i++) + if (_stack[i] == 0) + _parents[i] = kEmpty; + head = 257; + continue; + } + } + + if (eofCheck) + { + // It's can be error case. + // That error can be detected later in (*inSize != _inProcessed) check. + res = S_OK; + break; + } + + bool needPrev = false; + if (head < kNumItems && lastSym >= 0) + { + while (head < kNumItems && _parents[head] != kEmpty) + head++; + if (head < kNumItems) + { + /* + if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems: + 1) we must check _stack[i++] overflow in code that walks tree nodes. + 2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items. + */ + needPrev = true; + _parents[head] = (UInt16)lastSym; + _suffixes[head] = (Byte)lastChar; + head++; + } + } + + lastSym = (int)sym; + unsigned cur = sym; + unsigned i = 0; + + while (cur >= 256) + { + _stack[i++] = _suffixes[cur]; + cur = _parents[cur]; + // don't change that code: + // Orphan Check and self-linked Orphan check (_stack overflow check); + if (cur == kEmpty || i >= kNumItems) + break; + } + + if (cur == kEmpty || i >= kNumItems) + break; + + _stack[i++] = (Byte)cur; + lastChar = (Byte)cur; + + if (needPrev) + _suffixes[(size_t)head - 1] = (Byte)cur; + + if (outSize) + { + const UInt64 limit = *outSize - nowPos; + if (i > limit) + { + moreOut = true; + i = (unsigned)limit; + } + } + + do + outBuffer.WriteByte(_stack[--i]); + while (i); + } + + RINOK(outBuffer.Flush()) + + if (res == S_OK) + if (_fullStreamMode) + { + if (moreOut) + res = S_FALSE; + const UInt64 nowPos = outBuffer.GetProcessedSize(); + if (outSize && *outSize != nowPos) + res = S_FALSE; + if (inSize && *inSize != _inProcessed) + res = S_FALSE; + } + + return res; +} + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + try { return CodeReal(inStream, outStream, inSize, outSize, progress); } + // catch(const CInBufferException &e) { return e.ErrorCode; } + // catch(const COutBufferException &e) { return e.ErrorCode; } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + _fullStreamMode = (finishMode != 0); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inProcessed; + return S_OK; +} + + +}} diff --git a/CPP/7zip/Compress/ShrinkDecoder.h b/CPP/7zip/Compress/ShrinkDecoder.h index 0ff2db44c..5e7f78f3e 100644 --- a/CPP/7zip/Compress/ShrinkDecoder.h +++ b/CPP/7zip/Compress/ShrinkDecoder.h @@ -1,35 +1,35 @@ -// ShrinkDecoder.h - -#ifndef ZIP7_INC_COMPRESS_SHRINK_DECODER_H -#define ZIP7_INC_COMPRESS_SHRINK_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NShrink { - -const unsigned kNumMaxBits = 13; -const unsigned kNumItems = 1 << kNumMaxBits; - -Z7_CLASS_IMP_NOQIB_3( - CDecoder - , ICompressCoder - , ICompressSetFinishMode - , ICompressGetInStreamProcessedSize -) - bool _fullStreamMode; - UInt64 _inProcessed; - - UInt16 _parents[kNumItems]; - Byte _suffixes[kNumItems]; - Byte _stack[kNumItems]; - - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); -}; - -}} - -#endif +// ShrinkDecoder.h + +#ifndef ZIP7_INC_COMPRESS_SHRINK_DECODER_H +#define ZIP7_INC_COMPRESS_SHRINK_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NShrink { + +const unsigned kNumMaxBits = 13; +const unsigned kNumItems = 1 << kNumMaxBits; + +Z7_CLASS_IMP_NOQIB_3( + CDecoder + , ICompressCoder + , ICompressSetFinishMode + , ICompressGetInStreamProcessedSize +) + bool _fullStreamMode; + UInt64 _inProcessed; + + UInt16 _parents[kNumItems]; + Byte _suffixes[kNumItems]; + Byte _stack[kNumItems]; + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/StdAfx.h b/CPP/7zip/Compress/StdAfx.h index aa6fe0328..80866550d 100644 --- a/CPP/7zip/Compress/StdAfx.h +++ b/CPP/7zip/Compress/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Compress/XpressDecoder.cpp b/CPP/7zip/Compress/XpressDecoder.cpp index 0c624442e..47f60613f 100644 --- a/CPP/7zip/Compress/XpressDecoder.cpp +++ b/CPP/7zip/Compress/XpressDecoder.cpp @@ -1,399 +1,399 @@ -// XpressDecoder.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/RotateDefs.h" - -#include "HuffmanDecoder.h" -#include "XpressDecoder.h" - -#ifdef MY_CPU_LE_UNALIGN - #define Z7_XPRESS_DEC_USE_UNALIGNED_COPY -#endif - -#ifdef Z7_XPRESS_DEC_USE_UNALIGNED_COPY - - #define COPY_CHUNK_SIZE 16 - - #define COPY_CHUNK_4_2(dest, src) \ - { \ - ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \ - ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \ - src += 4 * 2; \ - dest += 4 * 2; \ - } - - /* sse2 doesn't help here in GCC and CLANG. - so we disabled sse2 here */ -#if 0 - #if defined(MY_CPU_AMD64) - #define Z7_XPRESS_DEC_USE_SSE2 - #elif defined(MY_CPU_X86) - #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ - || defined(__SSE2__) \ - // || 1 == 1 // for debug only - #define Z7_XPRESS_DEC_USE_SSE2 - #endif - #endif -#endif - - #if defined(MY_CPU_ARM64) - #include - #define COPY_OFFSET_MIN 16 - #define COPY_CHUNK1(dest, src) \ - { \ - vst1q_u8((uint8_t *)(void *)dest, \ - vld1q_u8((const uint8_t *)(const void *)src)); \ - src += 16; \ - dest += 16; \ - } - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK1(dest, src) \ - if (dest >= dest_lim) break; \ - COPY_CHUNK1(dest, src) \ - } - - #elif defined(Z7_XPRESS_DEC_USE_SSE2) - #include // sse2 - #define COPY_OFFSET_MIN 16 - - #define COPY_CHUNK1(dest, src) \ - { \ - _mm_storeu_si128((__m128i *)(void *)dest, \ - _mm_loadu_si128((const __m128i *)(const void *)src)); \ - src += 16; \ - dest += 16; \ - } - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK1(dest, src) \ - if (dest >= dest_lim) break; \ - COPY_CHUNK1(dest, src) \ - } - - #elif defined(MY_CPU_64BIT) - #define COPY_OFFSET_MIN 8 - - #define COPY_CHUNK(dest, src) \ - { \ - ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ - ((UInt64 *)(void *)dest)[1] = ((const UInt64 *)(const void *)src)[1]; \ - src += 8 * 2; \ - dest += 8 * 2; \ - } - - #else - #define COPY_OFFSET_MIN 4 - - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK_4_2(dest, src); \ - COPY_CHUNK_4_2(dest, src); \ - } - - #endif -#endif - - -#ifndef COPY_CHUNK_SIZE - #define COPY_OFFSET_MIN 4 - #define COPY_CHUNK_SIZE 8 - #define COPY_CHUNK_2(dest, src) \ - { \ - const Byte a0 = src[0]; \ - const Byte a1 = src[1]; \ - dest[0] = a0; \ - dest[1] = a1; \ - src += 2; \ - dest += 2; \ - } - #define COPY_CHUNK(dest, src) \ - { \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - COPY_CHUNK_2(dest, src) \ - } -#endif - - -#define COPY_CHUNKS \ -{ \ - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ - do { COPY_CHUNK(dest, src) } \ - while (dest < dest_lim); \ -} - - -static -Z7_FORCE_INLINE -// Z7_ATTRIB_NO_VECTOR -void CopyMatch_1(Byte *dest, const Byte *dest_lim) -{ - const unsigned b0 = dest[-1]; - { -#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16) - #if defined(MY_CPU_64BIT) - { - const UInt64 v64 = (UInt64)b0 * 0x0101010101010101; - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - ((UInt64 *)(void *)dest)[0] = v64; - ((UInt64 *)(void *)dest)[1] = v64; - dest += 16; - } - while (dest < dest_lim); - } - #else - { - UInt32 v = b0; - v |= v << 8; - v |= v << 16; - do - { - ((UInt32 *)(void *)dest)[0] = v; - ((UInt32 *)(void *)dest)[1] = v; - dest += 8; - ((UInt32 *)(void *)dest)[0] = v; - ((UInt32 *)(void *)dest)[1] = v; - dest += 8; - } - while (dest < dest_lim); - } - #endif -#else - do - { - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += 2; - dest[0] = (Byte)b0; - dest[1] = (Byte)b0; - dest += 2; - } - while (dest < dest_lim); -#endif - } -} - - -// (offset != 1) -static -Z7_FORCE_INLINE -// Z7_ATTRIB_NO_VECTOR -void CopyMatch_Non1(Byte *dest, size_t offset, const Byte *dest_lim) -{ - const Byte *src = dest - offset; - { - // (COPY_OFFSET_MIN >= 4) - if (offset >= COPY_OFFSET_MIN) - { - COPY_CHUNKS - // return; - } - else -#if (COPY_OFFSET_MIN > 4) - #if COPY_CHUNK_SIZE < 8 - #error Stop_Compiling_Bad_COPY_CHUNK_SIZE - #endif - if (offset >= 4) - { - Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE - do - { - COPY_CHUNK_4_2(dest, src) - #if COPY_CHUNK_SIZE != 16 - if (dest >= dest_lim) break; - #endif - COPY_CHUNK_4_2(dest, src) - } - while (dest < dest_lim); - // return; - } - else -#endif - { - // (offset < 4) - if (offset == 2) - { -#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) - UInt32 w0 = GetUi16(src); - w0 += w0 << 16; - do - { - SetUi32(dest, w0) - dest += 4; - } - while (dest < dest_lim); -#else - const unsigned b0 = src[0]; - const Byte b1 = src[1]; - do - { - dest[0] = (Byte)b0; - dest[1] = b1; - dest += 2; - } - while (dest < dest_lim); -#endif - } - else // (offset == 3) - { - const unsigned b0 = src[0]; -#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) - const unsigned w1 = GetUi16(src + 1); - do - { - dest[0] = (Byte)b0; - SetUi16(dest + 1, (UInt16)w1) - dest += 3; - } - while (dest < dest_lim); -#else - const Byte b1 = src[1]; - const Byte b2 = src[2]; - do - { - dest[0] = (Byte)b0; - dest[1] = b1; - dest[2] = b2; - dest += 3; - } - while (dest < dest_lim); -#endif - } - } - } -} - - -namespace NCompress { -namespace NXpress { - -#define BIT_STREAM_NORMALIZE \ - if (BitPos > 16) { \ - if (in >= lim) return S_FALSE; \ - BitPos -= 16; \ - Value |= (UInt32)GetUi16(in) << BitPos; \ - in += 2; } - -#define MOVE_POS(bs, numBits) \ - BitPos += (unsigned)numBits; \ - Value <<= numBits; \ - - -static const unsigned kNumHuffBits = 15; -static const unsigned kNumTableBits = 10; -static const unsigned kNumLenBits = 4; -static const unsigned kLenMask = (1 << kNumLenBits) - 1; -static const unsigned kNumPosSlots = 16; -static const unsigned kNumSyms = 256 + (kNumPosSlots << kNumLenBits); - -HRESULT Decode_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize) -{ - NCompress::NHuffman::CDecoder huff; - - if (inSize < kNumSyms / 2 + 4) - return S_FALSE; - { - Byte levels[kNumSyms]; - for (unsigned i = 0; i < kNumSyms / 2; i++) - { - const unsigned b = in[i]; - levels[(size_t)i * 2 ] = (Byte)(b & 0xf); - levels[(size_t)i * 2 + 1] = (Byte)(b >> 4); - } - if (!huff.Build(levels, NHuffman::k_BuildMode_Full)) - return S_FALSE; - } - - UInt32 Value; - unsigned BitPos; // how many bits in (Value) were processed - - const Byte *lim = in + inSize - 1; // points to last byte - in += kNumSyms / 2; -#ifdef MY_CPU_LE_UNALIGN - Value = GetUi32(in); - Value = rotlFixed(Value, 16); -#else - Value = ((UInt32)GetUi16(in) << 16) | GetUi16(in + 2); -#endif - - in += 4; - BitPos = 0; - Byte *dest = out; - const Byte *outLim = out + outSize; - - for (;;) - { - unsigned sym; - Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, &huff, kNumHuffBits, kNumTableBits, - Value, Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}, MOVE_POS, {}, bs) - // 0 < BitPos <= 31 - BIT_STREAM_NORMALIZE - // 0 < BitPos <= 16 - - if (dest >= outLim) - return (sym == 256 && Value == 0 && in == lim + 1) ? S_OK : S_FALSE; - - if (sym < 256) - *dest++ = (Byte)sym; - else - { - const unsigned distBits = (unsigned)(Byte)sym >> kNumLenBits; // (sym - 256) >> kNumLenBits; - UInt32 len = (UInt32)(sym & kLenMask); - - if (len == kLenMask) - { - if (in > lim) - return S_FALSE; - // here we read input bytes in out-of-order related to main input stream (bits in Value): - len = *in++; - if (len == 0xff) - { - if (in >= lim) - return S_FALSE; - len = GetUi16(in); - in += 2; - } - else - len += kLenMask; - } - - len += 3; - if (len > (size_t)(outLim - dest)) - return S_FALSE; - - if (distBits == 0) - { - // d == 1 - if (dest == out) - return S_FALSE; - Byte *destTemp = dest; - dest += len; - CopyMatch_1(destTemp, dest); - } - else - { - unsigned d = (unsigned)(Value >> (32 - distBits)); - MOVE_POS(bs, distBits) - d += 1u << distBits; - // 0 < BitPos <= 31 - BIT_STREAM_NORMALIZE - // 0 < BitPos <= 16 - if (d > (size_t)(dest - out)) - return S_FALSE; - Byte *destTemp = dest; - dest += len; - CopyMatch_Non1(destTemp, d, dest); - } - } - } -} - -}} +// XpressDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/RotateDefs.h" + +#include "HuffmanDecoder.h" +#include "XpressDecoder.h" + +#ifdef MY_CPU_LE_UNALIGN + #define Z7_XPRESS_DEC_USE_UNALIGNED_COPY +#endif + +#ifdef Z7_XPRESS_DEC_USE_UNALIGNED_COPY + + #define COPY_CHUNK_SIZE 16 + + #define COPY_CHUNK_4_2(dest, src) \ + { \ + ((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \ + ((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \ + src += 4 * 2; \ + dest += 4 * 2; \ + } + + /* sse2 doesn't help here in GCC and CLANG. + so we disabled sse2 here */ +#if 0 + #if defined(MY_CPU_AMD64) + #define Z7_XPRESS_DEC_USE_SSE2 + #elif defined(MY_CPU_X86) + #if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \ + || defined(__SSE2__) \ + // || 1 == 1 // for debug only + #define Z7_XPRESS_DEC_USE_SSE2 + #endif + #endif +#endif + + #if defined(MY_CPU_ARM64) + #include + #define COPY_OFFSET_MIN 16 + #define COPY_CHUNK1(dest, src) \ + { \ + vst1q_u8((uint8_t *)(void *)dest, \ + vld1q_u8((const uint8_t *)(const void *)src)); \ + src += 16; \ + dest += 16; \ + } + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK1(dest, src) \ + if (dest >= dest_lim) break; \ + COPY_CHUNK1(dest, src) \ + } + + #elif defined(Z7_XPRESS_DEC_USE_SSE2) + #include // sse2 + #define COPY_OFFSET_MIN 16 + + #define COPY_CHUNK1(dest, src) \ + { \ + _mm_storeu_si128((__m128i *)(void *)dest, \ + _mm_loadu_si128((const __m128i *)(const void *)src)); \ + src += 16; \ + dest += 16; \ + } + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK1(dest, src) \ + if (dest >= dest_lim) break; \ + COPY_CHUNK1(dest, src) \ + } + + #elif defined(MY_CPU_64BIT) + #define COPY_OFFSET_MIN 8 + + #define COPY_CHUNK(dest, src) \ + { \ + ((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \ + ((UInt64 *)(void *)dest)[1] = ((const UInt64 *)(const void *)src)[1]; \ + src += 8 * 2; \ + dest += 8 * 2; \ + } + + #else + #define COPY_OFFSET_MIN 4 + + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK_4_2(dest, src); \ + COPY_CHUNK_4_2(dest, src); \ + } + + #endif +#endif + + +#ifndef COPY_CHUNK_SIZE + #define COPY_OFFSET_MIN 4 + #define COPY_CHUNK_SIZE 8 + #define COPY_CHUNK_2(dest, src) \ + { \ + const Byte a0 = src[0]; \ + const Byte a1 = src[1]; \ + dest[0] = a0; \ + dest[1] = a1; \ + src += 2; \ + dest += 2; \ + } + #define COPY_CHUNK(dest, src) \ + { \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + COPY_CHUNK_2(dest, src) \ + } +#endif + + +#define COPY_CHUNKS \ +{ \ + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + do { COPY_CHUNK(dest, src) } \ + while (dest < dest_lim); \ +} + + +static +Z7_FORCE_INLINE +// Z7_ATTRIB_NO_VECTOR +void CopyMatch_1(Byte *dest, const Byte *dest_lim) +{ + const unsigned b0 = dest[-1]; + { +#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16) + #if defined(MY_CPU_64BIT) + { + const UInt64 v64 = (UInt64)b0 * 0x0101010101010101; + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + ((UInt64 *)(void *)dest)[0] = v64; + ((UInt64 *)(void *)dest)[1] = v64; + dest += 16; + } + while (dest < dest_lim); + } + #else + { + UInt32 v = b0; + v |= v << 8; + v |= v << 16; + do + { + ((UInt32 *)(void *)dest)[0] = v; + ((UInt32 *)(void *)dest)[1] = v; + dest += 8; + ((UInt32 *)(void *)dest)[0] = v; + ((UInt32 *)(void *)dest)[1] = v; + dest += 8; + } + while (dest < dest_lim); + } + #endif +#else + do + { + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += 2; + dest[0] = (Byte)b0; + dest[1] = (Byte)b0; + dest += 2; + } + while (dest < dest_lim); +#endif + } +} + + +// (offset != 1) +static +Z7_FORCE_INLINE +// Z7_ATTRIB_NO_VECTOR +void CopyMatch_Non1(Byte *dest, size_t offset, const Byte *dest_lim) +{ + const Byte *src = dest - offset; + { + // (COPY_OFFSET_MIN >= 4) + if (offset >= COPY_OFFSET_MIN) + { + COPY_CHUNKS + // return; + } + else +#if (COPY_OFFSET_MIN > 4) + #if COPY_CHUNK_SIZE < 8 + #error Stop_Compiling_Bad_COPY_CHUNK_SIZE + #endif + if (offset >= 4) + { + Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + do + { + COPY_CHUNK_4_2(dest, src) + #if COPY_CHUNK_SIZE != 16 + if (dest >= dest_lim) break; + #endif + COPY_CHUNK_4_2(dest, src) + } + while (dest < dest_lim); + // return; + } + else +#endif + { + // (offset < 4) + if (offset == 2) + { +#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) + UInt32 w0 = GetUi16(src); + w0 += w0 << 16; + do + { + SetUi32(dest, w0) + dest += 4; + } + while (dest < dest_lim); +#else + const unsigned b0 = src[0]; + const Byte b1 = src[1]; + do + { + dest[0] = (Byte)b0; + dest[1] = b1; + dest += 2; + } + while (dest < dest_lim); +#endif + } + else // (offset == 3) + { + const unsigned b0 = src[0]; +#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) + const unsigned w1 = GetUi16(src + 1); + do + { + dest[0] = (Byte)b0; + SetUi16(dest + 1, (UInt16)w1) + dest += 3; + } + while (dest < dest_lim); +#else + const Byte b1 = src[1]; + const Byte b2 = src[2]; + do + { + dest[0] = (Byte)b0; + dest[1] = b1; + dest[2] = b2; + dest += 3; + } + while (dest < dest_lim); +#endif + } + } + } +} + + +namespace NCompress { +namespace NXpress { + +#define BIT_STREAM_NORMALIZE \ + if (BitPos > 16) { \ + if (in >= lim) return S_FALSE; \ + BitPos -= 16; \ + Value |= (UInt32)GetUi16(in) << BitPos; \ + in += 2; } + +#define MOVE_POS(bs, numBits) \ + BitPos += (unsigned)numBits; \ + Value <<= numBits; \ + + +static const unsigned kNumHuffBits = 15; +static const unsigned kNumTableBits = 10; +static const unsigned kNumLenBits = 4; +static const unsigned kLenMask = (1 << kNumLenBits) - 1; +static const unsigned kNumPosSlots = 16; +static const unsigned kNumSyms = 256 + (kNumPosSlots << kNumLenBits); + +HRESULT Decode_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize) +{ + NCompress::NHuffman::CDecoder huff; + + if (inSize < kNumSyms / 2 + 4) + return S_FALSE; + { + Byte levels[kNumSyms]; + for (unsigned i = 0; i < kNumSyms / 2; i++) + { + const unsigned b = in[i]; + levels[(size_t)i * 2 ] = (Byte)(b & 0xf); + levels[(size_t)i * 2 + 1] = (Byte)(b >> 4); + } + if (!huff.Build(levels, NHuffman::k_BuildMode_Full)) + return S_FALSE; + } + + UInt32 Value; + unsigned BitPos; // how many bits in (Value) were processed + + const Byte *lim = in + inSize - 1; // points to last byte + in += kNumSyms / 2; +#ifdef MY_CPU_LE_UNALIGN + Value = GetUi32(in); + Value = rotlFixed(Value, 16); +#else + Value = ((UInt32)GetUi16(in) << 16) | GetUi16(in + 2); +#endif + + in += 4; + BitPos = 0; + Byte *dest = out; + const Byte *outLim = out + outSize; + + for (;;) + { + unsigned sym; + Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, &huff, kNumHuffBits, kNumTableBits, + Value, Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}, MOVE_POS, {}, bs) + // 0 < BitPos <= 31 + BIT_STREAM_NORMALIZE + // 0 < BitPos <= 16 + + if (dest >= outLim) + return (sym == 256 && Value == 0 && in == lim + 1) ? S_OK : S_FALSE; + + if (sym < 256) + *dest++ = (Byte)sym; + else + { + const unsigned distBits = (unsigned)(Byte)sym >> kNumLenBits; // (sym - 256) >> kNumLenBits; + UInt32 len = (UInt32)(sym & kLenMask); + + if (len == kLenMask) + { + if (in > lim) + return S_FALSE; + // here we read input bytes in out-of-order related to main input stream (bits in Value): + len = *in++; + if (len == 0xff) + { + if (in >= lim) + return S_FALSE; + len = GetUi16(in); + in += 2; + } + else + len += kLenMask; + } + + len += 3; + if (len > (size_t)(outLim - dest)) + return S_FALSE; + + if (distBits == 0) + { + // d == 1 + if (dest == out) + return S_FALSE; + Byte *destTemp = dest; + dest += len; + CopyMatch_1(destTemp, dest); + } + else + { + unsigned d = (unsigned)(Value >> (32 - distBits)); + MOVE_POS(bs, distBits) + d += 1u << distBits; + // 0 < BitPos <= 31 + BIT_STREAM_NORMALIZE + // 0 < BitPos <= 16 + if (d > (size_t)(dest - out)) + return S_FALSE; + Byte *destTemp = dest; + dest += len; + CopyMatch_Non1(destTemp, d, dest); + } + } + } +} + +}} diff --git a/CPP/7zip/Compress/XpressDecoder.h b/CPP/7zip/Compress/XpressDecoder.h index c842e9e19..7d176029b 100644 --- a/CPP/7zip/Compress/XpressDecoder.h +++ b/CPP/7zip/Compress/XpressDecoder.h @@ -1,18 +1,18 @@ -// XpressDecoder.h - -#ifndef ZIP7_INC_XPRESS_DECODER_H -#define ZIP7_INC_XPRESS_DECODER_H - -#include "../../Common/MyTypes.h" - -namespace NCompress { -namespace NXpress { - -// (out) buffer size must be larger than (outSize) for the following value: -const unsigned kAdditionalOutputBufSize = 32; - -HRESULT Decode_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize); - -}} - -#endif +// XpressDecoder.h + +#ifndef ZIP7_INC_XPRESS_DECODER_H +#define ZIP7_INC_XPRESS_DECODER_H + +#include "../../Common/MyTypes.h" + +namespace NCompress { +namespace NXpress { + +// (out) buffer size must be larger than (outSize) for the following value: +const unsigned kAdditionalOutputBufSize = 32; + +HRESULT Decode_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize); + +}} + +#endif diff --git a/CPP/7zip/Compress/XzDecoder.cpp b/CPP/7zip/Compress/XzDecoder.cpp index 73715f8f0..62a78bfe1 100644 --- a/CPP/7zip/Compress/XzDecoder.cpp +++ b/CPP/7zip/Compress/XzDecoder.cpp @@ -1,151 +1,151 @@ -// XzDecoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../Common/CWrappers.h" - -#include "XzDecoder.h" - -namespace NCompress { -namespace NXz { - -#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes; - -#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; - -static HRESULT SResToHRESULT_Code(SRes res) throw() -{ - if (res < 0) - return res; - switch (res) - { - case SZ_OK: return S_OK; - case SZ_ERROR_MEM: return E_OUTOFMEMORY; - case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; - default: break; - } - return S_FALSE; -} - - -HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, - const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress) -{ - MainDecodeSRes = SZ_OK; - MainDecodeSRes_wasUsed = false; - XzStatInfo_Clear(&Stat); - - if (!xz) - { - xz = XzDecMt_Create(&g_Alloc, &g_MidAlloc); - if (!xz) - return E_OUTOFMEMORY; - } - - CXzDecMtProps props; - XzDecMtProps_Init(&props); - - int isMT = False; - - #ifndef Z7_ST - { - props.numThreads = 1; - const UInt32 numThreads = _numThreads; - - if (_tryMt && numThreads > 1) - { - size_t memUsage = (size_t)_memUsage; - if (memUsage != _memUsage) - memUsage = (size_t)0 - 1; - props.memUseMax = memUsage; - isMT = (numThreads > 1); - } - - props.numThreads = numThreads; - } - #endif - - CSeqInStreamWrap inWrap; - CSeqOutStreamWrap outWrap; - CCompressProgressWrap progressWrap; - - inWrap.Init(seqInStream); - outWrap.Init(outStream); - progressWrap.Init(progress); - - SRes res = XzDecMt_Decode(xz, - &props, - outSizeLimit, finishStream, - &outWrap.vt, - &inWrap.vt, - &Stat, - &isMT, - progress ? &progressWrap.vt : NULL); - - MainDecodeSRes = res; - - #ifndef Z7_ST - // _tryMt = isMT; - #endif - - RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) - RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) - RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ) - - // return E_OUTOFMEMORY; // for debug check - - MainDecodeSRes_wasUsed = true; - - if (res == SZ_OK && finishStream) - { - /* - if (inSize && *inSize != Stat.PhySize) - res = SZ_ERROR_DATA; - */ - if (outSizeLimit && *outSizeLimit != outWrap.Processed) - res = SZ_ERROR_DATA; - } - - return SResToHRESULT_Code(res); -} - - -Z7_COM7F_IMF(CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - return Decode(inStream, outStream, outSize, _finishStream, progress); -} - -Z7_COM7F_IMF(CComDecoder::SetFinishMode(UInt32 finishMode)) -{ - _finishStream = (finishMode != 0); - return S_OK; -} - -Z7_COM7F_IMF(CComDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = Stat.InSize; - return S_OK; -} - -#ifndef Z7_ST - -Z7_COM7F_IMF(CComDecoder::SetNumberOfThreads(UInt32 numThreads)) -{ - _numThreads = numThreads; - return S_OK; -} - -Z7_COM7F_IMF(CComDecoder::SetMemLimit(UInt64 memUsage)) -{ - _memUsage = memUsage; - return S_OK; -} - -#endif - -}} +// XzDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/CWrappers.h" + +#include "XzDecoder.h" + +namespace NCompress { +namespace NXz { + +#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes; + +#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; + +static HRESULT SResToHRESULT_Code(SRes res) throw() +{ + if (res < 0) + return res; + switch (res) + { + case SZ_OK: return S_OK; + case SZ_ERROR_MEM: return E_OUTOFMEMORY; + case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; + default: break; + } + return S_FALSE; +} + + +HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, + const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress) +{ + MainDecodeSRes = SZ_OK; + MainDecodeSRes_wasUsed = false; + XzStatInfo_Clear(&Stat); + + if (!xz) + { + xz = XzDecMt_Create(&g_Alloc, &g_MidAlloc); + if (!xz) + return E_OUTOFMEMORY; + } + + CXzDecMtProps props; + XzDecMtProps_Init(&props); + + int isMT = False; + + #ifndef Z7_ST + { + props.numThreads = 1; + const UInt32 numThreads = _numThreads; + + if (_tryMt && numThreads > 1) + { + size_t memUsage = (size_t)_memUsage; + if (memUsage != _memUsage) + memUsage = (size_t)0 - 1; + props.memUseMax = memUsage; + isMT = (numThreads > 1); + } + + props.numThreads = numThreads; + } + #endif + + CSeqInStreamWrap inWrap; + CSeqOutStreamWrap outWrap; + CCompressProgressWrap progressWrap; + + inWrap.Init(seqInStream); + outWrap.Init(outStream); + progressWrap.Init(progress); + + SRes res = XzDecMt_Decode(xz, + &props, + outSizeLimit, finishStream, + &outWrap.vt, + &inWrap.vt, + &Stat, + &isMT, + progress ? &progressWrap.vt : NULL); + + MainDecodeSRes = res; + + #ifndef Z7_ST + // _tryMt = isMT; + #endif + + RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) + RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) + RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ) + + // return E_OUTOFMEMORY; // for debug check + + MainDecodeSRes_wasUsed = true; + + if (res == SZ_OK && finishStream) + { + /* + if (inSize && *inSize != Stat.PhySize) + res = SZ_ERROR_DATA; + */ + if (outSizeLimit && *outSizeLimit != outWrap.Processed) + res = SZ_ERROR_DATA; + } + + return SResToHRESULT_Code(res); +} + + +Z7_COM7F_IMF(CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + return Decode(inStream, outStream, outSize, _finishStream, progress); +} + +Z7_COM7F_IMF(CComDecoder::SetFinishMode(UInt32 finishMode)) +{ + _finishStream = (finishMode != 0); + return S_OK; +} + +Z7_COM7F_IMF(CComDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = Stat.InSize; + return S_OK; +} + +#ifndef Z7_ST + +Z7_COM7F_IMF(CComDecoder::SetNumberOfThreads(UInt32 numThreads)) +{ + _numThreads = numThreads; + return S_OK; +} + +Z7_COM7F_IMF(CComDecoder::SetMemLimit(UInt64 memUsage)) +{ + _memUsage = memUsage; + return S_OK; +} + +#endif + +}} diff --git a/CPP/7zip/Compress/XzDecoder.h b/CPP/7zip/Compress/XzDecoder.h index 515bbf77d..40ed4f5c5 100644 --- a/CPP/7zip/Compress/XzDecoder.h +++ b/CPP/7zip/Compress/XzDecoder.h @@ -1,86 +1,86 @@ -// XzDecoder.h - -#ifndef ZIP7_INC_XZ_DECODER_H -#define ZIP7_INC_XZ_DECODER_H - -#include "../../../C/Xz.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NXz { - -struct CDecoder -{ - CXzDecMtHandle xz; - int _tryMt; - UInt32 _numThreads; - UInt64 _memUsage; - - SRes MainDecodeSRes; // it's not HRESULT - bool MainDecodeSRes_wasUsed; - CXzStatInfo Stat; - - CDecoder(): - xz(NULL), - _tryMt(True), - _numThreads(1), - _memUsage((UInt64)(sizeof(size_t)) << 28), - MainDecodeSRes(SZ_OK), - MainDecodeSRes_wasUsed(false) - {} - - ~CDecoder() - { - if (xz) - XzDecMt_Destroy(xz); - } - - /* Decode() can return S_OK, if there is data after good xz streams, and that data is not new xz stream. - check also (Stat.DataAfterEnd) flag */ - - HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, - const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress); -}; - - -class CComDecoder Z7_final: - public ICompressCoder, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - #ifndef Z7_ST - public ICompressSetCoderMt, - public ICompressSetMemLimit, - #endif - public CMyUnknownImp, - public CDecoder -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - #ifndef Z7_ST - Z7_COM_QI_ENTRY(ICompressSetCoderMt) - Z7_COM_QI_ENTRY(ICompressSetMemLimit) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) - #ifndef Z7_ST - Z7_IFACE_COM7_IMP(ICompressSetCoderMt) - Z7_IFACE_COM7_IMP(ICompressSetMemLimit) - #endif - - bool _finishStream; - -public: - CComDecoder(): _finishStream(false) {} -}; - -}} - -#endif +// XzDecoder.h + +#ifndef ZIP7_INC_XZ_DECODER_H +#define ZIP7_INC_XZ_DECODER_H + +#include "../../../C/Xz.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NXz { + +struct CDecoder +{ + CXzDecMtHandle xz; + int _tryMt; + UInt32 _numThreads; + UInt64 _memUsage; + + SRes MainDecodeSRes; // it's not HRESULT + bool MainDecodeSRes_wasUsed; + CXzStatInfo Stat; + + CDecoder(): + xz(NULL), + _tryMt(True), + _numThreads(1), + _memUsage((UInt64)(sizeof(size_t)) << 28), + MainDecodeSRes(SZ_OK), + MainDecodeSRes_wasUsed(false) + {} + + ~CDecoder() + { + if (xz) + XzDecMt_Destroy(xz); + } + + /* Decode() can return S_OK, if there is data after good xz streams, and that data is not new xz stream. + check also (Stat.DataAfterEnd) flag */ + + HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream, + const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress); +}; + + +class CComDecoder Z7_final: + public ICompressCoder, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + #ifndef Z7_ST + public ICompressSetCoderMt, + public ICompressSetMemLimit, + #endif + public CMyUnknownImp, + public CDecoder +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + #ifndef Z7_ST + Z7_COM_QI_ENTRY(ICompressSetCoderMt) + Z7_COM_QI_ENTRY(ICompressSetMemLimit) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) + #ifndef Z7_ST + Z7_IFACE_COM7_IMP(ICompressSetCoderMt) + Z7_IFACE_COM7_IMP(ICompressSetMemLimit) + #endif + + bool _finishStream; + +public: + CComDecoder(): _finishStream(false) {} +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/XzEncoder.cpp b/CPP/7zip/Compress/XzEncoder.cpp index 0b65767d1..1bca32288 100644 --- a/CPP/7zip/Compress/XzEncoder.cpp +++ b/CPP/7zip/Compress/XzEncoder.cpp @@ -1,243 +1,243 @@ -// XzEncoder.cpp - -#include "StdAfx.h" - -#include "../../../C/Alloc.h" - -#include "../../Common/MyString.h" -#include "../../Common/StringToInt.h" - -#include "../Common/CWrappers.h" -#include "../Common/StreamUtils.h" - -#include "XzEncoder.h" - -namespace NCompress { - -namespace NLzma2 { -HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); -} - -namespace NXz { - -void CEncoder::InitCoderProps() -{ - XzProps_Init(&xzProps); -} - -CEncoder::CEncoder() -{ - XzProps_Init(&xzProps); - _encoder = NULL; - _encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc); - if (!_encoder) - throw 1; -} - -CEncoder::~CEncoder() -{ - if (_encoder) - XzEnc_Destroy(_encoder); -} - - -struct CMethodNamePair -{ - UInt32 Id; - const char *Name; -}; - -static const CMethodNamePair g_NamePairs[] = -{ - { XZ_ID_Delta, "Delta" }, - { XZ_ID_X86, "BCJ" }, - { XZ_ID_PPC, "PPC" }, - { XZ_ID_IA64, "IA64" }, - { XZ_ID_ARM, "ARM" }, - { XZ_ID_ARMT, "ARMT" }, - { XZ_ID_SPARC, "SPARC" } - // { XZ_ID_LZMA2, "LZMA2" } -}; - -static int FilterIdFromName(const wchar_t *name) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++) - { - const CMethodNamePair &pair = g_NamePairs[i]; - if (StringsAreEqualNoCase_Ascii(name, pair.Name)) - return (int)pair.Id; - } - return -1; -} - - -HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes) -{ - unsigned id; - switch (checkSizeInBytes) - { - case 0: id = XZ_CHECK_NO; break; - case 4: id = XZ_CHECK_CRC32; break; - case 8: id = XZ_CHECK_CRC64; break; - case 32: id = XZ_CHECK_SHA256; break; - default: return E_INVALIDARG; - } - xzProps.checkId = id; - return S_OK; -} - - -HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop) -{ - if (propID == NCoderPropID::kNumThreads) - { - if (prop.vt != VT_UI4) - return E_INVALIDARG; - xzProps.numTotalThreads = (int)(prop.ulVal); - return S_OK; - } - - if (propID == NCoderPropID::kCheckSize) - { - if (prop.vt != VT_UI4) - return E_INVALIDARG; - return SetCheckSize(prop.ulVal); - } - - if (propID == NCoderPropID::kBlockSize2) - { - if (prop.vt == VT_UI4) - xzProps.blockSize = prop.ulVal; - else if (prop.vt == VT_UI8) - xzProps.blockSize = prop.uhVal.QuadPart; - else - return E_INVALIDARG; - return S_OK; - } - - if (propID == NCoderPropID::kReduceSize) - { - if (prop.vt == VT_UI8) - xzProps.reduceSize = prop.uhVal.QuadPart; - else - return E_INVALIDARG; - return S_OK; - } - - if (propID == NCoderPropID::kFilter) - { - if (prop.vt == VT_UI4) - { - const UInt32 id32 = prop.ulVal; - if (id32 == XZ_ID_Delta) - return E_INVALIDARG; - xzProps.filterProps.id = prop.ulVal; - } - else - { - if (prop.vt != VT_BSTR) - return E_INVALIDARG; - - const wchar_t *name = prop.bstrVal; - const wchar_t *end; - - UInt32 id32 = ConvertStringToUInt32(name, &end); - - if (end != name) - name = end; - else - { - if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta")) - { - name += 5; // strlen("Delta"); - id32 = XZ_ID_Delta; - } - else - { - const int filterId = FilterIdFromName(prop.bstrVal); - if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */) - return E_INVALIDARG; - id32 = (UInt32)(unsigned)filterId; - } - } - - if (id32 == XZ_ID_Delta) - { - const wchar_t c = *name; - if (c != '-' && c != ':') - return E_INVALIDARG; - name++; - const UInt32 delta = ConvertStringToUInt32(name, &end); - if (end == name || *end != 0 || delta == 0 || delta > 256) - return E_INVALIDARG; - xzProps.filterProps.delta = delta; - } - - xzProps.filterProps.id = id32; - } - - return S_OK; - } - - return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props); -} - - -Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps)) -{ - XzProps_Init(&xzProps); - - for (UInt32 i = 0; i < numProps; i++) - { - RINOK(SetCoderProp(propIDs[i], coderProps[i])) - } - - return S_OK; - // return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps)); -} - - -Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, - const PROPVARIANT *coderProps, UInt32 numProps)) -{ - for (UInt32 i = 0; i < numProps; i++) - { - const PROPVARIANT &prop = coderProps[i]; - const PROPID propID = propIDs[i]; - if (propID == NCoderPropID::kExpectedDataSize) - if (prop.vt == VT_UI8) - XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart); - } - return S_OK; -} - - -#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ - if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) -{ - CSeqInStreamWrap inWrap; - CSeqOutStreamWrap outWrap; - CCompressProgressWrap progressWrap; - - inWrap.Init(inStream); - outWrap.Init(outStream); - progressWrap.Init(progress); - - SRes res = XzEnc_SetProps(_encoder, &xzProps); - if (res == SZ_OK) - res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL); - - // SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL); - - RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) - RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) - RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) - - return SResToHRESULT(res); -} - -}} +// XzEncoder.cpp + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../../Common/MyString.h" +#include "../../Common/StringToInt.h" + +#include "../Common/CWrappers.h" +#include "../Common/StreamUtils.h" + +#include "XzEncoder.h" + +namespace NCompress { + +namespace NLzma2 { +HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props); +} + +namespace NXz { + +void CEncoder::InitCoderProps() +{ + XzProps_Init(&xzProps); +} + +CEncoder::CEncoder() +{ + XzProps_Init(&xzProps); + _encoder = NULL; + _encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc); + if (!_encoder) + throw 1; +} + +CEncoder::~CEncoder() +{ + if (_encoder) + XzEnc_Destroy(_encoder); +} + + +struct CMethodNamePair +{ + UInt32 Id; + const char *Name; +}; + +static const CMethodNamePair g_NamePairs[] = +{ + { XZ_ID_Delta, "Delta" }, + { XZ_ID_X86, "BCJ" }, + { XZ_ID_PPC, "PPC" }, + { XZ_ID_IA64, "IA64" }, + { XZ_ID_ARM, "ARM" }, + { XZ_ID_ARMT, "ARMT" }, + { XZ_ID_SPARC, "SPARC" } + // { XZ_ID_LZMA2, "LZMA2" } +}; + +static int FilterIdFromName(const wchar_t *name) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++) + { + const CMethodNamePair &pair = g_NamePairs[i]; + if (StringsAreEqualNoCase_Ascii(name, pair.Name)) + return (int)pair.Id; + } + return -1; +} + + +HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes) +{ + unsigned id; + switch (checkSizeInBytes) + { + case 0: id = XZ_CHECK_NO; break; + case 4: id = XZ_CHECK_CRC32; break; + case 8: id = XZ_CHECK_CRC64; break; + case 32: id = XZ_CHECK_SHA256; break; + default: return E_INVALIDARG; + } + xzProps.checkId = id; + return S_OK; +} + + +HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop) +{ + if (propID == NCoderPropID::kNumThreads) + { + if (prop.vt != VT_UI4) + return E_INVALIDARG; + xzProps.numTotalThreads = (int)(prop.ulVal); + return S_OK; + } + + if (propID == NCoderPropID::kCheckSize) + { + if (prop.vt != VT_UI4) + return E_INVALIDARG; + return SetCheckSize(prop.ulVal); + } + + if (propID == NCoderPropID::kBlockSize2) + { + if (prop.vt == VT_UI4) + xzProps.blockSize = prop.ulVal; + else if (prop.vt == VT_UI8) + xzProps.blockSize = prop.uhVal.QuadPart; + else + return E_INVALIDARG; + return S_OK; + } + + if (propID == NCoderPropID::kReduceSize) + { + if (prop.vt == VT_UI8) + xzProps.reduceSize = prop.uhVal.QuadPart; + else + return E_INVALIDARG; + return S_OK; + } + + if (propID == NCoderPropID::kFilter) + { + if (prop.vt == VT_UI4) + { + const UInt32 id32 = prop.ulVal; + if (id32 == XZ_ID_Delta) + return E_INVALIDARG; + xzProps.filterProps.id = prop.ulVal; + } + else + { + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + + const wchar_t *name = prop.bstrVal; + const wchar_t *end; + + UInt32 id32 = ConvertStringToUInt32(name, &end); + + if (end != name) + name = end; + else + { + if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta")) + { + name += 5; // strlen("Delta"); + id32 = XZ_ID_Delta; + } + else + { + const int filterId = FilterIdFromName(prop.bstrVal); + if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */) + return E_INVALIDARG; + id32 = (UInt32)(unsigned)filterId; + } + } + + if (id32 == XZ_ID_Delta) + { + const wchar_t c = *name; + if (c != '-' && c != ':') + return E_INVALIDARG; + name++; + const UInt32 delta = ConvertStringToUInt32(name, &end); + if (end == name || *end != 0 || delta == 0 || delta > 256) + return E_INVALIDARG; + xzProps.filterProps.delta = delta; + } + + xzProps.filterProps.id = id32; + } + + return S_OK; + } + + return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props); +} + + +Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps)) +{ + XzProps_Init(&xzProps); + + for (UInt32 i = 0; i < numProps; i++) + { + RINOK(SetCoderProp(propIDs[i], coderProps[i])) + } + + return S_OK; + // return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps)); +} + + +Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, + const PROPVARIANT *coderProps, UInt32 numProps)) +{ + for (UInt32 i = 0; i < numProps; i++) + { + const PROPVARIANT &prop = coderProps[i]; + const PROPID propID = propIDs[i]; + if (propID == NCoderPropID::kExpectedDataSize) + if (prop.vt == VT_UI8) + XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart); + } + return S_OK; +} + + +#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \ + if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes; + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) +{ + CSeqInStreamWrap inWrap; + CSeqOutStreamWrap outWrap; + CCompressProgressWrap progressWrap; + + inWrap.Init(inStream); + outWrap.Init(outStream); + progressWrap.Init(progress); + + SRes res = XzEnc_SetProps(_encoder, &xzProps); + if (res == SZ_OK) + res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL); + + // SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL); + + RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ) + RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE) + RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS) + + return SResToHRESULT(res); +} + +}} diff --git a/CPP/7zip/Compress/XzEncoder.h b/CPP/7zip/Compress/XzEncoder.h index e08759f3f..434f58209 100644 --- a/CPP/7zip/Compress/XzEncoder.h +++ b/CPP/7zip/Compress/XzEncoder.h @@ -1,35 +1,35 @@ -// XzEncoder.h - -#ifndef ZIP7_INC_XZ_ENCODER_H -#define ZIP7_INC_XZ_ENCODER_H - -#include "../../../C/XzEnc.h" - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NXz { - -Z7_CLASS_IMP_COM_3( - CEncoder - , ICompressCoder - , ICompressSetCoderProperties - , ICompressSetCoderPropertiesOpt -) - CXzEncHandle _encoder; -public: - CXzProps xzProps; - - void InitCoderProps(); - HRESULT SetCheckSize(UInt32 checkSizeInBytes); - HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop); - - CEncoder(); - ~CEncoder(); -}; - -}} - -#endif +// XzEncoder.h + +#ifndef ZIP7_INC_XZ_ENCODER_H +#define ZIP7_INC_XZ_ENCODER_H + +#include "../../../C/XzEnc.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NXz { + +Z7_CLASS_IMP_COM_3( + CEncoder + , ICompressCoder + , ICompressSetCoderProperties + , ICompressSetCoderPropertiesOpt +) + CXzEncHandle _encoder; +public: + CXzProps xzProps; + + void InitCoderProps(); + HRESULT SetCheckSize(UInt32 checkSizeInBytes); + HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop); + + CEncoder(); + ~CEncoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/ZDecoder.cpp b/CPP/7zip/Compress/ZDecoder.cpp index f5886b94b..25eb80ee2 100644 --- a/CPP/7zip/Compress/ZDecoder.cpp +++ b/CPP/7zip/Compress/ZDecoder.cpp @@ -1,235 +1,235 @@ -// ZDecoder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/Alloc.h" - -#include "../Common/InBuffer.h" -#include "../Common/OutBuffer.h" - -#include "ZDecoder.h" - -namespace NCompress { -namespace NZ { - -static const size_t kBufferSize = 1 << 20; -static const Byte kNumBitsMask = 0x1F; -static const Byte kBlockModeMask = 0x80; -static const unsigned kNumMinBits = 9; -static const unsigned kNumMaxBits = 16; - -void CDecoder::Free() -{ - MyFree(_parents); _parents = NULL; - MyFree(_suffixes); _suffixes = NULL; - MyFree(_stack); _stack = NULL; -} - -CDecoder::~CDecoder() { Free(); } - -HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - ICompressProgressInfo *progress) -{ - try { - // PackSize = 0; - - CInBuffer inBuffer; - COutBuffer outBuffer; - - if (!inBuffer.Create(kBufferSize)) - return E_OUTOFMEMORY; - inBuffer.SetStream(inStream); - inBuffer.Init(); - - if (!outBuffer.Create(kBufferSize)) - return E_OUTOFMEMORY; - outBuffer.SetStream(outStream); - outBuffer.Init(); - - Byte buf[kNumMaxBits + 4]; - { - if (inBuffer.ReadBytes(buf, 3) < 3) - return S_FALSE; - if (buf[0] != 0x1F || buf[1] != 0x9D) - return S_FALSE; - } - const Byte prop = buf[2]; - - if ((prop & 0x60) != 0) - return S_FALSE; - const unsigned maxbits = prop & kNumBitsMask; - if (maxbits < kNumMinBits || maxbits > kNumMaxBits) - return S_FALSE; - const UInt32 numItems = (UInt32)1 << maxbits; - // Speed optimization: blockSymbol can contain unused velue. - - if (maxbits != _numMaxBits || !_parents || !_suffixes || !_stack) - { - Free(); - _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (!_parents) return E_OUTOFMEMORY; - _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_suffixes) return E_OUTOFMEMORY; - _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_stack) return E_OUTOFMEMORY; - _numMaxBits = maxbits; - } - - UInt64 prevPos = 0; - const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits); - unsigned numBits = kNumMinBits; - UInt32 head = (blockSymbol == 256) ? 257 : 256; - bool needPrev = false; - unsigned bitPos = 0; - unsigned numBufBits = 0; - - _parents[256] = 0; // virus protection - _suffixes[256] = 0; - HRESULT res = S_OK; - - for (;;) - { - if (numBufBits == bitPos) - { - numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8; - bitPos = 0; - const UInt64 nowPos = outBuffer.GetProcessedSize(); - if (progress && nowPos - prevPos >= (1 << 13)) - { - prevPos = nowPos; - const UInt64 packSize = inBuffer.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &nowPos)) - } - } - const unsigned bytePos = bitPos >> 3; - UInt32 symbol = buf[bytePos] | ((UInt32)buf[(size_t)bytePos + 1] << 8) | ((UInt32)buf[(size_t)bytePos + 2] << 16); - symbol >>= (bitPos & 7); - symbol &= ((UInt32)1 << numBits) - 1; - bitPos += numBits; - if (bitPos > numBufBits) - break; - if (symbol >= head) - { - res = S_FALSE; - break; - } - if (symbol == blockSymbol) - { - numBufBits = bitPos = 0; - numBits = kNumMinBits; - head = 257; - needPrev = false; - continue; - } - UInt32 cur = symbol; - unsigned i = 0; - while (cur >= 256) - { - _stack[i++] = _suffixes[cur]; - cur = _parents[cur]; - } - _stack[i++] = (Byte)cur; - if (needPrev) - { - _suffixes[(size_t)head - 1] = (Byte)cur; - if (symbol == head - 1) - _stack[0] = (Byte)cur; - } - do - outBuffer.WriteByte((_stack[--i])); - while (i > 0); - if (head < numItems) - { - needPrev = true; - _parents[head++] = (UInt16)symbol; - if (head > ((UInt32)1 << numBits)) - { - if (numBits < maxbits) - { - numBufBits = bitPos = 0; - numBits++; - } - } - } - else - needPrev = false; - } - // PackSize = inBuffer.GetProcessedSize(); - const HRESULT res2 = outBuffer.Flush(); - return (res == S_OK) ? res2 : res; - - } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const COutBufferException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } -} - - -bool CheckStream(const Byte *data, size_t size) -{ - if (size < 3) - return false; - if (data[0] != 0x1F || data[1] != 0x9D) - return false; - const Byte prop = data[2]; - if ((prop & 0x60) != 0) - return false; - const unsigned maxbits = prop & kNumBitsMask; - if (maxbits < kNumMinBits || maxbits > kNumMaxBits) - return false; - const UInt32 numItems = (UInt32)1 << maxbits; - const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits); - unsigned numBits = kNumMinBits; - UInt32 head = (blockSymbol == 256) ? 257 : 256; - unsigned bitPos = 0; - unsigned numBufBits = 0; - Byte buf[kNumMaxBits + 4]; - data += 3; - size -= 3; - // printf("\n\n"); - for (;;) - { - if (numBufBits == bitPos) - { - const unsigned num = (numBits < size) ? numBits : (unsigned)size; - memcpy(buf, data, num); - data += num; - size -= num; - numBufBits = num * 8; - bitPos = 0; - } - const unsigned bytePos = bitPos >> 3; - UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16); - symbol >>= (bitPos & 7); - symbol &= ((UInt32)1 << numBits) - 1; - bitPos += numBits; - if (bitPos > numBufBits) - { - // printf(" OK", symbol); - return true; - } - // printf("%3X ", symbol); - if (symbol >= head) - return false; - if (symbol == blockSymbol) - { - numBufBits = bitPos = 0; - numBits = kNumMinBits; - head = 257; - continue; - } - if (head < numItems) - { - head++; - if (head > ((UInt32)1 << numBits)) - { - if (numBits < maxbits) - { - numBufBits = bitPos = 0; - numBits++; - } - } - } - } -} - -}} +// ZDecoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/Alloc.h" + +#include "../Common/InBuffer.h" +#include "../Common/OutBuffer.h" + +#include "ZDecoder.h" + +namespace NCompress { +namespace NZ { + +static const size_t kBufferSize = 1 << 20; +static const Byte kNumBitsMask = 0x1F; +static const Byte kBlockModeMask = 0x80; +static const unsigned kNumMinBits = 9; +static const unsigned kNumMaxBits = 16; + +void CDecoder::Free() +{ + MyFree(_parents); _parents = NULL; + MyFree(_suffixes); _suffixes = NULL; + MyFree(_stack); _stack = NULL; +} + +CDecoder::~CDecoder() { Free(); } + +HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + ICompressProgressInfo *progress) +{ + try { + // PackSize = 0; + + CInBuffer inBuffer; + COutBuffer outBuffer; + + if (!inBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + inBuffer.SetStream(inStream); + inBuffer.Init(); + + if (!outBuffer.Create(kBufferSize)) + return E_OUTOFMEMORY; + outBuffer.SetStream(outStream); + outBuffer.Init(); + + Byte buf[kNumMaxBits + 4]; + { + if (inBuffer.ReadBytes(buf, 3) < 3) + return S_FALSE; + if (buf[0] != 0x1F || buf[1] != 0x9D) + return S_FALSE; + } + const Byte prop = buf[2]; + + if ((prop & 0x60) != 0) + return S_FALSE; + const unsigned maxbits = prop & kNumBitsMask; + if (maxbits < kNumMinBits || maxbits > kNumMaxBits) + return S_FALSE; + const UInt32 numItems = (UInt32)1 << maxbits; + // Speed optimization: blockSymbol can contain unused velue. + + if (maxbits != _numMaxBits || !_parents || !_suffixes || !_stack) + { + Free(); + _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (!_parents) return E_OUTOFMEMORY; + _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_suffixes) return E_OUTOFMEMORY; + _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_stack) return E_OUTOFMEMORY; + _numMaxBits = maxbits; + } + + UInt64 prevPos = 0; + const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits); + unsigned numBits = kNumMinBits; + UInt32 head = (blockSymbol == 256) ? 257 : 256; + bool needPrev = false; + unsigned bitPos = 0; + unsigned numBufBits = 0; + + _parents[256] = 0; // virus protection + _suffixes[256] = 0; + HRESULT res = S_OK; + + for (;;) + { + if (numBufBits == bitPos) + { + numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8; + bitPos = 0; + const UInt64 nowPos = outBuffer.GetProcessedSize(); + if (progress && nowPos - prevPos >= (1 << 13)) + { + prevPos = nowPos; + const UInt64 packSize = inBuffer.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &nowPos)) + } + } + const unsigned bytePos = bitPos >> 3; + UInt32 symbol = buf[bytePos] | ((UInt32)buf[(size_t)bytePos + 1] << 8) | ((UInt32)buf[(size_t)bytePos + 2] << 16); + symbol >>= (bitPos & 7); + symbol &= ((UInt32)1 << numBits) - 1; + bitPos += numBits; + if (bitPos > numBufBits) + break; + if (symbol >= head) + { + res = S_FALSE; + break; + } + if (symbol == blockSymbol) + { + numBufBits = bitPos = 0; + numBits = kNumMinBits; + head = 257; + needPrev = false; + continue; + } + UInt32 cur = symbol; + unsigned i = 0; + while (cur >= 256) + { + _stack[i++] = _suffixes[cur]; + cur = _parents[cur]; + } + _stack[i++] = (Byte)cur; + if (needPrev) + { + _suffixes[(size_t)head - 1] = (Byte)cur; + if (symbol == head - 1) + _stack[0] = (Byte)cur; + } + do + outBuffer.WriteByte((_stack[--i])); + while (i > 0); + if (head < numItems) + { + needPrev = true; + _parents[head++] = (UInt16)symbol; + if (head > ((UInt32)1 << numBits)) + { + if (numBits < maxbits) + { + numBufBits = bitPos = 0; + numBits++; + } + } + } + else + needPrev = false; + } + // PackSize = inBuffer.GetProcessedSize(); + const HRESULT res2 = outBuffer.Flush(); + return (res == S_OK) ? res2 : res; + + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + + +bool CheckStream(const Byte *data, size_t size) +{ + if (size < 3) + return false; + if (data[0] != 0x1F || data[1] != 0x9D) + return false; + const Byte prop = data[2]; + if ((prop & 0x60) != 0) + return false; + const unsigned maxbits = prop & kNumBitsMask; + if (maxbits < kNumMinBits || maxbits > kNumMaxBits) + return false; + const UInt32 numItems = (UInt32)1 << maxbits; + const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits); + unsigned numBits = kNumMinBits; + UInt32 head = (blockSymbol == 256) ? 257 : 256; + unsigned bitPos = 0; + unsigned numBufBits = 0; + Byte buf[kNumMaxBits + 4]; + data += 3; + size -= 3; + // printf("\n\n"); + for (;;) + { + if (numBufBits == bitPos) + { + const unsigned num = (numBits < size) ? numBits : (unsigned)size; + memcpy(buf, data, num); + data += num; + size -= num; + numBufBits = num * 8; + bitPos = 0; + } + const unsigned bytePos = bitPos >> 3; + UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16); + symbol >>= (bitPos & 7); + symbol &= ((UInt32)1 << numBits) - 1; + bitPos += numBits; + if (bitPos > numBufBits) + { + // printf(" OK", symbol); + return true; + } + // printf("%3X ", symbol); + if (symbol >= head) + return false; + if (symbol == blockSymbol) + { + numBufBits = bitPos = 0; + numBits = kNumMinBits; + head = 257; + continue; + } + if (head < numItems) + { + head++; + if (head > ((UInt32)1 << numBits)) + { + if (numBits < maxbits) + { + numBufBits = bitPos = 0; + numBits++; + } + } + } + } +} + +}} diff --git a/CPP/7zip/Compress/ZDecoder.h b/CPP/7zip/Compress/ZDecoder.h index e96ffbaf5..fd67f8f6d 100644 --- a/CPP/7zip/Compress/ZDecoder.h +++ b/CPP/7zip/Compress/ZDecoder.h @@ -1,47 +1,47 @@ -// ZDecoder.h - -#ifndef ZIP7_INC_COMPRESS_Z_DECODER_H -#define ZIP7_INC_COMPRESS_Z_DECODER_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCompress { -namespace NZ { - -// Z decoder decodes Z data stream, including 3 bytes of header. - -class CDecoder -{ - UInt16 *_parents; - Byte *_suffixes; - Byte *_stack; - unsigned _numMaxBits; - -public: - CDecoder(): _parents(NULL), _suffixes(NULL), _stack(NULL), /* _prop(0), */ _numMaxBits(0) {} - ~CDecoder(); - void Free(); - // UInt64 PackSize; - - HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - ICompressProgressInfo *progress); -}; - -/* - There is no end_of_payload_marker in Z stream. - Z decoder stops decoding, if it reaches end of input stream. - - CheckStream function: - (size) must be at least 3 bytes (size of Z header). - if (size) is larger than size of real Z stream in (data), CheckStream can return false. -*/ - -const unsigned kRecommendedCheckSize = 64; - -bool CheckStream(const Byte *data, size_t size); - -}} - -#endif +// ZDecoder.h + +#ifndef ZIP7_INC_COMPRESS_Z_DECODER_H +#define ZIP7_INC_COMPRESS_Z_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCompress { +namespace NZ { + +// Z decoder decodes Z data stream, including 3 bytes of header. + +class CDecoder +{ + UInt16 *_parents; + Byte *_suffixes; + Byte *_stack; + unsigned _numMaxBits; + +public: + CDecoder(): _parents(NULL), _suffixes(NULL), _stack(NULL), /* _prop(0), */ _numMaxBits(0) {} + ~CDecoder(); + void Free(); + // UInt64 PackSize; + + HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + ICompressProgressInfo *progress); +}; + +/* + There is no end_of_payload_marker in Z stream. + Z decoder stops decoding, if it reaches end of input stream. + + CheckStream function: + (size) must be at least 3 bytes (size of Z header). + if (size) is larger than size of real Z stream in (data), CheckStream can return false. +*/ + +const unsigned kRecommendedCheckSize = 64; + +bool CheckStream(const Byte *data, size_t size); + +}} + +#endif diff --git a/CPP/7zip/Compress/ZlibDecoder.cpp b/CPP/7zip/Compress/ZlibDecoder.cpp index 95beb9d98..dc018942c 100644 --- a/CPP/7zip/Compress/ZlibDecoder.cpp +++ b/CPP/7zip/Compress/ZlibDecoder.cpp @@ -1,136 +1,136 @@ -// ZlibDecoder.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../Common/StreamUtils.h" - -#include "ZlibDecoder.h" - -namespace NCompress { -namespace NZlib { - -#define DEFLATE_TRY_BEGIN try { -#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } - -#define ADLER_MOD 65521 -#define ADLER_LOOP_MAX 5550 - -UInt32 Adler32_Update(UInt32 adler, const Byte *data, size_t size); -UInt32 Adler32_Update(UInt32 adler, const Byte *data, size_t size) -{ - if (size == 0) - return adler; - UInt32 a = adler & 0xffff; - UInt32 b = adler >> 16; - do - { - size_t cur = size; - if (cur > ADLER_LOOP_MAX) - cur = ADLER_LOOP_MAX; - size -= cur; - const Byte *lim = data + cur; - if (cur >= 4) - { - lim -= 4 - 1; - do - { - a += data[0]; b += a; - a += data[1]; b += a; - a += data[2]; b += a; - a += data[3]; b += a; - data += 4; - } - while (data < lim); - lim += 4 - 1; - } - if (data != lim) { a += *data++; b += a; - if (data != lim) { a += *data++; b += a; - if (data != lim) { a += *data++; b += a; }}} - a %= ADLER_MOD; - b %= ADLER_MOD; - } - while (size); - return (b << 16) + a; -} - -Z7_COM7F_IMF(COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - _adler = Adler32_Update(_adler, (const Byte *)data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - DEFLATE_TRY_BEGIN - _inputProcessedSize_Additional = 0; - AdlerStream.Create_if_Empty(); - DeflateDecoder.Create_if_Empty(); - DeflateDecoder->Set_NeedFinishInput(true); - - if (inSize && *inSize < 2) - return S_FALSE; - { - Byte buf[2]; - RINOK(ReadStream_FALSE(inStream, buf, 2)) - if (!IsZlib(buf)) - return S_FALSE; - } - _inputProcessedSize_Additional = 2; - AdlerStream->SetStream(outStream); - AdlerStream->Init(); - // NDeflate::NDecoder::Code() ignores inSize - /* - UInt64 inSize2 = 0; - if (inSize) - inSize2 = *inSize - 2; - */ - const HRESULT res = DeflateDecoder.Interface()->Code(inStream, AdlerStream, - /* inSize ? &inSize2 : */ NULL, outSize, progress); - AdlerStream->ReleaseStream(); - - if (res == S_OK) - { - UInt32 footer32[1]; - UInt32 processedSize; - RINOK(DeflateDecoder->ReadUnusedFromInBuf(footer32, 4, &processedSize)) - if (processedSize != 4) - { - size_t processedSize2 = 4 - processedSize; - RINOK(ReadStream(inStream, (Byte *)(void *)footer32 + processedSize, &processedSize2)) - _inputProcessedSize_Additional += (Int32)processedSize2; - processedSize += (UInt32)processedSize2; - } - - if (processedSize == 4) - { - const UInt32 adler = GetBe32a(footer32); - if (adler != AdlerStream->GetAdler()) - return S_FALSE; // adler error - } - else if (!IsAdlerOptional) - return S_FALSE; // unexpeced end of stream (can't read adler) - else - { - // IsAdlerOptional == true - if (processedSize != 0) - { - // we exclude adler bytes from processed size: - _inputProcessedSize_Additional -= (Int32)processedSize; - return S_FALSE; - } - } - } - return res; - DEFLATE_TRY_END -} - -}} +// ZlibDecoder.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "ZlibDecoder.h" + +namespace NCompress { +namespace NZlib { + +#define DEFLATE_TRY_BEGIN try { +#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } + +#define ADLER_MOD 65521 +#define ADLER_LOOP_MAX 5550 + +UInt32 Adler32_Update(UInt32 adler, const Byte *data, size_t size); +UInt32 Adler32_Update(UInt32 adler, const Byte *data, size_t size) +{ + if (size == 0) + return adler; + UInt32 a = adler & 0xffff; + UInt32 b = adler >> 16; + do + { + size_t cur = size; + if (cur > ADLER_LOOP_MAX) + cur = ADLER_LOOP_MAX; + size -= cur; + const Byte *lim = data + cur; + if (cur >= 4) + { + lim -= 4 - 1; + do + { + a += data[0]; b += a; + a += data[1]; b += a; + a += data[2]; b += a; + a += data[3]; b += a; + data += 4; + } + while (data < lim); + lim += 4 - 1; + } + if (data != lim) { a += *data++; b += a; + if (data != lim) { a += *data++; b += a; + if (data != lim) { a += *data++; b += a; }}} + a %= ADLER_MOD; + b %= ADLER_MOD; + } + while (size); + return (b << 16) + a; +} + +Z7_COM7F_IMF(COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + _adler = Adler32_Update(_adler, (const Byte *)data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + DEFLATE_TRY_BEGIN + _inputProcessedSize_Additional = 0; + AdlerStream.Create_if_Empty(); + DeflateDecoder.Create_if_Empty(); + DeflateDecoder->Set_NeedFinishInput(true); + + if (inSize && *inSize < 2) + return S_FALSE; + { + Byte buf[2]; + RINOK(ReadStream_FALSE(inStream, buf, 2)) + if (!IsZlib(buf)) + return S_FALSE; + } + _inputProcessedSize_Additional = 2; + AdlerStream->SetStream(outStream); + AdlerStream->Init(); + // NDeflate::NDecoder::Code() ignores inSize + /* + UInt64 inSize2 = 0; + if (inSize) + inSize2 = *inSize - 2; + */ + const HRESULT res = DeflateDecoder.Interface()->Code(inStream, AdlerStream, + /* inSize ? &inSize2 : */ NULL, outSize, progress); + AdlerStream->ReleaseStream(); + + if (res == S_OK) + { + UInt32 footer32[1]; + UInt32 processedSize; + RINOK(DeflateDecoder->ReadUnusedFromInBuf(footer32, 4, &processedSize)) + if (processedSize != 4) + { + size_t processedSize2 = 4 - processedSize; + RINOK(ReadStream(inStream, (Byte *)(void *)footer32 + processedSize, &processedSize2)) + _inputProcessedSize_Additional += (Int32)processedSize2; + processedSize += (UInt32)processedSize2; + } + + if (processedSize == 4) + { + const UInt32 adler = GetBe32a(footer32); + if (adler != AdlerStream->GetAdler()) + return S_FALSE; // adler error + } + else if (!IsAdlerOptional) + return S_FALSE; // unexpeced end of stream (can't read adler) + else + { + // IsAdlerOptional == true + if (processedSize != 0) + { + // we exclude adler bytes from processed size: + _inputProcessedSize_Additional -= (Int32)processedSize; + return S_FALSE; + } + } + } + return res; + DEFLATE_TRY_END +} + +}} diff --git a/CPP/7zip/Compress/ZlibDecoder.h b/CPP/7zip/Compress/ZlibDecoder.h index 0570d81a4..548865304 100644 --- a/CPP/7zip/Compress/ZlibDecoder.h +++ b/CPP/7zip/Compress/ZlibDecoder.h @@ -1,78 +1,78 @@ -// ZlibDecoder.h - -#ifndef ZIP7_INC_ZLIB_DECODER_H -#define ZIP7_INC_ZLIB_DECODER_H - -#include "DeflateDecoder.h" - -namespace NCompress { -namespace NZlib { - -const UInt32 ADLER_INIT_VAL = 1; - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithAdler - , ISequentialOutStream -) - UInt32 _adler; - CMyComPtr _stream; - UInt64 _size; -public: - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _adler = ADLER_INIT_VAL; _size = 0; } - UInt32 GetAdler() const { return _adler; } - UInt64 GetSize() const { return _size; } -}; - -Z7_CLASS_IMP_NOQIB_1( - CDecoder - , ICompressCoder -) - CMyComPtr2 AdlerStream; - CMyComPtr2 DeflateDecoder; - Int32 _inputProcessedSize_Additional; -public: - bool IsAdlerOptional; - - CDecoder(): IsAdlerOptional(false) {} - UInt64 GetInputProcessedSize() const - { - return (UInt64)( - (Int64)DeflateDecoder->GetInputProcessedSize() + - (Int64)_inputProcessedSize_Additional); - } - UInt64 GetOutputProcessedSize() const { return AdlerStream->GetSize(); } -}; - -static bool inline IsZlib(const Byte *p) -{ - if ((p[0] & 0xF) != 8) // method - return false; - if (((unsigned)p[0] >> 4) > 7) // logar_window_size minus 8. - return false; - if ((p[1] & 0x20) != 0) // dictPresent - return false; - if ((((UInt32)p[0] << 8) + p[1]) % 31 != 0) - return false; - return true; -} - -// IsZlib_3bytes checks 2 bytes of zlib header and starting byte of Deflate stream - -static bool inline IsZlib_3bytes(const Byte *p) -{ - if (!IsZlib(p)) - return false; - const unsigned val = p[2]; - const unsigned blockType = (val >> 1) & 0x3; - if (blockType == 3) // unsupported block type for deflate - return false; - if (blockType == NCompress::NDeflate::NBlockType::kStored && (val >> 3) != 0) - return false; - return true; -} - -}} - -#endif +// ZlibDecoder.h + +#ifndef ZIP7_INC_ZLIB_DECODER_H +#define ZIP7_INC_ZLIB_DECODER_H + +#include "DeflateDecoder.h" + +namespace NCompress { +namespace NZlib { + +const UInt32 ADLER_INIT_VAL = 1; + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithAdler + , ISequentialOutStream +) + UInt32 _adler; + CMyComPtr _stream; + UInt64 _size; +public: + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _adler = ADLER_INIT_VAL; _size = 0; } + UInt32 GetAdler() const { return _adler; } + UInt64 GetSize() const { return _size; } +}; + +Z7_CLASS_IMP_NOQIB_1( + CDecoder + , ICompressCoder +) + CMyComPtr2 AdlerStream; + CMyComPtr2 DeflateDecoder; + Int32 _inputProcessedSize_Additional; +public: + bool IsAdlerOptional; + + CDecoder(): IsAdlerOptional(false) {} + UInt64 GetInputProcessedSize() const + { + return (UInt64)( + (Int64)DeflateDecoder->GetInputProcessedSize() + + (Int64)_inputProcessedSize_Additional); + } + UInt64 GetOutputProcessedSize() const { return AdlerStream->GetSize(); } +}; + +static bool inline IsZlib(const Byte *p) +{ + if ((p[0] & 0xF) != 8) // method + return false; + if (((unsigned)p[0] >> 4) > 7) // logar_window_size minus 8. + return false; + if ((p[1] & 0x20) != 0) // dictPresent + return false; + if ((((UInt32)p[0] << 8) + p[1]) % 31 != 0) + return false; + return true; +} + +// IsZlib_3bytes checks 2 bytes of zlib header and starting byte of Deflate stream + +static bool inline IsZlib_3bytes(const Byte *p) +{ + if (!IsZlib(p)) + return false; + const unsigned val = p[2]; + const unsigned blockType = (val >> 1) & 0x3; + if (blockType == 3) // unsupported block type for deflate + return false; + if (blockType == NCompress::NDeflate::NBlockType::kStored && (val >> 3) != 0) + return false; + return true; +} + +}} + +#endif diff --git a/CPP/7zip/Compress/ZlibEncoder.cpp b/CPP/7zip/Compress/ZlibEncoder.cpp index 4c875c300..3670d3036 100644 --- a/CPP/7zip/Compress/ZlibEncoder.cpp +++ b/CPP/7zip/Compress/ZlibEncoder.cpp @@ -1,61 +1,61 @@ -// ZlibEncoder.cpp - -#include "StdAfx.h" - -#include "../Common/StreamUtils.h" - -#include "ZlibEncoder.h" - -namespace NCompress { -namespace NZlib { - -#define DEFLATE_TRY_BEGIN try { -#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } - -UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size); - -Z7_COM7F_IMF(CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - const HRESULT result = _stream->Read(data, size, &size); - _adler = Adler32_Update(_adler, (const Byte *)data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -void CEncoder::Create() -{ - if (!DeflateEncoder) - DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder; -} - -Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) -{ - DEFLATE_TRY_BEGIN - if (!AdlerStream) - AdlerStream = AdlerSpec = new CInStreamWithAdler; - Create(); - - { - Byte buf[2] = { 0x78, 0xDA }; - RINOK(WriteStream(outStream, buf, 2)) - } - - AdlerSpec->SetStream(inStream); - AdlerSpec->Init(); - const HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress); - AdlerSpec->ReleaseStream(); - - RINOK(res) - - { - const UInt32 a = AdlerSpec->GetAdler(); - const Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) }; - return WriteStream(outStream, buf, 4); - } - DEFLATE_TRY_END -} - -}} +// ZlibEncoder.cpp + +#include "StdAfx.h" + +#include "../Common/StreamUtils.h" + +#include "ZlibEncoder.h" + +namespace NCompress { +namespace NZlib { + +#define DEFLATE_TRY_BEGIN try { +#define DEFLATE_TRY_END } catch(...) { return S_FALSE; } + +UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size); + +Z7_COM7F_IMF(CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + const HRESULT result = _stream->Read(data, size, &size); + _adler = Adler32_Update(_adler, (const Byte *)data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +void CEncoder::Create() +{ + if (!DeflateEncoder) + DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder; +} + +Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress)) +{ + DEFLATE_TRY_BEGIN + if (!AdlerStream) + AdlerStream = AdlerSpec = new CInStreamWithAdler; + Create(); + + { + Byte buf[2] = { 0x78, 0xDA }; + RINOK(WriteStream(outStream, buf, 2)) + } + + AdlerSpec->SetStream(inStream); + AdlerSpec->Init(); + const HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress); + AdlerSpec->ReleaseStream(); + + RINOK(res) + + { + const UInt32 a = AdlerSpec->GetAdler(); + const Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) }; + return WriteStream(outStream, buf, 4); + } + DEFLATE_TRY_END +} + +}} diff --git a/CPP/7zip/Compress/ZlibEncoder.h b/CPP/7zip/Compress/ZlibEncoder.h index a8b1dd89e..484a307c5 100644 --- a/CPP/7zip/Compress/ZlibEncoder.h +++ b/CPP/7zip/Compress/ZlibEncoder.h @@ -1,42 +1,42 @@ -// ZlibEncoder.h - -#ifndef ZIP7_INC_ZLIB_ENCODER_H -#define ZIP7_INC_ZLIB_ENCODER_H - -#include "DeflateEncoder.h" - -namespace NCompress { -namespace NZlib { - -Z7_CLASS_IMP_NOQIB_1( - CInStreamWithAdler - , ISequentialInStream -) - CMyComPtr _stream; - UInt32 _adler; - UInt64 _size; -public: - void SetStream(ISequentialInStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL - UInt32 GetAdler() const { return _adler; } - UInt64 GetSize() const { return _size; } -}; - -Z7_CLASS_IMP_NOQIB_1( - CEncoder - , ICompressCoder -) - CInStreamWithAdler *AdlerSpec; - CMyComPtr AdlerStream; - CMyComPtr DeflateEncoder; -public: - NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec; - - void Create(); - UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); } -}; - -}} - -#endif +// ZlibEncoder.h + +#ifndef ZIP7_INC_ZLIB_ENCODER_H +#define ZIP7_INC_ZLIB_ENCODER_H + +#include "DeflateEncoder.h" + +namespace NCompress { +namespace NZlib { + +Z7_CLASS_IMP_NOQIB_1( + CInStreamWithAdler + , ISequentialInStream +) + CMyComPtr _stream; + UInt32 _adler; + UInt64 _size; +public: + void SetStream(ISequentialInStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL + UInt32 GetAdler() const { return _adler; } + UInt64 GetSize() const { return _size; } +}; + +Z7_CLASS_IMP_NOQIB_1( + CEncoder + , ICompressCoder +) + CInStreamWithAdler *AdlerSpec; + CMyComPtr AdlerStream; + CMyComPtr DeflateEncoder; +public: + NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec; + + void Create(); + UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); } +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/ZstdDecoder.cpp b/CPP/7zip/Compress/ZstdDecoder.cpp index b5a60a212..c95847566 100644 --- a/CPP/7zip/Compress/ZstdDecoder.cpp +++ b/CPP/7zip/Compress/ZstdDecoder.cpp @@ -1,437 +1,437 @@ -// ZstdDecoder.cpp - -#include "StdAfx.h" - -// #include - -#include "../../../C/Alloc.h" - -#include "../Common/CWrappers.h" -#include "../Common/StreamUtils.h" - -#include "ZstdDecoder.h" - -namespace NCompress { -namespace NZstd { - -static const size_t k_Zstd_BlockSizeMax = 1 << 17; -/* - we set _outStepMask as (k_Zstd_BlockSizeMax - 1), because: - - cycSize in zstd decoder for isCyclicMode is aligned for (1 << 17) only. - So some write sizes will be multiple of ((1 << 17) * n). - - Also it can be optimal to flush data after each block decoding. -*/ - -CDecoder::CDecoder(): - _outStepMask(k_Zstd_BlockSizeMax - 1) // must be = (1 << x) - 1 - , _dec(NULL) - , _inProcessed(0) - , _inBufSize(1u << 19) // larger value will reduce the number of memcpy() calls in CZstdDec code - , _inBuf(NULL) - , FinishMode(false) - , DisableHash(False) - // , DisableHash(True) // for debug : fast decoding without hash calculation -{ - // ZstdDecInfo_Clear(&ResInfo); -} - -CDecoder::~CDecoder() -{ - if (_dec) - ZstdDec_Destroy(_dec); - MidFree(_inBuf); -} - - -Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) - { _inBufSize = size; return S_OK; } -Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) -{ - // we round it down: - size >>= 1; - size |= size >> (1 << 0); - size |= size >> (1 << 1); - size |= size >> (1 << 2); - size |= size >> (1 << 3); - size |= size >> (1 << 4); - _outStepMask = size; // it's (1 << x) - 1 now - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte * /* prop */, UInt32 /* size */)) -{ - // if (size != 3 && size != 5) return E_NOTIMPL; - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) -{ - FinishMode = (finishMode != 0); - // FinishMode = false; // for debug - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) -{ - size_t cur = ZstdDec_ReadUnusedFromInBuf(_dec, _afterDecoding_tempPos, data, size); - _afterDecoding_tempPos += cur; - size -= (UInt32)cur; - if (size) - { - const size_t rem = _state.inLim - _state.inPos; - if (size > rem) - size = (UInt32)rem; - if (size) - { - memcpy((Byte *)data + cur, _state.inBuf + _state.inPos, size); - _state.inPos += size; - cur += size; - } - } - *processedSize = (UInt32)cur; - return S_OK; -} - - - -HRESULT CDecoder::Prepare(const UInt64 *outSize) -{ - _inProcessed = 0; - _afterDecoding_tempPos = 0; - ZstdDecState_Clear(&_state); - ZstdDecInfo_CLEAR(&ResInfo) - // _state.outStep = _outStepMask + 1; // must be = (1 << x) - _state.disableHash = DisableHash; - if (outSize) - { - _state.outSize_Defined = True; - _state.outSize = *outSize; - // _state.outSize = 0; // for debug - } - if (!_dec) - { - _dec = ZstdDec_Create(&g_AlignedAlloc, &g_BigAlloc); - if (!_dec) - return E_OUTOFMEMORY; - } - if (!_inBuf || _inBufSize != _inBufSize_Allocated) - { - MidFree(_inBuf); - _inBuf = NULL; - _inBufSize_Allocated = 0; - _inBuf = (Byte *)MidAlloc(_inBufSize); - if (!_inBuf) - return E_OUTOFMEMORY; - _inBufSize_Allocated = _inBufSize; - } - _state.inBuf = _inBuf; - ZstdDec_Init(_dec); - return S_OK; -} - - -Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, - const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) -{ - RINOK(Prepare(outSize)) - - UInt64 inPrev = 0; - UInt64 outPrev = 0; - UInt64 writtenSize = 0; - bool readWasFinished = false; - SRes sres = SZ_OK; - HRESULT hres = S_OK; - HRESULT hres_Read = S_OK; - - for (;;) - { - if (_state.inPos == _state.inLim && !readWasFinished) - { - _state.inPos = 0; - _state.inLim = _inBufSize; - hres_Read = ReadStream(inStream, _inBuf, &_state.inLim); - // _state.inLim -= 5; readWasFinished = True; // for debug - if (_state.inLim != _inBufSize || hres_Read != S_OK) - { - // hres_Read = 99; // for debug - readWasFinished = True; - } - } - { - const size_t inPos_Start = _state.inPos; - sres = ZstdDec_Decode(_dec, &_state); - _inProcessed += _state.inPos - inPos_Start; - } - /* - if (_state.status == ZSTD_STATUS_FINISHED_FRAME) - printf("\nfinished frame pos=%8x, checksum=%08x\n", (unsigned)_state.outProcessed, (unsigned)_state.info.checksum); - */ - const bool needStop = (sres != SZ_OK) - || _state.status == ZSTD_STATUS_OUT_REACHED - || (outSize && *outSize < _state.outProcessed) - || (readWasFinished && _state.inPos == _state.inLim - && ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(&_state)); - - size_t size = _state.winPos - _state.wrPos; // full write size - if (size) - { - if (!needStop) - { - // we try to flush on aligned positions, if possible - size = _state.needWrite_Size; // minimal required write size - const size_t alignedPos = _state.winPos & ~(size_t)_outStepMask; - if (alignedPos > _state.wrPos) - { - const size_t size2 = alignedPos - _state.wrPos; // optimized aligned size - if (size < size2) - size = size2; - } - } - if (size) - { - { - size_t curSize = size; - if (outSize) - { - const UInt64 rem = *outSize - writtenSize; - if (curSize > rem) - curSize = (size_t)rem; - } - if (curSize) - { - // printf("Write wrPos=%8x, size=%8x\n", (unsigned)_state.wrPos, (unsigned)size); - hres = WriteStream(outStream, _state.win + _state.wrPos, curSize); - if (hres != S_OK) - break; - writtenSize += curSize; // it's real size of data that was written to stream - } - } - _state.wrPos += size; // virtual written size, that will be reported to CZstdDec - // _state.needWrite_Size = 0; // optional - } - } - - if (needStop) - break; - if (progress) - if (_inProcessed - inPrev >= (1 << 27) - || _state.outProcessed - outPrev >= (1 << 28)) - { - inPrev = _inProcessed; - outPrev = _state.outProcessed; - RINOK(progress->SetRatioInfo(&inPrev, &outPrev)) - } - } - - if (hres == S_OK) - { - ZstdDec_GetResInfo(_dec, &_state, sres, &ResInfo); - sres = ResInfo.decode_SRes; - /* now (ResInfo.decode_SRes) can contain 2 extra error codes: - - SZ_ERROR_NO_ARCHIVE : if no frames - - SZ_ERROR_INPUT_EOF : if ZSTD_STATUS_NEEDS_MORE_INPUT - */ - _inProcessed -= ResInfo.extraSize; - if (hres_Read != S_OK && _state.inLim == _state.inPos && readWasFinished) - { - /* if (there is stream reading error, - and decoding was stopped because of end of input stream), - then we use reading error as main error code */ - if (sres == SZ_OK || - sres == SZ_ERROR_INPUT_EOF || - sres == SZ_ERROR_NO_ARCHIVE) - hres = hres_Read; - } - if (sres == SZ_ERROR_INPUT_EOF && !FinishMode) - { - /* SZ_ERROR_INPUT_EOF case is allowed case for (!FinishMode) mode. - So we restore SZ_OK result for that case: */ - ResInfo.decode_SRes = sres = SZ_OK; - } - if (hres == S_OK) - { - hres = SResToHRESULT(sres); - if (hres == S_OK && FinishMode) - { - if ((inSize && *inSize != _inProcessed) - || ResInfo.is_NonFinishedFrame - || (outSize && (*outSize != writtenSize || writtenSize != _state.outProcessed))) - hres = S_FALSE; - } - } - } - return hres; -} - - -Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) -{ - *value = _inProcessed; - return S_OK; -} - - -#ifndef Z7_NO_READ_FROM_CODER_ZSTD - -Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) -{ - _inProcessed = 0; - _hres_Read = S_OK; - _hres_Decode = S_OK; - _writtenSize = 0; - _readWasFinished = false; - _wasFinished = false; - return Prepare(outSize); -} - - -Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) - { _inStream = inStream; return S_OK; } -Z7_COM7F_IMF(CDecoder::ReleaseInStream()) - { _inStream.Release(); return S_OK; } - - -// if SetInStream() mode: the caller must call GetFinishResult() after full decoding -// to check that there decoding was finished correctly - -HRESULT CDecoder::GetFinishResult() -{ - if (_state.winPos != _state.wrPos || !_wasFinished) - return FinishMode ? S_FALSE : S_OK; - // _state.winPos == _state.wrPos - // _wasFinished == true - if (FinishMode && _hres_Decode == S_OK && _state.outSize_Defined && _state.outSize != _writtenSize) - _hres_Decode = S_FALSE; - return _hres_Decode; -} - - -Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - - for (;;) - { - if (_state.outSize_Defined) - { - // _writtenSize <= _state.outSize - const UInt64 rem = _state.outSize - _writtenSize; - if (size > rem) - size = (UInt32)rem; - } - { - size_t cur = _state.winPos - _state.wrPos; - if (cur) - { - // _state.winPos != _state.wrPos; - // so there is some decoded data that was not written still - if (size == 0) - { - // if (FinishMode) and we are not allowed to write more, then it's data error - if (FinishMode && _state.outSize_Defined && _state.outSize == _writtenSize) - return S_FALSE; - return S_OK; - } - if (cur > size) - cur = (size_t)size; - // cur != 0 - memcpy(data, _state.win + _state.wrPos, cur); - _state.wrPos += cur; - _writtenSize += cur; - data = (void *)((Byte *)data + cur); - if (processedSize) - *processedSize += (UInt32)cur; - size -= (UInt32)cur; - continue; - } - } - - // _state.winPos == _state.wrPos - if (_wasFinished) - { - if (_hres_Decode == S_OK && FinishMode - && _state.outSize_Defined && _state.outSize != _writtenSize) - _hres_Decode = S_FALSE; - return _hres_Decode; - } - - // _wasFinished == false - if (size == 0 && _state.outSize_Defined && _state.outSize != _state.outProcessed) - { - /* size == 0 : so the caller don't need more data now. - _state.outSize > _state.outProcessed : so more data will be requested - later by caller for full processing. - So we exit without ZstdDec_Decode() call, because we don't want - ZstdDec_Decode() to start new block decoding - */ - return S_OK; - } - // size != 0 || !_state.outSize_Defined || _state.outSize == _state.outProcessed) - - if (_state.inPos == _state.inLim && !_readWasFinished) - { - _state.inPos = 0; - _state.inLim = _inBufSize; - _hres_Read = ReadStream(_inStream, _inBuf, &_state.inLim); - if (_state.inLim != _inBufSize || _hres_Read != S_OK) - { - // _hres_Read = 99; // for debug - _readWasFinished = True; - } - } - - SRes sres; - { - const SizeT inPos_Start = _state.inPos; - sres = ZstdDec_Decode(_dec, &_state); - _inProcessed += _state.inPos - inPos_Start; - } - - const bool inFinished = (_state.inPos == _state.inLim) && _readWasFinished; - - _wasFinished = (sres != SZ_OK) - || _state.status == ZSTD_STATUS_OUT_REACHED - || (_state.outSize_Defined && _state.outSize < _state.outProcessed) - || (inFinished - && ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(&_state)); - - if (!_wasFinished) - continue; - - // _wasFinished == true - /* (_state.winPos != _state.wrPos) is possible here. - So we still can have some data to flush, - but we must all result variables . - */ - HRESULT hres = S_OK; - ZstdDec_GetResInfo(_dec, &_state, sres, &ResInfo); - sres = ResInfo.decode_SRes; - _inProcessed -= ResInfo.extraSize; - if (_hres_Read != S_OK && inFinished) - { - if (sres == SZ_OK || - sres == SZ_ERROR_INPUT_EOF || - sres == SZ_ERROR_NO_ARCHIVE) - hres = _hres_Read; - } - if (sres == SZ_ERROR_INPUT_EOF && !FinishMode) - ResInfo.decode_SRes = sres = SZ_OK; - if (hres == S_OK) - { - hres = SResToHRESULT(sres); - if (hres == S_OK && FinishMode) - if (!inFinished - || ResInfo.is_NonFinishedFrame - || (_state.outSize_Defined && _state.outSize != _state.outProcessed)) - hres = S_FALSE; - } - _hres_Decode = hres; - } -} - -#endif - -}} +// ZstdDecoder.cpp + +#include "StdAfx.h" + +// #include + +#include "../../../C/Alloc.h" + +#include "../Common/CWrappers.h" +#include "../Common/StreamUtils.h" + +#include "ZstdDecoder.h" + +namespace NCompress { +namespace NZstd { + +static const size_t k_Zstd_BlockSizeMax = 1 << 17; +/* + we set _outStepMask as (k_Zstd_BlockSizeMax - 1), because: + - cycSize in zstd decoder for isCyclicMode is aligned for (1 << 17) only. + So some write sizes will be multiple of ((1 << 17) * n). + - Also it can be optimal to flush data after each block decoding. +*/ + +CDecoder::CDecoder(): + _outStepMask(k_Zstd_BlockSizeMax - 1) // must be = (1 << x) - 1 + , _dec(NULL) + , _inProcessed(0) + , _inBufSize(1u << 19) // larger value will reduce the number of memcpy() calls in CZstdDec code + , _inBuf(NULL) + , FinishMode(false) + , DisableHash(False) + // , DisableHash(True) // for debug : fast decoding without hash calculation +{ + // ZstdDecInfo_Clear(&ResInfo); +} + +CDecoder::~CDecoder() +{ + if (_dec) + ZstdDec_Destroy(_dec); + MidFree(_inBuf); +} + + +Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) + { _inBufSize = size; return S_OK; } +Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) +{ + // we round it down: + size >>= 1; + size |= size >> (1 << 0); + size |= size >> (1 << 1); + size |= size >> (1 << 2); + size |= size >> (1 << 3); + size |= size >> (1 << 4); + _outStepMask = size; // it's (1 << x) - 1 now + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte * /* prop */, UInt32 /* size */)) +{ + // if (size != 3 && size != 5) return E_NOTIMPL; + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode)) +{ + FinishMode = (finishMode != 0); + // FinishMode = false; // for debug + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) +{ + size_t cur = ZstdDec_ReadUnusedFromInBuf(_dec, _afterDecoding_tempPos, data, size); + _afterDecoding_tempPos += cur; + size -= (UInt32)cur; + if (size) + { + const size_t rem = _state.inLim - _state.inPos; + if (size > rem) + size = (UInt32)rem; + if (size) + { + memcpy((Byte *)data + cur, _state.inBuf + _state.inPos, size); + _state.inPos += size; + cur += size; + } + } + *processedSize = (UInt32)cur; + return S_OK; +} + + + +HRESULT CDecoder::Prepare(const UInt64 *outSize) +{ + _inProcessed = 0; + _afterDecoding_tempPos = 0; + ZstdDecState_Clear(&_state); + ZstdDecInfo_CLEAR(&ResInfo) + // _state.outStep = _outStepMask + 1; // must be = (1 << x) + _state.disableHash = DisableHash; + if (outSize) + { + _state.outSize_Defined = True; + _state.outSize = *outSize; + // _state.outSize = 0; // for debug + } + if (!_dec) + { + _dec = ZstdDec_Create(&g_AlignedAlloc, &g_BigAlloc); + if (!_dec) + return E_OUTOFMEMORY; + } + if (!_inBuf || _inBufSize != _inBufSize_Allocated) + { + MidFree(_inBuf); + _inBuf = NULL; + _inBufSize_Allocated = 0; + _inBuf = (Byte *)MidAlloc(_inBufSize); + if (!_inBuf) + return E_OUTOFMEMORY; + _inBufSize_Allocated = _inBufSize; + } + _state.inBuf = _inBuf; + ZstdDec_Init(_dec); + return S_OK; +} + + +Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) +{ + RINOK(Prepare(outSize)) + + UInt64 inPrev = 0; + UInt64 outPrev = 0; + UInt64 writtenSize = 0; + bool readWasFinished = false; + SRes sres = SZ_OK; + HRESULT hres = S_OK; + HRESULT hres_Read = S_OK; + + for (;;) + { + if (_state.inPos == _state.inLim && !readWasFinished) + { + _state.inPos = 0; + _state.inLim = _inBufSize; + hres_Read = ReadStream(inStream, _inBuf, &_state.inLim); + // _state.inLim -= 5; readWasFinished = True; // for debug + if (_state.inLim != _inBufSize || hres_Read != S_OK) + { + // hres_Read = 99; // for debug + readWasFinished = True; + } + } + { + const size_t inPos_Start = _state.inPos; + sres = ZstdDec_Decode(_dec, &_state); + _inProcessed += _state.inPos - inPos_Start; + } + /* + if (_state.status == ZSTD_STATUS_FINISHED_FRAME) + printf("\nfinished frame pos=%8x, checksum=%08x\n", (unsigned)_state.outProcessed, (unsigned)_state.info.checksum); + */ + const bool needStop = (sres != SZ_OK) + || _state.status == ZSTD_STATUS_OUT_REACHED + || (outSize && *outSize < _state.outProcessed) + || (readWasFinished && _state.inPos == _state.inLim + && ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(&_state)); + + size_t size = _state.winPos - _state.wrPos; // full write size + if (size) + { + if (!needStop) + { + // we try to flush on aligned positions, if possible + size = _state.needWrite_Size; // minimal required write size + const size_t alignedPos = _state.winPos & ~(size_t)_outStepMask; + if (alignedPos > _state.wrPos) + { + const size_t size2 = alignedPos - _state.wrPos; // optimized aligned size + if (size < size2) + size = size2; + } + } + if (size) + { + { + size_t curSize = size; + if (outSize) + { + const UInt64 rem = *outSize - writtenSize; + if (curSize > rem) + curSize = (size_t)rem; + } + if (curSize) + { + // printf("Write wrPos=%8x, size=%8x\n", (unsigned)_state.wrPos, (unsigned)size); + hres = WriteStream(outStream, _state.win + _state.wrPos, curSize); + if (hres != S_OK) + break; + writtenSize += curSize; // it's real size of data that was written to stream + } + } + _state.wrPos += size; // virtual written size, that will be reported to CZstdDec + // _state.needWrite_Size = 0; // optional + } + } + + if (needStop) + break; + if (progress) + if (_inProcessed - inPrev >= (1 << 27) + || _state.outProcessed - outPrev >= (1 << 28)) + { + inPrev = _inProcessed; + outPrev = _state.outProcessed; + RINOK(progress->SetRatioInfo(&inPrev, &outPrev)) + } + } + + if (hres == S_OK) + { + ZstdDec_GetResInfo(_dec, &_state, sres, &ResInfo); + sres = ResInfo.decode_SRes; + /* now (ResInfo.decode_SRes) can contain 2 extra error codes: + - SZ_ERROR_NO_ARCHIVE : if no frames + - SZ_ERROR_INPUT_EOF : if ZSTD_STATUS_NEEDS_MORE_INPUT + */ + _inProcessed -= ResInfo.extraSize; + if (hres_Read != S_OK && _state.inLim == _state.inPos && readWasFinished) + { + /* if (there is stream reading error, + and decoding was stopped because of end of input stream), + then we use reading error as main error code */ + if (sres == SZ_OK || + sres == SZ_ERROR_INPUT_EOF || + sres == SZ_ERROR_NO_ARCHIVE) + hres = hres_Read; + } + if (sres == SZ_ERROR_INPUT_EOF && !FinishMode) + { + /* SZ_ERROR_INPUT_EOF case is allowed case for (!FinishMode) mode. + So we restore SZ_OK result for that case: */ + ResInfo.decode_SRes = sres = SZ_OK; + } + if (hres == S_OK) + { + hres = SResToHRESULT(sres); + if (hres == S_OK && FinishMode) + { + if ((inSize && *inSize != _inProcessed) + || ResInfo.is_NonFinishedFrame + || (outSize && (*outSize != writtenSize || writtenSize != _state.outProcessed))) + hres = S_FALSE; + } + } + } + return hres; +} + + +Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value)) +{ + *value = _inProcessed; + return S_OK; +} + + +#ifndef Z7_NO_READ_FROM_CODER_ZSTD + +Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize)) +{ + _inProcessed = 0; + _hres_Read = S_OK; + _hres_Decode = S_OK; + _writtenSize = 0; + _readWasFinished = false; + _wasFinished = false; + return Prepare(outSize); +} + + +Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream)) + { _inStream = inStream; return S_OK; } +Z7_COM7F_IMF(CDecoder::ReleaseInStream()) + { _inStream.Release(); return S_OK; } + + +// if SetInStream() mode: the caller must call GetFinishResult() after full decoding +// to check that there decoding was finished correctly + +HRESULT CDecoder::GetFinishResult() +{ + if (_state.winPos != _state.wrPos || !_wasFinished) + return FinishMode ? S_FALSE : S_OK; + // _state.winPos == _state.wrPos + // _wasFinished == true + if (FinishMode && _hres_Decode == S_OK && _state.outSize_Defined && _state.outSize != _writtenSize) + _hres_Decode = S_FALSE; + return _hres_Decode; +} + + +Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + + for (;;) + { + if (_state.outSize_Defined) + { + // _writtenSize <= _state.outSize + const UInt64 rem = _state.outSize - _writtenSize; + if (size > rem) + size = (UInt32)rem; + } + { + size_t cur = _state.winPos - _state.wrPos; + if (cur) + { + // _state.winPos != _state.wrPos; + // so there is some decoded data that was not written still + if (size == 0) + { + // if (FinishMode) and we are not allowed to write more, then it's data error + if (FinishMode && _state.outSize_Defined && _state.outSize == _writtenSize) + return S_FALSE; + return S_OK; + } + if (cur > size) + cur = (size_t)size; + // cur != 0 + memcpy(data, _state.win + _state.wrPos, cur); + _state.wrPos += cur; + _writtenSize += cur; + data = (void *)((Byte *)data + cur); + if (processedSize) + *processedSize += (UInt32)cur; + size -= (UInt32)cur; + continue; + } + } + + // _state.winPos == _state.wrPos + if (_wasFinished) + { + if (_hres_Decode == S_OK && FinishMode + && _state.outSize_Defined && _state.outSize != _writtenSize) + _hres_Decode = S_FALSE; + return _hres_Decode; + } + + // _wasFinished == false + if (size == 0 && _state.outSize_Defined && _state.outSize != _state.outProcessed) + { + /* size == 0 : so the caller don't need more data now. + _state.outSize > _state.outProcessed : so more data will be requested + later by caller for full processing. + So we exit without ZstdDec_Decode() call, because we don't want + ZstdDec_Decode() to start new block decoding + */ + return S_OK; + } + // size != 0 || !_state.outSize_Defined || _state.outSize == _state.outProcessed) + + if (_state.inPos == _state.inLim && !_readWasFinished) + { + _state.inPos = 0; + _state.inLim = _inBufSize; + _hres_Read = ReadStream(_inStream, _inBuf, &_state.inLim); + if (_state.inLim != _inBufSize || _hres_Read != S_OK) + { + // _hres_Read = 99; // for debug + _readWasFinished = True; + } + } + + SRes sres; + { + const SizeT inPos_Start = _state.inPos; + sres = ZstdDec_Decode(_dec, &_state); + _inProcessed += _state.inPos - inPos_Start; + } + + const bool inFinished = (_state.inPos == _state.inLim) && _readWasFinished; + + _wasFinished = (sres != SZ_OK) + || _state.status == ZSTD_STATUS_OUT_REACHED + || (_state.outSize_Defined && _state.outSize < _state.outProcessed) + || (inFinished + && ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(&_state)); + + if (!_wasFinished) + continue; + + // _wasFinished == true + /* (_state.winPos != _state.wrPos) is possible here. + So we still can have some data to flush, + but we must all result variables . + */ + HRESULT hres = S_OK; + ZstdDec_GetResInfo(_dec, &_state, sres, &ResInfo); + sres = ResInfo.decode_SRes; + _inProcessed -= ResInfo.extraSize; + if (_hres_Read != S_OK && inFinished) + { + if (sres == SZ_OK || + sres == SZ_ERROR_INPUT_EOF || + sres == SZ_ERROR_NO_ARCHIVE) + hres = _hres_Read; + } + if (sres == SZ_ERROR_INPUT_EOF && !FinishMode) + ResInfo.decode_SRes = sres = SZ_OK; + if (hres == S_OK) + { + hres = SResToHRESULT(sres); + if (hres == S_OK && FinishMode) + if (!inFinished + || ResInfo.is_NonFinishedFrame + || (_state.outSize_Defined && _state.outSize != _state.outProcessed)) + hres = S_FALSE; + } + _hres_Decode = hres; + } +} + +#endif + +}} diff --git a/CPP/7zip/Compress/ZstdDecoder.h b/CPP/7zip/Compress/ZstdDecoder.h index 61d8dc4ae..6e15a964c 100644 --- a/CPP/7zip/Compress/ZstdDecoder.h +++ b/CPP/7zip/Compress/ZstdDecoder.h @@ -1,98 +1,98 @@ -// ZstdDecoder.h - -#ifndef ZIP7_INC_ZSTD_DECODER_H -#define ZIP7_INC_ZSTD_DECODER_H - -#include "../../../C/ZstdDec.h" - -#include "../../Common/MyCom.h" -#include "../ICoder.h" - -namespace NCompress { -namespace NZstd { - -#ifdef Z7_NO_READ_FROM_CODER -#define Z7_NO_READ_FROM_CODER_ZSTD -#endif - -#ifndef Z7_NO_READ_FROM_CODER_ZSTD -// #define Z7_NO_READ_FROM_CODER_ZSTD -#endif - -class CDecoder Z7_final: - public ICompressCoder, - public ICompressSetDecoderProperties2, - public ICompressSetFinishMode, - public ICompressGetInStreamProcessedSize, - public ICompressReadUnusedFromInBuf, - public ICompressSetBufSize, - #ifndef Z7_NO_READ_FROM_CODER_ZSTD - public ICompressSetInStream, - public ICompressSetOutStreamSize, - public ISequentialInStream, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressCoder) - Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) - Z7_COM_QI_ENTRY(ICompressSetFinishMode) - Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) - Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf) - Z7_COM_QI_ENTRY(ICompressSetBufSize) - #ifndef Z7_NO_READ_FROM_CODER_ZSTD - Z7_COM_QI_ENTRY(ICompressSetInStream) - Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) - Z7_COM_QI_ENTRY(ISequentialInStream) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressCoder) - Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) - Z7_IFACE_COM7_IMP(ICompressSetFinishMode) - Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) - Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf) - Z7_IFACE_COM7_IMP(ICompressSetBufSize) - #ifndef Z7_NO_READ_FROM_CODER_ZSTD - Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) - Z7_IFACE_COM7_IMP(ICompressSetInStream) - Z7_IFACE_COM7_IMP(ISequentialInStream) - #endif - - HRESULT Prepare(const UInt64 *outSize); - - UInt32 _outStepMask; - CZstdDecHandle _dec; -public: - UInt64 _inProcessed; - CZstdDecState _state; - -private: - UInt32 _inBufSize; - UInt32 _inBufSize_Allocated; - Byte *_inBuf; - size_t _afterDecoding_tempPos; - - #ifndef Z7_NO_READ_FROM_CODER_ZSTD - CMyComPtr _inStream; - HRESULT _hres_Read; - HRESULT _hres_Decode; - UInt64 _writtenSize; - bool _readWasFinished; - bool _wasFinished; - #endif - -public: - bool FinishMode; - Byte DisableHash; - CZstdDecResInfo ResInfo; - - HRESULT GetFinishResult(); - - CDecoder(); - ~CDecoder(); -}; - -}} - -#endif +// ZstdDecoder.h + +#ifndef ZIP7_INC_ZSTD_DECODER_H +#define ZIP7_INC_ZSTD_DECODER_H + +#include "../../../C/ZstdDec.h" + +#include "../../Common/MyCom.h" +#include "../ICoder.h" + +namespace NCompress { +namespace NZstd { + +#ifdef Z7_NO_READ_FROM_CODER +#define Z7_NO_READ_FROM_CODER_ZSTD +#endif + +#ifndef Z7_NO_READ_FROM_CODER_ZSTD +// #define Z7_NO_READ_FROM_CODER_ZSTD +#endif + +class CDecoder Z7_final: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public ICompressSetFinishMode, + public ICompressGetInStreamProcessedSize, + public ICompressReadUnusedFromInBuf, + public ICompressSetBufSize, + #ifndef Z7_NO_READ_FROM_CODER_ZSTD + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressCoder) + Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2) + Z7_COM_QI_ENTRY(ICompressSetFinishMode) + Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize) + Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf) + Z7_COM_QI_ENTRY(ICompressSetBufSize) + #ifndef Z7_NO_READ_FROM_CODER_ZSTD + Z7_COM_QI_ENTRY(ICompressSetInStream) + Z7_COM_QI_ENTRY(ICompressSetOutStreamSize) + Z7_COM_QI_ENTRY(ISequentialInStream) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressCoder) + Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) + Z7_IFACE_COM7_IMP(ICompressSetFinishMode) + Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize) + Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf) + Z7_IFACE_COM7_IMP(ICompressSetBufSize) + #ifndef Z7_NO_READ_FROM_CODER_ZSTD + Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize) + Z7_IFACE_COM7_IMP(ICompressSetInStream) + Z7_IFACE_COM7_IMP(ISequentialInStream) + #endif + + HRESULT Prepare(const UInt64 *outSize); + + UInt32 _outStepMask; + CZstdDecHandle _dec; +public: + UInt64 _inProcessed; + CZstdDecState _state; + +private: + UInt32 _inBufSize; + UInt32 _inBufSize_Allocated; + Byte *_inBuf; + size_t _afterDecoding_tempPos; + + #ifndef Z7_NO_READ_FROM_CODER_ZSTD + CMyComPtr _inStream; + HRESULT _hres_Read; + HRESULT _hres_Decode; + UInt64 _writtenSize; + bool _readWasFinished; + bool _wasFinished; + #endif + +public: + bool FinishMode; + Byte DisableHash; + CZstdDecResInfo ResInfo; + + HRESULT GetFinishResult(); + + CDecoder(); + ~CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Compress/makefile b/CPP/7zip/Compress/makefile index 9be1878f0..e981319dd 100644 --- a/CPP/7zip/Compress/makefile +++ b/CPP/7zip/Compress/makefile @@ -1,7 +1,7 @@ -DIRS = \ - LZMA_Alone\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + LZMA_Alone\~ \ + +all: $(DIRS) + +$(DIRS): +!include "../SubBuild.mak" diff --git a/CPP/7zip/Crc.mak b/CPP/7zip/Crc.mak index 2276dafa2..938fc7e97 100644 --- a/CPP/7zip/Crc.mak +++ b/CPP/7zip/Crc.mak @@ -1,8 +1,8 @@ -C_OBJS = $(C_OBJS) \ - $O\7zCrc.obj -!IF defined(USE_NO_ASM) || defined(USE_C_CRC) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" -C_OBJS = $(C_OBJS) \ -!ELSE -ASM_OBJS = $(ASM_OBJS) \ -!ENDIF - $O\7zCrcOpt.obj +C_OBJS = $(C_OBJS) \ + $O\7zCrc.obj +!IF defined(USE_NO_ASM) || defined(USE_C_CRC) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" +C_OBJS = $(C_OBJS) \ +!ELSE +ASM_OBJS = $(ASM_OBJS) \ +!ENDIF + $O\7zCrcOpt.obj diff --git a/CPP/7zip/Crc64.mak b/CPP/7zip/Crc64.mak index de5578837..27a50d7bf 100644 --- a/CPP/7zip/Crc64.mak +++ b/CPP/7zip/Crc64.mak @@ -1,8 +1,8 @@ -C_OBJS = $(C_OBJS) \ - $O\XzCrc64.obj -!IF defined(USE_NO_ASM) || defined(USE_C_CRC64) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" -C_OBJS = $(C_OBJS) \ -!ELSE -ASM_OBJS = $(ASM_OBJS) \ -!ENDIF - $O\XzCrc64Opt.obj +C_OBJS = $(C_OBJS) \ + $O\XzCrc64.obj +!IF defined(USE_NO_ASM) || defined(USE_C_CRC64) || "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" +C_OBJS = $(C_OBJS) \ +!ELSE +ASM_OBJS = $(ASM_OBJS) \ +!ENDIF + $O\XzCrc64Opt.obj diff --git a/CPP/7zip/Crypto/7zAes.cpp b/CPP/7zip/Crypto/7zAes.cpp index 7afca5c6c..b2031050a 100644 --- a/CPP/7zip/Crypto/7zAes.cpp +++ b/CPP/7zip/Crypto/7zAes.cpp @@ -1,315 +1,315 @@ -// 7zAes.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/Sha256.h" - -#include "../../Common/ComTry.h" -#include "../../Common/MyBuffer2.h" - -#ifndef Z7_ST -#include "../../Windows/Synchronization.h" -#endif - -#include "../Common/StreamUtils.h" - -#include "7zAes.h" -#include "MyAes.h" - -#ifndef Z7_EXTRACT_ONLY -#include "RandGen.h" -#endif - -namespace NCrypto { -namespace N7z { - -static const unsigned k_NumCyclesPower_Supported_MAX = 24; - -bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const -{ - if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower) - return false; - for (unsigned i = 0; i < SaltSize; i++) - if (Salt[i] != a.Salt[i]) - return false; - return (Password == a.Password); -} - -void CKeyInfo::CalcKey() -{ - if (NumCyclesPower == 0x3F) - { - unsigned pos; - for (pos = 0; pos < SaltSize; pos++) - Key[pos] = Salt[pos]; - for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++) - Key[pos++] = Password[i]; - for (; pos < kKeySize; pos++) - Key[pos] = 0; - } - else - { - const unsigned kUnrPow = 6; - const UInt32 numUnroll = (UInt32)1 << (NumCyclesPower <= kUnrPow ? (unsigned)NumCyclesPower : kUnrPow); - - const size_t bufSize = 8 + SaltSize + Password.Size(); - const size_t unrollSize = bufSize * numUnroll; - - // MY_ALIGN (16) - // CSha256 sha; - const size_t shaAllocSize = sizeof(CSha256) + unrollSize + bufSize * 2; - CAlignedBuffer1 sha(shaAllocSize); - Byte *buf = sha + sizeof(CSha256); - - memcpy(buf, Salt, SaltSize); - memcpy(buf + SaltSize, Password, Password.Size()); - memset(buf + bufSize - 8, 0, 8); - - Sha256_Init((CSha256 *)(void *)(Byte *)sha); - - { - { - Byte *dest = buf; - for (UInt32 i = 1; i < numUnroll; i++) - { - dest += bufSize; - memcpy(dest, buf, bufSize); - } - } - - const UInt32 numRounds = (UInt32)1 << NumCyclesPower; - UInt32 r = 0; - do - { - Byte *dest = buf + bufSize - 8; - UInt32 i = r; - r += numUnroll; - do - { - SetUi32(dest, i) i++; dest += bufSize; - // SetUi32(dest, i) i++; dest += bufSize; - } - while (i < r); - Sha256_Update((CSha256 *)(void *)(Byte *)sha, buf, unrollSize); - } - while (r < numRounds); - } - /* - UInt64 numRounds = (UInt64)1 << NumCyclesPower; - - do - { - Sha256_Update((CSha256 *)(Byte *)sha, buf, bufSize); - for (unsigned i = 0; i < 8; i++) - if (++(ctr[i]) != 0) - break; - } - while (--numRounds != 0); - */ - - Sha256_Final((CSha256 *)(void *)(Byte *)sha, Key); - memset(sha, 0, shaAllocSize); - } -} - -bool CKeyInfoCache::GetKey(CKeyInfo &key) -{ - FOR_VECTOR (i, Keys) - { - const CKeyInfo &cached = Keys[i]; - if (key.IsEqualTo(cached)) - { - for (unsigned j = 0; j < kKeySize; j++) - key.Key[j] = cached.Key[j]; - if (i != 0) - Keys.MoveToFront(i); - return true; - } - } - return false; -} - -void CKeyInfoCache::FindAndAdd(const CKeyInfo &key) -{ - FOR_VECTOR (i, Keys) - { - const CKeyInfo &cached = Keys[i]; - if (key.IsEqualTo(cached)) - { - if (i != 0) - Keys.MoveToFront(i); - return; - } - } - Add(key); -} - -void CKeyInfoCache::Add(const CKeyInfo &key) -{ - if (Keys.Size() >= Size) - Keys.DeleteBack(); - Keys.Insert(0, key); -} - -static CKeyInfoCache g_GlobalKeyCache(32); - -#ifndef Z7_ST - static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection; - #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection); -#else - #define MT_LOCK -#endif - -CBase::CBase(): - _cachedKeys(16), - _ivSize(0) -{ - for (unsigned i = 0; i < sizeof(_iv); i++) - _iv[i] = 0; -} - -void CBase::PrepareKey() -{ - // BCJ2 threads use same password. So we use long lock. - MT_LOCK - - bool finded = false; - if (!_cachedKeys.GetKey(_key)) - { - finded = g_GlobalKeyCache.GetKey(_key); - if (!finded) - _key.CalcKey(); - _cachedKeys.Add(_key); - } - if (!finded) - g_GlobalKeyCache.FindAndAdd(_key); -} - -#ifndef Z7_EXTRACT_ONLY - -/* -Z7_COM7F_IMF(CEncoder::ResetSalt()) -{ - _key.SaltSize = 4; - g_RandomGenerator.Generate(_key.Salt, _key.SaltSize); - return S_OK; -} -*/ - -Z7_COM7F_IMF(CEncoder::ResetInitVector()) -{ - for (unsigned i = 0; i < sizeof(_iv); i++) - _iv[i] = 0; - _ivSize = 16; - MY_RAND_GEN(_iv, _ivSize); - return S_OK; -} - -Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) -{ - Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)]; - unsigned propsSize = 1; - - props[0] = (Byte)(_key.NumCyclesPower - | (_key.SaltSize == 0 ? 0 : (1 << 7)) - | (_ivSize == 0 ? 0 : (1 << 6))); - - if (_key.SaltSize != 0 || _ivSize != 0) - { - props[1] = (Byte)( - ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4) - | (_ivSize == 0 ? 0 : _ivSize - 1)); - memcpy(props + 2, _key.Salt, _key.SaltSize); - propsSize = 2 + _key.SaltSize; - memcpy(props + propsSize, _iv, _ivSize); - propsSize += _ivSize; - } - - return WriteStream(outStream, props, propsSize); -} - -CEncoder::CEncoder() -{ - // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize); - // _key.NumCyclesPower = 0x3F; - _key.NumCyclesPower = 19; - _aesFilter = new CAesCbcEncoder(kKeySize); -} - -#endif - -CDecoder::CDecoder() -{ - _aesFilter = new CAesCbcDecoder(kKeySize); -} - -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - _key.ClearProps(); - - _ivSize = 0; - unsigned i; - for (i = 0; i < sizeof(_iv); i++) - _iv[i] = 0; - - if (size == 0) - return S_OK; - - const unsigned b0 = data[0]; - _key.NumCyclesPower = b0 & 0x3F; - if ((b0 & 0xC0) == 0) - return size == 1 ? S_OK : E_INVALIDARG; - if (size <= 1) - return E_INVALIDARG; - - const unsigned b1 = data[1]; - const unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4); - const unsigned ivSize = ((b0 >> 6) & 1) + (b1 & 0x0F); - - if (size != 2 + saltSize + ivSize) - return E_INVALIDARG; - _key.SaltSize = saltSize; - data += 2; - for (i = 0; i < saltSize; i++) - _key.Salt[i] = *data++; - for (i = 0; i < ivSize; i++) - _iv[i] = *data++; - return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX - || _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL; -} - - -Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)) -{ - COM_TRY_BEGIN - - _key.Password.Wipe(); - _key.Password.CopyFrom(data, (size_t)size); - return S_OK; - - COM_TRY_END -} - -Z7_COM7F_IMF(CBaseCoder::Init()) -{ - COM_TRY_BEGIN - - PrepareKey(); - CMyComPtr cp; - RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp)) - if (!cp) - return E_FAIL; - RINOK(cp->SetKey(_key.Key, kKeySize)) - RINOK(cp->SetInitVector(_iv, sizeof(_iv))) - return _aesFilter->Init(); - - COM_TRY_END -} - -Z7_COM7F_IMF2(UInt32, CBaseCoder::Filter(Byte *data, UInt32 size)) -{ - return _aesFilter->Filter(data, size); -} - -}} +// 7zAes.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/Sha256.h" + +#include "../../Common/ComTry.h" +#include "../../Common/MyBuffer2.h" + +#ifndef Z7_ST +#include "../../Windows/Synchronization.h" +#endif + +#include "../Common/StreamUtils.h" + +#include "7zAes.h" +#include "MyAes.h" + +#ifndef Z7_EXTRACT_ONLY +#include "RandGen.h" +#endif + +namespace NCrypto { +namespace N7z { + +static const unsigned k_NumCyclesPower_Supported_MAX = 24; + +bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const +{ + if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower) + return false; + for (unsigned i = 0; i < SaltSize; i++) + if (Salt[i] != a.Salt[i]) + return false; + return (Password == a.Password); +} + +void CKeyInfo::CalcKey() +{ + if (NumCyclesPower == 0x3F) + { + unsigned pos; + for (pos = 0; pos < SaltSize; pos++) + Key[pos] = Salt[pos]; + for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++) + Key[pos++] = Password[i]; + for (; pos < kKeySize; pos++) + Key[pos] = 0; + } + else + { + const unsigned kUnrPow = 6; + const UInt32 numUnroll = (UInt32)1 << (NumCyclesPower <= kUnrPow ? (unsigned)NumCyclesPower : kUnrPow); + + const size_t bufSize = 8 + SaltSize + Password.Size(); + const size_t unrollSize = bufSize * numUnroll; + + // MY_ALIGN (16) + // CSha256 sha; + const size_t shaAllocSize = sizeof(CSha256) + unrollSize + bufSize * 2; + CAlignedBuffer1 sha(shaAllocSize); + Byte *buf = sha + sizeof(CSha256); + + memcpy(buf, Salt, SaltSize); + memcpy(buf + SaltSize, Password, Password.Size()); + memset(buf + bufSize - 8, 0, 8); + + Sha256_Init((CSha256 *)(void *)(Byte *)sha); + + { + { + Byte *dest = buf; + for (UInt32 i = 1; i < numUnroll; i++) + { + dest += bufSize; + memcpy(dest, buf, bufSize); + } + } + + const UInt32 numRounds = (UInt32)1 << NumCyclesPower; + UInt32 r = 0; + do + { + Byte *dest = buf + bufSize - 8; + UInt32 i = r; + r += numUnroll; + do + { + SetUi32(dest, i) i++; dest += bufSize; + // SetUi32(dest, i) i++; dest += bufSize; + } + while (i < r); + Sha256_Update((CSha256 *)(void *)(Byte *)sha, buf, unrollSize); + } + while (r < numRounds); + } + /* + UInt64 numRounds = (UInt64)1 << NumCyclesPower; + + do + { + Sha256_Update((CSha256 *)(Byte *)sha, buf, bufSize); + for (unsigned i = 0; i < 8; i++) + if (++(ctr[i]) != 0) + break; + } + while (--numRounds != 0); + */ + + Sha256_Final((CSha256 *)(void *)(Byte *)sha, Key); + memset(sha, 0, shaAllocSize); + } +} + +bool CKeyInfoCache::GetKey(CKeyInfo &key) +{ + FOR_VECTOR (i, Keys) + { + const CKeyInfo &cached = Keys[i]; + if (key.IsEqualTo(cached)) + { + for (unsigned j = 0; j < kKeySize; j++) + key.Key[j] = cached.Key[j]; + if (i != 0) + Keys.MoveToFront(i); + return true; + } + } + return false; +} + +void CKeyInfoCache::FindAndAdd(const CKeyInfo &key) +{ + FOR_VECTOR (i, Keys) + { + const CKeyInfo &cached = Keys[i]; + if (key.IsEqualTo(cached)) + { + if (i != 0) + Keys.MoveToFront(i); + return; + } + } + Add(key); +} + +void CKeyInfoCache::Add(const CKeyInfo &key) +{ + if (Keys.Size() >= Size) + Keys.DeleteBack(); + Keys.Insert(0, key); +} + +static CKeyInfoCache g_GlobalKeyCache(32); + +#ifndef Z7_ST + static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection; + #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection); +#else + #define MT_LOCK +#endif + +CBase::CBase(): + _cachedKeys(16), + _ivSize(0) +{ + for (unsigned i = 0; i < sizeof(_iv); i++) + _iv[i] = 0; +} + +void CBase::PrepareKey() +{ + // BCJ2 threads use same password. So we use long lock. + MT_LOCK + + bool finded = false; + if (!_cachedKeys.GetKey(_key)) + { + finded = g_GlobalKeyCache.GetKey(_key); + if (!finded) + _key.CalcKey(); + _cachedKeys.Add(_key); + } + if (!finded) + g_GlobalKeyCache.FindAndAdd(_key); +} + +#ifndef Z7_EXTRACT_ONLY + +/* +Z7_COM7F_IMF(CEncoder::ResetSalt()) +{ + _key.SaltSize = 4; + g_RandomGenerator.Generate(_key.Salt, _key.SaltSize); + return S_OK; +} +*/ + +Z7_COM7F_IMF(CEncoder::ResetInitVector()) +{ + for (unsigned i = 0; i < sizeof(_iv); i++) + _iv[i] = 0; + _ivSize = 16; + MY_RAND_GEN(_iv, _ivSize); + return S_OK; +} + +Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)) +{ + Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)]; + unsigned propsSize = 1; + + props[0] = (Byte)(_key.NumCyclesPower + | (_key.SaltSize == 0 ? 0 : (1 << 7)) + | (_ivSize == 0 ? 0 : (1 << 6))); + + if (_key.SaltSize != 0 || _ivSize != 0) + { + props[1] = (Byte)( + ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4) + | (_ivSize == 0 ? 0 : _ivSize - 1)); + memcpy(props + 2, _key.Salt, _key.SaltSize); + propsSize = 2 + _key.SaltSize; + memcpy(props + propsSize, _iv, _ivSize); + propsSize += _ivSize; + } + + return WriteStream(outStream, props, propsSize); +} + +CEncoder::CEncoder() +{ + // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize); + // _key.NumCyclesPower = 0x3F; + _key.NumCyclesPower = 19; + _aesFilter = new CAesCbcEncoder(kKeySize); +} + +#endif + +CDecoder::CDecoder() +{ + _aesFilter = new CAesCbcDecoder(kKeySize); +} + +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + _key.ClearProps(); + + _ivSize = 0; + unsigned i; + for (i = 0; i < sizeof(_iv); i++) + _iv[i] = 0; + + if (size == 0) + return S_OK; + + const unsigned b0 = data[0]; + _key.NumCyclesPower = b0 & 0x3F; + if ((b0 & 0xC0) == 0) + return size == 1 ? S_OK : E_INVALIDARG; + if (size <= 1) + return E_INVALIDARG; + + const unsigned b1 = data[1]; + const unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4); + const unsigned ivSize = ((b0 >> 6) & 1) + (b1 & 0x0F); + + if (size != 2 + saltSize + ivSize) + return E_INVALIDARG; + _key.SaltSize = saltSize; + data += 2; + for (i = 0; i < saltSize; i++) + _key.Salt[i] = *data++; + for (i = 0; i < ivSize; i++) + _iv[i] = *data++; + return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX + || _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL; +} + + +Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)) +{ + COM_TRY_BEGIN + + _key.Password.Wipe(); + _key.Password.CopyFrom(data, (size_t)size); + return S_OK; + + COM_TRY_END +} + +Z7_COM7F_IMF(CBaseCoder::Init()) +{ + COM_TRY_BEGIN + + PrepareKey(); + CMyComPtr cp; + RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp)) + if (!cp) + return E_FAIL; + RINOK(cp->SetKey(_key.Key, kKeySize)) + RINOK(cp->SetInitVector(_iv, sizeof(_iv))) + return _aesFilter->Init(); + + COM_TRY_END +} + +Z7_COM7F_IMF2(UInt32, CBaseCoder::Filter(Byte *data, UInt32 size)) +{ + return _aesFilter->Filter(data, size); +} + +}} diff --git a/CPP/7zip/Crypto/7zAes.h b/CPP/7zip/Crypto/7zAes.h index acb4f1ccd..8f7bf03eb 100644 --- a/CPP/7zip/Crypto/7zAes.h +++ b/CPP/7zip/Crypto/7zAes.h @@ -1,130 +1,130 @@ -// 7zAes.h - -#ifndef ZIP7_INC_CRYPTO_7Z_AES_H -#define ZIP7_INC_CRYPTO_7Z_AES_H - -#include "../../Common/MyBuffer.h" -#include "../../Common/MyCom.h" -#include "../../Common/MyVector.h" - -#include "../ICoder.h" -#include "../IPassword.h" - -namespace NCrypto { -namespace N7z { - -const unsigned kKeySize = 32; -const unsigned kSaltSizeMax = 16; -const unsigned kIvSizeMax = 16; // AES_BLOCK_SIZE; - -class CKeyInfo -{ -public: - unsigned NumCyclesPower; - unsigned SaltSize; - Byte Salt[kSaltSizeMax]; - CByteBuffer Password; - Byte Key[kKeySize]; - - bool IsEqualTo(const CKeyInfo &a) const; - void CalcKey(); - - CKeyInfo() { ClearProps(); } - void ClearProps() - { - NumCyclesPower = 0; - SaltSize = 0; - for (unsigned i = 0; i < sizeof(Salt); i++) - Salt[i] = 0; - } - - void Wipe() - { - Password.Wipe(); - NumCyclesPower = 0; - SaltSize = 0; - Z7_memset_0_ARRAY(Salt); - Z7_memset_0_ARRAY(Key); - } - -#ifdef Z7_CPP_IS_SUPPORTED_default - CKeyInfo(const CKeyInfo &) = default; -#endif - ~CKeyInfo() { Wipe(); } -}; - -class CKeyInfoCache -{ - unsigned Size; - CObjectVector Keys; -public: - CKeyInfoCache(unsigned size): Size(size) {} - bool GetKey(CKeyInfo &key); - void Add(const CKeyInfo &key); - void FindAndAdd(const CKeyInfo &key); -}; - -class CBase -{ - CKeyInfoCache _cachedKeys; -protected: - CKeyInfo _key; - Byte _iv[kIvSizeMax]; - unsigned _ivSize; - - void PrepareKey(); - CBase(); -}; - -class CBaseCoder: - public ICompressFilter, - public ICryptoSetPassword, - public CMyUnknownImp, - public CBase -{ - Z7_IFACE_COM7_IMP(ICompressFilter) - Z7_IFACE_COM7_IMP(ICryptoSetPassword) -protected: - virtual ~CBaseCoder() {} - CMyComPtr _aesFilter; -}; - -#ifndef Z7_EXTRACT_ONLY - -class CEncoder Z7_final: - public CBaseCoder, - public ICompressWriteCoderProperties, - // public ICryptoResetSalt, - public ICryptoResetInitVector -{ - Z7_COM_UNKNOWN_IMP_4( - ICompressFilter, - ICryptoSetPassword, - ICompressWriteCoderProperties, - // ICryptoResetSalt, - ICryptoResetInitVector) - Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties) - // Z7_IFACE_COM7_IMP(ICryptoResetSalt) - Z7_IFACE_COM7_IMP(ICryptoResetInitVector) -public: - CEncoder(); -}; - -#endif - -class CDecoder Z7_final: - public CBaseCoder, - public ICompressSetDecoderProperties2 -{ - Z7_COM_UNKNOWN_IMP_3( - ICompressFilter, - ICryptoSetPassword, - ICompressSetDecoderProperties2) - Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) -public: - CDecoder(); -}; - -}} - -#endif +// 7zAes.h + +#ifndef ZIP7_INC_CRYPTO_7Z_AES_H +#define ZIP7_INC_CRYPTO_7Z_AES_H + +#include "../../Common/MyBuffer.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyVector.h" + +#include "../ICoder.h" +#include "../IPassword.h" + +namespace NCrypto { +namespace N7z { + +const unsigned kKeySize = 32; +const unsigned kSaltSizeMax = 16; +const unsigned kIvSizeMax = 16; // AES_BLOCK_SIZE; + +class CKeyInfo +{ +public: + unsigned NumCyclesPower; + unsigned SaltSize; + Byte Salt[kSaltSizeMax]; + CByteBuffer Password; + Byte Key[kKeySize]; + + bool IsEqualTo(const CKeyInfo &a) const; + void CalcKey(); + + CKeyInfo() { ClearProps(); } + void ClearProps() + { + NumCyclesPower = 0; + SaltSize = 0; + for (unsigned i = 0; i < sizeof(Salt); i++) + Salt[i] = 0; + } + + void Wipe() + { + Password.Wipe(); + NumCyclesPower = 0; + SaltSize = 0; + Z7_memset_0_ARRAY(Salt); + Z7_memset_0_ARRAY(Key); + } + +#ifdef Z7_CPP_IS_SUPPORTED_default + CKeyInfo(const CKeyInfo &) = default; +#endif + ~CKeyInfo() { Wipe(); } +}; + +class CKeyInfoCache +{ + unsigned Size; + CObjectVector Keys; +public: + CKeyInfoCache(unsigned size): Size(size) {} + bool GetKey(CKeyInfo &key); + void Add(const CKeyInfo &key); + void FindAndAdd(const CKeyInfo &key); +}; + +class CBase +{ + CKeyInfoCache _cachedKeys; +protected: + CKeyInfo _key; + Byte _iv[kIvSizeMax]; + unsigned _ivSize; + + void PrepareKey(); + CBase(); +}; + +class CBaseCoder: + public ICompressFilter, + public ICryptoSetPassword, + public CMyUnknownImp, + public CBase +{ + Z7_IFACE_COM7_IMP(ICompressFilter) + Z7_IFACE_COM7_IMP(ICryptoSetPassword) +protected: + virtual ~CBaseCoder() {} + CMyComPtr _aesFilter; +}; + +#ifndef Z7_EXTRACT_ONLY + +class CEncoder Z7_final: + public CBaseCoder, + public ICompressWriteCoderProperties, + // public ICryptoResetSalt, + public ICryptoResetInitVector +{ + Z7_COM_UNKNOWN_IMP_4( + ICompressFilter, + ICryptoSetPassword, + ICompressWriteCoderProperties, + // ICryptoResetSalt, + ICryptoResetInitVector) + Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties) + // Z7_IFACE_COM7_IMP(ICryptoResetSalt) + Z7_IFACE_COM7_IMP(ICryptoResetInitVector) +public: + CEncoder(); +}; + +#endif + +class CDecoder Z7_final: + public CBaseCoder, + public ICompressSetDecoderProperties2 +{ + Z7_COM_UNKNOWN_IMP_3( + ICompressFilter, + ICryptoSetPassword, + ICompressSetDecoderProperties2) + Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) +public: + CDecoder(); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/7zAesRegister.cpp b/CPP/7zip/Crypto/7zAesRegister.cpp index 99405585f..69d0890a4 100644 --- a/CPP/7zip/Crypto/7zAesRegister.cpp +++ b/CPP/7zip/Crypto/7zAesRegister.cpp @@ -1,17 +1,17 @@ -// 7zAesRegister.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "7zAes.h" - -namespace NCrypto { -namespace N7z { - -REGISTER_FILTER_E(SzAES, - CDecoder, - CEncoder, - 0x6F10701, "7zAES") - -}} +// 7zAesRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "7zAes.h" + +namespace NCrypto { +namespace N7z { + +REGISTER_FILTER_E(SzAES, + CDecoder, + CEncoder, + 0x6F10701, "7zAES") + +}} diff --git a/CPP/7zip/Crypto/Codec.def b/CPP/7zip/Crypto/Codec.def index aab87ef8e..ebf73a3b8 100644 --- a/CPP/7zip/Crypto/Codec.def +++ b/CPP/7zip/Crypto/Codec.def @@ -1,4 +1,4 @@ -EXPORTS - CreateObject PRIVATE - GetNumberOfMethods PRIVATE - GetMethodProperty PRIVATE +EXPORTS + CreateObject PRIVATE + GetNumberOfMethods PRIVATE + GetMethodProperty PRIVATE diff --git a/CPP/7zip/Crypto/HmacSha1.cpp b/CPP/7zip/Crypto/HmacSha1.cpp index 2c670f583..30b1a8f6f 100644 --- a/CPP/7zip/Crypto/HmacSha1.cpp +++ b/CPP/7zip/Crypto/HmacSha1.cpp @@ -1,94 +1,94 @@ -// HmacSha1.cpp - -#include "StdAfx.h" - -#include - -#include "../../../C/CpuArch.h" - -#include "HmacSha1.h" - -namespace NCrypto { -namespace NSha1 { - -void CHmac::SetKey(const Byte *key, size_t keySize) -{ - MY_ALIGN (16) - UInt32 temp[SHA1_NUM_BLOCK_WORDS]; - size_t i; - - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) - temp[i] = 0; - - if (keySize > kBlockSize) - { - _sha.Init(); - _sha.Update(key, keySize); - _sha.Final((Byte *)temp); - } - else - memcpy(temp, key, keySize); - - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) - temp[i] ^= 0x36363636; - - _sha.Init(); - _sha.Update((const Byte *)temp, kBlockSize); - - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) - temp[i] ^= 0x36363636 ^ 0x5C5C5C5C; - - _sha2.Init(); - _sha2.Update((const Byte *)temp, kBlockSize); -} - - -void CHmac::Final(Byte *mac) -{ - _sha.Final(mac); - _sha2.Update(mac, kDigestSize); - _sha2.Final(mac); -} - - -void CHmac::GetLoopXorDigest1(void *mac, UInt32 numIteration) -{ - MY_ALIGN (16) UInt32 block [SHA1_NUM_BLOCK_WORDS]; - MY_ALIGN (16) UInt32 block2[SHA1_NUM_BLOCK_WORDS]; - MY_ALIGN (16) UInt32 mac2 [SHA1_NUM_BLOCK_WORDS]; - - _sha. PrepareBlock((Byte *)block, SHA1_DIGEST_SIZE); - _sha2.PrepareBlock((Byte *)block2, SHA1_DIGEST_SIZE); - - block[0] = ((const UInt32 *)mac)[0]; - block[1] = ((const UInt32 *)mac)[1]; - block[2] = ((const UInt32 *)mac)[2]; - block[3] = ((const UInt32 *)mac)[3]; - block[4] = ((const UInt32 *)mac)[4]; - - mac2[0] = block[0]; - mac2[1] = block[1]; - mac2[2] = block[2]; - mac2[3] = block[3]; - mac2[4] = block[4]; - - for (UInt32 i = 0; i < numIteration; i++) - { - _sha. GetBlockDigest((const Byte *)block, (Byte *)block2); - _sha2.GetBlockDigest((const Byte *)block2, (Byte *)block); - - mac2[0] ^= block[0]; - mac2[1] ^= block[1]; - mac2[2] ^= block[2]; - mac2[3] ^= block[3]; - mac2[4] ^= block[4]; - } - - ((UInt32 *)mac)[0] = mac2[0]; - ((UInt32 *)mac)[1] = mac2[1]; - ((UInt32 *)mac)[2] = mac2[2]; - ((UInt32 *)mac)[3] = mac2[3]; - ((UInt32 *)mac)[4] = mac2[4]; -} - -}} +// HmacSha1.cpp + +#include "StdAfx.h" + +#include + +#include "../../../C/CpuArch.h" + +#include "HmacSha1.h" + +namespace NCrypto { +namespace NSha1 { + +void CHmac::SetKey(const Byte *key, size_t keySize) +{ + MY_ALIGN (16) + UInt32 temp[SHA1_NUM_BLOCK_WORDS]; + size_t i; + + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) + temp[i] = 0; + + if (keySize > kBlockSize) + { + _sha.Init(); + _sha.Update(key, keySize); + _sha.Final((Byte *)temp); + } + else + memcpy(temp, key, keySize); + + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) + temp[i] ^= 0x36363636; + + _sha.Init(); + _sha.Update((const Byte *)temp, kBlockSize); + + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) + temp[i] ^= 0x36363636 ^ 0x5C5C5C5C; + + _sha2.Init(); + _sha2.Update((const Byte *)temp, kBlockSize); +} + + +void CHmac::Final(Byte *mac) +{ + _sha.Final(mac); + _sha2.Update(mac, kDigestSize); + _sha2.Final(mac); +} + + +void CHmac::GetLoopXorDigest1(void *mac, UInt32 numIteration) +{ + MY_ALIGN (16) UInt32 block [SHA1_NUM_BLOCK_WORDS]; + MY_ALIGN (16) UInt32 block2[SHA1_NUM_BLOCK_WORDS]; + MY_ALIGN (16) UInt32 mac2 [SHA1_NUM_BLOCK_WORDS]; + + _sha. PrepareBlock((Byte *)block, SHA1_DIGEST_SIZE); + _sha2.PrepareBlock((Byte *)block2, SHA1_DIGEST_SIZE); + + block[0] = ((const UInt32 *)mac)[0]; + block[1] = ((const UInt32 *)mac)[1]; + block[2] = ((const UInt32 *)mac)[2]; + block[3] = ((const UInt32 *)mac)[3]; + block[4] = ((const UInt32 *)mac)[4]; + + mac2[0] = block[0]; + mac2[1] = block[1]; + mac2[2] = block[2]; + mac2[3] = block[3]; + mac2[4] = block[4]; + + for (UInt32 i = 0; i < numIteration; i++) + { + _sha. GetBlockDigest((const Byte *)block, (Byte *)block2); + _sha2.GetBlockDigest((const Byte *)block2, (Byte *)block); + + mac2[0] ^= block[0]; + mac2[1] ^= block[1]; + mac2[2] ^= block[2]; + mac2[3] ^= block[3]; + mac2[4] ^= block[4]; + } + + ((UInt32 *)mac)[0] = mac2[0]; + ((UInt32 *)mac)[1] = mac2[1]; + ((UInt32 *)mac)[2] = mac2[2]; + ((UInt32 *)mac)[3] = mac2[3]; + ((UInt32 *)mac)[4] = mac2[4]; +} + +}} diff --git a/CPP/7zip/Crypto/HmacSha1.h b/CPP/7zip/Crypto/HmacSha1.h index a69b81625..a36c78e11 100644 --- a/CPP/7zip/Crypto/HmacSha1.h +++ b/CPP/7zip/Crypto/HmacSha1.h @@ -1,31 +1,31 @@ -// HmacSha1.h -// Implements HMAC-SHA-1 (RFC2104, FIPS-198) - -#ifndef ZIP7_INC_CRYPTO_HMAC_SHA1_H -#define ZIP7_INC_CRYPTO_HMAC_SHA1_H - -#include "Sha1Cls.h" - -namespace NCrypto { -namespace NSha1 { - -// Use: SetKey(key, keySize); for () Update(data, size); FinalFull(mac); - -class CHmac -{ - CContext _sha; - CContext _sha2; -public: - void SetKey(const Byte *key, size_t keySize); - void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); } - - // Final() : mac is recommended to be aligned for 4 bytes - // GetLoopXorDigest1() : mac is required to be aligned for 4 bytes - // The caller can use: UInt32 mac[NSha1::kNumDigestWords] and typecast to (Byte *) and (void *); - void Final(Byte *mac); - void GetLoopXorDigest1(void *mac, UInt32 numIteration); -}; - -}} - -#endif +// HmacSha1.h +// Implements HMAC-SHA-1 (RFC2104, FIPS-198) + +#ifndef ZIP7_INC_CRYPTO_HMAC_SHA1_H +#define ZIP7_INC_CRYPTO_HMAC_SHA1_H + +#include "Sha1Cls.h" + +namespace NCrypto { +namespace NSha1 { + +// Use: SetKey(key, keySize); for () Update(data, size); FinalFull(mac); + +class CHmac +{ + CContext _sha; + CContext _sha2; +public: + void SetKey(const Byte *key, size_t keySize); + void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); } + + // Final() : mac is recommended to be aligned for 4 bytes + // GetLoopXorDigest1() : mac is required to be aligned for 4 bytes + // The caller can use: UInt32 mac[NSha1::kNumDigestWords] and typecast to (Byte *) and (void *); + void Final(Byte *mac); + void GetLoopXorDigest1(void *mac, UInt32 numIteration); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/HmacSha256.cpp b/CPP/7zip/Crypto/HmacSha256.cpp index 7377f42c5..56f8ede19 100644 --- a/CPP/7zip/Crypto/HmacSha256.cpp +++ b/CPP/7zip/Crypto/HmacSha256.cpp @@ -1,53 +1,53 @@ -// HmacSha256.cpp - -#include "StdAfx.h" - -#include - -#include "../../../C/CpuArch.h" - -#include "HmacSha256.h" - -namespace NCrypto { -namespace NSha256 { - -void CHmac::SetKey(const Byte *key, size_t keySize) -{ - MY_ALIGN (16) - UInt32 temp[SHA256_NUM_BLOCK_WORDS]; - size_t i; - - for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++) - temp[i] = 0; - - if (keySize > kBlockSize) - { - Sha256_Init(&_sha); - Sha256_Update(&_sha, key, keySize); - Sha256_Final(&_sha, (Byte *)temp); - } - else - memcpy(temp, key, keySize); - - for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++) - temp[i] ^= 0x36363636; - - Sha256_Init(&_sha); - Sha256_Update(&_sha, (const Byte *)temp, kBlockSize); - - for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++) - temp[i] ^= 0x36363636 ^ 0x5C5C5C5C; - - Sha256_Init(&_sha2); - Sha256_Update(&_sha2, (const Byte *)temp, kBlockSize); -} - - -void CHmac::Final(Byte *mac) -{ - Sha256_Final(&_sha, mac); - Sha256_Update(&_sha2, mac, SHA256_DIGEST_SIZE); - Sha256_Final(&_sha2, mac); -} - -}} +// HmacSha256.cpp + +#include "StdAfx.h" + +#include + +#include "../../../C/CpuArch.h" + +#include "HmacSha256.h" + +namespace NCrypto { +namespace NSha256 { + +void CHmac::SetKey(const Byte *key, size_t keySize) +{ + MY_ALIGN (16) + UInt32 temp[SHA256_NUM_BLOCK_WORDS]; + size_t i; + + for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++) + temp[i] = 0; + + if (keySize > kBlockSize) + { + Sha256_Init(&_sha); + Sha256_Update(&_sha, key, keySize); + Sha256_Final(&_sha, (Byte *)temp); + } + else + memcpy(temp, key, keySize); + + for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++) + temp[i] ^= 0x36363636; + + Sha256_Init(&_sha); + Sha256_Update(&_sha, (const Byte *)temp, kBlockSize); + + for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++) + temp[i] ^= 0x36363636 ^ 0x5C5C5C5C; + + Sha256_Init(&_sha2); + Sha256_Update(&_sha2, (const Byte *)temp, kBlockSize); +} + + +void CHmac::Final(Byte *mac) +{ + Sha256_Final(&_sha, mac); + Sha256_Update(&_sha2, mac, SHA256_DIGEST_SIZE); + Sha256_Final(&_sha2, mac); +} + +}} diff --git a/CPP/7zip/Crypto/HmacSha256.h b/CPP/7zip/Crypto/HmacSha256.h index 8ddac0553..4039c0ced 100644 --- a/CPP/7zip/Crypto/HmacSha256.h +++ b/CPP/7zip/Crypto/HmacSha256.h @@ -1,27 +1,27 @@ -// HmacSha256.h -// Implements HMAC-SHA-256 (RFC2104, FIPS-198) - -#ifndef ZIP7_INC_CRYPTO_HMAC_SHA256_H -#define ZIP7_INC_CRYPTO_HMAC_SHA256_H - -#include "../../../C/Sha256.h" - -namespace NCrypto { -namespace NSha256 { - -const unsigned kBlockSize = SHA256_BLOCK_SIZE; -const unsigned kDigestSize = SHA256_DIGEST_SIZE; - -class CHmac -{ - CSha256 _sha; - CSha256 _sha2; -public: - void SetKey(const Byte *key, size_t keySize); - void Update(const Byte *data, size_t dataSize) { Sha256_Update(&_sha, data, dataSize); } - void Final(Byte *mac); -}; - -}} - -#endif +// HmacSha256.h +// Implements HMAC-SHA-256 (RFC2104, FIPS-198) + +#ifndef ZIP7_INC_CRYPTO_HMAC_SHA256_H +#define ZIP7_INC_CRYPTO_HMAC_SHA256_H + +#include "../../../C/Sha256.h" + +namespace NCrypto { +namespace NSha256 { + +const unsigned kBlockSize = SHA256_BLOCK_SIZE; +const unsigned kDigestSize = SHA256_DIGEST_SIZE; + +class CHmac +{ + CSha256 _sha; + CSha256 _sha2; +public: + void SetKey(const Byte *key, size_t keySize); + void Update(const Byte *data, size_t dataSize) { Sha256_Update(&_sha, data, dataSize); } + void Final(Byte *mac); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp index 1244d444c..f84bca8b1 100644 --- a/CPP/7zip/Crypto/MyAes.cpp +++ b/CPP/7zip/Crypto/MyAes.cpp @@ -1,258 +1,258 @@ -// Crypto/MyAes.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "MyAes.h" - -namespace NCrypto { - -static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit; - -CAesCoder::CAesCoder( - // bool encodeMode, - unsigned keySize - // , bool ctrMode - ): - _keyIsSet(false), - // _encodeMode(encodeMode), - // _ctrMode(ctrMode), - _keySize(keySize), - // _ctrPos(0), // _ctrPos =0 will be set in Init() - _aes(AES_NUM_IVMRK_WORDS * 4 + AES_BLOCK_SIZE * 2) -{ - // _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32); - memset(_iv, 0, AES_BLOCK_SIZE); - /* - // we can use the following code to test 32-bit overflow case for AES-CTR - for (unsigned i = 0; i < 16; i++) _iv[i] = (Byte)(i + 1); - _iv[0] = 0xFE; _iv[1] = _iv[2] = _iv[3] = 0xFF; - */ -} - -Z7_COM7F_IMF(CAesCoder::Init()) -{ - _ctrPos = 0; - AesCbc_Init(Aes(), _iv); - return _keyIsSet ? S_OK : E_NOTIMPL; // E_FAIL -} - -Z7_COM7F_IMF2(UInt32, CAesCoder::Filter(Byte *data, UInt32 size)) -{ - if (!_keyIsSet) - return 0; - if (size < AES_BLOCK_SIZE) - { - if (size == 0) - return 0; - return AES_BLOCK_SIZE; - } - size >>= 4; - // (data) must be aligned for 16-bytes here - _codeFunc(Aes(), data, size); - return size << 4; -} - - -Z7_COM7F_IMF(CAesCoder::SetKey(const Byte *data, UInt32 size)) -{ - if ((size & 0x7) != 0 || size < 16 || size > 32) - return E_INVALIDARG; - if (_keySize != 0 && size != _keySize) - return E_INVALIDARG; - _setKeyFunc(Aes() + 4, data, size); - _keyIsSet = true; - return S_OK; -} - -Z7_COM7F_IMF(CAesCoder::SetInitVector(const Byte *data, UInt32 size)) -{ - if (size != AES_BLOCK_SIZE) - return E_INVALIDARG; - memcpy(_iv, data, size); - /* we allow SetInitVector() call before SetKey() call. - so we ignore possible error in Init() here */ - CAesCoder::Init(); // don't call virtual function here !!! - return S_OK; -} - - -#ifndef Z7_SFX - -/* -Z7_COM7F_IMF(CAesCtrCoder::Init()) -{ - _ctrPos = 0; - return CAesCoder::Init(); -} -*/ - -Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size)) -{ - if (!_keyIsSet) - return 0; - if (size == 0) - return 0; - - if (_ctrPos != 0) - { - /* Optimized caller will not call here */ - const Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS); - unsigned num = 0; - for (unsigned i = _ctrPos; i != AES_BLOCK_SIZE; i++) - { - if (num == size) - { - _ctrPos = i; - return num; - } - data[num++] ^= ctr[i]; - } - _ctrPos = 0; - /* if (num < size) { - we can filter more data with _codeFunc(). - But it's supposed that the caller can work correctly, - even if we do only partial filtering here. - So we filter data only for current 16-byte block. } - */ - /* - size -= num; - size >>= 4; - // (data) must be aligned for 16-bytes here - _codeFunc(Aes(), data + num, size); - return num + (size << 4); - */ - return num; - } - - if (size < AES_BLOCK_SIZE) - { - /* The good optimized caller can call here only in last Filter() call. - But we support also non-optimized callers, - where another Filter() calls are allowed after this call. - */ - Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS); - memset(ctr, 0, AES_BLOCK_SIZE); - memcpy(ctr, data, size); - _codeFunc(Aes(), ctr, 1); - memcpy(data, ctr, size); - _ctrPos = size; - return size; - } - - size >>= 4; - // (data) must be aligned for 16-bytes here - _codeFunc(Aes(), data, size); - return size << 4; -} - -#endif // Z7_SFX - - -#ifndef Z7_EXTRACT_ONLY - -#ifdef MY_CPU_X86_OR_AMD64 - #define USE_HW_AES -#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) - - #if defined(__ARM_FEATURE_AES) \ - || defined(__ARM_FEATURE_CRYPTO) - #define USE_HW_AES - #else - #if defined(MY_CPU_ARM64) \ - || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ - || defined(Z7_MSC_VER_ORIGINAL) - #if defined(__ARM_FP) && \ - ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ - || defined(__GNUC__) && (__GNUC__ >= 6) \ - ) \ - || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) - #if defined(MY_CPU_ARM64) \ - || !defined(Z7_CLANG_VERSION) \ - || defined(__ARM_NEON) && \ - (Z7_CLANG_VERSION < 170000 || \ - Z7_CLANG_VERSION > 170001) - #define USE_HW_AES - #endif - #endif - #endif - #endif -#endif - -#ifdef USE_HW_AES -// #pragma message("=== MyAES.c USE_HW_AES === ") - - #define SET_AES_FUNC_2(f2) \ - if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \ - { f = f2; } - #ifdef MY_CPU_X86_OR_AMD64 - #define SET_AES_FUNC_23(f2, f3) \ - SET_AES_FUNC_2(f2) \ - if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \ - { f = f3; } - #else // MY_CPU_X86_OR_AMD64 - #define SET_AES_FUNC_23(f2, f3) \ - SET_AES_FUNC_2(f2) - #endif // MY_CPU_X86_OR_AMD64 -#else // USE_HW_AES - #define SET_AES_FUNC_23(f2, f3) -#endif // USE_HW_AES - -#define SET_AES_FUNCS(c, f0, f1, f2, f3) \ - bool c::SetFunctions(UInt32 algo) { \ - _codeFunc = f0; if (algo < 1) return true; \ - AES_CODE_FUNC f = NULL; \ - if (algo == 1) { f = f1; } \ - SET_AES_FUNC_23(f2, f3) \ - if (f) { _codeFunc = f; return true; } \ - return false; } - - - -#ifndef Z7_SFX -SET_AES_FUNCS( - CAesCtrCoder, - g_AesCtr_Code, - AesCtr_Code, - AesCtr_Code_HW, - AesCtr_Code_HW_256) -#endif - -SET_AES_FUNCS( - CAesCbcEncoder, - g_AesCbc_Encode, - AesCbc_Encode, - AesCbc_Encode_HW, - AesCbc_Encode_HW) - -SET_AES_FUNCS( - CAesCbcDecoder, - g_AesCbc_Decode, - AesCbc_Decode, - AesCbc_Decode_HW, - AesCbc_Decode_HW_256) - -Z7_COM7F_IMF(CAesCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - UInt32 algo = 0; - for (UInt32 i = 0; i < numProps; i++) - { - if (propIDs[i] == NCoderPropID::kDefaultProp) - { - const PROPVARIANT &prop = coderProps[i]; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - if (prop.ulVal > 3) - return E_NOTIMPL; - algo = prop.ulVal; - } - } - if (!SetFunctions(algo)) - return E_NOTIMPL; - return S_OK; -} - -#endif // Z7_EXTRACT_ONLY - -} +// Crypto/MyAes.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "MyAes.h" + +namespace NCrypto { + +static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit; + +CAesCoder::CAesCoder( + // bool encodeMode, + unsigned keySize + // , bool ctrMode + ): + _keyIsSet(false), + // _encodeMode(encodeMode), + // _ctrMode(ctrMode), + _keySize(keySize), + // _ctrPos(0), // _ctrPos =0 will be set in Init() + _aes(AES_NUM_IVMRK_WORDS * 4 + AES_BLOCK_SIZE * 2) +{ + // _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32); + memset(_iv, 0, AES_BLOCK_SIZE); + /* + // we can use the following code to test 32-bit overflow case for AES-CTR + for (unsigned i = 0; i < 16; i++) _iv[i] = (Byte)(i + 1); + _iv[0] = 0xFE; _iv[1] = _iv[2] = _iv[3] = 0xFF; + */ +} + +Z7_COM7F_IMF(CAesCoder::Init()) +{ + _ctrPos = 0; + AesCbc_Init(Aes(), _iv); + return _keyIsSet ? S_OK : E_NOTIMPL; // E_FAIL +} + +Z7_COM7F_IMF2(UInt32, CAesCoder::Filter(Byte *data, UInt32 size)) +{ + if (!_keyIsSet) + return 0; + if (size < AES_BLOCK_SIZE) + { + if (size == 0) + return 0; + return AES_BLOCK_SIZE; + } + size >>= 4; + // (data) must be aligned for 16-bytes here + _codeFunc(Aes(), data, size); + return size << 4; +} + + +Z7_COM7F_IMF(CAesCoder::SetKey(const Byte *data, UInt32 size)) +{ + if ((size & 0x7) != 0 || size < 16 || size > 32) + return E_INVALIDARG; + if (_keySize != 0 && size != _keySize) + return E_INVALIDARG; + _setKeyFunc(Aes() + 4, data, size); + _keyIsSet = true; + return S_OK; +} + +Z7_COM7F_IMF(CAesCoder::SetInitVector(const Byte *data, UInt32 size)) +{ + if (size != AES_BLOCK_SIZE) + return E_INVALIDARG; + memcpy(_iv, data, size); + /* we allow SetInitVector() call before SetKey() call. + so we ignore possible error in Init() here */ + CAesCoder::Init(); // don't call virtual function here !!! + return S_OK; +} + + +#ifndef Z7_SFX + +/* +Z7_COM7F_IMF(CAesCtrCoder::Init()) +{ + _ctrPos = 0; + return CAesCoder::Init(); +} +*/ + +Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size)) +{ + if (!_keyIsSet) + return 0; + if (size == 0) + return 0; + + if (_ctrPos != 0) + { + /* Optimized caller will not call here */ + const Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS); + unsigned num = 0; + for (unsigned i = _ctrPos; i != AES_BLOCK_SIZE; i++) + { + if (num == size) + { + _ctrPos = i; + return num; + } + data[num++] ^= ctr[i]; + } + _ctrPos = 0; + /* if (num < size) { + we can filter more data with _codeFunc(). + But it's supposed that the caller can work correctly, + even if we do only partial filtering here. + So we filter data only for current 16-byte block. } + */ + /* + size -= num; + size >>= 4; + // (data) must be aligned for 16-bytes here + _codeFunc(Aes(), data + num, size); + return num + (size << 4); + */ + return num; + } + + if (size < AES_BLOCK_SIZE) + { + /* The good optimized caller can call here only in last Filter() call. + But we support also non-optimized callers, + where another Filter() calls are allowed after this call. + */ + Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS); + memset(ctr, 0, AES_BLOCK_SIZE); + memcpy(ctr, data, size); + _codeFunc(Aes(), ctr, 1); + memcpy(data, ctr, size); + _ctrPos = size; + return size; + } + + size >>= 4; + // (data) must be aligned for 16-bytes here + _codeFunc(Aes(), data, size); + return size << 4; +} + +#endif // Z7_SFX + + +#ifndef Z7_EXTRACT_ONLY + +#ifdef MY_CPU_X86_OR_AMD64 + #define USE_HW_AES +#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE) + + #if defined(__ARM_FEATURE_AES) \ + || defined(__ARM_FEATURE_CRYPTO) + #define USE_HW_AES + #else + #if defined(MY_CPU_ARM64) \ + || defined(__ARM_ARCH) && (__ARM_ARCH >= 4) \ + || defined(Z7_MSC_VER_ORIGINAL) + #if defined(__ARM_FP) && \ + ( defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30800) \ + || defined(__GNUC__) && (__GNUC__ >= 6) \ + ) \ + || defined(Z7_MSC_VER_ORIGINAL) && (_MSC_VER >= 1910) + #if defined(MY_CPU_ARM64) \ + || !defined(Z7_CLANG_VERSION) \ + || defined(__ARM_NEON) && \ + (Z7_CLANG_VERSION < 170000 || \ + Z7_CLANG_VERSION > 170001) + #define USE_HW_AES + #endif + #endif + #endif + #endif +#endif + +#ifdef USE_HW_AES +// #pragma message("=== MyAES.c USE_HW_AES === ") + + #define SET_AES_FUNC_2(f2) \ + if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \ + { f = f2; } + #ifdef MY_CPU_X86_OR_AMD64 + #define SET_AES_FUNC_23(f2, f3) \ + SET_AES_FUNC_2(f2) \ + if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \ + { f = f3; } + #else // MY_CPU_X86_OR_AMD64 + #define SET_AES_FUNC_23(f2, f3) \ + SET_AES_FUNC_2(f2) + #endif // MY_CPU_X86_OR_AMD64 +#else // USE_HW_AES + #define SET_AES_FUNC_23(f2, f3) +#endif // USE_HW_AES + +#define SET_AES_FUNCS(c, f0, f1, f2, f3) \ + bool c::SetFunctions(UInt32 algo) { \ + _codeFunc = f0; if (algo < 1) return true; \ + AES_CODE_FUNC f = NULL; \ + if (algo == 1) { f = f1; } \ + SET_AES_FUNC_23(f2, f3) \ + if (f) { _codeFunc = f; return true; } \ + return false; } + + + +#ifndef Z7_SFX +SET_AES_FUNCS( + CAesCtrCoder, + g_AesCtr_Code, + AesCtr_Code, + AesCtr_Code_HW, + AesCtr_Code_HW_256) +#endif + +SET_AES_FUNCS( + CAesCbcEncoder, + g_AesCbc_Encode, + AesCbc_Encode, + AesCbc_Encode_HW, + AesCbc_Encode_HW) + +SET_AES_FUNCS( + CAesCbcDecoder, + g_AesCbc_Decode, + AesCbc_Decode, + AesCbc_Decode_HW, + AesCbc_Decode_HW_256) + +Z7_COM7F_IMF(CAesCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + UInt32 algo = 0; + for (UInt32 i = 0; i < numProps; i++) + { + if (propIDs[i] == NCoderPropID::kDefaultProp) + { + const PROPVARIANT &prop = coderProps[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + if (prop.ulVal > 3) + return E_NOTIMPL; + algo = prop.ulVal; + } + } + if (!SetFunctions(algo)) + return E_NOTIMPL; + return S_OK; +} + +#endif // Z7_EXTRACT_ONLY + +} diff --git a/CPP/7zip/Crypto/MyAes.h b/CPP/7zip/Crypto/MyAes.h index d8706ab23..a3c1c27fa 100644 --- a/CPP/7zip/Crypto/MyAes.h +++ b/CPP/7zip/Crypto/MyAes.h @@ -1,122 +1,122 @@ -// Crypto/MyAes.h - -#ifndef ZIP7_INC_CRYPTO_MY_AES_H -#define ZIP7_INC_CRYPTO_MY_AES_H - -#include "../../../C/Aes.h" - -#include "../../Common/MyBuffer2.h" -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCrypto { - -#ifdef Z7_EXTRACT_ONLY -#define Z7_IFACEN_IAesCoderSetFunctions(x) -#else -#define Z7_IFACEN_IAesCoderSetFunctions(x) \ - virtual bool SetFunctions(UInt32 algo) x -#endif - - -class CAesCoder: - public ICompressFilter, - public ICryptoProperties, - #ifndef Z7_EXTRACT_ONLY - public ICompressSetCoderProperties, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(ICompressFilter) - Z7_COM_QI_ENTRY(ICryptoProperties) - #ifndef Z7_EXTRACT_ONLY - Z7_COM_QI_ENTRY(ICompressSetCoderProperties) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - -public: - Z7_IFACE_COM7_IMP_NONFINAL(ICompressFilter) - Z7_IFACE_COM7_IMP(ICryptoProperties) -private: - #ifndef Z7_EXTRACT_ONLY - Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) - #endif - -protected: - bool _keyIsSet; - // bool _encodeMode; - // bool _ctrMode; - // unsigned _offset; - unsigned _keySize; - unsigned _ctrPos; // we need _ctrPos here for Init() / SetInitVector() - AES_CODE_FUNC _codeFunc; - AES_SET_KEY_FUNC _setKeyFunc; -private: - // UInt32 _aes[AES_NUM_IVMRK_WORDS + 3]; - CAlignedBuffer1 _aes; - - Byte _iv[AES_BLOCK_SIZE]; - - // UInt32 *Aes() { return _aes + _offset; } -protected: - UInt32 *Aes() { return (UInt32 *)(void *)(Byte *)_aes; } - - Z7_IFACE_PURE(IAesCoderSetFunctions) - -public: - CAesCoder( - // bool encodeMode, - unsigned keySize - // , bool ctrMode - ); - virtual ~CAesCoder() {} // we need virtual destructor for derived classes - void SetKeySize(unsigned size) { _keySize = size; } -}; - - -#ifndef Z7_EXTRACT_ONLY -struct CAesCbcEncoder: public CAesCoder -{ - CAesCbcEncoder(unsigned keySize = 0): CAesCoder(keySize) - { - _setKeyFunc = Aes_SetKey_Enc; - _codeFunc = g_AesCbc_Encode; - } - Z7_IFACE_IMP(IAesCoderSetFunctions) -}; -#endif - -struct CAesCbcDecoder: public CAesCoder -{ - CAesCbcDecoder(unsigned keySize = 0): CAesCoder(keySize) - { - _setKeyFunc = Aes_SetKey_Dec; - _codeFunc = g_AesCbc_Decode; - } - Z7_IFACE_IMP(IAesCoderSetFunctions) -}; - -#ifndef Z7_SFX -struct CAesCtrCoder: public CAesCoder -{ -private: - // unsigned _ctrPos; - // Z7_IFACE_COM7_IMP(ICompressFilter) - // Z7_COM7F_IMP(Init()) - Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) -public: - CAesCtrCoder(unsigned keySize = 0): CAesCoder(keySize) - { - _ctrPos = 0; - _setKeyFunc = Aes_SetKey_Enc; - _codeFunc = g_AesCtr_Code; - } - Z7_IFACE_IMP(IAesCoderSetFunctions) -}; -#endif - -} - -#endif +// Crypto/MyAes.h + +#ifndef ZIP7_INC_CRYPTO_MY_AES_H +#define ZIP7_INC_CRYPTO_MY_AES_H + +#include "../../../C/Aes.h" + +#include "../../Common/MyBuffer2.h" +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCrypto { + +#ifdef Z7_EXTRACT_ONLY +#define Z7_IFACEN_IAesCoderSetFunctions(x) +#else +#define Z7_IFACEN_IAesCoderSetFunctions(x) \ + virtual bool SetFunctions(UInt32 algo) x +#endif + + +class CAesCoder: + public ICompressFilter, + public ICryptoProperties, + #ifndef Z7_EXTRACT_ONLY + public ICompressSetCoderProperties, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(ICompressFilter) + Z7_COM_QI_ENTRY(ICryptoProperties) + #ifndef Z7_EXTRACT_ONLY + Z7_COM_QI_ENTRY(ICompressSetCoderProperties) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + +public: + Z7_IFACE_COM7_IMP_NONFINAL(ICompressFilter) + Z7_IFACE_COM7_IMP(ICryptoProperties) +private: + #ifndef Z7_EXTRACT_ONLY + Z7_IFACE_COM7_IMP(ICompressSetCoderProperties) + #endif + +protected: + bool _keyIsSet; + // bool _encodeMode; + // bool _ctrMode; + // unsigned _offset; + unsigned _keySize; + unsigned _ctrPos; // we need _ctrPos here for Init() / SetInitVector() + AES_CODE_FUNC _codeFunc; + AES_SET_KEY_FUNC _setKeyFunc; +private: + // UInt32 _aes[AES_NUM_IVMRK_WORDS + 3]; + CAlignedBuffer1 _aes; + + Byte _iv[AES_BLOCK_SIZE]; + + // UInt32 *Aes() { return _aes + _offset; } +protected: + UInt32 *Aes() { return (UInt32 *)(void *)(Byte *)_aes; } + + Z7_IFACE_PURE(IAesCoderSetFunctions) + +public: + CAesCoder( + // bool encodeMode, + unsigned keySize + // , bool ctrMode + ); + virtual ~CAesCoder() {} // we need virtual destructor for derived classes + void SetKeySize(unsigned size) { _keySize = size; } +}; + + +#ifndef Z7_EXTRACT_ONLY +struct CAesCbcEncoder: public CAesCoder +{ + CAesCbcEncoder(unsigned keySize = 0): CAesCoder(keySize) + { + _setKeyFunc = Aes_SetKey_Enc; + _codeFunc = g_AesCbc_Encode; + } + Z7_IFACE_IMP(IAesCoderSetFunctions) +}; +#endif + +struct CAesCbcDecoder: public CAesCoder +{ + CAesCbcDecoder(unsigned keySize = 0): CAesCoder(keySize) + { + _setKeyFunc = Aes_SetKey_Dec; + _codeFunc = g_AesCbc_Decode; + } + Z7_IFACE_IMP(IAesCoderSetFunctions) +}; + +#ifndef Z7_SFX +struct CAesCtrCoder: public CAesCoder +{ +private: + // unsigned _ctrPos; + // Z7_IFACE_COM7_IMP(ICompressFilter) + // Z7_COM7F_IMP(Init()) + Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) +public: + CAesCtrCoder(unsigned keySize = 0): CAesCoder(keySize) + { + _ctrPos = 0; + _setKeyFunc = Aes_SetKey_Enc; + _codeFunc = g_AesCtr_Code; + } + Z7_IFACE_IMP(IAesCoderSetFunctions) +}; +#endif + +} + +#endif diff --git a/CPP/7zip/Crypto/MyAesReg.cpp b/CPP/7zip/Crypto/MyAesReg.cpp index 891ec19ab..e2b4f72db 100644 --- a/CPP/7zip/Crypto/MyAesReg.cpp +++ b/CPP/7zip/Crypto/MyAesReg.cpp @@ -1,29 +1,29 @@ -// MyAesReg.cpp - -#include "StdAfx.h" - -#include "../Common/RegisterCodec.h" - -#include "MyAes.h" - -namespace NCrypto { - -#ifndef Z7_SFX - -#define REGISTER_AES_2(name, nameString, keySize) \ - REGISTER_FILTER_E(name, \ - CAesCbcDecoder(keySize), \ - CAesCbcEncoder(keySize), \ - 0x6F00100 | ((keySize - 16) * 8) | (/* isCtr */ 0 ? 4 : 1), \ - nameString) \ - -#define REGISTER_AES(name, nameString) \ - /* REGISTER_AES_2(AES128 ## name, "AES128" nameString, 16) */ \ - /* REGISTER_AES_2(AES192 ## name, "AES192" nameString, 24) */ \ - REGISTER_AES_2(AES256 ## name, "AES256" nameString, 32) \ - -REGISTER_AES(CBC, "CBC") - -#endif - -} +// MyAesReg.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "MyAes.h" + +namespace NCrypto { + +#ifndef Z7_SFX + +#define REGISTER_AES_2(name, nameString, keySize) \ + REGISTER_FILTER_E(name, \ + CAesCbcDecoder(keySize), \ + CAesCbcEncoder(keySize), \ + 0x6F00100 | ((keySize - 16) * 8) | (/* isCtr */ 0 ? 4 : 1), \ + nameString) \ + +#define REGISTER_AES(name, nameString) \ + /* REGISTER_AES_2(AES128 ## name, "AES128" nameString, 16) */ \ + /* REGISTER_AES_2(AES192 ## name, "AES192" nameString, 24) */ \ + REGISTER_AES_2(AES256 ## name, "AES256" nameString, 32) \ + +REGISTER_AES(CBC, "CBC") + +#endif + +} diff --git a/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp index f0c5cad05..3d9e4c1a8 100644 --- a/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp +++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp @@ -1,48 +1,48 @@ -// Pbkdf2HmacSha1.cpp - -#include "StdAfx.h" - -#include - -#include "../../../C/CpuArch.h" - -#include "HmacSha1.h" -#include "Pbkdf2HmacSha1.h" - -namespace NCrypto { -namespace NSha1 { - -void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, - const Byte *salt, size_t saltSize, - UInt32 numIterations, - Byte *key, size_t keySize) -{ - MY_ALIGN (16) - CHmac baseCtx; - baseCtx.SetKey(pwd, pwdSize); - - for (UInt32 i = 1; keySize != 0; i++) - { - MY_ALIGN (16) - CHmac ctx; - ctx = baseCtx; - ctx.Update(salt, saltSize); - - MY_ALIGN (16) - UInt32 u[kNumDigestWords]; - SetBe32(u, i) - - ctx.Update((const Byte *)u, 4); - ctx.Final((Byte *)u); - - ctx = baseCtx; - ctx.GetLoopXorDigest1((void *)u, numIterations - 1); - - const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize; - memcpy(key, (const Byte *)u, curSize); - key += curSize; - keySize -= curSize; - } -} - -}} +// Pbkdf2HmacSha1.cpp + +#include "StdAfx.h" + +#include + +#include "../../../C/CpuArch.h" + +#include "HmacSha1.h" +#include "Pbkdf2HmacSha1.h" + +namespace NCrypto { +namespace NSha1 { + +void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, + const Byte *salt, size_t saltSize, + UInt32 numIterations, + Byte *key, size_t keySize) +{ + MY_ALIGN (16) + CHmac baseCtx; + baseCtx.SetKey(pwd, pwdSize); + + for (UInt32 i = 1; keySize != 0; i++) + { + MY_ALIGN (16) + CHmac ctx; + ctx = baseCtx; + ctx.Update(salt, saltSize); + + MY_ALIGN (16) + UInt32 u[kNumDigestWords]; + SetBe32(u, i) + + ctx.Update((const Byte *)u, 4); + ctx.Final((Byte *)u); + + ctx = baseCtx; + ctx.GetLoopXorDigest1((void *)u, numIterations - 1); + + const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize; + memcpy(key, (const Byte *)u, curSize); + key += curSize; + keySize -= curSize; + } +} + +}} diff --git a/CPP/7zip/Crypto/Pbkdf2HmacSha1.h b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h index a128989db..89cbe4149 100644 --- a/CPP/7zip/Crypto/Pbkdf2HmacSha1.h +++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h @@ -1,19 +1,19 @@ -// Pbkdf2HmacSha1.h -// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1 - -#ifndef ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H -#define ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H - -#include - -#include "../../Common/MyTypes.h" - -namespace NCrypto { -namespace NSha1 { - -void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize, - UInt32 numIterations, Byte *key, size_t keySize); - -}} - -#endif +// Pbkdf2HmacSha1.h +// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1 + +#ifndef ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H +#define ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H + +#include + +#include "../../Common/MyTypes.h" + +namespace NCrypto { +namespace NSha1 { + +void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize, + UInt32 numIterations, Byte *key, size_t keySize); + +}} + +#endif diff --git a/CPP/7zip/Crypto/RandGen.cpp b/CPP/7zip/Crypto/RandGen.cpp index 40644cb90..05a6c06d4 100644 --- a/CPP/7zip/Crypto/RandGen.cpp +++ b/CPP/7zip/Crypto/RandGen.cpp @@ -1,241 +1,241 @@ -// RandGen.cpp - -#include "StdAfx.h" - -#include "RandGen.h" - -#ifndef USE_STATIC_SYSTEM_RAND - -#ifndef Z7_ST -#include "../../Windows/Synchronization.h" -#endif - - -#ifdef _WIN32 - -#ifdef _WIN64 -#define USE_STATIC_RtlGenRandom -#endif - -#ifdef USE_STATIC_RtlGenRandom - -// #include - -EXTERN_C_BEGIN -#ifndef RtlGenRandom - #define RtlGenRandom SystemFunction036 - BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); -#endif -EXTERN_C_END - -#else -EXTERN_C_BEGIN -typedef BOOLEAN (WINAPI * Func_RtlGenRandom)(PVOID RandomBuffer, ULONG RandomBufferLength); -EXTERN_C_END -#endif - - -#else -#include -#include -#include -#include -#define USE_POSIX_TIME -#define USE_POSIX_TIME2 -#endif - -#ifdef USE_POSIX_TIME -#include -#ifdef USE_POSIX_TIME2 -#include -#endif -#endif - -// The seed and first generated data block depend from processID, -// theadID, timer and system random generator, if available. -// Other generated data blocks depend from previous state - -#define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x)); - -void CRandomGenerator::Init() -{ - MY_ALIGN (16) - CSha256 hash; - Sha256_Init(&hash); - - unsigned numIterations = 1000; - - { - #ifndef UNDER_CE - const unsigned kNumIterations_Small = 100; - const unsigned kBufSize = 32; - MY_ALIGN (16) - Byte buf[kBufSize]; - #endif - - #ifdef _WIN32 - - DWORD w = ::GetCurrentProcessId(); - HASH_UPD(w) - w = ::GetCurrentThreadId(); - HASH_UPD(w) - - #ifdef UNDER_CE - /* - if (CeGenRandom(kBufSize, buf)) - { - numIterations = kNumIterations_Small; - Sha256_Update(&hash, buf, kBufSize); - } - */ - #elif defined(USE_STATIC_RtlGenRandom) - if (RtlGenRandom(buf, kBufSize)) - { - numIterations = kNumIterations_Small; - Sha256_Update(&hash, buf, kBufSize); - } - #else - { - const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll")); - if (hModule) - { - // SystemFunction036() is real name of RtlGenRandom() function - const - Func_RtlGenRandom - my_RtlGenRandom = Z7_GET_PROC_ADDRESS( - Func_RtlGenRandom, hModule, "SystemFunction036"); - if (my_RtlGenRandom) - { - if (my_RtlGenRandom(buf, kBufSize)) - { - numIterations = kNumIterations_Small; - Sha256_Update(&hash, buf, kBufSize); - } - } - ::FreeLibrary(hModule); - } - } - #endif - - #else - - pid_t pid = getpid(); - HASH_UPD(pid) - pid = getppid(); - HASH_UPD(pid) - - { - int f = open("/dev/urandom", O_RDONLY); - unsigned numBytes = kBufSize; - if (f >= 0) - { - do - { - ssize_t n = read(f, buf, numBytes); - if (n <= 0) - break; - Sha256_Update(&hash, buf, (size_t)n); - numBytes -= (unsigned)n; - } - while (numBytes); - close(f); - if (numBytes == 0) - numIterations = kNumIterations_Small; - } - } - /* - { - int n = getrandom(buf, kBufSize, 0); - if (n > 0) - { - Sha256_Update(&hash, buf, n); - if (n == kBufSize) - numIterations = kNumIterations_Small; - } - } - */ - - #endif - } - - #ifdef _DEBUG - numIterations = 2; - #endif - - do - { - #ifdef _WIN32 - LARGE_INTEGER v; - if (::QueryPerformanceCounter(&v)) - HASH_UPD(v.QuadPart) - #endif - - #ifdef USE_POSIX_TIME - #ifdef USE_POSIX_TIME2 - timeval v; - if (gettimeofday(&v, NULL) == 0) - { - HASH_UPD(v.tv_sec) - HASH_UPD(v.tv_usec) - } - #endif - const time_t v2 = time(NULL); - HASH_UPD(v2) - #endif - - #ifdef _WIN32 - const DWORD tickCount = ::GetTickCount(); - HASH_UPD(tickCount) - #endif - - for (unsigned j = 0; j < 100; j++) - { - Sha256_Final(&hash, _buff); - Sha256_Init(&hash); - Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE); - } - } - while (--numIterations); - - Sha256_Final(&hash, _buff); - _needInit = false; -} - -#ifndef Z7_ST - static NWindows::NSynchronization::CCriticalSection g_CriticalSection; - #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else - #define MT_LOCK -#endif - -void CRandomGenerator::Generate(Byte *data, unsigned size) -{ - MT_LOCK - - if (_needInit) - Init(); - while (size != 0) - { - MY_ALIGN (16) - CSha256 hash; - - Sha256_Init(&hash); - Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE); - Sha256_Final(&hash, _buff); - - Sha256_Init(&hash); - UInt32 salt = 0xF672ABD1; - HASH_UPD(salt) - Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE); - MY_ALIGN (16) - Byte buff[SHA256_DIGEST_SIZE]; - Sha256_Final(&hash, buff); - for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--) - *data++ = buff[i]; - } -} - -MY_ALIGN (16) -CRandomGenerator g_RandomGenerator; - -#endif +// RandGen.cpp + +#include "StdAfx.h" + +#include "RandGen.h" + +#ifndef USE_STATIC_SYSTEM_RAND + +#ifndef Z7_ST +#include "../../Windows/Synchronization.h" +#endif + + +#ifdef _WIN32 + +#ifdef _WIN64 +#define USE_STATIC_RtlGenRandom +#endif + +#ifdef USE_STATIC_RtlGenRandom + +// #include + +EXTERN_C_BEGIN +#ifndef RtlGenRandom + #define RtlGenRandom SystemFunction036 + BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +#endif +EXTERN_C_END + +#else +EXTERN_C_BEGIN +typedef BOOLEAN (WINAPI * Func_RtlGenRandom)(PVOID RandomBuffer, ULONG RandomBufferLength); +EXTERN_C_END +#endif + + +#else +#include +#include +#include +#include +#define USE_POSIX_TIME +#define USE_POSIX_TIME2 +#endif + +#ifdef USE_POSIX_TIME +#include +#ifdef USE_POSIX_TIME2 +#include +#endif +#endif + +// The seed and first generated data block depend from processID, +// theadID, timer and system random generator, if available. +// Other generated data blocks depend from previous state + +#define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x)); + +void CRandomGenerator::Init() +{ + MY_ALIGN (16) + CSha256 hash; + Sha256_Init(&hash); + + unsigned numIterations = 1000; + + { + #ifndef UNDER_CE + const unsigned kNumIterations_Small = 100; + const unsigned kBufSize = 32; + MY_ALIGN (16) + Byte buf[kBufSize]; + #endif + + #ifdef _WIN32 + + DWORD w = ::GetCurrentProcessId(); + HASH_UPD(w) + w = ::GetCurrentThreadId(); + HASH_UPD(w) + + #ifdef UNDER_CE + /* + if (CeGenRandom(kBufSize, buf)) + { + numIterations = kNumIterations_Small; + Sha256_Update(&hash, buf, kBufSize); + } + */ + #elif defined(USE_STATIC_RtlGenRandom) + if (RtlGenRandom(buf, kBufSize)) + { + numIterations = kNumIterations_Small; + Sha256_Update(&hash, buf, kBufSize); + } + #else + { + const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll")); + if (hModule) + { + // SystemFunction036() is real name of RtlGenRandom() function + const + Func_RtlGenRandom + my_RtlGenRandom = Z7_GET_PROC_ADDRESS( + Func_RtlGenRandom, hModule, "SystemFunction036"); + if (my_RtlGenRandom) + { + if (my_RtlGenRandom(buf, kBufSize)) + { + numIterations = kNumIterations_Small; + Sha256_Update(&hash, buf, kBufSize); + } + } + ::FreeLibrary(hModule); + } + } + #endif + + #else + + pid_t pid = getpid(); + HASH_UPD(pid) + pid = getppid(); + HASH_UPD(pid) + + { + int f = open("/dev/urandom", O_RDONLY); + unsigned numBytes = kBufSize; + if (f >= 0) + { + do + { + ssize_t n = read(f, buf, numBytes); + if (n <= 0) + break; + Sha256_Update(&hash, buf, (size_t)n); + numBytes -= (unsigned)n; + } + while (numBytes); + close(f); + if (numBytes == 0) + numIterations = kNumIterations_Small; + } + } + /* + { + int n = getrandom(buf, kBufSize, 0); + if (n > 0) + { + Sha256_Update(&hash, buf, n); + if (n == kBufSize) + numIterations = kNumIterations_Small; + } + } + */ + + #endif + } + + #ifdef _DEBUG + numIterations = 2; + #endif + + do + { + #ifdef _WIN32 + LARGE_INTEGER v; + if (::QueryPerformanceCounter(&v)) + HASH_UPD(v.QuadPart) + #endif + + #ifdef USE_POSIX_TIME + #ifdef USE_POSIX_TIME2 + timeval v; + if (gettimeofday(&v, NULL) == 0) + { + HASH_UPD(v.tv_sec) + HASH_UPD(v.tv_usec) + } + #endif + const time_t v2 = time(NULL); + HASH_UPD(v2) + #endif + + #ifdef _WIN32 + const DWORD tickCount = ::GetTickCount(); + HASH_UPD(tickCount) + #endif + + for (unsigned j = 0; j < 100; j++) + { + Sha256_Final(&hash, _buff); + Sha256_Init(&hash); + Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE); + } + } + while (--numIterations); + + Sha256_Final(&hash, _buff); + _needInit = false; +} + +#ifndef Z7_ST + static NWindows::NSynchronization::CCriticalSection g_CriticalSection; + #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else + #define MT_LOCK +#endif + +void CRandomGenerator::Generate(Byte *data, unsigned size) +{ + MT_LOCK + + if (_needInit) + Init(); + while (size != 0) + { + MY_ALIGN (16) + CSha256 hash; + + Sha256_Init(&hash); + Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE); + Sha256_Final(&hash, _buff); + + Sha256_Init(&hash); + UInt32 salt = 0xF672ABD1; + HASH_UPD(salt) + Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE); + MY_ALIGN (16) + Byte buff[SHA256_DIGEST_SIZE]; + Sha256_Final(&hash, buff); + for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--) + *data++ = buff[i]; + } +} + +MY_ALIGN (16) +CRandomGenerator g_RandomGenerator; + +#endif diff --git a/CPP/7zip/Crypto/RandGen.h b/CPP/7zip/Crypto/RandGen.h index d3981fd5b..3bd69ec2d 100644 --- a/CPP/7zip/Crypto/RandGen.h +++ b/CPP/7zip/Crypto/RandGen.h @@ -1,41 +1,41 @@ -// RandGen.h - -#ifndef ZIP7_INC_CRYPTO_RAND_GEN_H -#define ZIP7_INC_CRYPTO_RAND_GEN_H - -#include "../../../C/Sha256.h" - -#ifdef _WIN64 -// #define USE_STATIC_SYSTEM_RAND -#endif - -#ifdef USE_STATIC_SYSTEM_RAND - -#ifdef _WIN32 -#include -#define MY_RAND_GEN(data, size) RtlGenRandom(data, size) -#else -#define MY_RAND_GEN(data, size) getrandom(data, size, 0) -#endif - -#else - -class CRandomGenerator -{ - Byte _buff[SHA256_DIGEST_SIZE]; - bool _needInit; - - void Init(); -public: - CRandomGenerator(): _needInit(true) {} - void Generate(Byte *data, unsigned size); -}; - -MY_ALIGN (16) -extern CRandomGenerator g_RandomGenerator; - -#define MY_RAND_GEN(data, size) g_RandomGenerator.Generate(data, size) - -#endif - -#endif +// RandGen.h + +#ifndef ZIP7_INC_CRYPTO_RAND_GEN_H +#define ZIP7_INC_CRYPTO_RAND_GEN_H + +#include "../../../C/Sha256.h" + +#ifdef _WIN64 +// #define USE_STATIC_SYSTEM_RAND +#endif + +#ifdef USE_STATIC_SYSTEM_RAND + +#ifdef _WIN32 +#include +#define MY_RAND_GEN(data, size) RtlGenRandom(data, size) +#else +#define MY_RAND_GEN(data, size) getrandom(data, size, 0) +#endif + +#else + +class CRandomGenerator +{ + Byte _buff[SHA256_DIGEST_SIZE]; + bool _needInit; + + void Init(); +public: + CRandomGenerator(): _needInit(true) {} + void Generate(Byte *data, unsigned size); +}; + +MY_ALIGN (16) +extern CRandomGenerator g_RandomGenerator; + +#define MY_RAND_GEN(data, size) g_RandomGenerator.Generate(data, size) + +#endif + +#endif diff --git a/CPP/7zip/Crypto/Rar20Crypto.cpp b/CPP/7zip/Crypto/Rar20Crypto.cpp index 40944a5c9..8e55763c6 100644 --- a/CPP/7zip/Crypto/Rar20Crypto.cpp +++ b/CPP/7zip/Crypto/Rar20Crypto.cpp @@ -1,130 +1,130 @@ -// Crypto/Rar20Crypto.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" -#include "../../../C/CpuArch.h" -#include "../../../C/RotateDefs.h" - -#include "Rar20Crypto.h" - -namespace NCrypto { -namespace NRar2 { - -static const unsigned kNumRounds = 32; - -static const Byte g_InitSubstTable[256] = { - 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42, - 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137, - 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6, - 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235, - 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36, - 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251, - 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11, - 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51, - 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7, - 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80, - 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129, - 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10, - 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108, - 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225, - 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52, - 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84 -}; - -void CData::UpdateKeys(const Byte *data) -{ - for (unsigned i = 0; i < 16; i += 4) - for (unsigned j = 0; j < 4; j++) - Keys[j] ^= g_CrcTable[data[i + j]]; -} - -static inline void Swap(Byte &b1, Byte &b2) -{ - Byte b = b1; - b1 = b2; - b2 = b; -} - -void CData::SetPassword(const Byte *data, unsigned size) -{ - Keys[0] = 0xD3A3B879L; - Keys[1] = 0x3F6D12F7L; - Keys[2] = 0x7515A235L; - Keys[3] = 0xA4E7F123L; - - Byte psw[128]; - Z7_memset_0_ARRAY(psw); - if (size != 0) - { - if (size >= sizeof(psw)) - size = sizeof(psw) - 1; - memcpy(psw, data, size); - } - - memcpy(SubstTable, g_InitSubstTable, sizeof(SubstTable)); - - for (unsigned j = 0; j < 256; j++) - for (unsigned i = 0; i < size; i += 2) - { - unsigned n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF]; - unsigned n2 = (Byte)g_CrcTable[(psw[(size_t)i + 1] + j) & 0xFF]; - for (unsigned k = 1; (n1 & 0xFF) != n2; n1++, k++) - Swap(SubstTable[n1 & 0xFF], SubstTable[(n1 + i + k) & 0xFF]); - } - - for (unsigned i = 0; i < size; i += 16) - EncryptBlock(psw + i); -} - -void CData::CryptBlock(Byte *buf, bool encrypt) -{ - Byte inBuf[16]; - UInt32 A, B, C, D; - - A = GetUi32(buf + 0) ^ Keys[0]; - B = GetUi32(buf + 4) ^ Keys[1]; - C = GetUi32(buf + 8) ^ Keys[2]; - D = GetUi32(buf + 12) ^ Keys[3]; - - if (!encrypt) - memcpy(inBuf, buf, sizeof(inBuf)); - - for (unsigned i = 0; i < kNumRounds; i++) - { - UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3]; - UInt32 TA = A ^ SubstLong((C + rotlFixed(D, 11)) ^ key); - UInt32 TB = B ^ SubstLong((D ^ rotlFixed(C, 17)) + key); - A = C; C = TA; - B = D; D = TB; - } - - SetUi32(buf + 0, C ^ Keys[0]) - SetUi32(buf + 4, D ^ Keys[1]) - SetUi32(buf + 8, A ^ Keys[2]) - SetUi32(buf + 12, B ^ Keys[3]) - - UpdateKeys(encrypt ? buf : inBuf); -} - -Z7_COM7F_IMF(CDecoder::Init()) -{ - return S_OK; -} - -static const UInt32 kBlockSize = 16; - -Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) -{ - if (size == 0) - return 0; - if (size < kBlockSize) - return kBlockSize; - size -= kBlockSize; - UInt32 i; - for (i = 0; i <= size; i += kBlockSize) - DecryptBlock(data + i); - return i; -} - -}} +// Crypto/Rar20Crypto.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" +#include "../../../C/RotateDefs.h" + +#include "Rar20Crypto.h" + +namespace NCrypto { +namespace NRar2 { + +static const unsigned kNumRounds = 32; + +static const Byte g_InitSubstTable[256] = { + 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42, + 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137, + 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6, + 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235, + 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36, + 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251, + 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11, + 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51, + 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7, + 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80, + 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129, + 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10, + 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108, + 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225, + 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52, + 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84 +}; + +void CData::UpdateKeys(const Byte *data) +{ + for (unsigned i = 0; i < 16; i += 4) + for (unsigned j = 0; j < 4; j++) + Keys[j] ^= g_CrcTable[data[i + j]]; +} + +static inline void Swap(Byte &b1, Byte &b2) +{ + Byte b = b1; + b1 = b2; + b2 = b; +} + +void CData::SetPassword(const Byte *data, unsigned size) +{ + Keys[0] = 0xD3A3B879L; + Keys[1] = 0x3F6D12F7L; + Keys[2] = 0x7515A235L; + Keys[3] = 0xA4E7F123L; + + Byte psw[128]; + Z7_memset_0_ARRAY(psw); + if (size != 0) + { + if (size >= sizeof(psw)) + size = sizeof(psw) - 1; + memcpy(psw, data, size); + } + + memcpy(SubstTable, g_InitSubstTable, sizeof(SubstTable)); + + for (unsigned j = 0; j < 256; j++) + for (unsigned i = 0; i < size; i += 2) + { + unsigned n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF]; + unsigned n2 = (Byte)g_CrcTable[(psw[(size_t)i + 1] + j) & 0xFF]; + for (unsigned k = 1; (n1 & 0xFF) != n2; n1++, k++) + Swap(SubstTable[n1 & 0xFF], SubstTable[(n1 + i + k) & 0xFF]); + } + + for (unsigned i = 0; i < size; i += 16) + EncryptBlock(psw + i); +} + +void CData::CryptBlock(Byte *buf, bool encrypt) +{ + Byte inBuf[16]; + UInt32 A, B, C, D; + + A = GetUi32(buf + 0) ^ Keys[0]; + B = GetUi32(buf + 4) ^ Keys[1]; + C = GetUi32(buf + 8) ^ Keys[2]; + D = GetUi32(buf + 12) ^ Keys[3]; + + if (!encrypt) + memcpy(inBuf, buf, sizeof(inBuf)); + + for (unsigned i = 0; i < kNumRounds; i++) + { + UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3]; + UInt32 TA = A ^ SubstLong((C + rotlFixed(D, 11)) ^ key); + UInt32 TB = B ^ SubstLong((D ^ rotlFixed(C, 17)) + key); + A = C; C = TA; + B = D; D = TB; + } + + SetUi32(buf + 0, C ^ Keys[0]) + SetUi32(buf + 4, D ^ Keys[1]) + SetUi32(buf + 8, A ^ Keys[2]) + SetUi32(buf + 12, B ^ Keys[3]) + + UpdateKeys(encrypt ? buf : inBuf); +} + +Z7_COM7F_IMF(CDecoder::Init()) +{ + return S_OK; +} + +static const UInt32 kBlockSize = 16; + +Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) +{ + if (size == 0) + return 0; + if (size < kBlockSize) + return kBlockSize; + size -= kBlockSize; + UInt32 i; + for (i = 0; i <= size; i += kBlockSize) + DecryptBlock(data + i); + return i; +} + +}} diff --git a/CPP/7zip/Crypto/Rar20Crypto.h b/CPP/7zip/Crypto/Rar20Crypto.h index 096c4ede1..855071820 100644 --- a/CPP/7zip/Crypto/Rar20Crypto.h +++ b/CPP/7zip/Crypto/Rar20Crypto.h @@ -1,54 +1,54 @@ -// Crypto/Rar20Crypto.h - -#ifndef ZIP7_INC_CRYPTO_RAR20_CRYPTO_H -#define ZIP7_INC_CRYPTO_RAR20_CRYPTO_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" - -namespace NCrypto { -namespace NRar2 { - -/* ICompressFilter::Init() does nothing for this filter. - Call SetPassword() to initialize filter. */ - -class CData -{ - Byte SubstTable[256]; - UInt32 Keys[4]; - - UInt32 SubstLong(UInt32 t) const - { - return (UInt32)SubstTable[(unsigned)t & 255] - | ((UInt32)SubstTable[(unsigned)(t >> 8) & 255] << 8) - | ((UInt32)SubstTable[(unsigned)(t >> 16) & 255] << 16) - | ((UInt32)SubstTable[(unsigned)(t >> 24) ] << 24); - } - void UpdateKeys(const Byte *data); - void CryptBlock(Byte *buf, bool encrypt); -public: - ~CData() { Wipe(); } - void Wipe() - { - Z7_memset_0_ARRAY(SubstTable); - Z7_memset_0_ARRAY(Keys); - } - - void EncryptBlock(Byte *buf) { CryptBlock(buf, true); } - void DecryptBlock(Byte *buf) { CryptBlock(buf, false); } - void SetPassword(const Byte *password, unsigned passwordLen); -}; - -class CDecoder Z7_final: - public ICompressFilter, - public CMyUnknownImp, - public CData -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(ICompressFilter) -}; - -}} - -#endif +// Crypto/Rar20Crypto.h + +#ifndef ZIP7_INC_CRYPTO_RAR20_CRYPTO_H +#define ZIP7_INC_CRYPTO_RAR20_CRYPTO_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +namespace NCrypto { +namespace NRar2 { + +/* ICompressFilter::Init() does nothing for this filter. + Call SetPassword() to initialize filter. */ + +class CData +{ + Byte SubstTable[256]; + UInt32 Keys[4]; + + UInt32 SubstLong(UInt32 t) const + { + return (UInt32)SubstTable[(unsigned)t & 255] + | ((UInt32)SubstTable[(unsigned)(t >> 8) & 255] << 8) + | ((UInt32)SubstTable[(unsigned)(t >> 16) & 255] << 16) + | ((UInt32)SubstTable[(unsigned)(t >> 24) ] << 24); + } + void UpdateKeys(const Byte *data); + void CryptBlock(Byte *buf, bool encrypt); +public: + ~CData() { Wipe(); } + void Wipe() + { + Z7_memset_0_ARRAY(SubstTable); + Z7_memset_0_ARRAY(Keys); + } + + void EncryptBlock(Byte *buf) { CryptBlock(buf, true); } + void DecryptBlock(Byte *buf) { CryptBlock(buf, false); } + void SetPassword(const Byte *password, unsigned passwordLen); +}; + +class CDecoder Z7_final: + public ICompressFilter, + public CMyUnknownImp, + public CData +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ICompressFilter) +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp index 4e9545b91..34ea4ff49 100644 --- a/CPP/7zip/Crypto/Rar5Aes.cpp +++ b/CPP/7zip/Crypto/Rar5Aes.cpp @@ -1,265 +1,272 @@ -// Crypto/Rar5Aes.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#ifndef Z7_ST -#include "../../Windows/Synchronization.h" -#endif - -#include "Rar5Aes.h" -#include "HmacSha256.h" - -namespace NCrypto { -namespace NRar5 { - -static const unsigned kNumIterationsLog_Max = 24; - -static const unsigned kPswCheckCsumSize = 4; -static const unsigned kCheckSize = kPswCheckSize + kPswCheckCsumSize; - -CKey::CKey(): - _needCalc(true), - _numIterationsLog(0) -{ - for (unsigned i = 0; i < sizeof(_salt); i++) - _salt[i] = 0; -} - -CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {} - -static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val) -{ - *val = 0; - - for (unsigned i = 0; i < maxSize && i < 10;) - { - Byte b = p[i]; - *val |= (UInt64)(b & 0x7F) << (7 * i); - i++; - if ((b & 0x80) == 0) - return i; - } - return 0; -} - -HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV, bool isService) -{ - UInt64 Version; - - unsigned num = ReadVarInt(p, size, &Version); - if (num == 0) - return E_NOTIMPL; - p += num; - size -= num; - - if (Version != 0) - return E_NOTIMPL; - - num = ReadVarInt(p, size, &Flags); - if (num == 0) - return E_NOTIMPL; - p += num; - size -= num; - - bool isCheck = IsThereCheck(); - if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize : 0)) - return E_NOTIMPL; - - if (_numIterationsLog != p[0]) - { - _numIterationsLog = p[0]; - _needCalc = true; - } - - p++; - - if (memcmp(_salt, p, kSaltSize) != 0) - { - memcpy(_salt, p, kSaltSize); - _needCalc = true; - } - - p += kSaltSize; - - if (includeIV) - { - memcpy(_iv, p, AES_BLOCK_SIZE); - p += AES_BLOCK_SIZE; - } - - _canCheck = true; - - if (isCheck) - { - memcpy(_check, p, kPswCheckSize); - CSha256 sha; - Byte digest[SHA256_DIGEST_SIZE]; - Sha256_Init(&sha); - Sha256_Update(&sha, _check, kPswCheckSize); - Sha256_Final(&sha, digest); - _canCheck = (memcmp(digest, p + kPswCheckSize, kPswCheckCsumSize) == 0); - if (_canCheck && isService) - { - // There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros. - // so we disable password checking for such bad records. - _canCheck = false; - for (unsigned i = 0; i < kPswCheckSize; i++) - if (p[i] != 0) - { - _canCheck = true; - break; - } - } - } - - return (_numIterationsLog <= kNumIterationsLog_Max ? S_OK : E_NOTIMPL); -} - - -void CDecoder::SetPassword(const Byte *data, size_t size) -{ - if (size != _password.Size() || memcmp(data, _password, size) != 0) - { - _needCalc = true; - _password.Wipe(); - _password.CopyFrom(data, size); - } -} - - -Z7_COM7F_IMF(CDecoder::Init()) -{ - CalcKey_and_CheckPassword(); - RINOK(SetKey(_key, kAesKeySize)) - RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)) - return CAesCoder::Init(); -} - - -UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const -{ - MY_ALIGN (16) - NSha256::CHmac ctx; - ctx.SetKey(_hashKey, NSha256::kDigestSize); - UInt32 v; - SetUi32(&v, crc) - ctx.Update((const Byte *)&v, 4); - MY_ALIGN (16) - UInt32 h[SHA256_NUM_DIGEST_WORDS]; - ctx.Final((Byte *)h); - crc = 0; - for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++) - crc ^= (UInt32)GetUi32(h + i); - return crc; -} - - -void CDecoder::Hmac_Convert_32Bytes(Byte *data) const -{ - MY_ALIGN (16) - NSha256::CHmac ctx; - ctx.SetKey(_hashKey, NSha256::kDigestSize); - ctx.Update(data, NSha256::kDigestSize); - ctx.Final(data); -} - - -static CKey g_Key; - -#ifndef Z7_ST - static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection; - #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection); -#else - #define MT_LOCK -#endif - -bool CDecoder::CalcKey_and_CheckPassword() -{ - if (_needCalc) - { - { - MT_LOCK - if (!g_Key._needCalc && IsKeyEqualTo(g_Key)) - { - CopyCalcedKeysFrom(g_Key); - _needCalc = false; - } - } - - if (_needCalc) - { - Byte pswCheck[SHA256_DIGEST_SIZE]; - - { - // Pbkdf HMAC-SHA-256 - - MY_ALIGN (16) - NSha256::CHmac baseCtx; - baseCtx.SetKey(_password, _password.Size()); - - NSha256::CHmac ctx = baseCtx; - ctx.Update(_salt, sizeof(_salt)); - - MY_ALIGN (16) - Byte u[NSha256::kDigestSize]; - MY_ALIGN (16) - Byte key[NSha256::kDigestSize]; - - u[0] = 0; - u[1] = 0; - u[2] = 0; - u[3] = 1; - - ctx.Update(u, 4); - ctx.Final(u); - - memcpy(key, u, NSha256::kDigestSize); - - UInt32 numIterations = ((UInt32)1 << _numIterationsLog) - 1; - - for (unsigned i = 0; i < 3; i++) - { - UInt32 j = numIterations; - - for (; j != 0; j--) - { - ctx = baseCtx; - ctx.Update(u, NSha256::kDigestSize); - ctx.Final(u); - for (unsigned s = 0; s < NSha256::kDigestSize; s++) - key[s] ^= u[s]; - } - - // RAR uses additional iterations for additional keys - memcpy((i == 0 ? _key : (i == 1 ? _hashKey : pswCheck)), key, NSha256::kDigestSize); - numIterations = 16; - } - } - - { - unsigned i; - - for (i = 0; i < kPswCheckSize; i++) - _check_Calced[i] = pswCheck[i]; - - for (i = kPswCheckSize; i < SHA256_DIGEST_SIZE; i++) - _check_Calced[i & (kPswCheckSize - 1)] ^= pswCheck[i]; - } - - _needCalc = false; - - { - MT_LOCK - g_Key = *this; - } - } - } - - if (IsThereCheck() && _canCheck) - return (memcmp(_check_Calced, _check, kPswCheckSize) == 0); - return true; -} - -}} +// Crypto/Rar5Aes.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#ifndef Z7_ST +#include "../../Windows/Synchronization.h" +#endif + +#include "HmacSha256.h" +#include "Rar5Aes.h" + +#define MY_ALIGN_FOR_SHA256 MY_ALIGN(16) + +namespace NCrypto { +namespace NRar5 { + +static const unsigned kNumIterationsLog_Max = 24; +static const unsigned kPswCheckCsumSize32 = 1; +static const unsigned kCheckSize32 = kPswCheckSize32 + kPswCheckCsumSize32; + +CKey::CKey(): + _needCalc(true), + _numIterationsLog(0) +{ + for (unsigned i = 0; i < sizeof(_salt); i++) + _salt[i] = 0; +} + +CKey::~CKey() +{ + Wipe(); +} + +void CKey::Wipe() +{ + _password.Wipe(); + Z7_memset_0_ARRAY(_salt); + // Z7_memset_0_ARRAY(_key32); + // Z7_memset_0_ARRAY(_check_Calced32); + // Z7_memset_0_ARRAY(_hashKey32); + CKeyBase::Wipe(); +} + +CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {} + +static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val) +{ + *val = 0; + for (unsigned i = 0; i < maxSize && i < 10;) + { + const Byte b = p[i]; + *val |= (UInt64)(b & 0x7F) << (7 * i); + i++; + if ((b & 0x80) == 0) + return i; + } + return 0; +} + +HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV, bool isService) +{ + UInt64 Version; + + unsigned num = ReadVarInt(p, size, &Version); + if (num == 0) + return E_NOTIMPL; + p += num; + size -= num; + + if (Version != 0) + return E_NOTIMPL; + + num = ReadVarInt(p, size, &Flags); + if (num == 0) + return E_NOTIMPL; + p += num; + size -= num; + + bool isCheck = IsThereCheck(); + if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize32 * 4 : 0)) + return E_NOTIMPL; + + if (_numIterationsLog != p[0]) + { + _numIterationsLog = p[0]; + _needCalc = true; + } + + p++; + + if (memcmp(_salt, p, kSaltSize) != 0) + { + memcpy(_salt, p, kSaltSize); + _needCalc = true; + } + + p += kSaltSize; + + if (includeIV) + { + memcpy(_iv, p, AES_BLOCK_SIZE); + p += AES_BLOCK_SIZE; + } + + _canCheck = true; + + if (isCheck) + { + memcpy(_check32, p, sizeof(_check32)); + MY_ALIGN_FOR_SHA256 + CSha256 sha; + MY_ALIGN_FOR_SHA256 + Byte digest[SHA256_DIGEST_SIZE]; + Sha256_Init(&sha); + Sha256_Update(&sha, (const Byte *)_check32, sizeof(_check32)); + Sha256_Final(&sha, digest); + _canCheck = (memcmp(digest, p + sizeof(_check32), kPswCheckCsumSize32 * 4) == 0); + if (_canCheck && isService) + { + // There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros. + // so we disable password checking for such bad records. + _canCheck = false; + for (unsigned i = 0; i < kPswCheckSize32 * 4; i++) + if (p[i] != 0) + { + _canCheck = true; + break; + } + } + } + + return (_numIterationsLog <= kNumIterationsLog_Max ? S_OK : E_NOTIMPL); +} + + +void CDecoder::SetPassword(const Byte *data, size_t size) +{ + if (size != _password.Size() || memcmp(data, _password, size) != 0) + { + _needCalc = true; + _password.Wipe(); + _password.CopyFrom(data, size); + } +} + + +Z7_COM7F_IMF(CDecoder::Init()) +{ + CalcKey_and_CheckPassword(); + RINOK(SetKey((const Byte *)_key32, kAesKeySize)) + RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)) + return CAesCoder::Init(); +} + + +UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const +{ + MY_ALIGN_FOR_SHA256 + NSha256::CHmac ctx; + ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize); + UInt32 v; + SetUi32a(&v, crc) + ctx.Update((const Byte *)&v, 4); + MY_ALIGN_FOR_SHA256 + UInt32 h[SHA256_NUM_DIGEST_WORDS]; + ctx.Final((Byte *)h); + crc = 0; + for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++) + crc ^= (UInt32)GetUi32a(h + i); + return crc; +} + + +void CDecoder::Hmac_Convert_32Bytes(Byte *data) const +{ + MY_ALIGN_FOR_SHA256 + NSha256::CHmac ctx; + ctx.SetKey((const Byte *)_hashKey32, NSha256::kDigestSize); + ctx.Update(data, NSha256::kDigestSize); + ctx.Final(data); +} + + +static CKey g_Key; + +#ifndef Z7_ST + static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection; + #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection); +#else + #define MT_LOCK +#endif + +bool CDecoder::CalcKey_and_CheckPassword() +{ + if (_needCalc) + { + { + MT_LOCK + if (!g_Key._needCalc && IsKeyEqualTo(g_Key)) + { + CopyCalcedKeysFrom(g_Key); + _needCalc = false; + } + } + + if (_needCalc) + { + MY_ALIGN_FOR_SHA256 + UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS]; + { + // Pbkdf HMAC-SHA-256 + MY_ALIGN_FOR_SHA256 + NSha256::CHmac baseCtx; + baseCtx.SetKey(_password, _password.Size()); + MY_ALIGN_FOR_SHA256 + NSha256::CHmac ctx; + ctx = baseCtx; + ctx.Update(_salt, sizeof(_salt)); + + MY_ALIGN_FOR_SHA256 + UInt32 u[SHA256_NUM_DIGEST_WORDS]; + MY_ALIGN_FOR_SHA256 + UInt32 key[SHA256_NUM_DIGEST_WORDS]; + + // u[0] = 0; + // u[1] = 0; + // u[2] = 0; + // u[3] = 1; + SetUi32a(u, 0x1000000) + + ctx.Update((const Byte *)(const void *)u, 4); + ctx.Final((Byte *)(void *)u); + + memcpy(key, u, NSha256::kDigestSize); + + UInt32 numIterations = ((UInt32)1 << _numIterationsLog) - 1; + + for (unsigned i = 0; i < 3; i++) + { + for (; numIterations != 0; numIterations--) + { + ctx = baseCtx; + ctx.Update((const Byte *)(const void *)u, NSha256::kDigestSize); + ctx.Final((Byte *)(void *)u); + for (unsigned s = 0; s < Z7_ARRAY_SIZE(u); s++) + key[s] ^= u[s]; + } + + // RAR uses additional iterations for additional keys + memcpy(i == 0 ? _key32 : i == 1 ? _hashKey32 : pswCheck, + key, NSha256::kDigestSize); + numIterations = 16; + } + } + _check_Calced32[0] = pswCheck[0] ^ pswCheck[2] ^ pswCheck[4] ^ pswCheck[6]; + _check_Calced32[1] = pswCheck[1] ^ pswCheck[3] ^ pswCheck[5] ^ pswCheck[7]; + _needCalc = false; + { + MT_LOCK + g_Key = *this; + } + } + } + + if (IsThereCheck() && _canCheck) + return memcmp(_check_Calced32, _check32, sizeof(_check32)) == 0; + return true; +} + +}} diff --git a/CPP/7zip/Crypto/Rar5Aes.h b/CPP/7zip/Crypto/Rar5Aes.h index 493cffb4f..c6059aa21 100644 --- a/CPP/7zip/Crypto/Rar5Aes.h +++ b/CPP/7zip/Crypto/Rar5Aes.h @@ -1,98 +1,97 @@ -// Crypto/Rar5Aes.h - -#ifndef ZIP7_INC_CRYPTO_RAR5_AES_H -#define ZIP7_INC_CRYPTO_RAR5_AES_H - -#include "../../../C/Sha256.h" - -#include "../../Common/MyBuffer.h" - -#include "MyAes.h" - -namespace NCrypto { -namespace NRar5 { - -const unsigned kSaltSize = 16; -const unsigned kPswCheckSize = 8; -const unsigned kAesKeySize = 32; - -namespace NCryptoFlags -{ - const unsigned kPswCheck = 1 << 0; - const unsigned kUseMAC = 1 << 1; -} - -struct CKey -{ - bool _needCalc; - - unsigned _numIterationsLog; - Byte _salt[kSaltSize]; - CByteBuffer _password; - - Byte _key[kAesKeySize]; - Byte _check_Calced[kPswCheckSize]; - Byte _hashKey[SHA256_DIGEST_SIZE]; - - void CopyCalcedKeysFrom(const CKey &k) - { - memcpy(_key, k._key, sizeof(_key)); - memcpy(_check_Calced, k._check_Calced, sizeof(_check_Calced)); - memcpy(_hashKey, k._hashKey, sizeof(_hashKey)); - } - - bool IsKeyEqualTo(const CKey &key) - { - return (_numIterationsLog == key._numIterationsLog - && memcmp(_salt, key._salt, sizeof(_salt)) == 0 - && _password == key._password); - } - - CKey(); - - void Wipe() - { - _password.Wipe(); - Z7_memset_0_ARRAY(_salt); - Z7_memset_0_ARRAY(_key); - Z7_memset_0_ARRAY(_check_Calced); - Z7_memset_0_ARRAY(_hashKey); - } - -#ifdef Z7_CPP_IS_SUPPORTED_default - // CKey(const CKey &) = default; - CKey& operator =(const CKey &) = default; -#endif - ~CKey() { Wipe(); } -}; - - -class CDecoder Z7_final: - public CAesCbcDecoder, - public CKey -{ - Byte _check[kPswCheckSize]; - bool _canCheck; - UInt64 Flags; - - bool IsThereCheck() const { return ((Flags & NCryptoFlags::kPswCheck) != 0); } -public: - Byte _iv[AES_BLOCK_SIZE]; - - CDecoder(); - - Z7_COM7F_IMP(Init()) - - void SetPassword(const Byte *data, size_t size); - HRESULT SetDecoderProps(const Byte *data, unsigned size, bool includeIV, bool isService); - - bool CalcKey_and_CheckPassword(); - - bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; } - UInt32 Hmac_Convert_Crc32(UInt32 crc) const; - void Hmac_Convert_32Bytes(Byte *data) const; -}; - -}} - -#endif +// Crypto/Rar5Aes.h + +#ifndef ZIP7_INC_CRYPTO_RAR5_AES_H +#define ZIP7_INC_CRYPTO_RAR5_AES_H + +#include "../../../C/Sha256.h" + +#include "../../Common/MyBuffer.h" + +#include "MyAes.h" + +namespace NCrypto { +namespace NRar5 { + +const unsigned kSaltSize = 16; +const unsigned kPswCheckSize32 = 2; +const unsigned kAesKeySize = 32; + +namespace NCryptoFlags +{ + const unsigned kPswCheck = 1 << 0; + const unsigned kUseMAC = 1 << 1; +} + +struct CKeyBase +{ +protected: + UInt32 _key32[kAesKeySize / 4]; + UInt32 _hashKey32[SHA256_NUM_DIGEST_WORDS]; + UInt32 _check_Calced32[kPswCheckSize32]; + + void Wipe() + { + memset(this, 0, sizeof(*this)); + } + + void CopyCalcedKeysFrom(const CKeyBase &k) + { + *this = k; + } +}; + +struct CKey: public CKeyBase +{ + CByteBuffer _password; + bool _needCalc; + unsigned _numIterationsLog; + Byte _salt[kSaltSize]; + + bool IsKeyEqualTo(const CKey &key) + { + return _numIterationsLog == key._numIterationsLog + && memcmp(_salt, key._salt, sizeof(_salt)) == 0 + && _password == key._password; + } + + CKey(); + ~CKey(); + + void Wipe(); + +#ifdef Z7_CPP_IS_SUPPORTED_default + // CKey(const CKey &) = default; + CKey& operator =(const CKey &) = default; +#endif +}; + + +class CDecoder Z7_final: + public CAesCbcDecoder, + public CKey +{ + UInt32 _check32[kPswCheckSize32]; + bool _canCheck; + UInt64 Flags; + + bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; } +public: + Byte _iv[AES_BLOCK_SIZE]; + + CDecoder(); + + Z7_COM7F_IMP(Init()) + + void SetPassword(const Byte *data, size_t size); + HRESULT SetDecoderProps(const Byte *data, unsigned size, bool includeIV, bool isService); + + bool CalcKey_and_CheckPassword(); + + bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; } + UInt32 Hmac_Convert_Crc32(UInt32 crc) const; + void Hmac_Convert_32Bytes(Byte *data) const; +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/RarAes.cpp b/CPP/7zip/Crypto/RarAes.cpp index b55c7a486..e63f82c68 100644 --- a/CPP/7zip/Crypto/RarAes.cpp +++ b/CPP/7zip/Crypto/RarAes.cpp @@ -1,194 +1,202 @@ -// Crypto/RarAes.cpp - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" -#include "../../../C/RotateDefs.h" - -#include "RarAes.h" -#include "Sha1Cls.h" - -namespace NCrypto { -namespace NRar3 { - -CDecoder::CDecoder(): - CAesCbcDecoder(kAesKeySize), - _thereIsSalt(false), - _needCalc(true) - // _rar350Mode(false) -{ - for (unsigned i = 0; i < sizeof(_salt); i++) - _salt[i] = 0; -} - -HRESULT CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) -{ - bool prev = _thereIsSalt; - _thereIsSalt = false; - if (size == 0) - { - if (!_needCalc && prev) - _needCalc = true; - return S_OK; - } - if (size < 8) - return E_INVALIDARG; - _thereIsSalt = true; - bool same = false; - if (_thereIsSalt == prev) - { - same = true; - if (_thereIsSalt) - { - for (unsigned i = 0; i < sizeof(_salt); i++) - if (_salt[i] != data[i]) - { - same = false; - break; - } - } - } - for (unsigned i = 0; i < sizeof(_salt); i++) - _salt[i] = data[i]; - if (!_needCalc && !same) - _needCalc = true; - return S_OK; -} - -static const unsigned kPasswordLen_Bytes_MAX = 127 * 2; - -void CDecoder::SetPassword(const Byte *data, unsigned size) -{ - if (size > kPasswordLen_Bytes_MAX) - size = kPasswordLen_Bytes_MAX; - bool same = false; - if (size == _password.Size()) - { - same = true; - for (UInt32 i = 0; i < size; i++) - if (data[i] != _password[i]) - { - same = false; - break; - } - } - if (!_needCalc && !same) - _needCalc = true; - _password.Wipe(); - _password.CopyFrom(data, (size_t)size); -} - -Z7_COM7F_IMF(CDecoder::Init()) -{ - CalcKey(); - RINOK(SetKey(_key, kAesKeySize)) - RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)) - return CAesCoder::Init(); -} - - -// if (password_size_in_bytes + SaltSize > 64), -// the original rar code updates password_with_salt buffer -// with some generated data from SHA1 code. - -// #define RAR_SHA1_REDUCE - -#ifdef RAR_SHA1_REDUCE - #define kNumW 16 - #define WW(i) W[(i)&15] -#else - #define kNumW 80 - #define WW(i) W[i] -#endif - -static void UpdatePswDataSha1(Byte *data) -{ - UInt32 W[kNumW]; - size_t i; - - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) - W[i] = GetBe32(data + i * 4); - - for (i = 16; i < 80; i++) - { - WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1); - } - - for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) - { - SetUi32(data + i * 4, W[kNumW - SHA1_NUM_BLOCK_WORDS + i]) - } -} - - -void CDecoder::CalcKey() -{ - if (!_needCalc) - return; - - const unsigned kSaltSize = 8; - - Byte buf[kPasswordLen_Bytes_MAX + kSaltSize]; - - if (_password.Size() != 0) - memcpy(buf, _password, _password.Size()); - - size_t rawSize = _password.Size(); - - if (_thereIsSalt) - { - memcpy(buf + rawSize, _salt, kSaltSize); - rawSize += kSaltSize; - } - - MY_ALIGN (16) - NSha1::CContext sha; - sha.Init(); - - MY_ALIGN (16) - Byte digest[NSha1::kDigestSize]; - // rar reverts hash for sha. - const UInt32 kNumRounds = ((UInt32)1 << 18); - UInt32 pos = 0; - UInt32 i; - for (i = 0; i < kNumRounds; i++) - { - sha.Update(buf, rawSize); - // if (_rar350Mode) - { - const UInt32 kBlockSize = 64; - const UInt32 endPos = (pos + (UInt32)rawSize) & ~(kBlockSize - 1); - if (endPos > pos + kBlockSize) - { - UInt32 curPos = pos & ~(kBlockSize - 1); - curPos += kBlockSize; - do - { - UpdatePswDataSha1(buf + (curPos - pos)); - curPos += kBlockSize; - } - while (curPos != endPos); - } - } - pos += (UInt32)rawSize; - Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) }; - sha.Update(pswNum, 3); - pos += 3; - if (i % (kNumRounds / 16) == 0) - { - MY_ALIGN (16) - NSha1::CContext shaTemp = sha; - shaTemp.Final(digest); - _iv[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3]; - } - } - - sha.Final(digest); - for (i = 0; i < 4; i++) - for (unsigned j = 0; j < 4; j++) - _key[i * 4 + j] = (digest[i * 4 + 3 - j]); - - _needCalc = false; -} - -}} +// Crypto/RarAes.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/RotateDefs.h" + +#include "RarAes.h" +#include "Sha1Cls.h" + +namespace NCrypto { +namespace NRar3 { + +CDecoder::CDecoder(): + CAesCbcDecoder(kAesKeySize), + _thereIsSalt(false), + _needCalc(true) + // _rar350Mode(false) +{ + for (unsigned i = 0; i < sizeof(_salt); i++) + _salt[i] = 0; +} + +HRESULT CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + bool prev = _thereIsSalt; + _thereIsSalt = false; + if (size == 0) + { + if (!_needCalc && prev) + _needCalc = true; + return S_OK; + } + if (size < 8) + return E_INVALIDARG; + _thereIsSalt = true; + bool same = false; + if (_thereIsSalt == prev) + { + same = true; + if (_thereIsSalt) + { + for (unsigned i = 0; i < sizeof(_salt); i++) + if (_salt[i] != data[i]) + { + same = false; + break; + } + } + } + for (unsigned i = 0; i < sizeof(_salt); i++) + _salt[i] = data[i]; + if (!_needCalc && !same) + _needCalc = true; + return S_OK; +} + +static const unsigned kPasswordLen_Bytes_MAX = 127 * 2; + +void CDecoder::SetPassword(const Byte *data, unsigned size) +{ + if (size > kPasswordLen_Bytes_MAX) + size = kPasswordLen_Bytes_MAX; + bool same = false; + if (size == _password.Size()) + { + same = true; + for (UInt32 i = 0; i < size; i++) + if (data[i] != _password[i]) + { + same = false; + break; + } + } + if (!_needCalc && !same) + _needCalc = true; + _password.Wipe(); + _password.CopyFrom(data, (size_t)size); +} + +Z7_COM7F_IMF(CDecoder::Init()) +{ + CalcKey(); + RINOK(SetKey(_key, kAesKeySize)) + RINOK(SetInitVector(_iv, AES_BLOCK_SIZE)) + return CAesCoder::Init(); +} + + +// if (password_size_in_bytes + SaltSize > 64), +// the original rar code updates password_with_salt buffer +// with some generated data from SHA1 code. + +// #define RAR_SHA1_REDUCE + +#ifdef RAR_SHA1_REDUCE + #define kNumW 16 + #define WW(i) W[(i)&15] +#else + #define kNumW 80 + #define WW(i) W[i] +#endif + +static void UpdatePswDataSha1(Byte *data) +{ + UInt32 W[kNumW]; + size_t i; + + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) + W[i] = GetBe32(data + i * 4); + + for (i = 16; i < 80; i++) + { + const UInt32 t = WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16); + WW(i) = rotlFixed(t, 1); + } + + for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++) + { + SetUi32(data + i * 4, W[kNumW - SHA1_NUM_BLOCK_WORDS + i]) + } +} + + +void CDecoder::CalcKey() +{ + if (!_needCalc) + return; + + const unsigned kSaltSize = 8; + + MY_ALIGN (16) + Byte buf[kPasswordLen_Bytes_MAX + kSaltSize]; + + if (_password.Size() != 0) + memcpy(buf, _password, _password.Size()); + + size_t rawSize = _password.Size(); + + if (_thereIsSalt) + { + memcpy(buf + rawSize, _salt, kSaltSize); + rawSize += kSaltSize; + } + + MY_ALIGN (16) + NSha1::CContext sha; + sha.Init(); + + MY_ALIGN (16) + Byte digest[NSha1::kDigestSize]; + // rar reverts hash for sha. + const UInt32 kNumRounds = (UInt32)1 << 18; + UInt32 pos = 0; + UInt32 i; + for (i = 0; i < kNumRounds; i++) + { + sha.Update(buf, rawSize); + // if (_rar350Mode) + { + const UInt32 kBlockSize = 64; + const UInt32 endPos = (pos + (UInt32)rawSize) & ~(kBlockSize - 1); + if (endPos > pos + kBlockSize) + { + UInt32 curPos = pos & ~(kBlockSize - 1); + curPos += kBlockSize; + do + { + UpdatePswDataSha1(buf + (curPos - pos)); + curPos += kBlockSize; + } + while (curPos != endPos); + } + } + pos += (UInt32)rawSize; +#if 1 + UInt32 pswNum; + SetUi32a(&pswNum, i) + sha.Update((const Byte *)&pswNum, 3); +#else + Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) }; + sha.Update(pswNum, 3); +#endif + pos += 3; + if (i % (kNumRounds / 16) == 0) + { + MY_ALIGN (16) + NSha1::CContext shaTemp = sha; + shaTemp.Final(digest); + _iv[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3]; + } + } + + sha.Final(digest); + for (i = 0; i < 4; i++) + for (unsigned j = 0; j < 4; j++) + _key[i * 4 + j] = (digest[i * 4 + 3 - j]); + + _needCalc = false; +} + +}} diff --git a/CPP/7zip/Crypto/RarAes.h b/CPP/7zip/Crypto/RarAes.h index dad2a85c8..d3c104c84 100644 --- a/CPP/7zip/Crypto/RarAes.h +++ b/CPP/7zip/Crypto/RarAes.h @@ -1,54 +1,54 @@ -// Crypto/RarAes.h - -#ifndef ZIP7_INC_CRYPTO_RAR_AES_H -#define ZIP7_INC_CRYPTO_RAR_AES_H - -#include "../../../C/Aes.h" - -#include "../../Common/MyBuffer.h" - -#include "../IPassword.h" - -#include "MyAes.h" - -namespace NCrypto { -namespace NRar3 { - -const unsigned kAesKeySize = 16; - -class CDecoder Z7_final: - public CAesCbcDecoder -{ - Byte _salt[8]; - bool _thereIsSalt; - bool _needCalc; - // bool _rar350Mode; - - CByteBuffer _password; - - Byte _key[kAesKeySize]; - Byte _iv[AES_BLOCK_SIZE]; - - void CalcKey(); -public: - Z7_COM7F_IMP(Init()) - - void SetPassword(const Byte *data, unsigned size); - HRESULT SetDecoderProperties2(const Byte *data, UInt32 size); - - CDecoder(); - - ~CDecoder() Z7_DESTRUCTOR_override { Wipe(); } - void Wipe() - { - _password.Wipe(); - Z7_memset_0_ARRAY(_salt); - Z7_memset_0_ARRAY(_key); - Z7_memset_0_ARRAY(_iv); - } - // void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; } -}; - -}} - -#endif +// Crypto/RarAes.h + +#ifndef ZIP7_INC_CRYPTO_RAR_AES_H +#define ZIP7_INC_CRYPTO_RAR_AES_H + +#include "../../../C/Aes.h" + +#include "../../Common/MyBuffer.h" + +#include "../IPassword.h" + +#include "MyAes.h" + +namespace NCrypto { +namespace NRar3 { + +const unsigned kAesKeySize = 16; + +class CDecoder Z7_final: + public CAesCbcDecoder +{ + Byte _salt[8]; + bool _thereIsSalt; + bool _needCalc; + // bool _rar350Mode; + + CByteBuffer _password; + + Byte _key[kAesKeySize]; + Byte _iv[AES_BLOCK_SIZE]; + + void CalcKey(); +public: + Z7_COM7F_IMP(Init()) + + void SetPassword(const Byte *data, unsigned size); + HRESULT SetDecoderProperties2(const Byte *data, UInt32 size); + + CDecoder(); + + ~CDecoder() Z7_DESTRUCTOR_override { Wipe(); } + void Wipe() + { + _password.Wipe(); + Z7_memset_0_ARRAY(_salt); + Z7_memset_0_ARRAY(_key); + Z7_memset_0_ARRAY(_iv); + } + // void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; } +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/Sha1Cls.h b/CPP/7zip/Crypto/Sha1Cls.h index c54891bdb..56ae040d9 100644 --- a/CPP/7zip/Crypto/Sha1Cls.h +++ b/CPP/7zip/Crypto/Sha1Cls.h @@ -1,37 +1,37 @@ -// Crypto/Sha1Cls.h - -#ifndef ZIP7_INC_CRYPTO_SHA1_CLS_H -#define ZIP7_INC_CRYPTO_SHA1_CLS_H - -#include "../../../C/Sha1.h" - -namespace NCrypto { -namespace NSha1 { - -const unsigned kNumBlockWords = SHA1_NUM_BLOCK_WORDS; -const unsigned kNumDigestWords = SHA1_NUM_DIGEST_WORDS; - -const unsigned kBlockSize = SHA1_BLOCK_SIZE; -const unsigned kDigestSize = SHA1_DIGEST_SIZE; - -class CContext -{ - CSha1 _s; - -public: - void Init() throw() { Sha1_Init(&_s); } - void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); } - void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); } - void PrepareBlock(Byte *block, unsigned size) const throw() - { - Sha1_PrepareBlock(&_s, block, size); - } - void GetBlockDigest(const Byte *blockData, Byte *destDigest) const throw() - { - Sha1_GetBlockDigest(&_s, blockData, destDigest); - } -}; - -}} - -#endif +// Crypto/Sha1Cls.h + +#ifndef ZIP7_INC_CRYPTO_SHA1_CLS_H +#define ZIP7_INC_CRYPTO_SHA1_CLS_H + +#include "../../../C/Sha1.h" + +namespace NCrypto { +namespace NSha1 { + +const unsigned kNumBlockWords = SHA1_NUM_BLOCK_WORDS; +const unsigned kNumDigestWords = SHA1_NUM_DIGEST_WORDS; + +const unsigned kBlockSize = SHA1_BLOCK_SIZE; +const unsigned kDigestSize = SHA1_DIGEST_SIZE; + +class CContext +{ + CSha1 _s; + +public: + void Init() throw() { Sha1_Init(&_s); } + void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); } + void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); } + void PrepareBlock(Byte *block, unsigned size) const throw() + { + Sha1_PrepareBlock(&_s, block, size); + } + void GetBlockDigest(const Byte *blockData, Byte *destDigest) const throw() + { + Sha1_GetBlockDigest(&_s, blockData, destDigest); + } +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/StdAfx.h b/CPP/7zip/Crypto/StdAfx.h index aa6fe0328..80866550d 100644 --- a/CPP/7zip/Crypto/StdAfx.h +++ b/CPP/7zip/Crypto/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../Common/Common.h" + +#endif diff --git a/CPP/7zip/Crypto/WzAes.cpp b/CPP/7zip/Crypto/WzAes.cpp index b06dfd123..3f2adab0a 100644 --- a/CPP/7zip/Crypto/WzAes.cpp +++ b/CPP/7zip/Crypto/WzAes.cpp @@ -1,231 +1,231 @@ -// Crypto/WzAes.cpp -/* -This code implements Brian Gladman's scheme -specified in "A Password Based File Encryption Utility". - -Note: you must include MyAes.cpp to project to initialize AES tables -*/ - -#include "StdAfx.h" - -#include "../../../C/CpuArch.h" - -#include "../Common/StreamUtils.h" - -#include "Pbkdf2HmacSha1.h" -#include "RandGen.h" -#include "WzAes.h" - -namespace NCrypto { -namespace NWzAes { - -const unsigned kAesKeySizeMax = 32; - -static const UInt32 kNumKeyGenIterations = 1000; - -Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)) -{ - if (size > kPasswordSizeMax) - return E_INVALIDARG; - _key.Password.Wipe(); - _key.Password.CopyFrom(data, (size_t)size); - return S_OK; -} - -void CBaseCoder::Init2() -{ - _hmacOverCalc = 0; - const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4; - Byte dk[dkSizeMax32 * 4]; - - const unsigned keySize = _key.GetKeySize(); - const unsigned dkSize = 2 * keySize + ((kPwdVerifSize + 3) & ~(unsigned)3); - - // for (unsigned ii = 0; ii < 1000; ii++) - { - NSha1::Pbkdf2Hmac( - _key.Password, _key.Password.Size(), - _key.Salt, _key.GetSaltSize(), - kNumKeyGenIterations, - dk, dkSize); - } - - Hmac()->SetKey(dk + keySize, keySize); - memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize); - - // Aes_SetKey_Enc(_aes.Aes() + 8, dk, keySize); - // AesCtr2_Init(&_aes); - _aesCoderSpec->SetKeySize(keySize); - if (_aesCoderSpec->SetKey(dk, keySize) != S_OK) throw 2; - if (_aesCoderSpec->Init() != S_OK) throw 3; -} - -Z7_COM7F_IMF(CBaseCoder::Init()) -{ - return S_OK; -} - -HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream) -{ - unsigned saltSize = _key.GetSaltSize(); - MY_RAND_GEN(_key.Salt, saltSize); - Init2(); - RINOK(WriteStream(outStream, _key.Salt, saltSize)) - return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize); -} - -HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream) -{ - MY_ALIGN (16) - UInt32 mac[NSha1::kNumDigestWords]; - Hmac()->Final((Byte *)mac); - return WriteStream(outStream, mac, kMacSize); -} - -/* -Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) -{ - if (size != 1) - return E_INVALIDARG; - _key.Init(); - return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG; -} -*/ - -HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) -{ - const unsigned saltSize = _key.GetSaltSize(); - const unsigned extraSize = saltSize + kPwdVerifSize; - Byte temp[kSaltSizeMax + kPwdVerifSize]; - RINOK(ReadStream_FAIL(inStream, temp, extraSize)) - unsigned i; - for (i = 0; i < saltSize; i++) - _key.Salt[i] = temp[i]; - for (i = 0; i < kPwdVerifSize; i++) - _pwdVerifFromArchive[i] = temp[saltSize + i]; - return S_OK; -} - -static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size) -{ - for (unsigned i = 0; i < size; i++) - if (p1[i] != p2[i]) - return false; - return true; -} - -bool CDecoder::Init_and_CheckPassword() -{ - Init2(); - return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize); -} - -HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK) -{ - isOK = false; - MY_ALIGN (16) - Byte mac1[kMacSize]; - RINOK(ReadStream_FAIL(inStream, mac1, kMacSize)) - MY_ALIGN (16) - UInt32 mac2[NSha1::kNumDigestWords]; - Hmac()->Final((Byte *)mac2); - isOK = CompareArrays(mac1, (const Byte *)mac2, kMacSize); - if (_hmacOverCalc) - isOK = false; - return S_OK; -} - -/* - -CAesCtr2::CAesCtr2(): - aes((4 + AES_NUM_IVMRK_WORDS) * 4) -{ - // offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32); - // first 16 bytes are buffer for last block data. - // so the ivAES is aligned for (Align + 16). -} - -void AesCtr2_Init(CAesCtr2 *p) -{ - UInt32 *ctr = p->Aes() + 4; - unsigned i; - for (i = 0; i < 4; i++) - ctr[i] = 0; - p->pos = AES_BLOCK_SIZE; -} - -// (size != 16 * N) is allowed only for last call - -void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size) -{ - unsigned pos = p->pos; - UInt32 *buf32 = p->Aes(); - if (size == 0) - return; - - if (pos != AES_BLOCK_SIZE) - { - const Byte *buf = (const Byte *)buf32; - do - *data++ ^= buf[pos++]; - while (--size != 0 && pos != AES_BLOCK_SIZE); - } - - // (size == 0 || pos == AES_BLOCK_SIZE) - - if (size >= 16) - { - SizeT size2 = size >> 4; - g_AesCtr_Code(buf32 + 4, data, size2); - size2 <<= 4; - data += size2; - size -= size2; - // (pos == AES_BLOCK_SIZE) - } - - // (size < 16) - - if (size != 0) - { - unsigned j; - const Byte *buf; - for (j = 0; j < 4; j++) - buf32[j] = 0; - g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1); - buf = (const Byte *)buf32; - pos = 0; - do - *data++ ^= buf[pos++]; - while (--size != 0); - } - - p->pos = pos; -} -*/ - -/* (size != 16 * N) is allowed only for last Filter() call */ - -Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) -{ - // AesCtr2_Code(&_aes, data, size); - size = _aesCoder->Filter(data, size); - Hmac()->Update(data, size); - return size; -} - -Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) -{ - if (size >= 16) - size &= ~(UInt32)15; - if (_hmacOverCalc < size) - { - Hmac()->Update(data + _hmacOverCalc, size - _hmacOverCalc); - _hmacOverCalc = size; - } - // AesCtr2_Code(&_aes, data, size); - size = _aesCoder->Filter(data, size); - _hmacOverCalc -= size; - return size; -} - -}} +// Crypto/WzAes.cpp +/* +This code implements Brian Gladman's scheme +specified in "A Password Based File Encryption Utility". + +Note: you must include MyAes.cpp to project to initialize AES tables +*/ + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "Pbkdf2HmacSha1.h" +#include "RandGen.h" +#include "WzAes.h" + +namespace NCrypto { +namespace NWzAes { + +const unsigned kAesKeySizeMax = 32; + +static const UInt32 kNumKeyGenIterations = 1000; + +Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)) +{ + if (size > kPasswordSizeMax) + return E_INVALIDARG; + _key.Password.Wipe(); + _key.Password.CopyFrom(data, (size_t)size); + return S_OK; +} + +void CBaseCoder::Init2() +{ + _hmacOverCalc = 0; + const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4; + Byte dk[dkSizeMax32 * 4]; + + const unsigned keySize = _key.GetKeySize(); + const unsigned dkSize = 2 * keySize + ((kPwdVerifSize + 3) & ~(unsigned)3); + + // for (unsigned ii = 0; ii < 1000; ii++) + { + NSha1::Pbkdf2Hmac( + _key.Password, _key.Password.Size(), + _key.Salt, _key.GetSaltSize(), + kNumKeyGenIterations, + dk, dkSize); + } + + Hmac()->SetKey(dk + keySize, keySize); + memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize); + + // Aes_SetKey_Enc(_aes.Aes() + 8, dk, keySize); + // AesCtr2_Init(&_aes); + _aesCoderSpec->SetKeySize(keySize); + if (_aesCoderSpec->SetKey(dk, keySize) != S_OK) throw 2; + if (_aesCoderSpec->Init() != S_OK) throw 3; +} + +Z7_COM7F_IMF(CBaseCoder::Init()) +{ + return S_OK; +} + +HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream) +{ + unsigned saltSize = _key.GetSaltSize(); + MY_RAND_GEN(_key.Salt, saltSize); + Init2(); + RINOK(WriteStream(outStream, _key.Salt, saltSize)) + return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize); +} + +HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream) +{ + MY_ALIGN (16) + UInt32 mac[NSha1::kNumDigestWords]; + Hmac()->Final((Byte *)mac); + return WriteStream(outStream, mac, kMacSize); +} + +/* +Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) +{ + if (size != 1) + return E_INVALIDARG; + _key.Init(); + return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG; +} +*/ + +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) +{ + const unsigned saltSize = _key.GetSaltSize(); + const unsigned extraSize = saltSize + kPwdVerifSize; + Byte temp[kSaltSizeMax + kPwdVerifSize]; + RINOK(ReadStream_FAIL(inStream, temp, extraSize)) + unsigned i; + for (i = 0; i < saltSize; i++) + _key.Salt[i] = temp[i]; + for (i = 0; i < kPwdVerifSize; i++) + _pwdVerifFromArchive[i] = temp[saltSize + i]; + return S_OK; +} + +static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size) +{ + for (unsigned i = 0; i < size; i++) + if (p1[i] != p2[i]) + return false; + return true; +} + +bool CDecoder::Init_and_CheckPassword() +{ + Init2(); + return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize); +} + +HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK) +{ + isOK = false; + MY_ALIGN (16) + Byte mac1[kMacSize]; + RINOK(ReadStream_FAIL(inStream, mac1, kMacSize)) + MY_ALIGN (16) + UInt32 mac2[NSha1::kNumDigestWords]; + Hmac()->Final((Byte *)mac2); + isOK = CompareArrays(mac1, (const Byte *)mac2, kMacSize); + if (_hmacOverCalc) + isOK = false; + return S_OK; +} + +/* + +CAesCtr2::CAesCtr2(): + aes((4 + AES_NUM_IVMRK_WORDS) * 4) +{ + // offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32); + // first 16 bytes are buffer for last block data. + // so the ivAES is aligned for (Align + 16). +} + +void AesCtr2_Init(CAesCtr2 *p) +{ + UInt32 *ctr = p->Aes() + 4; + unsigned i; + for (i = 0; i < 4; i++) + ctr[i] = 0; + p->pos = AES_BLOCK_SIZE; +} + +// (size != 16 * N) is allowed only for last call + +void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size) +{ + unsigned pos = p->pos; + UInt32 *buf32 = p->Aes(); + if (size == 0) + return; + + if (pos != AES_BLOCK_SIZE) + { + const Byte *buf = (const Byte *)buf32; + do + *data++ ^= buf[pos++]; + while (--size != 0 && pos != AES_BLOCK_SIZE); + } + + // (size == 0 || pos == AES_BLOCK_SIZE) + + if (size >= 16) + { + SizeT size2 = size >> 4; + g_AesCtr_Code(buf32 + 4, data, size2); + size2 <<= 4; + data += size2; + size -= size2; + // (pos == AES_BLOCK_SIZE) + } + + // (size < 16) + + if (size != 0) + { + unsigned j; + const Byte *buf; + for (j = 0; j < 4; j++) + buf32[j] = 0; + g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1); + buf = (const Byte *)buf32; + pos = 0; + do + *data++ ^= buf[pos++]; + while (--size != 0); + } + + p->pos = pos; +} +*/ + +/* (size != 16 * N) is allowed only for last Filter() call */ + +Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) +{ + // AesCtr2_Code(&_aes, data, size); + size = _aesCoder->Filter(data, size); + Hmac()->Update(data, size); + return size; +} + +Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) +{ + if (size >= 16) + size &= ~(UInt32)15; + if (_hmacOverCalc < size) + { + Hmac()->Update(data + _hmacOverCalc, size - _hmacOverCalc); + _hmacOverCalc = size; + } + // AesCtr2_Code(&_aes, data, size); + size = _aesCoder->Filter(data, size); + _hmacOverCalc -= size; + return size; +} + +}} diff --git a/CPP/7zip/Crypto/WzAes.h b/CPP/7zip/Crypto/WzAes.h index 82c0feb78..113ec81a2 100644 --- a/CPP/7zip/Crypto/WzAes.h +++ b/CPP/7zip/Crypto/WzAes.h @@ -1,161 +1,161 @@ -// Crypto/WzAes.h -/* -This code implements Brian Gladman's scheme -specified in "A Password Based File Encryption Utility": - - AES encryption (128,192,256-bit) in Counter (CTR) mode. - - HMAC-SHA1 authentication for encrypted data (10 bytes) - - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and - Salt (saltSize = aesKeySize / 2). - - 2 bytes contain Password Verifier's Code -*/ - -#ifndef ZIP7_INC_CRYPTO_WZ_AES_H -#define ZIP7_INC_CRYPTO_WZ_AES_H - -#include "../../Common/MyBuffer.h" - -#include "../IPassword.h" - -#include "HmacSha1.h" -#include "MyAes.h" - -namespace NCrypto { -namespace NWzAes { - -/* ICompressFilter::Init() does nothing for this filter. - - Call to init: - Encoder: - CryptoSetPassword(); - WriteHeader(); - Decoder: - [CryptoSetPassword();] - ReadHeader(); - [CryptoSetPassword();] Init_and_CheckPassword(); - [CryptoSetPassword();] Init_and_CheckPassword(); -*/ - -const UInt32 kPasswordSizeMax = 99; // 128; - -const unsigned kSaltSizeMax = 16; -const unsigned kPwdVerifSize = 2; -const unsigned kMacSize = 10; - -enum EKeySizeMode -{ - kKeySizeMode_AES128 = 1, - kKeySizeMode_AES192 = 2, - kKeySizeMode_AES256 = 3 -}; - -struct CKeyInfo -{ - EKeySizeMode KeySizeMode; - Byte Salt[kSaltSizeMax]; - Byte PwdVerifComputed[kPwdVerifSize]; - - CByteBuffer Password; - - unsigned GetKeySize() const { return (8 * KeySizeMode + 8); } - unsigned GetSaltSize() const { return (4 * KeySizeMode + 4); } - unsigned GetNumSaltWords() const { return (KeySizeMode + 1); } - - CKeyInfo(): KeySizeMode(kKeySizeMode_AES256) {} - - void Wipe() - { - Password.Wipe(); - Z7_memset_0_ARRAY(Salt); - Z7_memset_0_ARRAY(PwdVerifComputed); - } - - ~CKeyInfo() { Wipe(); } -}; - -/* -struct CAesCtr2 -{ - unsigned pos; - CAlignedBuffer aes; - UInt32 *Aes() { return (UInt32 *)(Byte *)aes; } - - // unsigned offset; - // UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3]; - // UInt32 *Aes() { return aes + offset; } - CAesCtr2(); -}; - -void AesCtr2_Init(CAesCtr2 *p); -void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size); -*/ - -class CBaseCoder: - public ICompressFilter, - public ICryptoSetPassword, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword) - Z7_COM7F_IMP(Init()) -public: - Z7_IFACE_COM7_IMP(ICryptoSetPassword) -protected: - CKeyInfo _key; - - // NSha1::CHmac _hmac; - // NSha1::CHmac *Hmac() { return &_hmac; } - CAlignedBuffer1 _hmacBuf; - UInt32 _hmacOverCalc; - - NSha1::CHmac *Hmac() { return (NSha1::CHmac *)(void *)(Byte *)_hmacBuf; } - - // CAesCtr2 _aes; - CAesCoder *_aesCoderSpec; - CMyComPtr _aesCoder; - CBaseCoder(): - _hmacBuf(sizeof(NSha1::CHmac)) - { - _aesCoderSpec = new CAesCtrCoder(32); - _aesCoder = _aesCoderSpec; - } - - void Init2(); -public: - unsigned GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifSize; } - unsigned GetAddPackSize() const { return GetHeaderSize() + kMacSize; } - - bool SetKeyMode(unsigned mode) - { - if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256) - return false; - _key.KeySizeMode = (EKeySizeMode)mode; - return true; - } - - virtual ~CBaseCoder() {} -}; - -class CEncoder Z7_final: - public CBaseCoder -{ - Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) -public: - HRESULT WriteHeader(ISequentialOutStream *outStream); - HRESULT WriteFooter(ISequentialOutStream *outStream); -}; - -class CDecoder Z7_final: - public CBaseCoder - // public ICompressSetDecoderProperties2 -{ - Byte _pwdVerifFromArchive[kPwdVerifSize]; - Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) -public: - // Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) - HRESULT ReadHeader(ISequentialInStream *inStream); - bool Init_and_CheckPassword(); - HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK); -}; - -}} - -#endif +// Crypto/WzAes.h +/* +This code implements Brian Gladman's scheme +specified in "A Password Based File Encryption Utility": + - AES encryption (128,192,256-bit) in Counter (CTR) mode. + - HMAC-SHA1 authentication for encrypted data (10 bytes) + - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and + Salt (saltSize = aesKeySize / 2). + - 2 bytes contain Password Verifier's Code +*/ + +#ifndef ZIP7_INC_CRYPTO_WZ_AES_H +#define ZIP7_INC_CRYPTO_WZ_AES_H + +#include "../../Common/MyBuffer.h" + +#include "../IPassword.h" + +#include "HmacSha1.h" +#include "MyAes.h" + +namespace NCrypto { +namespace NWzAes { + +/* ICompressFilter::Init() does nothing for this filter. + + Call to init: + Encoder: + CryptoSetPassword(); + WriteHeader(); + Decoder: + [CryptoSetPassword();] + ReadHeader(); + [CryptoSetPassword();] Init_and_CheckPassword(); + [CryptoSetPassword();] Init_and_CheckPassword(); +*/ + +const UInt32 kPasswordSizeMax = 99; // 128; + +const unsigned kSaltSizeMax = 16; +const unsigned kPwdVerifSize = 2; +const unsigned kMacSize = 10; + +enum EKeySizeMode +{ + kKeySizeMode_AES128 = 1, + kKeySizeMode_AES192 = 2, + kKeySizeMode_AES256 = 3 +}; + +struct CKeyInfo +{ + EKeySizeMode KeySizeMode; + Byte Salt[kSaltSizeMax]; + Byte PwdVerifComputed[kPwdVerifSize]; + + CByteBuffer Password; + + unsigned GetKeySize() const { return (8 * KeySizeMode + 8); } + unsigned GetSaltSize() const { return (4 * KeySizeMode + 4); } + unsigned GetNumSaltWords() const { return (KeySizeMode + 1); } + + CKeyInfo(): KeySizeMode(kKeySizeMode_AES256) {} + + void Wipe() + { + Password.Wipe(); + Z7_memset_0_ARRAY(Salt); + Z7_memset_0_ARRAY(PwdVerifComputed); + } + + ~CKeyInfo() { Wipe(); } +}; + +/* +struct CAesCtr2 +{ + unsigned pos; + CAlignedBuffer aes; + UInt32 *Aes() { return (UInt32 *)(Byte *)aes; } + + // unsigned offset; + // UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3]; + // UInt32 *Aes() { return aes + offset; } + CAesCtr2(); +}; + +void AesCtr2_Init(CAesCtr2 *p); +void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size); +*/ + +class CBaseCoder: + public ICompressFilter, + public ICryptoSetPassword, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword) + Z7_COM7F_IMP(Init()) +public: + Z7_IFACE_COM7_IMP(ICryptoSetPassword) +protected: + CKeyInfo _key; + + // NSha1::CHmac _hmac; + // NSha1::CHmac *Hmac() { return &_hmac; } + CAlignedBuffer1 _hmacBuf; + UInt32 _hmacOverCalc; + + NSha1::CHmac *Hmac() { return (NSha1::CHmac *)(void *)(Byte *)_hmacBuf; } + + // CAesCtr2 _aes; + CAesCoder *_aesCoderSpec; + CMyComPtr _aesCoder; + CBaseCoder(): + _hmacBuf(sizeof(NSha1::CHmac)) + { + _aesCoderSpec = new CAesCtrCoder(32); + _aesCoder = _aesCoderSpec; + } + + void Init2(); +public: + unsigned GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifSize; } + unsigned GetAddPackSize() const { return GetHeaderSize() + kMacSize; } + + bool SetKeyMode(unsigned mode) + { + if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256) + return false; + _key.KeySizeMode = (EKeySizeMode)mode; + return true; + } + + virtual ~CBaseCoder() {} +}; + +class CEncoder Z7_final: + public CBaseCoder +{ + Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) +public: + HRESULT WriteHeader(ISequentialOutStream *outStream); + HRESULT WriteFooter(ISequentialOutStream *outStream); +}; + +class CDecoder Z7_final: + public CBaseCoder + // public ICompressSetDecoderProperties2 +{ + Byte _pwdVerifFromArchive[kPwdVerifSize]; + Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) +public: + // Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2) + HRESULT ReadHeader(ISequentialInStream *inStream); + bool Init_and_CheckPassword(); + HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/ZipCrypto.cpp b/CPP/7zip/Crypto/ZipCrypto.cpp index 9d51cfb2a..047e2bd6c 100644 --- a/CPP/7zip/Crypto/ZipCrypto.cpp +++ b/CPP/7zip/Crypto/ZipCrypto.cpp @@ -1,114 +1,114 @@ -// Crypto/ZipCrypto.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" - -#include "../Common/StreamUtils.h" - -#include "RandGen.h" -#include "ZipCrypto.h" - -namespace NCrypto { -namespace NZip { - -#define UPDATE_KEYS(b) { \ - key0 = CRC_UPDATE_BYTE(key0, b); \ - key1 = (key1 + (key0 & 0xFF)) * 0x8088405 + 1; \ - key2 = CRC_UPDATE_BYTE(key2, (Byte)(key1 >> 24)); } \ - -#define DECRYPT_BYTE_1 UInt32 temp = key2 | 2; -#define DECRYPT_BYTE_2 ((Byte)((temp * (temp ^ 1)) >> 8)) - -Z7_COM7F_IMF(CCipher::CryptoSetPassword(const Byte *data, UInt32 size)) -{ - UInt32 key0 = 0x12345678; - UInt32 key1 = 0x23456789; - UInt32 key2 = 0x34567890; - - for (UInt32 i = 0; i < size; i++) - UPDATE_KEYS(data[i]) - - KeyMem0 = key0; - KeyMem1 = key1; - KeyMem2 = key2; - - return S_OK; -} - -Z7_COM7F_IMF(CCipher::Init()) -{ - return S_OK; -} - -HRESULT CEncoder::WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc) -{ - Byte h[kHeaderSize]; - - /* PKZIP before 2.0 used 2 byte CRC check. - PKZIP 2.0+ used 1 byte CRC check. It's more secure. - We also use 1 byte CRC. */ - - MY_RAND_GEN(h, kHeaderSize - 1); - // h[kHeaderSize - 2] = (Byte)(crc); - h[kHeaderSize - 1] = (Byte)(crc >> 8); - - RestoreKeys(); - Filter(h, kHeaderSize); - return WriteStream(outStream, h, kHeaderSize); -} - -Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) -{ - UInt32 key0 = this->Key0; - UInt32 key1 = this->Key1; - UInt32 key2 = this->Key2; - - for (UInt32 i = 0; i < size; i++) - { - Byte b = data[i]; - DECRYPT_BYTE_1 - data[i] = (Byte)(b ^ DECRYPT_BYTE_2); - UPDATE_KEYS(b) - } - - this->Key0 = key0; - this->Key1 = key1; - this->Key2 = key2; - - return size; -} - -HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) -{ - return ReadStream_FAIL(inStream, _header, kHeaderSize); -} - -void CDecoder::Init_BeforeDecode() -{ - RestoreKeys(); - Filter(_header, kHeaderSize); -} - -Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) -{ - UInt32 key0 = this->Key0; - UInt32 key1 = this->Key1; - UInt32 key2 = this->Key2; - - for (UInt32 i = 0; i < size; i++) - { - DECRYPT_BYTE_1 - Byte b = (Byte)(data[i] ^ DECRYPT_BYTE_2); - UPDATE_KEYS(b) - data[i] = b; - } - - this->Key0 = key0; - this->Key1 = key1; - this->Key2 = key2; - - return size; -} - -}} +// Crypto/ZipCrypto.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" + +#include "../Common/StreamUtils.h" + +#include "RandGen.h" +#include "ZipCrypto.h" + +namespace NCrypto { +namespace NZip { + +#define UPDATE_KEYS(b) { \ + key0 = CRC_UPDATE_BYTE(key0, b); \ + key1 = (key1 + (key0 & 0xFF)) * 0x8088405 + 1; \ + key2 = CRC_UPDATE_BYTE(key2, (Byte)(key1 >> 24)); } \ + +#define DECRYPT_BYTE_1 UInt32 temp = key2 | 2; +#define DECRYPT_BYTE_2 ((Byte)((temp * (temp ^ 1)) >> 8)) + +Z7_COM7F_IMF(CCipher::CryptoSetPassword(const Byte *data, UInt32 size)) +{ + UInt32 key0 = 0x12345678; + UInt32 key1 = 0x23456789; + UInt32 key2 = 0x34567890; + + for (UInt32 i = 0; i < size; i++) + UPDATE_KEYS(data[i]) + + KeyMem0 = key0; + KeyMem1 = key1; + KeyMem2 = key2; + + return S_OK; +} + +Z7_COM7F_IMF(CCipher::Init()) +{ + return S_OK; +} + +HRESULT CEncoder::WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc) +{ + Byte h[kHeaderSize]; + + /* PKZIP before 2.0 used 2 byte CRC check. + PKZIP 2.0+ used 1 byte CRC check. It's more secure. + We also use 1 byte CRC. */ + + MY_RAND_GEN(h, kHeaderSize - 1); + // h[kHeaderSize - 2] = (Byte)(crc); + h[kHeaderSize - 1] = (Byte)(crc >> 8); + + RestoreKeys(); + Filter(h, kHeaderSize); + return WriteStream(outStream, h, kHeaderSize); +} + +Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size)) +{ + UInt32 key0 = this->Key0; + UInt32 key1 = this->Key1; + UInt32 key2 = this->Key2; + + for (UInt32 i = 0; i < size; i++) + { + Byte b = data[i]; + DECRYPT_BYTE_1 + data[i] = (Byte)(b ^ DECRYPT_BYTE_2); + UPDATE_KEYS(b) + } + + this->Key0 = key0; + this->Key1 = key1; + this->Key2 = key2; + + return size; +} + +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream) +{ + return ReadStream_FAIL(inStream, _header, kHeaderSize); +} + +void CDecoder::Init_BeforeDecode() +{ + RestoreKeys(); + Filter(_header, kHeaderSize); +} + +Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) +{ + UInt32 key0 = this->Key0; + UInt32 key1 = this->Key1; + UInt32 key2 = this->Key2; + + for (UInt32 i = 0; i < size; i++) + { + DECRYPT_BYTE_1 + Byte b = (Byte)(data[i] ^ DECRYPT_BYTE_2); + UPDATE_KEYS(b) + data[i] = b; + } + + this->Key0 = key0; + this->Key1 = key1; + this->Key2 = key2; + + return size; +} + +}} diff --git a/CPP/7zip/Crypto/ZipCrypto.h b/CPP/7zip/Crypto/ZipCrypto.h index de4c648e6..485470ed3 100644 --- a/CPP/7zip/Crypto/ZipCrypto.h +++ b/CPP/7zip/Crypto/ZipCrypto.h @@ -1,80 +1,80 @@ -// Crypto/ZipCrypto.h - -#ifndef ZIP7_INC_CRYPTO_ZIP_CRYPTO_H -#define ZIP7_INC_CRYPTO_ZIP_CRYPTO_H - -#include "../../Common/MyCom.h" - -#include "../ICoder.h" -#include "../IPassword.h" - -namespace NCrypto { -namespace NZip { - -const unsigned kHeaderSize = 12; - -/* ICompressFilter::Init() does nothing for this filter. - Call to init: - Encoder: - CryptoSetPassword(); - WriteHeader(); - Decoder: - [CryptoSetPassword();] - ReadHeader(); - [CryptoSetPassword();] Init_and_GetCrcByte(); - [CryptoSetPassword();] Init_and_GetCrcByte(); -*/ - -class CCipher: - public ICompressFilter, - public ICryptoSetPassword, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword) - Z7_COM7F_IMP(Init()) -public: - Z7_IFACE_COM7_IMP(ICryptoSetPassword) -protected: - UInt32 Key0; - UInt32 Key1; - UInt32 Key2; - - UInt32 KeyMem0; - UInt32 KeyMem1; - UInt32 KeyMem2; - - void RestoreKeys() - { - Key0 = KeyMem0; - Key1 = KeyMem1; - Key2 = KeyMem2; - } - -public: - virtual ~CCipher() - { - Key0 = KeyMem0 = - Key1 = KeyMem1 = - Key2 = KeyMem2 = 0; - } -}; - -class CEncoder Z7_final: public CCipher -{ - Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) -public: - HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc); -}; - -class CDecoder Z7_final: public CCipher -{ - Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) -public: - Byte _header[kHeaderSize]; - HRESULT ReadHeader(ISequentialInStream *inStream); - void Init_BeforeDecode(); -}; - -}} - -#endif +// Crypto/ZipCrypto.h + +#ifndef ZIP7_INC_CRYPTO_ZIP_CRYPTO_H +#define ZIP7_INC_CRYPTO_ZIP_CRYPTO_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" +#include "../IPassword.h" + +namespace NCrypto { +namespace NZip { + +const unsigned kHeaderSize = 12; + +/* ICompressFilter::Init() does nothing for this filter. + Call to init: + Encoder: + CryptoSetPassword(); + WriteHeader(); + Decoder: + [CryptoSetPassword();] + ReadHeader(); + [CryptoSetPassword();] Init_and_GetCrcByte(); + [CryptoSetPassword();] Init_and_GetCrcByte(); +*/ + +class CCipher: + public ICompressFilter, + public ICryptoSetPassword, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword) + Z7_COM7F_IMP(Init()) +public: + Z7_IFACE_COM7_IMP(ICryptoSetPassword) +protected: + UInt32 Key0; + UInt32 Key1; + UInt32 Key2; + + UInt32 KeyMem0; + UInt32 KeyMem1; + UInt32 KeyMem2; + + void RestoreKeys() + { + Key0 = KeyMem0; + Key1 = KeyMem1; + Key2 = KeyMem2; + } + +public: + virtual ~CCipher() + { + Key0 = KeyMem0 = + Key1 = KeyMem1 = + Key2 = KeyMem2 = 0; + } +}; + +class CEncoder Z7_final: public CCipher +{ + Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) +public: + HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc); +}; + +class CDecoder Z7_final: public CCipher +{ + Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size)) +public: + Byte _header[kHeaderSize]; + HRESULT ReadHeader(ISequentialInStream *inStream); + void Init_BeforeDecode(); +}; + +}} + +#endif diff --git a/CPP/7zip/Crypto/ZipStrong.cpp b/CPP/7zip/Crypto/ZipStrong.cpp index a05cdf364..c4e83118f 100644 --- a/CPP/7zip/Crypto/ZipStrong.cpp +++ b/CPP/7zip/Crypto/ZipStrong.cpp @@ -1,264 +1,265 @@ -// Crypto/ZipStrong.cpp - -#include "StdAfx.h" - -#include "../../../C/7zCrc.h" -#include "../../../C/CpuArch.h" - -#include "../Common/StreamUtils.h" - -#include "Sha1Cls.h" -#include "ZipStrong.h" - -namespace NCrypto { -namespace NZipStrong { - -static const UInt16 kAES128 = 0x660E; - -/* - DeriveKey() function is similar to CryptDeriveKey() from Windows. - New version of MSDN contains the following condition in CryptDeriveKey() description: - "If the hash is not a member of the SHA-2 family and the required key is for either 3DES or AES". - Now we support ZipStrong for AES only. And it uses SHA1. - Our DeriveKey() code is equal to CryptDeriveKey() in Windows for such conditions: (SHA1 + AES). - if (method != AES && method != 3DES), probably we need another code. -*/ - -static void DeriveKey2(const Byte *digest, Byte c, Byte *dest) -{ - MY_ALIGN (16) - Byte buf[64]; - memset(buf, c, 64); - for (unsigned i = 0; i < NSha1::kDigestSize; i++) - buf[i] ^= digest[i]; - MY_ALIGN (16) - NSha1::CContext sha; - sha.Init(); - sha.Update(buf, 64); - sha.Final(dest); -} - -static void DeriveKey(NSha1::CContext &sha, Byte *key) -{ - MY_ALIGN (16) - Byte digest[NSha1::kDigestSize]; - sha.Final(digest); - MY_ALIGN (16) - Byte temp[NSha1::kDigestSize * 2]; - DeriveKey2(digest, 0x36, temp); - DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize); - memcpy(key, temp, 32); -} - -void CKeyInfo::SetPassword(const Byte *data, UInt32 size) -{ - MY_ALIGN (16) - NSha1::CContext sha; - sha.Init(); - sha.Update(data, size); - DeriveKey(sha, MasterKey); -} - - - -CDecoder::CDecoder() -{ - CAesCbcDecoder *d = new CAesCbcDecoder(); - _cbcDecoder = d; - _aesFilter = d; -} - -Z7_COM7F_IMF(CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)) -{ - _key.SetPassword(data, size); - return S_OK; -} - -Z7_COM7F_IMF(CDecoder::Init()) -{ - return S_OK; -} - -Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) -{ - return _aesFilter->Filter(data, size); -} - - -HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize) -{ - Byte temp[4]; - RINOK(ReadStream_FALSE(inStream, temp, 2)) - _ivSize = GetUi16(temp); - if (_ivSize == 0) - { - memset(_iv, 0, 16); - SetUi32(_iv + 0, crc) - SetUi64(_iv + 4, unpackSize) - _ivSize = 12; - } - else if (_ivSize == 16) - { - RINOK(ReadStream_FALSE(inStream, _iv, _ivSize)) - } - else - return E_NOTIMPL; - RINOK(ReadStream_FALSE(inStream, temp, 4)) - _remSize = GetUi32(temp); - // const UInt32 kAlign = 16; - if (_remSize < 16 || _remSize > (1 << 18)) - return E_NOTIMPL; - if (_remSize > _bufAligned.Size()) - { - _bufAligned.AllocAtLeast(_remSize); - if (!(Byte *)_bufAligned) - return E_OUTOFMEMORY; - } - return ReadStream_FALSE(inStream, _bufAligned, _remSize); -} - -HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK) -{ - passwOK = false; - if (_remSize < 16) - return E_NOTIMPL; - Byte *p = _bufAligned; - const unsigned format = GetUi16(p); - if (format != 3) - return E_NOTIMPL; - unsigned algId = GetUi16(p + 2); - if (algId < kAES128) - return E_NOTIMPL; - algId -= kAES128; - if (algId > 2) - return E_NOTIMPL; - const unsigned bitLen = GetUi16(p + 4); - const unsigned flags = GetUi16(p + 6); - if (algId * 64 + 128 != bitLen) - return E_NOTIMPL; - _key.KeySize = 16 + algId * 8; - const bool cert = ((flags & 2) != 0); - - if ((flags & 0x4000) != 0) - { - // Use 3DES for rd data - return E_NOTIMPL; - } - - if (cert) - { - return E_NOTIMPL; - } - else - { - if ((flags & 1) == 0) - return E_NOTIMPL; - } - - UInt32 rdSize = GetUi16(p + 8); - - if (rdSize + 16 > _remSize) - return E_NOTIMPL; - - const unsigned kPadSize = kAesPadAllign; // is equal to blockSize of cipher for rd - - /* - if (cert) - { - if ((rdSize & 0x7) != 0) - return E_NOTIMPL; - } - else - */ - { - // PKCS7 padding - if (rdSize < kPadSize) - return E_NOTIMPL; - if ((rdSize & (kPadSize - 1)) != 0) - return E_NOTIMPL; - } - - memmove(p, p + 10, rdSize); - const Byte *p2 = p + rdSize + 10; - UInt32 reserved = GetUi32(p2); - p2 += 4; - - /* - if (cert) - { - UInt32 numRecipients = reserved; - - if (numRecipients == 0) - return E_NOTIMPL; - - { - UInt32 hashAlg = GetUi16(p2); - hashAlg = hashAlg; - UInt32 hashSize = GetUi16(p2 + 2); - hashSize = hashSize; - p2 += 4; - - reserved = reserved; - // return E_NOTIMPL; - - for (unsigned r = 0; r < numRecipients; r++) - { - UInt32 specSize = GetUi16(p2); - p2 += 2; - p2 += specSize; - } - } - } - else - */ - { - if (reserved != 0) - return E_NOTIMPL; - } - - UInt32 validSize = GetUi16(p2); - p2 += 2; - const size_t validOffset = (size_t)(p2 - p); - if ((validSize & 0xF) != 0 || validOffset + validSize != _remSize) - return E_NOTIMPL; - - { - RINOK(_cbcDecoder->SetKey(_key.MasterKey, _key.KeySize)) - RINOK(_cbcDecoder->SetInitVector(_iv, 16)) - // SetInitVector() calls also Init() - RINOK(_cbcDecoder->Init()) // it's optional - Filter(p, rdSize); - - rdSize -= kPadSize; - for (unsigned i = 0; i < kPadSize; i++) - if (p[(size_t)rdSize + i] != kPadSize) - return S_OK; // passwOK = false; - } - - MY_ALIGN (16) - Byte fileKey[32]; - MY_ALIGN (16) - NSha1::CContext sha; - sha.Init(); - sha.Update(_iv, _ivSize); - sha.Update(p, rdSize); - DeriveKey(sha, fileKey); - - RINOK(_cbcDecoder->SetKey(fileKey, _key.KeySize)) - RINOK(_cbcDecoder->SetInitVector(_iv, 16)) - // SetInitVector() calls also Init() - RINOK(_cbcDecoder->Init()) // it's optional - - memmove(p, p + validOffset, validSize); - Filter(p, validSize); - - if (validSize < 4) - return E_NOTIMPL; - validSize -= 4; - if (GetUi32(p + validSize) != CrcCalc(p, validSize)) - return S_OK; - passwOK = true; - return S_OK; -} - -}} +// Crypto/ZipStrong.cpp + +#include "StdAfx.h" + +#include "../../../C/7zCrc.h" +#include "../../../C/CpuArch.h" + +#include "../Common/StreamUtils.h" + +#include "Sha1Cls.h" +#include "ZipStrong.h" + +namespace NCrypto { +namespace NZipStrong { + +static const UInt16 kAES128 = 0x660E; + +/* + DeriveKey() function is similar to CryptDeriveKey() from Windows. + New version of MSDN contains the following condition in CryptDeriveKey() description: + "If the hash is not a member of the SHA-2 family and the required key is for either 3DES or AES". + Now we support ZipStrong for AES only. And it uses SHA1. + Our DeriveKey() code is equal to CryptDeriveKey() in Windows for such conditions: (SHA1 + AES). + if (method != AES && method != 3DES), probably we need another code. +*/ + +static void DeriveKey2(const UInt32 *digest32, Byte c, UInt32 *dest32) +{ + const unsigned kBufSize = 64; + MY_ALIGN (16) + UInt32 buf32[kBufSize / 4]; + memset(buf32, c, kBufSize); + for (unsigned i = 0; i < NSha1::kNumDigestWords; i++) + buf32[i] ^= digest32[i]; + MY_ALIGN (16) + NSha1::CContext sha; + sha.Init(); + sha.Update((const Byte *)buf32, kBufSize); + sha.Final((Byte *)dest32); +} + +static void DeriveKey(NSha1::CContext &sha, Byte *key) +{ + MY_ALIGN (16) + UInt32 digest32[NSha1::kNumDigestWords]; + sha.Final((Byte *)digest32); + MY_ALIGN (16) + UInt32 temp32[NSha1::kNumDigestWords * 2]; + DeriveKey2(digest32, 0x36, temp32); + DeriveKey2(digest32, 0x5C, temp32 + NSha1::kNumDigestWords); + memcpy(key, temp32, 32); +} + +void CKeyInfo::SetPassword(const Byte *data, UInt32 size) +{ + MY_ALIGN (16) + NSha1::CContext sha; + sha.Init(); + sha.Update(data, size); + DeriveKey(sha, MasterKey); +} + + + +CDecoder::CDecoder() +{ + CAesCbcDecoder *d = new CAesCbcDecoder(); + _cbcDecoder = d; + _aesFilter = d; +} + +Z7_COM7F_IMF(CDecoder::CryptoSetPassword(const Byte *data, UInt32 size)) +{ + _key.SetPassword(data, size); + return S_OK; +} + +Z7_COM7F_IMF(CDecoder::Init()) +{ + return S_OK; +} + +Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size)) +{ + return _aesFilter->Filter(data, size); +} + + +HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize) +{ + Byte temp[4]; + RINOK(ReadStream_FALSE(inStream, temp, 2)) + _ivSize = GetUi16(temp); + if (_ivSize == 0) + { + memset(_iv, 0, 16); + SetUi32(_iv + 0, crc) + SetUi64(_iv + 4, unpackSize) + _ivSize = 12; + } + else if (_ivSize == 16) + { + RINOK(ReadStream_FALSE(inStream, _iv, _ivSize)) + } + else + return E_NOTIMPL; + RINOK(ReadStream_FALSE(inStream, temp, 4)) + _remSize = GetUi32(temp); + // const UInt32 kAlign = 16; + if (_remSize < 16 || _remSize > (1 << 18)) + return E_NOTIMPL; + if (_remSize > _bufAligned.Size()) + { + _bufAligned.AllocAtLeast(_remSize); + if (!(Byte *)_bufAligned) + return E_OUTOFMEMORY; + } + return ReadStream_FALSE(inStream, _bufAligned, _remSize); +} + +HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK) +{ + passwOK = false; + if (_remSize < 16) + return E_NOTIMPL; + Byte * const p = _bufAligned; + const unsigned format = GetUi16a(p); + if (format != 3) + return E_NOTIMPL; + unsigned algId = GetUi16a(p + 2); + if (algId < kAES128) + return E_NOTIMPL; + algId -= kAES128; + if (algId > 2) + return E_NOTIMPL; + const unsigned bitLen = GetUi16a(p + 4); + const unsigned flags = GetUi16a(p + 6); + if (algId * 64 + 128 != bitLen) + return E_NOTIMPL; + _key.KeySize = 16 + algId * 8; + const bool cert = ((flags & 2) != 0); + + if (flags & 0x4000) + { + // Use 3DES for rd data + return E_NOTIMPL; + } + + if (cert) + { + return E_NOTIMPL; + } + else + { + if ((flags & 1) == 0) + return E_NOTIMPL; + } + + UInt32 rdSize = GetUi16a(p + 8); + + if (rdSize + 16 > _remSize) + return E_NOTIMPL; + + const unsigned kPadSize = kAesPadAllign; // is equal to blockSize of cipher for rd + + /* + if (cert) + { + if ((rdSize & 0x7) != 0) + return E_NOTIMPL; + } + else + */ + { + // PKCS7 padding + if (rdSize < kPadSize) + return E_NOTIMPL; + if (rdSize & (kPadSize - 1)) + return E_NOTIMPL; + } + + memmove(p, p + 10, rdSize); + const Byte *p2 = p + rdSize + 10; + UInt32 reserved = GetUi32(p2); + p2 += 4; + + /* + if (cert) + { + UInt32 numRecipients = reserved; + + if (numRecipients == 0) + return E_NOTIMPL; + + { + UInt32 hashAlg = GetUi16(p2); + hashAlg = hashAlg; + UInt32 hashSize = GetUi16(p2 + 2); + hashSize = hashSize; + p2 += 4; + + reserved = reserved; + // return E_NOTIMPL; + + for (unsigned r = 0; r < numRecipients; r++) + { + UInt32 specSize = GetUi16(p2); + p2 += 2; + p2 += specSize; + } + } + } + else + */ + { + if (reserved != 0) + return E_NOTIMPL; + } + + UInt32 validSize = GetUi16(p2); + p2 += 2; + const size_t validOffset = (size_t)(p2 - p); + if ((validSize & 0xF) != 0 || validOffset + validSize != _remSize) + return E_NOTIMPL; + + { + RINOK(_cbcDecoder->SetKey(_key.MasterKey, _key.KeySize)) + RINOK(_cbcDecoder->SetInitVector(_iv, 16)) + // SetInitVector() calls also Init() + RINOK(_cbcDecoder->Init()) // it's optional + Filter(p, rdSize); + + rdSize -= kPadSize; + for (unsigned i = 0; i < kPadSize; i++) + if (p[(size_t)rdSize + i] != kPadSize) + return S_OK; // passwOK = false; + } + + MY_ALIGN (16) + Byte fileKey[32]; + MY_ALIGN (16) + NSha1::CContext sha; + sha.Init(); + sha.Update(_iv, _ivSize); + sha.Update(p, rdSize); + DeriveKey(sha, fileKey); + + RINOK(_cbcDecoder->SetKey(fileKey, _key.KeySize)) + RINOK(_cbcDecoder->SetInitVector(_iv, 16)) + // SetInitVector() calls also Init() + RINOK(_cbcDecoder->Init()) // it's optional + + memmove(p, p + validOffset, validSize); + Filter(p, validSize); + + if (validSize < 4) + return E_NOTIMPL; + validSize -= 4; + if (GetUi32(p + validSize) != CrcCalc(p, validSize)) + return S_OK; + passwOK = true; + return S_OK; +} + +}} diff --git a/CPP/7zip/Crypto/ZipStrong.h b/CPP/7zip/Crypto/ZipStrong.h index a00458845..a2b5cddfa 100644 --- a/CPP/7zip/Crypto/ZipStrong.h +++ b/CPP/7zip/Crypto/ZipStrong.h @@ -1,73 +1,73 @@ -// Crypto/ZipStrong.h - -#ifndef ZIP7_INC_CRYPTO_ZIP_STRONG_H -#define ZIP7_INC_CRYPTO_ZIP_STRONG_H - -#include "../../Common/MyBuffer2.h" - -#include "../IPassword.h" - -#include "MyAes.h" - -namespace NCrypto { -namespace NZipStrong { - -/* ICompressFilter::Init() does nothing for this filter. - Call to init: - Decoder: - [CryptoSetPassword();] - ReadHeader(); - [CryptoSetPassword();] Init_and_CheckPassword(); - [CryptoSetPassword();] Init_and_CheckPassword(); -*/ - -struct CKeyInfo -{ - Byte MasterKey[32]; - UInt32 KeySize; - - void SetPassword(const Byte *data, UInt32 size); - - void Wipe() - { - Z7_memset_0_ARRAY(MasterKey); - } -}; - - -const unsigned kAesPadAllign = AES_BLOCK_SIZE; - -Z7_CLASS_IMP_COM_2( - CDecoder - , ICompressFilter - , ICryptoSetPassword -) - CAesCbcDecoder *_cbcDecoder; - CMyComPtr _aesFilter; - CKeyInfo _key; - CAlignedBuffer _bufAligned; - - UInt32 _ivSize; - Byte _iv[16]; - UInt32 _remSize; -public: - HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize); - HRESULT Init_and_CheckPassword(bool &passwOK); - UInt32 GetPadSize(UInt32 packSize32) const - { - // Padding is to align to blockSize of cipher. - // Change it, if is not AES - return kAesPadAllign - (packSize32 & (kAesPadAllign - 1)); - } - CDecoder(); - ~CDecoder() { Wipe(); } - void Wipe() - { - Z7_memset_0_ARRAY(_iv); - _key.Wipe(); - } -}; - -}} - -#endif +// Crypto/ZipStrong.h + +#ifndef ZIP7_INC_CRYPTO_ZIP_STRONG_H +#define ZIP7_INC_CRYPTO_ZIP_STRONG_H + +#include "../../Common/MyBuffer2.h" + +#include "../IPassword.h" + +#include "MyAes.h" + +namespace NCrypto { +namespace NZipStrong { + +/* ICompressFilter::Init() does nothing for this filter. + Call to init: + Decoder: + [CryptoSetPassword();] + ReadHeader(); + [CryptoSetPassword();] Init_and_CheckPassword(); + [CryptoSetPassword();] Init_and_CheckPassword(); +*/ + +struct CKeyInfo +{ + Byte MasterKey[32]; + UInt32 KeySize; + + void SetPassword(const Byte *data, UInt32 size); + + void Wipe() + { + Z7_memset_0_ARRAY(MasterKey); + } +}; + + +const unsigned kAesPadAllign = AES_BLOCK_SIZE; + +Z7_CLASS_IMP_COM_2( + CDecoder + , ICompressFilter + , ICryptoSetPassword +) + CAesCbcDecoder *_cbcDecoder; + CMyComPtr _aesFilter; + CKeyInfo _key; + CAlignedBuffer _bufAligned; + + UInt32 _ivSize; + Byte _iv[16]; + UInt32 _remSize; +public: + HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize); + HRESULT Init_and_CheckPassword(bool &passwOK); + UInt32 GetPadSize(UInt32 packSize32) const + { + // Padding is to align to blockSize of cipher. + // Change it, if is not AES + return kAesPadAllign - (packSize32 & (kAesPadAllign - 1)); + } + CDecoder(); + ~CDecoder() { Wipe(); } + void Wipe() + { + Z7_memset_0_ARRAY(_iv); + _key.Wipe(); + } +}; + +}} + +#endif diff --git a/CPP/7zip/GuiCommon.rc b/CPP/7zip/GuiCommon.rc index 525dc7c6a..bf8ad8bc0 100644 --- a/CPP/7zip/GuiCommon.rc +++ b/CPP/7zip/GuiCommon.rc @@ -1,119 +1,119 @@ -#include - -// #include -// #include - -// for Windows CE: -#include - - -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#undef m -#undef bxs -#undef bys -#undef bxsDots -#undef y -#undef xc -#undef yc -#undef xs -#undef ys -#undef bx -#undef bx1 -#undef bx2 -#undef bx3 -#undef by -#undef by1 -#undef by2 -#undef by3 -#undef gSpace -#undef gSize -#undef marg2 -#undef marg3 - -#undef MY_DIALOG -#undef MY_RESIZE_DIALOG -#undef MY_PAGE - -#define m 8 -#define bxs 64 -#define bys 16 -#define bxsDots 20 - -#define xs (xc + m + m) -#define ys (yc + m + m) - -#define bx1 (xs - m - bxs) -#define bx2 (bx1 - m - bxs) -#define bx3 (bx2 - m - bxs) -#define bx bx1 - -#define by1 (ys - m - bys) -#define by2 (by1 - m - bys) -#define by by1 - - -#define MY_MODAL_DIALOG_STYLE STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -#define MY_MODAL_RESIZE_DIALOG_STYLE MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX | WS_THICKFRAME - -#define MY_PAGE_STYLE STYLE WS_CHILD | WS_DISABLED | WS_CAPTION - -#define MY_FONT FONT 8, "MS Shell Dlg" - -#define MY_MODAL_DIALOG_POSTFIX 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT - -#define SMALL_PAGE_SIZE_X 120 - -// #define MY_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -// #define MY_RESIZE_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -#define MY_PAGE_POSTFIX 0, 0, xs, ys MY_PAGE_STYLE MY_FONT -#define MY_PAGE DIALOG MY_PAGE_POSTFIX - -#define OK_CANCEL \ - DEFPUSHBUTTON "OK", IDOK, bx2, by, bxs, bys \ - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys - -#define CONTINUE_CANCEL \ - DEFPUSHBUTTON "Continue",IDCONTINUE, bx2, by, bxs, bys \ - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys - -#define MY_BUTTON__CLOSE \ - DEFPUSHBUTTON "&Close", IDCLOSE, bx1, by, bxs, bys - - -#define MY_COMBO CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP -#define MY_COMBO_SORTED MY_COMBO | CBS_SORT -#define MY_COMBO_WITH_EDIT CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - -#define MY_CHECKBOX "Button", BS_AUTOCHECKBOX | WS_TABSTOP - -#define cboxColonSize 18 -#define colonString ":" - -#define MY_CONTROL_CHECKBOX(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_CHECKBOX, _x,_y,_xsize,10 -#define MY_CONTROL_CHECKBOX_2LINES(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_CHECKBOX | BS_MULTILINE, _x,_y,_xsize,16 -#define MY_CONTROL_CHECKBOX_COLON(_id,_x,_y) MY_CONTROL_CHECKBOX( colonString, _id, _x,_y,cboxColonSize) - -#define MY_AUTORADIOBUTTON "Button", BS_AUTORADIOBUTTON -#define MY_AUTORADIOBUTTON_GROUP MY_AUTORADIOBUTTON | WS_GROUP - -#define MY_CONTROL_AUTORADIOBUTTON(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_AUTORADIOBUTTON, _x,_y,_xsize,10 -#define MY_CONTROL_AUTORADIOBUTTON_GROUP(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_AUTORADIOBUTTON_GROUP, _x,_y,_xsize,10 - -#define MY_TEXT_NOPREFIX 8, SS_NOPREFIX - - -// WS_EX_CLIENTEDGE -#define MY_CONTROL_EDIT_WITH_SPIN(_id_edit, _id_spin, _text, _x, _y, _xSize) \ - EDITTEXT _id_edit, _x, _y, _xSize, 12, ES_CENTER | ES_NUMBER | ES_AUTOHSCROLL \ - CONTROL _text, _id_spin, L"msctls_updown32", \ - UDS_SETBUDDYINT \ - | UDS_ALIGNRIGHT \ - | UDS_AUTOBUDDY \ - | UDS_ARROWKEYS \ - | UDS_NOTHOUSANDS, \ - _x + _xSize, _y, 8, 12 // these values are unused - - -#define OPTIONS_PAGE_XC_SIZE 280 -#define OPTIONS_PAGE_YC_SIZE 280 +#include + +// #include +// #include + +// for Windows CE: +#include + + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#undef m +#undef bxs +#undef bys +#undef bxsDots +#undef y +#undef xc +#undef yc +#undef xs +#undef ys +#undef bx +#undef bx1 +#undef bx2 +#undef bx3 +#undef by +#undef by1 +#undef by2 +#undef by3 +#undef gSpace +#undef gSize +#undef marg2 +#undef marg3 + +#undef MY_DIALOG +#undef MY_RESIZE_DIALOG +#undef MY_PAGE + +#define m 8 +#define bxs 64 +#define bys 16 +#define bxsDots 20 + +#define xs (xc + m + m) +#define ys (yc + m + m) + +#define bx1 (xs - m - bxs) +#define bx2 (bx1 - m - bxs) +#define bx3 (bx2 - m - bxs) +#define bx bx1 + +#define by1 (ys - m - bys) +#define by2 (by1 - m - bys) +#define by by1 + + +#define MY_MODAL_DIALOG_STYLE STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +#define MY_MODAL_RESIZE_DIALOG_STYLE MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX | WS_THICKFRAME + +#define MY_PAGE_STYLE STYLE WS_CHILD | WS_DISABLED | WS_CAPTION + +#define MY_FONT FONT 8, "MS Shell Dlg" + +#define MY_MODAL_DIALOG_POSTFIX 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT + +#define SMALL_PAGE_SIZE_X 120 + +// #define MY_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +// #define MY_RESIZE_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +#define MY_PAGE_POSTFIX 0, 0, xs, ys MY_PAGE_STYLE MY_FONT +#define MY_PAGE DIALOG MY_PAGE_POSTFIX + +#define OK_CANCEL \ + DEFPUSHBUTTON "OK", IDOK, bx2, by, bxs, bys \ + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys + +#define CONTINUE_CANCEL \ + DEFPUSHBUTTON "Continue",IDCONTINUE, bx2, by, bxs, bys \ + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys + +#define MY_BUTTON__CLOSE \ + DEFPUSHBUTTON "&Close", IDCLOSE, bx1, by, bxs, bys + + +#define MY_COMBO CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +#define MY_COMBO_SORTED MY_COMBO | CBS_SORT +#define MY_COMBO_WITH_EDIT CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + +#define MY_CHECKBOX "Button", BS_AUTOCHECKBOX | WS_TABSTOP + +#define cboxColonSize 18 +#define colonString ":" + +#define MY_CONTROL_CHECKBOX(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_CHECKBOX, _x,_y,_xsize,10 +#define MY_CONTROL_CHECKBOX_2LINES(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_CHECKBOX | BS_MULTILINE, _x,_y,_xsize,16 +#define MY_CONTROL_CHECKBOX_COLON(_id,_x,_y) MY_CONTROL_CHECKBOX( colonString, _id, _x,_y,cboxColonSize) + +#define MY_AUTORADIOBUTTON "Button", BS_AUTORADIOBUTTON +#define MY_AUTORADIOBUTTON_GROUP MY_AUTORADIOBUTTON | WS_GROUP + +#define MY_CONTROL_AUTORADIOBUTTON(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_AUTORADIOBUTTON, _x,_y,_xsize,10 +#define MY_CONTROL_AUTORADIOBUTTON_GROUP(_text,_id,_x,_y,_xsize) CONTROL _text, _id, MY_AUTORADIOBUTTON_GROUP, _x,_y,_xsize,10 + +#define MY_TEXT_NOPREFIX 8, SS_NOPREFIX + + +// WS_EX_CLIENTEDGE +#define MY_CONTROL_EDIT_WITH_SPIN(_id_edit, _id_spin, _text, _x, _y, _xSize) \ + EDITTEXT _id_edit, _x, _y, _xSize, 12, ES_CENTER | ES_NUMBER | ES_AUTOHSCROLL \ + CONTROL _text, _id_spin, L"msctls_updown32", \ + UDS_SETBUDDYINT \ + | UDS_ALIGNRIGHT \ + | UDS_AUTOBUDDY \ + | UDS_ARROWKEYS \ + | UDS_NOTHOUSANDS, \ + _x + _xSize, _y, 8, 12 // these values are unused + + +#define OPTIONS_PAGE_XC_SIZE 300 +#define OPTIONS_PAGE_YC_SIZE 280 diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt index b2d2086cf..fbae89c52 100644 --- a/CPP/7zip/Guid.txt +++ b/CPP/7zip/Guid.txt @@ -1,241 +1,243 @@ -{23170F69-40C1-278A-0000-00yy00xx0000} - -00 IProgress.h - - 05 IProgress - // 050002 IProgress2 - -01 IFolderArchive.h - - // 05 IArchiveFolder // old - // 06 IInFolderArchive // old - 07 IFileExtractCallback.h::IFolderArchiveExtractCallback - 08 IFileExtractCallback.h::IFolderArchiveExtractCallback2 - // 0A IOutFolderArchive - 0B IFolderArchiveUpdateCallback - 0C Agent.h::IArchiveFolderInternal - 0D IArchiveFolder - 0E IInFolderArchive - 0F IOutFolderArchive - 10 IFolderArchiveUpdateCallback2 - 11 IFolderScanProgress - 12 IFolderSetZoneIdMode - - 20 IFileExtractCallback.h::IGetProp - 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old) - 31 IFileExtractCallback.h::IFolderExtractToStreamCallback (new 21.04) - -03 IStream.h - - 01 ISequentialInStream - 02 ISequentialOutStream - 03 IInStream - 04 IOutStream - - 06 IStreamGetSize - 07 IOutStreamFinish - 08 IStreamGetProps - 09 IStreamGetProps2 - 0A IStreamGetProp - - 10 IStreamSetRestriction - - -04 ICoder.h - - 04 ICompressProgressInfo - 05 ICompressCoder - 18 ICompressCoder2 - 1F ICompressSetCoderPropertiesOpt - 20 ICompressSetCoderProperties - 21 ICompressSetDecoderProperties // - 22 ICompressSetDecoderProperties2 - 23 ICompressWriteCoderProperties - 24 ICompressGetInStreamProcessedSize - 25 ICompressSetCoderMt - 26 ICompressSetFinishMode - 27 ICompressGetInStreamProcessedSize2 - 28 ICompressSetMemLimit - 29 ICompressReadUnusedFromInBuf - - 30 ICompressGetSubStreamSize - 31 ICompressSetInStream - 32 ICompressSetOutStream -// 33 ICompressSetInStreamSize - 34 ICompressSetOutStreamSize - 35 ICompressSetBufSize - 36 ICompressInitEncoder - 37 ICompressSetInStream2 -// 38 ICompressSetOutStream2 -// 39 SetInStreamSize2 -// 3A SetOutStreamSize2 - - 40 ICompressFilter - 60 ICompressCodecsInfo - 61 ISetCompressCodecsInfo - 80 ICryptoProperties - 88 ICryptoResetSalt - 8C ICryptoResetInitVector - 90 ICryptoSetPassword - A0 ICryptoSetCRC - C0 IHasher - C1 IHashers - - -05 IPassword.h - - 10 ICryptoGetTextPassword - 11 ICryptoGetTextPassword2 - - -06 IArchive.h - - 03 ISetProperties - 04 IArchiveKeepModeForNextOpen - 05 IArchiveAllowTail - - 09 IArchiveRequestMemoryUseCallback - - 10 IArchiveOpenCallback - - 20 IArchiveExtractCallback - 21 IArchiveExtractCallbackMessage (deprecated in v23) - 22 IArchiveExtractCallbackMessage2 (new in v23) - - 30 IArchiveOpenVolumeCallback - 40 IInArchiveGetStream - 50 IArchiveOpenSetSubArchiveName - 60 IInArchive - 61 IArchiveOpenSeq - 70 IArchiveGetRawProps - 71 IArchiveGetRootProps - - 80 IArchiveUpdateCallback - 82 IArchiveUpdateCallback2 - 83 IArchiveUpdateCallbackFile - 84 IArchiveGetDiskProperty - 85 IArchiveUpdateCallbackArcProp (Reserved) - - - A0 IOutArchive - - - -08 IFolder.h - - 00 IFolderFolder - 01 IEnumProperties - 02 IFolderGetTypeID - 03 IFolderGetPath - 04 IFolderWasChanged - 05 // IFolderReload - 06 // IFolderOperations old - 07 IFolderGetSystemIconIndex - 08 IFolderGetItemFullSize - 09 IFolderClone - 0A IFolderSetFlatMode - 0B IFolderOperationsExtractCallback - 0C // - 0D // - 0E IFolderProperties - 0F - 10 IFolderArcProps - 11 IGetFolderArcProps - 12 // IFolderOperations - 13 IFolderOperations - 14 IFolderCalcItemFullSize - 15 IFolderCompare - 16 IFolderGetItemName - 17 IFolderAltStreams - - -09 IFolder.h :: FOLDER_MANAGER_INTERFACE - - 00 - 04 // old IFolderManager - 05 IFolderManager - - -// 0A PluginInterface.h - 00 IInitContextMenu - 01 IPluginOptionsCallback - 02 IPluginOptions - - -Handler GUIDs: - -{23170F69-40C1-278A-1000-000110xx0000} - - 01 Zip - 02 BZip2 - 03 Rar - 04 Arj - 05 Z - 06 Lzh - 07 7z - 08 Cab - 09 Nsis - 0A lzma - 0B lzma86 - 0C xz - 0D ppmd - 0E zstd - - BF LVM - C0 AVB - C1 LP - C2 Sparse - C3 APFS - C4 Vhdx - C5 Base64 - C6 COFF - C7 Ext - C8 VMDK - C9 VDI - CA Qcow - CB GPT - CC Rar5 - CD IHex - CE Hxs - CF TE - D0 UEFIc - D1 UEFIs - D2 SquashFS - D3 CramFS - D4 APM - D5 Mslz - D6 Flv - D7 Swf - D8 Swfc - D9 Ntfs - DA Fat - DB Mbr - DC Vhd - DD Pe - DE Elf - DF Mach-O - E0 Udf - E1 Xar - E2 Mub - E3 Hfs - E4 Dmg - E5 Compound - E6 Wim - E7 Iso - E8 - E9 Chm - EA Split - EB Rpm - EC Deb - ED Cpio - EE Tar - EF GZip - -{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu - -// {23170F69-40C1-278A-1000-000100030000} // CAgentArchiveHandler -// {23170F69-40C1-278B- old codecs clsids -// {23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions - -{23170F69-40C1-2790-id} Codec Decoders -{23170F69-40C1-2791-id} Codec Encoders -{23170F69-40C1-2792-id} Hashers +{23170F69-40C1-278A-0000-00yy00xx0000} + +00 IProgress.h + + 05 IProgress + // 050002 IProgress2 + +01 IFolderArchive.h + + // 05 IArchiveFolder // old + // 06 IInFolderArchive // old + 07 IFileExtractCallback.h::IFolderArchiveExtractCallback + 08 IFileExtractCallback.h::IFolderArchiveExtractCallback2 + // 0A IOutFolderArchive + 0B IFolderArchiveUpdateCallback + 0C Agent.h::IArchiveFolderInternal + 0D IArchiveFolder + 0E IInFolderArchive + 0F IOutFolderArchive + 10 IFolderArchiveUpdateCallback2 + 11 IFolderScanProgress + 12 IFolderSetZoneIdMode + 13 IFolderSetZoneIdFile + 14 IFolderArchiveUpdateCallback_MoveArc + + 20 IFileExtractCallback.h::IGetProp + 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old) + 31 IFileExtractCallback.h::IFolderExtractToStreamCallback (new 21.04) + +03 IStream.h + + 01 ISequentialInStream + 02 ISequentialOutStream + 03 IInStream + 04 IOutStream + + 06 IStreamGetSize + 07 IOutStreamFinish + 08 IStreamGetProps + 09 IStreamGetProps2 + 0A IStreamGetProp + + 10 IStreamSetRestriction + + +04 ICoder.h + + 04 ICompressProgressInfo + 05 ICompressCoder + 18 ICompressCoder2 + 1F ICompressSetCoderPropertiesOpt + 20 ICompressSetCoderProperties + 21 ICompressSetDecoderProperties // + 22 ICompressSetDecoderProperties2 + 23 ICompressWriteCoderProperties + 24 ICompressGetInStreamProcessedSize + 25 ICompressSetCoderMt + 26 ICompressSetFinishMode + 27 ICompressGetInStreamProcessedSize2 + 28 ICompressSetMemLimit + 29 ICompressReadUnusedFromInBuf + + 30 ICompressGetSubStreamSize + 31 ICompressSetInStream + 32 ICompressSetOutStream +// 33 ICompressSetInStreamSize + 34 ICompressSetOutStreamSize + 35 ICompressSetBufSize + 36 ICompressInitEncoder + 37 ICompressSetInStream2 +// 38 ICompressSetOutStream2 +// 39 SetInStreamSize2 +// 3A SetOutStreamSize2 + + 40 ICompressFilter + 60 ICompressCodecsInfo + 61 ISetCompressCodecsInfo + 80 ICryptoProperties + 88 ICryptoResetSalt + 8C ICryptoResetInitVector + 90 ICryptoSetPassword + A0 ICryptoSetCRC + C0 IHasher + C1 IHashers + + +05 IPassword.h + + 10 ICryptoGetTextPassword + 11 ICryptoGetTextPassword2 + + +06 IArchive.h + + 03 ISetProperties + 04 IArchiveKeepModeForNextOpen + 05 IArchiveAllowTail + + 09 IArchiveRequestMemoryUseCallback + + 10 IArchiveOpenCallback + + 20 IArchiveExtractCallback + 21 IArchiveExtractCallbackMessage (deprecated in v23) + 22 IArchiveExtractCallbackMessage2 (new in v23) + + 30 IArchiveOpenVolumeCallback + 40 IInArchiveGetStream + 50 IArchiveOpenSetSubArchiveName + 60 IInArchive + 61 IArchiveOpenSeq + 70 IArchiveGetRawProps + 71 IArchiveGetRootProps + + 80 IArchiveUpdateCallback + 82 IArchiveUpdateCallback2 + 83 IArchiveUpdateCallbackFile + 84 IArchiveGetDiskProperty + 85 IArchiveUpdateCallbackArcProp (Reserved) + + + A0 IOutArchive + + + +08 IFolder.h + + 00 IFolderFolder + 01 IEnumProperties + 02 IFolderGetTypeID + 03 IFolderGetPath + 04 IFolderWasChanged + 05 // IFolderReload + 06 // IFolderOperations old + 07 IFolderGetSystemIconIndex + 08 IFolderGetItemFullSize + 09 IFolderClone + 0A IFolderSetFlatMode + 0B IFolderOperationsExtractCallback + 0C // + 0D // + 0E IFolderProperties + 0F + 10 IFolderArcProps + 11 IGetFolderArcProps + 12 // IFolderOperations + 13 IFolderOperations + 14 IFolderCalcItemFullSize + 15 IFolderCompare + 16 IFolderGetItemName + 17 IFolderAltStreams + + +09 IFolder.h :: FOLDER_MANAGER_INTERFACE + + 00 - 04 // old IFolderManager + 05 IFolderManager + + +// 0A PluginInterface.h + 00 IInitContextMenu + 01 IPluginOptionsCallback + 02 IPluginOptions + + +Handler GUIDs: + +{23170F69-40C1-278A-1000-000110xx0000} + + 01 Zip + 02 BZip2 + 03 Rar + 04 Arj + 05 Z + 06 Lzh + 07 7z + 08 Cab + 09 Nsis + 0A lzma + 0B lzma86 + 0C xz + 0D ppmd + 0E zstd + + BF LVM + C0 AVB + C1 LP + C2 Sparse + C3 APFS + C4 Vhdx + C5 Base64 + C6 COFF + C7 Ext + C8 VMDK + C9 VDI + CA Qcow + CB GPT + CC Rar5 + CD IHex + CE Hxs + CF TE + D0 UEFIc + D1 UEFIs + D2 SquashFS + D3 CramFS + D4 APM + D5 Mslz + D6 Flv + D7 Swf + D8 Swfc + D9 Ntfs + DA Fat + DB Mbr + DC Vhd + DD Pe + DE Elf + DF Mach-O + E0 Udf + E1 Xar + E2 Mub + E3 Hfs + E4 Dmg + E5 Compound + E6 Wim + E7 Iso + E8 + E9 Chm + EA Split + EB Rpm + EC Deb + ED Cpio + EE Tar + EF GZip + +{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu + +// {23170F69-40C1-278A-1000-000100030000} // CAgentArchiveHandler +// {23170F69-40C1-278B- old codecs clsids +// {23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions + +{23170F69-40C1-2790-id} Codec Decoders +{23170F69-40C1-2791-id} Codec Encoders +{23170F69-40C1-2792-id} Hashers diff --git a/CPP/7zip/ICoder.h b/CPP/7zip/ICoder.h index def2fc3a1..aec2834ad 100644 --- a/CPP/7zip/ICoder.h +++ b/CPP/7zip/ICoder.h @@ -1,477 +1,477 @@ -// ICoder.h - -#ifndef ZIP7_INC_ICODER_H -#define ZIP7_INC_ICODER_H - -#include "IStream.h" - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACE_CONSTR_CODER(i, n) \ - Z7_DECL_IFACE_7ZIP(i, 4, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -#define Z7_IFACEM_ICompressProgressInfo(x) \ - x(SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -Z7_IFACE_CONSTR_CODER(ICompressProgressInfo, 0x04) - /* - SetRatioInfo() - (inSize) can be NULL, if unknown - (outSize) can be NULL, if unknown - returns: - S_OK - E_ABORT : Break by user - another error codes - */ - -#define Z7_IFACEM_ICompressCoder(x) \ - x(Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, \ - const UInt64 *inSize, const UInt64 *outSize, \ - ICompressProgressInfo *progress)) -Z7_IFACE_CONSTR_CODER(ICompressCoder, 0x05) - -#define Z7_IFACEM_ICompressCoder2(x) \ - x(Code(ISequentialInStream * const *inStreams, const UInt64 *const *inSizes, UInt32 numInStreams, \ - ISequentialOutStream *const *outStreams, const UInt64 *const *outSizes, UInt32 numOutStreams, \ - ICompressProgressInfo *progress)) -Z7_IFACE_CONSTR_CODER(ICompressCoder2, 0x18) - -/* - ICompressCoder::Code - ICompressCoder2::Code - - returns: - S_OK : OK - S_FALSE : data error (for decoders) - E_OUTOFMEMORY : memory allocation error - E_NOTIMPL : unsupported encoding method (for decoders) - another error code : some error. For example, it can be error code received from inStream or outStream function. - - Parameters: - (inStream != NULL) - (outStream != NULL) - - if (inSize != NULL) - { - Encoders in 7-Zip ignore (inSize). - Decoder can use (*inSize) to check that stream was decoded correctly. - Some decoders in 7-Zip check it, if (full_decoding mode was set via ICompressSetFinishMode) - } - - If it's required to limit the reading from input stream (inStream), it can - be done with ISequentialInStream implementation. - - if (outSize != NULL) - { - Encoders in 7-Zip ignore (outSize). - Decoder unpacks no more than (*outSize) bytes. - } - - (progress == NULL) is allowed. - - - Decoding with Code() function - ----------------------------- - - You can request some interfaces before decoding - - ICompressSetDecoderProperties2 - - ICompressSetFinishMode - - If you need to decode full stream: - { - 1) try to set full_decoding mode with ICompressSetFinishMode::SetFinishMode(1); - 2) call the Code() function with specified (inSize) and (outSize), if these sizes are known. - } - - If you need to decode only part of stream: - { - 1) try to set partial_decoding mode with ICompressSetFinishMode::SetFinishMode(0); - 2) Call the Code() function with specified (inSize = NULL) and specified (outSize). - } - - Encoding with Code() function - ----------------------------- - - You can request some interfaces : - - ICompressSetCoderProperties - use it before encoding to set properties - - ICompressWriteCoderProperties - use it before or after encoding to request encoded properties. - - ICompressCoder2 is used when (numInStreams != 1 || numOutStreams != 1) - The rules are similar to ICompressCoder rules -*/ - - -namespace NCoderPropID -{ - enum EEnum - { - kDefaultProp = 0, - kDictionarySize, // VT_UI4 - kUsedMemorySize, // VT_UI4 - kOrder, // VT_UI4 - kBlockSize, // VT_UI4 or VT_UI8 - kPosStateBits, // VT_UI4 - kLitContextBits, // VT_UI4 - kLitPosBits, // VT_UI4 - kNumFastBytes, // VT_UI4 - kMatchFinder, // VT_BSTR - kMatchFinderCycles, // VT_UI4 - kNumPasses, // VT_UI4 - kAlgorithm, // VT_UI4 - kNumThreads, // VT_UI4 - kEndMarker, // VT_BOOL - kLevel, // VT_UI4 - kReduceSize, // VT_UI8 : it's estimated size of largest data stream that will be compressed - // encoder can use this value to reduce dictionary size and allocate data buffers - - kExpectedDataSize, // VT_UI8 : for ICompressSetCoderPropertiesOpt : - // it's estimated size of current data stream - // real data size can differ from that size - // encoder can use this value to optimize encoder initialization - - kBlockSize2, // VT_UI4 or VT_UI8 - kCheckSize, // VT_UI4 : size of digest in bytes - kFilter, // VT_BSTR - kMemUse, // VT_UI8 - kAffinity, // VT_UI8 - kBranchOffset, // VT_UI4 - kHashBits, // VT_UI4 - /* - // kHash3Bits, // VT_UI4 - // kHash2Bits, // VT_UI4 - // kChainBits, // VT_UI4 - kChainSize, // VT_UI4 - kNativeLevel, // VT_UI4 - kFast, // VT_UI4 - kMinMatch, // VT_UI4 The minimum slen is 3 and the maximum is 7. - kOverlapLog, // VT_UI4 The minimum ovlog is 0 and the maximum is 9. (default: 6) - kRowMatchFinder, // VT_BOOL - kLdmEnable, // VT_BOOL - // kLdmWindowSizeLog, // VT_UI4 - kLdmWindowSize, // VT_UI4 - kLdmHashLog, // VT_UI4 The minimum ldmhlog is 6 and the maximum is 26 (default: 20). - kLdmMinMatchLength, // VT_UI4 The minimum ldmslen is 4 and the maximum is 4096 (default: 64). - kLdmBucketSizeLog, // VT_UI4 The minimum ldmblog is 0 and the maximum is 8 (default: 3). - kLdmHashRateLog, // VT_UI4 The default value is wlog - ldmhlog. - kWriteUnpackSizeFlag, // VT_BOOL - kUsePledged, // VT_BOOL - kUseSizeHintPledgedForSmall, // VT_BOOL - kUseSizeHintForEach, // VT_BOOL - kUseSizeHintGlobal, // VT_BOOL - kParamSelectMode, // VT_UI4 - // kSearchLog, // VT_UI4 The minimum slog is 1 and the maximum is 26 - // kTargetLen, // VT_UI4 The minimum tlen is 0 and the maximum is 999. - */ - k_NUM_DEFINED - }; -} - -#define Z7_IFACEM_ICompressSetCoderPropertiesOpt(x) \ - x(SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -Z7_IFACE_CONSTR_CODER(ICompressSetCoderPropertiesOpt, 0x1F) - - -#define Z7_IFACEM_ICompressSetCoderProperties(x) \ - x(SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) -Z7_IFACE_CONSTR_CODER(ICompressSetCoderProperties, 0x20) - -/* -#define Z7_IFACEM_ICompressSetDecoderProperties(x) \ - x(SetDecoderProperties(ISequentialInStream *inStream)) -Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties, 0x21) -*/ - -#define Z7_IFACEM_ICompressSetDecoderProperties2(x) \ - x(SetDecoderProperties2(const Byte *data, UInt32 size)) -Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties2, 0x22) - /* returns: - S_OK - E_NOTIMP : unsupported properties - E_INVALIDARG : incorrect (or unsupported) properties - E_OUTOFMEMORY : memory allocation error - */ - - -#define Z7_IFACEM_ICompressWriteCoderProperties(x) \ - x(WriteCoderProperties(ISequentialOutStream *outStream)) -Z7_IFACE_CONSTR_CODER(ICompressWriteCoderProperties, 0x23) - -#define Z7_IFACEM_ICompressGetInStreamProcessedSize(x) \ - x(GetInStreamProcessedSize(UInt64 *value)) -Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize, 0x24) - -#define Z7_IFACEM_ICompressSetCoderMt(x) \ - x(SetNumberOfThreads(UInt32 numThreads)) -Z7_IFACE_CONSTR_CODER(ICompressSetCoderMt, 0x25) - -#define Z7_IFACEM_ICompressSetFinishMode(x) \ - x(SetFinishMode(UInt32 finishMode)) -Z7_IFACE_CONSTR_CODER(ICompressSetFinishMode, 0x26) - /* finishMode: - 0 : partial decoding is allowed. It's default mode for ICompressCoder::Code(), if (outSize) is defined. - 1 : full decoding. The stream must be finished at the end of decoding. */ - -#define Z7_IFACEM_ICompressGetInStreamProcessedSize2(x) \ - x(GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)) -Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize2, 0x27) - -#define Z7_IFACEM_ICompressSetMemLimit(x) \ - x(SetMemLimit(UInt64 memUsage)) -Z7_IFACE_CONSTR_CODER(ICompressSetMemLimit, 0x28) - - -/* - ICompressReadUnusedFromInBuf is supported by ICoder object - call ReadUnusedFromInBuf() after ICoder::Code(inStream, ...). - ICoder::Code(inStream, ...) decodes data, and the ICoder object is allowed - to read from inStream to internal buffers more data than minimal data required for decoding. - So we can call ReadUnusedFromInBuf() from same ICoder object to read unused input - data from the internal buffer. - in ReadUnusedFromInBuf(): the Coder is not allowed to use (ISequentialInStream *inStream) object, that was sent to ICoder::Code(). -*/ -#define Z7_IFACEM_ICompressReadUnusedFromInBuf(x) \ - x(ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) -Z7_IFACE_CONSTR_CODER(ICompressReadUnusedFromInBuf, 0x29) - - -#define Z7_IFACEM_ICompressGetSubStreamSize(x) \ - x(GetSubStreamSize(UInt64 subStream, UInt64 *value)) -Z7_IFACE_CONSTR_CODER(ICompressGetSubStreamSize, 0x30) - /* returns: - S_OK : (*value) contains the size or estimated size (can be incorrect size) - S_FALSE : size is undefined - E_NOTIMP : the feature is not implemented - Let's (read_size) is size of data that was already read by ISequentialInStream::Read(). - The caller should call GetSubStreamSize() after each Read() and check sizes: - if (start_of_subStream + *value < read_size) - { - // (*value) is correct, and it's allowed to call GetSubStreamSize() for next subStream: - start_of_subStream += *value; - subStream++; - } - */ - -#define Z7_IFACEM_ICompressSetInStream(x) \ - x(SetInStream(ISequentialInStream *inStream)) \ - x(ReleaseInStream()) -Z7_IFACE_CONSTR_CODER(ICompressSetInStream, 0x31) - -#define Z7_IFACEM_ICompressSetOutStream(x) \ - x(SetOutStream(ISequentialOutStream *outStream)) \ - x(ReleaseOutStream()) -Z7_IFACE_CONSTR_CODER(ICompressSetOutStream, 0x32) - -/* -#define Z7_IFACEM_ICompressSetInStreamSize(x) \ - x(SetInStreamSize(const UInt64 *inSize)) \ -Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize, 0x33) -*/ - -#define Z7_IFACEM_ICompressSetOutStreamSize(x) \ - x(SetOutStreamSize(const UInt64 *outSize)) -Z7_IFACE_CONSTR_CODER(ICompressSetOutStreamSize, 0x34) - /* That function initializes decoder structures. - Call this function only for stream version of decoder. - if (outSize == NULL), then output size is unknown - if (outSize != NULL), then the decoder must stop decoding after (*outSize) bytes. */ - -#define Z7_IFACEM_ICompressSetBufSize(x) \ - x(SetInBufSize(UInt32 streamIndex, UInt32 size)) \ - x(SetOutBufSize(UInt32 streamIndex, UInt32 size)) - -Z7_IFACE_CONSTR_CODER(ICompressSetBufSize, 0x35) - -#define Z7_IFACEM_ICompressInitEncoder(x) \ - x(InitEncoder()) -Z7_IFACE_CONSTR_CODER(ICompressInitEncoder, 0x36) - /* That function initializes encoder structures. - Call this function only for stream version of encoder. */ - -#define Z7_IFACEM_ICompressSetInStream2(x) \ - x(SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)) \ - x(ReleaseInStream2(UInt32 streamIndex)) -Z7_IFACE_CONSTR_CODER(ICompressSetInStream2, 0x37) - -/* -#define Z7_IFACEM_ICompressSetOutStream2(x) \ - x(SetOutStream2(UInt32 streamIndex, ISequentialOutStream *outStream)) - x(ReleaseOutStream2(UInt32 streamIndex)) -Z7_IFACE_CONSTR_CODER(ICompressSetOutStream2, 0x38) - -#define Z7_IFACEM_ICompressSetInStreamSize2(x) \ - x(SetInStreamSize2(UInt32 streamIndex, const UInt64 *inSize)) -Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize2, 0x39) -*/ - -/* -#define Z7_IFACEM_ICompressInSubStreams(x) \ - x(GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream)) -Z7_IFACE_CONSTR_CODER(ICompressInSubStreams, 0x3A) - -#define Z7_IFACEM_ICompressOutSubStreams(x) \ - x(GetNextOutSubStream(UInt64 *streamIndexRes, ISequentialOutStream **stream)) -Z7_IFACE_CONSTR_CODER(ICompressOutSubStreams, 0x3B) -*/ - -/* - ICompressFilter - Filter(Byte *data, UInt32 size) - (size) - converts as most as possible bytes required for fast processing. - Some filters have (smallest_fast_block). - For example, (smallest_fast_block == 16) for AES CBC/CTR filters. - If data stream is not finished, caller must call Filter() for larger block: - where (size >= smallest_fast_block). - if (size >= smallest_fast_block) - { - The filter can leave some bytes at the end of data without conversion: - if there are data alignment reasons or speed reasons. - The caller can read additional data from stream and call Filter() again. - } - If data stream was finished, caller can call Filter() for (size < smallest_fast_block) - - (data) parameter: - Some filters require alignment for any Filter() call: - 1) (stream_offset % alignment_size) == (data % alignment_size) - 2) (alignment_size == 2^N) - where (stream_offset) - is the number of bytes that were already filtered before. - The callers of Filter() are required to meet these requirements. - (alignment_size) can be different: - 16 : for AES filters - 4 or 2 : for some branch convert filters - 1 : for another filters - (alignment_size >= 16) is enough for all current filters of 7-Zip. - But the caller can use larger (alignment_size). - Recommended alignment for (data) of Filter() call is (alignment_size == 64). - Also it's recommended to use aligned value for (size): - (size % alignment_size == 0), - if it's not last call of Filter() for current stream. - - returns: (outSize): - if (outSize == 0) : Filter have not converted anything. - So the caller can stop processing, if data stream was finished. - if (outSize <= size) : Filter have converted outSize bytes - if (outSize > size) : Filter have not converted anything. - and it needs at least outSize bytes to convert one block - (it's for crypto block algorithms). -*/ - -#define Z7_IFACEM_ICompressFilter(x) \ - x(Init()) \ - x##2(UInt32, Filter(Byte *data, UInt32 size)) -Z7_IFACE_CONSTR_CODER(ICompressFilter, 0x40) - - -#define Z7_IFACEM_ICompressCodecsInfo(x) \ - x(GetNumMethods(UInt32 *numMethods)) \ - x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - x(CreateDecoder(UInt32 index, const GUID *iid, void* *coder)) \ - x(CreateEncoder(UInt32 index, const GUID *iid, void* *coder)) -Z7_IFACE_CONSTR_CODER(ICompressCodecsInfo, 0x60) - -#define Z7_IFACEM_ISetCompressCodecsInfo(x) \ - x(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) -Z7_IFACE_CONSTR_CODER(ISetCompressCodecsInfo, 0x61) - -#define Z7_IFACEM_ICryptoProperties(x) \ - x(SetKey(const Byte *data, UInt32 size)) \ - x(SetInitVector(const Byte *data, UInt32 size)) -Z7_IFACE_CONSTR_CODER(ICryptoProperties, 0x80) - -/* - x(ResetSalt()) -Z7_IFACE_CONSTR_CODER(ICryptoResetSalt, 0x88) -*/ - -#define Z7_IFACEM_ICryptoResetInitVector(x) \ - x(ResetInitVector()) -Z7_IFACE_CONSTR_CODER(ICryptoResetInitVector, 0x8C) - /* Call ResetInitVector() only for encoding. - Call ResetInitVector() before encoding and before WriteCoderProperties(). - Crypto encoder can create random IV in that function. */ - -#define Z7_IFACEM_ICryptoSetPassword(x) \ - x(CryptoSetPassword(const Byte *data, UInt32 size)) -Z7_IFACE_CONSTR_CODER(ICryptoSetPassword, 0x90) - -#define Z7_IFACEM_ICryptoSetCRC(x) \ - x(CryptoSetCRC(UInt32 crc)) -Z7_IFACE_CONSTR_CODER(ICryptoSetCRC, 0xA0) - - -namespace NMethodPropID -{ - enum EEnum - { - kID, - kName, - kDecoder, - kEncoder, - kPackStreams, - kUnpackStreams, - kDescription, - kDecoderIsAssigned, - kEncoderIsAssigned, - kDigestSize, - kIsFilter - }; -} - -namespace NModuleInterfaceType -{ - /* - virtual destructor in IUnknown: - - no : 7-Zip (Windows) - - no : 7-Zip (Linux) (v23) in default mode - - yes : p7zip - - yes : 7-Zip (Linux) before v23 - - yes : 7-Zip (Linux) (v23), if Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN is defined - */ - const UInt32 k_IUnknown_VirtDestructor_No = 0; - const UInt32 k_IUnknown_VirtDestructor_Yes = 1; - const UInt32 k_IUnknown_VirtDestructor_ThisModule = - #if !defined(_WIN32) && defined(Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN) - k_IUnknown_VirtDestructor_Yes; - #else - k_IUnknown_VirtDestructor_No; - #endif -} - -namespace NModulePropID -{ - enum EEnum - { - kInterfaceType, // VT_UI4 - kVersion // VT_UI4 - }; -} - - -#define Z7_IFACEM_IHasher(x) \ - x##2(void, Init()) \ - x##2(void, Update(const void *data, UInt32 size)) \ - x##2(void, Final(Byte *digest)) \ - x##2(UInt32, GetDigestSize()) -Z7_IFACE_CONSTR_CODER(IHasher, 0xC0) - -#define Z7_IFACEM_IHashers(x) \ - x##2(UInt32, GetNumHashers()) \ - x(GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) \ - x(CreateHasher(UInt32 index, IHasher **hasher)) -Z7_IFACE_CONSTR_CODER(IHashers, 0xC1) - -extern "C" -{ - typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods); - typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); - typedef HRESULT (WINAPI *Func_CreateDecoder)(UInt32 index, const GUID *iid, void **outObject); - typedef HRESULT (WINAPI *Func_CreateEncoder)(UInt32 index, const GUID *iid, void **outObject); - - typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers); - - typedef HRESULT (WINAPI *Func_SetCodecs)(ICompressCodecsInfo *compressCodecsInfo); - typedef HRESULT (WINAPI *Func_GetModuleProp)(PROPID propID, PROPVARIANT *value); -} - -Z7_PURE_INTERFACES_END -#endif +// ICoder.h + +#ifndef ZIP7_INC_ICODER_H +#define ZIP7_INC_ICODER_H + +#include "IStream.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_CODER(i, n) \ + Z7_DECL_IFACE_7ZIP(i, 4, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACEM_ICompressProgressInfo(x) \ + x(SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +Z7_IFACE_CONSTR_CODER(ICompressProgressInfo, 0x04) + /* + SetRatioInfo() + (inSize) can be NULL, if unknown + (outSize) can be NULL, if unknown + returns: + S_OK + E_ABORT : Break by user + another error codes + */ + +#define Z7_IFACEM_ICompressCoder(x) \ + x(Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, \ + const UInt64 *inSize, const UInt64 *outSize, \ + ICompressProgressInfo *progress)) +Z7_IFACE_CONSTR_CODER(ICompressCoder, 0x05) + +#define Z7_IFACEM_ICompressCoder2(x) \ + x(Code(ISequentialInStream * const *inStreams, const UInt64 *const *inSizes, UInt32 numInStreams, \ + ISequentialOutStream *const *outStreams, const UInt64 *const *outSizes, UInt32 numOutStreams, \ + ICompressProgressInfo *progress)) +Z7_IFACE_CONSTR_CODER(ICompressCoder2, 0x18) + +/* + ICompressCoder::Code + ICompressCoder2::Code + + returns: + S_OK : OK + S_FALSE : data error (for decoders) + E_OUTOFMEMORY : memory allocation error + E_NOTIMPL : unsupported encoding method (for decoders) + another error code : some error. For example, it can be error code received from inStream or outStream function. + + Parameters: + (inStream != NULL) + (outStream != NULL) + + if (inSize != NULL) + { + Encoders in 7-Zip ignore (inSize). + Decoder can use (*inSize) to check that stream was decoded correctly. + Some decoders in 7-Zip check it, if (full_decoding mode was set via ICompressSetFinishMode) + } + + If it's required to limit the reading from input stream (inStream), it can + be done with ISequentialInStream implementation. + + if (outSize != NULL) + { + Encoders in 7-Zip ignore (outSize). + Decoder unpacks no more than (*outSize) bytes. + } + + (progress == NULL) is allowed. + + + Decoding with Code() function + ----------------------------- + + You can request some interfaces before decoding + - ICompressSetDecoderProperties2 + - ICompressSetFinishMode + + If you need to decode full stream: + { + 1) try to set full_decoding mode with ICompressSetFinishMode::SetFinishMode(1); + 2) call the Code() function with specified (inSize) and (outSize), if these sizes are known. + } + + If you need to decode only part of stream: + { + 1) try to set partial_decoding mode with ICompressSetFinishMode::SetFinishMode(0); + 2) Call the Code() function with specified (inSize = NULL) and specified (outSize). + } + + Encoding with Code() function + ----------------------------- + + You can request some interfaces : + - ICompressSetCoderProperties - use it before encoding to set properties + - ICompressWriteCoderProperties - use it before or after encoding to request encoded properties. + + ICompressCoder2 is used when (numInStreams != 1 || numOutStreams != 1) + The rules are similar to ICompressCoder rules +*/ + + +namespace NCoderPropID +{ + enum EEnum + { + kDefaultProp = 0, + kDictionarySize, // VT_UI4 + kUsedMemorySize, // VT_UI4 + kOrder, // VT_UI4 + kBlockSize, // VT_UI4 or VT_UI8 + kPosStateBits, // VT_UI4 + kLitContextBits, // VT_UI4 + kLitPosBits, // VT_UI4 + kNumFastBytes, // VT_UI4 + kMatchFinder, // VT_BSTR + kMatchFinderCycles, // VT_UI4 + kNumPasses, // VT_UI4 + kAlgorithm, // VT_UI4 + kNumThreads, // VT_UI4 + kEndMarker, // VT_BOOL + kLevel, // VT_UI4 + kReduceSize, // VT_UI8 : it's estimated size of largest data stream that will be compressed + // encoder can use this value to reduce dictionary size and allocate data buffers + + kExpectedDataSize, // VT_UI8 : for ICompressSetCoderPropertiesOpt : + // it's estimated size of current data stream + // real data size can differ from that size + // encoder can use this value to optimize encoder initialization + + kBlockSize2, // VT_UI4 or VT_UI8 + kCheckSize, // VT_UI4 : size of digest in bytes + kFilter, // VT_BSTR + kMemUse, // VT_UI8 + kAffinity, // VT_UI8 + kBranchOffset, // VT_UI4 + kHashBits, // VT_UI4 + /* + // kHash3Bits, // VT_UI4 + // kHash2Bits, // VT_UI4 + // kChainBits, // VT_UI4 + kChainSize, // VT_UI4 + kNativeLevel, // VT_UI4 + kFast, // VT_UI4 + kMinMatch, // VT_UI4 The minimum slen is 3 and the maximum is 7. + kOverlapLog, // VT_UI4 The minimum ovlog is 0 and the maximum is 9. (default: 6) + kRowMatchFinder, // VT_BOOL + kLdmEnable, // VT_BOOL + // kLdmWindowSizeLog, // VT_UI4 + kLdmWindowSize, // VT_UI4 + kLdmHashLog, // VT_UI4 The minimum ldmhlog is 6 and the maximum is 26 (default: 20). + kLdmMinMatchLength, // VT_UI4 The minimum ldmslen is 4 and the maximum is 4096 (default: 64). + kLdmBucketSizeLog, // VT_UI4 The minimum ldmblog is 0 and the maximum is 8 (default: 3). + kLdmHashRateLog, // VT_UI4 The default value is wlog - ldmhlog. + kWriteUnpackSizeFlag, // VT_BOOL + kUsePledged, // VT_BOOL + kUseSizeHintPledgedForSmall, // VT_BOOL + kUseSizeHintForEach, // VT_BOOL + kUseSizeHintGlobal, // VT_BOOL + kParamSelectMode, // VT_UI4 + // kSearchLog, // VT_UI4 The minimum slog is 1 and the maximum is 26 + // kTargetLen, // VT_UI4 The minimum tlen is 0 and the maximum is 999. + */ + k_NUM_DEFINED + }; +} + +#define Z7_IFACEM_ICompressSetCoderPropertiesOpt(x) \ + x(SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +Z7_IFACE_CONSTR_CODER(ICompressSetCoderPropertiesOpt, 0x1F) + + +#define Z7_IFACEM_ICompressSetCoderProperties(x) \ + x(SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +Z7_IFACE_CONSTR_CODER(ICompressSetCoderProperties, 0x20) + +/* +#define Z7_IFACEM_ICompressSetDecoderProperties(x) \ + x(SetDecoderProperties(ISequentialInStream *inStream)) +Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties, 0x21) +*/ + +#define Z7_IFACEM_ICompressSetDecoderProperties2(x) \ + x(SetDecoderProperties2(const Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties2, 0x22) + /* returns: + S_OK + E_NOTIMP : unsupported properties + E_INVALIDARG : incorrect (or unsupported) properties + E_OUTOFMEMORY : memory allocation error + */ + + +#define Z7_IFACEM_ICompressWriteCoderProperties(x) \ + x(WriteCoderProperties(ISequentialOutStream *outStream)) +Z7_IFACE_CONSTR_CODER(ICompressWriteCoderProperties, 0x23) + +#define Z7_IFACEM_ICompressGetInStreamProcessedSize(x) \ + x(GetInStreamProcessedSize(UInt64 *value)) +Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize, 0x24) + +#define Z7_IFACEM_ICompressSetCoderMt(x) \ + x(SetNumberOfThreads(UInt32 numThreads)) +Z7_IFACE_CONSTR_CODER(ICompressSetCoderMt, 0x25) + +#define Z7_IFACEM_ICompressSetFinishMode(x) \ + x(SetFinishMode(UInt32 finishMode)) +Z7_IFACE_CONSTR_CODER(ICompressSetFinishMode, 0x26) + /* finishMode: + 0 : partial decoding is allowed. It's default mode for ICompressCoder::Code(), if (outSize) is defined. + 1 : full decoding. The stream must be finished at the end of decoding. */ + +#define Z7_IFACEM_ICompressGetInStreamProcessedSize2(x) \ + x(GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)) +Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize2, 0x27) + +#define Z7_IFACEM_ICompressSetMemLimit(x) \ + x(SetMemLimit(UInt64 memUsage)) +Z7_IFACE_CONSTR_CODER(ICompressSetMemLimit, 0x28) + + +/* + ICompressReadUnusedFromInBuf is supported by ICoder object + call ReadUnusedFromInBuf() after ICoder::Code(inStream, ...). + ICoder::Code(inStream, ...) decodes data, and the ICoder object is allowed + to read from inStream to internal buffers more data than minimal data required for decoding. + So we can call ReadUnusedFromInBuf() from same ICoder object to read unused input + data from the internal buffer. + in ReadUnusedFromInBuf(): the Coder is not allowed to use (ISequentialInStream *inStream) object, that was sent to ICoder::Code(). +*/ +#define Z7_IFACEM_ICompressReadUnusedFromInBuf(x) \ + x(ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) +Z7_IFACE_CONSTR_CODER(ICompressReadUnusedFromInBuf, 0x29) + + +#define Z7_IFACEM_ICompressGetSubStreamSize(x) \ + x(GetSubStreamSize(UInt64 subStream, UInt64 *value)) +Z7_IFACE_CONSTR_CODER(ICompressGetSubStreamSize, 0x30) + /* returns: + S_OK : (*value) contains the size or estimated size (can be incorrect size) + S_FALSE : size is undefined + E_NOTIMP : the feature is not implemented + Let's (read_size) is size of data that was already read by ISequentialInStream::Read(). + The caller should call GetSubStreamSize() after each Read() and check sizes: + if (start_of_subStream + *value < read_size) + { + // (*value) is correct, and it's allowed to call GetSubStreamSize() for next subStream: + start_of_subStream += *value; + subStream++; + } + */ + +#define Z7_IFACEM_ICompressSetInStream(x) \ + x(SetInStream(ISequentialInStream *inStream)) \ + x(ReleaseInStream()) +Z7_IFACE_CONSTR_CODER(ICompressSetInStream, 0x31) + +#define Z7_IFACEM_ICompressSetOutStream(x) \ + x(SetOutStream(ISequentialOutStream *outStream)) \ + x(ReleaseOutStream()) +Z7_IFACE_CONSTR_CODER(ICompressSetOutStream, 0x32) + +/* +#define Z7_IFACEM_ICompressSetInStreamSize(x) \ + x(SetInStreamSize(const UInt64 *inSize)) \ +Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize, 0x33) +*/ + +#define Z7_IFACEM_ICompressSetOutStreamSize(x) \ + x(SetOutStreamSize(const UInt64 *outSize)) +Z7_IFACE_CONSTR_CODER(ICompressSetOutStreamSize, 0x34) + /* That function initializes decoder structures. + Call this function only for stream version of decoder. + if (outSize == NULL), then output size is unknown + if (outSize != NULL), then the decoder must stop decoding after (*outSize) bytes. */ + +#define Z7_IFACEM_ICompressSetBufSize(x) \ + x(SetInBufSize(UInt32 streamIndex, UInt32 size)) \ + x(SetOutBufSize(UInt32 streamIndex, UInt32 size)) + +Z7_IFACE_CONSTR_CODER(ICompressSetBufSize, 0x35) + +#define Z7_IFACEM_ICompressInitEncoder(x) \ + x(InitEncoder()) +Z7_IFACE_CONSTR_CODER(ICompressInitEncoder, 0x36) + /* That function initializes encoder structures. + Call this function only for stream version of encoder. */ + +#define Z7_IFACEM_ICompressSetInStream2(x) \ + x(SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)) \ + x(ReleaseInStream2(UInt32 streamIndex)) +Z7_IFACE_CONSTR_CODER(ICompressSetInStream2, 0x37) + +/* +#define Z7_IFACEM_ICompressSetOutStream2(x) \ + x(SetOutStream2(UInt32 streamIndex, ISequentialOutStream *outStream)) + x(ReleaseOutStream2(UInt32 streamIndex)) +Z7_IFACE_CONSTR_CODER(ICompressSetOutStream2, 0x38) + +#define Z7_IFACEM_ICompressSetInStreamSize2(x) \ + x(SetInStreamSize2(UInt32 streamIndex, const UInt64 *inSize)) +Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize2, 0x39) +*/ + +/* +#define Z7_IFACEM_ICompressInSubStreams(x) \ + x(GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream)) +Z7_IFACE_CONSTR_CODER(ICompressInSubStreams, 0x3A) + +#define Z7_IFACEM_ICompressOutSubStreams(x) \ + x(GetNextOutSubStream(UInt64 *streamIndexRes, ISequentialOutStream **stream)) +Z7_IFACE_CONSTR_CODER(ICompressOutSubStreams, 0x3B) +*/ + +/* + ICompressFilter + Filter(Byte *data, UInt32 size) + (size) + converts as most as possible bytes required for fast processing. + Some filters have (smallest_fast_block). + For example, (smallest_fast_block == 16) for AES CBC/CTR filters. + If data stream is not finished, caller must call Filter() for larger block: + where (size >= smallest_fast_block). + if (size >= smallest_fast_block) + { + The filter can leave some bytes at the end of data without conversion: + if there are data alignment reasons or speed reasons. + The caller can read additional data from stream and call Filter() again. + } + If data stream was finished, caller can call Filter() for (size < smallest_fast_block) + + (data) parameter: + Some filters require alignment for any Filter() call: + 1) (stream_offset % alignment_size) == (data % alignment_size) + 2) (alignment_size == 2^N) + where (stream_offset) - is the number of bytes that were already filtered before. + The callers of Filter() are required to meet these requirements. + (alignment_size) can be different: + 16 : for AES filters + 4 or 2 : for some branch convert filters + 1 : for another filters + (alignment_size >= 16) is enough for all current filters of 7-Zip. + But the caller can use larger (alignment_size). + Recommended alignment for (data) of Filter() call is (alignment_size == 64). + Also it's recommended to use aligned value for (size): + (size % alignment_size == 0), + if it's not last call of Filter() for current stream. + + returns: (outSize): + if (outSize == 0) : Filter have not converted anything. + So the caller can stop processing, if data stream was finished. + if (outSize <= size) : Filter have converted outSize bytes + if (outSize > size) : Filter have not converted anything. + and it needs at least outSize bytes to convert one block + (it's for crypto block algorithms). +*/ + +#define Z7_IFACEM_ICompressFilter(x) \ + x(Init()) \ + x##2(UInt32, Filter(Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICompressFilter, 0x40) + + +#define Z7_IFACEM_ICompressCodecsInfo(x) \ + x(GetNumMethods(UInt32 *numMethods)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(CreateDecoder(UInt32 index, const GUID *iid, void* *coder)) \ + x(CreateEncoder(UInt32 index, const GUID *iid, void* *coder)) +Z7_IFACE_CONSTR_CODER(ICompressCodecsInfo, 0x60) + +#define Z7_IFACEM_ISetCompressCodecsInfo(x) \ + x(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) +Z7_IFACE_CONSTR_CODER(ISetCompressCodecsInfo, 0x61) + +#define Z7_IFACEM_ICryptoProperties(x) \ + x(SetKey(const Byte *data, UInt32 size)) \ + x(SetInitVector(const Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICryptoProperties, 0x80) + +/* + x(ResetSalt()) +Z7_IFACE_CONSTR_CODER(ICryptoResetSalt, 0x88) +*/ + +#define Z7_IFACEM_ICryptoResetInitVector(x) \ + x(ResetInitVector()) +Z7_IFACE_CONSTR_CODER(ICryptoResetInitVector, 0x8C) + /* Call ResetInitVector() only for encoding. + Call ResetInitVector() before encoding and before WriteCoderProperties(). + Crypto encoder can create random IV in that function. */ + +#define Z7_IFACEM_ICryptoSetPassword(x) \ + x(CryptoSetPassword(const Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICryptoSetPassword, 0x90) + +#define Z7_IFACEM_ICryptoSetCRC(x) \ + x(CryptoSetCRC(UInt32 crc)) +Z7_IFACE_CONSTR_CODER(ICryptoSetCRC, 0xA0) + + +namespace NMethodPropID +{ + enum EEnum + { + kID, + kName, + kDecoder, + kEncoder, + kPackStreams, + kUnpackStreams, + kDescription, + kDecoderIsAssigned, + kEncoderIsAssigned, + kDigestSize, + kIsFilter + }; +} + +namespace NModuleInterfaceType +{ + /* + virtual destructor in IUnknown: + - no : 7-Zip (Windows) + - no : 7-Zip (Linux) (v23) in default mode + - yes : p7zip + - yes : 7-Zip (Linux) before v23 + - yes : 7-Zip (Linux) (v23), if Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN is defined + */ + const UInt32 k_IUnknown_VirtDestructor_No = 0; + const UInt32 k_IUnknown_VirtDestructor_Yes = 1; + const UInt32 k_IUnknown_VirtDestructor_ThisModule = + #if !defined(_WIN32) && defined(Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN) + k_IUnknown_VirtDestructor_Yes; + #else + k_IUnknown_VirtDestructor_No; + #endif +} + +namespace NModulePropID +{ + enum EEnum + { + kInterfaceType, // VT_UI4 + kVersion // VT_UI4 + }; +} + + +#define Z7_IFACEM_IHasher(x) \ + x##2(void, Init()) \ + x##2(void, Update(const void *data, UInt32 size)) \ + x##2(void, Final(Byte *digest)) \ + x##2(UInt32, GetDigestSize()) +Z7_IFACE_CONSTR_CODER(IHasher, 0xC0) + +#define Z7_IFACEM_IHashers(x) \ + x##2(UInt32, GetNumHashers()) \ + x(GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(CreateHasher(UInt32 index, IHasher **hasher)) +Z7_IFACE_CONSTR_CODER(IHashers, 0xC1) + +extern "C" +{ + typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods); + typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); + typedef HRESULT (WINAPI *Func_CreateDecoder)(UInt32 index, const GUID *iid, void **outObject); + typedef HRESULT (WINAPI *Func_CreateEncoder)(UInt32 index, const GUID *iid, void **outObject); + + typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers); + + typedef HRESULT (WINAPI *Func_SetCodecs)(ICompressCodecsInfo *compressCodecsInfo); + typedef HRESULT (WINAPI *Func_GetModuleProp)(PROPID propID, PROPVARIANT *value); +} + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/IDecl.h b/CPP/7zip/IDecl.h index dd6729d75..4dbf1eba0 100644 --- a/CPP/7zip/IDecl.h +++ b/CPP/7zip/IDecl.h @@ -1,76 +1,76 @@ -// IDecl.h - -#ifndef ZIP7_INC_IDECL_H -#define ZIP7_INC_IDECL_H - -#include "../Common/Common0.h" -#include "../Common/MyUnknown.h" - -#define k_7zip_GUID_Data1 0x23170F69 -#define k_7zip_GUID_Data2 0x40C1 - -#define k_7zip_GUID_Data3_Common 0x278A - -#define k_7zip_GUID_Data3_Decoder 0x2790 -#define k_7zip_GUID_Data3_Encoder 0x2791 -#define k_7zip_GUID_Data3_Hasher 0x2792 - -#define Z7_DECL_IFACE_7ZIP_SUB(i, _base, groupId, subId) \ - Z7_DEFINE_GUID(IID_ ## i, \ - k_7zip_GUID_Data1, \ - k_7zip_GUID_Data2, \ - k_7zip_GUID_Data3_Common, \ - 0, 0, 0, (groupId), 0, (subId), 0, 0); \ - struct Z7_DECLSPEC_NOVTABLE i: public _base - -#define Z7_DECL_IFACE_7ZIP(i, groupId, subId) \ - Z7_DECL_IFACE_7ZIP_SUB(i, IUnknown, groupId, subId) - - -#ifdef COM_DECLSPEC_NOTHROW -#define Z7_COMWF_B COM_DECLSPEC_NOTHROW STDMETHODIMP -#define Z7_COMWF_B_(t) COM_DECLSPEC_NOTHROW STDMETHODIMP_(t) -#else -#define Z7_COMWF_B STDMETHODIMP -#define Z7_COMWF_B_(t) STDMETHODIMP_(t) -#endif - -#if defined(_MSC_VER) && !defined(COM_DECLSPEC_NOTHROW) -#define Z7_COM7F_B __declspec(nothrow) STDMETHODIMP -#define Z7_COM7F_B_(t) __declspec(nothrow) STDMETHODIMP_(t) -#else -#define Z7_COM7F_B Z7_COMWF_B -#define Z7_COM7F_B_(t) Z7_COMWF_B_(t) -#endif - -// #define Z7_COM7F_E Z7_noexcept -#define Z7_COM7F_E throw() -#define Z7_COM7F_EO Z7_COM7F_E Z7_override -#define Z7_COM7F_EOF Z7_COM7F_EO Z7_final -#define Z7_COM7F_IMF(f) Z7_COM7F_B f Z7_COM7F_E -#define Z7_COM7F_IMF2(t, f) Z7_COM7F_B_(t) f Z7_COM7F_E - -#define Z7_COM7F_PURE(f) virtual Z7_COM7F_IMF(f) =0; -#define Z7_COM7F_PURE2(t, f) virtual Z7_COM7F_IMF2(t, f) =0; -#define Z7_COM7F_IMP(f) Z7_COM7F_IMF(f) Z7_override Z7_final; -#define Z7_COM7F_IMP2(t, f) Z7_COM7F_IMF2(t, f) Z7_override Z7_final; -#define Z7_COM7F_IMP_NONFINAL(f) Z7_COM7F_IMF(f) Z7_override; -#define Z7_COM7F_IMP_NONFINAL2(t, f) Z7_COM7F_IMF2(t, f) Z7_override; - -#define Z7_IFACE_PURE(name) Z7_IFACEN_ ## name(=0;) -#define Z7_IFACE_IMP(name) Z7_IFACEN_ ## name(Z7_override Z7_final;) - -#define Z7_IFACE_COM7_PURE(name) Z7_IFACEM_ ## name(Z7_COM7F_PURE) -#define Z7_IFACE_COM7_IMP(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP) -#define Z7_IFACE_COM7_IMP_NONFINAL(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP_NONFINAL) - - -#define Z7_IFACE_DECL_PURE(name) \ - DECLARE_INTERFACE(name) \ - { Z7_IFACE_PURE(name) }; - -#define Z7_IFACE_DECL_PURE_(name, baseiface) \ - DECLARE_INTERFACE_(name, baseiface) \ - { Z7_IFACE_PURE(name) }; - -#endif +// IDecl.h + +#ifndef ZIP7_INC_IDECL_H +#define ZIP7_INC_IDECL_H + +#include "../Common/Common0.h" +#include "../Common/MyUnknown.h" + +#define k_7zip_GUID_Data1 0x23170F69 +#define k_7zip_GUID_Data2 0x40C1 + +#define k_7zip_GUID_Data3_Common 0x278A + +#define k_7zip_GUID_Data3_Decoder 0x2790 +#define k_7zip_GUID_Data3_Encoder 0x2791 +#define k_7zip_GUID_Data3_Hasher 0x2792 + +#define Z7_DECL_IFACE_7ZIP_SUB(i, _base, groupId, subId) \ + Z7_DEFINE_GUID(IID_ ## i, \ + k_7zip_GUID_Data1, \ + k_7zip_GUID_Data2, \ + k_7zip_GUID_Data3_Common, \ + 0, 0, 0, (groupId), 0, (subId), 0, 0); \ + struct Z7_DECLSPEC_NOVTABLE i: public _base + +#define Z7_DECL_IFACE_7ZIP(i, groupId, subId) \ + Z7_DECL_IFACE_7ZIP_SUB(i, IUnknown, groupId, subId) + + +#ifdef COM_DECLSPEC_NOTHROW +#define Z7_COMWF_B COM_DECLSPEC_NOTHROW STDMETHODIMP +#define Z7_COMWF_B_(t) COM_DECLSPEC_NOTHROW STDMETHODIMP_(t) +#else +#define Z7_COMWF_B STDMETHODIMP +#define Z7_COMWF_B_(t) STDMETHODIMP_(t) +#endif + +#if defined(_MSC_VER) && !defined(COM_DECLSPEC_NOTHROW) +#define Z7_COM7F_B __declspec(nothrow) STDMETHODIMP +#define Z7_COM7F_B_(t) __declspec(nothrow) STDMETHODIMP_(t) +#else +#define Z7_COM7F_B Z7_COMWF_B +#define Z7_COM7F_B_(t) Z7_COMWF_B_(t) +#endif + +// #define Z7_COM7F_E Z7_noexcept +#define Z7_COM7F_E throw() +#define Z7_COM7F_EO Z7_COM7F_E Z7_override +#define Z7_COM7F_EOF Z7_COM7F_EO Z7_final +#define Z7_COM7F_IMF(f) Z7_COM7F_B f Z7_COM7F_E +#define Z7_COM7F_IMF2(t, f) Z7_COM7F_B_(t) f Z7_COM7F_E + +#define Z7_COM7F_PURE(f) virtual Z7_COM7F_IMF(f) =0; +#define Z7_COM7F_PURE2(t, f) virtual Z7_COM7F_IMF2(t, f) =0; +#define Z7_COM7F_IMP(f) Z7_COM7F_IMF(f) Z7_override Z7_final; +#define Z7_COM7F_IMP2(t, f) Z7_COM7F_IMF2(t, f) Z7_override Z7_final; +#define Z7_COM7F_IMP_NONFINAL(f) Z7_COM7F_IMF(f) Z7_override; +#define Z7_COM7F_IMP_NONFINAL2(t, f) Z7_COM7F_IMF2(t, f) Z7_override; + +#define Z7_IFACE_PURE(name) Z7_IFACEN_ ## name(=0;) +#define Z7_IFACE_IMP(name) Z7_IFACEN_ ## name(Z7_override Z7_final;) + +#define Z7_IFACE_COM7_PURE(name) Z7_IFACEM_ ## name(Z7_COM7F_PURE) +#define Z7_IFACE_COM7_IMP(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP) +#define Z7_IFACE_COM7_IMP_NONFINAL(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP_NONFINAL) + + +#define Z7_IFACE_DECL_PURE(name) \ + DECLARE_INTERFACE(name) \ + { Z7_IFACE_PURE(name) }; + +#define Z7_IFACE_DECL_PURE_(name, baseiface) \ + DECLARE_INTERFACE_(name, baseiface) \ + { Z7_IFACE_PURE(name) }; + +#endif diff --git a/CPP/7zip/IPassword.h b/CPP/7zip/IPassword.h index f981b5112..689f08cb4 100644 --- a/CPP/7zip/IPassword.h +++ b/CPP/7zip/IPassword.h @@ -1,54 +1,54 @@ -// IPassword.h - -#ifndef ZIP7_INC_IPASSWORD_H -#define ZIP7_INC_IPASSWORD_H - -#include "../Common/MyTypes.h" - -#include "IDecl.h" - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACE_CONSTR_PASSWORD(i, n) \ - Z7_DECL_IFACE_7ZIP(i, 5, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -/* -How to use output parameter (BSTR *password): - -in: The caller is required to set BSTR value as NULL (no string). - The callee (in 7-Zip code) ignores the input value stored in BSTR variable, - -out: The callee rewrites BSTR variable (*password) with new allocated string pointer. - The caller must free BSTR string with function SysFreeString(); -*/ - -#define Z7_IFACEM_ICryptoGetTextPassword(x) \ - x(CryptoGetTextPassword(BSTR *password)) -Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword, 0x10) - - -/* -CryptoGetTextPassword2() -in: - The caller is required to set BSTR value as NULL (no string). - The caller is not required to set (*passwordIsDefined) value. - -out: - Return code: != S_OK : error code - Return code: S_OK : success - - if (*passwordIsDefined == 1), the variable (*password) contains password string - - if (*passwordIsDefined == 0), the password is not defined, - but the callee still could set (*password) to some allocated string, for example, as empty string. - - The caller must free BSTR string with function SysFreeString() -*/ - -#define Z7_IFACEM_ICryptoGetTextPassword2(x) \ - x(CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) -Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword2, 0x11) - -Z7_PURE_INTERFACES_END -#endif +// IPassword.h + +#ifndef ZIP7_INC_IPASSWORD_H +#define ZIP7_INC_IPASSWORD_H + +#include "../Common/MyTypes.h" + +#include "IDecl.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_PASSWORD(i, n) \ + Z7_DECL_IFACE_7ZIP(i, 5, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +/* +How to use output parameter (BSTR *password): + +in: The caller is required to set BSTR value as NULL (no string). + The callee (in 7-Zip code) ignores the input value stored in BSTR variable, + +out: The callee rewrites BSTR variable (*password) with new allocated string pointer. + The caller must free BSTR string with function SysFreeString(); +*/ + +#define Z7_IFACEM_ICryptoGetTextPassword(x) \ + x(CryptoGetTextPassword(BSTR *password)) +Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword, 0x10) + + +/* +CryptoGetTextPassword2() +in: + The caller is required to set BSTR value as NULL (no string). + The caller is not required to set (*passwordIsDefined) value. + +out: + Return code: != S_OK : error code + Return code: S_OK : success + + if (*passwordIsDefined == 1), the variable (*password) contains password string + + if (*passwordIsDefined == 0), the password is not defined, + but the callee still could set (*password) to some allocated string, for example, as empty string. + + The caller must free BSTR string with function SysFreeString() +*/ + +#define Z7_IFACEM_ICryptoGetTextPassword2(x) \ + x(CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) +Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword2, 0x11) + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/IProgress.h b/CPP/7zip/IProgress.h index e980106d7..67149830b 100644 --- a/CPP/7zip/IProgress.h +++ b/CPP/7zip/IProgress.h @@ -1,20 +1,20 @@ -// IProgress.h - -#ifndef ZIP7_INC_IPROGRESS_H -#define ZIP7_INC_IPROGRESS_H - -#include "../Common/MyTypes.h" - -#include "IDecl.h" - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACEM_IProgress(x) \ - x(SetTotal(UInt64 total)) \ - x(SetCompleted(const UInt64 *completeValue)) \ - -Z7_DECL_IFACE_7ZIP(IProgress, 0, 5) - { Z7_IFACE_COM7_PURE(IProgress) }; - -Z7_PURE_INTERFACES_END -#endif +// IProgress.h + +#ifndef ZIP7_INC_IPROGRESS_H +#define ZIP7_INC_IPROGRESS_H + +#include "../Common/MyTypes.h" + +#include "IDecl.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACEM_IProgress(x) \ + x(SetTotal(UInt64 total)) \ + x(SetCompleted(const UInt64 *completeValue)) \ + +Z7_DECL_IFACE_7ZIP(IProgress, 0, 5) + { Z7_IFACE_COM7_PURE(IProgress) }; + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/IStream.h b/CPP/7zip/IStream.h index 1622ee8a9..0c44a9178 100644 --- a/CPP/7zip/IStream.h +++ b/CPP/7zip/IStream.h @@ -1,210 +1,210 @@ -// IStream.h - -#ifndef ZIP7_INC_ISTREAM_H -#define ZIP7_INC_ISTREAM_H - -#include "../Common/Common0.h" -#include "../Common/MyTypes.h" -#include "../Common/MyWindows.h" - -#include "IDecl.h" - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACE_CONSTR_STREAM_SUB(i, base, n) \ - Z7_DECL_IFACE_7ZIP_SUB(i, base, 3, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -#define Z7_IFACE_CONSTR_STREAM(i, n) \ - Z7_IFACE_CONSTR_STREAM_SUB(i, IUnknown, n) - - -/* -ISequentialInStream::Read() - The requirement for caller: (processedSize != NULL). - The callee can allow (processedSize == NULL) for compatibility reasons. - - if (size == 0), this function returns S_OK and (*processedSize) is set to 0. - - if (size != 0) - { - Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size), - where (avail_size) is the size of remaining bytes in stream. - If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0). - You must call Read() in loop, if you need to read exact amount of data. - } - - If seek pointer before Read() call was changed to position past the end of stream: - if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0. - - ERROR CASES: - If the function returns error code, then (*processedSize) is size of - data written to (data) buffer (it can be data before error or data with errors). - The recommended way for callee to work with reading errors: - 1) write part of data before error to (data) buffer and return S_OK. - 2) return error code for further calls of Read(). -*/ -#define Z7_IFACEM_ISequentialInStream(x) \ - x(Read(void *data, UInt32 size, UInt32 *processedSize)) -Z7_IFACE_CONSTR_STREAM(ISequentialInStream, 0x01) - - -/* -ISequentialOutStream::Write() - The requirement for caller: (processedSize != NULL). - The callee can allow (processedSize == NULL) for compatibility reasons. - - if (size != 0) - { - Partial write is allowed: (*processedSize <= size), - but this function must write at least 1 byte: (*processedSize > 0). - You must call Write() in loop, if you need to write exact amount of data. - } - - ERROR CASES: - If the function returns error code, then (*processedSize) is size of - data written from (data) buffer. -*/ -#define Z7_IFACEM_ISequentialOutStream(x) \ - x(Write(const void *data, UInt32 size, UInt32 *processedSize)) -Z7_IFACE_CONSTR_STREAM(ISequentialOutStream, 0x02) - - -#ifdef _WIN32 - -#ifdef __HRESULT_FROM_WIN32 -#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) -#else -#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) -#endif - -#else - -#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK MY_E_ERROR_NEGATIVE_SEEK - -#endif - - -/* -IInStream::Seek() / IOutStream::Seek() - If you seek to position before the beginning of the stream, - Seek() function returns error code: - Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK). - or STG_E_INVALIDFUNCTION - It is allowed to seek past the end of the stream. - if Seek() returns error, then the value of *newPosition is undefined. -*/ - -#define Z7_IFACEM_IInStream(x) \ - x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -Z7_IFACE_CONSTR_STREAM_SUB(IInStream, ISequentialInStream, 0x03) - -#define Z7_IFACEM_IOutStream(x) \ - x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) \ - x(SetSize(UInt64 newSize)) -Z7_IFACE_CONSTR_STREAM_SUB(IOutStream, ISequentialOutStream, 0x04) - -#define Z7_IFACEM_IStreamGetSize(x) \ - x(GetSize(UInt64 *size)) -Z7_IFACE_CONSTR_STREAM(IStreamGetSize, 0x06) - -#define Z7_IFACEM_IOutStreamFinish(x) \ - x(OutStreamFinish()) -Z7_IFACE_CONSTR_STREAM(IOutStreamFinish, 0x07) - -#define Z7_IFACEM_IStreamGetProps(x) \ - x(GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) -Z7_IFACE_CONSTR_STREAM(IStreamGetProps, 0x08) - - -struct CStreamFileProps -{ - UInt64 Size; - UInt64 VolID; - UInt64 FileID_Low; - UInt64 FileID_High; - UInt32 NumLinks; - UInt32 Attrib; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; -}; - - -#define Z7_IFACEM_IStreamGetProps2(x) \ - x(GetProps2(CStreamFileProps *props)) -Z7_IFACE_CONSTR_STREAM(IStreamGetProps2, 0x09) - -#define Z7_IFACEM_IStreamGetProp(x) \ - x(GetProperty(PROPID propID, PROPVARIANT *value)) \ - x(ReloadProps()) -Z7_IFACE_CONSTR_STREAM(IStreamGetProp, 0x0a) - - -/* -IStreamSetRestriction::SetRestriction(UInt64 begin, UInt64 end) - - It sets region of data in output stream that is restricted. - For restricted region it's expected (or allowed) - that the caller can write to same region with different calls of Write()/SetSize(). - Another regions of output stream will be supposed as non-restricted: - - The callee usually doesn't flush the data in restricted region. - - The callee usually can flush data from non-restricted region after writing. - -Actual restiction rules depend also from current stream position. -It's recommended to call SetRestriction() just before the Write() call. -So the callee can optimize writing and flushing, if that Write() -operation is not restricted. - -Note: Each new call of SetRestriction() sets new restictions, -so previous restrction calls has no effect anymore. - -inputs: - - (begin > end) is not allowed, and returns E_FAIL; - - if (begin == end) - { - No restriction. - The caller will call Write() in sequential order. - After SetRestriction(begin, begin), but before next call of SetRestriction() - { - Additional condition: - it's expected that current stream seek position is equal to stream size. - The callee can make final flushing for any data before current stream seek position. - For each Write(size) call: - The callee can make final flushing for that new written data. - } - The pair of values (begin == 0 && end == 0) is recommended to remove write restriction. - } - - if (begin < end) - { - it means that callee must NOT flush any data in region [begin, end). - The caller is allowed to Seek() to that region and rewrite the - data in that restriction region. - if (end == (UInt64)(Int64)-1) - { - there is no upper bound for restricted region. - So non-restricted region will be [0, begin) in that case - } - } - - returns: - - if (begin > end) it return ERROR code (E_FAIL) - - S_OK : if no errors. - - Also the call of SetRestriction() can initiate the flushing of already written data. - So it can return the result of that flushing. - - Note: IOutStream::SetSize() also can change the data. - So it's not expected the call - IOutStream::SetSize() to region that was written before as unrestricted. -*/ - -#define Z7_IFACEM_IStreamSetRestriction(x) \ - x(SetRestriction(UInt64 begin, UInt64 end)) \ - -Z7_IFACE_CONSTR_STREAM(IStreamSetRestriction, 0x10) - -Z7_PURE_INTERFACES_END -#endif +// IStream.h + +#ifndef ZIP7_INC_ISTREAM_H +#define ZIP7_INC_ISTREAM_H + +#include "../Common/Common0.h" +#include "../Common/MyTypes.h" +#include "../Common/MyWindows.h" + +#include "IDecl.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_STREAM_SUB(i, base, n) \ + Z7_DECL_IFACE_7ZIP_SUB(i, base, 3, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACE_CONSTR_STREAM(i, n) \ + Z7_IFACE_CONSTR_STREAM_SUB(i, IUnknown, n) + + +/* +ISequentialInStream::Read() + The requirement for caller: (processedSize != NULL). + The callee can allow (processedSize == NULL) for compatibility reasons. + + if (size == 0), this function returns S_OK and (*processedSize) is set to 0. + + if (size != 0) + { + Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size), + where (avail_size) is the size of remaining bytes in stream. + If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0). + You must call Read() in loop, if you need to read exact amount of data. + } + + If seek pointer before Read() call was changed to position past the end of stream: + if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0. + + ERROR CASES: + If the function returns error code, then (*processedSize) is size of + data written to (data) buffer (it can be data before error or data with errors). + The recommended way for callee to work with reading errors: + 1) write part of data before error to (data) buffer and return S_OK. + 2) return error code for further calls of Read(). +*/ +#define Z7_IFACEM_ISequentialInStream(x) \ + x(Read(void *data, UInt32 size, UInt32 *processedSize)) +Z7_IFACE_CONSTR_STREAM(ISequentialInStream, 0x01) + + +/* +ISequentialOutStream::Write() + The requirement for caller: (processedSize != NULL). + The callee can allow (processedSize == NULL) for compatibility reasons. + + if (size != 0) + { + Partial write is allowed: (*processedSize <= size), + but this function must write at least 1 byte: (*processedSize > 0). + You must call Write() in loop, if you need to write exact amount of data. + } + + ERROR CASES: + If the function returns error code, then (*processedSize) is size of + data written from (data) buffer. +*/ +#define Z7_IFACEM_ISequentialOutStream(x) \ + x(Write(const void *data, UInt32 size, UInt32 *processedSize)) +Z7_IFACE_CONSTR_STREAM(ISequentialOutStream, 0x02) + + +#ifdef _WIN32 + +#ifdef __HRESULT_FROM_WIN32 +#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) +#else +#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) +#endif + +#else + +#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK MY_E_ERROR_NEGATIVE_SEEK + +#endif + + +/* +IInStream::Seek() / IOutStream::Seek() + If you seek to position before the beginning of the stream, + Seek() function returns error code: + Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK). + or STG_E_INVALIDFUNCTION + It is allowed to seek past the end of the stream. + if Seek() returns error, then the value of *newPosition is undefined. +*/ + +#define Z7_IFACEM_IInStream(x) \ + x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +Z7_IFACE_CONSTR_STREAM_SUB(IInStream, ISequentialInStream, 0x03) + +#define Z7_IFACEM_IOutStream(x) \ + x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) \ + x(SetSize(UInt64 newSize)) +Z7_IFACE_CONSTR_STREAM_SUB(IOutStream, ISequentialOutStream, 0x04) + +#define Z7_IFACEM_IStreamGetSize(x) \ + x(GetSize(UInt64 *size)) +Z7_IFACE_CONSTR_STREAM(IStreamGetSize, 0x06) + +#define Z7_IFACEM_IOutStreamFinish(x) \ + x(OutStreamFinish()) +Z7_IFACE_CONSTR_STREAM(IOutStreamFinish, 0x07) + +#define Z7_IFACEM_IStreamGetProps(x) \ + x(GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) +Z7_IFACE_CONSTR_STREAM(IStreamGetProps, 0x08) + + +struct CStreamFileProps +{ + UInt64 Size; + UInt64 VolID; + UInt64 FileID_Low; + UInt64 FileID_High; + UInt32 NumLinks; + UInt32 Attrib; + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; +}; + + +#define Z7_IFACEM_IStreamGetProps2(x) \ + x(GetProps2(CStreamFileProps *props)) +Z7_IFACE_CONSTR_STREAM(IStreamGetProps2, 0x09) + +#define Z7_IFACEM_IStreamGetProp(x) \ + x(GetProperty(PROPID propID, PROPVARIANT *value)) \ + x(ReloadProps()) +Z7_IFACE_CONSTR_STREAM(IStreamGetProp, 0x0a) + + +/* +IStreamSetRestriction::SetRestriction(UInt64 begin, UInt64 end) + + It sets region of data in output stream that is restricted. + For restricted region it's expected (or allowed) + that the caller can write to same region with different calls of Write()/SetSize(). + Another regions of output stream will be supposed as non-restricted: + - The callee usually doesn't flush the data in restricted region. + - The callee usually can flush data from non-restricted region after writing. + +Actual restiction rules depend also from current stream position. +It's recommended to call SetRestriction() just before the Write() call. +So the callee can optimize writing and flushing, if that Write() +operation is not restricted. + +Note: Each new call of SetRestriction() sets new restictions, +so previous restrction calls has no effect anymore. + +inputs: + + (begin > end) is not allowed, and returns E_FAIL; + + if (begin == end) + { + No restriction. + The caller will call Write() in sequential order. + After SetRestriction(begin, begin), but before next call of SetRestriction() + { + Additional condition: + it's expected that current stream seek position is equal to stream size. + The callee can make final flushing for any data before current stream seek position. + For each Write(size) call: + The callee can make final flushing for that new written data. + } + The pair of values (begin == 0 && end == 0) is recommended to remove write restriction. + } + + if (begin < end) + { + it means that callee must NOT flush any data in region [begin, end). + The caller is allowed to Seek() to that region and rewrite the + data in that restriction region. + if (end == (UInt64)(Int64)-1) + { + there is no upper bound for restricted region. + So non-restricted region will be [0, begin) in that case + } + } + + returns: + - if (begin > end) it return ERROR code (E_FAIL) + - S_OK : if no errors. + - Also the call of SetRestriction() can initiate the flushing of already written data. + So it can return the result of that flushing. + + Note: IOutStream::SetSize() also can change the data. + So it's not expected the call + IOutStream::SetSize() to region that was written before as unrestricted. +*/ + +#define Z7_IFACEM_IStreamSetRestriction(x) \ + x(SetRestriction(UInt64 begin, UInt64 end)) \ + +Z7_IFACE_CONSTR_STREAM(IStreamSetRestriction, 0x10) + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/LzFindOpt.mak b/CPP/7zip/LzFindOpt.mak index cf64941dc..169e10f0b 100644 --- a/CPP/7zip/LzFindOpt.mak +++ b/CPP/7zip/LzFindOpt.mak @@ -1,7 +1,7 @@ -!IF defined(USE_C_LZFINDOPT) || "$(PLATFORM)" != "x64" -C_OBJS = $(C_OBJS) \ - $O\LzFindOpt.obj -!ELSE -ASM_OBJS = $(ASM_OBJS) \ - $O\LzFindOpt.obj -!ENDIF +!IF defined(USE_C_LZFINDOPT) || "$(PLATFORM)" != "x64" +C_OBJS = $(C_OBJS) \ + $O\LzFindOpt.obj +!ELSE +ASM_OBJS = $(ASM_OBJS) \ + $O\LzFindOpt.obj +!ENDIF diff --git a/CPP/7zip/LzmaDec.mak b/CPP/7zip/LzmaDec.mak index 6c0de7049..624ea9e69 100644 --- a/CPP/7zip/LzmaDec.mak +++ b/CPP/7zip/LzmaDec.mak @@ -1,7 +1,7 @@ -!IF "$(PLATFORM)" == "x64" || ("$(PLATFORM)" == "arm64" && !defined(NO_ASM_GNU)) -!IFNDEF NO_ASM -CFLAGS_C_SPEC = -DZ7_LZMA_DEC_OPT -ASM_OBJS = $(ASM_OBJS) \ - $O\LzmaDecOpt.obj -!ENDIF -!ENDIF +!IF "$(PLATFORM)" == "x64" || ("$(PLATFORM)" == "arm64" && !defined(NO_ASM_GNU)) +!IFNDEF NO_ASM +CFLAGS_C_SPEC = -DZ7_LZMA_DEC_OPT +ASM_OBJS = $(ASM_OBJS) \ + $O\LzmaDecOpt.obj +!ENDIF +!ENDIF diff --git a/CPP/7zip/LzmaDec_gcc.mak b/CPP/7zip/LzmaDec_gcc.mak index 067b1426f..51924f505 100644 --- a/CPP/7zip/LzmaDec_gcc.mak +++ b/CPP/7zip/LzmaDec_gcc.mak @@ -1,14 +1,14 @@ -ifdef USE_ASM -ifdef IS_X64 -USE_LZMA_DEC_ASM=1 -endif -ifdef IS_ARM64 -USE_LZMA_DEC_ASM=1 -endif -endif - -ifdef USE_LZMA_DEC_ASM - -LZMA_DEC_OPT_OBJS= $O/LzmaDecOpt.o - -endif +ifdef USE_ASM +ifdef IS_X64 +USE_LZMA_DEC_ASM=1 +endif +ifdef IS_ARM64 +USE_LZMA_DEC_ASM=1 +endif +endif + +ifdef USE_LZMA_DEC_ASM + +LZMA_DEC_OPT_OBJS= $O/LzmaDecOpt.o + +endif diff --git a/CPP/7zip/MyVersion.h b/CPP/7zip/MyVersion.h index 0d50f9426..8f52a1261 100644 --- a/CPP/7zip/MyVersion.h +++ b/CPP/7zip/MyVersion.h @@ -1,2 +1,2 @@ -#define USE_COPYRIGHT_CR -#include "../../C/7zVersion.h" +#define USE_COPYRIGHT_CR +#include "../../C/7zVersion.h" diff --git a/CPP/7zip/MyVersionInfo.rc b/CPP/7zip/MyVersionInfo.rc index 90e65376b..fc63d798a 100644 --- a/CPP/7zip/MyVersionInfo.rc +++ b/CPP/7zip/MyVersionInfo.rc @@ -1,2 +1,2 @@ -#include "MyVersion.h" -#include "../../C/7zVersion.rc" +#include "MyVersion.h" +#include "../../C/7zVersion.rc" diff --git a/CPP/7zip/PropID.h b/CPP/7zip/PropID.h index 16bebcb51..e07479428 100644 --- a/CPP/7zip/PropID.h +++ b/CPP/7zip/PropID.h @@ -1,178 +1,178 @@ -// PropID.h - -#ifndef ZIP7_INC_7ZIP_PROP_ID_H -#define ZIP7_INC_7ZIP_PROP_ID_H - -#include "../Common/MyTypes.h" - -enum -{ - kpidNoProperty = 0, - kpidMainSubfile, - kpidHandlerItemIndex, - kpidPath, - kpidName, - kpidExtension, - kpidIsDir, - kpidSize, - kpidPackSize, - kpidAttrib, - kpidCTime, - kpidATime, - kpidMTime, - kpidSolid, - kpidCommented, - kpidEncrypted, - kpidSplitBefore, - kpidSplitAfter, - kpidDictionarySize, - kpidCRC, - kpidType, - kpidIsAnti, - kpidMethod, - kpidHostOS, - kpidFileSystem, - kpidUser, - kpidGroup, - kpidBlock, - kpidComment, - kpidPosition, - kpidPrefix, - kpidNumSubDirs, - kpidNumSubFiles, - kpidUnpackVer, - kpidVolume, - kpidIsVolume, - kpidOffset, - kpidLinks, - kpidNumBlocks, - kpidNumVolumes, - kpidTimeType, - kpidBit64, - kpidBigEndian, - kpidCpu, - kpidPhySize, - kpidHeadersSize, - kpidChecksum, - kpidCharacts, - kpidVa, - kpidId, - kpidShortName, - kpidCreatorApp, - kpidSectorSize, - kpidPosixAttrib, - kpidSymLink, - kpidError, - kpidTotalSize, - kpidFreeSpace, - kpidClusterSize, - kpidVolumeName, - kpidLocalName, - kpidProvider, - kpidNtSecure, - kpidIsAltStream, - kpidIsAux, - kpidIsDeleted, - kpidIsTree, - kpidSha1, - kpidSha256, - kpidErrorType, - kpidNumErrors, - kpidErrorFlags, - kpidWarningFlags, - kpidWarning, - kpidNumStreams, - kpidNumAltStreams, - kpidAltStreamsSize, - kpidVirtualSize, - kpidUnpackSize, - kpidTotalPhySize, - kpidVolumeIndex, - kpidSubType, - kpidShortComment, - kpidCodePage, - kpidIsNotArcType, - kpidPhySizeCantBeDetected, - kpidZerosTailIsAllowed, - kpidTailSize, - kpidEmbeddedStubSize, - kpidNtReparse, - kpidHardLink, - kpidINode, - kpidStreamId, - kpidReadOnly, - kpidOutName, - kpidCopyLink, - kpidArcFileName, - kpidIsHash, - kpidChangeTime, - kpidUserId, - kpidGroupId, - kpidDeviceMajor, - kpidDeviceMinor, - kpidDevMajor, - kpidDevMinor, - - kpid_NUM_DEFINED, - - kpidUserDefined = 0x10000 -}; - -extern const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE - -const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0; -const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1; -const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2; -const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3; -const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4; -const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5; -const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6; -const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7; -const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8; -const UInt32 kpv_ErrorFlags_DataError = 1 << 9; -const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; -// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; - -/* -linux ctime : - file metadata was last changed. - changing the file modification time - counts as a metadata change, so will also have the side effect of updating the ctime. - -PROPVARIANT for timestamps in 7-Zip: -{ - vt = VT_FILETIME - wReserved1: set precision level - 0 : base value (backward compatibility value) - only filetime is used (7 digits precision). - wReserved2 and wReserved3 can contain random data - 1 : Unix (1 sec) - 2 : DOS (2 sec) - 3 : High Precision (1 ns) - 16 - 3 : (reserved) = 1 day - 16 - 2 : (reserved) = 1 hour - 16 - 1 : (reserved) = 1 minute - 16 + 0 : 1 sec (0 digits after point) - 16 + (1,2,3,4,5,6,7,8,9) : set subsecond precision level : - (number of decimal digits after point) - 16 + 9 : 1 ns (9 digits after point) - wReserved2 = ns % 100 : if (8 or 9 digits pecision) - = 0 : if not (8 or 9 digits pecision) - wReserved3 = 0; - filetime -} - -NOTE: TAR-PAX archives created by GNU TAR don't keep - whole information about original level of precision, - and timestamp are stored in reduced form, where tail zero - digits after point are removed. - So 7-Zip can return different precision levels for different items for such TAR archives. -*/ - -/* -TimePrec returned by IOutArchive::GetFileTimeType() -is used only for updating, when we compare MTime timestamp -from archive with timestamp from directory. -*/ - -#endif +// PropID.h + +#ifndef ZIP7_INC_7ZIP_PROP_ID_H +#define ZIP7_INC_7ZIP_PROP_ID_H + +#include "../Common/MyTypes.h" + +enum +{ + kpidNoProperty = 0, + kpidMainSubfile, + kpidHandlerItemIndex, + kpidPath, + kpidName, + kpidExtension, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidAttrib, + kpidCTime, + kpidATime, + kpidMTime, + kpidSolid, + kpidCommented, + kpidEncrypted, + kpidSplitBefore, + kpidSplitAfter, + kpidDictionarySize, + kpidCRC, + kpidType, + kpidIsAnti, + kpidMethod, + kpidHostOS, + kpidFileSystem, + kpidUser, + kpidGroup, + kpidBlock, + kpidComment, + kpidPosition, + kpidPrefix, + kpidNumSubDirs, + kpidNumSubFiles, + kpidUnpackVer, + kpidVolume, + kpidIsVolume, + kpidOffset, + kpidLinks, + kpidNumBlocks, + kpidNumVolumes, + kpidTimeType, + kpidBit64, + kpidBigEndian, + kpidCpu, + kpidPhySize, + kpidHeadersSize, + kpidChecksum, + kpidCharacts, + kpidVa, + kpidId, + kpidShortName, + kpidCreatorApp, + kpidSectorSize, + kpidPosixAttrib, + kpidSymLink, + kpidError, + kpidTotalSize, + kpidFreeSpace, + kpidClusterSize, + kpidVolumeName, + kpidLocalName, + kpidProvider, + kpidNtSecure, + kpidIsAltStream, + kpidIsAux, + kpidIsDeleted, + kpidIsTree, + kpidSha1, + kpidSha256, + kpidErrorType, + kpidNumErrors, + kpidErrorFlags, + kpidWarningFlags, + kpidWarning, + kpidNumStreams, + kpidNumAltStreams, + kpidAltStreamsSize, + kpidVirtualSize, + kpidUnpackSize, + kpidTotalPhySize, + kpidVolumeIndex, + kpidSubType, + kpidShortComment, + kpidCodePage, + kpidIsNotArcType, + kpidPhySizeCantBeDetected, + kpidZerosTailIsAllowed, + kpidTailSize, + kpidEmbeddedStubSize, + kpidNtReparse, + kpidHardLink, + kpidINode, + kpidStreamId, + kpidReadOnly, + kpidOutName, + kpidCopyLink, + kpidArcFileName, + kpidIsHash, + kpidChangeTime, + kpidUserId, + kpidGroupId, + kpidDeviceMajor, + kpidDeviceMinor, + kpidDevMajor, + kpidDevMinor, + + kpid_NUM_DEFINED, + + kpidUserDefined = 0x10000 +}; + +extern const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE + +const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0; +const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1; +const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2; +const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3; +const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4; +const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5; +const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6; +const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7; +const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8; +const UInt32 kpv_ErrorFlags_DataError = 1 << 9; +const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; +// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; + +/* +linux ctime : + file metadata was last changed. + changing the file modification time + counts as a metadata change, so will also have the side effect of updating the ctime. + +PROPVARIANT for timestamps in 7-Zip: +{ + vt = VT_FILETIME + wReserved1: set precision level + 0 : base value (backward compatibility value) + only filetime is used (7 digits precision). + wReserved2 and wReserved3 can contain random data + 1 : Unix (1 sec) + 2 : DOS (2 sec) + 3 : High Precision (1 ns) + 16 - 3 : (reserved) = 1 day + 16 - 2 : (reserved) = 1 hour + 16 - 1 : (reserved) = 1 minute + 16 + 0 : 1 sec (0 digits after point) + 16 + (1,2,3,4,5,6,7,8,9) : set subsecond precision level : + (number of decimal digits after point) + 16 + 9 : 1 ns (9 digits after point) + wReserved2 = ns % 100 : if (8 or 9 digits pecision) + = 0 : if not (8 or 9 digits pecision) + wReserved3 = 0; + filetime +} + +NOTE: TAR-PAX archives created by GNU TAR don't keep + whole information about original level of precision, + and timestamp are stored in reduced form, where tail zero + digits after point are removed. + So 7-Zip can return different precision levels for different items for such TAR archives. +*/ + +/* +TimePrec returned by IOutArchive::GetFileTimeType() +is used only for updating, when we compare MTime timestamp +from archive with timestamp from directory. +*/ + +#endif diff --git a/CPP/7zip/Sha1.mak b/CPP/7zip/Sha1.mak index 3b1d6d2a1..1b5f605fa 100644 --- a/CPP/7zip/Sha1.mak +++ b/CPP/7zip/Sha1.mak @@ -1,13 +1,13 @@ -COMMON_OBJS = $(COMMON_OBJS) \ - $O\Sha1Prepare.obj - -C_OBJS = $(C_OBJS) \ - $O\Sha1.obj - -!IF defined(USE_C_SHA) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" -C_OBJS = $(C_OBJS) \ - $O\Sha1Opt.obj -!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" -ASM_OBJS = $(ASM_OBJS) \ - $O\Sha1Opt.obj -!ENDIF +COMMON_OBJS = $(COMMON_OBJS) \ + $O\Sha1Prepare.obj + +C_OBJS = $(C_OBJS) \ + $O\Sha1.obj + +!IF defined(USE_C_SHA) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" +C_OBJS = $(C_OBJS) \ + $O\Sha1Opt.obj +!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" +ASM_OBJS = $(ASM_OBJS) \ + $O\Sha1Opt.obj +!ENDIF diff --git a/CPP/7zip/Sha256.mak b/CPP/7zip/Sha256.mak index 2012c8472..0bdbcb602 100644 --- a/CPP/7zip/Sha256.mak +++ b/CPP/7zip/Sha256.mak @@ -1,13 +1,13 @@ -COMMON_OBJS = $(COMMON_OBJS) \ - $O\Sha256Prepare.obj - -C_OBJS = $(C_OBJS) \ - $O\Sha256.obj - -!IF defined(USE_C_SHA) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" -C_OBJS = $(C_OBJS) \ - $O\Sha256Opt.obj -!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" -ASM_OBJS = $(ASM_OBJS) \ - $O\Sha256Opt.obj -!ENDIF +COMMON_OBJS = $(COMMON_OBJS) \ + $O\Sha256Prepare.obj + +C_OBJS = $(C_OBJS) \ + $O\Sha256.obj + +!IF defined(USE_C_SHA) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64" +C_OBJS = $(C_OBJS) \ + $O\Sha256Opt.obj +!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" +ASM_OBJS = $(ASM_OBJS) \ + $O\Sha256Opt.obj +!ENDIF diff --git a/CPP/7zip/SubBuild.mak b/CPP/7zip/SubBuild.mak index 0c49d3b71..f86ce4361 100644 --- a/CPP/7zip/SubBuild.mak +++ b/CPP/7zip/SubBuild.mak @@ -1,3 +1,3 @@ - cd $(@D) - $(MAKE) -nologo $(TARGETS) - cd .. + cd $(@D) + $(MAKE) -nologo $(TARGETS) + cd .. diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index e3f84fa74..46b740adc 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -1,1966 +1,1968 @@ -// Agent.cpp - -#include "StdAfx.h" - -#include - -#include "../../../../C/Sort.h" - -#include "../../../Common/ComTry.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariantConv.h" - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../Common/ArchiveExtractCallback.h" -#include "../FileManager/RegistryUtils.h" - -#include "Agent.h" - -using namespace NWindows; - -CCodecs *g_CodecsObj; - -static const bool k_keepEmptyDirPrefixes = - false; // 22.00 - // true; // 21.07 - -#ifdef Z7_EXTERNAL_CODECS - extern - CExternalCodecs g_ExternalCodecs; - CExternalCodecs g_ExternalCodecs; - extern - const CExternalCodecs *g_ExternalCodecs_Ptr; - const CExternalCodecs *g_ExternalCodecs_Ptr; - static CCodecs::CReleaser g_CodecsReleaser; -#else - extern - CMyComPtr g_CodecsRef; - CMyComPtr g_CodecsRef; -#endif - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - -void FreeGlobalCodecs() -{ - MT_LOCK - - #ifdef Z7_EXTERNAL_CODECS - if (g_CodecsObj) - { - g_CodecsObj->CloseLibs(); - } - g_CodecsReleaser.Set(NULL); - g_CodecsObj = NULL; - g_ExternalCodecs.ClearAndRelease(); - g_ExternalCodecs_Ptr = NULL; - #else - g_CodecsRef.Release(); - #endif -} - -HRESULT LoadGlobalCodecs() -{ - MT_LOCK - - if (g_CodecsObj) - return S_OK; - - g_CodecsObj = new CCodecs; - - #ifdef Z7_EXTERNAL_CODECS - g_ExternalCodecs.GetCodecs = g_CodecsObj; - g_ExternalCodecs.GetHashers = g_CodecsObj; - g_CodecsReleaser.Set(g_CodecsObj); - #else - g_CodecsRef.Release(); - g_CodecsRef = g_CodecsObj; - #endif - - RINOK(g_CodecsObj->Load()) - if (g_CodecsObj->Formats.IsEmpty()) - { - FreeGlobalCodecs(); - return E_NOTIMPL; - } - - Codecs_AddHashArcHandler(g_CodecsObj); - - #ifdef Z7_EXTERNAL_CODECS - RINOK(g_ExternalCodecs.Load()) - g_ExternalCodecs_Ptr = &g_ExternalCodecs; - #endif - - return S_OK; -} - -Z7_COM7F_IMF(CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder)) -{ - *agentFolder = this; - return S_OK; -} - -void CAgentFolder::LoadFolder(unsigned proxyDirIndex) -{ - CProxyItem item; - item.DirIndex = proxyDirIndex; - - if (_proxy2) - { - const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex]; - FOR_VECTOR (i, dir.Items) - { - item.Index = i; - _items.Add(item); - const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; - if (file.DirIndex != -1) - LoadFolder((unsigned)file.DirIndex); - if (_loadAltStreams && file.AltDirIndex != -1) - LoadFolder((unsigned)file.AltDirIndex); - } - return; - } - - const CProxyDir &dir = _proxy->Dirs[proxyDirIndex]; - unsigned i; - for (i = 0; i < dir.SubDirs.Size(); i++) - { - item.Index = i; - _items.Add(item); - LoadFolder(dir.SubDirs[i]); - } - - unsigned start = dir.SubDirs.Size(); - for (i = 0; i < dir.SubFiles.Size(); i++) - { - item.Index = start + i; - _items.Add(item); - } -} - -Z7_COM7F_IMF(CAgentFolder::LoadItems()) -{ - if (!_agentSpec->_archiveLink.IsOpen) - return E_FAIL; - _items.Clear(); - if (_flatMode) - { - LoadFolder(_proxyDirIndex); - if (_proxy2 && _loadAltStreams) - { - if (_proxyDirIndex == k_Proxy2_RootDirIndex) - LoadFolder(k_Proxy2_AltRootDirIndex); - } - } - return S_OK; -} - -Z7_COM7F_IMF(CAgentFolder::GetNumberOfItems(UInt32 *numItems)) -{ - if (_flatMode) - *numItems = _items.Size(); - else if (_proxy2) - *numItems = _proxy2->Dirs[_proxyDirIndex].Items.Size(); - else - { - const CProxyDir *dir = &_proxy->Dirs[_proxyDirIndex]; - *numItems = dir->SubDirs.Size() + dir->SubFiles.Size(); - } - return S_OK; -} - -#define SET_realIndex_AND_dir \ - unsigned realIndex; const CProxyDir *dir; \ - if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy->Dirs[item.DirIndex]; realIndex = item.Index; } \ - else { dir = &_proxy->Dirs[_proxyDirIndex]; realIndex = index; } - -#define SET_realIndex_AND_dir_2 \ - unsigned realIndex; const CProxyDir2 *dir; \ - if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy2->Dirs[item.DirIndex]; realIndex = item.Index; } \ - else { dir = &_proxy2->Dirs[_proxyDirIndex]; realIndex = index; } - -UString CAgentFolder::GetName(UInt32 index) const -{ - if (_proxy2) - { - SET_realIndex_AND_dir_2 - return _proxy2->Files[dir->Items[realIndex]].Name; - } - SET_realIndex_AND_dir - if (realIndex < dir->SubDirs.Size()) - return _proxy->Dirs[dir->SubDirs[realIndex]].Name; - return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name; -} - -void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const -{ - if (!_flatMode) - { - prefix.Empty(); - return; - } - - const CProxyItem &item = _items[index]; - unsigned proxyIndex = item.DirIndex; - - if (_proxy2) - { - // that code is unused. 7-Zip gets prefix via GetItemPrefix() . - - unsigned len = 0; - while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) - { - const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; - len += file.NameLen + 1; - proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); - } - - wchar_t *p = prefix.GetBuf_SetEnd(len) + len; - proxyIndex = item.DirIndex; - while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) - { - const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; - p--; - *p = WCHAR_PATH_SEPARATOR; - p -= file.NameLen; - wmemcpy(p, file.Name, file.NameLen); - proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); - } - } - else - { - unsigned len = 0; - while (proxyIndex != _proxyDirIndex) - { - const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; - len += dir->NameLen + 1; - proxyIndex = (unsigned)dir->ParentDir; - } - - wchar_t *p = prefix.GetBuf_SetEnd(len) + len; - proxyIndex = item.DirIndex; - while (proxyIndex != _proxyDirIndex) - { - const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; - p--; - *p = WCHAR_PATH_SEPARATOR; - p -= dir->NameLen; - wmemcpy(p, dir->Name, dir->NameLen); - proxyIndex = (unsigned)dir->ParentDir; - } - } -} - -UString CAgentFolder::GetFullPrefix(UInt32 index) const -{ - unsigned foldIndex = _proxyDirIndex; - - if (_flatMode) - foldIndex = _items[index].DirIndex; - - if (_proxy2) - return _proxy2->Dirs[foldIndex].PathPrefix; - else - return _proxy->GetDirPath_as_Prefix(foldIndex); -} - -Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(UInt32 index)) -{ - unsigned arcIndex; - if (_proxy2) - { - SET_realIndex_AND_dir_2 - arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.IsDir()) - { - const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex]; - if (!_flatMode) - return itemFolder.Size; - } - } - else - { - SET_realIndex_AND_dir - if (realIndex < dir->SubDirs.Size()) - { - const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; - if (!_flatMode) - return item.Size; - if (!item.IsLeaf()) - return 0; - arcIndex = (unsigned)item.ArcIndex; - } - else - { - arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; - } - } - NCOM::CPropVariant prop; - _agentSpec->GetArchive()->GetProperty(arcIndex, kpidSize, &prop); - if (prop.vt == VT_UI8) - return prop.uhVal.QuadPart; - else - return 0; -} - -Z7_COM7F_IMF(CAgentFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - if (propID == kpidPrefix) - { - if (_flatMode) - { - UString prefix; - GetPrefix(index, prefix); - prop = prefix; - } - } - else if (_proxy2) - { - SET_realIndex_AND_dir_2 - unsigned arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - /* - if (propID == kpidNumAltStreams) - { - if (item.AltDirIndex != -1) - prop = _proxy2->Dirs[item.AltDirIndex].Items.Size(); - } - else - */ - if (!item.IsDir()) - { - switch (propID) - { - case kpidIsDir: prop = false; break; - case kpidName: prop = item.Name; break; - default: return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value); - } - } - else - { - const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex]; - if (!_flatMode && propID == kpidSize) - prop = itemFolder.Size; - else if (!_flatMode && propID == kpidPackSize) - prop = itemFolder.PackSize; - else switch (propID) - { - case kpidIsDir: prop = true; break; - case kpidNumSubDirs: prop = itemFolder.NumSubDirs; break; - case kpidNumSubFiles: prop = itemFolder.NumSubFiles; break; - case kpidName: prop = item.Name; break; - case kpidCRC: - { - // if (itemFolder.IsLeaf) - if (!item.Ignore) - { - RINOK(_agentSpec->GetArchive()->GetProperty(arcIndex, propID, value)) - } - if (itemFolder.CrcIsDefined && value->vt == VT_EMPTY) - prop = itemFolder.Crc; - break; - } - default: - // if (itemFolder.IsLeaf) - if (!item.Ignore) - return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value); - } - } - } - else - { - SET_realIndex_AND_dir - if (realIndex < dir->SubDirs.Size()) - { - const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; - if (!_flatMode && propID == kpidSize) - prop = item.Size; - else if (!_flatMode && propID == kpidPackSize) - prop = item.PackSize; - else - switch (propID) - { - case kpidIsDir: prop = true; break; - case kpidNumSubDirs: prop = item.NumSubDirs; break; - case kpidNumSubFiles: prop = item.NumSubFiles; break; - case kpidName: prop = item.Name; break; - case kpidCRC: - { - if (item.IsLeaf()) - { - RINOK(_agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value)) - } - if (item.CrcIsDefined && value->vt == VT_EMPTY) - prop = item.Crc; - break; - } - default: - if (item.IsLeaf()) - return _agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value); - } - } - else - { - unsigned arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; - switch (propID) - { - case kpidIsDir: prop = false; break; - case kpidName: prop = _proxy->Files[arcIndex].Name; break; - default: - return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value); - } - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -static UInt64 GetUInt64Prop(IInArchive *archive, UInt32 index, PROPID propID) -{ - NCOM::CPropVariant prop; - if (archive->GetProperty(index, propID, &prop) != S_OK) - throw 111233443; - UInt64 v = 0; - if (ConvertPropVariantToUInt64(prop, v)) - return v; - return 0; -} - -Z7_COM7F_IMF(CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) -{ - if (_proxy2) - { - SET_realIndex_AND_dir_2 - unsigned arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - *name = item.Name; - *len = item.NameLen; - return S_OK; - } - else - { - SET_realIndex_AND_dir - if (realIndex < dir->SubDirs.Size()) - { - const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; - *name = item.Name; - *len = item.NameLen; - return S_OK; - } - else - { - const CProxyFile &item = _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]]; - *name = item.Name; - *len = item.NameLen; - return S_OK; - } - } -} - -Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) -{ - *name = NULL; - *len = 0; - if (!_flatMode) - return S_OK; - - if (_proxy2) - { - const CProxyItem &item = _items[index]; - const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix; - unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len(); - if (baseLen <= s.Len()) - { - *name = (const wchar_t *)s + baseLen; - *len = s.Len() - baseLen; - } - else - { - return E_FAIL; - // throw 111l; - } - } - return S_OK; -} - -static int CompareRawProps(IArchiveGetRawProps *rawProps, unsigned arcIndex1, unsigned arcIndex2, PROPID propID) -{ - // if (propID == kpidSha1) - if (rawProps) - { - const void *p1, *p2; - UInt32 size1, size2; - UInt32 propType1, propType2; - const HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1); - const HRESULT res2 = rawProps->GetRawProp(arcIndex2, propID, &p2, &size2, &propType2); - if (res1 == S_OK && res2 == S_OK) - { - for (UInt32 i = 0; i < size1 && i < size2; i++) - { - const Byte b1 = ((const Byte *)p1)[i]; - const Byte b2 = ((const Byte *)p2)[i]; - if (b1 < b2) return -1; - if (b1 > b2) return 1; - } - if (size1 < size2) return -1; - if (size1 > size2) return 1; - return 0; - } - } - return 0; -} - -// returns pointer to extension including '.' - -static const wchar_t *GetExtension(const wchar_t *name) -{ - for (const wchar_t *dotPtr = NULL;; name++) - { - wchar_t c = *name; - if (c == 0) - return dotPtr ? dotPtr : name; - if (c == '.') - dotPtr = name; - } -} - - -int CAgentFolder::CompareItems3(UInt32 index1, UInt32 index2, PROPID propID) -{ - NCOM::CPropVariant prop1, prop2; - // Name must be first property - GetProperty(index1, propID, &prop1); - GetProperty(index2, propID, &prop2); - if (prop1.vt != prop2.vt) - return MyCompare(prop1.vt, prop2.vt); - if (prop1.vt == VT_BSTR) - return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal); - return prop1.Compare(prop2); -} - - -int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw) -{ - unsigned realIndex1, realIndex2; - const CProxyDir2 *dir1, *dir2; - - if (_flatMode) - { - const CProxyItem &item1 = _items[index1]; - const CProxyItem &item2 = _items[index2]; - dir1 = &_proxy2->Dirs[item1.DirIndex]; - dir2 = &_proxy2->Dirs[item2.DirIndex]; - realIndex1 = item1.Index; - realIndex2 = item2.Index; - } - else - { - dir2 = dir1 = &_proxy2->Dirs[_proxyDirIndex]; - realIndex1 = index1; - realIndex2 = index2; - } - - UInt32 arcIndex1; - UInt32 arcIndex2; - bool isDir1, isDir2; - arcIndex1 = dir1->Items[realIndex1]; - arcIndex2 = dir2->Items[realIndex2]; - const CProxyFile2 &prox1 = _proxy2->Files[arcIndex1]; - const CProxyFile2 &prox2 = _proxy2->Files[arcIndex2]; - - if (propID == kpidName) - { - return CompareFileNames_ForFolderList(prox1.Name, prox2.Name); - } - - if (propID == kpidPrefix) - { - if (!_flatMode) - return 0; - return CompareFileNames_ForFolderList( - _proxy2->Dirs[_items[index1].DirIndex].PathPrefix, - _proxy2->Dirs[_items[index2].DirIndex].PathPrefix); - } - - if (propID == kpidExtension) - { - return CompareFileNames_ForFolderList( - GetExtension(prox1.Name), - GetExtension(prox2.Name)); - } - - isDir1 = prox1.IsDir(); - isDir2 = prox2.IsDir(); - - if (propID == kpidIsDir) - { - if (isDir1 == isDir2) - return 0; - return isDir1 ? -1 : 1; - } - - const CProxyDir2 *proxFolder1 = NULL; - const CProxyDir2 *proxFolder2 = NULL; - if (isDir1) proxFolder1 = &_proxy2->Dirs[prox1.DirIndex]; - if (isDir2) proxFolder2 = &_proxy2->Dirs[prox2.DirIndex]; - - if (propID == kpidNumSubDirs) - { - UInt32 n1 = 0; - UInt32 n2 = 0; - if (isDir1) n1 = proxFolder1->NumSubDirs; - if (isDir2) n2 = proxFolder2->NumSubDirs; - return MyCompare(n1, n2); - } - - if (propID == kpidNumSubFiles) - { - UInt32 n1 = 0; - UInt32 n2 = 0; - if (isDir1) n1 = proxFolder1->NumSubFiles; - if (isDir2) n2 = proxFolder2->NumSubFiles; - return MyCompare(n1, n2); - } - - if (propID == kpidSize) - { - UInt64 n1, n2; - if (isDir1) - n1 = _flatMode ? 0 : proxFolder1->Size; - else - n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize); - if (isDir2) - n2 = _flatMode ? 0 : proxFolder2->Size; - else - n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize); - return MyCompare(n1, n2); - } - - if (propID == kpidPackSize) - { - UInt64 n1, n2; - if (isDir1) - n1 = _flatMode ? 0 : proxFolder1->PackSize; - else - n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize); - if (isDir2) - n2 = _flatMode ? 0 : proxFolder2->PackSize; - else - n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize); - return MyCompare(n1, n2); - } - - if (propID == kpidCRC) - { - UInt64 n1, n2; - if (!isDir1 || !prox1.Ignore) - n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC); - else - n1 = proxFolder1->Crc; - if (!isDir2 || !prox2.Ignore) - n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC); - else - n2 = proxFolder2->Crc; - return MyCompare(n1, n2); - } - - if (propIsRaw) - return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID); - - return CompareItems3(index1, index2, propID); -} - - -Z7_COM7F_IMF2(Int32, CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)) -{ - try { - if (_proxy2) - return CompareItems2(index1, index2, propID, propIsRaw); - - unsigned realIndex1, realIndex2; - const CProxyDir *dir1, *dir2; - - if (_flatMode) - { - const CProxyItem &item1 = _items[index1]; - const CProxyItem &item2 = _items[index2]; - dir1 = &_proxy->Dirs[item1.DirIndex]; - dir2 = &_proxy->Dirs[item2.DirIndex]; - realIndex1 = item1.Index; - realIndex2 = item2.Index; - } - else - { - dir2 = dir1 = &_proxy->Dirs[_proxyDirIndex]; - realIndex1 = index1; - realIndex2 = index2; - } - - if (propID == kpidPrefix) - { - if (!_flatMode) - return 0; - UString prefix1, prefix2; - GetPrefix(index1, prefix1); - GetPrefix(index2, prefix2); - return CompareFileNames_ForFolderList(prefix1, prefix2); - } - - UInt32 arcIndex1; - UInt32 arcIndex2; - - const CProxyDir *proxFolder1 = NULL; - const CProxyDir *proxFolder2 = NULL; - - if (realIndex1 < dir1->SubDirs.Size()) - { - proxFolder1 = &_proxy->Dirs[dir1->SubDirs[realIndex1]]; - arcIndex1 = (unsigned)proxFolder1->ArcIndex; - } - else - arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()]; - - if (realIndex2 < dir2->SubDirs.Size()) - { - proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]]; - arcIndex2 = (unsigned)proxFolder2->ArcIndex; - } - else - arcIndex2 = dir2->SubFiles[realIndex2 - dir2->SubDirs.Size()]; - - if (propID == kpidName) - return CompareFileNames_ForFolderList( - proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name, - proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name); - - if (propID == kpidExtension) - return CompareFileNames_ForFolderList( - GetExtension(proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name), - GetExtension(proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name)); - - if (propID == kpidIsDir) - { - if (proxFolder1) - return proxFolder2 ? 0 : -1; - return proxFolder2 ? 1 : 0; - } - - if (propID == kpidNumSubDirs) - { - UInt32 n1 = 0; - UInt32 n2 = 0; - if (proxFolder1) n1 = proxFolder1->NumSubDirs; - if (proxFolder2) n2 = proxFolder2->NumSubDirs; - return MyCompare(n1, n2); - } - - if (propID == kpidNumSubFiles) - { - UInt32 n1 = 0; - UInt32 n2 = 0; - if (proxFolder1) n1 = proxFolder1->NumSubFiles; - if (proxFolder2) n2 = proxFolder2->NumSubFiles; - return MyCompare(n1, n2); - } - - if (propID == kpidSize) - { - UInt64 n1, n2; - if (proxFolder1) - n1 = _flatMode ? 0 : proxFolder1->Size; - else - n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize); - if (proxFolder2) - n2 = _flatMode ? 0 : proxFolder2->Size; - else - n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize); - return MyCompare(n1, n2); - } - - if (propID == kpidPackSize) - { - UInt64 n1, n2; - if (proxFolder1) - n1 = _flatMode ? 0 : proxFolder1->PackSize; - else - n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize); - if (proxFolder2) - n2 = _flatMode ? 0 : proxFolder2->PackSize; - else - n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize); - return MyCompare(n1, n2); - } - - if (propID == kpidCRC) - { - UInt64 n1, n2; - if (proxFolder1 && !proxFolder1->IsLeaf()) - n1 = proxFolder1->Crc; - else - n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC); - if (proxFolder2 && !proxFolder2->IsLeaf()) - n2 = proxFolder2->Crc; - else - n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC); - return MyCompare(n1, n2); - } - - if (propIsRaw) - { - bool isVirt1 = (proxFolder1 && !proxFolder1->IsLeaf()); - bool isVirt2 = (proxFolder2 && !proxFolder2->IsLeaf()); - if (isVirt1) - return isVirt2 ? 0 : -1; - if (isVirt2) - return 1; - return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID); - } - - return CompareItems3(index1, index2, propID); - - } catch(...) { return 0; } -} - - -HRESULT CAgentFolder::BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder) -{ - /* - CMyComPtr parentFolder; - - if (_proxy2) - { - const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex]; - int par = _proxy2->GetParentFolderOfFile(dir.ArcIndex); - if (par != (int)_proxyDirIndex) - { - RINOK(BindToFolder_Internal(par, &parentFolder)); - } - else - parentFolder = this; - } - else - { - const CProxyDir &dir = _proxy->Dirs[proxyDirIndex]; - if (dir.Parent != (int)_proxyDirIndex) - { - RINOK(BindToFolder_Internal(dir.Parent, &parentFolder)); - } - else - parentFolder = this; - } - */ - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) -{ - COM_TRY_BEGIN - if (_proxy2) - { - SET_realIndex_AND_dir_2 - const unsigned arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (!item.IsDir()) - return E_INVALIDARG; - return BindToFolder_Internal((unsigned)item.DirIndex, resultFolder); - } - SET_realIndex_AND_dir - if (realIndex >= (UInt32)dir->SubDirs.Size()) - return E_INVALIDARG; - return BindToFolder_Internal(dir->SubDirs[realIndex], resultFolder); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) -{ - COM_TRY_BEGIN - if (_proxy2) - { - const int index = _proxy2->FindItem(_proxyDirIndex, name, true); - if (index == -1) - return E_INVALIDARG; - return BindToFolder_Internal((unsigned)_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder); - } - const int index = _proxy->FindSubDir(_proxyDirIndex, name); - if (index == -1) - return E_INVALIDARG; - return BindToFolder_Internal((unsigned)index, resultFolder); - COM_TRY_END -} - - - -// ---------- IFolderAltStreams ---------- - -HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder) -{ - *resultFolder = NULL; - if (!_proxy2) - return S_OK; - - /* - CMyComPtr parentFolder; - - int par = _proxy2->GetParentFolderOfFile(_proxy2->Dirs[proxyDirIndex].ArcIndex); - if (par != (int)_proxyDirIndex) - { - RINOK(BindToFolder_Internal(par, &parentFolder)); - if (!parentFolder) - return S_OK; - } - else - parentFolder = this; - */ - - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **resultFolder)) -{ - COM_TRY_BEGIN - - *resultFolder = NULL; - - if (!_proxy2) - return S_OK; - - if (_proxy2->IsAltDir(_proxyDirIndex)) - return S_OK; - - { - if (index == (UInt32)(Int32)-1) - { - unsigned altDirIndex; - // IFolderFolder *parentFolder; - - if (_proxyDirIndex == k_Proxy2_RootDirIndex) - { - altDirIndex = k_Proxy2_AltRootDirIndex; - // parentFolder = this; // we want to use Root dir as parent for alt root - } - else - { - const unsigned arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.AltDirIndex == -1) - return S_OK; - altDirIndex = (unsigned)item.AltDirIndex; - // parentFolder = _parentFolder; - } - - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - return S_OK; - } - - SET_realIndex_AND_dir_2 - const unsigned arcIndex = dir->Items[realIndex]; - const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.AltDirIndex == -1) - return S_OK; - return BindToAltStreams_Internal((unsigned)item.AltDirIndex, resultFolder); - } - - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder)) -{ - COM_TRY_BEGIN - - *resultFolder = NULL; - - if (!_proxy2) - return S_OK; - - if (_proxy2->IsAltDir(_proxyDirIndex)) - return S_OK; - - if (name[0] == 0) - return BindToAltStreams((UInt32)(Int32)-1, resultFolder); - - { - const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; - FOR_VECTOR (i, dir.Items) - { - const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; - if (file.AltDirIndex != -1) - if (CompareFileNames(file.Name, name) == 0) - return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder); - } - return E_INVALIDARG; - } - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::AreAltStreamsSupported(UInt32 index, Int32 *isSupported)) -{ - *isSupported = BoolToInt(false); - - if (!_proxy2) - return S_OK; - - if (_proxy2->IsAltDir(_proxyDirIndex)) - return S_OK; - - unsigned arcIndex; - - if (index == (UInt32)(Int32)-1) - { - if (_proxyDirIndex == k_Proxy2_RootDirIndex) - { - *isSupported = BoolToInt(true); - return S_OK; - } - arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex; - } - else - { - SET_realIndex_AND_dir_2 - arcIndex = dir->Items[realIndex]; - } - - if (_proxy2->Files[arcIndex].AltDirIndex != -1) - *isSupported = BoolToInt(true); - return S_OK; -} - - -Z7_COM7F_IMF(CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder)) -{ - COM_TRY_BEGIN - /* - CMyComPtr parentFolder = _parentFolder; - *resultFolder = parentFolder.Detach(); - */ - *resultFolder = NULL; - - unsigned proxyDirIndex; - - if (_proxy2) - { - if (_proxyDirIndex == k_Proxy2_RootDirIndex) - return S_OK; - if (_proxyDirIndex == k_Proxy2_AltRootDirIndex) - proxyDirIndex = k_Proxy2_RootDirIndex; - else - { - const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex]; - const CProxyFile2 &file = _proxy2->Files[(unsigned)fold.ArcIndex]; - const int parentIndex = file.Parent; - if (parentIndex == -1) - proxyDirIndex = k_Proxy2_RootDirIndex; - else - proxyDirIndex = (unsigned)_proxy2->Files[(unsigned)parentIndex].DirIndex; - } - } - else - { - const int parent = _proxy->Dirs[_proxyDirIndex].ParentDir; - if (parent == -1) - return S_OK; - proxyDirIndex = (unsigned)parent; - } - - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr agentFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); - *resultFolder = agentFolder.Detach(); - - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - Z7_DECL_CMyComPtr_QI_FROM( - IInArchiveGetStream, - getStream, _agentSpec->GetArchive()) - if (!getStream) - return S_OK; - - UInt32 arcIndex; - if (_proxy2) - { - SET_realIndex_AND_dir_2 - arcIndex = dir->Items[realIndex]; - } - else - { - SET_realIndex_AND_dir - - if (realIndex < dir->SubDirs.Size()) - { - const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; - if (!item.IsLeaf()) - return S_OK; - arcIndex = (unsigned)item.ArcIndex; - } - else - arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; - } - return getStream->GetStream(arcIndex, stream); -} - -// static const unsigned k_FirstOptionalProp = 2; - -static const PROPID kProps[] = -{ - kpidNumSubDirs, - kpidNumSubFiles, - - // kpidNumAltStreams, - kpidPrefix -}; - -struct CArchiveItemPropertyTemp -{ - UString Name; - PROPID ID; - VARTYPE Type; -}; - -Z7_COM7F_IMF(CAgentFolder::GetNumberOfProperties(UInt32 *numProps)) -{ - COM_TRY_BEGIN - RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps)) - *numProps += Z7_ARRAY_SIZE(kProps); - if (!_flatMode) - (*numProps)--; - /* - if (!_agentSpec->ThereIsAltStreamProp) - (*numProps)--; - */ - /* - bool thereIsPathProp = _proxy2 ? - _agentSpec->_proxy2->ThereIsPathProp : - _agentSpec->_proxy->ThereIsPathProp; - */ - - // if there is kpidPath, we change kpidPath to kpidName - // if there is no kpidPath, we add kpidName. - if (!_agentSpec->ThereIsPathProp) - (*numProps)++; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) -{ - COM_TRY_BEGIN - UInt32 numProps; - _agentSpec->GetArchive()->GetNumberOfProperties(&numProps); - - /* - bool thereIsPathProp = _proxy2 ? - _agentSpec->_proxy2->ThereIsPathProp : - _agentSpec->_proxy->ThereIsPathProp; - */ - - if (!_agentSpec->ThereIsPathProp) - { - if (index == 0) - { - *propID = kpidName; - *varType = VT_BSTR; - *name = NULL; - return S_OK; - } - index--; - } - - if (index < numProps) - { - RINOK(_agentSpec->GetArchive()->GetPropertyInfo(index, name, propID, varType)) - if (*propID == kpidPath) - *propID = kpidName; - } - else - { - index -= numProps; - /* - if (index >= k_FirstOptionalProp) - { - if (!_agentSpec->ThereIsAltStreamProp) - index++; - } - */ - *propID = kProps[index]; - *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; - *name = NULL; - } - return S_OK; - COM_TRY_END -} - -static const PROPID kFolderProps[] = -{ - kpidSize, - kpidPackSize, - kpidNumSubDirs, - kpidNumSubFiles, - kpidCRC -}; - -Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - - NWindows::NCOM::CPropVariant prop; - - if (propID == kpidReadOnly) - { - if (_agentSpec->Is_Attrib_ReadOnly()) - prop = true; - else - prop = _agentSpec->IsThere_ReadOnlyArc(); - } - else if (propID == kpidIsHash) - { - prop = _agentSpec->_isHashHandler; - } - else if (_proxy2) - { - const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; - if (propID == kpidName) - { - if (dir.ArcIndex != -1) - prop = _proxy2->Files[(unsigned)dir.ArcIndex].Name; - } - else if (propID == kpidPath) - { - bool isAltStreamFolder = false; - prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder); - } - else switch (propID) - { - case kpidSize: prop = dir.Size; break; - case kpidPackSize: prop = dir.PackSize; break; - case kpidNumSubDirs: prop = dir.NumSubDirs; break; - case kpidNumSubFiles: prop = dir.NumSubFiles; break; - // case kpidName: prop = dir.Name; break; - // case kpidPath: prop = _proxy2->GetFullPathPrefix(_proxyDirIndex); break; - case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break; - case kpidCRC: if (dir.CrcIsDefined) { prop = dir.Crc; } break; - } - - } - else - { - const CProxyDir &dir = _proxy->Dirs[_proxyDirIndex]; - switch (propID) - { - case kpidSize: prop = dir.Size; break; - case kpidPackSize: prop = dir.PackSize; break; - case kpidNumSubDirs: prop = dir.NumSubDirs; break; - case kpidNumSubFiles: prop = dir.NumSubFiles; break; - case kpidName: prop = dir.Name; break; - case kpidPath: prop = _proxy->GetDirPath_as_Prefix(_proxyDirIndex); break; - case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break; - case kpidCRC: if (dir.CrcIsDefined) prop = dir.Crc; break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps)) -{ - *numProps = Z7_ARRAY_SIZE(kFolderProps); - return S_OK; -} - -IMP_IFolderFolder_GetProp( - CAgentFolder::GetFolderPropertyInfo, - kFolderProps) - -Z7_COM7F_IMF(CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */)) -{ - return E_FAIL; -} - - -Z7_COM7F_IMF(CAgentFolder::GetNumRawProps(UInt32 *numProps)) -{ - IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); - if (rawProps) - return rawProps->GetNumRawProps(numProps); - *numProps = 0; - return S_OK; -} - -Z7_COM7F_IMF(CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) -{ - IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); - if (rawProps) - return rawProps->GetRawPropInfo(index, name, propID); - return E_FAIL; -} - -Z7_COM7F_IMF(CAgentFolder::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); - if (rawProps) - { - unsigned arcIndex; - if (_proxy2) - { - SET_realIndex_AND_dir_2 - arcIndex = dir->Items[realIndex]; - } - else - { - SET_realIndex_AND_dir - if (realIndex < dir->SubDirs.Size()) - { - const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; - if (!item.IsLeaf()) - { - *data = NULL; - *dataSize = 0; - *propType = 0; - return S_OK; - } - arcIndex = (unsigned)item.ArcIndex; - } - else - arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; - } - return rawProps->GetRawProp(arcIndex, propID, data, dataSize, propType); - } - *data = NULL; - *dataSize = 0; - *propType = 0; - return S_OK; -} - -Z7_COM7F_IMF(CAgentFolder::GetFolderArcProps(IFolderArcProps **object)) -{ - CMyComPtr temp = _agentSpec; - *object = temp.Detach(); - return S_OK; -} - - -Z7_COM7F_IMF(CAgentFolder::SetFlatMode(Int32 flatMode)) -{ - _flatMode = IntToBool(flatMode); - return S_OK; -} - - -int CAgentFolder::GetRealIndex(unsigned index) const -{ - if (!_flatMode) - { - if (_proxy2) - return (int)_proxy2->GetRealIndex(_proxyDirIndex, index); - else - return _proxy->GetRealIndex(_proxyDirIndex, index); - } - { - const CProxyItem &item = _items[index]; - if (_proxy2) - { - const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex]; - return (int)dir->Items[item.Index]; - } - else - { - const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; - const unsigned realIndex = item.Index; - if (realIndex < dir->SubDirs.Size()) - { - const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]]; - if (!f.IsLeaf()) - return -1; - return f.ArcIndex; - } - return (int)dir->SubFiles[realIndex - dir->SubDirs.Size()]; - } - } -} - -void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const -{ - if (!_flatMode) - { - if (_proxy2) - _proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices); - else - _proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices); - return; - } - - realIndices.Clear(); - - for (UInt32 i = 0; i < numItems; i++) - { - const CProxyItem &item = _items[indices[i]]; - if (_proxy2) - { - const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex]; - _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices); - continue; - } - UInt32 arcIndex; - { - const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; - unsigned realIndex = item.Index; - if (realIndex < dir->SubDirs.Size()) - { - if (includeFolderSubItemsInFlatMode) - { - _proxy->AddRealIndices(dir->SubDirs[realIndex], realIndices); - continue; - } - const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]]; - if (!f.IsLeaf()) - continue; - arcIndex = (unsigned)f.ArcIndex; - } - else - arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; - } - realIndices.Add(arcIndex); - } - - HeapSort(realIndices.NonConstData(), realIndices.Size()); -} - -Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices, - UInt32 numItems, - Int32 includeAltStreams, - Int32 replaceAltStreamColon, - NExtract::NPathMode::EEnum pathMode, - NExtract::NOverwriteMode::EEnum overwriteMode, - const wchar_t *path, - Int32 testMode, - IFolderArchiveExtractCallback *extractCallback2)) -{ - COM_TRY_BEGIN - - if (!testMode && _agentSpec->_isHashHandler) - return E_NOTIMPL; - - CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; - CMyComPtr extractCallback = extractCallbackSpec; - UStringVector pathParts; - bool isAltStreamFolder = false; - if (_proxy2) - _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); - else - _proxy->GetDirPathParts(_proxyDirIndex, pathParts); - - /* - if (_flatMode) - pathMode = NExtract::NPathMode::kNoPathnames; - */ - - extractCallbackSpec->InitForMulti( - false, // multiArchives - pathMode, - overwriteMode, - _zoneMode, - k_keepEmptyDirPrefixes); - - if (extractCallback2) - extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); - - FString pathU; - if (path) - { - pathU = us2fs(path); - if (!pathU.IsEmpty() - && !NFile::NName::IsAltStreamPrefixWithColon(path)) - { - NFile::NName::NormalizeDirPathPrefix(pathU); - NFile::NDir::CreateComplexDir(pathU); - } - } - - CExtractNtOptions extractNtOptions; - extractNtOptions.AltStreams.Val = IntToBool(includeAltStreams); // change it!!! - extractNtOptions.AltStreams.Def = true; - - extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon); - - extractCallbackSpec->InitBeforeNewArchive(); - - #if defined(_WIN32) && !defined(UNDER_CE) - if (_zoneMode != NExtract::NZoneIdMode::kNone) - { - ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf); - } - #endif - - extractCallbackSpec->Init( - extractNtOptions, - NULL, &_agentSpec->GetArc(), - extractCallback2, - false, // stdOutMode - IntToBool(testMode), - pathU, - pathParts, isAltStreamFolder, - (UInt64)(Int64)-1); - - if (_proxy2) - extractCallbackSpec->SetBaseParentFolderIndex((unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex); - - // do we need another base folder for subfolders ? - extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix; - - CUIntVector realIndices; - GetRealIndices(indices, numItems, IntToBool(includeAltStreams), - false, // includeFolderSubItemsInFlatMode - realIndices); // - - #ifdef SUPPORT_LINKS - - if (!testMode) - { - RINOK(extractCallbackSpec->PrepareHardLinks(&realIndices)) - } - - #endif - - { - CArchiveExtractCallback_Closer ecsCloser(extractCallbackSpec); - - HRESULT res = _agentSpec->GetArchive()->Extract(realIndices.ConstData(), - realIndices.Size(), testMode, extractCallback); - - const HRESULT res2 = ecsCloser.Close(); - if (res == S_OK) - res = res2; - return res; - } - - COM_TRY_END -} - -///////////////////////////////////////// -// CAgent - -CAgent::CAgent(): - _proxy(NULL), - _proxy2(NULL), - _updatePathPrefix_is_AltFolder(false), - _isDeviceFile(false), - _isHashHandler(false) -{ -} - -CAgent::~CAgent() -{ - if (_proxy) - delete _proxy; - if (_proxy2) - delete _proxy2; -} - -bool CAgent::CanUpdate() const -{ - // FAR plugin uses empty agent to create new archive !!! - if (_archiveLink.Arcs.Size() == 0) - return true; - if (_isDeviceFile) - return false; - if (_archiveLink.Arcs.Size() != 1) - return false; - if (_archiveLink.Arcs[0].ErrorInfo.ThereIsTail) - return false; - return true; -} - -Z7_COM7F_IMF(CAgent::Open( - IInStream *inStream, - const wchar_t *filePath, - const wchar_t *arcFormat, - BSTR *archiveType, - IArchiveOpenCallback *openArchiveCallback)) -{ - COM_TRY_BEGIN - _archiveFilePath = filePath; - _hashBaseFolderPrefix.Empty(); - _attrib = 0; - _isDeviceFile = false; - _isHashHandler = false; - NFile::NFind::CFileInfo fi; - if (!inStream) - { - if (!fi.Find(us2fs(_archiveFilePath))) - return GetLastError_noZero_HRESULT(); - if (fi.IsDir()) - return E_FAIL; - _attrib = fi.Attrib; - _isDeviceFile = fi.IsDevice; - FString dirPrefix, fileName; - if (NFile::NDir::GetFullPathAndSplit(us2fs(_archiveFilePath), dirPrefix, fileName)) - { - NFile::NName::NormalizeDirPathPrefix(dirPrefix); - _hashBaseFolderPrefix = dirPrefix; - } - } - CArcInfoEx archiverInfo0, archiverInfo1; - - RINOK(LoadGlobalCodecs()) - - CObjectVector types; - if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types)) - return S_FALSE; - - /* - CObjectVector optProps; - if (Read_ShowDeleted()) - { - COptionalOpenProperties &optPair = optProps.AddNew(); - optPair.FormatName = "ntfs"; - // optPair.Props.AddNew().Name = "LS"; - optPair.Props.AddNew().Name = "LD"; - } - */ - - COpenOptions options; - options.props = NULL; - options.codecs = g_CodecsObj; - options.types = &types; - CIntVector exl; - options.excludedFormats = &exl; - options.stdInMode = false; - options.stream = inStream; - options.filePath = _archiveFilePath; - options.callback = openArchiveCallback; - - HRESULT res = _archiveLink.Open(options); - - if (!_archiveLink.Arcs.IsEmpty()) - { - CArc &arc = _archiveLink.Arcs.Back(); - if (!inStream) - { - arc.MTime.Set_From_FiTime(fi.MTime); - arc.MTime.Def = !fi.IsDevice; - } - - ArchiveType = GetTypeOfArc(arc); - if (archiveType) - { - RINOK(StringToBstr(ArchiveType, archiveType)) - } - - if (arc.IsHashHandler(options)) - _isHashHandler = true; - } - - return res; - - COM_TRY_END -} - - -Z7_COM7F_IMF(CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback)) -{ - COM_TRY_BEGIN - if (_proxy2) - { - delete _proxy2; - _proxy2 = NULL; - } - if (_proxy) - { - delete _proxy; - _proxy = NULL; - } - - CObjectVector incl; - CIntVector exl; - - COpenOptions options; - options.props = NULL; - options.codecs = g_CodecsObj; - options.types = &incl; - options.excludedFormats = &exl; - options.stdInMode = false; - options.filePath = _archiveFilePath; - options.callback = openArchiveCallback; - - RINOK(_archiveLink.ReOpen(options)) - return ReadItems(); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgent::Close()) -{ - COM_TRY_BEGIN - return _archiveLink.Close(); - COM_TRY_END -} - -/* -Z7_COM7F_IMF(CAgent::EnumProperties(IEnumSTATPROPSTG **EnumProperties) -{ - return _archive->EnumProperties(EnumProperties); -} -*/ - -HRESULT CAgent::ReadItems() -{ - if (_proxy || _proxy2) - return S_OK; - - const CArc &arc = GetArc(); - bool useProxy2 = (arc.GetRawProps && arc.IsTree); - - // useProxy2 = false; - - if (useProxy2) - _proxy2 = new CProxyArc2(); - else - _proxy = new CProxyArc(); - - { - ThereIsPathProp = false; - // ThereIsAltStreamProp = false; - UInt32 numProps; - arc.Archive->GetNumberOfProperties(&numProps); - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE varType; - RINOK(arc.Archive->GetPropertyInfo(i, &name, &propID, &varType)) - if (propID == kpidPath) - ThereIsPathProp = true; - /* - if (propID == kpidIsAltStream) - ThereIsAltStreamProp = true; - */ - } - } - - if (_proxy2) - return _proxy2->Load(GetArc(), NULL); - return _proxy->Load(GetArc(), NULL); -} - -Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder)) -{ - COM_TRY_BEGIN - if (!_archiveLink.Arcs.IsEmpty()) - { - RINOK(ReadItems()) - } - CAgentFolder *folderSpec = new CAgentFolder; - CMyComPtr rootFolder = folderSpec; - folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this); - *resultFolder = rootFolder.Detach(); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAgent::Extract( - NExtract::NPathMode::EEnum pathMode, - NExtract::NOverwriteMode::EEnum overwriteMode, - const wchar_t *path, - Int32 testMode, - IFolderArchiveExtractCallback *extractCallback2)) -{ - COM_TRY_BEGIN - - if (!testMode && _isHashHandler) - return E_NOTIMPL; - - CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; - CMyComPtr extractCallback = extractCallbackSpec; - extractCallbackSpec->InitForMulti( - false, // multiArchives - pathMode, - overwriteMode, - NExtract::NZoneIdMode::kNone, - k_keepEmptyDirPrefixes); - - CExtractNtOptions extractNtOptions; - extractNtOptions.AltStreams.Val = true; // change it!!! - extractNtOptions.AltStreams.Def = true; // change it!!! - extractNtOptions.ReplaceColonForAltStream = false; // change it!!! - - extractCallbackSpec->Init( - extractNtOptions, - NULL, &GetArc(), - extractCallback2, - false, // stdOutMode - IntToBool(testMode), - us2fs(path), - UStringVector(), false, - (UInt64)(Int64)-1); - - extractCallbackSpec->DirPathPrefix_for_HashFiles = _hashBaseFolderPrefix; - - #ifdef SUPPORT_LINKS - - if (!testMode) - { - RINOK(extractCallbackSpec->PrepareHardLinks(NULL)) // NULL means all items - } - - #endif - - return GetArchive()->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallback); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgent::GetNumberOfProperties(UInt32 *numProps)) -{ - COM_TRY_BEGIN - return GetArchive()->GetNumberOfProperties(numProps); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgent::GetPropertyInfo(UInt32 index, - BSTR *name, PROPID *propID, VARTYPE *varType)) -{ - COM_TRY_BEGIN - RINOK(GetArchive()->GetPropertyInfo(index, name, propID, varType)) - if (*propID == kpidPath) - *propID = kpidName; - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAgent::GetArcNumLevels(UInt32 *numLevels)) -{ - *numLevels = _archiveLink.Arcs.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - if (level > (UInt32)_archiveLink.Arcs.Size()) - return E_INVALIDARG; - if (level == (UInt32)_archiveLink.Arcs.Size()) - { - switch (propID) - { - case kpidPath: - if (!_archiveLink.NonOpen_ArcPath.IsEmpty()) - prop = _archiveLink.NonOpen_ArcPath; - break; - case kpidErrorType: - if (_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) - prop = g_CodecsObj->Formats[_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name; - break; - case kpidErrorFlags: - { - UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetErrorFlags(); - if (flags != 0) - prop = flags; - break; - } - case kpidWarningFlags: - { - UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetWarningFlags(); - if (flags != 0) - prop = flags; - break; - } - } - } - else - { - const CArc &arc = _archiveLink.Arcs[level]; - switch (propID) - { - case kpidType: prop = GetTypeOfArc(arc); break; - case kpidPath: prop = arc.Path; break; - case kpidErrorType: - if (arc.ErrorInfo.ErrorFormatIndex >= 0) - prop = g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name; - break; - case kpidErrorFlags: - { - const UInt32 flags = arc.ErrorInfo.GetErrorFlags(); - if (flags != 0) - prop = flags; - break; - } - case kpidWarningFlags: - { - const UInt32 flags = arc.ErrorInfo.GetWarningFlags(); - if (flags != 0) - prop = flags; - break; - } - case kpidOffset: - { - const Int64 v = arc.GetGlobalOffset(); - if (v != 0) - prop.Set_Int64(v); - break; - } - case kpidTailSize: - { - if (arc.ErrorInfo.TailSize != 0) - prop = arc.ErrorInfo.TailSize; - break; - } - default: return arc.Archive->GetArchiveProperty(propID, value); - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps)) -{ - return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps); -} - -Z7_COM7F_IMF(CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) -{ - return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType); -} - -// MainItemProperty -Z7_COM7F_IMF(CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value)) -{ - return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value); -} - -Z7_COM7F_IMF(CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps)) -{ - return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps); -} - -Z7_COM7F_IMF(CAgent::GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) -{ - return _archiveLink.Arcs[level - 1].Archive->GetPropertyInfo(index, name, propID, varType); -} +// Agent.cpp + +#include "StdAfx.h" + +#include + +#include "../../../../C/Sort.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariantConv.h" + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../Common/ArchiveExtractCallback.h" +#include "../FileManager/RegistryUtils.h" + +#include "Agent.h" + +using namespace NWindows; + +CCodecs *g_CodecsObj; + +static const bool k_keepEmptyDirPrefixes = + false; // 22.00 + // true; // 21.07 + +#ifdef Z7_EXTERNAL_CODECS + extern + CExternalCodecs g_ExternalCodecs; + CExternalCodecs g_ExternalCodecs; + extern + const CExternalCodecs *g_ExternalCodecs_Ptr; + const CExternalCodecs *g_ExternalCodecs_Ptr; + static CCodecs::CReleaser g_CodecsReleaser; +#else + extern + CMyComPtr g_CodecsRef; + CMyComPtr g_CodecsRef; +#endif + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + +void FreeGlobalCodecs() +{ + MT_LOCK + + #ifdef Z7_EXTERNAL_CODECS + if (g_CodecsObj) + { + g_CodecsObj->CloseLibs(); + } + g_CodecsReleaser.Set(NULL); + g_CodecsObj = NULL; + g_ExternalCodecs.ClearAndRelease(); + g_ExternalCodecs_Ptr = NULL; + #else + g_CodecsRef.Release(); + #endif +} + +HRESULT LoadGlobalCodecs() +{ + MT_LOCK + + if (g_CodecsObj) + return S_OK; + + g_CodecsObj = new CCodecs; + + #ifdef Z7_EXTERNAL_CODECS + g_ExternalCodecs.GetCodecs = g_CodecsObj; + g_ExternalCodecs.GetHashers = g_CodecsObj; + g_CodecsReleaser.Set(g_CodecsObj); + #else + g_CodecsRef.Release(); + g_CodecsRef = g_CodecsObj; + #endif + + RINOK(g_CodecsObj->Load()) + if (g_CodecsObj->Formats.IsEmpty()) + { + FreeGlobalCodecs(); + return E_NOTIMPL; + } + + Codecs_AddHashArcHandler(g_CodecsObj); + + #ifdef Z7_EXTERNAL_CODECS + RINOK(g_ExternalCodecs.Load()) + g_ExternalCodecs_Ptr = &g_ExternalCodecs; + #endif + + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder)) +{ + *agentFolder = this; + return S_OK; +} + +void CAgentFolder::LoadFolder(unsigned proxyDirIndex) +{ + CProxyItem item; + item.DirIndex = proxyDirIndex; + + if (_proxy2) + { + const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex]; + FOR_VECTOR (i, dir.Items) + { + item.Index = i; + _items.Add(item); + const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; + if (file.DirIndex != -1) + LoadFolder((unsigned)file.DirIndex); + if (_loadAltStreams && file.AltDirIndex != -1) + LoadFolder((unsigned)file.AltDirIndex); + } + return; + } + + const CProxyDir &dir = _proxy->Dirs[proxyDirIndex]; + unsigned i; + for (i = 0; i < dir.SubDirs.Size(); i++) + { + item.Index = i; + _items.Add(item); + LoadFolder(dir.SubDirs[i]); + } + + unsigned start = dir.SubDirs.Size(); + for (i = 0; i < dir.SubFiles.Size(); i++) + { + item.Index = start + i; + _items.Add(item); + } +} + +Z7_COM7F_IMF(CAgentFolder::LoadItems()) +{ + if (!_agentSpec->_archiveLink.IsOpen) + return E_FAIL; + _items.Clear(); + if (_flatMode) + { + LoadFolder(_proxyDirIndex); + if (_proxy2 && _loadAltStreams) + { + if (_proxyDirIndex == k_Proxy2_RootDirIndex) + LoadFolder(k_Proxy2_AltRootDirIndex); + } + } + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::GetNumberOfItems(UInt32 *numItems)) +{ + if (_flatMode) + *numItems = _items.Size(); + else if (_proxy2) + *numItems = _proxy2->Dirs[_proxyDirIndex].Items.Size(); + else + { + const CProxyDir *dir = &_proxy->Dirs[_proxyDirIndex]; + *numItems = dir->SubDirs.Size() + dir->SubFiles.Size(); + } + return S_OK; +} + +#define SET_realIndex_AND_dir \ + unsigned realIndex; const CProxyDir *dir; \ + if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy->Dirs[item.DirIndex]; realIndex = item.Index; } \ + else { dir = &_proxy->Dirs[_proxyDirIndex]; realIndex = index; } + +#define SET_realIndex_AND_dir_2 \ + unsigned realIndex; const CProxyDir2 *dir; \ + if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy2->Dirs[item.DirIndex]; realIndex = item.Index; } \ + else { dir = &_proxy2->Dirs[_proxyDirIndex]; realIndex = index; } + +UString CAgentFolder::GetName(UInt32 index) const +{ + if (_proxy2) + { + SET_realIndex_AND_dir_2 + return _proxy2->Files[dir->Items[realIndex]].Name; + } + SET_realIndex_AND_dir + if (realIndex < dir->SubDirs.Size()) + return _proxy->Dirs[dir->SubDirs[realIndex]].Name; + return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name; +} + +void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const +{ + if (!_flatMode) + { + prefix.Empty(); + return; + } + + const CProxyItem &item = _items[index]; + unsigned proxyIndex = item.DirIndex; + + if (_proxy2) + { + // that code is unused. 7-Zip gets prefix via GetItemPrefix() . + + unsigned len = 0; + while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) + { + const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; + len += file.NameLen + 1; + proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); + } + + wchar_t *p = prefix.GetBuf_SetEnd(len) + len; + proxyIndex = item.DirIndex; + while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) + { + const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; + p--; + *p = WCHAR_PATH_SEPARATOR; + p -= file.NameLen; + wmemcpy(p, file.Name, file.NameLen); + proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); + } + } + else + { + unsigned len = 0; + while (proxyIndex != _proxyDirIndex) + { + const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; + len += dir->NameLen + 1; + proxyIndex = (unsigned)dir->ParentDir; + } + + wchar_t *p = prefix.GetBuf_SetEnd(len) + len; + proxyIndex = item.DirIndex; + while (proxyIndex != _proxyDirIndex) + { + const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; + p--; + *p = WCHAR_PATH_SEPARATOR; + p -= dir->NameLen; + wmemcpy(p, dir->Name, dir->NameLen); + proxyIndex = (unsigned)dir->ParentDir; + } + } +} + +UString CAgentFolder::GetFullPrefix(UInt32 index) const +{ + unsigned foldIndex = _proxyDirIndex; + + if (_flatMode) + foldIndex = _items[index].DirIndex; + + if (_proxy2) + return _proxy2->Dirs[foldIndex].PathPrefix; + else + return _proxy->GetDirPath_as_Prefix(foldIndex); +} + +Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(UInt32 index)) +{ + unsigned arcIndex; + if (_proxy2) + { + SET_realIndex_AND_dir_2 + arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (item.IsDir()) + { + const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex]; + if (!_flatMode) + return itemFolder.Size; + } + } + else + { + SET_realIndex_AND_dir + if (realIndex < dir->SubDirs.Size()) + { + const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; + if (!_flatMode) + return item.Size; + if (!item.IsLeaf()) + return 0; + arcIndex = (unsigned)item.ArcIndex; + } + else + { + arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; + } + } + NCOM::CPropVariant prop; + _agentSpec->GetArchive()->GetProperty(arcIndex, kpidSize, &prop); + if (prop.vt == VT_UI8) + return prop.uhVal.QuadPart; + else + return 0; +} + +Z7_COM7F_IMF(CAgentFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + if (propID == kpidPrefix) + { + if (_flatMode) + { + UString prefix; + GetPrefix(index, prefix); + prop = prefix; + } + } + else if (_proxy2) + { + SET_realIndex_AND_dir_2 + unsigned arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + /* + if (propID == kpidNumAltStreams) + { + if (item.AltDirIndex != -1) + prop = _proxy2->Dirs[item.AltDirIndex].Items.Size(); + } + else + */ + if (!item.IsDir()) + { + switch (propID) + { + case kpidIsDir: prop = false; break; + case kpidName: prop = item.Name; break; + default: return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value); + } + } + else + { + const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex]; + if (!_flatMode && propID == kpidSize) + prop = itemFolder.Size; + else if (!_flatMode && propID == kpidPackSize) + prop = itemFolder.PackSize; + else switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidNumSubDirs: prop = itemFolder.NumSubDirs; break; + case kpidNumSubFiles: prop = itemFolder.NumSubFiles; break; + case kpidName: prop = item.Name; break; + case kpidCRC: + { + // if (itemFolder.IsLeaf) + if (!item.Ignore) + { + RINOK(_agentSpec->GetArchive()->GetProperty(arcIndex, propID, value)) + } + if (itemFolder.CrcIsDefined && value->vt == VT_EMPTY) + prop = itemFolder.Crc; + break; + } + default: + // if (itemFolder.IsLeaf) + if (!item.Ignore) + return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value); + } + } + } + else + { + SET_realIndex_AND_dir + if (realIndex < dir->SubDirs.Size()) + { + const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; + if (!_flatMode && propID == kpidSize) + prop = item.Size; + else if (!_flatMode && propID == kpidPackSize) + prop = item.PackSize; + else + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidNumSubDirs: prop = item.NumSubDirs; break; + case kpidNumSubFiles: prop = item.NumSubFiles; break; + case kpidName: prop = item.Name; break; + case kpidCRC: + { + if (item.IsLeaf()) + { + RINOK(_agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value)) + } + if (item.CrcIsDefined && value->vt == VT_EMPTY) + prop = item.Crc; + break; + } + default: + if (item.IsLeaf()) + return _agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value); + } + } + else + { + unsigned arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; + switch (propID) + { + case kpidIsDir: prop = false; break; + case kpidName: prop = _proxy->Files[arcIndex].Name; break; + default: + return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value); + } + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +static UInt64 GetUInt64Prop(IInArchive *archive, UInt32 index, PROPID propID) +{ + NCOM::CPropVariant prop; + if (archive->GetProperty(index, propID, &prop) != S_OK) + throw 111233443; + UInt64 v = 0; + if (ConvertPropVariantToUInt64(prop, v)) + return v; + return 0; +} + +Z7_COM7F_IMF(CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) +{ + if (_proxy2) + { + SET_realIndex_AND_dir_2 + unsigned arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + *name = item.Name; + *len = item.NameLen; + return S_OK; + } + else + { + SET_realIndex_AND_dir + if (realIndex < dir->SubDirs.Size()) + { + const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; + *name = item.Name; + *len = item.NameLen; + return S_OK; + } + else + { + const CProxyFile &item = _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]]; + *name = item.Name; + *len = item.NameLen; + return S_OK; + } + } +} + +Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) +{ + *name = NULL; + *len = 0; + if (!_flatMode) + return S_OK; + + if (_proxy2) + { + const CProxyItem &item = _items[index]; + const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix; + unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len(); + if (baseLen <= s.Len()) + { + *name = (const wchar_t *)s + baseLen; + *len = s.Len() - baseLen; + } + else + { + return E_FAIL; + // throw 111l; + } + } + return S_OK; +} + +static int CompareRawProps(IArchiveGetRawProps *rawProps, unsigned arcIndex1, unsigned arcIndex2, PROPID propID) +{ + // if (propID == kpidSha1) + if (rawProps) + { + const void *p1, *p2; + UInt32 size1, size2; + UInt32 propType1, propType2; + const HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1); + const HRESULT res2 = rawProps->GetRawProp(arcIndex2, propID, &p2, &size2, &propType2); + if (res1 == S_OK && res2 == S_OK) + { + for (UInt32 i = 0; i < size1 && i < size2; i++) + { + const Byte b1 = ((const Byte *)p1)[i]; + const Byte b2 = ((const Byte *)p2)[i]; + if (b1 < b2) return -1; + if (b1 > b2) return 1; + } + if (size1 < size2) return -1; + if (size1 > size2) return 1; + return 0; + } + } + return 0; +} + +// returns pointer to extension including '.' + +static const wchar_t *GetExtension(const wchar_t *name) +{ + for (const wchar_t *dotPtr = NULL;; name++) + { + wchar_t c = *name; + if (c == 0) + return dotPtr ? dotPtr : name; + if (c == '.') + dotPtr = name; + } +} + + +int CAgentFolder::CompareItems3(UInt32 index1, UInt32 index2, PROPID propID) +{ + NCOM::CPropVariant prop1, prop2; + // Name must be first property + GetProperty(index1, propID, &prop1); + GetProperty(index2, propID, &prop2); + if (prop1.vt != prop2.vt) + return MyCompare(prop1.vt, prop2.vt); + if (prop1.vt == VT_BSTR) + return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal); + return prop1.Compare(prop2); +} + + +int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw) +{ + unsigned realIndex1, realIndex2; + const CProxyDir2 *dir1, *dir2; + + if (_flatMode) + { + const CProxyItem &item1 = _items[index1]; + const CProxyItem &item2 = _items[index2]; + dir1 = &_proxy2->Dirs[item1.DirIndex]; + dir2 = &_proxy2->Dirs[item2.DirIndex]; + realIndex1 = item1.Index; + realIndex2 = item2.Index; + } + else + { + dir2 = dir1 = &_proxy2->Dirs[_proxyDirIndex]; + realIndex1 = index1; + realIndex2 = index2; + } + + UInt32 arcIndex1; + UInt32 arcIndex2; + bool isDir1, isDir2; + arcIndex1 = dir1->Items[realIndex1]; + arcIndex2 = dir2->Items[realIndex2]; + const CProxyFile2 &prox1 = _proxy2->Files[arcIndex1]; + const CProxyFile2 &prox2 = _proxy2->Files[arcIndex2]; + + if (propID == kpidName) + { + return CompareFileNames_ForFolderList(prox1.Name, prox2.Name); + } + + if (propID == kpidPrefix) + { + if (!_flatMode) + return 0; + return CompareFileNames_ForFolderList( + _proxy2->Dirs[_items[index1].DirIndex].PathPrefix, + _proxy2->Dirs[_items[index2].DirIndex].PathPrefix); + } + + if (propID == kpidExtension) + { + return CompareFileNames_ForFolderList( + GetExtension(prox1.Name), + GetExtension(prox2.Name)); + } + + isDir1 = prox1.IsDir(); + isDir2 = prox2.IsDir(); + + if (propID == kpidIsDir) + { + if (isDir1 == isDir2) + return 0; + return isDir1 ? -1 : 1; + } + + const CProxyDir2 *proxFolder1 = NULL; + const CProxyDir2 *proxFolder2 = NULL; + if (isDir1) proxFolder1 = &_proxy2->Dirs[prox1.DirIndex]; + if (isDir2) proxFolder2 = &_proxy2->Dirs[prox2.DirIndex]; + + if (propID == kpidNumSubDirs) + { + UInt32 n1 = 0; + UInt32 n2 = 0; + if (isDir1) n1 = proxFolder1->NumSubDirs; + if (isDir2) n2 = proxFolder2->NumSubDirs; + return MyCompare(n1, n2); + } + + if (propID == kpidNumSubFiles) + { + UInt32 n1 = 0; + UInt32 n2 = 0; + if (isDir1) n1 = proxFolder1->NumSubFiles; + if (isDir2) n2 = proxFolder2->NumSubFiles; + return MyCompare(n1, n2); + } + + if (propID == kpidSize) + { + UInt64 n1, n2; + if (isDir1) + n1 = _flatMode ? 0 : proxFolder1->Size; + else + n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize); + if (isDir2) + n2 = _flatMode ? 0 : proxFolder2->Size; + else + n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize); + return MyCompare(n1, n2); + } + + if (propID == kpidPackSize) + { + UInt64 n1, n2; + if (isDir1) + n1 = _flatMode ? 0 : proxFolder1->PackSize; + else + n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize); + if (isDir2) + n2 = _flatMode ? 0 : proxFolder2->PackSize; + else + n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize); + return MyCompare(n1, n2); + } + + if (propID == kpidCRC) + { + UInt64 n1, n2; + if (!isDir1 || !prox1.Ignore) + n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC); + else + n1 = proxFolder1->Crc; + if (!isDir2 || !prox2.Ignore) + n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC); + else + n2 = proxFolder2->Crc; + return MyCompare(n1, n2); + } + + if (propIsRaw) + return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID); + + return CompareItems3(index1, index2, propID); +} + + +Z7_COM7F_IMF2(Int32, CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)) +{ + try { + if (_proxy2) + return CompareItems2(index1, index2, propID, propIsRaw); + + unsigned realIndex1, realIndex2; + const CProxyDir *dir1, *dir2; + + if (_flatMode) + { + const CProxyItem &item1 = _items[index1]; + const CProxyItem &item2 = _items[index2]; + dir1 = &_proxy->Dirs[item1.DirIndex]; + dir2 = &_proxy->Dirs[item2.DirIndex]; + realIndex1 = item1.Index; + realIndex2 = item2.Index; + } + else + { + dir2 = dir1 = &_proxy->Dirs[_proxyDirIndex]; + realIndex1 = index1; + realIndex2 = index2; + } + + if (propID == kpidPrefix) + { + if (!_flatMode) + return 0; + UString prefix1, prefix2; + GetPrefix(index1, prefix1); + GetPrefix(index2, prefix2); + return CompareFileNames_ForFolderList(prefix1, prefix2); + } + + UInt32 arcIndex1; + UInt32 arcIndex2; + + const CProxyDir *proxFolder1 = NULL; + const CProxyDir *proxFolder2 = NULL; + + if (realIndex1 < dir1->SubDirs.Size()) + { + proxFolder1 = &_proxy->Dirs[dir1->SubDirs[realIndex1]]; + arcIndex1 = (unsigned)proxFolder1->ArcIndex; + } + else + arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()]; + + if (realIndex2 < dir2->SubDirs.Size()) + { + proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]]; + arcIndex2 = (unsigned)proxFolder2->ArcIndex; + } + else + arcIndex2 = dir2->SubFiles[realIndex2 - dir2->SubDirs.Size()]; + + if (propID == kpidName) + return CompareFileNames_ForFolderList( + proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name, + proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name); + + if (propID == kpidExtension) + return CompareFileNames_ForFolderList( + GetExtension(proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name), + GetExtension(proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name)); + + if (propID == kpidIsDir) + { + if (proxFolder1) + return proxFolder2 ? 0 : -1; + return proxFolder2 ? 1 : 0; + } + + if (propID == kpidNumSubDirs) + { + UInt32 n1 = 0; + UInt32 n2 = 0; + if (proxFolder1) n1 = proxFolder1->NumSubDirs; + if (proxFolder2) n2 = proxFolder2->NumSubDirs; + return MyCompare(n1, n2); + } + + if (propID == kpidNumSubFiles) + { + UInt32 n1 = 0; + UInt32 n2 = 0; + if (proxFolder1) n1 = proxFolder1->NumSubFiles; + if (proxFolder2) n2 = proxFolder2->NumSubFiles; + return MyCompare(n1, n2); + } + + if (propID == kpidSize) + { + UInt64 n1, n2; + if (proxFolder1) + n1 = _flatMode ? 0 : proxFolder1->Size; + else + n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize); + if (proxFolder2) + n2 = _flatMode ? 0 : proxFolder2->Size; + else + n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize); + return MyCompare(n1, n2); + } + + if (propID == kpidPackSize) + { + UInt64 n1, n2; + if (proxFolder1) + n1 = _flatMode ? 0 : proxFolder1->PackSize; + else + n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize); + if (proxFolder2) + n2 = _flatMode ? 0 : proxFolder2->PackSize; + else + n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize); + return MyCompare(n1, n2); + } + + if (propID == kpidCRC) + { + UInt64 n1, n2; + if (proxFolder1 && !proxFolder1->IsLeaf()) + n1 = proxFolder1->Crc; + else + n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC); + if (proxFolder2 && !proxFolder2->IsLeaf()) + n2 = proxFolder2->Crc; + else + n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC); + return MyCompare(n1, n2); + } + + if (propIsRaw) + { + bool isVirt1 = (proxFolder1 && !proxFolder1->IsLeaf()); + bool isVirt2 = (proxFolder2 && !proxFolder2->IsLeaf()); + if (isVirt1) + return isVirt2 ? 0 : -1; + if (isVirt2) + return 1; + return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID); + } + + return CompareItems3(index1, index2, propID); + + } catch(...) { return 0; } +} + + +HRESULT CAgentFolder::BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder) +{ + /* + CMyComPtr parentFolder; + + if (_proxy2) + { + const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex]; + int par = _proxy2->GetParentFolderOfFile(dir.ArcIndex); + if (par != (int)_proxyDirIndex) + { + RINOK(BindToFolder_Internal(par, &parentFolder)); + } + else + parentFolder = this; + } + else + { + const CProxyDir &dir = _proxy->Dirs[proxyDirIndex]; + if (dir.Parent != (int)_proxyDirIndex) + { + RINOK(BindToFolder_Internal(dir.Parent, &parentFolder)); + } + else + parentFolder = this; + } + */ + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) +{ + COM_TRY_BEGIN + if (_proxy2) + { + SET_realIndex_AND_dir_2 + const unsigned arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (!item.IsDir()) + return E_INVALIDARG; + return BindToFolder_Internal((unsigned)item.DirIndex, resultFolder); + } + SET_realIndex_AND_dir + if (realIndex >= (UInt32)dir->SubDirs.Size()) + return E_INVALIDARG; + return BindToFolder_Internal(dir->SubDirs[realIndex], resultFolder); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) +{ + COM_TRY_BEGIN + if (_proxy2) + { + const int index = _proxy2->FindItem(_proxyDirIndex, name, true); + if (index == -1) + return E_INVALIDARG; + return BindToFolder_Internal((unsigned)_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder); + } + const int index = _proxy->FindSubDir(_proxyDirIndex, name); + if (index == -1) + return E_INVALIDARG; + return BindToFolder_Internal((unsigned)index, resultFolder); + COM_TRY_END +} + + + +// ---------- IFolderAltStreams ---------- + +HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder) +{ + *resultFolder = NULL; + if (!_proxy2) + return S_OK; + + /* + CMyComPtr parentFolder; + + int par = _proxy2->GetParentFolderOfFile(_proxy2->Dirs[proxyDirIndex].ArcIndex); + if (par != (int)_proxyDirIndex) + { + RINOK(BindToFolder_Internal(par, &parentFolder)); + if (!parentFolder) + return S_OK; + } + else + parentFolder = this; + */ + + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **resultFolder)) +{ + COM_TRY_BEGIN + + *resultFolder = NULL; + + if (!_proxy2) + return S_OK; + + if (_proxy2->IsAltDir(_proxyDirIndex)) + return S_OK; + + { + if (index == (UInt32)(Int32)-1) + { + unsigned altDirIndex; + // IFolderFolder *parentFolder; + + if (_proxyDirIndex == k_Proxy2_RootDirIndex) + { + altDirIndex = k_Proxy2_AltRootDirIndex; + // parentFolder = this; // we want to use Root dir as parent for alt root + } + else + { + const unsigned arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (item.AltDirIndex == -1) + return S_OK; + altDirIndex = (unsigned)item.AltDirIndex; + // parentFolder = _parentFolder; + } + + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + return S_OK; + } + + SET_realIndex_AND_dir_2 + const unsigned arcIndex = dir->Items[realIndex]; + const CProxyFile2 &item = _proxy2->Files[arcIndex]; + if (item.AltDirIndex == -1) + return S_OK; + return BindToAltStreams_Internal((unsigned)item.AltDirIndex, resultFolder); + } + + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder)) +{ + COM_TRY_BEGIN + + *resultFolder = NULL; + + if (!_proxy2) + return S_OK; + + if (_proxy2->IsAltDir(_proxyDirIndex)) + return S_OK; + + if (name[0] == 0) + return BindToAltStreams((UInt32)(Int32)-1, resultFolder); + + { + const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; + FOR_VECTOR (i, dir.Items) + { + const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; + if (file.AltDirIndex != -1) + if (CompareFileNames(file.Name, name) == 0) + return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder); + } + return E_INVALIDARG; + } + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::AreAltStreamsSupported(UInt32 index, Int32 *isSupported)) +{ + *isSupported = BoolToInt(false); + + if (!_proxy2) + return S_OK; + + if (_proxy2->IsAltDir(_proxyDirIndex)) + return S_OK; + + unsigned arcIndex; + + if (index == (UInt32)(Int32)-1) + { + if (_proxyDirIndex == k_Proxy2_RootDirIndex) + { + *isSupported = BoolToInt(true); + return S_OK; + } + arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex; + } + else + { + SET_realIndex_AND_dir_2 + arcIndex = dir->Items[realIndex]; + } + + if (_proxy2->Files[arcIndex].AltDirIndex != -1) + *isSupported = BoolToInt(true); + return S_OK; +} + + +Z7_COM7F_IMF(CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder)) +{ + COM_TRY_BEGIN + /* + CMyComPtr parentFolder = _parentFolder; + *resultFolder = parentFolder.Detach(); + */ + *resultFolder = NULL; + + unsigned proxyDirIndex; + + if (_proxy2) + { + if (_proxyDirIndex == k_Proxy2_RootDirIndex) + return S_OK; + if (_proxyDirIndex == k_Proxy2_AltRootDirIndex) + proxyDirIndex = k_Proxy2_RootDirIndex; + else + { + const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex]; + const CProxyFile2 &file = _proxy2->Files[(unsigned)fold.ArcIndex]; + const int parentIndex = file.Parent; + if (parentIndex == -1) + proxyDirIndex = k_Proxy2_RootDirIndex; + else + proxyDirIndex = (unsigned)_proxy2->Files[(unsigned)parentIndex].DirIndex; + } + } + else + { + const int parent = _proxy->Dirs[_proxyDirIndex].ParentDir; + if (parent == -1) + return S_OK; + proxyDirIndex = (unsigned)parent; + } + + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr agentFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec); + *resultFolder = agentFolder.Detach(); + + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + Z7_DECL_CMyComPtr_QI_FROM( + IInArchiveGetStream, + getStream, _agentSpec->GetArchive()) + if (!getStream) + return S_OK; + + UInt32 arcIndex; + if (_proxy2) + { + SET_realIndex_AND_dir_2 + arcIndex = dir->Items[realIndex]; + } + else + { + SET_realIndex_AND_dir + + if (realIndex < dir->SubDirs.Size()) + { + const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; + if (!item.IsLeaf()) + return S_OK; + arcIndex = (unsigned)item.ArcIndex; + } + else + arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; + } + return getStream->GetStream(arcIndex, stream); +} + +// static const unsigned k_FirstOptionalProp = 2; + +static const PROPID kProps[] = +{ + kpidNumSubDirs, + kpidNumSubFiles, + + // kpidNumAltStreams, + kpidPrefix +}; + +struct CArchiveItemPropertyTemp +{ + UString Name; + PROPID ID; + VARTYPE Type; +}; + +Z7_COM7F_IMF(CAgentFolder::GetNumberOfProperties(UInt32 *numProps)) +{ + COM_TRY_BEGIN + RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps)) + *numProps += Z7_ARRAY_SIZE(kProps); + if (!_flatMode) + (*numProps)--; + /* + if (!_agentSpec->ThereIsAltStreamProp) + (*numProps)--; + */ + /* + bool thereIsPathProp = _proxy2 ? + _agentSpec->_proxy2->ThereIsPathProp : + _agentSpec->_proxy->ThereIsPathProp; + */ + + // if there is kpidPath, we change kpidPath to kpidName + // if there is no kpidPath, we add kpidName. + if (!_agentSpec->ThereIsPathProp) + (*numProps)++; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) +{ + COM_TRY_BEGIN + UInt32 numProps; + _agentSpec->GetArchive()->GetNumberOfProperties(&numProps); + + /* + bool thereIsPathProp = _proxy2 ? + _agentSpec->_proxy2->ThereIsPathProp : + _agentSpec->_proxy->ThereIsPathProp; + */ + + if (!_agentSpec->ThereIsPathProp) + { + if (index == 0) + { + *propID = kpidName; + *varType = VT_BSTR; + *name = NULL; + return S_OK; + } + index--; + } + + if (index < numProps) + { + RINOK(_agentSpec->GetArchive()->GetPropertyInfo(index, name, propID, varType)) + if (*propID == kpidPath) + *propID = kpidName; + } + else + { + index -= numProps; + /* + if (index >= k_FirstOptionalProp) + { + if (!_agentSpec->ThereIsAltStreamProp) + index++; + } + */ + *propID = kProps[index]; + *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; + *name = NULL; + } + return S_OK; + COM_TRY_END +} + +static const PROPID kFolderProps[] = +{ + kpidSize, + kpidPackSize, + kpidNumSubDirs, + kpidNumSubFiles, + kpidCRC +}; + +Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + + NWindows::NCOM::CPropVariant prop; + + if (propID == kpidReadOnly) + { + if (_agentSpec->Is_Attrib_ReadOnly()) + prop = true; + else + prop = _agentSpec->IsThere_ReadOnlyArc(); + } + else if (propID == kpidIsHash) + { + prop = _agentSpec->_isHashHandler; + } + else if (_proxy2) + { + const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; + if (propID == kpidName) + { + if (dir.ArcIndex != -1) + prop = _proxy2->Files[(unsigned)dir.ArcIndex].Name; + } + else if (propID == kpidPath) + { + bool isAltStreamFolder = false; + prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder); + } + else switch (propID) + { + case kpidSize: prop = dir.Size; break; + case kpidPackSize: prop = dir.PackSize; break; + case kpidNumSubDirs: prop = dir.NumSubDirs; break; + case kpidNumSubFiles: prop = dir.NumSubFiles; break; + // case kpidName: prop = dir.Name; break; + // case kpidPath: prop = _proxy2->GetFullPathPrefix(_proxyDirIndex); break; + case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break; + case kpidCRC: if (dir.CrcIsDefined) { prop = dir.Crc; } break; + } + + } + else + { + const CProxyDir &dir = _proxy->Dirs[_proxyDirIndex]; + switch (propID) + { + case kpidSize: prop = dir.Size; break; + case kpidPackSize: prop = dir.PackSize; break; + case kpidNumSubDirs: prop = dir.NumSubDirs; break; + case kpidNumSubFiles: prop = dir.NumSubFiles; break; + case kpidName: prop = dir.Name; break; + case kpidPath: prop = _proxy->GetDirPath_as_Prefix(_proxyDirIndex); break; + case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break; + case kpidCRC: if (dir.CrcIsDefined) prop = dir.Crc; break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps)) +{ + *numProps = Z7_ARRAY_SIZE(kFolderProps); + return S_OK; +} + +IMP_IFolderFolder_GetProp( + CAgentFolder::GetFolderPropertyInfo, + kFolderProps) + +Z7_COM7F_IMF(CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */)) +{ + return E_FAIL; +} + + +Z7_COM7F_IMF(CAgentFolder::GetNumRawProps(UInt32 *numProps)) +{ + IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); + if (rawProps) + return rawProps->GetNumRawProps(numProps); + *numProps = 0; + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) +{ + IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); + if (rawProps) + return rawProps->GetRawPropInfo(index, name, propID); + return E_FAIL; +} + +Z7_COM7F_IMF(CAgentFolder::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps(); + if (rawProps) + { + unsigned arcIndex; + if (_proxy2) + { + SET_realIndex_AND_dir_2 + arcIndex = dir->Items[realIndex]; + } + else + { + SET_realIndex_AND_dir + if (realIndex < dir->SubDirs.Size()) + { + const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]]; + if (!item.IsLeaf()) + { + *data = NULL; + *dataSize = 0; + *propType = 0; + return S_OK; + } + arcIndex = (unsigned)item.ArcIndex; + } + else + arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; + } + return rawProps->GetRawProp(arcIndex, propID, data, dataSize, propType); + } + *data = NULL; + *dataSize = 0; + *propType = 0; + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::GetFolderArcProps(IFolderArcProps **object)) +{ + CMyComPtr temp = _agentSpec; + *object = temp.Detach(); + return S_OK; +} + + +Z7_COM7F_IMF(CAgentFolder::SetFlatMode(Int32 flatMode)) +{ + _flatMode = IntToBool(flatMode); + return S_OK; +} + + +int CAgentFolder::GetRealIndex(unsigned index) const +{ + if (!_flatMode) + { + if (_proxy2) + return (int)_proxy2->GetRealIndex(_proxyDirIndex, index); + else + return _proxy->GetRealIndex(_proxyDirIndex, index); + } + { + const CProxyItem &item = _items[index]; + if (_proxy2) + { + const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex]; + return (int)dir->Items[item.Index]; + } + else + { + const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; + const unsigned realIndex = item.Index; + if (realIndex < dir->SubDirs.Size()) + { + const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]]; + if (!f.IsLeaf()) + return -1; + return f.ArcIndex; + } + return (int)dir->SubFiles[realIndex - dir->SubDirs.Size()]; + } + } +} + +void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const +{ + if (!_flatMode) + { + if (_proxy2) + _proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices); + else + _proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices); + return; + } + + realIndices.Clear(); + + for (UInt32 i = 0; i < numItems; i++) + { + const CProxyItem &item = _items[indices[i]]; + if (_proxy2) + { + const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex]; + _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices); + continue; + } + UInt32 arcIndex; + { + const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; + unsigned realIndex = item.Index; + if (realIndex < dir->SubDirs.Size()) + { + if (includeFolderSubItemsInFlatMode) + { + _proxy->AddRealIndices(dir->SubDirs[realIndex], realIndices); + continue; + } + const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]]; + if (!f.IsLeaf()) + continue; + arcIndex = (unsigned)f.ArcIndex; + } + else + arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()]; + } + realIndices.Add(arcIndex); + } + + HeapSort(realIndices.NonConstData(), realIndices.Size()); +} + +Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices, + UInt32 numItems, + Int32 includeAltStreams, + Int32 replaceAltStreamColon, + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode, + const wchar_t *path, + Int32 testMode, + IFolderArchiveExtractCallback *extractCallback2)) +{ + COM_TRY_BEGIN + + if (!testMode && _agentSpec->_isHashHandler) + return E_NOTIMPL; + + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; + CMyComPtr extractCallback = extractCallbackSpec; + UStringVector pathParts; + bool isAltStreamFolder = false; + if (_proxy2) + _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); + else + _proxy->GetDirPathParts(_proxyDirIndex, pathParts); + + /* + if (_flatMode) + pathMode = NExtract::NPathMode::kNoPathnames; + */ + + extractCallbackSpec->InitForMulti( + false, // multiArchives + pathMode, + overwriteMode, + _zoneMode, + k_keepEmptyDirPrefixes); + + if (extractCallback2) + extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); + + FString pathU; + if (path) + { + pathU = us2fs(path); + if (!pathU.IsEmpty() + && !NFile::NName::IsAltStreamPrefixWithColon(path)) + { + NFile::NName::NormalizeDirPathPrefix(pathU); + NFile::NDir::CreateComplexDir(pathU); + } + } + + CExtractNtOptions extractNtOptions; + extractNtOptions.AltStreams.Val = IntToBool(includeAltStreams); // change it!!! + extractNtOptions.AltStreams.Def = true; + + extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon); + + extractCallbackSpec->InitBeforeNewArchive(); + + #if defined(_WIN32) && !defined(UNDER_CE) + if (_zoneMode != NExtract::NZoneIdMode::kNone) + { + ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf); + if (_zoneBuf.Size() != 0) + extractCallbackSpec->ZoneBuf = _zoneBuf; + } + #endif + + extractCallbackSpec->Init( + extractNtOptions, + NULL, &_agentSpec->GetArc(), + extractCallback2, + false, // stdOutMode + IntToBool(testMode), + pathU, + pathParts, isAltStreamFolder, + (UInt64)(Int64)-1); + + if (_proxy2) + extractCallbackSpec->SetBaseParentFolderIndex((unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex); + + // do we need another base folder for subfolders ? + extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix; + + CUIntVector realIndices; + GetRealIndices(indices, numItems, IntToBool(includeAltStreams), + false, // includeFolderSubItemsInFlatMode + realIndices); // + + #ifdef SUPPORT_LINKS + + if (!testMode) + { + RINOK(extractCallbackSpec->PrepareHardLinks(&realIndices)) + } + + #endif + + { + CArchiveExtractCallback_Closer ecsCloser(extractCallbackSpec); + + HRESULT res = _agentSpec->GetArchive()->Extract(realIndices.ConstData(), + realIndices.Size(), testMode, extractCallback); + + const HRESULT res2 = ecsCloser.Close(); + if (res == S_OK) + res = res2; + return res; + } + + COM_TRY_END +} + +///////////////////////////////////////// +// CAgent + +CAgent::CAgent(): + _proxy(NULL), + _proxy2(NULL), + _updatePathPrefix_is_AltFolder(false), + _isDeviceFile(false), + _isHashHandler(false) +{ +} + +CAgent::~CAgent() +{ + if (_proxy) + delete _proxy; + if (_proxy2) + delete _proxy2; +} + +bool CAgent::CanUpdate() const +{ + // FAR plugin uses empty agent to create new archive !!! + if (_archiveLink.Arcs.Size() == 0) + return true; + if (_isDeviceFile) + return false; + if (_archiveLink.Arcs.Size() != 1) + return false; + if (_archiveLink.Arcs[0].ErrorInfo.ThereIsTail) + return false; + return true; +} + +Z7_COM7F_IMF(CAgent::Open( + IInStream *inStream, + const wchar_t *filePath, + const wchar_t *arcFormat, + BSTR *archiveType, + IArchiveOpenCallback *openArchiveCallback)) +{ + COM_TRY_BEGIN + _archiveFilePath = filePath; + _hashBaseFolderPrefix.Empty(); + _attrib = 0; + _isDeviceFile = false; + _isHashHandler = false; + NFile::NFind::CFileInfo fi; + if (!inStream) + { + if (!fi.Find(us2fs(_archiveFilePath))) + return GetLastError_noZero_HRESULT(); + if (fi.IsDir()) + return E_FAIL; + _attrib = fi.Attrib; + _isDeviceFile = fi.IsDevice; + FString dirPrefix, fileName; + if (NFile::NDir::GetFullPathAndSplit(us2fs(_archiveFilePath), dirPrefix, fileName)) + { + NFile::NName::NormalizeDirPathPrefix(dirPrefix); + _hashBaseFolderPrefix = dirPrefix; + } + } + CArcInfoEx archiverInfo0, archiverInfo1; + + RINOK(LoadGlobalCodecs()) + + CObjectVector types; + if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types)) + return S_FALSE; + + /* + CObjectVector optProps; + if (Read_ShowDeleted()) + { + COptionalOpenProperties &optPair = optProps.AddNew(); + optPair.FormatName = "ntfs"; + // optPair.Props.AddNew().Name = "LS"; + optPair.Props.AddNew().Name = "LD"; + } + */ + + COpenOptions options; + options.props = NULL; + options.codecs = g_CodecsObj; + options.types = &types; + CIntVector exl; + options.excludedFormats = &exl; + options.stdInMode = false; + options.stream = inStream; + options.filePath = _archiveFilePath; + options.callback = openArchiveCallback; + + HRESULT res = _archiveLink.Open(options); + + if (!_archiveLink.Arcs.IsEmpty()) + { + CArc &arc = _archiveLink.Arcs.Back(); + if (!inStream) + { + arc.MTime.Set_From_FiTime(fi.MTime); + arc.MTime.Def = !fi.IsDevice; + } + + ArchiveType = GetTypeOfArc(arc); + if (archiveType) + { + RINOK(StringToBstr(ArchiveType, archiveType)) + } + + if (arc.IsHashHandler(options)) + _isHashHandler = true; + } + + return res; + + COM_TRY_END +} + + +Z7_COM7F_IMF(CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback)) +{ + COM_TRY_BEGIN + if (_proxy2) + { + delete _proxy2; + _proxy2 = NULL; + } + if (_proxy) + { + delete _proxy; + _proxy = NULL; + } + + CObjectVector incl; + CIntVector exl; + + COpenOptions options; + options.props = NULL; + options.codecs = g_CodecsObj; + options.types = &incl; + options.excludedFormats = &exl; + options.stdInMode = false; + options.filePath = _archiveFilePath; + options.callback = openArchiveCallback; + + RINOK(_archiveLink.ReOpen(options)) + return ReadItems(); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgent::Close()) +{ + COM_TRY_BEGIN + return _archiveLink.Close(); + COM_TRY_END +} + +/* +Z7_COM7F_IMF(CAgent::EnumProperties(IEnumSTATPROPSTG **EnumProperties) +{ + return _archive->EnumProperties(EnumProperties); +} +*/ + +HRESULT CAgent::ReadItems() +{ + if (_proxy || _proxy2) + return S_OK; + + const CArc &arc = GetArc(); + bool useProxy2 = (arc.GetRawProps && arc.IsTree); + + // useProxy2 = false; + + if (useProxy2) + _proxy2 = new CProxyArc2(); + else + _proxy = new CProxyArc(); + + { + ThereIsPathProp = false; + // ThereIsAltStreamProp = false; + UInt32 numProps; + arc.Archive->GetNumberOfProperties(&numProps); + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE varType; + RINOK(arc.Archive->GetPropertyInfo(i, &name, &propID, &varType)) + if (propID == kpidPath) + ThereIsPathProp = true; + /* + if (propID == kpidIsAltStream) + ThereIsAltStreamProp = true; + */ + } + } + + if (_proxy2) + return _proxy2->Load(GetArc(), NULL); + return _proxy->Load(GetArc(), NULL); +} + +Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder)) +{ + COM_TRY_BEGIN + if (!_archiveLink.Arcs.IsEmpty()) + { + RINOK(ReadItems()) + } + CAgentFolder *folderSpec = new CAgentFolder; + CMyComPtr rootFolder = folderSpec; + folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this); + *resultFolder = rootFolder.Detach(); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAgent::Extract( + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode, + const wchar_t *path, + Int32 testMode, + IFolderArchiveExtractCallback *extractCallback2)) +{ + COM_TRY_BEGIN + + if (!testMode && _isHashHandler) + return E_NOTIMPL; + + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; + CMyComPtr extractCallback = extractCallbackSpec; + extractCallbackSpec->InitForMulti( + false, // multiArchives + pathMode, + overwriteMode, + NExtract::NZoneIdMode::kNone, + k_keepEmptyDirPrefixes); + + CExtractNtOptions extractNtOptions; + extractNtOptions.AltStreams.Val = true; // change it!!! + extractNtOptions.AltStreams.Def = true; // change it!!! + extractNtOptions.ReplaceColonForAltStream = false; // change it!!! + + extractCallbackSpec->Init( + extractNtOptions, + NULL, &GetArc(), + extractCallback2, + false, // stdOutMode + IntToBool(testMode), + us2fs(path), + UStringVector(), false, + (UInt64)(Int64)-1); + + extractCallbackSpec->DirPathPrefix_for_HashFiles = _hashBaseFolderPrefix; + + #ifdef SUPPORT_LINKS + + if (!testMode) + { + RINOK(extractCallbackSpec->PrepareHardLinks(NULL)) // NULL means all items + } + + #endif + + return GetArchive()->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallback); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgent::GetNumberOfProperties(UInt32 *numProps)) +{ + COM_TRY_BEGIN + return GetArchive()->GetNumberOfProperties(numProps); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgent::GetPropertyInfo(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType)) +{ + COM_TRY_BEGIN + RINOK(GetArchive()->GetPropertyInfo(index, name, propID, varType)) + if (*propID == kpidPath) + *propID = kpidName; + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAgent::GetArcNumLevels(UInt32 *numLevels)) +{ + *numLevels = _archiveLink.Arcs.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + if (level > (UInt32)_archiveLink.Arcs.Size()) + return E_INVALIDARG; + if (level == (UInt32)_archiveLink.Arcs.Size()) + { + switch (propID) + { + case kpidPath: + if (!_archiveLink.NonOpen_ArcPath.IsEmpty()) + prop = _archiveLink.NonOpen_ArcPath; + break; + case kpidErrorType: + if (_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + prop = g_CodecsObj->Formats[_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name; + break; + case kpidErrorFlags: + { + UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetErrorFlags(); + if (flags != 0) + prop = flags; + break; + } + case kpidWarningFlags: + { + UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetWarningFlags(); + if (flags != 0) + prop = flags; + break; + } + } + } + else + { + const CArc &arc = _archiveLink.Arcs[level]; + switch (propID) + { + case kpidType: prop = GetTypeOfArc(arc); break; + case kpidPath: prop = arc.Path; break; + case kpidErrorType: + if (arc.ErrorInfo.ErrorFormatIndex >= 0) + prop = g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name; + break; + case kpidErrorFlags: + { + const UInt32 flags = arc.ErrorInfo.GetErrorFlags(); + if (flags != 0) + prop = flags; + break; + } + case kpidWarningFlags: + { + const UInt32 flags = arc.ErrorInfo.GetWarningFlags(); + if (flags != 0) + prop = flags; + break; + } + case kpidOffset: + { + const Int64 v = arc.GetGlobalOffset(); + if (v != 0) + prop.Set_Int64(v); + break; + } + case kpidTailSize: + { + if (arc.ErrorInfo.TailSize != 0) + prop = arc.ErrorInfo.TailSize; + break; + } + default: return arc.Archive->GetArchiveProperty(propID, value); + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps)) +{ + return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps); +} + +Z7_COM7F_IMF(CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) +{ + return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType); +} + +// MainItemProperty +Z7_COM7F_IMF(CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value)) +{ + return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value); +} + +Z7_COM7F_IMF(CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps)) +{ + return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps); +} + +Z7_COM7F_IMF(CAgent::GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) +{ + return _archiveLink.Arcs[level - 1].Archive->GetPropertyInfo(index, name, propID, varType); +} diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h index 04cbdb3ce..a63e4598f 100644 --- a/CPP/7zip/UI/Agent/Agent.h +++ b/CPP/7zip/UI/Agent/Agent.h @@ -1,353 +1,358 @@ -// Agent/Agent.h - -#ifndef ZIP7_INC_AGENT_AGENT_H -#define ZIP7_INC_AGENT_AGENT_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/PropVariant.h" - -#include "../Common/LoadCodecs.h" -#include "../Common/OpenArchive.h" -#include "../Common/UpdateAction.h" - -#include "../FileManager/IFolder.h" - -#include "AgentProxy.h" -#include "IFolderArchive.h" - -extern CCodecs *g_CodecsObj; -HRESULT LoadGlobalCodecs(); -void FreeGlobalCodecs(); - -class CAgentFolder; - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACEM_IArchiveFolderInternal(x) \ - x(GetAgentFolder(CAgentFolder **agentFolder)) -Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolderInternal, 0xC) - -Z7_PURE_INTERFACES_END - -struct CProxyItem -{ - unsigned DirIndex; - unsigned Index; -}; - -class CAgent; - -enum AGENT_OP -{ - AGENT_OP_Uni, - AGENT_OP_Delete, - AGENT_OP_CreateFolder, - AGENT_OP_Rename, - AGENT_OP_CopyFromFile, - AGENT_OP_Comment -}; - -class CAgentFolder Z7_final: - public IFolderFolder, - public IFolderAltStreams, - public IFolderProperties, - public IArchiveGetRawProps, - public IGetFolderArcProps, - public IFolderCompare, - public IFolderGetItemName, - public IArchiveFolder, - public IArchiveFolderInternal, - public IInArchiveGetStream, - public IFolderSetZoneIdMode, - public IFolderOperations, - public IFolderSetFlatMode, - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IFolderFolder) - Z7_COM_QI_ENTRY(IFolderAltStreams) - Z7_COM_QI_ENTRY(IFolderProperties) - Z7_COM_QI_ENTRY(IArchiveGetRawProps) - Z7_COM_QI_ENTRY(IGetFolderArcProps) - Z7_COM_QI_ENTRY(IFolderCompare) - Z7_COM_QI_ENTRY(IFolderGetItemName) - Z7_COM_QI_ENTRY(IArchiveFolder) - Z7_COM_QI_ENTRY(IArchiveFolderInternal) - Z7_COM_QI_ENTRY(IInArchiveGetStream) - Z7_COM_QI_ENTRY(IFolderSetZoneIdMode) - Z7_COM_QI_ENTRY(IFolderOperations) - Z7_COM_QI_ENTRY(IFolderSetFlatMode) - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IFolderFolder) - Z7_IFACE_COM7_IMP(IFolderAltStreams) - Z7_IFACE_COM7_IMP(IFolderProperties) - Z7_IFACE_COM7_IMP(IArchiveGetRawProps) - Z7_IFACE_COM7_IMP(IGetFolderArcProps) - Z7_IFACE_COM7_IMP(IFolderCompare) - Z7_IFACE_COM7_IMP(IFolderGetItemName) - Z7_IFACE_COM7_IMP(IArchiveFolder) - Z7_IFACE_COM7_IMP(IArchiveFolderInternal) - Z7_IFACE_COM7_IMP(IInArchiveGetStream) - Z7_IFACE_COM7_IMP(IFolderSetZoneIdMode) - Z7_IFACE_COM7_IMP(IFolderOperations) - Z7_IFACE_COM7_IMP(IFolderSetFlatMode) - - void LoadFolder(unsigned proxyDirIndex); -public: - HRESULT BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder); - HRESULT BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder); - int GetRealIndex(unsigned index) const; - void GetRealIndices(const UInt32 *indices, UInt32 numItems, - bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const; - - int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID); - int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); - - CAgentFolder(): - _proxyDirIndex(0), - _isAltStreamFolder(false), - _flatMode(false), - _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now - , _zoneMode(NExtract::NZoneIdMode::kNone) - /* , _replaceAltStreamCharsMode(0) */ - {} - - void Init(const CProxyArc *proxy, const CProxyArc2 *proxy2, - unsigned proxyDirIndex, - /* IFolderFolder *parentFolder, */ - CAgent *agent) - { - _proxy = proxy; - _proxy2 = proxy2; - _proxyDirIndex = proxyDirIndex; - _isAltStreamFolder = false; - if (_proxy2) - _isAltStreamFolder = _proxy2->IsAltDir(proxyDirIndex); - // _parentFolder = parentFolder; - _agent = (IInFolderArchive *)agent; - _agentSpec = agent; - } - - void GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder); - HRESULT CommonUpdateOperation( - AGENT_OP operation, - bool moveMode, - const wchar_t *newItemName, - const NUpdateArchive::CActionSet *actionSet, - const UInt32 *indices, UInt32 numItems, - IProgress *progress); - - - void GetPrefix(UInt32 index, UString &prefix) const; - UString GetName(UInt32 index) const; - UString GetFullPrefix(UInt32 index) const; // relative too root folder of archive - -public: - const CProxyArc *_proxy; - const CProxyArc2 *_proxy2; - unsigned _proxyDirIndex; - bool _isAltStreamFolder; - // CMyComPtr _parentFolder; - CMyComPtr _agent; - CAgent *_agentSpec; - - CRecordVector _items; - bool _flatMode; - bool _loadAltStreams; // in Flat mode - // Int32 _replaceAltStreamCharsMode; - NExtract::NZoneIdMode::EEnum _zoneMode; -}; - -class CAgent Z7_final: - public IInFolderArchive, - public IFolderArcProps, - #ifndef Z7_EXTRACT_ONLY - public IOutFolderArchive, - public ISetProperties, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IInFolderArchive) - Z7_COM_QI_ENTRY(IFolderArcProps) - #ifndef Z7_EXTRACT_ONLY - Z7_COM_QI_ENTRY(IOutFolderArchive) - Z7_COM_QI_ENTRY(ISetProperties) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IInFolderArchive) - Z7_IFACE_COM7_IMP(IFolderArcProps) - - #ifndef Z7_EXTRACT_ONLY - Z7_IFACE_COM7_IMP(ISetProperties) - -public: - Z7_IFACE_COM7_IMP(IOutFolderArchive) - HRESULT CommonUpdate(ISequentialOutStream *outArchiveStream, - unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback); - - HRESULT CreateFolder(ISequentialOutStream *outArchiveStream, - const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100); - - HRESULT RenameItem(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, - IFolderArchiveUpdateCallback *updateCallback100); - - HRESULT CommentItem(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, - IFolderArchiveUpdateCallback *updateCallback100); - - HRESULT UpdateOneFile(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath, - IFolderArchiveUpdateCallback *updateCallback100); - #endif - -private: - HRESULT ReadItems(); - -public: - CProxyArc *_proxy; - CProxyArc2 *_proxy2; - CArchiveLink _archiveLink; - - bool ThereIsPathProp; - // bool ThereIsAltStreamProp; - - UString ArchiveType; - - FStringVector _names; - FString _folderPrefix; // for new files from disk - - bool _updatePathPrefix_is_AltFolder; - UString _updatePathPrefix; - CAgentFolder *_agentFolder; - - UString _archiveFilePath; - DWORD _attrib; - bool _isDeviceFile; - bool _isHashHandler; - FString _hashBaseFolderPrefix; - - #ifndef Z7_EXTRACT_ONLY - CObjectVector m_PropNames; - CObjectVector m_PropValues; - #endif - - CAgent(); - ~CAgent(); - - const CArc &GetArc() const { return _archiveLink.Arcs.Back(); } - IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return NULL; return GetArc().Archive; } - bool CanUpdate() const; - - bool Is_Attrib_ReadOnly() const - { - return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY); - } - - bool IsThere_ReadOnlyArc() const - { - FOR_VECTOR (i, _archiveLink.Arcs) - { - const CArc &arc = _archiveLink.Arcs[i]; - if (arc.FormatIndex < 0 - || arc.IsReadOnly - || !g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled) - return true; - } - return false; - } - - UString GetTypeOfArc(const CArc &arc) const - { - if (arc.FormatIndex < 0) - return UString("Parser"); - return g_CodecsObj->GetFormatNamePtr(arc.FormatIndex); - } - - UString GetErrorMessage() const - { - UString s; - for (int i = (int)_archiveLink.Arcs.Size() - 1; i >= 0; i--) - { - const CArc &arc = _archiveLink.Arcs[i]; - - UString s2; - if (arc.ErrorInfo.ErrorFormatIndex >= 0) - { - if (arc.ErrorInfo.ErrorFormatIndex == arc.FormatIndex) - s2 += "Warning: The archive is open with offset"; - else - { - s2 += "Cannot open the file as ["; - s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex); - s2 += "] archive"; - } - } - - if (!arc.ErrorInfo.ErrorMessage.IsEmpty()) - { - if (!s2.IsEmpty()) - s2.Add_LF(); - s2 += "\n["; - s2 += GetTypeOfArc(arc); - s2 += "]: "; - s2 += arc.ErrorInfo.ErrorMessage; - } - - if (!s2.IsEmpty()) - { - if (!s.IsEmpty()) - s += "--------------------\n"; - s += arc.Path; - s.Add_LF(); - s += s2; - s.Add_LF(); - } - } - return s; - } - - void KeepModeForNextOpen() { _archiveLink.KeepModeForNextOpen(); } -}; - - -// #ifdef NEW_FOLDER_INTERFACE - -struct CCodecIcons -{ - struct CIconPair - { - UString Ext; - int IconIndex; - }; - CObjectVector IconPairs; - - // void Clear() { IconPairs.Clear(); } - void LoadIcons(HMODULE m); - bool FindIconIndex(const UString &ext, int &iconIndex) const; -}; - - -Z7_CLASS_IMP_COM_1( - CArchiveFolderManager - , IFolderManager -) - CObjectVector CodecIconsVector; - CCodecIcons InternalIcons; - bool WasLoaded; - - void LoadFormats(); - // int FindFormat(const UString &type); -public: - CArchiveFolderManager(): - WasLoaded(false) - {} -}; - -// #endif - -#endif +// Agent/Agent.h + +#ifndef ZIP7_INC_AGENT_AGENT_H +#define ZIP7_INC_AGENT_AGENT_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/PropVariant.h" + +#include "../Common/LoadCodecs.h" +#include "../Common/OpenArchive.h" +#include "../Common/UpdateAction.h" + +#include "../FileManager/IFolder.h" + +#include "AgentProxy.h" +#include "IFolderArchive.h" + +extern CCodecs *g_CodecsObj; +HRESULT LoadGlobalCodecs(); +void FreeGlobalCodecs(); + +class CAgentFolder; + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACEM_IArchiveFolderInternal(x) \ + x(GetAgentFolder(CAgentFolder **agentFolder)) +Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolderInternal, 0xC) + +Z7_PURE_INTERFACES_END + +struct CProxyItem +{ + unsigned DirIndex; + unsigned Index; +}; + +class CAgent; + +enum AGENT_OP +{ + AGENT_OP_Uni, + AGENT_OP_Delete, + AGENT_OP_CreateFolder, + AGENT_OP_Rename, + AGENT_OP_CopyFromFile, + AGENT_OP_Comment +}; + +class CAgentFolder Z7_final: + public IFolderFolder, + public IFolderAltStreams, + public IFolderProperties, + public IArchiveGetRawProps, + public IGetFolderArcProps, + public IFolderCompare, + public IFolderGetItemName, + public IArchiveFolder, + public IArchiveFolderInternal, + public IInArchiveGetStream, + public IFolderSetZoneIdMode, + public IFolderSetZoneIdFile, + public IFolderOperations, + public IFolderSetFlatMode, + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IFolderFolder) + Z7_COM_QI_ENTRY(IFolderAltStreams) + Z7_COM_QI_ENTRY(IFolderProperties) + Z7_COM_QI_ENTRY(IArchiveGetRawProps) + Z7_COM_QI_ENTRY(IGetFolderArcProps) + Z7_COM_QI_ENTRY(IFolderCompare) + Z7_COM_QI_ENTRY(IFolderGetItemName) + Z7_COM_QI_ENTRY(IArchiveFolder) + Z7_COM_QI_ENTRY(IArchiveFolderInternal) + Z7_COM_QI_ENTRY(IInArchiveGetStream) + Z7_COM_QI_ENTRY(IFolderSetZoneIdMode) + Z7_COM_QI_ENTRY(IFolderSetZoneIdFile) + Z7_COM_QI_ENTRY(IFolderOperations) + Z7_COM_QI_ENTRY(IFolderSetFlatMode) + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IFolderFolder) + Z7_IFACE_COM7_IMP(IFolderAltStreams) + Z7_IFACE_COM7_IMP(IFolderProperties) + Z7_IFACE_COM7_IMP(IArchiveGetRawProps) + Z7_IFACE_COM7_IMP(IGetFolderArcProps) + Z7_IFACE_COM7_IMP(IFolderCompare) + Z7_IFACE_COM7_IMP(IFolderGetItemName) + Z7_IFACE_COM7_IMP(IArchiveFolder) + Z7_IFACE_COM7_IMP(IArchiveFolderInternal) + Z7_IFACE_COM7_IMP(IInArchiveGetStream) + Z7_IFACE_COM7_IMP(IFolderSetZoneIdMode) + Z7_IFACE_COM7_IMP(IFolderSetZoneIdFile) + Z7_IFACE_COM7_IMP(IFolderOperations) + Z7_IFACE_COM7_IMP(IFolderSetFlatMode) + + void LoadFolder(unsigned proxyDirIndex); +public: + HRESULT BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder); + HRESULT BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder); + int GetRealIndex(unsigned index) const; + void GetRealIndices(const UInt32 *indices, UInt32 numItems, + bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const; + + int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID); + int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); + + CAgentFolder(): + _isAltStreamFolder(false), + _flatMode(false), + _loadAltStreams(false), // _loadAltStreams alt streams works in flat mode, but we don't use it now + _proxyDirIndex(0), + _zoneMode(NExtract::NZoneIdMode::kNone) + /* , _replaceAltStreamCharsMode(0) */ + {} + + void Init(const CProxyArc *proxy, const CProxyArc2 *proxy2, + unsigned proxyDirIndex, + /* IFolderFolder *parentFolder, */ + CAgent *agent) + { + _proxy = proxy; + _proxy2 = proxy2; + _proxyDirIndex = proxyDirIndex; + _isAltStreamFolder = false; + if (_proxy2) + _isAltStreamFolder = _proxy2->IsAltDir(proxyDirIndex); + // _parentFolder = parentFolder; + _agent = (IInFolderArchive *)agent; + _agentSpec = agent; + } + + void GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder); + HRESULT CommonUpdateOperation( + AGENT_OP operation, + bool moveMode, + const wchar_t *newItemName, + const NUpdateArchive::CActionSet *actionSet, + const UInt32 *indices, UInt32 numItems, + IProgress *progress); + + + void GetPrefix(UInt32 index, UString &prefix) const; + UString GetName(UInt32 index) const; + UString GetFullPrefix(UInt32 index) const; // relative too root folder of archive + +public: + bool _isAltStreamFolder; + bool _flatMode; + bool _loadAltStreams; // in Flat mode + const CProxyArc *_proxy; + const CProxyArc2 *_proxy2; + unsigned _proxyDirIndex; + NExtract::NZoneIdMode::EEnum _zoneMode; + CByteBuffer _zoneBuf; + // Int32 _replaceAltStreamCharsMode; + // CMyComPtr _parentFolder; + CMyComPtr _agent; + CAgent *_agentSpec; + CRecordVector _items; +}; + + + +class CAgent Z7_final: + public IInFolderArchive, + public IFolderArcProps, + #ifndef Z7_EXTRACT_ONLY + public IOutFolderArchive, + public ISetProperties, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IInFolderArchive) + Z7_COM_QI_ENTRY(IFolderArcProps) + #ifndef Z7_EXTRACT_ONLY + Z7_COM_QI_ENTRY(IOutFolderArchive) + Z7_COM_QI_ENTRY(ISetProperties) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IInFolderArchive) + Z7_IFACE_COM7_IMP(IFolderArcProps) + + #ifndef Z7_EXTRACT_ONLY + Z7_IFACE_COM7_IMP(ISetProperties) + +public: + Z7_IFACE_COM7_IMP(IOutFolderArchive) + HRESULT CommonUpdate(ISequentialOutStream *outArchiveStream, + unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback); + + HRESULT CreateFolder(ISequentialOutStream *outArchiveStream, + const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100); + + HRESULT RenameItem(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, + IFolderArchiveUpdateCallback *updateCallback100); + + HRESULT CommentItem(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, + IFolderArchiveUpdateCallback *updateCallback100); + + HRESULT UpdateOneFile(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath, + IFolderArchiveUpdateCallback *updateCallback100); + #endif + +private: + HRESULT ReadItems(); + +public: + CProxyArc *_proxy; + CProxyArc2 *_proxy2; + CArchiveLink _archiveLink; + + UString ArchiveType; + + FStringVector _names; + FString _folderPrefix; // for new files from disk + + UString _updatePathPrefix; + CAgentFolder *_agentFolder; + + UString _archiveFilePath; // it can be path of non-existing file if file is virtual + + DWORD _attrib; + bool _updatePathPrefix_is_AltFolder; + bool ThereIsPathProp; + bool _isDeviceFile; + bool _isHashHandler; + + FString _hashBaseFolderPrefix; + + #ifndef Z7_EXTRACT_ONLY + CObjectVector m_PropNames; + CObjectVector m_PropValues; + #endif + + CAgent(); + ~CAgent(); + + const CArc &GetArc() const { return _archiveLink.Arcs.Back(); } + IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return NULL; return GetArc().Archive; } + bool CanUpdate() const; + + bool Is_Attrib_ReadOnly() const + { + return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY); + } + + bool IsThere_ReadOnlyArc() const + { + FOR_VECTOR (i, _archiveLink.Arcs) + { + const CArc &arc = _archiveLink.Arcs[i]; + if (arc.FormatIndex < 0 + || arc.IsReadOnly + || !g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled) + return true; + } + return false; + } + + UString GetTypeOfArc(const CArc &arc) const + { + if (arc.FormatIndex < 0) + return UString("Parser"); + return g_CodecsObj->GetFormatNamePtr(arc.FormatIndex); + } + + UString GetErrorMessage() const + { + UString s; + for (int i = (int)_archiveLink.Arcs.Size() - 1; i >= 0; i--) + { + const CArc &arc = _archiveLink.Arcs[i]; + + UString s2; + if (arc.ErrorInfo.ErrorFormatIndex >= 0) + { + if (arc.ErrorInfo.ErrorFormatIndex == arc.FormatIndex) + s2 += "Warning: The archive is open with offset"; + else + { + s2 += "Cannot open the file as ["; + s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex); + s2 += "] archive"; + } + } + + if (!arc.ErrorInfo.ErrorMessage.IsEmpty()) + { + if (!s2.IsEmpty()) + s2.Add_LF(); + s2 += "\n["; + s2 += GetTypeOfArc(arc); + s2 += "]: "; + s2 += arc.ErrorInfo.ErrorMessage; + } + + if (!s2.IsEmpty()) + { + if (!s.IsEmpty()) + s += "--------------------\n"; + s += arc.Path; + s.Add_LF(); + s += s2; + s.Add_LF(); + } + } + return s; + } + + void KeepModeForNextOpen() { _archiveLink.KeepModeForNextOpen(); } +}; + + +// #ifdef NEW_FOLDER_INTERFACE + +struct CCodecIcons +{ + struct CIconPair + { + UString Ext; + int IconIndex; + }; + CObjectVector IconPairs; + + // void Clear() { IconPairs.Clear(); } + void LoadIcons(HMODULE m); + bool FindIconIndex(const UString &ext, int &iconIndex) const; +}; + + +Z7_CLASS_IMP_COM_1( + CArchiveFolderManager + , IFolderManager +) + CObjectVector CodecIconsVector; + CCodecIcons InternalIcons; + bool WasLoaded; + + void LoadFormats(); + // int FindFormat(const UString &type); +public: + CArchiveFolderManager(): + WasLoaded(false) + {} +}; + +// #endif + +#endif diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp index b49a9f725..903cde225 100644 --- a/CPP/7zip/UI/Agent/AgentOut.cpp +++ b/CPP/7zip/UI/Agent/AgentOut.cpp @@ -1,718 +1,718 @@ -// AgentOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "../../Common/FileStreams.h" - -#include "../../Archive/Common/ItemNameUtils.h" - -#include "Agent.h" -#include "UpdateCallbackAgent.h" - -using namespace NWindows; -using namespace NCOM; - -Z7_COM7F_IMF(CAgent::SetFolder(IFolderFolder *folder)) -{ - _updatePathPrefix.Empty(); - _updatePathPrefix_is_AltFolder = false; - _agentFolder = NULL; - - if (!folder) - return S_OK; - - { - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveFolderInternal, - afi, folder) - if (afi) - { - RINOK(afi->GetAgentFolder(&_agentFolder)) - } - if (!_agentFolder) - return E_FAIL; - } - - if (_proxy2) - _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder); - else - _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); - return S_OK; -} - -Z7_COM7F_IMF(CAgent::SetFiles(const wchar_t *folderPrefix, - const wchar_t * const *names, UInt32 numNames)) -{ - _folderPrefix = us2fs(folderPrefix); - _names.ClearAndReserve(numNames); - for (UInt32 i = 0; i < numNames; i++) - _names.AddInReserved(us2fs(names[i])); - return S_OK; -} - -static HRESULT EnumerateArchiveItems(CAgent *agent, - const CProxyDir &item, - const UString &prefix, - CObjectVector &arcItems) -{ - unsigned i; - - for (i = 0; i < item.SubFiles.Size(); i++) - { - unsigned arcIndex = item.SubFiles[i]; - const CProxyFile &fileItem = agent->_proxy->Files[arcIndex]; - CArcItem ai; - RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) - RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) - ai.IsDir = false; - ai.Name = prefix + fileItem.Name; - ai.Censored = true; // test it - ai.IndexInServer = arcIndex; - arcItems.Add(ai); - } - - for (i = 0; i < item.SubDirs.Size(); i++) - { - const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]]; - UString fullName = prefix + dirItem.Name; - if (dirItem.IsLeaf()) - { - CArcItem ai; - RINOK(agent->GetArc().GetItem_MTime((unsigned)dirItem.ArcIndex, ai.MTime)) - ai.IsDir = true; - ai.Size_Defined = false; - ai.Name = fullName; - ai.Censored = true; // test it - ai.IndexInServer = (unsigned)dirItem.ArcIndex; - arcItems.Add(ai); - } - RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems)) - } - - return S_OK; -} - -static HRESULT EnumerateArchiveItems2(const CAgent *agent, - unsigned dirIndex, - const UString &prefix, - CObjectVector &arcItems) -{ - const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex]; - FOR_VECTOR (i, dir.Items) - { - unsigned arcIndex = dir.Items[i]; - const CProxyFile2 &file = agent->_proxy2->Files[arcIndex]; - CArcItem ai; - ai.IndexInServer = arcIndex; - ai.Name = prefix + file.Name; - ai.Censored = true; // test it - RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) - ai.IsDir = file.IsDir(); - ai.Size_Defined = false; - ai.IsAltStream = file.IsAltStream; - if (!ai.IsDir) - { - RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) - ai.IsDir = false; - } - arcItems.Add(ai); - - if (file.AltDirIndex != -1) - { - RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, ai.Name + L':', arcItems)) - } - - if (ai.IsDir) - { - RINOK(EnumerateArchiveItems2(agent, (unsigned)file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems)) - } - } - return S_OK; -} - -struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback -{ - const CObjectVector *_arcItems; - IFolderArchiveUpdateCallback *_callback; - - CAgUpCallbackImp(const CObjectVector *a, - IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {} - HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override; -}; - -HRESULT CAgUpCallbackImp::ShowDeleteFile(unsigned arcIndex) -{ - return _callback->DeleteOperation((*_arcItems)[arcIndex].Name); -} - - -static void SetInArchiveInterfaces(CAgent *agent, CArchiveUpdateCallback *upd) -{ - if (agent->_archiveLink.Arcs.IsEmpty()) - return; - const CArc &arc = agent->GetArc(); - upd->Arc = &arc; - upd->Archive = arc.Archive; - - upd->ArcFileName = ExtractFileNameFromPath(arc.Path); -} - -struct CDirItemsCallback_AgentOut Z7_final: public IDirItemsCallback -{ - CMyComPtr FolderScanProgress; - IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback; - HRESULT ErrorCode; - - CDirItemsCallback_AgentOut(): FolderArchiveUpdateCallback(NULL), ErrorCode(S_OK) {} - - HRESULT ScanError(const FString &name, DWORD systemError) Z7_override - { - const HRESULT hres = HRESULT_FROM_WIN32(systemError); - if (FolderArchiveUpdateCallback) - return FolderScanProgress->ScanError(fs2us(name), hres); - ErrorCode = hres; - return ErrorCode; - } - - HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) Z7_override - { - if (FolderScanProgress) - return FolderScanProgress->ScanProgress(st.NumDirs, st.NumFiles + st.NumAltStreams, - st.GetTotalBytes(), fs2us(path), BoolToInt(isDir)); - if (FolderArchiveUpdateCallback) - return FolderArchiveUpdateCallback->SetNumFiles(st.NumFiles); - return S_OK; - } -}; - - -Z7_COM7F_IMF(CAgent::DoOperation( - FStringVector *requestedPaths, - FStringVector *processedPaths, - CCodecs *codecs, - int formatIndex, - ISequentialOutStream *outArchiveStream, - const Byte *stateActions, - const wchar_t *sfxModule, - IFolderArchiveUpdateCallback *updateCallback100)) -{ - if (!CanUpdate()) - return E_NOTIMPL; - - NUpdateArchive::CActionSet actionSet; - { - for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) - actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i]; - } - - CDirItemsCallback_AgentOut enumCallback; - if (updateCallback100) - { - enumCallback.FolderArchiveUpdateCallback = updateCallback100; - updateCallback100->QueryInterface(IID_IFolderScanProgress, (void **)&enumCallback.FolderScanProgress); - } - - CDirItems dirItems; - dirItems.Callback = &enumCallback; - - { - FString folderPrefix = _folderPrefix; - if (!NFile::NName::IsAltStreamPrefixWithColon(fs2us(folderPrefix))) - NFile::NName::NormalizeDirPathPrefix(folderPrefix); - - RINOK(dirItems.EnumerateItems2(folderPrefix, _updatePathPrefix, _names, requestedPaths)) - - if (_updatePathPrefix_is_AltFolder) - { - FOR_VECTOR(i, dirItems.Items) - { - CDirItem &item = dirItems.Items[i]; - if (item.IsDir()) - return E_NOTIMPL; - item.IsAltStream = true; - } - } - } - - CMyComPtr outArchive; - - if (GetArchive()) - { - RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)) - } - else - { - if (formatIndex < 0) - return E_FAIL; - RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive)) - - #ifdef Z7_EXTERNAL_CODECS - { - CMyComPtr setCompressCodecsInfo; - outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)) - } - } - #endif - } - - NFileTimeType::EEnum fileTimeType = NFileTimeType::kNotDefined; - UInt32 value; - RINOK(outArchive->GetFileTimeType(&value)) - // we support any future fileType here. - // 22.00: - fileTimeType = (NFileTimeType::EEnum)value; - /* - switch (value) - { - case NFileTimeType::kWindows: - case NFileTimeType::kDOS: - case NFileTimeType::kUnix: - fileTimeType = NFileTimeType::EEnum(value); - break; - default: - { - return E_FAIL; - } - } - */ - - - CObjectVector arcItems; - if (GetArchive()) - { - RINOK(ReadItems()) - if (_proxy2) - { - RINOK(EnumerateArchiveItems2(this, k_Proxy2_RootDirIndex, L"", arcItems)) - RINOK(EnumerateArchiveItems2(this, k_Proxy2_AltRootDirIndex, L":", arcItems)) - } - else - { - RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems)) - } - } - - CRecordVector updatePairs2; - - { - CRecordVector updatePairs; - GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); - CAgUpCallbackImp upCallback(&arcItems, updateCallback100); - UpdateProduce(updatePairs, actionSet, updatePairs2, &upCallback); - } - - UInt32 numFiles = 0; - { - FOR_VECTOR (i, updatePairs2) - if (updatePairs2[i].NewData) - numFiles++; - } - - if (updateCallback100) - { - RINOK(updateCallback100->SetNumFiles(numFiles)) - } - - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CMyComPtr2_Create updateCallback; - - updateCallback->DirItems = &dirItems; - updateCallback->ArcItems = &arcItems; - updateCallback->UpdatePairs = &updatePairs2; - - SetInArchiveInterfaces(this, updateCallback.ClsPtr()); - - updateCallback->Callback = &updateCallbackAgent; - - CByteBuffer processedItems; - if (processedPaths) - { - unsigned num = dirItems.Items.Size(); - processedItems.Alloc(num); - for (unsigned i = 0; i < num; i++) - processedItems[i] = 0; - updateCallback->ProcessedItemsStatuses = processedItems; - } - - Z7_DECL_CMyComPtr_QI_FROM( - ISetProperties, - setProperties, outArchive) - if (setProperties) - { - if (m_PropNames.Size() == 0) - { - RINOK(setProperties->SetProperties(NULL, NULL, 0)) - } - else - { - CRecordVector names; - FOR_VECTOR (i, m_PropNames) - names.Add((const wchar_t *)m_PropNames[i]); - - CPropVariant *propValues = new CPropVariant[m_PropValues.Size()]; - try - { - FOR_VECTOR (i, m_PropValues) - propValues[i] = m_PropValues[i]; - RINOK(setProperties->SetProperties(names.ConstData(), propValues, names.Size())) - } - catch(...) - { - delete []propValues; - return E_FAIL; - } - delete []propValues; - } - } - m_PropNames.Clear(); - m_PropValues.Clear(); - - if (sfxModule != NULL) - { - CMyComPtr2_Create sfxStream; - if (!sfxStream->Open(us2fs(sfxModule))) - return E_FAIL; - // throw "Can't open sfx module"; - RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL)) - } - - const HRESULT res = outArchive->UpdateItems(outArchiveStream, updatePairs2.Size(), updateCallback); - if (res == S_OK && processedPaths) - { - { - /* OutHandler for 7z archives doesn't report compression operation for empty files. - So we must include these files manually */ - FOR_VECTOR(i, updatePairs2) - { - const CUpdatePair2 &up = updatePairs2[i]; - if (up.DirIndex != -1 && up.NewData) - { - const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; - if (!di.IsDir() && di.Size == 0) - processedItems[(unsigned)up.DirIndex] = 1; - } - } - } - - FOR_VECTOR (i, dirItems.Items) - if (processedItems[i] != 0) - processedPaths->Add(dirItems.GetPhyPath(i)); - } - return res; -} - -Z7_COM7F_IMF(CAgent::DoOperation2( - FStringVector *requestedPaths, - FStringVector *processedPaths, - ISequentialOutStream *outArchiveStream, - const Byte *stateActions, const wchar_t *sfxModule, IFolderArchiveUpdateCallback *updateCallback100)) -{ - return DoOperation(requestedPaths, processedPaths, g_CodecsObj, -1, outArchiveStream, stateActions, sfxModule, updateCallback100); -} - -HRESULT CAgent::CommonUpdate(ISequentialOutStream *outArchiveStream, - unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback) -{ - if (!CanUpdate()) - return E_NOTIMPL; - CMyComPtr outArchive; - RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)) - return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback); -} - -Z7_COM7F_IMF(CAgent::DeleteItems(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, - IFolderArchiveUpdateCallback *updateCallback100)) -{ - if (!CanUpdate()) - return E_NOTIMPL; - CRecordVector updatePairs; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CMyComPtr2_Create updateCallback; - - CUIntVector realIndices; - _agentFolder->GetRealIndices(indices, numItems, - true, // includeAltStreams - false, // includeFolderSubItemsInFlatMode, we don't want to delete subItems in Flat Mode - realIndices); - unsigned curIndex = 0; - UInt32 numItemsInArchive; - RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) - - UString deletePath; - - for (UInt32 i = 0; i < numItemsInArchive; i++) - { - if (curIndex < realIndices.Size()) - if (realIndices[curIndex] == i) - { - RINOK(GetArc().GetItem_Path2(i, deletePath)) - RINOK(updateCallback100->DeleteOperation(deletePath)) - - curIndex++; - continue; - } - CUpdatePair2 up2; - up2.SetAs_NoChangeArcItem(i); - updatePairs.Add(up2); - } - updateCallback->UpdatePairs = &updatePairs; - - SetInArchiveInterfaces(this, updateCallback.ClsPtr()); - - updateCallback->Callback = &updateCallbackAgent; - return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); -} - -HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream, - const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100) -{ - if (!CanUpdate()) - return E_NOTIMPL; - CRecordVector updatePairs; - CDirItems dirItems; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CMyComPtr2_Create updateCallback; - - UInt32 numItemsInArchive; - RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) - for (UInt32 i = 0; i < numItemsInArchive; i++) - { - CUpdatePair2 up2; - up2.SetAs_NoChangeArcItem(i); - updatePairs.Add(up2); - } - CUpdatePair2 up2; - up2.NewData = up2.NewProps = true; - up2.UseArcProps = false; - up2.DirIndex = 0; - - updatePairs.Add(up2); - - updatePairs.ReserveDown(); - - CDirItem di; - - di.Attrib = FILE_ATTRIBUTE_DIRECTORY; - di.Size = 0; - bool isAltStreamFolder = false; - if (_proxy2) - di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder); - else - di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); - di.Name += folderName; - - FILETIME ft; - NTime::GetCurUtcFileTime(ft); - di.CTime = di.ATime = di.MTime = ft; - - dirItems.Items.Add(di); - - updateCallback->Callback = &updateCallbackAgent; - updateCallback->DirItems = &dirItems; - updateCallback->UpdatePairs = &updatePairs; - - SetInArchiveInterfaces(this, updateCallback.ClsPtr()); - - return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); -} - - -HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, - IFolderArchiveUpdateCallback *updateCallback100) -{ - if (!CanUpdate()) - return E_NOTIMPL; - if (numItems != 1) - return E_INVALIDARG; - if (!_archiveLink.IsOpen) - return E_FAIL; - CRecordVector updatePairs; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CMyComPtr2_Create updateCallback; - - CUIntVector realIndices; - _agentFolder->GetRealIndices(indices, numItems, - true, // includeAltStreams - true, // includeFolderSubItemsInFlatMode - realIndices); - - const UInt32 ind0 = indices[0]; - const int mainRealIndex = _agentFolder->GetRealIndex(ind0); - const UString fullPrefix = _agentFolder->GetFullPrefix(ind0); - UString name = _agentFolder->GetName(ind0); - // 22.00 : we normalize name - NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); - const UString oldItemPath = fullPrefix + name; - const UString newItemPath = fullPrefix + newItemName; - - UStringVector newNames; - - unsigned curIndex = 0; - UInt32 numItemsInArchive; - RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) - - for (UInt32 i = 0; i < numItemsInArchive; i++) - { - CUpdatePair2 up2; - up2.SetAs_NoChangeArcItem(i); - if (curIndex < realIndices.Size()) - if (realIndices[curIndex] == i) - { - up2.NewProps = true; - RINOK(GetArc().IsItem_Anti(i, up2.IsAnti)) // it must work without that line too. - - UString oldFullPath; - RINOK(GetArc().GetItem_Path2(i, oldFullPath)) - - if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath)) - return E_INVALIDARG; - - up2.NewNameIndex = (int)newNames.Add(newItemPath + oldFullPath.Ptr(oldItemPath.Len())); - up2.IsMainRenameItem = (mainRealIndex == (int)i); - curIndex++; - } - updatePairs.Add(up2); - } - - updateCallback->Callback = &updateCallbackAgent; - updateCallback->UpdatePairs = &updatePairs; - updateCallback->NewNames = &newNames; - - SetInArchiveInterfaces(this, updateCallback.ClsPtr()); - - return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); -} - - -HRESULT CAgent::CommentItem(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, - IFolderArchiveUpdateCallback *updateCallback100) -{ - if (!CanUpdate()) - return E_NOTIMPL; - if (numItems != 1) - return E_INVALIDARG; - if (!_archiveLink.IsOpen) - return E_FAIL; - - CRecordVector updatePairs; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CMyComPtr2_Create updateCallback; - - const int mainRealIndex = _agentFolder->GetRealIndex(indices[0]); - - if (mainRealIndex < 0) - return E_NOTIMPL; - - UInt32 numItemsInArchive; - RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) - - UString newName = newItemName; - - for (UInt32 i = 0; i < numItemsInArchive; i++) - { - CUpdatePair2 up2; - up2.SetAs_NoChangeArcItem(i); - if ((int)i == mainRealIndex) - up2.NewProps = true; - updatePairs.Add(up2); - } - - updateCallback->Callback = &updateCallbackAgent; - updateCallback->UpdatePairs = &updatePairs; - updateCallback->CommentIndex = mainRealIndex; - updateCallback->Comment = &newName; - - SetInArchiveInterfaces(this, updateCallback.ClsPtr()); - - return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); -} - - - -HRESULT CAgent::UpdateOneFile(ISequentialOutStream *outArchiveStream, - const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath, - IFolderArchiveUpdateCallback *updateCallback100) -{ - if (!CanUpdate()) - return E_NOTIMPL; - CRecordVector updatePairs; - CDirItems dirItems; - CUpdateCallbackAgent updateCallbackAgent; - updateCallbackAgent.SetCallback(updateCallback100); - CMyComPtr2_Create updateCallback; - - UInt32 realIndex; - { - CUIntVector realIndices; - _agentFolder->GetRealIndices(indices, numItems, - false, // includeAltStreams // we update only main stream of file - false, // includeFolderSubItemsInFlatMode - realIndices); - if (realIndices.Size() != 1) - return E_FAIL; - realIndex = realIndices[0]; - } - - { - FStringVector filePaths; - filePaths.Add(us2fs(diskFilePath)); - dirItems.EnumerateItems2(FString(), UString(), filePaths, NULL); - if (dirItems.Items.Size() != 1) - return E_FAIL; - } - - UInt32 numItemsInArchive; - RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) - for (UInt32 i = 0; i < numItemsInArchive; i++) - { - CUpdatePair2 up2; - up2.SetAs_NoChangeArcItem(i); - if (realIndex == i) - { - up2.DirIndex = 0; - up2.NewData = true; - up2.NewProps = true; - up2.UseArcProps = false; - } - updatePairs.Add(up2); - } - updateCallback->DirItems = &dirItems; - updateCallback->Callback = &updateCallbackAgent; - updateCallback->UpdatePairs = &updatePairs; - - SetInArchiveInterfaces(this, updateCallback.ClsPtr()); - - updateCallback->KeepOriginalItemNames = true; - return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); -} - -Z7_COM7F_IMF(CAgent::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - m_PropNames.Clear(); - m_PropValues.Clear(); - for (UInt32 i = 0; i < numProps; i++) - { - m_PropNames.Add(names[i]); - m_PropValues.Add(values[i]); - } - return S_OK; -} +// AgentOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../../Common/FileStreams.h" + +#include "../../Archive/Common/ItemNameUtils.h" + +#include "Agent.h" +#include "UpdateCallbackAgent.h" + +using namespace NWindows; +using namespace NCOM; + +Z7_COM7F_IMF(CAgent::SetFolder(IFolderFolder *folder)) +{ + _updatePathPrefix.Empty(); + _updatePathPrefix_is_AltFolder = false; + _agentFolder = NULL; + + if (!folder) + return S_OK; + + { + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveFolderInternal, + afi, folder) + if (afi) + { + RINOK(afi->GetAgentFolder(&_agentFolder)) + } + if (!_agentFolder) + return E_FAIL; + } + + if (_proxy2) + _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder); + else + _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); + return S_OK; +} + +Z7_COM7F_IMF(CAgent::SetFiles(const wchar_t *folderPrefix, + const wchar_t * const *names, UInt32 numNames)) +{ + _folderPrefix = us2fs(folderPrefix); + _names.ClearAndReserve(numNames); + for (UInt32 i = 0; i < numNames; i++) + _names.AddInReserved(us2fs(names[i])); + return S_OK; +} + +static HRESULT EnumerateArchiveItems(CAgent *agent, + const CProxyDir &item, + const UString &prefix, + CObjectVector &arcItems) +{ + unsigned i; + + for (i = 0; i < item.SubFiles.Size(); i++) + { + unsigned arcIndex = item.SubFiles[i]; + const CProxyFile &fileItem = agent->_proxy->Files[arcIndex]; + CArcItem ai; + RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) + RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) + ai.IsDir = false; + ai.Name = prefix + fileItem.Name; + ai.Censored = true; // test it + ai.IndexInServer = arcIndex; + arcItems.Add(ai); + } + + for (i = 0; i < item.SubDirs.Size(); i++) + { + const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]]; + UString fullName = prefix + dirItem.Name; + if (dirItem.IsLeaf()) + { + CArcItem ai; + RINOK(agent->GetArc().GetItem_MTime((unsigned)dirItem.ArcIndex, ai.MTime)) + ai.IsDir = true; + ai.Size_Defined = false; + ai.Name = fullName; + ai.Censored = true; // test it + ai.IndexInServer = (unsigned)dirItem.ArcIndex; + arcItems.Add(ai); + } + RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems)) + } + + return S_OK; +} + +static HRESULT EnumerateArchiveItems2(const CAgent *agent, + unsigned dirIndex, + const UString &prefix, + CObjectVector &arcItems) +{ + const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex]; + FOR_VECTOR (i, dir.Items) + { + unsigned arcIndex = dir.Items[i]; + const CProxyFile2 &file = agent->_proxy2->Files[arcIndex]; + CArcItem ai; + ai.IndexInServer = arcIndex; + ai.Name = prefix + file.Name; + ai.Censored = true; // test it + RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) + ai.IsDir = file.IsDir(); + ai.Size_Defined = false; + ai.IsAltStream = file.IsAltStream; + if (!ai.IsDir) + { + RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) + ai.IsDir = false; + } + arcItems.Add(ai); + + if (file.AltDirIndex != -1) + { + RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, ai.Name + L':', arcItems)) + } + + if (ai.IsDir) + { + RINOK(EnumerateArchiveItems2(agent, (unsigned)file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems)) + } + } + return S_OK; +} + +struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback +{ + const CObjectVector *_arcItems; + IFolderArchiveUpdateCallback *_callback; + + CAgUpCallbackImp(const CObjectVector *a, + IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {} + HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override; +}; + +HRESULT CAgUpCallbackImp::ShowDeleteFile(unsigned arcIndex) +{ + return _callback->DeleteOperation((*_arcItems)[arcIndex].Name); +} + + +static void SetInArchiveInterfaces(CAgent *agent, CArchiveUpdateCallback *upd) +{ + if (agent->_archiveLink.Arcs.IsEmpty()) + return; + const CArc &arc = agent->GetArc(); + upd->Arc = &arc; + upd->Archive = arc.Archive; + + upd->ArcFileName = ExtractFileNameFromPath(arc.Path); +} + +struct CDirItemsCallback_AgentOut Z7_final: public IDirItemsCallback +{ + CMyComPtr FolderScanProgress; + IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback; + HRESULT ErrorCode; + + CDirItemsCallback_AgentOut(): FolderArchiveUpdateCallback(NULL), ErrorCode(S_OK) {} + + HRESULT ScanError(const FString &name, DWORD systemError) Z7_override + { + const HRESULT hres = HRESULT_FROM_WIN32(systemError); + if (FolderArchiveUpdateCallback) + return FolderScanProgress->ScanError(fs2us(name), hres); + ErrorCode = hres; + return ErrorCode; + } + + HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) Z7_override + { + if (FolderScanProgress) + return FolderScanProgress->ScanProgress(st.NumDirs, st.NumFiles + st.NumAltStreams, + st.GetTotalBytes(), fs2us(path), BoolToInt(isDir)); + if (FolderArchiveUpdateCallback) + return FolderArchiveUpdateCallback->SetNumFiles(st.NumFiles); + return S_OK; + } +}; + + +Z7_COM7F_IMF(CAgent::DoOperation( + FStringVector *requestedPaths, + FStringVector *processedPaths, + CCodecs *codecs, + int formatIndex, + ISequentialOutStream *outArchiveStream, + const Byte *stateActions, + const wchar_t *sfxModule, + IFolderArchiveUpdateCallback *updateCallback100)) +{ + if (!CanUpdate()) + return E_NOTIMPL; + + NUpdateArchive::CActionSet actionSet; + { + for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) + actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i]; + } + + CDirItemsCallback_AgentOut enumCallback; + if (updateCallback100) + { + enumCallback.FolderArchiveUpdateCallback = updateCallback100; + updateCallback100->QueryInterface(IID_IFolderScanProgress, (void **)&enumCallback.FolderScanProgress); + } + + CDirItems dirItems; + dirItems.Callback = &enumCallback; + + { + FString folderPrefix = _folderPrefix; + if (!NFile::NName::IsAltStreamPrefixWithColon(fs2us(folderPrefix))) + NFile::NName::NormalizeDirPathPrefix(folderPrefix); + + RINOK(dirItems.EnumerateItems2(folderPrefix, _updatePathPrefix, _names, requestedPaths)) + + if (_updatePathPrefix_is_AltFolder) + { + FOR_VECTOR(i, dirItems.Items) + { + CDirItem &item = dirItems.Items[i]; + if (item.IsDir()) + return E_NOTIMPL; + item.IsAltStream = true; + } + } + } + + CMyComPtr outArchive; + + if (GetArchive()) + { + RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)) + } + else + { + if (formatIndex < 0) + return E_FAIL; + RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive)) + + #ifdef Z7_EXTERNAL_CODECS + { + CMyComPtr setCompressCodecsInfo; + outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)) + } + } + #endif + } + + NFileTimeType::EEnum fileTimeType = NFileTimeType::kNotDefined; + UInt32 value; + RINOK(outArchive->GetFileTimeType(&value)) + // we support any future fileType here. + // 22.00: + fileTimeType = (NFileTimeType::EEnum)value; + /* + switch (value) + { + case NFileTimeType::kWindows: + case NFileTimeType::kDOS: + case NFileTimeType::kUnix: + fileTimeType = NFileTimeType::EEnum(value); + break; + default: + { + return E_FAIL; + } + } + */ + + + CObjectVector arcItems; + if (GetArchive()) + { + RINOK(ReadItems()) + if (_proxy2) + { + RINOK(EnumerateArchiveItems2(this, k_Proxy2_RootDirIndex, L"", arcItems)) + RINOK(EnumerateArchiveItems2(this, k_Proxy2_AltRootDirIndex, L":", arcItems)) + } + else + { + RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems)) + } + } + + CRecordVector updatePairs2; + + { + CRecordVector updatePairs; + GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); + CAgUpCallbackImp upCallback(&arcItems, updateCallback100); + UpdateProduce(updatePairs, actionSet, updatePairs2, &upCallback); + } + + UInt32 numFiles = 0; + { + FOR_VECTOR (i, updatePairs2) + if (updatePairs2[i].NewData) + numFiles++; + } + + if (updateCallback100) + { + RINOK(updateCallback100->SetNumFiles(numFiles)) + } + + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CMyComPtr2_Create updateCallback; + + updateCallback->DirItems = &dirItems; + updateCallback->ArcItems = &arcItems; + updateCallback->UpdatePairs = &updatePairs2; + + SetInArchiveInterfaces(this, updateCallback.ClsPtr()); + + updateCallback->Callback = &updateCallbackAgent; + + CByteBuffer processedItems; + if (processedPaths) + { + unsigned num = dirItems.Items.Size(); + processedItems.Alloc(num); + for (unsigned i = 0; i < num; i++) + processedItems[i] = 0; + updateCallback->ProcessedItemsStatuses = processedItems; + } + + Z7_DECL_CMyComPtr_QI_FROM( + ISetProperties, + setProperties, outArchive) + if (setProperties) + { + if (m_PropNames.Size() == 0) + { + RINOK(setProperties->SetProperties(NULL, NULL, 0)) + } + else + { + CRecordVector names; + FOR_VECTOR (i, m_PropNames) + names.Add((const wchar_t *)m_PropNames[i]); + + CPropVariant *propValues = new CPropVariant[m_PropValues.Size()]; + try + { + FOR_VECTOR (i, m_PropValues) + propValues[i] = m_PropValues[i]; + RINOK(setProperties->SetProperties(names.ConstData(), propValues, names.Size())) + } + catch(...) + { + delete []propValues; + return E_FAIL; + } + delete []propValues; + } + } + m_PropNames.Clear(); + m_PropValues.Clear(); + + if (sfxModule != NULL) + { + CMyComPtr2_Create sfxStream; + if (!sfxStream->Open(us2fs(sfxModule))) + return E_FAIL; + // throw "Can't open sfx module"; + RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL)) + } + + const HRESULT res = outArchive->UpdateItems(outArchiveStream, updatePairs2.Size(), updateCallback); + if (res == S_OK && processedPaths) + { + { + /* OutHandler for 7z archives doesn't report compression operation for empty files. + So we must include these files manually */ + FOR_VECTOR(i, updatePairs2) + { + const CUpdatePair2 &up = updatePairs2[i]; + if (up.DirIndex != -1 && up.NewData) + { + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; + if (!di.IsDir() && di.Size == 0) + processedItems[(unsigned)up.DirIndex] = 1; + } + } + } + + FOR_VECTOR (i, dirItems.Items) + if (processedItems[i] != 0) + processedPaths->Add(dirItems.GetPhyPath(i)); + } + return res; +} + +Z7_COM7F_IMF(CAgent::DoOperation2( + FStringVector *requestedPaths, + FStringVector *processedPaths, + ISequentialOutStream *outArchiveStream, + const Byte *stateActions, const wchar_t *sfxModule, IFolderArchiveUpdateCallback *updateCallback100)) +{ + return DoOperation(requestedPaths, processedPaths, g_CodecsObj, -1, outArchiveStream, stateActions, sfxModule, updateCallback100); +} + +HRESULT CAgent::CommonUpdate(ISequentialOutStream *outArchiveStream, + unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CMyComPtr outArchive; + RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)) + return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback); +} + +Z7_COM7F_IMF(CAgent::DeleteItems(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, + IFolderArchiveUpdateCallback *updateCallback100)) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CRecordVector updatePairs; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CMyComPtr2_Create updateCallback; + + CUIntVector realIndices; + _agentFolder->GetRealIndices(indices, numItems, + true, // includeAltStreams + false, // includeFolderSubItemsInFlatMode, we don't want to delete subItems in Flat Mode + realIndices); + unsigned curIndex = 0; + UInt32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) + + UString deletePath; + + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + if (curIndex < realIndices.Size()) + if (realIndices[curIndex] == i) + { + RINOK(GetArc().GetItem_Path2(i, deletePath)) + RINOK(updateCallback100->DeleteOperation(deletePath)) + + curIndex++; + continue; + } + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(i); + updatePairs.Add(up2); + } + updateCallback->UpdatePairs = &updatePairs; + + SetInArchiveInterfaces(this, updateCallback.ClsPtr()); + + updateCallback->Callback = &updateCallbackAgent; + return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); +} + +HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream, + const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CRecordVector updatePairs; + CDirItems dirItems; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CMyComPtr2_Create updateCallback; + + UInt32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(i); + updatePairs.Add(up2); + } + CUpdatePair2 up2; + up2.NewData = up2.NewProps = true; + up2.UseArcProps = false; + up2.DirIndex = 0; + + updatePairs.Add(up2); + + updatePairs.ReserveDown(); + + CDirItem di; + + di.Attrib = FILE_ATTRIBUTE_DIRECTORY; + di.Size = 0; + bool isAltStreamFolder = false; + if (_proxy2) + di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder); + else + di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); + di.Name += folderName; + + FILETIME ft; + NTime::GetCurUtcFileTime(ft); + di.CTime = di.ATime = di.MTime = ft; + + dirItems.Items.Add(di); + + updateCallback->Callback = &updateCallbackAgent; + updateCallback->DirItems = &dirItems; + updateCallback->UpdatePairs = &updatePairs; + + SetInArchiveInterfaces(this, updateCallback.ClsPtr()); + + return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); +} + + +HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + if (numItems != 1) + return E_INVALIDARG; + if (!_archiveLink.IsOpen) + return E_FAIL; + CRecordVector updatePairs; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CMyComPtr2_Create updateCallback; + + CUIntVector realIndices; + _agentFolder->GetRealIndices(indices, numItems, + true, // includeAltStreams + true, // includeFolderSubItemsInFlatMode + realIndices); + + const UInt32 ind0 = indices[0]; + const int mainRealIndex = _agentFolder->GetRealIndex(ind0); + const UString fullPrefix = _agentFolder->GetFullPrefix(ind0); + UString name = _agentFolder->GetName(ind0); + // 22.00 : we normalize name + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); + const UString oldItemPath = fullPrefix + name; + const UString newItemPath = fullPrefix + newItemName; + + UStringVector newNames; + + unsigned curIndex = 0; + UInt32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) + + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(i); + if (curIndex < realIndices.Size()) + if (realIndices[curIndex] == i) + { + up2.NewProps = true; + RINOK(GetArc().IsItem_Anti(i, up2.IsAnti)) // it must work without that line too. + + UString oldFullPath; + RINOK(GetArc().GetItem_Path2(i, oldFullPath)) + + if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath)) + return E_INVALIDARG; + + up2.NewNameIndex = (int)newNames.Add(newItemPath + oldFullPath.Ptr(oldItemPath.Len())); + up2.IsMainRenameItem = (mainRealIndex == (int)i); + curIndex++; + } + updatePairs.Add(up2); + } + + updateCallback->Callback = &updateCallbackAgent; + updateCallback->UpdatePairs = &updatePairs; + updateCallback->NewNames = &newNames; + + SetInArchiveInterfaces(this, updateCallback.ClsPtr()); + + return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); +} + + +HRESULT CAgent::CommentItem(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + if (numItems != 1) + return E_INVALIDARG; + if (!_archiveLink.IsOpen) + return E_FAIL; + + CRecordVector updatePairs; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CMyComPtr2_Create updateCallback; + + const int mainRealIndex = _agentFolder->GetRealIndex(indices[0]); + + if (mainRealIndex < 0) + return E_NOTIMPL; + + UInt32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) + + UString newName = newItemName; + + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(i); + if ((int)i == mainRealIndex) + up2.NewProps = true; + updatePairs.Add(up2); + } + + updateCallback->Callback = &updateCallbackAgent; + updateCallback->UpdatePairs = &updatePairs; + updateCallback->CommentIndex = mainRealIndex; + updateCallback->Comment = &newName; + + SetInArchiveInterfaces(this, updateCallback.ClsPtr()); + + return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); +} + + + +HRESULT CAgent::UpdateOneFile(ISequentialOutStream *outArchiveStream, + const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CRecordVector updatePairs; + CDirItems dirItems; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.SetCallback(updateCallback100); + CMyComPtr2_Create updateCallback; + + UInt32 realIndex; + { + CUIntVector realIndices; + _agentFolder->GetRealIndices(indices, numItems, + false, // includeAltStreams // we update only main stream of file + false, // includeFolderSubItemsInFlatMode + realIndices); + if (realIndices.Size() != 1) + return E_FAIL; + realIndex = realIndices[0]; + } + + { + FStringVector filePaths; + filePaths.Add(us2fs(diskFilePath)); + dirItems.EnumerateItems2(FString(), UString(), filePaths, NULL); + if (dirItems.Items.Size() != 1) + return E_FAIL; + } + + UInt32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)) + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(i); + if (realIndex == i) + { + up2.DirIndex = 0; + up2.NewData = true; + up2.NewProps = true; + up2.UseArcProps = false; + } + updatePairs.Add(up2); + } + updateCallback->DirItems = &dirItems; + updateCallback->Callback = &updateCallbackAgent; + updateCallback->UpdatePairs = &updatePairs; + + SetInArchiveInterfaces(this, updateCallback.ClsPtr()); + + updateCallback->KeepOriginalItemNames = true; + return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback); +} + +Z7_COM7F_IMF(CAgent::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + m_PropNames.Clear(); + m_PropValues.Clear(); + for (UInt32 i = 0; i < numProps; i++) + { + m_PropNames.Add(names[i]); + m_PropValues.Add(values[i]); + } + return S_OK; +} diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp index 8a96607ae..176f39b70 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.cpp +++ b/CPP/7zip/UI/Agent/AgentProxy.cpp @@ -1,752 +1,752 @@ -// AgentProxy.cpp - -#include "StdAfx.h" - -// #include -#ifdef _WIN32 -#include -#else -#include -#endif - -#include "../../../../C/Sort.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/UTFConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../Archive/Common/ItemNameUtils.h" - -#include "AgentProxy.h" - -using namespace NWindows; - -int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const -{ - const CRecordVector &subDirs = Dirs[dirIndex].SubDirs; - unsigned left = 0, right = subDirs.Size(); - for (;;) - { - if (left == right) - { - insertPos = left; - return -1; - } - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned dirIndex2 = subDirs[mid]; - const int comp = CompareFileNames(name, Dirs[dirIndex2].Name); - if (comp == 0) - return (int)dirIndex2; - if (comp < 0) - right = mid; - else - left = mid + 1; - } -} - -int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const -{ - unsigned insertPos; - return FindSubDir(dirIndex, name, insertPos); -} - -static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len) -{ - wchar_t *p = new wchar_t[len + 1]; - MyStringCopy(p, s); - return p; -} - -static const wchar_t *AllocStringAndCopy(const UString &s) -{ - return AllocStringAndCopy(s, s.Len()); -} - -unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) -{ - unsigned insertPos; - int subDirIndex = FindSubDir(dirIndex, name, insertPos); - if (subDirIndex != -1) - { - if (arcIndex != -1) - { - CProxyDir &item = Dirs[(unsigned)subDirIndex]; - if (item.ArcIndex == -1) - item.ArcIndex = arcIndex; - } - return (unsigned)subDirIndex; - } - subDirIndex = (int)Dirs.Size(); - Dirs[dirIndex].SubDirs.Insert(insertPos, (unsigned)subDirIndex); - CProxyDir &item = Dirs.AddNew(); - - item.NameLen = name.Len(); - item.Name = AllocStringAndCopy(name); - - item.ArcIndex = arcIndex; - item.ParentDir = (int)dirIndex; - return (unsigned)subDirIndex; -} - -void CProxyDir::Clear() -{ - SubDirs.Clear(); - SubFiles.Clear(); -} - -void CProxyArc::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const -{ - pathParts.Clear(); - // while (dirIndex != -1) - for (;;) - { - const CProxyDir &dir = Dirs[dirIndex]; - dirIndex = (unsigned)dir.ParentDir; - if (dir.ParentDir == -1) - break; - pathParts.Insert(0, dir.Name); - // 22.00: we normalize name - NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]); - } -} - -UString CProxyArc::GetDirPath_as_Prefix(unsigned dirIndex) const -{ - UString s; - // while (dirIndex != -1) - for (;;) - { - const CProxyDir &dir = Dirs[dirIndex]; - dirIndex = (unsigned)dir.ParentDir; - if (dir.ParentDir == -1) - break; - s.InsertAtFront(WCHAR_PATH_SEPARATOR); - s.Insert(0, dir.Name); - // 22.00: we normalize name - NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name)); - } - return s; -} - -void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const -{ - const CProxyDir &dir = Dirs[dirIndex]; - if (dir.IsLeaf()) - realIndices.Add((unsigned)dir.ArcIndex); - unsigned i; - for (i = 0; i < dir.SubDirs.Size(); i++) - AddRealIndices(dir.SubDirs[i], realIndices); - for (i = 0; i < dir.SubFiles.Size(); i++) - realIndices.Add(dir.SubFiles[i]); -} - -int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const -{ - const CProxyDir &dir = Dirs[dirIndex]; - const unsigned numDirItems = dir.SubDirs.Size(); - if (index < numDirItems) - { - const CProxyDir &f = Dirs[dir.SubDirs[index]]; - if (f.IsLeaf()) - return f.ArcIndex; - return -1; - } - return (int)dir.SubFiles[index - numDirItems]; -} - -void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const -{ - const CProxyDir &dir = Dirs[dirIndex]; - realIndices.Clear(); - for (UInt32 i = 0; i < numItems; i++) - { - const UInt32 index = indices[i]; - const unsigned numDirItems = dir.SubDirs.Size(); - if (index < numDirItems) - AddRealIndices(dir.SubDirs[index], realIndices); - else - realIndices.Add(dir.SubFiles[index - numDirItems]); - } - HeapSort(realIndices.NonConstData(), realIndices.Size()); -} - -/////////////////////////////////////////////// -// CProxyArc - -static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size) -{ - size = 0; - NCOM::CPropVariant prop; - if (archive->GetProperty(index, propID, &prop) != S_OK) - throw 20120228; - return ConvertPropVariantToUInt64(prop, size); -} - -void CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive) -{ - CProxyDir &dir = Dirs[dirIndex]; - dir.Size = dir.PackSize = 0; - dir.NumSubDirs = dir.SubDirs.Size(); - dir.NumSubFiles = dir.SubFiles.Size(); - dir.CrcIsDefined = true; - dir.Crc = 0; - - unsigned i; - - for (i = 0; i < dir.SubFiles.Size(); i++) - { - const UInt32 index = (UInt32)dir.SubFiles[i]; - UInt64 size, packSize; - const bool sizeDefined = GetSize(archive, index, kpidSize, size); - dir.Size += size; - GetSize(archive, index, kpidPackSize, packSize); - dir.PackSize += packSize; - { - NCOM::CPropVariant prop; - if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) - { - if (prop.vt == VT_UI4) - dir.Crc += prop.ulVal; - else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) - dir.CrcIsDefined = false; - } - else - dir.CrcIsDefined = false; - } - } - - for (i = 0; i < dir.SubDirs.Size(); i++) - { - unsigned subDirIndex = dir.SubDirs[i]; - CalculateSizes(subDirIndex, archive); - CProxyDir &f = Dirs[subDirIndex]; - dir.Size += f.Size; - dir.PackSize += f.PackSize; - dir.NumSubFiles += f.NumSubFiles; - dir.NumSubDirs += f.NumSubDirs; - dir.Crc += f.Crc; - if (!f.CrcIsDefined) - dir.CrcIsDefined = false; - } -} - -HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) -{ - // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { - - Files.Free(); - Dirs.Clear(); - - Dirs.AddNew(); - IInArchive *archive = arc.Archive; - - UInt32 numItems; - RINOK(archive->GetNumberOfItems(&numItems)) - - if (progress) - RINOK(progress->SetTotal(numItems)) - - Files.Alloc(numItems); - - UString path; - UString name; - NCOM::CPropVariant prop; - - for (UInt32 i = 0; i < numItems; i++) - { - if (progress && (i & 0xFFFF) == 0) - { - const UInt64 currentItemIndex = i; - RINOK(progress->SetCompleted(¤tItemIndex)) - } - - const wchar_t *s = NULL; - unsigned len = 0; - bool isPtrName = false; - - #if WCHAR_PATH_SEPARATOR != L'/' - wchar_t separatorChar = WCHAR_PATH_SEPARATOR; - #endif - - #if defined(MY_CPU_LE) && defined(_WIN32) - // it works only if (sizeof(wchar_t) == 2) - if (arc.GetRawProps) - { - const void *p; - UInt32 size; - UInt32 propType; - if (arc.GetRawProps->GetRawProp(i, kpidPath, &p, &size, &propType) == S_OK - && propType == NPropDataType::kUtf16z - && size > 2) - { - // is (size <= 2), it's empty name, and we call default arc.GetItemPath(); - len = size / 2 - 1; - s = (const wchar_t *)p; - isPtrName = true; - #if WCHAR_PATH_SEPARATOR != L'/' - separatorChar = L'/'; // 0 - #endif - } - } - if (!s) - #endif - { - prop.Clear(); - RINOK(arc.Archive->GetProperty(i, kpidPath, &prop)) - if (prop.vt == VT_BSTR) - { - s = prop.bstrVal; - len = ::SysStringLen(prop.bstrVal); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - if (len == 0) - { - RINOK(arc.GetItem_DefaultPath(i, path)) - len = path.Len(); - s = path; - } - - /* - RINOK(arc.GetItemPath(i, path)); - len = path.Len(); - s = path; - */ - } - - unsigned curItem = 0; - - /* - if (arc.Ask_Deleted) - { - bool isDeleted = false; - RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)); - if (isDeleted) - curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); - } - */ - - unsigned namePos = 0; - - unsigned numLevels = 0; - - for (unsigned j = 0; j < len; j++) - { - const wchar_t c = s[j]; - if (c == L'/' - #if WCHAR_PATH_SEPARATOR != L'/' - || (c == separatorChar) - #endif - ) - { - const unsigned kLevelLimit = 1 << 10; - if (numLevels <= kLevelLimit) - { - if (numLevels == kLevelLimit) - name = "[LONG_PATH]"; - else - name.SetFrom(s + namePos, j - namePos); - // 22.00: we can normalize dir here - // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); - curItem = AddDir(curItem, -1, name); - } - namePos = j + 1; - numLevels++; - } - } - - /* - that code must be implemeted to hide alt streams in list. - if (arc.Ask_AltStreams) - { - bool isAltStream; - RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); - if (isAltStream) - { - - } - } - */ - - bool isDir; - RINOK(Archive_IsItem_Dir(archive, i, isDir)) - - CProxyFile &f = Files[i]; - - f.NameLen = len - namePos; - s += namePos; - - if (isPtrName) - f.Name = s; - else - { - f.Name = AllocStringAndCopy(s, f.NameLen); - f.NeedDeleteName = true; - } - - if (isDir) - { - name = s; - // 22.00: we can normalize dir here - // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); - AddDir(curItem, (int)i, name); - } - else - Dirs[curItem].SubFiles.Add(i); - } - - CalculateSizes(0, archive); - - // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); - - return S_OK; -} - - - -// ---------- for Tree-mode archive ---------- - -void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const -{ - pathParts.Clear(); - - isAltStreamDir = false; - - if (dirIndex == k_Proxy2_RootDirIndex) - return; - if (dirIndex == k_Proxy2_AltRootDirIndex) - { - isAltStreamDir = true; - return; - } - - while (dirIndex >= k_Proxy2_NumRootDirs) - { - const CProxyDir2 &dir = Dirs[dirIndex]; - const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; - if (pathParts.IsEmpty() && (int)dirIndex == file.AltDirIndex) - isAltStreamDir = true; - pathParts.Insert(0, file.Name); - const int par = file.Parent; - if (par == -1) - break; - dirIndex = (unsigned)Files[(unsigned)par].DirIndex; - // if ((int)dirIndex == -1) break; - } -} - -bool CProxyArc2::IsAltDir(unsigned dirIndex) const -{ - if (dirIndex == k_Proxy2_RootDirIndex) - return false; - if (dirIndex == k_Proxy2_AltRootDirIndex) - return true; - const CProxyDir2 &dir = Dirs[dirIndex]; - const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; - return ((int)dirIndex == file.AltDirIndex); -} - -UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const -{ - isAltStreamDir = false; - const CProxyDir2 &dir = Dirs[dirIndex]; - if (dirIndex == k_Proxy2_AltRootDirIndex) - isAltStreamDir = true; - else if (dirIndex >= k_Proxy2_NumRootDirs) - { - const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; - isAltStreamDir = ((int)dirIndex == file.AltDirIndex); - } - return dir.PathPrefix; -} - -void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const -{ - realIndices.Add(arcIndex); - const CProxyFile2 &file = Files[arcIndex]; - if (file.DirIndex != -1) - AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices); - if (includeAltStreams && file.AltDirIndex != -1) - AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices); -} - -void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const -{ - const CRecordVector &subFiles = Dirs[dirIndex].Items; - FOR_VECTOR (i, subFiles) - { - AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices); - } -} - -unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const -{ - return Dirs[dirIndex].Items[index]; -} - -void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const -{ - const CProxyDir2 &dir = Dirs[dirIndex]; - realIndices.Clear(); - for (UInt32 i = 0; i < numItems; i++) - { - AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices); - } - HeapSort(realIndices.NonConstData(), realIndices.Size()); -} - -void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive) -{ - CProxyDir2 &dir = Dirs[dirIndex]; - dir.Size = dir.PackSize = 0; - dir.NumSubDirs = 0; // dir.SubDirs.Size(); - dir.NumSubFiles = 0; // dir.Files.Size(); - dir.CrcIsDefined = true; - dir.Crc = 0; - - FOR_VECTOR (i, dir.Items) - { - UInt32 index = dir.Items[i]; - UInt64 size, packSize; - const bool sizeDefined = GetSize(archive, index, kpidSize, size); - dir.Size += size; - GetSize(archive, index, kpidPackSize, packSize); - dir.PackSize += packSize; - { - NCOM::CPropVariant prop; - if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) - { - if (prop.vt == VT_UI4) - dir.Crc += prop.ulVal; - else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) - dir.CrcIsDefined = false; - } - else - dir.CrcIsDefined = false; - } - - const CProxyFile2 &subFile = Files[index]; - if (subFile.DirIndex == -1) - { - dir.NumSubFiles++; - } - else - { - // 22.00: we normalize name - UString s = subFile.Name; - NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s); - dir.NumSubDirs++; - CProxyDir2 &f = Dirs[subFile.DirIndex]; - f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR; - CalculateSizes((unsigned)subFile.DirIndex, archive); - dir.Size += f.Size; - dir.PackSize += f.PackSize; - dir.NumSubFiles += f.NumSubFiles; - dir.NumSubDirs += f.NumSubDirs; - dir.Crc += f.Crc; - if (!f.CrcIsDefined) - dir.CrcIsDefined = false; - } - - if (subFile.AltDirIndex == -1) - { - // dir.NumSubFiles++; - } - else - { - // dir.NumSubDirs++; - CProxyDir2 &f = Dirs[subFile.AltDirIndex]; - f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; - CalculateSizes((unsigned)subFile.AltDirIndex, archive); - } - } -} - - -bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const -{ - const CRecordVector &subFiles = Dirs[dirIndex].Items; - FOR_VECTOR (i, subFiles) - { - const CProxyFile2 &file = Files[subFiles[i]]; - if (file.IsDir()) - if (CompareFileNames(name, file.Name) == 0) - return true; - } - return false; -} - -HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) -{ - if (!arc.GetRawProps) - return E_FAIL; - - // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { - - Dirs.Clear(); - Files.Free(); - - IInArchive *archive = arc.Archive; - - UInt32 numItems; - RINOK(archive->GetNumberOfItems(&numItems)) - if (progress) - RINOK(progress->SetTotal(numItems)) - UString fileName; - - - { - // Dirs[0] - root dir - /* CProxyDir2 &dir = */ Dirs.AddNew(); - } - - { - // Dirs[1] - for alt streams of root dir - CProxyDir2 &dir = Dirs.AddNew(); - dir.PathPrefix = ':'; - } - - Files.Alloc(numItems); - - UString tempUString; - AString tempAString; - - UInt32 i; - for (i = 0; i < numItems; i++) - { - if (progress && (i & 0xFFFFF) == 0) - { - UInt64 currentItemIndex = i; - RINOK(progress->SetCompleted(¤tItemIndex)) - } - - CProxyFile2 &file = Files[i]; - - const void *p; - UInt32 size; - UInt32 propType; - RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType)) - - #ifdef MY_CPU_LE - if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) - { - file.Name = (const wchar_t *)p; - file.NameLen = 0; - if (size >= sizeof(wchar_t)) - file.NameLen = size / sizeof(wchar_t) - 1; - } - else - #endif - if (p && propType == NPropDataType::kUtf8z) - { - tempAString = (const char *)p; - ConvertUTF8ToUnicode(tempAString, tempUString); - file.NameLen = tempUString.Len(); - file.Name = AllocStringAndCopy(tempUString); - file.NeedDeleteName = true; - } - else - { - NCOM::CPropVariant prop; - RINOK(arc.Archive->GetProperty(i, kpidName, &prop)) - const wchar_t *s; - if (prop.vt == VT_BSTR) - s = prop.bstrVal; - else if (prop.vt == VT_EMPTY) - s = L"[Content]"; - else - return E_FAIL; - file.NameLen = MyStringLen(s); - file.Name = AllocStringAndCopy(s, file.NameLen); - file.NeedDeleteName = true; - } - - UInt32 parent = (UInt32)(Int32)-1; - UInt32 parentType = 0; - RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType)) - file.Parent = (Int32)parent; - - if (arc.Ask_Deleted) - { - bool isDeleted = false; - RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)) - if (isDeleted) - { - // continue; - // curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); - } - } - - bool isDir; - RINOK(Archive_IsItem_Dir(archive, i, isDir)) - - if (isDir) - { - file.DirIndex = (int)Dirs.Size(); - CProxyDir2 &dir = Dirs.AddNew(); - dir.ArcIndex = (int)i; - } - if (arc.Ask_AltStream) - RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream)) - } - - for (i = 0; i < numItems; i++) - { - CProxyFile2 &file = Files[i]; - int dirIndex; - - if (file.IsAltStream) - { - if (file.Parent == -1) - dirIndex = k_Proxy2_AltRootDirIndex; - else - { - int &folderIndex2 = Files[(unsigned)file.Parent].AltDirIndex; - if (folderIndex2 == -1) - { - folderIndex2 = (int)Dirs.Size(); - CProxyDir2 &dir = Dirs.AddNew(); - dir.ArcIndex = file.Parent; - } - dirIndex = folderIndex2; - } - } - else - { - if (file.Parent == -1) - dirIndex = k_Proxy2_RootDirIndex; - else - { - dirIndex = Files[(unsigned)file.Parent].DirIndex; - if (dirIndex == -1) - return E_FAIL; - } - } - - Dirs[dirIndex].Items.Add(i); - } - - for (i = 0; i < k_Proxy2_NumRootDirs; i++) - CalculateSizes(i, archive); - - // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); - - return S_OK; -} - -int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const -{ - const CProxyDir2 &dir = Dirs[dirIndex]; - FOR_VECTOR (i, dir.Items) - { - const CProxyFile2 &file = Files[dir.Items[i]]; - if (foldersOnly && file.DirIndex == -1) - continue; - if (CompareFileNames(file.Name, name) == 0) - return (int)i; - } - return -1; -} +// AgentProxy.cpp + +#include "StdAfx.h" + +// #include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "../../../../C/Sort.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/UTFConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../Archive/Common/ItemNameUtils.h" + +#include "AgentProxy.h" + +using namespace NWindows; + +int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const +{ + const CRecordVector &subDirs = Dirs[dirIndex].SubDirs; + unsigned left = 0, right = subDirs.Size(); + for (;;) + { + if (left == right) + { + insertPos = left; + return -1; + } + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned dirIndex2 = subDirs[mid]; + const int comp = CompareFileNames(name, Dirs[dirIndex2].Name); + if (comp == 0) + return (int)dirIndex2; + if (comp < 0) + right = mid; + else + left = mid + 1; + } +} + +int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const +{ + unsigned insertPos; + return FindSubDir(dirIndex, name, insertPos); +} + +static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len) +{ + wchar_t *p = new wchar_t[len + 1]; + MyStringCopy(p, s); + return p; +} + +static const wchar_t *AllocStringAndCopy(const UString &s) +{ + return AllocStringAndCopy(s, s.Len()); +} + +unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) +{ + unsigned insertPos; + int subDirIndex = FindSubDir(dirIndex, name, insertPos); + if (subDirIndex != -1) + { + if (arcIndex != -1) + { + CProxyDir &item = Dirs[(unsigned)subDirIndex]; + if (item.ArcIndex == -1) + item.ArcIndex = arcIndex; + } + return (unsigned)subDirIndex; + } + subDirIndex = (int)Dirs.Size(); + Dirs[dirIndex].SubDirs.Insert(insertPos, (unsigned)subDirIndex); + CProxyDir &item = Dirs.AddNew(); + + item.NameLen = name.Len(); + item.Name = AllocStringAndCopy(name); + + item.ArcIndex = arcIndex; + item.ParentDir = (int)dirIndex; + return (unsigned)subDirIndex; +} + +void CProxyDir::Clear() +{ + SubDirs.Clear(); + SubFiles.Clear(); +} + +void CProxyArc::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const +{ + pathParts.Clear(); + // while (dirIndex != -1) + for (;;) + { + const CProxyDir &dir = Dirs[dirIndex]; + dirIndex = (unsigned)dir.ParentDir; + if (dir.ParentDir == -1) + break; + pathParts.Insert(0, dir.Name); + // 22.00: we normalize name + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]); + } +} + +UString CProxyArc::GetDirPath_as_Prefix(unsigned dirIndex) const +{ + UString s; + // while (dirIndex != -1) + for (;;) + { + const CProxyDir &dir = Dirs[dirIndex]; + dirIndex = (unsigned)dir.ParentDir; + if (dir.ParentDir == -1) + break; + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + s.Insert(0, dir.Name); + // 22.00: we normalize name + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name)); + } + return s; +} + +void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const +{ + const CProxyDir &dir = Dirs[dirIndex]; + if (dir.IsLeaf()) + realIndices.Add((unsigned)dir.ArcIndex); + unsigned i; + for (i = 0; i < dir.SubDirs.Size(); i++) + AddRealIndices(dir.SubDirs[i], realIndices); + for (i = 0; i < dir.SubFiles.Size(); i++) + realIndices.Add(dir.SubFiles[i]); +} + +int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const +{ + const CProxyDir &dir = Dirs[dirIndex]; + const unsigned numDirItems = dir.SubDirs.Size(); + if (index < numDirItems) + { + const CProxyDir &f = Dirs[dir.SubDirs[index]]; + if (f.IsLeaf()) + return f.ArcIndex; + return -1; + } + return (int)dir.SubFiles[index - numDirItems]; +} + +void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const +{ + const CProxyDir &dir = Dirs[dirIndex]; + realIndices.Clear(); + for (UInt32 i = 0; i < numItems; i++) + { + const UInt32 index = indices[i]; + const unsigned numDirItems = dir.SubDirs.Size(); + if (index < numDirItems) + AddRealIndices(dir.SubDirs[index], realIndices); + else + realIndices.Add(dir.SubFiles[index - numDirItems]); + } + HeapSort(realIndices.NonConstData(), realIndices.Size()); +} + +/////////////////////////////////////////////// +// CProxyArc + +static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size) +{ + size = 0; + NCOM::CPropVariant prop; + if (archive->GetProperty(index, propID, &prop) != S_OK) + throw 20120228; + return ConvertPropVariantToUInt64(prop, size); +} + +void CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive) +{ + CProxyDir &dir = Dirs[dirIndex]; + dir.Size = dir.PackSize = 0; + dir.NumSubDirs = dir.SubDirs.Size(); + dir.NumSubFiles = dir.SubFiles.Size(); + dir.CrcIsDefined = true; + dir.Crc = 0; + + unsigned i; + + for (i = 0; i < dir.SubFiles.Size(); i++) + { + const UInt32 index = (UInt32)dir.SubFiles[i]; + UInt64 size, packSize; + const bool sizeDefined = GetSize(archive, index, kpidSize, size); + dir.Size += size; + GetSize(archive, index, kpidPackSize, packSize); + dir.PackSize += packSize; + { + NCOM::CPropVariant prop; + if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) + { + if (prop.vt == VT_UI4) + dir.Crc += prop.ulVal; + else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) + dir.CrcIsDefined = false; + } + else + dir.CrcIsDefined = false; + } + } + + for (i = 0; i < dir.SubDirs.Size(); i++) + { + unsigned subDirIndex = dir.SubDirs[i]; + CalculateSizes(subDirIndex, archive); + CProxyDir &f = Dirs[subDirIndex]; + dir.Size += f.Size; + dir.PackSize += f.PackSize; + dir.NumSubFiles += f.NumSubFiles; + dir.NumSubDirs += f.NumSubDirs; + dir.Crc += f.Crc; + if (!f.CrcIsDefined) + dir.CrcIsDefined = false; + } +} + +HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) +{ + // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { + + Files.Free(); + Dirs.Clear(); + + Dirs.AddNew(); + IInArchive *archive = arc.Archive; + + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)) + + if (progress) + RINOK(progress->SetTotal(numItems)) + + Files.Alloc(numItems); + + UString path; + UString name; + NCOM::CPropVariant prop; + + for (UInt32 i = 0; i < numItems; i++) + { + if (progress && (i & 0xFFFF) == 0) + { + const UInt64 currentItemIndex = i; + RINOK(progress->SetCompleted(¤tItemIndex)) + } + + const wchar_t *s = NULL; + unsigned len = 0; + bool isPtrName = false; + + #if WCHAR_PATH_SEPARATOR != L'/' + wchar_t separatorChar = WCHAR_PATH_SEPARATOR; + #endif + + #if defined(MY_CPU_LE) && defined(_WIN32) + // it works only if (sizeof(wchar_t) == 2) + if (arc.GetRawProps) + { + const void *p; + UInt32 size; + UInt32 propType; + if (arc.GetRawProps->GetRawProp(i, kpidPath, &p, &size, &propType) == S_OK + && propType == NPropDataType::kUtf16z + && size > 2) + { + // is (size <= 2), it's empty name, and we call default arc.GetItemPath(); + len = size / 2 - 1; + s = (const wchar_t *)p; + isPtrName = true; + #if WCHAR_PATH_SEPARATOR != L'/' + separatorChar = L'/'; // 0 + #endif + } + } + if (!s) + #endif + { + prop.Clear(); + RINOK(arc.Archive->GetProperty(i, kpidPath, &prop)) + if (prop.vt == VT_BSTR) + { + s = prop.bstrVal; + len = ::SysStringLen(prop.bstrVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + if (len == 0) + { + RINOK(arc.GetItem_DefaultPath(i, path)) + len = path.Len(); + s = path; + } + + /* + RINOK(arc.GetItemPath(i, path)); + len = path.Len(); + s = path; + */ + } + + unsigned curItem = 0; + + /* + if (arc.Ask_Deleted) + { + bool isDeleted = false; + RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)); + if (isDeleted) + curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); + } + */ + + unsigned namePos = 0; + + unsigned numLevels = 0; + + for (unsigned j = 0; j < len; j++) + { + const wchar_t c = s[j]; + if (c == L'/' + #if WCHAR_PATH_SEPARATOR != L'/' + || (c == separatorChar) + #endif + ) + { + const unsigned kLevelLimit = 1 << 10; + if (numLevels <= kLevelLimit) + { + if (numLevels == kLevelLimit) + name = "[LONG_PATH]"; + else + name.SetFrom(s + namePos, j - namePos); + // 22.00: we can normalize dir here + // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); + curItem = AddDir(curItem, -1, name); + } + namePos = j + 1; + numLevels++; + } + } + + /* + that code must be implemeted to hide alt streams in list. + if (arc.Ask_AltStreams) + { + bool isAltStream; + RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); + if (isAltStream) + { + + } + } + */ + + bool isDir; + RINOK(Archive_IsItem_Dir(archive, i, isDir)) + + CProxyFile &f = Files[i]; + + f.NameLen = len - namePos; + s += namePos; + + if (isPtrName) + f.Name = s; + else + { + f.Name = AllocStringAndCopy(s, f.NameLen); + f.NeedDeleteName = true; + } + + if (isDir) + { + name = s; + // 22.00: we can normalize dir here + // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); + AddDir(curItem, (int)i, name); + } + else + Dirs[curItem].SubFiles.Add(i); + } + + CalculateSizes(0, archive); + + // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); + + return S_OK; +} + + + +// ---------- for Tree-mode archive ---------- + +void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const +{ + pathParts.Clear(); + + isAltStreamDir = false; + + if (dirIndex == k_Proxy2_RootDirIndex) + return; + if (dirIndex == k_Proxy2_AltRootDirIndex) + { + isAltStreamDir = true; + return; + } + + while (dirIndex >= k_Proxy2_NumRootDirs) + { + const CProxyDir2 &dir = Dirs[dirIndex]; + const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; + if (pathParts.IsEmpty() && (int)dirIndex == file.AltDirIndex) + isAltStreamDir = true; + pathParts.Insert(0, file.Name); + const int par = file.Parent; + if (par == -1) + break; + dirIndex = (unsigned)Files[(unsigned)par].DirIndex; + // if ((int)dirIndex == -1) break; + } +} + +bool CProxyArc2::IsAltDir(unsigned dirIndex) const +{ + if (dirIndex == k_Proxy2_RootDirIndex) + return false; + if (dirIndex == k_Proxy2_AltRootDirIndex) + return true; + const CProxyDir2 &dir = Dirs[dirIndex]; + const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; + return ((int)dirIndex == file.AltDirIndex); +} + +UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const +{ + isAltStreamDir = false; + const CProxyDir2 &dir = Dirs[dirIndex]; + if (dirIndex == k_Proxy2_AltRootDirIndex) + isAltStreamDir = true; + else if (dirIndex >= k_Proxy2_NumRootDirs) + { + const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; + isAltStreamDir = ((int)dirIndex == file.AltDirIndex); + } + return dir.PathPrefix; +} + +void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const +{ + realIndices.Add(arcIndex); + const CProxyFile2 &file = Files[arcIndex]; + if (file.DirIndex != -1) + AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices); + if (includeAltStreams && file.AltDirIndex != -1) + AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices); +} + +void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const +{ + const CRecordVector &subFiles = Dirs[dirIndex].Items; + FOR_VECTOR (i, subFiles) + { + AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices); + } +} + +unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const +{ + return Dirs[dirIndex].Items[index]; +} + +void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const +{ + const CProxyDir2 &dir = Dirs[dirIndex]; + realIndices.Clear(); + for (UInt32 i = 0; i < numItems; i++) + { + AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices); + } + HeapSort(realIndices.NonConstData(), realIndices.Size()); +} + +void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive) +{ + CProxyDir2 &dir = Dirs[dirIndex]; + dir.Size = dir.PackSize = 0; + dir.NumSubDirs = 0; // dir.SubDirs.Size(); + dir.NumSubFiles = 0; // dir.Files.Size(); + dir.CrcIsDefined = true; + dir.Crc = 0; + + FOR_VECTOR (i, dir.Items) + { + UInt32 index = dir.Items[i]; + UInt64 size, packSize; + const bool sizeDefined = GetSize(archive, index, kpidSize, size); + dir.Size += size; + GetSize(archive, index, kpidPackSize, packSize); + dir.PackSize += packSize; + { + NCOM::CPropVariant prop; + if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) + { + if (prop.vt == VT_UI4) + dir.Crc += prop.ulVal; + else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) + dir.CrcIsDefined = false; + } + else + dir.CrcIsDefined = false; + } + + const CProxyFile2 &subFile = Files[index]; + if (subFile.DirIndex == -1) + { + dir.NumSubFiles++; + } + else + { + // 22.00: we normalize name + UString s = subFile.Name; + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s); + dir.NumSubDirs++; + CProxyDir2 &f = Dirs[subFile.DirIndex]; + f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR; + CalculateSizes((unsigned)subFile.DirIndex, archive); + dir.Size += f.Size; + dir.PackSize += f.PackSize; + dir.NumSubFiles += f.NumSubFiles; + dir.NumSubDirs += f.NumSubDirs; + dir.Crc += f.Crc; + if (!f.CrcIsDefined) + dir.CrcIsDefined = false; + } + + if (subFile.AltDirIndex == -1) + { + // dir.NumSubFiles++; + } + else + { + // dir.NumSubDirs++; + CProxyDir2 &f = Dirs[subFile.AltDirIndex]; + f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; + CalculateSizes((unsigned)subFile.AltDirIndex, archive); + } + } +} + + +bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const +{ + const CRecordVector &subFiles = Dirs[dirIndex].Items; + FOR_VECTOR (i, subFiles) + { + const CProxyFile2 &file = Files[subFiles[i]]; + if (file.IsDir()) + if (CompareFileNames(name, file.Name) == 0) + return true; + } + return false; +} + +HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) +{ + if (!arc.GetRawProps) + return E_FAIL; + + // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { + + Dirs.Clear(); + Files.Free(); + + IInArchive *archive = arc.Archive; + + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)) + if (progress) + RINOK(progress->SetTotal(numItems)) + UString fileName; + + + { + // Dirs[0] - root dir + /* CProxyDir2 &dir = */ Dirs.AddNew(); + } + + { + // Dirs[1] - for alt streams of root dir + CProxyDir2 &dir = Dirs.AddNew(); + dir.PathPrefix = ':'; + } + + Files.Alloc(numItems); + + UString tempUString; + AString tempAString; + + UInt32 i; + for (i = 0; i < numItems; i++) + { + if (progress && (i & 0xFFFFF) == 0) + { + UInt64 currentItemIndex = i; + RINOK(progress->SetCompleted(¤tItemIndex)) + } + + CProxyFile2 &file = Files[i]; + + const void *p; + UInt32 size; + UInt32 propType; + RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType)) + + #ifdef MY_CPU_LE + if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) + { + file.Name = (const wchar_t *)p; + file.NameLen = 0; + if (size >= sizeof(wchar_t)) + file.NameLen = size / sizeof(wchar_t) - 1; + } + else + #endif + if (p && propType == NPropDataType::kUtf8z) + { + tempAString = (const char *)p; + ConvertUTF8ToUnicode(tempAString, tempUString); + file.NameLen = tempUString.Len(); + file.Name = AllocStringAndCopy(tempUString); + file.NeedDeleteName = true; + } + else + { + NCOM::CPropVariant prop; + RINOK(arc.Archive->GetProperty(i, kpidName, &prop)) + const wchar_t *s; + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + else if (prop.vt == VT_EMPTY) + s = L"[Content]"; + else + return E_FAIL; + file.NameLen = MyStringLen(s); + file.Name = AllocStringAndCopy(s, file.NameLen); + file.NeedDeleteName = true; + } + + UInt32 parent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType)) + file.Parent = (Int32)parent; + + if (arc.Ask_Deleted) + { + bool isDeleted = false; + RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)) + if (isDeleted) + { + // continue; + // curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); + } + } + + bool isDir; + RINOK(Archive_IsItem_Dir(archive, i, isDir)) + + if (isDir) + { + file.DirIndex = (int)Dirs.Size(); + CProxyDir2 &dir = Dirs.AddNew(); + dir.ArcIndex = (int)i; + } + if (arc.Ask_AltStream) + RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream)) + } + + for (i = 0; i < numItems; i++) + { + CProxyFile2 &file = Files[i]; + int dirIndex; + + if (file.IsAltStream) + { + if (file.Parent == -1) + dirIndex = k_Proxy2_AltRootDirIndex; + else + { + int &folderIndex2 = Files[(unsigned)file.Parent].AltDirIndex; + if (folderIndex2 == -1) + { + folderIndex2 = (int)Dirs.Size(); + CProxyDir2 &dir = Dirs.AddNew(); + dir.ArcIndex = file.Parent; + } + dirIndex = folderIndex2; + } + } + else + { + if (file.Parent == -1) + dirIndex = k_Proxy2_RootDirIndex; + else + { + dirIndex = Files[(unsigned)file.Parent].DirIndex; + if (dirIndex == -1) + return E_FAIL; + } + } + + Dirs[dirIndex].Items.Add(i); + } + + for (i = 0; i < k_Proxy2_NumRootDirs; i++) + CalculateSizes(i, archive); + + // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); + + return S_OK; +} + +int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const +{ + const CProxyDir2 &dir = Dirs[dirIndex]; + FOR_VECTOR (i, dir.Items) + { + const CProxyFile2 &file = Files[dir.Items[i]]; + if (foldersOnly && file.DirIndex == -1) + continue; + if (CompareFileNames(file.Name, name) == 0) + return (int)i; + } + return -1; +} diff --git a/CPP/7zip/UI/Agent/AgentProxy.h b/CPP/7zip/UI/Agent/AgentProxy.h index ada03aecb..c24dd9147 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.h +++ b/CPP/7zip/UI/Agent/AgentProxy.h @@ -1,162 +1,162 @@ -// AgentProxy.h - -#ifndef ZIP7_INC_AGENT_PROXY_H -#define ZIP7_INC_AGENT_PROXY_H - -#include "../Common/OpenArchive.h" - -struct CProxyFile -{ - const wchar_t *Name; - unsigned NameLen; - bool NeedDeleteName; - - CProxyFile(): Name(NULL), NameLen(0), NeedDeleteName(false) {} - ~CProxyFile() { if (NeedDeleteName) delete [](wchar_t *)(void *)Name; } // delete [](wchar_t *)Name; -}; - -const unsigned k_Proxy_RootDirIndex = 0; - -struct CProxyDir -{ - const wchar_t *Name; - unsigned NameLen; - - int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder - int ParentDir; // index in proxy->Dirs[] ; -1 for root folder; ; - CRecordVector SubDirs; - CRecordVector SubFiles; - - UInt64 Size; - UInt64 PackSize; - UInt32 Crc; - UInt32 NumSubDirs; - UInt32 NumSubFiles; - bool CrcIsDefined; - - CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {} - ~CProxyDir() { delete [](wchar_t *)(void *)Name; } - - void Clear(); - bool IsLeaf() const { return ArcIndex != -1; } -}; - -class CProxyArc -{ - int FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const; - - void CalculateSizes(unsigned dirIndex, IInArchive *archive); - unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name); -public: - CObjectVector Dirs; // Dirs[0] - root - CObjArray Files; // all items from archive in same order - - // returns index in Dirs[], or -1, - int FindSubDir(unsigned dirIndex, const wchar_t *name) const; - - void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const; - // returns full path of Dirs[dirIndex], including back slash - UString GetDirPath_as_Prefix(unsigned dirIndex) const; - - // AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf) - void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const; - int GetRealIndex(unsigned dirIndex, unsigned index) const; - void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const; - - HRESULT Load(const CArc &arc, IProgress *progress); -}; - - -// ---------- for Tree-mode archive ---------- - -struct CProxyFile2 -{ - int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs) - int AltDirIndex; // >= 0 if there are alt streams. (index in ProxyArchive2->Dirs) - int Parent; // >= 0 if there is parent. (index in archive and in ProxyArchive2->Files) - const wchar_t *Name; - unsigned NameLen; - bool NeedDeleteName; - bool Ignore; - bool IsAltStream; - - int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; } - - bool IsDir() const { return DirIndex != -1; } - CProxyFile2(): - DirIndex(-1), AltDirIndex(-1), Parent(-1), - Name(NULL), NameLen(0), - NeedDeleteName(false), - Ignore(false), - IsAltStream(false) - {} - ~CProxyFile2() - { - if (NeedDeleteName) - delete [](wchar_t *)(void *)Name; - } -}; - -struct CProxyDir2 -{ - int ArcIndex; // = -1 for root folders, index in proxy->Files[] - CRecordVector Items; - UString PathPrefix; - UInt64 Size; - UInt64 PackSize; - bool CrcIsDefined; - UInt32 Crc; - UInt32 NumSubDirs; - UInt32 NumSubFiles; - - CProxyDir2(): ArcIndex(-1) {} - void AddFileSubItem(UInt32 index, const UString &name); - void Clear(); -}; - -const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex; -const unsigned k_Proxy2_AltRootDirIndex = 1; -const unsigned k_Proxy2_NumRootDirs = 2; - -class CProxyArc2 -{ - void CalculateSizes(unsigned dirIndex, IInArchive *archive); - // AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex - void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const; -public: - CObjectVector Dirs; // Dirs[0] - root folder - // Dirs[1] - for alt streams of root dir - CObjArray Files; // all items from archive in same order - - bool IsThere_SubDir(unsigned dirIndex, const UString &name) const; - - void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const; - UString GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const; - bool IsAltDir(unsigned dirIndex) const; - - // AddRealIndices_of_ArcItem DOES ADD item and subItems - void AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const; - unsigned GetRealIndex(unsigned dirIndex, unsigned index) const; - void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const; - - HRESULT Load(const CArc &arc, IProgress *progress); - - int GetParentDirOfFile(UInt32 arcIndex) const - { - const CProxyFile2 &file = Files[arcIndex]; - - if (file.Parent == -1) - return file.IsAltStream ? - k_Proxy2_AltRootDirIndex : - k_Proxy2_RootDirIndex; - - const CProxyFile2 &parentFile = Files[file.Parent]; - return file.IsAltStream ? - parentFile.AltDirIndex : - parentFile.DirIndex; - } - - int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const; -}; - -#endif +// AgentProxy.h + +#ifndef ZIP7_INC_AGENT_PROXY_H +#define ZIP7_INC_AGENT_PROXY_H + +#include "../Common/OpenArchive.h" + +struct CProxyFile +{ + const wchar_t *Name; + unsigned NameLen; + bool NeedDeleteName; + + CProxyFile(): Name(NULL), NameLen(0), NeedDeleteName(false) {} + ~CProxyFile() { if (NeedDeleteName) delete [](wchar_t *)(void *)Name; } // delete [](wchar_t *)Name; +}; + +const unsigned k_Proxy_RootDirIndex = 0; + +struct CProxyDir +{ + const wchar_t *Name; + unsigned NameLen; + + int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder + int ParentDir; // index in proxy->Dirs[] ; -1 for root folder; ; + CRecordVector SubDirs; + CRecordVector SubFiles; + + UInt64 Size; + UInt64 PackSize; + UInt32 Crc; + UInt32 NumSubDirs; + UInt32 NumSubFiles; + bool CrcIsDefined; + + CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {} + ~CProxyDir() { delete [](wchar_t *)(void *)Name; } + + void Clear(); + bool IsLeaf() const { return ArcIndex != -1; } +}; + +class CProxyArc +{ + int FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const; + + void CalculateSizes(unsigned dirIndex, IInArchive *archive); + unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name); +public: + CObjectVector Dirs; // Dirs[0] - root + CObjArray Files; // all items from archive in same order + + // returns index in Dirs[], or -1, + int FindSubDir(unsigned dirIndex, const wchar_t *name) const; + + void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const; + // returns full path of Dirs[dirIndex], including back slash + UString GetDirPath_as_Prefix(unsigned dirIndex) const; + + // AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf) + void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const; + int GetRealIndex(unsigned dirIndex, unsigned index) const; + void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const; + + HRESULT Load(const CArc &arc, IProgress *progress); +}; + + +// ---------- for Tree-mode archive ---------- + +struct CProxyFile2 +{ + int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs) + int AltDirIndex; // >= 0 if there are alt streams. (index in ProxyArchive2->Dirs) + int Parent; // >= 0 if there is parent. (index in archive and in ProxyArchive2->Files) + const wchar_t *Name; + unsigned NameLen; + bool NeedDeleteName; + bool Ignore; + bool IsAltStream; + + int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; } + + bool IsDir() const { return DirIndex != -1; } + CProxyFile2(): + DirIndex(-1), AltDirIndex(-1), Parent(-1), + Name(NULL), NameLen(0), + NeedDeleteName(false), + Ignore(false), + IsAltStream(false) + {} + ~CProxyFile2() + { + if (NeedDeleteName) + delete [](wchar_t *)(void *)Name; + } +}; + +struct CProxyDir2 +{ + int ArcIndex; // = -1 for root folders, index in proxy->Files[] + CRecordVector Items; + UString PathPrefix; + UInt64 Size; + UInt64 PackSize; + bool CrcIsDefined; + UInt32 Crc; + UInt32 NumSubDirs; + UInt32 NumSubFiles; + + CProxyDir2(): ArcIndex(-1) {} + void AddFileSubItem(UInt32 index, const UString &name); + void Clear(); +}; + +const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex; +const unsigned k_Proxy2_AltRootDirIndex = 1; +const unsigned k_Proxy2_NumRootDirs = 2; + +class CProxyArc2 +{ + void CalculateSizes(unsigned dirIndex, IInArchive *archive); + // AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex + void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const; +public: + CObjectVector Dirs; // Dirs[0] - root folder + // Dirs[1] - for alt streams of root dir + CObjArray Files; // all items from archive in same order + + bool IsThere_SubDir(unsigned dirIndex, const UString &name) const; + + void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const; + UString GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const; + bool IsAltDir(unsigned dirIndex) const; + + // AddRealIndices_of_ArcItem DOES ADD item and subItems + void AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const; + unsigned GetRealIndex(unsigned dirIndex, unsigned index) const; + void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const; + + HRESULT Load(const CArc &arc, IProgress *progress); + + int GetParentDirOfFile(UInt32 arcIndex) const + { + const CProxyFile2 &file = Files[arcIndex]; + + if (file.Parent == -1) + return file.IsAltStream ? + k_Proxy2_AltRootDirIndex : + k_Proxy2_RootDirIndex; + + const CProxyFile2 &parentFile = Files[file.Parent]; + return file.IsAltStream ? + parentFile.AltDirIndex : + parentFile.DirIndex; + } + + int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const; +}; + +#endif diff --git a/CPP/7zip/UI/Agent/ArchiveFolder.cpp b/CPP/7zip/UI/Agent/ArchiveFolder.cpp index e58a4d848..eea681cf5 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolder.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp @@ -1,51 +1,57 @@ -// Agent/ArchiveFolder.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" - -#include "../Common/ArchiveExtractCallback.h" - -#include "Agent.h" - -/* -Z7_COM7F_IMF(CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode)) -{ - _replaceAltStreamCharsMode = replaceAltStreamCharsMode; - return S_OK; -} -*/ - -Z7_COM7F_IMF(CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)) -{ - _zoneMode = zoneMode; - return S_OK; -} - - -Z7_COM7F_IMF(CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, - Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, - const wchar_t *path, IFolderOperationsExtractCallback *callback)) -{ - if (moveMode) - return E_NOTIMPL; - COM_TRY_BEGIN - CMyComPtr extractCallback2; - { - CMyComPtr callbackWrap = callback; - RINOK(callbackWrap.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2)) - } - NExtract::NPathMode::EEnum pathMode; - if (!_flatMode) - pathMode = NExtract::NPathMode::kCurPaths; - else - pathMode = (_proxy2 && _loadAltStreams) ? - NExtract::NPathMode::kNoPathsAlt : - NExtract::NPathMode::kNoPaths; - - return Extract(indices, numItems, - includeAltStreams, replaceAltStreamCharsMode, - pathMode, NExtract::NOverwriteMode::kAsk, - path, BoolToInt(false), extractCallback2); - COM_TRY_END -} +// Agent/ArchiveFolder.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../Common/ArchiveExtractCallback.h" + +#include "Agent.h" + +/* +Z7_COM7F_IMF(CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode)) +{ + _replaceAltStreamCharsMode = replaceAltStreamCharsMode; + return S_OK; +} +*/ + +Z7_COM7F_IMF(CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)) +{ + _zoneMode = zoneMode; + return S_OK; +} + +Z7_COM7F_IMF(CAgentFolder::SetZoneIdFile(const Byte *data, UInt32 size)) +{ + _zoneBuf.CopyFrom(data, size); + return S_OK; +} + + +Z7_COM7F_IMF(CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, + Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, + const wchar_t *path, IFolderOperationsExtractCallback *callback)) +{ + if (moveMode) + return E_NOTIMPL; + COM_TRY_BEGIN + CMyComPtr extractCallback2; + { + CMyComPtr callbackWrap = callback; + RINOK(callbackWrap.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2)) + } + NExtract::NPathMode::EEnum pathMode; + if (!_flatMode) + pathMode = NExtract::NPathMode::kCurPaths; + else + pathMode = (_proxy2 && _loadAltStreams) ? + NExtract::NPathMode::kNoPathsAlt : + NExtract::NPathMode::kNoPaths; + + return Extract(indices, numItems, + includeAltStreams, replaceAltStreamCharsMode, + pathMode, NExtract::NOverwriteMode::kAsk, + path, BoolToInt(false), extractCallback2); + COM_TRY_END +} diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp index 5bd9eb238..3fa027ddb 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp @@ -1,231 +1,231 @@ -// Agent/ArchiveFolderOpen.cpp - -#include "StdAfx.h" - -// #ifdef NEW_FOLDER_INTERFACE - -#include "../../../Common/StringToInt.h" -#include "../../../Windows/DLL.h" -#include "../../../Windows/ResourceString.h" - -#include "Agent.h" - -extern HINSTANCE g_hInstance; -static const UINT kIconTypesResId = 100; - -void CCodecIcons::LoadIcons(HMODULE m) -{ - IconPairs.Clear(); - UString iconTypes; - NWindows::MyLoadString(m, kIconTypesResId, iconTypes); - UStringVector pairs; - SplitString(iconTypes, pairs); - FOR_VECTOR (i, pairs) - { - const UString &s = pairs[i]; - int pos = s.Find(L':'); - CIconPair iconPair; - iconPair.IconIndex = -1; - if (pos < 0) - pos = (int)s.Len(); - else - { - const UString num = s.Ptr((unsigned)pos + 1); - if (!num.IsEmpty()) - { - const wchar_t *end; - iconPair.IconIndex = (int)ConvertStringToUInt32(num, &end); - if (*end != 0) - continue; - } - } - iconPair.Ext = s.Left((unsigned)pos); - IconPairs.Add(iconPair); - } -} - -bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const -{ - iconIndex = -1; - FOR_VECTOR (i, IconPairs) - { - const CIconPair &pair = IconPairs[i]; - if (ext.IsEqualTo_NoCase(pair.Ext)) - { - iconIndex = pair.IconIndex; - return true; - } - } - return false; -} - - -void CArchiveFolderManager::LoadFormats() -{ - if (WasLoaded) - return; - - LoadGlobalCodecs(); - - #ifdef Z7_EXTERNAL_CODECS - CodecIconsVector.Clear(); - FOR_VECTOR (i, g_CodecsObj->Libs) - { - CCodecIcons &ci = CodecIconsVector.AddNew(); - ci.LoadIcons(g_CodecsObj->Libs[i].Lib.Get_HMODULE()); - } - #endif - InternalIcons.LoadIcons(g_hInstance); - WasLoaded = true; -} - -/* -int CArchiveFolderManager::FindFormat(const UString &type) -{ - FOR_VECTOR (i, g_CodecsObj->Formats) - if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name)) - return (int)i; - return -1; -} -*/ - -Z7_COM7F_IMF(CArchiveFolderManager::OpenFolderFile(IInStream *inStream, - const wchar_t *filePath, const wchar_t *arcFormat, - IFolderFolder **resultFolder, IProgress *progress)) -{ - CMyComPtr openArchiveCallback; - if (progress) - { - CMyComPtr progressWrapper = progress; - progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback); - } - CAgent *agent = new CAgent(); - CMyComPtr archive = agent; - - const HRESULT res = archive->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback); - - if (res != S_OK) - { - if (res != S_FALSE) - return res; - /* 20.01: we create folder even for Non-Open cases, if there is NonOpen_ErrorInfo information. - So we can get error information from that IFolderFolder later. */ - if (!agent->_archiveLink.NonOpen_ErrorInfo.IsThereErrorOrWarning()) - return res; - } - - RINOK(archive->BindToRootFolder(resultFolder)) - return res; -} - -/* -HRESULT CAgent::FolderReOpen( - IArchiveOpenCallback *openArchiveCallback) -{ - return ReOpenArchive(_archive, _archiveFilePath); -} -*/ - - -/* -Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(const wchar_t *type, BSTR *extensions)) -{ - *extensions = 0; - int formatIndex = FindFormat(type); - if (formatIndex < 0) - return E_INVALIDARG; - // Exts[0].Ext; - return StringToBstr(g_CodecsObj.Formats[formatIndex].GetAllExtensions(), extensions); -} -*/ - -static void AddIconExt(const CCodecIcons &lib, UString &dest) -{ - FOR_VECTOR (i, lib.IconPairs) - { - dest.Add_Space_if_NotEmpty(); - dest += lib.IconPairs[i].Ext; - } -} - - -Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(BSTR *extensions)) -{ - *extensions = NULL; - LoadFormats(); - UString res; - - #ifdef Z7_EXTERNAL_CODECS - /* - FOR_VECTOR (i, g_CodecsObj->Libs) - AddIconExt(g_CodecsObj->Libs[i].CodecIcons, res); - */ - FOR_VECTOR (i, CodecIconsVector) - AddIconExt(CodecIconsVector[i], res); - #endif - - AddIconExt( - // g_CodecsObj-> - InternalIcons, res); - - return StringToBstr(res, extensions); -} - - -Z7_COM7F_IMF(CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex)) -{ - *iconPath = NULL; - *iconIndex = 0; - LoadFormats(); - - #ifdef Z7_EXTERNAL_CODECS - // FOR_VECTOR (i, g_CodecsObj->Libs) - FOR_VECTOR (i, CodecIconsVector) - { - int ii; - if (CodecIconsVector[i].FindIconIndex(ext, ii)) - { - const CCodecLib &lib = g_CodecsObj->Libs[i]; - *iconIndex = ii; - return StringToBstr(fs2us(lib.Path), iconPath); - } - } - #endif - - int ii; - if (InternalIcons.FindIconIndex(ext, ii)) - { - FString path; - if (NWindows::NDLL::MyGetModuleFileName(path)) - { - *iconIndex = ii; - return StringToBstr(fs2us(path), iconPath); - } - } - return S_OK; -} - -/* -Z7_COM7F_IMF(CArchiveFolderManager::GetTypes(BSTR *types)) -{ - LoadFormats(); - UString typesStrings; - FOR_VECTOR(i, g_CodecsObj.Formats) - { - const CArcInfoEx &ai = g_CodecsObj.Formats[i]; - if (ai.AssociateExts.Size() == 0) - continue; - if (i != 0) - typesStrings.Add_Space(); - typesStrings += ai.Name; - } - return StringToBstr(typesStrings, types); -} -Z7_COM7F_IMF(CArchiveFolderManager::CreateFolderFile(const wchar_t * type, - const wchar_t * filePath, IProgress progress)) -{ - return E_NOTIMPL; -} -*/ - -// #endif +// Agent/ArchiveFolderOpen.cpp + +#include "StdAfx.h" + +// #ifdef NEW_FOLDER_INTERFACE + +#include "../../../Common/StringToInt.h" +#include "../../../Windows/DLL.h" +#include "../../../Windows/ResourceString.h" + +#include "Agent.h" + +extern HINSTANCE g_hInstance; +static const UINT kIconTypesResId = 100; + +void CCodecIcons::LoadIcons(HMODULE m) +{ + IconPairs.Clear(); + UString iconTypes; + NWindows::MyLoadString(m, kIconTypesResId, iconTypes); + UStringVector pairs; + SplitString(iconTypes, pairs); + FOR_VECTOR (i, pairs) + { + const UString &s = pairs[i]; + int pos = s.Find(L':'); + CIconPair iconPair; + iconPair.IconIndex = -1; + if (pos < 0) + pos = (int)s.Len(); + else + { + const UString num = s.Ptr((unsigned)pos + 1); + if (!num.IsEmpty()) + { + const wchar_t *end; + iconPair.IconIndex = (int)ConvertStringToUInt32(num, &end); + if (*end != 0) + continue; + } + } + iconPair.Ext = s.Left((unsigned)pos); + IconPairs.Add(iconPair); + } +} + +bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const +{ + iconIndex = -1; + FOR_VECTOR (i, IconPairs) + { + const CIconPair &pair = IconPairs[i]; + if (ext.IsEqualTo_NoCase(pair.Ext)) + { + iconIndex = pair.IconIndex; + return true; + } + } + return false; +} + + +void CArchiveFolderManager::LoadFormats() +{ + if (WasLoaded) + return; + + LoadGlobalCodecs(); + + #ifdef Z7_EXTERNAL_CODECS + CodecIconsVector.Clear(); + FOR_VECTOR (i, g_CodecsObj->Libs) + { + CCodecIcons &ci = CodecIconsVector.AddNew(); + ci.LoadIcons(g_CodecsObj->Libs[i].Lib.Get_HMODULE()); + } + #endif + InternalIcons.LoadIcons(g_hInstance); + WasLoaded = true; +} + +/* +int CArchiveFolderManager::FindFormat(const UString &type) +{ + FOR_VECTOR (i, g_CodecsObj->Formats) + if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name)) + return (int)i; + return -1; +} +*/ + +Z7_COM7F_IMF(CArchiveFolderManager::OpenFolderFile(IInStream *inStream, + const wchar_t *filePath, const wchar_t *arcFormat, + IFolderFolder **resultFolder, IProgress *progress)) +{ + CMyComPtr openArchiveCallback; + if (progress) + { + CMyComPtr progressWrapper = progress; + progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback); + } + CAgent *agent = new CAgent(); + CMyComPtr archive = agent; + + const HRESULT res = archive->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback); + + if (res != S_OK) + { + if (res != S_FALSE) + return res; + /* 20.01: we create folder even for Non-Open cases, if there is NonOpen_ErrorInfo information. + So we can get error information from that IFolderFolder later. */ + if (!agent->_archiveLink.NonOpen_ErrorInfo.IsThereErrorOrWarning()) + return res; + } + + RINOK(archive->BindToRootFolder(resultFolder)) + return res; +} + +/* +HRESULT CAgent::FolderReOpen( + IArchiveOpenCallback *openArchiveCallback) +{ + return ReOpenArchive(_archive, _archiveFilePath); +} +*/ + + +/* +Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(const wchar_t *type, BSTR *extensions)) +{ + *extensions = 0; + int formatIndex = FindFormat(type); + if (formatIndex < 0) + return E_INVALIDARG; + // Exts[0].Ext; + return StringToBstr(g_CodecsObj.Formats[formatIndex].GetAllExtensions(), extensions); +} +*/ + +static void AddIconExt(const CCodecIcons &lib, UString &dest) +{ + FOR_VECTOR (i, lib.IconPairs) + { + dest.Add_Space_if_NotEmpty(); + dest += lib.IconPairs[i].Ext; + } +} + + +Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(BSTR *extensions)) +{ + *extensions = NULL; + LoadFormats(); + UString res; + + #ifdef Z7_EXTERNAL_CODECS + /* + FOR_VECTOR (i, g_CodecsObj->Libs) + AddIconExt(g_CodecsObj->Libs[i].CodecIcons, res); + */ + FOR_VECTOR (i, CodecIconsVector) + AddIconExt(CodecIconsVector[i], res); + #endif + + AddIconExt( + // g_CodecsObj-> + InternalIcons, res); + + return StringToBstr(res, extensions); +} + + +Z7_COM7F_IMF(CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex)) +{ + *iconPath = NULL; + *iconIndex = 0; + LoadFormats(); + + #ifdef Z7_EXTERNAL_CODECS + // FOR_VECTOR (i, g_CodecsObj->Libs) + FOR_VECTOR (i, CodecIconsVector) + { + int ii; + if (CodecIconsVector[i].FindIconIndex(ext, ii)) + { + const CCodecLib &lib = g_CodecsObj->Libs[i]; + *iconIndex = ii; + return StringToBstr(fs2us(lib.Path), iconPath); + } + } + #endif + + int ii; + if (InternalIcons.FindIconIndex(ext, ii)) + { + FString path; + if (NWindows::NDLL::MyGetModuleFileName(path)) + { + *iconIndex = ii; + return StringToBstr(fs2us(path), iconPath); + } + } + return S_OK; +} + +/* +Z7_COM7F_IMF(CArchiveFolderManager::GetTypes(BSTR *types)) +{ + LoadFormats(); + UString typesStrings; + FOR_VECTOR(i, g_CodecsObj.Formats) + { + const CArcInfoEx &ai = g_CodecsObj.Formats[i]; + if (ai.AssociateExts.Size() == 0) + continue; + if (i != 0) + typesStrings.Add_Space(); + typesStrings += ai.Name; + } + return StringToBstr(typesStrings, types); +} +Z7_COM7F_IMF(CArchiveFolderManager::CreateFolderFile(const wchar_t * type, + const wchar_t * filePath, IProgress progress)) +{ + return E_NOTIMPL; +} +*/ + +// #endif diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp index d1495d233..1da660157 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp @@ -1,386 +1,456 @@ -// ArchiveFolderOut.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" - -#include "../../../Windows/FileDir.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/LimitedStreams.h" - -#include "../../Compress/CopyCoder.h" - -#include "../Common/WorkDir.h" - -#include "Agent.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder) -{ - if (_proxy2) - _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); - else - _proxy->GetDirPathParts(_proxyDirIndex, pathParts); -} - -static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path) -{ - { - const FString pathPrefix = path + FCHAR_PATH_SEPARATOR; - CObjectVector names; - { - NFind::CDirEntry fileInfo; - NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(pathPrefix); - for (;;) - { - bool found; - if (!enumerator.Next(fileInfo, found)) - return false; - if (!found) - break; - if (fileInfo.IsDir()) - names.Add(fileInfo.Name); - } - } - bool res = true; - FOR_VECTOR (i, names) - { - if (!Delete_EmptyFolder_And_EmptySubFolders(pathPrefix + names[i])) - res = false; - } - if (!res) - return false; - } - // we clear read-only attrib to remove read-only dir - if (!SetFileAttrib(path, 0)) - return false; - return RemoveDir(path); -} - -HRESULT CAgentFolder::CommonUpdateOperation( - AGENT_OP operation, - bool moveMode, - const wchar_t *newItemName, - const NUpdateArchive::CActionSet *actionSet, - const UInt32 *indices, UInt32 numItems, - IProgress *progress) -{ - if (moveMode && _agentSpec->_isHashHandler) - return E_NOTIMPL; - - if (!_agentSpec->CanUpdate()) - return E_NOTIMPL; - - CMyComPtr updateCallback100; - if (progress) - progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100); - - try - { - - RINOK(_agentSpec->SetFolder(this)) - - // ---------- Save FolderItem ---------- - - UStringVector pathParts; - bool isAltStreamFolder = false; - GetPathParts(pathParts, isAltStreamFolder); - - FStringVector requestedPaths; - FStringVector processedPaths; - - CWorkDirTempFile tempFile; - RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath))) - { - CMyComPtr tailStream; - const CArc &arc = *_agentSpec->_archiveLink.GetArc(); - - if (arc.ArcStreamOffset == 0) - tailStream = tempFile.OutStream; - else - { - if (arc.Offset < 0) - return E_NOTIMPL; - RINOK(arc.InStream->Seek(0, STREAM_SEEK_SET, NULL)) - RINOK(NCompress::CopyStream_ExactSize(arc.InStream, tempFile.OutStream, arc.ArcStreamOffset, NULL)) - CTailOutStream *tailStreamSpec = new CTailOutStream; - tailStream = tailStreamSpec; - tailStreamSpec->Stream = tempFile.OutStream; - tailStreamSpec->Offset = arc.ArcStreamOffset; - tailStreamSpec->Init(); - } - - HRESULT result; - - switch ((int)operation) - { - case AGENT_OP_Delete: - result = _agentSpec->DeleteItems(tailStream, indices, numItems, updateCallback100); - break; - case AGENT_OP_CreateFolder: - result = _agentSpec->CreateFolder(tailStream, newItemName, updateCallback100); - break; - case AGENT_OP_Rename: - result = _agentSpec->RenameItem(tailStream, indices, numItems, newItemName, updateCallback100); - break; - case AGENT_OP_Comment: - result = _agentSpec->CommentItem(tailStream, indices, numItems, newItemName, updateCallback100); - break; - case AGENT_OP_CopyFromFile: - result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100); - break; - case AGENT_OP_Uni: - { - Byte actionSetByte[NUpdateArchive::NPairState::kNumValues]; - for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) - actionSetByte[i] = (Byte)actionSet->StateActions[i]; - result = _agentSpec->DoOperation2( - moveMode ? &requestedPaths : NULL, - moveMode ? &processedPaths : NULL, - tailStream, actionSetByte, NULL, updateCallback100); - break; - } - default: - return E_FAIL; - } - - RINOK(result) - } - - _agentSpec->KeepModeForNextOpen(); - _agent->Close(); - - // before 9.26: if there was error for MoveToOriginal archive was closed. - // now: we reopen archive after close - - // m_FolderItem = NULL; - - const HRESULT res = tempFile.MoveToOriginal(true); - - // RINOK(res); - if (res == S_OK) - { - if (moveMode) - { - unsigned i; - for (i = 0; i < processedPaths.Size(); i++) - { - DeleteFileAlways(processedPaths[i]); - } - for (i = 0; i < requestedPaths.Size(); i++) - { - const FString &fs = requestedPaths[i]; - if (NFind::DoesDirExist(fs)) - Delete_EmptyFolder_And_EmptySubFolders(fs); - } - } - } - - { - CMyComPtr openCallback; - if (updateCallback100) - updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback); - RINOK(_agent->ReOpen(openCallback)) - } - - // CAgent::ReOpen() deletes _proxy and _proxy2 - _items.Clear(); - _proxy = NULL; - _proxy2 = NULL; - _proxyDirIndex = k_Proxy_RootDirIndex; - _isAltStreamFolder = false; - - - // ---------- Restore FolderItem ---------- - - CMyComPtr archiveFolder; - RINOK(_agent->BindToRootFolder(&archiveFolder)) - - // CAgent::BindToRootFolder() changes _proxy and _proxy2 - _proxy = _agentSpec->_proxy; - _proxy2 = _agentSpec->_proxy2; - - if (_proxy) - { - FOR_VECTOR (i, pathParts) - { - const int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]); - if (next == -1) - break; - _proxyDirIndex = (unsigned)next; - } - } - - if (_proxy2) - { - if (pathParts.IsEmpty() && isAltStreamFolder) - { - _proxyDirIndex = k_Proxy2_AltRootDirIndex; - } - else FOR_VECTOR (i, pathParts) - { - const bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder); - const int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly); - if (index == -1) - break; - - const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]]; - - if (dirOnly) - _proxyDirIndex = (unsigned)file.DirIndex; - else - { - if (file.AltDirIndex != -1) - _proxyDirIndex = (unsigned)file.AltDirIndex; - break; - } - } - } - - /* - if (pathParts.IsEmpty() && isAltStreamFolder) - { - CMyComPtr folderAltStreams; - archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams); - if (folderAltStreams) - { - CMyComPtr newFolder; - folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder); - if (newFolder) - archiveFolder = newFolder; - } - } - - FOR_VECTOR (i, pathParts) - { - CMyComPtr newFolder; - - if (isAltStreamFolder && i == pathParts.Size() - 1) - { - CMyComPtr folderAltStreams; - archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams); - if (folderAltStreams) - folderAltStreams->BindToAltStreams(pathParts[i], &newFolder); - } - else - archiveFolder->BindToFolder(pathParts[i], &newFolder); - - if (!newFolder) - break; - archiveFolder = newFolder; - } - - CMyComPtr archiveFolderInternal; - RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal)); - CAgentFolder *agentFolder; - RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder)); - _proxyDirIndex = agentFolder->_proxyDirIndex; - // _parentFolder = agentFolder->_parentFolder; - */ - - if (_proxy2) - _isAltStreamFolder = _proxy2->IsAltDir(_proxyDirIndex); - - return res; - - } - catch(const UString &s) - { - if (updateCallback100) - { - UString s2 ("Error: "); - s2 += s; - RINOK(updateCallback100->UpdateErrorMessage(s2)) - return E_FAIL; - } - throw; - } -} - - -Z7_COM7F_IMF(CAgentFolder::CopyFrom(Int32 moveMode, - const wchar_t *fromFolderPath, /* test it */ - const wchar_t * const *itemsPaths, - UInt32 numItems, - IProgress *progress)) -{ - COM_TRY_BEGIN - { - RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems)) - return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL, - &NUpdateArchive::k_ActionSet_Add, - NULL, 0, progress); - } - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress *progress)) -{ - COM_TRY_BEGIN - return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath, - &NUpdateArchive::k_ActionSet_Add, - &destIndex, 1, progress); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress)) -{ - COM_TRY_BEGIN - return CommonUpdateOperation(AGENT_OP_Delete, false, NULL, - &NUpdateArchive::k_ActionSet_Delete, indices, numItems, progress); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress)) -{ - COM_TRY_BEGIN - - if (_isAltStreamFolder) - return E_NOTIMPL; - - if (_proxy2) - { - if (_proxy2->IsThere_SubDir(_proxyDirIndex, name)) - return ERROR_ALREADY_EXISTS; - } - else - { - if (_proxy->FindSubDir(_proxyDirIndex, name) != -1) - return ERROR_ALREADY_EXISTS; - } - - return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) -{ - COM_TRY_BEGIN - return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL, - &index, 1, progress); - COM_TRY_END -} - -Z7_COM7F_IMF(CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CAgentFolder::SetProperty(UInt32 index, PROPID propID, - const PROPVARIANT *value, IProgress *progress)) -{ - COM_TRY_BEGIN - if (propID != kpidComment || value->vt != VT_BSTR) - return E_NOTIMPL; - if (!_agentSpec || !_agentSpec->GetTypeOfArc(_agentSpec->GetArc()).IsEqualTo_Ascii_NoCase("zip")) - return E_NOTIMPL; - - return CommonUpdateOperation(AGENT_OP_Comment, false, value->bstrVal, NULL, - &index, 1, progress); - COM_TRY_END -} +// ArchiveFolderOut.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/FileDir.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/WorkDir.h" + +#include "Agent.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder) +{ + if (_proxy2) + _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); + else + _proxy->GetDirPathParts(_proxyDirIndex, pathParts); +} + +static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path) +{ + { + const FString pathPrefix = path + FCHAR_PATH_SEPARATOR; + CObjectVector names; + { + NFind::CDirEntry fileInfo; + NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(pathPrefix); + for (;;) + { + bool found; + if (!enumerator.Next(fileInfo, found)) + return false; + if (!found) + break; + if (fileInfo.IsDir()) + names.Add(fileInfo.Name); + } + } + bool res = true; + FOR_VECTOR (i, names) + { + if (!Delete_EmptyFolder_And_EmptySubFolders(pathPrefix + names[i])) + res = false; + } + if (!res) + return false; + } + // we clear read-only attrib to remove read-only dir + if (!SetFileAttrib(path, 0)) + return false; + return RemoveDir(path); +} + + + +struct C_CopyFileProgress_to_FolderCallback_MoveArc Z7_final: + public ICopyFileProgress +{ + IFolderArchiveUpdateCallback_MoveArc *Callback; + HRESULT CallbackResult; + + virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) Z7_override + { + HRESULT res = Callback->MoveArc_Progress(total, current); + CallbackResult = res; + // we can ignore E_ABORT here, because we update archive, + // and we want to get correct archive after updating + if (res == E_ABORT) + res = S_OK; + return res == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL; + } + + C_CopyFileProgress_to_FolderCallback_MoveArc( + IFolderArchiveUpdateCallback_MoveArc *callback) : + Callback(callback), + CallbackResult(S_OK) + {} +}; + + +HRESULT CAgentFolder::CommonUpdateOperation( + AGENT_OP operation, + bool moveMode, + const wchar_t *newItemName, + const NUpdateArchive::CActionSet *actionSet, + const UInt32 *indices, UInt32 numItems, + IProgress *progress) +{ + if (moveMode && _agentSpec->_isHashHandler) + return E_NOTIMPL; + + if (!_agentSpec->CanUpdate()) + return E_NOTIMPL; + + CMyComPtr updateCallback100; + if (progress) + progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100); + + try + { + + RINOK(_agentSpec->SetFolder(this)) + + // ---------- Save FolderItem ---------- + + UStringVector pathParts; + bool isAltStreamFolder = false; + GetPathParts(pathParts, isAltStreamFolder); + + FStringVector requestedPaths; + FStringVector processedPaths; + + CWorkDirTempFile tempFile; + RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath))) + { + CMyComPtr tailStream; + const CArc &arc = *_agentSpec->_archiveLink.GetArc(); + + if (arc.ArcStreamOffset == 0) + tailStream = tempFile.OutStream; + else + { + if (arc.Offset < 0) + return E_NOTIMPL; + RINOK(arc.InStream->Seek(0, STREAM_SEEK_SET, NULL)) + RINOK(NCompress::CopyStream_ExactSize(arc.InStream, tempFile.OutStream, arc.ArcStreamOffset, NULL)) + CTailOutStream *tailStreamSpec = new CTailOutStream; + tailStream = tailStreamSpec; + tailStreamSpec->Stream = tempFile.OutStream; + tailStreamSpec->Offset = arc.ArcStreamOffset; + tailStreamSpec->Init(); + } + + HRESULT result; + + switch ((int)operation) + { + case AGENT_OP_Delete: + result = _agentSpec->DeleteItems(tailStream, indices, numItems, updateCallback100); + break; + case AGENT_OP_CreateFolder: + result = _agentSpec->CreateFolder(tailStream, newItemName, updateCallback100); + break; + case AGENT_OP_Rename: + result = _agentSpec->RenameItem(tailStream, indices, numItems, newItemName, updateCallback100); + break; + case AGENT_OP_Comment: + result = _agentSpec->CommentItem(tailStream, indices, numItems, newItemName, updateCallback100); + break; + case AGENT_OP_CopyFromFile: + result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100); + break; + case AGENT_OP_Uni: + { + Byte actionSetByte[NUpdateArchive::NPairState::kNumValues]; + for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) + actionSetByte[i] = (Byte)actionSet->StateActions[i]; + result = _agentSpec->DoOperation2( + moveMode ? &requestedPaths : NULL, + moveMode ? &processedPaths : NULL, + tailStream, actionSetByte, NULL, updateCallback100); + break; + } + default: + return E_FAIL; + } + + RINOK(result) + } + + _agentSpec->KeepModeForNextOpen(); + _agent->Close(); + + // before 9.26: if there was error for MoveToOriginal archive was closed. + // now: we reopen archive after close + + // m_FolderItem = NULL; + _items.Clear(); + _proxyDirIndex = k_Proxy_RootDirIndex; + + CMyComPtr updateCallback_MoveArc; + if (progress) + progress->QueryInterface(IID_IFolderArchiveUpdateCallback_MoveArc, (void **)&updateCallback_MoveArc); + + HRESULT res; + if (updateCallback_MoveArc) + { + const FString &tempFilePath = tempFile.Get_TempFilePath(); + UInt64 totalSize = 0; + { + NFind::CFileInfo fi; + if (fi.Find(tempFilePath)) + totalSize = fi.Size; + } + RINOK(updateCallback_MoveArc->MoveArc_Start( + fs2us(tempFilePath), + fs2us(tempFile.Get_OriginalFilePath()), + totalSize, + 1)) // updateMode + + C_CopyFileProgress_to_FolderCallback_MoveArc prox(updateCallback_MoveArc); + res = tempFile.MoveToOriginal( + true, // deleteOriginal + &prox); + if (res == S_OK) + { + res = updateCallback_MoveArc->MoveArc_Finish(); + // we don't return after E_ABORT here, because + // we want to reopen new archive still. + } + else if (prox.CallbackResult != S_OK) + res = prox.CallbackResult; + + // if updating callback returned E_ABORT, + // then openCallback still can return E_ABORT also. + // So ReOpen() will return with E_ABORT. + // But we want to open archive still. + // And Before_ArcReopen() call will clear user break status in that case. + RINOK(updateCallback_MoveArc->Before_ArcReopen()) + } + else + res = tempFile.MoveToOriginal(true); // deleteOriginal + + // RINOK(res); + if (res == S_OK) + { + if (moveMode) + { + unsigned i; + for (i = 0; i < processedPaths.Size(); i++) + { + DeleteFileAlways(processedPaths[i]); + } + for (i = 0; i < requestedPaths.Size(); i++) + { + const FString &fs = requestedPaths[i]; + if (NFind::DoesDirExist(fs)) + Delete_EmptyFolder_And_EmptySubFolders(fs); + } + } + } + + { + CMyComPtr openCallback; + if (updateCallback100) + updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback); + RINOK(_agent->ReOpen(openCallback)) + } + + // CAgent::ReOpen() deletes _proxy and _proxy2 + // _items.Clear(); + _proxy = NULL; + _proxy2 = NULL; + // _proxyDirIndex = k_Proxy_RootDirIndex; + _isAltStreamFolder = false; + + + // ---------- Restore FolderItem ---------- + + CMyComPtr archiveFolder; + RINOK(_agent->BindToRootFolder(&archiveFolder)) + + // CAgent::BindToRootFolder() changes _proxy and _proxy2 + _proxy = _agentSpec->_proxy; + _proxy2 = _agentSpec->_proxy2; + + if (_proxy) + { + FOR_VECTOR (i, pathParts) + { + const int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]); + if (next == -1) + break; + _proxyDirIndex = (unsigned)next; + } + } + + if (_proxy2) + { + if (pathParts.IsEmpty() && isAltStreamFolder) + { + _proxyDirIndex = k_Proxy2_AltRootDirIndex; + } + else FOR_VECTOR (i, pathParts) + { + const bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder); + const int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly); + if (index == -1) + break; + + const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]]; + + if (dirOnly) + _proxyDirIndex = (unsigned)file.DirIndex; + else + { + if (file.AltDirIndex != -1) + _proxyDirIndex = (unsigned)file.AltDirIndex; + break; + } + } + } + + /* + if (pathParts.IsEmpty() && isAltStreamFolder) + { + CMyComPtr folderAltStreams; + archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams); + if (folderAltStreams) + { + CMyComPtr newFolder; + folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder); + if (newFolder) + archiveFolder = newFolder; + } + } + + FOR_VECTOR (i, pathParts) + { + CMyComPtr newFolder; + + if (isAltStreamFolder && i == pathParts.Size() - 1) + { + CMyComPtr folderAltStreams; + archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams); + if (folderAltStreams) + folderAltStreams->BindToAltStreams(pathParts[i], &newFolder); + } + else + archiveFolder->BindToFolder(pathParts[i], &newFolder); + + if (!newFolder) + break; + archiveFolder = newFolder; + } + + CMyComPtr archiveFolderInternal; + RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal)); + CAgentFolder *agentFolder; + RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder)); + _proxyDirIndex = agentFolder->_proxyDirIndex; + // _parentFolder = agentFolder->_parentFolder; + */ + + if (_proxy2) + _isAltStreamFolder = _proxy2->IsAltDir(_proxyDirIndex); + + return res; + + } + catch(const UString &s) + { + if (updateCallback100) + { + UString s2 ("Error: "); + s2 += s; + RINOK(updateCallback100->UpdateErrorMessage(s2)) + return E_FAIL; + } + throw; + } +} + + +Z7_COM7F_IMF(CAgentFolder::CopyFrom(Int32 moveMode, + const wchar_t *fromFolderPath, /* test it */ + const wchar_t * const *itemsPaths, + UInt32 numItems, + IProgress *progress)) +{ + COM_TRY_BEGIN + { + RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems)) + return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL, + &NUpdateArchive::k_ActionSet_Add, + NULL, 0, progress); + } + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress *progress)) +{ + COM_TRY_BEGIN + return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath, + &NUpdateArchive::k_ActionSet_Add, + &destIndex, 1, progress); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress)) +{ + COM_TRY_BEGIN + return CommonUpdateOperation(AGENT_OP_Delete, false, NULL, + &NUpdateArchive::k_ActionSet_Delete, indices, numItems, progress); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress)) +{ + COM_TRY_BEGIN + + if (_isAltStreamFolder) + return E_NOTIMPL; + + if (_proxy2) + { + if (_proxy2->IsThere_SubDir(_proxyDirIndex, name)) + return ERROR_ALREADY_EXISTS; + } + else + { + if (_proxy->FindSubDir(_proxyDirIndex, name) != -1) + return ERROR_ALREADY_EXISTS; + } + + return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) +{ + COM_TRY_BEGIN + return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL, + &index, 1, progress); + COM_TRY_END +} + +Z7_COM7F_IMF(CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CAgentFolder::SetProperty(UInt32 index, PROPID propID, + const PROPVARIANT *value, IProgress *progress)) +{ + COM_TRY_BEGIN + if (propID != kpidComment || value->vt != VT_BSTR) + return E_NOTIMPL; + if (!_agentSpec || !_agentSpec->GetTypeOfArc(_agentSpec->GetArc()).IsEqualTo_Ascii_NoCase("zip")) + return E_NOTIMPL; + + return CommonUpdateOperation(AGENT_OP_Comment, false, value->bstrVal, NULL, + &index, 1, progress); + COM_TRY_END +} diff --git a/CPP/7zip/UI/Agent/IFolderArchive.h b/CPP/7zip/UI/Agent/IFolderArchive.h index f930c7741..12b900fc5 100644 --- a/CPP/7zip/UI/Agent/IFolderArchive.h +++ b/CPP/7zip/UI/Agent/IFolderArchive.h @@ -1,107 +1,123 @@ -// IFolderArchive.h - -#ifndef ZIP7_INC_IFOLDER_ARCHIVE_H -#define ZIP7_INC_IFOLDER_ARCHIVE_H - -#include "../../../Common/MyString.h" - -#include "../../Archive/IArchive.h" -#include "../../UI/Common/LoadCodecs.h" -#include "../../UI/FileManager/IFolder.h" - -#include "../Common/ExtractMode.h" -#include "../Common/IFileExtractCallback.h" - -Z7_PURE_INTERFACES_BEGIN - -/* ---------- IArchiveFolder ---------- -IArchiveFolder is implemented by CAgentFolder (Agent/Agent.h) -IArchiveFolder is used by: - - FileManager/PanelCopy.cpp - CPanel::CopyTo(), if (options->testMode) - - FAR/PluginRead.cpp - CPlugin::ExtractFiles -*/ - -#define Z7_IFACEM_IArchiveFolder(x) \ - x(Extract(const UInt32 *indices, UInt32 numItems, \ - Int32 includeAltStreams, \ - Int32 replaceAltStreamCharsMode, \ - NExtract::NPathMode::EEnum pathMode, \ - NExtract::NOverwriteMode::EEnum overwriteMode, \ - const wchar_t *path, Int32 testMode, \ - IFolderArchiveExtractCallback *extractCallback2)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolder, 0x0D) - - -/* ---------- IInFolderArchive ---------- -IInFolderArchive is implemented by CAgent (Agent/Agent.h) -IInFolderArchive Is used by FAR/Plugin -*/ - -#define Z7_IFACEM_IInFolderArchive(x) \ - x(Open(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback)) \ - x(ReOpen(IArchiveOpenCallback *openArchiveCallback)) \ - x(Close()) \ - x(GetNumberOfProperties(UInt32 *numProperties)) \ - x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - x(BindToRootFolder(IFolderFolder **resultFolder)) \ - x(Extract(NExtract::NPathMode::EEnum pathMode, \ - NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \ - Int32 testMode, IFolderArchiveExtractCallback *extractCallback2)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IInFolderArchive, 0x0E) - -#define Z7_IFACEM_IFolderArchiveUpdateCallback(x) \ - x(CompressOperation(const wchar_t *name)) \ - x(DeleteOperation(const wchar_t *name)) \ - x(OperationResult(Int32 opRes)) \ - x(UpdateErrorMessage(const wchar_t *message)) \ - x(SetNumFiles(UInt64 numFiles)) \ - -Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B) - -#define Z7_IFACEM_IOutFolderArchive(x) \ - x(SetFolder(IFolderFolder *folder)) \ - x(SetFiles(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames)) \ - x(DeleteItems(ISequentialOutStream *outArchiveStream, \ - const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback)) \ - x(DoOperation( \ - FStringVector *requestedPaths, \ - FStringVector *processedPaths, \ - CCodecs *codecs, int index, \ - ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ - IFolderArchiveUpdateCallback *updateCallback)) \ - x(DoOperation2( \ - FStringVector *requestedPaths, \ - FStringVector *processedPaths, \ - ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ - IFolderArchiveUpdateCallback *updateCallback)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IOutFolderArchive, 0x0F) - - -#define Z7_IFACEM_IFolderArchiveUpdateCallback2(x) \ - x(OpenFileError(const wchar_t *path, HRESULT errorCode)) \ - x(ReadingFileError(const wchar_t *path, HRESULT errorCode)) \ - x(ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *path)) \ - x(ReportUpdateOperation(UInt32 notifyOp, const wchar_t *path, Int32 isDir)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback2, 0x10) - - -#define Z7_IFACEM_IFolderScanProgress(x) \ - x(ScanError(const wchar_t *path, HRESULT errorCode)) \ - x(ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IFolderScanProgress, 0x11) - - -#define Z7_IFACEM_IFolderSetZoneIdMode(x) \ - x(SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdMode, 0x12) - -Z7_PURE_INTERFACES_END -#endif +// IFolderArchive.h + +#ifndef ZIP7_INC_IFOLDER_ARCHIVE_H +#define ZIP7_INC_IFOLDER_ARCHIVE_H + +#include "../../../Common/MyString.h" + +#include "../../Archive/IArchive.h" +#include "../../UI/Common/LoadCodecs.h" +#include "../../UI/FileManager/IFolder.h" + +#include "../Common/ExtractMode.h" +#include "../Common/IFileExtractCallback.h" + +Z7_PURE_INTERFACES_BEGIN + +/* ---------- IArchiveFolder ---------- +IArchiveFolder is implemented by CAgentFolder (Agent/Agent.h) +IArchiveFolder is used by: + - FileManager/PanelCopy.cpp + CPanel::CopyTo(), if (options->testMode) + - FAR/PluginRead.cpp + CPlugin::ExtractFiles +*/ + +#define Z7_IFACEM_IArchiveFolder(x) \ + x(Extract(const UInt32 *indices, UInt32 numItems, \ + Int32 includeAltStreams, \ + Int32 replaceAltStreamCharsMode, \ + NExtract::NPathMode::EEnum pathMode, \ + NExtract::NOverwriteMode::EEnum overwriteMode, \ + const wchar_t *path, Int32 testMode, \ + IFolderArchiveExtractCallback *extractCallback2)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolder, 0x0D) + + +/* ---------- IInFolderArchive ---------- +IInFolderArchive is implemented by CAgent (Agent/Agent.h) +IInFolderArchive Is used by FAR/Plugin +*/ + +#define Z7_IFACEM_IInFolderArchive(x) \ + x(Open(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback)) \ + x(ReOpen(IArchiveOpenCallback *openArchiveCallback)) \ + x(Close()) \ + x(GetNumberOfProperties(UInt32 *numProperties)) \ + x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(BindToRootFolder(IFolderFolder **resultFolder)) \ + x(Extract(NExtract::NPathMode::EEnum pathMode, \ + NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \ + Int32 testMode, IFolderArchiveExtractCallback *extractCallback2)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IInFolderArchive, 0x0E) + +#define Z7_IFACEM_IFolderArchiveUpdateCallback(x) \ + x(CompressOperation(const wchar_t *name)) \ + x(DeleteOperation(const wchar_t *name)) \ + x(OperationResult(Int32 opRes)) \ + x(UpdateErrorMessage(const wchar_t *message)) \ + x(SetNumFiles(UInt64 numFiles)) \ + +Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B) + +#define Z7_IFACEM_IOutFolderArchive(x) \ + x(SetFolder(IFolderFolder *folder)) \ + x(SetFiles(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames)) \ + x(DeleteItems(ISequentialOutStream *outArchiveStream, \ + const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback)) \ + x(DoOperation( \ + FStringVector *requestedPaths, \ + FStringVector *processedPaths, \ + CCodecs *codecs, int index, \ + ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ + IFolderArchiveUpdateCallback *updateCallback)) \ + x(DoOperation2( \ + FStringVector *requestedPaths, \ + FStringVector *processedPaths, \ + ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \ + IFolderArchiveUpdateCallback *updateCallback)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IOutFolderArchive, 0x0F) + + +#define Z7_IFACEM_IFolderArchiveUpdateCallback2(x) \ + x(OpenFileError(const wchar_t *path, HRESULT errorCode)) \ + x(ReadingFileError(const wchar_t *path, HRESULT errorCode)) \ + x(ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *path)) \ + x(ReportUpdateOperation(UInt32 notifyOp, const wchar_t *path, Int32 isDir)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback2, 0x10) + + +#define Z7_IFACEM_IFolderScanProgress(x) \ + x(ScanError(const wchar_t *path, HRESULT errorCode)) \ + x(ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderScanProgress, 0x11) + + +#define Z7_IFACEM_IFolderSetZoneIdMode(x) \ + x(SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdMode, 0x12) + +#define Z7_IFACEM_IFolderSetZoneIdFile(x) \ + x(SetZoneIdFile(const Byte *data, UInt32 size)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdFile, 0x13) + + +// if the caller calls Before_ArcReopen(), the callee must +// clear user break status, because the caller want to open archive still. +#define Z7_IFACEM_IFolderArchiveUpdateCallback_MoveArc(x) \ + x(MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode)) \ + x(MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)) \ + x(MoveArc_Finish()) \ + x(Before_ArcReopen()) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback_MoveArc, 0x14) + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/UI/Agent/StdAfx.h b/CPP/7zip/UI/Agent/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/UI/Agent/StdAfx.h +++ b/CPP/7zip/UI/Agent/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp index d0c669520..8299902da 100644 --- a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp +++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp @@ -1,208 +1,208 @@ -// UpdateCallbackAgent.h - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/ErrorMsg.h" - -#include "UpdateCallbackAgent.h" - -using namespace NWindows; - -void CUpdateCallbackAgent::SetCallback(IFolderArchiveUpdateCallback *callback) -{ - Callback = callback; - _compressProgress.Release(); - Callback2.Release(); - if (Callback) - { - Callback.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); - Callback.QueryInterface(IID_IFolderArchiveUpdateCallback2, &Callback2); - } -} - -HRESULT CUpdateCallbackAgent::SetNumItems(const CArcToDoStat &stat) -{ - if (Callback) - return Callback->SetNumFiles(stat.Get_NumDataItems_Total()); - return S_OK; -} - - -HRESULT CUpdateCallbackAgent::WriteSfx(const wchar_t * /* name */, UInt64 /* size */) -{ - return S_OK; -} - - -HRESULT CUpdateCallbackAgent::SetTotal(UINT64 size) -{ - if (Callback) - return Callback->SetTotal(size); - return S_OK; -} - -HRESULT CUpdateCallbackAgent::SetCompleted(const UINT64 *completeValue) -{ - if (Callback) - return Callback->SetCompleted(completeValue); - return S_OK; -} - -HRESULT CUpdateCallbackAgent::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - if (_compressProgress) - return _compressProgress->SetRatioInfo(inSize, outSize); - return S_OK; -} - -HRESULT CUpdateCallbackAgent::CheckBreak() -{ - return S_OK; -} - -/* -HRESULT CUpdateCallbackAgent::Finalize() -{ - return S_OK; -} -*/ - -HRESULT CUpdateCallbackAgent::OpenFileError(const FString &path, DWORD systemError) -{ - const HRESULT hres = HRESULT_FROM_WIN32(systemError); - // if (systemError == ERROR_SHARING_VIOLATION) - { - if (Callback2) - { - RINOK(Callback2->OpenFileError(fs2us(path), hres)) - return S_FALSE; - } - - if (Callback) - { - UString s ("WARNING: "); - s += NError::MyFormatMessage(systemError); - s += ": "; - s += fs2us(path); - RINOK(Callback->UpdateErrorMessage(s)) - return S_FALSE; - } - } - // FailedFiles.Add(name); - return hres; -} - -HRESULT CUpdateCallbackAgent::ReadingFileError(const FString &path, DWORD systemError) -{ - const HRESULT hres = HRESULT_FROM_WIN32(systemError); - - // if (systemError == ERROR_SHARING_VIOLATION) - { - if (Callback2) - { - RINOK(Callback2->ReadingFileError(fs2us(path), hres)) - } - else if (Callback) - { - UString s ("ERROR: "); - s += NError::MyFormatMessage(systemError); - s += ": "; - s += fs2us(path); - RINOK(Callback->UpdateErrorMessage(s)) - } - } - // FailedFiles.Add(name); - return hres; -} - -HRESULT CUpdateCallbackAgent::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode) -{ - if (Callback2) - return Callback2->ReportUpdateOperation(mode, name, BoolToInt(isDir)); - if (Callback) - return Callback->CompressOperation(name); - return S_OK; -} - -HRESULT CUpdateCallbackAgent::SetOperationResult(Int32 operationResult) -{ - if (Callback) - return Callback->OperationResult(operationResult); - return S_OK; -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); - -HRESULT CUpdateCallbackAgent::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) -{ - if (Callback2) - { - return Callback2->ReportExtractResult(opRes, isEncrypted, name); - } - /* - if (mode != NArchive::NExtract::NOperationResult::kOK) - { - Int32 encrypted = 0; - UString s; - SetExtractErrorMessage(mode, encrypted, name, s); - // ProgressDialog->Sync.AddError_Message(s); - } - */ - return S_OK; -} - -HRESULT CUpdateCallbackAgent::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) -{ - if (Callback2) - { - return Callback2->ReportUpdateOperation(op, name, BoolToInt(isDir)); - } - return S_OK; -} - -/* -HRESULT CUpdateCallbackAgent::SetPassword(const UString & - #ifndef Z7_NO_CRYPTO - password - #endif - ) -{ - #ifndef Z7_NO_CRYPTO - PasswordIsDefined = true; - Password = password; - #endif - return S_OK; -} -*/ - -HRESULT CUpdateCallbackAgent::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) -{ - *password = NULL; - *passwordIsDefined = BoolToInt(false); - if (!_cryptoGetTextPassword) - { - if (!Callback) - return S_OK; - Callback.QueryInterface(IID_ICryptoGetTextPassword2, &_cryptoGetTextPassword); - if (!_cryptoGetTextPassword) - return S_OK; - } - return _cryptoGetTextPassword->CryptoGetTextPassword2(passwordIsDefined, password); -} - -HRESULT CUpdateCallbackAgent::CryptoGetTextPassword(BSTR *password) -{ - *password = NULL; - CMyComPtr getTextPassword; - Callback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); - if (!getTextPassword) - return E_NOTIMPL; - return getTextPassword->CryptoGetTextPassword(password); -} - -HRESULT CUpdateCallbackAgent::ShowDeleteFile(const wchar_t *name, bool /* isDir */) -{ - return Callback->DeleteOperation(name); -} +// UpdateCallbackAgent.h + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/ErrorMsg.h" + +#include "UpdateCallbackAgent.h" + +using namespace NWindows; + +void CUpdateCallbackAgent::SetCallback(IFolderArchiveUpdateCallback *callback) +{ + Callback = callback; + _compressProgress.Release(); + Callback2.Release(); + if (Callback) + { + Callback.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); + Callback.QueryInterface(IID_IFolderArchiveUpdateCallback2, &Callback2); + } +} + +HRESULT CUpdateCallbackAgent::SetNumItems(const CArcToDoStat &stat) +{ + if (Callback) + return Callback->SetNumFiles(stat.Get_NumDataItems_Total()); + return S_OK; +} + + +HRESULT CUpdateCallbackAgent::WriteSfx(const wchar_t * /* name */, UInt64 /* size */) +{ + return S_OK; +} + + +HRESULT CUpdateCallbackAgent::SetTotal(UINT64 size) +{ + if (Callback) + return Callback->SetTotal(size); + return S_OK; +} + +HRESULT CUpdateCallbackAgent::SetCompleted(const UINT64 *completeValue) +{ + if (Callback) + return Callback->SetCompleted(completeValue); + return S_OK; +} + +HRESULT CUpdateCallbackAgent::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + if (_compressProgress) + return _compressProgress->SetRatioInfo(inSize, outSize); + return S_OK; +} + +HRESULT CUpdateCallbackAgent::CheckBreak() +{ + return S_OK; +} + +/* +HRESULT CUpdateCallbackAgent::Finalize() +{ + return S_OK; +} +*/ + +HRESULT CUpdateCallbackAgent::OpenFileError(const FString &path, DWORD systemError) +{ + const HRESULT hres = HRESULT_FROM_WIN32(systemError); + // if (systemError == ERROR_SHARING_VIOLATION) + { + if (Callback2) + { + RINOK(Callback2->OpenFileError(fs2us(path), hres)) + return S_FALSE; + } + + if (Callback) + { + UString s ("WARNING: "); + s += NError::MyFormatMessage(systemError); + s += ": "; + s += fs2us(path); + RINOK(Callback->UpdateErrorMessage(s)) + return S_FALSE; + } + } + // FailedFiles.Add(name); + return hres; +} + +HRESULT CUpdateCallbackAgent::ReadingFileError(const FString &path, DWORD systemError) +{ + const HRESULT hres = HRESULT_FROM_WIN32(systemError); + + // if (systemError == ERROR_SHARING_VIOLATION) + { + if (Callback2) + { + RINOK(Callback2->ReadingFileError(fs2us(path), hres)) + } + else if (Callback) + { + UString s ("ERROR: "); + s += NError::MyFormatMessage(systemError); + s += ": "; + s += fs2us(path); + RINOK(Callback->UpdateErrorMessage(s)) + } + } + // FailedFiles.Add(name); + return hres; +} + +HRESULT CUpdateCallbackAgent::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode) +{ + if (Callback2) + return Callback2->ReportUpdateOperation(mode, name, BoolToInt(isDir)); + if (Callback) + return Callback->CompressOperation(name); + return S_OK; +} + +HRESULT CUpdateCallbackAgent::SetOperationResult(Int32 operationResult) +{ + if (Callback) + return Callback->OperationResult(operationResult); + return S_OK; +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); + +HRESULT CUpdateCallbackAgent::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) +{ + if (Callback2) + { + return Callback2->ReportExtractResult(opRes, isEncrypted, name); + } + /* + if (mode != NArchive::NExtract::NOperationResult::kOK) + { + Int32 encrypted = 0; + UString s; + SetExtractErrorMessage(mode, encrypted, name, s); + // ProgressDialog->Sync.AddError_Message(s); + } + */ + return S_OK; +} + +HRESULT CUpdateCallbackAgent::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) +{ + if (Callback2) + { + return Callback2->ReportUpdateOperation(op, name, BoolToInt(isDir)); + } + return S_OK; +} + +/* +HRESULT CUpdateCallbackAgent::SetPassword(const UString & + #ifndef Z7_NO_CRYPTO + password + #endif + ) +{ + #ifndef Z7_NO_CRYPTO + PasswordIsDefined = true; + Password = password; + #endif + return S_OK; +} +*/ + +HRESULT CUpdateCallbackAgent::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) +{ + *password = NULL; + *passwordIsDefined = BoolToInt(false); + if (!_cryptoGetTextPassword) + { + if (!Callback) + return S_OK; + Callback.QueryInterface(IID_ICryptoGetTextPassword2, &_cryptoGetTextPassword); + if (!_cryptoGetTextPassword) + return S_OK; + } + return _cryptoGetTextPassword->CryptoGetTextPassword2(passwordIsDefined, password); +} + +HRESULT CUpdateCallbackAgent::CryptoGetTextPassword(BSTR *password) +{ + *password = NULL; + CMyComPtr getTextPassword; + Callback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + if (!getTextPassword) + return E_NOTIMPL; + return getTextPassword->CryptoGetTextPassword(password); +} + +HRESULT CUpdateCallbackAgent::ShowDeleteFile(const wchar_t *name, bool /* isDir */) +{ + return Callback->DeleteOperation(name); +} diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.h b/CPP/7zip/UI/Agent/UpdateCallbackAgent.h index 055e952cc..179ce988a 100644 --- a/CPP/7zip/UI/Agent/UpdateCallbackAgent.h +++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.h @@ -1,22 +1,22 @@ -// UpdateCallbackAgent.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK_AGENT_H -#define ZIP7_INC_UPDATE_CALLBACK_AGENT_H - -#include "../Common/UpdateCallback.h" - -#include "IFolderArchive.h" - -class CUpdateCallbackAgent Z7_final: public IUpdateCallbackUI -{ - Z7_IFACE_IMP(IUpdateCallbackUI) - - CMyComPtr _cryptoGetTextPassword; - CMyComPtr Callback; - CMyComPtr Callback2; - CMyComPtr _compressProgress; -public: - void SetCallback(IFolderArchiveUpdateCallback *callback); -}; - -#endif +// UpdateCallbackAgent.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK_AGENT_H +#define ZIP7_INC_UPDATE_CALLBACK_AGENT_H + +#include "../Common/UpdateCallback.h" + +#include "IFolderArchive.h" + +class CUpdateCallbackAgent Z7_final: public IUpdateCallbackUI +{ + Z7_IFACE_IMP(IUpdateCallbackUI) + + CMyComPtr _cryptoGetTextPassword; + CMyComPtr Callback; + CMyComPtr Callback2; + CMyComPtr _compressProgress; +public: + void SetCallback(IFolderArchiveUpdateCallback *callback); +}; + +#endif diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp index f605ee411..b1e43dade 100644 --- a/CPP/7zip/UI/Client7z/Client7z.cpp +++ b/CPP/7zip/UI/Client7z/Client7z.cpp @@ -1,1145 +1,1145 @@ -// Client7z.cpp - -#include "StdAfx.h" - -#include - -#include "../../../Common/MyWindows.h" -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/Defs.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/NtCheck.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../Common/FileStreams.h" - -#include "../../Archive/IArchive.h" - -#if 0 -// for password request functions: -#include "../../UI/Console/UserInputUtils.h" -#endif - -#include "../../IPassword.h" -#include "../../../../C/7zVersion.h" - -#ifdef _WIN32 -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance = NULL; -#endif - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -// You can find full list of all GUIDs supported by 7-Zip in Guid.txt file. -// 7z format GUID: {23170F69-40C1-278A-1000-000110070000} - -#define DEFINE_GUID_ARC(name, id) Z7_DEFINE_GUID(name, \ - 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00); - -enum -{ - kId_Zip = 1, - kId_BZip2 = 2, - kId_7z = 7, - kId_Xz = 0xC, - kId_Tar = 0xEE, - kId_GZip = 0xEF -}; - -// use another id, if you want to support other formats (zip, Xz, ...). -// DEFINE_GUID_ARC (CLSID_Format, kId_Zip) -// DEFINE_GUID_ARC (CLSID_Format, kId_BZip2) -// DEFINE_GUID_ARC (CLSID_Format, kId_Xz) -// DEFINE_GUID_ARC (CLSID_Format, kId_Tar) -// DEFINE_GUID_ARC (CLSID_Format, kId_GZip) -DEFINE_GUID_ARC (CLSID_Format, kId_7z) - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -#ifdef _WIN32 -#define kDllName "7z.dll" -#else -#define kDllName "7z.so" -#endif - -static const char * const kCopyrightString = - "\n" - "7-Zip" - " (" kDllName " client)" - " " MY_VERSION - " : " MY_COPYRIGHT_DATE - "\n"; - -static const char * const kHelpString = -"Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n" -"Examples:\n" -" 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n" -" 7zcl.exe l archive.7z : List contents of archive.7z\n" -" 7zcl.exe x archive.7z : eXtract files from archive.7z\n"; - - -static void Convert_UString_to_AString(const UString &s, AString &temp) -{ - int codePage = CP_OEMCP; - /* - int g_CodePage = -1; - int codePage = g_CodePage; - if (codePage == -1) - codePage = CP_OEMCP; - if (codePage == CP_UTF8) - ConvertUnicodeToUTF8(s, temp); - else - */ - UnicodeStringToMultiByte2(temp, s, (UINT)codePage); -} - -static FString CmdStringToFString(const char *s) -{ - return us2fs(GetUnicodeString(s)); -} - -static void Print(const char *s) -{ - fputs(s, stdout); -} - -static void Print(const AString &s) -{ - Print(s.Ptr()); -} - -static void Print(const UString &s) -{ - AString as; - Convert_UString_to_AString(s, as); - Print(as); -} - -static void Print(const wchar_t *s) -{ - Print(UString(s)); -} - -static void PrintNewLine() -{ - Print("\n"); -} - -static void PrintStringLn(const char *s) -{ - Print(s); - PrintNewLine(); -} - -static void PrintError(const char *message) -{ - Print("Error: "); - PrintNewLine(); - Print(message); - PrintNewLine(); -} - -static void PrintError(const char *message, const FString &name) -{ - PrintError(message); - Print(name); -} - - -static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result) -{ - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, propID, &prop)) - if (prop.vt == VT_BOOL) - result = VARIANT_BOOLToBool(prop.boolVal); - else if (prop.vt == VT_EMPTY) - result = false; - else - return E_FAIL; - return S_OK; -} - -static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) -{ - return IsArchiveItemProp(archive, index, kpidIsDir, result); -} - - -static const wchar_t * const kEmptyFileAlias = L"[Content]"; - - -////////////////////////////////////////////////////////////// -// Archive Open callback class - - -class CArchiveOpenCallback Z7_final: - public IArchiveOpenCallback, - public ICryptoGetTextPassword, - public CMyUnknownImp -{ - Z7_IFACES_IMP_UNK_2(IArchiveOpenCallback, ICryptoGetTextPassword) -public: - - bool PasswordIsDefined; - UString Password; - - CArchiveOpenCallback() : PasswordIsDefined(false) {} -}; - -Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)) -{ - if (!PasswordIsDefined) - { - // You can ask real password here from user -#if 0 - RINOK(GetPassword_HRESULT(&g_StdOut, Password)) - PasswordIsDefined = true; -#else - PrintError("Password is not defined"); - return E_ABORT; -#endif - } - return StringToBstr(Password, password); -} - - - -static const char * const kIncorrectCommand = "incorrect command"; - -////////////////////////////////////////////////////////////// -// Archive Extracting callback class - -static const char * const kTestingString = "Testing "; -static const char * const kExtractingString = "Extracting "; -static const char * const kSkippingString = "Skipping "; -static const char * const kReadingString = "Reading "; - -static const char * const kUnsupportedMethod = "Unsupported Method"; -static const char * const kCRCFailed = "CRC Failed"; -static const char * const kDataError = "Data Error"; -static const char * const kUnavailableData = "Unavailable data"; -static const char * const kUnexpectedEnd = "Unexpected end of data"; -static const char * const kDataAfterEnd = "There are some data after the end of the payload data"; -static const char * const kIsNotArc = "Is not archive"; -static const char * const kHeadersError = "Headers Error"; - - -struct CArcTime -{ - FILETIME FT; - UInt16 Prec; - Byte Ns100; - bool Def; - - CArcTime() - { - Clear(); - } - - void Clear() - { - FT.dwHighDateTime = FT.dwLowDateTime = 0; - Prec = 0; - Ns100 = 0; - Def = false; - } - - bool IsZero() const - { - return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0; - } - - int GetNumDigits() const - { - if (Prec == k_PropVar_TimePrec_Unix || - Prec == k_PropVar_TimePrec_DOS) - return 0; - if (Prec == k_PropVar_TimePrec_HighPrec) - return 9; - if (Prec == k_PropVar_TimePrec_0) - return 7; - int digits = (int)Prec - (int)k_PropVar_TimePrec_Base; - if (digits < 0) - digits = 0; - return digits; - } - - void Write_To_FiTime(CFiTime &dest) const - { - #ifdef _WIN32 - dest = FT; - #else - if (FILETIME_To_timespec(FT, dest)) - if ((Prec == k_PropVar_TimePrec_Base + 8 || - Prec == k_PropVar_TimePrec_Base + 9) - && Ns100 != 0) - { - dest.tv_nsec += Ns100; - } - #endif - } - - void Set_From_Prop(const PROPVARIANT &prop) - { - FT = prop.filetime; - unsigned prec = 0; - unsigned ns100 = 0; - const unsigned prec_Temp = prop.wReserved1; - if (prec_Temp != 0 - && prec_Temp <= k_PropVar_TimePrec_1ns - && prop.wReserved3 == 0) - { - const unsigned ns100_Temp = prop.wReserved2; - if (ns100_Temp < 100) - { - ns100 = ns100_Temp; - prec = prec_Temp; - } - } - Prec = (UInt16)prec; - Ns100 = (Byte)ns100; - Def = true; - } -}; - - - -class CArchiveExtractCallback Z7_final: - public IArchiveExtractCallback, - public ICryptoGetTextPassword, - public CMyUnknownImp -{ - Z7_IFACES_IMP_UNK_2(IArchiveExtractCallback, ICryptoGetTextPassword) - Z7_IFACE_COM7_IMP(IProgress) - - CMyComPtr _archiveHandler; - FString _directoryPath; // Output directory - UString _filePath; // name inside arcvhive - FString _diskFilePath; // full path to file on disk - bool _extractMode; - struct CProcessedFileInfo - { - CArcTime MTime; - UInt32 Attrib; - bool isDir; - bool Attrib_Defined; - } _processedFileInfo; - - COutFileStream *_outFileStreamSpec; - CMyComPtr _outFileStream; - -public: - void Init(IInArchive *archiveHandler, const FString &directoryPath); - - UInt64 NumErrors; - bool PasswordIsDefined; - UString Password; - - CArchiveExtractCallback() : PasswordIsDefined(false) {} -}; - -void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath) -{ - NumErrors = 0; - _archiveHandler = archiveHandler; - _directoryPath = directoryPath; - NName::NormalizeDirPathPrefix(_directoryPath); -} - -Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 /* size */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, - ISequentialOutStream **outStream, Int32 askExtractMode)) -{ - *outStream = NULL; - _outFileStream.Release(); - - { - // Get Name - NCOM::CPropVariant prop; - RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop)) - - UString fullPath; - if (prop.vt == VT_EMPTY) - fullPath = kEmptyFileAlias; - else - { - if (prop.vt != VT_BSTR) - return E_FAIL; - fullPath = prop.bstrVal; - } - _filePath = fullPath; - } - - if (askExtractMode != NArchive::NExtract::NAskMode::kExtract) - return S_OK; - - { - // Get Attrib - NCOM::CPropVariant prop; - RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop)) - if (prop.vt == VT_EMPTY) - { - _processedFileInfo.Attrib = 0; - _processedFileInfo.Attrib_Defined = false; - } - else - { - if (prop.vt != VT_UI4) - return E_FAIL; - _processedFileInfo.Attrib = prop.ulVal; - _processedFileInfo.Attrib_Defined = true; - } - } - - RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir)) - - { - _processedFileInfo.MTime.Clear(); - // Get Modified Time - NCOM::CPropVariant prop; - RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)) - switch (prop.vt) - { - case VT_EMPTY: - // _processedFileInfo.MTime = _utcMTimeDefault; - break; - case VT_FILETIME: - _processedFileInfo.MTime.Set_From_Prop(prop); - break; - default: - return E_FAIL; - } - - } - { - // Get Size - NCOM::CPropVariant prop; - RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop)) - UInt64 newFileSize; - /* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize); - } - - - { - // Create folders for file - int slashPos = _filePath.ReverseFind_PathSepar(); - if (slashPos >= 0) - CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos))); - } - - FString fullProcessedPath = _directoryPath + us2fs(_filePath); - _diskFilePath = fullProcessedPath; - - if (_processedFileInfo.isDir) - { - CreateComplexDir(fullProcessedPath); - } - else - { - NFind::CFileInfo fi; - if (fi.Find(fullProcessedPath)) - { - if (!DeleteFileAlways(fullProcessedPath)) - { - PrintError("Cannot delete output file", fullProcessedPath); - return E_ABORT; - } - } - - _outFileStreamSpec = new COutFileStream; - CMyComPtr outStreamLoc(_outFileStreamSpec); - if (!_outFileStreamSpec->Create_ALWAYS(fullProcessedPath)) - { - PrintError("Cannot open output file", fullProcessedPath); - return E_ABORT; - } - _outFileStream = outStreamLoc; - *outStream = outStreamLoc.Detach(); - } - return S_OK; -} - -Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)) -{ - _extractMode = false; - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break; - } - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break; - case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break; - case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break; - case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break; - default: - Print("??? "); break; - } - Print(_filePath); - return S_OK; -} - -Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 operationResult)) -{ - switch (operationResult) - { - case NArchive::NExtract::NOperationResult::kOK: - break; - default: - { - NumErrors++; - Print(" : "); - const char *s = NULL; - switch (operationResult) - { - case NArchive::NExtract::NOperationResult::kUnsupportedMethod: - s = kUnsupportedMethod; - break; - case NArchive::NExtract::NOperationResult::kCRCError: - s = kCRCFailed; - break; - case NArchive::NExtract::NOperationResult::kDataError: - s = kDataError; - break; - case NArchive::NExtract::NOperationResult::kUnavailable: - s = kUnavailableData; - break; - case NArchive::NExtract::NOperationResult::kUnexpectedEnd: - s = kUnexpectedEnd; - break; - case NArchive::NExtract::NOperationResult::kDataAfterEnd: - s = kDataAfterEnd; - break; - case NArchive::NExtract::NOperationResult::kIsNotArc: - s = kIsNotArc; - break; - case NArchive::NExtract::NOperationResult::kHeadersError: - s = kHeadersError; - break; - } - if (s) - { - Print("Error : "); - Print(s); - } - else - { - char temp[16]; - ConvertUInt32ToString((UInt32)operationResult, temp); - Print("Error #"); - Print(temp); - } - } - } - - if (_outFileStream) - { - if (_processedFileInfo.MTime.Def) - { - CFiTime ft; - _processedFileInfo.MTime.Write_To_FiTime(ft); - _outFileStreamSpec->SetMTime(&ft); - } - RINOK(_outFileStreamSpec->Close()) - } - _outFileStream.Release(); - if (_extractMode && _processedFileInfo.Attrib_Defined) - SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib); - PrintNewLine(); - return S_OK; -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)) -{ - if (!PasswordIsDefined) - { -#if 0 - // You can ask real password here from user - RINOK(GetPassword_HRESULT(&g_StdOut, Password)) - PasswordIsDefined = true; -#else - PrintError("Password is not defined"); - return E_ABORT; -#endif - } - return StringToBstr(Password, password); -} - - - -////////////////////////////////////////////////////////////// -// Archive Creating callback class - -struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase -{ - UString Path_For_Handler; - FString FullPath; // for filesystem - - CDirItem(const NWindows::NFile::NFind::CFileInfo &fi): - CFileInfoBase(fi) - {} -}; - -class CArchiveUpdateCallback Z7_final: - public IArchiveUpdateCallback2, - public ICryptoGetTextPassword2, - public CMyUnknownImp -{ - Z7_IFACES_IMP_UNK_2(IArchiveUpdateCallback2, ICryptoGetTextPassword2) - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IArchiveUpdateCallback) - -public: - CRecordVector VolumesSizes; - UString VolName; - UString VolExt; - - FString DirPrefix; - const CObjectVector *DirItems; - - bool PasswordIsDefined; - UString Password; - bool AskPassword; - - bool m_NeedBeClosed; - - FStringVector FailedFiles; - CRecordVector FailedCodes; - - CArchiveUpdateCallback(): - DirItems(NULL), - PasswordIsDefined(false), - AskPassword(false) - {} - - ~CArchiveUpdateCallback() { Finilize(); } - HRESULT Finilize(); - - void Init(const CObjectVector *dirItems) - { - DirItems = dirItems; - m_NeedBeClosed = false; - FailedFiles.Clear(); - FailedCodes.Clear(); - } -}; - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 /* size */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, - Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)) -{ - if (newData) - *newData = BoolToInt(true); - if (newProperties) - *newProperties = BoolToInt(true); - if (indexInArchive) - *indexInArchive = (UInt32)(Int32)-1; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - - if (propID == kpidIsAnti) - { - prop = false; - prop.Detach(value); - return S_OK; - } - - { - const CDirItem &di = (*DirItems)[index]; - switch (propID) - { - case kpidPath: prop = di.Path_For_Handler; break; - case kpidIsDir: prop = di.IsDir(); break; - case kpidSize: prop = di.Size; break; - case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; - case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; - case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; - case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break; - case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break; - } - } - prop.Detach(value); - return S_OK; -} - -HRESULT CArchiveUpdateCallback::Finilize() -{ - if (m_NeedBeClosed) - { - PrintNewLine(); - m_NeedBeClosed = false; - } - return S_OK; -} - -static void GetStream2(const wchar_t *name) -{ - Print("Compressing "); - if (name[0] == 0) - name = kEmptyFileAlias; - Print(name); -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)) -{ - RINOK(Finilize()) - - const CDirItem &dirItem = (*DirItems)[index]; - GetStream2(dirItem.Path_For_Handler); - - if (dirItem.IsDir()) - return S_OK; - - { - CInFileStream *inStreamSpec = new CInFileStream; - CMyComPtr inStreamLoc(inStreamSpec); - FString path = DirPrefix + dirItem.FullPath; - if (!inStreamSpec->Open(path)) - { - const DWORD sysError = ::GetLastError(); - FailedCodes.Add(HRESULT_FROM_WIN32(sysError)); - FailedFiles.Add(path); - // if (systemError == ERROR_SHARING_VIOLATION) - { - PrintNewLine(); - PrintError("WARNING: can't open file"); - // Print(NError::MyFormatMessageW(systemError)); - return S_FALSE; - } - // return sysError; - } - *inStream = inStreamLoc.Detach(); - } - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */)) -{ - m_NeedBeClosed = true; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)) -{ - if (VolumesSizes.Size() == 0) - return S_FALSE; - if (index >= (UInt32)VolumesSizes.Size()) - index = VolumesSizes.Size() - 1; - *size = VolumesSizes[index]; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) -{ - wchar_t temp[16]; - ConvertUInt32ToString(index + 1, temp); - UString res = temp; - while (res.Len() < 2) - res.InsertAtFront(L'0'); - UString fileName = VolName; - fileName.Add_Dot(); - fileName += res; - fileName += VolExt; - COutFileStream *streamSpec = new COutFileStream; - CMyComPtr streamLoc(streamSpec); - if (!streamSpec->Create_NEW(us2fs(fileName))) - return GetLastError_noZero_HRESULT(); - *volumeStream = streamLoc.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) -{ - if (!PasswordIsDefined) - { - if (AskPassword) - { -#if 0 - RINOK(GetPassword_HRESULT(&g_StdOut, Password)) - PasswordIsDefined = true; -#else - PrintError("Password is not defined"); - return E_ABORT; -#endif - } - } - *passwordIsDefined = BoolToInt(PasswordIsDefined); - return StringToBstr(Password, password); -} - - -// Main function - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1; -#endif - -int Z7_CDECL main(int numArgs, const char *args[]) -{ - NT_CHECK - - #ifdef ENV_HAVE_LOCALE - MY_SetLocale(); - #endif - - PrintStringLn(kCopyrightString); - - if (numArgs < 2) - { - PrintStringLn(kHelpString); - return 0; - } - - FString dllPrefix; - - #ifdef _WIN32 - dllPrefix = NDLL::GetModuleDirPrefix(); - #else - { - AString s (args[0]); - int sep = s.ReverseFind_PathSepar(); - s.DeleteFrom(sep + 1); - dllPrefix = s; - } - #endif - - NDLL::CLibrary lib; - if (!lib.Load(dllPrefix + FTEXT(kDllName))) - { - PrintError("Cannot load 7-zip library"); - return 1; - } - -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" -#endif - -#ifdef _WIN32 -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -#endif - - Func_CreateObject - f_CreateObject = Z7_GET_PROC_ADDRESS( - Func_CreateObject, lib.Get_HMODULE(), - "CreateObject"); - if (!f_CreateObject) - { - PrintError("Cannot get CreateObject"); - return 1; - } - - char c = 0; - UString password; - bool passwordIsDefined = false; - CObjectVector params; - - for (int curCmd = 1; curCmd < numArgs; curCmd++) - { - AString a(args[curCmd]); - - if (!a.IsEmpty()) - { - if (a[0] == '-') - { - if (!passwordIsDefined && a[1] == 'p') - { - password = GetUnicodeString(a.Ptr(2)); - passwordIsDefined = true; - continue; - } - } - else - { - if (c) - { - params.Add(CmdStringToFString(a)); - continue; - } - if (a.Len() == 1) - { - c = (char)MyCharLower_Ascii(a[0]); - continue; - } - } - } - { - PrintError(kIncorrectCommand); - return 1; - } - } - - if (!c || params.Size() < 1) - { - PrintError(kIncorrectCommand); - return 1; - } - - const FString &archiveName = params[0]; - - if (c == 'a') - { - // create archive command - if (params.Size() < 2) - { - PrintError(kIncorrectCommand); - return 1; - } - CObjectVector dirItems; - { - unsigned i; - for (i = 1; i < params.Size(); i++) - { - const FString &name = params[i]; - - NFind::CFileInfo fi; - if (!fi.Find(name)) - { - PrintError("Can't find file", name); - return 1; - } - - CDirItem di(fi); - - di.Path_For_Handler = fs2us(name); - di.FullPath = name; - dirItems.Add(di); - } - } - - COutFileStream *outFileStreamSpec = new COutFileStream; - CMyComPtr outFileStream = outFileStreamSpec; - if (!outFileStreamSpec->Create_NEW(archiveName)) - { - PrintError("can't create archive file"); - return 1; - } - - CMyComPtr outArchive; - if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK) - { - PrintError("Cannot get class object"); - return 1; - } - - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr updateCallback(updateCallbackSpec); - updateCallbackSpec->Init(&dirItems); - updateCallbackSpec->PasswordIsDefined = passwordIsDefined; - updateCallbackSpec->Password = password; - - /* - { - const wchar_t *names[] = - { - L"m", - L"s", - L"x" - }; - const unsigned kNumProps = Z7_ARRAY_SIZE(names); - NCOM::CPropVariant values[kNumProps] = - { - L"lzma", - false, // solid mode OFF - (UInt32)9 // compression level = 9 - ultra - }; - CMyComPtr setProperties; - outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties); - if (!setProperties) - { - PrintError("ISetProperties unsupported"); - return 1; - } - if (setProperties->SetProperties(names, values, kNumProps) != S_OK) - { - PrintError("SetProperties() error"); - return 1; - } - } - */ - - HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback); - - updateCallbackSpec->Finilize(); - - if (result != S_OK) - { - PrintError("Update Error"); - return 1; - } - - FOR_VECTOR (i, updateCallbackSpec->FailedFiles) - { - PrintNewLine(); - PrintError("Error for file", updateCallbackSpec->FailedFiles[i]); - } - - if (updateCallbackSpec->FailedFiles.Size() != 0) - return 1; - } - else - { - if (params.Size() != 1) - { - PrintError(kIncorrectCommand); - return 1; - } - - bool listCommand; - - if (c == 'l') - listCommand = true; - else if (c == 'x') - listCommand = false; - else - { - PrintError(kIncorrectCommand); - return 1; - } - - CMyComPtr archive; - if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK) - { - PrintError("Cannot get class object"); - return 1; - } - - CInFileStream *fileSpec = new CInFileStream; - CMyComPtr file = fileSpec; - - if (!fileSpec->Open(archiveName)) - { - PrintError("Cannot open archive file", archiveName); - return 1; - } - - { - CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback; - CMyComPtr openCallback(openCallbackSpec); - openCallbackSpec->PasswordIsDefined = passwordIsDefined; - openCallbackSpec->Password = password; - - const UInt64 scanSize = 1 << 23; - if (archive->Open(file, &scanSize, openCallback) != S_OK) - { - PrintError("Cannot open file as archive", archiveName); - return 1; - } - } - - if (listCommand) - { - // List command - UInt32 numItems = 0; - archive->GetNumberOfItems(&numItems); - for (UInt32 i = 0; i < numItems; i++) - { - { - // Get uncompressed size of file - NCOM::CPropVariant prop; - archive->GetProperty(i, kpidSize, &prop); - char s[64]; - ConvertPropVariantToShortString(prop, s); - Print(s); - Print(" "); - } - { - // Get name of file - NCOM::CPropVariant prop; - archive->GetProperty(i, kpidPath, &prop); - if (prop.vt == VT_BSTR) - Print(prop.bstrVal); - else if (prop.vt != VT_EMPTY) - Print("ERROR!"); - } - PrintNewLine(); - } - } - else - { - // Extract command - CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; - CMyComPtr extractCallback(extractCallbackSpec); - extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path - extractCallbackSpec->PasswordIsDefined = passwordIsDefined; - extractCallbackSpec->Password = password; - - /* - const wchar_t *names[] = - { - L"mt", - L"mtf" - }; - const unsigned kNumProps = sizeof(names) / sizeof(names[0]); - NCOM::CPropVariant values[kNumProps] = - { - (UInt32)1, - false - }; - CMyComPtr setProperties; - archive->QueryInterface(IID_ISetProperties, (void **)&setProperties); - if (setProperties) - { - if (setProperties->SetProperties(names, values, kNumProps) != S_OK) - { - PrintError("SetProperties() error"); - return 1; - } - } - */ - - HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback); - - if (result != S_OK) - { - PrintError("Extract Error"); - return 1; - } - } - } - - return 0; -} +// Client7z.cpp + +#include "StdAfx.h" + +#include + +#include "../../../Common/MyWindows.h" +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/Defs.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/NtCheck.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../Common/FileStreams.h" + +#include "../../Archive/IArchive.h" + +#if 0 +// for password request functions: +#include "../../UI/Console/UserInputUtils.h" +#endif + +#include "../../IPassword.h" +#include "../../../../C/7zVersion.h" + +#ifdef _WIN32 +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance = NULL; +#endif + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +// You can find full list of all GUIDs supported by 7-Zip in Guid.txt file. +// 7z format GUID: {23170F69-40C1-278A-1000-000110070000} + +#define DEFINE_GUID_ARC(name, id) Z7_DEFINE_GUID(name, \ + 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00); + +enum +{ + kId_Zip = 1, + kId_BZip2 = 2, + kId_7z = 7, + kId_Xz = 0xC, + kId_Tar = 0xEE, + kId_GZip = 0xEF +}; + +// use another id, if you want to support other formats (zip, Xz, ...). +// DEFINE_GUID_ARC (CLSID_Format, kId_Zip) +// DEFINE_GUID_ARC (CLSID_Format, kId_BZip2) +// DEFINE_GUID_ARC (CLSID_Format, kId_Xz) +// DEFINE_GUID_ARC (CLSID_Format, kId_Tar) +// DEFINE_GUID_ARC (CLSID_Format, kId_GZip) +DEFINE_GUID_ARC (CLSID_Format, kId_7z) + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +#ifdef _WIN32 +#define kDllName "7z.dll" +#else +#define kDllName "7z.so" +#endif + +static const char * const kCopyrightString = + "\n" + "7-Zip" + " (" kDllName " client)" + " " MY_VERSION + " : " MY_COPYRIGHT_DATE + "\n"; + +static const char * const kHelpString = +"Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n" +"Examples:\n" +" 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n" +" 7zcl.exe l archive.7z : List contents of archive.7z\n" +" 7zcl.exe x archive.7z : eXtract files from archive.7z\n"; + + +static void Convert_UString_to_AString(const UString &s, AString &temp) +{ + int codePage = CP_OEMCP; + /* + int g_CodePage = -1; + int codePage = g_CodePage; + if (codePage == -1) + codePage = CP_OEMCP; + if (codePage == CP_UTF8) + ConvertUnicodeToUTF8(s, temp); + else + */ + UnicodeStringToMultiByte2(temp, s, (UINT)codePage); +} + +static FString CmdStringToFString(const char *s) +{ + return us2fs(GetUnicodeString(s)); +} + +static void Print(const char *s) +{ + fputs(s, stdout); +} + +static void Print(const AString &s) +{ + Print(s.Ptr()); +} + +static void Print(const UString &s) +{ + AString as; + Convert_UString_to_AString(s, as); + Print(as); +} + +static void Print(const wchar_t *s) +{ + Print(UString(s)); +} + +static void PrintNewLine() +{ + Print("\n"); +} + +static void PrintStringLn(const char *s) +{ + Print(s); + PrintNewLine(); +} + +static void PrintError(const char *message) +{ + Print("Error: "); + PrintNewLine(); + Print(message); + PrintNewLine(); +} + +static void PrintError(const char *message, const FString &name) +{ + PrintError(message); + Print(name); +} + + +static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result) +{ + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, propID, &prop)) + if (prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt == VT_EMPTY) + result = false; + else + return E_FAIL; + return S_OK; +} + +static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) +{ + return IsArchiveItemProp(archive, index, kpidIsDir, result); +} + + +static const wchar_t * const kEmptyFileAlias = L"[Content]"; + + +////////////////////////////////////////////////////////////// +// Archive Open callback class + + +class CArchiveOpenCallback Z7_final: + public IArchiveOpenCallback, + public ICryptoGetTextPassword, + public CMyUnknownImp +{ + Z7_IFACES_IMP_UNK_2(IArchiveOpenCallback, ICryptoGetTextPassword) +public: + + bool PasswordIsDefined; + UString Password; + + CArchiveOpenCallback() : PasswordIsDefined(false) {} +}; + +Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)) +{ + if (!PasswordIsDefined) + { + // You can ask real password here from user +#if 0 + RINOK(GetPassword_HRESULT(&g_StdOut, Password)) + PasswordIsDefined = true; +#else + PrintError("Password is not defined"); + return E_ABORT; +#endif + } + return StringToBstr(Password, password); +} + + + +static const char * const kIncorrectCommand = "incorrect command"; + +////////////////////////////////////////////////////////////// +// Archive Extracting callback class + +static const char * const kTestingString = "Testing "; +static const char * const kExtractingString = "Extracting "; +static const char * const kSkippingString = "Skipping "; +static const char * const kReadingString = "Reading "; + +static const char * const kUnsupportedMethod = "Unsupported Method"; +static const char * const kCRCFailed = "CRC Failed"; +static const char * const kDataError = "Data Error"; +static const char * const kUnavailableData = "Unavailable data"; +static const char * const kUnexpectedEnd = "Unexpected end of data"; +static const char * const kDataAfterEnd = "There are some data after the end of the payload data"; +static const char * const kIsNotArc = "Is not archive"; +static const char * const kHeadersError = "Headers Error"; + + +struct CArcTime +{ + FILETIME FT; + UInt16 Prec; + Byte Ns100; + bool Def; + + CArcTime() + { + Clear(); + } + + void Clear() + { + FT.dwHighDateTime = FT.dwLowDateTime = 0; + Prec = 0; + Ns100 = 0; + Def = false; + } + + bool IsZero() const + { + return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0; + } + + int GetNumDigits() const + { + if (Prec == k_PropVar_TimePrec_Unix || + Prec == k_PropVar_TimePrec_DOS) + return 0; + if (Prec == k_PropVar_TimePrec_HighPrec) + return 9; + if (Prec == k_PropVar_TimePrec_0) + return 7; + int digits = (int)Prec - (int)k_PropVar_TimePrec_Base; + if (digits < 0) + digits = 0; + return digits; + } + + void Write_To_FiTime(CFiTime &dest) const + { + #ifdef _WIN32 + dest = FT; + #else + if (FILETIME_To_timespec(FT, dest)) + if ((Prec == k_PropVar_TimePrec_Base + 8 || + Prec == k_PropVar_TimePrec_Base + 9) + && Ns100 != 0) + { + dest.tv_nsec += Ns100; + } + #endif + } + + void Set_From_Prop(const PROPVARIANT &prop) + { + FT = prop.filetime; + unsigned prec = 0; + unsigned ns100 = 0; + const unsigned prec_Temp = prop.wReserved1; + if (prec_Temp != 0 + && prec_Temp <= k_PropVar_TimePrec_1ns + && prop.wReserved3 == 0) + { + const unsigned ns100_Temp = prop.wReserved2; + if (ns100_Temp < 100) + { + ns100 = ns100_Temp; + prec = prec_Temp; + } + } + Prec = (UInt16)prec; + Ns100 = (Byte)ns100; + Def = true; + } +}; + + + +class CArchiveExtractCallback Z7_final: + public IArchiveExtractCallback, + public ICryptoGetTextPassword, + public CMyUnknownImp +{ + Z7_IFACES_IMP_UNK_2(IArchiveExtractCallback, ICryptoGetTextPassword) + Z7_IFACE_COM7_IMP(IProgress) + + CMyComPtr _archiveHandler; + FString _directoryPath; // Output directory + UString _filePath; // name inside arcvhive + FString _diskFilePath; // full path to file on disk + bool _extractMode; + struct CProcessedFileInfo + { + CArcTime MTime; + UInt32 Attrib; + bool isDir; + bool Attrib_Defined; + } _processedFileInfo; + + COutFileStream *_outFileStreamSpec; + CMyComPtr _outFileStream; + +public: + void Init(IInArchive *archiveHandler, const FString &directoryPath); + + UInt64 NumErrors; + bool PasswordIsDefined; + UString Password; + + CArchiveExtractCallback() : PasswordIsDefined(false) {} +}; + +void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath) +{ + NumErrors = 0; + _archiveHandler = archiveHandler; + _directoryPath = directoryPath; + NName::NormalizeDirPathPrefix(_directoryPath); +} + +Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 /* size */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, + ISequentialOutStream **outStream, Int32 askExtractMode)) +{ + *outStream = NULL; + _outFileStream.Release(); + + { + // Get Name + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop)) + + UString fullPath; + if (prop.vt == VT_EMPTY) + fullPath = kEmptyFileAlias; + else + { + if (prop.vt != VT_BSTR) + return E_FAIL; + fullPath = prop.bstrVal; + } + _filePath = fullPath; + } + + if (askExtractMode != NArchive::NExtract::NAskMode::kExtract) + return S_OK; + + { + // Get Attrib + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop)) + if (prop.vt == VT_EMPTY) + { + _processedFileInfo.Attrib = 0; + _processedFileInfo.Attrib_Defined = false; + } + else + { + if (prop.vt != VT_UI4) + return E_FAIL; + _processedFileInfo.Attrib = prop.ulVal; + _processedFileInfo.Attrib_Defined = true; + } + } + + RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir)) + + { + _processedFileInfo.MTime.Clear(); + // Get Modified Time + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)) + switch (prop.vt) + { + case VT_EMPTY: + // _processedFileInfo.MTime = _utcMTimeDefault; + break; + case VT_FILETIME: + _processedFileInfo.MTime.Set_From_Prop(prop); + break; + default: + return E_FAIL; + } + + } + { + // Get Size + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop)) + UInt64 newFileSize; + /* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize); + } + + + { + // Create folders for file + int slashPos = _filePath.ReverseFind_PathSepar(); + if (slashPos >= 0) + CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos))); + } + + FString fullProcessedPath = _directoryPath + us2fs(_filePath); + _diskFilePath = fullProcessedPath; + + if (_processedFileInfo.isDir) + { + CreateComplexDir(fullProcessedPath); + } + else + { + NFind::CFileInfo fi; + if (fi.Find(fullProcessedPath)) + { + if (!DeleteFileAlways(fullProcessedPath)) + { + PrintError("Cannot delete output file", fullProcessedPath); + return E_ABORT; + } + } + + _outFileStreamSpec = new COutFileStream; + CMyComPtr outStreamLoc(_outFileStreamSpec); + if (!_outFileStreamSpec->Create_ALWAYS(fullProcessedPath)) + { + PrintError("Cannot open output file", fullProcessedPath); + return E_ABORT; + } + _outFileStream = outStreamLoc; + *outStream = outStreamLoc.Detach(); + } + return S_OK; +} + +Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)) +{ + _extractMode = false; + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break; + } + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break; + case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break; + case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break; + case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break; + default: + Print("??? "); break; + } + Print(_filePath); + return S_OK; +} + +Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 operationResult)) +{ + switch (operationResult) + { + case NArchive::NExtract::NOperationResult::kOK: + break; + default: + { + NumErrors++; + Print(" : "); + const char *s = NULL; + switch (operationResult) + { + case NArchive::NExtract::NOperationResult::kUnsupportedMethod: + s = kUnsupportedMethod; + break; + case NArchive::NExtract::NOperationResult::kCRCError: + s = kCRCFailed; + break; + case NArchive::NExtract::NOperationResult::kDataError: + s = kDataError; + break; + case NArchive::NExtract::NOperationResult::kUnavailable: + s = kUnavailableData; + break; + case NArchive::NExtract::NOperationResult::kUnexpectedEnd: + s = kUnexpectedEnd; + break; + case NArchive::NExtract::NOperationResult::kDataAfterEnd: + s = kDataAfterEnd; + break; + case NArchive::NExtract::NOperationResult::kIsNotArc: + s = kIsNotArc; + break; + case NArchive::NExtract::NOperationResult::kHeadersError: + s = kHeadersError; + break; + } + if (s) + { + Print("Error : "); + Print(s); + } + else + { + char temp[16]; + ConvertUInt32ToString((UInt32)operationResult, temp); + Print("Error #"); + Print(temp); + } + } + } + + if (_outFileStream) + { + if (_processedFileInfo.MTime.Def) + { + CFiTime ft; + _processedFileInfo.MTime.Write_To_FiTime(ft); + _outFileStreamSpec->SetMTime(&ft); + } + RINOK(_outFileStreamSpec->Close()) + } + _outFileStream.Release(); + if (_extractMode && _processedFileInfo.Attrib_Defined) + SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib); + PrintNewLine(); + return S_OK; +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)) +{ + if (!PasswordIsDefined) + { +#if 0 + // You can ask real password here from user + RINOK(GetPassword_HRESULT(&g_StdOut, Password)) + PasswordIsDefined = true; +#else + PrintError("Password is not defined"); + return E_ABORT; +#endif + } + return StringToBstr(Password, password); +} + + + +////////////////////////////////////////////////////////////// +// Archive Creating callback class + +struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase +{ + UString Path_For_Handler; + FString FullPath; // for filesystem + + CDirItem(const NWindows::NFile::NFind::CFileInfo &fi): + CFileInfoBase(fi) + {} +}; + +class CArchiveUpdateCallback Z7_final: + public IArchiveUpdateCallback2, + public ICryptoGetTextPassword2, + public CMyUnknownImp +{ + Z7_IFACES_IMP_UNK_2(IArchiveUpdateCallback2, ICryptoGetTextPassword2) + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IArchiveUpdateCallback) + +public: + CRecordVector VolumesSizes; + UString VolName; + UString VolExt; + + FString DirPrefix; + const CObjectVector *DirItems; + + bool PasswordIsDefined; + UString Password; + bool AskPassword; + + bool m_NeedBeClosed; + + FStringVector FailedFiles; + CRecordVector FailedCodes; + + CArchiveUpdateCallback(): + DirItems(NULL), + PasswordIsDefined(false), + AskPassword(false) + {} + + ~CArchiveUpdateCallback() { Finilize(); } + HRESULT Finilize(); + + void Init(const CObjectVector *dirItems) + { + DirItems = dirItems; + m_NeedBeClosed = false; + FailedFiles.Clear(); + FailedCodes.Clear(); + } +}; + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 /* size */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, + Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)) +{ + if (newData) + *newData = BoolToInt(true); + if (newProperties) + *newProperties = BoolToInt(true); + if (indexInArchive) + *indexInArchive = (UInt32)(Int32)-1; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + + if (propID == kpidIsAnti) + { + prop = false; + prop.Detach(value); + return S_OK; + } + + { + const CDirItem &di = (*DirItems)[index]; + switch (propID) + { + case kpidPath: prop = di.Path_For_Handler; break; + case kpidIsDir: prop = di.IsDir(); break; + case kpidSize: prop = di.Size; break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; + case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break; + case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break; + } + } + prop.Detach(value); + return S_OK; +} + +HRESULT CArchiveUpdateCallback::Finilize() +{ + if (m_NeedBeClosed) + { + PrintNewLine(); + m_NeedBeClosed = false; + } + return S_OK; +} + +static void GetStream2(const wchar_t *name) +{ + Print("Compressing "); + if (name[0] == 0) + name = kEmptyFileAlias; + Print(name); +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)) +{ + RINOK(Finilize()) + + const CDirItem &dirItem = (*DirItems)[index]; + GetStream2(dirItem.Path_For_Handler); + + if (dirItem.IsDir()) + return S_OK; + + { + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStreamLoc(inStreamSpec); + FString path = DirPrefix + dirItem.FullPath; + if (!inStreamSpec->Open(path)) + { + const DWORD sysError = ::GetLastError(); + FailedCodes.Add(HRESULT_FROM_WIN32(sysError)); + FailedFiles.Add(path); + // if (systemError == ERROR_SHARING_VIOLATION) + { + PrintNewLine(); + PrintError("WARNING: can't open file"); + // Print(NError::MyFormatMessageW(systemError)); + return S_FALSE; + } + // return sysError; + } + *inStream = inStreamLoc.Detach(); + } + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */)) +{ + m_NeedBeClosed = true; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)) +{ + if (VolumesSizes.Size() == 0) + return S_FALSE; + if (index >= (UInt32)VolumesSizes.Size()) + index = VolumesSizes.Size() - 1; + *size = VolumesSizes[index]; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) +{ + wchar_t temp[16]; + ConvertUInt32ToString(index + 1, temp); + UString res = temp; + while (res.Len() < 2) + res.InsertAtFront(L'0'); + UString fileName = VolName; + fileName.Add_Dot(); + fileName += res; + fileName += VolExt; + COutFileStream *streamSpec = new COutFileStream; + CMyComPtr streamLoc(streamSpec); + if (!streamSpec->Create_NEW(us2fs(fileName))) + return GetLastError_noZero_HRESULT(); + *volumeStream = streamLoc.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) +{ + if (!PasswordIsDefined) + { + if (AskPassword) + { +#if 0 + RINOK(GetPassword_HRESULT(&g_StdOut, Password)) + PasswordIsDefined = true; +#else + PrintError("Password is not defined"); + return E_ABORT; +#endif + } + } + *passwordIsDefined = BoolToInt(PasswordIsDefined); + return StringToBstr(Password, password); +} + + +// Main function + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1; +#endif + +int Z7_CDECL main(int numArgs, const char *args[]) +{ + NT_CHECK + + #ifdef ENV_HAVE_LOCALE + MY_SetLocale(); + #endif + + PrintStringLn(kCopyrightString); + + if (numArgs < 2) + { + PrintStringLn(kHelpString); + return 0; + } + + FString dllPrefix; + + #ifdef _WIN32 + dllPrefix = NDLL::GetModuleDirPrefix(); + #else + { + AString s (args[0]); + int sep = s.ReverseFind_PathSepar(); + s.DeleteFrom(sep + 1); + dllPrefix = s; + } + #endif + + NDLL::CLibrary lib; + if (!lib.Load(dllPrefix + FTEXT(kDllName))) + { + PrintError("Cannot load 7-zip library"); + return 1; + } + +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#ifdef _WIN32 +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +#endif + + Func_CreateObject + f_CreateObject = Z7_GET_PROC_ADDRESS( + Func_CreateObject, lib.Get_HMODULE(), + "CreateObject"); + if (!f_CreateObject) + { + PrintError("Cannot get CreateObject"); + return 1; + } + + char c = 0; + UString password; + bool passwordIsDefined = false; + CObjectVector params; + + for (int curCmd = 1; curCmd < numArgs; curCmd++) + { + AString a(args[curCmd]); + + if (!a.IsEmpty()) + { + if (a[0] == '-') + { + if (!passwordIsDefined && a[1] == 'p') + { + password = GetUnicodeString(a.Ptr(2)); + passwordIsDefined = true; + continue; + } + } + else + { + if (c) + { + params.Add(CmdStringToFString(a)); + continue; + } + if (a.Len() == 1) + { + c = (char)MyCharLower_Ascii(a[0]); + continue; + } + } + } + { + PrintError(kIncorrectCommand); + return 1; + } + } + + if (!c || params.Size() < 1) + { + PrintError(kIncorrectCommand); + return 1; + } + + const FString &archiveName = params[0]; + + if (c == 'a') + { + // create archive command + if (params.Size() < 2) + { + PrintError(kIncorrectCommand); + return 1; + } + CObjectVector dirItems; + { + unsigned i; + for (i = 1; i < params.Size(); i++) + { + const FString &name = params[i]; + + NFind::CFileInfo fi; + if (!fi.Find(name)) + { + PrintError("Can't find file", name); + return 1; + } + + CDirItem di(fi); + + di.Path_For_Handler = fs2us(name); + di.FullPath = name; + dirItems.Add(di); + } + } + + COutFileStream *outFileStreamSpec = new COutFileStream; + CMyComPtr outFileStream = outFileStreamSpec; + if (!outFileStreamSpec->Create_NEW(archiveName)) + { + PrintError("can't create archive file"); + return 1; + } + + CMyComPtr outArchive; + if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK) + { + PrintError("Cannot get class object"); + return 1; + } + + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr updateCallback(updateCallbackSpec); + updateCallbackSpec->Init(&dirItems); + updateCallbackSpec->PasswordIsDefined = passwordIsDefined; + updateCallbackSpec->Password = password; + + /* + { + const wchar_t *names[] = + { + L"m", + L"s", + L"x" + }; + const unsigned kNumProps = Z7_ARRAY_SIZE(names); + NCOM::CPropVariant values[kNumProps] = + { + L"lzma", + false, // solid mode OFF + (UInt32)9 // compression level = 9 - ultra + }; + CMyComPtr setProperties; + outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties); + if (!setProperties) + { + PrintError("ISetProperties unsupported"); + return 1; + } + if (setProperties->SetProperties(names, values, kNumProps) != S_OK) + { + PrintError("SetProperties() error"); + return 1; + } + } + */ + + HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback); + + updateCallbackSpec->Finilize(); + + if (result != S_OK) + { + PrintError("Update Error"); + return 1; + } + + FOR_VECTOR (i, updateCallbackSpec->FailedFiles) + { + PrintNewLine(); + PrintError("Error for file", updateCallbackSpec->FailedFiles[i]); + } + + if (updateCallbackSpec->FailedFiles.Size() != 0) + return 1; + } + else + { + if (params.Size() != 1) + { + PrintError(kIncorrectCommand); + return 1; + } + + bool listCommand; + + if (c == 'l') + listCommand = true; + else if (c == 'x') + listCommand = false; + else + { + PrintError(kIncorrectCommand); + return 1; + } + + CMyComPtr archive; + if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK) + { + PrintError("Cannot get class object"); + return 1; + } + + CInFileStream *fileSpec = new CInFileStream; + CMyComPtr file = fileSpec; + + if (!fileSpec->Open(archiveName)) + { + PrintError("Cannot open archive file", archiveName); + return 1; + } + + { + CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback; + CMyComPtr openCallback(openCallbackSpec); + openCallbackSpec->PasswordIsDefined = passwordIsDefined; + openCallbackSpec->Password = password; + + const UInt64 scanSize = 1 << 23; + if (archive->Open(file, &scanSize, openCallback) != S_OK) + { + PrintError("Cannot open file as archive", archiveName); + return 1; + } + } + + if (listCommand) + { + // List command + UInt32 numItems = 0; + archive->GetNumberOfItems(&numItems); + for (UInt32 i = 0; i < numItems; i++) + { + { + // Get uncompressed size of file + NCOM::CPropVariant prop; + archive->GetProperty(i, kpidSize, &prop); + char s[64]; + ConvertPropVariantToShortString(prop, s); + Print(s); + Print(" "); + } + { + // Get name of file + NCOM::CPropVariant prop; + archive->GetProperty(i, kpidPath, &prop); + if (prop.vt == VT_BSTR) + Print(prop.bstrVal); + else if (prop.vt != VT_EMPTY) + Print("ERROR!"); + } + PrintNewLine(); + } + } + else + { + // Extract command + CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; + CMyComPtr extractCallback(extractCallbackSpec); + extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path + extractCallbackSpec->PasswordIsDefined = passwordIsDefined; + extractCallbackSpec->Password = password; + + /* + const wchar_t *names[] = + { + L"mt", + L"mtf" + }; + const unsigned kNumProps = sizeof(names) / sizeof(names[0]); + NCOM::CPropVariant values[kNumProps] = + { + (UInt32)1, + false + }; + CMyComPtr setProperties; + archive->QueryInterface(IID_ISetProperties, (void **)&setProperties); + if (setProperties) + { + if (setProperties->SetProperties(names, values, kNumProps) != S_OK) + { + PrintError("SetProperties() error"); + return 1; + } + } + */ + + HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback); + + if (result != S_OK) + { + PrintError("Extract Error"); + return 1; + } + } + } + + return 0; +} diff --git a/CPP/7zip/UI/Client7z/Client7z.dsp b/CPP/7zip/UI/Client7z/Client7z.dsp index 92cc75e2c..1b5826f4c 100644 --- a/CPP/7zip/UI/Client7z/Client7z.dsp +++ b/CPP/7zip/UI/Client7z/Client7z.dsp @@ -1,331 +1,331 @@ -# Microsoft Developer Studio Project File - Name="Client7z" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=Client7z - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Client7z.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Client7z.mak" CFG="Client7z - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Client7z - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "Client7z - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Client7z - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zcl.exe" - -!ELSEIF "$(CFG)" == "Client7z - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zcl.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "Client7z - Win32 Release" -# Name "Client7z - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"stdafx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyLinux.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "7zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# End Group -# Begin Group "7zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\Client7z.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="Client7z" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Client7z - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Client7z.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Client7z.mak" CFG="Client7z - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Client7z - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Client7z - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Client7z - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zcl.exe" + +!ELSEIF "$(CFG)" == "Client7z - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zcl.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Client7z - Win32 Release" +# Name "Client7z - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyLinux.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "7zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# End Group +# Begin Group "7zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\Client7z.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/UI/Client7z/Client7z.dsw b/CPP/7zip/UI/Client7z/Client7z.dsw index 4c2685118..598a6d3fb 100644 --- a/CPP/7zip/UI/Client7z/Client7z.dsw +++ b/CPP/7zip/UI/Client7z/Client7z.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Client7z"=.\Client7z.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Client7z"=.\Client7z.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/UI/Client7z/StdAfx.cpp b/CPP/7zip/UI/Client7z/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/Client7z/StdAfx.cpp +++ b/CPP/7zip/UI/Client7z/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/Client7z/StdAfx.h b/CPP/7zip/UI/Client7z/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/UI/Client7z/StdAfx.h +++ b/CPP/7zip/UI/Client7z/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Client7z/makefile b/CPP/7zip/UI/Client7z/makefile index 347c42726..9eff26290 100644 --- a/CPP/7zip/UI/Client7z/makefile +++ b/CPP/7zip/UI/Client7z/makefile @@ -1,29 +1,29 @@ -PROG = 7zcl.exe -MY_CONSOLE = 1 - -CURRENT_OBJS = \ - $O\Client7z.obj \ - -COMMON_OBJS = \ - $O\IntToString.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\FileStreams.obj \ - -!include "../../7zip.mak" +PROG = 7zcl.exe +MY_CONSOLE = 1 + +CURRENT_OBJS = \ + $O\Client7z.obj \ + +COMMON_OBJS = \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\FileStreams.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/Client7z/makefile.gcc b/CPP/7zip/UI/Client7z/makefile.gcc index 013b64481..fe270114d 100644 --- a/CPP/7zip/UI/Client7z/makefile.gcc +++ b/CPP/7zip/UI/Client7z/makefile.gcc @@ -1,69 +1,72 @@ -PROG = 7zcl -IS_NOT_STANDALONE = 1 - -# IS_X64 = 1 - - - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - - -ifdef IS_MINGW - -SYS_OBJS = \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - $O/TimeUtils.o \ - -endif - - -LOCAL_FLAGS = \ - - -CURRENT_OBJS = \ - $O/Client7z.o \ - -COMMON_OBJS = \ - $O/IntToString.o \ - $O/MyString.o \ - $O/MyVector.o \ - $O/NewHandler.o \ - $O/StringConvert.o \ - $O/StringToInt.o \ - $O/UTFConvert.o \ - $O/Wildcard.o \ - -WIN_OBJS = \ - $O/DLL.o \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileIO.o \ - $O/FileName.o \ - $O/PropVariant.o \ - $O/PropVariantConv.o \ - -7ZIP_COMMON_OBJS = \ - $O/FileStreams.o \ - - -OBJS = \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(SYS_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(CURRENT_OBJS) \ - - -include ../../7zip_gcc.mak +PROG = 7zcl +IS_NOT_STANDALONE = 1 + +# IS_X64 = 1 + + + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + + +ifdef IS_MINGW + +SYS_OBJS = \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + $O/TimeUtils.o \ + +endif + + +LOCAL_FLAGS = \ + + +CURRENT_OBJS = \ + $O/Client7z.o \ + +COMMON_OBJS = \ + $O/IntToString.o \ + $O/MyString.o \ + $O/MyVector.o \ + $O/NewHandler.o \ + $O/StringConvert.o \ + $O/StringToInt.o \ + $O/UTFConvert.o \ + $O/Wildcard.o \ + +WIN_OBJS = \ + $O/DLL.o \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileIO.o \ + $O/FileName.o \ + $O/PropVariant.o \ + $O/PropVariantConv.o \ + +7ZIP_COMMON_OBJS = \ + $O/FileStreams.o \ + +C_OBJS = \ + $O/Alloc.o \ + +OBJS = \ + $(C_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(SYS_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(CURRENT_OBJS) \ + + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/UI/Client7z/resource.rc b/CPP/7zip/UI/Client7z/resource.rc index 701a783e0..462df6fa7 100644 --- a/CPP/7zip/UI/Client7z/resource.rc +++ b/CPP/7zip/UI/Client7z/resource.rc @@ -1,3 +1,3 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("7-Zip client" , "7zcl") +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("7-Zip client" , "7zcl") diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index 45baca503..556b25ac0 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -1,1769 +1,1769 @@ -// ArchiveCommandLine.cpp - -#include "StdAfx.h" -#undef printf -#undef sprintf - -#ifdef _WIN32 -#ifndef UNDER_CE -#include -#endif -#else -// for isatty() -#include -#endif - -#include - -#ifdef Z7_LARGE_PAGES -#include "../../../../C/Alloc.h" -#endif - -#include "../../../Common/IntToString.h" -#include "../../../Common/ListFileUtils.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariantConv.h" -#include "../../../Windows/System.h" -#ifdef _WIN32 -#include "../../../Windows/FileMapping.h" -#include "../../../Windows/MemoryLock.h" -#include "../../../Windows/Synchronization.h" -#endif - -#include "ArchiveCommandLine.h" -#include "EnumDirItems.h" -#include "Update.h" -#include "UpdateAction.h" - -extern bool g_CaseSensitive; -extern bool g_PathTrailReplaceMode; - -#ifdef Z7_LARGE_PAGES -extern -bool g_LargePagesMode; -bool g_LargePagesMode = false; -#endif - -/* -#ifdef ENV_HAVE_LSTAT -EXTERN_C_BEGIN -extern int global_use_lstat; -EXTERN_C_END -#endif -*/ - -#ifdef UNDER_CE - -#define MY_IS_TERMINAL(x) false; - -#else - -// #define MY_isatty_fileno(x) (isatty(fileno(x))) -// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); -static inline bool MY_IS_TERMINAL(FILE *x) -{ - return ( - #if defined(_MSC_VER) && (_MSC_VER >= 1400) - _isatty(_fileno(x)) - #else - isatty(fileno(x)) - #endif - != 0); -} - -#endif - -using namespace NCommandLineParser; -using namespace NWindows; -using namespace NFile; - -static bool StringToUInt32(const wchar_t *s, UInt32 &v) -{ - if (*s == 0) - return false; - const wchar_t *end; - v = ConvertStringToUInt32(s, &end); - return *end == 0; -} - - -namespace NKey { -enum Enum -{ - kHelp1 = 0, - kHelp2, - kHelp3, - - kDisableHeaders, - kDisablePercents, - kShowTime, - kLogLevel, - - kOutStream, - kErrStream, - kPercentStream, - - kYes, - - kShowDialog, - kOverwrite, - - kArchiveType, - kExcludedArcType, - - kProperty, - kOutputDir, - kWorkingDir, - - kInclude, - kExclude, - kArInclude, - kArExclude, - kNoArName, - - kUpdate, - kVolume, - kRecursed, - - kAffinity, - kSfx, - kEmail, - kHash, - // kHashGenFile, - kHashDir, - kExtractMemLimit, - - kStdIn, - kStdOut, - - kLargePages, - kListfileCharSet, - kConsoleCharSet, - kTechMode, - kListFields, - kListPathSlash, - kListTimestampUTC, - - kPreserveATime, - kShareForWrite, - kStopAfterOpenError, - kCaseSensitive, - kArcNameMode, - - kUseSlashMark, - kDisableWildcardParsing, - kElimDup, - kFullPathMode, - - kHardLinks, - kSymLinks_AllowDangerous, - kSymLinks, - kNtSecurity, - - kStoreOwnerId, - kStoreOwnerName, - - kZoneFile, - kAltStreams, - kReplaceColonForAltStream, - kWriteToAltStreamIfColon, - - kNameTrailReplace, - - kDeleteAfterCompressing, - kSetArcMTime - - #ifndef Z7_NO_CRYPTO - , kPassword - #endif -}; - -} - - -static const wchar_t kRecursedIDChar = 'r'; -static const char * const kRecursedPostCharSet = "0-"; - -static const char * const k_ArcNameMode_PostCharSet = "sea"; - -static const char * const k_Stream_PostCharSet = "012"; - -static inline EArcNameMode ParseArcNameMode(int postCharIndex) -{ - switch (postCharIndex) - { - case 1: return k_ArcNameMode_Exact; - case 2: return k_ArcNameMode_Add; - default: return k_ArcNameMode_Smart; - } -} - -namespace NRecursedPostCharIndex { - enum EEnum - { - kWildcardRecursionOnly = 0, - kNoRecursion = 1 - }; -} - -// static const char -#define kImmediateNameID '!' -#ifdef _WIN32 -#define kMapNameID '#' -#endif -#define kFileListID '@' - -static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be -static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be - -static const char * const kOverwritePostCharSet = "asut"; - -static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = -{ - NExtract::NOverwriteMode::kOverwrite, - NExtract::NOverwriteMode::kSkip, - NExtract::NOverwriteMode::kRename, - NExtract::NOverwriteMode::kRenameExisting -}; - - - -#define SWFRM_3(t, mu, mi) t, mu, mi, NULL - -#define SWFRM_1(t) SWFRM_3(t, false, 0) -#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple) -#define SWFRM_MINUS SWFRM_1(NSwitchType::kMinus) -#define SWFRM_STRING SWFRM_1(NSwitchType::kString) - -#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi) -#define SWFRM_STRING_MULT(mi) SWFRM_3(NSwitchType::kString, true, mi) - - -static const CSwitchForm kSwitchForms[] = -{ - { "?", SWFRM_SIMPLE }, - { "h", SWFRM_SIMPLE }, - { "-help", SWFRM_SIMPLE }, - - { "ba", SWFRM_SIMPLE }, - { "bd", SWFRM_SIMPLE }, - { "bt", SWFRM_SIMPLE }, - { "bb", SWFRM_STRING_SINGL(0) }, - - { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, - { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, - { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, - - { "y", SWFRM_SIMPLE }, - - { "ad", SWFRM_SIMPLE }, - { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet}, - - { "t", SWFRM_STRING_SINGL(1) }, - { "stx", SWFRM_STRING_MULT(1) }, - - { "m", SWFRM_STRING_MULT(1) }, - { "o", SWFRM_STRING_SINGL(1) }, - { "w", SWFRM_STRING }, - - { "i", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, - { "x", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, - { "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, - { "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, - { "an", SWFRM_SIMPLE }, - - { "u", SWFRM_STRING_MULT(1) }, - { "v", SWFRM_STRING_MULT(1) }, - { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet }, - - { "stm", SWFRM_STRING }, - { "sfx", SWFRM_STRING }, - { "seml", SWFRM_STRING_SINGL(0) }, - { "scrc", SWFRM_STRING_MULT(0) }, - // { "scrf", SWFRM_STRING_SINGL(1) }, - { "shd", SWFRM_STRING_SINGL(1) }, - { "smemx", SWFRM_STRING }, - - { "si", SWFRM_STRING }, - { "so", SWFRM_SIMPLE }, - - { "slp", SWFRM_STRING }, - { "scs", SWFRM_STRING }, - { "scc", SWFRM_STRING }, - { "slt", SWFRM_SIMPLE }, - { "slf", SWFRM_STRING_SINGL(1) }, - { "slsl", SWFRM_MINUS }, - { "slmu", SWFRM_MINUS }, - - { "ssp", SWFRM_SIMPLE }, - { "ssw", SWFRM_SIMPLE }, - { "sse", SWFRM_SIMPLE }, - { "ssc", SWFRM_MINUS }, - { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, - - { "spm", SWFRM_STRING_SINGL(0) }, - { "spd", SWFRM_SIMPLE }, - { "spe", SWFRM_MINUS }, - { "spf", SWFRM_STRING_SINGL(0) }, - - { "snh", SWFRM_MINUS }, - { "snld", SWFRM_MINUS }, - { "snl", SWFRM_MINUS }, - { "sni", SWFRM_SIMPLE }, - - { "snoi", SWFRM_MINUS }, - { "snon", SWFRM_MINUS }, - - { "snz", SWFRM_STRING_SINGL(0) }, - { "sns", SWFRM_MINUS }, - { "snr", SWFRM_SIMPLE }, - { "snc", SWFRM_SIMPLE }, - - { "snt", SWFRM_MINUS }, - - { "sdel", SWFRM_SIMPLE }, - { "stl", SWFRM_SIMPLE } - - #ifndef Z7_NO_CRYPTO - , { "p", SWFRM_STRING } - #endif -}; - -static const char * const kUniversalWildcard = "*"; -static const unsigned kMinNonSwitchWords = 1; -static const unsigned kCommandIndex = 0; - -// static const char * const kUserErrorMessage = "Incorrect command line"; -// static const char * const kCannotFindListFile = "Cannot find listfile"; -static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; -static const char * const kTerminalOutError = "I won't write compressed data to a terminal"; -static const char * const kSameTerminalError = "I won't write data and program's messages to same stream"; -static const char * const kEmptyFilePath = "Empty file path"; - -bool CArcCommand::IsFromExtractGroup() const -{ - switch ((int)CommandType) - { - case NCommandType::kTest: - case NCommandType::kExtract: - case NCommandType::kExtractFull: - return true; - default: - return false; - } -} - -NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const -{ - switch ((int)CommandType) - { - case NCommandType::kTest: - case NCommandType::kExtractFull: - return NExtract::NPathMode::kFullPaths; - default: - return NExtract::NPathMode::kNoPaths; - } -} - -bool CArcCommand::IsFromUpdateGroup() const -{ - switch ((int)CommandType) - { - case NCommandType::kAdd: - case NCommandType::kUpdate: - case NCommandType::kDelete: - case NCommandType::kRename: - return true; - default: - return false; - } -} - -static NRecursedType::EEnum GetRecursedTypeFromIndex(int index) -{ - switch (index) - { - case NRecursedPostCharIndex::kWildcardRecursionOnly: - return NRecursedType::kWildcardOnlyRecursed; - case NRecursedPostCharIndex::kNoRecursion: - return NRecursedType::kNonRecursed; - default: - return NRecursedType::kRecursed; - } -} - -static const char *g_Commands = "audtexlbih"; - -static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command) -{ - UString s (commandString); - s.MakeLower_Ascii(); - if (s.Len() == 1) - { - if (s[0] > 0x7F) - return false; - int index = FindCharPosInString(g_Commands, (char)s[0]); - if (index < 0) - return false; - command.CommandType = (NCommandType::EEnum)index; - return true; - } - if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n') - { - command.CommandType = (NCommandType::kRename); - return true; - } - return false; -} - -// ------------------------------------------------------------------ -// filenames functions - -struct CNameOption -{ - bool Include; - bool WildcardMatching; - Byte MarkMode; - NRecursedType::EEnum RecursedType; - - CNameOption(): - Include(true), - WildcardMatching(true), - MarkMode(NWildcard::kMark_FileOrDir), - RecursedType(NRecursedType::kNonRecursed) - {} -}; - - -static void AddNameToCensor(NWildcard::CCensor &censor, - const CNameOption &nop, const UString &name) -{ - bool recursed = false; - - switch ((int)nop.RecursedType) - { - case NRecursedType::kWildcardOnlyRecursed: - recursed = DoesNameContainWildcard(name); - break; - case NRecursedType::kRecursed: - recursed = true; - break; - default: - break; - } - - NWildcard::CCensorPathProps props; - props.Recursive = recursed; - props.WildcardMatching = nop.WildcardMatching; - props.MarkMode = nop.MarkMode; - censor.AddPreItem(nop.Include, name, props); -} - -#ifndef Z7_EXTRACT_ONLY -static void AddRenamePair(CObjectVector *renamePairs, - const UString &oldName, const UString &newName, NRecursedType::EEnum type, - bool wildcardMatching) -{ - CRenamePair &pair = renamePairs->AddNew(); - pair.OldName = oldName; - pair.NewName = newName; - pair.RecursedType = type; - pair.WildcardParsing = wildcardMatching; - - if (!pair.Prepare()) - { - UString val; - val += pair.OldName; - val.Add_LF(); - val += pair.NewName; - val.Add_LF(); - if (type == NRecursedType::kRecursed) - val += "-r"; - else if (type == NRecursedType::kWildcardOnlyRecursed) - val += "-r0"; - throw CArcCmdLineException("Unsupported rename command:", val); - } -} -#endif - -static void AddToCensorFromListFile( - CObjectVector *renamePairs, - NWildcard::CCensor &censor, - const CNameOption &nop, LPCWSTR fileName, UInt32 codePage) -{ - UStringVector names; - /* - if (!NFind::DoesFileExist_FollowLink(us2fs(fileName))) - throw CArcCmdLineException(kCannotFindListFile, fileName); - */ - DWORD lastError = 0; - if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError)) - { - if (lastError != 0) - { - UString m; - m = "The file operation error for listfile"; - m.Add_LF(); - m += NError::MyFormatMessage(lastError); - throw CArcCmdLineException(m, fileName); - } - throw CArcCmdLineException(kIncorrectListFile, fileName); - } - if (renamePairs) - { - #ifndef Z7_EXTRACT_ONLY - if ((names.Size() & 1) != 0) - throw CArcCmdLineException(kIncorrectListFile, fileName); - for (unsigned i = 0; i < names.Size(); i += 2) - { - // change type !!!! - AddRenamePair(renamePairs, names[i], names[i + 1], nop.RecursedType, nop.WildcardMatching); - } - #else - throw "not implemented"; - #endif - } - else - FOR_VECTOR (i, names) - AddNameToCensor(censor, nop, names[i]); -} - -static void AddToCensorFromNonSwitchesStrings( - CObjectVector *renamePairs, - unsigned startIndex, - NWildcard::CCensor &censor, - const UStringVector &nonSwitchStrings, - int stopSwitchIndex, - const CNameOption &nop, - bool thereAreSwitchIncludes, UInt32 codePage) -{ - // another default - if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes) - { - /* for rename command: -i switch sets the mask for archive item reading. - if (thereAreSwitchIncludes), { we don't use UniversalWildcard. } - also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */ - // we use default fileds in (CNameOption) for UniversalWildcard. - CNameOption nop2; - // recursive mode is not important for UniversalWildcard (*) - // nop2.RecursedType = nop.RecursedType; // we don't need it - /* - nop2.RecursedType = NRecursedType::kNonRecursed; - nop2.Include = true; - nop2.WildcardMatching = true; - nop2.MarkMode = NWildcard::kMark_FileOrDir; - */ - AddNameToCensor(censor, nop2, UString(kUniversalWildcard)); - } - - int oldIndex = -1; - - if (stopSwitchIndex < 0) - stopSwitchIndex = (int)nonSwitchStrings.Size(); - - for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++) - { - const UString &s = nonSwitchStrings[i]; - if (s.IsEmpty()) - throw CArcCmdLineException(kEmptyFilePath); - if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID) - AddToCensorFromListFile(renamePairs, censor, nop, s.Ptr(1), codePage); - else if (renamePairs) - { - #ifndef Z7_EXTRACT_ONLY - if (oldIndex == -1) - oldIndex = (int)i; - else - { - // NRecursedType::EEnum type is used for global wildcard (-i! switches) - AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching); - // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type); - oldIndex = -1; - } - #else - throw "not implemented"; - #endif - } - else - AddNameToCensor(censor, nop, s); - } - - if (oldIndex != -1) - { - throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[(unsigned)oldIndex]); - } -} - -#ifdef _WIN32 - -struct CEventSetEnd -{ - UString Name; - - CEventSetEnd(const wchar_t *name): Name(name) {} - ~CEventSetEnd() - { - NSynchronization::CManualResetEvent event; - if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0) - event.Set(); - } -}; - -static const char * const k_IncorrectMapCommand = "Incorrect Map command"; - -static const char *ParseMapWithPaths( - NWildcard::CCensor &censor, - const UString &s2, - const CNameOption &nop) -{ - UString s (s2); - const int pos = s.Find(L':'); - if (pos < 0) - return k_IncorrectMapCommand; - const int pos2 = s.Find(L':', (unsigned)(pos + 1)); - if (pos2 < 0) - return k_IncorrectMapCommand; - - CEventSetEnd eventSetEnd((const wchar_t *)s + (unsigned)(pos2 + 1)); - s.DeleteFrom((unsigned)pos2); - UInt32 size; - if (!StringToUInt32(s.Ptr((unsigned)(pos + 1)), size) - || size < sizeof(wchar_t) - || size > ((UInt32)1 << 31) - || size % sizeof(wchar_t) != 0) - return "Unsupported Map data size"; - - s.DeleteFrom((unsigned)pos); - CFileMapping map; - if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0) - return "Cannot open mapping"; - const LPVOID data = map.Map(FILE_MAP_READ, 0, size); - if (!data) - return "MapViewOfFile error"; - CFileUnmapper unmapper(data); - - UString name; - const wchar_t *p = (const wchar_t *)data; - if (*p != 0) // data format marker - return "Unsupported Map data"; - const UInt32 numChars = size / sizeof(wchar_t); - for (UInt32 i = 1; i < numChars; i++) - { - const wchar_t c = p[i]; - if (c == 0) - { - // MessageBoxW(0, name, L"7-Zip", 0); - AddNameToCensor(censor, nop, name); - name.Empty(); - } - else - name += c; - } - if (!name.IsEmpty()) - return "Map data error"; - - return NULL; -} - -#endif - -static void AddSwitchWildcardsToCensor( - NWildcard::CCensor &censor, - const UStringVector &strings, - const CNameOption &nop, - UInt32 codePage) -{ - const char *errorMessage = NULL; - unsigned i; - for (i = 0; i < strings.Size(); i++) - { - const UString &name = strings[i]; - unsigned pos = 0; - - if (name.Len() < kSomeCludePostStringMinSize) - { - errorMessage = "Too short switch"; - break; - } - - if (!nop.Include) - { - if (name.IsEqualTo_Ascii_NoCase("td")) - { - censor.ExcludeDirItems = true; - continue; - } - if (name.IsEqualTo_Ascii_NoCase("tf")) - { - censor.ExcludeFileItems = true; - continue; - } - } - - CNameOption nop2 = nop; - - bool type_WasUsed = false; - bool recursed_WasUsed = false; - bool matching_WasUsed = false; - bool error = false; - - for (;;) - { - wchar_t c = ::MyCharLower_Ascii(name[pos]); - if (c == kRecursedIDChar) - { - if (recursed_WasUsed) - { - error = true; - break; - } - recursed_WasUsed = true; - pos++; - c = name[pos]; - int index = -1; - if (c <= 0x7F) - index = FindCharPosInString(kRecursedPostCharSet, (char)c); - nop2.RecursedType = GetRecursedTypeFromIndex(index); - if (index >= 0) - { - pos++; - continue; - } - } - - if (c == 'w') - { - if (matching_WasUsed) - { - error = true; - break; - } - matching_WasUsed = true; - nop2.WildcardMatching = true; - pos++; - if (name[pos] == '-') - { - nop2.WildcardMatching = false; - pos++; - } - } - else if (c == 'm') - { - if (type_WasUsed) - { - error = true; - break; - } - type_WasUsed = true; - pos++; - nop2.MarkMode = NWildcard::kMark_StrictFile; - c = name[pos]; - if (c == '-') - { - nop2.MarkMode = NWildcard::kMark_FileOrDir; - pos++; - } - else if (c == '2') - { - nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; - pos++; - } - } - else - break; - } - - if (error) - { - errorMessage = "inorrect switch"; - break; - } - - if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize) - { - errorMessage = "Too short switch"; - break; - } - - const UString tail = name.Ptr(pos + 1); - - const wchar_t c = name[pos]; - - if (c == kImmediateNameID) - AddNameToCensor(censor, nop2, tail); - else if (c == kFileListID) - AddToCensorFromListFile(NULL, censor, nop2, tail, codePage); - #ifdef _WIN32 - else if (c == kMapNameID) - { - errorMessage = ParseMapWithPaths(censor, tail, nop2); - if (errorMessage) - break; - } - #endif - else - { - errorMessage = "Incorrect wildcard type marker"; - break; - } - } - - if (i != strings.Size()) - throw CArcCmdLineException(errorMessage, strings[i]); -} - -/* -static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i) -{ - switch (i) - { - case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore; - case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy; - case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress; - case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti; - } - throw 98111603; -} -*/ - -static const char * const kUpdatePairStateIDSet = "pqrxyzw"; -static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; - -static const unsigned kNumUpdatePairActions = 4; -static const char * const kUpdateIgnoreItselfPostStringID = "-"; -static const wchar_t kUpdateNewArchivePostCharID = '!'; - - -static bool ParseUpdateCommandString2(const UString &command, - NUpdateArchive::CActionSet &actionSet, UString &postString) -{ - for (unsigned i = 0; i < command.Len();) - { - wchar_t c = MyCharLower_Ascii(command[i]); - int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c); - if (c > 0x7F || statePos < 0) - { - postString = command.Ptr(i); - return true; - } - i++; - if (i >= command.Len()) - return false; - c = command[i]; - if (c < '0' || c >= (wchar_t)('0' + kNumUpdatePairActions)) - return false; - unsigned actionPos = (unsigned)(c - '0'); - actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos); - if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos) - return false; - i++; - } - postString.Empty(); - return true; -} - -static void ParseUpdateCommandString(CUpdateOptions &options, - const UStringVector &updatePostStrings, - const NUpdateArchive::CActionSet &defaultActionSet) -{ - const char *errorMessage = "incorrect update switch command"; - unsigned i; - for (i = 0; i < updatePostStrings.Size(); i++) - { - const UString &updateString = updatePostStrings[i]; - if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID)) - { - if (options.UpdateArchiveItself) - { - options.UpdateArchiveItself = false; - options.Commands.Delete(0); - } - } - else - { - NUpdateArchive::CActionSet actionSet = defaultActionSet; - - UString postString; - if (!ParseUpdateCommandString2(updateString, actionSet, postString)) - break; - if (postString.IsEmpty()) - { - if (options.UpdateArchiveItself) - options.Commands[0].ActionSet = actionSet; - } - else - { - if (postString[0] != kUpdateNewArchivePostCharID) - break; - CUpdateArchiveCommand uc; - UString archivePath = postString.Ptr(1); - if (archivePath.IsEmpty()) - break; - uc.UserArchivePath = archivePath; - uc.ActionSet = actionSet; - options.Commands.Add(uc); - } - } - } - if (i != updatePostStrings.Size()) - throw CArcCmdLineException(errorMessage, updatePostStrings[i]); -} - -bool ParseComplexSize(const wchar_t *s, UInt64 &result); - -static void SetAddCommandOptions( - NCommandType::EEnum commandType, - const CParser &parser, - CUpdateOptions &options) -{ - NUpdateArchive::CActionSet defaultActionSet; - switch ((int)commandType) - { - case NCommandType::kAdd: - defaultActionSet = NUpdateArchive::k_ActionSet_Add; - break; - case NCommandType::kDelete: - defaultActionSet = NUpdateArchive::k_ActionSet_Delete; - break; - default: - defaultActionSet = NUpdateArchive::k_ActionSet_Update; - } - - options.UpdateArchiveItself = true; - - options.Commands.Clear(); - CUpdateArchiveCommand updateMainCommand; - updateMainCommand.ActionSet = defaultActionSet; - options.Commands.Add(updateMainCommand); - if (parser[NKey::kUpdate].ThereIs) - ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, - defaultActionSet); - if (parser[NKey::kWorkingDir].ThereIs) - { - const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; - if (postString.IsEmpty()) - NDir::MyGetTempPath(options.WorkingDir); - else - options.WorkingDir = us2fs(postString); - } - options.SfxMode = parser[NKey::kSfx].ThereIs; - if (options.SfxMode) - options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]); - - if (parser[NKey::kVolume].ThereIs) - { - const UStringVector &sv = parser[NKey::kVolume].PostStrings; - FOR_VECTOR (i, sv) - { - UInt64 size; - if (!ParseComplexSize(sv[i], size)) - throw CArcCmdLineException("Incorrect volume size:", sv[i]); - if (i == sv.Size() - 1 && size == 0) - throw CArcCmdLineException("zero size last volume is not allowed"); - options.VolumesSizes.Add(size); - } - } -} - -static void SetMethodOptions(const CParser &parser, CObjectVector &properties) -{ - if (parser[NKey::kProperty].ThereIs) - { - FOR_VECTOR (i, parser[NKey::kProperty].PostStrings) - { - CProperty prop; - prop.Name = parser[NKey::kProperty].PostStrings[i]; - int index = prop.Name.Find(L'='); - if (index >= 0) - { - prop.Value = prop.Name.Ptr((unsigned)(index + 1)); - prop.Name.DeleteFrom((unsigned)index); - } - properties.Add(prop); - } - } -} - - -static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res) -{ - if (sw.ThereIs) - res = (unsigned)sw.PostCharIndex; -} - - -#if defined(_WIN32) && !defined(UNDER_CE) -static void PrintHex(UString &s, UInt64 v) -{ - char temp[32]; - ConvertUInt64ToHex(v, temp); - s += temp; -} -#endif - - -void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, - CArcCmdLineOptions &options) -{ - Parse1Log.Empty(); - if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings)) - throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine); - - options.IsInTerminal = MY_IS_TERMINAL(stdin); - options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); - options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); - - options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs; - options.YesToAll = parser[NKey::kYes].ThereIs; - - options.StdInMode = parser[NKey::kStdIn].ThereIs; - options.StdOutMode = parser[NKey::kStdOut].ThereIs; - options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; - if (parser[NKey::kListFields].ThereIs) - { - const UString &s = parser[NKey::kListFields].PostStrings[0]; - options.ListFields = GetAnsiString(s); - } - if (parser[NKey::kListPathSlash].ThereIs) - { - options.ListPathSeparatorSlash.Val = !parser[NKey::kListPathSlash].WithMinus; - options.ListPathSeparatorSlash.Def = true; - } - if (parser[NKey::kListTimestampUTC].ThereIs) - g_Timestamp_Show_UTC = !parser[NKey::kListTimestampUTC].WithMinus; - options.TechMode = parser[NKey::kTechMode].ThereIs; - options.ShowTime = parser[NKey::kShowTime].ThereIs; - - if (parser[NKey::kDisablePercents].ThereIs) - options.DisablePercents = true; - - if (parser[NKey::kDisablePercents].ThereIs - || options.StdOutMode - || !options.IsStdOutTerminal) - options.Number_for_Percents = k_OutStream_disabled; - - if (options.StdOutMode) - options.Number_for_Out = k_OutStream_disabled; - - SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out); - SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors); - SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents); - - if (parser[NKey::kLogLevel].ThereIs) - { - const UString &s = parser[NKey::kLogLevel].PostStrings[0]; - if (s.IsEmpty()) - options.LogLevel = 1; - else - { - UInt32 v; - if (!StringToUInt32(s, v)) - throw CArcCmdLineException("Unsupported switch postfix -bb", s); - options.LogLevel = (unsigned)v; - } - } - - if (parser[NKey::kCaseSensitive].ThereIs) - { - options.CaseSensitive = - g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; - options.CaseSensitive_Change = true; - } - - - #if defined(_WIN32) && !defined(UNDER_CE) - NSecurity::EnablePrivilege_SymLink(); - #endif - - // options.LargePages = false; - - if (parser[NKey::kLargePages].ThereIs) - { - UInt32 slp = 0; - const UString &s = parser[NKey::kLargePages].PostStrings[0]; - if (s.IsEmpty()) - slp = 1; - else if (s != L"-") - { - if (!StringToUInt32(s, slp)) - throw CArcCmdLineException("Unsupported switch postfix for -slp", s); - } - - #ifdef Z7_LARGE_PAGES - if (slp > - #if defined(_WIN32) && !defined(UNDER_CE) - (unsigned)NSecurity::Get_LargePages_RiskLevel() - #else - 0 - #endif - ) - { - #ifdef _WIN32 // change it ! - SetLargePageSize(); - #endif - // note: this process also can inherit that Privilege from parent process - g_LargePagesMode = - #if defined(_WIN32) && !defined(UNDER_CE) - NSecurity::EnablePrivilege_LockMemory(); - #else - true; - #endif - } - #endif - } - - -#ifndef UNDER_CE - - if (parser[NKey::kAffinity].ThereIs) - { - const UString &s = parser[NKey::kAffinity].PostStrings[0]; - if (!s.IsEmpty()) - { - AString a; - a.SetFromWStr_if_Ascii(s); - Parse1Log += "Set process affinity mask: "; - - bool isError = false; - -#ifdef _WIN32 - - UInt64 v = 0; - { - const char *end; - v = ConvertHexStringToUInt64(a, &end); - if (*end != 0) - a.Empty(); - } - if (a.IsEmpty()) - isError = true; - else - { -#ifndef _WIN64 - if (v >= ((UInt64)1 << 32)) - throw CArcCmdLineException("unsupported value -stm", s); - else -#endif - { - PrintHex(Parse1Log, v); - if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v)) - { - const DWORD lastError = GetLastError(); - Parse1Log += " : ERROR : "; - Parse1Log += NError::MyFormatMessage(lastError); - } - } - } - -#else // _WIN32 - - if (a.Len() != s.Len()) - isError = true; - else - { - Parse1Log += a; - NSystem::CProcessAffinity aff; - aff.CpuZero(); - unsigned cpu = 0; - unsigned i = a.Len(); - while (i) - { - unsigned v = (Byte)a[--i]; - Z7_PARSE_HEX_DIGIT(v, { isError = true; break; }) - for (unsigned mask = 1; mask != 1u << 4; mask <<= 1, cpu++) - if (v & mask) - aff.CpuSet(cpu); - } - if (!isError) - if (!aff.SetProcAffinity()) - { - const DWORD lastError = GetLastError(); - Parse1Log += " : ERROR : "; - Parse1Log += NError::MyFormatMessage(lastError); - } - } -#endif // _WIN32 - - if (isError) - throw CArcCmdLineException("Unsupported switch postfix -stm", s); - - Parse1Log.Add_LF(); - } - } - -#endif -} - - - -struct CCodePagePair -{ - const char *Name; - UInt32 CodePage; -}; - -static const unsigned kNumByteOnlyCodePages = 3; - -static const CCodePagePair g_CodePagePairs[] = -{ - { "utf-8", CP_UTF8 }, - { "win", CP_ACP }, - { "dos", CP_OEMCP }, - { "utf-16le", Z7_WIN_CP_UTF16 }, - { "utf-16be", Z7_WIN_CP_UTF16BE } -}; - -static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex, - bool byteOnlyCodePages, Int32 defaultVal) -{ - if (!parser[keyIndex].ThereIs) - return defaultVal; - - UString name (parser[keyIndex].PostStrings.Back()); - UInt32 v; - if (StringToUInt32(name, v)) - if (v < ((UInt32)1 << 16)) - return (Int32)v; - name.MakeLower_Ascii(); - const unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : Z7_ARRAY_SIZE(g_CodePagePairs); - for (unsigned i = 0;; i++) - { - if (i == num) // to disable warnings from different compilers - throw CArcCmdLineException("Unsupported charset:", name); - const CCodePagePair &pair = g_CodePagePairs[i]; - if (name.IsEqualTo(pair.Name)) - return (Int32)pair.CodePage; - } -} - - -static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp) -{ - bp.Def = parser[switchID].ThereIs; - if (bp.Def) - bp.Val = !parser[switchID].WithMinus; -} - - -static bool ParseSizeString(const wchar_t *s, UInt64 &res) -{ - const wchar_t *end; - const UInt64 v = ConvertStringToUInt64(s, &end); - if (s == end) - return false; - const wchar_t c = *end; - - if (c == 0) - { - res = v; - return true; - } - if (end[1] != 0) - return false; - - unsigned numBits; - switch (MyCharLower_Ascii(c)) - { - case 'b': numBits = 0; break; - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - case 't': numBits = 40; break; - default: return false; - } - const UInt64 val2 = v << numBits; - if ((val2 >> numBits) != v) - return false; - res = val2; - return true; -} - -void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) -{ - const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; - const unsigned numNonSwitchStrings = nonSwitchStrings.Size(); - if (numNonSwitchStrings < kMinNonSwitchWords) - throw CArcCmdLineException("The command must be specified"); - - if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) - throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]); - - if (parser[NKey::kHash].ThereIs) - options.HashMethods = parser[NKey::kHash].PostStrings; - - /* - if (parser[NKey::kHashGenFile].ThereIs) - { - const UString &s = parser[NKey::kHashGenFile].PostStrings[0]; - for (unsigned i = 0 ; i < s.Len();) - { - const wchar_t c = s[i++]; - if (!options.HashOptions.ParseFlagCharOption(c, true)) - { - if (c != '=') - throw CArcCmdLineException("Unsupported hash mode switch:", s); - options.HashOptions.HashFilePath = s.Ptr(i); - break; - } - } - } - */ - - if (parser[NKey::kHashDir].ThereIs) - options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0]; - - if (parser[NKey::kExtractMemLimit].ThereIs) - { - const UString &s = parser[NKey::kExtractMemLimit].PostStrings[0]; - if (!ParseSizeString(s, options.ExtractOptions.NtOptions.MemLimit)) - throw CArcCmdLineException("Unsupported -smemx:", s); - } - - if (parser[NKey::kElimDup].ThereIs) - { - options.ExtractOptions.ElimDup.Def = true; - options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus; - } - - NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath; - bool fullPathMode = parser[NKey::kFullPathMode].ThereIs; - if (fullPathMode) - { - censorPathMode = NWildcard::k_AbsPath; - const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; - if (!s.IsEmpty()) - { - if (s == L"2") - censorPathMode = NWildcard::k_FullPath; - else - throw CArcCmdLineException("Unsupported -spf:", s); - } - } - - if (parser[NKey::kNameTrailReplace].ThereIs) - g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus; - - CNameOption nop; - - if (parser[NKey::kRecursed].ThereIs) - nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); - - if (parser[NKey::kDisableWildcardParsing].ThereIs) - nop.WildcardMatching = false; - - if (parser[NKey::kUseSlashMark].ThereIs) - { - const UString &s = parser[NKey::kUseSlashMark].PostStrings[0]; - if (s.IsEmpty()) - nop.MarkMode = NWildcard::kMark_StrictFile; - else if (s.IsEqualTo_Ascii_NoCase("-")) - nop.MarkMode = NWildcard::kMark_FileOrDir; - else if (s.IsEqualTo_Ascii_NoCase("2")) - nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; - else - throw CArcCmdLineException("Unsupported -spm:", s); - } - - - options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1); - - const UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8); - - bool thereAreSwitchIncludes = false; - - if (parser[NKey::kInclude].ThereIs) - { - thereAreSwitchIncludes = true; - nop.Include = true; - AddSwitchWildcardsToCensor(options.Censor, - parser[NKey::kInclude].PostStrings, nop, codePage); - } - - if (parser[NKey::kExclude].ThereIs) - { - nop.Include = false; - AddSwitchWildcardsToCensor(options.Censor, - parser[NKey::kExclude].PostStrings, nop, codePage); - } - - unsigned curCommandIndex = kCommandIndex + 1; - bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && - options.Command.CommandType != NCommandType::kBenchmark && - options.Command.CommandType != NCommandType::kInfo && - options.Command.CommandType != NCommandType::kHash; - - const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); - const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; - const bool isRename = options.Command.CommandType == NCommandType::kRename; - - if ((isExtractOrList || isRename) && options.StdInMode) - thereIsArchiveName = false; - - if (parser[NKey::kArcNameMode].ThereIs) - options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex); - - if (thereIsArchiveName) - { - if (curCommandIndex >= numNonSwitchStrings) - throw CArcCmdLineException("Cannot find archive name"); - options.ArchiveName = nonSwitchStrings[curCommandIndex++]; - if (options.ArchiveName.IsEmpty()) - throw CArcCmdLineException("Archive name cannot by empty"); - #ifdef _WIN32 - // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - } - - nop.Include = true; - AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, - curCommandIndex, options.Censor, - nonSwitchStrings, parser.StopSwitchIndex, - nop, - thereAreSwitchIncludes, codePage); - - #ifndef Z7_NO_CRYPTO - options.PasswordEnabled = parser[NKey::kPassword].ThereIs; - if (options.PasswordEnabled) - options.Password = parser[NKey::kPassword].PostStrings[0]; - #endif - - options.ShowDialog = parser[NKey::kShowDialog].ThereIs; - - if (parser[NKey::kArchiveType].ThereIs) - options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; - - options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings; - - SetMethodOptions(parser, options.Properties); - - if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue(); - - SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); - SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); - SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); - - SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); - SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); - - CBoolPair symLinks_AllowDangerous; - SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); - - - /* - bool supportSymLink = options.SymLinks.Val; - - if (!options.SymLinks.Def) - { - if (isExtractOrList) - supportSymLink = true; - else - supportSymLink = false; - } - - #ifdef ENV_HAVE_LSTAT - if (supportSymLink) - global_use_lstat = 1; - else - global_use_lstat = 0; - #endif - */ - - - if (isExtractOrList) - { - CExtractOptionsBase &eo = options.ExtractOptions; - - eo.ExcludeDirItems = options.Censor.ExcludeDirItems; - eo.ExcludeFileItems = options.Censor.ExcludeFileItems; - - { - CExtractNtOptions &nt = eo.NtOptions; - nt.NtSecurity = options.NtSecurity; - - nt.AltStreams = options.AltStreams; - if (!options.AltStreams.Def) - nt.AltStreams.Val = true; - - nt.HardLinks = options.HardLinks; - if (!options.HardLinks.Def) - nt.HardLinks.Val = true; - - nt.SymLinks = options.SymLinks; - if (!options.SymLinks.Def) - nt.SymLinks.Val = true; - - nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; - - nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; - nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; - - nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName - - if (parser[NKey::kPreserveATime].ThereIs) - nt.PreserveATime = true; - if (parser[NKey::kShareForWrite].ThereIs) - nt.OpenShareForWrite = true; - } - - if (parser[NKey::kZoneFile].ThereIs) - { - eo.ZoneMode = NExtract::NZoneIdMode::kAll; - const UString &s = parser[NKey::kZoneFile].PostStrings[0]; - if (!s.IsEmpty()) - { - if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; - else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; - else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; - else - throw CArcCmdLineException("Unsupported -snz:", s); - } - } - - options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); - options.Censor.ExtendExclude(); - - // are there paths that look as non-relative (!Prefix.IsEmpty()) - if (!options.Censor.AllAreRelative()) - throw CArcCmdLineException("Cannot use absolute pathnames for this command"); - - NWildcard::CCensor &arcCensor = options.arcCensor; - - CNameOption nopArc; - // nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified - // is it OK, external switches can disable WildcardMatching and MarcMode for arc. - nopArc.WildcardMatching = nop.WildcardMatching; - nopArc.MarkMode = nop.MarkMode; - - if (parser[NKey::kArInclude].ThereIs) - { - nopArc.Include = true; - AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage); - } - if (parser[NKey::kArExclude].ThereIs) - { - nopArc.Include = false; - AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage); - } - - if (thereIsArchiveName) - { - nopArc.Include = true; - AddNameToCensor(arcCensor, nopArc, options.ArchiveName); - } - - arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); - - #ifdef _WIN32 - ConvertToLongNames(arcCensor); - #endif - - arcCensor.ExtendExclude(); - - if (options.StdInMode) - options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front(); - - if (isExtractGroupCommand) - { - if (options.StdOutMode) - { - if ( - options.Number_for_Percents == k_OutStream_stdout - // || options.Number_for_Out == k_OutStream_stdout - // || options.Number_for_Errors == k_OutStream_stdout - || - ( - (options.IsStdOutTerminal && options.IsStdErrTerminal) - && - ( - options.Number_for_Percents != k_OutStream_disabled - // || options.Number_for_Out != k_OutStream_disabled - // || options.Number_for_Errors != k_OutStream_disabled - ) - ) - ) - throw CArcCmdLineException(kSameTerminalError); - } - - if (parser[NKey::kOutputDir].ThereIs) - { - eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); - #ifdef _WIN32 - NFile::NName::NormalizeDirSeparators(eo.OutputDir); - #endif - NFile::NName::NormalizeDirPathPrefix(eo.OutputDir); - } - - eo.OverwriteMode = NExtract::NOverwriteMode::kAsk; - if (parser[NKey::kOverwrite].ThereIs) - { - eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex]; - eo.OverwriteMode_Force = true; - } - else if (options.YesToAll) - { - eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; - eo.OverwriteMode_Force = true; - } - } - - eo.PathMode = options.Command.GetPathMode(); - if (censorPathMode == NWildcard::k_AbsPath) - { - eo.PathMode = NExtract::NPathMode::kAbsPaths; - eo.PathMode_Force = true; - } - else if (censorPathMode == NWildcard::k_FullPath) - { - eo.PathMode = NExtract::NPathMode::kFullPaths; - eo.PathMode_Force = true; - } - } - else if (options.Command.IsFromUpdateGroup()) - { - if (parser[NKey::kArInclude].ThereIs) - throw CArcCmdLineException("-ai switch is not supported for this command"); - - CUpdateOptions &updateOptions = options.UpdateOptions; - - SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); - - updateOptions.MethodMode.Properties = options.Properties; - - if (parser[NKey::kPreserveATime].ThereIs) - updateOptions.PreserveATime = true; - if (parser[NKey::kShareForWrite].ThereIs) - updateOptions.OpenShareForWrite = true; - if (parser[NKey::kStopAfterOpenError].ThereIs) - updateOptions.StopAfterOpenError = true; - - updateOptions.PathMode = censorPathMode; - - updateOptions.AltStreams = options.AltStreams; - updateOptions.NtSecurity = options.NtSecurity; - updateOptions.HardLinks = options.HardLinks; - updateOptions.SymLinks = options.SymLinks; - - updateOptions.StoreOwnerId = options.StoreOwnerId; - updateOptions.StoreOwnerName = options.StoreOwnerName; - - updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; - if (updateOptions.EMailMode) - { - updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); - if (updateOptions.EMailAddress.Len() > 0) - if (updateOptions.EMailAddress[0] == L'.') - { - updateOptions.EMailRemoveAfter = true; - updateOptions.EMailAddress.Delete(0); - } - } - - updateOptions.StdOutMode = options.StdOutMode; - updateOptions.StdInMode = options.StdInMode; - - updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs; - updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs; - - if (updateOptions.StdOutMode && updateOptions.EMailMode) - throw CArcCmdLineException("stdout mode and email mode cannot be combined"); - - if (updateOptions.StdOutMode) - { - if (options.IsStdOutTerminal) - throw CArcCmdLineException(kTerminalOutError); - - if (options.Number_for_Percents == k_OutStream_stdout - || options.Number_for_Out == k_OutStream_stdout - || options.Number_for_Errors == k_OutStream_stdout) - throw CArcCmdLineException(kSameTerminalError); - } - - if (updateOptions.StdInMode) - updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); - - if (options.Command.CommandType == NCommandType::kRename) - if (updateOptions.Commands.Size() != 1) - throw CArcCmdLineException("Only one archive can be created with rename command"); - } - else if (options.Command.CommandType == NCommandType::kBenchmark) - { - options.NumIterations = 1; - options.NumIterations_Defined = false; - if (curCommandIndex < numNonSwitchStrings) - { - if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations)) - throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]); - curCommandIndex++; - options.NumIterations_Defined = true; - } - } - else if (options.Command.CommandType == NCommandType::kHash) - { - options.Censor.AddPathsToCensor(censorPathMode); - options.Censor.ExtendExclude(); - - CHashOptions &hashOptions = options.HashOptions; - hashOptions.PathMode = censorPathMode; - hashOptions.Methods = options.HashMethods; - // hashOptions.HashFilePath = options.HashFilePath; - if (parser[NKey::kPreserveATime].ThereIs) - hashOptions.PreserveATime = true; - if (parser[NKey::kShareForWrite].ThereIs) - hashOptions.OpenShareForWrite = true; - hashOptions.StdInMode = options.StdInMode; - hashOptions.AltStreamsMode = options.AltStreams.Val; - hashOptions.SymLinks = options.SymLinks; - } - else if (options.Command.CommandType == NCommandType::kInfo) - { - } - else - throw 20150919; -} - - - -#ifndef _WIN32 - -static AString g_ModuleDirPrefix; - -void Set_ModuleDirPrefix_From_ProgArg0(const char *s); -void Set_ModuleDirPrefix_From_ProgArg0(const char *s) -{ - AString a (s); - int sep = a.ReverseFind_PathSepar(); - a.DeleteFrom((unsigned)(sep + 1)); - g_ModuleDirPrefix = a; -} - -namespace NWindows { -namespace NDLL { - -FString GetModuleDirPrefix(); -FString GetModuleDirPrefix() -{ - FString s; - - s = fas2fs(g_ModuleDirPrefix); - if (s.IsEmpty()) - s = FTEXT(".") FSTRING_PATH_SEPARATOR; - return s; - /* - setenv("_7ZIP_HOME_DIR", "/test/", 0); - const char *home = getenv("_7ZIP_HOME_DIR"); - if (home) - s = home; - else - s = FTEXT(".") FSTRING_PATH_SEPARATOR; - return s; - */ -} - -}} - -#endif // ! _WIN32 +// ArchiveCommandLine.cpp + +#include "StdAfx.h" +#undef printf +#undef sprintf + +#ifdef _WIN32 +#ifndef UNDER_CE +#include +#endif +#else +// for isatty() +#include +#endif + +#include + +#ifdef Z7_LARGE_PAGES +#include "../../../../C/Alloc.h" +#endif + +#include "../../../Common/IntToString.h" +#include "../../../Common/ListFileUtils.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/System.h" +#ifdef _WIN32 +#include "../../../Windows/FileMapping.h" +#include "../../../Windows/MemoryLock.h" +#include "../../../Windows/Synchronization.h" +#endif + +#include "ArchiveCommandLine.h" +#include "EnumDirItems.h" +#include "Update.h" +#include "UpdateAction.h" + +extern bool g_CaseSensitive; +extern bool g_PathTrailReplaceMode; + +#ifdef Z7_LARGE_PAGES +extern +bool g_LargePagesMode; +bool g_LargePagesMode = false; +#endif + +/* +#ifdef ENV_HAVE_LSTAT +EXTERN_C_BEGIN +extern int global_use_lstat; +EXTERN_C_END +#endif +*/ + +#ifdef UNDER_CE + +#define MY_IS_TERMINAL(x) false; + +#else + +// #define MY_isatty_fileno(x) (isatty(fileno(x))) +// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); +static inline bool MY_IS_TERMINAL(FILE *x) +{ + return ( + #if defined(_MSC_VER) && (_MSC_VER >= 1400) + _isatty(_fileno(x)) + #else + isatty(fileno(x)) + #endif + != 0); +} + +#endif + +using namespace NCommandLineParser; +using namespace NWindows; +using namespace NFile; + +static bool StringToUInt32(const wchar_t *s, UInt32 &v) +{ + if (*s == 0) + return false; + const wchar_t *end; + v = ConvertStringToUInt32(s, &end); + return *end == 0; +} + + +namespace NKey { +enum Enum +{ + kHelp1 = 0, + kHelp2, + kHelp3, + + kDisableHeaders, + kDisablePercents, + kShowTime, + kLogLevel, + + kOutStream, + kErrStream, + kPercentStream, + + kYes, + + kShowDialog, + kOverwrite, + + kArchiveType, + kExcludedArcType, + + kProperty, + kOutputDir, + kWorkingDir, + + kInclude, + kExclude, + kArInclude, + kArExclude, + kNoArName, + + kUpdate, + kVolume, + kRecursed, + + kAffinity, + kSfx, + kEmail, + kHash, + // kHashGenFile, + kHashDir, + kExtractMemLimit, + + kStdIn, + kStdOut, + + kLargePages, + kListfileCharSet, + kConsoleCharSet, + kTechMode, + kListFields, + kListPathSlash, + kListTimestampUTC, + + kPreserveATime, + kShareForWrite, + kStopAfterOpenError, + kCaseSensitive, + kArcNameMode, + + kUseSlashMark, + kDisableWildcardParsing, + kElimDup, + kFullPathMode, + + kHardLinks, + kSymLinks_AllowDangerous, + kSymLinks, + kNtSecurity, + + kStoreOwnerId, + kStoreOwnerName, + + kZoneFile, + kAltStreams, + kReplaceColonForAltStream, + kWriteToAltStreamIfColon, + + kNameTrailReplace, + + kDeleteAfterCompressing, + kSetArcMTime + + #ifndef Z7_NO_CRYPTO + , kPassword + #endif +}; + +} + + +static const wchar_t kRecursedIDChar = 'r'; +static const char * const kRecursedPostCharSet = "0-"; + +static const char * const k_ArcNameMode_PostCharSet = "sea"; + +static const char * const k_Stream_PostCharSet = "012"; + +static inline EArcNameMode ParseArcNameMode(int postCharIndex) +{ + switch (postCharIndex) + { + case 1: return k_ArcNameMode_Exact; + case 2: return k_ArcNameMode_Add; + default: return k_ArcNameMode_Smart; + } +} + +namespace NRecursedPostCharIndex { + enum EEnum + { + kWildcardRecursionOnly = 0, + kNoRecursion = 1 + }; +} + +// static const char +#define kImmediateNameID '!' +#ifdef _WIN32 +#define kMapNameID '#' +#endif +#define kFileListID '@' + +static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!>ame must be +static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!>ame must be + +static const char * const kOverwritePostCharSet = "asut"; + +static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = +{ + NExtract::NOverwriteMode::kOverwrite, + NExtract::NOverwriteMode::kSkip, + NExtract::NOverwriteMode::kRename, + NExtract::NOverwriteMode::kRenameExisting +}; + + + +#define SWFRM_3(t, mu, mi) t, mu, mi, NULL + +#define SWFRM_1(t) SWFRM_3(t, false, 0) +#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple) +#define SWFRM_MINUS SWFRM_1(NSwitchType::kMinus) +#define SWFRM_STRING SWFRM_1(NSwitchType::kString) + +#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi) +#define SWFRM_STRING_MULT(mi) SWFRM_3(NSwitchType::kString, true, mi) + + +static const CSwitchForm kSwitchForms[] = +{ + { "?", SWFRM_SIMPLE }, + { "h", SWFRM_SIMPLE }, + { "-help", SWFRM_SIMPLE }, + + { "ba", SWFRM_SIMPLE }, + { "bd", SWFRM_SIMPLE }, + { "bt", SWFRM_SIMPLE }, + { "bb", SWFRM_STRING_SINGL(0) }, + + { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, + { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, + { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet }, + + { "y", SWFRM_SIMPLE }, + + { "ad", SWFRM_SIMPLE }, + { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet}, + + { "t", SWFRM_STRING_SINGL(1) }, + { "stx", SWFRM_STRING_MULT(1) }, + + { "m", SWFRM_STRING_MULT(1) }, + { "o", SWFRM_STRING_SINGL(1) }, + { "w", SWFRM_STRING }, + + { "i", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, + { "x", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, + { "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, + { "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) }, + { "an", SWFRM_SIMPLE }, + + { "u", SWFRM_STRING_MULT(1) }, + { "v", SWFRM_STRING_MULT(1) }, + { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet }, + + { "stm", SWFRM_STRING }, + { "sfx", SWFRM_STRING }, + { "seml", SWFRM_STRING_SINGL(0) }, + { "scrc", SWFRM_STRING_MULT(0) }, + // { "scrf", SWFRM_STRING_SINGL(1) }, + { "shd", SWFRM_STRING_SINGL(1) }, + { "smemx", SWFRM_STRING }, + + { "si", SWFRM_STRING }, + { "so", SWFRM_SIMPLE }, + + { "slp", SWFRM_STRING }, + { "scs", SWFRM_STRING }, + { "scc", SWFRM_STRING }, + { "slt", SWFRM_SIMPLE }, + { "slf", SWFRM_STRING_SINGL(1) }, + { "slsl", SWFRM_MINUS }, + { "slmu", SWFRM_MINUS }, + + { "ssp", SWFRM_SIMPLE }, + { "ssw", SWFRM_SIMPLE }, + { "sse", SWFRM_SIMPLE }, + { "ssc", SWFRM_MINUS }, + { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, + + { "spm", SWFRM_STRING_SINGL(0) }, + { "spd", SWFRM_SIMPLE }, + { "spe", SWFRM_MINUS }, + { "spf", SWFRM_STRING_SINGL(0) }, + + { "snh", SWFRM_MINUS }, + { "snld", SWFRM_MINUS }, + { "snl", SWFRM_MINUS }, + { "sni", SWFRM_SIMPLE }, + + { "snoi", SWFRM_MINUS }, + { "snon", SWFRM_MINUS }, + + { "snz", SWFRM_STRING_SINGL(0) }, + { "sns", SWFRM_MINUS }, + { "snr", SWFRM_SIMPLE }, + { "snc", SWFRM_SIMPLE }, + + { "snt", SWFRM_MINUS }, + + { "sdel", SWFRM_SIMPLE }, + { "stl", SWFRM_SIMPLE } + + #ifndef Z7_NO_CRYPTO + , { "p", SWFRM_STRING } + #endif +}; + +static const char * const kUniversalWildcard = "*"; +static const unsigned kMinNonSwitchWords = 1; +static const unsigned kCommandIndex = 0; + +// static const char * const kUserErrorMessage = "Incorrect command line"; +// static const char * const kCannotFindListFile = "Cannot find listfile"; +static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch."; +static const char * const kTerminalOutError = "I won't write compressed data to a terminal"; +static const char * const kSameTerminalError = "I won't write data and program's messages to same stream"; +static const char * const kEmptyFilePath = "Empty file path"; + +bool CArcCommand::IsFromExtractGroup() const +{ + switch ((int)CommandType) + { + case NCommandType::kTest: + case NCommandType::kExtract: + case NCommandType::kExtractFull: + return true; + default: + return false; + } +} + +NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const +{ + switch ((int)CommandType) + { + case NCommandType::kTest: + case NCommandType::kExtractFull: + return NExtract::NPathMode::kFullPaths; + default: + return NExtract::NPathMode::kNoPaths; + } +} + +bool CArcCommand::IsFromUpdateGroup() const +{ + switch ((int)CommandType) + { + case NCommandType::kAdd: + case NCommandType::kUpdate: + case NCommandType::kDelete: + case NCommandType::kRename: + return true; + default: + return false; + } +} + +static NRecursedType::EEnum GetRecursedTypeFromIndex(int index) +{ + switch (index) + { + case NRecursedPostCharIndex::kWildcardRecursionOnly: + return NRecursedType::kWildcardOnlyRecursed; + case NRecursedPostCharIndex::kNoRecursion: + return NRecursedType::kNonRecursed; + default: + return NRecursedType::kRecursed; + } +} + +static const char *g_Commands = "audtexlbih"; + +static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command) +{ + UString s (commandString); + s.MakeLower_Ascii(); + if (s.Len() == 1) + { + if (s[0] > 0x7F) + return false; + int index = FindCharPosInString(g_Commands, (char)s[0]); + if (index < 0) + return false; + command.CommandType = (NCommandType::EEnum)index; + return true; + } + if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n') + { + command.CommandType = (NCommandType::kRename); + return true; + } + return false; +} + +// ------------------------------------------------------------------ +// filenames functions + +struct CNameOption +{ + bool Include; + bool WildcardMatching; + Byte MarkMode; + NRecursedType::EEnum RecursedType; + + CNameOption(): + Include(true), + WildcardMatching(true), + MarkMode(NWildcard::kMark_FileOrDir), + RecursedType(NRecursedType::kNonRecursed) + {} +}; + + +static void AddNameToCensor(NWildcard::CCensor &censor, + const CNameOption &nop, const UString &name) +{ + bool recursed = false; + + switch ((int)nop.RecursedType) + { + case NRecursedType::kWildcardOnlyRecursed: + recursed = DoesNameContainWildcard(name); + break; + case NRecursedType::kRecursed: + recursed = true; + break; + default: + break; + } + + NWildcard::CCensorPathProps props; + props.Recursive = recursed; + props.WildcardMatching = nop.WildcardMatching; + props.MarkMode = nop.MarkMode; + censor.AddPreItem(nop.Include, name, props); +} + +#ifndef Z7_EXTRACT_ONLY +static void AddRenamePair(CObjectVector *renamePairs, + const UString &oldName, const UString &newName, NRecursedType::EEnum type, + bool wildcardMatching) +{ + CRenamePair &pair = renamePairs->AddNew(); + pair.OldName = oldName; + pair.NewName = newName; + pair.RecursedType = type; + pair.WildcardParsing = wildcardMatching; + + if (!pair.Prepare()) + { + UString val; + val += pair.OldName; + val.Add_LF(); + val += pair.NewName; + val.Add_LF(); + if (type == NRecursedType::kRecursed) + val += "-r"; + else if (type == NRecursedType::kWildcardOnlyRecursed) + val += "-r0"; + throw CArcCmdLineException("Unsupported rename command:", val); + } +} +#endif + +static void AddToCensorFromListFile( + CObjectVector *renamePairs, + NWildcard::CCensor &censor, + const CNameOption &nop, LPCWSTR fileName, UInt32 codePage) +{ + UStringVector names; + /* + if (!NFind::DoesFileExist_FollowLink(us2fs(fileName))) + throw CArcCmdLineException(kCannotFindListFile, fileName); + */ + DWORD lastError = 0; + if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError)) + { + if (lastError != 0) + { + UString m; + m = "The file operation error for listfile"; + m.Add_LF(); + m += NError::MyFormatMessage(lastError); + throw CArcCmdLineException(m, fileName); + } + throw CArcCmdLineException(kIncorrectListFile, fileName); + } + if (renamePairs) + { + #ifndef Z7_EXTRACT_ONLY + if ((names.Size() & 1) != 0) + throw CArcCmdLineException(kIncorrectListFile, fileName); + for (unsigned i = 0; i < names.Size(); i += 2) + { + // change type !!!! + AddRenamePair(renamePairs, names[i], names[i + 1], nop.RecursedType, nop.WildcardMatching); + } + #else + throw "not implemented"; + #endif + } + else + FOR_VECTOR (i, names) + AddNameToCensor(censor, nop, names[i]); +} + +static void AddToCensorFromNonSwitchesStrings( + CObjectVector *renamePairs, + unsigned startIndex, + NWildcard::CCensor &censor, + const UStringVector &nonSwitchStrings, + int stopSwitchIndex, + const CNameOption &nop, + bool thereAreSwitchIncludes, UInt32 codePage) +{ + // another default + if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes) + { + /* for rename command: -i switch sets the mask for archive item reading. + if (thereAreSwitchIncludes), { we don't use UniversalWildcard. } + also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */ + // we use default fileds in (CNameOption) for UniversalWildcard. + CNameOption nop2; + // recursive mode is not important for UniversalWildcard (*) + // nop2.RecursedType = nop.RecursedType; // we don't need it + /* + nop2.RecursedType = NRecursedType::kNonRecursed; + nop2.Include = true; + nop2.WildcardMatching = true; + nop2.MarkMode = NWildcard::kMark_FileOrDir; + */ + AddNameToCensor(censor, nop2, UString(kUniversalWildcard)); + } + + int oldIndex = -1; + + if (stopSwitchIndex < 0) + stopSwitchIndex = (int)nonSwitchStrings.Size(); + + for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++) + { + const UString &s = nonSwitchStrings[i]; + if (s.IsEmpty()) + throw CArcCmdLineException(kEmptyFilePath); + if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID) + AddToCensorFromListFile(renamePairs, censor, nop, s.Ptr(1), codePage); + else if (renamePairs) + { + #ifndef Z7_EXTRACT_ONLY + if (oldIndex == -1) + oldIndex = (int)i; + else + { + // NRecursedType::EEnum type is used for global wildcard (-i! switches) + AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching); + // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type); + oldIndex = -1; + } + #else + throw "not implemented"; + #endif + } + else + AddNameToCensor(censor, nop, s); + } + + if (oldIndex != -1) + { + throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[(unsigned)oldIndex]); + } +} + +#ifdef _WIN32 + +struct CEventSetEnd +{ + UString Name; + + CEventSetEnd(const wchar_t *name): Name(name) {} + ~CEventSetEnd() + { + NSynchronization::CManualResetEvent event; + if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0) + event.Set(); + } +}; + +static const char * const k_IncorrectMapCommand = "Incorrect Map command"; + +static const char *ParseMapWithPaths( + NWildcard::CCensor &censor, + const UString &s2, + const CNameOption &nop) +{ + UString s (s2); + const int pos = s.Find(L':'); + if (pos < 0) + return k_IncorrectMapCommand; + const int pos2 = s.Find(L':', (unsigned)(pos + 1)); + if (pos2 < 0) + return k_IncorrectMapCommand; + + CEventSetEnd eventSetEnd((const wchar_t *)s + (unsigned)(pos2 + 1)); + s.DeleteFrom((unsigned)pos2); + UInt32 size; + if (!StringToUInt32(s.Ptr((unsigned)(pos + 1)), size) + || size < sizeof(wchar_t) + || size > ((UInt32)1 << 31) + || size % sizeof(wchar_t) != 0) + return "Unsupported Map data size"; + + s.DeleteFrom((unsigned)pos); + CFileMapping map; + if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0) + return "Cannot open mapping"; + const LPVOID data = map.Map(FILE_MAP_READ, 0, size); + if (!data) + return "MapViewOfFile error"; + CFileUnmapper unmapper(data); + + UString name; + const wchar_t *p = (const wchar_t *)data; + if (*p != 0) // data format marker + return "Unsupported Map data"; + const UInt32 numChars = size / sizeof(wchar_t); + for (UInt32 i = 1; i < numChars; i++) + { + const wchar_t c = p[i]; + if (c == 0) + { + // MessageBoxW(0, name, L"7-Zip", 0); + AddNameToCensor(censor, nop, name); + name.Empty(); + } + else + name += c; + } + if (!name.IsEmpty()) + return "Map data error"; + + return NULL; +} + +#endif + +static void AddSwitchWildcardsToCensor( + NWildcard::CCensor &censor, + const UStringVector &strings, + const CNameOption &nop, + UInt32 codePage) +{ + const char *errorMessage = NULL; + unsigned i; + for (i = 0; i < strings.Size(); i++) + { + const UString &name = strings[i]; + unsigned pos = 0; + + if (name.Len() < kSomeCludePostStringMinSize) + { + errorMessage = "Too short switch"; + break; + } + + if (!nop.Include) + { + if (name.IsEqualTo_Ascii_NoCase("td")) + { + censor.ExcludeDirItems = true; + continue; + } + if (name.IsEqualTo_Ascii_NoCase("tf")) + { + censor.ExcludeFileItems = true; + continue; + } + } + + CNameOption nop2 = nop; + + bool type_WasUsed = false; + bool recursed_WasUsed = false; + bool matching_WasUsed = false; + bool error = false; + + for (;;) + { + wchar_t c = ::MyCharLower_Ascii(name[pos]); + if (c == kRecursedIDChar) + { + if (recursed_WasUsed) + { + error = true; + break; + } + recursed_WasUsed = true; + pos++; + c = name[pos]; + int index = -1; + if (c <= 0x7F) + index = FindCharPosInString(kRecursedPostCharSet, (char)c); + nop2.RecursedType = GetRecursedTypeFromIndex(index); + if (index >= 0) + { + pos++; + continue; + } + } + + if (c == 'w') + { + if (matching_WasUsed) + { + error = true; + break; + } + matching_WasUsed = true; + nop2.WildcardMatching = true; + pos++; + if (name[pos] == '-') + { + nop2.WildcardMatching = false; + pos++; + } + } + else if (c == 'm') + { + if (type_WasUsed) + { + error = true; + break; + } + type_WasUsed = true; + pos++; + nop2.MarkMode = NWildcard::kMark_StrictFile; + c = name[pos]; + if (c == '-') + { + nop2.MarkMode = NWildcard::kMark_FileOrDir; + pos++; + } + else if (c == '2') + { + nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; + pos++; + } + } + else + break; + } + + if (error) + { + errorMessage = "inorrect switch"; + break; + } + + if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize) + { + errorMessage = "Too short switch"; + break; + } + + const UString tail = name.Ptr(pos + 1); + + const wchar_t c = name[pos]; + + if (c == kImmediateNameID) + AddNameToCensor(censor, nop2, tail); + else if (c == kFileListID) + AddToCensorFromListFile(NULL, censor, nop2, tail, codePage); + #ifdef _WIN32 + else if (c == kMapNameID) + { + errorMessage = ParseMapWithPaths(censor, tail, nop2); + if (errorMessage) + break; + } + #endif + else + { + errorMessage = "Incorrect wildcard type marker"; + break; + } + } + + if (i != strings.Size()) + throw CArcCmdLineException(errorMessage, strings[i]); +} + +/* +static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i) +{ + switch (i) + { + case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore; + case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy; + case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress; + case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti; + } + throw 98111603; +} +*/ + +static const char * const kUpdatePairStateIDSet = "pqrxyzw"; +static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; + +static const unsigned kNumUpdatePairActions = 4; +static const char * const kUpdateIgnoreItselfPostStringID = "-"; +static const wchar_t kUpdateNewArchivePostCharID = '!'; + + +static bool ParseUpdateCommandString2(const UString &command, + NUpdateArchive::CActionSet &actionSet, UString &postString) +{ + for (unsigned i = 0; i < command.Len();) + { + wchar_t c = MyCharLower_Ascii(command[i]); + int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c); + if (c > 0x7F || statePos < 0) + { + postString = command.Ptr(i); + return true; + } + i++; + if (i >= command.Len()) + return false; + c = command[i]; + if (c < '0' || c >= (wchar_t)('0' + kNumUpdatePairActions)) + return false; + unsigned actionPos = (unsigned)(c - '0'); + actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos); + if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos) + return false; + i++; + } + postString.Empty(); + return true; +} + +static void ParseUpdateCommandString(CUpdateOptions &options, + const UStringVector &updatePostStrings, + const NUpdateArchive::CActionSet &defaultActionSet) +{ + const char *errorMessage = "incorrect update switch command"; + unsigned i; + for (i = 0; i < updatePostStrings.Size(); i++) + { + const UString &updateString = updatePostStrings[i]; + if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID)) + { + if (options.UpdateArchiveItself) + { + options.UpdateArchiveItself = false; + options.Commands.Delete(0); + } + } + else + { + NUpdateArchive::CActionSet actionSet = defaultActionSet; + + UString postString; + if (!ParseUpdateCommandString2(updateString, actionSet, postString)) + break; + if (postString.IsEmpty()) + { + if (options.UpdateArchiveItself) + options.Commands[0].ActionSet = actionSet; + } + else + { + if (postString[0] != kUpdateNewArchivePostCharID) + break; + CUpdateArchiveCommand uc; + UString archivePath = postString.Ptr(1); + if (archivePath.IsEmpty()) + break; + uc.UserArchivePath = archivePath; + uc.ActionSet = actionSet; + options.Commands.Add(uc); + } + } + } + if (i != updatePostStrings.Size()) + throw CArcCmdLineException(errorMessage, updatePostStrings[i]); +} + +bool ParseComplexSize(const wchar_t *s, UInt64 &result); + +static void SetAddCommandOptions( + NCommandType::EEnum commandType, + const CParser &parser, + CUpdateOptions &options) +{ + NUpdateArchive::CActionSet defaultActionSet; + switch ((int)commandType) + { + case NCommandType::kAdd: + defaultActionSet = NUpdateArchive::k_ActionSet_Add; + break; + case NCommandType::kDelete: + defaultActionSet = NUpdateArchive::k_ActionSet_Delete; + break; + default: + defaultActionSet = NUpdateArchive::k_ActionSet_Update; + } + + options.UpdateArchiveItself = true; + + options.Commands.Clear(); + CUpdateArchiveCommand updateMainCommand; + updateMainCommand.ActionSet = defaultActionSet; + options.Commands.Add(updateMainCommand); + if (parser[NKey::kUpdate].ThereIs) + ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, + defaultActionSet); + if (parser[NKey::kWorkingDir].ThereIs) + { + const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; + if (postString.IsEmpty()) + NDir::MyGetTempPath(options.WorkingDir); + else + options.WorkingDir = us2fs(postString); + } + options.SfxMode = parser[NKey::kSfx].ThereIs; + if (options.SfxMode) + options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]); + + if (parser[NKey::kVolume].ThereIs) + { + const UStringVector &sv = parser[NKey::kVolume].PostStrings; + FOR_VECTOR (i, sv) + { + UInt64 size; + if (!ParseComplexSize(sv[i], size)) + throw CArcCmdLineException("Incorrect volume size:", sv[i]); + if (i == sv.Size() - 1 && size == 0) + throw CArcCmdLineException("zero size last volume is not allowed"); + options.VolumesSizes.Add(size); + } + } +} + +static void SetMethodOptions(const CParser &parser, CObjectVector &properties) +{ + if (parser[NKey::kProperty].ThereIs) + { + FOR_VECTOR (i, parser[NKey::kProperty].PostStrings) + { + CProperty prop; + prop.Name = parser[NKey::kProperty].PostStrings[i]; + int index = prop.Name.Find(L'='); + if (index >= 0) + { + prop.Value = prop.Name.Ptr((unsigned)(index + 1)); + prop.Name.DeleteFrom((unsigned)index); + } + properties.Add(prop); + } + } +} + + +static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res) +{ + if (sw.ThereIs) + res = (unsigned)sw.PostCharIndex; +} + + +#if defined(_WIN32) && !defined(UNDER_CE) +static void PrintHex(UString &s, UInt64 v) +{ + char temp[32]; + ConvertUInt64ToHex(v, temp); + s += temp; +} +#endif + + +void CArcCmdLineParser::Parse1(const UStringVector &commandStrings, + CArcCmdLineOptions &options) +{ + Parse1Log.Empty(); + if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings)) + throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine); + + options.IsInTerminal = MY_IS_TERMINAL(stdin); + options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); + options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); + + options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs; + options.YesToAll = parser[NKey::kYes].ThereIs; + + options.StdInMode = parser[NKey::kStdIn].ThereIs; + options.StdOutMode = parser[NKey::kStdOut].ThereIs; + options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; + if (parser[NKey::kListFields].ThereIs) + { + const UString &s = parser[NKey::kListFields].PostStrings[0]; + options.ListFields = GetAnsiString(s); + } + if (parser[NKey::kListPathSlash].ThereIs) + { + options.ListPathSeparatorSlash.Val = !parser[NKey::kListPathSlash].WithMinus; + options.ListPathSeparatorSlash.Def = true; + } + if (parser[NKey::kListTimestampUTC].ThereIs) + g_Timestamp_Show_UTC = !parser[NKey::kListTimestampUTC].WithMinus; + options.TechMode = parser[NKey::kTechMode].ThereIs; + options.ShowTime = parser[NKey::kShowTime].ThereIs; + + if (parser[NKey::kDisablePercents].ThereIs) + options.DisablePercents = true; + + if (parser[NKey::kDisablePercents].ThereIs + || options.StdOutMode + || !options.IsStdOutTerminal) + options.Number_for_Percents = k_OutStream_disabled; + + if (options.StdOutMode) + options.Number_for_Out = k_OutStream_disabled; + + SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out); + SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors); + SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents); + + if (parser[NKey::kLogLevel].ThereIs) + { + const UString &s = parser[NKey::kLogLevel].PostStrings[0]; + if (s.IsEmpty()) + options.LogLevel = 1; + else + { + UInt32 v; + if (!StringToUInt32(s, v)) + throw CArcCmdLineException("Unsupported switch postfix -bb", s); + options.LogLevel = (unsigned)v; + } + } + + if (parser[NKey::kCaseSensitive].ThereIs) + { + options.CaseSensitive = + g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; + options.CaseSensitive_Change = true; + } + + + #if defined(_WIN32) && !defined(UNDER_CE) + NSecurity::EnablePrivilege_SymLink(); + #endif + + // options.LargePages = false; + + if (parser[NKey::kLargePages].ThereIs) + { + UInt32 slp = 0; + const UString &s = parser[NKey::kLargePages].PostStrings[0]; + if (s.IsEmpty()) + slp = 1; + else if (s != L"-") + { + if (!StringToUInt32(s, slp)) + throw CArcCmdLineException("Unsupported switch postfix for -slp", s); + } + + #ifdef Z7_LARGE_PAGES + if (slp > + #if defined(_WIN32) && !defined(UNDER_CE) + (unsigned)NSecurity::Get_LargePages_RiskLevel() + #else + 0 + #endif + ) + { + #ifdef _WIN32 // change it ! + SetLargePageSize(); + #endif + // note: this process also can inherit that Privilege from parent process + g_LargePagesMode = + #if defined(_WIN32) && !defined(UNDER_CE) + NSecurity::EnablePrivilege_LockMemory(); + #else + true; + #endif + } + #endif + } + + +#ifndef UNDER_CE + + if (parser[NKey::kAffinity].ThereIs) + { + const UString &s = parser[NKey::kAffinity].PostStrings[0]; + if (!s.IsEmpty()) + { + AString a; + a.SetFromWStr_if_Ascii(s); + Parse1Log += "Set process affinity mask: "; + + bool isError = false; + +#ifdef _WIN32 + + UInt64 v = 0; + { + const char *end; + v = ConvertHexStringToUInt64(a, &end); + if (*end != 0) + a.Empty(); + } + if (a.IsEmpty()) + isError = true; + else + { +#ifndef _WIN64 + if (v >= ((UInt64)1 << 32)) + throw CArcCmdLineException("unsupported value -stm", s); + else +#endif + { + PrintHex(Parse1Log, v); + if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v)) + { + const DWORD lastError = GetLastError(); + Parse1Log += " : ERROR : "; + Parse1Log += NError::MyFormatMessage(lastError); + } + } + } + +#else // _WIN32 + + if (a.Len() != s.Len()) + isError = true; + else + { + Parse1Log += a; + NSystem::CProcessAffinity aff; + aff.CpuZero(); + unsigned cpu = 0; + unsigned i = a.Len(); + while (i) + { + unsigned v = (Byte)a[--i]; + Z7_PARSE_HEX_DIGIT(v, { isError = true; break; }) + for (unsigned mask = 1; mask != 1u << 4; mask <<= 1, cpu++) + if (v & mask) + aff.CpuSet(cpu); + } + if (!isError) + if (!aff.SetProcAffinity()) + { + const DWORD lastError = GetLastError(); + Parse1Log += " : ERROR : "; + Parse1Log += NError::MyFormatMessage(lastError); + } + } +#endif // _WIN32 + + if (isError) + throw CArcCmdLineException("Unsupported switch postfix -stm", s); + + Parse1Log.Add_LF(); + } + } + +#endif +} + + + +struct CCodePagePair +{ + const char *Name; + UInt32 CodePage; +}; + +static const unsigned kNumByteOnlyCodePages = 3; + +static const CCodePagePair g_CodePagePairs[] = +{ + { "utf-8", CP_UTF8 }, + { "win", CP_ACP }, + { "dos", CP_OEMCP }, + { "utf-16le", Z7_WIN_CP_UTF16 }, + { "utf-16be", Z7_WIN_CP_UTF16BE } +}; + +static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex, + bool byteOnlyCodePages, Int32 defaultVal) +{ + if (!parser[keyIndex].ThereIs) + return defaultVal; + + UString name (parser[keyIndex].PostStrings.Back()); + UInt32 v; + if (StringToUInt32(name, v)) + if (v < ((UInt32)1 << 16)) + return (Int32)v; + name.MakeLower_Ascii(); + const unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : Z7_ARRAY_SIZE(g_CodePagePairs); + for (unsigned i = 0;; i++) + { + if (i == num) // to disable warnings from different compilers + throw CArcCmdLineException("Unsupported charset:", name); + const CCodePagePair &pair = g_CodePagePairs[i]; + if (name.IsEqualTo(pair.Name)) + return (Int32)pair.CodePage; + } +} + + +static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp) +{ + bp.Def = parser[switchID].ThereIs; + if (bp.Def) + bp.Val = !parser[switchID].WithMinus; +} + + +static bool ParseSizeString(const wchar_t *s, UInt64 &res) +{ + const wchar_t *end; + const UInt64 v = ConvertStringToUInt64(s, &end); + if (s == end) + return false; + const wchar_t c = *end; + + if (c == 0) + { + res = v; + return true; + } + if (end[1] != 0) + return false; + + unsigned numBits; + switch (MyCharLower_Ascii(c)) + { + case 'b': numBits = 0; break; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return false; + } + const UInt64 val2 = v << numBits; + if ((val2 >> numBits) != v) + return false; + res = val2; + return true; +} + +void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) +{ + const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; + const unsigned numNonSwitchStrings = nonSwitchStrings.Size(); + if (numNonSwitchStrings < kMinNonSwitchWords) + throw CArcCmdLineException("The command must be specified"); + + if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) + throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]); + + if (parser[NKey::kHash].ThereIs) + options.HashMethods = parser[NKey::kHash].PostStrings; + + /* + if (parser[NKey::kHashGenFile].ThereIs) + { + const UString &s = parser[NKey::kHashGenFile].PostStrings[0]; + for (unsigned i = 0 ; i < s.Len();) + { + const wchar_t c = s[i++]; + if (!options.HashOptions.ParseFlagCharOption(c, true)) + { + if (c != '=') + throw CArcCmdLineException("Unsupported hash mode switch:", s); + options.HashOptions.HashFilePath = s.Ptr(i); + break; + } + } + } + */ + + if (parser[NKey::kHashDir].ThereIs) + options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0]; + + if (parser[NKey::kExtractMemLimit].ThereIs) + { + const UString &s = parser[NKey::kExtractMemLimit].PostStrings[0]; + if (!ParseSizeString(s, options.ExtractOptions.NtOptions.MemLimit)) + throw CArcCmdLineException("Unsupported -smemx:", s); + } + + if (parser[NKey::kElimDup].ThereIs) + { + options.ExtractOptions.ElimDup.Def = true; + options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus; + } + + NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath; + bool fullPathMode = parser[NKey::kFullPathMode].ThereIs; + if (fullPathMode) + { + censorPathMode = NWildcard::k_AbsPath; + const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; + if (!s.IsEmpty()) + { + if (s == L"2") + censorPathMode = NWildcard::k_FullPath; + else + throw CArcCmdLineException("Unsupported -spf:", s); + } + } + + if (parser[NKey::kNameTrailReplace].ThereIs) + g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus; + + CNameOption nop; + + if (parser[NKey::kRecursed].ThereIs) + nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex); + + if (parser[NKey::kDisableWildcardParsing].ThereIs) + nop.WildcardMatching = false; + + if (parser[NKey::kUseSlashMark].ThereIs) + { + const UString &s = parser[NKey::kUseSlashMark].PostStrings[0]; + if (s.IsEmpty()) + nop.MarkMode = NWildcard::kMark_StrictFile; + else if (s.IsEqualTo_Ascii_NoCase("-")) + nop.MarkMode = NWildcard::kMark_FileOrDir; + else if (s.IsEqualTo_Ascii_NoCase("2")) + nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard; + else + throw CArcCmdLineException("Unsupported -spm:", s); + } + + + options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1); + + const UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8); + + bool thereAreSwitchIncludes = false; + + if (parser[NKey::kInclude].ThereIs) + { + thereAreSwitchIncludes = true; + nop.Include = true; + AddSwitchWildcardsToCensor(options.Censor, + parser[NKey::kInclude].PostStrings, nop, codePage); + } + + if (parser[NKey::kExclude].ThereIs) + { + nop.Include = false; + AddSwitchWildcardsToCensor(options.Censor, + parser[NKey::kExclude].PostStrings, nop, codePage); + } + + unsigned curCommandIndex = kCommandIndex + 1; + bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && + options.Command.CommandType != NCommandType::kBenchmark && + options.Command.CommandType != NCommandType::kInfo && + options.Command.CommandType != NCommandType::kHash; + + const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; + const bool isRename = options.Command.CommandType == NCommandType::kRename; + + if ((isExtractOrList || isRename) && options.StdInMode) + thereIsArchiveName = false; + + if (parser[NKey::kArcNameMode].ThereIs) + options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex); + + if (thereIsArchiveName) + { + if (curCommandIndex >= numNonSwitchStrings) + throw CArcCmdLineException("Cannot find archive name"); + options.ArchiveName = nonSwitchStrings[curCommandIndex++]; + if (options.ArchiveName.IsEmpty()) + throw CArcCmdLineException("Archive name cannot by empty"); + #ifdef _WIN32 + // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + } + + nop.Include = true; + AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL, + curCommandIndex, options.Censor, + nonSwitchStrings, parser.StopSwitchIndex, + nop, + thereAreSwitchIncludes, codePage); + + #ifndef Z7_NO_CRYPTO + options.PasswordEnabled = parser[NKey::kPassword].ThereIs; + if (options.PasswordEnabled) + options.Password = parser[NKey::kPassword].PostStrings[0]; + #endif + + options.ShowDialog = parser[NKey::kShowDialog].ThereIs; + + if (parser[NKey::kArchiveType].ThereIs) + options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; + + options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings; + + SetMethodOptions(parser, options.Properties); + + if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue(); + + SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); + SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); + SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); + + SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); + SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); + + CBoolPair symLinks_AllowDangerous; + SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); + + + /* + bool supportSymLink = options.SymLinks.Val; + + if (!options.SymLinks.Def) + { + if (isExtractOrList) + supportSymLink = true; + else + supportSymLink = false; + } + + #ifdef ENV_HAVE_LSTAT + if (supportSymLink) + global_use_lstat = 1; + else + global_use_lstat = 0; + #endif + */ + + + if (isExtractOrList) + { + CExtractOptionsBase &eo = options.ExtractOptions; + + eo.ExcludeDirItems = options.Censor.ExcludeDirItems; + eo.ExcludeFileItems = options.Censor.ExcludeFileItems; + + { + CExtractNtOptions &nt = eo.NtOptions; + nt.NtSecurity = options.NtSecurity; + + nt.AltStreams = options.AltStreams; + if (!options.AltStreams.Def) + nt.AltStreams.Val = true; + + nt.HardLinks = options.HardLinks; + if (!options.HardLinks.Def) + nt.HardLinks.Val = true; + + nt.SymLinks = options.SymLinks; + if (!options.SymLinks.Def) + nt.SymLinks.Val = true; + + nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; + + nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; + nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; + + nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName + + if (parser[NKey::kPreserveATime].ThereIs) + nt.PreserveATime = true; + if (parser[NKey::kShareForWrite].ThereIs) + nt.OpenShareForWrite = true; + } + + if (parser[NKey::kZoneFile].ThereIs) + { + eo.ZoneMode = NExtract::NZoneIdMode::kAll; + const UString &s = parser[NKey::kZoneFile].PostStrings[0]; + if (!s.IsEmpty()) + { + if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; + else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; + else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; + else + throw CArcCmdLineException("Unsupported -snz:", s); + } + } + + options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); + options.Censor.ExtendExclude(); + + // are there paths that look as non-relative (!Prefix.IsEmpty()) + if (!options.Censor.AllAreRelative()) + throw CArcCmdLineException("Cannot use absolute pathnames for this command"); + + NWildcard::CCensor &arcCensor = options.arcCensor; + + CNameOption nopArc; + // nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified + // is it OK, external switches can disable WildcardMatching and MarcMode for arc. + nopArc.WildcardMatching = nop.WildcardMatching; + nopArc.MarkMode = nop.MarkMode; + + if (parser[NKey::kArInclude].ThereIs) + { + nopArc.Include = true; + AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage); + } + if (parser[NKey::kArExclude].ThereIs) + { + nopArc.Include = false; + AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage); + } + + if (thereIsArchiveName) + { + nopArc.Include = true; + AddNameToCensor(arcCensor, nopArc, options.ArchiveName); + } + + arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); + + #ifdef _WIN32 + ConvertToLongNames(arcCensor); + #endif + + arcCensor.ExtendExclude(); + + if (options.StdInMode) + options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front(); + + if (isExtractGroupCommand) + { + if (options.StdOutMode) + { + if ( + options.Number_for_Percents == k_OutStream_stdout + // || options.Number_for_Out == k_OutStream_stdout + // || options.Number_for_Errors == k_OutStream_stdout + || + ( + (options.IsStdOutTerminal && options.IsStdErrTerminal) + && + ( + options.Number_for_Percents != k_OutStream_disabled + // || options.Number_for_Out != k_OutStream_disabled + // || options.Number_for_Errors != k_OutStream_disabled + ) + ) + ) + throw CArcCmdLineException(kSameTerminalError); + } + + if (parser[NKey::kOutputDir].ThereIs) + { + eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); + #ifdef _WIN32 + NFile::NName::NormalizeDirSeparators(eo.OutputDir); + #endif + NFile::NName::NormalizeDirPathPrefix(eo.OutputDir); + } + + eo.OverwriteMode = NExtract::NOverwriteMode::kAsk; + if (parser[NKey::kOverwrite].ThereIs) + { + eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex]; + eo.OverwriteMode_Force = true; + } + else if (options.YesToAll) + { + eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; + eo.OverwriteMode_Force = true; + } + } + + eo.PathMode = options.Command.GetPathMode(); + if (censorPathMode == NWildcard::k_AbsPath) + { + eo.PathMode = NExtract::NPathMode::kAbsPaths; + eo.PathMode_Force = true; + } + else if (censorPathMode == NWildcard::k_FullPath) + { + eo.PathMode = NExtract::NPathMode::kFullPaths; + eo.PathMode_Force = true; + } + } + else if (options.Command.IsFromUpdateGroup()) + { + if (parser[NKey::kArInclude].ThereIs) + throw CArcCmdLineException("-ai switch is not supported for this command"); + + CUpdateOptions &updateOptions = options.UpdateOptions; + + SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); + + updateOptions.MethodMode.Properties = options.Properties; + + if (parser[NKey::kPreserveATime].ThereIs) + updateOptions.PreserveATime = true; + if (parser[NKey::kShareForWrite].ThereIs) + updateOptions.OpenShareForWrite = true; + if (parser[NKey::kStopAfterOpenError].ThereIs) + updateOptions.StopAfterOpenError = true; + + updateOptions.PathMode = censorPathMode; + + updateOptions.AltStreams = options.AltStreams; + updateOptions.NtSecurity = options.NtSecurity; + updateOptions.HardLinks = options.HardLinks; + updateOptions.SymLinks = options.SymLinks; + + updateOptions.StoreOwnerId = options.StoreOwnerId; + updateOptions.StoreOwnerName = options.StoreOwnerName; + + updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; + if (updateOptions.EMailMode) + { + updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); + if (updateOptions.EMailAddress.Len() > 0) + if (updateOptions.EMailAddress[0] == L'.') + { + updateOptions.EMailRemoveAfter = true; + updateOptions.EMailAddress.Delete(0); + } + } + + updateOptions.StdOutMode = options.StdOutMode; + updateOptions.StdInMode = options.StdInMode; + + updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs; + updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs; + + if (updateOptions.StdOutMode && updateOptions.EMailMode) + throw CArcCmdLineException("stdout mode and email mode cannot be combined"); + + if (updateOptions.StdOutMode) + { + if (options.IsStdOutTerminal) + throw CArcCmdLineException(kTerminalOutError); + + if (options.Number_for_Percents == k_OutStream_stdout + || options.Number_for_Out == k_OutStream_stdout + || options.Number_for_Errors == k_OutStream_stdout) + throw CArcCmdLineException(kSameTerminalError); + } + + if (updateOptions.StdInMode) + updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); + + if (options.Command.CommandType == NCommandType::kRename) + if (updateOptions.Commands.Size() != 1) + throw CArcCmdLineException("Only one archive can be created with rename command"); + } + else if (options.Command.CommandType == NCommandType::kBenchmark) + { + options.NumIterations = 1; + options.NumIterations_Defined = false; + if (curCommandIndex < numNonSwitchStrings) + { + if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations)) + throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]); + curCommandIndex++; + options.NumIterations_Defined = true; + } + } + else if (options.Command.CommandType == NCommandType::kHash) + { + options.Censor.AddPathsToCensor(censorPathMode); + options.Censor.ExtendExclude(); + + CHashOptions &hashOptions = options.HashOptions; + hashOptions.PathMode = censorPathMode; + hashOptions.Methods = options.HashMethods; + // hashOptions.HashFilePath = options.HashFilePath; + if (parser[NKey::kPreserveATime].ThereIs) + hashOptions.PreserveATime = true; + if (parser[NKey::kShareForWrite].ThereIs) + hashOptions.OpenShareForWrite = true; + hashOptions.StdInMode = options.StdInMode; + hashOptions.AltStreamsMode = options.AltStreams.Val; + hashOptions.SymLinks = options.SymLinks; + } + else if (options.Command.CommandType == NCommandType::kInfo) + { + } + else + throw 20150919; +} + + + +#ifndef _WIN32 + +static AString g_ModuleDirPrefix; + +void Set_ModuleDirPrefix_From_ProgArg0(const char *s); +void Set_ModuleDirPrefix_From_ProgArg0(const char *s) +{ + AString a (s); + int sep = a.ReverseFind_PathSepar(); + a.DeleteFrom((unsigned)(sep + 1)); + g_ModuleDirPrefix = a; +} + +namespace NWindows { +namespace NDLL { + +FString GetModuleDirPrefix(); +FString GetModuleDirPrefix() +{ + FString s; + + s = fas2fs(g_ModuleDirPrefix); + if (s.IsEmpty()) + s = FTEXT(".") FSTRING_PATH_SEPARATOR; + return s; + /* + setenv("_7ZIP_HOME_DIR", "/test/", 0); + const char *home = getenv("_7ZIP_HOME_DIR"); + if (home) + s = home; + else + s = FTEXT(".") FSTRING_PATH_SEPARATOR; + return s; + */ +} + +}} + +#endif // ! _WIN32 diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h index 439ee700e..d17ec5a3c 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.h +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h @@ -1,170 +1,170 @@ -// ArchiveCommandLine.h - -#ifndef ZIP7_INC_ARCHIVE_COMMAND_LINE_H -#define ZIP7_INC_ARCHIVE_COMMAND_LINE_H - -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/Wildcard.h" - -#include "EnumDirItems.h" - -#include "Extract.h" -#include "HashCalc.h" -#include "Update.h" - -typedef CMessagePathException CArcCmdLineException; - -namespace NCommandType { enum EEnum -{ - kAdd = 0, - kUpdate, - kDelete, - kTest, - kExtract, - kExtractFull, - kList, - kBenchmark, - kInfo, - kHash, - kRename -};} - -struct CArcCommand -{ - NCommandType::EEnum CommandType; - - bool IsFromExtractGroup() const; - bool IsFromUpdateGroup() const; - bool IsTestCommand() const { return CommandType == NCommandType::kTest; } - NExtract::NPathMode::EEnum GetPathMode() const; -}; - -enum -{ - k_OutStream_disabled = 0, - k_OutStream_stdout = 1, - k_OutStream_stderr = 2 -}; - -struct CArcCmdLineOptions -{ - bool HelpMode; - - // bool LargePages; - bool CaseSensitive_Change; - bool CaseSensitive; - - bool IsInTerminal; - bool IsStdOutTerminal; - bool IsStdErrTerminal; - bool StdInMode; - bool StdOutMode; - bool EnableHeaders; - bool DisablePercents; - - - bool YesToAll; - bool ShowDialog; - bool TechMode; - bool ShowTime; - CBoolPair ListPathSeparatorSlash; - - CBoolPair NtSecurity; - CBoolPair AltStreams; - CBoolPair HardLinks; - CBoolPair SymLinks; - - CBoolPair StoreOwnerId; - CBoolPair StoreOwnerName; - - AString ListFields; - - int ConsoleCodePage; - - NWildcard::CCensor Censor; - - CArcCommand Command; - UString ArchiveName; - - #ifndef Z7_NO_CRYPTO - bool PasswordEnabled; - UString Password; - #endif - - UStringVector HashMethods; - // UString HashFilePath; - - // bool AppendName; - // UStringVector ArchivePathsSorted; - // UStringVector ArchivePathsFullSorted; - NWildcard::CCensor arcCensor; - UString ArcName_for_StdInMode; - - CObjectVector Properties; - - CExtractOptionsBase ExtractOptions; - - CUpdateOptions UpdateOptions; - CHashOptions HashOptions; - UString ArcType; - UStringVector ExcludedArcTypes; - - unsigned Number_for_Out; - unsigned Number_for_Errors; - unsigned Number_for_Percents; - unsigned LogLevel; - - // bool IsOutAllowed() const { return Number_for_Out != k_OutStream_disabled; } - - // Benchmark - UInt32 NumIterations; - bool NumIterations_Defined; - - CArcCmdLineOptions(): - HelpMode(false), - // LargePages(false), - CaseSensitive_Change(false), - CaseSensitive(false), - - IsInTerminal(false), - IsStdOutTerminal(false), - IsStdErrTerminal(false), - - StdInMode(false), - StdOutMode(false), - - EnableHeaders(false), - DisablePercents(false), - - YesToAll(false), - ShowDialog(false), - TechMode(false), - ShowTime(false), - - ConsoleCodePage(-1), - - Number_for_Out(k_OutStream_stdout), - Number_for_Errors(k_OutStream_stderr), - Number_for_Percents(k_OutStream_stdout), - - LogLevel(0) - { - ListPathSeparatorSlash.Val = -#ifdef _WIN32 - false; -#else - true; -#endif - } -}; - -class CArcCmdLineParser -{ - NCommandLineParser::CParser parser; -public: - UString Parse1Log; - void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options); - void Parse2(CArcCmdLineOptions &options); -}; - -#endif +// ArchiveCommandLine.h + +#ifndef ZIP7_INC_ARCHIVE_COMMAND_LINE_H +#define ZIP7_INC_ARCHIVE_COMMAND_LINE_H + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/Wildcard.h" + +#include "EnumDirItems.h" + +#include "Extract.h" +#include "HashCalc.h" +#include "Update.h" + +typedef CMessagePathException CArcCmdLineException; + +namespace NCommandType { enum EEnum +{ + kAdd = 0, + kUpdate, + kDelete, + kTest, + kExtract, + kExtractFull, + kList, + kBenchmark, + kInfo, + kHash, + kRename +};} + +struct CArcCommand +{ + NCommandType::EEnum CommandType; + + bool IsFromExtractGroup() const; + bool IsFromUpdateGroup() const; + bool IsTestCommand() const { return CommandType == NCommandType::kTest; } + NExtract::NPathMode::EEnum GetPathMode() const; +}; + +enum +{ + k_OutStream_disabled = 0, + k_OutStream_stdout = 1, + k_OutStream_stderr = 2 +}; + +struct CArcCmdLineOptions +{ + bool HelpMode; + + // bool LargePages; + bool CaseSensitive_Change; + bool CaseSensitive; + + bool IsInTerminal; + bool IsStdOutTerminal; + bool IsStdErrTerminal; + bool StdInMode; + bool StdOutMode; + bool EnableHeaders; + bool DisablePercents; + + + bool YesToAll; + bool ShowDialog; + bool TechMode; + bool ShowTime; + CBoolPair ListPathSeparatorSlash; + + CBoolPair NtSecurity; + CBoolPair AltStreams; + CBoolPair HardLinks; + CBoolPair SymLinks; + + CBoolPair StoreOwnerId; + CBoolPair StoreOwnerName; + + AString ListFields; + + int ConsoleCodePage; + + NWildcard::CCensor Censor; + + CArcCommand Command; + UString ArchiveName; + + #ifndef Z7_NO_CRYPTO + bool PasswordEnabled; + UString Password; + #endif + + UStringVector HashMethods; + // UString HashFilePath; + + // bool AppendName; + // UStringVector ArchivePathsSorted; + // UStringVector ArchivePathsFullSorted; + NWildcard::CCensor arcCensor; + UString ArcName_for_StdInMode; + + CObjectVector Properties; + + CExtractOptionsBase ExtractOptions; + + CUpdateOptions UpdateOptions; + CHashOptions HashOptions; + UString ArcType; + UStringVector ExcludedArcTypes; + + unsigned Number_for_Out; + unsigned Number_for_Errors; + unsigned Number_for_Percents; + unsigned LogLevel; + + // bool IsOutAllowed() const { return Number_for_Out != k_OutStream_disabled; } + + // Benchmark + UInt32 NumIterations; + bool NumIterations_Defined; + + CArcCmdLineOptions(): + HelpMode(false), + // LargePages(false), + CaseSensitive_Change(false), + CaseSensitive(false), + + IsInTerminal(false), + IsStdOutTerminal(false), + IsStdErrTerminal(false), + + StdInMode(false), + StdOutMode(false), + + EnableHeaders(false), + DisablePercents(false), + + YesToAll(false), + ShowDialog(false), + TechMode(false), + ShowTime(false), + + ConsoleCodePage(-1), + + Number_for_Out(k_OutStream_stdout), + Number_for_Errors(k_OutStream_stderr), + Number_for_Percents(k_OutStream_stdout), + + LogLevel(0) + { + ListPathSeparatorSlash.Val = +#ifdef _WIN32 + false; +#else + true; +#endif + } +}; + +class CArcCmdLineParser +{ + NCommandLineParser::CParser parser; +public: + UString Parse1Log; + void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options); + void Parse2(CArcCmdLineOptions &options); +}; + +#endif diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 4815f4bff..67ea29c73 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -1,2721 +1,2747 @@ -// ArchiveExtractCallback.cpp - -#include "StdAfx.h" - -#undef sprintf -#undef printf - -// #include -// #include "../../../../C/CpuTicks.h" - -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) -#define Z7_USE_SECURITY_CODE -#include "../../../Windows/SecurityUtils.h" -#endif - -#include "../../Common/FilePathAutoRename.h" -#include "../../Common/StreamUtils.h" - -#include "../Common/ExtractingFilePath.h" -#include "../Common/PropIDUtils.h" - -#include "ArchiveExtractCallback.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static const char * const kCantAutoRename = "Cannot create file with auto name"; -static const char * const kCantRenameFile = "Cannot rename existing file"; -static const char * const kCantDeleteOutputFile = "Cannot delete output file"; -static const char * const kCantDeleteOutputDir = "Cannot delete output folder"; -static const char * const kCantOpenOutFile = "Cannot open output file"; -#ifndef Z7_SFX -static const char * const kCantOpenInFile = "Cannot open input file"; -#endif -static const char * const kCantSetFileLen = "Cannot set length for output file"; -#ifdef SUPPORT_LINKS -static const char * const kCantCreateHardLink = "Cannot create hard link"; -static const char * const kCantCreateSymLink = "Cannot create symbolic link"; -#endif - -#ifndef Z7_SFX - -Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - HRESULT result = S_OK; - if (_stream) - result = _stream->Write(data, size, &size); - if (_calculate) - _hash->Update(data, size); - _size += size; - if (processedSize) - *processedSize = size; - return result; -} - -#endif // Z7_SFX - - -#ifdef Z7_USE_SECURITY_CODE -bool InitLocalPrivileges(); -bool InitLocalPrivileges() -{ - NSecurity::CAccessToken token; - if (!token.OpenProcessToken(GetCurrentProcess(), - TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)) - return false; - - TOKEN_PRIVILEGES tp; - - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) - return false; - if (!token.AdjustPrivileges(&tp)) - return false; - return (GetLastError() == ERROR_SUCCESS); -} -#endif // Z7_USE_SECURITY_CODE - - - -#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) - -static const char * const kOfficeExtensions = - " doc dot wbk" - " docx docm dotx dotm docb wll wwl" - " xls xlt xlm" - " xlsx xlsm xltx xltm xlsb xla xlam" - " ppt pot pps ppa ppam" - " pptx pptm potx potm ppam ppsx ppsm sldx sldm" - " "; - -static bool FindExt2(const char *p, const UString &name) -{ - const int pathPos = name.ReverseFind_PathSepar(); - const int dotPos = name.ReverseFind_Dot(); - if (dotPos < 0 - || dotPos < pathPos - || dotPos == (int)name.Len() - 1) - return false; - - AString s; - for (unsigned pos = (unsigned)(dotPos + 1);; pos++) - { - const wchar_t c = name[pos]; - if (c <= 0) - break; - if (c >= 0x80) - return false; - s.Add_Char((char)MyCharLower_Ascii((char)c)); - } - for (unsigned i = 0; p[i] != 0;) - { - unsigned j; - for (j = i; p[j] != ' '; j++); - if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0) - return true; - i = j + 1; - } - return false; -} - - -static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); - -void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf) -{ - FString fileName (fileName2); - fileName += k_ZoneId_StreamName; - - buf.Free(); - NIO::CInFile file; - if (!file.Open(fileName)) - return; - UInt64 fileSize; - if (!file.GetLength(fileSize)) - return; - if (fileSize == 0 || fileSize >= ((UInt32)1 << 16)) - return; - buf.Alloc((size_t)fileSize); - size_t processed; - if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize) - return; - buf.Free(); -} - -bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf) -{ - FString path (fileName); - path += k_ZoneId_StreamName; - NIO::COutFile file; - if (!file.Create_ALWAYS(path)) - return false; - return file.WriteFull(buf, buf.Size()); -} - -#endif - - -#ifdef SUPPORT_LINKS - -int CHardLinkNode::Compare(const CHardLinkNode &a) const -{ - if (StreamId < a.StreamId) return -1; - if (StreamId > a.StreamId) return 1; - return MyCompare(INode, a.INode); -} - -static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined) -{ - h.INode = 0; - h.StreamId = (UInt64)(Int64)-1; - defined = false; - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidINode, &prop)) - if (!ConvertPropVariantToUInt64(prop, h.INode)) - return S_OK; - } - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidStreamId, &prop)) - ConvertPropVariantToUInt64(prop, h.StreamId); - } - defined = true; - return S_OK; -} - - -HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector *realIndices) -{ - _hardLinks.Clear(); - - if (!_arc->Ask_INode) - return S_OK; - - IInArchive *archive = _arc->Archive; - CRecordVector &hardIDs = _hardLinks.IDs; - - { - UInt32 numItems; - if (realIndices) - numItems = realIndices->Size(); - else - { - RINOK(archive->GetNumberOfItems(&numItems)) - } - - for (UInt32 i = 0; i < numItems; i++) - { - CHardLinkNode h; - bool defined; - const UInt32 realIndex = realIndices ? (*realIndices)[i] : i; - - RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined)) - if (defined) - { - bool isAltStream = false; - RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream)) - if (!isAltStream) - { - bool isDir = false; - RINOK(Archive_IsItem_Dir(archive, realIndex, isDir)) - if (!isDir) - hardIDs.Add(h); - } - } - } - } - - hardIDs.Sort2(); - - { - // we keep only items that have 2 or more items - unsigned k = 0; - unsigned numSame = 1; - for (unsigned i = 1; i < hardIDs.Size(); i++) - { - if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) - numSame = 1; - else if (++numSame == 2) - { - if (i - 1 != k) - hardIDs[k] = hardIDs[i - 1]; - k++; - } - } - hardIDs.DeleteFrom(k); - } - - _hardLinks.PrepareLinks(); - return S_OK; -} - -#endif // SUPPORT_LINKS - - -CArchiveExtractCallback::CArchiveExtractCallback(): - _arc(NULL), - Write_CTime(true), - Write_ATime(true), - Write_MTime(true), - Is_elimPrefix_Mode(false), - _multiArchives(false) -{ - LocalProgressSpec = new CLocalProgress(); - _localProgress = LocalProgressSpec; - - #ifdef Z7_USE_SECURITY_CODE - _saclEnabled = InitLocalPrivileges(); - #endif -} - - -void CArchiveExtractCallback::InitBeforeNewArchive() -{ - #if defined(_WIN32) && !defined(UNDER_CE) - ZoneBuf.Free(); - #endif -} - -void CArchiveExtractCallback::Init( - const CExtractNtOptions &ntOptions, - const NWildcard::CCensorNode *wildcardCensor, - const CArc *arc, - IFolderArchiveExtractCallback *extractCallback2, - bool stdOutMode, bool testMode, - const FString &directoryPath, - const UStringVector &removePathParts, bool removePartsForAltStreams, - UInt64 packSize) -{ - ClearExtractedDirsInfo(); - _outFileStream.Release(); - _bufPtrSeqOutStream.Release(); - - #ifdef SUPPORT_LINKS - _hardLinks.Clear(); - #endif - - #ifdef SUPPORT_ALT_STREAMS - _renamedFiles.Clear(); - #endif - - _ntOptions = ntOptions; - _wildcardCensor = wildcardCensor; - - _stdOutMode = stdOutMode; - _testMode = testMode; - - // _progressTotal = 0; - // _progressTotal_Defined = false; - - _packTotal = packSize; - _progressTotal = packSize; - _progressTotal_Defined = true; - - _extractCallback2 = extractCallback2; - - /* - _compressProgress.Release(); - _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); - - _callbackMessage.Release(); - _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage); - */ - - _folderArchiveExtractCallback2.Release(); - _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); - - #ifndef Z7_SFX - - ExtractToStreamCallback.Release(); - _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); - if (ExtractToStreamCallback) - { - Int32 useStreams = 0; - if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) - useStreams = 0; - if (useStreams == 0) - ExtractToStreamCallback.Release(); - } - - #endif - - LocalProgressSpec->Init(extractCallback2, true); - LocalProgressSpec->SendProgress = false; - - _removePathParts = removePathParts; - _removePartsForAltStreams = removePartsForAltStreams; - - #ifndef Z7_SFX - _baseParentFolder = (UInt32)(Int32)-1; - _use_baseParentFolder_mode = false; - #endif - - _arc = arc; - _dirPathPrefix = directoryPath; - _dirPathPrefix_Full = directoryPath; - #if defined(_WIN32) && !defined(UNDER_CE) - if (!NName::IsAltPathPrefix(_dirPathPrefix)) - #endif - { - NName::NormalizeDirPathPrefix(_dirPathPrefix); - NDir::MyGetFullPathName(directoryPath, _dirPathPrefix_Full); - NName::NormalizeDirPathPrefix(_dirPathPrefix_Full); - } -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size)) -{ - COM_TRY_BEGIN - _progressTotal = size; - _progressTotal_Defined = true; - if (!_multiArchives && _extractCallback2) - return _extractCallback2->SetTotal(size); - return S_OK; - COM_TRY_END -} - - -static void NormalizeVals(UInt64 &v1, UInt64 &v2) -{ - const UInt64 kMax = (UInt64)1 << 31; - while (v1 > kMax) - { - v1 >>= 1; - v2 >>= 1; - } -} - - -static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) -{ - NormalizeVals(packTotal, unpTotal); - NormalizeVals(unpCur, unpTotal); - if (unpTotal == 0) - unpTotal = 1; - return unpCur * packTotal / unpTotal; -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)) -{ - COM_TRY_BEGIN - - if (!_extractCallback2) - return S_OK; - - UInt64 packCur; - if (_multiArchives) - { - packCur = LocalProgressSpec->InSize; - if (completeValue && _progressTotal_Defined) - packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal); - completeValue = &packCur; - } - return _extractCallback2->SetCompleted(completeValue); - - COM_TRY_END -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - COM_TRY_BEGIN - return _localProgress->SetRatioInfo(inSize, outSize); - COM_TRY_END -} - - -void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) -{ - // we use (_item.IsDir) in this function - - bool isAbsPath = false; - - if (!dirPathParts.IsEmpty()) - { - const UString &s = dirPathParts[0]; - if (s.IsEmpty()) - isAbsPath = true; - #if defined(_WIN32) && !defined(UNDER_CE) - else - { - if (NName::IsDrivePath2(s)) - isAbsPath = true; - } - #endif - } - - if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) - fullPath.Empty(); - else - fullPath = _dirPathPrefix; - - FOR_VECTOR (i, dirPathParts) - { - if (i != 0) - fullPath.Add_PathSepar(); - const UString &s = dirPathParts[i]; - fullPath += us2fs(s); - - const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir); - - if (fullPath.IsEmpty()) - { - if (isFinalDir) - _itemFailure = true; - continue; - } - - #if defined(_WIN32) && !defined(UNDER_CE) - if (_pathMode == NExtract::NPathMode::kAbsPaths) - if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s)) - { - if (isFinalDir) - { - // we don't want to call SetAttrib() for root drive path - _itemFailure = true; - } - continue; - } - #endif - - HRESULT hres = S_OK; - if (!CreateDir(fullPath)) - hres = GetLastError_noZero_HRESULT(); - if (isFinalDir) - { - if (!NFile::NFind::DoesDirExist(fullPath)) - { - _itemFailure = true; - SendMessageError_with_Error(hres, "Cannot create folder", fullPath); - } - } - } -} - - -HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, CArcTime &ft) -{ - ft.Clear(); - NCOM::CPropVariant prop; - RINOK(_arc->Archive->GetProperty(index, propID, &prop)) - if (prop.vt == VT_FILETIME) - ft.Set_From_Prop(prop); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - - -HRESULT CArchiveExtractCallback::GetUnpackSize() -{ - return _arc->GetItem_Size(_index, _curSize, _curSize_Defined); -} - -static void AddPathToMessage(UString &s, const FString &path) -{ - s += " : "; - s += fs2us(path); -} - -HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) -{ - UString s (message); - AddPathToMessage(s, path); - return _extractCallback2->MessageError(s); -} - - -HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) -{ - UString s (message); - if (errorCode != S_OK) - { - s += " : "; - s += NError::MyFormatMessage(errorCode); - } - AddPathToMessage(s, path); - return _extractCallback2->MessageError(s); -} - -HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) -{ - const HRESULT errorCode = GetLastError_noZero_HRESULT(); - return SendMessageError_with_Error(errorCode, message, path); -} - -HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) -{ - UString s (message); - if (errorCode != 0) - { - s += " : "; - s += NError::MyFormatMessage(errorCode); - } - AddPathToMessage(s, path1); - AddPathToMessage(s, path2); - return _extractCallback2->MessageError(s); -} - -#ifndef Z7_SFX - -Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) -{ - /* - if (propID == kpidName) - { - COM_TRY_BEGIN - NCOM::CPropVariant prop = Name; - prop.Detach(value); - return S_OK; - COM_TRY_END - } - */ - return Arc->Archive->GetProperty(IndexInArc, propID, value); -} - -#endif // Z7_SFX - - -#ifdef SUPPORT_LINKS - -static UString GetDirPrefixOf(const UString &src) -{ - UString s (src); - if (!s.IsEmpty()) - { - if (IsPathSepar(s.Back())) - s.DeleteBack(); - int pos = s.ReverseFind_PathSepar(); - s.DeleteFrom((unsigned)(pos + 1)); - } - return s; -} - -#endif // SUPPORT_LINKS - -struct CLinkLevelsInfo -{ - bool IsAbsolute; - int LowLevel; - int FinalLevel; - - void Parse(const UString &path); -}; - -void CLinkLevelsInfo::Parse(const UString &path) -{ - IsAbsolute = NName::IsAbsolutePath(path); - - LowLevel = 0; - FinalLevel = 0; - - UStringVector parts; - SplitPathToParts(path, parts); - int level = 0; - - FOR_VECTOR (i, parts) - { - const UString &s = parts[i]; - if (s.IsEmpty()) - { - if (i == 0) - IsAbsolute = true; - continue; - } - if (s == L".") - continue; - if (s == L"..") - { - level--; - if (LowLevel > level) - LowLevel = level; - } - else - level++; - } - - FinalLevel = level; -} - - -bool IsSafePath(const UString &path); -bool IsSafePath(const UString &path) -{ - CLinkLevelsInfo levelsInfo; - levelsInfo.Parse(path); - return !levelsInfo.IsAbsolute - && levelsInfo.LowLevel >= 0 - && levelsInfo.FinalLevel > 0; -} - - -bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); -bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) -{ - bool found = false; - - // CheckPathVect() doesn't check path to Parent nodes - if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include)) - { - if (!include) - return true; - - #ifdef SUPPORT_ALT_STREAMS - if (!item.IsAltStream) - return true; - #endif - - found = true; - } - - #ifdef SUPPORT_ALT_STREAMS - - if (!item.IsAltStream) - return false; - - UStringVector pathParts2 = item.PathParts; - if (pathParts2.IsEmpty()) - pathParts2.AddNew(); - UString &back = pathParts2.Back(); - back.Add_Colon(); - back += item.AltStreamName; - bool include2; - - if (node.CheckPathVect(pathParts2, - true, // isFile, - include2)) - { - include = include2; - return true; - } - - #endif // SUPPORT_ALT_STREAMS - - return found; -} - - -bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item) -{ - bool include; - if (CensorNode_CheckPath2(node, item, include)) - return include; - return false; -} - - -static FString MakePath_from_2_Parts(const FString &prefix, const FString &path) -{ - FString s (prefix); - #if defined(_WIN32) && !defined(UNDER_CE) - if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back())) - { - if (!NName::IsDriveRootPath_SuperAllowed(prefix)) - s.DeleteBack(); - } - #endif - s += path; - return s; -} - - - -#ifdef SUPPORT_LINKS - -/* -struct CTempMidBuffer -{ - void *Buf; - - CTempMidBuffer(size_t size): Buf(NULL) { Buf = ::MidAlloc(size); } - ~CTempMidBuffer() { ::MidFree(Buf); } -}; - -HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream) -{ - const size_t kBufSize = 1 << 16; - CTempMidBuffer buf(kBufSize); - if (!buf.Buf) - return E_OUTOFMEMORY; - - NIO::CInFile inFile; - NIO::COutFile outFile; - - if (!inFile.Open(_copyFile_Path)) - return SendMessageError_with_LastError("Open error", _copyFile_Path); - - for (;;) - { - UInt32 num; - - if (!inFile.Read(buf.Buf, kBufSize, num)) - return SendMessageError_with_LastError("Read error", _copyFile_Path); - - if (num == 0) - return S_OK; - - - RINOK(WriteStream(outStream, buf.Buf, num)); - } -} -*/ - - -HRESULT CArchiveExtractCallback::ReadLink() -{ - IInArchive *archive = _arc->Archive; - const UInt32 index = _index; - _link.Clear(); - - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidHardLink, &prop)) - if (prop.vt == VT_BSTR) - { - _link.isHardLink = true; - // _link.isCopyLink = false; - _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive - _link.linkPath.SetFromBstr(prop.bstrVal); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - } - - /* - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); - if (prop.vt == VT_BSTR) - { - _link.isHardLink = false; - _link.isCopyLink = true; - _link.isRelative = false; // RAR5: copy links are from root folder of archive - _link.linkPath.SetFromBstr(prop.bstrVal); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - } - */ - - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidSymLink, &prop)) - if (prop.vt == VT_BSTR) - { - _link.isHardLink = false; - // _link.isCopyLink = false; - _link.isRelative = true; // RAR5, TAR: symbolic links can be relative - _link.linkPath.SetFromBstr(prop.bstrVal); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - } - - NtReparse_Data = NULL; - NtReparse_Size = 0; - - if (_link.linkPath.IsEmpty() && _arc->GetRawProps) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - - _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); - - // if (dataSize == 1234567) // for debug: unpacking without reparse - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - - // 21.06: we need kpidNtReparse in linux for wim archives created in Windows - // #ifdef _WIN32 - - NtReparse_Data = data; - NtReparse_Size = dataSize; - - CReparseAttr reparse; - bool isOkReparse = reparse.Parse((const Byte *)data, dataSize); - if (isOkReparse) - { - _link.isHardLink = false; - // _link.isCopyLink = false; - _link.linkPath = reparse.GetPath(); - _link.isJunction = reparse.IsMountPoint(); - - if (reparse.IsSymLink_WSL()) - { - _link.isWSL = true; - _link.isRelative = reparse.IsRelative_WSL(); - } - else - _link.isRelative = reparse.IsRelative_Win(); - - // const AString s = GetAnsiString(_link.linkPath); - // printf("\n_link.linkPath: %s\n", s.Ptr()); - - #ifndef _WIN32 - _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); - #endif - } - // #endif - } - } - - if (_link.linkPath.IsEmpty()) - return S_OK; - - { - #ifdef _WIN32 - _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - - // rar5 uses "\??\" prefix for absolute links - if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR)) - { - _link.isRelative = false; - _link.linkPath.DeleteFrontal(4); - } - - for (;;) - // while (NName::IsAbsolutePath(linkPath)) - { - unsigned n = NName::GetRootPrefixSize(_link.linkPath); - if (n == 0) - break; - _link.isRelative = false; - _link.linkPath.DeleteFrontal(n); - } - } - - if (_link.linkPath.IsEmpty()) - return S_OK; - - if (!_link.isRelative && _removePathParts.Size() != 0) - { - UStringVector pathParts; - SplitPathToParts(_link.linkPath, pathParts); - bool badPrefix = false; - FOR_VECTOR (i, _removePathParts) - { - if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) - { - badPrefix = true; - break; - } - } - if (!badPrefix) - pathParts.DeleteFrontal(_removePathParts.Size()); - _link.linkPath = MakePathFromParts(pathParts); - } - - /* - if (!_link.linkPath.IsEmpty()) - { - printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr()); - } - */ - - return S_OK; -} - -#endif // SUPPORT_LINKS - - -#ifndef _WIN32 - -static HRESULT GetOwner(IInArchive *archive, - UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) -{ - { - NWindows::NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, pidId, &prop)) - if (prop.vt == VT_UI4) - { - res.Id_Defined = true; - res.Id = prop.ulVal; // for debug - // res.Id++; // for debug - // if (pidId == kpidGroupId) res.Id += 7; // for debug - // res.Id = 0; // for debug - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - { - NWindows::NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, pidName, &prop)) - if (prop.vt == VT_BSTR) - { - const UString s = prop.bstrVal; - ConvertUnicodeToUTF8(s, res.Name); - } - else if (prop.vt == VT_UI4) - { - res.Id_Defined = true; - res.Id = prop.ulVal; - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - } - return S_OK; -} - -#endif - - -HRESULT CArchiveExtractCallback::Read_fi_Props() -{ - IInArchive *archive = _arc->Archive; - const UInt32 index = _index; - - _fi.Attrib_Defined = false; - - #ifndef _WIN32 - _fi.Owner.Clear(); - _fi.Group.Clear(); - #endif - - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidPosixAttrib, &prop)) - if (prop.vt == VT_UI4) - { - _fi.SetFromPosixAttrib(prop.ulVal); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - } - - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidAttrib, &prop)) - if (prop.vt == VT_UI4) - { - _fi.Attrib = prop.ulVal; - _fi.Attrib_Defined = true; - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - } - - RINOK(GetTime(index, kpidCTime, _fi.CTime)) - RINOK(GetTime(index, kpidATime, _fi.ATime)) - RINOK(GetTime(index, kpidMTime, _fi.MTime)) - - #ifndef _WIN32 - if (_ntOptions.ExtractOwner) - { - // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath); - GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner); - GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group); - } - #endif - - return S_OK; -} - - - -void CArchiveExtractCallback::CorrectPathParts() -{ - UStringVector &pathParts = _item.PathParts; - - #ifdef SUPPORT_ALT_STREAMS - if (!_item.IsAltStream - || !pathParts.IsEmpty() - || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)) - #endif - Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, _keepAndReplaceEmptyDirPrefixes, pathParts, _item.MainIsDir); - - #ifdef SUPPORT_ALT_STREAMS - - if (_item.IsAltStream) - { - UString s (_item.AltStreamName); - Correct_AltStream_Name(s); - bool needColon = true; - - if (pathParts.IsEmpty()) - { - pathParts.AddNew(); - if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt) - needColon = false; - } - #ifdef _WIN32 - else if (_pathMode == NExtract::NPathMode::kAbsPaths && - NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size()) - pathParts.AddNew(); - #endif - - UString &name = pathParts.Back(); - if (needColon) - name.Add_Char((char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':')); - name += s; - } - - #endif // SUPPORT_ALT_STREAMS -} - - -void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) -{ - pt.CTime_Defined = false; - pt.ATime_Defined = false; - pt.MTime_Defined = false; - - if (Write_MTime) - { - if (_fi.MTime.Def) - { - _fi.MTime.Write_To_FiTime(pt.MTime); - pt.MTime_Defined = true; - } - else if (_arc->MTime.Def) - { - _arc->MTime.Write_To_FiTime(pt.MTime); - pt.MTime_Defined = true; - } - } - - if (Write_CTime && _fi.CTime.Def) - { - _fi.CTime.Write_To_FiTime(pt.CTime); - pt.CTime_Defined = true; - } - - if (Write_ATime && _fi.ATime.Def) - { - _fi.ATime.Write_To_FiTime(pt.ATime); - pt.ATime_Defined = true; - } -} - - -void CArchiveExtractCallback::CreateFolders() -{ - // 21.04 : we don't change original (_item.PathParts) here - UStringVector pathParts = _item.PathParts; - - // bool is_DirOp = false; - if (!pathParts.IsEmpty()) - { - /* v23: if we extract symlink, and we know that it links to dir: - Linux: we don't create dir item (symlink_from_path) here. - Windows: SetReparseData() will create dir item, if it doesn't exist, - but if we create dir item here, it's not problem. */ - if (!_item.IsDir - #ifdef SUPPORT_LINKS - #ifndef WIN32 - || !_link.linkPath.IsEmpty() - #endif - #endif - ) - pathParts.DeleteBack(); - // else is_DirOp = true; - } - - if (pathParts.IsEmpty()) - { - /* if (_some_pathParts_wereRemoved && Is_elimPrefix_Mode), - then we can have empty pathParts() here for root folder. - v24.00: fixed: we set timestamps for such folder still. - */ - if (!_some_pathParts_wereRemoved || - !Is_elimPrefix_Mode) - return; - // return; // ignore empty paths case - } - /* - if (is_DirOp) - { - RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) - _op_WasReported = true; - } - */ - - FString fullPathNew; - CreateComplexDirectory(pathParts, fullPathNew); - - /* - if (is_DirOp) - { - RINOK(SetOperationResult( - // _itemFailure ? NArchive::NExtract::NOperationResult::kDataError : - NArchive::NExtract::NOperationResult::kOK - )) - } - */ - - if (!_item.IsDir) - return; - if (fullPathNew.IsEmpty()) - return; - - if (_itemFailure) - return; - - CDirPathTime pt; - GetFiTimesCAM(pt); - - if (pt.IsSomeTimeDefined()) - { - pt.Path = fullPathNew; - pt.SetDirTime(); - _extractedFolders.Add(pt); - } -} - - - -/* - CheckExistFile(fullProcessedPath) - it can change: fullProcessedPath, _isRenamed, _overwriteMode - (needExit = true) means that we must exit GetStream() even for S_OK result. -*/ - -HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool &needExit) -{ - needExit = true; // it was set already before - - NFind::CFileInfo fileInfo; - - if (fileInfo.Find(fullProcessedPath)) - { - if (_overwriteMode == NExtract::NOverwriteMode::kSkip) - return S_OK; - - if (_overwriteMode == NExtract::NOverwriteMode::kAsk) - { - const int slashPos = fullProcessedPath.ReverseFind_PathSepar(); - const FString realFullProcessedPath = fullProcessedPath.Left((unsigned)(slashPos + 1)) + fileInfo.Name; - - /* (fileInfo) can be symbolic link. - we can show final file properties here. */ - - FILETIME ft1; - FiTime_To_FILETIME(fileInfo.MTime, ft1); - - Int32 overwriteResult; - RINOK(_extractCallback2->AskOverwrite( - fs2us(realFullProcessedPath), &ft1, &fileInfo.Size, _item.Path, - _fi.MTime.Def ? &_fi.MTime.FT : NULL, - _curSize_Defined ? &_curSize : NULL, - &overwriteResult)) - - switch (overwriteResult) - { - case NOverwriteAnswer::kCancel: - return E_ABORT; - case NOverwriteAnswer::kNo: - return S_OK; - case NOverwriteAnswer::kNoToAll: - _overwriteMode = NExtract::NOverwriteMode::kSkip; - return S_OK; - - case NOverwriteAnswer::kYes: - break; - case NOverwriteAnswer::kYesToAll: - _overwriteMode = NExtract::NOverwriteMode::kOverwrite; - break; - case NOverwriteAnswer::kAutoRename: - _overwriteMode = NExtract::NOverwriteMode::kRename; - break; - default: - return E_FAIL; - } - } // NExtract::NOverwriteMode::kAsk - - if (_overwriteMode == NExtract::NOverwriteMode::kRename) - { - if (!AutoRenamePath(fullProcessedPath)) - { - RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)) - return E_FAIL; - } - _isRenamed = true; - } - else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting) - { - FString existPath (fullProcessedPath); - if (!AutoRenamePath(existPath)) - { - RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)) - return E_FAIL; - } - // MyMoveFile can rename folders. So it's OK to use it for folders too - if (!MyMoveFile(fullProcessedPath, existPath)) - { - HRESULT errorCode = GetLastError_noZero_HRESULT(); - RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath)) - return E_FAIL; - } - } - else // not Rename* - { - if (fileInfo.IsDir()) - { - // do we need to delete all files in folder? - if (!RemoveDir(fullProcessedPath)) - { - RINOK(SendMessageError_with_LastError(kCantDeleteOutputDir, fullProcessedPath)) - return S_OK; - } - } - else // fileInfo is not Dir - { - if (NFind::DoesFileExist_Raw(fullProcessedPath)) - if (!DeleteFileAlways(fullProcessedPath)) - if (GetLastError() != ERROR_FILE_NOT_FOUND) // check it in linux - { - RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath)) - return S_OK; - // return E_FAIL; - } - } // fileInfo is not Dir - } // not Rename* - } - else // not Find(fullProcessedPath) - { - #if defined(_WIN32) && !defined(UNDER_CE) - // we need to clear READ-ONLY of parent before creating alt stream - int colonPos = NName::FindAltStreamColon(fullProcessedPath); - if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0) - { - FString parentFsPath (fullProcessedPath); - parentFsPath.DeleteFrom((unsigned)colonPos); - NFind::CFileInfo parentFi; - if (parentFi.Find(parentFsPath)) - { - if (parentFi.IsReadOnly()) - SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY); - } - } - #endif // defined(_WIN32) && !defined(UNDER_CE) - } - - needExit = false; - return S_OK; -} - - - - - - -HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr &outStreamLoc, bool &needExit) -{ - needExit = true; - - RINOK(Read_fi_Props()) - - #ifdef SUPPORT_LINKS - IInArchive *archive = _arc->Archive; - #endif - - const UInt32 index = _index; - - bool isAnti = false; - RINOK(_arc->IsItem_Anti(index, isAnti)) - - CorrectPathParts(); - UString processedPath (MakePathFromParts(_item.PathParts)); - - if (!isAnti) - { - // 21.04: CreateFolders doesn't change (_item.PathParts) - CreateFolders(); - } - - FString fullProcessedPath (us2fs(processedPath)); - if (_pathMode != NExtract::NPathMode::kAbsPaths - || !NName::IsAbsolutePath(processedPath)) - { - fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath); - } - - #ifdef SUPPORT_ALT_STREAMS - if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1) - { - const int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex)); - if (renIndex != -1) - { - const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex]; - fullProcessedPath = pair.Path; - fullProcessedPath.Add_Colon(); - UString s (_item.AltStreamName); - Correct_AltStream_Name(s); - fullProcessedPath += us2fs(s); - } - } - #endif // SUPPORT_ALT_STREAMS - - if (_item.IsDir) - { - _diskFilePath = fullProcessedPath; - if (isAnti) - RemoveDir(_diskFilePath); - #ifdef SUPPORT_LINKS - if (_link.linkPath.IsEmpty()) - #endif - { - if (!isAnti) - SetAttrib(); - return S_OK; - } - } - else if (!_isSplit) - { - RINOK(CheckExistFile(fullProcessedPath, needExit)) - if (needExit) - return S_OK; - needExit = true; - } - - _diskFilePath = fullProcessedPath; - - - if (isAnti) - { - needExit = false; - return S_OK; - } - - // not anti - - #ifdef SUPPORT_LINKS - - if (!_link.linkPath.IsEmpty()) - { - #ifndef UNDER_CE - { - bool linkWasSet = false; - RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet)) - if (linkWasSet) - { - _isSymLinkCreated = _link.IsSymLink(); - SetAttrib(); - // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); - } - } - #endif // UNDER_CE - - // if (_copyFile_Path.IsEmpty()) - { - needExit = false; - return S_OK; - } - } - - if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream && !_item.IsDir) - { - CHardLinkNode h; - bool defined; - RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)) - if (defined) - { - const int linkIndex = _hardLinks.IDs.FindInSorted2(h); - if (linkIndex != -1) - { - FString &hl = _hardLinks.Links[(unsigned)linkIndex]; - if (hl.IsEmpty()) - hl = fullProcessedPath; - else - { - if (!MyCreateHardLink(fullProcessedPath, hl)) - { - const HRESULT errorCode = GetLastError_noZero_HRESULT(); - RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl)) - return S_OK; - } - - // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); - // _needSetAttrib = true; // do we need to set attribute ? - SetAttrib(); - needExit = false; - return S_OK; - } - } - } - } - - #endif // SUPPORT_LINKS - - - // ---------- CREATE WRITE FILE ----- - - _outFileStreamSpec = new COutFileStream; - CMyComPtr outFileStream_Loc(_outFileStreamSpec); - - if (!_outFileStreamSpec->Create_ALWAYS_or_Open_ALWAYS(fullProcessedPath, !_isSplit)) - { - // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) - { - RINOK(SendMessageError_with_LastError(kCantOpenOutFile, fullProcessedPath)) - return S_OK; - } - } - - _needSetAttrib = true; - - bool is_SymLink_in_Data = false; - - if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12)) - { - if (_fi.IsLinuxSymLink()) - { - is_SymLink_in_Data = true; - _is_SymLink_in_Data_Linux = true; - } - else if (_fi.IsReparse()) - { - is_SymLink_in_Data = true; - _is_SymLink_in_Data_Linux = false; - } - } - - if (is_SymLink_in_Data) - { - _outMemBuf.Alloc((size_t)_curSize); - _bufPtrSeqOutStream_Spec = new CBufPtrSeqOutStream; - _bufPtrSeqOutStream = _bufPtrSeqOutStream_Spec; - _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); - outStreamLoc = _bufPtrSeqOutStream; - } - else // not reprase - { - if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) - { - // UInt64 ticks = GetCpuTicks(); - _fileLength_that_WasSet = _curSize; - bool res = _outFileStreamSpec->File.SetLength(_curSize); - _fileLength_WasSet = res; - - // ticks = GetCpuTicks() - ticks; - // printf("\nticks = %10d\n", (unsigned)ticks); - if (!res) - { - RINOK(SendMessageError_with_LastError(kCantSetFileLen, fullProcessedPath)) - } - - /* - _outFileStreamSpec->File.Close(); - ticks = GetCpuTicks() - ticks; - printf("\nticks = %10d\n", (unsigned)ticks); - return S_FALSE; - */ - - /* - File.SetLength() on FAT (xp64): is fast, but then File.Close() can be slow, - if we don't write any data. - File.SetLength() for remote share file (exFAT) can be slow in some cases, - and the Windows can return "network error" after 1 minute, - while remote file still can grow. - We need some way to detect such bad cases and disable PreAllocateOutFile mode. - */ - - res = _outFileStreamSpec->SeekToBegin_bool(); - if (!res) - { - RINOK(SendMessageError_with_LastError("Cannot seek to begin of file", fullProcessedPath)) - } - } // PreAllocateOutFile - - #ifdef SUPPORT_ALT_STREAMS - if (_isRenamed && !_item.IsAltStream) - { - CIndexToPathPair pair(index, fullProcessedPath); - unsigned oldSize = _renamedFiles.Size(); - unsigned insertIndex = _renamedFiles.AddToUniqueSorted(pair); - if (oldSize == _renamedFiles.Size()) - _renamedFiles[insertIndex].Path = fullProcessedPath; - } - #endif // SUPPORT_ALT_STREAMS - - if (_isSplit) - { - RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) - } - outStreamLoc = outFileStream_Loc; - } // if not reprase - - _outFileStream = outFileStream_Loc; - - needExit = false; - return S_OK; -} - - - -HRESULT CArchiveExtractCallback::GetItem(UInt32 index) -{ - #ifndef Z7_SFX - _item._use_baseParentFolder_mode = _use_baseParentFolder_mode; - if (_use_baseParentFolder_mode) - { - _item._baseParentFolder = (int)_baseParentFolder; - if (_pathMode == NExtract::NPathMode::kFullPaths || - _pathMode == NExtract::NPathMode::kAbsPaths) - _item._baseParentFolder = -1; - } - #endif // Z7_SFX - - #ifdef SUPPORT_ALT_STREAMS - _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon; - #endif - - return _arc->GetItem(index, _item); -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)) -{ - COM_TRY_BEGIN - - *outStream = NULL; - - #ifndef Z7_SFX - if (_hashStream) - _hashStreamSpec->ReleaseStream(); - _hashStreamWasUsed = false; - #endif - - _outFileStream.Release(); - _bufPtrSeqOutStream.Release(); - - _encrypted = false; - _position = 0; - _isSplit = false; - - _curSize = 0; - _curSize_Defined = false; - _fileLength_WasSet = false; - _fileLength_that_WasSet = 0; - _index = index; - - _diskFilePath.Empty(); - - _isRenamed = false; - - // _fi.Clear(); - - // _is_SymLink_in_Data = false; - _is_SymLink_in_Data_Linux = false; - - _needSetAttrib = false; - _isSymLinkCreated = false; - _itemFailure = false; - - _some_pathParts_wereRemoved = false; - // _op_WasReported = false; - - #ifdef SUPPORT_LINKS - // _copyFile_Path.Empty(); - _link.Clear(); - #endif - - _extractMode = false; - - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: - if (_testMode) - { - // askExtractMode = NArchive::NExtract::NAskMode::kTest; - } - else - _extractMode = true; - break; - default: break; - } - - - IInArchive *archive = _arc->Archive; - - RINOK(GetItem(index)) - - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidPosition, &prop)) - if (prop.vt != VT_EMPTY) - { - if (prop.vt != VT_UI8) - return E_FAIL; - _position = prop.uhVal.QuadPart; - _isSplit = true; - } - } - - #ifdef SUPPORT_LINKS - RINOK(ReadLink()) - #endif // SUPPORT_LINKS - - - RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) - - RINOK(GetUnpackSize()) - - #ifdef SUPPORT_ALT_STREAMS - if (!_ntOptions.AltStreams.Val && _item.IsAltStream) - return S_OK; - #endif // SUPPORT_ALT_STREAMS - - // we can change (_item.PathParts) in this function - UStringVector &pathParts = _item.PathParts; - - if (_wildcardCensor) - { - if (!CensorNode_CheckPath(*_wildcardCensor, _item)) - return S_OK; - } - - #ifndef Z7_SFX - if (_use_baseParentFolder_mode) - { - if (!pathParts.IsEmpty()) - { - unsigned numRemovePathParts = 0; - - #ifdef SUPPORT_ALT_STREAMS - if (_pathMode == NExtract::NPathMode::kNoPathsAlt && _item.IsAltStream) - numRemovePathParts = pathParts.Size(); - else - #endif - if (_pathMode == NExtract::NPathMode::kNoPaths || - _pathMode == NExtract::NPathMode::kNoPathsAlt) - numRemovePathParts = pathParts.Size() - 1; - pathParts.DeleteFrontal(numRemovePathParts); - } - } - else - #endif // Z7_SFX - { - if (pathParts.IsEmpty()) - { - if (_item.IsDir) - return S_OK; - /* - #ifdef SUPPORT_ALT_STREAMS - if (!_item.IsAltStream) - #endif - return E_FAIL; - */ - } - - unsigned numRemovePathParts = 0; - - switch ((int)_pathMode) - { - case NExtract::NPathMode::kFullPaths: - case NExtract::NPathMode::kCurPaths: - { - if (_removePathParts.IsEmpty()) - break; - bool badPrefix = false; - - if (pathParts.Size() < _removePathParts.Size()) - badPrefix = true; - else - { - if (pathParts.Size() == _removePathParts.Size()) - { - if (_removePartsForAltStreams) - { - #ifdef SUPPORT_ALT_STREAMS - if (!_item.IsAltStream) - #endif - badPrefix = true; - } - else - { - if (!_item.MainIsDir) - badPrefix = true; - } - } - - if (!badPrefix) - FOR_VECTOR (i, _removePathParts) - { - if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) - { - badPrefix = true; - break; - } - } - } - - if (badPrefix) - { - if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) - return E_FAIL; - } - else - { - numRemovePathParts = _removePathParts.Size(); - _some_pathParts_wereRemoved = true; - } - break; - } - - case NExtract::NPathMode::kNoPaths: - { - if (!pathParts.IsEmpty()) - numRemovePathParts = pathParts.Size() - 1; - break; - } - case NExtract::NPathMode::kNoPathsAlt: - { - #ifdef SUPPORT_ALT_STREAMS - if (_item.IsAltStream) - numRemovePathParts = pathParts.Size(); - else - #endif - if (!pathParts.IsEmpty()) - numRemovePathParts = pathParts.Size() - 1; - break; - } - case NExtract::NPathMode::kAbsPaths: - default: - break; - } - - pathParts.DeleteFrontal(numRemovePathParts); - } - - - #ifndef Z7_SFX - - if (ExtractToStreamCallback) - { - if (!GetProp) - { - GetProp_Spec = new CGetProp; - GetProp = GetProp_Spec; - } - GetProp_Spec->Arc = _arc; - GetProp_Spec->IndexInArc = index; - UString name (MakePathFromParts(pathParts)); - - #ifdef SUPPORT_ALT_STREAMS - if (_item.IsAltStream) - { - if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt)) - name.Add_Colon(); - name += _item.AltStreamName; - } - #endif - - return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp); - } - - #endif // Z7_SFX - - - CMyComPtr outStreamLoc; - - if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) - { - if (_stdOutMode) - outStreamLoc = new CStdOutFileStream; - else - { - bool needExit = true; - RINOK(GetExtractStream(outStreamLoc, needExit)) - if (needExit) - return S_OK; - } - } - - #ifndef Z7_SFX - if (_hashStream) - { - if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || - askExtractMode == NArchive::NExtract::NAskMode::kTest) - { - _hashStreamSpec->SetStream(outStreamLoc); - outStreamLoc = _hashStream; - _hashStreamSpec->Init(true); - _hashStreamWasUsed = true; - } - } - #endif // Z7_SFX - - if (outStreamLoc) - { - /* - #ifdef SUPPORT_LINKS - if (!_copyFile_Path.IsEmpty()) - { - RINOK(PrepareOperation(askExtractMode)); - RINOK(MyCopyFile(outStreamLoc)); - return SetOperationResult(NArchive::NExtract::NOperationResult::kOK); - } - if (_link.isCopyLink && _testMode) - return S_OK; - #endif - */ - *outStream = outStreamLoc.Detach(); - } - - return S_OK; - - COM_TRY_END -} - - - - - - - - - - - -Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)) -{ - COM_TRY_BEGIN - - #ifndef Z7_SFX - // if (!_op_WasReported) - if (ExtractToStreamCallback) - return ExtractToStreamCallback->PrepareOperation7(askExtractMode); - #endif - - _extractMode = false; - - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: - if (_testMode) - askExtractMode = NArchive::NExtract::NAskMode::kTest; - else - _extractMode = true; - break; - default: break; - } - - // if (_op_WasReported) return S_OK; - - return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir), - askExtractMode, _isSplit ? &_position: NULL); - - COM_TRY_END -} - - - - - -HRESULT CArchiveExtractCallback::CloseFile() -{ - if (!_outFileStream) - return S_OK; - - HRESULT hres = S_OK; - - const UInt64 processedSize = _outFileStreamSpec->ProcessedSize; - if (_fileLength_WasSet && _fileLength_that_WasSet > processedSize) - { - const bool res = _outFileStreamSpec->File.SetLength(processedSize); - _fileLength_WasSet = res; - if (!res) - { - const HRESULT hres2 = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path)); - if (hres == S_OK) - hres = hres2; - } - } - - _curSize = processedSize; - _curSize_Defined = true; - - #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) - if (ZoneBuf.Size() != 0 - && !_item.IsAltStream) - { - // if (NFind::DoesFileExist_Raw(tempFilePath)) - if (ZoneMode != NExtract::NZoneIdMode::kOffice || - FindExt2(kOfficeExtensions, fs2us(_diskFilePath))) - { - // we must write zone file before setting of timestamps - if (!WriteZoneFile_To_BaseFile(_diskFilePath, ZoneBuf)) - { - // we can't write it in FAT - // SendMessageError_with_LastError("Can't write Zone.Identifier stream", path); - } - } - } - #endif - - CFiTimesCAM t; - GetFiTimesCAM(t); - - // #ifdef _WIN32 - if (t.IsSomeTimeDefined()) - _outFileStreamSpec->SetTime( - t.CTime_Defined ? &t.CTime : NULL, - t.ATime_Defined ? &t.ATime : NULL, - t.MTime_Defined ? &t.MTime : NULL); - // #endif - - RINOK(_outFileStreamSpec->Close()) - _outFileStream.Release(); - return hres; -} - - -#ifdef SUPPORT_LINKS - - -HRESULT CArchiveExtractCallback::SetFromLinkPath( - const FString &fullProcessedPath, - const CLinkInfo &linkInfo, - bool &linkWasSet) -{ - linkWasSet = false; - if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink) - return S_OK; - - UString relatPath; - - /* if (linkInfo.isRelative) - linkInfo.linkPath is final link path that must be stored to file link field - else - linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath. - */ - - if (linkInfo.isRelative) - relatPath = GetDirPrefixOf(_item.Path); - relatPath += linkInfo.linkPath; - - if (!IsSafePath(relatPath)) - { - return SendMessageError2( - 0, // errorCode - "Dangerous link path was ignored", - us2fs(_item.Path), - us2fs(linkInfo.linkPath)); // us2fs(relatPath) - } - - FString existPath; - if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative) - { - if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) - { - RINOK(SendMessageError("Incorrect path", us2fs(relatPath))) - } - } - else - { - existPath = us2fs(linkInfo.linkPath); - // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr()); - } - - if (existPath.IsEmpty()) - return SendMessageError("Empty link", fullProcessedPath); - - if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */) - { - // if (linkInfo.isHardLink) - { - if (!MyCreateHardLink(fullProcessedPath, existPath)) - { - const HRESULT errorCode = GetLastError_noZero_HRESULT(); - RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath)) - } - /* - RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) - _op_WasReported = true; - RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK)) - */ - linkWasSet = true; - return S_OK; - } - /* - // IsCopyLink - { - NFind::CFileInfo fi; - if (!fi.Find(existPath)) - { - RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath)); - } - else - { - if (_curSize_Defined && _curSize == fi.Size) - _copyFile_Path = existPath; - else - { - RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); - } - // RINOK(MyCopyFile(existPath, fullProcessedPath)); - } - } - */ - } - - // is Symbolic link - - /* - if (_item.IsDir && !isRelative) - { - // Windows before Vista doesn't support symbolic links. - // we could convert such symbolic links to Junction Points - // isJunction = true; - // convertToAbs = true; - } - */ - - if (!_ntOptions.SymLinks_AllowDangerous.Val) - { - #ifdef _WIN32 - if (_item.IsDir) - #endif - if (linkInfo.isRelative) - { - CLinkLevelsInfo levelsInfo; - levelsInfo.Parse(linkInfo.linkPath); - if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute) - { - return SendMessageError2( - 0, // errorCode - "Dangerous symbolic link path was ignored", - us2fs(_item.Path), - us2fs(linkInfo.linkPath)); - } - } - } - - - #ifdef _WIN32 - - CByteBuffer data; - // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr()); - if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL)) - return SendMessageError("Cannot fill link data", us2fs(_item.Path)); - - /* - if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) - { - SendMessageError("reconstructed Reparse is different", fs2us(existPath)); - } - */ - - CReparseAttr attr; - if (!attr.Parse(data, data.Size())) - { - RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))) - return S_OK; - } - if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) - { - RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) - return S_OK; - } - linkWasSet = true; - - return S_OK; - - - #else // ! _WIN32 - - if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath)) - { - RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) - return S_OK; - } - linkWasSet = true; - - return S_OK; - - #endif // ! _WIN32 -} - - -bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData) -{ - Clear(); - // this->isLinux = isLinuxData; - - if (isLinuxData) - { - isJunction = false; - isHardLink = false; - AString utf; - if (dataSize >= (1 << 12)) - return false; - utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize); - UString u; - if (!ConvertUTF8ToUnicode(utf, u)) - return false; - linkPath = u; - - // in linux symbolic data: we expect that linux separator '/' is used - // if windows link was created, then we also must use linux separator - if (u.IsEmpty()) - return false; - const wchar_t c = u[0]; - isRelative = !IS_PATH_SEPAR(c); - return true; - } - - CReparseAttr reparse; - if (!reparse.Parse(data, dataSize)) - return false; - isHardLink = false; - // isCopyLink = false; - linkPath = reparse.GetPath(); - isJunction = reparse.IsMountPoint(); - - if (reparse.IsSymLink_WSL()) - { - isWSL = true; - isRelative = reparse.IsRelative_WSL(); - } - else - isRelative = reparse.IsRelative_Win(); - - // FIXME !!! - #ifndef _WIN32 - linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); - #endif - - return true; -} - -#endif // SUPPORT_LINKS - - -HRESULT CArchiveExtractCallback::CloseReparseAndFile() -{ - HRESULT res = S_OK; - - #ifdef SUPPORT_LINKS - - size_t reparseSize = 0; - bool repraseMode = false; - bool needSetReparse = false; - CLinkInfo linkInfo; - - if (_bufPtrSeqOutStream) - { - repraseMode = true; - reparseSize = _bufPtrSeqOutStream_Spec->GetPos(); - if (_curSize_Defined && reparseSize == _outMemBuf.Size()) - { - /* - CReparseAttr reparse; - DWORD errorCode = 0; - needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); - if (needSetReparse) - { - UString linkPath = reparse.GetPath(); - #ifndef _WIN32 - linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); - #endif - } - */ - needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux); - if (!needSetReparse) - res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); - } - else - { - res = SendMessageError_with_LastError("Unknown reparse stream", us2fs(_item.Path)); - } - if (!needSetReparse && _outFileStream) - { - const HRESULT res2 = WriteStream(_outFileStream, _outMemBuf, reparseSize); - if (res == S_OK) - res = res2; - } - _bufPtrSeqOutStream.Release(); - } - - #endif // SUPPORT_LINKS - - - const HRESULT res2 = CloseFile(); - - if (res == S_OK) - res = res2; - - RINOK(res) - - #ifdef SUPPORT_LINKS - if (repraseMode) - { - _curSize = reparseSize; - _curSize_Defined = true; - - #ifdef SUPPORT_LINKS - if (needSetReparse) - { - // in Linux : we must delete empty file before symbolic link creation - // in Windows : we can create symbolic link even without file deleting - if (!DeleteFileAlways(_diskFilePath)) - { - RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) - } - { - /* - // for DEBUG ONLY: we can extract sym links as WSL links - // to eliminate (non-admin) errors for sym links. - #ifdef _WIN32 - if (!linkInfo.isHardLink && !linkInfo.isJunction) - linkInfo.isWSL = true; - #endif - */ - bool linkWasSet = false; - RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet)) - if (linkWasSet) - _isSymLinkCreated = linkInfo.IsSymLink(); - else - _needSetAttrib = false; - } - /* - if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, )) - { - res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath); - } - */ - } - #endif - } - #endif - return res; -} - - -void CArchiveExtractCallback::SetAttrib() -{ - #ifndef _WIN32 - // Linux now doesn't support permissions for symlinks - if (_isSymLinkCreated) - return; - #endif - - if (_itemFailure - || _diskFilePath.IsEmpty() - || _stdOutMode - || !_extractMode) - return; - - #ifndef _WIN32 - if (_fi.Owner.Id_Defined && - _fi.Group.Id_Defined) - { - if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0) - { - SendMessageError_with_LastError("Cannot set owner", _diskFilePath); - } - } - #endif - - if (_fi.Attrib_Defined) - { - // const AString s = GetAnsiString(_diskFilePath); - // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); - bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib); - if (!res) - { - // do we need error message here in Windows and in posix? - SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath); - } - } -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) -{ - COM_TRY_BEGIN - - // printf("\nCArchiveExtractCallback::SetOperationResult: %d %s\n", opRes, GetAnsiString(_diskFilePath)); - - #ifndef Z7_SFX - if (ExtractToStreamCallback) - { - GetUnpackSize(); - return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize); - } - #endif - - #ifndef Z7_SFX - - if (_hashStreamWasUsed) - { - _hashStreamSpec->_hash->Final(_item.IsDir, - #ifdef SUPPORT_ALT_STREAMS - _item.IsAltStream - #else - false - #endif - , _item.Path); - _curSize = _hashStreamSpec->GetSize(); - _curSize_Defined = true; - _hashStreamSpec->ReleaseStream(); - _hashStreamWasUsed = false; - } - - #endif // Z7_SFX - - RINOK(CloseReparseAndFile()) - - #ifdef Z7_USE_SECURITY_CODE - if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - if (CheckNtSecure((const Byte *)data, dataSize)) - { - SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; - if (_saclEnabled) - securInfo |= SACL_SECURITY_INFORMATION; - ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data)); - } - } - } - #endif // Z7_USE_SECURITY_CODE - - if (!_curSize_Defined) - GetUnpackSize(); - - if (_curSize_Defined) - { - #ifdef SUPPORT_ALT_STREAMS - if (_item.IsAltStream) - AltStreams_UnpackSize += _curSize; - else - #endif - UnpackSize += _curSize; - } - - if (_item.IsDir) - NumFolders++; - #ifdef SUPPORT_ALT_STREAMS - else if (_item.IsAltStream) - NumAltStreams++; - #endif - else - NumFiles++; - - if (_needSetAttrib) - SetAttrib(); - - RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted))) - - return S_OK; - - COM_TRY_END -} - - - -Z7_COM7F_IMF(CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) -{ - if (_folderArchiveExtractCallback2) - { - bool isEncrypted = false; - UString s; - - if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1) - { - CReadArcItem item; - RINOK(_arc->GetItem(index, item)) - s = item.Path; - RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted)) - } - else - { - s = '#'; - s.Add_UInt32(index); - // if (indexType == NArchive::NEventIndexType::kBlockIndex) {} - } - - return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s); - } - - return S_OK; -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)) -{ - COM_TRY_BEGIN - if (!_cryptoGetTextPassword) - { - RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, - &_cryptoGetTextPassword)) - } - return _cryptoGetTextPassword->CryptoGetTextPassword(password); - COM_TRY_END -} - - -#ifndef Z7_SFX - -// ---------- HASH functions ---------- - -FString CArchiveExtractCallback::Hash_GetFullFilePath() -{ - // this function changes _item.PathParts. - CorrectPathParts(); - const UStringVector &pathParts = _item.PathParts; - const UString processedPath (MakePathFromParts(pathParts)); - FString fullProcessedPath (us2fs(processedPath)); - if (_pathMode != NExtract::NPathMode::kAbsPaths - || !NName::IsAbsolutePath(processedPath)) - { - fullProcessedPath = MakePath_from_2_Parts( - DirPathPrefix_for_HashFiles, - // _dirPathPrefix, - fullProcessedPath); - } - return fullProcessedPath; -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (propID == kpidSize) - { - RINOK(GetItem(index)) - const FString fullProcessedPath = Hash_GetFullFilePath(); - NFile::NFind::CFileInfo fi; - if (fi.Find_FollowLink(fullProcessedPath)) - if (!fi.IsDir()) - prop = (UInt64)fi.Size; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)) -{ - COM_TRY_BEGIN - *inStream = NULL; - // if (index != _index) return E_FAIL; - if (mode != NUpdateNotifyOp::kHashRead) - return E_FAIL; - - RINOK(GetItem(index)) - const FString fullProcessedPath = Hash_GetFullFilePath(); - - CInFileStream *inStreamSpec = new CInFileStream; - CMyComPtr inStreamRef = inStreamSpec; - inStreamSpec->Set_PreserveATime(_ntOptions.PreserveATime); - if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite)) - { - RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath)) - return S_OK; - } - *inStream = inStreamRef.Detach(); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::ReportOperation( - UInt32 /* indexType */, UInt32 /* index */, UInt32 /* op */)) -{ - // COM_TRY_BEGIN - return S_OK; - // COM_TRY_END -} - - -Z7_COM7F_IMF(CArchiveExtractCallback::RequestMemoryUse( - UInt32 flags, UInt32 indexType, UInt32 index, const wchar_t *path, - UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) -{ - if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) - { - const UInt64 memLimit = _ntOptions.MemLimit; - if (memLimit != (UInt64)(Int64)-1) - { - // we overwrite allowedSize - *allowedSize = memLimit; - if (requiredSize <= memLimit) - { - *answerFlags = NRequestMemoryAnswerFlags::k_Allow; - return S_OK; - } - *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded; - if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) - *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc; - flags |= NRequestMemoryUseFlags::k_SLimit_Exceeded - | NRequestMemoryUseFlags::k_AllowedSize_WasForced; - } - } - - if (!_requestMemoryUseCallback) - { - _extractCallback2.QueryInterface(IID_IArchiveRequestMemoryUseCallback, - &_requestMemoryUseCallback); - if (!_requestMemoryUseCallback) - { - // keep default (answerFlags) from caller or (answerFlags) that was set in this function - return S_OK; - } - } - -#if 0 - if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) - if (requiredSize <= *allowedSize) - { - // it's expected, that *answerFlags was set to NRequestMemoryAnswerFlags::k_Allow already, - // because it's default answer for (requiredSize <= *allowedSize) case. - *answerFlags = NRequestMemoryAnswerFlags::k_Allow; // optional code - } - else - { - // we clear *answerFlags, because we want to disable dafault "Allow", if it's set. - // *answerFlags = 0; - /* - NRequestMemoryAnswerFlags::k_SkipArc | - NRequestMemoryAnswerFlags::k_Limit_Exceeded; - */ - } -#endif - - UString s; - if (!path - && indexType == NArchive::NEventIndexType::kInArcIndex - && index != (UInt32)(Int32)-1 - && _arc) - { - RINOK(_arc->GetItem_Path(index, s)) - path = s.Ptr(); - } - - return _requestMemoryUseCallback->RequestMemoryUse( - flags, indexType, index, path, - requiredSize, allowedSize, answerFlags); -} - -#endif // Z7_SFX - - - -// ------------ After Extracting functions ------------ - -void CDirPathSortPair::SetNumSlashes(const FChar *s) -{ - for (unsigned numSlashes = 0;;) - { - FChar c = *s++; - if (c == 0) - { - Len = numSlashes; - return; - } - if (IS_PATH_SEPAR(c)) - numSlashes++; - } -} - - -bool CDirPathTime::SetDirTime() const -{ - return NDir::SetDirTime(Path, - CTime_Defined ? &CTime : NULL, - ATime_Defined ? &ATime : NULL, - MTime_Defined ? &MTime : NULL); -} - - -HRESULT CArchiveExtractCallback::SetDirsTimes() -{ - if (!_arc) - return S_OK; - - CRecordVector pairs; - pairs.ClearAndSetSize(_extractedFolders.Size()); - unsigned i; - - for (i = 0; i < _extractedFolders.Size(); i++) - { - CDirPathSortPair &pair = pairs[i]; - pair.Index = i; - pair.SetNumSlashes(_extractedFolders[i].Path); - } - - pairs.Sort2(); - - HRESULT res = S_OK; - - for (i = 0; i < pairs.Size(); i++) - { - const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; - if (!dpt.SetDirTime()) - { - // result = E_FAIL; - // do we need error message here in Windows and in posix? - // SendMessageError_with_LastError("Cannot set directory time", dpt.Path); - } - } - - /* - #ifndef _WIN32 - for (i = 0; i < _delayedSymLinks.Size(); i++) - { - const CDelayedSymLink &link = _delayedSymLinks[i]; - if (!link.Create()) - { - if (res == S_OK) - res = GetLastError_noZero_HRESULT(); - // res = E_FAIL; - // do we need error message here in Windows and in posix? - SendMessageError_with_LastError("Cannot create Symbolic Link", link._source); - } - } - #endif // _WIN32 - */ - - ClearExtractedDirsInfo(); - return res; -} - - -HRESULT CArchiveExtractCallback::CloseArc() -{ - HRESULT res = CloseReparseAndFile(); - const HRESULT res2 = SetDirsTimes(); - if (res == S_OK) - res = res2; - _arc = NULL; - return res; -} +// ArchiveExtractCallback.cpp + +#include "StdAfx.h" + +#undef sprintf +#undef printf + +// #include +// #include "../../../../C/CpuTicks.h" + +#include "../../../../C/Alloc.h" +#include "../../../../C/CpuArch.h" + + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) +#define Z7_USE_SECURITY_CODE +#include "../../../Windows/SecurityUtils.h" +#endif + +#include "../../Common/FilePathAutoRename.h" +#include "../../Common/StreamUtils.h" + +#include "../Common/ExtractingFilePath.h" +#include "../Common/PropIDUtils.h" + +#include "ArchiveExtractCallback.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static const char * const kCantAutoRename = "Cannot create file with auto name"; +static const char * const kCantRenameFile = "Cannot rename existing file"; +static const char * const kCantDeleteOutputFile = "Cannot delete output file"; +static const char * const kCantDeleteOutputDir = "Cannot delete output folder"; +static const char * const kCantOpenOutFile = "Cannot open output file"; +#ifndef Z7_SFX +static const char * const kCantOpenInFile = "Cannot open input file"; +#endif +static const char * const kCantSetFileLen = "Cannot set length for output file"; +#ifdef SUPPORT_LINKS +static const char * const kCantCreateHardLink = "Cannot create hard link"; +static const char * const kCantCreateSymLink = "Cannot create symbolic link"; +#endif + +#ifndef Z7_SFX + +Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + HRESULT result = S_OK; + if (_stream) + result = _stream->Write(data, size, &size); + if (_calculate) + _hash->Update(data, size); + _size += size; + if (processedSize) + *processedSize = size; + return result; +} + +#endif // Z7_SFX + + +#ifdef Z7_USE_SECURITY_CODE +bool InitLocalPrivileges(); +bool InitLocalPrivileges() +{ + NSecurity::CAccessToken token; + if (!token.OpenProcessToken(GetCurrentProcess(), + TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)) + return false; + + TOKEN_PRIVILEGES tp; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) + return false; + if (!token.AdjustPrivileges(&tp)) + return false; + return (GetLastError() == ERROR_SUCCESS); +} +#endif // Z7_USE_SECURITY_CODE + + + +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + +static const char * const kOfficeExtensions = + " doc dot wbk" + " docx docm dotx dotm docb wll wwl" + " xls xlt xlm" + " xlsx xlsm xltx xltm xlsb xla xlam" + " ppt pot pps ppa ppam" + " pptx pptm potx potm ppam ppsx ppsm sldx sldm" + " "; + +static bool FindExt2(const char *p, const UString &name) +{ + const int pathPos = name.ReverseFind_PathSepar(); + const int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0 + || dotPos < pathPos + || dotPos == (int)name.Len() - 1) + return false; + + AString s; + for (unsigned pos = (unsigned)(dotPos + 1);; pos++) + { + const wchar_t c = name[pos]; + if (c <= 0) + break; + if (c >= 0x80) + return false; + s.Add_Char((char)MyCharLower_Ascii((char)c)); + } + for (unsigned i = 0; p[i] != 0;) + { + unsigned j; + for (j = i; p[j] != ' '; j++); + if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0) + return true; + i = j + 1; + } + return false; +} + + +static const char * const k_ZoneId_StreamName_With_Colon_Prefix = ":Zone.Identifier"; + +bool Is_ZoneId_StreamName(const wchar_t *s) +{ + return StringsAreEqualNoCase_Ascii(s, k_ZoneId_StreamName_With_Colon_Prefix + 1); +} + +void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf) +{ + buf.Free(); + FString path (fileName); + path += k_ZoneId_StreamName_With_Colon_Prefix; + NIO::CInFile file; + if (!file.Open(path)) + return; + UInt64 fileSize; + if (!file.GetLength(fileSize)) + return; + if (fileSize == 0 || fileSize >= (1u << 15)) + return; + buf.Alloc((size_t)fileSize); + size_t processed; + if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize) + return; + buf.Free(); +} + +bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf) +{ + FString path (fileName); + path += k_ZoneId_StreamName_With_Colon_Prefix; + NIO::COutFile file; + if (!file.Create_ALWAYS(path)) + return false; + return file.WriteFull(buf, buf.Size()); +} + +#endif + + +#ifdef SUPPORT_LINKS + +int CHardLinkNode::Compare(const CHardLinkNode &a) const +{ + if (StreamId < a.StreamId) return -1; + if (StreamId > a.StreamId) return 1; + return MyCompare(INode, a.INode); +} + +static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined) +{ + h.INode = 0; + h.StreamId = (UInt64)(Int64)-1; + defined = false; + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidINode, &prop)) + if (!ConvertPropVariantToUInt64(prop, h.INode)) + return S_OK; + } + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidStreamId, &prop)) + ConvertPropVariantToUInt64(prop, h.StreamId); + } + defined = true; + return S_OK; +} + + +HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector *realIndices) +{ + _hardLinks.Clear(); + + if (!_arc->Ask_INode) + return S_OK; + + IInArchive *archive = _arc->Archive; + CRecordVector &hardIDs = _hardLinks.IDs; + + { + UInt32 numItems; + if (realIndices) + numItems = realIndices->Size(); + else + { + RINOK(archive->GetNumberOfItems(&numItems)) + } + + for (UInt32 i = 0; i < numItems; i++) + { + CHardLinkNode h; + bool defined; + const UInt32 realIndex = realIndices ? (*realIndices)[i] : i; + + RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined)) + if (defined) + { + bool isAltStream = false; + RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream)) + if (!isAltStream) + { + bool isDir = false; + RINOK(Archive_IsItem_Dir(archive, realIndex, isDir)) + if (!isDir) + hardIDs.Add(h); + } + } + } + } + + hardIDs.Sort2(); + + { + // we keep only items that have 2 or more items + unsigned k = 0; + unsigned numSame = 1; + for (unsigned i = 1; i < hardIDs.Size(); i++) + { + if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) + numSame = 1; + else if (++numSame == 2) + { + if (i - 1 != k) + hardIDs[k] = hardIDs[i - 1]; + k++; + } + } + hardIDs.DeleteFrom(k); + } + + _hardLinks.PrepareLinks(); + return S_OK; +} + +#endif // SUPPORT_LINKS + + +CArchiveExtractCallback::CArchiveExtractCallback(): + // Write_CTime(true), + // Write_ATime(true), + // Write_MTime(true), + Is_elimPrefix_Mode(false), + _arc(NULL), + _multiArchives(false) +{ + #ifdef Z7_USE_SECURITY_CODE + _saclEnabled = InitLocalPrivileges(); + #endif +} + + +void CArchiveExtractCallback::InitBeforeNewArchive() +{ +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + ZoneBuf.Free(); +#endif +} + +void CArchiveExtractCallback::Init( + const CExtractNtOptions &ntOptions, + const NWildcard::CCensorNode *wildcardCensor, + const CArc *arc, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, bool testMode, + const FString &directoryPath, + const UStringVector &removePathParts, bool removePartsForAltStreams, + UInt64 packSize) +{ + ClearExtractedDirsInfo(); + _outFileStream.Release(); + _bufPtrSeqOutStream.Release(); + + #ifdef SUPPORT_LINKS + _hardLinks.Clear(); + #endif + + #ifdef SUPPORT_ALT_STREAMS + _renamedFiles.Clear(); + #endif + + _ntOptions = ntOptions; + _wildcardCensor = wildcardCensor; + _stdOutMode = stdOutMode; + _testMode = testMode; + _packTotal = packSize; + _progressTotal = packSize; + // _progressTotal = 0; + // _progressTotal_Defined = false; + // _progressTotal_Defined = true; + _extractCallback2 = extractCallback2; + /* + _compressProgress.Release(); + _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); + _callbackMessage.Release(); + _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage); + */ + _folderArchiveExtractCallback2.Release(); + _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); + + #ifndef Z7_SFX + + ExtractToStreamCallback.Release(); + _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); + if (ExtractToStreamCallback) + { + Int32 useStreams = 0; + if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) + useStreams = 0; + if (useStreams == 0) + ExtractToStreamCallback.Release(); + } + + #endif + + LocalProgressSpec->Init(extractCallback2, true); + LocalProgressSpec->SendProgress = false; + + _removePathParts = removePathParts; + _removePartsForAltStreams = removePartsForAltStreams; + + #ifndef Z7_SFX + _baseParentFolder = (UInt32)(Int32)-1; + _use_baseParentFolder_mode = false; + #endif + + _arc = arc; + _dirPathPrefix = directoryPath; + _dirPathPrefix_Full = directoryPath; + #if defined(_WIN32) && !defined(UNDER_CE) + if (!NName::IsAltPathPrefix(_dirPathPrefix)) + #endif + { + NName::NormalizeDirPathPrefix(_dirPathPrefix); + NDir::MyGetFullPathName(directoryPath, _dirPathPrefix_Full); + NName::NormalizeDirPathPrefix(_dirPathPrefix_Full); + } +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size)) +{ + COM_TRY_BEGIN + _progressTotal = size; + // _progressTotal_Defined = true; + if (!_multiArchives && _extractCallback2) + return _extractCallback2->SetTotal(size); + return S_OK; + COM_TRY_END +} + + +static void NormalizeVals(UInt64 &v1, UInt64 &v2) +{ + const UInt64 kMax = (UInt64)1 << 31; + while (v1 > kMax) + { + v1 >>= 1; + v2 >>= 1; + } +} + + +static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) +{ + NormalizeVals(packTotal, unpTotal); + NormalizeVals(unpCur, unpTotal); + if (unpTotal == 0) + unpTotal = 1; + return unpCur * packTotal / unpTotal; +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)) +{ + COM_TRY_BEGIN + + if (!_extractCallback2) + return S_OK; + + UInt64 packCur; + if (_multiArchives) + { + packCur = LocalProgressSpec->InSize; + if (completeValue /* && _progressTotal_Defined */) + packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal); + completeValue = &packCur; + } + return _extractCallback2->SetCompleted(completeValue); + + COM_TRY_END +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + COM_TRY_BEGIN + return LocalProgressSpec.Interface()->SetRatioInfo(inSize, outSize); + COM_TRY_END +} + + +void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) +{ + // we use (_item.IsDir) in this function + + bool isAbsPath = false; + + if (!dirPathParts.IsEmpty()) + { + const UString &s = dirPathParts[0]; + if (s.IsEmpty()) + isAbsPath = true; + #if defined(_WIN32) && !defined(UNDER_CE) + else + { + if (NName::IsDrivePath2(s)) + isAbsPath = true; + } + #endif + } + + if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) + fullPath.Empty(); + else + fullPath = _dirPathPrefix; + + FOR_VECTOR (i, dirPathParts) + { + if (i != 0) + fullPath.Add_PathSepar(); + const UString &s = dirPathParts[i]; + fullPath += us2fs(s); + + const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir); + + if (fullPath.IsEmpty()) + { + if (isFinalDir) + _itemFailure = true; + continue; + } + + #if defined(_WIN32) && !defined(UNDER_CE) + if (_pathMode == NExtract::NPathMode::kAbsPaths) + if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s)) + { + if (isFinalDir) + { + // we don't want to call SetAttrib() for root drive path + _itemFailure = true; + } + continue; + } + #endif + + HRESULT hres = S_OK; + if (!CreateDir(fullPath)) + hres = GetLastError_noZero_HRESULT(); + if (isFinalDir) + { + if (!NFile::NFind::DoesDirExist(fullPath)) + { + _itemFailure = true; + SendMessageError_with_Error(hres, "Cannot create folder", fullPath); + } + } + } +} + + +HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, CArcTime &ft) +{ + ft.Clear(); + NCOM::CPropVariant prop; + RINOK(_arc->Archive->GetProperty(index, propID, &prop)) + if (prop.vt == VT_FILETIME) + ft.Set_From_Prop(prop); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + + +HRESULT CArchiveExtractCallback::GetUnpackSize() +{ + return _arc->GetItem_Size(_index, _curSize, _curSize_Defined); +} + +static void AddPathToMessage(UString &s, const FString &path) +{ + s += " : "; + s += fs2us(path); +} + +HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) +{ + UString s (message); + AddPathToMessage(s, path); + return _extractCallback2->MessageError(s); +} + + +HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) +{ + UString s (message); + if (errorCode != S_OK) + { + s += " : "; + s += NError::MyFormatMessage(errorCode); + } + AddPathToMessage(s, path); + return _extractCallback2->MessageError(s); +} + +HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) +{ + const HRESULT errorCode = GetLastError_noZero_HRESULT(); + return SendMessageError_with_Error(errorCode, message, path); +} + +HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) +{ + UString s (message); + if (errorCode != 0) + { + s += " : "; + s += NError::MyFormatMessage(errorCode); + } + AddPathToMessage(s, path1); + AddPathToMessage(s, path2); + return _extractCallback2->MessageError(s); +} + +#ifndef Z7_SFX + +Z7_CLASS_IMP_COM_1( + CGetProp + , IGetProp +) +public: + UInt32 IndexInArc; + const CArc *Arc; + // UString BaseName; // relative path +}; + +Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) +{ + /* + if (propID == kpidBaseName) + { + COM_TRY_BEGIN + NCOM::CPropVariant prop = BaseName; + prop.Detach(value); + return S_OK; + COM_TRY_END + } + */ + return Arc->Archive->GetProperty(IndexInArc, propID, value); +} + +#endif // Z7_SFX + + +#ifdef SUPPORT_LINKS + +static UString GetDirPrefixOf(const UString &src) +{ + UString s (src); + if (!s.IsEmpty()) + { + if (IsPathSepar(s.Back())) + s.DeleteBack(); + int pos = s.ReverseFind_PathSepar(); + s.DeleteFrom((unsigned)(pos + 1)); + } + return s; +} + +#endif // SUPPORT_LINKS + +struct CLinkLevelsInfo +{ + bool IsAbsolute; + int LowLevel; + int FinalLevel; + + void Parse(const UString &path); +}; + +void CLinkLevelsInfo::Parse(const UString &path) +{ + IsAbsolute = NName::IsAbsolutePath(path); + + LowLevel = 0; + FinalLevel = 0; + + UStringVector parts; + SplitPathToParts(path, parts); + int level = 0; + + FOR_VECTOR (i, parts) + { + const UString &s = parts[i]; + if (s.IsEmpty()) + { + if (i == 0) + IsAbsolute = true; + continue; + } + if (s == L".") + continue; + if (s == L"..") + { + level--; + if (LowLevel > level) + LowLevel = level; + } + else + level++; + } + + FinalLevel = level; +} + + +bool IsSafePath(const UString &path); +bool IsSafePath(const UString &path) +{ + CLinkLevelsInfo levelsInfo; + levelsInfo.Parse(path); + return !levelsInfo.IsAbsolute + && levelsInfo.LowLevel >= 0 + && levelsInfo.FinalLevel > 0; +} + + +bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); +bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) +{ + bool found = false; + + // CheckPathVect() doesn't check path to Parent nodes + if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include)) + { + if (!include) + return true; + + #ifdef SUPPORT_ALT_STREAMS + if (!item.IsAltStream) + return true; + #endif + + found = true; + } + + #ifdef SUPPORT_ALT_STREAMS + + if (!item.IsAltStream) + return false; + + UStringVector pathParts2 = item.PathParts; + if (pathParts2.IsEmpty()) + pathParts2.AddNew(); + UString &back = pathParts2.Back(); + back.Add_Colon(); + back += item.AltStreamName; + bool include2; + + if (node.CheckPathVect(pathParts2, + true, // isFile, + include2)) + { + include = include2; + return true; + } + + #endif // SUPPORT_ALT_STREAMS + + return found; +} + + +bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item) +{ + bool include; + if (CensorNode_CheckPath2(node, item, include)) + return include; + return false; +} + + +static FString MakePath_from_2_Parts(const FString &prefix, const FString &path) +{ + FString s (prefix); + #if defined(_WIN32) && !defined(UNDER_CE) + if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back())) + { + if (!NName::IsDriveRootPath_SuperAllowed(prefix)) + s.DeleteBack(); + } + #endif + s += path; + return s; +} + + + +#ifdef SUPPORT_LINKS + +/* +struct CTempMidBuffer +{ + void *Buf; + + CTempMidBuffer(size_t size): Buf(NULL) { Buf = ::MidAlloc(size); } + ~CTempMidBuffer() { ::MidFree(Buf); } +}; + +HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream) +{ + const size_t kBufSize = 1 << 16; + CTempMidBuffer buf(kBufSize); + if (!buf.Buf) + return E_OUTOFMEMORY; + + NIO::CInFile inFile; + NIO::COutFile outFile; + + if (!inFile.Open(_copyFile_Path)) + return SendMessageError_with_LastError("Open error", _copyFile_Path); + + for (;;) + { + UInt32 num; + + if (!inFile.Read(buf.Buf, kBufSize, num)) + return SendMessageError_with_LastError("Read error", _copyFile_Path); + + if (num == 0) + return S_OK; + + + RINOK(WriteStream(outStream, buf.Buf, num)); + } +} +*/ + + +HRESULT CArchiveExtractCallback::ReadLink() +{ + IInArchive *archive = _arc->Archive; + const UInt32 index = _index; + _link.Clear(); + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidHardLink, &prop)) + if (prop.vt == VT_BSTR) + { + _link.isHardLink = true; + // _link.isCopyLink = false; + _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive + _link.linkPath.SetFromBstr(prop.bstrVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + + /* + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); + if (prop.vt == VT_BSTR) + { + _link.isHardLink = false; + _link.isCopyLink = true; + _link.isRelative = false; // RAR5: copy links are from root folder of archive + _link.linkPath.SetFromBstr(prop.bstrVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + */ + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidSymLink, &prop)) + if (prop.vt == VT_BSTR) + { + _link.isHardLink = false; + // _link.isCopyLink = false; + _link.isRelative = true; // RAR5, TAR: symbolic links can be relative + _link.linkPath.SetFromBstr(prop.bstrVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + + NtReparse_Data = NULL; + NtReparse_Size = 0; + + if (_link.linkPath.IsEmpty() && _arc->GetRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + + _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); + + // if (dataSize == 1234567) // for debug: unpacking without reparse + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + + // 21.06: we need kpidNtReparse in linux for wim archives created in Windows + // #ifdef _WIN32 + + NtReparse_Data = data; + NtReparse_Size = dataSize; + + CReparseAttr reparse; + bool isOkReparse = reparse.Parse((const Byte *)data, dataSize); + if (isOkReparse) + { + _link.isHardLink = false; + // _link.isCopyLink = false; + _link.linkPath = reparse.GetPath(); + _link.isJunction = reparse.IsMountPoint(); + + if (reparse.IsSymLink_WSL()) + { + _link.isWSL = true; + _link.isRelative = reparse.IsRelative_WSL(); + } + else + _link.isRelative = reparse.IsRelative_Win(); + + // const AString s = GetAnsiString(_link.linkPath); + // printf("\n_link.linkPath: %s\n", s.Ptr()); + + #ifndef _WIN32 + _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); + #endif + } + // #endif + } + } + + if (_link.linkPath.IsEmpty()) + return S_OK; + + { + #ifdef _WIN32 + _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + + // rar5 uses "\??\" prefix for absolute links + if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR)) + { + _link.isRelative = false; + _link.linkPath.DeleteFrontal(4); + } + + for (;;) + // while (NName::IsAbsolutePath(linkPath)) + { + unsigned n = NName::GetRootPrefixSize(_link.linkPath); + if (n == 0) + break; + _link.isRelative = false; + _link.linkPath.DeleteFrontal(n); + } + } + + if (_link.linkPath.IsEmpty()) + return S_OK; + + if (!_link.isRelative && _removePathParts.Size() != 0) + { + UStringVector pathParts; + SplitPathToParts(_link.linkPath, pathParts); + bool badPrefix = false; + FOR_VECTOR (i, _removePathParts) + { + if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) + { + badPrefix = true; + break; + } + } + if (!badPrefix) + pathParts.DeleteFrontal(_removePathParts.Size()); + _link.linkPath = MakePathFromParts(pathParts); + } + + /* + if (!_link.linkPath.IsEmpty()) + { + printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr()); + } + */ + + return S_OK; +} + +#endif // SUPPORT_LINKS + + +#ifndef _WIN32 + +static HRESULT GetOwner(IInArchive *archive, + UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) +{ + { + NWindows::NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, pidId, &prop)) + if (prop.vt == VT_UI4) + { + res.Id_Defined = true; + res.Id = prop.ulVal; // for debug + // res.Id++; // for debug + // if (pidId == kpidGroupId) res.Id += 7; // for debug + // res.Id = 0; // for debug + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NWindows::NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, pidName, &prop)) + if (prop.vt == VT_BSTR) + { + const UString s = prop.bstrVal; + ConvertUnicodeToUTF8(s, res.Name); + } + else if (prop.vt == VT_UI4) + { + res.Id_Defined = true; + res.Id = prop.ulVal; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + +#endif + + +HRESULT CArchiveExtractCallback::Read_fi_Props() +{ + IInArchive *archive = _arc->Archive; + const UInt32 index = _index; + + _fi.Attrib_Defined = false; + + #ifndef _WIN32 + _fi.Owner.Clear(); + _fi.Group.Clear(); + #endif + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidPosixAttrib, &prop)) + if (prop.vt == VT_UI4) + { + _fi.SetFromPosixAttrib(prop.ulVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidAttrib, &prop)) + if (prop.vt == VT_UI4) + { + _fi.Attrib = prop.ulVal; + _fi.Attrib_Defined = true; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + + RINOK(GetTime(index, kpidCTime, _fi.CTime)) + RINOK(GetTime(index, kpidATime, _fi.ATime)) + RINOK(GetTime(index, kpidMTime, _fi.MTime)) + + #ifndef _WIN32 + if (_ntOptions.ExtractOwner) + { + // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath); + GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner); + GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group); + } + #endif + + return S_OK; +} + + + +void CArchiveExtractCallback::CorrectPathParts() +{ + UStringVector &pathParts = _item.PathParts; + + #ifdef SUPPORT_ALT_STREAMS + if (!_item.IsAltStream + || !pathParts.IsEmpty() + || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)) + #endif + Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, _keepAndReplaceEmptyDirPrefixes, pathParts, _item.MainIsDir); + + #ifdef SUPPORT_ALT_STREAMS + + if (_item.IsAltStream) + { + UString s (_item.AltStreamName); + Correct_AltStream_Name(s); + bool needColon = true; + + if (pathParts.IsEmpty()) + { + pathParts.AddNew(); + if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt) + needColon = false; + } + #ifdef _WIN32 + else if (_pathMode == NExtract::NPathMode::kAbsPaths && + NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size()) + pathParts.AddNew(); + #endif + + UString &name = pathParts.Back(); + if (needColon) + name.Add_Char((char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':')); + name += s; + } + + #endif // SUPPORT_ALT_STREAMS +} + + +void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) +{ + pt.CTime_Defined = false; + pt.ATime_Defined = false; + pt.MTime_Defined = false; + + // if (Write_MTime) + { + if (_fi.MTime.Def) + { + _fi.MTime.Write_To_FiTime(pt.MTime); + pt.MTime_Defined = true; + } + else if (_arc->MTime.Def) + { + _arc->MTime.Write_To_FiTime(pt.MTime); + pt.MTime_Defined = true; + } + } + + if (/* Write_CTime && */ _fi.CTime.Def) + { + _fi.CTime.Write_To_FiTime(pt.CTime); + pt.CTime_Defined = true; + } + + if (/* Write_ATime && */ _fi.ATime.Def) + { + _fi.ATime.Write_To_FiTime(pt.ATime); + pt.ATime_Defined = true; + } +} + + +void CArchiveExtractCallback::CreateFolders() +{ + // 21.04 : we don't change original (_item.PathParts) here + UStringVector pathParts = _item.PathParts; + + // bool is_DirOp = false; + if (!pathParts.IsEmpty()) + { + /* v23: if we extract symlink, and we know that it links to dir: + Linux: we don't create dir item (symlink_from_path) here. + Windows: SetReparseData() will create dir item, if it doesn't exist, + but if we create dir item here, it's not problem. */ + if (!_item.IsDir + #ifdef SUPPORT_LINKS + #ifndef WIN32 + || !_link.linkPath.IsEmpty() + #endif + #endif + ) + pathParts.DeleteBack(); + // else is_DirOp = true; + } + + if (pathParts.IsEmpty()) + { + /* if (_some_pathParts_wereRemoved && Is_elimPrefix_Mode), + then we can have empty pathParts() here for root folder. + v24.00: fixed: we set timestamps for such folder still. + */ + if (!_some_pathParts_wereRemoved || + !Is_elimPrefix_Mode) + return; + // return; // ignore empty paths case + } + /* + if (is_DirOp) + { + RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) + _op_WasReported = true; + } + */ + + FString fullPathNew; + CreateComplexDirectory(pathParts, fullPathNew); + + /* + if (is_DirOp) + { + RINOK(SetOperationResult( + // _itemFailure ? NArchive::NExtract::NOperationResult::kDataError : + NArchive::NExtract::NOperationResult::kOK + )) + } + */ + + if (!_item.IsDir) + return; + if (fullPathNew.IsEmpty()) + return; + + if (_itemFailure) + return; + + CDirPathTime pt; + GetFiTimesCAM(pt); + + if (pt.IsSomeTimeDefined()) + { + pt.Path = fullPathNew; + pt.SetDirTime(); + _extractedFolders.Add(pt); + } +} + + + +/* + CheckExistFile(fullProcessedPath) + it can change: fullProcessedPath, _isRenamed, _overwriteMode + (needExit = true) means that we must exit GetStream() even for S_OK result. +*/ + +HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool &needExit) +{ + needExit = true; // it was set already before + + NFind::CFileInfo fileInfo; + + if (fileInfo.Find(fullProcessedPath)) + { + if (_overwriteMode == NExtract::NOverwriteMode::kSkip) + return S_OK; + + if (_overwriteMode == NExtract::NOverwriteMode::kAsk) + { + const int slashPos = fullProcessedPath.ReverseFind_PathSepar(); + const FString realFullProcessedPath = fullProcessedPath.Left((unsigned)(slashPos + 1)) + fileInfo.Name; + + /* (fileInfo) can be symbolic link. + we can show final file properties here. */ + + FILETIME ft1; + FiTime_To_FILETIME(fileInfo.MTime, ft1); + + Int32 overwriteResult; + RINOK(_extractCallback2->AskOverwrite( + fs2us(realFullProcessedPath), &ft1, &fileInfo.Size, _item.Path, + _fi.MTime.Def ? &_fi.MTime.FT : NULL, + _curSize_Defined ? &_curSize : NULL, + &overwriteResult)) + + switch (overwriteResult) + { + case NOverwriteAnswer::kCancel: + return E_ABORT; + case NOverwriteAnswer::kNo: + return S_OK; + case NOverwriteAnswer::kNoToAll: + _overwriteMode = NExtract::NOverwriteMode::kSkip; + return S_OK; + + case NOverwriteAnswer::kYes: + break; + case NOverwriteAnswer::kYesToAll: + _overwriteMode = NExtract::NOverwriteMode::kOverwrite; + break; + case NOverwriteAnswer::kAutoRename: + _overwriteMode = NExtract::NOverwriteMode::kRename; + break; + default: + return E_FAIL; + } + } // NExtract::NOverwriteMode::kAsk + + if (_overwriteMode == NExtract::NOverwriteMode::kRename) + { + if (!AutoRenamePath(fullProcessedPath)) + { + RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)) + return E_FAIL; + } + _isRenamed = true; + } + else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting) + { + FString existPath (fullProcessedPath); + if (!AutoRenamePath(existPath)) + { + RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)) + return E_FAIL; + } + // MyMoveFile can rename folders. So it's OK to use it for folders too + if (!MyMoveFile(fullProcessedPath, existPath)) + { + HRESULT errorCode = GetLastError_noZero_HRESULT(); + RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath)) + return E_FAIL; + } + } + else // not Rename* + { + if (fileInfo.IsDir()) + { + // do we need to delete all files in folder? + if (!RemoveDir(fullProcessedPath)) + { + RINOK(SendMessageError_with_LastError(kCantDeleteOutputDir, fullProcessedPath)) + return S_OK; + } + } + else // fileInfo is not Dir + { + if (NFind::DoesFileExist_Raw(fullProcessedPath)) + if (!DeleteFileAlways(fullProcessedPath)) + if (GetLastError() != ERROR_FILE_NOT_FOUND) // check it in linux + { + RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath)) + return S_OK; + // return E_FAIL; + } + } // fileInfo is not Dir + } // not Rename* + } + else // not Find(fullProcessedPath) + { + #if defined(_WIN32) && !defined(UNDER_CE) + // we need to clear READ-ONLY of parent before creating alt stream + const int colonPos = NName::FindAltStreamColon(fullProcessedPath); + if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0) + { + FString parentFsPath (fullProcessedPath); + parentFsPath.DeleteFrom((unsigned)colonPos); + NFind::CFileInfo parentFi; + if (parentFi.Find(parentFsPath)) + { + if (parentFi.IsReadOnly()) + { + _altStream_NeedRestore_Attrib_for_parentFsPath = parentFsPath; + _altStream_NeedRestore_AttribVal = parentFi.Attrib; + SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY); + } + } + } + #endif // defined(_WIN32) && !defined(UNDER_CE) + } + + needExit = false; + return S_OK; +} + + + + + + +HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr &outStreamLoc, bool &needExit) +{ + needExit = true; + + RINOK(Read_fi_Props()) + + #ifdef SUPPORT_LINKS + IInArchive *archive = _arc->Archive; + #endif + + const UInt32 index = _index; + + bool isAnti = false; + RINOK(_arc->IsItem_Anti(index, isAnti)) + + CorrectPathParts(); + UString processedPath (MakePathFromParts(_item.PathParts)); + + if (!isAnti) + { + // 21.04: CreateFolders doesn't change (_item.PathParts) + CreateFolders(); + } + + FString fullProcessedPath (us2fs(processedPath)); + if (_pathMode != NExtract::NPathMode::kAbsPaths + || !NName::IsAbsolutePath(processedPath)) + { + fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath); + } + + #ifdef SUPPORT_ALT_STREAMS + if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1) + { + const int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex)); + if (renIndex != -1) + { + const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex]; + fullProcessedPath = pair.Path; + fullProcessedPath.Add_Colon(); + UString s (_item.AltStreamName); + Correct_AltStream_Name(s); + fullProcessedPath += us2fs(s); + } + } + #endif // SUPPORT_ALT_STREAMS + + if (_item.IsDir) + { + _diskFilePath = fullProcessedPath; + if (isAnti) + RemoveDir(_diskFilePath); + #ifdef SUPPORT_LINKS + if (_link.linkPath.IsEmpty()) + #endif + { + if (!isAnti) + SetAttrib(); + return S_OK; + } + } + else if (!_isSplit) + { + RINOK(CheckExistFile(fullProcessedPath, needExit)) + if (needExit) + return S_OK; + needExit = true; + } + + _diskFilePath = fullProcessedPath; + + + if (isAnti) + { + needExit = false; + return S_OK; + } + + // not anti + + #ifdef SUPPORT_LINKS + + if (!_link.linkPath.IsEmpty()) + { + #ifndef UNDER_CE + { + bool linkWasSet = false; + RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet)) + if (linkWasSet) + { + _isSymLinkCreated = _link.IsSymLink(); + SetAttrib(); + // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); + } + } + #endif // UNDER_CE + + // if (_copyFile_Path.IsEmpty()) + { + needExit = false; + return S_OK; + } + } + + if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream && !_item.IsDir) + { + CHardLinkNode h; + bool defined; + RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)) + if (defined) + { + const int linkIndex = _hardLinks.IDs.FindInSorted2(h); + if (linkIndex != -1) + { + FString &hl = _hardLinks.Links[(unsigned)linkIndex]; + if (hl.IsEmpty()) + hl = fullProcessedPath; + else + { + if (!MyCreateHardLink(fullProcessedPath, hl)) + { + const HRESULT errorCode = GetLastError_noZero_HRESULT(); + RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl)) + return S_OK; + } + + // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); + // _needSetAttrib = true; // do we need to set attribute ? + SetAttrib(); + needExit = false; + return S_OK; + } + } + } + } + + #endif // SUPPORT_LINKS + + + // ---------- CREATE WRITE FILE ----- + + _outFileStreamSpec = new COutFileStream; + CMyComPtr outFileStream_Loc(_outFileStreamSpec); + + if (!_outFileStreamSpec->Create_ALWAYS_or_Open_ALWAYS(fullProcessedPath, !_isSplit)) + { + // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) + { + RINOK(SendMessageError_with_LastError(kCantOpenOutFile, fullProcessedPath)) + return S_OK; + } + } + + _needSetAttrib = true; + + bool is_SymLink_in_Data = false; + + if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12)) + { + if (_fi.IsLinuxSymLink()) + { + is_SymLink_in_Data = true; + _is_SymLink_in_Data_Linux = true; + } + else if (_fi.IsReparse()) + { + is_SymLink_in_Data = true; + _is_SymLink_in_Data_Linux = false; + } + } + + if (is_SymLink_in_Data) + { + _outMemBuf.Alloc((size_t)_curSize); + _bufPtrSeqOutStream_Spec = new CBufPtrSeqOutStream; + _bufPtrSeqOutStream = _bufPtrSeqOutStream_Spec; + _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); + outStreamLoc = _bufPtrSeqOutStream; + } + else // not reprase + { + if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) + { + // UInt64 ticks = GetCpuTicks(); + _fileLength_that_WasSet = _curSize; + bool res = _outFileStreamSpec->File.SetLength(_curSize); + _fileLength_WasSet = res; + + // ticks = GetCpuTicks() - ticks; + // printf("\nticks = %10d\n", (unsigned)ticks); + if (!res) + { + RINOK(SendMessageError_with_LastError(kCantSetFileLen, fullProcessedPath)) + } + + /* + _outFileStreamSpec->File.Close(); + ticks = GetCpuTicks() - ticks; + printf("\nticks = %10d\n", (unsigned)ticks); + return S_FALSE; + */ + + /* + File.SetLength() on FAT (xp64): is fast, but then File.Close() can be slow, + if we don't write any data. + File.SetLength() for remote share file (exFAT) can be slow in some cases, + and the Windows can return "network error" after 1 minute, + while remote file still can grow. + We need some way to detect such bad cases and disable PreAllocateOutFile mode. + */ + + res = _outFileStreamSpec->SeekToBegin_bool(); + if (!res) + { + RINOK(SendMessageError_with_LastError("Cannot seek to begin of file", fullProcessedPath)) + } + } // PreAllocateOutFile + + #ifdef SUPPORT_ALT_STREAMS + if (_isRenamed && !_item.IsAltStream) + { + CIndexToPathPair pair(index, fullProcessedPath); + unsigned oldSize = _renamedFiles.Size(); + unsigned insertIndex = _renamedFiles.AddToUniqueSorted(pair); + if (oldSize == _renamedFiles.Size()) + _renamedFiles[insertIndex].Path = fullProcessedPath; + } + #endif // SUPPORT_ALT_STREAMS + + if (_isSplit) + { + RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) + } + outStreamLoc = outFileStream_Loc; + } // if not reprase + + _outFileStream = outFileStream_Loc; + + needExit = false; + return S_OK; +} + + + +HRESULT CArchiveExtractCallback::GetItem(UInt32 index) +{ + #ifndef Z7_SFX + _item._use_baseParentFolder_mode = _use_baseParentFolder_mode; + if (_use_baseParentFolder_mode) + { + _item._baseParentFolder = (int)_baseParentFolder; + if (_pathMode == NExtract::NPathMode::kFullPaths || + _pathMode == NExtract::NPathMode::kAbsPaths) + _item._baseParentFolder = -1; + } + #endif // Z7_SFX + + #ifdef SUPPORT_ALT_STREAMS + _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon; + #endif + + return _arc->GetItem(index, _item); +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)) +{ + COM_TRY_BEGIN + + *outStream = NULL; + + #ifndef Z7_SFX + if (_hashStream) + _hashStreamSpec->ReleaseStream(); + _hashStreamWasUsed = false; + #endif + + _outFileStream.Release(); + _bufPtrSeqOutStream.Release(); + + _encrypted = false; + _isSplit = false; + _curSize_Defined = false; + _fileLength_WasSet = false; + _isRenamed = false; + // _fi.Clear(); + _extractMode = false; + // _is_SymLink_in_Data = false; + _is_SymLink_in_Data_Linux = false; + _needSetAttrib = false; + _isSymLinkCreated = false; + _itemFailure = false; + _some_pathParts_wereRemoved = false; + // _op_WasReported = false; + + _position = 0; + _curSize = 0; + _fileLength_that_WasSet = 0; + _index = index; + +#if defined(_WIN32) && !defined(UNDER_CE) + _altStream_NeedRestore_AttribVal = 0; + _altStream_NeedRestore_Attrib_for_parentFsPath.Empty(); +#endif + + _diskFilePath.Empty(); + + #ifdef SUPPORT_LINKS + // _copyFile_Path.Empty(); + _link.Clear(); + #endif + + + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: + if (_testMode) + { + // askExtractMode = NArchive::NExtract::NAskMode::kTest; + } + else + _extractMode = true; + break; + default: break; + } + + + IInArchive *archive = _arc->Archive; + + RINOK(GetItem(index)) + + { + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidPosition, &prop)) + if (prop.vt != VT_EMPTY) + { + if (prop.vt != VT_UI8) + return E_FAIL; + _position = prop.uhVal.QuadPart; + _isSplit = true; + } + } + + #ifdef SUPPORT_LINKS + RINOK(ReadLink()) + #endif // SUPPORT_LINKS + + + RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) + + RINOK(GetUnpackSize()) + + #ifdef SUPPORT_ALT_STREAMS + if (!_ntOptions.AltStreams.Val && _item.IsAltStream) + return S_OK; + #endif // SUPPORT_ALT_STREAMS + + // we can change (_item.PathParts) in this function + UStringVector &pathParts = _item.PathParts; + + if (_wildcardCensor) + { + if (!CensorNode_CheckPath(*_wildcardCensor, _item)) + return S_OK; + } + +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract + && !_testMode + && _item.IsAltStream + && ZoneBuf.Size() != 0 + && Is_ZoneId_StreamName(_item.AltStreamName)) + if (ZoneMode != NExtract::NZoneIdMode::kOffice + || _item.PathParts.IsEmpty() + || FindExt2(kOfficeExtensions, _item.PathParts.Back())) + return S_OK; +#endif + + + #ifndef Z7_SFX + if (_use_baseParentFolder_mode) + { + if (!pathParts.IsEmpty()) + { + unsigned numRemovePathParts = 0; + + #ifdef SUPPORT_ALT_STREAMS + if (_pathMode == NExtract::NPathMode::kNoPathsAlt && _item.IsAltStream) + numRemovePathParts = pathParts.Size(); + else + #endif + if (_pathMode == NExtract::NPathMode::kNoPaths || + _pathMode == NExtract::NPathMode::kNoPathsAlt) + numRemovePathParts = pathParts.Size() - 1; + pathParts.DeleteFrontal(numRemovePathParts); + } + } + else + #endif // Z7_SFX + { + if (pathParts.IsEmpty()) + { + if (_item.IsDir) + return S_OK; + /* + #ifdef SUPPORT_ALT_STREAMS + if (!_item.IsAltStream) + #endif + return E_FAIL; + */ + } + + unsigned numRemovePathParts = 0; + + switch ((int)_pathMode) + { + case NExtract::NPathMode::kFullPaths: + case NExtract::NPathMode::kCurPaths: + { + if (_removePathParts.IsEmpty()) + break; + bool badPrefix = false; + + if (pathParts.Size() < _removePathParts.Size()) + badPrefix = true; + else + { + if (pathParts.Size() == _removePathParts.Size()) + { + if (_removePartsForAltStreams) + { + #ifdef SUPPORT_ALT_STREAMS + if (!_item.IsAltStream) + #endif + badPrefix = true; + } + else + { + if (!_item.MainIsDir) + badPrefix = true; + } + } + + if (!badPrefix) + FOR_VECTOR (i, _removePathParts) + { + if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) + { + badPrefix = true; + break; + } + } + } + + if (badPrefix) + { + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) + return E_FAIL; + } + else + { + numRemovePathParts = _removePathParts.Size(); + _some_pathParts_wereRemoved = true; + } + break; + } + + case NExtract::NPathMode::kNoPaths: + { + if (!pathParts.IsEmpty()) + numRemovePathParts = pathParts.Size() - 1; + break; + } + case NExtract::NPathMode::kNoPathsAlt: + { + #ifdef SUPPORT_ALT_STREAMS + if (_item.IsAltStream) + numRemovePathParts = pathParts.Size(); + else + #endif + if (!pathParts.IsEmpty()) + numRemovePathParts = pathParts.Size() - 1; + break; + } + case NExtract::NPathMode::kAbsPaths: + default: + break; + } + + pathParts.DeleteFrontal(numRemovePathParts); + } + + + #ifndef Z7_SFX + + if (ExtractToStreamCallback) + { + CMyComPtr2_Create GetProp; + GetProp->Arc = _arc; + GetProp->IndexInArc = index; + UString name (MakePathFromParts(pathParts)); + // GetProp->BaseName = name; + #ifdef SUPPORT_ALT_STREAMS + if (_item.IsAltStream) + { + if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt)) + name.Add_Colon(); + name += _item.AltStreamName; + } + #endif + + return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp); + } + + #endif // Z7_SFX + + + CMyComPtr outStreamLoc; + + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) + { + if (_stdOutMode) + outStreamLoc = new CStdOutFileStream; + else + { + bool needExit = true; + RINOK(GetExtractStream(outStreamLoc, needExit)) + if (needExit) + return S_OK; + } + } + + #ifndef Z7_SFX + if (_hashStream) + { + if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || + askExtractMode == NArchive::NExtract::NAskMode::kTest) + { + _hashStreamSpec->SetStream(outStreamLoc); + outStreamLoc = _hashStream; + _hashStreamSpec->Init(true); + _hashStreamWasUsed = true; + } + } + #endif // Z7_SFX + + if (outStreamLoc) + { + /* + #ifdef SUPPORT_LINKS + if (!_copyFile_Path.IsEmpty()) + { + RINOK(PrepareOperation(askExtractMode)); + RINOK(MyCopyFile(outStreamLoc)); + return SetOperationResult(NArchive::NExtract::NOperationResult::kOK); + } + if (_link.isCopyLink && _testMode) + return S_OK; + #endif + */ + *outStream = outStreamLoc.Detach(); + } + + return S_OK; + + COM_TRY_END +} + + + + + + + + + + + +Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)) +{ + COM_TRY_BEGIN + + #ifndef Z7_SFX + // if (!_op_WasReported) + if (ExtractToStreamCallback) + return ExtractToStreamCallback->PrepareOperation7(askExtractMode); + #endif + + _extractMode = false; + + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: + if (_testMode) + askExtractMode = NArchive::NExtract::NAskMode::kTest; + else + _extractMode = true; + break; + default: break; + } + + // if (_op_WasReported) return S_OK; + + return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir), + askExtractMode, _isSplit ? &_position: NULL); + + COM_TRY_END +} + + + + + +HRESULT CArchiveExtractCallback::CloseFile() +{ + if (!_outFileStream) + return S_OK; + + HRESULT hres = S_OK; + + const UInt64 processedSize = _outFileStreamSpec->ProcessedSize; + if (_fileLength_WasSet && _fileLength_that_WasSet > processedSize) + { + const bool res = _outFileStreamSpec->File.SetLength(processedSize); + _fileLength_WasSet = res; + if (!res) + { + const HRESULT hres2 = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path)); + if (hres == S_OK) + hres = hres2; + } + } + + _curSize = processedSize; + _curSize_Defined = true; + + #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + if (ZoneBuf.Size() != 0 + && !_item.IsAltStream) + { + // if (NFind::DoesFileExist_Raw(tempFilePath)) + if (ZoneMode != NExtract::NZoneIdMode::kOffice || + FindExt2(kOfficeExtensions, fs2us(_diskFilePath))) + { + // we must write zone file before setting of timestamps + if (!WriteZoneFile_To_BaseFile(_diskFilePath, ZoneBuf)) + { + // we can't write it in FAT + // SendMessageError_with_LastError("Can't write Zone.Identifier stream", path); + } + } + } + #endif + + CFiTimesCAM t; + GetFiTimesCAM(t); + + // #ifdef _WIN32 + if (t.IsSomeTimeDefined()) + _outFileStreamSpec->SetTime( + t.CTime_Defined ? &t.CTime : NULL, + t.ATime_Defined ? &t.ATime : NULL, + t.MTime_Defined ? &t.MTime : NULL); + // #endif + + RINOK(_outFileStreamSpec->Close()) + _outFileStream.Release(); + +#if defined(_WIN32) && !defined(UNDER_CE) + if (!_altStream_NeedRestore_Attrib_for_parentFsPath.IsEmpty()) + { + SetFileAttrib(_altStream_NeedRestore_Attrib_for_parentFsPath, _altStream_NeedRestore_AttribVal); + _altStream_NeedRestore_Attrib_for_parentFsPath.Empty(); + } +#endif + + return hres; +} + + +#ifdef SUPPORT_LINKS + + +HRESULT CArchiveExtractCallback::SetFromLinkPath( + const FString &fullProcessedPath, + const CLinkInfo &linkInfo, + bool &linkWasSet) +{ + linkWasSet = false; + if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink) + return S_OK; + + UString relatPath; + + /* if (linkInfo.isRelative) + linkInfo.linkPath is final link path that must be stored to file link field + else + linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath. + */ + + if (linkInfo.isRelative) + relatPath = GetDirPrefixOf(_item.Path); + relatPath += linkInfo.linkPath; + + if (!IsSafePath(relatPath)) + { + return SendMessageError2( + 0, // errorCode + "Dangerous link path was ignored", + us2fs(_item.Path), + us2fs(linkInfo.linkPath)); // us2fs(relatPath) + } + + FString existPath; + if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative) + { + if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) + { + RINOK(SendMessageError("Incorrect path", us2fs(relatPath))) + } + } + else + { + existPath = us2fs(linkInfo.linkPath); + // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr()); + } + + if (existPath.IsEmpty()) + return SendMessageError("Empty link", fullProcessedPath); + + if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */) + { + // if (linkInfo.isHardLink) + { + if (!MyCreateHardLink(fullProcessedPath, existPath)) + { + const HRESULT errorCode = GetLastError_noZero_HRESULT(); + RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath)) + } + /* + RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) + _op_WasReported = true; + RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK)) + */ + linkWasSet = true; + return S_OK; + } + /* + // IsCopyLink + { + NFind::CFileInfo fi; + if (!fi.Find(existPath)) + { + RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath)); + } + else + { + if (_curSize_Defined && _curSize == fi.Size) + _copyFile_Path = existPath; + else + { + RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); + } + // RINOK(MyCopyFile(existPath, fullProcessedPath)); + } + } + */ + } + + // is Symbolic link + + /* + if (_item.IsDir && !isRelative) + { + // Windows before Vista doesn't support symbolic links. + // we could convert such symbolic links to Junction Points + // isJunction = true; + // convertToAbs = true; + } + */ + + if (!_ntOptions.SymLinks_AllowDangerous.Val) + { + #ifdef _WIN32 + if (_item.IsDir) + #endif + if (linkInfo.isRelative) + { + CLinkLevelsInfo levelsInfo; + levelsInfo.Parse(linkInfo.linkPath); + if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute) + { + return SendMessageError2( + 0, // errorCode + "Dangerous symbolic link path was ignored", + us2fs(_item.Path), + us2fs(linkInfo.linkPath)); + } + } + } + + + #ifdef _WIN32 + + CByteBuffer data; + // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr()); + if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL)) + return SendMessageError("Cannot fill link data", us2fs(_item.Path)); + + /* + if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0) + { + SendMessageError("reconstructed Reparse is different", fs2us(existPath)); + } + */ + + CReparseAttr attr; + if (!attr.Parse(data, data.Size())) + { + RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))) + return S_OK; + } + if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) + { + RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) + return S_OK; + } + linkWasSet = true; + + return S_OK; + + + #else // ! _WIN32 + + if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath)) + { + RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) + return S_OK; + } + linkWasSet = true; + + return S_OK; + + #endif // ! _WIN32 +} + + +bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData) +{ + Clear(); + // this->isLinux = isLinuxData; + + if (isLinuxData) + { + isJunction = false; + isHardLink = false; + AString utf; + if (dataSize >= (1 << 12)) + return false; + utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize); + UString u; + if (!ConvertUTF8ToUnicode(utf, u)) + return false; + linkPath = u; + + // in linux symbolic data: we expect that linux separator '/' is used + // if windows link was created, then we also must use linux separator + if (u.IsEmpty()) + return false; + const wchar_t c = u[0]; + isRelative = !IS_PATH_SEPAR(c); + return true; + } + + CReparseAttr reparse; + if (!reparse.Parse(data, dataSize)) + return false; + isHardLink = false; + // isCopyLink = false; + linkPath = reparse.GetPath(); + isJunction = reparse.IsMountPoint(); + + if (reparse.IsSymLink_WSL()) + { + isWSL = true; + isRelative = reparse.IsRelative_WSL(); + } + else + isRelative = reparse.IsRelative_Win(); + + // FIXME !!! + #ifndef _WIN32 + linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); + #endif + + return true; +} + +#endif // SUPPORT_LINKS + + +HRESULT CArchiveExtractCallback::CloseReparseAndFile() +{ + HRESULT res = S_OK; + + #ifdef SUPPORT_LINKS + + size_t reparseSize = 0; + bool repraseMode = false; + bool needSetReparse = false; + CLinkInfo linkInfo; + + if (_bufPtrSeqOutStream) + { + repraseMode = true; + reparseSize = _bufPtrSeqOutStream_Spec->GetPos(); + if (_curSize_Defined && reparseSize == _outMemBuf.Size()) + { + /* + CReparseAttr reparse; + DWORD errorCode = 0; + needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); + if (needSetReparse) + { + UString linkPath = reparse.GetPath(); + #ifndef _WIN32 + linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); + #endif + } + */ + needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux); + if (!needSetReparse) + res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); + } + else + { + res = SendMessageError_with_LastError("Unknown reparse stream", us2fs(_item.Path)); + } + if (!needSetReparse && _outFileStream) + { + const HRESULT res2 = WriteStream(_outFileStream, _outMemBuf, reparseSize); + if (res == S_OK) + res = res2; + } + _bufPtrSeqOutStream.Release(); + } + + #endif // SUPPORT_LINKS + + + const HRESULT res2 = CloseFile(); + + if (res == S_OK) + res = res2; + + RINOK(res) + + #ifdef SUPPORT_LINKS + if (repraseMode) + { + _curSize = reparseSize; + _curSize_Defined = true; + + #ifdef SUPPORT_LINKS + if (needSetReparse) + { + // in Linux : we must delete empty file before symbolic link creation + // in Windows : we can create symbolic link even without file deleting + if (!DeleteFileAlways(_diskFilePath)) + { + RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) + } + { + /* + // for DEBUG ONLY: we can extract sym links as WSL links + // to eliminate (non-admin) errors for sym links. + #ifdef _WIN32 + if (!linkInfo.isHardLink && !linkInfo.isJunction) + linkInfo.isWSL = true; + #endif + */ + bool linkWasSet = false; + RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet)) + if (linkWasSet) + _isSymLinkCreated = linkInfo.IsSymLink(); + else + _needSetAttrib = false; + } + /* + if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, )) + { + res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath); + } + */ + } + #endif + } + #endif + return res; +} + + +void CArchiveExtractCallback::SetAttrib() +{ + #ifndef _WIN32 + // Linux now doesn't support permissions for symlinks + if (_isSymLinkCreated) + return; + #endif + + if (_itemFailure + || _diskFilePath.IsEmpty() + || _stdOutMode + || !_extractMode) + return; + + #ifndef _WIN32 + if (_fi.Owner.Id_Defined && + _fi.Group.Id_Defined) + { + if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0) + { + SendMessageError_with_LastError("Cannot set owner", _diskFilePath); + } + } + #endif + + if (_fi.Attrib_Defined) + { + // const AString s = GetAnsiString(_diskFilePath); + // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); + bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib); + if (!res) + { + // do we need error message here in Windows and in posix? + SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath); + } + } +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) +{ + COM_TRY_BEGIN + + // printf("\nCArchiveExtractCallback::SetOperationResult: %d %s\n", opRes, GetAnsiString(_diskFilePath)); + + #ifndef Z7_SFX + if (ExtractToStreamCallback) + { + GetUnpackSize(); + return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize); + } + #endif + + #ifndef Z7_SFX + + if (_hashStreamWasUsed) + { + _hashStreamSpec->_hash->Final(_item.IsDir, + #ifdef SUPPORT_ALT_STREAMS + _item.IsAltStream + #else + false + #endif + , _item.Path); + _curSize = _hashStreamSpec->GetSize(); + _curSize_Defined = true; + _hashStreamSpec->ReleaseStream(); + _hashStreamWasUsed = false; + } + + #endif // Z7_SFX + + RINOK(CloseReparseAndFile()) + + #ifdef Z7_USE_SECURITY_CODE + if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); + if (dataSize != 0) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + if (CheckNtSecure((const Byte *)data, dataSize)) + { + SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; + if (_saclEnabled) + securInfo |= SACL_SECURITY_INFORMATION; + ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data)); + } + } + } + #endif // Z7_USE_SECURITY_CODE + + if (!_curSize_Defined) + GetUnpackSize(); + + if (_curSize_Defined) + { + #ifdef SUPPORT_ALT_STREAMS + if (_item.IsAltStream) + AltStreams_UnpackSize += _curSize; + else + #endif + UnpackSize += _curSize; + } + + if (_item.IsDir) + NumFolders++; + #ifdef SUPPORT_ALT_STREAMS + else if (_item.IsAltStream) + NumAltStreams++; + #endif + else + NumFiles++; + + if (_needSetAttrib) + SetAttrib(); + + RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted))) + + return S_OK; + + COM_TRY_END +} + + + +Z7_COM7F_IMF(CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) +{ + if (_folderArchiveExtractCallback2) + { + bool isEncrypted = false; + UString s; + + if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1) + { + CReadArcItem item; + RINOK(_arc->GetItem(index, item)) + s = item.Path; + RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted)) + } + else + { + s = '#'; + s.Add_UInt32(index); + // if (indexType == NArchive::NEventIndexType::kBlockIndex) {} + } + + return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s); + } + + return S_OK; +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)) +{ + COM_TRY_BEGIN + if (!_cryptoGetTextPassword) + { + RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, + &_cryptoGetTextPassword)) + } + return _cryptoGetTextPassword->CryptoGetTextPassword(password); + COM_TRY_END +} + + +#ifndef Z7_SFX + +// ---------- HASH functions ---------- + +FString CArchiveExtractCallback::Hash_GetFullFilePath() +{ + // this function changes _item.PathParts. + CorrectPathParts(); + const UStringVector &pathParts = _item.PathParts; + const UString processedPath (MakePathFromParts(pathParts)); + FString fullProcessedPath (us2fs(processedPath)); + if (_pathMode != NExtract::NPathMode::kAbsPaths + || !NName::IsAbsolutePath(processedPath)) + { + fullProcessedPath = MakePath_from_2_Parts( + DirPathPrefix_for_HashFiles, + // _dirPathPrefix, + fullProcessedPath); + } + return fullProcessedPath; +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (propID == kpidSize) + { + RINOK(GetItem(index)) + const FString fullProcessedPath = Hash_GetFullFilePath(); + NFile::NFind::CFileInfo fi; + if (fi.Find_FollowLink(fullProcessedPath)) + if (!fi.IsDir()) + prop = (UInt64)fi.Size; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)) +{ + COM_TRY_BEGIN + *inStream = NULL; + // if (index != _index) return E_FAIL; + if (mode != NUpdateNotifyOp::kHashRead) + return E_FAIL; + + RINOK(GetItem(index)) + const FString fullProcessedPath = Hash_GetFullFilePath(); + + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStreamRef = inStreamSpec; + inStreamSpec->Set_PreserveATime(_ntOptions.PreserveATime); + if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite)) + { + RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath)) + return S_OK; + } + *inStream = inStreamRef.Detach(); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::ReportOperation( + UInt32 /* indexType */, UInt32 /* index */, UInt32 /* op */)) +{ + // COM_TRY_BEGIN + return S_OK; + // COM_TRY_END +} + + +Z7_COM7F_IMF(CArchiveExtractCallback::RequestMemoryUse( + UInt32 flags, UInt32 indexType, UInt32 index, const wchar_t *path, + UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) +{ + if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) + { + const UInt64 memLimit = _ntOptions.MemLimit; + if (memLimit != (UInt64)(Int64)-1) + { + // we overwrite allowedSize + *allowedSize = memLimit; + if (requiredSize <= memLimit) + { + *answerFlags = NRequestMemoryAnswerFlags::k_Allow; + return S_OK; + } + *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded; + if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) + *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc; + flags |= NRequestMemoryUseFlags::k_SLimit_Exceeded + | NRequestMemoryUseFlags::k_AllowedSize_WasForced; + } + } + + if (!_requestMemoryUseCallback) + { + _extractCallback2.QueryInterface(IID_IArchiveRequestMemoryUseCallback, + &_requestMemoryUseCallback); + if (!_requestMemoryUseCallback) + { + // keep default (answerFlags) from caller or (answerFlags) that was set in this function + return S_OK; + } + } + +#if 0 + if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) + if (requiredSize <= *allowedSize) + { + // it's expected, that *answerFlags was set to NRequestMemoryAnswerFlags::k_Allow already, + // because it's default answer for (requiredSize <= *allowedSize) case. + *answerFlags = NRequestMemoryAnswerFlags::k_Allow; // optional code + } + else + { + // we clear *answerFlags, because we want to disable dafault "Allow", if it's set. + // *answerFlags = 0; + /* + NRequestMemoryAnswerFlags::k_SkipArc | + NRequestMemoryAnswerFlags::k_Limit_Exceeded; + */ + } +#endif + + UString s; + if (!path + && indexType == NArchive::NEventIndexType::kInArcIndex + && index != (UInt32)(Int32)-1 + && _arc) + { + RINOK(_arc->GetItem_Path(index, s)) + path = s.Ptr(); + } + + return _requestMemoryUseCallback->RequestMemoryUse( + flags, indexType, index, path, + requiredSize, allowedSize, answerFlags); +} + +#endif // Z7_SFX + + + +// ------------ After Extracting functions ------------ + +void CDirPathSortPair::SetNumSlashes(const FChar *s) +{ + for (unsigned numSlashes = 0;;) + { + FChar c = *s++; + if (c == 0) + { + Len = numSlashes; + return; + } + if (IS_PATH_SEPAR(c)) + numSlashes++; + } +} + + +bool CDirPathTime::SetDirTime() const +{ + return NDir::SetDirTime(Path, + CTime_Defined ? &CTime : NULL, + ATime_Defined ? &ATime : NULL, + MTime_Defined ? &MTime : NULL); +} + + +HRESULT CArchiveExtractCallback::SetDirsTimes() +{ + if (!_arc) + return S_OK; + + CRecordVector pairs; + pairs.ClearAndSetSize(_extractedFolders.Size()); + unsigned i; + + for (i = 0; i < _extractedFolders.Size(); i++) + { + CDirPathSortPair &pair = pairs[i]; + pair.Index = i; + pair.SetNumSlashes(_extractedFolders[i].Path); + } + + pairs.Sort2(); + + HRESULT res = S_OK; + + for (i = 0; i < pairs.Size(); i++) + { + const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; + if (!dpt.SetDirTime()) + { + // result = E_FAIL; + // do we need error message here in Windows and in posix? + // SendMessageError_with_LastError("Cannot set directory time", dpt.Path); + } + } + + /* + #ifndef _WIN32 + for (i = 0; i < _delayedSymLinks.Size(); i++) + { + const CDelayedSymLink &link = _delayedSymLinks[i]; + if (!link.Create()) + { + if (res == S_OK) + res = GetLastError_noZero_HRESULT(); + // res = E_FAIL; + // do we need error message here in Windows and in posix? + SendMessageError_with_LastError("Cannot create Symbolic Link", link._source); + } + } + #endif // _WIN32 + */ + + ClearExtractedDirsInfo(); + return res; +} + + +HRESULT CArchiveExtractCallback::CloseArc() +{ + HRESULT res = CloseReparseAndFile(); + const HRESULT res2 = SetDirsTimes(); + if (res == S_OK) + res = res2; + _arc = NULL; + return res; +} diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index 969b56abb..f3ee01c23 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -1,605 +1,584 @@ -// ArchiveExtractCallback.h - -#ifndef ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H -#define ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyLinux.h" -#include "../../../Common/Wildcard.h" - -#include "../../IPassword.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" - -#include "../../Archive/IArchive.h" - -#include "ExtractMode.h" -#include "IFileExtractCallback.h" -#include "OpenArchive.h" - -#include "HashCalc.h" - -#ifndef Z7_SFX - -Z7_CLASS_IMP_NOQIB_1( - COutStreamWithHash - , ISequentialOutStream -) - bool _calculate; - CMyComPtr _stream; - UInt64 _size; -public: - IHashCalc *_hash; - - void SetStream(ISequentialOutStream *stream) { _stream = stream; } - void ReleaseStream() { _stream.Release(); } - void Init(bool calculate = true) - { - InitCRC(); - _size = 0; - _calculate = calculate; - } - void EnableCalc(bool calculate) { _calculate = calculate; } - void InitCRC() { _hash->InitForNewFile(); } - UInt64 GetSize() const { return _size; } -}; - -#endif - -struct CExtractNtOptions -{ - CBoolPair NtSecurity; - CBoolPair SymLinks; - CBoolPair SymLinks_AllowDangerous; - CBoolPair HardLinks; - CBoolPair AltStreams; - bool ReplaceColonForAltStream; - bool WriteToAltStreamIfColon; - - bool ExtractOwner; - - bool PreAllocateOutFile; - - // used for hash arcs only, when we open external files - bool PreserveATime; - bool OpenShareForWrite; - - UInt64 MemLimit; - - CExtractNtOptions(): - ReplaceColonForAltStream(false), - WriteToAltStreamIfColon(false), - ExtractOwner(false), - PreserveATime(false), - OpenShareForWrite(false), - MemLimit((UInt64)(Int64)-1) - { - SymLinks.Val = true; - SymLinks_AllowDangerous.Val = false; - HardLinks.Val = true; - AltStreams.Val = true; - - PreAllocateOutFile = - #ifdef _WIN32 - true; - #else - false; - #endif - } -}; - -#ifndef Z7_SFX - -Z7_CLASS_IMP_COM_1( - CGetProp - , IGetProp -) -public: - UInt32 IndexInArc; - const CArc *Arc; - // UString Name; // relative path -}; - -#endif - -#ifndef Z7_SFX -#ifndef UNDER_CE - -#define SUPPORT_LINKS - -#endif -#endif - - -#ifdef SUPPORT_LINKS - -struct CHardLinkNode -{ - UInt64 StreamId; - UInt64 INode; - - int Compare(const CHardLinkNode &a) const; -}; - -class CHardLinks -{ -public: - CRecordVector IDs; - CObjectVector Links; - - void Clear() - { - IDs.Clear(); - Links.Clear(); - } - - void PrepareLinks() - { - while (Links.Size() < IDs.Size()) - Links.AddNew(); - } -}; - -#endif - -#ifdef SUPPORT_ALT_STREAMS - -struct CIndexToPathPair -{ - UInt32 Index; - FString Path; - - CIndexToPathPair(UInt32 index): Index(index) {} - CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {} - - int Compare(const CIndexToPathPair &pair) const - { - return MyCompare(Index, pair.Index); - } -}; - -#endif - - - -struct CFiTimesCAM -{ - CFiTime CTime; - CFiTime ATime; - CFiTime MTime; - - bool CTime_Defined; - bool ATime_Defined; - bool MTime_Defined; - - bool IsSomeTimeDefined() const - { - return - CTime_Defined | - ATime_Defined | - MTime_Defined; - } -}; - -struct CDirPathTime: public CFiTimesCAM -{ - FString Path; - - bool SetDirTime() const; -}; - - -#ifdef SUPPORT_LINKS - -struct CLinkInfo -{ - // bool isCopyLink; - bool isHardLink; - bool isJunction; - bool isRelative; - bool isWSL; - UString linkPath; - - bool IsSymLink() const { return !isHardLink; } - - CLinkInfo(): - // IsCopyLink(false), - isHardLink(false), - isJunction(false), - isRelative(false), - isWSL(false) - {} - - void Clear() - { - // IsCopyLink = false; - isHardLink = false; - isJunction = false; - isRelative = false; - isWSL = false; - linkPath.Empty(); - } - - bool Parse(const Byte *data, size_t dataSize, bool isLinuxData); -}; - -#endif // SUPPORT_LINKS - - -#ifndef _WIN32 - -struct COwnerInfo -{ - bool Id_Defined; - UInt32 Id; - AString Name; - - void Clear() - { - Id_Defined = false; - Id = 0; - Name.Empty(); - } -}; - -#endif - - -class CArchiveExtractCallback Z7_final: - public IArchiveExtractCallback, - public IArchiveExtractCallbackMessage2, - public ICryptoGetTextPassword, - public ICompressProgressInfo, -#ifndef Z7_SFX - public IArchiveUpdateCallbackFile, - public IArchiveGetDiskProperty, - public IArchiveRequestMemoryUseCallback, -#endif - public CMyUnknownImp -{ - /* IArchiveExtractCallback, */ - Z7_COM_QI_BEGIN2(IArchiveExtractCallbackMessage2) - Z7_COM_QI_ENTRY(ICryptoGetTextPassword) - Z7_COM_QI_ENTRY(ICompressProgressInfo) -#ifndef Z7_SFX - Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile) - Z7_COM_QI_ENTRY(IArchiveGetDiskProperty) - Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback) -#endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IArchiveExtractCallback) - Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2) - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - Z7_IFACE_COM7_IMP(ICompressProgressInfo) -#ifndef Z7_SFX - Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile) - Z7_IFACE_COM7_IMP(IArchiveGetDiskProperty) - Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) -#endif - - const CArc *_arc; - CExtractNtOptions _ntOptions; - - bool _isSplit; - - bool _extractMode; - - bool Write_CTime; - bool Write_ATime; - bool Write_MTime; - bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_"; - - bool _encrypted; - - // bool _is_SymLink_in_Data; - bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX - - bool _needSetAttrib; - bool _isSymLinkCreated; - bool _itemFailure; - - bool _some_pathParts_wereRemoved; -public: - bool Is_elimPrefix_Mode; - -private: - bool _curSize_Defined; - bool _fileLength_WasSet; - - bool _removePartsForAltStreams; - - bool _stdOutMode; - bool _testMode; - bool _multiArchives; - - NExtract::NPathMode::EEnum _pathMode; - NExtract::NOverwriteMode::EEnum _overwriteMode; - - const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin) - CMyComPtr _extractCallback2; - // CMyComPtr _compressProgress; - // CMyComPtr _callbackMessage; - CMyComPtr _folderArchiveExtractCallback2; - CMyComPtr _cryptoGetTextPassword; - - FString _dirPathPrefix; - FString _dirPathPrefix_Full; - - #ifndef Z7_SFX - - CMyComPtr ExtractToStreamCallback; - CGetProp *GetProp_Spec; - CMyComPtr GetProp; - CMyComPtr _requestMemoryUseCallback; - - #endif - - CReadArcItem _item; - FString _diskFilePath; - UInt64 _position; - - struct CProcessedFileInfo - { - CArcTime CTime; - CArcTime ATime; - CArcTime MTime; - UInt32 Attrib; - bool Attrib_Defined; - - #ifndef _WIN32 - COwnerInfo Owner; - COwnerInfo Group; - #endif - - bool IsReparse() const - { - return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); - } - - bool IsLinuxSymLink() const - { - return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); - } - - void SetFromPosixAttrib(UInt32 a) - { - // here we set only part of combined attribute required by SetFileAttrib() call - #ifdef _WIN32 - // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute. - Attrib = MY_LIN_S_ISDIR(a) ? - FILE_ATTRIBUTE_DIRECTORY : - FILE_ATTRIBUTE_ARCHIVE; - if ((a & 0222) == 0) // (& S_IWUSR) in p7zip - Attrib |= FILE_ATTRIBUTE_READONLY; - // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() - a &= MY_LIN_S_IFMT; - if (a == MY_LIN_S_IFLNK) - Attrib |= (a << 16); - #else - Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; - #endif - Attrib_Defined = true; - } - } _fi; - - UInt32 _index; - UInt64 _curSize; - UInt64 _fileLength_that_WasSet; - - COutFileStream *_outFileStreamSpec; - CMyComPtr _outFileStream; - - CByteBuffer _outMemBuf; - CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec; - CMyComPtr _bufPtrSeqOutStream; - - - #ifndef Z7_SFX - - COutStreamWithHash *_hashStreamSpec; - CMyComPtr _hashStream; - bool _hashStreamWasUsed; - - bool _use_baseParentFolder_mode; - UInt32 _baseParentFolder; - #endif - - UStringVector _removePathParts; - - CMyComPtr _localProgress; - UInt64 _packTotal; - - UInt64 _progressTotal; - bool _progressTotal_Defined; - - CObjectVector _extractedFolders; - - #ifndef _WIN32 - // CObjectVector _delayedSymLinks; - #endif - - #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) - bool _saclEnabled; - #endif - - void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); - HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); - HRESULT GetUnpackSize(); - - FString Hash_GetFullFilePath(); - - void SetAttrib(); - -public: - HRESULT SendMessageError(const char *message, const FString &path); - HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); - HRESULT SendMessageError_with_LastError(const char *message, const FString &path); - HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); - -public: - #if defined(_WIN32) && !defined(UNDER_CE) - NExtract::NZoneIdMode::EEnum ZoneMode; - CByteBuffer ZoneBuf; - #endif - - CLocalProgress *LocalProgressSpec; - - UInt64 NumFolders; - UInt64 NumFiles; - UInt64 NumAltStreams; - UInt64 UnpackSize; - UInt64 AltStreams_UnpackSize; - - FString DirPathPrefix_for_HashFiles; - - CArchiveExtractCallback(); - - void InitForMulti(bool multiArchives, - NExtract::NPathMode::EEnum pathMode, - NExtract::NOverwriteMode::EEnum overwriteMode, - NExtract::NZoneIdMode::EEnum zoneMode, - bool keepAndReplaceEmptyDirPrefixes) - { - _multiArchives = multiArchives; - _pathMode = pathMode; - _overwriteMode = overwriteMode; - #if defined(_WIN32) && !defined(UNDER_CE) - ZoneMode = zoneMode; - #else - UNUSED_VAR(zoneMode) - #endif - _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes; - NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; - } - - #ifndef Z7_SFX - - void SetHashMethods(IHashCalc *hash) - { - if (!hash) - return; - _hashStreamSpec = new COutStreamWithHash; - _hashStream = _hashStreamSpec; - _hashStreamSpec->_hash = hash; - } - - #endif - - void InitBeforeNewArchive(); - - void Init( - const CExtractNtOptions &ntOptions, - const NWildcard::CCensorNode *wildcardCensor, - const CArc *arc, - IFolderArchiveExtractCallback *extractCallback2, - bool stdOutMode, bool testMode, - const FString &directoryPath, - const UStringVector &removePathParts, bool removePartsForAltStreams, - UInt64 packSize); - - - #ifdef SUPPORT_LINKS - -private: - CHardLinks _hardLinks; - CLinkInfo _link; - - // FString _copyFile_Path; - // HRESULT MyCopyFile(ISequentialOutStream *outStream); - HRESULT Link(const FString &fullProcessedPath); - HRESULT ReadLink(); - -public: - // call PrepareHardLinks() after Init() - HRESULT PrepareHardLinks(const CRecordVector *realIndices); // NULL means all items - - #endif - - - #ifdef SUPPORT_ALT_STREAMS - CObjectVector _renamedFiles; - #endif - - // call it after Init() - - #ifndef Z7_SFX - void SetBaseParentFolderIndex(UInt32 indexInArc) - { - _baseParentFolder = indexInArc; - _use_baseParentFolder_mode = true; - } - #endif - - HRESULT CloseArc(); - -private: - void ClearExtractedDirsInfo() - { - _extractedFolders.Clear(); - #ifndef _WIN32 - // _delayedSymLinks.Clear(); - #endif - } - - HRESULT Read_fi_Props(); - void CorrectPathParts(); - void GetFiTimesCAM(CFiTimesCAM &pt); - void CreateFolders(); - - bool _isRenamed; - HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); - HRESULT GetExtractStream(CMyComPtr &outStreamLoc, bool &needExit); - HRESULT GetItem(UInt32 index); - - HRESULT CloseFile(); - HRESULT CloseReparseAndFile(); - HRESULT CloseReparseAndFile2(); - HRESULT SetDirsTimes(); - - const void *NtReparse_Data; - UInt32 NtReparse_Size; - - #ifdef SUPPORT_LINKS - HRESULT SetFromLinkPath( - const FString &fullProcessedPath, - const CLinkInfo &linkInfo, - bool &linkWasSet); - #endif -}; - - -struct CArchiveExtractCallback_Closer -{ - CArchiveExtractCallback *_ref; - - CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {} - - HRESULT Close() - { - HRESULT res = S_OK; - if (_ref) - { - res = _ref->CloseArc(); - _ref = NULL; - } - return res; - } - - ~CArchiveExtractCallback_Closer() - { - Close(); - } -}; - - -bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); - -void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf); -bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf); - -#endif +// ArchiveExtractCallback.h + +#ifndef ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H +#define ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyLinux.h" +#include "../../../Common/Wildcard.h" + +#include "../../IPassword.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" + +#include "../../Archive/IArchive.h" + +#include "ExtractMode.h" +#include "IFileExtractCallback.h" +#include "OpenArchive.h" + +#include "HashCalc.h" + +#ifndef Z7_SFX + +Z7_CLASS_IMP_NOQIB_1( + COutStreamWithHash + , ISequentialOutStream +) + bool _calculate; + CMyComPtr _stream; + UInt64 _size; +public: + IHashCalc *_hash; + + void SetStream(ISequentialOutStream *stream) { _stream = stream; } + void ReleaseStream() { _stream.Release(); } + void Init(bool calculate = true) + { + InitCRC(); + _size = 0; + _calculate = calculate; + } + void EnableCalc(bool calculate) { _calculate = calculate; } + void InitCRC() { _hash->InitForNewFile(); } + UInt64 GetSize() const { return _size; } +}; + +#endif + +struct CExtractNtOptions +{ + CBoolPair NtSecurity; + CBoolPair SymLinks; + CBoolPair SymLinks_AllowDangerous; + CBoolPair HardLinks; + CBoolPair AltStreams; + bool ReplaceColonForAltStream; + bool WriteToAltStreamIfColon; + + bool ExtractOwner; + + bool PreAllocateOutFile; + + // used for hash arcs only, when we open external files + bool PreserveATime; + bool OpenShareForWrite; + + UInt64 MemLimit; + + CExtractNtOptions(): + ReplaceColonForAltStream(false), + WriteToAltStreamIfColon(false), + ExtractOwner(false), + PreserveATime(false), + OpenShareForWrite(false), + MemLimit((UInt64)(Int64)-1) + { + SymLinks.Val = true; + SymLinks_AllowDangerous.Val = false; + HardLinks.Val = true; + AltStreams.Val = true; + + PreAllocateOutFile = + #ifdef _WIN32 + true; + #else + false; + #endif + } +}; + + +#ifndef Z7_SFX +#ifndef UNDER_CE +#define SUPPORT_LINKS +#endif +#endif + + +#ifdef SUPPORT_LINKS + +struct CHardLinkNode +{ + UInt64 StreamId; + UInt64 INode; + + int Compare(const CHardLinkNode &a) const; +}; + +class CHardLinks +{ +public: + CRecordVector IDs; + CObjectVector Links; + + void Clear() + { + IDs.Clear(); + Links.Clear(); + } + + void PrepareLinks() + { + while (Links.Size() < IDs.Size()) + Links.AddNew(); + } +}; + +#endif + +#ifdef SUPPORT_ALT_STREAMS + +struct CIndexToPathPair +{ + UInt32 Index; + FString Path; + + CIndexToPathPair(UInt32 index): Index(index) {} + CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {} + + int Compare(const CIndexToPathPair &pair) const + { + return MyCompare(Index, pair.Index); + } +}; + +#endif + + + +struct CFiTimesCAM +{ + CFiTime CTime; + CFiTime ATime; + CFiTime MTime; + + bool CTime_Defined; + bool ATime_Defined; + bool MTime_Defined; + + bool IsSomeTimeDefined() const + { + return + CTime_Defined | + ATime_Defined | + MTime_Defined; + } +}; + +struct CDirPathTime: public CFiTimesCAM +{ + FString Path; + + bool SetDirTime() const; +}; + + +#ifdef SUPPORT_LINKS + +struct CLinkInfo +{ + // bool isCopyLink; + bool isHardLink; + bool isJunction; + bool isRelative; + bool isWSL; + UString linkPath; + + bool IsSymLink() const { return !isHardLink; } + + CLinkInfo(): + // IsCopyLink(false), + isHardLink(false), + isJunction(false), + isRelative(false), + isWSL(false) + {} + + void Clear() + { + // IsCopyLink = false; + isHardLink = false; + isJunction = false; + isRelative = false; + isWSL = false; + linkPath.Empty(); + } + + bool Parse(const Byte *data, size_t dataSize, bool isLinuxData); +}; + +#endif // SUPPORT_LINKS + + +#ifndef _WIN32 + +struct COwnerInfo +{ + bool Id_Defined; + UInt32 Id; + AString Name; + + void Clear() + { + Id_Defined = false; + Id = 0; + Name.Empty(); + } +}; + +#endif + + +class CArchiveExtractCallback Z7_final: + public IArchiveExtractCallback, + public IArchiveExtractCallbackMessage2, + public ICryptoGetTextPassword, + public ICompressProgressInfo, +#ifndef Z7_SFX + public IArchiveUpdateCallbackFile, + public IArchiveGetDiskProperty, + public IArchiveRequestMemoryUseCallback, +#endif + public CMyUnknownImp +{ + /* IArchiveExtractCallback, */ + Z7_COM_QI_BEGIN2(IArchiveExtractCallbackMessage2) + Z7_COM_QI_ENTRY(ICryptoGetTextPassword) + Z7_COM_QI_ENTRY(ICompressProgressInfo) +#ifndef Z7_SFX + Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile) + Z7_COM_QI_ENTRY(IArchiveGetDiskProperty) + Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback) +#endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IArchiveExtractCallback) + Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2) + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + Z7_IFACE_COM7_IMP(ICompressProgressInfo) +#ifndef Z7_SFX + Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile) + Z7_IFACE_COM7_IMP(IArchiveGetDiskProperty) + Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) +#endif + + // bool Write_CTime; + // bool Write_ATime; + // bool Write_MTime; + bool _stdOutMode; + bool _testMode; + bool _removePartsForAltStreams; +public: + bool Is_elimPrefix_Mode; +private: + + const CArc *_arc; + CExtractNtOptions _ntOptions; + + bool _encrypted; + bool _isSplit; + bool _curSize_Defined; + bool _fileLength_WasSet; + + bool _isRenamed; + bool _extractMode; + // bool _is_SymLink_in_Data; + bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX + bool _needSetAttrib; + bool _isSymLinkCreated; + bool _itemFailure; + bool _some_pathParts_wereRemoved; + + bool _multiArchives; + bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_"; +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + bool _saclEnabled; +#endif + + NExtract::NPathMode::EEnum _pathMode; + NExtract::NOverwriteMode::EEnum _overwriteMode; + + CMyComPtr _extractCallback2; + const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin) + // CMyComPtr _compressProgress; + // CMyComPtr _callbackMessage; + CMyComPtr _folderArchiveExtractCallback2; + CMyComPtr _cryptoGetTextPassword; + + FString _dirPathPrefix; + FString _dirPathPrefix_Full; + + #ifndef Z7_SFX + + CMyComPtr ExtractToStreamCallback; + CMyComPtr _requestMemoryUseCallback; + + #endif + + CReadArcItem _item; + FString _diskFilePath; + + struct CProcessedFileInfo + { + CArcTime CTime; + CArcTime ATime; + CArcTime MTime; + UInt32 Attrib; + bool Attrib_Defined; + + #ifndef _WIN32 + COwnerInfo Owner; + COwnerInfo Group; + #endif + + bool IsReparse() const + { + return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); + } + + bool IsLinuxSymLink() const + { + return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); + } + + void SetFromPosixAttrib(UInt32 a) + { + // here we set only part of combined attribute required by SetFileAttrib() call + #ifdef _WIN32 + // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute. + Attrib = MY_LIN_S_ISDIR(a) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((a & 0222) == 0) // (& S_IWUSR) in p7zip + Attrib |= FILE_ATTRIBUTE_READONLY; + // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() + a &= MY_LIN_S_IFMT; + if (a == MY_LIN_S_IFLNK) + Attrib |= (a << 16); + #else + Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; + #endif + Attrib_Defined = true; + } + } _fi; + + UInt64 _position; + UInt64 _curSize; + UInt64 _fileLength_that_WasSet; + UInt32 _index; + +// #ifdef SUPPORT_ALT_STREAMS +#if defined(_WIN32) && !defined(UNDER_CE) + DWORD _altStream_NeedRestore_AttribVal; + FString _altStream_NeedRestore_Attrib_for_parentFsPath; +#endif +// #endif + + COutFileStream *_outFileStreamSpec; + CMyComPtr _outFileStream; + + CByteBuffer _outMemBuf; + CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec; + CMyComPtr _bufPtrSeqOutStream; + + #ifndef Z7_SFX + COutStreamWithHash *_hashStreamSpec; + CMyComPtr _hashStream; + bool _hashStreamWasUsed; + + bool _use_baseParentFolder_mode; + UInt32 _baseParentFolder; + #endif + + UStringVector _removePathParts; + + UInt64 _packTotal; + UInt64 _progressTotal; + // bool _progressTotal_Defined; + + CObjectVector _extractedFolders; + + #ifndef _WIN32 + // CObjectVector _delayedSymLinks; + #endif + + void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); + HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); + HRESULT GetUnpackSize(); + + FString Hash_GetFullFilePath(); + + void SetAttrib(); + +public: + HRESULT SendMessageError(const char *message, const FString &path); + HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); + HRESULT SendMessageError_with_LastError(const char *message, const FString &path); + HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); + +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + NExtract::NZoneIdMode::EEnum ZoneMode; + CByteBuffer ZoneBuf; +#endif + + CMyComPtr2_Create LocalProgressSpec; + + UInt64 NumFolders; + UInt64 NumFiles; + UInt64 NumAltStreams; + UInt64 UnpackSize; + UInt64 AltStreams_UnpackSize; + + FString DirPathPrefix_for_HashFiles; + + CArchiveExtractCallback(); + + void InitForMulti(bool multiArchives, + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode, + NExtract::NZoneIdMode::EEnum zoneMode, + bool keepAndReplaceEmptyDirPrefixes) + { + _multiArchives = multiArchives; + _pathMode = pathMode; + _overwriteMode = overwriteMode; +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + ZoneMode = zoneMode; +#else + UNUSED_VAR(zoneMode) +#endif + _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes; + NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; + } + + #ifndef Z7_SFX + + void SetHashMethods(IHashCalc *hash) + { + if (!hash) + return; + _hashStreamSpec = new COutStreamWithHash; + _hashStream = _hashStreamSpec; + _hashStreamSpec->_hash = hash; + } + + #endif + + void InitBeforeNewArchive(); + + void Init( + const CExtractNtOptions &ntOptions, + const NWildcard::CCensorNode *wildcardCensor, + const CArc *arc, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, bool testMode, + const FString &directoryPath, + const UStringVector &removePathParts, bool removePartsForAltStreams, + UInt64 packSize); + + + #ifdef SUPPORT_LINKS + +private: + CHardLinks _hardLinks; + CLinkInfo _link; + + // FString _copyFile_Path; + // HRESULT MyCopyFile(ISequentialOutStream *outStream); + HRESULT Link(const FString &fullProcessedPath); + HRESULT ReadLink(); + +public: + // call PrepareHardLinks() after Init() + HRESULT PrepareHardLinks(const CRecordVector *realIndices); // NULL means all items + + #endif + + + #ifdef SUPPORT_ALT_STREAMS + CObjectVector _renamedFiles; + #endif + + // call it after Init() + + #ifndef Z7_SFX + void SetBaseParentFolderIndex(UInt32 indexInArc) + { + _baseParentFolder = indexInArc; + _use_baseParentFolder_mode = true; + } + #endif + + HRESULT CloseArc(); + +private: + void ClearExtractedDirsInfo() + { + _extractedFolders.Clear(); + #ifndef _WIN32 + // _delayedSymLinks.Clear(); + #endif + } + + HRESULT Read_fi_Props(); + void CorrectPathParts(); + void GetFiTimesCAM(CFiTimesCAM &pt); + void CreateFolders(); + + HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); + HRESULT GetExtractStream(CMyComPtr &outStreamLoc, bool &needExit); + HRESULT GetItem(UInt32 index); + + HRESULT CloseFile(); + HRESULT CloseReparseAndFile(); + HRESULT CloseReparseAndFile2(); + HRESULT SetDirsTimes(); + + const void *NtReparse_Data; + UInt32 NtReparse_Size; + + #ifdef SUPPORT_LINKS + HRESULT SetFromLinkPath( + const FString &fullProcessedPath, + const CLinkInfo &linkInfo, + bool &linkWasSet); + #endif +}; + + +struct CArchiveExtractCallback_Closer +{ + CArchiveExtractCallback *_ref; + + CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {} + + HRESULT Close() + { + HRESULT res = S_OK; + if (_ref) + { + res = _ref->CloseArc(); + _ref = NULL; + } + return res; + } + + ~CArchiveExtractCallback_Closer() + { + Close(); + } +}; + + +bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); + +bool Is_ZoneId_StreamName(const wchar_t *s); +void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf); +bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf); + +#endif diff --git a/CPP/7zip/UI/Common/ArchiveName.cpp b/CPP/7zip/UI/Common/ArchiveName.cpp index 997f63432..3c0976d18 100644 --- a/CPP/7zip/UI/Common/ArchiveName.cpp +++ b/CPP/7zip/UI/Common/ArchiveName.cpp @@ -1,176 +1,176 @@ -// ArchiveName.cpp - -#include "StdAfx.h" - -#include "../../../../C/Sort.h" - -#include "../../../Common/Wildcard.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" - -#include "ArchiveName.h" -#include "ExtractingFilePath.h" - -using namespace NWindows; -using namespace NFile; - - -static const char *g_ArcExts = - "7z" - "\0" "zip" - "\0" "tar" - "\0" "wim" - "\0"; - -static const char *g_HashExts = - "sha256" - "\0"; - - -UString CreateArchiveName( - const UStringVector &paths, - bool isHash, - const NFind::CFileInfo *fi, - UString &baseName) -{ - bool keepName = isHash; - /* - if (paths.Size() == 1) - { - const UString &name = paths[0]; - if (name.Len() > 4) - if (CompareFileNames(name.RightPtr(4), L".tar") == 0) - keepName = true; - } - */ - - UString name ("Archive"); - NFind::CFileInfo fi3; - if (paths.Size() > 1) - fi = NULL; - if (!fi && paths.Size() != 0) - { - const UString &path = paths.Front(); - if (paths.Size() == 1) - { - if (fi3.Find(us2fs(path))) - fi = &fi3; - } - else - { - // we try to use name of parent folder - FString dirPrefix; - if (NDir::GetOnlyDirPrefix(us2fs(path), dirPrefix)) - { - if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back())) - { - #if defined(_WIN32) && !defined(UNDER_CE) - if (NName::IsDriveRootPath_SuperAllowed(dirPrefix)) - { - if (path != fs2us(dirPrefix)) - name = dirPrefix[dirPrefix.Len() - 3]; // only letter - } - else - #endif - { - dirPrefix.DeleteBack(); - if (!dirPrefix.IsEmpty()) - { - const int slash = dirPrefix.ReverseFind_PathSepar(); - if (slash >= 0 && slash != (int)dirPrefix.Len() - 1) - name = dirPrefix.Ptr(slash + 1); - else if (fi3.Find(dirPrefix)) - name = fs2us(fi3.Name); - } - } - } - } - } - } - - if (fi) - { - name = fs2us(fi->Name); - if (!fi->IsDir() && !keepName) - { - const int dotPos = name.Find(L'.'); - if (dotPos > 0 && name.Find(L'.', (unsigned)dotPos + 1) < 0) - name.DeleteFrom((unsigned)dotPos); - } - } - name = Get_Correct_FsFile_Name(name); - - CRecordVector ids; - bool simple_IsAllowed = true; - // for (int y = 0; y < 10000; y++) // for debug - { - // ids.Clear(); - UString n; - - FOR_VECTOR (i, paths) - { - const UString &a = paths[i]; - const int slash = a.ReverseFind_PathSepar(); - // if (name.Len() >= a.Len() - slash + 1) continue; - const wchar_t *s = a.Ptr(slash + 1); - if (!IsPath1PrefixedByPath2(s, name)) - continue; - s += name.Len(); - const char *exts = isHash ? g_HashExts : g_ArcExts; - - for (;;) - { - const char *ext = exts; - const unsigned len = MyStringLen(ext); - if (len == 0) - break; - exts += len + 1; - n = s; - if (n.Len() <= len) - continue; - if (!StringsAreEqualNoCase_Ascii(n.RightPtr(len), ext)) - continue; - n.DeleteFrom(n.Len() - len); - if (n.Back() != '.') - continue; - n.DeleteBack(); - if (n.IsEmpty()) - { - simple_IsAllowed = false; - break; - } - if (n.Len() < 2) - continue; - if (n[0] != '_') - continue; - const wchar_t *end; - const UInt32 v = ConvertStringToUInt32(n.Ptr(1), &end); - if (*end != 0) - continue; - ids.Add(v); - break; - } - } - } - - baseName = name; - if (!simple_IsAllowed) - { - HeapSort(ids.NonConstData(), ids.Size()); - UInt32 v = 2; - const unsigned num = ids.Size(); - for (unsigned i = 0; i < num; i++) - { - const UInt32 id = ids[i]; - if (id > v) - break; - if (id == v) - v = id + 1; - } - name.Add_Char('_'); - name.Add_UInt32(v); - } - return name; -} +// ArchiveName.cpp + +#include "StdAfx.h" + +#include "../../../../C/Sort.h" + +#include "../../../Common/Wildcard.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" + +#include "ArchiveName.h" +#include "ExtractingFilePath.h" + +using namespace NWindows; +using namespace NFile; + + +static const char *g_ArcExts = + "7z" + "\0" "zip" + "\0" "tar" + "\0" "wim" + "\0"; + +static const char *g_HashExts = + "sha256" + "\0"; + + +UString CreateArchiveName( + const UStringVector &paths, + bool isHash, + const NFind::CFileInfo *fi, + UString &baseName) +{ + bool keepName = isHash; + /* + if (paths.Size() == 1) + { + const UString &name = paths[0]; + if (name.Len() > 4) + if (CompareFileNames(name.RightPtr(4), L".tar") == 0) + keepName = true; + } + */ + + UString name ("Archive"); + NFind::CFileInfo fi3; + if (paths.Size() > 1) + fi = NULL; + if (!fi && paths.Size() != 0) + { + const UString &path = paths.Front(); + if (paths.Size() == 1) + { + if (fi3.Find(us2fs(path))) + fi = &fi3; + } + else + { + // we try to use name of parent folder + FString dirPrefix; + if (NDir::GetOnlyDirPrefix(us2fs(path), dirPrefix)) + { + if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back())) + { + #if defined(_WIN32) && !defined(UNDER_CE) + if (NName::IsDriveRootPath_SuperAllowed(dirPrefix)) + { + if (path != fs2us(dirPrefix)) + name = dirPrefix[dirPrefix.Len() - 3]; // only letter + } + else + #endif + { + dirPrefix.DeleteBack(); + if (!dirPrefix.IsEmpty()) + { + const int slash = dirPrefix.ReverseFind_PathSepar(); + if (slash >= 0 && slash != (int)dirPrefix.Len() - 1) + name = dirPrefix.Ptr(slash + 1); + else if (fi3.Find(dirPrefix)) + name = fs2us(fi3.Name); + } + } + } + } + } + } + + if (fi) + { + name = fs2us(fi->Name); + if (!fi->IsDir() && !keepName) + { + const int dotPos = name.Find(L'.'); + if (dotPos > 0 && name.Find(L'.', (unsigned)dotPos + 1) < 0) + name.DeleteFrom((unsigned)dotPos); + } + } + name = Get_Correct_FsFile_Name(name); + + CRecordVector ids; + bool simple_IsAllowed = true; + // for (int y = 0; y < 10000; y++) // for debug + { + // ids.Clear(); + UString n; + + FOR_VECTOR (i, paths) + { + const UString &a = paths[i]; + const int slash = a.ReverseFind_PathSepar(); + // if (name.Len() >= a.Len() - slash + 1) continue; + const wchar_t *s = a.Ptr(slash + 1); + if (!IsPath1PrefixedByPath2(s, name)) + continue; + s += name.Len(); + const char *exts = isHash ? g_HashExts : g_ArcExts; + + for (;;) + { + const char *ext = exts; + const unsigned len = MyStringLen(ext); + if (len == 0) + break; + exts += len + 1; + n = s; + if (n.Len() <= len) + continue; + if (!StringsAreEqualNoCase_Ascii(n.RightPtr(len), ext)) + continue; + n.DeleteFrom(n.Len() - len); + if (n.Back() != '.') + continue; + n.DeleteBack(); + if (n.IsEmpty()) + { + simple_IsAllowed = false; + break; + } + if (n.Len() < 2) + continue; + if (n[0] != '_') + continue; + const wchar_t *end; + const UInt32 v = ConvertStringToUInt32(n.Ptr(1), &end); + if (*end != 0) + continue; + ids.Add(v); + break; + } + } + } + + baseName = name; + if (!simple_IsAllowed) + { + HeapSort(ids.NonConstData(), ids.Size()); + UInt32 v = 2; + const unsigned num = ids.Size(); + for (unsigned i = 0; i < num; i++) + { + const UInt32 id = ids[i]; + if (id > v) + break; + if (id == v) + v = id + 1; + } + name.Add_Char('_'); + name.Add_UInt32(v); + } + return name; +} diff --git a/CPP/7zip/UI/Common/ArchiveName.h b/CPP/7zip/UI/Common/ArchiveName.h index e9205931c..9b6b7fe9d 100644 --- a/CPP/7zip/UI/Common/ArchiveName.h +++ b/CPP/7zip/UI/Common/ArchiveName.h @@ -1,16 +1,16 @@ -// ArchiveName.h - -#ifndef ZIP7_INC_ARCHIVE_NAME_H -#define ZIP7_INC_ARCHIVE_NAME_H - -#include "../../../Windows/FileFind.h" - -/* (fi != NULL) only if (paths.Size() == 1) */ - -UString CreateArchiveName( - const UStringVector &paths, - bool isHash, - const NWindows::NFile::NFind::CFileInfo *fi, - UString &baseName); - -#endif +// ArchiveName.h + +#ifndef ZIP7_INC_ARCHIVE_NAME_H +#define ZIP7_INC_ARCHIVE_NAME_H + +#include "../../../Windows/FileFind.h" + +/* (fi != NULL) only if (paths.Size() == 1) */ + +UString CreateArchiveName( + const UStringVector &paths, + bool isHash, + const NWindows::NFile::NFind::CFileInfo *fi, + UString &baseName); + +#endif diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp index 882a58b67..8a7293690 100644 --- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -1,398 +1,398 @@ -// ArchiveOpenCallback.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/System.h" - -#include "../../Common/StreamUtils.h" - -#include "ArchiveOpenCallback.h" - -// #define DEBUG_VOLUMES - -#ifdef DEBUG_VOLUMES -#include -#endif - - -#ifdef DEBUG_VOLUMES - #define PRF(x) x -#else - #define PRF(x) -#endif - -using namespace NWindows; - -HRESULT COpenCallbackImp::Init2(const FString &folderPrefix, const FString &fileName) -{ - Volumes.Init(); - FileNames.Clear(); - FileNames_WasUsed.Clear(); - FileSizes.Clear(); - _subArchiveMode = false; - // TotalSize = 0; - PasswordWasAsked = false; - _folderPrefix = folderPrefix; - if (!_fileInfo.Find_FollowLink(_folderPrefix + fileName)) - { - // throw 20121118; - return GetLastError_noZero_HRESULT(); - } - return S_OK; -} - -Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName(const wchar_t *name)) -{ - _subArchiveMode = true; - _subArchiveName = name; - // TotalSize = 0; - return S_OK; -} - -Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)) -{ - COM_TRY_BEGIN - if (ReOpenCallback) - return ReOpenCallback->SetTotal(files, bytes); - if (!Callback) - return S_OK; - return Callback->Open_SetTotal(files, bytes); - COM_TRY_END -} - -Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)) -{ - COM_TRY_BEGIN - if (ReOpenCallback) - return ReOpenCallback->SetCompleted(files, bytes); - if (!Callback) - return S_OK; - return Callback->Open_SetCompleted(files, bytes); - COM_TRY_END -} - - -Z7_COM7F_IMF(COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - if (_subArchiveMode) - switch (propID) - { - case kpidName: prop = _subArchiveName; break; - // case kpidSize: prop = _subArchiveSize; break; // we don't use it now - default: break; - } - else - switch (propID) - { - case kpidName: prop = fs2us(_fileInfo.Name); break; - case kpidIsDir: prop = _fileInfo.IsDir(); break; - case kpidSize: prop = _fileInfo.Size; break; - case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break; - case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break; - case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break; - case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break; - case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break; - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -// ---------- CInFileStreamVol ---------- - -Z7_class_final(CInFileStreamVol): - public IInStream - , public IStreamGetSize - , public CMyUnknownImp -{ - Z7_IFACES_IMP_UNK_3( - IInStream, - ISequentialInStream, - IStreamGetSize) -public: - unsigned FileIndex; - COpenCallbackImp *OpenCallbackImp; - CMyComPtr OpenCallbackRef; - - HRESULT EnsureOpen() - { - return OpenCallbackImp->Volumes.EnsureOpen(FileIndex); - } - - ~CInFileStreamVol() - { - if (OpenCallbackRef) - OpenCallbackImp->AtCloseFile(FileIndex); - } -}; - - -void CMultiStreams::InsertToList(unsigned index) -{ - { - CSubStream &s = Streams[index]; - s.Next = Head; - s.Prev = -1; - } - if (Head != -1) - Streams[(unsigned)Head].Prev = (int)index; - else - { - // if (Tail != -1) throw 1; - Tail = (int)index; - } - Head = (int)index; - NumListItems++; -} - -// s must bee in List -void CMultiStreams::RemoveFromList(CSubStream &s) -{ - if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev; - if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next; - s.Next = -1; // optional - s.Prev = -1; // optional - NumListItems--; -} - -void CMultiStreams::CloseFile(unsigned index) -{ - CSubStream &s = Streams[index]; - if (s.Stream) - { - s.Stream.Release(); - RemoveFromList(s); - // s.InFile->Close(); - // s.IsOpen = false; - #ifdef DEBUG_VOLUMES - static int numClosing = 0; - numClosing++; - printf("\nCloseFile %u, total_closes = %u, num_open_files = %u\n", index, numClosing, NumListItems); - #endif - } -} - -void CMultiStreams::Init() -{ - Head = -1; - Tail = -1; - NumListItems = 0; - Streams.Clear(); -} - -CMultiStreams::CMultiStreams(): - Head(-1), - Tail(-1), - NumListItems(0) -{ - NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); - PRF(printf("\nNumOpenFiles_Limit = %u\n", NumOpenFiles_AllowedMax)); -} - - -HRESULT CMultiStreams::PrepareToOpenNew() -{ - if (NumListItems < NumOpenFiles_AllowedMax) - return S_OK; - if (Tail == -1) - return E_FAIL; - CMultiStreams::CSubStream &tailStream = Streams[(unsigned)Tail]; - RINOK(InStream_GetPos(tailStream.Stream, tailStream.LocalPos)) - CloseFile((unsigned)Tail); - return S_OK; -} - - -HRESULT CMultiStreams::EnsureOpen(unsigned index) -{ - CMultiStreams::CSubStream &s = Streams[index]; - if (s.Stream) - { - if ((int)index != Head) - { - RemoveFromList(s); - InsertToList(index); - } - } - else - { - RINOK(PrepareToOpenNew()) - { - CInFileStream *inFile = new CInFileStream; - CMyComPtr inStreamTemp = inFile; - if (!inFile->Open(s.Path)) - return GetLastError_noZero_HRESULT(); - s.FileSpec = inFile; - s.Stream = s.FileSpec; - InsertToList(index); - } - // s.IsOpen = true; - if (s.LocalPos != 0) - { - RINOK(s.Stream->Seek((Int64)s.LocalPos, STREAM_SEEK_SET, &s.LocalPos)) - } - #ifdef DEBUG_VOLUMES - static int numOpens = 0; - numOpens++; - printf("\n-- %u, ReOpen, total_reopens = %u, num_open_files = %u\n", index, numOpens, NumListItems); - #endif - } - return S_OK; -} - - -Z7_COM7F_IMF(CInFileStreamVol::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - RINOK(EnsureOpen()) - CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; - PRF(printf("\n== %u, Read =%u \n", FileIndex, size)); - return s.Stream->Read(data, size, processedSize); -} - -Z7_COM7F_IMF(CInFileStreamVol::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) -{ - // if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; - RINOK(EnsureOpen()) - CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; - PRF(printf("\n-- %u, Seek seekOrigin=%u Seek =%u\n", FileIndex, seekOrigin, (unsigned)offset)); - return s.Stream->Seek(offset, seekOrigin, newPosition); -} - -Z7_COM7F_IMF(CInFileStreamVol::GetSize(UInt64 *size)) -{ - RINOK(EnsureOpen()) - CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; - return s.FileSpec->GetSize(size); -} - - -// from ArchiveExtractCallback.cpp -bool IsSafePath(const UString &path); - -Z7_COM7F_IMF(COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)) -{ - COM_TRY_BEGIN - *inStream = NULL; - - if (_subArchiveMode) - return S_FALSE; - if (Callback) - { - RINOK(Callback->Open_CheckBreak()) - } - - UString name2 = name; - - - #ifndef Z7_SFX - - #ifdef _WIN32 - name2.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - - // if (!allowAbsVolPaths) - if (!IsSafePath(name2)) - return S_FALSE; - - #ifdef _WIN32 - /* WIN32 allows wildcards in Find() function - and doesn't allow wildcard in File.Open() - so we can work without the following wildcard check here */ - if (name2.Find(L'*') >= 0) - return S_FALSE; - { - unsigned startPos = 0; - if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\")) - startPos = 3; - if (name2.Find(L'?', startPos) >= 0) - return S_FALSE; - } - #endif - - #endif - - - FString fullPath; - if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath)) - return S_FALSE; - if (!_fileInfo.Find_FollowLink(fullPath)) - return S_FALSE; - if (_fileInfo.IsDir()) - return S_FALSE; - - CMultiStreams::CSubStream s; - - { - CInFileStream *inFile = new CInFileStream; - CMyComPtr inStreamTemp = inFile; - if (!inFile->Open(fullPath)) - return GetLastError_noZero_HRESULT(); - RINOK(Volumes.PrepareToOpenNew()) - s.FileSpec = inFile; - s.Stream = s.FileSpec; - s.Path = fullPath; - // s.Size = _fileInfo.Size; - // s.IsOpen = true; - } - - const unsigned fileIndex = Volumes.Streams.Add(s); - Volumes.InsertToList(fileIndex); - - FileSizes.Add(_fileInfo.Size); - FileNames.Add(name2); - FileNames_WasUsed.Add(true); - - CInFileStreamVol *inFile = new CInFileStreamVol; - CMyComPtr inStreamTemp = inFile; - inFile->FileIndex = fileIndex; - inFile->OpenCallbackImp = this; - inFile->OpenCallbackRef = this; - // TotalSize += _fileInfo.Size; - *inStream = inStreamTemp.Detach(); - return S_OK; - COM_TRY_END -} - - -#ifndef Z7_NO_CRYPTO -Z7_COM7F_IMF(COpenCallbackImp::CryptoGetTextPassword(BSTR *password)) -{ - COM_TRY_BEGIN - if (ReOpenCallback) - { - Z7_DECL_CMyComPtr_QI_FROM( - ICryptoGetTextPassword, - getTextPassword, ReOpenCallback) - if (getTextPassword) - return getTextPassword->CryptoGetTextPassword(password); - } - if (!Callback) - return E_NOTIMPL; - PasswordWasAsked = true; - return Callback->Open_CryptoGetTextPassword(password); - COM_TRY_END -} -#endif - -// IProgress -Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */)) -{ - return S_OK; -} +// ArchiveOpenCallback.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/System.h" + +#include "../../Common/StreamUtils.h" + +#include "ArchiveOpenCallback.h" + +// #define DEBUG_VOLUMES + +#ifdef DEBUG_VOLUMES +#include +#endif + + +#ifdef DEBUG_VOLUMES + #define PRF(x) x +#else + #define PRF(x) +#endif + +using namespace NWindows; + +HRESULT COpenCallbackImp::Init2(const FString &folderPrefix, const FString &fileName) +{ + Volumes.Init(); + FileNames.Clear(); + FileNames_WasUsed.Clear(); + FileSizes.Clear(); + _subArchiveMode = false; + // TotalSize = 0; + PasswordWasAsked = false; + _folderPrefix = folderPrefix; + if (!_fileInfo.Find_FollowLink(_folderPrefix + fileName)) + { + // throw 20121118; + return GetLastError_noZero_HRESULT(); + } + return S_OK; +} + +Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName(const wchar_t *name)) +{ + _subArchiveMode = true; + _subArchiveName = name; + // TotalSize = 0; + return S_OK; +} + +Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + return ReOpenCallback->SetTotal(files, bytes); + if (!Callback) + return S_OK; + return Callback->Open_SetTotal(files, bytes); + COM_TRY_END +} + +Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + return ReOpenCallback->SetCompleted(files, bytes); + if (!Callback) + return S_OK; + return Callback->Open_SetCompleted(files, bytes); + COM_TRY_END +} + + +Z7_COM7F_IMF(COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + if (_subArchiveMode) + switch (propID) + { + case kpidName: prop = _subArchiveName; break; + // case kpidSize: prop = _subArchiveSize; break; // we don't use it now + default: break; + } + else + switch (propID) + { + case kpidName: prop = fs2us(_fileInfo.Name); break; + case kpidIsDir: prop = _fileInfo.IsDir(); break; + case kpidSize: prop = _fileInfo.Size; break; + case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break; + case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break; + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +// ---------- CInFileStreamVol ---------- + +Z7_class_final(CInFileStreamVol): + public IInStream + , public IStreamGetSize + , public CMyUnknownImp +{ + Z7_IFACES_IMP_UNK_3( + IInStream, + ISequentialInStream, + IStreamGetSize) +public: + unsigned FileIndex; + COpenCallbackImp *OpenCallbackImp; + CMyComPtr OpenCallbackRef; + + HRESULT EnsureOpen() + { + return OpenCallbackImp->Volumes.EnsureOpen(FileIndex); + } + + ~CInFileStreamVol() + { + if (OpenCallbackRef) + OpenCallbackImp->AtCloseFile(FileIndex); + } +}; + + +void CMultiStreams::InsertToList(unsigned index) +{ + { + CSubStream &s = Streams[index]; + s.Next = Head; + s.Prev = -1; + } + if (Head != -1) + Streams[(unsigned)Head].Prev = (int)index; + else + { + // if (Tail != -1) throw 1; + Tail = (int)index; + } + Head = (int)index; + NumListItems++; +} + +// s must bee in List +void CMultiStreams::RemoveFromList(CSubStream &s) +{ + if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev; + if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next; + s.Next = -1; // optional + s.Prev = -1; // optional + NumListItems--; +} + +void CMultiStreams::CloseFile(unsigned index) +{ + CSubStream &s = Streams[index]; + if (s.Stream) + { + s.Stream.Release(); + RemoveFromList(s); + // s.InFile->Close(); + // s.IsOpen = false; + #ifdef DEBUG_VOLUMES + static int numClosing = 0; + numClosing++; + printf("\nCloseFile %u, total_closes = %u, num_open_files = %u\n", index, numClosing, NumListItems); + #endif + } +} + +void CMultiStreams::Init() +{ + Head = -1; + Tail = -1; + NumListItems = 0; + Streams.Clear(); +} + +CMultiStreams::CMultiStreams(): + Head(-1), + Tail(-1), + NumListItems(0) +{ + NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); + PRF(printf("\nNumOpenFiles_Limit = %u\n", NumOpenFiles_AllowedMax)); +} + + +HRESULT CMultiStreams::PrepareToOpenNew() +{ + if (NumListItems < NumOpenFiles_AllowedMax) + return S_OK; + if (Tail == -1) + return E_FAIL; + CMultiStreams::CSubStream &tailStream = Streams[(unsigned)Tail]; + RINOK(InStream_GetPos(tailStream.Stream, tailStream.LocalPos)) + CloseFile((unsigned)Tail); + return S_OK; +} + + +HRESULT CMultiStreams::EnsureOpen(unsigned index) +{ + CMultiStreams::CSubStream &s = Streams[index]; + if (s.Stream) + { + if ((int)index != Head) + { + RemoveFromList(s); + InsertToList(index); + } + } + else + { + RINOK(PrepareToOpenNew()) + { + CInFileStream *inFile = new CInFileStream; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(s.Path)) + return GetLastError_noZero_HRESULT(); + s.FileSpec = inFile; + s.Stream = s.FileSpec; + InsertToList(index); + } + // s.IsOpen = true; + if (s.LocalPos != 0) + { + RINOK(s.Stream->Seek((Int64)s.LocalPos, STREAM_SEEK_SET, &s.LocalPos)) + } + #ifdef DEBUG_VOLUMES + static int numOpens = 0; + numOpens++; + printf("\n-- %u, ReOpen, total_reopens = %u, num_open_files = %u\n", index, numOpens, NumListItems); + #endif + } + return S_OK; +} + + +Z7_COM7F_IMF(CInFileStreamVol::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + RINOK(EnsureOpen()) + CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; + PRF(printf("\n== %u, Read =%u \n", FileIndex, size)); + return s.Stream->Read(data, size, processedSize); +} + +Z7_COM7F_IMF(CInFileStreamVol::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +{ + // if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; + RINOK(EnsureOpen()) + CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; + PRF(printf("\n-- %u, Seek seekOrigin=%u Seek =%u\n", FileIndex, seekOrigin, (unsigned)offset)); + return s.Stream->Seek(offset, seekOrigin, newPosition); +} + +Z7_COM7F_IMF(CInFileStreamVol::GetSize(UInt64 *size)) +{ + RINOK(EnsureOpen()) + CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex]; + return s.FileSpec->GetSize(size); +} + + +// from ArchiveExtractCallback.cpp +bool IsSafePath(const UString &path); + +Z7_COM7F_IMF(COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)) +{ + COM_TRY_BEGIN + *inStream = NULL; + + if (_subArchiveMode) + return S_FALSE; + if (Callback) + { + RINOK(Callback->Open_CheckBreak()) + } + + UString name2 = name; + + + #ifndef Z7_SFX + + #ifdef _WIN32 + name2.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + + // if (!allowAbsVolPaths) + if (!IsSafePath(name2)) + return S_FALSE; + + #ifdef _WIN32 + /* WIN32 allows wildcards in Find() function + and doesn't allow wildcard in File.Open() + so we can work without the following wildcard check here */ + if (name2.Find(L'*') >= 0) + return S_FALSE; + { + unsigned startPos = 0; + if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\")) + startPos = 3; + if (name2.Find(L'?', startPos) >= 0) + return S_FALSE; + } + #endif + + #endif + + + FString fullPath; + if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath)) + return S_FALSE; + if (!_fileInfo.Find_FollowLink(fullPath)) + return S_FALSE; + if (_fileInfo.IsDir()) + return S_FALSE; + + CMultiStreams::CSubStream s; + + { + CInFileStream *inFile = new CInFileStream; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return GetLastError_noZero_HRESULT(); + RINOK(Volumes.PrepareToOpenNew()) + s.FileSpec = inFile; + s.Stream = s.FileSpec; + s.Path = fullPath; + // s.Size = _fileInfo.Size; + // s.IsOpen = true; + } + + const unsigned fileIndex = Volumes.Streams.Add(s); + Volumes.InsertToList(fileIndex); + + FileSizes.Add(_fileInfo.Size); + FileNames.Add(name2); + FileNames_WasUsed.Add(true); + + CInFileStreamVol *inFile = new CInFileStreamVol; + CMyComPtr inStreamTemp = inFile; + inFile->FileIndex = fileIndex; + inFile->OpenCallbackImp = this; + inFile->OpenCallbackRef = this; + // TotalSize += _fileInfo.Size; + *inStream = inStreamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + +#ifndef Z7_NO_CRYPTO +Z7_COM7F_IMF(COpenCallbackImp::CryptoGetTextPassword(BSTR *password)) +{ + COM_TRY_BEGIN + if (ReOpenCallback) + { + Z7_DECL_CMyComPtr_QI_FROM( + ICryptoGetTextPassword, + getTextPassword, ReOpenCallback) + if (getTextPassword) + return getTextPassword->CryptoGetTextPassword(password); + } + if (!Callback) + return E_NOTIMPL; + PasswordWasAsked = true; + return Callback->Open_CryptoGetTextPassword(password); + COM_TRY_END +} +#endif + +// IProgress +Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */)) +{ + return S_OK; +} diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/CPP/7zip/UI/Common/ArchiveOpenCallback.h index b589c4268..a7b8b7613 100644 --- a/CPP/7zip/UI/Common/ArchiveOpenCallback.h +++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.h @@ -1,182 +1,182 @@ -// ArchiveOpenCallback.h - -#ifndef ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H -#define ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/FileFind.h" - -#include "../../Common/FileStreams.h" - -#ifndef Z7_NO_CRYPTO -#include "../../IPassword.h" -#endif -#include "../../Archive/IArchive.h" - -Z7_PURE_INTERFACES_BEGIN - -#ifdef Z7_NO_CRYPTO - -#define Z7_IFACEM_IOpenCallbackUI_Crypto(x) - -#else - -#define Z7_IFACEM_IOpenCallbackUI_Crypto(x) \ - virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x \ - /* virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x */ \ - /* virtual bool Open_WasPasswordAsked() x */ \ - /* virtual void Open_Clear_PasswordWasAsked_Flag() x */ \ - -#endif - -#define Z7_IFACEN_IOpenCallbackUI(x) \ - virtual HRESULT Open_CheckBreak() x \ - virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x \ - virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x \ - virtual HRESULT Open_Finished() x \ - Z7_IFACEM_IOpenCallbackUI_Crypto(x) - -Z7_IFACE_DECL_PURE(IOpenCallbackUI) - -Z7_PURE_INTERFACES_END - - -class CMultiStreams Z7_final -{ -public: - struct CSubStream - { - CMyComPtr Stream; - CInFileStream *FileSpec; - FString Path; - // UInt64 Size; - UInt64 LocalPos; - int Next; // next older - int Prev; // prev newer - // bool IsOpen; - - CSubStream(): - FileSpec(NULL), - // Size(0), - LocalPos(0), - Next(-1), - Prev(-1) - // IsOpen(false) - {} - }; - - CObjectVector Streams; -private: - // we must use critical section here, if we want to access from different volumnes simultaneously - int Head; // newest - int Tail; // oldest - unsigned NumListItems; - unsigned NumOpenFiles_AllowedMax; -public: - - CMultiStreams(); - void Init(); - HRESULT PrepareToOpenNew(); - void InsertToList(unsigned index); - void RemoveFromList(CSubStream &s); - void CloseFile(unsigned index); - HRESULT EnsureOpen(unsigned index); -}; - - -/* - We need COpenCallbackImp class for multivolume processing. - Also we use it as proxy from COM interfaces (IArchiveOpenCallback) to internal (IOpenCallbackUI) interfaces. - If archive is multivolume: - COpenCallbackImp object will exist after Open stage. - COpenCallbackImp object will be deleted when last reference - from each volume object (CInFileStreamVol) will be closed (when archive will be closed). -*/ - -class COpenCallbackImp Z7_final: - public IArchiveOpenCallback, - public IArchiveOpenVolumeCallback, - public IArchiveOpenSetSubArchiveName, - #ifndef Z7_NO_CRYPTO - public ICryptoGetTextPassword, - #endif - public IProgress, // IProgress is used for 7zFM - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IArchiveOpenCallback) - Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback) - Z7_COM_QI_ENTRY(IArchiveOpenSetSubArchiveName) - #ifndef Z7_NO_CRYPTO - Z7_COM_QI_ENTRY(ICryptoGetTextPassword) - #endif - // Z7_COM_QI_ENTRY(IProgress) // the code doesn't require it - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IArchiveOpenCallback) - Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback) - Z7_IFACE_COM7_IMP(IProgress) -public: - Z7_IFACE_COM7_IMP(IArchiveOpenSetSubArchiveName) -private: - #ifndef Z7_NO_CRYPTO - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - #endif - - bool _subArchiveMode; - -public: - bool PasswordWasAsked; - UStringVector FileNames; - CBoolVector FileNames_WasUsed; - CRecordVector FileSizes; - - void AtCloseFile(unsigned fileIndex) - { - FileNames_WasUsed[fileIndex] = false; - Volumes.CloseFile(fileIndex); - } - - /* we have two ways to Callback from this object - 1) IArchiveOpenCallback * ReOpenCallback - for ReOpen function, when IOpenCallbackUI is not available - 2) IOpenCallbackUI *Callback - for usual callback - we can't transfer IOpenCallbackUI pointer via internal interface, - so we use ReOpenCallback to callback without IOpenCallbackUI. - */ - - /* we use Callback/ReOpenCallback only at Open stage. - So the CMyComPtr reference counter is not required, - and we don't want additional reference to unused object, - if COpenCallbackImp is not closed - */ - IArchiveOpenCallback *ReOpenCallback; - // CMyComPtr ReOpenCallback; - IOpenCallbackUI *Callback; - // CMyComPtr Callback_Ref; - -private: - FString _folderPrefix; - UString _subArchiveName; - NWindows::NFile::NFind::CFileInfo _fileInfo; - -public: - CMultiStreams Volumes; - - // UInt64 TotalSize; - - COpenCallbackImp(): - _subArchiveMode(false), - PasswordWasAsked(false), - ReOpenCallback(NULL), - Callback(NULL) {} - - HRESULT Init2(const FString &folderPrefix, const FString &fileName); - - bool SetSecondFileInfo(CFSTR newName) - { - return _fileInfo.Find_FollowLink(newName) && !_fileInfo.IsDir(); - } -}; - -#endif +// ArchiveOpenCallback.h + +#ifndef ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H +#define ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/FileFind.h" + +#include "../../Common/FileStreams.h" + +#ifndef Z7_NO_CRYPTO +#include "../../IPassword.h" +#endif +#include "../../Archive/IArchive.h" + +Z7_PURE_INTERFACES_BEGIN + +#ifdef Z7_NO_CRYPTO + +#define Z7_IFACEM_IOpenCallbackUI_Crypto(x) + +#else + +#define Z7_IFACEM_IOpenCallbackUI_Crypto(x) \ + virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x \ + /* virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x */ \ + /* virtual bool Open_WasPasswordAsked() x */ \ + /* virtual void Open_Clear_PasswordWasAsked_Flag() x */ \ + +#endif + +#define Z7_IFACEN_IOpenCallbackUI(x) \ + virtual HRESULT Open_CheckBreak() x \ + virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x \ + virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x \ + virtual HRESULT Open_Finished() x \ + Z7_IFACEM_IOpenCallbackUI_Crypto(x) + +Z7_IFACE_DECL_PURE(IOpenCallbackUI) + +Z7_PURE_INTERFACES_END + + +class CMultiStreams Z7_final +{ +public: + struct CSubStream + { + CMyComPtr Stream; + CInFileStream *FileSpec; + FString Path; + // UInt64 Size; + UInt64 LocalPos; + int Next; // next older + int Prev; // prev newer + // bool IsOpen; + + CSubStream(): + FileSpec(NULL), + // Size(0), + LocalPos(0), + Next(-1), + Prev(-1) + // IsOpen(false) + {} + }; + + CObjectVector Streams; +private: + // we must use critical section here, if we want to access from different volumnes simultaneously + int Head; // newest + int Tail; // oldest + unsigned NumListItems; + unsigned NumOpenFiles_AllowedMax; +public: + + CMultiStreams(); + void Init(); + HRESULT PrepareToOpenNew(); + void InsertToList(unsigned index); + void RemoveFromList(CSubStream &s); + void CloseFile(unsigned index); + HRESULT EnsureOpen(unsigned index); +}; + + +/* + We need COpenCallbackImp class for multivolume processing. + Also we use it as proxy from COM interfaces (IArchiveOpenCallback) to internal (IOpenCallbackUI) interfaces. + If archive is multivolume: + COpenCallbackImp object will exist after Open stage. + COpenCallbackImp object will be deleted when last reference + from each volume object (CInFileStreamVol) will be closed (when archive will be closed). +*/ + +class COpenCallbackImp Z7_final: + public IArchiveOpenCallback, + public IArchiveOpenVolumeCallback, + public IArchiveOpenSetSubArchiveName, + #ifndef Z7_NO_CRYPTO + public ICryptoGetTextPassword, + #endif + public IProgress, // IProgress is used for 7zFM + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IArchiveOpenCallback) + Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback) + Z7_COM_QI_ENTRY(IArchiveOpenSetSubArchiveName) + #ifndef Z7_NO_CRYPTO + Z7_COM_QI_ENTRY(ICryptoGetTextPassword) + #endif + // Z7_COM_QI_ENTRY(IProgress) // the code doesn't require it + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IArchiveOpenCallback) + Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback) + Z7_IFACE_COM7_IMP(IProgress) +public: + Z7_IFACE_COM7_IMP(IArchiveOpenSetSubArchiveName) +private: + #ifndef Z7_NO_CRYPTO + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + #endif + + bool _subArchiveMode; + +public: + bool PasswordWasAsked; + UStringVector FileNames; + CBoolVector FileNames_WasUsed; + CRecordVector FileSizes; + + void AtCloseFile(unsigned fileIndex) + { + FileNames_WasUsed[fileIndex] = false; + Volumes.CloseFile(fileIndex); + } + + /* we have two ways to Callback from this object + 1) IArchiveOpenCallback * ReOpenCallback - for ReOpen function, when IOpenCallbackUI is not available + 2) IOpenCallbackUI *Callback - for usual callback + we can't transfer IOpenCallbackUI pointer via internal interface, + so we use ReOpenCallback to callback without IOpenCallbackUI. + */ + + /* we use Callback/ReOpenCallback only at Open stage. + So the CMyComPtr reference counter is not required, + and we don't want additional reference to unused object, + if COpenCallbackImp is not closed + */ + IArchiveOpenCallback *ReOpenCallback; + // CMyComPtr ReOpenCallback; + IOpenCallbackUI *Callback; + // CMyComPtr Callback_Ref; + +private: + FString _folderPrefix; + UString _subArchiveName; + NWindows::NFile::NFind::CFileInfo _fileInfo; + +public: + CMultiStreams Volumes; + + // UInt64 TotalSize; + + COpenCallbackImp(): + _subArchiveMode(false), + PasswordWasAsked(false), + ReOpenCallback(NULL), + Callback(NULL) {} + + HRESULT Init2(const FString &folderPrefix, const FString &fileName); + + bool SetSecondFileInfo(CFSTR newName) + { + return _fileInfo.Find_FollowLink(newName) && !_fileInfo.IsDir(); + } +}; + +#endif diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index 3ea745e08..05d66aa91 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp @@ -1,4941 +1,4971 @@ -// Bench.cpp - -#include "StdAfx.h" - -// #include - -#ifndef _WIN32 -#define USE_POSIX_TIME -#define USE_POSIX_TIME2 -#endif // _WIN32 - -#ifdef USE_POSIX_TIME -#include -#include -#ifdef USE_POSIX_TIME2 -#include -#include -#endif -#endif // USE_POSIX_TIME - -#ifdef _WIN32 -#define USE_ALLOCA -#endif - -#ifdef USE_ALLOCA -#ifdef _WIN32 -#include -#else -#include -#endif -#define BENCH_ALLOCA_VALUE(index) (((index) * 64 * 21) & 0x7FF) -#endif - -#include "../../../../C/7zCrc.h" -#include "../../../../C/RotateDefs.h" -#include "../../../../C/CpuArch.h" - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#include "../../../Windows/Thread.h" -#endif - -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/SystemInfo.h" - -#include "../../../Common/MyBuffer2.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/Wildcard.h" - -#include "../../Common/MethodProps.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "Bench.h" - -using namespace NWindows; - -#ifndef Z7_ST -static const UInt32 k_LZMA = 0x030101; -#endif - -static const UInt64 kComplexInCommands = (UInt64)1 << - #ifdef UNDER_CE - 31; - #else - 34; - #endif - -static const UInt32 kComplexInMs = 4000; - -static void SetComplexCommandsMs(UInt32 complexInMs, - bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands) -{ - complexInCommands = kComplexInCommands; - const UInt64 kMinFreq = (UInt64)1000000 * 4; - const UInt64 kMaxFreq = (UInt64)1000000 * 20000; - if (cpuFreq < kMinFreq && !isSpecifiedFreq) - cpuFreq = kMinFreq; - if (cpuFreq < kMaxFreq || isSpecifiedFreq) - { - if (complexInMs != 0) - complexInCommands = complexInMs * cpuFreq / 1000; - else - complexInCommands = cpuFreq >> 2; - } -} - -// const UInt64 kBenchmarkUsageMult = 1000000; // for debug -static const unsigned kBenchmarkUsageMultBits = 16; -static const UInt64 kBenchmarkUsageMult = 1 << kBenchmarkUsageMultBits; - -UInt64 Benchmark_GetUsage_Percents(UInt64 usage) -{ - return (100 * usage + kBenchmarkUsageMult / 2) / kBenchmarkUsageMult; -} - -static const unsigned kNumHashDictBits = 17; -static const UInt32 kFilterUnpackSize = (47 << 10); // + 5; // for test - -static const unsigned kOldLzmaDictBits = 32; - -// static const size_t kAdditionalSize = (size_t)1 << 32; // for debug -static const size_t kAdditionalSize = (size_t)1 << 16; -static const size_t kCompressedAdditionalSize = 1 << 10; - -static const UInt32 kMaxMethodPropSize = 1 << 6; - - -#define ALLOC_WITH_HRESULT(_buffer_, _size_) \ - { (_buffer_)->Alloc(_size_); \ - if (_size_ && !(_buffer_)->IsAllocated()) return E_OUTOFMEMORY; } - - -class CBaseRandomGenerator -{ - UInt32 A1; - UInt32 A2; - UInt32 Salt; -public: - CBaseRandomGenerator(UInt32 salt = 0): Salt(salt) { Init(); } - void Init() { A1 = 362436069; A2 = 521288629;} - Z7_FORCE_INLINE - UInt32 GetRnd() - { -#if 0 - // for debug: - return 0x0c080400; - // return 0; -#else - return Salt ^ - ( - ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) + - ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ) - ); -#endif - } -}; - - -static const size_t k_RandBuf_AlignMask = 4 - 1; - -Z7_NO_INLINE -static void RandGen_BufAfterPad(Byte *buf, size_t size) -{ - CBaseRandomGenerator RG; - for (size_t i = 0; i < size; i += 4) - { - const UInt32 v = RG.GetRnd(); - SetUi32a(buf + i, v) - } - /* - UInt32 v = RG.GetRnd(); - for (; i < size; i++) - { - buf[i] = (Byte)v; - v >>= 8; - } - */ -} - - -class CBenchRandomGenerator: public CMidAlignedBuffer -{ - static UInt32 GetVal(UInt32 &res, unsigned numBits) - { - const UInt32 val = res & (((UInt32)1 << numBits) - 1); - res >>= numBits; - return val; - } - - static UInt32 GetLen(UInt32 &r) - { - const unsigned len = (unsigned)GetVal(r, 2); - return GetVal(r, 1 + len); - } - -public: - - void GenerateSimpleRandom(UInt32 salt) - { - CBaseRandomGenerator rg(salt); - const size_t bufSize = Size(); - Byte *buf = (Byte *)*this; - for (size_t i = 0; i < bufSize; i++) - buf[i] = (Byte)rg.GetRnd(); - } - - void GenerateLz(unsigned dictBits, UInt32 salt) - { - CBaseRandomGenerator rg(salt); - size_t pos = 0; - size_t rep0 = 1; - const size_t bufSize = Size(); - Byte *buf = (Byte *)*this; - unsigned posBits = 1; - - // printf("\n dictBits = %d\n", (UInt32)dictBits); - // printf("\n bufSize = 0x%p\n", (const void *)bufSize); - - while (pos < bufSize) - { - /* - if (pos >= ((UInt32)1 << 31)) - printf(" %x\n", pos); - */ - UInt32 r = rg.GetRnd(); - if (GetVal(r, 1) == 0 || pos < 1024) - buf[pos++] = (Byte)(r & 0xFF); - else - { - UInt32 len; - len = 1 + GetLen(r); - - if (GetVal(r, 3) != 0) - { - len += GetLen(r); - - while (((size_t)1 << posBits) < pos) - posBits++; - - unsigned numBitsMax = dictBits; - if (numBitsMax > posBits) - numBitsMax = posBits; - - const unsigned kAddBits = 6; - unsigned numLogBits = 5; - if (numBitsMax <= (1 << 4) - 1 + kAddBits) - numLogBits = 4; - - for (;;) - { - const UInt32 ppp = GetVal(r, numLogBits) + kAddBits; - r = rg.GetRnd(); - if (ppp > numBitsMax) - continue; - // rep0 = GetVal(r, ppp); - rep0 = r & (((size_t)1 << ppp) - 1); - if (rep0 < pos) - break; - r = rg.GetRnd(); - } - rep0++; - } - - // len *= 300; // for debug - { - const size_t rem = bufSize - pos; - if (len > rem) - len = (UInt32)rem; - } - Byte *dest = buf + pos; - const Byte *src = dest - rep0; - pos += len; - for (UInt32 i = 0; i < len; i++) - *dest++ = *src++; - } - } - // printf("\n CRC = %x\n", CrcCalc(buf, bufSize)); - } -}; - - -Z7_CLASS_IMP_NOQIB_1( - CBenchmarkInStream - , ISequentialInStream -) - const Byte *Data; - size_t Pos; - size_t Size; -public: - void Init(const Byte *data, size_t size) - { - Data = data; - Size = size; - Pos = 0; - } - bool WasFinished() const { return Pos == Size; } -}; - -Z7_COM7F_IMF(CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) -{ - const UInt32 kMaxBlockSize = (1 << 20); - if (size > kMaxBlockSize) - size = kMaxBlockSize; - const size_t remain = Size - Pos; - if (size > remain) - size = (UInt32)remain; - - if (size) - memcpy(data, Data + Pos, size); - - Pos += size; - if (processedSize) - *processedSize = size; - return S_OK; -} - - -class CBenchmarkOutStream Z7_final: - public ISequentialOutStream, - public CMyUnknownImp, - public CMidAlignedBuffer -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(ISequentialOutStream) - // bool _overflow; -public: - size_t Pos; - bool RealCopy; - bool CalcCrc; - UInt32 Crc; - - // CBenchmarkOutStream(): _overflow(false) {} - void Init(bool realCopy, bool calcCrc) - { - Crc = CRC_INIT_VAL; - RealCopy = realCopy; - CalcCrc = calcCrc; - // _overflow = false; - Pos = 0; - } - - void InitCrc() - { - Crc = CRC_INIT_VAL; - } - - void Calc(const void *data, size_t size) - { - Crc = CrcUpdate(Crc, data, size); - } - - size_t GetPos() const { return Pos; } - - // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); } -}; - -Z7_COM7F_IMF(CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - size_t curSize = Size() - Pos; - if (curSize > size) - curSize = size; - if (curSize != 0) - { - if (RealCopy) - memcpy(((Byte *)*this) + Pos, data, curSize); - if (CalcCrc) - Calc(data, curSize); - Pos += curSize; - } - if (processedSize) - *processedSize = (UInt32)curSize; - if (curSize != size) - { - // _overflow = true; - return E_FAIL; - } - return S_OK; -} - - -Z7_CLASS_IMP_NOQIB_1( - CCrcOutStream - , ISequentialOutStream -) -public: - bool CalcCrc; - UInt32 Crc; - UInt64 Pos; - - CCrcOutStream(): CalcCrc(true) {} - void Init() { Crc = CRC_INIT_VAL; Pos = 0; } - void Calc(const void *data, size_t size) - { - Crc = CrcUpdate(Crc, data, size); - } -}; - -Z7_COM7F_IMF(CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (CalcCrc) - Calc(data, size); - Pos += size; - if (processedSize) - *processedSize = size; - return S_OK; -} - -// #include "../../../../C/My_sys_time.h" - -static UInt64 GetTimeCount() -{ - #ifdef USE_POSIX_TIME - #ifdef USE_POSIX_TIME2 - timeval v; - if (gettimeofday(&v, NULL) == 0) - return (UInt64)(v.tv_sec) * 1000000 + (UInt64)v.tv_usec; - return (UInt64)time(NULL) * 1000000; - #else - return time(NULL); - #endif - #else - LARGE_INTEGER value; - if (::QueryPerformanceCounter(&value)) - return (UInt64)value.QuadPart; - return GetTickCount(); - #endif -} - -static UInt64 GetFreq() -{ - #ifdef USE_POSIX_TIME - #ifdef USE_POSIX_TIME2 - return 1000000; - #else - return 1; - #endif - #else - LARGE_INTEGER value; - if (::QueryPerformanceFrequency(&value)) - return (UInt64)value.QuadPart; - return 1000; - #endif -} - - -#ifdef USE_POSIX_TIME - -struct CUserTime -{ - UInt64 Sum; - clock_t Prev; - - void Init() - { - // Prev = clock(); - Sum = 0; - Prev = 0; - Update(); - Sum = 0; - } - - void Update() - { - tms t; - /* clock_t res = */ times(&t); - clock_t newVal = t.tms_utime + t.tms_stime; - Sum += (UInt64)(newVal - Prev); - Prev = newVal; - - /* - clock_t v = clock(); - if (v != -1) - { - Sum += v - Prev; - Prev = v; - } - */ - } - UInt64 GetUserTime() - { - Update(); - return Sum; - } -}; - -#else - - -struct CUserTime -{ - bool UseTick; - DWORD Prev_Tick; - UInt64 Prev; - UInt64 Sum; - - void Init() - { - UseTick = false; - Prev_Tick = 0; - Prev = 0; - Sum = 0; - Update(); - Sum = 0; - } - UInt64 GetUserTime() - { - Update(); - return Sum; - } - void Update(); -}; - -static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } - -void CUserTime::Update() -{ - DWORD new_Tick = GetTickCount(); - FILETIME creationTime, exitTime, kernelTime, userTime; - if (!UseTick && - #ifdef UNDER_CE - ::GetThreadTimes(::GetCurrentThread() - #else - ::GetProcessTimes(::GetCurrentProcess() - #endif - , &creationTime, &exitTime, &kernelTime, &userTime)) - { - UInt64 newVal = GetTime64(userTime) + GetTime64(kernelTime); - Sum += newVal - Prev; - Prev = newVal; - } - else - { - UseTick = true; - Sum += (UInt64)(new_Tick - (DWORD)Prev_Tick) * 10000; - } - Prev_Tick = new_Tick; -} - - -#endif - -static UInt64 GetUserFreq() -{ - #ifdef USE_POSIX_TIME - // return CLOCKS_PER_SEC; - return (UInt64)sysconf(_SC_CLK_TCK); - #else - return 10000000; - #endif -} - -class CBenchProgressStatus Z7_final -{ - #ifndef Z7_ST - NSynchronization::CCriticalSection CS; - #endif -public: - HRESULT Res; - bool EncodeMode; - void SetResult(HRESULT res) - { - #ifndef Z7_ST - NSynchronization::CCriticalSectionLock lock(CS); - #endif - Res = res; - } - HRESULT GetResult() - { - #ifndef Z7_ST - NSynchronization::CCriticalSectionLock lock(CS); - #endif - return Res; - } -}; - -struct CBenchInfoCalc -{ - CBenchInfo BenchInfo; - CUserTime UserTime; - - void SetStartTime(); - void SetFinishTime(CBenchInfo &dest); -}; - -void CBenchInfoCalc::SetStartTime() -{ - BenchInfo.GlobalFreq = GetFreq(); - BenchInfo.UserFreq = GetUserFreq(); - BenchInfo.GlobalTime = ::GetTimeCount(); - BenchInfo.UserTime = 0; - UserTime.Init(); -} - -void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest) -{ - dest = BenchInfo; - dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime; - dest.UserTime = UserTime.GetUserTime(); -} - -class CBenchProgressInfo Z7_final: - public ICompressProgressInfo, - public CMyUnknownImp, - public CBenchInfoCalc -{ - Z7_COM_UNKNOWN_IMP_0 - Z7_IFACE_COM7_IMP(ICompressProgressInfo) -public: - CBenchProgressStatus *Status; - IBenchCallback *Callback; - - CBenchProgressInfo(): Callback(NULL) {} -}; - - -Z7_COM7F_IMF(CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - HRESULT res = Status->GetResult(); - if (res != S_OK) - return res; - if (!Callback) - return res; - - /* - static UInt64 inSizePrev = 0; - static UInt64 outSizePrev = 0; - UInt64 delta1 = 0, delta2 = 0, val1 = 0, val2 = 0; - if (inSize) { val1 = *inSize; delta1 = val1 - inSizePrev; inSizePrev = val1; } - if (outSize) { val2 = *outSize; delta2 = val2 - outSizePrev; outSizePrev = val2; } - UInt64 percents = delta2 * 1000; - if (delta1 != 0) - percents /= delta1; - printf("=== %7d %7d %7d %7d ratio = %4d\n", - (unsigned)(val1 >> 10), (unsigned)(delta1 >> 10), - (unsigned)(val2 >> 10), (unsigned)(delta2 >> 10), - (unsigned)percents); - */ - - CBenchInfo info; - SetFinishTime(info); - if (Status->EncodeMode) - { - info.UnpackSize = BenchInfo.UnpackSize + *inSize; - info.PackSize = BenchInfo.PackSize + *outSize; - res = Callback->SetEncodeResult(info, false); - } - else - { - info.PackSize = BenchInfo.PackSize + *inSize; - info.UnpackSize = BenchInfo.UnpackSize + *outSize; - res = Callback->SetDecodeResult(info, false); - } - if (res != S_OK) - Status->SetResult(res); - return res; -} - -static const unsigned kSubBits = 8; - -static unsigned GetLogSize(UInt64 size) -{ - unsigned i = 0; - for (;;) - { - i++; size >>= 1; if (size == 0) break; - } - return i; -} - - -static UInt32 GetLogSize_Sub(UInt64 size) -{ - if (size <= 1) - return 0; - const unsigned i = GetLogSize(size) - 1; - UInt32 v; - if (i <= kSubBits) - v = (UInt32)(size) << (kSubBits - i); - else - v = (UInt32)(size >> (i - kSubBits)); - return ((UInt32)i << kSubBits) + (v & (((UInt32)1 << kSubBits) - 1)); -} - - -static UInt64 Get_UInt64_from_double(double v) -{ - const UInt64 kMaxVal = (UInt64)1 << 62; - if (v > (double)(Int64)kMaxVal) - return kMaxVal; - return (UInt64)v; -} - -static UInt64 MyMultDiv64(UInt64 m1, UInt64 m2, UInt64 d) -{ - if (d == 0) - d = 1; - const double v = - (double)(Int64)m1 * - (double)(Int64)m2 / - (double)(Int64)d; - return Get_UInt64_from_double(v); - /* - unsigned n1 = GetLogSize(m1); - unsigned n2 = GetLogSize(m2); - while (n1 + n2 > 64) - { - if (n1 >= n2) - { - m1 >>= 1; - n1--; - } - else - { - m2 >>= 1; - n2--; - } - d >>= 1; - } - - if (d == 0) - d = 1; - return m1 * m2 / d; - */ -} - - -UInt64 CBenchInfo::GetUsage() const -{ - UInt64 userTime = UserTime; - UInt64 userFreq = UserFreq; - UInt64 globalTime = GlobalTime; - UInt64 globalFreq = GlobalFreq; - - if (userFreq == 0) - userFreq = 1; - if (globalTime == 0) - globalTime = 1; - - const double v = - ((double)(Int64)userTime / (double)(Int64)userFreq) - * ((double)(Int64)globalFreq / (double)(Int64)globalTime) - * (double)(Int64)kBenchmarkUsageMult; - return Get_UInt64_from_double(v); - /* - return MyMultDiv64( - MyMultDiv64(kBenchmarkUsageMult, userTime, userFreq), - globalFreq, globalTime); - */ -} - - -UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const -{ - if (UserTime == 0) - { - return 0; - // userTime = 1; - } - UInt64 globalFreq = GlobalFreq; - if (globalFreq == 0) - globalFreq = 1; - - const double v = - ((double)(Int64)GlobalTime / (double)(Int64)globalFreq) - * ((double)(Int64)UserFreq / (double)(Int64)UserTime) - * (double)(Int64)rating; - return Get_UInt64_from_double(v); - /* - return MyMultDiv64( - MyMultDiv64(rating, UserFreq, UserTime), - GlobalTime, globalFreq); - */ -} - - -UInt64 CBenchInfo::GetSpeed(UInt64 numUnits) const -{ - return MyMultDiv64(numUnits, GlobalFreq, GlobalTime); -} - -static UInt64 GetNumCommands_from_Size_and_Complexity(UInt64 size, Int32 complexity) -{ - return complexity >= 0 ? - size * (UInt32)complexity : - size / (UInt32)(-complexity); -} - -struct CBenchProps -{ - bool LzmaRatingMode; - - Int32 EncComplex; - Int32 DecComplexCompr; - Int32 DecComplexUnc; - - unsigned KeySize; - - CBenchProps(): - LzmaRatingMode(false), - KeySize(0) - {} - - void SetLzmaCompexity(); - - UInt64 GetNumCommands_Enc(UInt64 unpackSize) const - { - const UInt32 kMinSize = 100; - if (unpackSize < kMinSize) - unpackSize = kMinSize; - return GetNumCommands_from_Size_and_Complexity(unpackSize, EncComplex); - } - - UInt64 GetNumCommands_Dec(UInt64 packSize, UInt64 unpackSize) const - { - return - GetNumCommands_from_Size_and_Complexity(packSize, DecComplexCompr) + - GetNumCommands_from_Size_and_Complexity(unpackSize, DecComplexUnc); - } - - UInt64 GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const; - UInt64 GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const; -}; - -void CBenchProps::SetLzmaCompexity() -{ - EncComplex = 1200; - DecComplexUnc = 4; - DecComplexCompr = 190; - LzmaRatingMode = true; -} - -UInt64 CBenchProps::GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const -{ - if (dictSize < (1 << kBenchMinDicLogSize)) - dictSize = (1 << kBenchMinDicLogSize); - Int32 encComplex = EncComplex; - if (LzmaRatingMode) - { - /* - for (UInt64 uu = 0; uu < (UInt64)0xf << 60;) - { - unsigned rr = GetLogSize_Sub(uu); - printf("\n%16I64x , log = %4x", uu, rr); - uu += 1; - uu += uu / 50; - } - */ - // throw 1; - const UInt32 t = GetLogSize_Sub(dictSize) - (kBenchMinDicLogSize << kSubBits); - encComplex = 870 + ((t * t * 5) >> (2 * kSubBits)); - } - const UInt64 numCommands = GetNumCommands_from_Size_and_Complexity(size, encComplex); - return MyMultDiv64(numCommands, freq, elapsedTime); -} - -UInt64 CBenchProps::GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const -{ - const UInt64 numCommands = GetNumCommands_Dec(inSize, outSize) * numIterations; - return MyMultDiv64(numCommands, freq, elapsedTime); -} - - - -UInt64 CBenchInfo::GetRating_LzmaEnc(UInt64 dictSize) const -{ - CBenchProps props; - props.SetLzmaCompexity(); - return props.GetRating_Enc(dictSize, GlobalTime, GlobalFreq, UnpackSize * NumIterations); -} - -UInt64 CBenchInfo::GetRating_LzmaDec() const -{ - CBenchProps props; - props.SetLzmaCompexity(); - return props.GetRating_Dec(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations); -} - - -#ifndef Z7_ST - -#define NUM_CPU_LEVELS_MAX 3 - -struct CAffinityMode -{ - unsigned NumBundleThreads; - unsigned NumLevels; - unsigned NumCoreThreads; - unsigned NumCores; - // unsigned DivideNum; - UInt32 Sizes[NUM_CPU_LEVELS_MAX]; - - void SetLevels(unsigned numCores, unsigned numCoreThreads); - DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; - bool NeedAffinity() const { return NumBundleThreads != 0; } - - WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const - { - if (NeedAffinity()) - { - CCpuSet cpuSet; - GetAffinityMask(bundleIndex, &cpuSet); - return thread.Create_With_CpuSet(startAddress, parameter, &cpuSet); - } - return thread.Create(startAddress, parameter); - } - - CAffinityMode(): - NumBundleThreads(0), - NumLevels(0), - NumCoreThreads(1) - // DivideNum(1) - {} -}; - -void CAffinityMode::SetLevels(unsigned numCores, unsigned numCoreThreads) -{ - NumCores = numCores; - NumCoreThreads = numCoreThreads; - NumLevels = 0; - if (numCoreThreads == 0 || numCores == 0 || numCores % numCoreThreads != 0) - return; - UInt32 c = numCores / numCoreThreads; - UInt32 c2 = 1; - while ((c & 1) == 0) - { - c >>= 1; - c2 <<= 1; - } - if (c2 != 1) - Sizes[NumLevels++] = c2; - if (c != 1) - Sizes[NumLevels++] = c; - if (numCoreThreads != 1) - Sizes[NumLevels++] = numCoreThreads; - if (NumLevels == 0) - Sizes[NumLevels++] = 1; - - /* - printf("\n Cores:"); - for (unsigned i = 0; i < NumLevels; i++) - { - printf(" %d", Sizes[i]); - } - printf("\n"); - */ -} - - -DWORD_PTR CAffinityMode::GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const -{ - CpuSet_Zero(cpuSet); - - if (NumLevels == 0) - return 0; - - // printf("\n%2d", bundleIndex); - - /* - UInt32 low = 0; - if (DivideNum != 1) - { - low = bundleIndex % DivideNum; - bundleIndex /= DivideNum; - } - */ - - UInt32 numGroups = NumCores / NumBundleThreads; - UInt32 m = bundleIndex % numGroups; - UInt32 v = 0; - for (unsigned i = 0; i < NumLevels; i++) - { - UInt32 size = Sizes[i]; - while ((size & 1) == 0) - { - v *= 2; - v |= (m & 1); - m >>= 1; - size >>= 1; - } - v *= size; - v += m % size; - m /= size; - } - - // UInt32 nb = NumBundleThreads / DivideNum; - UInt32 nb = NumBundleThreads; - - DWORD_PTR mask = ((DWORD_PTR)1 << nb) - 1; - // v += low; - mask <<= v; - - // printf(" %2d %8x \n ", v, (unsigned)mask); - #ifdef _WIN32 - *cpuSet = mask; - #else - { - for (unsigned k = 0; k < nb; k++) - CpuSet_Set(cpuSet, v + k); - } - #endif - - return mask; -} - - -struct CBenchSyncCommon -{ - bool ExitMode; - NSynchronization::CManualResetEvent StartEvent; - - CBenchSyncCommon(): ExitMode(false) {} -}; - -#endif - - - -enum E_CheckCrcMode -{ - k_CheckCrcMode_Never = 0, - k_CheckCrcMode_Always = 1, - k_CheckCrcMode_FirstPass = 2 -}; - -class CEncoderInfo; - -class CEncoderInfo Z7_final -{ - Z7_CLASS_NO_COPY(CEncoderInfo) - -public: - - #ifndef Z7_ST - NWindows::CThread thread[2]; - NSynchronization::CManualResetEvent ReadyEvent; - UInt32 NumDecoderSubThreads; - CBenchSyncCommon *Common; - UInt32 EncoderIndex; - UInt32 NumEncoderInternalThreads; - CAffinityMode AffinityMode; - bool IsGlobalMtMode; // if more than one benchmark encoder threads - #endif - - CMyComPtr _encoder; - CMyComPtr _encoderFilter; - CBenchProgressInfo *progressInfoSpec[2]; - CMyComPtr progressInfo[2]; - UInt64 NumIterations; - - UInt32 Salt; - - #ifdef USE_ALLOCA - size_t AllocaSize; - #endif - - unsigned KeySize; - Byte _key[32]; - Byte _iv[16]; - - HRESULT Set_Key_and_IV(ICryptoProperties *cp) - { - RINOK(cp->SetKey(_key, KeySize)) - return cp->SetInitVector(_iv, sizeof(_iv)); - } - - Byte _psw[16]; - - bool CheckCrc_Enc; /* = 1, if we want to check packed data crcs after each pass - used for filter and usual coders */ - bool UseRealData_Enc; /* = 1, if we want to use only original data for each pass - used only for filter */ - E_CheckCrcMode CheckCrcMode_Dec; - - struct CDecoderInfo - { - CEncoderInfo *Encoder; - UInt32 DecoderIndex; - bool CallbackMode; - - #ifdef USE_ALLOCA - size_t AllocaSize; - #endif - }; - CDecoderInfo decodersInfo[2]; - - CMyComPtr _decoders[2]; - CMyComPtr _decoderFilter; - - HRESULT Results[2]; - CBenchmarkOutStream *outStreamSpec; - CMyComPtr outStream; - IBenchCallback *callback; - IBenchPrintCallback *printCallback; - UInt32 crc; - size_t kBufferSize; - size_t compressedSize; - const Byte *uncompressedDataPtr; - - const Byte *fileData; - CBenchRandomGenerator rg; - - CMidAlignedBuffer rgCopy; // it must be 16-byte aligned !!! - - // CBenchmarkOutStream *propStreamSpec; - Byte propsData[kMaxMethodPropSize]; - CBufPtrSeqOutStream *propStreamSpec; - CMyComPtr propStream; - - unsigned generateDictBits; - COneMethodInfo _method; - - // for decode - size_t _uncompressedDataSize; - - HRESULT Generate(); - HRESULT Encode(); - HRESULT Decode(UInt32 decoderIndex); - - CEncoderInfo(): - #ifndef Z7_ST - Common(NULL), - IsGlobalMtMode(true), - #endif - Salt(0), - KeySize(0), - CheckCrc_Enc(true), - UseRealData_Enc(true), - CheckCrcMode_Dec(k_CheckCrcMode_Always), - outStreamSpec(NULL), - callback(NULL), - printCallback(NULL), - fileData(NULL), - propStreamSpec(NULL) - {} - - #ifndef Z7_ST - - static THREAD_FUNC_DECL EncodeThreadFunction(void *param) - { - HRESULT res; - CEncoderInfo *encoder = (CEncoderInfo *)param; - try - { - #ifdef USE_ALLOCA - alloca(encoder->AllocaSize); - #endif - - res = encoder->Encode(); - } - catch(...) - { - res = E_FAIL; - } - encoder->Results[0] = res; - if (res != S_OK) - encoder->progressInfoSpec[0]->Status->SetResult(res); - encoder->ReadyEvent.Set(); - return THREAD_FUNC_RET_ZERO; - } - - static THREAD_FUNC_DECL DecodeThreadFunction(void *param) - { - CDecoderInfo *decoder = (CDecoderInfo *)param; - - #ifdef USE_ALLOCA - alloca(decoder->AllocaSize); - // printf("\nalloca=%d\n", (unsigned)decoder->AllocaSize); - #endif - - CEncoderInfo *encoder = decoder->Encoder; - encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex); - return THREAD_FUNC_RET_ZERO; - } - - HRESULT CreateEncoderThread() - { - WRes res = 0; - if (!ReadyEvent.IsCreated()) - res = ReadyEvent.Create(); - if (res == 0) - res = AffinityMode.CreateThread_WithAffinity(thread[0], EncodeThreadFunction, this, - EncoderIndex); - return HRESULT_FROM_WIN32(res); - } - - HRESULT CreateDecoderThread(unsigned index, bool callbackMode - #ifdef USE_ALLOCA - , size_t allocaSize - #endif - ) - { - CDecoderInfo &decoder = decodersInfo[index]; - decoder.DecoderIndex = index; - decoder.Encoder = this; - - #ifdef USE_ALLOCA - decoder.AllocaSize = allocaSize; - #endif - - decoder.CallbackMode = callbackMode; - - WRes res = AffinityMode.CreateThread_WithAffinity(thread[index], DecodeThreadFunction, &decoder, - // EncoderIndex * NumEncoderInternalThreads + index - EncoderIndex - ); - - return HRESULT_FROM_WIN32(res); - } - - #endif -}; - - - - -static size_t GetBenchCompressedSize(size_t bufferSize) -{ - return kCompressedAdditionalSize + bufferSize + bufferSize / 16; - // kBufferSize / 2; -} - - -HRESULT CEncoderInfo::Generate() -{ - const COneMethodInfo &method = _method; - - // we need extra space, if input data is already compressed - const size_t kCompressedBufferSize = _encoderFilter ? - kBufferSize : - GetBenchCompressedSize(kBufferSize); - - if (kCompressedBufferSize < kBufferSize) - return E_FAIL; - - uncompressedDataPtr = fileData; - if (fileData) - { - #if !defined(Z7_ST) - if (IsGlobalMtMode) - { - /* we copy the data to local buffer of thread to eliminate - using of shared buffer by different threads */ - ALLOC_WITH_HRESULT(&rg, kBufferSize) - memcpy((Byte *)rg, fileData, kBufferSize); - uncompressedDataPtr = (const Byte *)rg; - } - #endif - } - else - { - ALLOC_WITH_HRESULT(&rg, kBufferSize) - // DWORD ttt = GetTickCount(); - if (generateDictBits == 0) - rg.GenerateSimpleRandom(Salt); - else - { - if (generateDictBits >= sizeof(size_t) * 8 - && kBufferSize > ((size_t)1 << (sizeof(size_t) * 8 - 1))) - return E_INVALIDARG; - rg.GenerateLz(generateDictBits, Salt); - // return E_ABORT; // for debug - } - // printf("\n%d\n ", GetTickCount() - ttt); - - crc = CrcCalc((const Byte *)rg, rg.Size()); - uncompressedDataPtr = (const Byte *)rg; - } - - if (!outStream) - { - outStreamSpec = new CBenchmarkOutStream; - outStream = outStreamSpec; - } - - ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize) - - if (_encoderFilter) - { - /* we try to reduce the number of memcpy() in main encoding loop. - so we copy data to temp buffers here */ - ALLOC_WITH_HRESULT(&rgCopy, kBufferSize) - memcpy((Byte *)*outStreamSpec, uncompressedDataPtr, kBufferSize); - memcpy((Byte *)rgCopy, uncompressedDataPtr, kBufferSize); - } - - if (!propStream) - { - propStreamSpec = new CBufPtrSeqOutStream; // CBenchmarkOutStream; - propStream = propStreamSpec; - } - // ALLOC_WITH_HRESULT_2(propStreamSpec, kMaxMethodPropSize); - // propStreamSpec->Init(true, false); - propStreamSpec->Init(propsData, sizeof(propsData)); - - - CMyComPtr coder; - if (_encoderFilter) - coder = _encoderFilter; - else - coder = _encoder; - { - CMyComPtr scp; - coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - { - const UInt64 reduceSize = kBufferSize; - - /* in posix new thread uses same affinity as parent thread, - so we don't need to send affinity to coder in posix */ - UInt64 affMask; - #if !defined(Z7_ST) && defined(_WIN32) - { - CCpuSet cpuSet; - affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); - } - #else - affMask = 0; - #endif - // affMask <<= 3; // debug line: to test no affinity in coder; - // affMask = 0; - - RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL))) - } - else - { - if (method.AreThereNonOptionalProps()) - return E_INVALIDARG; - } - - CMyComPtr writeCoderProps; - coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps); - if (writeCoderProps) - { - RINOK(writeCoderProps->WriteCoderProperties(propStream)) - } - - { - CMyComPtr sp; - coder.QueryInterface(IID_ICryptoSetPassword, &sp); - if (sp) - { - RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))) - - // we must call encoding one time to calculate password key for key cache. - // it must be after WriteCoderProperties! - Byte temp[16]; - memset(temp, 0, sizeof(temp)); - - if (_encoderFilter) - { - _encoderFilter->Init(); - _encoderFilter->Filter(temp, sizeof(temp)); - } - else - { - CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; - CMyComPtr inStream = inStreamSpec; - inStreamSpec->Init(temp, sizeof(temp)); - - CCrcOutStream *crcStreamSpec = new CCrcOutStream; - CMyComPtr crcStream = crcStreamSpec; - crcStreamSpec->Init(); - - RINOK(_encoder->Code(inStream, crcStream, NULL, NULL, NULL)) - } - } - } - } - - return S_OK; -} - - -static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size, UInt32 *crc) -{ - while (size != 0) - { - UInt32 cur = crc ? 1 << 17 : 1 << 24; - if (cur > size) - cur = (UInt32)size; - UInt32 processed = filter->Filter(data, cur); - /* if (processed > size) (in AES filter), we must fill last block with zeros. - but it is not important for benchmark. So we just copy that data without filtering. - if (processed == 0) then filter can't process more */ - if (processed > size || processed == 0) - processed = (UInt32)size; - if (crc) - *crc = CrcUpdate(*crc, data, processed); - data += processed; - size -= processed; - } -} - - -HRESULT CEncoderInfo::Encode() -{ - // printf("\nCEncoderInfo::Generate\n"); - - RINOK(Generate()) - - // printf("\n2222\n"); - - #ifndef Z7_ST - if (Common) - { - Results[0] = S_OK; - WRes wres = ReadyEvent.Set(); - if (wres == 0) - wres = Common->StartEvent.Lock(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - if (Common->ExitMode) - return S_OK; - } - else - #endif - { - CBenchProgressInfo *bpi = progressInfoSpec[0]; - bpi->SetStartTime(); - } - - - CBenchInfo &bi = progressInfoSpec[0]->BenchInfo; - bi.UnpackSize = 0; - bi.PackSize = 0; - CMyComPtr cp; - CMyComPtr coder; - if (_encoderFilter) - coder = _encoderFilter; - else - coder = _encoder; - coder.QueryInterface(IID_ICryptoProperties, &cp); - CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; - CMyComPtr inStream = inStreamSpec; - - if (cp) - { - RINOK(Set_Key_and_IV(cp)) - } - - compressedSize = 0; - if (_encoderFilter) - compressedSize = kBufferSize; - - // CBenchmarkOutStream *outStreamSpec = this->outStreamSpec; - UInt64 prev = 0; - - const UInt32 mask = (CheckCrc_Enc ? 0 : 0xFFFF); - const bool useCrc = (mask < NumIterations); - bool crcPrev_defined = false; - UInt32 crcPrev = 0; - - bool useRealData_Enc = UseRealData_Enc; - bool data_Was_Changed = false; - if (useRealData_Enc) - { - /* we want memcpy() for each iteration including first iteration. - So results will be equal for different number of iterations */ - data_Was_Changed = true; - } - - const UInt64 numIterations = NumIterations; - UInt64 i = numIterations; - // printCallback->NewLine(); - - while (i != 0) - { - i--; - if (printCallback && bi.UnpackSize - prev >= (1 << 26)) - { - prev = bi.UnpackSize; - RINOK(printCallback->CheckBreak()) - } - - /* - CBenchInfo info; - progressInfoSpec[0]->SetStartTime(); - */ - - bool calcCrc = false; - if (useCrc) - calcCrc = (((UInt32)i & mask) == 0); - - if (_encoderFilter) - { - Byte *filterData = rgCopy; - if (i == numIterations - 1 || calcCrc || useRealData_Enc) - { - // printf("\nfilterData = (Byte *)*outStreamSpec;\n"); - filterData = (Byte *)*outStreamSpec; - if (data_Was_Changed) - { - // printf("\nmemcpy(filterData, uncompressedDataPtr\n"); - memcpy(filterData, uncompressedDataPtr, kBufferSize); - } - data_Was_Changed = true; - } - _encoderFilter->Init(); - if (calcCrc) - { - // printf("\nInitCrc\n"); - outStreamSpec->InitCrc(); - } - // printf("\nMy_FilterBench\n"); - My_FilterBench(_encoderFilter, filterData, kBufferSize, - calcCrc ? &outStreamSpec->Crc : NULL); - } - else - { - outStreamSpec->Init(true, calcCrc); // write real data for speed consistency at any number of iterations - inStreamSpec->Init(uncompressedDataPtr, kBufferSize); - RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0])) - if (!inStreamSpec->WasFinished()) - return E_FAIL; - if (compressedSize != outStreamSpec->Pos) - { - if (compressedSize != 0) - return E_FAIL; - compressedSize = outStreamSpec->Pos; - } - } - - // outStreamSpec->Print(); - - if (calcCrc) - { - const UInt32 crc2 = CRC_GET_DIGEST(outStreamSpec->Crc); - if (crcPrev_defined && crcPrev != crc2) - return E_FAIL; - crcPrev = crc2; - crcPrev_defined = true; - } - - bi.UnpackSize += kBufferSize; - bi.PackSize += compressedSize; - - /* - { - progressInfoSpec[0]->SetFinishTime(info); - info.UnpackSize = 0; - info.PackSize = 0; - info.NumIterations = 1; - - info.UnpackSize = kBufferSize; - info.PackSize = compressedSize; - // printf("\n%7d\n", encoder.compressedSize); - - RINOK(callback->SetEncodeResult(info, true)) - printCallback->NewLine(); - } - */ - - } - - _encoder.Release(); - _encoderFilter.Release(); - return S_OK; -} - - -HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) -{ - CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; - CMyComPtr inStream = inStreamSpec; - CMyComPtr &decoder = _decoders[decoderIndex]; - CMyComPtr coder; - if (_decoderFilter) - { - if (decoderIndex != 0) - return E_FAIL; - coder = _decoderFilter; - } - else - coder = decoder; - - // printf("\ndecoderIndex = %d, stack = %p", decoderIndex, &coder); - - CMyComPtr setDecProps; - coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps); - if (!setDecProps && propStreamSpec->GetPos() != 0) - return E_FAIL; - - CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; - CMyComPtr crcOutStream = crcOutStreamSpec; - - CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; - pi->BenchInfo.UnpackSize = 0; - pi->BenchInfo.PackSize = 0; - - #ifndef Z7_ST - { - CMyComPtr setCoderMt; - coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); - if (setCoderMt) - { - RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)) - } - } - #endif - - CMyComPtr scp; - coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - { - const UInt64 reduceSize = _uncompressedDataSize; - RINOK(_method.SetCoderProps(scp, &reduceSize)) - } - - CMyComPtr cp; - coder.QueryInterface(IID_ICryptoProperties, &cp); - - if (setDecProps) - { - RINOK(setDecProps->SetDecoderProperties2( - /* (const Byte *)*propStreamSpec, */ - propsData, - (UInt32)propStreamSpec->GetPos())) - } - - { - CMyComPtr sp; - coder.QueryInterface(IID_ICryptoSetPassword, &sp); - if (sp) - { - RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))) - } - } - - UInt64 prev = 0; - - if (cp) - { - RINOK(Set_Key_and_IV(cp)) - } - - CMyComPtr setFinishMode; - - if (_decoderFilter) - { - if (compressedSize > rgCopy.Size()) - return E_FAIL; - } - else - { - decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); - } - - const UInt64 numIterations = NumIterations; - const E_CheckCrcMode checkCrcMode = CheckCrcMode_Dec; - - for (UInt64 i = 0; i < numIterations; i++) - { - if (printCallback && pi->BenchInfo.UnpackSize - prev >= (1 << 26)) - { - RINOK(printCallback->CheckBreak()) - prev = pi->BenchInfo.UnpackSize; - } - - const UInt64 outSize = kBufferSize; - bool calcCrc = (checkCrcMode != k_CheckCrcMode_Never); - - crcOutStreamSpec->Init(); - - if (_decoderFilter) - { - Byte *filterData = (Byte *)*outStreamSpec; - if (calcCrc) - { - calcCrc = (i == 0); - if (checkCrcMode == k_CheckCrcMode_Always) - { - calcCrc = true; - memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize); - filterData = rgCopy; - } - } - _decoderFilter->Init(); - My_FilterBench(_decoderFilter, filterData, compressedSize, - calcCrc ? &crcOutStreamSpec->Crc : NULL); - } - else - { - crcOutStreamSpec->CalcCrc = calcCrc; - inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize); - - if (setFinishMode) - { - RINOK(setFinishMode->SetFinishMode(BoolToUInt(true))) - } - - RINOK(decoder->Code(inStream, crcOutStream, NULL, &outSize, progressInfo[decoderIndex])) - - if (setFinishMode) - { - if (!inStreamSpec->WasFinished()) - return S_FALSE; - - CMyComPtr getInStreamProcessedSize; - decoder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); - - if (getInStreamProcessedSize) - { - UInt64 processed; - RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) - if (processed != compressedSize) - return S_FALSE; - } - } - - if (crcOutStreamSpec->Pos != outSize) - return S_FALSE; - } - - if (calcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) - return S_FALSE; - - pi->BenchInfo.UnpackSize += kBufferSize; - pi->BenchInfo.PackSize += compressedSize; - } - - decoder.Release(); - _decoderFilter.Release(); - return S_OK; -} - - -static const UInt32 kNumThreadsMax = (1 << 12); - -struct CBenchEncoders -{ - CEncoderInfo *encoders; - CBenchEncoders(UInt32 num): encoders(NULL) { encoders = new CEncoderInfo[num]; } - ~CBenchEncoders() { delete []encoders; } -}; - - -static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands) -{ - if (numCommands < (1 << 4)) - numCommands = (1 << 4); - UInt64 res = complexInCommands / numCommands; - return (res == 0 ? 1 : res); -} - - - -#ifndef Z7_ST - -// ---------- CBenchThreadsFlusher ---------- - -struct CBenchThreadsFlusher -{ - CBenchEncoders *EncodersSpec; - CBenchSyncCommon Common; - unsigned NumThreads; - bool NeedClose; - - CBenchThreadsFlusher(): NumThreads(0), NeedClose(false) {} - - ~CBenchThreadsFlusher() - { - StartAndWait(true); - } - - WRes StartAndWait(bool exitMode = false); -}; - - -WRes CBenchThreadsFlusher::StartAndWait(bool exitMode) -{ - if (!NeedClose) - return 0; - - Common.ExitMode = exitMode; - WRes res = Common.StartEvent.Set(); - - for (unsigned i = 0; i < NumThreads; i++) - { - NWindows::CThread &t = EncodersSpec->encoders[i].thread[0]; - if (t.IsCreated()) - { - WRes res2 = t.Wait_Close(); - if (res == 0) - res = res2; - } - } - NeedClose = false; - return res; -} - -#endif // Z7_ST - - - -static void SetPseudoRand(Byte *data, size_t size, UInt32 startValue) -{ - for (size_t i = 0; i < size; i++) - { - data[i] = (Byte)startValue; - startValue++; - } -} - - - -static HRESULT MethodBench( - DECL_EXTERNAL_CODECS_LOC_VARS - UInt64 complexInCommands, - #ifndef Z7_ST - bool oldLzmaBenchMode, - UInt32 numThreads, - const CAffinityMode *affinityMode, - #endif - const COneMethodInfo &method2, - size_t uncompressedDataSize, - const Byte *fileData, - unsigned generateDictBits, - - IBenchPrintCallback *printCallback, - IBenchCallback *callback, - CBenchProps *benchProps) -{ - COneMethodInfo method = method2; - UInt64 methodId; - UInt32 numStreams; - bool isFilter; - const int codecIndex = FindMethod_Index( - EXTERNAL_CODECS_LOC_VARS - method.MethodName, true, - methodId, numStreams, isFilter); - if (codecIndex < 0) - return E_NOTIMPL; - if (numStreams != 1) - return E_INVALIDARG; - - UInt32 numEncoderThreads = 1; - UInt32 numSubDecoderThreads = 1; - - #ifndef Z7_ST - numEncoderThreads = numThreads; - - if (oldLzmaBenchMode) - if (methodId == k_LZMA) - { - if (numThreads == 1 && method.Get_NumThreads() < 0) - method.AddProp_NumThreads(1); - const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(); - if (numThreads > 1 && numLzmaThreads > 1) - { - numEncoderThreads = (numThreads + 1) / 2; // 20.03 - numSubDecoderThreads = 2; - } - } - - const bool mtEncMode = (numEncoderThreads > 1) || affinityMode->NeedAffinity(); - - #endif - - CBenchEncoders encodersSpec(numEncoderThreads); - CEncoderInfo *encoders = encodersSpec.encoders; - - UInt32 i; - - for (i = 0; i < numEncoderThreads; i++) - { - CEncoderInfo &encoder = encoders[i]; - encoder.callback = (i == 0) ? callback : NULL; - encoder.printCallback = printCallback; - - #ifndef Z7_ST - encoder.EncoderIndex = i; - encoder.NumEncoderInternalThreads = numSubDecoderThreads; - encoder.AffinityMode = *affinityMode; - - /* - if (numSubDecoderThreads > 1) - if (encoder.AffinityMode.NeedAffinity() - && encoder.AffinityMode.NumBundleThreads == 1) - { - // if old LZMA benchmark uses two threads in coder, we increase (NumBundleThreads) for old LZMA benchmark uses two threads instead of one - if (encoder.AffinityMode.NumBundleThreads * 2 <= encoder.AffinityMode.NumCores) - encoder.AffinityMode.NumBundleThreads *= 2; - } - */ - - #endif - - { - CCreatedCoder cod; - RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)codecIndex, true, encoder._encoderFilter, cod)) - encoder._encoder = cod.Coder; - if (!encoder._encoder && !encoder._encoderFilter) - return E_NOTIMPL; - } - - SetPseudoRand(encoder._iv, sizeof(encoder._iv), 17); - SetPseudoRand(encoder._key, sizeof(encoder._key), 51); - SetPseudoRand(encoder._psw, sizeof(encoder._psw), 123); - - for (UInt32 j = 0; j < numSubDecoderThreads; j++) - { - CCreatedCoder cod; - CMyComPtr &decoder = encoder._decoders[j]; - RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod)) - decoder = cod.Coder; - if (!encoder._decoderFilter && !decoder) - return E_NOTIMPL; - } - - encoder.UseRealData_Enc = - encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30; - - encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always; - if (benchProps->DecComplexCompr + - benchProps->DecComplexUnc <= 30) - encoder.CheckCrcMode_Dec = - k_CheckCrcMode_FirstPass; // for filters - // k_CheckCrcMode_Never; // for debug - // k_CheckCrcMode_Always; // for debug - if (fileData) - { - encoder.UseRealData_Enc = true; - encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always; - } - } - - UInt32 crc = 0; - if (fileData) - crc = CrcCalc(fileData, uncompressedDataSize); - - for (i = 0; i < numEncoderThreads; i++) - { - CEncoderInfo &encoder = encoders[i]; - encoder._method = method; - encoder.generateDictBits = generateDictBits; - encoder._uncompressedDataSize = uncompressedDataSize; - encoder.kBufferSize = uncompressedDataSize; - encoder.fileData = fileData; - encoder.crc = crc; - } - - CBenchProgressStatus status; - status.Res = S_OK; - status.EncodeMode = true; - - #ifndef Z7_ST - CBenchThreadsFlusher encoderFlusher; - if (mtEncMode) - { - WRes wres = encoderFlusher.Common.StartEvent.Create(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - encoderFlusher.NumThreads = numEncoderThreads; - encoderFlusher.EncodersSpec = &encodersSpec; - encoderFlusher.NeedClose = true; - } - #endif - - for (i = 0; i < numEncoderThreads; i++) - { - CEncoderInfo &encoder = encoders[i]; - encoder.NumIterations = GetNumIterations(benchProps->GetNumCommands_Enc(uncompressedDataSize), complexInCommands); - // encoder.NumIterations = 3; - { -#if 0 - #define kCrcPoly 0xEDB88320 - UInt32 r = i; - unsigned num = numEncoderThreads < 256 ? 8 : 16; - do - r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); - while (--num); - encoder.Salt = r; -#else - UInt32 salt0 = g_CrcTable[(Byte)i]; - UInt32 salt1 = g_CrcTable[(Byte)(i >> 8)]; - encoder.Salt = salt0 ^ (salt1 << 3); -#endif - } - - // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread - // printf("\n encoder index = %d, Salt = %8x\n", i, encoder.Salt); - - encoder.KeySize = benchProps->KeySize; - - for (int j = 0; j < 2; j++) - { - CBenchProgressInfo *spec = new CBenchProgressInfo; - encoder.progressInfoSpec[j] = spec; - encoder.progressInfo[j] = spec; - spec->Status = &status; - } - - if (i == 0) - { - CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; - bpi->Callback = callback; - bpi->BenchInfo.NumIterations = numEncoderThreads; - } - - #ifndef Z7_ST - if (mtEncMode) - { - #ifdef USE_ALLOCA - encoder.AllocaSize = BENCH_ALLOCA_VALUE(i); - #endif - - encoder.Common = &encoderFlusher.Common; - encoder.IsGlobalMtMode = numEncoderThreads > 1; - RINOK(encoder.CreateEncoderThread()) - } - #endif - } - - if (printCallback) - { - RINOK(printCallback->CheckBreak()) - } - - #ifndef Z7_ST - if (mtEncMode) - { - for (i = 0; i < numEncoderThreads; i++) - { - CEncoderInfo &encoder = encoders[i]; - const WRes wres = encoder.ReadyEvent.Lock(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - RINOK(encoder.Results[0]) - } - - CBenchProgressInfo *bpi = encoders[0].progressInfoSpec[0]; - bpi->SetStartTime(); - - const WRes wres = encoderFlusher.StartAndWait(); - if (status.Res == 0 && wres != 0) - return HRESULT_FROM_WIN32(wres); - } - else - #endif - { - RINOK(encoders[0].Encode()) - } - - RINOK(status.Res) - - CBenchInfo info; - - encoders[0].progressInfoSpec[0]->SetFinishTime(info); - info.UnpackSize = 0; - info.PackSize = 0; - info.NumIterations = encoders[0].NumIterations; - - for (i = 0; i < numEncoderThreads; i++) - { - const CEncoderInfo &encoder = encoders[i]; - info.UnpackSize += encoder.kBufferSize; - info.PackSize += encoder.compressedSize; - // printf("\n%7d\n", encoder.compressedSize); - } - - RINOK(callback->SetEncodeResult(info, true)) - - - - - // ---------- Decode ---------- - - status.Res = S_OK; - status.EncodeMode = false; - - const UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; - #ifndef Z7_ST - const bool mtDecoderMode = (numDecoderThreads > 1) || affinityMode->NeedAffinity(); - #endif - - for (i = 0; i < numEncoderThreads; i++) - { - CEncoderInfo &encoder = encoders[i]; - - /* - #ifndef Z7_ST - // encoder.affinityMode = *affinityMode; - if (encoder.NumEncoderInternalThreads != 1) - encoder.AffinityMode.DivideNum = encoder.NumEncoderInternalThreads; - #endif - */ - - - if (i == 0) - { - encoder.NumIterations = GetNumIterations( - benchProps->GetNumCommands_Dec( - encoder.compressedSize, - encoder.kBufferSize), - complexInCommands); - CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; - bpi->Callback = callback; - bpi->BenchInfo.NumIterations = numDecoderThreads; - bpi->SetStartTime(); - } - else - encoder.NumIterations = encoders[0].NumIterations; - - #ifndef Z7_ST - { - const int numSubThreads = method.Get_NumThreads(); - encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : (unsigned)numSubThreads; - } - if (mtDecoderMode) - { - for (UInt32 j = 0; j < numSubDecoderThreads; j++) - { - const HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) - #ifdef USE_ALLOCA - , BENCH_ALLOCA_VALUE(i * numSubDecoderThreads + j) - #endif - ); - RINOK(res) - } - } - else - #endif - { - RINOK(encoder.Decode(0)) - } - } - - #ifndef Z7_ST - if (mtDecoderMode) - { - WRes wres = 0; - HRESULT res = S_OK; - for (i = 0; i < numEncoderThreads; i++) - for (UInt32 j = 0; j < numSubDecoderThreads; j++) - { - CEncoderInfo &encoder = encoders[i]; - const WRes wres2 = encoder.thread[j]. - // Wait(); // later we can get thread times from thread in UNDER_CE - Wait_Close(); - if (wres == 0 && wres2 != 0) - wres = wres2; - const HRESULT res2 = encoder.Results[j]; - if (res == 0 && res2 != 0) - res = res2; - } - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - RINOK(res) - } - #endif // Z7_ST - - RINOK(status.Res) - encoders[0].progressInfoSpec[0]->SetFinishTime(info); - - /* - #ifndef Z7_ST - #ifdef UNDER_CE - if (mtDecoderMode) - for (i = 0; i < numEncoderThreads; i++) - for (UInt32 j = 0; j < numSubDecoderThreads; j++) - { - FILETIME creationTime, exitTime, kernelTime, userTime; - if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0) - info.UserTime += GetTime64(userTime) + GetTime64(kernelTime); - } - #endif - #endif - */ - - info.UnpackSize = 0; - info.PackSize = 0; - info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations; - - for (i = 0; i < numEncoderThreads; i++) - { - const CEncoderInfo &encoder = encoders[i]; - info.UnpackSize += encoder.kBufferSize; - info.PackSize += encoder.compressedSize; - } - - // RINOK(callback->SetDecodeResult(info, false)) // why we called before 21.03 ?? - RINOK(callback->SetDecodeResult(info, true)) - - return S_OK; -} - - - -static inline UInt64 GetDictSizeFromLog(unsigned dictSizeLog) -{ - /* - if (dictSizeLog < 32) - return (UInt32)1 << dictSizeLog; - else - return (UInt32)(Int32)-1; - */ - return (UInt64)1 << dictSizeLog; -} - - -// it's limit of current LZMA implementation that can be changed later -#define kLzmaMaxDictSize ((UInt32)15 << 28) - -static inline UInt64 GetLZMAUsage(bool multiThread, int btMode, UInt64 dict) -{ - if (dict == 0) - dict = 1; - if (dict > kLzmaMaxDictSize) - dict = kLzmaMaxDictSize; - UInt32 hs = (UInt32)dict - 1; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - hs >>= 1; - hs |= 0xFFFF; - if (hs > (1 << 24)) - hs >>= 1; - hs++; - hs += (1 << 16); - - const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); - UInt64 blockSize = (UInt64)dict + (1 << 16) - + (multiThread ? (1 << 20) : 0); - blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); - if (blockSize >= kBlockSizeMax) - blockSize = kBlockSizeMax; - - UInt64 son = (UInt64)dict; - if (btMode) - son *= 2; - const UInt64 v = (hs + son) * 4 + blockSize + - (1 << 20) + (multiThread ? (6 << 20) : 0); - - // printf("\nGetLZMAUsage = %d\n", (UInt32)(v >> 20)); - // printf("\nblockSize = %d\n", (UInt32)(blockSize >> 20)); - return v; -} - - -UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench) -{ - const size_t kBufferSize = (size_t)dictionary + kAdditionalSize; - const UInt64 kCompressedBufferSize = GetBenchCompressedSize(kBufferSize); // / 2; - if (level < 0) - level = 5; - const int algo = (level < 5 ? 0 : 1); - const int btMode = (algo == 0 ? 0 : 1); - - UInt32 numBigThreads = numThreads; - const bool lzmaMt = (totalBench || (numThreads > 1 && btMode)); - if (btMode) - { - if (!totalBench && lzmaMt) - numBigThreads /= 2; - } - return ((UInt64)kBufferSize + kCompressedBufferSize + - GetLZMAUsage(lzmaMt, btMode, dictionary) + (2 << 20)) * numBigThreads; -} - -static UInt64 GetBenchMemoryUsage_Hash(UInt32 numThreads, UInt64 dictionary) -{ - // dictionary += (dictionary >> 9); // for page tables (virtual memory) - return (UInt64)(dictionary + (1 << 15)) * numThreads + (2 << 20); -} - - -// ---------- CRC and HASH ---------- - -struct CCrcInfo_Base -{ - CMidAlignedBuffer Buffer; - const Byte *Data; - size_t Size; - bool CreateLocalBuf; - UInt32 CheckSum_Res; - - CCrcInfo_Base(): CreateLocalBuf(true), CheckSum_Res(0) {} - - HRESULT Generate(const Byte *data, size_t size); - HRESULT CrcProcess(UInt64 numIterations, - const UInt32 *checkSum, IHasher *hf, - IBenchPrintCallback *callback); -}; - - -// for debug: define it to test hash calling with unaligned data -// #define Z7_BENCH_HASH_ALIGN_BUF_OFFSET 3 - -HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size) -{ - Size = size; - Data = data; - if (!data || CreateLocalBuf) - { - Byte *buf; - const size_t size2 = (size + k_RandBuf_AlignMask) & ~(size_t)k_RandBuf_AlignMask; - if (size2 < size) - return E_OUTOFMEMORY; -#ifdef Z7_BENCH_HASH_ALIGN_BUF_OFFSET - ALLOC_WITH_HRESULT(&Buffer, size2 + Z7_BENCH_HASH_ALIGN_BUF_OFFSET) - buf = Buffer + Z7_BENCH_HASH_ALIGN_BUF_OFFSET; -#else - ALLOC_WITH_HRESULT(&Buffer, size2) - buf = Buffer; -#endif - Data = buf; - if (!data) - RandGen_BufAfterPad(buf, size); - else if (size != 0) // (CreateLocalBuf == true) - memcpy(buf, data, size); - } - return S_OK; -} - - -HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations, - const UInt32 *checkSum, IHasher *hf, - IBenchPrintCallback *callback) -{ - MY_ALIGN(16) - UInt32 hash32[64 / 4]; - memset(hash32, 0, sizeof(hash32)); - - CheckSum_Res = 0; - - const UInt32 hashSize = hf->GetDigestSize(); - if (hashSize > sizeof(hash32)) - return S_FALSE; - - const Byte *buf = Data; - const size_t size = Size; - UInt32 checkSum_Prev = 0; - - UInt64 prev = 0; - UInt64 cur = 0; - - do - { - hf->Init(); - size_t pos = 0; - do - { - const size_t rem = size - pos; - const UInt32 kStep = ((UInt32)1 << 31); - const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep; - hf->Update(buf + pos, curSize); - pos += curSize; - } - while (pos != size); - - hf->Final((Byte *)(void *)hash32); - UInt32 sum = 0; - for (UInt32 j = 0; j < hashSize; j += 4) - { - sum = rotlFixed(sum, 11); - sum += GetUi32((const Byte *)(const void *)hash32 + j); - } - if (checkSum) - { - if (sum != *checkSum) - return S_FALSE; - } - else - { - checkSum_Prev = sum; - checkSum = &checkSum_Prev; - } - if (callback) - { - cur += size; - if (cur - prev >= ((UInt32)1 << 30)) - { - prev = cur; - RINOK(callback->CheckBreak()) - } - } - } - while (--numIterations); - - CheckSum_Res = checkSum_Prev; - return S_OK; -} - -extern -UInt32 g_BenchCpuFreqTemp; // we need non-static variavble to disable compiler optimization -UInt32 g_BenchCpuFreqTemp = 1; - -#define YY1 sum += val; sum ^= val; -#define YY3 YY1 YY1 YY1 YY1 -#define YY5 YY3 YY3 YY3 YY3 -#define YY7 YY5 YY5 YY5 YY5 -static const UInt32 kNumFreqCommands = 128; - -EXTERN_C_BEGIN - -static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val) -{ - for (UInt32 i = 0; i < num; i++) - { - YY7 - } - return sum; -} - -EXTERN_C_END - - -#ifndef Z7_ST - -struct CBaseThreadInfo -{ - NWindows::CThread Thread; - IBenchPrintCallback *Callback; - HRESULT CallbackRes; - - WRes Wait_If_Created() - { - if (!Thread.IsCreated()) - return 0; - return Thread.Wait_Close(); - } -}; - -struct CFreqInfo: public CBaseThreadInfo -{ - UInt32 ValRes; - UInt32 Size; - UInt64 NumIterations; -}; - -static THREAD_FUNC_DECL FreqThreadFunction(void *param) -{ - CFreqInfo *p = (CFreqInfo *)param; - - UInt32 sum = g_BenchCpuFreqTemp; - for (UInt64 k = p->NumIterations; k > 0; k--) - { - if (p->Callback) - { - p->CallbackRes = p->Callback->CheckBreak(); - if (p->CallbackRes != S_OK) - break; - } - sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp); - } - p->ValRes = sum; - return THREAD_FUNC_RET_ZERO; -} - -struct CFreqThreads -{ - CFreqInfo *Items; - UInt32 NumThreads; - - CFreqThreads(): Items(NULL), NumThreads(0) {} - - WRes WaitAll() - { - WRes wres = 0; - for (UInt32 i = 0; i < NumThreads; i++) - { - WRes wres2 = Items[i].Wait_If_Created(); - if (wres == 0 && wres2 != 0) - wres = wres2; - } - NumThreads = 0; - return wres; - } - - ~CFreqThreads() - { - WaitAll(); - delete []Items; - } -}; - - -static THREAD_FUNC_DECL CrcThreadFunction(void *param); - -struct CCrcInfo: public CBaseThreadInfo -{ - const Byte *Data; - size_t Size; - UInt64 NumIterations; - bool CheckSumDefined; - UInt32 CheckSum; - CMyComPtr Hasher; - HRESULT Res; - UInt32 CheckSum_Res; - - #ifndef Z7_ST - NSynchronization::CManualResetEvent ReadyEvent; - UInt32 ThreadIndex; - CBenchSyncCommon *Common; - CAffinityMode AffinityMode; - #endif - - // we want to call CCrcInfo_Base::Buffer.Free() in main thread. - // so we uses non-local CCrcInfo_Base. - CCrcInfo_Base crcib; - - HRESULT CreateThread() - { - WRes res = 0; - if (!ReadyEvent.IsCreated()) - res = ReadyEvent.Create(); - if (res == 0) - res = AffinityMode.CreateThread_WithAffinity(Thread, CrcThreadFunction, this, - ThreadIndex); - return HRESULT_FROM_WIN32(res); - } - - #ifdef USE_ALLOCA - size_t AllocaSize; - #endif - - void Process(); - - CCrcInfo(): Res(E_FAIL) {} -}; - -static const bool k_Crc_CreateLocalBuf_For_File = true; // for total BW test -// static const bool k_Crc_CreateLocalBuf_For_File = false; // for shared memory read test - -void CCrcInfo::Process() -{ - crcib.CreateLocalBuf = k_Crc_CreateLocalBuf_For_File; - // we can use additional Generate() passes to reduce some time effects for new page allocation - // for (unsigned y = 0; y < 10; y++) - Res = crcib.Generate(Data, Size); - - // if (Common) - { - WRes wres = ReadyEvent.Set(); - if (wres != 0) - { - if (Res == 0) - Res = HRESULT_FROM_WIN32(wres); - return; - } - if (Res != 0) - return; - - wres = Common->StartEvent.Lock(); - - if (wres != 0) - { - Res = HRESULT_FROM_WIN32(wres); - return; - } - if (Common->ExitMode) - return; - } - - Res = crcib.CrcProcess(NumIterations, - CheckSumDefined ? &CheckSum : NULL, Hasher, - Callback); - CheckSum_Res = crcib.CheckSum_Res; - /* - We don't want to include the time of slow CCrcInfo_Base::Buffer.Free() - to time of benchmark. So we don't free Buffer here - */ - // crcib.Buffer.Free(); -} - - -static THREAD_FUNC_DECL CrcThreadFunction(void *param) -{ - CCrcInfo *p = (CCrcInfo *)param; - - #ifdef USE_ALLOCA - alloca(p->AllocaSize); - #endif - p->Process(); - return THREAD_FUNC_RET_ZERO; -} - - -struct CCrcThreads -{ - CCrcInfo *Items; - unsigned NumThreads; - CBenchSyncCommon Common; - bool NeedClose; - - CCrcThreads(): Items(NULL), NumThreads(0), NeedClose(false) {} - - WRes StartAndWait(bool exitMode = false); - - ~CCrcThreads() - { - StartAndWait(true); - delete []Items; - } -}; - - -WRes CCrcThreads::StartAndWait(bool exitMode) -{ - if (!NeedClose) - return 0; - - Common.ExitMode = exitMode; - WRes wres = Common.StartEvent.Set(); - - for (unsigned i = 0; i < NumThreads; i++) - { - WRes wres2 = Items[i].Wait_If_Created(); - if (wres == 0 && wres2 != 0) - wres = wres2; - } - NumThreads = 0; - NeedClose = false; - return wres; -} - -#endif - - -/* -static UInt32 CrcCalc1(const Byte *buf, size_t size) -{ - UInt32 crc = CRC_INIT_VAL; - for (size_t i = 0; i < size; i++) - crc = CRC_UPDATE_BYTE(crc, buf[i]); - return CRC_GET_DIGEST(crc); -} -*/ - -/* -static UInt32 RandGenCrc(Byte *buf, size_t size, CBaseRandomGenerator &RG) -{ - RandGen(buf, size, RG); - return CrcCalc1(buf, size); -} -*/ - -static bool CrcInternalTest() -{ - CAlignedBuffer buffer; - const size_t kBufSize = 1 << 11; - const size_t kCheckSize = 1 << 6; - buffer.Alloc(kBufSize); - if (!buffer.IsAllocated()) - return false; - Byte *buf = (Byte *)buffer; - RandGen_BufAfterPad(buf, kBufSize); - UInt32 sum = 0; - for (size_t i = 0; i < kBufSize - kCheckSize * 2; i += kCheckSize - 1) - for (size_t j = 0; j < kCheckSize; j++) - { - sum = rotlFixed(sum, 11); - sum += CrcCalc(buf + i + j, j); - } - return sum == 0x28462c7c; -} - -struct CBenchMethod -{ - unsigned Weight; - unsigned DictBits; - Int32 EncComplex; - Int32 DecComplexCompr; - Int32 DecComplexUnc; - const char *Name; - // unsigned KeySize; -}; - -// #define USE_SW_CMPLX - -#ifdef USE_SW_CMPLX -#define CMPLX(x) ((x) * 1000) -#else -#define CMPLX(x) (x) -#endif - -static const CBenchMethod g_Bench[] = -{ - // { 40, 17, 357, 145, 20, "LZMA:x1" }, - // { 20, 18, 360, 145, 20, "LZMA2:x1:mt2" }, - - { 20, 18, 360, 145, 20, "LZMA:x1" }, - { 20, 22, 600, 145, 20, "LZMA:x3" }, - - { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" }, - { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" }, - - { 10, 16, 124, 40, 14, "Deflate:x1" }, - { 20, 16, 376, 40, 14, "Deflate:x5" }, - { 10, 16, 1082, 40, 14, "Deflate:x7" }, - { 10, 17, 422, 40, 14, "Deflate64:x5" }, - - { 10, 15, 590, 69, 69, "BZip2:x1" }, - { 20, 19, 815, 122, 122, "BZip2:x5" }, - { 10, 19, 815, 122, 122, "BZip2:x5:mt2" }, - { 10, 19, 2530, 122, 122, "BZip2:x7" }, - - // { 10, 18, 1010, 0, 1150, "PPMDZip:x1" }, - { 10, 18, 1010, 0, 1150, "PPMD:x1" }, - // { 10, 22, 1655, 0, 1830, "PPMDZip:x5" }, - { 10, 22, 1655, 0, 1830, "PPMD:x5" }, - - // { 2, 0, -16, 0, -16, "Swap2" }, - { 2, 0, -16, 0, -16, "Swap4" }, - - // { 2, 0, 3, 0, 4, "Delta:1" }, - // { 2, 0, 3, 0, 4, "Delta:2" }, - // { 2, 0, 3, 0, 4, "Delta:3" }, - { 2, 0, 3, 0, 4, "Delta:4" }, - // { 2, 0, 3, 0, 4, "Delta:8" }, - // { 2, 0, 3, 0, 4, "Delta:32" }, - - { 2, 0, 2, 0, 2, "BCJ" }, - { 2, 0, 1, 0, 1, "ARM64" }, - { 2, 0, 1, 0, 1, "RISCV" }, - - // { 10, 0, 18, 0, 18, "AES128CBC:1" }, - // { 10, 0, 21, 0, 21, "AES192CBC:1" }, - { 10, 0, 24, 0, 24, "AES256CBC:1" }, - - // { 10, 0, 18, 0, 18, "AES128CTR:1" }, - // { 10, 0, 21, 0, 21, "AES192CTR:1" }, - // { 10, 0, 24, 0, 24, "AES256CTR:1" }, - // { 2, 0, CMPLX(6), 0, CMPLX(1), "AES128CBC:2" }, - // { 2, 0, CMPLX(7), 0, CMPLX(1), "AES192CBC:2" }, - { 2, 0, CMPLX(8), 0, CMPLX(1), "AES256CBC:2" }, - - // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES128CTR:2" }, - // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES192CTR:2" }, - // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES256CTR:2" }, - - // { 1, 0, CMPLX(6), 0, -2, "AES128CBC:3" }, - // { 1, 0, CMPLX(7), 0, -2, "AES192CBC:3" }, - { 1, 0, CMPLX(8), 0, -2, "AES256CBC:3" } - - // { 1, 0, CMPLX(1), 0, -2, "AES128CTR:3" }, - // { 1, 0, CMPLX(1), 0, -2, "AES192CTR:3" }, - // { 1, 0, CMPLX(1), 0, -2, "AES256CTR:3" }, -}; - -struct CBenchHash -{ - unsigned Weight; - UInt32 Complex; - UInt32 CheckSum; - const char *Name; -}; - -// #define ARM_CRC_MUL 100 -#define ARM_CRC_MUL 1 - -#define k_Hash_Complex_Mult 256 - -static const CBenchHash g_Hash[] = -{ - { 20, 256, 0x21e207bb, "CRC32:12" } , - { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" }, - { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" }, - { 10, 256, 0x41b901d1, "CRC64" }, - { 10, 64, 0x43eac94f, "XXH64" }, - - { 10, 5100, 0x7913ba03, "SHA256:1" }, - { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" }, - - { 10, 2340, 0xff769021, "SHA1:1" }, - { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" }, - - { 2, 4096, 0x85189d02, "BLAKE2sp:1" }, - { 2, 1024, 0x85189d02, "BLAKE2sp:2" }, // sse2-way4-fast - { 2, 512, 0x85189d02, "BLAKE2sp:3" } // avx2-way8-fast -#if 0 - , { 2, 2048, 0x85189d02, "BLAKE2sp:4" } // sse2-way1 - , { 2, 1024, 0x85189d02, "BLAKE2sp:5" } // sse2-way2 - , { 2, 1024, 0x85189d02, "BLAKE2sp:6" } // avx2-way2 - , { 2, 1024, 0x85189d02, "BLAKE2sp:7" } // avx2-way4 -#endif -}; - -static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size) -{ - char s[128]; - unsigned startPos = (unsigned)sizeof(s) - 32; - memset(s, ' ', startPos); - ConvertUInt64ToString(value, s + startPos); - // if (withSpace) - { - startPos--; - size++; - } - unsigned len = (unsigned)strlen(s + startPos); - if (size > len) - { - size -= len; - if (startPos < size) - startPos = 0; - else - startPos -= size; - } - f.Print(s + startPos); -} - -static const unsigned kFieldSize_Name = 12; -static const unsigned kFieldSize_SmallName = 4; -static const unsigned kFieldSize_Speed = 9; -static const unsigned kFieldSize_Usage = 5; -static const unsigned kFieldSize_RU = 6; -static const unsigned kFieldSize_Rating = 6; -static const unsigned kFieldSize_EU = 5; -static const unsigned kFieldSize_Effec = 5; -static const unsigned kFieldSize_CrcSpeed = 8; - - -static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating; -static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec; - - -static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size) -{ - PrintNumber(f, (rating + 500000) / 1000000, size); -} - - -static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size) -{ - UInt64 v = 0; - if (divider != 0) - v = (val * 100 + divider / 2) / divider; - PrintNumber(f, v, size); -} - -static void PrintChars(IBenchPrintCallback &f, char c, unsigned size) -{ - char s[256]; - memset(s, (Byte)c, size); - s[size] = 0; - f.Print(s); -} - -static void PrintSpaces(IBenchPrintCallback &f, unsigned size) -{ - PrintChars(f, ' ', size); -} - -static void PrintUsage(IBenchPrintCallback &f, UInt64 usage, unsigned size) -{ - PrintNumber(f, Benchmark_GetUsage_Percents(usage), size); -} - -static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq) -{ - PrintUsage(f, usage, kFieldSize_Usage); - PrintRating(f, rpu, kFieldSize_RU); - PrintRating(f, rating, kFieldSize_Rating); - if (showFreq) - { - if (cpuFreq == 0) - PrintSpaces(f, kFieldSize_EUAndEffec); - else - { - PrintPercents(f, rating, cpuFreq * usage / kBenchmarkUsageMult, kFieldSize_EU); - PrintPercents(f, rating, cpuFreq, kFieldSize_Effec); - } - } -} - - -void CTotalBenchRes::Generate_From_BenchInfo(const CBenchInfo &info) -{ - Speed = info.GetUnpackSizeSpeed(); - Usage = info.GetUsage(); - RPU = info.GetRatingPerUsage(Rating); -} - -void CTotalBenchRes::Mult_For_Weight(unsigned weight) -{ - NumIterations2 *= weight; - RPU *= weight; - Rating *= weight; - Usage *= weight; - Speed *= weight; -} - -void CTotalBenchRes::Update_With_Res(const CTotalBenchRes &r) -{ - Rating += r.Rating; - Usage += r.Usage; - RPU += r.RPU; - Speed += r.Speed; - // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); - NumIterations2 += r.NumIterations2; -} - -static void PrintResults(IBenchPrintCallback *f, - const CBenchInfo &info, - unsigned weight, - UInt64 rating, - bool showFreq, UInt64 cpuFreq, - CTotalBenchRes *res) -{ - CTotalBenchRes t; - t.Rating = rating; - t.NumIterations2 = 1; - t.Generate_From_BenchInfo(info); - - if (f) - { - if (t.Speed != 0) - PrintNumber(*f, t.Speed / 1024, kFieldSize_Speed); - else - PrintSpaces(*f, 1 + kFieldSize_Speed); - } - if (f) - { - PrintResults(*f, t.Usage, t.RPU, rating, showFreq, cpuFreq); - } - - if (res) - { - // res->NumIterations1++; - t.Mult_For_Weight(weight); - res->Update_With_Res(t); - } -} - -static void PrintTotals(IBenchPrintCallback &f, - bool showFreq, UInt64 cpuFreq, bool showSpeed, const CTotalBenchRes &res) -{ - const UInt64 numIterations2 = res.NumIterations2 ? res.NumIterations2 : 1; - const UInt64 speed = res.Speed / numIterations2; - if (showSpeed && speed != 0) - PrintNumber(f, speed / 1024, kFieldSize_Speed); - else - PrintSpaces(f, 1 + kFieldSize_Speed); - - // PrintSpaces(f, 1 + kFieldSize_Speed); - // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1; - PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq); -} - - -static void PrintHex(AString &s, UInt64 v) -{ - char temp[32]; - ConvertUInt64ToHex(v, temp); - s += temp; -} - -AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti) -{ - AString s; - // s.Add_UInt32(ti.numProcessThreads); - unsigned numSysThreads = ti.GetNumSystemThreads(); - if (ti.GetNumProcessThreads() != numSysThreads) - { - // if (ti.numProcessThreads != ti.numSysThreads) - { - s += " / "; - s.Add_UInt32(numSysThreads); - } - s += " : "; - #ifdef _WIN32 - PrintHex(s, ti.processAffinityMask); - s += " / "; - PrintHex(s, ti.systemAffinityMask); - #else - unsigned i = (numSysThreads + 3) & ~(unsigned)3; - if (i == 0) - i = 4; - for (; i >= 4; ) - { - i -= 4; - unsigned val = 0; - for (unsigned k = 0; k < 4; k++) - { - const unsigned bit = (ti.IsCpuSet(i + k) ? 1 : 0); - val += (bit << k); - } - PrintHex(s, val); - } - #endif - } - return s; -} - - -#ifdef Z7_LARGE_PAGES - -#ifdef _WIN32 -extern bool g_LargePagesMode; -extern "C" -{ - extern SIZE_T g_LargePageSize; -} -#endif - -void Add_LargePages_String(AString &s) -{ - #ifdef _WIN32 - if (g_LargePagesMode || g_LargePageSize != 0) - { - s.Add_OptSpaced("(LP-"); - PrintSize_KMGT_Or_Hex(s, g_LargePageSize); - #ifdef MY_CPU_X86_OR_AMD64 - if (CPU_IsSupported_PageGB()) - s += "-1G"; - #endif - if (!g_LargePagesMode) - s += "-NA"; - s += ")"; - } - #else - s += ""; - #endif -} - -#endif - - - -static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, - bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads) -{ - f.Print("RAM "); - f.Print(sizeString); - if (size_Defined) - PrintNumber(f, (size >> 20), 6); - else - f.Print(" ?"); - f.Print(" MB"); - - #ifdef Z7_LARGE_PAGES - { - AString s; - Add_LargePages_String(s); - f.Print(s); - } - #endif - - f.Print(", # "); - f.Print(threadsString); - PrintNumber(f, numThreads, 3); -} - - - -struct CBenchCallbackToPrint Z7_final: public IBenchCallback -{ - bool NeedPrint; - bool Use2Columns; - bool ShowFreq; - unsigned NameFieldSize; - - unsigned EncodeWeight; - unsigned DecodeWeight; - - UInt64 CpuFreq; - UInt64 DictSize; - - IBenchPrintCallback *_file; - CBenchProps BenchProps; - CTotalBenchRes EncodeRes; - CTotalBenchRes DecodeRes; - - CBenchInfo BenchInfo_Results[2]; - - CBenchCallbackToPrint(): - NeedPrint(true), - Use2Columns(false), - ShowFreq(false), - NameFieldSize(0), - EncodeWeight(1), - DecodeWeight(1), - CpuFreq(0) - {} - - void Init() { EncodeRes.Init(); DecodeRes.Init(); } - void Print(const char *s); - void NewLine(); - - HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); - HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override; - HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override; -}; - -HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq) -{ - ShowFreq = showFreq; - CpuFreq = cpuFreq; - return S_OK; -} - -HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final) -{ - RINOK(_file->CheckBreak()) - if (final) - BenchInfo_Results[0] = info; - if (final) - if (NeedPrint) - { - const UInt64 rating = BenchProps.GetRating_Enc(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations); - PrintResults(_file, info, - EncodeWeight, rating, - ShowFreq, CpuFreq, &EncodeRes); - if (!Use2Columns) - _file->NewLine(); - } - return S_OK; -} - -static const char * const kSep = " | "; - -HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final) -{ - RINOK(_file->CheckBreak()) - if (final) - BenchInfo_Results[1] = info; - if (final) - if (NeedPrint) - { - const UInt64 rating = BenchProps.GetRating_Dec(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); - if (Use2Columns) - _file->Print(kSep); - else - PrintSpaces(*_file, NameFieldSize); - CBenchInfo info2 = info; - info2.UnpackSize *= info2.NumIterations; - info2.PackSize *= info2.NumIterations; - info2.NumIterations = 1; - PrintResults(_file, info2, - DecodeWeight, rating, - ShowFreq, CpuFreq, &DecodeRes); - } - return S_OK; -} - -void CBenchCallbackToPrint::Print(const char *s) -{ - _file->Print(s); -} - -void CBenchCallbackToPrint::NewLine() -{ - _file->NewLine(); -} - -static void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size) -{ - f.Print(s); - int numSpaces = (int)size - (int)MyStringLen(s); - if (numSpaces > 0) - PrintSpaces(f, (unsigned)numSpaces); -} - -static void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size) -{ - int numSpaces = (int)size - (int)MyStringLen(s); - if (numSpaces > 0) - PrintSpaces(f, (unsigned)numSpaces); - f.Print(s); -} - - -static bool DoesWildcardMatchName_NoCase(const AString &mask, const char *name) -{ - UString wildc = GetUnicodeString(mask); - UString bname = GetUnicodeString(name); - wildc.MakeLower_Ascii(); - bname.MakeLower_Ascii(); - return DoesWildcardMatchName(wildc, bname); -} - - -static HRESULT TotalBench( - DECL_EXTERNAL_CODECS_LOC_VARS - const COneMethodInfo &methodMask, - UInt64 complexInCommands, - #ifndef Z7_ST - UInt32 numThreads, - const CAffinityMode *affinityMode, - #endif - bool forceUnpackSize, - size_t unpackSize, - const Byte *fileData, - IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) - { - const CBenchMethod &bench = g_Bench[i]; - if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name)) - continue; - PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); - { - unsigned keySize = 32; - if (IsString1PrefixedByString2(bench.Name, "AES128")) keySize = 16; - else if (IsString1PrefixedByString2(bench.Name, "AES192")) keySize = 24; - callback->BenchProps.KeySize = keySize; - } - callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; - callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; - callback->BenchProps.EncComplex = bench.EncComplex; - - COneMethodInfo method; - NCOM::CPropVariant propVariant; - propVariant = bench.Name; - RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)) - - size_t unpackSize2 = unpackSize; - if (!forceUnpackSize && bench.DictBits == 0) - unpackSize2 = kFilterUnpackSize; - - callback->EncodeWeight = bench.Weight; - callback->DecodeWeight = bench.Weight; - - const HRESULT res = MethodBench( - EXTERNAL_CODECS_LOC_VARS - complexInCommands, - #ifndef Z7_ST - false, numThreads, affinityMode, - #endif - method, - unpackSize2, fileData, - bench.DictBits, - printCallback, callback, &callback->BenchProps); - - if (res == E_NOTIMPL) - { - // callback->Print(" ---"); - // we need additional empty line as line for decompression results - if (!callback->Use2Columns) - callback->NewLine(); - } - else - { - RINOK(res) - } - - callback->NewLine(); - } - return S_OK; -} - - -struct CFreqBench -{ - // in: - UInt64 complexInCommands; - UInt32 numThreads; - bool showFreq; - UInt64 specifiedFreq; - - // out: - UInt64 CpuFreqRes; - UInt64 UsageRes; - UInt32 res; - - CFreqBench() - {} - - HRESULT FreqBench(IBenchPrintCallback *_file - #ifndef Z7_ST - , const CAffinityMode *affinityMode - #endif - ); -}; - - -HRESULT CFreqBench::FreqBench(IBenchPrintCallback *_file - #ifndef Z7_ST - , const CAffinityMode *affinityMode - #endif - ) -{ - res = 0; - CpuFreqRes = 0; - UsageRes = 0; - - if (numThreads == 0) - numThreads = 1; - - #ifdef Z7_ST - numThreads = 1; - #endif - - const UInt32 complexity = kNumFreqCommands; - UInt64 numIterations = complexInCommands / complexity; - UInt32 numIterations2 = 1 << 30; - if (numIterations > numIterations2) - numIterations /= numIterations2; - else - { - numIterations2 = (UInt32)numIterations; - numIterations = 1; - } - - CBenchInfoCalc progressInfoSpec; - - #ifndef Z7_ST - - bool mtMode = (numThreads > 1) || affinityMode->NeedAffinity(); - - if (mtMode) - { - CFreqThreads threads; - threads.Items = new CFreqInfo[numThreads]; - UInt32 i; - for (i = 0; i < numThreads; i++) - { - CFreqInfo &info = threads.Items[i]; - info.Callback = _file; - info.CallbackRes = S_OK; - info.NumIterations = numIterations; - info.Size = numIterations2; - } - progressInfoSpec.SetStartTime(); - for (i = 0; i < numThreads; i++) - { - // Sleep(10); - CFreqInfo &info = threads.Items[i]; - WRes wres = affinityMode->CreateThread_WithAffinity(info.Thread, FreqThreadFunction, &info, i); - if (info.Thread.IsCreated()) - threads.NumThreads++; - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - } - WRes wres = threads.WaitAll(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - for (i = 0; i < numThreads; i++) - { - RINOK(threads.Items[i].CallbackRes) - } - } - else - #endif - { - progressInfoSpec.SetStartTime(); - UInt32 sum = g_BenchCpuFreqTemp; - UInt64 k = numIterations; - do - { - sum = CountCpuFreq(sum, numIterations2, g_BenchCpuFreqTemp); - if (_file) - { - RINOK(_file->CheckBreak()) - } - } - while (--k); - res += sum; - } - - if (res == 0x12345678) - if (_file) - { - RINOK(_file->CheckBreak()) - } - - CBenchInfo info; - progressInfoSpec.SetFinishTime(info); - - info.UnpackSize = 0; - info.PackSize = 0; - info.NumIterations = 1; - - const UInt64 numCommands = (UInt64)numIterations * numIterations2 * numThreads * complexity; - const UInt64 rating = info.GetSpeed(numCommands); - CpuFreqRes = rating / numThreads; - UsageRes = info.GetUsage(); - - if (_file) - { - PrintResults(_file, info, - 0, // weight - rating, - showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : CpuFreqRes) : 0, NULL); - RINOK(_file->CheckBreak()) - } - - return S_OK; -} - - - -static HRESULT CrcBench( - DECL_EXTERNAL_CODECS_LOC_VARS - UInt64 complexInCommands, - UInt32 numThreads, - const size_t bufferSize, - const Byte *fileData, - - UInt64 &speed, - UInt64 &usage, - - UInt32 complexity, unsigned benchWeight, - const UInt32 *checkSum, - const COneMethodInfo &method, - IBenchPrintCallback *_file, - #ifndef Z7_ST - const CAffinityMode *affinityMode, - #endif - bool showRating, - CTotalBenchRes *encodeRes, - bool showFreq, UInt64 cpuFreq) -{ - if (numThreads == 0) - numThreads = 1; - - #ifdef Z7_ST - numThreads = 1; - #endif - - const AString &methodName = method.MethodName; - // methodName.RemoveChar(L'-'); - CMethodId hashID; - if (!FindHashMethod( - EXTERNAL_CODECS_LOC_VARS - methodName, hashID)) - return E_NOTIMPL; - - /* - // if will generate random data in each thread, instead of global data - CMidAlignedBuffer buffer; - if (!fileData) - { - ALLOC_WITH_HRESULT(&buffer, bufferSize) - RandGen(buffer, bufferSize); - fileData = buffer; - } - */ - - const size_t bsize = (bufferSize == 0 ? 1 : bufferSize); - UInt64 numIterations = complexInCommands * k_Hash_Complex_Mult / complexity / bsize; - if (numIterations == 0) - numIterations = 1; - - CBenchInfoCalc progressInfoSpec; - CBenchInfo info; - - #ifndef Z7_ST - bool mtEncMode = (numThreads > 1) || affinityMode->NeedAffinity(); - - if (mtEncMode) - { - CCrcThreads threads; - threads.Items = new CCrcInfo[numThreads]; - { - WRes wres = threads.Common.StartEvent.Create(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - threads.NeedClose = true; - } - - UInt32 i; - for (i = 0; i < numThreads; i++) - { - CCrcInfo &ci = threads.Items[i]; - AString name; - RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, ci.Hasher)) - if (!ci.Hasher) - return E_NOTIMPL; - CMyComPtr scp; - ci.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - { - RINOK(method.SetCoderProps(scp)) - } - - ci.Callback = _file; - ci.Data = fileData; - ci.NumIterations = numIterations; - ci.Size = bufferSize; - ci.CheckSumDefined = false; - if (checkSum) - { - ci.CheckSum = *checkSum; - ci.CheckSumDefined = true; - } - - #ifdef USE_ALLOCA - ci.AllocaSize = BENCH_ALLOCA_VALUE(i); - #endif - } - - for (i = 0; i < numThreads; i++) - { - CCrcInfo &ci = threads.Items[i]; - ci.ThreadIndex = i; - ci.Common = &threads.Common; - ci.AffinityMode = *affinityMode; - HRESULT hres = ci.CreateThread(); - if (ci.Thread.IsCreated()) - threads.NumThreads++; - if (hres != 0) - return hres; - } - - for (i = 0; i < numThreads; i++) - { - CCrcInfo &ci = threads.Items[i]; - WRes wres = ci.ReadyEvent.Lock(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - RINOK(ci.Res) - } - - progressInfoSpec.SetStartTime(); - - WRes wres = threads.StartAndWait(); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - - progressInfoSpec.SetFinishTime(info); - - for (i = 0; i < numThreads; i++) - { - RINOK(threads.Items[i].Res) - if (i != 0) - if (threads.Items[i].CheckSum_Res != - threads.Items[i - 1].CheckSum_Res) - return S_FALSE; - } - } - else - #endif - { - CMyComPtr hasher; - AString name; - RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)) - if (!hasher) - return E_NOTIMPL; - CMyComPtr scp; - hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - { - RINOK(method.SetCoderProps(scp)) - } - CCrcInfo_Base crcib; - crcib.CreateLocalBuf = false; - RINOK(crcib.Generate(fileData, bufferSize)) - progressInfoSpec.SetStartTime(); - RINOK(crcib.CrcProcess(numIterations, checkSum, hasher, _file)) - progressInfoSpec.SetFinishTime(info); - } - - - UInt64 unpSize = numIterations * bufferSize; - UInt64 unpSizeThreads = unpSize * numThreads; - info.UnpackSize = unpSizeThreads; - info.PackSize = unpSizeThreads; - info.NumIterations = 1; - - if (_file) - { - if (showRating) - { - UInt64 unpSizeThreads2 = unpSizeThreads; - if (unpSizeThreads2 == 0) - unpSizeThreads2 = numIterations * 1 * numThreads; - const UInt64 numCommands = unpSizeThreads2 * complexity / 256; - const UInt64 rating = info.GetSpeed(numCommands); - PrintResults(_file, info, - benchWeight, rating, - showFreq, cpuFreq, encodeRes); - } - RINOK(_file->CheckBreak()) - } - - speed = info.GetSpeed(unpSizeThreads); - usage = info.GetUsage(); - - return S_OK; -} - - - -static HRESULT TotalBench_Hash( - DECL_EXTERNAL_CODECS_LOC_VARS - const COneMethodInfo &methodMask, - UInt64 complexInCommands, - UInt32 numThreads, - size_t bufSize, - const Byte *fileData, - IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback, - #ifndef Z7_ST - const CAffinityMode *affinityMode, - #endif - CTotalBenchRes *encodeRes, - bool showFreq, UInt64 cpuFreq) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++) - { - const CBenchHash &bench = g_Hash[i]; - if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name)) - continue; - PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); - // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; - // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; - // callback->BenchProps.EncComplex = bench.EncComplex; - - COneMethodInfo method; - NCOM::CPropVariant propVariant; - propVariant = bench.Name; - RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)) - - UInt64 speed, usage; - - const HRESULT res = CrcBench( - EXTERNAL_CODECS_LOC_VARS - complexInCommands, - numThreads, bufSize, fileData, - speed, usage, - bench.Complex, bench.Weight, - (!fileData && bufSize == (1 << kNumHashDictBits)) ? &bench.CheckSum : NULL, - method, - printCallback, - #ifndef Z7_ST - affinityMode, - #endif - true, // showRating - encodeRes, showFreq, cpuFreq); - if (res == E_NOTIMPL) - { - // callback->Print(" ---"); - } - else - { - RINOK(res) - } - callback->NewLine(); - } - return S_OK; -} - -struct CTempValues -{ - UInt64 *Values; - CTempValues(): Values(NULL) {} - void Alloc(UInt32 num) { Values = new UInt64[num]; } - ~CTempValues() { delete []Values; } -}; - -static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) -{ - const wchar_t *end; - UInt64 result = ConvertStringToUInt64(s, &end); - if (*end != 0 || s.IsEmpty()) - prop = s; - else if (result <= (UInt32)0xFFFFFFFF) - prop = (UInt32)result; - else - prop = result; -} - - -static bool AreSameMethodNames(const char *fullName, const char *shortName) -{ - return StringsAreEqualNoCase_Ascii(fullName, shortName); -} - - - - -static void Print_Usage_and_Threads(IBenchPrintCallback &f, UInt64 usage, UInt32 threads) -{ - PrintRequirements(f, "usage:", true, usage, "Benchmark threads: ", threads); -} - - -static void Print_Delimiter(IBenchPrintCallback &f) -{ - f.Print(" |"); -} - -static void Print_Pow(IBenchPrintCallback &f, unsigned pow) -{ - char s[16]; - ConvertUInt32ToString(pow, s); - unsigned pos = MyStringLen(s); - s[pos++] = ':'; - s[pos] = 0; - PrintLeft(f, s, kFieldSize_SmallName); // 4 -} - -static void Bench_BW_Print_Usage_Speed(IBenchPrintCallback &f, - UInt64 usage, UInt64 speed) -{ - PrintUsage(f, usage, kFieldSize_Usage); - PrintNumber(f, speed / 1000000, kFieldSize_CrcSpeed); -} - - -HRESULT Bench( - DECL_EXTERNAL_CODECS_LOC_VARS - IBenchPrintCallback *printCallback, - IBenchCallback *benchCallback, - const CObjectVector &props, - UInt32 numIterations, - bool multiDict, - IBenchFreqCallback *freqCallback) -{ - // for (int y = 0; y < 10000; y++) - if (!CrcInternalTest()) - return E_FAIL; - - UInt32 numCPUs = 1; - UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29; - - NSystem::CProcessAffinity threadsInfo; - threadsInfo.InitST(); - - #ifndef Z7_ST - - if (threadsInfo.Get() && threadsInfo.GetNumProcessThreads() != 0) - numCPUs = threadsInfo.GetNumProcessThreads(); - else - numCPUs = NSystem::GetNumberOfProcessors(); - - #endif - - // numCPUs = 24; - /* - { - DWORD_PTR mask = (1 << 0); - DWORD_PTR old = SetThreadAffinityMask(GetCurrentThread(), mask); - old = old; - DWORD_PTR old2 = SetThreadAffinityMask(GetCurrentThread(), mask); - old2 = old2; - return 0; - } - */ - - const bool ramSize_Defined = NSystem::GetRamSize(ramSize); - - UInt32 numThreadsSpecified = numCPUs; - bool needSetComplexity = false; - UInt32 testTimeMs = kComplexInMs; - UInt32 startDicLog = 22; - bool startDicLog_Defined = false; - UInt64 specifiedFreq = 0; - bool multiThreadTests = false; - UInt64 complexInCommands = kComplexInCommands; - UInt32 numThreads_Start = 1; - - #ifndef Z7_ST - CAffinityMode affinityMode; - #endif - - - COneMethodInfo method; - - CMidAlignedBuffer fileDataBuffer; - bool use_fileData = false; - bool isFixedDict = false; - - { - unsigned i; - - if (printCallback) - { - for (i = 0; i < props.Size(); i++) - { - const CProperty &property = props[i]; - printCallback->Print(" "); - printCallback->Print(GetAnsiString(property.Name)); - if (!property.Value.IsEmpty()) - { - printCallback->Print("="); - printCallback->Print(GetAnsiString(property.Value)); - } - } - if (!props.IsEmpty()) - printCallback->NewLine(); - } - - - for (i = 0; i < props.Size(); i++) - { - const CProperty &property = props[i]; - UString name (property.Name); - name.MakeLower_Ascii(); - - if (name.IsEqualTo("file")) - { - if (property.Value.IsEmpty()) - return E_INVALIDARG; - - NFile::NIO::CInFile file; - if (!file.Open(us2fs(property.Value))) - return GetLastError_noZero_HRESULT(); - size_t len; - { - UInt64 len64; - if (!file.GetLength(len64)) - return GetLastError_noZero_HRESULT(); - if (printCallback) - { - printCallback->Print("file size ="); - PrintNumber(*printCallback, len64, 0); - printCallback->NewLine(); - } - len = (size_t)len64; - if (len != len64) - return E_INVALIDARG; - } - - // (len == 0) is allowed. Also it's allowed if Alloc(0) returns NULL here - - ALLOC_WITH_HRESULT(&fileDataBuffer, len) - use_fileData = true; - - { - size_t processed; - if (!file.ReadFull((Byte *)fileDataBuffer, len, processed)) - return GetLastError_noZero_HRESULT(); - if (processed != len) - return E_FAIL; - } - continue; - } - - NCOM::CPropVariant propVariant; - if (!property.Value.IsEmpty()) - ParseNumberString(property.Value, propVariant); - - if (name.IsEqualTo("time")) - { - RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs)) - needSetComplexity = true; - testTimeMs *= 1000; - continue; - } - - if (name.IsEqualTo("timems")) - { - RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs)) - needSetComplexity = true; - continue; - } - - if (name.IsEqualTo("tic")) - { - UInt32 v; - RINOK(ParsePropToUInt32(UString(), propVariant, v)) - if (v >= 64) - return E_INVALIDARG; - complexInCommands = (UInt64)1 << v; - continue; - } - - const bool isCurrent_fixedDict = name.IsEqualTo("df"); - if (isCurrent_fixedDict) - isFixedDict = true; - if (isCurrent_fixedDict || name.IsEqualTo("ds")) - { - RINOK(ParsePropToUInt32(UString(), propVariant, startDicLog)) - if (startDicLog > 32) - return E_INVALIDARG; - startDicLog_Defined = true; - continue; - } - - if (name.IsEqualTo("mts")) - { - RINOK(ParsePropToUInt32(UString(), propVariant, numThreads_Start)) - continue; - } - - if (name.IsEqualTo("af")) - { - UInt32 bundle; - RINOK(ParsePropToUInt32(UString(), propVariant, bundle)) - if (bundle > 0 && bundle < numCPUs) - { - #ifndef Z7_ST - affinityMode.SetLevels(numCPUs, 2); - affinityMode.NumBundleThreads = bundle; - #endif - } - continue; - } - - if (name.IsEqualTo("freq")) - { - UInt32 freq32 = 0; - RINOK(ParsePropToUInt32(UString(), propVariant, freq32)) - if (freq32 == 0) - return E_INVALIDARG; - specifiedFreq = (UInt64)freq32 * 1000000; - - if (printCallback) - { - printCallback->Print("freq="); - PrintNumber(*printCallback, freq32, 0); - printCallback->NewLine(); - } - - continue; - } - - if (name.IsPrefixedBy_Ascii_NoCase("mt")) - { - const UString s = name.Ptr(2); - if (s.IsEqualTo("*") - || (s.IsEmpty() - && propVariant.vt == VT_BSTR - && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))) - { - multiThreadTests = true; - continue; - } - #ifndef Z7_ST - RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified)) - #endif - continue; - } - - RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)) - } - } - - if (printCallback) - { - AString s; - -#if 1 || !defined(Z7_MSC_VER_ORIGINAL) || (Z7_MSC_VER_ORIGINAL >= 1900) - s += "Compiler: "; - GetCompiler(s); - printCallback->Print(s); - printCallback->NewLine(); - s.Empty(); -#endif - - GetSystemInfoText(s); - printCallback->Print(s); - printCallback->NewLine(); - } - - if (printCallback) - { - printCallback->Print("1T CPU Freq (MHz):"); - } - - if (printCallback || freqCallback) - { - UInt64 numMilCommands = 1 << 6; - if (specifiedFreq != 0) - { - while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) - numMilCommands >>= 1; - } - - for (int jj = 0;; jj++) - { - if (printCallback) - RINOK(printCallback->CheckBreak()) - - UInt64 start = ::GetTimeCount(); - UInt32 sum = (UInt32)start; - sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp); - if (sum == 0xF1541213) - if (printCallback) - printCallback->Print(""); - const UInt64 realDelta = ::GetTimeCount() - start; - start = realDelta; - if (start == 0) - start = 1; - if (start > (UInt64)1 << 61) - start = 1; - const UInt64 freq = GetFreq(); - // mips is constant in some compilers - const UInt64 hzVal = MyMultDiv64(numMilCommands * 1000000, freq, start); - const UInt64 mipsVal = numMilCommands * freq / start; - if (printCallback) - { - if (realDelta == 0) - { - printCallback->Print(" -"); - } - else - { - // PrintNumber(*printCallback, start, 0); - PrintNumber(*printCallback, mipsVal, 5); - } - } - if (freqCallback) - { - RINOK(freqCallback->AddCpuFreq(1, hzVal, kBenchmarkUsageMult)) - } - - if (jj >= 1) - { - bool needStop = (numMilCommands >= (1 << - #ifdef _DEBUG - 7 - #else - 11 - #endif - )); - if (start >= freq * 16) - { - printCallback->Print(" (Cmplx)"); - if (!freqCallback) // we don't want complexity change for old gui lzma benchmark - { - needSetComplexity = true; - } - needStop = true; - } - if (needSetComplexity) - SetComplexCommandsMs(testTimeMs, false, mipsVal * 1000000, complexInCommands); - if (needStop) - break; - numMilCommands <<= 1; - } - } - if (freqCallback) - { - RINOK(freqCallback->FreqsFinished(1)) - } - } - - if (printCallback || freqCallback) - for (unsigned test = 0; test < 3; test++) - { - if (numThreadsSpecified < 2) - { - // if (test == 1) - break; - } - if (test == 2 && numThreadsSpecified <= numCPUs) - break; - if (printCallback) - printCallback->NewLine(); - - /* it can show incorrect frequency for HT threads. */ - - UInt32 numThreads = numThreadsSpecified; - if (test < 2) - { - if (numThreads >= numCPUs) - numThreads = numCPUs; - if (test == 0) - numThreads /= 2; - } - if (numThreads < 1) - numThreads = 1; - - if (printCallback) - { - char s[128]; - ConvertUInt64ToString(numThreads, s); - printCallback->Print(s); - printCallback->Print("T CPU Freq (MHz):"); - } - UInt64 numMilCommands = 1 << - #ifdef _DEBUG - 7; - #else - 10; - #endif - - if (specifiedFreq != 0) - { - while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) - numMilCommands >>= 1; - } - - // for (int jj = 0;; jj++) - for (;;) - { - if (printCallback) - RINOK(printCallback->CheckBreak()) - - { - // PrintLeft(f, "CPU", kFieldSize_Name); - - // UInt32 resVal; - - CFreqBench fb; - fb.complexInCommands = numMilCommands * 1000000; - fb.numThreads = numThreads; - // showFreq; - // fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0); - fb.showFreq = true; - fb.specifiedFreq = 1; - - const HRESULT res = fb.FreqBench(NULL /* printCallback */ - #ifndef Z7_ST - , &affinityMode - #endif - ); - RINOK(res) - - if (freqCallback) - { - RINOK(freqCallback->AddCpuFreq(numThreads, fb.CpuFreqRes, fb.UsageRes)) - } - - if (printCallback) - { - /* - if (realDelta == 0) - { - printCallback->Print(" -"); - } - else - */ - { - // PrintNumber(*printCallback, start, 0); - PrintUsage(*printCallback, fb.UsageRes, 3); - printCallback->Print("%"); - PrintNumber(*printCallback, fb.CpuFreqRes / 1000000, 0); - printCallback->Print(" "); - - // PrintNumber(*printCallback, fb.UsageRes, 5); - } - } - } - // if (jj >= 1) - { - const bool needStop = (numMilCommands >= (1 << - #ifdef _DEBUG - 7 - #else - 11 - #endif - )); - if (needStop) - break; - numMilCommands <<= 1; - } - } - if (freqCallback) - { - RINOK(freqCallback->FreqsFinished(numThreads)) - } - } - - - if (printCallback) - { - printCallback->NewLine(); - printCallback->NewLine(); - PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs); - printCallback->Print(GetProcessThreadsInfo(threadsInfo)); - printCallback->NewLine(); - } - - if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax) - return E_INVALIDARG; - - UInt64 dict = (UInt64)1 << startDicLog; - const bool dictIsDefined = (isFixedDict || method.Get_DicSize(dict)); - - const unsigned level = method.GetLevel(); - - AString &methodName = method.MethodName; - const AString original_MethodName = methodName; - if (methodName.IsEmpty()) - methodName = "LZMA"; - - if (benchCallback) - { - CBenchProps benchProps; - benchProps.SetLzmaCompexity(); - const UInt64 dictSize = method.Get_Lzma_DicSize(); - - size_t uncompressedDataSize; - if (use_fileData) - { - uncompressedDataSize = fileDataBuffer.Size(); - } - else - { - uncompressedDataSize = kAdditionalSize + (size_t)dictSize; - if (uncompressedDataSize < dictSize) - return E_INVALIDARG; - } - - return MethodBench( - EXTERNAL_CODECS_LOC_VARS - complexInCommands, - #ifndef Z7_ST - true, numThreadsSpecified, - &affinityMode, - #endif - method, - uncompressedDataSize, (const Byte *)fileDataBuffer, - kOldLzmaDictBits, printCallback, benchCallback, &benchProps); - } - - if (methodName.IsEqualTo_Ascii_NoCase("CRC")) - methodName = "crc32"; - - CMethodId hashID; - const bool isHashMethod = FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID); - int codecIndex = -1; - bool isFilter = false; - if (!isHashMethod) - { - UInt32 numStreams; - codecIndex = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS original_MethodName, - true, // encode - hashID, numStreams, isFilter); - // we can allow non filter for BW tests - if (!isFilter) codecIndex = -1; - } - - CBenchCallbackToPrint callback; - callback.Init(); - callback._file = printCallback; - - if (isHashMethod || codecIndex != -1) - { - if (!printCallback) - return S_FALSE; - IBenchPrintCallback &f = *printCallback; - - UInt64 dict64 = dict; - if (!dictIsDefined) - dict64 = (1 << 27); - if (use_fileData) - { - if (!dictIsDefined) - dict64 = fileDataBuffer.Size(); - else if (dict64 > fileDataBuffer.Size()) - dict64 = fileDataBuffer.Size(); - } - - for (;;) - { - const int index = method.FindProp(NCoderPropID::kDictionarySize); - if (index < 0) - break; - method.Props.Delete((unsigned)index); - } - - // methodName.RemoveChar(L'-'); - Int32 complexity = 16 * k_Hash_Complex_Mult; // for unknown hash method - const UInt32 *checkSum = NULL; - int benchIndex = -1; - - if (isHashMethod) - { - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++) - { - const CBenchHash &h = g_Hash[i]; - AString benchMethod (h.Name); - AString benchProps; - const int propPos = benchMethod.Find(':'); - if (propPos >= 0) - { - benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); - benchMethod.DeleteFrom((unsigned)propPos); - } - - if (AreSameMethodNames(benchMethod, methodName)) - { - const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); - /* - bool isMainMethod = method.PropsString.IsEmpty(); - if (isMainMethod) - isMainMethod = !checkSum - || (benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps.IsEqualTo_Ascii_NoCase("8")); - if (sameProps || isMainMethod) - */ - { - complexity = (Int32)h.Complex; - checkSum = &h.CheckSum; - if (sameProps) - break; - /* - if property. is not specified, we use the complexity - for latest fastest method (crc32:64) - */ - } - } - } - // if (!checkSum) return E_NOTIMPL; - } - else - { - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) - { - const CBenchMethod &bench = g_Bench[i]; - AString benchMethod (bench.Name); - AString benchProps; - const int propPos = benchMethod.Find(':'); - if (propPos >= 0) - { - benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); - benchMethod.DeleteFrom((unsigned)propPos); - } - - if (AreSameMethodNames(benchMethod, methodName)) - { - const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); - // bool isMainMethod = method.PropsString.IsEmpty(); - // if (sameProps || isMainMethod) - { - benchIndex = (int)i; - if (sameProps) - break; - } - } - } - // if (benchIndex < 0) return E_NOTIMPL; - } - - { - /* we count usage only for crc and filter. non-filters are not supported */ - UInt64 usage = (1 << 20); - UInt64 bufSize = dict64; - UInt32 numBlocks = isHashMethod ? 1 : 3; - if (use_fileData) - { - usage += fileDataBuffer.Size(); - if (bufSize > fileDataBuffer.Size()) - bufSize = fileDataBuffer.Size(); - if (isHashMethod) - { - numBlocks = 0; - #ifndef Z7_ST - if (numThreadsSpecified != 1) - numBlocks = (k_Crc_CreateLocalBuf_For_File ? 1 : 0); - #endif - } - } - usage += numThreadsSpecified * bufSize * numBlocks; - Print_Usage_and_Threads(f, usage, numThreadsSpecified); - } - - CUIntVector numThreadsVector; - { - unsigned nt = numThreads_Start; - for (;;) - { - if (nt > numThreadsSpecified) - break; - numThreadsVector.Add(nt); - const unsigned next = nt * 2; - const UInt32 ntHalf= numThreadsSpecified / 2; - if (ntHalf > nt && ntHalf < next) - numThreadsVector.Add(ntHalf); - if (numThreadsSpecified > nt && numThreadsSpecified < next) - numThreadsVector.Add(numThreadsSpecified); - nt = next; - } - } - - unsigned numColumns = isHashMethod ? 1 : 2; - CTempValues speedTotals; - CTempValues usageTotals; - { - const unsigned numItems = numThreadsVector.Size() * numColumns; - speedTotals.Alloc(numItems); - usageTotals.Alloc(numItems); - for (unsigned i = 0; i < numItems; i++) - { - speedTotals.Values[i] = 0; - usageTotals.Values[i] = 0; - } - } - - f.NewLine(); - for (unsigned line = 0; line < 3; line++) - { - f.NewLine(); - f.Print(line == 0 ? "THRD" : line == 1 ? " " : "Size"); - FOR_VECTOR (ti, numThreadsVector) - { - if (ti != 0) - Print_Delimiter(f); - if (line == 0) - { - PrintSpaces(f, (kFieldSize_CrcSpeed + kFieldSize_Usage + 2) * (numColumns - 1)); - PrintNumber(f, numThreadsVector[ti], 1 + kFieldSize_Usage + kFieldSize_CrcSpeed); - } - else - { - for (unsigned c = 0; c < numColumns; c++) - { - PrintRight(f, line == 1 ? "Usage" : "%", kFieldSize_Usage + 1); - PrintRight(f, line == 1 ? "BW" : "MB/s", kFieldSize_CrcSpeed + 1); - } - } - } - } - f.NewLine(); - - UInt64 numSteps = 0; - - // for (UInt32 iter = 0; iter < numIterations; iter++) - // { - unsigned pow = 10; // kNumHashDictBits - if (startDicLog_Defined) - pow = startDicLog; - - // #define NUM_SUB_BITS 2 - // pow <<= NUM_SUB_BITS; - for (;; pow++) - { - const UInt64 bufSize = (UInt64)1 << pow; - // UInt64 bufSize = (UInt64)1 << (pow >> NUM_SUB_BITS); - // bufSize += ((UInt64)pow & ((1 << NUM_SUB_BITS) - 1)) << ((pow >> NUM_SUB_BITS) - NUM_SUB_BITS); - - size_t dataSize = fileDataBuffer.Size(); - if (dataSize > bufSize || !use_fileData) - dataSize = (size_t)bufSize; - - for (UInt32 iter = 0; iter < numIterations; iter++) - { - Print_Pow(f, pow); - // PrintNumber(f, bufSize >> 10, 4); - - FOR_VECTOR (ti, numThreadsVector) - { - RINOK(f.CheckBreak()) - const UInt32 numThreads = numThreadsVector[ti]; - if (isHashMethod) - { - UInt64 speed = 0; - UInt64 usage = 0; - const HRESULT res = CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, - numThreads, - dataSize, (const Byte *)fileDataBuffer, - speed, usage, - (UInt32)complexity, - 1, // benchWeight, - (pow == kNumHashDictBits && !use_fileData) ? checkSum : NULL, - method, - &f, - #ifndef Z7_ST - &affinityMode, - #endif - false, // showRating - NULL, false, 0); - RINOK(res) - - if (ti != 0) - Print_Delimiter(f); - - Bench_BW_Print_Usage_Speed(f, usage, speed); - speedTotals.Values[ti] += speed; - usageTotals.Values[ti] += usage; - } - else - { - { - unsigned keySize = 32; - if (IsString1PrefixedByString2(methodName, "AES128")) keySize = 16; - else if (IsString1PrefixedByString2(methodName, "AES192")) keySize = 24; - callback.BenchProps.KeySize = keySize; - } - - COneMethodInfo method2 = method; - unsigned bench_DictBits; - - if (benchIndex >= 0) - { - const CBenchMethod &bench = g_Bench[benchIndex]; - callback.BenchProps.EncComplex = bench.EncComplex; - callback.BenchProps.DecComplexUnc = bench.DecComplexUnc; - callback.BenchProps.DecComplexCompr = bench.DecComplexCompr; - bench_DictBits = bench.DictBits; - // bench_DictBits = kOldLzmaDictBits; = 32 default : for debug - } - else - { - bench_DictBits = kOldLzmaDictBits; // = 32 default - if (isFilter) - { - const unsigned k_UnknownCoderComplexity = 4; - callback.BenchProps.EncComplex = k_UnknownCoderComplexity; - callback.BenchProps.DecComplexUnc = k_UnknownCoderComplexity; - } - else - { - callback.BenchProps.EncComplex = 1 << 10; - callback.BenchProps.DecComplexUnc = 1 << 6; - } - callback.BenchProps.DecComplexCompr = 0; - } - callback.NeedPrint = false; - - if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA")) - { - const NCOM::CPropVariant propVariant = (UInt32)pow; - RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)) - } - - const HRESULT res = MethodBench( - EXTERNAL_CODECS_LOC_VARS - complexInCommands, - #ifndef Z7_ST - false, // oldLzmaBenchMode - numThreadsVector[ti], - &affinityMode, - #endif - method2, - dataSize, (const Byte *)fileDataBuffer, - bench_DictBits, - printCallback, - &callback, - &callback.BenchProps); - RINOK(res) - - if (ti != 0) - Print_Delimiter(f); - - for (unsigned i = 0; i < 2; i++) - { - const CBenchInfo &bi = callback.BenchInfo_Results[i]; - const UInt64 usage = bi.GetUsage(); - const UInt64 speed = bi.GetUnpackSizeSpeed(); - usageTotals.Values[ti * 2 + i] += usage; - speedTotals.Values[ti * 2 + i] += speed; - Bench_BW_Print_Usage_Speed(f, usage, speed); - } - } - } - - f.NewLine(); - numSteps++; - } - if (dataSize >= dict64) - break; - } - - if (numSteps != 0) - { - f.Print("Avg:"); - for (unsigned ti = 0; ti < numThreadsVector.Size(); ti++) - { - if (ti != 0) - Print_Delimiter(f); - for (unsigned i = 0; i < numColumns; i++) - Bench_BW_Print_Usage_Speed(f, - usageTotals.Values[ti * numColumns + i] / numSteps, - speedTotals.Values[ti * numColumns + i] / numSteps); - } - f.NewLine(); - } - - return S_OK; - } - - bool use2Columns = false; - - bool totalBenchMode = false; - bool onlyHashBench = false; - if (methodName.IsEqualTo_Ascii_NoCase("hash")) - { - onlyHashBench = true; - methodName = "*"; - totalBenchMode = true; - } - else if (methodName.Find('*') >= 0) - totalBenchMode = true; - - // ---------- Threads loop ---------- - for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++) - { - - UInt32 numThreads = numThreadsSpecified; - - if (!multiThreadTests) - { - if (threadsPassIndex != 0) - break; - } - else - { - numThreads = 1; - if (threadsPassIndex != 0) - { - if (numCPUs < 2) - break; - numThreads = numCPUs; - if (threadsPassIndex == 1) - { - if (numCPUs >= 4) - numThreads = numCPUs / 2; - } - else if (numCPUs < 4) - break; - } - } - - IBenchPrintCallback &f = *printCallback; - - if (threadsPassIndex > 0) - { - f.NewLine(); - f.NewLine(); - } - - if (!dictIsDefined && !onlyHashBench) - { - const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); - unsigned dicSizeLog = dicSizeLog_Main; - - #ifdef UNDER_CE - dicSizeLog = (UInt64)1 << 20; - #endif - - if (ramSize_Defined) - for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) - if (GetBenchMemoryUsage(numThreads, (int)level, ((UInt64)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) - break; - - dict = (UInt64)1 << dicSizeLog; - - if (totalBenchMode && dicSizeLog != dicSizeLog_Main) - { - f.Print("Dictionary reduced to: "); - PrintNumber(f, dicSizeLog, 1); - f.NewLine(); - } - } - - Print_Usage_and_Threads(f, - onlyHashBench ? - GetBenchMemoryUsage_Hash(numThreads, dict) : - GetBenchMemoryUsage(numThreads, (int)level, dict, totalBenchMode), - numThreads); - - f.NewLine(); - - f.NewLine(); - - if (totalBenchMode) - { - callback.NameFieldSize = kFieldSize_Name; - use2Columns = false; - } - else - { - callback.NameFieldSize = kFieldSize_SmallName; - use2Columns = true; - } - callback.Use2Columns = use2Columns; - - bool showFreq = false; - UInt64 cpuFreq = 0; - - if (totalBenchMode) - { - showFreq = true; - } - - unsigned fileldSize = kFieldSize_TotalSize; - if (showFreq) - fileldSize += kFieldSize_EUAndEffec; - - if (use2Columns) - { - PrintSpaces(f, callback.NameFieldSize); - PrintRight(f, "Compressing", fileldSize); - f.Print(kSep); - PrintRight(f, "Decompressing", fileldSize); - } - f.NewLine(); - PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize); - - int j; - - for (j = 0; j < 2; j++) - { - PrintRight(f, "Speed", kFieldSize_Speed + 1); - PrintRight(f, "Usage", kFieldSize_Usage + 1); - PrintRight(f, "R/U", kFieldSize_RU + 1); - PrintRight(f, "Rating", kFieldSize_Rating + 1); - if (showFreq) - { - PrintRight(f, "E/U", kFieldSize_EU + 1); - PrintRight(f, "Effec", kFieldSize_Effec + 1); - } - if (!use2Columns) - break; - if (j == 0) - f.Print(kSep); - } - - f.NewLine(); - PrintSpaces(f, callback.NameFieldSize); - - for (j = 0; j < 2; j++) - { - PrintRight(f, "KiB/s", kFieldSize_Speed + 1); - PrintRight(f, "%", kFieldSize_Usage + 1); - PrintRight(f, "MIPS", kFieldSize_RU + 1); - PrintRight(f, "MIPS", kFieldSize_Rating + 1); - if (showFreq) - { - PrintRight(f, "%", kFieldSize_EU + 1); - PrintRight(f, "%", kFieldSize_Effec + 1); - } - if (!use2Columns) - break; - if (j == 0) - f.Print(kSep); - } - - f.NewLine(); - f.NewLine(); - - if (specifiedFreq != 0) - cpuFreq = specifiedFreq; - - // bool showTotalSpeed = false; - - if (totalBenchMode) - { - for (UInt32 i = 0; i < numIterations; i++) - { - if (i != 0) - printCallback->NewLine(); - - const unsigned kNumCpuTests = 3; - for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++) - { - PrintLeft(f, "CPU", kFieldSize_Name); - - // UInt32 resVal; - - CFreqBench fb; - fb.complexInCommands = complexInCommands; - fb.numThreads = numThreads; - // showFreq; - fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0); - fb.specifiedFreq = specifiedFreq; - - const HRESULT res = fb.FreqBench(printCallback - #ifndef Z7_ST - , &affinityMode - #endif - ); - RINOK(res) - - cpuFreq = fb.CpuFreqRes; - callback.NewLine(); - - if (specifiedFreq != 0) - cpuFreq = specifiedFreq; - - if (testTimeMs >= 1000) - if (freqTest == kNumCpuTests - 1) - { - // SetComplexCommandsMs(testTimeMs, specifiedFreq != 0, cpuFreq, complexInCommands); - } - } - callback.NewLine(); - - // return S_OK; // change it - - callback.SetFreq(true, cpuFreq); - - if (!onlyHashBench) - { - size_t dataSize = (size_t)dict; - if (use_fileData) - { - dataSize = fileDataBuffer.Size(); - if (dictIsDefined && dataSize > dict) - dataSize = (size_t)dict; - } - - const HRESULT res = TotalBench(EXTERNAL_CODECS_LOC_VARS - method, complexInCommands, - #ifndef Z7_ST - numThreads, - &affinityMode, - #endif - dictIsDefined || use_fileData, // forceUnpackSize - dataSize, - (const Byte *)fileDataBuffer, - printCallback, &callback); - RINOK(res) - } - - { - size_t dataSize = (size_t)1 << kNumHashDictBits; - if (dictIsDefined) - { - dataSize = (size_t)dict; - if (dataSize != dict) - return E_OUTOFMEMORY; - } - if (use_fileData) - { - dataSize = fileDataBuffer.Size(); - if (dictIsDefined && dataSize > dict) - dataSize = (size_t)dict; - } - - const HRESULT res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS - method, complexInCommands, - numThreads, - dataSize, (const Byte *)fileDataBuffer, - printCallback, &callback, - #ifndef Z7_ST - &affinityMode, - #endif - &callback.EncodeRes, true, cpuFreq); - RINOK(res) - } - - callback.NewLine(); - { - PrintLeft(f, "CPU", kFieldSize_Name); - - CFreqBench fb; - fb.complexInCommands = complexInCommands; - fb.numThreads = numThreads; - // showFreq; - fb.showFreq = (specifiedFreq != 0); - fb.specifiedFreq = specifiedFreq; - - const HRESULT res = fb.FreqBench(printCallback - #ifndef Z7_ST - , &affinityMode - #endif - ); - RINOK(res) - callback.NewLine(); - } - } - } - else - { - needSetComplexity = true; - if (!methodName.IsEqualTo_Ascii_NoCase("LZMA")) - { - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) - { - const CBenchMethod &h = g_Bench[i]; - AString benchMethod (h.Name); - AString benchProps; - const int propPos = benchMethod.Find(':'); - if (propPos >= 0) - { - benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); - benchMethod.DeleteFrom((unsigned)propPos); - } - - if (AreSameMethodNames(benchMethod, methodName)) - { - if (benchProps.IsEmpty() - || (benchProps == "x5" && method.PropsString.IsEmpty()) - || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) - { - callback.BenchProps.EncComplex = h.EncComplex; - callback.BenchProps.DecComplexCompr = h.DecComplexCompr; - callback.BenchProps.DecComplexUnc = h.DecComplexUnc; - needSetComplexity = false; - break; - } - } - } - /* - if (i == Z7_ARRAY_SIZE(g_Bench)) - return E_NOTIMPL; - */ - } - if (needSetComplexity) - callback.BenchProps.SetLzmaCompexity(); - - if (startDicLog < kBenchMinDicLogSize) - startDicLog = kBenchMinDicLogSize; - - for (unsigned i = 0; i < numIterations; i++) - { - unsigned pow = (dict < GetDictSizeFromLog(startDicLog)) ? kBenchMinDicLogSize : (unsigned)startDicLog; - if (!multiDict) - pow = 32; - while (GetDictSizeFromLog(pow) > dict && pow > 0) - pow--; - for (; GetDictSizeFromLog(pow) <= dict; pow++) - { - Print_Pow(f, pow); - callback.DictSize = (UInt64)1 << pow; - - COneMethodInfo method2 = method; - - if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA")) - { - // We add dictionary size property. - // method2 can have two different dictionary size properties. - // And last property is main. - NCOM::CPropVariant propVariant = (UInt32)pow; - RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)) - } - - size_t uncompressedDataSize; - if (use_fileData) - { - uncompressedDataSize = fileDataBuffer.Size(); - } - else - { - uncompressedDataSize = (size_t)callback.DictSize; - if (uncompressedDataSize != callback.DictSize) - return E_OUTOFMEMORY; - if (uncompressedDataSize >= (1 << 18)) - uncompressedDataSize += kAdditionalSize; - } - - const HRESULT res = MethodBench( - EXTERNAL_CODECS_LOC_VARS - complexInCommands, - #ifndef Z7_ST - true, numThreads, - &affinityMode, - #endif - method2, - uncompressedDataSize, (const Byte *)fileDataBuffer, - kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps); - f.NewLine(); - RINOK(res) - if (!multiDict) - break; - } - } - } - - PrintChars(f, '-', callback.NameFieldSize + fileldSize); - - if (use2Columns) - { - f.Print(kSep); - PrintChars(f, '-', fileldSize); - } - - f.NewLine(); - - if (use2Columns) - { - PrintLeft(f, "Avr:", callback.NameFieldSize); - PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.EncodeRes); - f.Print(kSep); - PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.DecodeRes); - f.NewLine(); - } - - PrintLeft(f, "Tot:", callback.NameFieldSize); - CTotalBenchRes midRes; - midRes = callback.EncodeRes; - midRes.Update_With_Res(callback.DecodeRes); - - // midRes.SetSum(callback.EncodeRes, callback.DecodeRes); - PrintTotals(f, showFreq, cpuFreq, false, midRes); - f.NewLine(); - - } - return S_OK; -} +// Bench.cpp + +#include "StdAfx.h" + +// #include + +#ifndef _WIN32 +#define USE_POSIX_TIME +#define USE_POSIX_TIME2 +#endif // _WIN32 + +#ifdef USE_POSIX_TIME +#include +#include +#ifdef USE_POSIX_TIME2 +#include +#include +#endif +#endif // USE_POSIX_TIME + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include +#else +#include +#endif +#define BENCH_ALLOCA_VALUE(index) (((index) * 64 * 21) & 0x7FF) +#endif + +#include "../../../../C/7zCrc.h" +#include "../../../../C/RotateDefs.h" +#include "../../../../C/CpuArch.h" + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/Thread.h" +#endif + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/SystemInfo.h" + +#include "../../../Common/MyBuffer2.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/Wildcard.h" + +#include "../../Common/MethodProps.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "Bench.h" + +using namespace NWindows; + +#ifndef Z7_ST +static const UInt32 k_LZMA = 0x030101; +#endif + +static const UInt64 kComplexInCommands = (UInt64)1 << + #ifdef UNDER_CE + 31; + #else + 34; + #endif + +static const UInt32 kComplexInMs = 4000; + +static void SetComplexCommandsMs(UInt32 complexInMs, + bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands) +{ + complexInCommands = kComplexInCommands; + const UInt64 kMinFreq = (UInt64)1000000 * 4; + const UInt64 kMaxFreq = (UInt64)1000000 * 20000; + if (cpuFreq < kMinFreq && !isSpecifiedFreq) + cpuFreq = kMinFreq; + if (cpuFreq < kMaxFreq || isSpecifiedFreq) + { + if (complexInMs != 0) + complexInCommands = complexInMs * cpuFreq / 1000; + else + complexInCommands = cpuFreq >> 2; + } +} + +// const UInt64 kBenchmarkUsageMult = 1000000; // for debug +static const unsigned kBenchmarkUsageMultBits = 16; +static const UInt64 kBenchmarkUsageMult = 1 << kBenchmarkUsageMultBits; + +UInt64 Benchmark_GetUsage_Percents(UInt64 usage) +{ + return (100 * usage + kBenchmarkUsageMult / 2) / kBenchmarkUsageMult; +} + +static const unsigned kNumHashDictBits = 17; +static const UInt32 kFilterUnpackSize = (47 << 10); // + 5; // for test + +static const unsigned kOldLzmaDictBits = 32; + +// static const size_t kAdditionalSize = (size_t)1 << 32; // for debug +static const size_t kAdditionalSize = (size_t)1 << 16; +static const size_t kCompressedAdditionalSize = 1 << 10; + +static const UInt32 kMaxMethodPropSize = 1 << 6; + + +#define ALLOC_WITH_HRESULT(_buffer_, _size_) \ + { (_buffer_)->Alloc(_size_); \ + if (_size_ && !(_buffer_)->IsAllocated()) return E_OUTOFMEMORY; } + + +class CBaseRandomGenerator +{ + UInt32 A1; + UInt32 A2; + UInt32 Salt; +public: + CBaseRandomGenerator(UInt32 salt = 0): Salt(salt) { Init(); } + void Init() { A1 = 362436069; A2 = 521288629;} + Z7_FORCE_INLINE + UInt32 GetRnd() + { +#if 0 + // for debug: + return 0x0c080400; + // return 0; +#else + return Salt ^ + ( + ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) + + ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ) + ); +#endif + } +}; + + +static const size_t k_RandBuf_AlignMask = 4 - 1; + +Z7_NO_INLINE +static void RandGen_BufAfterPad(Byte *buf, size_t size) +{ + CBaseRandomGenerator RG; + for (size_t i = 0; i < size; i += 4) + { + const UInt32 v = RG.GetRnd(); + SetUi32a(buf + i, v) + } + /* + UInt32 v = RG.GetRnd(); + for (; i < size; i++) + { + buf[i] = (Byte)v; + v >>= 8; + } + */ +} + + +class CBenchRandomGenerator: public CMidAlignedBuffer +{ + static UInt32 GetVal(UInt32 &res, unsigned numBits) + { + const UInt32 val = res & (((UInt32)1 << numBits) - 1); + res >>= numBits; + return val; + } + + static UInt32 GetLen(UInt32 &r) + { + const unsigned len = (unsigned)GetVal(r, 2); + return GetVal(r, 1 + len); + } + +public: + + void GenerateSimpleRandom(UInt32 salt) + { + CBaseRandomGenerator rg(salt); + const size_t bufSize = Size(); + Byte *buf = (Byte *)*this; + for (size_t i = 0; i < bufSize; i++) + buf[i] = (Byte)rg.GetRnd(); + } + + void GenerateLz(unsigned dictBits, UInt32 salt) + { + CBaseRandomGenerator rg(salt); + size_t pos = 0; + size_t rep0 = 1; + const size_t bufSize = Size(); + Byte *buf = (Byte *)*this; + unsigned posBits = 1; + + // printf("\n dictBits = %d\n", (UInt32)dictBits); + // printf("\n bufSize = 0x%p\n", (const void *)bufSize); + + while (pos < bufSize) + { + /* + if (pos >= ((UInt32)1 << 31)) + printf(" %x\n", pos); + */ + UInt32 r = rg.GetRnd(); + if (GetVal(r, 1) == 0 || pos < 1024) + buf[pos++] = (Byte)(r & 0xFF); + else + { + UInt32 len; + len = 1 + GetLen(r); + + if (GetVal(r, 3) != 0) + { + len += GetLen(r); + + while (((size_t)1 << posBits) < pos) + posBits++; + + unsigned numBitsMax = dictBits; + if (numBitsMax > posBits) + numBitsMax = posBits; + + const unsigned kAddBits = 6; + unsigned numLogBits = 5; + if (numBitsMax <= (1 << 4) - 1 + kAddBits) + numLogBits = 4; + + for (;;) + { + const UInt32 ppp = GetVal(r, numLogBits) + kAddBits; + r = rg.GetRnd(); + if (ppp > numBitsMax) + continue; + // rep0 = GetVal(r, ppp); + rep0 = r & (((size_t)1 << ppp) - 1); + if (rep0 < pos) + break; + r = rg.GetRnd(); + } + rep0++; + } + + // len *= 300; // for debug + { + const size_t rem = bufSize - pos; + if (len > rem) + len = (UInt32)rem; + } + Byte *dest = buf + pos; + const Byte *src = dest - rep0; + pos += len; + for (UInt32 i = 0; i < len; i++) + *dest++ = *src++; + } + } + // printf("\n CRC = %x\n", CrcCalc(buf, bufSize)); + } +}; + + +Z7_CLASS_IMP_NOQIB_1( + CBenchmarkInStream + , ISequentialInStream +) + const Byte *Data; + size_t Pos; + size_t Size; +public: + void Init(const Byte *data, size_t size) + { + Data = data; + Size = size; + Pos = 0; + } + bool WasFinished() const { return Pos == Size; } +}; + +Z7_COM7F_IMF(CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) +{ + const UInt32 kMaxBlockSize = (1 << 20); + if (size > kMaxBlockSize) + size = kMaxBlockSize; + const size_t remain = Size - Pos; + if (size > remain) + size = (UInt32)remain; + + if (size) + memcpy(data, Data + Pos, size); + + Pos += size; + if (processedSize) + *processedSize = size; + return S_OK; +} + + +class CBenchmarkOutStream Z7_final: + public ISequentialOutStream, + public CMyUnknownImp, + public CMidAlignedBuffer +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ISequentialOutStream) + // bool _overflow; +public: + size_t Pos; + bool RealCopy; + bool CalcCrc; + UInt32 Crc; + + // CBenchmarkOutStream(): _overflow(false) {} + void Init(bool realCopy, bool calcCrc) + { + Crc = CRC_INIT_VAL; + RealCopy = realCopy; + CalcCrc = calcCrc; + // _overflow = false; + Pos = 0; + } + + void InitCrc() + { + Crc = CRC_INIT_VAL; + } + + void Calc(const void *data, size_t size) + { + Crc = CrcUpdate(Crc, data, size); + } + + size_t GetPos() const { return Pos; } + + // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); } +}; + +Z7_COM7F_IMF(CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + size_t curSize = Size() - Pos; + if (curSize > size) + curSize = size; + if (curSize != 0) + { + if (RealCopy) + memcpy(((Byte *)*this) + Pos, data, curSize); + if (CalcCrc) + Calc(data, curSize); + Pos += curSize; + } + if (processedSize) + *processedSize = (UInt32)curSize; + if (curSize != size) + { + // _overflow = true; + return E_FAIL; + } + return S_OK; +} + + +Z7_CLASS_IMP_NOQIB_1( + CCrcOutStream + , ISequentialOutStream +) +public: + bool CalcCrc; + UInt32 Crc; + UInt64 Pos; + + CCrcOutStream(): CalcCrc(true) {} + void Init() { Crc = CRC_INIT_VAL; Pos = 0; } + void Calc(const void *data, size_t size) + { + Crc = CrcUpdate(Crc, data, size); + } +}; + +Z7_COM7F_IMF(CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (CalcCrc) + Calc(data, size); + Pos += size; + if (processedSize) + *processedSize = size; + return S_OK; +} + +// #include "../../../../C/My_sys_time.h" + +static UInt64 GetTimeCount() +{ + #ifdef USE_POSIX_TIME + #ifdef USE_POSIX_TIME2 + timeval v; + if (gettimeofday(&v, NULL) == 0) + return (UInt64)(v.tv_sec) * 1000000 + (UInt64)v.tv_usec; + return (UInt64)time(NULL) * 1000000; + #else + return time(NULL); + #endif + #else + LARGE_INTEGER value; + if (::QueryPerformanceCounter(&value)) + return (UInt64)value.QuadPart; + return GetTickCount(); + #endif +} + +static UInt64 GetFreq() +{ + #ifdef USE_POSIX_TIME + #ifdef USE_POSIX_TIME2 + return 1000000; + #else + return 1; + #endif + #else + LARGE_INTEGER value; + if (::QueryPerformanceFrequency(&value)) + return (UInt64)value.QuadPart; + return 1000; + #endif +} + + +#ifdef USE_POSIX_TIME + +struct CUserTime +{ + UInt64 Sum; + clock_t Prev; + + void Init() + { + // Prev = clock(); + Sum = 0; + Prev = 0; + Update(); + Sum = 0; + } + + void Update() + { + tms t; + /* clock_t res = */ times(&t); + clock_t newVal = t.tms_utime + t.tms_stime; + Sum += (UInt64)(newVal - Prev); + Prev = newVal; + + /* + clock_t v = clock(); + if (v != -1) + { + Sum += v - Prev; + Prev = v; + } + */ + } + UInt64 GetUserTime() + { + Update(); + return Sum; + } +}; + +#else + + +struct CUserTime +{ + bool UseTick; + DWORD Prev_Tick; + UInt64 Prev; + UInt64 Sum; + + void Init() + { + UseTick = false; + Prev_Tick = 0; + Prev = 0; + Sum = 0; + Update(); + Sum = 0; + } + UInt64 GetUserTime() + { + Update(); + return Sum; + } + void Update(); +}; + +static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } + +void CUserTime::Update() +{ + DWORD new_Tick = GetTickCount(); + FILETIME creationTime, exitTime, kernelTime, userTime; + if (!UseTick && + #ifdef UNDER_CE + ::GetThreadTimes(::GetCurrentThread() + #else + ::GetProcessTimes(::GetCurrentProcess() + #endif + , &creationTime, &exitTime, &kernelTime, &userTime)) + { + UInt64 newVal = GetTime64(userTime) + GetTime64(kernelTime); + Sum += newVal - Prev; + Prev = newVal; + } + else + { + UseTick = true; + Sum += (UInt64)(new_Tick - (DWORD)Prev_Tick) * 10000; + } + Prev_Tick = new_Tick; +} + + +#endif + +static UInt64 GetUserFreq() +{ + #ifdef USE_POSIX_TIME + // return CLOCKS_PER_SEC; + return (UInt64)sysconf(_SC_CLK_TCK); + #else + return 10000000; + #endif +} + +class CBenchProgressStatus Z7_final +{ + #ifndef Z7_ST + NSynchronization::CCriticalSection CS; + #endif +public: + HRESULT Res; + bool EncodeMode; + void SetResult(HRESULT res) + { + #ifndef Z7_ST + NSynchronization::CCriticalSectionLock lock(CS); + #endif + Res = res; + } + HRESULT GetResult() + { + #ifndef Z7_ST + NSynchronization::CCriticalSectionLock lock(CS); + #endif + return Res; + } +}; + +struct CBenchInfoCalc +{ + CBenchInfo BenchInfo; + CUserTime UserTime; + + void SetStartTime(); + void SetFinishTime(CBenchInfo &dest); +}; + +void CBenchInfoCalc::SetStartTime() +{ + BenchInfo.GlobalFreq = GetFreq(); + BenchInfo.UserFreq = GetUserFreq(); + BenchInfo.GlobalTime = ::GetTimeCount(); + BenchInfo.UserTime = 0; + UserTime.Init(); +} + +void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest) +{ + dest = BenchInfo; + dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime; + dest.UserTime = UserTime.GetUserTime(); +} + +class CBenchProgressInfo Z7_final: + public ICompressProgressInfo, + public CMyUnknownImp, + public CBenchInfoCalc +{ + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ICompressProgressInfo) +public: + CBenchProgressStatus *Status; + IBenchCallback *Callback; + + CBenchProgressInfo(): Callback(NULL) {} +}; + + +Z7_COM7F_IMF(CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + HRESULT res = Status->GetResult(); + if (res != S_OK) + return res; + if (!Callback) + return res; + + /* + static UInt64 inSizePrev = 0; + static UInt64 outSizePrev = 0; + UInt64 delta1 = 0, delta2 = 0, val1 = 0, val2 = 0; + if (inSize) { val1 = *inSize; delta1 = val1 - inSizePrev; inSizePrev = val1; } + if (outSize) { val2 = *outSize; delta2 = val2 - outSizePrev; outSizePrev = val2; } + UInt64 percents = delta2 * 1000; + if (delta1 != 0) + percents /= delta1; + printf("=== %7d %7d %7d %7d ratio = %4d\n", + (unsigned)(val1 >> 10), (unsigned)(delta1 >> 10), + (unsigned)(val2 >> 10), (unsigned)(delta2 >> 10), + (unsigned)percents); + */ + + CBenchInfo info; + SetFinishTime(info); + if (Status->EncodeMode) + { + info.UnpackSize = BenchInfo.UnpackSize + *inSize; + info.PackSize = BenchInfo.PackSize + *outSize; + res = Callback->SetEncodeResult(info, false); + } + else + { + info.PackSize = BenchInfo.PackSize + *inSize; + info.UnpackSize = BenchInfo.UnpackSize + *outSize; + res = Callback->SetDecodeResult(info, false); + } + if (res != S_OK) + Status->SetResult(res); + return res; +} + +static const unsigned kSubBits = 8; + +static unsigned GetLogSize(UInt64 size) +{ + unsigned i = 0; + for (;;) + { + i++; size >>= 1; if (size == 0) break; + } + return i; +} + + +static UInt32 GetLogSize_Sub(UInt64 size) +{ + if (size <= 1) + return 0; + const unsigned i = GetLogSize(size) - 1; + UInt32 v; + if (i <= kSubBits) + v = (UInt32)(size) << (kSubBits - i); + else + v = (UInt32)(size >> (i - kSubBits)); + return ((UInt32)i << kSubBits) + (v & (((UInt32)1 << kSubBits) - 1)); +} + + +static UInt64 Get_UInt64_from_double(double v) +{ + const UInt64 kMaxVal = (UInt64)1 << 62; + if (v > (double)(Int64)kMaxVal) + return kMaxVal; + return (UInt64)v; +} + +static UInt64 MyMultDiv64(UInt64 m1, UInt64 m2, UInt64 d) +{ + if (d == 0) + d = 1; + const double v = + (double)(Int64)m1 * + (double)(Int64)m2 / + (double)(Int64)d; + return Get_UInt64_from_double(v); + /* + unsigned n1 = GetLogSize(m1); + unsigned n2 = GetLogSize(m2); + while (n1 + n2 > 64) + { + if (n1 >= n2) + { + m1 >>= 1; + n1--; + } + else + { + m2 >>= 1; + n2--; + } + d >>= 1; + } + + if (d == 0) + d = 1; + return m1 * m2 / d; + */ +} + + +UInt64 CBenchInfo::GetUsage() const +{ + UInt64 userTime = UserTime; + UInt64 userFreq = UserFreq; + UInt64 globalTime = GlobalTime; + UInt64 globalFreq = GlobalFreq; + + if (userFreq == 0) + userFreq = 1; + if (globalTime == 0) + globalTime = 1; + + const double v = + ((double)(Int64)userTime / (double)(Int64)userFreq) + * ((double)(Int64)globalFreq / (double)(Int64)globalTime) + * (double)(Int64)kBenchmarkUsageMult; + return Get_UInt64_from_double(v); + /* + return MyMultDiv64( + MyMultDiv64(kBenchmarkUsageMult, userTime, userFreq), + globalFreq, globalTime); + */ +} + + +UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const +{ + if (UserTime == 0) + { + return 0; + // userTime = 1; + } + UInt64 globalFreq = GlobalFreq; + if (globalFreq == 0) + globalFreq = 1; + + const double v = + ((double)(Int64)GlobalTime / (double)(Int64)globalFreq) + * ((double)(Int64)UserFreq / (double)(Int64)UserTime) + * (double)(Int64)rating; + return Get_UInt64_from_double(v); + /* + return MyMultDiv64( + MyMultDiv64(rating, UserFreq, UserTime), + GlobalTime, globalFreq); + */ +} + + +UInt64 CBenchInfo::GetSpeed(UInt64 numUnits) const +{ + return MyMultDiv64(numUnits, GlobalFreq, GlobalTime); +} + +static UInt64 GetNumCommands_from_Size_and_Complexity(UInt64 size, Int32 complexity) +{ + return complexity >= 0 ? + size * (UInt32)complexity : + size / (UInt32)(-complexity); +} + +struct CBenchProps +{ + bool LzmaRatingMode; + + Int32 EncComplex; + Int32 DecComplexCompr; + Int32 DecComplexUnc; + + unsigned KeySize; + + CBenchProps(): + LzmaRatingMode(false), + KeySize(0) + {} + + void SetLzmaCompexity(); + + UInt64 GetNumCommands_Enc(UInt64 unpackSize) const + { + const UInt32 kMinSize = 100; + if (unpackSize < kMinSize) + unpackSize = kMinSize; + return GetNumCommands_from_Size_and_Complexity(unpackSize, EncComplex); + } + + UInt64 GetNumCommands_Dec(UInt64 packSize, UInt64 unpackSize) const + { + return + GetNumCommands_from_Size_and_Complexity(packSize, DecComplexCompr) + + GetNumCommands_from_Size_and_Complexity(unpackSize, DecComplexUnc); + } + + UInt64 GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const; + UInt64 GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const; +}; + +void CBenchProps::SetLzmaCompexity() +{ + EncComplex = 1200; + DecComplexUnc = 4; + DecComplexCompr = 190; + LzmaRatingMode = true; +} + +UInt64 CBenchProps::GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const +{ + if (dictSize < (1 << kBenchMinDicLogSize)) + dictSize = (1 << kBenchMinDicLogSize); + Int32 encComplex = EncComplex; + if (LzmaRatingMode) + { + /* + for (UInt64 uu = 0; uu < (UInt64)0xf << 60;) + { + unsigned rr = GetLogSize_Sub(uu); + printf("\n%16I64x , log = %4x", uu, rr); + uu += 1; + uu += uu / 50; + } + */ + // throw 1; + const UInt32 t = GetLogSize_Sub(dictSize) - (kBenchMinDicLogSize << kSubBits); + encComplex = 870 + ((t * t * 5) >> (2 * kSubBits)); + } + const UInt64 numCommands = GetNumCommands_from_Size_and_Complexity(size, encComplex); + return MyMultDiv64(numCommands, freq, elapsedTime); +} + +UInt64 CBenchProps::GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const +{ + const UInt64 numCommands = GetNumCommands_Dec(inSize, outSize) * numIterations; + return MyMultDiv64(numCommands, freq, elapsedTime); +} + + + +UInt64 CBenchInfo::GetRating_LzmaEnc(UInt64 dictSize) const +{ + CBenchProps props; + props.SetLzmaCompexity(); + return props.GetRating_Enc(dictSize, GlobalTime, GlobalFreq, UnpackSize * NumIterations); +} + +UInt64 CBenchInfo::GetRating_LzmaDec() const +{ + CBenchProps props; + props.SetLzmaCompexity(); + return props.GetRating_Dec(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations); +} + + +#ifndef Z7_ST + +#define NUM_CPU_LEVELS_MAX 3 + +struct CAffinityMode +{ + unsigned NumBundleThreads; + unsigned NumLevels; + unsigned NumCoreThreads; + unsigned NumCores; + // unsigned DivideNum; + UInt32 Sizes[NUM_CPU_LEVELS_MAX]; + + void SetLevels(unsigned numCores, unsigned numCoreThreads); + DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; + bool NeedAffinity() const { return NumBundleThreads != 0; } + + WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const + { + if (NeedAffinity()) + { + CCpuSet cpuSet; + GetAffinityMask(bundleIndex, &cpuSet); + return thread.Create_With_CpuSet(startAddress, parameter, &cpuSet); + } + return thread.Create(startAddress, parameter); + } + + CAffinityMode(): + NumBundleThreads(0), + NumLevels(0), + NumCoreThreads(1) + // DivideNum(1) + {} +}; + +void CAffinityMode::SetLevels(unsigned numCores, unsigned numCoreThreads) +{ + NumCores = numCores; + NumCoreThreads = numCoreThreads; + NumLevels = 0; + if (numCoreThreads == 0 || numCores == 0 || numCores % numCoreThreads != 0) + return; + UInt32 c = numCores / numCoreThreads; + UInt32 c2 = 1; + while ((c & 1) == 0) + { + c >>= 1; + c2 <<= 1; + } + if (c2 != 1) + Sizes[NumLevels++] = c2; + if (c != 1) + Sizes[NumLevels++] = c; + if (numCoreThreads != 1) + Sizes[NumLevels++] = numCoreThreads; + if (NumLevels == 0) + Sizes[NumLevels++] = 1; + + /* + printf("\n Cores:"); + for (unsigned i = 0; i < NumLevels; i++) + { + printf(" %d", Sizes[i]); + } + printf("\n"); + */ +} + + +DWORD_PTR CAffinityMode::GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const +{ + CpuSet_Zero(cpuSet); + + if (NumLevels == 0) + return 0; + + // printf("\n%2d", bundleIndex); + + /* + UInt32 low = 0; + if (DivideNum != 1) + { + low = bundleIndex % DivideNum; + bundleIndex /= DivideNum; + } + */ + + UInt32 numGroups = NumCores / NumBundleThreads; + UInt32 m = bundleIndex % numGroups; + UInt32 v = 0; + for (unsigned i = 0; i < NumLevels; i++) + { + UInt32 size = Sizes[i]; + while ((size & 1) == 0) + { + v *= 2; + v |= (m & 1); + m >>= 1; + size >>= 1; + } + v *= size; + v += m % size; + m /= size; + } + + // UInt32 nb = NumBundleThreads / DivideNum; + UInt32 nb = NumBundleThreads; + + DWORD_PTR mask = ((DWORD_PTR)1 << nb) - 1; + // v += low; + mask <<= v; + + // printf(" %2d %8x \n ", v, (unsigned)mask); + #ifdef _WIN32 + *cpuSet = mask; + #else + { + for (unsigned k = 0; k < nb; k++) + CpuSet_Set(cpuSet, v + k); + } + #endif + + return mask; +} + + +struct CBenchSyncCommon +{ + bool ExitMode; + NSynchronization::CManualResetEvent StartEvent; + + CBenchSyncCommon(): ExitMode(false) {} +}; + +#endif + + + +enum E_CheckCrcMode +{ + k_CheckCrcMode_Never = 0, + k_CheckCrcMode_Always = 1, + k_CheckCrcMode_FirstPass = 2 +}; + +class CEncoderInfo; + +class CEncoderInfo Z7_final +{ + Z7_CLASS_NO_COPY(CEncoderInfo) + +public: + + #ifndef Z7_ST + NWindows::CThread thread[2]; + NSynchronization::CManualResetEvent ReadyEvent; + UInt32 NumDecoderSubThreads; + CBenchSyncCommon *Common; + UInt32 EncoderIndex; + UInt32 NumEncoderInternalThreads; + CAffinityMode AffinityMode; + bool IsGlobalMtMode; // if more than one benchmark encoder threads + #endif + + CMyComPtr _encoder; + CMyComPtr _encoderFilter; + CBenchProgressInfo *progressInfoSpec[2]; + CMyComPtr progressInfo[2]; + UInt64 NumIterations; + + UInt32 Salt; + + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + + unsigned KeySize; + Byte _key[32]; + Byte _iv[16]; + + HRESULT Set_Key_and_IV(ICryptoProperties *cp) + { + RINOK(cp->SetKey(_key, KeySize)) + return cp->SetInitVector(_iv, sizeof(_iv)); + } + + Byte _psw[16]; + + bool CheckCrc_Enc; /* = 1, if we want to check packed data crcs after each pass + used for filter and usual coders */ + bool UseRealData_Enc; /* = 1, if we want to use only original data for each pass + used only for filter */ + E_CheckCrcMode CheckCrcMode_Dec; + + struct CDecoderInfo + { + CEncoderInfo *Encoder; + UInt32 DecoderIndex; + bool CallbackMode; + + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + }; + CDecoderInfo decodersInfo[2]; + + CMyComPtr _decoders[2]; + CMyComPtr _decoderFilter; + + HRESULT Results[2]; + CBenchmarkOutStream *outStreamSpec; + CMyComPtr outStream; + IBenchCallback *callback; + IBenchPrintCallback *printCallback; + UInt32 crc; + size_t kBufferSize; + size_t compressedSize; + const Byte *uncompressedDataPtr; + + const Byte *fileData; + CBenchRandomGenerator rg; + + CMidAlignedBuffer rgCopy; // it must be 16-byte aligned !!! + + // CBenchmarkOutStream *propStreamSpec; + Byte propsData[kMaxMethodPropSize]; + CBufPtrSeqOutStream *propStreamSpec; + CMyComPtr propStream; + + unsigned generateDictBits; + COneMethodInfo _method; + + // for decode + size_t _uncompressedDataSize; + + HRESULT Generate(); + HRESULT Encode(); + HRESULT Decode(UInt32 decoderIndex); + + CEncoderInfo(): + #ifndef Z7_ST + Common(NULL), + IsGlobalMtMode(true), + #endif + Salt(0), + KeySize(0), + CheckCrc_Enc(true), + UseRealData_Enc(true), + CheckCrcMode_Dec(k_CheckCrcMode_Always), + outStreamSpec(NULL), + callback(NULL), + printCallback(NULL), + fileData(NULL), + propStreamSpec(NULL) + {} + + #ifndef Z7_ST + + static THREAD_FUNC_DECL EncodeThreadFunction(void *param) + { + HRESULT res; + CEncoderInfo *encoder = (CEncoderInfo *)param; + try + { + #ifdef USE_ALLOCA + alloca(encoder->AllocaSize); + #endif + + res = encoder->Encode(); + } + catch(...) + { + res = E_FAIL; + } + encoder->Results[0] = res; + if (res != S_OK) + encoder->progressInfoSpec[0]->Status->SetResult(res); + encoder->ReadyEvent.Set(); + return THREAD_FUNC_RET_ZERO; + } + + static THREAD_FUNC_DECL DecodeThreadFunction(void *param) + { + CDecoderInfo *decoder = (CDecoderInfo *)param; + + #ifdef USE_ALLOCA + alloca(decoder->AllocaSize); + // printf("\nalloca=%d\n", (unsigned)decoder->AllocaSize); + #endif + + CEncoderInfo *encoder = decoder->Encoder; + encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex); + return THREAD_FUNC_RET_ZERO; + } + + HRESULT CreateEncoderThread() + { + WRes res = 0; + if (!ReadyEvent.IsCreated()) + res = ReadyEvent.Create(); + if (res == 0) + res = AffinityMode.CreateThread_WithAffinity(thread[0], EncodeThreadFunction, this, + EncoderIndex); + return HRESULT_FROM_WIN32(res); + } + + HRESULT CreateDecoderThread(unsigned index, bool callbackMode + #ifdef USE_ALLOCA + , size_t allocaSize + #endif + ) + { + CDecoderInfo &decoder = decodersInfo[index]; + decoder.DecoderIndex = index; + decoder.Encoder = this; + + #ifdef USE_ALLOCA + decoder.AllocaSize = allocaSize; + #endif + + decoder.CallbackMode = callbackMode; + + WRes res = AffinityMode.CreateThread_WithAffinity(thread[index], DecodeThreadFunction, &decoder, + // EncoderIndex * NumEncoderInternalThreads + index + EncoderIndex + ); + + return HRESULT_FROM_WIN32(res); + } + + #endif +}; + + + + +static size_t GetBenchCompressedSize(size_t bufferSize) +{ + return kCompressedAdditionalSize + bufferSize + bufferSize / 16; + // kBufferSize / 2; +} + + +HRESULT CEncoderInfo::Generate() +{ + const COneMethodInfo &method = _method; + + // we need extra space, if input data is already compressed + const size_t kCompressedBufferSize = _encoderFilter ? + kBufferSize : + GetBenchCompressedSize(kBufferSize); + + if (kCompressedBufferSize < kBufferSize) + return E_FAIL; + + uncompressedDataPtr = fileData; + if (fileData) + { + #if !defined(Z7_ST) + if (IsGlobalMtMode) + { + /* we copy the data to local buffer of thread to eliminate + using of shared buffer by different threads */ + ALLOC_WITH_HRESULT(&rg, kBufferSize) + memcpy((Byte *)rg, fileData, kBufferSize); + uncompressedDataPtr = (const Byte *)rg; + } + #endif + } + else + { + ALLOC_WITH_HRESULT(&rg, kBufferSize) + // DWORD ttt = GetTickCount(); + if (generateDictBits == 0) + rg.GenerateSimpleRandom(Salt); + else + { + if (generateDictBits >= sizeof(size_t) * 8 + && kBufferSize > ((size_t)1 << (sizeof(size_t) * 8 - 1))) + return E_INVALIDARG; + rg.GenerateLz(generateDictBits, Salt); + // return E_ABORT; // for debug + } + // printf("\n%d\n ", GetTickCount() - ttt); + + crc = CrcCalc((const Byte *)rg, rg.Size()); + uncompressedDataPtr = (const Byte *)rg; + } + + if (!outStream) + { + outStreamSpec = new CBenchmarkOutStream; + outStream = outStreamSpec; + } + + ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize) + + if (_encoderFilter) + { + /* we try to reduce the number of memcpy() in main encoding loop. + so we copy data to temp buffers here */ + ALLOC_WITH_HRESULT(&rgCopy, kBufferSize) + memcpy((Byte *)*outStreamSpec, uncompressedDataPtr, kBufferSize); + memcpy((Byte *)rgCopy, uncompressedDataPtr, kBufferSize); + } + + if (!propStream) + { + propStreamSpec = new CBufPtrSeqOutStream; // CBenchmarkOutStream; + propStream = propStreamSpec; + } + // ALLOC_WITH_HRESULT_2(propStreamSpec, kMaxMethodPropSize); + // propStreamSpec->Init(true, false); + propStreamSpec->Init(propsData, sizeof(propsData)); + + + CMyComPtr coder; + if (_encoderFilter) + coder = _encoderFilter; + else + coder = _encoder; + { + CMyComPtr scp; + coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + const UInt64 reduceSize = kBufferSize; + + /* in posix new thread uses same affinity as parent thread, + so we don't need to send affinity to coder in posix */ + UInt64 affMask; + #if !defined(Z7_ST) && defined(_WIN32) + { + CCpuSet cpuSet; + affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); + } + #else + affMask = 0; + #endif + // affMask <<= 3; // debug line: to test no affinity in coder; + // affMask = 0; + + RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL))) + } + else + { + if (method.AreThereNonOptionalProps()) + return E_INVALIDARG; + } + + CMyComPtr writeCoderProps; + coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps); + if (writeCoderProps) + { + RINOK(writeCoderProps->WriteCoderProperties(propStream)) + } + + { + CMyComPtr sp; + coder.QueryInterface(IID_ICryptoSetPassword, &sp); + if (sp) + { + RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))) + + // we must call encoding one time to calculate password key for key cache. + // it must be after WriteCoderProperties! + Byte temp[16]; + memset(temp, 0, sizeof(temp)); + + if (_encoderFilter) + { + _encoderFilter->Init(); + _encoderFilter->Filter(temp, sizeof(temp)); + } + else + { + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr inStream = inStreamSpec; + inStreamSpec->Init(temp, sizeof(temp)); + + CCrcOutStream *crcStreamSpec = new CCrcOutStream; + CMyComPtr crcStream = crcStreamSpec; + crcStreamSpec->Init(); + + RINOK(_encoder->Code(inStream, crcStream, NULL, NULL, NULL)) + } + } + } + } + + return S_OK; +} + + +static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size, UInt32 *crc) +{ + while (size != 0) + { + UInt32 cur = crc ? 1 << 17 : 1 << 24; + if (cur > size) + cur = (UInt32)size; + UInt32 processed = filter->Filter(data, cur); + /* if (processed > size) (in AES filter), we must fill last block with zeros. + but it is not important for benchmark. So we just copy that data without filtering. + if (processed == 0) then filter can't process more */ + if (processed > size || processed == 0) + processed = (UInt32)size; + if (crc) + *crc = CrcUpdate(*crc, data, processed); + data += processed; + size -= processed; + } +} + + +HRESULT CEncoderInfo::Encode() +{ + // printf("\nCEncoderInfo::Generate\n"); + + RINOK(Generate()) + + // printf("\n2222\n"); + + #ifndef Z7_ST + if (Common) + { + Results[0] = S_OK; + WRes wres = ReadyEvent.Set(); + if (wres == 0) + wres = Common->StartEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + if (Common->ExitMode) + return S_OK; + } + else + #endif + { + CBenchProgressInfo *bpi = progressInfoSpec[0]; + bpi->SetStartTime(); + } + + + CBenchInfo &bi = progressInfoSpec[0]->BenchInfo; + bi.UnpackSize = 0; + bi.PackSize = 0; + CMyComPtr cp; + CMyComPtr coder; + if (_encoderFilter) + coder = _encoderFilter; + else + coder = _encoder; + coder.QueryInterface(IID_ICryptoProperties, &cp); + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr inStream = inStreamSpec; + + if (cp) + { + RINOK(Set_Key_and_IV(cp)) + } + + compressedSize = 0; + if (_encoderFilter) + compressedSize = kBufferSize; + + // CBenchmarkOutStream *outStreamSpec = this->outStreamSpec; + UInt64 prev = 0; + + const UInt32 mask = (CheckCrc_Enc ? 0 : 0xFFFF); + const bool useCrc = (mask < NumIterations); + bool crcPrev_defined = false; + UInt32 crcPrev = 0; + + bool useRealData_Enc = UseRealData_Enc; + bool data_Was_Changed = false; + if (useRealData_Enc) + { + /* we want memcpy() for each iteration including first iteration. + So results will be equal for different number of iterations */ + data_Was_Changed = true; + } + + const UInt64 numIterations = NumIterations; + UInt64 i = numIterations; + // printCallback->NewLine(); + + while (i != 0) + { + i--; + if (printCallback && bi.UnpackSize - prev >= (1 << 26)) + { + prev = bi.UnpackSize; + RINOK(printCallback->CheckBreak()) + } + + /* + CBenchInfo info; + progressInfoSpec[0]->SetStartTime(); + */ + + bool calcCrc = false; + if (useCrc) + calcCrc = (((UInt32)i & mask) == 0); + + if (_encoderFilter) + { + Byte *filterData = rgCopy; + if (i == numIterations - 1 || calcCrc || useRealData_Enc) + { + // printf("\nfilterData = (Byte *)*outStreamSpec;\n"); + filterData = (Byte *)*outStreamSpec; + if (data_Was_Changed) + { + // printf("\nmemcpy(filterData, uncompressedDataPtr\n"); + memcpy(filterData, uncompressedDataPtr, kBufferSize); + } + data_Was_Changed = true; + } + _encoderFilter->Init(); + if (calcCrc) + { + // printf("\nInitCrc\n"); + outStreamSpec->InitCrc(); + } + // printf("\nMy_FilterBench\n"); + My_FilterBench(_encoderFilter, filterData, kBufferSize, + calcCrc ? &outStreamSpec->Crc : NULL); + } + else + { + outStreamSpec->Init(true, calcCrc); // write real data for speed consistency at any number of iterations + inStreamSpec->Init(uncompressedDataPtr, kBufferSize); + RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0])) + if (!inStreamSpec->WasFinished()) + return E_FAIL; + if (compressedSize != outStreamSpec->Pos) + { + if (compressedSize != 0) + return E_FAIL; + compressedSize = outStreamSpec->Pos; + } + } + + // outStreamSpec->Print(); + + if (calcCrc) + { + const UInt32 crc2 = CRC_GET_DIGEST(outStreamSpec->Crc); + if (crcPrev_defined && crcPrev != crc2) + return E_FAIL; + crcPrev = crc2; + crcPrev_defined = true; + } + + bi.UnpackSize += kBufferSize; + bi.PackSize += compressedSize; + + /* + { + progressInfoSpec[0]->SetFinishTime(info); + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = 1; + + info.UnpackSize = kBufferSize; + info.PackSize = compressedSize; + // printf("\n%7d\n", encoder.compressedSize); + + RINOK(callback->SetEncodeResult(info, true)) + printCallback->NewLine(); + } + */ + + } + + _encoder.Release(); + _encoderFilter.Release(); + return S_OK; +} + + +HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) +{ + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr inStream = inStreamSpec; + CMyComPtr &decoder = _decoders[decoderIndex]; + CMyComPtr coder; + if (_decoderFilter) + { + if (decoderIndex != 0) + return E_FAIL; + coder = _decoderFilter; + } + else + coder = decoder; + + // printf("\ndecoderIndex = %d, stack = %p", decoderIndex, &coder); + + CMyComPtr setDecProps; + coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps); + if (!setDecProps && propStreamSpec->GetPos() != 0) + return E_FAIL; + + CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; + CMyComPtr crcOutStream = crcOutStreamSpec; + + CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; + pi->BenchInfo.UnpackSize = 0; + pi->BenchInfo.PackSize = 0; + + #ifndef Z7_ST + { + CMyComPtr setCoderMt; + coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)) + } + } + #endif + + CMyComPtr scp; + coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + const UInt64 reduceSize = _uncompressedDataSize; + RINOK(_method.SetCoderProps(scp, &reduceSize)) + } + + CMyComPtr cp; + coder.QueryInterface(IID_ICryptoProperties, &cp); + + if (setDecProps) + { + RINOK(setDecProps->SetDecoderProperties2( + /* (const Byte *)*propStreamSpec, */ + propsData, + (UInt32)propStreamSpec->GetPos())) + } + + { + CMyComPtr sp; + coder.QueryInterface(IID_ICryptoSetPassword, &sp); + if (sp) + { + RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))) + } + } + + UInt64 prev = 0; + + if (cp) + { + RINOK(Set_Key_and_IV(cp)) + } + + CMyComPtr setFinishMode; + + if (_decoderFilter) + { + if (compressedSize > rgCopy.Size()) + return E_FAIL; + } + else + { + decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + } + + const UInt64 numIterations = NumIterations; + const E_CheckCrcMode checkCrcMode = CheckCrcMode_Dec; + + for (UInt64 i = 0; i < numIterations; i++) + { + if (printCallback && pi->BenchInfo.UnpackSize - prev >= (1 << 26)) + { + RINOK(printCallback->CheckBreak()) + prev = pi->BenchInfo.UnpackSize; + } + + const UInt64 outSize = kBufferSize; + bool calcCrc = (checkCrcMode != k_CheckCrcMode_Never); + + crcOutStreamSpec->Init(); + + if (_decoderFilter) + { + Byte *filterData = (Byte *)*outStreamSpec; + if (calcCrc) + { + calcCrc = (i == 0); + if (checkCrcMode == k_CheckCrcMode_Always) + { + calcCrc = true; + memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize); + filterData = rgCopy; + } + } + _decoderFilter->Init(); + My_FilterBench(_decoderFilter, filterData, compressedSize, + calcCrc ? &crcOutStreamSpec->Crc : NULL); + } + else + { + crcOutStreamSpec->CalcCrc = calcCrc; + inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize); + + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToUInt(true))) + } + + RINOK(decoder->Code(inStream, crcOutStream, NULL, &outSize, progressInfo[decoderIndex])) + + if (setFinishMode) + { + if (!inStreamSpec->WasFinished()) + return S_FALSE; + + CMyComPtr getInStreamProcessedSize; + decoder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); + + if (getInStreamProcessedSize) + { + UInt64 processed; + RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) + if (processed != compressedSize) + return S_FALSE; + } + } + + if (crcOutStreamSpec->Pos != outSize) + return S_FALSE; + } + + if (calcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) + return S_FALSE; + + pi->BenchInfo.UnpackSize += kBufferSize; + pi->BenchInfo.PackSize += compressedSize; + } + + decoder.Release(); + _decoderFilter.Release(); + return S_OK; +} + + +static const UInt32 kNumThreadsMax = (1 << 12); + +struct CBenchEncoders +{ + CEncoderInfo *encoders; + CBenchEncoders(UInt32 num): encoders(NULL) { encoders = new CEncoderInfo[num]; } + ~CBenchEncoders() { delete []encoders; } +}; + + +static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands) +{ + if (numCommands < (1 << 4)) + numCommands = (1 << 4); + UInt64 res = complexInCommands / numCommands; + return (res == 0 ? 1 : res); +} + + + +#ifndef Z7_ST + +// ---------- CBenchThreadsFlusher ---------- + +struct CBenchThreadsFlusher +{ + CBenchEncoders *EncodersSpec; + CBenchSyncCommon Common; + unsigned NumThreads; + bool NeedClose; + + CBenchThreadsFlusher(): NumThreads(0), NeedClose(false) {} + + ~CBenchThreadsFlusher() + { + StartAndWait(true); + } + + WRes StartAndWait(bool exitMode = false); +}; + + +WRes CBenchThreadsFlusher::StartAndWait(bool exitMode) +{ + if (!NeedClose) + return 0; + + Common.ExitMode = exitMode; + WRes res = Common.StartEvent.Set(); + + for (unsigned i = 0; i < NumThreads; i++) + { + NWindows::CThread &t = EncodersSpec->encoders[i].thread[0]; + if (t.IsCreated()) + { + WRes res2 = t.Wait_Close(); + if (res == 0) + res = res2; + } + } + NeedClose = false; + return res; +} + +#endif // Z7_ST + + + +static void SetPseudoRand(Byte *data, size_t size, UInt32 startValue) +{ + for (size_t i = 0; i < size; i++) + { + data[i] = (Byte)startValue; + startValue++; + } +} + + + +static HRESULT MethodBench( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 complexInCommands, + #ifndef Z7_ST + bool oldLzmaBenchMode, + UInt32 numThreads, + const CAffinityMode *affinityMode, + #endif + const COneMethodInfo &method2, + size_t uncompressedDataSize, + const Byte *fileData, + unsigned generateDictBits, + + IBenchPrintCallback *printCallback, + IBenchCallback *callback, + CBenchProps *benchProps) +{ + COneMethodInfo method = method2; + UInt64 methodId; + UInt32 numStreams; + bool isFilter; + const int codecIndex = FindMethod_Index( + EXTERNAL_CODECS_LOC_VARS + method.MethodName, true, + methodId, numStreams, isFilter); + if (codecIndex < 0) + return E_NOTIMPL; + if (numStreams != 1) + return E_INVALIDARG; + + UInt32 numEncoderThreads = 1; + UInt32 numSubDecoderThreads = 1; + + #ifndef Z7_ST + numEncoderThreads = numThreads; + + if (oldLzmaBenchMode) + if (methodId == k_LZMA) + { + if (numThreads == 1 && method.Get_NumThreads() < 0) + method.AddProp_NumThreads(1); + const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(); + if (numThreads > 1 && numLzmaThreads > 1) + { + numEncoderThreads = (numThreads + 1) / 2; // 20.03 + numSubDecoderThreads = 2; + } + } + + const bool mtEncMode = (numEncoderThreads > 1) || affinityMode->NeedAffinity(); + + #endif + + CBenchEncoders encodersSpec(numEncoderThreads); + CEncoderInfo *encoders = encodersSpec.encoders; + + UInt32 i; + + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.callback = (i == 0) ? callback : NULL; + encoder.printCallback = printCallback; + + #ifndef Z7_ST + encoder.EncoderIndex = i; + encoder.NumEncoderInternalThreads = numSubDecoderThreads; + encoder.AffinityMode = *affinityMode; + + /* + if (numSubDecoderThreads > 1) + if (encoder.AffinityMode.NeedAffinity() + && encoder.AffinityMode.NumBundleThreads == 1) + { + // if old LZMA benchmark uses two threads in coder, we increase (NumBundleThreads) for old LZMA benchmark uses two threads instead of one + if (encoder.AffinityMode.NumBundleThreads * 2 <= encoder.AffinityMode.NumCores) + encoder.AffinityMode.NumBundleThreads *= 2; + } + */ + + #endif + + { + CCreatedCoder cod; + RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)codecIndex, true, encoder._encoderFilter, cod)) + encoder._encoder = cod.Coder; + if (!encoder._encoder && !encoder._encoderFilter) + return E_NOTIMPL; + } + + SetPseudoRand(encoder._iv, sizeof(encoder._iv), 17); + SetPseudoRand(encoder._key, sizeof(encoder._key), 51); + SetPseudoRand(encoder._psw, sizeof(encoder._psw), 123); + + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + CCreatedCoder cod; + CMyComPtr &decoder = encoder._decoders[j]; + RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod)) + decoder = cod.Coder; + if (!encoder._decoderFilter && !decoder) + return E_NOTIMPL; + } + + encoder.UseRealData_Enc = + encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30; + + encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always; + if (benchProps->DecComplexCompr + + benchProps->DecComplexUnc <= 30) + encoder.CheckCrcMode_Dec = + k_CheckCrcMode_FirstPass; // for filters + // k_CheckCrcMode_Never; // for debug + // k_CheckCrcMode_Always; // for debug + if (fileData) + { + encoder.UseRealData_Enc = true; + encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always; + } + } + + UInt32 crc = 0; + if (fileData) + crc = CrcCalc(fileData, uncompressedDataSize); + + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder._method = method; + encoder.generateDictBits = generateDictBits; + encoder._uncompressedDataSize = uncompressedDataSize; + encoder.kBufferSize = uncompressedDataSize; + encoder.fileData = fileData; + encoder.crc = crc; + } + + CBenchProgressStatus status; + status.Res = S_OK; + status.EncodeMode = true; + + #ifndef Z7_ST + CBenchThreadsFlusher encoderFlusher; + if (mtEncMode) + { + WRes wres = encoderFlusher.Common.StartEvent.Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + encoderFlusher.NumThreads = numEncoderThreads; + encoderFlusher.EncodersSpec = &encodersSpec; + encoderFlusher.NeedClose = true; + } + #endif + + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.NumIterations = GetNumIterations(benchProps->GetNumCommands_Enc(uncompressedDataSize), complexInCommands); + // encoder.NumIterations = 3; + { +#if 0 + #define kCrcPoly 0xEDB88320 + UInt32 r = i; + unsigned num = numEncoderThreads < 256 ? 8 : 16; + do + r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1))); + while (--num); + encoder.Salt = r; +#else + UInt32 salt0 = g_CrcTable[(Byte)i]; + UInt32 salt1 = g_CrcTable[(Byte)(i >> 8)]; + encoder.Salt = salt0 ^ (salt1 << 3); +#endif + } + + // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread + // printf("\n encoder index = %d, Salt = %8x\n", i, encoder.Salt); + + encoder.KeySize = benchProps->KeySize; + + for (int j = 0; j < 2; j++) + { + CBenchProgressInfo *spec = new CBenchProgressInfo; + encoder.progressInfoSpec[j] = spec; + encoder.progressInfo[j] = spec; + spec->Status = &status; + } + + if (i == 0) + { + CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; + bpi->Callback = callback; + bpi->BenchInfo.NumIterations = numEncoderThreads; + } + + #ifndef Z7_ST + if (mtEncMode) + { + #ifdef USE_ALLOCA + encoder.AllocaSize = BENCH_ALLOCA_VALUE(i); + #endif + + encoder.Common = &encoderFlusher.Common; + encoder.IsGlobalMtMode = numEncoderThreads > 1; + RINOK(encoder.CreateEncoderThread()) + } + #endif + } + + if (printCallback) + { + RINOK(printCallback->CheckBreak()) + } + + #ifndef Z7_ST + if (mtEncMode) + { + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + const WRes wres = encoder.ReadyEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(encoder.Results[0]) + } + + CBenchProgressInfo *bpi = encoders[0].progressInfoSpec[0]; + bpi->SetStartTime(); + + const WRes wres = encoderFlusher.StartAndWait(); + if (status.Res == 0 && wres != 0) + return HRESULT_FROM_WIN32(wres); + } + else + #endif + { + RINOK(encoders[0].Encode()) + } + + RINOK(status.Res) + + CBenchInfo info; + + encoders[0].progressInfoSpec[0]->SetFinishTime(info); + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = encoders[0].NumIterations; + + for (i = 0; i < numEncoderThreads; i++) + { + const CEncoderInfo &encoder = encoders[i]; + info.UnpackSize += encoder.kBufferSize; + info.PackSize += encoder.compressedSize; + // printf("\n%7d\n", encoder.compressedSize); + } + + RINOK(callback->SetEncodeResult(info, true)) + + + + + // ---------- Decode ---------- + + status.Res = S_OK; + status.EncodeMode = false; + + const UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + #ifndef Z7_ST + const bool mtDecoderMode = (numDecoderThreads > 1) || affinityMode->NeedAffinity(); + #endif + + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + + /* + #ifndef Z7_ST + // encoder.affinityMode = *affinityMode; + if (encoder.NumEncoderInternalThreads != 1) + encoder.AffinityMode.DivideNum = encoder.NumEncoderInternalThreads; + #endif + */ + + + if (i == 0) + { + encoder.NumIterations = GetNumIterations( + benchProps->GetNumCommands_Dec( + encoder.compressedSize, + encoder.kBufferSize), + complexInCommands); + CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; + bpi->Callback = callback; + bpi->BenchInfo.NumIterations = numDecoderThreads; + bpi->SetStartTime(); + } + else + encoder.NumIterations = encoders[0].NumIterations; + + #ifndef Z7_ST + { + const int numSubThreads = method.Get_NumThreads(); + encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : (unsigned)numSubThreads; + } + if (mtDecoderMode) + { + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + const HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) + #ifdef USE_ALLOCA + , BENCH_ALLOCA_VALUE(i * numSubDecoderThreads + j) + #endif + ); + RINOK(res) + } + } + else + #endif + { + RINOK(encoder.Decode(0)) + } + } + + #ifndef Z7_ST + if (mtDecoderMode) + { + WRes wres = 0; + HRESULT res = S_OK; + for (i = 0; i < numEncoderThreads; i++) + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + CEncoderInfo &encoder = encoders[i]; + const WRes wres2 = encoder.thread[j]. + // Wait(); // later we can get thread times from thread in UNDER_CE + Wait_Close(); + if (wres == 0 && wres2 != 0) + wres = wres2; + const HRESULT res2 = encoder.Results[j]; + if (res == 0 && res2 != 0) + res = res2; + } + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(res) + } + #endif // Z7_ST + + RINOK(status.Res) + encoders[0].progressInfoSpec[0]->SetFinishTime(info); + + /* + #ifndef Z7_ST + #ifdef UNDER_CE + if (mtDecoderMode) + for (i = 0; i < numEncoderThreads; i++) + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + FILETIME creationTime, exitTime, kernelTime, userTime; + if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0) + info.UserTime += GetTime64(userTime) + GetTime64(kernelTime); + } + #endif + #endif + */ + + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations; + + for (i = 0; i < numEncoderThreads; i++) + { + const CEncoderInfo &encoder = encoders[i]; + info.UnpackSize += encoder.kBufferSize; + info.PackSize += encoder.compressedSize; + } + + // RINOK(callback->SetDecodeResult(info, false)) // why we called before 21.03 ?? + RINOK(callback->SetDecodeResult(info, true)) + + return S_OK; +} + + + +static inline UInt64 GetDictSizeFromLog(unsigned dictSizeLog) +{ + /* + if (dictSizeLog < 32) + return (UInt32)1 << dictSizeLog; + else + return (UInt32)(Int32)-1; + */ + return (UInt64)1 << dictSizeLog; +} + + +// it's limit of current LZMA implementation that can be changed later +#define kLzmaMaxDictSize ((UInt32)15 << 28) + +static inline UInt64 GetLZMAUsage(bool multiThread, int btMode, UInt64 dict) +{ + if (dict == 0) + dict = 1; + if (dict > kLzmaMaxDictSize) + dict = kLzmaMaxDictSize; + UInt32 hs = (UInt32)dict - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; + if (hs > (1 << 24)) + hs >>= 1; + hs++; + hs += (1 << 16); + + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); + UInt64 blockSize = (UInt64)dict + (1 << 16) + + (multiThread ? (1 << 20) : 0); + blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); + if (blockSize >= kBlockSizeMax) + blockSize = kBlockSizeMax; + + UInt64 son = (UInt64)dict; + if (btMode) + son *= 2; + const UInt64 v = (hs + son) * 4 + blockSize + + (1 << 20) + (multiThread ? (6 << 20) : 0); + + // printf("\nGetLZMAUsage = %d\n", (UInt32)(v >> 20)); + // printf("\nblockSize = %d\n", (UInt32)(blockSize >> 20)); + return v; +} + + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench) +{ + const size_t kBufferSize = (size_t)dictionary + kAdditionalSize; + const UInt64 kCompressedBufferSize = GetBenchCompressedSize(kBufferSize); // / 2; + if (level < 0) + level = 5; + const int algo = (level < 5 ? 0 : 1); + const int btMode = (algo == 0 ? 0 : 1); + + UInt32 numBigThreads = numThreads; + const bool lzmaMt = (totalBench || (numThreads > 1 && btMode)); + if (btMode) + { + if (!totalBench && lzmaMt) + numBigThreads /= 2; + } + return ((UInt64)kBufferSize + kCompressedBufferSize + + GetLZMAUsage(lzmaMt, btMode, dictionary) + (2 << 20)) * numBigThreads; +} + +static UInt64 GetBenchMemoryUsage_Hash(UInt32 numThreads, UInt64 dictionary) +{ + // dictionary += (dictionary >> 9); // for page tables (virtual memory) + return (UInt64)(dictionary + (1 << 15)) * numThreads + (2 << 20); +} + + +// ---------- CRC and HASH ---------- + +struct CCrcInfo_Base +{ + CMidAlignedBuffer Buffer; + const Byte *Data; + size_t Size; + bool CreateLocalBuf; + UInt32 CheckSum_Res; + + CCrcInfo_Base(): CreateLocalBuf(true), CheckSum_Res(0) {} + + HRESULT Generate(const Byte *data, size_t size); + HRESULT CrcProcess(UInt64 numIterations, + const UInt32 *checkSum, IHasher *hf, + IBenchPrintCallback *callback); +}; + + +// for debug: define it to test hash calling with unaligned data +// #define Z7_BENCH_HASH_ALIGN_BUF_OFFSET 3 + +HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size) +{ + Size = size; + Data = data; + if (!data || CreateLocalBuf) + { + Byte *buf; + const size_t size2 = (size + k_RandBuf_AlignMask) & ~(size_t)k_RandBuf_AlignMask; + if (size2 < size) + return E_OUTOFMEMORY; +#ifdef Z7_BENCH_HASH_ALIGN_BUF_OFFSET + ALLOC_WITH_HRESULT(&Buffer, size2 + Z7_BENCH_HASH_ALIGN_BUF_OFFSET) + buf = Buffer + Z7_BENCH_HASH_ALIGN_BUF_OFFSET; +#else + ALLOC_WITH_HRESULT(&Buffer, size2) + buf = Buffer; +#endif + Data = buf; + if (!data) + RandGen_BufAfterPad(buf, size); + else if (size != 0) // (CreateLocalBuf == true) + memcpy(buf, data, size); + } + return S_OK; +} + + +#if 1 +#define HashUpdate(hf, data, size) hf->Update(data, size) +#else +// for debug: +static void HashUpdate(IHasher *hf, const void *data, UInt32 size) +{ + for (;;) + { + if (size == 0) + return; + UInt32 size2 = (size * 0x85EBCA87) % size / 8; + // UInt32 size2 = size / 2; + if (size2 == 0) + size2 = 1; + hf->Update(data, size2); + data = (const void *)((const Byte *)data + size2); + size -= size2; + } +} +#endif + + +HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations, + const UInt32 *checkSum, IHasher *hf, + IBenchPrintCallback *callback) +{ + MY_ALIGN(16) + UInt32 hash32[64 / 4]; + memset(hash32, 0, sizeof(hash32)); + + CheckSum_Res = 0; + + const UInt32 hashSize = hf->GetDigestSize(); + if (hashSize > sizeof(hash32)) + return S_FALSE; + + const Byte *buf = Data; + const size_t size = Size; + UInt32 checkSum_Prev = 0; + + UInt64 prev = 0; + UInt64 cur = 0; + + do + { + hf->Init(); + size_t pos = 0; + do + { + const size_t rem = size - pos; + const UInt32 kStep = ((UInt32)1 << 31); + const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep; + HashUpdate(hf, buf + pos, curSize); + pos += curSize; + } + while (pos != size); + + hf->Final((Byte *)(void *)hash32); + UInt32 sum = 0; + for (UInt32 j = 0; j < hashSize; j += 4) + { + sum = rotlFixed(sum, 11); + sum += GetUi32((const Byte *)(const void *)hash32 + j); + } + if (checkSum) + { + if (sum != *checkSum) + return S_FALSE; + } + else + { + checkSum_Prev = sum; + checkSum = &checkSum_Prev; + } + if (callback) + { + cur += size; + if (cur - prev >= ((UInt32)1 << 30)) + { + prev = cur; + RINOK(callback->CheckBreak()) + } + } + } + while (--numIterations); + + CheckSum_Res = checkSum_Prev; + return S_OK; +} + +extern +UInt32 g_BenchCpuFreqTemp; // we need non-static variavble to disable compiler optimization +UInt32 g_BenchCpuFreqTemp = 1; + +#define YY1 sum += val; sum ^= val; +#define YY3 YY1 YY1 YY1 YY1 +#define YY5 YY3 YY3 YY3 YY3 +#define YY7 YY5 YY5 YY5 YY5 +static const UInt32 kNumFreqCommands = 128; + +EXTERN_C_BEGIN + +static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val) +{ + for (UInt32 i = 0; i < num; i++) + { + YY7 + } + return sum; +} + +EXTERN_C_END + + +#ifndef Z7_ST + +struct CBaseThreadInfo +{ + NWindows::CThread Thread; + IBenchPrintCallback *Callback; + HRESULT CallbackRes; + + WRes Wait_If_Created() + { + if (!Thread.IsCreated()) + return 0; + return Thread.Wait_Close(); + } +}; + +struct CFreqInfo: public CBaseThreadInfo +{ + UInt32 ValRes; + UInt32 Size; + UInt64 NumIterations; +}; + +static THREAD_FUNC_DECL FreqThreadFunction(void *param) +{ + CFreqInfo *p = (CFreqInfo *)param; + + UInt32 sum = g_BenchCpuFreqTemp; + for (UInt64 k = p->NumIterations; k > 0; k--) + { + if (p->Callback) + { + p->CallbackRes = p->Callback->CheckBreak(); + if (p->CallbackRes != S_OK) + break; + } + sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp); + } + p->ValRes = sum; + return THREAD_FUNC_RET_ZERO; +} + +struct CFreqThreads +{ + CFreqInfo *Items; + UInt32 NumThreads; + + CFreqThreads(): Items(NULL), NumThreads(0) {} + + WRes WaitAll() + { + WRes wres = 0; + for (UInt32 i = 0; i < NumThreads; i++) + { + WRes wres2 = Items[i].Wait_If_Created(); + if (wres == 0 && wres2 != 0) + wres = wres2; + } + NumThreads = 0; + return wres; + } + + ~CFreqThreads() + { + WaitAll(); + delete []Items; + } +}; + + +static THREAD_FUNC_DECL CrcThreadFunction(void *param); + +struct CCrcInfo: public CBaseThreadInfo +{ + const Byte *Data; + size_t Size; + UInt64 NumIterations; + bool CheckSumDefined; + UInt32 CheckSum; + CMyComPtr Hasher; + HRESULT Res; + UInt32 CheckSum_Res; + + #ifndef Z7_ST + NSynchronization::CManualResetEvent ReadyEvent; + UInt32 ThreadIndex; + CBenchSyncCommon *Common; + CAffinityMode AffinityMode; + #endif + + // we want to call CCrcInfo_Base::Buffer.Free() in main thread. + // so we uses non-local CCrcInfo_Base. + CCrcInfo_Base crcib; + + HRESULT CreateThread() + { + WRes res = 0; + if (!ReadyEvent.IsCreated()) + res = ReadyEvent.Create(); + if (res == 0) + res = AffinityMode.CreateThread_WithAffinity(Thread, CrcThreadFunction, this, + ThreadIndex); + return HRESULT_FROM_WIN32(res); + } + + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + + void Process(); + + CCrcInfo(): Res(E_FAIL) {} +}; + +static const bool k_Crc_CreateLocalBuf_For_File = true; // for total BW test +// static const bool k_Crc_CreateLocalBuf_For_File = false; // for shared memory read test + +void CCrcInfo::Process() +{ + crcib.CreateLocalBuf = k_Crc_CreateLocalBuf_For_File; + // we can use additional Generate() passes to reduce some time effects for new page allocation + // for (unsigned y = 0; y < 10; y++) + Res = crcib.Generate(Data, Size); + + // if (Common) + { + WRes wres = ReadyEvent.Set(); + if (wres != 0) + { + if (Res == 0) + Res = HRESULT_FROM_WIN32(wres); + return; + } + if (Res != 0) + return; + + wres = Common->StartEvent.Lock(); + + if (wres != 0) + { + Res = HRESULT_FROM_WIN32(wres); + return; + } + if (Common->ExitMode) + return; + } + + Res = crcib.CrcProcess(NumIterations, + CheckSumDefined ? &CheckSum : NULL, Hasher, + Callback); + CheckSum_Res = crcib.CheckSum_Res; + /* + We don't want to include the time of slow CCrcInfo_Base::Buffer.Free() + to time of benchmark. So we don't free Buffer here + */ + // crcib.Buffer.Free(); +} + + +static THREAD_FUNC_DECL CrcThreadFunction(void *param) +{ + CCrcInfo *p = (CCrcInfo *)param; + + #ifdef USE_ALLOCA + alloca(p->AllocaSize); + #endif + p->Process(); + return THREAD_FUNC_RET_ZERO; +} + + +struct CCrcThreads +{ + CCrcInfo *Items; + unsigned NumThreads; + CBenchSyncCommon Common; + bool NeedClose; + + CCrcThreads(): Items(NULL), NumThreads(0), NeedClose(false) {} + + WRes StartAndWait(bool exitMode = false); + + ~CCrcThreads() + { + StartAndWait(true); + delete []Items; + } +}; + + +WRes CCrcThreads::StartAndWait(bool exitMode) +{ + if (!NeedClose) + return 0; + + Common.ExitMode = exitMode; + WRes wres = Common.StartEvent.Set(); + + for (unsigned i = 0; i < NumThreads; i++) + { + WRes wres2 = Items[i].Wait_If_Created(); + if (wres == 0 && wres2 != 0) + wres = wres2; + } + NumThreads = 0; + NeedClose = false; + return wres; +} + +#endif + + +/* +static UInt32 CrcCalc1(const Byte *buf, size_t size) +{ + UInt32 crc = CRC_INIT_VAL; + for (size_t i = 0; i < size; i++) + crc = CRC_UPDATE_BYTE(crc, buf[i]); + return CRC_GET_DIGEST(crc); +} +*/ + +/* +static UInt32 RandGenCrc(Byte *buf, size_t size, CBaseRandomGenerator &RG) +{ + RandGen(buf, size, RG); + return CrcCalc1(buf, size); +} +*/ + +static bool CrcInternalTest() +{ + CAlignedBuffer buffer; + const size_t kBufSize = 1 << 11; + const size_t kCheckSize = 1 << 6; + buffer.Alloc(kBufSize); + if (!buffer.IsAllocated()) + return false; + Byte *buf = (Byte *)buffer; + RandGen_BufAfterPad(buf, kBufSize); + UInt32 sum = 0; + for (size_t i = 0; i < kBufSize - kCheckSize * 2; i += kCheckSize - 1) + for (size_t j = 0; j < kCheckSize; j++) + { + sum = rotlFixed(sum, 11); + sum += CrcCalc(buf + i + j, j); + } + return sum == 0x28462c7c; +} + +struct CBenchMethod +{ + unsigned Weight; + unsigned DictBits; + Int32 EncComplex; + Int32 DecComplexCompr; + Int32 DecComplexUnc; + const char *Name; + // unsigned KeySize; +}; + +// #define USE_SW_CMPLX + +#ifdef USE_SW_CMPLX +#define CMPLX(x) ((x) * 1000) +#else +#define CMPLX(x) (x) +#endif + +static const CBenchMethod g_Bench[] = +{ + // { 40, 17, 357, 145, 20, "LZMA:x1" }, + // { 20, 18, 360, 145, 20, "LZMA2:x1:mt2" }, + + { 20, 18, 360, 145, 20, "LZMA:x1" }, + { 20, 22, 600, 145, 20, "LZMA:x3" }, + + { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" }, + { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" }, + + { 10, 16, 124, 40, 14, "Deflate:x1" }, + { 20, 16, 376, 40, 14, "Deflate:x5" }, + { 10, 16, 1082, 40, 14, "Deflate:x7" }, + { 10, 17, 422, 40, 14, "Deflate64:x5" }, + + { 10, 15, 590, 69, 69, "BZip2:x1" }, + { 20, 19, 815, 122, 122, "BZip2:x5" }, + { 10, 19, 815, 122, 122, "BZip2:x5:mt2" }, + { 10, 19, 2530, 122, 122, "BZip2:x7" }, + + // { 10, 18, 1010, 0, 1150, "PPMDZip:x1" }, + { 10, 18, 1010, 0, 1150, "PPMD:x1" }, + // { 10, 22, 1655, 0, 1830, "PPMDZip:x5" }, + { 10, 22, 1655, 0, 1830, "PPMD:x5" }, + + // { 2, 0, -16, 0, -16, "Swap2" }, + { 2, 0, -16, 0, -16, "Swap4" }, + + // { 2, 0, 3, 0, 4, "Delta:1" }, + // { 2, 0, 3, 0, 4, "Delta:2" }, + // { 2, 0, 3, 0, 4, "Delta:3" }, + { 2, 0, 3, 0, 4, "Delta:4" }, + // { 2, 0, 3, 0, 4, "Delta:8" }, + // { 2, 0, 3, 0, 4, "Delta:32" }, + + { 2, 0, 2, 0, 2, "BCJ" }, + { 2, 0, 1, 0, 1, "ARM64" }, + { 2, 0, 1, 0, 1, "RISCV" }, + + // { 10, 0, 18, 0, 18, "AES128CBC:1" }, + // { 10, 0, 21, 0, 21, "AES192CBC:1" }, + { 10, 0, 24, 0, 24, "AES256CBC:1" }, + + // { 10, 0, 18, 0, 18, "AES128CTR:1" }, + // { 10, 0, 21, 0, 21, "AES192CTR:1" }, + // { 10, 0, 24, 0, 24, "AES256CTR:1" }, + // { 2, 0, CMPLX(6), 0, CMPLX(1), "AES128CBC:2" }, + // { 2, 0, CMPLX(7), 0, CMPLX(1), "AES192CBC:2" }, + { 2, 0, CMPLX(8), 0, CMPLX(1), "AES256CBC:2" }, + + // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES128CTR:2" }, + // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES192CTR:2" }, + // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES256CTR:2" }, + + // { 1, 0, CMPLX(6), 0, -2, "AES128CBC:3" }, + // { 1, 0, CMPLX(7), 0, -2, "AES192CBC:3" }, + { 1, 0, CMPLX(8), 0, -2, "AES256CBC:3" } + + // { 1, 0, CMPLX(1), 0, -2, "AES128CTR:3" }, + // { 1, 0, CMPLX(1), 0, -2, "AES192CTR:3" }, + // { 1, 0, CMPLX(1), 0, -2, "AES256CTR:3" }, +}; + +struct CBenchHash +{ + unsigned Weight; + UInt32 Complex; + UInt32 CheckSum; + const char *Name; +}; + +// #define ARM_CRC_MUL 100 +#define ARM_CRC_MUL 1 + +#define k_Hash_Complex_Mult 256 + +static const CBenchHash g_Hash[] = +{ + { 20, 256, 0x21e207bb, "CRC32:12" } , + { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" }, + { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" }, + { 10, 256, 0x41b901d1, "CRC64" }, + { 5, 64, 0x43eac94f, "XXH64" }, + { 2, 2340, 0x3398a904, "MD5" }, + { 10, 2340, 0xff769021, "SHA1:1" }, + { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" }, + { 10, 5100, 0x7913ba03, "SHA256:1" }, + { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" }, + { 5, 3200, 0xe7aeb394, "SHA512:1" }, + { 2, CMPLX((40 * 4 + 1) * 4 + 4), 0xe7aeb394, "SHA512:2" }, + // { 10, 3428, 0x1cc99b18, "SHAKE128" }, + // { 10, 4235, 0x74eaddc3, "SHAKE256" }, + // { 10, 4000, 0xdf3e6863, "SHA3-224" }, + { 5, 4200, 0xcecac10d, "SHA3-256" }, + // { 10, 5538, 0x4e5d9163, "SHA3-384" }, + // { 10, 8000, 0x96a58289, "SHA3-512" }, + { 2, 4096, 0x85189d02, "BLAKE2sp:1" }, + { 2, 1024, 0x85189d02, "BLAKE2sp:2" }, // sse2-way4-fast + { 2, 512, 0x85189d02, "BLAKE2sp:3" } // avx2-way8-fast +#if 0 + , { 2, 2048, 0x85189d02, "BLAKE2sp:4" } // sse2-way1 + , { 2, 1024, 0x85189d02, "BLAKE2sp:5" } // sse2-way2 + , { 2, 1024, 0x85189d02, "BLAKE2sp:6" } // avx2-way2 + , { 2, 1024, 0x85189d02, "BLAKE2sp:7" } // avx2-way4 +#endif +}; + +static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size) +{ + char s[128]; + unsigned startPos = (unsigned)sizeof(s) - 32; + memset(s, ' ', startPos); + ConvertUInt64ToString(value, s + startPos); + // if (withSpace) + { + startPos--; + size++; + } + unsigned len = (unsigned)strlen(s + startPos); + if (size > len) + { + size -= len; + if (startPos < size) + startPos = 0; + else + startPos -= size; + } + f.Print(s + startPos); +} + +static const unsigned kFieldSize_Name = 12; +static const unsigned kFieldSize_SmallName = 4; +static const unsigned kFieldSize_Speed = 9; +static const unsigned kFieldSize_Usage = 5; +static const unsigned kFieldSize_RU = 6; +static const unsigned kFieldSize_Rating = 6; +static const unsigned kFieldSize_EU = 5; +static const unsigned kFieldSize_Effec = 5; +static const unsigned kFieldSize_CrcSpeed = 8; + + +static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating; +static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec; + + +static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size) +{ + PrintNumber(f, (rating + 500000) / 1000000, size); +} + + +static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size) +{ + UInt64 v = 0; + if (divider != 0) + v = (val * 100 + divider / 2) / divider; + PrintNumber(f, v, size); +} + +static void PrintChars(IBenchPrintCallback &f, char c, unsigned size) +{ + char s[256]; + memset(s, (Byte)c, size); + s[size] = 0; + f.Print(s); +} + +static void PrintSpaces(IBenchPrintCallback &f, unsigned size) +{ + PrintChars(f, ' ', size); +} + +static void PrintUsage(IBenchPrintCallback &f, UInt64 usage, unsigned size) +{ + PrintNumber(f, Benchmark_GetUsage_Percents(usage), size); +} + +static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq) +{ + PrintUsage(f, usage, kFieldSize_Usage); + PrintRating(f, rpu, kFieldSize_RU); + PrintRating(f, rating, kFieldSize_Rating); + if (showFreq) + { + if (cpuFreq == 0) + PrintSpaces(f, kFieldSize_EUAndEffec); + else + { + PrintPercents(f, rating, cpuFreq * usage / kBenchmarkUsageMult, kFieldSize_EU); + PrintPercents(f, rating, cpuFreq, kFieldSize_Effec); + } + } +} + + +void CTotalBenchRes::Generate_From_BenchInfo(const CBenchInfo &info) +{ + Speed = info.GetUnpackSizeSpeed(); + Usage = info.GetUsage(); + RPU = info.GetRatingPerUsage(Rating); +} + +void CTotalBenchRes::Mult_For_Weight(unsigned weight) +{ + NumIterations2 *= weight; + RPU *= weight; + Rating *= weight; + Usage *= weight; + Speed *= weight; +} + +void CTotalBenchRes::Update_With_Res(const CTotalBenchRes &r) +{ + Rating += r.Rating; + Usage += r.Usage; + RPU += r.RPU; + Speed += r.Speed; + // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); + NumIterations2 += r.NumIterations2; +} + +static void PrintResults(IBenchPrintCallback *f, + const CBenchInfo &info, + unsigned weight, + UInt64 rating, + bool showFreq, UInt64 cpuFreq, + CTotalBenchRes *res) +{ + CTotalBenchRes t; + t.Rating = rating; + t.NumIterations2 = 1; + t.Generate_From_BenchInfo(info); + + if (f) + { + if (t.Speed != 0) + PrintNumber(*f, t.Speed / 1024, kFieldSize_Speed); + else + PrintSpaces(*f, 1 + kFieldSize_Speed); + } + if (f) + { + PrintResults(*f, t.Usage, t.RPU, rating, showFreq, cpuFreq); + } + + if (res) + { + // res->NumIterations1++; + t.Mult_For_Weight(weight); + res->Update_With_Res(t); + } +} + +static void PrintTotals(IBenchPrintCallback &f, + bool showFreq, UInt64 cpuFreq, bool showSpeed, const CTotalBenchRes &res) +{ + const UInt64 numIterations2 = res.NumIterations2 ? res.NumIterations2 : 1; + const UInt64 speed = res.Speed / numIterations2; + if (showSpeed && speed != 0) + PrintNumber(f, speed / 1024, kFieldSize_Speed); + else + PrintSpaces(f, 1 + kFieldSize_Speed); + + // PrintSpaces(f, 1 + kFieldSize_Speed); + // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1; + PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq); +} + + +static void PrintHex(AString &s, UInt64 v) +{ + char temp[32]; + ConvertUInt64ToHex(v, temp); + s += temp; +} + +AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti) +{ + AString s; + // s.Add_UInt32(ti.numProcessThreads); + unsigned numSysThreads = ti.GetNumSystemThreads(); + if (ti.GetNumProcessThreads() != numSysThreads) + { + // if (ti.numProcessThreads != ti.numSysThreads) + { + s += " / "; + s.Add_UInt32(numSysThreads); + } + s += " : "; + #ifdef _WIN32 + PrintHex(s, ti.processAffinityMask); + s += " / "; + PrintHex(s, ti.systemAffinityMask); + #else + unsigned i = (numSysThreads + 3) & ~(unsigned)3; + if (i == 0) + i = 4; + for (; i >= 4; ) + { + i -= 4; + unsigned val = 0; + for (unsigned k = 0; k < 4; k++) + { + const unsigned bit = (ti.IsCpuSet(i + k) ? 1 : 0); + val += (bit << k); + } + PrintHex(s, val); + } + #endif + } + return s; +} + + +#ifdef Z7_LARGE_PAGES + +#ifdef _WIN32 +extern bool g_LargePagesMode; +extern "C" +{ + extern SIZE_T g_LargePageSize; +} +#endif + +void Add_LargePages_String(AString &s) +{ + #ifdef _WIN32 + if (g_LargePagesMode || g_LargePageSize != 0) + { + s.Add_OptSpaced("(LP-"); + PrintSize_KMGT_Or_Hex(s, g_LargePageSize); + #ifdef MY_CPU_X86_OR_AMD64 + if (CPU_IsSupported_PageGB()) + s += "-1G"; + #endif + if (!g_LargePagesMode) + s += "-NA"; + s += ")"; + } + #else + s += ""; + #endif +} + +#endif + + + +static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, + bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads) +{ + f.Print("RAM "); + f.Print(sizeString); + if (size_Defined) + PrintNumber(f, (size >> 20), 6); + else + f.Print(" ?"); + f.Print(" MB"); + + #ifdef Z7_LARGE_PAGES + { + AString s; + Add_LargePages_String(s); + f.Print(s); + } + #endif + + f.Print(", # "); + f.Print(threadsString); + PrintNumber(f, numThreads, 3); +} + + + +struct CBenchCallbackToPrint Z7_final: public IBenchCallback +{ + bool NeedPrint; + bool Use2Columns; + bool ShowFreq; + unsigned NameFieldSize; + + unsigned EncodeWeight; + unsigned DecodeWeight; + + UInt64 CpuFreq; + UInt64 DictSize; + + IBenchPrintCallback *_file; + CBenchProps BenchProps; + CTotalBenchRes EncodeRes; + CTotalBenchRes DecodeRes; + + CBenchInfo BenchInfo_Results[2]; + + CBenchCallbackToPrint(): + NeedPrint(true), + Use2Columns(false), + ShowFreq(false), + NameFieldSize(0), + EncodeWeight(1), + DecodeWeight(1), + CpuFreq(0) + {} + + void Init() { EncodeRes.Init(); DecodeRes.Init(); } + void Print(const char *s); + void NewLine(); + + HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); + HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override; + HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override; +}; + +HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq) +{ + ShowFreq = showFreq; + CpuFreq = cpuFreq; + return S_OK; +} + +HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final) +{ + RINOK(_file->CheckBreak()) + if (final) + BenchInfo_Results[0] = info; + if (final) + if (NeedPrint) + { + const UInt64 rating = BenchProps.GetRating_Enc(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations); + PrintResults(_file, info, + EncodeWeight, rating, + ShowFreq, CpuFreq, &EncodeRes); + if (!Use2Columns) + _file->NewLine(); + } + return S_OK; +} + +static const char * const kSep = " | "; + +HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final) +{ + RINOK(_file->CheckBreak()) + if (final) + BenchInfo_Results[1] = info; + if (final) + if (NeedPrint) + { + const UInt64 rating = BenchProps.GetRating_Dec(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); + if (Use2Columns) + _file->Print(kSep); + else + PrintSpaces(*_file, NameFieldSize); + CBenchInfo info2 = info; + info2.UnpackSize *= info2.NumIterations; + info2.PackSize *= info2.NumIterations; + info2.NumIterations = 1; + PrintResults(_file, info2, + DecodeWeight, rating, + ShowFreq, CpuFreq, &DecodeRes); + } + return S_OK; +} + +void CBenchCallbackToPrint::Print(const char *s) +{ + _file->Print(s); +} + +void CBenchCallbackToPrint::NewLine() +{ + _file->NewLine(); +} + +static void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size) +{ + f.Print(s); + int numSpaces = (int)size - (int)MyStringLen(s); + if (numSpaces > 0) + PrintSpaces(f, (unsigned)numSpaces); +} + +static void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size) +{ + int numSpaces = (int)size - (int)MyStringLen(s); + if (numSpaces > 0) + PrintSpaces(f, (unsigned)numSpaces); + f.Print(s); +} + + +static bool DoesWildcardMatchName_NoCase(const AString &mask, const char *name) +{ + UString wildc = GetUnicodeString(mask); + UString bname = GetUnicodeString(name); + wildc.MakeLower_Ascii(); + bname.MakeLower_Ascii(); + return DoesWildcardMatchName(wildc, bname); +} + + +static HRESULT TotalBench( + DECL_EXTERNAL_CODECS_LOC_VARS + const COneMethodInfo &methodMask, + UInt64 complexInCommands, + #ifndef Z7_ST + UInt32 numThreads, + const CAffinityMode *affinityMode, + #endif + bool forceUnpackSize, + size_t unpackSize, + const Byte *fileData, + IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) + { + const CBenchMethod &bench = g_Bench[i]; + if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name)) + continue; + PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); + { + unsigned keySize = 32; + if (IsString1PrefixedByString2(bench.Name, "AES128")) keySize = 16; + else if (IsString1PrefixedByString2(bench.Name, "AES192")) keySize = 24; + callback->BenchProps.KeySize = keySize; + } + callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; + callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; + callback->BenchProps.EncComplex = bench.EncComplex; + + COneMethodInfo method; + NCOM::CPropVariant propVariant; + propVariant = bench.Name; + RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)) + + size_t unpackSize2 = unpackSize; + if (!forceUnpackSize && bench.DictBits == 0) + unpackSize2 = kFilterUnpackSize; + + callback->EncodeWeight = bench.Weight; + callback->DecodeWeight = bench.Weight; + + const HRESULT res = MethodBench( + EXTERNAL_CODECS_LOC_VARS + complexInCommands, + #ifndef Z7_ST + false, numThreads, affinityMode, + #endif + method, + unpackSize2, fileData, + bench.DictBits, + printCallback, callback, &callback->BenchProps); + + if (res == E_NOTIMPL) + { + // callback->Print(" ---"); + // we need additional empty line as line for decompression results + if (!callback->Use2Columns) + callback->NewLine(); + } + else + { + RINOK(res) + } + + callback->NewLine(); + } + return S_OK; +} + + +struct CFreqBench +{ + // in: + UInt64 complexInCommands; + UInt32 numThreads; + bool showFreq; + UInt64 specifiedFreq; + + // out: + UInt64 CpuFreqRes; + UInt64 UsageRes; + UInt32 res; + + CFreqBench() + {} + + HRESULT FreqBench(IBenchPrintCallback *_file + #ifndef Z7_ST + , const CAffinityMode *affinityMode + #endif + ); +}; + + +HRESULT CFreqBench::FreqBench(IBenchPrintCallback *_file + #ifndef Z7_ST + , const CAffinityMode *affinityMode + #endif + ) +{ + res = 0; + CpuFreqRes = 0; + UsageRes = 0; + + if (numThreads == 0) + numThreads = 1; + + #ifdef Z7_ST + numThreads = 1; + #endif + + const UInt32 complexity = kNumFreqCommands; + UInt64 numIterations = complexInCommands / complexity; + UInt32 numIterations2 = 1 << 30; + if (numIterations > numIterations2) + numIterations /= numIterations2; + else + { + numIterations2 = (UInt32)numIterations; + numIterations = 1; + } + + CBenchInfoCalc progressInfoSpec; + + #ifndef Z7_ST + + bool mtMode = (numThreads > 1) || affinityMode->NeedAffinity(); + + if (mtMode) + { + CFreqThreads threads; + threads.Items = new CFreqInfo[numThreads]; + UInt32 i; + for (i = 0; i < numThreads; i++) + { + CFreqInfo &info = threads.Items[i]; + info.Callback = _file; + info.CallbackRes = S_OK; + info.NumIterations = numIterations; + info.Size = numIterations2; + } + progressInfoSpec.SetStartTime(); + for (i = 0; i < numThreads; i++) + { + // Sleep(10); + CFreqInfo &info = threads.Items[i]; + WRes wres = affinityMode->CreateThread_WithAffinity(info.Thread, FreqThreadFunction, &info, i); + if (info.Thread.IsCreated()) + threads.NumThreads++; + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + } + WRes wres = threads.WaitAll(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + for (i = 0; i < numThreads; i++) + { + RINOK(threads.Items[i].CallbackRes) + } + } + else + #endif + { + progressInfoSpec.SetStartTime(); + UInt32 sum = g_BenchCpuFreqTemp; + UInt64 k = numIterations; + do + { + sum = CountCpuFreq(sum, numIterations2, g_BenchCpuFreqTemp); + if (_file) + { + RINOK(_file->CheckBreak()) + } + } + while (--k); + res += sum; + } + + if (res == 0x12345678) + if (_file) + { + RINOK(_file->CheckBreak()) + } + + CBenchInfo info; + progressInfoSpec.SetFinishTime(info); + + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = 1; + + const UInt64 numCommands = (UInt64)numIterations * numIterations2 * numThreads * complexity; + const UInt64 rating = info.GetSpeed(numCommands); + CpuFreqRes = rating / numThreads; + UsageRes = info.GetUsage(); + + if (_file) + { + PrintResults(_file, info, + 0, // weight + rating, + showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : CpuFreqRes) : 0, NULL); + RINOK(_file->CheckBreak()) + } + + return S_OK; +} + + + +static HRESULT CrcBench( + DECL_EXTERNAL_CODECS_LOC_VARS + UInt64 complexInCommands, + UInt32 numThreads, + const size_t bufferSize, + const Byte *fileData, + + UInt64 &speed, + UInt64 &usage, + + UInt32 complexity, unsigned benchWeight, + const UInt32 *checkSum, + const COneMethodInfo &method, + IBenchPrintCallback *_file, + #ifndef Z7_ST + const CAffinityMode *affinityMode, + #endif + bool showRating, + CTotalBenchRes *encodeRes, + bool showFreq, UInt64 cpuFreq) +{ + if (numThreads == 0) + numThreads = 1; + + #ifdef Z7_ST + numThreads = 1; + #endif + + const AString &methodName = method.MethodName; + // methodName.RemoveChar(L'-'); + CMethodId hashID; + if (!FindHashMethod( + EXTERNAL_CODECS_LOC_VARS + methodName, hashID)) + return E_NOTIMPL; + + /* + // if will generate random data in each thread, instead of global data + CMidAlignedBuffer buffer; + if (!fileData) + { + ALLOC_WITH_HRESULT(&buffer, bufferSize) + RandGen(buffer, bufferSize); + fileData = buffer; + } + */ + + const size_t bsize = (bufferSize == 0 ? 1 : bufferSize); + UInt64 numIterations = complexInCommands * k_Hash_Complex_Mult / complexity / bsize; + if (numIterations == 0) + numIterations = 1; + + CBenchInfoCalc progressInfoSpec; + CBenchInfo info; + + #ifndef Z7_ST + bool mtEncMode = (numThreads > 1) || affinityMode->NeedAffinity(); + + if (mtEncMode) + { + CCrcThreads threads; + threads.Items = new CCrcInfo[numThreads]; + { + WRes wres = threads.Common.StartEvent.Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + threads.NeedClose = true; + } + + UInt32 i; + for (i = 0; i < numThreads; i++) + { + CCrcInfo &ci = threads.Items[i]; + AString name; + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, ci.Hasher)) + if (!ci.Hasher) + return E_NOTIMPL; + CMyComPtr scp; + ci.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + RINOK(method.SetCoderProps(scp)) + } + + ci.Callback = _file; + ci.Data = fileData; + ci.NumIterations = numIterations; + ci.Size = bufferSize; + ci.CheckSumDefined = false; + if (checkSum) + { + ci.CheckSum = *checkSum; + ci.CheckSumDefined = true; + } + + #ifdef USE_ALLOCA + ci.AllocaSize = BENCH_ALLOCA_VALUE(i); + #endif + } + + for (i = 0; i < numThreads; i++) + { + CCrcInfo &ci = threads.Items[i]; + ci.ThreadIndex = i; + ci.Common = &threads.Common; + ci.AffinityMode = *affinityMode; + HRESULT hres = ci.CreateThread(); + if (ci.Thread.IsCreated()) + threads.NumThreads++; + if (hres != 0) + return hres; + } + + for (i = 0; i < numThreads; i++) + { + CCrcInfo &ci = threads.Items[i]; + WRes wres = ci.ReadyEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(ci.Res) + } + + progressInfoSpec.SetStartTime(); + + WRes wres = threads.StartAndWait(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + + progressInfoSpec.SetFinishTime(info); + + for (i = 0; i < numThreads; i++) + { + RINOK(threads.Items[i].Res) + if (i != 0) + if (threads.Items[i].CheckSum_Res != + threads.Items[i - 1].CheckSum_Res) + return S_FALSE; + } + } + else + #endif + { + CMyComPtr hasher; + AString name; + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)) + if (!hasher) + return E_NOTIMPL; + CMyComPtr scp; + hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + { + RINOK(method.SetCoderProps(scp)) + } + CCrcInfo_Base crcib; + crcib.CreateLocalBuf = false; + RINOK(crcib.Generate(fileData, bufferSize)) + progressInfoSpec.SetStartTime(); + RINOK(crcib.CrcProcess(numIterations, checkSum, hasher, _file)) + progressInfoSpec.SetFinishTime(info); + } + + + UInt64 unpSize = numIterations * bufferSize; + UInt64 unpSizeThreads = unpSize * numThreads; + info.UnpackSize = unpSizeThreads; + info.PackSize = unpSizeThreads; + info.NumIterations = 1; + + if (_file) + { + if (showRating) + { + UInt64 unpSizeThreads2 = unpSizeThreads; + if (unpSizeThreads2 == 0) + unpSizeThreads2 = numIterations * 1 * numThreads; + const UInt64 numCommands = unpSizeThreads2 * complexity / 256; + const UInt64 rating = info.GetSpeed(numCommands); + PrintResults(_file, info, + benchWeight, rating, + showFreq, cpuFreq, encodeRes); + } + RINOK(_file->CheckBreak()) + } + + speed = info.GetSpeed(unpSizeThreads); + usage = info.GetUsage(); + + return S_OK; +} + + + +static HRESULT TotalBench_Hash( + DECL_EXTERNAL_CODECS_LOC_VARS + const COneMethodInfo &methodMask, + UInt64 complexInCommands, + UInt32 numThreads, + size_t bufSize, + const Byte *fileData, + IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback, + #ifndef Z7_ST + const CAffinityMode *affinityMode, + #endif + CTotalBenchRes *encodeRes, + bool showFreq, UInt64 cpuFreq) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++) + { + const CBenchHash &bench = g_Hash[i]; + if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name)) + continue; + PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); + // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; + // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; + // callback->BenchProps.EncComplex = bench.EncComplex; + + COneMethodInfo method; + NCOM::CPropVariant propVariant; + propVariant = bench.Name; + RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)) + + UInt64 speed, usage; + + const HRESULT res = CrcBench( + EXTERNAL_CODECS_LOC_VARS + complexInCommands, + numThreads, bufSize, fileData, + speed, usage, + bench.Complex, bench.Weight, + (!fileData && bufSize == (1 << kNumHashDictBits)) ? &bench.CheckSum : NULL, + method, + printCallback, + #ifndef Z7_ST + affinityMode, + #endif + true, // showRating + encodeRes, showFreq, cpuFreq); + if (res == E_NOTIMPL) + { + // callback->Print(" ---"); + } + else + { + RINOK(res) + } + callback->NewLine(); + } + return S_OK; +} + +struct CTempValues +{ + UInt64 *Values; + CTempValues(): Values(NULL) {} + void Alloc(UInt32 num) { Values = new UInt64[num]; } + ~CTempValues() { delete []Values; } +}; + +static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) +{ + const wchar_t *end; + UInt64 result = ConvertStringToUInt64(s, &end); + if (*end != 0 || s.IsEmpty()) + prop = s; + else if (result <= (UInt32)0xFFFFFFFF) + prop = (UInt32)result; + else + prop = result; +} + + +static bool AreSameMethodNames(const char *fullName, const char *shortName) +{ + return StringsAreEqualNoCase_Ascii(fullName, shortName); +} + + + + +static void Print_Usage_and_Threads(IBenchPrintCallback &f, UInt64 usage, UInt32 threads) +{ + PrintRequirements(f, "usage:", true, usage, "Benchmark threads: ", threads); +} + + +static void Print_Delimiter(IBenchPrintCallback &f) +{ + f.Print(" |"); +} + +static void Print_Pow(IBenchPrintCallback &f, unsigned pow) +{ + char s[16]; + ConvertUInt32ToString(pow, s); + unsigned pos = MyStringLen(s); + s[pos++] = ':'; + s[pos] = 0; + PrintLeft(f, s, kFieldSize_SmallName); // 4 +} + +static void Bench_BW_Print_Usage_Speed(IBenchPrintCallback &f, + UInt64 usage, UInt64 speed) +{ + PrintUsage(f, usage, kFieldSize_Usage); + PrintNumber(f, speed / 1000000, kFieldSize_CrcSpeed); +} + + +HRESULT Bench( + DECL_EXTERNAL_CODECS_LOC_VARS + IBenchPrintCallback *printCallback, + IBenchCallback *benchCallback, + const CObjectVector &props, + UInt32 numIterations, + bool multiDict, + IBenchFreqCallback *freqCallback) +{ + // for (int y = 0; y < 10000; y++) + if (!CrcInternalTest()) + return E_FAIL; + + UInt32 numCPUs = 1; + size_t ramSize = (size_t)sizeof(size_t) << 29; + + NSystem::CProcessAffinity threadsInfo; + threadsInfo.InitST(); + + #ifndef Z7_ST + + if (threadsInfo.Get() && threadsInfo.GetNumProcessThreads() != 0) + numCPUs = threadsInfo.GetNumProcessThreads(); + else + numCPUs = NSystem::GetNumberOfProcessors(); + + #endif + + // numCPUs = 24; + /* + { + DWORD_PTR mask = (1 << 0); + DWORD_PTR old = SetThreadAffinityMask(GetCurrentThread(), mask); + old = old; + DWORD_PTR old2 = SetThreadAffinityMask(GetCurrentThread(), mask); + old2 = old2; + return 0; + } + */ + + const bool ramSize_Defined = NSystem::GetRamSize(ramSize); + + UInt32 numThreadsSpecified = numCPUs; + bool needSetComplexity = false; + UInt32 testTimeMs = kComplexInMs; + UInt32 startDicLog = 22; + bool startDicLog_Defined = false; + UInt64 specifiedFreq = 0; + bool multiThreadTests = false; + UInt64 complexInCommands = kComplexInCommands; + UInt32 numThreads_Start = 1; + + #ifndef Z7_ST + CAffinityMode affinityMode; + #endif + + + COneMethodInfo method; + + CMidAlignedBuffer fileDataBuffer; + bool use_fileData = false; + bool isFixedDict = false; + + { + unsigned i; + + if (printCallback) + { + for (i = 0; i < props.Size(); i++) + { + const CProperty &property = props[i]; + printCallback->Print(" "); + printCallback->Print(GetAnsiString(property.Name)); + if (!property.Value.IsEmpty()) + { + printCallback->Print("="); + printCallback->Print(GetAnsiString(property.Value)); + } + } + if (!props.IsEmpty()) + printCallback->NewLine(); + } + + + for (i = 0; i < props.Size(); i++) + { + const CProperty &property = props[i]; + UString name (property.Name); + name.MakeLower_Ascii(); + + if (name.IsEqualTo("file")) + { + if (property.Value.IsEmpty()) + return E_INVALIDARG; + + NFile::NIO::CInFile file; + if (!file.Open(us2fs(property.Value))) + return GetLastError_noZero_HRESULT(); + size_t len; + { + UInt64 len64; + if (!file.GetLength(len64)) + return GetLastError_noZero_HRESULT(); + if (printCallback) + { + printCallback->Print("file size ="); + PrintNumber(*printCallback, len64, 0); + printCallback->NewLine(); + } + len = (size_t)len64; + if (len != len64) + return E_INVALIDARG; + } + + // (len == 0) is allowed. Also it's allowed if Alloc(0) returns NULL here + + ALLOC_WITH_HRESULT(&fileDataBuffer, len) + use_fileData = true; + + { + size_t processed; + if (!file.ReadFull((Byte *)fileDataBuffer, len, processed)) + return GetLastError_noZero_HRESULT(); + if (processed != len) + return E_FAIL; + } + continue; + } + + NCOM::CPropVariant propVariant; + if (!property.Value.IsEmpty()) + ParseNumberString(property.Value, propVariant); + + if (name.IsEqualTo("time")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs)) + needSetComplexity = true; + testTimeMs *= 1000; + continue; + } + + if (name.IsEqualTo("timems")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs)) + needSetComplexity = true; + continue; + } + + if (name.IsEqualTo("tic")) + { + UInt32 v; + RINOK(ParsePropToUInt32(UString(), propVariant, v)) + if (v >= 64) + return E_INVALIDARG; + complexInCommands = (UInt64)1 << v; + continue; + } + + const bool isCurrent_fixedDict = name.IsEqualTo("df"); + if (isCurrent_fixedDict) + isFixedDict = true; + if (isCurrent_fixedDict || name.IsEqualTo("ds")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, startDicLog)) + if (startDicLog > 32) + return E_INVALIDARG; + startDicLog_Defined = true; + continue; + } + + if (name.IsEqualTo("mts")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, numThreads_Start)) + continue; + } + + if (name.IsEqualTo("af")) + { + UInt32 bundle; + RINOK(ParsePropToUInt32(UString(), propVariant, bundle)) + if (bundle > 0 && bundle < numCPUs) + { + #ifndef Z7_ST + affinityMode.SetLevels(numCPUs, 2); + affinityMode.NumBundleThreads = bundle; + #endif + } + continue; + } + + if (name.IsEqualTo("freq")) + { + UInt32 freq32 = 0; + RINOK(ParsePropToUInt32(UString(), propVariant, freq32)) + if (freq32 == 0) + return E_INVALIDARG; + specifiedFreq = (UInt64)freq32 * 1000000; + + if (printCallback) + { + printCallback->Print("freq="); + PrintNumber(*printCallback, freq32, 0); + printCallback->NewLine(); + } + + continue; + } + + if (name.IsPrefixedBy_Ascii_NoCase("mt")) + { + const UString s = name.Ptr(2); + if (s.IsEqualTo("*") + || (s.IsEmpty() + && propVariant.vt == VT_BSTR + && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))) + { + multiThreadTests = true; + continue; + } + #ifndef Z7_ST + RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified)) + #endif + continue; + } + + RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)) + } + } + + if (printCallback) + { + AString s; + +#if 1 || !defined(Z7_MSC_VER_ORIGINAL) || (Z7_MSC_VER_ORIGINAL >= 1900) + s += "Compiler: "; + GetCompiler(s); + printCallback->Print(s); + printCallback->NewLine(); + s.Empty(); +#endif + + GetSystemInfoText(s); + printCallback->Print(s); + printCallback->NewLine(); + } + + if (printCallback) + { + printCallback->Print("1T CPU Freq (MHz):"); + } + + if (printCallback || freqCallback) + { + UInt64 numMilCommands = 1 << 6; + if (specifiedFreq != 0) + { + while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) + numMilCommands >>= 1; + } + + for (int jj = 0;; jj++) + { + if (printCallback) + RINOK(printCallback->CheckBreak()) + + UInt64 start = ::GetTimeCount(); + UInt32 sum = (UInt32)start; + sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp); + if (sum == 0xF1541213) + if (printCallback) + printCallback->Print(""); + const UInt64 realDelta = ::GetTimeCount() - start; + start = realDelta; + if (start == 0) + start = 1; + if (start > (UInt64)1 << 61) + start = 1; + const UInt64 freq = GetFreq(); + // mips is constant in some compilers + const UInt64 hzVal = MyMultDiv64(numMilCommands * 1000000, freq, start); + const UInt64 mipsVal = numMilCommands * freq / start; + if (printCallback) + { + if (realDelta == 0) + { + printCallback->Print(" -"); + } + else + { + // PrintNumber(*printCallback, start, 0); + PrintNumber(*printCallback, mipsVal, 5); + } + } + if (freqCallback) + { + RINOK(freqCallback->AddCpuFreq(1, hzVal, kBenchmarkUsageMult)) + } + + if (jj >= 1) + { + bool needStop = (numMilCommands >= (1 << + #ifdef _DEBUG + 7 + #else + 11 + #endif + )); + if (start >= freq * 16) + { + printCallback->Print(" (Cmplx)"); + if (!freqCallback) // we don't want complexity change for old gui lzma benchmark + { + needSetComplexity = true; + } + needStop = true; + } + if (needSetComplexity) + SetComplexCommandsMs(testTimeMs, false, mipsVal * 1000000, complexInCommands); + if (needStop) + break; + numMilCommands <<= 1; + } + } + if (freqCallback) + { + RINOK(freqCallback->FreqsFinished(1)) + } + } + + if (printCallback || freqCallback) + for (unsigned test = 0; test < 3; test++) + { + if (numThreadsSpecified < 2) + { + // if (test == 1) + break; + } + if (test == 2 && numThreadsSpecified <= numCPUs) + break; + if (printCallback) + printCallback->NewLine(); + + /* it can show incorrect frequency for HT threads. */ + + UInt32 numThreads = numThreadsSpecified; + if (test < 2) + { + if (numThreads >= numCPUs) + numThreads = numCPUs; + if (test == 0) + numThreads /= 2; + } + if (numThreads < 1) + numThreads = 1; + + if (printCallback) + { + char s[128]; + ConvertUInt64ToString(numThreads, s); + printCallback->Print(s); + printCallback->Print("T CPU Freq (MHz):"); + } + UInt64 numMilCommands = 1 << + #ifdef _DEBUG + 7; + #else + 10; + #endif + + if (specifiedFreq != 0) + { + while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) + numMilCommands >>= 1; + } + + // for (int jj = 0;; jj++) + for (;;) + { + if (printCallback) + RINOK(printCallback->CheckBreak()) + + { + // PrintLeft(f, "CPU", kFieldSize_Name); + + // UInt32 resVal; + + CFreqBench fb; + fb.complexInCommands = numMilCommands * 1000000; + fb.numThreads = numThreads; + // showFreq; + // fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0); + fb.showFreq = true; + fb.specifiedFreq = 1; + + const HRESULT res = fb.FreqBench(NULL /* printCallback */ + #ifndef Z7_ST + , &affinityMode + #endif + ); + RINOK(res) + + if (freqCallback) + { + RINOK(freqCallback->AddCpuFreq(numThreads, fb.CpuFreqRes, fb.UsageRes)) + } + + if (printCallback) + { + /* + if (realDelta == 0) + { + printCallback->Print(" -"); + } + else + */ + { + // PrintNumber(*printCallback, start, 0); + PrintUsage(*printCallback, fb.UsageRes, 3); + printCallback->Print("%"); + PrintNumber(*printCallback, fb.CpuFreqRes / 1000000, 0); + printCallback->Print(" "); + + // PrintNumber(*printCallback, fb.UsageRes, 5); + } + } + } + // if (jj >= 1) + { + const bool needStop = (numMilCommands >= (1 << + #ifdef _DEBUG + 7 + #else + 11 + #endif + )); + if (needStop) + break; + numMilCommands <<= 1; + } + } + if (freqCallback) + { + RINOK(freqCallback->FreqsFinished(numThreads)) + } + } + + + if (printCallback) + { + printCallback->NewLine(); + printCallback->NewLine(); + PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs); + printCallback->Print(GetProcessThreadsInfo(threadsInfo)); + printCallback->NewLine(); + } + + if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax) + return E_INVALIDARG; + + UInt64 dict = (UInt64)1 << startDicLog; + const bool dictIsDefined = (isFixedDict || method.Get_DicSize(dict)); + + const unsigned level = method.GetLevel(); + + AString &methodName = method.MethodName; + const AString original_MethodName = methodName; + if (methodName.IsEmpty()) + methodName = "LZMA"; + + if (benchCallback) + { + CBenchProps benchProps; + benchProps.SetLzmaCompexity(); + const UInt64 dictSize = method.Get_Lzma_DicSize(); + + size_t uncompressedDataSize; + if (use_fileData) + { + uncompressedDataSize = fileDataBuffer.Size(); + } + else + { + uncompressedDataSize = kAdditionalSize + (size_t)dictSize; + if (uncompressedDataSize < dictSize) + return E_INVALIDARG; + } + + return MethodBench( + EXTERNAL_CODECS_LOC_VARS + complexInCommands, + #ifndef Z7_ST + true, numThreadsSpecified, + &affinityMode, + #endif + method, + uncompressedDataSize, (const Byte *)fileDataBuffer, + kOldLzmaDictBits, printCallback, benchCallback, &benchProps); + } + + if (methodName.IsEqualTo_Ascii_NoCase("CRC")) + methodName = "crc32"; + + CMethodId hashID; + const bool isHashMethod = FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID); + int codecIndex = -1; + bool isFilter = false; + if (!isHashMethod) + { + UInt32 numStreams; + codecIndex = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS original_MethodName, + true, // encode + hashID, numStreams, isFilter); + // we can allow non filter for BW tests + if (!isFilter) codecIndex = -1; + } + + CBenchCallbackToPrint callback; + callback.Init(); + callback._file = printCallback; + + if (isHashMethod || codecIndex != -1) + { + if (!printCallback) + return S_FALSE; + IBenchPrintCallback &f = *printCallback; + + UInt64 dict64 = dict; + if (!dictIsDefined) + dict64 = (1 << 27); + if (use_fileData) + { + if (!dictIsDefined) + dict64 = fileDataBuffer.Size(); + else if (dict64 > fileDataBuffer.Size()) + dict64 = fileDataBuffer.Size(); + } + + for (;;) + { + const int index = method.FindProp(NCoderPropID::kDictionarySize); + if (index < 0) + break; + method.Props.Delete((unsigned)index); + } + + // methodName.RemoveChar(L'-'); + Int32 complexity = 16 * k_Hash_Complex_Mult; // for unknown hash method + const UInt32 *checkSum = NULL; + int benchIndex = -1; + + if (isHashMethod) + { + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++) + { + const CBenchHash &h = g_Hash[i]; + AString benchMethod (h.Name); + AString benchProps; + const int propPos = benchMethod.Find(':'); + if (propPos >= 0) + { + benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); + benchMethod.DeleteFrom((unsigned)propPos); + } + + if (AreSameMethodNames(benchMethod, methodName)) + { + const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); + /* + bool isMainMethod = method.PropsString.IsEmpty(); + if (isMainMethod) + isMainMethod = !checkSum + || (benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps.IsEqualTo_Ascii_NoCase("8")); + if (sameProps || isMainMethod) + */ + { + complexity = (Int32)h.Complex; + checkSum = &h.CheckSum; + if (sameProps) + break; + /* + if property. is not specified, we use the complexity + for latest fastest method (crc32:64) + */ + } + } + } + // if (!checkSum) return E_NOTIMPL; + } + else + { + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) + { + const CBenchMethod &bench = g_Bench[i]; + AString benchMethod (bench.Name); + AString benchProps; + const int propPos = benchMethod.Find(':'); + if (propPos >= 0) + { + benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); + benchMethod.DeleteFrom((unsigned)propPos); + } + + if (AreSameMethodNames(benchMethod, methodName)) + { + const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); + // bool isMainMethod = method.PropsString.IsEmpty(); + // if (sameProps || isMainMethod) + { + benchIndex = (int)i; + if (sameProps) + break; + } + } + } + // if (benchIndex < 0) return E_NOTIMPL; + } + + { + /* we count usage only for crc and filter. non-filters are not supported */ + UInt64 usage = (1 << 20); + UInt64 bufSize = dict64; + UInt32 numBlocks = isHashMethod ? 1 : 3; + if (use_fileData) + { + usage += fileDataBuffer.Size(); + if (bufSize > fileDataBuffer.Size()) + bufSize = fileDataBuffer.Size(); + if (isHashMethod) + { + numBlocks = 0; + #ifndef Z7_ST + if (numThreadsSpecified != 1) + numBlocks = (k_Crc_CreateLocalBuf_For_File ? 1 : 0); + #endif + } + } + usage += numThreadsSpecified * bufSize * numBlocks; + Print_Usage_and_Threads(f, usage, numThreadsSpecified); + } + + CUIntVector numThreadsVector; + { + unsigned nt = numThreads_Start; + for (;;) + { + if (nt > numThreadsSpecified) + break; + numThreadsVector.Add(nt); + const unsigned next = nt * 2; + const UInt32 ntHalf= numThreadsSpecified / 2; + if (ntHalf > nt && ntHalf < next) + numThreadsVector.Add(ntHalf); + if (numThreadsSpecified > nt && numThreadsSpecified < next) + numThreadsVector.Add(numThreadsSpecified); + nt = next; + } + } + + unsigned numColumns = isHashMethod ? 1 : 2; + CTempValues speedTotals; + CTempValues usageTotals; + { + const unsigned numItems = numThreadsVector.Size() * numColumns; + speedTotals.Alloc(numItems); + usageTotals.Alloc(numItems); + for (unsigned i = 0; i < numItems; i++) + { + speedTotals.Values[i] = 0; + usageTotals.Values[i] = 0; + } + } + + f.NewLine(); + for (unsigned line = 0; line < 3; line++) + { + f.NewLine(); + f.Print(line == 0 ? "THRD" : line == 1 ? " " : "Size"); + FOR_VECTOR (ti, numThreadsVector) + { + if (ti != 0) + Print_Delimiter(f); + if (line == 0) + { + PrintSpaces(f, (kFieldSize_CrcSpeed + kFieldSize_Usage + 2) * (numColumns - 1)); + PrintNumber(f, numThreadsVector[ti], 1 + kFieldSize_Usage + kFieldSize_CrcSpeed); + } + else + { + for (unsigned c = 0; c < numColumns; c++) + { + PrintRight(f, line == 1 ? "Usage" : "%", kFieldSize_Usage + 1); + PrintRight(f, line == 1 ? "BW" : "MB/s", kFieldSize_CrcSpeed + 1); + } + } + } + } + f.NewLine(); + + UInt64 numSteps = 0; + + // for (UInt32 iter = 0; iter < numIterations; iter++) + // { + unsigned pow = 10; // kNumHashDictBits + if (startDicLog_Defined) + pow = startDicLog; + + // #define NUM_SUB_BITS 2 + // pow <<= NUM_SUB_BITS; + for (;; pow++) + { + const UInt64 bufSize = (UInt64)1 << pow; + // UInt64 bufSize = (UInt64)1 << (pow >> NUM_SUB_BITS); + // bufSize += ((UInt64)pow & ((1 << NUM_SUB_BITS) - 1)) << ((pow >> NUM_SUB_BITS) - NUM_SUB_BITS); + + size_t dataSize = fileDataBuffer.Size(); + if (dataSize > bufSize || !use_fileData) + dataSize = (size_t)bufSize; + + for (UInt32 iter = 0; iter < numIterations; iter++) + { + Print_Pow(f, pow); + // PrintNumber(f, bufSize >> 10, 4); + + FOR_VECTOR (ti, numThreadsVector) + { + RINOK(f.CheckBreak()) + const UInt32 numThreads = numThreadsVector[ti]; + if (isHashMethod) + { + UInt64 speed = 0; + UInt64 usage = 0; + const HRESULT res = CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, + numThreads, + dataSize, (const Byte *)fileDataBuffer, + speed, usage, + (UInt32)complexity, + 1, // benchWeight, + (pow == kNumHashDictBits && !use_fileData) ? checkSum : NULL, + method, + &f, + #ifndef Z7_ST + &affinityMode, + #endif + false, // showRating + NULL, false, 0); + RINOK(res) + + if (ti != 0) + Print_Delimiter(f); + + Bench_BW_Print_Usage_Speed(f, usage, speed); + speedTotals.Values[ti] += speed; + usageTotals.Values[ti] += usage; + } + else + { + { + unsigned keySize = 32; + if (IsString1PrefixedByString2(methodName, "AES128")) keySize = 16; + else if (IsString1PrefixedByString2(methodName, "AES192")) keySize = 24; + callback.BenchProps.KeySize = keySize; + } + + COneMethodInfo method2 = method; + unsigned bench_DictBits; + + if (benchIndex >= 0) + { + const CBenchMethod &bench = g_Bench[benchIndex]; + callback.BenchProps.EncComplex = bench.EncComplex; + callback.BenchProps.DecComplexUnc = bench.DecComplexUnc; + callback.BenchProps.DecComplexCompr = bench.DecComplexCompr; + bench_DictBits = bench.DictBits; + // bench_DictBits = kOldLzmaDictBits; = 32 default : for debug + } + else + { + bench_DictBits = kOldLzmaDictBits; // = 32 default + if (isFilter) + { + const unsigned k_UnknownCoderComplexity = 4; + callback.BenchProps.EncComplex = k_UnknownCoderComplexity; + callback.BenchProps.DecComplexUnc = k_UnknownCoderComplexity; + } + else + { + callback.BenchProps.EncComplex = 1 << 10; + callback.BenchProps.DecComplexUnc = 1 << 6; + } + callback.BenchProps.DecComplexCompr = 0; + } + callback.NeedPrint = false; + + if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA")) + { + const NCOM::CPropVariant propVariant = (UInt32)pow; + RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)) + } + + const HRESULT res = MethodBench( + EXTERNAL_CODECS_LOC_VARS + complexInCommands, + #ifndef Z7_ST + false, // oldLzmaBenchMode + numThreadsVector[ti], + &affinityMode, + #endif + method2, + dataSize, (const Byte *)fileDataBuffer, + bench_DictBits, + printCallback, + &callback, + &callback.BenchProps); + RINOK(res) + + if (ti != 0) + Print_Delimiter(f); + + for (unsigned i = 0; i < 2; i++) + { + const CBenchInfo &bi = callback.BenchInfo_Results[i]; + const UInt64 usage = bi.GetUsage(); + const UInt64 speed = bi.GetUnpackSizeSpeed(); + usageTotals.Values[ti * 2 + i] += usage; + speedTotals.Values[ti * 2 + i] += speed; + Bench_BW_Print_Usage_Speed(f, usage, speed); + } + } + } + + f.NewLine(); + numSteps++; + } + if (dataSize >= dict64) + break; + } + + if (numSteps != 0) + { + f.Print("Avg:"); + for (unsigned ti = 0; ti < numThreadsVector.Size(); ti++) + { + if (ti != 0) + Print_Delimiter(f); + for (unsigned i = 0; i < numColumns; i++) + Bench_BW_Print_Usage_Speed(f, + usageTotals.Values[ti * numColumns + i] / numSteps, + speedTotals.Values[ti * numColumns + i] / numSteps); + } + f.NewLine(); + } + + return S_OK; + } + + bool use2Columns = false; + + bool totalBenchMode = false; + bool onlyHashBench = false; + if (methodName.IsEqualTo_Ascii_NoCase("hash")) + { + onlyHashBench = true; + methodName = "*"; + totalBenchMode = true; + } + else if (methodName.Find('*') >= 0) + totalBenchMode = true; + + // ---------- Threads loop ---------- + for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++) + { + + UInt32 numThreads = numThreadsSpecified; + + if (!multiThreadTests) + { + if (threadsPassIndex != 0) + break; + } + else + { + numThreads = 1; + if (threadsPassIndex != 0) + { + if (numCPUs < 2) + break; + numThreads = numCPUs; + if (threadsPassIndex == 1) + { + if (numCPUs >= 4) + numThreads = numCPUs / 2; + } + else if (numCPUs < 4) + break; + } + } + + IBenchPrintCallback &f = *printCallback; + + if (threadsPassIndex > 0) + { + f.NewLine(); + f.NewLine(); + } + + if (!dictIsDefined && !onlyHashBench) + { + // we use dicSizeLog and dicSizeLog_Main for data size. + // also we use it to reduce dictionary size of LZMA encoder via NCoderPropID::kReduceSize. + const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); + unsigned dicSizeLog = dicSizeLog_Main; + + #ifdef UNDER_CE + dicSizeLog = (UInt64)1 << 20; + #endif + + if (ramSize_Defined) + for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) + if (GetBenchMemoryUsage(numThreads, (int)level, ((UInt64)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) + break; + + dict = (UInt64)1 << dicSizeLog; + + if (totalBenchMode && dicSizeLog != dicSizeLog_Main) + { + f.Print("Dictionary reduced to: "); + PrintNumber(f, dicSizeLog, 1); + f.NewLine(); + } + } + + Print_Usage_and_Threads(f, + onlyHashBench ? + GetBenchMemoryUsage_Hash(numThreads, dict) : + GetBenchMemoryUsage(numThreads, (int)level, dict, totalBenchMode), + numThreads); + + f.NewLine(); + + f.NewLine(); + + if (totalBenchMode) + { + callback.NameFieldSize = kFieldSize_Name; + use2Columns = false; + } + else + { + callback.NameFieldSize = kFieldSize_SmallName; + use2Columns = true; + } + callback.Use2Columns = use2Columns; + + bool showFreq = false; + UInt64 cpuFreq = 0; + + if (totalBenchMode) + { + showFreq = true; + } + + unsigned fileldSize = kFieldSize_TotalSize; + if (showFreq) + fileldSize += kFieldSize_EUAndEffec; + + if (use2Columns) + { + PrintSpaces(f, callback.NameFieldSize); + PrintRight(f, "Compressing", fileldSize); + f.Print(kSep); + PrintRight(f, "Decompressing", fileldSize); + } + f.NewLine(); + PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize); + + int j; + + for (j = 0; j < 2; j++) + { + PrintRight(f, "Speed", kFieldSize_Speed + 1); + PrintRight(f, "Usage", kFieldSize_Usage + 1); + PrintRight(f, "R/U", kFieldSize_RU + 1); + PrintRight(f, "Rating", kFieldSize_Rating + 1); + if (showFreq) + { + PrintRight(f, "E/U", kFieldSize_EU + 1); + PrintRight(f, "Effec", kFieldSize_Effec + 1); + } + if (!use2Columns) + break; + if (j == 0) + f.Print(kSep); + } + + f.NewLine(); + PrintSpaces(f, callback.NameFieldSize); + + for (j = 0; j < 2; j++) + { + PrintRight(f, "KiB/s", kFieldSize_Speed + 1); + PrintRight(f, "%", kFieldSize_Usage + 1); + PrintRight(f, "MIPS", kFieldSize_RU + 1); + PrintRight(f, "MIPS", kFieldSize_Rating + 1); + if (showFreq) + { + PrintRight(f, "%", kFieldSize_EU + 1); + PrintRight(f, "%", kFieldSize_Effec + 1); + } + if (!use2Columns) + break; + if (j == 0) + f.Print(kSep); + } + + f.NewLine(); + f.NewLine(); + + if (specifiedFreq != 0) + cpuFreq = specifiedFreq; + + // bool showTotalSpeed = false; + + if (totalBenchMode) + { + for (UInt32 i = 0; i < numIterations; i++) + { + if (i != 0) + printCallback->NewLine(); + + const unsigned kNumCpuTests = 3; + for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++) + { + PrintLeft(f, "CPU", kFieldSize_Name); + + // UInt32 resVal; + + CFreqBench fb; + fb.complexInCommands = complexInCommands; + fb.numThreads = numThreads; + // showFreq; + fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0); + fb.specifiedFreq = specifiedFreq; + + const HRESULT res = fb.FreqBench(printCallback + #ifndef Z7_ST + , &affinityMode + #endif + ); + RINOK(res) + + cpuFreq = fb.CpuFreqRes; + callback.NewLine(); + + if (specifiedFreq != 0) + cpuFreq = specifiedFreq; + + if (testTimeMs >= 1000) + if (freqTest == kNumCpuTests - 1) + { + // SetComplexCommandsMs(testTimeMs, specifiedFreq != 0, cpuFreq, complexInCommands); + } + } + callback.NewLine(); + + // return S_OK; // change it + + callback.SetFreq(true, cpuFreq); + + if (!onlyHashBench) + { + size_t dataSize = (size_t)dict; + if (use_fileData) + { + dataSize = fileDataBuffer.Size(); + if (dictIsDefined && dataSize > dict) + dataSize = (size_t)dict; + } + + const HRESULT res = TotalBench(EXTERNAL_CODECS_LOC_VARS + method, complexInCommands, + #ifndef Z7_ST + numThreads, + &affinityMode, + #endif + dictIsDefined || use_fileData, // forceUnpackSize + dataSize, + (const Byte *)fileDataBuffer, + printCallback, &callback); + RINOK(res) + } + + { + size_t dataSize = (size_t)1 << kNumHashDictBits; + if (dictIsDefined) + { + dataSize = (size_t)dict; + if (dataSize != dict) + return E_OUTOFMEMORY; + } + if (use_fileData) + { + dataSize = fileDataBuffer.Size(); + if (dictIsDefined && dataSize > dict) + dataSize = (size_t)dict; + } + + const HRESULT res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS + method, complexInCommands, + numThreads, + dataSize, (const Byte *)fileDataBuffer, + printCallback, &callback, + #ifndef Z7_ST + &affinityMode, + #endif + &callback.EncodeRes, true, cpuFreq); + RINOK(res) + } + + callback.NewLine(); + { + PrintLeft(f, "CPU", kFieldSize_Name); + + CFreqBench fb; + fb.complexInCommands = complexInCommands; + fb.numThreads = numThreads; + // showFreq; + fb.showFreq = (specifiedFreq != 0); + fb.specifiedFreq = specifiedFreq; + + const HRESULT res = fb.FreqBench(printCallback + #ifndef Z7_ST + , &affinityMode + #endif + ); + RINOK(res) + callback.NewLine(); + } + } + } + else + { + needSetComplexity = true; + if (!methodName.IsEqualTo_Ascii_NoCase("LZMA")) + { + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) + { + const CBenchMethod &h = g_Bench[i]; + AString benchMethod (h.Name); + AString benchProps; + const int propPos = benchMethod.Find(':'); + if (propPos >= 0) + { + benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); + benchMethod.DeleteFrom((unsigned)propPos); + } + + if (AreSameMethodNames(benchMethod, methodName)) + { + if (benchProps.IsEmpty() + || (benchProps == "x5" && method.PropsString.IsEmpty()) + || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) + { + callback.BenchProps.EncComplex = h.EncComplex; + callback.BenchProps.DecComplexCompr = h.DecComplexCompr; + callback.BenchProps.DecComplexUnc = h.DecComplexUnc; + needSetComplexity = false; + break; + } + } + } + /* + if (i == Z7_ARRAY_SIZE(g_Bench)) + return E_NOTIMPL; + */ + } + if (needSetComplexity) + callback.BenchProps.SetLzmaCompexity(); + + if (startDicLog < kBenchMinDicLogSize) + startDicLog = kBenchMinDicLogSize; + + for (unsigned i = 0; i < numIterations; i++) + { + unsigned pow = (dict < GetDictSizeFromLog(startDicLog)) ? kBenchMinDicLogSize : (unsigned)startDicLog; + if (!multiDict) + pow = 32; + while (GetDictSizeFromLog(pow) > dict && pow > 0) + pow--; + for (; GetDictSizeFromLog(pow) <= dict; pow++) + { + Print_Pow(f, pow); + callback.DictSize = (UInt64)1 << pow; + + COneMethodInfo method2 = method; + + if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA")) + { + // We add dictionary size property. + // method2 can have two different dictionary size properties. + // And last property is main. + NCOM::CPropVariant propVariant = (UInt32)pow; + RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)) + } + + size_t uncompressedDataSize; + if (use_fileData) + { + uncompressedDataSize = fileDataBuffer.Size(); + } + else + { + uncompressedDataSize = (size_t)callback.DictSize; + if (uncompressedDataSize != callback.DictSize) + return E_OUTOFMEMORY; + if (uncompressedDataSize >= (1 << 18)) + uncompressedDataSize += kAdditionalSize; + } + + const HRESULT res = MethodBench( + EXTERNAL_CODECS_LOC_VARS + complexInCommands, + #ifndef Z7_ST + true, numThreads, + &affinityMode, + #endif + method2, + uncompressedDataSize, (const Byte *)fileDataBuffer, + kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps); + f.NewLine(); + RINOK(res) + if (!multiDict) + break; + } + } + } + + PrintChars(f, '-', callback.NameFieldSize + fileldSize); + + if (use2Columns) + { + f.Print(kSep); + PrintChars(f, '-', fileldSize); + } + + f.NewLine(); + + if (use2Columns) + { + PrintLeft(f, "Avr:", callback.NameFieldSize); + PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.EncodeRes); + f.Print(kSep); + PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.DecodeRes); + f.NewLine(); + } + + PrintLeft(f, "Tot:", callback.NameFieldSize); + CTotalBenchRes midRes; + midRes = callback.EncodeRes; + midRes.Update_With_Res(callback.DecodeRes); + + // midRes.SetSum(callback.EncodeRes, callback.DecodeRes); + PrintTotals(f, showFreq, cpuFreq, false, midRes); + f.NewLine(); + + } + return S_OK; +} diff --git a/CPP/7zip/UI/Common/Bench.h b/CPP/7zip/UI/Common/Bench.h index 5e16faaaf..313676dd5 100644 --- a/CPP/7zip/UI/Common/Bench.h +++ b/CPP/7zip/UI/Common/Bench.h @@ -1,121 +1,121 @@ -// Bench.h - -#ifndef ZIP7_INC_7ZIP_BENCH_H -#define ZIP7_INC_7ZIP_BENCH_H - -#include "../../../Windows/System.h" - -#include "../../Common/CreateCoder.h" -#include "../../UI/Common/Property.h" - -UInt64 Benchmark_GetUsage_Percents(UInt64 usage); - -struct CBenchInfo -{ - UInt64 GlobalTime; - UInt64 GlobalFreq; - UInt64 UserTime; - UInt64 UserFreq; - UInt64 UnpackSize; - UInt64 PackSize; - UInt64 NumIterations; - - /* - during Code(): we track benchInfo only from one thread (theads with index[0]) - NumIterations means number of threads - UnpackSize and PackSize are total sizes of all iterations of current thread - after Code(): - NumIterations means the number of Iterations - UnpackSize and PackSize are total sizes of all threads - */ - - CBenchInfo(): NumIterations(0) {} - - UInt64 GetUsage() const; - UInt64 GetRatingPerUsage(UInt64 rating) const; - UInt64 GetSpeed(UInt64 numUnits) const; - UInt64 GetUnpackSizeSpeed() const { return GetSpeed(UnpackSize * NumIterations); } - - UInt64 Get_UnpackSize_Full() const { return UnpackSize * NumIterations; } - - UInt64 GetRating_LzmaEnc(UInt64 dictSize) const; - UInt64 GetRating_LzmaDec() const; -}; - - -struct CTotalBenchRes -{ - // UInt64 NumIterations1; // for Usage - UInt64 NumIterations2; // for Rating / RPU - - UInt64 Rating; - UInt64 Usage; - UInt64 RPU; - UInt64 Speed; - - void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; Speed = 0; } - - void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2) - { - Rating = (r1.Rating + r2.Rating); - Usage = (r1.Usage + r2.Usage); - RPU = (r1.RPU + r2.RPU); - Speed = (r1.Speed + r2.Speed); - // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); - NumIterations2 = (r1.NumIterations2 + r2.NumIterations2); - } - - void Generate_From_BenchInfo(const CBenchInfo &info); - void Mult_For_Weight(unsigned weight); - void Update_With_Res(const CTotalBenchRes &r); -}; - - -const unsigned kBenchMinDicLogSize = 18; - -UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench); - -Z7_PURE_INTERFACES_BEGIN -DECLARE_INTERFACE(IBenchCallback) -{ - // virtual HRESULT SetFreq(bool showFreq, UInt64 cpuFreq) = 0; - virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0; - virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0; -}; - -DECLARE_INTERFACE(IBenchPrintCallback) -{ - virtual void Print(const char *s) = 0; - virtual void NewLine() = 0; - virtual HRESULT CheckBreak() = 0; -}; - -DECLARE_INTERFACE(IBenchFreqCallback) -{ - virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) = 0; - virtual HRESULT FreqsFinished(unsigned numThreads) = 0; -}; -Z7_PURE_INTERFACES_END - -HRESULT Bench( - DECL_EXTERNAL_CODECS_LOC_VARS - IBenchPrintCallback *printCallback, - IBenchCallback *benchCallback, - const CObjectVector &props, - UInt32 numIterations, - bool multiDict, - IBenchFreqCallback *freqCallback = NULL); - -AString GetProcessThreadsInfo(const NWindows::NSystem::CProcessAffinity &ti); - -void GetSysInfo(AString &s1, AString &s2); -void GetCpuName(AString &s); -void AddCpuFeatures(AString &s); - -#ifdef Z7_LARGE_PAGES -void Add_LargePages_String(AString &s); -#else -// #define Add_LargePages_String -#endif - -#endif +// Bench.h + +#ifndef ZIP7_INC_7ZIP_BENCH_H +#define ZIP7_INC_7ZIP_BENCH_H + +#include "../../../Windows/System.h" + +#include "../../Common/CreateCoder.h" +#include "../../UI/Common/Property.h" + +UInt64 Benchmark_GetUsage_Percents(UInt64 usage); + +struct CBenchInfo +{ + UInt64 GlobalTime; + UInt64 GlobalFreq; + UInt64 UserTime; + UInt64 UserFreq; + UInt64 UnpackSize; + UInt64 PackSize; + UInt64 NumIterations; + + /* + during Code(): we track benchInfo only from one thread (theads with index[0]) + NumIterations means number of threads + UnpackSize and PackSize are total sizes of all iterations of current thread + after Code(): + NumIterations means the number of Iterations + UnpackSize and PackSize are total sizes of all threads + */ + + CBenchInfo(): NumIterations(0) {} + + UInt64 GetUsage() const; + UInt64 GetRatingPerUsage(UInt64 rating) const; + UInt64 GetSpeed(UInt64 numUnits) const; + UInt64 GetUnpackSizeSpeed() const { return GetSpeed(UnpackSize * NumIterations); } + + UInt64 Get_UnpackSize_Full() const { return UnpackSize * NumIterations; } + + UInt64 GetRating_LzmaEnc(UInt64 dictSize) const; + UInt64 GetRating_LzmaDec() const; +}; + + +struct CTotalBenchRes +{ + // UInt64 NumIterations1; // for Usage + UInt64 NumIterations2; // for Rating / RPU + + UInt64 Rating; + UInt64 Usage; + UInt64 RPU; + UInt64 Speed; + + void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; Speed = 0; } + + void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2) + { + Rating = (r1.Rating + r2.Rating); + Usage = (r1.Usage + r2.Usage); + RPU = (r1.RPU + r2.RPU); + Speed = (r1.Speed + r2.Speed); + // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); + NumIterations2 = (r1.NumIterations2 + r2.NumIterations2); + } + + void Generate_From_BenchInfo(const CBenchInfo &info); + void Mult_For_Weight(unsigned weight); + void Update_With_Res(const CTotalBenchRes &r); +}; + + +const unsigned kBenchMinDicLogSize = 18; + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench); + +Z7_PURE_INTERFACES_BEGIN +DECLARE_INTERFACE(IBenchCallback) +{ + // virtual HRESULT SetFreq(bool showFreq, UInt64 cpuFreq) = 0; + virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0; + virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0; +}; + +DECLARE_INTERFACE(IBenchPrintCallback) +{ + virtual void Print(const char *s) = 0; + virtual void NewLine() = 0; + virtual HRESULT CheckBreak() = 0; +}; + +DECLARE_INTERFACE(IBenchFreqCallback) +{ + virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) = 0; + virtual HRESULT FreqsFinished(unsigned numThreads) = 0; +}; +Z7_PURE_INTERFACES_END + +HRESULT Bench( + DECL_EXTERNAL_CODECS_LOC_VARS + IBenchPrintCallback *printCallback, + IBenchCallback *benchCallback, + const CObjectVector &props, + UInt32 numIterations, + bool multiDict, + IBenchFreqCallback *freqCallback = NULL); + +AString GetProcessThreadsInfo(const NWindows::NSystem::CProcessAffinity &ti); + +void GetSysInfo(AString &s1, AString &s2); +void GetCpuName(AString &s); +void AddCpuFeatures(AString &s); + +#ifdef Z7_LARGE_PAGES +void Add_LargePages_String(AString &s); +#else +// #define Add_LargePages_String +#endif + +#endif diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp index 9993ab44c..1ded1b393 100644 --- a/CPP/7zip/UI/Common/CompressCall.cpp +++ b/CPP/7zip/UI/Common/CompressCall.cpp @@ -1,343 +1,343 @@ -// CompressCall.cpp - -#include "StdAfx.h" - -#include - -#include "../../../Common/IntToString.h" -#include "../../../Common/MyCom.h" -#include "../../../Common/Random.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileMapping.h" -#include "../../../Windows/MemoryLock.h" -#include "../../../Windows/ProcessUtils.h" -#include "../../../Windows/Synchronization.h" - -#include "../FileManager/RegistryUtils.h" - -#include "CompressCall.h" - -using namespace NWindows; - -#define MY_TRY_BEGIN try { - -#define MY_TRY_FINISH } \ - catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; } - -#define MY_TRY_FINISH_VOID } \ - catch(...) { ErrorMessageHRESULT(E_FAIL); } - -#define k7zGui "7zG.exe" - -// 21.07 : we can disable wildcard -// #define ISWITCH_NO_WILDCARD_POSTFIX "w-" -#define ISWITCH_NO_WILDCARD_POSTFIX - -#define kShowDialogSwitch " -ad" -#define kEmailSwitch " -seml." -#define kArchiveTypeSwitch " -t" -#define kIncludeSwitch " -i" ISWITCH_NO_WILDCARD_POSTFIX -#define kArcIncludeSwitches " -an -ai" ISWITCH_NO_WILDCARD_POSTFIX -#define kHashIncludeSwitches kIncludeSwitch -#define kStopSwitchParsing " --" - -extern HWND g_HWND; - -UString GetQuotedString(const UString &s) -{ - UString s2 ('\"'); - s2 += s; - s2.Add_Char('\"'); - return s2; -} - -static void ErrorMessage(LPCWSTR message) -{ - MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK); -} - -static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL) -{ - UString s2 = NError::MyFormatMessage(res); - if (s) - { - s2.Add_LF(); - s2 += s; - } - ErrorMessage(s2); -} - -static HRESULT Call7zGui(const UString ¶ms, - // LPCWSTR curDir, - bool waitFinish, - NSynchronization::CBaseEvent *event) -{ - UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); - imageName += k7zGui; - - CProcess process; - const WRes wres = process.Create(imageName, params, NULL); // curDir); - if (wres != 0) - { - const HRESULT hres = HRESULT_FROM_WIN32(wres); - ErrorMessageHRESULT(hres, imageName); - return hres; - } - if (waitFinish) - process.Wait(); - else if (event != NULL) - { - HANDLE handles[] = { process, *event }; - ::WaitForMultipleObjects(Z7_ARRAY_SIZE(handles), handles, FALSE, INFINITE); - } - return S_OK; -} - -static void AddLagePagesSwitch(UString ¶ms) -{ - if (ReadLockMemoryEnable()) - #ifndef UNDER_CE - if (NSecurity::Get_LargePages_RiskLevel() == 0) - #endif - params += " -slp"; -} - -class CRandNameGenerator -{ - CRandom _random; -public: - CRandNameGenerator() { _random.Init(); } - void GenerateName(UString &s, const char *prefix) - { - s += prefix; - s.Add_UInt32((UInt32)(unsigned)_random.Generate()); - } -}; - -static HRESULT CreateMap(const UStringVector &names, - CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event, - UString ¶ms) -{ - size_t totalSize = 1; - { - FOR_VECTOR (i, names) - totalSize += (names[i].Len() + 1); - } - totalSize *= sizeof(wchar_t); - - CRandNameGenerator random; - - UString mappingName; - for (;;) - { - random.GenerateName(mappingName, "7zMap"); - const WRes wres = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName)); - if (fileMapping.IsCreated() && wres == 0) - break; - if (wres != ERROR_ALREADY_EXISTS) - return HRESULT_FROM_WIN32(wres); - fileMapping.Close(); - } - - UString eventName; - for (;;) - { - random.GenerateName(eventName, "7zEvent"); - const WRes wres = event.CreateWithName(false, GetSystemString(eventName)); - if (event.IsCreated() && wres == 0) - break; - if (wres != ERROR_ALREADY_EXISTS) - return HRESULT_FROM_WIN32(wres); - event.Close(); - } - - params.Add_Char('#'); - params += mappingName; - params.Add_Colon(); - char temp[32]; - ConvertUInt64ToString(totalSize, temp); - params += temp; - - params.Add_Colon(); - params += eventName; - - LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize); - if (!data) - return E_FAIL; - CFileUnmapper unmapper(data); - { - wchar_t *cur = (wchar_t *)data; - *cur++ = 0; // it means wchar_t strings (UTF-16 in WIN32) - FOR_VECTOR (i, names) - { - const UString &s = names[i]; - const unsigned len = s.Len() + 1; - wmemcpy(cur, (const wchar_t *)s, len); - cur += len; - } - } - return S_OK; -} - -HRESULT CompressFiles( - const UString &arcPathPrefix, - const UString &arcName, - const UString &arcType, - bool addExtension, - const UStringVector &names, - bool email, bool showDialog, bool waitFinish) -{ - MY_TRY_BEGIN - UString params ('a'); - - CFileMapping fileMapping; - NSynchronization::CManualResetEvent event; - params += kIncludeSwitch; - RINOK(CreateMap(names, fileMapping, event, params)) - - if (!arcType.IsEmpty()) - { - params += kArchiveTypeSwitch; - params += arcType; - } - - if (email) - params += kEmailSwitch; - - if (showDialog) - params += kShowDialogSwitch; - - AddLagePagesSwitch(params); - - if (arcName.IsEmpty()) - params += " -an"; - - if (addExtension) - params += " -saa"; - else - params += " -sae"; - - params += kStopSwitchParsing; - params.Add_Space(); - - if (!arcName.IsEmpty()) - { - params += GetQuotedString( - // #ifdef UNDER_CE - arcPathPrefix + - // #endif - arcName); - } - - return Call7zGui(params, - // (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), - waitFinish, &event); - MY_TRY_FINISH -} - -static void ExtractGroupCommand(const UStringVector &arcPaths, UString ¶ms, bool isHash) -{ - AddLagePagesSwitch(params); - params += (isHash ? kHashIncludeSwitches : kArcIncludeSwitches); - CFileMapping fileMapping; - NSynchronization::CManualResetEvent event; - HRESULT result = CreateMap(arcPaths, fileMapping, event, params); - if (result == S_OK) - result = Call7zGui(params, false, &event); - if (result != S_OK) - ErrorMessageHRESULT(result); -} - -void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone) -{ - MY_TRY_BEGIN - UString params ('x'); - if (!outFolder.IsEmpty()) - { - params += " -o"; - params += GetQuotedString(outFolder); - } - if (elimDup) - params += " -spe"; - if (writeZone != (UInt32)(Int32)-1) - { - params += " -snz"; - params.Add_UInt32(writeZone); - } - if (showDialog) - params += kShowDialogSwitch; - ExtractGroupCommand(arcPaths, params, false); - MY_TRY_FINISH_VOID -} - - -void TestArchives(const UStringVector &arcPaths, bool hashMode) -{ - MY_TRY_BEGIN - UString params ('t'); - if (hashMode) - { - params += kArchiveTypeSwitch; - params += "hash"; - } - ExtractGroupCommand(arcPaths, params, false); - MY_TRY_FINISH_VOID -} - - -void CalcChecksum(const UStringVector &paths, - const UString &methodName, - const UString &arcPathPrefix, - const UString &arcFileName) -{ - MY_TRY_BEGIN - - if (!arcFileName.IsEmpty()) - { - CompressFiles( - arcPathPrefix, - arcFileName, - UString("hash"), - false, // addExtension, - paths, - false, // email, - false, // showDialog, - false // waitFinish - ); - return; - } - - UString params ('h'); - if (!methodName.IsEmpty()) - { - params += " -scrc"; - params += methodName; - /* - if (!arcFileName.IsEmpty()) - { - // not used alternate method of generating file - params += " -scrf="; - params += GetQuotedString(arcPathPrefix + arcFileName); - } - */ - } - ExtractGroupCommand(paths, params, true); - MY_TRY_FINISH_VOID -} - -void Benchmark(bool totalMode) -{ - MY_TRY_BEGIN - UString params ('b'); - if (totalMode) - params += " -mm=*"; - AddLagePagesSwitch(params); - const HRESULT result = Call7zGui(params, false, NULL); - if (result != S_OK) - ErrorMessageHRESULT(result); - MY_TRY_FINISH_VOID -} +// CompressCall.cpp + +#include "StdAfx.h" + +#include + +#include "../../../Common/IntToString.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/Random.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileMapping.h" +#include "../../../Windows/MemoryLock.h" +#include "../../../Windows/ProcessUtils.h" +#include "../../../Windows/Synchronization.h" + +#include "../FileManager/RegistryUtils.h" + +#include "CompressCall.h" + +using namespace NWindows; + +#define MY_TRY_BEGIN try { + +#define MY_TRY_FINISH } \ + catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; } + +#define MY_TRY_FINISH_VOID } \ + catch(...) { ErrorMessageHRESULT(E_FAIL); } + +#define k7zGui "7zG.exe" + +// 21.07 : we can disable wildcard +// #define ISWITCH_NO_WILDCARD_POSTFIX "w-" +#define ISWITCH_NO_WILDCARD_POSTFIX + +#define kShowDialogSwitch " -ad" +#define kEmailSwitch " -seml." +#define kArchiveTypeSwitch " -t" +#define kIncludeSwitch " -i" ISWITCH_NO_WILDCARD_POSTFIX +#define kArcIncludeSwitches " -an -ai" ISWITCH_NO_WILDCARD_POSTFIX +#define kHashIncludeSwitches kIncludeSwitch +#define kStopSwitchParsing " --" + +extern HWND g_HWND; + +UString GetQuotedString(const UString &s) +{ + UString s2 ('\"'); + s2 += s; + s2.Add_Char('\"'); + return s2; +} + +static void ErrorMessage(LPCWSTR message) +{ + MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK); +} + +static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL) +{ + UString s2 = NError::MyFormatMessage(res); + if (s) + { + s2.Add_LF(); + s2 += s; + } + ErrorMessage(s2); +} + +static HRESULT Call7zGui(const UString ¶ms, + // LPCWSTR curDir, + bool waitFinish, + NSynchronization::CBaseEvent *event) +{ + UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); + imageName += k7zGui; + + CProcess process; + const WRes wres = process.Create(imageName, params, NULL); // curDir); + if (wres != 0) + { + const HRESULT hres = HRESULT_FROM_WIN32(wres); + ErrorMessageHRESULT(hres, imageName); + return hres; + } + if (waitFinish) + process.Wait(); + else if (event != NULL) + { + HANDLE handles[] = { process, *event }; + ::WaitForMultipleObjects(Z7_ARRAY_SIZE(handles), handles, FALSE, INFINITE); + } + return S_OK; +} + +static void AddLagePagesSwitch(UString ¶ms) +{ + if (ReadLockMemoryEnable()) + #ifndef UNDER_CE + if (NSecurity::Get_LargePages_RiskLevel() == 0) + #endif + params += " -slp"; +} + +class CRandNameGenerator +{ + CRandom _random; +public: + CRandNameGenerator() { _random.Init(); } + void GenerateName(UString &s, const char *prefix) + { + s += prefix; + s.Add_UInt32((UInt32)(unsigned)_random.Generate()); + } +}; + +static HRESULT CreateMap(const UStringVector &names, + CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event, + UString ¶ms) +{ + size_t totalSize = 1; + { + FOR_VECTOR (i, names) + totalSize += (names[i].Len() + 1); + } + totalSize *= sizeof(wchar_t); + + CRandNameGenerator random; + + UString mappingName; + for (;;) + { + random.GenerateName(mappingName, "7zMap"); + const WRes wres = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName)); + if (fileMapping.IsCreated() && wres == 0) + break; + if (wres != ERROR_ALREADY_EXISTS) + return HRESULT_FROM_WIN32(wres); + fileMapping.Close(); + } + + UString eventName; + for (;;) + { + random.GenerateName(eventName, "7zEvent"); + const WRes wres = event.CreateWithName(false, GetSystemString(eventName)); + if (event.IsCreated() && wres == 0) + break; + if (wres != ERROR_ALREADY_EXISTS) + return HRESULT_FROM_WIN32(wres); + event.Close(); + } + + params.Add_Char('#'); + params += mappingName; + params.Add_Colon(); + char temp[32]; + ConvertUInt64ToString(totalSize, temp); + params += temp; + + params.Add_Colon(); + params += eventName; + + LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize); + if (!data) + return E_FAIL; + CFileUnmapper unmapper(data); + { + wchar_t *cur = (wchar_t *)data; + *cur++ = 0; // it means wchar_t strings (UTF-16 in WIN32) + FOR_VECTOR (i, names) + { + const UString &s = names[i]; + const unsigned len = s.Len() + 1; + wmemcpy(cur, (const wchar_t *)s, len); + cur += len; + } + } + return S_OK; +} + +HRESULT CompressFiles( + const UString &arcPathPrefix, + const UString &arcName, + const UString &arcType, + bool addExtension, + const UStringVector &names, + bool email, bool showDialog, bool waitFinish) +{ + MY_TRY_BEGIN + UString params ('a'); + + CFileMapping fileMapping; + NSynchronization::CManualResetEvent event; + params += kIncludeSwitch; + RINOK(CreateMap(names, fileMapping, event, params)) + + if (!arcType.IsEmpty()) + { + params += kArchiveTypeSwitch; + params += arcType; + } + + if (email) + params += kEmailSwitch; + + if (showDialog) + params += kShowDialogSwitch; + + AddLagePagesSwitch(params); + + if (arcName.IsEmpty()) + params += " -an"; + + if (addExtension) + params += " -saa"; + else + params += " -sae"; + + params += kStopSwitchParsing; + params.Add_Space(); + + if (!arcName.IsEmpty()) + { + params += GetQuotedString( + // #ifdef UNDER_CE + arcPathPrefix + + // #endif + arcName); + } + + return Call7zGui(params, + // (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix), + waitFinish, &event); + MY_TRY_FINISH +} + +static void ExtractGroupCommand(const UStringVector &arcPaths, UString ¶ms, bool isHash) +{ + AddLagePagesSwitch(params); + params += (isHash ? kHashIncludeSwitches : kArcIncludeSwitches); + CFileMapping fileMapping; + NSynchronization::CManualResetEvent event; + HRESULT result = CreateMap(arcPaths, fileMapping, event, params); + if (result == S_OK) + result = Call7zGui(params, false, &event); + if (result != S_OK) + ErrorMessageHRESULT(result); +} + +void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone) +{ + MY_TRY_BEGIN + UString params ('x'); + if (!outFolder.IsEmpty()) + { + params += " -o"; + params += GetQuotedString(outFolder); + } + if (elimDup) + params += " -spe"; + if (writeZone != (UInt32)(Int32)-1) + { + params += " -snz"; + params.Add_UInt32(writeZone); + } + if (showDialog) + params += kShowDialogSwitch; + ExtractGroupCommand(arcPaths, params, false); + MY_TRY_FINISH_VOID +} + + +void TestArchives(const UStringVector &arcPaths, bool hashMode) +{ + MY_TRY_BEGIN + UString params ('t'); + if (hashMode) + { + params += kArchiveTypeSwitch; + params += "hash"; + } + ExtractGroupCommand(arcPaths, params, false); + MY_TRY_FINISH_VOID +} + + +void CalcChecksum(const UStringVector &paths, + const UString &methodName, + const UString &arcPathPrefix, + const UString &arcFileName) +{ + MY_TRY_BEGIN + + if (!arcFileName.IsEmpty()) + { + CompressFiles( + arcPathPrefix, + arcFileName, + UString("hash"), + false, // addExtension, + paths, + false, // email, + false, // showDialog, + false // waitFinish + ); + return; + } + + UString params ('h'); + if (!methodName.IsEmpty()) + { + params += " -scrc"; + params += methodName; + /* + if (!arcFileName.IsEmpty()) + { + // not used alternate method of generating file + params += " -scrf="; + params += GetQuotedString(arcPathPrefix + arcFileName); + } + */ + } + ExtractGroupCommand(paths, params, true); + MY_TRY_FINISH_VOID +} + +void Benchmark(bool totalMode) +{ + MY_TRY_BEGIN + UString params ('b'); + if (totalMode) + params += " -mm=*"; + AddLagePagesSwitch(params); + const HRESULT result = Call7zGui(params, false, NULL); + if (result != S_OK) + ErrorMessageHRESULT(result); + MY_TRY_FINISH_VOID +} diff --git a/CPP/7zip/UI/Common/CompressCall.h b/CPP/7zip/UI/Common/CompressCall.h index 7c5f6f31c..f2da16312 100644 --- a/CPP/7zip/UI/Common/CompressCall.h +++ b/CPP/7zip/UI/Common/CompressCall.h @@ -1,28 +1,28 @@ -// CompressCall.h - -#ifndef ZIP7_INC_COMPRESS_CALL_H -#define ZIP7_INC_COMPRESS_CALL_H - -#include "../../../Common/MyString.h" - -UString GetQuotedString(const UString &s); - -HRESULT CompressFiles( - const UString &arcPathPrefix, - const UString &arcName, - const UString &arcType, - bool addExtension, - const UStringVector &names, - bool email, bool showDialog, bool waitFinish); - -void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone); -void TestArchives(const UStringVector &arcPaths, bool hashMode = false); - -void CalcChecksum(const UStringVector &paths, - const UString &methodName, - const UString &arcPathPrefix, - const UString &arcFileName); - -void Benchmark(bool totalMode); - -#endif +// CompressCall.h + +#ifndef ZIP7_INC_COMPRESS_CALL_H +#define ZIP7_INC_COMPRESS_CALL_H + +#include "../../../Common/MyString.h" + +UString GetQuotedString(const UString &s); + +HRESULT CompressFiles( + const UString &arcPathPrefix, + const UString &arcName, + const UString &arcType, + bool addExtension, + const UStringVector &names, + bool email, bool showDialog, bool waitFinish); + +void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone); +void TestArchives(const UStringVector &arcPaths, bool hashMode = false); + +void CalcChecksum(const UStringVector &paths, + const UString &methodName, + const UString &arcPathPrefix, + const UString &arcFileName); + +void Benchmark(bool totalMode); + +#endif diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp index e9b5ca1d2..fef0877a3 100644 --- a/CPP/7zip/UI/Common/CompressCall2.cpp +++ b/CPP/7zip/UI/Common/CompressCall2.cpp @@ -1,327 +1,327 @@ -// CompressCall2.cpp - -#include "StdAfx.h" - -#ifndef Z7_EXTERNAL_CODECS - -#include "../../../Common/MyException.h" - -#include "../../UI/Common/EnumDirItems.h" - -#include "../../UI/FileManager/LangUtils.h" - -#include "../../UI/GUI/BenchmarkDialog.h" -#include "../../UI/GUI/ExtractGUI.h" -#include "../../UI/GUI/UpdateGUI.h" -#include "../../UI/GUI/HashGUI.h" - -#include "../../UI/GUI/ExtractRes.h" - -#include "CompressCall.h" - -extern HWND g_HWND; - -#define MY_TRY_BEGIN HRESULT result; try { -#define MY_TRY_FINISH } \ - catch(CSystemException &e) { result = e.ErrorCode; } \ - catch(UString &s) { ErrorMessage(s); result = E_FAIL; } \ - catch(...) { result = E_FAIL; } \ - if (result != S_OK && result != E_ABORT) \ - ErrorMessageHRESULT(result); - -static void ThrowException_if_Error(HRESULT res) -{ - if (res != S_OK) - throw CSystemException(res); -} - -#ifdef Z7_EXTERNAL_CODECS - -#define CREATE_CODECS \ - CCodecs *codecs = new CCodecs; \ - CMyComPtr compressCodecsInfo = codecs; \ - ThrowException_if_Error(codecs->Load()); \ - Codecs_AddHashArcHandler(codecs); - -#define LOAD_EXTERNAL_CODECS \ - CExternalCodecs _externalCodecs; \ - _externalCodecs.GetCodecs = codecs; \ - _externalCodecs.GetHashers = codecs; \ - ThrowException_if_Error(_externalCodecs.Load()); - -#else - -#define CREATE_CODECS \ - CCodecs *codecs = new CCodecs; \ - CMyComPtr compressCodecsInfo = codecs; \ - ThrowException_if_Error(codecs->Load()); \ - Codecs_AddHashArcHandler(codecs); - -#define LOAD_EXTERNAL_CODECS - -#endif - - - - -UString GetQuotedString(const UString &s) -{ - UString s2 ('\"'); - s2 += s; - s2.Add_Char('\"'); - return s2; -} - -static void ErrorMessage(LPCWSTR message) -{ - MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR); -} - -static void ErrorMessageHRESULT(HRESULT res) -{ - ErrorMessage(HResultToMessage(res)); -} - -static void ErrorLangMessage(UINT resourceID) -{ - ErrorMessage(LangString(resourceID)); -} - -HRESULT CompressFiles( - const UString &arcPathPrefix, - const UString &arcName, - const UString &arcType, - bool addExtension, - const UStringVector &names, - bool email, bool showDialog, bool /* waitFinish */) -{ - MY_TRY_BEGIN - - CREATE_CODECS - - CUpdateCallbackGUI callback; - - callback.Init(); - - CUpdateOptions uo; - uo.EMailMode = email; - uo.SetActionCommand_Add(); - - uo.ArcNameMode = (addExtension ? k_ArcNameMode_Add : k_ArcNameMode_Exact); - - CObjectVector formatIndices; - if (!ParseOpenTypes(*codecs, arcType, formatIndices)) - { - ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); - return E_FAIL; - } - const UString arcPath = arcPathPrefix + arcName; - if (!uo.InitFormatIndex(codecs, formatIndices, arcPath) || - !uo.SetArcPath(codecs, arcPath)) - { - ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED); - return E_FAIL; - } - - NWildcard::CCensor censor; - FOR_VECTOR (i, names) - { - censor.AddPreItem_NoWildcard(names[i]); - } - - bool messageWasDisplayed = false; - - result = UpdateGUI(codecs, - formatIndices, arcPath, - censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND); - - if (result != S_OK) - { - if (result != E_ABORT && messageWasDisplayed) - return E_FAIL; - throw CSystemException(result); - } - if (callback.FailedFiles.Size() > 0) - { - if (!messageWasDisplayed) - throw CSystemException(E_FAIL); - return E_FAIL; - } - - MY_TRY_FINISH - return S_OK; -} - - -static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, - bool showDialog, CExtractOptions &eo, const char *kType = NULL) -{ - MY_TRY_BEGIN - - CREATE_CODECS - - CExtractCallbackImp *ecs = new CExtractCallbackImp; - CMyComPtr extractCallback = ecs; - - ecs->Init(); - - // eo.CalcCrc = options.CalcCrc; - - UStringVector arcPathsSorted; - UStringVector arcFullPathsSorted; - { - NWildcard::CCensor arcCensor; - FOR_VECTOR (i, arcPaths) - { - arcCensor.AddPreItem_NoWildcard(arcPaths[i]); - } - arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); - CDirItemsStat st; - EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(), - arcPathsSorted, arcFullPathsSorted, - st, - NULL // &scan: change it!!!! - ); - } - - CObjectVector formatIndices; - if (kType) - { - if (!ParseOpenTypes(*codecs, UString(kType), formatIndices)) - { - throw CSystemException(E_INVALIDARG); - // ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); - // return E_INVALIDARG; - } - } - - NWildcard::CCensor censor; - { - censor.AddPreItem_Wildcard(); - } - - censor.AddPathsToCensor(NWildcard::k_RelatPath); - - bool messageWasDisplayed = false; - - ecs->MultiArcMode = (arcPathsSorted.Size() > 1); - - result = ExtractGUI(codecs, - formatIndices, CIntVector(), - arcPathsSorted, arcFullPathsSorted, - censor.Pairs.Front().Head, eo, NULL, showDialog, messageWasDisplayed, ecs, g_HWND); - - if (result != S_OK) - { - if (result != E_ABORT && messageWasDisplayed) - return E_FAIL; - throw CSystemException(result); - } - return ecs->IsOK() ? S_OK : E_FAIL; - - MY_TRY_FINISH - return result; -} - -void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, - bool showDialog, bool elimDup, UInt32 writeZone) -{ - CExtractOptions eo; - eo.OutputDir = us2fs(outFolder); - eo.TestMode = false; - eo.ElimDup.Val = elimDup; - eo.ElimDup.Def = elimDup; - if (writeZone != (UInt32)(Int32)-1) - eo.ZoneMode = (NExtract::NZoneIdMode::EEnum)writeZone; - ExtractGroupCommand(arcPaths, showDialog, eo); -} - -void TestArchives(const UStringVector &arcPaths, bool hashMode) -{ - CExtractOptions eo; - eo.TestMode = true; - ExtractGroupCommand(arcPaths, - true, // showDialog - eo, - hashMode ? "hash" : NULL); -} - -void CalcChecksum(const UStringVector &paths, - const UString &methodName, - const UString &arcPathPrefix, - const UString &arcFileName) -{ - MY_TRY_BEGIN - - if (!arcFileName.IsEmpty()) - { - CompressFiles( - arcPathPrefix, - arcFileName, - UString("hash"), - false, // addExtension, - paths, - false, // email, - false, // showDialog, - false // waitFinish - ); - return; - } - - CREATE_CODECS - LOAD_EXTERNAL_CODECS - - NWildcard::CCensor censor; - FOR_VECTOR (i, paths) - { - censor.AddPreItem_NoWildcard(paths[i]); - } - - censor.AddPathsToCensor(NWildcard::k_RelatPath); - bool messageWasDisplayed = false; - - CHashOptions options; - options.Methods.Add(methodName); - - /* - if (!arcFileName.IsEmpty()) - options.HashFilePath = arcPathPrefix + arcFileName; - */ - - result = HashCalcGUI(EXTERNAL_CODECS_VARS_L censor, options, messageWasDisplayed); - if (result != S_OK) - { - if (result != E_ABORT && messageWasDisplayed) - return; // E_FAIL; - throw CSystemException(result); - } - - MY_TRY_FINISH - return; // result; -} - -void Benchmark(bool totalMode) -{ - MY_TRY_BEGIN - - CREATE_CODECS - LOAD_EXTERNAL_CODECS - - CObjectVector props; - if (totalMode) - { - CProperty prop; - prop.Name = "m"; - prop.Value = "*"; - props.Add(prop); - } - result = Benchmark( - EXTERNAL_CODECS_VARS_L - props, - k_NumBenchIterations_Default, - g_HWND); - - MY_TRY_FINISH -} - -#endif +// CompressCall2.cpp + +#include "StdAfx.h" + +#ifndef Z7_EXTERNAL_CODECS + +#include "../../../Common/MyException.h" + +#include "../../UI/Common/EnumDirItems.h" + +#include "../../UI/FileManager/LangUtils.h" + +#include "../../UI/GUI/BenchmarkDialog.h" +#include "../../UI/GUI/ExtractGUI.h" +#include "../../UI/GUI/UpdateGUI.h" +#include "../../UI/GUI/HashGUI.h" + +#include "../../UI/GUI/ExtractRes.h" + +#include "CompressCall.h" + +extern HWND g_HWND; + +#define MY_TRY_BEGIN HRESULT result; try { +#define MY_TRY_FINISH } \ + catch(CSystemException &e) { result = e.ErrorCode; } \ + catch(UString &s) { ErrorMessage(s); result = E_FAIL; } \ + catch(...) { result = E_FAIL; } \ + if (result != S_OK && result != E_ABORT) \ + ErrorMessageHRESULT(result); + +static void ThrowException_if_Error(HRESULT res) +{ + if (res != S_OK) + throw CSystemException(res); +} + +#ifdef Z7_EXTERNAL_CODECS + +#define CREATE_CODECS \ + CCodecs *codecs = new CCodecs; \ + CMyComPtr compressCodecsInfo = codecs; \ + ThrowException_if_Error(codecs->Load()); \ + Codecs_AddHashArcHandler(codecs); + +#define LOAD_EXTERNAL_CODECS \ + CExternalCodecs _externalCodecs; \ + _externalCodecs.GetCodecs = codecs; \ + _externalCodecs.GetHashers = codecs; \ + ThrowException_if_Error(_externalCodecs.Load()); + +#else + +#define CREATE_CODECS \ + CCodecs *codecs = new CCodecs; \ + CMyComPtr compressCodecsInfo = codecs; \ + ThrowException_if_Error(codecs->Load()); \ + Codecs_AddHashArcHandler(codecs); + +#define LOAD_EXTERNAL_CODECS + +#endif + + + + +UString GetQuotedString(const UString &s) +{ + UString s2 ('\"'); + s2 += s; + s2.Add_Char('\"'); + return s2; +} + +static void ErrorMessage(LPCWSTR message) +{ + MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR); +} + +static void ErrorMessageHRESULT(HRESULT res) +{ + ErrorMessage(HResultToMessage(res)); +} + +static void ErrorLangMessage(UINT resourceID) +{ + ErrorMessage(LangString(resourceID)); +} + +HRESULT CompressFiles( + const UString &arcPathPrefix, + const UString &arcName, + const UString &arcType, + bool addExtension, + const UStringVector &names, + bool email, bool showDialog, bool /* waitFinish */) +{ + MY_TRY_BEGIN + + CREATE_CODECS + + CUpdateCallbackGUI callback; + + callback.Init(); + + CUpdateOptions uo; + uo.EMailMode = email; + uo.SetActionCommand_Add(); + + uo.ArcNameMode = (addExtension ? k_ArcNameMode_Add : k_ArcNameMode_Exact); + + CObjectVector formatIndices; + if (!ParseOpenTypes(*codecs, arcType, formatIndices)) + { + ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); + return E_FAIL; + } + const UString arcPath = arcPathPrefix + arcName; + if (!uo.InitFormatIndex(codecs, formatIndices, arcPath) || + !uo.SetArcPath(codecs, arcPath)) + { + ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED); + return E_FAIL; + } + + NWildcard::CCensor censor; + FOR_VECTOR (i, names) + { + censor.AddPreItem_NoWildcard(names[i]); + } + + bool messageWasDisplayed = false; + + result = UpdateGUI(codecs, + formatIndices, arcPath, + censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND); + + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return E_FAIL; + throw CSystemException(result); + } + if (callback.FailedFiles.Size() > 0) + { + if (!messageWasDisplayed) + throw CSystemException(E_FAIL); + return E_FAIL; + } + + MY_TRY_FINISH + return S_OK; +} + + +static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, + bool showDialog, CExtractOptions &eo, const char *kType = NULL) +{ + MY_TRY_BEGIN + + CREATE_CODECS + + CExtractCallbackImp *ecs = new CExtractCallbackImp; + CMyComPtr extractCallback = ecs; + + ecs->Init(); + + // eo.CalcCrc = options.CalcCrc; + + UStringVector arcPathsSorted; + UStringVector arcFullPathsSorted; + { + NWildcard::CCensor arcCensor; + FOR_VECTOR (i, arcPaths) + { + arcCensor.AddPreItem_NoWildcard(arcPaths[i]); + } + arcCensor.AddPathsToCensor(NWildcard::k_RelatPath); + CDirItemsStat st; + EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(), + arcPathsSorted, arcFullPathsSorted, + st, + NULL // &scan: change it!!!! + ); + } + + CObjectVector formatIndices; + if (kType) + { + if (!ParseOpenTypes(*codecs, UString(kType), formatIndices)) + { + throw CSystemException(E_INVALIDARG); + // ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); + // return E_INVALIDARG; + } + } + + NWildcard::CCensor censor; + { + censor.AddPreItem_Wildcard(); + } + + censor.AddPathsToCensor(NWildcard::k_RelatPath); + + bool messageWasDisplayed = false; + + ecs->MultiArcMode = (arcPathsSorted.Size() > 1); + + result = ExtractGUI(codecs, + formatIndices, CIntVector(), + arcPathsSorted, arcFullPathsSorted, + censor.Pairs.Front().Head, eo, NULL, showDialog, messageWasDisplayed, ecs, g_HWND); + + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return E_FAIL; + throw CSystemException(result); + } + return ecs->IsOK() ? S_OK : E_FAIL; + + MY_TRY_FINISH + return result; +} + +void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, + bool showDialog, bool elimDup, UInt32 writeZone) +{ + CExtractOptions eo; + eo.OutputDir = us2fs(outFolder); + eo.TestMode = false; + eo.ElimDup.Val = elimDup; + eo.ElimDup.Def = elimDup; + if (writeZone != (UInt32)(Int32)-1) + eo.ZoneMode = (NExtract::NZoneIdMode::EEnum)writeZone; + ExtractGroupCommand(arcPaths, showDialog, eo); +} + +void TestArchives(const UStringVector &arcPaths, bool hashMode) +{ + CExtractOptions eo; + eo.TestMode = true; + ExtractGroupCommand(arcPaths, + true, // showDialog + eo, + hashMode ? "hash" : NULL); +} + +void CalcChecksum(const UStringVector &paths, + const UString &methodName, + const UString &arcPathPrefix, + const UString &arcFileName) +{ + MY_TRY_BEGIN + + if (!arcFileName.IsEmpty()) + { + CompressFiles( + arcPathPrefix, + arcFileName, + UString("hash"), + false, // addExtension, + paths, + false, // email, + false, // showDialog, + false // waitFinish + ); + return; + } + + CREATE_CODECS + LOAD_EXTERNAL_CODECS + + NWildcard::CCensor censor; + FOR_VECTOR (i, paths) + { + censor.AddPreItem_NoWildcard(paths[i]); + } + + censor.AddPathsToCensor(NWildcard::k_RelatPath); + bool messageWasDisplayed = false; + + CHashOptions options; + options.Methods.Add(methodName); + + /* + if (!arcFileName.IsEmpty()) + options.HashFilePath = arcPathPrefix + arcFileName; + */ + + result = HashCalcGUI(EXTERNAL_CODECS_VARS_L censor, options, messageWasDisplayed); + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return; // E_FAIL; + throw CSystemException(result); + } + + MY_TRY_FINISH + return; // result; +} + +void Benchmark(bool totalMode) +{ + MY_TRY_BEGIN + + CREATE_CODECS + LOAD_EXTERNAL_CODECS + + CObjectVector props; + if (totalMode) + { + CProperty prop; + prop.Name = "m"; + prop.Value = "*"; + props.Add(prop); + } + result = Benchmark( + EXTERNAL_CODECS_VARS_L + props, + k_NumBenchIterations_Default, + g_HWND); + + MY_TRY_FINISH +} + +#endif diff --git a/CPP/7zip/UI/Common/DefaultName.cpp b/CPP/7zip/UI/Common/DefaultName.cpp index 47bf4a65d..8c34ffc73 100644 --- a/CPP/7zip/UI/Common/DefaultName.cpp +++ b/CPP/7zip/UI/Common/DefaultName.cpp @@ -1,37 +1,37 @@ -// DefaultName.cpp - -#include "StdAfx.h" - -#include "DefaultName.h" - -static UString GetDefaultName3(const UString &fileName, - const UString &extension, const UString &addSubExtension) -{ - const unsigned extLen = extension.Len(); - const unsigned fileNameLen = fileName.Len(); - - if (fileNameLen > extLen + 1) - { - const unsigned dotPos = fileNameLen - (extLen + 1); - if (fileName[dotPos] == '.') - if (extension.IsEqualTo_NoCase(fileName.Ptr(dotPos + 1))) - return fileName.Left(dotPos) + addSubExtension; - } - - int dotPos = fileName.ReverseFind_Dot(); - if (dotPos > 0) - return fileName.Left((unsigned)dotPos) + addSubExtension; - - if (addSubExtension.IsEmpty()) - return fileName + L'~'; - else - return fileName + addSubExtension; -} - -UString GetDefaultName2(const UString &fileName, - const UString &extension, const UString &addSubExtension) -{ - UString name = GetDefaultName3(fileName, extension, addSubExtension); - name.TrimRight(); - return name; -} +// DefaultName.cpp + +#include "StdAfx.h" + +#include "DefaultName.h" + +static UString GetDefaultName3(const UString &fileName, + const UString &extension, const UString &addSubExtension) +{ + const unsigned extLen = extension.Len(); + const unsigned fileNameLen = fileName.Len(); + + if (fileNameLen > extLen + 1) + { + const unsigned dotPos = fileNameLen - (extLen + 1); + if (fileName[dotPos] == '.') + if (extension.IsEqualTo_NoCase(fileName.Ptr(dotPos + 1))) + return fileName.Left(dotPos) + addSubExtension; + } + + int dotPos = fileName.ReverseFind_Dot(); + if (dotPos > 0) + return fileName.Left((unsigned)dotPos) + addSubExtension; + + if (addSubExtension.IsEmpty()) + return fileName + L'~'; + else + return fileName + addSubExtension; +} + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension) +{ + UString name = GetDefaultName3(fileName, extension, addSubExtension); + name.TrimRight(); + return name; +} diff --git a/CPP/7zip/UI/Common/DefaultName.h b/CPP/7zip/UI/Common/DefaultName.h index 1398f1e2e..46f6e9e67 100644 --- a/CPP/7zip/UI/Common/DefaultName.h +++ b/CPP/7zip/UI/Common/DefaultName.h @@ -1,11 +1,11 @@ -// DefaultName.h - -#ifndef ZIP7_INC_DEFAULT_NAME_H -#define ZIP7_INC_DEFAULT_NAME_H - -#include "../../../Common/MyString.h" - -UString GetDefaultName2(const UString &fileName, - const UString &extension, const UString &addSubExtension); - -#endif +// DefaultName.h + +#ifndef ZIP7_INC_DEFAULT_NAME_H +#define ZIP7_INC_DEFAULT_NAME_H + +#include "../../../Common/MyString.h" + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension); + +#endif diff --git a/CPP/7zip/UI/Common/DirItem.h b/CPP/7zip/UI/Common/DirItem.h index 5952d7098..3c192495b 100644 --- a/CPP/7zip/UI/Common/DirItem.h +++ b/CPP/7zip/UI/Common/DirItem.h @@ -1,407 +1,407 @@ -// DirItem.h - -#ifndef ZIP7_INC_DIR_ITEM_H -#define ZIP7_INC_DIR_ITEM_H - -#ifdef _WIN32 -#include "../../../Common/MyLinux.h" -#endif - -#include "../../../Common/MyString.h" - -#include "../../../Windows/FileFind.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/UniqBlocks.h" - -#include "../../Archive/IArchive.h" - -struct CDirItemsStat -{ - UInt64 NumDirs; - UInt64 NumFiles; - UInt64 NumAltStreams; - UInt64 FilesSize; - UInt64 AltStreamsSize; - - UInt64 NumErrors; - - // UInt64 Get_NumItems() const { return NumDirs + NumFiles + NumAltStreams; } - UInt64 Get_NumDataItems() const { return NumFiles + NumAltStreams; } - UInt64 GetTotalBytes() const { return FilesSize + AltStreamsSize; } - - bool IsEmpty() const { return - 0 == NumDirs - && 0 == NumFiles - && 0 == NumAltStreams - && 0 == FilesSize - && 0 == AltStreamsSize - && 0 == NumErrors; } - - CDirItemsStat(): - NumDirs(0), - NumFiles(0), - NumAltStreams(0), - FilesSize(0), - AltStreamsSize(0), - NumErrors(0) - {} -}; - - -struct CDirItemsStat2: public CDirItemsStat -{ - UInt64 Anti_NumDirs; - UInt64 Anti_NumFiles; - UInt64 Anti_NumAltStreams; - - // UInt64 Get_NumItems() const { return Anti_NumDirs + Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumItems(); } - UInt64 Get_NumDataItems2() const { return Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumDataItems(); } - - bool IsEmpty() const { return CDirItemsStat::IsEmpty() - && 0 == Anti_NumDirs - && 0 == Anti_NumFiles - && 0 == Anti_NumAltStreams; } - - CDirItemsStat2(): - Anti_NumDirs(0), - Anti_NumFiles(0), - Anti_NumAltStreams(0) - {} -}; - - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACEN_IDirItemsCallback(x) \ - virtual HRESULT ScanError(const FString &path, DWORD systemError) x \ - virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x \ - -Z7_IFACE_DECL_PURE(IDirItemsCallback) - -Z7_PURE_INTERFACES_END - - -struct CArcTime -{ - FILETIME FT; - UInt16 Prec; - Byte Ns100; - bool Def; - - CArcTime() - { - Clear(); - } - - void Clear() - { - FT.dwHighDateTime = FT.dwLowDateTime = 0; - Prec = 0; - Ns100 = 0; - Def = false; - } - - bool IsZero() const - { - return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0; - } - - int CompareWith(const CArcTime &a) const - { - const int res = CompareFileTime(&FT, &a.FT); - if (res != 0) - return res; - if (Ns100 < a.Ns100) return -1; - if (Ns100 > a.Ns100) return 1; - return 0; - } - - UInt64 Get_FILETIME_as_UInt64() const - { - return (((UInt64)FT.dwHighDateTime) << 32) + FT.dwLowDateTime; - } - - UInt32 Get_DosTime() const - { - FILETIME ft2 = FT; - if ((Prec == k_PropVar_TimePrec_Base + 8 || - Prec == k_PropVar_TimePrec_Base + 9) - && Ns100 != 0) - { - UInt64 u64 = Get_FILETIME_as_UInt64(); - // we round up even small (ns < 100ns) as FileTimeToDosTime() - if (u64 % 20000000 == 0) - { - u64++; - ft2.dwHighDateTime = (DWORD)(u64 >> 32); - ft2.dwHighDateTime = (DWORD)u64; - } - } - // FileTimeToDosTime() is expected to round up in Windows - UInt32 dosTime; - // we use simplified code with utctime->dos. - // do we need local time instead here? - NWindows::NTime::FileTime_To_DosTime(ft2, dosTime); - return dosTime; - } - - int GetNumDigits() const - { - if (Prec == k_PropVar_TimePrec_Unix || - Prec == k_PropVar_TimePrec_DOS) - return 0; - if (Prec == k_PropVar_TimePrec_HighPrec) - return 9; - if (Prec == k_PropVar_TimePrec_0) - return 7; - int digits = (int)Prec - (int)k_PropVar_TimePrec_Base; - if (digits < 0) - digits = 0; - return digits; - } - - void Write_To_FiTime(CFiTime &dest) const - { - #ifdef _WIN32 - dest = FT; - #else - if (FILETIME_To_timespec(FT, dest)) - if ((Prec == k_PropVar_TimePrec_Base + 8 || - Prec == k_PropVar_TimePrec_Base + 9) - && Ns100 != 0) - { - dest.tv_nsec += Ns100; - } - #endif - } - - // (Def) is not set - void Set_From_FILETIME(const FILETIME &ft) - { - FT = ft; - // Prec = k_PropVar_TimePrec_CompatNTFS; - Prec = k_PropVar_TimePrec_Base + 7; - Ns100 = 0; - } - - // (Def) is not set - // it set full form precision: k_PropVar_TimePrec_Base + numDigits - void Set_From_FiTime(const CFiTime &ts) - { - #ifdef _WIN32 - FT = ts; - Prec = k_PropVar_TimePrec_Base + 7; - // Prec = k_PropVar_TimePrec_Base; // for debug - // Prec = 0; // for debug - Ns100 = 0; - #else - unsigned ns100; - FiTime_To_FILETIME_ns100(ts, FT, ns100); - Ns100 = (Byte)ns100; - Prec = k_PropVar_TimePrec_Base + 9; - #endif - } - - void Set_From_Prop(const PROPVARIANT &prop) - { - FT = prop.filetime; - unsigned prec = 0; - unsigned ns100 = 0; - const unsigned prec_Temp = prop.wReserved1; - if (prec_Temp != 0 - && prec_Temp <= k_PropVar_TimePrec_1ns - && prop.wReserved3 == 0) - { - const unsigned ns100_Temp = prop.wReserved2; - if (ns100_Temp < 100) - { - ns100 = ns100_Temp; - prec = prec_Temp; - } - } - Prec = (UInt16)prec; - Ns100 = (Byte)ns100; - Def = true; - } -}; - - -struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase -{ - UString Name; - - #ifndef UNDER_CE - CByteBuffer ReparseData; - - #ifdef _WIN32 - // UString ShortName; - CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format - bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } - #else - bool AreReparseData() const { return ReparseData.Size() != 0; } - #endif // _WIN32 - - #endif // !UNDER_CE - - void Copy_From_FileInfoBase(const NWindows::NFile::NFind::CFileInfoBase &fi) - { - (NWindows::NFile::NFind::CFileInfoBase &)*this = fi; - } - - int PhyParent; - int LogParent; - int SecureIndex; - - #ifdef _WIN32 - #else - int OwnerNameIndex; - int OwnerGroupIndex; - #endif - - // bool Attrib_IsDefined; - - CDirItem(): - PhyParent(-1) - , LogParent(-1) - , SecureIndex(-1) - #ifdef _WIN32 - #else - , OwnerNameIndex(-1) - , OwnerGroupIndex(-1) - #endif - // , Attrib_IsDefined(true) - { - } - - - CDirItem(const NWindows::NFile::NFind::CFileInfo &fi, - int phyParent, int logParent, int secureIndex): - CFileInfoBase(fi) - , Name(fs2us(fi.Name)) - #if defined(_WIN32) && !defined(UNDER_CE) - // , ShortName(fs2us(fi.ShortName)) - #endif - , PhyParent(phyParent) - , LogParent(logParent) - , SecureIndex(secureIndex) - #ifdef _WIN32 - #else - , OwnerNameIndex(-1) - , OwnerGroupIndex(-1) - #endif - {} -}; - - - -class CDirItems -{ - UStringVector Prefixes; - CIntVector PhyParents; - CIntVector LogParents; - - UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const; - - HRESULT EnumerateDir(int phyParent, int logParent, const FString &phyPrefix); - -public: - CObjectVector Items; - - bool SymLinks; - bool ScanAltStreams; - bool ExcludeDirItems; - bool ExcludeFileItems; - bool ShareForWrite; - - /* it must be called after anotrher checks */ - bool CanIncludeItem(bool isDir) const - { - return isDir ? !ExcludeDirItems : !ExcludeFileItems; - } - - - CDirItemsStat Stat; - - #if !defined(UNDER_CE) - HRESULT SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi, - const FString &phyPrefix); - #endif - - #if defined(_WIN32) && !defined(UNDER_CE) - - CUniqBlocks SecureBlocks; - CByteBuffer TempSecureBuf; - bool _saclEnabled; - bool ReadSecure; - - HRESULT AddSecurityItem(const FString &path, int &secureIndex); - HRESULT FillFixedReparse(); - - #endif - - #ifndef _WIN32 - - C_UInt32_UString_Map OwnerNameMap; - C_UInt32_UString_Map OwnerGroupMap; - bool StoreOwnerName; - - HRESULT FillDeviceSizes(); - - #endif - - IDirItemsCallback *Callback; - - CDirItems(); - - void AddDirFileInfo(int phyParent, int logParent, int secureIndex, - const NWindows::NFile::NFind::CFileInfo &fi); - - HRESULT AddError(const FString &path, DWORD errorCode); - HRESULT AddError(const FString &path); - - HRESULT ScanProgress(const FString &path); - - // unsigned GetNumFolders() const { return Prefixes.Size(); } - FString GetPhyPath(unsigned index) const; - UString GetLogPath(unsigned index) const; - - unsigned AddPrefix(int phyParent, int logParent, const UString &prefix); - void DeleteLastPrefix(); - - // HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector &files); - HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector &files); - - HRESULT EnumerateItems2( - const FString &phyPrefix, - const UString &logPrefix, - const FStringVector &filePaths, - FStringVector *requestedPaths); - - void ReserveDown(); -}; - - - - -struct CArcItem -{ - UInt64 Size; - UString Name; - CArcTime MTime; // it can be mtime of archive file, if MTime is not defined for item in archive - bool IsDir; - bool IsAltStream; - bool Size_Defined; - bool Censored; - UInt32 IndexInServer; - - CArcItem(): - IsDir(false), - IsAltStream(false), - Size_Defined(false), - Censored(false) - {} -}; - -#endif +// DirItem.h + +#ifndef ZIP7_INC_DIR_ITEM_H +#define ZIP7_INC_DIR_ITEM_H + +#ifdef _WIN32 +#include "../../../Common/MyLinux.h" +#endif + +#include "../../../Common/MyString.h" + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/UniqBlocks.h" + +#include "../../Archive/IArchive.h" + +struct CDirItemsStat +{ + UInt64 NumDirs; + UInt64 NumFiles; + UInt64 NumAltStreams; + UInt64 FilesSize; + UInt64 AltStreamsSize; + + UInt64 NumErrors; + + // UInt64 Get_NumItems() const { return NumDirs + NumFiles + NumAltStreams; } + UInt64 Get_NumDataItems() const { return NumFiles + NumAltStreams; } + UInt64 GetTotalBytes() const { return FilesSize + AltStreamsSize; } + + bool IsEmpty() const { return + 0 == NumDirs + && 0 == NumFiles + && 0 == NumAltStreams + && 0 == FilesSize + && 0 == AltStreamsSize + && 0 == NumErrors; } + + CDirItemsStat(): + NumDirs(0), + NumFiles(0), + NumAltStreams(0), + FilesSize(0), + AltStreamsSize(0), + NumErrors(0) + {} +}; + + +struct CDirItemsStat2: public CDirItemsStat +{ + UInt64 Anti_NumDirs; + UInt64 Anti_NumFiles; + UInt64 Anti_NumAltStreams; + + // UInt64 Get_NumItems() const { return Anti_NumDirs + Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumItems(); } + UInt64 Get_NumDataItems2() const { return Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumDataItems(); } + + bool IsEmpty() const { return CDirItemsStat::IsEmpty() + && 0 == Anti_NumDirs + && 0 == Anti_NumFiles + && 0 == Anti_NumAltStreams; } + + CDirItemsStat2(): + Anti_NumDirs(0), + Anti_NumFiles(0), + Anti_NumAltStreams(0) + {} +}; + + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACEN_IDirItemsCallback(x) \ + virtual HRESULT ScanError(const FString &path, DWORD systemError) x \ + virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x \ + +Z7_IFACE_DECL_PURE(IDirItemsCallback) + +Z7_PURE_INTERFACES_END + + +struct CArcTime +{ + FILETIME FT; + UInt16 Prec; + Byte Ns100; + bool Def; + + CArcTime() + { + Clear(); + } + + void Clear() + { + FT.dwHighDateTime = FT.dwLowDateTime = 0; + Prec = 0; + Ns100 = 0; + Def = false; + } + + bool IsZero() const + { + return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0; + } + + int CompareWith(const CArcTime &a) const + { + const int res = CompareFileTime(&FT, &a.FT); + if (res != 0) + return res; + if (Ns100 < a.Ns100) return -1; + if (Ns100 > a.Ns100) return 1; + return 0; + } + + UInt64 Get_FILETIME_as_UInt64() const + { + return (((UInt64)FT.dwHighDateTime) << 32) + FT.dwLowDateTime; + } + + UInt32 Get_DosTime() const + { + FILETIME ft2 = FT; + if ((Prec == k_PropVar_TimePrec_Base + 8 || + Prec == k_PropVar_TimePrec_Base + 9) + && Ns100 != 0) + { + UInt64 u64 = Get_FILETIME_as_UInt64(); + // we round up even small (ns < 100ns) as FileTimeToDosTime() + if (u64 % 20000000 == 0) + { + u64++; + ft2.dwHighDateTime = (DWORD)(u64 >> 32); + ft2.dwHighDateTime = (DWORD)u64; + } + } + // FileTimeToDosTime() is expected to round up in Windows + UInt32 dosTime; + // we use simplified code with utctime->dos. + // do we need local time instead here? + NWindows::NTime::FileTime_To_DosTime(ft2, dosTime); + return dosTime; + } + + int GetNumDigits() const + { + if (Prec == k_PropVar_TimePrec_Unix || + Prec == k_PropVar_TimePrec_DOS) + return 0; + if (Prec == k_PropVar_TimePrec_HighPrec) + return 9; + if (Prec == k_PropVar_TimePrec_0) + return 7; + int digits = (int)Prec - (int)k_PropVar_TimePrec_Base; + if (digits < 0) + digits = 0; + return digits; + } + + void Write_To_FiTime(CFiTime &dest) const + { + #ifdef _WIN32 + dest = FT; + #else + if (FILETIME_To_timespec(FT, dest)) + if ((Prec == k_PropVar_TimePrec_Base + 8 || + Prec == k_PropVar_TimePrec_Base + 9) + && Ns100 != 0) + { + dest.tv_nsec += Ns100; + } + #endif + } + + // (Def) is not set + void Set_From_FILETIME(const FILETIME &ft) + { + FT = ft; + // Prec = k_PropVar_TimePrec_CompatNTFS; + Prec = k_PropVar_TimePrec_Base + 7; + Ns100 = 0; + } + + // (Def) is not set + // it set full form precision: k_PropVar_TimePrec_Base + numDigits + void Set_From_FiTime(const CFiTime &ts) + { + #ifdef _WIN32 + FT = ts; + Prec = k_PropVar_TimePrec_Base + 7; + // Prec = k_PropVar_TimePrec_Base; // for debug + // Prec = 0; // for debug + Ns100 = 0; + #else + unsigned ns100; + FiTime_To_FILETIME_ns100(ts, FT, ns100); + Ns100 = (Byte)ns100; + Prec = k_PropVar_TimePrec_Base + 9; + #endif + } + + void Set_From_Prop(const PROPVARIANT &prop) + { + FT = prop.filetime; + unsigned prec = 0; + unsigned ns100 = 0; + const unsigned prec_Temp = prop.wReserved1; + if (prec_Temp != 0 + && prec_Temp <= k_PropVar_TimePrec_1ns + && prop.wReserved3 == 0) + { + const unsigned ns100_Temp = prop.wReserved2; + if (ns100_Temp < 100) + { + ns100 = ns100_Temp; + prec = prec_Temp; + } + } + Prec = (UInt16)prec; + Ns100 = (Byte)ns100; + Def = true; + } +}; + + +struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase +{ + UString Name; + + #ifndef UNDER_CE + CByteBuffer ReparseData; + + #ifdef _WIN32 + // UString ShortName; + CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format + bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } + #else + bool AreReparseData() const { return ReparseData.Size() != 0; } + #endif // _WIN32 + + #endif // !UNDER_CE + + void Copy_From_FileInfoBase(const NWindows::NFile::NFind::CFileInfoBase &fi) + { + (NWindows::NFile::NFind::CFileInfoBase &)*this = fi; + } + + int PhyParent; + int LogParent; + int SecureIndex; + + #ifdef _WIN32 + #else + int OwnerNameIndex; + int OwnerGroupIndex; + #endif + + // bool Attrib_IsDefined; + + CDirItem(): + PhyParent(-1) + , LogParent(-1) + , SecureIndex(-1) + #ifdef _WIN32 + #else + , OwnerNameIndex(-1) + , OwnerGroupIndex(-1) + #endif + // , Attrib_IsDefined(true) + { + } + + + CDirItem(const NWindows::NFile::NFind::CFileInfo &fi, + int phyParent, int logParent, int secureIndex): + CFileInfoBase(fi) + , Name(fs2us(fi.Name)) + #if defined(_WIN32) && !defined(UNDER_CE) + // , ShortName(fs2us(fi.ShortName)) + #endif + , PhyParent(phyParent) + , LogParent(logParent) + , SecureIndex(secureIndex) + #ifdef _WIN32 + #else + , OwnerNameIndex(-1) + , OwnerGroupIndex(-1) + #endif + {} +}; + + + +class CDirItems +{ + UStringVector Prefixes; + CIntVector PhyParents; + CIntVector LogParents; + + UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const; + + HRESULT EnumerateDir(int phyParent, int logParent, const FString &phyPrefix); + +public: + CObjectVector Items; + + bool SymLinks; + bool ScanAltStreams; + bool ExcludeDirItems; + bool ExcludeFileItems; + bool ShareForWrite; + + /* it must be called after anotrher checks */ + bool CanIncludeItem(bool isDir) const + { + return isDir ? !ExcludeDirItems : !ExcludeFileItems; + } + + + CDirItemsStat Stat; + + #if !defined(UNDER_CE) + HRESULT SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi, + const FString &phyPrefix); + #endif + + #if defined(_WIN32) && !defined(UNDER_CE) + + CUniqBlocks SecureBlocks; + CByteBuffer TempSecureBuf; + bool _saclEnabled; + bool ReadSecure; + + HRESULT AddSecurityItem(const FString &path, int &secureIndex); + HRESULT FillFixedReparse(); + + #endif + + #ifndef _WIN32 + + C_UInt32_UString_Map OwnerNameMap; + C_UInt32_UString_Map OwnerGroupMap; + bool StoreOwnerName; + + HRESULT FillDeviceSizes(); + + #endif + + IDirItemsCallback *Callback; + + CDirItems(); + + void AddDirFileInfo(int phyParent, int logParent, int secureIndex, + const NWindows::NFile::NFind::CFileInfo &fi); + + HRESULT AddError(const FString &path, DWORD errorCode); + HRESULT AddError(const FString &path); + + HRESULT ScanProgress(const FString &path); + + // unsigned GetNumFolders() const { return Prefixes.Size(); } + FString GetPhyPath(unsigned index) const; + UString GetLogPath(unsigned index) const; + + unsigned AddPrefix(int phyParent, int logParent, const UString &prefix); + void DeleteLastPrefix(); + + // HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector &files); + HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector &files); + + HRESULT EnumerateItems2( + const FString &phyPrefix, + const UString &logPrefix, + const FStringVector &filePaths, + FStringVector *requestedPaths); + + void ReserveDown(); +}; + + + + +struct CArcItem +{ + UInt64 Size; + UString Name; + CArcTime MTime; // it can be mtime of archive file, if MTime is not defined for item in archive + bool IsDir; + bool IsAltStream; + bool Size_Defined; + bool Censored; + UInt32 IndexInServer; + + CArcItem(): + IsDir(false), + IsAltStream(false), + Size_Defined(false), + Censored(false) + {} +}; + +#endif diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index 6932ace01..11643ae5a 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -1,1654 +1,1654 @@ -// EnumDirItems.cpp - -#include "StdAfx.h" - -#include -// #include - -#ifndef _WIN32 -#include -#include -#include "../../../Common/UTFConvert.h" -#endif - -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" - -#if defined(_WIN32) && !defined(UNDER_CE) -#define Z7_USE_SECURITY_CODE -#include "../../../Windows/SecurityUtils.h" -#endif - -#include "EnumDirItems.h" -#include "SortUtils.h" - -using namespace NWindows; -using namespace NFile; -using namespace NName; - - -static bool FindFile_KeepDots(NFile::NFind::CFileInfo &fi, const FString &path, bool followLink) -{ - const bool res = fi.Find(path, followLink); - if (!res) - return res; - if (path.IsEmpty()) - return res; - // we keep name "." and "..", if it's without tail slash - const FChar *p = path.RightPtr(1); - if (*p != '.') - return res; - if (p != path.Ptr()) - { - FChar c = p[-1]; - if (!IS_PATH_SEPAR(c)) - { - if (c != '.') - return res; - p--; - if (p != path.Ptr()) - { - c = p[-1]; - if (!IS_PATH_SEPAR(c)) - return res; - } - } - } - fi.Name = p; - return res; -} - - -void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex, - const NFind::CFileInfo &fi) -{ - /* - CDirItem di(fi); - di.PhyParent = phyParent; - di.LogParent = logParent; - di.SecureIndex = secureIndex; - Items.Add(di); - */ - VECTOR_ADD_NEW_OBJECT (Items, CDirItem(fi, phyParent, logParent, secureIndex)) - - if (fi.IsDir()) - Stat.NumDirs++; - #ifdef _WIN32 - else if (fi.IsAltStream) - { - Stat.NumAltStreams++; - Stat.AltStreamsSize += fi.Size; - } - #endif - else - { - Stat.NumFiles++; - Stat.FilesSize += fi.Size; - } -} - -// (DWORD)E_FAIL -#define DI_DEFAULT_ERROR ERROR_INVALID_FUNCTION - -HRESULT CDirItems::AddError(const FString &path, DWORD errorCode) -{ - if (errorCode == 0) - errorCode = DI_DEFAULT_ERROR; - Stat.NumErrors++; - if (Callback) - return Callback->ScanError(path, errorCode); - return S_OK; -} - -HRESULT CDirItems::AddError(const FString &path) -{ - return AddError(path, ::GetLastError()); -} - -static const unsigned kScanProgressStepMask = (1 << 12) - 1; - -HRESULT CDirItems::ScanProgress(const FString &dirPath) -{ - if (Callback) - return Callback->ScanProgress(Stat, dirPath, true); - return S_OK; -} - -UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const -{ - UString path; - unsigned len = name.Len(); - - int i; - for (i = index; i >= 0; i = parents[(unsigned)i]) - len += Prefixes[(unsigned)i].Len(); - - wchar_t *p = path.GetBuf_SetEnd(len) + len; - - p -= name.Len(); - wmemcpy(p, (const wchar_t *)name, name.Len()); - - for (i = index; i >= 0; i = parents[(unsigned)i]) - { - const UString &s = Prefixes[(unsigned)i]; - p -= s.Len(); - wmemcpy(p, (const wchar_t *)s, s.Len()); - } - - return path; -} - -FString CDirItems::GetPhyPath(unsigned index) const -{ - const CDirItem &di = Items[index]; - return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name)); -} - -UString CDirItems::GetLogPath(unsigned index) const -{ - const CDirItem &di = Items[index]; - return GetPrefixesPath(LogParents, di.LogParent, di.Name); -} - -void CDirItems::ReserveDown() -{ - Prefixes.ReserveDown(); - PhyParents.ReserveDown(); - LogParents.ReserveDown(); - Items.ReserveDown(); -} - -unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) -{ - PhyParents.Add(phyParent); - LogParents.Add(logParent); - return Prefixes.Add(prefix); -} - -void CDirItems::DeleteLastPrefix() -{ - PhyParents.DeleteBack(); - LogParents.DeleteBack(); - Prefixes.DeleteBack(); -} - -bool InitLocalPrivileges(); - -CDirItems::CDirItems(): - SymLinks(false), - ScanAltStreams(false) - , ExcludeDirItems(false) - , ExcludeFileItems(false) - , ShareForWrite(false) - #ifdef Z7_USE_SECURITY_CODE - , ReadSecure(false) - #endif - #ifndef _WIN32 - , StoreOwnerName(false) - #endif - , Callback(NULL) -{ - #ifdef Z7_USE_SECURITY_CODE - _saclEnabled = InitLocalPrivileges(); - #endif -} - - -#ifdef Z7_USE_SECURITY_CODE - -HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex) -{ - secureIndex = -1; - - SECURITY_INFORMATION securInfo = - DACL_SECURITY_INFORMATION | - GROUP_SECURITY_INFORMATION | - OWNER_SECURITY_INFORMATION; - if (_saclEnabled) - securInfo |= SACL_SECURITY_INFORMATION; - - DWORD errorCode = 0; - DWORD secureSize; - - BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); - - if (res) - { - if (secureSize == 0) - return S_OK; - if (secureSize > TempSecureBuf.Size()) - errorCode = ERROR_INVALID_FUNCTION; - } - else - { - errorCode = GetLastError(); - if (errorCode == ERROR_INSUFFICIENT_BUFFER) - { - if (secureSize <= TempSecureBuf.Size()) - errorCode = ERROR_INVALID_FUNCTION; - else - { - TempSecureBuf.Alloc(secureSize); - res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); - if (res) - { - if (secureSize != TempSecureBuf.Size()) - errorCode = ERROR_INVALID_FUNCTION; - } - else - errorCode = GetLastError(); - } - } - } - - if (res) - { - secureIndex = (int)SecureBlocks.AddUniq(TempSecureBuf, secureSize); - return S_OK; - } - - return AddError(path, errorCode); -} - -#endif // Z7_USE_SECURITY_CODE - - -HRESULT CDirItems::EnumerateOneDir(const FString &phyPrefix, CObjectVector &files) -{ - NFind::CEnumerator enumerator; - // printf("\n enumerator.SetDirPrefix(phyPrefix) \n"); - - enumerator.SetDirPrefix(phyPrefix); - - #ifdef _WIN32 - - NFind::CFileInfo fi; - - for (unsigned ttt = 0; ; ttt++) - { - bool found; - if (!enumerator.Next(fi, found)) - return AddError(phyPrefix); - if (!found) - return S_OK; - files.Add(fi); - if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask) - { - RINOK(ScanProgress(phyPrefix)) - } - } - - #else // _WIN32 - - // enumerator.SolveLinks = !SymLinks; - - CObjectVector entries; - - for (;;) - { - bool found; - NFind::CDirEntry de; - if (!enumerator.Next(de, found)) - return AddError(phyPrefix); - if (!found) - break; - entries.Add(de); - } - - FOR_VECTOR(i, entries) - { - const NFind::CDirEntry &de = entries[i]; - NFind::CFileInfo fi; - if (!enumerator.Fill_FileInfo(de, fi, !SymLinks)) - // if (!fi.Find_AfterEnumerator(path)) - { - const FString path = phyPrefix + de.Name; - { - RINOK(AddError(path)) - continue; - } - } - - files.Add(fi); - - if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) - { - RINOK(ScanProgress(phyPrefix)) - } - } - - return S_OK; - - #endif // _WIN32 -} - - - - -HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix) -{ - RINOK(ScanProgress(phyPrefix)) - - CObjectVector files; - RINOK(EnumerateOneDir(phyPrefix, files)) - - FOR_VECTOR (i, files) - { - #ifdef _WIN32 - const NFind::CFileInfo &fi = files[i]; - #else - const NFind::CFileInfo &fi = files[i]; - /* - NFind::CFileInfo fi; - { - const NFind::CDirEntry &di = files[i]; - const FString path = phyPrefix + di.Name; - if (!fi.Find_AfterEnumerator(path)) - { - RINOK(AddError(path)); - continue; - } - fi.Name = di.Name; - } - */ - #endif - - if (CanIncludeItem(fi.IsDir())) - { - int secureIndex = -1; - #ifdef Z7_USE_SECURITY_CODE - if (ReadSecure) - { - RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex)) - } - #endif - AddDirFileInfo(phyParent, logParent, secureIndex, fi); - } - - if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) - { - RINOK(ScanProgress(phyPrefix)) - } - - if (fi.IsDir()) - { - const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; - unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2)); - RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + name2)) - } - } - return S_OK; -} - - -/* -EnumerateItems2() - const FStringVector &filePaths - are path without tail slashes. - All dir prefixes of filePaths will be not stores in logical paths -fix it: we can scan AltStream also. -*/ - -#ifdef _WIN32 -// #define FOLLOW_LINK_PARAM -// #define FOLLOW_LINK_PARAM2 -#define FOLLOW_LINK_PARAM , (!SymLinks) -#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks) -#else -#define FOLLOW_LINK_PARAM , (!SymLinks) -#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks) -#endif - -HRESULT CDirItems::EnumerateItems2( - const FString &phyPrefix, - const UString &logPrefix, - const FStringVector &filePaths, - FStringVector *requestedPaths) -{ - const int phyParent = phyPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, fs2us(phyPrefix)); - const int logParent = logPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, logPrefix); - - #ifdef _WIN32 - const bool phyPrefix_isAltStreamPrefix = - NFile::NName::IsAltStreamPrefixWithColon(fs2us(phyPrefix)); - #endif - - FOR_VECTOR (i, filePaths) - { - const FString &filePath = filePaths[i]; - NFind::CFileInfo fi; - const FString phyPath = phyPrefix + filePath; - if (!FindFile_KeepDots(fi, phyPath FOLLOW_LINK_PARAM)) - { - RINOK(AddError(phyPath)) - continue; - } - if (requestedPaths) - requestedPaths->Add(phyPath); - - const int delimiter = filePath.ReverseFind_PathSepar(); - FString phyPrefixCur; - int phyParentCur = phyParent; - if (delimiter >= 0) - { - phyPrefixCur.SetFrom(filePath, (unsigned)(delimiter + 1)); - phyParentCur = (int)AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); - } - - if (CanIncludeItem(fi.IsDir())) - { - int secureIndex = -1; - #ifdef Z7_USE_SECURITY_CODE - if (ReadSecure) - { - RINOK(AddSecurityItem(phyPath, secureIndex)) - } - #endif - #ifdef _WIN32 - if (phyPrefix_isAltStreamPrefix && fi.IsAltStream) - { - const int pos = fi.Name.Find(FChar(':')); - if (pos >= 0) - fi.Name.DeleteFrontal((unsigned)pos + 1); - } - #endif - AddDirFileInfo(phyParentCur, logParent, secureIndex, fi); - } - - if (fi.IsDir()) - { - const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; - const unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2)); - RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + phyPrefixCur + name2)) - } - } - - ReserveDown(); - return S_OK; -} - - - - -static HRESULT EnumerateDirItems( - const NWildcard::CCensorNode &curNode, - const int phyParent, const int logParent, - const FString &phyPrefix, - const UStringVector &addParts, // additional parts from curNode - CDirItems &dirItems, - bool enterToSubFolders); - - -/* EnumerateDirItems_Spec() - adds new Dir item prefix, and enumerates dir items, - then it can remove that Dir item prefix, if there are no items in that dir. -*/ - - -/* - EnumerateDirItems_Spec() - it's similar to EnumerateDirItems, but phyPrefix doesn't include (curFolderName) -*/ - -static HRESULT EnumerateDirItems_Spec( - const NWildcard::CCensorNode &curNode, - const int phyParent, const int logParent, const FString &curFolderName, - const FString &phyPrefix, // without (curFolderName) - const UStringVector &addParts, // (curNode + addParts) includes (curFolderName) - CDirItems &dirItems, - bool enterToSubFolders) -{ - const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR; - const unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2)); - const unsigned numItems = dirItems.Items.Size(); - HRESULT res = EnumerateDirItems( - curNode, (int)parent, (int)parent, phyPrefix + name2, - addParts, dirItems, enterToSubFolders); - if (numItems == dirItems.Items.Size()) - dirItems.DeleteLastPrefix(); - return res; -} - - -#ifndef UNDER_CE - -#ifdef _WIN32 - -static HRESULT EnumerateAltStreams( - const NFind::CFileInfo &fi, - const NWildcard::CCensorNode &curNode, - const int phyParent, const int logParent, - const FString &phyPath, // with (fi.Name), without tail slash for folders - const UStringVector &addParts, // with (fi.Name), prefix parts from curNode - bool addAllSubStreams, - CDirItems &dirItems) -{ - // we don't use (ExcludeFileItems) rules for AltStreams - // if (dirItems.ExcludeFileItems) return S_OK; - - NFind::CStreamEnumerator enumerator(phyPath); - for (;;) - { - NFind::CStreamInfo si; - bool found; - if (!enumerator.Next(si, found)) - { - return dirItems.AddError(phyPath + FTEXT(":*")); // , (DWORD)E_FAIL - } - if (!found) - return S_OK; - if (si.IsMainStream()) - continue; - UStringVector parts = addParts; - const UString reducedName = si.GetReducedName(); - parts.Back() += reducedName; - if (curNode.CheckPathToRoot(false, parts, true)) - continue; - if (!addAllSubStreams) - if (!curNode.CheckPathToRoot(true, parts, true)) - continue; - - NFind::CFileInfo fi2 = fi; - fi2.Name += us2fs(reducedName); - fi2.Size = si.Size; - fi2.Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); - fi2.IsAltStream = true; - dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2); - } -} - -#endif // _WIN32 - - -/* We get Reparse data and parse it. - If there is Reparse error, we free dirItem.Reparse data. - Do we need to work with empty reparse data? -*/ - -HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi, - const FString &phyPrefix) -{ - if (!SymLinks) - return S_OK; - - #ifdef _WIN32 - if (!fi.HasReparsePoint() || fi.IsAltStream) - #else // _WIN32 - if (!fi.IsPosixLink()) - #endif // _WIN32 - return S_OK; - - const FString path = phyPrefix + fi.Name; - CByteBuffer &buf = dirItem.ReparseData; - if (NIO::GetReparseData(path, buf)) - { - // if (dirItem.ReparseData.Size() != 0) - Stat.FilesSize -= fi.Size; - return S_OK; - } - - DWORD res = ::GetLastError(); - buf.Free(); - return AddError(path, res); -} - -#endif // UNDER_CE - - - -static HRESULT EnumerateForItem( - const NFind::CFileInfo &fi, - const NWildcard::CCensorNode &curNode, - const int phyParent, const int logParent, const FString &phyPrefix, - const UStringVector &addParts, // additional parts from curNode, without (fi.Name) - CDirItems &dirItems, - bool enterToSubFolders) -{ - const UString name = fs2us(fi.Name); - UStringVector newParts = addParts; - newParts.Add(name); - - // check the path in exclude rules - if (curNode.CheckPathToRoot(false, newParts, !fi.IsDir())) - return S_OK; - - #if !defined(UNDER_CE) - int dirItemIndex = -1; - #if defined(_WIN32) - bool addAllSubStreams = false; - bool needAltStreams = true; - #endif // _WIN32 - #endif // !defined(UNDER_CE) - - // check the path in inlcude rules - if (curNode.CheckPathToRoot(true, newParts, !fi.IsDir())) - { - #if !defined(UNDER_CE) - // dirItemIndex = (int)dirItems.Items.Size(); - #if defined(_WIN32) - // we will not check include rules for substreams. - addAllSubStreams = true; - #endif // _WIN32 - #endif // !defined(UNDER_CE) - - if (dirItems.CanIncludeItem(fi.IsDir())) - { - int secureIndex = -1; - #ifdef Z7_USE_SECURITY_CODE - if (dirItems.ReadSecure) - { - RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex)) - } - #endif - #if !defined(UNDER_CE) - dirItemIndex = (int)dirItems.Items.Size(); - #endif // !defined(UNDER_CE) - dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); - } - else - { - #if defined(_WIN32) && !defined(UNDER_CE) - needAltStreams = false; - #endif - } - - if (fi.IsDir()) - enterToSubFolders = true; - } - - #if !defined(UNDER_CE) - - // we don't scan AltStreams for link files - - if (dirItemIndex >= 0) - { - CDirItem &dirItem = dirItems.Items[(unsigned)dirItemIndex]; - RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix)) - if (dirItem.ReparseData.Size() != 0) - return S_OK; - } - - #if defined(_WIN32) - if (needAltStreams && dirItems.ScanAltStreams) - { - RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, - phyPrefix + fi.Name, // with (fi.Name) - newParts, // with (fi.Name) - addAllSubStreams, - dirItems)) - } - #endif - - #endif // !defined(UNDER_CE) - - - #ifndef _WIN32 - if (!fi.IsPosixLink()) // posix link can follow to dir - #endif - if (!fi.IsDir()) - return S_OK; - - const NWildcard::CCensorNode *nextNode = NULL; - - if (addParts.IsEmpty()) - { - int index = curNode.FindSubNode(name); - if (index >= 0) - { - nextNode = &curNode.SubNodes[(unsigned)index]; - newParts.Clear(); - } - } - - if (!nextNode) - { - if (!enterToSubFolders) - return S_OK; - - #ifndef _WIN32 - if (fi.IsPosixLink()) - { - // here we can try to resolve posix link - // if the link to dir, then can we follow it - return S_OK; // we don't follow posix link - } - #else - if (dirItems.SymLinks && fi.HasReparsePoint()) - { - /* 20.03: in SymLinks mode: we don't enter to directory that - has reparse point and has no CCensorNode - NOTE: (curNode and parent nodes) still can have wildcard rules - to include some items of target directory (of reparse point), - but we ignore these rules here. - */ - return S_OK; - } - #endif - nextNode = &curNode; - } - - return EnumerateDirItems_Spec( - *nextNode, phyParent, logParent, fi.Name, - phyPrefix, // without (fi.Name) - newParts, // relative to (*nextNode). (*nextNode + newParts) includes (fi.Name) - dirItems, - enterToSubFolders); -} - - -static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode) -{ - FOR_VECTOR (i, curNode.IncludeItems) - { - const NWildcard::CItem &item = curNode.IncludeItems[i]; - if (item.Recursive || item.PathParts.Size() != 1) - return false; - const UString &name = item.PathParts.Front(); - /* - if (name.IsEmpty()) - return false; - */ - - /* Windows doesn't support file name with wildcard - But if another system supports file name with wildcard, - and wildcard mode is disabled, we can ignore wildcard in name - */ - /* - #ifndef _WIN32 - if (!item.WildcardParsing) - continue; - #endif - */ - if (DoesNameContainWildcard(name)) - return false; - } - return true; -} - - -#if defined(_WIN32) && !defined(UNDER_CE) - -static bool IsVirtualFsFolder(const FString &prefix, const UString &name) -{ - UString s = fs2us(prefix); - s += name; - s.Add_PathSepar(); - // it returns (true) for non real FS folder path like - "\\SERVER\" - return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0; -} - -#endif - - - -static HRESULT EnumerateDirItems( - const NWildcard::CCensorNode &curNode, - const int phyParent, const int logParent, const FString &phyPrefix, - const UStringVector &addParts, // prefix from curNode including - CDirItems &dirItems, - bool enterToSubFolders) -{ - if (!enterToSubFolders) - { - /* if there are IncludeItems censor rules that affect items in subdirs, - then we will enter to all subfolders */ - if (curNode.NeedCheckSubDirs()) - enterToSubFolders = true; - } - - RINOK(dirItems.ScanProgress(phyPrefix)) - - // try direct_names case at first - if (addParts.IsEmpty() && !enterToSubFolders) - { - if (CanUseFsDirect(curNode)) - { - // all names are direct (no wildcards) - // so we don't need file_system's dir enumerator - CRecordVector needEnterVector; - unsigned i; - - for (i = 0; i < curNode.IncludeItems.Size(); i++) - { - const NWildcard::CItem &item = curNode.IncludeItems[i]; - const UString &name = item.PathParts.Front(); - FString fullPath = phyPrefix + us2fs(name); - - /* - // not possible now - if (!item.ForDir && !item.ForFile) - { - RINOK(dirItems.AddError(fullPath, ERROR_INVALID_PARAMETER)); - continue; - } - */ - - #if defined(_WIN32) && !defined(UNDER_CE) - bool needAltStreams = true; - #endif - - #ifdef Z7_USE_SECURITY_CODE - bool needSecurity = true; - #endif - - if (phyPrefix.IsEmpty()) - { - if (!item.ForFile) - { - /* we don't like some names for alt streams inside archive: - ":sname" for "\" - "c:::sname" for "C:\" - So we ignore alt streams for these cases */ - if (name.IsEmpty()) - { - #if defined(_WIN32) && !defined(UNDER_CE) - needAltStreams = false; - #endif - - /* - // do we need to ignore security info for "\\" folder ? - #ifdef Z7_USE_SECURITY_CODE - needSecurity = false; - #endif - */ - - fullPath = CHAR_PATH_SEPARATOR; - } - #if defined(_WIN32) && !defined(UNDER_CE) - else if (item.IsDriveItem()) - { - needAltStreams = false; - fullPath.Add_PathSepar(); - } - #endif - } - } - - NFind::CFileInfo fi; - #if defined(_WIN32) && !defined(UNDER_CE) - if (IsVirtualFsFolder(phyPrefix, name)) - { - fi.SetAsDir(); - fi.Name = us2fs(name); - } - else - #endif - if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2)) - { - RINOK(dirItems.AddError(fullPath)) - continue; - } - - /* - #ifdef _WIN32 - #define MY_ERROR_IS_DIR ERROR_FILE_NOT_FOUND - #define MY_ERROR_NOT_DIR DI_DEFAULT_ERROR - #else - #define MY_ERROR_IS_DIR EISDIR - #define MY_ERROR_NOT_DIR ENOTDIR - #endif - */ - - const bool isDir = fi.IsDir(); - if (isDir ? !item.ForDir : !item.ForFile) - { - // RINOK(dirItems.AddError(fullPath, isDir ? MY_ERROR_IS_DIR: MY_ERROR_NOT_DIR)); - RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR)) - continue; - } - { - UStringVector pathParts; - pathParts.Add(fs2us(fi.Name)); - if (curNode.CheckPathToRoot(false, pathParts, !isDir)) - continue; - } - - - if (dirItems.CanIncludeItem(fi.IsDir())) - { - int secureIndex = -1; - #ifdef Z7_USE_SECURITY_CODE - if (needSecurity && dirItems.ReadSecure) - { - RINOK(dirItems.AddSecurityItem(fullPath, secureIndex)) - } - #endif - - dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); - - // we don't scan AltStreams for link files - - #if !defined(UNDER_CE) - { - CDirItem &dirItem = dirItems.Items.Back(); - RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix)) - if (dirItem.ReparseData.Size() != 0) - continue; - } - - #if defined(_WIN32) - if (needAltStreams && dirItems.ScanAltStreams) - { - UStringVector pathParts; - pathParts.Add(fs2us(fi.Name)); - RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, - fullPath, // including (name) - pathParts, // including (fi.Name) - true, /* addAllSubStreams */ - dirItems)) - } - #endif // defined(_WIN32) - - #endif // !defined(UNDER_CE) - } - - - #ifndef _WIN32 - if (!fi.IsPosixLink()) // posix link can follow to dir - #endif - if (!isDir) - continue; - - UStringVector newParts; - const NWildcard::CCensorNode *nextNode = NULL; - int index = curNode.FindSubNode(name); - if (index >= 0) - { - for (int t = (int)needEnterVector.Size(); t <= index; t++) - needEnterVector.Add(true); - needEnterVector[(unsigned)index] = false; - nextNode = &curNode.SubNodes[(unsigned)index]; - } - else - { - #ifndef _WIN32 - if (fi.IsPosixLink()) - { - // here we can try to resolve posix link - // if the link to dir, then can we follow it - continue; // we don't follow posix link - } - #else - if (dirItems.SymLinks) - { - if (fi.HasReparsePoint()) - { - /* 20.03: in SymLinks mode: we don't enter to directory that - has reparse point and has no CCensorNode */ - continue; - } - } - #endif - nextNode = &curNode; - newParts.Add(name); // don't change it to fi.Name. It's for shortnames support - } - - RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, - newParts, dirItems, true)) - } - - for (i = 0; i < curNode.SubNodes.Size(); i++) - { - if (i < needEnterVector.Size()) - if (!needEnterVector[i]) - continue; - const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; - FString fullPath = phyPrefix + us2fs(nextNode.Name); - NFind::CFileInfo fi; - - if (nextNode.Name.IsEmpty()) - { - if (phyPrefix.IsEmpty()) - fullPath = CHAR_PATH_SEPARATOR; - } - #ifdef _WIN32 - else if(phyPrefix.IsEmpty() - || (phyPrefix.Len() == NName::kSuperPathPrefixSize - && IsSuperPath(phyPrefix))) - { - if (NWildcard::IsDriveColonName(nextNode.Name)) - fullPath.Add_PathSepar(); - } - #endif - - // we don't want to call fi.Find() for root folder or virtual folder - if ((phyPrefix.IsEmpty() && nextNode.Name.IsEmpty()) - #if defined(_WIN32) && !defined(UNDER_CE) - || IsVirtualFsFolder(phyPrefix, nextNode.Name) - #endif - ) - { - fi.SetAsDir(); - fi.Name = us2fs(nextNode.Name); - } - else - { - if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2)) - { - if (!nextNode.AreThereIncludeItems()) - continue; - RINOK(dirItems.AddError(fullPath)) - continue; - } - - if (!fi.IsDir()) - { - RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR)) - continue; - } - } - - RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, - UStringVector(), dirItems, false)) - } - - return S_OK; - } - } - - #ifdef _WIN32 - #ifndef UNDER_CE - - // scan drives, if wildcard is "*:\" - - if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0) - { - unsigned i; - for (i = 0; i < curNode.IncludeItems.Size(); i++) - { - const NWildcard::CItem &item = curNode.IncludeItems[i]; - if (item.PathParts.Size() < 1) - break; - const UString &name = item.PathParts.Front(); - if (name.Len() != 2 || name[1] != ':') - break; - if (item.PathParts.Size() == 1) - if (item.ForFile || !item.ForDir) - break; - if (NWildcard::IsDriveColonName(name)) - continue; - if (name[0] != '*' && name[0] != '?') - break; - } - if (i == curNode.IncludeItems.Size()) - { - FStringVector driveStrings; - NFind::MyGetLogicalDriveStrings(driveStrings); - for (i = 0; i < driveStrings.Size(); i++) - { - FString driveName = driveStrings[i]; - if (driveName.Len() < 3 || driveName.Back() != '\\') - return E_FAIL; - driveName.DeleteBack(); - NFind::CFileInfo fi; - fi.SetAsDir(); - fi.Name = driveName; - - RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, - addParts, dirItems, enterToSubFolders)) - } - return S_OK; - } - } - - #endif - #endif - - - CObjectVector files; - - // for (int y = 0; y < 1; y++) - { - // files.Clear(); - RINOK(dirItems.EnumerateOneDir(phyPrefix, files)) - /* - FOR_VECTOR (i, files) - { - #ifdef _WIN32 - // const NFind::CFileInfo &fi = files[i]; - #else - NFind::CFileInfo &fi = files[i]; - { - const NFind::CFileInfo &di = files[i]; - const FString path = phyPrefix + di.Name; - if (!fi.Find_AfterEnumerator(path)) - { - RINOK(dirItems.AddError(path)); - continue; - } - fi.Name = di.Name; - } - #endif - - } - */ - } - - FOR_VECTOR (i, files) - { - #ifdef _WIN32 - const NFind::CFileInfo &fi = files[i]; - #else - const NFind::CFileInfo &fi = files[i]; - /* - NFind::CFileInfo fi; - { - const NFind::CDirEntry &di = files[i]; - const FString path = phyPrefix + di.Name; - if (!fi.Find_AfterEnumerator(path)) - { - RINOK(dirItems.AddError(path)); - continue; - } - fi.Name = di.Name; - } - */ - #endif - - RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, - addParts, dirItems, enterToSubFolders)) - if (dirItems.Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) - { - RINOK(dirItems.ScanProgress(phyPrefix)) - } - } - - return S_OK; -} - - - - -HRESULT EnumerateItems( - const NWildcard::CCensor &censor, - const NWildcard::ECensorPathMode pathMode, - const UString &addPathPrefix, // prefix that will be added to Logical Path - CDirItems &dirItems) -{ - FOR_VECTOR (i, censor.Pairs) - { - const NWildcard::CPair &pair = censor.Pairs[i]; - const int phyParent = pair.Prefix.IsEmpty() ? -1 : (int)dirItems.AddPrefix(-1, -1, pair.Prefix); - int logParent = -1; - - if (pathMode == NWildcard::k_AbsPath) - logParent = phyParent; - else - { - if (!addPathPrefix.IsEmpty()) - logParent = (int)dirItems.AddPrefix(-1, -1, addPathPrefix); - } - - RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(), - dirItems, - false // enterToSubFolders - )) - } - dirItems.ReserveDown(); - - #if defined(_WIN32) && !defined(UNDER_CE) - RINOK(dirItems.FillFixedReparse()) - #endif - - #ifndef _WIN32 - RINOK(dirItems.FillDeviceSizes()) - #endif - - return S_OK; -} - - -#if defined(_WIN32) && !defined(UNDER_CE) - -HRESULT CDirItems::FillFixedReparse() -{ - FOR_VECTOR(i, Items) - { - CDirItem &item = Items[i]; - - if (!SymLinks) - { - // continue; // for debug - if (!item.Has_Attrib_ReparsePoint()) - continue; - - // if (item.IsDir()) continue; - - const FString phyPath = GetPhyPath(i); - - NFind::CFileInfo fi; - if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir() - { - item.Size = fi.Size; - item.CTime = fi.CTime; - item.ATime = fi.ATime; - item.MTime = fi.MTime; - item.Attrib = fi.Attrib; - continue; - } - - /* - // we request properties of target file instead of properies of symbolic link - // here we also can manually parse unsupported links (like WSL links) - NIO::CInFile inFile; - if (inFile.Open(phyPath)) - { - BY_HANDLE_FILE_INFORMATION info; - if (inFile.GetFileInformation(&info)) - { - // Stat.FilesSize doesn't contain item.Size already - // Stat.FilesSize -= item.Size; - item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; - Stat.FilesSize += item.Size; - item.CTime = info.ftCreationTime; - item.ATime = info.ftLastAccessTime; - item.MTime = info.ftLastWriteTime; - item.Attrib = info.dwFileAttributes; - continue; - } - } - */ - - RINOK(AddError(phyPath)) - continue; - } - - // (SymLinks == true) here - - if (item.ReparseData.Size() == 0) - continue; - - // if (item.Size == 0) - { - // 20.03: we use Reparse Data instead of real data - item.Size = item.ReparseData.Size(); - } - - CReparseAttr attr; - if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) - { - const FString phyPath = GetPhyPath(i); - AddError(phyPath, attr.ErrorCode); - continue; - } - - /* imagex/WIM reduces absolute paths in links (raparse data), - if we archive non root folder. We do same thing here */ - - bool isWSL = false; - if (attr.IsSymLink_WSL()) - { - // isWSL = true; - // we don't change WSL symlinks - continue; - } - else - { - if (attr.IsRelative_Win()) - continue; - } - - const UString &link = attr.GetPath(); - if (!IsDrivePath(link)) - continue; - // maybe we need to support networks paths also ? - - FString fullPathF; - if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF)) - continue; - const UString fullPath = fs2us(fullPathF); - const UString logPath = GetLogPath(i); - if (logPath.Len() >= fullPath.Len()) - continue; - if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0) - continue; - - const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len()); - if (!IsPathSepar(prefix.Back())) - continue; - - const unsigned rootPrefixSize = GetRootPrefixSize(prefix); - if (rootPrefixSize == 0) - continue; - if (rootPrefixSize == prefix.Len()) - continue; // simple case: paths are from root - - if (link.Len() <= prefix.Len()) - continue; - - if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) - continue; - - UString newLink = prefix.Left(rootPrefixSize); - newLink += link.Ptr(prefix.Len()); - - CByteBuffer data; - bool isSymLink = !attr.IsMountPoint(); - if (!FillLinkData(data, newLink, isSymLink, isWSL)) - continue; - item.ReparseData2 = data; - } - return S_OK; -} - -#endif - - -#ifndef _WIN32 - -HRESULT CDirItems::FillDeviceSizes() -{ - { - FOR_VECTOR (i, Items) - { - CDirItem &item = Items[i]; - - if (S_ISBLK(item.mode) && item.Size == 0) - { - const FString phyPath = GetPhyPath(i); - NIO::CInFile inFile; - inFile.PreserveATime = true; - if (inFile.OpenShared(phyPath, ShareForWrite)) // fixme: OpenShared ?? - { - UInt64 size = 0; - if (inFile.GetLength(size)) - item.Size = size; - } - } - if (StoreOwnerName) - { - OwnerNameMap.Add_UInt32(item.uid); - OwnerGroupMap.Add_UInt32(item.gid); - } - } - } - - if (StoreOwnerName) - { - UString u; - AString a; - { - FOR_VECTOR (i, OwnerNameMap.Numbers) - { - // 200K/sec speed - u.Empty(); - const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]); - // printf("\ngetpwuid=%s\n", pw->pw_name); - if (pw) - { - a = pw->pw_name; - ConvertUTF8ToUnicode(a, u); - } - OwnerNameMap.Strings.Add(u); - } - } - { - FOR_VECTOR (i, OwnerGroupMap.Numbers) - { - u.Empty(); - const group *gr = getgrgid(OwnerGroupMap.Numbers[i]); - if (gr) - { - // printf("\ngetgrgid %d %s\n", OwnerGroupMap.Numbers[i], gr->gr_name); - a = gr->gr_name; - ConvertUTF8ToUnicode(a, u); - } - OwnerGroupMap.Strings.Add(u); - } - } - - FOR_VECTOR (i, Items) - { - CDirItem &item = Items[i]; - { - const int index = OwnerNameMap.Find(item.uid); - if (index < 0) throw 1; - item.OwnerNameIndex = index; - } - { - const int index = OwnerGroupMap.Find(item.gid); - if (index < 0) throw 1; - item.OwnerGroupIndex = index; - } - } - } - - - // if (NeedOwnerNames) - { - /* - { - for (unsigned i = 0 ; i < 10000; i++) - { - const passwd *pw = getpwuid(i); - if (pw) - { - UString u; - ConvertUTF8ToUnicode(AString(pw->pw_name), u); - OwnerNameMap.Add(i, u); - OwnerNameMap.Add(i, u); - OwnerNameMap.Add(i, u); - } - const group *gr = getgrgid(i); - if (gr) - { - // we can use utf-8 here. - UString u; - ConvertUTF8ToUnicode(AString(gr->gr_name), u); - OwnerGroupMap.Add(i, u); - } - } - } - */ - /* - { - FOR_VECTOR (i, OwnerNameMap.Strings) - { - AString s; - ConvertUnicodeToUTF8(OwnerNameMap.Strings[i], s); - printf("\n%5d %s", (unsigned)OwnerNameMap.Numbers[i], s.Ptr()); - } - } - { - printf("\n\n=========Groups\n"); - FOR_VECTOR (i, OwnerGroupMap.Strings) - { - AString s; - ConvertUnicodeToUTF8(OwnerGroupMap.Strings[i], s); - printf("\n%5d %s", (unsigned)OwnerGroupMap.Numbers[i], s.Ptr()); - } - } - */ - } - /* - for (unsigned i = 0 ; i < 100000000; i++) - { - // const passwd *pw = getpwuid(1000); - // pw = pw; - int pos = OwnerNameMap.Find(1000); - if (pos < 0 - (int)i) - throw 1; - } - */ - - return S_OK; -} - -#endif - - - -static const char * const kCannotFindArchive = "Cannot find archive"; - -HRESULT EnumerateDirItemsAndSort( - NWildcard::CCensor &censor, - NWildcard::ECensorPathMode censorPathMode, - const UString &addPathPrefix, - UStringVector &sortedPaths, - UStringVector &sortedFullPaths, - CDirItemsStat &st, - IDirItemsCallback *callback) -{ - FStringVector paths; - - { - CDirItems dirItems; - dirItems.Callback = callback; - { - HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems); - st = dirItems.Stat; - RINOK(res) - } - - FOR_VECTOR (i, dirItems.Items) - { - const CDirItem &dirItem = dirItems.Items[i]; - if (!dirItem.IsDir()) - paths.Add(dirItems.GetPhyPath(i)); - } - } - - if (paths.Size() == 0) - { - // return S_OK; - throw CMessagePathException(kCannotFindArchive); - } - - UStringVector fullPaths; - - unsigned i; - - for (i = 0; i < paths.Size(); i++) - { - FString fullPath; - NFile::NDir::MyGetFullPathName(paths[i], fullPath); - fullPaths.Add(fs2us(fullPath)); - } - - CUIntVector indices; - SortFileNames(fullPaths, indices); - sortedPaths.ClearAndReserve(indices.Size()); - sortedFullPaths.ClearAndReserve(indices.Size()); - - for (i = 0; i < indices.Size(); i++) - { - unsigned index = indices[i]; - sortedPaths.AddInReserved(fs2us(paths[index])); - sortedFullPaths.AddInReserved(fullPaths[index]); - if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0) - throw CMessagePathException("Duplicate archive path:", sortedFullPaths[i]); - } - - return S_OK; -} - - - - -#ifdef _WIN32 - -static bool IsDotsName(const wchar_t *s) -{ - return s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)); -} - -// This code converts all short file names to long file names. - -static void ConvertToLongName(const UString &prefix, UString &name) -{ - if (name.IsEmpty() - || DoesNameContainWildcard(name) - || IsDotsName(name)) - return; - NFind::CFileInfo fi; - const FString path (us2fs(prefix + name)); - #ifndef UNDER_CE - if (NFile::NName::IsDevicePath(path)) - return; - #endif - if (fi.Find(path)) - name = fs2us(fi.Name); -} - -static void ConvertToLongNames(const UString &prefix, CObjectVector &items) -{ - FOR_VECTOR (i, items) - { - NWildcard::CItem &item = items[i]; - if (item.Recursive || item.PathParts.Size() != 1) - continue; - if (prefix.IsEmpty() && item.IsDriveItem()) - continue; - ConvertToLongName(prefix, item.PathParts.Front()); - } -} - -static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node) -{ - ConvertToLongNames(prefix, node.IncludeItems); - ConvertToLongNames(prefix, node.ExcludeItems); - unsigned i; - for (i = 0; i < node.SubNodes.Size(); i++) - { - UString &name = node.SubNodes[i].Name; - if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name)) - continue; - ConvertToLongName(prefix, name); - } - // mix folders with same name - for (i = 0; i < node.SubNodes.Size(); i++) - { - NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; - for (unsigned j = i + 1; j < node.SubNodes.Size();) - { - const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; - if (nextNode1.Name.IsEqualTo_NoCase(nextNode2.Name)) - { - nextNode1.IncludeItems += nextNode2.IncludeItems; - nextNode1.ExcludeItems += nextNode2.ExcludeItems; - node.SubNodes.Delete(j); - } - else - j++; - } - } - for (i = 0; i < node.SubNodes.Size(); i++) - { - NWildcard::CCensorNode &nextNode = node.SubNodes[i]; - ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode); - } -} - -void ConvertToLongNames(NWildcard::CCensor &censor) -{ - FOR_VECTOR (i, censor.Pairs) - { - NWildcard::CPair &pair = censor.Pairs[i]; - ConvertToLongNames(pair.Prefix, pair.Head); - } -} - -#endif - - -CMessagePathException::CMessagePathException(const char *a, const wchar_t *u) -{ - (*this) += a; - if (u) - { - Add_LF(); - (*this) += u; - } -} - -CMessagePathException::CMessagePathException(const wchar_t *a, const wchar_t *u) -{ - (*this) += a; - if (u) - { - Add_LF(); - (*this) += u; - } -} +// EnumDirItems.cpp + +#include "StdAfx.h" + +#include +// #include + +#ifndef _WIN32 +#include +#include +#include "../../../Common/UTFConvert.h" +#endif + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +#define Z7_USE_SECURITY_CODE +#include "../../../Windows/SecurityUtils.h" +#endif + +#include "EnumDirItems.h" +#include "SortUtils.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; + + +static bool FindFile_KeepDots(NFile::NFind::CFileInfo &fi, const FString &path, bool followLink) +{ + const bool res = fi.Find(path, followLink); + if (!res) + return res; + if (path.IsEmpty()) + return res; + // we keep name "." and "..", if it's without tail slash + const FChar *p = path.RightPtr(1); + if (*p != '.') + return res; + if (p != path.Ptr()) + { + FChar c = p[-1]; + if (!IS_PATH_SEPAR(c)) + { + if (c != '.') + return res; + p--; + if (p != path.Ptr()) + { + c = p[-1]; + if (!IS_PATH_SEPAR(c)) + return res; + } + } + } + fi.Name = p; + return res; +} + + +void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex, + const NFind::CFileInfo &fi) +{ + /* + CDirItem di(fi); + di.PhyParent = phyParent; + di.LogParent = logParent; + di.SecureIndex = secureIndex; + Items.Add(di); + */ + VECTOR_ADD_NEW_OBJECT (Items, CDirItem(fi, phyParent, logParent, secureIndex)) + + if (fi.IsDir()) + Stat.NumDirs++; + #ifdef _WIN32 + else if (fi.IsAltStream) + { + Stat.NumAltStreams++; + Stat.AltStreamsSize += fi.Size; + } + #endif + else + { + Stat.NumFiles++; + Stat.FilesSize += fi.Size; + } +} + +// (DWORD)E_FAIL +#define DI_DEFAULT_ERROR ERROR_INVALID_FUNCTION + +HRESULT CDirItems::AddError(const FString &path, DWORD errorCode) +{ + if (errorCode == 0) + errorCode = DI_DEFAULT_ERROR; + Stat.NumErrors++; + if (Callback) + return Callback->ScanError(path, errorCode); + return S_OK; +} + +HRESULT CDirItems::AddError(const FString &path) +{ + return AddError(path, ::GetLastError()); +} + +static const unsigned kScanProgressStepMask = (1 << 12) - 1; + +HRESULT CDirItems::ScanProgress(const FString &dirPath) +{ + if (Callback) + return Callback->ScanProgress(Stat, dirPath, true); + return S_OK; +} + +UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const +{ + UString path; + unsigned len = name.Len(); + + int i; + for (i = index; i >= 0; i = parents[(unsigned)i]) + len += Prefixes[(unsigned)i].Len(); + + wchar_t *p = path.GetBuf_SetEnd(len) + len; + + p -= name.Len(); + wmemcpy(p, (const wchar_t *)name, name.Len()); + + for (i = index; i >= 0; i = parents[(unsigned)i]) + { + const UString &s = Prefixes[(unsigned)i]; + p -= s.Len(); + wmemcpy(p, (const wchar_t *)s, s.Len()); + } + + return path; +} + +FString CDirItems::GetPhyPath(unsigned index) const +{ + const CDirItem &di = Items[index]; + return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name)); +} + +UString CDirItems::GetLogPath(unsigned index) const +{ + const CDirItem &di = Items[index]; + return GetPrefixesPath(LogParents, di.LogParent, di.Name); +} + +void CDirItems::ReserveDown() +{ + Prefixes.ReserveDown(); + PhyParents.ReserveDown(); + LogParents.ReserveDown(); + Items.ReserveDown(); +} + +unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) +{ + PhyParents.Add(phyParent); + LogParents.Add(logParent); + return Prefixes.Add(prefix); +} + +void CDirItems::DeleteLastPrefix() +{ + PhyParents.DeleteBack(); + LogParents.DeleteBack(); + Prefixes.DeleteBack(); +} + +bool InitLocalPrivileges(); + +CDirItems::CDirItems(): + SymLinks(false), + ScanAltStreams(false) + , ExcludeDirItems(false) + , ExcludeFileItems(false) + , ShareForWrite(false) + #ifdef Z7_USE_SECURITY_CODE + , ReadSecure(false) + #endif + #ifndef _WIN32 + , StoreOwnerName(false) + #endif + , Callback(NULL) +{ + #ifdef Z7_USE_SECURITY_CODE + _saclEnabled = InitLocalPrivileges(); + #endif +} + + +#ifdef Z7_USE_SECURITY_CODE + +HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex) +{ + secureIndex = -1; + + SECURITY_INFORMATION securInfo = + DACL_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION; + if (_saclEnabled) + securInfo |= SACL_SECURITY_INFORMATION; + + DWORD errorCode = 0; + DWORD secureSize; + + BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); + + if (res) + { + if (secureSize == 0) + return S_OK; + if (secureSize > TempSecureBuf.Size()) + errorCode = ERROR_INVALID_FUNCTION; + } + else + { + errorCode = GetLastError(); + if (errorCode == ERROR_INSUFFICIENT_BUFFER) + { + if (secureSize <= TempSecureBuf.Size()) + errorCode = ERROR_INVALID_FUNCTION; + else + { + TempSecureBuf.Alloc(secureSize); + res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize); + if (res) + { + if (secureSize != TempSecureBuf.Size()) + errorCode = ERROR_INVALID_FUNCTION; + } + else + errorCode = GetLastError(); + } + } + } + + if (res) + { + secureIndex = (int)SecureBlocks.AddUniq(TempSecureBuf, secureSize); + return S_OK; + } + + return AddError(path, errorCode); +} + +#endif // Z7_USE_SECURITY_CODE + + +HRESULT CDirItems::EnumerateOneDir(const FString &phyPrefix, CObjectVector &files) +{ + NFind::CEnumerator enumerator; + // printf("\n enumerator.SetDirPrefix(phyPrefix) \n"); + + enumerator.SetDirPrefix(phyPrefix); + + #ifdef _WIN32 + + NFind::CFileInfo fi; + + for (unsigned ttt = 0; ; ttt++) + { + bool found; + if (!enumerator.Next(fi, found)) + return AddError(phyPrefix); + if (!found) + return S_OK; + files.Add(fi); + if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask) + { + RINOK(ScanProgress(phyPrefix)) + } + } + + #else // _WIN32 + + // enumerator.SolveLinks = !SymLinks; + + CObjectVector entries; + + for (;;) + { + bool found; + NFind::CDirEntry de; + if (!enumerator.Next(de, found)) + return AddError(phyPrefix); + if (!found) + break; + entries.Add(de); + } + + FOR_VECTOR(i, entries) + { + const NFind::CDirEntry &de = entries[i]; + NFind::CFileInfo fi; + if (!enumerator.Fill_FileInfo(de, fi, !SymLinks)) + // if (!fi.Find_AfterEnumerator(path)) + { + const FString path = phyPrefix + de.Name; + { + RINOK(AddError(path)) + continue; + } + } + + files.Add(fi); + + if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) + { + RINOK(ScanProgress(phyPrefix)) + } + } + + return S_OK; + + #endif // _WIN32 +} + + + + +HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix) +{ + RINOK(ScanProgress(phyPrefix)) + + CObjectVector files; + RINOK(EnumerateOneDir(phyPrefix, files)) + + FOR_VECTOR (i, files) + { + #ifdef _WIN32 + const NFind::CFileInfo &fi = files[i]; + #else + const NFind::CFileInfo &fi = files[i]; + /* + NFind::CFileInfo fi; + { + const NFind::CDirEntry &di = files[i]; + const FString path = phyPrefix + di.Name; + if (!fi.Find_AfterEnumerator(path)) + { + RINOK(AddError(path)); + continue; + } + fi.Name = di.Name; + } + */ + #endif + + if (CanIncludeItem(fi.IsDir())) + { + int secureIndex = -1; + #ifdef Z7_USE_SECURITY_CODE + if (ReadSecure) + { + RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex)) + } + #endif + AddDirFileInfo(phyParent, logParent, secureIndex, fi); + } + + if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) + { + RINOK(ScanProgress(phyPrefix)) + } + + if (fi.IsDir()) + { + const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; + unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2)); + RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + name2)) + } + } + return S_OK; +} + + +/* +EnumerateItems2() + const FStringVector &filePaths - are path without tail slashes. + All dir prefixes of filePaths will be not stores in logical paths +fix it: we can scan AltStream also. +*/ + +#ifdef _WIN32 +// #define FOLLOW_LINK_PARAM +// #define FOLLOW_LINK_PARAM2 +#define FOLLOW_LINK_PARAM , (!SymLinks) +#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks) +#else +#define FOLLOW_LINK_PARAM , (!SymLinks) +#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks) +#endif + +HRESULT CDirItems::EnumerateItems2( + const FString &phyPrefix, + const UString &logPrefix, + const FStringVector &filePaths, + FStringVector *requestedPaths) +{ + const int phyParent = phyPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, fs2us(phyPrefix)); + const int logParent = logPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, logPrefix); + + #ifdef _WIN32 + const bool phyPrefix_isAltStreamPrefix = + NFile::NName::IsAltStreamPrefixWithColon(fs2us(phyPrefix)); + #endif + + FOR_VECTOR (i, filePaths) + { + const FString &filePath = filePaths[i]; + NFind::CFileInfo fi; + const FString phyPath = phyPrefix + filePath; + if (!FindFile_KeepDots(fi, phyPath FOLLOW_LINK_PARAM)) + { + RINOK(AddError(phyPath)) + continue; + } + if (requestedPaths) + requestedPaths->Add(phyPath); + + const int delimiter = filePath.ReverseFind_PathSepar(); + FString phyPrefixCur; + int phyParentCur = phyParent; + if (delimiter >= 0) + { + phyPrefixCur.SetFrom(filePath, (unsigned)(delimiter + 1)); + phyParentCur = (int)AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); + } + + if (CanIncludeItem(fi.IsDir())) + { + int secureIndex = -1; + #ifdef Z7_USE_SECURITY_CODE + if (ReadSecure) + { + RINOK(AddSecurityItem(phyPath, secureIndex)) + } + #endif + #ifdef _WIN32 + if (phyPrefix_isAltStreamPrefix && fi.IsAltStream) + { + const int pos = fi.Name.Find(FChar(':')); + if (pos >= 0) + fi.Name.DeleteFrontal((unsigned)pos + 1); + } + #endif + AddDirFileInfo(phyParentCur, logParent, secureIndex, fi); + } + + if (fi.IsDir()) + { + const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR; + const unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2)); + RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + phyPrefixCur + name2)) + } + } + + ReserveDown(); + return S_OK; +} + + + + +static HRESULT EnumerateDirItems( + const NWildcard::CCensorNode &curNode, + const int phyParent, const int logParent, + const FString &phyPrefix, + const UStringVector &addParts, // additional parts from curNode + CDirItems &dirItems, + bool enterToSubFolders); + + +/* EnumerateDirItems_Spec() + adds new Dir item prefix, and enumerates dir items, + then it can remove that Dir item prefix, if there are no items in that dir. +*/ + + +/* + EnumerateDirItems_Spec() + it's similar to EnumerateDirItems, but phyPrefix doesn't include (curFolderName) +*/ + +static HRESULT EnumerateDirItems_Spec( + const NWildcard::CCensorNode &curNode, + const int phyParent, const int logParent, const FString &curFolderName, + const FString &phyPrefix, // without (curFolderName) + const UStringVector &addParts, // (curNode + addParts) includes (curFolderName) + CDirItems &dirItems, + bool enterToSubFolders) +{ + const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR; + const unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2)); + const unsigned numItems = dirItems.Items.Size(); + HRESULT res = EnumerateDirItems( + curNode, (int)parent, (int)parent, phyPrefix + name2, + addParts, dirItems, enterToSubFolders); + if (numItems == dirItems.Items.Size()) + dirItems.DeleteLastPrefix(); + return res; +} + + +#ifndef UNDER_CE + +#ifdef _WIN32 + +static HRESULT EnumerateAltStreams( + const NFind::CFileInfo &fi, + const NWildcard::CCensorNode &curNode, + const int phyParent, const int logParent, + const FString &phyPath, // with (fi.Name), without tail slash for folders + const UStringVector &addParts, // with (fi.Name), prefix parts from curNode + bool addAllSubStreams, + CDirItems &dirItems) +{ + // we don't use (ExcludeFileItems) rules for AltStreams + // if (dirItems.ExcludeFileItems) return S_OK; + + NFind::CStreamEnumerator enumerator(phyPath); + for (;;) + { + NFind::CStreamInfo si; + bool found; + if (!enumerator.Next(si, found)) + { + return dirItems.AddError(phyPath + FTEXT(":*")); // , (DWORD)E_FAIL + } + if (!found) + return S_OK; + if (si.IsMainStream()) + continue; + UStringVector parts = addParts; + const UString reducedName = si.GetReducedName(); + parts.Back() += reducedName; + if (curNode.CheckPathToRoot(false, parts, true)) + continue; + if (!addAllSubStreams) + if (!curNode.CheckPathToRoot(true, parts, true)) + continue; + + NFind::CFileInfo fi2 = fi; + fi2.Name += us2fs(reducedName); + fi2.Size = si.Size; + fi2.Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); + fi2.IsAltStream = true; + dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2); + } +} + +#endif // _WIN32 + + +/* We get Reparse data and parse it. + If there is Reparse error, we free dirItem.Reparse data. + Do we need to work with empty reparse data? +*/ + +HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi, + const FString &phyPrefix) +{ + if (!SymLinks) + return S_OK; + + #ifdef _WIN32 + if (!fi.HasReparsePoint() || fi.IsAltStream) + #else // _WIN32 + if (!fi.IsPosixLink()) + #endif // _WIN32 + return S_OK; + + const FString path = phyPrefix + fi.Name; + CByteBuffer &buf = dirItem.ReparseData; + if (NIO::GetReparseData(path, buf)) + { + // if (dirItem.ReparseData.Size() != 0) + Stat.FilesSize -= fi.Size; + return S_OK; + } + + DWORD res = ::GetLastError(); + buf.Free(); + return AddError(path, res); +} + +#endif // UNDER_CE + + + +static HRESULT EnumerateForItem( + const NFind::CFileInfo &fi, + const NWildcard::CCensorNode &curNode, + const int phyParent, const int logParent, const FString &phyPrefix, + const UStringVector &addParts, // additional parts from curNode, without (fi.Name) + CDirItems &dirItems, + bool enterToSubFolders) +{ + const UString name = fs2us(fi.Name); + UStringVector newParts = addParts; + newParts.Add(name); + + // check the path in exclude rules + if (curNode.CheckPathToRoot(false, newParts, !fi.IsDir())) + return S_OK; + + #if !defined(UNDER_CE) + int dirItemIndex = -1; + #if defined(_WIN32) + bool addAllSubStreams = false; + bool needAltStreams = true; + #endif // _WIN32 + #endif // !defined(UNDER_CE) + + // check the path in inlcude rules + if (curNode.CheckPathToRoot(true, newParts, !fi.IsDir())) + { + #if !defined(UNDER_CE) + // dirItemIndex = (int)dirItems.Items.Size(); + #if defined(_WIN32) + // we will not check include rules for substreams. + addAllSubStreams = true; + #endif // _WIN32 + #endif // !defined(UNDER_CE) + + if (dirItems.CanIncludeItem(fi.IsDir())) + { + int secureIndex = -1; + #ifdef Z7_USE_SECURITY_CODE + if (dirItems.ReadSecure) + { + RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex)) + } + #endif + #if !defined(UNDER_CE) + dirItemIndex = (int)dirItems.Items.Size(); + #endif // !defined(UNDER_CE) + dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); + } + else + { + #if defined(_WIN32) && !defined(UNDER_CE) + needAltStreams = false; + #endif + } + + if (fi.IsDir()) + enterToSubFolders = true; + } + + #if !defined(UNDER_CE) + + // we don't scan AltStreams for link files + + if (dirItemIndex >= 0) + { + CDirItem &dirItem = dirItems.Items[(unsigned)dirItemIndex]; + RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix)) + if (dirItem.ReparseData.Size() != 0) + return S_OK; + } + + #if defined(_WIN32) + if (needAltStreams && dirItems.ScanAltStreams && !fi.IsAltStream) + { + RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, + phyPrefix + fi.Name, // with (fi.Name) + newParts, // with (fi.Name) + addAllSubStreams, + dirItems)) + } + #endif + + #endif // !defined(UNDER_CE) + + + #ifndef _WIN32 + if (!fi.IsPosixLink()) // posix link can follow to dir + #endif + if (!fi.IsDir()) + return S_OK; + + const NWildcard::CCensorNode *nextNode = NULL; + + if (addParts.IsEmpty()) + { + int index = curNode.FindSubNode(name); + if (index >= 0) + { + nextNode = &curNode.SubNodes[(unsigned)index]; + newParts.Clear(); + } + } + + if (!nextNode) + { + if (!enterToSubFolders) + return S_OK; + + #ifndef _WIN32 + if (fi.IsPosixLink()) + { + // here we can try to resolve posix link + // if the link to dir, then can we follow it + return S_OK; // we don't follow posix link + } + #else + if (dirItems.SymLinks && fi.HasReparsePoint()) + { + /* 20.03: in SymLinks mode: we don't enter to directory that + has reparse point and has no CCensorNode + NOTE: (curNode and parent nodes) still can have wildcard rules + to include some items of target directory (of reparse point), + but we ignore these rules here. + */ + return S_OK; + } + #endif + nextNode = &curNode; + } + + return EnumerateDirItems_Spec( + *nextNode, phyParent, logParent, fi.Name, + phyPrefix, // without (fi.Name) + newParts, // relative to (*nextNode). (*nextNode + newParts) includes (fi.Name) + dirItems, + enterToSubFolders); +} + + +static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode) +{ + FOR_VECTOR (i, curNode.IncludeItems) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + if (item.Recursive || item.PathParts.Size() != 1) + return false; + const UString &name = item.PathParts.Front(); + /* + if (name.IsEmpty()) + return false; + */ + + /* Windows doesn't support file name with wildcard + But if another system supports file name with wildcard, + and wildcard mode is disabled, we can ignore wildcard in name + */ + /* + #ifndef _WIN32 + if (!item.WildcardParsing) + continue; + #endif + */ + if (DoesNameContainWildcard(name)) + return false; + } + return true; +} + + +#if defined(_WIN32) && !defined(UNDER_CE) + +static bool IsVirtualFsFolder(const FString &prefix, const UString &name) +{ + UString s = fs2us(prefix); + s += name; + s.Add_PathSepar(); + // it returns (true) for non real FS folder path like - "\\SERVER\" + return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0; +} + +#endif + + + +static HRESULT EnumerateDirItems( + const NWildcard::CCensorNode &curNode, + const int phyParent, const int logParent, const FString &phyPrefix, + const UStringVector &addParts, // prefix from curNode including + CDirItems &dirItems, + bool enterToSubFolders) +{ + if (!enterToSubFolders) + { + /* if there are IncludeItems censor rules that affect items in subdirs, + then we will enter to all subfolders */ + if (curNode.NeedCheckSubDirs()) + enterToSubFolders = true; + } + + RINOK(dirItems.ScanProgress(phyPrefix)) + + // try direct_names case at first + if (addParts.IsEmpty() && !enterToSubFolders) + { + if (CanUseFsDirect(curNode)) + { + // all names are direct (no wildcards) + // so we don't need file_system's dir enumerator + CRecordVector needEnterVector; + unsigned i; + + for (i = 0; i < curNode.IncludeItems.Size(); i++) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + const UString &name = item.PathParts.Front(); + FString fullPath = phyPrefix + us2fs(name); + + /* + // not possible now + if (!item.ForDir && !item.ForFile) + { + RINOK(dirItems.AddError(fullPath, ERROR_INVALID_PARAMETER)); + continue; + } + */ + + #if defined(_WIN32) && !defined(UNDER_CE) + bool needAltStreams = true; + #endif + + #ifdef Z7_USE_SECURITY_CODE + bool needSecurity = true; + #endif + + if (phyPrefix.IsEmpty()) + { + if (!item.ForFile) + { + /* we don't like some names for alt streams inside archive: + ":sname" for "\" + "c:::sname" for "C:\" + So we ignore alt streams for these cases */ + if (name.IsEmpty()) + { + #if defined(_WIN32) && !defined(UNDER_CE) + needAltStreams = false; + #endif + + /* + // do we need to ignore security info for "\\" folder ? + #ifdef Z7_USE_SECURITY_CODE + needSecurity = false; + #endif + */ + + fullPath = CHAR_PATH_SEPARATOR; + } + #if defined(_WIN32) && !defined(UNDER_CE) + else if (item.IsDriveItem()) + { + needAltStreams = false; + fullPath.Add_PathSepar(); + } + #endif + } + } + + NFind::CFileInfo fi; + #if defined(_WIN32) && !defined(UNDER_CE) + if (IsVirtualFsFolder(phyPrefix, name)) + { + fi.SetAsDir(); + fi.Name = us2fs(name); + } + else + #endif + if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2)) + { + RINOK(dirItems.AddError(fullPath)) + continue; + } + + /* + #ifdef _WIN32 + #define MY_ERROR_IS_DIR ERROR_FILE_NOT_FOUND + #define MY_ERROR_NOT_DIR DI_DEFAULT_ERROR + #else + #define MY_ERROR_IS_DIR EISDIR + #define MY_ERROR_NOT_DIR ENOTDIR + #endif + */ + + const bool isDir = fi.IsDir(); + if (isDir ? !item.ForDir : !item.ForFile) + { + // RINOK(dirItems.AddError(fullPath, isDir ? MY_ERROR_IS_DIR: MY_ERROR_NOT_DIR)); + RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR)) + continue; + } + { + UStringVector pathParts; + pathParts.Add(fs2us(fi.Name)); + if (curNode.CheckPathToRoot(false, pathParts, !isDir)) + continue; + } + + + if (dirItems.CanIncludeItem(fi.IsDir())) + { + int secureIndex = -1; + #ifdef Z7_USE_SECURITY_CODE + if (needSecurity && dirItems.ReadSecure) + { + RINOK(dirItems.AddSecurityItem(fullPath, secureIndex)) + } + #endif + + dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi); + + // we don't scan AltStreams for link files + + #if !defined(UNDER_CE) + { + CDirItem &dirItem = dirItems.Items.Back(); + RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix)) + if (dirItem.ReparseData.Size() != 0) + continue; + } + + #if defined(_WIN32) + if (needAltStreams && dirItems.ScanAltStreams && !fi.IsAltStream) + { + UStringVector pathParts; + pathParts.Add(fs2us(fi.Name)); + RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, + fullPath, // including (name) + pathParts, // including (fi.Name) + true, /* addAllSubStreams */ + dirItems)) + } + #endif // defined(_WIN32) + + #endif // !defined(UNDER_CE) + } + + + #ifndef _WIN32 + if (!fi.IsPosixLink()) // posix link can follow to dir + #endif + if (!isDir) + continue; + + UStringVector newParts; + const NWildcard::CCensorNode *nextNode = NULL; + int index = curNode.FindSubNode(name); + if (index >= 0) + { + for (int t = (int)needEnterVector.Size(); t <= index; t++) + needEnterVector.Add(true); + needEnterVector[(unsigned)index] = false; + nextNode = &curNode.SubNodes[(unsigned)index]; + } + else + { + #ifndef _WIN32 + if (fi.IsPosixLink()) + { + // here we can try to resolve posix link + // if the link to dir, then can we follow it + continue; // we don't follow posix link + } + #else + if (dirItems.SymLinks) + { + if (fi.HasReparsePoint()) + { + /* 20.03: in SymLinks mode: we don't enter to directory that + has reparse point and has no CCensorNode */ + continue; + } + } + #endif + nextNode = &curNode; + newParts.Add(name); // don't change it to fi.Name. It's for shortnames support + } + + RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, + newParts, dirItems, true)) + } + + for (i = 0; i < curNode.SubNodes.Size(); i++) + { + if (i < needEnterVector.Size()) + if (!needEnterVector[i]) + continue; + const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; + FString fullPath = phyPrefix + us2fs(nextNode.Name); + NFind::CFileInfo fi; + + if (nextNode.Name.IsEmpty()) + { + if (phyPrefix.IsEmpty()) + fullPath = CHAR_PATH_SEPARATOR; + } + #ifdef _WIN32 + else if(phyPrefix.IsEmpty() + || (phyPrefix.Len() == NName::kSuperPathPrefixSize + && IsSuperPath(phyPrefix))) + { + if (NWildcard::IsDriveColonName(nextNode.Name)) + fullPath.Add_PathSepar(); + } + #endif + + // we don't want to call fi.Find() for root folder or virtual folder + if ((phyPrefix.IsEmpty() && nextNode.Name.IsEmpty()) + #if defined(_WIN32) && !defined(UNDER_CE) + || IsVirtualFsFolder(phyPrefix, nextNode.Name) + #endif + ) + { + fi.SetAsDir(); + fi.Name = us2fs(nextNode.Name); + } + else + { + if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2)) + { + if (!nextNode.AreThereIncludeItems()) + continue; + RINOK(dirItems.AddError(fullPath)) + continue; + } + + if (!fi.IsDir()) + { + RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR)) + continue; + } + } + + RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix, + UStringVector(), dirItems, false)) + } + + return S_OK; + } + } + + #ifdef _WIN32 + #ifndef UNDER_CE + + // scan drives, if wildcard is "*:\" + + if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0) + { + unsigned i; + for (i = 0; i < curNode.IncludeItems.Size(); i++) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + if (item.PathParts.Size() < 1) + break; + const UString &name = item.PathParts.Front(); + if (name.Len() != 2 || name[1] != ':') + break; + if (item.PathParts.Size() == 1) + if (item.ForFile || !item.ForDir) + break; + if (NWildcard::IsDriveColonName(name)) + continue; + if (name[0] != '*' && name[0] != '?') + break; + } + if (i == curNode.IncludeItems.Size()) + { + FStringVector driveStrings; + NFind::MyGetLogicalDriveStrings(driveStrings); + for (i = 0; i < driveStrings.Size(); i++) + { + FString driveName = driveStrings[i]; + if (driveName.Len() < 3 || driveName.Back() != '\\') + return E_FAIL; + driveName.DeleteBack(); + NFind::CFileInfo fi; + fi.SetAsDir(); + fi.Name = driveName; + + RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, + addParts, dirItems, enterToSubFolders)) + } + return S_OK; + } + } + + #endif + #endif + + + CObjectVector files; + + // for (int y = 0; y < 1; y++) + { + // files.Clear(); + RINOK(dirItems.EnumerateOneDir(phyPrefix, files)) + /* + FOR_VECTOR (i, files) + { + #ifdef _WIN32 + // const NFind::CFileInfo &fi = files[i]; + #else + NFind::CFileInfo &fi = files[i]; + { + const NFind::CFileInfo &di = files[i]; + const FString path = phyPrefix + di.Name; + if (!fi.Find_AfterEnumerator(path)) + { + RINOK(dirItems.AddError(path)); + continue; + } + fi.Name = di.Name; + } + #endif + + } + */ + } + + FOR_VECTOR (i, files) + { + #ifdef _WIN32 + const NFind::CFileInfo &fi = files[i]; + #else + const NFind::CFileInfo &fi = files[i]; + /* + NFind::CFileInfo fi; + { + const NFind::CDirEntry &di = files[i]; + const FString path = phyPrefix + di.Name; + if (!fi.Find_AfterEnumerator(path)) + { + RINOK(dirItems.AddError(path)); + continue; + } + fi.Name = di.Name; + } + */ + #endif + + RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, + addParts, dirItems, enterToSubFolders)) + if (dirItems.Callback && (i & kScanProgressStepMask) == kScanProgressStepMask) + { + RINOK(dirItems.ScanProgress(phyPrefix)) + } + } + + return S_OK; +} + + + + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + const NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, // prefix that will be added to Logical Path + CDirItems &dirItems) +{ + FOR_VECTOR (i, censor.Pairs) + { + const NWildcard::CPair &pair = censor.Pairs[i]; + const int phyParent = pair.Prefix.IsEmpty() ? -1 : (int)dirItems.AddPrefix(-1, -1, pair.Prefix); + int logParent = -1; + + if (pathMode == NWildcard::k_AbsPath) + logParent = phyParent; + else + { + if (!addPathPrefix.IsEmpty()) + logParent = (int)dirItems.AddPrefix(-1, -1, addPathPrefix); + } + + RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(), + dirItems, + false // enterToSubFolders + )) + } + dirItems.ReserveDown(); + + #if defined(_WIN32) && !defined(UNDER_CE) + RINOK(dirItems.FillFixedReparse()) + #endif + + #ifndef _WIN32 + RINOK(dirItems.FillDeviceSizes()) + #endif + + return S_OK; +} + + +#if defined(_WIN32) && !defined(UNDER_CE) + +HRESULT CDirItems::FillFixedReparse() +{ + FOR_VECTOR(i, Items) + { + CDirItem &item = Items[i]; + + if (!SymLinks) + { + // continue; // for debug + if (!item.Has_Attrib_ReparsePoint()) + continue; + + // if (item.IsDir()) continue; + + const FString phyPath = GetPhyPath(i); + + NFind::CFileInfo fi; + if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir() + { + item.Size = fi.Size; + item.CTime = fi.CTime; + item.ATime = fi.ATime; + item.MTime = fi.MTime; + item.Attrib = fi.Attrib; + continue; + } + + /* + // we request properties of target file instead of properies of symbolic link + // here we also can manually parse unsupported links (like WSL links) + NIO::CInFile inFile; + if (inFile.Open(phyPath)) + { + BY_HANDLE_FILE_INFORMATION info; + if (inFile.GetFileInformation(&info)) + { + // Stat.FilesSize doesn't contain item.Size already + // Stat.FilesSize -= item.Size; + item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + Stat.FilesSize += item.Size; + item.CTime = info.ftCreationTime; + item.ATime = info.ftLastAccessTime; + item.MTime = info.ftLastWriteTime; + item.Attrib = info.dwFileAttributes; + continue; + } + } + */ + + RINOK(AddError(phyPath)) + continue; + } + + // (SymLinks == true) here + + if (item.ReparseData.Size() == 0) + continue; + + // if (item.Size == 0) + { + // 20.03: we use Reparse Data instead of real data + item.Size = item.ReparseData.Size(); + } + + CReparseAttr attr; + if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) + { + const FString phyPath = GetPhyPath(i); + AddError(phyPath, attr.ErrorCode); + continue; + } + + /* imagex/WIM reduces absolute paths in links (raparse data), + if we archive non root folder. We do same thing here */ + + bool isWSL = false; + if (attr.IsSymLink_WSL()) + { + // isWSL = true; + // we don't change WSL symlinks + continue; + } + else + { + if (attr.IsRelative_Win()) + continue; + } + + const UString &link = attr.GetPath(); + if (!IsDrivePath(link)) + continue; + // maybe we need to support networks paths also ? + + FString fullPathF; + if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF)) + continue; + const UString fullPath = fs2us(fullPathF); + const UString logPath = GetLogPath(i); + if (logPath.Len() >= fullPath.Len()) + continue; + if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0) + continue; + + const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len()); + if (!IsPathSepar(prefix.Back())) + continue; + + const unsigned rootPrefixSize = GetRootPrefixSize(prefix); + if (rootPrefixSize == 0) + continue; + if (rootPrefixSize == prefix.Len()) + continue; // simple case: paths are from root + + if (link.Len() <= prefix.Len()) + continue; + + if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) + continue; + + UString newLink = prefix.Left(rootPrefixSize); + newLink += link.Ptr(prefix.Len()); + + CByteBuffer data; + bool isSymLink = !attr.IsMountPoint(); + if (!FillLinkData(data, newLink, isSymLink, isWSL)) + continue; + item.ReparseData2 = data; + } + return S_OK; +} + +#endif + + +#ifndef _WIN32 + +HRESULT CDirItems::FillDeviceSizes() +{ + { + FOR_VECTOR (i, Items) + { + CDirItem &item = Items[i]; + + if (S_ISBLK(item.mode) && item.Size == 0) + { + const FString phyPath = GetPhyPath(i); + NIO::CInFile inFile; + inFile.PreserveATime = true; + if (inFile.OpenShared(phyPath, ShareForWrite)) // fixme: OpenShared ?? + { + UInt64 size = 0; + if (inFile.GetLength(size)) + item.Size = size; + } + } + if (StoreOwnerName) + { + OwnerNameMap.Add_UInt32(item.uid); + OwnerGroupMap.Add_UInt32(item.gid); + } + } + } + + if (StoreOwnerName) + { + UString u; + AString a; + { + FOR_VECTOR (i, OwnerNameMap.Numbers) + { + // 200K/sec speed + u.Empty(); + const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]); + // printf("\ngetpwuid=%s\n", pw->pw_name); + if (pw) + { + a = pw->pw_name; + ConvertUTF8ToUnicode(a, u); + } + OwnerNameMap.Strings.Add(u); + } + } + { + FOR_VECTOR (i, OwnerGroupMap.Numbers) + { + u.Empty(); + const group *gr = getgrgid(OwnerGroupMap.Numbers[i]); + if (gr) + { + // printf("\ngetgrgid %d %s\n", OwnerGroupMap.Numbers[i], gr->gr_name); + a = gr->gr_name; + ConvertUTF8ToUnicode(a, u); + } + OwnerGroupMap.Strings.Add(u); + } + } + + FOR_VECTOR (i, Items) + { + CDirItem &item = Items[i]; + { + const int index = OwnerNameMap.Find(item.uid); + if (index < 0) throw 1; + item.OwnerNameIndex = index; + } + { + const int index = OwnerGroupMap.Find(item.gid); + if (index < 0) throw 1; + item.OwnerGroupIndex = index; + } + } + } + + + // if (NeedOwnerNames) + { + /* + { + for (unsigned i = 0 ; i < 10000; i++) + { + const passwd *pw = getpwuid(i); + if (pw) + { + UString u; + ConvertUTF8ToUnicode(AString(pw->pw_name), u); + OwnerNameMap.Add(i, u); + OwnerNameMap.Add(i, u); + OwnerNameMap.Add(i, u); + } + const group *gr = getgrgid(i); + if (gr) + { + // we can use utf-8 here. + UString u; + ConvertUTF8ToUnicode(AString(gr->gr_name), u); + OwnerGroupMap.Add(i, u); + } + } + } + */ + /* + { + FOR_VECTOR (i, OwnerNameMap.Strings) + { + AString s; + ConvertUnicodeToUTF8(OwnerNameMap.Strings[i], s); + printf("\n%5d %s", (unsigned)OwnerNameMap.Numbers[i], s.Ptr()); + } + } + { + printf("\n\n=========Groups\n"); + FOR_VECTOR (i, OwnerGroupMap.Strings) + { + AString s; + ConvertUnicodeToUTF8(OwnerGroupMap.Strings[i], s); + printf("\n%5d %s", (unsigned)OwnerGroupMap.Numbers[i], s.Ptr()); + } + } + */ + } + /* + for (unsigned i = 0 ; i < 100000000; i++) + { + // const passwd *pw = getpwuid(1000); + // pw = pw; + int pos = OwnerNameMap.Find(1000); + if (pos < 0 - (int)i) + throw 1; + } + */ + + return S_OK; +} + +#endif + + + +static const char * const kCannotFindArchive = "Cannot find archive"; + +HRESULT EnumerateDirItemsAndSort( + NWildcard::CCensor &censor, + NWildcard::ECensorPathMode censorPathMode, + const UString &addPathPrefix, + UStringVector &sortedPaths, + UStringVector &sortedFullPaths, + CDirItemsStat &st, + IDirItemsCallback *callback) +{ + FStringVector paths; + + { + CDirItems dirItems; + dirItems.Callback = callback; + { + HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems); + st = dirItems.Stat; + RINOK(res) + } + + FOR_VECTOR (i, dirItems.Items) + { + const CDirItem &dirItem = dirItems.Items[i]; + if (!dirItem.IsDir()) + paths.Add(dirItems.GetPhyPath(i)); + } + } + + if (paths.Size() == 0) + { + // return S_OK; + throw CMessagePathException(kCannotFindArchive); + } + + UStringVector fullPaths; + + unsigned i; + + for (i = 0; i < paths.Size(); i++) + { + FString fullPath; + NFile::NDir::MyGetFullPathName(paths[i], fullPath); + fullPaths.Add(fs2us(fullPath)); + } + + CUIntVector indices; + SortFileNames(fullPaths, indices); + sortedPaths.ClearAndReserve(indices.Size()); + sortedFullPaths.ClearAndReserve(indices.Size()); + + for (i = 0; i < indices.Size(); i++) + { + unsigned index = indices[i]; + sortedPaths.AddInReserved(fs2us(paths[index])); + sortedFullPaths.AddInReserved(fullPaths[index]); + if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0) + throw CMessagePathException("Duplicate archive path:", sortedFullPaths[i]); + } + + return S_OK; +} + + + + +#ifdef _WIN32 + +static bool IsDotsName(const wchar_t *s) +{ + return s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)); +} + +// This code converts all short file names to long file names. + +static void ConvertToLongName(const UString &prefix, UString &name) +{ + if (name.IsEmpty() + || DoesNameContainWildcard(name) + || IsDotsName(name)) + return; + NFind::CFileInfo fi; + const FString path (us2fs(prefix + name)); + #ifndef UNDER_CE + if (NFile::NName::IsDevicePath(path)) + return; + #endif + if (fi.Find(path)) + name = fs2us(fi.Name); +} + +static void ConvertToLongNames(const UString &prefix, CObjectVector &items) +{ + FOR_VECTOR (i, items) + { + NWildcard::CItem &item = items[i]; + if (item.Recursive || item.PathParts.Size() != 1) + continue; + if (prefix.IsEmpty() && item.IsDriveItem()) + continue; + ConvertToLongName(prefix, item.PathParts.Front()); + } +} + +static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node) +{ + ConvertToLongNames(prefix, node.IncludeItems); + ConvertToLongNames(prefix, node.ExcludeItems); + unsigned i; + for (i = 0; i < node.SubNodes.Size(); i++) + { + UString &name = node.SubNodes[i].Name; + if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name)) + continue; + ConvertToLongName(prefix, name); + } + // mix folders with same name + for (i = 0; i < node.SubNodes.Size(); i++) + { + NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; + for (unsigned j = i + 1; j < node.SubNodes.Size();) + { + const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; + if (nextNode1.Name.IsEqualTo_NoCase(nextNode2.Name)) + { + nextNode1.IncludeItems += nextNode2.IncludeItems; + nextNode1.ExcludeItems += nextNode2.ExcludeItems; + node.SubNodes.Delete(j); + } + else + j++; + } + } + for (i = 0; i < node.SubNodes.Size(); i++) + { + NWildcard::CCensorNode &nextNode = node.SubNodes[i]; + ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode); + } +} + +void ConvertToLongNames(NWildcard::CCensor &censor) +{ + FOR_VECTOR (i, censor.Pairs) + { + NWildcard::CPair &pair = censor.Pairs[i]; + ConvertToLongNames(pair.Prefix, pair.Head); + } +} + +#endif + + +CMessagePathException::CMessagePathException(const char *a, const wchar_t *u) +{ + (*this) += a; + if (u) + { + Add_LF(); + (*this) += u; + } +} + +CMessagePathException::CMessagePathException(const wchar_t *a, const wchar_t *u) +{ + (*this) += a; + if (u) + { + Add_LF(); + (*this) += u; + } +} diff --git a/CPP/7zip/UI/Common/EnumDirItems.h b/CPP/7zip/UI/Common/EnumDirItems.h index 6d02babf3..24f1c8bd5 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.h +++ b/CPP/7zip/UI/Common/EnumDirItems.h @@ -1,38 +1,38 @@ -// EnumDirItems.h - -#ifndef ZIP7_INC_ENUM_DIR_ITEMS_H -#define ZIP7_INC_ENUM_DIR_ITEMS_H - -#include "../../../Common/Wildcard.h" - -#include "DirItem.h" - - -HRESULT EnumerateItems( - const NWildcard::CCensor &censor, - NWildcard::ECensorPathMode pathMode, - const UString &addPathPrefix, - CDirItems &dirItems); - - -struct CMessagePathException: public UString -{ - CMessagePathException(const char *a, const wchar_t *u = NULL); - CMessagePathException(const wchar_t *a, const wchar_t *u = NULL); -}; - - -HRESULT EnumerateDirItemsAndSort( - NWildcard::CCensor &censor, - NWildcard::ECensorPathMode pathMode, - const UString &addPathPrefix, - UStringVector &sortedPaths, - UStringVector &sortedFullPaths, - CDirItemsStat &st, - IDirItemsCallback *callback); - -#ifdef _WIN32 -void ConvertToLongNames(NWildcard::CCensor &censor); -#endif - -#endif +// EnumDirItems.h + +#ifndef ZIP7_INC_ENUM_DIR_ITEMS_H +#define ZIP7_INC_ENUM_DIR_ITEMS_H + +#include "../../../Common/Wildcard.h" + +#include "DirItem.h" + + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, + CDirItems &dirItems); + + +struct CMessagePathException: public UString +{ + CMessagePathException(const char *a, const wchar_t *u = NULL); + CMessagePathException(const wchar_t *a, const wchar_t *u = NULL); +}; + + +HRESULT EnumerateDirItemsAndSort( + NWildcard::CCensor &censor, + NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, + UStringVector &sortedPaths, + UStringVector &sortedFullPaths, + CDirItemsStat &st, + IDirItemsCallback *callback); + +#ifdef _WIN32 +void ConvertToLongNames(NWildcard::CCensor &censor); +#endif + +#endif diff --git a/CPP/7zip/UI/Common/ExitCode.h b/CPP/7zip/UI/Common/ExitCode.h index 507178953..2d7b0293a 100644 --- a/CPP/7zip/UI/Common/ExitCode.h +++ b/CPP/7zip/UI/Common/ExitCode.h @@ -1,27 +1,27 @@ -// ExitCode.h - -#ifndef ZIP7_INC_EXIT_CODE_H -#define ZIP7_INC_EXIT_CODE_H - -namespace NExitCode { - -enum EEnum { - - kSuccess = 0, // Successful operation - kWarning = 1, // Non fatal error(s) occurred - kFatalError = 2, // A fatal error occurred - // kCRCError = 3, // A CRC error occurred when unpacking - // kLockedArchive = 4, // Attempt to modify an archive previously locked - // kWriteError = 5, // Write to disk error - // kOpenError = 6, // Open file error - kUserError = 7, // Command line option error - kMemoryError = 8, // Not enough memory for operation - // kCreateFileError = 9, // Create file error - - kUserBreak = 255 // User stopped the process - -}; - -} - -#endif +// ExitCode.h + +#ifndef ZIP7_INC_EXIT_CODE_H +#define ZIP7_INC_EXIT_CODE_H + +namespace NExitCode { + +enum EEnum { + + kSuccess = 0, // Successful operation + kWarning = 1, // Non fatal error(s) occurred + kFatalError = 2, // A fatal error occurred + // kCRCError = 3, // A CRC error occurred when unpacking + // kLockedArchive = 4, // Attempt to modify an archive previously locked + // kWriteError = 5, // Write to disk error + // kOpenError = 6, // Open file error + kUserError = 7, // Command line option error + kMemoryError = 8, // Not enough memory for operation + // kCreateFileError = 9, // Create file error + + kUserBreak = 255 // User stopped the process + +}; + +} + +#endif diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index 325a08c9e..010b01c29 100644 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp @@ -1,575 +1,575 @@ -// Extract.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../Common/ExtractingFilePath.h" -#include "../Common/HashCalc.h" - -#include "Extract.h" -#include "SetProperties.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - - -static void SetErrorMessage(const char *message, - const FString &path, HRESULT errorCode, - UString &s) -{ - s = message; - s += " : "; - s += NError::MyFormatMessage(errorCode); - s += " : "; - s += fs2us(path); -} - - -static HRESULT DecompressArchive( - CCodecs *codecs, - const CArchiveLink &arcLink, - UInt64 packSize, - const NWildcard::CCensorNode &wildcardCensor, - const CExtractOptions &options, - bool calcCrc, - IExtractCallbackUI *callback, - IFolderArchiveExtractCallback *callbackFAE, - CArchiveExtractCallback *ecs, - UString &errorMessage, - UInt64 &stdInProcessed) -{ - const CArc &arc = arcLink.Arcs.Back(); - stdInProcessed = 0; - IInArchive *archive = arc.Archive; - CRecordVector realIndices; - - UStringVector removePathParts; - - FString outDir = options.OutputDir; - UString replaceName = arc.DefaultName; - - if (arcLink.Arcs.Size() > 1) - { - // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1". - // So it extracts different archives to one folder. - // We will use top level archive name - const CArc &arc0 = arcLink.Arcs[0]; - if (arc0.FormatIndex >= 0 && StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)arc0.FormatIndex].Name, "pe")) - replaceName = arc0.DefaultName; - } - - outDir.Replace(FString("*"), us2fs(Get_Correct_FsFile_Name(replaceName))); - - bool elimIsPossible = false; - UString elimPrefix; // only pure name without dir delimiter - FString outDirReduced = outDir; - - if (options.ElimDup.Val && options.PathMode != NExtract::NPathMode::kAbsPaths) - { - UString dirPrefix; - SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix); - if (!elimPrefix.IsEmpty()) - { - if (IsPathSepar(elimPrefix.Back())) - elimPrefix.DeleteBack(); - if (!elimPrefix.IsEmpty()) - { - outDirReduced = us2fs(dirPrefix); - elimIsPossible = true; - } - } - } - - const bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); - - if (!options.StdInMode) - { - UInt32 numItems; - RINOK(archive->GetNumberOfItems(&numItems)) - - CReadArcItem item; - - for (UInt32 i = 0; i < numItems; i++) - { - if (elimIsPossible - || !allFilesAreAllowed - || options.ExcludeDirItems - || options.ExcludeFileItems) - { - RINOK(arc.GetItem(i, item)) - if (item.IsDir ? options.ExcludeDirItems : options.ExcludeFileItems) - continue; - } - else - { - #ifdef SUPPORT_ALT_STREAMS - item.IsAltStream = false; - if (!options.NtOptions.AltStreams.Val && arc.Ask_AltStream) - { - RINOK(Archive_IsItem_AltStream(arc.Archive, i, item.IsAltStream)) - } - #endif - } - - #ifdef SUPPORT_ALT_STREAMS - if (!options.NtOptions.AltStreams.Val && item.IsAltStream) - continue; - #endif - - if (elimIsPossible) - { - const UString &s = - #ifdef SUPPORT_ALT_STREAMS - item.MainPath; - #else - item.Path; - #endif - if (!IsPath1PrefixedByPath2(s, elimPrefix)) - elimIsPossible = false; - else - { - wchar_t c = s[elimPrefix.Len()]; - if (c == 0) - { - if (!item.MainIsDir) - elimIsPossible = false; - } - else if (!IsPathSepar(c)) - elimIsPossible = false; - } - } - - if (!allFilesAreAllowed) - { - if (!CensorNode_CheckPath(wildcardCensor, item)) - continue; - } - - realIndices.Add(i); - } - - if (realIndices.Size() == 0) - { - callback->ThereAreNoFiles(); - return callback->ExtractResult(S_OK); - } - } - - if (elimIsPossible) - { - removePathParts.Add(elimPrefix); - // outDir = outDirReduced; - } - - #ifdef _WIN32 - // GetCorrectFullFsPath doesn't like "..". - // outDir.TrimRight(); - // outDir = GetCorrectFullFsPath(outDir); - #endif - - if (outDir.IsEmpty()) - outDir = "." STRING_PATH_SEPARATOR; - /* - #ifdef _WIN32 - else if (NName::IsAltPathPrefix(outDir)) {} - #endif - */ - else if (!CreateComplexDir(outDir)) - { - const HRESULT res = GetLastError_noZero_HRESULT(); - SetErrorMessage("Cannot create output directory", outDir, res, errorMessage); - return res; - } - - ecs->Init( - options.NtOptions, - options.StdInMode ? &wildcardCensor : NULL, - &arc, - callbackFAE, - options.StdOutMode, options.TestMode, - outDir, - removePathParts, false, - packSize); - - ecs->Is_elimPrefix_Mode = elimIsPossible; - - - #ifdef SUPPORT_LINKS - - if (!options.StdInMode && - !options.TestMode && - options.NtOptions.HardLinks.Val) - { - RINOK(ecs->PrepareHardLinks(&realIndices)) - } - - #endif - - - HRESULT result; - const Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; - - CArchiveExtractCallback_Closer ecsCloser(ecs); - - if (options.StdInMode) - { - result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); - NCOM::CPropVariant prop; - if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) - ConvertPropVariantToUInt64(prop, stdInProcessed); - } - else - { - // v23.02: we reset completed value that could be set by Open() operation - IArchiveExtractCallback *aec = ecs; - const UInt64 val = 0; - RINOK(aec->SetCompleted(&val)) - result = archive->Extract(realIndices.ConstData(), realIndices.Size(), testMode, aec); - } - - const HRESULT res2 = ecsCloser.Close(); - if (result == S_OK) - result = res2; - - return callback->ExtractResult(result); -} - -/* v9.31: BUG was fixed: - Sorted list for file paths was sorted with case insensitive compare function. - But FindInSorted function did binary search via case sensitive compare function */ - -int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name); -int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name) -{ - unsigned left = 0, right = fileNames.Size(); - while (left != right) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const UString &midVal = fileNames[mid]; - const int comp = CompareFileNames(name, midVal); - if (comp == 0) - return (int)mid; - if (comp < 0) - right = mid; - else - left = mid + 1; - } - return -1; -} - - - -HRESULT Extract( - // DECL_EXTERNAL_CODECS_LOC_VARS - CCodecs *codecs, - const CObjectVector &types, - const CIntVector &excludedFormats, - UStringVector &arcPaths, UStringVector &arcPathsFull, - const NWildcard::CCensorNode &wildcardCensor, - const CExtractOptions &options, - IOpenCallbackUI *openCallback, - IExtractCallbackUI *extractCallback, - IFolderArchiveExtractCallback *faeCallback, - #ifndef Z7_SFX - IHashCalc *hash, - #endif - UString &errorMessage, - CDecompressStat &st) -{ - st.Clear(); - UInt64 totalPackSize = 0; - CRecordVector arcSizes; - - unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size(); - - unsigned i; - - for (i = 0; i < numArcs; i++) - { - NFind::CFileInfo fi; - fi.Size = 0; - if (!options.StdInMode) - { - const FString arcPath = us2fs(arcPaths[i]); - if (!fi.Find_FollowLink(arcPath)) - { - const HRESULT errorCode = GetLastError_noZero_HRESULT(); - SetErrorMessage("Cannot find archive file", arcPath, errorCode, errorMessage); - return errorCode; - } - if (fi.IsDir()) - { - HRESULT errorCode = E_FAIL; - SetErrorMessage("The item is a directory", arcPath, errorCode, errorMessage); - return errorCode; - } - } - arcSizes.Add(fi.Size); - totalPackSize += fi.Size; - } - - CBoolArr skipArcs(numArcs); - for (i = 0; i < numArcs; i++) - skipArcs[i] = false; - - CArchiveExtractCallback *ecs = new CArchiveExtractCallback; - CMyComPtr ec(ecs); - - const bool multi = (numArcs > 1); - - ecs->InitForMulti(multi, - options.PathMode, - options.OverwriteMode, - options.ZoneMode, - false // keepEmptyDirParts - ); - #ifndef Z7_SFX - ecs->SetHashMethods(hash); - #endif - - if (multi) - { - RINOK(faeCallback->SetTotal(totalPackSize)) - } - - UInt64 totalPackProcessed = 0; - bool thereAreNotOpenArcs = false; - - for (i = 0; i < numArcs; i++) - { - if (skipArcs[i]) - continue; - - ecs->InitBeforeNewArchive(); - - const UString &arcPath = arcPaths[i]; - NFind::CFileInfo fi; - if (options.StdInMode) - { - // do we need ctime and mtime? - // fi.ClearBase(); - // fi.Size = 0; // (UInt64)(Int64)-1; - if (!fi.SetAs_StdInFile()) - return GetLastError_noZero_HRESULT(); - } - else - { - if (!fi.Find_FollowLink(us2fs(arcPath)) || fi.IsDir()) - { - const HRESULT errorCode = GetLastError_noZero_HRESULT(); - SetErrorMessage("Cannot find archive file", us2fs(arcPath), errorCode, errorMessage); - return errorCode; - } - } - - /* - #ifndef Z7_NO_CRYPTO - openCallback->Open_Clear_PasswordWasAsked_Flag(); - #endif - */ - - RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode)) - CArchiveLink arcLink; - - CObjectVector types2 = types; - /* - #ifndef Z7_SFX - if (types.IsEmpty()) - { - int pos = arcPath.ReverseFind(L'.'); - if (pos >= 0) - { - UString s = arcPath.Ptr(pos + 1); - int index = codecs->FindFormatForExtension(s); - if (index >= 0 && s == L"001") - { - s = arcPath.Left(pos); - pos = s.ReverseFind(L'.'); - if (pos >= 0) - { - int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1)); - if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0 - { - types2.Add(index2); - types2.Add(index); - } - } - } - } - } - #endif - */ - - COpenOptions op; - #ifndef Z7_SFX - op.props = &options.Properties; - #endif - op.codecs = codecs; - op.types = &types2; - op.excludedFormats = &excludedFormats; - op.stdInMode = options.StdInMode; - op.stream = NULL; - op.filePath = arcPath; - - HRESULT result = arcLink.Open_Strict(op, openCallback); - - if (result == E_ABORT) - return result; - - // arcLink.Set_ErrorsText(); - RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result)) - - if (result != S_OK) - { - thereAreNotOpenArcs = true; - if (!options.StdInMode) - totalPackProcessed += fi.Size; - continue; - } - - #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) - if (options.ZoneMode != NExtract::NZoneIdMode::kNone - && !options.StdInMode) - { - ReadZoneFile_Of_BaseFile(us2fs(arcPath), ecs->ZoneBuf); - } - #endif - - - if (arcLink.Arcs.Size() != 0) - { - if (arcLink.GetArc()->IsHashHandler(op)) - { - if (!options.TestMode) - { - /* real Extracting to files is possible. - But user can think that hash archive contains real files. - So we block extracting here. */ - // v23.00 : we don't break process. - RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, E_NOTIMPL)) - thereAreNotOpenArcs = true; - if (!options.StdInMode) - totalPackProcessed += fi.Size; - continue; - // return E_NOTIMPL; // before v23 - } - FString dirPrefix = us2fs(options.HashDir); - if (dirPrefix.IsEmpty()) - { - if (!NFile::NDir::GetOnlyDirPrefix(us2fs(arcPath), dirPrefix)) - { - // return GetLastError_noZero_HRESULT(); - } - } - if (!dirPrefix.IsEmpty()) - NName::NormalizeDirPathPrefix(dirPrefix); - ecs->DirPathPrefix_for_HashFiles = dirPrefix; - } - } - - if (!options.StdInMode) - { - // numVolumes += arcLink.VolumePaths.Size(); - // arcLink.VolumesSize; - - // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes); - // numArcs = arcPaths.Size(); - if (arcLink.VolumePaths.Size() != 0) - { - Int64 correctionSize = (Int64)arcLink.VolumesSize; - FOR_VECTOR (v, arcLink.VolumePaths) - { - int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); - if (index >= 0) - { - if ((unsigned)index > i) - { - skipArcs[(unsigned)index] = true; - correctionSize -= arcSizes[(unsigned)index]; - } - } - } - if (correctionSize != 0) - { - Int64 newPackSize = (Int64)totalPackSize + correctionSize; - if (newPackSize < 0) - newPackSize = 0; - totalPackSize = (UInt64)newPackSize; - RINOK(faeCallback->SetTotal(totalPackSize)) - } - } - } - - /* - // Now openCallback and extractCallback use same object. So we don't need to send password. - - #ifndef Z7_NO_CRYPTO - bool passwordIsDefined; - UString password; - RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password)) - if (passwordIsDefined) - { - RINOK(extractCallback->SetPassword(password)) - } - #endif - */ - - CArc &arc = arcLink.Arcs.Back(); - arc.MTime.Def = !options.StdInMode - #ifdef _WIN32 - && !fi.IsDevice - #endif - ; - if (arc.MTime.Def) - arc.MTime.Set_From_FiTime(fi.MTime); - - UInt64 packProcessed; - const bool calcCrc = - #ifndef Z7_SFX - (hash != NULL); - #else - false; - #endif - - RINOK(DecompressArchive( - codecs, - arcLink, - fi.Size + arcLink.VolumesSize, - wildcardCensor, - options, - calcCrc, - extractCallback, faeCallback, ecs, - errorMessage, packProcessed)) - - if (!options.StdInMode) - packProcessed = fi.Size + arcLink.VolumesSize; - totalPackProcessed += packProcessed; - ecs->LocalProgressSpec->InSize += packProcessed; - ecs->LocalProgressSpec->OutSize = ecs->UnpackSize; - if (!errorMessage.IsEmpty()) - return E_FAIL; - } - - if (multi || thereAreNotOpenArcs) - { - RINOK(faeCallback->SetTotal(totalPackSize)) - RINOK(faeCallback->SetCompleted(&totalPackProcessed)) - } - - st.NumFolders = ecs->NumFolders; - st.NumFiles = ecs->NumFiles; - st.NumAltStreams = ecs->NumAltStreams; - st.UnpackSize = ecs->UnpackSize; - st.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize; - st.NumArchives = arcPaths.Size(); - st.PackSize = ecs->LocalProgressSpec->InSize; - return S_OK; -} +// Extract.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../Common/ExtractingFilePath.h" +#include "../Common/HashCalc.h" + +#include "Extract.h" +#include "SetProperties.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + + +static void SetErrorMessage(const char *message, + const FString &path, HRESULT errorCode, + UString &s) +{ + s = message; + s += " : "; + s += NError::MyFormatMessage(errorCode); + s += " : "; + s += fs2us(path); +} + + +static HRESULT DecompressArchive( + CCodecs *codecs, + const CArchiveLink &arcLink, + UInt64 packSize, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + bool calcCrc, + IExtractCallbackUI *callback, + IFolderArchiveExtractCallback *callbackFAE, + CArchiveExtractCallback *ecs, + UString &errorMessage, + UInt64 &stdInProcessed) +{ + const CArc &arc = arcLink.Arcs.Back(); + stdInProcessed = 0; + IInArchive *archive = arc.Archive; + CRecordVector realIndices; + + UStringVector removePathParts; + + FString outDir = options.OutputDir; + UString replaceName = arc.DefaultName; + + if (arcLink.Arcs.Size() > 1) + { + // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1". + // So it extracts different archives to one folder. + // We will use top level archive name + const CArc &arc0 = arcLink.Arcs[0]; + if (arc0.FormatIndex >= 0 && StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)arc0.FormatIndex].Name, "pe")) + replaceName = arc0.DefaultName; + } + + outDir.Replace(FString("*"), us2fs(Get_Correct_FsFile_Name(replaceName))); + + bool elimIsPossible = false; + UString elimPrefix; // only pure name without dir delimiter + FString outDirReduced = outDir; + + if (options.ElimDup.Val && options.PathMode != NExtract::NPathMode::kAbsPaths) + { + UString dirPrefix; + SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix); + if (!elimPrefix.IsEmpty()) + { + if (IsPathSepar(elimPrefix.Back())) + elimPrefix.DeleteBack(); + if (!elimPrefix.IsEmpty()) + { + outDirReduced = us2fs(dirPrefix); + elimIsPossible = true; + } + } + } + + const bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); + + if (!options.StdInMode) + { + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)) + + CReadArcItem item; + + for (UInt32 i = 0; i < numItems; i++) + { + if (elimIsPossible + || !allFilesAreAllowed + || options.ExcludeDirItems + || options.ExcludeFileItems) + { + RINOK(arc.GetItem(i, item)) + if (item.IsDir ? options.ExcludeDirItems : options.ExcludeFileItems) + continue; + } + else + { + #ifdef SUPPORT_ALT_STREAMS + item.IsAltStream = false; + if (!options.NtOptions.AltStreams.Val && arc.Ask_AltStream) + { + RINOK(Archive_IsItem_AltStream(arc.Archive, i, item.IsAltStream)) + } + #endif + } + + #ifdef SUPPORT_ALT_STREAMS + if (!options.NtOptions.AltStreams.Val && item.IsAltStream) + continue; + #endif + + if (elimIsPossible) + { + const UString &s = + #ifdef SUPPORT_ALT_STREAMS + item.MainPath; + #else + item.Path; + #endif + if (!IsPath1PrefixedByPath2(s, elimPrefix)) + elimIsPossible = false; + else + { + wchar_t c = s[elimPrefix.Len()]; + if (c == 0) + { + if (!item.MainIsDir) + elimIsPossible = false; + } + else if (!IsPathSepar(c)) + elimIsPossible = false; + } + } + + if (!allFilesAreAllowed) + { + if (!CensorNode_CheckPath(wildcardCensor, item)) + continue; + } + + realIndices.Add(i); + } + + if (realIndices.Size() == 0) + { + callback->ThereAreNoFiles(); + return callback->ExtractResult(S_OK); + } + } + + if (elimIsPossible) + { + removePathParts.Add(elimPrefix); + // outDir = outDirReduced; + } + + #ifdef _WIN32 + // GetCorrectFullFsPath doesn't like "..". + // outDir.TrimRight(); + // outDir = GetCorrectFullFsPath(outDir); + #endif + + if (outDir.IsEmpty()) + outDir = "." STRING_PATH_SEPARATOR; + /* + #ifdef _WIN32 + else if (NName::IsAltPathPrefix(outDir)) {} + #endif + */ + else if (!CreateComplexDir(outDir)) + { + const HRESULT res = GetLastError_noZero_HRESULT(); + SetErrorMessage("Cannot create output directory", outDir, res, errorMessage); + return res; + } + + ecs->Init( + options.NtOptions, + options.StdInMode ? &wildcardCensor : NULL, + &arc, + callbackFAE, + options.StdOutMode, options.TestMode, + outDir, + removePathParts, false, + packSize); + + ecs->Is_elimPrefix_Mode = elimIsPossible; + + + #ifdef SUPPORT_LINKS + + if (!options.StdInMode && + !options.TestMode && + options.NtOptions.HardLinks.Val) + { + RINOK(ecs->PrepareHardLinks(&realIndices)) + } + + #endif + + + HRESULT result; + const Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; + + CArchiveExtractCallback_Closer ecsCloser(ecs); + + if (options.StdInMode) + { + result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); + NCOM::CPropVariant prop; + if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) + ConvertPropVariantToUInt64(prop, stdInProcessed); + } + else + { + // v23.02: we reset completed value that could be set by Open() operation + IArchiveExtractCallback *aec = ecs; + const UInt64 val = 0; + RINOK(aec->SetCompleted(&val)) + result = archive->Extract(realIndices.ConstData(), realIndices.Size(), testMode, aec); + } + + const HRESULT res2 = ecsCloser.Close(); + if (result == S_OK) + result = res2; + + return callback->ExtractResult(result); +} + +/* v9.31: BUG was fixed: + Sorted list for file paths was sorted with case insensitive compare function. + But FindInSorted function did binary search via case sensitive compare function */ + +int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name); +int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name) +{ + unsigned left = 0, right = fileNames.Size(); + while (left != right) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const UString &midVal = fileNames[mid]; + const int comp = CompareFileNames(name, midVal); + if (comp == 0) + return (int)mid; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + return -1; +} + + + +HRESULT Extract( + // DECL_EXTERNAL_CODECS_LOC_VARS + CCodecs *codecs, + const CObjectVector &types, + const CIntVector &excludedFormats, + UStringVector &arcPaths, UStringVector &arcPathsFull, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IOpenCallbackUI *openCallback, + IExtractCallbackUI *extractCallback, + IFolderArchiveExtractCallback *faeCallback, + #ifndef Z7_SFX + IHashCalc *hash, + #endif + UString &errorMessage, + CDecompressStat &st) +{ + st.Clear(); + UInt64 totalPackSize = 0; + CRecordVector arcSizes; + + unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size(); + + unsigned i; + + for (i = 0; i < numArcs; i++) + { + NFind::CFileInfo fi; + fi.Size = 0; + if (!options.StdInMode) + { + const FString arcPath = us2fs(arcPaths[i]); + if (!fi.Find_FollowLink(arcPath)) + { + const HRESULT errorCode = GetLastError_noZero_HRESULT(); + SetErrorMessage("Cannot find archive file", arcPath, errorCode, errorMessage); + return errorCode; + } + if (fi.IsDir()) + { + HRESULT errorCode = E_FAIL; + SetErrorMessage("The item is a directory", arcPath, errorCode, errorMessage); + return errorCode; + } + } + arcSizes.Add(fi.Size); + totalPackSize += fi.Size; + } + + CBoolArr skipArcs(numArcs); + for (i = 0; i < numArcs; i++) + skipArcs[i] = false; + + CArchiveExtractCallback *ecs = new CArchiveExtractCallback; + CMyComPtr ec(ecs); + + const bool multi = (numArcs > 1); + + ecs->InitForMulti(multi, + options.PathMode, + options.OverwriteMode, + options.ZoneMode, + false // keepEmptyDirParts + ); + #ifndef Z7_SFX + ecs->SetHashMethods(hash); + #endif + + if (multi) + { + RINOK(faeCallback->SetTotal(totalPackSize)) + } + + UInt64 totalPackProcessed = 0; + bool thereAreNotOpenArcs = false; + + for (i = 0; i < numArcs; i++) + { + if (skipArcs[i]) + continue; + + ecs->InitBeforeNewArchive(); + + const UString &arcPath = arcPaths[i]; + NFind::CFileInfo fi; + if (options.StdInMode) + { + // do we need ctime and mtime? + // fi.ClearBase(); + // fi.Size = 0; // (UInt64)(Int64)-1; + if (!fi.SetAs_StdInFile()) + return GetLastError_noZero_HRESULT(); + } + else + { + if (!fi.Find_FollowLink(us2fs(arcPath)) || fi.IsDir()) + { + const HRESULT errorCode = GetLastError_noZero_HRESULT(); + SetErrorMessage("Cannot find archive file", us2fs(arcPath), errorCode, errorMessage); + return errorCode; + } + } + + /* + #ifndef Z7_NO_CRYPTO + openCallback->Open_Clear_PasswordWasAsked_Flag(); + #endif + */ + + RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode)) + CArchiveLink arcLink; + + CObjectVector types2 = types; + /* + #ifndef Z7_SFX + if (types.IsEmpty()) + { + int pos = arcPath.ReverseFind(L'.'); + if (pos >= 0) + { + UString s = arcPath.Ptr(pos + 1); + int index = codecs->FindFormatForExtension(s); + if (index >= 0 && s == L"001") + { + s = arcPath.Left(pos); + pos = s.ReverseFind(L'.'); + if (pos >= 0) + { + int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1)); + if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0 + { + types2.Add(index2); + types2.Add(index); + } + } + } + } + } + #endif + */ + + COpenOptions op; + #ifndef Z7_SFX + op.props = &options.Properties; + #endif + op.codecs = codecs; + op.types = &types2; + op.excludedFormats = &excludedFormats; + op.stdInMode = options.StdInMode; + op.stream = NULL; + op.filePath = arcPath; + + HRESULT result = arcLink.Open_Strict(op, openCallback); + + if (result == E_ABORT) + return result; + + // arcLink.Set_ErrorsText(); + RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result)) + + if (result != S_OK) + { + thereAreNotOpenArcs = true; + if (!options.StdInMode) + totalPackProcessed += fi.Size; + continue; + } + + #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) + if (options.ZoneMode != NExtract::NZoneIdMode::kNone + && !options.StdInMode) + { + ReadZoneFile_Of_BaseFile(us2fs(arcPath), ecs->ZoneBuf); + } + #endif + + + if (arcLink.Arcs.Size() != 0) + { + if (arcLink.GetArc()->IsHashHandler(op)) + { + if (!options.TestMode) + { + /* real Extracting to files is possible. + But user can think that hash archive contains real files. + So we block extracting here. */ + // v23.00 : we don't break process. + RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, E_NOTIMPL)) + thereAreNotOpenArcs = true; + if (!options.StdInMode) + totalPackProcessed += fi.Size; + continue; + // return E_NOTIMPL; // before v23 + } + FString dirPrefix = us2fs(options.HashDir); + if (dirPrefix.IsEmpty()) + { + if (!NFile::NDir::GetOnlyDirPrefix(us2fs(arcPath), dirPrefix)) + { + // return GetLastError_noZero_HRESULT(); + } + } + if (!dirPrefix.IsEmpty()) + NName::NormalizeDirPathPrefix(dirPrefix); + ecs->DirPathPrefix_for_HashFiles = dirPrefix; + } + } + + if (!options.StdInMode) + { + // numVolumes += arcLink.VolumePaths.Size(); + // arcLink.VolumesSize; + + // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes); + // numArcs = arcPaths.Size(); + if (arcLink.VolumePaths.Size() != 0) + { + Int64 correctionSize = (Int64)arcLink.VolumesSize; + FOR_VECTOR (v, arcLink.VolumePaths) + { + int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); + if (index >= 0) + { + if ((unsigned)index > i) + { + skipArcs[(unsigned)index] = true; + correctionSize -= arcSizes[(unsigned)index]; + } + } + } + if (correctionSize != 0) + { + Int64 newPackSize = (Int64)totalPackSize + correctionSize; + if (newPackSize < 0) + newPackSize = 0; + totalPackSize = (UInt64)newPackSize; + RINOK(faeCallback->SetTotal(totalPackSize)) + } + } + } + + /* + // Now openCallback and extractCallback use same object. So we don't need to send password. + + #ifndef Z7_NO_CRYPTO + bool passwordIsDefined; + UString password; + RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password)) + if (passwordIsDefined) + { + RINOK(extractCallback->SetPassword(password)) + } + #endif + */ + + CArc &arc = arcLink.Arcs.Back(); + arc.MTime.Def = !options.StdInMode + #ifdef _WIN32 + && !fi.IsDevice + #endif + ; + if (arc.MTime.Def) + arc.MTime.Set_From_FiTime(fi.MTime); + + UInt64 packProcessed; + const bool calcCrc = + #ifndef Z7_SFX + (hash != NULL); + #else + false; + #endif + + RINOK(DecompressArchive( + codecs, + arcLink, + fi.Size + arcLink.VolumesSize, + wildcardCensor, + options, + calcCrc, + extractCallback, faeCallback, ecs, + errorMessage, packProcessed)) + + if (!options.StdInMode) + packProcessed = fi.Size + arcLink.VolumesSize; + totalPackProcessed += packProcessed; + ecs->LocalProgressSpec->InSize += packProcessed; + ecs->LocalProgressSpec->OutSize = ecs->UnpackSize; + if (!errorMessage.IsEmpty()) + return E_FAIL; + } + + if (multi || thereAreNotOpenArcs) + { + RINOK(faeCallback->SetTotal(totalPackSize)) + RINOK(faeCallback->SetCompleted(&totalPackProcessed)) + } + + st.NumFolders = ecs->NumFolders; + st.NumFiles = ecs->NumFiles; + st.NumAltStreams = ecs->NumAltStreams; + st.UnpackSize = ecs->UnpackSize; + st.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize; + st.NumArchives = arcPaths.Size(); + st.PackSize = ecs->LocalProgressSpec->InSize; + return S_OK; +} diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h index bdacaba96..defaa2709 100644 --- a/CPP/7zip/UI/Common/Extract.h +++ b/CPP/7zip/UI/Common/Extract.h @@ -1,107 +1,107 @@ -// Extract.h - -#ifndef ZIP7_INC_EXTRACT_H -#define ZIP7_INC_EXTRACT_H - -#include "../../../Windows/FileFind.h" - -#include "../../Archive/IArchive.h" - -#include "ArchiveExtractCallback.h" -#include "ArchiveOpenCallback.h" -#include "ExtractMode.h" -#include "Property.h" - -#include "../Common/LoadCodecs.h" - -struct CExtractOptionsBase -{ - CBoolPair ElimDup; - - bool ExcludeDirItems; - bool ExcludeFileItems; - - bool PathMode_Force; - bool OverwriteMode_Force; - NExtract::NPathMode::EEnum PathMode; - NExtract::NOverwriteMode::EEnum OverwriteMode; - NExtract::NZoneIdMode::EEnum ZoneMode; - - CExtractNtOptions NtOptions; - - FString OutputDir; - UString HashDir; - - CExtractOptionsBase(): - ExcludeDirItems(false), - ExcludeFileItems(false), - PathMode_Force(false), - OverwriteMode_Force(false), - PathMode(NExtract::NPathMode::kFullPaths), - OverwriteMode(NExtract::NOverwriteMode::kAsk), - ZoneMode(NExtract::NZoneIdMode::kNone) - {} -}; - -struct CExtractOptions: public CExtractOptionsBase -{ - bool StdInMode; - bool StdOutMode; - bool YesToAll; - bool TestMode; - - // bool ShowDialog; - // bool PasswordEnabled; - // UString Password; - #ifndef Z7_SFX - CObjectVector Properties; - #endif - - /* - #ifdef Z7_EXTERNAL_CODECS - CCodecs *Codecs; - #endif - */ - - CExtractOptions(): - StdInMode(false), - StdOutMode(false), - YesToAll(false), - TestMode(false) - {} -}; - -struct CDecompressStat -{ - UInt64 NumArchives; - UInt64 UnpackSize; - UInt64 AltStreams_UnpackSize; - UInt64 PackSize; - UInt64 NumFolders; - UInt64 NumFiles; - UInt64 NumAltStreams; - - void Clear() - { - NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0; - } -}; - -HRESULT Extract( - // DECL_EXTERNAL_CODECS_LOC_VARS - CCodecs *codecs, - const CObjectVector &types, - const CIntVector &excludedFormats, - UStringVector &archivePaths, UStringVector &archivePathsFull, - const NWildcard::CCensorNode &wildcardCensor, - const CExtractOptions &options, - IOpenCallbackUI *openCallback, - IExtractCallbackUI *extractCallback, - IFolderArchiveExtractCallback *faeCallback, - #ifndef Z7_SFX - IHashCalc *hash, - #endif - UString &errorMessage, - CDecompressStat &st); - -#endif +// Extract.h + +#ifndef ZIP7_INC_EXTRACT_H +#define ZIP7_INC_EXTRACT_H + +#include "../../../Windows/FileFind.h" + +#include "../../Archive/IArchive.h" + +#include "ArchiveExtractCallback.h" +#include "ArchiveOpenCallback.h" +#include "ExtractMode.h" +#include "Property.h" + +#include "../Common/LoadCodecs.h" + +struct CExtractOptionsBase +{ + CBoolPair ElimDup; + + bool ExcludeDirItems; + bool ExcludeFileItems; + + bool PathMode_Force; + bool OverwriteMode_Force; + NExtract::NPathMode::EEnum PathMode; + NExtract::NOverwriteMode::EEnum OverwriteMode; + NExtract::NZoneIdMode::EEnum ZoneMode; + + CExtractNtOptions NtOptions; + + FString OutputDir; + UString HashDir; + + CExtractOptionsBase(): + ExcludeDirItems(false), + ExcludeFileItems(false), + PathMode_Force(false), + OverwriteMode_Force(false), + PathMode(NExtract::NPathMode::kFullPaths), + OverwriteMode(NExtract::NOverwriteMode::kAsk), + ZoneMode(NExtract::NZoneIdMode::kNone) + {} +}; + +struct CExtractOptions: public CExtractOptionsBase +{ + bool StdInMode; + bool StdOutMode; + bool YesToAll; + bool TestMode; + + // bool ShowDialog; + // bool PasswordEnabled; + // UString Password; + #ifndef Z7_SFX + CObjectVector Properties; + #endif + + /* + #ifdef Z7_EXTERNAL_CODECS + CCodecs *Codecs; + #endif + */ + + CExtractOptions(): + StdInMode(false), + StdOutMode(false), + YesToAll(false), + TestMode(false) + {} +}; + +struct CDecompressStat +{ + UInt64 NumArchives; + UInt64 UnpackSize; + UInt64 AltStreams_UnpackSize; + UInt64 PackSize; + UInt64 NumFolders; + UInt64 NumFiles; + UInt64 NumAltStreams; + + void Clear() + { + NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0; + } +}; + +HRESULT Extract( + // DECL_EXTERNAL_CODECS_LOC_VARS + CCodecs *codecs, + const CObjectVector &types, + const CIntVector &excludedFormats, + UStringVector &archivePaths, UStringVector &archivePathsFull, + const NWildcard::CCensorNode &wildcardCensor, + const CExtractOptions &options, + IOpenCallbackUI *openCallback, + IExtractCallbackUI *extractCallback, + IFolderArchiveExtractCallback *faeCallback, + #ifndef Z7_SFX + IHashCalc *hash, + #endif + UString &errorMessage, + CDecompressStat &st); + +#endif diff --git a/CPP/7zip/UI/Common/ExtractMode.h b/CPP/7zip/UI/Common/ExtractMode.h index f65549b25..6e38f2601 100644 --- a/CPP/7zip/UI/Common/ExtractMode.h +++ b/CPP/7zip/UI/Common/ExtractMode.h @@ -1,44 +1,44 @@ -// ExtractMode.h - -#ifndef ZIP7_INC_EXTRACT_MODE_H -#define ZIP7_INC_EXTRACT_MODE_H - -namespace NExtract { - -namespace NPathMode -{ - enum EEnum - { - kFullPaths, - kCurPaths, - kNoPaths, - kAbsPaths, - kNoPathsAlt // alt streams must be extracted without name of base file - }; -} - -namespace NOverwriteMode -{ - enum EEnum - { - kAsk, - kOverwrite, - kSkip, - kRename, - kRenameExisting - }; -} - -namespace NZoneIdMode -{ - enum EEnum - { - kNone, - kAll, - kOffice - }; -} - -} - -#endif +// ExtractMode.h + +#ifndef ZIP7_INC_EXTRACT_MODE_H +#define ZIP7_INC_EXTRACT_MODE_H + +namespace NExtract { + +namespace NPathMode +{ + enum EEnum + { + kFullPaths, + kCurPaths, + kNoPaths, + kAbsPaths, + kNoPathsAlt // alt streams must be extracted without name of base file + }; +} + +namespace NOverwriteMode +{ + enum EEnum + { + kAsk, + kOverwrite, + kSkip, + kRename, + kRenameExisting + }; +} + +namespace NZoneIdMode +{ + enum EEnum + { + kNone, + kAll, + kOffice + }; +} + +} + +#endif diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp index 57dd9c0b1..88da4ad36 100644 --- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp +++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -1,296 +1,296 @@ -// ExtractingFilePath.cpp - -#include "StdAfx.h" - -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileName.h" - -#include "ExtractingFilePath.h" - -extern -bool g_PathTrailReplaceMode; -bool g_PathTrailReplaceMode = - #ifdef _WIN32 - true - #else - false - #endif - ; - - -#ifdef _WIN32 -static void ReplaceIncorrectChars(UString &s) -{ - { - for (unsigned i = 0; i < s.Len(); i++) - { - wchar_t c = s[i]; - if ( - #ifdef _WIN32 - c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"' - || c == '/' - // || c == 0x202E // RLO - || - #endif - c == WCHAR_PATH_SEPARATOR) - { - #if WCHAR_PATH_SEPARATOR != L'/' - // 22.00 : WSL replacement for backslash - if (c == WCHAR_PATH_SEPARATOR) - c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; - else - #endif - c = '_'; - s.ReplaceOneCharAtPos(i, - c - // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters - ); - } - } - } - - if (g_PathTrailReplaceMode) - { - /* - // if (g_PathTrailReplaceMode == 1) - { - if (!s.IsEmpty()) - { - wchar_t c = s.Back(); - if (c == '.' || c == ' ') - { - // s += (wchar_t)(0x9c); // STRING TERMINATOR - s += (wchar_t)'_'; - } - } - } - else - */ - { - unsigned i; - for (i = s.Len(); i != 0;) - { - wchar_t c = s[i - 1]; - if (c != '.' && c != ' ') - break; - i--; - s.ReplaceOneCharAtPos(i, '_'); - // s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7)); - } - /* - if (g_PathTrailReplaceMode > 1 && i != s.Len()) - { - s.DeleteFrom(i); - } - */ - } - } -} -#endif - -/* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream. - But colon in postfix ":$DATA" is allowed. - WIN32 functions don't allow empty alt stream name "name:" */ - -void Correct_AltStream_Name(UString &s) -{ - unsigned len = s.Len(); - const unsigned kPostfixSize = 6; - if (s.Len() >= kPostfixSize - && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA")) - len -= kPostfixSize; - for (unsigned i = 0; i < len; i++) - { - wchar_t c = s[i]; - if (c == ':' || c == '\\' || c == '/' - || c == 0x202E // RLO - ) - s.ReplaceOneCharAtPos(i, '_'); - } - if (s.IsEmpty()) - s = '_'; -} - -#ifdef _WIN32 - -static const unsigned g_ReservedWithNum_Index = 4; - -static const char * const g_ReservedNames[] = -{ - "CON", "PRN", "AUX", "NUL", - "COM", "LPT" -}; - -static bool IsSupportedName(const UString &name) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ReservedNames); i++) - { - const char *reservedName = g_ReservedNames[i]; - unsigned len = MyStringLen(reservedName); - if (name.Len() < len) - continue; - if (!name.IsPrefixedBy_Ascii_NoCase(reservedName)) - continue; - if (i >= g_ReservedWithNum_Index) - { - wchar_t c = name[len]; - if (c < L'0' || c > L'9') - continue; - len++; - } - for (;;) - { - wchar_t c = name[len++]; - if (c == 0 || c == '.') - return false; - if (c != ' ') - break; - } - } - return true; -} - -static void CorrectUnsupportedName(UString &name) -{ - if (!IsSupportedName(name)) - name.InsertAtFront(L'_'); -} - -#endif - -static void Correct_PathPart(UString &s) -{ - // "." and ".." - if (s.IsEmpty()) - return; - - if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) - s.Empty(); - #ifdef _WIN32 - else - ReplaceIncorrectChars(s); - #endif -} - -// static const char * const k_EmptyReplaceName = "[]"; -static const char k_EmptyReplaceName = '_'; - -UString Get_Correct_FsFile_Name(const UString &name) -{ - UString res = name; - Correct_PathPart(res); - - #ifdef _WIN32 - CorrectUnsupportedName(res); - #endif - - if (res.IsEmpty()) - res = k_EmptyReplaceName; - return res; -} - - -void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir) -{ - unsigned i = 0; - - if (absIsAllowed) - { - #if defined(_WIN32) && !defined(UNDER_CE) - bool isDrive = false; - #endif - - if (parts[0].IsEmpty()) - { - i = 1; - #if defined(_WIN32) && !defined(UNDER_CE) - if (parts.Size() > 1 && parts[1].IsEmpty()) - { - i = 2; - if (parts.Size() > 2 && parts[2] == L"?") - { - i = 3; - if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) - { - isDrive = true; - i = 4; - } - } - } - #endif - } - #if defined(_WIN32) && !defined(UNDER_CE) - else if (NWindows::NFile::NName::IsDrivePath2(parts[0])) - { - isDrive = true; - i = 1; - } - - if (isDrive) - { - // we convert "c:name" to "c:\name", if absIsAllowed path. - UString &ds = parts[i - 1]; - if (ds.Len() > 2) - { - parts.Insert(i, ds.Ptr(2)); - ds.DeleteFrom(2); - } - } - #endif - } - - if (i != 0) - keepAndReplaceEmptyPrefixes = false; - - for (; i < parts.Size();) - { - UString &s = parts[i]; - - Correct_PathPart(s); - - if (s.IsEmpty()) - { - if (!keepAndReplaceEmptyPrefixes) - if (isDir || i != parts.Size() - 1) - { - parts.Delete(i); - continue; - } - s = k_EmptyReplaceName; - } - else - { - keepAndReplaceEmptyPrefixes = false; - #ifdef _WIN32 - CorrectUnsupportedName(s); - #endif - } - - i++; - } - - if (!isDir) - { - if (parts.IsEmpty()) - parts.Add((UString)k_EmptyReplaceName); - else - { - UString &s = parts.Back(); - if (s.IsEmpty()) - s = k_EmptyReplaceName; - } - } -} - -UString MakePathFromParts(const UStringVector &parts) -{ - UString s; - FOR_VECTOR (i, parts) - { - if (i != 0) - s.Add_PathSepar(); - s += parts[i]; - } - return s; -} +// ExtractingFilePath.cpp + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileName.h" + +#include "ExtractingFilePath.h" + +extern +bool g_PathTrailReplaceMode; +bool g_PathTrailReplaceMode = + #ifdef _WIN32 + true + #else + false + #endif + ; + + +#ifdef _WIN32 +static void ReplaceIncorrectChars(UString &s) +{ + { + for (unsigned i = 0; i < s.Len(); i++) + { + wchar_t c = s[i]; + if ( + #ifdef _WIN32 + c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"' + || c == '/' + // || c == 0x202E // RLO + || + #endif + c == WCHAR_PATH_SEPARATOR) + { + #if WCHAR_PATH_SEPARATOR != L'/' + // 22.00 : WSL replacement for backslash + if (c == WCHAR_PATH_SEPARATOR) + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; + else + #endif + c = '_'; + s.ReplaceOneCharAtPos(i, + c + // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters + ); + } + } + } + + if (g_PathTrailReplaceMode) + { + /* + // if (g_PathTrailReplaceMode == 1) + { + if (!s.IsEmpty()) + { + wchar_t c = s.Back(); + if (c == '.' || c == ' ') + { + // s += (wchar_t)(0x9c); // STRING TERMINATOR + s += (wchar_t)'_'; + } + } + } + else + */ + { + unsigned i; + for (i = s.Len(); i != 0;) + { + wchar_t c = s[i - 1]; + if (c != '.' && c != ' ') + break; + i--; + s.ReplaceOneCharAtPos(i, '_'); + // s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7)); + } + /* + if (g_PathTrailReplaceMode > 1 && i != s.Len()) + { + s.DeleteFrom(i); + } + */ + } + } +} +#endif + +/* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream. + But colon in postfix ":$DATA" is allowed. + WIN32 functions don't allow empty alt stream name "name:" */ + +void Correct_AltStream_Name(UString &s) +{ + unsigned len = s.Len(); + const unsigned kPostfixSize = 6; + if (s.Len() >= kPostfixSize + && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA")) + len -= kPostfixSize; + for (unsigned i = 0; i < len; i++) + { + wchar_t c = s[i]; + if (c == ':' || c == '\\' || c == '/' + || c == 0x202E // RLO + ) + s.ReplaceOneCharAtPos(i, '_'); + } + if (s.IsEmpty()) + s = '_'; +} + +#ifdef _WIN32 + +static const unsigned g_ReservedWithNum_Index = 4; + +static const char * const g_ReservedNames[] = +{ + "CON", "PRN", "AUX", "NUL", + "COM", "LPT" +}; + +static bool IsSupportedName(const UString &name) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ReservedNames); i++) + { + const char *reservedName = g_ReservedNames[i]; + unsigned len = MyStringLen(reservedName); + if (name.Len() < len) + continue; + if (!name.IsPrefixedBy_Ascii_NoCase(reservedName)) + continue; + if (i >= g_ReservedWithNum_Index) + { + wchar_t c = name[len]; + if (c < L'0' || c > L'9') + continue; + len++; + } + for (;;) + { + wchar_t c = name[len++]; + if (c == 0 || c == '.') + return false; + if (c != ' ') + break; + } + } + return true; +} + +static void CorrectUnsupportedName(UString &name) +{ + if (!IsSupportedName(name)) + name.InsertAtFront(L'_'); +} + +#endif + +static void Correct_PathPart(UString &s) +{ + // "." and ".." + if (s.IsEmpty()) + return; + + if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) + s.Empty(); + #ifdef _WIN32 + else + ReplaceIncorrectChars(s); + #endif +} + +// static const char * const k_EmptyReplaceName = "[]"; +static const char k_EmptyReplaceName = '_'; + +UString Get_Correct_FsFile_Name(const UString &name) +{ + UString res = name; + Correct_PathPart(res); + + #ifdef _WIN32 + CorrectUnsupportedName(res); + #endif + + if (res.IsEmpty()) + res = k_EmptyReplaceName; + return res; +} + + +void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir) +{ + unsigned i = 0; + + if (absIsAllowed) + { + #if defined(_WIN32) && !defined(UNDER_CE) + bool isDrive = false; + #endif + + if (parts[0].IsEmpty()) + { + i = 1; + #if defined(_WIN32) && !defined(UNDER_CE) + if (parts.Size() > 1 && parts[1].IsEmpty()) + { + i = 2; + if (parts.Size() > 2 && parts[2] == L"?") + { + i = 3; + if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) + { + isDrive = true; + i = 4; + } + } + } + #endif + } + #if defined(_WIN32) && !defined(UNDER_CE) + else if (NWindows::NFile::NName::IsDrivePath2(parts[0])) + { + isDrive = true; + i = 1; + } + + if (isDrive) + { + // we convert "c:name" to "c:\name", if absIsAllowed path. + UString &ds = parts[i - 1]; + if (ds.Len() > 2) + { + parts.Insert(i, ds.Ptr(2)); + ds.DeleteFrom(2); + } + } + #endif + } + + if (i != 0) + keepAndReplaceEmptyPrefixes = false; + + for (; i < parts.Size();) + { + UString &s = parts[i]; + + Correct_PathPart(s); + + if (s.IsEmpty()) + { + if (!keepAndReplaceEmptyPrefixes) + if (isDir || i != parts.Size() - 1) + { + parts.Delete(i); + continue; + } + s = k_EmptyReplaceName; + } + else + { + keepAndReplaceEmptyPrefixes = false; + #ifdef _WIN32 + CorrectUnsupportedName(s); + #endif + } + + i++; + } + + if (!isDir) + { + if (parts.IsEmpty()) + parts.Add((UString)k_EmptyReplaceName); + else + { + UString &s = parts.Back(); + if (s.IsEmpty()) + s = k_EmptyReplaceName; + } + } +} + +UString MakePathFromParts(const UStringVector &parts) +{ + UString s; + FOR_VECTOR (i, parts) + { + if (i != 0) + s.Add_PathSepar(); + s += parts[i]; + } + return s; +} diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.h b/CPP/7zip/UI/Common/ExtractingFilePath.h index e1f528f10..bb1732fc8 100644 --- a/CPP/7zip/UI/Common/ExtractingFilePath.h +++ b/CPP/7zip/UI/Common/ExtractingFilePath.h @@ -1,31 +1,31 @@ -// ExtractingFilePath.h - -#ifndef ZIP7_INC_EXTRACTING_FILE_PATH_H -#define ZIP7_INC_EXTRACTING_FILE_PATH_H - -#include "../../../Common/MyString.h" - -// #ifdef _WIN32 -void Correct_AltStream_Name(UString &s); -// #endif - -// replaces unsuported characters, and replaces "." , ".." and "" to "[]" -UString Get_Correct_FsFile_Name(const UString &name); - -/* - Correct_FsPath() corrects path parts to prepare it for File System operations. - It also corrects empty path parts like "\\\\": - - frontal empty path parts : it removes them or changes them to "_" - - another empty path parts : it removes them - if (absIsAllowed && path is absolute) : it removes empty path parts after start absolute path prefix marker - else - { - if (!keepAndReplaceEmptyPrefixes) : it removes empty path parts - if ( keepAndReplaceEmptyPrefixes) : it changes each empty frontal path part to "_" - } -*/ -void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir); - -UString MakePathFromParts(const UStringVector &parts); - -#endif +// ExtractingFilePath.h + +#ifndef ZIP7_INC_EXTRACTING_FILE_PATH_H +#define ZIP7_INC_EXTRACTING_FILE_PATH_H + +#include "../../../Common/MyString.h" + +// #ifdef _WIN32 +void Correct_AltStream_Name(UString &s); +// #endif + +// replaces unsuported characters, and replaces "." , ".." and "" to "[]" +UString Get_Correct_FsFile_Name(const UString &name); + +/* + Correct_FsPath() corrects path parts to prepare it for File System operations. + It also corrects empty path parts like "\\\\": + - frontal empty path parts : it removes them or changes them to "_" + - another empty path parts : it removes them + if (absIsAllowed && path is absolute) : it removes empty path parts after start absolute path prefix marker + else + { + if (!keepAndReplaceEmptyPrefixes) : it removes empty path parts + if ( keepAndReplaceEmptyPrefixes) : it changes each empty frontal path part to "_" + } +*/ +void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir); + +UString MakePathFromParts(const UStringVector &parts); + +#endif diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp index afa1a1e99..9caac3638 100644 --- a/CPP/7zip/UI/Common/HashCalc.cpp +++ b/CPP/7zip/UI/Common/HashCalc.cpp @@ -1,2096 +1,2120 @@ -// HashCalc.cpp - -#include "StdAfx.h" - -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/DynLimBuf.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringToInt.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamObjects.h" -#include "../../Common/StreamUtils.h" - -#include "../../Archive/Common/ItemNameUtils.h" -#include "../../Archive/IArchive.h" - -#include "EnumDirItems.h" -#include "HashCalc.h" - -using namespace NWindows; - -#ifdef Z7_EXTERNAL_CODECS -extern const CExternalCodecs *g_ExternalCodecs_Ptr; -#endif - -class CHashMidBuf -{ - void *_data; -public: - CHashMidBuf(): _data(NULL) {} - operator void *() { return _data; } - bool Alloc(size_t size) - { - if (_data) - return false; - _data = ::MidAlloc(size); - return _data != NULL; - } - ~CHashMidBuf() { ::MidFree(_data); } -}; - -static const char * const k_DefaultHashMethod = "CRC32"; - -HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods) -{ - UStringVector names = hashMethods; - if (names.IsEmpty()) - names.Add(UString(k_DefaultHashMethod)); - - CRecordVector ids; - CObjectVector methods; - - unsigned i; - for (i = 0; i < names.Size(); i++) - { - COneMethodInfo m; - RINOK(m.ParseMethodFromString(names[i])) - - if (m.MethodName.IsEmpty()) - m.MethodName = k_DefaultHashMethod; - - if (m.MethodName == "*") - { - CRecordVector tempMethods; - GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); - methods.Clear(); - ids.Clear(); - FOR_VECTOR (t, tempMethods) - { - unsigned index = ids.AddToUniqueSorted(tempMethods[t]); - if (ids.Size() != methods.Size()) - methods.Insert(index, m); - } - break; - } - else - { - // m.MethodName.RemoveChar(L'-'); - CMethodId id; - if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id)) - return E_NOTIMPL; - unsigned index = ids.AddToUniqueSorted(id); - if (ids.Size() != methods.Size()) - methods.Insert(index, m); - } - } - - for (i = 0; i < ids.Size(); i++) - { - CMyComPtr hasher; - AString name; - RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher)) - if (!hasher) - throw "Can't create hasher"; - const COneMethodInfo &m = methods[i]; - { - CMyComPtr scp; - hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); - if (scp) - RINOK(m.SetCoderProps(scp, NULL)) - } - const UInt32 digestSize = hasher->GetDigestSize(); - if (digestSize > k_HashCalc_DigestSize_Max) - return E_NOTIMPL; - CHasherState &h = Hashers.AddNew(); - h.DigestSize = digestSize; - h.Hasher = hasher; - h.Name = name; - for (unsigned k = 0; k < k_HashCalc_NumGroups; k++) - h.InitDigestGroup(k); - } - - return S_OK; -} - -void CHashBundle::InitForNewFile() -{ - CurSize = 0; - FOR_VECTOR (i, Hashers) - { - CHasherState &h = Hashers[i]; - h.Hasher->Init(); - h.InitDigestGroup(k_HashCalc_Index_Current); - } -} - -void CHashBundle::Update(const void *data, UInt32 size) -{ - CurSize += size; - FOR_VECTOR (i, Hashers) - Hashers[i].Hasher->Update(data, size); -} - -void CHashBundle::SetSize(UInt64 size) -{ - CurSize = size; -} - -static void AddDigests(Byte *dest, const Byte *src, UInt32 size) -{ - unsigned next = 0; - /* - // we could use big-endian addition for sha-1 and sha-256 - // but another hashers are little-endian - if (size > 8) - { - for (unsigned i = size; i != 0;) - { - i--; - next += (unsigned)dest[i] + (unsigned)src[i]; - dest[i] = (Byte)next; - next >>= 8; - } - } - else - */ - { - for (unsigned i = 0; i < size; i++) - { - next += (unsigned)dest[i] + (unsigned)src[i]; - dest[i] = (Byte)next; - next >>= 8; - } - } - - // we use little-endian to store extra bytes - dest += k_HashCalc_DigestSize_Max; - for (unsigned i = 0; i < k_HashCalc_ExtraSize; i++) - { - next += (unsigned)dest[i]; - dest[i] = (Byte)next; - next >>= 8; - } -} - -void CHasherState::AddDigest(unsigned groupIndex, const Byte *data) -{ - NumSums[groupIndex]++; - AddDigests(Digests[groupIndex], data, DigestSize); -} - -void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) -{ - if (isDir) - NumDirs++; - else if (isAltStream) - { - NumAltStreams++; - AltStreamsSize += CurSize; - } - else - { - NumFiles++; - FilesSize += CurSize; - } - - Byte pre[16]; - memset(pre, 0, sizeof(pre)); - if (isDir) - pre[0] = 1; - - FOR_VECTOR (i, Hashers) - { - CHasherState &h = Hashers[i]; - if (!isDir) - { - h.Hasher->Final(h.Digests[0]); // k_HashCalc_Index_Current - if (!isAltStream) - h.AddDigest(k_HashCalc_Index_DataSum, h.Digests[0]); - } - - h.Hasher->Init(); - h.Hasher->Update(pre, sizeof(pre)); - h.Hasher->Update(h.Digests[0], h.DigestSize); - - for (unsigned k = 0; k < path.Len(); k++) - { - wchar_t c = path[k]; - - // 21.04: we want same hash for linux and windows paths - #if CHAR_PATH_SEPARATOR != '/' - if (c == CHAR_PATH_SEPARATOR) - c = '/'; - // if (c == (wchar_t)('\\' + 0xf000)) c = '\\'; // to debug WSL - // if (c > 0xf000 && c < 0xf080) c -= 0xf000; // to debug WSL - #endif - - Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) }; - h.Hasher->Update(temp, 2); - } - - Byte tempDigest[k_HashCalc_DigestSize_Max]; - h.Hasher->Final(tempDigest); - if (!isAltStream) - h.AddDigest(k_HashCalc_Index_NamesSum, tempDigest); - h.AddDigest(k_HashCalc_Index_StreamsSum, tempDigest); - } -} - - -static void CSum_Name_OriginalToEscape(const AString &src, AString &dest) -{ - dest.Empty(); - for (unsigned i = 0; i < src.Len();) - { - char c = src[i++]; - if (c == '\n') - { - dest.Add_Char('\\'); - c = 'n'; - } - else if (c == '\\') - dest.Add_Char('\\'); - dest.Add_Char(c); - } -} - - -static bool CSum_Name_EscapeToOriginal(const char *s, AString &dest) -{ - bool isOK = true; - dest.Empty(); - for (;;) - { - char c = *s++; - if (c == 0) - break; - if (c == '\\') - { - const char c1 = *s; - if (c1 == 'n') - { - c = '\n'; - s++; - } - else if (c1 == '\\') - { - c = c1; - s++; - } - else - { - // original md5sum returns NULL for such bad strings - isOK = false; - } - } - dest.Add_Char(c); - } - return isOK; -} - - - -static void SetSpacesAndNul(char *s, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - s[i] = ' '; - s[num] = 0; -} - -static const unsigned kHashColumnWidth_Min = 4 * 2; - -static unsigned GetColumnWidth(unsigned digestSize) -{ - const unsigned width = digestSize * 2; - return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; -} - - -static void AddHashResultLine( - AString &_s, - // bool showHash, - // UInt64 fileSize, bool showSize, - const CObjectVector &hashers - // unsigned digestIndex, = k_HashCalc_Index_Current - ) -{ - FOR_VECTOR (i, hashers) - { - const CHasherState &h = hashers[i]; - char s[k_HashCalc_DigestSize_Max * 2 + 64]; - s[0] = 0; - // if (showHash) - HashHexToString(s, h.Digests[k_HashCalc_Index_Current], h.DigestSize); - const unsigned pos = (unsigned)strlen(s); - const int numSpaces = (int)GetColumnWidth(h.DigestSize) - (int)pos; - if (numSpaces > 0) - SetSpacesAndNul(s + pos, (unsigned)numSpaces); - if (i != 0) - _s.Add_Space(); - _s += s; - } - - /* - if (showSize) - { - _s.Add_Space(); - static const unsigned kSizeField_Len = 13; // same as in HashCon.cpp - char s[kSizeField_Len + 32]; - char *p = s; - SetSpacesAndNul(s, kSizeField_Len); - p = s + kSizeField_Len; - ConvertUInt64ToString(fileSize, p); - int numSpaces = (int)kSizeField_Len - (int)strlen(p); - if (numSpaces > 0) - p -= (unsigned)numSpaces; - _s += p; - } - */ -} - - -static void Add_LF(CDynLimBuf &hashFileString, const CHashOptionsLocal &options) -{ - hashFileString += (char)(options.HashMode_Zero.Val ? 0 : '\n'); -} - - - - -static void WriteLine(CDynLimBuf &hashFileString, - const CHashOptionsLocal &options, - const UString &path2, - bool isDir, - const AString &methodName, - const AString &hashesString) -{ - if (options.HashMode_OnlyHash.Val) - { - hashFileString += hashesString; - Add_LF(hashFileString, options); - return; - } - - UString path = path2; - - bool isBin = false; - const bool zeroMode = options.HashMode_Zero.Val; - const bool tagMode = options.HashMode_Tag.Val; - -#if CHAR_PATH_SEPARATOR != '/' - path.Replace(WCHAR_PATH_SEPARATOR, L'/'); - // path.Replace((wchar_t)('\\' + 0xf000), L'\\'); // to debug WSL -#endif - - AString utf8; - ConvertUnicodeToUTF8(path, utf8); - - AString esc; - CSum_Name_OriginalToEscape(utf8, esc); - - if (!zeroMode) - { - if (esc != utf8) - { - /* Original md5sum writes escape in that case. - We do same for compatibility with original md5sum. */ - hashFileString += '\\'; - } - } - - if (isDir && !esc.IsEmpty() && esc.Back() != '/') - esc.Add_Slash(); - - if (tagMode) - { - if (!methodName.IsEmpty()) - { - hashFileString += methodName; - hashFileString += ' '; - } - hashFileString += '('; - hashFileString += esc; - hashFileString += ')'; - hashFileString += " = "; - } - - hashFileString += hashesString; - - if (!tagMode) - { - hashFileString += ' '; - hashFileString += (char)(isBin ? '*' : ' '); - hashFileString += esc; - } - - Add_LF(hashFileString, options); -} - - - -static void WriteLine(CDynLimBuf &hashFileString, - const CHashOptionsLocal &options, - const UString &path, - bool isDir, - const CHashBundle &hb) -{ - AString methodName; - if (!hb.Hashers.IsEmpty()) - methodName = hb.Hashers[0].Name; - - AString hashesString; - AddHashResultLine(hashesString, hb.Hashers); - WriteLine(hashFileString, options, path, isDir, methodName, hashesString); -} - - -HRESULT HashCalc( - DECL_EXTERNAL_CODECS_LOC_VARS - const NWildcard::CCensor &censor, - const CHashOptions &options, - AString &errorInfo, - IHashCallbackUI *callback) -{ - CDirItems dirItems; - dirItems.Callback = callback; - - if (options.StdInMode) - { - CDirItem di; - if (!di.SetAs_StdInFile()) - return GetLastError_noZero_HRESULT(); - dirItems.Items.Add(di); - } - else - { - RINOK(callback->StartScanning()) - - dirItems.SymLinks = options.SymLinks.Val; - dirItems.ScanAltStreams = options.AltStreamsMode; - dirItems.ExcludeDirItems = censor.ExcludeDirItems; - dirItems.ExcludeFileItems = censor.ExcludeFileItems; - - dirItems.ShareForWrite = options.OpenShareForWrite; - - HRESULT res = EnumerateItems(censor, - options.PathMode, - UString(), - dirItems); - - if (res != S_OK) - { - if (res != E_ABORT) - errorInfo = "Scanning error"; - return res; - } - RINOK(callback->FinishScanning(dirItems.Stat)) - } - - unsigned i; - CHashBundle hb; - RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods)) - // hb.Init(); - - hb.NumErrors = dirItems.Stat.NumErrors; - - UInt64 totalSize = 0; - if (options.StdInMode) - { - RINOK(callback->SetNumFiles(1)) - } - else - { - totalSize = dirItems.Stat.GetTotalBytes(); - RINOK(callback->SetTotal(totalSize)) - } - - const UInt32 kBufSize = 1 << 15; - CHashMidBuf buf; - if (!buf.Alloc(kBufSize)) - return E_OUTOFMEMORY; - - UInt64 completeValue = 0; - - RINOK(callback->BeforeFirstFile(hb)) - - /* - CDynLimBuf hashFileString((size_t)1 << 31); - const bool needGenerate = !options.HashFilePath.IsEmpty(); - */ - - for (i = 0; i < dirItems.Items.Size(); i++) - { - CMyComPtr inStream; - UString path; - bool isDir = false; - bool isAltStream = false; - - if (options.StdInMode) - { -#if 1 - inStream = new CStdInFileStream; -#else - if (!CreateStdInStream(inStream)) - { - const DWORD lastError = ::GetLastError(); - const HRESULT res = callback->OpenFileError(FString("stdin"), lastError); - hb.NumErrors++; - if (res != S_FALSE && res != S_OK) - return res; - continue; - } -#endif - } - else - { - path = dirItems.GetLogPath(i); - const CDirItem &di = dirItems.Items[i]; - #ifdef _WIN32 - isAltStream = di.IsAltStream; - #endif - - #ifndef UNDER_CE - // if (di.AreReparseData()) - if (di.ReparseData.Size() != 0) - { - CBufInStream *inStreamSpec = new CBufInStream(); - inStream = inStreamSpec; - inStreamSpec->Init(di.ReparseData, di.ReparseData.Size()); - } - else - #endif - { - CInFileStream *inStreamSpec = new CInFileStream; - inStreamSpec->Set_PreserveATime(options.PreserveATime); - inStream = inStreamSpec; - isDir = di.IsDir(); - if (!isDir) - { - const FString phyPath = dirItems.GetPhyPath(i); - if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite)) - { - const HRESULT res = callback->OpenFileError(phyPath, ::GetLastError()); - hb.NumErrors++; - if (res != S_FALSE) - return res; - continue; - } - if (!options.StdInMode) - { - UInt64 curSize = 0; - if (inStreamSpec->GetSize(&curSize) == S_OK) - { - if (curSize > di.Size) - { - totalSize += curSize - di.Size; - RINOK(callback->SetTotal(totalSize)) - // printf("\ntotal = %d MiB\n", (unsigned)(totalSize >> 20)); - } - } - } - // inStreamSpec->ReloadProps(); - } - } - } - - RINOK(callback->GetStream(path, isDir)) - UInt64 fileSize = 0; - - hb.InitForNewFile(); - - if (!isDir) - { - for (UInt32 step = 0;; step++) - { - if ((step & 0xFF) == 0) - { - // printf("\ncompl = %d\n", (unsigned)(completeValue >> 20)); - RINOK(callback->SetCompleted(&completeValue)) - } - UInt32 size; - RINOK(inStream->Read(buf, kBufSize, &size)) - if (size == 0) - break; - hb.Update(buf, size); - fileSize += size; - completeValue += size; - } - } - - hb.Final(isDir, isAltStream, path); - - /* - if (needGenerate - && (options.HashMode_Dirs.Val || !isDir)) - { - WriteLine(hashFileString, - options, - path, // change it - isDir, - hb); - - if (hashFileString.IsError()) - return E_OUTOFMEMORY; - } - */ - - RINOK(callback->SetOperationResult(fileSize, hb, !isDir)) - RINOK(callback->SetCompleted(&completeValue)) - } - - /* - if (needGenerate) - { - NFile::NIO::COutFile file; - if (!file.Create(us2fs(options.HashFilePath), true)) // createAlways - return GetLastError_noZero_HRESULT(); - if (!file.WriteFull(hashFileString, hashFileString.Len())) - return GetLastError_noZero_HRESULT(); - } - */ - - return callback->AfterLastFile(hb); -} - - -void HashHexToString(char *dest, const Byte *data, size_t size) -{ - if (!data) - { - for (size_t i = 0; i < size; i++) - { - dest[0] = ' '; - dest[1] = ' '; - dest += 2; - } - *dest = 0; - return; - } - - if (size > 8) - ConvertDataToHex_Lower(dest, data, size); - else if (size == 0) - { - *dest = 0; - return; - } - else - { - const char *dest_start = dest; - dest += size * 2; - *dest = 0; - do - { - const size_t b = *data++; - dest -= 2; - dest[0] = GET_HEX_CHAR_UPPER(b >> 4); - dest[1] = GET_HEX_CHAR_UPPER(b & 15); - } - while (dest != dest_start); - } -} - -void CHasherState::WriteToString(unsigned digestIndex, char *s) const -{ - HashHexToString(s, Digests[digestIndex], DigestSize); - - if (digestIndex != 0 && NumSums[digestIndex] != 1) - { - unsigned numExtraBytes = GetNumExtraBytes_for_Group(digestIndex); - if (numExtraBytes > 4) - numExtraBytes = 8; - else // if (numExtraBytes >= 0) - numExtraBytes = 4; - // if (numExtraBytes != 0) - { - s += strlen(s); - *s++ = '-'; - // *s = 0; - HashHexToString(s, GetExtraData_for_Group(digestIndex), numExtraBytes); - } - } -} - - - -// ---------- Hash Handler ---------- - -namespace NHash { - -#define IsWhite(c) ((c) == ' ' || (c) == '\t') - -bool CHashPair::IsDir() const -{ - if (Name.IsEmpty() || Name.Back() != '/') - return false; - // here we expect that Dir items contain only zeros or no Hash - for (size_t i = 0; i < Hash.Size(); i++) - if (Hash.ConstData()[i] != 0) - return false; - return true; -} - - -bool CHashPair::ParseCksum(const char *s) -{ - const char *end; - - const UInt32 crc = ConvertStringToUInt32(s, &end); - if (*end != ' ') - return false; - end++; - - const UInt64 size = ConvertStringToUInt64(end, &end); - if (*end != ' ') - return false; - end++; - - Name = end; - - Hash.Alloc(4); - SetBe32(Hash, crc) - - Size_from_Arc = size; - Size_from_Arc_Defined = true; - - return true; -} - - - -static const char *SkipWhite(const char *s) -{ - while (IsWhite(*s)) - s++; - return s; -} - -static const char * const k_CsumMethodNames[] = -{ - "sha256" - , "sha224" -// , "sha512/224" -// , "sha512/256" - , "sha512" - , "sha384" - , "sha1" - , "md5" - , "blake2b" - , "crc64" - , "crc32" - , "cksum" -}; - -static UString GetMethod_from_FileName(const UString &name) -{ - AString s; - ConvertUnicodeToUTF8(name, s); - const int dotPos = s.ReverseFind_Dot(); - const char *src = s.Ptr(); - bool isExtension = false; - if (dotPos >= 0) - { - isExtension = true; - src = s.Ptr(dotPos + 1); - } - const char *m = ""; - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) - { - m = k_CsumMethodNames[i]; - if (isExtension) - { - if (StringsAreEqual_Ascii(src, m)) - break; - } - else if (IsString1PrefixedByString2_NoCase_Ascii(src, m)) - if (StringsAreEqual_Ascii(src + strlen(m), "sums")) - break; - } - UString res; - if (i != Z7_ARRAY_SIZE(k_CsumMethodNames)) - res = m; - return res; -} - - -bool CHashPair::Parse(const char *s) -{ - // here we keep compatibility with original md5sum / shasum - bool escape = false; - - s = SkipWhite(s); - - if (*s == '\\') - { - s++; - escape = true; - } - Escape = escape; - - // const char *kMethod = GetMethod_from_FileName(s); - // if (kMethod) - if ((size_t)(FindNonHexChar(s) - s) < 4) - { - // BSD-style checksum line - { - const char *s2 = s; - for (; *s2 != 0; s2++) - { - const char c = *s2; - if (c == 0) - return false; - if (c == ' ' || c == '(') - break; - } - Method.SetFrom(s, (unsigned)(s2 - s)); - s = s2; - } - IsBSD = true; - if (*s == ' ') - s++; - if (*s != '(') - return false; - s++; - { - const char *s2 = s; - for (; *s2 != 0; s2++) - {} - for (;;) - { - s2--; - if (s2 < s) - return false; - if (*s2 == ')') - break; - } - Name.SetFrom(s, (unsigned)(s2 - s)); - s = s2 + 1; - } - - s = SkipWhite(s); - if (*s != '=') - return false; - s++; - s = SkipWhite(s); - } - - { - const size_t numChars = (size_t)(FindNonHexChar(s) - s) & ~(size_t)1; - Hash.Alloc(numChars / 2); - if ((size_t)(ParseHexString(s, Hash) - Hash) != numChars / 2) - throw 101; - HashString.SetFrom(s, (unsigned)numChars); - s += numChars; - } - - if (IsBSD) - { - if (*s != 0) - return false; - if (escape) - { - const AString temp (Name); - return CSum_Name_EscapeToOriginal(temp, Name); - } - return true; - } - - if (*s == 0) - return true; - - if (*s != ' ') - return false; - s++; - const char c = *s; - if (c != ' ' - && c != '*' - && c != 'U' // shasum Universal - && c != '^' // shasum 0/1 - ) - return false; - Mode = c; - s++; - if (escape) - return CSum_Name_EscapeToOriginal(s, Name); - Name = s; - return true; -} - - -static bool GetLine(CByteBuffer &buf, bool zeroMode, bool cr_lf_Mode, size_t &posCur, AString &s) -{ - s.Empty(); - size_t pos = posCur; - const Byte *p = buf; - unsigned numDigits = 0; - for (; pos < buf.Size(); pos++) - { - const Byte b = p[pos]; - if (b == 0) - { - numDigits = 1; - break; - } - if (zeroMode) - continue; - if (b == 0x0a) - { - numDigits = 1; - break; - } - if (!cr_lf_Mode) - continue; - if (b == 0x0d) - { - if (pos + 1 >= buf.Size()) - { - numDigits = 1; - break; - // return false; - } - if (p[pos + 1] == 0x0a) - { - numDigits = 2; - break; - } - } - } - s.SetFrom((const char *)(p + posCur), (unsigned)(pos - posCur)); - posCur = pos + numDigits; - return true; -} - - -static bool Is_CR_LF_Data(const Byte *buf, size_t size) -{ - bool isCrLf = false; - for (size_t i = 0; i < size;) - { - const Byte b = buf[i]; - if (b == 0x0a) - return false; - if (b == 0x0d) - { - if (i == size - 1) - return false; - if (buf[i + 1] != 0x0a) - return false; - isCrLf = true; - i += 2; - } - else - i++; - } - return isCrLf; -} - - -static const Byte kArcProps[] = -{ - // kpidComment, - kpidCharacts -}; - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidPackSize, - kpidMethod -}; - -static const Byte kRawProps[] = -{ - kpidChecksum -}; - - -Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */ , UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = Z7_ARRAY_SIZE(kRawProps); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) -{ - *propID = kRawProps[index]; - *name = NULL; - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (propID == kpidChecksum) - { - const CHashPair &hp = HashPairs[index]; - if (hp.Hash.Size() > 0) - { - *data = hp.Hash; - *dataSize = (UInt32)hp.Hash.Size(); - *propType = NPropDataType::kRaw; - } - return S_OK; - } - - return S_OK; -} - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = HashPairs.Size(); - return S_OK; -} - -static void Add_OptSpace_String(UString &dest, const char *src) -{ - dest.Add_Space_if_NotEmpty(); - dest += src; -} - -Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidPhySize: if (_phySize != 0) prop = _phySize; break; - /* - case kpidErrorFlags: - { - UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; - // if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; - if (v != 0) - prop = v; - break; - } - */ - case kpidCharacts: - { - UString s; - if (_hashSize_Defined) - { - s.Add_Space_if_NotEmpty(); - s.Add_UInt32(_hashSize * 8); - s += "-bit"; - } - if (!_nameExtenstion.IsEmpty()) - { - s.Add_Space_if_NotEmpty(); - s += _nameExtenstion; - } - if (_is_PgpMethod) - { - Add_OptSpace_String(s, "PGP"); - if (!_pgpMethod.IsEmpty()) - { - s.Add_Colon(); - s += _pgpMethod; - } - } - if (_is_ZeroMode) - Add_OptSpace_String(s, "ZERO"); - if (_are_there_Tags) - Add_OptSpace_String(s, "TAG"); - if (_are_there_Dirs) - Add_OptSpace_String(s, "DIRS"); - prop = s; - break; - } - - case kpidReadOnly: - { - if (_isArc) - if (!CanUpdate()) - prop = true; - break; - } - default: break; - } - prop.Detach(value); - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - // COM_TRY_BEGIN - NCOM::CPropVariant prop; - const CHashPair &hp = HashPairs[index]; - switch (propID) - { - case kpidIsDir: - { - prop = hp.IsDir(); - break; - } - case kpidPath: - { - UString path; - hp.Get_UString_Path(path); - - bool useBackslashReplacement = true; - if (_supportWindowsBackslash && !hp.Escape && path.Find(L"\\\\") < 0) - { -#if WCHAR_PATH_SEPARATOR == L'/' - path.Replace(L'\\', L'/'); -#else - useBackslashReplacement = false; -#endif - } - NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash( - path, useBackslashReplacement); - prop = path; - break; - } - case kpidSize: - { - // client needs processed size of last file - if (hp.Size_from_Disk_Defined) - prop = (UInt64)hp.Size_from_Disk; - else if (hp.Size_from_Arc_Defined) - prop = (UInt64)hp.Size_from_Arc; - break; - } - case kpidPackSize: - { - prop = (UInt64)hp.Hash.Size(); - break; - } - case kpidMethod: - { - if (!hp.Method.IsEmpty()) - prop = hp.Method; - break; - } - default: break; - } - prop.Detach(value); - return S_OK; - // COM_TRY_END -} - - -static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOpenCallback *openCallback) -{ - buf.Free(); - UInt64 len; - RINOK(InStream_AtBegin_GetSize(stream, len)) - if (len == 0 || len >= ((UInt64)1 << 31)) - return S_FALSE; - buf.Alloc((size_t)len); - UInt64 pos = 0; - // return ReadStream_FALSE(stream, buf, (size_t)len); - for (;;) - { - const UInt32 kBlockSize = ((UInt32)1 << 24); - const UInt32 curSize = (len < kBlockSize) ? (UInt32)len : kBlockSize; - UInt32 processedSizeLoc; - RINOK(stream->Read((Byte *)buf + pos, curSize, &processedSizeLoc)) - if (processedSizeLoc == 0) - return E_FAIL; - len -= processedSizeLoc; - pos += processedSizeLoc; - if (len == 0) - return S_OK; - if (openCallback) - { - const UInt64 files = 0; - RINOK(openCallback->SetCompleted(&files, &pos)) - } - } -} - - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) -{ - COM_TRY_BEGIN - { - Close(); - - CByteBuffer buf; - RINOK(ReadStream_to_Buf(stream, buf, openCallback)) - - CObjectVector &pairs = HashPairs; - - bool zeroMode = false; - bool cr_lf_Mode = false; - { - for (size_t i = 0; i < buf.Size(); i++) - if (buf.ConstData()[i] == 0) - { - zeroMode = true; - break; - } - } - _is_ZeroMode = zeroMode; - if (!zeroMode) - cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); - - if (openCallback) - { - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpenVolumeCallback, - openVolumeCallback, openCallback) - if (openVolumeCallback) - { - NCOM::CPropVariant prop; - RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) - if (prop.vt == VT_BSTR) - _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); - } - } - - bool cksumMode = false; - if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) - cksumMode = true; - _is_CksumMode = cksumMode; - - size_t pos = 0; - AString s; - bool minusMode = false; - unsigned numLines = 0; - - while (pos < buf.Size()) - { - if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s)) - return S_FALSE; - numLines++; - if (s.IsEmpty()) - continue; - - if (s.IsPrefixedBy_Ascii_NoCase("; ")) - { - if (numLines != 1) - return S_FALSE; - // comment line of FileVerifier++ - continue; - } - - if (s.IsPrefixedBy_Ascii_NoCase("-----")) - { - if (minusMode) - break; // end of pgp mode - minusMode = true; - if (s.IsPrefixedBy_Ascii_NoCase("-----BEGIN PGP SIGNED MESSAGE")) - { - if (_is_PgpMethod) - return S_FALSE; - if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s)) - return S_FALSE; - const char *kStart = "Hash: "; - if (!s.IsPrefixedBy_Ascii_NoCase(kStart)) - return S_FALSE; - _pgpMethod = s.Ptr((unsigned)strlen(kStart)); - _is_PgpMethod = true; - } - continue; - } - - CHashPair pair; - pair.FullLine = s; - if (cksumMode) - { - if (!pair.ParseCksum(s)) - return S_FALSE; - } - else if (!pair.Parse(s)) - return S_FALSE; - pairs.Add(pair); - } - - { - unsigned hashSize = 0; - bool hashSize_Dismatch = false; - for (unsigned i = 0; i < HashPairs.Size(); i++) - { - const CHashPair &hp = HashPairs[i]; - if (i == 0) - hashSize = (unsigned)hp.Hash.Size(); - else - if (hashSize != hp.Hash.Size()) - hashSize_Dismatch = true; - - if (hp.IsBSD) - _are_there_Tags = true; - if (!_are_there_Dirs && hp.IsDir()) - _are_there_Dirs = true; - } - if (!hashSize_Dismatch && hashSize != 0) - { - _hashSize = hashSize; - _hashSize_Defined = true; - } - } - - _phySize = buf.Size(); - _isArc = true; - return S_OK; - } - COM_TRY_END -} - - -void CHandler::ClearVars() -{ - _phySize = 0; - _isArc = false; - _is_CksumMode = false; - _is_PgpMethod = false; - _is_ZeroMode = false; - _are_there_Tags = false; - _are_there_Dirs = false; - _hashSize_Defined = false; - _hashSize = 0; -} - - -Z7_COM7F_IMF(CHandler::Close()) -{ - ClearVars(); - _nameExtenstion.Empty(); - _pgpMethod.Empty(); - HashPairs.Clear(); - return S_OK; -} - - -static bool CheckDigests(const Byte *a, const Byte *b, size_t size) -{ - if (size <= 8) - { - /* we use reversed order for one digest, when text representation - uses big-order for crc-32 and crc-64 */ - for (size_t i = 0; i < size; i++) - if (a[i] != b[size - 1 - i]) - return false; - return true; - } - { - for (size_t i = 0; i < size; i++) - if (a[i] != b[i]) - return false; - return true; - } -} - - -static void AddDefaultMethod(UStringVector &methods, unsigned size) -{ - const char *m = NULL; - if (size == 32) m = "sha256"; - else if (size == 20) m = "sha1"; - else if (size == 16) m = "md5"; - else if (size == 8) m = "crc64"; - else if (size == 4) m = "crc32"; - else - return; - #ifdef Z7_EXTERNAL_CODECS - const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; - #endif - CMethodId id; - if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS - AString(m), id)) - methods.Add(UString(m)); -} - - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - - /* - if (testMode == 0) - return E_NOTIMPL; - */ - - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = HashPairs.Size(); - if (numItems == 0) - return S_OK; - - #ifdef Z7_EXTERNAL_CODECS - const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; - #endif - - CHashBundle hb_Glob; - // UStringVector methods = options.Methods; - UStringVector methods; - - if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) - { - AString utf; - ConvertUnicodeToUTF8(_nameExtenstion, utf); - CMethodId id; - if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) - methods.Add(_nameExtenstion); - } - - if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) - { - CMethodId id; - if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS _pgpMethod, id)) - methods.Add(UString(_pgpMethod)); - } - - if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) - AddDefaultMethod(methods, _hashSize); - - RINOK(hb_Glob.SetMethods( - EXTERNAL_CODECS_LOC_VARS - methods)) - - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveUpdateCallbackFile, - updateCallbackFile, extractCallback) - if (!updateCallbackFile) - return E_NOTIMPL; - { - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveGetDiskProperty, - GetDiskProperty, extractCallback) - if (GetDiskProperty) - { - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = allFilesMode ? i : indices[i]; - const CHashPair &hp = HashPairs[index]; - if (hp.IsDir()) - continue; - { - NCOM::CPropVariant prop; - RINOK(GetDiskProperty->GetDiskProperty(index, kpidSize, &prop)) - if (prop.vt != VT_UI8) - continue; - totalSize += prop.uhVal.QuadPart; - } - } - RINOK(extractCallback->SetTotal(totalSize)) - // RINOK(Hash_SetTotalUnpacked->Hash_SetTotalUnpacked(indices, numItems)); - } - } - - const UInt32 kBufSize = 1 << 15; - CHashMidBuf buf; - if (!buf.Alloc(kBufSize)) - return E_OUTOFMEMORY; - - CMyComPtr2_Create lps; - lps->Init(extractCallback, false); - - for (UInt32 i = 0;; i++) - { - RINOK(lps->SetCur()) - if (i >= numItems) - break; - const UInt32 index = allFilesMode ? i : indices[i]; - - CHashPair &hp = HashPairs[index]; - - UString path; - hp.Get_UString_Path(path); - - CMyComPtr inStream; - const bool isDir = hp.IsDir(); - if (!isDir) - { - RINOK(updateCallbackFile->GetStream2(index, &inStream, NUpdateNotifyOp::kHashRead)) - if (!inStream) - { - continue; // we have shown error in GetStream2() - } - // askMode = NArchive::NExtract::NAskMode::kSkip; - } - - Int32 askMode = testMode ? - NArchive::NExtract::NAskMode::kTest : - NArchive::NExtract::NAskMode::kExtract; - - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - - /* PrepareOperation() can expect kExtract to set - Attrib and security of output file */ - askMode = NArchive::NExtract::NAskMode::kReadExternal; - - RINOK(extractCallback->PrepareOperation(askMode)) - - const bool isAltStream = false; - - UInt64 fileSize = 0; - - CHashBundle hb_Loc; - - CHashBundle *hb_Use = &hb_Glob; - - HRESULT res_SetMethods = S_OK; - - UStringVector methods_loc; - - if (!hp.Method.IsEmpty()) - { - hb_Use = &hb_Loc; - CMethodId id; - if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id)) - { - methods_loc.Add(UString(hp.Method)); - RINOK(hb_Loc.SetMethods( - EXTERNAL_CODECS_LOC_VARS - methods_loc)) - } - else - res_SetMethods = E_NOTIMPL; - } - else if (methods.IsEmpty()) - { - AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size()); - if (!methods_loc.IsEmpty()) - { - hb_Use = &hb_Loc; - RINOK(hb_Loc.SetMethods( - EXTERNAL_CODECS_LOC_VARS - methods_loc)) - } - } - - const bool isSupportedMode = hp.IsSupportedMode(); - hb_Use->InitForNewFile(); - - if (inStream) - { - for (UInt32 step = 0;; step++) - { - if ((step & 0xFF) == 0) - { - RINOK(lps.Interface()->SetRatioInfo(NULL, &fileSize)) - } - UInt32 size; - RINOK(inStream->Read(buf, kBufSize, &size)) - if (size == 0) - break; - hb_Use->Update(buf, size); - if (realOutStream) - { - RINOK(WriteStream(realOutStream, buf, size)) - } - fileSize += size; - } - - hp.Size_from_Disk = fileSize; - hp.Size_from_Disk_Defined = true; - } - - realOutStream.Release(); - inStream.Release(); - - lps->InSize += hp.Hash.Size(); - lps->OutSize += fileSize; - - hb_Use->Final(isDir, isAltStream, path); - - Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; - if (isSupportedMode - && res_SetMethods != E_NOTIMPL - && hb_Use->Hashers.Size() > 0 - ) - { - const CHasherState &hs = hb_Use->Hashers[0]; - if (hs.DigestSize == hp.Hash.Size()) - { - opRes = NArchive::NExtract::NOperationResult::kCRCError; - if (CheckDigests(hp.Hash, hs.Digests[0], hs.DigestSize)) - if (!hp.Size_from_Arc_Defined || hp.Size_from_Arc == fileSize) - opRes = NArchive::NExtract::NOperationResult::kOK; - } - } - - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - COM_TRY_END -} - - -// ---------- UPDATE ---------- - -struct CUpdateItem -{ - int IndexInArc; - unsigned IndexInClient; - UInt64 Size; - bool NewData; - bool NewProps; - bool IsDir; - UString Path; - - CUpdateItem(): Size(0), IsDir(false) {} -}; - - -static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, - UString &res, - bool convertSlash) -{ - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(index, propId, &prop)) - if (prop.vt == VT_BSTR) - { - res = prop.bstrVal; - if (convertSlash) - NArchive::NItemName::ReplaceSlashes_OsToUnix(res); - } - else if (prop.vt != VT_EMPTY) - return E_INVALIDARG; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) -{ - *type = NFileTimeType::kUnix; - return S_OK; -} - - -Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, - IArchiveUpdateCallback *callback)) -{ - COM_TRY_BEGIN - - if (_isArc && !CanUpdate()) - return E_NOTIMPL; - - /* - Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, - reportArcProp, callback) - */ - - CObjectVector updateItems; - - UInt64 complexity = 0; - - UInt32 i; - for (i = 0; i < numItems; i++) - { - CUpdateItem ui; - Int32 newData; - Int32 newProps; - UInt32 indexInArc; - - if (!callback) - return E_FAIL; - - RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)) - - ui.NewProps = IntToBool(newProps); - ui.NewData = IntToBool(newData); - ui.IndexInArc = (int)indexInArc; - ui.IndexInClient = i; - if (IntToBool(newProps)) - { - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidIsDir, &prop)) - if (prop.vt == VT_EMPTY) - ui.IsDir = false; - else if (prop.vt != VT_BOOL) - return E_INVALIDARG; - else - ui.IsDir = (prop.boolVal != VARIANT_FALSE); - } - - RINOK(GetPropString(callback, i, kpidPath, ui.Path, - true)) // convertSlash - /* - if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') - ui.Name += '/'; - */ - } - - if (IntToBool(newData)) - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidSize, &prop)) - if (prop.vt == VT_UI8) - { - ui.Size = prop.uhVal.QuadPart; - complexity += ui.Size; - } - else if (prop.vt == VT_EMPTY) - ui.Size = (UInt64)(Int64)-1; - else - return E_INVALIDARG; - } - - updateItems.Add(ui); - } - - if (complexity != 0) - { - RINOK(callback->SetTotal(complexity)) - } - - #ifdef Z7_EXTERNAL_CODECS - const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; - #endif - - CHashBundle hb; - UStringVector methods; - if (!_methods.IsEmpty()) - { - FOR_VECTOR(k, _methods) - { - methods.Add(_methods[k]); - } - } - else if (_crcSize_WasSet) - { - AddDefaultMethod(methods, _crcSize); - } - else - { - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveGetRootProps, - getRootProps, callback) - if (getRootProps) - { - NCOM::CPropVariant prop; - RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) - if (prop.vt == VT_BSTR) - { - const UString method = GetMethod_from_FileName(prop.bstrVal); - if (!method.IsEmpty()) - methods.Add(method); - } - } - } - - RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) - - CMyComPtr2_Create lps; - lps->Init(callback, true); - - const UInt32 kBufSize = 1 << 15; - CHashMidBuf buf; - if (!buf.Alloc(kBufSize)) - return E_OUTOFMEMORY; - - CDynLimBuf hashFileString((size_t)1 << 31); - - CHashOptionsLocal options = _options; - - if (_isArc) - { - if (!options.HashMode_Zero.Def && _is_ZeroMode) - options.HashMode_Zero.Val = true; - if (!options.HashMode_Tag.Def && _are_there_Tags) - options.HashMode_Tag.Val = true; - if (!options.HashMode_Dirs.Def && _are_there_Dirs) - options.HashMode_Dirs.Val = true; - } - if (options.HashMode_OnlyHash.Val && updateItems.Size() != 1) - options.HashMode_OnlyHash.Val = false; - - complexity = 0; - - for (i = 0; i < updateItems.Size(); i++) - { - lps->InSize = complexity; - RINOK(lps->SetCur()) - - const CUpdateItem &ui = updateItems[i]; - - /* - CHashPair item; - if (!ui.NewProps) - item = HashPairs[(unsigned)ui.IndexInArc]; - */ - - if (ui.NewData) - { - UInt64 currentComplexity = ui.Size; - UInt64 fileSize = 0; - - CMyComPtr fileInStream; - bool needWrite = true; - { - HRESULT res = callback->GetStream(ui.IndexInClient, &fileInStream); - - if (res == S_FALSE) - needWrite = false; - else - { - RINOK(res) - - if (fileInStream) - { - Z7_DECL_CMyComPtr_QI_FROM( - IStreamGetSize, - streamGetSize, fileInStream) - if (streamGetSize) - { - UInt64 size; - if (streamGetSize->GetSize(&size) == S_OK) - currentComplexity = size; - } - /* - Z7_DECL_CMyComPtr_QI_FROM( - IStreamGetProps, - getProps, fileInStream) - if (getProps) - { - FILETIME mTime; - UInt64 size2; - if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) - { - currentComplexity = size2; - // item.MTime = NTime::FileTimeToUnixTime64(mTime);; - } - } - */ - } - else - { - currentComplexity = 0; - } - } - } - - hb.InitForNewFile(); - const bool isDir = ui.IsDir; - - if (needWrite && fileInStream && !isDir) - { - for (UInt32 step = 0;; step++) - { - if ((step & 0xFF) == 0) - { - RINOK(lps.Interface()->SetRatioInfo(&fileSize, NULL)) - // RINOK(callback->SetCompleted(&completeValue)); - } - UInt32 size; - RINOK(fileInStream->Read(buf, kBufSize, &size)) - if (size == 0) - break; - hb.Update(buf, size); - fileSize += size; - } - currentComplexity = fileSize; - } - - fileInStream.Release(); - const bool isAltStream = false; - hb.Final(isDir, isAltStream, ui.Path); - - if (options.HashMode_Dirs.Val || !isDir) - { - if (!hb.Hashers.IsEmpty()) - lps->OutSize += hb.Hashers[0].DigestSize; - WriteLine(hashFileString, - options, - ui.Path, - isDir, - hb); - if (hashFileString.IsError()) - return E_OUTOFMEMORY; - } - - complexity += currentComplexity; - - /* - if (reportArcProp) - { - PROPVARIANT prop; - prop.vt = VT_EMPTY; - prop.wReserved1 = 0; - - NCOM::PropVarEm_Set_UInt64(&prop, fileSize); - RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidSize, &prop)); - - for (unsigned k = 0; k < hb.Hashers.Size(); k++) - { - const CHasherState &hs = hb.Hashers[k]; - - if (hs.DigestSize == 4 && hs.Name.IsEqualTo_Ascii_NoCase("crc32")) - { - NCOM::PropVarEm_Set_UInt32(&prop, GetUi32(hs.Digests[k_HashCalc_Index_Current])); - RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidCRC, &prop)); - } - else - { - RINOK(reportArcProp->ReportRawProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, - kpidChecksum, hs.Digests[k_HashCalc_Index_Current], - hs.DigestSize, NPropDataType::kRaw)); - } - RINOK(reportArcProp->ReportFinished(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, NArchive::NUpdate::NOperationResult::kOK)); - } - } - */ - RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) - } - else - { - // old data - const CHashPair &existItem = HashPairs[(unsigned)ui.IndexInArc]; - if (ui.NewProps) - { - WriteLine(hashFileString, - options, - ui.Path, - ui.IsDir, - existItem.Method, existItem.HashString - ); - } - else - { - hashFileString += existItem.FullLine; - Add_LF(hashFileString, options); - } - } - if (hashFileString.IsError()) - return E_OUTOFMEMORY; - } - - RINOK(WriteStream(outStream, hashFileString, hashFileString.Len())) - - return S_OK; - COM_TRY_END -} - - - -HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) -{ - UString name = nameSpec; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - - if (name.IsEqualTo("m")) // "hm" hash method - { - // COneMethodInfo omi; - // RINOK(omi.ParseMethodFromPROPVARIANT(L"", value)); - // _methods.Add(omi.MethodName); // change it. use omi.PropsString - if (value.vt != VT_BSTR) - return E_INVALIDARG; - UString s (value.bstrVal); - _methods.Add(s); - return S_OK; - } - - if (name.IsEqualTo("flags")) - { - if (value.vt != VT_BSTR) - return E_INVALIDARG; - if (!_options.ParseString(value.bstrVal)) - return E_INVALIDARG; - return S_OK; - } - - if (name.IsEqualTo("backslash")) - return PROPVARIANT_to_bool(value, _supportWindowsBackslash); - - if (name.IsPrefixedBy_Ascii_NoCase("crc")) - { - name.Delete(0, 3); - _crcSize = 4; - _crcSize_WasSet = true; - return ParsePropToUInt32(name, value, _crcSize); - } - - // common properties - if (name.IsPrefixedBy_Ascii_NoCase("mt") - || name.IsPrefixedBy_Ascii_NoCase("memuse")) - return S_OK; - - return E_INVALIDARG; -} - - -Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) -{ - COM_TRY_BEGIN - - InitProps(); - - for (UInt32 i = 0; i < numProps; i++) - { - RINOK(SetProperty(names[i], values[i])) - } - return S_OK; - COM_TRY_END -} - -CHandler::CHandler() -{ - ClearVars(); - InitProps(); -} - -} - - - -static IInArchive *CreateHashHandler_In() { return new NHash::CHandler; } -static IOutArchive *CreateHashHandler_Out() { return new NHash::CHandler; } - -void Codecs_AddHashArcHandler(CCodecs *codecs) -{ - { - CArcInfoEx item; - - item.Name = "Hash"; - item.CreateInArchive = CreateHashHandler_In; - item.CreateOutArchive = CreateHashHandler_Out; - item.IsArcFunc = NULL; - item.Flags = - NArcInfoFlags::kKeepName - | NArcInfoFlags::kStartOpen - | NArcInfoFlags::kByExtOnlyOpen - // | NArcInfoFlags::kPureStartOpen - | NArcInfoFlags::kHashHandler - ; - - // ubuntu uses "SHA256SUMS" file - item.AddExts(UString ( - "sha256 sha512 sha224 sha384 sha1 sha md5" - // "b2sum" - " crc32 crc64" - " asc" - " cksum" - ), - UString()); - - item.UpdateEnabled = (item.CreateOutArchive != NULL); - item.SignatureOffset = 0; - // item.Version = MY_VER_MIX; - item.NewInterface = true; - - item.Signatures.AddNew().CopyFrom(NULL, 0); - - codecs->Formats.Add(item); - } -} +// HashCalc.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/DynLimBuf.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" + +#include "../../Archive/Common/ItemNameUtils.h" +#include "../../Archive/IArchive.h" + +#include "EnumDirItems.h" +#include "HashCalc.h" + +using namespace NWindows; + +#ifdef Z7_EXTERNAL_CODECS +extern const CExternalCodecs *g_ExternalCodecs_Ptr; +#endif + +class CHashMidBuf +{ + void *_data; +public: + CHashMidBuf(): _data(NULL) {} + operator void *() { return _data; } + bool Alloc(size_t size) + { + if (_data) + return false; + _data = ::MidAlloc(size); + return _data != NULL; + } + ~CHashMidBuf() { ::MidFree(_data); } +}; + +static const char * const k_DefaultHashMethod = "CRC32"; + +HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods) +{ + UStringVector names = hashMethods; + if (names.IsEmpty()) + names.Add(UString(k_DefaultHashMethod)); + + CRecordVector ids; + CObjectVector methods; + + unsigned i; + for (i = 0; i < names.Size(); i++) + { + COneMethodInfo m; + RINOK(m.ParseMethodFromString(names[i])) + + if (m.MethodName.IsEmpty()) + m.MethodName = k_DefaultHashMethod; + + if (m.MethodName == "*") + { + CRecordVector tempMethods; + GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); + methods.Clear(); + ids.Clear(); + FOR_VECTOR (t, tempMethods) + { + unsigned index = ids.AddToUniqueSorted(tempMethods[t]); + if (ids.Size() != methods.Size()) + methods.Insert(index, m); + } + break; + } + else + { + // m.MethodName.RemoveChar(L'-'); + CMethodId id; + if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id)) + return E_NOTIMPL; + unsigned index = ids.AddToUniqueSorted(id); + if (ids.Size() != methods.Size()) + methods.Insert(index, m); + } + } + + for (i = 0; i < ids.Size(); i++) + { + CMyComPtr hasher; + AString name; + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher)) + if (!hasher) + throw "Can't create hasher"; + const COneMethodInfo &m = methods[i]; + { + CMyComPtr scp; + hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); + if (scp) + RINOK(m.SetCoderProps(scp, NULL)) + } + const UInt32 digestSize = hasher->GetDigestSize(); + if (digestSize > k_HashCalc_DigestSize_Max) + return E_NOTIMPL; + CHasherState &h = Hashers.AddNew(); + h.DigestSize = digestSize; + h.Hasher = hasher; + h.Name = name; + for (unsigned k = 0; k < k_HashCalc_NumGroups; k++) + h.InitDigestGroup(k); + } + + return S_OK; +} + +void CHashBundle::InitForNewFile() +{ + CurSize = 0; + FOR_VECTOR (i, Hashers) + { + CHasherState &h = Hashers[i]; + h.Hasher->Init(); + h.InitDigestGroup(k_HashCalc_Index_Current); + } +} + +void CHashBundle::Update(const void *data, UInt32 size) +{ + CurSize += size; + FOR_VECTOR (i, Hashers) + Hashers[i].Hasher->Update(data, size); +} + +void CHashBundle::SetSize(UInt64 size) +{ + CurSize = size; +} + +static void AddDigests(Byte *dest, const Byte *src, UInt32 size) +{ + unsigned next = 0; + /* + // we could use big-endian addition for sha-1 and sha-256 + // but another hashers are little-endian + if (size > 8) + { + for (unsigned i = size; i != 0;) + { + i--; + next += (unsigned)dest[i] + (unsigned)src[i]; + dest[i] = (Byte)next; + next >>= 8; + } + } + else + */ + { + for (unsigned i = 0; i < size; i++) + { + next += (unsigned)dest[i] + (unsigned)src[i]; + dest[i] = (Byte)next; + next >>= 8; + } + } + + // we use little-endian to store extra bytes + dest += k_HashCalc_DigestSize_Max; + for (unsigned i = 0; i < k_HashCalc_ExtraSize; i++) + { + next += (unsigned)dest[i]; + dest[i] = (Byte)next; + next >>= 8; + } +} + +void CHasherState::AddDigest(unsigned groupIndex, const Byte *data) +{ + NumSums[groupIndex]++; + AddDigests(Digests[groupIndex], data, DigestSize); +} + +void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path) +{ + if (isDir) + NumDirs++; + else if (isAltStream) + { + NumAltStreams++; + AltStreamsSize += CurSize; + } + else + { + NumFiles++; + FilesSize += CurSize; + } + + Byte pre[16]; + memset(pre, 0, sizeof(pre)); + if (isDir) + pre[0] = 1; + + FOR_VECTOR (i, Hashers) + { + CHasherState &h = Hashers[i]; + if (!isDir) + { + h.Hasher->Final(h.Digests[0]); // k_HashCalc_Index_Current + if (!isAltStream) + h.AddDigest(k_HashCalc_Index_DataSum, h.Digests[0]); + } + + h.Hasher->Init(); + h.Hasher->Update(pre, sizeof(pre)); + h.Hasher->Update(h.Digests[0], h.DigestSize); + + for (unsigned k = 0; k < path.Len(); k++) + { + wchar_t c = path[k]; + + // 21.04: we want same hash for linux and windows paths + #if CHAR_PATH_SEPARATOR != '/' + if (c == CHAR_PATH_SEPARATOR) + c = '/'; + // if (c == (wchar_t)('\\' + 0xf000)) c = '\\'; // to debug WSL + // if (c > 0xf000 && c < 0xf080) c -= 0xf000; // to debug WSL + #endif + + Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) }; + h.Hasher->Update(temp, 2); + } + + Byte tempDigest[k_HashCalc_DigestSize_Max]; + h.Hasher->Final(tempDigest); + if (!isAltStream) + h.AddDigest(k_HashCalc_Index_NamesSum, tempDigest); + h.AddDigest(k_HashCalc_Index_StreamsSum, tempDigest); + } +} + + +static void CSum_Name_OriginalToEscape(const AString &src, AString &dest) +{ + dest.Empty(); + for (unsigned i = 0; i < src.Len();) + { + char c = src[i++]; + if (c == '\n') + { + dest.Add_Char('\\'); + c = 'n'; + } + else if (c == '\\') + dest.Add_Char('\\'); + dest.Add_Char(c); + } +} + + +static bool CSum_Name_EscapeToOriginal(const char *s, AString &dest) +{ + bool isOK = true; + dest.Empty(); + for (;;) + { + char c = *s++; + if (c == 0) + break; + if (c == '\\') + { + const char c1 = *s; + if (c1 == 'n') + { + c = '\n'; + s++; + } + else if (c1 == '\\') + { + c = c1; + s++; + } + else + { + // original md5sum returns NULL for such bad strings + isOK = false; + } + } + dest.Add_Char(c); + } + return isOK; +} + + + +static void SetSpacesAndNul(char *s, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + s[i] = ' '; + s[num] = 0; +} + +static const unsigned kHashColumnWidth_Min = 4 * 2; + +static unsigned GetColumnWidth(unsigned digestSize) +{ + const unsigned width = digestSize * 2; + return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; +} + + +static void AddHashResultLine( + AString &_s, + // bool showHash, + // UInt64 fileSize, bool showSize, + const CObjectVector &hashers + // unsigned digestIndex, = k_HashCalc_Index_Current + ) +{ + FOR_VECTOR (i, hashers) + { + const CHasherState &h = hashers[i]; + char s[k_HashCalc_DigestSize_Max * 2 + 64]; + s[0] = 0; + // if (showHash) + HashHexToString(s, h.Digests[k_HashCalc_Index_Current], h.DigestSize); + const unsigned pos = (unsigned)strlen(s); + const int numSpaces = (int)GetColumnWidth(h.DigestSize) - (int)pos; + if (numSpaces > 0) + SetSpacesAndNul(s + pos, (unsigned)numSpaces); + if (i != 0) + _s.Add_Space(); + _s += s; + } + + /* + if (showSize) + { + _s.Add_Space(); + static const unsigned kSizeField_Len = 13; // same as in HashCon.cpp + char s[kSizeField_Len + 32]; + char *p = s; + SetSpacesAndNul(s, kSizeField_Len); + p = s + kSizeField_Len; + ConvertUInt64ToString(fileSize, p); + int numSpaces = (int)kSizeField_Len - (int)strlen(p); + if (numSpaces > 0) + p -= (unsigned)numSpaces; + _s += p; + } + */ +} + + +static void Add_LF(CDynLimBuf &hashFileString, const CHashOptionsLocal &options) +{ + hashFileString += (char)(options.HashMode_Zero.Val ? 0 : '\n'); +} + + + + +static void WriteLine(CDynLimBuf &hashFileString, + const CHashOptionsLocal &options, + const UString &path2, + bool isDir, + const AString &methodName, + const AString &hashesString) +{ + if (options.HashMode_OnlyHash.Val) + { + hashFileString += hashesString; + Add_LF(hashFileString, options); + return; + } + + UString path = path2; + + bool isBin = false; + const bool zeroMode = options.HashMode_Zero.Val; + const bool tagMode = options.HashMode_Tag.Val; + +#if CHAR_PATH_SEPARATOR != '/' + path.Replace(WCHAR_PATH_SEPARATOR, L'/'); + // path.Replace((wchar_t)('\\' + 0xf000), L'\\'); // to debug WSL +#endif + + AString utf8; + ConvertUnicodeToUTF8(path, utf8); + + AString esc; + CSum_Name_OriginalToEscape(utf8, esc); + + if (!zeroMode) + { + if (esc != utf8) + { + /* Original md5sum writes escape in that case. + We do same for compatibility with original md5sum. */ + hashFileString += '\\'; + } + } + + if (isDir && !esc.IsEmpty() && esc.Back() != '/') + esc.Add_Slash(); + + if (tagMode) + { + if (!methodName.IsEmpty()) + { + hashFileString += methodName; + hashFileString += ' '; + } + hashFileString += '('; + hashFileString += esc; + hashFileString += ')'; + hashFileString += " = "; + } + + hashFileString += hashesString; + + if (!tagMode) + { + hashFileString += ' '; + hashFileString += (char)(isBin ? '*' : ' '); + hashFileString += esc; + } + + Add_LF(hashFileString, options); +} + + + +static void WriteLine(CDynLimBuf &hashFileString, + const CHashOptionsLocal &options, + const UString &path, + bool isDir, + const CHashBundle &hb) +{ + AString methodName; + if (!hb.Hashers.IsEmpty()) + methodName = hb.Hashers[0].Name; + + AString hashesString; + AddHashResultLine(hashesString, hb.Hashers); + WriteLine(hashFileString, options, path, isDir, methodName, hashesString); +} + + +HRESULT HashCalc( + DECL_EXTERNAL_CODECS_LOC_VARS + const NWildcard::CCensor &censor, + const CHashOptions &options, + AString &errorInfo, + IHashCallbackUI *callback) +{ + CDirItems dirItems; + dirItems.Callback = callback; + + if (options.StdInMode) + { + CDirItem di; + if (!di.SetAs_StdInFile()) + return GetLastError_noZero_HRESULT(); + dirItems.Items.Add(di); + } + else + { + RINOK(callback->StartScanning()) + + dirItems.SymLinks = options.SymLinks.Val; + dirItems.ScanAltStreams = options.AltStreamsMode; + dirItems.ExcludeDirItems = censor.ExcludeDirItems; + dirItems.ExcludeFileItems = censor.ExcludeFileItems; + + dirItems.ShareForWrite = options.OpenShareForWrite; + + HRESULT res = EnumerateItems(censor, + options.PathMode, + UString(), + dirItems); + + if (res != S_OK) + { + if (res != E_ABORT) + errorInfo = "Scanning error"; + return res; + } + RINOK(callback->FinishScanning(dirItems.Stat)) + } + + unsigned i; + CHashBundle hb; + RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods)) + // hb.Init(); + + hb.NumErrors = dirItems.Stat.NumErrors; + + UInt64 totalSize = 0; + if (options.StdInMode) + { + RINOK(callback->SetNumFiles(1)) + } + else + { + totalSize = dirItems.Stat.GetTotalBytes(); + RINOK(callback->SetTotal(totalSize)) + } + + const UInt32 kBufSize = 1 << 15; + CHashMidBuf buf; + if (!buf.Alloc(kBufSize)) + return E_OUTOFMEMORY; + + UInt64 completeValue = 0; + + RINOK(callback->BeforeFirstFile(hb)) + + /* + CDynLimBuf hashFileString((size_t)1 << 31); + const bool needGenerate = !options.HashFilePath.IsEmpty(); + */ + + for (i = 0; i < dirItems.Items.Size(); i++) + { + CMyComPtr inStream; + UString path; + bool isDir = false; + bool isAltStream = false; + + if (options.StdInMode) + { +#if 1 + inStream = new CStdInFileStream; +#else + if (!CreateStdInStream(inStream)) + { + const DWORD lastError = ::GetLastError(); + const HRESULT res = callback->OpenFileError(FString("stdin"), lastError); + hb.NumErrors++; + if (res != S_FALSE && res != S_OK) + return res; + continue; + } +#endif + } + else + { + path = dirItems.GetLogPath(i); + const CDirItem &di = dirItems.Items[i]; + #ifdef _WIN32 + isAltStream = di.IsAltStream; + #endif + + #ifndef UNDER_CE + // if (di.AreReparseData()) + if (di.ReparseData.Size() != 0) + { + CBufInStream *inStreamSpec = new CBufInStream(); + inStream = inStreamSpec; + inStreamSpec->Init(di.ReparseData, di.ReparseData.Size()); + } + else + #endif + { + CInFileStream *inStreamSpec = new CInFileStream; + inStreamSpec->Set_PreserveATime(options.PreserveATime); + inStream = inStreamSpec; + isDir = di.IsDir(); + if (!isDir) + { + const FString phyPath = dirItems.GetPhyPath(i); + if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite)) + { + const HRESULT res = callback->OpenFileError(phyPath, ::GetLastError()); + hb.NumErrors++; + if (res != S_FALSE) + return res; + continue; + } + if (!options.StdInMode) + { + UInt64 curSize = 0; + if (inStreamSpec->GetSize(&curSize) == S_OK) + { + if (curSize > di.Size) + { + totalSize += curSize - di.Size; + RINOK(callback->SetTotal(totalSize)) + // printf("\ntotal = %d MiB\n", (unsigned)(totalSize >> 20)); + } + } + } + // inStreamSpec->ReloadProps(); + } + } + } + + RINOK(callback->GetStream(path, isDir)) + UInt64 fileSize = 0; + + hb.InitForNewFile(); + + if (!isDir) + { + for (UInt32 step = 0;; step++) + { + if ((step & 0xFF) == 0) + { + // printf("\ncompl = %d\n", (unsigned)(completeValue >> 20)); + RINOK(callback->SetCompleted(&completeValue)) + } + UInt32 size; + RINOK(inStream->Read(buf, kBufSize, &size)) + if (size == 0) + break; + hb.Update(buf, size); + fileSize += size; + completeValue += size; + } + } + + hb.Final(isDir, isAltStream, path); + + /* + if (needGenerate + && (options.HashMode_Dirs.Val || !isDir)) + { + WriteLine(hashFileString, + options, + path, // change it + isDir, + hb); + + if (hashFileString.IsError()) + return E_OUTOFMEMORY; + } + */ + + RINOK(callback->SetOperationResult(fileSize, hb, !isDir)) + RINOK(callback->SetCompleted(&completeValue)) + } + + /* + if (needGenerate) + { + NFile::NIO::COutFile file; + if (!file.Create(us2fs(options.HashFilePath), true)) // createAlways + return GetLastError_noZero_HRESULT(); + if (!file.WriteFull(hashFileString, hashFileString.Len())) + return GetLastError_noZero_HRESULT(); + } + */ + + return callback->AfterLastFile(hb); +} + + +void HashHexToString(char *dest, const Byte *data, size_t size) +{ + if (!data) + { + for (size_t i = 0; i < size; i++) + { + dest[0] = ' '; + dest[1] = ' '; + dest += 2; + } + *dest = 0; + return; + } + + if (size > 8) + ConvertDataToHex_Lower(dest, data, size); + else if (size == 0) + { + *dest = 0; + return; + } + else + { + const char *dest_start = dest; + dest += size * 2; + *dest = 0; + do + { + const size_t b = *data++; + dest -= 2; + dest[0] = GET_HEX_CHAR_UPPER(b >> 4); + dest[1] = GET_HEX_CHAR_UPPER(b & 15); + } + while (dest != dest_start); + } +} + +void CHasherState::WriteToString(unsigned digestIndex, char *s) const +{ + HashHexToString(s, Digests[digestIndex], DigestSize); + + if (digestIndex != 0 && NumSums[digestIndex] != 1) + { + unsigned numExtraBytes = GetNumExtraBytes_for_Group(digestIndex); + if (numExtraBytes > 4) + numExtraBytes = 8; + else // if (numExtraBytes >= 0) + numExtraBytes = 4; + // if (numExtraBytes != 0) + { + s += strlen(s); + *s++ = '-'; + // *s = 0; + HashHexToString(s, GetExtraData_for_Group(digestIndex), numExtraBytes); + } + } +} + + + +// ---------- Hash Handler ---------- + +namespace NHash { + +#define IsWhite(c) ((c) == ' ' || (c) == '\t') + +bool CHashPair::IsDir() const +{ + if (Name.IsEmpty() || Name.Back() != '/') + return false; + // here we expect that Dir items contain only zeros or no Hash + for (size_t i = 0; i < Hash.Size(); i++) + if (Hash.ConstData()[i] != 0) + return false; + return true; +} + + +bool CHashPair::ParseCksum(const char *s) +{ + const char *end; + + const UInt32 crc = ConvertStringToUInt32(s, &end); + if (*end != ' ') + return false; + end++; + + const UInt64 size = ConvertStringToUInt64(end, &end); + if (*end != ' ') + return false; + end++; + + Name = end; + + Hash.Alloc(4); + SetBe32(Hash, crc) + + Size_from_Arc = size; + Size_from_Arc_Defined = true; + + return true; +} + + + +static const char *SkipWhite(const char *s) +{ + while (IsWhite(*s)) + s++; + return s; +} + +static const char * const k_CsumMethodNames[] = +{ + "sha256" + , "sha224" +// , "sha512-224" +// , "sha512-256" + , "sha384" + , "sha512" +// , "sha3-224" + , "sha3-256" +// , "sha3-384" +// , "sha3-512" +// , "shake128" +// , "shake256" + , "sha1" + , "md5" + , "blake2sp" + , "blake2b" + , "xxh64" + , "crc64" + , "crc32" + , "cksum" +}; + +static UString GetMethod_from_FileName(const UString &name) +{ + AString s; + ConvertUnicodeToUTF8(name, s); + const int dotPos = s.ReverseFind_Dot(); + const char *src = s.Ptr(); + bool isExtension = false; + if (dotPos >= 0) + { + isExtension = true; + src = s.Ptr(dotPos + 1); + } + const char *m = ""; + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) + { + m = k_CsumMethodNames[i]; + if (isExtension) + { + if (StringsAreEqual_Ascii(src, m)) + break; + } + else if (IsString1PrefixedByString2_NoCase_Ascii(src, m)) + if (StringsAreEqual_Ascii(src + strlen(m), "sums")) + break; + } + UString res; + if (i != Z7_ARRAY_SIZE(k_CsumMethodNames)) + res = m; + return res; +} + + +bool CHashPair::Parse(const char *s) +{ + // here we keep compatibility with original md5sum / shasum + bool escape = false; + + s = SkipWhite(s); + + if (*s == '\\') + { + s++; + escape = true; + } + Escape = escape; + + // const char *kMethod = GetMethod_from_FileName(s); + // if (kMethod) + if ((size_t)(FindNonHexChar(s) - s) < 4) + { + // BSD-style checksum line + { + const char *s2 = s; + for (; *s2 != 0; s2++) + { + const char c = *s2; + if (c == 0) + return false; + if (c == ' ' || c == '(') + break; + } + Method.SetFrom(s, (unsigned)(s2 - s)); + s = s2; + } + IsBSD = true; + if (*s == ' ') + s++; + if (*s != '(') + return false; + s++; + { + const char *s2 = s; + for (; *s2 != 0; s2++) + {} + for (;;) + { + s2--; + if (s2 < s) + return false; + if (*s2 == ')') + break; + } + Name.SetFrom(s, (unsigned)(s2 - s)); + s = s2 + 1; + } + + s = SkipWhite(s); + if (*s != '=') + return false; + s++; + s = SkipWhite(s); + } + + { + const size_t numChars = (size_t)(FindNonHexChar(s) - s) & ~(size_t)1; + Hash.Alloc(numChars / 2); + if ((size_t)(ParseHexString(s, Hash) - Hash) != numChars / 2) + throw 101; + HashString.SetFrom(s, (unsigned)numChars); + s += numChars; + } + + if (IsBSD) + { + if (*s != 0) + return false; + if (escape) + { + const AString temp (Name); + return CSum_Name_EscapeToOriginal(temp, Name); + } + return true; + } + + if (*s == 0) + return true; + + if (*s != ' ') + return false; + s++; + const char c = *s; + if (c != ' ' + && c != '*' + && c != 'U' // shasum Universal + && c != '^' // shasum 0/1 + ) + return false; + Mode = c; + s++; + if (escape) + return CSum_Name_EscapeToOriginal(s, Name); + Name = s; + return true; +} + + +static bool GetLine(CByteBuffer &buf, bool zeroMode, bool cr_lf_Mode, size_t &posCur, AString &s) +{ + s.Empty(); + size_t pos = posCur; + const Byte *p = buf; + unsigned numDigits = 0; + for (; pos < buf.Size(); pos++) + { + const Byte b = p[pos]; + if (b == 0) + { + numDigits = 1; + break; + } + if (zeroMode) + continue; + if (b == 0x0a) + { + numDigits = 1; + break; + } + if (!cr_lf_Mode) + continue; + if (b == 0x0d) + { + if (pos + 1 >= buf.Size()) + { + numDigits = 1; + break; + // return false; + } + if (p[pos + 1] == 0x0a) + { + numDigits = 2; + break; + } + } + } + s.SetFrom((const char *)(p + posCur), (unsigned)(pos - posCur)); + posCur = pos + numDigits; + return true; +} + + +static bool Is_CR_LF_Data(const Byte *buf, size_t size) +{ + bool isCrLf = false; + for (size_t i = 0; i < size;) + { + const Byte b = buf[i]; + if (b == 0x0a) + return false; + if (b == 0x0d) + { + if (i == size - 1) + return false; + if (buf[i + 1] != 0x0a) + return false; + isCrLf = true; + i += 2; + } + else + i++; + } + return isCrLf; +} + + +static const Byte kArcProps[] = +{ + // kpidComment, + kpidCharacts +}; + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidMethod +}; + +static const Byte kRawProps[] = +{ + kpidChecksum +}; + + +Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */ , UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = Z7_ARRAY_SIZE(kRawProps); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) +{ + *propID = kRawProps[index]; + *name = NULL; + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidChecksum) + { + const CHashPair &hp = HashPairs[index]; + if (hp.Hash.Size() > 0) + { + *data = hp.Hash; + *dataSize = (UInt32)hp.Hash.Size(); + *propType = NPropDataType::kRaw; + } + return S_OK; + } + + return S_OK; +} + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = HashPairs.Size(); + return S_OK; +} + +static void Add_OptSpace_String(UString &dest, const char *src) +{ + dest.Add_Space_if_NotEmpty(); + dest += src; +} + +Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + /* + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + // if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (v != 0) + prop = v; + break; + } + */ + case kpidCharacts: + { + UString s; + if (_hashSize_Defined) + { + s.Add_Space_if_NotEmpty(); + s.Add_UInt32(_hashSize * 8); + s += "-bit"; + } + if (!_nameExtenstion.IsEmpty()) + { + s.Add_Space_if_NotEmpty(); + s += _nameExtenstion; + } + if (_is_PgpMethod) + { + Add_OptSpace_String(s, "PGP"); + if (!_pgpMethod.IsEmpty()) + { + s.Add_Colon(); + s += _pgpMethod; + } + } + if (_is_ZeroMode) + Add_OptSpace_String(s, "ZERO"); + if (_are_there_Tags) + Add_OptSpace_String(s, "TAG"); + if (_are_there_Dirs) + Add_OptSpace_String(s, "DIRS"); + prop = s; + break; + } + + case kpidReadOnly: + { + if (_isArc) + if (!CanUpdate()) + prop = true; + break; + } + default: break; + } + prop.Detach(value); + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + // COM_TRY_BEGIN + NCOM::CPropVariant prop; + const CHashPair &hp = HashPairs[index]; + switch (propID) + { + case kpidIsDir: + { + prop = hp.IsDir(); + break; + } + case kpidPath: + { + UString path; + hp.Get_UString_Path(path); + + bool useBackslashReplacement = true; + if (_supportWindowsBackslash && !hp.Escape && path.Find(L"\\\\") < 0) + { +#if WCHAR_PATH_SEPARATOR == L'/' + path.Replace(L'\\', L'/'); +#else + useBackslashReplacement = false; +#endif + } + NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash( + path, useBackslashReplacement); + prop = path; + break; + } + case kpidSize: + { + // client needs processed size of last file + if (hp.Size_from_Disk_Defined) + prop = (UInt64)hp.Size_from_Disk; + else if (hp.Size_from_Arc_Defined) + prop = (UInt64)hp.Size_from_Arc; + break; + } + case kpidPackSize: + { + prop = (UInt64)hp.Hash.Size(); + break; + } + case kpidMethod: + { + if (!hp.Method.IsEmpty()) + prop = hp.Method; + break; + } + default: break; + } + prop.Detach(value); + return S_OK; + // COM_TRY_END +} + + +static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOpenCallback *openCallback) +{ + buf.Free(); + UInt64 len; + RINOK(InStream_AtBegin_GetSize(stream, len)) + if (len == 0 || len >= ((UInt64)1 << 31)) + return S_FALSE; + buf.Alloc((size_t)len); + UInt64 pos = 0; + // return ReadStream_FALSE(stream, buf, (size_t)len); + for (;;) + { + const UInt32 kBlockSize = ((UInt32)1 << 24); + const UInt32 curSize = (len < kBlockSize) ? (UInt32)len : kBlockSize; + UInt32 processedSizeLoc; + RINOK(stream->Read((Byte *)buf + pos, curSize, &processedSizeLoc)) + if (processedSizeLoc == 0) + return E_FAIL; + len -= processedSizeLoc; + pos += processedSizeLoc; + if (len == 0) + return S_OK; + if (openCallback) + { + const UInt64 files = 0; + RINOK(openCallback->SetCompleted(&files, &pos)) + } + } +} + + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) +{ + COM_TRY_BEGIN + { + Close(); + + CByteBuffer buf; + RINOK(ReadStream_to_Buf(stream, buf, openCallback)) + + CObjectVector &pairs = HashPairs; + + bool zeroMode = false; + bool cr_lf_Mode = false; + { + for (size_t i = 0; i < buf.Size(); i++) + if (buf.ConstData()[i] == 0) + { + zeroMode = true; + break; + } + } + _is_ZeroMode = zeroMode; + if (!zeroMode) + cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); + + if (openCallback) + { + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpenVolumeCallback, + openVolumeCallback, openCallback) + if (openVolumeCallback) + { + NCOM::CPropVariant prop; + RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) + if (prop.vt == VT_BSTR) + _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); + } + } + + bool cksumMode = false; + if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) + cksumMode = true; + _is_CksumMode = cksumMode; + + size_t pos = 0; + AString s; + bool minusMode = false; + unsigned numLines = 0; + + while (pos < buf.Size()) + { + if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s)) + return S_FALSE; + numLines++; + if (s.IsEmpty()) + continue; + + if (s.IsPrefixedBy_Ascii_NoCase("; ")) + { + if (numLines != 1) + return S_FALSE; + // comment line of FileVerifier++ + continue; + } + + if (s.IsPrefixedBy_Ascii_NoCase("-----")) + { + if (minusMode) + break; // end of pgp mode + minusMode = true; + if (s.IsPrefixedBy_Ascii_NoCase("-----BEGIN PGP SIGNED MESSAGE")) + { + if (_is_PgpMethod) + return S_FALSE; + if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s)) + return S_FALSE; + const char *kStart = "Hash: "; + if (!s.IsPrefixedBy_Ascii_NoCase(kStart)) + return S_FALSE; + _pgpMethod = s.Ptr((unsigned)strlen(kStart)); + _is_PgpMethod = true; + } + continue; + } + + CHashPair pair; + pair.FullLine = s; + if (cksumMode) + { + if (!pair.ParseCksum(s)) + return S_FALSE; + } + else if (!pair.Parse(s)) + return S_FALSE; + pairs.Add(pair); + } + + { + unsigned hashSize = 0; + bool hashSize_Dismatch = false; + for (unsigned i = 0; i < HashPairs.Size(); i++) + { + const CHashPair &hp = HashPairs[i]; + if (i == 0) + hashSize = (unsigned)hp.Hash.Size(); + else + if (hashSize != hp.Hash.Size()) + hashSize_Dismatch = true; + + if (hp.IsBSD) + _are_there_Tags = true; + if (!_are_there_Dirs && hp.IsDir()) + _are_there_Dirs = true; + } + if (!hashSize_Dismatch && hashSize != 0) + { + _hashSize = hashSize; + _hashSize_Defined = true; + } + } + + _phySize = buf.Size(); + _isArc = true; + return S_OK; + } + COM_TRY_END +} + + +void CHandler::ClearVars() +{ + _phySize = 0; + _isArc = false; + _is_CksumMode = false; + _is_PgpMethod = false; + _is_ZeroMode = false; + _are_there_Tags = false; + _are_there_Dirs = false; + _hashSize_Defined = false; + _hashSize = 0; +} + + +Z7_COM7F_IMF(CHandler::Close()) +{ + ClearVars(); + _nameExtenstion.Empty(); + _pgpMethod.Empty(); + HashPairs.Clear(); + return S_OK; +} + + +static bool CheckDigests(const Byte *a, const Byte *b, size_t size) +{ + if (size <= 8) + { + /* we use reversed order for one digest, when text representation + uses big-order for crc-32 and crc-64 */ + for (size_t i = 0; i < size; i++) + if (a[i] != b[size - 1 - i]) + return false; + return true; + } + { + for (size_t i = 0; i < size; i++) + if (a[i] != b[i]) + return false; + return true; + } +} + + +static void AddDefaultMethod(UStringVector &methods, unsigned size) +{ + const char *m = NULL; + if (size == 32) m = "sha256"; + else if (size == 20) m = "sha1"; + else if (size == 16) m = "md5"; + else if (size == 8) m = "crc64"; + else if (size == 4) m = "crc32"; + else + return; + #ifdef Z7_EXTERNAL_CODECS + const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; + #endif + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS + AString(m), id)) + methods.Add(UString(m)); +} + + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + + /* + if (testMode == 0) + return E_NOTIMPL; + */ + + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = HashPairs.Size(); + if (numItems == 0) + return S_OK; + + #ifdef Z7_EXTERNAL_CODECS + const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; + #endif + + CHashBundle hb_Glob; + // UStringVector methods = options.Methods; + UStringVector methods; + + if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) + { + AString utf; + ConvertUnicodeToUTF8(_nameExtenstion, utf); + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) + methods.Add(_nameExtenstion); + } + + if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) + { + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS _pgpMethod, id)) + methods.Add(UString(_pgpMethod)); + } + + if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) + AddDefaultMethod(methods, _hashSize); + + RINOK(hb_Glob.SetMethods( + EXTERNAL_CODECS_LOC_VARS + methods)) + + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveUpdateCallbackFile, + updateCallbackFile, extractCallback) + if (!updateCallbackFile) + return E_NOTIMPL; + { + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveGetDiskProperty, + GetDiskProperty, extractCallback) + if (GetDiskProperty) + { + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + const CHashPair &hp = HashPairs[index]; + if (hp.IsDir()) + continue; + { + NCOM::CPropVariant prop; + RINOK(GetDiskProperty->GetDiskProperty(index, kpidSize, &prop)) + if (prop.vt != VT_UI8) + continue; + totalSize += prop.uhVal.QuadPart; + } + } + RINOK(extractCallback->SetTotal(totalSize)) + // RINOK(Hash_SetTotalUnpacked->Hash_SetTotalUnpacked(indices, numItems)); + } + } + + const UInt32 kBufSize = 1 << 15; + CHashMidBuf buf; + if (!buf.Alloc(kBufSize)) + return E_OUTOFMEMORY; + + CMyComPtr2_Create lps; + lps->Init(extractCallback, false); + + for (UInt32 i = 0;; i++) + { + RINOK(lps->SetCur()) + if (i >= numItems) + break; + const UInt32 index = allFilesMode ? i : indices[i]; + + CHashPair &hp = HashPairs[index]; + + UString path; + hp.Get_UString_Path(path); + + CMyComPtr inStream; + const bool isDir = hp.IsDir(); + if (!isDir) + { + RINOK(updateCallbackFile->GetStream2(index, &inStream, NUpdateNotifyOp::kHashRead)) + if (!inStream) + { + continue; // we have shown error in GetStream2() + } + // askMode = NArchive::NExtract::NAskMode::kSkip; + } + + Int32 askMode = testMode ? + NArchive::NExtract::NAskMode::kTest : + NArchive::NExtract::NAskMode::kExtract; + + CMyComPtr realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + + /* PrepareOperation() can expect kExtract to set + Attrib and security of output file */ + askMode = NArchive::NExtract::NAskMode::kReadExternal; + + RINOK(extractCallback->PrepareOperation(askMode)) + + const bool isAltStream = false; + + UInt64 fileSize = 0; + + CHashBundle hb_Loc; + + CHashBundle *hb_Use = &hb_Glob; + + HRESULT res_SetMethods = S_OK; + + UStringVector methods_loc; + + if (!hp.Method.IsEmpty()) + { + hb_Use = &hb_Loc; + CMethodId id; + if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id)) + { + methods_loc.Add(UString(hp.Method)); + RINOK(hb_Loc.SetMethods( + EXTERNAL_CODECS_LOC_VARS + methods_loc)) + } + else + res_SetMethods = E_NOTIMPL; + } + else if (methods.IsEmpty()) + { + AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size()); + if (!methods_loc.IsEmpty()) + { + hb_Use = &hb_Loc; + RINOK(hb_Loc.SetMethods( + EXTERNAL_CODECS_LOC_VARS + methods_loc)) + } + } + + const bool isSupportedMode = hp.IsSupportedMode(); + hb_Use->InitForNewFile(); + + if (inStream) + { + for (UInt32 step = 0;; step++) + { + if ((step & 0xFF) == 0) + { + RINOK(lps.Interface()->SetRatioInfo(NULL, &fileSize)) + } + UInt32 size; + RINOK(inStream->Read(buf, kBufSize, &size)) + if (size == 0) + break; + hb_Use->Update(buf, size); + if (realOutStream) + { + RINOK(WriteStream(realOutStream, buf, size)) + } + fileSize += size; + } + + hp.Size_from_Disk = fileSize; + hp.Size_from_Disk_Defined = true; + } + + realOutStream.Release(); + inStream.Release(); + + lps->InSize += hp.Hash.Size(); + lps->OutSize += fileSize; + + hb_Use->Final(isDir, isAltStream, path); + + Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; + if (isSupportedMode + && res_SetMethods != E_NOTIMPL + && hb_Use->Hashers.Size() > 0 + ) + { + const CHasherState &hs = hb_Use->Hashers[0]; + if (hs.DigestSize == hp.Hash.Size()) + { + opRes = NArchive::NExtract::NOperationResult::kCRCError; + if (CheckDigests(hp.Hash, hs.Digests[0], hs.DigestSize)) + if (!hp.Size_from_Arc_Defined || hp.Size_from_Arc == fileSize) + opRes = NArchive::NExtract::NOperationResult::kOK; + } + } + + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + COM_TRY_END +} + + +// ---------- UPDATE ---------- + +struct CUpdateItem +{ + int IndexInArc; + unsigned IndexInClient; + UInt64 Size; + bool NewData; + bool NewProps; + bool IsDir; + UString Path; + + CUpdateItem(): Size(0), IsDir(false) {} +}; + + +static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, + UString &res, + bool convertSlash) +{ + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(index, propId, &prop)) + if (prop.vt == VT_BSTR) + { + res = prop.bstrVal; + if (convertSlash) + NArchive::NItemName::ReplaceSlashes_OsToUnix(res); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type)) +{ + *type = NFileTimeType::kUnix; + return S_OK; +} + + +Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *callback)) +{ + COM_TRY_BEGIN + + if (_isArc && !CanUpdate()) + return E_NOTIMPL; + + /* + Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, + reportArcProp, callback) + */ + + CObjectVector updateItems; + + UInt64 complexity = 0; + + UInt32 i; + for (i = 0; i < numItems; i++) + { + CUpdateItem ui; + Int32 newData; + Int32 newProps; + UInt32 indexInArc; + + if (!callback) + return E_FAIL; + + RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc)) + + ui.NewProps = IntToBool(newProps); + ui.NewData = IntToBool(newData); + ui.IndexInArc = (int)indexInArc; + ui.IndexInClient = i; + if (IntToBool(newProps)) + { + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidIsDir, &prop)) + if (prop.vt == VT_EMPTY) + ui.IsDir = false; + else if (prop.vt != VT_BOOL) + return E_INVALIDARG; + else + ui.IsDir = (prop.boolVal != VARIANT_FALSE); + } + + RINOK(GetPropString(callback, i, kpidPath, ui.Path, + true)) // convertSlash + /* + if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') + ui.Name += '/'; + */ + } + + if (IntToBool(newData)) + { + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidSize, &prop)) + if (prop.vt == VT_UI8) + { + ui.Size = prop.uhVal.QuadPart; + complexity += ui.Size; + } + else if (prop.vt == VT_EMPTY) + ui.Size = (UInt64)(Int64)-1; + else + return E_INVALIDARG; + } + + updateItems.Add(ui); + } + + if (complexity != 0) + { + RINOK(callback->SetTotal(complexity)) + } + + #ifdef Z7_EXTERNAL_CODECS + const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; + #endif + + CHashBundle hb; + UStringVector methods; + if (!_methods.IsEmpty()) + { + FOR_VECTOR(k, _methods) + { + methods.Add(_methods[k]); + } + } + else if (_crcSize_WasSet) + { + AddDefaultMethod(methods, _crcSize); + } + else + { + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveGetRootProps, + getRootProps, callback) + if (getRootProps) + { + NCOM::CPropVariant prop; + RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) + if (prop.vt == VT_BSTR) + { + const UString method = GetMethod_from_FileName(prop.bstrVal); + if (!method.IsEmpty()) + methods.Add(method); + } + } + } + + RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) + + CMyComPtr2_Create lps; + lps->Init(callback, true); + + const UInt32 kBufSize = 1 << 15; + CHashMidBuf buf; + if (!buf.Alloc(kBufSize)) + return E_OUTOFMEMORY; + + CDynLimBuf hashFileString((size_t)1 << 31); + + CHashOptionsLocal options = _options; + + if (_isArc) + { + if (!options.HashMode_Zero.Def && _is_ZeroMode) + options.HashMode_Zero.Val = true; + if (!options.HashMode_Tag.Def && _are_there_Tags) + options.HashMode_Tag.Val = true; + if (!options.HashMode_Dirs.Def && _are_there_Dirs) + options.HashMode_Dirs.Val = true; + } + if (options.HashMode_OnlyHash.Val && updateItems.Size() != 1) + options.HashMode_OnlyHash.Val = false; + + complexity = 0; + + for (i = 0; i < updateItems.Size(); i++) + { + lps->InSize = complexity; + RINOK(lps->SetCur()) + + const CUpdateItem &ui = updateItems[i]; + + /* + CHashPair item; + if (!ui.NewProps) + item = HashPairs[(unsigned)ui.IndexInArc]; + */ + + if (ui.NewData) + { + UInt64 currentComplexity = ui.Size; + UInt64 fileSize = 0; + + CMyComPtr fileInStream; + bool needWrite = true; + { + HRESULT res = callback->GetStream(ui.IndexInClient, &fileInStream); + + if (res == S_FALSE) + needWrite = false; + else + { + RINOK(res) + + if (fileInStream) + { + Z7_DECL_CMyComPtr_QI_FROM( + IStreamGetSize, + streamGetSize, fileInStream) + if (streamGetSize) + { + UInt64 size; + if (streamGetSize->GetSize(&size) == S_OK) + currentComplexity = size; + } + /* + Z7_DECL_CMyComPtr_QI_FROM( + IStreamGetProps, + getProps, fileInStream) + if (getProps) + { + FILETIME mTime; + UInt64 size2; + if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) + { + currentComplexity = size2; + // item.MTime = NTime::FileTimeToUnixTime64(mTime);; + } + } + */ + } + else + { + currentComplexity = 0; + } + } + } + + hb.InitForNewFile(); + const bool isDir = ui.IsDir; + + if (needWrite && fileInStream && !isDir) + { + for (UInt32 step = 0;; step++) + { + if ((step & 0xFF) == 0) + { + RINOK(lps.Interface()->SetRatioInfo(&fileSize, NULL)) + // RINOK(callback->SetCompleted(&completeValue)); + } + UInt32 size; + RINOK(fileInStream->Read(buf, kBufSize, &size)) + if (size == 0) + break; + hb.Update(buf, size); + fileSize += size; + } + currentComplexity = fileSize; + } + + fileInStream.Release(); + const bool isAltStream = false; + hb.Final(isDir, isAltStream, ui.Path); + + if (options.HashMode_Dirs.Val || !isDir) + { + if (!hb.Hashers.IsEmpty()) + lps->OutSize += hb.Hashers[0].DigestSize; + WriteLine(hashFileString, + options, + ui.Path, + isDir, + hb); + if (hashFileString.IsError()) + return E_OUTOFMEMORY; + } + + complexity += currentComplexity; + + /* + if (reportArcProp) + { + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + + NCOM::PropVarEm_Set_UInt64(&prop, fileSize); + RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidSize, &prop)); + + for (unsigned k = 0; k < hb.Hashers.Size(); k++) + { + const CHasherState &hs = hb.Hashers[k]; + + if (hs.DigestSize == 4 && hs.Name.IsEqualTo_Ascii_NoCase("crc32")) + { + NCOM::PropVarEm_Set_UInt32(&prop, GetUi32(hs.Digests[k_HashCalc_Index_Current])); + RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidCRC, &prop)); + } + else + { + RINOK(reportArcProp->ReportRawProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, + kpidChecksum, hs.Digests[k_HashCalc_Index_Current], + hs.DigestSize, NPropDataType::kRaw)); + } + RINOK(reportArcProp->ReportFinished(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, NArchive::NUpdate::NOperationResult::kOK)); + } + } + */ + RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)) + } + else + { + // old data + const CHashPair &existItem = HashPairs[(unsigned)ui.IndexInArc]; + if (ui.NewProps) + { + WriteLine(hashFileString, + options, + ui.Path, + ui.IsDir, + existItem.Method, existItem.HashString + ); + } + else + { + hashFileString += existItem.FullLine; + Add_LF(hashFileString, options); + } + } + if (hashFileString.IsError()) + return E_OUTOFMEMORY; + } + + RINOK(WriteStream(outStream, hashFileString, hashFileString.Len())) + + return S_OK; + COM_TRY_END +} + + + +HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) +{ + UString name = nameSpec; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + + if (name.IsEqualTo("m")) // "hm" hash method + { + // COneMethodInfo omi; + // RINOK(omi.ParseMethodFromPROPVARIANT(L"", value)); + // _methods.Add(omi.MethodName); // change it. use omi.PropsString + if (value.vt != VT_BSTR) + return E_INVALIDARG; + UString s (value.bstrVal); + _methods.Add(s); + return S_OK; + } + + if (name.IsEqualTo("flags")) + { + if (value.vt != VT_BSTR) + return E_INVALIDARG; + if (!_options.ParseString(value.bstrVal)) + return E_INVALIDARG; + return S_OK; + } + + if (name.IsEqualTo("backslash")) + return PROPVARIANT_to_bool(value, _supportWindowsBackslash); + + if (name.IsPrefixedBy_Ascii_NoCase("crc")) + { + name.Delete(0, 3); + _crcSize = 4; + _crcSize_WasSet = true; + return ParsePropToUInt32(name, value, _crcSize); + } + + // common properties + if (name.IsPrefixedBy_Ascii_NoCase("mt") + || name.IsPrefixedBy_Ascii_NoCase("memuse")) + return S_OK; + + return E_INVALIDARG; +} + + +Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) +{ + COM_TRY_BEGIN + + InitProps(); + + for (UInt32 i = 0; i < numProps; i++) + { + RINOK(SetProperty(names[i], values[i])) + } + return S_OK; + COM_TRY_END +} + +CHandler::CHandler() +{ + ClearVars(); + InitProps(); +} + +} + + + +static IInArchive *CreateHashHandler_In() { return new NHash::CHandler; } +static IOutArchive *CreateHashHandler_Out() { return new NHash::CHandler; } + +void Codecs_AddHashArcHandler(CCodecs *codecs) +{ + { + CArcInfoEx item; + + item.Name = "Hash"; + item.CreateInArchive = CreateHashHandler_In; + item.CreateOutArchive = CreateHashHandler_Out; + item.IsArcFunc = NULL; + item.Flags = + NArcInfoFlags::kKeepName + | NArcInfoFlags::kStartOpen + | NArcInfoFlags::kByExtOnlyOpen + // | NArcInfoFlags::kPureStartOpen + | NArcInfoFlags::kHashHandler + ; + + // ubuntu uses "SHA256SUMS" file + item.AddExts(UString ( + "sha256" + " sha512" + " sha384" + " sha224" + // " sha512-224" + // " sha512-256" + // " sha3-224" + " sha3-256" + // " sha3-384" + // " sha3-512" + // " shake128" + // " shake256" + " sha1" + " sha" + " md5" + " blake2sp" + " xxh64" + " crc32 crc64" + " asc" + " cksum" + // " b2sum" + ), + UString()); + + item.UpdateEnabled = (item.CreateOutArchive != NULL); + item.SignatureOffset = 0; + // item.Version = MY_VER_MIX; + item.NewInterface = true; + + item.Signatures.AddNew().CopyFrom(NULL, 0); + + codecs->Formats.Add(item); + } +} diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h index 88671881e..1e9dbf4e7 100644 --- a/CPP/7zip/UI/Common/HashCalc.h +++ b/CPP/7zip/UI/Common/HashCalc.h @@ -1,329 +1,329 @@ -// HashCalc.h - -#ifndef ZIP7_INC_HASH_CALC_H -#define ZIP7_INC_HASH_CALC_H - -#include "../../../Common/UTFConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../Common/CreateCoder.h" -#include "../../Common/MethodProps.h" - -#include "DirItem.h" -#include "IFileExtractCallback.h" - -const unsigned k_HashCalc_DigestSize_Max = 64; -const unsigned k_HashCalc_ExtraSize = 8; -const unsigned k_HashCalc_NumGroups = 4; - -/* - if (size <= 8) : upper case : reversed byte order : it shows 32-bit/64-bit number, if data contains little-endian number - if (size > 8) : lower case : original byte order (as big-endian byte sequence) -*/ -void HashHexToString(char *dest, const Byte *data, size_t size); - -enum -{ - k_HashCalc_Index_Current, - k_HashCalc_Index_DataSum, - k_HashCalc_Index_NamesSum, - k_HashCalc_Index_StreamsSum -}; - -struct CHasherState -{ - CMyComPtr Hasher; - AString Name; - UInt32 DigestSize; - UInt64 NumSums[k_HashCalc_NumGroups]; - Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max + k_HashCalc_ExtraSize]; - - void InitDigestGroup(unsigned groupIndex) - { - NumSums[groupIndex] = 0; - memset(Digests[groupIndex], 0, sizeof(Digests[groupIndex])); - } - - const Byte *GetExtraData_for_Group(unsigned groupIndex) const - { - return Digests[groupIndex] + k_HashCalc_DigestSize_Max; - } - - unsigned GetNumExtraBytes_for_Group(unsigned groupIndex) const - { - const Byte *p = GetExtraData_for_Group(groupIndex); - // we use little-endian to read extra bytes - for (unsigned i = k_HashCalc_ExtraSize; i != 0; i--) - if (p[i - 1] != 0) - return i; - return 0; - } - - void AddDigest(unsigned groupIndex, const Byte *data); - - void WriteToString(unsigned digestIndex, char *s) const; -}; - - -Z7_PURE_INTERFACES_BEGIN - - -DECLARE_INTERFACE(IHashCalc) -{ - virtual void InitForNewFile() = 0; - virtual void Update(const void *data, UInt32 size) = 0; - virtual void SetSize(UInt64 size) = 0; - virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0; -}; - -Z7_PURE_INTERFACES_END - -struct CHashBundle Z7_final: public IHashCalc -{ - CObjectVector Hashers; - - UInt64 NumDirs; - UInt64 NumFiles; - UInt64 NumAltStreams; - UInt64 FilesSize; - UInt64 AltStreamsSize; - UInt64 NumErrors; - - UInt64 CurSize; - - UString MainName; - UString FirstFileName; - - HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods); - - // void Init() {} - CHashBundle() - { - NumDirs = NumFiles = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0; - } - - void InitForNewFile() Z7_override; - void Update(const void *data, UInt32 size) Z7_override; - void SetSize(UInt64 size) Z7_override; - void Final(bool isDir, bool isAltStream, const UString &path) Z7_override; -}; - -Z7_PURE_INTERFACES_BEGIN - -// INTERFACE_IDirItemsCallback(x) - -#define Z7_IFACEN_IHashCallbackUI(x) \ - virtual HRESULT StartScanning() x \ - virtual HRESULT FinishScanning(const CDirItemsStat &st) x \ - virtual HRESULT SetNumFiles(UInt64 numFiles) x \ - virtual HRESULT SetTotal(UInt64 size) x \ - virtual HRESULT SetCompleted(const UInt64 *completeValue) x \ - virtual HRESULT CheckBreak() x \ - virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x \ - virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x \ - virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \ - virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x \ - virtual HRESULT AfterLastFile(CHashBundle &hb) x \ - -Z7_IFACE_DECL_PURE_(IHashCallbackUI, IDirItemsCallback) - -Z7_PURE_INTERFACES_END - - -struct CHashOptionsLocal -{ - CBoolPair HashMode_Zero; - CBoolPair HashMode_Tag; - CBoolPair HashMode_Dirs; - CBoolPair HashMode_OnlyHash; - - void Init_HashOptionsLocal() - { - HashMode_Zero.Init(); - HashMode_Tag.Init(); - HashMode_Dirs.Init(); - HashMode_OnlyHash.Init(); - // HashMode_Dirs = true; // for debug - } - - CHashOptionsLocal() - { - Init_HashOptionsLocal(); - } - - bool ParseFlagCharOption(wchar_t c, bool val) - { - c = MyCharLower_Ascii(c); - if (c == 'z') HashMode_Zero.SetVal_as_Defined(val); - else if (c == 't') HashMode_Tag.SetVal_as_Defined(val); - else if (c == 'd') HashMode_Dirs.SetVal_as_Defined(val); - else if (c == 'h') HashMode_OnlyHash.SetVal_as_Defined(val); - else return false; - return true; - } - - bool ParseString(const UString &s) - { - for (unsigned i = 0; i < s.Len();) - { - const wchar_t c = s[i++]; - bool val = true; - if (i < s.Len()) - { - const wchar_t next = s[i]; - if (next == '-') - { - val = false; - i++; - } - } - if (!ParseFlagCharOption(c, val)) - return false; - } - return true; - } -}; - - -struct CHashOptions - // : public CHashOptionsLocal -{ - UStringVector Methods; - // UString HashFilePath; - - bool PreserveATime; - bool OpenShareForWrite; - bool StdInMode; - bool AltStreamsMode; - CBoolPair SymLinks; - - NWildcard::ECensorPathMode PathMode; - - CHashOptions(): - PreserveATime(false), - OpenShareForWrite(false), - StdInMode(false), - AltStreamsMode(false), - PathMode(NWildcard::k_RelatPath) {} -}; - - -HRESULT HashCalc( - DECL_EXTERNAL_CODECS_LOC_VARS - const NWildcard::CCensor &censor, - const CHashOptions &options, - AString &errorInfo, - IHashCallbackUI *callback); - - - -#ifndef Z7_SFX - -namespace NHash { - -struct CHashPair -{ - CByteBuffer Hash; - char Mode; - bool IsBSD; - bool Escape; - bool Size_from_Arc_Defined; - bool Size_from_Disk_Defined; - AString Method; - AString Name; - - AString FullLine; - AString HashString; - // unsigned HashLengthInBits; - - // AString MethodName; - UInt64 Size_from_Arc; - UInt64 Size_from_Disk; - - bool IsDir() const; - - void Get_UString_Path(UString &path) const - { - path.Empty(); - if (!ConvertUTF8ToUnicode(Name, path)) - return; - } - - bool ParseCksum(const char *s); - bool Parse(const char *s); - - bool IsSupportedMode() const - { - return Mode != 'U' && Mode != '^'; - } - - CHashPair(): - Mode(0) - , IsBSD(false) - , Escape(false) - , Size_from_Arc_Defined(false) - , Size_from_Disk_Defined(false) - // , HashLengthInBits(0) - , Size_from_Arc(0) - , Size_from_Disk(0) - {} -}; - - -Z7_CLASS_IMP_CHandler_IInArchive_3( - IArchiveGetRawProps, - /* public IGetArchiveHashHandler, */ - IOutArchive, - ISetProperties -) - bool _isArc; - bool _supportWindowsBackslash; - bool _crcSize_WasSet; - UInt64 _phySize; - CObjectVector HashPairs; - UString _nameExtenstion; - // UString _method_fromName; - AString _pgpMethod; - bool _is_CksumMode; - bool _is_PgpMethod; - bool _is_ZeroMode; - bool _are_there_Tags; - bool _are_there_Dirs; - bool _hashSize_Defined; - unsigned _hashSize; - UInt32 _crcSize; - UStringVector _methods; - CHashOptionsLocal _options; - - void ClearVars(); - - void InitProps() - { - _supportWindowsBackslash = true; - _crcSize_WasSet = false; - _crcSize = 4; - _methods.Clear(); - _options.Init_HashOptionsLocal(); - } - - bool CanUpdate() const - { - if (!_isArc || _is_PgpMethod || _is_CksumMode) - return false; - return true; - } - - HRESULT SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value); - -public: - CHandler(); -}; - -} - -void Codecs_AddHashArcHandler(CCodecs *codecs); - -#endif - - -#endif +// HashCalc.h + +#ifndef ZIP7_INC_HASH_CALC_H +#define ZIP7_INC_HASH_CALC_H + +#include "../../../Common/UTFConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../Common/CreateCoder.h" +#include "../../Common/MethodProps.h" + +#include "DirItem.h" +#include "IFileExtractCallback.h" + +const unsigned k_HashCalc_DigestSize_Max = 64; +const unsigned k_HashCalc_ExtraSize = 8; +const unsigned k_HashCalc_NumGroups = 4; + +/* + if (size <= 8) : upper case : reversed byte order : it shows 32-bit/64-bit number, if data contains little-endian number + if (size > 8) : lower case : original byte order (as big-endian byte sequence) +*/ +void HashHexToString(char *dest, const Byte *data, size_t size); + +enum +{ + k_HashCalc_Index_Current, + k_HashCalc_Index_DataSum, + k_HashCalc_Index_NamesSum, + k_HashCalc_Index_StreamsSum +}; + +struct CHasherState +{ + CMyComPtr Hasher; + AString Name; + UInt32 DigestSize; + UInt64 NumSums[k_HashCalc_NumGroups]; + Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max + k_HashCalc_ExtraSize]; + + void InitDigestGroup(unsigned groupIndex) + { + NumSums[groupIndex] = 0; + memset(Digests[groupIndex], 0, sizeof(Digests[groupIndex])); + } + + const Byte *GetExtraData_for_Group(unsigned groupIndex) const + { + return Digests[groupIndex] + k_HashCalc_DigestSize_Max; + } + + unsigned GetNumExtraBytes_for_Group(unsigned groupIndex) const + { + const Byte *p = GetExtraData_for_Group(groupIndex); + // we use little-endian to read extra bytes + for (unsigned i = k_HashCalc_ExtraSize; i != 0; i--) + if (p[i - 1] != 0) + return i; + return 0; + } + + void AddDigest(unsigned groupIndex, const Byte *data); + + void WriteToString(unsigned digestIndex, char *s) const; +}; + + +Z7_PURE_INTERFACES_BEGIN + + +DECLARE_INTERFACE(IHashCalc) +{ + virtual void InitForNewFile() = 0; + virtual void Update(const void *data, UInt32 size) = 0; + virtual void SetSize(UInt64 size) = 0; + virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0; +}; + +Z7_PURE_INTERFACES_END + +struct CHashBundle Z7_final: public IHashCalc +{ + CObjectVector Hashers; + + UInt64 NumDirs; + UInt64 NumFiles; + UInt64 NumAltStreams; + UInt64 FilesSize; + UInt64 AltStreamsSize; + UInt64 NumErrors; + + UInt64 CurSize; + + UString MainName; + UString FirstFileName; + + HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods); + + // void Init() {} + CHashBundle() + { + NumDirs = NumFiles = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0; + } + + void InitForNewFile() Z7_override; + void Update(const void *data, UInt32 size) Z7_override; + void SetSize(UInt64 size) Z7_override; + void Final(bool isDir, bool isAltStream, const UString &path) Z7_override; +}; + +Z7_PURE_INTERFACES_BEGIN + +// INTERFACE_IDirItemsCallback(x) + +#define Z7_IFACEN_IHashCallbackUI(x) \ + virtual HRESULT StartScanning() x \ + virtual HRESULT FinishScanning(const CDirItemsStat &st) x \ + virtual HRESULT SetNumFiles(UInt64 numFiles) x \ + virtual HRESULT SetTotal(UInt64 size) x \ + virtual HRESULT SetCompleted(const UInt64 *completeValue) x \ + virtual HRESULT CheckBreak() x \ + virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x \ + virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x \ + virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \ + virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x \ + virtual HRESULT AfterLastFile(CHashBundle &hb) x \ + +Z7_IFACE_DECL_PURE_(IHashCallbackUI, IDirItemsCallback) + +Z7_PURE_INTERFACES_END + + +struct CHashOptionsLocal +{ + CBoolPair HashMode_Zero; + CBoolPair HashMode_Tag; + CBoolPair HashMode_Dirs; + CBoolPair HashMode_OnlyHash; + + void Init_HashOptionsLocal() + { + HashMode_Zero.Init(); + HashMode_Tag.Init(); + HashMode_Dirs.Init(); + HashMode_OnlyHash.Init(); + // HashMode_Dirs = true; // for debug + } + + CHashOptionsLocal() + { + Init_HashOptionsLocal(); + } + + bool ParseFlagCharOption(wchar_t c, bool val) + { + c = MyCharLower_Ascii(c); + if (c == 'z') HashMode_Zero.SetVal_as_Defined(val); + else if (c == 't') HashMode_Tag.SetVal_as_Defined(val); + else if (c == 'd') HashMode_Dirs.SetVal_as_Defined(val); + else if (c == 'h') HashMode_OnlyHash.SetVal_as_Defined(val); + else return false; + return true; + } + + bool ParseString(const UString &s) + { + for (unsigned i = 0; i < s.Len();) + { + const wchar_t c = s[i++]; + bool val = true; + if (i < s.Len()) + { + const wchar_t next = s[i]; + if (next == '-') + { + val = false; + i++; + } + } + if (!ParseFlagCharOption(c, val)) + return false; + } + return true; + } +}; + + +struct CHashOptions + // : public CHashOptionsLocal +{ + UStringVector Methods; + // UString HashFilePath; + + bool PreserveATime; + bool OpenShareForWrite; + bool StdInMode; + bool AltStreamsMode; + CBoolPair SymLinks; + + NWildcard::ECensorPathMode PathMode; + + CHashOptions(): + PreserveATime(false), + OpenShareForWrite(false), + StdInMode(false), + AltStreamsMode(false), + PathMode(NWildcard::k_RelatPath) {} +}; + + +HRESULT HashCalc( + DECL_EXTERNAL_CODECS_LOC_VARS + const NWildcard::CCensor &censor, + const CHashOptions &options, + AString &errorInfo, + IHashCallbackUI *callback); + + + +#ifndef Z7_SFX + +namespace NHash { + +struct CHashPair +{ + CByteBuffer Hash; + char Mode; + bool IsBSD; + bool Escape; + bool Size_from_Arc_Defined; + bool Size_from_Disk_Defined; + AString Method; + AString Name; + + AString FullLine; + AString HashString; + // unsigned HashLengthInBits; + + // AString MethodName; + UInt64 Size_from_Arc; + UInt64 Size_from_Disk; + + bool IsDir() const; + + void Get_UString_Path(UString &path) const + { + path.Empty(); + if (!ConvertUTF8ToUnicode(Name, path)) + return; + } + + bool ParseCksum(const char *s); + bool Parse(const char *s); + + bool IsSupportedMode() const + { + return Mode != 'U' && Mode != '^'; + } + + CHashPair(): + Mode(0) + , IsBSD(false) + , Escape(false) + , Size_from_Arc_Defined(false) + , Size_from_Disk_Defined(false) + // , HashLengthInBits(0) + , Size_from_Arc(0) + , Size_from_Disk(0) + {} +}; + + +Z7_CLASS_IMP_CHandler_IInArchive_3( + IArchiveGetRawProps, + /* public IGetArchiveHashHandler, */ + IOutArchive, + ISetProperties +) + bool _isArc; + bool _supportWindowsBackslash; + bool _crcSize_WasSet; + UInt64 _phySize; + CObjectVector HashPairs; + UString _nameExtenstion; + // UString _method_fromName; + AString _pgpMethod; + bool _is_CksumMode; + bool _is_PgpMethod; + bool _is_ZeroMode; + bool _are_there_Tags; + bool _are_there_Dirs; + bool _hashSize_Defined; + unsigned _hashSize; + UInt32 _crcSize; + UStringVector _methods; + CHashOptionsLocal _options; + + void ClearVars(); + + void InitProps() + { + _supportWindowsBackslash = true; + _crcSize_WasSet = false; + _crcSize = 4; + _methods.Clear(); + _options.Init_HashOptionsLocal(); + } + + bool CanUpdate() const + { + if (!_isArc || _is_PgpMethod || _is_CksumMode) + return false; + return true; + } + + HRESULT SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value); + +public: + CHandler(); +}; + +} + +void Codecs_AddHashArcHandler(CCodecs *codecs); + +#endif + + +#endif diff --git a/CPP/7zip/UI/Common/IFileExtractCallback.h b/CPP/7zip/UI/Common/IFileExtractCallback.h index 04e85e096..dd5c0d721 100644 --- a/CPP/7zip/UI/Common/IFileExtractCallback.h +++ b/CPP/7zip/UI/Common/IFileExtractCallback.h @@ -1,112 +1,112 @@ -// IFileExtractCallback.h - -#ifndef ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H -#define ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H - -#include "../../../Common/MyString.h" - -#include "../../IDecl.h" - -#include "LoadCodecs.h" -#include "OpenArchive.h" - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACE_CONSTR_FOLDERARC_SUB(i, base, n) \ - Z7_DECL_IFACE_7ZIP_SUB(i, base, 1, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -#define Z7_IFACE_CONSTR_FOLDERARC(i, n) \ - Z7_IFACE_CONSTR_FOLDERARC_SUB(i, IUnknown, n) - -namespace NOverwriteAnswer -{ - enum EEnum - { - kYes, - kYesToAll, - kNo, - kNoToAll, - kAutoRename, - kCancel - }; -} - - -/* ---------- IFolderArchiveExtractCallback ---------- -is implemented by - Console/ExtractCallbackConsole.h CExtractCallbackConsole - FileManager/ExtractCallback.h CExtractCallbackImp - FAR/ExtractEngine.cpp CExtractCallBackImp: (QueryInterface is not supported) - -IID_IFolderArchiveExtractCallback is requested by: - - Agent/ArchiveFolder.cpp - CAgentFolder::CopyTo(..., IFolderOperationsExtractCallback *callback) - is sent to IArchiveFolder::Extract() - - - FileManager/PanelCopy.cpp - CPanel::CopyTo(), if (options->testMode) - is sent to IArchiveFolder::Extract() - - IFolderArchiveExtractCallback is used by Common/ArchiveExtractCallback.cpp -*/ - -#define Z7_IFACEM_IFolderArchiveExtractCallback(x) \ - x(AskOverwrite( \ - const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \ - const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \ - Int32 *answer)) \ - x(PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) \ - x(MessageError(const wchar_t *message)) \ - x(SetOperationResult(Int32 opRes, Int32 encrypted)) \ - -Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveExtractCallback, IProgress, 0x07) - -#define Z7_IFACEM_IFolderArchiveExtractCallback2(x) \ - x(ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveExtractCallback2, 0x08) - -/* ---------- IExtractCallbackUI ---------- -is implemented by - Console/ExtractCallbackConsole.h CExtractCallbackConsole - FileManager/ExtractCallback.h CExtractCallbackImp -*/ - -#ifdef Z7_NO_CRYPTO - #define Z7_IFACEM_IExtractCallbackUI_Crypto(px) -#else - #define Z7_IFACEM_IExtractCallbackUI_Crypto(px) \ - virtual HRESULT SetPassword(const UString &password) px -#endif - -#define Z7_IFACEN_IExtractCallbackUI(px) \ - virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) px \ - virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) px \ - virtual HRESULT ThereAreNoFiles() px \ - virtual HRESULT ExtractResult(HRESULT result) px \ - Z7_IFACEM_IExtractCallbackUI_Crypto(px) - -// IExtractCallbackUI - is non-COM interface -// IFolderArchiveExtractCallback - is COM interface -// Z7_IFACE_DECL_PURE_(IExtractCallbackUI, IFolderArchiveExtractCallback) -Z7_IFACE_DECL_PURE(IExtractCallbackUI) - - - -#define Z7_IFACEM_IGetProp(x) \ - x(GetProp(PROPID propID, PROPVARIANT *value)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IGetProp, 0x20) - -#define Z7_IFACEM_IFolderExtractToStreamCallback(x) \ - x(UseExtractToStream(Int32 *res)) \ - x(GetStream7(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp)) \ - x(PrepareOperation7(Int32 askExtractMode)) \ - x(SetOperationResult8(Int32 resultEOperationResult, Int32 encrypted, UInt64 size)) \ - -Z7_IFACE_CONSTR_FOLDERARC(IFolderExtractToStreamCallback, 0x31) - -Z7_PURE_INTERFACES_END - -#endif +// IFileExtractCallback.h + +#ifndef ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H +#define ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H + +#include "../../../Common/MyString.h" + +#include "../../IDecl.h" + +#include "LoadCodecs.h" +#include "OpenArchive.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_FOLDERARC_SUB(i, base, n) \ + Z7_DECL_IFACE_7ZIP_SUB(i, base, 1, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACE_CONSTR_FOLDERARC(i, n) \ + Z7_IFACE_CONSTR_FOLDERARC_SUB(i, IUnknown, n) + +namespace NOverwriteAnswer +{ + enum EEnum + { + kYes, + kYesToAll, + kNo, + kNoToAll, + kAutoRename, + kCancel + }; +} + + +/* ---------- IFolderArchiveExtractCallback ---------- +is implemented by + Console/ExtractCallbackConsole.h CExtractCallbackConsole + FileManager/ExtractCallback.h CExtractCallbackImp + FAR/ExtractEngine.cpp CExtractCallBackImp: (QueryInterface is not supported) + +IID_IFolderArchiveExtractCallback is requested by: + - Agent/ArchiveFolder.cpp + CAgentFolder::CopyTo(..., IFolderOperationsExtractCallback *callback) + is sent to IArchiveFolder::Extract() + + - FileManager/PanelCopy.cpp + CPanel::CopyTo(), if (options->testMode) + is sent to IArchiveFolder::Extract() + + IFolderArchiveExtractCallback is used by Common/ArchiveExtractCallback.cpp +*/ + +#define Z7_IFACEM_IFolderArchiveExtractCallback(x) \ + x(AskOverwrite( \ + const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \ + const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \ + Int32 *answer)) \ + x(PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) \ + x(MessageError(const wchar_t *message)) \ + x(SetOperationResult(Int32 opRes, Int32 encrypted)) \ + +Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveExtractCallback, IProgress, 0x07) + +#define Z7_IFACEM_IFolderArchiveExtractCallback2(x) \ + x(ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveExtractCallback2, 0x08) + +/* ---------- IExtractCallbackUI ---------- +is implemented by + Console/ExtractCallbackConsole.h CExtractCallbackConsole + FileManager/ExtractCallback.h CExtractCallbackImp +*/ + +#ifdef Z7_NO_CRYPTO + #define Z7_IFACEM_IExtractCallbackUI_Crypto(px) +#else + #define Z7_IFACEM_IExtractCallbackUI_Crypto(px) \ + virtual HRESULT SetPassword(const UString &password) px +#endif + +#define Z7_IFACEN_IExtractCallbackUI(px) \ + virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) px \ + virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) px \ + virtual HRESULT ThereAreNoFiles() px \ + virtual HRESULT ExtractResult(HRESULT result) px \ + Z7_IFACEM_IExtractCallbackUI_Crypto(px) + +// IExtractCallbackUI - is non-COM interface +// IFolderArchiveExtractCallback - is COM interface +// Z7_IFACE_DECL_PURE_(IExtractCallbackUI, IFolderArchiveExtractCallback) +Z7_IFACE_DECL_PURE(IExtractCallbackUI) + + + +#define Z7_IFACEM_IGetProp(x) \ + x(GetProp(PROPID propID, PROPVARIANT *value)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IGetProp, 0x20) + +#define Z7_IFACEM_IFolderExtractToStreamCallback(x) \ + x(UseExtractToStream(Int32 *res)) \ + x(GetStream7(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp)) \ + x(PrepareOperation7(Int32 askExtractMode)) \ + x(SetOperationResult8(Int32 resultEOperationResult, Int32 encrypted, UInt64 size)) \ + +Z7_IFACE_CONSTR_FOLDERARC(IFolderExtractToStreamCallback, 0x31) + +Z7_PURE_INTERFACES_END + +#endif diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp index 999d3ecaf..6bf53ead0 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.cpp +++ b/CPP/7zip/UI/Common/LoadCodecs.cpp @@ -1,1337 +1,1337 @@ -// LoadCodecs.cpp - -/* -Z7_EXTERNAL_CODECS ---------------- - CCodecs::Load() tries to detect the directory with plugins. - It stops the checking, if it can find any of the following items: - - 7z.dll file - - "Formats" subdir - - "Codecs" subdir - The order of check: - 1) directory of client executable - 2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**] - The order for HKEY_* : Path** : - - HKEY_CURRENT_USER : PathXX - - HKEY_LOCAL_MACHINE : PathXX - - HKEY_CURRENT_USER : Path - - HKEY_LOCAL_MACHINE : Path - PathXX is Path32 in 32-bit code - PathXX is Path64 in 64-bit code - - -EXPORT_CODECS -------------- - if (Z7_EXTERNAL_CODECS) is defined, then the code exports internal - codecs of client from CCodecs object to external plugins. - 7-Zip doesn't use that feature. 7-Zip uses the scheme: - - client application without internal plugins. - - 7z.dll module contains all (or almost all) plugins. - 7z.dll can use codecs from another plugins, if required. -*/ - - -#include "StdAfx.h" - -#include "../../../Common/MyCom.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/PropVariant.h" - -#include "LoadCodecs.h" - -#include "../../ICoder.h" -#include "../../Common/RegisterArc.h" -#include "../../Common/RegisterCodec.h" - -#ifdef Z7_EXTERNAL_CODECS -// #define EXPORT_CODECS -#endif - -#ifdef Z7_EXTERNAL_CODECS - -#include "../../../Windows/FileFind.h" -#include "../../../Windows/DLL.h" - -#ifdef _WIN32 -#include "../../../Windows/FileName.h" -#include "../../../Windows/Registry.h" -#endif - -using namespace NWindows; -using namespace NFile; - - -#define kCodecsFolderName FTEXT("Codecs") -#define kFormatsFolderName FTEXT("Formats") - - -static CFSTR const kMainDll = - #ifdef _WIN32 - FTEXT("7z.dll"); - #else - FTEXT("7z.so"); - #endif - - -#ifdef _WIN32 - -static LPCTSTR const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); -static LPCWSTR const kProgramPathValue = L"Path"; -static LPCWSTR const kProgramPath2Value = L"Path" - #ifdef _WIN64 - L"64"; - #else - L"32"; - #endif - -static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path) -{ - NRegistry::CKey key; - if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) - { - UString pathU; - if (key.QueryValue(value, pathU) == ERROR_SUCCESS) - { - path = us2fs(pathU); - NName::NormalizeDirPathPrefix(path); - return NFind::DoesFileExist_Raw(path + kMainDll); - } - } - return false; -} - -#endif // _WIN32 - -#endif // Z7_EXTERNAL_CODECS - - -static const unsigned kNumArcsMax = 72; -static unsigned g_NumArcs = 0; -static const CArcInfo *g_Arcs[kNumArcsMax]; - -void RegisterArc(const CArcInfo *arcInfo) throw() -{ - if (g_NumArcs < kNumArcsMax) - { - g_Arcs[g_NumArcs] = arcInfo; - g_NumArcs++; - } - // else throw 1; -} - -/* -static void SplitString(const UString &srcString, UStringVector &destStrings) -{ - destStrings.Clear(); - UString s; - unsigned len = srcString.Len(); - if (len == 0) - return; - for (unsigned i = 0; i < len; i++) - { - wchar_t c = srcString[i]; - if (c == L' ') - { - if (!s.IsEmpty()) - { - destStrings.Add(s); - s.Empty(); - } - } - else - s += c; - } - if (!s.IsEmpty()) - destStrings.Add(s); -} -*/ - -int CArcInfoEx::FindExtension(const UString &ext) const -{ - FOR_VECTOR (i, Exts) - if (ext.IsEqualTo_NoCase(Exts[i].Ext)) - return (int)i; - return -1; -} - -void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) -{ - UStringVector exts, addExts; - SplitString(ext, exts); - SplitString(addExt, addExts); - FOR_VECTOR (i, exts) - { - CArcExtInfo extInfo; - extInfo.Ext = exts[i]; - if (i < addExts.Size()) - { - extInfo.AddExt = addExts[i]; - if (extInfo.AddExt == L"*") - extInfo.AddExt.Empty(); - } - Exts.Add(extInfo); - } -} - -#ifndef Z7_SFX - -static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector &signatures) -{ - signatures.Clear(); - while (size != 0) - { - const unsigned len = *data++; - size--; - if (len > size) - return false; - signatures.AddNew().CopyFrom(data, len); - data += len; - size -= len; - } - return true; -} - -#endif // Z7_SFX - -// #include - -#ifdef Z7_EXTERNAL_CODECS - -static FString GetBaseFolderPrefixFromRegistry() -{ - FString moduleFolderPrefix = NDLL::GetModuleDirPrefix(); - - #ifdef _WIN32 - if ( !NFind::DoesFileOrDirExist(moduleFolderPrefix + kMainDll) - && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kCodecsFolderName) - && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kFormatsFolderName)) - { - FString path; - if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path; - if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path; - if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path; - if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path; - } - #endif - - // printf("\nmoduleFolderPrefix = %s\n", (const char *)GetAnsiString(moduleFolderPrefix)); - return moduleFolderPrefix; -} - - -static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index, - PROPID propId, CLSID &clsId, bool &isAssigned) -{ - NCOM::CPropVariant prop; - isAssigned = false; - RINOK(getMethodProperty(index, propId, &prop)) - if (prop.vt == VT_BSTR) - { - if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) - return E_FAIL; - isAssigned = true; - clsId = *(const GUID *)(const void *)prop.bstrVal; - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - - -static HRESULT GetMethodBoolProp(Func_GetMethodProperty getMethodProperty, UInt32 index, - PROPID propId, bool &resVal, bool &isAssigned) -{ - NCOM::CPropVariant prop; - resVal = false; - isAssigned = false; - RINOK(getMethodProperty(index, propId, &prop)) - if (prop.vt == VT_BOOL) - { - isAssigned = true; - resVal = VARIANT_BOOLToBool(prop.boolVal); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" -#endif - -#ifdef _WIN32 -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -#endif - -#define MY_GET_FUNC(dest, type, lib, func) \ - dest = Z7_GET_PROC_ADDRESS(type, lib.Get_HMODULE(), func); -// #define MY_GET_FUNC(dest, type, func) dest = (type)(func); - -#define MY_GET_FUNC_LOC(dest, type, lib, func) \ - type dest; MY_GET_FUNC(dest, type, lib, func) - -HRESULT CCodecs::LoadCodecs() -{ - CCodecLib &lib = Libs.Back(); - - MY_GET_FUNC (lib.CreateDecoder, Func_CreateDecoder, lib.Lib, "CreateDecoder") - MY_GET_FUNC (lib.CreateEncoder, Func_CreateEncoder, lib.Lib, "CreateEncoder") - MY_GET_FUNC (lib.GetMethodProperty, Func_GetMethodProperty, lib.Lib, "GetMethodProperty") - - if (lib.GetMethodProperty) - { - UInt32 numMethods = 1; - MY_GET_FUNC_LOC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib, "GetNumberOfMethods") - if (getNumberOfMethods) - { - RINOK(getNumberOfMethods(&numMethods)) - } - for (UInt32 i = 0; i < numMethods; i++) - { - CDllCodecInfo info; - info.LibIndex = Libs.Size() - 1; - info.CodecIndex = i; - RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)) - RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)) - RINOK(GetMethodBoolProp(lib.GetMethodProperty, i, NMethodPropID::kIsFilter, info.IsFilter, info.IsFilter_Assigned)) - Codecs.Add(info); - } - } - - MY_GET_FUNC_LOC (getHashers, Func_GetHashers, lib.Lib, "GetHashers") - if (getHashers) - { - RINOK(getHashers(&lib.ComHashers)) - if (lib.ComHashers) - { - UInt32 numMethods = lib.ComHashers->GetNumHashers(); - for (UInt32 i = 0; i < numMethods; i++) - { - CDllHasherInfo info; - info.LibIndex = Libs.Size() - 1; - info.HasherIndex = i; - Hashers.Add(info); - } - } - } - - return S_OK; -} - -static HRESULT GetProp( - Func_GetHandlerProperty getProp, - Func_GetHandlerProperty2 getProp2, - UInt32 index, PROPID propID, NCOM::CPropVariant &prop) -{ - if (getProp2) - return getProp2(index, propID, &prop); - return getProp(propID, &prop); -} - -static HRESULT GetProp_Bool( - Func_GetHandlerProperty getProp, - Func_GetHandlerProperty2 getProp2, - UInt32 index, PROPID propID, bool &res) -{ - res = false; - NCOM::CPropVariant prop; - RINOK(GetProp(getProp, getProp2, index, propID, prop)) - if (prop.vt == VT_BOOL) - res = VARIANT_BOOLToBool(prop.boolVal); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -static HRESULT GetProp_UInt32( - Func_GetHandlerProperty getProp, - Func_GetHandlerProperty2 getProp2, - UInt32 index, PROPID propID, UInt32 &res, bool &defined) -{ - res = 0; - defined = false; - NCOM::CPropVariant prop; - RINOK(GetProp(getProp, getProp2, index, propID, prop)) - if (prop.vt == VT_UI4) - { - res = prop.ulVal; - defined = true; - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -static HRESULT GetProp_String( - Func_GetHandlerProperty getProp, - Func_GetHandlerProperty2 getProp2, - UInt32 index, PROPID propID, UString &res) -{ - res.Empty(); - NCOM::CPropVariant prop; - RINOK(GetProp(getProp, getProp2, index, propID, prop)) - if (prop.vt == VT_BSTR) - res.SetFromBstr(prop.bstrVal); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -static HRESULT GetProp_RawData( - Func_GetHandlerProperty getProp, - Func_GetHandlerProperty2 getProp2, - UInt32 index, PROPID propID, CByteBuffer &bb) -{ - bb.Free(); - NCOM::CPropVariant prop; - RINOK(GetProp(getProp, getProp2, index, propID, prop)) - if (prop.vt == VT_BSTR) - { - UINT len = ::SysStringByteLen(prop.bstrVal); - bb.CopyFrom((const Byte *)prop.bstrVal, len); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -static const UInt32 kArcFlagsPars[] = -{ - NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName, - NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams, - NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure -}; - -HRESULT CCodecs::LoadFormats() -{ - const NDLL::CLibrary &lib = Libs.Back().Lib; - - Func_GetHandlerProperty getProp = NULL; - MY_GET_FUNC_LOC (getProp2, Func_GetHandlerProperty2, lib, "GetHandlerProperty2") - MY_GET_FUNC_LOC (getIsArc, Func_GetIsArc, lib, "GetIsArc") - - UInt32 numFormats = 1; - - if (getProp2) - { - MY_GET_FUNC_LOC (getNumberOfFormats, Func_GetNumberOfFormats, lib, "GetNumberOfFormats") - if (getNumberOfFormats) - { - RINOK(getNumberOfFormats(&numFormats)) - } - } - else - { - MY_GET_FUNC (getProp, Func_GetHandlerProperty, lib, "GetHandlerProperty") - if (!getProp) - return S_OK; - } - - for (UInt32 i = 0; i < numFormats; i++) - { - CArcInfoEx item; - item.LibIndex = (int)(Libs.Size() - 1); - item.FormatIndex = i; - - RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name)) - - { - NCOM::CPropVariant prop; - if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK) - continue; - if (prop.vt != VT_BSTR) - continue; - if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) - return E_FAIL; - item.ClassID = *(const GUID *)(const void *)prop.bstrVal; - prop.Clear(); - } - - UString ext, addExt; - RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext)) - RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt)) - item.AddExts(ext, addExt); - - GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled); - bool flags_Defined = false; - RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined)) - item.NewInterface = flags_Defined; - if (!flags_Defined) // && item.UpdateEnabled - { - // support for DLL version before 9.31: - for (unsigned j = 0; j < Z7_ARRAY_SIZE(kArcFlagsPars); j += 2) - { - bool val = false; - GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val); - if (val) - item.Flags |= kArcFlagsPars[j + 1]; - } - } - - { - bool defined = false; - RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kTimeFlags, item.TimeFlags, defined)) - } - - CByteBuffer sig; - RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)) - if (sig.Size() != 0) - item.Signatures.Add(sig); - else - { - RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig)) - ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures); - } - - bool signatureOffset_Defined; - RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined)) - - // bool version_Defined; - // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined)); - - if (getIsArc) - getIsArc(i, &item.IsArcFunc); - - Formats.Add(item); - } - return S_OK; -} - -#ifdef Z7_LARGE_PAGES -extern "C" -{ - extern SIZE_T g_LargePageSize; -} -#endif - - -void CCodecs::AddLastError(const FString &path) -{ - const HRESULT res = GetLastError_noZero_HRESULT(); - CCodecError &error = Errors.AddNew(); - error.Path = path; - error.ErrorCode = res; -} - - -static bool IsSupportedDll(CCodecLib &lib) -{ - MY_GET_FUNC_LOC ( - f_GetModuleProp, - Func_GetModuleProp, lib.Lib, - "GetModuleProp") - /* p7zip and 7-Zip before v23 used virtual destructor in IUnknown, - if _WIN32 is not defined */ - UInt32 flags = - #ifdef _WIN32 - NModuleInterfaceType::k_IUnknown_VirtDestructor_No; - #else - NModuleInterfaceType::k_IUnknown_VirtDestructor_Yes; - #endif - if (f_GetModuleProp) - { - { - NCOM::CPropVariant prop; - if (f_GetModuleProp(NModulePropID::kInterfaceType, &prop) == S_OK) - { - if (prop.vt == VT_UI4) - flags = prop.ulVal; - else if (prop.vt != VT_EMPTY) - return false; - } - } - { - NCOM::CPropVariant prop; - if (f_GetModuleProp(NModulePropID::kVersion, &prop) == S_OK) - { - if (prop.vt == VT_UI4) - lib.Version = prop.ulVal; - } - } - } - if ( - flags - // (flags & NModuleFlags::kMask) - != NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule) - return false; - return true; -} - - -HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK) -{ - if (loadedOK) - *loadedOK = false; - - // needCheckDll = 1; - - #ifdef _WIN32 - if (needCheckDll) - { - NDLL::CLibrary lib; - if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) - { - /* if is not win32 - // %1 is not a valid Win32 application. - // #define ERROR_BAD_EXE_FORMAT 193L - */ - // return GetLastError_noZero_HRESULT(); - const DWORD lastError = GetLastError(); - if (lastError != ERROR_BAD_EXE_FORMAT) - { - CCodecError &error = Errors.AddNew(); - error.Path = dllPath; - error.Message = "cannot load file as datafile library"; - error.ErrorCode = HRESULT_FROM_WIN32(lastError); - } - return S_OK; - } - } - #else - UNUSED_VAR(needCheckDll) - #endif - - Libs.AddNew(); - CCodecLib &lib = Libs.Back(); - lib.Path = dllPath; - bool used = false; - // HRESULT res = S_OK; - - if (lib.Lib.Load(dllPath)) - { - if (!IsSupportedDll(lib)) - { - CCodecError &error = Errors.AddNew(); - error.Path = dllPath; - error.Message = "the module is not compatible with program"; - } - else - { - if (loadedOK) - *loadedOK = true; - /* - #ifdef NEW_FOLDER_INTERFACE - lib.LoadIcons(); - #endif - */ - - /* - { - MY_GET_FUNC_LOC (_libStartup, Func_libStartup, lib.Lib, "LibStartup") - if (_libStartup) - { - HRESULT res = _libStartup(); - if (res != 0) - { - CCodecError &error = Errors.AddNew(); - error.Path = dllPath; - error.ErrorCode = res; - } - } - } - */ - - #ifdef Z7_LARGE_PAGES - if (g_LargePageSize != 0) - { - MY_GET_FUNC_LOC (setLargePageMode, Func_SetLargePageMode, lib.Lib, "SetLargePageMode") - if (setLargePageMode) - setLargePageMode(); - } - #endif - - if (CaseSensitive_Change) - { - MY_GET_FUNC_LOC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib, "SetCaseSensitive") - if (setCaseSensitive) - setCaseSensitive(CaseSensitive ? 1 : 0); - } - - /* - { - MY_GET_FUNC_LOC (setClientVersion, Func_SetClientVersion, lib.Lib, "SetClientVersion") - if (setClientVersion) - { - // const UInt32 kVersion = (MY_VER_MAJOR << 16) | MY_VER_MINOR; - setClientVersion(g_ClientVersion); - } - } - */ - - - MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib, "CreateObject") - { - unsigned startSize = Codecs.Size() + Hashers.Size(); - HRESULT res = LoadCodecs(); - if (startSize != Codecs.Size() + Hashers.Size()) - used = true; - if (res == S_OK && lib.CreateObject) - { - startSize = Formats.Size(); - res = LoadFormats(); - if (startSize != Formats.Size()) - used = true; - } - if (res != S_OK) - { - CCodecError &error = Errors.AddNew(); - error.Path = dllPath; - error.ErrorCode = res; - } - } - // plugins can use non-7-zip dlls, so we silently ignore non7zip DLLs - /* - if (!used) - { - CCodecError &error = Errors.AddNew(); - error.Path = dllPath; - error.Message = "no 7-Zip code"; - } - */ - } - } - else - { - AddLastError(dllPath); - } - - if (!used) - Libs.DeleteBack(); - - return S_OK; -} - -HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPath) -{ - if (!NFile::NFind::DoesDirExist_FollowLink(folderPath)) - // if (!NFile::NFind::DoesDirExist(folderPath)) - { - // AddLastError(folderPath); - return S_OK; - } - - FString folderPrefix = folderPath; - folderPrefix.Add_PathSepar(); - - NFile::NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(folderPrefix); - NFile::NFind::CDirEntry fi; - for (;;) - { - bool found; - if (!enumerator.Next(fi, found)) - { - // it can be wrong Symbolic link to folder here - AddLastError(folderPath); - break; - // return GetLastError_noZero_HRESULT(); - } - if (!found) - break; - #ifdef _WIN32 - if (fi.IsDir()) - continue; - #else - if (enumerator.DirEntry_IsDir(fi, true)) // followLink - continue; - #endif - - RINOK(LoadDll(folderPrefix + fi.Name, true)) - } - return S_OK; -} - -void CCodecs::CloseLibs() -{ - // OutputDebugStringA("~CloseLibs start"); - /* - WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected, - if it's called from another FreeLibrary() call. - So we need to call FreeLibrary() before global destructors. - - Also we free global links from DLLs to object of this module before CLibrary::Free() call. - */ - - FOR_VECTOR(i, Libs) - { - const CCodecLib &lib = Libs[i]; - if (lib.SetCodecs) - lib.SetCodecs(NULL); - } - - // OutputDebugStringA("~CloseLibs after SetCodecs"); - Libs.Clear(); - // OutputDebugStringA("~CloseLibs end"); -} - -#endif // Z7_EXTERNAL_CODECS - - -HRESULT CCodecs::Load() -{ - /* - #ifdef NEW_FOLDER_INTERFACE - InternalIcons.LoadIcons(g_hInstance); - #endif - */ - - Formats.Clear(); - - #ifdef Z7_EXTERNAL_CODECS - Errors.Clear(); - MainDll_ErrorPath.Empty(); - Codecs.Clear(); - Hashers.Clear(); - #endif - - for (UInt32 i = 0; i < g_NumArcs; i++) - { - const CArcInfo &arc = *g_Arcs[i]; - CArcInfoEx item; - - item.Name = arc.Name; - item.CreateInArchive = arc.CreateInArchive; - item.IsArcFunc = arc.IsArc; - item.Flags = arc.Flags; - - { - UString e, ae; - if (arc.Ext) - e = arc.Ext; - if (arc.AddExt) - ae = arc.AddExt; - item.AddExts(e, ae); - } - - #ifndef Z7_SFX - - item.CreateOutArchive = arc.CreateOutArchive; - item.UpdateEnabled = (arc.CreateOutArchive != NULL); - item.SignatureOffset = arc.SignatureOffset; - // item.Version = MY_VER_MIX; - item.NewInterface = true; - - if (arc.IsMultiSignature()) - ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); - else - { - if (arc.SignatureSize != 0) // 21.04 - item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); - } - - #endif - - Formats.Add(item); - } - - // printf("\nLoad codecs \n"); - - #ifdef Z7_EXTERNAL_CODECS - const FString baseFolder = GetBaseFolderPrefixFromRegistry(); - { - bool loadedOK; - RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK)) - if (!loadedOK) - MainDll_ErrorPath = kMainDll; - } - RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName)) - RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName)) - - NeedSetLibCodecs = true; - - if (Libs.Size() == 0) - NeedSetLibCodecs = false; - else if (Libs.Size() == 1) - { - // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module. - #ifndef EXPORT_CODECS - if (g_NumArcs == 0) - NeedSetLibCodecs = false; - #endif - } - - if (NeedSetLibCodecs) - { - /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c) - old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */ - - FOR_VECTOR(i, Libs) - { - CCodecLib &lib = Libs[i]; - MY_GET_FUNC (lib.SetCodecs, Func_SetCodecs, lib.Lib, "SetCodecs") - if (lib.SetCodecs) - { - RINOK(lib.SetCodecs(this)) - } - } - } - - #endif - - // we sort Formats to get fixed order of Formats after compilation. - Formats.Sort(); - return S_OK; -} - -#ifndef Z7_SFX - -int CCodecs::FindFormatForArchiveName(const UString &arcPath) const -{ - int dotPos = arcPath.ReverseFind_Dot(); - if (dotPos <= arcPath.ReverseFind_PathSepar()) - return -1; - const UString ext = arcPath.Ptr((unsigned)(dotPos + 1)); - if (ext.IsEmpty()) - return -1; - if (ext.IsEqualTo_Ascii_NoCase("exe")) - return -1; - FOR_VECTOR (i, Formats) - { - const CArcInfoEx &arc = Formats[i]; - /* - if (!arc.UpdateEnabled) - continue; - */ - if (arc.FindExtension(ext) >= 0) - return (int)i; - } - return -1; -} - -int CCodecs::FindFormatForExtension(const UString &ext) const -{ - if (ext.IsEmpty()) - return -1; - FOR_VECTOR (i, Formats) - if (Formats[i].FindExtension(ext) >= 0) - return (int)i; - return -1; -} - -int CCodecs::FindFormatForArchiveType(const UString &arcType) const -{ - FOR_VECTOR (i, Formats) - if (Formats[i].Name.IsEqualTo_NoCase(arcType)) - return (int)i; - return -1; -} - -bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const -{ - formatIndices.Clear(); - for (unsigned pos = 0; pos < arcType.Len();) - { - int pos2 = arcType.Find(L'.', pos); - if (pos2 < 0) - pos2 = (int)arcType.Len(); - const UString name = arcType.Mid(pos, (unsigned)pos2 - pos); - if (name.IsEmpty()) - return false; - int index = FindFormatForArchiveType(name); - if (index < 0 && name != L"*") - { - formatIndices.Clear(); - return false; - } - formatIndices.Add(index); - pos = (unsigned)pos2 + 1; - } - return true; -} - -#endif // Z7_SFX - - -#ifdef Z7_EXTERNAL_CODECS - -// #define EXPORT_CODECS - -#ifdef EXPORT_CODECS - -extern unsigned g_NumCodecs; -STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject); -STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject); -STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); -#define NUM_EXPORT_CODECS g_NumCodecs - -extern unsigned g_NumHashers; -STDAPI CreateHasher(UInt32 index, IHasher **hasher); -STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); -#define NUM_EXPORT_HASHERS g_NumHashers - -#else // EXPORT_CODECS - -#define NUM_EXPORT_CODECS 0 -#define NUM_EXPORT_HASHERS 0 - -#endif // EXPORT_CODECS - -Z7_COM7F_IMF(CCodecs::GetNumMethods(UInt32 *numMethods)) -{ - *numMethods = NUM_EXPORT_CODECS - #ifdef Z7_EXTERNAL_CODECS - + Codecs.Size() - #endif - ; - return S_OK; -} - -Z7_COM7F_IMF(CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - return GetMethodProperty(index, propID, value); - #endif - - #ifdef Z7_EXTERNAL_CODECS - const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; - - if (propID == NMethodPropID::kDecoderIsAssigned || - propID == NMethodPropID::kEncoderIsAssigned) - { - NCOM::CPropVariant prop; - prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ? - ci.DecoderIsAssigned : - ci.EncoderIsAssigned); - prop.Detach(value); - return S_OK; - } - - if (propID == NMethodPropID::kIsFilter && ci.IsFilter_Assigned) - { - NCOM::CPropVariant prop; - prop = (bool)ci.IsFilter; - prop.Detach(value); - return S_OK; - } - - const CCodecLib &lib = Libs[ci.LibIndex]; - return lib.GetMethodProperty(ci.CodecIndex, propID, value); - #else - return E_FAIL; - #endif -} - -Z7_COM7F_IMF(CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)) -{ - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - return CreateDecoder(index, iid, coder); - #endif - - #ifdef Z7_EXTERNAL_CODECS - const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; - if (ci.DecoderIsAssigned) - { - const CCodecLib &lib = Libs[ci.LibIndex]; - if (lib.CreateDecoder) - return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder); - if (lib.CreateObject) - return lib.CreateObject(&ci.Decoder, iid, (void **)coder); - } - return S_OK; - #else - return E_FAIL; - #endif -} - -Z7_COM7F_IMF(CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)) -{ - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - return CreateEncoder(index, iid, coder); - #endif - - #ifdef Z7_EXTERNAL_CODECS - const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; - if (ci.EncoderIsAssigned) - { - const CCodecLib &lib = Libs[ci.LibIndex]; - if (lib.CreateEncoder) - return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder); - if (lib.CreateObject) - return lib.CreateObject(&ci.Encoder, iid, (void **)coder); - } - return S_OK; - #else - return E_FAIL; - #endif -} - - -Z7_COM7F_IMF2(UInt32, CCodecs::GetNumHashers()) -{ - return NUM_EXPORT_HASHERS - #ifdef Z7_EXTERNAL_CODECS - + Hashers.Size() - #endif - ; -} - -Z7_COM7F_IMF(CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - #ifdef EXPORT_CODECS - if (index < g_NumHashers) - return ::GetHasherProp(index, propID, value); - #endif - - #ifdef Z7_EXTERNAL_CODECS - const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; - return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value); - #else - return E_FAIL; - #endif -} - -Z7_COM7F_IMF(CCodecs::CreateHasher(UInt32 index, IHasher **hasher)) -{ - #ifdef EXPORT_CODECS - if (index < g_NumHashers) - return CreateHasher(index, hasher); - #endif - #ifdef Z7_EXTERNAL_CODECS - const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; - return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher); - #else - return E_FAIL; - #endif -} - -int CCodecs::GetCodec_LibIndex(UInt32 index) const -{ - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - return -1; - #endif - - #ifdef Z7_EXTERNAL_CODECS - const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; - return (int)ci.LibIndex; - #else - return -1; - #endif -} - -int CCodecs::GetHasherLibIndex(UInt32 index) -{ - #ifdef EXPORT_CODECS - if (index < g_NumHashers) - return -1; - #endif - - #ifdef Z7_EXTERNAL_CODECS - const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; - return (int)ci.LibIndex; - #else - return -1; - #endif -} - -bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const -{ - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - { - NCOM::CPropVariant prop; - if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK) - { - if (prop.vt == VT_BOOL) - return VARIANT_BOOLToBool(prop.boolVal); - } - return false; - } - #endif - - #ifdef Z7_EXTERNAL_CODECS - return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned; - #else - return false; - #endif -} - - -bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const -{ - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - { - NCOM::CPropVariant prop; - if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK) - { - if (prop.vt == VT_BOOL) - return VARIANT_BOOLToBool(prop.boolVal); - } - return false; - } - #endif - - #ifdef Z7_EXTERNAL_CODECS - return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned; - #else - return false; - #endif -} - - -bool CCodecs::GetCodec_IsFilter(UInt32 index, bool &isAssigned) const -{ - isAssigned = false; - #ifdef EXPORT_CODECS - if (index < g_NumCodecs) - { - NCOM::CPropVariant prop; - if (GetProperty(index, NMethodPropID::kIsFilter, &prop) == S_OK) - { - if (prop.vt == VT_BOOL) - { - isAssigned = true; - return VARIANT_BOOLToBool(prop.boolVal); - } - } - return false; - } - #endif - - #ifdef Z7_EXTERNAL_CODECS - { - const CDllCodecInfo &c = Codecs[index - NUM_EXPORT_CODECS]; - isAssigned = c.IsFilter_Assigned; - return c.IsFilter; - } - #else - return false; - #endif -} - - -UInt32 CCodecs::GetCodec_NumStreams(UInt32 index) -{ - NCOM::CPropVariant prop; - if (GetProperty(index, NMethodPropID::kPackStreams, &prop) != S_OK) - return 0; - if (prop.vt == VT_UI4) - return (UInt32)prop.ulVal; - if (prop.vt == VT_EMPTY) - return 1; - return 0; -} - -HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id) -{ - NCOM::CPropVariant prop; - RINOK(GetProperty(index, NMethodPropID::kID, &prop)) - if (prop.vt != VT_UI8) - return E_INVALIDARG; - id = prop.uhVal.QuadPart; - return S_OK; -} - -AString CCodecs::GetCodec_Name(UInt32 index) -{ - AString s; - NCOM::CPropVariant prop; - if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) - if (prop.vt == VT_BSTR) - s.SetFromWStr_if_Ascii(prop.bstrVal); - return s; -} - -UInt64 CCodecs::GetHasherId(UInt32 index) -{ - NCOM::CPropVariant prop; - if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK) - return 0; - if (prop.vt != VT_UI8) - return 0; - return prop.uhVal.QuadPart; -} - -AString CCodecs::GetHasherName(UInt32 index) -{ - AString s; - NCOM::CPropVariant prop; - if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK) - if (prop.vt == VT_BSTR) - s.SetFromWStr_if_Ascii(prop.bstrVal); - return s; -} - -UInt32 CCodecs::GetHasherDigestSize(UInt32 index) -{ - NCOM::CPropVariant prop; - if (GetHasherProp(index, NMethodPropID::kDigestSize, &prop) != S_OK) - return 0; - if (prop.vt != VT_UI4) - return 0; - return prop.ulVal; -} - -void CCodecs::GetCodecsErrorMessage(UString &s) -{ - s.Empty(); - FOR_VECTOR (i, Errors) - { - const CCodecError &ce = Errors[i]; - s += "Codec Load Error: "; - s += fs2us(ce.Path); - if (ce.ErrorCode != 0) - { - s += " : "; - s += NWindows::NError::MyFormatMessage(ce.ErrorCode); - } - if (!ce.Message.IsEmpty()) - { - s += " : "; - s += ce.Message; - } - s.Add_LF(); - } -} - -#endif // Z7_EXTERNAL_CODECS - -#ifndef Z7_SFX - -extern unsigned g_NumCodecs; -extern const CCodecInfo *g_Codecs[]; - -void CCodecs::Get_CodecsInfoUser_Vector(CObjectVector &v) -{ - v.Clear(); - { - for (unsigned i = 0; i < g_NumCodecs; i++) - { - const CCodecInfo &cod = *g_Codecs[i]; - CCodecInfoUser &u = v.AddNew(); - u.EncoderIsAssigned = (cod.CreateEncoder != NULL); - u.DecoderIsAssigned = (cod.CreateDecoder != NULL); - u.IsFilter_Assigned = true; - u.IsFilter = cod.IsFilter; - u.NumStreams = cod.NumStreams; - u.Name = cod.Name; - } - } - - - #ifdef Z7_EXTERNAL_CODECS - { - UInt32 numMethods; - if (GetNumMethods(&numMethods) == S_OK) - for (UInt32 j = 0; j < numMethods; j++) - { - CCodecInfoUser &u = v.AddNew(); - u.EncoderIsAssigned = GetCodec_EncoderIsAssigned(j); - u.DecoderIsAssigned = GetCodec_DecoderIsAssigned(j); - u.IsFilter = GetCodec_IsFilter(j, u.IsFilter_Assigned); - u.NumStreams = GetCodec_NumStreams(j); - u.Name = GetCodec_Name(j); - } - } - #endif -} - -#endif +// LoadCodecs.cpp + +/* +Z7_EXTERNAL_CODECS +--------------- + CCodecs::Load() tries to detect the directory with plugins. + It stops the checking, if it can find any of the following items: + - 7z.dll file + - "Formats" subdir + - "Codecs" subdir + The order of check: + 1) directory of client executable + 2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**] + The order for HKEY_* : Path** : + - HKEY_CURRENT_USER : PathXX + - HKEY_LOCAL_MACHINE : PathXX + - HKEY_CURRENT_USER : Path + - HKEY_LOCAL_MACHINE : Path + PathXX is Path32 in 32-bit code + PathXX is Path64 in 64-bit code + + +EXPORT_CODECS +------------- + if (Z7_EXTERNAL_CODECS) is defined, then the code exports internal + codecs of client from CCodecs object to external plugins. + 7-Zip doesn't use that feature. 7-Zip uses the scheme: + - client application without internal plugins. + - 7z.dll module contains all (or almost all) plugins. + 7z.dll can use codecs from another plugins, if required. +*/ + + +#include "StdAfx.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/PropVariant.h" + +#include "LoadCodecs.h" + +#include "../../ICoder.h" +#include "../../Common/RegisterArc.h" +#include "../../Common/RegisterCodec.h" + +#ifdef Z7_EXTERNAL_CODECS +// #define EXPORT_CODECS +#endif + +#ifdef Z7_EXTERNAL_CODECS + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/DLL.h" + +#ifdef _WIN32 +#include "../../../Windows/FileName.h" +#include "../../../Windows/Registry.h" +#endif + +using namespace NWindows; +using namespace NFile; + + +#define kCodecsFolderName FTEXT("Codecs") +#define kFormatsFolderName FTEXT("Formats") + + +static CFSTR const kMainDll = + #ifdef _WIN32 + FTEXT("7z.dll"); + #else + FTEXT("7z.so"); + #endif + + +#ifdef _WIN32 + +static LPCTSTR const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip"); +static LPCWSTR const kProgramPathValue = L"Path"; +static LPCWSTR const kProgramPath2Value = L"Path" + #ifdef _WIN64 + L"64"; + #else + L"32"; + #endif + +static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path) +{ + NRegistry::CKey key; + if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) + { + UString pathU; + if (key.QueryValue(value, pathU) == ERROR_SUCCESS) + { + path = us2fs(pathU); + NName::NormalizeDirPathPrefix(path); + return NFind::DoesFileExist_Raw(path + kMainDll); + } + } + return false; +} + +#endif // _WIN32 + +#endif // Z7_EXTERNAL_CODECS + + +static const unsigned kNumArcsMax = 72; +static unsigned g_NumArcs = 0; +static const CArcInfo *g_Arcs[kNumArcsMax]; + +void RegisterArc(const CArcInfo *arcInfo) throw() +{ + if (g_NumArcs < kNumArcsMax) + { + g_Arcs[g_NumArcs] = arcInfo; + g_NumArcs++; + } + // else throw 1; +} + +/* +static void SplitString(const UString &srcString, UStringVector &destStrings) +{ + destStrings.Clear(); + UString s; + unsigned len = srcString.Len(); + if (len == 0) + return; + for (unsigned i = 0; i < len; i++) + { + wchar_t c = srcString[i]; + if (c == L' ') + { + if (!s.IsEmpty()) + { + destStrings.Add(s); + s.Empty(); + } + } + else + s += c; + } + if (!s.IsEmpty()) + destStrings.Add(s); +} +*/ + +int CArcInfoEx::FindExtension(const UString &ext) const +{ + FOR_VECTOR (i, Exts) + if (ext.IsEqualTo_NoCase(Exts[i].Ext)) + return (int)i; + return -1; +} + +void CArcInfoEx::AddExts(const UString &ext, const UString &addExt) +{ + UStringVector exts, addExts; + SplitString(ext, exts); + SplitString(addExt, addExts); + FOR_VECTOR (i, exts) + { + CArcExtInfo extInfo; + extInfo.Ext = exts[i]; + if (i < addExts.Size()) + { + extInfo.AddExt = addExts[i]; + if (extInfo.AddExt == L"*") + extInfo.AddExt.Empty(); + } + Exts.Add(extInfo); + } +} + +#ifndef Z7_SFX + +static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector &signatures) +{ + signatures.Clear(); + while (size != 0) + { + const unsigned len = *data++; + size--; + if (len > size) + return false; + signatures.AddNew().CopyFrom(data, len); + data += len; + size -= len; + } + return true; +} + +#endif // Z7_SFX + +// #include + +#ifdef Z7_EXTERNAL_CODECS + +static FString GetBaseFolderPrefixFromRegistry() +{ + FString moduleFolderPrefix = NDLL::GetModuleDirPrefix(); + + #ifdef _WIN32 + if ( !NFind::DoesFileOrDirExist(moduleFolderPrefix + kMainDll) + && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kCodecsFolderName) + && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kFormatsFolderName)) + { + FString path; + if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path; + if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path; + if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path; + if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path; + } + #endif + + // printf("\nmoduleFolderPrefix = %s\n", (const char *)GetAnsiString(moduleFolderPrefix)); + return moduleFolderPrefix; +} + + +static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index, + PROPID propId, CLSID &clsId, bool &isAssigned) +{ + NCOM::CPropVariant prop; + isAssigned = false; + RINOK(getMethodProperty(index, propId, &prop)) + if (prop.vt == VT_BSTR) + { + if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) + return E_FAIL; + isAssigned = true; + clsId = *(const GUID *)(const void *)prop.bstrVal; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + + +static HRESULT GetMethodBoolProp(Func_GetMethodProperty getMethodProperty, UInt32 index, + PROPID propId, bool &resVal, bool &isAssigned) +{ + NCOM::CPropVariant prop; + resVal = false; + isAssigned = false; + RINOK(getMethodProperty(index, propId, &prop)) + if (prop.vt == VT_BOOL) + { + isAssigned = true; + resVal = VARIANT_BOOLToBool(prop.boolVal); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#ifdef _WIN32 +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +#endif + +#define MY_GET_FUNC(dest, type, lib, func) \ + dest = Z7_GET_PROC_ADDRESS(type, lib.Get_HMODULE(), func); +// #define MY_GET_FUNC(dest, type, func) dest = (type)(func); + +#define MY_GET_FUNC_LOC(dest, type, lib, func) \ + type dest; MY_GET_FUNC(dest, type, lib, func) + +HRESULT CCodecs::LoadCodecs() +{ + CCodecLib &lib = Libs.Back(); + + MY_GET_FUNC (lib.CreateDecoder, Func_CreateDecoder, lib.Lib, "CreateDecoder") + MY_GET_FUNC (lib.CreateEncoder, Func_CreateEncoder, lib.Lib, "CreateEncoder") + MY_GET_FUNC (lib.GetMethodProperty, Func_GetMethodProperty, lib.Lib, "GetMethodProperty") + + if (lib.GetMethodProperty) + { + UInt32 numMethods = 1; + MY_GET_FUNC_LOC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib, "GetNumberOfMethods") + if (getNumberOfMethods) + { + RINOK(getNumberOfMethods(&numMethods)) + } + for (UInt32 i = 0; i < numMethods; i++) + { + CDllCodecInfo info; + info.LibIndex = Libs.Size() - 1; + info.CodecIndex = i; + RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned)) + RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned)) + RINOK(GetMethodBoolProp(lib.GetMethodProperty, i, NMethodPropID::kIsFilter, info.IsFilter, info.IsFilter_Assigned)) + Codecs.Add(info); + } + } + + MY_GET_FUNC_LOC (getHashers, Func_GetHashers, lib.Lib, "GetHashers") + if (getHashers) + { + RINOK(getHashers(&lib.ComHashers)) + if (lib.ComHashers) + { + UInt32 numMethods = lib.ComHashers->GetNumHashers(); + for (UInt32 i = 0; i < numMethods; i++) + { + CDllHasherInfo info; + info.LibIndex = Libs.Size() - 1; + info.HasherIndex = i; + Hashers.Add(info); + } + } + } + + return S_OK; +} + +static HRESULT GetProp( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, NCOM::CPropVariant &prop) +{ + if (getProp2) + return getProp2(index, propID, &prop); + return getProp(propID, &prop); +} + +static HRESULT GetProp_Bool( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, bool &res) +{ + res = false; + NCOM::CPropVariant prop; + RINOK(GetProp(getProp, getProp2, index, propID, prop)) + if (prop.vt == VT_BOOL) + res = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT GetProp_UInt32( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, UInt32 &res, bool &defined) +{ + res = 0; + defined = false; + NCOM::CPropVariant prop; + RINOK(GetProp(getProp, getProp2, index, propID, prop)) + if (prop.vt == VT_UI4) + { + res = prop.ulVal; + defined = true; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT GetProp_String( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, UString &res) +{ + res.Empty(); + NCOM::CPropVariant prop; + RINOK(GetProp(getProp, getProp2, index, propID, prop)) + if (prop.vt == VT_BSTR) + res.SetFromBstr(prop.bstrVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT GetProp_RawData( + Func_GetHandlerProperty getProp, + Func_GetHandlerProperty2 getProp2, + UInt32 index, PROPID propID, CByteBuffer &bb) +{ + bb.Free(); + NCOM::CPropVariant prop; + RINOK(GetProp(getProp, getProp2, index, propID, prop)) + if (prop.vt == VT_BSTR) + { + UINT len = ::SysStringByteLen(prop.bstrVal); + bb.CopyFrom((const Byte *)prop.bstrVal, len); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static const UInt32 kArcFlagsPars[] = +{ + NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName, + NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams, + NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure +}; + +HRESULT CCodecs::LoadFormats() +{ + const NDLL::CLibrary &lib = Libs.Back().Lib; + + Func_GetHandlerProperty getProp = NULL; + MY_GET_FUNC_LOC (getProp2, Func_GetHandlerProperty2, lib, "GetHandlerProperty2") + MY_GET_FUNC_LOC (getIsArc, Func_GetIsArc, lib, "GetIsArc") + + UInt32 numFormats = 1; + + if (getProp2) + { + MY_GET_FUNC_LOC (getNumberOfFormats, Func_GetNumberOfFormats, lib, "GetNumberOfFormats") + if (getNumberOfFormats) + { + RINOK(getNumberOfFormats(&numFormats)) + } + } + else + { + MY_GET_FUNC (getProp, Func_GetHandlerProperty, lib, "GetHandlerProperty") + if (!getProp) + return S_OK; + } + + for (UInt32 i = 0; i < numFormats; i++) + { + CArcInfoEx item; + item.LibIndex = (int)(Libs.Size() - 1); + item.FormatIndex = i; + + RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name)) + + { + NCOM::CPropVariant prop; + if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK) + continue; + if (prop.vt != VT_BSTR) + continue; + if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID)) + return E_FAIL; + item.ClassID = *(const GUID *)(const void *)prop.bstrVal; + prop.Clear(); + } + + UString ext, addExt; + RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext)) + RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt)) + item.AddExts(ext, addExt); + + GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled); + bool flags_Defined = false; + RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined)) + item.NewInterface = flags_Defined; + if (!flags_Defined) // && item.UpdateEnabled + { + // support for DLL version before 9.31: + for (unsigned j = 0; j < Z7_ARRAY_SIZE(kArcFlagsPars); j += 2) + { + bool val = false; + GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val); + if (val) + item.Flags |= kArcFlagsPars[j + 1]; + } + } + + { + bool defined = false; + RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kTimeFlags, item.TimeFlags, defined)) + } + + CByteBuffer sig; + RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)) + if (sig.Size() != 0) + item.Signatures.Add(sig); + else + { + RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig)) + ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures); + } + + bool signatureOffset_Defined; + RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined)) + + // bool version_Defined; + // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined)); + + if (getIsArc) + getIsArc(i, &item.IsArcFunc); + + Formats.Add(item); + } + return S_OK; +} + +#ifdef Z7_LARGE_PAGES +extern "C" +{ + extern SIZE_T g_LargePageSize; +} +#endif + + +void CCodecs::AddLastError(const FString &path) +{ + const HRESULT res = GetLastError_noZero_HRESULT(); + CCodecError &error = Errors.AddNew(); + error.Path = path; + error.ErrorCode = res; +} + + +static bool IsSupportedDll(CCodecLib &lib) +{ + MY_GET_FUNC_LOC ( + f_GetModuleProp, + Func_GetModuleProp, lib.Lib, + "GetModuleProp") + /* p7zip and 7-Zip before v23 used virtual destructor in IUnknown, + if _WIN32 is not defined */ + UInt32 flags = + #ifdef _WIN32 + NModuleInterfaceType::k_IUnknown_VirtDestructor_No; + #else + NModuleInterfaceType::k_IUnknown_VirtDestructor_Yes; + #endif + if (f_GetModuleProp) + { + { + NCOM::CPropVariant prop; + if (f_GetModuleProp(NModulePropID::kInterfaceType, &prop) == S_OK) + { + if (prop.vt == VT_UI4) + flags = prop.ulVal; + else if (prop.vt != VT_EMPTY) + return false; + } + } + { + NCOM::CPropVariant prop; + if (f_GetModuleProp(NModulePropID::kVersion, &prop) == S_OK) + { + if (prop.vt == VT_UI4) + lib.Version = prop.ulVal; + } + } + } + if ( + flags + // (flags & NModuleFlags::kMask) + != NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule) + return false; + return true; +} + + +HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK) +{ + if (loadedOK) + *loadedOK = false; + + // needCheckDll = 1; + + #ifdef _WIN32 + if (needCheckDll) + { + NDLL::CLibrary lib; + if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE)) + { + /* if is not win32 + // %1 is not a valid Win32 application. + // #define ERROR_BAD_EXE_FORMAT 193L + */ + // return GetLastError_noZero_HRESULT(); + const DWORD lastError = GetLastError(); + if (lastError != ERROR_BAD_EXE_FORMAT) + { + CCodecError &error = Errors.AddNew(); + error.Path = dllPath; + error.Message = "cannot load file as datafile library"; + error.ErrorCode = HRESULT_FROM_WIN32(lastError); + } + return S_OK; + } + } + #else + UNUSED_VAR(needCheckDll) + #endif + + Libs.AddNew(); + CCodecLib &lib = Libs.Back(); + lib.Path = dllPath; + bool used = false; + // HRESULT res = S_OK; + + if (lib.Lib.Load(dllPath)) + { + if (!IsSupportedDll(lib)) + { + CCodecError &error = Errors.AddNew(); + error.Path = dllPath; + error.Message = "the module is not compatible with program"; + } + else + { + if (loadedOK) + *loadedOK = true; + /* + #ifdef NEW_FOLDER_INTERFACE + lib.LoadIcons(); + #endif + */ + + /* + { + MY_GET_FUNC_LOC (_libStartup, Func_libStartup, lib.Lib, "LibStartup") + if (_libStartup) + { + HRESULT res = _libStartup(); + if (res != 0) + { + CCodecError &error = Errors.AddNew(); + error.Path = dllPath; + error.ErrorCode = res; + } + } + } + */ + + #ifdef Z7_LARGE_PAGES + if (g_LargePageSize != 0) + { + MY_GET_FUNC_LOC (setLargePageMode, Func_SetLargePageMode, lib.Lib, "SetLargePageMode") + if (setLargePageMode) + setLargePageMode(); + } + #endif + + if (CaseSensitive_Change) + { + MY_GET_FUNC_LOC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib, "SetCaseSensitive") + if (setCaseSensitive) + setCaseSensitive(CaseSensitive ? 1 : 0); + } + + /* + { + MY_GET_FUNC_LOC (setClientVersion, Func_SetClientVersion, lib.Lib, "SetClientVersion") + if (setClientVersion) + { + // const UInt32 kVersion = (MY_VER_MAJOR << 16) | MY_VER_MINOR; + setClientVersion(g_ClientVersion); + } + } + */ + + + MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib, "CreateObject") + { + unsigned startSize = Codecs.Size() + Hashers.Size(); + HRESULT res = LoadCodecs(); + if (startSize != Codecs.Size() + Hashers.Size()) + used = true; + if (res == S_OK && lib.CreateObject) + { + startSize = Formats.Size(); + res = LoadFormats(); + if (startSize != Formats.Size()) + used = true; + } + if (res != S_OK) + { + CCodecError &error = Errors.AddNew(); + error.Path = dllPath; + error.ErrorCode = res; + } + } + // plugins can use non-7-zip dlls, so we silently ignore non7zip DLLs + /* + if (!used) + { + CCodecError &error = Errors.AddNew(); + error.Path = dllPath; + error.Message = "no 7-Zip code"; + } + */ + } + } + else + { + AddLastError(dllPath); + } + + if (!used) + Libs.DeleteBack(); + + return S_OK; +} + +HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPath) +{ + if (!NFile::NFind::DoesDirExist_FollowLink(folderPath)) + // if (!NFile::NFind::DoesDirExist(folderPath)) + { + // AddLastError(folderPath); + return S_OK; + } + + FString folderPrefix = folderPath; + folderPrefix.Add_PathSepar(); + + NFile::NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(folderPrefix); + NFile::NFind::CDirEntry fi; + for (;;) + { + bool found; + if (!enumerator.Next(fi, found)) + { + // it can be wrong Symbolic link to folder here + AddLastError(folderPath); + break; + // return GetLastError_noZero_HRESULT(); + } + if (!found) + break; + #ifdef _WIN32 + if (fi.IsDir()) + continue; + #else + if (enumerator.DirEntry_IsDir(fi, true)) // followLink + continue; + #endif + + RINOK(LoadDll(folderPrefix + fi.Name, true)) + } + return S_OK; +} + +void CCodecs::CloseLibs() +{ + // OutputDebugStringA("~CloseLibs start"); + /* + WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected, + if it's called from another FreeLibrary() call. + So we need to call FreeLibrary() before global destructors. + + Also we free global links from DLLs to object of this module before CLibrary::Free() call. + */ + + FOR_VECTOR(i, Libs) + { + const CCodecLib &lib = Libs[i]; + if (lib.SetCodecs) + lib.SetCodecs(NULL); + } + + // OutputDebugStringA("~CloseLibs after SetCodecs"); + Libs.Clear(); + // OutputDebugStringA("~CloseLibs end"); +} + +#endif // Z7_EXTERNAL_CODECS + + +HRESULT CCodecs::Load() +{ + /* + #ifdef NEW_FOLDER_INTERFACE + InternalIcons.LoadIcons(g_hInstance); + #endif + */ + + Formats.Clear(); + + #ifdef Z7_EXTERNAL_CODECS + Errors.Clear(); + MainDll_ErrorPath.Empty(); + Codecs.Clear(); + Hashers.Clear(); + #endif + + for (UInt32 i = 0; i < g_NumArcs; i++) + { + const CArcInfo &arc = *g_Arcs[i]; + CArcInfoEx item; + + item.Name = arc.Name; + item.CreateInArchive = arc.CreateInArchive; + item.IsArcFunc = arc.IsArc; + item.Flags = arc.Flags; + + { + UString e, ae; + if (arc.Ext) + e = arc.Ext; + if (arc.AddExt) + ae = arc.AddExt; + item.AddExts(e, ae); + } + + #ifndef Z7_SFX + + item.CreateOutArchive = arc.CreateOutArchive; + item.UpdateEnabled = (arc.CreateOutArchive != NULL); + item.SignatureOffset = arc.SignatureOffset; + // item.Version = MY_VER_MIX; + item.NewInterface = true; + + if (arc.IsMultiSignature()) + ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures); + else + { + if (arc.SignatureSize != 0) // 21.04 + item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize); + } + + #endif + + Formats.Add(item); + } + + // printf("\nLoad codecs \n"); + + #ifdef Z7_EXTERNAL_CODECS + const FString baseFolder = GetBaseFolderPrefixFromRegistry(); + { + bool loadedOK; + RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK)) + if (!loadedOK) + MainDll_ErrorPath = kMainDll; + } + RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName)) + RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName)) + + NeedSetLibCodecs = true; + + if (Libs.Size() == 0) + NeedSetLibCodecs = false; + else if (Libs.Size() == 1) + { + // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module. + #ifndef EXPORT_CODECS + if (g_NumArcs == 0) + NeedSetLibCodecs = false; + #endif + } + + if (NeedSetLibCodecs) + { + /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c) + old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */ + + FOR_VECTOR(i, Libs) + { + CCodecLib &lib = Libs[i]; + MY_GET_FUNC (lib.SetCodecs, Func_SetCodecs, lib.Lib, "SetCodecs") + if (lib.SetCodecs) + { + RINOK(lib.SetCodecs(this)) + } + } + } + + #endif + + // we sort Formats to get fixed order of Formats after compilation. + Formats.Sort(); + return S_OK; +} + +#ifndef Z7_SFX + +int CCodecs::FindFormatForArchiveName(const UString &arcPath) const +{ + int dotPos = arcPath.ReverseFind_Dot(); + if (dotPos <= arcPath.ReverseFind_PathSepar()) + return -1; + const UString ext = arcPath.Ptr((unsigned)(dotPos + 1)); + if (ext.IsEmpty()) + return -1; + if (ext.IsEqualTo_Ascii_NoCase("exe")) + return -1; + FOR_VECTOR (i, Formats) + { + const CArcInfoEx &arc = Formats[i]; + /* + if (!arc.UpdateEnabled) + continue; + */ + if (arc.FindExtension(ext) >= 0) + return (int)i; + } + return -1; +} + +int CCodecs::FindFormatForExtension(const UString &ext) const +{ + if (ext.IsEmpty()) + return -1; + FOR_VECTOR (i, Formats) + if (Formats[i].FindExtension(ext) >= 0) + return (int)i; + return -1; +} + +int CCodecs::FindFormatForArchiveType(const UString &arcType) const +{ + FOR_VECTOR (i, Formats) + if (Formats[i].Name.IsEqualTo_NoCase(arcType)) + return (int)i; + return -1; +} + +bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const +{ + formatIndices.Clear(); + for (unsigned pos = 0; pos < arcType.Len();) + { + int pos2 = arcType.Find(L'.', pos); + if (pos2 < 0) + pos2 = (int)arcType.Len(); + const UString name = arcType.Mid(pos, (unsigned)pos2 - pos); + if (name.IsEmpty()) + return false; + int index = FindFormatForArchiveType(name); + if (index < 0 && name != L"*") + { + formatIndices.Clear(); + return false; + } + formatIndices.Add(index); + pos = (unsigned)pos2 + 1; + } + return true; +} + +#endif // Z7_SFX + + +#ifdef Z7_EXTERNAL_CODECS + +// #define EXPORT_CODECS + +#ifdef EXPORT_CODECS + +extern unsigned g_NumCodecs; +STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject); +STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject); +STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +#define NUM_EXPORT_CODECS g_NumCodecs + +extern unsigned g_NumHashers; +STDAPI CreateHasher(UInt32 index, IHasher **hasher); +STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value); +#define NUM_EXPORT_HASHERS g_NumHashers + +#else // EXPORT_CODECS + +#define NUM_EXPORT_CODECS 0 +#define NUM_EXPORT_HASHERS 0 + +#endif // EXPORT_CODECS + +Z7_COM7F_IMF(CCodecs::GetNumMethods(UInt32 *numMethods)) +{ + *numMethods = NUM_EXPORT_CODECS + #ifdef Z7_EXTERNAL_CODECS + + Codecs.Size() + #endif + ; + return S_OK; +} + +Z7_COM7F_IMF(CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return GetMethodProperty(index, propID, value); + #endif + + #ifdef Z7_EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + + if (propID == NMethodPropID::kDecoderIsAssigned || + propID == NMethodPropID::kEncoderIsAssigned) + { + NCOM::CPropVariant prop; + prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ? + ci.DecoderIsAssigned : + ci.EncoderIsAssigned); + prop.Detach(value); + return S_OK; + } + + if (propID == NMethodPropID::kIsFilter && ci.IsFilter_Assigned) + { + NCOM::CPropVariant prop; + prop = (bool)ci.IsFilter; + prop.Detach(value); + return S_OK; + } + + const CCodecLib &lib = Libs[ci.LibIndex]; + return lib.GetMethodProperty(ci.CodecIndex, propID, value); + #else + return E_FAIL; + #endif +} + +Z7_COM7F_IMF(CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return CreateDecoder(index, iid, coder); + #endif + + #ifdef Z7_EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + if (ci.DecoderIsAssigned) + { + const CCodecLib &lib = Libs[ci.LibIndex]; + if (lib.CreateDecoder) + return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder); + if (lib.CreateObject) + return lib.CreateObject(&ci.Decoder, iid, (void **)coder); + } + return S_OK; + #else + return E_FAIL; + #endif +} + +Z7_COM7F_IMF(CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)) +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return CreateEncoder(index, iid, coder); + #endif + + #ifdef Z7_EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + if (ci.EncoderIsAssigned) + { + const CCodecLib &lib = Libs[ci.LibIndex]; + if (lib.CreateEncoder) + return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder); + if (lib.CreateObject) + return lib.CreateObject(&ci.Encoder, iid, (void **)coder); + } + return S_OK; + #else + return E_FAIL; + #endif +} + + +Z7_COM7F_IMF2(UInt32, CCodecs::GetNumHashers()) +{ + return NUM_EXPORT_HASHERS + #ifdef Z7_EXTERNAL_CODECS + + Hashers.Size() + #endif + ; +} + +Z7_COM7F_IMF(CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + #ifdef EXPORT_CODECS + if (index < g_NumHashers) + return ::GetHasherProp(index, propID, value); + #endif + + #ifdef Z7_EXTERNAL_CODECS + const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; + return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value); + #else + return E_FAIL; + #endif +} + +Z7_COM7F_IMF(CCodecs::CreateHasher(UInt32 index, IHasher **hasher)) +{ + #ifdef EXPORT_CODECS + if (index < g_NumHashers) + return CreateHasher(index, hasher); + #endif + #ifdef Z7_EXTERNAL_CODECS + const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; + return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher); + #else + return E_FAIL; + #endif +} + +int CCodecs::GetCodec_LibIndex(UInt32 index) const +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + return -1; + #endif + + #ifdef Z7_EXTERNAL_CODECS + const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS]; + return (int)ci.LibIndex; + #else + return -1; + #endif +} + +int CCodecs::GetHasherLibIndex(UInt32 index) +{ + #ifdef EXPORT_CODECS + if (index < g_NumHashers) + return -1; + #endif + + #ifdef Z7_EXTERNAL_CODECS + const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS]; + return (int)ci.LibIndex; + #else + return -1; + #endif +} + +bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + { + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK) + { + if (prop.vt == VT_BOOL) + return VARIANT_BOOLToBool(prop.boolVal); + } + return false; + } + #endif + + #ifdef Z7_EXTERNAL_CODECS + return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned; + #else + return false; + #endif +} + + +bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const +{ + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + { + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK) + { + if (prop.vt == VT_BOOL) + return VARIANT_BOOLToBool(prop.boolVal); + } + return false; + } + #endif + + #ifdef Z7_EXTERNAL_CODECS + return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned; + #else + return false; + #endif +} + + +bool CCodecs::GetCodec_IsFilter(UInt32 index, bool &isAssigned) const +{ + isAssigned = false; + #ifdef EXPORT_CODECS + if (index < g_NumCodecs) + { + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kIsFilter, &prop) == S_OK) + { + if (prop.vt == VT_BOOL) + { + isAssigned = true; + return VARIANT_BOOLToBool(prop.boolVal); + } + } + return false; + } + #endif + + #ifdef Z7_EXTERNAL_CODECS + { + const CDllCodecInfo &c = Codecs[index - NUM_EXPORT_CODECS]; + isAssigned = c.IsFilter_Assigned; + return c.IsFilter; + } + #else + return false; + #endif +} + + +UInt32 CCodecs::GetCodec_NumStreams(UInt32 index) +{ + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kPackStreams, &prop) != S_OK) + return 0; + if (prop.vt == VT_UI4) + return (UInt32)prop.ulVal; + if (prop.vt == VT_EMPTY) + return 1; + return 0; +} + +HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id) +{ + NCOM::CPropVariant prop; + RINOK(GetProperty(index, NMethodPropID::kID, &prop)) + if (prop.vt != VT_UI8) + return E_INVALIDARG; + id = prop.uhVal.QuadPart; + return S_OK; +} + +AString CCodecs::GetCodec_Name(UInt32 index) +{ + AString s; + NCOM::CPropVariant prop; + if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK) + if (prop.vt == VT_BSTR) + s.SetFromWStr_if_Ascii(prop.bstrVal); + return s; +} + +UInt64 CCodecs::GetHasherId(UInt32 index) +{ + NCOM::CPropVariant prop; + if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK) + return 0; + if (prop.vt != VT_UI8) + return 0; + return prop.uhVal.QuadPart; +} + +AString CCodecs::GetHasherName(UInt32 index) +{ + AString s; + NCOM::CPropVariant prop; + if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK) + if (prop.vt == VT_BSTR) + s.SetFromWStr_if_Ascii(prop.bstrVal); + return s; +} + +UInt32 CCodecs::GetHasherDigestSize(UInt32 index) +{ + NCOM::CPropVariant prop; + if (GetHasherProp(index, NMethodPropID::kDigestSize, &prop) != S_OK) + return 0; + if (prop.vt != VT_UI4) + return 0; + return prop.ulVal; +} + +void CCodecs::GetCodecsErrorMessage(UString &s) +{ + s.Empty(); + FOR_VECTOR (i, Errors) + { + const CCodecError &ce = Errors[i]; + s += "Codec Load Error: "; + s += fs2us(ce.Path); + if (ce.ErrorCode != 0) + { + s += " : "; + s += NWindows::NError::MyFormatMessage(ce.ErrorCode); + } + if (!ce.Message.IsEmpty()) + { + s += " : "; + s += ce.Message; + } + s.Add_LF(); + } +} + +#endif // Z7_EXTERNAL_CODECS + +#ifndef Z7_SFX + +extern unsigned g_NumCodecs; +extern const CCodecInfo *g_Codecs[]; + +void CCodecs::Get_CodecsInfoUser_Vector(CObjectVector &v) +{ + v.Clear(); + { + for (unsigned i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &cod = *g_Codecs[i]; + CCodecInfoUser &u = v.AddNew(); + u.EncoderIsAssigned = (cod.CreateEncoder != NULL); + u.DecoderIsAssigned = (cod.CreateDecoder != NULL); + u.IsFilter_Assigned = true; + u.IsFilter = cod.IsFilter; + u.NumStreams = cod.NumStreams; + u.Name = cod.Name; + } + } + + + #ifdef Z7_EXTERNAL_CODECS + { + UInt32 numMethods; + if (GetNumMethods(&numMethods) == S_OK) + for (UInt32 j = 0; j < numMethods; j++) + { + CCodecInfoUser &u = v.AddNew(); + u.EncoderIsAssigned = GetCodec_EncoderIsAssigned(j); + u.DecoderIsAssigned = GetCodec_DecoderIsAssigned(j); + u.IsFilter = GetCodec_IsFilter(j, u.IsFilter_Assigned); + u.NumStreams = GetCodec_NumStreams(j); + u.Name = GetCodec_Name(j); + } + } + #endif +} + +#endif diff --git a/CPP/7zip/UI/Common/LoadCodecs.h b/CPP/7zip/UI/Common/LoadCodecs.h index 179b42efe..a81bb5c74 100644 --- a/CPP/7zip/UI/Common/LoadCodecs.h +++ b/CPP/7zip/UI/Common/LoadCodecs.h @@ -1,482 +1,482 @@ -// LoadCodecs.h - -#ifndef ZIP7_INC_LOAD_CODECS_H -#define ZIP7_INC_LOAD_CODECS_H - -/* -Client application uses LoadCodecs.* to load plugins to -CCodecs object, that contains 3 lists of plugins: - 1) Formats - internal and external archive handlers - 2) Codecs - external codecs - 3) Hashers - external hashers - -Z7_EXTERNAL_CODECS ---------------- - - if Z7_EXTERNAL_CODECS is defined, then the code tries to load external - plugins from DLL files (shared libraries). - - There are two types of executables in 7-Zip: - - 1) Executable that uses external plugins must be compiled - with Z7_EXTERNAL_CODECS defined: - - 7z.exe, 7zG.exe, 7zFM.exe - - Note: Z7_EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h - that code is used in plugin module (7z.dll). - - 2) Standalone modules are compiled without Z7_EXTERNAL_CODECS: - - SFX modules: 7z.sfx, 7zCon.sfx - - standalone versions of console 7-Zip: 7za.exe, 7zr.exe - - if Z7_EXTERNAL_CODECS is defined, CCodecs class implements interfaces: - - ICompressCodecsInfo : for Codecs - - IHashers : for Hashers - - The client application can send CCodecs object to each plugin module. - And plugin module can use ICompressCodecsInfo or IHashers interface to access - another plugins. - - There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin - 1) for old versions: - a) request ISetCompressCodecsInfo from created archive handler. - b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo) - 2) for new versions: - a) request "SetCodecs" function from DLL file - b) call SetCodecs(compressCodecsInfo) function from DLL file -*/ - -#include "../../../Common/MyBuffer.h" -#include "../../../Common/MyCom.h" -#include "../../../Common/MyString.h" -#include "../../../Common/ComTry.h" - -#ifdef Z7_EXTERNAL_CODECS -#include "../../../Windows/DLL.h" -#endif - -#include "../../ICoder.h" - -#include "../../Archive/IArchive.h" - - -#ifdef Z7_EXTERNAL_CODECS - -struct CDllCodecInfo -{ - unsigned LibIndex; - UInt32 CodecIndex; - bool EncoderIsAssigned; - bool DecoderIsAssigned; - bool IsFilter; - bool IsFilter_Assigned; - CLSID Encoder; - CLSID Decoder; -}; - -struct CDllHasherInfo -{ - unsigned LibIndex; - UInt32 HasherIndex; -}; - -#endif - -struct CArcExtInfo -{ - UString Ext; - UString AddExt; - - CArcExtInfo() {} - CArcExtInfo(const UString &ext): Ext(ext) {} - CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} -}; - - -struct CArcInfoEx -{ - UInt32 Flags; - UInt32 TimeFlags; - - Func_CreateInArchive CreateInArchive; - Func_IsArc IsArcFunc; - - UString Name; - CObjectVector Exts; - - #ifndef Z7_SFX - Func_CreateOutArchive CreateOutArchive; - bool UpdateEnabled; - bool NewInterface; - // UInt32 Version; - UInt32 SignatureOffset; - CObjectVector Signatures; - /* - #ifdef NEW_FOLDER_INTERFACE - UStringVector AssociateExts; - #endif - */ - #endif - - #ifdef Z7_EXTERNAL_CODECS - int LibIndex; - UInt32 FormatIndex; - CLSID ClassID; - #endif - - int Compare(const CArcInfoEx &a) const - { - const int res = Name.Compare(a.Name); - if (res != 0) - return res; - #ifdef Z7_EXTERNAL_CODECS - return MyCompare(LibIndex, a.LibIndex); - #else - return 0; - #endif - /* - if (LibIndex < a.LibIndex) return -1; - if (LibIndex > a.LibIndex) return 1; - return 0; - */ - } - - bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } - bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } - - bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } - bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } - bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } - bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } - - bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; } - bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; } - bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; } - bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } - bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } - bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; } - bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; } - - bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; } - bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; } - bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; } - - bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; } - bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; } - bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; } - - UInt32 Get_TimePrecFlags() const - { - return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) & - (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1); - } - - UInt32 Get_DefaultTimePrec() const - { - return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) & - (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1); - } - - - UString GetMainExt() const - { - if (Exts.IsEmpty()) - return UString(); - return Exts[0].Ext; - } - int FindExtension(const UString &ext) const; - - bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); } - bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); } - bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); } - bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); } - bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); } - bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); } - bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); } - bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); } - bool Is_Zstd() const { return Name.IsEqualTo_Ascii_NoCase("zstd"); } - - /* - UString GetAllExtensions() const - { - UString s; - for (int i = 0; i < Exts.Size(); i++) - { - if (i > 0) - s.Add_Space(); - s += Exts[i].Ext; - } - return s; - } - */ - - void AddExts(const UString &ext, const UString &addExt); - - - CArcInfoEx(): - Flags(0), - TimeFlags(0), - CreateInArchive(NULL), - IsArcFunc(NULL) - #ifndef Z7_SFX - , CreateOutArchive(NULL) - , UpdateEnabled(false) - , NewInterface(false) - // , Version(0) - , SignatureOffset(0) - #endif - #ifdef Z7_EXTERNAL_CODECS - , LibIndex(-1) - #endif - {} -}; - - -#ifdef Z7_EXTERNAL_CODECS - -struct CCodecLib -{ - NWindows::NDLL::CLibrary Lib; - FString Path; - - Func_CreateObject CreateObject; - Func_GetMethodProperty GetMethodProperty; - Func_CreateDecoder CreateDecoder; - Func_CreateEncoder CreateEncoder; - Func_SetCodecs SetCodecs; - - CMyComPtr ComHashers; - - UInt32 Version; - - /* - #ifdef NEW_FOLDER_INTERFACE - CCodecIcons CodecIcons; - void LoadIcons() { CodecIcons.LoadIcons((HMODULE)Lib); } - #endif - */ - - CCodecLib(): - CreateObject(NULL), - GetMethodProperty(NULL), - CreateDecoder(NULL), - CreateEncoder(NULL), - SetCodecs(NULL), - Version(0) - {} -}; - -#endif - -struct CCodecError -{ - FString Path; - HRESULT ErrorCode; - AString Message; - CCodecError(): ErrorCode(0) {} -}; - - -struct CCodecInfoUser -{ - // unsigned LibIndex; - // UInt32 CodecIndex; - // UInt64 id; - bool EncoderIsAssigned; - bool DecoderIsAssigned; - bool IsFilter; - bool IsFilter_Assigned; - UInt32 NumStreams; - AString Name; -}; - - -class CCodecs Z7_final: - #ifdef Z7_EXTERNAL_CODECS - public ICompressCodecsInfo, - public IHashers, - #else - public IUnknown, - #endif - public CMyUnknownImp -{ -#ifdef Z7_EXTERNAL_CODECS - Z7_IFACES_IMP_UNK_2(ICompressCodecsInfo, IHashers) -#else - Z7_COM_UNKNOWN_IMP_0 -#endif // Z7_EXTERNAL_CODECS - - Z7_CLASS_NO_COPY(CCodecs) -public: - #ifdef Z7_EXTERNAL_CODECS - - CObjectVector Libs; - FString MainDll_ErrorPath; - CObjectVector Errors; - - void AddLastError(const FString &path); - void CloseLibs(); - - class CReleaser - { - Z7_CLASS_NO_COPY(CReleaser) - - /* CCodecsReleaser object releases CCodecs links. - 1) CCodecs is COM object that is deleted when all links to that object will be released/ - 2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself. - To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */ - - CCodecs *_codecs; - - public: - CReleaser(): _codecs(NULL) {} - void Set(CCodecs *codecs) { _codecs = codecs; } - ~CReleaser() { if (_codecs) _codecs->CloseLibs(); } - }; - - bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo - - HRESULT LoadCodecs(); - HRESULT LoadFormats(); - HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL); - HRESULT LoadDllsFromFolder(const FString &folderPrefix); - - HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const - { - return Libs[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); - } - - #endif - - /* - #ifdef NEW_FOLDER_INTERFACE - CCodecIcons InternalIcons; - #endif - */ - - CObjectVector Formats; - - #ifdef Z7_EXTERNAL_CODECS - CRecordVector Codecs; - CRecordVector Hashers; - #endif - - bool CaseSensitive_Change; - bool CaseSensitive; - - CCodecs(): - #ifdef Z7_EXTERNAL_CODECS - NeedSetLibCodecs(true), - #endif - CaseSensitive_Change(false), - CaseSensitive(false) - {} - - ~CCodecs() - { - // OutputDebugStringA("~CCodecs"); - } - - const wchar_t *GetFormatNamePtr(int formatIndex) const - { - return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name; - } - - HRESULT Load(); - - #ifndef Z7_SFX - int FindFormatForArchiveName(const UString &arcPath) const; - int FindFormatForExtension(const UString &ext) const; - int FindFormatForArchiveType(const UString &arcType) const; - bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const; - #endif - - #ifdef Z7_EXTERNAL_CODECS - - int GetCodec_LibIndex(UInt32 index) const; - bool GetCodec_DecoderIsAssigned(UInt32 index) const; - bool GetCodec_EncoderIsAssigned(UInt32 index) const; - bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const; - UInt32 GetCodec_NumStreams(UInt32 index); - HRESULT GetCodec_Id(UInt32 index, UInt64 &id); - AString GetCodec_Name(UInt32 index); - - int GetHasherLibIndex(UInt32 index); - UInt64 GetHasherId(UInt32 index); - AString GetHasherName(UInt32 index); - UInt32 GetHasherDigestSize(UInt32 index); - - void GetCodecsErrorMessage(UString &s); - - #endif - - HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr &archive) const - { - const CArcInfoEx &ai = Formats[formatIndex]; - #ifdef Z7_EXTERNAL_CODECS - if (ai.LibIndex < 0) - #endif - { - COM_TRY_BEGIN - archive = ai.CreateInArchive(); - return S_OK; - COM_TRY_END - } - #ifdef Z7_EXTERNAL_CODECS - return CreateArchiveHandler(ai, false, (void **)&archive); - #endif - } - - #ifndef Z7_SFX - - HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr &archive) const - { - const CArcInfoEx &ai = Formats[formatIndex]; - #ifdef Z7_EXTERNAL_CODECS - if (ai.LibIndex < 0) - #endif - { - COM_TRY_BEGIN - archive = ai.CreateOutArchive(); - return S_OK; - COM_TRY_END - } - - #ifdef Z7_EXTERNAL_CODECS - return CreateArchiveHandler(ai, true, (void **)&archive); - #endif - } - - int FindOutFormatFromName(const UString &name) const - { - FOR_VECTOR (i, Formats) - { - const CArcInfoEx &arc = Formats[i]; - if (!arc.UpdateEnabled) - continue; - if (arc.Name.IsEqualTo_NoCase(name)) - return (int)i; - } - return -1; - } - - void Get_CodecsInfoUser_Vector(CObjectVector &v); - - #endif // Z7_SFX -}; - -#ifdef Z7_EXTERNAL_CODECS - #define CREATE_CODECS_OBJECT \ - CCodecs *codecs = new CCodecs; \ - CExternalCodecs _externalCodecs; \ - _externalCodecs.GetCodecs = codecs; \ - _externalCodecs.GetHashers = codecs; \ - CCodecs::CReleaser codecsReleaser; \ - codecsReleaser.Set(codecs); -#else - #define CREATE_CODECS_OBJECT \ - CCodecs *codecs = new CCodecs; \ - CMyComPtr _codecsRef = codecs; -#endif - -#endif +// LoadCodecs.h + +#ifndef ZIP7_INC_LOAD_CODECS_H +#define ZIP7_INC_LOAD_CODECS_H + +/* +Client application uses LoadCodecs.* to load plugins to +CCodecs object, that contains 3 lists of plugins: + 1) Formats - internal and external archive handlers + 2) Codecs - external codecs + 3) Hashers - external hashers + +Z7_EXTERNAL_CODECS +--------------- + + if Z7_EXTERNAL_CODECS is defined, then the code tries to load external + plugins from DLL files (shared libraries). + + There are two types of executables in 7-Zip: + + 1) Executable that uses external plugins must be compiled + with Z7_EXTERNAL_CODECS defined: + - 7z.exe, 7zG.exe, 7zFM.exe + + Note: Z7_EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h + that code is used in plugin module (7z.dll). + + 2) Standalone modules are compiled without Z7_EXTERNAL_CODECS: + - SFX modules: 7z.sfx, 7zCon.sfx + - standalone versions of console 7-Zip: 7za.exe, 7zr.exe + + if Z7_EXTERNAL_CODECS is defined, CCodecs class implements interfaces: + - ICompressCodecsInfo : for Codecs + - IHashers : for Hashers + + The client application can send CCodecs object to each plugin module. + And plugin module can use ICompressCodecsInfo or IHashers interface to access + another plugins. + + There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin + 1) for old versions: + a) request ISetCompressCodecsInfo from created archive handler. + b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo) + 2) for new versions: + a) request "SetCodecs" function from DLL file + b) call SetCodecs(compressCodecsInfo) function from DLL file +*/ + +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" +#include "../../../Common/ComTry.h" + +#ifdef Z7_EXTERNAL_CODECS +#include "../../../Windows/DLL.h" +#endif + +#include "../../ICoder.h" + +#include "../../Archive/IArchive.h" + + +#ifdef Z7_EXTERNAL_CODECS + +struct CDllCodecInfo +{ + unsigned LibIndex; + UInt32 CodecIndex; + bool EncoderIsAssigned; + bool DecoderIsAssigned; + bool IsFilter; + bool IsFilter_Assigned; + CLSID Encoder; + CLSID Decoder; +}; + +struct CDllHasherInfo +{ + unsigned LibIndex; + UInt32 HasherIndex; +}; + +#endif + +struct CArcExtInfo +{ + UString Ext; + UString AddExt; + + CArcExtInfo() {} + CArcExtInfo(const UString &ext): Ext(ext) {} + CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} +}; + + +struct CArcInfoEx +{ + UInt32 Flags; + UInt32 TimeFlags; + + Func_CreateInArchive CreateInArchive; + Func_IsArc IsArcFunc; + + UString Name; + CObjectVector Exts; + + #ifndef Z7_SFX + Func_CreateOutArchive CreateOutArchive; + bool UpdateEnabled; + bool NewInterface; + // UInt32 Version; + UInt32 SignatureOffset; + CObjectVector Signatures; + /* + #ifdef NEW_FOLDER_INTERFACE + UStringVector AssociateExts; + #endif + */ + #endif + + #ifdef Z7_EXTERNAL_CODECS + int LibIndex; + UInt32 FormatIndex; + CLSID ClassID; + #endif + + int Compare(const CArcInfoEx &a) const + { + const int res = Name.Compare(a.Name); + if (res != 0) + return res; + #ifdef Z7_EXTERNAL_CODECS + return MyCompare(LibIndex, a.LibIndex); + #else + return 0; + #endif + /* + if (LibIndex < a.LibIndex) return -1; + if (LibIndex > a.LibIndex) return 1; + return 0; + */ + } + + bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; } + bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } + + bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } + bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } + bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } + bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } + + bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; } + bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; } + bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; } + bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; } + bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; } + bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; } + bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; } + + bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; } + bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; } + bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; } + + bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; } + bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; } + bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; } + + UInt32 Get_TimePrecFlags() const + { + return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) & + (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1); + } + + UInt32 Get_DefaultTimePrec() const + { + return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) & + (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1); + } + + + UString GetMainExt() const + { + if (Exts.IsEmpty()) + return UString(); + return Exts[0].Ext; + } + int FindExtension(const UString &ext) const; + + bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); } + bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); } + bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); } + bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); } + bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); } + bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); } + bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); } + bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); } + bool Is_Zstd() const { return Name.IsEqualTo_Ascii_NoCase("zstd"); } + + /* + UString GetAllExtensions() const + { + UString s; + for (int i = 0; i < Exts.Size(); i++) + { + if (i > 0) + s.Add_Space(); + s += Exts[i].Ext; + } + return s; + } + */ + + void AddExts(const UString &ext, const UString &addExt); + + + CArcInfoEx(): + Flags(0), + TimeFlags(0), + CreateInArchive(NULL), + IsArcFunc(NULL) + #ifndef Z7_SFX + , CreateOutArchive(NULL) + , UpdateEnabled(false) + , NewInterface(false) + // , Version(0) + , SignatureOffset(0) + #endif + #ifdef Z7_EXTERNAL_CODECS + , LibIndex(-1) + #endif + {} +}; + + +#ifdef Z7_EXTERNAL_CODECS + +struct CCodecLib +{ + NWindows::NDLL::CLibrary Lib; + FString Path; + + Func_CreateObject CreateObject; + Func_GetMethodProperty GetMethodProperty; + Func_CreateDecoder CreateDecoder; + Func_CreateEncoder CreateEncoder; + Func_SetCodecs SetCodecs; + + CMyComPtr ComHashers; + + UInt32 Version; + + /* + #ifdef NEW_FOLDER_INTERFACE + CCodecIcons CodecIcons; + void LoadIcons() { CodecIcons.LoadIcons((HMODULE)Lib); } + #endif + */ + + CCodecLib(): + CreateObject(NULL), + GetMethodProperty(NULL), + CreateDecoder(NULL), + CreateEncoder(NULL), + SetCodecs(NULL), + Version(0) + {} +}; + +#endif + +struct CCodecError +{ + FString Path; + HRESULT ErrorCode; + AString Message; + CCodecError(): ErrorCode(0) {} +}; + + +struct CCodecInfoUser +{ + // unsigned LibIndex; + // UInt32 CodecIndex; + // UInt64 id; + bool EncoderIsAssigned; + bool DecoderIsAssigned; + bool IsFilter; + bool IsFilter_Assigned; + UInt32 NumStreams; + AString Name; +}; + + +class CCodecs Z7_final: + #ifdef Z7_EXTERNAL_CODECS + public ICompressCodecsInfo, + public IHashers, + #else + public IUnknown, + #endif + public CMyUnknownImp +{ +#ifdef Z7_EXTERNAL_CODECS + Z7_IFACES_IMP_UNK_2(ICompressCodecsInfo, IHashers) +#else + Z7_COM_UNKNOWN_IMP_0 +#endif // Z7_EXTERNAL_CODECS + + Z7_CLASS_NO_COPY(CCodecs) +public: + #ifdef Z7_EXTERNAL_CODECS + + CObjectVector Libs; + FString MainDll_ErrorPath; + CObjectVector Errors; + + void AddLastError(const FString &path); + void CloseLibs(); + + class CReleaser + { + Z7_CLASS_NO_COPY(CReleaser) + + /* CCodecsReleaser object releases CCodecs links. + 1) CCodecs is COM object that is deleted when all links to that object will be released/ + 2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself. + To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */ + + CCodecs *_codecs; + + public: + CReleaser(): _codecs(NULL) {} + void Set(CCodecs *codecs) { _codecs = codecs; } + ~CReleaser() { if (_codecs) _codecs->CloseLibs(); } + }; + + bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo + + HRESULT LoadCodecs(); + HRESULT LoadFormats(); + HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL); + HRESULT LoadDllsFromFolder(const FString &folderPrefix); + + HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const + { + return Libs[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive); + } + + #endif + + /* + #ifdef NEW_FOLDER_INTERFACE + CCodecIcons InternalIcons; + #endif + */ + + CObjectVector Formats; + + #ifdef Z7_EXTERNAL_CODECS + CRecordVector Codecs; + CRecordVector Hashers; + #endif + + bool CaseSensitive_Change; + bool CaseSensitive; + + CCodecs(): + #ifdef Z7_EXTERNAL_CODECS + NeedSetLibCodecs(true), + #endif + CaseSensitive_Change(false), + CaseSensitive(false) + {} + + ~CCodecs() + { + // OutputDebugStringA("~CCodecs"); + } + + const wchar_t *GetFormatNamePtr(int formatIndex) const + { + return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name; + } + + HRESULT Load(); + + #ifndef Z7_SFX + int FindFormatForArchiveName(const UString &arcPath) const; + int FindFormatForExtension(const UString &ext) const; + int FindFormatForArchiveType(const UString &arcType) const; + bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const; + #endif + + #ifdef Z7_EXTERNAL_CODECS + + int GetCodec_LibIndex(UInt32 index) const; + bool GetCodec_DecoderIsAssigned(UInt32 index) const; + bool GetCodec_EncoderIsAssigned(UInt32 index) const; + bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const; + UInt32 GetCodec_NumStreams(UInt32 index); + HRESULT GetCodec_Id(UInt32 index, UInt64 &id); + AString GetCodec_Name(UInt32 index); + + int GetHasherLibIndex(UInt32 index); + UInt64 GetHasherId(UInt32 index); + AString GetHasherName(UInt32 index); + UInt32 GetHasherDigestSize(UInt32 index); + + void GetCodecsErrorMessage(UString &s); + + #endif + + HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr &archive) const + { + const CArcInfoEx &ai = Formats[formatIndex]; + #ifdef Z7_EXTERNAL_CODECS + if (ai.LibIndex < 0) + #endif + { + COM_TRY_BEGIN + archive = ai.CreateInArchive(); + return S_OK; + COM_TRY_END + } + #ifdef Z7_EXTERNAL_CODECS + return CreateArchiveHandler(ai, false, (void **)&archive); + #endif + } + + #ifndef Z7_SFX + + HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr &archive) const + { + const CArcInfoEx &ai = Formats[formatIndex]; + #ifdef Z7_EXTERNAL_CODECS + if (ai.LibIndex < 0) + #endif + { + COM_TRY_BEGIN + archive = ai.CreateOutArchive(); + return S_OK; + COM_TRY_END + } + + #ifdef Z7_EXTERNAL_CODECS + return CreateArchiveHandler(ai, true, (void **)&archive); + #endif + } + + int FindOutFormatFromName(const UString &name) const + { + FOR_VECTOR (i, Formats) + { + const CArcInfoEx &arc = Formats[i]; + if (!arc.UpdateEnabled) + continue; + if (arc.Name.IsEqualTo_NoCase(name)) + return (int)i; + } + return -1; + } + + void Get_CodecsInfoUser_Vector(CObjectVector &v); + + #endif // Z7_SFX +}; + +#ifdef Z7_EXTERNAL_CODECS + #define CREATE_CODECS_OBJECT \ + CCodecs *codecs = new CCodecs; \ + CExternalCodecs _externalCodecs; \ + _externalCodecs.GetCodecs = codecs; \ + _externalCodecs.GetHashers = codecs; \ + CCodecs::CReleaser codecsReleaser; \ + codecsReleaser.Set(codecs); +#else + #define CREATE_CODECS_OBJECT \ + CCodecs *codecs = new CCodecs; \ + CMyComPtr _codecsRef = codecs; +#endif + +#endif diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp index d36d42515..c26d4c059 100644 --- a/CPP/7zip/UI/Common/OpenArchive.cpp +++ b/CPP/7zip/UI/Common/OpenArchive.cpp @@ -1,3702 +1,3702 @@ -// OpenArchive.cpp - -#include "StdAfx.h" - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO -#include -#endif - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/UTFConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/ProgressUtils.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "DefaultName.h" -#include "OpenArchive.h" - -#ifndef Z7_SFX -#include "SetProperties.h" -#endif - -#ifndef Z7_SFX -#ifdef SHOW_DEBUG_INFO -#define PRF(x) x -#else -#define PRF(x) -#endif -#endif - -// increase it, if you need to support larger SFX stubs -static const UInt64 kMaxCheckStartPosition = 1 << 23; - -/* -Open: - - formatIndex >= 0 (exact Format) - 1) Open with main type. Archive handler is allowed to use archive start finder. - Warning, if there is tail. - - - formatIndex = -1 (Parser:0) (default) - - same as #1 but doesn't return Parser - - - formatIndex = -2 (#1) - - file has supported extension (like a.7z) - Open with that main type (only starting from start of file). - - open OK: - - if there is no tail - return OK - - if there is tail: - - archive is not "Self Exe" - return OK with Warning, that there is tail - - archive is "Self Exe" - ignore "Self Exe" stub, and tries to open tail - - tail can be open as archive - shows that archive and stub size property. - - tail can't be open as archive - shows Parser ??? - - open FAIL: - Try to open with all other types from offset 0 only. - If some open type is OK and physical archive size is uequal or larger - than file size, then return that archive with warning that cannot be open as [extension type]. - If extension was EXE, it will try to open as unknown_extension case - - file has unknown extension (like a.hhh) - It tries to open via parser code. - - if there is full archive or tail archive and unknown block or "Self Exe" - at front, it shows tail archive and stub size property. - - in another cases, if there is some archive inside file, it returns parser/ - - in another cases, it retuens S_FALSE - - - - formatIndex = -3 (#2) - - same as #1, but - - stub (EXE) + archive is open in Parser - - - formatIndex = -4 (#3) - - returns only Parser. skip full file archive. And show other sub-archives - - - formatIndex = -5 (#4) - - returns only Parser. skip full file archive. And show other sub-archives for each byte pos - -*/ - - - - -using namespace NWindows; - -/* -#ifdef Z7_SFX -#define OPEN_PROPS_PARAM -#else -#define OPEN_PROPS_PARAM , props -#endif -*/ - -/* -CArc::~CArc() -{ - GetRawProps.Release(); - Archive.Release(); - printf("\nCArc::~CArc()\n"); -} -*/ - -#ifndef Z7_SFX - -namespace NArchive { -namespace NParser { - -struct CParseItem -{ - UInt64 Offset; - UInt64 Size; - // UInt64 OkSize; - UString Name; - UString Extension; - FILETIME FileTime; - UString Comment; - UString ArcType; - - bool FileTime_Defined; - bool UnpackSize_Defined; - bool NumSubDirs_Defined; - bool NumSubFiles_Defined; - - bool IsSelfExe; - bool IsNotArcType; - - UInt64 UnpackSize; - UInt64 NumSubDirs; - UInt64 NumSubFiles; - - int FormatIndex; - - bool LenIsUnknown; - - CParseItem(): - // OkSize(0), - FileTime_Defined(false), - UnpackSize_Defined(false), - NumSubDirs_Defined(false), - NumSubFiles_Defined(false), - IsSelfExe(false), - IsNotArcType(false), - LenIsUnknown(false) - {} - - /* - bool IsEqualTo(const CParseItem &item) const - { - return Offset == item.Offset && Size == item.Size; - } - */ - - void NormalizeOffset() - { - if ((Int64)Offset < 0) - { - Size += Offset; - // OkSize += Offset; - Offset = 0; - } - } -}; - -Z7_CLASS_IMP_CHandler_IInArchive_1( - IInArchiveGetStream -) -public: - CObjectVector _items; - UInt64 _maxEndOffset; - CMyComPtr _stream; - - UInt64 GetLastEnd() const - { - if (_items.IsEmpty()) - return 0; - const CParseItem &back = _items.Back(); - return back.Offset + back.Size; - } - - void AddUnknownItem(UInt64 next); - int FindInsertPos(const CParseItem &item) const; - void AddItem(const CParseItem &item); - - CHandler(): _maxEndOffset(0) {} -}; - -int CHandler::FindInsertPos(const CParseItem &item) const -{ - unsigned left = 0, right = _items.Size(); - while (left != right) - { - const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const CParseItem &midItem = _items[mid]; - if (item.Offset < midItem.Offset) - right = mid; - else if (item.Offset > midItem.Offset) - left = mid + 1; - else if (item.Size < midItem.Size) - right = mid; - /* - else if (item.Size > midItem.Size) - left = mid + 1; - */ - else - { - left = mid + 1; - // return -1; - } - } - return (int)left; -} - -void CHandler::AddUnknownItem(UInt64 next) -{ - /* - UInt64 prevEnd = 0; - if (!_items.IsEmpty()) - { - const CParseItem &back = _items.Back(); - prevEnd = back.Offset + back.Size; - } - */ - if (_maxEndOffset < next) - { - CParseItem item2; - item2.Offset = _maxEndOffset; - item2.Size = next - _maxEndOffset; - _maxEndOffset = next; - _items.Add(item2); - } - else if (_maxEndOffset > next && !_items.IsEmpty()) - { - CParseItem &back = _items.Back(); - if (back.LenIsUnknown) - { - back.Size = next - back.Offset; - _maxEndOffset = next; - } - } -} - -void CHandler::AddItem(const CParseItem &item) -{ - AddUnknownItem(item.Offset); - const int pos = FindInsertPos(item); - if (pos != -1) - { - _items.Insert((unsigned)pos, item); - UInt64 next = item.Offset + item.Size; - if (_maxEndOffset < next) - _maxEndOffset = next; - } -} - -/* -static const CStatProp kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidType, VT_BSTR}, - { NULL, kpidComment, VT_BSTR}, - { NULL, kpidOffset, VT_UI8}, - { NULL, kpidUnpackSize, VT_UI8}, -// { NULL, kpidNumSubDirs, VT_UI8}, -}; -*/ - -static const Byte kProps[] = -{ - kpidPath, - kpidSize, - kpidMTime, - kpidType, - kpidComment, - kpidOffset, - kpidUnpackSize -}; - -IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO - -Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */)) -{ - COM_TRY_BEGIN - { - Close(); - _stream = stream; - } - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Close()) -{ - _items.Clear(); - _stream.Release(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - - const CParseItem &item = _items[index]; - - switch (propID) - { - case kpidPath: - { - char sz[32]; - ConvertUInt32ToString(index + 1, sz); - UString s(sz); - if (!item.Name.IsEmpty()) - { - s.Add_Dot(); - s += item.Name; - } - if (!item.Extension.IsEmpty()) - { - s.Add_Dot(); - s += item.Extension; - } - prop = s; break; - } - case kpidSize: - case kpidPackSize: prop = item.Size; break; - case kpidOffset: prop = item.Offset; break; - case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break; - case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break; - case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break; - case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break; - case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break; - case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break; - default: break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, - Int32 testMode, IArchiveExtractCallback *extractCallback)) -{ - COM_TRY_BEGIN - - const bool allFilesMode = (numItems == (UInt32)(Int32)-1); - if (allFilesMode) - numItems = _items.Size(); - if (_stream && numItems == 0) - return S_OK; - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].Size; - extractCallback->SetTotal(totalSize); - - totalSize = 0; - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - - CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; - CMyComPtr inStream(streamSpec); - streamSpec->SetStream(_stream); - - CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; - CMyComPtr outStream(outStreamSpec); - - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); - CMyComPtr copyCoder = copyCoderSpec; - - for (i = 0; i < numItems; i++) - { - lps->InSize = totalSize; - lps->OutSize = totalSize; - RINOK(lps->SetCur()) - CMyComPtr realOutStream; - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - const UInt32 index = allFilesMode ? i : indices[i]; - const CParseItem &item = _items[index]; - - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - UInt64 unpackSize = item.Size; - totalSize += unpackSize; - bool skipMode = false; - if (!testMode && !realOutStream) - continue; - RINOK(extractCallback->PrepareOperation(askMode)) - - outStreamSpec->SetStream(realOutStream); - realOutStream.Release(); - outStreamSpec->Init(skipMode ? 0 : unpackSize, true); - - Int32 opRes = NExtract::NOperationResult::kOK; - RINOK(InStream_SeekSet(_stream, item.Offset)) - streamSpec->Init(unpackSize); - RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) - - if (outStreamSpec->GetRem() != 0) - opRes = NExtract::NOperationResult::kDataError; - outStreamSpec->ReleaseStream(); - RINOK(extractCallback->SetOperationResult(opRes)) - } - - return S_OK; - - COM_TRY_END -} - - -Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) -{ - COM_TRY_BEGIN - const CParseItem &item = _items[index]; - return CreateLimitedInStream(_stream, item.Offset, item.Size, stream); - COM_TRY_END -} - -}} - -#endif - -HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw() -{ - NCOM::CPropVariant prop; - result = false; - RINOK(arc->GetProperty(index, propID, &prop)) - if (prop.vt == VT_BOOL) - result = VARIANT_BOOLToBool(prop.boolVal); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw() -{ - return Archive_GetItemBoolProp(arc, index, kpidIsDir, result); -} - -HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw() -{ - return Archive_GetItemBoolProp(arc, index, kpidIsAux, result); -} - -HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw() -{ - return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result); -} - -HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw() -{ - return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); -} - -static HRESULT Archive_GetArcProp_Bool(IInArchive *arc, PROPID propid, bool &result) throw() -{ - NCOM::CPropVariant prop; - result = false; - RINOK(arc->GetArchiveProperty(propid, &prop)) - if (prop.vt == VT_BOOL) - result = VARIANT_BOOLToBool(prop.boolVal); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined) -{ - defined = false; - NCOM::CPropVariant prop; - RINOK(arc->GetArchiveProperty(propid, &prop)) - switch (prop.vt) - { - case VT_UI4: result = prop.ulVal; break; - case VT_I4: result = (UInt64)(Int64)prop.lVal; break; - case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; break; - case VT_I8: result = (UInt64)prop.hVal.QuadPart; break; - case VT_EMPTY: return S_OK; - default: return E_FAIL; - } - defined = true; - return S_OK; -} - -static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined) -{ - defined = false; - NCOM::CPropVariant prop; - RINOK(arc->GetArchiveProperty(propid, &prop)) - switch (prop.vt) - { - case VT_UI4: result = prop.ulVal; break; - case VT_I4: result = prop.lVal; break; - case VT_UI8: result = (Int64)prop.uhVal.QuadPart; break; - case VT_I8: result = (Int64)prop.hVal.QuadPart; break; - case VT_EMPTY: return S_OK; - default: return E_FAIL; - } - defined = true; - return S_OK; -} - -#ifndef Z7_SFX - -HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const -{ - if (!GetRawProps) - return E_FAIL; - if (index == parent) - return S_OK; - UInt32 curIndex = index; - - UString s; - - bool prevWasAltStream = false; - - for (;;) - { - #ifdef MY_CPU_LE - const void *p; - UInt32 size; - UInt32 propType; - RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)) - if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) - s = (const wchar_t *)p; - else - #endif - { - NCOM::CPropVariant prop; - RINOK(Archive->GetProperty(curIndex, kpidName, &prop)) - if (prop.vt == VT_BSTR && prop.bstrVal) - s.SetFromBstr(prop.bstrVal); - else if (prop.vt == VT_EMPTY) - s.Empty(); - else - return E_FAIL; - } - - UInt32 curParent = (UInt32)(Int32)-1; - UInt32 parentType = 0; - RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType)) - - // 18.06: fixed : we don't want to split name to parts - /* - if (parentType != NParentType::kAltStream) - { - for (;;) - { - int pos = s.ReverseFind_PathSepar(); - if (pos < 0) - { - break; - } - parts.Insert(0, s.Ptr(pos + 1)); - s.DeleteFrom(pos); - } - } - */ - - parts.Insert(0, s); - - if (prevWasAltStream) - { - { - UString &s2 = parts[parts.Size() - 2]; - s2.Add_Colon(); - s2 += parts.Back(); - } - parts.DeleteBack(); - } - - if (parent == curParent) - return S_OK; - - prevWasAltStream = false; - if (parentType == NParentType::kAltStream) - prevWasAltStream = true; - - if (curParent == (UInt32)(Int32)-1) - return E_FAIL; - curIndex = curParent; - } -} - -#endif - - - -HRESULT CArc::GetItem_Path(UInt32 index, UString &result) const -{ - #ifdef MY_CPU_LE - if (GetRawProps) - { - const void *p; - UInt32 size; - UInt32 propType; - if (!IsTree) - { - if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK && - propType == NPropDataType::kUtf16z) - { - unsigned len = size / 2 - 1; - // (len) doesn't include null terminator - - /* - #if WCHAR_MAX > 0xffff - len = (unsigned)Utf16LE__Get_Num_WCHARs(p, len); - - wchar_t *s = result.GetBuf(len); - wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, len, s); - if (s + len != sEnd) return E_FAIL; - *sEnd = 0; - - #else - */ - - wchar_t *s = result.GetBuf(len); - for (unsigned i = 0; i < len; i++) - { - wchar_t c = GetUi16(p); - p = (const void *)((const Byte *)p + 2); - - #if WCHAR_PATH_SEPARATOR != L'/' - if (c == L'/') - c = WCHAR_PATH_SEPARATOR; - else if (c == L'\\') - c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme - #endif - - *s++ = c; - } - *s = 0; - - // #endif - - result.ReleaseBuf_SetLen(len); - - Convert_UnicodeEsc16_To_UnicodeEscHigh(result); - if (len != 0) - return S_OK; - } - } - /* - else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK && - p && propType == NPropDataType::kUtf16z) - { - size -= 2; - UInt32 totalSize = size; - bool isOK = false; - - { - UInt32 index2 = index; - for (;;) - { - UInt32 parent = (UInt32)(Int32)-1; - UInt32 parentType = 0; - if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) - break; - if (parent == (UInt32)(Int32)-1) - { - if (parentType != 0) - totalSize += 2; - isOK = true; - break; - } - index2 = parent; - UInt32 size2; - const void *p2; - if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK && - p2 && propType == NPropDataType::kUtf16z) - break; - totalSize += size2; - } - } - - if (isOK) - { - wchar_t *sz = result.GetBuf_SetEnd(totalSize / 2); - UInt32 pos = totalSize - size; - memcpy((Byte *)sz + pos, p, size); - UInt32 index2 = index; - for (;;) - { - UInt32 parent = (UInt32)(Int32)-1; - UInt32 parentType = 0; - if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) - break; - if (parent == (UInt32)(Int32)-1) - { - if (parentType != 0) - sz[pos / 2 - 1] = L':'; - break; - } - index2 = parent; - UInt32 size2; - const void *p2; - if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) - break; - pos -= size2; - memcpy((Byte *)sz + pos, p2, size2); - sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':'; - } - #ifdef _WIN32 - // result.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - return S_OK; - } - } - */ - } - #endif - - { - NCOM::CPropVariant prop; - RINOK(Archive->GetProperty(index, kpidPath, &prop)) - if (prop.vt == VT_BSTR && prop.bstrVal) - result.SetFromBstr(prop.bstrVal); - else if (prop.vt == VT_EMPTY) - result.Empty(); - else - return E_FAIL; - } - - if (result.IsEmpty()) - return GetItem_DefaultPath(index, result); - - Convert_UnicodeEsc16_To_UnicodeEscHigh(result); - return S_OK; -} - -HRESULT CArc::GetItem_DefaultPath(UInt32 index, UString &result) const -{ - result.Empty(); - bool isDir; - RINOK(Archive_IsItem_Dir(Archive, index, isDir)) - if (!isDir) - { - result = DefaultName; - NCOM::CPropVariant prop; - RINOK(Archive->GetProperty(index, kpidExtension, &prop)) - if (prop.vt == VT_BSTR) - { - result.Add_Dot(); - result += prop.bstrVal; - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - } - return S_OK; -} - -HRESULT CArc::GetItem_Path2(UInt32 index, UString &result) const -{ - RINOK(GetItem_Path(index, result)) - if (Ask_Deleted) - { - bool isDeleted = false; - RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted)) - if (isDeleted) - result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR); - } - return S_OK; -} - -#ifdef SUPPORT_ALT_STREAMS - -int FindAltStreamColon_in_Path(const wchar_t *path) -{ - unsigned i = 0; - int colonPos = -1; - for (;; i++) - { - wchar_t c = path[i]; - if (c == 0) - return colonPos; - if (c == ':') - { - if (colonPos < 0) - colonPos = (int)i; - continue; - } - if (c == WCHAR_PATH_SEPARATOR) - colonPos = -1; - } -} - -#endif - -HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const -{ - #ifdef SUPPORT_ALT_STREAMS - item.IsAltStream = false; - item.AltStreamName.Empty(); - item.MainPath.Empty(); - #endif - - item.IsDir = false; - item.Path.Empty(); - item.ParentIndex = (UInt32)(Int32)-1; - - item.PathParts.Clear(); - - RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir)) - item.MainIsDir = item.IsDir; - - RINOK(GetItem_Path2(index, item.Path)) - - #ifndef Z7_SFX - UInt32 mainIndex = index; - #endif - - #ifdef SUPPORT_ALT_STREAMS - - item.MainPath = item.Path; - if (Ask_AltStream) - { - RINOK(Archive_IsItem_AltStream(Archive, index, item.IsAltStream)) - } - - bool needFindAltStream = false; - - if (item.IsAltStream) - { - needFindAltStream = true; - if (GetRawProps) - { - UInt32 parentType = 0; - UInt32 parentIndex; - RINOK(GetRawProps->GetParent(index, &parentIndex, &parentType)) - if (parentType == NParentType::kAltStream) - { - NCOM::CPropVariant prop; - RINOK(Archive->GetProperty(index, kpidName, &prop)) - if (prop.vt == VT_BSTR && prop.bstrVal) - item.AltStreamName.SetFromBstr(prop.bstrVal); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - else - { - // item.IsAltStream = false; - } - /* - if (item.AltStreamName.IsEmpty()) - item.IsAltStream = false; - */ - - needFindAltStream = false; - item.ParentIndex = parentIndex; - mainIndex = parentIndex; - - if (parentIndex == (UInt32)(Int32)-1) - { - item.MainPath.Empty(); - item.MainIsDir = true; - } - else - { - RINOK(GetItem_Path2(parentIndex, item.MainPath)) - RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir)) - } - } - } - } - - if (item.WriteToAltStreamIfColon || needFindAltStream) - { - /* Good handler must support GetRawProps::GetParent for alt streams. - So the following code currently is not used */ - int colon = FindAltStreamColon_in_Path(item.Path); - if (colon >= 0) - { - item.MainPath.DeleteFrom((unsigned)colon); - item.AltStreamName = item.Path.Ptr((unsigned)(colon + 1)); - item.MainIsDir = (colon == 0 || IsPathSepar(item.Path[(unsigned)colon - 1])); - item.IsAltStream = true; - } - } - - #endif - - #ifndef Z7_SFX - if (item._use_baseParentFolder_mode) - { - RINOK(GetItem_PathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts)) - - #ifdef SUPPORT_ALT_STREAMS - if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty()) - { - int colon; - { - UString &s = item.PathParts.Back(); - colon = FindAltStreamColon_in_Path(s); - if (colon >= 0) - { - item.AltStreamName = s.Ptr((unsigned)(colon + 1)); - item.MainIsDir = (colon == 0 || IsPathSepar(s[(unsigned)colon - 1])); - item.IsAltStream = true; - s.DeleteFrom((unsigned)colon); - } - } - if (colon == 0) - item.PathParts.DeleteBack(); - } - #endif - - } - else - #endif - SplitPathToParts( - #ifdef SUPPORT_ALT_STREAMS - item.MainPath - #else - item.Path - #endif - , item.PathParts); - - return S_OK; -} - -#ifndef Z7_SFX - -static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined) -{ - NCOM::CPropVariant prop; - defined = false; - size = 0; - RINOK(archive->GetProperty(index, kpidSize, &prop)) - switch (prop.vt) - { - case VT_UI1: size = prop.bVal; break; - case VT_UI2: size = prop.uiVal; break; - case VT_UI4: size = prop.ulVal; break; - case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; - case VT_EMPTY: return S_OK; - default: return E_FAIL; - } - defined = true; - return S_OK; -} - -#endif - -HRESULT CArc::GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const -{ - NCOM::CPropVariant prop; - defined = false; - size = 0; - RINOK(Archive->GetProperty(index, kpidSize, &prop)) - switch (prop.vt) - { - case VT_UI1: size = prop.bVal; break; - case VT_UI2: size = prop.uiVal; break; - case VT_UI4: size = prop.ulVal; break; - case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; - case VT_EMPTY: return S_OK; - default: return E_FAIL; - } - defined = true; - return S_OK; -} - -HRESULT CArc::GetItem_MTime(UInt32 index, CArcTime &at) const -{ - at.Clear(); - NCOM::CPropVariant prop; - RINOK(Archive->GetProperty(index, kpidMTime, &prop)) - - if (prop.vt == VT_FILETIME) - { - /* - // for debug - if (FILETIME_IsZero(prop.at) && MTime.Def) - { - at = MTime; - return S_OK; - } - */ - at.Set_From_Prop(prop); - if (at.Prec == 0) - { - // (at.Prec == 0) before version 22. - // so kpidTimeType is required for that code - prop.Clear(); - RINOK(Archive->GetProperty(index, kpidTimeType, &prop)) - if (prop.vt == VT_UI4) - { - UInt32 val = prop.ulVal; - if (val == NFileTimeType::kWindows) - val = k_PropVar_TimePrec_100ns; - /* - else if (val > k_PropVar_TimePrec_1ns) - { - val = k_PropVar_TimePrec_100ns; - // val = k_PropVar_TimePrec_1ns; - // return E_FAIL; // for debug - } - */ - at.Prec = (UInt16)val; - } - } - return S_OK; - } - - if (prop.vt != VT_EMPTY) - return E_FAIL; - if (MTime.Def) - at = MTime; - return S_OK; -} - -#ifndef Z7_SFX - -static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size) -{ - for (size_t i = 0; i < size; i++) - if (p1[i] != p2[i]) - return false; - return true; -} - - -static void MakeCheckOrder(CCodecs *codecs, - CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, - const Byte *data, size_t dataSize) -{ - for (unsigned i = 0; i < numTypes; i++) - { - const int index = orderIndices[i]; - if (index < 0) - continue; - const CArcInfoEx &ai = codecs->Formats[(unsigned)index]; - if (ai.SignatureOffset == 0) - { - if (ai.Signatures.IsEmpty()) - { - if (dataSize != 0) // 21.04: no Signature means Empty Signature - continue; - } - else - { - unsigned k; - const CObjectVector &sigs = ai.Signatures; - for (k = 0; k < sigs.Size(); k++) - { - const CByteBuffer &sig = sigs[k]; - if (sig.Size() <= dataSize && TestSignature(data, sig, sig.Size())) - break; - } - if (k == sigs.Size()) - continue; - } - } - orderIndices2.Add(index); - orderIndices[i] = -1; - } -} - -#ifdef UNDER_CE - static const unsigned kNumHashBytes = 1; - #define HASH_VAL(buf) ((buf)[0]) -#else - static const unsigned kNumHashBytes = 2; - // #define HASH_VAL(buf) ((buf)[0] | ((UInt32)(buf)[1] << 8)) - #define HASH_VAL(buf) GetUi16(buf) -#endif - -static bool IsExeExt(const UString &ext) -{ - return ext.IsEqualTo_Ascii_NoCase("exe"); -} - -static const char * const k_PreArcFormats[] = -{ - "pe" - , "elf" - , "macho" - , "mub" - , "te" -}; - -static bool IsNameFromList(const UString &s, const char * const names[], size_t num) -{ - for (unsigned i = 0; i < num; i++) - if (StringsAreEqualNoCase_Ascii(s, names[i])) - return true; - return false; -} - - -static bool IsPreArcFormat(const CArcInfoEx &ai) -{ - if (ai.Flags_PreArc()) - return true; - return IsNameFromList(ai.Name, k_PreArcFormats, Z7_ARRAY_SIZE(k_PreArcFormats)); -} - -static const char * const k_Formats_with_simple_signuature[] = -{ - "7z" - , "xz" - , "rar" - , "bzip2" - , "gzip" - , "cab" - , "wim" - , "rpm" - , "vhd" - , "xar" -}; - -static bool IsNewStyleSignature(const CArcInfoEx &ai) -{ - // if (ai.Version >= 0x91F) - if (ai.NewInterface) - return true; - return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, Z7_ARRAY_SIZE(k_Formats_with_simple_signuature)); -} - - - -class CArchiveOpenCallback_Offset Z7_final: - public IArchiveOpenCallback, - public IArchiveOpenVolumeCallback, - #ifndef Z7_NO_CRYPTO - public ICryptoGetTextPassword, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IArchiveOpenCallback) - Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback) - #ifndef Z7_NO_CRYPTO - Z7_COM_QI_ENTRY(ICryptoGetTextPassword) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IArchiveOpenCallback) - Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback) - #ifndef Z7_NO_CRYPTO - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - #endif - -public: - CMyComPtr Callback; - CMyComPtr OpenVolumeCallback; - UInt64 Files; - UInt64 Offset; - - #ifndef Z7_NO_CRYPTO - CMyComPtr GetTextPassword; - #endif -}; - -#ifndef Z7_NO_CRYPTO -Z7_COM7F_IMF(CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password)) -{ - COM_TRY_BEGIN - if (GetTextPassword) - return GetTextPassword->CryptoGetTextPassword(password); - return E_NOTIMPL; - COM_TRY_END -} -#endif - -Z7_COM7F_IMF(CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CArchiveOpenCallback_Offset::SetCompleted(const UInt64 *, const UInt64 *bytes)) -{ - if (!Callback) - return S_OK; - UInt64 value = Offset; - if (bytes) - value += *bytes; - return Callback->SetCompleted(&Files, &value); -} - -Z7_COM7F_IMF(CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value)) -{ - if (OpenVolumeCallback) - return OpenVolumeCallback->GetProperty(propID, value); - NCOM::PropVariant_Clear(value); - return S_OK; - // return E_NOTIMPL; -} - -Z7_COM7F_IMF(CArchiveOpenCallback_Offset::GetStream(const wchar_t *name, IInStream **inStream)) -{ - if (OpenVolumeCallback) - return OpenVolumeCallback->GetStream(name, inStream); - return S_FALSE; -} - -#endif - - -UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp) -{ - if (isDefinedProp != NULL) - *isDefinedProp = false; - - switch (prop.vt) - { - case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart; - case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal; - case VT_EMPTY: return 0; - default: throw 151199; - } -} - -void CArcErrorInfo::ClearErrors() -{ - // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!! - - ThereIsTail = false; - UnexpecedEnd = false; - IgnoreTail = false; - // NonZerosTail = false; - ErrorFlags_Defined = false; - ErrorFlags = 0; - WarningFlags = 0; - TailSize = 0; - - ErrorMessage.Empty(); - WarningMessage.Empty(); -} - -HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) -{ - // OkPhySize_Defined = false; - PhySize_Defined = false; - PhySize = 0; - Offset = 0; - AvailPhySize = FileSize - startPos; - - ErrorInfo.ClearErrors(); - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop)) - ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined); - } - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop)) - ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop); - } - - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidError, &prop)) - if (prop.vt != VT_EMPTY) - ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown error"); - } - - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidWarning, &prop)) - if (prop.vt != VT_EMPTY) - ErrorInfo.WarningMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown warning"); - } - - if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) - { - RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySize_Defined)) - /* - RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); - if (!OkPhySize_Defined) - { - OkPhySize_Defined = PhySize_Defined; - OkPhySize = PhySize; - } - */ - - bool offsetDefined; - RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined)) - - Int64 globalOffset = (Int64)startPos + Offset; - AvailPhySize = (UInt64)((Int64)FileSize - globalOffset); - if (PhySize_Defined) - { - UInt64 endPos = (UInt64)(globalOffset + (Int64)PhySize); - if (endPos < FileSize) - { - AvailPhySize = PhySize; - ErrorInfo.ThereIsTail = true; - ErrorInfo.TailSize = FileSize - endPos; - } - else if (endPos > FileSize) - ErrorInfo.UnexpecedEnd = true; - } - } - - return S_OK; -} - -/* -static void PrintNumber(const char *s, int n) -{ - char temp[100]; - sprintf(temp, "%s %d", s, n); - // OutputDebugStringA(temp); - printf(temp); -} -*/ - -HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive) -{ - // OutputDebugStringA("a1"); - // PrintNumber("formatIndex", formatIndex); - - RINOK(op.codecs->CreateInArchive(formatIndex, archive)) - // OutputDebugStringA("a2"); - if (!archive) - return S_OK; - - #ifdef Z7_EXTERNAL_CODECS - if (op.codecs->NeedSetLibCodecs) - { - const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; - if (ai.LibIndex >= 0 ? - !op.codecs->Libs[(unsigned)ai.LibIndex].SetCodecs : - !op.codecs->Libs.IsEmpty()) - { - CMyComPtr setCompressCodecsInfo; - archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs)) - } - } - } - #endif - - - #ifndef Z7_SFX - - const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; - - // OutputDebugStringW(ai.Name); - // OutputDebugStringA("a3"); - - if (ai.Flags_PreArc()) - { - /* we notify parsers that extract executables, that they don't need - to open archive, if there is tail after executable (for SFX cases) */ - CMyComPtr allowTail; - archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail); - if (allowTail) - allowTail->AllowTail(BoolToInt(true)); - } - - if (op.props) - { - /* - FOR_VECTOR (y, op.props) - { - const COptionalOpenProperties &optProps = (*op.props)[y]; - if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0) - { - RINOK(SetProperties(archive, optProps.Props)); - break; - } - } - */ - RINOK(SetProperties(archive, *op.props)) - } - - #endif - return S_OK; -} - -#ifndef Z7_SFX - -static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi) -{ - pi.Extension = ai.GetMainExt(); - pi.FileTime_Defined = false; - pi.ArcType = ai.Name; - - RINOK(Archive_GetArcProp_Bool(archive, kpidIsNotArcType, pi.IsNotArcType)) - - // RINOK(Archive_GetArcProp_Bool(archive, kpidIsSelfExe, pi.IsSelfExe)); - pi.IsSelfExe = ai.Flags_PreArc(); - - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidMTime, &prop)) - if (prop.vt == VT_FILETIME) - { - pi.FileTime_Defined = true; - pi.FileTime = prop.filetime; - } - } - - if (!pi.FileTime_Defined) - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidCTime, &prop)) - if (prop.vt == VT_FILETIME) - { - pi.FileTime_Defined = true; - pi.FileTime = prop.filetime; - } - } - - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidName, &prop)) - if (prop.vt == VT_BSTR) - { - pi.Name.SetFromBstr(prop.bstrVal); - pi.Extension.Empty(); - } - else - { - RINOK(archive->GetArchiveProperty(kpidExtension, &prop)) - if (prop.vt == VT_BSTR) - pi.Extension.SetFromBstr(prop.bstrVal); - } - } - - { - NCOM::CPropVariant prop; - RINOK(archive->GetArchiveProperty(kpidShortComment, &prop)) - if (prop.vt == VT_BSTR) - pi.Comment.SetFromBstr(prop.bstrVal); - } - - - UInt32 numItems; - RINOK(archive->GetNumberOfItems(&numItems)) - - // pi.NumSubFiles = numItems; - // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined)); - // if (!pi.UnpackSize_Defined) - { - pi.NumSubFiles = 0; - pi.NumSubDirs = 0; - pi.UnpackSize = 0; - for (UInt32 i = 0; i < numItems; i++) - { - UInt64 size = 0; - bool defined = false; - Archive_GetItem_Size(archive, i, size, defined); - if (defined) - { - pi.UnpackSize_Defined = true; - pi.UnpackSize += size; - } - - bool isDir = false; - Archive_IsItem_Dir(archive, i, isDir); - if (isDir) - pi.NumSubDirs++; - else - pi.NumSubFiles++; - } - if (pi.NumSubDirs != 0) - pi.NumSubDirs_Defined = true; - pi.NumSubFiles_Defined = true; - } - - return S_OK; -} - -#endif - -HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset) -{ - if (!op.stream) - return S_OK; - RINOK(InStream_SeekSet(op.stream, offset)) - const UInt32 kBufSize = 1 << 11; - Byte buf[kBufSize]; - - for (;;) - { - UInt32 processed = 0; - RINOK(op.stream->Read(buf, kBufSize, &processed)) - if (processed == 0) - { - // ErrorInfo.NonZerosTail = false; - ErrorInfo.IgnoreTail = true; - return S_OK; - } - for (size_t i = 0; i < processed; i++) - { - if (buf[i] != 0) - { - // ErrorInfo.IgnoreTail = false; - // ErrorInfo.NonZerosTail = true; - return S_OK; - } - } - } -} - - - -#ifndef Z7_SFX - -Z7_CLASS_IMP_COM_2( - CExtractCallback_To_OpenCallback - , IArchiveExtractCallback - , ICompressProgressInfo -) - Z7_IFACE_COM7_IMP(IProgress) -public: - CMyComPtr Callback; - UInt64 Files; - UInt64 Offset; - - void Init(IArchiveOpenCallback *callback) - { - Callback = callback; - Files = 0; - Offset = 0; - } -}; - -Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) -{ - if (Callback) - { - UInt64 value = Offset; - if (inSize) - value += *inSize; - return Callback->SetCompleted(&Files, &value); - } - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */)) -{ - *outStream = NULL; - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */)) -{ - return S_OK; -} - - -static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize, - IInStream *stream, const UInt64 *maxCheckStartPosition, - IArchiveOpenCallback *openCallback, - IArchiveExtractCallback *extractCallback) -{ - /* - if (needPhySize) - { - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpen2, - open2, archive) - if (open2) - return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback); - } - */ - RINOK(archive->Open(stream, maxCheckStartPosition, openCallback)) - if (needPhySize) - { - bool phySize_Defined = false; - UInt64 phySize = 0; - RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined)) - if (phySize_Defined) - return S_OK; - - bool phySizeCantBeDetected = false; - RINOK(Archive_GetArcProp_Bool(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)) - - if (!phySizeCantBeDetected) - { - PRF(printf("\n-- !phySize_Defined after Open, call archive->Extract()")); - // It's for bzip2/gz and some xz archives, where Open operation doesn't know phySize. - // But the Handler will know phySize after full archive testing. - RINOK(archive->Extract(NULL, (UInt32)(Int32)-1, BoolToInt(true), extractCallback)) - PRF(printf("\n-- OK")); - } - } - return S_OK; -} - - - -static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name) -{ - FOR_VECTOR (i, orderIndices) - { - int oi = orderIndices[i]; - if (oi >= 0) - if (StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)oi].Name, name)) - return (int)i; - } - return -1; -} - -#endif - -HRESULT CArc::OpenStream2(const COpenOptions &op) -{ - // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout); - - Archive.Release(); - GetRawProps.Release(); - GetRootProps.Release(); - - ErrorInfo.ClearErrors(); - ErrorInfo.ErrorFormatIndex = -1; - - IsParseArc = false; - ArcStreamOffset = 0; - - // OutputDebugStringA("1"); - // OutputDebugStringW(Path); - - const UString fileName = ExtractFileNameFromPath(Path); - UString extension; - { - const int dotPos = fileName.ReverseFind_Dot(); - if (dotPos >= 0) - extension = fileName.Ptr((unsigned)(dotPos + 1)); - } - - CIntVector orderIndices; - - bool searchMarkerInHandler = false; - #ifdef Z7_SFX - searchMarkerInHandler = true; - #endif - - CBoolArr isMainFormatArr(op.codecs->Formats.Size()); - { - FOR_VECTOR(i, op.codecs->Formats) - isMainFormatArr[i] = false; - } - - const UInt64 maxStartOffset = - op.openType.MaxStartOffset_Defined ? - op.openType.MaxStartOffset : - kMaxCheckStartPosition; - - #ifndef Z7_SFX - bool isUnknownExt = false; - #endif - - #ifndef Z7_SFX - bool isForced = false; - #endif - - unsigned numMainTypes = 0; - const int formatIndex = op.openType.FormatIndex; - - if (formatIndex >= 0) - { - #ifndef Z7_SFX - isForced = true; - #endif - orderIndices.Add(formatIndex); - numMainTypes = 1; - isMainFormatArr[(unsigned)formatIndex] = true; - - searchMarkerInHandler = true; - } - else - { - unsigned numFinded = 0; - #ifndef Z7_SFX - bool isPrearcExt = false; - #endif - - { - #ifndef Z7_SFX - - bool isZip = false; - bool isRar = false; - - const wchar_t c = extension[0]; - if (c == 'z' || c == 'Z' || c == 'r' || c == 'R') - { - bool isNumber = false; - for (unsigned k = 1;; k++) - { - const wchar_t d = extension[k]; - if (d == 0) - break; - if (d < '0' || d > '9') - { - isNumber = false; - break; - } - isNumber = true; - } - if (isNumber) - { - if (c == 'z' || c == 'Z') - isZip = true; - else - isRar = true; - } - } - - #endif - - FOR_VECTOR (i, op.codecs->Formats) - { - const CArcInfoEx &ai = op.codecs->Formats[i]; - - if (IgnoreSplit || !op.openType.CanReturnArc) - if (ai.Is_Split()) - continue; - if (op.excludedFormats->FindInSorted((int)i) >= 0) - continue; - - #ifndef Z7_SFX - if (IsPreArcFormat(ai)) - isPrearcExt = true; - #endif - - if (ai.FindExtension(extension) >= 0 - #ifndef Z7_SFX - || (isZip && ai.Is_Zip()) - || (isRar && ai.Is_Rar()) - #endif - ) - { - // PrintNumber("orderIndices.Insert", i); - orderIndices.Insert(numFinded++, (int)i); - isMainFormatArr[i] = true; - } - else - orderIndices.Add((int)i); - } - } - - if (!op.stream) - { - if (numFinded != 1) - return E_NOTIMPL; - orderIndices.DeleteFrom(1); - } - // PrintNumber("numFinded", numFinded ); - - /* - if (op.openOnlySpecifiedByExtension) - { - if (numFinded != 0 && !IsExeExt(extension)) - orderIndices.DeleteFrom(numFinded); - } - */ - - #ifndef Z7_SFX - - if (op.stream && orderIndices.Size() >= 2) - { - RINOK(InStream_SeekToBegin(op.stream)) - CByteBuffer byteBuffer; - CIntVector orderIndices2; - if (numFinded == 0 || IsExeExt(extension)) - { - // signature search was here - } - else if (extension.IsEqualTo("000") || extension.IsEqualTo("001")) - { - const int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar"); - if (i >= 0) - { - const size_t kBufSize = (1 << 10); - byteBuffer.Alloc(kBufSize); - size_t processedSize = kBufSize; - RINOK(ReadStream(op.stream, byteBuffer, &processedSize)) - if (processedSize >= 16) - { - const Byte *buf = byteBuffer; - const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; - if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0) - { - orderIndices2.Add(orderIndices[(unsigned)i]); - orderIndices[(unsigned)i] = -1; - if (i >= (int)numFinded) - numFinded++; - } - } - } - } - else - { - const size_t kBufSize = (1 << 10); - byteBuffer.Alloc(kBufSize); - size_t processedSize = kBufSize; - RINOK(ReadStream(op.stream, byteBuffer, &processedSize)) - if (processedSize == 0) - return S_FALSE; - - /* - check type order: - 0) matched_extension && Backward - 1) matched_extension && (no_signuature || SignatureOffset != 0) - 2) matched_extension && (matched_signature) - // 3) no signuature - // 4) matched signuature - */ - // we move index from orderIndices to orderIndices2 for priority handlers. - - for (unsigned i = 0; i < numFinded; i++) - { - const int index = orderIndices[i]; - if (index < 0) - continue; - const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index]; - if (ai.Flags_BackwardOpen()) - { - // backward doesn't need start signatures - orderIndices2.Add(index); - orderIndices[i] = -1; - } - } - - MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); - MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); - // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0); - // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize); - } - - FOR_VECTOR (i, orderIndices) - { - const int val = orderIndices[i]; - if (val != -1) - orderIndices2.Add(val); - } - orderIndices = orderIndices2; - } - - if (orderIndices.Size() >= 2) - { - const int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso"); - const int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf"); - if (iUdf > iIso && iIso >= 0) - { - const int isoIndex = orderIndices[(unsigned)iIso]; - const int udfIndex = orderIndices[(unsigned)iUdf]; - orderIndices[(unsigned)iUdf] = isoIndex; - orderIndices[(unsigned)iIso] = udfIndex; - } - } - - numMainTypes = numFinded; - isUnknownExt = (numMainTypes == 0) || isPrearcExt; - - #else // Z7_SFX - - numMainTypes = orderIndices.Size(); - - // we need correct numMainTypes for mutlivolume SFX (if some volume is missing) - if (numFinded != 0) - numMainTypes = numFinded; - - #endif - } - - UInt64 fileSize = 0; - if (op.stream) - { - RINOK(InStream_GetSize_SeekToBegin(op.stream, fileSize)) - } - FileSize = fileSize; - - - #ifndef Z7_SFX - - CBoolArr skipFrontalFormat(op.codecs->Formats.Size()); - { - FOR_VECTOR(i, op.codecs->Formats) - skipFrontalFormat[i] = false; - } - - #endif - - const COpenType &mode = op.openType; - - - - - - if (mode.CanReturnArc) - { - // ---------- OPEN main type by extenssion ---------- - - unsigned numCheckTypes = orderIndices.Size(); - if (formatIndex >= 0) - numCheckTypes = numMainTypes; - - for (unsigned i = 0; i < numCheckTypes; i++) - { - FormatIndex = orderIndices[i]; - - // orderIndices[] item cannot be negative here - - bool exactOnly = false; - - #ifndef Z7_SFX - - const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex]; - // OutputDebugStringW(ai.Name); - if (i >= numMainTypes) - { - // here we allow mismatched extension only for backward handlers - if (!ai.Flags_BackwardOpen() - // && !ai.Flags_PureStartOpen() - ) - continue; - exactOnly = true; - } - - #endif - - // Some handlers do not set total bytes. So we set it here - if (op.callback) - RINOK(op.callback->SetTotal(NULL, &fileSize)) - - if (op.stream) - { - RINOK(InStream_SeekToBegin(op.stream)) - } - - CMyComPtr archive; - - RINOK(PrepareToOpen(op, (unsigned)FormatIndex, archive)) - if (!archive) - continue; - - HRESULT result; - if (op.stream) - { - UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0; - result = archive->Open(op.stream, &searchLimit, op.callback); - } - else - { - CMyComPtr openSeq; - archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); - if (!openSeq) - return E_NOTIMPL; - result = openSeq->OpenSeq(op.seqStream); - } - - RINOK(ReadBasicProps(archive, 0, result)) - - if (result == S_FALSE) - { - bool isArc = ErrorInfo.IsArc_After_NonOpen(); - - #ifndef Z7_SFX - // if it's archive, we allow another open attempt for parser - if (!mode.CanReturnParser || !isArc) - skipFrontalFormat[(unsigned)FormatIndex] = true; - #endif - - if (exactOnly) - continue; - - if (i == 0 && numMainTypes == 1) - { - // we set NonOpenErrorInfo, only if there is only one main format (defined by extension). - ErrorInfo.ErrorFormatIndex = FormatIndex; - NonOpen_ErrorInfo = ErrorInfo; - - if (!mode.CanReturnParser && isArc) - { - // if (formatIndex < 0 && !searchMarkerInHandler) - { - // if bad archive was detected, we don't need additional open attempts - #ifndef Z7_SFX - if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */) - #endif - return S_FALSE; - } - } - } - - /* - #ifndef Z7_SFX - if (IsExeExt(extension) || ai.Flags_PreArc()) - { - // openOnlyFullArc = false; - // canReturnTailArc = true; - // limitSignatureSearch = true; - } - #endif - */ - - continue; - } - - RINOK(result) - - #ifndef Z7_SFX - - bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex]; - const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); - - bool thereIsTail = ErrorInfo.ThereIsTail; - if (thereIsTail && mode.ZerosTailIsAllowed) - { - RINOK(CheckZerosTail(op, (UInt64)(Offset + (Int64)PhySize))) - if (ErrorInfo.IgnoreTail) - thereIsTail = false; - } - - if (Offset > 0) - { - if (exactOnly - || !searchMarkerInHandler - || !specFlags.CanReturn_NonStart() - || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset)) - continue; - } - if (thereIsTail) - { - if (Offset > 0) - { - if (!specFlags.CanReturnMid) - continue; - } - else if (!specFlags.CanReturnFrontal) - continue; - } - - if (Offset > 0 || thereIsTail) - { - if (formatIndex < 0) - { - if (IsPreArcFormat(ai)) - { - // openOnlyFullArc = false; - // canReturnTailArc = true; - /* - if (mode.SkipSfxStub) - limitSignatureSearch = true; - */ - // if (mode.SkipSfxStub) - { - // skipFrontalFormat[FormatIndex] = true; - continue; - } - } - } - } - - #endif - - Archive = archive; - return S_OK; - } - } - - - - #ifndef Z7_SFX - - if (!op.stream) - return S_FALSE; - - if (formatIndex >= 0 && !mode.CanReturnParser) - { - if (mode.MaxStartOffset_Defined) - { - if (mode.MaxStartOffset == 0) - return S_FALSE; - } - else - { - const CArcInfoEx &ai = op.codecs->Formats[(unsigned)formatIndex]; - if (ai.FindExtension(extension) >= 0) - { - if (ai.Flags_FindSignature() && searchMarkerInHandler) - return S_FALSE; - } - } - } - - NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler; - CMyComPtr handler = handlerSpec; - - CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; - CMyComPtr extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec; - extractCallback_To_OpenCallback_Spec->Init(op.callback); - - { - // ---------- Check all possible START archives ---------- - // this code is better for full file archives than Parser's code. - - CByteBuffer byteBuffer; - bool endOfFile = false; - size_t processedSize; - { - size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF) - if (bufSize > fileSize) - { - bufSize = (size_t)fileSize; - endOfFile = true; - } - byteBuffer.Alloc(bufSize); - RINOK(InStream_SeekToBegin(op.stream)) - processedSize = bufSize; - RINOK(ReadStream(op.stream, byteBuffer, &processedSize)) - if (processedSize == 0) - return S_FALSE; - if (processedSize < bufSize) - endOfFile = true; - } - CUIntVector sortedFormats; - - unsigned i; - - int splitIndex = -1; - - for (i = 0; i < orderIndices.Size(); i++) - { - // orderIndices[] item cannot be negative here - unsigned form = (unsigned)orderIndices[i]; - if (skipFrontalFormat[form]) - continue; - - const CArcInfoEx &ai = op.codecs->Formats[form]; - - if (ai.Is_Split()) - { - splitIndex = (int)form; - continue; - } - - if (ai.Flags_ByExtOnlyOpen()) - continue; - - if (ai.IsArcFunc) - { - UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize); - if (isArcRes == k_IsArc_Res_NO) - continue; - if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) - continue; - // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue; - sortedFormats.Insert(0, form); - continue; - } - - const bool isNewStyleSignature = IsNewStyleSignature(ai); - bool needCheck = !isNewStyleSignature - || ai.Signatures.IsEmpty() - || ai.Flags_PureStartOpen() - || ai.Flags_StartOpen() - || ai.Flags_BackwardOpen(); - - if (isNewStyleSignature && !ai.Signatures.IsEmpty()) - { - unsigned k; - for (k = 0; k < ai.Signatures.Size(); k++) - { - const CByteBuffer &sig = ai.Signatures[k]; - if (processedSize < ai.SignatureOffset + sig.Size()) - { - if (!endOfFile) - needCheck = true; - } - else if (TestSignature(sig, byteBuffer + ai.SignatureOffset, sig.Size())) - break; - } - if (k != ai.Signatures.Size()) - { - sortedFormats.Insert(0, form); - continue; - } - } - if (needCheck) - sortedFormats.Add(form); - } - - if (splitIndex >= 0) - sortedFormats.Insert(0, (unsigned)splitIndex); - - for (i = 0; i < sortedFormats.Size(); i++) - { - FormatIndex = (int)sortedFormats[i]; - const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex]; - - if (op.callback) - RINOK(op.callback->SetTotal(NULL, &fileSize)) - - RINOK(InStream_SeekToBegin(op.stream)) - - CMyComPtr archive; - RINOK(PrepareToOpen(op, (unsigned)FormatIndex, archive)) - if (!archive) - continue; - - PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name)); - HRESULT result; - { - UInt64 searchLimit = 0; - /* - if (mode.CanReturnArc) - result = archive->Open(op.stream, &searchLimit, op.callback); - else - */ - // if (!CanReturnArc), it's ParserMode, and we need phy size - result = OpenArchiveSpec(archive, - !mode.CanReturnArc, // needPhySize - op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback); - } - - if (result == S_FALSE) - { - skipFrontalFormat[(unsigned)FormatIndex] = true; - // FIXME: maybe we must use LenIsUnknown. - // printf(" OpenForSize Error"); - continue; - } - RINOK(result) - - RINOK(ReadBasicProps(archive, 0, result)) - - if (Offset > 0) - { - continue; // good handler doesn't return such Offset > 0 - // but there are some cases like false prefixed PK00 archive, when - // we can support it? - } - - NArchive::NParser::CParseItem pi; - pi.Offset = (UInt64)Offset; - pi.Size = AvailPhySize; - - // bool needScan = false; - - if (!PhySize_Defined) - { - // it's for Z format - pi.LenIsUnknown = true; - // needScan = true; - // phySize = arcRem; - // nextNeedCheckStartOpen = false; - } - - /* - if (OkPhySize_Defined) - pi.OkSize = pi.OkPhySize; - else - pi.OkSize = pi.Size; - */ - - pi.NormalizeOffset(); - // printf(" phySize = %8d", (unsigned)phySize); - - - if (mode.CanReturnArc) - { - const bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex]; - const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); - bool openCur = false; - - if (!ErrorInfo.ThereIsTail) - openCur = true; - else - { - if (mode.ZerosTailIsAllowed) - { - RINOK(CheckZerosTail(op, (UInt64)(Offset + (Int64)PhySize))) - if (ErrorInfo.IgnoreTail) - openCur = true; - } - if (!openCur) - { - openCur = specFlags.CanReturnFrontal; - if (formatIndex < 0) // format is not forced - { - if (IsPreArcFormat(ai)) - { - // if (mode.SkipSfxStub) - { - openCur = false; - } - } - } - } - } - - if (openCur) - { - InStream = op.stream; - Archive = archive; - return S_OK; - } - } - - skipFrontalFormat[(unsigned)FormatIndex] = true; - - - // if (!mode.CanReturnArc) - /* - if (!ErrorInfo.ThereIsTail) - continue; - */ - if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) - continue; - - // printf("\nAdd offset = %d", (int)pi.Offset); - RINOK(ReadParseItemProps(archive, ai, pi)) - handlerSpec->AddItem(pi); - } - } - - - - - - // ---------- PARSER ---------- - - CUIntVector arc2sig; // formatIndex to signatureIndex - CUIntVector sig2arc; // signatureIndex to formatIndex; - { - unsigned sum = 0; - FOR_VECTOR (i, op.codecs->Formats) - { - arc2sig.Add(sum); - const CObjectVector &sigs = op.codecs->Formats[i].Signatures; - sum += sigs.Size(); - FOR_VECTOR (k, sigs) - sig2arc.Add(i); - } - } - - { - const size_t kBeforeSize = 1 << 16; - const size_t kAfterSize = 1 << 20; - const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize - - const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8); - CByteArr hashBuffer(kNumVals); - Byte *hash = hashBuffer; - memset(hash, 0xFF, kNumVals); - Byte prevs[256]; - memset(prevs, 0xFF, sizeof(prevs)); - if (sig2arc.Size() >= 0xFF) - return S_FALSE; - - CUIntVector difficultFormats; - CBoolArr difficultBools(256); - { - for (unsigned i = 0; i < 256; i++) - difficultBools[i] = false; - } - - bool thereAreHandlersForSearch = false; - - // UInt32 maxSignatureEnd = 0; - - FOR_VECTOR (i, orderIndices) - { - int index = orderIndices[i]; - if (index < 0) - continue; - const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index]; - if (ai.Flags_ByExtOnlyOpen()) - continue; - bool isDifficult = false; - // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31) - if (!ai.NewInterface) - isDifficult = true; - else - { - if (ai.Flags_StartOpen()) - isDifficult = true; - FOR_VECTOR (k, ai.Signatures) - { - const CByteBuffer &sig = ai.Signatures[k]; - /* - UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); - if (maxSignatureEnd < signatureEnd) - maxSignatureEnd = signatureEnd; - */ - if (sig.Size() < kNumHashBytes) - { - isDifficult = true; - continue; - } - thereAreHandlersForSearch = true; - UInt32 v = HASH_VAL(sig); - unsigned sigIndex = arc2sig[(unsigned)index] + k; - prevs[sigIndex] = hash[v]; - hash[v] = (Byte)sigIndex; - } - } - if (isDifficult) - { - difficultFormats.Add((unsigned)index); - difficultBools[(unsigned)index] = true; - } - } - - if (!thereAreHandlersForSearch) - { - // openOnlyFullArc = true; - // canReturnTailArc = true; - } - - RINOK(InStream_SeekToBegin(op.stream)) - - CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream; - CMyComPtr limitedStream = limitedStreamSpec; - limitedStreamSpec->SetStream(op.stream); - - CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL; - CMyComPtr openCallback_Offset; - if (op.callback) - { - openCallback_Offset_Spec = new CArchiveOpenCallback_Offset; - openCallback_Offset = openCallback_Offset_Spec; - openCallback_Offset_Spec->Callback = op.callback; - openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback); - #ifndef Z7_NO_CRYPTO - openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword); - #endif - } - - if (op.callback) - RINOK(op.callback->SetTotal(NULL, &fileSize)) - - CByteBuffer &byteBuffer = limitedStreamSpec->Buffer; - byteBuffer.Alloc(kBufSize); - - UInt64 callbackPrev = 0; - bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos. - - bool endOfFile = false; - UInt64 bufPhyPos = 0; - size_t bytesInBuf = 0; - // UInt64 prevPos = 0; - - // ---------- Main Scan Loop ---------- - - UInt64 pos = 0; - - if (!mode.EachPos && handlerSpec->_items.Size() == 1) - { - NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; - if (!pi.LenIsUnknown && pi.Offset == 0) - pos = pi.Size; - } - - for (;;) - { - // printf("\nPos = %d", (int)pos); - UInt64 posInBuf = pos - bufPhyPos; - - // if (pos > ((UInt64)1 << 35)) break; - - if (!endOfFile) - { - if (bytesInBuf < kBufSize) - { - size_t processedSize = kBufSize - bytesInBuf; - // printf("\nRead ask = %d", (unsigned)processedSize); - UInt64 seekPos = bufPhyPos + bytesInBuf; - RINOK(InStream_SeekSet(op.stream, bufPhyPos + bytesInBuf)) - RINOK(ReadStream(op.stream, byteBuffer.NonConstData() + bytesInBuf, &processedSize)) - // printf(" processed = %d", (unsigned)processedSize); - if (processedSize == 0) - { - fileSize = seekPos; - endOfFile = true; - } - else - { - bytesInBuf += processedSize; - limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos); - } - continue; - } - - if (bytesInBuf < posInBuf) - { - UInt64 skipSize = posInBuf - bytesInBuf; - if (skipSize <= kBeforeSize) - { - size_t keepSize = (size_t)(kBeforeSize - skipSize); - // printf("\nmemmove skip = %d", (int)keepSize); - memmove(byteBuffer, byteBuffer.ConstData() + bytesInBuf - keepSize, keepSize); - bytesInBuf = keepSize; - bufPhyPos = pos - keepSize; - continue; - } - // printf("\nSkip %d", (int)(skipSize - kBeforeSize)); - // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL)); - bytesInBuf = 0; - bufPhyPos = pos - kBeforeSize; - continue; - } - - if (bytesInBuf - posInBuf < kAfterSize) - { - size_t beg = (size_t)posInBuf - kBeforeSize; - // printf("\nmemmove for after beg = %d", (int)beg); - memmove(byteBuffer, byteBuffer.ConstData() + beg, bytesInBuf - beg); - bufPhyPos += beg; - bytesInBuf -= beg; - continue; - } - } - - if (bytesInBuf <= (size_t)posInBuf) - break; - - bool useOffsetCallback = false; - if (openCallback_Offset) - { - openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); - openCallback_Offset_Spec->Offset = pos; - - useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1); - - if (pos >= callbackPrev + (1 << 23)) - { - RINOK(openCallback_Offset->SetCompleted(NULL, NULL)) - callbackPrev = pos; - } - } - - { - UInt64 endPos = bufPhyPos + bytesInBuf; - if (fileSize < endPos) - { - FileSize = fileSize; // why ???? - fileSize = endPos; - } - } - - const size_t availSize = bytesInBuf - (size_t)posInBuf; - if (availSize < kNumHashBytes) - break; - size_t scanSize = availSize - - ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes); - - { - /* - UInt64 scanLimit = openOnlyFullArc ? - maxSignatureEnd : - op.openType.ScanSize + maxSignatureEnd; - */ - if (!mode.CanReturnParser) - { - if (pos > maxStartOffset) - break; - UInt64 remScan = maxStartOffset - pos; - if (scanSize > remScan) - scanSize = (size_t)remScan; - } - } - - scanSize++; - - const Byte *buf = byteBuffer.ConstData() + (size_t)posInBuf; - const Byte *bufLimit = buf + scanSize; - size_t ppp = 0; - - if (!needCheckStartOpen) - { - for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++); - ppp = (size_t)(buf - (byteBuffer.ConstData() + (size_t)posInBuf)); - pos += ppp; - if (buf == bufLimit) - continue; - } - - UInt32 v = HASH_VAL(buf); - bool nextNeedCheckStartOpen = true; - unsigned i = hash[v]; - unsigned indexOfDifficult = 0; - - // ---------- Open Loop for Current Pos ---------- - bool wasOpen = false; - - for (;;) - { - unsigned index; - bool isDifficult; - if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size()) - { - index = difficultFormats[indexOfDifficult++]; - isDifficult = true; - } - else - { - if (i == 0xFF) - break; - index = sig2arc[i]; - unsigned sigIndex = i - arc2sig[index]; - i = prevs[i]; - if (needCheckStartOpen && difficultBools[index]) - continue; - const CArcInfoEx &ai = op.codecs->Formats[index]; - - if (pos < ai.SignatureOffset) - continue; - - /* - if (openOnlyFullArc) - if (pos != ai.SignatureOffset) - continue; - */ - - const CByteBuffer &sig = ai.Signatures[sigIndex]; - - if (ppp + sig.Size() > availSize - || !TestSignature(buf, sig, sig.Size())) - continue; - // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos)); - // prevPos = pos; - isDifficult = false; - } - - const CArcInfoEx &ai = op.codecs->Formats[index]; - - - if ((isDifficult && pos == 0) || ai.SignatureOffset == pos) - { - // we don't check same archive second time */ - if (skipFrontalFormat[index]) - continue; - } - - UInt64 startArcPos = pos; - if (!isDifficult) - { - if (pos < ai.SignatureOffset) - continue; - startArcPos = pos - ai.SignatureOffset; - /* - // we don't need the check for Z files - if (startArcPos < handlerSpec->GetLastEnd()) - continue; - */ - } - - if (ai.IsArcFunc && startArcPos >= bufPhyPos) - { - const size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos); - if (offsetInBuf < bytesInBuf) - { - const UInt32 isArcRes = ai.IsArcFunc(byteBuffer.ConstData() + offsetInBuf, bytesInBuf - offsetInBuf); - if (isArcRes == k_IsArc_Res_NO) - continue; - if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) - continue; - /* - if (isArcRes == k_IsArc_Res_YES_LOW_PROB) - { - // if (pos != ai.SignatureOffset) - continue; - } - */ - } - // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name); - } - - PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name)); - - const bool isMainFormat = isMainFormatArr[index]; - const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); - - CMyComPtr archive; - RINOK(PrepareToOpen(op, index, archive)) - if (!archive) - return E_FAIL; - - // OutputDebugStringW(ai.Name); - - const UInt64 rem = fileSize - startArcPos; - - UInt64 arcStreamOffset = 0; - - if (ai.Flags_UseGlobalOffset()) - { - RINOK(limitedStreamSpec->InitAndSeek(0, fileSize)) - RINOK(InStream_SeekSet(limitedStream, startArcPos)) - } - else - { - RINOK(limitedStreamSpec->InitAndSeek(startArcPos, rem)) - arcStreamOffset = startArcPos; - } - - UInt64 maxCheckStartPosition = 0; - - if (openCallback_Offset) - { - openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); - openCallback_Offset_Spec->Offset = startArcPos; - } - - // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset); - extractCallback_To_OpenCallback_Spec->Files = 0; - extractCallback_To_OpenCallback_Spec->Offset = startArcPos; - - HRESULT result = OpenArchiveSpec(archive, - true, // needPhySize - limitedStream, &maxCheckStartPosition, - useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback, - extractCallback_To_OpenCallback); - - RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result)) - - bool isOpen = false; - - if (result == S_FALSE) - { - if (!mode.CanReturnParser) - { - if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen()) - { - ErrorInfo.ErrorFormatIndex = (int)index; - NonOpen_ErrorInfo = ErrorInfo; - // if archive was detected, we don't need additional open attempts - return S_FALSE; - } - continue; - } - if (!ErrorInfo.IsArc_After_NonOpen() || !PhySize_Defined || PhySize == 0) - continue; - } - else - { - if (PhySize_Defined && PhySize == 0) - { - PRF(printf(" phySize_Defined && PhySize == 0 ")); - // we skip that epmty archive case with unusual unexpected (PhySize == 0) from Code function. - continue; - } - isOpen = true; - RINOK(result) - PRF(printf(" OK ")); - } - - // fprintf(stderr, "\n %8X %S", startArcPos, Path); - // printf("\nOpen OK: %S", ai.Name); - - - NArchive::NParser::CParseItem pi; - pi.Offset = startArcPos; - - if (ai.Flags_UseGlobalOffset()) - pi.Offset = (UInt64)Offset; - else if (Offset != 0) - return E_FAIL; - - const UInt64 arcRem = FileSize - pi.Offset; - UInt64 phySize = arcRem; - const bool phySize_Defined = PhySize_Defined; - if (phySize_Defined) - { - if (pi.Offset + PhySize > FileSize) - { - // ErrorInfo.ThereIsTail = true; - PhySize = FileSize - pi.Offset; - } - phySize = PhySize; - } - if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63)) - return E_FAIL; - - /* - if (!ai.UseGlobalOffset) - { - if (phySize > arcRem) - { - ThereIsTail = true; - phySize = arcRem; - } - } - */ - - bool needScan = false; - - - if (isOpen && !phySize_Defined) - { - // it's for Z format, or bzip2,gz,xz with phySize that was not detected - pi.LenIsUnknown = true; - needScan = true; - phySize = arcRem; - nextNeedCheckStartOpen = false; - } - - pi.Size = phySize; - /* - if (OkPhySize_Defined) - pi.OkSize = OkPhySize; - */ - pi.NormalizeOffset(); - // printf(" phySize = %8d", (unsigned)phySize); - - /* - if (needSkipFullArc) - if (pi.Offset == 0 && phySize_Defined && pi.Size >= fileSize) - continue; - */ - if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) - { - // it's possible for dmg archives - if (!mode.CanReturnArc) - continue; - } - - if (mode.EachPos) - pos++; - else if (needScan) - { - pos++; - /* - if (!OkPhySize_Defined) - pos++; - else - pos = pi.Offset + pi.OkSize; - */ - } - else - pos = pi.Offset + pi.Size; - - - RINOK(ReadParseItemProps(archive, ai, pi)) - - if (pi.Offset < startArcPos && !mode.EachPos /* && phySize_Defined */) - { - /* It's for DMG format. - This code deletes all previous items that are included to current item */ - - while (!handlerSpec->_items.IsEmpty()) - { - { - const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back(); - if (back.Offset < pi.Offset) - break; - if (back.Offset + back.Size > pi.Offset + pi.Size) - break; - } - handlerSpec->_items.DeleteBack(); - } - } - - - if (isOpen && mode.CanReturnArc && phySize_Defined) - { - // if (pi.Offset + pi.Size >= fileSize) - bool openCur = false; - - bool thereIsTail = ErrorInfo.ThereIsTail; - if (thereIsTail && mode.ZerosTailIsAllowed) - { - RINOK(CheckZerosTail(op, (UInt64)((Int64)arcStreamOffset + Offset + (Int64)PhySize))) - if (ErrorInfo.IgnoreTail) - thereIsTail = false; - } - - if (pi.Offset != 0) - { - if (!pi.IsNotArcType) - { - if (thereIsTail) - openCur = specFlags.CanReturnMid; - else - openCur = specFlags.CanReturnTail; - } - } - else - { - if (!thereIsTail) - openCur = true; - else - openCur = specFlags.CanReturnFrontal; - - if (formatIndex >= -2) - openCur = true; - } - - if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */) - openCur = false; - - // We open file as SFX, if there is front archive or first archive is "Self Executable" - if (!openCur && !pi.IsSelfExe && !thereIsTail && - (!pi.IsNotArcType || pi.Offset == 0)) - { - if (handlerSpec->_items.IsEmpty()) - { - if (specFlags.CanReturnTail) - openCur = true; - } - else if (handlerSpec->_items.Size() == 1) - { - if (handlerSpec->_items[0].IsSelfExe) - { - if (mode.SpecUnknownExt.CanReturnTail) - openCur = true; - } - } - } - - if (openCur) - { - InStream = op.stream; - Archive = archive; - FormatIndex = (int)index; - ArcStreamOffset = arcStreamOffset; - return S_OK; - } - } - - /* - if (openOnlyFullArc) - { - ErrorInfo.ClearErrors(); - return S_FALSE; - } - */ - - pi.FormatIndex = (int)index; - - // printf("\nAdd offset = %d", (int)pi.Offset); - handlerSpec->AddItem(pi); - wasOpen = true; - break; - } - // ---------- End of Open Loop for Current Pos ---------- - - if (!wasOpen) - pos++; - needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen); - } - // ---------- End of Main Scan Loop ---------- - - /* - if (handlerSpec->_items.Size() == 1) - { - const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; - if (pi.Size == fileSize && pi.Offset == 0) - { - Archive = archive; - FormatIndex2 = pi.FormatIndex; - return S_OK; - } - } - */ - - if (mode.CanReturnParser) - { - bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing - handlerSpec->AddUnknownItem(fileSize); - if (handlerSpec->_items.Size() == 0) - return S_FALSE; - if (returnParser || handlerSpec->_items.Size() != 1) - { - // return S_FALSE; - handlerSpec->_stream = op.stream; - Archive = handler; - ErrorInfo.ClearErrors(); - IsParseArc = true; - FormatIndex = -1; // It's parser - Offset = 0; - return S_OK; - } - } - } - - #endif - - if (!Archive) - return S_FALSE; - return S_OK; -} - - - - -HRESULT CArc::OpenStream(const COpenOptions &op) -{ - RINOK(OpenStream2(op)) - // PrintNumber("op.formatIndex 3", op.formatIndex); - - if (Archive) - { - GetRawProps.Release(); - GetRootProps.Release(); - Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); - Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); - - RINOK(Archive_GetArcProp_Bool(Archive, kpidIsTree, IsTree)) - RINOK(Archive_GetArcProp_Bool(Archive, kpidIsDeleted, Ask_Deleted)) - RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAltStream, Ask_AltStream)) - RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAux, Ask_Aux)) - RINOK(Archive_GetArcProp_Bool(Archive, kpidINode, Ask_INode)) - RINOK(Archive_GetArcProp_Bool(Archive, kpidReadOnly, IsReadOnly)) - - const UString fileName = ExtractFileNameFromPath(Path); - UString extension; - { - int dotPos = fileName.ReverseFind_Dot(); - if (dotPos >= 0) - extension = fileName.Ptr((unsigned)(dotPos + 1)); - } - - DefaultName.Empty(); - if (FormatIndex >= 0) - { - const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex]; - if (ai.Exts.Size() == 0) - DefaultName = GetDefaultName2(fileName, UString(), UString()); - else - { - int subExtIndex = ai.FindExtension(extension); - if (subExtIndex < 0) - subExtIndex = 0; - const CArcExtInfo &extInfo = ai.Exts[(unsigned)subExtIndex]; - DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); - } - } - } - - return S_OK; -} - -#ifdef Z7_SFX - -#ifdef _WIN32 - #define k_ExeExt ".exe" - static const unsigned k_ExeExt_Len = 4; -#else - #define k_ExeExt "" - static const unsigned k_ExeExt_Len = 0; -#endif - -#endif - -HRESULT CArc::OpenStreamOrFile(COpenOptions &op) -{ - CMyComPtr fileStream; - CMyComPtr seqStream; - CInFileStream *fileStreamSpec = NULL; - - if (op.stdInMode) - { -#if 1 - seqStream = new CStdInFileStream; -#else - if (!CreateStdInStream(seqStream)) - return GetLastError_noZero_HRESULT(); -#endif - op.seqStream = seqStream; - } - else if (!op.stream) - { - fileStreamSpec = new CInFileStream; - fileStream = fileStreamSpec; - Path = filePath; - if (!fileStreamSpec->Open(us2fs(Path))) - return GetLastError_noZero_HRESULT(); - op.stream = fileStream; - #ifdef Z7_SFX - IgnoreSplit = true; - #endif - } - - /* - if (callback) - { - UInt64 fileSize; - RINOK(InStream_GetSize_SeekToEnd(op.stream, fileSize)); - RINOK(op.callback->SetTotal(NULL, &fileSize)) - } - */ - - HRESULT res = OpenStream(op); - IgnoreSplit = false; - - #ifdef Z7_SFX - - if (res != S_FALSE - || !fileStreamSpec - || !op.callbackSpec - || NonOpen_ErrorInfo.IsArc_After_NonOpen()) - return res; - - { - if (filePath.Len() > k_ExeExt_Len - && StringsAreEqualNoCase_Ascii(filePath.RightPtr(k_ExeExt_Len), k_ExeExt)) - { - const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len); - FOR_VECTOR (i, op.codecs->Formats) - { - const CArcInfoEx &ai = op.codecs->Formats[i]; - if (ai.Is_Split()) - continue; - UString path3 = path2; - path3.Add_Dot(); - path3 += ai.GetMainExt(); // "7z" for SFX. - Path = path3; - Path += ".001"; - bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); - if (!isOk) - { - Path = path3; - isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); - } - if (isOk) - { - if (fileStreamSpec->Open(us2fs(Path))) - { - op.stream = fileStream; - NonOpen_ErrorInfo.ClearErrors_Full(); - if (OpenStream(op) == S_OK) - return S_OK; - } - } - } - } - } - - #endif - - return res; -} - -void CArchiveLink::KeepModeForNextOpen() -{ - for (unsigned i = Arcs.Size(); i != 0;) - { - i--; - CMyComPtr keep; - Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep); - if (keep) - keep->KeepModeForNextOpen(); - } -} - -HRESULT CArchiveLink::Close() -{ - for (unsigned i = Arcs.Size(); i != 0;) - { - i--; - RINOK(Arcs[i].Close()) - } - IsOpen = false; - // ErrorsText.Empty(); - return S_OK; -} - -void CArchiveLink::Release() -{ - // NonOpenErrorFormatIndex = -1; - NonOpen_ErrorInfo.ClearErrors(); - NonOpen_ArcPath.Empty(); - while (!Arcs.IsEmpty()) - Arcs.DeleteBack(); -} - -/* -void CArchiveLink::Set_ErrorsText() -{ - FOR_VECTOR(i, Arcs) - { - const CArc &arc = Arcs[i]; - if (!arc.ErrorFlagsText.IsEmpty()) - { - if (!ErrorsText.IsEmpty()) - ErrorsText.Add_LF(); - ErrorsText += GetUnicodeString(arc.ErrorFlagsText); - } - if (!arc.ErrorMessage.IsEmpty()) - { - if (!ErrorsText.IsEmpty()) - ErrorsText.Add_LF(); - ErrorsText += arc.ErrorMessage; - } - - if (!arc.WarningMessage.IsEmpty()) - { - if (!ErrorsText.IsEmpty()) - ErrorsText.Add_LF(); - ErrorsText += arc.WarningMessage; - } - } -} -*/ - -HRESULT CArchiveLink::Open(COpenOptions &op) -{ - Release(); - if (op.types->Size() >= 32) - return E_NOTIMPL; - - HRESULT resSpec; - - for (;;) - { - resSpec = S_OK; - - op.openType = COpenType(); - if (op.types->Size() >= 1) - { - COpenType latest; - if (Arcs.Size() < op.types->Size()) - latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; - else - { - latest = (*op.types)[0]; - if (!latest.Recursive) - break; - } - op.openType = latest; - } - else if (Arcs.Size() >= 32) - break; - - /* - op.formatIndex = -1; - if (op.types->Size() >= 1) - { - int latest; - if (Arcs.Size() < op.types->Size()) - latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; - else - { - latest = (*op.types)[0]; - if (latest != -2 && latest != -3) - break; - } - if (latest >= 0) - op.formatIndex = latest; - else if (latest == -1 || latest == -2) - { - // default - } - else if (latest == -3) - op.formatIndex = -2; - else - op.formatIndex = latest + 2; - } - else if (Arcs.Size() >= 32) - break; - */ - - if (Arcs.IsEmpty()) - { - CArc arc; - arc.filePath = op.filePath; - arc.Path = op.filePath; - arc.SubfileIndex = (UInt32)(Int32)-1; - HRESULT result = arc.OpenStreamOrFile(op); - if (result != S_OK) - { - if (result == S_FALSE) - { - NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo; - // NonOpenErrorFormatIndex = arc.ErrorFormatIndex; - NonOpen_ArcPath = arc.Path; - } - return result; - } - Arcs.Add(arc); - continue; - } - - // PrintNumber("op.formatIndex 11", op.formatIndex); - - const CArc &arc = Arcs.Back(); - - if (op.types->Size() > Arcs.Size()) - resSpec = E_NOTIMPL; - - UInt32 mainSubfile; - { - NCOM::CPropVariant prop; - RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop)) - if (prop.vt == VT_UI4) - mainSubfile = prop.ulVal; - else - break; - UInt32 numItems; - RINOK(arc.Archive->GetNumberOfItems(&numItems)) - if (mainSubfile >= numItems) - break; - } - - - CMyComPtr getStream; - if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) - break; - - CMyComPtr subSeqStream; - if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) - break; - - CMyComPtr subStream; - if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) - break; - - CArc arc2; - RINOK(arc.GetItem_Path(mainSubfile, arc2.Path)) - - bool zerosTailIsAllowed; - RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)) - - - if (op.callback) - { - Z7_DECL_CMyComPtr_QI_FROM( - IArchiveOpenSetSubArchiveName, - setSubArchiveName, op.callback) - if (setSubArchiveName) - setSubArchiveName->SetSubArchiveName(arc2.Path); - } - - arc2.SubfileIndex = mainSubfile; - - // CIntVector incl; - CIntVector excl; - - COpenOptions op2; - #ifndef Z7_SFX - op2.props = op.props; - #endif - op2.codecs = op.codecs; - // op2.types = &incl; - op2.openType = op.openType; - op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed; - op2.excludedFormats = ! - op2.stdInMode = false; - op2.stream = subStream; - op2.filePath = arc2.Path; - op2.callback = op.callback; - op2.callbackSpec = op.callbackSpec; - - - HRESULT result = arc2.OpenStream(op2); - resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE); - if (result == S_FALSE) - { - NonOpen_ErrorInfo = arc2.ErrorInfo; - NonOpen_ArcPath = arc2.Path; - break; - } - RINOK(result) - RINOK(arc.GetItem_MTime(mainSubfile, arc2.MTime)) - Arcs.Add(arc2); - } - IsOpen = !Arcs.IsEmpty(); - return resSpec; -} - -HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) -{ - VolumesSize = 0; - COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; - CMyComPtr callback = openCallbackSpec; - openCallbackSpec->Callback = callbackUI; - - FString prefix, name; - - if (!op.stream && !op.stdInMode) - { - NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name); - RINOK(openCallbackSpec->Init2(prefix, name)) - } - else - { - openCallbackSpec->SetSubArchiveName(op.filePath); - } - - op.callback = callback; - op.callbackSpec = openCallbackSpec; - - HRESULT res = Open(op); - - PasswordWasAsked = openCallbackSpec->PasswordWasAsked; - // Password = openCallbackSpec->Password; - - RINOK(res) - // VolumePaths.Add(fs2us(prefix + name)); - - FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed) - { - if (openCallbackSpec->FileNames_WasUsed[i]) - { - VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]); - VolumesSize += openCallbackSpec->FileSizes[i]; - } - } - // VolumesSize = openCallbackSpec->TotalSize; - return S_OK; -} - -HRESULT CArc::ReOpen(const COpenOptions &op, IArchiveOpenCallback *openCallback_Additional) -{ - ErrorInfo.ClearErrors(); - ErrorInfo.ErrorFormatIndex = -1; - - UInt64 fileSize = 0; - if (op.stream) - { - RINOK(InStream_SeekToBegin(op.stream)) - RINOK(InStream_AtBegin_GetSize(op.stream, fileSize)) - // RINOK(InStream_GetSize_SeekToBegin(op.stream, fileSize)) - } - FileSize = fileSize; - - CMyComPtr stream2; - Int64 globalOffset = GetGlobalOffset(); - if (globalOffset <= 0) - stream2 = op.stream; - else - { - CTailInStream *tailStreamSpec = new CTailInStream; - stream2 = tailStreamSpec; - tailStreamSpec->Stream = op.stream; - tailStreamSpec->Offset = (UInt64)globalOffset; - tailStreamSpec->Init(); - RINOK(tailStreamSpec->SeekToStart()) - } - - // There are archives with embedded STUBs (like ZIP), so we must support signature scanning - // But for another archives we can use 0 here. So the code can be fixed !!! - UInt64 maxStartPosition = kMaxCheckStartPosition; - IArchiveOpenCallback *openCallback = openCallback_Additional; - if (!openCallback) - openCallback = op.callback; - HRESULT res = Archive->Open(stream2, &maxStartPosition, openCallback); - - if (res == S_OK) - { - RINOK(ReadBasicProps(Archive, (UInt64)globalOffset, res)) - ArcStreamOffset = (UInt64)globalOffset; - if (ArcStreamOffset != 0) - InStream = op.stream; - } - return res; -} - -HRESULT CArchiveLink::Open3(COpenOptions &op, IOpenCallbackUI *callbackUI) -{ - HRESULT res = Open2(op, callbackUI); - if (callbackUI) - { - RINOK(callbackUI->Open_Finished()) - } - return res; -} - -HRESULT CArchiveLink::ReOpen(COpenOptions &op) -{ - if (Arcs.Size() > 1) - return E_NOTIMPL; - - CObjectVector inc; - CIntVector excl; - - op.types = &inc; - op.excludedFormats = ! - op.stdInMode = false; - op.stream = NULL; - if (Arcs.Size() == 0) // ??? - return Open2(op, NULL); - - /* if archive is multivolume (unsupported here still) - COpenCallbackImp object will exist after Open stage. */ - COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; - CMyComPtr openCallbackNew = openCallbackSpec; - - openCallbackSpec->Callback = NULL; - openCallbackSpec->ReOpenCallback = op.callback; - { - FString dirPrefix, fileName; - NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName); - RINOK(openCallbackSpec->Init2(dirPrefix, fileName)) - } - - - CInFileStream *fileStreamSpec = new CInFileStream; - CMyComPtr stream(fileStreamSpec); - if (!fileStreamSpec->Open(us2fs(op.filePath))) - return GetLastError_noZero_HRESULT(); - op.stream = stream; - - CArc &arc = Arcs[0]; - const HRESULT res = arc.ReOpen(op, openCallbackNew); - - openCallbackSpec->ReOpenCallback = NULL; - - PasswordWasAsked = openCallbackSpec->PasswordWasAsked; - // Password = openCallbackSpec->Password; - - IsOpen = (res == S_OK); - return res; -} - -#ifndef Z7_SFX - -bool ParseComplexSize(const wchar_t *s, UInt64 &result); -bool ParseComplexSize(const wchar_t *s, UInt64 &result) -{ - result = 0; - const wchar_t *end; - UInt64 number = ConvertStringToUInt64(s, &end); - if (end == s) - return false; - if (*end == 0) - { - result = number; - return true; - } - if (end[1] != 0) - return false; - unsigned numBits; - switch (MyCharLower_Ascii(*end)) - { - case 'b': result = number; return true; - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - case 't': numBits = 40; break; - default: return false; - } - if (number >= ((UInt64)1 << (64 - numBits))) - return false; - result = number << numBits; - return true; -} - -static bool ParseTypeParams(const UString &s, COpenType &type) -{ - if (s[0] == 0) - return true; - if (s[1] == 0) - { - switch ((unsigned)(Byte)s[0]) - { - case 'e': type.EachPos = true; return true; - case 'a': type.CanReturnArc = true; return true; - case 'r': type.Recursive = true; return true; - default: break; - } - return false; - } - if (s[0] == 's') - { - UInt64 result; - if (!ParseComplexSize(s.Ptr(1), result)) - return false; - type.MaxStartOffset = result; - type.MaxStartOffset_Defined = true; - return true; - } - - return false; -} - -static bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) -{ - int pos2 = s.Find(L':'); - - { - UString name; - if (pos2 < 0) - { - name = s; - pos2 = (int)s.Len(); - } - else - { - name = s.Left((unsigned)pos2); - pos2++; - } - - int index = codecs.FindFormatForArchiveType(name); - type.Recursive = false; - - if (index < 0) - { - if (name[0] == '*') - { - if (name[1] != 0) - return false; - } - else if (name[0] == '#') - { - if (name[1] != 0) - return false; - type.CanReturnArc = false; - type.CanReturnParser = true; - } - else if (name.IsEqualTo_Ascii_NoCase("hash")) - { - // type.CanReturnArc = false; - // type.CanReturnParser = false; - type.IsHashType = true; - } - else - return false; - } - - type.FormatIndex = index; - - } - - for (unsigned i = (unsigned)pos2; i < s.Len();) - { - int next = s.Find(L':', i); - if (next < 0) - next = (int)s.Len(); - const UString name = s.Mid(i, (unsigned)next - i); - if (name.IsEmpty()) - return false; - if (!ParseTypeParams(name, type)) - return false; - i = (unsigned)next + 1; - } - - return true; -} - -bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types) -{ - types.Clear(); - bool isHashType = false; - for (unsigned pos = 0; pos < s.Len();) - { - int pos2 = s.Find(L'.', pos); - if (pos2 < 0) - pos2 = (int)s.Len(); - UString name = s.Mid(pos, (unsigned)pos2 - pos); - if (name.IsEmpty()) - return false; - COpenType type; - if (!ParseType(codecs, name, type)) - return false; - if (isHashType) - return false; - if (type.IsHashType) - isHashType = true; - types.Add(type); - pos = (unsigned)pos2 + 1; - } - return true; -} - -/* -bool IsHashType(const CObjectVector &types) -{ - if (types.Size() != 1) - return false; - return types[0].IsHashType; -} -*/ - - -#endif +// OpenArchive.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#endif + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/UTFConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "DefaultName.h" +#include "OpenArchive.h" + +#ifndef Z7_SFX +#include "SetProperties.h" +#endif + +#ifndef Z7_SFX +#ifdef SHOW_DEBUG_INFO +#define PRF(x) x +#else +#define PRF(x) +#endif +#endif + +// increase it, if you need to support larger SFX stubs +static const UInt64 kMaxCheckStartPosition = 1 << 23; + +/* +Open: + - formatIndex >= 0 (exact Format) + 1) Open with main type. Archive handler is allowed to use archive start finder. + Warning, if there is tail. + + - formatIndex = -1 (Parser:0) (default) + - same as #1 but doesn't return Parser + + - formatIndex = -2 (#1) + - file has supported extension (like a.7z) + Open with that main type (only starting from start of file). + - open OK: + - if there is no tail - return OK + - if there is tail: + - archive is not "Self Exe" - return OK with Warning, that there is tail + - archive is "Self Exe" + ignore "Self Exe" stub, and tries to open tail + - tail can be open as archive - shows that archive and stub size property. + - tail can't be open as archive - shows Parser ??? + - open FAIL: + Try to open with all other types from offset 0 only. + If some open type is OK and physical archive size is uequal or larger + than file size, then return that archive with warning that cannot be open as [extension type]. + If extension was EXE, it will try to open as unknown_extension case + - file has unknown extension (like a.hhh) + It tries to open via parser code. + - if there is full archive or tail archive and unknown block or "Self Exe" + at front, it shows tail archive and stub size property. + - in another cases, if there is some archive inside file, it returns parser/ + - in another cases, it retuens S_FALSE + + + - formatIndex = -3 (#2) + - same as #1, but + - stub (EXE) + archive is open in Parser + + - formatIndex = -4 (#3) + - returns only Parser. skip full file archive. And show other sub-archives + + - formatIndex = -5 (#4) + - returns only Parser. skip full file archive. And show other sub-archives for each byte pos + +*/ + + + + +using namespace NWindows; + +/* +#ifdef Z7_SFX +#define OPEN_PROPS_PARAM +#else +#define OPEN_PROPS_PARAM , props +#endif +*/ + +/* +CArc::~CArc() +{ + GetRawProps.Release(); + Archive.Release(); + printf("\nCArc::~CArc()\n"); +} +*/ + +#ifndef Z7_SFX + +namespace NArchive { +namespace NParser { + +struct CParseItem +{ + UInt64 Offset; + UInt64 Size; + // UInt64 OkSize; + UString Name; + UString Extension; + FILETIME FileTime; + UString Comment; + UString ArcType; + + bool FileTime_Defined; + bool UnpackSize_Defined; + bool NumSubDirs_Defined; + bool NumSubFiles_Defined; + + bool IsSelfExe; + bool IsNotArcType; + + UInt64 UnpackSize; + UInt64 NumSubDirs; + UInt64 NumSubFiles; + + int FormatIndex; + + bool LenIsUnknown; + + CParseItem(): + // OkSize(0), + FileTime_Defined(false), + UnpackSize_Defined(false), + NumSubDirs_Defined(false), + NumSubFiles_Defined(false), + IsSelfExe(false), + IsNotArcType(false), + LenIsUnknown(false) + {} + + /* + bool IsEqualTo(const CParseItem &item) const + { + return Offset == item.Offset && Size == item.Size; + } + */ + + void NormalizeOffset() + { + if ((Int64)Offset < 0) + { + Size += Offset; + // OkSize += Offset; + Offset = 0; + } + } +}; + +Z7_CLASS_IMP_CHandler_IInArchive_1( + IInArchiveGetStream +) +public: + CObjectVector _items; + UInt64 _maxEndOffset; + CMyComPtr _stream; + + UInt64 GetLastEnd() const + { + if (_items.IsEmpty()) + return 0; + const CParseItem &back = _items.Back(); + return back.Offset + back.Size; + } + + void AddUnknownItem(UInt64 next); + int FindInsertPos(const CParseItem &item) const; + void AddItem(const CParseItem &item); + + CHandler(): _maxEndOffset(0) {} +}; + +int CHandler::FindInsertPos(const CParseItem &item) const +{ + unsigned left = 0, right = _items.Size(); + while (left != right) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const CParseItem &midItem = _items[mid]; + if (item.Offset < midItem.Offset) + right = mid; + else if (item.Offset > midItem.Offset) + left = mid + 1; + else if (item.Size < midItem.Size) + right = mid; + /* + else if (item.Size > midItem.Size) + left = mid + 1; + */ + else + { + left = mid + 1; + // return -1; + } + } + return (int)left; +} + +void CHandler::AddUnknownItem(UInt64 next) +{ + /* + UInt64 prevEnd = 0; + if (!_items.IsEmpty()) + { + const CParseItem &back = _items.Back(); + prevEnd = back.Offset + back.Size; + } + */ + if (_maxEndOffset < next) + { + CParseItem item2; + item2.Offset = _maxEndOffset; + item2.Size = next - _maxEndOffset; + _maxEndOffset = next; + _items.Add(item2); + } + else if (_maxEndOffset > next && !_items.IsEmpty()) + { + CParseItem &back = _items.Back(); + if (back.LenIsUnknown) + { + back.Size = next - back.Offset; + _maxEndOffset = next; + } + } +} + +void CHandler::AddItem(const CParseItem &item) +{ + AddUnknownItem(item.Offset); + const int pos = FindInsertPos(item); + if (pos != -1) + { + _items.Insert((unsigned)pos, item); + UInt64 next = item.Offset + item.Size; + if (_maxEndOffset < next) + _maxEndOffset = next; + } +} + +/* +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidType, VT_BSTR}, + { NULL, kpidComment, VT_BSTR}, + { NULL, kpidOffset, VT_UI8}, + { NULL, kpidUnpackSize, VT_UI8}, +// { NULL, kpidNumSubDirs, VT_UI8}, +}; +*/ + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidMTime, + kpidType, + kpidComment, + kpidOffset, + kpidUnpackSize +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps_NO + +Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */)) +{ + COM_TRY_BEGIN + { + Close(); + _stream = stream; + } + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Close()) +{ + _items.Clear(); + _stream.Release(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CParseItem &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + char sz[32]; + ConvertUInt32ToString(index + 1, sz); + UString s(sz); + if (!item.Name.IsEmpty()) + { + s.Add_Dot(); + s += item.Name; + } + if (!item.Extension.IsEmpty()) + { + s.Add_Dot(); + s += item.Extension; + } + prop = s; break; + } + case kpidSize: + case kpidPackSize: prop = item.Size; break; + case kpidOffset: prop = item.Offset; break; + case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break; + case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break; + case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break; + case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break; + case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break; + case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break; + default: break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback)) +{ + COM_TRY_BEGIN + + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (_stream && numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + totalSize += _items[allFilesMode ? i : indices[i]].Size; + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr inStream(streamSpec); + streamSpec->SetStream(_stream); + + CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream; + CMyComPtr outStream(outStreamSpec); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()) + CMyComPtr realOutStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + const CParseItem &item = _items[index]; + + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) + UInt64 unpackSize = item.Size; + totalSize += unpackSize; + bool skipMode = false; + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)) + + outStreamSpec->SetStream(realOutStream); + realOutStream.Release(); + outStreamSpec->Init(skipMode ? 0 : unpackSize, true); + + Int32 opRes = NExtract::NOperationResult::kOK; + RINOK(InStream_SeekSet(_stream, item.Offset)) + streamSpec->Init(unpackSize); + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)) + + if (outStreamSpec->GetRem() != 0) + opRes = NExtract::NOperationResult::kDataError; + outStreamSpec->ReleaseStream(); + RINOK(extractCallback->SetOperationResult(opRes)) + } + + return S_OK; + + COM_TRY_END +} + + +Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) +{ + COM_TRY_BEGIN + const CParseItem &item = _items[index]; + return CreateLimitedInStream(_stream, item.Offset, item.Size, stream); + COM_TRY_END +} + +}} + +#endif + +HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw() +{ + NCOM::CPropVariant prop; + result = false; + RINOK(arc->GetProperty(index, propID, &prop)) + if (prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsDir, result); +} + +HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsAux, result); +} + +HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result); +} + +HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw() +{ + return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); +} + +static HRESULT Archive_GetArcProp_Bool(IInArchive *arc, PROPID propid, bool &result) throw() +{ + NCOM::CPropVariant prop; + result = false; + RINOK(arc->GetArchiveProperty(propid, &prop)) + if (prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined) +{ + defined = false; + NCOM::CPropVariant prop; + RINOK(arc->GetArchiveProperty(propid, &prop)) + switch (prop.vt) + { + case VT_UI4: result = prop.ulVal; break; + case VT_I4: result = (UInt64)(Int64)prop.lVal; break; + case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; break; + case VT_I8: result = (UInt64)prop.hVal.QuadPart; break; + case VT_EMPTY: return S_OK; + default: return E_FAIL; + } + defined = true; + return S_OK; +} + +static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined) +{ + defined = false; + NCOM::CPropVariant prop; + RINOK(arc->GetArchiveProperty(propid, &prop)) + switch (prop.vt) + { + case VT_UI4: result = prop.ulVal; break; + case VT_I4: result = prop.lVal; break; + case VT_UI8: result = (Int64)prop.uhVal.QuadPart; break; + case VT_I8: result = (Int64)prop.hVal.QuadPart; break; + case VT_EMPTY: return S_OK; + default: return E_FAIL; + } + defined = true; + return S_OK; +} + +#ifndef Z7_SFX + +HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const +{ + if (!GetRawProps) + return E_FAIL; + if (index == parent) + return S_OK; + UInt32 curIndex = index; + + UString s; + + bool prevWasAltStream = false; + + for (;;) + { + #ifdef MY_CPU_LE + const void *p; + UInt32 size; + UInt32 propType; + RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)) + if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) + s = (const wchar_t *)p; + else + #endif + { + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(curIndex, kpidName, &prop)) + if (prop.vt == VT_BSTR && prop.bstrVal) + s.SetFromBstr(prop.bstrVal); + else if (prop.vt == VT_EMPTY) + s.Empty(); + else + return E_FAIL; + } + + UInt32 curParent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType)) + + // 18.06: fixed : we don't want to split name to parts + /* + if (parentType != NParentType::kAltStream) + { + for (;;) + { + int pos = s.ReverseFind_PathSepar(); + if (pos < 0) + { + break; + } + parts.Insert(0, s.Ptr(pos + 1)); + s.DeleteFrom(pos); + } + } + */ + + parts.Insert(0, s); + + if (prevWasAltStream) + { + { + UString &s2 = parts[parts.Size() - 2]; + s2.Add_Colon(); + s2 += parts.Back(); + } + parts.DeleteBack(); + } + + if (parent == curParent) + return S_OK; + + prevWasAltStream = false; + if (parentType == NParentType::kAltStream) + prevWasAltStream = true; + + if (curParent == (UInt32)(Int32)-1) + return E_FAIL; + curIndex = curParent; + } +} + +#endif + + + +HRESULT CArc::GetItem_Path(UInt32 index, UString &result) const +{ + #ifdef MY_CPU_LE + if (GetRawProps) + { + const void *p; + UInt32 size; + UInt32 propType; + if (!IsTree) + { + if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK && + propType == NPropDataType::kUtf16z) + { + unsigned len = size / 2 - 1; + // (len) doesn't include null terminator + + /* + #if WCHAR_MAX > 0xffff + len = (unsigned)Utf16LE__Get_Num_WCHARs(p, len); + + wchar_t *s = result.GetBuf(len); + wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, len, s); + if (s + len != sEnd) return E_FAIL; + *sEnd = 0; + + #else + */ + + wchar_t *s = result.GetBuf(len); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = GetUi16(p); + p = (const void *)((const Byte *)p + 2); + + #if WCHAR_PATH_SEPARATOR != L'/' + if (c == L'/') + c = WCHAR_PATH_SEPARATOR; + else if (c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme + #endif + + *s++ = c; + } + *s = 0; + + // #endif + + result.ReleaseBuf_SetLen(len); + + Convert_UnicodeEsc16_To_UnicodeEscHigh(result); + if (len != 0) + return S_OK; + } + } + /* + else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK && + p && propType == NPropDataType::kUtf16z) + { + size -= 2; + UInt32 totalSize = size; + bool isOK = false; + + { + UInt32 index2 = index; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) + break; + if (parent == (UInt32)(Int32)-1) + { + if (parentType != 0) + totalSize += 2; + isOK = true; + break; + } + index2 = parent; + UInt32 size2; + const void *p2; + if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK && + p2 && propType == NPropDataType::kUtf16z) + break; + totalSize += size2; + } + } + + if (isOK) + { + wchar_t *sz = result.GetBuf_SetEnd(totalSize / 2); + UInt32 pos = totalSize - size; + memcpy((Byte *)sz + pos, p, size); + UInt32 index2 = index; + for (;;) + { + UInt32 parent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK) + break; + if (parent == (UInt32)(Int32)-1) + { + if (parentType != 0) + sz[pos / 2 - 1] = L':'; + break; + } + index2 = parent; + UInt32 size2; + const void *p2; + if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK) + break; + pos -= size2; + memcpy((Byte *)sz + pos, p2, size2); + sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':'; + } + #ifdef _WIN32 + // result.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + return S_OK; + } + } + */ + } + #endif + + { + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(index, kpidPath, &prop)) + if (prop.vt == VT_BSTR && prop.bstrVal) + result.SetFromBstr(prop.bstrVal); + else if (prop.vt == VT_EMPTY) + result.Empty(); + else + return E_FAIL; + } + + if (result.IsEmpty()) + return GetItem_DefaultPath(index, result); + + Convert_UnicodeEsc16_To_UnicodeEscHigh(result); + return S_OK; +} + +HRESULT CArc::GetItem_DefaultPath(UInt32 index, UString &result) const +{ + result.Empty(); + bool isDir; + RINOK(Archive_IsItem_Dir(Archive, index, isDir)) + if (!isDir) + { + result = DefaultName; + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(index, kpidExtension, &prop)) + if (prop.vt == VT_BSTR) + { + result.Add_Dot(); + result += prop.bstrVal; + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + } + return S_OK; +} + +HRESULT CArc::GetItem_Path2(UInt32 index, UString &result) const +{ + RINOK(GetItem_Path(index, result)) + if (Ask_Deleted) + { + bool isDeleted = false; + RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted)) + if (isDeleted) + result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR); + } + return S_OK; +} + +#ifdef SUPPORT_ALT_STREAMS + +int FindAltStreamColon_in_Path(const wchar_t *path) +{ + unsigned i = 0; + int colonPos = -1; + for (;; i++) + { + wchar_t c = path[i]; + if (c == 0) + return colonPos; + if (c == ':') + { + if (colonPos < 0) + colonPos = (int)i; + continue; + } + if (c == WCHAR_PATH_SEPARATOR) + colonPos = -1; + } +} + +#endif + +HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const +{ + #ifdef SUPPORT_ALT_STREAMS + item.IsAltStream = false; + item.AltStreamName.Empty(); + item.MainPath.Empty(); + #endif + + item.IsDir = false; + item.Path.Empty(); + item.ParentIndex = (UInt32)(Int32)-1; + + item.PathParts.Clear(); + + RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir)) + item.MainIsDir = item.IsDir; + + RINOK(GetItem_Path2(index, item.Path)) + + #ifndef Z7_SFX + UInt32 mainIndex = index; + #endif + + #ifdef SUPPORT_ALT_STREAMS + + item.MainPath = item.Path; + if (Ask_AltStream) + { + RINOK(Archive_IsItem_AltStream(Archive, index, item.IsAltStream)) + } + + bool needFindAltStream = false; + + if (item.IsAltStream) + { + needFindAltStream = true; + if (GetRawProps) + { + UInt32 parentType = 0; + UInt32 parentIndex; + RINOK(GetRawProps->GetParent(index, &parentIndex, &parentType)) + if (parentType == NParentType::kAltStream) + { + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(index, kpidName, &prop)) + if (prop.vt == VT_BSTR && prop.bstrVal) + item.AltStreamName.SetFromBstr(prop.bstrVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + else + { + // item.IsAltStream = false; + } + /* + if (item.AltStreamName.IsEmpty()) + item.IsAltStream = false; + */ + + needFindAltStream = false; + item.ParentIndex = parentIndex; + mainIndex = parentIndex; + + if (parentIndex == (UInt32)(Int32)-1) + { + item.MainPath.Empty(); + item.MainIsDir = true; + } + else + { + RINOK(GetItem_Path2(parentIndex, item.MainPath)) + RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir)) + } + } + } + } + + if (item.WriteToAltStreamIfColon || needFindAltStream) + { + /* Good handler must support GetRawProps::GetParent for alt streams. + So the following code currently is not used */ + int colon = FindAltStreamColon_in_Path(item.Path); + if (colon >= 0) + { + item.MainPath.DeleteFrom((unsigned)colon); + item.AltStreamName = item.Path.Ptr((unsigned)(colon + 1)); + item.MainIsDir = (colon == 0 || IsPathSepar(item.Path[(unsigned)colon - 1])); + item.IsAltStream = true; + } + } + + #endif + + #ifndef Z7_SFX + if (item._use_baseParentFolder_mode) + { + RINOK(GetItem_PathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts)) + + #ifdef SUPPORT_ALT_STREAMS + if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty()) + { + int colon; + { + UString &s = item.PathParts.Back(); + colon = FindAltStreamColon_in_Path(s); + if (colon >= 0) + { + item.AltStreamName = s.Ptr((unsigned)(colon + 1)); + item.MainIsDir = (colon == 0 || IsPathSepar(s[(unsigned)colon - 1])); + item.IsAltStream = true; + s.DeleteFrom((unsigned)colon); + } + } + if (colon == 0) + item.PathParts.DeleteBack(); + } + #endif + + } + else + #endif + SplitPathToParts( + #ifdef SUPPORT_ALT_STREAMS + item.MainPath + #else + item.Path + #endif + , item.PathParts); + + return S_OK; +} + +#ifndef Z7_SFX + +static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined) +{ + NCOM::CPropVariant prop; + defined = false; + size = 0; + RINOK(archive->GetProperty(index, kpidSize, &prop)) + switch (prop.vt) + { + case VT_UI1: size = prop.bVal; break; + case VT_UI2: size = prop.uiVal; break; + case VT_UI4: size = prop.ulVal; break; + case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; + case VT_EMPTY: return S_OK; + default: return E_FAIL; + } + defined = true; + return S_OK; +} + +#endif + +HRESULT CArc::GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const +{ + NCOM::CPropVariant prop; + defined = false; + size = 0; + RINOK(Archive->GetProperty(index, kpidSize, &prop)) + switch (prop.vt) + { + case VT_UI1: size = prop.bVal; break; + case VT_UI2: size = prop.uiVal; break; + case VT_UI4: size = prop.ulVal; break; + case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break; + case VT_EMPTY: return S_OK; + default: return E_FAIL; + } + defined = true; + return S_OK; +} + +HRESULT CArc::GetItem_MTime(UInt32 index, CArcTime &at) const +{ + at.Clear(); + NCOM::CPropVariant prop; + RINOK(Archive->GetProperty(index, kpidMTime, &prop)) + + if (prop.vt == VT_FILETIME) + { + /* + // for debug + if (FILETIME_IsZero(prop.at) && MTime.Def) + { + at = MTime; + return S_OK; + } + */ + at.Set_From_Prop(prop); + if (at.Prec == 0) + { + // (at.Prec == 0) before version 22. + // so kpidTimeType is required for that code + prop.Clear(); + RINOK(Archive->GetProperty(index, kpidTimeType, &prop)) + if (prop.vt == VT_UI4) + { + UInt32 val = prop.ulVal; + if (val == NFileTimeType::kWindows) + val = k_PropVar_TimePrec_100ns; + /* + else if (val > k_PropVar_TimePrec_1ns) + { + val = k_PropVar_TimePrec_100ns; + // val = k_PropVar_TimePrec_1ns; + // return E_FAIL; // for debug + } + */ + at.Prec = (UInt16)val; + } + } + return S_OK; + } + + if (prop.vt != VT_EMPTY) + return E_FAIL; + if (MTime.Def) + at = MTime; + return S_OK; +} + +#ifndef Z7_SFX + +static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size) +{ + for (size_t i = 0; i < size; i++) + if (p1[i] != p2[i]) + return false; + return true; +} + + +static void MakeCheckOrder(CCodecs *codecs, + CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, + const Byte *data, size_t dataSize) +{ + for (unsigned i = 0; i < numTypes; i++) + { + const int index = orderIndices[i]; + if (index < 0) + continue; + const CArcInfoEx &ai = codecs->Formats[(unsigned)index]; + if (ai.SignatureOffset == 0) + { + if (ai.Signatures.IsEmpty()) + { + if (dataSize != 0) // 21.04: no Signature means Empty Signature + continue; + } + else + { + unsigned k; + const CObjectVector &sigs = ai.Signatures; + for (k = 0; k < sigs.Size(); k++) + { + const CByteBuffer &sig = sigs[k]; + if (sig.Size() <= dataSize && TestSignature(data, sig, sig.Size())) + break; + } + if (k == sigs.Size()) + continue; + } + } + orderIndices2.Add(index); + orderIndices[i] = -1; + } +} + +#ifdef UNDER_CE + static const unsigned kNumHashBytes = 1; + #define HASH_VAL(buf) ((buf)[0]) +#else + static const unsigned kNumHashBytes = 2; + // #define HASH_VAL(buf) ((buf)[0] | ((UInt32)(buf)[1] << 8)) + #define HASH_VAL(buf) GetUi16(buf) +#endif + +static bool IsExeExt(const UString &ext) +{ + return ext.IsEqualTo_Ascii_NoCase("exe"); +} + +static const char * const k_PreArcFormats[] = +{ + "pe" + , "elf" + , "macho" + , "mub" + , "te" +}; + +static bool IsNameFromList(const UString &s, const char * const names[], size_t num) +{ + for (unsigned i = 0; i < num; i++) + if (StringsAreEqualNoCase_Ascii(s, names[i])) + return true; + return false; +} + + +static bool IsPreArcFormat(const CArcInfoEx &ai) +{ + if (ai.Flags_PreArc()) + return true; + return IsNameFromList(ai.Name, k_PreArcFormats, Z7_ARRAY_SIZE(k_PreArcFormats)); +} + +static const char * const k_Formats_with_simple_signuature[] = +{ + "7z" + , "xz" + , "rar" + , "bzip2" + , "gzip" + , "cab" + , "wim" + , "rpm" + , "vhd" + , "xar" +}; + +static bool IsNewStyleSignature(const CArcInfoEx &ai) +{ + // if (ai.Version >= 0x91F) + if (ai.NewInterface) + return true; + return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, Z7_ARRAY_SIZE(k_Formats_with_simple_signuature)); +} + + + +class CArchiveOpenCallback_Offset Z7_final: + public IArchiveOpenCallback, + public IArchiveOpenVolumeCallback, + #ifndef Z7_NO_CRYPTO + public ICryptoGetTextPassword, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IArchiveOpenCallback) + Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback) + #ifndef Z7_NO_CRYPTO + Z7_COM_QI_ENTRY(ICryptoGetTextPassword) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IArchiveOpenCallback) + Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback) + #ifndef Z7_NO_CRYPTO + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + #endif + +public: + CMyComPtr Callback; + CMyComPtr OpenVolumeCallback; + UInt64 Files; + UInt64 Offset; + + #ifndef Z7_NO_CRYPTO + CMyComPtr GetTextPassword; + #endif +}; + +#ifndef Z7_NO_CRYPTO +Z7_COM7F_IMF(CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password)) +{ + COM_TRY_BEGIN + if (GetTextPassword) + return GetTextPassword->CryptoGetTextPassword(password); + return E_NOTIMPL; + COM_TRY_END +} +#endif + +Z7_COM7F_IMF(CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CArchiveOpenCallback_Offset::SetCompleted(const UInt64 *, const UInt64 *bytes)) +{ + if (!Callback) + return S_OK; + UInt64 value = Offset; + if (bytes) + value += *bytes; + return Callback->SetCompleted(&Files, &value); +} + +Z7_COM7F_IMF(CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value)) +{ + if (OpenVolumeCallback) + return OpenVolumeCallback->GetProperty(propID, value); + NCOM::PropVariant_Clear(value); + return S_OK; + // return E_NOTIMPL; +} + +Z7_COM7F_IMF(CArchiveOpenCallback_Offset::GetStream(const wchar_t *name, IInStream **inStream)) +{ + if (OpenVolumeCallback) + return OpenVolumeCallback->GetStream(name, inStream); + return S_FALSE; +} + +#endif + + +UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp) +{ + if (isDefinedProp != NULL) + *isDefinedProp = false; + + switch (prop.vt) + { + case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart; + case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal; + case VT_EMPTY: return 0; + default: throw 151199; + } +} + +void CArcErrorInfo::ClearErrors() +{ + // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!! + + ThereIsTail = false; + UnexpecedEnd = false; + IgnoreTail = false; + // NonZerosTail = false; + ErrorFlags_Defined = false; + ErrorFlags = 0; + WarningFlags = 0; + TailSize = 0; + + ErrorMessage.Empty(); + WarningMessage.Empty(); +} + +HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) +{ + // OkPhySize_Defined = false; + PhySize_Defined = false; + PhySize = 0; + Offset = 0; + AvailPhySize = FileSize - startPos; + + ErrorInfo.ClearErrors(); + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop)) + ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined); + } + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop)) + ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop); + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidError, &prop)) + if (prop.vt != VT_EMPTY) + ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown error"); + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidWarning, &prop)) + if (prop.vt != VT_EMPTY) + ErrorInfo.WarningMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown warning"); + } + + if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) + { + RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySize_Defined)) + /* + RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); + if (!OkPhySize_Defined) + { + OkPhySize_Defined = PhySize_Defined; + OkPhySize = PhySize; + } + */ + + bool offsetDefined; + RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined)) + + Int64 globalOffset = (Int64)startPos + Offset; + AvailPhySize = (UInt64)((Int64)FileSize - globalOffset); + if (PhySize_Defined) + { + UInt64 endPos = (UInt64)(globalOffset + (Int64)PhySize); + if (endPos < FileSize) + { + AvailPhySize = PhySize; + ErrorInfo.ThereIsTail = true; + ErrorInfo.TailSize = FileSize - endPos; + } + else if (endPos > FileSize) + ErrorInfo.UnexpecedEnd = true; + } + } + + return S_OK; +} + +/* +static void PrintNumber(const char *s, int n) +{ + char temp[100]; + sprintf(temp, "%s %d", s, n); + // OutputDebugStringA(temp); + printf(temp); +} +*/ + +HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive) +{ + // OutputDebugStringA("a1"); + // PrintNumber("formatIndex", formatIndex); + + RINOK(op.codecs->CreateInArchive(formatIndex, archive)) + // OutputDebugStringA("a2"); + if (!archive) + return S_OK; + + #ifdef Z7_EXTERNAL_CODECS + if (op.codecs->NeedSetLibCodecs) + { + const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; + if (ai.LibIndex >= 0 ? + !op.codecs->Libs[(unsigned)ai.LibIndex].SetCodecs : + !op.codecs->Libs.IsEmpty()) + { + CMyComPtr setCompressCodecsInfo; + archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs)) + } + } + } + #endif + + + #ifndef Z7_SFX + + const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; + + // OutputDebugStringW(ai.Name); + // OutputDebugStringA("a3"); + + if (ai.Flags_PreArc()) + { + /* we notify parsers that extract executables, that they don't need + to open archive, if there is tail after executable (for SFX cases) */ + CMyComPtr allowTail; + archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail); + if (allowTail) + allowTail->AllowTail(BoolToInt(true)); + } + + if (op.props) + { + /* + FOR_VECTOR (y, op.props) + { + const COptionalOpenProperties &optProps = (*op.props)[y]; + if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0) + { + RINOK(SetProperties(archive, optProps.Props)); + break; + } + } + */ + RINOK(SetProperties(archive, *op.props)) + } + + #endif + return S_OK; +} + +#ifndef Z7_SFX + +static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi) +{ + pi.Extension = ai.GetMainExt(); + pi.FileTime_Defined = false; + pi.ArcType = ai.Name; + + RINOK(Archive_GetArcProp_Bool(archive, kpidIsNotArcType, pi.IsNotArcType)) + + // RINOK(Archive_GetArcProp_Bool(archive, kpidIsSelfExe, pi.IsSelfExe)); + pi.IsSelfExe = ai.Flags_PreArc(); + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidMTime, &prop)) + if (prop.vt == VT_FILETIME) + { + pi.FileTime_Defined = true; + pi.FileTime = prop.filetime; + } + } + + if (!pi.FileTime_Defined) + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidCTime, &prop)) + if (prop.vt == VT_FILETIME) + { + pi.FileTime_Defined = true; + pi.FileTime = prop.filetime; + } + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidName, &prop)) + if (prop.vt == VT_BSTR) + { + pi.Name.SetFromBstr(prop.bstrVal); + pi.Extension.Empty(); + } + else + { + RINOK(archive->GetArchiveProperty(kpidExtension, &prop)) + if (prop.vt == VT_BSTR) + pi.Extension.SetFromBstr(prop.bstrVal); + } + } + + { + NCOM::CPropVariant prop; + RINOK(archive->GetArchiveProperty(kpidShortComment, &prop)) + if (prop.vt == VT_BSTR) + pi.Comment.SetFromBstr(prop.bstrVal); + } + + + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)) + + // pi.NumSubFiles = numItems; + // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined)); + // if (!pi.UnpackSize_Defined) + { + pi.NumSubFiles = 0; + pi.NumSubDirs = 0; + pi.UnpackSize = 0; + for (UInt32 i = 0; i < numItems; i++) + { + UInt64 size = 0; + bool defined = false; + Archive_GetItem_Size(archive, i, size, defined); + if (defined) + { + pi.UnpackSize_Defined = true; + pi.UnpackSize += size; + } + + bool isDir = false; + Archive_IsItem_Dir(archive, i, isDir); + if (isDir) + pi.NumSubDirs++; + else + pi.NumSubFiles++; + } + if (pi.NumSubDirs != 0) + pi.NumSubDirs_Defined = true; + pi.NumSubFiles_Defined = true; + } + + return S_OK; +} + +#endif + +HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset) +{ + if (!op.stream) + return S_OK; + RINOK(InStream_SeekSet(op.stream, offset)) + const UInt32 kBufSize = 1 << 11; + Byte buf[kBufSize]; + + for (;;) + { + UInt32 processed = 0; + RINOK(op.stream->Read(buf, kBufSize, &processed)) + if (processed == 0) + { + // ErrorInfo.NonZerosTail = false; + ErrorInfo.IgnoreTail = true; + return S_OK; + } + for (size_t i = 0; i < processed; i++) + { + if (buf[i] != 0) + { + // ErrorInfo.IgnoreTail = false; + // ErrorInfo.NonZerosTail = true; + return S_OK; + } + } + } +} + + + +#ifndef Z7_SFX + +Z7_CLASS_IMP_COM_2( + CExtractCallback_To_OpenCallback + , IArchiveExtractCallback + , ICompressProgressInfo +) + Z7_IFACE_COM7_IMP(IProgress) +public: + CMyComPtr Callback; + UInt64 Files; + UInt64 Offset; + + void Init(IArchiveOpenCallback *callback) + { + Callback = callback; + Files = 0; + Offset = 0; + } +}; + +Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)) +{ + if (Callback) + { + UInt64 value = Offset; + if (inSize) + value += *inSize; + return Callback->SetCompleted(&Files, &value); + } + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */)) +{ + *outStream = NULL; + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */)) +{ + return S_OK; +} + + +static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize, + IInStream *stream, const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openCallback, + IArchiveExtractCallback *extractCallback) +{ + /* + if (needPhySize) + { + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpen2, + open2, archive) + if (open2) + return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback); + } + */ + RINOK(archive->Open(stream, maxCheckStartPosition, openCallback)) + if (needPhySize) + { + bool phySize_Defined = false; + UInt64 phySize = 0; + RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined)) + if (phySize_Defined) + return S_OK; + + bool phySizeCantBeDetected = false; + RINOK(Archive_GetArcProp_Bool(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)) + + if (!phySizeCantBeDetected) + { + PRF(printf("\n-- !phySize_Defined after Open, call archive->Extract()")); + // It's for bzip2/gz and some xz archives, where Open operation doesn't know phySize. + // But the Handler will know phySize after full archive testing. + RINOK(archive->Extract(NULL, (UInt32)(Int32)-1, BoolToInt(true), extractCallback)) + PRF(printf("\n-- OK")); + } + } + return S_OK; +} + + + +static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name) +{ + FOR_VECTOR (i, orderIndices) + { + int oi = orderIndices[i]; + if (oi >= 0) + if (StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)oi].Name, name)) + return (int)i; + } + return -1; +} + +#endif + +HRESULT CArc::OpenStream2(const COpenOptions &op) +{ + // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout); + + Archive.Release(); + GetRawProps.Release(); + GetRootProps.Release(); + + ErrorInfo.ClearErrors(); + ErrorInfo.ErrorFormatIndex = -1; + + IsParseArc = false; + ArcStreamOffset = 0; + + // OutputDebugStringA("1"); + // OutputDebugStringW(Path); + + const UString fileName = ExtractFileNameFromPath(Path); + UString extension; + { + const int dotPos = fileName.ReverseFind_Dot(); + if (dotPos >= 0) + extension = fileName.Ptr((unsigned)(dotPos + 1)); + } + + CIntVector orderIndices; + + bool searchMarkerInHandler = false; + #ifdef Z7_SFX + searchMarkerInHandler = true; + #endif + + CBoolArr isMainFormatArr(op.codecs->Formats.Size()); + { + FOR_VECTOR(i, op.codecs->Formats) + isMainFormatArr[i] = false; + } + + const UInt64 maxStartOffset = + op.openType.MaxStartOffset_Defined ? + op.openType.MaxStartOffset : + kMaxCheckStartPosition; + + #ifndef Z7_SFX + bool isUnknownExt = false; + #endif + + #ifndef Z7_SFX + bool isForced = false; + #endif + + unsigned numMainTypes = 0; + const int formatIndex = op.openType.FormatIndex; + + if (formatIndex >= 0) + { + #ifndef Z7_SFX + isForced = true; + #endif + orderIndices.Add(formatIndex); + numMainTypes = 1; + isMainFormatArr[(unsigned)formatIndex] = true; + + searchMarkerInHandler = true; + } + else + { + unsigned numFinded = 0; + #ifndef Z7_SFX + bool isPrearcExt = false; + #endif + + { + #ifndef Z7_SFX + + bool isZip = false; + bool isRar = false; + + const wchar_t c = extension[0]; + if (c == 'z' || c == 'Z' || c == 'r' || c == 'R') + { + bool isNumber = false; + for (unsigned k = 1;; k++) + { + const wchar_t d = extension[k]; + if (d == 0) + break; + if (d < '0' || d > '9') + { + isNumber = false; + break; + } + isNumber = true; + } + if (isNumber) + { + if (c == 'z' || c == 'Z') + isZip = true; + else + isRar = true; + } + } + + #endif + + FOR_VECTOR (i, op.codecs->Formats) + { + const CArcInfoEx &ai = op.codecs->Formats[i]; + + if (IgnoreSplit || !op.openType.CanReturnArc) + if (ai.Is_Split()) + continue; + if (op.excludedFormats->FindInSorted((int)i) >= 0) + continue; + + #ifndef Z7_SFX + if (IsPreArcFormat(ai)) + isPrearcExt = true; + #endif + + if (ai.FindExtension(extension) >= 0 + #ifndef Z7_SFX + || (isZip && ai.Is_Zip()) + || (isRar && ai.Is_Rar()) + #endif + ) + { + // PrintNumber("orderIndices.Insert", i); + orderIndices.Insert(numFinded++, (int)i); + isMainFormatArr[i] = true; + } + else + orderIndices.Add((int)i); + } + } + + if (!op.stream) + { + if (numFinded != 1) + return E_NOTIMPL; + orderIndices.DeleteFrom(1); + } + // PrintNumber("numFinded", numFinded ); + + /* + if (op.openOnlySpecifiedByExtension) + { + if (numFinded != 0 && !IsExeExt(extension)) + orderIndices.DeleteFrom(numFinded); + } + */ + + #ifndef Z7_SFX + + if (op.stream && orderIndices.Size() >= 2) + { + RINOK(InStream_SeekToBegin(op.stream)) + CByteBuffer byteBuffer; + CIntVector orderIndices2; + if (numFinded == 0 || IsExeExt(extension)) + { + // signature search was here + } + else if (extension.IsEqualTo("000") || extension.IsEqualTo("001")) + { + const int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar"); + if (i >= 0) + { + const size_t kBufSize = (1 << 10); + byteBuffer.Alloc(kBufSize); + size_t processedSize = kBufSize; + RINOK(ReadStream(op.stream, byteBuffer, &processedSize)) + if (processedSize >= 16) + { + const Byte *buf = byteBuffer; + const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; + if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0) + { + orderIndices2.Add(orderIndices[(unsigned)i]); + orderIndices[(unsigned)i] = -1; + if (i >= (int)numFinded) + numFinded++; + } + } + } + } + else + { + const size_t kBufSize = (1 << 10); + byteBuffer.Alloc(kBufSize); + size_t processedSize = kBufSize; + RINOK(ReadStream(op.stream, byteBuffer, &processedSize)) + if (processedSize == 0) + return S_FALSE; + + /* + check type order: + 0) matched_extension && Backward + 1) matched_extension && (no_signuature || SignatureOffset != 0) + 2) matched_extension && (matched_signature) + // 3) no signuature + // 4) matched signuature + */ + // we move index from orderIndices to orderIndices2 for priority handlers. + + for (unsigned i = 0; i < numFinded; i++) + { + const int index = orderIndices[i]; + if (index < 0) + continue; + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index]; + if (ai.Flags_BackwardOpen()) + { + // backward doesn't need start signatures + orderIndices2.Add(index); + orderIndices[i] = -1; + } + } + + MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); + MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); + // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0); + // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize); + } + + FOR_VECTOR (i, orderIndices) + { + const int val = orderIndices[i]; + if (val != -1) + orderIndices2.Add(val); + } + orderIndices = orderIndices2; + } + + if (orderIndices.Size() >= 2) + { + const int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso"); + const int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf"); + if (iUdf > iIso && iIso >= 0) + { + const int isoIndex = orderIndices[(unsigned)iIso]; + const int udfIndex = orderIndices[(unsigned)iUdf]; + orderIndices[(unsigned)iUdf] = isoIndex; + orderIndices[(unsigned)iIso] = udfIndex; + } + } + + numMainTypes = numFinded; + isUnknownExt = (numMainTypes == 0) || isPrearcExt; + + #else // Z7_SFX + + numMainTypes = orderIndices.Size(); + + // we need correct numMainTypes for mutlivolume SFX (if some volume is missing) + if (numFinded != 0) + numMainTypes = numFinded; + + #endif + } + + UInt64 fileSize = 0; + if (op.stream) + { + RINOK(InStream_GetSize_SeekToBegin(op.stream, fileSize)) + } + FileSize = fileSize; + + + #ifndef Z7_SFX + + CBoolArr skipFrontalFormat(op.codecs->Formats.Size()); + { + FOR_VECTOR(i, op.codecs->Formats) + skipFrontalFormat[i] = false; + } + + #endif + + const COpenType &mode = op.openType; + + + + + + if (mode.CanReturnArc) + { + // ---------- OPEN main type by extenssion ---------- + + unsigned numCheckTypes = orderIndices.Size(); + if (formatIndex >= 0) + numCheckTypes = numMainTypes; + + for (unsigned i = 0; i < numCheckTypes; i++) + { + FormatIndex = orderIndices[i]; + + // orderIndices[] item cannot be negative here + + bool exactOnly = false; + + #ifndef Z7_SFX + + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex]; + // OutputDebugStringW(ai.Name); + if (i >= numMainTypes) + { + // here we allow mismatched extension only for backward handlers + if (!ai.Flags_BackwardOpen() + // && !ai.Flags_PureStartOpen() + ) + continue; + exactOnly = true; + } + + #endif + + // Some handlers do not set total bytes. So we set it here + if (op.callback) + RINOK(op.callback->SetTotal(NULL, &fileSize)) + + if (op.stream) + { + RINOK(InStream_SeekToBegin(op.stream)) + } + + CMyComPtr archive; + + RINOK(PrepareToOpen(op, (unsigned)FormatIndex, archive)) + if (!archive) + continue; + + HRESULT result; + if (op.stream) + { + UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0; + result = archive->Open(op.stream, &searchLimit, op.callback); + } + else + { + CMyComPtr openSeq; + archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); + if (!openSeq) + return E_NOTIMPL; + result = openSeq->OpenSeq(op.seqStream); + } + + RINOK(ReadBasicProps(archive, 0, result)) + + if (result == S_FALSE) + { + bool isArc = ErrorInfo.IsArc_After_NonOpen(); + + #ifndef Z7_SFX + // if it's archive, we allow another open attempt for parser + if (!mode.CanReturnParser || !isArc) + skipFrontalFormat[(unsigned)FormatIndex] = true; + #endif + + if (exactOnly) + continue; + + if (i == 0 && numMainTypes == 1) + { + // we set NonOpenErrorInfo, only if there is only one main format (defined by extension). + ErrorInfo.ErrorFormatIndex = FormatIndex; + NonOpen_ErrorInfo = ErrorInfo; + + if (!mode.CanReturnParser && isArc) + { + // if (formatIndex < 0 && !searchMarkerInHandler) + { + // if bad archive was detected, we don't need additional open attempts + #ifndef Z7_SFX + if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */) + #endif + return S_FALSE; + } + } + } + + /* + #ifndef Z7_SFX + if (IsExeExt(extension) || ai.Flags_PreArc()) + { + // openOnlyFullArc = false; + // canReturnTailArc = true; + // limitSignatureSearch = true; + } + #endif + */ + + continue; + } + + RINOK(result) + + #ifndef Z7_SFX + + bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex]; + const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); + + bool thereIsTail = ErrorInfo.ThereIsTail; + if (thereIsTail && mode.ZerosTailIsAllowed) + { + RINOK(CheckZerosTail(op, (UInt64)(Offset + (Int64)PhySize))) + if (ErrorInfo.IgnoreTail) + thereIsTail = false; + } + + if (Offset > 0) + { + if (exactOnly + || !searchMarkerInHandler + || !specFlags.CanReturn_NonStart() + || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset)) + continue; + } + if (thereIsTail) + { + if (Offset > 0) + { + if (!specFlags.CanReturnMid) + continue; + } + else if (!specFlags.CanReturnFrontal) + continue; + } + + if (Offset > 0 || thereIsTail) + { + if (formatIndex < 0) + { + if (IsPreArcFormat(ai)) + { + // openOnlyFullArc = false; + // canReturnTailArc = true; + /* + if (mode.SkipSfxStub) + limitSignatureSearch = true; + */ + // if (mode.SkipSfxStub) + { + // skipFrontalFormat[FormatIndex] = true; + continue; + } + } + } + } + + #endif + + Archive = archive; + return S_OK; + } + } + + + + #ifndef Z7_SFX + + if (!op.stream) + return S_FALSE; + + if (formatIndex >= 0 && !mode.CanReturnParser) + { + if (mode.MaxStartOffset_Defined) + { + if (mode.MaxStartOffset == 0) + return S_FALSE; + } + else + { + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)formatIndex]; + if (ai.FindExtension(extension) >= 0) + { + if (ai.Flags_FindSignature() && searchMarkerInHandler) + return S_FALSE; + } + } + } + + NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler; + CMyComPtr handler = handlerSpec; + + CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; + CMyComPtr extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec; + extractCallback_To_OpenCallback_Spec->Init(op.callback); + + { + // ---------- Check all possible START archives ---------- + // this code is better for full file archives than Parser's code. + + CByteBuffer byteBuffer; + bool endOfFile = false; + size_t processedSize; + { + size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF) + if (bufSize > fileSize) + { + bufSize = (size_t)fileSize; + endOfFile = true; + } + byteBuffer.Alloc(bufSize); + RINOK(InStream_SeekToBegin(op.stream)) + processedSize = bufSize; + RINOK(ReadStream(op.stream, byteBuffer, &processedSize)) + if (processedSize == 0) + return S_FALSE; + if (processedSize < bufSize) + endOfFile = true; + } + CUIntVector sortedFormats; + + unsigned i; + + int splitIndex = -1; + + for (i = 0; i < orderIndices.Size(); i++) + { + // orderIndices[] item cannot be negative here + unsigned form = (unsigned)orderIndices[i]; + if (skipFrontalFormat[form]) + continue; + + const CArcInfoEx &ai = op.codecs->Formats[form]; + + if (ai.Is_Split()) + { + splitIndex = (int)form; + continue; + } + + if (ai.Flags_ByExtOnlyOpen()) + continue; + + if (ai.IsArcFunc) + { + UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize); + if (isArcRes == k_IsArc_Res_NO) + continue; + if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) + continue; + // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue; + sortedFormats.Insert(0, form); + continue; + } + + const bool isNewStyleSignature = IsNewStyleSignature(ai); + bool needCheck = !isNewStyleSignature + || ai.Signatures.IsEmpty() + || ai.Flags_PureStartOpen() + || ai.Flags_StartOpen() + || ai.Flags_BackwardOpen(); + + if (isNewStyleSignature && !ai.Signatures.IsEmpty()) + { + unsigned k; + for (k = 0; k < ai.Signatures.Size(); k++) + { + const CByteBuffer &sig = ai.Signatures[k]; + if (processedSize < ai.SignatureOffset + sig.Size()) + { + if (!endOfFile) + needCheck = true; + } + else if (TestSignature(sig, byteBuffer + ai.SignatureOffset, sig.Size())) + break; + } + if (k != ai.Signatures.Size()) + { + sortedFormats.Insert(0, form); + continue; + } + } + if (needCheck) + sortedFormats.Add(form); + } + + if (splitIndex >= 0) + sortedFormats.Insert(0, (unsigned)splitIndex); + + for (i = 0; i < sortedFormats.Size(); i++) + { + FormatIndex = (int)sortedFormats[i]; + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex]; + + if (op.callback) + RINOK(op.callback->SetTotal(NULL, &fileSize)) + + RINOK(InStream_SeekToBegin(op.stream)) + + CMyComPtr archive; + RINOK(PrepareToOpen(op, (unsigned)FormatIndex, archive)) + if (!archive) + continue; + + PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name)); + HRESULT result; + { + UInt64 searchLimit = 0; + /* + if (mode.CanReturnArc) + result = archive->Open(op.stream, &searchLimit, op.callback); + else + */ + // if (!CanReturnArc), it's ParserMode, and we need phy size + result = OpenArchiveSpec(archive, + !mode.CanReturnArc, // needPhySize + op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback); + } + + if (result == S_FALSE) + { + skipFrontalFormat[(unsigned)FormatIndex] = true; + // FIXME: maybe we must use LenIsUnknown. + // printf(" OpenForSize Error"); + continue; + } + RINOK(result) + + RINOK(ReadBasicProps(archive, 0, result)) + + if (Offset > 0) + { + continue; // good handler doesn't return such Offset > 0 + // but there are some cases like false prefixed PK00 archive, when + // we can support it? + } + + NArchive::NParser::CParseItem pi; + pi.Offset = (UInt64)Offset; + pi.Size = AvailPhySize; + + // bool needScan = false; + + if (!PhySize_Defined) + { + // it's for Z format + pi.LenIsUnknown = true; + // needScan = true; + // phySize = arcRem; + // nextNeedCheckStartOpen = false; + } + + /* + if (OkPhySize_Defined) + pi.OkSize = pi.OkPhySize; + else + pi.OkSize = pi.Size; + */ + + pi.NormalizeOffset(); + // printf(" phySize = %8d", (unsigned)phySize); + + + if (mode.CanReturnArc) + { + const bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex]; + const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); + bool openCur = false; + + if (!ErrorInfo.ThereIsTail) + openCur = true; + else + { + if (mode.ZerosTailIsAllowed) + { + RINOK(CheckZerosTail(op, (UInt64)(Offset + (Int64)PhySize))) + if (ErrorInfo.IgnoreTail) + openCur = true; + } + if (!openCur) + { + openCur = specFlags.CanReturnFrontal; + if (formatIndex < 0) // format is not forced + { + if (IsPreArcFormat(ai)) + { + // if (mode.SkipSfxStub) + { + openCur = false; + } + } + } + } + } + + if (openCur) + { + InStream = op.stream; + Archive = archive; + return S_OK; + } + } + + skipFrontalFormat[(unsigned)FormatIndex] = true; + + + // if (!mode.CanReturnArc) + /* + if (!ErrorInfo.ThereIsTail) + continue; + */ + if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) + continue; + + // printf("\nAdd offset = %d", (int)pi.Offset); + RINOK(ReadParseItemProps(archive, ai, pi)) + handlerSpec->AddItem(pi); + } + } + + + + + + // ---------- PARSER ---------- + + CUIntVector arc2sig; // formatIndex to signatureIndex + CUIntVector sig2arc; // signatureIndex to formatIndex; + { + unsigned sum = 0; + FOR_VECTOR (i, op.codecs->Formats) + { + arc2sig.Add(sum); + const CObjectVector &sigs = op.codecs->Formats[i].Signatures; + sum += sigs.Size(); + FOR_VECTOR (k, sigs) + sig2arc.Add(i); + } + } + + { + const size_t kBeforeSize = 1 << 16; + const size_t kAfterSize = 1 << 20; + const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize + + const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8); + CByteArr hashBuffer(kNumVals); + Byte *hash = hashBuffer; + memset(hash, 0xFF, kNumVals); + Byte prevs[256]; + memset(prevs, 0xFF, sizeof(prevs)); + if (sig2arc.Size() >= 0xFF) + return S_FALSE; + + CUIntVector difficultFormats; + CBoolArr difficultBools(256); + { + for (unsigned i = 0; i < 256; i++) + difficultBools[i] = false; + } + + bool thereAreHandlersForSearch = false; + + // UInt32 maxSignatureEnd = 0; + + FOR_VECTOR (i, orderIndices) + { + int index = orderIndices[i]; + if (index < 0) + continue; + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index]; + if (ai.Flags_ByExtOnlyOpen()) + continue; + bool isDifficult = false; + // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31) + if (!ai.NewInterface) + isDifficult = true; + else + { + if (ai.Flags_StartOpen()) + isDifficult = true; + FOR_VECTOR (k, ai.Signatures) + { + const CByteBuffer &sig = ai.Signatures[k]; + /* + UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); + if (maxSignatureEnd < signatureEnd) + maxSignatureEnd = signatureEnd; + */ + if (sig.Size() < kNumHashBytes) + { + isDifficult = true; + continue; + } + thereAreHandlersForSearch = true; + UInt32 v = HASH_VAL(sig); + unsigned sigIndex = arc2sig[(unsigned)index] + k; + prevs[sigIndex] = hash[v]; + hash[v] = (Byte)sigIndex; + } + } + if (isDifficult) + { + difficultFormats.Add((unsigned)index); + difficultBools[(unsigned)index] = true; + } + } + + if (!thereAreHandlersForSearch) + { + // openOnlyFullArc = true; + // canReturnTailArc = true; + } + + RINOK(InStream_SeekToBegin(op.stream)) + + CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream; + CMyComPtr limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(op.stream); + + CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL; + CMyComPtr openCallback_Offset; + if (op.callback) + { + openCallback_Offset_Spec = new CArchiveOpenCallback_Offset; + openCallback_Offset = openCallback_Offset_Spec; + openCallback_Offset_Spec->Callback = op.callback; + openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback); + #ifndef Z7_NO_CRYPTO + openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword); + #endif + } + + if (op.callback) + RINOK(op.callback->SetTotal(NULL, &fileSize)) + + CByteBuffer &byteBuffer = limitedStreamSpec->Buffer; + byteBuffer.Alloc(kBufSize); + + UInt64 callbackPrev = 0; + bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos. + + bool endOfFile = false; + UInt64 bufPhyPos = 0; + size_t bytesInBuf = 0; + // UInt64 prevPos = 0; + + // ---------- Main Scan Loop ---------- + + UInt64 pos = 0; + + if (!mode.EachPos && handlerSpec->_items.Size() == 1) + { + NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; + if (!pi.LenIsUnknown && pi.Offset == 0) + pos = pi.Size; + } + + for (;;) + { + // printf("\nPos = %d", (int)pos); + UInt64 posInBuf = pos - bufPhyPos; + + // if (pos > ((UInt64)1 << 35)) break; + + if (!endOfFile) + { + if (bytesInBuf < kBufSize) + { + size_t processedSize = kBufSize - bytesInBuf; + // printf("\nRead ask = %d", (unsigned)processedSize); + UInt64 seekPos = bufPhyPos + bytesInBuf; + RINOK(InStream_SeekSet(op.stream, bufPhyPos + bytesInBuf)) + RINOK(ReadStream(op.stream, byteBuffer.NonConstData() + bytesInBuf, &processedSize)) + // printf(" processed = %d", (unsigned)processedSize); + if (processedSize == 0) + { + fileSize = seekPos; + endOfFile = true; + } + else + { + bytesInBuf += processedSize; + limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos); + } + continue; + } + + if (bytesInBuf < posInBuf) + { + UInt64 skipSize = posInBuf - bytesInBuf; + if (skipSize <= kBeforeSize) + { + size_t keepSize = (size_t)(kBeforeSize - skipSize); + // printf("\nmemmove skip = %d", (int)keepSize); + memmove(byteBuffer, byteBuffer.ConstData() + bytesInBuf - keepSize, keepSize); + bytesInBuf = keepSize; + bufPhyPos = pos - keepSize; + continue; + } + // printf("\nSkip %d", (int)(skipSize - kBeforeSize)); + // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL)); + bytesInBuf = 0; + bufPhyPos = pos - kBeforeSize; + continue; + } + + if (bytesInBuf - posInBuf < kAfterSize) + { + size_t beg = (size_t)posInBuf - kBeforeSize; + // printf("\nmemmove for after beg = %d", (int)beg); + memmove(byteBuffer, byteBuffer.ConstData() + beg, bytesInBuf - beg); + bufPhyPos += beg; + bytesInBuf -= beg; + continue; + } + } + + if (bytesInBuf <= (size_t)posInBuf) + break; + + bool useOffsetCallback = false; + if (openCallback_Offset) + { + openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); + openCallback_Offset_Spec->Offset = pos; + + useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1); + + if (pos >= callbackPrev + (1 << 23)) + { + RINOK(openCallback_Offset->SetCompleted(NULL, NULL)) + callbackPrev = pos; + } + } + + { + UInt64 endPos = bufPhyPos + bytesInBuf; + if (fileSize < endPos) + { + FileSize = fileSize; // why ???? + fileSize = endPos; + } + } + + const size_t availSize = bytesInBuf - (size_t)posInBuf; + if (availSize < kNumHashBytes) + break; + size_t scanSize = availSize - + ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes); + + { + /* + UInt64 scanLimit = openOnlyFullArc ? + maxSignatureEnd : + op.openType.ScanSize + maxSignatureEnd; + */ + if (!mode.CanReturnParser) + { + if (pos > maxStartOffset) + break; + UInt64 remScan = maxStartOffset - pos; + if (scanSize > remScan) + scanSize = (size_t)remScan; + } + } + + scanSize++; + + const Byte *buf = byteBuffer.ConstData() + (size_t)posInBuf; + const Byte *bufLimit = buf + scanSize; + size_t ppp = 0; + + if (!needCheckStartOpen) + { + for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++); + ppp = (size_t)(buf - (byteBuffer.ConstData() + (size_t)posInBuf)); + pos += ppp; + if (buf == bufLimit) + continue; + } + + UInt32 v = HASH_VAL(buf); + bool nextNeedCheckStartOpen = true; + unsigned i = hash[v]; + unsigned indexOfDifficult = 0; + + // ---------- Open Loop for Current Pos ---------- + bool wasOpen = false; + + for (;;) + { + unsigned index; + bool isDifficult; + if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size()) + { + index = difficultFormats[indexOfDifficult++]; + isDifficult = true; + } + else + { + if (i == 0xFF) + break; + index = sig2arc[i]; + unsigned sigIndex = i - arc2sig[index]; + i = prevs[i]; + if (needCheckStartOpen && difficultBools[index]) + continue; + const CArcInfoEx &ai = op.codecs->Formats[index]; + + if (pos < ai.SignatureOffset) + continue; + + /* + if (openOnlyFullArc) + if (pos != ai.SignatureOffset) + continue; + */ + + const CByteBuffer &sig = ai.Signatures[sigIndex]; + + if (ppp + sig.Size() > availSize + || !TestSignature(buf, sig, sig.Size())) + continue; + // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos)); + // prevPos = pos; + isDifficult = false; + } + + const CArcInfoEx &ai = op.codecs->Formats[index]; + + + if ((isDifficult && pos == 0) || ai.SignatureOffset == pos) + { + // we don't check same archive second time */ + if (skipFrontalFormat[index]) + continue; + } + + UInt64 startArcPos = pos; + if (!isDifficult) + { + if (pos < ai.SignatureOffset) + continue; + startArcPos = pos - ai.SignatureOffset; + /* + // we don't need the check for Z files + if (startArcPos < handlerSpec->GetLastEnd()) + continue; + */ + } + + if (ai.IsArcFunc && startArcPos >= bufPhyPos) + { + const size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos); + if (offsetInBuf < bytesInBuf) + { + const UInt32 isArcRes = ai.IsArcFunc(byteBuffer.ConstData() + offsetInBuf, bytesInBuf - offsetInBuf); + if (isArcRes == k_IsArc_Res_NO) + continue; + if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) + continue; + /* + if (isArcRes == k_IsArc_Res_YES_LOW_PROB) + { + // if (pos != ai.SignatureOffset) + continue; + } + */ + } + // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name); + } + + PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name)); + + const bool isMainFormat = isMainFormatArr[index]; + const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); + + CMyComPtr archive; + RINOK(PrepareToOpen(op, index, archive)) + if (!archive) + return E_FAIL; + + // OutputDebugStringW(ai.Name); + + const UInt64 rem = fileSize - startArcPos; + + UInt64 arcStreamOffset = 0; + + if (ai.Flags_UseGlobalOffset()) + { + RINOK(limitedStreamSpec->InitAndSeek(0, fileSize)) + RINOK(InStream_SeekSet(limitedStream, startArcPos)) + } + else + { + RINOK(limitedStreamSpec->InitAndSeek(startArcPos, rem)) + arcStreamOffset = startArcPos; + } + + UInt64 maxCheckStartPosition = 0; + + if (openCallback_Offset) + { + openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); + openCallback_Offset_Spec->Offset = startArcPos; + } + + // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset); + extractCallback_To_OpenCallback_Spec->Files = 0; + extractCallback_To_OpenCallback_Spec->Offset = startArcPos; + + HRESULT result = OpenArchiveSpec(archive, + true, // needPhySize + limitedStream, &maxCheckStartPosition, + useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback, + extractCallback_To_OpenCallback); + + RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result)) + + bool isOpen = false; + + if (result == S_FALSE) + { + if (!mode.CanReturnParser) + { + if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen()) + { + ErrorInfo.ErrorFormatIndex = (int)index; + NonOpen_ErrorInfo = ErrorInfo; + // if archive was detected, we don't need additional open attempts + return S_FALSE; + } + continue; + } + if (!ErrorInfo.IsArc_After_NonOpen() || !PhySize_Defined || PhySize == 0) + continue; + } + else + { + if (PhySize_Defined && PhySize == 0) + { + PRF(printf(" phySize_Defined && PhySize == 0 ")); + // we skip that epmty archive case with unusual unexpected (PhySize == 0) from Code function. + continue; + } + isOpen = true; + RINOK(result) + PRF(printf(" OK ")); + } + + // fprintf(stderr, "\n %8X %S", startArcPos, Path); + // printf("\nOpen OK: %S", ai.Name); + + + NArchive::NParser::CParseItem pi; + pi.Offset = startArcPos; + + if (ai.Flags_UseGlobalOffset()) + pi.Offset = (UInt64)Offset; + else if (Offset != 0) + return E_FAIL; + + const UInt64 arcRem = FileSize - pi.Offset; + UInt64 phySize = arcRem; + const bool phySize_Defined = PhySize_Defined; + if (phySize_Defined) + { + if (pi.Offset + PhySize > FileSize) + { + // ErrorInfo.ThereIsTail = true; + PhySize = FileSize - pi.Offset; + } + phySize = PhySize; + } + if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63)) + return E_FAIL; + + /* + if (!ai.UseGlobalOffset) + { + if (phySize > arcRem) + { + ThereIsTail = true; + phySize = arcRem; + } + } + */ + + bool needScan = false; + + + if (isOpen && !phySize_Defined) + { + // it's for Z format, or bzip2,gz,xz with phySize that was not detected + pi.LenIsUnknown = true; + needScan = true; + phySize = arcRem; + nextNeedCheckStartOpen = false; + } + + pi.Size = phySize; + /* + if (OkPhySize_Defined) + pi.OkSize = OkPhySize; + */ + pi.NormalizeOffset(); + // printf(" phySize = %8d", (unsigned)phySize); + + /* + if (needSkipFullArc) + if (pi.Offset == 0 && phySize_Defined && pi.Size >= fileSize) + continue; + */ + if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) + { + // it's possible for dmg archives + if (!mode.CanReturnArc) + continue; + } + + if (mode.EachPos) + pos++; + else if (needScan) + { + pos++; + /* + if (!OkPhySize_Defined) + pos++; + else + pos = pi.Offset + pi.OkSize; + */ + } + else + pos = pi.Offset + pi.Size; + + + RINOK(ReadParseItemProps(archive, ai, pi)) + + if (pi.Offset < startArcPos && !mode.EachPos /* && phySize_Defined */) + { + /* It's for DMG format. + This code deletes all previous items that are included to current item */ + + while (!handlerSpec->_items.IsEmpty()) + { + { + const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back(); + if (back.Offset < pi.Offset) + break; + if (back.Offset + back.Size > pi.Offset + pi.Size) + break; + } + handlerSpec->_items.DeleteBack(); + } + } + + + if (isOpen && mode.CanReturnArc && phySize_Defined) + { + // if (pi.Offset + pi.Size >= fileSize) + bool openCur = false; + + bool thereIsTail = ErrorInfo.ThereIsTail; + if (thereIsTail && mode.ZerosTailIsAllowed) + { + RINOK(CheckZerosTail(op, (UInt64)((Int64)arcStreamOffset + Offset + (Int64)PhySize))) + if (ErrorInfo.IgnoreTail) + thereIsTail = false; + } + + if (pi.Offset != 0) + { + if (!pi.IsNotArcType) + { + if (thereIsTail) + openCur = specFlags.CanReturnMid; + else + openCur = specFlags.CanReturnTail; + } + } + else + { + if (!thereIsTail) + openCur = true; + else + openCur = specFlags.CanReturnFrontal; + + if (formatIndex >= -2) + openCur = true; + } + + if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */) + openCur = false; + + // We open file as SFX, if there is front archive or first archive is "Self Executable" + if (!openCur && !pi.IsSelfExe && !thereIsTail && + (!pi.IsNotArcType || pi.Offset == 0)) + { + if (handlerSpec->_items.IsEmpty()) + { + if (specFlags.CanReturnTail) + openCur = true; + } + else if (handlerSpec->_items.Size() == 1) + { + if (handlerSpec->_items[0].IsSelfExe) + { + if (mode.SpecUnknownExt.CanReturnTail) + openCur = true; + } + } + } + + if (openCur) + { + InStream = op.stream; + Archive = archive; + FormatIndex = (int)index; + ArcStreamOffset = arcStreamOffset; + return S_OK; + } + } + + /* + if (openOnlyFullArc) + { + ErrorInfo.ClearErrors(); + return S_FALSE; + } + */ + + pi.FormatIndex = (int)index; + + // printf("\nAdd offset = %d", (int)pi.Offset); + handlerSpec->AddItem(pi); + wasOpen = true; + break; + } + // ---------- End of Open Loop for Current Pos ---------- + + if (!wasOpen) + pos++; + needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen); + } + // ---------- End of Main Scan Loop ---------- + + /* + if (handlerSpec->_items.Size() == 1) + { + const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; + if (pi.Size == fileSize && pi.Offset == 0) + { + Archive = archive; + FormatIndex2 = pi.FormatIndex; + return S_OK; + } + } + */ + + if (mode.CanReturnParser) + { + bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing + handlerSpec->AddUnknownItem(fileSize); + if (handlerSpec->_items.Size() == 0) + return S_FALSE; + if (returnParser || handlerSpec->_items.Size() != 1) + { + // return S_FALSE; + handlerSpec->_stream = op.stream; + Archive = handler; + ErrorInfo.ClearErrors(); + IsParseArc = true; + FormatIndex = -1; // It's parser + Offset = 0; + return S_OK; + } + } + } + + #endif + + if (!Archive) + return S_FALSE; + return S_OK; +} + + + + +HRESULT CArc::OpenStream(const COpenOptions &op) +{ + RINOK(OpenStream2(op)) + // PrintNumber("op.formatIndex 3", op.formatIndex); + + if (Archive) + { + GetRawProps.Release(); + GetRootProps.Release(); + Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); + Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); + + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsTree, IsTree)) + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsDeleted, Ask_Deleted)) + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAltStream, Ask_AltStream)) + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAux, Ask_Aux)) + RINOK(Archive_GetArcProp_Bool(Archive, kpidINode, Ask_INode)) + RINOK(Archive_GetArcProp_Bool(Archive, kpidReadOnly, IsReadOnly)) + + const UString fileName = ExtractFileNameFromPath(Path); + UString extension; + { + int dotPos = fileName.ReverseFind_Dot(); + if (dotPos >= 0) + extension = fileName.Ptr((unsigned)(dotPos + 1)); + } + + DefaultName.Empty(); + if (FormatIndex >= 0) + { + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex]; + if (ai.Exts.Size() == 0) + DefaultName = GetDefaultName2(fileName, UString(), UString()); + else + { + int subExtIndex = ai.FindExtension(extension); + if (subExtIndex < 0) + subExtIndex = 0; + const CArcExtInfo &extInfo = ai.Exts[(unsigned)subExtIndex]; + DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); + } + } + } + + return S_OK; +} + +#ifdef Z7_SFX + +#ifdef _WIN32 + #define k_ExeExt ".exe" + static const unsigned k_ExeExt_Len = 4; +#else + #define k_ExeExt "" + static const unsigned k_ExeExt_Len = 0; +#endif + +#endif + +HRESULT CArc::OpenStreamOrFile(COpenOptions &op) +{ + CMyComPtr fileStream; + CMyComPtr seqStream; + CInFileStream *fileStreamSpec = NULL; + + if (op.stdInMode) + { +#if 1 + seqStream = new CStdInFileStream; +#else + if (!CreateStdInStream(seqStream)) + return GetLastError_noZero_HRESULT(); +#endif + op.seqStream = seqStream; + } + else if (!op.stream) + { + fileStreamSpec = new CInFileStream; + fileStream = fileStreamSpec; + Path = filePath; + if (!fileStreamSpec->Open(us2fs(Path))) + return GetLastError_noZero_HRESULT(); + op.stream = fileStream; + #ifdef Z7_SFX + IgnoreSplit = true; + #endif + } + + /* + if (callback) + { + UInt64 fileSize; + RINOK(InStream_GetSize_SeekToEnd(op.stream, fileSize)); + RINOK(op.callback->SetTotal(NULL, &fileSize)) + } + */ + + HRESULT res = OpenStream(op); + IgnoreSplit = false; + + #ifdef Z7_SFX + + if (res != S_FALSE + || !fileStreamSpec + || !op.callbackSpec + || NonOpen_ErrorInfo.IsArc_After_NonOpen()) + return res; + + { + if (filePath.Len() > k_ExeExt_Len + && StringsAreEqualNoCase_Ascii(filePath.RightPtr(k_ExeExt_Len), k_ExeExt)) + { + const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len); + FOR_VECTOR (i, op.codecs->Formats) + { + const CArcInfoEx &ai = op.codecs->Formats[i]; + if (ai.Is_Split()) + continue; + UString path3 = path2; + path3.Add_Dot(); + path3 += ai.GetMainExt(); // "7z" for SFX. + Path = path3; + Path += ".001"; + bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); + if (!isOk) + { + Path = path3; + isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); + } + if (isOk) + { + if (fileStreamSpec->Open(us2fs(Path))) + { + op.stream = fileStream; + NonOpen_ErrorInfo.ClearErrors_Full(); + if (OpenStream(op) == S_OK) + return S_OK; + } + } + } + } + } + + #endif + + return res; +} + +void CArchiveLink::KeepModeForNextOpen() +{ + for (unsigned i = Arcs.Size(); i != 0;) + { + i--; + CMyComPtr keep; + Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep); + if (keep) + keep->KeepModeForNextOpen(); + } +} + +HRESULT CArchiveLink::Close() +{ + for (unsigned i = Arcs.Size(); i != 0;) + { + i--; + RINOK(Arcs[i].Close()) + } + IsOpen = false; + // ErrorsText.Empty(); + return S_OK; +} + +void CArchiveLink::Release() +{ + // NonOpenErrorFormatIndex = -1; + NonOpen_ErrorInfo.ClearErrors(); + NonOpen_ArcPath.Empty(); + while (!Arcs.IsEmpty()) + Arcs.DeleteBack(); +} + +/* +void CArchiveLink::Set_ErrorsText() +{ + FOR_VECTOR(i, Arcs) + { + const CArc &arc = Arcs[i]; + if (!arc.ErrorFlagsText.IsEmpty()) + { + if (!ErrorsText.IsEmpty()) + ErrorsText.Add_LF(); + ErrorsText += GetUnicodeString(arc.ErrorFlagsText); + } + if (!arc.ErrorMessage.IsEmpty()) + { + if (!ErrorsText.IsEmpty()) + ErrorsText.Add_LF(); + ErrorsText += arc.ErrorMessage; + } + + if (!arc.WarningMessage.IsEmpty()) + { + if (!ErrorsText.IsEmpty()) + ErrorsText.Add_LF(); + ErrorsText += arc.WarningMessage; + } + } +} +*/ + +HRESULT CArchiveLink::Open(COpenOptions &op) +{ + Release(); + if (op.types->Size() >= 32) + return E_NOTIMPL; + + HRESULT resSpec; + + for (;;) + { + resSpec = S_OK; + + op.openType = COpenType(); + if (op.types->Size() >= 1) + { + COpenType latest; + if (Arcs.Size() < op.types->Size()) + latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; + else + { + latest = (*op.types)[0]; + if (!latest.Recursive) + break; + } + op.openType = latest; + } + else if (Arcs.Size() >= 32) + break; + + /* + op.formatIndex = -1; + if (op.types->Size() >= 1) + { + int latest; + if (Arcs.Size() < op.types->Size()) + latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; + else + { + latest = (*op.types)[0]; + if (latest != -2 && latest != -3) + break; + } + if (latest >= 0) + op.formatIndex = latest; + else if (latest == -1 || latest == -2) + { + // default + } + else if (latest == -3) + op.formatIndex = -2; + else + op.formatIndex = latest + 2; + } + else if (Arcs.Size() >= 32) + break; + */ + + if (Arcs.IsEmpty()) + { + CArc arc; + arc.filePath = op.filePath; + arc.Path = op.filePath; + arc.SubfileIndex = (UInt32)(Int32)-1; + HRESULT result = arc.OpenStreamOrFile(op); + if (result != S_OK) + { + if (result == S_FALSE) + { + NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo; + // NonOpenErrorFormatIndex = arc.ErrorFormatIndex; + NonOpen_ArcPath = arc.Path; + } + return result; + } + Arcs.Add(arc); + continue; + } + + // PrintNumber("op.formatIndex 11", op.formatIndex); + + const CArc &arc = Arcs.Back(); + + if (op.types->Size() > Arcs.Size()) + resSpec = E_NOTIMPL; + + UInt32 mainSubfile; + { + NCOM::CPropVariant prop; + RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop)) + if (prop.vt == VT_UI4) + mainSubfile = prop.ulVal; + else + break; + UInt32 numItems; + RINOK(arc.Archive->GetNumberOfItems(&numItems)) + if (mainSubfile >= numItems) + break; + } + + + CMyComPtr getStream; + if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) + break; + + CMyComPtr subSeqStream; + if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) + break; + + CMyComPtr subStream; + if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) + break; + + CArc arc2; + RINOK(arc.GetItem_Path(mainSubfile, arc2.Path)) + + bool zerosTailIsAllowed; + RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)) + + + if (op.callback) + { + Z7_DECL_CMyComPtr_QI_FROM( + IArchiveOpenSetSubArchiveName, + setSubArchiveName, op.callback) + if (setSubArchiveName) + setSubArchiveName->SetSubArchiveName(arc2.Path); + } + + arc2.SubfileIndex = mainSubfile; + + // CIntVector incl; + CIntVector excl; + + COpenOptions op2; + #ifndef Z7_SFX + op2.props = op.props; + #endif + op2.codecs = op.codecs; + // op2.types = &incl; + op2.openType = op.openType; + op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed; + op2.excludedFormats = ! + op2.stdInMode = false; + op2.stream = subStream; + op2.filePath = arc2.Path; + op2.callback = op.callback; + op2.callbackSpec = op.callbackSpec; + + + HRESULT result = arc2.OpenStream(op2); + resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE); + if (result == S_FALSE) + { + NonOpen_ErrorInfo = arc2.ErrorInfo; + NonOpen_ArcPath = arc2.Path; + break; + } + RINOK(result) + RINOK(arc.GetItem_MTime(mainSubfile, arc2.MTime)) + Arcs.Add(arc2); + } + IsOpen = !Arcs.IsEmpty(); + return resSpec; +} + +HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) +{ + VolumesSize = 0; + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr callback = openCallbackSpec; + openCallbackSpec->Callback = callbackUI; + + FString prefix, name; + + if (!op.stream && !op.stdInMode) + { + NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name); + RINOK(openCallbackSpec->Init2(prefix, name)) + } + else + { + openCallbackSpec->SetSubArchiveName(op.filePath); + } + + op.callback = callback; + op.callbackSpec = openCallbackSpec; + + HRESULT res = Open(op); + + PasswordWasAsked = openCallbackSpec->PasswordWasAsked; + // Password = openCallbackSpec->Password; + + RINOK(res) + // VolumePaths.Add(fs2us(prefix + name)); + + FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed) + { + if (openCallbackSpec->FileNames_WasUsed[i]) + { + VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]); + VolumesSize += openCallbackSpec->FileSizes[i]; + } + } + // VolumesSize = openCallbackSpec->TotalSize; + return S_OK; +} + +HRESULT CArc::ReOpen(const COpenOptions &op, IArchiveOpenCallback *openCallback_Additional) +{ + ErrorInfo.ClearErrors(); + ErrorInfo.ErrorFormatIndex = -1; + + UInt64 fileSize = 0; + if (op.stream) + { + RINOK(InStream_SeekToBegin(op.stream)) + RINOK(InStream_AtBegin_GetSize(op.stream, fileSize)) + // RINOK(InStream_GetSize_SeekToBegin(op.stream, fileSize)) + } + FileSize = fileSize; + + CMyComPtr stream2; + Int64 globalOffset = GetGlobalOffset(); + if (globalOffset <= 0) + stream2 = op.stream; + else + { + CTailInStream *tailStreamSpec = new CTailInStream; + stream2 = tailStreamSpec; + tailStreamSpec->Stream = op.stream; + tailStreamSpec->Offset = (UInt64)globalOffset; + tailStreamSpec->Init(); + RINOK(tailStreamSpec->SeekToStart()) + } + + // There are archives with embedded STUBs (like ZIP), so we must support signature scanning + // But for another archives we can use 0 here. So the code can be fixed !!! + UInt64 maxStartPosition = kMaxCheckStartPosition; + IArchiveOpenCallback *openCallback = openCallback_Additional; + if (!openCallback) + openCallback = op.callback; + HRESULT res = Archive->Open(stream2, &maxStartPosition, openCallback); + + if (res == S_OK) + { + RINOK(ReadBasicProps(Archive, (UInt64)globalOffset, res)) + ArcStreamOffset = (UInt64)globalOffset; + if (ArcStreamOffset != 0) + InStream = op.stream; + } + return res; +} + +HRESULT CArchiveLink::Open3(COpenOptions &op, IOpenCallbackUI *callbackUI) +{ + HRESULT res = Open2(op, callbackUI); + if (callbackUI) + { + RINOK(callbackUI->Open_Finished()) + } + return res; +} + +HRESULT CArchiveLink::ReOpen(COpenOptions &op) +{ + if (Arcs.Size() > 1) + return E_NOTIMPL; + + CObjectVector inc; + CIntVector excl; + + op.types = &inc; + op.excludedFormats = ! + op.stdInMode = false; + op.stream = NULL; + if (Arcs.Size() == 0) // ??? + return Open2(op, NULL); + + /* if archive is multivolume (unsupported here still) + COpenCallbackImp object will exist after Open stage. */ + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr openCallbackNew = openCallbackSpec; + + openCallbackSpec->Callback = NULL; + openCallbackSpec->ReOpenCallback = op.callback; + { + FString dirPrefix, fileName; + NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName); + RINOK(openCallbackSpec->Init2(dirPrefix, fileName)) + } + + + CInFileStream *fileStreamSpec = new CInFileStream; + CMyComPtr stream(fileStreamSpec); + if (!fileStreamSpec->Open(us2fs(op.filePath))) + return GetLastError_noZero_HRESULT(); + op.stream = stream; + + CArc &arc = Arcs[0]; + const HRESULT res = arc.ReOpen(op, openCallbackNew); + + openCallbackSpec->ReOpenCallback = NULL; + + PasswordWasAsked = openCallbackSpec->PasswordWasAsked; + // Password = openCallbackSpec->Password; + + IsOpen = (res == S_OK); + return res; +} + +#ifndef Z7_SFX + +bool ParseComplexSize(const wchar_t *s, UInt64 &result); +bool ParseComplexSize(const wchar_t *s, UInt64 &result) +{ + result = 0; + const wchar_t *end; + UInt64 number = ConvertStringToUInt64(s, &end); + if (end == s) + return false; + if (*end == 0) + { + result = number; + return true; + } + if (end[1] != 0) + return false; + unsigned numBits; + switch (MyCharLower_Ascii(*end)) + { + case 'b': result = number; return true; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return false; + } + if (number >= ((UInt64)1 << (64 - numBits))) + return false; + result = number << numBits; + return true; +} + +static bool ParseTypeParams(const UString &s, COpenType &type) +{ + if (s[0] == 0) + return true; + if (s[1] == 0) + { + switch ((unsigned)(Byte)s[0]) + { + case 'e': type.EachPos = true; return true; + case 'a': type.CanReturnArc = true; return true; + case 'r': type.Recursive = true; return true; + default: break; + } + return false; + } + if (s[0] == 's') + { + UInt64 result; + if (!ParseComplexSize(s.Ptr(1), result)) + return false; + type.MaxStartOffset = result; + type.MaxStartOffset_Defined = true; + return true; + } + + return false; +} + +static bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) +{ + int pos2 = s.Find(L':'); + + { + UString name; + if (pos2 < 0) + { + name = s; + pos2 = (int)s.Len(); + } + else + { + name = s.Left((unsigned)pos2); + pos2++; + } + + int index = codecs.FindFormatForArchiveType(name); + type.Recursive = false; + + if (index < 0) + { + if (name[0] == '*') + { + if (name[1] != 0) + return false; + } + else if (name[0] == '#') + { + if (name[1] != 0) + return false; + type.CanReturnArc = false; + type.CanReturnParser = true; + } + else if (name.IsEqualTo_Ascii_NoCase("hash")) + { + // type.CanReturnArc = false; + // type.CanReturnParser = false; + type.IsHashType = true; + } + else + return false; + } + + type.FormatIndex = index; + + } + + for (unsigned i = (unsigned)pos2; i < s.Len();) + { + int next = s.Find(L':', i); + if (next < 0) + next = (int)s.Len(); + const UString name = s.Mid(i, (unsigned)next - i); + if (name.IsEmpty()) + return false; + if (!ParseTypeParams(name, type)) + return false; + i = (unsigned)next + 1; + } + + return true; +} + +bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types) +{ + types.Clear(); + bool isHashType = false; + for (unsigned pos = 0; pos < s.Len();) + { + int pos2 = s.Find(L'.', pos); + if (pos2 < 0) + pos2 = (int)s.Len(); + UString name = s.Mid(pos, (unsigned)pos2 - pos); + if (name.IsEmpty()) + return false; + COpenType type; + if (!ParseType(codecs, name, type)) + return false; + if (isHashType) + return false; + if (type.IsHashType) + isHashType = true; + types.Add(type); + pos = (unsigned)pos2 + 1; + } + return true; +} + +/* +bool IsHashType(const CObjectVector &types) +{ + if (types.Size() != 1) + return false; + return types[0].IsHashType; +} +*/ + + +#endif diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h index cad607dcf..5c3bfe5df 100644 --- a/CPP/7zip/UI/Common/OpenArchive.h +++ b/CPP/7zip/UI/Common/OpenArchive.h @@ -1,469 +1,469 @@ -// OpenArchive.h - -#ifndef ZIP7_INC_OPEN_ARCHIVE_H -#define ZIP7_INC_OPEN_ARCHIVE_H - -#include "../../../Windows/PropVariant.h" - -#include "ArchiveOpenCallback.h" -#include "LoadCodecs.h" -#include "Property.h" -#include "DirItem.h" - -#ifndef Z7_SFX - -#define SUPPORT_ALT_STREAMS - -#endif - -HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw(); -HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw(); -HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw(); -HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw(); -HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw(); - -#ifdef SUPPORT_ALT_STREAMS -int FindAltStreamColon_in_Path(const wchar_t *path); -#endif - -/* -struct COptionalOpenProperties -{ - UString FormatName; - CObjectVector Props; -}; -*/ - -#ifdef Z7_SFX -#define OPEN_PROPS_DECL -#else -#define OPEN_PROPS_DECL const CObjectVector *props; -// #define OPEN_PROPS_DECL , const CObjectVector *props -#endif - -struct COpenSpecFlags -{ - // bool CanReturnFull; - bool CanReturnFrontal; - bool CanReturnTail; - bool CanReturnMid; - - bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; } - - COpenSpecFlags(): - // CanReturnFull(true), - CanReturnFrontal(false), - CanReturnTail(false), - CanReturnMid(false) - {} -}; - -struct COpenType -{ - int FormatIndex; - - COpenSpecFlags SpecForcedType; - COpenSpecFlags SpecMainType; - COpenSpecFlags SpecWrongExt; - COpenSpecFlags SpecUnknownExt; - - bool Recursive; - - bool CanReturnArc; - bool CanReturnParser; - bool IsHashType; - bool EachPos; - - // bool SkipSfxStub; - // bool ExeAsUnknown; - - bool ZerosTailIsAllowed; - - bool MaxStartOffset_Defined; - UInt64 MaxStartOffset; - - const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const - { - return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt)); - } - - COpenType(): - FormatIndex(-1), - Recursive(true), - CanReturnArc(true), - CanReturnParser(false), - IsHashType(false), - EachPos(false), - // SkipSfxStub(true), - // ExeAsUnknown(true), - ZerosTailIsAllowed(false), - MaxStartOffset_Defined(false), - MaxStartOffset(0) - { - SpecForcedType.CanReturnFrontal = true; - SpecForcedType.CanReturnTail = true; - SpecForcedType.CanReturnMid = true; - - SpecMainType.CanReturnFrontal = true; - - SpecUnknownExt.CanReturnTail = true; // for sfx - SpecUnknownExt.CanReturnMid = true; - SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad - - // ZerosTailIsAllowed = true; - } -}; - -struct COpenOptions -{ - CCodecs *codecs; - COpenType openType; - const CObjectVector *types; - const CIntVector *excludedFormats; - - IInStream *stream; - ISequentialInStream *seqStream; - IArchiveOpenCallback *callback; - COpenCallbackImp *callbackSpec; // it's used for SFX only - OPEN_PROPS_DECL - // bool openOnlySpecifiedByExtension, - - bool stdInMode; - UString filePath; - - COpenOptions(): - codecs(NULL), - types(NULL), - excludedFormats(NULL), - stream(NULL), - seqStream(NULL), - callback(NULL), - callbackSpec(NULL), - stdInMode(false) - {} - -}; - -UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL); - -struct CArcErrorInfo -{ - bool ThereIsTail; - bool UnexpecedEnd; - bool IgnoreTail; // all are zeros - // bool NonZerosTail; - bool ErrorFlags_Defined; - UInt32 ErrorFlags; - UInt32 WarningFlags; - int ErrorFormatIndex; // - 1 means no Error. - // if FormatIndex == ErrorFormatIndex, the archive is open with offset - UInt64 TailSize; - - /* if CArc is Open OK with some format: - - ErrorFormatIndex shows error format index, if extension is incorrect - - other variables show message and warnings of archive that is open */ - - UString ErrorMessage; - UString WarningMessage; - - // call IsArc_After_NonOpen only if Open returns S_FALSE - bool IsArc_After_NonOpen() const - { - return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0); - } - - - CArcErrorInfo(): - ThereIsTail(false), - UnexpecedEnd(false), - IgnoreTail(false), - // NonZerosTail(false), - ErrorFlags_Defined(false), - ErrorFlags(0), - WarningFlags(0), - ErrorFormatIndex(-1), - TailSize(0) - {} - - void ClearErrors(); - - void ClearErrors_Full() - { - ErrorFormatIndex = -1; - ClearErrors(); - } - - bool IsThereErrorOrWarning() const - { - return ErrorFlags != 0 - || WarningFlags != 0 - || NeedTailWarning() - || UnexpecedEnd - || !ErrorMessage.IsEmpty() - || !WarningMessage.IsEmpty(); - } - - bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; } - bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); } - - bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; } - - UInt32 GetWarningFlags() const - { - UInt32 a = WarningFlags; - if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0) - a |= kpv_ErrorFlags_DataAfterEnd; - return a; - } - - UInt32 GetErrorFlags() const - { - UInt32 a = ErrorFlags; - if (UnexpecedEnd) - a |= kpv_ErrorFlags_UnexpectedEnd; - return a; - } -}; - -struct CReadArcItem -{ - UString Path; // Path from root (including alt stream name, if alt stream) - UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode - - #ifdef SUPPORT_ALT_STREAMS - UString MainPath; - /* MainPath = Path for non-AltStream, - MainPath = Path of parent, if there is parent for AltStream. */ - UString AltStreamName; - bool IsAltStream; - bool WriteToAltStreamIfColon; - #endif - - bool IsDir; - bool MainIsDir; - UInt32 ParentIndex; // use it, if IsAltStream - - #ifndef Z7_SFX - bool _use_baseParentFolder_mode; - int _baseParentFolder; - #endif - - CReadArcItem() - { - #ifdef SUPPORT_ALT_STREAMS - WriteToAltStreamIfColon = false; - #endif - - #ifndef Z7_SFX - _use_baseParentFolder_mode = false; - _baseParentFolder = -1; - #endif - } -}; - - - - -class CArc -{ - HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive); - HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset); - HRESULT OpenStream2(const COpenOptions &options); - - #ifndef Z7_SFX - // parts.Back() can contain alt stream name "nams:AltName" - HRESULT GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; - #endif - -public: - CMyComPtr Archive; - CMyComPtr InStream; - // we use InStream in 2 cases (ArcStreamOffset != 0): - // 1) if we use additional cache stream - // 2) we reopen sfx archive with CTailInStream - - CMyComPtr GetRawProps; - CMyComPtr GetRootProps; - - bool IsParseArc; - - bool IsTree; - bool IsReadOnly; - - bool Ask_Deleted; - bool Ask_AltStream; - bool Ask_Aux; - bool Ask_INode; - - bool IgnoreSplit; // don't try split handler - - UString Path; - UString filePath; - UString DefaultName; - int FormatIndex; // -1 means Parser - UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile - - // CFiTime MTime; - // bool MTime_Defined; - CArcTime MTime; - - Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler - UInt64 PhySize; - // UInt64 OkPhySize; - bool PhySize_Defined; - // bool OkPhySize_Defined; - UInt64 FileSize; - UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file - - CArcErrorInfo ErrorInfo; // for OK archives - CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN) - - UInt64 GetEstmatedPhySize() const { return PhySize_Defined ? PhySize : FileSize; } - - UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler - Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive - - // AString ErrorFlagsText; - - // void Set_ErrorFlagsText(); - - CArc(): - // MTime_Defined(false), - IsTree(false), - IsReadOnly(false), - Ask_Deleted(false), - Ask_AltStream(false), - Ask_Aux(false), - Ask_INode(false), - IgnoreSplit(false) - {} - - HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes); - - HRESULT Close() - { - InStream.Release(); - return Archive->Close(); - } - - HRESULT GetItem_Path(UInt32 index, UString &result) const; - HRESULT GetItem_DefaultPath(UInt32 index, UString &result) const; - - // GetItemPath2 adds [DELETED] dir prefix for deleted items. - HRESULT GetItem_Path2(UInt32 index, UString &result) const; - - HRESULT GetItem(UInt32 index, CReadArcItem &item) const; - - HRESULT GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const; - - /* if (GetProperty() returns vt==VT_EMPTY), this function sets - timestamp from archive file timestamp (MTime). - So (at) will be set in most cases (at.Def == true) - if (at.Prec == 0) - { - it means that (Prec == 0) was returned for (kpidMTime), - and no value was returned for (kpidTimeType). - it can mean Windows precision or unknown precision. - } - */ - HRESULT GetItem_MTime(UInt32 index, CArcTime &at) const; - - HRESULT IsItem_Anti(UInt32 index, bool &result) const - { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } - - - HRESULT OpenStream(const COpenOptions &options); - HRESULT OpenStreamOrFile(COpenOptions &options); - - HRESULT ReOpen(const COpenOptions &options, IArchiveOpenCallback *openCallback_Additional); - - HRESULT CreateNewTailStream(CMyComPtr &stream); - - bool IsHashHandler(const COpenOptions &options) const - { - if (FormatIndex < 0) - return false; - return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler(); - } -}; - -struct CArchiveLink -{ - CObjectVector Arcs; - UStringVector VolumePaths; - UInt64 VolumesSize; - bool IsOpen; - - bool PasswordWasAsked; - // UString Password; - - // int NonOpenErrorFormatIndex; // - 1 means no Error. - UString NonOpen_ArcPath; - - CArcErrorInfo NonOpen_ErrorInfo; - - // UString ErrorsText; - // void Set_ErrorsText(); - - CArchiveLink(): - VolumesSize(0), - IsOpen(false), - PasswordWasAsked(false) - {} - - void KeepModeForNextOpen(); - HRESULT Close(); - void Release(); - ~CArchiveLink() { Release(); } - - const CArc *GetArc() const { return &Arcs.Back(); } - IInArchive *GetArchive() const { return Arcs.Back().Archive; } - IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; } - IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; } - - /* - Open() opens archive and COpenOptions::callback - Open2() uses COpenCallbackImp that implements Volumes and password callback - Open3() calls Open2() and callbackUI->Open_Finished(); - Open_Strict() returns S_FALSE also in case, if there is non-open expected nested archive. - */ - - HRESULT Open(COpenOptions &options); - HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI); - HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI); - - HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI) - { - HRESULT result = Open3(options, callbackUI); - if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0) - result = S_FALSE; - return result; - } - - HRESULT ReOpen(COpenOptions &options); -}; - -bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types); - -// bool IsHashType(const CObjectVector &types); - - -struct CDirPathSortPair -{ - unsigned Len; - unsigned Index; - - void SetNumSlashes(const FChar *s); - - int Compare(const CDirPathSortPair &a) const - { - // We need sorting order where parent items will be after child items - if (Len < a.Len) return 1; - if (Len > a.Len) return -1; - if (Index < a.Index) return -1; - if (Index > a.Index) return 1; - return 0; - } -}; - -#endif +// OpenArchive.h + +#ifndef ZIP7_INC_OPEN_ARCHIVE_H +#define ZIP7_INC_OPEN_ARCHIVE_H + +#include "../../../Windows/PropVariant.h" + +#include "ArchiveOpenCallback.h" +#include "LoadCodecs.h" +#include "Property.h" +#include "DirItem.h" + +#ifndef Z7_SFX + +#define SUPPORT_ALT_STREAMS + +#endif + +HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw(); +HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw(); +HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw(); +HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw(); +HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw(); + +#ifdef SUPPORT_ALT_STREAMS +int FindAltStreamColon_in_Path(const wchar_t *path); +#endif + +/* +struct COptionalOpenProperties +{ + UString FormatName; + CObjectVector Props; +}; +*/ + +#ifdef Z7_SFX +#define OPEN_PROPS_DECL +#else +#define OPEN_PROPS_DECL const CObjectVector *props; +// #define OPEN_PROPS_DECL , const CObjectVector *props +#endif + +struct COpenSpecFlags +{ + // bool CanReturnFull; + bool CanReturnFrontal; + bool CanReturnTail; + bool CanReturnMid; + + bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; } + + COpenSpecFlags(): + // CanReturnFull(true), + CanReturnFrontal(false), + CanReturnTail(false), + CanReturnMid(false) + {} +}; + +struct COpenType +{ + int FormatIndex; + + COpenSpecFlags SpecForcedType; + COpenSpecFlags SpecMainType; + COpenSpecFlags SpecWrongExt; + COpenSpecFlags SpecUnknownExt; + + bool Recursive; + + bool CanReturnArc; + bool CanReturnParser; + bool IsHashType; + bool EachPos; + + // bool SkipSfxStub; + // bool ExeAsUnknown; + + bool ZerosTailIsAllowed; + + bool MaxStartOffset_Defined; + UInt64 MaxStartOffset; + + const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const + { + return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt)); + } + + COpenType(): + FormatIndex(-1), + Recursive(true), + CanReturnArc(true), + CanReturnParser(false), + IsHashType(false), + EachPos(false), + // SkipSfxStub(true), + // ExeAsUnknown(true), + ZerosTailIsAllowed(false), + MaxStartOffset_Defined(false), + MaxStartOffset(0) + { + SpecForcedType.CanReturnFrontal = true; + SpecForcedType.CanReturnTail = true; + SpecForcedType.CanReturnMid = true; + + SpecMainType.CanReturnFrontal = true; + + SpecUnknownExt.CanReturnTail = true; // for sfx + SpecUnknownExt.CanReturnMid = true; + SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad + + // ZerosTailIsAllowed = true; + } +}; + +struct COpenOptions +{ + CCodecs *codecs; + COpenType openType; + const CObjectVector *types; + const CIntVector *excludedFormats; + + IInStream *stream; + ISequentialInStream *seqStream; + IArchiveOpenCallback *callback; + COpenCallbackImp *callbackSpec; // it's used for SFX only + OPEN_PROPS_DECL + // bool openOnlySpecifiedByExtension, + + bool stdInMode; + UString filePath; + + COpenOptions(): + codecs(NULL), + types(NULL), + excludedFormats(NULL), + stream(NULL), + seqStream(NULL), + callback(NULL), + callbackSpec(NULL), + stdInMode(false) + {} + +}; + +UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL); + +struct CArcErrorInfo +{ + bool ThereIsTail; + bool UnexpecedEnd; + bool IgnoreTail; // all are zeros + // bool NonZerosTail; + bool ErrorFlags_Defined; + UInt32 ErrorFlags; + UInt32 WarningFlags; + int ErrorFormatIndex; // - 1 means no Error. + // if FormatIndex == ErrorFormatIndex, the archive is open with offset + UInt64 TailSize; + + /* if CArc is Open OK with some format: + - ErrorFormatIndex shows error format index, if extension is incorrect + - other variables show message and warnings of archive that is open */ + + UString ErrorMessage; + UString WarningMessage; + + // call IsArc_After_NonOpen only if Open returns S_FALSE + bool IsArc_After_NonOpen() const + { + return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0); + } + + + CArcErrorInfo(): + ThereIsTail(false), + UnexpecedEnd(false), + IgnoreTail(false), + // NonZerosTail(false), + ErrorFlags_Defined(false), + ErrorFlags(0), + WarningFlags(0), + ErrorFormatIndex(-1), + TailSize(0) + {} + + void ClearErrors(); + + void ClearErrors_Full() + { + ErrorFormatIndex = -1; + ClearErrors(); + } + + bool IsThereErrorOrWarning() const + { + return ErrorFlags != 0 + || WarningFlags != 0 + || NeedTailWarning() + || UnexpecedEnd + || !ErrorMessage.IsEmpty() + || !WarningMessage.IsEmpty(); + } + + bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; } + bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); } + + bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; } + + UInt32 GetWarningFlags() const + { + UInt32 a = WarningFlags; + if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0) + a |= kpv_ErrorFlags_DataAfterEnd; + return a; + } + + UInt32 GetErrorFlags() const + { + UInt32 a = ErrorFlags; + if (UnexpecedEnd) + a |= kpv_ErrorFlags_UnexpectedEnd; + return a; + } +}; + +struct CReadArcItem +{ + UString Path; // Path from root (including alt stream name, if alt stream) + UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode + + #ifdef SUPPORT_ALT_STREAMS + UString MainPath; + /* MainPath = Path for non-AltStream, + MainPath = Path of parent, if there is parent for AltStream. */ + UString AltStreamName; + bool IsAltStream; + bool WriteToAltStreamIfColon; + #endif + + bool IsDir; + bool MainIsDir; + UInt32 ParentIndex; // use it, if IsAltStream + + #ifndef Z7_SFX + bool _use_baseParentFolder_mode; + int _baseParentFolder; + #endif + + CReadArcItem() + { + #ifdef SUPPORT_ALT_STREAMS + WriteToAltStreamIfColon = false; + #endif + + #ifndef Z7_SFX + _use_baseParentFolder_mode = false; + _baseParentFolder = -1; + #endif + } +}; + + + + +class CArc +{ + HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive); + HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset); + HRESULT OpenStream2(const COpenOptions &options); + + #ifndef Z7_SFX + // parts.Back() can contain alt stream name "nams:AltName" + HRESULT GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; + #endif + +public: + CMyComPtr Archive; + CMyComPtr InStream; + // we use InStream in 2 cases (ArcStreamOffset != 0): + // 1) if we use additional cache stream + // 2) we reopen sfx archive with CTailInStream + + CMyComPtr GetRawProps; + CMyComPtr GetRootProps; + + bool IsParseArc; + + bool IsTree; + bool IsReadOnly; + + bool Ask_Deleted; + bool Ask_AltStream; + bool Ask_Aux; + bool Ask_INode; + + bool IgnoreSplit; // don't try split handler + + UString Path; + UString filePath; + UString DefaultName; + int FormatIndex; // -1 means Parser + UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile + + // CFiTime MTime; + // bool MTime_Defined; + CArcTime MTime; + + Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler + UInt64 PhySize; + // UInt64 OkPhySize; + bool PhySize_Defined; + // bool OkPhySize_Defined; + UInt64 FileSize; + UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file + + CArcErrorInfo ErrorInfo; // for OK archives + CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN) + + UInt64 GetEstmatedPhySize() const { return PhySize_Defined ? PhySize : FileSize; } + + UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler + Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive + + // AString ErrorFlagsText; + + // void Set_ErrorFlagsText(); + + CArc(): + // MTime_Defined(false), + IsTree(false), + IsReadOnly(false), + Ask_Deleted(false), + Ask_AltStream(false), + Ask_Aux(false), + Ask_INode(false), + IgnoreSplit(false) + {} + + HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes); + + HRESULT Close() + { + InStream.Release(); + return Archive->Close(); + } + + HRESULT GetItem_Path(UInt32 index, UString &result) const; + HRESULT GetItem_DefaultPath(UInt32 index, UString &result) const; + + // GetItemPath2 adds [DELETED] dir prefix for deleted items. + HRESULT GetItem_Path2(UInt32 index, UString &result) const; + + HRESULT GetItem(UInt32 index, CReadArcItem &item) const; + + HRESULT GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const; + + /* if (GetProperty() returns vt==VT_EMPTY), this function sets + timestamp from archive file timestamp (MTime). + So (at) will be set in most cases (at.Def == true) + if (at.Prec == 0) + { + it means that (Prec == 0) was returned for (kpidMTime), + and no value was returned for (kpidTimeType). + it can mean Windows precision or unknown precision. + } + */ + HRESULT GetItem_MTime(UInt32 index, CArcTime &at) const; + + HRESULT IsItem_Anti(UInt32 index, bool &result) const + { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } + + + HRESULT OpenStream(const COpenOptions &options); + HRESULT OpenStreamOrFile(COpenOptions &options); + + HRESULT ReOpen(const COpenOptions &options, IArchiveOpenCallback *openCallback_Additional); + + HRESULT CreateNewTailStream(CMyComPtr &stream); + + bool IsHashHandler(const COpenOptions &options) const + { + if (FormatIndex < 0) + return false; + return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler(); + } +}; + +struct CArchiveLink +{ + CObjectVector Arcs; + UStringVector VolumePaths; + UInt64 VolumesSize; + bool IsOpen; + + bool PasswordWasAsked; + // UString Password; + + // int NonOpenErrorFormatIndex; // - 1 means no Error. + UString NonOpen_ArcPath; + + CArcErrorInfo NonOpen_ErrorInfo; + + // UString ErrorsText; + // void Set_ErrorsText(); + + CArchiveLink(): + VolumesSize(0), + IsOpen(false), + PasswordWasAsked(false) + {} + + void KeepModeForNextOpen(); + HRESULT Close(); + void Release(); + ~CArchiveLink() { Release(); } + + const CArc *GetArc() const { return &Arcs.Back(); } + IInArchive *GetArchive() const { return Arcs.Back().Archive; } + IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; } + IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; } + + /* + Open() opens archive and COpenOptions::callback + Open2() uses COpenCallbackImp that implements Volumes and password callback + Open3() calls Open2() and callbackUI->Open_Finished(); + Open_Strict() returns S_FALSE also in case, if there is non-open expected nested archive. + */ + + HRESULT Open(COpenOptions &options); + HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI); + HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI); + + HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI) + { + HRESULT result = Open3(options, callbackUI); + if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + result = S_FALSE; + return result; + } + + HRESULT ReOpen(COpenOptions &options); +}; + +bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types); + +// bool IsHashType(const CObjectVector &types); + + +struct CDirPathSortPair +{ + unsigned Len; + unsigned Index; + + void SetNumSlashes(const FChar *s); + + int Compare(const CDirPathSortPair &a) const + { + // We need sorting order where parent items will be after child items + if (Len < a.Len) return 1; + if (Len > a.Len) return -1; + if (Index < a.Index) return -1; + if (Index > a.Index) return 1; + return 0; + } +}; + +#endif diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp index 304af4da2..d73680b1b 100644 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -1,745 +1,745 @@ -// PropIDUtils.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileIO.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../PropID.h" - -#include "PropIDUtils.h" - -#ifndef Z7_SFX -#define Get16(x) GetUi16(x) -#define Get32(x) GetUi32(x) -#endif - -using namespace NWindows; - -static const unsigned kNumWinAtrribFlags = 30; -static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEVvX.PU.M......B"; - -/* -FILE_ATTRIBUTE_ - -0 READONLY -1 HIDDEN -2 SYSTEM -3 (Volume label - obsolete) -4 DIRECTORY -5 ARCHIVE -6 DEVICE -7 NORMAL -8 TEMPORARY -9 SPARSE_FILE -10 REPARSE_POINT -11 COMPRESSED -12 OFFLINE -13 NOT_CONTENT_INDEXED (I - Win10 attrib/Explorer) -14 ENCRYPTED -15 INTEGRITY_STREAM (V - ReFS Win8/Win2012) -16 VIRTUAL (reserved) -17 NO_SCRUB_DATA (X - ReFS Win8/Win2012 attrib) -18 RECALL_ON_OPEN or EA -19 PINNED -20 UNPINNED -21 STRICTLY_SEQUENTIAL (10.0.16267) -22 RECALL_ON_DATA_ACCESS -29 STRICTLY_SEQUENTIAL (10.0.17134+) (SMR Blob) -*/ - - -static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; -#define MY_ATTR_CHAR(a, n, c) (((a) & (1 << (n))) ? c : '-') - -static void ConvertPosixAttribToString(char *s, UInt32 a) throw() -{ - s[0] = kPosixTypes[(a >> 12) & 0xF]; - for (int i = 6; i >= 0; i -= 3) - { - s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); - s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); - s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); - } - if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID - if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID - if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX - s[10] = 0; - - a &= ~(UInt32)0xFFFF; - if (a != 0) - { - s[10] = ' '; - ConvertUInt32ToHex8Digits(a, s + 11); - } -} - - -void ConvertWinAttribToString(char *s, UInt32 wa) throw() -{ - /* - some programs store posix attributes in high 16 bits. - p7zip - stores additional 0x8000 flag marker. - macos - stores additional 0x4000 flag marker. - info-zip - no additional marker. - But this code works with Attrib from internal 7zip code. - So we expect that 0x8000 marker is set, if there are posix attributes. - (DT_UNKNOWN == 0) type in high bits is possible in some case for linux files. - 0x8000 flag is possible also in ReFS (Windows)? - */ - - const bool isPosix = ( - (wa & 0x8000) != 0 // FILE_ATTRIBUTE_UNIX_EXTENSION; - // && (wa & 0xFFFF0000u) != 0 - ); - - UInt32 posix = 0; - if (isPosix) - { - posix = wa >> 16; - if ((wa & 0xF0000000u) != 0) - wa &= (UInt32)0x3FFF; - } - - for (unsigned i = 0; i < kNumWinAtrribFlags; i++) - { - const UInt32 flag = (UInt32)1 << i; - if (wa & flag) - { - const char c = g_WinAttribChars[i]; - if (c != '.') - { - wa &= ~flag; - // if (i != 7) // we can disable N (NORMAL) printing - *s++ = c; - } - } - } - - if (wa != 0) - { - *s++ = ' '; - ConvertUInt32ToHex8Digits(wa, s); - s += strlen(s); - } - - *s = 0; - - if (isPosix) - { - *s++ = ' '; - ConvertPosixAttribToString(s, posix); - } -} - - -void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID propID, int level) throw() -{ - *dest = 0; - - if (prop.vt == VT_FILETIME) - { - const FILETIME &ft = prop.filetime; - unsigned ns100 = 0; - int numDigits = kTimestampPrintLevel_NTFS; - const unsigned prec = prop.wReserved1; - const unsigned ns100_Temp = prop.wReserved2; - if (prec != 0 - && prec <= k_PropVar_TimePrec_1ns - && ns100_Temp < 100 - && prop.wReserved3 == 0) - { - ns100 = ns100_Temp; - if (prec == k_PropVar_TimePrec_Unix || - prec == k_PropVar_TimePrec_DOS) - numDigits = 0; - else if (prec == k_PropVar_TimePrec_HighPrec) - numDigits = 9; - else - { - numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; - if ( - // numDigits < kTimestampPrintLevel_DAY // for debuf - numDigits < kTimestampPrintLevel_SEC - ) - - numDigits = kTimestampPrintLevel_NTFS; - } - } - if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0 && ns100 == 0) - return; - if (level > numDigits) - level = numDigits; - ConvertUtcFileTimeToString2(ft, ns100, dest, level); - return; - } - - switch (propID) - { - case kpidCRC: - { - if (prop.vt != VT_UI4) - break; - ConvertUInt32ToHex8Digits(prop.ulVal, dest); - return; - } - case kpidAttrib: - { - if (prop.vt != VT_UI4) - break; - const UInt32 a = prop.ulVal; - - /* - if ((a & 0x8000) && (a & 0x7FFF) == 0) - ConvertPosixAttribToString(dest, a >> 16); - else - */ - ConvertWinAttribToString(dest, a); - return; - } - case kpidPosixAttrib: - { - if (prop.vt != VT_UI4) - break; - ConvertPosixAttribToString(dest, prop.ulVal); - return; - } - case kpidINode: - { - if (prop.vt != VT_UI8) - break; - ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest); - dest += strlen(dest); - *dest++ = '-'; - const UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1); - ConvertUInt64ToString(low, dest); - return; - } - case kpidVa: - { - UInt64 v = 0; - if (prop.vt == VT_UI4) - v = prop.ulVal; - else if (prop.vt == VT_UI8) - v = (UInt64)prop.uhVal.QuadPart; - else - break; - dest[0] = '0'; - dest[1] = 'x'; - ConvertUInt64ToHex(v, dest + 2); - return; - } - - /* - case kpidDevice: - { - UInt64 v = 0; - if (prop.vt == VT_UI4) - v = prop.ulVal; - else if (prop.vt == VT_UI8) - v = (UInt64)prop.uhVal.QuadPart; - else - break; - ConvertUInt32ToString(MY_dev_major(v), dest); - dest += strlen(dest); - *dest++ = ','; - ConvertUInt32ToString(MY_dev_minor(v), dest); - return; - } - */ - default: break; - } - - ConvertPropVariantToShortString(prop, dest); -} - -void ConvertPropertyToString2(UString &dest, const PROPVARIANT &prop, PROPID propID, int level) -{ - if (prop.vt == VT_BSTR) - { - dest.SetFromBstr(prop.bstrVal); - return; - } - char temp[64]; - ConvertPropertyToShortString2(temp, prop, propID, level); - dest = temp; -} - -#ifndef Z7_SFX - -static inline void AddHexToString(AString &res, unsigned v) -{ - res.Add_Char((char)GET_HEX_CHAR_UPPER(v >> 4)); - res.Add_Char((char)GET_HEX_CHAR_UPPER(v & 15)); -} - -/* -static AString Data_To_Hex(const Byte *data, size_t size) -{ - AString s; - for (size_t i = 0; i < size; i++) - AddHexToString(s, data[i]); - return s; -} -*/ - -static const char * const sidNames[] = -{ - "0" - , "Dialup" - , "Network" - , "Batch" - , "Interactive" - , "Logon" // S-1-5-5-X-Y - , "Service" - , "Anonymous" - , "Proxy" - , "EnterpriseDC" - , "Self" - , "AuthenticatedUsers" - , "RestrictedCode" - , "TerminalServer" - , "RemoteInteractiveLogon" - , "ThisOrganization" - , "16" - , "IUserIIS" - , "LocalSystem" - , "LocalService" - , "NetworkService" - , "Domains" -}; - -struct CSecID2Name -{ - UInt32 n; - const char *sz; -}; - -static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id) -{ - for (unsigned i = 0; i < num; i++) - if (pairs[i].n == id) - return (int)i; - return -1; -} - -static const CSecID2Name sid_32_Names[] = -{ - { 544, "Administrators" }, - { 545, "Users" }, - { 546, "Guests" }, - { 547, "PowerUsers" }, - { 548, "AccountOperators" }, - { 549, "ServerOperators" }, - { 550, "PrintOperators" }, - { 551, "BackupOperators" }, - { 552, "Replicators" }, - { 553, "Backup Operators" }, - { 554, "PreWindows2000CompatibleAccess" }, - { 555, "RemoteDesktopUsers" }, - { 556, "NetworkConfigurationOperators" }, - { 557, "IncomingForestTrustBuilders" }, - { 558, "PerformanceMonitorUsers" }, - { 559, "PerformanceLogUsers" }, - { 560, "WindowsAuthorizationAccessGroup" }, - { 561, "TerminalServerLicenseServers" }, - { 562, "DistributedCOMUsers" }, - { 569, "CryptographicOperators" }, - { 573, "EventLogReaders" }, - { 574, "CertificateServiceDCOMAccess" } -}; - -static const CSecID2Name sid_21_Names[] = -{ - { 500, "Administrator" }, - { 501, "Guest" }, - { 502, "KRBTGT" }, - { 512, "DomainAdmins" }, - { 513, "DomainUsers" }, - { 515, "DomainComputers" }, - { 516, "DomainControllers" }, - { 517, "CertPublishers" }, - { 518, "SchemaAdmins" }, - { 519, "EnterpriseAdmins" }, - { 520, "GroupPolicyCreatorOwners" }, - { 553, "RASandIASServers" }, - { 553, "RASandIASServers" }, - { 571, "AllowedRODCPasswordReplicationGroup" }, - { 572, "DeniedRODCPasswordReplicationGroup" } -}; - -struct CServicesToName -{ - UInt32 n[5]; - const char *sz; -}; - -static const CServicesToName services_to_name[] = -{ - { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } -}; - -static void ParseSid(AString &s, const Byte *p, size_t lim /* , unsigned &sidSize */) -{ - // sidSize = 0; - if (lim < 8) - { - s += "ERROR"; - return; - } - if (p[0] != 1) // rev - { - s += "UNSUPPORTED"; - return; - } - const unsigned num = p[1]; - const unsigned sidSize_Loc = 8 + num * 4; - if (sidSize_Loc > lim) - { - s += "ERROR"; - return; - } - // sidSize = sidSize_Loc; - const UInt32 authority = GetBe32(p + 4); - - if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1) - { - const UInt32 v0 = Get32(p + 8); - if (v0 < Z7_ARRAY_SIZE(sidNames)) - { - s += sidNames[v0]; - return; - } - if (v0 == 32 && num == 2) - { - const UInt32 v1 = Get32(p + 12); - const int index = FindPairIndex(sid_32_Names, Z7_ARRAY_SIZE(sid_32_Names), v1); - if (index >= 0) - { - s += sid_32_Names[(unsigned)index].sz; - return; - } - } - if (v0 == 21 && num == 5) - { - UInt32 v4 = Get32(p + 8 + 4 * 4); - const int index = FindPairIndex(sid_21_Names, Z7_ARRAY_SIZE(sid_21_Names), v4); - if (index >= 0) - { - s += sid_21_Names[(unsigned)index].sz; - return; - } - } - if (v0 == 80 && num == 6) - { - for (unsigned i = 0; i < Z7_ARRAY_SIZE(services_to_name); i++) - { - const CServicesToName &sn = services_to_name[i]; - int j; - for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++); - if (j == 5) - { - s += sn.sz; - return; - } - } - } - } - - s += "S-1-"; - if (p[2] == 0 && p[3] == 0) - s.Add_UInt32(authority); - else - { - s += "0x"; - for (int i = 2; i < 8; i++) - AddHexToString(s, p[i]); - } - for (UInt32 i = 0; i < num; i++) - { - s.Add_Minus(); - s.Add_UInt32(Get32(p + 8 + i * 4)); - } -} - -static void ParseOwner(AString &s, const Byte *p, size_t size, UInt32 pos) -{ - if (pos > size) - { - s += "ERROR"; - return; - } - // unsigned sidSize = 0; - ParseSid(s, p + pos, size - pos /* , sidSize */); -} - -static void ParseAcl(AString &s, const Byte *p, size_t size, const char *strName, UInt32 flags, UInt32 offset) -{ - const unsigned control = Get16(p + 2); - if ((flags & control) == 0) - return; - const UInt32 pos = Get32(p + offset); - s.Add_Space(); - s += strName; - if (pos >= size) - return; - p += pos; - size -= (size_t)pos; - if (size < 8) - return; - if (Get16(p) != 2) // revision - return; - const UInt32 num = Get32(p + 4); - s.Add_UInt32(num); - - /* - UInt32 aclSize = Get16(p + 2); - if (num >= (1 << 16)) - return; - if (aclSize > size) - return; - size = aclSize; - size -= 8; - p += 8; - for (UInt32 i = 0 ; i < num; i++) - { - if (size <= 8) - return; - // Byte type = p[0]; - // Byte flags = p[1]; - // UInt32 aceSize = Get16(p + 2); - // UInt32 mask = Get32(p + 4); - p += 8; - size -= 8; - - UInt32 sidSize = 0; - s.Add_Space(); - ParseSid(s, p, size, sidSize); - if (sidSize == 0) - return; - p += sidSize; - size -= sidSize; - } - - // the tail can contain zeros. So (size != 0) is not ERROR - // if (size != 0) s += " ERROR"; - */ -} - -/* -#define MY_SE_OWNER_DEFAULTED (0x0001) -#define MY_SE_GROUP_DEFAULTED (0x0002) -*/ -#define MY_SE_DACL_PRESENT (0x0004) -/* -#define MY_SE_DACL_DEFAULTED (0x0008) -*/ -#define MY_SE_SACL_PRESENT (0x0010) -/* -#define MY_SE_SACL_DEFAULTED (0x0020) -#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100) -#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200) -#define MY_SE_DACL_AUTO_INHERITED (0x0400) -#define MY_SE_SACL_AUTO_INHERITED (0x0800) -#define MY_SE_DACL_PROTECTED (0x1000) -#define MY_SE_SACL_PROTECTED (0x2000) -#define MY_SE_RM_CONTROL_VALID (0x4000) -#define MY_SE_SELF_RELATIVE (0x8000) -*/ - -void ConvertNtSecureToString(const Byte *data, size_t size, AString &s) -{ - s.Empty(); - if (size < 20 || size > (1 << 18)) - { - s += "ERROR"; - return; - } - if (Get16(data) != 1) // revision - { - s += "UNSUPPORTED"; - return; - } - ParseOwner(s, data, size, Get32(data + 4)); - s.Add_Space(); - ParseOwner(s, data, size, Get32(data + 8)); - ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); - ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); - s.Add_Space(); - s.Add_UInt32((UInt32)size); - // s.Add_LF(); - // s += Data_To_Hex(data, size); -} - -#ifdef _WIN32 - -static bool CheckSid(const Byte *data, size_t size, UInt32 pos) throw() -{ - if (pos >= size) - return false; - size -= pos; - if (size < 8) - return false; - if (data[pos] != 1) // rev - return false; - const unsigned num = data[pos + 1]; - return (8 + num * 4 <= size); -} - -static bool CheckAcl(const Byte *p, size_t size, UInt32 flags, size_t offset) throw() -{ - const unsigned control = Get16(p + 2); - if ((flags & control) == 0) - return true; - const UInt32 pos = Get32(p + offset); - if (pos >= size) - return false; - p += pos; - size -= pos; - if (size < 8) - return false; - const unsigned aclSize = Get16(p + 2); - return (aclSize <= size); -} - -bool CheckNtSecure(const Byte *data, size_t size) throw() -{ - if (size < 20) - return false; - if (Get16(data) != 1) // revision - return true; // windows function can handle such error, so we allow it - if (size > (1 << 18)) - return false; - if (!CheckSid(data, size, Get32(data + 4))) return false; - if (!CheckSid(data, size, Get32(data + 8))) return false; - if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false; - if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false; - return true; -} - -#endif - - - -// IO_REPARSE_TAG_* - -static const CSecID2Name k_ReparseTags[] = -{ - { 0xA0000003, "MOUNT_POINT" }, - { 0xC0000004, "HSM" }, - { 0x80000005, "DRIVE_EXTENDER" }, - { 0x80000006, "HSM2" }, - { 0x80000007, "SIS" }, - { 0x80000008, "WIM" }, - { 0x80000009, "CSV" }, - { 0x8000000A, "DFS" }, - { 0x8000000B, "FILTER_MANAGER" }, - { 0xA000000C, "SYMLINK" }, - { 0xA0000010, "IIS_CACHE" }, - { 0x80000012, "DFSR" }, - { 0x80000013, "DEDUP" }, - { 0xC0000014, "APPXSTRM" }, - { 0x80000014, "NFS" }, - { 0x80000015, "FILE_PLACEHOLDER" }, - { 0x80000016, "DFM" }, - { 0x80000017, "WOF" }, - { 0x80000018, "WCI" }, - { 0x8000001B, "APPEXECLINK" }, - { 0xA000001D, "LX_SYMLINK" }, - { 0x80000023, "AF_UNIX" }, - { 0x80000024, "LX_FIFO" }, - { 0x80000025, "LX_CHR" }, - { 0x80000026, "LX_BLK" } -}; - -bool ConvertNtReparseToString(const Byte *data, size_t size, UString &s) -{ - s.Empty(); - NFile::CReparseAttr attr; - - if (attr.Parse(data, size)) - { - if (attr.IsSymLink_WSL()) - { - s += "WSL: "; - s += attr.GetPath(); - } - else - { - if (!attr.IsSymLink_Win()) - s += "Junction: "; - s += attr.GetPath(); - if (s.IsEmpty()) - s += "Link: "; - if (!attr.IsOkNamePair()) - { - s += " : "; - s += attr.PrintName; - } - } - if (attr.MinorError) - s += " : MINOR_ERROR"; - return true; - // s.Add_Space(); // for debug - } - - if (size < 8) - return false; - const UInt32 tag = Get32(data); - const UInt32 len = Get16(data + 4); - if (len + 8 > size) - return false; - if (Get16(data + 6) != 0) // padding - return false; - - /* - #define my_IO_REPARSE_TAG_DEDUP (0x80000013L) - if (tag == my_IO_REPARSE_TAG_DEDUP) - { - } - */ - - { - const int index = FindPairIndex(k_ReparseTags, Z7_ARRAY_SIZE(k_ReparseTags), tag); - if (index >= 0) - s += k_ReparseTags[(unsigned)index].sz; - else - { - s += "REPARSE:"; - char hex[16]; - ConvertUInt32ToHex8Digits(tag, hex); - s += hex; - } - } - - s.Add_Colon(); - s.Add_UInt32(len); - - if (len != 0) - { - s.Add_Space(); - - data += 8; - - for (UInt32 i = 0; i < len; i++) - { - if (i >= 16) - { - s += "..."; - break; - } - const unsigned b = data[i]; - s.Add_Char((char)GET_HEX_CHAR_UPPER(b >> 4)); - s.Add_Char((char)GET_HEX_CHAR_UPPER(b & 15)); - } - } - - return true; -} - -#endif +// PropIDUtils.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileIO.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../PropID.h" + +#include "PropIDUtils.h" + +#ifndef Z7_SFX +#define Get16(x) GetUi16(x) +#define Get32(x) GetUi32(x) +#endif + +using namespace NWindows; + +static const unsigned kNumWinAtrribFlags = 30; +static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEVvX.PU.M......B"; + +/* +FILE_ATTRIBUTE_ + +0 READONLY +1 HIDDEN +2 SYSTEM +3 (Volume label - obsolete) +4 DIRECTORY +5 ARCHIVE +6 DEVICE +7 NORMAL +8 TEMPORARY +9 SPARSE_FILE +10 REPARSE_POINT +11 COMPRESSED +12 OFFLINE +13 NOT_CONTENT_INDEXED (I - Win10 attrib/Explorer) +14 ENCRYPTED +15 INTEGRITY_STREAM (V - ReFS Win8/Win2012) +16 VIRTUAL (reserved) +17 NO_SCRUB_DATA (X - ReFS Win8/Win2012 attrib) +18 RECALL_ON_OPEN or EA +19 PINNED +20 UNPINNED +21 STRICTLY_SEQUENTIAL (10.0.16267) +22 RECALL_ON_DATA_ACCESS +29 STRICTLY_SEQUENTIAL (10.0.17134+) (SMR Blob) +*/ + + +static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; +#define MY_ATTR_CHAR(a, n, c) (((a) & (1 << (n))) ? c : '-') + +static void ConvertPosixAttribToString(char *s, UInt32 a) throw() +{ + s[0] = kPosixTypes[(a >> 12) & 0xF]; + for (int i = 6; i >= 0; i -= 3) + { + s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); + s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); + s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); + } + if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID + if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID + if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX + s[10] = 0; + + a &= ~(UInt32)0xFFFF; + if (a != 0) + { + s[10] = ' '; + ConvertUInt32ToHex8Digits(a, s + 11); + } +} + + +void ConvertWinAttribToString(char *s, UInt32 wa) throw() +{ + /* + some programs store posix attributes in high 16 bits. + p7zip - stores additional 0x8000 flag marker. + macos - stores additional 0x4000 flag marker. + info-zip - no additional marker. + But this code works with Attrib from internal 7zip code. + So we expect that 0x8000 marker is set, if there are posix attributes. + (DT_UNKNOWN == 0) type in high bits is possible in some case for linux files. + 0x8000 flag is possible also in ReFS (Windows)? + */ + + const bool isPosix = ( + (wa & 0x8000) != 0 // FILE_ATTRIBUTE_UNIX_EXTENSION; + // && (wa & 0xFFFF0000u) != 0 + ); + + UInt32 posix = 0; + if (isPosix) + { + posix = wa >> 16; + if ((wa & 0xF0000000u) != 0) + wa &= (UInt32)0x3FFF; + } + + for (unsigned i = 0; i < kNumWinAtrribFlags; i++) + { + const UInt32 flag = (UInt32)1 << i; + if (wa & flag) + { + const char c = g_WinAttribChars[i]; + if (c != '.') + { + wa &= ~flag; + // if (i != 7) // we can disable N (NORMAL) printing + *s++ = c; + } + } + } + + if (wa != 0) + { + *s++ = ' '; + ConvertUInt32ToHex8Digits(wa, s); + s += strlen(s); + } + + *s = 0; + + if (isPosix) + { + *s++ = ' '; + ConvertPosixAttribToString(s, posix); + } +} + + +void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID propID, int level) throw() +{ + *dest = 0; + + if (prop.vt == VT_FILETIME) + { + const FILETIME &ft = prop.filetime; + unsigned ns100 = 0; + int numDigits = kTimestampPrintLevel_NTFS; + const unsigned prec = prop.wReserved1; + const unsigned ns100_Temp = prop.wReserved2; + if (prec != 0 + && prec <= k_PropVar_TimePrec_1ns + && ns100_Temp < 100 + && prop.wReserved3 == 0) + { + ns100 = ns100_Temp; + if (prec == k_PropVar_TimePrec_Unix || + prec == k_PropVar_TimePrec_DOS) + numDigits = 0; + else if (prec == k_PropVar_TimePrec_HighPrec) + numDigits = 9; + else + { + numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; + if ( + // numDigits < kTimestampPrintLevel_DAY // for debuf + numDigits < kTimestampPrintLevel_SEC + ) + + numDigits = kTimestampPrintLevel_NTFS; + } + } + if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0 && ns100 == 0) + return; + if (level > numDigits) + level = numDigits; + ConvertUtcFileTimeToString2(ft, ns100, dest, level); + return; + } + + switch (propID) + { + case kpidCRC: + { + if (prop.vt != VT_UI4) + break; + ConvertUInt32ToHex8Digits(prop.ulVal, dest); + return; + } + case kpidAttrib: + { + if (prop.vt != VT_UI4) + break; + const UInt32 a = prop.ulVal; + + /* + if ((a & 0x8000) && (a & 0x7FFF) == 0) + ConvertPosixAttribToString(dest, a >> 16); + else + */ + ConvertWinAttribToString(dest, a); + return; + } + case kpidPosixAttrib: + { + if (prop.vt != VT_UI4) + break; + ConvertPosixAttribToString(dest, prop.ulVal); + return; + } + case kpidINode: + { + if (prop.vt != VT_UI8) + break; + ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest); + dest += strlen(dest); + *dest++ = '-'; + const UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1); + ConvertUInt64ToString(low, dest); + return; + } + case kpidVa: + { + UInt64 v = 0; + if (prop.vt == VT_UI4) + v = prop.ulVal; + else if (prop.vt == VT_UI8) + v = (UInt64)prop.uhVal.QuadPart; + else + break; + dest[0] = '0'; + dest[1] = 'x'; + ConvertUInt64ToHex(v, dest + 2); + return; + } + + /* + case kpidDevice: + { + UInt64 v = 0; + if (prop.vt == VT_UI4) + v = prop.ulVal; + else if (prop.vt == VT_UI8) + v = (UInt64)prop.uhVal.QuadPart; + else + break; + ConvertUInt32ToString(MY_dev_major(v), dest); + dest += strlen(dest); + *dest++ = ','; + ConvertUInt32ToString(MY_dev_minor(v), dest); + return; + } + */ + default: break; + } + + ConvertPropVariantToShortString(prop, dest); +} + +void ConvertPropertyToString2(UString &dest, const PROPVARIANT &prop, PROPID propID, int level) +{ + if (prop.vt == VT_BSTR) + { + dest.SetFromBstr(prop.bstrVal); + return; + } + char temp[64]; + ConvertPropertyToShortString2(temp, prop, propID, level); + dest = temp; +} + +#ifndef Z7_SFX + +static inline void AddHexToString(AString &res, unsigned v) +{ + res.Add_Char((char)GET_HEX_CHAR_UPPER(v >> 4)); + res.Add_Char((char)GET_HEX_CHAR_UPPER(v & 15)); +} + +/* +static AString Data_To_Hex(const Byte *data, size_t size) +{ + AString s; + for (size_t i = 0; i < size; i++) + AddHexToString(s, data[i]); + return s; +} +*/ + +static const char * const sidNames[] = +{ + "0" + , "Dialup" + , "Network" + , "Batch" + , "Interactive" + , "Logon" // S-1-5-5-X-Y + , "Service" + , "Anonymous" + , "Proxy" + , "EnterpriseDC" + , "Self" + , "AuthenticatedUsers" + , "RestrictedCode" + , "TerminalServer" + , "RemoteInteractiveLogon" + , "ThisOrganization" + , "16" + , "IUserIIS" + , "LocalSystem" + , "LocalService" + , "NetworkService" + , "Domains" +}; + +struct CSecID2Name +{ + UInt32 n; + const char *sz; +}; + +static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id) +{ + for (unsigned i = 0; i < num; i++) + if (pairs[i].n == id) + return (int)i; + return -1; +} + +static const CSecID2Name sid_32_Names[] = +{ + { 544, "Administrators" }, + { 545, "Users" }, + { 546, "Guests" }, + { 547, "PowerUsers" }, + { 548, "AccountOperators" }, + { 549, "ServerOperators" }, + { 550, "PrintOperators" }, + { 551, "BackupOperators" }, + { 552, "Replicators" }, + { 553, "Backup Operators" }, + { 554, "PreWindows2000CompatibleAccess" }, + { 555, "RemoteDesktopUsers" }, + { 556, "NetworkConfigurationOperators" }, + { 557, "IncomingForestTrustBuilders" }, + { 558, "PerformanceMonitorUsers" }, + { 559, "PerformanceLogUsers" }, + { 560, "WindowsAuthorizationAccessGroup" }, + { 561, "TerminalServerLicenseServers" }, + { 562, "DistributedCOMUsers" }, + { 569, "CryptographicOperators" }, + { 573, "EventLogReaders" }, + { 574, "CertificateServiceDCOMAccess" } +}; + +static const CSecID2Name sid_21_Names[] = +{ + { 500, "Administrator" }, + { 501, "Guest" }, + { 502, "KRBTGT" }, + { 512, "DomainAdmins" }, + { 513, "DomainUsers" }, + { 515, "DomainComputers" }, + { 516, "DomainControllers" }, + { 517, "CertPublishers" }, + { 518, "SchemaAdmins" }, + { 519, "EnterpriseAdmins" }, + { 520, "GroupPolicyCreatorOwners" }, + { 553, "RASandIASServers" }, + { 553, "RASandIASServers" }, + { 571, "AllowedRODCPasswordReplicationGroup" }, + { 572, "DeniedRODCPasswordReplicationGroup" } +}; + +struct CServicesToName +{ + UInt32 n[5]; + const char *sz; +}; + +static const CServicesToName services_to_name[] = +{ + { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } +}; + +static void ParseSid(AString &s, const Byte *p, size_t lim /* , unsigned &sidSize */) +{ + // sidSize = 0; + if (lim < 8) + { + s += "ERROR"; + return; + } + if (p[0] != 1) // rev + { + s += "UNSUPPORTED"; + return; + } + const unsigned num = p[1]; + const unsigned sidSize_Loc = 8 + num * 4; + if (sidSize_Loc > lim) + { + s += "ERROR"; + return; + } + // sidSize = sidSize_Loc; + const UInt32 authority = GetBe32(p + 4); + + if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1) + { + const UInt32 v0 = Get32(p + 8); + if (v0 < Z7_ARRAY_SIZE(sidNames)) + { + s += sidNames[v0]; + return; + } + if (v0 == 32 && num == 2) + { + const UInt32 v1 = Get32(p + 12); + const int index = FindPairIndex(sid_32_Names, Z7_ARRAY_SIZE(sid_32_Names), v1); + if (index >= 0) + { + s += sid_32_Names[(unsigned)index].sz; + return; + } + } + if (v0 == 21 && num == 5) + { + UInt32 v4 = Get32(p + 8 + 4 * 4); + const int index = FindPairIndex(sid_21_Names, Z7_ARRAY_SIZE(sid_21_Names), v4); + if (index >= 0) + { + s += sid_21_Names[(unsigned)index].sz; + return; + } + } + if (v0 == 80 && num == 6) + { + for (unsigned i = 0; i < Z7_ARRAY_SIZE(services_to_name); i++) + { + const CServicesToName &sn = services_to_name[i]; + int j; + for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++); + if (j == 5) + { + s += sn.sz; + return; + } + } + } + } + + s += "S-1-"; + if (p[2] == 0 && p[3] == 0) + s.Add_UInt32(authority); + else + { + s += "0x"; + for (int i = 2; i < 8; i++) + AddHexToString(s, p[i]); + } + for (UInt32 i = 0; i < num; i++) + { + s.Add_Minus(); + s.Add_UInt32(Get32(p + 8 + i * 4)); + } +} + +static void ParseOwner(AString &s, const Byte *p, size_t size, UInt32 pos) +{ + if (pos > size) + { + s += "ERROR"; + return; + } + // unsigned sidSize = 0; + ParseSid(s, p + pos, size - pos /* , sidSize */); +} + +static void ParseAcl(AString &s, const Byte *p, size_t size, const char *strName, UInt32 flags, UInt32 offset) +{ + const unsigned control = Get16(p + 2); + if ((flags & control) == 0) + return; + const UInt32 pos = Get32(p + offset); + s.Add_Space(); + s += strName; + if (pos >= size) + return; + p += pos; + size -= (size_t)pos; + if (size < 8) + return; + if (Get16(p) != 2) // revision + return; + const UInt32 num = Get32(p + 4); + s.Add_UInt32(num); + + /* + UInt32 aclSize = Get16(p + 2); + if (num >= (1 << 16)) + return; + if (aclSize > size) + return; + size = aclSize; + size -= 8; + p += 8; + for (UInt32 i = 0 ; i < num; i++) + { + if (size <= 8) + return; + // Byte type = p[0]; + // Byte flags = p[1]; + // UInt32 aceSize = Get16(p + 2); + // UInt32 mask = Get32(p + 4); + p += 8; + size -= 8; + + UInt32 sidSize = 0; + s.Add_Space(); + ParseSid(s, p, size, sidSize); + if (sidSize == 0) + return; + p += sidSize; + size -= sidSize; + } + + // the tail can contain zeros. So (size != 0) is not ERROR + // if (size != 0) s += " ERROR"; + */ +} + +/* +#define MY_SE_OWNER_DEFAULTED (0x0001) +#define MY_SE_GROUP_DEFAULTED (0x0002) +*/ +#define MY_SE_DACL_PRESENT (0x0004) +/* +#define MY_SE_DACL_DEFAULTED (0x0008) +*/ +#define MY_SE_SACL_PRESENT (0x0010) +/* +#define MY_SE_SACL_DEFAULTED (0x0020) +#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100) +#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200) +#define MY_SE_DACL_AUTO_INHERITED (0x0400) +#define MY_SE_SACL_AUTO_INHERITED (0x0800) +#define MY_SE_DACL_PROTECTED (0x1000) +#define MY_SE_SACL_PROTECTED (0x2000) +#define MY_SE_RM_CONTROL_VALID (0x4000) +#define MY_SE_SELF_RELATIVE (0x8000) +*/ + +void ConvertNtSecureToString(const Byte *data, size_t size, AString &s) +{ + s.Empty(); + if (size < 20 || size > (1 << 18)) + { + s += "ERROR"; + return; + } + if (Get16(data) != 1) // revision + { + s += "UNSUPPORTED"; + return; + } + ParseOwner(s, data, size, Get32(data + 4)); + s.Add_Space(); + ParseOwner(s, data, size, Get32(data + 8)); + ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); + ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); + s.Add_Space(); + s.Add_UInt32((UInt32)size); + // s.Add_LF(); + // s += Data_To_Hex(data, size); +} + +#ifdef _WIN32 + +static bool CheckSid(const Byte *data, size_t size, UInt32 pos) throw() +{ + if (pos >= size) + return false; + size -= pos; + if (size < 8) + return false; + if (data[pos] != 1) // rev + return false; + const unsigned num = data[pos + 1]; + return (8 + num * 4 <= size); +} + +static bool CheckAcl(const Byte *p, size_t size, UInt32 flags, size_t offset) throw() +{ + const unsigned control = Get16(p + 2); + if ((flags & control) == 0) + return true; + const UInt32 pos = Get32(p + offset); + if (pos >= size) + return false; + p += pos; + size -= pos; + if (size < 8) + return false; + const unsigned aclSize = Get16(p + 2); + return (aclSize <= size); +} + +bool CheckNtSecure(const Byte *data, size_t size) throw() +{ + if (size < 20) + return false; + if (Get16(data) != 1) // revision + return true; // windows function can handle such error, so we allow it + if (size > (1 << 18)) + return false; + if (!CheckSid(data, size, Get32(data + 4))) return false; + if (!CheckSid(data, size, Get32(data + 8))) return false; + if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false; + if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false; + return true; +} + +#endif + + + +// IO_REPARSE_TAG_* + +static const CSecID2Name k_ReparseTags[] = +{ + { 0xA0000003, "MOUNT_POINT" }, + { 0xC0000004, "HSM" }, + { 0x80000005, "DRIVE_EXTENDER" }, + { 0x80000006, "HSM2" }, + { 0x80000007, "SIS" }, + { 0x80000008, "WIM" }, + { 0x80000009, "CSV" }, + { 0x8000000A, "DFS" }, + { 0x8000000B, "FILTER_MANAGER" }, + { 0xA000000C, "SYMLINK" }, + { 0xA0000010, "IIS_CACHE" }, + { 0x80000012, "DFSR" }, + { 0x80000013, "DEDUP" }, + { 0xC0000014, "APPXSTRM" }, + { 0x80000014, "NFS" }, + { 0x80000015, "FILE_PLACEHOLDER" }, + { 0x80000016, "DFM" }, + { 0x80000017, "WOF" }, + { 0x80000018, "WCI" }, + { 0x8000001B, "APPEXECLINK" }, + { 0xA000001D, "LX_SYMLINK" }, + { 0x80000023, "AF_UNIX" }, + { 0x80000024, "LX_FIFO" }, + { 0x80000025, "LX_CHR" }, + { 0x80000026, "LX_BLK" } +}; + +bool ConvertNtReparseToString(const Byte *data, size_t size, UString &s) +{ + s.Empty(); + NFile::CReparseAttr attr; + + if (attr.Parse(data, size)) + { + if (attr.IsSymLink_WSL()) + { + s += "WSL: "; + s += attr.GetPath(); + } + else + { + if (!attr.IsSymLink_Win()) + s += "Junction: "; + s += attr.GetPath(); + if (s.IsEmpty()) + s += "Link: "; + if (!attr.IsOkNamePair()) + { + s += " : "; + s += attr.PrintName; + } + } + if (attr.MinorError) + s += " : MINOR_ERROR"; + return true; + // s.Add_Space(); // for debug + } + + if (size < 8) + return false; + const UInt32 tag = Get32(data); + const UInt32 len = Get16(data + 4); + if (len + 8 > size) + return false; + if (Get16(data + 6) != 0) // padding + return false; + + /* + #define my_IO_REPARSE_TAG_DEDUP (0x80000013L) + if (tag == my_IO_REPARSE_TAG_DEDUP) + { + } + */ + + { + const int index = FindPairIndex(k_ReparseTags, Z7_ARRAY_SIZE(k_ReparseTags), tag); + if (index >= 0) + s += k_ReparseTags[(unsigned)index].sz; + else + { + s += "REPARSE:"; + char hex[16]; + ConvertUInt32ToHex8Digits(tag, hex); + s += hex; + } + } + + s.Add_Colon(); + s.Add_UInt32(len); + + if (len != 0) + { + s.Add_Space(); + + data += 8; + + for (UInt32 i = 0; i < len; i++) + { + if (i >= 16) + { + s += "..."; + break; + } + const unsigned b = data[i]; + s.Add_Char((char)GET_HEX_CHAR_UPPER(b >> 4)); + s.Add_Char((char)GET_HEX_CHAR_UPPER(b & 15)); + } + } + + return true; +} + +#endif diff --git a/CPP/7zip/UI/Common/PropIDUtils.h b/CPP/7zip/UI/Common/PropIDUtils.h index 6344b63cb..dc22793df 100644 --- a/CPP/7zip/UI/Common/PropIDUtils.h +++ b/CPP/7zip/UI/Common/PropIDUtils.h @@ -1,18 +1,18 @@ -// PropIDUtils.h - -#ifndef ZIP7_INC_PROPID_UTILS_H -#define ZIP7_INC_PROPID_UTILS_H - -#include "../../../Common/MyString.h" - -// provide at least 64 bytes for buffer including zero-end -void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0) throw(); -void ConvertPropertyToString2(UString &dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0); - -bool ConvertNtReparseToString(const Byte *data, size_t size, UString &s); -void ConvertNtSecureToString(const Byte *data, size_t size, AString &s); -bool CheckNtSecure(const Byte *data, size_t size) throw(); - -void ConvertWinAttribToString(char *s, UInt32 wa) throw(); - -#endif +// PropIDUtils.h + +#ifndef ZIP7_INC_PROPID_UTILS_H +#define ZIP7_INC_PROPID_UTILS_H + +#include "../../../Common/MyString.h" + +// provide at least 64 bytes for buffer including zero-end +void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0) throw(); +void ConvertPropertyToString2(UString &dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0); + +bool ConvertNtReparseToString(const Byte *data, size_t size, UString &s); +void ConvertNtSecureToString(const Byte *data, size_t size, AString &s); +bool CheckNtSecure(const Byte *data, size_t size) throw(); + +void ConvertWinAttribToString(char *s, UInt32 wa) throw(); + +#endif diff --git a/CPP/7zip/UI/Common/Property.h b/CPP/7zip/UI/Common/Property.h index 48e4a138f..046280989 100644 --- a/CPP/7zip/UI/Common/Property.h +++ b/CPP/7zip/UI/Common/Property.h @@ -1,14 +1,14 @@ -// Property.h - -#ifndef ZIP7_INC_7Z_PROPERTY_H -#define ZIP7_INC_7Z_PROPERTY_H - -#include "../../../Common/MyString.h" - -struct CProperty -{ - UString Name; - UString Value; -}; - -#endif +// Property.h + +#ifndef ZIP7_INC_7Z_PROPERTY_H +#define ZIP7_INC_7Z_PROPERTY_H + +#include "../../../Common/MyString.h" + +struct CProperty +{ + UString Name; + UString Value; +}; + +#endif diff --git a/CPP/7zip/UI/Common/SetProperties.cpp b/CPP/7zip/UI/Common/SetProperties.cpp index ec3b5cf7c..5a05beb57 100644 --- a/CPP/7zip/UI/Common/SetProperties.cpp +++ b/CPP/7zip/UI/Common/SetProperties.cpp @@ -1,88 +1,88 @@ -// SetProperties.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyString.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../Archive/IArchive.h" - -#include "SetProperties.h" - -using namespace NWindows; -using namespace NCOM; - -static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) -{ - const wchar_t *end; - const UInt64 result = ConvertStringToUInt64(s, &end); - if (*end != 0 || s.IsEmpty()) - prop = s; - else if (result <= (UInt32)0xFFFFFFFF) - prop = (UInt32)result; - else - prop = result; -} - - -struct CPropPropetiesVector -{ - CPropVariant *values; - CPropPropetiesVector(unsigned num) - { - values = new CPropVariant[num]; - } - ~CPropPropetiesVector() - { - delete []values; - } -}; - - -HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties) -{ - if (properties.IsEmpty()) - return S_OK; - Z7_DECL_CMyComPtr_QI_FROM( - ISetProperties, - setProperties, unknown) - if (!setProperties) - return S_OK; - - UStringVector realNames; - CPropPropetiesVector values(properties.Size()); - { - unsigned i; - for (i = 0; i < properties.Size(); i++) - { - const CProperty &property = properties[i]; - NCOM::CPropVariant propVariant; - UString name = property.Name; - if (property.Value.IsEmpty()) - { - if (!name.IsEmpty()) - { - const wchar_t c = name.Back(); - if (c == L'-') - propVariant = false; - else if (c == L'+') - propVariant = true; - if (propVariant.vt != VT_EMPTY) - name.DeleteBack(); - } - } - else - ParseNumberString(property.Value, propVariant); - realNames.Add(name); - values.values[i] = propVariant; - } - CRecordVector names; - for (i = 0; i < realNames.Size(); i++) - names.Add((const wchar_t *)realNames[i]); - - return setProperties->SetProperties(names.ConstData(), values.values, names.Size()); - } -} +// SetProperties.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../Archive/IArchive.h" + +#include "SetProperties.h" + +using namespace NWindows; +using namespace NCOM; + +static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) +{ + const wchar_t *end; + const UInt64 result = ConvertStringToUInt64(s, &end); + if (*end != 0 || s.IsEmpty()) + prop = s; + else if (result <= (UInt32)0xFFFFFFFF) + prop = (UInt32)result; + else + prop = result; +} + + +struct CPropPropetiesVector +{ + CPropVariant *values; + CPropPropetiesVector(unsigned num) + { + values = new CPropVariant[num]; + } + ~CPropPropetiesVector() + { + delete []values; + } +}; + + +HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties) +{ + if (properties.IsEmpty()) + return S_OK; + Z7_DECL_CMyComPtr_QI_FROM( + ISetProperties, + setProperties, unknown) + if (!setProperties) + return S_OK; + + UStringVector realNames; + CPropPropetiesVector values(properties.Size()); + { + unsigned i; + for (i = 0; i < properties.Size(); i++) + { + const CProperty &property = properties[i]; + NCOM::CPropVariant propVariant; + UString name = property.Name; + if (property.Value.IsEmpty()) + { + if (!name.IsEmpty()) + { + const wchar_t c = name.Back(); + if (c == L'-') + propVariant = false; + else if (c == L'+') + propVariant = true; + if (propVariant.vt != VT_EMPTY) + name.DeleteBack(); + } + } + else + ParseNumberString(property.Value, propVariant); + realNames.Add(name); + values.values[i] = propVariant; + } + CRecordVector names; + for (i = 0; i < realNames.Size(); i++) + names.Add((const wchar_t *)realNames[i]); + + return setProperties->SetProperties(names.ConstData(), values.values, names.Size()); + } +} diff --git a/CPP/7zip/UI/Common/SetProperties.h b/CPP/7zip/UI/Common/SetProperties.h index cf470e3bc..0676c45da 100644 --- a/CPP/7zip/UI/Common/SetProperties.h +++ b/CPP/7zip/UI/Common/SetProperties.h @@ -1,10 +1,10 @@ -// SetProperties.h - -#ifndef ZIP7_INC_SETPROPERTIES_H -#define ZIP7_INC_SETPROPERTIES_H - -#include "Property.h" - -HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties); - -#endif +// SetProperties.h + +#ifndef ZIP7_INC_SETPROPERTIES_H +#define ZIP7_INC_SETPROPERTIES_H + +#include "Property.h" + +HRESULT SetProperties(IUnknown *unknown, const CObjectVector &properties); + +#endif diff --git a/CPP/7zip/UI/Common/SortUtils.cpp b/CPP/7zip/UI/Common/SortUtils.cpp index f73ece86e..5f29249bd 100644 --- a/CPP/7zip/UI/Common/SortUtils.cpp +++ b/CPP/7zip/UI/Common/SortUtils.cpp @@ -1,25 +1,25 @@ -// SortUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/Wildcard.h" - -#include "SortUtils.h" - -static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param) -{ - const UStringVector &strings = *(const UStringVector *)param; - return CompareFileNames(strings[*p1], strings[*p2]); -} - -void SortFileNames(const UStringVector &strings, CUIntVector &indices) -{ - const unsigned numItems = strings.Size(); - indices.ClearAndSetSize(numItems); - if (numItems == 0) - return; - unsigned *vals = &indices[0]; - for (unsigned i = 0; i < numItems; i++) - vals[i] = i; - indices.Sort(CompareStrings, (void *)&strings); -} +// SortUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/Wildcard.h" + +#include "SortUtils.h" + +static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param) +{ + const UStringVector &strings = *(const UStringVector *)param; + return CompareFileNames(strings[*p1], strings[*p2]); +} + +void SortFileNames(const UStringVector &strings, CUIntVector &indices) +{ + const unsigned numItems = strings.Size(); + indices.ClearAndSetSize(numItems); + if (numItems == 0) + return; + unsigned *vals = &indices[0]; + for (unsigned i = 0; i < numItems; i++) + vals[i] = i; + indices.Sort(CompareStrings, (void *)&strings); +} diff --git a/CPP/7zip/UI/Common/SortUtils.h b/CPP/7zip/UI/Common/SortUtils.h index d8164dd84..07aa24d22 100644 --- a/CPP/7zip/UI/Common/SortUtils.h +++ b/CPP/7zip/UI/Common/SortUtils.h @@ -1,10 +1,10 @@ -// SortUtils.h - -#ifndef ZIP7_INC_SORT_UTLS_H -#define ZIP7_INC_SORT_UTLS_H - -#include "../../../Common/MyString.h" - -void SortFileNames(const UStringVector &strings, CUIntVector &indices); - -#endif +// SortUtils.h + +#ifndef ZIP7_INC_SORT_UTLS_H +#define ZIP7_INC_SORT_UTLS_H + +#include "../../../Common/MyString.h" + +void SortFileNames(const UStringVector &strings, CUIntVector &indices); + +#endif diff --git a/CPP/7zip/UI/Common/StdAfx.h b/CPP/7zip/UI/Common/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/UI/Common/StdAfx.h +++ b/CPP/7zip/UI/Common/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Common/TempFiles.cpp b/CPP/7zip/UI/Common/TempFiles.cpp index 56bba9a1f..ad16e36fc 100644 --- a/CPP/7zip/UI/Common/TempFiles.cpp +++ b/CPP/7zip/UI/Common/TempFiles.cpp @@ -1,19 +1,20 @@ -// TempFiles.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileDir.h" - -#include "TempFiles.h" - -using namespace NWindows; -using namespace NFile; - -void CTempFiles::Clear() -{ - while (!Paths.IsEmpty()) - { - NDir::DeleteFileAlways(Paths.Back()); - Paths.DeleteBack(); - } -} +// TempFiles.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileDir.h" + +#include "TempFiles.h" + +using namespace NWindows; +using namespace NFile; + +void CTempFiles::Clear() +{ + while (!Paths.IsEmpty()) + { + if (NeedDeleteFiles) + NDir::DeleteFileAlways(Paths.Back()); + Paths.DeleteBack(); + } +} diff --git a/CPP/7zip/UI/Common/TempFiles.h b/CPP/7zip/UI/Common/TempFiles.h index 517cb3f34..83c741fcd 100644 --- a/CPP/7zip/UI/Common/TempFiles.h +++ b/CPP/7zip/UI/Common/TempFiles.h @@ -1,16 +1,19 @@ -// TempFiles.h - -#ifndef ZIP7_INC_TEMP_FILES_H -#define ZIP7_INC_TEMP_FILES_H - -#include "../../../Common/MyString.h" - -class CTempFiles -{ - void Clear(); -public: - FStringVector Paths; - ~CTempFiles() { Clear(); } -}; - -#endif +// TempFiles.h + +#ifndef ZIP7_INC_TEMP_FILES_H +#define ZIP7_INC_TEMP_FILES_H + +#include "../../../Common/MyString.h" + +class CTempFiles +{ + void Clear(); +public: + FStringVector Paths; + bool NeedDeleteFiles; + + CTempFiles(): NeedDeleteFiles(true) {} + ~CTempFiles() { Clear(); } +}; + +#endif diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp index e28041ac4..b959a3cb1 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp @@ -1,1877 +1,1931 @@ -// Update.cpp - -#include "StdAfx.h" - -// #include - -#include "Update.h" - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" -#include "../../../Windows/TimeUtils.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/LimitedStreams.h" -#include "../../Common/MultiOutStream.h" -#include "../../Common/StreamUtils.h" - -#include "../../Compress/CopyCoder.h" - -#include "../Common/DirItem.h" -#include "../Common/EnumDirItems.h" -#include "../Common/OpenArchive.h" -#include "../Common/UpdateProduce.h" - -#include "EnumDirItems.h" -#include "SetProperties.h" -#include "TempFiles.h" -#include "UpdateCallback.h" - -static const char * const kUpdateIsNotSupoorted = - "update operations are not supported for this archive"; - -static const char * const kUpdateIsNotSupported_MultiVol = - "Updating for multivolume archives is not implemented"; - -using namespace NWindows; -using namespace NCOM; -using namespace NFile; -using namespace NDir; -using namespace NName; - -#ifdef _WIN32 -static CFSTR const kTempFolderPrefix = FTEXT("7zE"); -#endif - -void CUpdateErrorInfo::SetFromLastError(const char *message) -{ - SystemError = ::GetLastError(); - Message = message; -} - -HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &fileName) -{ - SetFromLastError(message); - FileNames.Add(fileName); - return Get_HRESULT_Error(); -} - -HRESULT CUpdateErrorInfo::SetFromError_DWORD(const char *message, const FString &fileName, DWORD error) -{ - Message = message; - FileNames.Add(fileName); - SystemError = error; - return Get_HRESULT_Error(); -} - - -using namespace NUpdateArchive; - -struct CMultiOutStream_Rec -{ - CMultiOutStream *Spec; - CMyComPtr Ref; -}; - -struct CMultiOutStream_Bunch -{ - CObjectVector Items; - - HRESULT Destruct() - { - HRESULT hres = S_OK; - FOR_VECTOR (i, Items) - { - CMultiOutStream_Rec &rec = Items[i]; - if (rec.Ref) - { - const HRESULT hres2 = rec.Spec->Destruct(); - if (hres == S_OK) - hres = hres2; - } - } - Items.Clear(); - return hres; - } - - void DisableDeletion() - { - FOR_VECTOR (i, Items) - { - CMultiOutStream_Rec &rec = Items[i]; - if (rec.Ref) - rec.Spec->NeedDelete = false; - } - } -}; - - -void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) -{ - OriginalPath = path; - - SplitPathToParts_2(path, Prefix, Name); - - if (mode == k_ArcNameMode_Add) - return; - - if (mode != k_ArcNameMode_Exact) - { - int dotPos = Name.ReverseFind_Dot(); - if (dotPos < 0) - return; - if ((unsigned)dotPos == Name.Len() - 1) - Name.DeleteBack(); - else - { - const UString ext = Name.Ptr((unsigned)(dotPos + 1)); - if (BaseExtension.IsEqualTo_NoCase(ext)) - { - BaseExtension = ext; - Name.DeleteFrom((unsigned)dotPos); - return; - } - } - } - - BaseExtension.Empty(); -} - -UString CArchivePath::GetFinalPath() const -{ - UString path = GetPathWithoutExt(); - if (!BaseExtension.IsEmpty()) - { - path.Add_Dot(); - path += BaseExtension; - } - return path; -} - -UString CArchivePath::GetFinalVolPath() const -{ - UString path = GetPathWithoutExt(); - // if BaseExtension is empty, we must ignore VolExtension also. - if (!BaseExtension.IsEmpty()) - { - path.Add_Dot(); - path += VolExtension; - } - return path; -} - -FString CArchivePath::GetTempPath() const -{ - FString path = TempPrefix; - path += us2fs(Name); - if (!BaseExtension.IsEmpty()) - { - path.Add_Dot(); - path += us2fs(BaseExtension); - } - path += ".tmp"; - path += TempPostfix; - return path; -} - -static const char * const kDefaultArcType = "7z"; -static const char * const kDefaultArcExt = "7z"; -static const char * const kSFXExtension = - #ifdef _WIN32 - "exe"; - #else - ""; - #endif - -bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, - const CObjectVector &types, const UString &arcPath) -{ - if (types.Size() > 1) - return false; - // int arcTypeIndex = -1; - if (types.Size() != 0) - { - MethodMode.Type = types[0]; - MethodMode.Type_Defined = true; - } - if (MethodMode.Type.FormatIndex < 0) - { - // MethodMode.Type = -1; - MethodMode.Type = COpenType(); - if (ArcNameMode != k_ArcNameMode_Add) - { - MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); - if (MethodMode.Type.FormatIndex >= 0) - MethodMode.Type_Defined = true; - } - } - return true; -} - -bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) -{ - UString typeExt; - int formatIndex = MethodMode.Type.FormatIndex; - if (formatIndex < 0) - { - typeExt = kDefaultArcExt; - } - else - { - const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; - if (!arcInfo.UpdateEnabled) - return false; - typeExt = arcInfo.GetMainExt(); - } - UString ext = typeExt; - if (SfxMode) - ext = kSFXExtension; - ArchivePath.BaseExtension = ext; - ArchivePath.VolExtension = typeExt; - ArchivePath.ParseFromPath(arcPath, ArcNameMode); - FOR_VECTOR (i, Commands) - { - CUpdateArchiveCommand &uc = Commands[i]; - uc.ArchivePath.BaseExtension = ext; - uc.ArchivePath.VolExtension = typeExt; - uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); - } - return true; -} - - -struct CUpdateProduceCallbackImp Z7_final: public IUpdateProduceCallback -{ - const CObjectVector *_arcItems; - CDirItemsStat *_stat; - IUpdateCallbackUI *_callback; - - CUpdateProduceCallbackImp( - const CObjectVector *a, - CDirItemsStat *stat, - IUpdateCallbackUI *callback): - _arcItems(a), - _stat(stat), - _callback(callback) {} - - virtual HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override; -}; - - -HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex) -{ - const CArcItem &ai = (*_arcItems)[arcIndex]; - { - CDirItemsStat &stat = *_stat; - if (ai.IsDir) - stat.NumDirs++; - else if (ai.IsAltStream) - { - stat.NumAltStreams++; - stat.AltStreamsSize += ai.Size; - } - else - { - stat.NumFiles++; - stat.FilesSize += ai.Size; - } - } - return _callback->ShowDeleteFile(ai.Name, ai.IsDir); -} - -bool CRenamePair::Prepare() -{ - if (RecursedType != NRecursedType::kNonRecursed) - return false; - if (!WildcardParsing) - return true; - return !DoesNameContainWildcard(OldName); -} - -extern bool g_CaseSensitive; - -static unsigned CompareTwoNames(const wchar_t *s1, const wchar_t *s2) -{ - for (unsigned i = 0;; i++) - { - wchar_t c1 = s1[i]; - wchar_t c2 = s2[i]; - if (c1 == 0 || c2 == 0) - return i; - if (c1 == c2) - continue; - if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) - continue; - if (IsPathSepar(c1) && IsPathSepar(c2)) - continue; - return i; - } -} - -bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const -{ - unsigned num = CompareTwoNames(OldName, src); - if (OldName[num] == 0) - { - if (src[num] != 0 && !IsPathSepar(src[num]) && num != 0 && !IsPathSepar(src[num - 1])) - return false; - } - else - { - // OldName[num] != 0 - // OldName = "1\1a.txt" - // src = "1" - - if (!isFolder - || src[num] != 0 - || !IsPathSepar(OldName[num]) - || OldName[num + 1] != 0) - return false; - } - dest = NewName + src.Ptr(num); - return true; -} - -#ifdef SUPPORT_ALT_STREAMS -int FindAltStreamColon_in_Path(const wchar_t *path); -#endif - - - -static HRESULT Compress( - const CUpdateOptions &options, - bool isUpdatingItself, - CCodecs *codecs, - const CActionSet &actionSet, - const CArc *arc, - CArchivePath &archivePath, - const CObjectVector &arcItems, - Byte *processedItemsStatuses, - const CDirItems &dirItems, - const CDirItem *parentDirItem, - CTempFiles &tempFiles, - CMultiOutStream_Bunch &multiStreams, - CUpdateErrorInfo &errorInfo, - IUpdateCallbackUI *callback, - CFinishArchiveStat &st) -{ - CMyComPtr outArchive; - int formatIndex = options.MethodMode.Type.FormatIndex; - - if (arc) - { - formatIndex = arc->FormatIndex; - if (formatIndex < 0) - return E_NOTIMPL; - CMyComPtr archive2 = arc->Archive; - HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); - if (result != S_OK) - throw kUpdateIsNotSupoorted; - } - else - { - RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive)) - - #ifdef Z7_EXTERNAL_CODECS - { - CMyComPtr setCompressCodecsInfo; - outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); - if (setCompressCodecsInfo) - { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)) - } - } - #endif - } - - if (!outArchive) - throw kUpdateIsNotSupoorted; - - // we need to set properties to get fileTimeType. - RINOK(SetProperties(outArchive, options.MethodMode.Properties)) - - NFileTimeType::EEnum fileTimeType; - { - /* - how we compare file_in_archive::MTime with dirItem.MTime - for GetUpdatePairInfoList(): - - if (kpidMTime is not defined), external MTime of archive is used. - - before 22.00: - if (kpidTimeType is defined) - { - kpidTimeType is used as precision. - (kpidTimeType > kDOS) is not allowed. - } - else GetFileTimeType() value is used as precision. - - 22.00: - if (kpidMTime is defined) - { - if (kpidMTime::precision != 0), then kpidMTime::precision is used as precision. - else - { - if (kpidTimeType is defined), kpidTimeType is used as precision. - else GetFileTimeType() value is used as precision. - } - } - else external MTime of archive is used as precision. - */ - - UInt32 value; - RINOK(outArchive->GetFileTimeType(&value)) - - // we support any future fileType here. - fileTimeType = (NFileTimeType::EEnum)value; - - /* - old 21.07 code: - switch (value) - { - case NFileTimeType::kWindows: - case NFileTimeType::kUnix: - case NFileTimeType::kDOS: - fileTimeType = (NFileTimeType::EEnum)value; - break; - default: - return E_FAIL; - } - */ - } - - // bool noTimestampExpected = false; - { - const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; - - // if (arcInfo.Flags_KeepName()) noTimestampExpected = true; - if (arcInfo.Is_Xz() || - arcInfo.Is_BZip2()) - { - /* 7-zip before 22.00 returns NFileTimeType::kUnix for xz and bzip2, - but we want to set timestamp without reduction to unix. */ - // noTimestampExpected = true; - fileTimeType = NFileTimeType::kNotDefined; // it means not defined - } - - if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) - return E_NOTIMPL; - if (options.NtSecurity.Val && !arcInfo.Flags_NtSecurity()) - return E_NOTIMPL; - if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler()) - return E_NOTIMPL; - } - - CRecordVector updatePairs2; - - UStringVector newNames; - - CArcToDoStat stat2; - - if (options.RenamePairs.Size() != 0) - { - FOR_VECTOR (i, arcItems) - { - const CArcItem &ai = arcItems[i]; - bool needRename = false; - UString dest; - - if (ai.Censored) - { - FOR_VECTOR (j, options.RenamePairs) - { - const CRenamePair &rp = options.RenamePairs[j]; - if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) - { - needRename = true; - break; - } - - #ifdef SUPPORT_ALT_STREAMS - if (ai.IsAltStream) - { - int colonPos = FindAltStreamColon_in_Path(ai.Name); - if (colonPos >= 0) - { - UString mainName = ai.Name.Left((unsigned)colonPos); - /* - actually we must improve that code to support cases - with folder renaming like: rn arc dir1\ dir2\ - */ - if (rp.GetNewPath(false, mainName, dest)) - { - needRename = true; - dest.Add_Colon(); - dest += ai.Name.Ptr((unsigned)(colonPos + 1)); - break; - } - } - } - #endif - } - } - - CUpdatePair2 up2; - up2.SetAs_NoChangeArcItem(ai.IndexInServer); - if (needRename) - { - up2.NewProps = true; - RINOK(arc->IsItem_Anti(i, up2.IsAnti)) - up2.NewNameIndex = (int)newNames.Add(dest); - } - updatePairs2.Add(up2); - } - } - else - { - CRecordVector updatePairs; - GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! - CUpdateProduceCallbackImp upCallback(&arcItems, &stat2.DeleteData, callback); - - UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL); - } - - { - FOR_VECTOR (i, updatePairs2) - { - const CUpdatePair2 &up = updatePairs2[i]; - - // 17.01: anti-item is (up.NewData && (p.UseArcProps in most cases)) - - if (up.NewData && !up.UseArcProps) - { - if (up.ExistOnDisk()) - { - CDirItemsStat2 &stat = stat2.NewData; - const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; - if (di.IsDir()) - { - if (up.IsAnti) - stat.Anti_NumDirs++; - else - stat.NumDirs++; - } - #ifdef _WIN32 - else if (di.IsAltStream) - { - if (up.IsAnti) - stat.Anti_NumAltStreams++; - else - { - stat.NumAltStreams++; - stat.AltStreamsSize += di.Size; - } - } - #endif - else - { - if (up.IsAnti) - stat.Anti_NumFiles++; - else - { - stat.NumFiles++; - stat.FilesSize += di.Size; - } - } - } - } - else if (up.ArcIndex >= 0) - { - CDirItemsStat2 &stat = *(up.NewData ? &stat2.NewData : &stat2.OldData); - const CArcItem &ai = arcItems[(unsigned)up.ArcIndex]; - if (ai.IsDir) - { - if (up.IsAnti) - stat.Anti_NumDirs++; - else - stat.NumDirs++; - } - else if (ai.IsAltStream) - { - if (up.IsAnti) - stat.Anti_NumAltStreams++; - else - { - stat.NumAltStreams++; - stat.AltStreamsSize += ai.Size; - } - } - else - { - if (up.IsAnti) - stat.Anti_NumFiles++; - else - { - stat.NumFiles++; - stat.FilesSize += ai.Size; - } - } - } - } - RINOK(callback->SetNumItems(stat2)) - } - - CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; - CMyComPtr updateCallback(updateCallbackSpec); - - updateCallbackSpec->PreserveATime = options.PreserveATime; - updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; - updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError; - updateCallbackSpec->StdInMode = options.StdInMode; - updateCallbackSpec->Callback = callback; - - if (arc) - { - // we set Archive to allow to transfer GetProperty requests back to DLL. - updateCallbackSpec->Archive = arc->Archive; - } - - updateCallbackSpec->DirItems = &dirItems; - updateCallbackSpec->ParentDirItem = parentDirItem; - - updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; - updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; - updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; - updateCallbackSpec->StoreOwnerName = options.StoreOwnerName.Val; - updateCallbackSpec->StoreOwnerId = options.StoreOwnerId.Val; - - updateCallbackSpec->Arc = arc; - updateCallbackSpec->ArcItems = &arcItems; - updateCallbackSpec->UpdatePairs = &updatePairs2; - - updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; - - { - const UString arcPath = archivePath.GetFinalPath(); - updateCallbackSpec->ArcFileName = ExtractFileNameFromPath(arcPath); - } - - if (options.RenamePairs.Size() != 0) - updateCallbackSpec->NewNames = &newNames; - - if (options.SetArcMTime) - { - // updateCallbackSpec->Need_ArcMTime_Report = true; - updateCallbackSpec->Need_LatestMTime = true; - } - - CMyComPtr outSeekStream; - CMyComPtr outStream; - - if (!options.StdOutMode) - { - FString dirPrefix; - if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) - throw 1417161; - CreateComplexDir(dirPrefix); - } - - COutFileStream *outStreamSpec = NULL; - CStdOutFileStream *stdOutFileStreamSpec = NULL; - CMultiOutStream *volStreamSpec = NULL; - - if (options.VolumesSizes.Size() == 0) - { - if (options.StdOutMode) - { - stdOutFileStreamSpec = new CStdOutFileStream; - outStream = stdOutFileStreamSpec; - } - else - { - outStreamSpec = new COutFileStream; - outSeekStream = outStreamSpec; - outStream = outSeekStream; - bool isOK = false; - FString realPath; - - for (unsigned i = 0; i < (1 << 16); i++) - { - if (archivePath.Temp) - { - if (i > 0) - { - archivePath.TempPostfix.Empty(); - archivePath.TempPostfix.Add_UInt32(i); - } - realPath = archivePath.GetTempPath(); - } - else - realPath = us2fs(archivePath.GetFinalPath()); - if (outStreamSpec->Create_NEW(realPath)) - { - tempFiles.Paths.Add(realPath); - isOK = true; - break; - } - if (::GetLastError() != ERROR_FILE_EXISTS) - break; - if (!archivePath.Temp) - break; - } - - if (!isOK) - return errorInfo.SetFromLastError("cannot open file", realPath); - } - } - else - { - if (options.StdOutMode) - return E_FAIL; - if (arc && arc->GetGlobalOffset() > 0) - return E_NOTIMPL; - - volStreamSpec = new CMultiOutStream(); - outSeekStream = volStreamSpec; - outStream = outSeekStream; - volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath()); - volStreamSpec->Prefix.Add_Dot(); - volStreamSpec->Init(options.VolumesSizes); - { - CMultiOutStream_Rec &rec = multiStreams.Items.AddNew(); - rec.Spec = volStreamSpec; - rec.Ref = rec.Spec; - } - - /* - updateCallbackSpec->VolumesSizes = volumesSizes; - updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; - if (!archivePath.VolExtension.IsEmpty()) - updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension; - */ - } - - if (options.SfxMode) - { - CInFileStream *sfxStreamSpec = new CInFileStream; - CMyComPtr sfxStream(sfxStreamSpec); - if (!sfxStreamSpec->Open(options.SfxModule)) - return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule); - - CMyComPtr sfxOutStream; - COutFileStream *outStreamSpec2 = NULL; - if (options.VolumesSizes.Size() == 0) - sfxOutStream = outStream; - else - { - outStreamSpec2 = new COutFileStream; - sfxOutStream = outStreamSpec2; - const FString realPath = us2fs(archivePath.GetFinalPath()); - if (!outStreamSpec2->Create_NEW(realPath)) - return errorInfo.SetFromLastError("cannot open file", realPath); - } - - { - UInt64 sfxSize; - RINOK(sfxStreamSpec->GetSize(&sfxSize)) - RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize)) - } - - RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)) - - if (outStreamSpec2) - { - RINOK(outStreamSpec2->Close()) - } - } - - CMyComPtr tailStream; - - if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) - tailStream = outStream; - else - { - // Int64 globalOffset = arc->GetGlobalOffset(); - RINOK(InStream_SeekToBegin(arc->InStream)) - RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)) - if (options.StdOutMode) - tailStream = outStream; - else - { - CTailOutStream *tailStreamSpec = new CTailOutStream; - tailStream = tailStreamSpec; - tailStreamSpec->Stream = outSeekStream; - tailStreamSpec->Offset = arc->ArcStreamOffset; - tailStreamSpec->Init(); - } - } - - CFiTime ft; - FiTime_Clear(ft); - bool ft_Defined = false; - { - FOR_VECTOR (i, updatePairs2) - { - const CUpdatePair2 &pair2 = updatePairs2[i]; - CFiTime ft2; - FiTime_Clear(ft2); - bool ft2_Defined = false; - /* we use full precision of dirItem, if dirItem is defined - and (dirItem will be used or dirItem is sameTime in dir and arc */ - if (pair2.DirIndex >= 0 && - (pair2.NewProps || pair2.IsSameTime)) - { - ft2 = dirItems.Items[(unsigned)pair2.DirIndex].MTime; - ft2_Defined = true; - } - else if (pair2.UseArcProps && pair2.ArcIndex >= 0) - { - const CArcItem &arcItem = arcItems[(unsigned)pair2.ArcIndex]; - if (arcItem.MTime.Def) - { - arcItem.MTime.Write_To_FiTime(ft2); - ft2_Defined = true; - } - } - if (ft2_Defined) - { - if (!ft_Defined || Compare_FiTime(&ft, &ft2) < 0) - { - ft = ft2; - ft_Defined = true; - } - } - } - /* - if (fileTimeType != NFileTimeType::kNotDefined) - FiTime_Normalize_With_Prec(ft, fileTimeType); - */ - } - - if (volStreamSpec && options.SetArcMTime && ft_Defined) - { - volStreamSpec->MTime = ft; - volStreamSpec->MTime_Defined = true; - } - - HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); - // callback->Finalize(); - RINOK(result) - - if (!updateCallbackSpec->AreAllFilesClosed()) - { - errorInfo.Message = "There are unclosed input files:"; - errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths; - return E_FAIL; - } - - if (options.SetArcMTime) - { - // bool needNormalizeAfterStream; - // needParse; - /* - if (updateCallbackSpec->ArcMTime_WasReported) - { - isDefined = updateCallbackSpec->Reported_ArcMTime.Def; - if (isDefined) - updateCallbackSpec->Reported_ArcMTime.Write_To_FiTime(ft); - else - fileTimeType = NFileTimeType::kNotDefined; - } - if (!isDefined) - */ - { - if (updateCallbackSpec->LatestMTime_Defined) - { - // CArcTime at = StreamCallback_ArcMTime; - // updateCallbackSpec->StreamCallback_ArcMTime.Write_To_FiTime(ft); - // we must normalize with precision from archive; - if (!ft_Defined || Compare_FiTime(&ft, &updateCallbackSpec->LatestMTime) < 0) - ft = updateCallbackSpec->LatestMTime; - ft_Defined = true; - } - /* - if (fileTimeType != NFileTimeType::kNotDefined) - FiTime_Normalize_With_Prec(ft, fileTimeType); - */ - } - // if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) - if (ft_Defined) - { - // we ignore set time errors here. - // note that user could move some finished volumes to another folder. - if (outStreamSpec) - outStreamSpec->SetMTime(&ft); - else if (volStreamSpec) - volStreamSpec->SetMTime_Final(ft); - } - } - - if (callback) - { - UInt64 size = 0; - if (outStreamSpec) - outStreamSpec->GetSize(&size); - else if (stdOutFileStreamSpec) - size = stdOutFileStreamSpec->GetSize(); - else - size = volStreamSpec->GetSize(); - - st.OutArcFileSize = size; - } - - if (outStreamSpec) - result = outStreamSpec->Close(); - else if (volStreamSpec) - { - result = volStreamSpec->FinalFlush_and_CloseFiles(st.NumVolumes); - st.IsMultiVolMode = true; - } - - RINOK(result) - - if (processedItemsStatuses) - { - FOR_VECTOR (i, updatePairs2) - { - const CUpdatePair2 &up = updatePairs2[i]; - if (up.NewData && up.DirIndex >= 0) - { - const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; - if (di.AreReparseData() || (!di.IsDir() && di.Size == 0)) - processedItemsStatuses[(unsigned)up.DirIndex] = 1; - } - } - } - - return result; -} - - - -static bool Censor_AreAllAllowed(const NWildcard::CCensor &censor) -{ - if (censor.Pairs.Size() != 1) - return false; - const NWildcard::CPair &pair = censor.Pairs[0]; - /* Censor_CheckPath() ignores (CPair::Prefix). - So we also ignore (CPair::Prefix) here */ - // if (!pair.Prefix.IsEmpty()) return false; - return pair.Head.AreAllAllowed(); -} - -bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); - -static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) -{ - bool finded = false; - FOR_VECTOR (i, censor.Pairs) - { - /* (CPair::Prefix) in not used for matching items in archive. - So we ignore (CPair::Prefix) here */ - bool include; - if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include)) - { - // Check it and FIXME !!!! - // here we can exclude item via some Pair, that is still allowed by another Pair - if (!include) - return false; - finded = true; - } - } - return finded; -} - -static HRESULT EnumerateInArchiveItems( - // bool storeStreamsMode, - const NWildcard::CCensor &censor, - const CArc &arc, - CObjectVector &arcItems) -{ - arcItems.Clear(); - UInt32 numItems; - IInArchive *archive = arc.Archive; - RINOK(archive->GetNumberOfItems(&numItems)) - arcItems.ClearAndReserve(numItems); - - CReadArcItem item; - - const bool allFilesAreAllowed = Censor_AreAllAllowed(censor); - - for (UInt32 i = 0; i < numItems; i++) - { - CArcItem ai; - - RINOK(arc.GetItem(i, item)) - ai.Name = item.Path; - ai.IsDir = item.IsDir; - ai.IsAltStream = - #ifdef SUPPORT_ALT_STREAMS - item.IsAltStream; - #else - false; - #endif - - /* - if (!storeStreamsMode && ai.IsAltStream) - continue; - */ - if (allFilesAreAllowed) - ai.Censored = true; - else - ai.Censored = Censor_CheckPath(censor, item); - - // ai.MTime will be set to archive MTime, if not present in archive item - RINOK(arc.GetItem_MTime(i, ai.MTime)) - RINOK(arc.GetItem_Size(i, ai.Size, ai.Size_Defined)) - - ai.IndexInServer = i; - arcItems.AddInReserved(ai); - } - return S_OK; -} - -#if defined(_WIN32) && !defined(UNDER_CE) - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -extern "C" { - -#ifdef MAPI_FORCE_UNICODE - -#define Z7_WIN_LPMAPISENDMAILW LPMAPISENDMAILW -#define Z7_WIN_MapiFileDescW MapiFileDescW -#define Z7_WIN_MapiMessageW MapiMessageW -#define Z7_WIN_MapiRecipDescW MapiRecipDescW - -#else - -typedef struct -{ - ULONG ulReserved; - ULONG ulRecipClass; - PWSTR lpszName; - PWSTR lpszAddress; - ULONG ulEIDSize; - PVOID lpEntryID; -} Z7_WIN_MapiRecipDescW, *Z7_WIN_lpMapiRecipDescW; - -typedef struct -{ - ULONG ulReserved; - ULONG flFlags; - ULONG nPosition; - PWSTR lpszPathName; - PWSTR lpszFileName; - PVOID lpFileType; -} Z7_WIN_MapiFileDescW, *Z7_WIN_lpMapiFileDescW; - -typedef struct -{ - ULONG ulReserved; - PWSTR lpszSubject; - PWSTR lpszNoteText; - PWSTR lpszMessageType; - PWSTR lpszDateReceived; - PWSTR lpszConversationID; - FLAGS flFlags; - Z7_WIN_lpMapiRecipDescW lpOriginator; - ULONG nRecipCount; - Z7_WIN_lpMapiRecipDescW lpRecips; - ULONG nFileCount; - Z7_WIN_lpMapiFileDescW lpFiles; -} Z7_WIN_MapiMessageW, *Z7_WIN_lpMapiMessageW; - -typedef ULONG (FAR PASCAL Z7_WIN_MAPISENDMAILW)( - LHANDLE lhSession, - ULONG_PTR ulUIParam, - Z7_WIN_lpMapiMessageW lpMessage, - FLAGS flFlags, - ULONG ulReserved -); -typedef Z7_WIN_MAPISENDMAILW FAR *Z7_WIN_LPMAPISENDMAILW; - -#endif // MAPI_FORCE_UNICODE -} -#endif // _WIN32 - - -HRESULT UpdateArchive( - CCodecs *codecs, - const CObjectVector &types, - const UString &cmdArcPath2, - NWildcard::CCensor &censor, - CUpdateOptions &options, - CUpdateErrorInfo &errorInfo, - IOpenCallbackUI *openCallback, - IUpdateCallbackUI2 *callback, - bool needSetPath) -{ - if (options.StdOutMode && options.EMailMode) - return E_FAIL; - - if (types.Size() > 1) - return E_NOTIMPL; - - bool renameMode = !options.RenamePairs.IsEmpty(); - if (renameMode) - { - if (options.Commands.Size() != 1) - return E_FAIL; - } - - if (options.DeleteAfterCompressing) - { - if (options.Commands.Size() != 1) - return E_NOTIMPL; - const CActionSet &as = options.Commands[0].ActionSet; - for (unsigned i = 2; i < NPairState::kNumValues; i++) - if (as.StateActions[i] != NPairAction::kCompress) - return E_NOTIMPL; - } - - censor.AddPathsToCensor(options.PathMode); - #ifdef _WIN32 - ConvertToLongNames(censor); - #endif - censor.ExtendExclude(); - - - if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */)) - return E_NOTIMPL; - - if (options.SfxMode) - { - CProperty property; - property.Name = "rsfx"; - options.MethodMode.Properties.Add(property); - if (options.SfxModule.IsEmpty()) - { - errorInfo.Message = "SFX file is not specified"; - return E_FAIL; - } - bool found = false; - if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) - { - const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule; - if (NFind::DoesFileExist_FollowLink(fullName)) - { - options.SfxModule = fullName; - found = true; - } - } - if (!found) - { - if (!NFind::DoesFileExist_FollowLink(options.SfxModule)) - return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule); - } - } - - CArchiveLink arcLink; - - - if (needSetPath) - { - if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || - !options.SetArcPath(codecs, cmdArcPath2)) - return E_NOTIMPL; - } - - UString arcPath = options.ArchivePath.GetFinalPath(); - - if (!options.VolumesSizes.IsEmpty()) - { - arcPath = options.ArchivePath.GetFinalVolPath(); - arcPath += ".001"; - } - - if (cmdArcPath2.IsEmpty()) - { - if (options.MethodMode.Type.FormatIndex < 0) - throw "type of archive is not specified"; - } - else - { - NFind::CFileInfo fi; - if (!fi.Find_FollowLink(us2fs(arcPath))) - { - if (renameMode) - throw "can't find archive"; - if (options.MethodMode.Type.FormatIndex < 0) - { - if (!options.SetArcPath(codecs, cmdArcPath2)) - return E_NOTIMPL; - } - } - else - { - if (fi.IsDir()) - return errorInfo.SetFromError_DWORD("There is a folder with the name of archive", - us2fs(arcPath), - #ifdef _WIN32 - ERROR_ACCESS_DENIED - #else - EISDIR - #endif - ); - #ifdef _WIN32 - if (fi.IsDevice) - return E_NOTIMPL; - #endif - - if (!options.StdOutMode && options.UpdateArchiveItself) - if (fi.IsReadOnly()) - { - return errorInfo.SetFromError_DWORD("The file is read-only", - us2fs(arcPath), - #ifdef _WIN32 - ERROR_ACCESS_DENIED - #else - EACCES - #endif - ); - } - - if (options.VolumesSizes.Size() > 0) - { - errorInfo.FileNames.Add(us2fs(arcPath)); - // errorInfo.SystemError = (DWORD)E_NOTIMPL; - errorInfo.Message = kUpdateIsNotSupported_MultiVol; - return E_NOTIMPL; - } - CObjectVector types2; - // change it. - if (options.MethodMode.Type_Defined) - types2.Add(options.MethodMode.Type); - // We need to set Properties to open archive only in some cases (WIM archives). - - CIntVector excl; - COpenOptions op; - #ifndef Z7_SFX - op.props = &options.MethodMode.Properties; - #endif - op.codecs = codecs; - op.types = &types2; - op.excludedFormats = ! - op.stdInMode = false; - op.stream = NULL; - op.filePath = arcPath; - - RINOK(callback->StartOpenArchive(arcPath)) - - HRESULT result = arcLink.Open_Strict(op, openCallback); - - if (result == E_ABORT) - return result; - - HRESULT res2 = callback->OpenResult(codecs, arcLink, arcPath, result); - /* - if (result == S_FALSE) - return E_FAIL; - */ - RINOK(res2) - RINOK(result) - - if (arcLink.VolumePaths.Size() > 1) - { - // errorInfo.SystemError = (DWORD)E_NOTIMPL; - errorInfo.Message = kUpdateIsNotSupported_MultiVol; - return E_NOTIMPL; - } - - CArc &arc = arcLink.Arcs.Back(); - arc.MTime.Def = - #ifdef _WIN32 - !fi.IsDevice; - #else - true; - #endif - if (arc.MTime.Def) - arc.MTime.Set_From_FiTime(fi.MTime); - - if (arc.ErrorInfo.ThereIsTail) - { - // errorInfo.SystemError = (DWORD)E_NOTIMPL; - errorInfo.Message = "There is some data block after the end of the archive"; - return E_NOTIMPL; - } - if (options.MethodMode.Type.FormatIndex < 0) - { - options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; - if (!options.SetArcPath(codecs, cmdArcPath2)) - return E_NOTIMPL; - } - } - } - - if (options.MethodMode.Type.FormatIndex < 0) - { - options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType((UString)kDefaultArcType); - if (options.MethodMode.Type.FormatIndex < 0) - return E_NOTIMPL; - } - - bool thereIsInArchive = arcLink.IsOpen; - if (!thereIsInArchive && renameMode) - return E_FAIL; - - CDirItems dirItems; - dirItems.Callback = callback; - - CDirItem parentDirItem; - CDirItem *parentDirItem_Ptr = NULL; - - /* - FStringVector requestedPaths; - FStringVector *requestedPaths_Ptr = NULL; - if (options.DeleteAfterCompressing) - requestedPaths_Ptr = &requestedPaths; - */ - - if (options.StdInMode) - { - CDirItem di; - // di.ClearBase(); - // di.Size = (UInt64)(Int64)-1; - if (!di.SetAs_StdInFile()) - return GetLastError_noZero_HRESULT(); - di.Name = options.StdInFileName; - // di.Attrib_IsDefined = false; - // NTime::GetCurUtc_FiTime(di.MTime); - // di.CTime = di.ATime = di.MTime; - dirItems.Items.Add(di); - } - else - { - bool needScanning = false; - - if (!renameMode) - FOR_VECTOR (i, options.Commands) - if (options.Commands[i].ActionSet.NeedScanning()) - needScanning = true; - - if (needScanning) - { - RINOK(callback->StartScanning()) - - dirItems.SymLinks = options.SymLinks.Val; - - #if defined(_WIN32) && !defined(UNDER_CE) - dirItems.ReadSecure = options.NtSecurity.Val; - #endif - - dirItems.ScanAltStreams = options.AltStreams.Val; - dirItems.ExcludeDirItems = censor.ExcludeDirItems; - dirItems.ExcludeFileItems = censor.ExcludeFileItems; - - dirItems.ShareForWrite = options.OpenShareForWrite; - - #ifndef _WIN32 - dirItems.StoreOwnerName = options.StoreOwnerName.Val; - #endif - - const HRESULT res = EnumerateItems(censor, - options.PathMode, - UString(), // options.AddPathPrefix, - dirItems); - - if (res != S_OK) - { - if (res != E_ABORT) - errorInfo.Message = "Scanning error"; - return res; - } - - RINOK(callback->FinishScanning(dirItems.Stat)) - - // 22.00: we don't need parent folder, if absolute path mode - if (options.PathMode != NWildcard::k_AbsPath) - if (censor.Pairs.Size() == 1) - { - NFind::CFileInfo fi; - FString prefix = us2fs(censor.Pairs[0].Prefix); - prefix.Add_Dot(); - // UString prefix = censor.Pairs[0].Prefix; - /* - if (prefix.Back() == WCHAR_PATH_SEPARATOR) - { - prefix.DeleteBack(); - } - */ - if (fi.Find(prefix)) - if (fi.IsDir()) - { - parentDirItem.Copy_From_FileInfoBase(fi); - parentDirItem_Ptr = &parentDirItem; - - int secureIndex = -1; - #if defined(_WIN32) && !defined(UNDER_CE) - if (options.NtSecurity.Val) - dirItems.AddSecurityItem(prefix, secureIndex); - #endif - parentDirItem.SecureIndex = secureIndex; - } - } - } - } - - FString tempDirPrefix; - bool usesTempDir = false; - - #ifdef _WIN32 - CTempDir tempDirectory; - if (options.EMailMode && options.EMailRemoveAfter) - { - tempDirectory.Create(kTempFolderPrefix); - tempDirPrefix = tempDirectory.GetPath(); - NormalizeDirPathPrefix(tempDirPrefix); - usesTempDir = true; - } - #endif - - CTempFiles tempFiles; - - bool createTempFile = false; - - if (!options.StdOutMode && options.UpdateArchiveItself) - { - CArchivePath &ap = options.Commands[0].ArchivePath; - ap = options.ArchivePath; - // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) - if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0) - { - createTempFile = true; - ap.Temp = true; - if (!options.WorkingDir.IsEmpty()) - ap.TempPrefix = options.WorkingDir; - else - ap.TempPrefix = us2fs(ap.Prefix); - NormalizeDirPathPrefix(ap.TempPrefix); - } - } - - unsigned ci; - - - // self including protection - if (options.DeleteAfterCompressing) - { - for (ci = 0; ci < options.Commands.Size(); ci++) - { - CArchivePath &ap = options.Commands[ci].ArchivePath; - const FString path = us2fs(ap.GetFinalPath()); - // maybe we must compare absolute paths path here - FOR_VECTOR (i, dirItems.Items) - { - const FString phyPath = dirItems.GetPhyPath(i); - if (phyPath == path) - { - UString s; - s = "It is not allowed to include archive to itself"; - s.Add_LF(); - s += fs2us(path); - throw s; - } - } - } - } - - - for (ci = 0; ci < options.Commands.Size(); ci++) - { - CArchivePath &ap = options.Commands[ci].ArchivePath; - if (usesTempDir) - { - // Check it - ap.Prefix = fs2us(tempDirPrefix); - // ap.Temp = true; - // ap.TempPrefix = tempDirPrefix; - } - if (!options.StdOutMode && - (ci > 0 || !createTempFile)) - { - const FString path = us2fs(ap.GetFinalPath()); - if (NFind::DoesFileOrDirExist(path)) - { - errorInfo.SystemError = ERROR_FILE_EXISTS; - errorInfo.Message = "The file already exists"; - errorInfo.FileNames.Add(path); - return errorInfo.Get_HRESULT_Error(); - } - } - } - - CObjectVector arcItems; - if (thereIsInArchive) - { - RINOK(EnumerateInArchiveItems( - // options.StoreAltStreams, - censor, arcLink.Arcs.Back(), arcItems)) - } - - /* - FStringVector processedFilePaths; - FStringVector *processedFilePaths_Ptr = NULL; - if (options.DeleteAfterCompressing) - processedFilePaths_Ptr = &processedFilePaths; - */ - - CByteBuffer processedItems; - if (options.DeleteAfterCompressing) - { - const unsigned num = dirItems.Items.Size(); - processedItems.Alloc(num); - for (unsigned i = 0; i < num; i++) - processedItems[i] = 0; - } - - CMultiOutStream_Bunch multiStreams; - - /* - #ifndef Z7_NO_CRYPTO - if (arcLink.PasswordWasAsked) - { - // We set password, if open have requested password - RINOK(callback->SetPassword(arcLink.Password)); - } - #endif - */ - - for (ci = 0; ci < options.Commands.Size(); ci++) - { - const CArc *arc = thereIsInArchive ? arcLink.GetArc() : NULL; - CUpdateArchiveCommand &command = options.Commands[ci]; - UString name; - bool isUpdating; - - if (options.StdOutMode) - { - name = "stdout"; - isUpdating = thereIsInArchive; - } - else - { - name = command.ArchivePath.GetFinalPath(); - isUpdating = (ci == 0 && options.UpdateArchiveItself && thereIsInArchive); - } - - RINOK(callback->StartArchive(name, isUpdating)) - - CFinishArchiveStat st; - - RINOK(Compress(options, - isUpdating, - codecs, - command.ActionSet, - arc, - command.ArchivePath, - arcItems, - options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, - - dirItems, - parentDirItem_Ptr, - - tempFiles, - multiStreams, - errorInfo, callback, st)) - - RINOK(callback->FinishArchive(st)) - } - - - if (thereIsInArchive) - { - RINOK(arcLink.Close()) - arcLink.Release(); - } - - multiStreams.DisableDeletion(); - RINOK(multiStreams.Destruct()) - - tempFiles.Paths.Clear(); - if (createTempFile) - { - try - { - CArchivePath &ap = options.Commands[0].ArchivePath; - const FString &tempPath = ap.GetTempPath(); - - // DWORD attrib = 0; - if (thereIsInArchive) - { - // attrib = NFind::GetFileAttrib(us2fs(arcPath)); - if (!DeleteFileAlways(us2fs(arcPath))) - return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); - } - - if (!MyMoveFile(tempPath, us2fs(arcPath))) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = "cannot move the file"; - if (errorInfo.SystemError == ERROR_INVALID_PARAMETER) - { - NFind::CFileInfo fi; - if (fi.Find(tempPath) && - fi.Size > (UInt32)(Int32)-1) - { - // bool isFsDetected = false; - // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected) - { - errorInfo.Message.Add_LF(); - errorInfo.Message += "Archive file size exceeds 4 GB"; - } - } - } - errorInfo.FileNames.Add(tempPath); - errorInfo.FileNames.Add(us2fs(arcPath)); - return errorInfo.Get_HRESULT_Error(); - } - - /* - if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) - { - DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath)); - if (attrib2 != INVALID_FILE_ATTRIBUTES) - NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY); - } - */ - } - catch(...) - { - throw; - } - } - - - #if defined(_WIN32) && !defined(UNDER_CE) - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - - if (options.EMailMode) - { - NDLL::CLibrary mapiLib; - if (!mapiLib.Load(FTEXT("Mapi32.dll"))) - { - errorInfo.SetFromLastError("cannot load Mapi32.dll"); - return errorInfo.Get_HRESULT_Error(); - } - - FStringVector fullPaths; - unsigned i; - - for (i = 0; i < options.Commands.Size(); i++) - { - CArchivePath &ap = options.Commands[i].ArchivePath; - const FString finalPath = us2fs(ap.GetFinalPath()); - FString arcPath2; - if (!MyGetFullPathName(finalPath, arcPath2)) - return errorInfo.SetFromLastError("GetFullPathName error", finalPath); - fullPaths.Add(arcPath2); - } - - /* - LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); - if (fnSend == 0) - { - errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function"); - return errorInfo.Get_HRESULT_Error(); - } - */ - const - Z7_WIN_LPMAPISENDMAILW sendMailW = Z7_GET_PROC_ADDRESS( - Z7_WIN_LPMAPISENDMAILW, mapiLib.Get_HMODULE(), - "MAPISendMailW"); - if (sendMailW) - { - - CCurrentDirRestorer curDirRestorer; - - UStringVector paths; - UStringVector names; - - for (i = 0; i < fullPaths.Size(); i++) - { - const UString arcPath2 = fs2us(fullPaths[i]); - const UString fileName = ExtractFileNameFromPath(arcPath2); - paths.Add(arcPath2); - names.Add(fileName); - // Warning!!! MAPISendDocuments function changes Current directory - // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); - } - - CRecordVector files; - files.ClearAndSetSize(paths.Size()); - - for (i = 0; i < paths.Size(); i++) - { - Z7_WIN_MapiFileDescW &f = files[i]; - memset(&f, 0, sizeof(f)); - f.nPosition = 0xFFFFFFFF; - f.lpszPathName = paths[i].Ptr_non_const(); - f.lpszFileName = names[i].Ptr_non_const(); - } - - { - Z7_WIN_MapiMessageW m; - memset(&m, 0, sizeof(m)); - m.nFileCount = files.Size(); - m.lpFiles = files.NonConstData(); - - const UString addr (options.EMailAddress); - Z7_WIN_MapiRecipDescW rec; - if (!addr.IsEmpty()) - { - memset(&rec, 0, sizeof(rec)); - rec.ulRecipClass = MAPI_TO; - rec.lpszAddress = addr.Ptr_non_const(); - m.nRecipCount = 1; - m.lpRecips = &rec; - } - - sendMailW((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); - } - } - else - { - const - LPMAPISENDMAIL sendMail = Z7_GET_PROC_ADDRESS( - LPMAPISENDMAIL, mapiLib.Get_HMODULE(), - "MAPISendMail"); - if (!sendMail) - { - errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function"); - return errorInfo.Get_HRESULT_Error(); - } - - CCurrentDirRestorer curDirRestorer; - - AStringVector paths; - AStringVector names; - - for (i = 0; i < fullPaths.Size(); i++) - { - const UString arcPath2 = fs2us(fullPaths[i]); - const UString fileName = ExtractFileNameFromPath(arcPath2); - paths.Add(GetAnsiString(arcPath2)); - names.Add(GetAnsiString(fileName)); - // const AString path (GetAnsiString(arcPath2)); - // const AString name (GetAnsiString(fileName)); - // Warning!!! MAPISendDocuments function changes Current directory - // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); - } - - CRecordVector files; - files.ClearAndSetSize(paths.Size()); - - for (i = 0; i < paths.Size(); i++) - { - MapiFileDesc &f = files[i]; - memset(&f, 0, sizeof(f)); - f.nPosition = 0xFFFFFFFF; - f.lpszPathName = paths[i].Ptr_non_const(); - f.lpszFileName = names[i].Ptr_non_const(); - } - - { - MapiMessage m; - memset(&m, 0, sizeof(m)); - m.nFileCount = files.Size(); - m.lpFiles = files.NonConstData(); - - const AString addr (GetAnsiString(options.EMailAddress)); - MapiRecipDesc rec; - if (!addr.IsEmpty()) - { - memset(&rec, 0, sizeof(rec)); - rec.ulRecipClass = MAPI_TO; - rec.lpszAddress = addr.Ptr_non_const(); - m.nRecipCount = 1; - m.lpRecips = &rec; - } - - sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); - } - } - } - - #endif - - if (options.DeleteAfterCompressing) - { - CRecordVector pairs; - FStringVector foldersNames; - - unsigned i; - - for (i = 0; i < dirItems.Items.Size(); i++) - { - const CDirItem &dirItem = dirItems.Items[i]; - const FString phyPath = dirItems.GetPhyPath(i); - if (dirItem.IsDir()) - { - CDirPathSortPair pair; - pair.Index = i; - pair.SetNumSlashes(phyPath); - pairs.Add(pair); - } - else - { - // 21.04: we have set processedItems[*] before for all required items - if (processedItems[i] != 0 - // || dirItem.Size == 0 - // || dirItem.AreReparseData() - ) - { - NFind::CFileInfo fileInfo; - /* if (!SymLinks), we follow link here, similar to (dirItem) filling */ - if (fileInfo.Find(phyPath, !options.SymLinks.Val)) - { - bool is_SameSize = false; - if (options.SymLinks.Val && dirItem.AreReparseData()) - { - /* (dirItem.Size = dirItem.ReparseData.Size()) was set before. - So we don't compare sizes for that case here */ - is_SameSize = fileInfo.IsOsSymLink(); - } - else - is_SameSize = (fileInfo.Size == dirItem.Size); - - if (is_SameSize - && Compare_FiTime(&fileInfo.MTime, &dirItem.MTime) == 0 - && Compare_FiTime(&fileInfo.CTime, &dirItem.CTime) == 0) - { - RINOK(callback->DeletingAfterArchiving(phyPath, false)) - DeleteFileAlways(phyPath); - } - } - } - else - { - // file was skipped by some reason. We can throw error for debug: - /* - errorInfo.SystemError = 0; - errorInfo.Message = "file was not processed"; - errorInfo.FileNames.Add(phyPath); - return E_FAIL; - */ - } - } - } - - pairs.Sort2(); - - for (i = 0; i < pairs.Size(); i++) - { - const FString phyPath = dirItems.GetPhyPath(pairs[i].Index); - if (NFind::DoesDirExist(phyPath)) - { - RINOK(callback->DeletingAfterArchiving(phyPath, true)) - RemoveDir(phyPath); - } - } - - RINOK(callback->FinishDeletingAfterArchiving()) - } - - return S_OK; -} +// Update.cpp + +#include "StdAfx.h" + +// #include + +#include "Update.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/TimeUtils.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.h" +#include "../../Common/MultiOutStream.h" +#include "../../Common/StreamUtils.h" + +#include "../../Compress/CopyCoder.h" + +#include "../Common/DirItem.h" +#include "../Common/EnumDirItems.h" +#include "../Common/OpenArchive.h" +#include "../Common/UpdateProduce.h" + +#include "EnumDirItems.h" +#include "SetProperties.h" +#include "TempFiles.h" +#include "UpdateCallback.h" + +static const char * const kUpdateIsNotSupoorted = + "update operations are not supported for this archive"; + +static const char * const kUpdateIsNotSupported_MultiVol = + "Updating for multivolume archives is not implemented"; + +using namespace NWindows; +using namespace NCOM; +using namespace NFile; +using namespace NDir; +using namespace NName; + +#ifdef _WIN32 +static CFSTR const kTempFolderPrefix = FTEXT("7zE"); +#endif + +void CUpdateErrorInfo::SetFromLastError(const char *message) +{ + SystemError = ::GetLastError(); + Message = message; +} + +HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &fileName) +{ + SetFromLastError(message); + FileNames.Add(fileName); + return Get_HRESULT_Error(); +} + +HRESULT CUpdateErrorInfo::SetFromError_DWORD(const char *message, const FString &fileName, DWORD error) +{ + Message = message; + FileNames.Add(fileName); + SystemError = error; + return Get_HRESULT_Error(); +} + + +using namespace NUpdateArchive; + +struct CMultiOutStream_Rec +{ + CMultiOutStream *Spec; + CMyComPtr Ref; +}; + +struct CMultiOutStream_Bunch +{ + CObjectVector Items; + + HRESULT Destruct() + { + HRESULT hres = S_OK; + FOR_VECTOR (i, Items) + { + CMultiOutStream_Rec &rec = Items[i]; + if (rec.Ref) + { + const HRESULT hres2 = rec.Spec->Destruct(); + if (hres == S_OK) + hres = hres2; + } + } + Items.Clear(); + return hres; + } + + void DisableDeletion() + { + FOR_VECTOR (i, Items) + { + CMultiOutStream_Rec &rec = Items[i]; + if (rec.Ref) + rec.Spec->NeedDelete = false; + } + } +}; + + +void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) +{ + OriginalPath = path; + + SplitPathToParts_2(path, Prefix, Name); + + if (mode == k_ArcNameMode_Add) + return; + + if (mode != k_ArcNameMode_Exact) + { + int dotPos = Name.ReverseFind_Dot(); + if (dotPos < 0) + return; + if ((unsigned)dotPos == Name.Len() - 1) + Name.DeleteBack(); + else + { + const UString ext = Name.Ptr((unsigned)(dotPos + 1)); + if (BaseExtension.IsEqualTo_NoCase(ext)) + { + BaseExtension = ext; + Name.DeleteFrom((unsigned)dotPos); + return; + } + } + } + + BaseExtension.Empty(); +} + +UString CArchivePath::GetFinalPath() const +{ + UString path = GetPathWithoutExt(); + if (!BaseExtension.IsEmpty()) + { + path.Add_Dot(); + path += BaseExtension; + } + return path; +} + +UString CArchivePath::GetFinalVolPath() const +{ + UString path = GetPathWithoutExt(); + // if BaseExtension is empty, we must ignore VolExtension also. + if (!BaseExtension.IsEmpty()) + { + path.Add_Dot(); + path += VolExtension; + } + return path; +} + +FString CArchivePath::GetTempPath() const +{ + FString path = TempPrefix; + path += us2fs(Name); + if (!BaseExtension.IsEmpty()) + { + path.Add_Dot(); + path += us2fs(BaseExtension); + } + path += ".tmp"; + path += TempPostfix; + return path; +} + +static const char * const kDefaultArcType = "7z"; +static const char * const kDefaultArcExt = "7z"; +static const char * const kSFXExtension = + #ifdef _WIN32 + "exe"; + #else + ""; + #endif + +bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, + const CObjectVector &types, const UString &arcPath) +{ + if (types.Size() > 1) + return false; + // int arcTypeIndex = -1; + if (types.Size() != 0) + { + MethodMode.Type = types[0]; + MethodMode.Type_Defined = true; + } + if (MethodMode.Type.FormatIndex < 0) + { + // MethodMode.Type = -1; + MethodMode.Type = COpenType(); + if (ArcNameMode != k_ArcNameMode_Add) + { + MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); + if (MethodMode.Type.FormatIndex >= 0) + MethodMode.Type_Defined = true; + } + } + return true; +} + +bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) +{ + UString typeExt; + int formatIndex = MethodMode.Type.FormatIndex; + if (formatIndex < 0) + { + typeExt = kDefaultArcExt; + } + else + { + const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; + if (!arcInfo.UpdateEnabled) + return false; + typeExt = arcInfo.GetMainExt(); + } + UString ext = typeExt; + if (SfxMode) + ext = kSFXExtension; + ArchivePath.BaseExtension = ext; + ArchivePath.VolExtension = typeExt; + ArchivePath.ParseFromPath(arcPath, ArcNameMode); + FOR_VECTOR (i, Commands) + { + CUpdateArchiveCommand &uc = Commands[i]; + uc.ArchivePath.BaseExtension = ext; + uc.ArchivePath.VolExtension = typeExt; + uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); + } + return true; +} + + +struct CUpdateProduceCallbackImp Z7_final: public IUpdateProduceCallback +{ + const CObjectVector *_arcItems; + CDirItemsStat *_stat; + IUpdateCallbackUI *_callback; + + CUpdateProduceCallbackImp( + const CObjectVector *a, + CDirItemsStat *stat, + IUpdateCallbackUI *callback): + _arcItems(a), + _stat(stat), + _callback(callback) {} + + virtual HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override; +}; + + +HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex) +{ + const CArcItem &ai = (*_arcItems)[arcIndex]; + { + CDirItemsStat &stat = *_stat; + if (ai.IsDir) + stat.NumDirs++; + else if (ai.IsAltStream) + { + stat.NumAltStreams++; + stat.AltStreamsSize += ai.Size; + } + else + { + stat.NumFiles++; + stat.FilesSize += ai.Size; + } + } + return _callback->ShowDeleteFile(ai.Name, ai.IsDir); +} + +bool CRenamePair::Prepare() +{ + if (RecursedType != NRecursedType::kNonRecursed) + return false; + if (!WildcardParsing) + return true; + return !DoesNameContainWildcard(OldName); +} + +extern bool g_CaseSensitive; + +static unsigned CompareTwoNames(const wchar_t *s1, const wchar_t *s2) +{ + for (unsigned i = 0;; i++) + { + wchar_t c1 = s1[i]; + wchar_t c2 = s2[i]; + if (c1 == 0 || c2 == 0) + return i; + if (c1 == c2) + continue; + if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) + continue; + if (IsPathSepar(c1) && IsPathSepar(c2)) + continue; + return i; + } +} + +bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const +{ + unsigned num = CompareTwoNames(OldName, src); + if (OldName[num] == 0) + { + if (src[num] != 0 && !IsPathSepar(src[num]) && num != 0 && !IsPathSepar(src[num - 1])) + return false; + } + else + { + // OldName[num] != 0 + // OldName = "1\1a.txt" + // src = "1" + + if (!isFolder + || src[num] != 0 + || !IsPathSepar(OldName[num]) + || OldName[num + 1] != 0) + return false; + } + dest = NewName + src.Ptr(num); + return true; +} + +#ifdef SUPPORT_ALT_STREAMS +int FindAltStreamColon_in_Path(const wchar_t *path); +#endif + + + +static HRESULT Compress( + const CUpdateOptions &options, + bool isUpdatingItself, + CCodecs *codecs, + const CActionSet &actionSet, + const CArc *arc, + CArchivePath &archivePath, + const CObjectVector &arcItems, + Byte *processedItemsStatuses, + const CDirItems &dirItems, + const CDirItem *parentDirItem, + CTempFiles &tempFiles, + CMultiOutStream_Bunch &multiStreams, + CUpdateErrorInfo &errorInfo, + IUpdateCallbackUI *callback, + CFinishArchiveStat &st) +{ + CMyComPtr outArchive; + int formatIndex = options.MethodMode.Type.FormatIndex; + + if (arc) + { + formatIndex = arc->FormatIndex; + if (formatIndex < 0) + return E_NOTIMPL; + CMyComPtr archive2 = arc->Archive; + HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); + if (result != S_OK) + throw kUpdateIsNotSupoorted; + } + else + { + RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive)) + + #ifdef Z7_EXTERNAL_CODECS + { + CMyComPtr setCompressCodecsInfo; + outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)) + } + } + #endif + } + + if (!outArchive) + throw kUpdateIsNotSupoorted; + + // we need to set properties to get fileTimeType. + RINOK(SetProperties(outArchive, options.MethodMode.Properties)) + + NFileTimeType::EEnum fileTimeType; + { + /* + how we compare file_in_archive::MTime with dirItem.MTime + for GetUpdatePairInfoList(): + + if (kpidMTime is not defined), external MTime of archive is used. + + before 22.00: + if (kpidTimeType is defined) + { + kpidTimeType is used as precision. + (kpidTimeType > kDOS) is not allowed. + } + else GetFileTimeType() value is used as precision. + + 22.00: + if (kpidMTime is defined) + { + if (kpidMTime::precision != 0), then kpidMTime::precision is used as precision. + else + { + if (kpidTimeType is defined), kpidTimeType is used as precision. + else GetFileTimeType() value is used as precision. + } + } + else external MTime of archive is used as precision. + */ + + UInt32 value; + RINOK(outArchive->GetFileTimeType(&value)) + + // we support any future fileType here. + fileTimeType = (NFileTimeType::EEnum)value; + + /* + old 21.07 code: + switch (value) + { + case NFileTimeType::kWindows: + case NFileTimeType::kUnix: + case NFileTimeType::kDOS: + fileTimeType = (NFileTimeType::EEnum)value; + break; + default: + return E_FAIL; + } + */ + } + + // bool noTimestampExpected = false; + { + const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; + + // if (arcInfo.Flags_KeepName()) noTimestampExpected = true; + if (arcInfo.Is_Xz() || + arcInfo.Is_BZip2()) + { + /* 7-zip before 22.00 returns NFileTimeType::kUnix for xz and bzip2, + but we want to set timestamp without reduction to unix. */ + // noTimestampExpected = true; + fileTimeType = NFileTimeType::kNotDefined; // it means not defined + } + + if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) + return E_NOTIMPL; + if (options.NtSecurity.Val && !arcInfo.Flags_NtSecurity()) + return E_NOTIMPL; + if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler()) + return E_NOTIMPL; + } + + CRecordVector updatePairs2; + + UStringVector newNames; + + CArcToDoStat stat2; + + if (options.RenamePairs.Size() != 0) + { + FOR_VECTOR (i, arcItems) + { + const CArcItem &ai = arcItems[i]; + bool needRename = false; + UString dest; + + if (ai.Censored) + { + FOR_VECTOR (j, options.RenamePairs) + { + const CRenamePair &rp = options.RenamePairs[j]; + if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) + { + needRename = true; + break; + } + + #ifdef SUPPORT_ALT_STREAMS + if (ai.IsAltStream) + { + int colonPos = FindAltStreamColon_in_Path(ai.Name); + if (colonPos >= 0) + { + UString mainName = ai.Name.Left((unsigned)colonPos); + /* + actually we must improve that code to support cases + with folder renaming like: rn arc dir1\ dir2\ + */ + if (rp.GetNewPath(false, mainName, dest)) + { + needRename = true; + dest.Add_Colon(); + dest += ai.Name.Ptr((unsigned)(colonPos + 1)); + break; + } + } + } + #endif + } + } + + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(ai.IndexInServer); + if (needRename) + { + up2.NewProps = true; + RINOK(arc->IsItem_Anti(i, up2.IsAnti)) + up2.NewNameIndex = (int)newNames.Add(dest); + } + updatePairs2.Add(up2); + } + } + else + { + CRecordVector updatePairs; + GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! + CUpdateProduceCallbackImp upCallback(&arcItems, &stat2.DeleteData, callback); + + UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL); + } + + { + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &up = updatePairs2[i]; + + // 17.01: anti-item is (up.NewData && (p.UseArcProps in most cases)) + + if (up.NewData && !up.UseArcProps) + { + if (up.ExistOnDisk()) + { + CDirItemsStat2 &stat = stat2.NewData; + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; + if (di.IsDir()) + { + if (up.IsAnti) + stat.Anti_NumDirs++; + else + stat.NumDirs++; + } + #ifdef _WIN32 + else if (di.IsAltStream) + { + if (up.IsAnti) + stat.Anti_NumAltStreams++; + else + { + stat.NumAltStreams++; + stat.AltStreamsSize += di.Size; + } + } + #endif + else + { + if (up.IsAnti) + stat.Anti_NumFiles++; + else + { + stat.NumFiles++; + stat.FilesSize += di.Size; + } + } + } + } + else if (up.ArcIndex >= 0) + { + CDirItemsStat2 &stat = *(up.NewData ? &stat2.NewData : &stat2.OldData); + const CArcItem &ai = arcItems[(unsigned)up.ArcIndex]; + if (ai.IsDir) + { + if (up.IsAnti) + stat.Anti_NumDirs++; + else + stat.NumDirs++; + } + else if (ai.IsAltStream) + { + if (up.IsAnti) + stat.Anti_NumAltStreams++; + else + { + stat.NumAltStreams++; + stat.AltStreamsSize += ai.Size; + } + } + else + { + if (up.IsAnti) + stat.Anti_NumFiles++; + else + { + stat.NumFiles++; + stat.FilesSize += ai.Size; + } + } + } + } + RINOK(callback->SetNumItems(stat2)) + } + + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr updateCallback(updateCallbackSpec); + + updateCallbackSpec->PreserveATime = options.PreserveATime; + updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; + updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError; + updateCallbackSpec->StdInMode = options.StdInMode; + updateCallbackSpec->Callback = callback; + + if (arc) + { + // we set Archive to allow to transfer GetProperty requests back to DLL. + updateCallbackSpec->Archive = arc->Archive; + } + + updateCallbackSpec->DirItems = &dirItems; + updateCallbackSpec->ParentDirItem = parentDirItem; + + updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; + updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; + updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; + updateCallbackSpec->StoreOwnerName = options.StoreOwnerName.Val; + updateCallbackSpec->StoreOwnerId = options.StoreOwnerId.Val; + + updateCallbackSpec->Arc = arc; + updateCallbackSpec->ArcItems = &arcItems; + updateCallbackSpec->UpdatePairs = &updatePairs2; + + updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; + + { + const UString arcPath = archivePath.GetFinalPath(); + updateCallbackSpec->ArcFileName = ExtractFileNameFromPath(arcPath); + } + + if (options.RenamePairs.Size() != 0) + updateCallbackSpec->NewNames = &newNames; + + if (options.SetArcMTime) + { + // updateCallbackSpec->Need_ArcMTime_Report = true; + updateCallbackSpec->Need_LatestMTime = true; + } + + CMyComPtr outSeekStream; + CMyComPtr outStream; + + if (!options.StdOutMode) + { + FString dirPrefix; + if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) + throw 1417161; + CreateComplexDir(dirPrefix); + } + + COutFileStream *outStreamSpec = NULL; + CStdOutFileStream *stdOutFileStreamSpec = NULL; + CMultiOutStream *volStreamSpec = NULL; + + if (options.VolumesSizes.Size() == 0) + { + if (options.StdOutMode) + { + stdOutFileStreamSpec = new CStdOutFileStream; + outStream = stdOutFileStreamSpec; + } + else + { + outStreamSpec = new COutFileStream; + outSeekStream = outStreamSpec; + outStream = outSeekStream; + bool isOK = false; + FString realPath; + + for (unsigned i = 0; i < (1 << 16); i++) + { + if (archivePath.Temp) + { + if (i > 0) + { + archivePath.TempPostfix.Empty(); + archivePath.TempPostfix.Add_UInt32(i); + } + realPath = archivePath.GetTempPath(); + } + else + realPath = us2fs(archivePath.GetFinalPath()); + if (outStreamSpec->Create_NEW(realPath)) + { + tempFiles.Paths.Add(realPath); + isOK = true; + break; + } + if (::GetLastError() != ERROR_FILE_EXISTS) + break; + if (!archivePath.Temp) + break; + } + + if (!isOK) + return errorInfo.SetFromLastError("cannot open file", realPath); + } + } + else + { + if (options.StdOutMode) + return E_FAIL; + if (arc && arc->GetGlobalOffset() > 0) + return E_NOTIMPL; + + volStreamSpec = new CMultiOutStream(); + outSeekStream = volStreamSpec; + outStream = outSeekStream; + volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath()); + volStreamSpec->Prefix.Add_Dot(); + volStreamSpec->Init(options.VolumesSizes); + { + CMultiOutStream_Rec &rec = multiStreams.Items.AddNew(); + rec.Spec = volStreamSpec; + rec.Ref = rec.Spec; + } + + /* + updateCallbackSpec->VolumesSizes = volumesSizes; + updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; + if (!archivePath.VolExtension.IsEmpty()) + updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension; + */ + } + + if (options.SfxMode) + { + CInFileStream *sfxStreamSpec = new CInFileStream; + CMyComPtr sfxStream(sfxStreamSpec); + if (!sfxStreamSpec->Open(options.SfxModule)) + return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule); + + CMyComPtr sfxOutStream; + COutFileStream *outStreamSpec2 = NULL; + if (options.VolumesSizes.Size() == 0) + sfxOutStream = outStream; + else + { + outStreamSpec2 = new COutFileStream; + sfxOutStream = outStreamSpec2; + const FString realPath = us2fs(archivePath.GetFinalPath()); + if (!outStreamSpec2->Create_NEW(realPath)) + return errorInfo.SetFromLastError("cannot open file", realPath); + } + + { + UInt64 sfxSize; + RINOK(sfxStreamSpec->GetSize(&sfxSize)) + RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize)) + } + + RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)) + + if (outStreamSpec2) + { + RINOK(outStreamSpec2->Close()) + } + } + + CMyComPtr tailStream; + + if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) + tailStream = outStream; + else + { + // Int64 globalOffset = arc->GetGlobalOffset(); + RINOK(InStream_SeekToBegin(arc->InStream)) + RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)) + if (options.StdOutMode) + tailStream = outStream; + else + { + CTailOutStream *tailStreamSpec = new CTailOutStream; + tailStream = tailStreamSpec; + tailStreamSpec->Stream = outSeekStream; + tailStreamSpec->Offset = arc->ArcStreamOffset; + tailStreamSpec->Init(); + } + } + + CFiTime ft; + FiTime_Clear(ft); + bool ft_Defined = false; + { + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &pair2 = updatePairs2[i]; + CFiTime ft2; + FiTime_Clear(ft2); + bool ft2_Defined = false; + /* we use full precision of dirItem, if dirItem is defined + and (dirItem will be used or dirItem is sameTime in dir and arc */ + if (pair2.DirIndex >= 0 && + (pair2.NewProps || pair2.IsSameTime)) + { + ft2 = dirItems.Items[(unsigned)pair2.DirIndex].MTime; + ft2_Defined = true; + } + else if (pair2.UseArcProps && pair2.ArcIndex >= 0) + { + const CArcItem &arcItem = arcItems[(unsigned)pair2.ArcIndex]; + if (arcItem.MTime.Def) + { + arcItem.MTime.Write_To_FiTime(ft2); + ft2_Defined = true; + } + } + if (ft2_Defined) + { + if (!ft_Defined || Compare_FiTime(&ft, &ft2) < 0) + { + ft = ft2; + ft_Defined = true; + } + } + } + /* + if (fileTimeType != NFileTimeType::kNotDefined) + FiTime_Normalize_With_Prec(ft, fileTimeType); + */ + } + + if (volStreamSpec && options.SetArcMTime && ft_Defined) + { + volStreamSpec->MTime = ft; + volStreamSpec->MTime_Defined = true; + } + + HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); + // callback->Finalize(); + RINOK(result) + + if (!updateCallbackSpec->AreAllFilesClosed()) + { + errorInfo.Message = "There are unclosed input files:"; + errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths; + return E_FAIL; + } + + if (options.SetArcMTime) + { + // bool needNormalizeAfterStream; + // needParse; + /* + if (updateCallbackSpec->ArcMTime_WasReported) + { + isDefined = updateCallbackSpec->Reported_ArcMTime.Def; + if (isDefined) + updateCallbackSpec->Reported_ArcMTime.Write_To_FiTime(ft); + else + fileTimeType = NFileTimeType::kNotDefined; + } + if (!isDefined) + */ + { + if (updateCallbackSpec->LatestMTime_Defined) + { + // CArcTime at = StreamCallback_ArcMTime; + // updateCallbackSpec->StreamCallback_ArcMTime.Write_To_FiTime(ft); + // we must normalize with precision from archive; + if (!ft_Defined || Compare_FiTime(&ft, &updateCallbackSpec->LatestMTime) < 0) + ft = updateCallbackSpec->LatestMTime; + ft_Defined = true; + } + /* + if (fileTimeType != NFileTimeType::kNotDefined) + FiTime_Normalize_With_Prec(ft, fileTimeType); + */ + } + // if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + if (ft_Defined) + { + // we ignore set time errors here. + // note that user could move some finished volumes to another folder. + if (outStreamSpec) + outStreamSpec->SetMTime(&ft); + else if (volStreamSpec) + volStreamSpec->SetMTime_Final(ft); + } + } + + if (callback) + { + UInt64 size = 0; + if (outStreamSpec) + outStreamSpec->GetSize(&size); + else if (stdOutFileStreamSpec) + size = stdOutFileStreamSpec->GetSize(); + else + size = volStreamSpec->GetSize(); + + st.OutArcFileSize = size; + } + + if (outStreamSpec) + result = outStreamSpec->Close(); + else if (volStreamSpec) + { + result = volStreamSpec->FinalFlush_and_CloseFiles(st.NumVolumes); + st.IsMultiVolMode = true; + } + + RINOK(result) + + if (processedItemsStatuses) + { + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &up = updatePairs2[i]; + if (up.NewData && up.DirIndex >= 0) + { + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; + if (di.AreReparseData() || (!di.IsDir() && di.Size == 0)) + processedItemsStatuses[(unsigned)up.DirIndex] = 1; + } + } + } + + return result; +} + + + +static bool Censor_AreAllAllowed(const NWildcard::CCensor &censor) +{ + if (censor.Pairs.Size() != 1) + return false; + const NWildcard::CPair &pair = censor.Pairs[0]; + /* Censor_CheckPath() ignores (CPair::Prefix). + So we also ignore (CPair::Prefix) here */ + // if (!pair.Prefix.IsEmpty()) return false; + return pair.Head.AreAllAllowed(); +} + +bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); + +static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) +{ + bool finded = false; + FOR_VECTOR (i, censor.Pairs) + { + /* (CPair::Prefix) in not used for matching items in archive. + So we ignore (CPair::Prefix) here */ + bool include; + if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include)) + { + // Check it and FIXME !!!! + // here we can exclude item via some Pair, that is still allowed by another Pair + if (!include) + return false; + finded = true; + } + } + return finded; +} + +static HRESULT EnumerateInArchiveItems( + // bool storeStreamsMode, + const NWildcard::CCensor &censor, + const CArc &arc, + CObjectVector &arcItems) +{ + arcItems.Clear(); + UInt32 numItems; + IInArchive *archive = arc.Archive; + RINOK(archive->GetNumberOfItems(&numItems)) + arcItems.ClearAndReserve(numItems); + + CReadArcItem item; + + const bool allFilesAreAllowed = Censor_AreAllAllowed(censor); + + for (UInt32 i = 0; i < numItems; i++) + { + CArcItem ai; + + RINOK(arc.GetItem(i, item)) + ai.Name = item.Path; + ai.IsDir = item.IsDir; + ai.IsAltStream = + #ifdef SUPPORT_ALT_STREAMS + item.IsAltStream; + #else + false; + #endif + + /* + if (!storeStreamsMode && ai.IsAltStream) + continue; + */ + if (allFilesAreAllowed) + ai.Censored = true; + else + ai.Censored = Censor_CheckPath(censor, item); + + // ai.MTime will be set to archive MTime, if not present in archive item + RINOK(arc.GetItem_MTime(i, ai.MTime)) + RINOK(arc.GetItem_Size(i, ai.Size, ai.Size_Defined)) + + ai.IndexInServer = i; + arcItems.AddInReserved(ai); + } + return S_OK; +} + +#if defined(_WIN32) && !defined(UNDER_CE) + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +extern "C" { + +#ifdef MAPI_FORCE_UNICODE + +#define Z7_WIN_LPMAPISENDMAILW LPMAPISENDMAILW +#define Z7_WIN_MapiFileDescW MapiFileDescW +#define Z7_WIN_MapiMessageW MapiMessageW +#define Z7_WIN_MapiRecipDescW MapiRecipDescW + +#else + +typedef struct +{ + ULONG ulReserved; + ULONG ulRecipClass; + PWSTR lpszName; + PWSTR lpszAddress; + ULONG ulEIDSize; + PVOID lpEntryID; +} Z7_WIN_MapiRecipDescW, *Z7_WIN_lpMapiRecipDescW; + +typedef struct +{ + ULONG ulReserved; + ULONG flFlags; + ULONG nPosition; + PWSTR lpszPathName; + PWSTR lpszFileName; + PVOID lpFileType; +} Z7_WIN_MapiFileDescW, *Z7_WIN_lpMapiFileDescW; + +typedef struct +{ + ULONG ulReserved; + PWSTR lpszSubject; + PWSTR lpszNoteText; + PWSTR lpszMessageType; + PWSTR lpszDateReceived; + PWSTR lpszConversationID; + FLAGS flFlags; + Z7_WIN_lpMapiRecipDescW lpOriginator; + ULONG nRecipCount; + Z7_WIN_lpMapiRecipDescW lpRecips; + ULONG nFileCount; + Z7_WIN_lpMapiFileDescW lpFiles; +} Z7_WIN_MapiMessageW, *Z7_WIN_lpMapiMessageW; + +typedef ULONG (FAR PASCAL Z7_WIN_MAPISENDMAILW)( + LHANDLE lhSession, + ULONG_PTR ulUIParam, + Z7_WIN_lpMapiMessageW lpMessage, + FLAGS flFlags, + ULONG ulReserved +); +typedef Z7_WIN_MAPISENDMAILW FAR *Z7_WIN_LPMAPISENDMAILW; + +#endif // MAPI_FORCE_UNICODE +} +#endif // _WIN32 + + +struct C_CopyFileProgress_to_IUpdateCallbackUI2 Z7_final: + public ICopyFileProgress +{ + IUpdateCallbackUI2 *Callback; + HRESULT CallbackResult; + // bool Disable_Break; + + virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) Z7_override + { + const HRESULT res = Callback->MoveArc_Progress(total, current); + CallbackResult = res; + // if (Disable_Break && res == E_ABORT) res = S_OK; + return res == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL; + } + + C_CopyFileProgress_to_IUpdateCallbackUI2( + IUpdateCallbackUI2 *callback) : + Callback(callback), + CallbackResult(S_OK) + // , Disable_Break(false) + {} +}; + + +HRESULT UpdateArchive( + CCodecs *codecs, + const CObjectVector &types, + const UString &cmdArcPath2, + NWildcard::CCensor &censor, + CUpdateOptions &options, + CUpdateErrorInfo &errorInfo, + IOpenCallbackUI *openCallback, + IUpdateCallbackUI2 *callback, + bool needSetPath) +{ + if (options.StdOutMode && options.EMailMode) + return E_FAIL; + + if (types.Size() > 1) + return E_NOTIMPL; + + bool renameMode = !options.RenamePairs.IsEmpty(); + if (renameMode) + { + if (options.Commands.Size() != 1) + return E_FAIL; + } + + if (options.DeleteAfterCompressing) + { + if (options.Commands.Size() != 1) + return E_NOTIMPL; + const CActionSet &as = options.Commands[0].ActionSet; + for (unsigned i = 2; i < NPairState::kNumValues; i++) + if (as.StateActions[i] != NPairAction::kCompress) + return E_NOTIMPL; + } + + censor.AddPathsToCensor(options.PathMode); + #ifdef _WIN32 + ConvertToLongNames(censor); + #endif + censor.ExtendExclude(); + + + if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */)) + return E_NOTIMPL; + + if (options.SfxMode) + { + CProperty property; + property.Name = "rsfx"; + options.MethodMode.Properties.Add(property); + if (options.SfxModule.IsEmpty()) + { + errorInfo.Message = "SFX file is not specified"; + return E_FAIL; + } + bool found = false; + if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) + { + const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule; + if (NFind::DoesFileExist_FollowLink(fullName)) + { + options.SfxModule = fullName; + found = true; + } + } + if (!found) + { + if (!NFind::DoesFileExist_FollowLink(options.SfxModule)) + return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule); + } + } + + CArchiveLink arcLink; + + + if (needSetPath) + { + if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || + !options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + + UString arcPath = options.ArchivePath.GetFinalPath(); + + if (!options.VolumesSizes.IsEmpty()) + { + arcPath = options.ArchivePath.GetFinalVolPath(); + arcPath += ".001"; + } + + if (cmdArcPath2.IsEmpty()) + { + if (options.MethodMode.Type.FormatIndex < 0) + throw "type of archive is not specified"; + } + else + { + NFind::CFileInfo fi; + if (!fi.Find_FollowLink(us2fs(arcPath))) + { + if (renameMode) + throw "can't find archive"; + if (options.MethodMode.Type.FormatIndex < 0) + { + if (!options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + } + else + { + if (fi.IsDir()) + return errorInfo.SetFromError_DWORD("There is a folder with the name of archive", + us2fs(arcPath), + #ifdef _WIN32 + ERROR_ACCESS_DENIED + #else + EISDIR + #endif + ); + #ifdef _WIN32 + if (fi.IsDevice) + return E_NOTIMPL; + #endif + + if (!options.StdOutMode && options.UpdateArchiveItself) + if (fi.IsReadOnly()) + { + return errorInfo.SetFromError_DWORD("The file is read-only", + us2fs(arcPath), + #ifdef _WIN32 + ERROR_ACCESS_DENIED + #else + EACCES + #endif + ); + } + + if (options.VolumesSizes.Size() > 0) + { + errorInfo.FileNames.Add(us2fs(arcPath)); + // errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = kUpdateIsNotSupported_MultiVol; + return E_NOTIMPL; + } + CObjectVector types2; + // change it. + if (options.MethodMode.Type_Defined) + types2.Add(options.MethodMode.Type); + // We need to set Properties to open archive only in some cases (WIM archives). + + CIntVector excl; + COpenOptions op; + #ifndef Z7_SFX + op.props = &options.MethodMode.Properties; + #endif + op.codecs = codecs; + op.types = &types2; + op.excludedFormats = ! + op.stdInMode = false; + op.stream = NULL; + op.filePath = arcPath; + + RINOK(callback->StartOpenArchive(arcPath)) + + HRESULT result = arcLink.Open_Strict(op, openCallback); + + if (result == E_ABORT) + return result; + + HRESULT res2 = callback->OpenResult(codecs, arcLink, arcPath, result); + /* + if (result == S_FALSE) + return E_FAIL; + */ + RINOK(res2) + RINOK(result) + + if (arcLink.VolumePaths.Size() > 1) + { + // errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = kUpdateIsNotSupported_MultiVol; + return E_NOTIMPL; + } + + CArc &arc = arcLink.Arcs.Back(); + arc.MTime.Def = + #ifdef _WIN32 + !fi.IsDevice; + #else + true; + #endif + if (arc.MTime.Def) + arc.MTime.Set_From_FiTime(fi.MTime); + + if (arc.ErrorInfo.ThereIsTail) + { + // errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = "There is some data block after the end of the archive"; + return E_NOTIMPL; + } + if (options.MethodMode.Type.FormatIndex < 0) + { + options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; + if (!options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + } + } + + if (options.MethodMode.Type.FormatIndex < 0) + { + options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType((UString)kDefaultArcType); + if (options.MethodMode.Type.FormatIndex < 0) + return E_NOTIMPL; + } + + const bool thereIsInArchive = arcLink.IsOpen; + if (!thereIsInArchive && renameMode) + return E_FAIL; + + CDirItems dirItems; + dirItems.Callback = callback; + + CDirItem parentDirItem; + CDirItem *parentDirItem_Ptr = NULL; + + /* + FStringVector requestedPaths; + FStringVector *requestedPaths_Ptr = NULL; + if (options.DeleteAfterCompressing) + requestedPaths_Ptr = &requestedPaths; + */ + + if (options.StdInMode) + { + CDirItem di; + // di.ClearBase(); + // di.Size = (UInt64)(Int64)-1; + if (!di.SetAs_StdInFile()) + return GetLastError_noZero_HRESULT(); + di.Name = options.StdInFileName; + // di.Attrib_IsDefined = false; + // NTime::GetCurUtc_FiTime(di.MTime); + // di.CTime = di.ATime = di.MTime; + dirItems.Items.Add(di); + } + else + { + bool needScanning = false; + + if (!renameMode) + FOR_VECTOR (i, options.Commands) + if (options.Commands[i].ActionSet.NeedScanning()) + needScanning = true; + + if (needScanning) + { + RINOK(callback->StartScanning()) + + dirItems.SymLinks = options.SymLinks.Val; + + #if defined(_WIN32) && !defined(UNDER_CE) + dirItems.ReadSecure = options.NtSecurity.Val; + #endif + + dirItems.ScanAltStreams = options.AltStreams.Val; + dirItems.ExcludeDirItems = censor.ExcludeDirItems; + dirItems.ExcludeFileItems = censor.ExcludeFileItems; + + dirItems.ShareForWrite = options.OpenShareForWrite; + + #ifndef _WIN32 + dirItems.StoreOwnerName = options.StoreOwnerName.Val; + #endif + + const HRESULT res = EnumerateItems(censor, + options.PathMode, + UString(), // options.AddPathPrefix, + dirItems); + + if (res != S_OK) + { + if (res != E_ABORT) + errorInfo.Message = "Scanning error"; + return res; + } + + RINOK(callback->FinishScanning(dirItems.Stat)) + + // 22.00: we don't need parent folder, if absolute path mode + if (options.PathMode != NWildcard::k_AbsPath) + if (censor.Pairs.Size() == 1) + { + NFind::CFileInfo fi; + FString prefix = us2fs(censor.Pairs[0].Prefix); + prefix.Add_Dot(); + // UString prefix = censor.Pairs[0].Prefix; + /* + if (prefix.Back() == WCHAR_PATH_SEPARATOR) + { + prefix.DeleteBack(); + } + */ + if (fi.Find(prefix)) + if (fi.IsDir()) + { + parentDirItem.Copy_From_FileInfoBase(fi); + parentDirItem_Ptr = &parentDirItem; + + int secureIndex = -1; + #if defined(_WIN32) && !defined(UNDER_CE) + if (options.NtSecurity.Val) + dirItems.AddSecurityItem(prefix, secureIndex); + #endif + parentDirItem.SecureIndex = secureIndex; + } + } + } + } + + FString tempDirPrefix; + bool usesTempDir = false; + + #ifdef _WIN32 + CTempDir tempDirectory; + if (options.EMailMode && options.EMailRemoveAfter) + { + tempDirectory.Create(kTempFolderPrefix); + tempDirPrefix = tempDirectory.GetPath(); + NormalizeDirPathPrefix(tempDirPrefix); + usesTempDir = true; + } + #endif + + CTempFiles tempFiles; + + bool createTempFile = false; + + if (!options.StdOutMode && options.UpdateArchiveItself) + { + CArchivePath &ap = options.Commands[0].ArchivePath; + ap = options.ArchivePath; + // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) + if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0) + { + createTempFile = true; + ap.Temp = true; + if (!options.WorkingDir.IsEmpty()) + ap.TempPrefix = options.WorkingDir; + else + ap.TempPrefix = us2fs(ap.Prefix); + NormalizeDirPathPrefix(ap.TempPrefix); + } + } + + unsigned ci; + + + // self including protection + if (options.DeleteAfterCompressing) + { + for (ci = 0; ci < options.Commands.Size(); ci++) + { + CArchivePath &ap = options.Commands[ci].ArchivePath; + const FString path = us2fs(ap.GetFinalPath()); + // maybe we must compare absolute paths path here + FOR_VECTOR (i, dirItems.Items) + { + const FString phyPath = dirItems.GetPhyPath(i); + if (phyPath == path) + { + UString s; + s = "It is not allowed to include archive to itself"; + s.Add_LF(); + s += fs2us(path); + throw s; + } + } + } + } + + + for (ci = 0; ci < options.Commands.Size(); ci++) + { + CArchivePath &ap = options.Commands[ci].ArchivePath; + if (usesTempDir) + { + // Check it + ap.Prefix = fs2us(tempDirPrefix); + // ap.Temp = true; + // ap.TempPrefix = tempDirPrefix; + } + if (!options.StdOutMode && + (ci > 0 || !createTempFile)) + { + const FString path = us2fs(ap.GetFinalPath()); + if (NFind::DoesFileOrDirExist(path)) + { + errorInfo.SystemError = ERROR_FILE_EXISTS; + errorInfo.Message = "The file already exists"; + errorInfo.FileNames.Add(path); + return errorInfo.Get_HRESULT_Error(); + } + } + } + + CObjectVector arcItems; + if (thereIsInArchive) + { + RINOK(EnumerateInArchiveItems( + // options.StoreAltStreams, + censor, arcLink.Arcs.Back(), arcItems)) + } + + /* + FStringVector processedFilePaths; + FStringVector *processedFilePaths_Ptr = NULL; + if (options.DeleteAfterCompressing) + processedFilePaths_Ptr = &processedFilePaths; + */ + + CByteBuffer processedItems; + if (options.DeleteAfterCompressing) + { + const unsigned num = dirItems.Items.Size(); + processedItems.Alloc(num); + for (unsigned i = 0; i < num; i++) + processedItems[i] = 0; + } + + CMultiOutStream_Bunch multiStreams; + + /* + #ifndef Z7_NO_CRYPTO + if (arcLink.PasswordWasAsked) + { + // We set password, if open have requested password + RINOK(callback->SetPassword(arcLink.Password)); + } + #endif + */ + + for (ci = 0; ci < options.Commands.Size(); ci++) + { + const CArc *arc = thereIsInArchive ? arcLink.GetArc() : NULL; + CUpdateArchiveCommand &command = options.Commands[ci]; + UString name; + bool isUpdating; + + if (options.StdOutMode) + { + name = "stdout"; + isUpdating = thereIsInArchive; + } + else + { + name = command.ArchivePath.GetFinalPath(); + isUpdating = (ci == 0 && options.UpdateArchiveItself && thereIsInArchive); + } + + RINOK(callback->StartArchive(name, isUpdating)) + + CFinishArchiveStat st; + + RINOK(Compress(options, + isUpdating, + codecs, + command.ActionSet, + arc, + command.ArchivePath, + arcItems, + options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, + + dirItems, + parentDirItem_Ptr, + + tempFiles, + multiStreams, + errorInfo, callback, st)) + + RINOK(callback->FinishArchive(st)) + } + + + if (thereIsInArchive) + { + RINOK(arcLink.Close()) + arcLink.Release(); + } + + multiStreams.DisableDeletion(); + RINOK(multiStreams.Destruct()) + + // here we disable deleting of temp archives. + // note: archive moving can fail, or it can be interrupted, + // if we move new temp update from another volume. + // And we still want to keep temp archive in that case, + // because we will have deleted original archive. + tempFiles.NeedDeleteFiles = false; + // tempFiles.Paths.Clear(); + + if (createTempFile) + { + try + { + CArchivePath &ap = options.Commands[0].ArchivePath; + const FString &tempPath = ap.GetTempPath(); + + // DWORD attrib = 0; + if (thereIsInArchive) + { + // attrib = NFind::GetFileAttrib(us2fs(arcPath)); + if (!DeleteFileAlways(us2fs(arcPath))) + return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); + } + + UInt64 totalArcSize = 0; + { + NFind::CFileInfo fi; + if (fi.Find(tempPath)) + totalArcSize = fi.Size; + } + RINOK(callback->MoveArc_Start(fs2us(tempPath), arcPath, + totalArcSize, BoolToInt(thereIsInArchive))) + + C_CopyFileProgress_to_IUpdateCallbackUI2 prox(callback); + // if we update archive, we have removed original archive. + // So if we break archive moving, we will have only temporary archive. + // We can disable breaking here: + // prox.Disable_Break = thereIsInArchive; + + if (!MyMoveFile_with_Progress(tempPath, us2fs(arcPath), &prox)) + { + errorInfo.SystemError = ::GetLastError(); + errorInfo.Message = "cannot move the file"; + if (errorInfo.SystemError == ERROR_INVALID_PARAMETER) + { + if (totalArcSize > (UInt32)(Int32)-1) + { + // bool isFsDetected = false; + // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected) + { + errorInfo.Message.Add_LF(); + errorInfo.Message += "Archive file size exceeds 4 GB"; + } + } + } + // if there was no input archive, and we have operation breaking. + // then we can remove temporary archive, because we still have original uncompressed files. + if (!thereIsInArchive + && prox.CallbackResult == E_ABORT) + tempFiles.NeedDeleteFiles = true; + errorInfo.FileNames.Add(tempPath); + errorInfo.FileNames.Add(us2fs(arcPath)); + RINOK(prox.CallbackResult) + return errorInfo.Get_HRESULT_Error(); + } + + // MoveArc_Finish() can return delayed user break (E_ABORT) status, + // if callback callee ignored interruption to finish archive creation operation. + RINOK(callback->MoveArc_Finish()) + + /* + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) + { + DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath)); + if (attrib2 != INVALID_FILE_ATTRIBUTES) + NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY); + } + */ + } + catch(...) + { + throw; + } + } + + + #if defined(_WIN32) && !defined(UNDER_CE) + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + + if (options.EMailMode) + { + NDLL::CLibrary mapiLib; + if (!mapiLib.Load(FTEXT("Mapi32.dll"))) + { + errorInfo.SetFromLastError("cannot load Mapi32.dll"); + return errorInfo.Get_HRESULT_Error(); + } + + FStringVector fullPaths; + unsigned i; + + for (i = 0; i < options.Commands.Size(); i++) + { + CArchivePath &ap = options.Commands[i].ArchivePath; + const FString finalPath = us2fs(ap.GetFinalPath()); + FString arcPath2; + if (!MyGetFullPathName(finalPath, arcPath2)) + return errorInfo.SetFromLastError("GetFullPathName error", finalPath); + fullPaths.Add(arcPath2); + } + + /* + LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); + if (fnSend == 0) + { + errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function"); + return errorInfo.Get_HRESULT_Error(); + } + */ + const + Z7_WIN_LPMAPISENDMAILW sendMailW = Z7_GET_PROC_ADDRESS( + Z7_WIN_LPMAPISENDMAILW, mapiLib.Get_HMODULE(), + "MAPISendMailW"); + if (sendMailW) + { + + CCurrentDirRestorer curDirRestorer; + + UStringVector paths; + UStringVector names; + + for (i = 0; i < fullPaths.Size(); i++) + { + const UString arcPath2 = fs2us(fullPaths[i]); + const UString fileName = ExtractFileNameFromPath(arcPath2); + paths.Add(arcPath2); + names.Add(fileName); + // Warning!!! MAPISendDocuments function changes Current directory + // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); + } + + CRecordVector files; + files.ClearAndSetSize(paths.Size()); + + for (i = 0; i < paths.Size(); i++) + { + Z7_WIN_MapiFileDescW &f = files[i]; + memset(&f, 0, sizeof(f)); + f.nPosition = 0xFFFFFFFF; + f.lpszPathName = paths[i].Ptr_non_const(); + f.lpszFileName = names[i].Ptr_non_const(); + } + + { + Z7_WIN_MapiMessageW m; + memset(&m, 0, sizeof(m)); + m.nFileCount = files.Size(); + m.lpFiles = files.NonConstData(); + + const UString addr (options.EMailAddress); + Z7_WIN_MapiRecipDescW rec; + if (!addr.IsEmpty()) + { + memset(&rec, 0, sizeof(rec)); + rec.ulRecipClass = MAPI_TO; + rec.lpszAddress = addr.Ptr_non_const(); + m.nRecipCount = 1; + m.lpRecips = &rec; + } + + sendMailW((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); + } + } + else + { + const + LPMAPISENDMAIL sendMail = Z7_GET_PROC_ADDRESS( + LPMAPISENDMAIL, mapiLib.Get_HMODULE(), + "MAPISendMail"); + if (!sendMail) + { + errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function"); + return errorInfo.Get_HRESULT_Error(); + } + + CCurrentDirRestorer curDirRestorer; + + AStringVector paths; + AStringVector names; + + for (i = 0; i < fullPaths.Size(); i++) + { + const UString arcPath2 = fs2us(fullPaths[i]); + const UString fileName = ExtractFileNameFromPath(arcPath2); + paths.Add(GetAnsiString(arcPath2)); + names.Add(GetAnsiString(fileName)); + // const AString path (GetAnsiString(arcPath2)); + // const AString name (GetAnsiString(fileName)); + // Warning!!! MAPISendDocuments function changes Current directory + // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); + } + + CRecordVector files; + files.ClearAndSetSize(paths.Size()); + + for (i = 0; i < paths.Size(); i++) + { + MapiFileDesc &f = files[i]; + memset(&f, 0, sizeof(f)); + f.nPosition = 0xFFFFFFFF; + f.lpszPathName = paths[i].Ptr_non_const(); + f.lpszFileName = names[i].Ptr_non_const(); + } + + { + MapiMessage m; + memset(&m, 0, sizeof(m)); + m.nFileCount = files.Size(); + m.lpFiles = files.NonConstData(); + + const AString addr (GetAnsiString(options.EMailAddress)); + MapiRecipDesc rec; + if (!addr.IsEmpty()) + { + memset(&rec, 0, sizeof(rec)); + rec.ulRecipClass = MAPI_TO; + rec.lpszAddress = addr.Ptr_non_const(); + m.nRecipCount = 1; + m.lpRecips = &rec; + } + + sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); + } + } + } + + #endif + + if (options.DeleteAfterCompressing) + { + CRecordVector pairs; + FStringVector foldersNames; + + unsigned i; + + for (i = 0; i < dirItems.Items.Size(); i++) + { + const CDirItem &dirItem = dirItems.Items[i]; + const FString phyPath = dirItems.GetPhyPath(i); + if (dirItem.IsDir()) + { + CDirPathSortPair pair; + pair.Index = i; + pair.SetNumSlashes(phyPath); + pairs.Add(pair); + } + else + { + // 21.04: we have set processedItems[*] before for all required items + if (processedItems[i] != 0 + // || dirItem.Size == 0 + // || dirItem.AreReparseData() + ) + { + NFind::CFileInfo fileInfo; + /* if (!SymLinks), we follow link here, similar to (dirItem) filling */ + if (fileInfo.Find(phyPath, !options.SymLinks.Val)) + { + bool is_SameSize = false; + if (options.SymLinks.Val && dirItem.AreReparseData()) + { + /* (dirItem.Size = dirItem.ReparseData.Size()) was set before. + So we don't compare sizes for that case here */ + is_SameSize = fileInfo.IsOsSymLink(); + } + else + is_SameSize = (fileInfo.Size == dirItem.Size); + + if (is_SameSize + && Compare_FiTime(&fileInfo.MTime, &dirItem.MTime) == 0 + && Compare_FiTime(&fileInfo.CTime, &dirItem.CTime) == 0) + { + RINOK(callback->DeletingAfterArchiving(phyPath, false)) + DeleteFileAlways(phyPath); + } + } + } + else + { + // file was skipped by some reason. We can throw error for debug: + /* + errorInfo.SystemError = 0; + errorInfo.Message = "file was not processed"; + errorInfo.FileNames.Add(phyPath); + return E_FAIL; + */ + } + } + } + + pairs.Sort2(); + + for (i = 0; i < pairs.Size(); i++) + { + const FString phyPath = dirItems.GetPhyPath(pairs[i].Index); + if (NFind::DoesDirExist(phyPath)) + { + RINOK(callback->DeletingAfterArchiving(phyPath, true)) + RemoveDir(phyPath); + } + } + + RINOK(callback->FinishDeletingAfterArchiving()) + } + + return S_OK; +} diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h index 3460217e2..216339aa3 100644 --- a/CPP/7zip/UI/Common/Update.h +++ b/CPP/7zip/UI/Common/Update.h @@ -1,218 +1,219 @@ -// Update.h - -#ifndef ZIP7_INC_COMMON_UPDATE_H -#define ZIP7_INC_COMMON_UPDATE_H - -#include "../../../Common/Wildcard.h" - -#include "ArchiveOpenCallback.h" -#include "LoadCodecs.h" -#include "OpenArchive.h" -#include "Property.h" -#include "UpdateAction.h" -#include "UpdateCallback.h" - -#include "DirItem.h" - -enum EArcNameMode -{ - k_ArcNameMode_Smart, - k_ArcNameMode_Exact, - k_ArcNameMode_Add -}; - -struct CArchivePath -{ - UString OriginalPath; - - UString Prefix; // path(folder) prefix including slash - UString Name; // base name - UString BaseExtension; // archive type extension or "exe" extension - UString VolExtension; // archive type extension for volumes - - bool Temp; - FString TempPrefix; // path(folder) for temp location - FString TempPostfix; - - CArchivePath(): Temp(false) {} - - void ParseFromPath(const UString &path, EArcNameMode mode); - UString GetPathWithoutExt() const { return Prefix + Name; } - UString GetFinalPath() const; - UString GetFinalVolPath() const; - FString GetTempPath() const; -}; - -struct CUpdateArchiveCommand -{ - UString UserArchivePath; - CArchivePath ArchivePath; - NUpdateArchive::CActionSet ActionSet; -}; - -struct CCompressionMethodMode -{ - bool Type_Defined; - COpenType Type; - CObjectVector Properties; - - CCompressionMethodMode(): Type_Defined(false) {} -}; - -namespace NRecursedType { enum EEnum -{ - kRecursed, - kWildcardOnlyRecursed, - kNonRecursed -};} - -struct CRenamePair -{ - UString OldName; - UString NewName; - bool WildcardParsing; - NRecursedType::EEnum RecursedType; - - CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {} - - bool Prepare(); - bool GetNewPath(bool isFolder, const UString &src, UString &dest) const; -}; - -struct CUpdateOptions -{ - bool UpdateArchiveItself; - bool SfxMode; - - bool PreserveATime; - bool OpenShareForWrite; - bool StopAfterOpenError; - - bool StdInMode; - bool StdOutMode; - - bool EMailMode; - bool EMailRemoveAfter; - - bool DeleteAfterCompressing; - bool SetArcMTime; - - CBoolPair NtSecurity; - CBoolPair AltStreams; - CBoolPair HardLinks; - CBoolPair SymLinks; - - CBoolPair StoreOwnerId; - CBoolPair StoreOwnerName; - - EArcNameMode ArcNameMode; - NWildcard::ECensorPathMode PathMode; - - CCompressionMethodMode MethodMode; - - CObjectVector Commands; - CArchivePath ArchivePath; - - FString SfxModule; - UString StdInFileName; - UString EMailAddress; - FString WorkingDir; - // UString AddPathPrefix; - - CObjectVector RenamePairs; - CRecordVector VolumesSizes; - - bool InitFormatIndex(const CCodecs *codecs, const CObjectVector &types, const UString &arcPath); - bool SetArcPath(const CCodecs *codecs, const UString &arcPath); - - CUpdateOptions(): - UpdateArchiveItself(true), - SfxMode(false), - - PreserveATime(false), - OpenShareForWrite(false), - StopAfterOpenError(false), - - StdInMode(false), - StdOutMode(false), - - EMailMode(false), - EMailRemoveAfter(false), - - DeleteAfterCompressing(false), - SetArcMTime(false), - - ArcNameMode(k_ArcNameMode_Smart), - PathMode(NWildcard::k_RelatPath) - - {} - - void SetActionCommand_Add() - { - Commands.Clear(); - CUpdateArchiveCommand c; - c.ActionSet = NUpdateArchive::k_ActionSet_Add; - Commands.Add(c); - } -}; - - -struct CUpdateErrorInfo -{ - DWORD SystemError; // it's DWORD (WRes) only; - AString Message; - FStringVector FileNames; - - bool ThereIsError() const { return SystemError != 0 || !Message.IsEmpty() || !FileNames.IsEmpty(); } - HRESULT Get_HRESULT_Error() const { return SystemError == 0 ? E_FAIL : HRESULT_FROM_WIN32(SystemError); } - void SetFromLastError(const char *message); - HRESULT SetFromLastError(const char *message, const FString &fileName); - HRESULT SetFromError_DWORD(const char *message, const FString &fileName, DWORD error); - - CUpdateErrorInfo(): SystemError(0) {} -}; - -struct CFinishArchiveStat -{ - UInt64 OutArcFileSize; - unsigned NumVolumes; - bool IsMultiVolMode; - - CFinishArchiveStat(): OutArcFileSize(0), NumVolumes(0), IsMultiVolMode(false) {} -}; - -Z7_PURE_INTERFACES_BEGIN - -// INTERFACE_IUpdateCallbackUI(x) -// INTERFACE_IDirItemsCallback(x) - -#define Z7_IFACEN_IUpdateCallbackUI2(x) \ - virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x \ - virtual HRESULT StartScanning() x \ - virtual HRESULT FinishScanning(const CDirItemsStat &st) x \ - virtual HRESULT StartOpenArchive(const wchar_t *name) x \ - virtual HRESULT StartArchive(const wchar_t *name, bool updating) x \ - virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \ - virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \ - virtual HRESULT FinishDeletingAfterArchiving() x \ - -DECLARE_INTERFACE(IUpdateCallbackUI2): - public IUpdateCallbackUI, - public IDirItemsCallback -{ - Z7_IFACE_PURE(IUpdateCallbackUI2) -}; -Z7_PURE_INTERFACES_END - -HRESULT UpdateArchive( - CCodecs *codecs, - const CObjectVector &types, - const UString &cmdArcPath2, - NWildcard::CCensor &censor, - CUpdateOptions &options, - CUpdateErrorInfo &errorInfo, - IOpenCallbackUI *openCallback, - IUpdateCallbackUI2 *callback, - bool needSetPath); - -#endif +// Update.h + +#ifndef ZIP7_INC_COMMON_UPDATE_H +#define ZIP7_INC_COMMON_UPDATE_H + +#include "../../../Common/Wildcard.h" + +#include "ArchiveOpenCallback.h" +#include "LoadCodecs.h" +#include "OpenArchive.h" +#include "Property.h" +#include "UpdateAction.h" +#include "UpdateCallback.h" + +enum EArcNameMode +{ + k_ArcNameMode_Smart, + k_ArcNameMode_Exact, + k_ArcNameMode_Add +}; + +struct CArchivePath +{ + UString OriginalPath; + + UString Prefix; // path(folder) prefix including slash + UString Name; // base name + UString BaseExtension; // archive type extension or "exe" extension + UString VolExtension; // archive type extension for volumes + + bool Temp; + FString TempPrefix; // path(folder) for temp location + FString TempPostfix; + + CArchivePath(): Temp(false) {} + + void ParseFromPath(const UString &path, EArcNameMode mode); + UString GetPathWithoutExt() const { return Prefix + Name; } + UString GetFinalPath() const; + UString GetFinalVolPath() const; + FString GetTempPath() const; +}; + +struct CUpdateArchiveCommand +{ + UString UserArchivePath; + CArchivePath ArchivePath; + NUpdateArchive::CActionSet ActionSet; +}; + +struct CCompressionMethodMode +{ + bool Type_Defined; + COpenType Type; + CObjectVector Properties; + + CCompressionMethodMode(): Type_Defined(false) {} +}; + +namespace NRecursedType { enum EEnum +{ + kRecursed, + kWildcardOnlyRecursed, + kNonRecursed +};} + +struct CRenamePair +{ + UString OldName; + UString NewName; + bool WildcardParsing; + NRecursedType::EEnum RecursedType; + + CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {} + + bool Prepare(); + bool GetNewPath(bool isFolder, const UString &src, UString &dest) const; +}; + +struct CUpdateOptions +{ + bool UpdateArchiveItself; + bool SfxMode; + + bool PreserveATime; + bool OpenShareForWrite; + bool StopAfterOpenError; + + bool StdInMode; + bool StdOutMode; + + bool EMailMode; + bool EMailRemoveAfter; + + bool DeleteAfterCompressing; + bool SetArcMTime; + + CBoolPair NtSecurity; + CBoolPair AltStreams; + CBoolPair HardLinks; + CBoolPair SymLinks; + + CBoolPair StoreOwnerId; + CBoolPair StoreOwnerName; + + EArcNameMode ArcNameMode; + NWildcard::ECensorPathMode PathMode; + + CCompressionMethodMode MethodMode; + + CObjectVector Commands; + CArchivePath ArchivePath; + + FString SfxModule; + UString StdInFileName; + UString EMailAddress; + FString WorkingDir; + // UString AddPathPrefix; + + CObjectVector RenamePairs; + CRecordVector VolumesSizes; + + bool InitFormatIndex(const CCodecs *codecs, const CObjectVector &types, const UString &arcPath); + bool SetArcPath(const CCodecs *codecs, const UString &arcPath); + + CUpdateOptions(): + UpdateArchiveItself(true), + SfxMode(false), + + PreserveATime(false), + OpenShareForWrite(false), + StopAfterOpenError(false), + + StdInMode(false), + StdOutMode(false), + + EMailMode(false), + EMailRemoveAfter(false), + + DeleteAfterCompressing(false), + SetArcMTime(false), + + ArcNameMode(k_ArcNameMode_Smart), + PathMode(NWildcard::k_RelatPath) + + {} + + void SetActionCommand_Add() + { + Commands.Clear(); + CUpdateArchiveCommand c; + c.ActionSet = NUpdateArchive::k_ActionSet_Add; + Commands.Add(c); + } +}; + + +struct CUpdateErrorInfo +{ + DWORD SystemError; // it's DWORD (WRes) only; + AString Message; + FStringVector FileNames; + + bool ThereIsError() const { return SystemError != 0 || !Message.IsEmpty() || !FileNames.IsEmpty(); } + HRESULT Get_HRESULT_Error() const { return SystemError == 0 ? E_FAIL : HRESULT_FROM_WIN32(SystemError); } + void SetFromLastError(const char *message); + HRESULT SetFromLastError(const char *message, const FString &fileName); + HRESULT SetFromError_DWORD(const char *message, const FString &fileName, DWORD error); + + CUpdateErrorInfo(): SystemError(0) {} +}; + +struct CFinishArchiveStat +{ + UInt64 OutArcFileSize; + unsigned NumVolumes; + bool IsMultiVolMode; + + CFinishArchiveStat(): OutArcFileSize(0), NumVolumes(0), IsMultiVolMode(false) {} +}; + +Z7_PURE_INTERFACES_BEGIN + +// INTERFACE_IUpdateCallbackUI(x) +// INTERFACE_IDirItemsCallback(x) + +#define Z7_IFACEN_IUpdateCallbackUI2(x) \ + virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x \ + virtual HRESULT StartScanning() x \ + virtual HRESULT FinishScanning(const CDirItemsStat &st) x \ + virtual HRESULT StartOpenArchive(const wchar_t *name) x \ + virtual HRESULT StartArchive(const wchar_t *name, bool updating) x \ + virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \ + virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \ + virtual HRESULT FinishDeletingAfterArchiving() x \ + virtual HRESULT MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode) x \ + virtual HRESULT MoveArc_Progress(UInt64 total, UInt64 current) x \ + virtual HRESULT MoveArc_Finish() x \ + +DECLARE_INTERFACE(IUpdateCallbackUI2): + public IUpdateCallbackUI, + public IDirItemsCallback +{ + Z7_IFACE_PURE(IUpdateCallbackUI2) +}; +Z7_PURE_INTERFACES_END + +HRESULT UpdateArchive( + CCodecs *codecs, + const CObjectVector &types, + const UString &cmdArcPath2, + NWildcard::CCensor &censor, + CUpdateOptions &options, + CUpdateErrorInfo &errorInfo, + IOpenCallbackUI *openCallback, + IUpdateCallbackUI2 *callback, + bool needSetPath); + +#endif diff --git a/CPP/7zip/UI/Common/UpdateAction.cpp b/CPP/7zip/UI/Common/UpdateAction.cpp index ba138d201..a80db7212 100644 --- a/CPP/7zip/UI/Common/UpdateAction.cpp +++ b/CPP/7zip/UI/Common/UpdateAction.cpp @@ -1,64 +1,64 @@ -// UpdateAction.cpp - -#include "StdAfx.h" - -#include "UpdateAction.h" - -namespace NUpdateArchive { - -const CActionSet k_ActionSet_Add = -{{ - NPairAction::kCopy, - NPairAction::kCopy, - NPairAction::kCompress, - NPairAction::kCompress, - NPairAction::kCompress, - NPairAction::kCompress, - NPairAction::kCompress -}}; - -const CActionSet k_ActionSet_Update = -{{ - NPairAction::kCopy, - NPairAction::kCopy, - NPairAction::kCompress, - NPairAction::kCopy, - NPairAction::kCompress, - NPairAction::kCopy, - NPairAction::kCompress -}}; - -const CActionSet k_ActionSet_Fresh = -{{ - NPairAction::kCopy, - NPairAction::kCopy, - NPairAction::kIgnore, - NPairAction::kCopy, - NPairAction::kCompress, - NPairAction::kCopy, - NPairAction::kCompress -}}; - -const CActionSet k_ActionSet_Sync = -{{ - NPairAction::kCopy, - NPairAction::kIgnore, - NPairAction::kCompress, - NPairAction::kCopy, - NPairAction::kCompress, - NPairAction::kCopy, - NPairAction::kCompress, -}}; - -const CActionSet k_ActionSet_Delete = -{{ - NPairAction::kCopy, - NPairAction::kIgnore, - NPairAction::kIgnore, - NPairAction::kIgnore, - NPairAction::kIgnore, - NPairAction::kIgnore, - NPairAction::kIgnore -}}; - -} +// UpdateAction.cpp + +#include "StdAfx.h" + +#include "UpdateAction.h" + +namespace NUpdateArchive { + +const CActionSet k_ActionSet_Add = +{{ + NPairAction::kCopy, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCompress, + NPairAction::kCompress, + NPairAction::kCompress, + NPairAction::kCompress +}}; + +const CActionSet k_ActionSet_Update = +{{ + NPairAction::kCopy, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress +}}; + +const CActionSet k_ActionSet_Fresh = +{{ + NPairAction::kCopy, + NPairAction::kCopy, + NPairAction::kIgnore, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress +}}; + +const CActionSet k_ActionSet_Sync = +{{ + NPairAction::kCopy, + NPairAction::kIgnore, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress, + NPairAction::kCopy, + NPairAction::kCompress, +}}; + +const CActionSet k_ActionSet_Delete = +{{ + NPairAction::kCopy, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore, + NPairAction::kIgnore +}}; + +} diff --git a/CPP/7zip/UI/Common/UpdateAction.h b/CPP/7zip/UI/Common/UpdateAction.h index b8a7e6f36..6a3565e79 100644 --- a/CPP/7zip/UI/Common/UpdateAction.h +++ b/CPP/7zip/UI/Common/UpdateAction.h @@ -1,66 +1,66 @@ -// UpdateAction.h - -#ifndef ZIP7_INC_UPDATE_ACTION_H -#define ZIP7_INC_UPDATE_ACTION_H - -namespace NUpdateArchive { - - namespace NPairState - { - const unsigned kNumValues = 7; - enum EEnum - { - kNotMasked = 0, - kOnlyInArchive, - kOnlyOnDisk, - kNewInArchive, - kOldInArchive, - kSameFiles, - kUnknowNewerFiles - }; - } - - namespace NPairAction - { - enum EEnum - { - kIgnore = 0, - kCopy, - kCompress, - kCompressAsAnti - }; - } - - struct CActionSet - { - NPairAction::EEnum StateActions[NPairState::kNumValues]; - - bool IsEqualTo(const CActionSet &a) const - { - for (unsigned i = 0; i < NPairState::kNumValues; i++) - if (StateActions[i] != a.StateActions[i]) - return false; - return true; - } - - bool NeedScanning() const - { - unsigned i; - for (i = 0; i < NPairState::kNumValues; i++) - if (StateActions[i] == NPairAction::kCompress) - return true; - for (i = 1; i < NPairState::kNumValues; i++) - if (StateActions[i] != NPairAction::kIgnore) - return true; - return false; - } - }; - - extern const CActionSet k_ActionSet_Add; - extern const CActionSet k_ActionSet_Update; - extern const CActionSet k_ActionSet_Fresh; - extern const CActionSet k_ActionSet_Sync; - extern const CActionSet k_ActionSet_Delete; -} - -#endif +// UpdateAction.h + +#ifndef ZIP7_INC_UPDATE_ACTION_H +#define ZIP7_INC_UPDATE_ACTION_H + +namespace NUpdateArchive { + + namespace NPairState + { + const unsigned kNumValues = 7; + enum EEnum + { + kNotMasked = 0, + kOnlyInArchive, + kOnlyOnDisk, + kNewInArchive, + kOldInArchive, + kSameFiles, + kUnknowNewerFiles + }; + } + + namespace NPairAction + { + enum EEnum + { + kIgnore = 0, + kCopy, + kCompress, + kCompressAsAnti + }; + } + + struct CActionSet + { + NPairAction::EEnum StateActions[NPairState::kNumValues]; + + bool IsEqualTo(const CActionSet &a) const + { + for (unsigned i = 0; i < NPairState::kNumValues; i++) + if (StateActions[i] != a.StateActions[i]) + return false; + return true; + } + + bool NeedScanning() const + { + unsigned i; + for (i = 0; i < NPairState::kNumValues; i++) + if (StateActions[i] == NPairAction::kCompress) + return true; + for (i = 1; i < NPairState::kNumValues; i++) + if (StateActions[i] != NPairAction::kIgnore) + return true; + return false; + } + }; + + extern const CActionSet k_ActionSet_Add; + extern const CActionSet k_ActionSet_Update; + extern const CActionSet k_ActionSet_Fresh; + extern const CActionSet k_ActionSet_Sync; + extern const CActionSet k_ActionSet_Delete; +} + +#endif diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index 0313756d2..d3ee639b5 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -1,1029 +1,1029 @@ -// UpdateCallback.cpp - -#include "StdAfx.h" - -// #include - -#ifndef _WIN32 -// #include -// #include -// for major()/minor(): -#if defined(__APPLE__) || defined(__DragonFly__) || \ - defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#else -#include -#endif - -#endif // _WIN32 - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "../../Common/StreamObjects.h" - -#include "UpdateCallback.h" - -#if defined(_WIN32) && !defined(UNDER_CE) -#define Z7_USE_SECURITY_CODE -#include "../../../Windows/SecurityUtils.h" -#endif - -using namespace NWindows; -using namespace NFile; - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - - -#ifdef Z7_USE_SECURITY_CODE -bool InitLocalPrivileges(); -#endif - -CArchiveUpdateCallback::CArchiveUpdateCallback(): - PreserveATime(false), - ShareForWrite(false), - StopAfterOpenError(false), - StdInMode(false), - - KeepOriginalItemNames(false), - StoreNtSecurity(false), - StoreHardLinks(false), - StoreSymLinks(false), - - #ifndef _WIN32 - StoreOwnerId(false), - StoreOwnerName(false), - #endif - - /* - , Need_ArcMTime_Report(false), - , ArcMTime_WasReported(false), - */ - Need_LatestMTime(false), - LatestMTime_Defined(false), - - Callback(NULL), - - DirItems(NULL), - ParentDirItem(NULL), - - Arc(NULL), - ArcItems(NULL), - UpdatePairs(NULL), - NewNames(NULL), - Comment(NULL), - CommentIndex(-1), - - ProcessedItemsStatuses(NULL), - _hardIndex_From((UInt32)(Int32)-1) -{ - #ifdef Z7_USE_SECURITY_CODE - _saclEnabled = InitLocalPrivileges(); - #endif -} - - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 size)) -{ - COM_TRY_BEGIN - return Callback->SetTotal(size); - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)) -{ - COM_TRY_BEGIN - return Callback->SetCompleted(completeValue); - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - COM_TRY_BEGIN - return Callback->SetRatioInfo(inSize, outSize); - COM_TRY_END -} - - -/* -static const CStatProp kProps[] = -{ - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsDir, VT_BOOL}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidCTime, VT_FILETIME}, - { NULL, kpidATime, VT_FILETIME}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidIsAnti, VT_BOOL} -}; - -Z7_COM7F_IMF(CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) -{ - return CStatPropEnumerator::CreateEnumerator(kProps, Z7_ARRAY_SIZE(kProps), enumerator); -} -*/ - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, - Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) -{ - COM_TRY_BEGIN - RINOK(Callback->CheckBreak()) - const CUpdatePair2 &up = (*UpdatePairs)[index]; - if (newData) *newData = BoolToInt(up.NewData); - if (newProps) *newProps = BoolToInt(up.NewProps); - if (indexInArchive) - { - *indexInArchive = (UInt32)(Int32)-1; - if (up.ExistInArchive()) - *indexInArchive = ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex; - } - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidIsDir: prop = true; break; - case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break; - case kpidCTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break; - case kpidATime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break; - case kpidMTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break; - case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break; - default: break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)) -{ - *parentType = NParentType::kDir; - *parent = (UInt32)(Int32)-1; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = 0; - if (StoreNtSecurity) - *numProps = 1; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) -{ - *name = NULL; - *propID = kpidNtSecure; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootRawProp(PROPID - propID - , const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - #ifndef Z7_USE_SECURITY_CODE - UNUSED_VAR(propID) - #endif - - *data = NULL; - *dataSize = 0; - *propType = 0; - if (!StoreNtSecurity) - return S_OK; - #ifdef Z7_USE_SECURITY_CODE - if (propID == kpidNtSecure) - { - if (StdInMode) - return S_OK; - - if (ParentDirItem) - { - if (ParentDirItem->SecureIndex < 0) - return S_OK; - const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)ParentDirItem->SecureIndex]; - *data = buf; - *dataSize = (UInt32)buf.Size(); - *propType = NPropDataType::kRaw; - return S_OK; - } - - if (Arc && Arc->GetRootProps) - return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType); - } - #endif - return S_OK; -} - - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - *data = NULL; - *dataSize = 0; - *propType = 0; - - if (propID == kpidNtSecure || - propID == kpidNtReparse) - { - if (StdInMode) - return S_OK; - - const CUpdatePair2 &up = (*UpdatePairs)[index]; - if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps) - return Arc->GetRawProps->GetRawProp( - ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, - propID, data, dataSize, propType); - { - /* - if (!up.NewData) - return E_FAIL; - */ - if (up.IsAnti) - return S_OK; - - #if defined(_WIN32) && !defined(UNDER_CE) - const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; - #endif - - #ifdef Z7_USE_SECURITY_CODE - if (propID == kpidNtSecure) - { - if (!StoreNtSecurity) - return S_OK; - if (di.SecureIndex < 0) - return S_OK; - const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)di.SecureIndex]; - *data = buf; - *dataSize = (UInt32)buf.Size(); - *propType = NPropDataType::kRaw; - } - else - #endif - if (propID == kpidNtReparse) - { - if (!StoreSymLinks) - return S_OK; - #if defined(_WIN32) && !defined(UNDER_CE) - // we use ReparseData2 instead of ReparseData for WIM format - const CByteBuffer *buf = &di.ReparseData2; - if (buf->Size() == 0) - buf = &di.ReparseData; - if (buf->Size() != 0) - { - *data = *buf; - *dataSize = (UInt32)buf->Size(); - *propType = NPropDataType::kRaw; - } - #endif - } - - return S_OK; - } - } - - return S_OK; -} - -#if defined(_WIN32) && !defined(UNDER_CE) - -static UString GetRelativePath(const UString &to, const UString &from) -{ - UStringVector partsTo, partsFrom; - SplitPathToParts(to, partsTo); - SplitPathToParts(from, partsFrom); - - unsigned i; - for (i = 0;; i++) - { - if (i + 1 >= partsFrom.Size() || - i + 1 >= partsTo.Size()) - break; - if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) - break; - } - - if (i == 0) - { - #ifdef _WIN32 - if (NName::IsDrivePath(to) || - NName::IsDrivePath(from)) - return to; - #endif - } - - UString s; - unsigned k; - - for (k = i + 1; k < partsFrom.Size(); k++) - s += ".." STRING_PATH_SEPARATOR; - - for (k = i; k < partsTo.Size(); k++) - { - if (k != i) - s.Add_PathSepar(); - s += partsTo[k]; - } - - return s; -} - -#endif - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - const CUpdatePair2 &up = (*UpdatePairs)[index]; - NCOM::CPropVariant prop; - - if (up.NewData) - { - /* - if (propID == kpidIsHardLink) - { - prop = _isHardLink; - prop.Detach(value); - return S_OK; - } - */ - if (propID == kpidSymLink) - { - if (index == _hardIndex_From) - { - prop.Detach(value); - return S_OK; - } - - #if !defined(UNDER_CE) - - if (up.DirIndex >= 0) - { - const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; - - #ifdef _WIN32 - // if (di.IsDir()) - { - CReparseAttr attr; - if (attr.Parse(di.ReparseData, di.ReparseData.Size())) - { - const UString simpleName = attr.GetPath(); - if (!attr.IsSymLink_WSL() && attr.IsRelative_Win()) - prop = simpleName; - else - { - const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); - FString fullPath; - if (NDir::MyGetFullPathName(phyPath, fullPath)) - { - prop = GetRelativePath(simpleName, fs2us(fullPath)); - } - } - prop.Detach(value); - return S_OK; - } - } - - #else // _WIN32 - - if (di.ReparseData.Size() != 0) - { - AString utf; - utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); - - UString us; - if (ConvertUTF8ToUnicode(utf, us)) - { - prop = us; - prop.Detach(value); - return S_OK; - } - } - - #endif // _WIN32 - } - #endif // !defined(UNDER_CE) - } - else if (propID == kpidHardLink) - { - if (index == _hardIndex_From) - { - const CKeyKeyValPair &pair = _map[_hardIndex_To]; - const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; - prop = DirItems->GetLogPath((unsigned)up2.DirIndex); - prop.Detach(value); - return S_OK; - } - if (up.DirIndex >= 0) - { - prop.Detach(value); - return S_OK; - } - } - } - - if (up.IsAnti - && propID != kpidIsDir - && propID != kpidPath - && propID != kpidIsAltStream) - { - switch (propID) - { - case kpidSize: prop = (UInt64)0; break; - case kpidIsAnti: prop = true; break; - default: break; - } - } - else if (propID == kpidPath && up.NewNameIndex >= 0) - prop = (*NewNames)[(unsigned)up.NewNameIndex]; - else if (propID == kpidComment - && CommentIndex >= 0 - && (unsigned)CommentIndex == index - && Comment) - prop = *Comment; - else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) - { - // we can generate new ShortName here; - } - else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) - && up.ExistInArchive() && Archive) - return Archive->GetProperty(ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, propID, value); - else if (up.ExistOnDisk()) - { - const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; - switch (propID) - { - case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break; - case kpidIsDir: prop = di.IsDir(); break; - case kpidSize: prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break; - case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; - case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; - case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; - case kpidAttrib: /* if (di.Attrib_IsDefined) */ prop = (UInt32)di.GetWinAttrib(); break; - case kpidPosixAttrib: /* if (di.Attrib_IsDefined) */ prop = (UInt32)di.GetPosixAttrib(); break; - - #if defined(_WIN32) - case kpidIsAltStream: prop = di.IsAltStream; break; - // case kpidShortName: prop = di.ShortName; break; - #else - - #if defined(__APPLE__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wsign-conversion" - #endif - - case kpidDeviceMajor: - /* - printf("\ndi.mode = %o\n", di.mode); - printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev)); - printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev)); - */ - if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) - prop = (UInt32)major(di.rdev); - break; - - case kpidDeviceMinor: - if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) - prop = (UInt32)minor(di.rdev); - break; - - #if defined(__APPLE__) - #pragma GCC diagnostic pop - #endif - - // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break; - - case kpidUserId: if (StoreOwnerId) prop = (UInt32)di.uid; break; - case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break; - case kpidUser: - if (di.OwnerNameIndex >= 0) - prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; - break; - case kpidGroup: - if (di.OwnerGroupIndex >= 0) - prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; - break; - #endif - default: break; - } - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CS; -#endif - -void CArchiveUpdateCallback::UpdateProcessedItemStatus(unsigned dirIndex) -{ - if (ProcessedItemsStatuses) - { - #ifndef Z7_ST - NSynchronization::CCriticalSectionLock lock(g_CS); - #endif - ProcessedItemsStatuses[dirIndex] = 1; - } -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)) -{ - COM_TRY_BEGIN - *inStream = NULL; - const CUpdatePair2 &up = (*UpdatePairs)[index]; - if (!up.NewData) - return E_FAIL; - - RINOK(Callback->CheckBreak()) - // RINOK(Callback->Finalize()); - - bool isDir = IsDir(up); - - if (up.IsAnti) - { - UString name; - if (up.ArcIndex >= 0) - name = (*ArcItems)[(unsigned)up.ArcIndex].Name; - else if (up.DirIndex >= 0) - name = DirItems->GetLogPath((unsigned)up.DirIndex); - RINOK(Callback->GetStream(name, isDir, true, mode)) - - /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. - so we return empty stream */ - - if (!isDir) - { - CBufInStream *inStreamSpec = new CBufInStream(); - CMyComPtr inStreamLoc = inStreamSpec; - inStreamSpec->Init(NULL, 0); - *inStream = inStreamLoc.Detach(); - } - return S_OK; - } - - RINOK(Callback->GetStream(DirItems->GetLogPath((unsigned)up.DirIndex), isDir, false, mode)) - - if (isDir) - return S_OK; - - if (StdInMode) - { - if (mode != NUpdateNotifyOp::kAdd && - mode != NUpdateNotifyOp::kUpdate) - return S_OK; - -#if 1 - CStdInFileStream *inStreamSpec = new CStdInFileStream; - CMyComPtr inStreamLoc(inStreamSpec); -#else - CMyComPtr inStreamLoc; - if (!CreateStdInStream(inStreamLoc)) - return GetLastError_noZero_HRESULT(); -#endif - *inStream = inStreamLoc.Detach(); - } - else - { - #if !defined(UNDER_CE) - const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; - if (di.AreReparseData()) - { - /* - // we still need DeviceIoControlOut() instead of Read - if (!inStreamSpec->File.OpenReparse(path)) - { - return Callback->OpenFileError(path, ::GetLastError()); - } - */ - // 20.03: we use Reparse Data instead of real data - - CBufInStream *inStreamSpec = new CBufInStream(); - CMyComPtr inStreamLoc = inStreamSpec; - inStreamSpec->Init(di.ReparseData, di.ReparseData.Size()); - *inStream = inStreamLoc.Detach(); - - UpdateProcessedItemStatus((unsigned)up.DirIndex); - return S_OK; - } - #endif // !defined(UNDER_CE) - - CInFileStream *inStreamSpec = new CInFileStream; - CMyComPtr inStreamLoc(inStreamSpec); - - /* - // for debug: - #ifdef _WIN32 - inStreamSpec->StoreOwnerName = true; - inStreamSpec->OwnerName = "user_name"; - inStreamSpec->OwnerName += di.Name; - inStreamSpec->OwnerName += "11111111112222222222222333333333333"; - inStreamSpec->OwnerGroup = "gname_"; - inStreamSpec->OwnerGroup += inStreamSpec->OwnerName; - #endif - */ - - #ifndef _WIN32 - inStreamSpec->StoreOwnerId = StoreOwnerId; - inStreamSpec->StoreOwnerName = StoreOwnerName; - - // if (StoreOwner) - { - inStreamSpec->_uid = di.uid; - inStreamSpec->_gid = di.gid; - if (di.OwnerNameIndex >= 0) - inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; - if (di.OwnerGroupIndex >= 0) - inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; - } - #endif - - inStreamSpec->SupportHardLinks = StoreHardLinks; - const bool preserveATime = (PreserveATime - || mode == NUpdateNotifyOp::kAnalyze); // 22.00 : we don't change access time in Analyze pass. - inStreamSpec->Set_PreserveATime(preserveATime); - - const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex); - _openFiles_Indexes.Add(index); - _openFiles_Paths.Add(path); - // _openFiles_Streams.Add(inStreamSpec); - - /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding - for correct working if exception was raised in GetPhyPath */ - inStreamSpec->Callback = this; - inStreamSpec->CallbackRef = index; - - if (!inStreamSpec->OpenShared(path, ShareForWrite)) - { - bool isOpen = false; - if (preserveATime) - { - inStreamSpec->Set_PreserveATime(false); - isOpen = inStreamSpec->OpenShared(path, ShareForWrite); - } - if (!isOpen) - { - const DWORD error = ::GetLastError(); - const HRESULT hres = Callback->OpenFileError(path, error); - if (hres == S_OK || hres == S_FALSE) - if (StopAfterOpenError || - // v23: we check also for some critical errors: - #ifdef _WIN32 - error == ERROR_NO_SYSTEM_RESOURCES - #else - error == EMFILE - #endif - ) - { - if (error == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(error); - } - return hres; - } - } - - /* - { - // for debug: - Byte b = 0; - UInt32 processedSize = 0; - if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK || - processedSize != 1) - return E_FAIL; - } - */ - - if (Need_LatestMTime) - { - inStreamSpec->ReloadProps(); - } - - // #if defined(Z7_FILE_STREAMS_USE_WIN_FILE) || !defined(_WIN32) - if (StoreHardLinks) - { - CStreamFileProps props; - if (inStreamSpec->GetProps2(&props) == S_OK) - { - if (props.NumLinks > 1) - { - CKeyKeyValPair pair; - pair.Key1 = props.VolID; - pair.Key2 = props.FileID_Low; - pair.Value = index; - const unsigned numItems = _map.Size(); - const unsigned pairIndex = _map.AddToUniqueSorted2(pair); - if (numItems == _map.Size()) - { - // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; - _hardIndex_From = index; - _hardIndex_To = pairIndex; - // we could return NULL as stream, but it's better to return real stream - // return S_OK; - } - } - } - } - // #endif - - UpdateProcessedItemStatus((unsigned)up.DirIndex); - *inStream = inStreamLoc.Detach(); - } - - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 opRes)) -{ - COM_TRY_BEGIN - return Callback->SetOperationResult(opRes); - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)) -{ - COM_TRY_BEGIN - return GetStream2(index, inStream, - (*UpdatePairs)[index].ArcIndex < 0 ? - NUpdateNotifyOp::kAdd : - NUpdateNotifyOp::kUpdate); - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)) -{ - COM_TRY_BEGIN - - // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index); - - bool isDir = false; - - if (indexType == NArchive::NEventIndexType::kOutArcIndex) - { - UString name; - if (index != (UInt32)(Int32)-1) - { - const CUpdatePair2 &up = (*UpdatePairs)[index]; - if (up.ExistOnDisk()) - { - name = DirItems->GetLogPath((unsigned)up.DirIndex); - isDir = DirItems->Items[(unsigned)up.DirIndex].IsDir(); - } - } - return Callback->ReportUpdateOperation(op, name.IsEmpty() ? NULL : name.Ptr(), isDir); - } - - wchar_t temp[16]; - UString s2; - const wchar_t *s = NULL; - - if (indexType == NArchive::NEventIndexType::kInArcIndex) - { - if (index != (UInt32)(Int32)-1) - { - if (ArcItems) - { - const CArcItem &ai = (*ArcItems)[index]; - s = ai.Name; - isDir = ai.IsDir; - } - else if (Arc) - { - RINOK(Arc->GetItem_Path(index, s2)) - s = s2; - RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir)) - } - } - } - else if (indexType == NArchive::NEventIndexType::kBlockIndex) - { - temp[0] = '#'; - ConvertUInt32ToString(index, temp + 1); - s = temp; - } - - if (!s) - s = L""; - - return Callback->ReportUpdateOperation(op, s, isDir); - - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) -{ - COM_TRY_BEGIN - - bool isEncrypted = false; - wchar_t temp[16]; - UString s2; - const wchar_t *s = NULL; - - if (indexType == NArchive::NEventIndexType::kOutArcIndex) - { - /* - UString name; - if (index != (UInt32)(Int32)-1) - { - const CUpdatePair2 &up = (*UpdatePairs)[index]; - if (up.ExistOnDisk()) - { - s2 = DirItems->GetLogPath(up.DirIndex); - s = s2; - } - } - */ - return E_FAIL; - } - - if (indexType == NArchive::NEventIndexType::kInArcIndex) - { - if (index != (UInt32)(Int32)-1) - { - if (ArcItems) - s = (*ArcItems)[index].Name; - else if (Arc) - { - RINOK(Arc->GetItem_Path(index, s2)) - s = s2; - } - if (Archive) - { - RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted)) - } - } - } - else if (indexType == NArchive::NEventIndexType::kBlockIndex) - { - temp[0] = '#'; - ConvertUInt32ToString(index, temp + 1); - s = temp; - } - - return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s); - - COM_TRY_END -} - - -/* -Z7_COM7F_IMF(CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer)) -{ - *answer = 0; - if (Need_ArcMTime_Report && propID == kpidComboMTime) - *answer = 1; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) -{ - if (indexType == NArchive::NEventIndexType::kArcProp) - { - if (propID == kpidComboMTime) - { - ArcMTime_WasReported = true; - if (value->vt == VT_FILETIME) - { - Reported_ArcMTime.Set_From_Prop(*value); - Reported_ArcMTime.Def = true; - } - else - { - Reported_ArcMTime.Clear(); - if (value->vt != VT_EMPTY) - return E_FAIL; // for debug - } - } - } - return Callback->ReportProp(indexType, index, propID, value); -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index, - PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) -{ - return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType); -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) -{ - return Callback->ReportFinished(indexType, index, opRes); -} -*/ - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)) -{ - if (VolumesSizes.Size() == 0) - return S_FALSE; - if (index >= (UInt32)VolumesSizes.Size()) - index = VolumesSizes.Size() - 1; - *size = VolumesSizes[index]; - return S_OK; -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) -{ - COM_TRY_BEGIN - char temp[16]; - ConvertUInt32ToString(index + 1, temp); - FString res (temp); - while (res.Len() < 2) - res.InsertAtFront(FTEXT('0')); - FString fileName = VolName; - fileName.Add_Dot(); - fileName += res; - fileName += VolExt; - COutFileStream *streamSpec = new COutFileStream; - CMyComPtr streamLoc(streamSpec); - if (!streamSpec->Create_NEW(fileName)) - return GetLastError_noZero_HRESULT(); - *volumeStream = streamLoc.Detach(); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) -{ - COM_TRY_BEGIN - return Callback->CryptoGetTextPassword2(passwordIsDefined, password); - COM_TRY_END -} - -Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)) -{ - COM_TRY_BEGIN - return Callback->CryptoGetTextPassword(password); - COM_TRY_END -} - -HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error) -{ - #ifdef _WIN32 // FIX IT !!! - // why did we check only for ERROR_LOCK_VIOLATION ? - // if (error == ERROR_LOCK_VIOLATION) - #endif - { - MT_LOCK - const UInt32 index = (UInt32)val; - FOR_VECTOR(i, _openFiles_Indexes) - { - if (_openFiles_Indexes[i] == index) - { - RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error)) - break; - } - } - } - return HRESULT_FROM_WIN32(error); -} - -void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) -{ - MT_LOCK - if (Need_LatestMTime) - { - if (stream->_info_WasLoaded) - { - const CFiTime &ft = ST_MTIME(stream->_info); - if (!LatestMTime_Defined - || Compare_FiTime(&LatestMTime, &ft) < 0) - LatestMTime = ft; - LatestMTime_Defined = true; - } - } - const UInt32 index = (UInt32)val; - FOR_VECTOR(i, _openFiles_Indexes) - { - if (_openFiles_Indexes[i] == index) - { - _openFiles_Indexes.Delete(i); - _openFiles_Paths.Delete(i); - // _openFiles_Streams.Delete(i); - return; - } - } - /* 21.02 : this function can be called in destructor. - And destructor can be called after some exception. - If we don't want to throw exception in desctructors or after another exceptions, - we must disable the code below that raises new exception. - */ - // throw 20141125; -} +// UpdateCallback.cpp + +#include "StdAfx.h" + +// #include + +#ifndef _WIN32 +// #include +// #include +// for major()/minor(): +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include +#else +#include +#endif + +#endif // _WIN32 + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "../../Common/StreamObjects.h" + +#include "UpdateCallback.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +#define Z7_USE_SECURITY_CODE +#include "../../../Windows/SecurityUtils.h" +#endif + +using namespace NWindows; +using namespace NFile; + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + + +#ifdef Z7_USE_SECURITY_CODE +bool InitLocalPrivileges(); +#endif + +CArchiveUpdateCallback::CArchiveUpdateCallback(): + PreserveATime(false), + ShareForWrite(false), + StopAfterOpenError(false), + StdInMode(false), + + KeepOriginalItemNames(false), + StoreNtSecurity(false), + StoreHardLinks(false), + StoreSymLinks(false), + + #ifndef _WIN32 + StoreOwnerId(false), + StoreOwnerName(false), + #endif + + /* + , Need_ArcMTime_Report(false), + , ArcMTime_WasReported(false), + */ + Need_LatestMTime(false), + LatestMTime_Defined(false), + + Callback(NULL), + + DirItems(NULL), + ParentDirItem(NULL), + + Arc(NULL), + ArcItems(NULL), + UpdatePairs(NULL), + NewNames(NULL), + Comment(NULL), + CommentIndex(-1), + + ProcessedItemsStatuses(NULL), + _hardIndex_From((UInt32)(Int32)-1) +{ + #ifdef Z7_USE_SECURITY_CODE + _saclEnabled = InitLocalPrivileges(); + #endif +} + + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 size)) +{ + COM_TRY_BEGIN + return Callback->SetTotal(size); + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)) +{ + COM_TRY_BEGIN + return Callback->SetCompleted(completeValue); + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + COM_TRY_BEGIN + return Callback->SetRatioInfo(inSize, outSize); + COM_TRY_END +} + + +/* +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR}, + { NULL, kpidIsDir, VT_BOOL}, + { NULL, kpidSize, VT_UI8}, + { NULL, kpidCTime, VT_FILETIME}, + { NULL, kpidATime, VT_FILETIME}, + { NULL, kpidMTime, VT_FILETIME}, + { NULL, kpidAttrib, VT_UI4}, + { NULL, kpidIsAnti, VT_BOOL} +}; + +Z7_COM7F_IMF(CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) +{ + return CStatPropEnumerator::CreateEnumerator(kProps, Z7_ARRAY_SIZE(kProps), enumerator); +} +*/ + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, + Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) +{ + COM_TRY_BEGIN + RINOK(Callback->CheckBreak()) + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (newData) *newData = BoolToInt(up.NewData); + if (newProps) *newProps = BoolToInt(up.NewProps); + if (indexInArchive) + { + *indexInArchive = (UInt32)(Int32)-1; + if (up.ExistInArchive()) + *indexInArchive = ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex; + } + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break; + case kpidCTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break; + case kpidATime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break; + case kpidMTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break; + case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break; + default: break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)) +{ + *parentType = NParentType::kDir; + *parent = (UInt32)(Int32)-1; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = 0; + if (StoreNtSecurity) + *numProps = 1; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) +{ + *name = NULL; + *propID = kpidNtSecure; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootRawProp(PROPID + propID + , const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + #ifndef Z7_USE_SECURITY_CODE + UNUSED_VAR(propID) + #endif + + *data = NULL; + *dataSize = 0; + *propType = 0; + if (!StoreNtSecurity) + return S_OK; + #ifdef Z7_USE_SECURITY_CODE + if (propID == kpidNtSecure) + { + if (StdInMode) + return S_OK; + + if (ParentDirItem) + { + if (ParentDirItem->SecureIndex < 0) + return S_OK; + const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)ParentDirItem->SecureIndex]; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + return S_OK; + } + + if (Arc && Arc->GetRootProps) + return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType); + } + #endif + return S_OK; +} + + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + + if (propID == kpidNtSecure || + propID == kpidNtReparse) + { + if (StdInMode) + return S_OK; + + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps) + return Arc->GetRawProps->GetRawProp( + ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, + propID, data, dataSize, propType); + { + /* + if (!up.NewData) + return E_FAIL; + */ + if (up.IsAnti) + return S_OK; + + #if defined(_WIN32) && !defined(UNDER_CE) + const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; + #endif + + #ifdef Z7_USE_SECURITY_CODE + if (propID == kpidNtSecure) + { + if (!StoreNtSecurity) + return S_OK; + if (di.SecureIndex < 0) + return S_OK; + const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)di.SecureIndex]; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + } + else + #endif + if (propID == kpidNtReparse) + { + if (!StoreSymLinks) + return S_OK; + #if defined(_WIN32) && !defined(UNDER_CE) + // we use ReparseData2 instead of ReparseData for WIM format + const CByteBuffer *buf = &di.ReparseData2; + if (buf->Size() == 0) + buf = &di.ReparseData; + if (buf->Size() != 0) + { + *data = *buf; + *dataSize = (UInt32)buf->Size(); + *propType = NPropDataType::kRaw; + } + #endif + } + + return S_OK; + } + } + + return S_OK; +} + +#if defined(_WIN32) && !defined(UNDER_CE) + +static UString GetRelativePath(const UString &to, const UString &from) +{ + UStringVector partsTo, partsFrom; + SplitPathToParts(to, partsTo); + SplitPathToParts(from, partsFrom); + + unsigned i; + for (i = 0;; i++) + { + if (i + 1 >= partsFrom.Size() || + i + 1 >= partsTo.Size()) + break; + if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) + break; + } + + if (i == 0) + { + #ifdef _WIN32 + if (NName::IsDrivePath(to) || + NName::IsDrivePath(from)) + return to; + #endif + } + + UString s; + unsigned k; + + for (k = i + 1; k < partsFrom.Size(); k++) + s += ".." STRING_PATH_SEPARATOR; + + for (k = i; k < partsTo.Size(); k++) + { + if (k != i) + s.Add_PathSepar(); + s += partsTo[k]; + } + + return s; +} + +#endif + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + const CUpdatePair2 &up = (*UpdatePairs)[index]; + NCOM::CPropVariant prop; + + if (up.NewData) + { + /* + if (propID == kpidIsHardLink) + { + prop = _isHardLink; + prop.Detach(value); + return S_OK; + } + */ + if (propID == kpidSymLink) + { + if (index == _hardIndex_From) + { + prop.Detach(value); + return S_OK; + } + + #if !defined(UNDER_CE) + + if (up.DirIndex >= 0) + { + const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; + + #ifdef _WIN32 + // if (di.IsDir()) + { + CReparseAttr attr; + if (attr.Parse(di.ReparseData, di.ReparseData.Size())) + { + const UString simpleName = attr.GetPath(); + if (!attr.IsSymLink_WSL() && attr.IsRelative_Win()) + prop = simpleName; + else + { + const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); + FString fullPath; + if (NDir::MyGetFullPathName(phyPath, fullPath)) + { + prop = GetRelativePath(simpleName, fs2us(fullPath)); + } + } + prop.Detach(value); + return S_OK; + } + } + + #else // _WIN32 + + if (di.ReparseData.Size() != 0) + { + AString utf; + utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); + + UString us; + if (ConvertUTF8ToUnicode(utf, us)) + { + prop = us; + prop.Detach(value); + return S_OK; + } + } + + #endif // _WIN32 + } + #endif // !defined(UNDER_CE) + } + else if (propID == kpidHardLink) + { + if (index == _hardIndex_From) + { + const CKeyKeyValPair &pair = _map[_hardIndex_To]; + const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; + prop = DirItems->GetLogPath((unsigned)up2.DirIndex); + prop.Detach(value); + return S_OK; + } + if (up.DirIndex >= 0) + { + prop.Detach(value); + return S_OK; + } + } + } + + if (up.IsAnti + && propID != kpidIsDir + && propID != kpidPath + && propID != kpidIsAltStream) + { + switch (propID) + { + case kpidSize: prop = (UInt64)0; break; + case kpidIsAnti: prop = true; break; + default: break; + } + } + else if (propID == kpidPath && up.NewNameIndex >= 0) + prop = (*NewNames)[(unsigned)up.NewNameIndex]; + else if (propID == kpidComment + && CommentIndex >= 0 + && (unsigned)CommentIndex == index + && Comment) + prop = *Comment; + else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) + { + // we can generate new ShortName here; + } + else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) + && up.ExistInArchive() && Archive) + return Archive->GetProperty(ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, propID, value); + else if (up.ExistOnDisk()) + { + const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; + switch (propID) + { + case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break; + case kpidIsDir: prop = di.IsDir(); break; + case kpidSize: prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; + case kpidAttrib: /* if (di.Attrib_IsDefined) */ prop = (UInt32)di.GetWinAttrib(); break; + case kpidPosixAttrib: /* if (di.Attrib_IsDefined) */ prop = (UInt32)di.GetPosixAttrib(); break; + + #if defined(_WIN32) + case kpidIsAltStream: prop = di.IsAltStream; break; + // case kpidShortName: prop = di.ShortName; break; + #else + + #if defined(__APPLE__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wsign-conversion" + #endif + + case kpidDeviceMajor: + /* + printf("\ndi.mode = %o\n", di.mode); + printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev)); + printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev)); + */ + if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) + prop = (UInt32)major(di.rdev); + break; + + case kpidDeviceMinor: + if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) + prop = (UInt32)minor(di.rdev); + break; + + #if defined(__APPLE__) + #pragma GCC diagnostic pop + #endif + + // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break; + + case kpidUserId: if (StoreOwnerId) prop = (UInt32)di.uid; break; + case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break; + case kpidUser: + if (di.OwnerNameIndex >= 0) + prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; + break; + case kpidGroup: + if (di.OwnerGroupIndex >= 0) + prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; + break; + #endif + default: break; + } + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CS; +#endif + +void CArchiveUpdateCallback::UpdateProcessedItemStatus(unsigned dirIndex) +{ + if (ProcessedItemsStatuses) + { + #ifndef Z7_ST + NSynchronization::CCriticalSectionLock lock(g_CS); + #endif + ProcessedItemsStatuses[dirIndex] = 1; + } +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)) +{ + COM_TRY_BEGIN + *inStream = NULL; + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (!up.NewData) + return E_FAIL; + + RINOK(Callback->CheckBreak()) + // RINOK(Callback->Finalize()); + + bool isDir = IsDir(up); + + if (up.IsAnti) + { + UString name; + if (up.ArcIndex >= 0) + name = (*ArcItems)[(unsigned)up.ArcIndex].Name; + else if (up.DirIndex >= 0) + name = DirItems->GetLogPath((unsigned)up.DirIndex); + RINOK(Callback->GetStream(name, isDir, true, mode)) + + /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. + so we return empty stream */ + + if (!isDir) + { + CBufInStream *inStreamSpec = new CBufInStream(); + CMyComPtr inStreamLoc = inStreamSpec; + inStreamSpec->Init(NULL, 0); + *inStream = inStreamLoc.Detach(); + } + return S_OK; + } + + RINOK(Callback->GetStream(DirItems->GetLogPath((unsigned)up.DirIndex), isDir, false, mode)) + + if (isDir) + return S_OK; + + if (StdInMode) + { + if (mode != NUpdateNotifyOp::kAdd && + mode != NUpdateNotifyOp::kUpdate) + return S_OK; + +#if 1 + CStdInFileStream *inStreamSpec = new CStdInFileStream; + CMyComPtr inStreamLoc(inStreamSpec); +#else + CMyComPtr inStreamLoc; + if (!CreateStdInStream(inStreamLoc)) + return GetLastError_noZero_HRESULT(); +#endif + *inStream = inStreamLoc.Detach(); + } + else + { + #if !defined(UNDER_CE) + const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; + if (di.AreReparseData()) + { + /* + // we still need DeviceIoControlOut() instead of Read + if (!inStreamSpec->File.OpenReparse(path)) + { + return Callback->OpenFileError(path, ::GetLastError()); + } + */ + // 20.03: we use Reparse Data instead of real data + + CBufInStream *inStreamSpec = new CBufInStream(); + CMyComPtr inStreamLoc = inStreamSpec; + inStreamSpec->Init(di.ReparseData, di.ReparseData.Size()); + *inStream = inStreamLoc.Detach(); + + UpdateProcessedItemStatus((unsigned)up.DirIndex); + return S_OK; + } + #endif // !defined(UNDER_CE) + + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStreamLoc(inStreamSpec); + + /* + // for debug: + #ifdef _WIN32 + inStreamSpec->StoreOwnerName = true; + inStreamSpec->OwnerName = "user_name"; + inStreamSpec->OwnerName += di.Name; + inStreamSpec->OwnerName += "11111111112222222222222333333333333"; + inStreamSpec->OwnerGroup = "gname_"; + inStreamSpec->OwnerGroup += inStreamSpec->OwnerName; + #endif + */ + + #ifndef _WIN32 + inStreamSpec->StoreOwnerId = StoreOwnerId; + inStreamSpec->StoreOwnerName = StoreOwnerName; + + // if (StoreOwner) + { + inStreamSpec->_uid = di.uid; + inStreamSpec->_gid = di.gid; + if (di.OwnerNameIndex >= 0) + inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; + if (di.OwnerGroupIndex >= 0) + inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; + } + #endif + + inStreamSpec->SupportHardLinks = StoreHardLinks; + const bool preserveATime = (PreserveATime + || mode == NUpdateNotifyOp::kAnalyze); // 22.00 : we don't change access time in Analyze pass. + inStreamSpec->Set_PreserveATime(preserveATime); + + const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex); + _openFiles_Indexes.Add(index); + _openFiles_Paths.Add(path); + // _openFiles_Streams.Add(inStreamSpec); + + /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding + for correct working if exception was raised in GetPhyPath */ + inStreamSpec->Callback = this; + inStreamSpec->CallbackRef = index; + + if (!inStreamSpec->OpenShared(path, ShareForWrite)) + { + bool isOpen = false; + if (preserveATime) + { + inStreamSpec->Set_PreserveATime(false); + isOpen = inStreamSpec->OpenShared(path, ShareForWrite); + } + if (!isOpen) + { + const DWORD error = ::GetLastError(); + const HRESULT hres = Callback->OpenFileError(path, error); + if (hres == S_OK || hres == S_FALSE) + if (StopAfterOpenError || + // v23: we check also for some critical errors: + #ifdef _WIN32 + error == ERROR_NO_SYSTEM_RESOURCES + #else + error == EMFILE + #endif + ) + { + if (error == 0) + return E_FAIL; + return HRESULT_FROM_WIN32(error); + } + return hres; + } + } + + /* + { + // for debug: + Byte b = 0; + UInt32 processedSize = 0; + if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK || + processedSize != 1) + return E_FAIL; + } + */ + + if (Need_LatestMTime) + { + inStreamSpec->ReloadProps(); + } + + // #if defined(Z7_FILE_STREAMS_USE_WIN_FILE) || !defined(_WIN32) + if (StoreHardLinks) + { + CStreamFileProps props; + if (inStreamSpec->GetProps2(&props) == S_OK) + { + if (props.NumLinks > 1) + { + CKeyKeyValPair pair; + pair.Key1 = props.VolID; + pair.Key2 = props.FileID_Low; + pair.Value = index; + const unsigned numItems = _map.Size(); + const unsigned pairIndex = _map.AddToUniqueSorted2(pair); + if (numItems == _map.Size()) + { + // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; + _hardIndex_From = index; + _hardIndex_To = pairIndex; + // we could return NULL as stream, but it's better to return real stream + // return S_OK; + } + } + } + } + // #endif + + UpdateProcessedItemStatus((unsigned)up.DirIndex); + *inStream = inStreamLoc.Detach(); + } + + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 opRes)) +{ + COM_TRY_BEGIN + return Callback->SetOperationResult(opRes); + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)) +{ + COM_TRY_BEGIN + return GetStream2(index, inStream, + (*UpdatePairs)[index].ArcIndex < 0 ? + NUpdateNotifyOp::kAdd : + NUpdateNotifyOp::kUpdate); + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)) +{ + COM_TRY_BEGIN + + // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index); + + bool isDir = false; + + if (indexType == NArchive::NEventIndexType::kOutArcIndex) + { + UString name; + if (index != (UInt32)(Int32)-1) + { + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (up.ExistOnDisk()) + { + name = DirItems->GetLogPath((unsigned)up.DirIndex); + isDir = DirItems->Items[(unsigned)up.DirIndex].IsDir(); + } + } + return Callback->ReportUpdateOperation(op, name.IsEmpty() ? NULL : name.Ptr(), isDir); + } + + wchar_t temp[16]; + UString s2; + const wchar_t *s = NULL; + + if (indexType == NArchive::NEventIndexType::kInArcIndex) + { + if (index != (UInt32)(Int32)-1) + { + if (ArcItems) + { + const CArcItem &ai = (*ArcItems)[index]; + s = ai.Name; + isDir = ai.IsDir; + } + else if (Arc) + { + RINOK(Arc->GetItem_Path(index, s2)) + s = s2; + RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir)) + } + } + } + else if (indexType == NArchive::NEventIndexType::kBlockIndex) + { + temp[0] = '#'; + ConvertUInt32ToString(index, temp + 1); + s = temp; + } + + if (!s) + s = L""; + + return Callback->ReportUpdateOperation(op, s, isDir); + + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) +{ + COM_TRY_BEGIN + + bool isEncrypted = false; + wchar_t temp[16]; + UString s2; + const wchar_t *s = NULL; + + if (indexType == NArchive::NEventIndexType::kOutArcIndex) + { + /* + UString name; + if (index != (UInt32)(Int32)-1) + { + const CUpdatePair2 &up = (*UpdatePairs)[index]; + if (up.ExistOnDisk()) + { + s2 = DirItems->GetLogPath(up.DirIndex); + s = s2; + } + } + */ + return E_FAIL; + } + + if (indexType == NArchive::NEventIndexType::kInArcIndex) + { + if (index != (UInt32)(Int32)-1) + { + if (ArcItems) + s = (*ArcItems)[index].Name; + else if (Arc) + { + RINOK(Arc->GetItem_Path(index, s2)) + s = s2; + } + if (Archive) + { + RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted)) + } + } + } + else if (indexType == NArchive::NEventIndexType::kBlockIndex) + { + temp[0] = '#'; + ConvertUInt32ToString(index, temp + 1); + s = temp; + } + + return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s); + + COM_TRY_END +} + + +/* +Z7_COM7F_IMF(CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer)) +{ + *answer = 0; + if (Need_ArcMTime_Report && propID == kpidComboMTime) + *answer = 1; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) +{ + if (indexType == NArchive::NEventIndexType::kArcProp) + { + if (propID == kpidComboMTime) + { + ArcMTime_WasReported = true; + if (value->vt == VT_FILETIME) + { + Reported_ArcMTime.Set_From_Prop(*value); + Reported_ArcMTime.Def = true; + } + else + { + Reported_ArcMTime.Clear(); + if (value->vt != VT_EMPTY) + return E_FAIL; // for debug + } + } + } + return Callback->ReportProp(indexType, index, propID, value); +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index, + PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) +{ + return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType); +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) +{ + return Callback->ReportFinished(indexType, index, opRes); +} +*/ + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)) +{ + if (VolumesSizes.Size() == 0) + return S_FALSE; + if (index >= (UInt32)VolumesSizes.Size()) + index = VolumesSizes.Size() - 1; + *size = VolumesSizes[index]; + return S_OK; +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) +{ + COM_TRY_BEGIN + char temp[16]; + ConvertUInt32ToString(index + 1, temp); + FString res (temp); + while (res.Len() < 2) + res.InsertAtFront(FTEXT('0')); + FString fileName = VolName; + fileName.Add_Dot(); + fileName += res; + fileName += VolExt; + COutFileStream *streamSpec = new COutFileStream; + CMyComPtr streamLoc(streamSpec); + if (!streamSpec->Create_NEW(fileName)) + return GetLastError_noZero_HRESULT(); + *volumeStream = streamLoc.Detach(); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) +{ + COM_TRY_BEGIN + return Callback->CryptoGetTextPassword2(passwordIsDefined, password); + COM_TRY_END +} + +Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)) +{ + COM_TRY_BEGIN + return Callback->CryptoGetTextPassword(password); + COM_TRY_END +} + +HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error) +{ + #ifdef _WIN32 // FIX IT !!! + // why did we check only for ERROR_LOCK_VIOLATION ? + // if (error == ERROR_LOCK_VIOLATION) + #endif + { + MT_LOCK + const UInt32 index = (UInt32)val; + FOR_VECTOR(i, _openFiles_Indexes) + { + if (_openFiles_Indexes[i] == index) + { + RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error)) + break; + } + } + } + return HRESULT_FROM_WIN32(error); +} + +void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) +{ + MT_LOCK + if (Need_LatestMTime) + { + if (stream->_info_WasLoaded) + { + const CFiTime &ft = ST_MTIME(stream->_info); + if (!LatestMTime_Defined + || Compare_FiTime(&LatestMTime, &ft) < 0) + LatestMTime = ft; + LatestMTime_Defined = true; + } + } + const UInt32 index = (UInt32)val; + FOR_VECTOR(i, _openFiles_Indexes) + { + if (_openFiles_Indexes[i] == index) + { + _openFiles_Indexes.Delete(i); + _openFiles_Paths.Delete(i); + // _openFiles_Streams.Delete(i); + return; + } + } + /* 21.02 : this function can be called in destructor. + And destructor can be called after some exception. + If we don't want to throw exception in desctructors or after another exceptions, + we must disable the code below that raises new exception. + */ + // throw 20141125; +} diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h index 1987aeb21..379b81462 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.h +++ b/CPP/7zip/UI/Common/UpdateCallback.h @@ -1,197 +1,197 @@ -// UpdateCallback.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK_H -#define ZIP7_INC_UPDATE_CALLBACK_H - -#include "../../../Common/MyCom.h" - -#include "../../Common/FileStreams.h" - -#include "../../IPassword.h" -#include "../../ICoder.h" - -#include "../Common/UpdatePair.h" -#include "../Common/UpdateProduce.h" - -#include "OpenArchive.h" - -struct CArcToDoStat -{ - CDirItemsStat2 NewData; - CDirItemsStat2 OldData; - CDirItemsStat2 DeleteData; - - UInt64 Get_NumDataItems_Total() const - { - return NewData.Get_NumDataItems2() + OldData.Get_NumDataItems2(); - } -}; - - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACEN_IUpdateCallbackUI(x) \ - virtual HRESULT WriteSfx(const wchar_t *name, UInt64 size) x \ - virtual HRESULT SetTotal(UInt64 size) x \ - virtual HRESULT SetCompleted(const UInt64 *completeValue) x \ - virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x \ - virtual HRESULT CheckBreak() x \ - /* virtual HRESULT Finalize() x */ \ - virtual HRESULT SetNumItems(const CArcToDoStat &stat) x \ - virtual HRESULT GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) x \ - virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \ - virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x \ - virtual HRESULT SetOperationResult(Int32 opRes) x \ - virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x \ - virtual HRESULT ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) x \ - /* virtual HRESULT SetPassword(const UString &password) x */ \ - virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x \ - virtual HRESULT CryptoGetTextPassword(BSTR *password) x \ - virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x \ - - /* - virtual HRESULT ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x \ - virtual HRESULT ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x \ - virtual HRESULT ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) x \ - */ - - /* virtual HRESULT CloseProgress() { return S_OK; } */ - -Z7_IFACE_DECL_PURE(IUpdateCallbackUI) -Z7_PURE_INTERFACES_END - -struct CKeyKeyValPair -{ - UInt64 Key1; - UInt64 Key2; - unsigned Value; - - int Compare(const CKeyKeyValPair &a) const - { - if (Key1 < a.Key1) return -1; - if (Key1 > a.Key1) return 1; - return MyCompare(Key2, a.Key2); - } -}; - - -class CArchiveUpdateCallback Z7_final: - public IArchiveUpdateCallback2, - public IArchiveUpdateCallbackFile, - // public IArchiveUpdateCallbackArcProp, - public IArchiveExtractCallbackMessage2, - public IArchiveGetRawProps, - public IArchiveGetRootProps, - public ICryptoGetTextPassword2, - public ICryptoGetTextPassword, - public ICompressProgressInfo, - public IInFileStream_Callback, - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IArchiveUpdateCallback2) - Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile) - // Z7_COM_QI_ENTRY(IArchiveUpdateCallbackArcProp) - Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage2) - Z7_COM_QI_ENTRY(IArchiveGetRawProps) - Z7_COM_QI_ENTRY(IArchiveGetRootProps) - Z7_COM_QI_ENTRY(ICryptoGetTextPassword2) - Z7_COM_QI_ENTRY(ICryptoGetTextPassword) - Z7_COM_QI_ENTRY(ICompressProgressInfo) - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(ICompressProgressInfo) - - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IArchiveUpdateCallback) - Z7_IFACE_COM7_IMP(IArchiveUpdateCallback2) - Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile) - // Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackArcProp) - Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2) - Z7_IFACE_COM7_IMP(IArchiveGetRawProps) - Z7_IFACE_COM7_IMP(IArchiveGetRootProps) - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2) - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - - - void UpdateProcessedItemStatus(unsigned dirIndex); - -public: - bool PreserveATime; - bool ShareForWrite; - bool StopAfterOpenError; - bool StdInMode; - - bool KeepOriginalItemNames; - bool StoreNtSecurity; - bool StoreHardLinks; - bool StoreSymLinks; - - bool StoreOwnerId; - bool StoreOwnerName; - - bool Need_LatestMTime; - bool LatestMTime_Defined; - - /* - bool Need_ArcMTime_Report; - bool ArcMTime_WasReported; - */ - - CRecordVector _openFiles_Indexes; - FStringVector _openFiles_Paths; - // CRecordVector< CInFileStream* > _openFiles_Streams; - - bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); } - virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) Z7_override; - virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) Z7_override; - - IUpdateCallbackUI *Callback; - - const CDirItems *DirItems; - const CDirItem *ParentDirItem; - - const CArc *Arc; - CMyComPtr Archive; - const CObjectVector *ArcItems; - const CRecordVector *UpdatePairs; - - CRecordVector VolumesSizes; - FString VolName; - FString VolExt; - UString ArcFileName; // without path prefix - - const UStringVector *NewNames; - const UString *Comment; - int CommentIndex; - - /* - CArcTime Reported_ArcMTime; - */ - CFiTime LatestMTime; - - Byte *ProcessedItemsStatuses; - - - CArchiveUpdateCallback(); - - bool IsDir(const CUpdatePair2 &up) const - { - if (up.DirIndex >= 0) - return DirItems->Items[(unsigned)up.DirIndex].IsDir(); - else if (up.ArcIndex >= 0) - return (*ArcItems)[(unsigned)up.ArcIndex].IsDir; - return false; - } - -private: - #if defined(_WIN32) && !defined(UNDER_CE) - bool _saclEnabled; - #endif - CRecordVector _map; - - UInt32 _hardIndex_From; - UInt32 _hardIndex_To; -}; - -#endif +// UpdateCallback.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK_H +#define ZIP7_INC_UPDATE_CALLBACK_H + +#include "../../../Common/MyCom.h" + +#include "../../Common/FileStreams.h" + +#include "../../IPassword.h" +#include "../../ICoder.h" + +#include "../Common/UpdatePair.h" +#include "../Common/UpdateProduce.h" + +#include "OpenArchive.h" + +struct CArcToDoStat +{ + CDirItemsStat2 NewData; + CDirItemsStat2 OldData; + CDirItemsStat2 DeleteData; + + UInt64 Get_NumDataItems_Total() const + { + return NewData.Get_NumDataItems2() + OldData.Get_NumDataItems2(); + } +}; + + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACEN_IUpdateCallbackUI(x) \ + virtual HRESULT WriteSfx(const wchar_t *name, UInt64 size) x \ + virtual HRESULT SetTotal(UInt64 size) x \ + virtual HRESULT SetCompleted(const UInt64 *completeValue) x \ + virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x \ + virtual HRESULT CheckBreak() x \ + /* virtual HRESULT Finalize() x */ \ + virtual HRESULT SetNumItems(const CArcToDoStat &stat) x \ + virtual HRESULT GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) x \ + virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \ + virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x \ + virtual HRESULT SetOperationResult(Int32 opRes) x \ + virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x \ + virtual HRESULT ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) x \ + /* virtual HRESULT SetPassword(const UString &password) x */ \ + virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x \ + virtual HRESULT CryptoGetTextPassword(BSTR *password) x \ + virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x \ + + /* + virtual HRESULT ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x \ + virtual HRESULT ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x \ + virtual HRESULT ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) x \ + */ + + /* virtual HRESULT CloseProgress() { return S_OK; } */ + +Z7_IFACE_DECL_PURE(IUpdateCallbackUI) +Z7_PURE_INTERFACES_END + +struct CKeyKeyValPair +{ + UInt64 Key1; + UInt64 Key2; + unsigned Value; + + int Compare(const CKeyKeyValPair &a) const + { + if (Key1 < a.Key1) return -1; + if (Key1 > a.Key1) return 1; + return MyCompare(Key2, a.Key2); + } +}; + + +class CArchiveUpdateCallback Z7_final: + public IArchiveUpdateCallback2, + public IArchiveUpdateCallbackFile, + // public IArchiveUpdateCallbackArcProp, + public IArchiveExtractCallbackMessage2, + public IArchiveGetRawProps, + public IArchiveGetRootProps, + public ICryptoGetTextPassword2, + public ICryptoGetTextPassword, + public ICompressProgressInfo, + public IInFileStream_Callback, + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IArchiveUpdateCallback2) + Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile) + // Z7_COM_QI_ENTRY(IArchiveUpdateCallbackArcProp) + Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage2) + Z7_COM_QI_ENTRY(IArchiveGetRawProps) + Z7_COM_QI_ENTRY(IArchiveGetRootProps) + Z7_COM_QI_ENTRY(ICryptoGetTextPassword2) + Z7_COM_QI_ENTRY(ICryptoGetTextPassword) + Z7_COM_QI_ENTRY(ICompressProgressInfo) + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(ICompressProgressInfo) + + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IArchiveUpdateCallback) + Z7_IFACE_COM7_IMP(IArchiveUpdateCallback2) + Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile) + // Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackArcProp) + Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2) + Z7_IFACE_COM7_IMP(IArchiveGetRawProps) + Z7_IFACE_COM7_IMP(IArchiveGetRootProps) + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2) + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + + + void UpdateProcessedItemStatus(unsigned dirIndex); + +public: + bool PreserveATime; + bool ShareForWrite; + bool StopAfterOpenError; + bool StdInMode; + + bool KeepOriginalItemNames; + bool StoreNtSecurity; + bool StoreHardLinks; + bool StoreSymLinks; + + bool StoreOwnerId; + bool StoreOwnerName; + + bool Need_LatestMTime; + bool LatestMTime_Defined; + + /* + bool Need_ArcMTime_Report; + bool ArcMTime_WasReported; + */ + + CRecordVector _openFiles_Indexes; + FStringVector _openFiles_Paths; + // CRecordVector< CInFileStream* > _openFiles_Streams; + + bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); } + virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) Z7_override; + virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) Z7_override; + + IUpdateCallbackUI *Callback; + + const CDirItems *DirItems; + const CDirItem *ParentDirItem; + + const CArc *Arc; + CMyComPtr Archive; + const CObjectVector *ArcItems; + const CRecordVector *UpdatePairs; + + CRecordVector VolumesSizes; + FString VolName; + FString VolExt; + UString ArcFileName; // without path prefix + + const UStringVector *NewNames; + const UString *Comment; + int CommentIndex; + + /* + CArcTime Reported_ArcMTime; + */ + CFiTime LatestMTime; + + Byte *ProcessedItemsStatuses; + + + CArchiveUpdateCallback(); + + bool IsDir(const CUpdatePair2 &up) const + { + if (up.DirIndex >= 0) + return DirItems->Items[(unsigned)up.DirIndex].IsDir(); + else if (up.ArcIndex >= 0) + return (*ArcItems)[(unsigned)up.ArcIndex].IsDir; + return false; + } + +private: + #if defined(_WIN32) && !defined(UNDER_CE) + bool _saclEnabled; + #endif + CRecordVector _map; + + UInt32 _hardIndex_From; + UInt32 _hardIndex_To; +}; + +#endif diff --git a/CPP/7zip/UI/Common/UpdatePair.cpp b/CPP/7zip/UI/Common/UpdatePair.cpp index e3eee9830..99b0aafb2 100644 --- a/CPP/7zip/UI/Common/UpdatePair.cpp +++ b/CPP/7zip/UI/Common/UpdatePair.cpp @@ -1,302 +1,302 @@ -// UpdatePair.cpp - -#include "StdAfx.h" - -#include -// #include - -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/TimeUtils.h" - -#include "SortUtils.h" -#include "UpdatePair.h" - -using namespace NWindows; -using namespace NTime; - - -/* - a2.Prec = - { - 0 (k_PropVar_TimePrec_0): - if GetProperty(kpidMTime) returned 0 and - GetProperty(kpidTimeType) did not returned VT_UI4. - 7z, wim, tar in 7-Zip before v21) - in that case we use - (prec) that is set by IOutArchive::GetFileTimeType() - } -*/ - -static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2) -{ - // except of precision, we also have limitation, when timestamp is out of range - - /* if (Prec) in archive item is defined, then use global (prec) */ - if (a2.Prec != k_PropVar_TimePrec_0) - prec = a2.Prec; - - CArcTime a1; - a1.Set_From_FiTime(f1); - /* Set_From_FiTime() must set full form precision: - k_PropVar_TimePrec_Base + numDigits - windows: 7 digits, non-windows: 9 digits */ - - if (prec == k_PropVar_TimePrec_DOS) - { - const UInt32 dosTime1 = a1.Get_DosTime(); - const UInt32 dosTime2 = a2.Get_DosTime(); - return MyCompare(dosTime1, dosTime2); - } - - if (prec == k_PropVar_TimePrec_Unix) - { - const Int64 u2 = FileTime_To_UnixTime64(a2.FT); - if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF) - { - // timestamp probably was saturated in archive to 32-bit - // so we use saturated 32-bit value for disk file too. - UInt32 u1; - FileTime_To_UnixTime(a1.FT, u1); - const UInt32 u2_32 = (UInt32)u2; - return MyCompare(u1, u2_32); - } - - const Int64 u1 = FileTime_To_UnixTime64(a1.FT); - return MyCompare(u1, u2); - // prec = k_PropVar_TimePrec_Base; // for debug - } - - if (prec == k_PropVar_TimePrec_0) - prec = k_PropVar_TimePrec_Base + 7; - else if (prec == k_PropVar_TimePrec_HighPrec) - prec = k_PropVar_TimePrec_Base + 9; - else if (prec < k_PropVar_TimePrec_Base) - prec = k_PropVar_TimePrec_Base; - else if (prec > k_PropVar_TimePrec_Base + 9) - prec = k_PropVar_TimePrec_Base + 7; - - // prec now is full form: k_PropVar_TimePrec_Base + numDigits; - if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base) - prec = a1.Prec; - - const unsigned numDigits = prec - k_PropVar_TimePrec_Base; - if (numDigits >= 7) - { - const int comp = CompareFileTime(&a1.FT, &a2.FT); - if (comp != 0 || numDigits == 7) - return comp; - return MyCompare(a1.Ns100, a2.Ns100); - } - UInt32 d = 1; - for (unsigned k = numDigits; k < 7; k++) - d *= 10; - const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d; - const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d; - // printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits); - return MyCompare(v1, v2); -} - - - -static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:"; -static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:"; -static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; - -Z7_ATTR_NORETURN -static -void ThrowError(const char *message, const UString &s1, const UString &s2) -{ - UString m (message); - m.Add_LF(); m += s1; - m.Add_LF(); m += s2; - throw m; -} - -static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2) -{ - const int res = CompareFileNames(ai1.Name, ai2.Name); - if (res != 0) - return res; - if (ai1.IsDir != ai2.IsDir) - return ai1.IsDir ? -1 : 1; - return 0; -} - -static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) -{ - const unsigned i1 = *p1; - const unsigned i2 = *p2; - const CObjectVector &arcItems = *(const CObjectVector *)param; - const int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); - if (res != 0) - return res; - return MyCompare(i1, i2); -} - -void GetUpdatePairInfoList( - const CDirItems &dirItems, - const CObjectVector &arcItems, - NFileTimeType::EEnum fileTimeType, - CRecordVector &updatePairs) -{ - CUIntVector dirIndices, arcIndices; - - const unsigned numDirItems = dirItems.Items.Size(); - const unsigned numArcItems = arcItems.Size(); - - CIntArr duplicatedArcItem(numArcItems); - { - int *vals = &duplicatedArcItem[0]; - for (unsigned i = 0; i < numArcItems; i++) - vals[i] = 0; - } - - { - arcIndices.ClearAndSetSize(numArcItems); - if (numArcItems != 0) - { - unsigned *vals = &arcIndices[0]; - for (unsigned i = 0; i < numArcItems; i++) - vals[i] = i; - } - arcIndices.Sort(CompareArcItems, (void *)&arcItems); - for (unsigned i = 0; i + 1 < numArcItems; i++) - if (CompareArcItemsBase( - arcItems[arcIndices[i]], - arcItems[arcIndices[i + 1]]) == 0) - { - duplicatedArcItem[i] = 1; - duplicatedArcItem[i + 1] = -1; - } - } - - UStringVector dirNames; - { - dirNames.ClearAndReserve(numDirItems); - unsigned i; - for (i = 0; i < numDirItems; i++) - dirNames.AddInReserved(dirItems.GetLogPath(i)); - SortFileNames(dirNames, dirIndices); - for (i = 0; i + 1 < numDirItems; i++) - { - const UString &s1 = dirNames[dirIndices[i]]; - const UString &s2 = dirNames[dirIndices[i + 1]]; - if (CompareFileNames(s1, s2) == 0) - ThrowError(k_Duplicate_inDir_Message, s1, s2); - } - } - - unsigned dirIndex = 0; - unsigned arcIndex = 0; - - int prevHostFile = -1; - const UString *prevHostName = NULL; - - while (dirIndex < numDirItems || arcIndex < numArcItems) - { - CUpdatePair pair; - - int dirIndex2 = -1; - int arcIndex2 = -1; - const CDirItem *di = NULL; - const CArcItem *ai = NULL; - - int compareResult = -1; - const UString *name = NULL; - - if (dirIndex < numDirItems) - { - dirIndex2 = (int)dirIndices[dirIndex]; - di = &dirItems.Items[(unsigned)dirIndex2]; - } - - if (arcIndex < numArcItems) - { - arcIndex2 = (int)arcIndices[arcIndex]; - ai = &arcItems[(unsigned)arcIndex2]; - compareResult = 1; - if (dirIndex < numDirItems) - { - compareResult = CompareFileNames(dirNames[(unsigned)dirIndex2], ai->Name); - if (compareResult == 0) - { - if (di->IsDir() != ai->IsDir) - compareResult = (ai->IsDir ? 1 : -1); - } - } - } - - if (compareResult < 0) - { - name = &dirNames[(unsigned)dirIndex2]; - pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; - pair.DirIndex = dirIndex2; - dirIndex++; - } - else if (compareResult > 0) - { - name = &ai->Name; - pair.State = ai->Censored ? - NUpdateArchive::NPairState::kOnlyInArchive: - NUpdateArchive::NPairState::kNotMasked; - pair.ArcIndex = arcIndex2; - arcIndex++; - } - else - { - const int dupl = duplicatedArcItem[arcIndex]; - if (dupl != 0) - ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name); - - name = &dirNames[(unsigned)dirIndex2]; - if (!ai->Censored) - ThrowError(k_NotCensoredCollision_Message, *name, ai->Name); - - pair.DirIndex = dirIndex2; - pair.ArcIndex = arcIndex2; - - int compResult = 0; - if (ai->MTime.Def) - { - compResult = MyCompareTime((unsigned)fileTimeType, di->MTime, ai->MTime); - } - switch (compResult) - { - case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; - case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; - default: - pair.State = (ai->Size_Defined && di->Size == ai->Size) ? - NUpdateArchive::NPairState::kSameFiles : - NUpdateArchive::NPairState::kUnknowNewerFiles; - } - - dirIndex++; - arcIndex++; - } - - if ( - #ifdef _WIN32 - (di && di->IsAltStream) || - #endif - (ai && ai->IsAltStream)) - { - if (prevHostName) - { - const unsigned hostLen = prevHostName->Len(); - if (name->Len() > hostLen) - if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0) - pair.HostIndex = prevHostFile; - } - } - else - { - prevHostFile = (int)updatePairs.Size(); - prevHostName = name; - } - - updatePairs.Add(pair); - } - - updatePairs.ReserveDown(); -} +// UpdatePair.cpp + +#include "StdAfx.h" + +#include +// #include + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/TimeUtils.h" + +#include "SortUtils.h" +#include "UpdatePair.h" + +using namespace NWindows; +using namespace NTime; + + +/* + a2.Prec = + { + 0 (k_PropVar_TimePrec_0): + if GetProperty(kpidMTime) returned 0 and + GetProperty(kpidTimeType) did not returned VT_UI4. + 7z, wim, tar in 7-Zip before v21) + in that case we use + (prec) that is set by IOutArchive::GetFileTimeType() + } +*/ + +static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2) +{ + // except of precision, we also have limitation, when timestamp is out of range + + /* if (Prec) in archive item is defined, then use global (prec) */ + if (a2.Prec != k_PropVar_TimePrec_0) + prec = a2.Prec; + + CArcTime a1; + a1.Set_From_FiTime(f1); + /* Set_From_FiTime() must set full form precision: + k_PropVar_TimePrec_Base + numDigits + windows: 7 digits, non-windows: 9 digits */ + + if (prec == k_PropVar_TimePrec_DOS) + { + const UInt32 dosTime1 = a1.Get_DosTime(); + const UInt32 dosTime2 = a2.Get_DosTime(); + return MyCompare(dosTime1, dosTime2); + } + + if (prec == k_PropVar_TimePrec_Unix) + { + const Int64 u2 = FileTime_To_UnixTime64(a2.FT); + if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF) + { + // timestamp probably was saturated in archive to 32-bit + // so we use saturated 32-bit value for disk file too. + UInt32 u1; + FileTime_To_UnixTime(a1.FT, u1); + const UInt32 u2_32 = (UInt32)u2; + return MyCompare(u1, u2_32); + } + + const Int64 u1 = FileTime_To_UnixTime64(a1.FT); + return MyCompare(u1, u2); + // prec = k_PropVar_TimePrec_Base; // for debug + } + + if (prec == k_PropVar_TimePrec_0) + prec = k_PropVar_TimePrec_Base + 7; + else if (prec == k_PropVar_TimePrec_HighPrec) + prec = k_PropVar_TimePrec_Base + 9; + else if (prec < k_PropVar_TimePrec_Base) + prec = k_PropVar_TimePrec_Base; + else if (prec > k_PropVar_TimePrec_Base + 9) + prec = k_PropVar_TimePrec_Base + 7; + + // prec now is full form: k_PropVar_TimePrec_Base + numDigits; + if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base) + prec = a1.Prec; + + const unsigned numDigits = prec - k_PropVar_TimePrec_Base; + if (numDigits >= 7) + { + const int comp = CompareFileTime(&a1.FT, &a2.FT); + if (comp != 0 || numDigits == 7) + return comp; + return MyCompare(a1.Ns100, a2.Ns100); + } + UInt32 d = 1; + for (unsigned k = numDigits; k < 7; k++) + d *= 10; + const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d; + const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d; + // printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits); + return MyCompare(v1, v2); +} + + + +static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:"; +static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:"; +static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; + +Z7_ATTR_NORETURN +static +void ThrowError(const char *message, const UString &s1, const UString &s2) +{ + UString m (message); + m.Add_LF(); m += s1; + m.Add_LF(); m += s2; + throw m; +} + +static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2) +{ + const int res = CompareFileNames(ai1.Name, ai2.Name); + if (res != 0) + return res; + if (ai1.IsDir != ai2.IsDir) + return ai1.IsDir ? -1 : 1; + return 0; +} + +static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) +{ + const unsigned i1 = *p1; + const unsigned i2 = *p2; + const CObjectVector &arcItems = *(const CObjectVector *)param; + const int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); + if (res != 0) + return res; + return MyCompare(i1, i2); +} + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector &updatePairs) +{ + CUIntVector dirIndices, arcIndices; + + const unsigned numDirItems = dirItems.Items.Size(); + const unsigned numArcItems = arcItems.Size(); + + CIntArr duplicatedArcItem(numArcItems); + { + int *vals = &duplicatedArcItem[0]; + for (unsigned i = 0; i < numArcItems; i++) + vals[i] = 0; + } + + { + arcIndices.ClearAndSetSize(numArcItems); + if (numArcItems != 0) + { + unsigned *vals = &arcIndices[0]; + for (unsigned i = 0; i < numArcItems; i++) + vals[i] = i; + } + arcIndices.Sort(CompareArcItems, (void *)&arcItems); + for (unsigned i = 0; i + 1 < numArcItems; i++) + if (CompareArcItemsBase( + arcItems[arcIndices[i]], + arcItems[arcIndices[i + 1]]) == 0) + { + duplicatedArcItem[i] = 1; + duplicatedArcItem[i + 1] = -1; + } + } + + UStringVector dirNames; + { + dirNames.ClearAndReserve(numDirItems); + unsigned i; + for (i = 0; i < numDirItems; i++) + dirNames.AddInReserved(dirItems.GetLogPath(i)); + SortFileNames(dirNames, dirIndices); + for (i = 0; i + 1 < numDirItems; i++) + { + const UString &s1 = dirNames[dirIndices[i]]; + const UString &s2 = dirNames[dirIndices[i + 1]]; + if (CompareFileNames(s1, s2) == 0) + ThrowError(k_Duplicate_inDir_Message, s1, s2); + } + } + + unsigned dirIndex = 0; + unsigned arcIndex = 0; + + int prevHostFile = -1; + const UString *prevHostName = NULL; + + while (dirIndex < numDirItems || arcIndex < numArcItems) + { + CUpdatePair pair; + + int dirIndex2 = -1; + int arcIndex2 = -1; + const CDirItem *di = NULL; + const CArcItem *ai = NULL; + + int compareResult = -1; + const UString *name = NULL; + + if (dirIndex < numDirItems) + { + dirIndex2 = (int)dirIndices[dirIndex]; + di = &dirItems.Items[(unsigned)dirIndex2]; + } + + if (arcIndex < numArcItems) + { + arcIndex2 = (int)arcIndices[arcIndex]; + ai = &arcItems[(unsigned)arcIndex2]; + compareResult = 1; + if (dirIndex < numDirItems) + { + compareResult = CompareFileNames(dirNames[(unsigned)dirIndex2], ai->Name); + if (compareResult == 0) + { + if (di->IsDir() != ai->IsDir) + compareResult = (ai->IsDir ? 1 : -1); + } + } + } + + if (compareResult < 0) + { + name = &dirNames[(unsigned)dirIndex2]; + pair.State = NUpdateArchive::NPairState::kOnlyOnDisk; + pair.DirIndex = dirIndex2; + dirIndex++; + } + else if (compareResult > 0) + { + name = &ai->Name; + pair.State = ai->Censored ? + NUpdateArchive::NPairState::kOnlyInArchive: + NUpdateArchive::NPairState::kNotMasked; + pair.ArcIndex = arcIndex2; + arcIndex++; + } + else + { + const int dupl = duplicatedArcItem[arcIndex]; + if (dupl != 0) + ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name); + + name = &dirNames[(unsigned)dirIndex2]; + if (!ai->Censored) + ThrowError(k_NotCensoredCollision_Message, *name, ai->Name); + + pair.DirIndex = dirIndex2; + pair.ArcIndex = arcIndex2; + + int compResult = 0; + if (ai->MTime.Def) + { + compResult = MyCompareTime((unsigned)fileTimeType, di->MTime, ai->MTime); + } + switch (compResult) + { + case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; + case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; + default: + pair.State = (ai->Size_Defined && di->Size == ai->Size) ? + NUpdateArchive::NPairState::kSameFiles : + NUpdateArchive::NPairState::kUnknowNewerFiles; + } + + dirIndex++; + arcIndex++; + } + + if ( + #ifdef _WIN32 + (di && di->IsAltStream) || + #endif + (ai && ai->IsAltStream)) + { + if (prevHostName) + { + const unsigned hostLen = prevHostName->Len(); + if (name->Len() > hostLen) + if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0) + pair.HostIndex = prevHostFile; + } + } + else + { + prevHostFile = (int)updatePairs.Size(); + prevHostName = name; + } + + updatePairs.Add(pair); + } + + updatePairs.ReserveDown(); +} diff --git a/CPP/7zip/UI/Common/UpdatePair.h b/CPP/7zip/UI/Common/UpdatePair.h index 8d480695c..13228b0e0 100644 --- a/CPP/7zip/UI/Common/UpdatePair.h +++ b/CPP/7zip/UI/Common/UpdatePair.h @@ -1,27 +1,27 @@ -// UpdatePair.h - -#ifndef ZIP7_INC_UPDATE_PAIR_H -#define ZIP7_INC_UPDATE_PAIR_H - -#include "DirItem.h" -#include "UpdateAction.h" - -#include "../../Archive/IArchive.h" - -struct CUpdatePair -{ - NUpdateArchive::NPairState::EEnum State; - int ArcIndex; - int DirIndex; - int HostIndex; // >= 0 for alt streams only, contains index of host pair - - CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {} -}; - -void GetUpdatePairInfoList( - const CDirItems &dirItems, - const CObjectVector &arcItems, - NFileTimeType::EEnum fileTimeType, - CRecordVector &updatePairs); - -#endif +// UpdatePair.h + +#ifndef ZIP7_INC_UPDATE_PAIR_H +#define ZIP7_INC_UPDATE_PAIR_H + +#include "DirItem.h" +#include "UpdateAction.h" + +#include "../../Archive/IArchive.h" + +struct CUpdatePair +{ + NUpdateArchive::NPairState::EEnum State; + int ArcIndex; + int DirIndex; + int HostIndex; // >= 0 for alt streams only, contains index of host pair + + CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {} +}; + +void GetUpdatePairInfoList( + const CDirItems &dirItems, + const CObjectVector &arcItems, + NFileTimeType::EEnum fileTimeType, + CRecordVector &updatePairs); + +#endif diff --git a/CPP/7zip/UI/Common/UpdateProduce.cpp b/CPP/7zip/UI/Common/UpdateProduce.cpp index d36ea018a..88d250159 100644 --- a/CPP/7zip/UI/Common/UpdateProduce.cpp +++ b/CPP/7zip/UI/Common/UpdateProduce.cpp @@ -1,74 +1,74 @@ -// UpdateProduce.cpp - -#include "StdAfx.h" - -#include "UpdateProduce.h" - -using namespace NUpdateArchive; - -static const char * const kUpdateActionSetCollision = "Internal collision in update action set"; - -void UpdateProduce( - const CRecordVector &updatePairs, - const CActionSet &actionSet, - CRecordVector &operationChain, - IUpdateProduceCallback *callback) -{ - FOR_VECTOR (i, updatePairs) - { - const CUpdatePair &pair = updatePairs[i]; - - CUpdatePair2 up2; - up2.DirIndex = pair.DirIndex; - up2.ArcIndex = pair.ArcIndex; - up2.NewData = up2.NewProps = true; - up2.UseArcProps = false; - - switch ((int)actionSet.StateActions[(unsigned)pair.State]) - { - case NPairAction::kIgnore: - if (pair.ArcIndex >= 0 && callback) - callback->ShowDeleteFile((unsigned)pair.ArcIndex); - continue; - - case NPairAction::kCopy: - if (pair.State == NPairState::kOnlyOnDisk) - throw kUpdateActionSetCollision; - if (pair.State == NPairState::kOnlyInArchive) - { - if (pair.HostIndex >= 0) - { - /* - ignore alt stream if - 1) no such alt stream in Disk - 2) there is Host file in disk - */ - if (updatePairs[(unsigned)pair.HostIndex].DirIndex >= 0) - continue; - } - } - up2.NewData = up2.NewProps = false; - up2.UseArcProps = true; - break; - - case NPairAction::kCompress: - if (pair.State == NPairState::kOnlyInArchive || - pair.State == NPairState::kNotMasked) - throw kUpdateActionSetCollision; - break; - - case NPairAction::kCompressAsAnti: - up2.IsAnti = true; - up2.UseArcProps = (pair.ArcIndex >= 0); - break; - - default: throw 123; // break; // is unexpected case - } - - up2.IsSameTime = ((unsigned)pair.State == NUpdateArchive::NPairState::kSameFiles); - - operationChain.Add(up2); - } - - operationChain.ReserveDown(); -} +// UpdateProduce.cpp + +#include "StdAfx.h" + +#include "UpdateProduce.h" + +using namespace NUpdateArchive; + +static const char * const kUpdateActionSetCollision = "Internal collision in update action set"; + +void UpdateProduce( + const CRecordVector &updatePairs, + const CActionSet &actionSet, + CRecordVector &operationChain, + IUpdateProduceCallback *callback) +{ + FOR_VECTOR (i, updatePairs) + { + const CUpdatePair &pair = updatePairs[i]; + + CUpdatePair2 up2; + up2.DirIndex = pair.DirIndex; + up2.ArcIndex = pair.ArcIndex; + up2.NewData = up2.NewProps = true; + up2.UseArcProps = false; + + switch ((int)actionSet.StateActions[(unsigned)pair.State]) + { + case NPairAction::kIgnore: + if (pair.ArcIndex >= 0 && callback) + callback->ShowDeleteFile((unsigned)pair.ArcIndex); + continue; + + case NPairAction::kCopy: + if (pair.State == NPairState::kOnlyOnDisk) + throw kUpdateActionSetCollision; + if (pair.State == NPairState::kOnlyInArchive) + { + if (pair.HostIndex >= 0) + { + /* + ignore alt stream if + 1) no such alt stream in Disk + 2) there is Host file in disk + */ + if (updatePairs[(unsigned)pair.HostIndex].DirIndex >= 0) + continue; + } + } + up2.NewData = up2.NewProps = false; + up2.UseArcProps = true; + break; + + case NPairAction::kCompress: + if (pair.State == NPairState::kOnlyInArchive || + pair.State == NPairState::kNotMasked) + throw kUpdateActionSetCollision; + break; + + case NPairAction::kCompressAsAnti: + up2.IsAnti = true; + up2.UseArcProps = (pair.ArcIndex >= 0); + break; + + default: throw 123; // break; // is unexpected case + } + + up2.IsSameTime = ((unsigned)pair.State == NUpdateArchive::NPairState::kSameFiles); + + operationChain.Add(up2); + } + + operationChain.ReserveDown(); +} diff --git a/CPP/7zip/UI/Common/UpdateProduce.h b/CPP/7zip/UI/Common/UpdateProduce.h index ed41725bc..9db6c1e44 100644 --- a/CPP/7zip/UI/Common/UpdateProduce.h +++ b/CPP/7zip/UI/Common/UpdateProduce.h @@ -1,60 +1,60 @@ -// UpdateProduce.h - -#ifndef ZIP7_INC_UPDATE_PRODUCE_H -#define ZIP7_INC_UPDATE_PRODUCE_H - -#include "UpdatePair.h" - -struct CUpdatePair2 -{ - bool NewData; - bool NewProps; - bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties. - bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status - - int DirIndex; - int ArcIndex; - int NewNameIndex; - - bool IsMainRenameItem; - bool IsSameTime; - - void SetAs_NoChangeArcItem(unsigned arcIndex) // int - { - NewData = NewProps = false; - UseArcProps = true; - IsAnti = false; - ArcIndex = (int)arcIndex; - } - - bool ExistOnDisk() const { return DirIndex != -1; } - bool ExistInArchive() const { return ArcIndex != -1; } - - CUpdatePair2(): - NewData(false), - NewProps(false), - UseArcProps(false), - IsAnti(false), - DirIndex(-1), - ArcIndex(-1), - NewNameIndex(-1), - IsMainRenameItem(false), - IsSameTime(false) - {} -}; - -Z7_PURE_INTERFACES_BEGIN - -DECLARE_INTERFACE(IUpdateProduceCallback) -{ - virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0; -}; -Z7_PURE_INTERFACES_END - -void UpdateProduce( - const CRecordVector &updatePairs, - const NUpdateArchive::CActionSet &actionSet, - CRecordVector &operationChain, - IUpdateProduceCallback *callback); - -#endif +// UpdateProduce.h + +#ifndef ZIP7_INC_UPDATE_PRODUCE_H +#define ZIP7_INC_UPDATE_PRODUCE_H + +#include "UpdatePair.h" + +struct CUpdatePair2 +{ + bool NewData; + bool NewProps; + bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties. + bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status + + int DirIndex; + int ArcIndex; + int NewNameIndex; + + bool IsMainRenameItem; + bool IsSameTime; + + void SetAs_NoChangeArcItem(unsigned arcIndex) // int + { + NewData = NewProps = false; + UseArcProps = true; + IsAnti = false; + ArcIndex = (int)arcIndex; + } + + bool ExistOnDisk() const { return DirIndex != -1; } + bool ExistInArchive() const { return ArcIndex != -1; } + + CUpdatePair2(): + NewData(false), + NewProps(false), + UseArcProps(false), + IsAnti(false), + DirIndex(-1), + ArcIndex(-1), + NewNameIndex(-1), + IsMainRenameItem(false), + IsSameTime(false) + {} +}; + +Z7_PURE_INTERFACES_BEGIN + +DECLARE_INTERFACE(IUpdateProduceCallback) +{ + virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0; +}; +Z7_PURE_INTERFACES_END + +void UpdateProduce( + const CRecordVector &updatePairs, + const NUpdateArchive::CActionSet &actionSet, + CRecordVector &operationChain, + IUpdateProduceCallback *callback); + +#endif diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp index 133428850..a49296718 100644 --- a/CPP/7zip/UI/Common/WorkDir.cpp +++ b/CPP/7zip/UI/Common/WorkDir.cpp @@ -1,86 +1,84 @@ -// WorkDir.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileSystem.h" - -#include "WorkDir.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName) -{ - NWorkDir::NMode::EEnum mode = workDirInfo.Mode; - - #if defined(_WIN32) && !defined(UNDER_CE) - if (workDirInfo.ForRemovableOnly) - { - mode = NWorkDir::NMode::kCurrent; - const FString prefix = path.Left(3); - if (NName::IsDrivePath(prefix)) - { - const UINT driveType = NSystem::MyGetDriveType(prefix); - if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE) - mode = workDirInfo.Mode; - } - /* - CParsedPath parsedPath; - parsedPath.ParsePath(archiveName); - UINT driveType = GetDriveType(parsedPath.Prefix); - if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE)) - mode = NZipSettings::NWorkDir::NMode::kCurrent; - */ - } - #endif - - const int pos = path.ReverseFind_PathSepar() + 1; - fileName = path.Ptr((unsigned)pos); - - FString tempDir; - switch ((int)mode) - { - case NWorkDir::NMode::kCurrent: - tempDir = path.Left((unsigned)pos); - break; - case NWorkDir::NMode::kSpecified: - tempDir = workDirInfo.Path; - break; - // case NWorkDir::NMode::kSystem: - default: - if (!MyGetTempPath(tempDir)) - throw 141717; - break; - } - NName::NormalizeDirPathPrefix(tempDir); - return tempDir; -} - -HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath) -{ - NWorkDir::CInfo workDirInfo; - workDirInfo.Load(); - FString namePart; - const FString workDir = GetWorkDir(workDirInfo, originalPath, namePart); - CreateComplexDir(workDir); - _outStreamSpec = new COutFileStream; - OutStream = _outStreamSpec; - if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File)) - { - return GetLastError_noZero_HRESULT(); - } - _originalPath = originalPath; - return S_OK; -} - -HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal) -{ - OutStream.Release(); - if (!_tempFile.MoveTo(_originalPath, deleteOriginal)) - { - return GetLastError_noZero_HRESULT(); - } - return S_OK; -} +// WorkDir.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileSystem.h" + +#include "WorkDir.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName) +{ + NWorkDir::NMode::EEnum mode = workDirInfo.Mode; + + #if defined(_WIN32) && !defined(UNDER_CE) + if (workDirInfo.ForRemovableOnly) + { + mode = NWorkDir::NMode::kCurrent; + const FString prefix = path.Left(3); + if (NName::IsDrivePath(prefix)) + { + const UINT driveType = NSystem::MyGetDriveType(prefix); + if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE) + mode = workDirInfo.Mode; + } + /* + CParsedPath parsedPath; + parsedPath.ParsePath(archiveName); + UINT driveType = GetDriveType(parsedPath.Prefix); + if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE)) + mode = NZipSettings::NWorkDir::NMode::kCurrent; + */ + } + #endif + + const int pos = path.ReverseFind_PathSepar() + 1; + fileName = path.Ptr((unsigned)pos); + + FString tempDir; + switch ((int)mode) + { + case NWorkDir::NMode::kCurrent: + tempDir = path.Left((unsigned)pos); + break; + case NWorkDir::NMode::kSpecified: + tempDir = workDirInfo.Path; + break; + // case NWorkDir::NMode::kSystem: + default: + if (!MyGetTempPath(tempDir)) + throw 141717; + break; + } + NName::NormalizeDirPathPrefix(tempDir); + return tempDir; +} + +HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath) +{ + NWorkDir::CInfo workDirInfo; + workDirInfo.Load(); + FString namePart; + FString path = GetWorkDir(workDirInfo, originalPath, namePart); + CreateComplexDir(path); + path += namePart; + _outStreamSpec = new COutFileStream; + OutStream = _outStreamSpec; + if (!_tempFile.Create(path, &_outStreamSpec->File)) + return GetLastError_noZero_HRESULT(); + _originalPath = originalPath; + return S_OK; +} + +HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal, + NWindows::NFile::NDir::ICopyFileProgress *progress) +{ + OutStream.Release(); + if (!_tempFile.MoveTo(_originalPath, deleteOriginal, progress)) + return GetLastError_noZero_HRESULT(); + return S_OK; +} diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h index f3b2837f7..fed8c4a7e 100644 --- a/CPP/7zip/UI/Common/WorkDir.h +++ b/CPP/7zip/UI/Common/WorkDir.h @@ -1,26 +1,30 @@ -// WorkDir.h - -#ifndef ZIP7_INC_WORK_DIR_H -#define ZIP7_INC_WORK_DIR_H - -#include "../../../Windows/FileDir.h" - -#include "../../Common/FileStreams.h" - -#include "ZipRegistry.h" - -FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName); - -class CWorkDirTempFile -{ - FString _originalPath; - NWindows::NFile::NDir::CTempFile _tempFile; - COutFileStream *_outStreamSpec; -public: - CMyComPtr OutStream; - - HRESULT CreateTempFile(const FString &originalPath); - HRESULT MoveToOriginal(bool deleteOriginal); -}; - -#endif +// WorkDir.h + +#ifndef ZIP7_INC_WORK_DIR_H +#define ZIP7_INC_WORK_DIR_H + +#include "../../../Windows/FileDir.h" + +#include "../../Common/FileStreams.h" + +#include "ZipRegistry.h" + +FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName); + +class CWorkDirTempFile MY_UNCOPYABLE +{ + FString _originalPath; + NWindows::NFile::NDir::CTempFile _tempFile; + COutFileStream *_outStreamSpec; +public: + CMyComPtr OutStream; + + const FString &Get_OriginalFilePath() const { return _originalPath; } + const FString &Get_TempFilePath() const { return _tempFile.GetPath(); } + + HRESULT CreateTempFile(const FString &originalPath); + HRESULT MoveToOriginal(bool deleteOriginal, + NWindows::NFile::NDir::ICopyFileProgress *progress = NULL); +}; + +#endif diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp index c6d64623c..936b8881b 100644 --- a/CPP/7zip/UI/Common/ZipRegistry.cpp +++ b/CPP/7zip/UI/Common/ZipRegistry.cpp @@ -1,602 +1,599 @@ -// ZipRegistry.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/Registry.h" -#include "../../../Windows/Synchronization.h" - -// #include "../Explorer/ContextMenuFlags.h" -#include "ZipRegistry.h" - -using namespace NWindows; -using namespace NRegistry; - -static NSynchronization::CCriticalSection g_CS; -#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS); - -static LPCTSTR const kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR); - -static CSysString GetKeyPath(LPCTSTR path) { return kCuPrefix + (CSysString)path; } - -static LONG OpenMainKey(CKey &key, LPCTSTR keyName) -{ - return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ); -} - -static LONG CreateMainKey(CKey &key, LPCTSTR keyName) -{ - return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName)); -} - -static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value) -{ - if (value == (UInt32)(Int32)-1) - key.DeleteValue(name); - else - key.SetValue(name, value); -} - - -static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value) -{ - if (key.QueryValue(name, value) != ERROR_SUCCESS) - value = (UInt32)(Int32)-1; -} - - -static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b) -{ - if (b.Def) - key.SetValue(name, b.Val); -} - -static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val) -{ - bool oldVal = false; - if (key.GetValue_IfOk(name, oldVal) == ERROR_SUCCESS) - if (val == oldVal) - return; - key.SetValue(name, val); -} - -static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoolPair &b) -{ - if (b.Def) - Key_Set_bool_if_Changed(key, name, b.Val); - else - key.DeleteValue(name); -} - -static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b) -{ - b.Val = false; - b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS); -} - -static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b) -{ - b.Val = true; - b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS); -} - -namespace NExtract -{ - -static LPCTSTR const kKeyName = TEXT("Extraction"); - -static LPCTSTR const kExtractMode = TEXT("ExtractMode"); -static LPCTSTR const kOverwriteMode = TEXT("OverwriteMode"); -static LPCTSTR const kShowPassword = TEXT("ShowPassword"); -static LPCTSTR const kPathHistory = TEXT("PathHistory"); -static LPCTSTR const kSplitDest = TEXT("SplitDest"); -static LPCTSTR const kElimDup = TEXT("ElimDup"); -// static LPCTSTR const kAltStreams = TEXT("AltStreams"); -static LPCTSTR const kNtSecur = TEXT("Security"); -static LPCTSTR const kMemLimit = TEXT("MemLimit"); - -void CInfo::Save() const -{ - CS_LOCK - CKey key; - CreateMainKey(key, kKeyName); - - if (PathMode_Force) - key.SetValue(kExtractMode, (UInt32)PathMode); - if (OverwriteMode_Force) - key.SetValue(kOverwriteMode, (UInt32)OverwriteMode); - - Key_Set_BoolPair(key, kSplitDest, SplitDest); - Key_Set_BoolPair(key, kElimDup, ElimDup); - // Key_Set_BoolPair(key, kAltStreams, AltStreams); - Key_Set_BoolPair(key, kNtSecur, NtSecurity); - Key_Set_BoolPair(key, kShowPassword, ShowPassword); - - key.RecurseDeleteKey(kPathHistory); - key.SetValue_Strings(kPathHistory, Paths); -} - -void Save_ShowPassword(bool showPassword) -{ - CS_LOCK - CKey key; - CreateMainKey(key, kKeyName); - key.SetValue(kShowPassword, showPassword); -} - -void Save_LimitGB(UInt32 limit_GB) -{ - CS_LOCK - CKey key; - CreateMainKey(key, kKeyName); - Key_Set_UInt32(key, kMemLimit, limit_GB); -} - -void CInfo::Load() -{ - PathMode = NPathMode::kCurPaths; - PathMode_Force = false; - OverwriteMode = NOverwriteMode::kAsk; - OverwriteMode_Force = false; - - SplitDest.Val = true; - - Paths.Clear(); - - CS_LOCK - CKey key; - if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) - return; - - key.GetValue_Strings(kPathHistory, Paths); - UInt32 v; - if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths) - { - PathMode = (NPathMode::EEnum)v; - PathMode_Force = true; - } - if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting) - { - OverwriteMode = (NOverwriteMode::EEnum)v; - OverwriteMode_Force = true; - } - - Key_Get_BoolPair_true(key, kSplitDest, SplitDest); - - Key_Get_BoolPair(key, kElimDup, ElimDup); - // Key_Get_BoolPair(key, kAltStreams, AltStreams); - Key_Get_BoolPair(key, kNtSecur, NtSecurity); - Key_Get_BoolPair(key, kShowPassword, ShowPassword); -} - -bool Read_ShowPassword() -{ - CS_LOCK - CKey key; - bool showPassword = false; - if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) - return showPassword; - key.GetValue_IfOk(kShowPassword, showPassword); - return showPassword; -} - -UInt32 Read_LimitGB() -{ - CS_LOCK - CKey key; - if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS) - { - UInt32 v; - if (key.QueryValue(kMemLimit, v) == ERROR_SUCCESS) - return v; - } - return (UInt32)(Int32)-1; -} - -} - -namespace NCompression -{ - -static LPCTSTR const kKeyName = TEXT("Compression"); - -static LPCTSTR const kArcHistory = TEXT("ArcHistory"); -static LPCWSTR const kArchiver = L"Archiver"; -static LPCTSTR const kShowPassword = TEXT("ShowPassword"); -static LPCTSTR const kEncryptHeaders = TEXT("EncryptHeaders"); - -static LPCTSTR const kOptionsKeyName = TEXT("Options"); - -static LPCTSTR const kLevel = TEXT("Level"); -static LPCTSTR const kDictionary = TEXT("Dictionary"); -// static LPCTSTR const kDictionaryChain = TEXT("DictionaryChain"); -static LPCTSTR const kOrder = TEXT("Order"); -static LPCTSTR const kBlockSize = TEXT("BlockSize"); -static LPCTSTR const kNumThreads = TEXT("NumThreads"); -static LPCWSTR const kMethod = L"Method"; -static LPCWSTR const kOptions = L"Options"; -static LPCWSTR const kEncryptionMethod = L"EncryptionMethod"; - -static LPCTSTR const kNtSecur = TEXT("Security"); -static LPCTSTR const kAltStreams = TEXT("AltStreams"); -static LPCTSTR const kHardLinks = TEXT("HardLinks"); -static LPCTSTR const kSymLinks = TEXT("SymLinks"); -static LPCTSTR const kPreserveATime = TEXT("PreserveATime"); - -static LPCTSTR const kTimePrec = TEXT("TimePrec"); -static LPCTSTR const kMTime = TEXT("MTime"); -static LPCTSTR const kATime = TEXT("ATime"); -static LPCTSTR const kCTime = TEXT("CTime"); -static LPCTSTR const kSetArcMTime = TEXT("SetArcMTime"); - -static void SetRegString(CKey &key, LPCWSTR name, const UString &value) -{ - if (value.IsEmpty()) - key.DeleteValue(name); - else - key.SetValue(name, value); -} - -static void GetRegString(CKey &key, LPCWSTR name, UString &value) -{ - if (key.QueryValue(name, value) != ERROR_SUCCESS) - value.Empty(); -} - -static LPCWSTR const kMemUse = L"MemUse" - #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) - L"32"; - #else - L"64"; - #endif - -void CInfo::Save() const -{ - CS_LOCK - - CKey key; - CreateMainKey(key, kKeyName); - - Key_Set_BoolPair_Delete_IfNotDef (key, kNtSecur, NtSecurity); - Key_Set_BoolPair_Delete_IfNotDef (key, kAltStreams, AltStreams); - Key_Set_BoolPair_Delete_IfNotDef (key, kHardLinks, HardLinks); - Key_Set_BoolPair_Delete_IfNotDef (key, kSymLinks, SymLinks); - Key_Set_BoolPair_Delete_IfNotDef (key, kPreserveATime, PreserveATime); - - key.SetValue(kShowPassword, ShowPassword); - key.SetValue(kLevel, (UInt32)Level); - key.SetValue(kArchiver, ArcType); - key.SetValue(kShowPassword, ShowPassword); - key.SetValue(kEncryptHeaders, EncryptHeaders); - key.RecurseDeleteKey(kArcHistory); - key.SetValue_Strings(kArcHistory, ArcPaths); - - key.RecurseDeleteKey(kOptionsKeyName); - { - CKey optionsKey; - optionsKey.Create(key, kOptionsKeyName); - FOR_VECTOR (i, Formats) - { - const CFormatOptions &fo = Formats[i]; - CKey fk; - fk.Create(optionsKey, fo.FormatID); - - SetRegString(fk, kMethod, fo.Method); - SetRegString(fk, kOptions, fo.Options); - SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); - SetRegString(fk, kMemUse, fo.MemUse); - - Key_Set_UInt32(fk, kLevel, fo.Level); - Key_Set_UInt32(fk, kDictionary, fo.Dictionary); - // Key_Set_UInt32(fk, kDictionaryChain, fo.DictionaryChain); - Key_Set_UInt32(fk, kOrder, fo.Order); - Key_Set_UInt32(fk, kBlockSize, fo.BlockLogSize); - Key_Set_UInt32(fk, kNumThreads, fo.NumThreads); - - Key_Set_UInt32(fk, kTimePrec, fo.TimePrec); - Key_Set_BoolPair_Delete_IfNotDef (fk, kMTime, fo.MTime); - Key_Set_BoolPair_Delete_IfNotDef (fk, kATime, fo.ATime); - Key_Set_BoolPair_Delete_IfNotDef (fk, kCTime, fo.CTime); - Key_Set_BoolPair_Delete_IfNotDef (fk, kSetArcMTime, fo.SetArcMTime); - } - } -} - -void CInfo::Load() -{ - ArcPaths.Clear(); - Formats.Clear(); - - Level = 5; - ArcType = L"7z"; - ShowPassword = false; - EncryptHeaders = false; - - CS_LOCK - CKey key; - - if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) - return; - - Key_Get_BoolPair(key, kNtSecur, NtSecurity); - Key_Get_BoolPair(key, kAltStreams, AltStreams); - Key_Get_BoolPair(key, kHardLinks, HardLinks); - Key_Get_BoolPair(key, kSymLinks, SymLinks); - Key_Get_BoolPair(key, kPreserveATime, PreserveATime); - - key.GetValue_Strings(kArcHistory, ArcPaths); - - { - CKey optionsKey; - if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS) - { - CSysStringVector formatIDs; - optionsKey.EnumKeys(formatIDs); - FOR_VECTOR (i, formatIDs) - { - CKey fk; - CFormatOptions fo; - fo.FormatID = formatIDs[i]; - if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS) - { - GetRegString(fk, kMethod, fo.Method); - GetRegString(fk, kOptions, fo.Options); - GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); - GetRegString(fk, kMemUse, fo.MemUse); - - Key_Get_UInt32(fk, kLevel, fo.Level); - Key_Get_UInt32(fk, kDictionary, fo.Dictionary); - // Key_Get_UInt32(fk, kDictionaryChain, fo.DictionaryChain); - Key_Get_UInt32(fk, kOrder, fo.Order); - Key_Get_UInt32(fk, kBlockSize, fo.BlockLogSize); - Key_Get_UInt32(fk, kNumThreads, fo.NumThreads); - - Key_Get_UInt32(fk, kTimePrec, fo.TimePrec); - Key_Get_BoolPair(fk, kMTime, fo.MTime); - Key_Get_BoolPair(fk, kATime, fo.ATime); - Key_Get_BoolPair(fk, kCTime, fo.CTime); - Key_Get_BoolPair(fk, kSetArcMTime, fo.SetArcMTime); - - Formats.Add(fo); - } - } - } - } - - UString a; - if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) - ArcType = a; - key.GetValue_IfOk(kLevel, Level); - key.GetValue_IfOk(kShowPassword, ShowPassword); - key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders); -} - - -static bool ParseMemUse(const wchar_t *s, CMemUse &mu) -{ - mu.Clear(); - - bool percentMode = false; - { - const wchar_t c = *s; - if (MyCharLower_Ascii(c) == 'p') - { - percentMode = true; - s++; - } - } - const wchar_t *end; - UInt64 number = ConvertStringToUInt64(s, &end); - if (end == s) - return false; - - wchar_t c = *end; - - if (percentMode) - { - if (c != 0) - return false; - mu.IsPercent = true; - mu.Val = number; - return true; - } - - if (c == 0) - { - mu.Val = number; - return true; - } - - c = MyCharLower_Ascii(c); - - const wchar_t c1 = end[1]; - - if (c == '%') - { - if (c1 != 0) - return false; - mu.IsPercent = true; - mu.Val = number; - return true; - } - - if (c == 'b') - { - if (c1 != 0) - return false; - mu.Val = number; - return true; - } - - if (c1 != 0) - if (MyCharLower_Ascii(c1) != 'b' || end[2] != 0) - return false; - - unsigned numBits; - switch (c) - { - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - case 't': numBits = 40; break; - default: return false; - } - if (number >= ((UInt64)1 << (64 - numBits))) - return false; - mu.Val = number << numBits; - return true; -} - - -void CMemUse::Parse(const UString &s) -{ - IsDefined = ParseMemUse(s, *this); -} - -/* -void MemLimit_Save(const UString &s) -{ - CS_LOCK - CKey key; - CreateMainKey(key, kKeyName); - SetRegString(key, kMemUse, s); -} - -bool MemLimit_Load(NCompression::CMemUse &mu) -{ - mu.Clear(); - UString a; - { - CS_LOCK - CKey key; - if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) - return false; - if (key.QueryValue(kMemUse, a) != ERROR_SUCCESS) - return false; - } - if (a.IsEmpty()) - return false; - mu.Parse(a); - return mu.IsDefined; -} -*/ - -} - -static LPCTSTR const kOptionsInfoKeyName = TEXT("Options"); - -namespace NWorkDir -{ -static LPCTSTR const kWorkDirType = TEXT("WorkDirType"); -static LPCWSTR const kWorkDirPath = L"WorkDirPath"; -static LPCTSTR const kTempRemovableOnly = TEXT("TempRemovableOnly"); - - -void CInfo::Save()const -{ - CS_LOCK - CKey key; - CreateMainKey(key, kOptionsInfoKeyName); - key.SetValue(kWorkDirType, (UInt32)Mode); - key.SetValue(kWorkDirPath, fs2us(Path)); - key.SetValue(kTempRemovableOnly, ForRemovableOnly); -} - -void CInfo::Load() -{ - SetDefault(); - - CS_LOCK - CKey key; - if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS) - return; - - UInt32 dirType; - if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS) - return; - switch (dirType) - { - case NMode::kSystem: - case NMode::kCurrent: - case NMode::kSpecified: - Mode = (NMode::EEnum)dirType; - } - UString pathU; - if (key.QueryValue(kWorkDirPath, pathU) == ERROR_SUCCESS) - Path = us2fs(pathU); - else - { - Path.Empty(); - if (Mode == NMode::kSpecified) - Mode = NMode::kSystem; - } - key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly); -} - -} - -static LPCTSTR const kCascadedMenu = TEXT("CascadedMenu"); -static LPCTSTR const kContextMenu = TEXT("ContextMenu"); -static LPCTSTR const kMenuIcons = TEXT("MenuIcons"); -static LPCTSTR const kElimDup = TEXT("ElimDupExtract"); -static LPCTSTR const kWriteZoneId = TEXT("WriteZoneIdExtract"); - -void CContextMenuInfo::Save() const -{ - CS_LOCK - CKey key; - CreateMainKey(key, kOptionsInfoKeyName); - - Key_Set_BoolPair(key, kCascadedMenu, Cascaded); - Key_Set_BoolPair(key, kMenuIcons, MenuIcons); - Key_Set_BoolPair(key, kElimDup, ElimDup); - - Key_Set_UInt32(key, kWriteZoneId, WriteZone); - - if (Flags_Def) - key.SetValue(kContextMenu, Flags); -} - -void CContextMenuInfo::Load() -{ - Cascaded.Val = true; - Cascaded.Def = false; - - MenuIcons.Val = false; - MenuIcons.Def = false; - - ElimDup.Val = true; - ElimDup.Def = false; - - WriteZone = (UInt32)(Int32)-1; - - /* we can disable email items by default, - because email code doesn't work in some systems */ - Flags = (UInt32)(Int32)-1 - /* - & ~NContextMenuFlags::kCompressEmail - & ~NContextMenuFlags::kCompressTo7zEmail - & ~NContextMenuFlags::kCompressToZipEmail - */ - ; - Flags_Def = false; - - CS_LOCK - - CKey key; - if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS) - return; - - Key_Get_BoolPair_true(key, kCascadedMenu, Cascaded); - Key_Get_BoolPair_true(key, kElimDup, ElimDup); - Key_Get_BoolPair(key, kMenuIcons, MenuIcons); - - Key_Get_UInt32(key, kWriteZoneId, WriteZone); - - Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); -} +// ZipRegistry.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/Registry.h" +#include "../../../Windows/Synchronization.h" + +// #include "../Explorer/ContextMenuFlags.h" +#include "ZipRegistry.h" + +using namespace NWindows; +using namespace NRegistry; + +static NSynchronization::CCriticalSection g_CS; +#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS); + +static LPCTSTR const kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR); + +static CSysString GetKeyPath(LPCTSTR path) { return kCuPrefix + (CSysString)path; } + +static LONG OpenMainKey(CKey &key, LPCTSTR keyName) +{ + return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ); +} + +static LONG CreateMainKey(CKey &key, LPCTSTR keyName) +{ + return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName)); +} + +static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value) +{ + if (value == (UInt32)(Int32)-1) + key.DeleteValue(name); + else + key.SetValue(name, value); +} + + +static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value) +{ + value = (UInt32)(Int32)-1; + key.GetValue_UInt32_IfOk(name, value); +} + + +static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b) +{ + if (b.Def) + key.SetValue(name, b.Val); +} + +static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val) +{ + bool oldVal = false; + if (key.GetValue_bool_IfOk(name, oldVal) == ERROR_SUCCESS) + if (val == oldVal) + return; + key.SetValue(name, val); +} + +static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoolPair &b) +{ + if (b.Def) + Key_Set_bool_if_Changed(key, name, b.Val); + else + key.DeleteValue(name); +} + +static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b) +{ + b.Val = false; + b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS); +} + +static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b) +{ + b.Val = true; + b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS); +} + +namespace NExtract +{ + +static LPCTSTR const kKeyName = TEXT("Extraction"); + +static LPCTSTR const kExtractMode = TEXT("ExtractMode"); +static LPCTSTR const kOverwriteMode = TEXT("OverwriteMode"); +static LPCTSTR const kShowPassword = TEXT("ShowPassword"); +static LPCTSTR const kPathHistory = TEXT("PathHistory"); +static LPCTSTR const kSplitDest = TEXT("SplitDest"); +static LPCTSTR const kElimDup = TEXT("ElimDup"); +// static LPCTSTR const kAltStreams = TEXT("AltStreams"); +static LPCTSTR const kNtSecur = TEXT("Security"); +static LPCTSTR const kMemLimit = TEXT("MemLimit"); + +void CInfo::Save() const +{ + CS_LOCK + CKey key; + CreateMainKey(key, kKeyName); + + if (PathMode_Force) + key.SetValue(kExtractMode, (UInt32)PathMode); + if (OverwriteMode_Force) + key.SetValue(kOverwriteMode, (UInt32)OverwriteMode); + + Key_Set_BoolPair(key, kSplitDest, SplitDest); + Key_Set_BoolPair(key, kElimDup, ElimDup); + // Key_Set_BoolPair(key, kAltStreams, AltStreams); + Key_Set_BoolPair(key, kNtSecur, NtSecurity); + Key_Set_BoolPair(key, kShowPassword, ShowPassword); + + key.RecurseDeleteKey(kPathHistory); + key.SetValue_Strings(kPathHistory, Paths); +} + +void Save_ShowPassword(bool showPassword) +{ + CS_LOCK + CKey key; + CreateMainKey(key, kKeyName); + key.SetValue(kShowPassword, showPassword); +} + +void Save_LimitGB(UInt32 limit_GB) +{ + CS_LOCK + CKey key; + CreateMainKey(key, kKeyName); + Key_Set_UInt32(key, kMemLimit, limit_GB); +} + +void CInfo::Load() +{ + PathMode = NPathMode::kCurPaths; + PathMode_Force = false; + OverwriteMode = NOverwriteMode::kAsk; + OverwriteMode_Force = false; + + SplitDest.Val = true; + + Paths.Clear(); + + CS_LOCK + CKey key; + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return; + + key.GetValue_Strings(kPathHistory, Paths); + UInt32 v; + if (key.GetValue_UInt32_IfOk(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths) + { + PathMode = (NPathMode::EEnum)v; + PathMode_Force = true; + } + if (key.GetValue_UInt32_IfOk(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting) + { + OverwriteMode = (NOverwriteMode::EEnum)v; + OverwriteMode_Force = true; + } + + Key_Get_BoolPair_true(key, kSplitDest, SplitDest); + + Key_Get_BoolPair(key, kElimDup, ElimDup); + // Key_Get_BoolPair(key, kAltStreams, AltStreams); + Key_Get_BoolPair(key, kNtSecur, NtSecurity); + Key_Get_BoolPair(key, kShowPassword, ShowPassword); +} + +bool Read_ShowPassword() +{ + CS_LOCK + CKey key; + bool showPassword = false; + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return showPassword; + key.GetValue_bool_IfOk(kShowPassword, showPassword); + return showPassword; +} + +UInt32 Read_LimitGB() +{ + CS_LOCK + CKey key; + UInt32 v = (UInt32)(Int32)-1; + if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS) + key.GetValue_UInt32_IfOk(kMemLimit, v); + return v; +} + +} + +namespace NCompression +{ + +static LPCTSTR const kKeyName = TEXT("Compression"); + +static LPCTSTR const kArcHistory = TEXT("ArcHistory"); +static LPCWSTR const kArchiver = L"Archiver"; +static LPCTSTR const kShowPassword = TEXT("ShowPassword"); +static LPCTSTR const kEncryptHeaders = TEXT("EncryptHeaders"); + +static LPCTSTR const kOptionsKeyName = TEXT("Options"); + +static LPCTSTR const kLevel = TEXT("Level"); +static LPCTSTR const kDictionary = TEXT("Dictionary"); +// static LPCTSTR const kDictionaryChain = TEXT("DictionaryChain"); +static LPCTSTR const kOrder = TEXT("Order"); +static LPCTSTR const kBlockSize = TEXT("BlockSize"); +static LPCTSTR const kNumThreads = TEXT("NumThreads"); +static LPCWSTR const kMethod = L"Method"; +static LPCWSTR const kOptions = L"Options"; +static LPCWSTR const kEncryptionMethod = L"EncryptionMethod"; + +static LPCTSTR const kNtSecur = TEXT("Security"); +static LPCTSTR const kAltStreams = TEXT("AltStreams"); +static LPCTSTR const kHardLinks = TEXT("HardLinks"); +static LPCTSTR const kSymLinks = TEXT("SymLinks"); +static LPCTSTR const kPreserveATime = TEXT("PreserveATime"); + +static LPCTSTR const kTimePrec = TEXT("TimePrec"); +static LPCTSTR const kMTime = TEXT("MTime"); +static LPCTSTR const kATime = TEXT("ATime"); +static LPCTSTR const kCTime = TEXT("CTime"); +static LPCTSTR const kSetArcMTime = TEXT("SetArcMTime"); + +static void SetRegString(CKey &key, LPCWSTR name, const UString &value) +{ + if (value.IsEmpty()) + key.DeleteValue(name); + else + key.SetValue(name, value); +} + +static void GetRegString(CKey &key, LPCWSTR name, UString &value) +{ + if (key.QueryValue(name, value) != ERROR_SUCCESS) + value.Empty(); +} + +static LPCWSTR const kMemUse = L"MemUse" + #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) + L"32"; + #else + L"64"; + #endif + +void CInfo::Save() const +{ + CS_LOCK + + CKey key; + CreateMainKey(key, kKeyName); + + Key_Set_BoolPair_Delete_IfNotDef (key, kNtSecur, NtSecurity); + Key_Set_BoolPair_Delete_IfNotDef (key, kAltStreams, AltStreams); + Key_Set_BoolPair_Delete_IfNotDef (key, kHardLinks, HardLinks); + Key_Set_BoolPair_Delete_IfNotDef (key, kSymLinks, SymLinks); + Key_Set_BoolPair_Delete_IfNotDef (key, kPreserveATime, PreserveATime); + + key.SetValue(kShowPassword, ShowPassword); + key.SetValue(kLevel, (UInt32)Level); + key.SetValue(kArchiver, ArcType); + key.SetValue(kShowPassword, ShowPassword); + key.SetValue(kEncryptHeaders, EncryptHeaders); + key.RecurseDeleteKey(kArcHistory); + key.SetValue_Strings(kArcHistory, ArcPaths); + + key.RecurseDeleteKey(kOptionsKeyName); + { + CKey optionsKey; + optionsKey.Create(key, kOptionsKeyName); + FOR_VECTOR (i, Formats) + { + const CFormatOptions &fo = Formats[i]; + CKey fk; + fk.Create(optionsKey, fo.FormatID); + + SetRegString(fk, kMethod, fo.Method); + SetRegString(fk, kOptions, fo.Options); + SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); + SetRegString(fk, kMemUse, fo.MemUse); + + Key_Set_UInt32(fk, kLevel, fo.Level); + Key_Set_UInt32(fk, kDictionary, fo.Dictionary); + // Key_Set_UInt32(fk, kDictionaryChain, fo.DictionaryChain); + Key_Set_UInt32(fk, kOrder, fo.Order); + Key_Set_UInt32(fk, kBlockSize, fo.BlockLogSize); + Key_Set_UInt32(fk, kNumThreads, fo.NumThreads); + + Key_Set_UInt32(fk, kTimePrec, fo.TimePrec); + Key_Set_BoolPair_Delete_IfNotDef (fk, kMTime, fo.MTime); + Key_Set_BoolPair_Delete_IfNotDef (fk, kATime, fo.ATime); + Key_Set_BoolPair_Delete_IfNotDef (fk, kCTime, fo.CTime); + Key_Set_BoolPair_Delete_IfNotDef (fk, kSetArcMTime, fo.SetArcMTime); + } + } +} + +void CInfo::Load() +{ + ArcPaths.Clear(); + Formats.Clear(); + + Level = 5; + ArcType = L"7z"; + ShowPassword = false; + EncryptHeaders = false; + + CS_LOCK + CKey key; + + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return; + + Key_Get_BoolPair(key, kNtSecur, NtSecurity); + Key_Get_BoolPair(key, kAltStreams, AltStreams); + Key_Get_BoolPair(key, kHardLinks, HardLinks); + Key_Get_BoolPair(key, kSymLinks, SymLinks); + Key_Get_BoolPair(key, kPreserveATime, PreserveATime); + + key.GetValue_Strings(kArcHistory, ArcPaths); + + { + CKey optionsKey; + if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS) + { + CSysStringVector formatIDs; + optionsKey.EnumKeys(formatIDs); + FOR_VECTOR (i, formatIDs) + { + CKey fk; + CFormatOptions fo; + fo.FormatID = formatIDs[i]; + if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS) + { + GetRegString(fk, kMethod, fo.Method); + GetRegString(fk, kOptions, fo.Options); + GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); + GetRegString(fk, kMemUse, fo.MemUse); + + Key_Get_UInt32(fk, kLevel, fo.Level); + Key_Get_UInt32(fk, kDictionary, fo.Dictionary); + // Key_Get_UInt32(fk, kDictionaryChain, fo.DictionaryChain); + Key_Get_UInt32(fk, kOrder, fo.Order); + Key_Get_UInt32(fk, kBlockSize, fo.BlockLogSize); + Key_Get_UInt32(fk, kNumThreads, fo.NumThreads); + + Key_Get_UInt32(fk, kTimePrec, fo.TimePrec); + Key_Get_BoolPair(fk, kMTime, fo.MTime); + Key_Get_BoolPair(fk, kATime, fo.ATime); + Key_Get_BoolPair(fk, kCTime, fo.CTime); + Key_Get_BoolPair(fk, kSetArcMTime, fo.SetArcMTime); + + Formats.Add(fo); + } + } + } + } + + UString a; + if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) + ArcType = a; + key.GetValue_UInt32_IfOk(kLevel, Level); + key.GetValue_bool_IfOk(kShowPassword, ShowPassword); + key.GetValue_bool_IfOk(kEncryptHeaders, EncryptHeaders); +} + + +static bool ParseMemUse(const wchar_t *s, CMemUse &mu) +{ + mu.Clear(); + + bool percentMode = false; + { + const wchar_t c = *s; + if (MyCharLower_Ascii(c) == 'p') + { + percentMode = true; + s++; + } + } + const wchar_t *end; + UInt64 number = ConvertStringToUInt64(s, &end); + if (end == s) + return false; + + wchar_t c = *end; + + if (percentMode) + { + if (c != 0) + return false; + mu.IsPercent = true; + mu.Val = number; + return true; + } + + if (c == 0) + { + mu.Val = number; + return true; + } + + c = MyCharLower_Ascii(c); + + const wchar_t c1 = end[1]; + + if (c == '%') + { + if (c1 != 0) + return false; + mu.IsPercent = true; + mu.Val = number; + return true; + } + + if (c == 'b') + { + if (c1 != 0) + return false; + mu.Val = number; + return true; + } + + if (c1 != 0) + if (MyCharLower_Ascii(c1) != 'b' || end[2] != 0) + return false; + + unsigned numBits; + switch (c) + { + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + default: return false; + } + if (number >= ((UInt64)1 << (64 - numBits))) + return false; + mu.Val = number << numBits; + return true; +} + + +void CMemUse::Parse(const UString &s) +{ + IsDefined = ParseMemUse(s, *this); +} + +/* +void MemLimit_Save(const UString &s) +{ + CS_LOCK + CKey key; + CreateMainKey(key, kKeyName); + SetRegString(key, kMemUse, s); +} + +bool MemLimit_Load(NCompression::CMemUse &mu) +{ + mu.Clear(); + UString a; + { + CS_LOCK + CKey key; + if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) + return false; + if (key.QueryValue(kMemUse, a) != ERROR_SUCCESS) + return false; + } + if (a.IsEmpty()) + return false; + mu.Parse(a); + return mu.IsDefined; +} +*/ + +} + +static LPCTSTR const kOptionsInfoKeyName = TEXT("Options"); + +namespace NWorkDir +{ +static LPCTSTR const kWorkDirType = TEXT("WorkDirType"); +static LPCWSTR const kWorkDirPath = L"WorkDirPath"; +static LPCTSTR const kTempRemovableOnly = TEXT("TempRemovableOnly"); + + +void CInfo::Save()const +{ + CS_LOCK + CKey key; + CreateMainKey(key, kOptionsInfoKeyName); + key.SetValue(kWorkDirType, (UInt32)Mode); + key.SetValue(kWorkDirPath, fs2us(Path)); + key.SetValue(kTempRemovableOnly, ForRemovableOnly); +} + +void CInfo::Load() +{ + SetDefault(); + + CS_LOCK + CKey key; + if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS) + return; + + UInt32 dirType; + if (key.GetValue_UInt32_IfOk(kWorkDirType, dirType) != ERROR_SUCCESS) + return; + switch (dirType) + { + case NMode::kSystem: + case NMode::kCurrent: + case NMode::kSpecified: + Mode = (NMode::EEnum)dirType; + } + UString pathU; + if (key.QueryValue(kWorkDirPath, pathU) == ERROR_SUCCESS) + Path = us2fs(pathU); + else + { + Path.Empty(); + if (Mode == NMode::kSpecified) + Mode = NMode::kSystem; + } + key.GetValue_bool_IfOk(kTempRemovableOnly, ForRemovableOnly); +} + +} + +static LPCTSTR const kCascadedMenu = TEXT("CascadedMenu"); +static LPCTSTR const kContextMenu = TEXT("ContextMenu"); +static LPCTSTR const kMenuIcons = TEXT("MenuIcons"); +static LPCTSTR const kElimDup = TEXT("ElimDupExtract"); +static LPCTSTR const kWriteZoneId = TEXT("WriteZoneIdExtract"); + +void CContextMenuInfo::Save() const +{ + CS_LOCK + CKey key; + CreateMainKey(key, kOptionsInfoKeyName); + + Key_Set_BoolPair(key, kCascadedMenu, Cascaded); + Key_Set_BoolPair(key, kMenuIcons, MenuIcons); + Key_Set_BoolPair(key, kElimDup, ElimDup); + + Key_Set_UInt32(key, kWriteZoneId, WriteZone); + + if (Flags_Def) + key.SetValue(kContextMenu, Flags); +} + +void CContextMenuInfo::Load() +{ + Cascaded.Val = true; + Cascaded.Def = false; + + MenuIcons.Val = false; + MenuIcons.Def = false; + + ElimDup.Val = true; + ElimDup.Def = false; + + WriteZone = (UInt32)(Int32)-1; + + /* we can disable email items by default, + because email code doesn't work in some systems */ + Flags = (UInt32)(Int32)-1 + /* + & ~NContextMenuFlags::kCompressEmail + & ~NContextMenuFlags::kCompressTo7zEmail + & ~NContextMenuFlags::kCompressToZipEmail + */ + ; + Flags_Def = false; + + CS_LOCK + + CKey key; + if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS) + return; + + Key_Get_BoolPair_true(key, kCascadedMenu, Cascaded); + Key_Get_BoolPair_true(key, kElimDup, ElimDup); + Key_Get_BoolPair(key, kMenuIcons, MenuIcons); + + Key_Get_UInt32(key, kWriteZoneId, WriteZone); + + Flags_Def = (key.GetValue_UInt32_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); +} diff --git a/CPP/7zip/UI/Common/ZipRegistry.h b/CPP/7zip/UI/Common/ZipRegistry.h index 842c95a2f..ce084f4ea 100644 --- a/CPP/7zip/UI/Common/ZipRegistry.h +++ b/CPP/7zip/UI/Common/ZipRegistry.h @@ -1,212 +1,212 @@ -// ZipRegistry.h - -#ifndef ZIP7_INC_ZIP_REGISTRY_H -#define ZIP7_INC_ZIP_REGISTRY_H - -#include "../../../Common/MyTypes.h" -#include "../../../Common/MyString.h" - -#include "../../Common/MethodProps.h" - -#include "ExtractMode.h" - -/* -CBoolPair::Def in writing functions means: - if ( CBoolPair::Def ), we write CBoolPair::Val - if ( !CBoolPair::Def ) - { - in NCompression functions we delete registry value - in another functions we do nothing - } -*/ - -namespace NExtract -{ - struct CInfo - { - NPathMode::EEnum PathMode; - NOverwriteMode::EEnum OverwriteMode; - bool PathMode_Force; - bool OverwriteMode_Force; - - CBoolPair SplitDest; - CBoolPair ElimDup; - // CBoolPair AltStreams; - CBoolPair NtSecurity; - CBoolPair ShowPassword; - - UStringVector Paths; - - void Save() const; - void Load(); - }; - - void Save_ShowPassword(bool showPassword); - bool Read_ShowPassword(); - - void Save_LimitGB(UInt32 limit_GB); - UInt32 Read_LimitGB(); -} - -namespace NCompression -{ - struct CMemUse - { - // UString Str; - bool IsDefined; - bool IsPercent; - UInt64 Val; - - CMemUse(): - IsDefined(false), - IsPercent(false), - Val(0) - {} - - void Clear() - { - // Str.Empty(); - IsDefined = false; - IsPercent = false; - Val = 0; - } - - UInt64 GetBytes(UInt64 ramSize) const - { - if (!IsPercent) - return Val; - return Calc_From_Val_Percents(ramSize, Val); - } - void Parse(const UString &s); - }; - - struct CFormatOptions - { - UInt32 Level; - UInt32 Dictionary; - // UInt32 DictionaryChain; - UInt32 Order; - UInt32 BlockLogSize; - UInt32 NumThreads; - - UInt32 TimePrec; - CBoolPair MTime; - CBoolPair ATime; - CBoolPair CTime; - CBoolPair SetArcMTime; - - CSysString FormatID; - UString Method; - UString Options; - UString EncryptionMethod; - UString MemUse; - - void Reset_TimePrec() - { - TimePrec = (UInt32)(Int32)-1; - } - - bool IsSet_TimePrec() const - { - return TimePrec != (UInt32)(Int32)-1; - } - - - void Reset_BlockLogSize() - { - BlockLogSize = (UInt32)(Int32)-1; - } - - void ResetForLevelChange() - { - BlockLogSize = NumThreads = Level = Dictionary = Order = (UInt32)(Int32)-1; - // DictionaryChain = (UInt32)(Int32)-1; - Method.Empty(); - // Options.Empty(); - // EncryptionMethod.Empty(); - } - CFormatOptions() - { - // TimePrec = 0; - Reset_TimePrec(); - ResetForLevelChange(); - } - }; - - struct CInfo - { - UInt32 Level; - bool ShowPassword; - bool EncryptHeaders; - - CBoolPair NtSecurity; - CBoolPair AltStreams; - CBoolPair HardLinks; - CBoolPair SymLinks; - - CBoolPair PreserveATime; - - UString ArcType; - UStringVector ArcPaths; - - CObjectVector Formats; - - void Save() const; - void Load(); - }; -} - -namespace NWorkDir -{ - namespace NMode - { - enum EEnum - { - kSystem, - kCurrent, - kSpecified - }; - } - struct CInfo - { - NMode::EEnum Mode; - bool ForRemovableOnly; - FString Path; - - void SetForRemovableOnlyDefault() { ForRemovableOnly = true; } - void SetDefault() - { - Mode = NMode::kSystem; - Path.Empty(); - SetForRemovableOnlyDefault(); - } - - void Save() const; - void Load(); - }; -} - - -struct CContextMenuInfo -{ - CBoolPair Cascaded; - CBoolPair MenuIcons; - CBoolPair ElimDup; - - bool Flags_Def; - UInt32 Flags; - UInt32 WriteZone; - - /* - CContextMenuInfo(): - Flags_Def(0), - WriteZone((UInt32)(Int32)-1), - Flags((UInt32)(Int32)-1) - {} - */ - - void Save() const; - void Load(); -}; - -#endif +// ZipRegistry.h + +#ifndef ZIP7_INC_ZIP_REGISTRY_H +#define ZIP7_INC_ZIP_REGISTRY_H + +#include "../../../Common/MyTypes.h" +#include "../../../Common/MyString.h" + +#include "../../Common/MethodProps.h" + +#include "ExtractMode.h" + +/* +CBoolPair::Def in writing functions means: + if ( CBoolPair::Def ), we write CBoolPair::Val + if ( !CBoolPair::Def ) + { + in NCompression functions we delete registry value + in another functions we do nothing + } +*/ + +namespace NExtract +{ + struct CInfo + { + NPathMode::EEnum PathMode; + NOverwriteMode::EEnum OverwriteMode; + bool PathMode_Force; + bool OverwriteMode_Force; + + CBoolPair SplitDest; + CBoolPair ElimDup; + // CBoolPair AltStreams; + CBoolPair NtSecurity; + CBoolPair ShowPassword; + + UStringVector Paths; + + void Save() const; + void Load(); + }; + + void Save_ShowPassword(bool showPassword); + bool Read_ShowPassword(); + + void Save_LimitGB(UInt32 limit_GB); + UInt32 Read_LimitGB(); +} + +namespace NCompression +{ + struct CMemUse + { + // UString Str; + bool IsDefined; + bool IsPercent; + UInt64 Val; + + CMemUse(): + IsDefined(false), + IsPercent(false), + Val(0) + {} + + void Clear() + { + // Str.Empty(); + IsDefined = false; + IsPercent = false; + Val = 0; + } + + UInt64 GetBytes(UInt64 ramSize) const + { + if (!IsPercent) + return Val; + return Calc_From_Val_Percents(ramSize, Val); + } + void Parse(const UString &s); + }; + + struct CFormatOptions + { + UInt32 Level; + UInt32 Dictionary; + // UInt32 DictionaryChain; + UInt32 Order; + UInt32 BlockLogSize; + UInt32 NumThreads; + + UInt32 TimePrec; + CBoolPair MTime; + CBoolPair ATime; + CBoolPair CTime; + CBoolPair SetArcMTime; + + CSysString FormatID; + UString Method; + UString Options; + UString EncryptionMethod; + UString MemUse; + + void Reset_TimePrec() + { + TimePrec = (UInt32)(Int32)-1; + } + + bool IsSet_TimePrec() const + { + return TimePrec != (UInt32)(Int32)-1; + } + + + void Reset_BlockLogSize() + { + BlockLogSize = (UInt32)(Int32)-1; + } + + void ResetForLevelChange() + { + BlockLogSize = NumThreads = Level = Dictionary = Order = (UInt32)(Int32)-1; + // DictionaryChain = (UInt32)(Int32)-1; + Method.Empty(); + // Options.Empty(); + // EncryptionMethod.Empty(); + } + CFormatOptions() + { + // TimePrec = 0; + Reset_TimePrec(); + ResetForLevelChange(); + } + }; + + struct CInfo + { + UInt32 Level; + bool ShowPassword; + bool EncryptHeaders; + + CBoolPair NtSecurity; + CBoolPair AltStreams; + CBoolPair HardLinks; + CBoolPair SymLinks; + + CBoolPair PreserveATime; + + UString ArcType; + UStringVector ArcPaths; + + CObjectVector Formats; + + void Save() const; + void Load(); + }; +} + +namespace NWorkDir +{ + namespace NMode + { + enum EEnum + { + kSystem, + kCurrent, + kSpecified + }; + } + struct CInfo + { + NMode::EEnum Mode; + bool ForRemovableOnly; + FString Path; + + void SetForRemovableOnlyDefault() { ForRemovableOnly = true; } + void SetDefault() + { + Mode = NMode::kSystem; + Path.Empty(); + SetForRemovableOnlyDefault(); + } + + void Save() const; + void Load(); + }; +} + + +struct CContextMenuInfo +{ + CBoolPair Cascaded; + CBoolPair MenuIcons; + CBoolPair ElimDup; + + bool Flags_Def; + UInt32 Flags; + UInt32 WriteZone; + + /* + CContextMenuInfo(): + Flags_Def(0), + WriteZone((UInt32)(Int32)-1), + Flags((UInt32)(Int32)-1) + {} + */ + + void Save() const; + void Load(); +}; + +#endif diff --git a/CPP/7zip/UI/Console/BenchCon.cpp b/CPP/7zip/UI/Console/BenchCon.cpp index 77aee286b..113f584a2 100644 --- a/CPP/7zip/UI/Console/BenchCon.cpp +++ b/CPP/7zip/UI/Console/BenchCon.cpp @@ -1,41 +1,41 @@ -// BenchCon.cpp - -#include "StdAfx.h" - -#include "../Common/Bench.h" - -#include "BenchCon.h" -#include "ConsoleClose.h" - -struct CPrintBenchCallback Z7_final: public IBenchPrintCallback -{ - FILE *_file; - - void Print(const char *s) Z7_override; - void NewLine() Z7_override; - HRESULT CheckBreak() Z7_override; -}; - -void CPrintBenchCallback::Print(const char *s) -{ - fputs(s, _file); -} - -void CPrintBenchCallback::NewLine() -{ - fputc('\n', _file); -} - -HRESULT CPrintBenchCallback::CheckBreak() -{ - return NConsoleClose::TestBreakSignal() ? E_ABORT: S_OK; -} - -HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &props, UInt32 numIterations, FILE *f) -{ - CPrintBenchCallback callback; - callback._file = f; - return Bench(EXTERNAL_CODECS_LOC_VARS - &callback, NULL, props, numIterations, true); -} +// BenchCon.cpp + +#include "StdAfx.h" + +#include "../Common/Bench.h" + +#include "BenchCon.h" +#include "ConsoleClose.h" + +struct CPrintBenchCallback Z7_final: public IBenchPrintCallback +{ + FILE *_file; + + void Print(const char *s) Z7_override; + void NewLine() Z7_override; + HRESULT CheckBreak() Z7_override; +}; + +void CPrintBenchCallback::Print(const char *s) +{ + fputs(s, _file); +} + +void CPrintBenchCallback::NewLine() +{ + fputc('\n', _file); +} + +HRESULT CPrintBenchCallback::CheckBreak() +{ + return NConsoleClose::TestBreakSignal() ? E_ABORT: S_OK; +} + +HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &props, UInt32 numIterations, FILE *f) +{ + CPrintBenchCallback callback; + callback._file = f; + return Bench(EXTERNAL_CODECS_LOC_VARS + &callback, NULL, props, numIterations, true); +} diff --git a/CPP/7zip/UI/Console/BenchCon.h b/CPP/7zip/UI/Console/BenchCon.h index 8912bced6..844cc2a79 100644 --- a/CPP/7zip/UI/Console/BenchCon.h +++ b/CPP/7zip/UI/Console/BenchCon.h @@ -1,14 +1,14 @@ -// BenchCon.h - -#ifndef ZIP7_INC_BENCH_CON_H -#define ZIP7_INC_BENCH_CON_H - -#include - -#include "../../Common/CreateCoder.h" -#include "../../UI/Common/Property.h" - -HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &props, UInt32 numIterations, FILE *f); - -#endif +// BenchCon.h + +#ifndef ZIP7_INC_BENCH_CON_H +#define ZIP7_INC_BENCH_CON_H + +#include + +#include "../../Common/CreateCoder.h" +#include "../../UI/Common/Property.h" + +HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &props, UInt32 numIterations, FILE *f); + +#endif diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp index 7ea9887a3..0ca250d5a 100644 --- a/CPP/7zip/UI/Console/Console.dsp +++ b/CPP/7zip/UI/Console/Console.dsp @@ -1,1052 +1,1052 @@ -# Microsoft Developer Studio Project File - Name="Console" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=Console - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Console.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Console.mak" CFG="Console - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Console - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "Console - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE "Console - Win32 ReleaseU" (based on "Win32 (x86) Console Application") -!MESSAGE "Console - Win32 DebugU" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Console - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /GF /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7z.exe" /OPT:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Console - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept /ignore:4033 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Console___Win32_ReleaseU" -# PROP BASE Intermediate_Dir "Console___Win32_ReleaseU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /Gz /MD /W3 /GX /O1 /I "../../../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7z.exe" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7zn.exe" /OPT:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Console - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Console___Win32_DebugU" -# PROP BASE Intermediate_Dir "Console___Win32_DebugU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /Gz /W3 /Gm /GX /ZI /Od /I "../../../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c -# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "Console - Win32 Release" -# Name "Console - Win32 Debug" -# Name "Console - Win32 ReleaseU" -# Name "Console - Win32 DebugU" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Console" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\BenchCon.cpp -# End Source File -# Begin Source File - -SOURCE=.\BenchCon.h -# End Source File -# Begin Source File - -SOURCE=.\ConsoleClose.cpp -# End Source File -# Begin Source File - -SOURCE=.\ConsoleClose.h -# End Source File -# Begin Source File - -SOURCE=.\ExtractCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=.\HashCon.cpp -# End Source File -# Begin Source File - -SOURCE=.\HashCon.h -# End Source File -# Begin Source File - -SOURCE=.\List.cpp -# End Source File -# Begin Source File - -SOURCE=.\List.h -# End Source File -# Begin Source File - -SOURCE=.\Main.cpp -# End Source File -# Begin Source File - -SOURCE=.\MainAr.cpp -# End Source File -# Begin Source File - -SOURCE=.\OpenCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=.\OpenCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=.\PercentPrinter.cpp -# End Source File -# Begin Source File - -SOURCE=.\PercentPrinter.h -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackConsole.cpp -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackConsole.h -# End Source File -# Begin Source File - -SOURCE=.\UserInputUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\UserInputUtils.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common0.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer2.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyGuidDef.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdInStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StdOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Common\ArchiveCommandLine.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveCommandLine.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Bench.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\Bench.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\Common\IFileExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Property.h -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\TempFiles.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\TempFiles.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Update.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\Update.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.h -# End Source File -# End Group -# Begin Group "7-zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\RegisterArc.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c - -!IF "$(CFG)" == "Console - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Console - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "Console - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "ArchiveCommon" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# Begin Group "Asm" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\7zAsm.asm -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\Asm\x86\7zCrcOpt.asm - -!IF "$(CFG)" == "Console - Win32 Release" - -# Begin Custom Build -OutDir=.\Release -InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm -InputName=7zCrcOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Console - Win32 Debug" - -# Begin Custom Build -OutDir=.\Debug -InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm -InputName=7zCrcOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU" - -# Begin Custom Build -OutDir=.\ReleaseU -InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm -InputName=7zCrcOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Console - Win32 DebugU" - -# Begin Custom Build -OutDir=.\DebugU -InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm -InputName=7zCrcOpt - -"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# Begin Group "Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="Console" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Console - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Console.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Console.mak" CFG="Console - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Console - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Console - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "Console - Win32 ReleaseU" (based on "Win32 (x86) Console Application") +!MESSAGE "Console - Win32 DebugU" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Console - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /GF /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7z.exe" /OPT:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Console - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept /ignore:4033 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Console___Win32_ReleaseU" +# PROP BASE Intermediate_Dir "Console___Win32_ReleaseU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /Gz /MD /W3 /GX /O1 /I "../../../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7z.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7zn.exe" /OPT:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Console - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Console___Win32_DebugU" +# PROP BASE Intermediate_Dir "Console___Win32_DebugU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /Gz /W3 /Gm /GX /ZI /Od /I "../../../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c +# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Console - Win32 Release" +# Name "Console - Win32 Debug" +# Name "Console - Win32 ReleaseU" +# Name "Console - Win32 DebugU" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Console" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\BenchCon.cpp +# End Source File +# Begin Source File + +SOURCE=.\BenchCon.h +# End Source File +# Begin Source File + +SOURCE=.\ConsoleClose.cpp +# End Source File +# Begin Source File + +SOURCE=.\ConsoleClose.h +# End Source File +# Begin Source File + +SOURCE=.\ExtractCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=.\HashCon.cpp +# End Source File +# Begin Source File + +SOURCE=.\HashCon.h +# End Source File +# Begin Source File + +SOURCE=.\List.cpp +# End Source File +# Begin Source File + +SOURCE=.\List.h +# End Source File +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# Begin Source File + +SOURCE=.\MainAr.cpp +# End Source File +# Begin Source File + +SOURCE=.\OpenCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=.\OpenCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=.\PercentPrinter.cpp +# End Source File +# Begin Source File + +SOURCE=.\PercentPrinter.h +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackConsole.cpp +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackConsole.h +# End Source File +# Begin Source File + +SOURCE=.\UserInputUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\UserInputUtils.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common0.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyGuidDef.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdInStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StdOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Common\ArchiveCommandLine.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveCommandLine.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Bench.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\Bench.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\Common\IFileExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Property.h +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\TempFiles.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\TempFiles.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Update.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\Update.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.h +# End Source File +# End Group +# Begin Group "7-zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\RegisterArc.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c + +!IF "$(CFG)" == "Console - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Console - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "Console - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "ArchiveCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "Asm" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\7zAsm.asm +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\Asm\x86\7zCrcOpt.asm + +!IF "$(CFG)" == "Console - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm +InputName=7zCrcOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "Console - Win32 Debug" + +# Begin Custom Build +OutDir=.\Debug +InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm +InputName=7zCrcOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU" + +# Begin Custom Build +OutDir=.\ReleaseU +InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm +InputName=7zCrcOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "Console - Win32 DebugU" + +# Begin Custom Build +OutDir=.\DebugU +InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm +InputName=7zCrcOpt + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/UI/Console/Console.dsw b/CPP/7zip/UI/Console/Console.dsw index 6e37f110a..0d93da2f6 100644 --- a/CPP/7zip/UI/Console/Console.dsw +++ b/CPP/7zip/UI/Console/Console.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Console"=".\Console.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Console"=".\Console.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/UI/Console/Console.mak b/CPP/7zip/UI/Console/Console.mak index f54d62102..4effea609 100644 --- a/CPP/7zip/UI/Console/Console.mak +++ b/CPP/7zip/UI/Console/Console.mak @@ -1,46 +1,46 @@ -MY_CONSOLE = 1 - -!IFNDEF UNDER_CE -CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE -# -DZ7_LONG_PATH -DZ7_LARGE_PAGES -!ENDIF - -CONSOLE_OBJS = \ - $O\BenchCon.obj \ - $O\ConsoleClose.obj \ - $O\ExtractCallbackConsole.obj \ - $O\HashCon.obj \ - $O\List.obj \ - $O\Main.obj \ - $O\MainAr.obj \ - $O\OpenCallbackConsole.obj \ - $O\PercentPrinter.obj \ - $O\UpdateCallbackConsole.obj \ - $O\UserInputUtils.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveCommandLine.obj \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveOpenCallback.obj \ - $O\Bench.obj \ - $O\DefaultName.obj \ - $O\EnumDirItems.obj \ - $O\Extract.obj \ - $O\ExtractingFilePath.obj \ - $O\HashCalc.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - $O\PropIDUtils.obj \ - $O\SetProperties.obj \ - $O\SortUtils.obj \ - $O\TempFiles.obj \ - $O\Update.obj \ - $O\UpdateAction.obj \ - $O\UpdateCallback.obj \ - $O\UpdatePair.obj \ - $O\UpdateProduce.obj \ - -C_OBJS = $(C_OBJS) \ - $O\DllSecur.obj \ - -# we need empty line after last line above +MY_CONSOLE = 1 + +!IFNDEF UNDER_CE +CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE +# -DZ7_LONG_PATH -DZ7_LARGE_PAGES +!ENDIF + +CONSOLE_OBJS = \ + $O\BenchCon.obj \ + $O\ConsoleClose.obj \ + $O\ExtractCallbackConsole.obj \ + $O\HashCon.obj \ + $O\List.obj \ + $O\Main.obj \ + $O\MainAr.obj \ + $O\OpenCallbackConsole.obj \ + $O\PercentPrinter.obj \ + $O\UpdateCallbackConsole.obj \ + $O\UserInputUtils.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveCommandLine.obj \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveOpenCallback.obj \ + $O\Bench.obj \ + $O\DefaultName.obj \ + $O\EnumDirItems.obj \ + $O\Extract.obj \ + $O\ExtractingFilePath.obj \ + $O\HashCalc.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + $O\PropIDUtils.obj \ + $O\SetProperties.obj \ + $O\SortUtils.obj \ + $O\TempFiles.obj \ + $O\Update.obj \ + $O\UpdateAction.obj \ + $O\UpdateCallback.obj \ + $O\UpdatePair.obj \ + $O\UpdateProduce.obj \ + +C_OBJS = $(C_OBJS) \ + $O\DllSecur.obj \ + +# we need empty line after last line above diff --git a/CPP/7zip/UI/Console/Console.manifest b/CPP/7zip/UI/Console/Console.manifest index 34d8bdd37..c932b28ce 100644 --- a/CPP/7zip/UI/Console/Console.manifest +++ b/CPP/7zip/UI/Console/Console.manifest @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - -true + + + + + + + + + + + + + + +true \ No newline at end of file diff --git a/CPP/7zip/UI/Console/ConsoleClose.cpp b/CPP/7zip/UI/Console/ConsoleClose.cpp index 373ff4cc4..a184ffb85 100644 --- a/CPP/7zip/UI/Console/ConsoleClose.cpp +++ b/CPP/7zip/UI/Console/ConsoleClose.cpp @@ -1,100 +1,98 @@ -// ConsoleClose.cpp - -#include "StdAfx.h" - -#include "ConsoleClose.h" - -#ifndef UNDER_CE - -#ifdef _WIN32 -#include "../../../Common/MyWindows.h" -#else -#include -#include -#endif - -namespace NConsoleClose { - -unsigned g_BreakCounter = 0; -static const unsigned kBreakAbortThreshold = 2; - -#ifdef _WIN32 - -static BOOL WINAPI HandlerRoutine(DWORD ctrlType) -{ - if (ctrlType == CTRL_LOGOFF_EVENT) - { - // printf("\nCTRL_LOGOFF_EVENT\n"); - return TRUE; - } - - g_BreakCounter++; - if (g_BreakCounter < kBreakAbortThreshold) - return TRUE; - return FALSE; - /* - switch (ctrlType) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - if (g_BreakCounter < kBreakAbortThreshold) - return TRUE; - } - return FALSE; - */ -} - -CCtrlHandlerSetter::CCtrlHandlerSetter() -{ - if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE)) - throw "SetConsoleCtrlHandler fails"; -} - -CCtrlHandlerSetter::~CCtrlHandlerSetter() -{ - if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE)) - { - // warning for throw in destructor. - // throw "SetConsoleCtrlHandler fails"; - } -} - -#else // _WIN32 - -static void HandlerRoutine(int) -{ - g_BreakCounter++; - if (g_BreakCounter < kBreakAbortThreshold) - return; - exit(EXIT_FAILURE); -} - -CCtrlHandlerSetter::CCtrlHandlerSetter() -{ - memo_sig_int = signal(SIGINT, HandlerRoutine); // CTRL-C - if (memo_sig_int == SIG_ERR) - throw "SetConsoleCtrlHandler fails (SIGINT)"; - memo_sig_term = signal(SIGTERM, HandlerRoutine); // for kill -15 (before "kill -9") - if (memo_sig_term == SIG_ERR) - throw "SetConsoleCtrlHandler fails (SIGTERM)"; -} - -CCtrlHandlerSetter::~CCtrlHandlerSetter() -{ - signal(SIGINT, memo_sig_int); // CTRL-C - signal(SIGTERM, memo_sig_term); // kill {pid} -} - -#endif // _WIN32 - -/* -void CheckCtrlBreak() -{ - if (TestBreakSignal()) - throw CCtrlBreakException(); -} -*/ - -} - -#endif +// ConsoleClose.cpp + +#include "StdAfx.h" + +#include "ConsoleClose.h" + +#ifndef UNDER_CE + +#ifdef _WIN32 +#include "../../../Common/MyWindows.h" +#else +#include +#include +#endif + +namespace NConsoleClose { + +unsigned g_BreakCounter = 0; +static const unsigned kBreakAbortThreshold = 3; + +#ifdef _WIN32 + +static BOOL WINAPI HandlerRoutine(DWORD ctrlType) +{ + if (ctrlType == CTRL_LOGOFF_EVENT) + { + // printf("\nCTRL_LOGOFF_EVENT\n"); + return TRUE; + } + + if (++g_BreakCounter < kBreakAbortThreshold) + return TRUE; + return FALSE; + /* + switch (ctrlType) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + if (g_BreakCounter < kBreakAbortThreshold) + return TRUE; + } + return FALSE; + */ +} + +CCtrlHandlerSetter::CCtrlHandlerSetter() +{ + if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE)) + throw 1019; // "SetConsoleCtrlHandler fails"; +} + +CCtrlHandlerSetter::~CCtrlHandlerSetter() +{ + if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE)) + { + // warning for throw in destructor. + // throw "SetConsoleCtrlHandler fails"; + } +} + +#else // _WIN32 + +static void HandlerRoutine(int) +{ + if (++g_BreakCounter < kBreakAbortThreshold) + return; + exit(EXIT_FAILURE); +} + +CCtrlHandlerSetter::CCtrlHandlerSetter() +{ + memo_sig_int = signal(SIGINT, HandlerRoutine); // CTRL-C + if (memo_sig_int == SIG_ERR) + throw "SetConsoleCtrlHandler fails (SIGINT)"; + memo_sig_term = signal(SIGTERM, HandlerRoutine); // for kill -15 (before "kill -9") + if (memo_sig_term == SIG_ERR) + throw "SetConsoleCtrlHandler fails (SIGTERM)"; +} + +CCtrlHandlerSetter::~CCtrlHandlerSetter() +{ + signal(SIGINT, memo_sig_int); // CTRL-C + signal(SIGTERM, memo_sig_term); // kill {pid} +} + +#endif // _WIN32 + +/* +void CheckCtrlBreak() +{ + if (TestBreakSignal()) + throw CCtrlBreakException(); +} +*/ + +} + +#endif diff --git a/CPP/7zip/UI/Console/ConsoleClose.h b/CPP/7zip/UI/Console/ConsoleClose.h index 62cbdb0bc..b0d99b484 100644 --- a/CPP/7zip/UI/Console/ConsoleClose.h +++ b/CPP/7zip/UI/Console/ConsoleClose.h @@ -1,39 +1,39 @@ -// ConsoleClose.h - -#ifndef ZIP7_INC_CONSOLE_CLOSE_H -#define ZIP7_INC_CONSOLE_CLOSE_H - -namespace NConsoleClose { - -class CCtrlBreakException {}; - -#ifdef UNDER_CE - -inline bool TestBreakSignal() { return false; } -struct CCtrlHandlerSetter {}; - -#else - -extern unsigned g_BreakCounter; - -inline bool TestBreakSignal() -{ - return (g_BreakCounter != 0); -} - -class CCtrlHandlerSetter Z7_final -{ - #ifndef _WIN32 - void (*memo_sig_int)(int); - void (*memo_sig_term)(int); - #endif -public: - CCtrlHandlerSetter(); - ~CCtrlHandlerSetter(); -}; - -#endif - -} - -#endif +// ConsoleClose.h + +#ifndef ZIP7_INC_CONSOLE_CLOSE_H +#define ZIP7_INC_CONSOLE_CLOSE_H + +namespace NConsoleClose { + +// class CCtrlBreakException {}; + +#ifdef UNDER_CE + +inline bool TestBreakSignal() { return false; } +struct CCtrlHandlerSetter {}; + +#else + +extern unsigned g_BreakCounter; + +inline bool TestBreakSignal() +{ + return (g_BreakCounter != 0); +} + +class CCtrlHandlerSetter Z7_final +{ + #ifndef _WIN32 + void (*memo_sig_int)(int); + void (*memo_sig_term)(int); + #endif +public: + CCtrlHandlerSetter(); + ~CCtrlHandlerSetter(); +}; + +#endif + +} + +#endif diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index fddbc1b2d..b12763124 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp @@ -1,946 +1,946 @@ -// ExtractCallbackConsole.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/TimeUtils.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/PropVariantConv.h" - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../../Common/FilePathAutoRename.h" - -#include "../Common/ExtractingFilePath.h" - -#include "ConsoleClose.h" -#include "ExtractCallbackConsole.h" -#include "UserInputUtils.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static HRESULT CheckBreak2() -{ - return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; -} - -static const char * const kError = "ERROR: "; - - -void CExtractScanConsole::StartScanning() -{ - if (NeedPercents()) - _percent.Command = "Scan"; -} - -HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) -{ - if (NeedPercents()) - { - _percent.Files = st.NumDirs + st.NumFiles; - _percent.Completed = st.GetTotalBytes(); - _percent.FileName = fs2us(path); - _percent.Print(); - } - - return CheckBreak2(); -} - -HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError) -{ - // 22.00: - // ScanErrors.AddError(path, systemError); - - ClosePercentsAndFlush(); - - if (_se) - { - *_se << endl << kError << NError::MyFormatMessage(systemError) << endl; - _se->NormalizePrint_UString_Path(fs2us(path)); - *_se << endl << endl; - _se->Flush(); - } - return HRESULT_FROM_WIN32(systemError); - - // 22.00: commented - // CommonError(path, systemError, true); - // return S_OK; -} - - -void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); -void Print_UInt64_and_String(AString &s, UInt64 val, const char *name) -{ - char temp[32]; - ConvertUInt64ToString(val, temp); - s += temp; - s.Add_Space(); - s += name; -} - -void PrintSize_bytes_Smart(AString &s, UInt64 val); -void PrintSize_bytes_Smart(AString &s, UInt64 val) -{ - Print_UInt64_and_String(s, val, "bytes"); - - if (val == 0) - return; - - unsigned numBits = 10; - char c = 'K'; - char temp[4] = { 'K', 'i', 'B', 0 }; - if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; } - else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; } - temp[0] = c; - s += " ("; - Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp); - s.Add_Char(')'); -} - -static void PrintSize_bytes_Smart_comma(AString &s, UInt64 val) -{ - if (val == (UInt64)(Int64)-1) - return; - s += ", "; - PrintSize_bytes_Smart(s, val); -} - - - -void Print_DirItemsStat(AString &s, const CDirItemsStat &st); -void Print_DirItemsStat(AString &s, const CDirItemsStat &st) -{ - if (st.NumDirs != 0) - { - Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders"); - s += ", "; - } - Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files"); - PrintSize_bytes_Smart_comma(s, st.FilesSize); - if (st.NumAltStreams != 0) - { - s.Add_LF(); - Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams"); - PrintSize_bytes_Smart_comma(s, st.AltStreamsSize); - } -} - - -void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); -void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st) -{ - Print_DirItemsStat(s, (CDirItemsStat &)st); - bool needLF = true; - if (st.Anti_NumDirs != 0) - { - if (needLF) - s.Add_LF(); - needLF = false; - Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders"); - } - if (st.Anti_NumFiles != 0) - { - if (needLF) - s.Add_LF(); - else - s += ", "; - needLF = false; - Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files"); - } - if (st.Anti_NumAltStreams != 0) - { - if (needLF) - s.Add_LF(); - else - s += ", "; - needLF = false; - Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams"); - } -} - - -void CExtractScanConsole::PrintStat(const CDirItemsStat &st) -{ - if (_so) - { - AString s; - Print_DirItemsStat(s, st); - *_so << s << endl; - } -} - - - - - - - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - - -static const char * const kTestString = "T"; -static const char * const kExtractString = "-"; -static const char * const kSkipString = "."; -static const char * const kReadString = "H"; - -// static const char * const kCantAutoRename = "cannot create file with auto name\n"; -// static const char * const kCantRenameFile = "cannot rename existing file\n"; -// static const char * const kCantDeleteOutputFile = "cannot delete output file "; - -static const char * const kMemoryExceptionMessage = "Can't allocate required memory!"; - -static const char * const kExtracting = "Extracting archive: "; -static const char * const kTesting = "Testing archive: "; - -static const char * const kEverythingIsOk = "Everything is Ok"; -static const char * const kNoFiles = "No files to process"; - -static const char * const kUnsupportedMethod = "Unsupported Method"; -static const char * const kCrcFailed = "CRC Failed"; -static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?"; -static const char * const kDataError = "Data Error"; -static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?"; -static const char * const kUnavailableData = "Unavailable data"; -static const char * const kUnexpectedEnd = "Unexpected end of data"; -static const char * const kDataAfterEnd = "There are some data after the end of the payload data"; -static const char * const kIsNotArc = "Is not archive"; -static const char * const kHeadersError = "Headers Error"; -static const char * const kWrongPassword = "Wrong password"; - -static const char * const k_ErrorFlagsMessages[] = -{ - "Is not archive" - , "Headers Error" - , "Headers Error in encrypted archive. Wrong password?" - , "Unavailable start of archive" - , "Unconfirmed start of archive" - , "Unexpected end of archive" - , "There are data after the end of archive" - , "Unsupported method" - , "Unsupported feature" - , "Data Error" - , "CRC Error" -}; - -Z7_COM7F_IMF(CExtractCallbackConsole::SetTotal(UInt64 size)) -{ - MT_LOCK - - if (NeedPercents()) - { - _percent.Total = size; - _percent.Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue)) -{ - MT_LOCK - - if (NeedPercents()) - { - if (completeValue) - _percent.Completed = *completeValue; - _percent.Print(); - } - return CheckBreak2(); -} - -static const char * const kTab = " "; - -static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size) -{ - *_so << kTab << "Path: "; - _so->NormalizePrint_wstr_Path(path); - *_so << endl; - if (size && *size != (UInt64)(Int64)-1) - { - AString s; - PrintSize_bytes_Smart(s, *size); - *_so << kTab << "Size: " << s << endl; - } - if (ft) - { - char temp[64]; - if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC)) - *_so << kTab << "Modified: " << temp << endl; - } -} - -Z7_COM7F_IMF(CExtractCallbackConsole::AskOverwrite( - const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, - const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, - Int32 *answer)) -{ - MT_LOCK - - RINOK(CheckBreak2()) - - ClosePercentsAndFlush(); - - if (_so) - { - *_so << endl << "Would you like to replace the existing file:\n"; - PrintFileInfo(_so, existName, existTime, existSize); - *_so << "with the file from archive:\n"; - PrintFileInfo(_so, newName, newTime, newSize); - } - - NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so); - - switch ((int)overwriteAnswer) - { - case NUserAnswerMode::kQuit: return E_ABORT; - case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break; - case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break; - case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break; - case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break; - case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break; - case NUserAnswerMode::kEof: return E_ABORT; - case NUserAnswerMode::kError: return E_FAIL; - default: return E_FAIL; - } - - if (_so) - { - *_so << endl; - if (NeedFlush) - _so->Flush(); - } - - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) -{ - MT_LOCK - - _currentName = name; - - const char *s; - unsigned requiredLevel = 1; - - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; - case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; - case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break; - case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; requiredLevel = 0; break; - default: s = "???"; requiredLevel = 2; - } - - const bool show2 = (LogLevel >= requiredLevel && _so); - - if (show2) - { - ClosePercents_for_so(); - - _tempA = s; - if (name) - _tempA.Add_Space(); - *_so << _tempA; - - _tempU.Empty(); - if (name) - { - _tempU = name; - _so->Normalize_UString_Path(_tempU); - // 21.04 - if (isFolder) - { - if (!_tempU.IsEmpty() && _tempU.Back() != WCHAR_PATH_SEPARATOR) - _tempU.Add_PathSepar(); - } - } - _so->PrintUString(_tempU, _tempA); - if (position) - *_so << " <" << *position << ">"; - *_so << endl; - - if (NeedFlush) - _so->Flush(); - // _so->Flush(); // for debug only - } - - if (NeedPercents()) - { - if (PercentsNameLevel >= 1) - { - _percent.FileName.Empty(); - _percent.Command.Empty(); - if (PercentsNameLevel > 1 || !show2) - { - _percent.Command = s; - if (name) - _percent.FileName = name; - } - } - _percent.Print(); - } - - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackConsole::MessageError(const wchar_t *message)) -{ - MT_LOCK - - RINOK(CheckBreak2()) - - NumFileErrors_in_Current++; - NumFileErrors++; - - ClosePercentsAndFlush(); - if (_se) - { - *_se << kError << message << endl; - _se->Flush(); - } - - return CheckBreak2(); -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest) -{ - dest.Empty(); - const char *s = NULL; - - switch (opRes) - { - case NArchive::NExtract::NOperationResult::kUnsupportedMethod: - s = kUnsupportedMethod; - break; - case NArchive::NExtract::NOperationResult::kCRCError: - s = (encrypted ? kCrcFailedEncrypted : kCrcFailed); - break; - case NArchive::NExtract::NOperationResult::kDataError: - s = (encrypted ? kDataErrorEncrypted : kDataError); - break; - case NArchive::NExtract::NOperationResult::kUnavailable: - s = kUnavailableData; - break; - case NArchive::NExtract::NOperationResult::kUnexpectedEnd: - s = kUnexpectedEnd; - break; - case NArchive::NExtract::NOperationResult::kDataAfterEnd: - s = kDataAfterEnd; - break; - case NArchive::NExtract::NOperationResult::kIsNotArc: - s = kIsNotArc; - break; - case NArchive::NExtract::NOperationResult::kHeadersError: - s = kHeadersError; - break; - case NArchive::NExtract::NOperationResult::kWrongPassword: - s = kWrongPassword; - break; - default: break; - } - - dest += kError; - if (s) - dest += s; - else - { - dest += "Error #"; - dest.Add_UInt32((UInt32)opRes); - } -} - -Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted)) -{ - MT_LOCK - - if (opRes == NArchive::NExtract::NOperationResult::kOK) - { - if (NeedPercents()) - { - _percent.Command.Empty(); - _percent.FileName.Empty(); - _percent.Files++; - } - } - else - { - NumFileErrors_in_Current++; - NumFileErrors++; - - if (_se) - { - ClosePercentsAndFlush(); - - AString s; - SetExtractErrorMessage(opRes, encrypted, s); - - *_se << s; - if (!_currentName.IsEmpty()) - { - *_se << " : "; - _se->NormalizePrint_UString_Path(_currentName); - } - *_se << endl; - _se->Flush(); - } - } - - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) -{ - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - _currentName = name; - return SetOperationResult(opRes, encrypted); - } - - return CheckBreak2(); -} - - - -#ifndef Z7_NO_CRYPTO - -HRESULT CExtractCallbackConsole::SetPassword(const UString &password) -{ - PasswordIsDefined = true; - Password = password; - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)) -{ - COM_TRY_BEGIN - MT_LOCK - return Open_CryptoGetTextPassword(password); - COM_TRY_END -} - -#endif - - -#ifndef Z7_SFX - -void CExtractCallbackConsole::PrintTo_se_Path_WithTitle(const UString &path, const char *title) -{ - *_se << title; - _se->NormalizePrint_UString_Path(path); - *_se << endl; -} - -void CExtractCallbackConsole::Add_ArchiveName_Error() -{ - if (_needWriteArchivePath) - { - PrintTo_se_Path_WithTitle(_currentArchivePath, "Archive: "); - _needWriteArchivePath = false; - } -} - - -Z7_COM7F_IMF(CExtractCallbackConsole::RequestMemoryUse( - UInt32 flags, UInt32 /* indexType */, UInt32 /* index */, const wchar_t *path, - UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) -{ - if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0 - && requiredSize <= *allowedSize) - { -#if 0 - // it's expected, that *answerFlags was set to NRequestMemoryAnswerFlags::k_Allow already, - // because it's default answer for (requiredSize <= *allowedSize) case. - // optional code: - *answerFlags = NRequestMemoryAnswerFlags::k_Allow; -#endif - } - else - { - if ((flags & NRequestMemoryUseFlags::k_NoErrorMessage) == 0) - if (_se) - { - const UInt64 num_GB_allowed = (*allowedSize + ((1u << 30) - 1)) >> 30; - const UInt64 num_GB_required = (requiredSize + ((1u << 30) - 1)) >> 30; - ClosePercentsAndFlush(); - Add_ArchiveName_Error(); - if (path) - PrintTo_se_Path_WithTitle(path, "File: "); - *_se << "The extraction operation requires big amount memory (RAM):" << endl - << " " << num_GB_required << " GB : required memory usage size" << endl - << " " << num_GB_allowed << " GB : allowed memory usage limit" << endl - << " Use -smemx{size}g switch to set allowed memory usage limit for extraction." << endl; - *_se << "ERROR: Memory usage limit was exceeded." << endl; - const char *m = NULL; - // if (indexType == NArchive::NEventIndexType::kNoIndex) - if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) || - (flags & NRequestMemoryUseFlags::k_Report_SkipArc)) - m = "Archive unpacking was skipped."; -/* - else if ((flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected) || - (flags & NRequestMemoryUseFlags::k_Report_SkipBigFiles)) - m = "Extraction for some files will be skipped."; - else if ((flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected) || - (flags & NRequestMemoryUseFlags::k_Report_SkipBigFile)) - m = "File extraction was skipped."; -*/ - if (m) - *_se << m; - _se->Flush(); - } - - if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) - { - // default answer can be k_Allow, if limit was not forced, - // so we change answer to non-allowed here. - *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded; - if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) - *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc; -/* - else if (flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected) - *answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFile; - else if (flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected) - *answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFiles; -*/ - } - } - return CheckBreak2(); -} - -#endif - - -HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode) -{ - _currentArchivePath = name; - _needWriteArchivePath = true; - - RINOK(CheckBreak2()) - - NumTryArcs++; - ThereIsError_in_Current = false; - ThereIsWarning_in_Current = false; - NumFileErrors_in_Current = 0; - - ClosePercents_for_so(); - if (_so) - { - *_so << endl << (testMode ? kTesting : kExtracting); - _so->NormalizePrint_wstr_Path(name); - *_so << endl; - } - - if (NeedPercents()) - _percent.Command = "Open"; - return S_OK; -} - -HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); -HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); - -static AString GetOpenArcErrorMessage(UInt32 errorFlags) -{ - AString s; - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsMessages); i++) - { - UInt32 f = (1 << i); - if ((errorFlags & f) == 0) - continue; - const char *m = k_ErrorFlagsMessages[i]; - if (!s.IsEmpty()) - s.Add_LF(); - s += m; - errorFlags &= ~f; - } - - if (errorFlags != 0) - { - char sz[16]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt32ToHex(errorFlags, sz + 2); - if (!s.IsEmpty()) - s.Add_LF(); - s += sz; - } - - return s; -} - -void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); -void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags) -{ - if (errorFlags == 0) - return; - so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl; -} - -static void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType) -{ - s.Add_LF(); - s += pre; - s += " as ["; - s += arcType; - s += "] archive"; -} - -void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); -void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc) -{ - const CArcErrorInfo &er = arc.ErrorInfo; - - *_so << "WARNING:\n"; - _so->NormalizePrint_UString_Path(arc.Path); - UString s; - if (arc.FormatIndex == er.ErrorFormatIndex) - { - s.Add_LF(); - s += "The archive is open with offset"; - } - else - { - Add_Messsage_Pre_ArcType(s, "Cannot open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex)); - Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex)); - } - - *_so << s << endl << endl; -} - - -HRESULT CExtractCallbackConsole::OpenResult( - const CCodecs *codecs, const CArchiveLink &arcLink, - const wchar_t *name, HRESULT result) -{ - _currentArchivePath = name; - _needWriteArchivePath = true; - - ClosePercents(); - - if (NeedPercents()) - { - _percent.Files = 0; - _percent.Command.Empty(); - _percent.FileName.Empty(); - } - - - ClosePercentsAndFlush(); - - FOR_VECTOR (level, arcLink.Arcs) - { - const CArc &arc = arcLink.Arcs[level]; - const CArcErrorInfo &er = arc.ErrorInfo; - - UInt32 errorFlags = er.GetErrorFlags(); - - if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) - { - if (_se) - { - *_se << endl; - if (level != 0) - { - _se->NormalizePrint_UString_Path(arc.Path); - *_se << endl; - } - } - - if (errorFlags != 0) - { - if (_se) - PrintErrorFlags(*_se, "ERRORS:", errorFlags); - NumOpenArcErrors++; - ThereIsError_in_Current = true; - } - - if (!er.ErrorMessage.IsEmpty()) - { - if (_se) - *_se << "ERRORS:" << endl << er.ErrorMessage << endl; - NumOpenArcErrors++; - ThereIsError_in_Current = true; - } - - if (_se) - { - *_se << endl; - _se->Flush(); - } - } - - UInt32 warningFlags = er.GetWarningFlags(); - - if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) - { - if (_so) - { - *_so << endl; - if (level != 0) - { - _so->NormalizePrint_UString_Path(arc.Path); - *_so << endl; - } - } - - if (warningFlags != 0) - { - if (_so) - PrintErrorFlags(*_so, "WARNINGS:", warningFlags); - NumOpenArcWarnings++; - ThereIsWarning_in_Current = true; - } - - if (!er.WarningMessage.IsEmpty()) - { - if (_so) - *_so << "WARNINGS:" << endl << er.WarningMessage << endl; - NumOpenArcWarnings++; - ThereIsWarning_in_Current = true; - } - - if (_so) - { - *_so << endl; - if (NeedFlush) - _so->Flush(); - } - } - - - if (er.ErrorFormatIndex >= 0) - { - if (_so) - { - Print_ErrorFormatIndex_Warning(_so, codecs, arc); - if (NeedFlush) - _so->Flush(); - } - ThereIsWarning_in_Current = true; - } - } - - if (result == S_OK) - { - if (_so) - { - RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)) - *_so << endl; - } - } - else - { - NumCantOpenArcs++; - if (_so) - _so->Flush(); - if (_se) - { - *_se << kError; - _se->NormalizePrint_wstr_Path(name); - *_se << endl; - const HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); - RINOK(res) - if (result == S_FALSE) - { - } - else - { - if (result == E_OUTOFMEMORY) - *_se << "Can't allocate required memory"; - else - *_se << NError::MyFormatMessage(result); - *_se << endl; - } - _se->Flush(); - } - } - - - return CheckBreak2(); -} - -HRESULT CExtractCallbackConsole::ThereAreNoFiles() -{ - ClosePercents_for_so(); - - if (_so) - { - *_so << endl << kNoFiles << endl; - if (NeedFlush) - _so->Flush(); - } - return CheckBreak2(); -} - -HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result) -{ - MT_LOCK - - if (NeedPercents()) - { - _percent.ClosePrint(true); - _percent.Command.Empty(); - _percent.FileName.Empty(); - } - - if (_so) - _so->Flush(); - - if (result == S_OK) - { - if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current) - { - if (ThereIsWarning_in_Current) - NumArcsWithWarnings++; - else - NumOkArcs++; - if (_so) - *_so << kEverythingIsOk << endl; - } - else - { - NumArcsWithError++; - if (_so) - { - *_so << endl; - if (NumFileErrors_in_Current != 0) - *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl; - } - } - if (_so && NeedFlush) - _so->Flush(); - } - else - { - // we don't update NumArcsWithError, if error is not related to archive data. - if (result == E_ABORT - || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)) - return result; - NumArcsWithError++; - - if (_se) - { - *_se << endl << kError; - if (result == E_OUTOFMEMORY) - *_se << kMemoryExceptionMessage; - else - *_se << NError::MyFormatMessage(result); - *_se << endl; - _se->Flush(); - } - } - - return CheckBreak2(); -} +// ExtractCallbackConsole.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/TimeUtils.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/PropVariantConv.h" + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../../Common/FilePathAutoRename.h" + +#include "../Common/ExtractingFilePath.h" + +#include "ConsoleClose.h" +#include "ExtractCallbackConsole.h" +#include "UserInputUtils.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static HRESULT CheckBreak2() +{ + return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; +} + +static const char * const kError = "ERROR: "; + + +void CExtractScanConsole::StartScanning() +{ + if (NeedPercents()) + _percent.Command = "Scan"; +} + +HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) +{ + if (NeedPercents()) + { + _percent.Files = st.NumDirs + st.NumFiles; + _percent.Completed = st.GetTotalBytes(); + _percent.FileName = fs2us(path); + _percent.Print(); + } + + return CheckBreak2(); +} + +HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError) +{ + // 22.00: + // ScanErrors.AddError(path, systemError); + + ClosePercentsAndFlush(); + + if (_se) + { + *_se << endl << kError << NError::MyFormatMessage(systemError) << endl; + _se->NormalizePrint_UString_Path(fs2us(path)); + *_se << endl << endl; + _se->Flush(); + } + return HRESULT_FROM_WIN32(systemError); + + // 22.00: commented + // CommonError(path, systemError, true); + // return S_OK; +} + + +void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); +void Print_UInt64_and_String(AString &s, UInt64 val, const char *name) +{ + char temp[32]; + ConvertUInt64ToString(val, temp); + s += temp; + s.Add_Space(); + s += name; +} + +void PrintSize_bytes_Smart(AString &s, UInt64 val); +void PrintSize_bytes_Smart(AString &s, UInt64 val) +{ + Print_UInt64_and_String(s, val, "bytes"); + + if (val == 0) + return; + + unsigned numBits = 10; + char c = 'K'; + char temp[4] = { 'K', 'i', 'B', 0 }; + if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; } + else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; } + temp[0] = c; + s += " ("; + Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp); + s.Add_Char(')'); +} + +static void PrintSize_bytes_Smart_comma(AString &s, UInt64 val) +{ + if (val == (UInt64)(Int64)-1) + return; + s += ", "; + PrintSize_bytes_Smart(s, val); +} + + + +void Print_DirItemsStat(AString &s, const CDirItemsStat &st); +void Print_DirItemsStat(AString &s, const CDirItemsStat &st) +{ + if (st.NumDirs != 0) + { + Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders"); + s += ", "; + } + Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files"); + PrintSize_bytes_Smart_comma(s, st.FilesSize); + if (st.NumAltStreams != 0) + { + s.Add_LF(); + Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams"); + PrintSize_bytes_Smart_comma(s, st.AltStreamsSize); + } +} + + +void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); +void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st) +{ + Print_DirItemsStat(s, (CDirItemsStat &)st); + bool needLF = true; + if (st.Anti_NumDirs != 0) + { + if (needLF) + s.Add_LF(); + needLF = false; + Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders"); + } + if (st.Anti_NumFiles != 0) + { + if (needLF) + s.Add_LF(); + else + s += ", "; + needLF = false; + Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files"); + } + if (st.Anti_NumAltStreams != 0) + { + if (needLF) + s.Add_LF(); + else + s += ", "; + needLF = false; + Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams"); + } +} + + +void CExtractScanConsole::PrintStat(const CDirItemsStat &st) +{ + if (_so) + { + AString s; + Print_DirItemsStat(s, st); + *_so << s << endl; + } +} + + + + + + + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + + +static const char * const kTestString = "T"; +static const char * const kExtractString = "-"; +static const char * const kSkipString = "."; +static const char * const kReadString = "H"; + +// static const char * const kCantAutoRename = "cannot create file with auto name\n"; +// static const char * const kCantRenameFile = "cannot rename existing file\n"; +// static const char * const kCantDeleteOutputFile = "cannot delete output file "; + +static const char * const kMemoryExceptionMessage = "Can't allocate required memory!"; + +static const char * const kExtracting = "Extracting archive: "; +static const char * const kTesting = "Testing archive: "; + +static const char * const kEverythingIsOk = "Everything is Ok"; +static const char * const kNoFiles = "No files to process"; + +static const char * const kUnsupportedMethod = "Unsupported Method"; +static const char * const kCrcFailed = "CRC Failed"; +static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?"; +static const char * const kDataError = "Data Error"; +static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?"; +static const char * const kUnavailableData = "Unavailable data"; +static const char * const kUnexpectedEnd = "Unexpected end of data"; +static const char * const kDataAfterEnd = "There are some data after the end of the payload data"; +static const char * const kIsNotArc = "Is not archive"; +static const char * const kHeadersError = "Headers Error"; +static const char * const kWrongPassword = "Wrong password"; + +static const char * const k_ErrorFlagsMessages[] = +{ + "Is not archive" + , "Headers Error" + , "Headers Error in encrypted archive. Wrong password?" + , "Unavailable start of archive" + , "Unconfirmed start of archive" + , "Unexpected end of archive" + , "There are data after the end of archive" + , "Unsupported method" + , "Unsupported feature" + , "Data Error" + , "CRC Error" +}; + +Z7_COM7F_IMF(CExtractCallbackConsole::SetTotal(UInt64 size)) +{ + MT_LOCK + + if (NeedPercents()) + { + _percent.Total = size; + _percent.Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue)) +{ + MT_LOCK + + if (NeedPercents()) + { + if (completeValue) + _percent.Completed = *completeValue; + _percent.Print(); + } + return CheckBreak2(); +} + +static const char * const kTab = " "; + +static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size) +{ + *_so << kTab << "Path: "; + _so->NormalizePrint_wstr_Path(path); + *_so << endl; + if (size && *size != (UInt64)(Int64)-1) + { + AString s; + PrintSize_bytes_Smart(s, *size); + *_so << kTab << "Size: " << s << endl; + } + if (ft) + { + char temp[64]; + if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC)) + *_so << kTab << "Modified: " << temp << endl; + } +} + +Z7_COM7F_IMF(CExtractCallbackConsole::AskOverwrite( + const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, + const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, + Int32 *answer)) +{ + MT_LOCK + + RINOK(CheckBreak2()) + + ClosePercentsAndFlush(); + + if (_so) + { + *_so << endl << "Would you like to replace the existing file:\n"; + PrintFileInfo(_so, existName, existTime, existSize); + *_so << "with the file from archive:\n"; + PrintFileInfo(_so, newName, newTime, newSize); + } + + NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so); + + switch ((int)overwriteAnswer) + { + case NUserAnswerMode::kQuit: return E_ABORT; + case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break; + case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break; + case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break; + case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break; + case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break; + case NUserAnswerMode::kEof: return E_ABORT; + case NUserAnswerMode::kError: return E_FAIL; + default: return E_FAIL; + } + + if (_so) + { + *_so << endl; + if (NeedFlush) + _so->Flush(); + } + + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) +{ + MT_LOCK + + _currentName = name; + + const char *s; + unsigned requiredLevel = 1; + + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; + case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; + case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break; + case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; requiredLevel = 0; break; + default: s = "???"; requiredLevel = 2; + } + + const bool show2 = (LogLevel >= requiredLevel && _so); + + if (show2) + { + ClosePercents_for_so(); + + _tempA = s; + if (name) + _tempA.Add_Space(); + *_so << _tempA; + + _tempU.Empty(); + if (name) + { + _tempU = name; + _so->Normalize_UString_Path(_tempU); + // 21.04 + if (isFolder) + { + if (!_tempU.IsEmpty() && _tempU.Back() != WCHAR_PATH_SEPARATOR) + _tempU.Add_PathSepar(); + } + } + _so->PrintUString(_tempU, _tempA); + if (position) + *_so << " <" << *position << ">"; + *_so << endl; + + if (NeedFlush) + _so->Flush(); + // _so->Flush(); // for debug only + } + + if (NeedPercents()) + { + if (PercentsNameLevel >= 1) + { + _percent.FileName.Empty(); + _percent.Command.Empty(); + if (PercentsNameLevel > 1 || !show2) + { + _percent.Command = s; + if (name) + _percent.FileName = name; + } + } + _percent.Print(); + } + + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackConsole::MessageError(const wchar_t *message)) +{ + MT_LOCK + + RINOK(CheckBreak2()) + + NumFileErrors_in_Current++; + NumFileErrors++; + + ClosePercentsAndFlush(); + if (_se) + { + *_se << kError << message << endl; + _se->Flush(); + } + + return CheckBreak2(); +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest) +{ + dest.Empty(); + const char *s = NULL; + + switch (opRes) + { + case NArchive::NExtract::NOperationResult::kUnsupportedMethod: + s = kUnsupportedMethod; + break; + case NArchive::NExtract::NOperationResult::kCRCError: + s = (encrypted ? kCrcFailedEncrypted : kCrcFailed); + break; + case NArchive::NExtract::NOperationResult::kDataError: + s = (encrypted ? kDataErrorEncrypted : kDataError); + break; + case NArchive::NExtract::NOperationResult::kUnavailable: + s = kUnavailableData; + break; + case NArchive::NExtract::NOperationResult::kUnexpectedEnd: + s = kUnexpectedEnd; + break; + case NArchive::NExtract::NOperationResult::kDataAfterEnd: + s = kDataAfterEnd; + break; + case NArchive::NExtract::NOperationResult::kIsNotArc: + s = kIsNotArc; + break; + case NArchive::NExtract::NOperationResult::kHeadersError: + s = kHeadersError; + break; + case NArchive::NExtract::NOperationResult::kWrongPassword: + s = kWrongPassword; + break; + default: break; + } + + dest += kError; + if (s) + dest += s; + else + { + dest += "Error #"; + dest.Add_UInt32((UInt32)opRes); + } +} + +Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted)) +{ + MT_LOCK + + if (opRes == NArchive::NExtract::NOperationResult::kOK) + { + if (NeedPercents()) + { + _percent.Command.Empty(); + _percent.FileName.Empty(); + _percent.Files++; + } + } + else + { + NumFileErrors_in_Current++; + NumFileErrors++; + + if (_se) + { + ClosePercentsAndFlush(); + + AString s; + SetExtractErrorMessage(opRes, encrypted, s); + + *_se << s; + if (!_currentName.IsEmpty()) + { + *_se << " : "; + _se->NormalizePrint_UString_Path(_currentName); + } + *_se << endl; + _se->Flush(); + } + } + + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) +{ + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + _currentName = name; + return SetOperationResult(opRes, encrypted); + } + + return CheckBreak2(); +} + + + +#ifndef Z7_NO_CRYPTO + +HRESULT CExtractCallbackConsole::SetPassword(const UString &password) +{ + PasswordIsDefined = true; + Password = password; + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)) +{ + COM_TRY_BEGIN + MT_LOCK + return Open_CryptoGetTextPassword(password); + COM_TRY_END +} + +#endif + + +#ifndef Z7_SFX + +void CExtractCallbackConsole::PrintTo_se_Path_WithTitle(const UString &path, const char *title) +{ + *_se << title; + _se->NormalizePrint_UString_Path(path); + *_se << endl; +} + +void CExtractCallbackConsole::Add_ArchiveName_Error() +{ + if (_needWriteArchivePath) + { + PrintTo_se_Path_WithTitle(_currentArchivePath, "Archive: "); + _needWriteArchivePath = false; + } +} + + +Z7_COM7F_IMF(CExtractCallbackConsole::RequestMemoryUse( + UInt32 flags, UInt32 /* indexType */, UInt32 /* index */, const wchar_t *path, + UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) +{ + if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0 + && requiredSize <= *allowedSize) + { +#if 0 + // it's expected, that *answerFlags was set to NRequestMemoryAnswerFlags::k_Allow already, + // because it's default answer for (requiredSize <= *allowedSize) case. + // optional code: + *answerFlags = NRequestMemoryAnswerFlags::k_Allow; +#endif + } + else + { + if ((flags & NRequestMemoryUseFlags::k_NoErrorMessage) == 0) + if (_se) + { + const UInt64 num_GB_allowed = (*allowedSize + ((1u << 30) - 1)) >> 30; + const UInt64 num_GB_required = (requiredSize + ((1u << 30) - 1)) >> 30; + ClosePercentsAndFlush(); + Add_ArchiveName_Error(); + if (path) + PrintTo_se_Path_WithTitle(path, "File: "); + *_se << "The extraction operation requires big amount memory (RAM):" << endl + << " " << num_GB_required << " GB : required memory usage size" << endl + << " " << num_GB_allowed << " GB : allowed memory usage limit" << endl + << " Use -smemx{size}g switch to set allowed memory usage limit for extraction." << endl; + *_se << "ERROR: Memory usage limit was exceeded." << endl; + const char *m = NULL; + // if (indexType == NArchive::NEventIndexType::kNoIndex) + if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) || + (flags & NRequestMemoryUseFlags::k_Report_SkipArc)) + m = "Archive unpacking was skipped."; +/* + else if ((flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected) || + (flags & NRequestMemoryUseFlags::k_Report_SkipBigFiles)) + m = "Extraction for some files will be skipped."; + else if ((flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected) || + (flags & NRequestMemoryUseFlags::k_Report_SkipBigFile)) + m = "File extraction was skipped."; +*/ + if (m) + *_se << m; + _se->Flush(); + } + + if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) + { + // default answer can be k_Allow, if limit was not forced, + // so we change answer to non-allowed here. + *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded; + if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) + *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc; +/* + else if (flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected) + *answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFile; + else if (flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected) + *answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFiles; +*/ + } + } + return CheckBreak2(); +} + +#endif + + +HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode) +{ + _currentArchivePath = name; + _needWriteArchivePath = true; + + RINOK(CheckBreak2()) + + NumTryArcs++; + ThereIsError_in_Current = false; + ThereIsWarning_in_Current = false; + NumFileErrors_in_Current = 0; + + ClosePercents_for_so(); + if (_so) + { + *_so << endl << (testMode ? kTesting : kExtracting); + _so->NormalizePrint_wstr_Path(name); + *_so << endl; + } + + if (NeedPercents()) + _percent.Command = "Open"; + return S_OK; +} + +HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); +HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); + +static AString GetOpenArcErrorMessage(UInt32 errorFlags) +{ + AString s; + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsMessages); i++) + { + UInt32 f = (1 << i); + if ((errorFlags & f) == 0) + continue; + const char *m = k_ErrorFlagsMessages[i]; + if (!s.IsEmpty()) + s.Add_LF(); + s += m; + errorFlags &= ~f; + } + + if (errorFlags != 0) + { + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(errorFlags, sz + 2); + if (!s.IsEmpty()) + s.Add_LF(); + s += sz; + } + + return s; +} + +void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); +void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags) +{ + if (errorFlags == 0) + return; + so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl; +} + +static void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType) +{ + s.Add_LF(); + s += pre; + s += " as ["; + s += arcType; + s += "] archive"; +} + +void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); +void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc) +{ + const CArcErrorInfo &er = arc.ErrorInfo; + + *_so << "WARNING:\n"; + _so->NormalizePrint_UString_Path(arc.Path); + UString s; + if (arc.FormatIndex == er.ErrorFormatIndex) + { + s.Add_LF(); + s += "The archive is open with offset"; + } + else + { + Add_Messsage_Pre_ArcType(s, "Cannot open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex)); + Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex)); + } + + *_so << s << endl << endl; +} + + +HRESULT CExtractCallbackConsole::OpenResult( + const CCodecs *codecs, const CArchiveLink &arcLink, + const wchar_t *name, HRESULT result) +{ + _currentArchivePath = name; + _needWriteArchivePath = true; + + ClosePercents(); + + if (NeedPercents()) + { + _percent.Files = 0; + _percent.Command.Empty(); + _percent.FileName.Empty(); + } + + + ClosePercentsAndFlush(); + + FOR_VECTOR (level, arcLink.Arcs) + { + const CArc &arc = arcLink.Arcs[level]; + const CArcErrorInfo &er = arc.ErrorInfo; + + UInt32 errorFlags = er.GetErrorFlags(); + + if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) + { + if (_se) + { + *_se << endl; + if (level != 0) + { + _se->NormalizePrint_UString_Path(arc.Path); + *_se << endl; + } + } + + if (errorFlags != 0) + { + if (_se) + PrintErrorFlags(*_se, "ERRORS:", errorFlags); + NumOpenArcErrors++; + ThereIsError_in_Current = true; + } + + if (!er.ErrorMessage.IsEmpty()) + { + if (_se) + *_se << "ERRORS:" << endl << er.ErrorMessage << endl; + NumOpenArcErrors++; + ThereIsError_in_Current = true; + } + + if (_se) + { + *_se << endl; + _se->Flush(); + } + } + + UInt32 warningFlags = er.GetWarningFlags(); + + if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) + { + if (_so) + { + *_so << endl; + if (level != 0) + { + _so->NormalizePrint_UString_Path(arc.Path); + *_so << endl; + } + } + + if (warningFlags != 0) + { + if (_so) + PrintErrorFlags(*_so, "WARNINGS:", warningFlags); + NumOpenArcWarnings++; + ThereIsWarning_in_Current = true; + } + + if (!er.WarningMessage.IsEmpty()) + { + if (_so) + *_so << "WARNINGS:" << endl << er.WarningMessage << endl; + NumOpenArcWarnings++; + ThereIsWarning_in_Current = true; + } + + if (_so) + { + *_so << endl; + if (NeedFlush) + _so->Flush(); + } + } + + + if (er.ErrorFormatIndex >= 0) + { + if (_so) + { + Print_ErrorFormatIndex_Warning(_so, codecs, arc); + if (NeedFlush) + _so->Flush(); + } + ThereIsWarning_in_Current = true; + } + } + + if (result == S_OK) + { + if (_so) + { + RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)) + *_so << endl; + } + } + else + { + NumCantOpenArcs++; + if (_so) + _so->Flush(); + if (_se) + { + *_se << kError; + _se->NormalizePrint_wstr_Path(name); + *_se << endl; + const HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); + RINOK(res) + if (result == S_FALSE) + { + } + else + { + if (result == E_OUTOFMEMORY) + *_se << "Can't allocate required memory"; + else + *_se << NError::MyFormatMessage(result); + *_se << endl; + } + _se->Flush(); + } + } + + + return CheckBreak2(); +} + +HRESULT CExtractCallbackConsole::ThereAreNoFiles() +{ + ClosePercents_for_so(); + + if (_so) + { + *_so << endl << kNoFiles << endl; + if (NeedFlush) + _so->Flush(); + } + return CheckBreak2(); +} + +HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result) +{ + MT_LOCK + + if (NeedPercents()) + { + _percent.ClosePrint(true); + _percent.Command.Empty(); + _percent.FileName.Empty(); + } + + if (_so) + _so->Flush(); + + if (result == S_OK) + { + if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current) + { + if (ThereIsWarning_in_Current) + NumArcsWithWarnings++; + else + NumOkArcs++; + if (_so) + *_so << kEverythingIsOk << endl; + } + else + { + NumArcsWithError++; + if (_so) + { + *_so << endl; + if (NumFileErrors_in_Current != 0) + *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl; + } + } + if (_so && NeedFlush) + _so->Flush(); + } + else + { + // we don't update NumArcsWithError, if error is not related to archive data. + if (result == E_ABORT + || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)) + return result; + NumArcsWithError++; + + if (_se) + { + *_se << endl << kError; + if (result == E_OUTOFMEMORY) + *_se << kMemoryExceptionMessage; + else + *_se << NError::MyFormatMessage(result); + *_se << endl; + _se->Flush(); + } + } + + return CheckBreak2(); +} diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/CPP/7zip/UI/Console/ExtractCallbackConsole.h index 4c269390d..4e4534800 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.h +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.h @@ -1,211 +1,211 @@ -// ExtractCallbackConsole.h - -#ifndef ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H -#define ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H - -#include "../../../Common/StdOutStream.h" - -#include "../../IPassword.h" - -#include "../../Archive/IArchive.h" - -#include "../Common/ArchiveExtractCallback.h" - -#include "PercentPrinter.h" - -#include "OpenCallbackConsole.h" - -/* -struct CErrorPathCodes2 -{ - FStringVector Paths; - CRecordVector Codes; - - void AddError(const FString &path, DWORD systemError) - { - Paths.Add(path); - Codes.Add(systemError); - } - void Clear() - { - Paths.Clear(); - Codes.Clear(); - } -}; -*/ - -class CExtractScanConsole Z7_final: public IDirItemsCallback -{ - Z7_IFACE_IMP(IDirItemsCallback) - - CStdOutStream *_so; - CStdOutStream *_se; - CPercentPrinter _percent; - - // CErrorPathCodes2 ScanErrors; - - bool NeedPercents() const { return _percent._so && !_percent.DisablePrint; } - - void ClosePercentsAndFlush() - { - if (NeedPercents()) - _percent.ClosePrint(true); - if (_so) - _so->Flush(); - } - -public: - - void Init( - CStdOutStream *outStream, - CStdOutStream *errorStream, - CStdOutStream *percentStream, - bool disablePercents) - { - _so = outStream; - _se = errorStream; - _percent._so = percentStream; - _percent.DisablePrint = disablePercents; - } - - void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } - - void StartScanning(); - - void CloseScanning() - { - if (NeedPercents()) - _percent.ClosePrint(true); - } - - void PrintStat(const CDirItemsStat &st); -}; - - - - -class CExtractCallbackConsole Z7_final: - public IFolderArchiveExtractCallback, - public IExtractCallbackUI, - // public IArchiveExtractCallbackMessage, - public IFolderArchiveExtractCallback2, - #ifndef Z7_NO_CRYPTO - public ICryptoGetTextPassword, - #endif - #ifndef Z7_SFX - public IArchiveRequestMemoryUseCallback, - #endif - - public COpenCallbackConsole, - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback) - // Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage) - Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2) - #ifndef Z7_NO_CRYPTO - Z7_COM_QI_ENTRY(ICryptoGetTextPassword) - #endif - #ifndef Z7_SFX - Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback) - #endif - - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback) - Z7_IFACE_IMP(IExtractCallbackUI) - // Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage) - Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2) - #ifndef Z7_NO_CRYPTO - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - #endif - #ifndef Z7_SFX - Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) - #endif - - bool _needWriteArchivePath; - -public: - bool ThereIsError_in_Current; - bool ThereIsWarning_in_Current; - bool NeedFlush; - -private: - AString _tempA; - UString _tempU; - - UString _currentArchivePath; - UString _currentName; - -#ifndef Z7_SFX - void PrintTo_se_Path_WithTitle(const UString &path, const char *title); - void Add_ArchiveName_Error(); -#endif - - void ClosePercents_for_so() - { - if (NeedPercents() && _so == _percent._so) - _percent.ClosePrint(false); - } - - void ClosePercentsAndFlush() - { - if (NeedPercents()) - _percent.ClosePrint(true); - if (_so) - _so->Flush(); - } -public: - UInt64 NumTryArcs; - - UInt64 NumOkArcs; - UInt64 NumCantOpenArcs; - UInt64 NumArcsWithError; - UInt64 NumArcsWithWarnings; - - UInt64 NumOpenArcErrors; - UInt64 NumOpenArcWarnings; - - UInt64 NumFileErrors; - UInt64 NumFileErrors_in_Current; - - unsigned PercentsNameLevel; - unsigned LogLevel; - - CExtractCallbackConsole(): - _needWriteArchivePath(true), - NeedFlush(false), - PercentsNameLevel(1), - LogLevel(0) - {} - - void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } - - void Init( - CStdOutStream *outStream, - CStdOutStream *errorStream, - CStdOutStream *percentStream, - bool disablePercents) - { - COpenCallbackConsole::Init(outStream, errorStream, percentStream, disablePercents); - - NumTryArcs = 0; - - ThereIsError_in_Current = false; - ThereIsWarning_in_Current = false; - - NumOkArcs = 0; - NumCantOpenArcs = 0; - NumArcsWithError = 0; - NumArcsWithWarnings = 0; - - NumOpenArcErrors = 0; - NumOpenArcWarnings = 0; - - NumFileErrors = 0; - NumFileErrors_in_Current = 0; - } -}; - -#endif +// ExtractCallbackConsole.h + +#ifndef ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H +#define ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H + +#include "../../../Common/StdOutStream.h" + +#include "../../IPassword.h" + +#include "../../Archive/IArchive.h" + +#include "../Common/ArchiveExtractCallback.h" + +#include "PercentPrinter.h" + +#include "OpenCallbackConsole.h" + +/* +struct CErrorPathCodes2 +{ + FStringVector Paths; + CRecordVector Codes; + + void AddError(const FString &path, DWORD systemError) + { + Paths.Add(path); + Codes.Add(systemError); + } + void Clear() + { + Paths.Clear(); + Codes.Clear(); + } +}; +*/ + +class CExtractScanConsole Z7_final: public IDirItemsCallback +{ + Z7_IFACE_IMP(IDirItemsCallback) + + CStdOutStream *_so; + CStdOutStream *_se; + CPercentPrinter _percent; + + // CErrorPathCodes2 ScanErrors; + + bool NeedPercents() const { return _percent._so && !_percent.DisablePrint; } + + void ClosePercentsAndFlush() + { + if (NeedPercents()) + _percent.ClosePrint(true); + if (_so) + _so->Flush(); + } + +public: + + void Init( + CStdOutStream *outStream, + CStdOutStream *errorStream, + CStdOutStream *percentStream, + bool disablePercents) + { + _so = outStream; + _se = errorStream; + _percent._so = percentStream; + _percent.DisablePrint = disablePercents; + } + + void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } + + void StartScanning(); + + void CloseScanning() + { + if (NeedPercents()) + _percent.ClosePrint(true); + } + + void PrintStat(const CDirItemsStat &st); +}; + + + + +class CExtractCallbackConsole Z7_final: + public IFolderArchiveExtractCallback, + public IExtractCallbackUI, + // public IArchiveExtractCallbackMessage, + public IFolderArchiveExtractCallback2, + #ifndef Z7_NO_CRYPTO + public ICryptoGetTextPassword, + #endif + #ifndef Z7_SFX + public IArchiveRequestMemoryUseCallback, + #endif + + public COpenCallbackConsole, + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback) + // Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage) + Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2) + #ifndef Z7_NO_CRYPTO + Z7_COM_QI_ENTRY(ICryptoGetTextPassword) + #endif + #ifndef Z7_SFX + Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback) + #endif + + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback) + Z7_IFACE_IMP(IExtractCallbackUI) + // Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage) + Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2) + #ifndef Z7_NO_CRYPTO + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + #endif + #ifndef Z7_SFX + Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) + #endif + + bool _needWriteArchivePath; + +public: + bool ThereIsError_in_Current; + bool ThereIsWarning_in_Current; + bool NeedFlush; + +private: + AString _tempA; + UString _tempU; + + UString _currentArchivePath; + UString _currentName; + +#ifndef Z7_SFX + void PrintTo_se_Path_WithTitle(const UString &path, const char *title); + void Add_ArchiveName_Error(); +#endif + + void ClosePercents_for_so() + { + if (NeedPercents() && _so == _percent._so) + _percent.ClosePrint(false); + } + + void ClosePercentsAndFlush() + { + if (NeedPercents()) + _percent.ClosePrint(true); + if (_so) + _so->Flush(); + } +public: + UInt64 NumTryArcs; + + UInt64 NumOkArcs; + UInt64 NumCantOpenArcs; + UInt64 NumArcsWithError; + UInt64 NumArcsWithWarnings; + + UInt64 NumOpenArcErrors; + UInt64 NumOpenArcWarnings; + + UInt64 NumFileErrors; + UInt64 NumFileErrors_in_Current; + + unsigned PercentsNameLevel; + unsigned LogLevel; + + CExtractCallbackConsole(): + _needWriteArchivePath(true), + NeedFlush(false), + PercentsNameLevel(1), + LogLevel(0) + {} + + void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } + + void Init( + CStdOutStream *outStream, + CStdOutStream *errorStream, + CStdOutStream *percentStream, + bool disablePercents) + { + COpenCallbackConsole::Init(outStream, errorStream, percentStream, disablePercents); + + NumTryArcs = 0; + + ThereIsError_in_Current = false; + ThereIsWarning_in_Current = false; + + NumOkArcs = 0; + NumCantOpenArcs = 0; + NumArcsWithError = 0; + NumArcsWithWarnings = 0; + + NumOpenArcErrors = 0; + NumOpenArcWarnings = 0; + + NumFileErrors = 0; + NumFileErrors_in_Current = 0; + } +}; + +#endif diff --git a/CPP/7zip/UI/Console/HashCon.cpp b/CPP/7zip/UI/Console/HashCon.cpp index 3190c4eeb..078a625ae 100644 --- a/CPP/7zip/UI/Console/HashCon.cpp +++ b/CPP/7zip/UI/Console/HashCon.cpp @@ -1,426 +1,426 @@ -// HashCon.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/FileName.h" - -#include "ConsoleClose.h" -#include "HashCon.h" - -static const char * const kEmptyFileAlias = "[Content]"; - -static const char * const kScanningMessage = "Scanning"; - -static HRESULT CheckBreak2() -{ - return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; -} - -HRESULT CHashCallbackConsole::CheckBreak() -{ - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::StartScanning() -{ - if (PrintHeaders && _so) - *_so << kScanningMessage << endl; - if (NeedPercents()) - { - _percent.ClearCurState(); - _percent.Command = "Scan"; - } - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) -{ - if (NeedPercents()) - { - _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; - _percent.Completed = st.GetTotalBytes(); - _percent.FileName = fs2us(path); - if (isDir) - NWindows::NFile::NName::NormalizeDirPathPrefix(_percent.FileName); - _percent.Print(); - } - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError) -{ - return ScanError_Base(path, systemError); -} - -void Print_DirItemsStat(AString &s, const CDirItemsStat &st); - -HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st) -{ - if (NeedPercents()) - { - _percent.ClosePrint(true); - _percent.ClearCurState(); - } - if (PrintHeaders && _so) - { - Print_DirItemsStat(_s, st); - *_so << _s << endl << endl; - } - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */) -{ - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::SetTotal(UInt64 size) -{ - if (NeedPercents()) - { - _percent.Total = size; - _percent.Print(); - } - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue) -{ - if (completeValue && NeedPercents()) - { - _percent.Completed = *completeValue; - _percent.Print(); - } - return CheckBreak2(); -} - -static void AddMinuses(AString &s, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - s.Add_Minus(); -} - -static void AddSpaces_if_Positive(AString &s, int num) -{ - for (int i = 0; i < num; i++) - s.Add_Space(); -} - -static void SetSpacesAndNul(char *s, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - s[i] = ' '; - s[num] = 0; -} - -static void SetSpacesAndNul_if_Positive(char *s, int num) -{ - if (num < 0) - return; - for (int i = 0; i < num; i++) - s[i] = ' '; - s[num] = 0; -} - -static const unsigned kSizeField_Len = 13; -static const unsigned kNameField_Len = 12; - -static const unsigned kHashColumnWidth_Min = 4 * 2; - -static unsigned GetColumnWidth(unsigned digestSize) -{ - unsigned width = digestSize * 2; - return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; -} - - -AString CHashCallbackConsole::GetFields() const -{ - AString s (PrintFields); - if (s.IsEmpty()) - s = "hsn"; - s.MakeLower_Ascii(); - return s; -} - - -void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector &hashers) -{ - _s.Empty(); - const AString fields = GetFields(); - for (unsigned pos = 0; pos < fields.Len(); pos++) - { - const char c = fields[pos]; - if (c == 'h') - { - for (unsigned i = 0; i < hashers.Size(); i++) - { - AddSpace(); - const CHasherState &h = hashers[i]; - AddMinuses(_s, GetColumnWidth(h.DigestSize)); - } - } - else if (c == 's') - { - AddSpace(); - AddMinuses(_s, kSizeField_Len); - } - else if (c == 'n') - { - AddSpacesBeforeName(); - AddMinuses(_s, kNameField_Len); - } - } - - *_so << _s << endl; -} - - -HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb) -{ - if (PrintHeaders && _so) - { - _s.Empty(); - ClosePercents_for_so(); - - const AString fields = GetFields(); - for (unsigned pos = 0; pos < fields.Len(); pos++) - { - const char c = fields[pos]; - if (c == 'h') - { - FOR_VECTOR (i, hb.Hashers) - { - AddSpace(); - const CHasherState &h = hb.Hashers[i]; - _s += h.Name; - AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len()); - } - } - - else if (c == 's') - { - AddSpace(); - const AString s2 ("Size"); - AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len()); - _s += s2; - } - else if (c == 'n') - { - AddSpacesBeforeName(); - _s += "Name"; - } - } - - *_so << _s << endl; - PrintSeparatorLine(hb.Hashers); - } - - return CheckBreak2(); -} - -HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError) -{ - return OpenFileError_Base(path, systemError); -} - -HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool isDir) -{ - _fileName = name; - if (isDir) - NWindows::NFile::NName::NormalizeDirPathPrefix(_fileName); - - if (NeedPercents()) - { - if (PrintNameInPercents) - { - _percent.FileName.Empty(); - if (name) - _percent.FileName = name; - } - _percent.Print(); - } - return CheckBreak2(); -} - - -static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16; - - - -void CHashCallbackConsole::PrintResultLine(UInt64 fileSize, - const CObjectVector &hashers, unsigned digestIndex, bool showHash, - const AString &path) -{ - ClosePercents_for_so(); - - _s.Empty(); - const AString fields = GetFields(); - - for (unsigned pos = 0; pos < fields.Len(); pos++) - { - const char c = fields[pos]; - if (c == 'h') - { - FOR_VECTOR (i, hashers) - { - AddSpace(); - const CHasherState &h = hashers[i]; - char s[k_DigestStringSize]; - s[0] = 0; - if (showHash) - h.WriteToString(digestIndex, s); - const unsigned len = (unsigned)strlen(s); - SetSpacesAndNul_if_Positive(s + len, (int)GetColumnWidth(h.DigestSize) - (int)len); - _s += s; - } - } - else if (c == 's') - { - AddSpace(); - char s[kSizeField_Len + 32]; - char *p = s; - SetSpacesAndNul(s, kSizeField_Len); - if (showHash) - { - p = s + kSizeField_Len; - ConvertUInt64ToString(fileSize, p); - const int numSpaces = (int)kSizeField_Len - (int)strlen(p); - if (numSpaces > 0) - p -= (unsigned)numSpaces; - } - _s += p; - } - else if (c == 'n') - { - AddSpacesBeforeName(); - _s += path; - } - } - - *_so << _s; -} - - -HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) -{ - if (_so) - { - AString s; - if (_fileName.IsEmpty()) - s = kEmptyFileAlias; - else - { - UString temp (_fileName); - _so->Normalize_UString_Path(temp); - _so->Convert_UString_to_AString(temp, s); - } - PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash, s); - - /* - PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash); - if (PrintName) - { - if (_fileName.IsEmpty()) - *_so << kEmptyFileAlias; - else - _so->NormalizePrint_UString(_fileName); - } - */ - // if (PrintNewLine) - *_so << endl; - } - - if (NeedPercents()) - { - _percent.Files++; - _percent.Print(); - } - - return CheckBreak2(); -} - -static const char * const k_DigestTitles[] = -{ - " : " - , " for data: " - , " for data and names: " - , " for streams and names: " -}; - -static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex) -{ - so << h.Name; - - { - AString temp; - AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len()); - so << temp; - } - - so << k_DigestTitles[digestIndex]; - - char s[k_DigestStringSize]; - // s[0] = 0; - h.WriteToString(digestIndex, s); - so << s << endl; -} - -void PrintHashStat(CStdOutStream &so, const CHashBundle &hb) -{ - FOR_VECTOR (i, hb.Hashers) - { - const CHasherState &h = hb.Hashers[i]; - PrintSum(so, h, k_HashCalc_Index_DataSum); - if (hb.NumFiles != 1 || hb.NumDirs != 0) - PrintSum(so, h, k_HashCalc_Index_NamesSum); - if (hb.NumAltStreams != 0) - PrintSum(so, h, k_HashCalc_Index_StreamsSum); - so << endl; - } -} - -void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value) -{ - char s[32]; - s[0] = ':'; - s[1] = ' '; - ConvertUInt64ToString(value, s + 2); - *_so << name << s << endl; -} - -HRESULT CHashCallbackConsole::AfterLastFile(CHashBundle &hb) -{ - ClosePercents2(); - - if (PrintHeaders && _so) - { - PrintSeparatorLine(hb.Hashers); - - PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true, AString()); - - *_so << endl << endl; - - if (hb.NumFiles != 1 || hb.NumDirs != 0) - { - if (hb.NumDirs != 0) - PrintProperty("Folders", hb.NumDirs); - PrintProperty("Files", hb.NumFiles); - } - - PrintProperty("Size", hb.FilesSize); - - if (hb.NumAltStreams != 0) - { - PrintProperty("Alternate streams", hb.NumAltStreams); - PrintProperty("Alternate streams size", hb.AltStreamsSize); - } - - *_so << endl; - PrintHashStat(*_so, hb); - } - - return S_OK; -} +// HashCon.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/FileName.h" + +#include "ConsoleClose.h" +#include "HashCon.h" + +static const char * const kEmptyFileAlias = "[Content]"; + +static const char * const kScanningMessage = "Scanning"; + +static HRESULT CheckBreak2() +{ + return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; +} + +HRESULT CHashCallbackConsole::CheckBreak() +{ + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::StartScanning() +{ + if (PrintHeaders && _so) + *_so << kScanningMessage << endl; + if (NeedPercents()) + { + _percent.ClearCurState(); + _percent.Command = "Scan"; + } + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) +{ + if (NeedPercents()) + { + _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; + _percent.Completed = st.GetTotalBytes(); + _percent.FileName = fs2us(path); + if (isDir) + NWindows::NFile::NName::NormalizeDirPathPrefix(_percent.FileName); + _percent.Print(); + } + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError) +{ + return ScanError_Base(path, systemError); +} + +void Print_DirItemsStat(AString &s, const CDirItemsStat &st); + +HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st) +{ + if (NeedPercents()) + { + _percent.ClosePrint(true); + _percent.ClearCurState(); + } + if (PrintHeaders && _so) + { + Print_DirItemsStat(_s, st); + *_so << _s << endl << endl; + } + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */) +{ + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::SetTotal(UInt64 size) +{ + if (NeedPercents()) + { + _percent.Total = size; + _percent.Print(); + } + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue) +{ + if (completeValue && NeedPercents()) + { + _percent.Completed = *completeValue; + _percent.Print(); + } + return CheckBreak2(); +} + +static void AddMinuses(AString &s, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + s.Add_Minus(); +} + +static void AddSpaces_if_Positive(AString &s, int num) +{ + for (int i = 0; i < num; i++) + s.Add_Space(); +} + +static void SetSpacesAndNul(char *s, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + s[i] = ' '; + s[num] = 0; +} + +static void SetSpacesAndNul_if_Positive(char *s, int num) +{ + if (num < 0) + return; + for (int i = 0; i < num; i++) + s[i] = ' '; + s[num] = 0; +} + +static const unsigned kSizeField_Len = 13; +static const unsigned kNameField_Len = 12; + +static const unsigned kHashColumnWidth_Min = 4 * 2; + +static unsigned GetColumnWidth(unsigned digestSize) +{ + unsigned width = digestSize * 2; + return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width; +} + + +AString CHashCallbackConsole::GetFields() const +{ + AString s (PrintFields); + if (s.IsEmpty()) + s = "hsn"; + s.MakeLower_Ascii(); + return s; +} + + +void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector &hashers) +{ + _s.Empty(); + const AString fields = GetFields(); + for (unsigned pos = 0; pos < fields.Len(); pos++) + { + const char c = fields[pos]; + if (c == 'h') + { + for (unsigned i = 0; i < hashers.Size(); i++) + { + AddSpace(); + const CHasherState &h = hashers[i]; + AddMinuses(_s, GetColumnWidth(h.DigestSize)); + } + } + else if (c == 's') + { + AddSpace(); + AddMinuses(_s, kSizeField_Len); + } + else if (c == 'n') + { + AddSpacesBeforeName(); + AddMinuses(_s, kNameField_Len); + } + } + + *_so << _s << endl; +} + + +HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb) +{ + if (PrintHeaders && _so) + { + _s.Empty(); + ClosePercents_for_so(); + + const AString fields = GetFields(); + for (unsigned pos = 0; pos < fields.Len(); pos++) + { + const char c = fields[pos]; + if (c == 'h') + { + FOR_VECTOR (i, hb.Hashers) + { + AddSpace(); + const CHasherState &h = hb.Hashers[i]; + _s += h.Name; + AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len()); + } + } + + else if (c == 's') + { + AddSpace(); + const AString s2 ("Size"); + AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len()); + _s += s2; + } + else if (c == 'n') + { + AddSpacesBeforeName(); + _s += "Name"; + } + } + + *_so << _s << endl; + PrintSeparatorLine(hb.Hashers); + } + + return CheckBreak2(); +} + +HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError) +{ + return OpenFileError_Base(path, systemError); +} + +HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool isDir) +{ + _fileName = name; + if (isDir) + NWindows::NFile::NName::NormalizeDirPathPrefix(_fileName); + + if (NeedPercents()) + { + if (PrintNameInPercents) + { + _percent.FileName.Empty(); + if (name) + _percent.FileName = name; + } + _percent.Print(); + } + return CheckBreak2(); +} + + +static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16; + + + +void CHashCallbackConsole::PrintResultLine(UInt64 fileSize, + const CObjectVector &hashers, unsigned digestIndex, bool showHash, + const AString &path) +{ + ClosePercents_for_so(); + + _s.Empty(); + const AString fields = GetFields(); + + for (unsigned pos = 0; pos < fields.Len(); pos++) + { + const char c = fields[pos]; + if (c == 'h') + { + FOR_VECTOR (i, hashers) + { + AddSpace(); + const CHasherState &h = hashers[i]; + char s[k_DigestStringSize]; + s[0] = 0; + if (showHash) + h.WriteToString(digestIndex, s); + const unsigned len = (unsigned)strlen(s); + SetSpacesAndNul_if_Positive(s + len, (int)GetColumnWidth(h.DigestSize) - (int)len); + _s += s; + } + } + else if (c == 's') + { + AddSpace(); + char s[kSizeField_Len + 32]; + char *p = s; + SetSpacesAndNul(s, kSizeField_Len); + if (showHash) + { + p = s + kSizeField_Len; + ConvertUInt64ToString(fileSize, p); + const int numSpaces = (int)kSizeField_Len - (int)strlen(p); + if (numSpaces > 0) + p -= (unsigned)numSpaces; + } + _s += p; + } + else if (c == 'n') + { + AddSpacesBeforeName(); + _s += path; + } + } + + *_so << _s; +} + + +HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) +{ + if (_so) + { + AString s; + if (_fileName.IsEmpty()) + s = kEmptyFileAlias; + else + { + UString temp (_fileName); + _so->Normalize_UString_Path(temp); + _so->Convert_UString_to_AString(temp, s); + } + PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash, s); + + /* + PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash); + if (PrintName) + { + if (_fileName.IsEmpty()) + *_so << kEmptyFileAlias; + else + _so->NormalizePrint_UString(_fileName); + } + */ + // if (PrintNewLine) + *_so << endl; + } + + if (NeedPercents()) + { + _percent.Files++; + _percent.Print(); + } + + return CheckBreak2(); +} + +static const char * const k_DigestTitles[] = +{ + " : " + , " for data: " + , " for data and names: " + , " for streams and names: " +}; + +static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex) +{ + so << h.Name; + + { + AString temp; + AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len()); + so << temp; + } + + so << k_DigestTitles[digestIndex]; + + char s[k_DigestStringSize]; + // s[0] = 0; + h.WriteToString(digestIndex, s); + so << s << endl; +} + +void PrintHashStat(CStdOutStream &so, const CHashBundle &hb) +{ + FOR_VECTOR (i, hb.Hashers) + { + const CHasherState &h = hb.Hashers[i]; + PrintSum(so, h, k_HashCalc_Index_DataSum); + if (hb.NumFiles != 1 || hb.NumDirs != 0) + PrintSum(so, h, k_HashCalc_Index_NamesSum); + if (hb.NumAltStreams != 0) + PrintSum(so, h, k_HashCalc_Index_StreamsSum); + so << endl; + } +} + +void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value) +{ + char s[32]; + s[0] = ':'; + s[1] = ' '; + ConvertUInt64ToString(value, s + 2); + *_so << name << s << endl; +} + +HRESULT CHashCallbackConsole::AfterLastFile(CHashBundle &hb) +{ + ClosePercents2(); + + if (PrintHeaders && _so) + { + PrintSeparatorLine(hb.Hashers); + + PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true, AString()); + + *_so << endl << endl; + + if (hb.NumFiles != 1 || hb.NumDirs != 0) + { + if (hb.NumDirs != 0) + PrintProperty("Folders", hb.NumDirs); + PrintProperty("Files", hb.NumFiles); + } + + PrintProperty("Size", hb.FilesSize); + + if (hb.NumAltStreams != 0) + { + PrintProperty("Alternate streams", hb.NumAltStreams); + PrintProperty("Alternate streams size", hb.AltStreamsSize); + } + + *_so << endl; + PrintHashStat(*_so, hb); + } + + return S_OK; +} diff --git a/CPP/7zip/UI/Console/HashCon.h b/CPP/7zip/UI/Console/HashCon.h index 6ece32381..ebccb6ff3 100644 --- a/CPP/7zip/UI/Console/HashCon.h +++ b/CPP/7zip/UI/Console/HashCon.h @@ -1,58 +1,58 @@ -// HashCon.h - -#ifndef ZIP7_INC_HASH_CON_H -#define ZIP7_INC_HASH_CON_H - -#include "../Common/HashCalc.h" - -#include "UpdateCallbackConsole.h" - -class CHashCallbackConsole Z7_final: - public IHashCallbackUI, - public CCallbackConsoleBase -{ - Z7_IFACE_IMP(IDirItemsCallback) - Z7_IFACE_IMP(IHashCallbackUI) - - UString _fileName; - AString _s; - - void AddSpace() - { - _s.Add_Space_if_NotEmpty(); - } - - void AddSpacesBeforeName() - { - if (!_s.IsEmpty()) - { - _s.Add_Space(); - _s.Add_Space(); - } - } - - void PrintSeparatorLine(const CObjectVector &hashers); - void PrintResultLine(UInt64 fileSize, - const CObjectVector &hashers, unsigned digestIndex, bool showHash, const AString &path); - void PrintProperty(const char *name, UInt64 value); - -public: - bool PrintNameInPercents; - bool PrintHeaders; - // bool PrintSize; - // bool PrintNewLine; // set it too (false), if you need only hash for single file without LF char. - AString PrintFields; - - AString GetFields() const; - - CHashCallbackConsole(): - PrintNameInPercents(true), - PrintHeaders(false) - // , PrintSize(true), - // , PrintNewLine(true) - {} -}; - -void PrintHashStat(CStdOutStream &so, const CHashBundle &hb); - -#endif +// HashCon.h + +#ifndef ZIP7_INC_HASH_CON_H +#define ZIP7_INC_HASH_CON_H + +#include "../Common/HashCalc.h" + +#include "UpdateCallbackConsole.h" + +class CHashCallbackConsole Z7_final: + public IHashCallbackUI, + public CCallbackConsoleBase +{ + Z7_IFACE_IMP(IDirItemsCallback) + Z7_IFACE_IMP(IHashCallbackUI) + + UString _fileName; + AString _s; + + void AddSpace() + { + _s.Add_Space_if_NotEmpty(); + } + + void AddSpacesBeforeName() + { + if (!_s.IsEmpty()) + { + _s.Add_Space(); + _s.Add_Space(); + } + } + + void PrintSeparatorLine(const CObjectVector &hashers); + void PrintResultLine(UInt64 fileSize, + const CObjectVector &hashers, unsigned digestIndex, bool showHash, const AString &path); + void PrintProperty(const char *name, UInt64 value); + +public: + bool PrintNameInPercents; + bool PrintHeaders; + // bool PrintSize; + // bool PrintNewLine; // set it too (false), if you need only hash for single file without LF char. + AString PrintFields; + + AString GetFields() const; + + CHashCallbackConsole(): + PrintNameInPercents(true), + PrintHeaders(false) + // , PrintSize(true), + // , PrintNewLine(true) + {} +}; + +void PrintHashStat(CStdOutStream &so, const CHashBundle &hb); + +#endif diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp index 1c7865812..874caef3c 100644 --- a/CPP/7zip/UI/Console/List.cpp +++ b/CPP/7zip/UI/Console/List.cpp @@ -1,1417 +1,1417 @@ -// List.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/MyCom.h" -#include "../../../Common/StdOutStream.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../Common/OpenArchive.h" -#include "../Common/PropIDUtils.h" - -#include "ConsoleClose.h" -#include "List.h" -#include "OpenCallbackConsole.h" - -using namespace NWindows; -using namespace NCOM; - -extern CStdOutStream *g_StdStream; -extern CStdOutStream *g_ErrStream; - -static const char * const kPropIdToName[] = -{ - "0" - , "1" - , "2" - , "Path" - , "Name" - , "Extension" - , "Folder" - , "Size" - , "Packed Size" - , "Attributes" - , "Created" - , "Accessed" - , "Modified" - , "Solid" - , "Commented" - , "Encrypted" - , "Split Before" - , "Split After" - , "Dictionary Size" - , "CRC" - , "Type" - , "Anti" - , "Method" - , "Host OS" - , "File System" - , "User" - , "Group" - , "Block" - , "Comment" - , "Position" - , "Path Prefix" - , "Folders" - , "Files" - , "Version" - , "Volume" - , "Multivolume" - , "Offset" - , "Links" - , "Blocks" - , "Volumes" - , "Time Type" - , "64-bit" - , "Big-endian" - , "CPU" - , "Physical Size" - , "Headers Size" - , "Checksum" - , "Characteristics" - , "Virtual Address" - , "ID" - , "Short Name" - , "Creator Application" - , "Sector Size" - , "Mode" - , "Symbolic Link" - , "Error" - , "Total Size" - , "Free Space" - , "Cluster Size" - , "Label" - , "Local Name" - , "Provider" - , "NT Security" - , "Alternate Stream" - , "Aux" - , "Deleted" - , "Tree" - , "SHA-1" - , "SHA-256" - , "Error Type" - , "Errors" - , "Errors" - , "Warnings" - , "Warning" - , "Streams" - , "Alternate Streams" - , "Alternate Streams Size" - , "Virtual Size" - , "Unpack Size" - , "Total Physical Size" - , "Volume Index" - , "SubType" - , "Short Comment" - , "Code Page" - , "Is not archive type" - , "Physical Size can't be detected" - , "Zeros Tail Is Allowed" - , "Tail Size" - , "Embedded Stub Size" - , "Link" - , "Hard Link" - , "iNode" - , "Stream ID" - , "Read-only" - , "Out Name" - , "Copy Link" - , "ArcFileName" - , "IsHash" - , "Metadata Changed" - , "User ID" - , "Group ID" - , "Device Major" - , "Device Minor" - , "Dev Major" - , "Dev Minor" -}; - -static const char kEmptyAttribChar = '.'; - -static const char * const kListing = "Listing archive: "; - -static const char * const kString_Files = "files"; -static const char * const kString_Dirs = "folders"; -static const char * const kString_AltStreams = "alternate streams"; -static const char * const kString_Streams = "streams"; - -static const char * const kError = "ERROR: "; - -static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s) -{ - if (isDir) - wa |= FILE_ATTRIBUTE_DIRECTORY; - if (allAttribs) - { - ConvertWinAttribToString(s, wa); - return; - } - s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar; - s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar; - s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar; - s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar; - s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar; - s[5] = 0; -} - -enum EAdjustment -{ - kLeft, - kCenter, - kRight -}; - -struct CFieldInfo -{ - PROPID PropID; - bool IsRawProp; - UString NameU; - AString NameA; - EAdjustment TitleAdjustment; - EAdjustment TextAdjustment; - unsigned PrefixSpacesWidth; - unsigned Width; -}; - -struct CFieldInfoInit -{ - PROPID PropID; - const char *Name; - EAdjustment TitleAdjustment; - EAdjustment TextAdjustment; - unsigned PrefixSpacesWidth; - unsigned Width; -}; - -static const CFieldInfoInit kStandardFieldTable[] = -{ - { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 }, - { kpidAttrib, "Attr", kRight, kCenter, 1, 5 }, - { kpidSize, "Size", kRight, kRight, 1, 12 }, - { kpidPackSize, "Compressed", kRight, kRight, 1, 12 }, - { kpidPath, "Name", kLeft, kLeft, 2, 24 } -}; - -const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width -static const char *g_Spaces = -" " ; - -static void PrintSpaces(unsigned numSpaces) -{ - if (numSpaces > 0 && numSpaces <= kNumSpacesMax) - g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces); -} - -static void PrintSpacesToString(char *dest, unsigned numSpaces) -{ - unsigned i; - for (i = 0; i < numSpaces; i++) - dest[i] = ' '; - dest[i] = 0; -} - -// extern int g_CodePage; - -static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp) -{ - /* - // we don't need multibyte align. - int codePage = g_CodePage; - if (codePage == -1) - codePage = CP_OEMCP; - if (codePage == CP_UTF8) - ConvertUnicodeToUTF8(s, temp); - else - UnicodeStringToMultiByte2(temp, s, (UINT)codePage); - */ - - unsigned numSpaces = 0; - - if (width > s.Len()) - { - numSpaces = width - s.Len(); - unsigned numLeftSpaces = 0; - switch ((int)adj) - { - // case kLeft: numLeftSpaces = 0; break; - case kCenter: numLeftSpaces = numSpaces / 2; break; - case kRight: numLeftSpaces = numSpaces; break; - // case kLeft: - default: break; - } - PrintSpaces(numLeftSpaces); - numSpaces -= numLeftSpaces; - } - - g_StdOut.PrintUString(s, temp); - PrintSpaces(numSpaces); -} - -static void PrintString(EAdjustment adj, unsigned width, const char *s) -{ - unsigned numSpaces = 0; - unsigned len = (unsigned)strlen(s); - - if (width > len) - { - numSpaces = width - len; - unsigned numLeftSpaces = 0; - switch ((int)adj) - { - // case kLeft: numLeftSpaces = 0; break; - case kCenter: numLeftSpaces = numSpaces / 2; break; - case kRight: numLeftSpaces = numSpaces; break; - // case kLeft: - default: break; - } - PrintSpaces(numLeftSpaces); - numSpaces -= numLeftSpaces; - } - - g_StdOut << s; - PrintSpaces(numSpaces); -} - -static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString) -{ - unsigned numSpaces = 0; - unsigned len = (unsigned)strlen(textString); - - if (width > len) - { - numSpaces = width - len; - unsigned numLeftSpaces = 0; - switch ((int)adj) - { - // case kLeft: numLeftSpaces = 0; break; - case kCenter: numLeftSpaces = numSpaces / 2; break; - case kRight: numLeftSpaces = numSpaces; break; - // case kLeft: - default: break; - } - PrintSpacesToString(dest, numLeftSpaces); - dest += numLeftSpaces; - numSpaces -= numLeftSpaces; - } - - memcpy(dest, textString, len); - dest += len; - PrintSpacesToString(dest, numSpaces); -} - -struct CListUInt64Def -{ - UInt64 Val; - bool Def; - - CListUInt64Def(): Val(0), Def(false) {} - void Add(UInt64 v) { Val += v; Def = true; } - void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } -}; - - -struct CListFileTimeDef: public CArcTime -{ - void Update(const CListFileTimeDef &t) - { - if (t.Def && (!Def || CompareWith(t) < 0)) - (*this) = t; - } -}; - - - -struct CListStat -{ - CListUInt64Def Size; - CListUInt64Def PackSize; - CListFileTimeDef MTime; - UInt64 NumFiles; - - CListStat(): NumFiles(0) {} - void Update(const CListStat &st) - { - Size.Add(st.Size); - PackSize.Add(st.PackSize); - MTime.Update(st.MTime); - NumFiles += st.NumFiles; - } - void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; } -}; - -struct CListStat2 -{ - CListStat MainFiles; - CListStat AltStreams; - UInt64 NumDirs; - - CListStat2(): NumDirs(0) {} - - void Update(const CListStat2 &st) - { - MainFiles.Update(st.MainFiles); - AltStreams.Update(st.AltStreams); - NumDirs += st.NumDirs; - } - UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; } - CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; } -}; - -class CFieldPrinter -{ - CObjectVector _fields; - - void AddProp(const wchar_t *name, PROPID propID, bool isRawProp); -public: - const CArc *Arc; - bool TechMode; - UString FilePath; - AString TempAString; - UString TempWString; - bool IsDir; - - AString LinesString; - - void Clear() { _fields.Clear(); LinesString.Empty(); } - void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems); - - HRESULT AddMainProps(IInArchive *archive); - HRESULT AddRawProps(IArchiveGetRawProps *getRawProps); - - void PrintTitle(); - void PrintTitleLines(); - HRESULT PrintItemInfo(UInt32 index, const CListStat &st); - void PrintSum(const CListStat &st, UInt64 numDirs, const char *str); - void PrintSum(const CListStat2 &stat2); -}; - -void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems) -{ - Clear(); - for (unsigned i = 0; i < numItems; i++) - { - CFieldInfo &f = _fields.AddNew(); - const CFieldInfoInit &fii = standardFieldTable[i]; - f.PropID = fii.PropID; - f.IsRawProp = false; - f.NameA = fii.Name; - f.TitleAdjustment = fii.TitleAdjustment; - f.TextAdjustment = fii.TextAdjustment; - f.PrefixSpacesWidth = fii.PrefixSpacesWidth; - f.Width = fii.Width; - - unsigned k; - for (k = 0; k < fii.PrefixSpacesWidth; k++) - LinesString.Add_Space(); - for (k = 0; k < fii.Width; k++) - LinesString.Add_Minus(); - } -} - -static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU) -{ - if (propID < Z7_ARRAY_SIZE(kPropIdToName)) - { - nameA = kPropIdToName[propID]; - return; - } - if (name) - nameU = name; - else - { - nameA.Empty(); - nameA.Add_UInt32(propID); - } -} - -void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp) -{ - CFieldInfo f; - f.PropID = propID; - f.IsRawProp = isRawProp; - GetPropName(propID, name, f.NameA, f.NameU); - f.NameU += " = "; - if (!f.NameA.IsEmpty()) - f.NameA += " = "; - else - { - const UString &s = f.NameU; - AString sA; - unsigned i; - for (i = 0; i < s.Len(); i++) - { - const wchar_t c = s[i]; - if (c >= 0x80) - break; - sA.Add_Char((char)c); - } - if (i == s.Len()) - f.NameA = sA; - } - _fields.Add(f); -} - -HRESULT CFieldPrinter::AddMainProps(IInArchive *archive) -{ - UInt32 numProps; - RINOK(archive->GetNumberOfProperties(&numProps)) - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt)) - AddProp(name, propID, false); - } - return S_OK; -} - -HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps) -{ - UInt32 numProps; - RINOK(getRawProps->GetNumRawProps(&numProps)) - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - RINOK(getRawProps->GetRawPropInfo(i, &name, &propID)) - AddProp(name, propID, true); - } - return S_OK; -} - -void CFieldPrinter::PrintTitle() -{ - FOR_VECTOR (i, _fields) - { - const CFieldInfo &f = _fields[i]; - PrintSpaces(f.PrefixSpacesWidth); - PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA); - } -} - -void CFieldPrinter::PrintTitleLines() -{ - g_StdOut << LinesString; -} - -static void PrintTime(char *dest, const CListFileTimeDef &t, bool showNS) -{ - *dest = 0; - if (t.IsZero()) - return; - int prec = kTimestampPrintLevel_SEC; - unsigned flags = 0; - if (showNS) // techmode - { - prec = kTimestampPrintLevel_NTFS; - if (t.Prec != 0) - { - prec = t.GetNumDigits(); - if (prec < kTimestampPrintLevel_DAY) - prec = kTimestampPrintLevel_NTFS; - } - } - else - { - // we want same default number of characters, so we disable 'Z' marker: - flags = kTimestampPrintFlags_DisableZ; - } - - ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec, flags); -} - -#ifndef Z7_SFX - -#endif - -#define MY_ENDL endl - -inline bool IsPropId_for_PathString(UInt32 propId) -{ - return (propId == kpidPath - // || propId == kpidName - || propId == kpidSymLink - || propId == kpidHardLink - || propId == kpidCopyLink); -} - -HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st) -{ - char temp[128]; - size_t tempPos = 0; - - bool techMode = this->TechMode; - /* - if (techMode) - { - g_StdOut << "Index = "; - g_StdOut << (UInt64)index; - g_StdOut << endl; - } - */ - FOR_VECTOR (i, _fields) - { - const CFieldInfo &f = _fields[i]; - - if (!techMode) - { - PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth); - tempPos += f.PrefixSpacesWidth; - } - - if (techMode) - { - if (!f.NameA.IsEmpty()) - g_StdOut << f.NameA; - else - g_StdOut << f.NameU; - } - - if (f.PropID == kpidPath) - { - if (!techMode) - g_StdOut << temp; - g_StdOut.NormalizePrint_UString_Path(FilePath, TempWString, TempAString); - if (techMode) - g_StdOut << MY_ENDL; - continue; - } - - const unsigned width = f.Width; - - if (f.IsRawProp) - { - #ifndef Z7_SFX - - const void *data; - UInt32 dataSize; - UInt32 propType; - RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType)) - - if (dataSize != 0) - { - bool needPrint = true; - - if (f.PropID == kpidNtSecure) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - #ifndef Z7_SFX - ConvertNtSecureToString((const Byte *)data, dataSize, TempAString); - g_StdOut << TempAString; - needPrint = false; - #endif - } - else if (f.PropID == kpidNtReparse) - { - UString s; - if (ConvertNtReparseToString((const Byte *)data, dataSize, s)) - { - needPrint = false; - g_StdOut.PrintUString(s, TempAString); - } - } - - if (needPrint) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - - const UInt32 kMaxDataSize = 64; - - if (dataSize > kMaxDataSize) - { - g_StdOut << "data:"; - g_StdOut << dataSize; - } - else - { - char hexStr[kMaxDataSize * 2 + 4]; - ConvertDataToHex_Lower(hexStr, (const Byte *)data, dataSize); - g_StdOut << hexStr; - } - } - } - - #endif - } - else - { - CPropVariant prop; - switch (f.PropID) - { - case kpidSize: if (st.Size.Def) prop = st.Size.Val; break; - case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break; - case kpidMTime: - { - const CListFileTimeDef &mtime = st.MTime; - if (mtime.Def) - prop.SetAsTimeFrom_FT_Prec_Ns100(mtime.FT, mtime.Prec, mtime.Ns100); - break; - } - default: - RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)) - } - if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4)) - { - GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos); - if (techMode) - g_StdOut << temp + tempPos; - else - tempPos += strlen(temp + tempPos); - } - else if (prop.vt == VT_EMPTY) - { - if (!techMode) - { - PrintSpacesToString(temp + tempPos, width); - tempPos += width; - } - } - else if (prop.vt == VT_FILETIME) - { - CListFileTimeDef t; - t.Set_From_Prop(prop); - PrintTime(temp + tempPos, t, techMode); - if (techMode) - g_StdOut << temp + tempPos; - else - { - size_t len = strlen(temp + tempPos); - tempPos += len; - if (len < (unsigned)f.Width) - { - len = f.Width - len; - PrintSpacesToString(temp + tempPos, (unsigned)len); - tempPos += len; - } - } - } - else if (prop.vt == VT_BSTR) - { - TempWString.SetFromBstr(prop.bstrVal); - // do we need multi-line support here ? - if (IsPropId_for_PathString(f.PropID)) - g_StdOut.Normalize_UString_Path(TempWString); - else - g_StdOut.Normalize_UString(TempWString); - if (techMode) - g_StdOut.PrintUString(TempWString, TempAString); - else - PrintUString(f.TextAdjustment, width, TempWString, TempAString); - } - else - { - char s[64]; - ConvertPropertyToShortString2(s, prop, f.PropID); - if (techMode) - g_StdOut << s; - else - { - PrintStringToString(temp + tempPos, f.TextAdjustment, width, s); - tempPos += strlen(temp + tempPos); - } - } - } - if (techMode) - g_StdOut << MY_ENDL; - } - g_StdOut << MY_ENDL; - return S_OK; -} - -static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value) -{ - char s[32]; - s[0] = 0; - if (value.Def) - ConvertUInt64ToString(value.Val, s); - PrintString(adj, width, s); -} - -void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); - -void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str) -{ - FOR_VECTOR (i, _fields) - { - const CFieldInfo &f = _fields[i]; - PrintSpaces(f.PrefixSpacesWidth); - if (f.PropID == kpidSize) - PrintNumber(f.TextAdjustment, f.Width, st.Size); - else if (f.PropID == kpidPackSize) - PrintNumber(f.TextAdjustment, f.Width, st.PackSize); - else if (f.PropID == kpidMTime) - { - char s[64]; - s[0] = 0; - if (st.MTime.Def) - PrintTime(s, st.MTime, false); // showNS - PrintString(f.TextAdjustment, f.Width, s); - } - else if (f.PropID == kpidPath) - { - AString s; - Print_UInt64_and_String(s, st.NumFiles, str); - if (numDirs != 0) - { - s += ", "; - Print_UInt64_and_String(s, numDirs, kString_Dirs); - } - PrintString(f.TextAdjustment, 0, s); - } - else - PrintString(f.TextAdjustment, f.Width, ""); - } - g_StdOut << endl; -} - -void CFieldPrinter::PrintSum(const CListStat2 &stat2) -{ - PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files); - if (stat2.AltStreams.NumFiles != 0) - { - PrintSum(stat2.AltStreams, 0, kString_AltStreams); - CListStat st = stat2.MainFiles; - st.Update(stat2.AltStreams); - PrintSum(st, 0, kString_Streams); - } -} - -static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value) -{ - value.Val = 0; - value.Def = false; - CPropVariant prop; - RINOK(archive->GetProperty(index, propID, &prop)) - value.Def = ConvertPropVariantToUInt64(prop, value.Val); - return S_OK; -} - -static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) -{ - /* maybe we could call CArc::GetItemMTime(UInt32 index, CArcTime &ft, bool &defined) here - that can set default timestamp, if not defined */ - t.Clear(); - // t.Def = false; - CPropVariant prop; - RINOK(archive->GetProperty(index, kpidMTime, &prop)) - if (prop.vt == VT_FILETIME) - t.Set_From_Prop(prop); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val) -{ - so << name << ": " << val << endl; -} - -static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID) -{ - const char *s; - char temp[16]; - if (propID < Z7_ARRAY_SIZE(kPropIdToName)) - s = kPropIdToName[propID]; - else - { - ConvertUInt32ToString(propID, temp); - s = temp; - } - so << s << " = "; -} - -static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val) -{ - PrintPropName_and_Eq(so, propID); - so << val << endl; -} - -static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val) -{ - PrintPropName_and_Eq(so, propID); - so << val << endl; -} - - -static void UString_Replace_CRLF_to_LF(UString &s) -{ - // s.Replace(L"\r\n", L"\n"); - wchar_t *src = s.GetBuf(); - wchar_t *dest = src; - for (;;) - { - wchar_t c = *src++; - if (c == 0) - break; - if (c == '\r' && *src == '\n') - { - src++; - c = '\n'; - } - *dest++ = c; - } - s.ReleaseBuf_SetEnd((unsigned)(size_t)(dest - s.GetBuf())); -} - -static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val) -{ - UString s (val); - if (s.Find(L'\n') >= 0) - { - so << endl; - so << "{"; - so << endl; - UString_Replace_CRLF_to_LF(s); - UString temp; - unsigned start = 0; - for (;;) - { - unsigned size = s.Len() - start; - if (size == 0) - break; - const int next = s.Find(L'\n', start); - if (next >= 0) - size = (unsigned)next - start; - temp.SetFrom(s.Ptr() + start, size); - so.NormalizePrint_UString(temp); - so << endl; - if (next < 0) - break; - start = (unsigned)next + 1; - } - so << "}"; - } - else - { - so.NormalizePrint_UString(s); - } - so << endl; -} - - -static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine, bool isPath = false) -{ - so << name << " = "; - if (multiLine) - { - PrintPropVal_MultiLine(so, val); - return; - } - UString s (val); - if (isPath) - so.Normalize_UString_Path(s); - else - so.Normalize_UString(s); - so << s; - so << endl; -} - - -static void PrintPropPair_Path(CStdOutStream &so, const wchar_t *path) -{ - PrintPropPair(so, "Path", path, - false, // multiLine - true); // isPath -} - -static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop) -{ - UString s; - const int levelTopLimit = 9; // 1ns level - ConvertPropertyToString2(s, prop, propID, levelTopLimit); - if (!s.IsEmpty()) - { - AString nameA; - UString nameU; - GetPropName(propID, name, nameA, nameU); - if (!nameA.IsEmpty()) - so << nameA; - else - so << nameU; - so << " = "; - PrintPropVal_MultiLine(so, s); - } -} - -static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name) -{ - CPropVariant prop; - RINOK(archive->GetArchiveProperty(propID, &prop)) - PrintPropertyPair2(so, propID, name, prop); - return S_OK; -} - -static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning) -{ - so << "Open " << (isWarning ? "WARNING" : "ERROR") - << ": Cannot open the file as [" - << type - << "] archive" - << endl; -} - -int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name); - -void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); - -static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er) -{ - PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags()); - if (!er.ErrorMessage.IsEmpty()) - PrintPropPair(so, "ERROR", er.ErrorMessage, true); - - PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags()); - if (!er.WarningMessage.IsEmpty()) - PrintPropPair(so, "WARNING", er.WarningMessage, true); -} - -HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); -HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) -{ - FOR_VECTOR (r, arcLink.Arcs) - { - const CArc &arc = arcLink.Arcs[r]; - const CArcErrorInfo &er = arc.ErrorInfo; - - so << "--\n"; - PrintPropPair_Path(so, arc.Path); - if (er.ErrorFormatIndex >= 0) - { - if (er.ErrorFormatIndex == arc.FormatIndex) - so << "Warning: The archive is open with offset" << endl; - else - PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true); - } - PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false); - - ErrorInfo_Print(so, er); - - Int64 offset = arc.GetGlobalOffset(); - if (offset != 0) - PrintPropNameAndNumber_Signed(so, kpidOffset, offset); - IInArchive *archive = arc.Archive; - RINOK(PrintArcProp(so, archive, kpidPhySize, NULL)) - if (er.TailSize != 0) - PrintPropNameAndNumber(so, kpidTailSize, er.TailSize); - { - UInt32 numProps; - RINOK(archive->GetNumberOfArchiveProperties(&numProps)) - - for (UInt32 j = 0; j < numProps; j++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt)) - RINOK(PrintArcProp(so, archive, propID, name)) - } - } - - if (r != arcLink.Arcs.Size() - 1) - { - UInt32 numProps; - so << "----\n"; - if (archive->GetNumberOfProperties(&numProps) == S_OK) - { - UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex; - for (UInt32 j = 0; j < numProps; j++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt)) - CPropVariant prop; - RINOK(archive->GetProperty(mainIndex, propID, &prop)) - PrintPropertyPair2(so, propID, name, prop); - } - } - } - } - return S_OK; -} - -HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); -HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) -{ - #ifndef Z7_NO_CRYPTO - if (arcLink.PasswordWasAsked) - so << "Cannot open encrypted archive. Wrong password?"; - else - #endif - { - if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) - { - so.NormalizePrint_UString_Path(arcLink.NonOpen_ArcPath); - so << endl; - PrintArcTypeError(so, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); - } - else - so << "Cannot open the file as archive"; - } - - so << endl; - so << endl; - ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo); - - return S_OK; -} - -bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); - -HRESULT ListArchives( - const CListOptions &listOptions, - CCodecs *codecs, - const CObjectVector &types, - const CIntVector &excludedFormats, - bool stdInMode, - UStringVector &arcPaths, UStringVector &arcPathsFull, - bool processAltStreams, bool showAltStreams, - const NWildcard::CCensorNode &wildcardCensor, - bool enableHeaders, bool techMode, - #ifndef Z7_NO_CRYPTO - bool &passwordEnabled, UString &password, - #endif - #ifndef Z7_SFX - const CObjectVector *props, - #endif - UInt64 &numErrors, - UInt64 &numWarnings) -{ - bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); - - numErrors = 0; - numWarnings = 0; - - CFieldPrinter fp; - if (!techMode) - fp.Init(kStandardFieldTable, Z7_ARRAY_SIZE(kStandardFieldTable)); - - CListStat2 stat2total; - - CBoolArr skipArcs(arcPaths.Size()); - unsigned arcIndex; - for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) - skipArcs[arcIndex] = false; - UInt64 numVolumes = 0; - UInt64 numArcs = 0; - UInt64 totalArcSizes = 0; - - HRESULT lastError = 0; - - for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) - { - if (skipArcs[arcIndex]) - continue; - const UString &arcPath = arcPaths[arcIndex]; - UInt64 arcPackSize = 0; - - if (!stdInMode) - { - NFile::NFind::CFileInfo fi; - if (!fi.Find_FollowLink(us2fs(arcPath))) - { - DWORD errorCode = GetLastError(); - if (errorCode == 0) - errorCode = ERROR_FILE_NOT_FOUND; - lastError = HRESULT_FROM_WIN32(errorCode); - g_StdOut.Flush(); - if (g_ErrStream) - { - *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl; - g_ErrStream->NormalizePrint_UString_Path(arcPath); - *g_ErrStream << endl << endl; - } - numErrors++; - continue; - } - if (fi.IsDir()) - { - g_StdOut.Flush(); - if (g_ErrStream) - { - *g_ErrStream << endl << kError; - g_ErrStream->NormalizePrint_UString_Path(arcPath); - *g_ErrStream << " is not a file" << endl << endl; - } - numErrors++; - continue; - } - arcPackSize = fi.Size; - totalArcSizes += arcPackSize; - } - - CArchiveLink arcLink; - - COpenCallbackConsole openCallback; - openCallback.Init(&g_StdOut, g_ErrStream, NULL, listOptions.DisablePercents); - - #ifndef Z7_NO_CRYPTO - - openCallback.PasswordIsDefined = passwordEnabled; - openCallback.Password = password; - - #endif - - /* - CObjectVector optPropsVector; - COptionalOpenProperties &optProps = optPropsVector.AddNew(); - optProps.Props = *props; - */ - - COpenOptions options; - #ifndef Z7_SFX - options.props = props; - #endif - options.codecs = codecs; - options.types = &types; - options.excludedFormats = &excludedFormats; - options.stdInMode = stdInMode; - options.stream = NULL; - options.filePath = arcPath; - - if (enableHeaders) - { - g_StdOut << endl << kListing; - g_StdOut.NormalizePrint_UString_Path(arcPath); - g_StdOut << endl << endl; - } - - HRESULT result = arcLink.Open_Strict(options, &openCallback); - - if (result != S_OK) - { - if (result == E_ABORT) - return result; - if (result != S_FALSE) - lastError = result; - g_StdOut.Flush(); - if (g_ErrStream) - { - *g_ErrStream << endl << kError; - g_ErrStream->NormalizePrint_UString_Path(arcPath); - *g_ErrStream << " : "; - if (result == S_FALSE) - { - Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink); - } - else - { - *g_ErrStream << "opening : "; - if (result == E_OUTOFMEMORY) - *g_ErrStream << "Can't allocate required memory"; - else - *g_ErrStream << NError::MyFormatMessage(result); - } - *g_ErrStream << endl; - } - numErrors++; - continue; - } - - { - FOR_VECTOR (r, arcLink.Arcs) - { - const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo; - if (!arc.WarningMessage.IsEmpty()) - numWarnings++; - if (arc.AreThereWarnings()) - numWarnings++; - if (arc.ErrorFormatIndex >= 0) - numWarnings++; - if (arc.AreThereErrors()) - { - numErrors++; - // break; - } - if (!arc.ErrorMessage.IsEmpty()) - numErrors++; - } - } - - numArcs++; - numVolumes++; - - if (!stdInMode) - { - numVolumes += arcLink.VolumePaths.Size(); - totalArcSizes += arcLink.VolumesSize; - FOR_VECTOR (v, arcLink.VolumePaths) - { - int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); - if (index >= 0 && (unsigned)index > arcIndex) - skipArcs[(unsigned)index] = true; - } - } - - - if (enableHeaders) - { - RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink)) - - g_StdOut << endl; - if (techMode) - g_StdOut << "----------\n"; - } - - if (enableHeaders && !techMode) - { - fp.PrintTitle(); - g_StdOut << endl; - fp.PrintTitleLines(); - g_StdOut << endl; - } - - const CArc &arc = arcLink.Arcs.Back(); - fp.Arc = &arc; - fp.TechMode = techMode; - IInArchive *archive = arc.Archive; - if (techMode) - { - fp.Clear(); - RINOK(fp.AddMainProps(archive)) - if (arc.GetRawProps) - { - RINOK(fp.AddRawProps(arc.GetRawProps)) - } - } - - CListStat2 stat2; - - UInt32 numItems; - RINOK(archive->GetNumberOfItems(&numItems)) - - CReadArcItem item; - UStringVector pathParts; - - for (UInt32 i = 0; i < numItems; i++) - { - if (NConsoleClose::TestBreakSignal()) - return E_ABORT; - - HRESULT res = arc.GetItem_Path2(i, fp.FilePath); - - if (stdInMode && res == E_INVALIDARG) - break; - RINOK(res) - - if (arc.Ask_Aux) - { - bool isAux; - RINOK(Archive_IsItem_Aux(archive, i, isAux)) - if (isAux) - continue; - } - - bool isAltStream = false; - if (arc.Ask_AltStream) - { - RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)) - if (isAltStream && !processAltStreams) - continue; - } - - RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir)) - - if (fp.IsDir ? listOptions.ExcludeDirItems : listOptions.ExcludeFileItems) - continue; - - if (!allFilesAreAllowed) - { - if (isAltStream) - { - RINOK(arc.GetItem(i, item)) - if (!CensorNode_CheckPath(wildcardCensor, item)) - continue; - } - else - { - SplitPathToParts(fp.FilePath, pathParts); - bool include; - if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include)) - continue; - if (!include) - continue; - } - } - - CListStat st; - - RINOK(GetUInt64Value(archive, i, kpidSize, st.Size)) - RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize)) - RINOK(GetItemMTime(archive, i, st.MTime)) - - if (fp.IsDir) - stat2.NumDirs++; - else - st.NumFiles = 1; - stat2.GetStat(isAltStream).Update(st); - - if (isAltStream && !showAltStreams) - continue; - RINOK(fp.PrintItemInfo(i, st)) - } - - UInt64 numStreams = stat2.GetNumStreams(); - if (!stdInMode - && !stat2.MainFiles.PackSize.Def - && !stat2.AltStreams.PackSize.Def) - { - if (arcLink.VolumePaths.Size() != 0) - arcPackSize += arcLink.VolumesSize; - stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize); - } - - stat2.MainFiles.SetSizeDefIfNoFiles(); - stat2.AltStreams.SetSizeDefIfNoFiles(); - - if (enableHeaders && !techMode) - { - fp.PrintTitleLines(); - g_StdOut << endl; - fp.PrintSum(stat2); - } - - if (enableHeaders) - { - if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) - { - g_StdOut << "----------\n"; - PrintPropPair_Path(g_StdOut, arcLink.NonOpen_ArcPath); - PrintArcTypeError(g_StdOut, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); - } - } - - stat2total.Update(stat2); - - g_StdOut.Flush(); - } - - if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1)) - { - g_StdOut << endl; - fp.PrintTitleLines(); - g_StdOut << endl; - fp.PrintSum(stat2total); - g_StdOut << endl; - PrintPropNameAndNumber(g_StdOut, "Archives", numArcs); - PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes); - PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes); - } - - if (numErrors == 1 && lastError != 0) - return lastError; - - return S_OK; -} +// List.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/MyCom.h" +#include "../../../Common/StdOutStream.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../Common/OpenArchive.h" +#include "../Common/PropIDUtils.h" + +#include "ConsoleClose.h" +#include "List.h" +#include "OpenCallbackConsole.h" + +using namespace NWindows; +using namespace NCOM; + +extern CStdOutStream *g_StdStream; +extern CStdOutStream *g_ErrStream; + +static const char * const kPropIdToName[] = +{ + "0" + , "1" + , "2" + , "Path" + , "Name" + , "Extension" + , "Folder" + , "Size" + , "Packed Size" + , "Attributes" + , "Created" + , "Accessed" + , "Modified" + , "Solid" + , "Commented" + , "Encrypted" + , "Split Before" + , "Split After" + , "Dictionary Size" + , "CRC" + , "Type" + , "Anti" + , "Method" + , "Host OS" + , "File System" + , "User" + , "Group" + , "Block" + , "Comment" + , "Position" + , "Path Prefix" + , "Folders" + , "Files" + , "Version" + , "Volume" + , "Multivolume" + , "Offset" + , "Links" + , "Blocks" + , "Volumes" + , "Time Type" + , "64-bit" + , "Big-endian" + , "CPU" + , "Physical Size" + , "Headers Size" + , "Checksum" + , "Characteristics" + , "Virtual Address" + , "ID" + , "Short Name" + , "Creator Application" + , "Sector Size" + , "Mode" + , "Symbolic Link" + , "Error" + , "Total Size" + , "Free Space" + , "Cluster Size" + , "Label" + , "Local Name" + , "Provider" + , "NT Security" + , "Alternate Stream" + , "Aux" + , "Deleted" + , "Tree" + , "SHA-1" + , "SHA-256" + , "Error Type" + , "Errors" + , "Errors" + , "Warnings" + , "Warning" + , "Streams" + , "Alternate Streams" + , "Alternate Streams Size" + , "Virtual Size" + , "Unpack Size" + , "Total Physical Size" + , "Volume Index" + , "SubType" + , "Short Comment" + , "Code Page" + , "Is not archive type" + , "Physical Size can't be detected" + , "Zeros Tail Is Allowed" + , "Tail Size" + , "Embedded Stub Size" + , "Link" + , "Hard Link" + , "iNode" + , "Stream ID" + , "Read-only" + , "Out Name" + , "Copy Link" + , "ArcFileName" + , "IsHash" + , "Metadata Changed" + , "User ID" + , "Group ID" + , "Device Major" + , "Device Minor" + , "Dev Major" + , "Dev Minor" +}; + +static const char kEmptyAttribChar = '.'; + +static const char * const kListing = "Listing archive: "; + +static const char * const kString_Files = "files"; +static const char * const kString_Dirs = "folders"; +static const char * const kString_AltStreams = "alternate streams"; +static const char * const kString_Streams = "streams"; + +static const char * const kError = "ERROR: "; + +static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s) +{ + if (isDir) + wa |= FILE_ATTRIBUTE_DIRECTORY; + if (allAttribs) + { + ConvertWinAttribToString(s, wa); + return; + } + s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar; + s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar; + s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar; + s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar; + s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar; + s[5] = 0; +} + +enum EAdjustment +{ + kLeft, + kCenter, + kRight +}; + +struct CFieldInfo +{ + PROPID PropID; + bool IsRawProp; + UString NameU; + AString NameA; + EAdjustment TitleAdjustment; + EAdjustment TextAdjustment; + unsigned PrefixSpacesWidth; + unsigned Width; +}; + +struct CFieldInfoInit +{ + PROPID PropID; + const char *Name; + EAdjustment TitleAdjustment; + EAdjustment TextAdjustment; + unsigned PrefixSpacesWidth; + unsigned Width; +}; + +static const CFieldInfoInit kStandardFieldTable[] = +{ + { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 }, + { kpidAttrib, "Attr", kRight, kCenter, 1, 5 }, + { kpidSize, "Size", kRight, kRight, 1, 12 }, + { kpidPackSize, "Compressed", kRight, kRight, 1, 12 }, + { kpidPath, "Name", kLeft, kLeft, 2, 24 } +}; + +const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width +static const char *g_Spaces = +" " ; + +static void PrintSpaces(unsigned numSpaces) +{ + if (numSpaces > 0 && numSpaces <= kNumSpacesMax) + g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces); +} + +static void PrintSpacesToString(char *dest, unsigned numSpaces) +{ + unsigned i; + for (i = 0; i < numSpaces; i++) + dest[i] = ' '; + dest[i] = 0; +} + +// extern int g_CodePage; + +static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp) +{ + /* + // we don't need multibyte align. + int codePage = g_CodePage; + if (codePage == -1) + codePage = CP_OEMCP; + if (codePage == CP_UTF8) + ConvertUnicodeToUTF8(s, temp); + else + UnicodeStringToMultiByte2(temp, s, (UINT)codePage); + */ + + unsigned numSpaces = 0; + + if (width > s.Len()) + { + numSpaces = width - s.Len(); + unsigned numLeftSpaces = 0; + switch ((int)adj) + { + // case kLeft: numLeftSpaces = 0; break; + case kCenter: numLeftSpaces = numSpaces / 2; break; + case kRight: numLeftSpaces = numSpaces; break; + // case kLeft: + default: break; + } + PrintSpaces(numLeftSpaces); + numSpaces -= numLeftSpaces; + } + + g_StdOut.PrintUString(s, temp); + PrintSpaces(numSpaces); +} + +static void PrintString(EAdjustment adj, unsigned width, const char *s) +{ + unsigned numSpaces = 0; + unsigned len = (unsigned)strlen(s); + + if (width > len) + { + numSpaces = width - len; + unsigned numLeftSpaces = 0; + switch ((int)adj) + { + // case kLeft: numLeftSpaces = 0; break; + case kCenter: numLeftSpaces = numSpaces / 2; break; + case kRight: numLeftSpaces = numSpaces; break; + // case kLeft: + default: break; + } + PrintSpaces(numLeftSpaces); + numSpaces -= numLeftSpaces; + } + + g_StdOut << s; + PrintSpaces(numSpaces); +} + +static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString) +{ + unsigned numSpaces = 0; + unsigned len = (unsigned)strlen(textString); + + if (width > len) + { + numSpaces = width - len; + unsigned numLeftSpaces = 0; + switch ((int)adj) + { + // case kLeft: numLeftSpaces = 0; break; + case kCenter: numLeftSpaces = numSpaces / 2; break; + case kRight: numLeftSpaces = numSpaces; break; + // case kLeft: + default: break; + } + PrintSpacesToString(dest, numLeftSpaces); + dest += numLeftSpaces; + numSpaces -= numLeftSpaces; + } + + memcpy(dest, textString, len); + dest += len; + PrintSpacesToString(dest, numSpaces); +} + +struct CListUInt64Def +{ + UInt64 Val; + bool Def; + + CListUInt64Def(): Val(0), Def(false) {} + void Add(UInt64 v) { Val += v; Def = true; } + void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } +}; + + +struct CListFileTimeDef: public CArcTime +{ + void Update(const CListFileTimeDef &t) + { + if (t.Def && (!Def || CompareWith(t) < 0)) + (*this) = t; + } +}; + + + +struct CListStat +{ + CListUInt64Def Size; + CListUInt64Def PackSize; + CListFileTimeDef MTime; + UInt64 NumFiles; + + CListStat(): NumFiles(0) {} + void Update(const CListStat &st) + { + Size.Add(st.Size); + PackSize.Add(st.PackSize); + MTime.Update(st.MTime); + NumFiles += st.NumFiles; + } + void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; } +}; + +struct CListStat2 +{ + CListStat MainFiles; + CListStat AltStreams; + UInt64 NumDirs; + + CListStat2(): NumDirs(0) {} + + void Update(const CListStat2 &st) + { + MainFiles.Update(st.MainFiles); + AltStreams.Update(st.AltStreams); + NumDirs += st.NumDirs; + } + UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; } + CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; } +}; + +class CFieldPrinter +{ + CObjectVector _fields; + + void AddProp(const wchar_t *name, PROPID propID, bool isRawProp); +public: + const CArc *Arc; + bool TechMode; + UString FilePath; + AString TempAString; + UString TempWString; + bool IsDir; + + AString LinesString; + + void Clear() { _fields.Clear(); LinesString.Empty(); } + void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems); + + HRESULT AddMainProps(IInArchive *archive); + HRESULT AddRawProps(IArchiveGetRawProps *getRawProps); + + void PrintTitle(); + void PrintTitleLines(); + HRESULT PrintItemInfo(UInt32 index, const CListStat &st); + void PrintSum(const CListStat &st, UInt64 numDirs, const char *str); + void PrintSum(const CListStat2 &stat2); +}; + +void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems) +{ + Clear(); + for (unsigned i = 0; i < numItems; i++) + { + CFieldInfo &f = _fields.AddNew(); + const CFieldInfoInit &fii = standardFieldTable[i]; + f.PropID = fii.PropID; + f.IsRawProp = false; + f.NameA = fii.Name; + f.TitleAdjustment = fii.TitleAdjustment; + f.TextAdjustment = fii.TextAdjustment; + f.PrefixSpacesWidth = fii.PrefixSpacesWidth; + f.Width = fii.Width; + + unsigned k; + for (k = 0; k < fii.PrefixSpacesWidth; k++) + LinesString.Add_Space(); + for (k = 0; k < fii.Width; k++) + LinesString.Add_Minus(); + } +} + +static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU) +{ + if (propID < Z7_ARRAY_SIZE(kPropIdToName)) + { + nameA = kPropIdToName[propID]; + return; + } + if (name) + nameU = name; + else + { + nameA.Empty(); + nameA.Add_UInt32(propID); + } +} + +void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp) +{ + CFieldInfo f; + f.PropID = propID; + f.IsRawProp = isRawProp; + GetPropName(propID, name, f.NameA, f.NameU); + f.NameU += " = "; + if (!f.NameA.IsEmpty()) + f.NameA += " = "; + else + { + const UString &s = f.NameU; + AString sA; + unsigned i; + for (i = 0; i < s.Len(); i++) + { + const wchar_t c = s[i]; + if (c >= 0x80) + break; + sA.Add_Char((char)c); + } + if (i == s.Len()) + f.NameA = sA; + } + _fields.Add(f); +} + +HRESULT CFieldPrinter::AddMainProps(IInArchive *archive) +{ + UInt32 numProps; + RINOK(archive->GetNumberOfProperties(&numProps)) + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt)) + AddProp(name, propID, false); + } + return S_OK; +} + +HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps) +{ + UInt32 numProps; + RINOK(getRawProps->GetNumRawProps(&numProps)) + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + RINOK(getRawProps->GetRawPropInfo(i, &name, &propID)) + AddProp(name, propID, true); + } + return S_OK; +} + +void CFieldPrinter::PrintTitle() +{ + FOR_VECTOR (i, _fields) + { + const CFieldInfo &f = _fields[i]; + PrintSpaces(f.PrefixSpacesWidth); + PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA); + } +} + +void CFieldPrinter::PrintTitleLines() +{ + g_StdOut << LinesString; +} + +static void PrintTime(char *dest, const CListFileTimeDef &t, bool showNS) +{ + *dest = 0; + if (t.IsZero()) + return; + int prec = kTimestampPrintLevel_SEC; + unsigned flags = 0; + if (showNS) // techmode + { + prec = kTimestampPrintLevel_NTFS; + if (t.Prec != 0) + { + prec = t.GetNumDigits(); + if (prec < kTimestampPrintLevel_DAY) + prec = kTimestampPrintLevel_NTFS; + } + } + else + { + // we want same default number of characters, so we disable 'Z' marker: + flags = kTimestampPrintFlags_DisableZ; + } + + ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec, flags); +} + +#ifndef Z7_SFX + +#endif + +#define MY_ENDL endl + +inline bool IsPropId_for_PathString(UInt32 propId) +{ + return (propId == kpidPath + // || propId == kpidName + || propId == kpidSymLink + || propId == kpidHardLink + || propId == kpidCopyLink); +} + +HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st) +{ + char temp[128]; + size_t tempPos = 0; + + bool techMode = this->TechMode; + /* + if (techMode) + { + g_StdOut << "Index = "; + g_StdOut << (UInt64)index; + g_StdOut << endl; + } + */ + FOR_VECTOR (i, _fields) + { + const CFieldInfo &f = _fields[i]; + + if (!techMode) + { + PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth); + tempPos += f.PrefixSpacesWidth; + } + + if (techMode) + { + if (!f.NameA.IsEmpty()) + g_StdOut << f.NameA; + else + g_StdOut << f.NameU; + } + + if (f.PropID == kpidPath) + { + if (!techMode) + g_StdOut << temp; + g_StdOut.NormalizePrint_UString_Path(FilePath, TempWString, TempAString); + if (techMode) + g_StdOut << MY_ENDL; + continue; + } + + const unsigned width = f.Width; + + if (f.IsRawProp) + { + #ifndef Z7_SFX + + const void *data; + UInt32 dataSize; + UInt32 propType; + RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType)) + + if (dataSize != 0) + { + bool needPrint = true; + + if (f.PropID == kpidNtSecure) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + #ifndef Z7_SFX + ConvertNtSecureToString((const Byte *)data, dataSize, TempAString); + g_StdOut << TempAString; + needPrint = false; + #endif + } + else if (f.PropID == kpidNtReparse) + { + UString s; + if (ConvertNtReparseToString((const Byte *)data, dataSize, s)) + { + needPrint = false; + g_StdOut.PrintUString(s, TempAString); + } + } + + if (needPrint) + { + if (propType != NPropDataType::kRaw) + return E_FAIL; + + const UInt32 kMaxDataSize = 64; + + if (dataSize > kMaxDataSize) + { + g_StdOut << "data:"; + g_StdOut << dataSize; + } + else + { + char hexStr[kMaxDataSize * 2 + 4]; + ConvertDataToHex_Lower(hexStr, (const Byte *)data, dataSize); + g_StdOut << hexStr; + } + } + } + + #endif + } + else + { + CPropVariant prop; + switch (f.PropID) + { + case kpidSize: if (st.Size.Def) prop = st.Size.Val; break; + case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break; + case kpidMTime: + { + const CListFileTimeDef &mtime = st.MTime; + if (mtime.Def) + prop.SetAsTimeFrom_FT_Prec_Ns100(mtime.FT, mtime.Prec, mtime.Ns100); + break; + } + default: + RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)) + } + if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4)) + { + GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos); + if (techMode) + g_StdOut << temp + tempPos; + else + tempPos += strlen(temp + tempPos); + } + else if (prop.vt == VT_EMPTY) + { + if (!techMode) + { + PrintSpacesToString(temp + tempPos, width); + tempPos += width; + } + } + else if (prop.vt == VT_FILETIME) + { + CListFileTimeDef t; + t.Set_From_Prop(prop); + PrintTime(temp + tempPos, t, techMode); + if (techMode) + g_StdOut << temp + tempPos; + else + { + size_t len = strlen(temp + tempPos); + tempPos += len; + if (len < (unsigned)f.Width) + { + len = f.Width - len; + PrintSpacesToString(temp + tempPos, (unsigned)len); + tempPos += len; + } + } + } + else if (prop.vt == VT_BSTR) + { + TempWString.SetFromBstr(prop.bstrVal); + // do we need multi-line support here ? + if (IsPropId_for_PathString(f.PropID)) + g_StdOut.Normalize_UString_Path(TempWString); + else + g_StdOut.Normalize_UString(TempWString); + if (techMode) + g_StdOut.PrintUString(TempWString, TempAString); + else + PrintUString(f.TextAdjustment, width, TempWString, TempAString); + } + else + { + char s[64]; + ConvertPropertyToShortString2(s, prop, f.PropID); + if (techMode) + g_StdOut << s; + else + { + PrintStringToString(temp + tempPos, f.TextAdjustment, width, s); + tempPos += strlen(temp + tempPos); + } + } + } + if (techMode) + g_StdOut << MY_ENDL; + } + g_StdOut << MY_ENDL; + return S_OK; +} + +static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value) +{ + char s[32]; + s[0] = 0; + if (value.Def) + ConvertUInt64ToString(value.Val, s); + PrintString(adj, width, s); +} + +void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); + +void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str) +{ + FOR_VECTOR (i, _fields) + { + const CFieldInfo &f = _fields[i]; + PrintSpaces(f.PrefixSpacesWidth); + if (f.PropID == kpidSize) + PrintNumber(f.TextAdjustment, f.Width, st.Size); + else if (f.PropID == kpidPackSize) + PrintNumber(f.TextAdjustment, f.Width, st.PackSize); + else if (f.PropID == kpidMTime) + { + char s[64]; + s[0] = 0; + if (st.MTime.Def) + PrintTime(s, st.MTime, false); // showNS + PrintString(f.TextAdjustment, f.Width, s); + } + else if (f.PropID == kpidPath) + { + AString s; + Print_UInt64_and_String(s, st.NumFiles, str); + if (numDirs != 0) + { + s += ", "; + Print_UInt64_and_String(s, numDirs, kString_Dirs); + } + PrintString(f.TextAdjustment, 0, s); + } + else + PrintString(f.TextAdjustment, f.Width, ""); + } + g_StdOut << endl; +} + +void CFieldPrinter::PrintSum(const CListStat2 &stat2) +{ + PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files); + if (stat2.AltStreams.NumFiles != 0) + { + PrintSum(stat2.AltStreams, 0, kString_AltStreams); + CListStat st = stat2.MainFiles; + st.Update(stat2.AltStreams); + PrintSum(st, 0, kString_Streams); + } +} + +static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value) +{ + value.Val = 0; + value.Def = false; + CPropVariant prop; + RINOK(archive->GetProperty(index, propID, &prop)) + value.Def = ConvertPropVariantToUInt64(prop, value.Val); + return S_OK; +} + +static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) +{ + /* maybe we could call CArc::GetItemMTime(UInt32 index, CArcTime &ft, bool &defined) here + that can set default timestamp, if not defined */ + t.Clear(); + // t.Def = false; + CPropVariant prop; + RINOK(archive->GetProperty(index, kpidMTime, &prop)) + if (prop.vt == VT_FILETIME) + t.Set_From_Prop(prop); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val) +{ + so << name << ": " << val << endl; +} + +static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID) +{ + const char *s; + char temp[16]; + if (propID < Z7_ARRAY_SIZE(kPropIdToName)) + s = kPropIdToName[propID]; + else + { + ConvertUInt32ToString(propID, temp); + s = temp; + } + so << s << " = "; +} + +static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val) +{ + PrintPropName_and_Eq(so, propID); + so << val << endl; +} + +static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val) +{ + PrintPropName_and_Eq(so, propID); + so << val << endl; +} + + +static void UString_Replace_CRLF_to_LF(UString &s) +{ + // s.Replace(L"\r\n", L"\n"); + wchar_t *src = s.GetBuf(); + wchar_t *dest = src; + for (;;) + { + wchar_t c = *src++; + if (c == 0) + break; + if (c == '\r' && *src == '\n') + { + src++; + c = '\n'; + } + *dest++ = c; + } + s.ReleaseBuf_SetEnd((unsigned)(size_t)(dest - s.GetBuf())); +} + +static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val) +{ + UString s (val); + if (s.Find(L'\n') >= 0) + { + so << endl; + so << "{"; + so << endl; + UString_Replace_CRLF_to_LF(s); + UString temp; + unsigned start = 0; + for (;;) + { + unsigned size = s.Len() - start; + if (size == 0) + break; + const int next = s.Find(L'\n', start); + if (next >= 0) + size = (unsigned)next - start; + temp.SetFrom(s.Ptr() + start, size); + so.NormalizePrint_UString(temp); + so << endl; + if (next < 0) + break; + start = (unsigned)next + 1; + } + so << "}"; + } + else + { + so.NormalizePrint_UString(s); + } + so << endl; +} + + +static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine, bool isPath = false) +{ + so << name << " = "; + if (multiLine) + { + PrintPropVal_MultiLine(so, val); + return; + } + UString s (val); + if (isPath) + so.Normalize_UString_Path(s); + else + so.Normalize_UString(s); + so << s; + so << endl; +} + + +static void PrintPropPair_Path(CStdOutStream &so, const wchar_t *path) +{ + PrintPropPair(so, "Path", path, + false, // multiLine + true); // isPath +} + +static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop) +{ + UString s; + const int levelTopLimit = 9; // 1ns level + ConvertPropertyToString2(s, prop, propID, levelTopLimit); + if (!s.IsEmpty()) + { + AString nameA; + UString nameU; + GetPropName(propID, name, nameA, nameU); + if (!nameA.IsEmpty()) + so << nameA; + else + so << nameU; + so << " = "; + PrintPropVal_MultiLine(so, s); + } +} + +static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name) +{ + CPropVariant prop; + RINOK(archive->GetArchiveProperty(propID, &prop)) + PrintPropertyPair2(so, propID, name, prop); + return S_OK; +} + +static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning) +{ + so << "Open " << (isWarning ? "WARNING" : "ERROR") + << ": Cannot open the file as [" + << type + << "] archive" + << endl; +} + +int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name); + +void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); + +static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er) +{ + PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags()); + if (!er.ErrorMessage.IsEmpty()) + PrintPropPair(so, "ERROR", er.ErrorMessage, true); + + PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags()); + if (!er.WarningMessage.IsEmpty()) + PrintPropPair(so, "WARNING", er.WarningMessage, true); +} + +HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); +HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) +{ + FOR_VECTOR (r, arcLink.Arcs) + { + const CArc &arc = arcLink.Arcs[r]; + const CArcErrorInfo &er = arc.ErrorInfo; + + so << "--\n"; + PrintPropPair_Path(so, arc.Path); + if (er.ErrorFormatIndex >= 0) + { + if (er.ErrorFormatIndex == arc.FormatIndex) + so << "Warning: The archive is open with offset" << endl; + else + PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true); + } + PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false); + + ErrorInfo_Print(so, er); + + Int64 offset = arc.GetGlobalOffset(); + if (offset != 0) + PrintPropNameAndNumber_Signed(so, kpidOffset, offset); + IInArchive *archive = arc.Archive; + RINOK(PrintArcProp(so, archive, kpidPhySize, NULL)) + if (er.TailSize != 0) + PrintPropNameAndNumber(so, kpidTailSize, er.TailSize); + { + UInt32 numProps; + RINOK(archive->GetNumberOfArchiveProperties(&numProps)) + + for (UInt32 j = 0; j < numProps; j++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt)) + RINOK(PrintArcProp(so, archive, propID, name)) + } + } + + if (r != arcLink.Arcs.Size() - 1) + { + UInt32 numProps; + so << "----\n"; + if (archive->GetNumberOfProperties(&numProps) == S_OK) + { + UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex; + for (UInt32 j = 0; j < numProps; j++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt)) + CPropVariant prop; + RINOK(archive->GetProperty(mainIndex, propID, &prop)) + PrintPropertyPair2(so, propID, name, prop); + } + } + } + } + return S_OK; +} + +HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); +HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink) +{ + #ifndef Z7_NO_CRYPTO + if (arcLink.PasswordWasAsked) + so << "Cannot open encrypted archive. Wrong password?"; + else + #endif + { + if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + { + so.NormalizePrint_UString_Path(arcLink.NonOpen_ArcPath); + so << endl; + PrintArcTypeError(so, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); + } + else + so << "Cannot open the file as archive"; + } + + so << endl; + so << endl; + ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo); + + return S_OK; +} + +bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); + +HRESULT ListArchives( + const CListOptions &listOptions, + CCodecs *codecs, + const CObjectVector &types, + const CIntVector &excludedFormats, + bool stdInMode, + UStringVector &arcPaths, UStringVector &arcPathsFull, + bool processAltStreams, bool showAltStreams, + const NWildcard::CCensorNode &wildcardCensor, + bool enableHeaders, bool techMode, + #ifndef Z7_NO_CRYPTO + bool &passwordEnabled, UString &password, + #endif + #ifndef Z7_SFX + const CObjectVector *props, + #endif + UInt64 &numErrors, + UInt64 &numWarnings) +{ + bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); + + numErrors = 0; + numWarnings = 0; + + CFieldPrinter fp; + if (!techMode) + fp.Init(kStandardFieldTable, Z7_ARRAY_SIZE(kStandardFieldTable)); + + CListStat2 stat2total; + + CBoolArr skipArcs(arcPaths.Size()); + unsigned arcIndex; + for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) + skipArcs[arcIndex] = false; + UInt64 numVolumes = 0; + UInt64 numArcs = 0; + UInt64 totalArcSizes = 0; + + HRESULT lastError = 0; + + for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++) + { + if (skipArcs[arcIndex]) + continue; + const UString &arcPath = arcPaths[arcIndex]; + UInt64 arcPackSize = 0; + + if (!stdInMode) + { + NFile::NFind::CFileInfo fi; + if (!fi.Find_FollowLink(us2fs(arcPath))) + { + DWORD errorCode = GetLastError(); + if (errorCode == 0) + errorCode = ERROR_FILE_NOT_FOUND; + lastError = HRESULT_FROM_WIN32(errorCode); + g_StdOut.Flush(); + if (g_ErrStream) + { + *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl; + g_ErrStream->NormalizePrint_UString_Path(arcPath); + *g_ErrStream << endl << endl; + } + numErrors++; + continue; + } + if (fi.IsDir()) + { + g_StdOut.Flush(); + if (g_ErrStream) + { + *g_ErrStream << endl << kError; + g_ErrStream->NormalizePrint_UString_Path(arcPath); + *g_ErrStream << " is not a file" << endl << endl; + } + numErrors++; + continue; + } + arcPackSize = fi.Size; + totalArcSizes += arcPackSize; + } + + CArchiveLink arcLink; + + COpenCallbackConsole openCallback; + openCallback.Init(&g_StdOut, g_ErrStream, NULL, listOptions.DisablePercents); + + #ifndef Z7_NO_CRYPTO + + openCallback.PasswordIsDefined = passwordEnabled; + openCallback.Password = password; + + #endif + + /* + CObjectVector optPropsVector; + COptionalOpenProperties &optProps = optPropsVector.AddNew(); + optProps.Props = *props; + */ + + COpenOptions options; + #ifndef Z7_SFX + options.props = props; + #endif + options.codecs = codecs; + options.types = &types; + options.excludedFormats = &excludedFormats; + options.stdInMode = stdInMode; + options.stream = NULL; + options.filePath = arcPath; + + if (enableHeaders) + { + g_StdOut << endl << kListing; + g_StdOut.NormalizePrint_UString_Path(arcPath); + g_StdOut << endl << endl; + } + + HRESULT result = arcLink.Open_Strict(options, &openCallback); + + if (result != S_OK) + { + if (result == E_ABORT) + return result; + if (result != S_FALSE) + lastError = result; + g_StdOut.Flush(); + if (g_ErrStream) + { + *g_ErrStream << endl << kError; + g_ErrStream->NormalizePrint_UString_Path(arcPath); + *g_ErrStream << " : "; + if (result == S_FALSE) + { + Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink); + } + else + { + *g_ErrStream << "opening : "; + if (result == E_OUTOFMEMORY) + *g_ErrStream << "Can't allocate required memory"; + else + *g_ErrStream << NError::MyFormatMessage(result); + } + *g_ErrStream << endl; + } + numErrors++; + continue; + } + + { + FOR_VECTOR (r, arcLink.Arcs) + { + const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo; + if (!arc.WarningMessage.IsEmpty()) + numWarnings++; + if (arc.AreThereWarnings()) + numWarnings++; + if (arc.ErrorFormatIndex >= 0) + numWarnings++; + if (arc.AreThereErrors()) + { + numErrors++; + // break; + } + if (!arc.ErrorMessage.IsEmpty()) + numErrors++; + } + } + + numArcs++; + numVolumes++; + + if (!stdInMode) + { + numVolumes += arcLink.VolumePaths.Size(); + totalArcSizes += arcLink.VolumesSize; + FOR_VECTOR (v, arcLink.VolumePaths) + { + int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); + if (index >= 0 && (unsigned)index > arcIndex) + skipArcs[(unsigned)index] = true; + } + } + + + if (enableHeaders) + { + RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink)) + + g_StdOut << endl; + if (techMode) + g_StdOut << "----------\n"; + } + + if (enableHeaders && !techMode) + { + fp.PrintTitle(); + g_StdOut << endl; + fp.PrintTitleLines(); + g_StdOut << endl; + } + + const CArc &arc = arcLink.Arcs.Back(); + fp.Arc = &arc; + fp.TechMode = techMode; + IInArchive *archive = arc.Archive; + if (techMode) + { + fp.Clear(); + RINOK(fp.AddMainProps(archive)) + if (arc.GetRawProps) + { + RINOK(fp.AddRawProps(arc.GetRawProps)) + } + } + + CListStat2 stat2; + + UInt32 numItems; + RINOK(archive->GetNumberOfItems(&numItems)) + + CReadArcItem item; + UStringVector pathParts; + + for (UInt32 i = 0; i < numItems; i++) + { + if (NConsoleClose::TestBreakSignal()) + return E_ABORT; + + HRESULT res = arc.GetItem_Path2(i, fp.FilePath); + + if (stdInMode && res == E_INVALIDARG) + break; + RINOK(res) + + if (arc.Ask_Aux) + { + bool isAux; + RINOK(Archive_IsItem_Aux(archive, i, isAux)) + if (isAux) + continue; + } + + bool isAltStream = false; + if (arc.Ask_AltStream) + { + RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)) + if (isAltStream && !processAltStreams) + continue; + } + + RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir)) + + if (fp.IsDir ? listOptions.ExcludeDirItems : listOptions.ExcludeFileItems) + continue; + + if (!allFilesAreAllowed) + { + if (isAltStream) + { + RINOK(arc.GetItem(i, item)) + if (!CensorNode_CheckPath(wildcardCensor, item)) + continue; + } + else + { + SplitPathToParts(fp.FilePath, pathParts); + bool include; + if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include)) + continue; + if (!include) + continue; + } + } + + CListStat st; + + RINOK(GetUInt64Value(archive, i, kpidSize, st.Size)) + RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize)) + RINOK(GetItemMTime(archive, i, st.MTime)) + + if (fp.IsDir) + stat2.NumDirs++; + else + st.NumFiles = 1; + stat2.GetStat(isAltStream).Update(st); + + if (isAltStream && !showAltStreams) + continue; + RINOK(fp.PrintItemInfo(i, st)) + } + + UInt64 numStreams = stat2.GetNumStreams(); + if (!stdInMode + && !stat2.MainFiles.PackSize.Def + && !stat2.AltStreams.PackSize.Def) + { + if (arcLink.VolumePaths.Size() != 0) + arcPackSize += arcLink.VolumesSize; + stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize); + } + + stat2.MainFiles.SetSizeDefIfNoFiles(); + stat2.AltStreams.SetSizeDefIfNoFiles(); + + if (enableHeaders && !techMode) + { + fp.PrintTitleLines(); + g_StdOut << endl; + fp.PrintSum(stat2); + } + + if (enableHeaders) + { + if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + { + g_StdOut << "----------\n"; + PrintPropPair_Path(g_StdOut, arcLink.NonOpen_ArcPath); + PrintArcTypeError(g_StdOut, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false); + } + } + + stat2total.Update(stat2); + + g_StdOut.Flush(); + } + + if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1)) + { + g_StdOut << endl; + fp.PrintTitleLines(); + g_StdOut << endl; + fp.PrintSum(stat2total); + g_StdOut << endl; + PrintPropNameAndNumber(g_StdOut, "Archives", numArcs); + PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes); + PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes); + } + + if (numErrors == 1 && lastError != 0) + return lastError; + + return S_OK; +} diff --git a/CPP/7zip/UI/Console/List.h b/CPP/7zip/UI/Console/List.h index 0494d8f6d..d87f512b6 100644 --- a/CPP/7zip/UI/Console/List.h +++ b/CPP/7zip/UI/Console/List.h @@ -1,42 +1,42 @@ -// List.h - -#ifndef ZIP7_INC_LIST_H -#define ZIP7_INC_LIST_H - -#include "../../../Common/Wildcard.h" - -#include "../Common/LoadCodecs.h" - -struct CListOptions -{ - bool ExcludeDirItems; - bool ExcludeFileItems; - bool DisablePercents; - - CListOptions(): - ExcludeDirItems(false), - ExcludeFileItems(false), - DisablePercents(false) - {} -}; - -HRESULT ListArchives( - const CListOptions &listOptions, - CCodecs *codecs, - const CObjectVector &types, - const CIntVector &excludedFormats, - bool stdInMode, - UStringVector &archivePaths, UStringVector &archivePathsFull, - bool processAltStreams, bool showAltStreams, - const NWildcard::CCensorNode &wildcardCensor, - bool enableHeaders, bool techMode, - #ifndef Z7_NO_CRYPTO - bool &passwordEnabled, UString &password, - #endif - #ifndef Z7_SFX - const CObjectVector *props, - #endif - UInt64 &errors, - UInt64 &numWarnings); - -#endif +// List.h + +#ifndef ZIP7_INC_LIST_H +#define ZIP7_INC_LIST_H + +#include "../../../Common/Wildcard.h" + +#include "../Common/LoadCodecs.h" + +struct CListOptions +{ + bool ExcludeDirItems; + bool ExcludeFileItems; + bool DisablePercents; + + CListOptions(): + ExcludeDirItems(false), + ExcludeFileItems(false), + DisablePercents(false) + {} +}; + +HRESULT ListArchives( + const CListOptions &listOptions, + CCodecs *codecs, + const CObjectVector &types, + const CIntVector &excludedFormats, + bool stdInMode, + UStringVector &archivePaths, UStringVector &archivePathsFull, + bool processAltStreams, bool showAltStreams, + const NWildcard::CCensorNode &wildcardCensor, + bool enableHeaders, bool techMode, + #ifndef Z7_NO_CRYPTO + bool &passwordEnabled, UString &password, + #endif + #ifndef Z7_SFX + const CObjectVector *props, + #endif + UInt64 &errors, + UInt64 &numWarnings); + +#endif diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index 4fa5c3500..dabd69628 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -1,1632 +1,1632 @@ -// Main.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#ifdef _WIN32 - -#ifndef Z7_OLD_WIN_SDK - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#else // Z7_OLD_WIN_SDK - -typedef struct { - DWORD cb; - DWORD PageFaultCount; - SIZE_T PeakWorkingSetSize; - SIZE_T WorkingSetSize; - SIZE_T QuotaPeakPagedPoolUsage; - SIZE_T QuotaPagedPoolUsage; - SIZE_T QuotaPeakNonPagedPoolUsage; - SIZE_T QuotaNonPagedPoolUsage; - SIZE_T PagefileUsage; - SIZE_T PeakPagefileUsage; -} PROCESS_MEMORY_COUNTERS; -typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - -#endif // Z7_OLD_WIN_SDK - -#else // _WIN32 -#include -#include -#include -#include -#endif // _WIN32 - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyException.h" -#include "../../../Common/StdInStream.h" -#include "../../../Common/StdOutStream.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/TimeUtils.h" -#include "../../../Windows/FileDir.h" - -#include "../Common/ArchiveCommandLine.h" -#include "../Common/Bench.h" -#include "../Common/ExitCode.h" -#include "../Common/Extract.h" - -#ifdef Z7_EXTERNAL_CODECS -#include "../Common/LoadCodecs.h" -#endif - -#include "../../Common/RegisterCodec.h" - -#include "BenchCon.h" -#include "ConsoleClose.h" -#include "ExtractCallbackConsole.h" -#include "HashCon.h" -#include "List.h" -#include "OpenCallbackConsole.h" -#include "UpdateCallbackConsole.h" - -#ifdef Z7_PROG_VARIANT_R -#include "../../../../C/7zVersion.h" -#else -#include "../../MyVersion.h" -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NCommandLineParser; - -#ifdef _WIN32 -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance = NULL; -#endif - -extern CStdOutStream *g_StdStream; -extern CStdOutStream *g_ErrStream; - -extern unsigned g_NumCodecs; -extern const CCodecInfo *g_Codecs[]; - -extern unsigned g_NumHashers; -extern const CHasherInfo *g_Hashers[]; - -#ifdef Z7_EXTERNAL_CODECS -extern -const CExternalCodecs *g_ExternalCodecs_Ptr; -const CExternalCodecs *g_ExternalCodecs_Ptr; -#endif - -DECLARE_AND_SET_CLIENT_VERSION_VAR - -#if defined(Z7_PROG_VARIANT_Z) - #define PROG_POSTFIX "z" - #define PROG_POSTFIX_2 " (z)" -#elif defined(Z7_PROG_VARIANT_R) - #define PROG_POSTFIX "r" - #define PROG_POSTFIX_2 " (r)" -#elif defined(Z7_PROG_VARIANT_A) || !defined(Z7_EXTERNAL_CODECS) - #define PROG_POSTFIX "a" - #define PROG_POSTFIX_2 " (a)" -#else - #define PROG_POSTFIX "" - #define PROG_POSTFIX_2 "" -#endif - - -static const char * const kCopyrightString = "\n7-Zip" - PROG_POSTFIX_2 - " " MY_VERSION_CPU - " : " MY_COPYRIGHT_DATE "\n"; - -static const char * const kHelpString = - "Usage: 7z" - PROG_POSTFIX - " [...] [...] [@listfile]\n" - "\n" - "\n" - " a : Add files to archive\n" - " b : Benchmark\n" - " d : Delete files from archive\n" - " e : Extract files from archive (without using directory names)\n" - " h : Calculate hash values for files\n" - " i : Show information about supported formats\n" - " l : List contents of archive\n" - " rn : Rename files in archive\n" - " t : Test integrity of archive\n" - " u : Update files to archive\n" - " x : eXtract files with full paths\n" - "\n" - "\n" - " -- : Stop switches and @listfile parsing\n" - " -ai[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : Include archives\n" - " -ax[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : eXclude archives\n" - " -ao{a|s|t|u} : set Overwrite mode\n" - " -an : disable archive_name field\n" - " -bb[0-3] : set output log level\n" - " -bd : disable progress indicator\n" - " -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n" - " -bt : show execution time statistics\n" - " -i[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : Include filenames\n" - " -m{Parameters} : set compression Method\n" - " -mmt[N] : set number of CPU threads\n" - " -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra)\n" - " -o{Directory} : set Output directory\n" - #ifndef Z7_NO_CRYPTO - " -p{Password} : set Password\n" - #endif - " -r[-|0] : Recurse subdirectories for name search\n" - " -sa{a|e|s} : set Archive name mode\n" - " -scc{UTF-8|WIN|DOS} : set charset for console input/output\n" - " -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n" - " -scrc[CRC32|CRC64|SHA256" -#ifndef Z7_PROG_VARIANT_R - "|SHA1|XXH64" -#ifdef Z7_PROG_VARIANT_Z - "|BLAKE2SP" -#endif -#endif - "|*] : set hash function for x, e, h commands\n" - " -sdel : delete files after compression\n" - " -seml[.] : send archive by email\n" - " -sfx[{name}] : Create SFX archive\n" - " -si[{name}] : read data from stdin\n" - " -slp : set Large Pages mode\n" - " -slt : show technical information for l (List) command\n" - " -snh : store hard links as links\n" - " -snl : store symbolic links as links\n" - " -sni : store NT security information\n" - " -sns[-] : store NTFS alternate streams\n" - " -so : write data to stdout\n" - " -spd : disable wildcard matching for file names\n" - " -spe : eliminate duplication of root folder for extract command\n" - " -spf[2] : use fully qualified file paths\n" - " -ssc[-] : set sensitive case mode\n" - " -sse : stop archive creating, if it can't open some input file\n" - " -ssp : do not change Last Access Time of source files while archiving\n" - " -ssw : compress shared files\n" - " -stl : set archive timestamp from the most recently modified file\n" - " -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n" - " -stx{Type} : exclude archive type\n" - " -t{Type} : Set type of archive\n" - " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n" - " -v{Size}[b|k|m|g] : Create volumes\n" - " -w[{path}] : assign Work directory. Empty path means a temporary directory\n" - " -x[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : eXclude filenames\n" - " -y : assume Yes on all queries\n"; - -// --------------------------- -// exception messages - -static const char * const kEverythingIsOk = "Everything is Ok"; -static const char * const kUserErrorMessage = "Incorrect command line"; -static const char * const kNoFormats = "7-Zip cannot find the code that works with archives."; -static const char * const kUnsupportedArcTypeMessage = "Unsupported archive type"; -// static const char * const kUnsupportedUpdateArcType = "Can't create archive for that type"; - -#ifndef Z7_EXTRACT_ONLY -#define kDefaultSfxModule "7zCon.sfx" -#endif - -Z7_ATTR_NORETURN -static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code) -{ - if (g_ErrStream) - *g_ErrStream << endl << "ERROR: " << message << endl; - throw code; -} - - -#ifdef _WIN32 -#define ShowProgInfo(so) -#else -static void ShowProgInfo(CStdOutStream *so) -{ - if (!so) - return; - - *so - - /* - #ifdef __DATE__ - << " " << __DATE__ - #endif - #ifdef __TIME__ - << " " << __TIME__ - #endif - */ - - << " " << (unsigned)(sizeof(void *)) * 8 << "-bit" - - #ifdef __ILP32__ - << " ILP32" - #endif - - #ifdef __ARM_ARCH - << " arm_v:" << __ARM_ARCH - #if (__ARM_ARCH == 8) - // for macos: - #if defined(__ARM_ARCH_8_9__) - << ".9" - #elif defined(__ARM_ARCH_8_8__) - << ".8" - #elif defined(__ARM_ARCH_8_7__) - << ".7" - #elif defined(__ARM_ARCH_8_6__) - << ".6" - #elif defined(__ARM_ARCH_8_5__) - << ".5" - #elif defined(__ARM_ARCH_8_4__) - << ".4" - #elif defined(__ARM_ARCH_8_3__) - << ".3" - #elif defined(__ARM_ARCH_8_2__) - << ".2" - #elif defined(__ARM_ARCH_8_1__) - << ".1" - #endif - #endif - - #if defined(__ARM_ARCH_PROFILE) && \ - ( __ARM_ARCH_PROFILE >= 'A' && __ARM_ARCH_PROFILE <= 'Z' \ - || __ARM_ARCH_PROFILE >= 65 && __ARM_ARCH_PROFILE <= 65 + 25) - << "-" << (char)__ARM_ARCH_PROFILE - #endif - - #ifdef __ARM_ARCH_ISA_THUMB - << " thumb:" << __ARM_ARCH_ISA_THUMB - #endif - #endif - - #ifdef _MIPS_ARCH - << " mips_arch:" << _MIPS_ARCH - #endif - #ifdef __mips_isa_rev - << " mips_isa_rev:" << __mips_isa_rev - #endif - - #ifdef __iset__ - << " e2k_v:" << __iset__ - #endif - ; - - - - #ifdef ENV_HAVE_LOCALE - *so << " locale=" << GetLocale(); - #endif - #ifndef _WIN32 - { - const bool is_IsNativeUTF8 = IsNativeUTF8(); - if (!is_IsNativeUTF8) - *so << " UTF8=" << (is_IsNativeUTF8 ? "+" : "-"); - } - if (!g_ForceToUTF8) - *so << " use-UTF8=" << (g_ForceToUTF8 ? "+" : "-"); - { - const unsigned wchar_t_size = (unsigned)sizeof(wchar_t); - if (wchar_t_size != 4) - *so << " wchar_t=" << wchar_t_size * 8 << "-bit"; - } - { - const unsigned off_t_size = (unsigned)sizeof(off_t); - if (off_t_size != 8) - *so << " Files=" << off_t_size * 8 << "-bit"; - } - #endif - - { - const UInt32 numCpus = NWindows::NSystem::GetNumberOfProcessors(); - *so << " Threads:" << numCpus; - const UInt64 openMAX= NWindows::NSystem::Get_File_OPEN_MAX(); - *so << " OPEN_MAX:" << openMAX; - { - FString temp; - NDir::MyGetTempPath(temp); - if (!temp.IsEqualTo(STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR)) - *so << " temp_path:" << temp; - } - } - - #ifdef Z7_7ZIP_ASM - *so << ", ASM"; - #endif - - /* - { - AString s; - GetCpuName(s); - s.Trim(); - *so << ", " << s; - } - - #ifdef __ARM_FEATURE_CRC32 - << " CRC32" - #endif - - - #if (defined MY_CPU_X86_OR_AMD64 || defined(MY_CPU_ARM_OR_ARM64)) - if (CPU_IsSupported_AES()) *so << ",AES"; - #endif - - #ifdef MY_CPU_ARM_OR_ARM64 - if (CPU_IsSupported_CRC32()) *so << ",CRC32"; - #if defined(_WIN32) - if (CPU_IsSupported_CRYPTO()) *so << ",CRYPTO"; - #else - if (CPU_IsSupported_SHA1()) *so << ",SHA1"; - if (CPU_IsSupported_SHA2()) *so << ",SHA2"; - #endif - #endif - */ - - *so << endl; -} -#endif - -static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp) -{ - if (!so) - return; - *so << kCopyrightString; - // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << endl; - ShowProgInfo(so); - *so << endl; - if (needHelp) - *so << kHelpString; -} - - -static void PrintStringRight(CStdOutStream &so, const char *s, unsigned size) -{ - unsigned len = MyStringLen(s); - for (unsigned i = len; i < size; i++) - so << ' '; - so << s; -} - -static void PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size) -{ - char s[16]; - ConvertUInt32ToString(val, s); - PrintStringRight(so, s, size); -} - -#ifdef Z7_EXTERNAL_CODECS -static void PrintNumber(CStdOutStream &so, UInt32 val, unsigned numDigits) -{ - AString s; - s.Add_UInt32(val); - while (s.Len() < numDigits) - s.InsertAtFront('0'); - so << s; -} -#endif - -static void PrintLibIndex(CStdOutStream &so, int libIndex) -{ - if (libIndex >= 0) - PrintUInt32(so, (UInt32)libIndex, 2); - else - so << " "; - so << ' '; -} - -static void PrintString(CStdOutStream &so, const UString &s, unsigned size) -{ - unsigned len = s.Len(); - so << s; - for (unsigned i = len; i < size; i++) - so << ' '; -} - -static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so) -{ - FOR_VECTOR(i, pc.Paths) - { - so.NormalizePrint_UString_Path(fs2us(pc.Paths[i])); - so << " : "; - so << NError::MyFormatMessage(pc.Codes[i]) << endl; - } - so << "----------------" << endl; -} - -static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback, - const CUpdateErrorInfo &errorInfo, - CStdOutStream *so, - CStdOutStream *se, - bool showHeaders) -{ - int exitCode = NExitCode::kSuccess; - - if (callback.ScanErrors.Paths.Size() != 0) - { - if (se) - { - *se << endl; - *se << "Scan WARNINGS for files and folders:" << endl << endl; - PrintWarningsPaths(callback.ScanErrors, *se); - *se << "Scan WARNINGS: " << callback.ScanErrors.Paths.Size(); - *se << endl; - } - exitCode = NExitCode::kWarning; - } - - if (result != S_OK || errorInfo.ThereIsError()) - { - if (se) - { - UString message; - if (!errorInfo.Message.IsEmpty()) - { - message += errorInfo.Message.Ptr(); - message.Add_LF(); - } - { - FOR_VECTOR(i, errorInfo.FileNames) - { - message += fs2us(errorInfo.FileNames[i]); - message.Add_LF(); - } - } - if (errorInfo.SystemError != 0) - { - message += NError::MyFormatMessage(errorInfo.SystemError); - message.Add_LF(); - } - if (!message.IsEmpty()) - *se << L"\nError:\n" << message; - } - - // we will work with (result) later - // throw CSystemException(result); - return NExitCode::kFatalError; - } - - unsigned numErrors = callback.FailedFiles.Paths.Size(); - if (numErrors == 0) - { - if (showHeaders) - if (callback.ScanErrors.Paths.Size() == 0) - if (so) - { - if (se) - se->Flush(); - *so << kEverythingIsOk << endl; - } - } - else - { - if (se) - { - *se << endl; - *se << "WARNINGS for files:" << endl << endl; - PrintWarningsPaths(callback.FailedFiles, *se); - *se << "WARNING: Cannot open " << numErrors << " file"; - if (numErrors > 1) - *se << 's'; - *se << endl; - } - exitCode = NExitCode::kWarning; - } - - return exitCode; -} - -static void ThrowException_if_Error(HRESULT res) -{ - if (res != S_OK) - throw CSystemException(res); -} - -static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ') -{ - char temp[64]; - char *p = temp + 32; - ConvertUInt64ToString(val, p); - unsigned len = MyStringLen(p); - for (; len < numDigits; len++) - *--p = c; - *g_StdStream << p; -} - -#ifdef _WIN32 - -static void PrintTime(const char *s, UInt64 val, UInt64 total) -{ - *g_StdStream << endl << s << " Time ="; - const UInt32 kFreq = 10000000; - UInt64 sec = val / kFreq; - PrintNum(sec, 6); - *g_StdStream << '.'; - UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000); - PrintNum(ms, 3, '0'); - - while (val > ((UInt64)1 << 56)) - { - val >>= 1; - total >>= 1; - } - - UInt64 percent = 0; - if (total != 0) - percent = val * 100 / total; - *g_StdStream << " ="; - PrintNum(percent, 5); - *g_StdStream << '%'; -} - -#ifndef UNDER_CE - -#define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num)) - -static void PrintMemUsage(const char *s, UInt64 val) -{ - *g_StdStream << " " << s << " Memory ="; - PrintNum(SHIFT_SIZE_VALUE(val, 20), 7); - *g_StdStream << " MB"; - /* - *g_StdStream << " ="; - PrintNum(SHIFT_SIZE_VALUE(val, 10), 9); - *g_StdStream << " KB"; - */ - #ifdef Z7_LARGE_PAGES - AString lp; - Add_LargePages_String(lp); - if (!lp.IsEmpty()) - *g_StdStream << lp; - #endif -} - -EXTERN_C_BEGIN -typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process, - PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); -typedef BOOL (WINAPI *Func_QueryProcessCycleTime)(HANDLE Process, PULONG64 CycleTime); -EXTERN_C_END - -#endif - -static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } - -static void PrintStat() -{ - FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT; - if (! - #ifdef UNDER_CE - ::GetThreadTimes(::GetCurrentThread() - #else - // NT 3.5 - ::GetProcessTimes(::GetCurrentProcess() - #endif - , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT)) - return; - FILETIME curTimeFT; - NTime::GetCurUtc_FiTime(curTimeFT); - - #ifndef UNDER_CE - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - - PROCESS_MEMORY_COUNTERS m; - memset(&m, 0, sizeof(m)); - BOOL memDefined = FALSE; - BOOL cycleDefined = FALSE; - ULONG64 cycleTime = 0; - { - /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll - Win7: new function K32GetProcessMemoryInfo() in kernel32.dll - It's faster to call kernel32.dll code than Psapi.dll code - GetProcessMemoryInfo() requires Psapi.lib - Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll - The program with K32GetProcessMemoryInfo will not work on systems before Win7 - // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)); - */ - const HMODULE kern = ::GetModuleHandleW(L"kernel32.dll"); - Func_GetProcessMemoryInfo - my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS( - Func_GetProcessMemoryInfo, kern, - "K32GetProcessMemoryInfo"); - if (!my_GetProcessMemoryInfo) - { - const HMODULE lib = LoadLibraryW(L"Psapi.dll"); - if (lib) - my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS( - Func_GetProcessMemoryInfo, lib, - "GetProcessMemoryInfo"); - } - if (my_GetProcessMemoryInfo) - memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)); - // FreeLibrary(lib); - const - Func_QueryProcessCycleTime - my_QueryProcessCycleTime = Z7_GET_PROC_ADDRESS( - Func_QueryProcessCycleTime, kern, - "QueryProcessCycleTime"); - if (my_QueryProcessCycleTime) - cycleDefined = my_QueryProcessCycleTime(GetCurrentProcess(), &cycleTime); - } - - #endif - - UInt64 curTime = GetTime64(curTimeFT); - UInt64 creationTime = GetTime64(creationTimeFT); - UInt64 kernelTime = GetTime64(kernelTimeFT); - UInt64 userTime = GetTime64(userTimeFT); - - UInt64 totalTime = curTime - creationTime; - - PrintTime("Kernel ", kernelTime, totalTime); - - const UInt64 processTime = kernelTime + userTime; - - #ifndef UNDER_CE - if (cycleDefined) - { - *g_StdStream << " Cnt:"; - PrintNum(cycleTime / 1000000, 15); - *g_StdStream << " MCycles"; - } - #endif - - PrintTime("User ", userTime, totalTime); - - #ifndef UNDER_CE - if (cycleDefined) - { - *g_StdStream << " Freq (cnt/ptime):"; - UInt64 us = processTime / 10; - if (us == 0) - us = 1; - PrintNum(cycleTime / us, 6); - *g_StdStream << " MHz"; - } - #endif - - PrintTime("Process", processTime, totalTime); - #ifndef UNDER_CE - if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage); - #endif - - PrintTime("Global ", totalTime, totalTime); - #ifndef UNDER_CE - if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize); - #endif - *g_StdStream << endl; -} - - -#else // ! _WIN32 - -static UInt64 Get_timeofday_us() -{ - struct timeval now; - if (gettimeofday(&now, NULL) == 0) - return (UInt64)now.tv_sec * 1000000 + (UInt64)now.tv_usec; - return 0; -} - -static void PrintTime(const char *s, UInt64 val, UInt64 total_us, UInt64 kFreq) -{ - *g_StdStream << endl << s << " Time ="; - - { - UInt64 sec, ms; - - if (kFreq == 0) - { - sec = val / 1000000; - ms = val % 1000000 / 1000; - } - else - { - sec = val / kFreq; - ms = (UInt32)((val - (sec * kFreq)) * 1000 / kFreq); - } - - PrintNum(sec, 6); - *g_StdStream << '.'; - PrintNum(ms, 3, '0'); - } - - if (total_us == 0) - return; - - UInt64 percent = 0; - if (kFreq == 0) - percent = val * 100 / total_us; - else - { - const UInt64 kMaxVal = (UInt64)(Int64)-1; - UInt32 m = 100000000; - for (;;) - { - if (m == 0 || kFreq == 0) - break; - if (kMaxVal / m > val && - kMaxVal / kFreq > total_us) - break; - if (val > m) - val >>= 1; - else - m >>= 1; - if (kFreq > total_us) - kFreq >>= 1; - else - total_us >>= 1; - } - const UInt64 total = kFreq * total_us; - if (total != 0) - percent = val * m / total; - } - *g_StdStream << " ="; - PrintNum(percent, 5); - *g_StdStream << '%'; -} - -static void PrintStat(const UInt64 startTime) -{ - tms t; - /* clock_t res = */ times(&t); - const UInt64 totalTime = Get_timeofday_us() - startTime; - const UInt64 kFreq = (UInt64)sysconf(_SC_CLK_TCK); - PrintTime("Kernel ", (UInt64)t.tms_stime, totalTime, kFreq); - PrintTime("User ", (UInt64)t.tms_utime, totalTime, kFreq); - PrintTime("Process", (UInt64)t.tms_utime + (UInt64)t.tms_stime, totalTime, kFreq); - PrintTime("Global ", totalTime, totalTime, 0); - *g_StdStream << endl; -} - -#endif // ! _WIN32 - - - - - -static void PrintHexId(CStdOutStream &so, UInt64 id) -{ - char s[32]; - ConvertUInt64ToHex(id, s); - PrintStringRight(so, s, 8); -} - -#ifndef _WIN32 -void Set_ModuleDirPrefix_From_ProgArg0(const char *s); -#endif - -int Main2( - #ifndef _WIN32 - int numArgs, char *args[] - #endif -); -int Main2( - #ifndef _WIN32 - int numArgs, char *args[] - #endif -) -{ - #if defined(MY_CPU_SIZEOF_POINTER) - { unsigned k = sizeof(void *); if (k != MY_CPU_SIZEOF_POINTER) throw "incorrect MY_CPU_PTR_SIZE"; } - #endif - - #if defined(_WIN32) && !defined(UNDER_CE) - SetFileApisToOEM(); - #endif - - #ifdef ENV_HAVE_LOCALE - // printf("\nBefore SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8"); - MY_SetLocale(); - // printf("\nAfter SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8"); - #endif - - #ifndef _WIN32 - const UInt64 startTime = Get_timeofday_us(); - #endif - - /* - { - g_StdOut << "DWORD:" << (unsigned)sizeof(DWORD); - g_StdOut << " LONG:" << (unsigned)sizeof(LONG); - g_StdOut << " long:" << (unsigned)sizeof(long); - #ifdef _WIN64 - // g_StdOut << " long long:" << (unsigned)sizeof(long long); - #endif - g_StdOut << " int:" << (unsigned)sizeof(int); - g_StdOut << " void*:" << (unsigned)sizeof(void *); - g_StdOut << endl; - } - */ - - UStringVector commandStrings; - - #ifdef _WIN32 - NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); - #else - { - if (numArgs > 0) - Set_ModuleDirPrefix_From_ProgArg0(args[0]); - - for (int i = 0; i < numArgs; i++) - { - AString a (args[i]); -#if 0 - printf("\n%d %s :", i, a.Ptr()); - for (unsigned k = 0; k < a.Len(); k++) - printf(" %2x", (unsigned)(Byte)a[k]); -#endif - const UString s = MultiByteToUnicodeString(a); - commandStrings.Add(s); - } - // printf("\n"); - } - - #endif - - #ifndef UNDER_CE - if (commandStrings.Size() > 0) - commandStrings.Delete(0); - #endif - - if (commandStrings.Size() == 0) - { - ShowCopyrightAndHelp(g_StdStream, true); - return 0; - } - - CArcCmdLineOptions options; - - CArcCmdLineParser parser; - - parser.Parse1(commandStrings, options); - - g_StdOut.IsTerminalMode = options.IsStdOutTerminal; - g_StdErr.IsTerminalMode = options.IsStdErrTerminal; - - if (options.Number_for_Out != k_OutStream_stdout) - g_StdStream = (options.Number_for_Out == k_OutStream_stderr ? &g_StdErr : NULL); - - if (options.Number_for_Errors != k_OutStream_stderr) - g_ErrStream = (options.Number_for_Errors == k_OutStream_stdout ? &g_StdOut : NULL); - - CStdOutStream *percentsStream = NULL; - if (options.Number_for_Percents != k_OutStream_disabled) - percentsStream = (options.Number_for_Percents == k_OutStream_stderr) ? &g_StdErr : &g_StdOut; - - if (options.HelpMode) - { - ShowCopyrightAndHelp(g_StdStream, true); - return 0; - } - - if (options.EnableHeaders) - { - ShowCopyrightAndHelp(g_StdStream, false); - if (!parser.Parse1Log.IsEmpty()) - *g_StdStream << parser.Parse1Log; - } - - parser.Parse2(options); - - { - int cp = options.ConsoleCodePage; - - int stdout_cp = cp; - int stderr_cp = cp; - int stdin_cp = cp; - - /* - // these cases are complicated. - // maybe we must use CRT functions instead of console WIN32. - // different Windows/CRT versions also can work different ways. - // so the following code was not enabled: - if (cp == -1) - { - // we set CodePage only if stream is attached to terminal - // maybe we should set CodePage even if is not terminal? - #ifdef _WIN32 - { - UINT ccp = GetConsoleOutputCP(); - if (ccp != 0) - { - if (options.IsStdOutTerminal) stdout_cp = ccp; - if (options.IsStdErrTerminal) stderr_cp = ccp; - } - } - if (options.IsInTerminal) - { - UINT ccp = GetConsoleCP(); - if (ccp != 0) stdin_cp = ccp; - } - #endif - } - */ - - if (stdout_cp != -1) g_StdOut.CodePage = stdout_cp; - if (stderr_cp != -1) g_StdErr.CodePage = stderr_cp; - if (stdin_cp != -1) g_StdIn.CodePage = stdin_cp; - } - g_StdOut.ListPathSeparatorSlash = options.ListPathSeparatorSlash; - g_StdErr.ListPathSeparatorSlash = options.ListPathSeparatorSlash; - - unsigned percentsNameLevel = 1; - if (options.LogLevel == 0 || options.Number_for_Percents != options.Number_for_Out) - percentsNameLevel = 2; - - unsigned consoleWidth = 80; - - if (percentsStream) - { - #ifdef _WIN32 - - #if !defined(UNDER_CE) - CONSOLE_SCREEN_BUFFER_INFO consoleInfo; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo)) - consoleWidth = (USHORT)consoleInfo.dwSize.X; - #endif - - #else - -#if !defined(__sun) - struct winsize w; - if (ioctl(0, TIOCGWINSZ, &w) == 0) - consoleWidth = w.ws_col; -#endif - #endif - } - - CREATE_CODECS_OBJECT - - codecs->CaseSensitive_Change = options.CaseSensitive_Change; - codecs->CaseSensitive = options.CaseSensitive; - ThrowException_if_Error(codecs->Load()); - Codecs_AddHashArcHandler(codecs); - - #ifdef Z7_EXTERNAL_CODECS - { - g_ExternalCodecs_Ptr = &_externalCodecs; - UString s; - codecs->GetCodecsErrorMessage(s); - if (!s.IsEmpty()) - { - CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut); - so << endl << s << endl; - } - } - #endif - - const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); - - if (codecs->Formats.Size() == 0 && - (isExtractGroupCommand - || options.Command.CommandType == NCommandType::kList - || options.Command.IsFromUpdateGroup())) - { - #ifdef Z7_EXTERNAL_CODECS - if (!codecs->MainDll_ErrorPath.IsEmpty()) - { - UString s ("Can't load module: "); - s += fs2us(codecs->MainDll_ErrorPath); - throw s; - } - #endif - throw kNoFormats; - } - - CObjectVector types; - if (!ParseOpenTypes(*codecs, options.ArcType, types)) - { - throw kUnsupportedArcTypeMessage; - } - - - CIntVector excludedFormats; - FOR_VECTOR (k, options.ExcludedArcTypes) - { - CIntVector tempIndices; - if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices) - || tempIndices.Size() != 1) - throw kUnsupportedArcTypeMessage; - - - - excludedFormats.AddToUniqueSorted(tempIndices[0]); - // excludedFormats.Sort(); - } - - #ifdef Z7_EXTERNAL_CODECS - if (isExtractGroupCommand - || options.Command.IsFromUpdateGroup() - || options.Command.CommandType == NCommandType::kHash - || options.Command.CommandType == NCommandType::kBenchmark) - ThrowException_if_Error(_externalCodecs.Load()); - #endif - - int retCode = NExitCode::kSuccess; - HRESULT hresultMain = S_OK; - - // bool showStat = options.ShowTime; - - /* - if (!options.EnableHeaders || - options.TechMode) - showStat = false; - */ - - - if (options.Command.CommandType == NCommandType::kInfo) - { - CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut); - unsigned i; - - #ifdef Z7_EXTERNAL_CODECS - so << endl << "Libs:" << endl; - for (i = 0; i < codecs->Libs.Size(); i++) - { - PrintLibIndex(so, (int)i); - const CCodecLib &lib = codecs->Libs[i]; - // if (lib.Version != 0) - so << ": " << (lib.Version >> 16) << "."; - PrintNumber(so, lib.Version & 0xffff, 2); - so << " : " << lib.Path << endl; - } - #endif - - so << endl << "Formats:" << endl; - - const char * const kArcFlags = "KSNFMGOPBELHXCc+a+m+r+"; - const char * const kArcTimeFlags = "wudn"; - const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); - const unsigned kNumArcTimeFlags = (unsigned)strlen(kArcTimeFlags); - - for (i = 0; i < codecs->Formats.Size(); i++) - { - const CArcInfoEx &arc = codecs->Formats[i]; - - #ifdef Z7_EXTERNAL_CODECS - PrintLibIndex(so, arc.LibIndex); - #else - so << " "; - #endif - - so << (char)(arc.UpdateEnabled ? 'C' : ' '); - - { - unsigned b; - for (b = 0; b < kNumArcFlags; b++) - so << (char)((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : '.'); - so << ' '; - } - - if (arc.TimeFlags != 0) - { - unsigned b; - for (b = 0; b < kNumArcTimeFlags; b++) - so << (char)((arc.TimeFlags & ((UInt32)1 << b)) != 0 ? kArcTimeFlags[b] : '.'); - so << arc.Get_DefaultTimePrec(); - so << ' '; - } - - so << ' '; - PrintString(so, arc.Name, 8); - so << ' '; - UString s; - - FOR_VECTOR (t, arc.Exts) - { - if (t != 0) - s.Add_Space(); - const CArcExtInfo &ext = arc.Exts[t]; - s += ext.Ext; - if (!ext.AddExt.IsEmpty()) - { - s += " ("; - s += ext.AddExt; - s.Add_Char(')'); - } - } - - PrintString(so, s, 13); - so << ' '; - - if (arc.SignatureOffset != 0) - so << "offset=" << arc.SignatureOffset << ' '; - - // so << "numSignatures = " << arc.Signatures.Size() << " "; - - FOR_VECTOR(si, arc.Signatures) - { - if (si != 0) - so << " || "; - - const CByteBuffer &sig = arc.Signatures[si]; - - for (size_t j = 0; j < sig.Size(); j++) - { - if (j != 0) - so << ' '; - const unsigned b = sig.ConstData()[j]; - if (b > 0x20 && b < 0x80) - { - so << (char)b; - } - else - { - so << GET_HEX_CHAR_UPPER(b >> 4); - so << GET_HEX_CHAR_UPPER(b & 15); - } - } - } - so << endl; - } - - so << endl << "Codecs:" << endl; // << "Lib ID Name" << endl; - - for (i = 0; i < g_NumCodecs; i++) - { - const CCodecInfo &cod = *g_Codecs[i]; - - PrintLibIndex(so, -1); - - if (cod.NumStreams == 1) - so << ' '; - else - so << cod.NumStreams; - - so << (char)(cod.CreateEncoder ? 'E' : ' '); - so << (char)(cod.CreateDecoder ? 'D' : ' '); - so << (char)(cod.IsFilter ? 'F' : ' '); - - so << ' '; - PrintHexId(so, cod.Id); - so << ' ' << cod.Name << endl; - } - - - #ifdef Z7_EXTERNAL_CODECS - - UInt32 numMethods; - if (_externalCodecs.GetCodecs->GetNumMethods(&numMethods) == S_OK) - for (UInt32 j = 0; j < numMethods; j++) - { - PrintLibIndex(so, codecs->GetCodec_LibIndex(j)); - - UInt32 numStreams = codecs->GetCodec_NumStreams(j); - if (numStreams == 1) - so << ' '; - else - so << numStreams; - - so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' '); - so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' '); - { - bool isFilter_Assigned; - const bool isFilter = codecs->GetCodec_IsFilter(j, isFilter_Assigned); - so << (char)(isFilter ? 'F' : isFilter_Assigned ? ' ' : '*'); - } - - - so << ' '; - UInt64 id; - HRESULT res = codecs->GetCodec_Id(j, id); - if (res != S_OK) - id = (UInt64)(Int64)-1; - PrintHexId(so, id); - so << ' ' << codecs->GetCodec_Name(j) << endl; - } - - #endif - - - so << endl << "Hashers:" << endl; // << " L Size ID Name" << endl; - - for (i = 0; i < g_NumHashers; i++) - { - const CHasherInfo &codec = *g_Hashers[i]; - PrintLibIndex(so, -1); - PrintUInt32(so, codec.DigestSize, 4); - so << ' '; - PrintHexId(so, codec.Id); - so << ' ' << codec.Name << endl; - } - - #ifdef Z7_EXTERNAL_CODECS - - numMethods = _externalCodecs.GetHashers->GetNumHashers(); - for (UInt32 j = 0; j < numMethods; j++) - { - PrintLibIndex(so, codecs->GetHasherLibIndex(j)); - PrintUInt32(so, codecs->GetHasherDigestSize(j), 4); - so << ' '; - PrintHexId(so, codecs->GetHasherId(j)); - so << ' ' << codecs->GetHasherName(j) << endl; - } - - #endif - - } - else if (options.Command.CommandType == NCommandType::kBenchmark) - { - CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut); - hresultMain = BenchCon(EXTERNAL_CODECS_VARS_L - options.Properties, options.NumIterations, (FILE *)so); - if (hresultMain == S_FALSE) - { - so << endl; - if (g_ErrStream) - *g_ErrStream << "\nDecoding ERROR\n"; - retCode = NExitCode::kFatalError; - hresultMain = S_OK; - } - } - else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList) - { - UStringVector ArchivePathsSorted; - UStringVector ArchivePathsFullSorted; - - if (options.StdInMode) - { - ArchivePathsSorted.Add(options.ArcName_for_StdInMode); - ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode); - } - else - { - CExtractScanConsole scan; - - scan.Init(options.EnableHeaders ? g_StdStream : NULL, - g_ErrStream, percentsStream, - options.DisablePercents); - scan.SetWindowWidth(consoleWidth); - - if (g_StdStream && options.EnableHeaders) - *g_StdStream << "Scanning the drive for archives:" << endl; - - CDirItemsStat st; - - scan.StartScanning(); - - hresultMain = EnumerateDirItemsAndSort( - options.arcCensor, - NWildcard::k_RelatPath, - UString(), // addPathPrefix - ArchivePathsSorted, - ArchivePathsFullSorted, - st, - &scan); - - scan.CloseScanning(); - - if (hresultMain == S_OK) - { - if (options.EnableHeaders) - scan.PrintStat(st); - } - else - { - /* - if (res != E_ABORT) - { - throw CSystemException(res); - // errorInfo.Message = "Scanning error"; - } - return res; - */ - } - } - - if (hresultMain == S_OK) { - if (isExtractGroupCommand) - { - CExtractCallbackConsole *ecs = new CExtractCallbackConsole; - CMyComPtr extractCallback = ecs; - - #ifndef Z7_NO_CRYPTO - ecs->PasswordIsDefined = options.PasswordEnabled; - ecs->Password = options.Password; - #endif - - ecs->Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); - ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); - - ecs->LogLevel = options.LogLevel; - ecs->PercentsNameLevel = percentsNameLevel; - - if (percentsStream) - ecs->SetWindowWidth(consoleWidth); - - /* - COpenCallbackConsole openCallback; - openCallback.Init(g_StdStream, g_ErrStream); - - #ifndef Z7_NO_CRYPTO - openCallback.PasswordIsDefined = options.PasswordEnabled; - openCallback.Password = options.Password; - #endif - */ - - CExtractOptions eo; - (CExtractOptionsBase &)eo = options.ExtractOptions; - - eo.StdInMode = options.StdInMode; - eo.StdOutMode = options.StdOutMode; - eo.YesToAll = options.YesToAll; - eo.TestMode = options.Command.IsTestCommand(); - - #ifndef Z7_SFX - eo.Properties = options.Properties; - #endif - - UString errorMessage; - CDecompressStat stat; - CHashBundle hb; - IHashCalc *hashCalc = NULL; - - if (!options.HashMethods.IsEmpty()) - { - hashCalc = &hb; - ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods)); - // hb.Init(); - } - - hresultMain = Extract( - // EXTERNAL_CODECS_VARS_L - codecs, - types, - excludedFormats, - ArchivePathsSorted, - ArchivePathsFullSorted, - options.Censor.Pairs.Front().Head, - eo, - ecs, ecs, ecs, - hashCalc, errorMessage, stat); - - ecs->ClosePercents(); - - if (!errorMessage.IsEmpty()) - { - if (g_ErrStream) - *g_ErrStream << endl << "ERROR:" << endl << errorMessage << endl; - if (hresultMain == S_OK) - hresultMain = E_FAIL; - } - - CStdOutStream *so = g_StdStream; - - bool isError = false; - - if (so) - { - *so << endl; - - if (ecs->NumTryArcs > 1) - { - *so << "Archives: " << ecs->NumTryArcs << endl; - *so << "OK archives: " << ecs->NumOkArcs << endl; - } - } - - if (ecs->NumCantOpenArcs != 0) - { - isError = true; - if (so) - *so << "Can't open as archive: " << ecs->NumCantOpenArcs << endl; - } - - if (ecs->NumArcsWithError != 0) - { - isError = true; - if (so) - *so << "Archives with Errors: " << ecs->NumArcsWithError << endl; - } - - if (so) - { - if (ecs->NumArcsWithWarnings != 0) - *so << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl; - - if (ecs->NumOpenArcWarnings != 0) - { - *so << endl; - if (ecs->NumOpenArcWarnings != 0) - *so << "Warnings: " << ecs->NumOpenArcWarnings << endl; - } - } - - if (ecs->NumOpenArcErrors != 0) - { - isError = true; - if (so) - { - *so << endl; - if (ecs->NumOpenArcErrors != 0) - *so << "Open Errors: " << ecs->NumOpenArcErrors << endl; - } - } - - if (isError) - retCode = NExitCode::kFatalError; - - if (so) { - if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0) - { - // if (ecs->NumArchives > 1) - { - *so << endl; - if (ecs->NumFileErrors != 0) - *so << "Sub items Errors: " << ecs->NumFileErrors << endl; - } - } - else if (hresultMain == S_OK) - { - if (stat.NumFolders != 0) - *so << "Folders: " << stat.NumFolders << endl; - if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0) - *so << "Files: " << stat.NumFiles << endl; - if (stat.NumAltStreams != 0) - { - *so << "Alternate Streams: " << stat.NumAltStreams << endl; - *so << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl; - } - - *so - << "Size: " << stat.UnpackSize << endl - << "Compressed: " << stat.PackSize << endl; - if (hashCalc) - { - *so << endl; - PrintHashStat(*so, hb); - } - } - } // if (so) - } - else // if_(!isExtractGroupCommand) - { - UInt64 numErrors = 0; - UInt64 numWarnings = 0; - - // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed - - CListOptions lo; - lo.ExcludeDirItems = options.Censor.ExcludeDirItems; - lo.ExcludeFileItems = options.Censor.ExcludeFileItems; - lo.DisablePercents = options.DisablePercents; - - hresultMain = ListArchives( - lo, - codecs, - types, - excludedFormats, - options.StdInMode, - ArchivePathsSorted, - ArchivePathsFullSorted, - options.ExtractOptions.NtOptions.AltStreams.Val, - options.AltStreams.Val, // we don't want to show AltStreams by default - options.Censor.Pairs.Front().Head, - options.EnableHeaders, - options.TechMode, - #ifndef Z7_NO_CRYPTO - options.PasswordEnabled, - options.Password, - #endif - &options.Properties, - numErrors, numWarnings); - - if (options.EnableHeaders) - if (numWarnings > 0) - g_StdOut << endl << "Warnings: " << numWarnings << endl; - - if (numErrors > 0) - { - if (options.EnableHeaders) - g_StdOut << endl << "Errors: " << numErrors << endl; - retCode = NExitCode::kFatalError; - } - } // if_(isExtractGroupCommand) - } // if_(hresultMain == S_OK) - } - else if (options.Command.IsFromUpdateGroup()) - { - #ifdef Z7_EXTRACT_ONLY - throw "update commands are not implemented"; - #else - CUpdateOptions &uo = options.UpdateOptions; - if (uo.SfxMode && uo.SfxModule.IsEmpty()) - uo.SfxModule = kDefaultSfxModule; - - COpenCallbackConsole openCallback; - openCallback.Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); - - #ifndef Z7_NO_CRYPTO - bool passwordIsDefined = - (options.PasswordEnabled && !options.Password.IsEmpty()); - openCallback.PasswordIsDefined = passwordIsDefined; - openCallback.Password = options.Password; - #endif - - CUpdateCallbackConsole callback; - callback.LogLevel = options.LogLevel; - callback.PercentsNameLevel = percentsNameLevel; - - if (percentsStream) - callback.SetWindowWidth(consoleWidth); - - #ifndef Z7_NO_CRYPTO - callback.PasswordIsDefined = passwordIsDefined; - callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty()); - callback.Password = options.Password; - #endif - - callback.StdOutMode = uo.StdOutMode; - callback.Init( - // NULL, - g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); - - CUpdateErrorInfo errorInfo; - - /* - if (!uo.Init(codecs, types, options.ArchiveName)) - throw kUnsupportedUpdateArcType; - */ - hresultMain = UpdateArchive(codecs, - types, - options.ArchiveName, - options.Censor, - uo, - errorInfo, &openCallback, &callback, true); - - callback.ClosePercents2(); - - CStdOutStream *se = g_StdStream; - if (!se) - se = g_ErrStream; - - retCode = WarningsCheck(hresultMain, callback, errorInfo, - g_StdStream, se, - true // options.EnableHeaders - ); - #endif - } - else if (options.Command.CommandType == NCommandType::kHash) - { - const CHashOptions &uo = options.HashOptions; - - CHashCallbackConsole callback; - if (percentsStream) - callback.SetWindowWidth(consoleWidth); - - callback.Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); - callback.PrintHeaders = options.EnableHeaders; - callback.PrintFields = options.ListFields; - - AString errorInfoString; - hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L - options.Censor, uo, - errorInfoString, &callback); - CUpdateErrorInfo errorInfo; - errorInfo.Message = errorInfoString; - CStdOutStream *se = g_StdStream; - if (!se) - se = g_ErrStream; - retCode = WarningsCheck(hresultMain, callback, errorInfo, g_StdStream, se, options.EnableHeaders); - } - else - ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError); - - if (options.ShowTime && g_StdStream) - PrintStat( - #ifndef _WIN32 - startTime - #endif - ); - - ThrowException_if_Error(hresultMain); - - return retCode; -} +// Main.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#ifdef _WIN32 + +#ifndef Z7_OLD_WIN_SDK + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#else // Z7_OLD_WIN_SDK + +typedef struct { + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} PROCESS_MEMORY_COUNTERS; +typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; + +#endif // Z7_OLD_WIN_SDK + +#else // _WIN32 +#include +#include +#include +#include +#endif // _WIN32 + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyException.h" +#include "../../../Common/StdInStream.h" +#include "../../../Common/StdOutStream.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/TimeUtils.h" +#include "../../../Windows/FileDir.h" + +#include "../Common/ArchiveCommandLine.h" +#include "../Common/Bench.h" +#include "../Common/ExitCode.h" +#include "../Common/Extract.h" + +#ifdef Z7_EXTERNAL_CODECS +#include "../Common/LoadCodecs.h" +#endif + +#include "../../Common/RegisterCodec.h" + +#include "BenchCon.h" +#include "ConsoleClose.h" +#include "ExtractCallbackConsole.h" +#include "HashCon.h" +#include "List.h" +#include "OpenCallbackConsole.h" +#include "UpdateCallbackConsole.h" + +#ifdef Z7_PROG_VARIANT_R +#include "../../../../C/7zVersion.h" +#else +#include "../../MyVersion.h" +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NCommandLineParser; + +#ifdef _WIN32 +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance = NULL; +#endif + +extern CStdOutStream *g_StdStream; +extern CStdOutStream *g_ErrStream; + +extern unsigned g_NumCodecs; +extern const CCodecInfo *g_Codecs[]; + +extern unsigned g_NumHashers; +extern const CHasherInfo *g_Hashers[]; + +#ifdef Z7_EXTERNAL_CODECS +extern +const CExternalCodecs *g_ExternalCodecs_Ptr; +const CExternalCodecs *g_ExternalCodecs_Ptr; +#endif + +DECLARE_AND_SET_CLIENT_VERSION_VAR + +#if defined(Z7_PROG_VARIANT_Z) + #define PROG_POSTFIX "z" + #define PROG_POSTFIX_2 " (z)" +#elif defined(Z7_PROG_VARIANT_R) + #define PROG_POSTFIX "r" + #define PROG_POSTFIX_2 " (r)" +#elif defined(Z7_PROG_VARIANT_A) || !defined(Z7_EXTERNAL_CODECS) + #define PROG_POSTFIX "a" + #define PROG_POSTFIX_2 " (a)" +#else + #define PROG_POSTFIX "" + #define PROG_POSTFIX_2 "" +#endif + + +static const char * const kCopyrightString = "\n7-Zip" + PROG_POSTFIX_2 + " " MY_VERSION_CPU + " : " MY_COPYRIGHT_DATE "\n"; + +static const char * const kHelpString = + "Usage: 7z" + PROG_POSTFIX + " [...] [...] [@listfile]\n" + "\n" + "\n" + " a : Add files to archive\n" + " b : Benchmark\n" + " d : Delete files from archive\n" + " e : Extract files from archive (without using directory names)\n" + " h : Calculate hash values for files\n" + " i : Show information about supported formats\n" + " l : List contents of archive\n" + " rn : Rename files in archive\n" + " t : Test integrity of archive\n" + " u : Update files to archive\n" + " x : eXtract files with full paths\n" + "\n" + "\n" + " -- : Stop switches and @listfile parsing\n" + " -ai[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : Include archives\n" + " -ax[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : eXclude archives\n" + " -ao{a|s|t|u} : set Overwrite mode\n" + " -an : disable archive_name field\n" + " -bb[0-3] : set output log level\n" + " -bd : disable progress indicator\n" + " -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n" + " -bt : show execution time statistics\n" + " -i[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : Include filenames\n" + " -m{Parameters} : set compression Method\n" + " -mmt[N] : set number of CPU threads\n" + " -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra)\n" + " -o{Directory} : set Output directory\n" + #ifndef Z7_NO_CRYPTO + " -p{Password} : set Password\n" + #endif + " -r[-|0] : Recurse subdirectories for name search\n" + " -sa{a|e|s} : set Archive name mode\n" + " -scc{UTF-8|WIN|DOS} : set charset for console input/output\n" + " -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n" + " -scrc[CRC32|CRC64|SHA256" +#ifndef Z7_PROG_VARIANT_R + "|SHA1|XXH64" +#ifdef Z7_PROG_VARIANT_Z + "|BLAKE2SP" +#endif +#endif + "|*] : set hash function for x, e, h commands\n" + " -sdel : delete files after compression\n" + " -seml[.] : send archive by email\n" + " -sfx[{name}] : Create SFX archive\n" + " -si[{name}] : read data from stdin\n" + " -slp : set Large Pages mode\n" + " -slt : show technical information for l (List) command\n" + " -snh : store hard links as links\n" + " -snl : store symbolic links as links\n" + " -sni : store NT security information\n" + " -sns[-] : store NTFS alternate streams\n" + " -so : write data to stdout\n" + " -spd : disable wildcard matching for file names\n" + " -spe : eliminate duplication of root folder for extract command\n" + " -spf[2] : use fully qualified file paths\n" + " -ssc[-] : set sensitive case mode\n" + " -sse : stop archive creating, if it can't open some input file\n" + " -ssp : do not change Last Access Time of source files while archiving\n" + " -ssw : compress shared files\n" + " -stl : set archive timestamp from the most recently modified file\n" + " -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n" + " -stx{Type} : exclude archive type\n" + " -t{Type} : Set type of archive\n" + " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n" + " -v{Size}[b|k|m|g] : Create volumes\n" + " -w[{path}] : assign Work directory. Empty path means a temporary directory\n" + " -x[r[-|0]][m[-|2]][w[-]]{@listfile|!wildcard} : eXclude filenames\n" + " -y : assume Yes on all queries\n"; + +// --------------------------- +// exception messages + +static const char * const kEverythingIsOk = "Everything is Ok"; +static const char * const kUserErrorMessage = "Incorrect command line"; +static const char * const kNoFormats = "7-Zip cannot find the code that works with archives."; +static const char * const kUnsupportedArcTypeMessage = "Unsupported archive type"; +// static const char * const kUnsupportedUpdateArcType = "Can't create archive for that type"; + +#ifndef Z7_EXTRACT_ONLY +#define kDefaultSfxModule "7zCon.sfx" +#endif + +Z7_ATTR_NORETURN +static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code) +{ + if (g_ErrStream) + *g_ErrStream << endl << "ERROR: " << message << endl; + throw code; +} + + +#ifdef _WIN32 +#define ShowProgInfo(so) +#else +static void ShowProgInfo(CStdOutStream *so) +{ + if (!so) + return; + + *so + + /* + #ifdef __DATE__ + << " " << __DATE__ + #endif + #ifdef __TIME__ + << " " << __TIME__ + #endif + */ + + << " " << (unsigned)(sizeof(void *)) * 8 << "-bit" + + #ifdef __ILP32__ + << " ILP32" + #endif + + #ifdef __ARM_ARCH + << " arm_v:" << __ARM_ARCH + #if (__ARM_ARCH == 8) + // for macos: + #if defined(__ARM_ARCH_8_9__) + << ".9" + #elif defined(__ARM_ARCH_8_8__) + << ".8" + #elif defined(__ARM_ARCH_8_7__) + << ".7" + #elif defined(__ARM_ARCH_8_6__) + << ".6" + #elif defined(__ARM_ARCH_8_5__) + << ".5" + #elif defined(__ARM_ARCH_8_4__) + << ".4" + #elif defined(__ARM_ARCH_8_3__) + << ".3" + #elif defined(__ARM_ARCH_8_2__) + << ".2" + #elif defined(__ARM_ARCH_8_1__) + << ".1" + #endif + #endif + + #if defined(__ARM_ARCH_PROFILE) && \ + ( __ARM_ARCH_PROFILE >= 'A' && __ARM_ARCH_PROFILE <= 'Z' \ + || __ARM_ARCH_PROFILE >= 65 && __ARM_ARCH_PROFILE <= 65 + 25) + << "-" << (char)__ARM_ARCH_PROFILE + #endif + + #ifdef __ARM_ARCH_ISA_THUMB + << " thumb:" << __ARM_ARCH_ISA_THUMB + #endif + #endif + + #ifdef _MIPS_ARCH + << " mips_arch:" << _MIPS_ARCH + #endif + #ifdef __mips_isa_rev + << " mips_isa_rev:" << __mips_isa_rev + #endif + + #ifdef __iset__ + << " e2k_v:" << __iset__ + #endif + ; + + + + #ifdef ENV_HAVE_LOCALE + *so << " locale=" << GetLocale(); + #endif + #ifndef _WIN32 + { + const bool is_IsNativeUTF8 = IsNativeUTF8(); + if (!is_IsNativeUTF8) + *so << " UTF8=" << (is_IsNativeUTF8 ? "+" : "-"); + } + if (!g_ForceToUTF8) + *so << " use-UTF8=" << (g_ForceToUTF8 ? "+" : "-"); + { + const unsigned wchar_t_size = (unsigned)sizeof(wchar_t); + if (wchar_t_size != 4) + *so << " wchar_t=" << wchar_t_size * 8 << "-bit"; + } + { + const unsigned off_t_size = (unsigned)sizeof(off_t); + if (off_t_size != 8) + *so << " Files=" << off_t_size * 8 << "-bit"; + } + #endif + + { + const UInt32 numCpus = NWindows::NSystem::GetNumberOfProcessors(); + *so << " Threads:" << numCpus; + const UInt64 openMAX= NWindows::NSystem::Get_File_OPEN_MAX(); + *so << " OPEN_MAX:" << openMAX; + { + FString temp; + NDir::MyGetTempPath(temp); + if (!temp.IsEqualTo(STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR)) + *so << " temp_path:" << temp; + } + } + + #ifdef Z7_7ZIP_ASM + *so << ", ASM"; + #endif + + /* + { + AString s; + GetCpuName(s); + s.Trim(); + *so << ", " << s; + } + + #ifdef __ARM_FEATURE_CRC32 + << " CRC32" + #endif + + + #if (defined MY_CPU_X86_OR_AMD64 || defined(MY_CPU_ARM_OR_ARM64)) + if (CPU_IsSupported_AES()) *so << ",AES"; + #endif + + #ifdef MY_CPU_ARM_OR_ARM64 + if (CPU_IsSupported_CRC32()) *so << ",CRC32"; + #if defined(_WIN32) + if (CPU_IsSupported_CRYPTO()) *so << ",CRYPTO"; + #else + if (CPU_IsSupported_SHA1()) *so << ",SHA1"; + if (CPU_IsSupported_SHA2()) *so << ",SHA2"; + #endif + #endif + */ + + *so << endl; +} +#endif + +static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp) +{ + if (!so) + return; + *so << kCopyrightString; + // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << endl; + ShowProgInfo(so); + *so << endl; + if (needHelp) + *so << kHelpString; +} + + +static void PrintStringRight(CStdOutStream &so, const char *s, unsigned size) +{ + unsigned len = MyStringLen(s); + for (unsigned i = len; i < size; i++) + so << ' '; + so << s; +} + +static void PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size) +{ + char s[16]; + ConvertUInt32ToString(val, s); + PrintStringRight(so, s, size); +} + +#ifdef Z7_EXTERNAL_CODECS +static void PrintNumber(CStdOutStream &so, UInt32 val, unsigned numDigits) +{ + AString s; + s.Add_UInt32(val); + while (s.Len() < numDigits) + s.InsertAtFront('0'); + so << s; +} +#endif + +static void PrintLibIndex(CStdOutStream &so, int libIndex) +{ + if (libIndex >= 0) + PrintUInt32(so, (UInt32)libIndex, 2); + else + so << " "; + so << ' '; +} + +static void PrintString(CStdOutStream &so, const UString &s, unsigned size) +{ + unsigned len = s.Len(); + so << s; + for (unsigned i = len; i < size; i++) + so << ' '; +} + +static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so) +{ + FOR_VECTOR(i, pc.Paths) + { + so.NormalizePrint_UString_Path(fs2us(pc.Paths[i])); + so << " : "; + so << NError::MyFormatMessage(pc.Codes[i]) << endl; + } + so << "----------------" << endl; +} + +static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback, + const CUpdateErrorInfo &errorInfo, + CStdOutStream *so, + CStdOutStream *se, + bool showHeaders) +{ + int exitCode = NExitCode::kSuccess; + + if (callback.ScanErrors.Paths.Size() != 0) + { + if (se) + { + *se << endl; + *se << "Scan WARNINGS for files and folders:" << endl << endl; + PrintWarningsPaths(callback.ScanErrors, *se); + *se << "Scan WARNINGS: " << callback.ScanErrors.Paths.Size(); + *se << endl; + } + exitCode = NExitCode::kWarning; + } + + if (result != S_OK || errorInfo.ThereIsError()) + { + if (se) + { + UString message; + if (!errorInfo.Message.IsEmpty()) + { + message += errorInfo.Message.Ptr(); + message.Add_LF(); + } + { + FOR_VECTOR(i, errorInfo.FileNames) + { + message += fs2us(errorInfo.FileNames[i]); + message.Add_LF(); + } + } + if (errorInfo.SystemError != 0) + { + message += NError::MyFormatMessage(errorInfo.SystemError); + message.Add_LF(); + } + if (!message.IsEmpty()) + *se << L"\nError:\n" << message; + } + + // we will work with (result) later + // throw CSystemException(result); + return NExitCode::kFatalError; + } + + unsigned numErrors = callback.FailedFiles.Paths.Size(); + if (numErrors == 0) + { + if (showHeaders) + if (callback.ScanErrors.Paths.Size() == 0) + if (so) + { + if (se) + se->Flush(); + *so << kEverythingIsOk << endl; + } + } + else + { + if (se) + { + *se << endl; + *se << "WARNINGS for files:" << endl << endl; + PrintWarningsPaths(callback.FailedFiles, *se); + *se << "WARNING: Cannot open " << numErrors << " file"; + if (numErrors > 1) + *se << 's'; + *se << endl; + } + exitCode = NExitCode::kWarning; + } + + return exitCode; +} + +static void ThrowException_if_Error(HRESULT res) +{ + if (res != S_OK) + throw CSystemException(res); +} + +static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ') +{ + char temp[64]; + char *p = temp + 32; + ConvertUInt64ToString(val, p); + unsigned len = MyStringLen(p); + for (; len < numDigits; len++) + *--p = c; + *g_StdStream << p; +} + +#ifdef _WIN32 + +static void PrintTime(const char *s, UInt64 val, UInt64 total) +{ + *g_StdStream << endl << s << " Time ="; + const UInt32 kFreq = 10000000; + UInt64 sec = val / kFreq; + PrintNum(sec, 6); + *g_StdStream << '.'; + UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000); + PrintNum(ms, 3, '0'); + + while (val > ((UInt64)1 << 56)) + { + val >>= 1; + total >>= 1; + } + + UInt64 percent = 0; + if (total != 0) + percent = val * 100 / total; + *g_StdStream << " ="; + PrintNum(percent, 5); + *g_StdStream << '%'; +} + +#ifndef UNDER_CE + +#define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num)) + +static void PrintMemUsage(const char *s, UInt64 val) +{ + *g_StdStream << " " << s << " Memory ="; + PrintNum(SHIFT_SIZE_VALUE(val, 20), 7); + *g_StdStream << " MB"; + /* + *g_StdStream << " ="; + PrintNum(SHIFT_SIZE_VALUE(val, 10), 9); + *g_StdStream << " KB"; + */ + #ifdef Z7_LARGE_PAGES + AString lp; + Add_LargePages_String(lp); + if (!lp.IsEmpty()) + *g_StdStream << lp; + #endif +} + +EXTERN_C_BEGIN +typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process, + PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb); +typedef BOOL (WINAPI *Func_QueryProcessCycleTime)(HANDLE Process, PULONG64 CycleTime); +EXTERN_C_END + +#endif + +static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } + +static void PrintStat() +{ + FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT; + if (! + #ifdef UNDER_CE + ::GetThreadTimes(::GetCurrentThread() + #else + // NT 3.5 + ::GetProcessTimes(::GetCurrentProcess() + #endif + , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT)) + return; + FILETIME curTimeFT; + NTime::GetCurUtc_FiTime(curTimeFT); + + #ifndef UNDER_CE + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + + PROCESS_MEMORY_COUNTERS m; + memset(&m, 0, sizeof(m)); + BOOL memDefined = FALSE; + BOOL cycleDefined = FALSE; + ULONG64 cycleTime = 0; + { + /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll + Win7: new function K32GetProcessMemoryInfo() in kernel32.dll + It's faster to call kernel32.dll code than Psapi.dll code + GetProcessMemoryInfo() requires Psapi.lib + Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll + The program with K32GetProcessMemoryInfo will not work on systems before Win7 + // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)); + */ + const HMODULE kern = ::GetModuleHandleW(L"kernel32.dll"); + Func_GetProcessMemoryInfo + my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS( + Func_GetProcessMemoryInfo, kern, + "K32GetProcessMemoryInfo"); + if (!my_GetProcessMemoryInfo) + { + const HMODULE lib = LoadLibraryW(L"Psapi.dll"); + if (lib) + my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS( + Func_GetProcessMemoryInfo, lib, + "GetProcessMemoryInfo"); + } + if (my_GetProcessMemoryInfo) + memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m)); + // FreeLibrary(lib); + const + Func_QueryProcessCycleTime + my_QueryProcessCycleTime = Z7_GET_PROC_ADDRESS( + Func_QueryProcessCycleTime, kern, + "QueryProcessCycleTime"); + if (my_QueryProcessCycleTime) + cycleDefined = my_QueryProcessCycleTime(GetCurrentProcess(), &cycleTime); + } + + #endif + + UInt64 curTime = GetTime64(curTimeFT); + UInt64 creationTime = GetTime64(creationTimeFT); + UInt64 kernelTime = GetTime64(kernelTimeFT); + UInt64 userTime = GetTime64(userTimeFT); + + UInt64 totalTime = curTime - creationTime; + + PrintTime("Kernel ", kernelTime, totalTime); + + const UInt64 processTime = kernelTime + userTime; + + #ifndef UNDER_CE + if (cycleDefined) + { + *g_StdStream << " Cnt:"; + PrintNum(cycleTime / 1000000, 15); + *g_StdStream << " MCycles"; + } + #endif + + PrintTime("User ", userTime, totalTime); + + #ifndef UNDER_CE + if (cycleDefined) + { + *g_StdStream << " Freq (cnt/ptime):"; + UInt64 us = processTime / 10; + if (us == 0) + us = 1; + PrintNum(cycleTime / us, 6); + *g_StdStream << " MHz"; + } + #endif + + PrintTime("Process", processTime, totalTime); + #ifndef UNDER_CE + if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage); + #endif + + PrintTime("Global ", totalTime, totalTime); + #ifndef UNDER_CE + if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize); + #endif + *g_StdStream << endl; +} + + +#else // ! _WIN32 + +static UInt64 Get_timeofday_us() +{ + struct timeval now; + if (gettimeofday(&now, NULL) == 0) + return (UInt64)now.tv_sec * 1000000 + (UInt64)now.tv_usec; + return 0; +} + +static void PrintTime(const char *s, UInt64 val, UInt64 total_us, UInt64 kFreq) +{ + *g_StdStream << endl << s << " Time ="; + + { + UInt64 sec, ms; + + if (kFreq == 0) + { + sec = val / 1000000; + ms = val % 1000000 / 1000; + } + else + { + sec = val / kFreq; + ms = (UInt32)((val - (sec * kFreq)) * 1000 / kFreq); + } + + PrintNum(sec, 6); + *g_StdStream << '.'; + PrintNum(ms, 3, '0'); + } + + if (total_us == 0) + return; + + UInt64 percent = 0; + if (kFreq == 0) + percent = val * 100 / total_us; + else + { + const UInt64 kMaxVal = (UInt64)(Int64)-1; + UInt32 m = 100000000; + for (;;) + { + if (m == 0 || kFreq == 0) + break; + if (kMaxVal / m > val && + kMaxVal / kFreq > total_us) + break; + if (val > m) + val >>= 1; + else + m >>= 1; + if (kFreq > total_us) + kFreq >>= 1; + else + total_us >>= 1; + } + const UInt64 total = kFreq * total_us; + if (total != 0) + percent = val * m / total; + } + *g_StdStream << " ="; + PrintNum(percent, 5); + *g_StdStream << '%'; +} + +static void PrintStat(const UInt64 startTime) +{ + tms t; + /* clock_t res = */ times(&t); + const UInt64 totalTime = Get_timeofday_us() - startTime; + const UInt64 kFreq = (UInt64)sysconf(_SC_CLK_TCK); + PrintTime("Kernel ", (UInt64)t.tms_stime, totalTime, kFreq); + PrintTime("User ", (UInt64)t.tms_utime, totalTime, kFreq); + PrintTime("Process", (UInt64)t.tms_utime + (UInt64)t.tms_stime, totalTime, kFreq); + PrintTime("Global ", totalTime, totalTime, 0); + *g_StdStream << endl; +} + +#endif // ! _WIN32 + + + + + +static void PrintHexId(CStdOutStream &so, UInt64 id) +{ + char s[32]; + ConvertUInt64ToHex(id, s); + PrintStringRight(so, s, 8); +} + +#ifndef _WIN32 +void Set_ModuleDirPrefix_From_ProgArg0(const char *s); +#endif + +int Main2( + #ifndef _WIN32 + int numArgs, char *args[] + #endif +); +int Main2( + #ifndef _WIN32 + int numArgs, char *args[] + #endif +) +{ + #if defined(MY_CPU_SIZEOF_POINTER) + { unsigned k = sizeof(void *); if (k != MY_CPU_SIZEOF_POINTER) throw "incorrect MY_CPU_PTR_SIZE"; } + #endif + + #if defined(_WIN32) && !defined(UNDER_CE) + SetFileApisToOEM(); + #endif + + #ifdef ENV_HAVE_LOCALE + // printf("\nBefore SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8"); + MY_SetLocale(); + // printf("\nAfter SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8"); + #endif + + #ifndef _WIN32 + const UInt64 startTime = Get_timeofday_us(); + #endif + + /* + { + g_StdOut << "DWORD:" << (unsigned)sizeof(DWORD); + g_StdOut << " LONG:" << (unsigned)sizeof(LONG); + g_StdOut << " long:" << (unsigned)sizeof(long); + #ifdef _WIN64 + // g_StdOut << " long long:" << (unsigned)sizeof(long long); + #endif + g_StdOut << " int:" << (unsigned)sizeof(int); + g_StdOut << " void*:" << (unsigned)sizeof(void *); + g_StdOut << endl; + } + */ + + UStringVector commandStrings; + + #ifdef _WIN32 + NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); + #else + { + if (numArgs > 0) + Set_ModuleDirPrefix_From_ProgArg0(args[0]); + + for (int i = 0; i < numArgs; i++) + { + AString a (args[i]); +#if 0 + printf("\n%d %s :", i, a.Ptr()); + for (unsigned k = 0; k < a.Len(); k++) + printf(" %2x", (unsigned)(Byte)a[k]); +#endif + const UString s = MultiByteToUnicodeString(a); + commandStrings.Add(s); + } + // printf("\n"); + } + + #endif + + #ifndef UNDER_CE + if (commandStrings.Size() > 0) + commandStrings.Delete(0); + #endif + + if (commandStrings.Size() == 0) + { + ShowCopyrightAndHelp(g_StdStream, true); + return 0; + } + + CArcCmdLineOptions options; + + CArcCmdLineParser parser; + + parser.Parse1(commandStrings, options); + + g_StdOut.IsTerminalMode = options.IsStdOutTerminal; + g_StdErr.IsTerminalMode = options.IsStdErrTerminal; + + if (options.Number_for_Out != k_OutStream_stdout) + g_StdStream = (options.Number_for_Out == k_OutStream_stderr ? &g_StdErr : NULL); + + if (options.Number_for_Errors != k_OutStream_stderr) + g_ErrStream = (options.Number_for_Errors == k_OutStream_stdout ? &g_StdOut : NULL); + + CStdOutStream *percentsStream = NULL; + if (options.Number_for_Percents != k_OutStream_disabled) + percentsStream = (options.Number_for_Percents == k_OutStream_stderr) ? &g_StdErr : &g_StdOut; + + if (options.HelpMode) + { + ShowCopyrightAndHelp(g_StdStream, true); + return 0; + } + + if (options.EnableHeaders) + { + ShowCopyrightAndHelp(g_StdStream, false); + if (!parser.Parse1Log.IsEmpty()) + *g_StdStream << parser.Parse1Log; + } + + parser.Parse2(options); + + { + int cp = options.ConsoleCodePage; + + int stdout_cp = cp; + int stderr_cp = cp; + int stdin_cp = cp; + + /* + // these cases are complicated. + // maybe we must use CRT functions instead of console WIN32. + // different Windows/CRT versions also can work different ways. + // so the following code was not enabled: + if (cp == -1) + { + // we set CodePage only if stream is attached to terminal + // maybe we should set CodePage even if is not terminal? + #ifdef _WIN32 + { + UINT ccp = GetConsoleOutputCP(); + if (ccp != 0) + { + if (options.IsStdOutTerminal) stdout_cp = ccp; + if (options.IsStdErrTerminal) stderr_cp = ccp; + } + } + if (options.IsInTerminal) + { + UINT ccp = GetConsoleCP(); + if (ccp != 0) stdin_cp = ccp; + } + #endif + } + */ + + if (stdout_cp != -1) g_StdOut.CodePage = stdout_cp; + if (stderr_cp != -1) g_StdErr.CodePage = stderr_cp; + if (stdin_cp != -1) g_StdIn.CodePage = stdin_cp; + } + g_StdOut.ListPathSeparatorSlash = options.ListPathSeparatorSlash; + g_StdErr.ListPathSeparatorSlash = options.ListPathSeparatorSlash; + + unsigned percentsNameLevel = 1; + if (options.LogLevel == 0 || options.Number_for_Percents != options.Number_for_Out) + percentsNameLevel = 2; + + unsigned consoleWidth = 80; + + if (percentsStream) + { + #ifdef _WIN32 + + #if !defined(UNDER_CE) + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo)) + consoleWidth = (USHORT)consoleInfo.dwSize.X; + #endif + + #else + +#if !defined(__sun) + struct winsize w; + if (ioctl(0, TIOCGWINSZ, &w) == 0) + consoleWidth = w.ws_col; +#endif + #endif + } + + CREATE_CODECS_OBJECT + + codecs->CaseSensitive_Change = options.CaseSensitive_Change; + codecs->CaseSensitive = options.CaseSensitive; + ThrowException_if_Error(codecs->Load()); + Codecs_AddHashArcHandler(codecs); + + #ifdef Z7_EXTERNAL_CODECS + { + g_ExternalCodecs_Ptr = &_externalCodecs; + UString s; + codecs->GetCodecsErrorMessage(s); + if (!s.IsEmpty()) + { + CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut); + so << endl << s << endl; + } + } + #endif + + const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + + if (codecs->Formats.Size() == 0 && + (isExtractGroupCommand + || options.Command.CommandType == NCommandType::kList + || options.Command.IsFromUpdateGroup())) + { + #ifdef Z7_EXTERNAL_CODECS + if (!codecs->MainDll_ErrorPath.IsEmpty()) + { + UString s ("Can't load module: "); + s += fs2us(codecs->MainDll_ErrorPath); + throw s; + } + #endif + throw kNoFormats; + } + + CObjectVector types; + if (!ParseOpenTypes(*codecs, options.ArcType, types)) + { + throw kUnsupportedArcTypeMessage; + } + + + CIntVector excludedFormats; + FOR_VECTOR (k, options.ExcludedArcTypes) + { + CIntVector tempIndices; + if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices) + || tempIndices.Size() != 1) + throw kUnsupportedArcTypeMessage; + + + + excludedFormats.AddToUniqueSorted(tempIndices[0]); + // excludedFormats.Sort(); + } + + #ifdef Z7_EXTERNAL_CODECS + if (isExtractGroupCommand + || options.Command.IsFromUpdateGroup() + || options.Command.CommandType == NCommandType::kHash + || options.Command.CommandType == NCommandType::kBenchmark) + ThrowException_if_Error(_externalCodecs.Load()); + #endif + + int retCode = NExitCode::kSuccess; + HRESULT hresultMain = S_OK; + + // bool showStat = options.ShowTime; + + /* + if (!options.EnableHeaders || + options.TechMode) + showStat = false; + */ + + + if (options.Command.CommandType == NCommandType::kInfo) + { + CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut); + unsigned i; + + #ifdef Z7_EXTERNAL_CODECS + so << endl << "Libs:" << endl; + for (i = 0; i < codecs->Libs.Size(); i++) + { + PrintLibIndex(so, (int)i); + const CCodecLib &lib = codecs->Libs[i]; + // if (lib.Version != 0) + so << ": " << (lib.Version >> 16) << "."; + PrintNumber(so, lib.Version & 0xffff, 2); + so << " : " << lib.Path << endl; + } + #endif + + so << endl << "Formats:" << endl; + + const char * const kArcFlags = "KSNFMGOPBELHXCc+a+m+r+"; + const char * const kArcTimeFlags = "wudn"; + const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); + const unsigned kNumArcTimeFlags = (unsigned)strlen(kArcTimeFlags); + + for (i = 0; i < codecs->Formats.Size(); i++) + { + const CArcInfoEx &arc = codecs->Formats[i]; + + #ifdef Z7_EXTERNAL_CODECS + PrintLibIndex(so, arc.LibIndex); + #else + so << " "; + #endif + + so << (char)(arc.UpdateEnabled ? 'C' : ' '); + + { + unsigned b; + for (b = 0; b < kNumArcFlags; b++) + so << (char)((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : '.'); + so << ' '; + } + + if (arc.TimeFlags != 0) + { + unsigned b; + for (b = 0; b < kNumArcTimeFlags; b++) + so << (char)((arc.TimeFlags & ((UInt32)1 << b)) != 0 ? kArcTimeFlags[b] : '.'); + so << arc.Get_DefaultTimePrec(); + so << ' '; + } + + so << ' '; + PrintString(so, arc.Name, 8); + so << ' '; + UString s; + + FOR_VECTOR (t, arc.Exts) + { + if (t != 0) + s.Add_Space(); + const CArcExtInfo &ext = arc.Exts[t]; + s += ext.Ext; + if (!ext.AddExt.IsEmpty()) + { + s += " ("; + s += ext.AddExt; + s.Add_Char(')'); + } + } + + PrintString(so, s, 13); + so << ' '; + + if (arc.SignatureOffset != 0) + so << "offset=" << arc.SignatureOffset << ' '; + + // so << "numSignatures = " << arc.Signatures.Size() << " "; + + FOR_VECTOR(si, arc.Signatures) + { + if (si != 0) + so << " || "; + + const CByteBuffer &sig = arc.Signatures[si]; + + for (size_t j = 0; j < sig.Size(); j++) + { + if (j != 0) + so << ' '; + const unsigned b = sig.ConstData()[j]; + if (b > 0x20 && b < 0x80) + { + so << (char)b; + } + else + { + so << GET_HEX_CHAR_UPPER(b >> 4); + so << GET_HEX_CHAR_UPPER(b & 15); + } + } + } + so << endl; + } + + so << endl << "Codecs:" << endl; // << "Lib ID Name" << endl; + + for (i = 0; i < g_NumCodecs; i++) + { + const CCodecInfo &cod = *g_Codecs[i]; + + PrintLibIndex(so, -1); + + if (cod.NumStreams == 1) + so << ' '; + else + so << cod.NumStreams; + + so << (char)(cod.CreateEncoder ? 'E' : ' '); + so << (char)(cod.CreateDecoder ? 'D' : ' '); + so << (char)(cod.IsFilter ? 'F' : ' '); + + so << ' '; + PrintHexId(so, cod.Id); + so << ' ' << cod.Name << endl; + } + + + #ifdef Z7_EXTERNAL_CODECS + + UInt32 numMethods; + if (_externalCodecs.GetCodecs->GetNumMethods(&numMethods) == S_OK) + for (UInt32 j = 0; j < numMethods; j++) + { + PrintLibIndex(so, codecs->GetCodec_LibIndex(j)); + + UInt32 numStreams = codecs->GetCodec_NumStreams(j); + if (numStreams == 1) + so << ' '; + else + so << numStreams; + + so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' '); + so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' '); + { + bool isFilter_Assigned; + const bool isFilter = codecs->GetCodec_IsFilter(j, isFilter_Assigned); + so << (char)(isFilter ? 'F' : isFilter_Assigned ? ' ' : '*'); + } + + + so << ' '; + UInt64 id; + HRESULT res = codecs->GetCodec_Id(j, id); + if (res != S_OK) + id = (UInt64)(Int64)-1; + PrintHexId(so, id); + so << ' ' << codecs->GetCodec_Name(j) << endl; + } + + #endif + + + so << endl << "Hashers:" << endl; // << " L Size ID Name" << endl; + + for (i = 0; i < g_NumHashers; i++) + { + const CHasherInfo &codec = *g_Hashers[i]; + PrintLibIndex(so, -1); + PrintUInt32(so, codec.DigestSize, 4); + so << ' '; + PrintHexId(so, codec.Id); + so << ' ' << codec.Name << endl; + } + + #ifdef Z7_EXTERNAL_CODECS + + numMethods = _externalCodecs.GetHashers->GetNumHashers(); + for (UInt32 j = 0; j < numMethods; j++) + { + PrintLibIndex(so, codecs->GetHasherLibIndex(j)); + PrintUInt32(so, codecs->GetHasherDigestSize(j), 4); + so << ' '; + PrintHexId(so, codecs->GetHasherId(j)); + so << ' ' << codecs->GetHasherName(j) << endl; + } + + #endif + + } + else if (options.Command.CommandType == NCommandType::kBenchmark) + { + CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut); + hresultMain = BenchCon(EXTERNAL_CODECS_VARS_L + options.Properties, options.NumIterations, (FILE *)so); + if (hresultMain == S_FALSE) + { + so << endl; + if (g_ErrStream) + *g_ErrStream << "\nDecoding ERROR\n"; + retCode = NExitCode::kFatalError; + hresultMain = S_OK; + } + } + else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList) + { + UStringVector ArchivePathsSorted; + UStringVector ArchivePathsFullSorted; + + if (options.StdInMode) + { + ArchivePathsSorted.Add(options.ArcName_for_StdInMode); + ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode); + } + else + { + CExtractScanConsole scan; + + scan.Init(options.EnableHeaders ? g_StdStream : NULL, + g_ErrStream, percentsStream, + options.DisablePercents); + scan.SetWindowWidth(consoleWidth); + + if (g_StdStream && options.EnableHeaders) + *g_StdStream << "Scanning the drive for archives:" << endl; + + CDirItemsStat st; + + scan.StartScanning(); + + hresultMain = EnumerateDirItemsAndSort( + options.arcCensor, + NWildcard::k_RelatPath, + UString(), // addPathPrefix + ArchivePathsSorted, + ArchivePathsFullSorted, + st, + &scan); + + scan.CloseScanning(); + + if (hresultMain == S_OK) + { + if (options.EnableHeaders) + scan.PrintStat(st); + } + else + { + /* + if (res != E_ABORT) + { + throw CSystemException(res); + // errorInfo.Message = "Scanning error"; + } + return res; + */ + } + } + + if (hresultMain == S_OK) { + if (isExtractGroupCommand) + { + CExtractCallbackConsole *ecs = new CExtractCallbackConsole; + CMyComPtr extractCallback = ecs; + + #ifndef Z7_NO_CRYPTO + ecs->PasswordIsDefined = options.PasswordEnabled; + ecs->Password = options.Password; + #endif + + ecs->Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); + ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); + + ecs->LogLevel = options.LogLevel; + ecs->PercentsNameLevel = percentsNameLevel; + + if (percentsStream) + ecs->SetWindowWidth(consoleWidth); + + /* + COpenCallbackConsole openCallback; + openCallback.Init(g_StdStream, g_ErrStream); + + #ifndef Z7_NO_CRYPTO + openCallback.PasswordIsDefined = options.PasswordEnabled; + openCallback.Password = options.Password; + #endif + */ + + CExtractOptions eo; + (CExtractOptionsBase &)eo = options.ExtractOptions; + + eo.StdInMode = options.StdInMode; + eo.StdOutMode = options.StdOutMode; + eo.YesToAll = options.YesToAll; + eo.TestMode = options.Command.IsTestCommand(); + + #ifndef Z7_SFX + eo.Properties = options.Properties; + #endif + + UString errorMessage; + CDecompressStat stat; + CHashBundle hb; + IHashCalc *hashCalc = NULL; + + if (!options.HashMethods.IsEmpty()) + { + hashCalc = &hb; + ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods)); + // hb.Init(); + } + + hresultMain = Extract( + // EXTERNAL_CODECS_VARS_L + codecs, + types, + excludedFormats, + ArchivePathsSorted, + ArchivePathsFullSorted, + options.Censor.Pairs.Front().Head, + eo, + ecs, ecs, ecs, + hashCalc, errorMessage, stat); + + ecs->ClosePercents(); + + if (!errorMessage.IsEmpty()) + { + if (g_ErrStream) + *g_ErrStream << endl << "ERROR:" << endl << errorMessage << endl; + if (hresultMain == S_OK) + hresultMain = E_FAIL; + } + + CStdOutStream *so = g_StdStream; + + bool isError = false; + + if (so) + { + *so << endl; + + if (ecs->NumTryArcs > 1) + { + *so << "Archives: " << ecs->NumTryArcs << endl; + *so << "OK archives: " << ecs->NumOkArcs << endl; + } + } + + if (ecs->NumCantOpenArcs != 0) + { + isError = true; + if (so) + *so << "Can't open as archive: " << ecs->NumCantOpenArcs << endl; + } + + if (ecs->NumArcsWithError != 0) + { + isError = true; + if (so) + *so << "Archives with Errors: " << ecs->NumArcsWithError << endl; + } + + if (so) + { + if (ecs->NumArcsWithWarnings != 0) + *so << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl; + + if (ecs->NumOpenArcWarnings != 0) + { + *so << endl; + if (ecs->NumOpenArcWarnings != 0) + *so << "Warnings: " << ecs->NumOpenArcWarnings << endl; + } + } + + if (ecs->NumOpenArcErrors != 0) + { + isError = true; + if (so) + { + *so << endl; + if (ecs->NumOpenArcErrors != 0) + *so << "Open Errors: " << ecs->NumOpenArcErrors << endl; + } + } + + if (isError) + retCode = NExitCode::kFatalError; + + if (so) { + if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0) + { + // if (ecs->NumArchives > 1) + { + *so << endl; + if (ecs->NumFileErrors != 0) + *so << "Sub items Errors: " << ecs->NumFileErrors << endl; + } + } + else if (hresultMain == S_OK) + { + if (stat.NumFolders != 0) + *so << "Folders: " << stat.NumFolders << endl; + if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0) + *so << "Files: " << stat.NumFiles << endl; + if (stat.NumAltStreams != 0) + { + *so << "Alternate Streams: " << stat.NumAltStreams << endl; + *so << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl; + } + + *so + << "Size: " << stat.UnpackSize << endl + << "Compressed: " << stat.PackSize << endl; + if (hashCalc) + { + *so << endl; + PrintHashStat(*so, hb); + } + } + } // if (so) + } + else // if_(!isExtractGroupCommand) + { + UInt64 numErrors = 0; + UInt64 numWarnings = 0; + + // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed + + CListOptions lo; + lo.ExcludeDirItems = options.Censor.ExcludeDirItems; + lo.ExcludeFileItems = options.Censor.ExcludeFileItems; + lo.DisablePercents = options.DisablePercents; + + hresultMain = ListArchives( + lo, + codecs, + types, + excludedFormats, + options.StdInMode, + ArchivePathsSorted, + ArchivePathsFullSorted, + options.ExtractOptions.NtOptions.AltStreams.Val, + options.AltStreams.Val, // we don't want to show AltStreams by default + options.Censor.Pairs.Front().Head, + options.EnableHeaders, + options.TechMode, + #ifndef Z7_NO_CRYPTO + options.PasswordEnabled, + options.Password, + #endif + &options.Properties, + numErrors, numWarnings); + + if (options.EnableHeaders) + if (numWarnings > 0) + g_StdOut << endl << "Warnings: " << numWarnings << endl; + + if (numErrors > 0) + { + if (options.EnableHeaders) + g_StdOut << endl << "Errors: " << numErrors << endl; + retCode = NExitCode::kFatalError; + } + } // if_(isExtractGroupCommand) + } // if_(hresultMain == S_OK) + } + else if (options.Command.IsFromUpdateGroup()) + { + #ifdef Z7_EXTRACT_ONLY + throw "update commands are not implemented"; + #else + CUpdateOptions &uo = options.UpdateOptions; + if (uo.SfxMode && uo.SfxModule.IsEmpty()) + uo.SfxModule = kDefaultSfxModule; + + COpenCallbackConsole openCallback; + openCallback.Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); + + #ifndef Z7_NO_CRYPTO + bool passwordIsDefined = + (options.PasswordEnabled && !options.Password.IsEmpty()); + openCallback.PasswordIsDefined = passwordIsDefined; + openCallback.Password = options.Password; + #endif + + CUpdateCallbackConsole callback; + callback.LogLevel = options.LogLevel; + callback.PercentsNameLevel = percentsNameLevel; + + if (percentsStream) + callback.SetWindowWidth(consoleWidth); + + #ifndef Z7_NO_CRYPTO + callback.PasswordIsDefined = passwordIsDefined; + callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty()); + callback.Password = options.Password; + #endif + + callback.StdOutMode = uo.StdOutMode; + callback.Init( + // NULL, + g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); + + CUpdateErrorInfo errorInfo; + + /* + if (!uo.Init(codecs, types, options.ArchiveName)) + throw kUnsupportedUpdateArcType; + */ + hresultMain = UpdateArchive(codecs, + types, + options.ArchiveName, + options.Censor, + uo, + errorInfo, &openCallback, &callback, true); + + callback.ClosePercents2(); + + CStdOutStream *se = g_StdStream; + if (!se) + se = g_ErrStream; + + retCode = WarningsCheck(hresultMain, callback, errorInfo, + g_StdStream, se, + true // options.EnableHeaders + ); + #endif + } + else if (options.Command.CommandType == NCommandType::kHash) + { + const CHashOptions &uo = options.HashOptions; + + CHashCallbackConsole callback; + if (percentsStream) + callback.SetWindowWidth(consoleWidth); + + callback.Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); + callback.PrintHeaders = options.EnableHeaders; + callback.PrintFields = options.ListFields; + + AString errorInfoString; + hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L + options.Censor, uo, + errorInfoString, &callback); + CUpdateErrorInfo errorInfo; + errorInfo.Message = errorInfoString; + CStdOutStream *se = g_StdStream; + if (!se) + se = g_ErrStream; + retCode = WarningsCheck(hresultMain, callback, errorInfo, g_StdStream, se, options.EnableHeaders); + } + else + ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError); + + if (options.ShowTime && g_StdStream) + PrintStat( + #ifndef _WIN32 + startTime + #endif + ); + + ThrowException_if_Error(hresultMain); + + return retCode; +} diff --git a/CPP/7zip/UI/Console/MainAr.cpp b/CPP/7zip/UI/Console/MainAr.cpp index 8cc3cac4b..490950b4c 100644 --- a/CPP/7zip/UI/Console/MainAr.cpp +++ b/CPP/7zip/UI/Console/MainAr.cpp @@ -1,233 +1,235 @@ -// MainAr.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include "../../../../C/DllSecur.h" -#endif -#include "../../../../C/CpuArch.h" - -#include "../../../Common/MyException.h" -#include "../../../Common/StdOutStream.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/NtCheck.h" - -#include "../Common/ArchiveCommandLine.h" -#include "../Common/ExitCode.h" - -#include "ConsoleClose.h" - -using namespace NWindows; - -extern -CStdOutStream *g_StdStream; -CStdOutStream *g_StdStream = NULL; -extern -CStdOutStream *g_ErrStream; -CStdOutStream *g_ErrStream = NULL; - -extern int Main2( - #ifndef _WIN32 - int numArgs, char *args[] - #endif -); - -static const char * const kException_CmdLine_Error_Message = "Command Line Error:"; -static const char * const kExceptionErrorMessage = "ERROR:"; -static const char * const kUserBreakMessage = "Break signaled"; -static const char * const kMemoryExceptionMessage = "ERROR: Can't allocate required memory!"; -static const char * const kUnknownExceptionMessage = "Unknown Error"; -static const char * const kInternalExceptionMessage = "\n\nInternal Error #"; - -static void FlushStreams() -{ - if (g_StdStream) - g_StdStream->Flush(); -} - -static void PrintError(const char *message) -{ - FlushStreams(); - if (g_ErrStream) - *g_ErrStream << "\n\n" << message << endl; -} - -#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION *g_StdStream << "Unsupported Windows version"; return NExitCode::kFatalError; -#endif - -static inline bool CheckIsa() -{ - // __try - { - // some compilers (e2k) support SSE/AVX, but cpuid() can be unavailable or return lower isa support -#ifdef MY_CPU_X86_OR_AMD64 - #if 0 && (defined(__AVX512F__) && defined(__AVX512VL__)) - if (!CPU_IsSupported_AVX512F_AVX512VL()) - return false; - #elif defined(__AVX2__) - if (!CPU_IsSupported_AVX2()) - return false; - #elif defined(__AVX__) - if (!CPU_IsSupported_AVX()) - return false; - #elif defined(__SSE2__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 2) - if (!CPU_IsSupported_SSE2()) - return false; - #elif defined(__SSE__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 1) - if (!CPU_IsSupported_SSE() || - !CPU_IsSupported_CMOV()) - return false; - #endif -#endif - /* - __asm - { - _emit 0fH - _emit 038H - _emit 0cbH - _emit (0c0H + 0 * 8 + 0) - } - */ - return true; - } - /* - __except (EXCEPTION_EXECUTE_HANDLER) - { - return false; - } - */ -} - -int Z7_CDECL main -( - #ifndef _WIN32 - int numArgs, char *args[] - #endif -) -{ - g_ErrStream = &g_StdErr; - g_StdStream = &g_StdOut; - - // #if (defined(_MSC_VER) && defined(_M_IX86)) - if (!CheckIsa()) - { - PrintError("ERROR: processor doesn't support required ISA extension"); - return NExitCode::kFatalError; - } - // #endif - - NT_CHECK - - NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter; - int res = 0; - - try - { - #ifdef _WIN32 - My_SetDefaultDllDirectories(); - #endif - - res = Main2( - #ifndef _WIN32 - numArgs, args - #endif - ); - } - catch(const CNewException &) - { - PrintError(kMemoryExceptionMessage); - return (NExitCode::kMemoryError); - } - catch(const NConsoleClose::CCtrlBreakException &) - { - PrintError(kUserBreakMessage); - return (NExitCode::kUserBreak); - } - catch(const CMessagePathException &e) - { - PrintError(kException_CmdLine_Error_Message); - if (g_ErrStream) - *g_ErrStream << e << endl; - return (NExitCode::kUserError); - } - catch(const CSystemException &systemError) - { - if (systemError.ErrorCode == E_OUTOFMEMORY) - { - PrintError(kMemoryExceptionMessage); - return (NExitCode::kMemoryError); - } - if (systemError.ErrorCode == E_ABORT) - { - PrintError(kUserBreakMessage); - return (NExitCode::kUserBreak); - } - if (g_ErrStream) - { - PrintError("System ERROR:"); - *g_ErrStream << NError::MyFormatMessage(systemError.ErrorCode) << endl; - } - return (NExitCode::kFatalError); - } - catch(NExitCode::EEnum exitCode) - { - FlushStreams(); - if (g_ErrStream) - *g_ErrStream << kInternalExceptionMessage << exitCode << endl; - return (exitCode); - } - catch(const UString &s) - { - if (g_ErrStream) - { - PrintError(kExceptionErrorMessage); - *g_ErrStream << s << endl; - } - return (NExitCode::kFatalError); - } - catch(const AString &s) - { - if (g_ErrStream) - { - PrintError(kExceptionErrorMessage); - *g_ErrStream << s << endl; - } - return (NExitCode::kFatalError); - } - catch(const char *s) - { - if (g_ErrStream) - { - PrintError(kExceptionErrorMessage); - *g_ErrStream << s << endl; - } - return (NExitCode::kFatalError); - } - catch(const wchar_t *s) - { - if (g_ErrStream) - { - PrintError(kExceptionErrorMessage); - *g_ErrStream << s << endl; - } - return (NExitCode::kFatalError); - } - catch(int t) - { - if (g_ErrStream) - { - FlushStreams(); - *g_ErrStream << kInternalExceptionMessage << t << endl; - return (NExitCode::kFatalError); - } - } - catch(...) - { - PrintError(kUnknownExceptionMessage); - return (NExitCode::kFatalError); - } - - return res; -} +// MainAr.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include "../../../../C/DllSecur.h" +#endif +#include "../../../../C/CpuArch.h" + +#include "../../../Common/MyException.h" +#include "../../../Common/StdOutStream.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/NtCheck.h" + +#include "../Common/ArchiveCommandLine.h" +#include "../Common/ExitCode.h" + +#include "ConsoleClose.h" + +using namespace NWindows; + +extern +CStdOutStream *g_StdStream; +CStdOutStream *g_StdStream = NULL; +extern +CStdOutStream *g_ErrStream; +CStdOutStream *g_ErrStream = NULL; + +extern int Main2( + #ifndef _WIN32 + int numArgs, char *args[] + #endif +); + +static const char * const kException_CmdLine_Error_Message = "Command Line Error:"; +static const char * const kExceptionErrorMessage = "ERROR:"; +static const char * const kUserBreakMessage = "Break signaled"; +static const char * const kMemoryExceptionMessage = "ERROR: Can't allocate required memory!"; +static const char * const kUnknownExceptionMessage = "Unknown Error"; +static const char * const kInternalExceptionMessage = "\n\nInternal Error #"; + +static void FlushStreams() +{ + if (g_StdStream) + g_StdStream->Flush(); +} + +static void PrintError(const char *message) +{ + FlushStreams(); + if (g_ErrStream) + *g_ErrStream << "\n\n" << message << endl; +} + +#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION *g_StdStream << "Unsupported Windows version"; return NExitCode::kFatalError; +#endif + +static inline bool CheckIsa() +{ + // __try + { + // some compilers (e2k) support SSE/AVX, but cpuid() can be unavailable or return lower isa support +#ifdef MY_CPU_X86_OR_AMD64 + #if 0 && (defined(__AVX512F__) && defined(__AVX512VL__)) + if (!CPU_IsSupported_AVX512F_AVX512VL()) + return false; + #elif defined(__AVX2__) + if (!CPU_IsSupported_AVX2()) + return false; + #elif defined(__AVX__) + if (!CPU_IsSupported_AVX()) + return false; + #elif defined(__SSE2__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 2) + if (!CPU_IsSupported_SSE2()) + return false; + #elif defined(__SSE__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 1) + if (!CPU_IsSupported_SSE() || + !CPU_IsSupported_CMOV()) + return false; + #endif +#endif + /* + __asm + { + _emit 0fH + _emit 038H + _emit 0cbH + _emit (0c0H + 0 * 8 + 0) + } + */ + return true; + } + /* + __except (EXCEPTION_EXECUTE_HANDLER) + { + return false; + } + */ +} + +int Z7_CDECL main +( + #ifndef _WIN32 + int numArgs, char *args[] + #endif +) +{ + g_ErrStream = &g_StdErr; + g_StdStream = &g_StdOut; + + // #if (defined(_MSC_VER) && defined(_M_IX86)) + if (!CheckIsa()) + { + PrintError("ERROR: processor doesn't support required ISA extension"); + return NExitCode::kFatalError; + } + // #endif + + NT_CHECK + + NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter; + int res = 0; + + try + { + #ifdef _WIN32 + My_SetDefaultDllDirectories(); + #endif + + res = Main2( + #ifndef _WIN32 + numArgs, args + #endif + ); + } + catch(const CNewException &) + { + PrintError(kMemoryExceptionMessage); + return (NExitCode::kMemoryError); + } +/* + catch(const NConsoleClose::CCtrlBreakException &) + { + PrintError(kUserBreakMessage); + return (NExitCode::kUserBreak); + } +*/ + catch(const CMessagePathException &e) + { + PrintError(kException_CmdLine_Error_Message); + if (g_ErrStream) + *g_ErrStream << e << endl; + return (NExitCode::kUserError); + } + catch(const CSystemException &systemError) + { + if (systemError.ErrorCode == E_OUTOFMEMORY) + { + PrintError(kMemoryExceptionMessage); + return (NExitCode::kMemoryError); + } + if (systemError.ErrorCode == E_ABORT) + { + PrintError(kUserBreakMessage); + return (NExitCode::kUserBreak); + } + if (g_ErrStream) + { + PrintError("System ERROR:"); + *g_ErrStream << NError::MyFormatMessage(systemError.ErrorCode) << endl; + } + return (NExitCode::kFatalError); + } + catch(NExitCode::EEnum exitCode) + { + FlushStreams(); + if (g_ErrStream) + *g_ErrStream << kInternalExceptionMessage << exitCode << endl; + return (exitCode); + } + catch(const UString &s) + { + if (g_ErrStream) + { + PrintError(kExceptionErrorMessage); + *g_ErrStream << s << endl; + } + return (NExitCode::kFatalError); + } + catch(const AString &s) + { + if (g_ErrStream) + { + PrintError(kExceptionErrorMessage); + *g_ErrStream << s << endl; + } + return (NExitCode::kFatalError); + } + catch(const char *s) + { + if (g_ErrStream) + { + PrintError(kExceptionErrorMessage); + *g_ErrStream << s << endl; + } + return (NExitCode::kFatalError); + } + catch(const wchar_t *s) + { + if (g_ErrStream) + { + PrintError(kExceptionErrorMessage); + *g_ErrStream << s << endl; + } + return (NExitCode::kFatalError); + } + catch(int t) + { + if (g_ErrStream) + { + FlushStreams(); + *g_ErrStream << kInternalExceptionMessage << t << endl; + return (NExitCode::kFatalError); + } + } + catch(...) + { + PrintError(kUnknownExceptionMessage); + return (NExitCode::kFatalError); + } + + return res; +} diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp index 12b3483c1..1e7adf5d4 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp @@ -1,115 +1,115 @@ -// OpenCallbackConsole.cpp - -#include "StdAfx.h" - -#include "OpenCallbackConsole.h" - -#include "ConsoleClose.h" -#include "UserInputUtils.h" - -static HRESULT CheckBreak2() -{ - return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; -} - -HRESULT COpenCallbackConsole::Open_CheckBreak() -{ - return CheckBreak2(); -} - -HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) -{ - if (!MultiArcMode && NeedPercents()) - { - if (files) - { - _totalFilesDefined = true; - // _totalFiles = *files; - _percent.Total = *files; - } - else - _totalFilesDefined = false; - - if (bytes) - { - // _totalBytesDefined = true; - _totalBytes = *bytes; - if (!files) - _percent.Total = *bytes; - } - else - { - // _totalBytesDefined = false; - if (!files) - _percent.Total = _totalBytes; - } - } - - return CheckBreak2(); -} - -HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) -{ - if (!MultiArcMode && NeedPercents()) - { - if (files) - { - _percent.Files = *files; - if (_totalFilesDefined) - _percent.Completed = *files; - } - - if (bytes) - { - if (!_totalFilesDefined) - _percent.Completed = *bytes; - } - _percent.Print(); - } - - return CheckBreak2(); -} - -HRESULT COpenCallbackConsole::Open_Finished() -{ - ClosePercents(); - return S_OK; -} - - -#ifndef Z7_NO_CRYPTO - -HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password) -{ - *password = NULL; - RINOK(CheckBreak2()) - - if (!PasswordIsDefined) - { - ClosePercents(); - RINOK(GetPassword_HRESULT(_so, Password)) - PasswordIsDefined = true; - } - return StringToBstr(Password, password); -} - -/* -HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) -{ - passwordIsDefined = PasswordIsDefined; - password = Password; - return S_OK; -} - -bool COpenCallbackConsole::Open_WasPasswordAsked() -{ - return PasswordWasAsked; -} - -void COpenCallbackConsole::Open_Clear_PasswordWasAsked_Flag () -{ - PasswordWasAsked = false; -} -*/ - -#endif +// OpenCallbackConsole.cpp + +#include "StdAfx.h" + +#include "OpenCallbackConsole.h" + +#include "ConsoleClose.h" +#include "UserInputUtils.h" + +static HRESULT CheckBreak2() +{ + return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; +} + +HRESULT COpenCallbackConsole::Open_CheckBreak() +{ + return CheckBreak2(); +} + +HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) +{ + if (!MultiArcMode && NeedPercents()) + { + if (files) + { + _totalFilesDefined = true; + // _totalFiles = *files; + _percent.Total = *files; + } + else + _totalFilesDefined = false; + + if (bytes) + { + // _totalBytesDefined = true; + _totalBytes = *bytes; + if (!files) + _percent.Total = *bytes; + } + else + { + // _totalBytesDefined = false; + if (!files) + _percent.Total = _totalBytes; + } + } + + return CheckBreak2(); +} + +HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) +{ + if (!MultiArcMode && NeedPercents()) + { + if (files) + { + _percent.Files = *files; + if (_totalFilesDefined) + _percent.Completed = *files; + } + + if (bytes) + { + if (!_totalFilesDefined) + _percent.Completed = *bytes; + } + _percent.Print(); + } + + return CheckBreak2(); +} + +HRESULT COpenCallbackConsole::Open_Finished() +{ + ClosePercents(); + return S_OK; +} + + +#ifndef Z7_NO_CRYPTO + +HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password) +{ + *password = NULL; + RINOK(CheckBreak2()) + + if (!PasswordIsDefined) + { + ClosePercents(); + RINOK(GetPassword_HRESULT(_so, Password)) + PasswordIsDefined = true; + } + return StringToBstr(Password, password); +} + +/* +HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) +{ + passwordIsDefined = PasswordIsDefined; + password = Password; + return S_OK; +} + +bool COpenCallbackConsole::Open_WasPasswordAsked() +{ + return PasswordWasAsked; +} + +void COpenCallbackConsole::Open_Clear_PasswordWasAsked_Flag () +{ + PasswordWasAsked = false; +} +*/ + +#endif diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.h b/CPP/7zip/UI/Console/OpenCallbackConsole.h index 0afdabc81..5e7c19cc0 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.h +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h @@ -1,73 +1,73 @@ -// OpenCallbackConsole.h - -#ifndef ZIP7_INC_OPEN_CALLBACK_CONSOLE_H -#define ZIP7_INC_OPEN_CALLBACK_CONSOLE_H - -#include "../../../Common/StdOutStream.h" - -#include "../Common/ArchiveOpenCallback.h" - -#include "PercentPrinter.h" - -class COpenCallbackConsole: public IOpenCallbackUI -{ -protected: - CPercentPrinter _percent; - - CStdOutStream *_so; - CStdOutStream *_se; - - // UInt64 _totalFiles; - UInt64 _totalBytes; - bool _totalFilesDefined; - // bool _totalBytesDefined; - - bool NeedPercents() const { return _percent._so && !_percent.DisablePrint; } - -public: - - bool MultiArcMode; - - void ClosePercents() - { - if (NeedPercents()) - _percent.ClosePrint(true); - } - - COpenCallbackConsole(): - _totalBytes(0), - _totalFilesDefined(false), - // _totalBytesDefined(false), - MultiArcMode(false) - - #ifndef Z7_NO_CRYPTO - , PasswordIsDefined(false) - // , PasswordWasAsked(false) - #endif - - {} - - virtual ~COpenCallbackConsole() {} - - void Init( - CStdOutStream *outStream, - CStdOutStream *errorStream, - CStdOutStream *percentStream, - bool disablePercents) - { - _so = outStream; - _se = errorStream; - _percent._so = percentStream; - _percent.DisablePrint = disablePercents; - } - - Z7_IFACE_IMP(IOpenCallbackUI) - - #ifndef Z7_NO_CRYPTO - bool PasswordIsDefined; - // bool PasswordWasAsked; - UString Password; - #endif -}; - -#endif +// OpenCallbackConsole.h + +#ifndef ZIP7_INC_OPEN_CALLBACK_CONSOLE_H +#define ZIP7_INC_OPEN_CALLBACK_CONSOLE_H + +#include "../../../Common/StdOutStream.h" + +#include "../Common/ArchiveOpenCallback.h" + +#include "PercentPrinter.h" + +class COpenCallbackConsole: public IOpenCallbackUI +{ +protected: + CPercentPrinter _percent; + + CStdOutStream *_so; + CStdOutStream *_se; + + // UInt64 _totalFiles; + UInt64 _totalBytes; + bool _totalFilesDefined; + // bool _totalBytesDefined; + + bool NeedPercents() const { return _percent._so && !_percent.DisablePrint; } + +public: + + bool MultiArcMode; + + void ClosePercents() + { + if (NeedPercents()) + _percent.ClosePrint(true); + } + + COpenCallbackConsole(): + _totalBytes(0), + _totalFilesDefined(false), + // _totalBytesDefined(false), + MultiArcMode(false) + + #ifndef Z7_NO_CRYPTO + , PasswordIsDefined(false) + // , PasswordWasAsked(false) + #endif + + {} + + virtual ~COpenCallbackConsole() {} + + void Init( + CStdOutStream *outStream, + CStdOutStream *errorStream, + CStdOutStream *percentStream, + bool disablePercents) + { + _so = outStream; + _se = errorStream; + _percent._so = percentStream; + _percent.DisablePrint = disablePercents; + } + + Z7_IFACE_IMP(IOpenCallbackUI) + + #ifndef Z7_NO_CRYPTO + bool PasswordIsDefined; + // bool PasswordWasAsked; + UString Password; + #endif +}; + +#endif diff --git a/CPP/7zip/UI/Console/PercentPrinter.cpp b/CPP/7zip/UI/Console/PercentPrinter.cpp index 5d3da7f6d..cfdab0300 100644 --- a/CPP/7zip/UI/Console/PercentPrinter.cpp +++ b/CPP/7zip/UI/Console/PercentPrinter.cpp @@ -1,186 +1,186 @@ -// PercentPrinter.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "PercentPrinter.h" - -static const unsigned kPercentsSize = 4; - -CPercentPrinter::~CPercentPrinter() -{ - ClosePrint(false); -} - -void CPercentPrinterState::ClearCurState() -{ - Completed = 0; - Total = ((UInt64)(Int64)-1); - Files = 0; - Command.Empty(); - FileName.Empty(); -} - -void CPercentPrinter::ClosePrint(bool needFlush) -{ - unsigned num = _printedString.Len(); - if (num != 0) - { - - unsigned i; - - /* '\r' in old MAC OS means "new line". - So we can't use '\r' in some systems */ - - #ifdef _WIN32 - char *start = _temp.GetBuf(num + 2); - char *p = start; - *p++ = '\r'; - for (i = 0; i < num; i++) *p++ = ' '; - *p++ = '\r'; - #else - char *start = _temp.GetBuf(num * 3); - char *p = start; - for (i = 0; i < num; i++) *p++ = '\b'; - for (i = 0; i < num; i++) *p++ = ' '; - for (i = 0; i < num; i++) *p++ = '\b'; - #endif - - *p = 0; - _temp.ReleaseBuf_SetLen((unsigned)(p - start)); - *_so << _temp; - } - if (needFlush) - _so->Flush(); - _printedString.Empty(); -} - -void CPercentPrinter::GetPercents() -{ - char s[32]; - unsigned size; - { - char c = '%'; - UInt64 val = 0; - if (Total == (UInt64)(Int64)-1 || - (Total == 0 && Completed != 0)) - { - val = Completed >> 20; - c = 'M'; - } - else if (Total != 0) - val = Completed * 100 / Total; - ConvertUInt64ToString(val, s); - size = (unsigned)strlen(s); - s[size++] = c; - s[size] = 0; - } - - while (size < kPercentsSize) - { - _s.Add_Space(); - size++; - } - - _s += s; -} - -void CPercentPrinter::Print() -{ - if (DisablePrint) - return; - DWORD tick = 0; - if (_tickStep != 0) - tick = GetTickCount(); - - bool onlyPercentsChanged = false; - - if (!_printedString.IsEmpty()) - { - if (_tickStep != 0 && (UInt32)(tick - _prevTick) < _tickStep) - return; - - CPercentPrinterState &st = *this; - if (_printedState.Command == st.Command - && _printedState.FileName == st.FileName - && _printedState.Files == st.Files) - { - if (_printedState.Total == st.Total - && _printedState.Completed == st.Completed) - return; - onlyPercentsChanged = true; - } - } - - _s.Empty(); - - GetPercents(); - - if (onlyPercentsChanged && _s == _printedPercents) - return; - - _printedPercents = _s; - - if (Files != 0) - { - char s[32]; - ConvertUInt64ToString(Files, s); - // unsigned size = (unsigned)strlen(s); - // for (; size < 3; size++) _s.Add_Space(); - _s.Add_Space(); - _s += s; - // _s += "f"; - } - - - if (!Command.IsEmpty()) - { - _s.Add_Space(); - _s += Command; - } - - if (!FileName.IsEmpty() && _s.Len() < MaxLen) - { - _s.Add_Space(); - - _tempU = FileName; - _so->Normalize_UString_Path(_tempU); - _so->Convert_UString_to_AString(_tempU, _temp); - if (_s.Len() + _temp.Len() > MaxLen) - { - unsigned len = FileName.Len(); - for (; len != 0;) - { - unsigned delta = len / 8; - if (delta == 0) - delta = 1; - len -= delta; - _tempU = FileName; - _tempU.Delete(len / 2, _tempU.Len() - len); - _tempU.Insert(len / 2, L" . "); - _so->Normalize_UString_Path(_tempU); - _so->Convert_UString_to_AString(_tempU, _temp); - if (_s.Len() + _temp.Len() <= MaxLen) - break; - } - if (len == 0) - _temp.Empty(); - } - _s += _temp; - } - - if (_printedString != _s) - { - ClosePrint(false); - *_so << _s; - if (NeedFlush) - _so->Flush(); - _printedString = _s; - } - - _printedState = *this; - - if (_tickStep != 0) - _prevTick = tick; -} +// PercentPrinter.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "PercentPrinter.h" + +static const unsigned kPercentsSize = 4; + +CPercentPrinter::~CPercentPrinter() +{ + ClosePrint(false); +} + +void CPercentPrinterState::ClearCurState() +{ + Completed = 0; + Total = ((UInt64)(Int64)-1); + Files = 0; + Command.Empty(); + FileName.Empty(); +} + +void CPercentPrinter::ClosePrint(bool needFlush) +{ + unsigned num = _printedString.Len(); + if (num != 0) + { + + unsigned i; + + /* '\r' in old MAC OS means "new line". + So we can't use '\r' in some systems */ + + #ifdef _WIN32 + char *start = _temp.GetBuf(num + 2); + char *p = start; + *p++ = '\r'; + for (i = 0; i < num; i++) *p++ = ' '; + *p++ = '\r'; + #else + char *start = _temp.GetBuf(num * 3); + char *p = start; + for (i = 0; i < num; i++) *p++ = '\b'; + for (i = 0; i < num; i++) *p++ = ' '; + for (i = 0; i < num; i++) *p++ = '\b'; + #endif + + *p = 0; + _temp.ReleaseBuf_SetLen((unsigned)(p - start)); + *_so << _temp; + } + if (needFlush) + _so->Flush(); + _printedString.Empty(); +} + +void CPercentPrinter::GetPercents() +{ + char s[32]; + unsigned size; + { + char c = '%'; + UInt64 val = 0; + if (Total == (UInt64)(Int64)-1 || + (Total == 0 && Completed != 0)) + { + val = Completed >> 20; + c = 'M'; + } + else if (Total != 0) + val = Completed * 100 / Total; + ConvertUInt64ToString(val, s); + size = (unsigned)strlen(s); + s[size++] = c; + s[size] = 0; + } + + while (size < kPercentsSize) + { + _s.Add_Space(); + size++; + } + + _s += s; +} + +void CPercentPrinter::Print() +{ + if (DisablePrint) + return; + DWORD tick = 0; + if (_tickStep != 0) + tick = GetTickCount(); + + bool onlyPercentsChanged = false; + + if (!_printedString.IsEmpty()) + { + if (_tickStep != 0 && (UInt32)(tick - _prevTick) < _tickStep) + return; + + CPercentPrinterState &st = *this; + if (_printedState.Command == st.Command + && _printedState.FileName == st.FileName + && _printedState.Files == st.Files) + { + if (_printedState.Total == st.Total + && _printedState.Completed == st.Completed) + return; + onlyPercentsChanged = true; + } + } + + _s.Empty(); + + GetPercents(); + + if (onlyPercentsChanged && _s == _printedPercents) + return; + + _printedPercents = _s; + + if (Files != 0) + { + char s[32]; + ConvertUInt64ToString(Files, s); + // unsigned size = (unsigned)strlen(s); + // for (; size < 3; size++) _s.Add_Space(); + _s.Add_Space(); + _s += s; + // _s += "f"; + } + + + if (!Command.IsEmpty()) + { + _s.Add_Space(); + _s += Command; + } + + if (!FileName.IsEmpty() && _s.Len() < MaxLen) + { + _s.Add_Space(); + + _tempU = FileName; + _so->Normalize_UString_Path(_tempU); + _so->Convert_UString_to_AString(_tempU, _temp); + if (_s.Len() + _temp.Len() > MaxLen) + { + unsigned len = FileName.Len(); + for (; len != 0;) + { + unsigned delta = len / 8; + if (delta == 0) + delta = 1; + len -= delta; + _tempU = FileName; + _tempU.Delete(len / 2, _tempU.Len() - len); + _tempU.Insert(len / 2, L" . "); + _so->Normalize_UString_Path(_tempU); + _so->Convert_UString_to_AString(_tempU, _temp); + if (_s.Len() + _temp.Len() <= MaxLen) + break; + } + if (len == 0) + _temp.Empty(); + } + _s += _temp; + } + + if (_printedString != _s) + { + ClosePrint(false); + *_so << _s; + if (NeedFlush) + _so->Flush(); + _printedString = _s; + } + + _printedState = *this; + + if (_tickStep != 0) + _prevTick = tick; +} diff --git a/CPP/7zip/UI/Console/PercentPrinter.h b/CPP/7zip/UI/Console/PercentPrinter.h index 7653fc814..379aa1b7a 100644 --- a/CPP/7zip/UI/Console/PercentPrinter.h +++ b/CPP/7zip/UI/Console/PercentPrinter.h @@ -1,64 +1,66 @@ -// PercentPrinter.h - -#ifndef ZIP7_INC_PERCENT_PRINTER_H -#define ZIP7_INC_PERCENT_PRINTER_H - -#include "../../../Common/StdOutStream.h" - -struct CPercentPrinterState -{ - UInt64 Completed; - UInt64 Total; - - UInt64 Files; - - AString Command; - UString FileName; - - void ClearCurState(); - - CPercentPrinterState(): - Completed(0), - Total((UInt64)(Int64)-1), - Files(0) - {} -}; - -class CPercentPrinter: public CPercentPrinterState -{ - UInt32 _tickStep; - DWORD _prevTick; - - AString _s; - - AString _printedString; - AString _temp; - UString _tempU; - - CPercentPrinterState _printedState; - AString _printedPercents; - - void GetPercents(); - -public: - CStdOutStream *_so; - - bool DisablePrint; - bool NeedFlush; - unsigned MaxLen; - - CPercentPrinter(UInt32 tickStep = 200): - _tickStep(tickStep), - _prevTick(0), - DisablePrint(false), - NeedFlush(true), - MaxLen(80 - 1) - {} - - ~CPercentPrinter(); - - void ClosePrint(bool needFlush); - void Print(); -}; - -#endif +// PercentPrinter.h + +#ifndef ZIP7_INC_PERCENT_PRINTER_H +#define ZIP7_INC_PERCENT_PRINTER_H + +#include "../../../Common/StdOutStream.h" + +struct CPercentPrinterState +{ + UInt64 Completed; + UInt64 Total; + + UInt64 Files; + + AString Command; + UString FileName; + + void ClearCurState(); + + CPercentPrinterState(): + Completed(0), + Total((UInt64)(Int64)-1), + Files(0) + {} +}; + +class CPercentPrinter: public CPercentPrinterState +{ +public: + CStdOutStream *_so; + bool DisablePrint; + bool NeedFlush; + unsigned MaxLen; + +private: + UInt32 _tickStep; + DWORD _prevTick; + + AString _s; + + AString _printedString; + AString _temp; + UString _tempU; + + CPercentPrinterState _printedState; + AString _printedPercents; + + void GetPercents(); + +public: + + CPercentPrinter(UInt32 tickStep = 200): + DisablePrint(false), + NeedFlush(true), + MaxLen(80 - 1), + _tickStep(tickStep), + _prevTick(0) + {} + + ~CPercentPrinter(); + + void ClosePrint(bool needFlush); + void Print(); +}; + +#endif diff --git a/CPP/7zip/UI/Console/StdAfx.cpp b/CPP/7zip/UI/Console/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/Console/StdAfx.cpp +++ b/CPP/7zip/UI/Console/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/Console/StdAfx.h b/CPP/7zip/UI/Console/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/UI/Console/StdAfx.h +++ b/CPP/7zip/UI/Console/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp index 4d7dbe6a2..5185d5cc8 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp @@ -1,885 +1,998 @@ -// UpdateCallbackConsole.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileName.h" - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#endif - -// #include "../Common/PropIDUtils.h" - -#include "ConsoleClose.h" -#include "UserInputUtils.h" -#include "UpdateCallbackConsole.h" - -using namespace NWindows; - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - -static const wchar_t * const kEmptyFileAlias = L"[Content]"; - -static const char * const kOpenArchiveMessage = "Open archive: "; -static const char * const kCreatingArchiveMessage = "Creating archive: "; -static const char * const kUpdatingArchiveMessage = "Updating archive: "; -static const char * const kScanningMessage = "Scanning the drive:"; - -static const char * const kError = "ERROR: "; -static const char * const kWarning = "WARNING: "; - -static HRESULT CheckBreak2() -{ - return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; -} - -HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); -HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); - -void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); - -void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); - -HRESULT CUpdateCallbackConsole::OpenResult( - const CCodecs *codecs, const CArchiveLink &arcLink, - const wchar_t *name, HRESULT result) -{ - ClosePercents2(); - - FOR_VECTOR (level, arcLink.Arcs) - { - const CArc &arc = arcLink.Arcs[level]; - const CArcErrorInfo &er = arc.ErrorInfo; - - UInt32 errorFlags = er.GetErrorFlags(); - - if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) - { - if (_se) - { - *_se << endl; - if (level != 0) - *_se << arc.Path << endl; - } - - if (errorFlags != 0) - { - if (_se) - PrintErrorFlags(*_se, "ERRORS:", errorFlags); - } - - if (!er.ErrorMessage.IsEmpty()) - { - if (_se) - *_se << "ERRORS:" << endl << er.ErrorMessage << endl; - } - - if (_se) - { - *_se << endl; - _se->Flush(); - } - } - - UInt32 warningFlags = er.GetWarningFlags(); - - if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) - { - if (_so) - { - *_so << endl; - if (level != 0) - *_so << arc.Path << endl; - } - - if (warningFlags != 0) - { - if (_so) - PrintErrorFlags(*_so, "WARNINGS:", warningFlags); - } - - if (!er.WarningMessage.IsEmpty()) - { - if (_so) - *_so << "WARNINGS:" << endl << er.WarningMessage << endl; - } - - if (_so) - { - *_so << endl; - if (NeedFlush) - _so->Flush(); - } - } - - - if (er.ErrorFormatIndex >= 0) - { - if (_so) - { - Print_ErrorFormatIndex_Warning(_so, codecs, arc); - if (NeedFlush) - _so->Flush(); - } - } - } - - if (result == S_OK) - { - if (_so) - { - RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)) - *_so << endl; - } - } - else - { - if (_so) - _so->Flush(); - if (_se) - { - *_se << kError; - _se->NormalizePrint_wstr_Path(name); - *_se << endl; - HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); - RINOK(res) - _se->Flush(); - } - } - - return S_OK; -} - -HRESULT CUpdateCallbackConsole::StartScanning() -{ - if (_so) - *_so << kScanningMessage << endl; - _percent.Command = "Scan "; - return S_OK; -} - -HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) -{ - if (NeedPercents()) - { - _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; - _percent.Completed = st.GetTotalBytes(); - _percent.FileName = fs2us(path); - _percent.Print(); - } - - return CheckBreak(); -} - -void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning) -{ - ClosePercents2(); - - if (_se) - { - if (_so) - _so->Flush(); - - *_se << endl << (isWarning ? kWarning : kError) - << NError::MyFormatMessage(systemError) - << endl; - _se->NormalizePrint_UString_Path(fs2us(path)); - *_se << endl << endl; - _se->Flush(); - } -} - -/* -void CCallbackConsoleBase::CommonError(const char *message) -{ - ClosePercents2(); - - if (_se) - { - if (_so) - _so->Flush(); - - *_se << endl << kError << message << endl; - _se->Flush(); - } -} -*/ - - -HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError) -{ - MT_LOCK - - ScanErrors.AddError(path, systemError); - CommonError(path, systemError, true); - - return S_OK; -} - -HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError) -{ - MT_LOCK - FailedFiles.AddError(path, systemError); - NumNonOpenFiles++; - /* - if (systemError == ERROR_SHARING_VIOLATION) - { - */ - CommonError(path, systemError, true); - return S_FALSE; - /* - } - return systemError; - */ -} - -HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError) -{ - MT_LOCK - CommonError(path, systemError, false); - return HRESULT_FROM_WIN32(systemError); -} - -HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError) -{ - return ScanError_Base(path, systemError); -} - - -static void PrintPropPair(AString &s, const char *name, UInt64 val) -{ - char temp[32]; - ConvertUInt64ToString(val, temp); - s += name; - s += ": "; - s += temp; -} - -void PrintSize_bytes_Smart(AString &s, UInt64 val); -void Print_DirItemsStat(AString &s, const CDirItemsStat &st); -void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); - -HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st) -{ - if (NeedPercents()) - { - _percent.ClosePrint(true); - _percent.ClearCurState(); - } - - if (_so) - { - AString s; - Print_DirItemsStat(s, st); - *_so << s << endl << endl; - } - return S_OK; -} - -static const char * const k_StdOut_ArcName = "StdOut"; - -HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name) -{ - if (_so) - { - *_so << kOpenArchiveMessage; - if (name) - *_so << name; - else - *_so << k_StdOut_ArcName; - *_so << endl; - } - return S_OK; -} - -HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating) -{ - if (NeedPercents()) - _percent.ClosePrint(true); - - _percent.ClearCurState(); - NumNonOpenFiles = 0; - - if (_so) - { - *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage); - if (name) - _so->NormalizePrint_wstr_Path(name); - else - *_so << k_StdOut_ArcName; - *_so << endl << endl; - } - return S_OK; -} - -HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st) -{ - ClosePercents2(); - - if (_so) - { - AString s; - // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files); - PrintPropPair(s, "Files read from disk", _percent.Files - NumNonOpenFiles); - s.Add_LF(); - s += "Archive size: "; - PrintSize_bytes_Smart(s, st.OutArcFileSize); - s.Add_LF(); - if (st.IsMultiVolMode) - { - s += "Volumes: "; - s.Add_UInt32(st.NumVolumes); - s.Add_LF(); - } - *_so << endl; - *_so << s; - // *_so << endl; - } - - return S_OK; -} - -HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size) -{ - if (_so) - { - *_so << "Write SFX: "; - *_so << name; - AString s (" : "); - PrintSize_bytes_Smart(s, size); - *_so << s << endl; - } - return S_OK; -} - - -HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */) -{ - if (LogLevel > 0 && _so) - { - ClosePercents_for_so(); - - if (!DeleteMessageWasShown) - { - if (_so) - *_so << endl << ": Removing files after including to archive" << endl; - } - - { - { - _tempA = "Removing"; - _tempA.Add_Space(); - *_so << _tempA; - _tempU = fs2us(path); - _so->Normalize_UString_Path(_tempU); - _so->PrintUString(_tempU, _tempA); - *_so << endl; - if (NeedFlush) - _so->Flush(); - } - } - } - - if (!DeleteMessageWasShown) - { - if (NeedPercents()) - { - _percent.ClearCurState(); - } - DeleteMessageWasShown = true; - } - else - { - _percent.Files++; - } - - if (NeedPercents()) - { - // if (!FullLog) - { - _percent.Command = "Removing"; - _percent.FileName = fs2us(path); - } - _percent.Print(); - } - - return S_OK; -} - - -HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving() -{ - ClosePercents2(); - if (_so && DeleteMessageWasShown) - *_so << endl; - return S_OK; -} - -HRESULT CUpdateCallbackConsole::CheckBreak() -{ - return CheckBreak2(); -} - -/* -HRESULT CUpdateCallbackConsole::Finalize() -{ - // MT_LOCK - return S_OK; -} -*/ - - -void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name) -{ - AString s; - Print_DirItemsStat2(s, stat); - *_so << name << ": " << s << endl; -} - -HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat) -{ - if (_so) - { - ClosePercents_for_so(); - if (!stat.DeleteData.IsEmpty()) - { - *_so << endl; - PrintToDoStat(_so, stat.DeleteData, "Delete data from archive"); - } - if (!stat.OldData.IsEmpty()) - PrintToDoStat(_so, stat.OldData, "Keep old data in archive"); - // if (!stat.NewData.IsEmpty()) - { - PrintToDoStat(_so, stat.NewData, "Add new data to archive"); - } - *_so << endl; - } - return S_OK; -} - -HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size) -{ - MT_LOCK - if (NeedPercents()) - { - _percent.Total = size; - _percent.Print(); - } - return S_OK; -} - -HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue) -{ - MT_LOCK - if (completeValue) - { - if (NeedPercents()) - { - _percent.Completed = *completeValue; - _percent.Print(); - } - } - return CheckBreak2(); -} - -HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */) -{ - return CheckBreak2(); -} - -HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog) -{ - MT_LOCK - - bool show2 = (showInLog && _so); - - if (show2) - { - ClosePercents_for_so(); - - _tempA = command; - if (name) - _tempA.Add_Space(); - *_so << _tempA; - - _tempU.Empty(); - if (name) - { - _tempU = name; - if (isDir) - NWindows::NFile::NName::NormalizeDirPathPrefix(_tempU); - _so->Normalize_UString_Path(_tempU); - } - _so->PrintUString(_tempU, _tempA); - *_so << endl; - if (NeedFlush) - _so->Flush(); - } - - if (NeedPercents()) - { - if (PercentsNameLevel >= 1) - { - _percent.FileName.Empty(); - _percent.Command.Empty(); - if (PercentsNameLevel > 1 || !show2) - { - _percent.Command = command; - if (name) - _percent.FileName = name; - } - } - _percent.Print(); - } - - return CheckBreak2(); -} - - -/* -void CCallbackConsoleBase::PrintInfoLine(const UString &s) -{ - if (LogLevel < 1000) - return; - - MT_LOCK - - const bool show2 = (_so != NULL); - - if (show2) - { - ClosePercents_for_so(); - _so->PrintUString(s, _tempA); - *_so << endl; - if (NeedFlush) - _so->Flush(); - } -} -*/ - -HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) -{ - if (StdOutMode) - return S_OK; - - if (!name || name[0] == 0) - name = kEmptyFileAlias; - - unsigned requiredLevel = 1; - - const char *s; - if (mode == NUpdateNotifyOp::kAdd || - mode == NUpdateNotifyOp::kUpdate) - { - if (isAnti) - s = "Anti"; - else if (mode == NUpdateNotifyOp::kAdd) - s = "+"; - else - s = "U"; - } - else - { - requiredLevel = 3; - if (mode == NUpdateNotifyOp::kAnalyze) - s = "A"; - else - s = "Reading"; - } - - return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); -} - -HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError) -{ - return OpenFileError_Base(path, systemError); -} - -HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError) -{ - return ReadingFileError_Base(path, systemError); -} - -HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */) -{ - MT_LOCK - _percent.Files++; - /* - if (opRes != NArchive::NUpdate::NOperationResult::kOK) - { - if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged) - { - CommonError("Input file changed"); - } - } - */ - return S_OK; -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); - -HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) -{ - // if (StdOutMode) return S_OK; - - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - ClosePercents2(); - - if (_se) - { - if (_so) - _so->Flush(); - - AString s; - SetExtractErrorMessage(opRes, isEncrypted, s); - *_se << s << " : " << endl; - _se->NormalizePrint_wstr_Path(name); - *_se << endl << endl; - _se->Flush(); - } - return S_OK; - } - return S_OK; -} - - -HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) -{ - // if (StdOutMode) return S_OK; - - char temp[16]; - const char *s; - - unsigned requiredLevel = 1; - - switch (op) - { - case NUpdateNotifyOp::kAdd: s = "+"; break; - case NUpdateNotifyOp::kUpdate: s = "U"; break; - case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break; - case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break; - case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break; - case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break; - case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break; - case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break; - case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break; - // case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break; - default: - { - temp[0] = 'o'; - temp[1] = 'p'; - ConvertUInt64ToString(op, temp + 2); - s = temp; - } - } - - return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); -} - -/* -HRESULT CUpdateCallbackConsole::SetPassword(const UString & - #ifndef Z7_NO_CRYPTO - password - #endif - ) -{ - #ifndef Z7_NO_CRYPTO - PasswordIsDefined = true; - Password = password; - #endif - return S_OK; -} -*/ - -HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) -{ - COM_TRY_BEGIN - - *password = NULL; - - #ifdef Z7_NO_CRYPTO - - *passwordIsDefined = false; - return S_OK; - - #else - - if (!PasswordIsDefined) - { - if (AskPassword) - { - RINOK(GetPassword_HRESULT(_so, Password)) - PasswordIsDefined = true; - } - } - *passwordIsDefined = BoolToInt(PasswordIsDefined); - return StringToBstr(Password, password); - - #endif - - COM_TRY_END -} - -HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password) -{ - COM_TRY_BEGIN - - *password = NULL; - - #ifdef Z7_NO_CRYPTO - - return E_NOTIMPL; - - #else - - if (!PasswordIsDefined) - { - { - RINOK(GetPassword_HRESULT(_so, Password)) - PasswordIsDefined = true; - } - } - return StringToBstr(Password, password); - - #endif - COM_TRY_END -} - -HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir) -{ - if (StdOutMode) - return S_OK; - - if (LogLevel > 7) - { - if (!name || name[0] == 0) - name = kEmptyFileAlias; - return PrintProgress(name, isDir, "D", true); - } - return S_OK; -} - -/* -void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU); - -static void GetPropName(PROPID propID, UString &nameU) -{ - AString nameA; - GetPropName(propID, NULL, nameA, nameU); - // if (!nameA.IsEmpty()) - nameU = nameA; -} - - -static void AddPropNamePrefix(UString &s, PROPID propID) -{ - UString name; - GetPropName(propID, name); - s += name; - s += " = "; -} - -void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value) -{ - AddPropNamePrefix(s, propID); - { - UString dest; - const int level = 9; // we show up to ns precision level - ConvertPropertyToString2(dest, *value, propID, level); - s += dest; - } - PrintInfoLine(s); -} - -static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index) -{ - if (indexType == NArchive::NEventIndexType::kArcProp) - { - } - else - { - if (indexType == NArchive::NEventIndexType::kBlockIndex) - { - s += "#"; - } - else if (indexType == NArchive::NEventIndexType::kOutArcIndex) - { - } - else - { - s += "indexType_"; - s.Add_UInt32(indexType); - s.Add_Space(); - } - s.Add_UInt32(index); - } - s += ": "; -} - -HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) -{ - UString s; - Add_IndexType_Index(s, indexType, index); - PrintPropInfo(s, propID, value); - return S_OK; -} - -static inline char GetHex(Byte value) -{ - return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10))); -} - -static void AddHexToString(UString &dest, const Byte *data, UInt32 size) -{ - for (UInt32 i = 0; i < size; i++) - { - Byte b = data[i]; - dest += GetHex((Byte)((b >> 4) & 0xF)); - dest += GetHex((Byte)(b & 0xF)); - } -} - -void HashHexToString(char *dest, const Byte *data, UInt32 size); - -HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index, - PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) -{ - UString s; - propType = propType; - Add_IndexType_Index(s, indexType, index); - AddPropNamePrefix(s, propID); - if (propID == kpidChecksum) - { - char temp[k_HashCalc_DigestSize_Max + 8]; - HashHexToString(temp, (const Byte *)data, dataSize); - s += temp; - } - else - AddHexToString(s, (const Byte *)data, dataSize); - PrintInfoLine(s); - return S_OK; -} - -HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) -{ - UString s; - Add_IndexType_Index(s, indexType, index); - s += "finished"; - if (opRes != NArchive::NUpdate::NOperationResult::kOK) - { - s += ": "; - s.Add_UInt32(opRes); - } - PrintInfoLine(s); - return S_OK; -} -*/ +// UpdateCallbackConsole.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileName.h" + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#endif + +// #include "../Common/PropIDUtils.h" + +#include "ConsoleClose.h" +#include "UserInputUtils.h" +#include "UpdateCallbackConsole.h" + +using namespace NWindows; + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + +static const wchar_t * const kEmptyFileAlias = L"[Content]"; + +static const char * const kOpenArchiveMessage = "Open archive: "; +static const char * const kCreatingArchiveMessage = "Creating archive: "; +static const char * const kUpdatingArchiveMessage = "Updating archive: "; +static const char * const kScanningMessage = "Scanning the drive:"; + +static const char * const kError = "ERROR: "; +static const char * const kWarning = "WARNING: "; + +static HRESULT CheckBreak2() +{ + return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; +} + +HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); +HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); + +void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); + +void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); + +HRESULT CUpdateCallbackConsole::OpenResult( + const CCodecs *codecs, const CArchiveLink &arcLink, + const wchar_t *name, HRESULT result) +{ + ClosePercents2(); + + FOR_VECTOR (level, arcLink.Arcs) + { + const CArc &arc = arcLink.Arcs[level]; + const CArcErrorInfo &er = arc.ErrorInfo; + + UInt32 errorFlags = er.GetErrorFlags(); + + if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) + { + if (_se) + { + *_se << endl; + if (level != 0) + *_se << arc.Path << endl; + } + + if (errorFlags != 0) + { + if (_se) + PrintErrorFlags(*_se, "ERRORS:", errorFlags); + } + + if (!er.ErrorMessage.IsEmpty()) + { + if (_se) + *_se << "ERRORS:" << endl << er.ErrorMessage << endl; + } + + if (_se) + { + *_se << endl; + _se->Flush(); + } + } + + UInt32 warningFlags = er.GetWarningFlags(); + + if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) + { + if (_so) + { + *_so << endl; + if (level != 0) + *_so << arc.Path << endl; + } + + if (warningFlags != 0) + { + if (_so) + PrintErrorFlags(*_so, "WARNINGS:", warningFlags); + } + + if (!er.WarningMessage.IsEmpty()) + { + if (_so) + *_so << "WARNINGS:" << endl << er.WarningMessage << endl; + } + + if (_so) + { + *_so << endl; + if (NeedFlush) + _so->Flush(); + } + } + + + if (er.ErrorFormatIndex >= 0) + { + if (_so) + { + Print_ErrorFormatIndex_Warning(_so, codecs, arc); + if (NeedFlush) + _so->Flush(); + } + } + } + + if (result == S_OK) + { + if (_so) + { + RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)) + *_so << endl; + } + } + else + { + if (_so) + _so->Flush(); + if (_se) + { + *_se << kError; + _se->NormalizePrint_wstr_Path(name); + *_se << endl; + HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); + RINOK(res) + _se->Flush(); + } + } + + return S_OK; +} + +HRESULT CUpdateCallbackConsole::StartScanning() +{ + if (_so) + *_so << kScanningMessage << endl; + _percent.Command = "Scan "; + return S_OK; +} + +HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) +{ + if (NeedPercents()) + { + _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; + _percent.Completed = st.GetTotalBytes(); + _percent.FileName = fs2us(path); + _percent.Print(); + } + + return CheckBreak(); +} + +void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning) +{ + ClosePercents2(); + + if (_se) + { + if (_so) + _so->Flush(); + + *_se << endl << (isWarning ? kWarning : kError) + << NError::MyFormatMessage(systemError) + << endl; + _se->NormalizePrint_UString_Path(fs2us(path)); + *_se << endl << endl; + _se->Flush(); + } +} + +/* +void CCallbackConsoleBase::CommonError(const char *message) +{ + ClosePercents2(); + + if (_se) + { + if (_so) + _so->Flush(); + + *_se << endl << kError << message << endl; + _se->Flush(); + } +} +*/ + + +HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError) +{ + MT_LOCK + + ScanErrors.AddError(path, systemError); + CommonError(path, systemError, true); + + return S_OK; +} + +HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError) +{ + MT_LOCK + FailedFiles.AddError(path, systemError); + NumNonOpenFiles++; + /* + if (systemError == ERROR_SHARING_VIOLATION) + { + */ + CommonError(path, systemError, true); + return S_FALSE; + /* + } + return systemError; + */ +} + +HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError) +{ + MT_LOCK + CommonError(path, systemError, false); + return HRESULT_FROM_WIN32(systemError); +} + +HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError) +{ + return ScanError_Base(path, systemError); +} + + +static void PrintPropPair(AString &s, const char *name, UInt64 val) +{ + char temp[32]; + ConvertUInt64ToString(val, temp); + s += name; + s += ": "; + s += temp; +} + +void PrintSize_bytes_Smart(AString &s, UInt64 val); +void Print_DirItemsStat(AString &s, const CDirItemsStat &st); +void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); + +HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st) +{ + if (NeedPercents()) + { + _percent.ClosePrint(true); + _percent.ClearCurState(); + } + + if (_so) + { + AString s; + Print_DirItemsStat(s, st); + *_so << s << endl << endl; + } + return S_OK; +} + +static const char * const k_StdOut_ArcName = "StdOut"; + +HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name) +{ + if (_so) + { + *_so << kOpenArchiveMessage; + if (name) + *_so << name; + else + *_so << k_StdOut_ArcName; + *_so << endl; + } + return S_OK; +} + +HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating) +{ + if (NeedPercents()) + _percent.ClosePrint(true); + + _percent.ClearCurState(); + NumNonOpenFiles = 0; + + if (_so) + { + *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage); + if (name) + _so->NormalizePrint_wstr_Path(name); + else + *_so << k_StdOut_ArcName; + *_so << endl << endl; + } + return S_OK; +} + +HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st) +{ + ClosePercents2(); + + if (_so) + { + AString s; + // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files); + PrintPropPair(s, "Files read from disk", _percent.Files - NumNonOpenFiles); + s.Add_LF(); + s += "Archive size: "; + PrintSize_bytes_Smart(s, st.OutArcFileSize); + s.Add_LF(); + if (st.IsMultiVolMode) + { + s += "Volumes: "; + s.Add_UInt32(st.NumVolumes); + s.Add_LF(); + } + *_so << endl; + *_so << s; + // *_so << endl; + } + + return S_OK; +} + +HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size) +{ + if (_so) + { + *_so << "Write SFX: "; + *_so << name; + AString s (" : "); + PrintSize_bytes_Smart(s, size); + *_so << s << endl; + } + return S_OK; +} + + + +HRESULT CUpdateCallbackConsole::MoveArc_UpdateStatus() +{ + if (NeedPercents()) + { + AString &s = _percent.Command; + s = " : "; + s.Add_UInt64(_arcMoving_percents); + s.Add_Char('%'); + const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1); + if (_arcMoving_current != 0 || totalDefined) + { + s += " : "; + s.Add_UInt64(_arcMoving_current >> 20); + s += " MiB"; + } + if (totalDefined) + { + s += " / "; + s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20); + s += " MiB"; + } + s += " : temporary archive moving ..."; + _percent.Print(); + } + + // we ignore single Ctrl-C, if (_arcMoving_updateMode) mode + // because we want to get good final archive instead of temp archive. + if (NConsoleClose::g_BreakCounter == 1 && _arcMoving_updateMode) + return S_OK; + return CheckBreak(); +} + + +HRESULT CUpdateCallbackConsole::MoveArc_Start( + const wchar_t *srcTempPath, const wchar_t *destFinalPath, + UInt64 size, Int32 updateMode) +{ +#if 0 // 1 : for debug + if (LogLevel > 0 && _so) + { + ClosePercents_for_so(); + *_so << "Temporary archive moving:" << endl; + _tempU = srcTempPath; + _so->Normalize_UString_Path(_tempU); + _so->PrintUString(_tempU, _tempA); + *_so << endl; + _tempU = destFinalPath; + _so->Normalize_UString_Path(_tempU); + _so->PrintUString(_tempU, _tempA); + *_so << endl; + } +#else + UNUSED_VAR(srcTempPath) + UNUSED_VAR(destFinalPath) +#endif + + _arcMoving_updateMode = updateMode; + _arcMoving_total = size; + _arcMoving_current = 0; + _arcMoving_percents = 0; + return MoveArc_UpdateStatus(); +} + + +HRESULT CUpdateCallbackConsole::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize) +{ +#if 0 // 1 : for debug + if (_so) + { + ClosePercents_for_so(); + *_so << totalSize << " : " << currentSize << endl; + } +#endif + + UInt64 percents = 0; + if (totalSize != 0) + { + if (totalSize < ((UInt64)1 << 57)) + percents = currentSize * 100 / totalSize; + else + percents = currentSize / (totalSize / 100); + } + +#ifdef _WIN32 + // Sleep(300); // for debug +#endif + // totalSize = (UInt64)(Int64)-1; // for debug + + if (percents == _arcMoving_percents) + return CheckBreak(); + _arcMoving_current = currentSize; + _arcMoving_total = totalSize; + _arcMoving_percents = percents; + return MoveArc_UpdateStatus(); +} + + +HRESULT CUpdateCallbackConsole::MoveArc_Finish() +{ + // _arcMoving_percents = 0; + if (NeedPercents()) + { + _percent.Command.Empty(); + _percent.Print(); + } + // it can return delayed user break (E_ABORT) status, + // if it ignored single CTRL+C in MoveArc_Progress(). + return CheckBreak(); +} + + + +HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */) +{ + if (LogLevel > 0 && _so) + { + ClosePercents_for_so(); + + if (!DeleteMessageWasShown) + { + if (_so) + *_so << endl << ": Removing files after including to archive" << endl; + } + + { + { + _tempA = "Removing"; + _tempA.Add_Space(); + *_so << _tempA; + _tempU = fs2us(path); + _so->Normalize_UString_Path(_tempU); + _so->PrintUString(_tempU, _tempA); + *_so << endl; + if (NeedFlush) + _so->Flush(); + } + } + } + + if (!DeleteMessageWasShown) + { + if (NeedPercents()) + { + _percent.ClearCurState(); + } + DeleteMessageWasShown = true; + } + else + { + _percent.Files++; + } + + if (NeedPercents()) + { + // if (!FullLog) + { + _percent.Command = "Removing"; + _percent.FileName = fs2us(path); + } + _percent.Print(); + } + + return S_OK; +} + + +HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving() +{ + ClosePercents2(); + if (_so && DeleteMessageWasShown) + *_so << endl; + return S_OK; +} + +HRESULT CUpdateCallbackConsole::CheckBreak() +{ + return CheckBreak2(); +} + +/* +HRESULT CUpdateCallbackConsole::Finalize() +{ + // MT_LOCK + return S_OK; +} +*/ + + +void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name) +{ + AString s; + Print_DirItemsStat2(s, stat); + *_so << name << ": " << s << endl; +} + +HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat) +{ + if (_so) + { + ClosePercents_for_so(); + if (!stat.DeleteData.IsEmpty()) + { + *_so << endl; + PrintToDoStat(_so, stat.DeleteData, "Delete data from archive"); + } + if (!stat.OldData.IsEmpty()) + PrintToDoStat(_so, stat.OldData, "Keep old data in archive"); + // if (!stat.NewData.IsEmpty()) + { + PrintToDoStat(_so, stat.NewData, "Add new data to archive"); + } + *_so << endl; + } + return S_OK; +} + +HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size) +{ + MT_LOCK + if (NeedPercents()) + { + _percent.Total = size; + _percent.Print(); + } + return S_OK; +} + +HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue) +{ + MT_LOCK + if (completeValue) + { + if (NeedPercents()) + { + _percent.Completed = *completeValue; + _percent.Print(); + } + } + return CheckBreak2(); +} + +HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */) +{ + return CheckBreak2(); +} + +HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog) +{ + MT_LOCK + + bool show2 = (showInLog && _so); + + if (show2) + { + ClosePercents_for_so(); + + _tempA = command; + if (name) + _tempA.Add_Space(); + *_so << _tempA; + + _tempU.Empty(); + if (name) + { + _tempU = name; + if (isDir) + NWindows::NFile::NName::NormalizeDirPathPrefix(_tempU); + _so->Normalize_UString_Path(_tempU); + } + _so->PrintUString(_tempU, _tempA); + *_so << endl; + if (NeedFlush) + _so->Flush(); + } + + if (NeedPercents()) + { + if (PercentsNameLevel >= 1) + { + _percent.FileName.Empty(); + _percent.Command.Empty(); + if (PercentsNameLevel > 1 || !show2) + { + _percent.Command = command; + if (name) + _percent.FileName = name; + } + } + _percent.Print(); + } + + return CheckBreak2(); +} + + +/* +void CCallbackConsoleBase::PrintInfoLine(const UString &s) +{ + if (LogLevel < 1000) + return; + + MT_LOCK + + const bool show2 = (_so != NULL); + + if (show2) + { + ClosePercents_for_so(); + _so->PrintUString(s, _tempA); + *_so << endl; + if (NeedFlush) + _so->Flush(); + } +} +*/ + +HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) +{ + if (StdOutMode) + return S_OK; + + if (!name || name[0] == 0) + name = kEmptyFileAlias; + + unsigned requiredLevel = 1; + + const char *s; + if (mode == NUpdateNotifyOp::kAdd || + mode == NUpdateNotifyOp::kUpdate) + { + if (isAnti) + s = "Anti"; + else if (mode == NUpdateNotifyOp::kAdd) + s = "+"; + else + s = "U"; + } + else + { + requiredLevel = 3; + if (mode == NUpdateNotifyOp::kAnalyze) + s = "A"; + else + s = "Reading"; + } + + return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); +} + +HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError) +{ + return OpenFileError_Base(path, systemError); +} + +HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError) +{ + return ReadingFileError_Base(path, systemError); +} + +HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */) +{ + MT_LOCK + _percent.Files++; + /* + if (opRes != NArchive::NUpdate::NOperationResult::kOK) + { + if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged) + { + CommonError("Input file changed"); + } + } + */ + return S_OK; +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); + +HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) +{ + // if (StdOutMode) return S_OK; + + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + ClosePercents2(); + + if (_se) + { + if (_so) + _so->Flush(); + + AString s; + SetExtractErrorMessage(opRes, isEncrypted, s); + *_se << s << " : " << endl; + _se->NormalizePrint_wstr_Path(name); + *_se << endl << endl; + _se->Flush(); + } + return S_OK; + } + return S_OK; +} + + +HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) +{ + // if (StdOutMode) return S_OK; + + char temp[16]; + const char *s; + + unsigned requiredLevel = 1; + + switch (op) + { + case NUpdateNotifyOp::kAdd: s = "+"; break; + case NUpdateNotifyOp::kUpdate: s = "U"; break; + case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break; + case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break; + case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break; + case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break; + case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break; + case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break; + case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break; + // case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break; + default: + { + temp[0] = 'o'; + temp[1] = 'p'; + ConvertUInt64ToString(op, temp + 2); + s = temp; + } + } + + return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); +} + +/* +HRESULT CUpdateCallbackConsole::SetPassword(const UString & + #ifndef Z7_NO_CRYPTO + password + #endif + ) +{ + #ifndef Z7_NO_CRYPTO + PasswordIsDefined = true; + Password = password; + #endif + return S_OK; +} +*/ + +HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) +{ + COM_TRY_BEGIN + + *password = NULL; + + #ifdef Z7_NO_CRYPTO + + *passwordIsDefined = false; + return S_OK; + + #else + + if (!PasswordIsDefined) + { + if (AskPassword) + { + RINOK(GetPassword_HRESULT(_so, Password)) + PasswordIsDefined = true; + } + } + *passwordIsDefined = BoolToInt(PasswordIsDefined); + return StringToBstr(Password, password); + + #endif + + COM_TRY_END +} + +HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + + *password = NULL; + + #ifdef Z7_NO_CRYPTO + + return E_NOTIMPL; + + #else + + if (!PasswordIsDefined) + { + { + RINOK(GetPassword_HRESULT(_so, Password)) + PasswordIsDefined = true; + } + } + return StringToBstr(Password, password); + + #endif + COM_TRY_END +} + +HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir) +{ + if (StdOutMode) + return S_OK; + + if (LogLevel > 7) + { + if (!name || name[0] == 0) + name = kEmptyFileAlias; + return PrintProgress(name, isDir, "D", true); + } + return S_OK; +} + +/* +void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU); + +static void GetPropName(PROPID propID, UString &nameU) +{ + AString nameA; + GetPropName(propID, NULL, nameA, nameU); + // if (!nameA.IsEmpty()) + nameU = nameA; +} + + +static void AddPropNamePrefix(UString &s, PROPID propID) +{ + UString name; + GetPropName(propID, name); + s += name; + s += " = "; +} + +void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value) +{ + AddPropNamePrefix(s, propID); + { + UString dest; + const int level = 9; // we show up to ns precision level + ConvertPropertyToString2(dest, *value, propID, level); + s += dest; + } + PrintInfoLine(s); +} + +static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index) +{ + if (indexType == NArchive::NEventIndexType::kArcProp) + { + } + else + { + if (indexType == NArchive::NEventIndexType::kBlockIndex) + { + s += "#"; + } + else if (indexType == NArchive::NEventIndexType::kOutArcIndex) + { + } + else + { + s += "indexType_"; + s.Add_UInt32(indexType); + s.Add_Space(); + } + s.Add_UInt32(index); + } + s += ": "; +} + +HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) +{ + UString s; + Add_IndexType_Index(s, indexType, index); + PrintPropInfo(s, propID, value); + return S_OK; +} + +static inline char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10))); +} + +static void AddHexToString(UString &dest, const Byte *data, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + { + Byte b = data[i]; + dest += GetHex((Byte)((b >> 4) & 0xF)); + dest += GetHex((Byte)(b & 0xF)); + } +} + +void HashHexToString(char *dest, const Byte *data, UInt32 size); + +HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index, + PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) +{ + UString s; + propType = propType; + Add_IndexType_Index(s, indexType, index); + AddPropNamePrefix(s, propID); + if (propID == kpidChecksum) + { + char temp[k_HashCalc_DigestSize_Max + 8]; + HashHexToString(temp, (const Byte *)data, dataSize); + s += temp; + } + else + AddHexToString(s, (const Byte *)data, dataSize); + PrintInfoLine(s); + return S_OK; +} + +HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) +{ + UString s; + Add_IndexType_Index(s, indexType, index); + s += "finished"; + if (opRes != NArchive::NUpdate::NOperationResult::kOK) + { + s += ": "; + s.Add_UInt32(opRes); + } + PrintInfoLine(s); + return S_OK; +} +*/ diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h index 4a8cd5241..a3863711c 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h @@ -1,138 +1,148 @@ -// UpdateCallbackConsole.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H -#define ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H - -#include "../../../Common/StdOutStream.h" - -#include "../Common/Update.h" - -#include "PercentPrinter.h" - -struct CErrorPathCodes -{ - FStringVector Paths; - CRecordVector Codes; - - void AddError(const FString &path, DWORD systemError) - { - Paths.Add(path); - Codes.Add(systemError); - } - void Clear() - { - Paths.Clear(); - Codes.Clear(); - } -}; - - -class CCallbackConsoleBase -{ -protected: - CPercentPrinter _percent; - - CStdOutStream *_so; - CStdOutStream *_se; - - void CommonError(const FString &path, DWORD systemError, bool isWarning); - // void CommonError(const char *message); - - HRESULT ScanError_Base(const FString &path, DWORD systemError); - HRESULT OpenFileError_Base(const FString &name, DWORD systemError); - HRESULT ReadingFileError_Base(const FString &name, DWORD systemError); - -public: - bool NeedPercents() const { return _percent._so != NULL; } - - bool StdOutMode; - - bool NeedFlush; - unsigned PercentsNameLevel; - unsigned LogLevel; - - AString _tempA; - UString _tempU; - - CCallbackConsoleBase(): - StdOutMode(false), - NeedFlush(false), - PercentsNameLevel(1), - LogLevel(0), - NumNonOpenFiles(0) - {} - - void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } - - void Init( - CStdOutStream *outStream, - CStdOutStream *errorStream, - CStdOutStream *percentStream, - bool disablePercents) - { - FailedFiles.Clear(); - - _so = outStream; - _se = errorStream; - _percent._so = percentStream; - _percent.DisablePrint = disablePercents; - } - - void ClosePercents2() - { - if (NeedPercents()) - _percent.ClosePrint(true); - } - - void ClosePercents_for_so() - { - if (NeedPercents() && _so == _percent._so) - _percent.ClosePrint(false); - } - - CErrorPathCodes FailedFiles; - CErrorPathCodes ScanErrors; - UInt64 NumNonOpenFiles; - - HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog); - - // void PrintInfoLine(const UString &s); - // void PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value); -}; - - -class CUpdateCallbackConsole Z7_final: - public IUpdateCallbackUI2, - public CCallbackConsoleBase -{ - // void PrintPropPair(const char *name, const wchar_t *val); - Z7_IFACE_IMP(IUpdateCallbackUI) - Z7_IFACE_IMP(IDirItemsCallback) - Z7_IFACE_IMP(IUpdateCallbackUI2) -public: - bool DeleteMessageWasShown; - - #ifndef Z7_NO_CRYPTO - bool PasswordIsDefined; - bool AskPassword; - UString Password; - #endif - - CUpdateCallbackConsole(): - DeleteMessageWasShown(false) - #ifndef Z7_NO_CRYPTO - , PasswordIsDefined(false) - , AskPassword(false) - #endif - {} - - /* - void Init(CStdOutStream *outStream) - { - CCallbackConsoleBase::Init(outStream); - } - */ - // ~CUpdateCallbackConsole() { if (NeedPercents()) _percent.ClosePrint(); } -}; - -#endif +// UpdateCallbackConsole.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H +#define ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H + +#include "../../../Common/StdOutStream.h" + +#include "../Common/Update.h" + +#include "PercentPrinter.h" + +struct CErrorPathCodes +{ + FStringVector Paths; + CRecordVector Codes; + + void AddError(const FString &path, DWORD systemError) + { + Paths.Add(path); + Codes.Add(systemError); + } + void Clear() + { + Paths.Clear(); + Codes.Clear(); + } +}; + + +class CCallbackConsoleBase +{ + void CommonError(const FString &path, DWORD systemError, bool isWarning); + +protected: + CStdOutStream *_so; + CStdOutStream *_se; + + HRESULT ScanError_Base(const FString &path, DWORD systemError); + HRESULT OpenFileError_Base(const FString &name, DWORD systemError); + HRESULT ReadingFileError_Base(const FString &name, DWORD systemError); + +public: + bool StdOutMode; + bool NeedFlush; + unsigned PercentsNameLevel; + unsigned LogLevel; + +protected: + AString _tempA; + UString _tempU; + CPercentPrinter _percent; + +public: + CErrorPathCodes FailedFiles; + CErrorPathCodes ScanErrors; + UInt64 NumNonOpenFiles; + + CCallbackConsoleBase(): + StdOutMode(false), + NeedFlush(false), + PercentsNameLevel(1), + LogLevel(0), + NumNonOpenFiles(0) + {} + + bool NeedPercents() const { return _percent._so != NULL; } + void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; } + + void Init( + CStdOutStream *outStream, + CStdOutStream *errorStream, + CStdOutStream *percentStream, + bool disablePercents) + { + FailedFiles.Clear(); + + _so = outStream; + _se = errorStream; + _percent._so = percentStream; + _percent.DisablePrint = disablePercents; + } + + void ClosePercents2() + { + if (NeedPercents()) + _percent.ClosePrint(true); + } + + void ClosePercents_for_so() + { + if (NeedPercents() && _so == _percent._so) + _percent.ClosePrint(false); + } + + HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog); + + // void PrintInfoLine(const UString &s); + // void PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value); +}; + + +class CUpdateCallbackConsole Z7_final: + public IUpdateCallbackUI2, + public CCallbackConsoleBase +{ + // void PrintPropPair(const char *name, const wchar_t *val); + Z7_IFACE_IMP(IUpdateCallbackUI) + Z7_IFACE_IMP(IDirItemsCallback) + Z7_IFACE_IMP(IUpdateCallbackUI2) + + HRESULT MoveArc_UpdateStatus(); + + UInt64 _arcMoving_total; + UInt64 _arcMoving_current; + UInt64 _arcMoving_percents; + Int32 _arcMoving_updateMode; + +public: + bool DeleteMessageWasShown; + + #ifndef Z7_NO_CRYPTO + bool PasswordIsDefined; + bool AskPassword; + UString Password; + #endif + + CUpdateCallbackConsole(): + _arcMoving_total(0) + , _arcMoving_current(0) + , _arcMoving_percents(0) + , _arcMoving_updateMode(0) + , DeleteMessageWasShown(false) + #ifndef Z7_NO_CRYPTO + , PasswordIsDefined(false) + , AskPassword(false) + #endif + {} + + /* + void Init(CStdOutStream *outStream) + { + CCallbackConsoleBase::Init(outStream); + } + */ + // ~CUpdateCallbackConsole() { if (NeedPercents()) _percent.ClosePrint(); } +}; + +#endif diff --git a/CPP/7zip/UI/Console/UserInputUtils.cpp b/CPP/7zip/UI/Console/UserInputUtils.cpp index 6c3c85a50..2adf9dfed 100644 --- a/CPP/7zip/UI/Console/UserInputUtils.cpp +++ b/CPP/7zip/UI/Console/UserInputUtils.cpp @@ -1,118 +1,118 @@ -// UserInputUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/StdInStream.h" -#include "../../../Common/StringConvert.h" - -#include "UserInputUtils.h" - -static const char kYes = 'y'; -static const char kNo = 'n'; -static const char kYesAll = 'a'; -static const char kNoAll = 's'; -static const char kAutoRenameAll = 'u'; -static const char kQuit = 'q'; - -static const char * const kFirstQuestionMessage = "? "; -static const char * const kHelpQuestionMessage = - "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? "; - -// return true if pressed Quite; - -NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream) -{ - if (outStream) - *outStream << kFirstQuestionMessage; - for (;;) - { - if (outStream) - { - *outStream << kHelpQuestionMessage; - outStream->Flush(); - } - AString scannedString; - if (!g_StdIn.ScanAStringUntilNewLine(scannedString)) - return NUserAnswerMode::kError; - if (g_StdIn.Error()) - return NUserAnswerMode::kError; - scannedString.Trim(); - if (scannedString.IsEmpty() && g_StdIn.Eof()) - return NUserAnswerMode::kEof; - - if (scannedString.Len() == 1) - switch (::MyCharLower_Ascii(scannedString[0])) - { - case kYes: return NUserAnswerMode::kYes; - case kNo: return NUserAnswerMode::kNo; - case kYesAll: return NUserAnswerMode::kYesAll; - case kNoAll: return NUserAnswerMode::kNoAll; - case kAutoRenameAll: return NUserAnswerMode::kAutoRenameAll; - case kQuit: return NUserAnswerMode::kQuit; - default: break; - } - } -} - -#ifdef _WIN32 -#ifndef UNDER_CE -#define MY_DISABLE_ECHO -#endif -#endif - -static bool GetPassword(CStdOutStream *outStream, UString &psw) -{ - if (outStream) - { - *outStream << "\nEnter password" - #ifdef MY_DISABLE_ECHO - " (will not be echoed)" - #endif - ":"; - outStream->Flush(); - } - - #ifdef MY_DISABLE_ECHO - - const HANDLE console = GetStdHandle(STD_INPUT_HANDLE); - - /* - GetStdHandle() returns - INVALID_HANDLE_VALUE: If the function fails. - NULL : If an application does not have associated standard handles, - such as a service running on an interactive desktop, - and has not redirected them. */ - bool wasChanged = false; - DWORD mode = 0; - if (console != INVALID_HANDLE_VALUE && console != NULL) - if (GetConsoleMode(console, &mode)) - wasChanged = (SetConsoleMode(console, mode & ~(DWORD)ENABLE_ECHO_INPUT) != 0); - const bool res = g_StdIn.ScanUStringUntilNewLine(psw); - if (wasChanged) - SetConsoleMode(console, mode); - - #else - - const bool res = g_StdIn.ScanUStringUntilNewLine(psw); - - #endif - - if (outStream) - { - *outStream << endl; - outStream->Flush(); - } - - return res; -} - -HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw) -{ - if (!GetPassword(outStream, psw)) - return E_INVALIDARG; - if (g_StdIn.Error()) - return E_FAIL; - if (g_StdIn.Eof() && psw.IsEmpty()) - return E_ABORT; - return S_OK; -} +// UserInputUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/StdInStream.h" +#include "../../../Common/StringConvert.h" + +#include "UserInputUtils.h" + +static const char kYes = 'y'; +static const char kNo = 'n'; +static const char kYesAll = 'a'; +static const char kNoAll = 's'; +static const char kAutoRenameAll = 'u'; +static const char kQuit = 'q'; + +static const char * const kFirstQuestionMessage = "? "; +static const char * const kHelpQuestionMessage = + "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? "; + +// return true if pressed Quite; + +NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream) +{ + if (outStream) + *outStream << kFirstQuestionMessage; + for (;;) + { + if (outStream) + { + *outStream << kHelpQuestionMessage; + outStream->Flush(); + } + AString scannedString; + if (!g_StdIn.ScanAStringUntilNewLine(scannedString)) + return NUserAnswerMode::kError; + if (g_StdIn.Error()) + return NUserAnswerMode::kError; + scannedString.Trim(); + if (scannedString.IsEmpty() && g_StdIn.Eof()) + return NUserAnswerMode::kEof; + + if (scannedString.Len() == 1) + switch (::MyCharLower_Ascii(scannedString[0])) + { + case kYes: return NUserAnswerMode::kYes; + case kNo: return NUserAnswerMode::kNo; + case kYesAll: return NUserAnswerMode::kYesAll; + case kNoAll: return NUserAnswerMode::kNoAll; + case kAutoRenameAll: return NUserAnswerMode::kAutoRenameAll; + case kQuit: return NUserAnswerMode::kQuit; + default: break; + } + } +} + +#ifdef _WIN32 +#ifndef UNDER_CE +#define MY_DISABLE_ECHO +#endif +#endif + +static bool GetPassword(CStdOutStream *outStream, UString &psw) +{ + if (outStream) + { + *outStream << "\nEnter password" + #ifdef MY_DISABLE_ECHO + " (will not be echoed)" + #endif + ":"; + outStream->Flush(); + } + + #ifdef MY_DISABLE_ECHO + + const HANDLE console = GetStdHandle(STD_INPUT_HANDLE); + + /* + GetStdHandle() returns + INVALID_HANDLE_VALUE: If the function fails. + NULL : If an application does not have associated standard handles, + such as a service running on an interactive desktop, + and has not redirected them. */ + bool wasChanged = false; + DWORD mode = 0; + if (console != INVALID_HANDLE_VALUE && console != NULL) + if (GetConsoleMode(console, &mode)) + wasChanged = (SetConsoleMode(console, mode & ~(DWORD)ENABLE_ECHO_INPUT) != 0); + const bool res = g_StdIn.ScanUStringUntilNewLine(psw); + if (wasChanged) + SetConsoleMode(console, mode); + + #else + + const bool res = g_StdIn.ScanUStringUntilNewLine(psw); + + #endif + + if (outStream) + { + *outStream << endl; + outStream->Flush(); + } + + return res; +} + +HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw) +{ + if (!GetPassword(outStream, psw)) + return E_INVALIDARG; + if (g_StdIn.Error()) + return E_FAIL; + if (g_StdIn.Eof() && psw.IsEmpty()) + return E_ABORT; + return S_OK; +} diff --git a/CPP/7zip/UI/Console/UserInputUtils.h b/CPP/7zip/UI/Console/UserInputUtils.h index e444c6f1c..695a3e66d 100644 --- a/CPP/7zip/UI/Console/UserInputUtils.h +++ b/CPP/7zip/UI/Console/UserInputUtils.h @@ -1,27 +1,27 @@ -// UserInputUtils.h - -#ifndef ZIP7_INC_USER_INPUT_UTILS_H -#define ZIP7_INC_USER_INPUT_UTILS_H - -#include "../../../Common/StdOutStream.h" - -namespace NUserAnswerMode { - -enum EEnum -{ - kYes, - kNo, - kYesAll, - kNoAll, - kAutoRenameAll, - kQuit, - kEof, - kError -}; -} - -NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream); -// bool GetPassword(CStdOutStream *outStream, UString &psw); -HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw); - -#endif +// UserInputUtils.h + +#ifndef ZIP7_INC_USER_INPUT_UTILS_H +#define ZIP7_INC_USER_INPUT_UTILS_H + +#include "../../../Common/StdOutStream.h" + +namespace NUserAnswerMode { + +enum EEnum +{ + kYes, + kNo, + kYesAll, + kNoAll, + kAutoRenameAll, + kQuit, + kEof, + kError +}; +} + +NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream); +// bool GetPassword(CStdOutStream *outStream, UString &psw); +HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw); + +#endif diff --git a/CPP/7zip/UI/Console/makefile b/CPP/7zip/UI/Console/makefile index d2927262f..a20b0cc0b 100644 --- a/CPP/7zip/UI/Console/makefile +++ b/CPP/7zip/UI/Console/makefile @@ -1,68 +1,68 @@ -PROG = 7z.exe -CFLAGS = $(CFLAGS) \ - -DZ7_EXTERNAL_CODECS \ - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\ListFileUtils.obj \ - $O\NewHandler.obj \ - $O\StdInStream.obj \ - $O\StdOutStream.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\MyVector.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\FileSystem.obj \ - $O\MemoryLock.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Registry.obj \ - $O\System.obj \ - $O\SystemInfo.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodProps.obj \ - $O\MultiOutStream.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - -AR_COMMON_OBJS = \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - -COMPRESS_OBJS = \ - $O\CopyCoder.obj \ - -C_OBJS = $(C_OBJS) \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" -!include "Console.mak" - -!include "../../7zip.mak" +PROG = 7z.exe +CFLAGS = $(CFLAGS) \ + -DZ7_EXTERNAL_CODECS \ + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\ListFileUtils.obj \ + $O\NewHandler.obj \ + $O\StdInStream.obj \ + $O\StdOutStream.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\MyVector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\FileSystem.obj \ + $O\MemoryLock.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Registry.obj \ + $O\System.obj \ + $O\SystemInfo.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodProps.obj \ + $O\MultiOutStream.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + +AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + +COMPRESS_OBJS = \ + $O\CopyCoder.obj \ + +C_OBJS = $(C_OBJS) \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" +!include "Console.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/Console/makefile.gcc b/CPP/7zip/UI/Console/makefile.gcc index 6b69b9ea9..da995a77d 100644 --- a/CPP/7zip/UI/Console/makefile.gcc +++ b/CPP/7zip/UI/Console/makefile.gcc @@ -1,187 +1,187 @@ -PROG = 7z -IS_NOT_STANDALONE = 1 - -# IS_X64 = 1 -# USE_ASM = 1 -# ST_MODE = 1 - - -LOCAL_FLAGS_ST = -MT_OBJS = - -ifdef SystemDrive -IS_MINGW = 1 -else -ifdef SYSTEMDRIVE -# ifdef OS -IS_MINGW = 1 -endif -endif - -ifdef ST_MODE - -LOCAL_FLAGS_ST = -DZ7_ST - -ifdef IS_MINGW -MT_OBJS = \ - $O/Threads.o \ - -endif - -else - -MT_OBJS = \ - $O/Synchronization.o \ - $O/Threads.o \ - -endif - - - -LOCAL_FLAGS_SYS= - -ifdef IS_MINGW - -LOCAL_FLAGS_SYS = \ - -DZ7_DEVICE_FILE \ - -# -DZ7_LARGE_PAGES -# -DZ7_LONG_PATH - -SYS_OBJS = \ - $O/FileSystem.o \ - $O/Registry.o \ - $O/MemoryLock.o \ - $O/DllSecur.o \ - $O/resource.o \ - -else - -SYS_OBJS = \ - $O/MyWindows.o \ - -endif - - - -LOCAL_FLAGS = \ - $(LOCAL_FLAGS_SYS) \ - $(LOCAL_FLAGS_ST) \ - -DZ7_EXTERNAL_CODECS \ - - - -CONSOLE_OBJS = \ - $O/BenchCon.o \ - $O/ConsoleClose.o \ - $O/ExtractCallbackConsole.o \ - $O/HashCon.o \ - $O/List.o \ - $O/Main.o \ - $O/MainAr.o \ - $O/OpenCallbackConsole.o \ - $O/PercentPrinter.o \ - $O/UpdateCallbackConsole.o \ - $O/UserInputUtils.o \ - -UI_COMMON_OBJS = \ - $O/ArchiveCommandLine.o \ - $O/ArchiveExtractCallback.o \ - $O/ArchiveOpenCallback.o \ - $O/Bench.o \ - $O/DefaultName.o \ - $O/EnumDirItems.o \ - $O/Extract.o \ - $O/ExtractingFilePath.o \ - $O/HashCalc.o \ - $O/LoadCodecs.o \ - $O/OpenArchive.o \ - $O/PropIDUtils.o \ - $O/SetProperties.o \ - $O/SortUtils.o \ - $O/TempFiles.o \ - $O/Update.o \ - $O/UpdateAction.o \ - $O/UpdateCallback.o \ - $O/UpdatePair.o \ - $O/UpdateProduce.o \ - -COMMON_OBJS = \ - $O/CommandLineParser.o \ - $O/CRC.o \ - $O/CrcReg.o \ - $O/DynLimBuf.o \ - $O/IntToString.o \ - $O/ListFileUtils.o \ - $O/NewHandler.o \ - $O/StdInStream.o \ - $O/StdOutStream.o \ - $O/MyString.o \ - $O/StringConvert.o \ - $O/StringToInt.o \ - $O/UTFConvert.o \ - $O/MyVector.o \ - $O/Wildcard.o \ - -WIN_OBJS = \ - $O/DLL.o \ - $O/ErrorMsg.o \ - $O/FileDir.o \ - $O/FileFind.o \ - $O/FileIO.o \ - $O/FileLink.o \ - $O/FileName.o \ - $O/PropVariant.o \ - $O/PropVariantConv.o \ - $O/System.o \ - $O/SystemInfo.o \ - $O/TimeUtils.o \ - -7ZIP_COMMON_OBJS = \ - $O/CreateCoder.o \ - $O/CWrappers.o \ - $O/FilePathAutoRename.o \ - $O/FileStreams.o \ - $O/InBuffer.o \ - $O/InOutTempBuffer.o \ - $O/FilterCoder.o \ - $O/LimitedStreams.o \ - $O/MethodId.o \ - $O/MethodProps.o \ - $O/MultiOutStream.o \ - $O/OffsetStream.o \ - $O/OutBuffer.o \ - $O/ProgressUtils.o \ - $O/PropId.o \ - $O/StreamObjects.o \ - $O/StreamUtils.o \ - $O/UniqBlocks.o \ - -COMPRESS_OBJS = \ - $O/CopyCoder.o \ - -AR_COMMON_OBJS = \ - $O/ItemNameUtils.o \ - -C_OBJS = \ - $O/Alloc.o \ - $O/CpuArch.o \ - $O/Sort.o \ - $O/7zCrc.o \ - $O/7zCrcOpt.o \ - - -OBJS = \ - $(C_OBJS) \ - $(MT_OBJS) \ - $(COMMON_OBJS) \ - $(WIN_OBJS) \ - $(SYS_OBJS) \ - $(COMPRESS_OBJS) \ - $(AR_COMMON_OBJS) \ - $(7ZIP_COMMON_OBJS) \ - $(UI_COMMON_OBJS) \ - $(CONSOLE_OBJS) \ - - -include ../../7zip_gcc.mak +PROG = 7z +IS_NOT_STANDALONE = 1 + +# IS_X64 = 1 +# USE_ASM = 1 +# ST_MODE = 1 + + +LOCAL_FLAGS_ST = +MT_OBJS = + +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef ST_MODE + +LOCAL_FLAGS_ST = -DZ7_ST + +ifdef IS_MINGW +MT_OBJS = \ + $O/Threads.o \ + +endif + +else + +MT_OBJS = \ + $O/Synchronization.o \ + $O/Threads.o \ + +endif + + + +LOCAL_FLAGS_SYS= + +ifdef IS_MINGW + +LOCAL_FLAGS_SYS = \ + -DZ7_DEVICE_FILE \ + +# -DZ7_LARGE_PAGES +# -DZ7_LONG_PATH + +SYS_OBJS = \ + $O/FileSystem.o \ + $O/Registry.o \ + $O/MemoryLock.o \ + $O/DllSecur.o \ + $O/resource.o \ + +else + +SYS_OBJS = \ + $O/MyWindows.o \ + +endif + + + +LOCAL_FLAGS = \ + $(LOCAL_FLAGS_SYS) \ + $(LOCAL_FLAGS_ST) \ + -DZ7_EXTERNAL_CODECS \ + + + +CONSOLE_OBJS = \ + $O/BenchCon.o \ + $O/ConsoleClose.o \ + $O/ExtractCallbackConsole.o \ + $O/HashCon.o \ + $O/List.o \ + $O/Main.o \ + $O/MainAr.o \ + $O/OpenCallbackConsole.o \ + $O/PercentPrinter.o \ + $O/UpdateCallbackConsole.o \ + $O/UserInputUtils.o \ + +UI_COMMON_OBJS = \ + $O/ArchiveCommandLine.o \ + $O/ArchiveExtractCallback.o \ + $O/ArchiveOpenCallback.o \ + $O/Bench.o \ + $O/DefaultName.o \ + $O/EnumDirItems.o \ + $O/Extract.o \ + $O/ExtractingFilePath.o \ + $O/HashCalc.o \ + $O/LoadCodecs.o \ + $O/OpenArchive.o \ + $O/PropIDUtils.o \ + $O/SetProperties.o \ + $O/SortUtils.o \ + $O/TempFiles.o \ + $O/Update.o \ + $O/UpdateAction.o \ + $O/UpdateCallback.o \ + $O/UpdatePair.o \ + $O/UpdateProduce.o \ + +COMMON_OBJS = \ + $O/CommandLineParser.o \ + $O/CRC.o \ + $O/CrcReg.o \ + $O/DynLimBuf.o \ + $O/IntToString.o \ + $O/ListFileUtils.o \ + $O/NewHandler.o \ + $O/StdInStream.o \ + $O/StdOutStream.o \ + $O/MyString.o \ + $O/StringConvert.o \ + $O/StringToInt.o \ + $O/UTFConvert.o \ + $O/MyVector.o \ + $O/Wildcard.o \ + +WIN_OBJS = \ + $O/DLL.o \ + $O/ErrorMsg.o \ + $O/FileDir.o \ + $O/FileFind.o \ + $O/FileIO.o \ + $O/FileLink.o \ + $O/FileName.o \ + $O/PropVariant.o \ + $O/PropVariantConv.o \ + $O/System.o \ + $O/SystemInfo.o \ + $O/TimeUtils.o \ + +7ZIP_COMMON_OBJS = \ + $O/CreateCoder.o \ + $O/CWrappers.o \ + $O/FilePathAutoRename.o \ + $O/FileStreams.o \ + $O/InBuffer.o \ + $O/InOutTempBuffer.o \ + $O/FilterCoder.o \ + $O/LimitedStreams.o \ + $O/MethodId.o \ + $O/MethodProps.o \ + $O/MultiOutStream.o \ + $O/OffsetStream.o \ + $O/OutBuffer.o \ + $O/ProgressUtils.o \ + $O/PropId.o \ + $O/StreamObjects.o \ + $O/StreamUtils.o \ + $O/UniqBlocks.o \ + +COMPRESS_OBJS = \ + $O/CopyCoder.o \ + +AR_COMMON_OBJS = \ + $O/ItemNameUtils.o \ + +C_OBJS = \ + $O/Alloc.o \ + $O/CpuArch.o \ + $O/Sort.o \ + $O/7zCrc.o \ + $O/7zCrcOpt.o \ + + +OBJS = \ + $(C_OBJS) \ + $(MT_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(SYS_OBJS) \ + $(COMPRESS_OBJS) \ + $(AR_COMMON_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(UI_COMMON_OBJS) \ + $(CONSOLE_OBJS) \ + + +include ../../7zip_gcc.mak diff --git a/CPP/7zip/UI/Console/resource.rc b/CPP/7zip/UI/Console/resource.rc index 8d721f509..414427fb2 100644 --- a/CPP/7zip/UI/Console/resource.rc +++ b/CPP/7zip/UI/Console/resource.rc @@ -1,7 +1,7 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_APP("7-Zip Console" , "7z") - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "Console.manifest" -#endif +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_APP("7-Zip Console" , "7z") + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "Console.manifest" +#endif diff --git a/CPP/7zip/UI/Explorer/7-zip.dll.manifest b/CPP/7zip/UI/Explorer/7-zip.dll.manifest index 9276dfb8d..cba1c5df4 100644 --- a/CPP/7zip/UI/Explorer/7-zip.dll.manifest +++ b/CPP/7zip/UI/Explorer/7-zip.dll.manifest @@ -1 +1 @@ -7-Zip Extension. +7-Zip Extension. diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp index 0af85e4ee..0630d78e5 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp @@ -1,1829 +1,1837 @@ -// ContextMenu.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/COM.h" -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/ProcessUtils.h" - -// for IS_INTRESOURCE(): -#include "../../../Windows/Window.h" - -#include "../../PropID.h" - -#include "../Common/ArchiveName.h" -#include "../Common/CompressCall.h" -#include "../Common/ExtractingFilePath.h" -#include "../Common/ZipRegistry.h" - -#include "../FileManager/FormatUtils.h" -#include "../FileManager/LangUtils.h" -#include "../FileManager/PropertyName.h" - -#include "ContextMenu.h" -#include "ContextMenuFlags.h" -#include "MyMessages.h" - -#include "resource.h" - - -// #define SHOW_DEBUG_CTX_MENU - -#ifdef SHOW_DEBUG_CTX_MENU -#include -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -#ifndef UNDER_CE -#define EMAIL_SUPPORT 1 -#endif - -extern LONG g_DllRefCount; - -#ifdef _WIN32 -extern HINSTANCE g_hInstance; -#endif - -#ifdef UNDER_CE - #define MY_IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16) == 0) -#else - #define MY_IS_INTRESOURCE(_r) IS_INTRESOURCE(_r) -#endif - - -#ifdef SHOW_DEBUG_CTX_MENU - -static void PrintStringA(const char *name, LPCSTR ptr) -{ - AString m; - m += name; - m += ": "; - char s[32]; - sprintf(s, "%p", (const void *)ptr); - m += s; - if (!MY_IS_INTRESOURCE(ptr)) - { - m += ": \""; - m += ptr; - m += "\""; - } - OutputDebugStringA(m); -} - -#if !defined(UNDER_CE) -static void PrintStringW(const char *name, LPCWSTR ptr) -{ - UString m; - m += name; - m += ": "; - char s[32]; - sprintf(s, "%p", (const void *)ptr); - m += s; - if (!MY_IS_INTRESOURCE(ptr)) - { - m += ": \""; - m += ptr; - m += "\""; - } - OutputDebugStringW(m); -} -#endif - -static void Print_Ptr(const void *p, const char *s) -{ - char temp[32]; - sprintf(temp, "%p", (const void *)p); - AString m; - m += temp; - m.Add_Space(); - m += s; - OutputDebugStringA(m); -} - -static void Print_Number(UInt32 number, const char *s) -{ - AString m; - m.Add_UInt32(number); - m.Add_Space(); - m += s; - OutputDebugStringA(m); -} - -#define ODS(sz) { Print_Ptr(this, sz); } -#define ODS_U(s) { OutputDebugStringW(s); } -#define ODS_(op) { op; } -#define ODS_SPRF_s(x) { char s[256]; x; OutputDebugStringA(s); } - -#else - -#define ODS(sz) -#define ODS_U(s) -#define ODS_(op) -#define ODS_SPRF_s(x) - -#endif - - -/* -DOCs: In Windows 7 and later, the number of items passed to - a verb is limited to 16 when a shortcut menu is queried. - The verb is then re-created and re-initialized with the full - selection when that verb is invoked. -win10 tests: - if (the number of selected file/dir objects > 16) - { - Explorer does the following actions: - - it creates ctx_menu_1 IContextMenu object - - it calls ctx_menu_1->Initialize() with list of only up to 16 items - - it calls ctx_menu_1->QueryContextMenu(menu_1) - - if (some menu command is pressed) - { - - it gets shown string from selected menu item : shown_menu_1_string - - it creates another ctx_menu_2 IContextMenu object - - it calls ctx_menu_2->Initialize() with list of all items - - it calls ctx_menu_2->QueryContextMenu(menu_2) - - if there is menu item with shown_menu_1_string string in menu_2, - Explorer calls ctx_menu_2->InvokeCommand() for that item. - Explorer probably doesn't use VERB from first object ctx_menu_1. - So we must provide same shown menu strings for both objects: - ctx_menu_1 and ctx_menu_2. - } - } -*/ - - -CZipContextMenu::CZipContextMenu(): - _isMenuForFM(true), - _fileNames_WereReduced(true), - _dropMode(false), - _bitmap(NULL), - _writeZone((UInt32)(Int32)-1), - IsSeparator(false), - IsRoot(true), - CurrentSubCommand(0) -{ - ODS("== CZipContextMenu()"); - InterlockedIncrement(&g_DllRefCount); -} - -CZipContextMenu::~CZipContextMenu() -{ - ODS("== ~CZipContextMenu"); - if (_bitmap) - DeleteObject(_bitmap); - InterlockedDecrement(&g_DllRefCount); -} - -// IShellExtInit - -/* -IShellExtInit::Initialize() - pidlFolder: - - for property sheet extension: - NULL - - for shortcut menu extensions: - pidl of folder that contains the item whose shortcut menu is being displayed: - - for nondefault drag-and-drop menu extensions: - pidl of target folder: for nondefault drag-and-drop menu extensions - pidlFolder == NULL in (win10): for context menu -*/ - -Z7_COMWF_B CZipContextMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY /* hkeyProgID */) -{ - COM_TRY_BEGIN - ODS("==== CZipContextMenu::Initialize START") - _isMenuForFM = false; - _fileNames_WereReduced = true; - _dropMode = false; - _attribs.Clear(); - _fileNames.Clear(); - _dropPath.Empty(); - - if (pidlFolder) - { - ODS("==== CZipContextMenu::Initialize (pidlFolder != 0)") - #ifndef UNDER_CE - if (NShell::GetPathFromIDList(pidlFolder, _dropPath)) - { - ODS("==== CZipContextMenu::Initialize path from (pidl):") - ODS_U(_dropPath); - /* win10 : path with "\\\\?\\\" prefix is returned by GetPathFromIDList, if path is long - we can remove super prefix here. But probably prefix - is not problem for following 7-zip code. - so we don't remove super prefix */ - NFile::NName::If_IsSuperPath_RemoveSuperPrefix(_dropPath); - NName::NormalizeDirPathPrefix(_dropPath); - _dropMode = !_dropPath.IsEmpty(); - } - else - #endif - _dropPath.Empty(); - } - - if (!dataObject) - return E_INVALIDARG; - - #ifndef UNDER_CE - - RINOK(NShell::DataObject_GetData_HDROP_or_IDLIST_Names(dataObject, _fileNames)) - // for (unsigned y = 0; y < 10000; y++) - if (NShell::DataObject_GetData_FILE_ATTRS(dataObject, _attribs) != S_OK) - _attribs.Clear(); - - #endif - - ODS_SPRF_s(sprintf(s, "==== CZipContextMenu::Initialize END _files=%d", - _fileNames.Size())) - - return S_OK; - COM_TRY_END -} - - -///////////////////////////// -// IContextMenu - -static LPCSTR const kMainVerb = "SevenZip"; -static LPCSTR const kOpenCascadedVerb = "SevenZip.OpenWithType."; -static LPCSTR const kCheckSumCascadedVerb = "SevenZip.Checksum"; - - -struct CContextMenuCommand -{ - UInt32 flag; - CZipContextMenu::enum_CommandInternalID CommandInternalID; - LPCSTR Verb; - UINT ResourceID; -}; - -#define CMD_REC(cns, verb, ids) { NContextMenuFlags::cns, CZipContextMenu::cns, verb, ids } - -static const CContextMenuCommand g_Commands[] = -{ - CMD_REC( kOpen, "Open", IDS_CONTEXT_OPEN), - CMD_REC( kExtract, "Extract", IDS_CONTEXT_EXTRACT), - CMD_REC( kExtractHere, "ExtractHere", IDS_CONTEXT_EXTRACT_HERE), - CMD_REC( kExtractTo, "ExtractTo", IDS_CONTEXT_EXTRACT_TO), - CMD_REC( kTest, "Test", IDS_CONTEXT_TEST), - CMD_REC( kCompress, "Compress", IDS_CONTEXT_COMPRESS), - CMD_REC( kCompressEmail, "CompressEmail", IDS_CONTEXT_COMPRESS_EMAIL), - CMD_REC( kCompressTo7z, "CompressTo7z", IDS_CONTEXT_COMPRESS_TO), - CMD_REC( kCompressTo7zEmail, "CompressTo7zEmail", IDS_CONTEXT_COMPRESS_TO_EMAIL), - CMD_REC( kCompressToZip, "CompressToZip", IDS_CONTEXT_COMPRESS_TO), - CMD_REC( kCompressToZipEmail, "CompressToZipEmail", IDS_CONTEXT_COMPRESS_TO_EMAIL) -}; - - -struct CHashCommand -{ - CZipContextMenu::enum_CommandInternalID CommandInternalID; - LPCSTR UserName; - LPCSTR MethodName; -}; - -static const CHashCommand g_HashCommands[] = -{ - { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" }, - { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" }, - { CZipContextMenu::kHash_XXH64, "XXH64", "XXH64" }, - { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" }, - { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" }, - { CZipContextMenu::kHash_BLAKE2SP, "BLAKE2sp", "BLAKE2sp" }, - { CZipContextMenu::kHash_All, "*", "*" }, - { CZipContextMenu::kHash_Generate_SHA256, "SHA-256 -> file.sha256", "SHA256" }, - { CZipContextMenu::kHash_TestArc, "Checksum : Test", "Hash" } -}; - - -static int FindCommand(CZipContextMenu::enum_CommandInternalID &id) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Commands); i++) - if (g_Commands[i].CommandInternalID == id) - return (int)i; - return -1; -} - - -void CZipContextMenu::FillCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) const -{ - mainString.Empty(); - const int i = FindCommand(id); - if (i < 0) - throw 201908; - const CContextMenuCommand &command = g_Commands[(unsigned)i]; - cmi.CommandInternalID = command.CommandInternalID; - cmi.Verb = kMainVerb; - cmi.Verb += command.Verb; - // cmi.HelpString = cmi.Verb; - LangString(command.ResourceID, mainString); - cmi.UserString = mainString; -} - - -static UString LangStringAlt(UInt32 id, const char *altString) -{ - UString s = LangString(id); - if (s.IsEmpty()) - s = altString; - return s; -} - - -void CZipContextMenu::AddCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) -{ - FillCommand(id, mainString, cmi); - _commandMap.Add(cmi); -} - - - -/* -note: old msdn article: -Duplicate Menu Items In the File Menu For a Shell Context Menu Extension (214477) ----------- - On systems with Shell32.dll version 4.71 or higher, a context menu extension - for a file folder that inserts one or more pop-up menus results in duplicates - of these menu items. - This occurs when the file menu is activated more than once for the selected object. - -CAUSE - In a context menu extension, if pop-up menus are inserted using InsertMenu - or AppendMenu, then the ID for the pop-up menu item cannot be specified. - Instead, this field should take in the HMENU of the pop-up menu. - Because the ID is not specified for the pop-up menu item, the Shell does - not keep track of the menu item if the file menu is pulled down multiple times. - As a result, the pop-up menu items are added multiple times in the context menu. - - This problem occurs only when the file menu is pulled down, and does not happen - when the context menu is invoked by using the right button or the context menu key. -RESOLUTION - To work around this problem, use InsertMenuItem and specify the ID of the - pop-up menu item in the wID member of the MENUITEMINFO structure. -*/ - -static void MyInsertMenu(CMenu &menu, unsigned pos, UINT id, const UString &s, HBITMAP bitmap) -{ - if (!menu) - return; - CMenuItem mi; - mi.fType = MFT_STRING; - mi.fMask = MIIM_TYPE | MIIM_ID; - if (bitmap) - mi.fMask |= MIIM_CHECKMARKS; - mi.wID = id; - mi.StringValue = s; - mi.hbmpUnchecked = bitmap; - // mi.hbmpChecked = bitmap; // do we need hbmpChecked ??? - if (!menu.InsertItem(pos, true, mi)) - throw 20190816; - - // SetMenuItemBitmaps also works - // ::SetMenuItemBitmaps(menu, pos, MF_BYPOSITION, bitmap, NULL); -} - - -static void MyAddSubMenu( - CObjectVector &_commandMap, - const char *verb, - CMenu &menu, unsigned pos, UINT id, const UString &s, HMENU hSubMenu, HBITMAP bitmap) -{ - CZipContextMenu::CCommandMapItem cmi; - cmi.CommandInternalID = CZipContextMenu::kCommandNULL; - cmi.Verb = verb; - cmi.IsPopup = true; - // cmi.HelpString = verb; - cmi.UserString = s; - _commandMap.Add(cmi); - - if (!menu) - return; - - CMenuItem mi; - mi.fType = MFT_STRING; - mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; - if (bitmap) - mi.fMask |= MIIM_CHECKMARKS; - mi.wID = id; - mi.hSubMenu = hSubMenu; - mi.hbmpUnchecked = bitmap; - - mi.StringValue = s; - if (!menu.InsertItem(pos, true, mi)) - throw 20190817; -} - - -static const char * const kArcExts[] = -{ - "7z" - , "bz2" - , "gz" - , "rar" - , "zip" -}; - -static bool IsItArcExt(const UString &ext) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kArcExts); i++) - if (ext.IsEqualTo_Ascii_NoCase(kArcExts[i])) - return true; - return false; -} - -UString GetSubFolderNameForExtract(const UString &arcName); -UString GetSubFolderNameForExtract(const UString &arcName) -{ - int dotPos = arcName.ReverseFind_Dot(); - if (dotPos < 0) - return Get_Correct_FsFile_Name(arcName) + L'~'; - - const UString ext = arcName.Ptr(dotPos + 1); - UString res = arcName.Left(dotPos); - res.TrimRight(); - dotPos = res.ReverseFind_Dot(); - if (dotPos > 0) - { - const UString ext2 = res.Ptr(dotPos + 1); - if ((ext.IsEqualTo_Ascii_NoCase("001") && IsItArcExt(ext2)) - || (ext.IsEqualTo_Ascii_NoCase("rar") && - ( ext2.IsEqualTo_Ascii_NoCase("part001") - || ext2.IsEqualTo_Ascii_NoCase("part01") - || ext2.IsEqualTo_Ascii_NoCase("part1")))) - res.DeleteFrom(dotPos); - res.TrimRight(); - } - return Get_Correct_FsFile_Name(res); -} - -static void ReduceString(UString &s) -{ - const unsigned kMaxSize = 64; - if (s.Len() <= kMaxSize) - return; - s.Delete(kMaxSize / 2, s.Len() - kMaxSize); - s.Insert(kMaxSize / 2, L" ... "); -} - -static UString GetQuotedReducedString(const UString &s) -{ - UString s2 = s; - ReduceString(s2); - s2.Replace(L"&", L"&&"); - return GetQuotedString(s2); -} - -static void MyFormatNew_ReducedName(UString &s, const UString &name) -{ - s = MyFormatNew(s, GetQuotedReducedString(name)); -} - -static const char * const kExtractExcludeExtensions = - " 3gp" - " aac ans ape asc asm asp aspx avi awk" - " bas bat bmp" - " c cs cls clw cmd cpp csproj css ctl cxx" - " def dep dlg dsp dsw" - " eps" - " f f77 f90 f95 fla flac frm" - " gif" - " h hpp hta htm html hxx" - " ico idl inc ini inl" - " java jpeg jpg js" - " la lnk log" - " mak manifest wmv mov mp3 mp4 mpe mpeg mpg m4a" - " ofr ogg" - " pac pas pdf php php3 php4 php5 phptml pl pm png ps py pyo" - " ra rb rc reg rka rm rtf" - " sed sh shn shtml sln sql srt swa" - " tcl tex tiff tta txt" - " vb vcproj vbs" - " mkv wav webm wma wv" - " xml xsd xsl xslt" - " "; - -/* -static const char * const kNoOpenAsExtensions = - " 7z arj bz2 cab chm cpio flv gz lha lzh lzma rar swm tar tbz2 tgz wim xar xz z zip "; -*/ - -static const char * const kOpenTypes[] = -{ - "" - , "*" - , "#" - , "#:e" - // , "#:a" - , "7z" - , "zip" - , "cab" - , "rar" -}; - - -bool FindExt(const char *p, const UString &name, CStringFinder &finder); -bool FindExt(const char *p, const UString &name, CStringFinder &finder) -{ - const int dotPos = name.ReverseFind_Dot(); - int len = (int)name.Len() - (dotPos + 1); - if (len == 0 || len > 32 || dotPos < 0) - return false; - return finder.FindWord_In_LowCaseAsciiList_NoCase(p, name.Ptr(dotPos + 1)); -} - -/* returns false, if extraction of that file extension is not expected */ -static bool DoNeedExtract(const UString &name, CStringFinder &finder) -{ - // for (int y = 0; y < 1000; y++) FindExt(kExtractExcludeExtensions, name); - return !FindExt(kExtractExcludeExtensions, name, finder); -} - -// we must use diferent Verbs for Popup subMenu. -void CZipContextMenu::AddMapItem_ForSubMenu(const char *verb) -{ - CCommandMapItem cmi; - cmi.CommandInternalID = kCommandNULL; - cmi.Verb = verb; - // cmi.HelpString = verb; - _commandMap.Add(cmi); -} - - -static HRESULT RETURN_WIN32_LastError_AS_HRESULT() -{ - DWORD lastError = ::GetLastError(); - if (lastError == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(lastError); -} - - -/* - we add CCommandMapItem to _commandMap for each new Menu ID. - so then we use _commandMap[offset]. - That way we can execute commands that have menu item. - Another non-implemented way: - We can return the number off all possible commands in QueryContextMenu(). - so the caller could call InvokeCommand() via string verb even - without using menu items. -*/ - - -Z7_COMWF_B CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, - UINT commandIDFirst, UINT commandIDLast, UINT flags) -{ - ODS("+ QueryContextMenu()") - COM_TRY_BEGIN - try { - - _commandMap.Clear(); - - ODS_SPRF_s(sprintf(s, "QueryContextMenu: index=%u first=%u last=%u flags=%x _files=%u", - indexMenu, commandIDFirst, commandIDLast, flags, _fileNames.Size())) - /* - for (UInt32 i = 0; i < _fileNames.Size(); i++) - { - ODS_U(_fileNames[i]) - } - */ - - #define MAKE_HRESULT_SUCCESS_FAC0(code) (HRESULT)(code) - - if (_fileNames.Size() == 0) - { - return MAKE_HRESULT_SUCCESS_FAC0(0); - // return E_INVALIDARG; - } - - if (commandIDFirst > commandIDLast) - return E_INVALIDARG; - - UINT currentCommandID = commandIDFirst; - - if ((flags & 0x000F) != CMF_NORMAL - && (flags & CMF_VERBSONLY) == 0 - && (flags & CMF_EXPLORE) == 0) - return MAKE_HRESULT_SUCCESS_FAC0(currentCommandID - commandIDFirst); - // return MAKE_HRESULT_SUCCESS_FAC0(currentCommandID); - // 19.01 : we changed from (currentCommandID) to (currentCommandID - commandIDFirst) - // why it was so before? - -#ifdef Z7_LANG - LoadLangOneTime(); -#endif - - CMenu popupMenu; - CMenuDestroyer menuDestroyer; - - ODS("### 40") - CContextMenuInfo ci; - ci.Load(); - ODS("### 44") - - _elimDup = ci.ElimDup; - _writeZone = ci.WriteZone; - - HBITMAP bitmap = NULL; - if (ci.MenuIcons.Val) - { - ODS("### 45") - if (!_bitmap) - _bitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_MENU_LOGO)); - bitmap = _bitmap; - } - - UINT subIndex = indexMenu; - - ODS("### 50") - - if (ci.Cascaded.Val) - { - if (hMenu) - if (!popupMenu.CreatePopup()) - return RETURN_WIN32_LastError_AS_HRESULT(); - menuDestroyer.Attach(popupMenu); - - /* 9.31: we commented the following code. Probably we don't need. - Check more systems. Maybe it was for old Windows? */ - /* - AddMapItem_ForSubMenu(); - currentCommandID++; - */ - subIndex = 0; - } - else - { - popupMenu.Attach(hMenu); - CMenuItem mi; - mi.fType = MFT_SEPARATOR; - mi.fMask = MIIM_TYPE; - if (hMenu) - popupMenu.InsertItem(subIndex++, true, mi); - } - - const UInt32 contextMenuFlags = ci.Flags; - - NFind::CFileInfo fi0; - FString folderPrefix; - - if (_fileNames.Size() > 0) - { - const UString &fileName = _fileNames.Front(); - - #if defined(_WIN32) && !defined(UNDER_CE) - if (NName::IsDevicePath(us2fs(fileName))) - { - // CFileInfo::Find can be slow for device files. So we don't call it. - // we need only name here. - fi0.Name = us2fs(fileName.Ptr(NName::kDevicePathPrefixSize)); - folderPrefix = - #ifdef UNDER_CE - "\\"; - #else - "C:\\"; - #endif - } - else - #endif - { - if (!fi0.Find(us2fs(fileName))) - { - throw 20190820; - // return RETURN_WIN32_LastError_AS_HRESULT(); - } - GetOnlyDirPrefix(us2fs(fileName), folderPrefix); - } - } - - ODS("### 100") - - UString mainString; - CStringFinder finder; - UStringVector fileNames_Reduced; - const unsigned k_Explorer_NumReducedItems = 16; - const bool needReduce = !_isMenuForFM && (_fileNames.Size() >= k_Explorer_NumReducedItems); - _fileNames_WereReduced = needReduce; - // _fileNames_WereReduced = true; // for debug; - const UStringVector *fileNames = &_fileNames; - if (needReduce) - { - for (unsigned i = 0; i < k_Explorer_NumReducedItems - && i < _fileNames.Size(); i++) - fileNames_Reduced.Add(_fileNames[i]); - fileNames = &fileNames_Reduced; - } - - /* - if (_fileNames.Size() == k_Explorer_NumReducedItems) // for debug - { - for (int i = 0; i < 10; i++) - { - CCommandMapItem cmi; - AddCommand(kCompressToZipEmail, mainString, cmi); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - } - */ - - if (_fileNames.Size() == 1 && currentCommandID + 14 <= commandIDLast) - { - if (!fi0.IsDir() && DoNeedExtract(fs2us(fi0.Name), finder)) - { - // Open - const bool thereIsMainOpenItem = ((contextMenuFlags & NContextMenuFlags::kOpen) != 0); - if (thereIsMainOpenItem) - { - CCommandMapItem cmi; - AddCommand(kOpen, mainString, cmi); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0 - // && (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fi0.Name)) - && hMenu // we want to reduce number of menu items below 16 - ) - { - CMenu subMenu; - if (!hMenu || subMenu.CreatePopup()) - { - MyAddSubMenu(_commandMap, kOpenCascadedVerb, popupMenu, subIndex++, currentCommandID++, LangString(IDS_CONTEXT_OPEN), subMenu, bitmap); - _commandMap.Back().CtxCommandType = CtxCommandType_OpenRoot; - - UINT subIndex2 = 0; - for (unsigned i = (thereIsMainOpenItem ? 1 : 0); i < Z7_ARRAY_SIZE(kOpenTypes); i++) - { - CCommandMapItem cmi; - if (i == 0) - FillCommand(kOpen, mainString, cmi); - else - { - mainString = kOpenTypes[i]; - cmi.CommandInternalID = kOpen; - cmi.Verb = kMainVerb; - cmi.Verb += ".Open."; - cmi.Verb += mainString; - // cmi.HelpString = cmi.Verb; - cmi.ArcType = mainString; - cmi.CtxCommandType = CtxCommandType_OpenChild; - } - _commandMap.Add(cmi); - Set_UserString_in_LastCommand(mainString); - MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString, bitmap); - } - - subMenu.Detach(); - } - } - } - } - - ODS("### 150") - - if (_fileNames.Size() > 0 && currentCommandID + 10 <= commandIDLast) - { - ODS("### needExtract list START") - const bool needExtendedVerbs = ((flags & Z7_WIN_CMF_EXTENDEDVERBS) != 0); - // || _isMenuForFM; - bool needExtract = true; - bool areDirs = fi0.IsDir() || (unsigned)_attribs.FirstDirIndex < k_Explorer_NumReducedItems; - if (!needReduce) - areDirs = areDirs || (_attribs.FirstDirIndex != -1); - if (areDirs) - needExtract = false; - - if (!needExtendedVerbs) - if (needExtract) - { - UString name; - const unsigned numItemsCheck = fileNames->Size(); - for (unsigned i = 0; i < numItemsCheck; i++) - { - const UString &a = (*fileNames)[i]; - const int slash = a.ReverseFind_PathSepar(); - name = a.Ptr(slash + 1); - // for (int y = 0; y < 600; y++) // for debug - const bool needExtr2 = DoNeedExtract(name, finder); - if (!needExtr2) - { - needExtract = needExtr2; - break; - } - } - } - ODS("### needExtract list END") - - if (needExtract) - { - { - UString baseFolder = fs2us(folderPrefix); - if (_dropMode) - baseFolder = _dropPath; - - UString specFolder ('*'); - if (_fileNames.Size() == 1) - specFolder = GetSubFolderNameForExtract(fs2us(fi0.Name)); - specFolder.Add_PathSepar(); - - if ((contextMenuFlags & NContextMenuFlags::kExtract) != 0) - { - // Extract - CCommandMapItem cmi; - cmi.Folder = baseFolder + specFolder; - AddCommand(kExtract, mainString, cmi); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - - if ((contextMenuFlags & NContextMenuFlags::kExtractHere) != 0) - { - // Extract Here - CCommandMapItem cmi; - cmi.Folder = baseFolder; - AddCommand(kExtractHere, mainString, cmi); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - - if ((contextMenuFlags & NContextMenuFlags::kExtractTo) != 0) - { - // Extract To - CCommandMapItem cmi; - UString s; - cmi.Folder = baseFolder + specFolder; - AddCommand(kExtractTo, s, cmi); - MyFormatNew_ReducedName(s, specFolder); - Set_UserString_in_LastCommand(s); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - } - } - - if ((contextMenuFlags & NContextMenuFlags::kTest) != 0) - { - // Test - CCommandMapItem cmi; - AddCommand(kTest, mainString, cmi); - // if (_fileNames.Size() == 16) mainString += "_[16]"; // for debug - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - } - - ODS("### CreateArchiveName START") - UString arcName_base; - const UString arcName = CreateArchiveName( - *fileNames, - false, // isHash - fileNames->Size() == 1 ? &fi0 : NULL, - arcName_base); - ODS("### CreateArchiveName END") - UString arcName_Show = arcName; - if (needReduce) - { - /* we need same arcName_Show for two calls from Explorer: - 1) reduced call (only first 16 items) - 2) full call with all items (can be >= 16 items) - (fileNames) array was reduced to 16 items. - So we will have same (arcName) in both reduced and full calls. - If caller (Explorer) uses (reduce_to_first_16_items) scheme, - we can use (arcName) here instead of (arcName_base). - (arcName_base) has no number in name. - */ - arcName_Show = arcName_base; // we can comment that line - /* we use "_" in archive name as sign to user - that shows that final archive name can be changed. */ - arcName_Show += "_"; - } - - UString arcName_7z = arcName; - arcName_7z += ".7z"; - UString arcName_7z_Show = arcName_Show; - arcName_7z_Show += ".7z"; - UString arcName_zip = arcName; - arcName_zip += ".zip"; - UString arcName_zip_Show = arcName_Show; - arcName_zip_Show += ".zip"; - - - // Compress - if ((contextMenuFlags & NContextMenuFlags::kCompress) != 0) - { - CCommandMapItem cmi; - if (_dropMode) - cmi.Folder = _dropPath; - else - cmi.Folder = fs2us(folderPrefix); - cmi.ArcName = arcName; - AddCommand(kCompress, mainString, cmi); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - - #ifdef EMAIL_SUPPORT - // CompressEmail - if ((contextMenuFlags & NContextMenuFlags::kCompressEmail) != 0 && !_dropMode) - { - CCommandMapItem cmi; - cmi.ArcName = arcName; - AddCommand(kCompressEmail, mainString, cmi); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); - } - #endif - - // CompressTo7z - if (contextMenuFlags & NContextMenuFlags::kCompressTo7z && - !arcName_7z.IsEqualTo_NoCase(fs2us(fi0.Name))) - { - CCommandMapItem cmi; - UString s; - if (_dropMode) - cmi.Folder = _dropPath; - else - cmi.Folder = fs2us(folderPrefix); - cmi.ArcName = arcName_7z; - cmi.ArcType = "7z"; - AddCommand(kCompressTo7z, s, cmi); - MyFormatNew_ReducedName(s, arcName_7z_Show); - Set_UserString_in_LastCommand(s); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - } - - #ifdef EMAIL_SUPPORT - // CompressTo7zEmail - if ((contextMenuFlags & NContextMenuFlags::kCompressTo7zEmail) != 0 && !_dropMode) - { - CCommandMapItem cmi; - UString s; - cmi.ArcName = arcName_7z; - cmi.ArcType = "7z"; - AddCommand(kCompressTo7zEmail, s, cmi); - MyFormatNew_ReducedName(s, arcName_7z_Show); - Set_UserString_in_LastCommand(s); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - } - #endif - - // CompressToZip - if (contextMenuFlags & NContextMenuFlags::kCompressToZip && - !arcName_zip.IsEqualTo_NoCase(fs2us(fi0.Name))) - { - CCommandMapItem cmi; - UString s; - if (_dropMode) - cmi.Folder = _dropPath; - else - cmi.Folder = fs2us(folderPrefix); - cmi.ArcName = arcName_zip; - cmi.ArcType = "zip"; - AddCommand(kCompressToZip, s, cmi); - MyFormatNew_ReducedName(s, arcName_zip_Show); - Set_UserString_in_LastCommand(s); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - } - - #ifdef EMAIL_SUPPORT - // CompressToZipEmail - if ((contextMenuFlags & NContextMenuFlags::kCompressToZipEmail) != 0 && !_dropMode) - { - CCommandMapItem cmi; - UString s; - cmi.ArcName = arcName_zip; - cmi.ArcType = "zip"; - AddCommand(kCompressToZipEmail, s, cmi); - MyFormatNew_ReducedName(s, arcName_zip_Show); - Set_UserString_in_LastCommand(s); - MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); - } - #endif - } - - ODS("### 300") - - // don't use InsertMenu: See MSDN: - // PRB: Duplicate Menu Items In the File Menu For a Shell Context Menu Extension - // ID: Q214477 - - if (ci.Cascaded.Val) - { - CMenu menu; - menu.Attach(hMenu); - menuDestroyer.Disable(); - MyAddSubMenu(_commandMap, kMainVerb, menu, indexMenu++, currentCommandID++, (UString)"7-Zip", - popupMenu, // popupMenu.Detach(), - bitmap); - } - else - { - // popupMenu.Detach(); - indexMenu = subIndex; - } - - ODS("### 350") - - const bool needCrc = ((contextMenuFlags & - (NContextMenuFlags::kCRC | - NContextMenuFlags::kCRC_Cascaded)) != 0); - - if ( - // !_isMenuForFM && // 21.04: we don't hide CRC SHA menu in 7-Zip FM - needCrc - && currentCommandID + 1 < commandIDLast) - { - CMenu subMenu; - // CMenuDestroyer menuDestroyer_CRC; - - UINT subIndex_CRC = 0; - - if (!hMenu || subMenu.CreatePopup()) - { - // menuDestroyer_CRC.Attach(subMenu); - const bool insertHashMenuTo7zipMenu = (ci.Cascaded.Val - && (contextMenuFlags & NContextMenuFlags::kCRC_Cascaded) != 0); - - CMenu menu; - { - unsigned indexInParent; - if (insertHashMenuTo7zipMenu) - { - indexInParent = subIndex; - menu.Attach(popupMenu); - } - else - { - indexInParent = indexMenu; - menu.Attach(hMenu); - // menuDestroyer_CRC.Disable(); - } - MyAddSubMenu(_commandMap, kCheckSumCascadedVerb, menu, indexInParent++, currentCommandID++, (UString)"CRC SHA", subMenu, - /* insertHashMenuTo7zipMenu ? NULL : */ bitmap); - _commandMap.Back().CtxCommandType = CtxCommandType_CrcRoot; - if (!insertHashMenuTo7zipMenu) - indexMenu = indexInParent; - } - - ODS("### HashCommands") - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_HashCommands); i++) - { - if (currentCommandID >= commandIDLast) - break; - const CHashCommand &hc = g_HashCommands[i]; - CCommandMapItem cmi; - cmi.CommandInternalID = hc.CommandInternalID; - cmi.Verb = kCheckSumCascadedVerb; - cmi.Verb.Add_Dot(); - UString s; - s += hc.UserName; - - if (hc.CommandInternalID == kHash_Generate_SHA256) - { - cmi.Verb += "Generate"; - { - popupMenu.Attach(hMenu); - CMenuItem mi; - mi.fType = MFT_SEPARATOR; - mi.fMask = MIIM_TYPE; - subMenu.InsertItem(subIndex_CRC++, true, mi); - } - - UString name; - UString showName; - ODS("### Hash CreateArchiveName Start") - // for (int y = 0; y < 10000; y++) // for debug - // if (fileNames->Size() == 1) name = fs2us(fi0.Name); else - name = CreateArchiveName( - *fileNames, - true, // isHash - fileNames->Size() == 1 ? &fi0 : NULL, - showName); - if (needReduce) - showName += "_"; - else - showName = name; - - ODS("### Hash CreateArchiveName END") - name += ".sha256"; - showName += ".sha256"; - cmi.Folder = fs2us(folderPrefix); - cmi.ArcName = name; - s = "SHA-256 -> "; - s += showName; - } - else if (hc.CommandInternalID == kHash_TestArc) - { - cmi.Verb += "Test"; - s = LangStringAlt(IDS_CONTEXT_TEST, "Test archive"); - s += " : "; - s += GetNameOfProperty(kpidChecksum, UString("Checksum")); - } - else - cmi.Verb += "Calc"; - - cmi.Verb.Add_Dot(); - cmi.Verb += hc.MethodName; - - // cmi.HelpString = cmi.Verb; - cmi.UserString = s; - cmi.CtxCommandType = CtxCommandType_CrcChild; - _commandMap.Add(cmi); - MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, s, bitmap); - ODS("### 380") - } - - subMenu.Detach(); - } - } - - popupMenu.Detach(); - /* - if (!ci.Cascaded.Val) - indexMenu = subIndex; - */ - const unsigned numCommands = currentCommandID - commandIDFirst; - ODS("+ QueryContextMenu() END") - ODS_SPRF_s(sprintf(s, "Commands=%u currentCommandID - commandIDFirst = %u", - _commandMap.Size(), numCommands)) - if (_commandMap.Size() != numCommands) - throw 20190818; - /* - FOR_VECTOR (k, _commandMap) - { - ODS_U(_commandMap[k].Verb); - } - */ - } - catch(...) - { - ODS_SPRF_s(sprintf(s, "catch() exception: Commands=%u", _commandMap.Size())) - if (_commandMap.Size() == 0) - throw; - } - /* we added some menu items already : num_added_menu_items, - So we MUST return (number_of_defined_ids), where (number_of_defined_ids >= num_added_menu_items) - This will prevent incorrect menu working, when same IDs can be - assigned in multiple menu items from different subhandlers. - And we must add items to _commandMap before adding to menu. - */ - return MAKE_HRESULT_SUCCESS_FAC0(_commandMap.Size()); - COM_TRY_END -} - - -int CZipContextMenu::FindVerb(const UString &verb) const -{ - FOR_VECTOR (i, _commandMap) - if (_commandMap[i].Verb == verb) - return (int)i; - return -1; -} - -static UString Get7zFmPath() -{ - return fs2us(NWindows::NDLL::GetModuleDirPrefix()) + L"7zFM.exe"; -} - - -Z7_COMWF_B CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) -{ - COM_TRY_BEGIN - - ODS("==== CZipContextMenu::InvokeCommand()") - - #ifdef SHOW_DEBUG_CTX_MENU - - ODS_SPRF_s(sprintf(s, ": InvokeCommand: cbSize=%u flags=%x ", - (unsigned)commandInfo->cbSize, (unsigned)commandInfo->fMask)) - - PrintStringA("Verb", commandInfo->lpVerb); - PrintStringA("Parameters", commandInfo->lpParameters); - PrintStringA("Directory", commandInfo->lpDirectory); - #endif - - int commandOffset = -1; - - // xp64 / Win10 : explorer.exe sends 0 in lpVerbW - // MSDN: if (IS_INTRESOURCE(lpVerbW)), we must use LOWORD(lpVerb) as command offset - - // FIXME: old MINGW doesn't define CMINVOKECOMMANDINFOEX / CMIC_MASK_UNICODE - #if !defined(UNDER_CE) && defined(CMIC_MASK_UNICODE) - bool unicodeVerb = false; - if (commandInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && - (commandInfo->fMask & CMIC_MASK_UNICODE) != 0) - { - LPCMINVOKECOMMANDINFOEX commandInfoEx = (LPCMINVOKECOMMANDINFOEX)commandInfo; - if (!MY_IS_INTRESOURCE(commandInfoEx->lpVerbW)) - { - unicodeVerb = true; - commandOffset = FindVerb(commandInfoEx->lpVerbW); - } - - #ifdef SHOW_DEBUG_CTX_MENU - PrintStringW("VerbW", commandInfoEx->lpVerbW); - PrintStringW("ParametersW", commandInfoEx->lpParametersW); - PrintStringW("DirectoryW", commandInfoEx->lpDirectoryW); - PrintStringW("TitleW", commandInfoEx->lpTitleW); - PrintStringA("Title", commandInfoEx->lpTitle); - #endif - } - if (!unicodeVerb) - #endif - { - ODS("use non-UNICODE verb") - // if (HIWORD(commandInfo->lpVerb) == 0) - if (MY_IS_INTRESOURCE(commandInfo->lpVerb)) - commandOffset = LOWORD(commandInfo->lpVerb); - else - commandOffset = FindVerb(GetUnicodeString(commandInfo->lpVerb)); - } - - ODS_SPRF_s(sprintf(s, "commandOffset=%d", commandOffset)) - - if (/* commandOffset < 0 || */ (unsigned)commandOffset >= _commandMap.Size()) - return E_INVALIDARG; - const CCommandMapItem &cmi = _commandMap[(unsigned)commandOffset]; - return InvokeCommandCommon(cmi); - COM_TRY_END -} - - -HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi) -{ - const enum_CommandInternalID cmdID = cmi.CommandInternalID; - - try - { - switch (cmdID) - { - case kOpen: - { - UString params; - params = GetQuotedString(_fileNames[0]); - if (!cmi.ArcType.IsEmpty()) - { - params += " -t"; - params += cmi.ArcType; - } - MyCreateProcess(Get7zFmPath(), params); - break; - } - case kExtract: - case kExtractHere: - case kExtractTo: - { - if (_attribs.FirstDirIndex != -1) - { - ShowErrorMessageRes(IDS_SELECT_FILES); - break; - } - ExtractArchives(_fileNames, cmi.Folder, - (cmdID == kExtract), // showDialog - (cmdID == kExtractTo) && _elimDup.Val, // elimDup - _writeZone - ); - break; - } - case kTest: - { - TestArchives(_fileNames); - break; - } - case kCompress: - case kCompressEmail: - case kCompressTo7z: - case kCompressTo7zEmail: - case kCompressToZip: - case kCompressToZipEmail: - { - UString arcName = cmi.ArcName; - if (_fileNames_WereReduced) - { - UString arcName_base; - arcName = CreateArchiveName( - _fileNames, - false, // isHash - NULL, // fi0 - arcName_base); - const char *postfix = NULL; - if (cmdID == kCompressTo7z || - cmdID == kCompressTo7zEmail) - postfix = ".7z"; - else if ( - cmdID == kCompressToZip || - cmdID == kCompressToZipEmail) - postfix = ".zip"; - if (postfix) - arcName += postfix; - } - - const bool email = - cmdID == kCompressEmail || - cmdID == kCompressTo7zEmail || - cmdID == kCompressToZipEmail; - const bool showDialog = - cmdID == kCompress || - cmdID == kCompressEmail; - const bool addExtension = showDialog; - CompressFiles(cmi.Folder, - arcName, cmi.ArcType, - addExtension, - _fileNames, email, showDialog, - false // waitFinish - ); - break; - } - - case kHash_CRC32: - case kHash_CRC64: - case kHash_XXH64: - case kHash_SHA1: - case kHash_SHA256: - case kHash_BLAKE2SP: - case kHash_All: - case kHash_Generate_SHA256: - case kHash_TestArc: - { - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_HashCommands); i++) - { - const CHashCommand &hc = g_HashCommands[i]; - if (hc.CommandInternalID == cmdID) - { - if (cmdID == kHash_TestArc) - { - TestArchives(_fileNames, true); // hashMode - break; - } - UString generateName; - if (cmdID == kHash_Generate_SHA256) - { - generateName = cmi.ArcName; - if (_fileNames_WereReduced) - { - UString arcName_base; - generateName = CreateArchiveName(_fileNames, - true, // isHash - NULL, // fi0 - arcName_base); - generateName += ".sha256"; - } - } - CalcChecksum(_fileNames, (UString)hc.MethodName, - cmi.Folder, generateName); - break; - } - } - break; - } - case kCommandNULL: - break; - } - } - catch(...) - { - ShowErrorMessage(NULL, L"Error"); - } - return S_OK; -} - - - -static void MyCopyString_isUnicode(void *dest, UINT size, const UString &src, bool writeInUnicode) -{ - if (size != 0) - size--; - if (writeInUnicode) - { - UString s = src; - s.DeleteFrom(size); - MyStringCopy((wchar_t *)dest, s); - ODS_U(s) - } - else - { - AString s = GetAnsiString(src); - s.DeleteFrom(size); - MyStringCopy((char *)dest, s); - } -} - - -Z7_COMWF_B CZipContextMenu::GetCommandString( - #ifdef Z7_OLD_WIN_SDK - UINT - #else - UINT_PTR - #endif - commandOffset, - UINT uType, - UINT * /* pwReserved */ , LPSTR pszName, UINT cchMax) -{ - COM_TRY_BEGIN - - ODS("GetCommandString") - - const int cmdOffset = (int)commandOffset; - - ODS_SPRF_s(sprintf(s, "GetCommandString: cmdOffset=%d uType=%d cchMax = %d", - cmdOffset, uType, cchMax)) - - if ((uType | GCS_UNICODE) == GCS_VALIDATEW) - { - if (/* cmdOffset < 0 || */ (unsigned)cmdOffset >= _commandMap.Size()) - return S_FALSE; - return S_OK; - } - - if (/* cmdOffset < 0 || */ (unsigned)cmdOffset >= _commandMap.Size()) - { - ODS("------ cmdOffset: E_INVALIDARG") - return E_INVALIDARG; - } - - // we use Verb as HelpString - if (cchMax != 0) - if ((uType | GCS_UNICODE) == GCS_VERBW || - (uType | GCS_UNICODE) == GCS_HELPTEXTW) - { - const CCommandMapItem &cmi = _commandMap[(unsigned)cmdOffset]; - MyCopyString_isUnicode(pszName, cchMax, cmi.Verb, (uType & GCS_UNICODE) != 0); - return S_OK; - } - - return E_INVALIDARG; - - COM_TRY_END -} - - - -// ---------- IExplorerCommand ---------- - -static HRESULT WINAPI My_SHStrDupW(LPCWSTR src, LPWSTR *dest) -{ - if (src) - { - const SIZE_T size = (wcslen(src) + 1) * sizeof(WCHAR); - WCHAR *p = (WCHAR *)CoTaskMemAlloc(size); - if (p) - { - memcpy(p, src, size); - *dest = p; - return S_OK; - } - } - *dest = NULL; - return E_OUTOFMEMORY; -} - - -#define CZipExplorerCommand CZipContextMenu - -class CCoTaskWSTR -{ - LPWSTR m_str; - Z7_CLASS_NO_COPY(CCoTaskWSTR) -public: - CCoTaskWSTR(): m_str(NULL) {} - ~CCoTaskWSTR() { ::CoTaskMemFree(m_str); } - LPWSTR* operator&() { return &m_str; } - operator LPCWSTR () const { return m_str; } - // operator LPCOLESTR() const { return m_str; } - operator bool() const { return m_str != NULL; } - // bool operator!() const { return m_str == NULL; } - - /* - void Wipe_and_Free() - { - if (m_str) - { - memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str)); - Empty(); - } - } - */ - -private: - /* - CCoTaskWSTR(LPCOLESTR src) { m_str = ::CoTaskMemAlloc(src); } - - CCoTaskWSTR& operator=(LPCOLESTR src) - { - ::CoTaskMemFree(m_str); - m_str = ::SysAllocString(src); - return *this; - } - - - void Empty() - { - ::CoTaskMemFree(m_str); - m_str = NULL; - } - */ -}; - -static HRESULT LoadPaths(IShellItemArray *psiItemArray, UStringVector &paths) -{ - if (psiItemArray) - { - DWORD numItems = 0; - RINOK(psiItemArray->GetCount(&numItems)) - { - ODS_(Print_Number(numItems, " ==== LoadPaths START === ")) - for (DWORD i = 0; i < numItems; i++) - { - CMyComPtr item; - RINOK(psiItemArray->GetItemAt(i, &item)) - if (item) - { - CCoTaskWSTR displayName; - if (item->GetDisplayName(SIGDN_FILESYSPATH, &displayName) == S_OK - && (bool)displayName) - { - ODS_U(displayName) - paths.Add((LPCWSTR)displayName); - } - } - } - ODS_(Print_Number(numItems, " ==== LoadPaths END === ")) - } - } - return S_OK; -} - - -void CZipExplorerCommand::LoadItems(IShellItemArray *psiItemArray) -{ - SubCommands.Clear(); - _fileNames.Clear(); - { - UStringVector paths; - if (LoadPaths(psiItemArray, paths) != S_OK) - return; - _fileNames = paths; - } - const HRESULT res = QueryContextMenu( - NULL, // hMenu, - 0, // indexMenu, - 0, // commandIDFirst, - 0 + 999, // commandIDLast, - CMF_NORMAL); - - if (FAILED(res)) - return /* res */; - - CZipExplorerCommand *crcHandler = NULL; - CZipExplorerCommand *openHandler = NULL; - - bool useCascadedCrc = true; // false; - bool useCascadedOpen = true; // false; - - for (unsigned i = 0; i < _commandMap.Size(); i++) - { - const CCommandMapItem &cmi = _commandMap[i]; - - if (cmi.IsPopup) - if (!cmi.IsSubMenu()) - continue; - - // if (cmi.IsSubMenu()) continue // for debug - - CZipContextMenu *shellExt = new CZipContextMenu(); - shellExt->IsRoot = false; - - if (cmi.CtxCommandType == CtxCommandType_CrcRoot && !useCascadedCrc) - shellExt->IsSeparator = true; - - { - CZipExplorerCommand *handler = this; - if (cmi.CtxCommandType == CtxCommandType_CrcChild && crcHandler) - handler = crcHandler; - else if (cmi.CtxCommandType == CtxCommandType_OpenChild && openHandler) - handler = openHandler; - handler->SubCommands.AddNew() = shellExt; - } - - shellExt->_commandMap_Cur.Add(cmi); - - ODS_U(cmi.UserString) - - if (cmi.CtxCommandType == CtxCommandType_CrcRoot && useCascadedCrc) - crcHandler = shellExt; - if (cmi.CtxCommandType == CtxCommandType_OpenRoot && useCascadedOpen) - { - // ODS("cmi.CtxCommandType == CtxCommandType_OpenRoot"); - openHandler = shellExt; - } - } -} - - -Z7_COMWF_B CZipExplorerCommand::GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName) -{ - ODS("- GetTitle()") - // COM_TRY_BEGIN - if (IsSeparator) - { - *ppszName = NULL; - return S_FALSE; - } - - UString name; - if (IsRoot) - { - LoadItems(psiItemArray); - name = "7-Zip"; // "New" - } - else - name = "7-Zip item"; - - if (!_commandMap_Cur.IsEmpty()) - { - const CCommandMapItem &mi = _commandMap_Cur[0]; - // s += mi.Verb; - // s += " : "; - name = mi.UserString; - } - - return My_SHStrDupW(name, ppszName); - // return S_OK; - // COM_TRY_END -} - - -Z7_COMWF_B CZipExplorerCommand::GetIcon(IShellItemArray * /* psiItemArray */, LPWSTR *ppszIcon) -{ - ODS("- GetIcon()") - // COM_TRY_BEGIN - *ppszIcon = NULL; - // return E_NOTIMPL; - UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); - // imageName += "7zG.exe"; - imageName += "7-zip.dll"; - // imageName += ",190"; - return My_SHStrDupW(imageName, ppszIcon); - // COM_TRY_END -} - - -Z7_COMWF_B CZipExplorerCommand::GetToolTip (IShellItemArray * /* psiItemArray */, LPWSTR *ppszInfotip) -{ - // COM_TRY_BEGIN - ODS("- GetToolTip()") - *ppszInfotip = NULL; - return E_NOTIMPL; - // COM_TRY_END -} - - -Z7_COMWF_B CZipExplorerCommand::GetCanonicalName(GUID *pguidCommandName) -{ - // COM_TRY_BEGIN - ODS("- GetCanonicalName()") - *pguidCommandName = GUID_NULL; - return E_NOTIMPL; - // COM_TRY_END -} - - -Z7_COMWF_B CZipExplorerCommand::GetState(IShellItemArray * /* psiItemArray */, BOOL /* fOkToBeSlow */, EXPCMDSTATE *pCmdState) -{ - // COM_TRY_BEGIN - ODS("- GetState()") - *pCmdState = ECS_ENABLED; - return S_OK; - // COM_TRY_END -} - - - - -Z7_COMWF_B CZipExplorerCommand::Invoke(IShellItemArray *psiItemArray, IBindCtx * /* pbc */) -{ - COM_TRY_BEGIN - - if (_commandMap_Cur.IsEmpty()) - return E_INVALIDARG; - - ODS("- Invoke()") - _fileNames.Clear(); - UStringVector paths; - RINOK(LoadPaths(psiItemArray, paths)) - _fileNames = paths; - return InvokeCommandCommon(_commandMap_Cur[0]); - - COM_TRY_END -} - - -Z7_COMWF_B CZipExplorerCommand::GetFlags(EXPCMDFLAGS *pFlags) -{ - ODS("- GetFlags()") - // COM_TRY_BEGIN - EXPCMDFLAGS f = ECF_DEFAULT; - if (IsSeparator) - f = ECF_ISSEPARATOR; - else if (IsRoot) - f = ECF_HASSUBCOMMANDS; - else - { - if (!_commandMap_Cur.IsEmpty()) - { - // const CCommandMapItem &cmi = ; - if (_commandMap_Cur[0].IsSubMenu()) - { - // ODS("ECF_HASSUBCOMMANDS") - f = ECF_HASSUBCOMMANDS; - } - } - } - *pFlags = f; - return S_OK; - // COM_TRY_END -} - - -Z7_COMWF_B CZipExplorerCommand::EnumSubCommands(IEnumExplorerCommand **ppEnum) -{ - ODS("- EnumSubCommands()") - // COM_TRY_BEGIN - *ppEnum = NULL; - - if (!_commandMap_Cur.IsEmpty() && _commandMap_Cur[0].IsSubMenu()) - { - } - else - { - if (!IsRoot) - return E_NOTIMPL; - if (SubCommands.IsEmpty()) - { - return E_NOTIMPL; - } - } - - // shellExt-> - return QueryInterface(IID_IEnumExplorerCommand, (void **)ppEnum); - - // return S_OK; - // COM_TRY_END -} - - -Z7_COMWF_B CZipContextMenu::Next(ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) -{ - ODS("CZipContextMenu::Next()") - ODS_(Print_Number(celt, "celt")) - ODS_(Print_Number(CurrentSubCommand, "CurrentSubCommand")) - ODS_(Print_Number(SubCommands.Size(), "SubCommands.Size()")) - - COM_TRY_BEGIN - ULONG fetched = 0; - - ULONG i; - for (i = 0; i < celt; i++) - { - pUICommand[i] = NULL; - } - - for (i = 0; i < celt && CurrentSubCommand < SubCommands.Size(); i++) - { - pUICommand[i] = SubCommands[CurrentSubCommand++]; - pUICommand[i]->AddRef(); - fetched++; - } - - if (pceltFetched) - *pceltFetched = fetched; - - ODS(fetched == celt ? " === OK === " : "=== ERROR ===") - - // we return S_FALSE for (fetched == 0) - return (fetched == celt) ? S_OK : S_FALSE; - COM_TRY_END -} - - -Z7_COMWF_B CZipContextMenu::Skip(ULONG /* celt */) -{ - ODS("CZipContextMenu::Skip()") - return E_NOTIMPL; -} - - -Z7_COMWF_B CZipContextMenu::Reset(void) -{ - ODS("CZipContextMenu::Reset()") - CurrentSubCommand = 0; - return S_OK; -} - - -Z7_COMWF_B CZipContextMenu::Clone(IEnumExplorerCommand **ppenum) -{ - ODS("CZipContextMenu::Clone()") - *ppenum = NULL; - return E_NOTIMPL; -} +// ContextMenu.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/COM.h" +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/ProcessUtils.h" + +// for IS_INTRESOURCE(): +#include "../../../Windows/Window.h" + +#include "../../PropID.h" + +#include "../Common/ArchiveName.h" +#include "../Common/CompressCall.h" +#include "../Common/ExtractingFilePath.h" +#include "../Common/ZipRegistry.h" + +#include "../FileManager/FormatUtils.h" +#include "../FileManager/LangUtils.h" +#include "../FileManager/PropertyName.h" + +#include "ContextMenu.h" +#include "ContextMenuFlags.h" +#include "MyMessages.h" + +#include "resource.h" + + +// #define SHOW_DEBUG_CTX_MENU + +#ifdef SHOW_DEBUG_CTX_MENU +#include +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +#ifndef UNDER_CE +#define EMAIL_SUPPORT 1 +#endif + +extern LONG g_DllRefCount; + +#ifdef _WIN32 +extern HINSTANCE g_hInstance; +#endif + +#ifdef UNDER_CE + #define MY_IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16) == 0) +#else + #define MY_IS_INTRESOURCE(_r) IS_INTRESOURCE(_r) +#endif + + +#ifdef SHOW_DEBUG_CTX_MENU + +static void PrintStringA(const char *name, LPCSTR ptr) +{ + AString m; + m += name; + m += ": "; + char s[32]; + sprintf(s, "%p", (const void *)ptr); + m += s; + if (!MY_IS_INTRESOURCE(ptr)) + { + m += ": \""; + m += ptr; + m += "\""; + } + OutputDebugStringA(m); +} + +#if !defined(UNDER_CE) +static void PrintStringW(const char *name, LPCWSTR ptr) +{ + UString m; + m += name; + m += ": "; + char s[32]; + sprintf(s, "%p", (const void *)ptr); + m += s; + if (!MY_IS_INTRESOURCE(ptr)) + { + m += ": \""; + m += ptr; + m += "\""; + } + OutputDebugStringW(m); +} +#endif + +static void Print_Ptr(const void *p, const char *s) +{ + char temp[32]; + sprintf(temp, "%p", (const void *)p); + AString m; + m += temp; + m.Add_Space(); + m += s; + OutputDebugStringA(m); +} + +static void Print_Number(UInt32 number, const char *s) +{ + AString m; + m.Add_UInt32(number); + m.Add_Space(); + m += s; + OutputDebugStringA(m); +} + +#define ODS(sz) { Print_Ptr(this, sz); } +#define ODS_U(s) { OutputDebugStringW(s); } +#define ODS_(op) { op; } +#define ODS_SPRF_s(x) { char s[256]; x; OutputDebugStringA(s); } + +#else + +#define ODS(sz) +#define ODS_U(s) +#define ODS_(op) +#define ODS_SPRF_s(x) + +#endif + + +/* +DOCs: In Windows 7 and later, the number of items passed to + a verb is limited to 16 when a shortcut menu is queried. + The verb is then re-created and re-initialized with the full + selection when that verb is invoked. +win10 tests: + if (the number of selected file/dir objects > 16) + { + Explorer does the following actions: + - it creates ctx_menu_1 IContextMenu object + - it calls ctx_menu_1->Initialize() with list of only up to 16 items + - it calls ctx_menu_1->QueryContextMenu(menu_1) + - if (some menu command is pressed) + { + - it gets shown string from selected menu item : shown_menu_1_string + - it creates another ctx_menu_2 IContextMenu object + - it calls ctx_menu_2->Initialize() with list of all items + - it calls ctx_menu_2->QueryContextMenu(menu_2) + - if there is menu item with shown_menu_1_string string in menu_2, + Explorer calls ctx_menu_2->InvokeCommand() for that item. + Explorer probably doesn't use VERB from first object ctx_menu_1. + So we must provide same shown menu strings for both objects: + ctx_menu_1 and ctx_menu_2. + } + } +*/ + + +CZipContextMenu::CZipContextMenu(): + _isMenuForFM(true), + _fileNames_WereReduced(true), + _dropMode(false), + _bitmap(NULL), + _writeZone((UInt32)(Int32)-1), + IsSeparator(false), + IsRoot(true), + CurrentSubCommand(0) +{ + ODS("== CZipContextMenu()"); + InterlockedIncrement(&g_DllRefCount); +} + +CZipContextMenu::~CZipContextMenu() +{ + ODS("== ~CZipContextMenu"); + if (_bitmap) + DeleteObject(_bitmap); + InterlockedDecrement(&g_DllRefCount); +} + +// IShellExtInit + +/* +IShellExtInit::Initialize() + pidlFolder: + - for property sheet extension: + NULL + - for shortcut menu extensions: + pidl of folder that contains the item whose shortcut menu is being displayed: + - for nondefault drag-and-drop menu extensions: + pidl of target folder: for nondefault drag-and-drop menu extensions + pidlFolder == NULL in (win10): for context menu +*/ + +Z7_COMWF_B CZipContextMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY /* hkeyProgID */) +{ + COM_TRY_BEGIN + ODS("==== CZipContextMenu::Initialize START") + _isMenuForFM = false; + _fileNames_WereReduced = true; + _dropMode = false; + _attribs.Clear(); + _fileNames.Clear(); + _dropPath.Empty(); + + if (pidlFolder) + { + ODS("==== CZipContextMenu::Initialize (pidlFolder != 0)") + #ifndef UNDER_CE + if (NShell::GetPathFromIDList(pidlFolder, _dropPath)) + { + ODS("==== CZipContextMenu::Initialize path from (pidl):") + ODS_U(_dropPath); + /* win10 : path with "\\\\?\\\" prefix is returned by GetPathFromIDList, if path is long + we can remove super prefix here. But probably prefix + is not problem for following 7-zip code. + so we don't remove super prefix */ + NFile::NName::If_IsSuperPath_RemoveSuperPrefix(_dropPath); + NName::NormalizeDirPathPrefix(_dropPath); + _dropMode = !_dropPath.IsEmpty(); + } + else + #endif + _dropPath.Empty(); + } + + if (!dataObject) + return E_INVALIDARG; + + #ifndef UNDER_CE + + RINOK(NShell::DataObject_GetData_HDROP_or_IDLIST_Names(dataObject, _fileNames)) + // for (unsigned y = 0; y < 10000; y++) + if (NShell::DataObject_GetData_FILE_ATTRS(dataObject, _attribs) != S_OK) + _attribs.Clear(); + + #endif + + ODS_SPRF_s(sprintf(s, "==== CZipContextMenu::Initialize END _files=%d", + _fileNames.Size())) + + return S_OK; + COM_TRY_END +} + + +///////////////////////////// +// IContextMenu + +static LPCSTR const kMainVerb = "SevenZip"; +static LPCSTR const kOpenCascadedVerb = "SevenZip.OpenWithType."; +static LPCSTR const kCheckSumCascadedVerb = "SevenZip.Checksum"; + + +struct CContextMenuCommand +{ + UInt32 flag; + CZipContextMenu::enum_CommandInternalID CommandInternalID; + LPCSTR Verb; + UINT ResourceID; +}; + +#define CMD_REC(cns, verb, ids) { NContextMenuFlags::cns, CZipContextMenu::cns, verb, ids } + +static const CContextMenuCommand g_Commands[] = +{ + CMD_REC( kOpen, "Open", IDS_CONTEXT_OPEN), + CMD_REC( kExtract, "Extract", IDS_CONTEXT_EXTRACT), + CMD_REC( kExtractHere, "ExtractHere", IDS_CONTEXT_EXTRACT_HERE), + CMD_REC( kExtractTo, "ExtractTo", IDS_CONTEXT_EXTRACT_TO), + CMD_REC( kTest, "Test", IDS_CONTEXT_TEST), + CMD_REC( kCompress, "Compress", IDS_CONTEXT_COMPRESS), + CMD_REC( kCompressEmail, "CompressEmail", IDS_CONTEXT_COMPRESS_EMAIL), + CMD_REC( kCompressTo7z, "CompressTo7z", IDS_CONTEXT_COMPRESS_TO), + CMD_REC( kCompressTo7zEmail, "CompressTo7zEmail", IDS_CONTEXT_COMPRESS_TO_EMAIL), + CMD_REC( kCompressToZip, "CompressToZip", IDS_CONTEXT_COMPRESS_TO), + CMD_REC( kCompressToZipEmail, "CompressToZipEmail", IDS_CONTEXT_COMPRESS_TO_EMAIL) +}; + + +struct CHashCommand +{ + CZipContextMenu::enum_CommandInternalID CommandInternalID; + LPCSTR UserName; + LPCSTR MethodName; +}; + +static const CHashCommand g_HashCommands[] = +{ + { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" }, + { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" }, + { CZipContextMenu::kHash_XXH64, "XXH64", "XXH64" }, + { CZipContextMenu::kHash_MD5, "MD5", "MD5" }, + { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" }, + { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" }, + { CZipContextMenu::kHash_SHA384, "SHA-384", "SHA384" }, + { CZipContextMenu::kHash_SHA512, "SHA-512", "SHA512" }, + { CZipContextMenu::kHash_SHA3_256, "SHA3-256", "SHA3-256" }, + { CZipContextMenu::kHash_BLAKE2SP, "BLAKE2sp", "BLAKE2sp" }, + { CZipContextMenu::kHash_All, "*", "*" }, + { CZipContextMenu::kHash_Generate_SHA256, "SHA-256 -> file.sha256", "SHA256" }, + { CZipContextMenu::kHash_TestArc, "Checksum : Test", "Hash" } +}; + + +static int FindCommand(CZipContextMenu::enum_CommandInternalID &id) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Commands); i++) + if (g_Commands[i].CommandInternalID == id) + return (int)i; + return -1; +} + + +void CZipContextMenu::FillCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) const +{ + mainString.Empty(); + const int i = FindCommand(id); + if (i < 0) + throw 201908; + const CContextMenuCommand &command = g_Commands[(unsigned)i]; + cmi.CommandInternalID = command.CommandInternalID; + cmi.Verb = kMainVerb; + cmi.Verb += command.Verb; + // cmi.HelpString = cmi.Verb; + LangString(command.ResourceID, mainString); + cmi.UserString = mainString; +} + + +static UString LangStringAlt(UInt32 id, const char *altString) +{ + UString s = LangString(id); + if (s.IsEmpty()) + s = altString; + return s; +} + + +void CZipContextMenu::AddCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) +{ + FillCommand(id, mainString, cmi); + _commandMap.Add(cmi); +} + + + +/* +note: old msdn article: +Duplicate Menu Items In the File Menu For a Shell Context Menu Extension (214477) +---------- + On systems with Shell32.dll version 4.71 or higher, a context menu extension + for a file folder that inserts one or more pop-up menus results in duplicates + of these menu items. + This occurs when the file menu is activated more than once for the selected object. + +CAUSE + In a context menu extension, if pop-up menus are inserted using InsertMenu + or AppendMenu, then the ID for the pop-up menu item cannot be specified. + Instead, this field should take in the HMENU of the pop-up menu. + Because the ID is not specified for the pop-up menu item, the Shell does + not keep track of the menu item if the file menu is pulled down multiple times. + As a result, the pop-up menu items are added multiple times in the context menu. + + This problem occurs only when the file menu is pulled down, and does not happen + when the context menu is invoked by using the right button or the context menu key. +RESOLUTION + To work around this problem, use InsertMenuItem and specify the ID of the + pop-up menu item in the wID member of the MENUITEMINFO structure. +*/ + +static void MyInsertMenu(CMenu &menu, unsigned pos, UINT id, const UString &s, HBITMAP bitmap) +{ + if (!menu) + return; + CMenuItem mi; + mi.fType = MFT_STRING; + mi.fMask = MIIM_TYPE | MIIM_ID; + if (bitmap) + mi.fMask |= MIIM_CHECKMARKS; + mi.wID = id; + mi.StringValue = s; + mi.hbmpUnchecked = bitmap; + // mi.hbmpChecked = bitmap; // do we need hbmpChecked ??? + if (!menu.InsertItem(pos, true, mi)) + throw 20190816; + + // SetMenuItemBitmaps also works + // ::SetMenuItemBitmaps(menu, pos, MF_BYPOSITION, bitmap, NULL); +} + + +static void MyAddSubMenu( + CObjectVector &_commandMap, + const char *verb, + CMenu &menu, unsigned pos, UINT id, const UString &s, HMENU hSubMenu, HBITMAP bitmap) +{ + CZipContextMenu::CCommandMapItem cmi; + cmi.CommandInternalID = CZipContextMenu::kCommandNULL; + cmi.Verb = verb; + cmi.IsPopup = true; + // cmi.HelpString = verb; + cmi.UserString = s; + _commandMap.Add(cmi); + + if (!menu) + return; + + CMenuItem mi; + mi.fType = MFT_STRING; + mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; + if (bitmap) + mi.fMask |= MIIM_CHECKMARKS; + mi.wID = id; + mi.hSubMenu = hSubMenu; + mi.hbmpUnchecked = bitmap; + + mi.StringValue = s; + if (!menu.InsertItem(pos, true, mi)) + throw 20190817; +} + + +static const char * const kArcExts[] = +{ + "7z" + , "bz2" + , "gz" + , "rar" + , "zip" +}; + +static bool IsItArcExt(const UString &ext) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kArcExts); i++) + if (ext.IsEqualTo_Ascii_NoCase(kArcExts[i])) + return true; + return false; +} + +UString GetSubFolderNameForExtract(const UString &arcName); +UString GetSubFolderNameForExtract(const UString &arcName) +{ + int dotPos = arcName.ReverseFind_Dot(); + if (dotPos < 0) + return Get_Correct_FsFile_Name(arcName) + L'~'; + + const UString ext = arcName.Ptr(dotPos + 1); + UString res = arcName.Left(dotPos); + res.TrimRight(); + dotPos = res.ReverseFind_Dot(); + if (dotPos > 0) + { + const UString ext2 = res.Ptr(dotPos + 1); + if ((ext.IsEqualTo_Ascii_NoCase("001") && IsItArcExt(ext2)) + || (ext.IsEqualTo_Ascii_NoCase("rar") && + ( ext2.IsEqualTo_Ascii_NoCase("part001") + || ext2.IsEqualTo_Ascii_NoCase("part01") + || ext2.IsEqualTo_Ascii_NoCase("part1")))) + res.DeleteFrom(dotPos); + res.TrimRight(); + } + return Get_Correct_FsFile_Name(res); +} + +static void ReduceString(UString &s) +{ + const unsigned kMaxSize = 64; + if (s.Len() <= kMaxSize) + return; + s.Delete(kMaxSize / 2, s.Len() - kMaxSize); + s.Insert(kMaxSize / 2, L" ... "); +} + +static UString GetQuotedReducedString(const UString &s) +{ + UString s2 = s; + ReduceString(s2); + s2.Replace(L"&", L"&&"); + return GetQuotedString(s2); +} + +static void MyFormatNew_ReducedName(UString &s, const UString &name) +{ + s = MyFormatNew(s, GetQuotedReducedString(name)); +} + +static const char * const kExtractExcludeExtensions = + " 3gp" + " aac ans ape asc asm asp aspx avi awk" + " bas bat bmp" + " c cs cls clw cmd cpp csproj css ctl cxx" + " def dep dlg dsp dsw" + " eps" + " f f77 f90 f95 fla flac frm" + " gif" + " h hpp hta htm html hxx" + " ico idl inc ini inl" + " java jpeg jpg js" + " la lnk log" + " mak manifest wmv mov mp3 mp4 mpe mpeg mpg m4a" + " ofr ogg" + " pac pas pdf php php3 php4 php5 phptml pl pm png ps py pyo" + " ra rb rc reg rka rm rtf" + " sed sh shn shtml sln sql srt swa" + " tcl tex tiff tta txt" + " vb vcproj vbs" + " mkv wav webm wma wv" + " xml xsd xsl xslt" + " "; + +/* +static const char * const kNoOpenAsExtensions = + " 7z arj bz2 cab chm cpio flv gz lha lzh lzma rar swm tar tbz2 tgz wim xar xz z zip "; +*/ + +static const char * const kOpenTypes[] = +{ + "" + , "*" + , "#" + , "#:e" + // , "#:a" + , "7z" + , "zip" + , "cab" + , "rar" +}; + + +bool FindExt(const char *p, const UString &name, CStringFinder &finder); +bool FindExt(const char *p, const UString &name, CStringFinder &finder) +{ + const int dotPos = name.ReverseFind_Dot(); + int len = (int)name.Len() - (dotPos + 1); + if (len == 0 || len > 32 || dotPos < 0) + return false; + return finder.FindWord_In_LowCaseAsciiList_NoCase(p, name.Ptr(dotPos + 1)); +} + +/* returns false, if extraction of that file extension is not expected */ +static bool DoNeedExtract(const UString &name, CStringFinder &finder) +{ + // for (int y = 0; y < 1000; y++) FindExt(kExtractExcludeExtensions, name); + return !FindExt(kExtractExcludeExtensions, name, finder); +} + +// we must use diferent Verbs for Popup subMenu. +void CZipContextMenu::AddMapItem_ForSubMenu(const char *verb) +{ + CCommandMapItem cmi; + cmi.CommandInternalID = kCommandNULL; + cmi.Verb = verb; + // cmi.HelpString = verb; + _commandMap.Add(cmi); +} + + +static HRESULT RETURN_WIN32_LastError_AS_HRESULT() +{ + DWORD lastError = ::GetLastError(); + if (lastError == 0) + return E_FAIL; + return HRESULT_FROM_WIN32(lastError); +} + + +/* + we add CCommandMapItem to _commandMap for each new Menu ID. + so then we use _commandMap[offset]. + That way we can execute commands that have menu item. + Another non-implemented way: + We can return the number off all possible commands in QueryContextMenu(). + so the caller could call InvokeCommand() via string verb even + without using menu items. +*/ + + +Z7_COMWF_B CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, + UINT commandIDFirst, UINT commandIDLast, UINT flags) +{ + ODS("+ QueryContextMenu()") + COM_TRY_BEGIN + try { + + _commandMap.Clear(); + + ODS_SPRF_s(sprintf(s, "QueryContextMenu: index=%u first=%u last=%u flags=%x _files=%u", + indexMenu, commandIDFirst, commandIDLast, flags, _fileNames.Size())) + /* + for (UInt32 i = 0; i < _fileNames.Size(); i++) + { + ODS_U(_fileNames[i]) + } + */ + + #define MAKE_HRESULT_SUCCESS_FAC0(code) (HRESULT)(code) + + if (_fileNames.Size() == 0) + { + return MAKE_HRESULT_SUCCESS_FAC0(0); + // return E_INVALIDARG; + } + + if (commandIDFirst > commandIDLast) + return E_INVALIDARG; + + UINT currentCommandID = commandIDFirst; + + if ((flags & 0x000F) != CMF_NORMAL + && (flags & CMF_VERBSONLY) == 0 + && (flags & CMF_EXPLORE) == 0) + return MAKE_HRESULT_SUCCESS_FAC0(currentCommandID - commandIDFirst); + // return MAKE_HRESULT_SUCCESS_FAC0(currentCommandID); + // 19.01 : we changed from (currentCommandID) to (currentCommandID - commandIDFirst) + // why it was so before? + +#ifdef Z7_LANG + LoadLangOneTime(); +#endif + + CMenu popupMenu; + CMenuDestroyer menuDestroyer; + + ODS("### 40") + CContextMenuInfo ci; + ci.Load(); + ODS("### 44") + + _elimDup = ci.ElimDup; + _writeZone = ci.WriteZone; + + HBITMAP bitmap = NULL; + if (ci.MenuIcons.Val) + { + ODS("### 45") + if (!_bitmap) + _bitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_MENU_LOGO)); + bitmap = _bitmap; + } + + UINT subIndex = indexMenu; + + ODS("### 50") + + if (ci.Cascaded.Val) + { + if (hMenu) + if (!popupMenu.CreatePopup()) + return RETURN_WIN32_LastError_AS_HRESULT(); + menuDestroyer.Attach(popupMenu); + + /* 9.31: we commented the following code. Probably we don't need. + Check more systems. Maybe it was for old Windows? */ + /* + AddMapItem_ForSubMenu(); + currentCommandID++; + */ + subIndex = 0; + } + else + { + popupMenu.Attach(hMenu); + CMenuItem mi; + mi.fType = MFT_SEPARATOR; + mi.fMask = MIIM_TYPE; + if (hMenu) + popupMenu.InsertItem(subIndex++, true, mi); + } + + const UInt32 contextMenuFlags = ci.Flags; + + NFind::CFileInfo fi0; + FString folderPrefix; + + if (_fileNames.Size() > 0) + { + const UString &fileName = _fileNames.Front(); + + #if defined(_WIN32) && !defined(UNDER_CE) + if (NName::IsDevicePath(us2fs(fileName))) + { + // CFileInfo::Find can be slow for device files. So we don't call it. + // we need only name here. + fi0.Name = us2fs(fileName.Ptr(NName::kDevicePathPrefixSize)); + folderPrefix = + #ifdef UNDER_CE + "\\"; + #else + "C:\\"; + #endif + } + else + #endif + { + if (!fi0.Find(us2fs(fileName))) + { + throw 20190820; + // return RETURN_WIN32_LastError_AS_HRESULT(); + } + GetOnlyDirPrefix(us2fs(fileName), folderPrefix); + } + } + + ODS("### 100") + + UString mainString; + CStringFinder finder; + UStringVector fileNames_Reduced; + const unsigned k_Explorer_NumReducedItems = 16; + const bool needReduce = !_isMenuForFM && (_fileNames.Size() >= k_Explorer_NumReducedItems); + _fileNames_WereReduced = needReduce; + // _fileNames_WereReduced = true; // for debug; + const UStringVector *fileNames = &_fileNames; + if (needReduce) + { + for (unsigned i = 0; i < k_Explorer_NumReducedItems + && i < _fileNames.Size(); i++) + fileNames_Reduced.Add(_fileNames[i]); + fileNames = &fileNames_Reduced; + } + + /* + if (_fileNames.Size() == k_Explorer_NumReducedItems) // for debug + { + for (int i = 0; i < 10; i++) + { + CCommandMapItem cmi; + AddCommand(kCompressToZipEmail, mainString, cmi); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + } + */ + + if (_fileNames.Size() == 1 && currentCommandID + 14 <= commandIDLast) + { + if (!fi0.IsDir() && DoNeedExtract(fs2us(fi0.Name), finder)) + { + // Open + const bool thereIsMainOpenItem = ((contextMenuFlags & NContextMenuFlags::kOpen) != 0); + if (thereIsMainOpenItem) + { + CCommandMapItem cmi; + AddCommand(kOpen, mainString, cmi); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0 + // && (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fi0.Name)) + && hMenu // we want to reduce number of menu items below 16 + ) + { + CMenu subMenu; + if (!hMenu || subMenu.CreatePopup()) + { + MyAddSubMenu(_commandMap, kOpenCascadedVerb, popupMenu, subIndex++, currentCommandID++, LangString(IDS_CONTEXT_OPEN), subMenu, bitmap); + _commandMap.Back().CtxCommandType = CtxCommandType_OpenRoot; + + UINT subIndex2 = 0; + for (unsigned i = (thereIsMainOpenItem ? 1 : 0); i < Z7_ARRAY_SIZE(kOpenTypes); i++) + { + CCommandMapItem cmi; + if (i == 0) + FillCommand(kOpen, mainString, cmi); + else + { + mainString = kOpenTypes[i]; + cmi.CommandInternalID = kOpen; + cmi.Verb = kMainVerb; + cmi.Verb += ".Open."; + cmi.Verb += mainString; + // cmi.HelpString = cmi.Verb; + cmi.ArcType = mainString; + cmi.CtxCommandType = CtxCommandType_OpenChild; + } + _commandMap.Add(cmi); + Set_UserString_in_LastCommand(mainString); + MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString, bitmap); + } + + subMenu.Detach(); + } + } + } + } + + ODS("### 150") + + if (_fileNames.Size() > 0 && currentCommandID + 10 <= commandIDLast) + { + ODS("### needExtract list START") + const bool needExtendedVerbs = ((flags & Z7_WIN_CMF_EXTENDEDVERBS) != 0); + // || _isMenuForFM; + bool needExtract = true; + bool areDirs = fi0.IsDir() || (unsigned)_attribs.FirstDirIndex < k_Explorer_NumReducedItems; + if (!needReduce) + areDirs = areDirs || (_attribs.FirstDirIndex != -1); + if (areDirs) + needExtract = false; + + if (!needExtendedVerbs) + if (needExtract) + { + UString name; + const unsigned numItemsCheck = fileNames->Size(); + for (unsigned i = 0; i < numItemsCheck; i++) + { + const UString &a = (*fileNames)[i]; + const int slash = a.ReverseFind_PathSepar(); + name = a.Ptr(slash + 1); + // for (int y = 0; y < 600; y++) // for debug + const bool needExtr2 = DoNeedExtract(name, finder); + if (!needExtr2) + { + needExtract = needExtr2; + break; + } + } + } + ODS("### needExtract list END") + + if (needExtract) + { + { + UString baseFolder = fs2us(folderPrefix); + if (_dropMode) + baseFolder = _dropPath; + + UString specFolder ('*'); + if (_fileNames.Size() == 1) + specFolder = GetSubFolderNameForExtract(fs2us(fi0.Name)); + specFolder.Add_PathSepar(); + + if ((contextMenuFlags & NContextMenuFlags::kExtract) != 0) + { + // Extract + CCommandMapItem cmi; + cmi.Folder = baseFolder + specFolder; + AddCommand(kExtract, mainString, cmi); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + + if ((contextMenuFlags & NContextMenuFlags::kExtractHere) != 0) + { + // Extract Here + CCommandMapItem cmi; + cmi.Folder = baseFolder; + AddCommand(kExtractHere, mainString, cmi); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + + if ((contextMenuFlags & NContextMenuFlags::kExtractTo) != 0) + { + // Extract To + CCommandMapItem cmi; + UString s; + cmi.Folder = baseFolder + specFolder; + AddCommand(kExtractTo, s, cmi); + MyFormatNew_ReducedName(s, specFolder); + Set_UserString_in_LastCommand(s); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + } + } + + if ((contextMenuFlags & NContextMenuFlags::kTest) != 0) + { + // Test + CCommandMapItem cmi; + AddCommand(kTest, mainString, cmi); + // if (_fileNames.Size() == 16) mainString += "_[16]"; // for debug + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + } + + ODS("### CreateArchiveName START") + UString arcName_base; + const UString arcName = CreateArchiveName( + *fileNames, + false, // isHash + fileNames->Size() == 1 ? &fi0 : NULL, + arcName_base); + ODS("### CreateArchiveName END") + UString arcName_Show = arcName; + if (needReduce) + { + /* we need same arcName_Show for two calls from Explorer: + 1) reduced call (only first 16 items) + 2) full call with all items (can be >= 16 items) + (fileNames) array was reduced to 16 items. + So we will have same (arcName) in both reduced and full calls. + If caller (Explorer) uses (reduce_to_first_16_items) scheme, + we can use (arcName) here instead of (arcName_base). + (arcName_base) has no number in name. + */ + arcName_Show = arcName_base; // we can comment that line + /* we use "_" in archive name as sign to user + that shows that final archive name can be changed. */ + arcName_Show += "_"; + } + + UString arcName_7z = arcName; + arcName_7z += ".7z"; + UString arcName_7z_Show = arcName_Show; + arcName_7z_Show += ".7z"; + UString arcName_zip = arcName; + arcName_zip += ".zip"; + UString arcName_zip_Show = arcName_Show; + arcName_zip_Show += ".zip"; + + + // Compress + if ((contextMenuFlags & NContextMenuFlags::kCompress) != 0) + { + CCommandMapItem cmi; + if (_dropMode) + cmi.Folder = _dropPath; + else + cmi.Folder = fs2us(folderPrefix); + cmi.ArcName = arcName; + AddCommand(kCompress, mainString, cmi); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + + #ifdef EMAIL_SUPPORT + // CompressEmail + if ((contextMenuFlags & NContextMenuFlags::kCompressEmail) != 0 && !_dropMode) + { + CCommandMapItem cmi; + cmi.ArcName = arcName; + AddCommand(kCompressEmail, mainString, cmi); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap); + } + #endif + + // CompressTo7z + if (contextMenuFlags & NContextMenuFlags::kCompressTo7z && + !arcName_7z.IsEqualTo_NoCase(fs2us(fi0.Name))) + { + CCommandMapItem cmi; + UString s; + if (_dropMode) + cmi.Folder = _dropPath; + else + cmi.Folder = fs2us(folderPrefix); + cmi.ArcName = arcName_7z; + cmi.ArcType = "7z"; + AddCommand(kCompressTo7z, s, cmi); + MyFormatNew_ReducedName(s, arcName_7z_Show); + Set_UserString_in_LastCommand(s); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + } + + #ifdef EMAIL_SUPPORT + // CompressTo7zEmail + if ((contextMenuFlags & NContextMenuFlags::kCompressTo7zEmail) != 0 && !_dropMode) + { + CCommandMapItem cmi; + UString s; + cmi.ArcName = arcName_7z; + cmi.ArcType = "7z"; + AddCommand(kCompressTo7zEmail, s, cmi); + MyFormatNew_ReducedName(s, arcName_7z_Show); + Set_UserString_in_LastCommand(s); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + } + #endif + + // CompressToZip + if (contextMenuFlags & NContextMenuFlags::kCompressToZip && + !arcName_zip.IsEqualTo_NoCase(fs2us(fi0.Name))) + { + CCommandMapItem cmi; + UString s; + if (_dropMode) + cmi.Folder = _dropPath; + else + cmi.Folder = fs2us(folderPrefix); + cmi.ArcName = arcName_zip; + cmi.ArcType = "zip"; + AddCommand(kCompressToZip, s, cmi); + MyFormatNew_ReducedName(s, arcName_zip_Show); + Set_UserString_in_LastCommand(s); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + } + + #ifdef EMAIL_SUPPORT + // CompressToZipEmail + if ((contextMenuFlags & NContextMenuFlags::kCompressToZipEmail) != 0 && !_dropMode) + { + CCommandMapItem cmi; + UString s; + cmi.ArcName = arcName_zip; + cmi.ArcType = "zip"; + AddCommand(kCompressToZipEmail, s, cmi); + MyFormatNew_ReducedName(s, arcName_zip_Show); + Set_UserString_in_LastCommand(s); + MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap); + } + #endif + } + + ODS("### 300") + + // don't use InsertMenu: See MSDN: + // PRB: Duplicate Menu Items In the File Menu For a Shell Context Menu Extension + // ID: Q214477 + + if (ci.Cascaded.Val) + { + CMenu menu; + menu.Attach(hMenu); + menuDestroyer.Disable(); + MyAddSubMenu(_commandMap, kMainVerb, menu, indexMenu++, currentCommandID++, (UString)"7-Zip", + popupMenu, // popupMenu.Detach(), + bitmap); + } + else + { + // popupMenu.Detach(); + indexMenu = subIndex; + } + + ODS("### 350") + + const bool needCrc = ((contextMenuFlags & + (NContextMenuFlags::kCRC | + NContextMenuFlags::kCRC_Cascaded)) != 0); + + if ( + // !_isMenuForFM && // 21.04: we don't hide CRC SHA menu in 7-Zip FM + needCrc + && currentCommandID + 1 < commandIDLast) + { + CMenu subMenu; + // CMenuDestroyer menuDestroyer_CRC; + + UINT subIndex_CRC = 0; + + if (!hMenu || subMenu.CreatePopup()) + { + // menuDestroyer_CRC.Attach(subMenu); + const bool insertHashMenuTo7zipMenu = (ci.Cascaded.Val + && (contextMenuFlags & NContextMenuFlags::kCRC_Cascaded) != 0); + + CMenu menu; + { + unsigned indexInParent; + if (insertHashMenuTo7zipMenu) + { + indexInParent = subIndex; + menu.Attach(popupMenu); + } + else + { + indexInParent = indexMenu; + menu.Attach(hMenu); + // menuDestroyer_CRC.Disable(); + } + MyAddSubMenu(_commandMap, kCheckSumCascadedVerb, menu, indexInParent++, currentCommandID++, (UString)"CRC SHA", subMenu, + /* insertHashMenuTo7zipMenu ? NULL : */ bitmap); + _commandMap.Back().CtxCommandType = CtxCommandType_CrcRoot; + if (!insertHashMenuTo7zipMenu) + indexMenu = indexInParent; + } + + ODS("### HashCommands") + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_HashCommands); i++) + { + if (currentCommandID >= commandIDLast) + break; + const CHashCommand &hc = g_HashCommands[i]; + CCommandMapItem cmi; + cmi.CommandInternalID = hc.CommandInternalID; + cmi.Verb = kCheckSumCascadedVerb; + cmi.Verb.Add_Dot(); + UString s; + s += hc.UserName; + + if (hc.CommandInternalID == kHash_Generate_SHA256) + { + cmi.Verb += "Generate"; + { + popupMenu.Attach(hMenu); + CMenuItem mi; + mi.fType = MFT_SEPARATOR; + mi.fMask = MIIM_TYPE; + subMenu.InsertItem(subIndex_CRC++, true, mi); + } + + UString name; + UString showName; + ODS("### Hash CreateArchiveName Start") + // for (int y = 0; y < 10000; y++) // for debug + // if (fileNames->Size() == 1) name = fs2us(fi0.Name); else + name = CreateArchiveName( + *fileNames, + true, // isHash + fileNames->Size() == 1 ? &fi0 : NULL, + showName); + if (needReduce) + showName += "_"; + else + showName = name; + + ODS("### Hash CreateArchiveName END") + name += ".sha256"; + showName += ".sha256"; + cmi.Folder = fs2us(folderPrefix); + cmi.ArcName = name; + s = "SHA-256 -> "; + s += showName; + } + else if (hc.CommandInternalID == kHash_TestArc) + { + cmi.Verb += "Test"; + s = LangStringAlt(IDS_CONTEXT_TEST, "Test archive"); + s += " : "; + s += GetNameOfProperty(kpidChecksum, UString("Checksum")); + } + else + cmi.Verb += "Calc"; + + cmi.Verb.Add_Dot(); + cmi.Verb += hc.MethodName; + + // cmi.HelpString = cmi.Verb; + cmi.UserString = s; + cmi.CtxCommandType = CtxCommandType_CrcChild; + _commandMap.Add(cmi); + MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, s, bitmap); + ODS("### 380") + } + + subMenu.Detach(); + } + } + + popupMenu.Detach(); + /* + if (!ci.Cascaded.Val) + indexMenu = subIndex; + */ + const unsigned numCommands = currentCommandID - commandIDFirst; + ODS("+ QueryContextMenu() END") + ODS_SPRF_s(sprintf(s, "Commands=%u currentCommandID - commandIDFirst = %u", + _commandMap.Size(), numCommands)) + if (_commandMap.Size() != numCommands) + throw 20190818; + /* + FOR_VECTOR (k, _commandMap) + { + ODS_U(_commandMap[k].Verb); + } + */ + } + catch(...) + { + ODS_SPRF_s(sprintf(s, "catch() exception: Commands=%u", _commandMap.Size())) + if (_commandMap.Size() == 0) + throw; + } + /* we added some menu items already : num_added_menu_items, + So we MUST return (number_of_defined_ids), where (number_of_defined_ids >= num_added_menu_items) + This will prevent incorrect menu working, when same IDs can be + assigned in multiple menu items from different subhandlers. + And we must add items to _commandMap before adding to menu. + */ + return MAKE_HRESULT_SUCCESS_FAC0(_commandMap.Size()); + COM_TRY_END +} + + +int CZipContextMenu::FindVerb(const UString &verb) const +{ + FOR_VECTOR (i, _commandMap) + if (_commandMap[i].Verb == verb) + return (int)i; + return -1; +} + +static UString Get7zFmPath() +{ + return fs2us(NWindows::NDLL::GetModuleDirPrefix()) + L"7zFM.exe"; +} + + +Z7_COMWF_B CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo) +{ + COM_TRY_BEGIN + + ODS("==== CZipContextMenu::InvokeCommand()") + + #ifdef SHOW_DEBUG_CTX_MENU + + ODS_SPRF_s(sprintf(s, ": InvokeCommand: cbSize=%u flags=%x ", + (unsigned)commandInfo->cbSize, (unsigned)commandInfo->fMask)) + + PrintStringA("Verb", commandInfo->lpVerb); + PrintStringA("Parameters", commandInfo->lpParameters); + PrintStringA("Directory", commandInfo->lpDirectory); + #endif + + int commandOffset = -1; + + // xp64 / Win10 : explorer.exe sends 0 in lpVerbW + // MSDN: if (IS_INTRESOURCE(lpVerbW)), we must use LOWORD(lpVerb) as command offset + + // FIXME: old MINGW doesn't define CMINVOKECOMMANDINFOEX / CMIC_MASK_UNICODE + #if !defined(UNDER_CE) && defined(CMIC_MASK_UNICODE) + bool unicodeVerb = false; + if (commandInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && + (commandInfo->fMask & CMIC_MASK_UNICODE) != 0) + { + LPCMINVOKECOMMANDINFOEX commandInfoEx = (LPCMINVOKECOMMANDINFOEX)commandInfo; + if (!MY_IS_INTRESOURCE(commandInfoEx->lpVerbW)) + { + unicodeVerb = true; + commandOffset = FindVerb(commandInfoEx->lpVerbW); + } + + #ifdef SHOW_DEBUG_CTX_MENU + PrintStringW("VerbW", commandInfoEx->lpVerbW); + PrintStringW("ParametersW", commandInfoEx->lpParametersW); + PrintStringW("DirectoryW", commandInfoEx->lpDirectoryW); + PrintStringW("TitleW", commandInfoEx->lpTitleW); + PrintStringA("Title", commandInfoEx->lpTitle); + #endif + } + if (!unicodeVerb) + #endif + { + ODS("use non-UNICODE verb") + // if (HIWORD(commandInfo->lpVerb) == 0) + if (MY_IS_INTRESOURCE(commandInfo->lpVerb)) + commandOffset = LOWORD(commandInfo->lpVerb); + else + commandOffset = FindVerb(GetUnicodeString(commandInfo->lpVerb)); + } + + ODS_SPRF_s(sprintf(s, "commandOffset=%d", commandOffset)) + + if (/* commandOffset < 0 || */ (unsigned)commandOffset >= _commandMap.Size()) + return E_INVALIDARG; + const CCommandMapItem &cmi = _commandMap[(unsigned)commandOffset]; + return InvokeCommandCommon(cmi); + COM_TRY_END +} + + +HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi) +{ + const enum_CommandInternalID cmdID = cmi.CommandInternalID; + + try + { + switch (cmdID) + { + case kOpen: + { + UString params; + params = GetQuotedString(_fileNames[0]); + if (!cmi.ArcType.IsEmpty()) + { + params += " -t"; + params += cmi.ArcType; + } + MyCreateProcess(Get7zFmPath(), params); + break; + } + case kExtract: + case kExtractHere: + case kExtractTo: + { + if (_attribs.FirstDirIndex != -1) + { + ShowErrorMessageRes(IDS_SELECT_FILES); + break; + } + ExtractArchives(_fileNames, cmi.Folder, + (cmdID == kExtract), // showDialog + (cmdID == kExtractTo) && _elimDup.Val, // elimDup + _writeZone + ); + break; + } + case kTest: + { + TestArchives(_fileNames); + break; + } + case kCompress: + case kCompressEmail: + case kCompressTo7z: + case kCompressTo7zEmail: + case kCompressToZip: + case kCompressToZipEmail: + { + UString arcName = cmi.ArcName; + if (_fileNames_WereReduced) + { + UString arcName_base; + arcName = CreateArchiveName( + _fileNames, + false, // isHash + NULL, // fi0 + arcName_base); + const char *postfix = NULL; + if (cmdID == kCompressTo7z || + cmdID == kCompressTo7zEmail) + postfix = ".7z"; + else if ( + cmdID == kCompressToZip || + cmdID == kCompressToZipEmail) + postfix = ".zip"; + if (postfix) + arcName += postfix; + } + + const bool email = + cmdID == kCompressEmail || + cmdID == kCompressTo7zEmail || + cmdID == kCompressToZipEmail; + const bool showDialog = + cmdID == kCompress || + cmdID == kCompressEmail; + const bool addExtension = showDialog; + CompressFiles(cmi.Folder, + arcName, cmi.ArcType, + addExtension, + _fileNames, email, showDialog, + false // waitFinish + ); + break; + } + + case kHash_CRC32: + case kHash_CRC64: + case kHash_XXH64: + case kHash_MD5: + case kHash_SHA1: + case kHash_SHA256: + case kHash_SHA384: + case kHash_SHA512: + case kHash_SHA3_256: + case kHash_BLAKE2SP: + case kHash_All: + case kHash_Generate_SHA256: + case kHash_TestArc: + { + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_HashCommands); i++) + { + const CHashCommand &hc = g_HashCommands[i]; + if (hc.CommandInternalID == cmdID) + { + if (cmdID == kHash_TestArc) + { + TestArchives(_fileNames, true); // hashMode + break; + } + UString generateName; + if (cmdID == kHash_Generate_SHA256) + { + generateName = cmi.ArcName; + if (_fileNames_WereReduced) + { + UString arcName_base; + generateName = CreateArchiveName(_fileNames, + true, // isHash + NULL, // fi0 + arcName_base); + generateName += ".sha256"; + } + } + CalcChecksum(_fileNames, (UString)hc.MethodName, + cmi.Folder, generateName); + break; + } + } + break; + } + case kCommandNULL: + break; + } + } + catch(...) + { + ShowErrorMessage(NULL, L"Error"); + } + return S_OK; +} + + + +static void MyCopyString_isUnicode(void *dest, UINT size, const UString &src, bool writeInUnicode) +{ + if (size != 0) + size--; + if (writeInUnicode) + { + UString s = src; + s.DeleteFrom(size); + MyStringCopy((wchar_t *)dest, s); + ODS_U(s) + } + else + { + AString s = GetAnsiString(src); + s.DeleteFrom(size); + MyStringCopy((char *)dest, s); + } +} + + +Z7_COMWF_B CZipContextMenu::GetCommandString( + #ifdef Z7_OLD_WIN_SDK + UINT + #else + UINT_PTR + #endif + commandOffset, + UINT uType, + UINT * /* pwReserved */ , LPSTR pszName, UINT cchMax) +{ + COM_TRY_BEGIN + + ODS("GetCommandString") + + const int cmdOffset = (int)commandOffset; + + ODS_SPRF_s(sprintf(s, "GetCommandString: cmdOffset=%d uType=%d cchMax = %d", + cmdOffset, uType, cchMax)) + + if ((uType | GCS_UNICODE) == GCS_VALIDATEW) + { + if (/* cmdOffset < 0 || */ (unsigned)cmdOffset >= _commandMap.Size()) + return S_FALSE; + return S_OK; + } + + if (/* cmdOffset < 0 || */ (unsigned)cmdOffset >= _commandMap.Size()) + { + ODS("------ cmdOffset: E_INVALIDARG") + return E_INVALIDARG; + } + + // we use Verb as HelpString + if (cchMax != 0) + if ((uType | GCS_UNICODE) == GCS_VERBW || + (uType | GCS_UNICODE) == GCS_HELPTEXTW) + { + const CCommandMapItem &cmi = _commandMap[(unsigned)cmdOffset]; + MyCopyString_isUnicode(pszName, cchMax, cmi.Verb, (uType & GCS_UNICODE) != 0); + return S_OK; + } + + return E_INVALIDARG; + + COM_TRY_END +} + + + +// ---------- IExplorerCommand ---------- + +static HRESULT WINAPI My_SHStrDupW(LPCWSTR src, LPWSTR *dest) +{ + if (src) + { + const SIZE_T size = (wcslen(src) + 1) * sizeof(WCHAR); + WCHAR *p = (WCHAR *)CoTaskMemAlloc(size); + if (p) + { + memcpy(p, src, size); + *dest = p; + return S_OK; + } + } + *dest = NULL; + return E_OUTOFMEMORY; +} + + +#define CZipExplorerCommand CZipContextMenu + +class CCoTaskWSTR +{ + LPWSTR m_str; + Z7_CLASS_NO_COPY(CCoTaskWSTR) +public: + CCoTaskWSTR(): m_str(NULL) {} + ~CCoTaskWSTR() { ::CoTaskMemFree(m_str); } + LPWSTR* operator&() { return &m_str; } + operator LPCWSTR () const { return m_str; } + // operator LPCOLESTR() const { return m_str; } + operator bool() const { return m_str != NULL; } + // bool operator!() const { return m_str == NULL; } + + /* + void Wipe_and_Free() + { + if (m_str) + { + memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str)); + Empty(); + } + } + */ + +private: + /* + CCoTaskWSTR(LPCOLESTR src) { m_str = ::CoTaskMemAlloc(src); } + + CCoTaskWSTR& operator=(LPCOLESTR src) + { + ::CoTaskMemFree(m_str); + m_str = ::SysAllocString(src); + return *this; + } + + + void Empty() + { + ::CoTaskMemFree(m_str); + m_str = NULL; + } + */ +}; + +static HRESULT LoadPaths(IShellItemArray *psiItemArray, UStringVector &paths) +{ + if (psiItemArray) + { + DWORD numItems = 0; + RINOK(psiItemArray->GetCount(&numItems)) + { + ODS_(Print_Number(numItems, " ==== LoadPaths START === ")) + for (DWORD i = 0; i < numItems; i++) + { + CMyComPtr item; + RINOK(psiItemArray->GetItemAt(i, &item)) + if (item) + { + CCoTaskWSTR displayName; + if (item->GetDisplayName(SIGDN_FILESYSPATH, &displayName) == S_OK + && (bool)displayName) + { + ODS_U(displayName) + paths.Add((LPCWSTR)displayName); + } + } + } + ODS_(Print_Number(numItems, " ==== LoadPaths END === ")) + } + } + return S_OK; +} + + +void CZipExplorerCommand::LoadItems(IShellItemArray *psiItemArray) +{ + SubCommands.Clear(); + _fileNames.Clear(); + { + UStringVector paths; + if (LoadPaths(psiItemArray, paths) != S_OK) + return; + _fileNames = paths; + } + const HRESULT res = QueryContextMenu( + NULL, // hMenu, + 0, // indexMenu, + 0, // commandIDFirst, + 0 + 999, // commandIDLast, + CMF_NORMAL); + + if (FAILED(res)) + return /* res */; + + CZipExplorerCommand *crcHandler = NULL; + CZipExplorerCommand *openHandler = NULL; + + bool useCascadedCrc = true; // false; + bool useCascadedOpen = true; // false; + + for (unsigned i = 0; i < _commandMap.Size(); i++) + { + const CCommandMapItem &cmi = _commandMap[i]; + + if (cmi.IsPopup) + if (!cmi.IsSubMenu()) + continue; + + // if (cmi.IsSubMenu()) continue // for debug + + CZipContextMenu *shellExt = new CZipContextMenu(); + shellExt->IsRoot = false; + + if (cmi.CtxCommandType == CtxCommandType_CrcRoot && !useCascadedCrc) + shellExt->IsSeparator = true; + + { + CZipExplorerCommand *handler = this; + if (cmi.CtxCommandType == CtxCommandType_CrcChild && crcHandler) + handler = crcHandler; + else if (cmi.CtxCommandType == CtxCommandType_OpenChild && openHandler) + handler = openHandler; + handler->SubCommands.AddNew() = shellExt; + } + + shellExt->_commandMap_Cur.Add(cmi); + + ODS_U(cmi.UserString) + + if (cmi.CtxCommandType == CtxCommandType_CrcRoot && useCascadedCrc) + crcHandler = shellExt; + if (cmi.CtxCommandType == CtxCommandType_OpenRoot && useCascadedOpen) + { + // ODS("cmi.CtxCommandType == CtxCommandType_OpenRoot"); + openHandler = shellExt; + } + } +} + + +Z7_COMWF_B CZipExplorerCommand::GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName) +{ + ODS("- GetTitle()") + // COM_TRY_BEGIN + if (IsSeparator) + { + *ppszName = NULL; + return S_FALSE; + } + + UString name; + if (IsRoot) + { + LoadItems(psiItemArray); + name = "7-Zip"; // "New" + } + else + name = "7-Zip item"; + + if (!_commandMap_Cur.IsEmpty()) + { + const CCommandMapItem &mi = _commandMap_Cur[0]; + // s += mi.Verb; + // s += " : "; + name = mi.UserString; + } + + return My_SHStrDupW(name, ppszName); + // return S_OK; + // COM_TRY_END +} + + +Z7_COMWF_B CZipExplorerCommand::GetIcon(IShellItemArray * /* psiItemArray */, LPWSTR *ppszIcon) +{ + ODS("- GetIcon()") + // COM_TRY_BEGIN + *ppszIcon = NULL; + // return E_NOTIMPL; + UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); + // imageName += "7zG.exe"; + imageName += "7-zip.dll"; + // imageName += ",190"; + return My_SHStrDupW(imageName, ppszIcon); + // COM_TRY_END +} + + +Z7_COMWF_B CZipExplorerCommand::GetToolTip (IShellItemArray * /* psiItemArray */, LPWSTR *ppszInfotip) +{ + // COM_TRY_BEGIN + ODS("- GetToolTip()") + *ppszInfotip = NULL; + return E_NOTIMPL; + // COM_TRY_END +} + + +Z7_COMWF_B CZipExplorerCommand::GetCanonicalName(GUID *pguidCommandName) +{ + // COM_TRY_BEGIN + ODS("- GetCanonicalName()") + *pguidCommandName = GUID_NULL; + return E_NOTIMPL; + // COM_TRY_END +} + + +Z7_COMWF_B CZipExplorerCommand::GetState(IShellItemArray * /* psiItemArray */, BOOL /* fOkToBeSlow */, EXPCMDSTATE *pCmdState) +{ + // COM_TRY_BEGIN + ODS("- GetState()") + *pCmdState = ECS_ENABLED; + return S_OK; + // COM_TRY_END +} + + + + +Z7_COMWF_B CZipExplorerCommand::Invoke(IShellItemArray *psiItemArray, IBindCtx * /* pbc */) +{ + COM_TRY_BEGIN + + if (_commandMap_Cur.IsEmpty()) + return E_INVALIDARG; + + ODS("- Invoke()") + _fileNames.Clear(); + UStringVector paths; + RINOK(LoadPaths(psiItemArray, paths)) + _fileNames = paths; + return InvokeCommandCommon(_commandMap_Cur[0]); + + COM_TRY_END +} + + +Z7_COMWF_B CZipExplorerCommand::GetFlags(EXPCMDFLAGS *pFlags) +{ + ODS("- GetFlags()") + // COM_TRY_BEGIN + EXPCMDFLAGS f = ECF_DEFAULT; + if (IsSeparator) + f = ECF_ISSEPARATOR; + else if (IsRoot) + f = ECF_HASSUBCOMMANDS; + else + { + if (!_commandMap_Cur.IsEmpty()) + { + // const CCommandMapItem &cmi = ; + if (_commandMap_Cur[0].IsSubMenu()) + { + // ODS("ECF_HASSUBCOMMANDS") + f = ECF_HASSUBCOMMANDS; + } + } + } + *pFlags = f; + return S_OK; + // COM_TRY_END +} + + +Z7_COMWF_B CZipExplorerCommand::EnumSubCommands(IEnumExplorerCommand **ppEnum) +{ + ODS("- EnumSubCommands()") + // COM_TRY_BEGIN + *ppEnum = NULL; + + if (!_commandMap_Cur.IsEmpty() && _commandMap_Cur[0].IsSubMenu()) + { + } + else + { + if (!IsRoot) + return E_NOTIMPL; + if (SubCommands.IsEmpty()) + { + return E_NOTIMPL; + } + } + + // shellExt-> + return QueryInterface(IID_IEnumExplorerCommand, (void **)ppEnum); + + // return S_OK; + // COM_TRY_END +} + + +Z7_COMWF_B CZipContextMenu::Next(ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) +{ + ODS("CZipContextMenu::Next()") + ODS_(Print_Number(celt, "celt")) + ODS_(Print_Number(CurrentSubCommand, "CurrentSubCommand")) + ODS_(Print_Number(SubCommands.Size(), "SubCommands.Size()")) + + COM_TRY_BEGIN + ULONG fetched = 0; + + ULONG i; + for (i = 0; i < celt; i++) + { + pUICommand[i] = NULL; + } + + for (i = 0; i < celt && CurrentSubCommand < SubCommands.Size(); i++) + { + pUICommand[i] = SubCommands[CurrentSubCommand++]; + pUICommand[i]->AddRef(); + fetched++; + } + + if (pceltFetched) + *pceltFetched = fetched; + + ODS(fetched == celt ? " === OK === " : "=== ERROR ===") + + // we return S_FALSE for (fetched == 0) + return (fetched == celt) ? S_OK : S_FALSE; + COM_TRY_END +} + + +Z7_COMWF_B CZipContextMenu::Skip(ULONG /* celt */) +{ + ODS("CZipContextMenu::Skip()") + return E_NOTIMPL; +} + + +Z7_COMWF_B CZipContextMenu::Reset(void) +{ + ODS("CZipContextMenu::Reset()") + CurrentSubCommand = 0; + return S_OK; +} + + +Z7_COMWF_B CZipContextMenu::Clone(IEnumExplorerCommand **ppenum) +{ + ODS("CZipContextMenu::Clone()") + *ppenum = NULL; + return E_NOTIMPL; +} diff --git a/CPP/7zip/UI/Explorer/ContextMenu.h b/CPP/7zip/UI/Explorer/ContextMenu.h index a6d5e7f91..2759967dd 100644 --- a/CPP/7zip/UI/Explorer/ContextMenu.h +++ b/CPP/7zip/UI/Explorer/ContextMenu.h @@ -1,169 +1,173 @@ -// ContextMenu.h - -#ifndef ZIP7_INC_CONTEXT_MENU_H -#define ZIP7_INC_CONTEXT_MENU_H - -#include "../../../Windows/Shell.h" - -#include "MyExplorerCommand.h" - -#include "../FileManager/MyCom2.h" - -#ifdef CMF_EXTENDEDVERBS -#define Z7_WIN_CMF_EXTENDEDVERBS CMF_EXTENDEDVERBS -#else -#define Z7_WIN_CMF_EXTENDEDVERBS 0x00000100 -#endif - -enum enum_CtxCommandType -{ - CtxCommandType_Normal, - CtxCommandType_OpenRoot, - CtxCommandType_OpenChild, - CtxCommandType_CrcRoot, - CtxCommandType_CrcChild -}; - - -class CZipContextMenu Z7_final: - public IContextMenu, - public IShellExtInit, - public IExplorerCommand, - public IEnumExplorerCommand, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_4_MT( - IContextMenu, - IShellExtInit, - IExplorerCommand, - IEnumExplorerCommand - ) - - // IShellExtInit - STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY hkeyProgID) Z7_override; - - // IContextMenu - STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) Z7_override; - STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici) Z7_override; - STDMETHOD(GetCommandString)( - #ifdef Z7_OLD_WIN_SDK - UINT - #else - UINT_PTR - #endif - idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) Z7_override; - - // IExplorerCommand - STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) Z7_override; - STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) Z7_override; - STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) Z7_override; - STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) Z7_override; - STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) Z7_override; - STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) Z7_override; - STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) Z7_override; - STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) Z7_override; - - // IEnumExplorerCommand - STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) Z7_override; - STDMETHOD (Skip) (ULONG celt) Z7_override; - STDMETHOD (Reset) (void) Z7_override; - STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) Z7_override; - -public: - - enum enum_CommandInternalID - { - kCommandNULL, - kOpen, - kExtract, - kExtractHere, - kExtractTo, - kTest, - kCompress, - kCompressEmail, - kCompressTo7z, - kCompressTo7zEmail, - kCompressToZip, - kCompressToZipEmail, - kHash_CRC32, - kHash_CRC64, - kHash_XXH64, - kHash_SHA1, - kHash_SHA256, - kHash_BLAKE2SP, - kHash_All, - kHash_Generate_SHA256, - kHash_TestArc - }; - -public: - void Init_For_7zFM() - { - // _isMenuForFM = true; - // _fileNames_WereReduced = false; - } - - void LoadItems(IShellItemArray *psiItemArray); - - CZipContextMenu(); - ~CZipContextMenu(); - - struct CCommandMapItem - { - enum_CommandInternalID CommandInternalID; - UString Verb; - UString UserString; - // UString HelpString; - UString Folder; - UString ArcName; - UString ArcType; - bool IsPopup; - enum_CtxCommandType CtxCommandType; - - CCommandMapItem(): - IsPopup(false), - CtxCommandType(CtxCommandType_Normal) - {} - - bool IsSubMenu() const - { - return - CtxCommandType == CtxCommandType_CrcRoot || - CtxCommandType == CtxCommandType_OpenRoot; - } - }; - - UStringVector _fileNames; - NWindows::NShell::CFileAttribs _attribs; - -private: - bool _isMenuForFM; - bool _fileNames_WereReduced; // = true, if only first 16 items were used in QueryContextMenu() - bool _dropMode; - UString _dropPath; - CObjectVector _commandMap; - CObjectVector _commandMap_Cur; - - HBITMAP _bitmap; - UInt32 _writeZone; - CBoolPair _elimDup; - - bool IsSeparator; - bool IsRoot; - CObjectVector< CMyComPtr > SubCommands; - unsigned CurrentSubCommand; - - void Set_UserString_in_LastCommand(const UString &s) - { - _commandMap.Back().UserString = s; - } - - int FindVerb(const UString &verb) const; - void FillCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) const; - void AddCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi); - void AddMapItem_ForSubMenu(const char *ver); - - HRESULT InvokeCommandCommon(const CCommandMapItem &cmi); -}; - -#endif +// ContextMenu.h + +#ifndef ZIP7_INC_CONTEXT_MENU_H +#define ZIP7_INC_CONTEXT_MENU_H + +#include "../../../Windows/Shell.h" + +#include "MyExplorerCommand.h" + +#include "../FileManager/MyCom2.h" + +#ifdef CMF_EXTENDEDVERBS +#define Z7_WIN_CMF_EXTENDEDVERBS CMF_EXTENDEDVERBS +#else +#define Z7_WIN_CMF_EXTENDEDVERBS 0x00000100 +#endif + +enum enum_CtxCommandType +{ + CtxCommandType_Normal, + CtxCommandType_OpenRoot, + CtxCommandType_OpenChild, + CtxCommandType_CrcRoot, + CtxCommandType_CrcChild +}; + + +class CZipContextMenu Z7_final: + public IContextMenu, + public IShellExtInit, + public IExplorerCommand, + public IEnumExplorerCommand, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_4_MT( + IContextMenu, + IShellExtInit, + IExplorerCommand, + IEnumExplorerCommand + ) + + // IShellExtInit + STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY hkeyProgID) Z7_override; + + // IContextMenu + STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) Z7_override; + STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici) Z7_override; + STDMETHOD(GetCommandString)( + #ifdef Z7_OLD_WIN_SDK + UINT + #else + UINT_PTR + #endif + idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) Z7_override; + + // IExplorerCommand + STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) Z7_override; + STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) Z7_override; + STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) Z7_override; + STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) Z7_override; + STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) Z7_override; + STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) Z7_override; + STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) Z7_override; + STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) Z7_override; + + // IEnumExplorerCommand + STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) Z7_override; + STDMETHOD (Skip) (ULONG celt) Z7_override; + STDMETHOD (Reset) (void) Z7_override; + STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) Z7_override; + +public: + + enum enum_CommandInternalID + { + kCommandNULL, + kOpen, + kExtract, + kExtractHere, + kExtractTo, + kTest, + kCompress, + kCompressEmail, + kCompressTo7z, + kCompressTo7zEmail, + kCompressToZip, + kCompressToZipEmail, + kHash_CRC32, + kHash_CRC64, + kHash_XXH64, + kHash_MD5, + kHash_SHA1, + kHash_SHA256, + kHash_SHA384, + kHash_SHA512, + kHash_SHA3_256, + kHash_BLAKE2SP, + kHash_All, + kHash_Generate_SHA256, + kHash_TestArc + }; + +public: + void Init_For_7zFM() + { + // _isMenuForFM = true; + // _fileNames_WereReduced = false; + } + + void LoadItems(IShellItemArray *psiItemArray); + + CZipContextMenu(); + ~CZipContextMenu(); + + struct CCommandMapItem + { + enum_CommandInternalID CommandInternalID; + UString Verb; + UString UserString; + // UString HelpString; + UString Folder; + UString ArcName; + UString ArcType; + bool IsPopup; + enum_CtxCommandType CtxCommandType; + + CCommandMapItem(): + IsPopup(false), + CtxCommandType(CtxCommandType_Normal) + {} + + bool IsSubMenu() const + { + return + CtxCommandType == CtxCommandType_CrcRoot || + CtxCommandType == CtxCommandType_OpenRoot; + } + }; + + UStringVector _fileNames; + NWindows::NShell::CFileAttribs _attribs; + +private: + bool _isMenuForFM; + bool _fileNames_WereReduced; // = true, if only first 16 items were used in QueryContextMenu() + bool _dropMode; + UString _dropPath; + CObjectVector _commandMap; + CObjectVector _commandMap_Cur; + + HBITMAP _bitmap; + UInt32 _writeZone; + CBoolPair _elimDup; + + bool IsSeparator; + bool IsRoot; + CObjectVector< CMyComPtr > SubCommands; + unsigned CurrentSubCommand; + + void Set_UserString_in_LastCommand(const UString &s) + { + _commandMap.Back().UserString = s; + } + + int FindVerb(const UString &verb) const; + void FillCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) const; + void AddCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi); + void AddMapItem_ForSubMenu(const char *ver); + + HRESULT InvokeCommandCommon(const CCommandMapItem &cmi); +}; + +#endif diff --git a/CPP/7zip/UI/Explorer/ContextMenuFlags.h b/CPP/7zip/UI/Explorer/ContextMenuFlags.h index 23b990d0d..50c177e9b 100644 --- a/CPP/7zip/UI/Explorer/ContextMenuFlags.h +++ b/CPP/7zip/UI/Explorer/ContextMenuFlags.h @@ -1,27 +1,27 @@ -// ContextMenuFlags.h - -#ifndef ZIP7_INC_CONTEXT_MENU_FLAGS_H -#define ZIP7_INC_CONTEXT_MENU_FLAGS_H - -namespace NContextMenuFlags -{ - const UInt32 kExtract = 1 << 0; - const UInt32 kExtractHere = 1 << 1; - const UInt32 kExtractTo = 1 << 2; - - const UInt32 kTest = 1 << 4; - const UInt32 kOpen = 1 << 5; - const UInt32 kOpenAs = 1 << 6; - - const UInt32 kCompress = 1 << 8; - const UInt32 kCompressTo7z = 1 << 9; - const UInt32 kCompressEmail = 1 << 10; - const UInt32 kCompressTo7zEmail = 1 << 11; - const UInt32 kCompressToZip = 1 << 12; - const UInt32 kCompressToZipEmail = 1 << 13; - - const UInt32 kCRC_Cascaded = (UInt32)1 << 30; - const UInt32 kCRC = (UInt32)1 << 31; -} - -#endif +// ContextMenuFlags.h + +#ifndef ZIP7_INC_CONTEXT_MENU_FLAGS_H +#define ZIP7_INC_CONTEXT_MENU_FLAGS_H + +namespace NContextMenuFlags +{ + const UInt32 kExtract = 1 << 0; + const UInt32 kExtractHere = 1 << 1; + const UInt32 kExtractTo = 1 << 2; + + const UInt32 kTest = 1 << 4; + const UInt32 kOpen = 1 << 5; + const UInt32 kOpenAs = 1 << 6; + + const UInt32 kCompress = 1 << 8; + const UInt32 kCompressTo7z = 1 << 9; + const UInt32 kCompressEmail = 1 << 10; + const UInt32 kCompressTo7zEmail = 1 << 11; + const UInt32 kCompressToZip = 1 << 12; + const UInt32 kCompressToZipEmail = 1 << 13; + + const UInt32 kCRC_Cascaded = (UInt32)1 << 30; + const UInt32 kCRC = (UInt32)1 << 31; +} + +#endif diff --git a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp index 5699b3821..c92c983d3 100644 --- a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp +++ b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp @@ -1,268 +1,268 @@ -// DLLExportsExplorer.cpp -// -// Notes: -// Win2000: -// If I register at HKCR\Folder\ShellEx then DLL is locked. -// otherwise it unloads after explorer closing. -// but if I call menu for desktop items it's locked all the time - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#if defined(__clang__) && __clang_major__ >= 4 -#pragma GCC diagnostic ignored "-Wnonportable-system-include-path" -#endif -// : in new Windows Kit 10.0.2**** (NTDDI_WIN10_MN is defined) -// : in another Windows Kit versions -#if defined(NTDDI_WIN10_MN) || defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/ComTry.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/NtCheck.h" -#include "../../../Windows/Registry.h" - -#include "../FileManager/IFolder.h" - -#include "ContextMenu.h" - -static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension"); -static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"); - -// {23170F69-40C1-278A-1000-000100020000} -static LPCTSTR const k_Clsid = TEXT("{23170F69-40C1-278A-1000-000100020000}"); - -Z7_DEFINE_GUID(CLSID_CZipContextMenu, - k_7zip_GUID_Data1, - k_7zip_GUID_Data2, - k_7zip_GUID_Data3_Common, - 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00); - -using namespace NWindows; - -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance = NULL; - -extern -HWND g_HWND; -HWND g_HWND = NULL; - -extern -LONG g_DllRefCount; -LONG g_DllRefCount = 0; // Reference count of this DLL. - -extern -bool g_DisableUserQuestions; -bool g_DisableUserQuestions; - - -// #define ODS(sz) OutputDebugStringW(L#sz) -#define ODS(sz) - -class CShellExtClassFactory Z7_final: - public IClassFactory, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1_MT(IClassFactory) - - STDMETHOD(CreateInstance)(LPUNKNOWN, REFIID, void**) Z7_override Z7_final; - STDMETHOD(LockServer)(BOOL) Z7_override Z7_final; -public: - CShellExtClassFactory() { InterlockedIncrement(&g_DllRefCount); } - ~CShellExtClassFactory() { InterlockedDecrement(&g_DllRefCount); } -}; - -Z7_COMWF_B CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, - REFIID riid, void **ppvObj) -{ - ODS("CShellExtClassFactory::CreateInstance()\r\n"); - /* - char s[64]; - ConvertUInt32ToHex(riid.Data1, s); - OutputDebugStringA(s); - */ - *ppvObj = NULL; - if (pUnkOuter) - return CLASS_E_NOAGGREGATION; - - CZipContextMenu *shellExt; - try - { - shellExt = new CZipContextMenu(); - } - catch(...) { return E_OUTOFMEMORY; } - if (!shellExt) - return E_OUTOFMEMORY; - - IContextMenu *ctxm = shellExt; - const HRESULT res = ctxm->QueryInterface(riid, ppvObj); - if (res != S_OK) - delete shellExt; - return res; -} - - -Z7_COMWF_B CShellExtClassFactory::LockServer(BOOL /* fLock */) -{ - return S_OK; // Check it -} - - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION return FALSE; -#endif - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE hInstance - #else - HINSTANCE hInstance - #endif - , DWORD dwReason, LPVOID); - -extern "C" -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE hInstance - #else - HINSTANCE hInstance - #endif - , DWORD dwReason, LPVOID) -{ - if (dwReason == DLL_PROCESS_ATTACH) - { - g_hInstance = (HINSTANCE)hInstance; - ODS("In DLLMain, DLL_PROCESS_ATTACH\r\n"); - NT_CHECK - } - else if (dwReason == DLL_PROCESS_DETACH) - { - ODS("In DLLMain, DLL_PROCESS_DETACH\r\n"); - } - return TRUE; -} - - -// Used to determine whether the DLL can be unloaded by OLE - -STDAPI DllCanUnloadNow(void) -{ - ODS("In DLLCanUnloadNow\r\n"); - /* - if (g_DllRefCount == 0) - ODS( "g_DllRefCount == 0"); - else - ODS( "g_DllRefCount != 0"); - */ - return (g_DllRefCount == 0 ? S_OK : S_FALSE); -} - -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) -{ - ODS("In DllGetClassObject\r\n"); - *ppv = NULL; - if (IsEqualIID(rclsid, CLSID_CZipContextMenu)) - { - CShellExtClassFactory *cf; - try - { - cf = new CShellExtClassFactory; - } - catch(...) { return E_OUTOFMEMORY; } - if (!cf) - return E_OUTOFMEMORY; - IClassFactory *cf2 = cf; - const HRESULT res = cf2->QueryInterface(riid, ppv); - if (res != S_OK) - delete cf; - return res; - } - return CLASS_E_CLASSNOTAVAILABLE; - // return _Module.GetClassObject(rclsid, riid, ppv); -} - - -static BOOL RegisterServer() -{ - ODS("RegisterServer\r\n"); - FString modulePath; - if (!NDLL::MyGetModuleFileName(modulePath)) - return FALSE; - const UString modulePathU = fs2us(modulePath); - - CSysString s ("CLSID\\"); - s += k_Clsid; - - { - NRegistry::CKey key; - if (key.Create(HKEY_CLASSES_ROOT, s, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR) - return FALSE; - key.SetValue(NULL, k_ShellExtName); - NRegistry::CKey keyInproc; - if (keyInproc.Create(key, TEXT("InprocServer32"), NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR) - return FALSE; - keyInproc.SetValue(NULL, modulePathU); - keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment")); - } - - #if !defined(_WIN64) && !defined(UNDER_CE) - if (IsItWindowsNT()) - #endif - { - NRegistry::CKey key; - if (key.Create(HKEY_LOCAL_MACHINE, k_Approved, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) == NOERROR) - key.SetValue(k_Clsid, k_ShellExtName); - } - - ODS("RegisterServer :: return TRUE"); - return TRUE; -} - -STDAPI DllRegisterServer(void) -{ - return RegisterServer() ? S_OK: SELFREG_E_CLASS; -} - -static BOOL UnregisterServer() -{ - CSysString s ("CLSID\\"); - s += k_Clsid; - - RegDeleteKey(HKEY_CLASSES_ROOT, s + TEXT("\\InprocServer32")); - RegDeleteKey(HKEY_CLASSES_ROOT, s); - - #if !defined(_WIN64) && !defined(UNDER_CE) - if (IsItWindowsNT()) - #endif - { - HKEY hKey; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, k_Approved, 0, KEY_SET_VALUE, &hKey) == NOERROR) - { - RegDeleteValue(hKey, k_Clsid); - RegCloseKey(hKey); - } - } - - return TRUE; -} - -STDAPI DllUnregisterServer(void) -{ - return UnregisterServer() ? S_OK: SELFREG_E_CLASS; -} +// DLLExportsExplorer.cpp +// +// Notes: +// Win2000: +// If I register at HKCR\Folder\ShellEx then DLL is locked. +// otherwise it unloads after explorer closing. +// but if I call menu for desktop items it's locked all the time + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#if defined(__clang__) && __clang_major__ >= 4 +#pragma GCC diagnostic ignored "-Wnonportable-system-include-path" +#endif +// : in new Windows Kit 10.0.2**** (NTDDI_WIN10_MN is defined) +// : in another Windows Kit versions +#if defined(NTDDI_WIN10_MN) || defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/ComTry.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/NtCheck.h" +#include "../../../Windows/Registry.h" + +#include "../FileManager/IFolder.h" + +#include "ContextMenu.h" + +static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension"); +static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"); + +// {23170F69-40C1-278A-1000-000100020000} +static LPCTSTR const k_Clsid = TEXT("{23170F69-40C1-278A-1000-000100020000}"); + +Z7_DEFINE_GUID(CLSID_CZipContextMenu, + k_7zip_GUID_Data1, + k_7zip_GUID_Data2, + k_7zip_GUID_Data3_Common, + 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00); + +using namespace NWindows; + +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance = NULL; + +extern +HWND g_HWND; +HWND g_HWND = NULL; + +extern +LONG g_DllRefCount; +LONG g_DllRefCount = 0; // Reference count of this DLL. + +extern +bool g_DisableUserQuestions; +bool g_DisableUserQuestions; + + +// #define ODS(sz) OutputDebugStringW(L#sz) +#define ODS(sz) + +class CShellExtClassFactory Z7_final: + public IClassFactory, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1_MT(IClassFactory) + + STDMETHOD(CreateInstance)(LPUNKNOWN, REFIID, void**) Z7_override Z7_final; + STDMETHOD(LockServer)(BOOL) Z7_override Z7_final; +public: + CShellExtClassFactory() { InterlockedIncrement(&g_DllRefCount); } + ~CShellExtClassFactory() { InterlockedDecrement(&g_DllRefCount); } +}; + +Z7_COMWF_B CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, + REFIID riid, void **ppvObj) +{ + ODS("CShellExtClassFactory::CreateInstance()\r\n"); + /* + char s[64]; + ConvertUInt32ToHex(riid.Data1, s); + OutputDebugStringA(s); + */ + *ppvObj = NULL; + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + CZipContextMenu *shellExt; + try + { + shellExt = new CZipContextMenu(); + } + catch(...) { return E_OUTOFMEMORY; } + if (!shellExt) + return E_OUTOFMEMORY; + + IContextMenu *ctxm = shellExt; + const HRESULT res = ctxm->QueryInterface(riid, ppvObj); + if (res != S_OK) + delete shellExt; + return res; +} + + +Z7_COMWF_B CShellExtClassFactory::LockServer(BOOL /* fLock */) +{ + return S_OK; // Check it +} + + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION return FALSE; +#endif + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE hInstance + #else + HINSTANCE hInstance + #endif + , DWORD dwReason, LPVOID); + +extern "C" +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE hInstance + #else + HINSTANCE hInstance + #endif + , DWORD dwReason, LPVOID) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hInstance = (HINSTANCE)hInstance; + ODS("In DLLMain, DLL_PROCESS_ATTACH\r\n"); + NT_CHECK + } + else if (dwReason == DLL_PROCESS_DETACH) + { + ODS("In DLLMain, DLL_PROCESS_DETACH\r\n"); + } + return TRUE; +} + + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) +{ + ODS("In DLLCanUnloadNow\r\n"); + /* + if (g_DllRefCount == 0) + ODS( "g_DllRefCount == 0"); + else + ODS( "g_DllRefCount != 0"); + */ + return (g_DllRefCount == 0 ? S_OK : S_FALSE); +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + ODS("In DllGetClassObject\r\n"); + *ppv = NULL; + if (IsEqualIID(rclsid, CLSID_CZipContextMenu)) + { + CShellExtClassFactory *cf; + try + { + cf = new CShellExtClassFactory; + } + catch(...) { return E_OUTOFMEMORY; } + if (!cf) + return E_OUTOFMEMORY; + IClassFactory *cf2 = cf; + const HRESULT res = cf2->QueryInterface(riid, ppv); + if (res != S_OK) + delete cf; + return res; + } + return CLASS_E_CLASSNOTAVAILABLE; + // return _Module.GetClassObject(rclsid, riid, ppv); +} + + +static BOOL RegisterServer() +{ + ODS("RegisterServer\r\n"); + FString modulePath; + if (!NDLL::MyGetModuleFileName(modulePath)) + return FALSE; + const UString modulePathU = fs2us(modulePath); + + CSysString s ("CLSID\\"); + s += k_Clsid; + + { + NRegistry::CKey key; + if (key.Create(HKEY_CLASSES_ROOT, s, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR) + return FALSE; + key.SetValue(NULL, k_ShellExtName); + NRegistry::CKey keyInproc; + if (keyInproc.Create(key, TEXT("InprocServer32"), NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR) + return FALSE; + keyInproc.SetValue(NULL, modulePathU); + keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment")); + } + + #if !defined(_WIN64) && !defined(UNDER_CE) + if (IsItWindowsNT()) + #endif + { + NRegistry::CKey key; + if (key.Create(HKEY_LOCAL_MACHINE, k_Approved, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) == NOERROR) + key.SetValue(k_Clsid, k_ShellExtName); + } + + ODS("RegisterServer :: return TRUE"); + return TRUE; +} + +STDAPI DllRegisterServer(void) +{ + return RegisterServer() ? S_OK: SELFREG_E_CLASS; +} + +static BOOL UnregisterServer() +{ + CSysString s ("CLSID\\"); + s += k_Clsid; + + RegDeleteKey(HKEY_CLASSES_ROOT, s + TEXT("\\InprocServer32")); + RegDeleteKey(HKEY_CLASSES_ROOT, s); + + #if !defined(_WIN64) && !defined(UNDER_CE) + if (IsItWindowsNT()) + #endif + { + HKEY hKey; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, k_Approved, 0, KEY_SET_VALUE, &hKey) == NOERROR) + { + RegDeleteValue(hKey, k_Clsid); + RegCloseKey(hKey); + } + } + + return TRUE; +} + +STDAPI DllUnregisterServer(void) +{ + return UnregisterServer() ? S_OK: SELFREG_E_CLASS; +} diff --git a/CPP/7zip/UI/Explorer/Explorer.def b/CPP/7zip/UI/Explorer/Explorer.def index 5374c3739..034a269d7 100644 --- a/CPP/7zip/UI/Explorer/Explorer.def +++ b/CPP/7zip/UI/Explorer/Explorer.def @@ -1,9 +1,9 @@ -; 7-zip.def - -LIBRARY "7-zip" - -EXPORTS - DllCanUnloadNow PRIVATE - DllGetClassObject PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE +; 7-zip.def + +LIBRARY "7-zip" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/CPP/7zip/UI/Explorer/Explorer.dsp b/CPP/7zip/UI/Explorer/Explorer.dsp index 78cd9f578..2ed491f41 100644 --- a/CPP/7zip/UI/Explorer/Explorer.dsp +++ b/CPP/7zip/UI/Explorer/Explorer.dsp @@ -1,620 +1,620 @@ -# Microsoft Developer Studio Project File - Name="Explorer" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=Explorer - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Explorer.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Explorer.mak" CFG="Explorer - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Explorer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Explorer - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Explorer - Win32 ReleaseU" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Explorer - Win32 DebugU" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Explorer - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /FAcs /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Explorer - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept - -!ELSEIF "$(CFG)" == "Explorer - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseU" -# PROP BASE Intermediate_Dir "ReleaseU" -# PROP BASE Ignore_Export_Lib 1 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "_MBCS" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /opt:NOWIN98 -# SUBTRACT BASE LINK32 /pdb:none -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Explorer - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "DebugU" -# PROP BASE Intermediate_Dir "DebugU" -# PROP BASE Ignore_Export_Lib 1 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "Explorer - Win32 Release" -# Name "Explorer - Win32 Debug" -# Name "Explorer - Win32 ReleaseU" -# Name "Explorer - Win32 DebugU" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\DllExportsExplorer.cpp -# End Source File -# Begin Source File - -SOURCE=.\Explorer.def -# End Source File -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Common\ArchiveName.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveName.h -# End Source File -# Begin Source File - -SOURCE=..\Common\CompressCall.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\CompressCall.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.h -# End Source File -# End Group -# Begin Group "Engine" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\ContextMenu.cpp -# End Source File -# Begin Source File - -SOURCE=.\ContextMenu.h -# End Source File -# Begin Source File - -SOURCE=.\MyExplorerCommand.h -# End Source File -# Begin Source File - -SOURCE=.\MyMessages.cpp -# End Source File -# Begin Source File - -SOURCE=.\MyMessages.h -# End Source File -# End Group -# Begin Group "FileManager" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\FileManager\FormatUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\FormatUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\HelpUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\HelpUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\IFolder.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\LangUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\LangUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\MyCom2.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgramLocation.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgramLocation.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\PropertyName.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\PropertyName.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\RegistryUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\RegistryUtils.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Random.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Random.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Types.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Group "Control" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\PropertyPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\PropertyPage.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\Windows\COM.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Menu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Menu.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ProcessUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ProcessUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.h -# End Source File -# End Group -# Begin Source File - -SOURCE=".\7-zip.dll.manifest" -# End Source File -# Begin Source File - -SOURCE=.\ContextMenuFlags.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\FM.ico -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="Explorer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Explorer - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Explorer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Explorer.mak" CFG="Explorer - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Explorer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Explorer - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Explorer - Win32 ReleaseU" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Explorer - Win32 DebugU" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Explorer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /FAcs /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Explorer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept + +!ELSEIF "$(CFG)" == "Explorer - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Ignore_Export_Lib 1 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "_MBCS" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /opt:NOWIN98 +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Explorer - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Ignore_Export_Lib 1 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Explorer - Win32 Release" +# Name "Explorer - Win32 Debug" +# Name "Explorer - Win32 ReleaseU" +# Name "Explorer - Win32 DebugU" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\DllExportsExplorer.cpp +# End Source File +# Begin Source File + +SOURCE=.\Explorer.def +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Common\ArchiveName.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveName.h +# End Source File +# Begin Source File + +SOURCE=..\Common\CompressCall.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\CompressCall.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.h +# End Source File +# End Group +# Begin Group "Engine" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ContextMenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\ContextMenu.h +# End Source File +# Begin Source File + +SOURCE=.\MyExplorerCommand.h +# End Source File +# Begin Source File + +SOURCE=.\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=.\MyMessages.h +# End Source File +# End Group +# Begin Group "FileManager" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\FileManager\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\FormatUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\HelpUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\HelpUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\IFolder.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\LangUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\LangUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\MyCom2.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgramLocation.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgramLocation.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PropertyName.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PropertyName.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\RegistryUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\RegistryUtils.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Types.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\PropertyPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\PropertyPage.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\COM.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Menu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Menu.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ProcessUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ProcessUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Source File + +SOURCE=".\7-zip.dll.manifest" +# End Source File +# Begin Source File + +SOURCE=.\ContextMenuFlags.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\FM.ico +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/UI/Explorer/Explorer.dsw b/CPP/7zip/UI/Explorer/Explorer.dsw index 38275b184..beb8df7bc 100644 --- a/CPP/7zip/UI/Explorer/Explorer.dsw +++ b/CPP/7zip/UI/Explorer/Explorer.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Explorer"=".\Explorer.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Explorer"=".\Explorer.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/UI/Explorer/MyExplorerCommand.h b/CPP/7zip/UI/Explorer/MyExplorerCommand.h index 99184294c..41ac8d67d 100644 --- a/CPP/7zip/UI/Explorer/MyExplorerCommand.h +++ b/CPP/7zip/UI/Explorer/MyExplorerCommand.h @@ -1,217 +1,217 @@ -// MyExplorerCommand.h - -#ifndef ZIP7_INC_MY_EXPLORER_COMMAND_H -#define ZIP7_INC_MY_EXPLORER_COMMAND_H - -#if _MSC_VER >= 1910 -#define USE_SYS_shobjidl_core -#endif - -#ifdef USE_SYS_shobjidl_core - -// #include - -#else - -/* IShellItem is defined: - ShObjIdl.h : old Windows SDK - ShObjIdl_core.h : new Windows 10 SDK */ - -#ifndef Z7_OLD_WIN_SDK -#include -#endif - -#ifndef __IShellItem_INTERFACE_DEFINED__ -#define __IShellItem_INTERFACE_DEFINED__ - -// For MINGW we define IShellItem - -// #error Stop_Compiling__NOT_DEFINED__IShellItem_INTERFACE_DEFINED__ - -typedef -enum -{ SIGDN_NORMALDISPLAY = 0, - SIGDN_PARENTRELATIVEPARSING = 0x80018001, - SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001, - SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, - SIGDN_PARENTRELATIVEEDITING = 0x80031001, - SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, - SIGDN_FILESYSPATH = 0x80058000, - SIGDN_URL = 0x80068000 -} SIGDN; - - -typedef DWORD SICHINTF; -typedef ULONG SFGAOF; - -struct IShellItem : public IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) = 0; - virtual HRESULT STDMETHODCALLTYPE GetParent(IShellItem **ppsi) = 0; - virtual HRESULT STDMETHODCALLTYPE GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName) = 0; - virtual HRESULT STDMETHODCALLTYPE GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0; - virtual HRESULT STDMETHODCALLTYPE Compare(IShellItem *psi, SICHINTF hint, int *piOrder) = 0; -}; - -#endif // __IShellItem_INTERFACE_DEFINED__ - - - -#ifndef __IShellItemArray_INTERFACE_DEFINED__ -#define __IShellItemArray_INTERFACE_DEFINED__ - -// propsys.h - -typedef /* [v1_enum] */ -enum GETPROPERTYSTOREFLAGS -{ - GPS_DEFAULT = 0, - GPS_HANDLERPROPERTIESONLY = 0x1, - GPS_READWRITE = 0x2, - GPS_TEMPORARY = 0x4, - GPS_FASTPROPERTIESONLY = 0x8, - GPS_OPENSLOWITEM = 0x10, - GPS_DELAYCREATION = 0x20, - GPS_BESTEFFORT = 0x40, - GPS_NO_OPLOCK = 0x80, - GPS_PREFERQUERYPROPERTIES = 0x100, - GPS_EXTRINSICPROPERTIES = 0x200, - GPS_EXTRINSICPROPERTIESONLY = 0x400, - GPS_VOLATILEPROPERTIES = 0x800, - GPS_VOLATILEPROPERTIESONLY = 0x1000, - GPS_MASK_VALID = 0x1fff -} GETPROPERTYSTOREFLAGS; - -// DEFINE_ENUM_FLAG_OPERATORS(GETPROPERTYSTOREFLAGS) - - -#ifndef PROPERTYKEY_DEFINED -#define PROPERTYKEY_DEFINED - -typedef -struct -{ - GUID fmtid; - DWORD pid; -} PROPERTYKEY; - -#endif // PROPERTYKEY_DEFINED - -// propkeydef.h -#define REFPROPERTYKEY const PROPERTYKEY & - -#ifdef INITGUID -#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } -#else -#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name -#endif // INITGUID - - -// -typedef /* [v1_enum] */ -enum SIATTRIBFLAGS -{ - SIATTRIBFLAGS_AND = 0x1, - SIATTRIBFLAGS_OR = 0x2, - SIATTRIBFLAGS_APPCOMPAT = 0x3, - SIATTRIBFLAGS_MASK = 0x3, - SIATTRIBFLAGS_ALLITEMS = 0x4000 -} SIATTRIBFLAGS; - -// DEFINE_ENUM_FLAG_OPERATORS(SIATTRIBFLAGS) - - -// MIDL_INTERFACE("70629033-e363-4a28-a567-0db78006e6d7") -DEFINE_GUID(IID_IEnumShellItems, 0x70629033, 0xe363, 0xe363, 0xa5, 0x67, 0x0d, 0xb7, 0x80, 0x06, 0xe6, 0xd7); - -struct IEnumShellItems : public IUnknown -{ - STDMETHOD (Next) (ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) = 0; - STDMETHOD (Skip) (ULONG celt) = 0; - STDMETHOD (Reset) (void) = 0; - STDMETHOD (Clone) (IEnumShellItems **ppenum) = 0; -}; - - -// MIDL_INTERFACE("b63ea76d-1f85-456f-a19c-48159efa858b") -DEFINE_GUID(IID_IShellItemArray, 0xb63ea76d, 0x1f85, 0x456f, 0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b); - -struct IShellItemArray : public IUnknown -{ - STDMETHOD (BindToHandler) (IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut) = 0; - STDMETHOD (GetPropertyStore) (GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) = 0; - STDMETHOD (GetPropertyDescriptionList) (REFPROPERTYKEY keyType, REFIID riid, void **ppv) = 0; - STDMETHOD (GetAttributes) ( SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0; - STDMETHOD (GetCount) (DWORD *pdwNumItems) = 0; - STDMETHOD (GetItemAt) (DWORD dwIndex, IShellItem **ppsi) = 0; - STDMETHOD (EnumItems) (IEnumShellItems **ppenumShellItems) = 0; -}; - - -#ifndef __IEnumExplorerCommand_INTERFACE_DEFINED__ -#define __IEnumExplorerCommand_INTERFACE_DEFINED__ - -struct IExplorerCommand; - -// MIDL_INTERFACE("a88826f8-186f-4987-aade-ea0cef8fbfe8") -DEFINE_GUID(IID_IEnumExplorerCommand , 0xa88826f8, 0x186f, 0x4987, 0xaa, 0xde, 0xea, 0x0c, 0xef, 0x8f, 0xbf, 0xe8); - -struct IEnumExplorerCommand : public IUnknown -{ - STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) = 0; - STDMETHOD (Skip) (ULONG celt) = 0; - STDMETHOD (Reset) (void) = 0; - STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) = 0; -}; - - -enum _EXPCMDSTATE -{ - ECS_ENABLED = 0, - ECS_DISABLED = 0x1, - ECS_HIDDEN = 0x2, - ECS_CHECKBOX = 0x4, - ECS_CHECKED = 0x8, - ECS_RADIOCHECK = 0x10 -}; - -typedef DWORD EXPCMDSTATE; - -/* [v1_enum] */ -enum _EXPCMDFLAGS -{ - ECF_DEFAULT = 0, - ECF_HASSUBCOMMANDS = 0x1, - ECF_HASSPLITBUTTON = 0x2, - ECF_HIDELABEL = 0x4, - ECF_ISSEPARATOR = 0x8, - ECF_HASLUASHIELD = 0x10, - ECF_SEPARATORBEFORE = 0x20, - ECF_SEPARATORAFTER = 0x40, - ECF_ISDROPDOWN = 0x80, - ECF_TOGGLEABLE = 0x100, - ECF_AUTOMENUICONS = 0x200 -}; -typedef DWORD EXPCMDFLAGS; - - -// MIDL_INTERFACE("a08ce4d0-fa25-44ab-b57c-c7b1c323e0b9") -DEFINE_GUID(IID_IExplorerCommand, 0xa08ce4d0, 0xfa25, 0x44ab, 0xb5, 0x7c, 0xc7, 0xb1, 0xc3, 0x23, 0xe0, 0xb9); - -struct IExplorerCommand : public IUnknown -{ - STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) = 0; - STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) = 0; - STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) = 0; - STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) = 0; - STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) = 0; - STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) = 0; - STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) = 0; - STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) = 0; -}; - -#endif // IShellItemArray -#endif // __IEnumExplorerCommand_INTERFACE_DEFINED__ -#endif // USE_SYS_shobjidl_core - -#endif // __MY_EXPLORER_COMMAND_H +// MyExplorerCommand.h + +#ifndef ZIP7_INC_MY_EXPLORER_COMMAND_H +#define ZIP7_INC_MY_EXPLORER_COMMAND_H + +#if _MSC_VER >= 1910 +#define USE_SYS_shobjidl_core +#endif + +#ifdef USE_SYS_shobjidl_core + +// #include + +#else + +/* IShellItem is defined: + ShObjIdl.h : old Windows SDK + ShObjIdl_core.h : new Windows 10 SDK */ + +#ifndef Z7_OLD_WIN_SDK +#include +#endif + +#ifndef __IShellItem_INTERFACE_DEFINED__ +#define __IShellItem_INTERFACE_DEFINED__ + +// For MINGW we define IShellItem + +// #error Stop_Compiling__NOT_DEFINED__IShellItem_INTERFACE_DEFINED__ + +typedef +enum +{ SIGDN_NORMALDISPLAY = 0, + SIGDN_PARENTRELATIVEPARSING = 0x80018001, + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, + SIGDN_PARENTRELATIVEEDITING = 0x80031001, + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, + SIGDN_FILESYSPATH = 0x80058000, + SIGDN_URL = 0x80068000 +} SIGDN; + + +typedef DWORD SICHINTF; +typedef ULONG SFGAOF; + +struct IShellItem : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) = 0; + virtual HRESULT STDMETHODCALLTYPE GetParent(IShellItem **ppsi) = 0; + virtual HRESULT STDMETHODCALLTYPE GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName) = 0; + virtual HRESULT STDMETHODCALLTYPE GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0; + virtual HRESULT STDMETHODCALLTYPE Compare(IShellItem *psi, SICHINTF hint, int *piOrder) = 0; +}; + +#endif // __IShellItem_INTERFACE_DEFINED__ + + + +#ifndef __IShellItemArray_INTERFACE_DEFINED__ +#define __IShellItemArray_INTERFACE_DEFINED__ + +// propsys.h + +typedef /* [v1_enum] */ +enum GETPROPERTYSTOREFLAGS +{ + GPS_DEFAULT = 0, + GPS_HANDLERPROPERTIESONLY = 0x1, + GPS_READWRITE = 0x2, + GPS_TEMPORARY = 0x4, + GPS_FASTPROPERTIESONLY = 0x8, + GPS_OPENSLOWITEM = 0x10, + GPS_DELAYCREATION = 0x20, + GPS_BESTEFFORT = 0x40, + GPS_NO_OPLOCK = 0x80, + GPS_PREFERQUERYPROPERTIES = 0x100, + GPS_EXTRINSICPROPERTIES = 0x200, + GPS_EXTRINSICPROPERTIESONLY = 0x400, + GPS_VOLATILEPROPERTIES = 0x800, + GPS_VOLATILEPROPERTIESONLY = 0x1000, + GPS_MASK_VALID = 0x1fff +} GETPROPERTYSTOREFLAGS; + +// DEFINE_ENUM_FLAG_OPERATORS(GETPROPERTYSTOREFLAGS) + + +#ifndef PROPERTYKEY_DEFINED +#define PROPERTYKEY_DEFINED + +typedef +struct +{ + GUID fmtid; + DWORD pid; +} PROPERTYKEY; + +#endif // PROPERTYKEY_DEFINED + +// propkeydef.h +#define REFPROPERTYKEY const PROPERTYKEY & + +#ifdef INITGUID +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } +#else +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name +#endif // INITGUID + + +// +typedef /* [v1_enum] */ +enum SIATTRIBFLAGS +{ + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3, + SIATTRIBFLAGS_ALLITEMS = 0x4000 +} SIATTRIBFLAGS; + +// DEFINE_ENUM_FLAG_OPERATORS(SIATTRIBFLAGS) + + +// MIDL_INTERFACE("70629033-e363-4a28-a567-0db78006e6d7") +DEFINE_GUID(IID_IEnumShellItems, 0x70629033, 0xe363, 0xe363, 0xa5, 0x67, 0x0d, 0xb7, 0x80, 0x06, 0xe6, 0xd7); + +struct IEnumShellItems : public IUnknown +{ + STDMETHOD (Next) (ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) = 0; + STDMETHOD (Skip) (ULONG celt) = 0; + STDMETHOD (Reset) (void) = 0; + STDMETHOD (Clone) (IEnumShellItems **ppenum) = 0; +}; + + +// MIDL_INTERFACE("b63ea76d-1f85-456f-a19c-48159efa858b") +DEFINE_GUID(IID_IShellItemArray, 0xb63ea76d, 0x1f85, 0x456f, 0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b); + +struct IShellItemArray : public IUnknown +{ + STDMETHOD (BindToHandler) (IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut) = 0; + STDMETHOD (GetPropertyStore) (GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) = 0; + STDMETHOD (GetPropertyDescriptionList) (REFPROPERTYKEY keyType, REFIID riid, void **ppv) = 0; + STDMETHOD (GetAttributes) ( SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0; + STDMETHOD (GetCount) (DWORD *pdwNumItems) = 0; + STDMETHOD (GetItemAt) (DWORD dwIndex, IShellItem **ppsi) = 0; + STDMETHOD (EnumItems) (IEnumShellItems **ppenumShellItems) = 0; +}; + + +#ifndef __IEnumExplorerCommand_INTERFACE_DEFINED__ +#define __IEnumExplorerCommand_INTERFACE_DEFINED__ + +struct IExplorerCommand; + +// MIDL_INTERFACE("a88826f8-186f-4987-aade-ea0cef8fbfe8") +DEFINE_GUID(IID_IEnumExplorerCommand , 0xa88826f8, 0x186f, 0x4987, 0xaa, 0xde, 0xea, 0x0c, 0xef, 0x8f, 0xbf, 0xe8); + +struct IEnumExplorerCommand : public IUnknown +{ + STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) = 0; + STDMETHOD (Skip) (ULONG celt) = 0; + STDMETHOD (Reset) (void) = 0; + STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) = 0; +}; + + +enum _EXPCMDSTATE +{ + ECS_ENABLED = 0, + ECS_DISABLED = 0x1, + ECS_HIDDEN = 0x2, + ECS_CHECKBOX = 0x4, + ECS_CHECKED = 0x8, + ECS_RADIOCHECK = 0x10 +}; + +typedef DWORD EXPCMDSTATE; + +/* [v1_enum] */ +enum _EXPCMDFLAGS +{ + ECF_DEFAULT = 0, + ECF_HASSUBCOMMANDS = 0x1, + ECF_HASSPLITBUTTON = 0x2, + ECF_HIDELABEL = 0x4, + ECF_ISSEPARATOR = 0x8, + ECF_HASLUASHIELD = 0x10, + ECF_SEPARATORBEFORE = 0x20, + ECF_SEPARATORAFTER = 0x40, + ECF_ISDROPDOWN = 0x80, + ECF_TOGGLEABLE = 0x100, + ECF_AUTOMENUICONS = 0x200 +}; +typedef DWORD EXPCMDFLAGS; + + +// MIDL_INTERFACE("a08ce4d0-fa25-44ab-b57c-c7b1c323e0b9") +DEFINE_GUID(IID_IExplorerCommand, 0xa08ce4d0, 0xfa25, 0x44ab, 0xb5, 0x7c, 0xc7, 0xb1, 0xc3, 0x23, 0xe0, 0xb9); + +struct IExplorerCommand : public IUnknown +{ + STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) = 0; + STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) = 0; + STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) = 0; + STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) = 0; + STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) = 0; + STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) = 0; + STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) = 0; + STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) = 0; +}; + +#endif // IShellItemArray +#endif // __IEnumExplorerCommand_INTERFACE_DEFINED__ +#endif // USE_SYS_shobjidl_core + +#endif // __MY_EXPLORER_COMMAND_H diff --git a/CPP/7zip/UI/Explorer/MyMessages.cpp b/CPP/7zip/UI/Explorer/MyMessages.cpp index 4777d0d32..c079e310e 100644 --- a/CPP/7zip/UI/Explorer/MyMessages.cpp +++ b/CPP/7zip/UI/Explorer/MyMessages.cpp @@ -1,43 +1,43 @@ -// MyMessages.cpp - -#include "StdAfx.h" - -#include "MyMessages.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/ResourceString.h" - -#include "../FileManager/LangUtils.h" - -using namespace NWindows; - -extern bool g_DisableUserQuestions; - -void ShowErrorMessage(HWND window, LPCWSTR message) -{ - if (!g_DisableUserQuestions) - ::MessageBoxW(window, message, L"7-Zip", MB_OK | MB_ICONSTOP); -} - -void ShowErrorMessageHwndRes(HWND window, UInt32 resID) -{ - UString s = LangString(resID); - if (s.IsEmpty()) - s.Add_UInt32(resID); - ShowErrorMessage(window, s); -} - -void ShowErrorMessageRes(UInt32 resID) -{ - ShowErrorMessageHwndRes(NULL, resID); -} - -static void ShowErrorMessageDWORD(HWND window, DWORD errorCode) -{ - ShowErrorMessage(window, NError::MyFormatMessage(errorCode)); -} - -void ShowLastErrorMessage(HWND window) -{ - ShowErrorMessageDWORD(window, ::GetLastError()); -} +// MyMessages.cpp + +#include "StdAfx.h" + +#include "MyMessages.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/ResourceString.h" + +#include "../FileManager/LangUtils.h" + +using namespace NWindows; + +extern bool g_DisableUserQuestions; + +void ShowErrorMessage(HWND window, LPCWSTR message) +{ + if (!g_DisableUserQuestions) + ::MessageBoxW(window, message, L"7-Zip", MB_OK | MB_ICONSTOP); +} + +void ShowErrorMessageHwndRes(HWND window, UInt32 resID) +{ + UString s = LangString(resID); + if (s.IsEmpty()) + s.Add_UInt32(resID); + ShowErrorMessage(window, s); +} + +void ShowErrorMessageRes(UInt32 resID) +{ + ShowErrorMessageHwndRes(NULL, resID); +} + +static void ShowErrorMessageDWORD(HWND window, DWORD errorCode) +{ + ShowErrorMessage(window, NError::MyFormatMessage(errorCode)); +} + +void ShowLastErrorMessage(HWND window) +{ + ShowErrorMessageDWORD(window, ::GetLastError()); +} diff --git a/CPP/7zip/UI/Explorer/MyMessages.h b/CPP/7zip/UI/Explorer/MyMessages.h index 039c6a42b..47d10db71 100644 --- a/CPP/7zip/UI/Explorer/MyMessages.h +++ b/CPP/7zip/UI/Explorer/MyMessages.h @@ -1,16 +1,16 @@ -// MyMessages.h - -#ifndef ZIP7_INC_MY_MESSAGES_H -#define ZIP7_INC_MY_MESSAGES_H - -#include "../../../Common/MyString.h" - -void ShowErrorMessage(HWND window, LPCWSTR message); -inline void ShowErrorMessage(LPCWSTR message) { ShowErrorMessage(NULL, message); } - -void ShowErrorMessageHwndRes(HWND window, UInt32 langID); -void ShowErrorMessageRes(UInt32 langID); - -void ShowLastErrorMessage(HWND window = NULL); - -#endif +// MyMessages.h + +#ifndef ZIP7_INC_MY_MESSAGES_H +#define ZIP7_INC_MY_MESSAGES_H + +#include "../../../Common/MyString.h" + +void ShowErrorMessage(HWND window, LPCWSTR message); +inline void ShowErrorMessage(LPCWSTR message) { ShowErrorMessage(NULL, message); } + +void ShowErrorMessageHwndRes(HWND window, UInt32 langID); +void ShowErrorMessageRes(UInt32 langID); + +void ShowLastErrorMessage(HWND window = NULL); + +#endif diff --git a/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp index 923e63d6a..6563d89b8 100644 --- a/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp +++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp @@ -1,225 +1,225 @@ -// RegistryContextMenu.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/Registry.h" - -#include "RegistryContextMenu.h" - -using namespace NWindows; -using namespace NRegistry; - -#ifndef UNDER_CE - -// does extension can work, if Approved is removed ? -// CLISID (and Approved ?) items are separated for 32-bit and 64-bit code. -// shellex items shared by 32-bit and 64-bit code? - -#define k_Clsid_A "{23170F69-40C1-278A-1000-000100020000}" - -static LPCTSTR const k_Clsid = TEXT(k_Clsid_A); -static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension"); - -static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"); -static LPCTSTR const k_Inproc = TEXT("InprocServer32"); - -static LPCSTR const k_KeyPostfix_ContextMenu = "\\shellex\\ContextMenuHandlers\\7-Zip"; -static LPCSTR const k_KeyPostfix_DragDrop = "\\shellex\\DragDropHandlers\\7-Zip"; - -static LPCSTR const k_KeyName_File = "*"; -static LPCSTR const k_KeyName_Folder = "Folder"; -static LPCSTR const k_KeyName_Directory = "Directory"; -static LPCSTR const k_KeyName_Drive = "Drive"; - -static LPCSTR const k_shellex_Prefixes[] = -{ - k_KeyName_File, - k_KeyName_Folder, - k_KeyName_Directory, - k_KeyName_Drive -}; - -static const bool k_shellex_Statuses[2][4] = -{ - { true, true, true, false }, - { false, false, true, true } -}; - - -// RegDeleteKeyExW is supported starting from win2003sp1/xp-pro-x64 -// Z7_WIN32_WINNT_MIN < 0x0600 // Vista -#if !defined(Z7_WIN32_WINNT_MIN) \ - || Z7_WIN32_WINNT_MIN < 0x0502 /* < win2003 */ \ - || Z7_WIN32_WINNT_MIN == 0x0502 && !defined(_M_AMD64) -#define Z7_USE_DYN_RegDeleteKeyExW -#endif - -#ifdef Z7_USE_DYN_RegDeleteKeyExW -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -typedef -// WINADVAPI -LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); -static Func_RegDeleteKeyExW func_RegDeleteKeyExW; - -static void Init_RegDeleteKeyExW() -{ - if (!func_RegDeleteKeyExW) - func_RegDeleteKeyExW = Z7_GET_PROC_ADDRESS( - Func_RegDeleteKeyExW, GetModuleHandleW(L"advapi32.dll"), - "RegDeleteKeyExW"); -} -#define INIT_REG_WOW if (wow != 0) Init_RegDeleteKeyExW(); -#else -#define INIT_REG_WOW -#endif - - -static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCTSTR name, UInt32 wow) -{ - if (wow == 0) - return RegDeleteKey(parentKey, name); - -#ifdef Z7_USE_DYN_RegDeleteKeyExW - if (!func_RegDeleteKeyExW) - return E_NOTIMPL; - return func_RegDeleteKeyExW -#else - return RegDeleteKeyExW -#endif - (parentKey, GetUnicodeString(name), wow, 0); -} - -static LONG MyRegistry_DeleteKey_HKCR(LPCTSTR name, UInt32 wow) -{ - return MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, name, wow); -} - -// static NSynchronization::CCriticalSection g_CS; - -static AString Get_ContextMenuHandler_KeyName(LPCSTR keyName) - { return (AString)keyName + k_KeyPostfix_ContextMenu; } - -/* -static CSysString Get_DragDropHandler_KeyName(LPCTSTR keyName) - { return (AString)keyName + k_KeyPostfix_DragDrop); } -*/ - -static bool CheckHandlerCommon(const AString &keyName, UInt32 wow) -{ - CKey key; - if (key.Open(HKEY_CLASSES_ROOT, (CSysString)keyName, KEY_READ | wow) != ERROR_SUCCESS) - return false; - CSysString value; - if (key.QueryValue(NULL, value) != ERROR_SUCCESS) - return false; - return StringsAreEqualNoCase_Ascii(value, k_Clsid_A); -} - -bool CheckContextMenuHandler(const UString &path, UInt32 wow) -{ - // NSynchronization::CCriticalSectionLock lock(g_CS); - - CSysString s ("CLSID\\"); - s += k_Clsid_A; - s += "\\InprocServer32"; - - { - NRegistry::CKey key; - if (key.Open(HKEY_CLASSES_ROOT, s, KEY_READ | wow) != ERROR_SUCCESS) - return false; - UString regPath; - if (key.QueryValue(NULL, regPath) != ERROR_SUCCESS) - return false; - if (!path.IsEqualTo_NoCase(regPath)) - return false; - } - - return - CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_File), wow); - /* - && CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_Directory), wow) - // && CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_Folder)) - - && CheckHandlerCommon(Get_DragDropHandler_KeyName(k_KeyName_Directory), wow) - && CheckHandlerCommon(Get_DragDropHandler_KeyName(k_KeyName_Drive), wow); - */ -} - - -static LONG MyCreateKey(CKey &key, HKEY parentKey, LPCTSTR keyName, UInt32 wow) -{ - return key.Create(parentKey, keyName, REG_NONE, - REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | wow); -} - -LONG SetContextMenuHandler(bool setMode, const UString &path, UInt32 wow) -{ - // NSynchronization::CCriticalSectionLock lock(g_CS); - - INIT_REG_WOW - - LONG res; - - { - CSysString s ("CLSID\\"); - s += k_Clsid_A; - - if (setMode) - { - { - CKey key; - res = MyCreateKey(key, HKEY_CLASSES_ROOT, s, wow); - if (res == ERROR_SUCCESS) - { - key.SetValue(NULL, k_ShellExtName); - CKey keyInproc; - res = MyCreateKey(keyInproc, key, k_Inproc, wow); - if (res == ERROR_SUCCESS) - { - res = keyInproc.SetValue(NULL, path); - keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment")); - } - } - } - - { - CKey key; - if (MyCreateKey(key, HKEY_LOCAL_MACHINE, k_Approved, wow) == ERROR_SUCCESS) - key.SetValue(k_Clsid, k_ShellExtName); - } - } - else - { - CSysString s2 (s); - s2 += "\\InprocServer32"; - - MyRegistry_DeleteKey_HKCR(s2, wow); - res = MyRegistry_DeleteKey_HKCR(s, wow); - } - } - - // shellex items probably are shared beween 32-bit and 64-bit apps. So we don't delete items for delete operation. - if (setMode) - for (unsigned i = 0; i < 2; i++) - { - for (unsigned k = 0; k < Z7_ARRAY_SIZE(k_shellex_Prefixes); k++) - { - CSysString s (k_shellex_Prefixes[k]); - s += (i == 0 ? k_KeyPostfix_ContextMenu : k_KeyPostfix_DragDrop); - if (k_shellex_Statuses[i][k]) - { - CKey key; - MyCreateKey(key, HKEY_CLASSES_ROOT, s, wow); - key.SetValue(NULL, k_Clsid); - } - else - MyRegistry_DeleteKey_HKCR(s, wow); - } - } - - return res; -} - -#endif +// RegistryContextMenu.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/Registry.h" + +#include "RegistryContextMenu.h" + +using namespace NWindows; +using namespace NRegistry; + +#ifndef UNDER_CE + +// does extension can work, if Approved is removed ? +// CLISID (and Approved ?) items are separated for 32-bit and 64-bit code. +// shellex items shared by 32-bit and 64-bit code? + +#define k_Clsid_A "{23170F69-40C1-278A-1000-000100020000}" + +static LPCTSTR const k_Clsid = TEXT(k_Clsid_A); +static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension"); + +static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"); +static LPCTSTR const k_Inproc = TEXT("InprocServer32"); + +static LPCSTR const k_KeyPostfix_ContextMenu = "\\shellex\\ContextMenuHandlers\\7-Zip"; +static LPCSTR const k_KeyPostfix_DragDrop = "\\shellex\\DragDropHandlers\\7-Zip"; + +static LPCSTR const k_KeyName_File = "*"; +static LPCSTR const k_KeyName_Folder = "Folder"; +static LPCSTR const k_KeyName_Directory = "Directory"; +static LPCSTR const k_KeyName_Drive = "Drive"; + +static LPCSTR const k_shellex_Prefixes[] = +{ + k_KeyName_File, + k_KeyName_Folder, + k_KeyName_Directory, + k_KeyName_Drive +}; + +static const bool k_shellex_Statuses[2][4] = +{ + { true, true, true, false }, + { false, false, true, true } +}; + + +// RegDeleteKeyExW is supported starting from win2003sp1/xp-pro-x64 +// Z7_WIN32_WINNT_MIN < 0x0600 // Vista +#if !defined(Z7_WIN32_WINNT_MIN) \ + || Z7_WIN32_WINNT_MIN < 0x0502 /* < win2003 */ \ + || Z7_WIN32_WINNT_MIN == 0x0502 && !defined(_M_AMD64) +#define Z7_USE_DYN_RegDeleteKeyExW +#endif + +#ifdef Z7_USE_DYN_RegDeleteKeyExW +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +typedef +// WINADVAPI +LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved); +static Func_RegDeleteKeyExW func_RegDeleteKeyExW; + +static void Init_RegDeleteKeyExW() +{ + if (!func_RegDeleteKeyExW) + func_RegDeleteKeyExW = Z7_GET_PROC_ADDRESS( + Func_RegDeleteKeyExW, GetModuleHandleW(L"advapi32.dll"), + "RegDeleteKeyExW"); +} +#define INIT_REG_WOW if (wow != 0) Init_RegDeleteKeyExW(); +#else +#define INIT_REG_WOW +#endif + + +static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCTSTR name, UInt32 wow) +{ + if (wow == 0) + return RegDeleteKey(parentKey, name); + +#ifdef Z7_USE_DYN_RegDeleteKeyExW + if (!func_RegDeleteKeyExW) + return E_NOTIMPL; + return func_RegDeleteKeyExW +#else + return RegDeleteKeyExW +#endif + (parentKey, GetUnicodeString(name), wow, 0); +} + +static LONG MyRegistry_DeleteKey_HKCR(LPCTSTR name, UInt32 wow) +{ + return MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, name, wow); +} + +// static NSynchronization::CCriticalSection g_CS; + +static AString Get_ContextMenuHandler_KeyName(LPCSTR keyName) + { return (AString)keyName + k_KeyPostfix_ContextMenu; } + +/* +static CSysString Get_DragDropHandler_KeyName(LPCTSTR keyName) + { return (AString)keyName + k_KeyPostfix_DragDrop); } +*/ + +static bool CheckHandlerCommon(const AString &keyName, UInt32 wow) +{ + CKey key; + if (key.Open(HKEY_CLASSES_ROOT, (CSysString)keyName, KEY_READ | wow) != ERROR_SUCCESS) + return false; + CSysString value; + if (key.QueryValue(NULL, value) != ERROR_SUCCESS) + return false; + return StringsAreEqualNoCase_Ascii(value, k_Clsid_A); +} + +bool CheckContextMenuHandler(const UString &path, UInt32 wow) +{ + // NSynchronization::CCriticalSectionLock lock(g_CS); + + CSysString s ("CLSID\\"); + s += k_Clsid_A; + s += "\\InprocServer32"; + + { + NRegistry::CKey key; + if (key.Open(HKEY_CLASSES_ROOT, s, KEY_READ | wow) != ERROR_SUCCESS) + return false; + UString regPath; + if (key.QueryValue(NULL, regPath) != ERROR_SUCCESS) + return false; + if (!path.IsEqualTo_NoCase(regPath)) + return false; + } + + return + CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_File), wow); + /* + && CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_Directory), wow) + // && CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_Folder)) + + && CheckHandlerCommon(Get_DragDropHandler_KeyName(k_KeyName_Directory), wow) + && CheckHandlerCommon(Get_DragDropHandler_KeyName(k_KeyName_Drive), wow); + */ +} + + +static LONG MyCreateKey(CKey &key, HKEY parentKey, LPCTSTR keyName, UInt32 wow) +{ + return key.Create(parentKey, keyName, REG_NONE, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | wow); +} + +LONG SetContextMenuHandler(bool setMode, const UString &path, UInt32 wow) +{ + // NSynchronization::CCriticalSectionLock lock(g_CS); + + INIT_REG_WOW + + LONG res; + + { + CSysString s ("CLSID\\"); + s += k_Clsid_A; + + if (setMode) + { + { + CKey key; + res = MyCreateKey(key, HKEY_CLASSES_ROOT, s, wow); + if (res == ERROR_SUCCESS) + { + key.SetValue(NULL, k_ShellExtName); + CKey keyInproc; + res = MyCreateKey(keyInproc, key, k_Inproc, wow); + if (res == ERROR_SUCCESS) + { + res = keyInproc.SetValue(NULL, path); + keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment")); + } + } + } + + { + CKey key; + if (MyCreateKey(key, HKEY_LOCAL_MACHINE, k_Approved, wow) == ERROR_SUCCESS) + key.SetValue(k_Clsid, k_ShellExtName); + } + } + else + { + CSysString s2 (s); + s2 += "\\InprocServer32"; + + MyRegistry_DeleteKey_HKCR(s2, wow); + res = MyRegistry_DeleteKey_HKCR(s, wow); + } + } + + // shellex items probably are shared beween 32-bit and 64-bit apps. So we don't delete items for delete operation. + if (setMode) + for (unsigned i = 0; i < 2; i++) + { + for (unsigned k = 0; k < Z7_ARRAY_SIZE(k_shellex_Prefixes); k++) + { + CSysString s (k_shellex_Prefixes[k]); + s += (i == 0 ? k_KeyPostfix_ContextMenu : k_KeyPostfix_DragDrop); + if (k_shellex_Statuses[i][k]) + { + CKey key; + MyCreateKey(key, HKEY_CLASSES_ROOT, s, wow); + key.SetValue(NULL, k_Clsid); + } + else + MyRegistry_DeleteKey_HKCR(s, wow); + } + } + + return res; +} + +#endif diff --git a/CPP/7zip/UI/Explorer/RegistryContextMenu.h b/CPP/7zip/UI/Explorer/RegistryContextMenu.h index eb17b2ee5..bf3bb5b77 100644 --- a/CPP/7zip/UI/Explorer/RegistryContextMenu.h +++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.h @@ -1,13 +1,13 @@ -// RegistryContextMenu.h - -#ifndef ZIP7_INC_REGISTRY_CONTEXT_MENU_H -#define ZIP7_INC_REGISTRY_CONTEXT_MENU_H - -#ifndef UNDER_CE - -bool CheckContextMenuHandler(const UString &path, UInt32 wow = 0); -LONG SetContextMenuHandler(bool setMode, const UString &path, UInt32 wow = 0); - -#endif - -#endif +// RegistryContextMenu.h + +#ifndef ZIP7_INC_REGISTRY_CONTEXT_MENU_H +#define ZIP7_INC_REGISTRY_CONTEXT_MENU_H + +#ifndef UNDER_CE + +bool CheckContextMenuHandler(const UString &path, UInt32 wow = 0); +LONG SetContextMenuHandler(bool setMode, const UString &path, UInt32 wow = 0); + +#endif + +#endif diff --git a/CPP/7zip/UI/Explorer/StdAfx.cpp b/CPP/7zip/UI/Explorer/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/Explorer/StdAfx.cpp +++ b/CPP/7zip/UI/Explorer/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/Explorer/StdAfx.h b/CPP/7zip/UI/Explorer/StdAfx.h index 6c2379d6f..130db8aab 100644 --- a/CPP/7zip/UI/Explorer/StdAfx.h +++ b/CPP/7zip/UI/Explorer/StdAfx.h @@ -1,6 +1,6 @@ -// StdAfx.h - -#if _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../FileManager/StdAfx.h" +// StdAfx.h + +#if _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../FileManager/StdAfx.h" diff --git a/CPP/7zip/UI/Explorer/makefile b/CPP/7zip/UI/Explorer/makefile index b31320c78..3901d6bd3 100644 --- a/CPP/7zip/UI/Explorer/makefile +++ b/CPP/7zip/UI/Explorer/makefile @@ -1,78 +1,78 @@ -PROG = 7-zip.dll -DEF_FILE = Explorer.def -CFLAGS = $(CFLAGS) \ - -DZ7_LANG \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) Commctrl.lib -!ELSE -LIBS = $(LIBS) htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib -# CFLAGS = $(CFLAGS) -DZ7_LONG_PATH -# -DZ7_NO_LARGE_PAGES -!ENDIF - -EXPLORER_OBJS = \ - $O\DllExportsExplorer.obj \ - $O\ContextMenu.obj \ - $O\MyMessages.obj \ - -COMMON_OBJS = \ - $O\IntToString.obj \ - $O\Lang.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\NewHandler.obj \ - $O\Random.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileName.obj \ - $O\MemoryLock.obj \ - $O\Menu.obj \ - $O\ProcessUtils.obj \ - $O\Registry.obj \ - $O\ResourceString.obj \ - $O\Shell.obj \ - $O\Synchronization.obj \ - $O\TimeUtils.obj \ - $O\Window.obj \ - -!IFDEF UNDER_CE - -WIN_OBJS = $(WIN_OBJS) \ - $O\CommonDialog.obj \ - -!ENDIF - -WIN_CTRL_OBJS = \ - $O\Dialog.obj \ - $O\ListView.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveName.obj \ - $O\CompressCall.obj \ - $O\ExtractingFilePath.obj \ - $O\ZipRegistry.obj \ - -FM_OBJS = \ - $O\FormatUtils.obj \ - $O\HelpUtils.obj \ - $O\LangUtils.obj \ - $O\ProgramLocation.obj \ - $O\PropertyName.obj \ - $O\RegistryUtils.obj \ - -C_OBJS = \ - $O\CpuArch.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../7zip.mak" +PROG = 7-zip.dll +DEF_FILE = Explorer.def +CFLAGS = $(CFLAGS) \ + -DZ7_LANG \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) Commctrl.lib +!ELSE +LIBS = $(LIBS) htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib +# CFLAGS = $(CFLAGS) -DZ7_LONG_PATH +# -DZ7_NO_LARGE_PAGES +!ENDIF + +EXPLORER_OBJS = \ + $O\DllExportsExplorer.obj \ + $O\ContextMenu.obj \ + $O\MyMessages.obj \ + +COMMON_OBJS = \ + $O\IntToString.obj \ + $O\Lang.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\NewHandler.obj \ + $O\Random.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\MemoryLock.obj \ + $O\Menu.obj \ + $O\ProcessUtils.obj \ + $O\Registry.obj \ + $O\ResourceString.obj \ + $O\Shell.obj \ + $O\Synchronization.obj \ + $O\TimeUtils.obj \ + $O\Window.obj \ + +!IFDEF UNDER_CE + +WIN_OBJS = $(WIN_OBJS) \ + $O\CommonDialog.obj \ + +!ENDIF + +WIN_CTRL_OBJS = \ + $O\Dialog.obj \ + $O\ListView.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveName.obj \ + $O\CompressCall.obj \ + $O\ExtractingFilePath.obj \ + $O\ZipRegistry.obj \ + +FM_OBJS = \ + $O\FormatUtils.obj \ + $O\HelpUtils.obj \ + $O\LangUtils.obj \ + $O\ProgramLocation.obj \ + $O\PropertyName.obj \ + $O\RegistryUtils.obj \ + +C_OBJS = \ + $O\CpuArch.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/Explorer/resource.h b/CPP/7zip/UI/Explorer/resource.h index c2282bbf5..bbb28b16e 100644 --- a/CPP/7zip/UI/Explorer/resource.h +++ b/CPP/7zip/UI/Explorer/resource.h @@ -1,15 +1,15 @@ -#define IDS_CONTEXT_FOLDER 2320 -#define IDS_CONTEXT_ARCHIVE 2321 -#define IDS_CONTEXT_OPEN 2322 -#define IDS_CONTEXT_EXTRACT 2323 -#define IDS_CONTEXT_COMPRESS 2324 -#define IDS_CONTEXT_TEST 2325 -#define IDS_CONTEXT_EXTRACT_HERE 2326 -#define IDS_CONTEXT_EXTRACT_TO 2327 -#define IDS_CONTEXT_COMPRESS_TO 2328 -#define IDS_CONTEXT_COMPRESS_EMAIL 2329 -#define IDS_CONTEXT_COMPRESS_TO_EMAIL 2330 - -#define IDS_SELECT_FILES 3015 - -#define IDB_MENU_LOGO 190 +#define IDS_CONTEXT_FOLDER 2320 +#define IDS_CONTEXT_ARCHIVE 2321 +#define IDS_CONTEXT_OPEN 2322 +#define IDS_CONTEXT_EXTRACT 2323 +#define IDS_CONTEXT_COMPRESS 2324 +#define IDS_CONTEXT_TEST 2325 +#define IDS_CONTEXT_EXTRACT_HERE 2326 +#define IDS_CONTEXT_EXTRACT_TO 2327 +#define IDS_CONTEXT_COMPRESS_TO 2328 +#define IDS_CONTEXT_COMPRESS_EMAIL 2329 +#define IDS_CONTEXT_COMPRESS_TO_EMAIL 2330 + +#define IDS_SELECT_FILES 3015 + +#define IDB_MENU_LOGO 190 diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc index 231dda664..acfa6e5a4 100644 --- a/CPP/7zip/UI/Explorer/resource.rc +++ b/CPP/7zip/UI/Explorer/resource.rc @@ -1,10 +1,10 @@ -#include "../../MyVersionInfo.rc" -#include "resource2.rc" - -MY_VERSION_INFO_DLL("7-Zip Shell Extension", "7-zip") - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "7-zip.dll.manifest" -#endif - -IDI_ICON ICON "../FileManager/FM.ico" +#include "../../MyVersionInfo.rc" +#include "resource2.rc" + +MY_VERSION_INFO_DLL("7-Zip Shell Extension", "7-zip") + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "7-zip.dll.manifest" +#endif + +IDI_ICON ICON "../FileManager/FM.ico" diff --git a/CPP/7zip/UI/Explorer/resource2.rc b/CPP/7zip/UI/Explorer/resource2.rc index 120c1b6bc..de34824b1 100644 --- a/CPP/7zip/UI/Explorer/resource2.rc +++ b/CPP/7zip/UI/Explorer/resource2.rc @@ -1,19 +1,19 @@ -#include "resource.h" - -STRINGTABLE -BEGIN - IDS_CONTEXT_FOLDER "" - IDS_CONTEXT_ARCHIVE "" - IDS_CONTEXT_OPEN "Open archive" - IDS_CONTEXT_EXTRACT "Extract files..." - IDS_CONTEXT_COMPRESS "Add to archive..." - IDS_CONTEXT_TEST "Test archive" - IDS_CONTEXT_EXTRACT_HERE "Extract Here" - IDS_CONTEXT_EXTRACT_TO "Extract to {0}" - IDS_CONTEXT_COMPRESS_TO "Add to {0}" - IDS_CONTEXT_COMPRESS_EMAIL "Compress and email..." - IDS_CONTEXT_COMPRESS_TO_EMAIL "Compress to {0} and email" - IDS_SELECT_FILES "You must select one or more files" -END - -IDB_MENU_LOGO BITMAP "../../UI/Explorer/MenuLogo.bmp" +#include "resource.h" + +STRINGTABLE +BEGIN + IDS_CONTEXT_FOLDER "" + IDS_CONTEXT_ARCHIVE "" + IDS_CONTEXT_OPEN "Open archive" + IDS_CONTEXT_EXTRACT "Extract files..." + IDS_CONTEXT_COMPRESS "Add to archive..." + IDS_CONTEXT_TEST "Test archive" + IDS_CONTEXT_EXTRACT_HERE "Extract Here" + IDS_CONTEXT_EXTRACT_TO "Extract to {0}" + IDS_CONTEXT_COMPRESS_TO "Add to {0}" + IDS_CONTEXT_COMPRESS_EMAIL "Compress and email..." + IDS_CONTEXT_COMPRESS_TO_EMAIL "Compress to {0} and email" + IDS_SELECT_FILES "You must select one or more files" +END + +IDB_MENU_LOGO BITMAP "../../UI/Explorer/MenuLogo.bmp" diff --git a/CPP/7zip/UI/Far/ExtractEngine.cpp b/CPP/7zip/UI/Far/ExtractEngine.cpp index e0e967abe..05e920814 100644 --- a/CPP/7zip/UI/Far/ExtractEngine.cpp +++ b/CPP/7zip/UI/Far/ExtractEngine.cpp @@ -1,274 +1,274 @@ -// ExtractEngine.h - -#include "StdAfx.h" - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../../../Common/StringConvert.h" - -#include "ExtractEngine.h" -#include "FarUtils.h" -#include "Messages.h" -#include "OverwriteDialogFar.h" - -using namespace NWindows; -using namespace NFar; - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - - -static HRESULT CheckBreak2() -{ - return WasEscPressed() ? E_ABORT : S_OK; -} - -extern void PrintMessage(const char *message); - -void CExtractCallbackImp::Init( - UINT codePage, - CProgressBox *progressBox, - bool passwordIsDefined, - const UString &password) -{ - m_PasswordIsDefined = passwordIsDefined; - m_Password = password; - m_CodePage = codePage; - _percent = progressBox; -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 size)) -{ - MT_LOCK - - if (_percent) - { - _percent->Total = size; - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)) -{ - MT_LOCK - - if (_percent) - { - if (completeValue) - _percent->Completed = *completeValue; - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite( - const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, - const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, - Int32 *answer)) -{ - MT_LOCK - - NOverwriteDialog::CFileInfo oldFileInfo, newFileInfo; - oldFileInfo.TimeIsDefined = (existTime != NULL); - if (oldFileInfo.TimeIsDefined) - oldFileInfo.Time = *existTime; - oldFileInfo.SizeIsDefined = (existSize != NULL); - if (oldFileInfo.SizeIsDefined) - oldFileInfo.Size = *existSize; - oldFileInfo.Name = existName; - - newFileInfo.TimeIsDefined = (newTime != NULL); - if (newFileInfo.TimeIsDefined) - newFileInfo.Time = *newTime; - newFileInfo.SizeIsDefined = (newSize != NULL); - if (newFileInfo.SizeIsDefined) - newFileInfo.Size = *newSize; - newFileInfo.Name = newName; - - NOverwriteDialog::NResult::EEnum result = - NOverwriteDialog::Execute(oldFileInfo, newFileInfo); - - switch ((int)result) - { - case NOverwriteDialog::NResult::kCancel: - // *answer = NOverwriteAnswer::kCancel; - // break; - return E_ABORT; - case NOverwriteDialog::NResult::kNo: - *answer = NOverwriteAnswer::kNo; - break; - case NOverwriteDialog::NResult::kNoToAll: - *answer = NOverwriteAnswer::kNoToAll; - break; - case NOverwriteDialog::NResult::kYesToAll: - *answer = NOverwriteAnswer::kYesToAll; - break; - case NOverwriteDialog::NResult::kYes: - *answer = NOverwriteAnswer::kYes; - break; - case NOverwriteDialog::NResult::kAutoRename: - *answer = NOverwriteAnswer::kAutoRename; - break; - default: - return E_FAIL; - } - - return CheckBreak2(); -} - -static const char * const kTestString = "Testing"; -static const char * const kExtractString = "Extracting"; -static const char * const kSkipString = "Skipping"; -static const char * const kReadString = "Reading"; - -Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 * /* position */)) -{ - MT_LOCK - - m_CurrentFilePath = name; - const char *s; - - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; - case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; - case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; break; - case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; break; - default: s = "???"; // return E_FAIL; - } - - if (_percent) - { - _percent->Command = s; - _percent->FileName = name; - _percent->Print(); - } - - return CheckBreak2(); -} - -Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *message)) -{ - MT_LOCK - - AString s (UnicodeStringToMultiByte(message, CP_OEMCP)); - if (g_StartupInfo.ShowErrorMessage((const char *)s) == -1) - return E_ABORT; - - return CheckBreak2(); -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s); -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s) -{ - s.Empty(); - - switch (opRes) - { - case NArchive::NExtract::NOperationResult::kOK: - return; - default: - { - UINT messageID = 0; - switch (opRes) - { - case NArchive::NExtract::NOperationResult::kUnsupportedMethod: - messageID = NMessageID::kExtractUnsupportedMethod; - break; - case NArchive::NExtract::NOperationResult::kCRCError: - messageID = encrypted ? - NMessageID::kExtractCRCFailedEncrypted : - NMessageID::kExtractCRCFailed; - break; - case NArchive::NExtract::NOperationResult::kDataError: - messageID = encrypted ? - NMessageID::kExtractDataErrorEncrypted : - NMessageID::kExtractDataError; - break; - } - if (messageID != 0) - { - s = g_StartupInfo.GetMsgString((int)messageID); - s.Replace((AString)" '%s'", AString()); - } - else if (opRes == NArchive::NExtract::NOperationResult::kUnavailable) - s = "Unavailable data"; - else if (opRes == NArchive::NExtract::NOperationResult::kUnexpectedEnd) - s = "Unexpected end of data"; - else if (opRes == NArchive::NExtract::NOperationResult::kDataAfterEnd) - s = "There are some data after the end of the payload data"; - else if (opRes == NArchive::NExtract::NOperationResult::kIsNotArc) - s = "Is not archive"; - else if (opRes == NArchive::NExtract::NOperationResult::kHeadersError) - s = "kHeaders Error"; - else if (opRes == NArchive::NExtract::NOperationResult::kWrongPassword) - s = "Wrong Password"; - else - { - s = "Error #"; - s.Add_UInt32((UInt32)opRes); - } - } - } -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)) -{ - MT_LOCK - - if (opRes == NArchive::NExtract::NOperationResult::kOK) - { - if (_percent) - { - _percent->Command.Empty(); - _percent->FileName.Empty(); - _percent->Files++; - } - } - else - { - AString s; - SetExtractErrorMessage(opRes, encrypted, s); - if (PrintErrorMessage(s, m_CurrentFilePath) == -1) - return E_ABORT; - } - - return CheckBreak2(); -} - - -Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) -{ - MT_LOCK - - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - AString s; - SetExtractErrorMessage(opRes, encrypted, s); - if (PrintErrorMessage(s, name) == -1) - return E_ABORT; - } - - return CheckBreak2(); -} - -extern HRESULT GetPassword(UString &password); - -Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)) -{ - MT_LOCK - - if (!m_PasswordIsDefined) - { - RINOK(GetPassword(m_Password)) - m_PasswordIsDefined = true; - } - return StringToBstr(m_Password, password); -} +// ExtractEngine.h + +#include "StdAfx.h" + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../../../Common/StringConvert.h" + +#include "ExtractEngine.h" +#include "FarUtils.h" +#include "Messages.h" +#include "OverwriteDialogFar.h" + +using namespace NWindows; +using namespace NFar; + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + + +static HRESULT CheckBreak2() +{ + return WasEscPressed() ? E_ABORT : S_OK; +} + +extern void PrintMessage(const char *message); + +void CExtractCallbackImp::Init( + UINT codePage, + CProgressBox *progressBox, + bool passwordIsDefined, + const UString &password) +{ + m_PasswordIsDefined = passwordIsDefined; + m_Password = password; + m_CodePage = codePage; + _percent = progressBox; +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 size)) +{ + MT_LOCK + + if (_percent) + { + _percent->Total = size; + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)) +{ + MT_LOCK + + if (_percent) + { + if (completeValue) + _percent->Completed = *completeValue; + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite( + const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, + const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, + Int32 *answer)) +{ + MT_LOCK + + NOverwriteDialog::CFileInfo oldFileInfo, newFileInfo; + oldFileInfo.TimeIsDefined = (existTime != NULL); + if (oldFileInfo.TimeIsDefined) + oldFileInfo.Time = *existTime; + oldFileInfo.SizeIsDefined = (existSize != NULL); + if (oldFileInfo.SizeIsDefined) + oldFileInfo.Size = *existSize; + oldFileInfo.Name = existName; + + newFileInfo.TimeIsDefined = (newTime != NULL); + if (newFileInfo.TimeIsDefined) + newFileInfo.Time = *newTime; + newFileInfo.SizeIsDefined = (newSize != NULL); + if (newFileInfo.SizeIsDefined) + newFileInfo.Size = *newSize; + newFileInfo.Name = newName; + + NOverwriteDialog::NResult::EEnum result = + NOverwriteDialog::Execute(oldFileInfo, newFileInfo); + + switch ((int)result) + { + case NOverwriteDialog::NResult::kCancel: + // *answer = NOverwriteAnswer::kCancel; + // break; + return E_ABORT; + case NOverwriteDialog::NResult::kNo: + *answer = NOverwriteAnswer::kNo; + break; + case NOverwriteDialog::NResult::kNoToAll: + *answer = NOverwriteAnswer::kNoToAll; + break; + case NOverwriteDialog::NResult::kYesToAll: + *answer = NOverwriteAnswer::kYesToAll; + break; + case NOverwriteDialog::NResult::kYes: + *answer = NOverwriteAnswer::kYes; + break; + case NOverwriteDialog::NResult::kAutoRename: + *answer = NOverwriteAnswer::kAutoRename; + break; + default: + return E_FAIL; + } + + return CheckBreak2(); +} + +static const char * const kTestString = "Testing"; +static const char * const kExtractString = "Extracting"; +static const char * const kSkipString = "Skipping"; +static const char * const kReadString = "Reading"; + +Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 * /* position */)) +{ + MT_LOCK + + m_CurrentFilePath = name; + const char *s; + + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; + case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; + case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; break; + case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; break; + default: s = "???"; // return E_FAIL; + } + + if (_percent) + { + _percent->Command = s; + _percent->FileName = name; + _percent->Print(); + } + + return CheckBreak2(); +} + +Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *message)) +{ + MT_LOCK + + AString s (UnicodeStringToMultiByte(message, CP_OEMCP)); + if (g_StartupInfo.ShowErrorMessage((const char *)s) == -1) + return E_ABORT; + + return CheckBreak2(); +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s); +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s) +{ + s.Empty(); + + switch (opRes) + { + case NArchive::NExtract::NOperationResult::kOK: + return; + default: + { + UINT messageID = 0; + switch (opRes) + { + case NArchive::NExtract::NOperationResult::kUnsupportedMethod: + messageID = NMessageID::kExtractUnsupportedMethod; + break; + case NArchive::NExtract::NOperationResult::kCRCError: + messageID = encrypted ? + NMessageID::kExtractCRCFailedEncrypted : + NMessageID::kExtractCRCFailed; + break; + case NArchive::NExtract::NOperationResult::kDataError: + messageID = encrypted ? + NMessageID::kExtractDataErrorEncrypted : + NMessageID::kExtractDataError; + break; + } + if (messageID != 0) + { + s = g_StartupInfo.GetMsgString((int)messageID); + s.Replace((AString)" '%s'", AString()); + } + else if (opRes == NArchive::NExtract::NOperationResult::kUnavailable) + s = "Unavailable data"; + else if (opRes == NArchive::NExtract::NOperationResult::kUnexpectedEnd) + s = "Unexpected end of data"; + else if (opRes == NArchive::NExtract::NOperationResult::kDataAfterEnd) + s = "There are some data after the end of the payload data"; + else if (opRes == NArchive::NExtract::NOperationResult::kIsNotArc) + s = "Is not archive"; + else if (opRes == NArchive::NExtract::NOperationResult::kHeadersError) + s = "kHeaders Error"; + else if (opRes == NArchive::NExtract::NOperationResult::kWrongPassword) + s = "Wrong Password"; + else + { + s = "Error #"; + s.Add_UInt32((UInt32)opRes); + } + } + } +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)) +{ + MT_LOCK + + if (opRes == NArchive::NExtract::NOperationResult::kOK) + { + if (_percent) + { + _percent->Command.Empty(); + _percent->FileName.Empty(); + _percent->Files++; + } + } + else + { + AString s; + SetExtractErrorMessage(opRes, encrypted, s); + if (PrintErrorMessage(s, m_CurrentFilePath) == -1) + return E_ABORT; + } + + return CheckBreak2(); +} + + +Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) +{ + MT_LOCK + + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + AString s; + SetExtractErrorMessage(opRes, encrypted, s); + if (PrintErrorMessage(s, name) == -1) + return E_ABORT; + } + + return CheckBreak2(); +} + +extern HRESULT GetPassword(UString &password); + +Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)) +{ + MT_LOCK + + if (!m_PasswordIsDefined) + { + RINOK(GetPassword(m_Password)) + m_PasswordIsDefined = true; + } + return StringToBstr(m_Password, password); +} diff --git a/CPP/7zip/UI/Far/ExtractEngine.h b/CPP/7zip/UI/Far/ExtractEngine.h index 8c7b7fe24..2bee2ee4b 100644 --- a/CPP/7zip/UI/Far/ExtractEngine.h +++ b/CPP/7zip/UI/Far/ExtractEngine.h @@ -1,43 +1,43 @@ -// ExtractEngine.h - -#ifndef ZIP7_INC_EXTRACT_ENGINE_H -#define ZIP7_INC_EXTRACT_ENGINE_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyString.h" - -#include "../../IPassword.h" -#include "../Agent/IFolderArchive.h" - -#include "ProgressBox.h" - -Z7_CLASS_IMP_COM_3( - CExtractCallbackImp - , IFolderArchiveExtractCallback - , IFolderArchiveExtractCallback2 - , ICryptoGetTextPassword -) - Z7_IFACE_COM7_IMP(IProgress) - - UString m_CurrentFilePath; - - CProgressBox *_percent; - UINT m_CodePage; - - bool m_PasswordIsDefined; - UString m_Password; - - void CreateComplexDirectory(const UStringVector &dirPathParts); - /* - void GetPropertyValue(LPITEMIDLIST anItemIDList, PROPID aPropId, - PROPVARIANT *aValue); - bool IsEncrypted(LPITEMIDLIST anItemIDList); - */ - void AddErrorMessage(LPCTSTR message); -public: - void Init(UINT codePage, - CProgressBox *progressBox, - bool passwordIsDefined, const UString &password); -}; - -#endif +// ExtractEngine.h + +#ifndef ZIP7_INC_EXTRACT_ENGINE_H +#define ZIP7_INC_EXTRACT_ENGINE_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" + +#include "../../IPassword.h" +#include "../Agent/IFolderArchive.h" + +#include "ProgressBox.h" + +Z7_CLASS_IMP_COM_3( + CExtractCallbackImp + , IFolderArchiveExtractCallback + , IFolderArchiveExtractCallback2 + , ICryptoGetTextPassword +) + Z7_IFACE_COM7_IMP(IProgress) + + UString m_CurrentFilePath; + + CProgressBox *_percent; + UINT m_CodePage; + + bool m_PasswordIsDefined; + UString m_Password; + + void CreateComplexDirectory(const UStringVector &dirPathParts); + /* + void GetPropertyValue(LPITEMIDLIST anItemIDList, PROPID aPropId, + PROPVARIANT *aValue); + bool IsEncrypted(LPITEMIDLIST anItemIDList); + */ + void AddErrorMessage(LPCTSTR message); +public: + void Init(UINT codePage, + CProgressBox *progressBox, + bool passwordIsDefined, const UString &password); +}; + +#endif diff --git a/CPP/7zip/UI/Far/Far.cpp b/CPP/7zip/UI/Far/Far.cpp index 746a9abd7..962af97b2 100644 --- a/CPP/7zip/UI/Far/Far.cpp +++ b/CPP/7zip/UI/Far/Far.cpp @@ -1,587 +1,588 @@ -// Far.cpp -// Test Align for updating !!!!!!!!!!!!!!!!!! - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/NtCheck.h" - -#include "../../Common/FileStreams.h" - -#include "Messages.h" -#include "Plugin.h" -#include "ProgressBox.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NFar; - -static const DWORD kShowProgressTime_ms = 100; - -static const char * const kCommandPrefix = "7-zip"; -static const char * const kRegisrtryMainKeyName = NULL; // "" -static LPCTSTR const kRegisrtryValueNameEnabled = TEXT("UsedByDefault3"); -static const char * const kHelpTopicConfig = "Config"; -static bool kPluginEnabledDefault = true; - -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance; - -namespace NFar { - -extern -const char *g_PluginName_for_Error; -const char *g_PluginName_for_Error = "7-Zip"; - -} - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION return FALSE; -#endif - -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - hInstance, DWORD dwReason, LPVOID); -BOOL WINAPI DllMain( - #ifdef UNDER_CE - HANDLE - #else - HINSTANCE - #endif - hInstance, DWORD dwReason, LPVOID) -{ - if (dwReason == DLL_PROCESS_ATTACH) - { - // OutputDebugStringA("7-Zip FAR DLL_PROCESS_ATTACH"); - g_hInstance = (HINSTANCE)hInstance; - NT_CHECK - } - if (dwReason == DLL_PROCESS_DETACH) - { - // OutputDebugStringA("7-Zip FAR DLL_PROCESS_DETACH"); - } - return TRUE; -} - -static struct COptions -{ - bool Enabled; -} g_Options; - -static const char * const kPliginNameForRegistry = "7-ZIP"; - -EXTERN_C void WINAPI ExitFAR() -{ - /* WIN32: - it's not allowed to call FreeLibrary() from FreeLibrary(). - So we try to free all DLLs before destructors */ - // OutputDebugStringA("-- ExitFAR --- START"); - - FreeGlobalCodecs(); - - // OutputDebugStringA("-- ExitFAR --- END"); -} - -EXTERN_C void WINAPI SetStartupInfo(const PluginStartupInfo *info) -{ - MY_TRY_BEGIN - g_StartupInfo.Init(*info, kPliginNameForRegistry); - g_Options.Enabled = g_StartupInfo.QueryRegKeyValue( - HKEY_CURRENT_USER, kRegisrtryMainKeyName, - kRegisrtryValueNameEnabled, kPluginEnabledDefault); - - // OutputDebugStringA("SetStartupInfo"); - // LoadGlobalCodecs(); - - MY_TRY_END1("SetStartupInfo") -} - -Z7_CLASS_IMP_COM_3( - COpenArchiveCallback - , IArchiveOpenCallback - , IProgress - , ICryptoGetTextPassword -) - // DWORD m_StartTickValue; - bool m_MessageBoxIsShown; - - CProgressBox _progressBox; - - bool _numFilesTotalDefined; - bool _numBytesTotalDefined; - -public: - bool PasswordIsDefined; - UString Password; - - COpenArchiveCallback() - {} - - void Init() - { - PasswordIsDefined = false; - - _numFilesTotalDefined = false; - _numBytesTotalDefined = false; - - m_MessageBoxIsShown = false; - - _progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kReading)); - } - void ShowMessage(); -}; - -static HRESULT CheckBreak2() -{ - return WasEscPressed() ? E_ABORT : S_OK; -} - -void COpenArchiveCallback::ShowMessage() -{ - if (!m_MessageBoxIsShown) - { - DWORD currentTime = GetTickCount(); - if (currentTime - _progressBox.StartTick < kShowProgressTime_ms) - return; - m_MessageBoxIsShown = true; - } - - _progressBox.UseBytesForPercents = !_numFilesTotalDefined; - _progressBox.Print(); -} - -Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes)) -{ - _numFilesTotalDefined = (numFiles != NULL); - if (_numFilesTotalDefined) - _progressBox.FilesTotal = *numFiles; - - _numBytesTotalDefined = (numBytes != NULL); - if (_numBytesTotalDefined) - _progressBox.Total = *numBytes; - - return CheckBreak2(); -} - -Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes)) -{ - if (numFiles) - _progressBox.Files = *numFiles; - - if (numBytes) - _progressBox.Completed = *numBytes; - - ShowMessage(); - return CheckBreak2(); -} - - -Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 /* total */)) -{ - return CheckBreak2(); -} - -Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 * /* completed */)) -{ - ShowMessage(); - return CheckBreak2(); -} - -HRESULT GetPassword(UString &password); -HRESULT GetPassword(UString &password) -{ - if (WasEscPressed()) - return E_ABORT; - password.Empty(); - CInitDialogItem initItems[]= - { - { DI_DOUBLEBOX, 3, 1, 72, 4, false, false, 0, false, NMessageID::kGetPasswordTitle, NULL, NULL }, - { DI_TEXT, 5, 2, 0, 0, false, false, DIF_SHOWAMPERSAND, false, NMessageID::kEnterPasswordForFile, NULL, NULL }, - { DI_PSWEDIT, 5, 3, 70, 3, true, false, 0, true, -1, "", NULL } - }; - - const int kNumItems = Z7_ARRAY_SIZE(initItems); - FarDialogItem dialogItems[kNumItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumItems); - - // sprintf(DialogItems[1].Data,GetMsg(MGetPasswordForFile),FileName); - if (g_StartupInfo.ShowDialog(76, 6, NULL, dialogItems, kNumItems) < 0) - return E_ABORT; - - password = MultiByteToUnicodeString(dialogItems[2].Data, CP_OEMCP); - return S_OK; -} - -Z7_COM7F_IMF(COpenArchiveCallback::CryptoGetTextPassword(BSTR *password)) -{ - if (!PasswordIsDefined) - { - RINOK(GetPassword(Password)) - PasswordIsDefined = true; - } - return StringToBstr(Password, password); -} - -/* -HRESULT OpenArchive(const CSysString &fileName, - IInFolderArchive **archiveHandlerResult, - CArchiverInfo &archiverInfoResult, - UString &defaultName, - IArchiveOpenCallback *openArchiveCallback) -{ - HRESULT OpenArchive(const CSysString &fileName, - IInArchive **archive, - CArchiverInfo &archiverInfoResult, - IArchiveOpenCallback *openArchiveCallback); -} -*/ - -static HANDLE MyOpenFilePluginW(const wchar_t *name, bool isAbortCodeSupported) -{ - FString normalizedName = us2fs(name); - normalizedName.Trim(); - FString fullName; - MyGetFullPathName(normalizedName, fullName); - NFind::CFileInfo fileInfo; - if (!fileInfo.Find(fullName)) - return INVALID_HANDLE_VALUE; - if (fileInfo.IsDir()) - return INVALID_HANDLE_VALUE; - - - CMyComPtr archiveHandler; - - // CArchiverInfo archiverInfoResult; - // ::OutputDebugStringA("before OpenArchive\n"); - - CScreenRestorer screenRestorer; - { - screenRestorer.Save(); - } - - COpenArchiveCallback *openArchiveCallbackSpec = new COpenArchiveCallback; - CMyComPtr uiCallback = openArchiveCallbackSpec; - - /* COpenCallbackImp object will exist after Open stage for multivolume archioves */ - COpenCallbackImp *impSpec = new COpenCallbackImp; - CMyComPtr impCallback = impSpec; - impSpec->ReOpenCallback = openArchiveCallbackSpec; // we set pointer without reference counter - - // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) - openArchiveCallbackSpec->Init(); - { - FString dirPrefix, fileName; - GetFullPathAndSplit(fullName, dirPrefix, fileName); - impSpec->Init2(dirPrefix, fileName); - } - - // ::OutputDebugStringA("before OpenArchive\n"); - - CAgent *agent = new CAgent; - archiveHandler = agent; - CMyComBSTR archiveType; - HRESULT result = archiveHandler->Open(NULL, - GetUnicodeString(fullName, CP_OEMCP), UString(), &archiveType, impCallback); - /* - HRESULT result = ::OpenArchive(fullName, &archiveHandler, - archiverInfoResult, defaultName, openArchiveCallback); - */ - if (result == E_ABORT) - { - // fixed 18.06: - // OpenFilePlugin() is allowed to return (HANDLE)-2 as abort code - // OpenPlugin() is not allowed to return (HANDLE)-2. - return isAbortCodeSupported ? (HANDLE)-2 : INVALID_HANDLE_VALUE; - } - - UString errorMessage = agent->GetErrorMessage(); - if (!errorMessage.IsEmpty()) - g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(errorMessage, CP_OEMCP)); - - if (result != S_OK) - { - if (result == S_FALSE) - return INVALID_HANDLE_VALUE; - ShowSysErrorMessage(result); - return INVALID_HANDLE_VALUE; - } - - // ::OutputDebugStringA("after OpenArchive\n"); - - CPlugin *plugin = new CPlugin( - fullName, - // defaultName, - agent, - (const wchar_t *)archiveType - ); - - plugin->PasswordIsDefined = openArchiveCallbackSpec->PasswordIsDefined; - plugin->Password = openArchiveCallbackSpec->Password; - - // OutputDebugStringA("--- OpenFilePlugin ---- END"); - return (HANDLE)(plugin); -} - -static HANDLE MyOpenFilePlugin(const char *name, bool isAbortCodeSupported) -{ - UINT codePage = - #ifdef UNDER_CE - CP_OEMCP; - #else - ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; - #endif - return MyOpenFilePluginW(GetUnicodeString(name, codePage), isAbortCodeSupported); -} - -EXTERN_C HANDLE WINAPI OpenFilePlugin(char *name, const Byte * /* data */, int /* dataSize */) -{ - MY_TRY_BEGIN - // OutputDebugStringA("--- OpenFilePlugin"); - if (name == NULL || (!g_Options.Enabled)) - { - // if (!Opt.ProcessShiftF1) - return(INVALID_HANDLE_VALUE); - } - return MyOpenFilePlugin(name, true); // isAbortCodeSupported - MY_TRY_END2("OpenFilePlugin", INVALID_HANDLE_VALUE) -} - -/* -EXTERN_C HANDLE WINAPI OpenFilePluginW(const wchar_t *name,const Byte *Data,int DataSize,int OpMode) -{ - MY_TRY_BEGIN - if (name == NULL || (!g_Options.Enabled)) - { - // if (!Opt.ProcessShiftF1) - return(INVALID_HANDLE_VALUE); - } - return MyOpenFilePluginW(name); - ::OutputDebugStringA("OpenFilePluginW\n"); - MY_TRY_END2("OpenFilePluginW", INVALID_HANDLE_VALUE); -} -*/ - -EXTERN_C HANDLE WINAPI OpenPlugin(int openFrom, INT_PTR item) -{ - MY_TRY_BEGIN - - if (openFrom == OPEN_COMMANDLINE) - { - AString fileName ((const char *)item); - if (fileName.IsEmpty()) - return INVALID_HANDLE_VALUE; - if (fileName.Len() >= 2 - && fileName[0] == '\"' - && fileName.Back() == '\"') - { - fileName.DeleteBack(); - fileName.DeleteFrontal(1); - } - return MyOpenFilePlugin(fileName, false); // isAbortCodeSupported - } - - if (openFrom == OPEN_PLUGINSMENU) - { - switch (item) - { - case 0: - { - PluginPanelItem pluginPanelItem; - if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem)) - throw 142134; - return MyOpenFilePlugin(pluginPanelItem.FindData.cFileName, false); // isAbortCodeSupported - } - - case 1: - { - CObjectVector pluginPanelItem; - if (!g_StartupInfo.ControlGetActivePanelSelectedOrCurrentItems(pluginPanelItem)) - throw 142134; - HRESULT res = CompressFiles(pluginPanelItem); - if (res != S_OK && res != E_ABORT) - { - ShowSysErrorMessage(res); - } - // if (res == S_OK) - { - /* int t = */ g_StartupInfo.ControlClearPanelSelection(); - g_StartupInfo.ControlRequestActivePanel(FCTL_UPDATEPANEL, NULL); - g_StartupInfo.ControlRequestActivePanel(FCTL_REDRAWPANEL, NULL); - g_StartupInfo.ControlRequestActivePanel(FCTL_UPDATEANOTHERPANEL, NULL); - g_StartupInfo.ControlRequestActivePanel(FCTL_REDRAWANOTHERPANEL, NULL); - } - return INVALID_HANDLE_VALUE; - } - - default: - throw 4282215; - } - } - - return INVALID_HANDLE_VALUE; - MY_TRY_END2("OpenPlugin", INVALID_HANDLE_VALUE) -} - -EXTERN_C void WINAPI ClosePlugin(HANDLE plugin) -{ - // OutputDebugStringA("-- ClosePlugin --- START"); - // MY_TRY_BEGIN - delete (CPlugin *)plugin; - // OutputDebugStringA("-- ClosePlugin --- END"); - // MY_TRY_END1("ClosePlugin"); -} - -EXTERN_C int WINAPI GetFindData(HANDLE plugin, struct PluginPanelItem **panelItems, int *itemsNumber, int opMode) -{ - MY_TRY_BEGIN - return(((CPlugin *)plugin)->GetFindData(panelItems, itemsNumber, opMode)); - MY_TRY_END2("GetFindData", FALSE) -} - -EXTERN_C void WINAPI FreeFindData(HANDLE plugin, struct PluginPanelItem *panelItems, int itemsNumber) -{ - // MY_TRY_BEGIN - ((CPlugin *)plugin)->FreeFindData(panelItems, itemsNumber); - // MY_TRY_END1("FreeFindData"); -} - -EXTERN_C int WINAPI GetFiles(HANDLE plugin, struct PluginPanelItem *panelItems, - int itemsNumber, int move, char *destPath, int opMode) -{ - MY_TRY_BEGIN - return(((CPlugin *)plugin)->GetFiles(panelItems, (unsigned)itemsNumber, move, destPath, opMode)); - MY_TRY_END2("GetFiles", NFileOperationReturnCode::kError) -} - -EXTERN_C int WINAPI SetDirectory(HANDLE plugin, const char *dir, int opMode) -{ - MY_TRY_BEGIN - return(((CPlugin *)plugin)->SetDirectory(dir, opMode)); - MY_TRY_END2("SetDirectory", FALSE) -} - -EXTERN_C void WINAPI GetPluginInfo(struct PluginInfo *info) -{ - MY_TRY_BEGIN - - info->StructSize = sizeof(*info); - info->Flags = 0; - info->DiskMenuStrings = NULL; - info->DiskMenuNumbers = NULL; - info->DiskMenuStringsNumber = 0; - static char *pluginMenuStrings[2]; - pluginMenuStrings[0] = const_cast(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString)); - pluginMenuStrings[1] = const_cast(g_StartupInfo.GetMsgString(NMessageID::kCreateArchiveMenuString)); - info->PluginMenuStrings = (char **)pluginMenuStrings; - info->PluginMenuStringsNumber = 2; - static char *pluginCfgStrings[1]; - pluginCfgStrings[0] = const_cast(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString)); - info->PluginConfigStrings = (char **)pluginCfgStrings; - info->PluginConfigStringsNumber = Z7_ARRAY_SIZE(pluginCfgStrings); - info->CommandPrefix = const_cast(kCommandPrefix); - MY_TRY_END1("GetPluginInfo") -} - -EXTERN_C int WINAPI Configure(int /* itemNumber */) -{ - MY_TRY_BEGIN - - const int kEnabledCheckBoxIndex = 1; - - const int kYSize = 7; - - struct CInitDialogItem initItems[]= - { - { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kConfigTitle, NULL, NULL }, - { DI_CHECKBOX, 5, 2, 0, 0, true, g_Options.Enabled, 0, false, NMessageID::kConfigPluginEnabled, NULL, NULL }, - { DI_TEXT, 5, 3, 0, 0, false, false, DIF_BOXCOLOR | DIF_SEPARATOR, false, -1, "", NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL }, - }; - - const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); - const int kOkButtonIndex = kNumDialogItems - 2; - - FarDialogItem dialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); - - int askCode = g_StartupInfo.ShowDialog(76, kYSize, - kHelpTopicConfig, dialogItems, kNumDialogItems); - - if (askCode != kOkButtonIndex) - return (FALSE); - - g_Options.Enabled = BOOLToBool(dialogItems[kEnabledCheckBoxIndex].Selected); - - g_StartupInfo.SetRegKeyValue(HKEY_CURRENT_USER, kRegisrtryMainKeyName, - kRegisrtryValueNameEnabled, g_Options.Enabled); - return(TRUE); - MY_TRY_END2("Configure", FALSE) -} - -EXTERN_C void WINAPI GetOpenPluginInfo(HANDLE plugin,struct OpenPluginInfo *info) -{ - MY_TRY_BEGIN - ((CPlugin *)plugin)->GetOpenPluginInfo(info); - MY_TRY_END1("GetOpenPluginInfo") -} - -EXTERN_C int WINAPI PutFiles(HANDLE plugin, struct PluginPanelItem *panelItems, int itemsNumber, int move, int opMode) -{ - MY_TRY_BEGIN - return (((CPlugin *)plugin)->PutFiles(panelItems, (unsigned)itemsNumber, move, opMode)); - MY_TRY_END2("PutFiles", NFileOperationReturnCode::kError) -} - -EXTERN_C int WINAPI DeleteFiles(HANDLE plugin, PluginPanelItem *panelItems, int itemsNumber, int opMode) -{ - MY_TRY_BEGIN - return (((CPlugin *)plugin)->DeleteFiles(panelItems, (unsigned)itemsNumber, opMode)); - MY_TRY_END2("DeleteFiles", FALSE) -} - -EXTERN_C int WINAPI ProcessKey(HANDLE plugin, int key, unsigned controlState) -{ - MY_TRY_BEGIN - /* FIXME: after folder creation with F7, it doesn't reload new file list - We need some to reload it */ - return (((CPlugin *)plugin)->ProcessKey(key, controlState)); - MY_TRY_END2("ProcessKey", FALSE) -} - -/* -struct MakeDirectoryInfo -{ - size_t StructSize; - HANDLE hPanel; - const wchar_t *Name; - OPERATION_MODES OpMode; - void* Instance; -}; - -typedef INT_PTR MY_intptr_t; - -MY_intptr_t WINAPI MakeDirectoryW(struct MakeDirectoryInfo *Info) -{ - MY_TRY_BEGIN - if (Info->StructSize < sizeof(MakeDirectoryInfo)) - { - return 0; - } - return 0; - MY_TRY_END2("MakeDirectoryW", FALSE); -} -*/ +// Far.cpp +// Test Align for updating !!!!!!!!!!!!!!!!!! + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/NtCheck.h" + +#include "../../Common/FileStreams.h" + +#include "Messages.h" +#include "Plugin.h" +#include "ProgressBox.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NFar; + +static const DWORD kShowProgressTime_ms = 100; + +static const char * const kCommandPrefix = "7-zip"; +static const char * const kRegisrtryMainKeyName = NULL; // "" +static LPCTSTR const kRegisrtryValueNameEnabled = TEXT("UsedByDefault3"); +static const char * const kHelpTopicConfig = "Config"; +static bool kPluginEnabledDefault = true; + +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance; + +namespace NFar { + +extern +const char *g_PluginName_for_Error; +const char *g_PluginName_for_Error = "7-Zip"; + +} + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION return FALSE; +#endif + +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + hInstance, DWORD dwReason, LPVOID); +BOOL WINAPI DllMain( + #ifdef UNDER_CE + HANDLE + #else + HINSTANCE + #endif + hInstance, DWORD dwReason, LPVOID) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + // OutputDebugStringA("7-Zip FAR DLL_PROCESS_ATTACH"); + g_hInstance = (HINSTANCE)hInstance; + NT_CHECK + } + if (dwReason == DLL_PROCESS_DETACH) + { + // OutputDebugStringA("7-Zip FAR DLL_PROCESS_DETACH"); + } + return TRUE; +} + +static struct COptions +{ + bool Enabled; +} g_Options; + +static const char * const kPliginNameForRegistry = "7-ZIP"; + +EXTERN_C void WINAPI ExitFAR() +{ + /* WIN32: + it's not allowed to call FreeLibrary() from FreeLibrary(). + So we try to free all DLLs before destructors */ + // OutputDebugStringA("-- ExitFAR --- START"); + + FreeGlobalCodecs(); + + // OutputDebugStringA("-- ExitFAR --- END"); +} + +EXTERN_C void WINAPI SetStartupInfo(const PluginStartupInfo *info) +{ + MY_TRY_BEGIN + g_StartupInfo.Init(*info, kPliginNameForRegistry); + g_Options.Enabled = g_StartupInfo.QueryRegKeyValue( + HKEY_CURRENT_USER, kRegisrtryMainKeyName, + kRegisrtryValueNameEnabled, kPluginEnabledDefault); + + // OutputDebugStringA("SetStartupInfo"); + // LoadGlobalCodecs(); + + MY_TRY_END1("SetStartupInfo") +} + +Z7_CLASS_IMP_COM_3( + COpenArchiveCallback + , IArchiveOpenCallback + , IProgress + , ICryptoGetTextPassword +) + // DWORD m_StartTickValue; + bool m_MessageBoxIsShown; + + bool _numFilesTotalDefined; + bool _numBytesTotalDefined; +public: + bool PasswordIsDefined; + UString Password; + +private: + CProgressBox _progressBox; +public: + + COpenArchiveCallback() + {} + + void Init() + { + PasswordIsDefined = false; + + _numFilesTotalDefined = false; + _numBytesTotalDefined = false; + + m_MessageBoxIsShown = false; + + _progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kReading)); + } + void ShowMessage(); +}; + +static HRESULT CheckBreak2() +{ + return WasEscPressed() ? E_ABORT : S_OK; +} + +void COpenArchiveCallback::ShowMessage() +{ + if (!m_MessageBoxIsShown) + { + DWORD currentTime = GetTickCount(); + if (currentTime - _progressBox.StartTick < kShowProgressTime_ms) + return; + m_MessageBoxIsShown = true; + } + + _progressBox.UseBytesForPercents = !_numFilesTotalDefined; + _progressBox.Print(); +} + +Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes)) +{ + _numFilesTotalDefined = (numFiles != NULL); + if (_numFilesTotalDefined) + _progressBox.FilesTotal = *numFiles; + + _numBytesTotalDefined = (numBytes != NULL); + if (_numBytesTotalDefined) + _progressBox.Total = *numBytes; + + return CheckBreak2(); +} + +Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes)) +{ + if (numFiles) + _progressBox.Files = *numFiles; + + if (numBytes) + _progressBox.Completed = *numBytes; + + ShowMessage(); + return CheckBreak2(); +} + + +Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 /* total */)) +{ + return CheckBreak2(); +} + +Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 * /* completed */)) +{ + ShowMessage(); + return CheckBreak2(); +} + +HRESULT GetPassword(UString &password); +HRESULT GetPassword(UString &password) +{ + if (WasEscPressed()) + return E_ABORT; + password.Empty(); + CInitDialogItem initItems[]= + { + { DI_DOUBLEBOX, 3, 1, 72, 4, false, false, 0, false, NMessageID::kGetPasswordTitle, NULL, NULL }, + { DI_TEXT, 5, 2, 0, 0, false, false, DIF_SHOWAMPERSAND, false, NMessageID::kEnterPasswordForFile, NULL, NULL }, + { DI_PSWEDIT, 5, 3, 70, 3, true, false, 0, true, -1, "", NULL } + }; + + const int kNumItems = Z7_ARRAY_SIZE(initItems); + FarDialogItem dialogItems[kNumItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumItems); + + // sprintf(DialogItems[1].Data,GetMsg(MGetPasswordForFile),FileName); + if (g_StartupInfo.ShowDialog(76, 6, NULL, dialogItems, kNumItems) < 0) + return E_ABORT; + + password = MultiByteToUnicodeString(dialogItems[2].Data, CP_OEMCP); + return S_OK; +} + +Z7_COM7F_IMF(COpenArchiveCallback::CryptoGetTextPassword(BSTR *password)) +{ + if (!PasswordIsDefined) + { + RINOK(GetPassword(Password)) + PasswordIsDefined = true; + } + return StringToBstr(Password, password); +} + +/* +HRESULT OpenArchive(const CSysString &fileName, + IInFolderArchive **archiveHandlerResult, + CArchiverInfo &archiverInfoResult, + UString &defaultName, + IArchiveOpenCallback *openArchiveCallback) +{ + HRESULT OpenArchive(const CSysString &fileName, + IInArchive **archive, + CArchiverInfo &archiverInfoResult, + IArchiveOpenCallback *openArchiveCallback); +} +*/ + +static HANDLE MyOpenFilePluginW(const wchar_t *name, bool isAbortCodeSupported) +{ + FString normalizedName = us2fs(name); + normalizedName.Trim(); + FString fullName; + MyGetFullPathName(normalizedName, fullName); + NFind::CFileInfo fileInfo; + if (!fileInfo.Find(fullName)) + return INVALID_HANDLE_VALUE; + if (fileInfo.IsDir()) + return INVALID_HANDLE_VALUE; + + + CMyComPtr archiveHandler; + + // CArchiverInfo archiverInfoResult; + // ::OutputDebugStringA("before OpenArchive\n"); + + CScreenRestorer screenRestorer; + { + screenRestorer.Save(); + } + + COpenArchiveCallback *openArchiveCallbackSpec = new COpenArchiveCallback; + CMyComPtr uiCallback = openArchiveCallbackSpec; + + /* COpenCallbackImp object will exist after Open stage for multivolume archioves */ + COpenCallbackImp *impSpec = new COpenCallbackImp; + CMyComPtr impCallback = impSpec; + impSpec->ReOpenCallback = openArchiveCallbackSpec; // we set pointer without reference counter + + // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) + openArchiveCallbackSpec->Init(); + { + FString dirPrefix, fileName; + GetFullPathAndSplit(fullName, dirPrefix, fileName); + impSpec->Init2(dirPrefix, fileName); + } + + // ::OutputDebugStringA("before OpenArchive\n"); + + CAgent *agent = new CAgent; + archiveHandler = agent; + CMyComBSTR archiveType; + HRESULT result = archiveHandler->Open(NULL, + GetUnicodeString(fullName, CP_OEMCP), UString(), &archiveType, impCallback); + /* + HRESULT result = ::OpenArchive(fullName, &archiveHandler, + archiverInfoResult, defaultName, openArchiveCallback); + */ + if (result == E_ABORT) + { + // fixed 18.06: + // OpenFilePlugin() is allowed to return (HANDLE)-2 as abort code + // OpenPlugin() is not allowed to return (HANDLE)-2. + return isAbortCodeSupported ? (HANDLE)-2 : INVALID_HANDLE_VALUE; + } + + UString errorMessage = agent->GetErrorMessage(); + if (!errorMessage.IsEmpty()) + g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(errorMessage, CP_OEMCP)); + + if (result != S_OK) + { + if (result == S_FALSE) + return INVALID_HANDLE_VALUE; + ShowSysErrorMessage(result); + return INVALID_HANDLE_VALUE; + } + + // ::OutputDebugStringA("after OpenArchive\n"); + + CPlugin *plugin = new CPlugin( + fullName, + // defaultName, + agent, + (const wchar_t *)archiveType + ); + + plugin->PasswordIsDefined = openArchiveCallbackSpec->PasswordIsDefined; + plugin->Password = openArchiveCallbackSpec->Password; + + // OutputDebugStringA("--- OpenFilePlugin ---- END"); + return (HANDLE)(plugin); +} + +static HANDLE MyOpenFilePlugin(const char *name, bool isAbortCodeSupported) +{ + UINT codePage = + #ifdef UNDER_CE + CP_OEMCP; + #else + ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; + #endif + return MyOpenFilePluginW(GetUnicodeString(name, codePage), isAbortCodeSupported); +} + +EXTERN_C HANDLE WINAPI OpenFilePlugin(char *name, const Byte * /* data */, int /* dataSize */) +{ + MY_TRY_BEGIN + // OutputDebugStringA("--- OpenFilePlugin"); + if (name == NULL || (!g_Options.Enabled)) + { + // if (!Opt.ProcessShiftF1) + return(INVALID_HANDLE_VALUE); + } + return MyOpenFilePlugin(name, true); // isAbortCodeSupported + MY_TRY_END2("OpenFilePlugin", INVALID_HANDLE_VALUE) +} + +/* +EXTERN_C HANDLE WINAPI OpenFilePluginW(const wchar_t *name,const Byte *Data,int DataSize,int OpMode) +{ + MY_TRY_BEGIN + if (name == NULL || (!g_Options.Enabled)) + { + // if (!Opt.ProcessShiftF1) + return(INVALID_HANDLE_VALUE); + } + return MyOpenFilePluginW(name); + ::OutputDebugStringA("OpenFilePluginW\n"); + MY_TRY_END2("OpenFilePluginW", INVALID_HANDLE_VALUE); +} +*/ + +EXTERN_C HANDLE WINAPI OpenPlugin(int openFrom, INT_PTR item) +{ + MY_TRY_BEGIN + + if (openFrom == OPEN_COMMANDLINE) + { + AString fileName ((const char *)item); + if (fileName.IsEmpty()) + return INVALID_HANDLE_VALUE; + if (fileName.Len() >= 2 + && fileName[0] == '\"' + && fileName.Back() == '\"') + { + fileName.DeleteBack(); + fileName.DeleteFrontal(1); + } + return MyOpenFilePlugin(fileName, false); // isAbortCodeSupported + } + + if (openFrom == OPEN_PLUGINSMENU) + { + switch (item) + { + case 0: + { + PluginPanelItem pluginPanelItem; + if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem)) + throw 142134; + return MyOpenFilePlugin(pluginPanelItem.FindData.cFileName, false); // isAbortCodeSupported + } + + case 1: + { + CObjectVector pluginPanelItem; + if (!g_StartupInfo.ControlGetActivePanelSelectedOrCurrentItems(pluginPanelItem)) + throw 142134; + HRESULT res = CompressFiles(pluginPanelItem); + if (res != S_OK && res != E_ABORT) + { + ShowSysErrorMessage(res); + } + // if (res == S_OK) + { + /* int t = */ g_StartupInfo.ControlClearPanelSelection(); + g_StartupInfo.ControlRequestActivePanel(FCTL_UPDATEPANEL, NULL); + g_StartupInfo.ControlRequestActivePanel(FCTL_REDRAWPANEL, NULL); + g_StartupInfo.ControlRequestActivePanel(FCTL_UPDATEANOTHERPANEL, NULL); + g_StartupInfo.ControlRequestActivePanel(FCTL_REDRAWANOTHERPANEL, NULL); + } + return INVALID_HANDLE_VALUE; + } + + default: + throw 4282215; + } + } + + return INVALID_HANDLE_VALUE; + MY_TRY_END2("OpenPlugin", INVALID_HANDLE_VALUE) +} + +EXTERN_C void WINAPI ClosePlugin(HANDLE plugin) +{ + // OutputDebugStringA("-- ClosePlugin --- START"); + // MY_TRY_BEGIN + delete (CPlugin *)plugin; + // OutputDebugStringA("-- ClosePlugin --- END"); + // MY_TRY_END1("ClosePlugin"); +} + +EXTERN_C int WINAPI GetFindData(HANDLE plugin, struct PluginPanelItem **panelItems, int *itemsNumber, int opMode) +{ + MY_TRY_BEGIN + return(((CPlugin *)plugin)->GetFindData(panelItems, itemsNumber, opMode)); + MY_TRY_END2("GetFindData", FALSE) +} + +EXTERN_C void WINAPI FreeFindData(HANDLE plugin, struct PluginPanelItem *panelItems, int itemsNumber) +{ + // MY_TRY_BEGIN + ((CPlugin *)plugin)->FreeFindData(panelItems, itemsNumber); + // MY_TRY_END1("FreeFindData"); +} + +EXTERN_C int WINAPI GetFiles(HANDLE plugin, struct PluginPanelItem *panelItems, + int itemsNumber, int move, char *destPath, int opMode) +{ + MY_TRY_BEGIN + return(((CPlugin *)plugin)->GetFiles(panelItems, (unsigned)itemsNumber, move, destPath, opMode)); + MY_TRY_END2("GetFiles", NFileOperationReturnCode::kError) +} + +EXTERN_C int WINAPI SetDirectory(HANDLE plugin, const char *dir, int opMode) +{ + MY_TRY_BEGIN + return(((CPlugin *)plugin)->SetDirectory(dir, opMode)); + MY_TRY_END2("SetDirectory", FALSE) +} + +EXTERN_C void WINAPI GetPluginInfo(struct PluginInfo *info) +{ + MY_TRY_BEGIN + + info->StructSize = sizeof(*info); + info->Flags = 0; + info->DiskMenuStrings = NULL; + info->DiskMenuNumbers = NULL; + info->DiskMenuStringsNumber = 0; + static char *pluginMenuStrings[2]; + pluginMenuStrings[0] = const_cast(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString)); + pluginMenuStrings[1] = const_cast(g_StartupInfo.GetMsgString(NMessageID::kCreateArchiveMenuString)); + info->PluginMenuStrings = (char **)pluginMenuStrings; + info->PluginMenuStringsNumber = 2; + static char *pluginCfgStrings[1]; + pluginCfgStrings[0] = const_cast(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString)); + info->PluginConfigStrings = (char **)pluginCfgStrings; + info->PluginConfigStringsNumber = Z7_ARRAY_SIZE(pluginCfgStrings); + info->CommandPrefix = const_cast(kCommandPrefix); + MY_TRY_END1("GetPluginInfo") +} + +EXTERN_C int WINAPI Configure(int /* itemNumber */) +{ + MY_TRY_BEGIN + + const int kEnabledCheckBoxIndex = 1; + + const int kYSize = 7; + + struct CInitDialogItem initItems[]= + { + { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kConfigTitle, NULL, NULL }, + { DI_CHECKBOX, 5, 2, 0, 0, true, g_Options.Enabled, 0, false, NMessageID::kConfigPluginEnabled, NULL, NULL }, + { DI_TEXT, 5, 3, 0, 0, false, false, DIF_BOXCOLOR | DIF_SEPARATOR, false, -1, "", NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL }, + }; + + const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); + const int kOkButtonIndex = kNumDialogItems - 2; + + FarDialogItem dialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); + + int askCode = g_StartupInfo.ShowDialog(76, kYSize, + kHelpTopicConfig, dialogItems, kNumDialogItems); + + if (askCode != kOkButtonIndex) + return (FALSE); + + g_Options.Enabled = BOOLToBool(dialogItems[kEnabledCheckBoxIndex].Selected); + + g_StartupInfo.SetRegKeyValue(HKEY_CURRENT_USER, kRegisrtryMainKeyName, + kRegisrtryValueNameEnabled, g_Options.Enabled); + return(TRUE); + MY_TRY_END2("Configure", FALSE) +} + +EXTERN_C void WINAPI GetOpenPluginInfo(HANDLE plugin,struct OpenPluginInfo *info) +{ + MY_TRY_BEGIN + ((CPlugin *)plugin)->GetOpenPluginInfo(info); + MY_TRY_END1("GetOpenPluginInfo") +} + +EXTERN_C int WINAPI PutFiles(HANDLE plugin, struct PluginPanelItem *panelItems, int itemsNumber, int move, int opMode) +{ + MY_TRY_BEGIN + return (((CPlugin *)plugin)->PutFiles(panelItems, (unsigned)itemsNumber, move, opMode)); + MY_TRY_END2("PutFiles", NFileOperationReturnCode::kError) +} + +EXTERN_C int WINAPI DeleteFiles(HANDLE plugin, PluginPanelItem *panelItems, int itemsNumber, int opMode) +{ + MY_TRY_BEGIN + return (((CPlugin *)plugin)->DeleteFiles(panelItems, (unsigned)itemsNumber, opMode)); + MY_TRY_END2("DeleteFiles", FALSE) +} + +EXTERN_C int WINAPI ProcessKey(HANDLE plugin, int key, unsigned controlState) +{ + MY_TRY_BEGIN + /* FIXME: after folder creation with F7, it doesn't reload new file list + We need some to reload it */ + return (((CPlugin *)plugin)->ProcessKey(key, controlState)); + MY_TRY_END2("ProcessKey", FALSE) +} + +/* +struct MakeDirectoryInfo +{ + size_t StructSize; + HANDLE hPanel; + const wchar_t *Name; + OPERATION_MODES OpMode; + void* Instance; +}; + +typedef INT_PTR MY_intptr_t; + +MY_intptr_t WINAPI MakeDirectoryW(struct MakeDirectoryInfo *Info) +{ + MY_TRY_BEGIN + if (Info->StructSize < sizeof(MakeDirectoryInfo)) + { + return 0; + } + return 0; + MY_TRY_END2("MakeDirectoryW", FALSE); +} +*/ diff --git a/CPP/7zip/UI/Far/Far.def b/CPP/7zip/UI/Far/Far.def index 1b345d243..1de9acdf7 100644 --- a/CPP/7zip/UI/Far/Far.def +++ b/CPP/7zip/UI/Far/Far.def @@ -1,35 +1,35 @@ -; 7-ZipFar.def : Declares the module parameters for the DLL. - -LIBRARY "7-ZipFar" - -EXPORTS - ExitFAR - SetStartupInfo - OpenPlugin - OpenFilePlugin - ClosePlugin - GetFindData - FreeFindData - SetDirectory - GetPluginInfo - Configure - GetOpenPluginInfo - GetFiles - PutFiles - DeleteFiles - ProcessKey - - ;SetStartupInfoW - ;OpenPluginW - ;OpenFilePluginW - ;ClosePluginW - ;GetFindDataW - ;FreeFindDataW - ;SetDirectoryW - ;GetPluginInfoW - ;ConfigureW - ;GetOpenPluginInfoW - ;GetFilesW - ;PutFilesW - ;DeleteFilesW - ;ProcessKeyW +; 7-ZipFar.def : Declares the module parameters for the DLL. + +LIBRARY "7-ZipFar" + +EXPORTS + ExitFAR + SetStartupInfo + OpenPlugin + OpenFilePlugin + ClosePlugin + GetFindData + FreeFindData + SetDirectory + GetPluginInfo + Configure + GetOpenPluginInfo + GetFiles + PutFiles + DeleteFiles + ProcessKey + + ;SetStartupInfoW + ;OpenPluginW + ;OpenFilePluginW + ;ClosePluginW + ;GetFindDataW + ;FreeFindDataW + ;SetDirectoryW + ;GetPluginInfoW + ;ConfigureW + ;GetOpenPluginInfoW + ;GetFilesW + ;PutFilesW + ;DeleteFilesW + ;ProcessKeyW diff --git a/CPP/7zip/UI/Far/Far.dsp b/CPP/7zip/UI/Far/Far.dsp index 6cec6cf1f..823c728dc 100644 --- a/CPP/7zip/UI/Far/Far.dsp +++ b/CPP/7zip/UI/Far/Far.dsp @@ -1,831 +1,831 @@ -# Microsoft Developer Studio Project File - Name="Far" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=Far - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Far.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Far.mak" CFG="Far - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Far - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Far - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Far - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /YX /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Progs\Far\Plugins\7-Zip\7-ZipFar.dll" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "Far - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Progs\Far\Plugins\7-Zip\7-ZipFar.dll" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "Far - Win32 Release" -# Name "Far - Win32 Debug" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\Far.def -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "Plugin" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\ExtractEngine.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractEngine.h -# End Source File -# Begin Source File - -SOURCE=.\Far.cpp -# End Source File -# Begin Source File - -SOURCE=.\Messages.h -# End Source File -# Begin Source File - -SOURCE=.\OverwriteDialogFar.cpp -# End Source File -# Begin Source File - -SOURCE=.\OverwriteDialogFar.h -# End Source File -# Begin Source File - -SOURCE=.\Plugin.cpp -# End Source File -# Begin Source File - -SOURCE=.\Plugin.h -# End Source File -# Begin Source File - -SOURCE=.\PluginDelete.cpp -# End Source File -# Begin Source File - -SOURCE=.\PluginRead.cpp -# End Source File -# Begin Source File - -SOURCE=.\PluginWrite.cpp -# End Source File -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackFar.cpp -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackFar.h -# End Source File -# End Group -# Begin Group "Far" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\FarPlugin.h -# End Source File -# Begin Source File - -SOURCE=.\FarUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\FarUtils.h -# End Source File -# Begin Source File - -SOURCE=.\ProgressBox.cpp -# End Source File -# Begin Source File - -SOURCE=.\ProgressBox.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\HandlerLoader.h -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.h -# End Source File -# Begin Source File - -SOURCE=..\Common\WorkDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\WorkDir.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.h -# End Source File -# End Group -# Begin Group "Agent" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Agent\Agent.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\Agent.h -# End Source File -# Begin Source File - -SOURCE=..\Agent\AgentOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\AgentProxy.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\AgentProxy.h -# End Source File -# Begin Source File - -SOURCE=..\Agent\ArchiveFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\ArchiveFolderOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\IFolderArchive.h -# End Source File -# Begin Source File - -SOURCE=..\Agent\UpdateCallbackAgent.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\UpdateCallbackAgent.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# End Group -# Begin Group "7-zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "Arc Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# Begin Group "Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\Common\IFileExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\IFolder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="Far" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=Far - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Far.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Far.mak" CFG="Far - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Far - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "Far - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Far - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Progs\Far\Plugins\7-Zip\7-ZipFar.dll" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "Far - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Progs\Far\Plugins\7-Zip\7-ZipFar.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Far - Win32 Release" +# Name "Far - Win32 Debug" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Far.def +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "Plugin" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ExtractEngine.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractEngine.h +# End Source File +# Begin Source File + +SOURCE=.\Far.cpp +# End Source File +# Begin Source File + +SOURCE=.\Messages.h +# End Source File +# Begin Source File + +SOURCE=.\OverwriteDialogFar.cpp +# End Source File +# Begin Source File + +SOURCE=.\OverwriteDialogFar.h +# End Source File +# Begin Source File + +SOURCE=.\Plugin.cpp +# End Source File +# Begin Source File + +SOURCE=.\Plugin.h +# End Source File +# Begin Source File + +SOURCE=.\PluginDelete.cpp +# End Source File +# Begin Source File + +SOURCE=.\PluginRead.cpp +# End Source File +# Begin Source File + +SOURCE=.\PluginWrite.cpp +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackFar.cpp +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackFar.h +# End Source File +# End Group +# Begin Group "Far" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\FarPlugin.h +# End Source File +# Begin Source File + +SOURCE=.\FarUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\FarUtils.h +# End Source File +# Begin Source File + +SOURCE=.\ProgressBox.cpp +# End Source File +# Begin Source File + +SOURCE=.\ProgressBox.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\HandlerLoader.h +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.h +# End Source File +# Begin Source File + +SOURCE=..\Common\WorkDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\WorkDir.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.h +# End Source File +# End Group +# Begin Group "Agent" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Agent\Agent.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\Agent.h +# End Source File +# Begin Source File + +SOURCE=..\Agent\AgentOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\AgentProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\AgentProxy.h +# End Source File +# Begin Source File + +SOURCE=..\Agent\ArchiveFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\ArchiveFolderOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\IFolderArchive.h +# End Source File +# Begin Source File + +SOURCE=..\Agent\UpdateCallbackAgent.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\UpdateCallbackAgent.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# End Group +# Begin Group "7-zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "Arc Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\Common\IFileExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\IFolder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/UI/Far/Far.dsw b/CPP/7zip/UI/Far/Far.dsw index ed5200341..f4ef08019 100644 --- a/CPP/7zip/UI/Far/Far.dsw +++ b/CPP/7zip/UI/Far/Far.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Far"=.\Far.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Far"=.\Far.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/UI/Far/FarPlugin.h b/CPP/7zip/UI/Far/FarPlugin.h index b4ac341b6..68c767b3e 100644 --- a/CPP/7zip/UI/Far/FarPlugin.h +++ b/CPP/7zip/UI/Far/FarPlugin.h @@ -1,560 +1,560 @@ -// FarPlugin.h - -// #include "plugin.hpp" - -const int kInfoPanelLineSize = 80; - -// #define __FAR_PLUGIN_H - -#ifdef UNDER_CE -typedef struct { - union { - WCHAR UnicodeChar; - CHAR AsciiChar; - } Char; - WORD Attributes; -} CHAR_INFO, *PCHAR_INFO; -#endif - -#ifndef ZIP7_INC_FAR_PLUGIN_H -#define ZIP7_INC_FAR_PLUGIN_H - -#ifndef _WIN64 -#if defined(__BORLANDC__) && (__BORLANDC <= 0x520) - #pragma option -a1 -#elif defined(__GNUC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100)) - #pragma pack(1) -#else - #pragma pack(push,1) -#endif -#endif - - // #if _MSC_VER - #define _export - // #endif - -#define NM 260 - -struct FarFindData -{ - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - char cFileName[ MAX_PATH ]; - char cAlternateFileName[ 14 ]; -}; - -struct PluginPanelItem -{ - FarFindData FindData; - DWORD PackSizeHigh; - DWORD PackSize; - DWORD Flags; - DWORD NumberOfLinks; - char *Description; - char *Owner; - char **CustomColumnData; - int CustomColumnNumber; - DWORD_PTR UserData; - DWORD CRC32; - DWORD_PTR Reserved[2]; -}; - -#define PPIF_PROCESSDESCR 0x80000000 -#define PPIF_SELECTED 0x40000000 -#define PPIF_USERDATA 0x20000000 - -enum { - FMENU_SHOWAMPERSAND=1, - FMENU_WRAPMODE=2, - FMENU_AUTOHIGHLIGHT=4, - FMENU_REVERSEAUTOHIGHLIGHT=8 -}; - - -typedef int (WINAPI *FARAPIMENU)( - INT_PTR PluginNumber, - int X, - int Y, - int MaxHeight, - unsigned Flags, - char *Title, - char *Bottom, - char *HelpTopic, - int *BreakKeys, - int *BreakCode, - struct FarMenuItem *Item, - int ItemsNumber -); - -typedef int (WINAPI *FARAPIDIALOG)( - INT_PTR PluginNumber, - int X1, - int Y1, - int X2, - int Y2, - char *HelpTopic, - struct FarDialogItem *Item, - int ItemsNumber -); - -enum { - FMSG_WARNING = 0x00000001, - FMSG_ERRORTYPE = 0x00000002, - FMSG_KEEPBACKGROUND = 0x00000004, - FMSG_DOWN = 0x00000008, - FMSG_LEFTALIGN = 0x00000010, - - FMSG_ALLINONE = 0x00000020, - - FMSG_MB_OK = 0x00010000, - FMSG_MB_OKCANCEL = 0x00020000, - FMSG_MB_ABORTRETRYIGNORE = 0x00030000, - FMSG_MB_YESNO = 0x00040000, - FMSG_MB_YESNOCANCEL = 0x00050000, - FMSG_MB_RETRYCANCEL = 0x00060000 -}; - -typedef int (WINAPI *FARAPIMESSAGE)( - INT_PTR PluginNumber, - unsigned Flags, - const char *HelpTopic, - const char * const *Items, - int ItemsNumber, - int ButtonsNumber -); - -typedef char* (WINAPI *FARAPIGETMSG)( - INT_PTR PluginNumber, - int MsgId -); - - -enum DialogItemTypes { - DI_TEXT, - DI_VTEXT, - DI_SINGLEBOX, - DI_DOUBLEBOX, - DI_EDIT, - DI_PSWEDIT, - DI_FIXEDIT, - DI_BUTTON, - DI_CHECKBOX, - DI_RADIOBUTTON -}; - -enum FarDialogItemFlags { - DIF_COLORMASK = 0xff, - DIF_SETCOLOR = 0x100, - DIF_BOXCOLOR = 0x200, - DIF_GROUP = 0x400, - DIF_LEFTTEXT = 0x800, - DIF_MOVESELECT = 0x1000, - DIF_SHOWAMPERSAND = 0x2000, - DIF_CENTERGROUP = 0x4000, - DIF_NOBRACKETS = 0x8000, - DIF_SEPARATOR = 0x10000, - DIF_EDITOR = 0x20000, - DIF_HISTORY = 0x40000 -}; - -struct FarDialogItem -{ - int Type; - int X1,Y1,X2,Y2; - int Focus; - union - { - int Selected; - const char *History; - const char *Mask; - struct FarList *ListItems; - int ListPos; - CHAR_INFO *VBuf; - }; - unsigned Flags; - int DefaultButton; - char Data[512]; -}; - - -struct FarMenuItem -{ - char Text[128]; - int Selected; - int Checked; - int Separator; -}; - - -enum {FCTL_CLOSEPLUGIN,FCTL_GETPANELINFO,FCTL_GETANOTHERPANELINFO, - FCTL_UPDATEPANEL,FCTL_UPDATEANOTHERPANEL, - FCTL_REDRAWPANEL,FCTL_REDRAWANOTHERPANEL, - FCTL_SETANOTHERPANELDIR,FCTL_GETCMDLINE,FCTL_SETCMDLINE, - FCTL_SETSELECTION,FCTL_SETANOTHERSELECTION, - FCTL_SETVIEWMODE,FCTL_SETANOTHERVIEWMODE,FCTL_INSERTCMDLINE, - FCTL_SETUSERSCREEN,FCTL_SETPANELDIR,FCTL_SETCMDLINEPOS, - FCTL_GETCMDLINEPOS -}; - -enum {PTYPE_FILEPANEL,PTYPE_TREEPANEL,PTYPE_QVIEWPANEL,PTYPE_INFOPANEL}; - -struct PanelInfo -{ - int PanelType; - int Plugin; - RECT PanelRect; - struct PluginPanelItem *PanelItems; - int ItemsNumber; - struct PluginPanelItem *SelectedItems; - int SelectedItemsNumber; - int CurrentItem; - int TopPanelItem; - int Visible; - int Focus; - int ViewMode; - char ColumnTypes[80]; - char ColumnWidths[80]; - char CurDir[NM]; - int ShortNames; - int SortMode; - DWORD Flags; - DWORD Reserved; -}; - - -struct PanelRedrawInfo -{ - int CurrentItem; - int TopPanelItem; -}; - - -typedef int (WINAPI *FARAPICONTROL)( - HANDLE hPlugin, - int Command, - void *Param -); - -typedef HANDLE (WINAPI *FARAPISAVESCREEN)(int X1,int Y1,int X2,int Y2); - -typedef void (WINAPI *FARAPIRESTORESCREEN)(HANDLE hScreen); - -typedef int (WINAPI *FARAPIGETDIRLIST)( - char *Dir, - struct PluginPanelItem **pPanelItem, - int *pItemsNumber -); - -typedef int (WINAPI *FARAPIGETPLUGINDIRLIST)( - INT_PTR PluginNumber, - HANDLE hPlugin, - char *Dir, - struct PluginPanelItem **pPanelItem, - int *pItemsNumber -); - -typedef void (WINAPI *FARAPIFREEDIRLIST)(struct PluginPanelItem *PanelItem); - -enum VIEWER_FLAGS { - VF_NONMODAL=1,VF_DELETEONCLOSE=2 -}; - -typedef int (WINAPI *FARAPIVIEWER)( - char *FileName, - char *Title, - int X1, - int Y1, - int X2, - int Y2, - DWORD Flags -); - -typedef int (WINAPI *FARAPIEDITOR)( - char *FileName, - char *Title, - int X1, - int Y1, - int X2, - int Y2, - DWORD Flags, - int StartLine, - int StartChar -); - -typedef int (WINAPI *FARAPICMPNAME)( - char *Pattern, - char *String, - int SkipPath -); - - -#define FCT_DETECT 0x40000000 - -struct CharTableSet -{ - char DecodeTable[256]; - char EncodeTable[256]; - char UpperTable[256]; - char LowerTable[256]; - char TableName[128]; -}; - -typedef int (WINAPI *FARAPICHARTABLE)( - int Command, - char *Buffer, - int BufferSize -); - -typedef void (WINAPI *FARAPITEXT)( - int X, - int Y, - int Color, - char *Str -); - - -typedef int (WINAPI *FARAPIEDITORCONTROL)( - int Command, - void *Param -); - -struct PluginStartupInfo -{ - int StructSize; - char ModuleName[NM]; - INT_PTR ModuleNumber; - char *RootKey; - FARAPIMENU Menu; - FARAPIDIALOG Dialog; - FARAPIMESSAGE Message; - FARAPIGETMSG GetMsg; - FARAPICONTROL Control; - FARAPISAVESCREEN SaveScreen; - FARAPIRESTORESCREEN RestoreScreen; - FARAPIGETDIRLIST GetDirList; - FARAPIGETPLUGINDIRLIST GetPluginDirList; - FARAPIFREEDIRLIST FreeDirList; - FARAPIVIEWER Viewer; - FARAPIEDITOR Editor; - FARAPICMPNAME CmpName; - FARAPICHARTABLE CharTable; - FARAPITEXT Text; - FARAPIEDITORCONTROL EditorControl; -}; - - -enum PLUGIN_FLAGS { - PF_PRELOAD = 0x0001, - PF_DISABLEPANELS = 0x0002, - PF_EDITOR = 0x0004, - PF_VIEWER = 0x0008 -}; - - -struct PluginInfo -{ - int StructSize; - DWORD Flags; - char **DiskMenuStrings; - int *DiskMenuNumbers; - int DiskMenuStringsNumber; - char **PluginMenuStrings; - int PluginMenuStringsNumber; - char **PluginConfigStrings; - int PluginConfigStringsNumber; - char *CommandPrefix; -}; - -struct InfoPanelLine -{ - char Text[kInfoPanelLineSize]; - char Data[kInfoPanelLineSize]; - int Separator; -}; - - -struct PanelMode -{ - char *ColumnTypes; - char *ColumnWidths; - char **ColumnTitles; - int FullScreen; - int DetailedStatus; - int AlignExtensions; - int CaseConversion; - char *StatusColumnTypes; - char *StatusColumnWidths; - DWORD Reserved[2]; -}; - - -enum OPENPLUGININFO_FLAGS { - OPIF_USEFILTER = 0x0001, - OPIF_USESORTGROUPS = 0x0002, - OPIF_USEHIGHLIGHTING = 0x0004, - OPIF_ADDDOTS = 0x0008, - OPIF_RAWSELECTION = 0x0010, - OPIF_REALNAMES = 0x0020, - OPIF_SHOWNAMESONLY = 0x0040, - OPIF_SHOWRIGHTALIGNNAMES = 0x0080, - OPIF_SHOWPRESERVECASE = 0x0100, - OPIF_FINDFOLDERS = 0x0200, - OPIF_COMPAREFATTIME = 0x0400, - OPIF_EXTERNALGET = 0x0800, - OPIF_EXTERNALPUT = 0x1000, - OPIF_EXTERNALDELETE = 0x2000, - OPIF_EXTERNALMKDIR = 0x4000, - OPIF_USEATTRHIGHLIGHTING = 0x8000 -}; - - -enum OPENPLUGININFO_SORTMODES { - SM_DEFAULT,SM_UNSORTED,SM_NAME,SM_EXT,SM_MTIME,SM_CTIME, - SM_ATIME,SM_SIZE,SM_DESCR,SM_OWNER,SM_COMPRESSEDSIZE,SM_NUMLINKS -}; - - -struct KeyBarTitles -{ - char *Titles[12]; - char *CtrlTitles[12]; - char *AltTitles[12]; - char *ShiftTitles[12]; -}; - - -struct OpenPluginInfo -{ - int StructSize; - DWORD Flags; - const char *HostFile; - const char *CurDir; - const char *Format; - const char *PanelTitle; - const struct InfoPanelLine *InfoLines; - int InfoLinesNumber; - const char * const *DescrFiles; - int DescrFilesNumber; - const struct PanelMode *PanelModesArray; - int PanelModesNumber; - int StartPanelMode; - int StartSortMode; - int StartSortOrder; - const struct KeyBarTitles *KeyBar; - const char *ShortcutData; - // long Reserverd; -}; - -enum { - OPEN_DISKMENU, - OPEN_PLUGINSMENU, - OPEN_FINDLIST, - OPEN_SHORTCUT, - OPEN_COMMANDLINE, - OPEN_EDITOR, - OPEN_VIEWER -}; - -enum {PKF_CONTROL=1,PKF_ALT=2,PKF_SHIFT=4}; - -enum FAR_EVENTS { - FE_CHANGEVIEWMODE, - FE_REDRAW, - FE_IDLE, - FE_CLOSE, - FE_BREAK, - FE_COMMAND -}; - -enum OPERATION_MODES { - OPM_SILENT=1, - OPM_FIND=2, - OPM_VIEW=4, - OPM_EDIT=8, - OPM_TOPLEVEL=16, - OPM_DESCR=32 -}; - -#ifndef _WIN64 -#if defined(__BORLANDC__) && (__BORLANDC <= 0x520) - #pragma option -a. -#elif defined(__GNUC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100)) - #pragma pack() -#else - #pragma pack(pop) -#endif -#endif - -/* -EXTERN_C_BEGIN - - void WINAPI _export ClosePluginW(HANDLE hPlugin); - int WINAPI _export CompareW(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned Mode); - int WINAPI _export ConfigureW(int ItemNumber); - int WINAPI _export DeleteFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); - void WINAPI _export ExitFARW(void); - void WINAPI _export FreeFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); - void WINAPI _export FreeVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); - int WINAPI _export GetFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t **DestPath,int OpMode); - int WINAPI _export GetFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode); - int WINAPI _export GetMinFarVersionW(void); - void WINAPI _export GetOpenPluginInfoW(HANDLE hPlugin,struct OpenPluginInfo *Info); - void WINAPI _export GetPluginInfoW(struct PluginInfo *Info); - int WINAPI _export GetVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const wchar_t *Path); - int WINAPI _export MakeDirectoryW(HANDLE hPlugin,const wchar_t **Name,int OpMode); - HANDLE WINAPI _export OpenFilePluginW(const wchar_t *Name,const unsigned char *Data,int DataSize,int OpMode); - HANDLE WINAPI _export OpenPluginW(int OpenFrom,INT_PTR Item); - int WINAPI _export ProcessDialogEventW(int Event,void *Param); - int WINAPI _export ProcessEditorEventW(int Event,void *Param); - int WINAPI _export ProcessEditorInputW(const INPUT_RECORD *Rec); - int WINAPI _export ProcessEventW(HANDLE hPlugin,int Event,void *Param); - int WINAPI _export ProcessHostFileW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); - int WINAPI _export ProcessKeyW(HANDLE hPlugin,int Key,unsigned ControlState); - int WINAPI _export ProcessSynchroEventW(int Event,void *Param); - int WINAPI _export ProcessViewerEventW(int Event,void *Param); - int WINAPI _export PutFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t *SrcPath,int OpMode); - int WINAPI _export SetDirectoryW(HANDLE hPlugin,const wchar_t *Dir,int OpMode); - int WINAPI _export SetFindListW(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber); - void WINAPI _export SetStartupInfoW(const struct PluginStartupInfo *Info); - -EXTERN_C_END -*/ -EXTERN_C_BEGIN - - void WINAPI _export ClosePlugin(HANDLE hPlugin); - int WINAPI _export Compare(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned Mode); - int WINAPI _export Configure(int ItemNumber); - int WINAPI _export DeleteFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); - void WINAPI _export ExitFAR(void); - void WINAPI _export FreeFindData(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); - void WINAPI _export FreeVirtualFindData(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); - int WINAPI _export GetFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,char *DestPath,int OpMode); - int WINAPI _export GetFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode); - int WINAPI _export GetMinFarVersion(void); - void WINAPI _export GetOpenPluginInfo(HANDLE hPlugin,struct OpenPluginInfo *Info); - void WINAPI _export GetPluginInfo(struct PluginInfo *Info); - int WINAPI _export GetVirtualFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const char *Path); - int WINAPI _export MakeDirectory(HANDLE hPlugin,char *Name,int OpMode); - HANDLE WINAPI _export OpenFilePlugin(char *Name,const BYTE *Data,int DataSize); - HANDLE WINAPI _export OpenPlugin(int OpenFrom,INT_PTR Item); - int WINAPI _export ProcessDialogEvent(int Event,void *Param); - int WINAPI _export ProcessEditorEvent(int Event,void *Param); - int WINAPI _export ProcessEditorInput(const INPUT_RECORD *Rec); - int WINAPI _export ProcessEvent(HANDLE hPlugin,int Event,void *Param); - int WINAPI _export ProcessHostFile(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); - int WINAPI _export ProcessKey(HANDLE hPlugin,int Key,unsigned ControlState); - int WINAPI _export ProcessViewerEvent(int Event,void *Param); - int WINAPI _export PutFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,int OpMode); - int WINAPI _export SetDirectory(HANDLE hPlugin,const char *Dir,int OpMode); - int WINAPI _export SetFindList(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber); - void WINAPI _export SetStartupInfo(const struct PluginStartupInfo *Info); - -EXTERN_C_END - -#endif +// FarPlugin.h + +// #include "plugin.hpp" + +const int kInfoPanelLineSize = 80; + +// #define __FAR_PLUGIN_H + +#ifdef UNDER_CE +typedef struct { + union { + WCHAR UnicodeChar; + CHAR AsciiChar; + } Char; + WORD Attributes; +} CHAR_INFO, *PCHAR_INFO; +#endif + +#ifndef ZIP7_INC_FAR_PLUGIN_H +#define ZIP7_INC_FAR_PLUGIN_H + +#ifndef _WIN64 +#if defined(__BORLANDC__) && (__BORLANDC <= 0x520) + #pragma option -a1 +#elif defined(__GNUC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100)) + #pragma pack(1) +#else + #pragma pack(push,1) +#endif +#endif + + // #if _MSC_VER + #define _export + // #endif + +#define NM 260 + +struct FarFindData +{ + DWORD dwFileAttributes; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; + DWORD nFileSizeHigh; + DWORD nFileSizeLow; + DWORD dwReserved0; + DWORD dwReserved1; + char cFileName[ MAX_PATH ]; + char cAlternateFileName[ 14 ]; +}; + +struct PluginPanelItem +{ + FarFindData FindData; + DWORD PackSizeHigh; + DWORD PackSize; + DWORD Flags; + DWORD NumberOfLinks; + char *Description; + char *Owner; + char **CustomColumnData; + int CustomColumnNumber; + DWORD_PTR UserData; + DWORD CRC32; + DWORD_PTR Reserved[2]; +}; + +#define PPIF_PROCESSDESCR 0x80000000 +#define PPIF_SELECTED 0x40000000 +#define PPIF_USERDATA 0x20000000 + +enum { + FMENU_SHOWAMPERSAND=1, + FMENU_WRAPMODE=2, + FMENU_AUTOHIGHLIGHT=4, + FMENU_REVERSEAUTOHIGHLIGHT=8 +}; + + +typedef int (WINAPI *FARAPIMENU)( + INT_PTR PluginNumber, + int X, + int Y, + int MaxHeight, + unsigned Flags, + char *Title, + char *Bottom, + char *HelpTopic, + int *BreakKeys, + int *BreakCode, + struct FarMenuItem *Item, + int ItemsNumber +); + +typedef int (WINAPI *FARAPIDIALOG)( + INT_PTR PluginNumber, + int X1, + int Y1, + int X2, + int Y2, + char *HelpTopic, + struct FarDialogItem *Item, + int ItemsNumber +); + +enum { + FMSG_WARNING = 0x00000001, + FMSG_ERRORTYPE = 0x00000002, + FMSG_KEEPBACKGROUND = 0x00000004, + FMSG_DOWN = 0x00000008, + FMSG_LEFTALIGN = 0x00000010, + + FMSG_ALLINONE = 0x00000020, + + FMSG_MB_OK = 0x00010000, + FMSG_MB_OKCANCEL = 0x00020000, + FMSG_MB_ABORTRETRYIGNORE = 0x00030000, + FMSG_MB_YESNO = 0x00040000, + FMSG_MB_YESNOCANCEL = 0x00050000, + FMSG_MB_RETRYCANCEL = 0x00060000 +}; + +typedef int (WINAPI *FARAPIMESSAGE)( + INT_PTR PluginNumber, + unsigned Flags, + const char *HelpTopic, + const char * const *Items, + int ItemsNumber, + int ButtonsNumber +); + +typedef char* (WINAPI *FARAPIGETMSG)( + INT_PTR PluginNumber, + int MsgId +); + + +enum DialogItemTypes { + DI_TEXT, + DI_VTEXT, + DI_SINGLEBOX, + DI_DOUBLEBOX, + DI_EDIT, + DI_PSWEDIT, + DI_FIXEDIT, + DI_BUTTON, + DI_CHECKBOX, + DI_RADIOBUTTON +}; + +enum FarDialogItemFlags { + DIF_COLORMASK = 0xff, + DIF_SETCOLOR = 0x100, + DIF_BOXCOLOR = 0x200, + DIF_GROUP = 0x400, + DIF_LEFTTEXT = 0x800, + DIF_MOVESELECT = 0x1000, + DIF_SHOWAMPERSAND = 0x2000, + DIF_CENTERGROUP = 0x4000, + DIF_NOBRACKETS = 0x8000, + DIF_SEPARATOR = 0x10000, + DIF_EDITOR = 0x20000, + DIF_HISTORY = 0x40000 +}; + +struct FarDialogItem +{ + int Type; + int X1,Y1,X2,Y2; + int Focus; + union + { + int Selected; + const char *History; + const char *Mask; + struct FarList *ListItems; + int ListPos; + CHAR_INFO *VBuf; + }; + unsigned Flags; + int DefaultButton; + char Data[512]; +}; + + +struct FarMenuItem +{ + char Text[128]; + int Selected; + int Checked; + int Separator; +}; + + +enum {FCTL_CLOSEPLUGIN,FCTL_GETPANELINFO,FCTL_GETANOTHERPANELINFO, + FCTL_UPDATEPANEL,FCTL_UPDATEANOTHERPANEL, + FCTL_REDRAWPANEL,FCTL_REDRAWANOTHERPANEL, + FCTL_SETANOTHERPANELDIR,FCTL_GETCMDLINE,FCTL_SETCMDLINE, + FCTL_SETSELECTION,FCTL_SETANOTHERSELECTION, + FCTL_SETVIEWMODE,FCTL_SETANOTHERVIEWMODE,FCTL_INSERTCMDLINE, + FCTL_SETUSERSCREEN,FCTL_SETPANELDIR,FCTL_SETCMDLINEPOS, + FCTL_GETCMDLINEPOS +}; + +enum {PTYPE_FILEPANEL,PTYPE_TREEPANEL,PTYPE_QVIEWPANEL,PTYPE_INFOPANEL}; + +struct PanelInfo +{ + int PanelType; + int Plugin; + RECT PanelRect; + struct PluginPanelItem *PanelItems; + int ItemsNumber; + struct PluginPanelItem *SelectedItems; + int SelectedItemsNumber; + int CurrentItem; + int TopPanelItem; + int Visible; + int Focus; + int ViewMode; + char ColumnTypes[80]; + char ColumnWidths[80]; + char CurDir[NM]; + int ShortNames; + int SortMode; + DWORD Flags; + DWORD Reserved; +}; + + +struct PanelRedrawInfo +{ + int CurrentItem; + int TopPanelItem; +}; + + +typedef int (WINAPI *FARAPICONTROL)( + HANDLE hPlugin, + int Command, + void *Param +); + +typedef HANDLE (WINAPI *FARAPISAVESCREEN)(int X1,int Y1,int X2,int Y2); + +typedef void (WINAPI *FARAPIRESTORESCREEN)(HANDLE hScreen); + +typedef int (WINAPI *FARAPIGETDIRLIST)( + char *Dir, + struct PluginPanelItem **pPanelItem, + int *pItemsNumber +); + +typedef int (WINAPI *FARAPIGETPLUGINDIRLIST)( + INT_PTR PluginNumber, + HANDLE hPlugin, + char *Dir, + struct PluginPanelItem **pPanelItem, + int *pItemsNumber +); + +typedef void (WINAPI *FARAPIFREEDIRLIST)(struct PluginPanelItem *PanelItem); + +enum VIEWER_FLAGS { + VF_NONMODAL=1,VF_DELETEONCLOSE=2 +}; + +typedef int (WINAPI *FARAPIVIEWER)( + char *FileName, + char *Title, + int X1, + int Y1, + int X2, + int Y2, + DWORD Flags +); + +typedef int (WINAPI *FARAPIEDITOR)( + char *FileName, + char *Title, + int X1, + int Y1, + int X2, + int Y2, + DWORD Flags, + int StartLine, + int StartChar +); + +typedef int (WINAPI *FARAPICMPNAME)( + char *Pattern, + char *String, + int SkipPath +); + + +#define FCT_DETECT 0x40000000 + +struct CharTableSet +{ + char DecodeTable[256]; + char EncodeTable[256]; + char UpperTable[256]; + char LowerTable[256]; + char TableName[128]; +}; + +typedef int (WINAPI *FARAPICHARTABLE)( + int Command, + char *Buffer, + int BufferSize +); + +typedef void (WINAPI *FARAPITEXT)( + int X, + int Y, + int Color, + char *Str +); + + +typedef int (WINAPI *FARAPIEDITORCONTROL)( + int Command, + void *Param +); + +struct PluginStartupInfo +{ + int StructSize; + char ModuleName[NM]; + INT_PTR ModuleNumber; + char *RootKey; + FARAPIMENU Menu; + FARAPIDIALOG Dialog; + FARAPIMESSAGE Message; + FARAPIGETMSG GetMsg; + FARAPICONTROL Control; + FARAPISAVESCREEN SaveScreen; + FARAPIRESTORESCREEN RestoreScreen; + FARAPIGETDIRLIST GetDirList; + FARAPIGETPLUGINDIRLIST GetPluginDirList; + FARAPIFREEDIRLIST FreeDirList; + FARAPIVIEWER Viewer; + FARAPIEDITOR Editor; + FARAPICMPNAME CmpName; + FARAPICHARTABLE CharTable; + FARAPITEXT Text; + FARAPIEDITORCONTROL EditorControl; +}; + + +enum PLUGIN_FLAGS { + PF_PRELOAD = 0x0001, + PF_DISABLEPANELS = 0x0002, + PF_EDITOR = 0x0004, + PF_VIEWER = 0x0008 +}; + + +struct PluginInfo +{ + int StructSize; + DWORD Flags; + char **DiskMenuStrings; + int *DiskMenuNumbers; + int DiskMenuStringsNumber; + char **PluginMenuStrings; + int PluginMenuStringsNumber; + char **PluginConfigStrings; + int PluginConfigStringsNumber; + char *CommandPrefix; +}; + +struct InfoPanelLine +{ + char Text[kInfoPanelLineSize]; + char Data[kInfoPanelLineSize]; + int Separator; +}; + + +struct PanelMode +{ + char *ColumnTypes; + char *ColumnWidths; + char **ColumnTitles; + int FullScreen; + int DetailedStatus; + int AlignExtensions; + int CaseConversion; + char *StatusColumnTypes; + char *StatusColumnWidths; + DWORD Reserved[2]; +}; + + +enum OPENPLUGININFO_FLAGS { + OPIF_USEFILTER = 0x0001, + OPIF_USESORTGROUPS = 0x0002, + OPIF_USEHIGHLIGHTING = 0x0004, + OPIF_ADDDOTS = 0x0008, + OPIF_RAWSELECTION = 0x0010, + OPIF_REALNAMES = 0x0020, + OPIF_SHOWNAMESONLY = 0x0040, + OPIF_SHOWRIGHTALIGNNAMES = 0x0080, + OPIF_SHOWPRESERVECASE = 0x0100, + OPIF_FINDFOLDERS = 0x0200, + OPIF_COMPAREFATTIME = 0x0400, + OPIF_EXTERNALGET = 0x0800, + OPIF_EXTERNALPUT = 0x1000, + OPIF_EXTERNALDELETE = 0x2000, + OPIF_EXTERNALMKDIR = 0x4000, + OPIF_USEATTRHIGHLIGHTING = 0x8000 +}; + + +enum OPENPLUGININFO_SORTMODES { + SM_DEFAULT,SM_UNSORTED,SM_NAME,SM_EXT,SM_MTIME,SM_CTIME, + SM_ATIME,SM_SIZE,SM_DESCR,SM_OWNER,SM_COMPRESSEDSIZE,SM_NUMLINKS +}; + + +struct KeyBarTitles +{ + char *Titles[12]; + char *CtrlTitles[12]; + char *AltTitles[12]; + char *ShiftTitles[12]; +}; + + +struct OpenPluginInfo +{ + int StructSize; + DWORD Flags; + const char *HostFile; + const char *CurDir; + const char *Format; + const char *PanelTitle; + const struct InfoPanelLine *InfoLines; + int InfoLinesNumber; + const char * const *DescrFiles; + int DescrFilesNumber; + const struct PanelMode *PanelModesArray; + int PanelModesNumber; + int StartPanelMode; + int StartSortMode; + int StartSortOrder; + const struct KeyBarTitles *KeyBar; + const char *ShortcutData; + // long Reserverd; +}; + +enum { + OPEN_DISKMENU, + OPEN_PLUGINSMENU, + OPEN_FINDLIST, + OPEN_SHORTCUT, + OPEN_COMMANDLINE, + OPEN_EDITOR, + OPEN_VIEWER +}; + +enum {PKF_CONTROL=1,PKF_ALT=2,PKF_SHIFT=4}; + +enum FAR_EVENTS { + FE_CHANGEVIEWMODE, + FE_REDRAW, + FE_IDLE, + FE_CLOSE, + FE_BREAK, + FE_COMMAND +}; + +enum OPERATION_MODES { + OPM_SILENT=1, + OPM_FIND=2, + OPM_VIEW=4, + OPM_EDIT=8, + OPM_TOPLEVEL=16, + OPM_DESCR=32 +}; + +#ifndef _WIN64 +#if defined(__BORLANDC__) && (__BORLANDC <= 0x520) + #pragma option -a. +#elif defined(__GNUC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100)) + #pragma pack() +#else + #pragma pack(pop) +#endif +#endif + +/* +EXTERN_C_BEGIN + + void WINAPI _export ClosePluginW(HANDLE hPlugin); + int WINAPI _export CompareW(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned Mode); + int WINAPI _export ConfigureW(int ItemNumber); + int WINAPI _export DeleteFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); + void WINAPI _export ExitFARW(void); + void WINAPI _export FreeFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); + void WINAPI _export FreeVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); + int WINAPI _export GetFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t **DestPath,int OpMode); + int WINAPI _export GetFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode); + int WINAPI _export GetMinFarVersionW(void); + void WINAPI _export GetOpenPluginInfoW(HANDLE hPlugin,struct OpenPluginInfo *Info); + void WINAPI _export GetPluginInfoW(struct PluginInfo *Info); + int WINAPI _export GetVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const wchar_t *Path); + int WINAPI _export MakeDirectoryW(HANDLE hPlugin,const wchar_t **Name,int OpMode); + HANDLE WINAPI _export OpenFilePluginW(const wchar_t *Name,const unsigned char *Data,int DataSize,int OpMode); + HANDLE WINAPI _export OpenPluginW(int OpenFrom,INT_PTR Item); + int WINAPI _export ProcessDialogEventW(int Event,void *Param); + int WINAPI _export ProcessEditorEventW(int Event,void *Param); + int WINAPI _export ProcessEditorInputW(const INPUT_RECORD *Rec); + int WINAPI _export ProcessEventW(HANDLE hPlugin,int Event,void *Param); + int WINAPI _export ProcessHostFileW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); + int WINAPI _export ProcessKeyW(HANDLE hPlugin,int Key,unsigned ControlState); + int WINAPI _export ProcessSynchroEventW(int Event,void *Param); + int WINAPI _export ProcessViewerEventW(int Event,void *Param); + int WINAPI _export PutFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t *SrcPath,int OpMode); + int WINAPI _export SetDirectoryW(HANDLE hPlugin,const wchar_t *Dir,int OpMode); + int WINAPI _export SetFindListW(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber); + void WINAPI _export SetStartupInfoW(const struct PluginStartupInfo *Info); + +EXTERN_C_END +*/ +EXTERN_C_BEGIN + + void WINAPI _export ClosePlugin(HANDLE hPlugin); + int WINAPI _export Compare(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned Mode); + int WINAPI _export Configure(int ItemNumber); + int WINAPI _export DeleteFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); + void WINAPI _export ExitFAR(void); + void WINAPI _export FreeFindData(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); + void WINAPI _export FreeVirtualFindData(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber); + int WINAPI _export GetFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,char *DestPath,int OpMode); + int WINAPI _export GetFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode); + int WINAPI _export GetMinFarVersion(void); + void WINAPI _export GetOpenPluginInfo(HANDLE hPlugin,struct OpenPluginInfo *Info); + void WINAPI _export GetPluginInfo(struct PluginInfo *Info); + int WINAPI _export GetVirtualFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const char *Path); + int WINAPI _export MakeDirectory(HANDLE hPlugin,char *Name,int OpMode); + HANDLE WINAPI _export OpenFilePlugin(char *Name,const BYTE *Data,int DataSize); + HANDLE WINAPI _export OpenPlugin(int OpenFrom,INT_PTR Item); + int WINAPI _export ProcessDialogEvent(int Event,void *Param); + int WINAPI _export ProcessEditorEvent(int Event,void *Param); + int WINAPI _export ProcessEditorInput(const INPUT_RECORD *Rec); + int WINAPI _export ProcessEvent(HANDLE hPlugin,int Event,void *Param); + int WINAPI _export ProcessHostFile(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode); + int WINAPI _export ProcessKey(HANDLE hPlugin,int Key,unsigned ControlState); + int WINAPI _export ProcessViewerEvent(int Event,void *Param); + int WINAPI _export PutFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,int OpMode); + int WINAPI _export SetDirectory(HANDLE hPlugin,const char *Dir,int OpMode); + int WINAPI _export SetFindList(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber); + void WINAPI _export SetStartupInfo(const struct PluginStartupInfo *Info); + +EXTERN_C_END + +#endif diff --git a/CPP/7zip/UI/Far/FarUtils.cpp b/CPP/7zip/UI/Far/FarUtils.cpp index bec92e02d..3c33d8eb8 100644 --- a/CPP/7zip/UI/Far/FarUtils.cpp +++ b/CPP/7zip/UI/Far/FarUtils.cpp @@ -1,524 +1,524 @@ -// FarUtils.cpp - -#include "StdAfx.h" - -// #include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#ifndef UNDER_CE -#include "../../../Windows/Console.h" -#endif -#include "../../../Windows/Defs.h" -#include "../../../Windows/ErrorMsg.h" - -#include "FarUtils.h" - -using namespace NWindows; - -namespace NFar { - -CStartupInfo g_StartupInfo; - -const char kRegistryKeyDelimiter = '\\'; - -void CStartupInfo::Init(const PluginStartupInfo &pluginStartupInfo, - const char *pluginNameForRegistry) -{ - m_Data = pluginStartupInfo; - m_RegistryPath = pluginStartupInfo.RootKey; - m_RegistryPath += kRegistryKeyDelimiter; - m_RegistryPath += pluginNameForRegistry; -} - -const char *CStartupInfo::GetMsgString(int messageId) -{ - return (const char*)m_Data.GetMsg(m_Data.ModuleNumber, messageId); -} - -int CStartupInfo::ShowMessage(UInt32 flags, - const char *helpTopic, const char **items, unsigned numItems, int numButtons) -{ - return m_Data.Message(m_Data.ModuleNumber, flags, helpTopic, - items, (int)numItems, numButtons); -} - -namespace NMessageID -{ - enum - { - kOk, - kCancel, - kWarning, - kError - }; -} - -int CStartupInfo::ShowWarningWithOk(const char **items, unsigned numItems) -{ - return ShowMessage(FMSG_WARNING | FMSG_MB_OK, NULL, items, numItems, 0); -} - -extern const char *g_PluginName_for_Error; - -void CStartupInfo::SetErrorTitle(AString &s) -{ - if (g_PluginName_for_Error) - { - s += g_PluginName_for_Error; - s += ": "; - } - s += GetMsgString(NMessageID::kError); -} - -/* -int CStartupInfo::ShowErrorMessage(const char *message) -{ - AString s; - SetErrorTitle(s); - const char *items[]= { s, message }; - return ShowWarningWithOk(items, Z7_ARRAY_SIZE(items)); -} -*/ - -int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2) -{ - AString s; - SetErrorTitle(s); - const char *items[]= { s, m1, m2 }; - return ShowWarningWithOk(items, Z7_ARRAY_SIZE(items)); -} - -static void SplitString(const AString &src, AStringVector &destStrings) -{ - destStrings.Clear(); - AString s; - unsigned len = src.Len(); - if (len == 0) - return; - for (unsigned i = 0; i < len; i++) - { - char c = src[i]; - if (c == '\n') - { - if (!s.IsEmpty()) - { - destStrings.Add(s); - s.Empty(); - } - } - else - s += c; - } - if (!s.IsEmpty()) - destStrings.Add(s); -} - -int CStartupInfo::ShowErrorMessage(const char *message) -{ - AStringVector strings; - SplitString((AString)message, strings); - const unsigned kNumStringsMax = 20; - const char *items[kNumStringsMax + 1]; - unsigned pos = 0; - items[pos++] = GetMsgString(NMessageID::kError); - for (unsigned i = 0; i < strings.Size() && pos < kNumStringsMax; i++) - items[pos++] = strings[i]; - items[pos++] = GetMsgString(NMessageID::kOk); - - return ShowMessage(FMSG_WARNING, NULL, items, pos, 1); -} - -/* -int CStartupInfo::ShowMessageLines(const char *message) -{ - AString s = GetMsgString(NMessageID::kError); - s.Add_LF(); - s += message; - return ShowMessage(FMSG_WARNING | FMSG_MB_OK | FMSG_ALLINONE, NULL, - (const char **)(const char *)s, 1, 0); -} -*/ - -int CStartupInfo::ShowMessage(int messageId) -{ - return ShowErrorMessage(GetMsgString(messageId)); -} - -int CStartupInfo::ShowDialog(int X1, int Y1, int X2, int Y2, - const char *helpTopic, struct FarDialogItem *items, unsigned numItems) -{ - return m_Data.Dialog(m_Data.ModuleNumber, X1, Y1, X2, Y2, const_cast(helpTopic), - items, (int)numItems); -} - -int CStartupInfo::ShowDialog(int sizeX, int sizeY, - const char *helpTopic, struct FarDialogItem *items, unsigned numItems) -{ - return ShowDialog(-1, -1, sizeX, sizeY, helpTopic, items, numItems); -} - -inline static BOOL GetBOOLValue(bool v) { return (v? TRUE: FALSE); } - -void CStartupInfo::InitDialogItems(const CInitDialogItem *srcItems, - FarDialogItem *destItems, unsigned numItems) -{ - for (unsigned i = 0; i < numItems; i++) - { - const CInitDialogItem &srcItem = srcItems[i]; - FarDialogItem &destItem = destItems[i]; - - destItem.Type = srcItem.Type; - destItem.X1 = srcItem.X1; - destItem.Y1 = srcItem.Y1; - destItem.X2 = srcItem.X2; - destItem.Y2 = srcItem.Y2; - destItem.Focus = GetBOOLValue(srcItem.Focus); - if (srcItem.HistoryName != NULL) - destItem.History = srcItem.HistoryName; - else - destItem.Selected = GetBOOLValue(srcItem.Selected); - destItem.Flags = srcItem.Flags; - destItem.DefaultButton = GetBOOLValue(srcItem.DefaultButton); - - if (srcItem.DataMessageId < 0) - MyStringCopy(destItem.Data, srcItem.DataString); - else - MyStringCopy(destItem.Data, GetMsgString(srcItem.DataMessageId)); - - /* - if ((unsigned)Init[i].Data < 0xFFF) - MyStringCopy(destItem.Data, GetMsg((unsigned)srcItem.Data)); - else - MyStringCopy(destItem.Data,srcItem.Data); - */ - } -} - -// -------------------------------------------- - -HANDLE CStartupInfo::SaveScreen(int X1, int Y1, int X2, int Y2) -{ - return m_Data.SaveScreen(X1, Y1, X2, Y2); -} - -HANDLE CStartupInfo::SaveScreen() -{ - return SaveScreen(0, 0, -1, -1); -} - -void CStartupInfo::RestoreScreen(HANDLE handle) -{ - m_Data.RestoreScreen(handle); -} - -CSysString CStartupInfo::GetFullKeyName(const char *keyName) const -{ - AString s (m_RegistryPath); - if (keyName && *keyName) - { - s += kRegistryKeyDelimiter; - s += keyName; - } - return (CSysString)s; -} - - -LONG CStartupInfo::CreateRegKey(HKEY parentKey, - const char *keyName, NRegistry::CKey &destKey) const -{ - return destKey.Create(parentKey, GetFullKeyName(keyName)); -} - -LONG CStartupInfo::OpenRegKey(HKEY parentKey, - const char *keyName, NRegistry::CKey &destKey) const -{ - return destKey.Open(parentKey, GetFullKeyName(keyName)); -} - -void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, LPCTSTR value) const -{ - NRegistry::CKey regKey; - CreateRegKey(parentKey, keyName, regKey); - regKey.SetValue(valueName, value); -} - -void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, UInt32 value) const -{ - NRegistry::CKey regKey; - CreateRegKey(parentKey, keyName, regKey); - regKey.SetValue(valueName, value); -} - -void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, bool value) const -{ - NRegistry::CKey regKey; - CreateRegKey(parentKey, keyName, regKey); - regKey.SetValue(valueName, value); -} - -CSysString CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, const CSysString &valueDefault) const -{ - NRegistry::CKey regKey; - if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS) - return valueDefault; - - CSysString value; - if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS) - return valueDefault; - - return value; -} - -UInt32 CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, UInt32 valueDefault) const -{ - NRegistry::CKey regKey; - if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS) - return valueDefault; - - UInt32 value; - if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS) - return valueDefault; - - return value; -} - -bool CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, bool valueDefault) const -{ - NRegistry::CKey regKey; - if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS) - return valueDefault; - - bool value; - if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS) - return valueDefault; - - return value; -} - -bool CStartupInfo::Control(HANDLE pluginHandle, int command, void *param) -{ - return BOOLToBool(m_Data.Control(pluginHandle, command, param)); -} - -bool CStartupInfo::ControlRequestActivePanel(int command, void *param) -{ - return Control(INVALID_HANDLE_VALUE, command, param); -} - -bool CStartupInfo::ControlGetActivePanelInfo(PanelInfo &panelInfo) -{ - return ControlRequestActivePanel(FCTL_GETPANELINFO, &panelInfo); -} - -bool CStartupInfo::ControlSetSelection(const PanelInfo &panelInfo) -{ - return ControlRequestActivePanel(FCTL_SETSELECTION, (void *)&panelInfo); -} - -bool CStartupInfo::ControlGetActivePanelCurrentItemInfo( - PluginPanelItem &pluginPanelItem) -{ - PanelInfo panelInfo; - if (!ControlGetActivePanelInfo(panelInfo)) - return false; - if (panelInfo.ItemsNumber <= 0) - throw "There are no items"; - pluginPanelItem = panelInfo.PanelItems[panelInfo.CurrentItem]; - return true; -} - -bool CStartupInfo::ControlGetActivePanelSelectedOrCurrentItems( - CObjectVector &pluginPanelItems) -{ - pluginPanelItems.Clear(); - PanelInfo panelInfo; - if (!ControlGetActivePanelInfo(panelInfo)) - return false; - if (panelInfo.ItemsNumber <= 0) - throw "There are no items"; - if (panelInfo.SelectedItemsNumber == 0) - pluginPanelItems.Add(panelInfo.PanelItems[panelInfo.CurrentItem]); - else - for (int i = 0; i < panelInfo.SelectedItemsNumber; i++) - pluginPanelItems.Add(panelInfo.SelectedItems[i]); - return true; -} - -bool CStartupInfo::ControlClearPanelSelection() -{ - PanelInfo panelInfo; - if (!ControlGetActivePanelInfo(panelInfo)) - return false; - for (int i = 0; i < panelInfo.ItemsNumber; i++) - panelInfo.PanelItems[i].Flags &= ~(DWORD)PPIF_SELECTED; - return ControlSetSelection(panelInfo); -} - -//////////////////////////////////////////////// -// menu function - -int CStartupInfo::Menu( - int x, - int y, - int maxHeight, - unsigned flags, - const char *title, - const char *aBottom, - const char *helpTopic, - int *breakKeys, - int *breakCode, - struct FarMenuItem *items, - unsigned numItems) -{ - return m_Data.Menu(m_Data.ModuleNumber, x, y, maxHeight, flags, - const_cast(title), - const_cast(aBottom), - const_cast(helpTopic), - breakKeys, breakCode, items, (int)numItems); -} - -int CStartupInfo::Menu( - unsigned flags, - const char *title, - const char *helpTopic, - struct FarMenuItem *items, - unsigned numItems) -{ - return Menu(-1, -1, 0, flags, title, NULL, helpTopic, NULL, - NULL, items, numItems); -} - -int CStartupInfo::Menu( - unsigned flags, - const char *title, - const char *helpTopic, - const AStringVector &items, - int selectedItem) -{ - CRecordVector farMenuItems; - FOR_VECTOR (i, items) - { - FarMenuItem item; - item.Checked = 0; - item.Separator = 0; - item.Selected = ((int)i == selectedItem); - const AString reducedString (items[i].Left(Z7_ARRAY_SIZE(item.Text) - 1)); - MyStringCopy(item.Text, reducedString); - farMenuItems.Add(item); - } - return Menu(flags, title, helpTopic, farMenuItems.NonConstData(), farMenuItems.Size()); -} - - -////////////////////////////////// -// CScreenRestorer - -CScreenRestorer::~CScreenRestorer() -{ - Restore(); -} -void CScreenRestorer::Save() -{ - if (m_Saved) - return; - m_HANDLE = g_StartupInfo.SaveScreen(); - m_Saved = true; -} - -void CScreenRestorer::Restore() -{ - if (m_Saved) - { - g_StartupInfo.RestoreScreen(m_HANDLE); - m_Saved = false; - } -} - -int PrintErrorMessage(const char *message, unsigned code) -{ - AString s (message); - s += " #"; - s.Add_UInt32((UInt32)code); - return g_StartupInfo.ShowErrorMessage(s); -} - -int PrintErrorMessage(const char *message, const char *text) -{ - return g_StartupInfo.ShowErrorMessage2(message, text); -} - - -void ReduceString(UString &s, unsigned size) -{ - if (s.Len() > size) - { - if (size > 5) - size -= 5; - s.Delete(size / 2, s.Len() - size); - s.Insert(size / 2, L" ... "); - } -} - -int PrintErrorMessage(const char *message, const wchar_t *name, unsigned maxLen) -{ - UString s = name; - ReduceString(s, maxLen); - return PrintErrorMessage(message, UnicodeStringToMultiByte(s, CP_OEMCP)); -} - -int ShowSysErrorMessage(DWORD errorCode) -{ - const UString message = NError::MyFormatMessage(errorCode); - return g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)); -} - -int ShowLastErrorMessage() -{ - return ShowSysErrorMessage(::GetLastError()); -} - -int ShowSysErrorMessage(DWORD errorCode, const wchar_t *name) -{ - const UString s = NError::MyFormatMessage(errorCode); - return g_StartupInfo.ShowErrorMessage2( - UnicodeStringToMultiByte(s, CP_OEMCP), - UnicodeStringToMultiByte(name, CP_OEMCP)); -} - - -bool WasEscPressed() -{ - #ifdef UNDER_CE - return false; - #else - NConsole::CIn inConsole; - HANDLE handle = ::GetStdHandle(STD_INPUT_HANDLE); - if (handle == INVALID_HANDLE_VALUE) - return true; - inConsole.Attach(handle); - for (;;) - { - DWORD numEvents; - if (!inConsole.GetNumberOfEvents(numEvents)) - return true; - if (numEvents == 0) - return false; - - INPUT_RECORD event; - if (!inConsole.ReadEvent(event, numEvents)) - return true; - if (event.EventType == KEY_EVENT && - event.Event.KeyEvent.bKeyDown && - event.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) - return true; - } - #endif -} - -} +// FarUtils.cpp + +#include "StdAfx.h" + +// #include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#ifndef UNDER_CE +#include "../../../Windows/Console.h" +#endif +#include "../../../Windows/Defs.h" +#include "../../../Windows/ErrorMsg.h" + +#include "FarUtils.h" + +using namespace NWindows; + +namespace NFar { + +CStartupInfo g_StartupInfo; + +const char kRegistryKeyDelimiter = '\\'; + +void CStartupInfo::Init(const PluginStartupInfo &pluginStartupInfo, + const char *pluginNameForRegistry) +{ + m_Data = pluginStartupInfo; + m_RegistryPath = pluginStartupInfo.RootKey; + m_RegistryPath += kRegistryKeyDelimiter; + m_RegistryPath += pluginNameForRegistry; +} + +const char *CStartupInfo::GetMsgString(int messageId) +{ + return (const char*)m_Data.GetMsg(m_Data.ModuleNumber, messageId); +} + +int CStartupInfo::ShowMessage(UInt32 flags, + const char *helpTopic, const char **items, unsigned numItems, int numButtons) +{ + return m_Data.Message(m_Data.ModuleNumber, flags, helpTopic, + items, (int)numItems, numButtons); +} + +namespace NMessageID +{ + enum + { + kOk, + kCancel, + kWarning, + kError + }; +} + +int CStartupInfo::ShowWarningWithOk(const char **items, unsigned numItems) +{ + return ShowMessage(FMSG_WARNING | FMSG_MB_OK, NULL, items, numItems, 0); +} + +extern const char *g_PluginName_for_Error; + +void CStartupInfo::SetErrorTitle(AString &s) +{ + if (g_PluginName_for_Error) + { + s += g_PluginName_for_Error; + s += ": "; + } + s += GetMsgString(NMessageID::kError); +} + +/* +int CStartupInfo::ShowErrorMessage(const char *message) +{ + AString s; + SetErrorTitle(s); + const char *items[]= { s, message }; + return ShowWarningWithOk(items, Z7_ARRAY_SIZE(items)); +} +*/ + +int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2) +{ + AString s; + SetErrorTitle(s); + const char *items[]= { s, m1, m2 }; + return ShowWarningWithOk(items, Z7_ARRAY_SIZE(items)); +} + +static void SplitString(const AString &src, AStringVector &destStrings) +{ + destStrings.Clear(); + AString s; + unsigned len = src.Len(); + if (len == 0) + return; + for (unsigned i = 0; i < len; i++) + { + char c = src[i]; + if (c == '\n') + { + if (!s.IsEmpty()) + { + destStrings.Add(s); + s.Empty(); + } + } + else + s += c; + } + if (!s.IsEmpty()) + destStrings.Add(s); +} + +int CStartupInfo::ShowErrorMessage(const char *message) +{ + AStringVector strings; + SplitString((AString)message, strings); + const unsigned kNumStringsMax = 20; + const char *items[kNumStringsMax + 1]; + unsigned pos = 0; + items[pos++] = GetMsgString(NMessageID::kError); + for (unsigned i = 0; i < strings.Size() && pos < kNumStringsMax; i++) + items[pos++] = strings[i]; + items[pos++] = GetMsgString(NMessageID::kOk); + + return ShowMessage(FMSG_WARNING, NULL, items, pos, 1); +} + +/* +int CStartupInfo::ShowMessageLines(const char *message) +{ + AString s = GetMsgString(NMessageID::kError); + s.Add_LF(); + s += message; + return ShowMessage(FMSG_WARNING | FMSG_MB_OK | FMSG_ALLINONE, NULL, + (const char **)(const char *)s, 1, 0); +} +*/ + +int CStartupInfo::ShowMessage(int messageId) +{ + return ShowErrorMessage(GetMsgString(messageId)); +} + +int CStartupInfo::ShowDialog(int X1, int Y1, int X2, int Y2, + const char *helpTopic, struct FarDialogItem *items, unsigned numItems) +{ + return m_Data.Dialog(m_Data.ModuleNumber, X1, Y1, X2, Y2, const_cast(helpTopic), + items, (int)numItems); +} + +int CStartupInfo::ShowDialog(int sizeX, int sizeY, + const char *helpTopic, struct FarDialogItem *items, unsigned numItems) +{ + return ShowDialog(-1, -1, sizeX, sizeY, helpTopic, items, numItems); +} + +inline static BOOL GetBOOLValue(bool v) { return (v? TRUE: FALSE); } + +void CStartupInfo::InitDialogItems(const CInitDialogItem *srcItems, + FarDialogItem *destItems, unsigned numItems) +{ + for (unsigned i = 0; i < numItems; i++) + { + const CInitDialogItem &srcItem = srcItems[i]; + FarDialogItem &destItem = destItems[i]; + + destItem.Type = srcItem.Type; + destItem.X1 = srcItem.X1; + destItem.Y1 = srcItem.Y1; + destItem.X2 = srcItem.X2; + destItem.Y2 = srcItem.Y2; + destItem.Focus = GetBOOLValue(srcItem.Focus); + if (srcItem.HistoryName != NULL) + destItem.History = srcItem.HistoryName; + else + destItem.Selected = GetBOOLValue(srcItem.Selected); + destItem.Flags = srcItem.Flags; + destItem.DefaultButton = GetBOOLValue(srcItem.DefaultButton); + + if (srcItem.DataMessageId < 0) + MyStringCopy(destItem.Data, srcItem.DataString); + else + MyStringCopy(destItem.Data, GetMsgString(srcItem.DataMessageId)); + + /* + if ((unsigned)Init[i].Data < 0xFFF) + MyStringCopy(destItem.Data, GetMsg((unsigned)srcItem.Data)); + else + MyStringCopy(destItem.Data,srcItem.Data); + */ + } +} + +// -------------------------------------------- + +HANDLE CStartupInfo::SaveScreen(int X1, int Y1, int X2, int Y2) +{ + return m_Data.SaveScreen(X1, Y1, X2, Y2); +} + +HANDLE CStartupInfo::SaveScreen() +{ + return SaveScreen(0, 0, -1, -1); +} + +void CStartupInfo::RestoreScreen(HANDLE handle) +{ + m_Data.RestoreScreen(handle); +} + +CSysString CStartupInfo::GetFullKeyName(const char *keyName) const +{ + AString s (m_RegistryPath); + if (keyName && *keyName) + { + s += kRegistryKeyDelimiter; + s += keyName; + } + return (CSysString)s; +} + + +LONG CStartupInfo::CreateRegKey(HKEY parentKey, + const char *keyName, NRegistry::CKey &destKey) const +{ + return destKey.Create(parentKey, GetFullKeyName(keyName)); +} + +LONG CStartupInfo::OpenRegKey(HKEY parentKey, + const char *keyName, NRegistry::CKey &destKey) const +{ + return destKey.Open(parentKey, GetFullKeyName(keyName)); +} + +void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, LPCTSTR value) const +{ + NRegistry::CKey regKey; + CreateRegKey(parentKey, keyName, regKey); + regKey.SetValue(valueName, value); +} + +void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, UInt32 value) const +{ + NRegistry::CKey regKey; + CreateRegKey(parentKey, keyName, regKey); + regKey.SetValue(valueName, value); +} + +void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, bool value) const +{ + NRegistry::CKey regKey; + CreateRegKey(parentKey, keyName, regKey); + regKey.SetValue(valueName, value); +} + +CSysString CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, const CSysString &valueDefault) const +{ + NRegistry::CKey regKey; + if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS) + return valueDefault; + + CSysString value; + if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS) + return valueDefault; + + return value; +} + +UInt32 CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, UInt32 valueDefault) const +{ + NRegistry::CKey regKey; + if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS) + return valueDefault; + + UInt32 value; + if (regKey.GetValue_UInt32_IfOk(valueName, value) != ERROR_SUCCESS) + return valueDefault; + + return value; +} + +bool CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, bool valueDefault) const +{ + NRegistry::CKey regKey; + if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS) + return valueDefault; + + bool value; + if (regKey.GetValue_bool_IfOk(valueName, value) != ERROR_SUCCESS) + return valueDefault; + + return value; +} + +bool CStartupInfo::Control(HANDLE pluginHandle, int command, void *param) +{ + return BOOLToBool(m_Data.Control(pluginHandle, command, param)); +} + +bool CStartupInfo::ControlRequestActivePanel(int command, void *param) +{ + return Control(INVALID_HANDLE_VALUE, command, param); +} + +bool CStartupInfo::ControlGetActivePanelInfo(PanelInfo &panelInfo) +{ + return ControlRequestActivePanel(FCTL_GETPANELINFO, &panelInfo); +} + +bool CStartupInfo::ControlSetSelection(const PanelInfo &panelInfo) +{ + return ControlRequestActivePanel(FCTL_SETSELECTION, (void *)&panelInfo); +} + +bool CStartupInfo::ControlGetActivePanelCurrentItemInfo( + PluginPanelItem &pluginPanelItem) +{ + PanelInfo panelInfo; + if (!ControlGetActivePanelInfo(panelInfo)) + return false; + if (panelInfo.ItemsNumber <= 0) + throw "There are no items"; + pluginPanelItem = panelInfo.PanelItems[panelInfo.CurrentItem]; + return true; +} + +bool CStartupInfo::ControlGetActivePanelSelectedOrCurrentItems( + CObjectVector &pluginPanelItems) +{ + pluginPanelItems.Clear(); + PanelInfo panelInfo; + if (!ControlGetActivePanelInfo(panelInfo)) + return false; + if (panelInfo.ItemsNumber <= 0) + throw "There are no items"; + if (panelInfo.SelectedItemsNumber == 0) + pluginPanelItems.Add(panelInfo.PanelItems[panelInfo.CurrentItem]); + else + for (int i = 0; i < panelInfo.SelectedItemsNumber; i++) + pluginPanelItems.Add(panelInfo.SelectedItems[i]); + return true; +} + +bool CStartupInfo::ControlClearPanelSelection() +{ + PanelInfo panelInfo; + if (!ControlGetActivePanelInfo(panelInfo)) + return false; + for (int i = 0; i < panelInfo.ItemsNumber; i++) + panelInfo.PanelItems[i].Flags &= ~(DWORD)PPIF_SELECTED; + return ControlSetSelection(panelInfo); +} + +//////////////////////////////////////////////// +// menu function + +int CStartupInfo::Menu( + int x, + int y, + int maxHeight, + unsigned flags, + const char *title, + const char *aBottom, + const char *helpTopic, + int *breakKeys, + int *breakCode, + struct FarMenuItem *items, + unsigned numItems) +{ + return m_Data.Menu(m_Data.ModuleNumber, x, y, maxHeight, flags, + const_cast(title), + const_cast(aBottom), + const_cast(helpTopic), + breakKeys, breakCode, items, (int)numItems); +} + +int CStartupInfo::Menu( + unsigned flags, + const char *title, + const char *helpTopic, + struct FarMenuItem *items, + unsigned numItems) +{ + return Menu(-1, -1, 0, flags, title, NULL, helpTopic, NULL, + NULL, items, numItems); +} + +int CStartupInfo::Menu( + unsigned flags, + const char *title, + const char *helpTopic, + const AStringVector &items, + int selectedItem) +{ + CRecordVector farMenuItems; + FOR_VECTOR (i, items) + { + FarMenuItem item; + item.Checked = 0; + item.Separator = 0; + item.Selected = ((int)i == selectedItem); + const AString reducedString (items[i].Left(Z7_ARRAY_SIZE(item.Text) - 1)); + MyStringCopy(item.Text, reducedString); + farMenuItems.Add(item); + } + return Menu(flags, title, helpTopic, farMenuItems.NonConstData(), farMenuItems.Size()); +} + + +////////////////////////////////// +// CScreenRestorer + +CScreenRestorer::~CScreenRestorer() +{ + Restore(); +} +void CScreenRestorer::Save() +{ + if (m_Saved) + return; + m_HANDLE = g_StartupInfo.SaveScreen(); + m_Saved = true; +} + +void CScreenRestorer::Restore() +{ + if (m_Saved) + { + g_StartupInfo.RestoreScreen(m_HANDLE); + m_Saved = false; + } +} + +int PrintErrorMessage(const char *message, unsigned code) +{ + AString s (message); + s += " #"; + s.Add_UInt32((UInt32)code); + return g_StartupInfo.ShowErrorMessage(s); +} + +int PrintErrorMessage(const char *message, const char *text) +{ + return g_StartupInfo.ShowErrorMessage2(message, text); +} + + +void ReduceString(UString &s, unsigned size) +{ + if (s.Len() > size) + { + if (size > 5) + size -= 5; + s.Delete(size / 2, s.Len() - size); + s.Insert(size / 2, L" ... "); + } +} + +int PrintErrorMessage(const char *message, const wchar_t *name, unsigned maxLen) +{ + UString s = name; + ReduceString(s, maxLen); + return PrintErrorMessage(message, UnicodeStringToMultiByte(s, CP_OEMCP)); +} + +int ShowSysErrorMessage(DWORD errorCode) +{ + const UString message = NError::MyFormatMessage(errorCode); + return g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)); +} + +int ShowLastErrorMessage() +{ + return ShowSysErrorMessage(::GetLastError()); +} + +int ShowSysErrorMessage(DWORD errorCode, const wchar_t *name) +{ + const UString s = NError::MyFormatMessage(errorCode); + return g_StartupInfo.ShowErrorMessage2( + UnicodeStringToMultiByte(s, CP_OEMCP), + UnicodeStringToMultiByte(name, CP_OEMCP)); +} + + +bool WasEscPressed() +{ + #ifdef UNDER_CE + return false; + #else + NConsole::CIn inConsole; + HANDLE handle = ::GetStdHandle(STD_INPUT_HANDLE); + if (handle == INVALID_HANDLE_VALUE) + return true; + inConsole.Attach(handle); + for (;;) + { + DWORD numEvents; + if (!inConsole.GetNumberOfEvents(numEvents)) + return true; + if (numEvents == 0) + return false; + + INPUT_RECORD event; + if (!inConsole.ReadEvent(event, numEvents)) + return true; + if (event.EventType == KEY_EVENT && + event.Event.KeyEvent.bKeyDown && + event.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) + return true; + } + #endif +} + +} diff --git a/CPP/7zip/UI/Far/FarUtils.h b/CPP/7zip/UI/Far/FarUtils.h index b17446a06..fefbc22c7 100644 --- a/CPP/7zip/UI/Far/FarUtils.h +++ b/CPP/7zip/UI/Far/FarUtils.h @@ -1,203 +1,203 @@ -// FarUtils.h - -#ifndef ZIP7_INC_FAR_UTILS_H -#define ZIP7_INC_FAR_UTILS_H - -#include "FarPlugin.h" - -#include "../../../Windows/Registry.h" - -namespace NFar { - -namespace NFileOperationReturnCode -{ - enum EEnum - { - kInterruptedByUser = -1, - kError = 0, - kSuccess = 1 - }; -} - -namespace NEditorReturnCode -{ - enum EEnum - { - kOpenError = 0, - kFileWasChanged = 1, - kFileWasNotChanged = 2, - kInterruptedByUser = 3 - }; -} - -struct CInitDialogItem -{ - DialogItemTypes Type; - int X1,Y1,X2,Y2; - bool Focus; - bool Selected; - UInt32 Flags; //FarDialogItemFlags Flags; - bool DefaultButton; - int DataMessageId; - const char *DataString; - const char *HistoryName; - // void InitToFarDialogItem(struct FarDialogItem &anItemDest); -}; - -class CStartupInfo -{ - PluginStartupInfo m_Data; - AString m_RegistryPath; - - CSysString GetFullKeyName(const char *keyName) const; - LONG CreateRegKey(HKEY parentKey, - const char *keyName, NWindows::NRegistry::CKey &destKey) const; - LONG OpenRegKey(HKEY parentKey, - const char *keyName, NWindows::NRegistry::CKey &destKey) const; - -public: - void Init(const PluginStartupInfo &pluginStartupInfo, - const char *pluginNameForRegistry); - const char *GetMsgString(int messageId); - - int ShowMessage(UInt32 flags, const char *helpTopic, - const char **items, unsigned numItems, int numButtons); - int ShowWarningWithOk(const char **items, unsigned numItems); - - void SetErrorTitle(AString &s); - int ShowErrorMessage(const char *message); - int ShowErrorMessage2(const char *m1, const char *m2); - // int ShowMessageLines(const char *messageLines); - int ShowMessage(int messageId); - - int ShowDialog(int X1, int Y1, int X2, int Y2, - const char *helpTopic, struct FarDialogItem *items, unsigned numItems); - int ShowDialog(int sizeX, int sizeY, - const char *helpTopic, struct FarDialogItem *items, unsigned numItems); - - void InitDialogItems(const CInitDialogItem *srcItems, - FarDialogItem *destItems, unsigned numItems); - - HANDLE SaveScreen(int X1, int Y1, int X2, int Y2); - HANDLE SaveScreen(); - void RestoreScreen(HANDLE handle); - - void SetRegKeyValue(HKEY parentKey, const char *keyName, - const LPCTSTR valueName, LPCTSTR value) const; - void SetRegKeyValue(HKEY hRoot, const char *keyName, - const LPCTSTR valueName, UInt32 value) const; - void SetRegKeyValue(HKEY hRoot, const char *keyName, - const LPCTSTR valueName, bool value) const; - - CSysString QueryRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, const CSysString &valueDefault) const; - - UInt32 QueryRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, UInt32 valueDefault) const; - - bool QueryRegKeyValue(HKEY parentKey, const char *keyName, - LPCTSTR valueName, bool valueDefault) const; - - bool Control(HANDLE plugin, int command, void *param); - bool ControlRequestActivePanel(int command, void *param); - bool ControlGetActivePanelInfo(PanelInfo &panelInfo); - bool ControlSetSelection(const PanelInfo &panelInfo); - bool ControlGetActivePanelCurrentItemInfo(PluginPanelItem &pluginPanelItem); - bool ControlGetActivePanelSelectedOrCurrentItems( - CObjectVector &pluginPanelItems); - - bool ControlClearPanelSelection(); - - int Menu( - int x, - int y, - int maxHeight, - unsigned flags, - const char *title, - const char *aBottom, - const char *helpTopic, - int *breakKeys, - int *breakCode, - FarMenuItem *items, - unsigned numItems); - int Menu( - unsigned flags, - const char *title, - const char *helpTopic, - FarMenuItem *items, - unsigned numItems); - - int Menu( - unsigned flags, - const char *title, - const char *helpTopic, - const AStringVector &items, - int selectedItem); - - int Editor(const char *fileName, const char *title, - int X1, int Y1, int X2, int Y2, DWORD flags, int startLine, int startChar) - { return m_Data.Editor(const_cast(fileName), const_cast(title), X1, Y1, X2, Y2, - flags, startLine, startChar); } - int Editor(const char *fileName) - { return Editor(fileName, NULL, 0, 0, -1, -1, 0, -1, -1); } - - int Viewer(const char *fileName, const char *title, - int X1, int Y1, int X2, int Y2, DWORD flags) - { return m_Data.Viewer(const_cast(fileName), const_cast(title), X1, Y1, X2, Y2, flags); } - int Viewer(const char *fileName) - { return Viewer(fileName, NULL, 0, 0, -1, -1, VF_NONMODAL); } - -}; - -class CScreenRestorer -{ - bool m_Saved; - HANDLE m_HANDLE; -public: - CScreenRestorer(): m_Saved(false) {} - ~CScreenRestorer(); - void Save(); - void Restore(); -}; - - -extern CStartupInfo g_StartupInfo; - - -int PrintErrorMessage(const char *message, unsigned code); -int PrintErrorMessage(const char *message, const char *text); -int PrintErrorMessage(const char *message, const wchar_t *name, unsigned maxLen = 70); - -#define MY_TRY_BEGIN try { - -#define MY_TRY_END1(x) }\ - catch(unsigned n) { PrintErrorMessage(x, n); return; }\ - catch(const CSysString &s) { PrintErrorMessage(x, s); return; }\ - catch(const char *s) { PrintErrorMessage(x, s); return; }\ - catch(...) { g_StartupInfo.ShowErrorMessage(x); return; } - -#define MY_TRY_END2(x, y) }\ - catch(unsigned n) { PrintErrorMessage(x, n); return y; }\ - catch(const AString &s) { PrintErrorMessage(x, s); return y; }\ - catch(const char *s) { PrintErrorMessage(x, s); return y; }\ - catch(const UString &s) { PrintErrorMessage(x, s); return y; }\ - catch(const wchar_t *s) { PrintErrorMessage(x, s); return y; }\ - catch(...) { g_StartupInfo.ShowErrorMessage(x); return y; } - - -int ShowSysErrorMessage(DWORD errorCode); -int ShowSysErrorMessage(DWORD errorCode, const wchar_t *name); -int ShowLastErrorMessage(); - -inline int ShowSysErrorMessage(HRESULT errorCode) - { return ShowSysErrorMessage((DWORD)errorCode); } -inline int ShowSysErrorMessage(HRESULT errorCode, const wchar_t *name) - { return ShowSysErrorMessage((DWORD)errorCode, name); } - -bool WasEscPressed(); - -void ReduceString(UString &s, unsigned size); - -} - -#endif +// FarUtils.h + +#ifndef ZIP7_INC_FAR_UTILS_H +#define ZIP7_INC_FAR_UTILS_H + +#include "FarPlugin.h" + +#include "../../../Windows/Registry.h" + +namespace NFar { + +namespace NFileOperationReturnCode +{ + enum EEnum + { + kInterruptedByUser = -1, + kError = 0, + kSuccess = 1 + }; +} + +namespace NEditorReturnCode +{ + enum EEnum + { + kOpenError = 0, + kFileWasChanged = 1, + kFileWasNotChanged = 2, + kInterruptedByUser = 3 + }; +} + +struct CInitDialogItem +{ + DialogItemTypes Type; + int X1,Y1,X2,Y2; + bool Focus; + bool Selected; + UInt32 Flags; //FarDialogItemFlags Flags; + bool DefaultButton; + int DataMessageId; + const char *DataString; + const char *HistoryName; + // void InitToFarDialogItem(struct FarDialogItem &anItemDest); +}; + +class CStartupInfo +{ + PluginStartupInfo m_Data; + AString m_RegistryPath; + + CSysString GetFullKeyName(const char *keyName) const; + LONG CreateRegKey(HKEY parentKey, + const char *keyName, NWindows::NRegistry::CKey &destKey) const; + LONG OpenRegKey(HKEY parentKey, + const char *keyName, NWindows::NRegistry::CKey &destKey) const; + +public: + void Init(const PluginStartupInfo &pluginStartupInfo, + const char *pluginNameForRegistry); + const char *GetMsgString(int messageId); + + int ShowMessage(UInt32 flags, const char *helpTopic, + const char **items, unsigned numItems, int numButtons); + int ShowWarningWithOk(const char **items, unsigned numItems); + + void SetErrorTitle(AString &s); + int ShowErrorMessage(const char *message); + int ShowErrorMessage2(const char *m1, const char *m2); + // int ShowMessageLines(const char *messageLines); + int ShowMessage(int messageId); + + int ShowDialog(int X1, int Y1, int X2, int Y2, + const char *helpTopic, struct FarDialogItem *items, unsigned numItems); + int ShowDialog(int sizeX, int sizeY, + const char *helpTopic, struct FarDialogItem *items, unsigned numItems); + + void InitDialogItems(const CInitDialogItem *srcItems, + FarDialogItem *destItems, unsigned numItems); + + HANDLE SaveScreen(int X1, int Y1, int X2, int Y2); + HANDLE SaveScreen(); + void RestoreScreen(HANDLE handle); + + void SetRegKeyValue(HKEY parentKey, const char *keyName, + const LPCTSTR valueName, LPCTSTR value) const; + void SetRegKeyValue(HKEY hRoot, const char *keyName, + const LPCTSTR valueName, UInt32 value) const; + void SetRegKeyValue(HKEY hRoot, const char *keyName, + const LPCTSTR valueName, bool value) const; + + CSysString QueryRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, const CSysString &valueDefault) const; + + UInt32 QueryRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, UInt32 valueDefault) const; + + bool QueryRegKeyValue(HKEY parentKey, const char *keyName, + LPCTSTR valueName, bool valueDefault) const; + + bool Control(HANDLE plugin, int command, void *param); + bool ControlRequestActivePanel(int command, void *param); + bool ControlGetActivePanelInfo(PanelInfo &panelInfo); + bool ControlSetSelection(const PanelInfo &panelInfo); + bool ControlGetActivePanelCurrentItemInfo(PluginPanelItem &pluginPanelItem); + bool ControlGetActivePanelSelectedOrCurrentItems( + CObjectVector &pluginPanelItems); + + bool ControlClearPanelSelection(); + + int Menu( + int x, + int y, + int maxHeight, + unsigned flags, + const char *title, + const char *aBottom, + const char *helpTopic, + int *breakKeys, + int *breakCode, + FarMenuItem *items, + unsigned numItems); + int Menu( + unsigned flags, + const char *title, + const char *helpTopic, + FarMenuItem *items, + unsigned numItems); + + int Menu( + unsigned flags, + const char *title, + const char *helpTopic, + const AStringVector &items, + int selectedItem); + + int Editor(const char *fileName, const char *title, + int X1, int Y1, int X2, int Y2, DWORD flags, int startLine, int startChar) + { return m_Data.Editor(const_cast(fileName), const_cast(title), X1, Y1, X2, Y2, + flags, startLine, startChar); } + int Editor(const char *fileName) + { return Editor(fileName, NULL, 0, 0, -1, -1, 0, -1, -1); } + + int Viewer(const char *fileName, const char *title, + int X1, int Y1, int X2, int Y2, DWORD flags) + { return m_Data.Viewer(const_cast(fileName), const_cast(title), X1, Y1, X2, Y2, flags); } + int Viewer(const char *fileName) + { return Viewer(fileName, NULL, 0, 0, -1, -1, VF_NONMODAL); } + +}; + +class CScreenRestorer +{ + bool m_Saved; + HANDLE m_HANDLE; +public: + CScreenRestorer(): m_Saved(false) {} + ~CScreenRestorer(); + void Save(); + void Restore(); +}; + + +extern CStartupInfo g_StartupInfo; + + +int PrintErrorMessage(const char *message, unsigned code); +int PrintErrorMessage(const char *message, const char *text); +int PrintErrorMessage(const char *message, const wchar_t *name, unsigned maxLen = 70); + +#define MY_TRY_BEGIN try { + +#define MY_TRY_END1(x) }\ + catch(unsigned n) { PrintErrorMessage(x, n); return; }\ + catch(const CSysString &s) { PrintErrorMessage(x, s); return; }\ + catch(const char *s) { PrintErrorMessage(x, s); return; }\ + catch(...) { g_StartupInfo.ShowErrorMessage(x); return; } + +#define MY_TRY_END2(x, y) }\ + catch(unsigned n) { PrintErrorMessage(x, n); return y; }\ + catch(const AString &s) { PrintErrorMessage(x, s); return y; }\ + catch(const char *s) { PrintErrorMessage(x, s); return y; }\ + catch(const UString &s) { PrintErrorMessage(x, s); return y; }\ + catch(const wchar_t *s) { PrintErrorMessage(x, s); return y; }\ + catch(...) { g_StartupInfo.ShowErrorMessage(x); return y; } + + +int ShowSysErrorMessage(DWORD errorCode); +int ShowSysErrorMessage(DWORD errorCode, const wchar_t *name); +int ShowLastErrorMessage(); + +inline int ShowSysErrorMessage(HRESULT errorCode) + { return ShowSysErrorMessage((DWORD)errorCode); } +inline int ShowSysErrorMessage(HRESULT errorCode, const wchar_t *name) + { return ShowSysErrorMessage((DWORD)errorCode, name); } + +bool WasEscPressed(); + +void ReduceString(UString &s, unsigned size); + +} + +#endif diff --git a/CPP/7zip/UI/Far/Messages.h b/CPP/7zip/UI/Far/Messages.h index 63f0bc0a3..f6b20a3d8 100644 --- a/CPP/7zip/UI/Far/Messages.h +++ b/CPP/7zip/UI/Far/Messages.h @@ -1,136 +1,136 @@ -// Far/Messages.h - -#ifndef ZIP7_INC_FAR_MESSAGES_H -#define ZIP7_INC_FAR_MESSAGES_H - -#include "../../PropID.h" - -namespace NMessageID { - -const unsigned k_Last_PropId_supported_by_plugin = kpidDevMinor; - -enum EEnum -{ - kOk, - kCancel, - - kWarning, - kError, - - kArchiveType, - - kProperties, - - kYes, - kNo, - - kGetPasswordTitle, - kEnterPasswordForFile, - - kExtractTitle, - kExtractTo, - - kExtractPathMode, - kExtractPathFull, - kExtractPathCurrent, - kExtractPathNo, - - kExtractOwerwriteMode, - kExtractOwerwriteAsk, - kExtractOwerwritePrompt, - kExtractOwerwriteSkip, - kExtractOwerwriteAutoRename, - kExtractOwerwriteAutoRenameExisting, - - kExtractFilesMode, - kExtractFilesSelected, - kExtractFilesAll, - - kExtractPassword, - - kExtractExtract, - kExtractCancel, - - kExtractCanNotOpenOutputFile, - - kExtractUnsupportedMethod, - kExtractCRCFailed, - kExtractDataError, - kExtractCRCFailedEncrypted, - kExtractDataErrorEncrypted, - - kOverwriteTitle, - kOverwriteMessage1, - kOverwriteMessageWouldYouLike, - kOverwriteMessageWithtTisOne, - - kOverwriteBytes, - kOverwriteModifiedOn, - - kOverwriteYes, - kOverwriteYesToAll, - kOverwriteNo, - kOverwriteNoToAll, - kOverwriteAutoRename, - kOverwriteCancel, - - kUpdateNotSupportedForThisArchive, - - kDeleteTitle, - kDeleteFile, - kDeleteFiles, - kDeleteNumberOfFiles, - kDeleteDelete, - kDeleteCancel, - - kUpdateTitle, - kUpdateAddToArchive, - - kUpdateMethod, - kUpdateMethod_Store, - kUpdateMethod_Fastest, - kUpdateMethod_Fast, - kUpdateMethod_Normal, - kUpdateMethod_Maximum, - kUpdateMethod_Ultra, - - kUpdateMode, - kUpdateMode_Add, - kUpdateMode_Update, - kUpdateMode_Fresh, - kUpdateMode_Sync, - - kUpdateAdd, - kUpdateSelectArchiver, - - kUpdateSelectArchiverMenuTitle, - - // kArcReadFiles, - - kWaitTitle, - - kReading, - kExtracting, - kDeleting, - kUpdating, - - // kReadingList, - - kMoveIsNotSupported, - - kOpenArchiveMenuString, - kCreateArchiveMenuString, - - kConfigTitle, - - kConfigPluginEnabled, - - // ---------- IDs for Properies (kpid*) ---------- - kNoProperty, - k_Last_MessageID_for_Property = kNoProperty + k_Last_PropId_supported_by_plugin - // ---------- -}; - -} - -#endif +// Far/Messages.h + +#ifndef ZIP7_INC_FAR_MESSAGES_H +#define ZIP7_INC_FAR_MESSAGES_H + +#include "../../PropID.h" + +namespace NMessageID { + +const unsigned k_Last_PropId_supported_by_plugin = kpidDevMinor; + +enum EEnum +{ + kOk, + kCancel, + + kWarning, + kError, + + kArchiveType, + + kProperties, + + kYes, + kNo, + + kGetPasswordTitle, + kEnterPasswordForFile, + + kExtractTitle, + kExtractTo, + + kExtractPathMode, + kExtractPathFull, + kExtractPathCurrent, + kExtractPathNo, + + kExtractOwerwriteMode, + kExtractOwerwriteAsk, + kExtractOwerwritePrompt, + kExtractOwerwriteSkip, + kExtractOwerwriteAutoRename, + kExtractOwerwriteAutoRenameExisting, + + kExtractFilesMode, + kExtractFilesSelected, + kExtractFilesAll, + + kExtractPassword, + + kExtractExtract, + kExtractCancel, + + kExtractCanNotOpenOutputFile, + + kExtractUnsupportedMethod, + kExtractCRCFailed, + kExtractDataError, + kExtractCRCFailedEncrypted, + kExtractDataErrorEncrypted, + + kOverwriteTitle, + kOverwriteMessage1, + kOverwriteMessageWouldYouLike, + kOverwriteMessageWithtTisOne, + + kOverwriteBytes, + kOverwriteModifiedOn, + + kOverwriteYes, + kOverwriteYesToAll, + kOverwriteNo, + kOverwriteNoToAll, + kOverwriteAutoRename, + kOverwriteCancel, + + kUpdateNotSupportedForThisArchive, + + kDeleteTitle, + kDeleteFile, + kDeleteFiles, + kDeleteNumberOfFiles, + kDeleteDelete, + kDeleteCancel, + + kUpdateTitle, + kUpdateAddToArchive, + + kUpdateMethod, + kUpdateMethod_Store, + kUpdateMethod_Fastest, + kUpdateMethod_Fast, + kUpdateMethod_Normal, + kUpdateMethod_Maximum, + kUpdateMethod_Ultra, + + kUpdateMode, + kUpdateMode_Add, + kUpdateMode_Update, + kUpdateMode_Fresh, + kUpdateMode_Sync, + + kUpdateAdd, + kUpdateSelectArchiver, + + kUpdateSelectArchiverMenuTitle, + + // kArcReadFiles, + + kWaitTitle, + + kReading, + kExtracting, + kDeleting, + kUpdating, + + // kReadingList, + + kMoveIsNotSupported, + + kOpenArchiveMenuString, + kCreateArchiveMenuString, + + kConfigTitle, + + kConfigPluginEnabled, + + // ---------- IDs for Properies (kpid*) ---------- + kNoProperty, + k_Last_MessageID_for_Property = kNoProperty + k_Last_PropId_supported_by_plugin + // ---------- +}; + +} + +#endif diff --git a/CPP/7zip/UI/Far/OverwriteDialogFar.cpp b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp index 54554341a..4d1b971fc 100644 --- a/CPP/7zip/UI/Far/OverwriteDialogFar.cpp +++ b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp @@ -1,145 +1,145 @@ -// OverwriteDialogFar.cpp - -#include "StdAfx.h" - -#include - -#include "../../../Common/StringConvert.h" -#include "../../../Common/IntToString.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariantConv.h" - -#include "FarUtils.h" -#include "Messages.h" - -#include "OverwriteDialogFar.h" - -using namespace NWindows; -using namespace NFar; - -namespace NOverwriteDialog { - -struct CFileInfoStrings -{ - AString Size; - AString Time; -}; - -static void SetFileInfoStrings(const CFileInfo &fileInfo, - CFileInfoStrings &fileInfoStrings) -{ - char buffer[256]; - - if (fileInfo.SizeIsDefined) - { - ConvertUInt64ToString(fileInfo.Size, buffer); - fileInfoStrings.Size = buffer; - fileInfoStrings.Size.Add_Space(); - fileInfoStrings.Size += g_StartupInfo.GetMsgString(NMessageID::kOverwriteBytes); - } - else - { - fileInfoStrings.Size = ""; - } - - fileInfoStrings.Time.Empty(); - if (fileInfo.TimeIsDefined) - { - char timeString[64]; - ConvertUtcFileTimeToString(fileInfo.Time, timeString); - fileInfoStrings.Time = g_StartupInfo.GetMsgString(NMessageID::kOverwriteModifiedOn); - fileInfoStrings.Time.Add_Space(); - fileInfoStrings.Time += timeString; - } -} - -static void ReduceString2(UString &s, unsigned size) -{ - if (!s.IsEmpty() && s.Back() == ' ') - { - // s += (wchar_t)(0x2423); - s.InsertAtFront(L'\"'); - s += L'\"'; - } - ReduceString(s, size); -} - -NResult::EEnum Execute(const CFileInfo &oldFileInfo, const CFileInfo &newFileInfo) -{ - const int kYSize = 22; - const int kXSize = 76; - - CFileInfoStrings oldFileInfoStrings; - CFileInfoStrings newFileInfoStrings; - - SetFileInfoStrings(oldFileInfo, oldFileInfoStrings); - SetFileInfoStrings(newFileInfo, newFileInfoStrings); - - const UString &oldName2 = oldFileInfo.Name; - const UString &newName2 = newFileInfo.Name; - - int slashPos = oldName2.ReverseFind_PathSepar(); - UString pref1 = oldName2.Left(slashPos + 1); - UString name1 = oldName2.Ptr(slashPos + 1); - - slashPos = newName2.ReverseFind_PathSepar(); - UString pref2 = newName2.Left(slashPos + 1); - UString name2 = newName2.Ptr(slashPos + 1); - - const unsigned kNameOffset = 2; - { - const unsigned maxNameLen = kXSize - 9 - 2; - ReduceString(pref1, maxNameLen); - ReduceString(pref2, maxNameLen); - ReduceString2(name1, maxNameLen - kNameOffset); - ReduceString2(name2, maxNameLen - kNameOffset); - } - - const AString pref1A (UnicodeStringToMultiByte(pref1, CP_OEMCP)); - const AString pref2A (UnicodeStringToMultiByte(pref2, CP_OEMCP)); - const AString name1A (UnicodeStringToMultiByte(name1, CP_OEMCP)); - const AString name2A (UnicodeStringToMultiByte(name2, CP_OEMCP)); - - const struct CInitDialogItem initItems[]={ - { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kOverwriteTitle, NULL, NULL }, - { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessage1, NULL, NULL }, - - { DI_TEXT, 3, 3, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, - - { DI_TEXT, 5, 4, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessageWouldYouLike, NULL, NULL }, - - { DI_TEXT, 7, 6, 0, 0, false, false, 0, false, -1, pref1A, NULL }, - { DI_TEXT, 7 + kNameOffset, 7, 0, 0, false, false, 0, false, -1, name1A, NULL }, - { DI_TEXT, 7, 8, 0, 0, false, false, 0, false, -1, oldFileInfoStrings.Size, NULL }, - { DI_TEXT, 7, 9, 0, 0, false, false, 0, false, -1, oldFileInfoStrings.Time, NULL }, - - { DI_TEXT, 5, 11, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessageWithtTisOne, NULL, NULL }, - - { DI_TEXT, 7, 13, 0, 0, false, false, 0, false, -1, pref2A, NULL }, - { DI_TEXT, 7 + kNameOffset, 14, 0, 0, false, false, 0, false, -1, name2A, NULL }, - { DI_TEXT, 7, 15, 0, 0, false, false, 0, false, -1, newFileInfoStrings.Size, NULL }, - { DI_TEXT, 7, 16, 0, 0, false, false, 0, false, -1, newFileInfoStrings.Time, NULL }, - - { DI_TEXT, 3, kYSize - 5, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, - - { DI_BUTTON, 0, kYSize - 4, 0, 0, true, false, DIF_CENTERGROUP, true, NMessageID::kOverwriteYes, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteYesToAll, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteNo, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteNoToAll, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteAutoRename, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteCancel, NULL, NULL } - }; - - const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); - FarDialogItem aDialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, aDialogItems, kNumDialogItems); - const int anAskCode = g_StartupInfo.ShowDialog(kXSize, kYSize, - NULL, aDialogItems, kNumDialogItems); - const int kButtonStartPos = kNumDialogItems - 6; - if (anAskCode >= kButtonStartPos && anAskCode < kNumDialogItems) - return NResult::EEnum(anAskCode - kButtonStartPos); - return NResult::kCancel; -} - -} +// OverwriteDialogFar.cpp + +#include "StdAfx.h" + +#include + +#include "../../../Common/StringConvert.h" +#include "../../../Common/IntToString.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariantConv.h" + +#include "FarUtils.h" +#include "Messages.h" + +#include "OverwriteDialogFar.h" + +using namespace NWindows; +using namespace NFar; + +namespace NOverwriteDialog { + +struct CFileInfoStrings +{ + AString Size; + AString Time; +}; + +static void SetFileInfoStrings(const CFileInfo &fileInfo, + CFileInfoStrings &fileInfoStrings) +{ + char buffer[256]; + + if (fileInfo.SizeIsDefined) + { + ConvertUInt64ToString(fileInfo.Size, buffer); + fileInfoStrings.Size = buffer; + fileInfoStrings.Size.Add_Space(); + fileInfoStrings.Size += g_StartupInfo.GetMsgString(NMessageID::kOverwriteBytes); + } + else + { + fileInfoStrings.Size = ""; + } + + fileInfoStrings.Time.Empty(); + if (fileInfo.TimeIsDefined) + { + char timeString[64]; + ConvertUtcFileTimeToString(fileInfo.Time, timeString); + fileInfoStrings.Time = g_StartupInfo.GetMsgString(NMessageID::kOverwriteModifiedOn); + fileInfoStrings.Time.Add_Space(); + fileInfoStrings.Time += timeString; + } +} + +static void ReduceString2(UString &s, unsigned size) +{ + if (!s.IsEmpty() && s.Back() == ' ') + { + // s += (wchar_t)(0x2423); + s.InsertAtFront(L'\"'); + s += L'\"'; + } + ReduceString(s, size); +} + +NResult::EEnum Execute(const CFileInfo &oldFileInfo, const CFileInfo &newFileInfo) +{ + const int kYSize = 22; + const int kXSize = 76; + + CFileInfoStrings oldFileInfoStrings; + CFileInfoStrings newFileInfoStrings; + + SetFileInfoStrings(oldFileInfo, oldFileInfoStrings); + SetFileInfoStrings(newFileInfo, newFileInfoStrings); + + const UString &oldName2 = oldFileInfo.Name; + const UString &newName2 = newFileInfo.Name; + + int slashPos = oldName2.ReverseFind_PathSepar(); + UString pref1 = oldName2.Left(slashPos + 1); + UString name1 = oldName2.Ptr(slashPos + 1); + + slashPos = newName2.ReverseFind_PathSepar(); + UString pref2 = newName2.Left(slashPos + 1); + UString name2 = newName2.Ptr(slashPos + 1); + + const unsigned kNameOffset = 2; + { + const unsigned maxNameLen = kXSize - 9 - 2; + ReduceString(pref1, maxNameLen); + ReduceString(pref2, maxNameLen); + ReduceString2(name1, maxNameLen - kNameOffset); + ReduceString2(name2, maxNameLen - kNameOffset); + } + + const AString pref1A (UnicodeStringToMultiByte(pref1, CP_OEMCP)); + const AString pref2A (UnicodeStringToMultiByte(pref2, CP_OEMCP)); + const AString name1A (UnicodeStringToMultiByte(name1, CP_OEMCP)); + const AString name2A (UnicodeStringToMultiByte(name2, CP_OEMCP)); + + const struct CInitDialogItem initItems[]={ + { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kOverwriteTitle, NULL, NULL }, + { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessage1, NULL, NULL }, + + { DI_TEXT, 3, 3, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, + + { DI_TEXT, 5, 4, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessageWouldYouLike, NULL, NULL }, + + { DI_TEXT, 7, 6, 0, 0, false, false, 0, false, -1, pref1A, NULL }, + { DI_TEXT, 7 + kNameOffset, 7, 0, 0, false, false, 0, false, -1, name1A, NULL }, + { DI_TEXT, 7, 8, 0, 0, false, false, 0, false, -1, oldFileInfoStrings.Size, NULL }, + { DI_TEXT, 7, 9, 0, 0, false, false, 0, false, -1, oldFileInfoStrings.Time, NULL }, + + { DI_TEXT, 5, 11, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessageWithtTisOne, NULL, NULL }, + + { DI_TEXT, 7, 13, 0, 0, false, false, 0, false, -1, pref2A, NULL }, + { DI_TEXT, 7 + kNameOffset, 14, 0, 0, false, false, 0, false, -1, name2A, NULL }, + { DI_TEXT, 7, 15, 0, 0, false, false, 0, false, -1, newFileInfoStrings.Size, NULL }, + { DI_TEXT, 7, 16, 0, 0, false, false, 0, false, -1, newFileInfoStrings.Time, NULL }, + + { DI_TEXT, 3, kYSize - 5, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, + + { DI_BUTTON, 0, kYSize - 4, 0, 0, true, false, DIF_CENTERGROUP, true, NMessageID::kOverwriteYes, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteYesToAll, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteNo, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteNoToAll, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteAutoRename, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteCancel, NULL, NULL } + }; + + const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); + FarDialogItem aDialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, aDialogItems, kNumDialogItems); + const int anAskCode = g_StartupInfo.ShowDialog(kXSize, kYSize, + NULL, aDialogItems, kNumDialogItems); + const int kButtonStartPos = kNumDialogItems - 6; + if (anAskCode >= kButtonStartPos && anAskCode < kNumDialogItems) + return NResult::EEnum(anAskCode - kButtonStartPos); + return NResult::kCancel; +} + +} diff --git a/CPP/7zip/UI/Far/OverwriteDialogFar.h b/CPP/7zip/UI/Far/OverwriteDialogFar.h index e2e49b74b..bc6e92bc0 100644 --- a/CPP/7zip/UI/Far/OverwriteDialogFar.h +++ b/CPP/7zip/UI/Far/OverwriteDialogFar.h @@ -1,37 +1,37 @@ -// OverwriteDialogFar.h - -#ifndef ZIP7_INC_OVERWRITE_DIALOG_FAR_H -#define ZIP7_INC_OVERWRITE_DIALOG_FAR_H - -#include "../../../Common/MyString.h" -#include "../../../Common/MyTypes.h" - -namespace NOverwriteDialog { - -struct CFileInfo -{ - bool SizeIsDefined; - bool TimeIsDefined; - UInt64 Size; - FILETIME Time; - UString Name; -}; - -namespace NResult -{ - enum EEnum - { - kYes, - kYesToAll, - kNo, - kNoToAll, - kAutoRename, - kCancel - }; -} - -NResult::EEnum Execute(const CFileInfo &oldFileInfo, const CFileInfo &newFileInfo); - -} - -#endif +// OverwriteDialogFar.h + +#ifndef ZIP7_INC_OVERWRITE_DIALOG_FAR_H +#define ZIP7_INC_OVERWRITE_DIALOG_FAR_H + +#include "../../../Common/MyString.h" +#include "../../../Common/MyTypes.h" + +namespace NOverwriteDialog { + +struct CFileInfo +{ + bool SizeIsDefined; + bool TimeIsDefined; + UInt64 Size; + FILETIME Time; + UString Name; +}; + +namespace NResult +{ + enum EEnum + { + kYes, + kYesToAll, + kNo, + kNoToAll, + kAutoRename, + kCancel + }; +} + +NResult::EEnum Execute(const CFileInfo &oldFileInfo, const CFileInfo &newFileInfo); + +} + +#endif diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp index 0bbbe0bed..2d31b8a14 100644 --- a/CPP/7zip/UI/Far/Plugin.cpp +++ b/CPP/7zip/UI/Far/Plugin.cpp @@ -1,927 +1,927 @@ -// Plugin.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../Common/PropIDUtils.h" - -#include "FarUtils.h" -#include "Messages.h" -#include "Plugin.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NFar; - -// This function is used by CAgentFolder -int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2); -int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2) -{ - return MyStringCompareNoCase(s1, s2); -} - -CPlugin::CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName): - _agent(agent), - m_FileName(fileName), - _archiveTypeName(archiveTypeName), - PasswordIsDefined(false) -{ - m_ArchiveHandler = agent; - if (!m_FileInfo.Find(m_FileName)) - throw "error"; - m_ArchiveHandler->BindToRootFolder(&_folder); -} - -CPlugin::~CPlugin() {} - -static void MyGetFileTime(IFolderFolder *folder, UInt32 itemIndex, - PROPID propID, FILETIME &fileTime) -{ - NCOM::CPropVariant prop; - if (folder->GetProperty(itemIndex, propID, &prop) != S_OK) - throw 271932; - if (prop.vt == VT_EMPTY) - { - fileTime.dwHighDateTime = 0; - fileTime.dwLowDateTime = 0; - } - else - { - if (prop.vt != VT_FILETIME) - throw 4191730; - fileTime = prop.filetime; - } -} - -#define kDotsReplaceString "[[..]]" -#define kDotsReplaceStringU L"[[..]]" - -static void CopyStrLimited(char *dest, const AString &src, unsigned len) -{ - len--; - if (src.Len() < len) - len = src.Len(); - memcpy(dest, src, sizeof(dest[0]) * len); - dest[len] = 0; -} - -#define COPY_STR_LIMITED(dest, src) CopyStrLimited(dest, src, Z7_ARRAY_SIZE(dest)) - -void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex) -{ - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) - throw 271932; - - if (prop.vt != VT_BSTR) - throw 272340; - - AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); - if (oemString == "..") - oemString = kDotsReplaceString; - - COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString); - panelItem.FindData.cAlternateFileName[0] = 0; - - if (_folder->GetProperty(itemIndex, kpidAttrib, &prop) != S_OK) - throw 271932; - if (prop.vt == VT_UI4) - panelItem.FindData.dwFileAttributes = prop.ulVal; - else if (prop.vt == VT_EMPTY) - panelItem.FindData.dwFileAttributes = m_FileInfo.Attrib; - else - throw 21631; - - if (_folder->GetProperty(itemIndex, kpidIsDir, &prop) != S_OK) - throw 271932; - if (prop.vt == VT_BOOL) - { - if (VARIANT_BOOLToBool(prop.boolVal)) - panelItem.FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; - } - else if (prop.vt != VT_EMPTY) - throw 21632; - - if (_folder->GetProperty(itemIndex, kpidSize, &prop) != S_OK) - throw 271932; - UInt64 length = 0; - ConvertPropVariantToUInt64(prop, length); - panelItem.FindData.nFileSizeLow = (UInt32)length; - panelItem.FindData.nFileSizeHigh = (UInt32)(length >> 32); - - MyGetFileTime(_folder, itemIndex, kpidCTime, panelItem.FindData.ftCreationTime); - MyGetFileTime(_folder, itemIndex, kpidATime, panelItem.FindData.ftLastAccessTime); - MyGetFileTime(_folder, itemIndex, kpidMTime, panelItem.FindData.ftLastWriteTime); - - if (panelItem.FindData.ftLastWriteTime.dwHighDateTime == 0 && - panelItem.FindData.ftLastWriteTime.dwLowDateTime == 0) - panelItem.FindData.ftLastWriteTime = m_FileInfo.MTime; - - if (_folder->GetProperty(itemIndex, kpidPackSize, &prop) != S_OK) - throw 271932; - length = 0; - ConvertPropVariantToUInt64(prop, length); - panelItem.PackSize = UInt32(length); - panelItem.PackSizeHigh = UInt32(length >> 32); - - panelItem.Flags = 0; - panelItem.NumberOfLinks = 0; - - panelItem.Description = NULL; - panelItem.Owner = NULL; - panelItem.CustomColumnData = NULL; - panelItem.CustomColumnNumber = 0; - - panelItem.CRC32 = 0; - panelItem.Reserved[0] = 0; - panelItem.Reserved[1] = 0; -} - -int CPlugin::GetFindData(PluginPanelItem **panelItems, int *itemsNumber, int opMode) -{ - // CScreenRestorer screenRestorer; - if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) - { - /* - screenRestorer.Save(); - const char *msgItems[]= - { - g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kReadingList) - }; - g_StartupInfo.ShowMessage(0, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 0); - */ - } - - UInt32 numItems; - _folder->GetNumberOfItems(&numItems); - *panelItems = new PluginPanelItem[numItems]; - try - { - for (UInt32 i = 0; i < numItems; i++) - { - PluginPanelItem &panelItem = (*panelItems)[i]; - ReadPluginPanelItem(panelItem, i); - panelItem.UserData = i; - } - } - catch(...) - { - delete [](*panelItems); - throw; - } - *itemsNumber = (int)numItems; - return(TRUE); -} - -void CPlugin::FreeFindData(struct PluginPanelItem *panelItems, int itemsNumber) -{ - for (int i = 0; i < itemsNumber; i++) - if (panelItems[i].Description != NULL) - delete []panelItems[i].Description; - delete []panelItems; -} - -void CPlugin::EnterToDirectory(const UString &dirName) -{ - CMyComPtr newFolder; - UString s = dirName; - if (dirName == kDotsReplaceStringU) - s = ".."; - _folder->BindToFolder(s, &newFolder); - if (!newFolder) - { - if (dirName.IsEmpty()) - return; - else - throw 40325; - } - _folder = newFolder; -} - -int CPlugin::SetDirectory(const char *aszDir, int /* opMode */) -{ - UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP); - if (path == WSTRING_PATH_SEPARATOR) - { - _folder.Release(); - m_ArchiveHandler->BindToRootFolder(&_folder); - } - else if (path == L"..") - { - CMyComPtr newFolder; - _folder->BindToParentFolder(&newFolder); - if (!newFolder) - throw 40312; - _folder = newFolder; - } - else if (path.IsEmpty()) - EnterToDirectory(path); - else - { - if (path[0] == WCHAR_PATH_SEPARATOR) - { - _folder.Release(); - m_ArchiveHandler->BindToRootFolder(&_folder); - path.DeleteFrontal(1); - } - UStringVector pathParts; - SplitPathToParts(path, pathParts); - FOR_VECTOR (i, pathParts) - EnterToDirectory(pathParts[i]); - } - SetCurrentDirVar(); - return TRUE; -} - -void CPlugin::GetPathParts(UStringVector &pathParts) -{ - pathParts.Clear(); - CMyComPtr folderItem = _folder; - for (;;) - { - CMyComPtr newFolder; - folderItem->BindToParentFolder(&newFolder); - if (!newFolder) - break; - NCOM::CPropVariant prop; - if (folderItem->GetFolderProperty(kpidName, &prop) == S_OK) - if (prop.vt == VT_BSTR) - pathParts.Insert(0, (const wchar_t *)prop.bstrVal); - folderItem = newFolder; - } -} - -void CPlugin::SetCurrentDirVar() -{ - m_CurrentDir.Empty(); - - /* - // kpidPath path has tail slash, but we don't need it for compatibility with default FAR style - NCOM::CPropVariant prop; - if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK) - if (prop.vt == VT_BSTR) - { - m_CurrentDir = (wchar_t *)prop.bstrVal; - // if (!m_CurrentDir.IsEmpty()) - } - m_CurrentDir.InsertAtFront(WCHAR_PATH_SEPARATOR); - */ - - UStringVector pathParts; - GetPathParts(pathParts); - FOR_VECTOR (i, pathParts) - { - m_CurrentDir.Add_PathSepar(); - m_CurrentDir += pathParts[i]; - } -} - -static const char * const kPluginFormatName = "7-ZIP"; - - -static int FindPropNameID(PROPID propID) -{ - if (propID > NMessageID::k_Last_PropId_supported_by_plugin) - return -1; - return NMessageID::kNoProperty + (int)propID; -} - -/* -struct CPropertyIDInfo -{ - PROPID PropID; - const char *FarID; - int Width; - // char CharID; -}; - -static CPropertyIDInfo kPropertyIDInfos[] = -{ - { kpidName, "N", 0}, - { kpidSize, "S", 8}, - { kpidPackSize, "P", 8}, - { kpidAttrib, "A", 0}, - { kpidCTime, "DC", 14}, - { kpidATime, "DA", 14}, - { kpidMTime, "DM", 14}, - - { kpidSolid, NULL, 0, 'S'}, - { kpidEncrypted, NULL, 0, 'P'}, - - { kpidDictionarySize, IDS_PROPERTY_DICTIONARY_SIZE }, - { kpidSplitBefore, NULL, 'B'}, - { kpidSplitAfter, NULL, 'A'}, - { kpidComment, NULL, 'C'}, - { kpidCRC, IDS_PROPERTY_CRC } - // { kpidType, L"Type" } -}; - -static const int kNumPropertyIDInfos = Z7_ARRAY_SIZE(kPropertyIDInfos); - -static int FindPropertyInfo(PROPID propID) -{ - for (int i = 0; i < kNumPropertyIDInfos; i++) - if (kPropertyIDInfos[i].PropID == propID) - return i; - return -1; -} -*/ - -// char *g_Titles[] = { "a", "f", "v" }; -/* -static void SmartAddToString(AString &destString, const char *srcString) -{ - if (!destString.IsEmpty()) - destString += ','; - destString += srcString; -} -*/ - -/* -void CPlugin::AddColumn(PROPID propID) -{ - int index = FindPropertyInfo(propID); - if (index >= 0) - { - for (int i = 0; i < m_ProxyHandler->m_InternalProperties.Size(); i++) - { - const CArchiveItemProperty &aHandlerProperty = m_ProxyHandler->m_InternalProperties[i]; - if (aHandlerProperty.ID == propID) - break; - } - if (i == m_ProxyHandler->m_InternalProperties.Size()) - return; - - const CPropertyIDInfo &propertyIDInfo = kPropertyIDInfos[index]; - SmartAddToString(PanelModeColumnTypes, propertyIDInfo.FarID); - char tmp[32]; - itoa(propertyIDInfo.Width, tmp, 10); - SmartAddToString(PanelModeColumnWidths, tmp); - return; - } -} -*/ - -static AString GetNameOfProp(PROPID propID, const wchar_t *name) -{ - int farID = FindPropNameID(propID); - if (farID >= 0) - return (AString)g_StartupInfo.GetMsgString(farID); - if (name) - return UnicodeStringToMultiByte(name, CP_OEMCP); - char s[16]; - ConvertUInt32ToString(propID, s); - return (AString)s; -} - -static AString GetNameOfProp2(PROPID propID, const wchar_t *name) -{ - AString s (GetNameOfProp(propID, name)); - if (s.Len() > (kInfoPanelLineSize - 1)) - s.DeleteFrom(kInfoPanelLineSize - 1); - return s; -} - -static AString ConvertSizeToString(UInt64 value) -{ - char s[32]; - ConvertUInt64ToString(value, s); - unsigned i = MyStringLen(s); - unsigned pos = Z7_ARRAY_SIZE(s); - s[--pos] = 0; - while (i > 3) - { - s[--pos] = s[--i]; - s[--pos] = s[--i]; - s[--pos] = s[--i]; - s[--pos] = ' '; - } - while (i > 0) - s[--pos] = s[--i]; - return (AString)(s + pos); -} - -static AString PropToString(const NCOM::CPropVariant &prop, PROPID propID) -{ - if (prop.vt == VT_BSTR) - { - AString s (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); - s.Replace((char)0xA, ' '); - s.Replace((char)0xD, ' '); - return s; - } - if (prop.vt == VT_BOOL) - { - int messageID = VARIANT_BOOLToBool(prop.boolVal) ? - NMessageID::kYes : NMessageID::kNo; - return (AString)g_StartupInfo.GetMsgString(messageID); - } - if (prop.vt != VT_EMPTY) - { - if ((prop.vt == VT_UI8 || prop.vt == VT_UI4) && ( - propID == kpidSize || - propID == kpidPackSize || - propID == kpidNumSubDirs || - propID == kpidNumSubFiles || - propID == kpidNumBlocks || - propID == kpidPhySize || - propID == kpidHeadersSize || - propID == kpidClusterSize || - propID == kpidUnpackSize - )) - { - UInt64 v = 0; - ConvertPropVariantToUInt64(prop, v); - return ConvertSizeToString(v); - } - { - char sz[64]; - ConvertPropertyToShortString2(sz, prop, propID); - return (AString)sz; - } - } - return AString(); -} - -static AString PropToString2(const NCOM::CPropVariant &prop, PROPID propID) -{ - AString s (PropToString(prop, propID)); - if (s.Len() > (kInfoPanelLineSize - 1)) - s.DeleteFrom(kInfoPanelLineSize - 1); - return s; -} - -static void AddPropertyString(InfoPanelLine *lines, unsigned &numItems, PROPID propID, const wchar_t *name, - const NCOM::CPropVariant &prop) -{ - if (prop.vt != VT_EMPTY) - { - AString val (PropToString2(prop, propID)); - if (!val.IsEmpty()) - { - InfoPanelLine &item = lines[numItems++]; - COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name)); - COPY_STR_LIMITED(item.Data, val); - } - } -} - -static void InsertSeparator(InfoPanelLine *lines, unsigned &numItems) -{ - if (numItems < kNumInfoLinesMax) - { - InfoPanelLine &item = lines[numItems++]; - *item.Text = 0; - *item.Data = 0; - item.Separator = TRUE; - } -} - -void CPlugin::GetOpenPluginInfo(struct OpenPluginInfo *info) -{ - info->StructSize = sizeof(*info); - info->Flags = OPIF_USEFILTER | OPIF_USESORTGROUPS | OPIF_USEHIGHLIGHTING | - OPIF_ADDDOTS | OPIF_COMPAREFATTIME; - - COPY_STR_LIMITED(m_FileNameBuffer, UnicodeStringToMultiByte(fs2us(m_FileName), CP_OEMCP)); - info->HostFile = m_FileNameBuffer; // test it it is not static - - COPY_STR_LIMITED(m_CurrentDirBuffer, UnicodeStringToMultiByte(m_CurrentDir, CP_OEMCP)); - info->CurDir = m_CurrentDirBuffer; - - info->Format = kPluginFormatName; - - { - UString name; - { - FString dirPrefix, fileName; - GetFullPathAndSplit(m_FileName, dirPrefix, fileName); - name = fs2us(fileName); - } - - m_PannelTitle = ' '; - m_PannelTitle += _archiveTypeName; - m_PannelTitle.Add_Colon(); - m_PannelTitle += name; - m_PannelTitle.Add_Space(); - if (!m_CurrentDir.IsEmpty()) - { - // m_PannelTitle += '\\'; - m_PannelTitle += m_CurrentDir; - } - - COPY_STR_LIMITED(m_PannelTitleBuffer, UnicodeStringToMultiByte(m_PannelTitle, CP_OEMCP)); - info->PanelTitle = m_PannelTitleBuffer; - - } - - memset(m_InfoLines, 0, sizeof(m_InfoLines)); - m_InfoLines[0].Text[0] = 0; - m_InfoLines[0].Separator = TRUE; - - MyStringCopy(m_InfoLines[1].Text, g_StartupInfo.GetMsgString(NMessageID::kArchiveType)); - MyStringCopy(m_InfoLines[1].Data, (const char *)UnicodeStringToMultiByte(_archiveTypeName, CP_OEMCP)); - - unsigned numItems = 2; - - { - CMyComPtr folderProperties; - _folder.QueryInterface(IID_IFolderProperties, &folderProperties); - if (folderProperties) - { - UInt32 numProps; - if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK) - { - for (UInt32 i = 0; i < numProps && numItems < kNumInfoLinesMax; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK) - continue; - NCOM::CPropVariant prop; - if (_folder->GetFolderProperty(propID, &prop) != S_OK || prop.vt == VT_EMPTY) - continue; - - InfoPanelLine &item = m_InfoLines[numItems++]; - COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name)); - COPY_STR_LIMITED(item.Data, PropToString2(prop, propID)); - } - } - } - } - - /* - if (numItems < kNumInfoLinesMax) - { - InsertSeparator(m_InfoLines, numItems); - } - */ - - { - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - if (getFolderArcProps) - { - CMyComPtr getProps; - getFolderArcProps->GetFolderArcProps(&getProps); - if (getProps) - { - UInt32 numLevels; - if (getProps->GetArcNumLevels(&numLevels) != S_OK) - numLevels = 0; - for (UInt32 level2 = 0; level2 < numLevels; level2++) - { - { - UInt32 level = numLevels - 1 - level2; - UInt32 numProps; - if (getProps->GetArcNumProps(level, &numProps) == S_OK) - { - InsertSeparator(m_InfoLines, numItems); - for (Int32 i = -3; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - switch (i) - { - case -3: propID = kpidPath; break; - case -2: propID = kpidType; break; - case -1: propID = kpidError; break; - default: - if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK) - continue; - } - NCOM::CPropVariant prop; - if (getProps->GetArcProp(level, propID, &prop) != S_OK) - continue; - AddPropertyString(m_InfoLines, numItems, propID, name, prop); - } - } - } - if (level2 != numLevels - 1) - { - UInt32 level = numLevels - 1 - level2; - UInt32 numProps; - if (getProps->GetArcNumProps2(level, &numProps) == S_OK) - { - InsertSeparator(m_InfoLines, numItems); - for (Int32 i = 0; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - if (getProps->GetArcPropInfo2(level, (UInt32)i, &name, &propID, &vt) != S_OK) - continue; - NCOM::CPropVariant prop; - if (getProps->GetArcProp2(level, propID, &prop) != S_OK) - continue; - AddPropertyString(m_InfoLines, numItems, propID, name, prop); - } - } - } - } - } - } - } - - //m_InfoLines[1].Separator = 0; - - info->InfoLines = m_InfoLines; - info->InfoLinesNumber = (int)numItems; - - - info->DescrFiles = NULL; - info->DescrFilesNumber = 0; - - PanelModeColumnTypes.Empty(); - PanelModeColumnWidths.Empty(); - - /* - AddColumn(kpidName); - AddColumn(kpidSize); - AddColumn(kpidPackSize); - AddColumn(kpidMTime); - AddColumn(kpidCTime); - AddColumn(kpidATime); - AddColumn(kpidAttrib); - - _panelMode.ColumnTypes = (char *)(const char *)PanelModeColumnTypes; - _panelMode.ColumnWidths = (char *)(const char *)PanelModeColumnWidths; - _panelMode.ColumnTitles = NULL; - _panelMode.FullScreen = TRUE; - _panelMode.DetailedStatus = FALSE; - _panelMode.AlignExtensions = FALSE; - _panelMode.CaseConversion = FALSE; - _panelMode.StatusColumnTypes = "N"; - _panelMode.StatusColumnWidths = "0"; - _panelMode.Reserved[0] = 0; - _panelMode.Reserved[1] = 0; - - info->PanelModesArray = &_panelMode; - info->PanelModesNumber = 1; - */ - - info->PanelModesArray = NULL; - info->PanelModesNumber = 0; - - info->StartPanelMode = 0; - info->StartSortMode = 0; - info->KeyBar = NULL; - info->ShortcutData = NULL; -} - -struct CArchiveItemProperty -{ - AString Name; - PROPID ID; - VARTYPE Type; -}; - -static inline char GetHex_A_minus10(unsigned v, unsigned a10) -{ - return (char)(v < 10 ? v + '0' : v + a10); -} - -HRESULT CPlugin::ShowAttributesWindow() -{ - PluginPanelItem pluginPanelItem; - if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem)) - return S_FALSE; - if (strcmp(pluginPanelItem.FindData.cFileName, "..") == 0 && - NFind::NAttributes::IsDir(pluginPanelItem.FindData.dwFileAttributes)) - return S_FALSE; - const UInt32 itemIndex = (UInt32)pluginPanelItem.UserData; - - CObjectVector properties; - UInt32 numProps; - RINOK(_folder->GetNumberOfProperties(&numProps)) - unsigned i; - for (i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - RINOK(_folder->GetPropertyInfo(i, &name, &propID, &vt)) - CArchiveItemProperty prop; - prop.Type = vt; - prop.ID = propID; - if (prop.ID == kpidPath) - prop.ID = kpidName; - prop.Name = GetNameOfProp(propID, name); - properties.Add(prop); - } - - int size = 2; - CRecordVector initDialogItems; - - int xSize = 70; - { - const CInitDialogItem idi = - { DI_DOUBLEBOX, 3, 1, xSize - 4, size - 2, false, false, 0, false, NMessageID::kProperties, NULL, NULL }; - initDialogItems.Add(idi); - } - - AStringVector values; - - const int kStartY = 3; - - for (i = 0; i < properties.Size(); i++) - { - const CArchiveItemProperty &property = properties[i]; - - const int startY = kStartY + (int)values.Size(); - - { - CInitDialogItem idi = - { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL }; - idi.DataMessageId = FindPropNameID(property.ID); - if (idi.DataMessageId < 0) - idi.DataString = property.Name; - initDialogItems.Add(idi); - } - - NCOM::CPropVariant prop; - RINOK(_folder->GetProperty(itemIndex, property.ID, &prop)) - values.Add(PropToString(prop, property.ID)); - - { - const CInitDialogItem idi = - { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL }; - initDialogItems.Add(idi); - } - } - - CMyComPtr _folderRawProps; - _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps); - - CObjectVector properties2; - - if (_folderRawProps) - { - _folderRawProps->GetNumRawProps(&numProps); - - for (i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK) - continue; - CArchiveItemProperty prop; - prop.Type = VT_EMPTY; - prop.ID = propID; - if (prop.ID == kpidPath) - prop.ID = kpidName; - prop.Name = GetNameOfProp(propID, name); - properties2.Add(prop); - } - - for (i = 0; i < properties2.Size(); i++) - { - const CArchiveItemProperty &property = properties2[i]; - CMyComBSTR name; - - const void *data; - UInt32 dataSize; - UInt32 propType; - if (_folderRawProps->GetRawProp(itemIndex, property.ID, &data, &dataSize, &propType) != S_OK) - continue; - - if (dataSize != 0) - { - AString s; - if (property.ID == kpidNtSecure) - ConvertNtSecureToString((const Byte *)data, dataSize, s); - else - { - const UInt32 kMaxDataSize = 64; - if (dataSize > kMaxDataSize) - { - s += "data:"; - s.Add_UInt32(dataSize); - } - else - { - const unsigned a = dataSize <= 8 - && (property.ID == kpidCRC || property.ID == kpidChecksum) - ? 'A' - 10 : 'a' - 10; - for (UInt32 k = 0; k < dataSize; k++) - { - const unsigned b = ((const Byte *)data)[k]; - s += GetHex_A_minus10(b >> 4, a); - s += GetHex_A_minus10(b & 15, a); - } - } - } - - const int startY = kStartY + (int)values.Size(); - - { - CInitDialogItem idi = - { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL }; - idi.DataMessageId = FindPropNameID(property.ID); - if (idi.DataMessageId < 0) - idi.DataString = property.Name; - initDialogItems.Add(idi); - } - - values.Add(s); - - { - const CInitDialogItem idi = - { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL }; - initDialogItems.Add(idi); - } - } - } - } - - const unsigned numLines = values.Size(); - for (i = 0; i < numLines; i++) - { - CInitDialogItem &idi = initDialogItems[1 + i * 2 + 1]; - idi.DataString = values[i]; - } - - const unsigned numDialogItems = initDialogItems.Size(); - - CObjArray dialogItems(numDialogItems); - g_StartupInfo.InitDialogItems(initDialogItems.ConstData(), dialogItems, numDialogItems); - - unsigned maxLen = 0; - - for (i = 0; i < numLines; i++) - { - FarDialogItem &dialogItem = dialogItems[1 + i * 2]; - unsigned len = (unsigned)strlen(dialogItem.Data); - if (len > maxLen) - maxLen = len; - } - - unsigned maxLen2 = 0; - const unsigned kSpace = 10; - - for (i = 0; i < numLines; i++) - { - FarDialogItem &dialogItem = dialogItems[1 + i * 2 + 1]; - const unsigned len = (unsigned)strlen(dialogItem.Data); - if (len > maxLen2) - maxLen2 = len; - dialogItem.X1 = (int)(maxLen + kSpace); - } - - size = (int)numLines + 6; - xSize = (int)(maxLen + kSpace + maxLen2 + 5); - FarDialogItem &firstDialogItem = dialogItems[0]; - firstDialogItem.Y2 = size - 2; - firstDialogItem.X2 = xSize - 4; - - /* int askCode = */ g_StartupInfo.ShowDialog(xSize, size, NULL, dialogItems, numDialogItems); - return S_OK; -} - -int CPlugin::ProcessKey(int key, unsigned controlState) -{ - if (key == VK_F7 && controlState == 0) - { - CreateFolder(); - return TRUE; - } - - if (controlState == PKF_CONTROL && key == 'A') - { - HRESULT result = ShowAttributesWindow(); - if (result == S_OK) - return TRUE; - if (result == S_FALSE) - return FALSE; - throw "Error"; - } - - if ((controlState & PKF_ALT) != 0 && key == VK_F6) - { - FString folderPath; - if (!GetOnlyDirPrefix(m_FileName, folderPath)) - return FALSE; - PanelInfo panelInfo; - g_StartupInfo.ControlGetActivePanelInfo(panelInfo); - GetFilesReal(panelInfo.SelectedItems, - (unsigned)panelInfo.SelectedItemsNumber, FALSE, - UnicodeStringToMultiByte(fs2us(folderPath), CP_OEMCP), OPM_SILENT, true); - g_StartupInfo.Control(this, FCTL_UPDATEPANEL, NULL); - g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL); - g_StartupInfo.Control(this, FCTL_UPDATEANOTHERPANEL, NULL); - g_StartupInfo.Control(this, FCTL_REDRAWANOTHERPANEL, NULL); - return TRUE; - } - - return FALSE; -} +// Plugin.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../Common/PropIDUtils.h" + +#include "FarUtils.h" +#include "Messages.h" +#include "Plugin.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NFar; + +// This function is used by CAgentFolder +int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2); +int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2) +{ + return MyStringCompareNoCase(s1, s2); +} + +CPlugin::CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName): + _agent(agent), + m_FileName(fileName), + _archiveTypeName(archiveTypeName), + PasswordIsDefined(false) +{ + m_ArchiveHandler = agent; + if (!m_FileInfo.Find(m_FileName)) + throw "error"; + m_ArchiveHandler->BindToRootFolder(&_folder); +} + +CPlugin::~CPlugin() {} + +static void MyGetFileTime(IFolderFolder *folder, UInt32 itemIndex, + PROPID propID, FILETIME &fileTime) +{ + NCOM::CPropVariant prop; + if (folder->GetProperty(itemIndex, propID, &prop) != S_OK) + throw 271932; + if (prop.vt == VT_EMPTY) + { + fileTime.dwHighDateTime = 0; + fileTime.dwLowDateTime = 0; + } + else + { + if (prop.vt != VT_FILETIME) + throw 4191730; + fileTime = prop.filetime; + } +} + +#define kDotsReplaceString "[[..]]" +#define kDotsReplaceStringU L"[[..]]" + +static void CopyStrLimited(char *dest, const AString &src, unsigned len) +{ + len--; + if (src.Len() < len) + len = src.Len(); + memcpy(dest, src, sizeof(dest[0]) * len); + dest[len] = 0; +} + +#define COPY_STR_LIMITED(dest, src) CopyStrLimited(dest, src, Z7_ARRAY_SIZE(dest)) + +void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex) +{ + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) + throw 271932; + + if (prop.vt != VT_BSTR) + throw 272340; + + AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); + if (oemString == "..") + oemString = kDotsReplaceString; + + COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString); + panelItem.FindData.cAlternateFileName[0] = 0; + + if (_folder->GetProperty(itemIndex, kpidAttrib, &prop) != S_OK) + throw 271932; + if (prop.vt == VT_UI4) + panelItem.FindData.dwFileAttributes = prop.ulVal; + else if (prop.vt == VT_EMPTY) + panelItem.FindData.dwFileAttributes = m_FileInfo.Attrib; + else + throw 21631; + + if (_folder->GetProperty(itemIndex, kpidIsDir, &prop) != S_OK) + throw 271932; + if (prop.vt == VT_BOOL) + { + if (VARIANT_BOOLToBool(prop.boolVal)) + panelItem.FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + else if (prop.vt != VT_EMPTY) + throw 21632; + + if (_folder->GetProperty(itemIndex, kpidSize, &prop) != S_OK) + throw 271932; + UInt64 length = 0; + ConvertPropVariantToUInt64(prop, length); + panelItem.FindData.nFileSizeLow = (UInt32)length; + panelItem.FindData.nFileSizeHigh = (UInt32)(length >> 32); + + MyGetFileTime(_folder, itemIndex, kpidCTime, panelItem.FindData.ftCreationTime); + MyGetFileTime(_folder, itemIndex, kpidATime, panelItem.FindData.ftLastAccessTime); + MyGetFileTime(_folder, itemIndex, kpidMTime, panelItem.FindData.ftLastWriteTime); + + if (panelItem.FindData.ftLastWriteTime.dwHighDateTime == 0 && + panelItem.FindData.ftLastWriteTime.dwLowDateTime == 0) + panelItem.FindData.ftLastWriteTime = m_FileInfo.MTime; + + if (_folder->GetProperty(itemIndex, kpidPackSize, &prop) != S_OK) + throw 271932; + length = 0; + ConvertPropVariantToUInt64(prop, length); + panelItem.PackSize = UInt32(length); + panelItem.PackSizeHigh = UInt32(length >> 32); + + panelItem.Flags = 0; + panelItem.NumberOfLinks = 0; + + panelItem.Description = NULL; + panelItem.Owner = NULL; + panelItem.CustomColumnData = NULL; + panelItem.CustomColumnNumber = 0; + + panelItem.CRC32 = 0; + panelItem.Reserved[0] = 0; + panelItem.Reserved[1] = 0; +} + +int CPlugin::GetFindData(PluginPanelItem **panelItems, int *itemsNumber, int opMode) +{ + // CScreenRestorer screenRestorer; + if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) + { + /* + screenRestorer.Save(); + const char *msgItems[]= + { + g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kReadingList) + }; + g_StartupInfo.ShowMessage(0, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 0); + */ + } + + UInt32 numItems; + _folder->GetNumberOfItems(&numItems); + *panelItems = new PluginPanelItem[numItems]; + try + { + for (UInt32 i = 0; i < numItems; i++) + { + PluginPanelItem &panelItem = (*panelItems)[i]; + ReadPluginPanelItem(panelItem, i); + panelItem.UserData = i; + } + } + catch(...) + { + delete [](*panelItems); + throw; + } + *itemsNumber = (int)numItems; + return(TRUE); +} + +void CPlugin::FreeFindData(struct PluginPanelItem *panelItems, int itemsNumber) +{ + for (int i = 0; i < itemsNumber; i++) + if (panelItems[i].Description != NULL) + delete []panelItems[i].Description; + delete []panelItems; +} + +void CPlugin::EnterToDirectory(const UString &dirName) +{ + CMyComPtr newFolder; + UString s = dirName; + if (dirName == kDotsReplaceStringU) + s = ".."; + _folder->BindToFolder(s, &newFolder); + if (!newFolder) + { + if (dirName.IsEmpty()) + return; + else + throw 40325; + } + _folder = newFolder; +} + +int CPlugin::SetDirectory(const char *aszDir, int /* opMode */) +{ + UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP); + if (path == WSTRING_PATH_SEPARATOR) + { + _folder.Release(); + m_ArchiveHandler->BindToRootFolder(&_folder); + } + else if (path == L"..") + { + CMyComPtr newFolder; + _folder->BindToParentFolder(&newFolder); + if (!newFolder) + throw 40312; + _folder = newFolder; + } + else if (path.IsEmpty()) + EnterToDirectory(path); + else + { + if (path[0] == WCHAR_PATH_SEPARATOR) + { + _folder.Release(); + m_ArchiveHandler->BindToRootFolder(&_folder); + path.DeleteFrontal(1); + } + UStringVector pathParts; + SplitPathToParts(path, pathParts); + FOR_VECTOR (i, pathParts) + EnterToDirectory(pathParts[i]); + } + SetCurrentDirVar(); + return TRUE; +} + +void CPlugin::GetPathParts(UStringVector &pathParts) +{ + pathParts.Clear(); + CMyComPtr folderItem = _folder; + for (;;) + { + CMyComPtr newFolder; + folderItem->BindToParentFolder(&newFolder); + if (!newFolder) + break; + NCOM::CPropVariant prop; + if (folderItem->GetFolderProperty(kpidName, &prop) == S_OK) + if (prop.vt == VT_BSTR) + pathParts.Insert(0, (const wchar_t *)prop.bstrVal); + folderItem = newFolder; + } +} + +void CPlugin::SetCurrentDirVar() +{ + m_CurrentDir.Empty(); + + /* + // kpidPath path has tail slash, but we don't need it for compatibility with default FAR style + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK) + if (prop.vt == VT_BSTR) + { + m_CurrentDir = (wchar_t *)prop.bstrVal; + // if (!m_CurrentDir.IsEmpty()) + } + m_CurrentDir.InsertAtFront(WCHAR_PATH_SEPARATOR); + */ + + UStringVector pathParts; + GetPathParts(pathParts); + FOR_VECTOR (i, pathParts) + { + m_CurrentDir.Add_PathSepar(); + m_CurrentDir += pathParts[i]; + } +} + +static const char * const kPluginFormatName = "7-ZIP"; + + +static int FindPropNameID(PROPID propID) +{ + if (propID > NMessageID::k_Last_PropId_supported_by_plugin) + return -1; + return NMessageID::kNoProperty + (int)propID; +} + +/* +struct CPropertyIDInfo +{ + PROPID PropID; + const char *FarID; + int Width; + // char CharID; +}; + +static CPropertyIDInfo kPropertyIDInfos[] = +{ + { kpidName, "N", 0}, + { kpidSize, "S", 8}, + { kpidPackSize, "P", 8}, + { kpidAttrib, "A", 0}, + { kpidCTime, "DC", 14}, + { kpidATime, "DA", 14}, + { kpidMTime, "DM", 14}, + + { kpidSolid, NULL, 0, 'S'}, + { kpidEncrypted, NULL, 0, 'P'}, + + { kpidDictionarySize, IDS_PROPERTY_DICTIONARY_SIZE }, + { kpidSplitBefore, NULL, 'B'}, + { kpidSplitAfter, NULL, 'A'}, + { kpidComment, NULL, 'C'}, + { kpidCRC, IDS_PROPERTY_CRC } + // { kpidType, L"Type" } +}; + +static const int kNumPropertyIDInfos = Z7_ARRAY_SIZE(kPropertyIDInfos); + +static int FindPropertyInfo(PROPID propID) +{ + for (int i = 0; i < kNumPropertyIDInfos; i++) + if (kPropertyIDInfos[i].PropID == propID) + return i; + return -1; +} +*/ + +// char *g_Titles[] = { "a", "f", "v" }; +/* +static void SmartAddToString(AString &destString, const char *srcString) +{ + if (!destString.IsEmpty()) + destString += ','; + destString += srcString; +} +*/ + +/* +void CPlugin::AddColumn(PROPID propID) +{ + int index = FindPropertyInfo(propID); + if (index >= 0) + { + for (int i = 0; i < m_ProxyHandler->m_InternalProperties.Size(); i++) + { + const CArchiveItemProperty &aHandlerProperty = m_ProxyHandler->m_InternalProperties[i]; + if (aHandlerProperty.ID == propID) + break; + } + if (i == m_ProxyHandler->m_InternalProperties.Size()) + return; + + const CPropertyIDInfo &propertyIDInfo = kPropertyIDInfos[index]; + SmartAddToString(PanelModeColumnTypes, propertyIDInfo.FarID); + char tmp[32]; + itoa(propertyIDInfo.Width, tmp, 10); + SmartAddToString(PanelModeColumnWidths, tmp); + return; + } +} +*/ + +static AString GetNameOfProp(PROPID propID, const wchar_t *name) +{ + int farID = FindPropNameID(propID); + if (farID >= 0) + return (AString)g_StartupInfo.GetMsgString(farID); + if (name) + return UnicodeStringToMultiByte(name, CP_OEMCP); + char s[16]; + ConvertUInt32ToString(propID, s); + return (AString)s; +} + +static AString GetNameOfProp2(PROPID propID, const wchar_t *name) +{ + AString s (GetNameOfProp(propID, name)); + if (s.Len() > (kInfoPanelLineSize - 1)) + s.DeleteFrom(kInfoPanelLineSize - 1); + return s; +} + +static AString ConvertSizeToString(UInt64 value) +{ + char s[32]; + ConvertUInt64ToString(value, s); + unsigned i = MyStringLen(s); + unsigned pos = Z7_ARRAY_SIZE(s); + s[--pos] = 0; + while (i > 3) + { + s[--pos] = s[--i]; + s[--pos] = s[--i]; + s[--pos] = s[--i]; + s[--pos] = ' '; + } + while (i > 0) + s[--pos] = s[--i]; + return (AString)(s + pos); +} + +static AString PropToString(const NCOM::CPropVariant &prop, PROPID propID) +{ + if (prop.vt == VT_BSTR) + { + AString s (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP)); + s.Replace((char)0xA, ' '); + s.Replace((char)0xD, ' '); + return s; + } + if (prop.vt == VT_BOOL) + { + int messageID = VARIANT_BOOLToBool(prop.boolVal) ? + NMessageID::kYes : NMessageID::kNo; + return (AString)g_StartupInfo.GetMsgString(messageID); + } + if (prop.vt != VT_EMPTY) + { + if ((prop.vt == VT_UI8 || prop.vt == VT_UI4) && ( + propID == kpidSize || + propID == kpidPackSize || + propID == kpidNumSubDirs || + propID == kpidNumSubFiles || + propID == kpidNumBlocks || + propID == kpidPhySize || + propID == kpidHeadersSize || + propID == kpidClusterSize || + propID == kpidUnpackSize + )) + { + UInt64 v = 0; + ConvertPropVariantToUInt64(prop, v); + return ConvertSizeToString(v); + } + { + char sz[64]; + ConvertPropertyToShortString2(sz, prop, propID); + return (AString)sz; + } + } + return AString(); +} + +static AString PropToString2(const NCOM::CPropVariant &prop, PROPID propID) +{ + AString s (PropToString(prop, propID)); + if (s.Len() > (kInfoPanelLineSize - 1)) + s.DeleteFrom(kInfoPanelLineSize - 1); + return s; +} + +static void AddPropertyString(InfoPanelLine *lines, unsigned &numItems, PROPID propID, const wchar_t *name, + const NCOM::CPropVariant &prop) +{ + if (prop.vt != VT_EMPTY) + { + AString val (PropToString2(prop, propID)); + if (!val.IsEmpty()) + { + InfoPanelLine &item = lines[numItems++]; + COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name)); + COPY_STR_LIMITED(item.Data, val); + } + } +} + +static void InsertSeparator(InfoPanelLine *lines, unsigned &numItems) +{ + if (numItems < kNumInfoLinesMax) + { + InfoPanelLine &item = lines[numItems++]; + *item.Text = 0; + *item.Data = 0; + item.Separator = TRUE; + } +} + +void CPlugin::GetOpenPluginInfo(struct OpenPluginInfo *info) +{ + info->StructSize = sizeof(*info); + info->Flags = OPIF_USEFILTER | OPIF_USESORTGROUPS | OPIF_USEHIGHLIGHTING | + OPIF_ADDDOTS | OPIF_COMPAREFATTIME; + + COPY_STR_LIMITED(m_FileNameBuffer, UnicodeStringToMultiByte(fs2us(m_FileName), CP_OEMCP)); + info->HostFile = m_FileNameBuffer; // test it it is not static + + COPY_STR_LIMITED(m_CurrentDirBuffer, UnicodeStringToMultiByte(m_CurrentDir, CP_OEMCP)); + info->CurDir = m_CurrentDirBuffer; + + info->Format = kPluginFormatName; + + { + UString name; + { + FString dirPrefix, fileName; + GetFullPathAndSplit(m_FileName, dirPrefix, fileName); + name = fs2us(fileName); + } + + m_PannelTitle = ' '; + m_PannelTitle += _archiveTypeName; + m_PannelTitle.Add_Colon(); + m_PannelTitle += name; + m_PannelTitle.Add_Space(); + if (!m_CurrentDir.IsEmpty()) + { + // m_PannelTitle += '\\'; + m_PannelTitle += m_CurrentDir; + } + + COPY_STR_LIMITED(m_PannelTitleBuffer, UnicodeStringToMultiByte(m_PannelTitle, CP_OEMCP)); + info->PanelTitle = m_PannelTitleBuffer; + + } + + memset(m_InfoLines, 0, sizeof(m_InfoLines)); + m_InfoLines[0].Text[0] = 0; + m_InfoLines[0].Separator = TRUE; + + MyStringCopy(m_InfoLines[1].Text, g_StartupInfo.GetMsgString(NMessageID::kArchiveType)); + MyStringCopy(m_InfoLines[1].Data, (const char *)UnicodeStringToMultiByte(_archiveTypeName, CP_OEMCP)); + + unsigned numItems = 2; + + { + CMyComPtr folderProperties; + _folder.QueryInterface(IID_IFolderProperties, &folderProperties); + if (folderProperties) + { + UInt32 numProps; + if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK) + { + for (UInt32 i = 0; i < numProps && numItems < kNumInfoLinesMax; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK) + continue; + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(propID, &prop) != S_OK || prop.vt == VT_EMPTY) + continue; + + InfoPanelLine &item = m_InfoLines[numItems++]; + COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name)); + COPY_STR_LIMITED(item.Data, PropToString2(prop, propID)); + } + } + } + } + + /* + if (numItems < kNumInfoLinesMax) + { + InsertSeparator(m_InfoLines, numItems); + } + */ + + { + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (getFolderArcProps) + { + CMyComPtr getProps; + getFolderArcProps->GetFolderArcProps(&getProps); + if (getProps) + { + UInt32 numLevels; + if (getProps->GetArcNumLevels(&numLevels) != S_OK) + numLevels = 0; + for (UInt32 level2 = 0; level2 < numLevels; level2++) + { + { + UInt32 level = numLevels - 1 - level2; + UInt32 numProps; + if (getProps->GetArcNumProps(level, &numProps) == S_OK) + { + InsertSeparator(m_InfoLines, numItems); + for (Int32 i = -3; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + switch (i) + { + case -3: propID = kpidPath; break; + case -2: propID = kpidType; break; + case -1: propID = kpidError; break; + default: + if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK) + continue; + } + NCOM::CPropVariant prop; + if (getProps->GetArcProp(level, propID, &prop) != S_OK) + continue; + AddPropertyString(m_InfoLines, numItems, propID, name, prop); + } + } + } + if (level2 != numLevels - 1) + { + UInt32 level = numLevels - 1 - level2; + UInt32 numProps; + if (getProps->GetArcNumProps2(level, &numProps) == S_OK) + { + InsertSeparator(m_InfoLines, numItems); + for (Int32 i = 0; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + if (getProps->GetArcPropInfo2(level, (UInt32)i, &name, &propID, &vt) != S_OK) + continue; + NCOM::CPropVariant prop; + if (getProps->GetArcProp2(level, propID, &prop) != S_OK) + continue; + AddPropertyString(m_InfoLines, numItems, propID, name, prop); + } + } + } + } + } + } + } + + //m_InfoLines[1].Separator = 0; + + info->InfoLines = m_InfoLines; + info->InfoLinesNumber = (int)numItems; + + + info->DescrFiles = NULL; + info->DescrFilesNumber = 0; + + PanelModeColumnTypes.Empty(); + PanelModeColumnWidths.Empty(); + + /* + AddColumn(kpidName); + AddColumn(kpidSize); + AddColumn(kpidPackSize); + AddColumn(kpidMTime); + AddColumn(kpidCTime); + AddColumn(kpidATime); + AddColumn(kpidAttrib); + + _panelMode.ColumnTypes = (char *)(const char *)PanelModeColumnTypes; + _panelMode.ColumnWidths = (char *)(const char *)PanelModeColumnWidths; + _panelMode.ColumnTitles = NULL; + _panelMode.FullScreen = TRUE; + _panelMode.DetailedStatus = FALSE; + _panelMode.AlignExtensions = FALSE; + _panelMode.CaseConversion = FALSE; + _panelMode.StatusColumnTypes = "N"; + _panelMode.StatusColumnWidths = "0"; + _panelMode.Reserved[0] = 0; + _panelMode.Reserved[1] = 0; + + info->PanelModesArray = &_panelMode; + info->PanelModesNumber = 1; + */ + + info->PanelModesArray = NULL; + info->PanelModesNumber = 0; + + info->StartPanelMode = 0; + info->StartSortMode = 0; + info->KeyBar = NULL; + info->ShortcutData = NULL; +} + +struct CArchiveItemProperty +{ + AString Name; + PROPID ID; + VARTYPE Type; +}; + +static inline char GetHex_A_minus10(unsigned v, unsigned a10) +{ + return (char)(v < 10 ? v + '0' : v + a10); +} + +HRESULT CPlugin::ShowAttributesWindow() +{ + PluginPanelItem pluginPanelItem; + if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem)) + return S_FALSE; + if (strcmp(pluginPanelItem.FindData.cFileName, "..") == 0 && + NFind::NAttributes::IsDir(pluginPanelItem.FindData.dwFileAttributes)) + return S_FALSE; + const UInt32 itemIndex = (UInt32)pluginPanelItem.UserData; + + CObjectVector properties; + UInt32 numProps; + RINOK(_folder->GetNumberOfProperties(&numProps)) + unsigned i; + for (i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + RINOK(_folder->GetPropertyInfo(i, &name, &propID, &vt)) + CArchiveItemProperty prop; + prop.Type = vt; + prop.ID = propID; + if (prop.ID == kpidPath) + prop.ID = kpidName; + prop.Name = GetNameOfProp(propID, name); + properties.Add(prop); + } + + int size = 2; + CRecordVector initDialogItems; + + int xSize = 70; + { + const CInitDialogItem idi = + { DI_DOUBLEBOX, 3, 1, xSize - 4, size - 2, false, false, 0, false, NMessageID::kProperties, NULL, NULL }; + initDialogItems.Add(idi); + } + + AStringVector values; + + const int kStartY = 3; + + for (i = 0; i < properties.Size(); i++) + { + const CArchiveItemProperty &property = properties[i]; + + const int startY = kStartY + (int)values.Size(); + + { + CInitDialogItem idi = + { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL }; + idi.DataMessageId = FindPropNameID(property.ID); + if (idi.DataMessageId < 0) + idi.DataString = property.Name; + initDialogItems.Add(idi); + } + + NCOM::CPropVariant prop; + RINOK(_folder->GetProperty(itemIndex, property.ID, &prop)) + values.Add(PropToString(prop, property.ID)); + + { + const CInitDialogItem idi = + { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL }; + initDialogItems.Add(idi); + } + } + + CMyComPtr _folderRawProps; + _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps); + + CObjectVector properties2; + + if (_folderRawProps) + { + _folderRawProps->GetNumRawProps(&numProps); + + for (i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK) + continue; + CArchiveItemProperty prop; + prop.Type = VT_EMPTY; + prop.ID = propID; + if (prop.ID == kpidPath) + prop.ID = kpidName; + prop.Name = GetNameOfProp(propID, name); + properties2.Add(prop); + } + + for (i = 0; i < properties2.Size(); i++) + { + const CArchiveItemProperty &property = properties2[i]; + CMyComBSTR name; + + const void *data; + UInt32 dataSize; + UInt32 propType; + if (_folderRawProps->GetRawProp(itemIndex, property.ID, &data, &dataSize, &propType) != S_OK) + continue; + + if (dataSize != 0) + { + AString s; + if (property.ID == kpidNtSecure) + ConvertNtSecureToString((const Byte *)data, dataSize, s); + else + { + const UInt32 kMaxDataSize = 64; + if (dataSize > kMaxDataSize) + { + s += "data:"; + s.Add_UInt32(dataSize); + } + else + { + const unsigned a = dataSize <= 8 + && (property.ID == kpidCRC || property.ID == kpidChecksum) + ? 'A' - 10 : 'a' - 10; + for (UInt32 k = 0; k < dataSize; k++) + { + const unsigned b = ((const Byte *)data)[k]; + s += GetHex_A_minus10(b >> 4, a); + s += GetHex_A_minus10(b & 15, a); + } + } + } + + const int startY = kStartY + (int)values.Size(); + + { + CInitDialogItem idi = + { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL }; + idi.DataMessageId = FindPropNameID(property.ID); + if (idi.DataMessageId < 0) + idi.DataString = property.Name; + initDialogItems.Add(idi); + } + + values.Add(s); + + { + const CInitDialogItem idi = + { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL }; + initDialogItems.Add(idi); + } + } + } + } + + const unsigned numLines = values.Size(); + for (i = 0; i < numLines; i++) + { + CInitDialogItem &idi = initDialogItems[1 + i * 2 + 1]; + idi.DataString = values[i]; + } + + const unsigned numDialogItems = initDialogItems.Size(); + + CObjArray dialogItems(numDialogItems); + g_StartupInfo.InitDialogItems(initDialogItems.ConstData(), dialogItems, numDialogItems); + + unsigned maxLen = 0; + + for (i = 0; i < numLines; i++) + { + FarDialogItem &dialogItem = dialogItems[1 + i * 2]; + unsigned len = (unsigned)strlen(dialogItem.Data); + if (len > maxLen) + maxLen = len; + } + + unsigned maxLen2 = 0; + const unsigned kSpace = 10; + + for (i = 0; i < numLines; i++) + { + FarDialogItem &dialogItem = dialogItems[1 + i * 2 + 1]; + const unsigned len = (unsigned)strlen(dialogItem.Data); + if (len > maxLen2) + maxLen2 = len; + dialogItem.X1 = (int)(maxLen + kSpace); + } + + size = (int)numLines + 6; + xSize = (int)(maxLen + kSpace + maxLen2 + 5); + FarDialogItem &firstDialogItem = dialogItems[0]; + firstDialogItem.Y2 = size - 2; + firstDialogItem.X2 = xSize - 4; + + /* int askCode = */ g_StartupInfo.ShowDialog(xSize, size, NULL, dialogItems, numDialogItems); + return S_OK; +} + +int CPlugin::ProcessKey(int key, unsigned controlState) +{ + if (key == VK_F7 && controlState == 0) + { + CreateFolder(); + return TRUE; + } + + if (controlState == PKF_CONTROL && key == 'A') + { + HRESULT result = ShowAttributesWindow(); + if (result == S_OK) + return TRUE; + if (result == S_FALSE) + return FALSE; + throw "Error"; + } + + if ((controlState & PKF_ALT) != 0 && key == VK_F6) + { + FString folderPath; + if (!GetOnlyDirPrefix(m_FileName, folderPath)) + return FALSE; + PanelInfo panelInfo; + g_StartupInfo.ControlGetActivePanelInfo(panelInfo); + GetFilesReal(panelInfo.SelectedItems, + (unsigned)panelInfo.SelectedItemsNumber, FALSE, + UnicodeStringToMultiByte(fs2us(folderPath), CP_OEMCP), OPM_SILENT, true); + g_StartupInfo.Control(this, FCTL_UPDATEPANEL, NULL); + g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL); + g_StartupInfo.Control(this, FCTL_UPDATEANOTHERPANEL, NULL); + g_StartupInfo.Control(this, FCTL_REDRAWANOTHERPANEL, NULL); + return TRUE; + } + + return FALSE; +} diff --git a/CPP/7zip/UI/Far/Plugin.h b/CPP/7zip/UI/Far/Plugin.h index 5619aef31..84f6bed3f 100644 --- a/CPP/7zip/UI/Far/Plugin.h +++ b/CPP/7zip/UI/Far/Plugin.h @@ -1,94 +1,94 @@ -// 7zip/Far/Plugin.h - -#ifndef ZIP7_INC_7ZIP_FAR_PLUGIN_H -#define ZIP7_INC_7ZIP_FAR_PLUGIN_H - -#include "../../../Common/MyCom.h" - -// #include "../../../Windows/COM.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/PropVariant.h" - -#include "../Common/WorkDir.h" - -#include "../Agent/Agent.h" - -#include "FarUtils.h" - -const UInt32 kNumInfoLinesMax = 64; - -class CPlugin -{ - CAgent *_agent; - CMyComPtr m_ArchiveHandler; - CMyComPtr _folder; - - // NWindows::NCOM::CComInitializer m_ComInitializer; - UString m_CurrentDir; - - UString m_PannelTitle; - FString m_FileName; - NWindows::NFile::NFind::CFileInfo m_FileInfo; - - UString _archiveTypeName; - - InfoPanelLine m_InfoLines[kNumInfoLinesMax]; - - char m_FileNameBuffer[1024]; - char m_CurrentDirBuffer[1024]; - char m_PannelTitleBuffer[1024]; - - AString PanelModeColumnTypes; - AString PanelModeColumnWidths; - // PanelMode _panelMode; - void AddColumn(PROPID aPropID); - - void EnterToDirectory(const UString &dirName); - void GetPathParts(UStringVector &pathParts); - void SetCurrentDirVar(); - // HRESULT AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector); - -public: - - bool PasswordIsDefined; - UString Password; - - CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName); - ~CPlugin(); - - void ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex); - - int GetFindData(PluginPanelItem **panelItems,int *itemsNumber,int opMode); - void FreeFindData(PluginPanelItem *panelItem,int ItemsNumber); - int SetDirectory(const char *aszDir, int opMode); - void GetOpenPluginInfo(struct OpenPluginInfo *info); - int DeleteFiles(PluginPanelItem *panelItems, unsigned itemsNumber, int opMode); - - HRESULT ExtractFiles( - bool decompressAllItems, - const UInt32 *indices, - UInt32 numIndices, - bool silent, - NExtract::NPathMode::EEnum pathMode, - NExtract::NOverwriteMode::EEnum overwriteMode, - const UString &destPath, - bool passwordIsDefined, const UString &password); - - NFar::NFileOperationReturnCode::EEnum GetFiles(struct PluginPanelItem *panelItem, unsigned itemsNumber, - int move, char *destPath, int opMode); - - NFar::NFileOperationReturnCode::EEnum GetFilesReal(struct PluginPanelItem *panelItems, - unsigned itemsNumber, int move, const char *_aDestPath, int opMode, bool showBox); - - NFar::NFileOperationReturnCode::EEnum PutFiles(struct PluginPanelItem *panelItems, unsigned itemsNumber, - int move, int opMode); - HRESULT CreateFolder(); - - HRESULT ShowAttributesWindow(); - - int ProcessKey(int key, unsigned controlState); -}; - -HRESULT CompressFiles(const CObjectVector &pluginPanelItems); - -#endif +// 7zip/Far/Plugin.h + +#ifndef ZIP7_INC_7ZIP_FAR_PLUGIN_H +#define ZIP7_INC_7ZIP_FAR_PLUGIN_H + +#include "../../../Common/MyCom.h" + +// #include "../../../Windows/COM.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/PropVariant.h" + +#include "../Common/WorkDir.h" + +#include "../Agent/Agent.h" + +#include "FarUtils.h" + +const UInt32 kNumInfoLinesMax = 64; + +class CPlugin +{ + CAgent *_agent; + CMyComPtr m_ArchiveHandler; + CMyComPtr _folder; + + // NWindows::NCOM::CComInitializer m_ComInitializer; + UString m_CurrentDir; + + UString m_PannelTitle; + FString m_FileName; + NWindows::NFile::NFind::CFileInfo m_FileInfo; + + UString _archiveTypeName; + + InfoPanelLine m_InfoLines[kNumInfoLinesMax]; + + char m_FileNameBuffer[1024]; + char m_CurrentDirBuffer[1024]; + char m_PannelTitleBuffer[1024]; + + AString PanelModeColumnTypes; + AString PanelModeColumnWidths; + // PanelMode _panelMode; + void AddColumn(PROPID aPropID); + + void EnterToDirectory(const UString &dirName); + void GetPathParts(UStringVector &pathParts); + void SetCurrentDirVar(); + // HRESULT AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector); + +public: + + bool PasswordIsDefined; + UString Password; + + CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName); + ~CPlugin(); + + void ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex); + + int GetFindData(PluginPanelItem **panelItems,int *itemsNumber,int opMode); + void FreeFindData(PluginPanelItem *panelItem,int ItemsNumber); + int SetDirectory(const char *aszDir, int opMode); + void GetOpenPluginInfo(struct OpenPluginInfo *info); + int DeleteFiles(PluginPanelItem *panelItems, unsigned itemsNumber, int opMode); + + HRESULT ExtractFiles( + bool decompressAllItems, + const UInt32 *indices, + UInt32 numIndices, + bool silent, + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode, + const UString &destPath, + bool passwordIsDefined, const UString &password); + + NFar::NFileOperationReturnCode::EEnum GetFiles(struct PluginPanelItem *panelItem, unsigned itemsNumber, + int move, char *destPath, int opMode); + + NFar::NFileOperationReturnCode::EEnum GetFilesReal(struct PluginPanelItem *panelItems, + unsigned itemsNumber, int move, const char *_aDestPath, int opMode, bool showBox); + + NFar::NFileOperationReturnCode::EEnum PutFiles(struct PluginPanelItem *panelItems, unsigned itemsNumber, + int move, int opMode); + HRESULT CreateFolder(); + + HRESULT ShowAttributesWindow(); + + int ProcessKey(int key, unsigned controlState); +}; + +HRESULT CompressFiles(const CObjectVector &pluginPanelItems); + +#endif diff --git a/CPP/7zip/UI/Far/PluginCommon.cpp b/CPP/7zip/UI/Far/PluginCommon.cpp index d50b2e03a..e1d445827 100644 --- a/CPP/7zip/UI/Far/PluginCommon.cpp +++ b/CPP/7zip/UI/Far/PluginCommon.cpp @@ -1,50 +1,50 @@ -// SevenZip/Plugin.cpp - -#include "StdAfx.h" - -#include "Plugin.h" - -/* -void CPlugin::AddRealIndexOfFile(const CArchiveFolderItem &aFolder, - int anIndexInVector, vector &aRealIndexes) -{ - const CArchiveFolderFileItem &anItem = aFolder.m_FileSubItems[anIndexInVector]; - int aHandlerItemIndex = m_ProxyHandler->GetHandlerItemIndex(anItem.m_Properties); - if (aHandlerItemIndex < 0) - throw "error"; - aRealIndexes.push_back(aHandlerItemIndex); -} - -void CPlugin::AddRealIndexes(const CArchiveFolderItem &anItem, - vector &aRealIndexes) -{ - int aHandlerItemIndex = m_ProxyHandler->GetHandlerItemIndex(anItem.m_Properties); - if (aHandlerItemIndex >= 0) // test -1 value - aRealIndexes.push_back(aHandlerItemIndex); - for (int i = 0; i < anItem.m_DirSubItems.Size(); i++) - AddRealIndexes(anItem.m_DirSubItems[i], aRealIndexes); - for (i = 0; i < anItem.m_FileSubItems.Size(); i++) - AddRealIndexOfFile(anItem, i , aRealIndexes); -} - - -void CPlugin::GetRealIndexes(PluginPanelItem *aPanelItems, int anItemsNumber, - vector &aRealIndexes) -{ - aRealIndexes.clear(); - for (int i = 0; i < anItemsNumber; i++) - { - int anIndex = aPanelItems[i].UserData; - if (anIndex < m_FolderItem->m_DirSubItems.Size()) - { - const CArchiveFolderItem &anItem = m_FolderItem->m_DirSubItems[anIndex]; - AddRealIndexes(anItem, aRealIndexes); - } - else - AddRealIndexOfFile(*m_FolderItem, anIndex - m_FolderItem->m_DirSubItems.Size(), - aRealIndexes); - } - sort(aRealIndexes.begin(), aRealIndexes.end()); -} - -*/ +// SevenZip/Plugin.cpp + +#include "StdAfx.h" + +#include "Plugin.h" + +/* +void CPlugin::AddRealIndexOfFile(const CArchiveFolderItem &aFolder, + int anIndexInVector, vector &aRealIndexes) +{ + const CArchiveFolderFileItem &anItem = aFolder.m_FileSubItems[anIndexInVector]; + int aHandlerItemIndex = m_ProxyHandler->GetHandlerItemIndex(anItem.m_Properties); + if (aHandlerItemIndex < 0) + throw "error"; + aRealIndexes.push_back(aHandlerItemIndex); +} + +void CPlugin::AddRealIndexes(const CArchiveFolderItem &anItem, + vector &aRealIndexes) +{ + int aHandlerItemIndex = m_ProxyHandler->GetHandlerItemIndex(anItem.m_Properties); + if (aHandlerItemIndex >= 0) // test -1 value + aRealIndexes.push_back(aHandlerItemIndex); + for (int i = 0; i < anItem.m_DirSubItems.Size(); i++) + AddRealIndexes(anItem.m_DirSubItems[i], aRealIndexes); + for (i = 0; i < anItem.m_FileSubItems.Size(); i++) + AddRealIndexOfFile(anItem, i , aRealIndexes); +} + + +void CPlugin::GetRealIndexes(PluginPanelItem *aPanelItems, int anItemsNumber, + vector &aRealIndexes) +{ + aRealIndexes.clear(); + for (int i = 0; i < anItemsNumber; i++) + { + int anIndex = aPanelItems[i].UserData; + if (anIndex < m_FolderItem->m_DirSubItems.Size()) + { + const CArchiveFolderItem &anItem = m_FolderItem->m_DirSubItems[anIndex]; + AddRealIndexes(anItem, aRealIndexes); + } + else + AddRealIndexOfFile(*m_FolderItem, anIndex - m_FolderItem->m_DirSubItems.Size(), + aRealIndexes); + } + sort(aRealIndexes.begin(), aRealIndexes.end()); +} + +*/ diff --git a/CPP/7zip/UI/Far/PluginDelete.cpp b/CPP/7zip/UI/Far/PluginDelete.cpp index 03b24e30b..fdade1a34 100644 --- a/CPP/7zip/UI/Far/PluginDelete.cpp +++ b/CPP/7zip/UI/Far/PluginDelete.cpp @@ -1,144 +1,144 @@ -// PluginDelete.cpp - -#include "StdAfx.h" - -#include - -#include "../../../Common/StringConvert.h" -#include "FarUtils.h" - -#include "Messages.h" -#include "Plugin.h" -#include "UpdateCallbackFar.h" - -using namespace NFar; - -int CPlugin::DeleteFiles(PluginPanelItem *panelItems, unsigned numItems, int opMode) -{ - if (numItems == 0) - return FALSE; - if (_agent->IsThere_ReadOnlyArc()) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return FALSE; - } - if ((opMode & OPM_SILENT) == 0) - { - const char *msgItems[]= - { - g_StartupInfo.GetMsgString(NMessageID::kDeleteTitle), - g_StartupInfo.GetMsgString(NMessageID::kDeleteFiles), - g_StartupInfo.GetMsgString(NMessageID::kDeleteDelete), - g_StartupInfo.GetMsgString(NMessageID::kDeleteCancel) - }; - - // char msg[1024]; - AString str1; - - if (numItems == 1) - { - str1 = g_StartupInfo.GetMsgString(NMessageID::kDeleteFile); - AString name (panelItems[0].FindData.cFileName); - const unsigned kSizeLimit = 48; - if (name.Len() > kSizeLimit) - { - UString s = MultiByteToUnicodeString(name, CP_OEMCP); - ReduceString(s, kSizeLimit); - name = UnicodeStringToMultiByte(s, CP_OEMCP); - } - str1.Replace(AString ("%.40s"), name); - msgItems[1] = str1; - // sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName); - // msgItems[2] = msg; - } - else if (numItems > 1) - { - str1 = g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles); - { - AString n; - n.Add_UInt32(numItems); - str1.Replace(AString ("%d"), n); - } - msgItems[1] = str1; - // sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems); - // msgItems[1] = msg; - } - if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 2) != 0) - return (FALSE); - } - - CScreenRestorer screenRestorer; - CProgressBox progressBox; - CProgressBox *progressBoxPointer = NULL; - if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) - { - screenRestorer.Save(); - - progressBoxPointer = &progressBox; - progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kDeleting)); - } - - /* - CWorkDirTempFile tempFile; - if (tempFile.CreateTempFile(m_FileName) != S_OK) - return FALSE; - */ - - CObjArray indices(numItems); - unsigned i; - for (i = 0; i < numItems; i++) - indices[i] = (UInt32)panelItems[i].UserData; - - /* - UStringVector pathVector; - GetPathParts(pathVector); - - CMyComPtr outArchive; - HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive); - if (result != S_OK) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return FALSE; - } - */ - - CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; - CMyComPtr updateCallback(updateCallbackSpec); - - updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); - updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; - updateCallbackSpec->Password = Password; - - /* - outArchive->SetFolder(_folder); - result = outArchive->DeleteItems(tempFile.OutStream, indices, numItems, updateCallback); - updateCallback.Release(); - outArchive.Release(); - - if (result == S_OK) - { - result = AfterUpdate(tempFile, pathVector); - } - */ - - HRESULT result; - { - CMyComPtr folderOperations; - result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations); - if (folderOperations) - result = folderOperations->Delete(indices, numItems, updateCallback); - else if (result != S_OK) - result = E_FAIL; - } - - if (result != S_OK) - { - ShowSysErrorMessage(result); - return FALSE; - } - - SetCurrentDirVar(); - return TRUE; -} +// PluginDelete.cpp + +#include "StdAfx.h" + +#include + +#include "../../../Common/StringConvert.h" +#include "FarUtils.h" + +#include "Messages.h" +#include "Plugin.h" +#include "UpdateCallbackFar.h" + +using namespace NFar; + +int CPlugin::DeleteFiles(PluginPanelItem *panelItems, unsigned numItems, int opMode) +{ + if (numItems == 0) + return FALSE; + if (_agent->IsThere_ReadOnlyArc()) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return FALSE; + } + if ((opMode & OPM_SILENT) == 0) + { + const char *msgItems[]= + { + g_StartupInfo.GetMsgString(NMessageID::kDeleteTitle), + g_StartupInfo.GetMsgString(NMessageID::kDeleteFiles), + g_StartupInfo.GetMsgString(NMessageID::kDeleteDelete), + g_StartupInfo.GetMsgString(NMessageID::kDeleteCancel) + }; + + // char msg[1024]; + AString str1; + + if (numItems == 1) + { + str1 = g_StartupInfo.GetMsgString(NMessageID::kDeleteFile); + AString name (panelItems[0].FindData.cFileName); + const unsigned kSizeLimit = 48; + if (name.Len() > kSizeLimit) + { + UString s = MultiByteToUnicodeString(name, CP_OEMCP); + ReduceString(s, kSizeLimit); + name = UnicodeStringToMultiByte(s, CP_OEMCP); + } + str1.Replace(AString ("%.40s"), name); + msgItems[1] = str1; + // sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName); + // msgItems[2] = msg; + } + else if (numItems > 1) + { + str1 = g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles); + { + AString n; + n.Add_UInt32(numItems); + str1.Replace(AString ("%d"), n); + } + msgItems[1] = str1; + // sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems); + // msgItems[1] = msg; + } + if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 2) != 0) + return (FALSE); + } + + CScreenRestorer screenRestorer; + CProgressBox progressBox; + CProgressBox *progressBoxPointer = NULL; + if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) + { + screenRestorer.Save(); + + progressBoxPointer = &progressBox; + progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kDeleting)); + } + + /* + CWorkDirTempFile tempFile; + if (tempFile.CreateTempFile(m_FileName) != S_OK) + return FALSE; + */ + + CObjArray indices(numItems); + unsigned i; + for (i = 0; i < numItems; i++) + indices[i] = (UInt32)panelItems[i].UserData; + + /* + UStringVector pathVector; + GetPathParts(pathVector); + + CMyComPtr outArchive; + HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive); + if (result != S_OK) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return FALSE; + } + */ + + CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; + CMyComPtr updateCallback(updateCallbackSpec); + + updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); + updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; + updateCallbackSpec->Password = Password; + + /* + outArchive->SetFolder(_folder); + result = outArchive->DeleteItems(tempFile.OutStream, indices, numItems, updateCallback); + updateCallback.Release(); + outArchive.Release(); + + if (result == S_OK) + { + result = AfterUpdate(tempFile, pathVector); + } + */ + + HRESULT result; + { + CMyComPtr folderOperations; + result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations); + if (folderOperations) + result = folderOperations->Delete(indices, numItems, updateCallback); + else if (result != S_OK) + result = E_FAIL; + } + + if (result != S_OK) + { + ShowSysErrorMessage(result); + return FALSE; + } + + SetCurrentDirVar(); + return TRUE; +} diff --git a/CPP/7zip/UI/Far/PluginRead.cpp b/CPP/7zip/UI/Far/PluginRead.cpp index 5f0cddd11..7e81dddbf 100644 --- a/CPP/7zip/UI/Far/PluginRead.cpp +++ b/CPP/7zip/UI/Far/PluginRead.cpp @@ -1,301 +1,301 @@ -// PluginRead.cpp - -#include "StdAfx.h" - -#include "Plugin.h" - -#include "Messages.h" - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileDir.h" - -#include "../Common/ZipRegistry.h" - -#include "ExtractEngine.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NFar; - -static const char * const kHelpTopicExtrFromSevenZip = "Extract"; - -static const char kDirDelimiter = CHAR_PATH_SEPARATOR; - -static const char * const kExractPathHistoryName = "7-ZipExtractPath"; - -HRESULT CPlugin::ExtractFiles( - bool decompressAllItems, - const UInt32 *indices, - UInt32 numIndices, - bool silent, - NExtract::NPathMode::EEnum pathMode, - NExtract::NOverwriteMode::EEnum overwriteMode, - const UString &destPath, - bool passwordIsDefined, const UString &password) -{ - if (_agent->_isHashHandler) - { - g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); - return NFileOperationReturnCode::kError; - } - - CScreenRestorer screenRestorer; - CProgressBox progressBox; - CProgressBox *progressBoxPointer = NULL; - if (!silent) - { - screenRestorer.Save(); - - progressBoxPointer = &progressBox; - progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kExtracting)); - } - - - CExtractCallbackImp *extractCallbackSpec = new CExtractCallbackImp; - CMyComPtr extractCallback(extractCallbackSpec); - - extractCallbackSpec->Init( - CP_OEMCP, - progressBoxPointer, - /* - GetDefaultName(m_FileName, m_ArchiverInfo.Extension), - m_FileInfo.MTime, m_FileInfo.Attributes, - */ - passwordIsDefined, password); - - if (decompressAllItems) - return m_ArchiveHandler->Extract(pathMode, overwriteMode, - destPath, BoolToInt(false), extractCallback); - else - { - CMyComPtr archiveFolder; - _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder); - - return archiveFolder->Extract(indices, numIndices, - BoolToInt(true), // includeAltStreams - BoolToInt(false), // replaceAltStreamChars - pathMode, overwriteMode, - destPath, BoolToInt(false), extractCallback); - } -} - -NFileOperationReturnCode::EEnum CPlugin::GetFiles(struct PluginPanelItem *panelItems, - unsigned itemsNumber, int move, char *destPath, int opMode) -{ - return GetFilesReal(panelItems, itemsNumber, move, - destPath, opMode, (opMode & OPM_SILENT) == 0); -} - -NFileOperationReturnCode::EEnum CPlugin::GetFilesReal(struct PluginPanelItem *panelItems, - unsigned itemsNumber, int move, const char *destPathLoc, int opMode, bool showBox) -{ - if (move != 0) - { - g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); - return NFileOperationReturnCode::kError; - } - - AString destPath (destPathLoc); - UString destPathU = GetUnicodeString(destPath, CP_OEMCP); - NName::NormalizeDirPathPrefix(destPathU); - destPath = UnicodeStringToMultiByte(destPathU, CP_OEMCP); - - // bool extractSelectedFiles = true; - - NExtract::CInfo extractionInfo; - extractionInfo.PathMode = NExtract::NPathMode::kCurPaths; - extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; - - const bool silent = (opMode & OPM_SILENT) != 0; - bool decompressAllItems = false; - UString password = Password; - bool passwordIsDefined = PasswordIsDefined; - - if (!silent) - { - const int kPathIndex = 2; - - extractionInfo.Load(); - - const int kPathModeRadioIndex = 4; - const int kOverwriteModeRadioIndex = kPathModeRadioIndex + 4; - const int kNumOverwriteOptions = 6; - const int kFilesModeIndex = kOverwriteModeRadioIndex + kNumOverwriteOptions; - const int kXSize = 76; - const int kYSize = 19; - const int kPasswordYPos = 12; - - const int kXMid = kXSize / 2; - - AString oemPassword (UnicodeStringToMultiByte(password, CP_OEMCP)); - - struct CInitDialogItem initItems[]={ - { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kExtractTitle, NULL, NULL }, - { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kExtractTo, NULL, NULL }, - - { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, kExractPathHistoryName}, - // { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, 0, false, -1, destPath, NULL}, - - { DI_SINGLEBOX, 4, 5, kXMid - 2, 5 + 4, false, false, 0, false, NMessageID::kExtractPathMode, NULL, NULL }, - { DI_RADIOBUTTON, 6, 6, 0, 0, false, - extractionInfo.PathMode == NExtract::NPathMode::kFullPaths, - DIF_GROUP, false, NMessageID::kExtractPathFull, NULL, NULL }, - { DI_RADIOBUTTON, 6, 7, 0, 0, false, - extractionInfo.PathMode == NExtract::NPathMode::kCurPaths, - 0, false, NMessageID::kExtractPathCurrent, NULL, NULL }, - { DI_RADIOBUTTON, 6, 8, 0, 0, false, - extractionInfo.PathMode == NExtract::NPathMode::kNoPaths, - false, 0, NMessageID::kExtractPathNo, NULL, NULL }, - - { DI_SINGLEBOX, kXMid, 5, kXSize - 6, 5 + kNumOverwriteOptions, false, false, 0, false, NMessageID::kExtractOwerwriteMode, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, - extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kAsk, - DIF_GROUP, false, NMessageID::kExtractOwerwriteAsk, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, - extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kOverwrite, - 0, false, NMessageID::kExtractOwerwritePrompt, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, - extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kSkip, - 0, false, NMessageID::kExtractOwerwriteSkip, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 9, 0, 0, false, - extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kRename, - 0, false, NMessageID::kExtractOwerwriteAutoRename, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 10, 0, 0, false, - extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kRenameExisting, - 0, false, NMessageID::kExtractOwerwriteAutoRenameExisting, NULL, NULL }, - - { DI_SINGLEBOX, 4, 10, kXMid- 2, 10 + 3, false, false, 0, false, NMessageID::kExtractFilesMode, NULL, NULL }, - { DI_RADIOBUTTON, 6, 11, 0, 0, false, true, DIF_GROUP, false, NMessageID::kExtractFilesSelected, NULL, NULL }, - { DI_RADIOBUTTON, 6, 12, 0, 0, false, false, 0, false, NMessageID::kExtractFilesAll, NULL, NULL }, - - { DI_SINGLEBOX, kXMid, kPasswordYPos, kXSize - 6, kPasswordYPos + 2, false, false, 0, false, NMessageID::kExtractPassword, NULL, NULL }, - { DI_PSWEDIT, kXMid + 2, kPasswordYPos + 1, kXSize - 8, 12, false, false, 0, false, -1, oemPassword, NULL}, - - { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, - - - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kExtractExtract, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kExtractCancel, NULL, NULL } - }; - - const unsigned kNumDialogItems = Z7_ARRAY_SIZE(initItems); - const unsigned kOkButtonIndex = kNumDialogItems - 2; - const unsigned kPasswordIndex = kNumDialogItems - 4; - - FarDialogItem dialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); - for (;;) - { - int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize, - kHelpTopicExtrFromSevenZip, dialogItems, kNumDialogItems); - if (askCode != kOkButtonIndex) - return NFileOperationReturnCode::kInterruptedByUser; - destPath = dialogItems[kPathIndex].Data; - destPathU = GetUnicodeString(destPath, CP_OEMCP); - destPathU.Trim(); - if (destPathU.IsEmpty()) - { - #ifdef UNDER_CE - destPathU = "\\"; - #else - FString destPathF = us2fs(destPathU); - if (!GetCurrentDir(destPathF)) - throw 318016; - NName::NormalizeDirPathPrefix(destPathF); - destPathU = fs2us(destPathF); - #endif - break; - } - else - { - if (destPathU.Back() == kDirDelimiter) - break; - } - g_StartupInfo.ShowErrorMessage("You must specify directory path"); - } - - if (dialogItems[kPathModeRadioIndex].Selected) - extractionInfo.PathMode = NExtract::NPathMode::kFullPaths; - else if (dialogItems[kPathModeRadioIndex + 1].Selected) - extractionInfo.PathMode = NExtract::NPathMode::kCurPaths; - else if (dialogItems[kPathModeRadioIndex + 2].Selected) - extractionInfo.PathMode = NExtract::NPathMode::kNoPaths; - else - throw 31806; - - if (dialogItems[kOverwriteModeRadioIndex].Selected) - extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kAsk; - else if (dialogItems[kOverwriteModeRadioIndex + 1].Selected) - extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; - else if (dialogItems[kOverwriteModeRadioIndex + 2].Selected) - extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kSkip; - else if (dialogItems[kOverwriteModeRadioIndex + 3].Selected) - extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kRename; - else if (dialogItems[kOverwriteModeRadioIndex + 4].Selected) - extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kRenameExisting; - else - throw 31806; - - if (dialogItems[kFilesModeIndex].Selected) - decompressAllItems = false; - else if (dialogItems[kFilesModeIndex + 1].Selected) - decompressAllItems = true; - else - throw 31806; - - extractionInfo.Save(); - - if (dialogItems[kFilesModeIndex].Selected) - { - // extractSelectedFiles = true; - } - else if (dialogItems[kFilesModeIndex + 1].Selected) - { - // extractSelectedFiles = false; - } - else - throw 31806; - - oemPassword = dialogItems[kPasswordIndex].Data; - password = MultiByteToUnicodeString(oemPassword, CP_OEMCP); - passwordIsDefined = !password.IsEmpty(); - } - - CreateComplexDir(us2fs(destPathU)); - - /* - vector realIndices; - if (!decompressAllItems) - GetRealIndexes(panelItems, itemsNumber, realIndices); - */ - CObjArray indices(itemsNumber); - for (unsigned i = 0; i < itemsNumber; i++) - indices[i] = (UInt32)panelItems[i].UserData; - - const HRESULT result = ExtractFiles(decompressAllItems, indices, itemsNumber, - !showBox, extractionInfo.PathMode, extractionInfo.OverwriteMode, - destPathU, - passwordIsDefined, password); - // HRESULT result = ExtractFiles(decompressAllItems, realIndices, !showBox, - // extractionInfo, destPath, passwordIsDefined, password); - if (result != S_OK) - { - if (result == E_ABORT) - return NFileOperationReturnCode::kInterruptedByUser; - ShowSysErrorMessage(result); - return NFileOperationReturnCode::kError; - } - - // if (move != 0) - // { - // if (DeleteFiles(panelItems, itemsNumber, opMode) == FALSE) - // return NFileOperationReturnCode::kError; - // } - return NFileOperationReturnCode::kSuccess; -} +// PluginRead.cpp + +#include "StdAfx.h" + +#include "Plugin.h" + +#include "Messages.h" + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileDir.h" + +#include "../Common/ZipRegistry.h" + +#include "ExtractEngine.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NFar; + +static const char * const kHelpTopicExtrFromSevenZip = "Extract"; + +static const char kDirDelimiter = CHAR_PATH_SEPARATOR; + +static const char * const kExractPathHistoryName = "7-ZipExtractPath"; + +HRESULT CPlugin::ExtractFiles( + bool decompressAllItems, + const UInt32 *indices, + UInt32 numIndices, + bool silent, + NExtract::NPathMode::EEnum pathMode, + NExtract::NOverwriteMode::EEnum overwriteMode, + const UString &destPath, + bool passwordIsDefined, const UString &password) +{ + if (_agent->_isHashHandler) + { + g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); + return NFileOperationReturnCode::kError; + } + + CScreenRestorer screenRestorer; + CProgressBox progressBox; + CProgressBox *progressBoxPointer = NULL; + if (!silent) + { + screenRestorer.Save(); + + progressBoxPointer = &progressBox; + progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kExtracting)); + } + + + CExtractCallbackImp *extractCallbackSpec = new CExtractCallbackImp; + CMyComPtr extractCallback(extractCallbackSpec); + + extractCallbackSpec->Init( + CP_OEMCP, + progressBoxPointer, + /* + GetDefaultName(m_FileName, m_ArchiverInfo.Extension), + m_FileInfo.MTime, m_FileInfo.Attributes, + */ + passwordIsDefined, password); + + if (decompressAllItems) + return m_ArchiveHandler->Extract(pathMode, overwriteMode, + destPath, BoolToInt(false), extractCallback); + else + { + CMyComPtr archiveFolder; + _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder); + + return archiveFolder->Extract(indices, numIndices, + BoolToInt(true), // includeAltStreams + BoolToInt(false), // replaceAltStreamChars + pathMode, overwriteMode, + destPath, BoolToInt(false), extractCallback); + } +} + +NFileOperationReturnCode::EEnum CPlugin::GetFiles(struct PluginPanelItem *panelItems, + unsigned itemsNumber, int move, char *destPath, int opMode) +{ + return GetFilesReal(panelItems, itemsNumber, move, + destPath, opMode, (opMode & OPM_SILENT) == 0); +} + +NFileOperationReturnCode::EEnum CPlugin::GetFilesReal(struct PluginPanelItem *panelItems, + unsigned itemsNumber, int move, const char *destPathLoc, int opMode, bool showBox) +{ + if (move != 0) + { + g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); + return NFileOperationReturnCode::kError; + } + + AString destPath (destPathLoc); + UString destPathU = GetUnicodeString(destPath, CP_OEMCP); + NName::NormalizeDirPathPrefix(destPathU); + destPath = UnicodeStringToMultiByte(destPathU, CP_OEMCP); + + // bool extractSelectedFiles = true; + + NExtract::CInfo extractionInfo; + extractionInfo.PathMode = NExtract::NPathMode::kCurPaths; + extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; + + const bool silent = (opMode & OPM_SILENT) != 0; + bool decompressAllItems = false; + UString password = Password; + bool passwordIsDefined = PasswordIsDefined; + + if (!silent) + { + const int kPathIndex = 2; + + extractionInfo.Load(); + + const int kPathModeRadioIndex = 4; + const int kOverwriteModeRadioIndex = kPathModeRadioIndex + 4; + const int kNumOverwriteOptions = 6; + const int kFilesModeIndex = kOverwriteModeRadioIndex + kNumOverwriteOptions; + const int kXSize = 76; + const int kYSize = 19; + const int kPasswordYPos = 12; + + const int kXMid = kXSize / 2; + + AString oemPassword (UnicodeStringToMultiByte(password, CP_OEMCP)); + + struct CInitDialogItem initItems[]={ + { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kExtractTitle, NULL, NULL }, + { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kExtractTo, NULL, NULL }, + + { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, kExractPathHistoryName}, + // { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, 0, false, -1, destPath, NULL}, + + { DI_SINGLEBOX, 4, 5, kXMid - 2, 5 + 4, false, false, 0, false, NMessageID::kExtractPathMode, NULL, NULL }, + { DI_RADIOBUTTON, 6, 6, 0, 0, false, + extractionInfo.PathMode == NExtract::NPathMode::kFullPaths, + DIF_GROUP, false, NMessageID::kExtractPathFull, NULL, NULL }, + { DI_RADIOBUTTON, 6, 7, 0, 0, false, + extractionInfo.PathMode == NExtract::NPathMode::kCurPaths, + 0, false, NMessageID::kExtractPathCurrent, NULL, NULL }, + { DI_RADIOBUTTON, 6, 8, 0, 0, false, + extractionInfo.PathMode == NExtract::NPathMode::kNoPaths, + false, 0, NMessageID::kExtractPathNo, NULL, NULL }, + + { DI_SINGLEBOX, kXMid, 5, kXSize - 6, 5 + kNumOverwriteOptions, false, false, 0, false, NMessageID::kExtractOwerwriteMode, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, + extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kAsk, + DIF_GROUP, false, NMessageID::kExtractOwerwriteAsk, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, + extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kOverwrite, + 0, false, NMessageID::kExtractOwerwritePrompt, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, + extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kSkip, + 0, false, NMessageID::kExtractOwerwriteSkip, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 9, 0, 0, false, + extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kRename, + 0, false, NMessageID::kExtractOwerwriteAutoRename, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 10, 0, 0, false, + extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kRenameExisting, + 0, false, NMessageID::kExtractOwerwriteAutoRenameExisting, NULL, NULL }, + + { DI_SINGLEBOX, 4, 10, kXMid- 2, 10 + 3, false, false, 0, false, NMessageID::kExtractFilesMode, NULL, NULL }, + { DI_RADIOBUTTON, 6, 11, 0, 0, false, true, DIF_GROUP, false, NMessageID::kExtractFilesSelected, NULL, NULL }, + { DI_RADIOBUTTON, 6, 12, 0, 0, false, false, 0, false, NMessageID::kExtractFilesAll, NULL, NULL }, + + { DI_SINGLEBOX, kXMid, kPasswordYPos, kXSize - 6, kPasswordYPos + 2, false, false, 0, false, NMessageID::kExtractPassword, NULL, NULL }, + { DI_PSWEDIT, kXMid + 2, kPasswordYPos + 1, kXSize - 8, 12, false, false, 0, false, -1, oemPassword, NULL}, + + { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, + + + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kExtractExtract, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kExtractCancel, NULL, NULL } + }; + + const unsigned kNumDialogItems = Z7_ARRAY_SIZE(initItems); + const unsigned kOkButtonIndex = kNumDialogItems - 2; + const unsigned kPasswordIndex = kNumDialogItems - 4; + + FarDialogItem dialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); + for (;;) + { + int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize, + kHelpTopicExtrFromSevenZip, dialogItems, kNumDialogItems); + if (askCode != kOkButtonIndex) + return NFileOperationReturnCode::kInterruptedByUser; + destPath = dialogItems[kPathIndex].Data; + destPathU = GetUnicodeString(destPath, CP_OEMCP); + destPathU.Trim(); + if (destPathU.IsEmpty()) + { + #ifdef UNDER_CE + destPathU = "\\"; + #else + FString destPathF = us2fs(destPathU); + if (!GetCurrentDir(destPathF)) + throw 318016; + NName::NormalizeDirPathPrefix(destPathF); + destPathU = fs2us(destPathF); + #endif + break; + } + else + { + if (destPathU.Back() == kDirDelimiter) + break; + } + g_StartupInfo.ShowErrorMessage("You must specify directory path"); + } + + if (dialogItems[kPathModeRadioIndex].Selected) + extractionInfo.PathMode = NExtract::NPathMode::kFullPaths; + else if (dialogItems[kPathModeRadioIndex + 1].Selected) + extractionInfo.PathMode = NExtract::NPathMode::kCurPaths; + else if (dialogItems[kPathModeRadioIndex + 2].Selected) + extractionInfo.PathMode = NExtract::NPathMode::kNoPaths; + else + throw 31806; + + if (dialogItems[kOverwriteModeRadioIndex].Selected) + extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kAsk; + else if (dialogItems[kOverwriteModeRadioIndex + 1].Selected) + extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite; + else if (dialogItems[kOverwriteModeRadioIndex + 2].Selected) + extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kSkip; + else if (dialogItems[kOverwriteModeRadioIndex + 3].Selected) + extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kRename; + else if (dialogItems[kOverwriteModeRadioIndex + 4].Selected) + extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kRenameExisting; + else + throw 31806; + + if (dialogItems[kFilesModeIndex].Selected) + decompressAllItems = false; + else if (dialogItems[kFilesModeIndex + 1].Selected) + decompressAllItems = true; + else + throw 31806; + + extractionInfo.Save(); + + if (dialogItems[kFilesModeIndex].Selected) + { + // extractSelectedFiles = true; + } + else if (dialogItems[kFilesModeIndex + 1].Selected) + { + // extractSelectedFiles = false; + } + else + throw 31806; + + oemPassword = dialogItems[kPasswordIndex].Data; + password = MultiByteToUnicodeString(oemPassword, CP_OEMCP); + passwordIsDefined = !password.IsEmpty(); + } + + CreateComplexDir(us2fs(destPathU)); + + /* + vector realIndices; + if (!decompressAllItems) + GetRealIndexes(panelItems, itemsNumber, realIndices); + */ + CObjArray indices(itemsNumber); + for (unsigned i = 0; i < itemsNumber; i++) + indices[i] = (UInt32)panelItems[i].UserData; + + const HRESULT result = ExtractFiles(decompressAllItems, indices, itemsNumber, + !showBox, extractionInfo.PathMode, extractionInfo.OverwriteMode, + destPathU, + passwordIsDefined, password); + // HRESULT result = ExtractFiles(decompressAllItems, realIndices, !showBox, + // extractionInfo, destPath, passwordIsDefined, password); + if (result != S_OK) + { + if (result == E_ABORT) + return NFileOperationReturnCode::kInterruptedByUser; + ShowSysErrorMessage(result); + return NFileOperationReturnCode::kError; + } + + // if (move != 0) + // { + // if (DeleteFiles(panelItems, itemsNumber, opMode) == FALSE) + // return NFileOperationReturnCode::kError; + // } + return NFileOperationReturnCode::kSuccess; +} diff --git a/CPP/7zip/UI/Far/PluginWrite.cpp b/CPP/7zip/UI/Far/PluginWrite.cpp index 13ba8d7e6..8a000496b 100644 --- a/CPP/7zip/UI/Far/PluginWrite.cpp +++ b/CPP/7zip/UI/Far/PluginWrite.cpp @@ -1,840 +1,840 @@ -// PluginWrite.cpp - -#include "StdAfx.h" - -#include - -#include "Plugin.h" - -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileFind.h" - -#include "../Common/ZipRegistry.h" - -#include "../Agent/Agent.h" - -#include "ProgressBox.h" -#include "Messages.h" -#include "UpdateCallbackFar.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NFar; - -using namespace NUpdateArchive; - -static const char * const kHelpTopic = "Update"; - -static const char * const kArchiveHistoryKeyName = "7-ZipArcName"; - -static const UInt32 g_MethodMap[] = { 0, 1, 3, 5, 7, 9 }; - -static HRESULT SetOutProperties(IOutFolderArchive *outArchive, UInt32 method) -{ - CMyComPtr setProperties; - if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) - { - /* - UStringVector realNames; - realNames.Add(UString("x")); - NCOM::CPropVariant value = (UInt32)method; - CRecordVector names; - FOR_VECTOR (i, realNames) - names.Add(realNames[i]); - RINOK(setProperties->SetProperties(&names.Front(), &value, names.Size())); - */ - NCOM::CPropVariant value = (UInt32)method; - const wchar_t *name = L"x"; - RINOK(setProperties->SetProperties(&name, &value, 1)) - } - return S_OK; -} - -/* -HRESULT CPlugin::AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector) -{ - _folder.Release(); - m_ArchiveHandler->Close(); - - RINOK(tempFile.MoveToOriginal(true)); - - RINOK(m_ArchiveHandler->ReOpen(NULL)); // check it - - m_ArchiveHandler->BindToRootFolder(&_folder); - FOR_VECTOR (i, pathVector) - { - CMyComPtr newFolder; - _folder->BindToFolder(pathVector[i], &newFolder); - if (!newFolder) - break; - _folder = newFolder; - } - return S_OK; -} -*/ - -NFileOperationReturnCode::EEnum CPlugin::PutFiles( - struct PluginPanelItem *panelItems, unsigned numItems, - int moveMode, int opMode) -{ - if (moveMode != 0 - && _agent->_isHashHandler) - { - g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); - return NFileOperationReturnCode::kError; - } - - if (numItems <= 0) - return NFileOperationReturnCode::kError; - - if (_agent->IsThere_ReadOnlyArc()) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return NFileOperationReturnCode::kError; - } - - const int kYSize = 14; - const int kXMid = 38; - - NCompression::CInfo compressionInfo; - compressionInfo.Load(); - - unsigned methodIndex = 0; - - unsigned i; - for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;) - { - i--; - if (compressionInfo.Level >= g_MethodMap[i]) - { - methodIndex = i; - break; - } - } - - const int kMethodRadioIndex = 2; - const int kModeRadioIndex = kMethodRadioIndex + 7; - - struct CInitDialogItem initItems[]={ - { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL }, - - { DI_SINGLEBOX, 4, 2, kXMid - 2, 2 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL }, - - { DI_RADIOBUTTON, 6, 3, 0, 0, methodIndex == 0, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL }, - { DI_RADIOBUTTON, 6, 4, 0, 0, methodIndex == 1, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL }, - { DI_RADIOBUTTON, 6, 5, 0, 0, methodIndex == 2, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL }, - { DI_RADIOBUTTON, 6, 6, 0, 0, methodIndex == 3, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL }, - { DI_RADIOBUTTON, 6, 7, 0, 0, methodIndex == 4, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL }, - { DI_RADIOBUTTON, 6, 8, 0, 0, methodIndex == 5, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL }, - - { DI_SINGLEBOX, kXMid, 2, 70, 2 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL }, - - { DI_RADIOBUTTON, kXMid + 2, 3, 0, 0, false, true, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 4, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Update, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Sync, NULL, NULL }, - - { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, - - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } - }; - - const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); - const int kOkButtonIndex = kNumDialogItems - 2; - FarDialogItem dialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); - const int askCode = g_StartupInfo.ShowDialog(76, kYSize, - kHelpTopic, dialogItems, kNumDialogItems); - if (askCode != kOkButtonIndex) - return NFileOperationReturnCode::kInterruptedByUser; - - compressionInfo.Level = g_MethodMap[0]; - for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++) - if (dialogItems[kMethodRadioIndex + i].Selected) - compressionInfo.Level = g_MethodMap[i]; - - const CActionSet *actionSet; - - if (dialogItems[kModeRadioIndex ].Selected) actionSet = &k_ActionSet_Add; - else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update; - else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh; - else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync; - else throw 51751; - - compressionInfo.Save(); - - CWorkDirTempFile tempFile; - if (tempFile.CreateTempFile(m_FileName) != S_OK) - return NFileOperationReturnCode::kError; - - - /* - CSysStringVector fileNames; - for (int i = 0; i < numItems; i++) - { - const PluginPanelItem &panelItem = panelItems[i]; - CSysString fullName; - if (!MyGetFullPathName(panelItem.FindData.cFileName, fullName)) - return NFileOperationReturnCode::kError; - fileNames.Add(fullName); - } - */ - - CScreenRestorer screenRestorer; - CProgressBox progressBox; - CProgressBox *progressBoxPointer = NULL; - if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) - { - screenRestorer.Save(); - - progressBoxPointer = &progressBox; - progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kUpdating)); - } - - UStringVector pathVector; - GetPathParts(pathVector); - - UStringVector fileNames; - fileNames.ClearAndReserve(numItems); - for (i = 0; i < (unsigned)numItems; i++) - fileNames.AddInReserved(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP)); - CObjArray fileNamePointers(numItems); - for (i = 0; i < (unsigned)numItems; i++) - fileNamePointers[i] = fileNames[i]; - - CMyComPtr outArchive; - HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive); - if (result != S_OK) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return NFileOperationReturnCode::kError; - } - - /* - BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues]; - for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) - actionSetByte[i] = (BYTE)actionSet->StateActions[i]; - */ - - CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; - CMyComPtr updateCallback(updateCallbackSpec ); - - updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); - updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; - updateCallbackSpec->Password = Password; - - if (!_agent->_isHashHandler) - { - if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK) - return NFileOperationReturnCode::kError; - } - - /* - outArchive->SetFolder(_folder); - outArchive->SetFiles(L"", fileNamePointers, numItems); - // FStringVector requestedPaths; - // FStringVector processedPaths; - result = outArchive->DoOperation2( - // &requestedPaths, &processedPaths, - NULL, NULL, - tempFile.OutStream, actionSetByte, NULL, updateCallback); - updateCallback.Release(); - outArchive.Release(); - - if (result == S_OK) - { - result = AfterUpdate(tempFile, pathVector); - } - */ - - { - result = _agent->SetFiles(L"", fileNamePointers, numItems); - if (result == S_OK) - { - CAgentFolder *agentFolder = NULL; - { - CMyComPtr afi; - _folder.QueryInterface(IID_IArchiveFolderInternal, &afi); - if (afi) - afi->GetAgentFolder(&agentFolder); - } - if (agentFolder) - result = agentFolder->CommonUpdateOperation(AGENT_OP_Uni, - (moveMode != 0), NULL, actionSet, NULL, 0, updateCallback); - else - result = E_FAIL; - } - } - - if (result != S_OK) - { - ShowSysErrorMessage(result); - return NFileOperationReturnCode::kError; - } - - return NFileOperationReturnCode::kSuccess; -} - -namespace NPathType -{ - enum EEnum - { - kLocal, - kUNC - }; - EEnum GetPathType(const UString &path); -} - -struct CParsedPath -{ - UString Prefix; // Disk or UNC with slash - UStringVector PathParts; - void ParsePath(const UString &path); - UString MergePath() const; -}; - -static const char kDirDelimiter = CHAR_PATH_SEPARATOR; -static const wchar_t kDiskDelimiter = L':'; - -namespace NPathType -{ - EEnum GetPathType(const UString &path) - { - if (path.Len() <= 2) - return kLocal; - if (path[0] == kDirDelimiter && path[1] == kDirDelimiter) - return kUNC; - return kLocal; - } -} - -void CParsedPath::ParsePath(const UString &path) -{ - int curPos = 0; - switch (NPathType::GetPathType(path)) - { - case NPathType::kLocal: - { - const int posDiskDelimiter = path.Find(kDiskDelimiter); - if (posDiskDelimiter >= 0) - { - curPos = posDiskDelimiter + 1; - if ((int)path.Len() > curPos) - if (path[curPos] == kDirDelimiter) - curPos++; - } - break; - } - case NPathType::kUNC: - { - // the bug was fixed: - curPos = path.Find((wchar_t)kDirDelimiter, 2); - if (curPos < 0) - curPos = (int)path.Len(); - else - curPos++; - } - } - Prefix = path.Left(curPos); - SplitPathToParts(path.Ptr(curPos), PathParts); -} - -UString CParsedPath::MergePath() const -{ - UString result = Prefix; - FOR_VECTOR (i, PathParts) - { - if (i != 0) - // result += kDirDelimiter; - result.Add_PathSepar(); - result += PathParts[i]; - } - return result; -} - - -static void SetArcName(UString &arcName, const CArcInfoEx &arcInfo) -{ - if (!arcInfo.Flags_KeepName()) - { - int dotPos = arcName.ReverseFind_Dot(); - int slashPos = arcName.ReverseFind_PathSepar(); - if (dotPos > slashPos + 1) - arcName.DeleteFrom(dotPos); - } - arcName.Add_Dot(); - arcName += arcInfo.GetMainExt(); -} - -HRESULT CompressFiles(const CObjectVector &pluginPanelItems) -{ - if (pluginPanelItems.Size() == 0) - return E_FAIL; - - UStringVector fileNames; - { - FOR_VECTOR (i, pluginPanelItems) - { - const PluginPanelItem &panelItem = pluginPanelItems[i]; - if (strcmp(panelItem.FindData.cFileName, "..") == 0 && - NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes)) - return E_FAIL; - if (strcmp(panelItem.FindData.cFileName, ".") == 0 && - NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes)) - return E_FAIL; - FString fullPath; - FString fileNameUnicode = us2fs(MultiByteToUnicodeString(panelItem.FindData.cFileName, CP_OEMCP)); - if (!MyGetFullPathName(fileNameUnicode, fullPath)) - return E_FAIL; - fileNames.Add(fs2us(fullPath)); - } - } - - NCompression::CInfo compressionInfo; - compressionInfo.Load(); - - int archiverIndex = -1; - - /* - CCodecs *codecs = new CCodecs; - CMyComPtr compressCodecsInfo = codecs; - if (codecs->Load() != S_OK) - throw "Can't load 7-Zip codecs"; - */ - - if (LoadGlobalCodecs() != S_OK) - throw "Can't load 7-Zip codecs"; - - CCodecs *codecs = g_CodecsObj; - - { - FOR_VECTOR (i, codecs->Formats) - { - const CArcInfoEx &arcInfo = codecs->Formats[i]; - if (arcInfo.UpdateEnabled) - { - if (archiverIndex == -1) - archiverIndex = (int)i; - if (MyStringCompareNoCase(arcInfo.Name, compressionInfo.ArcType) == 0) - archiverIndex = (int)i; - } - } - } - - if (archiverIndex < 0) - throw "there is no output handler"; - - UString resultPath; - { - CParsedPath parsedPath; - parsedPath.ParsePath(fileNames.Front()); - if (parsedPath.PathParts.Size() == 0) - return E_FAIL; - if (fileNames.Size() == 1 || parsedPath.PathParts.Size() == 1) - { - // CSysString pureName, dot, extension; - resultPath = parsedPath.PathParts.Back(); - } - else - { - parsedPath.PathParts.DeleteBack(); - resultPath = parsedPath.PathParts.Back(); - } - } - UString archiveNameSrc = resultPath; - UString arcName = archiveNameSrc; - - int prevFormat = archiverIndex; - SetArcName(arcName, codecs->Formats[archiverIndex]); - - const CActionSet *actionSet = &k_ActionSet_Add; - - for (;;) - { - AString archiveNameA (UnicodeStringToMultiByte(arcName, CP_OEMCP)); - const int kYSize = 16; - const int kXMid = 38; - - const int kArchiveNameIndex = 2; - const int kMethodRadioIndex = kArchiveNameIndex + 2; - const int kModeRadioIndex = kMethodRadioIndex + 7; - - // char updateAddToArchiveString[512]; - AString str1; - { - const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; - const AString s (UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP)); - str1 = g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive); - str1.Replace(AString ("%s"), s); - /* - sprintf(updateAddToArchiveString, - g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s); - */ - } - - unsigned methodIndex = 0; - unsigned i; - for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;) - { - i--; - if (compressionInfo.Level >= g_MethodMap[i]) - { - methodIndex = i; - break; - } - } - - const struct CInitDialogItem initItems[]= - { - { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL }, - - { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, str1, NULL }, - - { DI_EDIT, 5, 3, 70, 3, true, false, DIF_HISTORY, false, -1, archiveNameA, kArchiveHistoryKeyName}, - // { DI_EDIT, 5, 3, 70, 3, true, false, 0, false, -1, arcName, NULL}, - - { DI_SINGLEBOX, 4, 4, kXMid - 2, 4 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL }, - - { DI_RADIOBUTTON, 6, 5, 0, 0, false, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL }, - { DI_RADIOBUTTON, 6, 6, 0, 0, false, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL }, - { DI_RADIOBUTTON, 6, 7, 0, 0, false, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL }, - { DI_RADIOBUTTON, 6, 8, 0, 0, false, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL }, - { DI_RADIOBUTTON, 6, 9, 0, 0, false, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL }, - { DI_RADIOBUTTON, 6,10, 0, 0, false, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL }, - - { DI_SINGLEBOX, kXMid, 4, 70, 4 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL }, - - { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, actionSet == &k_ActionSet_Add, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, actionSet == &k_ActionSet_Update, 0, false, NMessageID::kUpdateMode_Update, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, actionSet == &k_ActionSet_Fresh, 0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL }, - { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, actionSet == &k_ActionSet_Sync, 0, false, NMessageID::kUpdateMode_Sync, NULL, NULL }, - - { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, - - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kUpdateSelectArchiver, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } - }; - - const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); - - const int kOkButtonIndex = kNumDialogItems - 3; - const int kSelectarchiverButtonIndex = kNumDialogItems - 2; - - FarDialogItem dialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); - int askCode = g_StartupInfo.ShowDialog(76, kYSize, - kHelpTopic, dialogItems, kNumDialogItems); - - archiveNameA = dialogItems[kArchiveNameIndex].Data; - archiveNameA.Trim(); - MultiByteToUnicodeString2(arcName, archiveNameA, CP_OEMCP); - - compressionInfo.Level = g_MethodMap[0]; - for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++) - if (dialogItems[kMethodRadioIndex + i].Selected) - compressionInfo.Level = g_MethodMap[i]; - - if (dialogItems[kModeRadioIndex ].Selected) actionSet = &k_ActionSet_Add; - else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update; - else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh; - else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync; - else throw 51751; - - if (askCode == kSelectarchiverButtonIndex) - { - CUIntVector indices; - AStringVector archiverNames; - FOR_VECTOR (k, codecs->Formats) - { - const CArcInfoEx &arc = codecs->Formats[k]; - if (arc.UpdateEnabled) - { - indices.Add(k); - archiverNames.Add(GetOemString(arc.Name)); - } - } - - const int index = g_StartupInfo.Menu(FMENU_AUTOHIGHLIGHT, - g_StartupInfo.GetMsgString(NMessageID::kUpdateSelectArchiverMenuTitle), - NULL, archiverNames, archiverIndex); - if (index >= 0) - { - const CArcInfoEx &prevArchiverInfo = codecs->Formats[prevFormat]; - if (prevArchiverInfo.Flags_KeepName()) - { - const UString &prevExtension = prevArchiverInfo.GetMainExt(); - const unsigned prevExtensionLen = prevExtension.Len(); - if (arcName.Len() >= prevExtensionLen && - MyStringCompareNoCase(arcName.RightPtr(prevExtensionLen), prevExtension) == 0) - { - const unsigned pos = arcName.Len() - prevExtensionLen; - if (pos > 2) - { - if (arcName[pos - 1] == '.') - arcName.DeleteFrom(pos - 1); - } - } - } - - archiverIndex = (int)indices[index]; - const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; - prevFormat = archiverIndex; - - if (arcInfo.Flags_KeepName()) - arcName = archiveNameSrc; - SetArcName(arcName, arcInfo); - } - continue; - } - - if (askCode != kOkButtonIndex) - return E_ABORT; - - break; - } - - const CArcInfoEx &archiverInfoFinal = codecs->Formats[archiverIndex]; - compressionInfo.ArcType = archiverInfoFinal.Name; - compressionInfo.Save(); - - NWorkDir::CInfo workDirInfo; - workDirInfo.Load(); - - FString fullArcName; - if (!MyGetFullPathName(us2fs(arcName), fullArcName)) - return E_FAIL; - - CWorkDirTempFile tempFile; - RINOK(tempFile.CreateTempFile(fullArcName)) - CScreenRestorer screenRestorer; - CProgressBox progressBox; - CProgressBox *progressBoxPointer = NULL; - - screenRestorer.Save(); - - progressBoxPointer = &progressBox; - progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kUpdating)); - - - NFind::CFileInfo fileInfo; - - CMyComPtr outArchive; - - CMyComPtr archiveHandler; - if (fileInfo.Find(fullArcName)) - { - if (fileInfo.IsDir()) - throw "There is Directory with such name"; - - CAgent *agentSpec = new CAgent; - archiveHandler = agentSpec; - // CLSID realClassID; - CMyComBSTR archiveType; - RINOK(archiveHandler->Open(NULL, - GetUnicodeString(fullArcName, CP_OEMCP), UString(), - // &realClassID, - &archiveType, - NULL)) - - if (MyStringCompareNoCase(archiverInfoFinal.Name, (const wchar_t *)archiveType) != 0) - throw "Type of existing archive differs from specified type"; - const HRESULT result = archiveHandler.QueryInterface( - IID_IOutFolderArchive, &outArchive); - if (result != S_OK) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return E_FAIL; - } - } - else - { - // HRESULT result = outArchive.CoCreateInstance(classID); - CAgent *agentSpec = new CAgent; - outArchive = agentSpec; - - /* - HRESULT result = outArchive.CoCreateInstance(CLSID_CAgentArchiveHandler); - if (result != S_OK) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return E_FAIL; - } - */ - } - - CObjArray fileNamePointers(fileNames.Size()); - - unsigned i; - for (i = 0; i < fileNames.Size(); i++) - fileNamePointers[i] = fileNames[i]; - - outArchive->SetFolder(NULL); - outArchive->SetFiles(L"", fileNamePointers, fileNames.Size()); - BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues]; - for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) - actionSetByte[i] = (BYTE)actionSet->StateActions[i]; - - CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; - CMyComPtr updateCallback(updateCallbackSpec ); - - updateCallbackSpec->Init(/* archiveHandler, */ progressBoxPointer); - - - RINOK(SetOutProperties(outArchive, compressionInfo.Level)) - - // FStringVector requestedPaths; - // FStringVector processedPaths; - HRESULT result = outArchive->DoOperation( - // &requestedPaths, &processedPaths, - NULL, NULL, - codecs, archiverIndex, - tempFile.OutStream, actionSetByte, - NULL, updateCallback); - updateCallback.Release(); - outArchive.Release(); - - if (result != S_OK) - { - ShowSysErrorMessage(result); - return result; - } - - if (archiveHandler) - { - archiveHandler->Close(); - } - - result = tempFile.MoveToOriginal(archiveHandler != NULL); - if (result != S_OK) - { - ShowSysErrorMessage(result); - return result; - } - return S_OK; -} - - -static const char * const k_CreateFolder_History = "NewFolder"; // we use default FAR folder name - -HRESULT CPlugin::CreateFolder() -{ - if (_agent->IsThere_ReadOnlyArc()) - { - g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); - return TRUE; - } - - UString destPathU; - { - const int kXSize = 60; - const int kYSize = 8; - const int kPathIndex = 2; - - AString destPath ("New Folder"); - - const struct CInitDialogItem initItems[]={ - { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, - -1, "Create Folder", NULL }, - - { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, "Folder name:", NULL }, - - { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, k_CreateFolder_History }, - - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL }, - { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } - }; - - const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); - const int kOkButtonIndex = kNumDialogItems - 2; - - FarDialogItem dialogItems[kNumDialogItems]; - g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); - for (;;) - { - int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize, - NULL, // kHelpTopic - dialogItems, kNumDialogItems); - if (askCode != kOkButtonIndex) - return E_ABORT; - destPath = dialogItems[kPathIndex].Data; - destPathU = GetUnicodeString(destPath, CP_OEMCP); - destPathU.Trim(); - if (!destPathU.IsEmpty()) - break; - g_StartupInfo.ShowErrorMessage("You must specify folder name"); - } - - } - - CScreenRestorer screenRestorer; - CProgressBox progressBox; - CProgressBox *progressBoxPointer = NULL; - // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) - { - screenRestorer.Save(); - - progressBoxPointer = &progressBox; - progressBox.Init( - // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), - g_StartupInfo.GetMsgString(NMessageID::kDeleting)); - } - - CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; - CMyComPtr updateCallback(updateCallbackSpec); - - updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); - updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; - updateCallbackSpec->Password = Password; - - HRESULT result; - { - CMyComPtr folderOperations; - result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations); - if (folderOperations) - result = folderOperations->CreateFolder(destPathU, updateCallback); - else if (result != S_OK) - result = E_FAIL; - } - - if (result != S_OK) - { - ShowSysErrorMessage(result); - return result; - } - - g_StartupInfo.Control(this, FCTL_UPDATEPANEL, (void *)1); - g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL); - - PanelInfo panelInfo; - - if (g_StartupInfo.ControlGetActivePanelInfo(panelInfo)) - { - const AString destPath (GetOemString(destPathU)); - - for (int i = 0; i < panelInfo.ItemsNumber; i++) - { - const PluginPanelItem &pi = panelInfo.PanelItems[i]; - if (strcmp(destPath, pi.FindData.cFileName) == 0) - { - PanelRedrawInfo panelRedrawInfo; - panelRedrawInfo.CurrentItem = i; - panelRedrawInfo.TopPanelItem = 0; - g_StartupInfo.Control(this, FCTL_REDRAWPANEL, &panelRedrawInfo); - break; - } - } - } - - SetCurrentDirVar(); - return S_OK; -} +// PluginWrite.cpp + +#include "StdAfx.h" + +#include + +#include "Plugin.h" + +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileFind.h" + +#include "../Common/ZipRegistry.h" + +#include "../Agent/Agent.h" + +#include "ProgressBox.h" +#include "Messages.h" +#include "UpdateCallbackFar.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NFar; + +using namespace NUpdateArchive; + +static const char * const kHelpTopic = "Update"; + +static const char * const kArchiveHistoryKeyName = "7-ZipArcName"; + +static const UInt32 g_MethodMap[] = { 0, 1, 3, 5, 7, 9 }; + +static HRESULT SetOutProperties(IOutFolderArchive *outArchive, UInt32 method) +{ + CMyComPtr setProperties; + if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) + { + /* + UStringVector realNames; + realNames.Add(UString("x")); + NCOM::CPropVariant value = (UInt32)method; + CRecordVector names; + FOR_VECTOR (i, realNames) + names.Add(realNames[i]); + RINOK(setProperties->SetProperties(&names.Front(), &value, names.Size())); + */ + NCOM::CPropVariant value = (UInt32)method; + const wchar_t *name = L"x"; + RINOK(setProperties->SetProperties(&name, &value, 1)) + } + return S_OK; +} + +/* +HRESULT CPlugin::AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector) +{ + _folder.Release(); + m_ArchiveHandler->Close(); + + RINOK(tempFile.MoveToOriginal(true)); + + RINOK(m_ArchiveHandler->ReOpen(NULL)); // check it + + m_ArchiveHandler->BindToRootFolder(&_folder); + FOR_VECTOR (i, pathVector) + { + CMyComPtr newFolder; + _folder->BindToFolder(pathVector[i], &newFolder); + if (!newFolder) + break; + _folder = newFolder; + } + return S_OK; +} +*/ + +NFileOperationReturnCode::EEnum CPlugin::PutFiles( + struct PluginPanelItem *panelItems, unsigned numItems, + int moveMode, int opMode) +{ + if (moveMode != 0 + && _agent->_isHashHandler) + { + g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported); + return NFileOperationReturnCode::kError; + } + + if (numItems <= 0) + return NFileOperationReturnCode::kError; + + if (_agent->IsThere_ReadOnlyArc()) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return NFileOperationReturnCode::kError; + } + + const int kYSize = 14; + const int kXMid = 38; + + NCompression::CInfo compressionInfo; + compressionInfo.Load(); + + unsigned methodIndex = 0; + + unsigned i; + for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;) + { + i--; + if (compressionInfo.Level >= g_MethodMap[i]) + { + methodIndex = i; + break; + } + } + + const int kMethodRadioIndex = 2; + const int kModeRadioIndex = kMethodRadioIndex + 7; + + struct CInitDialogItem initItems[]={ + { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL }, + + { DI_SINGLEBOX, 4, 2, kXMid - 2, 2 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL }, + + { DI_RADIOBUTTON, 6, 3, 0, 0, methodIndex == 0, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL }, + { DI_RADIOBUTTON, 6, 4, 0, 0, methodIndex == 1, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL }, + { DI_RADIOBUTTON, 6, 5, 0, 0, methodIndex == 2, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL }, + { DI_RADIOBUTTON, 6, 6, 0, 0, methodIndex == 3, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL }, + { DI_RADIOBUTTON, 6, 7, 0, 0, methodIndex == 4, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL }, + { DI_RADIOBUTTON, 6, 8, 0, 0, methodIndex == 5, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL }, + + { DI_SINGLEBOX, kXMid, 2, 70, 2 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL }, + + { DI_RADIOBUTTON, kXMid + 2, 3, 0, 0, false, true, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 4, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Update, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Sync, NULL, NULL }, + + { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, + + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } + }; + + const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); + const int kOkButtonIndex = kNumDialogItems - 2; + FarDialogItem dialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); + const int askCode = g_StartupInfo.ShowDialog(76, kYSize, + kHelpTopic, dialogItems, kNumDialogItems); + if (askCode != kOkButtonIndex) + return NFileOperationReturnCode::kInterruptedByUser; + + compressionInfo.Level = g_MethodMap[0]; + for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++) + if (dialogItems[kMethodRadioIndex + i].Selected) + compressionInfo.Level = g_MethodMap[i]; + + const CActionSet *actionSet; + + if (dialogItems[kModeRadioIndex ].Selected) actionSet = &k_ActionSet_Add; + else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update; + else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh; + else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync; + else throw 51751; + + compressionInfo.Save(); + + CWorkDirTempFile tempFile; + if (tempFile.CreateTempFile(m_FileName) != S_OK) + return NFileOperationReturnCode::kError; + + + /* + CSysStringVector fileNames; + for (int i = 0; i < numItems; i++) + { + const PluginPanelItem &panelItem = panelItems[i]; + CSysString fullName; + if (!MyGetFullPathName(panelItem.FindData.cFileName, fullName)) + return NFileOperationReturnCode::kError; + fileNames.Add(fullName); + } + */ + + CScreenRestorer screenRestorer; + CProgressBox progressBox; + CProgressBox *progressBoxPointer = NULL; + if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) + { + screenRestorer.Save(); + + progressBoxPointer = &progressBox; + progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kUpdating)); + } + + UStringVector pathVector; + GetPathParts(pathVector); + + UStringVector fileNames; + fileNames.ClearAndReserve(numItems); + for (i = 0; i < (unsigned)numItems; i++) + fileNames.AddInReserved(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP)); + CObjArray fileNamePointers(numItems); + for (i = 0; i < (unsigned)numItems; i++) + fileNamePointers[i] = fileNames[i]; + + CMyComPtr outArchive; + HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive); + if (result != S_OK) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return NFileOperationReturnCode::kError; + } + + /* + BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues]; + for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) + actionSetByte[i] = (BYTE)actionSet->StateActions[i]; + */ + + CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; + CMyComPtr updateCallback(updateCallbackSpec ); + + updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); + updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; + updateCallbackSpec->Password = Password; + + if (!_agent->_isHashHandler) + { + if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK) + return NFileOperationReturnCode::kError; + } + + /* + outArchive->SetFolder(_folder); + outArchive->SetFiles(L"", fileNamePointers, numItems); + // FStringVector requestedPaths; + // FStringVector processedPaths; + result = outArchive->DoOperation2( + // &requestedPaths, &processedPaths, + NULL, NULL, + tempFile.OutStream, actionSetByte, NULL, updateCallback); + updateCallback.Release(); + outArchive.Release(); + + if (result == S_OK) + { + result = AfterUpdate(tempFile, pathVector); + } + */ + + { + result = _agent->SetFiles(L"", fileNamePointers, numItems); + if (result == S_OK) + { + CAgentFolder *agentFolder = NULL; + { + CMyComPtr afi; + _folder.QueryInterface(IID_IArchiveFolderInternal, &afi); + if (afi) + afi->GetAgentFolder(&agentFolder); + } + if (agentFolder) + result = agentFolder->CommonUpdateOperation(AGENT_OP_Uni, + (moveMode != 0), NULL, actionSet, NULL, 0, updateCallback); + else + result = E_FAIL; + } + } + + if (result != S_OK) + { + ShowSysErrorMessage(result); + return NFileOperationReturnCode::kError; + } + + return NFileOperationReturnCode::kSuccess; +} + +namespace NPathType +{ + enum EEnum + { + kLocal, + kUNC + }; + EEnum GetPathType(const UString &path); +} + +struct CParsedPath +{ + UString Prefix; // Disk or UNC with slash + UStringVector PathParts; + void ParsePath(const UString &path); + UString MergePath() const; +}; + +static const char kDirDelimiter = CHAR_PATH_SEPARATOR; +static const wchar_t kDiskDelimiter = L':'; + +namespace NPathType +{ + EEnum GetPathType(const UString &path) + { + if (path.Len() <= 2) + return kLocal; + if (path[0] == kDirDelimiter && path[1] == kDirDelimiter) + return kUNC; + return kLocal; + } +} + +void CParsedPath::ParsePath(const UString &path) +{ + int curPos = 0; + switch (NPathType::GetPathType(path)) + { + case NPathType::kLocal: + { + const int posDiskDelimiter = path.Find(kDiskDelimiter); + if (posDiskDelimiter >= 0) + { + curPos = posDiskDelimiter + 1; + if ((int)path.Len() > curPos) + if (path[curPos] == kDirDelimiter) + curPos++; + } + break; + } + case NPathType::kUNC: + { + // the bug was fixed: + curPos = path.Find((wchar_t)kDirDelimiter, 2); + if (curPos < 0) + curPos = (int)path.Len(); + else + curPos++; + } + } + Prefix = path.Left(curPos); + SplitPathToParts(path.Ptr(curPos), PathParts); +} + +UString CParsedPath::MergePath() const +{ + UString result = Prefix; + FOR_VECTOR (i, PathParts) + { + if (i != 0) + // result += kDirDelimiter; + result.Add_PathSepar(); + result += PathParts[i]; + } + return result; +} + + +static void SetArcName(UString &arcName, const CArcInfoEx &arcInfo) +{ + if (!arcInfo.Flags_KeepName()) + { + int dotPos = arcName.ReverseFind_Dot(); + int slashPos = arcName.ReverseFind_PathSepar(); + if (dotPos > slashPos + 1) + arcName.DeleteFrom(dotPos); + } + arcName.Add_Dot(); + arcName += arcInfo.GetMainExt(); +} + +HRESULT CompressFiles(const CObjectVector &pluginPanelItems) +{ + if (pluginPanelItems.Size() == 0) + return E_FAIL; + + UStringVector fileNames; + { + FOR_VECTOR (i, pluginPanelItems) + { + const PluginPanelItem &panelItem = pluginPanelItems[i]; + if (strcmp(panelItem.FindData.cFileName, "..") == 0 && + NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes)) + return E_FAIL; + if (strcmp(panelItem.FindData.cFileName, ".") == 0 && + NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes)) + return E_FAIL; + FString fullPath; + FString fileNameUnicode = us2fs(MultiByteToUnicodeString(panelItem.FindData.cFileName, CP_OEMCP)); + if (!MyGetFullPathName(fileNameUnicode, fullPath)) + return E_FAIL; + fileNames.Add(fs2us(fullPath)); + } + } + + NCompression::CInfo compressionInfo; + compressionInfo.Load(); + + int archiverIndex = -1; + + /* + CCodecs *codecs = new CCodecs; + CMyComPtr compressCodecsInfo = codecs; + if (codecs->Load() != S_OK) + throw "Can't load 7-Zip codecs"; + */ + + if (LoadGlobalCodecs() != S_OK) + throw "Can't load 7-Zip codecs"; + + CCodecs *codecs = g_CodecsObj; + + { + FOR_VECTOR (i, codecs->Formats) + { + const CArcInfoEx &arcInfo = codecs->Formats[i]; + if (arcInfo.UpdateEnabled) + { + if (archiverIndex == -1) + archiverIndex = (int)i; + if (MyStringCompareNoCase(arcInfo.Name, compressionInfo.ArcType) == 0) + archiverIndex = (int)i; + } + } + } + + if (archiverIndex < 0) + throw "there is no output handler"; + + UString resultPath; + { + CParsedPath parsedPath; + parsedPath.ParsePath(fileNames.Front()); + if (parsedPath.PathParts.Size() == 0) + return E_FAIL; + if (fileNames.Size() == 1 || parsedPath.PathParts.Size() == 1) + { + // CSysString pureName, dot, extension; + resultPath = parsedPath.PathParts.Back(); + } + else + { + parsedPath.PathParts.DeleteBack(); + resultPath = parsedPath.PathParts.Back(); + } + } + UString archiveNameSrc = resultPath; + UString arcName = archiveNameSrc; + + int prevFormat = archiverIndex; + SetArcName(arcName, codecs->Formats[archiverIndex]); + + const CActionSet *actionSet = &k_ActionSet_Add; + + for (;;) + { + AString archiveNameA (UnicodeStringToMultiByte(arcName, CP_OEMCP)); + const int kYSize = 16; + const int kXMid = 38; + + const int kArchiveNameIndex = 2; + const int kMethodRadioIndex = kArchiveNameIndex + 2; + const int kModeRadioIndex = kMethodRadioIndex + 7; + + // char updateAddToArchiveString[512]; + AString str1; + { + const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; + const AString s (UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP)); + str1 = g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive); + str1.Replace(AString ("%s"), s); + /* + sprintf(updateAddToArchiveString, + g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s); + */ + } + + unsigned methodIndex = 0; + unsigned i; + for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;) + { + i--; + if (compressionInfo.Level >= g_MethodMap[i]) + { + methodIndex = i; + break; + } + } + + const struct CInitDialogItem initItems[]= + { + { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL }, + + { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, str1, NULL }, + + { DI_EDIT, 5, 3, 70, 3, true, false, DIF_HISTORY, false, -1, archiveNameA, kArchiveHistoryKeyName}, + // { DI_EDIT, 5, 3, 70, 3, true, false, 0, false, -1, arcName, NULL}, + + { DI_SINGLEBOX, 4, 4, kXMid - 2, 4 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL }, + + { DI_RADIOBUTTON, 6, 5, 0, 0, false, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL }, + { DI_RADIOBUTTON, 6, 6, 0, 0, false, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL }, + { DI_RADIOBUTTON, 6, 7, 0, 0, false, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL }, + { DI_RADIOBUTTON, 6, 8, 0, 0, false, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL }, + { DI_RADIOBUTTON, 6, 9, 0, 0, false, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL }, + { DI_RADIOBUTTON, 6,10, 0, 0, false, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL }, + + { DI_SINGLEBOX, kXMid, 4, 70, 4 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL }, + + { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, actionSet == &k_ActionSet_Add, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, actionSet == &k_ActionSet_Update, 0, false, NMessageID::kUpdateMode_Update, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, actionSet == &k_ActionSet_Fresh, 0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL }, + { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, actionSet == &k_ActionSet_Sync, 0, false, NMessageID::kUpdateMode_Sync, NULL, NULL }, + + { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL }, + + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kUpdateSelectArchiver, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } + }; + + const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); + + const int kOkButtonIndex = kNumDialogItems - 3; + const int kSelectarchiverButtonIndex = kNumDialogItems - 2; + + FarDialogItem dialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); + int askCode = g_StartupInfo.ShowDialog(76, kYSize, + kHelpTopic, dialogItems, kNumDialogItems); + + archiveNameA = dialogItems[kArchiveNameIndex].Data; + archiveNameA.Trim(); + MultiByteToUnicodeString2(arcName, archiveNameA, CP_OEMCP); + + compressionInfo.Level = g_MethodMap[0]; + for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++) + if (dialogItems[kMethodRadioIndex + i].Selected) + compressionInfo.Level = g_MethodMap[i]; + + if (dialogItems[kModeRadioIndex ].Selected) actionSet = &k_ActionSet_Add; + else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update; + else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh; + else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync; + else throw 51751; + + if (askCode == kSelectarchiverButtonIndex) + { + CUIntVector indices; + AStringVector archiverNames; + FOR_VECTOR (k, codecs->Formats) + { + const CArcInfoEx &arc = codecs->Formats[k]; + if (arc.UpdateEnabled) + { + indices.Add(k); + archiverNames.Add(GetOemString(arc.Name)); + } + } + + const int index = g_StartupInfo.Menu(FMENU_AUTOHIGHLIGHT, + g_StartupInfo.GetMsgString(NMessageID::kUpdateSelectArchiverMenuTitle), + NULL, archiverNames, archiverIndex); + if (index >= 0) + { + const CArcInfoEx &prevArchiverInfo = codecs->Formats[prevFormat]; + if (prevArchiverInfo.Flags_KeepName()) + { + const UString &prevExtension = prevArchiverInfo.GetMainExt(); + const unsigned prevExtensionLen = prevExtension.Len(); + if (arcName.Len() >= prevExtensionLen && + MyStringCompareNoCase(arcName.RightPtr(prevExtensionLen), prevExtension) == 0) + { + const unsigned pos = arcName.Len() - prevExtensionLen; + if (pos > 2) + { + if (arcName[pos - 1] == '.') + arcName.DeleteFrom(pos - 1); + } + } + } + + archiverIndex = (int)indices[index]; + const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex]; + prevFormat = archiverIndex; + + if (arcInfo.Flags_KeepName()) + arcName = archiveNameSrc; + SetArcName(arcName, arcInfo); + } + continue; + } + + if (askCode != kOkButtonIndex) + return E_ABORT; + + break; + } + + const CArcInfoEx &archiverInfoFinal = codecs->Formats[archiverIndex]; + compressionInfo.ArcType = archiverInfoFinal.Name; + compressionInfo.Save(); + + NWorkDir::CInfo workDirInfo; + workDirInfo.Load(); + + FString fullArcName; + if (!MyGetFullPathName(us2fs(arcName), fullArcName)) + return E_FAIL; + + CWorkDirTempFile tempFile; + RINOK(tempFile.CreateTempFile(fullArcName)) + CScreenRestorer screenRestorer; + CProgressBox progressBox; + CProgressBox *progressBoxPointer = NULL; + + screenRestorer.Save(); + + progressBoxPointer = &progressBox; + progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kUpdating)); + + + NFind::CFileInfo fileInfo; + + CMyComPtr outArchive; + + CMyComPtr archiveHandler; + if (fileInfo.Find(fullArcName)) + { + if (fileInfo.IsDir()) + throw "There is Directory with such name"; + + CAgent *agentSpec = new CAgent; + archiveHandler = agentSpec; + // CLSID realClassID; + CMyComBSTR archiveType; + RINOK(archiveHandler->Open(NULL, + GetUnicodeString(fullArcName, CP_OEMCP), UString(), + // &realClassID, + &archiveType, + NULL)) + + if (MyStringCompareNoCase(archiverInfoFinal.Name, (const wchar_t *)archiveType) != 0) + throw "Type of existing archive differs from specified type"; + const HRESULT result = archiveHandler.QueryInterface( + IID_IOutFolderArchive, &outArchive); + if (result != S_OK) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return E_FAIL; + } + } + else + { + // HRESULT result = outArchive.CoCreateInstance(classID); + CAgent *agentSpec = new CAgent; + outArchive = agentSpec; + + /* + HRESULT result = outArchive.CoCreateInstance(CLSID_CAgentArchiveHandler); + if (result != S_OK) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return E_FAIL; + } + */ + } + + CObjArray fileNamePointers(fileNames.Size()); + + unsigned i; + for (i = 0; i < fileNames.Size(); i++) + fileNamePointers[i] = fileNames[i]; + + outArchive->SetFolder(NULL); + outArchive->SetFiles(L"", fileNamePointers, fileNames.Size()); + BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues]; + for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) + actionSetByte[i] = (BYTE)actionSet->StateActions[i]; + + CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; + CMyComPtr updateCallback(updateCallbackSpec ); + + updateCallbackSpec->Init(/* archiveHandler, */ progressBoxPointer); + + + RINOK(SetOutProperties(outArchive, compressionInfo.Level)) + + // FStringVector requestedPaths; + // FStringVector processedPaths; + HRESULT result = outArchive->DoOperation( + // &requestedPaths, &processedPaths, + NULL, NULL, + codecs, archiverIndex, + tempFile.OutStream, actionSetByte, + NULL, updateCallback); + updateCallback.Release(); + outArchive.Release(); + + if (result != S_OK) + { + ShowSysErrorMessage(result); + return result; + } + + if (archiveHandler) + { + archiveHandler->Close(); + } + + result = tempFile.MoveToOriginal(archiveHandler != NULL); + if (result != S_OK) + { + ShowSysErrorMessage(result); + return result; + } + return S_OK; +} + + +static const char * const k_CreateFolder_History = "NewFolder"; // we use default FAR folder name + +HRESULT CPlugin::CreateFolder() +{ + if (_agent->IsThere_ReadOnlyArc()) + { + g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive); + return TRUE; + } + + UString destPathU; + { + const int kXSize = 60; + const int kYSize = 8; + const int kPathIndex = 2; + + AString destPath ("New Folder"); + + const struct CInitDialogItem initItems[]={ + { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, + -1, "Create Folder", NULL }, + + { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, "Folder name:", NULL }, + + { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, k_CreateFolder_History }, + + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL }, + { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL } + }; + + const int kNumDialogItems = Z7_ARRAY_SIZE(initItems); + const int kOkButtonIndex = kNumDialogItems - 2; + + FarDialogItem dialogItems[kNumDialogItems]; + g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems); + for (;;) + { + int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize, + NULL, // kHelpTopic + dialogItems, kNumDialogItems); + if (askCode != kOkButtonIndex) + return E_ABORT; + destPath = dialogItems[kPathIndex].Data; + destPathU = GetUnicodeString(destPath, CP_OEMCP); + destPathU.Trim(); + if (!destPathU.IsEmpty()) + break; + g_StartupInfo.ShowErrorMessage("You must specify folder name"); + } + + } + + CScreenRestorer screenRestorer; + CProgressBox progressBox; + CProgressBox *progressBoxPointer = NULL; + // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0) + { + screenRestorer.Save(); + + progressBoxPointer = &progressBox; + progressBox.Init( + // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle), + g_StartupInfo.GetMsgString(NMessageID::kDeleting)); + } + + CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp; + CMyComPtr updateCallback(updateCallbackSpec); + + updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer); + updateCallbackSpec->PasswordIsDefined = PasswordIsDefined; + updateCallbackSpec->Password = Password; + + HRESULT result; + { + CMyComPtr folderOperations; + result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations); + if (folderOperations) + result = folderOperations->CreateFolder(destPathU, updateCallback); + else if (result != S_OK) + result = E_FAIL; + } + + if (result != S_OK) + { + ShowSysErrorMessage(result); + return result; + } + + g_StartupInfo.Control(this, FCTL_UPDATEPANEL, (void *)1); + g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL); + + PanelInfo panelInfo; + + if (g_StartupInfo.ControlGetActivePanelInfo(panelInfo)) + { + const AString destPath (GetOemString(destPathU)); + + for (int i = 0; i < panelInfo.ItemsNumber; i++) + { + const PluginPanelItem &pi = panelInfo.PanelItems[i]; + if (strcmp(destPath, pi.FindData.cFileName) == 0) + { + PanelRedrawInfo panelRedrawInfo; + panelRedrawInfo.CurrentItem = i; + panelRedrawInfo.TopPanelItem = 0; + g_StartupInfo.Control(this, FCTL_REDRAWPANEL, &panelRedrawInfo); + break; + } + } + } + + SetCurrentDirVar(); + return S_OK; +} diff --git a/CPP/7zip/UI/Far/ProgressBox.cpp b/CPP/7zip/UI/Far/ProgressBox.cpp index ad3ce9695..ab25a104b 100644 --- a/CPP/7zip/UI/Far/ProgressBox.cpp +++ b/CPP/7zip/UI/Far/ProgressBox.cpp @@ -1,305 +1,305 @@ -// ProgressBox.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "FarUtils.h" -#include "ProgressBox.h" - -void CPercentPrinterState::ClearCurState() -{ - Completed = 0; - Total = ((UInt64)(Int64)-1); - Files = 0; - FilesTotal = 0; - Command.Empty(); - FileName.Empty(); -} - -void CProgressBox::Init(const char *title) -{ - _title = title; - _wasPrinted = false; - StartTick = GetTickCount(); - _prevTick = StartTick; - _prevElapsedSec = 0; -} - -static unsigned GetPower32(UInt32 val) -{ - const unsigned kStart = 32; - UInt32 mask = ((UInt32)1 << (kStart - 1)); - for (unsigned i = kStart;; i--) - { - if (i == 0 || (val & mask) != 0) - return i; - mask >>= 1; - } -} - -static unsigned GetPower64(UInt64 val) -{ - UInt32 high = (UInt32)(val >> 32); - if (high == 0) - return GetPower32((UInt32)val); - return GetPower32(high) + 32; -} - -static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider) -{ - unsigned pow1 = GetPower64(mult1); - unsigned pow2 = GetPower64(mult2); - while (pow1 + pow2 > 64) - { - if (pow1 > pow2) { pow1--; mult1 >>= 1; } - else { pow2--; mult2 >>= 1; } - divider >>= 1; - } - UInt64 res = mult1 * mult2; - if (divider != 0) - res /= divider; - return res; -} - -#define UINT_TO_STR_2(val) { s[0] = (char)('0' + (val) / 10); s[1] = (char)('0' + (val) % 10); s += 2; } - -static void GetTimeString(UInt64 timeValue, char *s) -{ - const UInt64 hours = timeValue / 3600; - UInt32 seconds = (UInt32)(timeValue - hours * 3600); - const UInt32 minutes = seconds / 60; - seconds %= 60; - if (hours > 99) - { - ConvertUInt64ToString(hours, s); - for (; *s != 0; s++); - } - else - { - const UInt32 hours32 = (UInt32)hours; - UINT_TO_STR_2(hours32) - } - *s++ = ':'; UINT_TO_STR_2(minutes) - *s++ = ':'; UINT_TO_STR_2(seconds) - *s = 0; -} - -void CProgressBox::ReduceString(const UString &src, AString &dest) -{ - UnicodeStringToMultiByte2(dest, src, CP_OEMCP); - - if (dest.Len() <= MaxLen) - return; - unsigned len = FileName.Len(); - for (; len != 0;) - { - unsigned delta = len / 8; - if (delta == 0) - delta = 1; - len -= delta; - _tempU = FileName; - _tempU.Delete(len / 2, FileName.Len() - len); - _tempU.Insert(len / 2, L" . "); - UnicodeStringToMultiByte2(dest, _tempU, CP_OEMCP); - if (dest.Len() <= MaxLen) - return; - } - dest.Empty(); -} - -static void Print_UInt64_and_String(AString &s, UInt64 val, const char *name) -{ - char temp[32]; - ConvertUInt64ToString(val, temp); - s += temp; - s.Add_Space(); - s += name; -} - - -static void PrintSize_bytes_Smart(AString &s, UInt64 val) -{ - // Print_UInt64_and_String(s, val, "bytes"); - { - char temp[32]; - ConvertUInt64ToString(val, temp); - s += temp; - } - - if (val == 0) - return; - - unsigned numBits = 10; - char c = 'K'; - char temp[4] = { 'K', 'i', 'B', 0 }; - if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; } - else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; } - temp[0] = c; - s += " ("; - Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp); - s += ')'; -} - - -static const unsigned kPercentsSize = 4; - -void CProgressBox::Print() -{ - DWORD tick = GetTickCount(); - DWORD elapsedTicks = tick - StartTick; - DWORD elapsedSec = elapsedTicks / 1000; - - if (_wasPrinted) - { - if (elapsedSec == _prevElapsedSec) - { - if ((UInt32)(tick - _prevTick) < _tickStep) - return; - if (_printedState.IsEqualTo((const CPercentPrinterState &)*this)) - return; - } - } - - UInt64 cur = Completed; - UInt64 total = Total; - - if (!UseBytesForPercents) - { - cur = Files; - total = FilesTotal; - } - - { - _timeStr.Empty(); - _timeStr = "Elapsed time: "; - char s[40]; - GetTimeString(elapsedSec, s); - _timeStr += s; - - if (cur != 0) - { - UInt64 remainingTime = 0; - if (cur < total) - remainingTime = MyMultAndDiv(elapsedTicks, total - cur, cur); - UInt64 remainingSec = remainingTime / 1000; - _timeStr += " Remaining time: "; - - GetTimeString(remainingSec, s); - _timeStr += s; - } - } - - - { - _perc.Empty(); - char s[32]; - unsigned size; - { - UInt64 val = 0; - if (total != (UInt64)(Int64)-1 && total != 0) - val = cur * 100 / Total; - - ConvertUInt64ToString(val, s); - size = (unsigned)strlen(s); - s[size++] = '%'; - s[size] = 0; - } - - unsigned len = size; - while (len < kPercentsSize) - len = kPercentsSize; - len++; - - if (len < MaxLen) - { - unsigned numChars = MaxLen - len; - unsigned filled = 0; - if (total != (UInt64)(Int64)-1 && total != 0) - filled = (unsigned)(cur * numChars / total); - if (filled > numChars) - filled = numChars; - unsigned i = 0; - for (i = 0; i < filled; i++) - _perc += (char)(Byte)0xDB; // '='; - for (; i < numChars; i++) - _perc += (char)(Byte)0xB0; // '.'; - } - - _perc.Add_Space(); - while (size < kPercentsSize) - { - _perc.Add_Space(); - size++; - } - _perc += s; - } - - _files.Empty(); - if (Files != 0 || FilesTotal != 0) - { - _files += "Files: "; - char s[32]; - // if (Files != 0) - { - ConvertUInt64ToString(Files, s); - _files += s; - } - if (FilesTotal != 0) - { - _files += " / "; - ConvertUInt64ToString(FilesTotal, s); - _files += s; - } - } - - _sizesStr.Empty(); - if (Total != 0) - { - _sizesStr += "Size: "; - PrintSize_bytes_Smart(_sizesStr, Completed); - if (Total != 0 && Total != (UInt64)(Int64)-1) - { - _sizesStr += " / "; - PrintSize_bytes_Smart(_sizesStr, Total); - } - } - - _name1.Empty(); - _name2.Empty(); - - if (!FileName.IsEmpty()) - { - _name1U.Empty(); - _name2U.Empty(); - - /* - if (_isDir) - s1 = _filePath; - else - */ - { - const int slashPos = FileName.ReverseFind_PathSepar(); - if (slashPos >= 0) - { - _name1U.SetFrom(FileName, (unsigned)(slashPos + 1)); - _name2U = FileName.Ptr(slashPos + 1); - } - else - _name2U = FileName; - } - ReduceString(_name1U, _name1); - ReduceString(_name2U, _name2); - } - - { - const char *strings[] = { _title, _timeStr, _files, _sizesStr, Command, _name1, _name2, _perc }; - NFar::g_StartupInfo.ShowMessage(FMSG_LEFTALIGN, NULL, strings, Z7_ARRAY_SIZE(strings), 0); - } - - _wasPrinted = true; - _printedState = *this; - _prevTick = tick; - _prevElapsedSec = elapsedSec; -} +// ProgressBox.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "FarUtils.h" +#include "ProgressBox.h" + +void CPercentPrinterState::ClearCurState() +{ + Completed = 0; + Total = ((UInt64)(Int64)-1); + Files = 0; + FilesTotal = 0; + Command.Empty(); + FileName.Empty(); +} + +void CProgressBox::Init(const char *title) +{ + _title = title; + _wasPrinted = false; + StartTick = GetTickCount(); + _prevTick = StartTick; + _prevElapsedSec = 0; +} + +static unsigned GetPower32(UInt32 val) +{ + const unsigned kStart = 32; + UInt32 mask = ((UInt32)1 << (kStart - 1)); + for (unsigned i = kStart;; i--) + { + if (i == 0 || (val & mask) != 0) + return i; + mask >>= 1; + } +} + +static unsigned GetPower64(UInt64 val) +{ + UInt32 high = (UInt32)(val >> 32); + if (high == 0) + return GetPower32((UInt32)val); + return GetPower32(high) + 32; +} + +static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider) +{ + unsigned pow1 = GetPower64(mult1); + unsigned pow2 = GetPower64(mult2); + while (pow1 + pow2 > 64) + { + if (pow1 > pow2) { pow1--; mult1 >>= 1; } + else { pow2--; mult2 >>= 1; } + divider >>= 1; + } + UInt64 res = mult1 * mult2; + if (divider != 0) + res /= divider; + return res; +} + +#define UINT_TO_STR_2(val) { s[0] = (char)('0' + (val) / 10); s[1] = (char)('0' + (val) % 10); s += 2; } + +static void GetTimeString(UInt64 timeValue, char *s) +{ + const UInt64 hours = timeValue / 3600; + UInt32 seconds = (UInt32)(timeValue - hours * 3600); + const UInt32 minutes = seconds / 60; + seconds %= 60; + if (hours > 99) + { + ConvertUInt64ToString(hours, s); + for (; *s != 0; s++); + } + else + { + const UInt32 hours32 = (UInt32)hours; + UINT_TO_STR_2(hours32) + } + *s++ = ':'; UINT_TO_STR_2(minutes) + *s++ = ':'; UINT_TO_STR_2(seconds) + *s = 0; +} + +void CProgressBox::ReduceString(const UString &src, AString &dest) +{ + UnicodeStringToMultiByte2(dest, src, CP_OEMCP); + + if (dest.Len() <= MaxLen) + return; + unsigned len = FileName.Len(); + for (; len != 0;) + { + unsigned delta = len / 8; + if (delta == 0) + delta = 1; + len -= delta; + _tempU = FileName; + _tempU.Delete(len / 2, FileName.Len() - len); + _tempU.Insert(len / 2, L" . "); + UnicodeStringToMultiByte2(dest, _tempU, CP_OEMCP); + if (dest.Len() <= MaxLen) + return; + } + dest.Empty(); +} + +static void Print_UInt64_and_String(AString &s, UInt64 val, const char *name) +{ + char temp[32]; + ConvertUInt64ToString(val, temp); + s += temp; + s.Add_Space(); + s += name; +} + + +static void PrintSize_bytes_Smart(AString &s, UInt64 val) +{ + // Print_UInt64_and_String(s, val, "bytes"); + { + char temp[32]; + ConvertUInt64ToString(val, temp); + s += temp; + } + + if (val == 0) + return; + + unsigned numBits = 10; + char c = 'K'; + char temp[4] = { 'K', 'i', 'B', 0 }; + if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; } + else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; } + temp[0] = c; + s += " ("; + Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp); + s += ')'; +} + + +static const unsigned kPercentsSize = 4; + +void CProgressBox::Print() +{ + DWORD tick = GetTickCount(); + DWORD elapsedTicks = tick - StartTick; + DWORD elapsedSec = elapsedTicks / 1000; + + if (_wasPrinted) + { + if (elapsedSec == _prevElapsedSec) + { + if ((UInt32)(tick - _prevTick) < _tickStep) + return; + if (_printedState.IsEqualTo((const CPercentPrinterState &)*this)) + return; + } + } + + UInt64 cur = Completed; + UInt64 total = Total; + + if (!UseBytesForPercents) + { + cur = Files; + total = FilesTotal; + } + + { + _timeStr.Empty(); + _timeStr = "Elapsed time: "; + char s[40]; + GetTimeString(elapsedSec, s); + _timeStr += s; + + if (cur != 0) + { + UInt64 remainingTime = 0; + if (cur < total) + remainingTime = MyMultAndDiv(elapsedTicks, total - cur, cur); + UInt64 remainingSec = remainingTime / 1000; + _timeStr += " Remaining time: "; + + GetTimeString(remainingSec, s); + _timeStr += s; + } + } + + + { + _perc.Empty(); + char s[32]; + unsigned size; + { + UInt64 val = 0; + if (total != (UInt64)(Int64)-1 && total != 0) + val = cur * 100 / Total; + + ConvertUInt64ToString(val, s); + size = (unsigned)strlen(s); + s[size++] = '%'; + s[size] = 0; + } + + unsigned len = size; + while (len < kPercentsSize) + len = kPercentsSize; + len++; + + if (len < MaxLen) + { + unsigned numChars = MaxLen - len; + unsigned filled = 0; + if (total != (UInt64)(Int64)-1 && total != 0) + filled = (unsigned)(cur * numChars / total); + if (filled > numChars) + filled = numChars; + unsigned i = 0; + for (i = 0; i < filled; i++) + _perc += (char)(Byte)0xDB; // '='; + for (; i < numChars; i++) + _perc += (char)(Byte)0xB0; // '.'; + } + + _perc.Add_Space(); + while (size < kPercentsSize) + { + _perc.Add_Space(); + size++; + } + _perc += s; + } + + _files.Empty(); + if (Files != 0 || FilesTotal != 0) + { + _files += "Files: "; + char s[32]; + // if (Files != 0) + { + ConvertUInt64ToString(Files, s); + _files += s; + } + if (FilesTotal != 0) + { + _files += " / "; + ConvertUInt64ToString(FilesTotal, s); + _files += s; + } + } + + _sizesStr.Empty(); + if (Total != 0) + { + _sizesStr += "Size: "; + PrintSize_bytes_Smart(_sizesStr, Completed); + if (Total != 0 && Total != (UInt64)(Int64)-1) + { + _sizesStr += " / "; + PrintSize_bytes_Smart(_sizesStr, Total); + } + } + + _name1.Empty(); + _name2.Empty(); + + if (!FileName.IsEmpty()) + { + _name1U.Empty(); + _name2U.Empty(); + + /* + if (_isDir) + s1 = _filePath; + else + */ + { + const int slashPos = FileName.ReverseFind_PathSepar(); + if (slashPos >= 0) + { + _name1U.SetFrom(FileName, (unsigned)(slashPos + 1)); + _name2U = FileName.Ptr(slashPos + 1); + } + else + _name2U = FileName; + } + ReduceString(_name1U, _name1); + ReduceString(_name2U, _name2); + } + + { + const char *strings[] = { _title, _timeStr, _files, _sizesStr, Command, _name1, _name2, _perc }; + NFar::g_StartupInfo.ShowMessage(FMSG_LEFTALIGN, NULL, strings, Z7_ARRAY_SIZE(strings), 0); + } + + _wasPrinted = true; + _printedState = *this; + _prevTick = tick; + _prevElapsedSec = elapsedSec; +} diff --git a/CPP/7zip/UI/Far/ProgressBox.h b/CPP/7zip/UI/Far/ProgressBox.h index ba35a2ac4..f6b36c45b 100644 --- a/CPP/7zip/UI/Far/ProgressBox.h +++ b/CPP/7zip/UI/Far/ProgressBox.h @@ -1,83 +1,85 @@ -// ProgressBox.h - -#ifndef ZIP7_INC_PROGRESS_BOX_H -#define ZIP7_INC_PROGRESS_BOX_H - -#include "../../../Common/MyString.h" -#include "../../../Common/MyTypes.h" - -struct CPercentPrinterState -{ - UInt64 Completed; - UInt64 Total; - - UInt64 Files; - UInt64 FilesTotal; - - AString Command; - UString FileName; - - void ClearCurState(); - - bool IsEqualTo(const CPercentPrinterState &s) const - { - return - Completed == s.Completed - && Total == s.Total - && Files == s.Files - && FilesTotal == s.FilesTotal - && Command == s.Command - && FileName == s.FileName; - } - - CPercentPrinterState(): - Completed(0), - Total((UInt64)(Int64)-1), - Files(0), - FilesTotal(0) - {} -}; - -class CProgressBox: public CPercentPrinterState -{ - UInt32 _tickStep; - DWORD _prevTick; - DWORD _prevElapsedSec; - - bool _wasPrinted; - - UString _tempU; - UString _name1U; - UString _name2U; - - CPercentPrinterState _printedState; - - AString _title; - - AString _timeStr; - AString _files; - AString _sizesStr; - AString _name1; - AString _name2; - AString _perc; - - void ReduceString(const UString &src, AString &dest); - -public: - DWORD StartTick; - bool UseBytesForPercents; - unsigned MaxLen; - - CProgressBox(UInt32 tickStep = 200): - _tickStep(tickStep), - _prevTick(0), - StartTick(0), - UseBytesForPercents(true), - MaxLen(60) - {} - - void Init(const char *title); - void Print(); -}; - -#endif +// ProgressBox.h + +#ifndef ZIP7_INC_PROGRESS_BOX_H +#define ZIP7_INC_PROGRESS_BOX_H + +#include "../../../Common/MyString.h" +#include "../../../Common/MyTypes.h" + +struct CPercentPrinterState +{ + UInt64 Completed; + UInt64 Total; + + UInt64 Files; + UInt64 FilesTotal; + + AString Command; + UString FileName; + + void ClearCurState(); + + bool IsEqualTo(const CPercentPrinterState &s) const + { + return + Completed == s.Completed + && Total == s.Total + && Files == s.Files + && FilesTotal == s.FilesTotal + && Command == s.Command + && FileName == s.FileName; + } + + CPercentPrinterState(): + Completed(0), + Total((UInt64)(Int64)-1), + Files(0), + FilesTotal(0) + {} +}; + +class CProgressBox: public CPercentPrinterState +{ + UInt32 _tickStep; + DWORD _prevTick; + DWORD _prevElapsedSec; + + bool _wasPrinted; +public: + bool UseBytesForPercents; + DWORD StartTick; + unsigned MaxLen; + +private: + UString _tempU; + UString _name1U; + UString _name2U; + + CPercentPrinterState _printedState; + + AString _title; + + AString _timeStr; + AString _files; + AString _sizesStr; + AString _name1; + AString _name2; + AString _perc; + + void ReduceString(const UString &src, AString &dest); + +public: + + CProgressBox(UInt32 tickStep = 200): + _tickStep(tickStep), + _prevTick(0), + UseBytesForPercents(true), + StartTick(0), + MaxLen(60) + {} + + void Init(const char *title); + void Print(); +}; + +#endif diff --git a/CPP/7zip/UI/Far/StdAfx.cpp b/CPP/7zip/UI/Far/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/Far/StdAfx.cpp +++ b/CPP/7zip/UI/Far/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/Far/StdAfx.h b/CPP/7zip/UI/Far/StdAfx.h index 19f96f87b..035267ccd 100644 --- a/CPP/7zip/UI/Far/StdAfx.h +++ b/CPP/7zip/UI/Far/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../../Common/Common.h" + +#endif diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp index 7fceacfb8..16702d3bb 100644 --- a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp +++ b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp @@ -1,237 +1,327 @@ -// UpdateCallbackFar.cpp - -#include "StdAfx.h" - -#ifndef Z7_ST -#include "../../../Windows/Synchronization.h" -#endif - -#include "../../../Common/StringConvert.h" - -#include "FarUtils.h" -#include "UpdateCallbackFar.h" - -using namespace NWindows; -using namespace NFar; - -#ifndef Z7_ST -static NSynchronization::CCriticalSection g_CriticalSection; -#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); -#else -#define MT_LOCK -#endif - -static HRESULT CheckBreak2() -{ - return WasEscPressed() ? E_ABORT : S_OK; -} - - -Z7_COM7F_IMF(CUpdateCallback100Imp::ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */)) -{ - MT_LOCK - - if (_percent) - { - _percent->FilesTotal = numFolders + numFiles; - _percent->Total = totalSize; - _percent->Command = "Scanning"; - _percent->FileName = path; - _percent->Print(); - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode)) -{ - if (ShowSysErrorMessage(errorCode, path) == -1) - return E_ABORT; - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles)) -{ - MT_LOCK - - if (_percent) - { - _percent->FilesTotal = numFiles; - _percent->Print(); - } - return CheckBreak2(); -} - - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)) -{ - MT_LOCK - return CheckBreak2(); -} - - - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(UInt64 size)) -{ - MT_LOCK - - if (_percent) - { - _percent->Total = size; - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 *completeValue)) -{ - MT_LOCK - - if (_percent) - { - if (completeValue) - _percent->Completed = *completeValue; - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::CompressOperation(const wchar_t *name)) -{ - MT_LOCK - - if (_percent) - { - _percent->Command = "Adding"; - _percent->FileName = name; - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::DeleteOperation(const wchar_t *name)) -{ - MT_LOCK - - if (_percent) - { - _percent->Command = "Deleting"; - _percent->FileName = name; - _percent->Print(); - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::OperationResult(Int32 /* opRes */)) -{ - MT_LOCK - - if (_percent) - { - _percent->Files++; - } - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message)) -{ - MT_LOCK - - if (g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)) == -1) - return E_ABORT; - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode)) -{ - if (ShowSysErrorMessage(errorCode, path) == -1) - return E_ABORT; - return CheckBreak2(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode)) -{ - if (ShowSysErrorMessage(errorCode, path) == -1) - return E_ABORT; - return CheckBreak2(); -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s); - -Z7_COM7F_IMF(CUpdateCallback100Imp::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)) -{ - MT_LOCK - - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - AString s; - SetExtractErrorMessage(opRes, isEncrypted, s); - if (PrintErrorMessage(s, name) == -1) - return E_ABORT; - } - - return CheckBreak2(); -} - - -Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 op, const wchar_t *name, Int32 /* isDir */)) -{ - const char *s; - switch (op) - { - case NUpdateNotifyOp::kAdd: s = "Adding"; break; - case NUpdateNotifyOp::kUpdate: s = "Updating"; break; - case NUpdateNotifyOp::kAnalyze: s = "Analyzing"; break; - case NUpdateNotifyOp::kReplicate: s = "Replicating"; break; - case NUpdateNotifyOp::kRepack: s = "Repacking"; break; - case NUpdateNotifyOp::kSkip: s = "Skipping"; break; - case NUpdateNotifyOp::kHeader: s = "Header creating"; break; - case NUpdateNotifyOp::kDelete: s = "Deleting"; break; - default: s = "Unknown operation"; - } - - MT_LOCK - - if (_percent) - { - _percent->Command = s; - _percent->FileName.Empty(); - if (name) - _percent->FileName = name; - _percent->Print(); - } - - return CheckBreak2(); -} - - -extern HRESULT GetPassword(UString &password); - -Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password)) -{ - MT_LOCK - - *password = NULL; - if (!PasswordIsDefined) - { - RINOK(GetPassword(Password)) - PasswordIsDefined = true; - } - return StringToBstr(Password, password); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) -{ - MT_LOCK - - *password = NULL; - *passwordIsDefined = BoolToInt(PasswordIsDefined); - if (!PasswordIsDefined) - return S_OK; - return StringToBstr(Password, password); -} +// UpdateCallbackFar.cpp + +#include "StdAfx.h" + +#ifndef Z7_ST +#include "../../../Windows/Synchronization.h" +#endif + +#include "../../../Common/StringConvert.h" + +#include "FarUtils.h" +#include "UpdateCallbackFar.h" + +using namespace NWindows; +using namespace NFar; + +#ifndef Z7_ST +static NSynchronization::CCriticalSection g_CriticalSection; +#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); +#else +#define MT_LOCK +#endif + +static HRESULT CheckBreak2() +{ + return WasEscPressed() ? E_ABORT : S_OK; +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */)) +{ + MT_LOCK + + if (_percent) + { + _percent->FilesTotal = numFolders + numFiles; + _percent->Total = totalSize; + _percent->Command = "Scanning"; + _percent->FileName = path; + _percent->Print(); + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode)) +{ + if (ShowSysErrorMessage(errorCode, path) == -1) + return E_ABORT; + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles)) +{ + MT_LOCK + + if (_percent) + { + _percent->FilesTotal = numFiles; + _percent->Print(); + } + return CheckBreak2(); +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)) +{ + MT_LOCK + return CheckBreak2(); +} + + + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(UInt64 size)) +{ + MT_LOCK + + if (_percent) + { + _percent->Total = size; + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 *completeValue)) +{ + MT_LOCK + + if (_percent) + { + if (completeValue) + _percent->Completed = *completeValue; + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::CompressOperation(const wchar_t *name)) +{ + MT_LOCK + + if (_percent) + { + _percent->Command = "Adding"; + _percent->FileName = name; + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::DeleteOperation(const wchar_t *name)) +{ + MT_LOCK + + if (_percent) + { + _percent->Command = "Deleting"; + _percent->FileName = name; + _percent->Print(); + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::OperationResult(Int32 /* opRes */)) +{ + MT_LOCK + + if (_percent) + { + _percent->Files++; + } + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message)) +{ + MT_LOCK + + if (g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)) == -1) + return E_ABORT; + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode)) +{ + if (ShowSysErrorMessage(errorCode, path) == -1) + return E_ABORT; + return CheckBreak2(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode)) +{ + if (ShowSysErrorMessage(errorCode, path) == -1) + return E_ABORT; + return CheckBreak2(); +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s); + +Z7_COM7F_IMF(CUpdateCallback100Imp::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)) +{ + MT_LOCK + + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + AString s; + SetExtractErrorMessage(opRes, isEncrypted, s); + if (PrintErrorMessage(s, name) == -1) + return E_ABORT; + } + + return CheckBreak2(); +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 op, const wchar_t *name, Int32 /* isDir */)) +{ + const char *s; + switch (op) + { + case NUpdateNotifyOp::kAdd: s = "Adding"; break; + case NUpdateNotifyOp::kUpdate: s = "Updating"; break; + case NUpdateNotifyOp::kAnalyze: s = "Analyzing"; break; + case NUpdateNotifyOp::kReplicate: s = "Replicating"; break; + case NUpdateNotifyOp::kRepack: s = "Repacking"; break; + case NUpdateNotifyOp::kSkip: s = "Skipping"; break; + case NUpdateNotifyOp::kHeader: s = "Header creating"; break; + case NUpdateNotifyOp::kDelete: s = "Deleting"; break; + default: s = "Unknown operation"; + } + + MT_LOCK + + if (_percent) + { + _percent->Command = s; + _percent->FileName.Empty(); + if (name) + _percent->FileName = name; + _percent->Print(); + } + + return CheckBreak2(); +} + + +HRESULT CUpdateCallback100Imp::MoveArc_UpdateStatus() +{ + MT_LOCK + + if (_percent) + { + AString s; + s.Add_UInt64(_arcMoving_percents); + // status.Add_Space(); + s.Add_Char('%'); + const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1); + if (_arcMoving_current != 0 || totalDefined) + { + s += " : "; + s.Add_UInt64(_arcMoving_current >> 20); + s += " MiB"; + } + if (totalDefined) + { + s += " / "; + s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20); + s += " MiB"; + } + s += " : temporary archive moving ..."; + _percent->Command = s; + _percent->Print(); + } + + return CheckBreak2(); +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Start(const wchar_t *srcTempPath, const wchar_t * /* destFinalPath */ , UInt64 size, Int32 /* updateMode */)) +{ + MT_LOCK + + _arcMoving_total = size; + _arcMoving_current = 0; + _arcMoving_percents = 0; + // _arcMoving_updateMode = updateMode; + // _name2 = fs2us(destFinalPath); + if (_percent) + _percent->FileName = srcTempPath; + return MoveArc_UpdateStatus(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)) +{ + UInt64 percents = 0; + if (totalSize != 0) + { + if (totalSize < ((UInt64)1 << 57)) + percents = currentSize * 100 / totalSize; + else + percents = currentSize / (totalSize / 100); + } + +#ifdef _WIN32 + // Sleep(300); // for debug +#endif + if (percents == _arcMoving_percents) + return CheckBreak2(); + _arcMoving_total = totalSize; + _arcMoving_current = currentSize; + _arcMoving_percents = percents; + // if (_arcMoving_percents > 100) return E_FAIL; + return MoveArc_UpdateStatus(); +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Finish()) +{ + // _arcMoving_percents = 0; + if (_percent) + { + _percent->Command.Empty(); + _percent->FileName.Empty(); + _percent->Print(); + } + return CheckBreak2(); +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::Before_ArcReopen()) +{ + // fixme: we can use Clear_Stop_Status() here + return CheckBreak2(); +} + + +extern HRESULT GetPassword(UString &password); + +Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password)) +{ + MT_LOCK + + *password = NULL; + if (!PasswordIsDefined) + { + RINOK(GetPassword(Password)) + PasswordIsDefined = true; + } + return StringToBstr(Password, password); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) +{ + MT_LOCK + + *password = NULL; + *passwordIsDefined = BoolToInt(PasswordIsDefined); + if (!PasswordIsDefined) + return S_OK; + return StringToBstr(Password, password); +} diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.h b/CPP/7zip/UI/Far/UpdateCallbackFar.h index e20a20d1d..8d2c8b8a1 100644 --- a/CPP/7zip/UI/Far/UpdateCallbackFar.h +++ b/CPP/7zip/UI/Far/UpdateCallbackFar.h @@ -1,44 +1,58 @@ -// UpdateCallbackFar.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK_FAR_H -#define ZIP7_INC_UPDATE_CALLBACK_FAR_H - -#include "../../../Common/MyCom.h" - -#include "../../IPassword.h" - -#include "../Agent/IFolderArchive.h" - -#include "ProgressBox.h" - -Z7_CLASS_IMP_COM_6( - CUpdateCallback100Imp - , IFolderArchiveUpdateCallback - , IFolderArchiveUpdateCallback2 - , IFolderScanProgress - , ICryptoGetTextPassword2 - , ICryptoGetTextPassword - , IArchiveOpenCallback -) - Z7_IFACE_COM7_IMP(IProgress) - - // CMyComPtr _archiveHandler; - CProgressBox *_percent; - // UInt64 _total; -public: - bool PasswordIsDefined; - UString Password; - - CUpdateCallback100Imp() - // : _total(0) - {} - void Init(/* IInFolderArchive *archiveHandler, */ CProgressBox *progressBox) - { - // _archiveHandler = archiveHandler; - _percent = progressBox; - PasswordIsDefined = false; - Password.Empty(); - } -}; - -#endif +// UpdateCallbackFar.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK_FAR_H +#define ZIP7_INC_UPDATE_CALLBACK_FAR_H + +#include "../../../Common/MyCom.h" + +#include "../../IPassword.h" + +#include "../Agent/IFolderArchive.h" + +#include "ProgressBox.h" + +Z7_CLASS_IMP_COM_7( + CUpdateCallback100Imp + , IFolderArchiveUpdateCallback + , IFolderArchiveUpdateCallback2 + , IFolderArchiveUpdateCallback_MoveArc + , IFolderScanProgress + , ICryptoGetTextPassword2 + , ICryptoGetTextPassword + , IArchiveOpenCallback +) + Z7_IFACE_COM7_IMP(IProgress) + + // CMyComPtr _archiveHandler; + CProgressBox *_percent; + // UInt64 _total; + + HRESULT MoveArc_UpdateStatus(); + +private: + UInt64 _arcMoving_total; + UInt64 _arcMoving_current; + UInt64 _arcMoving_percents; + // Int32 _arcMoving_updateMode; + +public: + bool PasswordIsDefined; + UString Password; + + CUpdateCallback100Imp() + // : _total(0) + {} + void Init(/* IInFolderArchive *archiveHandler, */ CProgressBox *progressBox) + { + // _archiveHandler = archiveHandler; + _percent = progressBox; + PasswordIsDefined = false; + Password.Empty(); + _arcMoving_total = 0; + _arcMoving_current = 0; + _arcMoving_percents = 0; + // _arcMoving_updateMode = 0; + } +}; + +#endif diff --git a/CPP/7zip/UI/Far/makefile b/CPP/7zip/UI/Far/makefile index 052c56e81..a66f9d766 100644 --- a/CPP/7zip/UI/Far/makefile +++ b/CPP/7zip/UI/Far/makefile @@ -1,107 +1,107 @@ -PROG = 7-ZipFar.dll -DEF_FILE = Far.def -CFLAGS = $(CFLAGS) \ - -DZ7_EXTERNAL_CODECS \ - -!IFNDEF UNDER_CE -# CFLAGS = $(CFLAGS) -DZ7_LONG_PATH -# -DZ7_NO_LARGE_PAGES -!ENDIF - -CURRENT_OBJS = \ - $O\ExtractEngine.obj \ - $O\FarUtils.obj \ - $O\Far.obj \ - $O\OverwriteDialogFar.obj \ - $O\Plugin.obj \ - $O\PluginCommon.obj \ - $O\PluginDelete.obj \ - $O\PluginRead.obj \ - $O\PluginWrite.obj \ - $O\ProgressBox.obj \ - $O\UpdateCallbackFar.obj \ - -COMMON_OBJS = \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\NewHandler.obj \ - $O\MyString.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\MyVector.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\FileSystem.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Registry.obj \ - $O\ResourceString.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodProps.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveOpenCallback.obj \ - $O\DefaultName.obj \ - $O\EnumDirItems.obj \ - $O\ExtractingFilePath.obj \ - $O\HashCalc.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - $O\PropIDUtils.obj \ - $O\SetProperties.obj \ - $O\SortUtils.obj \ - $O\UpdateAction.obj \ - $O\UpdateCallback.obj \ - $O\UpdatePair.obj \ - $O\UpdateProduce.obj \ - $O\WorkDir.obj \ - $O\ZipRegistry.obj \ - -AR_COMMON_OBJS = \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - -AGENT_OBJS = \ - $O\Agent.obj \ - $O\AgentOut.obj \ - $O\AgentProxy.obj \ - $O\ArchiveFolder.obj \ - $O\ArchiveFolderOut.obj \ - $O\UpdateCallbackAgent.obj \ - -COMPRESS_OBJS = \ - $O\CopyCoder.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" - -!include "../../7zip.mak" +PROG = 7-ZipFar.dll +DEF_FILE = Far.def +CFLAGS = $(CFLAGS) \ + -DZ7_EXTERNAL_CODECS \ + +!IFNDEF UNDER_CE +# CFLAGS = $(CFLAGS) -DZ7_LONG_PATH +# -DZ7_NO_LARGE_PAGES +!ENDIF + +CURRENT_OBJS = \ + $O\ExtractEngine.obj \ + $O\FarUtils.obj \ + $O\Far.obj \ + $O\OverwriteDialogFar.obj \ + $O\Plugin.obj \ + $O\PluginCommon.obj \ + $O\PluginDelete.obj \ + $O\PluginRead.obj \ + $O\PluginWrite.obj \ + $O\ProgressBox.obj \ + $O\UpdateCallbackFar.obj \ + +COMMON_OBJS = \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\MyString.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\MyVector.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\FileSystem.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Registry.obj \ + $O\ResourceString.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodProps.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveOpenCallback.obj \ + $O\DefaultName.obj \ + $O\EnumDirItems.obj \ + $O\ExtractingFilePath.obj \ + $O\HashCalc.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + $O\PropIDUtils.obj \ + $O\SetProperties.obj \ + $O\SortUtils.obj \ + $O\UpdateAction.obj \ + $O\UpdateCallback.obj \ + $O\UpdatePair.obj \ + $O\UpdateProduce.obj \ + $O\WorkDir.obj \ + $O\ZipRegistry.obj \ + +AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + +AGENT_OBJS = \ + $O\Agent.obj \ + $O\AgentOut.obj \ + $O\AgentProxy.obj \ + $O\ArchiveFolder.obj \ + $O\ArchiveFolderOut.obj \ + $O\UpdateCallbackAgent.obj \ + +COMPRESS_OBJS = \ + $O\CopyCoder.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/Far/resource.rc b/CPP/7zip/UI/Far/resource.rc index 7d04d2d0a..a5c2e2f31 100644 --- a/CPP/7zip/UI/Far/resource.rc +++ b/CPP/7zip/UI/Far/resource.rc @@ -1,3 +1,3 @@ -#include "../../MyVersionInfo.rc" - -MY_VERSION_INFO_DLL("7-Zip Plugin for FAR Manager", "7-ZipFar") +#include "../../MyVersionInfo.rc" + +MY_VERSION_INFO_DLL("7-Zip Plugin for FAR Manager", "7-ZipFar") diff --git a/CPP/7zip/UI/FileManager/7zFM.exe.manifest b/CPP/7zip/UI/FileManager/7zFM.exe.manifest index bb47880d2..69c7f0bf3 100644 --- a/CPP/7zip/UI/FileManager/7zFM.exe.manifest +++ b/CPP/7zip/UI/FileManager/7zFM.exe.manifest @@ -1,23 +1,23 @@ - - - - 7-Zip File Manager. - - - - - - - - - - - - - true - - - - -true - + + + + 7-Zip File Manager. + + + + + + + + + + + + + true + + + + +true + diff --git a/CPP/7zip/UI/FileManager/AboutDialog.cpp b/CPP/7zip/UI/FileManager/AboutDialog.cpp index 722ad8176..efc74cc83 100644 --- a/CPP/7zip/UI/FileManager/AboutDialog.cpp +++ b/CPP/7zip/UI/FileManager/AboutDialog.cpp @@ -1,81 +1,81 @@ -// AboutDialog.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../MyVersion.h" - -#include "../Common/LoadCodecs.h" - -#include "AboutDialog.h" -#include "PropertyNameRes.h" - -#include "HelpUtils.h" -#include "LangUtils.h" - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_ABOUT_INFO -}; -#endif - -#define kHomePageURL TEXT("https://www.7-zip.org/") -#define kHelpTopic "start.htm" - -#define LLL_(quote) L##quote -#define LLL(quote) LLL_(quote) - -extern CCodecs *g_CodecsObj; - -bool CAboutDialog::OnInit() -{ - #ifdef Z7_EXTERNAL_CODECS - if (g_CodecsObj) - { - UString s; - g_CodecsObj->GetCodecsErrorMessage(s); - if (!s.IsEmpty()) - MessageBoxW(GetParent(), s, L"7-Zip", MB_ICONERROR); - } - #endif - - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_ABOUT); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - SetItemText(IDT_ABOUT_VERSION, UString("7-Zip " MY_VERSION_CPU)); - SetItemText(IDT_ABOUT_DATE, LLL(MY_DATE)); - - NormalizePosition(); - return CModalDialog::OnInit(); -} - -void CAboutDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); -} - -bool CAboutDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - LPCTSTR url; - switch (buttonID) - { - case IDB_ABOUT_HOMEPAGE: url = kHomePageURL; break; - default: - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); - } - - #ifdef UNDER_CE - SHELLEXECUTEINFO s; - memset(&s, 0, sizeof(s)); - s.cbSize = sizeof(s); - s.lpFile = url; - ::ShellExecuteEx(&s); - #else - ::ShellExecute(NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL); - #endif - - return true; -} +// AboutDialog.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../MyVersion.h" + +#include "../Common/LoadCodecs.h" + +#include "AboutDialog.h" +#include "PropertyNameRes.h" + +#include "HelpUtils.h" +#include "LangUtils.h" + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_ABOUT_INFO +}; +#endif + +#define kHomePageURL TEXT("https://www.7-zip.org/") +#define kHelpTopic "start.htm" + +#define LLL_(quote) L##quote +#define LLL(quote) LLL_(quote) + +extern CCodecs *g_CodecsObj; + +bool CAboutDialog::OnInit() +{ + #ifdef Z7_EXTERNAL_CODECS + if (g_CodecsObj) + { + UString s; + g_CodecsObj->GetCodecsErrorMessage(s); + if (!s.IsEmpty()) + MessageBoxW(GetParent(), s, L"7-Zip", MB_ICONERROR); + } + #endif + + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_ABOUT); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + SetItemText(IDT_ABOUT_VERSION, UString("7-Zip " MY_VERSION_CPU)); + SetItemText(IDT_ABOUT_DATE, LLL(MY_DATE)); + + NormalizePosition(); + return CModalDialog::OnInit(); +} + +void CAboutDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + +bool CAboutDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + LPCTSTR url; + switch (buttonID) + { + case IDB_ABOUT_HOMEPAGE: url = kHomePageURL; break; + default: + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); + } + + #ifdef UNDER_CE + SHELLEXECUTEINFO s; + memset(&s, 0, sizeof(s)); + s.cbSize = sizeof(s); + s.lpFile = url; + ::ShellExecuteEx(&s); + #else + ::ShellExecute(NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL); + #endif + + return true; +} diff --git a/CPP/7zip/UI/FileManager/AboutDialog.h b/CPP/7zip/UI/FileManager/AboutDialog.h index fe3e563b8..1d11d7495 100644 --- a/CPP/7zip/UI/FileManager/AboutDialog.h +++ b/CPP/7zip/UI/FileManager/AboutDialog.h @@ -1,19 +1,19 @@ -// AboutDialog.h - -#ifndef ZIP7_INC_ABOUT_DIALOG_H -#define ZIP7_INC_ABOUT_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" - -#include "AboutDialogRes.h" - -class CAboutDialog: public NWindows::NControl::CModalDialog -{ -public: - virtual bool OnInit() Z7_override; - virtual void OnHelp() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_ABOUT, wndParent); } -}; - -#endif +// AboutDialog.h + +#ifndef ZIP7_INC_ABOUT_DIALOG_H +#define ZIP7_INC_ABOUT_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" + +#include "AboutDialogRes.h" + +class CAboutDialog: public NWindows::NControl::CModalDialog +{ +public: + virtual bool OnInit() Z7_override; + virtual void OnHelp() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_ABOUT, wndParent); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/AboutDialog.rc b/CPP/7zip/UI/FileManager/AboutDialog.rc index 5c233d2eb..b235df0b0 100644 --- a/CPP/7zip/UI/FileManager/AboutDialog.rc +++ b/CPP/7zip/UI/FileManager/AboutDialog.rc @@ -1,26 +1,26 @@ -#include "AboutDialogRes.h" -#include "../../GuiCommon.rc" -#include "../../MyVersion.h" - -#define xc 144 -#define yc 144 - -#define y 93 - -IDI_LOGO ICON "../../UI/FileManager/7zipLogo.ico" - -#ifndef SS_REALSIZEIMAGE -#define SS_REALSIZEIMAGE 0x800 -#endif - -IDD_ABOUT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "About 7-Zip" -{ - DEFPUSHBUTTON "OK", IDOK, bx1, by, bxs, bys - PUSHBUTTON "www.7-zip.org", IDB_ABOUT_HOMEPAGE, bx2, by, bxs, bys - ICON IDI_LOGO, -1, m, m, 32, 32, SS_REALSIZEIMAGE - LTEXT "", IDT_ABOUT_VERSION, m, 54, xc, 8 - LTEXT "", IDT_ABOUT_DATE, m, 67, xc, 8 - LTEXT MY_COPYRIGHT, -1, m, 80, xc, 8 - LTEXT "7-Zip is free software", IDT_ABOUT_INFO, m, y, xc, (by - y - 1) -} +#include "AboutDialogRes.h" +#include "../../GuiCommon.rc" +#include "../../MyVersion.h" + +#define xc 144 +#define yc 144 + +#define y 93 + +IDI_LOGO ICON "../../UI/FileManager/7zipLogo.ico" + +#ifndef SS_REALSIZEIMAGE +#define SS_REALSIZEIMAGE 0x800 +#endif + +IDD_ABOUT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "About 7-Zip" +{ + DEFPUSHBUTTON "OK", IDOK, bx1, by, bxs, bys + PUSHBUTTON "www.7-zip.org", IDB_ABOUT_HOMEPAGE, bx2, by, bxs, bys + ICON IDI_LOGO, -1, m, m, 32, 32, SS_REALSIZEIMAGE + LTEXT "", IDT_ABOUT_VERSION, m, 54, xc, 8 + LTEXT "", IDT_ABOUT_DATE, m, 67, xc, 8 + LTEXT MY_COPYRIGHT, -1, m, 80, xc, 8 + LTEXT "7-Zip is free software", IDT_ABOUT_INFO, m, y, xc, (by - y - 1) +} diff --git a/CPP/7zip/UI/FileManager/AboutDialogRes.h b/CPP/7zip/UI/FileManager/AboutDialogRes.h index dfe223266..b41655804 100644 --- a/CPP/7zip/UI/FileManager/AboutDialogRes.h +++ b/CPP/7zip/UI/FileManager/AboutDialogRes.h @@ -1,8 +1,8 @@ -#define IDD_ABOUT 2900 - -#define IDT_ABOUT_INFO 2901 - -#define IDI_LOGO 100 -#define IDT_ABOUT_VERSION 101 -#define IDT_ABOUT_DATE 102 -#define IDB_ABOUT_HOMEPAGE 110 +#define IDD_ABOUT 2900 + +#define IDT_ABOUT_INFO 2901 + +#define IDI_LOGO 100 +#define IDT_ABOUT_VERSION 101 +#define IDT_ABOUT_DATE 102 +#define IDB_ABOUT_HOMEPAGE 110 diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp index f31504a45..685ac707d 100644 --- a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp +++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp @@ -1,946 +1,946 @@ -// AltStreamsFolder.cpp - -#include "StdAfx.h" - -#ifdef __MINGW32_VERSION -// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) -// for old mingw -#include -#else -#ifndef Z7_OLD_WIN_SDK - #if !defined(_M_IA64) - #include - #endif -#else -typedef LONG NTSTATUS; -typedef struct _IO_STATUS_BLOCK { - union { - NTSTATUS Status; - PVOID Pointer; - }; - ULONG_PTR Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; -#endif -#endif - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "../Common/ExtractingFilePath.h" - -#include "../Agent/IFolderArchive.h" - -#include "AltStreamsFolder.h" -#include "FSDrives.h" -#include "FSFolder.h" - -#include "SysIconUtils.h" - -using namespace NWindows; -using namespace NFile; -using namespace NFind; -using namespace NDir; -using namespace NName; - -#ifndef USE_UNICODE_FSTRING -int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); -#endif - -#ifndef UNDER_CE - -namespace NFsFolder -{ -bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size); -} - -#endif - -namespace NAltStreamsFolder { - -static const Byte kProps[] = -{ - kpidName, - kpidSize, - kpidPackSize -}; - -static unsigned GetFsParentPrefixSize(const FString &path) -{ - if (IsNetworkShareRootPath(path)) - return 0; - const unsigned prefixSize = GetRootPrefixSize(path); - if (prefixSize == 0 || prefixSize >= path.Len()) - return 0; - FString parentPath = path; - int pos = parentPath.ReverseFind_PathSepar(); - if (pos < 0) - return 0; - if (pos == (int)parentPath.Len() - 1) - { - parentPath.DeleteBack(); - pos = parentPath.ReverseFind_PathSepar(); - if (pos < 0) - return 0; - } - if ((unsigned)pos + 1 < prefixSize) - return 0; - return (unsigned)pos + 1; -} - -HRESULT CAltStreamsFolder::Init(const FString &path /* , IFolderFolder *parentFolder */) -{ - // _parentFolder = parentFolder; - if (path.Back() != ':') - return E_FAIL; - - _pathPrefix = path; - _pathBaseFile = path; - _pathBaseFile.DeleteBack(); - - { - CFileInfo fi; - if (!fi.Find(_pathBaseFile)) - return GetLastError_noZero_HRESULT(); - } - - unsigned prefixSize = GetFsParentPrefixSize(_pathBaseFile); - if (prefixSize == 0) - return S_OK; - FString parentPath = _pathBaseFile; - parentPath.DeleteFrom(prefixSize); - - _findChangeNotification.FindFirst(parentPath, false, - FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_ATTRIBUTES - | FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_LAST_WRITE - /* - | FILE_NOTIFY_CHANGE_LAST_ACCESS - | FILE_NOTIFY_CHANGE_CREATION - | FILE_NOTIFY_CHANGE_SECURITY - */ - ); - /* - if (_findChangeNotification.IsHandleAllocated()) - return S_OK; - return GetLastError(); - */ - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::LoadItems()) -{ - Int32 dummy; - WasChanged(&dummy); - Clear(); - - CStreamEnumerator enumerator(_pathBaseFile); - - CStreamInfo si; - for (;;) - { - bool found; - if (!enumerator.Next(si, found)) - { - // if (GetLastError() == ERROR_ACCESS_DENIED) - // break; - // return E_FAIL; - break; - } - if (!found) - break; - if (si.IsMainStream()) - continue; - CAltStream ss; - ss.Name = si.GetReducedName(); - if (!ss.Name.IsEmpty() && ss.Name[0] == ':') - ss.Name.Delete(0); - - ss.Size = si.Size; - ss.PackSize_Defined = false; - ss.PackSize = si.Size; - Streams.Add(ss); - } - - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = Streams.Size(); - return S_OK; -} - -#ifdef USE_UNICODE_FSTRING - -Z7_COM7F_IMF(CAltStreamsFolder::GetItemPrefix(UInt32 /* index */, const wchar_t **name, unsigned *len)) -{ - *name = NULL; - *len = 0; - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) -{ - *name = NULL; - *len = 0; - { - const CAltStream &ss = Streams[index]; - *name = ss.Name; - *len = ss.Name.Len(); - } - return S_OK; -} - -Z7_COM7F_IMF2(UInt64, CAltStreamsFolder::GetItemSize(UInt32 index)) -{ - return Streams[index].Size; -} - -#endif - - -Z7_COM7F_IMF(CAltStreamsFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - { - CAltStream &ss = Streams[index]; - switch (propID) - { - case kpidIsDir: prop = false; break; - case kpidIsAltStream: prop = true; break; - case kpidName: prop = ss.Name; break; - case kpidSize: prop = ss.Size; break; - case kpidPackSize: - #ifdef UNDER_CE - prop = ss.Size; - #else - if (!ss.PackSize_Defined) - { - ss.PackSize_Defined = true; - if (!NFsFolder::MyGetCompressedFileSizeW(_pathPrefix + us2fs(ss.Name), ss.PackSize)) - ss.PackSize = ss.Size; - } - prop = ss.PackSize; - #endif - break; - } - } - - prop.Detach(value); - return S_OK; -} - - -// returns Position of extension including '.' - -static inline const wchar_t *GetExtensionPtr(const UString &name) -{ - const int dotPos = name.ReverseFind_Dot(); - return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos); -} - -Z7_COM7F_IMF2(Int32, CAltStreamsFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */)) -{ - const CAltStream &ss1 = Streams[index1]; - const CAltStream &ss2 = Streams[index2]; - - switch (propID) - { - case kpidName: - { - return CompareFileNames_ForFolderList(ss1.Name, ss2.Name); - // return MyStringCompareNoCase(ss1.Name, ss2.Name); - } - case kpidSize: - return MyCompare(ss1.Size, ss2.Size); - case kpidPackSize: - { - #ifdef UNDER_CE - return MyCompare(ss1.Size, ss2.Size); - #else - // PackSize can be undefined here - return MyCompare( - ss1.PackSize, - ss2.PackSize); - #endif - } - - case kpidExtension: - return CompareFileNames_ForFolderList( - GetExtensionPtr(ss1.Name), - GetExtensionPtr(ss2.Name)); - } - - return 0; -} - -Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(UInt32 /* index */, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - return E_INVALIDARG; -} - -Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - return E_INVALIDARG; -} - -// static CFSTR const kSuperPrefix = FTEXT("\\\\?\\"); - -Z7_COM7F_IMF(CAltStreamsFolder::BindToParentFolder(IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - /* - if (_parentFolder) - { - CMyComPtr parentFolder = _parentFolder; - *resultFolder = parentFolder.Detach(); - return S_OK; - } - */ - - if (IsDriveRootPath_SuperAllowed(_pathBaseFile)) - { - CFSDrives *drivesFolderSpec = new CFSDrives; - CMyComPtr drivesFolder = drivesFolderSpec; - drivesFolderSpec->Init(); - *resultFolder = drivesFolder.Detach(); - return S_OK; - } - - /* - parentPath.DeleteFrom(pos + 1); - - if (parentPath == kSuperPrefix) - { - #ifdef UNDER_CE - *resultFolder = 0; - #else - CFSDrives *drivesFolderSpec = new CFSDrives; - CMyComPtr drivesFolder = drivesFolderSpec; - drivesFolderSpec->Init(false, true); - *resultFolder = drivesFolder.Detach(); - #endif - return S_OK; - } - - FString parentPathReduced = parentPath.Left(pos); - - #ifndef UNDER_CE - pos = parentPathReduced.ReverseFind_PathSepar(); - if (pos == 1) - { - if (!IS_PATH_SEPAR_CHAR(parentPath[0])) - return E_FAIL; - CNetFolder *netFolderSpec = new CNetFolder; - CMyComPtr netFolder = netFolderSpec; - netFolderSpec->Init(fs2us(parentPath)); - *resultFolder = netFolder.Detach(); - return S_OK; - } - #endif - - CFSFolder *parentFolderSpec = new CFSFolder; - CMyComPtr parentFolder = parentFolderSpec; - RINOK(parentFolderSpec->Init(parentPath, 0)); - *resultFolder = parentFolder.Detach(); - */ - - return S_OK; -} - -IMP_IFolderFolder_Props(CAltStreamsFolder) - -Z7_COM7F_IMF(CAltStreamsFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidType: prop = "AltStreamsFolder"; break; - case kpidPath: prop = fs2us(_pathPrefix); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CAltStreamsFolder::WasChanged(Int32 *wasChanged)) -{ - bool wasChangedMain = false; - for (;;) - { - if (!_findChangeNotification.IsHandleAllocated()) - { - *wasChanged = BoolToInt(false); - return S_OK; - } - - const DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); - const bool wasChangedLoc = (waitResult == WAIT_OBJECT_0); - if (wasChangedLoc) - { - _findChangeNotification.FindNext(); - wasChangedMain = true; - } - else - break; - } - *wasChanged = BoolToInt(wasChangedMain); - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::Clone(IFolderFolder **resultFolder)) -{ - CAltStreamsFolder *folderSpec = new CAltStreamsFolder; - CMyComPtr folderNew = folderSpec; - folderSpec->Init(_pathPrefix); - *resultFolder = folderNew.Detach(); - return S_OK; -} - -void CAltStreamsFolder::GetAbsPath(const wchar_t *name, FString &absPath) -{ - absPath.Empty(); - if (!IsAbsolutePath(name)) - absPath += _pathPrefix; - absPath += us2fs(name); -} - - - -static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, - const wchar_t *message, const FString &fileName) -{ - UString s = message; - s += " : "; - s += fs2us(fileName); - return callback->ShowMessage(s); -} - -static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback, - const wchar_t *message, const FString &fileName) -{ - UString s = message; - s += " : "; - s += fs2us(fileName); - return callback->UpdateErrorMessage(s); -} - -static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, - const char *message, const FString &fileName) -{ - return SendMessageError(callback, MultiByteToUnicodeString(message), fileName); -} - -/* -static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback, - const char *message, const FString &fileName) -{ - return SendMessageError(callback, MultiByteToUnicodeString(message), fileName); -} -*/ - -Z7_COM7F_IMF(CAltStreamsFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CAltStreamsFolder::CreateFile(const wchar_t *name, IProgress * /* progress */)) -{ - FString absPath; - GetAbsPath(name, absPath); - NIO::COutFile outFile; - if (!outFile.Create_NEW(absPath)) - return GetLastError_noZero_HRESULT(); - return S_OK; -} - -static UString GetLastErrorMessage() -{ - return NError::MyFormatMessage(GetLastError_noZero_HRESULT()); -} - -static HRESULT UpdateFile(NFsFolder::CCopyStateIO &state, CFSTR inPath, CFSTR outPath, IFolderArchiveUpdateCallback *callback) -{ - if (NFind::DoesFileOrDirExist(outPath)) - { - RINOK(SendMessageError(callback, NError::MyFormatMessage(ERROR_ALREADY_EXISTS), FString(outPath))) - CFileInfo fi; - if (fi.Find(inPath)) - { - if (state.TotalSize >= fi.Size) - state.TotalSize -= fi.Size; - } - return S_OK; - } - - { - if (callback) - RINOK(callback->CompressOperation(fs2us(inPath))) - RINOK(state.MyCopyFile(inPath, outPath)) - if (state.ErrorFileIndex >= 0) - { - if (state.ErrorMessage.IsEmpty()) - state.ErrorMessage = GetLastErrorMessage(); - FString errorName; - if (state.ErrorFileIndex == 0) - errorName = inPath; - else - errorName = outPath; - if (callback) - RINOK(SendMessageError(callback, state.ErrorMessage, errorName)) - } - if (callback) - RINOK(callback->OperationResult(0)) - } - - return S_OK; -} - -EXTERN_C_BEGIN - -typedef enum -{ - Z7_WIN_FileRenameInformation = 10 -} -Z7_WIN_FILE_INFORMATION_CLASS; - - -typedef struct -{ - // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1) - union - { - BOOLEAN ReplaceIfExists; // FileRenameInformation - ULONG Flags; // FileRenameInformationEx - } DUMMYUNIONNAME; - // #else - // BOOLEAN ReplaceIfExists; - // #endif - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; -} Z7_WIN_FILE_RENAME_INFORMATION; - -#if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) -#define Z7_WIN_NTSTATUS NTSTATUS -#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK -#else -typedef LONG Z7_WIN_NTSTATUS; -typedef struct -{ - union - { - Z7_WIN_NTSTATUS Status; - PVOID Pointer; - } DUMMYUNIONNAME; - ULONG_PTR Information; -} Z7_WIN_IO_STATUS_BLOCK; -#endif - -typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)( - HANDLE FileHandle, - Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock, - PVOID FileInformation, - ULONG Length, - Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass); - -// NTAPI -typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status); - -#define MY_STATUS_SUCCESS 0 - -EXTERN_C_END - -// static Func_NtSetInformationFile f_NtSetInformationFile; -// static bool g_NtSetInformationFile_WasRequested = false; -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) -{ - const CAltStream &ss = Streams[index]; - const FString srcPath = _pathPrefix + us2fs(ss.Name); - - const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); - // if (!g_NtSetInformationFile_WasRequested) { - // g_NtSetInformationFile_WasRequested = true; - const - Func_NtSetInformationFile - f_NtSetInformationFile = Z7_GET_PROC_ADDRESS( - Func_NtSetInformationFile, ntdll, - "NtSetInformationFile"); - if (f_NtSetInformationFile) - { - NIO::CInFile inFile; - if (inFile.Open_for_FileRenameInformation(srcPath)) - { - UString destPath (':'); - destPath += newName; - const ULONG len = (ULONG)sizeof(wchar_t) * destPath.Len(); - CByteBuffer buffer(sizeof(Z7_WIN_FILE_RENAME_INFORMATION) + len); - // buffer is 4 bytes larger than required. - Z7_WIN_FILE_RENAME_INFORMATION *fri = (Z7_WIN_FILE_RENAME_INFORMATION *)(void *)(Byte *)buffer; - memset(fri, 0, sizeof(Z7_WIN_FILE_RENAME_INFORMATION)); - /* DOCS: If ReplaceIfExists is set to TRUE, the rename operation will succeed only - if a stream with the same name does not exist or is a zero-length data stream. */ - fri->ReplaceIfExists = FALSE; - fri->RootDirectory = NULL; - fri->FileNameLength = len; - memcpy(fri->FileName, destPath.Ptr(), len); - Z7_WIN_IO_STATUS_BLOCK iosb; - const Z7_WIN_NTSTATUS status = f_NtSetInformationFile (inFile.GetHandle(), - &iosb, fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation); - if (status != MY_STATUS_SUCCESS) - { - const - Func_RtlNtStatusToDosError - f_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS( - Func_RtlNtStatusToDosError, ntdll, - "RtlNtStatusToDosError"); - if (f_RtlNtStatusToDosError) - { - const ULONG res = f_RtlNtStatusToDosError(status); - if (res != ERROR_MR_MID_NOT_FOUND) - return HRESULT_FROM_WIN32(res); - } - } - return status; - } - } - - CMyComPtr callback; - if (progress) - { - RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)) - } - - if (callback) - { - RINOK(callback->SetNumFiles(1)) - RINOK(callback->SetTotal(ss.Size)) - } - - NFsFolder::CCopyStateIO state; - state.Progress = progress; - state.TotalSize = 0; - state.DeleteSrcFile = true; - - const FString destPath = _pathPrefix + us2fs(newName); - return UpdateFile(state, srcPath, destPath, callback); -} - -Z7_COM7F_IMF(CAltStreamsFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress)) -{ - RINOK(progress->SetTotal(numItems)) - for (UInt32 i = 0; i < numItems; i++) - { - const CAltStream &ss = Streams[indices[i]]; - const FString fullPath = _pathPrefix + us2fs(ss.Name); - const bool result = DeleteFileAlways(fullPath); - if (!result) - return GetLastError_noZero_HRESULT(); - const UInt64 completed = i; - RINOK(progress->SetCompleted(&completed)) - } - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID */, - const PROPVARIANT * /* value */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) -{ - const CAltStream &ss = Streams[index]; - return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - _pathPrefix + us2fs(ss.Name), - FILE_ATTRIBUTE_ARCHIVE, - iconIndex); -} - -/* -Z7_CLASS_IMP_COM_1( - CGetProp - , IGetProp -) -public: - // const CArc *Arc; - // UInt32 IndexInArc; - UString Name; // relative path - UInt64 Size; -}; - -Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) -{ - if (propID == kpidName) - { - COM_TRY_BEGIN - NCOM::CPropVariant prop; - prop = Name; - prop.Detach(value); - return S_OK; - COM_TRY_END - } - if (propID == kpidSize) - { - NCOM::CPropVariant prop = Size; - prop.Detach(value); - return S_OK; - } - NCOM::CPropVariant prop; - prop.Detach(value); - return S_OK; -} -*/ - -static HRESULT CopyStream( - NFsFolder::CCopyStateIO &state, - const FString &srcPath, - const CFileInfo &srcFileInfo, - const CAltStream &srcAltStream, - const FString &destPathSpec, - IFolderOperationsExtractCallback *callback) -{ - FString destPath = destPathSpec; - if (CompareFileNames(destPath, srcPath) == 0) - { - RINOK(SendMessageError(callback, "Cannot copy file onto itself", destPath)) - return E_ABORT; - } - - Int32 writeAskResult; - CMyComBSTR destPathResult; - RINOK(callback->AskWrite( - fs2us(srcPath), - BoolToInt(false), - &srcFileInfo.MTime, &srcAltStream.Size, - fs2us(destPath), - &destPathResult, - &writeAskResult)) - - if (IntToBool(writeAskResult)) - { - RINOK(callback->SetCurrentFilePath(fs2us(srcPath))) - FString destPathNew (us2fs((LPCOLESTR)destPathResult)); - RINOK(state.MyCopyFile(srcPath, destPathNew)) - if (state.ErrorFileIndex >= 0) - { - if (state.ErrorMessage.IsEmpty()) - state.ErrorMessage = GetLastErrorMessage(); - FString errorName; - if (state.ErrorFileIndex == 0) - errorName = srcPath; - else - errorName = destPathNew; - RINOK(SendMessageError(callback, state.ErrorMessage, errorName)) - return E_ABORT; - } - state.StartPos += state.CurrentSize; - } - else - { - if (state.TotalSize >= srcAltStream.Size) - { - state.TotalSize -= srcAltStream.Size; - RINOK(state.Progress->SetTotal(state.TotalSize)) - } - } - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, - Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */, - const wchar_t *path, IFolderOperationsExtractCallback *callback)) -{ - if (numItems == 0) - return S_OK; - - /* - Z7_DECL_CMyComPtr_QI_FROM( - IFolderExtractToStreamCallback, - ExtractToStreamCallback, callback) - if (ExtractToStreamCallback) - { - Int32 useStreams = 0; - if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) - useStreams = 0; - if (useStreams == 0) - ExtractToStreamCallback.Release(); - } - */ - - UInt64 totalSize = 0; - { - UInt32 i; - for (i = 0; i < numItems; i++) - { - totalSize += Streams[indices[i]].Size; - } - RINOK(callback->SetTotal(totalSize)) - RINOK(callback->SetNumFiles(numItems)) - } - - /* - if (ExtractToStreamCallback) - { - CGetProp *GetProp_Spec = new CGetProp; - CMyComPtr GetProp= GetProp_Spec; - - for (UInt32 i = 0; i < numItems; i++) - { - UInt32 index = indices[i]; - const CAltStream &ss = Streams[index]; - GetProp_Spec->Name = ss.Name; - GetProp_Spec->Size = ss.Size; - CMyComPtr outStream; - RINOK(ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, BoolToInt(false), &outStream, - NArchive::NExtract::NAskMode::kExtract, GetProp)); // isDir - FString srcPath; - GetFullPath(ss, srcPath); - RINOK(ExtractToStreamCallback->PrepareOperation7(NArchive::NExtract::NAskMode::kExtract)); - RINOK(ExtractToStreamCallback->SetOperationResult7(NArchive::NExtract::NOperationResult::kOK, BoolToInt(false))); // _encrypted - // RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback, completedSize)); - } - return S_OK; - } - */ - - FString destPath (us2fs(path)); - if (destPath.IsEmpty() /* && !ExtractToStreamCallback */) - return E_INVALIDARG; - - const bool isAltDest = NName::IsAltPathPrefix(destPath); - const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); - - if (isDirectPath) - { - if (numItems > 1) - return E_INVALIDARG; - } - - CFileInfo fi; - if (!fi.Find(_pathBaseFile)) - return GetLastError_noZero_HRESULT(); - - NFsFolder::CCopyStateIO state; - state.Progress = callback; - state.DeleteSrcFile = IntToBool(moveMode); - state.TotalSize = totalSize; - - for (UInt32 i = 0; i < numItems; i++) - { - const UInt32 index = indices[i]; - const CAltStream &ss = Streams[index]; - FString destPath2 = destPath; - if (!isDirectPath) - destPath2 += us2fs(Get_Correct_FsFile_Name(ss.Name)); - FString srcPath; - GetFullPath(ss, srcPath); - RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback)) - } - - return S_OK; -} - -Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, - const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)) -{ - /* - if (numItems == 0) - return S_OK; - - CMyComPtr callback; - if (progress) - { - RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)); - } - - if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0) - { - RINOK(SendMessageError(callback, "Cannot copy file onto itself", _pathPrefix)); - return E_ABORT; - } - - if (callback) - RINOK(callback->SetNumFiles(numItems)); - - UInt64 totalSize = 0; - - UInt32 i; - - FString path; - for (i = 0; i < numItems; i++) - { - path = us2fs(fromFolderPath); - path += us2fs(itemsPaths[i]); - - CFileInfo fi; - if (!fi.Find(path)) - return ::GetLastError(); - if (fi.IsDir()) - return E_NOTIMPL; - totalSize += fi.Size; - } - - RINOK(progress->SetTotal(totalSize)); - - // UInt64 completedSize = 0; - - NFsFolder::CCopyStateIO state; - state.Progress = progress; - state.DeleteSrcFile = IntToBool(moveMode); - state.TotalSize = totalSize; - - // we need to clear READ-ONLY of parent before creating alt stream - { - DWORD attrib = GetFileAttrib(_pathBaseFile); - if (attrib != INVALID_FILE_ATTRIBUTES - && (attrib & FILE_ATTRIBUTE_READONLY) != 0) - { - if (!SetFileAttrib(_pathBaseFile, attrib & ~FILE_ATTRIBUTE_READONLY)) - { - if (callback) - { - RINOK(SendMessageError(callback, GetLastErrorMessage(), _pathBaseFile)); - return S_OK; - } - return Return_LastError_or_FAIL(); - } - } - } - - for (i = 0; i < numItems; i++) - { - path = us2fs(fromFolderPath); - path += us2fs(itemsPaths[i]); - - FString destPath = _pathPrefix + us2fs(itemsPaths[i]); - - RINOK(UpdateFile(state, path, destPath, callback)); - } - - return S_OK; - */ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -} +// AltStreamsFolder.cpp + +#include "StdAfx.h" + +#ifdef __MINGW32_VERSION +// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) +// for old mingw +#include +#else +#ifndef Z7_OLD_WIN_SDK + #if !defined(_M_IA64) + #include + #endif +#else +typedef LONG NTSTATUS; +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +#endif +#endif + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "../Common/ExtractingFilePath.h" + +#include "../Agent/IFolderArchive.h" + +#include "AltStreamsFolder.h" +#include "FSDrives.h" +#include "FSFolder.h" + +#include "SysIconUtils.h" + +using namespace NWindows; +using namespace NFile; +using namespace NFind; +using namespace NDir; +using namespace NName; + +#ifndef USE_UNICODE_FSTRING +int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); +#endif + +#ifndef UNDER_CE + +namespace NFsFolder +{ +bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size); +} + +#endif + +namespace NAltStreamsFolder { + +static const Byte kProps[] = +{ + kpidName, + kpidSize, + kpidPackSize +}; + +static unsigned GetFsParentPrefixSize(const FString &path) +{ + if (IsNetworkShareRootPath(path)) + return 0; + const unsigned prefixSize = GetRootPrefixSize(path); + if (prefixSize == 0 || prefixSize >= path.Len()) + return 0; + FString parentPath = path; + int pos = parentPath.ReverseFind_PathSepar(); + if (pos < 0) + return 0; + if (pos == (int)parentPath.Len() - 1) + { + parentPath.DeleteBack(); + pos = parentPath.ReverseFind_PathSepar(); + if (pos < 0) + return 0; + } + if ((unsigned)pos + 1 < prefixSize) + return 0; + return (unsigned)pos + 1; +} + +HRESULT CAltStreamsFolder::Init(const FString &path /* , IFolderFolder *parentFolder */) +{ + // _parentFolder = parentFolder; + if (path.Back() != ':') + return E_FAIL; + + _pathPrefix = path; + _pathBaseFile = path; + _pathBaseFile.DeleteBack(); + + { + CFileInfo fi; + if (!fi.Find(_pathBaseFile)) + return GetLastError_noZero_HRESULT(); + } + + unsigned prefixSize = GetFsParentPrefixSize(_pathBaseFile); + if (prefixSize == 0) + return S_OK; + FString parentPath = _pathBaseFile; + parentPath.DeleteFrom(prefixSize); + + _findChangeNotification.FindFirst(parentPath, false, + FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_LAST_WRITE + /* + | FILE_NOTIFY_CHANGE_LAST_ACCESS + | FILE_NOTIFY_CHANGE_CREATION + | FILE_NOTIFY_CHANGE_SECURITY + */ + ); + /* + if (_findChangeNotification.IsHandleAllocated()) + return S_OK; + return GetLastError(); + */ + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::LoadItems()) +{ + Int32 dummy; + WasChanged(&dummy); + Clear(); + + CStreamEnumerator enumerator(_pathBaseFile); + + CStreamInfo si; + for (;;) + { + bool found; + if (!enumerator.Next(si, found)) + { + // if (GetLastError() == ERROR_ACCESS_DENIED) + // break; + // return E_FAIL; + break; + } + if (!found) + break; + if (si.IsMainStream()) + continue; + CAltStream ss; + ss.Name = si.GetReducedName(); + if (!ss.Name.IsEmpty() && ss.Name[0] == ':') + ss.Name.Delete(0); + + ss.Size = si.Size; + ss.PackSize_Defined = false; + ss.PackSize = si.Size; + Streams.Add(ss); + } + + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = Streams.Size(); + return S_OK; +} + +#ifdef USE_UNICODE_FSTRING + +Z7_COM7F_IMF(CAltStreamsFolder::GetItemPrefix(UInt32 /* index */, const wchar_t **name, unsigned *len)) +{ + *name = NULL; + *len = 0; + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) +{ + *name = NULL; + *len = 0; + { + const CAltStream &ss = Streams[index]; + *name = ss.Name; + *len = ss.Name.Len(); + } + return S_OK; +} + +Z7_COM7F_IMF2(UInt64, CAltStreamsFolder::GetItemSize(UInt32 index)) +{ + return Streams[index].Size; +} + +#endif + + +Z7_COM7F_IMF(CAltStreamsFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + { + CAltStream &ss = Streams[index]; + switch (propID) + { + case kpidIsDir: prop = false; break; + case kpidIsAltStream: prop = true; break; + case kpidName: prop = ss.Name; break; + case kpidSize: prop = ss.Size; break; + case kpidPackSize: + #ifdef UNDER_CE + prop = ss.Size; + #else + if (!ss.PackSize_Defined) + { + ss.PackSize_Defined = true; + if (!NFsFolder::MyGetCompressedFileSizeW(_pathPrefix + us2fs(ss.Name), ss.PackSize)) + ss.PackSize = ss.Size; + } + prop = ss.PackSize; + #endif + break; + } + } + + prop.Detach(value); + return S_OK; +} + + +// returns Position of extension including '.' + +static inline const wchar_t *GetExtensionPtr(const UString &name) +{ + const int dotPos = name.ReverseFind_Dot(); + return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos); +} + +Z7_COM7F_IMF2(Int32, CAltStreamsFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */)) +{ + const CAltStream &ss1 = Streams[index1]; + const CAltStream &ss2 = Streams[index2]; + + switch (propID) + { + case kpidName: + { + return CompareFileNames_ForFolderList(ss1.Name, ss2.Name); + // return MyStringCompareNoCase(ss1.Name, ss2.Name); + } + case kpidSize: + return MyCompare(ss1.Size, ss2.Size); + case kpidPackSize: + { + #ifdef UNDER_CE + return MyCompare(ss1.Size, ss2.Size); + #else + // PackSize can be undefined here + return MyCompare( + ss1.PackSize, + ss2.PackSize); + #endif + } + + case kpidExtension: + return CompareFileNames_ForFolderList( + GetExtensionPtr(ss1.Name), + GetExtensionPtr(ss2.Name)); + } + + return 0; +} + +Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(UInt32 /* index */, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + return E_INVALIDARG; +} + +Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + return E_INVALIDARG; +} + +// static CFSTR const kSuperPrefix = FTEXT("\\\\?\\"); + +Z7_COM7F_IMF(CAltStreamsFolder::BindToParentFolder(IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + /* + if (_parentFolder) + { + CMyComPtr parentFolder = _parentFolder; + *resultFolder = parentFolder.Detach(); + return S_OK; + } + */ + + if (IsDriveRootPath_SuperAllowed(_pathBaseFile)) + { + CFSDrives *drivesFolderSpec = new CFSDrives; + CMyComPtr drivesFolder = drivesFolderSpec; + drivesFolderSpec->Init(); + *resultFolder = drivesFolder.Detach(); + return S_OK; + } + + /* + parentPath.DeleteFrom(pos + 1); + + if (parentPath == kSuperPrefix) + { + #ifdef UNDER_CE + *resultFolder = 0; + #else + CFSDrives *drivesFolderSpec = new CFSDrives; + CMyComPtr drivesFolder = drivesFolderSpec; + drivesFolderSpec->Init(false, true); + *resultFolder = drivesFolder.Detach(); + #endif + return S_OK; + } + + FString parentPathReduced = parentPath.Left(pos); + + #ifndef UNDER_CE + pos = parentPathReduced.ReverseFind_PathSepar(); + if (pos == 1) + { + if (!IS_PATH_SEPAR_CHAR(parentPath[0])) + return E_FAIL; + CNetFolder *netFolderSpec = new CNetFolder; + CMyComPtr netFolder = netFolderSpec; + netFolderSpec->Init(fs2us(parentPath)); + *resultFolder = netFolder.Detach(); + return S_OK; + } + #endif + + CFSFolder *parentFolderSpec = new CFSFolder; + CMyComPtr parentFolder = parentFolderSpec; + RINOK(parentFolderSpec->Init(parentPath, 0)); + *resultFolder = parentFolder.Detach(); + */ + + return S_OK; +} + +IMP_IFolderFolder_Props(CAltStreamsFolder) + +Z7_COM7F_IMF(CAltStreamsFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidType: prop = "AltStreamsFolder"; break; + case kpidPath: prop = fs2us(_pathPrefix); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CAltStreamsFolder::WasChanged(Int32 *wasChanged)) +{ + bool wasChangedMain = false; + for (;;) + { + if (!_findChangeNotification.IsHandleAllocated()) + { + *wasChanged = BoolToInt(false); + return S_OK; + } + + const DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); + const bool wasChangedLoc = (waitResult == WAIT_OBJECT_0); + if (wasChangedLoc) + { + _findChangeNotification.FindNext(); + wasChangedMain = true; + } + else + break; + } + *wasChanged = BoolToInt(wasChangedMain); + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::Clone(IFolderFolder **resultFolder)) +{ + CAltStreamsFolder *folderSpec = new CAltStreamsFolder; + CMyComPtr folderNew = folderSpec; + folderSpec->Init(_pathPrefix); + *resultFolder = folderNew.Detach(); + return S_OK; +} + +void CAltStreamsFolder::GetAbsPath(const wchar_t *name, FString &absPath) +{ + absPath.Empty(); + if (!IsAbsolutePath(name)) + absPath += _pathPrefix; + absPath += us2fs(name); +} + + + +static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, + const wchar_t *message, const FString &fileName) +{ + UString s = message; + s += " : "; + s += fs2us(fileName); + return callback->ShowMessage(s); +} + +static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback, + const wchar_t *message, const FString &fileName) +{ + UString s = message; + s += " : "; + s += fs2us(fileName); + return callback->UpdateErrorMessage(s); +} + +static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, + const char *message, const FString &fileName) +{ + return SendMessageError(callback, MultiByteToUnicodeString(message), fileName); +} + +/* +static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback, + const char *message, const FString &fileName) +{ + return SendMessageError(callback, MultiByteToUnicodeString(message), fileName); +} +*/ + +Z7_COM7F_IMF(CAltStreamsFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CAltStreamsFolder::CreateFile(const wchar_t *name, IProgress * /* progress */)) +{ + FString absPath; + GetAbsPath(name, absPath); + NIO::COutFile outFile; + if (!outFile.Create_NEW(absPath)) + return GetLastError_noZero_HRESULT(); + return S_OK; +} + +static UString GetLastErrorMessage() +{ + return NError::MyFormatMessage(GetLastError_noZero_HRESULT()); +} + +static HRESULT UpdateFile(NFsFolder::CCopyStateIO &state, CFSTR inPath, CFSTR outPath, IFolderArchiveUpdateCallback *callback) +{ + if (NFind::DoesFileOrDirExist(outPath)) + { + RINOK(SendMessageError(callback, NError::MyFormatMessage(ERROR_ALREADY_EXISTS), FString(outPath))) + CFileInfo fi; + if (fi.Find(inPath)) + { + if (state.TotalSize >= fi.Size) + state.TotalSize -= fi.Size; + } + return S_OK; + } + + { + if (callback) + RINOK(callback->CompressOperation(fs2us(inPath))) + RINOK(state.MyCopyFile(inPath, outPath)) + if (state.ErrorFileIndex >= 0) + { + if (state.ErrorMessage.IsEmpty()) + state.ErrorMessage = GetLastErrorMessage(); + FString errorName; + if (state.ErrorFileIndex == 0) + errorName = inPath; + else + errorName = outPath; + if (callback) + RINOK(SendMessageError(callback, state.ErrorMessage, errorName)) + } + if (callback) + RINOK(callback->OperationResult(0)) + } + + return S_OK; +} + +EXTERN_C_BEGIN + +typedef enum +{ + Z7_WIN_FileRenameInformation = 10 +} +Z7_WIN_FILE_INFORMATION_CLASS; + + +typedef struct +{ + // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1) + union + { + BOOLEAN ReplaceIfExists; // FileRenameInformation + ULONG Flags; // FileRenameInformationEx + } DUMMYUNIONNAME; + // #else + // BOOLEAN ReplaceIfExists; + // #endif + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} Z7_WIN_FILE_RENAME_INFORMATION; + +#if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) +#define Z7_WIN_NTSTATUS NTSTATUS +#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK +#else +typedef LONG Z7_WIN_NTSTATUS; +typedef struct +{ + union + { + Z7_WIN_NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} Z7_WIN_IO_STATUS_BLOCK; +#endif + +typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)( + HANDLE FileHandle, + Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock, + PVOID FileInformation, + ULONG Length, + Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass); + +// NTAPI +typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status); + +#define MY_STATUS_SUCCESS 0 + +EXTERN_C_END + +// static Func_NtSetInformationFile f_NtSetInformationFile; +// static bool g_NtSetInformationFile_WasRequested = false; +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) +{ + const CAltStream &ss = Streams[index]; + const FString srcPath = _pathPrefix + us2fs(ss.Name); + + const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); + // if (!g_NtSetInformationFile_WasRequested) { + // g_NtSetInformationFile_WasRequested = true; + const + Func_NtSetInformationFile + f_NtSetInformationFile = Z7_GET_PROC_ADDRESS( + Func_NtSetInformationFile, ntdll, + "NtSetInformationFile"); + if (f_NtSetInformationFile) + { + NIO::CInFile inFile; + if (inFile.Open_for_FileRenameInformation(srcPath)) + { + UString destPath (':'); + destPath += newName; + const ULONG len = (ULONG)sizeof(wchar_t) * destPath.Len(); + CByteBuffer buffer(sizeof(Z7_WIN_FILE_RENAME_INFORMATION) + len); + // buffer is 4 bytes larger than required. + Z7_WIN_FILE_RENAME_INFORMATION *fri = (Z7_WIN_FILE_RENAME_INFORMATION *)(void *)(Byte *)buffer; + memset(fri, 0, sizeof(Z7_WIN_FILE_RENAME_INFORMATION)); + /* DOCS: If ReplaceIfExists is set to TRUE, the rename operation will succeed only + if a stream with the same name does not exist or is a zero-length data stream. */ + fri->ReplaceIfExists = FALSE; + fri->RootDirectory = NULL; + fri->FileNameLength = len; + memcpy(fri->FileName, destPath.Ptr(), len); + Z7_WIN_IO_STATUS_BLOCK iosb; + const Z7_WIN_NTSTATUS status = f_NtSetInformationFile (inFile.GetHandle(), + &iosb, fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation); + if (status != MY_STATUS_SUCCESS) + { + const + Func_RtlNtStatusToDosError + f_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS( + Func_RtlNtStatusToDosError, ntdll, + "RtlNtStatusToDosError"); + if (f_RtlNtStatusToDosError) + { + const ULONG res = f_RtlNtStatusToDosError(status); + if (res != ERROR_MR_MID_NOT_FOUND) + return HRESULT_FROM_WIN32(res); + } + } + return status; + } + } + + CMyComPtr callback; + if (progress) + { + RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)) + } + + if (callback) + { + RINOK(callback->SetNumFiles(1)) + RINOK(callback->SetTotal(ss.Size)) + } + + NFsFolder::CCopyStateIO state; + state.Progress = progress; + state.TotalSize = 0; + state.DeleteSrcFile = true; + + const FString destPath = _pathPrefix + us2fs(newName); + return UpdateFile(state, srcPath, destPath, callback); +} + +Z7_COM7F_IMF(CAltStreamsFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress)) +{ + RINOK(progress->SetTotal(numItems)) + for (UInt32 i = 0; i < numItems; i++) + { + const CAltStream &ss = Streams[indices[i]]; + const FString fullPath = _pathPrefix + us2fs(ss.Name); + const bool result = DeleteFileAlways(fullPath); + if (!result) + return GetLastError_noZero_HRESULT(); + const UInt64 completed = i; + RINOK(progress->SetCompleted(&completed)) + } + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID */, + const PROPVARIANT * /* value */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) +{ + const CAltStream &ss = Streams[index]; + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + _pathPrefix + us2fs(ss.Name), + FILE_ATTRIBUTE_ARCHIVE, + iconIndex); +} + +/* +Z7_CLASS_IMP_COM_1( + CGetProp + , IGetProp +) +public: + // const CArc *Arc; + // UInt32 IndexInArc; + UString Name; // relative path + UInt64 Size; +}; + +Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) +{ + if (propID == kpidName) + { + COM_TRY_BEGIN + NCOM::CPropVariant prop; + prop = Name; + prop.Detach(value); + return S_OK; + COM_TRY_END + } + if (propID == kpidSize) + { + NCOM::CPropVariant prop = Size; + prop.Detach(value); + return S_OK; + } + NCOM::CPropVariant prop; + prop.Detach(value); + return S_OK; +} +*/ + +static HRESULT CopyStream( + NFsFolder::CCopyStateIO &state, + const FString &srcPath, + const CFileInfo &srcFileInfo, + const CAltStream &srcAltStream, + const FString &destPathSpec, + IFolderOperationsExtractCallback *callback) +{ + FString destPath = destPathSpec; + if (CompareFileNames(destPath, srcPath) == 0) + { + RINOK(SendMessageError(callback, "Cannot copy file onto itself", destPath)) + return E_ABORT; + } + + Int32 writeAskResult; + CMyComBSTR destPathResult; + RINOK(callback->AskWrite( + fs2us(srcPath), + BoolToInt(false), + &srcFileInfo.MTime, &srcAltStream.Size, + fs2us(destPath), + &destPathResult, + &writeAskResult)) + + if (IntToBool(writeAskResult)) + { + RINOK(callback->SetCurrentFilePath(fs2us(srcPath))) + FString destPathNew (us2fs((LPCOLESTR)destPathResult)); + RINOK(state.MyCopyFile(srcPath, destPathNew)) + if (state.ErrorFileIndex >= 0) + { + if (state.ErrorMessage.IsEmpty()) + state.ErrorMessage = GetLastErrorMessage(); + FString errorName; + if (state.ErrorFileIndex == 0) + errorName = srcPath; + else + errorName = destPathNew; + RINOK(SendMessageError(callback, state.ErrorMessage, errorName)) + return E_ABORT; + } + state.StartPos += state.CurrentSize; + } + else + { + if (state.TotalSize >= srcAltStream.Size) + { + state.TotalSize -= srcAltStream.Size; + RINOK(state.Progress->SetTotal(state.TotalSize)) + } + } + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, + Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */, + const wchar_t *path, IFolderOperationsExtractCallback *callback)) +{ + if (numItems == 0) + return S_OK; + + /* + Z7_DECL_CMyComPtr_QI_FROM( + IFolderExtractToStreamCallback, + ExtractToStreamCallback, callback) + if (ExtractToStreamCallback) + { + Int32 useStreams = 0; + if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) + useStreams = 0; + if (useStreams == 0) + ExtractToStreamCallback.Release(); + } + */ + + UInt64 totalSize = 0; + { + UInt32 i; + for (i = 0; i < numItems; i++) + { + totalSize += Streams[indices[i]].Size; + } + RINOK(callback->SetTotal(totalSize)) + RINOK(callback->SetNumFiles(numItems)) + } + + /* + if (ExtractToStreamCallback) + { + CGetProp *GetProp_Spec = new CGetProp; + CMyComPtr GetProp= GetProp_Spec; + + for (UInt32 i = 0; i < numItems; i++) + { + UInt32 index = indices[i]; + const CAltStream &ss = Streams[index]; + GetProp_Spec->Name = ss.Name; + GetProp_Spec->Size = ss.Size; + CMyComPtr outStream; + RINOK(ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, BoolToInt(false), &outStream, + NArchive::NExtract::NAskMode::kExtract, GetProp)); // isDir + FString srcPath; + GetFullPath(ss, srcPath); + RINOK(ExtractToStreamCallback->PrepareOperation7(NArchive::NExtract::NAskMode::kExtract)); + RINOK(ExtractToStreamCallback->SetOperationResult7(NArchive::NExtract::NOperationResult::kOK, BoolToInt(false))); // _encrypted + // RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback, completedSize)); + } + return S_OK; + } + */ + + FString destPath (us2fs(path)); + if (destPath.IsEmpty() /* && !ExtractToStreamCallback */) + return E_INVALIDARG; + + const bool isAltDest = NName::IsAltPathPrefix(destPath); + const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); + + if (isDirectPath) + { + if (numItems > 1) + return E_INVALIDARG; + } + + CFileInfo fi; + if (!fi.Find(_pathBaseFile)) + return GetLastError_noZero_HRESULT(); + + NFsFolder::CCopyStateIO state; + state.Progress = callback; + state.DeleteSrcFile = IntToBool(moveMode); + state.TotalSize = totalSize; + + for (UInt32 i = 0; i < numItems; i++) + { + const UInt32 index = indices[i]; + const CAltStream &ss = Streams[index]; + FString destPath2 = destPath; + if (!isDirectPath) + destPath2 += us2fs(Get_Correct_FsFile_Name(ss.Name)); + FString srcPath; + GetFullPath(ss, srcPath); + RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback)) + } + + return S_OK; +} + +Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, + const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)) +{ + /* + if (numItems == 0) + return S_OK; + + CMyComPtr callback; + if (progress) + { + RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback)); + } + + if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0) + { + RINOK(SendMessageError(callback, "Cannot copy file onto itself", _pathPrefix)); + return E_ABORT; + } + + if (callback) + RINOK(callback->SetNumFiles(numItems)); + + UInt64 totalSize = 0; + + UInt32 i; + + FString path; + for (i = 0; i < numItems; i++) + { + path = us2fs(fromFolderPath); + path += us2fs(itemsPaths[i]); + + CFileInfo fi; + if (!fi.Find(path)) + return ::GetLastError(); + if (fi.IsDir()) + return E_NOTIMPL; + totalSize += fi.Size; + } + + RINOK(progress->SetTotal(totalSize)); + + // UInt64 completedSize = 0; + + NFsFolder::CCopyStateIO state; + state.Progress = progress; + state.DeleteSrcFile = IntToBool(moveMode); + state.TotalSize = totalSize; + + // we need to clear READ-ONLY of parent before creating alt stream + { + DWORD attrib = GetFileAttrib(_pathBaseFile); + if (attrib != INVALID_FILE_ATTRIBUTES + && (attrib & FILE_ATTRIBUTE_READONLY) != 0) + { + if (!SetFileAttrib(_pathBaseFile, attrib & ~FILE_ATTRIBUTE_READONLY)) + { + if (callback) + { + RINOK(SendMessageError(callback, GetLastErrorMessage(), _pathBaseFile)); + return S_OK; + } + return Return_LastError_or_FAIL(); + } + } + } + + for (i = 0; i < numItems; i++) + { + path = us2fs(fromFolderPath); + path += us2fs(itemsPaths[i]); + + FString destPath = _pathPrefix + us2fs(itemsPaths[i]); + + RINOK(UpdateFile(state, path, destPath, callback)); + } + + return S_OK; + */ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +} diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.h b/CPP/7zip/UI/FileManager/AltStreamsFolder.h index 86244c7ad..ccb6d6f42 100644 --- a/CPP/7zip/UI/FileManager/AltStreamsFolder.h +++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.h @@ -1,92 +1,92 @@ -// AltStreamsFolder.h - -#ifndef ZIP7_INC_ALT_STREAMS_FOLDER_H -#define ZIP7_INC_ALT_STREAMS_FOLDER_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/FileFind.h" - -#include "../../Archive/IArchive.h" - -#include "IFolder.h" - -namespace NAltStreamsFolder { - -class CAltStreamsFolder; - -struct CAltStream -{ - UInt64 Size; - UInt64 PackSize; - bool PackSize_Defined; - UString Name; -}; - - -class CAltStreamsFolder Z7_final: - public IFolderFolder, - public IFolderCompare, - #ifdef USE_UNICODE_FSTRING - public IFolderGetItemName, - #endif - public IFolderWasChanged, - public IFolderOperations, - // public IFolderOperationsDeleteToRecycleBin, - public IFolderClone, - public IFolderGetSystemIconIndex, - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IFolderFolder) - Z7_COM_QI_ENTRY(IFolderCompare) - #ifdef USE_UNICODE_FSTRING - Z7_COM_QI_ENTRY(IFolderGetItemName) - #endif - Z7_COM_QI_ENTRY(IFolderWasChanged) - // Z7_COM_QI_ENTRY(IFolderOperationsDeleteToRecycleBin) - Z7_COM_QI_ENTRY(IFolderOperations) - Z7_COM_QI_ENTRY(IFolderClone) - Z7_COM_QI_ENTRY(IFolderGetSystemIconIndex) - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IFolderFolder) - Z7_IFACE_COM7_IMP(IFolderCompare) - #ifdef USE_UNICODE_FSTRING - Z7_IFACE_COM7_IMP(IFolderGetItemName) - #endif - Z7_IFACE_COM7_IMP(IFolderWasChanged) - Z7_IFACE_COM7_IMP(IFolderOperations) - Z7_IFACE_COM7_IMP(IFolderClone) - Z7_IFACE_COM7_IMP(IFolderGetSystemIconIndex) - - FString _pathBaseFile; // folder - FString _pathPrefix; // folder: - - CObjectVector Streams; - // CMyComPtr _parentFolder; - - NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; - - HRESULT GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress); - void GetAbsPath(const wchar_t *name, FString &absPath); - -public: - // path must be with ':' at tail - HRESULT Init(const FString &path /* , IFolderFolder *parentFolder */); - - void GetFullPath(const CAltStream &item, FString &path) const - { - path = _pathPrefix; - path += us2fs(item.Name); - } - - void Clear() - { - Streams.Clear(); - } -}; - -} - -#endif +// AltStreamsFolder.h + +#ifndef ZIP7_INC_ALT_STREAMS_FOLDER_H +#define ZIP7_INC_ALT_STREAMS_FOLDER_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/FileFind.h" + +#include "../../Archive/IArchive.h" + +#include "IFolder.h" + +namespace NAltStreamsFolder { + +class CAltStreamsFolder; + +struct CAltStream +{ + UInt64 Size; + UInt64 PackSize; + bool PackSize_Defined; + UString Name; +}; + + +class CAltStreamsFolder Z7_final: + public IFolderFolder, + public IFolderCompare, + #ifdef USE_UNICODE_FSTRING + public IFolderGetItemName, + #endif + public IFolderWasChanged, + public IFolderOperations, + // public IFolderOperationsDeleteToRecycleBin, + public IFolderClone, + public IFolderGetSystemIconIndex, + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IFolderFolder) + Z7_COM_QI_ENTRY(IFolderCompare) + #ifdef USE_UNICODE_FSTRING + Z7_COM_QI_ENTRY(IFolderGetItemName) + #endif + Z7_COM_QI_ENTRY(IFolderWasChanged) + // Z7_COM_QI_ENTRY(IFolderOperationsDeleteToRecycleBin) + Z7_COM_QI_ENTRY(IFolderOperations) + Z7_COM_QI_ENTRY(IFolderClone) + Z7_COM_QI_ENTRY(IFolderGetSystemIconIndex) + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IFolderFolder) + Z7_IFACE_COM7_IMP(IFolderCompare) + #ifdef USE_UNICODE_FSTRING + Z7_IFACE_COM7_IMP(IFolderGetItemName) + #endif + Z7_IFACE_COM7_IMP(IFolderWasChanged) + Z7_IFACE_COM7_IMP(IFolderOperations) + Z7_IFACE_COM7_IMP(IFolderClone) + Z7_IFACE_COM7_IMP(IFolderGetSystemIconIndex) + + FString _pathBaseFile; // folder + FString _pathPrefix; // folder: + + CObjectVector Streams; + // CMyComPtr _parentFolder; + + NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; + + HRESULT GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress); + void GetAbsPath(const wchar_t *name, FString &absPath); + +public: + // path must be with ':' at tail + HRESULT Init(const FString &path /* , IFolderFolder *parentFolder */); + + void GetFullPath(const CAltStream &item, FString &path) const + { + path = _pathPrefix; + path += us2fs(item.Name); + } + + void Clear() + { + Streams.Clear(); + } +}; + +} + +#endif diff --git a/CPP/7zip/UI/FileManager/App.cpp b/CPP/7zip/UI/FileManager/App.cpp index 7c73efb5d..5b7d6167c 100644 --- a/CPP/7zip/UI/FileManager/App.cpp +++ b/CPP/7zip/UI/FileManager/App.cpp @@ -1,998 +1,1004 @@ -// App.cpp - -#include "StdAfx.h" - -#include "resource.h" -#include "OverwriteDialogRes.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariantConv.h" - -/* -#include "Windows/COM.h" -#include "Windows/Error.h" -#include "Windows/FileDir.h" - -#include "Windows/PropVariant.h" -#include "Windows/Thread.h" -*/ - -#include "App.h" -#include "CopyDialog.h" -#include "ExtractCallback.h" -#include "FormatUtils.h" -#include "IFolder.h" -#include "LangUtils.h" -#include "MyLoadMenu.h" -#include "RegistryUtils.h" -#include "ViewSettings.h" - -#include "PropertyNameRes.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NFind; -using namespace NName; - -extern HINSTANCE g_hInstance; - -#define kTempDirPrefix FTEXT("7zE") - -void CPanelCallbackImp::OnTab() -{ - if (g_App.NumPanels != 1) - _app->Panels[1 - _index].SetFocusToList(); - _app->RefreshTitle(); -} - -void CPanelCallbackImp::SetFocusToPath(unsigned index) -{ - unsigned newPanelIndex = index; - if (g_App.NumPanels == 1) - newPanelIndex = g_App.LastFocusedPanel; - _app->RefreshTitle(); - _app->Panels[newPanelIndex]._headerComboBox.SetFocus(); - _app->Panels[newPanelIndex]._headerComboBox.ShowDropDown(); -} - - -void CPanelCallbackImp::OnCopy(bool move, bool copyToSame) { _app->OnCopy(move, copyToSame, _index); } -void CPanelCallbackImp::OnSetSameFolder() { _app->OnSetSameFolder(_index); } -void CPanelCallbackImp::OnSetSubFolder() { _app->OnSetSubFolder(_index); } -void CPanelCallbackImp::PanelWasFocused() { _app->SetFocusedPanel(_index); _app->RefreshTitlePanel(_index); } -void CPanelCallbackImp::DragBegin() { _app->DragBegin(_index); } -void CPanelCallbackImp::DragEnd() { _app->DragEnd(); } -void CPanelCallbackImp::RefreshTitle(bool always) { _app->RefreshTitlePanel(_index, always); } - -void CApp::ReloadLangItems() -{ - LangString(IDS_N_SELECTED_ITEMS, LangString_N_SELECTED_ITEMS); -} - -void CApp::SetListSettings() -{ - CFmSettings st; - st.Load(); - - ShowSystemMenu = st.ShowSystemMenu; - - DWORD extendedStyle = LVS_EX_HEADERDRAGDROP; - if (st.FullRow) - extendedStyle |= LVS_EX_FULLROWSELECT; - if (st.ShowGrid) - extendedStyle |= LVS_EX_GRIDLINES; - - if (st.SingleClick) - { - extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT; - /* - if (ReadUnderline()) - extendedStyle |= LVS_EX_UNDERLINEHOT; - */ - } - - for (unsigned i = 0; i < kNumPanelsMax; i++) - { - CPanel &panel = Panels[i]; - panel._mySelectMode = st.AlternativeSelection; - panel._showDots = st.ShowDots; - panel._showRealFileIcons = st.ShowRealFileIcons; - panel._exStyle = extendedStyle; - - LONG_PTR style = panel._listView.GetStyle(); - if (st.AlternativeSelection) - style |= LVS_SINGLESEL; - else - style &= ~(LONG_PTR)(DWORD)LVS_SINGLESEL; - panel._listView.SetStyle(style); - panel.SetExtendedStyle(); - } -} - -#ifndef ILC_COLOR32 -#define ILC_COLOR32 0x0020 -#endif - -HRESULT CApp::CreateOnePanel(unsigned panelIndex, const UString &mainPath, const UString &arcFormat, - bool needOpenArc, - COpenResult &openRes) -{ - if (Panels[panelIndex].PanelCreated) - return S_OK; - - m_PanelCallbackImp[panelIndex].Init(this, panelIndex); - - UString path; - if (mainPath.IsEmpty()) - { - if (!::ReadPanelPath(panelIndex, path)) - path.Empty(); - } - else - path = mainPath; - - const unsigned id = 1000 + 100 * panelIndex; // check it - - return Panels[panelIndex].Create(_window, _window, - id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState, - needOpenArc, - openRes); -} - - -static void CreateToolbar(HWND parent, - NControl::CImageList &imageList, - NControl::CToolBar &toolBar, - bool largeButtons) -{ - toolBar.Attach(::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 0 - | WS_CHILD - | WS_VISIBLE - | TBSTYLE_FLAT - | TBSTYLE_TOOLTIPS - | TBSTYLE_WRAPABLE - // | TBSTYLE_AUTOSIZE - // | CCS_NORESIZE - #ifdef UNDER_CE - | CCS_NODIVIDER - | CCS_NOPARENTALIGN - #endif - ,0,0,0,0, parent, NULL, g_hInstance, NULL)); - - // TB_BUTTONSTRUCTSIZE message, which is required for - // backward compatibility. - toolBar.ButtonStructSize(); - - imageList.Create( - largeButtons ? 48: 24, - largeButtons ? 36: 24, - ILC_MASK | ILC_COLOR32, 0, 0); - toolBar.SetImageList(0, imageList); -} - - -struct CButtonInfo -{ - int CommandID; - UINT BitmapResID; - UINT Bitmap2ResID; - UINT StringResID; - - UString GetText() const { return LangString(StringResID); } -}; - -static const CButtonInfo g_StandardButtons[] = -{ - { IDM_COPY_TO, IDB_COPY, IDB_COPY2, IDS_BUTTON_COPY }, - { IDM_MOVE_TO, IDB_MOVE, IDB_MOVE2, IDS_BUTTON_MOVE }, - { IDM_DELETE, IDB_DELETE, IDB_DELETE2, IDS_BUTTON_DELETE } , - { IDM_PROPERTIES, IDB_INFO, IDB_INFO2, IDS_BUTTON_INFO } -}; - -static const CButtonInfo g_ArchiveButtons[] = -{ - { kMenuCmdID_Toolbar_Add, IDB_ADD, IDB_ADD2, IDS_ADD }, - { kMenuCmdID_Toolbar_Extract, IDB_EXTRACT, IDB_EXTRACT2, IDS_EXTRACT }, - { kMenuCmdID_Toolbar_Test, IDB_TEST, IDB_TEST2, IDS_TEST } -}; - -static bool SetButtonText(int commandID, const CButtonInfo *buttons, unsigned numButtons, UString &s) -{ - for (unsigned i = 0; i < numButtons; i++) - { - const CButtonInfo &b = buttons[i]; - if (b.CommandID == commandID) - { - s = b.GetText(); - return true; - } - } - return false; -} - -static void SetButtonText(int commandID, UString &s) -{ - if (SetButtonText(commandID, g_StandardButtons, Z7_ARRAY_SIZE(g_StandardButtons), s)) - return; - SetButtonText(commandID, g_ArchiveButtons, Z7_ARRAY_SIZE(g_ArchiveButtons), s); -} - -static void AddButton( - NControl::CImageList &imageList, - NControl::CToolBar &toolBar, - const CButtonInfo &butInfo, bool showText, bool large) -{ - TBBUTTON but; - but.iBitmap = 0; - but.idCommand = butInfo.CommandID; - but.fsState = TBSTATE_ENABLED; - but.fsStyle = TBSTYLE_BUTTON; - but.dwData = 0; - - UString s = butInfo.GetText(); - but.iString = 0; - if (showText) - but.iString = (INT_PTR)(LPCWSTR)s; - - but.iBitmap = imageList.GetImageCount(); - HBITMAP b = ::LoadBitmap(g_hInstance, - large ? - MAKEINTRESOURCE(butInfo.BitmapResID): - MAKEINTRESOURCE(butInfo.Bitmap2ResID)); - if (b) - { - imageList.AddMasked(b, RGB(255, 0, 255)); - ::DeleteObject(b); - } - #ifdef _UNICODE - toolBar.AddButton(1, &but); - #else - toolBar.AddButtonW(1, &but); - #endif -} - -void CApp::ReloadToolbars() -{ - _buttonsImageList.Destroy(); - _toolBar.Destroy(); - - - if (ShowArchiveToolbar || ShowStandardToolbar) - { - CreateToolbar(_window, _buttonsImageList, _toolBar, LargeButtons); - unsigned i; - if (ShowArchiveToolbar) - for (i = 0; i < Z7_ARRAY_SIZE(g_ArchiveButtons); i++) - AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons); - if (ShowStandardToolbar) - for (i = 0; i < Z7_ARRAY_SIZE(g_StandardButtons); i++) - AddButton(_buttonsImageList, _toolBar, g_StandardButtons[i], ShowButtonsLables, LargeButtons); - - _toolBar.AutoSize(); - } -} - -void CApp::SaveToolbarChanges() -{ - SaveToolbar(); - ReloadToolbars(); - MoveSubWindows(); -} - - -HRESULT CApp::Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes) -{ - _window.Attach(hwnd); - - #ifdef UNDER_CE - _commandBar.Create(g_hInstance, hwnd, 1); - #endif - - MyLoadMenu(false); // needResetMenu - - #ifdef UNDER_CE - _commandBar.AutoSize(); - #endif - - ReadToolbar(); - ReloadToolbars(); - - unsigned i; - for (i = 0; i < kNumPanelsMax; i++) - Panels[i].PanelCreated = false; - - AppState.Read(); - - SetListSettings(); - - if (LastFocusedPanel >= kNumPanelsMax) - LastFocusedPanel = 0; - // ShowDeletedFiles = Read_ShowDeleted(); - - CListMode listMode; - listMode.Read(); - - for (i = 0; i < kNumPanelsMax; i++) - { - CPanel &panel = Panels[i]; - panel._listViewMode = listMode.Panels[i]; - panel._xSize = xSizes[i]; - panel._flatModeForArc = ReadFlatView(i); - } - - for (i = 0; i < kNumPanelsMax; i++) - { - unsigned panelIndex = i; - if (needOpenArc && LastFocusedPanel == 1) - panelIndex = 1 - i; - - bool isMainPanel = (panelIndex == LastFocusedPanel); - - if (NumPanels > 1 || isMainPanel) - { - if (NumPanels == 1) - Panels[panelIndex]._xSize = xSizes[0] + xSizes[1]; - - COpenResult openRes2; - UString path; - if (isMainPanel) - path = mainPath; - - RINOK(CreateOnePanel(panelIndex, path, arcFormat, - isMainPanel && needOpenArc, - *(isMainPanel ? &openRes : &openRes2))) - - if (isMainPanel) - { - if (needOpenArc && !openRes.ArchiveIsOpened) - return S_OK; - } - } - } - - SetFocusedPanel(LastFocusedPanel); - Panels[LastFocusedPanel].SetFocusToList(); - return S_OK; -} - - -HRESULT CApp::SwitchOnOffOnePanel() -{ - if (NumPanels == 1) - { - NumPanels++; - COpenResult openRes; - RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(), - false, // needOpenArc - openRes)) - Panels[1 - LastFocusedPanel].Enable(true); - Panels[1 - LastFocusedPanel].Show(SW_SHOWNORMAL); - } - else - { - NumPanels--; - Panels[1 - LastFocusedPanel].Enable(false); - Panels[1 - LastFocusedPanel].Show(SW_HIDE); - } - MoveSubWindows(); - return S_OK; -} - -void CApp::Save() -{ - AppState.Save(); - CListMode listMode; - - for (unsigned i = 0; i < kNumPanelsMax; i++) - { - const CPanel &panel = Panels[i]; - UString path; - if (panel._parentFolders.IsEmpty()) - path = panel._currentFolderPrefix; - else - path = panel._parentFolders[0].ParentFolderPath; - // GetFolderPath(panel._parentFolders[0].ParentFolder); - SavePanelPath(i, path); - listMode.Panels[i] = panel.GetListViewMode(); - SaveFlatView(i, panel._flatModeForArc); - } - - listMode.Save(); - // Save_ShowDeleted(ShowDeletedFiles); -} - -void CApp::Release() -{ - // It's for unloading COM dll's: don't change it. - for (unsigned i = 0; i < kNumPanelsMax; i++) - Panels[i].Release(); -} - -// reduces path to part that exists on disk (or root prefix of path) -// output path is normalized (with WCHAR_PATH_SEPARATOR) -static void Reduce_Path_To_RealFileSystemPath(UString &path) -{ - unsigned prefixSize = GetRootPrefixSize(path); - - while (!path.IsEmpty()) - { - if (NFind::DoesDirExist_FollowLink(us2fs(path))) - { - NName::NormalizeDirPathPrefix(path); - break; - } - int pos = path.ReverseFind_PathSepar(); - if (pos < 0) - { - path.Empty(); - break; - } - path.DeleteFrom((unsigned)(pos + 1)); - if ((unsigned)pos + 1 == prefixSize) - break; - path.DeleteFrom((unsigned)pos); - } -} - -// returns: true, if such dir exists or is root -/* -static bool CheckFolderPath(const UString &path) -{ - UString pathReduced = path; - Reduce_Path_To_RealFileSystemPath(pathReduced); - return (pathReduced == path); -} -*/ - -extern UString ConvertSizeToString(UInt64 value); - -static void AddSizeValue(UString &s, UInt64 size) -{ - s += MyFormatNew(IDS_FILE_SIZE, ConvertSizeToString(size)); -} - -static void AddValuePair1(UString &s, UINT resourceID, UInt64 size) -{ - AddLangString(s, resourceID); - s += ": "; - AddSizeValue(s, size); - s.Add_LF(); -} - -void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size); -void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size) -{ - if (num == 0) - return; - AddLangString(s, resourceID); - s += ": "; - s += ConvertSizeToString(num); - - if (size != (UInt64)(Int64)-1) - { - s += " ( "; - AddSizeValue(s, size); - s += " )"; - } - s.Add_LF(); -} - -static void AddPropValueToSum(IFolderFolder *folder, UInt32 index, PROPID propID, UInt64 &sum) -{ - if (sum == (UInt64)(Int64)-1) - return; - NCOM::CPropVariant prop; - folder->GetProperty(index, propID, &prop); - UInt64 val = 0; - if (ConvertPropVariantToUInt64(prop, val)) - sum += val; - else - sum = (UInt64)(Int64)-1; -} - -UString CPanel::GetItemsInfoString(const CRecordVector &indices) -{ - UString info; - UInt64 numDirs, numFiles, filesSize, foldersSize; - numDirs = numFiles = filesSize = foldersSize = 0; - - unsigned i; - for (i = 0; i < indices.Size(); i++) - { - const UInt32 index = indices[i]; - if (IsItem_Folder(index)) - { - AddPropValueToSum(_folder, index, kpidSize, foldersSize); - numDirs++; - } - else - { - AddPropValueToSum(_folder, index, kpidSize, filesSize); - numFiles++; - } - } - - AddValuePair2(info, IDS_PROP_FOLDERS, numDirs, foldersSize); - AddValuePair2(info, IDS_PROP_FILES, numFiles, filesSize); - int numDefined = ((foldersSize != (UInt64)(Int64)-1) && foldersSize != 0) ? 1: 0; - numDefined += ((filesSize != (UInt64)(Int64)-1) && filesSize != 0) ? 1: 0; - if (numDefined == 2) - AddValuePair1(info, IDS_PROP_SIZE, filesSize + foldersSize); - - info.Add_LF(); - info += _currentFolderPrefix; - - for (i = 0; i < indices.Size() && (int)i < (int)kCopyDialog_NumInfoLines - 6; i++) - { - info.Add_LF(); - info += " "; - const UInt32 index = indices[i]; - info += GetItemRelPath(index); - if (IsItem_Folder(index)) - info.Add_PathSepar(); - } - if (i != indices.Size()) - { - info.Add_LF(); - info += " ..."; - } - return info; -} - -bool IsCorrectFsName(const UString &name); - - - -/* Returns true, if path is path that can be used as path for File System functions -*/ - -/* -static bool IsFsPath(const FString &path) -{ - if (!IsAbsolutePath(path)) - return false; - unsigned prefixSize = GetRootPrefixSize(path); -} -*/ - -void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex) -{ - const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); - CPanel &srcPanel = Panels[srcPanelIndex]; - CPanel &destPanel = Panels[destPanelIndex]; - - CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel); - CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel); - - if (move) - { - if (!srcPanel.CheckBeforeUpdate(IDS_MOVE)) - return; - } - else if (!srcPanel.DoesItSupportOperations()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - - CRecordVector indices; - UString destPath; - bool useDestPanel = false; - - { - if (copyToSame) - { - const int focusedItem = srcPanel._listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem); - if (realIndex == kParentIndex) - return; - indices.Add(realIndex); - destPath = srcPanel.GetItemName(realIndex); - } - else - { - srcPanel.Get_ItemIndices_OperSmart(indices); - if (indices.Size() == 0) - return; - destPath = destPanel.GetFsPath(); - if (NumPanels == 1) - Reduce_Path_To_RealFileSystemPath(destPath); - } - } - - UStringVector copyFolders; - ReadCopyHistory(copyFolders); - - const bool useFullItemPaths = srcPanel.Is_IO_FS_Folder(); // maybe we need flat also here ?? - - { - CCopyDialog copyDialog; - - copyDialog.Strings = copyFolders; - copyDialog.Value = destPath; - LangString(move ? IDS_MOVE : IDS_COPY, copyDialog.Title); - LangString(move ? IDS_MOVE_TO : IDS_COPY_TO, copyDialog.Static); - copyDialog.Info = srcPanel.GetItemsInfoString(indices); - - if (copyDialog.Create(srcPanel.GetParent()) != IDOK) - return; - - destPath = copyDialog.Value; - } - - { - if (destPath.IsEmpty()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - - UString correctName; - if (!srcPanel.CorrectFsPath(destPath, correctName)) - { - srcPanel.MessageBox_Error_HRESULT(E_INVALIDARG); - return; - } - - if (IsAbsolutePath(destPath)) - destPath.Empty(); - else - destPath = srcPanel.GetFsPath(); - destPath += correctName; - - #if defined(_WIN32) && !defined(UNDER_CE) - if (destPath.Len() > 0 && destPath[0] == '\\') - if (destPath.Len() == 1 || destPath[1] != '\\') - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - #endif - - bool possibleToUseDestPanel = false; - - if (CompareFileNames(destPath, destPanel.GetFsPath()) == 0) - { - if (NumPanels == 1 || CompareFileNames(destPath, srcPanel.GetFsPath()) == 0) - { - srcPanel.MessageBox_Error(L"Cannot copy files onto itself"); - return; - } - - if (destPanel.DoesItSupportOperations()) - possibleToUseDestPanel = true; - } - - bool destIsFsPath = false; - - if (possibleToUseDestPanel) - { - if (destPanel.IsFSFolder() || destPanel.IsAltStreamsFolder()) - destIsFsPath = true; - else if (destPanel.IsFSDrivesFolder() || destPanel.IsRootFolder()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - } - else - { - if (IsAltPathPrefix(us2fs(destPath))) - { - // we allow alt streams dest only to alt stream folder in second panel - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - /* - FString basePath = us2fs(destPath); - basePath.DeleteBack(); - if (!DoesFileOrDirExist(basePath)) - { - srcPanel.MessageBoxError2Lines(basePath, ERROR_FILE_NOT_FOUND); // GetLastError() - return; - } - destIsFsPath = true; - */ - } - else - { - if (indices.Size() == 1 && - !destPath.IsEmpty() && !IS_PATH_SEPAR(destPath.Back())) - { - int pos = destPath.ReverseFind_PathSepar(); - if (pos < 0) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - { - /* - #ifdef _WIN32 - UString name = destPath.Ptr(pos + 1); - if (name.Find(L':') >= 0) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - #endif - */ - UString prefix = destPath.Left(pos + 1); - if (!CreateComplexDir(us2fs(prefix))) - { - const HRESULT lastError = GetLastError_noZero_HRESULT(); - srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError); - return; - } - } - // bool isFolder = srcPanael.IsItem_Folder(indices[0]); - } - else - { - NName::NormalizeDirPathPrefix(destPath); - if (!CreateComplexDir(us2fs(destPath))) - { - const HRESULT lastError = GetLastError_noZero_HRESULT(); - srcPanel.MessageBox_Error_2Lines_Message_HRESULT(destPath, lastError); - return; - } - } - destIsFsPath = true; - } - } - - if (!destIsFsPath) - useDestPanel = true; - - AddUniqueStringToHeadOfList(copyFolders, destPath); - while (copyFolders.Size() > 20) - copyFolders.DeleteBack(); - SaveCopyHistory(copyFolders); - } - - bool useSrcPanel = !useDestPanel || !srcPanel.Is_IO_FS_Folder(); - - bool useTemp = useSrcPanel && useDestPanel; - if (useTemp && NumPanels == 1) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - - CTempDir tempDirectory; - FString tempDirPrefix; - if (useTemp) - { - tempDirectory.Create(kTempDirPrefix); - tempDirPrefix = tempDirectory.GetPath(); - NFile::NName::NormalizeDirPathPrefix(tempDirPrefix); - } - - CSelectedState srcSelState; - CSelectedState destSelState; - srcPanel.SaveSelectedState(srcSelState); - destPanel.SaveSelectedState(destSelState); - - CPanel::CDisableNotify disableNotify1(destPanel); - CPanel::CDisableNotify disableNotify2(srcPanel); - - HRESULT result = S_OK; - - if (useSrcPanel) - { - CCopyToOptions options; - // options.src_Is_IO_FS_Folder = useFullItemPaths; - options.folder = useTemp ? fs2us(tempDirPrefix) : destPath; - options.moveMode = move; - options.includeAltStreams = true; - options.replaceAltStreamChars = false; - options.showErrorMessages = true; - - result = srcPanel.CopyTo(options, indices, NULL); - } - - if (result == S_OK && useDestPanel) - { - UStringVector filePaths; - UString folderPrefix; - - if (useTemp) - folderPrefix = fs2us(tempDirPrefix); - else - folderPrefix = srcPanel.GetFsPath(); - - filePaths.ClearAndReserve(indices.Size()); - - FOR_VECTOR (i, indices) - { - UInt32 index = indices[i]; - UString s; - if (useFullItemPaths) - s = srcPanel.GetItemRelPath2(index); - else - s = srcPanel.GetItemName_for_Copy(index); - filePaths.AddInReserved(s); - } - - result = destPanel.CopyFrom(move, folderPrefix, filePaths, true, NULL); - } - - if (result != S_OK) - { - // disableNotify1.Restore(); - // disableNotify2.Restore(); - // For Password: - // srcPanel.SetFocusToList(); - // srcPanel.InvalidateList(NULL, true); - - if (result != E_ABORT) - srcPanel.MessageBox_Error_HRESULT(result); - // return; - } - - RefreshTitleAlways(); - - if (copyToSame || move) - { - srcPanel.RefreshListCtrl(srcSelState); - } - - if (!copyToSame) - { - destPanel.RefreshListCtrl(destSelState); - srcPanel.KillSelection(); - } - - disableNotify1.Restore(); - disableNotify2.Restore(); - srcPanel.SetFocusToList(); -} - -void CApp::OnSetSameFolder(unsigned srcPanelIndex) -{ - if (NumPanels <= 1) - return; - const CPanel &srcPanel = Panels[srcPanelIndex]; - CPanel &destPanel = Panels[1 - srcPanelIndex]; - destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix); -} - -void CApp::OnSetSubFolder(unsigned srcPanelIndex) -{ - if (NumPanels <= 1) - return; - const CPanel &srcPanel = Panels[srcPanelIndex]; - CPanel &destPanel = Panels[1 - srcPanelIndex]; - - const int focusedItem = srcPanel._listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem); - if (!srcPanel.IsItem_Folder(realIndex)) - return; - - // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR); - - CMyComPtr newFolder; - if (realIndex == kParentIndex) - { - if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK) - return; - if (!newFolder) - { - { - const UString parentPrefix = srcPanel.GetParentDirPrefix(); - COpenResult openRes; - destPanel.BindToPath(parentPrefix, UString(), openRes); - } - destPanel.RefreshListCtrl(); - return; - } - } - else - { - if (srcPanel._folder->BindToFolder(realIndex, &newFolder) != S_OK) - return; - } - - if (!newFolder) - return; - - destPanel.CloseOpenFolders(); - destPanel.SetNewFolder(newFolder); - destPanel.RefreshListCtrl(); -} - -/* -int CApp::GetFocusedPanelIndex() const -{ - return LastFocusedPanel; - HWND hwnd = ::GetFocus(); - for (;;) - { - if (hwnd == 0) - return 0; - for (unsigned i = 0; i < kNumPanelsMax; i++) - { - if (PanelsCreated[i] && - ((HWND)Panels[i] == hwnd || Panels[i]._listView == hwnd)) - return i; - } - hwnd = GetParent(hwnd); - } -} -*/ - -static UString g_ToolTipBuffer; -static CSysString g_ToolTipBufferSys; - -void CApp::OnNotify(int /* ctrlID */, LPNMHDR pnmh) -{ - { - if (pnmh->code == TTN_GETDISPINFO) - { - LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh; - info->hinst = NULL; - g_ToolTipBuffer.Empty(); - SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); - g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer); - info->lpszText = g_ToolTipBufferSys.Ptr_non_const(); - return; - } - #ifndef _UNICODE - if (pnmh->code == TTN_GETDISPINFOW) - { - LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh; - info->hinst = NULL; - g_ToolTipBuffer.Empty(); - SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); - info->lpszText = g_ToolTipBuffer.Ptr_non_const(); - return; - } - #endif - } -} - -void CApp::RefreshTitle(bool always) -{ - UString path = GetFocusedPanel()._currentFolderPrefix; - if (path.IsEmpty()) - path = "7-Zip"; // LangString(IDS_APP_TITLE); - if (!always && path == PrevTitle) - return; - PrevTitle = path; - NWindows::MySetWindowText(_window, path); -} - -void CApp::RefreshTitlePanel(unsigned panelIndex, bool always) -{ - if (panelIndex != GetFocusedPanelIndex()) - return; - RefreshTitle(always); -} - -static void AddUniqueStringToHead(UStringVector &list, const UString &s) -{ - for (unsigned i = 0; i < list.Size();) - if (s.IsEqualTo_NoCase(list[i])) - list.Delete(i); - else - i++; - list.Insert(0, s); -} - - -void CFolderHistory::Normalize() -{ - const unsigned kMaxSize = 100; - if (Strings.Size() > kMaxSize) - Strings.DeleteFrom(kMaxSize); -} - -void CFolderHistory::AddString(const UString &s) -{ - NSynchronization::CCriticalSectionLock lock(_criticalSection); - AddUniqueStringToHead(Strings, s); - Normalize(); -} +// App.cpp + +#include "StdAfx.h" + +#include "resource.h" +#include "OverwriteDialogRes.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariantConv.h" + +/* +#include "Windows/COM.h" +#include "Windows/Error.h" +#include "Windows/FileDir.h" + +#include "Windows/PropVariant.h" +#include "Windows/Thread.h" +*/ + +#include "App.h" +#include "CopyDialog.h" +#include "ExtractCallback.h" +#include "FormatUtils.h" +#include "IFolder.h" +#include "LangUtils.h" +#include "MyLoadMenu.h" +#include "RegistryUtils.h" +#include "ViewSettings.h" + +#include "PropertyNameRes.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NFind; +using namespace NName; + +extern HINSTANCE g_hInstance; + +#define kTempDirPrefix FTEXT("7zE") + +void CPanelCallbackImp::OnTab() +{ + if (g_App.NumPanels != 1) + _app->Panels[1 - _index].SetFocusToList(); + _app->RefreshTitle(); +} + +void CPanelCallbackImp::SetFocusToPath(unsigned index) +{ + unsigned newPanelIndex = index; + if (g_App.NumPanels == 1) + newPanelIndex = g_App.LastFocusedPanel; + _app->RefreshTitle(); + _app->Panels[newPanelIndex]._headerComboBox.SetFocus(); + _app->Panels[newPanelIndex]._headerComboBox.ShowDropDown(); +} + + +void CPanelCallbackImp::OnCopy(bool move, bool copyToSame) { _app->OnCopy(move, copyToSame, _index); } +void CPanelCallbackImp::OnSetSameFolder() { _app->OnSetSameFolder(_index); } +void CPanelCallbackImp::OnSetSubFolder() { _app->OnSetSubFolder(_index); } +void CPanelCallbackImp::PanelWasFocused() { _app->SetFocusedPanel(_index); _app->RefreshTitlePanel(_index); } +void CPanelCallbackImp::DragBegin() { _app->DragBegin(_index); } +void CPanelCallbackImp::DragEnd() { _app->DragEnd(); } +void CPanelCallbackImp::RefreshTitle(bool always) { _app->RefreshTitlePanel(_index, always); } + +void CApp::ReloadLangItems() +{ + LangString(IDS_N_SELECTED_ITEMS, LangString_N_SELECTED_ITEMS); +} + +void CApp::SetListSettings() +{ + CFmSettings st; + st.Load(); + + ShowSystemMenu = st.ShowSystemMenu; + + DWORD extendedStyle = LVS_EX_HEADERDRAGDROP; + if (st.FullRow) + extendedStyle |= LVS_EX_FULLROWSELECT; + if (st.ShowGrid) + extendedStyle |= LVS_EX_GRIDLINES; + + if (st.SingleClick) + { + extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT; + /* + if (ReadUnderline()) + extendedStyle |= LVS_EX_UNDERLINEHOT; + */ + } + + for (unsigned i = 0; i < kNumPanelsMax; i++) + { + CPanel &panel = Panels[i]; + panel._mySelectMode = st.AlternativeSelection; + panel._showDots = st.ShowDots; + panel._showRealFileIcons = st.ShowRealFileIcons; + panel._exStyle = extendedStyle; + + LONG_PTR style = panel._listView.GetStyle(); + if (st.AlternativeSelection) + style |= LVS_SINGLESEL; + else + style &= ~(LONG_PTR)(DWORD)LVS_SINGLESEL; + panel._listView.SetStyle(style); + panel.SetExtendedStyle(); + } +} + +#ifndef ILC_COLOR32 +#define ILC_COLOR32 0x0020 +#endif + +HRESULT CApp::CreateOnePanel(unsigned panelIndex, const UString &mainPath, const UString &arcFormat, + bool needOpenArc, + COpenResult &openRes) +{ + if (Panels[panelIndex].PanelCreated) + return S_OK; + + m_PanelCallbackImp[panelIndex].Init(this, panelIndex); + + UString path; + if (mainPath.IsEmpty()) + { + if (!::ReadPanelPath(panelIndex, path)) + path.Empty(); + } + else + path = mainPath; + + const unsigned id = 1000 + 100 * panelIndex; // check it + + return Panels[panelIndex].Create(_window, _window, + id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState, + needOpenArc, + openRes); +} + + +static void CreateToolbar(HWND parent, + NControl::CImageList &imageList, + NControl::CToolBar &toolBar, + bool largeButtons) +{ + toolBar.Attach(::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 0 + | WS_CHILD + | WS_VISIBLE + | TBSTYLE_FLAT + | TBSTYLE_TOOLTIPS + | TBSTYLE_WRAPABLE + // | TBSTYLE_AUTOSIZE + // | CCS_NORESIZE + #ifdef UNDER_CE + | CCS_NODIVIDER + | CCS_NOPARENTALIGN + #endif + ,0,0,0,0, parent, NULL, g_hInstance, NULL)); + + // TB_BUTTONSTRUCTSIZE message, which is required for + // backward compatibility. + toolBar.ButtonStructSize(); + + imageList.Create( + largeButtons ? 48: 24, + largeButtons ? 36: 24, + ILC_MASK | ILC_COLOR32, 0, 0); + toolBar.SetImageList(0, imageList); +} + + +struct CButtonInfo +{ + int CommandID; + UINT BitmapResID; + UINT Bitmap2ResID; + UINT StringResID; + + UString GetText() const { return LangString(StringResID); } +}; + +static const CButtonInfo g_StandardButtons[] = +{ + { IDM_COPY_TO, IDB_COPY, IDB_COPY2, IDS_BUTTON_COPY }, + { IDM_MOVE_TO, IDB_MOVE, IDB_MOVE2, IDS_BUTTON_MOVE }, + { IDM_DELETE, IDB_DELETE, IDB_DELETE2, IDS_BUTTON_DELETE } , + { IDM_PROPERTIES, IDB_INFO, IDB_INFO2, IDS_BUTTON_INFO } +}; + +static const CButtonInfo g_ArchiveButtons[] = +{ + { kMenuCmdID_Toolbar_Add, IDB_ADD, IDB_ADD2, IDS_ADD }, + { kMenuCmdID_Toolbar_Extract, IDB_EXTRACT, IDB_EXTRACT2, IDS_EXTRACT }, + { kMenuCmdID_Toolbar_Test, IDB_TEST, IDB_TEST2, IDS_TEST } +}; + +static bool SetButtonText(int commandID, const CButtonInfo *buttons, unsigned numButtons, UString &s) +{ + for (unsigned i = 0; i < numButtons; i++) + { + const CButtonInfo &b = buttons[i]; + if (b.CommandID == commandID) + { + s = b.GetText(); + return true; + } + } + return false; +} + +static void SetButtonText(int commandID, UString &s) +{ + if (SetButtonText(commandID, g_StandardButtons, Z7_ARRAY_SIZE(g_StandardButtons), s)) + return; + SetButtonText(commandID, g_ArchiveButtons, Z7_ARRAY_SIZE(g_ArchiveButtons), s); +} + +static void AddButton( + NControl::CImageList &imageList, + NControl::CToolBar &toolBar, + const CButtonInfo &butInfo, bool showText, bool large) +{ + TBBUTTON but; + but.iBitmap = 0; + but.idCommand = butInfo.CommandID; + but.fsState = TBSTATE_ENABLED; + but.fsStyle = TBSTYLE_BUTTON; + but.dwData = 0; + + UString s = butInfo.GetText(); + but.iString = 0; + if (showText) + but.iString = (INT_PTR)(LPCWSTR)s; + + but.iBitmap = imageList.GetImageCount(); + HBITMAP b = ::LoadBitmap(g_hInstance, + large ? + MAKEINTRESOURCE(butInfo.BitmapResID): + MAKEINTRESOURCE(butInfo.Bitmap2ResID)); + if (b) + { + imageList.AddMasked(b, RGB(255, 0, 255)); + ::DeleteObject(b); + } + #ifdef _UNICODE + toolBar.AddButton(1, &but); + #else + toolBar.AddButtonW(1, &but); + #endif +} + +void CApp::ReloadToolbars() +{ + _buttonsImageList.Destroy(); + _toolBar.Destroy(); + + + if (ShowArchiveToolbar || ShowStandardToolbar) + { + CreateToolbar(_window, _buttonsImageList, _toolBar, LargeButtons); + unsigned i; + if (ShowArchiveToolbar) + for (i = 0; i < Z7_ARRAY_SIZE(g_ArchiveButtons); i++) + AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons); + if (ShowStandardToolbar) + for (i = 0; i < Z7_ARRAY_SIZE(g_StandardButtons); i++) + AddButton(_buttonsImageList, _toolBar, g_StandardButtons[i], ShowButtonsLables, LargeButtons); + + _toolBar.AutoSize(); + } +} + +void CApp::SaveToolbarChanges() +{ + SaveToolbar(); + ReloadToolbars(); + MoveSubWindows(); +} + + +HRESULT CApp::Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes) +{ + _window.Attach(hwnd); + + #ifdef UNDER_CE + _commandBar.Create(g_hInstance, hwnd, 1); + #endif + + MyLoadMenu(false); // needResetMenu + + #ifdef UNDER_CE + _commandBar.AutoSize(); + #endif + + ReadToolbar(); + ReloadToolbars(); + + unsigned i; + for (i = 0; i < kNumPanelsMax; i++) + Panels[i].PanelCreated = false; + + AppState.Read(); + + SetListSettings(); + + if (LastFocusedPanel >= kNumPanelsMax) + LastFocusedPanel = 0; + // ShowDeletedFiles = Read_ShowDeleted(); + + CListMode listMode; + listMode.Read(); + + for (i = 0; i < kNumPanelsMax; i++) + { + CPanel &panel = Panels[i]; + panel._listViewMode = listMode.Panels[i]; + panel._xSize = xSizes[i]; + panel._flatModeForArc = ReadFlatView(i); + } + + for (i = 0; i < kNumPanelsMax; i++) + { + unsigned panelIndex = i; + if (needOpenArc && LastFocusedPanel == 1) + panelIndex = 1 - i; + + bool isMainPanel = (panelIndex == LastFocusedPanel); + + if (NumPanels > 1 || isMainPanel) + { + if (NumPanels == 1) + Panels[panelIndex]._xSize = xSizes[0] + xSizes[1]; + + COpenResult openRes2; + UString path; + if (isMainPanel) + path = mainPath; + + RINOK(CreateOnePanel(panelIndex, path, arcFormat, + isMainPanel && needOpenArc, + *(isMainPanel ? &openRes : &openRes2))) + + if (isMainPanel) + { + if (needOpenArc && !openRes.ArchiveIsOpened) + return S_OK; + } + } + } + + SetFocusedPanel(LastFocusedPanel); + Panels[LastFocusedPanel].SetFocusToList(); + return S_OK; +} + + +HRESULT CApp::SwitchOnOffOnePanel() +{ + if (NumPanels == 1) + { + NumPanels++; + COpenResult openRes; + RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(), + false, // needOpenArc + openRes)) + Panels[1 - LastFocusedPanel].Enable(true); + Panels[1 - LastFocusedPanel].Show(SW_SHOWNORMAL); + } + else + { + NumPanels--; + Panels[1 - LastFocusedPanel].Enable(false); + Panels[1 - LastFocusedPanel].Show(SW_HIDE); + } + MoveSubWindows(); + return S_OK; +} + +void CApp::Save() +{ + AppState.Save(); + CListMode listMode; + + for (unsigned i = 0; i < kNumPanelsMax; i++) + { + const CPanel &panel = Panels[i]; + UString path; + if (panel._parentFolders.IsEmpty()) + path = panel._currentFolderPrefix; + else + path = panel._parentFolders[0].ParentFolderPath; + // GetFolderPath(panel._parentFolders[0].ParentFolder); + SavePanelPath(i, path); + listMode.Panels[i] = panel.GetListViewMode(); + SaveFlatView(i, panel._flatModeForArc); + } + + listMode.Save(); + // Save_ShowDeleted(ShowDeletedFiles); +} + +void CApp::ReleaseApp() +{ + // 24.09: ReleasePanel() will stop panel timer processing. + // but we want to stop timer processing for all panels + // before ReleasePanel() calling. + unsigned i; + for (i = 0; i < kNumPanelsMax; i++) + Panels[i].Disable_Processing_Timer_Notify_StatusBar(); + // It's for unloading COM dll's: don't change it. + for (i = 0; i < kNumPanelsMax; i++) + Panels[i].ReleasePanel(); +} + +// reduces path to part that exists on disk (or root prefix of path) +// output path is normalized (with WCHAR_PATH_SEPARATOR) +static void Reduce_Path_To_RealFileSystemPath(UString &path) +{ + unsigned prefixSize = GetRootPrefixSize(path); + + while (!path.IsEmpty()) + { + if (NFind::DoesDirExist_FollowLink(us2fs(path))) + { + NName::NormalizeDirPathPrefix(path); + break; + } + int pos = path.ReverseFind_PathSepar(); + if (pos < 0) + { + path.Empty(); + break; + } + path.DeleteFrom((unsigned)(pos + 1)); + if ((unsigned)pos + 1 == prefixSize) + break; + path.DeleteFrom((unsigned)pos); + } +} + +// returns: true, if such dir exists or is root +/* +static bool CheckFolderPath(const UString &path) +{ + UString pathReduced = path; + Reduce_Path_To_RealFileSystemPath(pathReduced); + return (pathReduced == path); +} +*/ + +extern UString ConvertSizeToString(UInt64 value); + +static void AddSizeValue(UString &s, UInt64 size) +{ + s += MyFormatNew(IDS_FILE_SIZE, ConvertSizeToString(size)); +} + +static void AddValuePair1(UString &s, UINT resourceID, UInt64 size) +{ + AddLangString(s, resourceID); + s += ": "; + AddSizeValue(s, size); + s.Add_LF(); +} + +void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size); +void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size) +{ + if (num == 0) + return; + AddLangString(s, resourceID); + s += ": "; + s += ConvertSizeToString(num); + + if (size != (UInt64)(Int64)-1) + { + s += " ( "; + AddSizeValue(s, size); + s += " )"; + } + s.Add_LF(); +} + +static void AddPropValueToSum(IFolderFolder *folder, UInt32 index, PROPID propID, UInt64 &sum) +{ + if (sum == (UInt64)(Int64)-1) + return; + NCOM::CPropVariant prop; + folder->GetProperty(index, propID, &prop); + UInt64 val = 0; + if (ConvertPropVariantToUInt64(prop, val)) + sum += val; + else + sum = (UInt64)(Int64)-1; +} + +UString CPanel::GetItemsInfoString(const CRecordVector &indices) +{ + UString info; + UInt64 numDirs, numFiles, filesSize, foldersSize; + numDirs = numFiles = filesSize = foldersSize = 0; + + unsigned i; + for (i = 0; i < indices.Size(); i++) + { + const UInt32 index = indices[i]; + if (IsItem_Folder(index)) + { + AddPropValueToSum(_folder, index, kpidSize, foldersSize); + numDirs++; + } + else + { + AddPropValueToSum(_folder, index, kpidSize, filesSize); + numFiles++; + } + } + + AddValuePair2(info, IDS_PROP_FOLDERS, numDirs, foldersSize); + AddValuePair2(info, IDS_PROP_FILES, numFiles, filesSize); + int numDefined = ((foldersSize != (UInt64)(Int64)-1) && foldersSize != 0) ? 1: 0; + numDefined += ((filesSize != (UInt64)(Int64)-1) && filesSize != 0) ? 1: 0; + if (numDefined == 2) + AddValuePair1(info, IDS_PROP_SIZE, filesSize + foldersSize); + + info.Add_LF(); + info += _currentFolderPrefix; + + for (i = 0; i < indices.Size() && (int)i < (int)kCopyDialog_NumInfoLines - 6; i++) + { + info.Add_LF(); + info += " "; + const UInt32 index = indices[i]; + info += GetItemRelPath(index); + if (IsItem_Folder(index)) + info.Add_PathSepar(); + } + if (i != indices.Size()) + { + info.Add_LF(); + info += " ..."; + } + return info; +} + +bool IsCorrectFsName(const UString &name); + + + +/* Returns true, if path is path that can be used as path for File System functions +*/ + +/* +static bool IsFsPath(const FString &path) +{ + if (!IsAbsolutePath(path)) + return false; + unsigned prefixSize = GetRootPrefixSize(path); +} +*/ + +void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex) +{ + const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); + CPanel &srcPanel = Panels[srcPanelIndex]; + CPanel &destPanel = Panels[destPanelIndex]; + + CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel); + CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel); + + if (move) + { + if (!srcPanel.CheckBeforeUpdate(IDS_MOVE)) + return; + } + else if (!srcPanel.DoesItSupportOperations()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + + CRecordVector indices; + UString destPath; + bool useDestPanel = false; + + { + if (copyToSame) + { + const int focusedItem = srcPanel._listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem); + if (realIndex == kParentIndex) + return; + indices.Add(realIndex); + destPath = srcPanel.GetItemName(realIndex); + } + else + { + srcPanel.Get_ItemIndices_OperSmart(indices); + if (indices.Size() == 0) + return; + destPath = destPanel.GetFsPath(); + if (NumPanels == 1) + Reduce_Path_To_RealFileSystemPath(destPath); + } + } + + UStringVector copyFolders; + ReadCopyHistory(copyFolders); + + const bool useFullItemPaths = srcPanel.Is_IO_FS_Folder(); // maybe we need flat also here ?? + + { + CCopyDialog copyDialog; + + copyDialog.Strings = copyFolders; + copyDialog.Value = destPath; + LangString(move ? IDS_MOVE : IDS_COPY, copyDialog.Title); + LangString(move ? IDS_MOVE_TO : IDS_COPY_TO, copyDialog.Static); + copyDialog.Info = srcPanel.GetItemsInfoString(indices); + + if (copyDialog.Create(srcPanel.GetParent()) != IDOK) + return; + + destPath = copyDialog.Value; + } + + { + if (destPath.IsEmpty()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + + UString correctName; + if (!srcPanel.CorrectFsPath(destPath, correctName)) + { + srcPanel.MessageBox_Error_HRESULT(E_INVALIDARG); + return; + } + + if (IsAbsolutePath(destPath)) + destPath.Empty(); + else + destPath = srcPanel.GetFsPath(); + destPath += correctName; + + #if defined(_WIN32) && !defined(UNDER_CE) + if (destPath.Len() != 0 && destPath[0] == '\\') + if (destPath.Len() == 1 || destPath[1] != '\\') + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + #endif + + bool possibleToUseDestPanel = false; + + if (CompareFileNames(destPath, destPanel.GetFsPath()) == 0) + { + if (NumPanels == 1 || CompareFileNames(destPath, srcPanel.GetFsPath()) == 0) + { + srcPanel.MessageBox_Error(L"Cannot copy files onto itself"); + return; + } + + if (destPanel.DoesItSupportOperations()) + possibleToUseDestPanel = true; + } + + bool destIsFsPath = false; + + if (possibleToUseDestPanel) + { + if (destPanel.IsFSFolder() || destPanel.IsAltStreamsFolder()) + destIsFsPath = true; + else if (destPanel.IsFSDrivesFolder() || destPanel.IsRootFolder()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + } + else + { + if (IsAltPathPrefix(us2fs(destPath))) + { + // we allow alt streams dest only to alt stream folder in second panel + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + /* + FString basePath = us2fs(destPath); + basePath.DeleteBack(); + if (!DoesFileOrDirExist(basePath)) + { + srcPanel.MessageBoxError2Lines(basePath, ERROR_FILE_NOT_FOUND); // GetLastError() + return; + } + destIsFsPath = true; + */ + } + else + { + if (indices.Size() == 1 && + !destPath.IsEmpty() && !IS_PATH_SEPAR(destPath.Back())) + { + int pos = destPath.ReverseFind_PathSepar(); + if (pos < 0) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + { + /* + #ifdef _WIN32 + UString name = destPath.Ptr(pos + 1); + if (name.Find(L':') >= 0) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + #endif + */ + UString prefix = destPath.Left(pos + 1); + if (!CreateComplexDir(us2fs(prefix))) + { + const HRESULT lastError = GetLastError_noZero_HRESULT(); + srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError); + return; + } + } + // bool isFolder = srcPanael.IsItem_Folder(indices[0]); + } + else + { + NName::NormalizeDirPathPrefix(destPath); + if (!CreateComplexDir(us2fs(destPath))) + { + const HRESULT lastError = GetLastError_noZero_HRESULT(); + srcPanel.MessageBox_Error_2Lines_Message_HRESULT(destPath, lastError); + return; + } + } + destIsFsPath = true; + } + } + + if (!destIsFsPath) + useDestPanel = true; + + AddUniqueStringToHeadOfList(copyFolders, destPath); + while (copyFolders.Size() > 20) + copyFolders.DeleteBack(); + SaveCopyHistory(copyFolders); + } + + bool useSrcPanel = !useDestPanel || !srcPanel.Is_IO_FS_Folder(); + + bool useTemp = useSrcPanel && useDestPanel; + if (useTemp && NumPanels == 1) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + + CTempDir tempDirectory; + FString tempDirPrefix; + if (useTemp) + { + tempDirectory.Create(kTempDirPrefix); + tempDirPrefix = tempDirectory.GetPath(); + NFile::NName::NormalizeDirPathPrefix(tempDirPrefix); + } + + CSelectedState srcSelState; + CSelectedState destSelState; + srcPanel.SaveSelectedState(srcSelState); + destPanel.SaveSelectedState(destSelState); + + CPanel::CDisableNotify disableNotify1(destPanel); + CPanel::CDisableNotify disableNotify2(srcPanel); + + HRESULT result = S_OK; + + if (useSrcPanel) + { + CCopyToOptions options; + // options.src_Is_IO_FS_Folder = useFullItemPaths; + options.folder = useTemp ? fs2us(tempDirPrefix) : destPath; + options.moveMode = move; + options.includeAltStreams = true; + options.replaceAltStreamChars = false; + options.showErrorMessages = true; + + result = srcPanel.CopyTo(options, indices, NULL); + } + + if (result == S_OK && useDestPanel) + { + UStringVector filePaths; + UString folderPrefix; + + if (useTemp) + folderPrefix = fs2us(tempDirPrefix); + else + folderPrefix = srcPanel.GetFsPath(); + + filePaths.ClearAndReserve(indices.Size()); + + FOR_VECTOR (i, indices) + { + UInt32 index = indices[i]; + UString s; + if (useFullItemPaths) + s = srcPanel.GetItemRelPath2(index); + else + s = srcPanel.GetItemName_for_Copy(index); + filePaths.AddInReserved(s); + } + + result = destPanel.CopyFrom(move, folderPrefix, filePaths, true, NULL); + } + + if (result != S_OK) + { + // disableNotify1.Restore(); + // disableNotify2.Restore(); + // For Password: + // srcPanel.SetFocusToList(); + // srcPanel.InvalidateList(NULL, true); + + if (result != E_ABORT) + srcPanel.MessageBox_Error_HRESULT(result); + // return; + } + + RefreshTitleAlways(); + + if (copyToSame || move) + { + srcPanel.RefreshListCtrl(srcSelState); + } + + if (!copyToSame) + { + destPanel.RefreshListCtrl(destSelState); + srcPanel.KillSelection(); + } + + disableNotify1.Restore(); + disableNotify2.Restore(); + srcPanel.SetFocusToList(); +} + +void CApp::OnSetSameFolder(unsigned srcPanelIndex) +{ + if (NumPanels <= 1) + return; + const CPanel &srcPanel = Panels[srcPanelIndex]; + CPanel &destPanel = Panels[1 - srcPanelIndex]; + destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix); +} + +void CApp::OnSetSubFolder(unsigned srcPanelIndex) +{ + if (NumPanels <= 1) + return; + const CPanel &srcPanel = Panels[srcPanelIndex]; + CPanel &destPanel = Panels[1 - srcPanelIndex]; + + const int focusedItem = srcPanel._listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem); + if (!srcPanel.IsItem_Folder(realIndex)) + return; + + // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR); + + CMyComPtr newFolder; + if (realIndex == kParentIndex) + { + if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK) + return; + if (!newFolder) + { + { + const UString parentPrefix = srcPanel.GetParentDirPrefix(); + COpenResult openRes; + destPanel.BindToPath(parentPrefix, UString(), openRes); + } + destPanel.RefreshListCtrl(); + return; + } + } + else + { + if (srcPanel._folder->BindToFolder(realIndex, &newFolder) != S_OK) + return; + } + + if (!newFolder) + return; + + destPanel.CloseOpenFolders(); + destPanel.SetNewFolder(newFolder); + destPanel.RefreshListCtrl(); +} + +/* +int CApp::GetFocusedPanelIndex() const +{ + return LastFocusedPanel; + HWND hwnd = ::GetFocus(); + for (;;) + { + if (hwnd == 0) + return 0; + for (unsigned i = 0; i < kNumPanelsMax; i++) + { + if (PanelsCreated[i] && + ((HWND)Panels[i] == hwnd || Panels[i]._listView == hwnd)) + return i; + } + hwnd = GetParent(hwnd); + } +} +*/ + +static UString g_ToolTipBuffer; +static CSysString g_ToolTipBufferSys; + +void CApp::OnNotify(int /* ctrlID */, LPNMHDR pnmh) +{ + { + if (pnmh->code == TTN_GETDISPINFO) + { + LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh; + info->hinst = NULL; + g_ToolTipBuffer.Empty(); + SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); + g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer); + info->lpszText = g_ToolTipBufferSys.Ptr_non_const(); + return; + } + #ifndef _UNICODE + if (pnmh->code == TTN_GETDISPINFOW) + { + LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh; + info->hinst = NULL; + g_ToolTipBuffer.Empty(); + SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer); + info->lpszText = g_ToolTipBuffer.Ptr_non_const(); + return; + } + #endif + } +} + +void CApp::RefreshTitle(bool always) +{ + UString path = GetFocusedPanel()._currentFolderPrefix; + if (path.IsEmpty()) + path = "7-Zip"; // LangString(IDS_APP_TITLE); + if (!always && path == PrevTitle) + return; + PrevTitle = path; + NWindows::MySetWindowText(_window, path); +} + +void CApp::RefreshTitlePanel(unsigned panelIndex, bool always) +{ + if (panelIndex != GetFocusedPanelIndex()) + return; + RefreshTitle(always); +} + +static void AddUniqueStringToHead(UStringVector &list, const UString &s) +{ + for (unsigned i = 0; i < list.Size();) + if (s.IsEqualTo_NoCase(list[i])) + list.Delete(i); + else + i++; + list.Insert(0, s); +} + + +void CFolderHistory::Normalize() +{ + const unsigned kMaxSize = 100; + if (Strings.Size() > kMaxSize) + Strings.DeleteFrom(kMaxSize); +} + +void CFolderHistory::AddString(const UString &s) +{ + NSynchronization::CCriticalSectionLock lock(_criticalSection); + AddUniqueStringToHead(Strings, s); + Normalize(); +} diff --git a/CPP/7zip/UI/FileManager/App.h b/CPP/7zip/UI/FileManager/App.h index 89c844fce..cf74d6a5d 100644 --- a/CPP/7zip/UI/FileManager/App.h +++ b/CPP/7zip/UI/FileManager/App.h @@ -1,314 +1,314 @@ -// App.h - -#ifndef ZIP7_INC_APP_H -#define ZIP7_INC_APP_H - -#include "../../../Windows/Control/CommandBar.h" -#include "../../../Windows/Control/ImageList.h" - -#include "AppState.h" -#include "Panel.h" - -class CApp; - -extern CApp g_App; -extern HWND g_HWND; - -const unsigned kNumPanelsMax = 2; - -extern bool g_IsSmallScreen; - -// must be larger than context menu IDs -const int kMenuCmdID_Toolbar_Start = 1070; -const int kMenuCmdID_Plugin_Start = 1100; - -enum -{ - kMenuCmdID_Toolbar_Add = kMenuCmdID_Toolbar_Start, - kMenuCmdID_Toolbar_Extract, - kMenuCmdID_Toolbar_Test, - kMenuCmdID_Toolbar_End -}; - -class CPanelCallbackImp Z7_final: public CPanelCallback -{ - CApp *_app; - unsigned _index; -public: - void Init(CApp *app, unsigned index) - { - _app = app; - _index = index; - } - virtual void OnTab() Z7_override; - virtual void SetFocusToPath(unsigned index) Z7_override; - virtual void OnCopy(bool move, bool copyToSame) Z7_override; - virtual void OnSetSameFolder() Z7_override; - virtual void OnSetSubFolder() Z7_override; - virtual void PanelWasFocused() Z7_override; - virtual void DragBegin() Z7_override; - virtual void DragEnd() Z7_override; - virtual void RefreshTitle(bool always) Z7_override; -}; - - -class CDropTarget; - -class CApp -{ -public: - NWindows::CWindow _window; - bool ShowSystemMenu; - bool AutoRefresh_Mode; - // bool ShowDeletedFiles; - unsigned NumPanels; - unsigned LastFocusedPanel; - - bool ShowStandardToolbar; - bool ShowArchiveToolbar; - bool ShowButtonsLables; - bool LargeButtons; - - CAppState AppState; - CPanelCallbackImp m_PanelCallbackImp[kNumPanelsMax]; - CPanel Panels[kNumPanelsMax]; - - NWindows::NControl::CImageList _buttonsImageList; - - #ifdef UNDER_CE - NWindows::NControl::CCommandBar _commandBar; - #endif - NWindows::NControl::CToolBar _toolBar; - - CDropTarget *_dropTargetSpec; - CMyComPtr _dropTarget; - - UString LangString_N_SELECTED_ITEMS; - - void ReloadLangItems(); - - CApp(): - _window(NULL), - AutoRefresh_Mode(true), - NumPanels(2), - LastFocusedPanel(0) - { - SetPanels_AutoRefresh_Mode(); - } - - void CreateDragTarget(); - void SetFocusedPanel(unsigned index); - void DragBegin(unsigned panelIndex); - void DragEnd(); - - void OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex); - void OnSetSameFolder(unsigned srcPanelIndex); - void OnSetSubFolder(unsigned srcPanelIndex); - - HRESULT CreateOnePanel(unsigned panelIndex, const UString &mainPath, const UString &arcFormat, bool needOpenArc, COpenResult &openRes); - HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes); - void Read(); - void Save(); - void Release(); - - // void SetFocus(int panelIndex) { Panels[panelIndex].SetFocusToList(); } - void SetFocusToLastItem() { Panels[LastFocusedPanel].SetFocusToLastRememberedItem(); } - unsigned GetFocusedPanelIndex() const { return LastFocusedPanel; } - bool IsPanelVisible(unsigned index) const { return (NumPanels > 1 || index == LastFocusedPanel); } - CPanel &GetFocusedPanel() { return Panels[GetFocusedPanelIndex()]; } - - // File Menu - void OpenItem() { GetFocusedPanel().OpenSelectedItems(true); } - void OpenItemInside(const wchar_t *type) { GetFocusedPanel().OpenFocusedItemAsInternal(type); } - void OpenItemOutside() { GetFocusedPanel().OpenSelectedItems(false); } - void EditItem(bool useEditor) { GetFocusedPanel().EditItem(useEditor); } - void Rename() { GetFocusedPanel().RenameFile(); } - void CopyTo() { OnCopy(false, false, GetFocusedPanelIndex()); } - void MoveTo() { OnCopy(true, false, GetFocusedPanelIndex()); } - void Delete(bool toRecycleBin) { GetFocusedPanel().DeleteItems(toRecycleBin); } - HRESULT CalculateCrc2(const UString &methodName); - void CalculateCrc(const char *methodName); - - void DiffFiles(const UString &path1, const UString &path2); - void DiffFiles(); - - void VerCtrl(unsigned id); - - void Split(); - void Combine(); - void Properties() { GetFocusedPanel().Properties(); } - void Comment() { GetFocusedPanel().ChangeComment(); } - - #ifndef UNDER_CE - void Link(); - void OpenAltStreams() { GetFocusedPanel().OpenAltStreams(); } - #endif - - void CreateFolder() { GetFocusedPanel().CreateFolder(); } - void CreateFile() { GetFocusedPanel().CreateFile(); } - - // Edit - void EditCut() { GetFocusedPanel().EditCut(); } - void EditCopy() { GetFocusedPanel().EditCopy(); } - void EditPaste() { GetFocusedPanel().EditPaste(); } - - void SelectAll(bool selectMode) { GetFocusedPanel().SelectAll(selectMode); } - void InvertSelection() { GetFocusedPanel().InvertSelection(); } - void SelectSpec(bool selectMode) { GetFocusedPanel().SelectSpec(selectMode); } - void SelectByType(bool selectMode) { GetFocusedPanel().SelectByType(selectMode); } - - void Refresh_StatusBar() { GetFocusedPanel().Refresh_StatusBar(); } - - void SetListViewMode(UInt32 index) { GetFocusedPanel().SetListViewMode(index); } - UInt32 GetListViewMode() { return GetFocusedPanel().GetListViewMode(); } - PROPID GetSortID() { return GetFocusedPanel().GetSortID(); } - - void SortItemsWithPropID(PROPID propID) { GetFocusedPanel().SortItemsWithPropID(propID); } - - void OpenRootFolder() { GetFocusedPanel().OpenDrivesFolder(); } - void OpenParentFolder() { GetFocusedPanel().OpenParentFolder(); } - void FoldersHistory() { GetFocusedPanel().FoldersHistory(); } - void RefreshView() { GetFocusedPanel().OnReload(); } - void RefreshAllPanels() - { - for (unsigned i = 0; i < NumPanels; i++) - { - unsigned index = i; - if (NumPanels == 1) - index = LastFocusedPanel; - Panels[index].OnReload(); - } - } - - /* - void SysIconsWereChanged() - { - for (unsigned i = 0; i < NumPanels; i++) - { - unsigned index = i; - if (NumPanels == 1) - index = LastFocusedPanel; - Panels[index].SysIconsWereChanged(); - } - } - */ - - void SetListSettings(); - HRESULT SwitchOnOffOnePanel(); - - CIntVector _timestampLevels; - - bool GetFlatMode() { return Panels[LastFocusedPanel].GetFlatMode(); } - - int GetTimestampLevel() const { return Panels[LastFocusedPanel]._timestampLevel; } - void SetTimestampLevel(int level) - { - for (unsigned i = 0; i < kNumPanelsMax; i++) - { - CPanel &panel = Panels[i]; - panel._timestampLevel = level; - } - RedrawListItems_InPanels(); - } - - void RedrawListItems_InPanels() - { - for (unsigned i = 0; i < kNumPanelsMax; i++) - { - CPanel &panel = Panels[i]; - if (panel.PanelCreated) - panel.RedrawListItems(); - } - } - - // bool Get_ShowNtfsStrems_Mode() { return Panels[LastFocusedPanel].Get_ShowNtfsStrems_Mode(); } - - void ChangeFlatMode() { Panels[LastFocusedPanel].ChangeFlatMode(); } - // void Change_ShowNtfsStrems_Mode() { Panels[LastFocusedPanel].Change_ShowNtfsStrems_Mode(); } - // void Change_ShowDeleted() { ShowDeletedFiles = !ShowDeletedFiles; } - - bool Get_AutoRefresh_Mode() - { - // return Panels[LastFocusedPanel].Get_ShowNtfsStrems_Mode(); - return AutoRefresh_Mode; - } - void Change_AutoRefresh_Mode() - { - AutoRefresh_Mode = !AutoRefresh_Mode; - SetPanels_AutoRefresh_Mode(); - } - void SetPanels_AutoRefresh_Mode() - { - for (unsigned i = 0; i < kNumPanelsMax; i++) - Panels[i].Set_AutoRefresh_Mode(AutoRefresh_Mode); - } - - void OpenBookmark(unsigned index) { GetFocusedPanel().OpenBookmark(index); } - void SetBookmark(unsigned index) { GetFocusedPanel().SetBookmark(index); } - - void ReloadToolbars(); - void ReadToolbar() - { - const UInt32 mask = ReadToolbarsMask(); - if (mask & ((UInt32)1 << 31)) - { - ShowButtonsLables = !g_IsSmallScreen; - LargeButtons = false; - ShowStandardToolbar = ShowArchiveToolbar = true; - } - else - { - ShowButtonsLables = ((mask & 1) != 0); - LargeButtons = ((mask & 2) != 0); - ShowStandardToolbar = ((mask & 4) != 0); - ShowArchiveToolbar = ((mask & 8) != 0); - } - } - void SaveToolbar() - { - UInt32 mask = 0; - if (ShowButtonsLables) mask |= 1; - if (LargeButtons) mask |= 2; - if (ShowStandardToolbar) mask |= 4; - if (ShowArchiveToolbar) mask |= 8; - SaveToolbarsMask(mask); - } - - void SaveToolbarChanges(); - - void SwitchStandardToolbar() - { - ShowStandardToolbar = !ShowStandardToolbar; - SaveToolbarChanges(); - } - void SwitchArchiveToolbar() - { - ShowArchiveToolbar = !ShowArchiveToolbar; - SaveToolbarChanges(); - } - void SwitchButtonsLables() - { - ShowButtonsLables = !ShowButtonsLables; - SaveToolbarChanges(); - } - void SwitchLargeButtons() - { - LargeButtons = !LargeButtons; - SaveToolbarChanges(); - } - - void AddToArchive() { GetFocusedPanel().AddToArchive(); } - void ExtractArchives() { GetFocusedPanel().ExtractArchives(); } - void TestArchives() { GetFocusedPanel().TestArchives(); } - - void OnNotify(int ctrlID, LPNMHDR pnmh); - - UString PrevTitle; - void RefreshTitle(bool always = false); - void RefreshTitleAlways() { RefreshTitle(true); } - void RefreshTitlePanel(unsigned panelIndex, bool always = false); - - void MoveSubWindows(); -}; - -#endif +// App.h + +#ifndef ZIP7_INC_APP_H +#define ZIP7_INC_APP_H + +#include "../../../Windows/Control/CommandBar.h" +#include "../../../Windows/Control/ImageList.h" + +#include "AppState.h" +#include "Panel.h" + +class CApp; + +extern CApp g_App; +extern HWND g_HWND; + +const unsigned kNumPanelsMax = 2; + +extern bool g_IsSmallScreen; + +// must be larger than context menu IDs +const int kMenuCmdID_Toolbar_Start = 1070; +const int kMenuCmdID_Plugin_Start = 1100; + +enum +{ + kMenuCmdID_Toolbar_Add = kMenuCmdID_Toolbar_Start, + kMenuCmdID_Toolbar_Extract, + kMenuCmdID_Toolbar_Test, + kMenuCmdID_Toolbar_End +}; + +class CPanelCallbackImp Z7_final: public CPanelCallback +{ + CApp *_app; + unsigned _index; +public: + void Init(CApp *app, unsigned index) + { + _app = app; + _index = index; + } + virtual void OnTab() Z7_override; + virtual void SetFocusToPath(unsigned index) Z7_override; + virtual void OnCopy(bool move, bool copyToSame) Z7_override; + virtual void OnSetSameFolder() Z7_override; + virtual void OnSetSubFolder() Z7_override; + virtual void PanelWasFocused() Z7_override; + virtual void DragBegin() Z7_override; + virtual void DragEnd() Z7_override; + virtual void RefreshTitle(bool always) Z7_override; +}; + + +class CDropTarget; + +class CApp +{ +public: + NWindows::CWindow _window; + bool ShowSystemMenu; + bool AutoRefresh_Mode; + // bool ShowDeletedFiles; + unsigned NumPanels; + unsigned LastFocusedPanel; + + bool ShowStandardToolbar; + bool ShowArchiveToolbar; + bool ShowButtonsLables; + bool LargeButtons; + + CAppState AppState; + CPanelCallbackImp m_PanelCallbackImp[kNumPanelsMax]; + CPanel Panels[kNumPanelsMax]; + + NWindows::NControl::CImageList _buttonsImageList; + + #ifdef UNDER_CE + NWindows::NControl::CCommandBar _commandBar; + #endif + NWindows::NControl::CToolBar _toolBar; + + CDropTarget *_dropTargetSpec; + CMyComPtr _dropTarget; + + UString LangString_N_SELECTED_ITEMS; + + void ReloadLangItems(); + + CApp(): + _window(NULL), + AutoRefresh_Mode(true), + NumPanels(2), + LastFocusedPanel(0) + { + SetPanels_AutoRefresh_Mode(); + } + + void CreateDragTarget(); + void SetFocusedPanel(unsigned index); + void DragBegin(unsigned panelIndex); + void DragEnd(); + + void OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex); + void OnSetSameFolder(unsigned srcPanelIndex); + void OnSetSubFolder(unsigned srcPanelIndex); + + HRESULT CreateOnePanel(unsigned panelIndex, const UString &mainPath, const UString &arcFormat, bool needOpenArc, COpenResult &openRes); + HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes); + void Read(); + void Save(); + void ReleaseApp(); + + // void SetFocus(int panelIndex) { Panels[panelIndex].SetFocusToList(); } + void SetFocusToLastItem() { Panels[LastFocusedPanel].SetFocusToLastRememberedItem(); } + unsigned GetFocusedPanelIndex() const { return LastFocusedPanel; } + bool IsPanelVisible(unsigned index) const { return (NumPanels > 1 || index == LastFocusedPanel); } + CPanel &GetFocusedPanel() { return Panels[GetFocusedPanelIndex()]; } + + // File Menu + void OpenItem() { GetFocusedPanel().OpenSelectedItems(true); } + void OpenItemInside(const wchar_t *type) { GetFocusedPanel().OpenFocusedItemAsInternal(type); } + void OpenItemOutside() { GetFocusedPanel().OpenSelectedItems(false); } + void EditItem(bool useEditor) { GetFocusedPanel().EditItem(useEditor); } + void Rename() { GetFocusedPanel().RenameFile(); } + void CopyTo() { OnCopy(false, false, GetFocusedPanelIndex()); } + void MoveTo() { OnCopy(true, false, GetFocusedPanelIndex()); } + void Delete(bool toRecycleBin) { GetFocusedPanel().DeleteItems(toRecycleBin); } + HRESULT CalculateCrc2(const UString &methodName); + void CalculateCrc(const char *methodName); + + void DiffFiles(const UString &path1, const UString &path2); + void DiffFiles(); + + void VerCtrl(unsigned id); + + void Split(); + void Combine(); + void Properties() { GetFocusedPanel().Properties(); } + void Comment() { GetFocusedPanel().ChangeComment(); } + + #ifndef UNDER_CE + void Link(); + void OpenAltStreams() { GetFocusedPanel().OpenAltStreams(); } + #endif + + void CreateFolder() { GetFocusedPanel().CreateFolder(); } + void CreateFile() { GetFocusedPanel().CreateFile(); } + + // Edit + void EditCut() { GetFocusedPanel().EditCut(); } + void EditCopy() { GetFocusedPanel().EditCopy(); } + void EditPaste() { GetFocusedPanel().EditPaste(); } + + void SelectAll(bool selectMode) { GetFocusedPanel().SelectAll(selectMode); } + void InvertSelection() { GetFocusedPanel().InvertSelection(); } + void SelectSpec(bool selectMode) { GetFocusedPanel().SelectSpec(selectMode); } + void SelectByType(bool selectMode) { GetFocusedPanel().SelectByType(selectMode); } + + void Refresh_StatusBar() { GetFocusedPanel().Refresh_StatusBar(); } + + void SetListViewMode(UInt32 index) { GetFocusedPanel().SetListViewMode(index); } + UInt32 GetListViewMode() { return GetFocusedPanel().GetListViewMode(); } + PROPID GetSortID() { return GetFocusedPanel().GetSortID(); } + + void SortItemsWithPropID(PROPID propID) { GetFocusedPanel().SortItemsWithPropID(propID); } + + void OpenRootFolder() { GetFocusedPanel().OpenDrivesFolder(); } + void OpenParentFolder() { GetFocusedPanel().OpenParentFolder(); } + void FoldersHistory() { GetFocusedPanel().FoldersHistory(); } + void RefreshView() { GetFocusedPanel().OnReload(); } + void RefreshAllPanels() + { + for (unsigned i = 0; i < NumPanels; i++) + { + unsigned index = i; + if (NumPanels == 1) + index = LastFocusedPanel; + Panels[index].OnReload(); + } + } + + /* + void SysIconsWereChanged() + { + for (unsigned i = 0; i < NumPanels; i++) + { + unsigned index = i; + if (NumPanels == 1) + index = LastFocusedPanel; + Panels[index].SysIconsWereChanged(); + } + } + */ + + void SetListSettings(); + HRESULT SwitchOnOffOnePanel(); + + CIntVector _timestampLevels; + + bool GetFlatMode() { return Panels[LastFocusedPanel].GetFlatMode(); } + + int GetTimestampLevel() const { return Panels[LastFocusedPanel]._timestampLevel; } + void SetTimestampLevel(int level) + { + for (unsigned i = 0; i < kNumPanelsMax; i++) + { + CPanel &panel = Panels[i]; + panel._timestampLevel = level; + } + RedrawListItems_InPanels(); + } + + void RedrawListItems_InPanels() + { + for (unsigned i = 0; i < kNumPanelsMax; i++) + { + CPanel &panel = Panels[i]; + if (panel.PanelCreated) + panel.RedrawListItems(); + } + } + + // bool Get_ShowNtfsStrems_Mode() { return Panels[LastFocusedPanel].Get_ShowNtfsStrems_Mode(); } + + void ChangeFlatMode() { Panels[LastFocusedPanel].ChangeFlatMode(); } + // void Change_ShowNtfsStrems_Mode() { Panels[LastFocusedPanel].Change_ShowNtfsStrems_Mode(); } + // void Change_ShowDeleted() { ShowDeletedFiles = !ShowDeletedFiles; } + + bool Get_AutoRefresh_Mode() + { + // return Panels[LastFocusedPanel].Get_ShowNtfsStrems_Mode(); + return AutoRefresh_Mode; + } + void Change_AutoRefresh_Mode() + { + AutoRefresh_Mode = !AutoRefresh_Mode; + SetPanels_AutoRefresh_Mode(); + } + void SetPanels_AutoRefresh_Mode() + { + for (unsigned i = 0; i < kNumPanelsMax; i++) + Panels[i].Set_AutoRefresh_Mode(AutoRefresh_Mode); + } + + void OpenBookmark(unsigned index) { GetFocusedPanel().OpenBookmark(index); } + void SetBookmark(unsigned index) { GetFocusedPanel().SetBookmark(index); } + + void ReloadToolbars(); + void ReadToolbar() + { + const UInt32 mask = ReadToolbarsMask(); + if (mask & ((UInt32)1 << 31)) + { + ShowButtonsLables = !g_IsSmallScreen; + LargeButtons = false; + ShowStandardToolbar = ShowArchiveToolbar = true; + } + else + { + ShowButtonsLables = ((mask & 1) != 0); + LargeButtons = ((mask & 2) != 0); + ShowStandardToolbar = ((mask & 4) != 0); + ShowArchiveToolbar = ((mask & 8) != 0); + } + } + void SaveToolbar() + { + UInt32 mask = 0; + if (ShowButtonsLables) mask |= 1; + if (LargeButtons) mask |= 2; + if (ShowStandardToolbar) mask |= 4; + if (ShowArchiveToolbar) mask |= 8; + SaveToolbarsMask(mask); + } + + void SaveToolbarChanges(); + + void SwitchStandardToolbar() + { + ShowStandardToolbar = !ShowStandardToolbar; + SaveToolbarChanges(); + } + void SwitchArchiveToolbar() + { + ShowArchiveToolbar = !ShowArchiveToolbar; + SaveToolbarChanges(); + } + void SwitchButtonsLables() + { + ShowButtonsLables = !ShowButtonsLables; + SaveToolbarChanges(); + } + void SwitchLargeButtons() + { + LargeButtons = !LargeButtons; + SaveToolbarChanges(); + } + + void AddToArchive() { GetFocusedPanel().AddToArchive(); } + void ExtractArchives() { GetFocusedPanel().ExtractArchives(); } + void TestArchives() { GetFocusedPanel().TestArchives(); } + + void OnNotify(int ctrlID, LPNMHDR pnmh); + + UString PrevTitle; + void RefreshTitle(bool always = false); + void RefreshTitleAlways() { RefreshTitle(true); } + void RefreshTitlePanel(unsigned panelIndex, bool always = false); + + void MoveSubWindows(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/AppState.h b/CPP/7zip/UI/FileManager/AppState.h index 8348fd02c..6630b9628 100644 --- a/CPP/7zip/UI/FileManager/AppState.h +++ b/CPP/7zip/UI/FileManager/AppState.h @@ -1,95 +1,95 @@ -// AppState.h - -#ifndef ZIP7_INC_APP_STATE_H -#define ZIP7_INC_APP_STATE_H - -#include "../../../Windows/Synchronization.h" - -#include "ViewSettings.h" - -class CFastFolders -{ - NWindows::NSynchronization::CCriticalSection _criticalSection; -public: - UStringVector Strings; - void SetString(unsigned index, const UString &s) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - while (Strings.Size() <= index) - Strings.AddNew(); - Strings[index] = s; - } - UString GetString(unsigned index) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - if (index >= Strings.Size()) - return UString(); - return Strings[index]; - } - void Save() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - SaveFastFolders(Strings); - } - void Read() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - ReadFastFolders(Strings); - } -}; - -class CFolderHistory -{ - NWindows::NSynchronization::CCriticalSection _criticalSection; - UStringVector Strings; - - void Normalize(); - -public: - - void GetList(UStringVector &foldersHistory) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - foldersHistory = Strings; - } - - void AddString(const UString &s); - - void RemoveAll() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - Strings.Clear(); - } - - void Save() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - SaveFolderHistory(Strings); - } - - void Read() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); - ReadFolderHistory(Strings); - Normalize(); - } -}; - -struct CAppState -{ - CFastFolders FastFolders; - CFolderHistory FolderHistory; - - void Save() - { - FastFolders.Save(); - FolderHistory.Save(); - } - void Read() - { - FastFolders.Read(); - FolderHistory.Read(); - } -}; - -#endif +// AppState.h + +#ifndef ZIP7_INC_APP_STATE_H +#define ZIP7_INC_APP_STATE_H + +#include "../../../Windows/Synchronization.h" + +#include "ViewSettings.h" + +class CFastFolders +{ + NWindows::NSynchronization::CCriticalSection _criticalSection; +public: + UStringVector Strings; + void SetString(unsigned index, const UString &s) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + while (Strings.Size() <= index) + Strings.AddNew(); + Strings[index] = s; + } + UString GetString(unsigned index) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + if (index >= Strings.Size()) + return UString(); + return Strings[index]; + } + void Save() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + SaveFastFolders(Strings); + } + void Read() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + ReadFastFolders(Strings); + } +}; + +class CFolderHistory +{ + NWindows::NSynchronization::CCriticalSection _criticalSection; + UStringVector Strings; + + void Normalize(); + +public: + + void GetList(UStringVector &foldersHistory) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + foldersHistory = Strings; + } + + void AddString(const UString &s); + + void RemoveAll() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + Strings.Clear(); + } + + void Save() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + SaveFolderHistory(Strings); + } + + void Read() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + ReadFolderHistory(Strings); + Normalize(); + } +}; + +struct CAppState +{ + CFastFolders FastFolders; + CFolderHistory FolderHistory; + + void Save() + { + FastFolders.Save(); + FolderHistory.Save(); + } + void Read() + { + FastFolders.Read(); + FolderHistory.Read(); + } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.cpp b/CPP/7zip/UI/FileManager/BrowseDialog.cpp index b4ff7e8d3..b12d8e814 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.cpp +++ b/CPP/7zip/UI/FileManager/BrowseDialog.cpp @@ -1,1132 +1,1132 @@ -// BrowseDialog.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include "../../../Common/IntToString.h" - -#ifndef UNDER_CE -#include "../../../Windows/CommonDialog.h" -#include "../../../Windows/Shell.h" -#endif - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileFind.h" - -#ifdef UNDER_CE -#include -#endif - -#include "BrowseDialog.h" - -#define USE_MY_BROWSE_DIALOG - -#ifdef USE_MY_BROWSE_DIALOG - -#include "../../../Common/Defs.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/Edit.h" -#include "../../../Windows/Control/ListView.h" - -#include "BrowseDialogRes.h" -#include "PropertyNameRes.h" -#include "SysIconUtils.h" - -#ifndef Z7_SFX -#include "RegistryUtils.h" -#endif - -#endif // USE_MY_BROWSE_DIALOG - -#include "ComboDialog.h" -#include "LangUtils.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NName; -using namespace NFind; - -static void MessageBox_Error_Global(HWND wnd, const wchar_t *message) -{ - ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR); -} - -#ifdef USE_MY_BROWSE_DIALOG - -#if 0 -extern HINSTANCE g_hInstance; -#endif -extern bool g_LVN_ITEMACTIVATE_Support; - -static const int kParentIndex = -1; -static const UINT k_Message_RefreshPathEdit = WM_APP + 1; - -extern UString HResultToMessage(HRESULT errorCode); - -static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name) -{ - UString s = HResultToMessage(errorCode); - if (name) - { - s.Add_LF(); - s += name; - } - MessageBox_Error_Global(wnd, s); -} - -class CBrowseDialog: public NControl::CModalDialog -{ - NControl::CListView _list; - NControl::CEdit _pathEdit; - NControl::CComboBox _filterCombo; - - CObjectVector _files; - - CExtToIconMap _extToIconMap; - int _sortIndex; - bool _ascending; - #ifndef Z7_SFX - bool _showDots; - #endif - UString _topDirPrefix; // we don't open parent of that folder - UString DirPrefix; - - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual void OnOK() Z7_override; - - bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo); - - void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); } - - bool GetParentPath(const UString &path, UString &parentPrefix, UString &name); - // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter - HRESULT Reload(const UString &pathPrefix, const UString &selectedName); - HRESULT Reload(); - - void OpenParentFolder(); - void SetPathEditText(); - void OnCreateDir(); - void OnItemEnter(); - void FinishOnOK(); - - int GetRealItemIndex(int indexInListView) const - { - LPARAM param; - if (!_list.GetItemParam((unsigned)indexInListView, param)) - return (int)-1; - return (int)param; - } - -public: - - bool SaveMode; - bool FolderMode; - int FilterIndex; // [in / out] - CObjectVector Filters; - - UString FilePath; // [in / out] - UString Title; - - CBrowseDialog(): - #ifndef Z7_SFX - _showDots(false), - #endif - SaveMode(false) - , FolderMode(false) - , FilterIndex(-1) - {} - INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_BROWSE, parent); } - int CompareItems(LPARAM lParam1, LPARAM lParam2) const; -}; - - -bool CBrowseDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetDlgItems(*this, NULL, 0); - #endif - if (!Title.IsEmpty()) - SetText(Title); - _list.Attach(GetItem(IDL_BROWSE)); - _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER)); - _pathEdit.Attach(GetItem(IDE_BROWSE_PATH)); - - #ifndef UNDER_CE - _list.SetUnicodeFormat(); - #endif - - #ifndef Z7_SFX - CFmSettings st; - st.Load(); - if (st.SingleClick) - _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT); - _showDots = st.ShowDots; - #endif - - { - /* - Filters.Clear(); // for debug - if (Filters.IsEmpty() && !FolderMode) - { - CBrowseFilterInfo &f = Filters.AddNew(); - const UString mask("*.*"); - f.Masks.Add(mask); - // f.Description = "("; - f.Description += mask; - // f.Description += ")"; - } - */ - - FOR_VECTOR (i, Filters) - { - _filterCombo.AddString(Filters[i].Description); - } - - if (Filters.Size() <= 1) - { - if (FolderMode) - HideItem(IDC_BROWSE_FILTER); - else - EnableItem(IDC_BROWSE_FILTER, false); - } - - if (/* FilterIndex >= 0 && */ (unsigned)FilterIndex < Filters.Size()) - _filterCombo.SetCurSel(FilterIndex); - } - - _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); - _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); - - _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100); - _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100); - { - LV_COLUMNW column; - column.iSubItem = 2; - column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; - column.fmt = LVCFMT_RIGHT; - column.cx = 100; - const UString s = LangString(IDS_PROP_SIZE); - column.pszText = s.Ptr_non_const(); - _list.InsertColumn(2, &column); - } - - _list.InsertItem(0, L"12345678901234567" - #ifndef UNDER_CE - L"1234567890" - #endif - ); - _list.SetSubItem(0, 1, L"2009-09-09" - #ifndef UNDER_CE - L" 09:09" - #endif - ); - _list.SetSubItem(0, 2, L"9999 MB"); - for (int i = 0; i < 3; i++) - _list.SetColumnWidthAuto(i); - _list.DeleteAllItems(); - - _ascending = true; - _sortIndex = 0; - - NormalizeSize(); - - _topDirPrefix.Empty(); - { - unsigned rootSize = GetRootPrefixSize(FilePath); - #if defined(_WIN32) && !defined(UNDER_CE) - // We can go up from root folder to drives list - if (IsDrivePath(FilePath)) - rootSize = 0; - else if (IsSuperPath(FilePath)) - { - if (IsDrivePath(FilePath.Ptr(kSuperPathPrefixSize))) - rootSize = kSuperPathPrefixSize; - } - #endif - _topDirPrefix.SetFrom(FilePath, rootSize); - } - - UString name; - if (!GetParentPath(FilePath, DirPrefix, name)) - DirPrefix = _topDirPrefix; - - for (;;) - { - UString baseFolder = DirPrefix; - if (Reload(baseFolder, name) == S_OK) - break; - name.Empty(); - if (DirPrefix.IsEmpty()) - break; - UString parent, name2; - GetParentPath(DirPrefix, parent, name2); - DirPrefix = parent; - } - - if (name.IsEmpty()) - name = FilePath; - if (FolderMode) - NormalizeDirPathPrefix(name); - _pathEdit.SetText(name); - - #ifndef UNDER_CE - /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible, - even if we use mouse for pressing the button to open this dialog. */ - PostMsg(Z7_WIN_WM_UPDATEUISTATE, MAKEWPARAM(Z7_WIN_UIS_CLEAR, Z7_WIN_UISF_HIDEFOCUS)); - #endif - -#if 0 - { - const HWND hwndTool = GetItem(IDB_BROWSE_CREATE_DIR); - if (hwndTool) - { - // Create the tooltip: - const HWND hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, - WS_POPUP | TTS_ALWAYSTIP - // | TTS_BALLOON - , CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - *this, NULL, g_hInstance, NULL); - if (hwndTip) - { - // Associate the tooltip with the tool: - TOOLINFOW toolInfo; - memset(&toolInfo, 0, sizeof(toolInfo)); - toolInfo.cbSize = sizeof(toolInfo); - toolInfo.hwnd = *this; - toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; - toolInfo.uId = (UINT_PTR)hwndTool; - UString s; -#ifdef Z7_LANG - LangString_OnlyFromLangFile(IDM_CREATE_FOLDER, s); - s.RemoveChar(L'&'); - if (s.IsEmpty()) -#endif - s = "Create Folder"; - toolInfo.lpszText = s.Ptr_non_const(); - SendMessage(hwndTip, TTM_ADDTOOLW, 0, (LPARAM)&toolInfo); - } - } - } -#endif - return CModalDialog::OnInit(); -} - -bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - { - RECT r; - GetClientRectOfItem(IDB_BROWSE_PARENT, r); - mx = r.left; - my = r.top; - } - InvalidateRect(NULL); - - int xLim = xSize - mx; - { - RECT r; - GetClientRectOfItem(IDT_BROWSE_FOLDER, r); - MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r)); - } - - int bx1, bx2, by; - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDOK, bx2, by); - int y = ySize - my - by; - int x = xLim - bx1; - MoveItem(IDCANCEL, x, y, bx1, by); - MoveItem(IDOK, x - mx - bx2, y, bx2, by); - - // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead - - int yPathSize; - { - RECT r; - GetClientRectOfItem(IDE_BROWSE_PATH, r); - yPathSize = RECT_SIZE_Y(r); - _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize); - } - - { - RECT r; - GetClientRectOfItem(IDC_BROWSE_FILTER, r); - _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r)); - } - - { - RECT r; - GetClientRectOfItem(IDL_BROWSE, r); - _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top); - } - - return false; -} - -bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == k_Message_RefreshPathEdit) - { - SetPathEditText(); - return true; - } - return CModalDialog::OnMessage(message, wParam, lParam); -} - - -bool CBrowseDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE) - { - switch (itemID) - { - case IDC_BROWSE_FILTER: - { - Reload(); - return true; - } - } - } - return CModalDialog::OnCommand(code, itemID, lParam); -} - - -bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header) -{ - if (header->hwndFrom != _list) - return false; - switch (header->code) - { - case LVN_ITEMACTIVATE: - if (g_LVN_ITEMACTIVATE_Support) - OnItemEnter(); - break; - case NM_DBLCLK: - case NM_RETURN: // probably it's unused - if (!g_LVN_ITEMACTIVATE_Support) - OnItemEnter(); - break; - case LVN_COLUMNCLICK: - { - const int index = LPNMLISTVIEW(header)->iSubItem; - if (index == _sortIndex) - _ascending = !_ascending; - else - { - _ascending = (index == 0); - _sortIndex = index; - } - Reload(); - return false; - } - case LVN_KEYDOWN: - { - bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header)); - Post_RefreshPathEdit(); - return boolResult; - } - case NM_RCLICK: - case NM_CLICK: - case LVN_BEGINDRAG: - Post_RefreshPathEdit(); - break; - } - return false; -} - -bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo) -{ - const bool ctrl = IsKeyDown(VK_CONTROL); - - switch (keyDownInfo->wVKey) - { - case VK_BACK: - OpenParentFolder(); - return true; - case 'R': - if (ctrl) - { - Reload(); - return true; - } - return false; - case VK_F7: - OnCreateDir(); - return true; - } - return false; -} - - -bool CBrowseDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_BROWSE_PARENT: OpenParentFolder(); break; - case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break; - default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND); - } - _list.SetFocus(); - return true; -} - -void CBrowseDialog::OnOK() -{ - /* When we press "Enter" in listview, Windows sends message to first Button. - We check that message was from ListView; */ - if (GetFocus() == _list) - { - OnItemEnter(); - return; - } - FinishOnOK(); -} - - -bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name) -{ - parentPrefix.Empty(); - name.Empty(); - if (path.IsEmpty()) - return false; - if (_topDirPrefix == path) - return false; - UString s = path; - if (IS_PATH_SEPAR(s.Back())) - s.DeleteBack(); - if (s.IsEmpty()) - return false; - if (IS_PATH_SEPAR(s.Back())) - return false; - const unsigned pos1 = (unsigned)(s.ReverseFind_PathSepar() + 1); - parentPrefix.SetFrom(s, pos1); - name = s.Ptr(pos1); - return true; -} - -int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2) const -{ - if (lParam1 == lParam2) return 0; - if (lParam1 == kParentIndex) return -1; - if (lParam2 == kParentIndex) return 1; - - const CFileInfo &f1 = _files[(int)lParam1]; - const CFileInfo &f2 = _files[(int)lParam2]; - - const bool isDir2 = f2.IsDir(); - if (f1.IsDir()) - { - if (!isDir2) return -1; - } - else if (isDir2) return 1; - - int res = 0; - switch (_sortIndex) - { - case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break; - case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break; - case 2: res = MyCompare(f1.Size, f2.Size); break; - } - return _ascending ? res: -res; -} - -static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) -{ - return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2); -} - -wchar_t *Browse_ConvertSizeToString(UInt64 v, wchar_t *s); -wchar_t *Browse_ConvertSizeToString(UInt64 v, wchar_t *s) -{ - char c = 0; - if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; } - else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; } - else if (v >= ((UInt64)10000 << 0)) { v >>= 10; c = 'K'; } - s = ConvertUInt64ToString(v, s); - if (c != 0) - { - *s++ = ' '; - *s++ = (wchar_t)c; - *s++ = 'B'; - *s = 0; - } - return s; -} - -// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter - -HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName) -{ - CObjectVector files; - - #ifndef UNDER_CE - bool isDrive = false; - if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix)) - { - isDrive = true; - FStringVector drives; - if (!MyGetLogicalDriveStrings(drives)) - return GetLastError_noZero_HRESULT(); - FOR_VECTOR (i, drives) - { - const FString &d = drives[i]; - if (d.Len() < 2 || d.Back() != '\\') - return E_FAIL; - CFileInfo &fi = files.AddNew(); - fi.SetAsDir(); - fi.Name = d; - fi.Name.DeleteBack(); - } - } - else - #endif - { - const UStringVector *masks = NULL; - if (!Filters.IsEmpty() && _filterCombo.GetCount() > 0) - { - const int selected = _filterCombo.GetCurSel(); - // GetItemData_of_CurSel(); // we don't use data field - if (/* selected >= 0 && */ (unsigned)selected < Filters.Size()) - { - const UStringVector &m = Filters[selected].Masks; - if (m.Size() > 1 || (m.Size() == 1 - && !m[0].IsEqualTo("*.*") - && !m[0].IsEqualTo("*"))) - masks = &m; - } - } - CEnumerator enumerator; - enumerator.SetDirPrefix(us2fs(pathPrefix)); - CFileInfo fi; - for (;;) - { - bool found; - if (!enumerator.Next(fi, found)) - return GetLastError_noZero_HRESULT(); - if (!found) - break; - if (!fi.IsDir()) - { - if (FolderMode) - continue; - if (masks) - { - unsigned i; - const unsigned numMasks = masks->Size(); - for (i = 0; i < numMasks; i++) - if (DoesWildcardMatchName((*masks)[i], fs2us(fi.Name))) - break; - if (i == numMasks) - continue; - } - } - files.Add(fi); - } - } - - DirPrefix = pathPrefix; - - _files = files; - - SetItemText(IDT_BROWSE_FOLDER, DirPrefix); - - _list.SetRedraw(false); - _list.DeleteAllItems(); - - LVITEMW item; - - unsigned index = 0; - int cursorIndex = -1; - - #ifndef Z7_SFX - if (_showDots && _topDirPrefix != DirPrefix) - { - item.iItem = (int)index; - const UString itemName (".."); - if (selectedName.IsEmpty()) - cursorIndex = (int)index; - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - unsigned subItem = 0; - item.iSubItem = (int)(subItem++); - item.lParam = kParentIndex; - item.pszText = itemName.Ptr_non_const(); - item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix); - if (item.iImage < 0) - item.iImage = 0; - _list.InsertItem(&item); - _list.SetSubItem(index, subItem++, L""); - _list.SetSubItem(index, subItem++, L""); - index++; - } - #endif - - for (unsigned i = 0; i < _files.Size(); i++, index++) - { - item.iItem = (int)index; - const CFileInfo &fi = _files[i]; - const UString name = fs2us(fi.Name); - if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0) - cursorIndex = (int)index; - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - unsigned subItem = 0; - item.iSubItem = (int)(subItem++); - item.lParam = (LPARAM)i; - item.pszText = name.Ptr_non_const(); - - const UString fullPath = DirPrefix + name; - #ifndef UNDER_CE - if (isDrive) - { - item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path( - fi.Name + FCHAR_PATH_SEPARATOR, - FILE_ATTRIBUTE_DIRECTORY); - } - else - #endif - item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); - if (item.iImage < 0) - item.iImage = 0; - _list.InsertItem(&item); - wchar_t s[64]; - { - s[0] = 0; - if (!FILETIME_IsZero(fi.MTime)) - ConvertUtcFileTimeToString(fi.MTime, s, - #ifndef UNDER_CE - kTimestampPrintLevel_MIN - #else - kTimestampPrintLevel_DAY - #endif - ); - _list.SetSubItem(index, subItem++, s); - } - { - s[0] = 0; - if (!fi.IsDir()) - Browse_ConvertSizeToString(fi.Size, s); - _list.SetSubItem(index, subItem++, s); - } - } - - if (_list.GetItemCount() > 0 && cursorIndex >= 0) - _list.SetItemState_FocusedSelected(cursorIndex); - _list.SortItems(CompareItems2, (LPARAM)this); - if (_list.GetItemCount() > 0 && cursorIndex < 0) - _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); - _list.EnsureVisible(_list.GetFocusedItem(), false); - _list.SetRedraw(true); - _list.InvalidateRect(NULL, true); - return S_OK; -} - -HRESULT CBrowseDialog::Reload() -{ - UString selected; - const int index = _list.GetNextSelectedItem(-1); - if (index >= 0) - { - const int fileIndex = GetRealItemIndex(index); - if (fileIndex != kParentIndex) - selected = fs2us(_files[fileIndex].Name); - } - const UString dirPathTemp = DirPrefix; - return Reload(dirPathTemp, selected); -} - -void CBrowseDialog::OpenParentFolder() -{ - UString parent, selected; - if (GetParentPath(DirPrefix, parent, selected)) - { - Reload(parent, selected); - SetPathEditText(); - } -} - -void CBrowseDialog::SetPathEditText() -{ - const int index = _list.GetNextSelectedItem(-1); - if (index < 0) - { - if (FolderMode) - _pathEdit.SetText(DirPrefix); - return; - } - const int fileIndex = GetRealItemIndex(index); - if (fileIndex == kParentIndex) - { - if (FolderMode) - _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR); - return; - } - const CFileInfo &file = _files[fileIndex]; - if (file.IsDir()) - { - if (!FolderMode) - return; - _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR); - } - else - _pathEdit.SetText(fs2us(file.Name)); -} - -void CBrowseDialog::OnCreateDir() -{ - UString name; - { - UString enteredName; - Dlg_CreateFolder((HWND)*this, enteredName); - if (enteredName.IsEmpty()) - return; - if (!CorrectFsPath(DirPrefix, enteredName, name)) - { - MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name); - return; - } - } - if (name.IsEmpty()) - return; - - FString destPath; - if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath)) - { - if (!NDir::CreateComplexDir(destPath)) - { - MessageBox_HResError((HWND)*this, GetLastError_noZero_HRESULT(), fs2us(destPath)); - } - else - { - UString tempPath = DirPrefix; - Reload(tempPath, name); - SetPathEditText(); - } - _list.SetFocus(); - } -} - -void CBrowseDialog::OnItemEnter() -{ - const int index = _list.GetNextSelectedItem(-1); - if (index < 0) - return; - const int fileIndex = GetRealItemIndex(index); - if (fileIndex == kParentIndex) - OpenParentFolder(); - else - { - const CFileInfo &file = _files[fileIndex]; - if (!file.IsDir()) - { - if (!FolderMode) - FinishOnOK(); - /* - MessageBox_Error_Global(*this, FolderMode ? - L"You must select some folder": - L"You must select some file"); - */ - return; - } - UString s = DirPrefix; - s += fs2us(file.Name); - s.Add_PathSepar(); - const HRESULT res = Reload(s, UString()); - if (res != S_OK) - MessageBox_HResError(*this, res, s); - SetPathEditText(); - } -} - -void CBrowseDialog::FinishOnOK() -{ - UString s; - _pathEdit.GetText(s); - FString destPath; - if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath)) - { - MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s); - return; - } - FilePath = fs2us(destPath); - if (FolderMode) - NormalizeDirPathPrefix(FilePath); - FilterIndex = _filterCombo.GetCurSel(); - End(IDOK); -} - -#endif // USE_MY_BROWSE_DIALOG - - - -bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath) -{ - resultPath.Empty(); - - #ifndef UNDER_CE - -#ifdef USE_MY_BROWSE_DIALOG - if (!IsSuperOrDevicePath(path)) - if (MyStringLen(path) < MAX_PATH) -#endif - return NShell::BrowseForFolder(owner, title, path, resultPath); - - #endif // UNDER_CE - - #ifdef USE_MY_BROWSE_DIALOG - - CBrowseDialog dialog; - dialog.FolderMode = true; - if (title) - dialog.Title = title; - if (path) - dialog.FilePath = path; - if (dialog.Create(owner) != IDOK) - return false; - resultPath = dialog.FilePath; - return true; - - #endif -} - - -// LPCWSTR filterDescription, LPCWSTR filter, - -bool CBrowseInfo::BrowseForFile(const CObjectVector &filters) -{ -#ifndef UNDER_CE -#ifdef USE_MY_BROWSE_DIALOG - /* win10: - GetOpenFileName() for FilePath doesn't support super prefix "\\\\?\\" - GetOpenFileName() for FilePath doesn't support long path - */ - if (!IsSuperOrDevicePath(FilePath)) - // if (filters.Size() > 100) // for debug -#endif - { - const UString filePath_Store = FilePath; - UString dirPrefix; - { - FString prefix, name; - if (NDir::GetFullPathAndSplit(us2fs(FilePath), prefix, name)) - { - dirPrefix = fs2us(prefix); - FilePath = fs2us(name); - } - } - UStringVector filters2; - FOR_VECTOR (i, filters) - { - const CBrowseFilterInfo &fi = filters[i]; - filters2.Add(fi.Description); - UString s; - FOR_VECTOR (k, fi.Masks) - { - if (k != 0) - s += ";"; - s += fi.Masks[k]; - } - filters2.Add(s); - } - if (CommonDlg_BrowseForFile(!dirPrefix.IsEmpty() ? dirPrefix.Ptr(): NULL, filters2)) - return true; - FilePath = filePath_Store; - - #ifdef UNDER_CE - return false; - #else - // maybe we must use GetLastError in WinCE. - const DWORD errorCode = CommDlgExtendedError(); - #ifdef USE_MY_BROWSE_DIALOG - // FNERR_INVALIDFILENAME is expected error, if long path was used - if (errorCode != FNERR_INVALIDFILENAME - || FilePath.Len() < MAX_PATH) - #endif - { - if (errorCode == 0) // cancel or close on dialog - return false; - const char *message = NULL; - if (errorCode == FNERR_INVALIDFILENAME) - message = "Invalid file name"; - UString s ("Open Dialog Error:"); - s.Add_LF(); - if (message) - s += message; - else - { - char temp[16]; - ConvertUInt32ToHex8Digits(errorCode, temp); - s += "Error #"; - s += temp; - } - s.Add_LF(); - s += FilePath; - MessageBox_Error_Global(hwndOwner, s); - } - #endif // UNDER_CE - } - -#endif // UNDER_CE - -#ifdef USE_MY_BROWSE_DIALOG - - CBrowseDialog dialog; - - dialog.FolderMode = false; - dialog.SaveMode = SaveMode; - dialog.FilterIndex = FilterIndex; - dialog.Filters = filters; - - if (lpstrTitle) - dialog.Title = lpstrTitle; - dialog.FilePath = FilePath; - if (dialog.Create(hwndOwner) != IDOK) - return false; - FilePath = dialog.FilePath; - FilterIndex = dialog.FilterIndex; -#endif - - return true; -} - - -#ifdef _WIN32 - -static void RemoveDotsAndSpaces(UString &path) -{ - while (!path.IsEmpty()) - { - wchar_t c = path.Back(); - if (c != ' ' && c != '.') - return; - path.DeleteBack(); - } -} - - -bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result) -{ - result.Empty(); - - UString path = path2; - #ifdef _WIN32 - path.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - unsigned start = 0; - UString base; - - if (IsAbsolutePath(path)) - { - #if defined(_WIN32) && !defined(UNDER_CE) - if (IsSuperOrDevicePath(path)) - { - result = path; - return true; - } - #endif - start = GetRootPrefixSize(path); - } - else - { - #if defined(_WIN32) && !defined(UNDER_CE) - if (IsSuperOrDevicePath(relBase)) - { - result = path; - return true; - } - #endif - base = relBase; - } - - /* We can't use backward, since we must change only disk paths */ - /* - for (;;) - { - if (path.Len() <= start) - break; - if (DoesFileOrDirExist(us2fs(path))) - break; - if (path.Back() == WCHAR_PATH_SEPARATOR) - { - path.DeleteBack(); - result.Insert(0, WCHAR_PATH_SEPARATOR); - } - int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1; - UString cur = path.Ptr(pos); - RemoveDotsAndSpaces(cur); - result.Insert(0, cur); - path.DeleteFrom(pos); - } - result.Insert(0, path); - return true; - */ - - result += path.Left(start); - bool checkExist = true; - UString cur; - - for (;;) - { - if (start == path.Len()) - break; - const int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start); - cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : (unsigned)slashPos) - start); - if (checkExist) - { - CFileInfo fi; - if (fi.Find(us2fs(base + result + cur))) - { - if (!fi.IsDir()) - { - result = path; - break; - } - } - else - checkExist = false; - } - if (!checkExist) - RemoveDotsAndSpaces(cur); - result += cur; - if (slashPos < 0) - break; - start = (unsigned)(slashPos + 1); - result.Add_PathSepar(); - } - - return true; -} - -#else - -bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result) -{ - result = path; - return true; -} - -#endif - -bool Dlg_CreateFolder(HWND wnd, UString &destName) -{ - destName.Empty(); - CComboDialog dlg; - LangString(IDS_CREATE_FOLDER, dlg.Title); - LangString(IDS_CREATE_FOLDER_NAME, dlg.Static); - LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value); - if (dlg.Create(wnd) != IDOK) - return false; - destName = dlg.Value; - return true; -} +// BrowseDialog.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include "../../../Common/IntToString.h" + +#ifndef UNDER_CE +#include "../../../Windows/CommonDialog.h" +#include "../../../Windows/Shell.h" +#endif + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileFind.h" + +#ifdef UNDER_CE +#include +#endif + +#include "BrowseDialog.h" + +#define USE_MY_BROWSE_DIALOG + +#ifdef USE_MY_BROWSE_DIALOG + +#include "../../../Common/Defs.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/Edit.h" +#include "../../../Windows/Control/ListView.h" + +#include "BrowseDialogRes.h" +#include "PropertyNameRes.h" +#include "SysIconUtils.h" + +#ifndef Z7_SFX +#include "RegistryUtils.h" +#endif + +#endif // USE_MY_BROWSE_DIALOG + +#include "ComboDialog.h" +#include "LangUtils.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; +using namespace NFind; + +static void MessageBox_Error_Global(HWND wnd, const wchar_t *message) +{ + ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR); +} + +#ifdef USE_MY_BROWSE_DIALOG + +#if 0 +extern HINSTANCE g_hInstance; +#endif +extern bool g_LVN_ITEMACTIVATE_Support; + +static const int kParentIndex = -1; +static const UINT k_Message_RefreshPathEdit = WM_APP + 1; + +extern UString HResultToMessage(HRESULT errorCode); + +static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name) +{ + UString s = HResultToMessage(errorCode); + if (name) + { + s.Add_LF(); + s += name; + } + MessageBox_Error_Global(wnd, s); +} + +class CBrowseDialog: public NControl::CModalDialog +{ + NControl::CListView _list; + NControl::CEdit _pathEdit; + NControl::CComboBox _filterCombo; + + CObjectVector _files; + + CExtToIconMap _extToIconMap; + int _sortIndex; + bool _ascending; + #ifndef Z7_SFX + bool _showDots; + #endif + UString _topDirPrefix; // we don't open parent of that folder + UString DirPrefix; + + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual void OnOK() Z7_override; + + bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo); + + void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); } + + bool GetParentPath(const UString &path, UString &parentPrefix, UString &name); + // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter + HRESULT Reload(const UString &pathPrefix, const UString &selectedName); + HRESULT Reload(); + + void OpenParentFolder(); + void SetPathEditText(); + void OnCreateDir(); + void OnItemEnter(); + void FinishOnOK(); + + int GetRealItemIndex(int indexInListView) const + { + LPARAM param; + if (!_list.GetItemParam((unsigned)indexInListView, param)) + return (int)-1; + return (int)param; + } + +public: + + bool SaveMode; + bool FolderMode; + int FilterIndex; // [in / out] + CObjectVector Filters; + + UString FilePath; // [in / out] + UString Title; + + CBrowseDialog(): + #ifndef Z7_SFX + _showDots(false), + #endif + SaveMode(false) + , FolderMode(false) + , FilterIndex(-1) + {} + INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_BROWSE, parent); } + int CompareItems(LPARAM lParam1, LPARAM lParam2) const; +}; + + +bool CBrowseDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetDlgItems(*this, NULL, 0); + #endif + if (!Title.IsEmpty()) + SetText(Title); + _list.Attach(GetItem(IDL_BROWSE)); + _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER)); + _pathEdit.Attach(GetItem(IDE_BROWSE_PATH)); + + #ifndef UNDER_CE + _list.SetUnicodeFormat(); + #endif + + #ifndef Z7_SFX + CFmSettings st; + st.Load(); + if (st.SingleClick) + _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT); + _showDots = st.ShowDots; + #endif + + { + /* + Filters.Clear(); // for debug + if (Filters.IsEmpty() && !FolderMode) + { + CBrowseFilterInfo &f = Filters.AddNew(); + const UString mask("*.*"); + f.Masks.Add(mask); + // f.Description = "("; + f.Description += mask; + // f.Description += ")"; + } + */ + + FOR_VECTOR (i, Filters) + { + _filterCombo.AddString(Filters[i].Description); + } + + if (Filters.Size() <= 1) + { + if (FolderMode) + HideItem(IDC_BROWSE_FILTER); + else + EnableItem(IDC_BROWSE_FILTER, false); + } + + if (/* FilterIndex >= 0 && */ (unsigned)FilterIndex < Filters.Size()) + _filterCombo.SetCurSel(FilterIndex); + } + + _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); + _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); + + _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100); + _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100); + { + LV_COLUMNW column; + column.iSubItem = 2; + column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + column.fmt = LVCFMT_RIGHT; + column.cx = 100; + const UString s = LangString(IDS_PROP_SIZE); + column.pszText = s.Ptr_non_const(); + _list.InsertColumn(2, &column); + } + + _list.InsertItem(0, L"12345678901234567" + #ifndef UNDER_CE + L"1234567890" + #endif + ); + _list.SetSubItem(0, 1, L"2009-09-09" + #ifndef UNDER_CE + L" 09:09" + #endif + ); + _list.SetSubItem(0, 2, L"9999 MB"); + for (int i = 0; i < 3; i++) + _list.SetColumnWidthAuto(i); + _list.DeleteAllItems(); + + _ascending = true; + _sortIndex = 0; + + NormalizeSize(); + + _topDirPrefix.Empty(); + { + unsigned rootSize = GetRootPrefixSize(FilePath); + #if defined(_WIN32) && !defined(UNDER_CE) + // We can go up from root folder to drives list + if (IsDrivePath(FilePath)) + rootSize = 0; + else if (IsSuperPath(FilePath)) + { + if (IsDrivePath(FilePath.Ptr(kSuperPathPrefixSize))) + rootSize = kSuperPathPrefixSize; + } + #endif + _topDirPrefix.SetFrom(FilePath, rootSize); + } + + UString name; + if (!GetParentPath(FilePath, DirPrefix, name)) + DirPrefix = _topDirPrefix; + + for (;;) + { + UString baseFolder = DirPrefix; + if (Reload(baseFolder, name) == S_OK) + break; + name.Empty(); + if (DirPrefix.IsEmpty()) + break; + UString parent, name2; + GetParentPath(DirPrefix, parent, name2); + DirPrefix = parent; + } + + if (name.IsEmpty()) + name = FilePath; + if (FolderMode) + NormalizeDirPathPrefix(name); + _pathEdit.SetText(name); + + #ifndef UNDER_CE + /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible, + even if we use mouse for pressing the button to open this dialog. */ + PostMsg(Z7_WIN_WM_UPDATEUISTATE, MAKEWPARAM(Z7_WIN_UIS_CLEAR, Z7_WIN_UISF_HIDEFOCUS)); + #endif + +#if 0 + { + const HWND hwndTool = GetItem(IDB_BROWSE_CREATE_DIR); + if (hwndTool) + { + // Create the tooltip: + const HWND hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, + WS_POPUP | TTS_ALWAYSTIP + // | TTS_BALLOON + , CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + *this, NULL, g_hInstance, NULL); + if (hwndTip) + { + // Associate the tooltip with the tool: + TOOLINFOW toolInfo; + memset(&toolInfo, 0, sizeof(toolInfo)); + toolInfo.cbSize = sizeof(toolInfo); + toolInfo.hwnd = *this; + toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + toolInfo.uId = (UINT_PTR)hwndTool; + UString s; +#ifdef Z7_LANG + LangString_OnlyFromLangFile(IDM_CREATE_FOLDER, s); + s.RemoveChar(L'&'); + if (s.IsEmpty()) +#endif + s = "Create Folder"; + toolInfo.lpszText = s.Ptr_non_const(); + SendMessage(hwndTip, TTM_ADDTOOLW, 0, (LPARAM)&toolInfo); + } + } + } +#endif + return CModalDialog::OnInit(); +} + +bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + { + RECT r; + GetClientRectOfItem(IDB_BROWSE_PARENT, r); + mx = r.left; + my = r.top; + } + InvalidateRect(NULL); + + int xLim = xSize - mx; + { + RECT r; + GetClientRectOfItem(IDT_BROWSE_FOLDER, r); + MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r)); + } + + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDOK, bx2, by); + int y = ySize - my - by; + int x = xLim - bx1; + MoveItem(IDCANCEL, x, y, bx1, by); + MoveItem(IDOK, x - mx - bx2, y, bx2, by); + + // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead + + int yPathSize; + { + RECT r; + GetClientRectOfItem(IDE_BROWSE_PATH, r); + yPathSize = RECT_SIZE_Y(r); + _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize); + } + + { + RECT r; + GetClientRectOfItem(IDC_BROWSE_FILTER, r); + _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r)); + } + + { + RECT r; + GetClientRectOfItem(IDL_BROWSE, r); + _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top); + } + + return false; +} + +bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == k_Message_RefreshPathEdit) + { + SetPathEditText(); + return true; + } + return CModalDialog::OnMessage(message, wParam, lParam); +} + + +bool CBrowseDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_BROWSE_FILTER: + { + Reload(); + return true; + } + } + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + + +bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header) +{ + if (header->hwndFrom != _list) + return false; + switch (header->code) + { + case LVN_ITEMACTIVATE: + if (g_LVN_ITEMACTIVATE_Support) + OnItemEnter(); + break; + case NM_DBLCLK: + case NM_RETURN: // probably it's unused + if (!g_LVN_ITEMACTIVATE_Support) + OnItemEnter(); + break; + case LVN_COLUMNCLICK: + { + const int index = LPNMLISTVIEW(header)->iSubItem; + if (index == _sortIndex) + _ascending = !_ascending; + else + { + _ascending = (index == 0); + _sortIndex = index; + } + Reload(); + return false; + } + case LVN_KEYDOWN: + { + bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header)); + Post_RefreshPathEdit(); + return boolResult; + } + case NM_RCLICK: + case NM_CLICK: + case LVN_BEGINDRAG: + Post_RefreshPathEdit(); + break; + } + return false; +} + +bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo) +{ + const bool ctrl = IsKeyDown(VK_CONTROL); + + switch (keyDownInfo->wVKey) + { + case VK_BACK: + OpenParentFolder(); + return true; + case 'R': + if (ctrl) + { + Reload(); + return true; + } + return false; + case VK_F7: + OnCreateDir(); + return true; + } + return false; +} + + +bool CBrowseDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_BROWSE_PARENT: OpenParentFolder(); break; + case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break; + default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND); + } + _list.SetFocus(); + return true; +} + +void CBrowseDialog::OnOK() +{ + /* When we press "Enter" in listview, Windows sends message to first Button. + We check that message was from ListView; */ + if (GetFocus() == _list) + { + OnItemEnter(); + return; + } + FinishOnOK(); +} + + +bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name) +{ + parentPrefix.Empty(); + name.Empty(); + if (path.IsEmpty()) + return false; + if (_topDirPrefix == path) + return false; + UString s = path; + if (IS_PATH_SEPAR(s.Back())) + s.DeleteBack(); + if (s.IsEmpty()) + return false; + if (IS_PATH_SEPAR(s.Back())) + return false; + const unsigned pos1 = (unsigned)(s.ReverseFind_PathSepar() + 1); + parentPrefix.SetFrom(s, pos1); + name = s.Ptr(pos1); + return true; +} + +int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2) const +{ + if (lParam1 == lParam2) return 0; + if (lParam1 == kParentIndex) return -1; + if (lParam2 == kParentIndex) return 1; + + const CFileInfo &f1 = _files[(int)lParam1]; + const CFileInfo &f2 = _files[(int)lParam2]; + + const bool isDir2 = f2.IsDir(); + if (f1.IsDir()) + { + if (!isDir2) return -1; + } + else if (isDir2) return 1; + + int res = 0; + switch (_sortIndex) + { + case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break; + case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break; + case 2: res = MyCompare(f1.Size, f2.Size); break; + } + return _ascending ? res: -res; +} + +static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) +{ + return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2); +} + +wchar_t *Browse_ConvertSizeToString(UInt64 v, wchar_t *s); +wchar_t *Browse_ConvertSizeToString(UInt64 v, wchar_t *s) +{ + char c = 0; + if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; } + else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; } + else if (v >= ((UInt64)10000 << 0)) { v >>= 10; c = 'K'; } + s = ConvertUInt64ToString(v, s); + if (c != 0) + { + *s++ = ' '; + *s++ = (wchar_t)c; + *s++ = 'B'; + *s = 0; + } + return s; +} + +// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter + +HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName) +{ + CObjectVector files; + + #ifndef UNDER_CE + bool isDrive = false; + if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix)) + { + isDrive = true; + FStringVector drives; + if (!MyGetLogicalDriveStrings(drives)) + return GetLastError_noZero_HRESULT(); + FOR_VECTOR (i, drives) + { + const FString &d = drives[i]; + if (d.Len() < 2 || d.Back() != '\\') + return E_FAIL; + CFileInfo &fi = files.AddNew(); + fi.SetAsDir(); + fi.Name = d; + fi.Name.DeleteBack(); + } + } + else + #endif + { + const UStringVector *masks = NULL; + if (!Filters.IsEmpty() && _filterCombo.GetCount() > 0) + { + const int selected = _filterCombo.GetCurSel(); + // GetItemData_of_CurSel(); // we don't use data field + if (/* selected >= 0 && */ (unsigned)selected < Filters.Size()) + { + const UStringVector &m = Filters[selected].Masks; + if (m.Size() > 1 || (m.Size() == 1 + && !m[0].IsEqualTo("*.*") + && !m[0].IsEqualTo("*"))) + masks = &m; + } + } + CEnumerator enumerator; + enumerator.SetDirPrefix(us2fs(pathPrefix)); + CFileInfo fi; + for (;;) + { + bool found; + if (!enumerator.Next(fi, found)) + return GetLastError_noZero_HRESULT(); + if (!found) + break; + if (!fi.IsDir()) + { + if (FolderMode) + continue; + if (masks) + { + unsigned i; + const unsigned numMasks = masks->Size(); + for (i = 0; i < numMasks; i++) + if (DoesWildcardMatchName((*masks)[i], fs2us(fi.Name))) + break; + if (i == numMasks) + continue; + } + } + files.Add(fi); + } + } + + DirPrefix = pathPrefix; + + _files = files; + + SetItemText(IDT_BROWSE_FOLDER, DirPrefix); + + _list.SetRedraw(false); + _list.DeleteAllItems(); + + LVITEMW item; + + unsigned index = 0; + int cursorIndex = -1; + + #ifndef Z7_SFX + if (_showDots && _topDirPrefix != DirPrefix) + { + item.iItem = (int)index; + const UString itemName (".."); + if (selectedName.IsEmpty()) + cursorIndex = (int)index; + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + unsigned subItem = 0; + item.iSubItem = (int)(subItem++); + item.lParam = kParentIndex; + item.pszText = itemName.Ptr_non_const(); + item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix); + if (item.iImage < 0) + item.iImage = 0; + _list.InsertItem(&item); + _list.SetSubItem(index, subItem++, L""); + _list.SetSubItem(index, subItem++, L""); + index++; + } + #endif + + for (unsigned i = 0; i < _files.Size(); i++, index++) + { + item.iItem = (int)index; + const CFileInfo &fi = _files[i]; + const UString name = fs2us(fi.Name); + if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0) + cursorIndex = (int)index; + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + unsigned subItem = 0; + item.iSubItem = (int)(subItem++); + item.lParam = (LPARAM)i; + item.pszText = name.Ptr_non_const(); + + const UString fullPath = DirPrefix + name; + #ifndef UNDER_CE + if (isDrive) + { + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path( + fi.Name + FCHAR_PATH_SEPARATOR, + FILE_ATTRIBUTE_DIRECTORY); + } + else + #endif + item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); + if (item.iImage < 0) + item.iImage = 0; + _list.InsertItem(&item); + wchar_t s[64]; + { + s[0] = 0; + if (!FILETIME_IsZero(fi.MTime)) + ConvertUtcFileTimeToString(fi.MTime, s, + #ifndef UNDER_CE + kTimestampPrintLevel_MIN + #else + kTimestampPrintLevel_DAY + #endif + ); + _list.SetSubItem(index, subItem++, s); + } + { + s[0] = 0; + if (!fi.IsDir()) + Browse_ConvertSizeToString(fi.Size, s); + _list.SetSubItem(index, subItem++, s); + } + } + + if (_list.GetItemCount() > 0 && cursorIndex >= 0) + _list.SetItemState_FocusedSelected(cursorIndex); + _list.SortItems(CompareItems2, (LPARAM)this); + if (_list.GetItemCount() > 0 && cursorIndex < 0) + _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); + _list.EnsureVisible(_list.GetFocusedItem(), false); + _list.SetRedraw(true); + _list.InvalidateRect(NULL, true); + return S_OK; +} + +HRESULT CBrowseDialog::Reload() +{ + UString selected; + const int index = _list.GetNextSelectedItem(-1); + if (index >= 0) + { + const int fileIndex = GetRealItemIndex(index); + if (fileIndex != kParentIndex) + selected = fs2us(_files[fileIndex].Name); + } + const UString dirPathTemp = DirPrefix; + return Reload(dirPathTemp, selected); +} + +void CBrowseDialog::OpenParentFolder() +{ + UString parent, selected; + if (GetParentPath(DirPrefix, parent, selected)) + { + Reload(parent, selected); + SetPathEditText(); + } +} + +void CBrowseDialog::SetPathEditText() +{ + const int index = _list.GetNextSelectedItem(-1); + if (index < 0) + { + if (FolderMode) + _pathEdit.SetText(DirPrefix); + return; + } + const int fileIndex = GetRealItemIndex(index); + if (fileIndex == kParentIndex) + { + if (FolderMode) + _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR); + return; + } + const CFileInfo &file = _files[fileIndex]; + if (file.IsDir()) + { + if (!FolderMode) + return; + _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR); + } + else + _pathEdit.SetText(fs2us(file.Name)); +} + +void CBrowseDialog::OnCreateDir() +{ + UString name; + { + UString enteredName; + Dlg_CreateFolder((HWND)*this, enteredName); + if (enteredName.IsEmpty()) + return; + if (!CorrectFsPath(DirPrefix, enteredName, name)) + { + MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name); + return; + } + } + if (name.IsEmpty()) + return; + + FString destPath; + if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath)) + { + if (!NDir::CreateComplexDir(destPath)) + { + MessageBox_HResError((HWND)*this, GetLastError_noZero_HRESULT(), fs2us(destPath)); + } + else + { + UString tempPath = DirPrefix; + Reload(tempPath, name); + SetPathEditText(); + } + _list.SetFocus(); + } +} + +void CBrowseDialog::OnItemEnter() +{ + const int index = _list.GetNextSelectedItem(-1); + if (index < 0) + return; + const int fileIndex = GetRealItemIndex(index); + if (fileIndex == kParentIndex) + OpenParentFolder(); + else + { + const CFileInfo &file = _files[fileIndex]; + if (!file.IsDir()) + { + if (!FolderMode) + FinishOnOK(); + /* + MessageBox_Error_Global(*this, FolderMode ? + L"You must select some folder": + L"You must select some file"); + */ + return; + } + UString s = DirPrefix; + s += fs2us(file.Name); + s.Add_PathSepar(); + const HRESULT res = Reload(s, UString()); + if (res != S_OK) + MessageBox_HResError(*this, res, s); + SetPathEditText(); + } +} + +void CBrowseDialog::FinishOnOK() +{ + UString s; + _pathEdit.GetText(s); + FString destPath; + if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath)) + { + MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s); + return; + } + FilePath = fs2us(destPath); + if (FolderMode) + NormalizeDirPathPrefix(FilePath); + FilterIndex = _filterCombo.GetCurSel(); + End(IDOK); +} + +#endif // USE_MY_BROWSE_DIALOG + + + +bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath) +{ + resultPath.Empty(); + + #ifndef UNDER_CE + +#ifdef USE_MY_BROWSE_DIALOG + if (!IsSuperOrDevicePath(path)) + if (MyStringLen(path) < MAX_PATH) +#endif + return NShell::BrowseForFolder(owner, title, path, resultPath); + + #endif // UNDER_CE + + #ifdef USE_MY_BROWSE_DIALOG + + CBrowseDialog dialog; + dialog.FolderMode = true; + if (title) + dialog.Title = title; + if (path) + dialog.FilePath = path; + if (dialog.Create(owner) != IDOK) + return false; + resultPath = dialog.FilePath; + return true; + + #endif +} + + +// LPCWSTR filterDescription, LPCWSTR filter, + +bool CBrowseInfo::BrowseForFile(const CObjectVector &filters) +{ +#ifndef UNDER_CE +#ifdef USE_MY_BROWSE_DIALOG + /* win10: + GetOpenFileName() for FilePath doesn't support super prefix "\\\\?\\" + GetOpenFileName() for FilePath doesn't support long path + */ + if (!IsSuperOrDevicePath(FilePath)) + // if (filters.Size() > 100) // for debug +#endif + { + const UString filePath_Store = FilePath; + UString dirPrefix; + { + FString prefix, name; + if (NDir::GetFullPathAndSplit(us2fs(FilePath), prefix, name)) + { + dirPrefix = fs2us(prefix); + FilePath = fs2us(name); + } + } + UStringVector filters2; + FOR_VECTOR (i, filters) + { + const CBrowseFilterInfo &fi = filters[i]; + filters2.Add(fi.Description); + UString s; + FOR_VECTOR (k, fi.Masks) + { + if (k != 0) + s += ";"; + s += fi.Masks[k]; + } + filters2.Add(s); + } + if (CommonDlg_BrowseForFile(!dirPrefix.IsEmpty() ? dirPrefix.Ptr(): NULL, filters2)) + return true; + FilePath = filePath_Store; + + #ifdef UNDER_CE + return false; + #else + // maybe we must use GetLastError in WinCE. + const DWORD errorCode = CommDlgExtendedError(); + #ifdef USE_MY_BROWSE_DIALOG + // FNERR_INVALIDFILENAME is expected error, if long path was used + if (errorCode != FNERR_INVALIDFILENAME + || FilePath.Len() < MAX_PATH) + #endif + { + if (errorCode == 0) // cancel or close on dialog + return false; + const char *message = NULL; + if (errorCode == FNERR_INVALIDFILENAME) + message = "Invalid file name"; + UString s ("Open Dialog Error:"); + s.Add_LF(); + if (message) + s += message; + else + { + char temp[16]; + ConvertUInt32ToHex8Digits(errorCode, temp); + s += "Error #"; + s += temp; + } + s.Add_LF(); + s += FilePath; + MessageBox_Error_Global(hwndOwner, s); + } + #endif // UNDER_CE + } + +#endif // UNDER_CE + +#ifdef USE_MY_BROWSE_DIALOG + + CBrowseDialog dialog; + + dialog.FolderMode = false; + dialog.SaveMode = SaveMode; + dialog.FilterIndex = FilterIndex; + dialog.Filters = filters; + + if (lpstrTitle) + dialog.Title = lpstrTitle; + dialog.FilePath = FilePath; + if (dialog.Create(hwndOwner) != IDOK) + return false; + FilePath = dialog.FilePath; + FilterIndex = dialog.FilterIndex; +#endif + + return true; +} + + +#ifdef _WIN32 + +static void RemoveDotsAndSpaces(UString &path) +{ + while (!path.IsEmpty()) + { + wchar_t c = path.Back(); + if (c != ' ' && c != '.') + return; + path.DeleteBack(); + } +} + + +bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result) +{ + result.Empty(); + + UString path = path2; + #ifdef _WIN32 + path.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + unsigned start = 0; + UString base; + + if (IsAbsolutePath(path)) + { + #if defined(_WIN32) && !defined(UNDER_CE) + if (IsSuperOrDevicePath(path)) + { + result = path; + return true; + } + #endif + start = GetRootPrefixSize(path); + } + else + { + #if defined(_WIN32) && !defined(UNDER_CE) + if (IsSuperOrDevicePath(relBase)) + { + result = path; + return true; + } + #endif + base = relBase; + } + + /* We can't use backward, since we must change only disk paths */ + /* + for (;;) + { + if (path.Len() <= start) + break; + if (DoesFileOrDirExist(us2fs(path))) + break; + if (path.Back() == WCHAR_PATH_SEPARATOR) + { + path.DeleteBack(); + result.Insert(0, WCHAR_PATH_SEPARATOR); + } + int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1; + UString cur = path.Ptr(pos); + RemoveDotsAndSpaces(cur); + result.Insert(0, cur); + path.DeleteFrom(pos); + } + result.Insert(0, path); + return true; + */ + + result += path.Left(start); + bool checkExist = true; + UString cur; + + for (;;) + { + if (start == path.Len()) + break; + const int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start); + cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : (unsigned)slashPos) - start); + if (checkExist) + { + CFileInfo fi; + if (fi.Find(us2fs(base + result + cur))) + { + if (!fi.IsDir()) + { + result = path; + break; + } + } + else + checkExist = false; + } + if (!checkExist) + RemoveDotsAndSpaces(cur); + result += cur; + if (slashPos < 0) + break; + start = (unsigned)(slashPos + 1); + result.Add_PathSepar(); + } + + return true; +} + +#else + +bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result) +{ + result = path; + return true; +} + +#endif + +bool Dlg_CreateFolder(HWND wnd, UString &destName) +{ + destName.Empty(); + CComboDialog dlg; + LangString(IDS_CREATE_FOLDER, dlg.Title); + LangString(IDS_CREATE_FOLDER_NAME, dlg.Static); + LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value); + if (dlg.Create(wnd) != IDOK) + return false; + destName = dlg.Value; + return true; +} diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.h b/CPP/7zip/UI/FileManager/BrowseDialog.h index 2ba60f3bd..2ad8d5443 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.h +++ b/CPP/7zip/UI/FileManager/BrowseDialog.h @@ -1,32 +1,32 @@ -// BrowseDialog.h - -#ifndef ZIP7_INC_BROWSE_DIALOG_H -#define ZIP7_INC_BROWSE_DIALOG_H - -#include "../../../Windows/CommonDialog.h" - -bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath); - -struct CBrowseFilterInfo -{ - UStringVector Masks; - UString Description; -}; - -struct CBrowseInfo: public NWindows::CCommonDialogInfo -{ - bool BrowseForFile(const CObjectVector &filters); -}; - - -/* CorrectFsPath removes undesirable characters in names (dots and spaces at the end of file) - But it doesn't change "bad" name in any of the following cases: - - path is Super Path (with \\?\ prefix) - - path is relative and relBase is Super Path - - there is file or dir in filesystem with specified "bad" name */ - -bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); - -bool Dlg_CreateFolder(HWND wnd, UString &destName); - -#endif +// BrowseDialog.h + +#ifndef ZIP7_INC_BROWSE_DIALOG_H +#define ZIP7_INC_BROWSE_DIALOG_H + +#include "../../../Windows/CommonDialog.h" + +bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath); + +struct CBrowseFilterInfo +{ + UStringVector Masks; + UString Description; +}; + +struct CBrowseInfo: public NWindows::CCommonDialogInfo +{ + bool BrowseForFile(const CObjectVector &filters); +}; + + +/* CorrectFsPath removes undesirable characters in names (dots and spaces at the end of file) + But it doesn't change "bad" name in any of the following cases: + - path is Super Path (with \\?\ prefix) + - path is relative and relBase is Super Path + - there is file or dir in filesystem with specified "bad" name */ + +bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); + +bool Dlg_CreateFolder(HWND wnd, UString &destName); + +#endif diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.rc b/CPP/7zip/UI/FileManager/BrowseDialog.rc index 66f46f32d..04a6ad617 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog.rc +++ b/CPP/7zip/UI/FileManager/BrowseDialog.rc @@ -1,25 +1,25 @@ -#include "BrowseDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 256 -#define yc 320 - -#define k_BROWSE_y_CtrlSize 14 - -#define k_BROWSE_y_List 24 - -IDD_BROWSE DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "7-Zip: Browse" -{ - EDITTEXT IDE_BROWSE_PATH, m, by - m - k_BROWSE_y_CtrlSize - k_BROWSE_y_CtrlSize - m, xc, k_BROWSE_y_CtrlSize, ES_AUTOHSCROLL - COMBOBOX IDC_BROWSE_FILTER, m, by - m - k_BROWSE_y_CtrlSize, xc, 30, MY_COMBO - - PUSHBUTTON "OK", IDOK, bx2, by, bxs, bys - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys - PUSHBUTTON "<--", IDB_BROWSE_PARENT, m, m, 24, bys - PUSHBUTTON "+", IDB_BROWSE_CREATE_DIR, m + 32, m, 24, bys - LTEXT "", IDT_BROWSE_FOLDER, m + 64, m + 3, xc - 20, 8 - CONTROL "List1", IDL_BROWSE, "SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP, - m, m + k_BROWSE_y_List, xc, yc - bys - m - k_BROWSE_y_List - k_BROWSE_y_CtrlSize - m - k_BROWSE_y_CtrlSize - m -} +#include "BrowseDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 256 +#define yc 320 + +#define k_BROWSE_y_CtrlSize 14 + +#define k_BROWSE_y_List 24 + +IDD_BROWSE DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "7-Zip: Browse" +{ + EDITTEXT IDE_BROWSE_PATH, m, by - m - k_BROWSE_y_CtrlSize - k_BROWSE_y_CtrlSize - m, xc, k_BROWSE_y_CtrlSize, ES_AUTOHSCROLL + COMBOBOX IDC_BROWSE_FILTER, m, by - m - k_BROWSE_y_CtrlSize, xc, 30, MY_COMBO + + PUSHBUTTON "OK", IDOK, bx2, by, bxs, bys + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys + PUSHBUTTON "<--", IDB_BROWSE_PARENT, m, m, 24, bys + PUSHBUTTON "+", IDB_BROWSE_CREATE_DIR, m + 32, m, 24, bys + LTEXT "", IDT_BROWSE_FOLDER, m + 64, m + 3, xc - 20, 8 + CONTROL "List1", IDL_BROWSE, "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP, + m, m + k_BROWSE_y_List, xc, yc - bys - m - k_BROWSE_y_List - k_BROWSE_y_CtrlSize - m - k_BROWSE_y_CtrlSize - m +} diff --git a/CPP/7zip/UI/FileManager/BrowseDialog2.cpp b/CPP/7zip/UI/FileManager/BrowseDialog2.cpp index 0de6ae3d0..ee98ab438 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog2.cpp +++ b/CPP/7zip/UI/FileManager/BrowseDialog2.cpp @@ -1,1834 +1,1834 @@ -// BrowseDialog2.cpp - -#include "StdAfx.h" - -#ifdef UNDER_CE -#include -#endif - -#include - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/ProcessUtils.h" -#include "../../../Windows/PropVariantConv.h" -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/Edit.h" -#include "../../../Windows/Control/ListView.h" - -#include "../Explorer/MyMessages.h" - -#ifndef Z7_NO_REGISTRY -#include "HelpUtils.h" -#endif - -#include "../Common/PropIDUtils.h" - -#include "PropertyNameRes.h" -#include "RegistryUtils.h" -#include "SysIconUtils.h" -#include "FormatUtils.h" -#include "LangUtils.h" - -#include "resource.h" -#include "BrowseDialog2Res.h" -#include "BrowseDialog2.h" - -using namespace NWindows; -using namespace NFile; -using namespace NName; -using namespace NFind; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -extern bool g_LVN_ITEMACTIVATE_Support; - -static const int kParentIndex = -1; -// static const UINT k_Message_RefreshPathEdit = WM_APP + 1; - - -static const wchar_t *k_Message_Link_operation_was_Blocked = - L"link openning was blocked by 7-Zip"; - -extern UString HResultToMessage(HRESULT errorCode); - -static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name) -{ - UString s = HResultToMessage(errorCode); - if (name) - { - s.Add_LF(); - s += name; - } - ShowErrorMessage(wnd, s); -} - -static void MessageBox_LastError_path(HWND wnd, const FString &path) -{ - const HRESULT hres = GetLastError_noZero_HRESULT(); - MessageBox_HResError(wnd, hres, fs2us(path)); -} - - -static const UInt32 k_EnumerateDirsLimit = 200; -static const UInt32 k_EnumerateFilesLimit = 2000; - -struct CBrowseItem -{ - unsigned MainFileIndex; - int SubFileIndex; - bool WasInterrupted; - UInt32 NumFiles; - UInt32 NumDirs; - UInt32 NumRootItems; - UInt64 Size; - - CBrowseItem(): - // MainFileIndex(0), - SubFileIndex(-1), - WasInterrupted(false), - NumFiles(0), - NumDirs(0), - NumRootItems(0), - Size(0) - {} -}; - - -struct CBrowseEnumerator -{ - FString Path; // folder path without slash at the end - CFileInfo fi; // temp - CFileInfo fi_SubFile; - CBrowseItem bi; - - void Enumerate(unsigned level); - bool NeedInterrupt() const - { - return bi.NumFiles >= k_EnumerateFilesLimit - || bi.NumDirs >= k_EnumerateDirsLimit; - } -}; - -void CBrowseEnumerator::Enumerate(unsigned level) -{ - Path.Add_PathSepar(); - const unsigned len = Path.Len(); - CObjectVector names; - { - CEnumerator enumerator; - enumerator.SetDirPrefix(Path); - while (enumerator.Next(fi)) - { - if (level == 0) - { - if (bi.NumRootItems == 0) - fi_SubFile = fi; - bi.NumRootItems++; - } - - if (fi.IsDir()) - { - bi.NumDirs++; - if (!fi.HasReparsePoint()) - names.Add(fi.Name); - } - else - { - bi.NumFiles++; - bi.Size += fi.Size; - } - - if (level != 0 || bi.NumRootItems > 1) - if (NeedInterrupt()) - { - bi.WasInterrupted = true; - return; - } - } - } - - FOR_VECTOR (i, names) - { - if (NeedInterrupt()) - { - bi.WasInterrupted = true; - return; - } - Path.DeleteFrom(len); - Path += names[i]; - Enumerate(level + 1); - } -} - - - - -class CBrowseDialog2: public NControl::CModalDialog -{ - CRecordVector _items; - CObjectVector _files; - - NControl::CListView _list; - // NControl::CEdit _pathEdit; - NControl::CComboBox _filterCombo; - - CExtToIconMap _extToIconMap; - int _sortIndex; - int _columnIndex_fileNameInDir; - int _columnIndex_NumFiles; - int _columnIndex_NumDirs; - bool _ascending; - #ifndef Z7_SFX - bool _showDots; - #endif - UString _topDirPrefix; // we don't open parent of that folder - UString DirPrefix; - - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; - // virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual void OnOK() Z7_override; - - bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo); - - // void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); } - bool GetParentPath(const UString &path, UString &parentPrefix, UString &name); - // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter - HRESULT Reload(const UString &pathPrefix, const UStringVector &selectedNames, const UString &focusedName); - HRESULT Reload(const UString &pathPrefix, const UString &selectedNames); - HRESULT Reload(); - - void ChangeSorting_and_Reload(int columnIndex); - - const CFileInfo & Get_MainFileInfo_for_realIndex(unsigned realIndex) const - { - return _files[_items[realIndex].MainFileIndex]; - } - - const FString & Get_MainFileName_for_realIndex(unsigned realIndex) const - { - return Get_MainFileInfo_for_realIndex(realIndex).Name; - } - - void Reload_WithErrorMessage(); - void OpenParentFolder(); - // void SetPathEditText(); - void PrintFileProps(UString &s, const CFileInfo &file); - void Show_FileProps_Window(const CFileInfo &file); - void OnItemEnter(); - // void FinishOnOK(); - void OnDelete(/* bool toRecycleBin */); - virtual void OnHelp() Z7_override; - bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos); - - int GetRealItemIndex(int indexInListView) const - { - LPARAM param; - if (!_list.GetItemParam((unsigned)indexInListView, param)) - return (int)-1; - return (int)param; - } - - void GetSelected_RealIndexes(CUIntVector &vector); - -public: - // bool TempMode; - // bool Show_Non7zDirs_InTemp; - // int FilterIndex; // [in / out] - // CObjectVector Filters; - - UString TempFolderPath; // with slash - UString Title; - - bool IsExactTempFolder(const UString &pathPrefix) const - { - return CompareFileNames(pathPrefix, TempFolderPath) == 0; - } - - CBrowseDialog2(): - #ifndef Z7_SFX - _showDots(false) - #endif - // , TempMode(false) - // Show_Non7zDirs_InTemp(false), - // FilterIndex(-1) - {} - INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_BROWSE2, parent); } - int CompareItems(LPARAM lParam1, LPARAM lParam2) const; -}; - - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDS_BUTTON_DELETE, - IDM_VIEW_REFRESH -}; -#endif - -bool CBrowseDialog2::OnInit() -{ - #ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - if (!Title.IsEmpty()) - SetText(Title); - - _list.Attach(GetItem(IDL_BROWSE2)); - _filterCombo.Attach(GetItem(IDC_BROWSE2_FILTER)); - - _ascending = true; - _sortIndex = 0; - _columnIndex_fileNameInDir = -1; - _columnIndex_NumFiles = -1; - _columnIndex_NumDirs = -1; - // _pathEdit.Attach(GetItem(IDE_BROWSE_PATH)); - - #ifndef UNDER_CE - _list.SetUnicodeFormat(); - #endif - - #ifndef Z7_SFX - { - CFmSettings st; - st.Load(); - - DWORD extendedStyle = 0; - if (st.FullRow) - extendedStyle |= LVS_EX_FULLROWSELECT; - if (st.ShowGrid) - extendedStyle |= LVS_EX_GRIDLINES; - if (st.SingleClick) - { - extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT; - /* - if (ReadUnderline()) - extendedStyle |= LVS_EX_UNDERLINEHOT; - */ - } - if (extendedStyle) - _list.SetExtendedListViewStyle(extendedStyle); - _showDots = st.ShowDots; - } - #endif - - { - /* - Filters.Clear(); // for debug - if (Filters.IsEmpty() && !FolderMode) - { - CBrowseFilterInfo &f = Filters.AddNew(); - const UString mask("*.*"); - f.Masks.Add(mask); - // f.Description = "("; - f.Description += mask; - // f.Description += ")"; - } - */ - _filterCombo.AddString(L"7-Zip temp files (7z*)"); - _filterCombo.SetCurSel(0); - EnableItem(IDC_BROWSE2_FILTER, false); -#if 0 - FOR_VECTOR (i, Filters) - { - _filterCombo.AddString(Filters[i].Description); - } - if (Filters.Size() <= 1) - { - EnableItem(IDC_BROWSE_FILTER, false); - } - if (/* FilterIndex >= 0 && */ (unsigned)FilterIndex < Filters.Size()) - _filterCombo.SetCurSel(FilterIndex); -#endif - } - - _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); - _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); - - unsigned columnIndex = 0; - _list.InsertColumn(columnIndex++, LangString(IDS_PROP_NAME), 100); - _list.InsertColumn(columnIndex++, LangString(IDS_PROP_MTIME), 100); - { - LV_COLUMNW column; - column.iSubItem = (int)columnIndex; - column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; - column.fmt = LVCFMT_RIGHT; - column.cx = 100; - UString s = LangString(IDS_PROP_SIZE); - column.pszText = s.Ptr_non_const(); - _list.InsertColumn(columnIndex++, &column); - - // if (TempMode) - { - _columnIndex_NumFiles = (int)columnIndex; - s = LangString(IDS_PROP_FILES); - column.pszText = s.Ptr_non_const(); - _list.InsertColumn(columnIndex++, &column); - - _columnIndex_NumDirs = (int)columnIndex; - s = LangString(IDS_PROP_FOLDERS); - column.pszText = s.Ptr_non_const(); - _list.InsertColumn(columnIndex++, &column); - - _columnIndex_fileNameInDir = (int)columnIndex; - s = LangString(IDS_PROP_NAME); - s += "-2"; - _list.InsertColumn(columnIndex++, s, 100); - } - } - - _list.InsertItem(0, L"12345678901234567" - #ifndef UNDER_CE - L"1234567890" - #endif - ); - _list.SetSubItem(0, 1, L"2009-09-09" - #ifndef UNDER_CE - L" 09:09:09" - #endif - ); - _list.SetSubItem(0, 2, L"99999 MB+"); - - if (_columnIndex_NumFiles >= 0) - _list.SetSubItem(0, (unsigned)_columnIndex_NumFiles, L"123456789+"); - if (_columnIndex_NumDirs >= 0) - _list.SetSubItem(0, (unsigned)_columnIndex_NumDirs, L"123456789+"); - if (_columnIndex_fileNameInDir >= 0) - _list.SetSubItem(0, (unsigned)_columnIndex_fileNameInDir, L"12345678901234567890"); - - for (unsigned i = 0; i < columnIndex; i++) - _list.SetColumnWidthAuto((int)i); - _list.DeleteAllItems(); - - // if (TempMode) - { - _sortIndex = 1; // for MTime column - // _ascending = false; - } - - - NormalizeSize(); - - _topDirPrefix.Empty(); - { - unsigned rootSize = GetRootPrefixSize(TempFolderPath); - #if defined(_WIN32) && !defined(UNDER_CE) - // We can go up from root folder to drives list - if (IsDrivePath(TempFolderPath)) - rootSize = 0; - else if (IsSuperPath(TempFolderPath)) - { - if (IsDrivePath(TempFolderPath.Ptr(kSuperPathPrefixSize))) - rootSize = kSuperPathPrefixSize; - } - #endif - _topDirPrefix.SetFrom(TempFolderPath, rootSize); - } - - if (Reload(TempFolderPath, UString()) != S_OK) - { - // return false; - } -/* - UString name; - DirPrefix = TempFolderPath; - for (;;) - { - UString baseFolder = DirPrefix; - if (Reload(baseFolder, name) == S_OK) - break; - name.Empty(); - if (DirPrefix.IsEmpty()) - break; - UString parent, name2; - GetParentPath(DirPrefix, parent, name2); - DirPrefix = parent; - } -*/ - - #ifndef UNDER_CE - /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible, - even if we use mouse for pressing the button to open this dialog. */ - PostMsg(Z7_WIN_WM_UPDATEUISTATE, MAKEWPARAM(Z7_WIN_UIS_CLEAR, Z7_WIN_UISF_HIDEFOCUS)); - #endif - - /* - */ - - return CModalDialog::OnInit(); -} - - -bool CBrowseDialog2::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - { - RECT r; - GetClientRectOfItem(IDS_BUTTON_DELETE, r); - mx = r.left; - my = r.top; - } - InvalidateRect(NULL); - - const int xLim = xSize - mx; - { - RECT r; - GetClientRectOfItem(IDT_BROWSE2_FOLDER, r); - MoveItem(IDT_BROWSE2_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r)); - } - - int bx1, bx2, by; - GetItemSizes(IDCLOSE, bx1, by); - GetItemSizes(IDHELP, bx2, by); - const int y = ySize - my - by; - const int x = xLim - bx1; - MoveItem(IDCLOSE, x - mx - bx2, y, bx1, by); - MoveItem(IDHELP, x, y, bx2, by); - /* - int yPathSize; - { - RECT r; - GetClientRectOfItem(IDE_BROWSE_PATH, r); - yPathSize = RECT_SIZE_Y(r); - _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize); - } - */ - // Y_Size of ComboBox is tricky. Can we use it? - int yFilterSize; - { - RECT r; - GetClientRectOfItem(IDC_BROWSE2_FILTER, r); - yFilterSize = RECT_SIZE_Y(r); - _filterCombo.Move(r.left, y - my - yFilterSize, xLim - r.left, yFilterSize); - } - { - RECT r; - GetClientRectOfItem(IDL_BROWSE2, r); - _list.Move(r.left, r.top, xLim - r.left, y - my - yFilterSize - my - r.top); - } - return false; -} - - -bool CBrowseDialog2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - /* - if (message == k_Message_RefreshPathEdit) - { - // SetPathEditText(); - return true; - } - */ - if (message == WM_CONTEXTMENU) - { - if (OnContextMenu((HANDLE)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) - return true; - } - return CModalDialog::OnMessage(message, wParam, lParam); -} - - -/* -bool CBrowseDialog2::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE) - { - switch (itemID) - { - case IDC_BROWSE2_FILTER: - { - Reload(); - return true; - } - } - } - return CModalDialog::OnCommand(code, itemID, lParam); -} -*/ - -bool CBrowseDialog2::OnNotify(UINT /* controlID */, LPNMHDR header) -{ - if (header->hwndFrom != _list) - { - if (::GetParent(header->hwndFrom) == _list) - { - // NMHDR:code is UINT - // NM_RCLICK is unsigned in windows sdk - // NM_RCLICK is int in MinGW - if (header->code == (UINT)NM_RCLICK) - { -#ifdef UNDER_CE -#define MY_NMLISTVIEW_NMITEMACTIVATE NMLISTVIEW -#else -#define MY_NMLISTVIEW_NMITEMACTIVATE NMITEMACTIVATE -#endif - MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate = (MY_NMLISTVIEW_NMITEMACTIVATE *)header; - if (itemActivate->hdr.hwndFrom == HWND(_list)) - return false; - /* - POINT point; - ::GetCursorPos(&point); - ShowColumnsContextMenu(point.x, point.y); - */ - // we want to disable menu for columns. - // to return the value from a dialog procedure we must - // call SetMsgResult(val) and return true; - // NM_RCLICK : Return nonzero to not allow the default processing - SetMsgResult(TRUE); // do not allow default processing - return true; - } - } - return false; - } - - switch (header->code) - { - case LVN_ITEMACTIVATE: - if (g_LVN_ITEMACTIVATE_Support) - OnItemEnter(); - break; - case NM_DBLCLK: - case NM_RETURN: // probably it's unused - if (!g_LVN_ITEMACTIVATE_Support) - OnItemEnter(); - break; - case LVN_COLUMNCLICK: - { - const int index = LPNMLISTVIEW(header)->iSubItem; - ChangeSorting_and_Reload(index); - return false; - } - case LVN_KEYDOWN: - { - bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header)); - // Post_RefreshPathEdit(); - return boolResult; - } - /* - case NM_RCLICK: - case NM_CLICK: - case LVN_BEGINDRAG: - Post_RefreshPathEdit(); - break; - */ - } - - return false; -} - -bool CBrowseDialog2::OnKeyDown(LPNMLVKEYDOWN keyDownInfo) -{ - const bool ctrl = IsKeyDown(VK_CONTROL); - // const bool alt = IsKeyDown(VK_MENU); - // const bool leftCtrl = IsKeyDown(VK_LCONTROL); - // const bool rightCtrl = IsKeyDown(VK_RCONTROL); - // const bool shift = IsKeyDown(VK_SHIFT); - - switch (keyDownInfo->wVKey) - { - case VK_BACK: - OpenParentFolder(); - return true; - case 'R': - if (ctrl) - { - Reload_WithErrorMessage(); - return true; - } - return false; - case VK_F3: - case VK_F5: - case VK_F6: - if (ctrl) - { - int index = 0; // name - if (keyDownInfo->wVKey == VK_F5) index = 1; // MTime - else if (keyDownInfo->wVKey == VK_F6) index = 2; // Size - ChangeSorting_and_Reload(index); - Reload_WithErrorMessage(); - return true; - } - return false; - case 'A': - if (ctrl) - { - // if (TempMode) - _list.SelectAll(); - return true; - } - return false; - - case VK_DELETE: - // if (TempMode) - OnDelete(/* !shift */); - return true; -#if 0 - case VK_NEXT: - case VK_PRIOR: - { - if (ctrl && !alt && !shift) - { - if (keyDownInfo->wVKey == VK_NEXT) - OnItemEnter(); - else - OpenParentFolder(); - SetMsgResult(TRUE); // to disable processing - return true; - } - break; - } -#endif - } - return false; -} - - -bool CBrowseDialog2::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_BROWSE2_PARENT: OpenParentFolder(); break; - case IDS_BUTTON_DELETE: - { - OnDelete(/* !IsKeyDown(VK_SHIFT) */); - break; - } - case IDM_VIEW_REFRESH: - { - Reload_WithErrorMessage(); - break; - } - default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND); - } - _list.SetFocus(); - return true; -} - - - -static void PrintPropsPrefix(UString &s, UInt32 id) -{ - s.Add_LF(); - s += " "; - AddLangString(s, id); - s += ": "; -} - -wchar_t *Browse_ConvertSizeToString(UInt64 v, wchar_t *s); - -static void Browse_ConvertSizeToString(const CBrowseItem &bi, wchar_t *s) -{ - s = Browse_ConvertSizeToString(bi.Size, s); - if (bi.WasInterrupted) - { - *s++ = '+'; - *s = 0; - } -} - -void AddSizeValue(UString &s, UInt64 value); - -static void PrintProps_Size(UString &s, UInt64 size) -{ - PrintPropsPrefix(s, IDS_PROP_SIZE); -#if 1 - AddSizeValue(s, size); -#else - s.Add_UInt64(size); - if (size >= 10000) - { - s += " ("; - wchar_t temp[64]; - Browse_ConvertSizeToString(size, temp); - s += temp; - s.Add_Char(')'); - } -#endif -} - -static void PrintProps_MTime(UString &s, const CFileInfo &fi) -{ - PrintPropsPrefix(s, IDS_PROP_MTIME); - char t[64]; - ConvertUtcFileTimeToString(fi.MTime, t); - s += t; -} - - -static void PrintProps_Name(UString &s, const CFileInfo &fi) -{ - s += fs2us(fi.Name); - if (fi.IsDir()) - s.Add_PathSepar(); -} - -static void PrintProps_Attrib(UString &s, const CFileInfo &fi) -{ - PrintPropsPrefix(s, IDS_PROP_ATTRIBUTES); - char props[64]; - ConvertWinAttribToString(props, fi.Attrib); - s += props; -#if 0 - if (fi.HasReparsePoint()) - { - s.Add_LF(); - s += "IsLink: +"; - } -#endif -} - -static void PrintProps(UString &s, const CBrowseItem &bi, - const CFileInfo &fi, const CFileInfo *fi2) -{ - PrintProps_Name(s, fi); - PrintProps_Attrib(s, fi); - if (bi.NumDirs != 0) - { - PrintPropsPrefix(s, IDS_PROP_FOLDERS); - s.Add_UInt32(bi.NumDirs); - if (bi.WasInterrupted) - s += "+"; - } - if (bi.NumFiles != 0) - { - PrintPropsPrefix(s, IDS_PROP_FILES); - s.Add_UInt32(bi.NumFiles); - if (bi.WasInterrupted) - s += "+"; - } - { - PrintProps_Size(s, bi.Size); - if (bi.WasInterrupted) - s += "+"; - } - - PrintProps_MTime(s, fi); - - if (fi2) - { - s.Add_LF(); - s += "----------------"; - s.Add_LF(); - PrintProps_Name(s, *fi2); - PrintProps_Attrib(s, *fi2); - if (!fi2->IsDir()) - PrintProps_Size(s, fi2->Size); - PrintProps_MTime(s, *fi2); - } -} - - -void CBrowseDialog2::GetSelected_RealIndexes(CUIntVector &vector) -{ - vector.Clear(); - int index = -1; - for (;;) - { - index = _list.GetNextSelectedItem(index); - if (index < 0) - break; - const int realIndex = GetRealItemIndex(index); - if (realIndex >= 0) - vector.Add((unsigned)realIndex); - } -} - - -void CBrowseDialog2::PrintFileProps(UString &s, const CFileInfo &file) -{ - CFileInfo file2; - FString path = us2fs(DirPrefix); - path += file.Name; - if (!file2.Find(path)) - { - MessageBox_LastError_path(*this, path); - Reload_WithErrorMessage(); - return; - } - CBrowseEnumerator enumer; - enumer.bi.Size = file2.Size; - if (file2.IsDir() && !file2.HasReparsePoint()) - { - enumer.Path = path; - enumer.Enumerate(0); // level - } - PrintProps(s, enumer.bi, file2, - enumer.bi.NumRootItems == 1 ? &enumer.fi_SubFile : NULL); -} - - -void CBrowseDialog2::Show_FileProps_Window(const CFileInfo &file) -{ - UString s; - PrintFileProps(s, file); - MessageBoxW(*this, s, LangString(IDS_PROPERTIES), MB_OK); -} - - -void CBrowseDialog2::OnDelete(/* bool toRecycleBin */) -{ -#if 1 - // we don't want deleting in non temp folders - if (!DirPrefix.IsPrefixedBy(TempFolderPath)) - return; -#endif - - CUIntVector indices; - GetSelected_RealIndexes(indices); - if (indices.Size() == 0) - return; - { - UInt32 titleID, messageID; - UString messageParam; - UString s2; - if (indices.Size() == 1) - { - const unsigned index = indices[0]; - const CBrowseItem &bi = _items[index]; - const CFileInfo &file = _files[bi.MainFileIndex]; - PrintFileProps(s2, file); - messageParam = fs2us(file.Name); - if (file.IsDir()) - { - titleID = IDS_CONFIRM_FOLDER_DELETE; - messageID = IDS_WANT_TO_DELETE_FOLDER; - } - else - { - titleID = IDS_CONFIRM_FILE_DELETE; - messageID = IDS_WANT_TO_DELETE_FILE; - } - } - else - { - titleID = IDS_CONFIRM_ITEMS_DELETE; - messageID = IDS_WANT_TO_DELETE_ITEMS; - messageParam = NumberToString(indices.Size()); - - for (UInt32 i = 0; i < indices.Size(); i++) - { - if (i >= 10) - { - s2 += "..."; - break; - } - const CBrowseItem &bi = _items[indices[i]]; - const CFileInfo &fi = _files[bi.MainFileIndex]; - PrintProps_Name(s2, fi); - s2.Add_LF(); - } - } - UString s = MyFormatNew(messageID, messageParam); - if (!s2.IsEmpty()) - { - s.Add_LF(); - s.Add_LF(); - s += s2; - } - if (::MessageBoxW((HWND)*this, s, LangString(titleID), - MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) - return; - } - - for (UInt32 i = 0; i < indices.Size(); i++) - { - const unsigned index = indices[i]; - bool result = true; - const CBrowseItem &bi = _items[index]; - const CFileInfo &fi = _files[bi.MainFileIndex]; - if (fi.Name.IsEmpty()) - return; // some error - const FString fullPath = us2fs(DirPrefix) + fi.Name; - if (fi.IsDir()) - result = NFile::NDir::RemoveDirWithSubItems(fullPath); - else - result = NFile::NDir::DeleteFileAlways(fullPath); - if (!result) - { - MessageBox_LastError_path(*this, fullPath); - return; - } - } - - Reload_WithErrorMessage(); -} - - -#ifndef Z7_NO_REGISTRY -#define kHelpTopic "fm/temp.htm" -void CBrowseDialog2::OnHelp() -{ - ShowHelpWindow(kHelpTopic); - CModalDialog::OnHelp(); -} -#endif - - -HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process); -HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process) -{ - UString path2 = path; - - #ifdef _WIN32 - { - const int dot = path2.ReverseFind_Dot(); - const int separ = path2.ReverseFind_PathSepar(); - if (dot < 0 || dot < separ) - path2.Add_Dot(); - } - #endif - - UINT32 result; - -#ifndef _UNICODE - if (g_IsNT) - { - SHELLEXECUTEINFOW execInfo; - execInfo.cbSize = sizeof(execInfo); - execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; - execInfo.hwnd = NULL; - execInfo.lpVerb = NULL; - execInfo.lpFile = path2; - execInfo.lpParameters = NULL; - execInfo.lpDirectory = dir.IsEmpty() ? NULL : (LPCWSTR)dir; - execInfo.nShow = SW_SHOWNORMAL; - execInfo.hProcess = NULL; -typedef BOOL (WINAPI * Func_ShellExecuteExW)(LPSHELLEXECUTEINFOW lpExecInfo); -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - const - Func_ShellExecuteExW - f_ShellExecuteExW = Z7_GET_PROC_ADDRESS( - Func_ShellExecuteExW, ::GetModuleHandleW(L"shell32.dll"), - "ShellExecuteExW"); - if (!f_ShellExecuteExW) - return 0; - f_ShellExecuteExW(&execInfo); - result = (UINT32)(UINT_PTR)execInfo.hInstApp; - process.Attach(execInfo.hProcess); - } - else -#endif - { - SHELLEXECUTEINFO execInfo; - execInfo.cbSize = sizeof(execInfo); - execInfo.fMask = SEE_MASK_NOCLOSEPROCESS - #ifndef UNDER_CE - | SEE_MASK_FLAG_DDEWAIT - #endif - ; - execInfo.hwnd = NULL; - execInfo.lpVerb = NULL; - const CSysString sysPath (GetSystemString(path2)); - const CSysString sysDir (GetSystemString(dir)); - execInfo.lpFile = sysPath; - execInfo.lpParameters = NULL; - execInfo.lpDirectory = - #ifdef UNDER_CE - NULL - #else - sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir - #endif - ; - execInfo.nShow = SW_SHOWNORMAL; - execInfo.hProcess = NULL; - ::ShellExecuteEx(&execInfo); - result = (UINT32)(UINT_PTR)execInfo.hInstApp; - process.Attach(execInfo.hProcess); - } - - // DEBUG_PRINT_NUM("-- ShellExecuteEx -- execInfo.hInstApp = ", result) - - if (result <= 32) - { - switch (result) - { - case SE_ERR_NOASSOC: - MessageBox_HResError(window, - GetLastError_noZero_HRESULT(), - NULL - // L"There is no application associated with the given file name extension", - ); - } - - return E_FAIL; // fixed in 15.13. Can we use it for any Windows version? - } - - return S_OK; -} - -void StartApplicationDontWait(const UString &dir, const UString &path, HWND window); -void StartApplicationDontWait(const UString &dir, const UString &path, HWND window) -{ - CProcess process; - StartApplication(dir, path, window, process); -} - - -static UString GetQuotedString2(const UString &s) -{ - UString s2 ('\"'); - s2 += s; - s2.Add_Char('\"'); - return s2; -} - - -bool CBrowseDialog2::OnContextMenu(HANDLE windowHandle, int xPos, int yPos) -{ - if (windowHandle != _list) - return false; - - CUIntVector indices; - GetSelected_RealIndexes(indices); - - // negative x,y are possible for multi-screen modes. - // x=-1 && y=-1 for keyboard call (SHIFT+F10 and others). -#if 1 // 0 : for debug - if (xPos == -1 && yPos == -1) -#endif - { -/* - if (indices.Size() == 0) - { - xPos = 0; - yPos = 0; - } - else -*/ - { - const int itemIndex = _list.GetFocusedItem(); - if (itemIndex == -1) - return false; - RECT rect; - if (!_list.GetItemRect(itemIndex, &rect, LVIR_ICON)) - return false; - // rect : rect of file icon relative to listVeiw. - xPos = (rect.left + rect.right) / 2; - yPos = (rect.top + rect.bottom) / 2; - RECT r; - GetClientRectOfItem(IDL_BROWSE2, r); - if (yPos < 0 || yPos >= RECT_SIZE_Y(r)) - yPos = 0; - } - POINT point = {xPos, yPos}; - _list.ClientToScreen(&point); - xPos = point.x; - yPos = point.y; - } - - const UInt32 k_CmdId_Delete = 1; - const UInt32 k_CmdId_Open_Explorer = 2; - const UInt32 k_CmdId_Open_7zip = 3; - const UInt32 k_CmdId_Props = 4; - int menuResult; - { - CMenu menu; - CMenuDestroyer menuDestroyer(menu); - menu.CreatePopup(); - - unsigned numMenuItems = 0; - // unsigned defaultCmd = 0; - - for (unsigned cmd = k_CmdId_Delete; cmd <= k_CmdId_Props; cmd++) - { - if (cmd == k_CmdId_Delete) - { - if (/* !TempMode || */ indices.Size() == 0) - continue; - // defaultCmd = cmd; - } - else if (indices.Size() > 1) - break; - - - if (numMenuItems != 0) - { - if (cmd == k_CmdId_Open_Explorer) - menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); - if (cmd == k_CmdId_Props) - menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); - } - - const UINT flags = MF_STRING; - UString s; - if (cmd == k_CmdId_Delete) - { - s = LangString(IDS_BUTTON_DELETE); - s += "\tDelete"; - } - else if (cmd == k_CmdId_Open_Explorer) - { - s = LangString(IDM_OPEN_OUTSIDE); - if (s.IsEmpty()) - s = "Open Outside"; - s += "\tShift+Enter"; - } - else if (cmd == k_CmdId_Open_7zip) - { - s = LangString(IDM_OPEN_OUTSIDE); - if (s.IsEmpty()) - s = "Open Outside"; - s += " : 7-Zip"; - } - else if (cmd == k_CmdId_Props) - { - s = LangString(IDS_PROPERTIES); - if (s.IsEmpty()) - s = "Properties"; - s += "\tAlt+Enter"; - } - else - break; - s.RemoveChar(L'&'); - menu.AppendItem(flags, cmd, s); - numMenuItems++; - } - // default item is useless for us - /* - if (defaultCmd != 0) - SetMenuDefaultItem(menu, (unsigned)defaultCmd, - FALSE); // byPos - */ - /* hwnd for TrackPopupMenuEx(): DOCS: - A handle to the window that owns the shortcut menu. - This window receives all messages from the menu. - The window does not receive a WM_COMMAND message from the menu - until the function returns. - If you specify TPM_NONOTIFY in the fuFlags parameter, - the function does not send messages to the window identified by hwnd. - */ - if (numMenuItems == 0) - return true; - menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, - xPos, yPos, *this); - /* menu.Track() return value is zero, if the user cancels - the menu without making a selection, or if an error occurs */ - if (menuResult <= 0) - return true; - } - - if (menuResult == k_CmdId_Delete) - { - OnDelete(/* !IsKeyDown(VK_SHIFT) */); - return true; - } - - if (indices.Size() <= 1) - { - UString fullPath = DirPrefix; - if (indices.Size() != 0) - { - const CBrowseItem &bi = _items[indices[0]]; - const CFileInfo &file = _files[bi.MainFileIndex]; - if (file.HasReparsePoint()) - { - // we don't want external program was used to work with Links - ShowErrorMessage(*this, k_Message_Link_operation_was_Blocked); - return true; - } - fullPath += fs2us(file.Name); - } - if (menuResult == k_CmdId_Open_Explorer) - { - StartApplicationDontWait(DirPrefix, fullPath, (HWND)*this); - return true; - } - - if (menuResult == k_CmdId_Open_7zip) - { - UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); - imageName += "7zFM.exe"; - WRes wres; - { - CProcess process; - wres = process.Create(imageName, GetQuotedString2(fullPath), NULL); // curDir - } - if (wres != 0) - { - const HRESULT hres = HRESULT_FROM_WIN32(wres); - MessageBox_HResError(*this, hres, imageName); - } - return true; - } - - if (indices.Size() == 1) - if (menuResult == k_CmdId_Props) - { - const CBrowseItem &bi = _items[indices[0]]; - const CFileInfo &file = _files[bi.MainFileIndex]; - Show_FileProps_Window(file); - return true; - } - } - - return true; -} - - - -struct CWaitCursor2 -{ - HCURSOR _waitCursor; - HCURSOR _oldCursor; - - CWaitCursor2(): - _waitCursor(NULL), - _oldCursor(NULL) - {} - void Set() - { - if (!_waitCursor) - { - _waitCursor = LoadCursor(NULL, IDC_WAIT); - if (_waitCursor) - _oldCursor = SetCursor(_waitCursor); - } - } - ~CWaitCursor2() - { - if (_waitCursor) - SetCursor(_oldCursor); - } -}; - - -void CBrowseDialog2::OnOK() -{ - /* DOCS: - If a dialog box or one of its controls currently has the input focus, - then pressing the ENTER key causes Windows to send a WM_COMMAND message - with the idItem (wParam) parameter set to the ID of the default command button. - If the dialog box does not have a default command button, - then the idItem parameter is set to IDOK by default. - - We process IDOK here for Enter pressing, because we have no DEFPUSHBUTTON. - */ - if (GetFocus() == _list) - { - OnItemEnter(); - return; - } - // Enter can be pressed in another controls (Edit). - // So we don't need End() call here -} - - -bool CBrowseDialog2::GetParentPath(const UString &path, UString &parentPrefix, UString &name) -{ - parentPrefix.Empty(); - name.Empty(); - if (path.IsEmpty()) - return false; - if (_topDirPrefix == path) - return false; - UString s = path; - if (IS_PATH_SEPAR(s.Back())) - s.DeleteBack(); - if (s.IsEmpty()) - return false; - if (IS_PATH_SEPAR(s.Back())) - return false; - const unsigned pos1 = (unsigned)(s.ReverseFind_PathSepar() + 1); - parentPrefix.SetFrom(s, pos1); - name = s.Ptr(pos1); - return true; -} - - -int CBrowseDialog2::CompareItems(LPARAM lParam1, LPARAM lParam2) const -{ - if (lParam1 == lParam2) return 0; - if (lParam1 == kParentIndex) return -1; - if (lParam2 == kParentIndex) return 1; - - const int index1 = (int)lParam1; - const int index2 = (int)lParam2; - - const CBrowseItem &item1 = _items[index1]; - const CBrowseItem &item2 = _items[index2]; - - const CFileInfo &f1 = _files[item1.MainFileIndex]; - const CFileInfo &f2 = _files[item2.MainFileIndex]; - - const bool isDir2 = f2.IsDir(); - if (f1.IsDir()) - { - if (!isDir2) return -1; - } - else if (isDir2) return 1; - - const int res2 = MyCompare(index1, index2); - int res = 0; - switch (_sortIndex) - { - case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break; - case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break; - case 2: res = MyCompare(item1.Size, item2.Size); break; - case 3: res = MyCompare(item1.NumFiles, item2.NumFiles); break; - case 4: res = MyCompare(item1.NumDirs, item2.NumDirs); break; - case 5: - { - const int sub1 = item1.SubFileIndex; - const int sub2 = item2.SubFileIndex; - if (sub1 < 0) - { - if (sub2 >= 0) - res = -1; - } - else if (sub2 < 0) - res = 1; - else - res = CompareFileNames(fs2us(_files[sub1].Name), fs2us(_files[sub2].Name)); - break; - } - } - if (res == 0) - res = res2; - return _ascending ? res: -res; -} - -static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) -{ - return ((CBrowseDialog2 *)lpData)->CompareItems(lParam1, lParam2); -} - - -static const FChar *FindNonHexChar_F(const FChar *s) throw() -{ - for (;;) - { - const FChar c = (FChar)*s++; // pointer can go 1 byte after end - if ( (c < '0' || c > '9') - && (c < 'a' || c > 'z') - && (c < 'A' || c > 'Z')) - return s - 1; - } -} - - -void CBrowseDialog2::Reload_WithErrorMessage() -{ - const HRESULT res = Reload(); - if (res != S_OK) - MessageBox_HResError(*this, res, DirPrefix); -} - -void CBrowseDialog2::ChangeSorting_and_Reload(int columnIndex) -{ - if (columnIndex == _sortIndex) - _ascending = !_ascending; - else - { - _ascending = (columnIndex == 0 || columnIndex == _columnIndex_fileNameInDir); // for name columns - _sortIndex = columnIndex; - } - Reload_WithErrorMessage(); -} - - -// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter -HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UString &selectedName) -{ - UStringVector selectedVector; - if (!selectedName.IsEmpty()) - selectedVector.Add(selectedName); - return Reload(pathPrefix, selectedVector, selectedName); -} - - -HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UStringVector &selectedVector2, const UString &focusedName) -{ - UStringVector selectedVector = selectedVector2; - selectedVector.Sort(); - CObjectVector files; - CRecordVector items; - CWaitCursor2 waitCursor; - - #ifndef UNDER_CE - bool isDrive = false; - if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix)) - { - isDrive = true; - FStringVector drives; - if (!MyGetLogicalDriveStrings(drives)) - return GetLastError_noZero_HRESULT(); - FOR_VECTOR (i, drives) - { - const FString &d = drives[i]; - if (d.Len() < 2 || d.Back() != '\\') - return E_FAIL; - CBrowseItem item; - item.MainFileIndex = files.Size(); - CFileInfo &fi = files.AddNew(); - fi.SetAsDir(); - fi.Name = d; - fi.Name.DeleteBack(); - items.Add(item); - } - } - else - #endif - { - { - CEnumerator enumerator; - enumerator.SetDirPrefix(us2fs(pathPrefix)); - CFileInfo fi; - FString tail; - - const bool isTempFolder = ( - // TempMode && - IsExactTempFolder(pathPrefix) - ); - for (;;) - { - { - bool found; - if (!enumerator.Next(fi, found)) - return GetLastError_noZero_HRESULT(); - if (!found) - break; - } - if (isTempFolder) - { - // if (!Show_Non7zDirs_InTemp) - { - if (!fi.Name.IsPrefixedBy_Ascii_NoCase("7z")) - continue; - tail = fi.Name.Ptr(2); - if ( !tail.IsPrefixedBy_Ascii_NoCase("E") // drag and drop / Copy / create to email - && !tail.IsPrefixedBy_Ascii_NoCase("O") // open - && !tail.IsPrefixedBy_Ascii_NoCase("S")) // SFXSetup - continue; - const FChar *beg = tail.Ptr(1); - const FChar *end = FindNonHexChar_F(beg); - if (end - beg != 8 || *end != 0) - continue; - } - } - CBrowseItem item; - item.MainFileIndex = files.Size(); - item.Size = fi.Size; - files.Add(fi); - items.Add(item); - } - } - - UInt64 cnt = items.Size(); - // if (TempMode) - { - FOR_VECTOR (i, items) - { - CBrowseItem &item = items[i]; - const CFileInfo &fi = files[item.MainFileIndex]; - if (!fi.IsDir() || fi.HasReparsePoint()) - continue; - - CBrowseEnumerator enumer; - // we need to keep MainFileIndex and Size value of item: - enumer.bi = item; // don't change it - enumer.Path = us2fs(pathPrefix); - enumer.Path += fi.Name; - enumer.Enumerate(0); // level - item = enumer.bi; - if (item.NumRootItems == 1) - { - item.SubFileIndex = (int)files.Size(); - files.Add(enumer.fi_SubFile); - } - cnt += item.NumDirs; - cnt += item.NumFiles; - if (cnt > 1000) - waitCursor.Set(); - } - } - } - _items = items; - _files = files; - - DirPrefix = pathPrefix; - - EnableItem(IDB_BROWSE2_PARENT, !IsExactTempFolder(pathPrefix)); - - SetItemText(IDT_BROWSE2_FOLDER, DirPrefix); - - _list.SetRedraw(false); - _list.DeleteAllItems(); - - LVITEMW item; - - unsigned index = 0; - int cursorIndex = -1; - - #ifndef Z7_SFX - if (_showDots && _topDirPrefix != DirPrefix) - { - item.iItem = (int)index; - const UString itemName (".."); - if (focusedName == itemName) - cursorIndex = (int)index; - /* - if (selectedVector.IsEmpty() - // && focusedName.IsEmpty() - // && focusedName == ".." - ) - cursorIndex = (int)index; - */ - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - unsigned subItem = 0; - item.iSubItem = (int)(subItem++); - item.lParam = kParentIndex; - item.pszText = itemName.Ptr_non_const(); - item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix); - if (item.iImage < 0) - item.iImage = 0; - _list.InsertItem(&item); -#if 0 - for (int k = 1; k < 6; k++) - _list.SetSubItem(index, subItem++, L"2"); -#endif - index++; - } - #endif - - for (unsigned i = 0; i < _items.Size(); i++, index++) - { - item.iItem = (int)index; - const CBrowseItem &bi = _items[i]; - const CFileInfo &fi = _files[bi.MainFileIndex]; - const UString name = fs2us(fi.Name); - // if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0) - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - item.state = 0; - if (selectedVector.FindInSorted(name) != -1) - { - /* - if (cursorIndex == -1) - cursorIndex = (int)index; - */ - item.mask |= LVIF_STATE; - item.state |= LVIS_SELECTED; - } - if (focusedName == name) - { - if (cursorIndex == -1) - cursorIndex = (int)index; - item.mask |= LVIF_STATE; - item.state |= LVIS_FOCUSED; - } - - unsigned subItem = 0; - item.iSubItem = (int)(subItem++); - item.lParam = (LPARAM)i; - item.pszText = name.Ptr_non_const(); - - const UString fullPath = DirPrefix + name; - #ifndef UNDER_CE - if (isDrive) - { - item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path( - fi.Name + FCHAR_PATH_SEPARATOR, - FILE_ATTRIBUTE_DIRECTORY); - } - else - #endif - item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); - if (item.iImage < 0) - item.iImage = 0; - _list.InsertItem(&item); - wchar_t s[64]; - { - s[0] = 0; - if (!FILETIME_IsZero(fi.MTime)) - ConvertUtcFileTimeToString(fi.MTime, s, - #ifndef UNDER_CE - kTimestampPrintLevel_MIN - #else - kTimestampPrintLevel_DAY - #endif - ); - _list.SetSubItem(index, subItem++, s); - } - { - s[0] = 0; - Browse_ConvertSizeToString(bi, s); - _list.SetSubItem(index, subItem++, s); - } - if (_columnIndex_NumFiles >= 0) - { - UString s2; - if (fi.HasReparsePoint()) - { - s2 = "Link"; - } - else if (bi.NumFiles != 0) - { - s2.Add_UInt32(bi.NumFiles); - if (bi.WasInterrupted) - s2 += "+"; - } - _list.SetSubItem(index, subItem, s2); - } - subItem++; - if (_columnIndex_NumDirs >= 0 && bi.NumDirs != 0) - { - UString s2; - s2.Add_UInt32(bi.NumDirs); - if (bi.WasInterrupted) - s2 += "+"; - _list.SetSubItem(index, subItem, s2); - } - subItem++; - if (_columnIndex_fileNameInDir >= 0 && bi.SubFileIndex >= 0) - { - _list.SetSubItem(index, subItem, fs2us(_files[bi.SubFileIndex].Name)); - } - subItem++; - } - - if (_list.GetItemCount() > 0 && cursorIndex >= 0) - { - // _list.SetItemState_FocusedSelected(cursorIndex); - // _list.SetItemState_Focused(cursorIndex); - } - _list.SortItems(CompareItems2, (LPARAM)this); - if (_list.GetItemCount() > 0 && cursorIndex < 0) - { - if (selectedVector.IsEmpty()) - _list.SetItemState_FocusedSelected(0); - else - _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); - } - _list.EnsureVisible(_list.GetFocusedItem(), false); - _list.SetRedraw(true); - _list.InvalidateRect(NULL, true); - return S_OK; -} - - - -HRESULT CBrowseDialog2::Reload() -{ - UStringVector selected; - { - CUIntVector indexes; - GetSelected_RealIndexes(indexes); - FOR_VECTOR (i, indexes) - selected.Add(fs2us(Get_MainFileName_for_realIndex(indexes[i]))); - } - UString focusedName; - const int focusedItem = _list.GetFocusedItem(); - if (focusedItem >= 0) - { - const int realIndex = GetRealItemIndex(focusedItem); - if (realIndex != kParentIndex) - focusedName = fs2us(Get_MainFileName_for_realIndex((unsigned)realIndex)); - } - const UString dirPathTemp = DirPrefix; - return Reload(dirPathTemp, selected, focusedName); -} - - -void CBrowseDialog2::OpenParentFolder() -{ -#if 1 // 0 : for debug - // we don't allow to go to parent of TempFolder. - // if (TempMode) - { - if (IsExactTempFolder(DirPrefix)) - return; - } -#endif - - UString parent, selected; - if (GetParentPath(DirPrefix, parent, selected)) - Reload(parent, selected); -} - - -void CBrowseDialog2::OnItemEnter() -{ - const bool alt = IsKeyDown(VK_MENU); - const bool ctrl = IsKeyDown(VK_CONTROL); - const bool shift = IsKeyDown(VK_SHIFT); - - const int index = _list.GetNextSelectedItem(-1); - if (index < 0) - return; - if (_list.GetNextSelectedItem(index) >= 0) - return; // more than one selected - const int realIndex = GetRealItemIndex(index); - if (realIndex == kParentIndex) - OpenParentFolder(); - else - { - const CBrowseItem &bi = _items[realIndex]; - const CFileInfo &file = _files[bi.MainFileIndex]; - if (alt) - { - Show_FileProps_Window(file); - return; - } - if (file.HasReparsePoint()) - { - // we don't want Link open operation, - // because user can think that it's usual folder/file (non-link). - ShowErrorMessage(*this, k_Message_Link_operation_was_Blocked); - return; - } - bool needExternal = true; - if (file.IsDir()) - { - if (!shift || alt || ctrl) // open folder in Explorer: - needExternal = false; - } - const UString fullPath = DirPrefix + fs2us(file.Name); - if (needExternal) - { - StartApplicationDontWait(DirPrefix, fullPath, (HWND)*this); - return; - } - UString s = fullPath; - s.Add_PathSepar(); - const HRESULT res = Reload(s, UString()); - if (res != S_OK) - MessageBox_HResError(*this, res, s); - // SetPathEditText(); - } -} - - -void MyBrowseForTempFolder(HWND owner) -{ - FString tempPathF; - if (!NFile::NDir::MyGetTempPath(tempPathF) || tempPathF.IsEmpty()) - { - MessageBox_LastError_path(owner, tempPathF); - return; - } - CBrowseDialog2 dialog; - - LangString_OnlyFromLangFile(IDM_TEMP_DIR, dialog.Title); - dialog.Title.Replace(L"...", L""); - if (dialog.Title.IsEmpty()) - dialog.Title = "Delete Temporary Files"; - - dialog.TempFolderPath = fs2us(tempPathF); - dialog.Create(owner); - // we can exit from dialog with 2 ways: - // IDCANCEL : Esc Key, or close icons - // IDCLOSE : with Close button -} +// BrowseDialog2.cpp + +#include "StdAfx.h" + +#ifdef UNDER_CE +#include +#endif + +#include + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/ProcessUtils.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/Edit.h" +#include "../../../Windows/Control/ListView.h" + +#include "../Explorer/MyMessages.h" + +#ifndef Z7_NO_REGISTRY +#include "HelpUtils.h" +#endif + +#include "../Common/PropIDUtils.h" + +#include "PropertyNameRes.h" +#include "RegistryUtils.h" +#include "SysIconUtils.h" +#include "FormatUtils.h" +#include "LangUtils.h" + +#include "resource.h" +#include "BrowseDialog2Res.h" +#include "BrowseDialog2.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; +using namespace NFind; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +extern bool g_LVN_ITEMACTIVATE_Support; + +static const int kParentIndex = -1; +// static const UINT k_Message_RefreshPathEdit = WM_APP + 1; + + +static const wchar_t *k_Message_Link_operation_was_Blocked = + L"link openning was blocked by 7-Zip"; + +extern UString HResultToMessage(HRESULT errorCode); + +static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name) +{ + UString s = HResultToMessage(errorCode); + if (name) + { + s.Add_LF(); + s += name; + } + ShowErrorMessage(wnd, s); +} + +static void MessageBox_LastError_path(HWND wnd, const FString &path) +{ + const HRESULT hres = GetLastError_noZero_HRESULT(); + MessageBox_HResError(wnd, hres, fs2us(path)); +} + + +static const UInt32 k_EnumerateDirsLimit = 200; +static const UInt32 k_EnumerateFilesLimit = 2000; + +struct CBrowseItem +{ + unsigned MainFileIndex; + int SubFileIndex; + bool WasInterrupted; + UInt32 NumFiles; + UInt32 NumDirs; + UInt32 NumRootItems; + UInt64 Size; + + CBrowseItem(): + // MainFileIndex(0), + SubFileIndex(-1), + WasInterrupted(false), + NumFiles(0), + NumDirs(0), + NumRootItems(0), + Size(0) + {} +}; + + +struct CBrowseEnumerator +{ + FString Path; // folder path without slash at the end + CFileInfo fi; // temp + CFileInfo fi_SubFile; + CBrowseItem bi; + + void Enumerate(unsigned level); + bool NeedInterrupt() const + { + return bi.NumFiles >= k_EnumerateFilesLimit + || bi.NumDirs >= k_EnumerateDirsLimit; + } +}; + +void CBrowseEnumerator::Enumerate(unsigned level) +{ + Path.Add_PathSepar(); + const unsigned len = Path.Len(); + CObjectVector names; + { + CEnumerator enumerator; + enumerator.SetDirPrefix(Path); + while (enumerator.Next(fi)) + { + if (level == 0) + { + if (bi.NumRootItems == 0) + fi_SubFile = fi; + bi.NumRootItems++; + } + + if (fi.IsDir()) + { + bi.NumDirs++; + if (!fi.HasReparsePoint()) + names.Add(fi.Name); + } + else + { + bi.NumFiles++; + bi.Size += fi.Size; + } + + if (level != 0 || bi.NumRootItems > 1) + if (NeedInterrupt()) + { + bi.WasInterrupted = true; + return; + } + } + } + + FOR_VECTOR (i, names) + { + if (NeedInterrupt()) + { + bi.WasInterrupted = true; + return; + } + Path.DeleteFrom(len); + Path += names[i]; + Enumerate(level + 1); + } +} + + + + +class CBrowseDialog2: public NControl::CModalDialog +{ + CRecordVector _items; + CObjectVector _files; + + NControl::CListView _list; + // NControl::CEdit _pathEdit; + NControl::CComboBox _filterCombo; + + CExtToIconMap _extToIconMap; + int _sortIndex; + int _columnIndex_fileNameInDir; + int _columnIndex_NumFiles; + int _columnIndex_NumDirs; + bool _ascending; + #ifndef Z7_SFX + bool _showDots; + #endif + UString _topDirPrefix; // we don't open parent of that folder + UString DirPrefix; + + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; + // virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual void OnOK() Z7_override; + + bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo); + + // void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); } + bool GetParentPath(const UString &path, UString &parentPrefix, UString &name); + // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter + HRESULT Reload(const UString &pathPrefix, const UStringVector &selectedNames, const UString &focusedName); + HRESULT Reload(const UString &pathPrefix, const UString &selectedNames); + HRESULT Reload(); + + void ChangeSorting_and_Reload(int columnIndex); + + const CFileInfo & Get_MainFileInfo_for_realIndex(unsigned realIndex) const + { + return _files[_items[realIndex].MainFileIndex]; + } + + const FString & Get_MainFileName_for_realIndex(unsigned realIndex) const + { + return Get_MainFileInfo_for_realIndex(realIndex).Name; + } + + void Reload_WithErrorMessage(); + void OpenParentFolder(); + // void SetPathEditText(); + void PrintFileProps(UString &s, const CFileInfo &file); + void Show_FileProps_Window(const CFileInfo &file); + void OnItemEnter(); + // void FinishOnOK(); + void OnDelete(/* bool toRecycleBin */); + virtual void OnHelp() Z7_override; + bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos); + + int GetRealItemIndex(int indexInListView) const + { + LPARAM param; + if (!_list.GetItemParam((unsigned)indexInListView, param)) + return (int)-1; + return (int)param; + } + + void GetSelected_RealIndexes(CUIntVector &vector); + +public: + // bool TempMode; + // bool Show_Non7zDirs_InTemp; + // int FilterIndex; // [in / out] + // CObjectVector Filters; + + UString TempFolderPath; // with slash + UString Title; + + bool IsExactTempFolder(const UString &pathPrefix) const + { + return CompareFileNames(pathPrefix, TempFolderPath) == 0; + } + + CBrowseDialog2(): + #ifndef Z7_SFX + _showDots(false) + #endif + // , TempMode(false) + // Show_Non7zDirs_InTemp(false), + // FilterIndex(-1) + {} + INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_BROWSE2, parent); } + int CompareItems(LPARAM lParam1, LPARAM lParam2) const; +}; + + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDS_BUTTON_DELETE, + IDM_VIEW_REFRESH +}; +#endif + +bool CBrowseDialog2::OnInit() +{ + #ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + if (!Title.IsEmpty()) + SetText(Title); + + _list.Attach(GetItem(IDL_BROWSE2)); + _filterCombo.Attach(GetItem(IDC_BROWSE2_FILTER)); + + _ascending = true; + _sortIndex = 0; + _columnIndex_fileNameInDir = -1; + _columnIndex_NumFiles = -1; + _columnIndex_NumDirs = -1; + // _pathEdit.Attach(GetItem(IDE_BROWSE_PATH)); + + #ifndef UNDER_CE + _list.SetUnicodeFormat(); + #endif + + #ifndef Z7_SFX + { + CFmSettings st; + st.Load(); + + DWORD extendedStyle = 0; + if (st.FullRow) + extendedStyle |= LVS_EX_FULLROWSELECT; + if (st.ShowGrid) + extendedStyle |= LVS_EX_GRIDLINES; + if (st.SingleClick) + { + extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT; + /* + if (ReadUnderline()) + extendedStyle |= LVS_EX_UNDERLINEHOT; + */ + } + if (extendedStyle) + _list.SetExtendedListViewStyle(extendedStyle); + _showDots = st.ShowDots; + } + #endif + + { + /* + Filters.Clear(); // for debug + if (Filters.IsEmpty() && !FolderMode) + { + CBrowseFilterInfo &f = Filters.AddNew(); + const UString mask("*.*"); + f.Masks.Add(mask); + // f.Description = "("; + f.Description += mask; + // f.Description += ")"; + } + */ + _filterCombo.AddString(L"7-Zip temp files (7z*)"); + _filterCombo.SetCurSel(0); + EnableItem(IDC_BROWSE2_FILTER, false); +#if 0 + FOR_VECTOR (i, Filters) + { + _filterCombo.AddString(Filters[i].Description); + } + if (Filters.Size() <= 1) + { + EnableItem(IDC_BROWSE_FILTER, false); + } + if (/* FilterIndex >= 0 && */ (unsigned)FilterIndex < Filters.Size()) + _filterCombo.SetCurSel(FilterIndex); +#endif + } + + _list.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); + _list.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); + + unsigned columnIndex = 0; + _list.InsertColumn(columnIndex++, LangString(IDS_PROP_NAME), 100); + _list.InsertColumn(columnIndex++, LangString(IDS_PROP_MTIME), 100); + { + LV_COLUMNW column; + column.iSubItem = (int)columnIndex; + column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + column.fmt = LVCFMT_RIGHT; + column.cx = 100; + UString s = LangString(IDS_PROP_SIZE); + column.pszText = s.Ptr_non_const(); + _list.InsertColumn(columnIndex++, &column); + + // if (TempMode) + { + _columnIndex_NumFiles = (int)columnIndex; + s = LangString(IDS_PROP_FILES); + column.pszText = s.Ptr_non_const(); + _list.InsertColumn(columnIndex++, &column); + + _columnIndex_NumDirs = (int)columnIndex; + s = LangString(IDS_PROP_FOLDERS); + column.pszText = s.Ptr_non_const(); + _list.InsertColumn(columnIndex++, &column); + + _columnIndex_fileNameInDir = (int)columnIndex; + s = LangString(IDS_PROP_NAME); + s += "-2"; + _list.InsertColumn(columnIndex++, s, 100); + } + } + + _list.InsertItem(0, L"12345678901234567" + #ifndef UNDER_CE + L"1234567890" + #endif + ); + _list.SetSubItem(0, 1, L"2009-09-09" + #ifndef UNDER_CE + L" 09:09:09" + #endif + ); + _list.SetSubItem(0, 2, L"99999 MB+"); + + if (_columnIndex_NumFiles >= 0) + _list.SetSubItem(0, (unsigned)_columnIndex_NumFiles, L"123456789+"); + if (_columnIndex_NumDirs >= 0) + _list.SetSubItem(0, (unsigned)_columnIndex_NumDirs, L"123456789+"); + if (_columnIndex_fileNameInDir >= 0) + _list.SetSubItem(0, (unsigned)_columnIndex_fileNameInDir, L"12345678901234567890"); + + for (unsigned i = 0; i < columnIndex; i++) + _list.SetColumnWidthAuto((int)i); + _list.DeleteAllItems(); + + // if (TempMode) + { + _sortIndex = 1; // for MTime column + // _ascending = false; + } + + + NormalizeSize(); + + _topDirPrefix.Empty(); + { + unsigned rootSize = GetRootPrefixSize(TempFolderPath); + #if defined(_WIN32) && !defined(UNDER_CE) + // We can go up from root folder to drives list + if (IsDrivePath(TempFolderPath)) + rootSize = 0; + else if (IsSuperPath(TempFolderPath)) + { + if (IsDrivePath(TempFolderPath.Ptr(kSuperPathPrefixSize))) + rootSize = kSuperPathPrefixSize; + } + #endif + _topDirPrefix.SetFrom(TempFolderPath, rootSize); + } + + if (Reload(TempFolderPath, UString()) != S_OK) + { + // return false; + } +/* + UString name; + DirPrefix = TempFolderPath; + for (;;) + { + UString baseFolder = DirPrefix; + if (Reload(baseFolder, name) == S_OK) + break; + name.Empty(); + if (DirPrefix.IsEmpty()) + break; + UString parent, name2; + GetParentPath(DirPrefix, parent, name2); + DirPrefix = parent; + } +*/ + + #ifndef UNDER_CE + /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible, + even if we use mouse for pressing the button to open this dialog. */ + PostMsg(Z7_WIN_WM_UPDATEUISTATE, MAKEWPARAM(Z7_WIN_UIS_CLEAR, Z7_WIN_UISF_HIDEFOCUS)); + #endif + + /* + */ + + return CModalDialog::OnInit(); +} + + +bool CBrowseDialog2::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + { + RECT r; + GetClientRectOfItem(IDS_BUTTON_DELETE, r); + mx = r.left; + my = r.top; + } + InvalidateRect(NULL); + + const int xLim = xSize - mx; + { + RECT r; + GetClientRectOfItem(IDT_BROWSE2_FOLDER, r); + MoveItem(IDT_BROWSE2_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r)); + } + + int bx1, bx2, by; + GetItemSizes(IDCLOSE, bx1, by); + GetItemSizes(IDHELP, bx2, by); + const int y = ySize - my - by; + const int x = xLim - bx1; + MoveItem(IDCLOSE, x - mx - bx2, y, bx1, by); + MoveItem(IDHELP, x, y, bx2, by); + /* + int yPathSize; + { + RECT r; + GetClientRectOfItem(IDE_BROWSE_PATH, r); + yPathSize = RECT_SIZE_Y(r); + _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize); + } + */ + // Y_Size of ComboBox is tricky. Can we use it? + int yFilterSize; + { + RECT r; + GetClientRectOfItem(IDC_BROWSE2_FILTER, r); + yFilterSize = RECT_SIZE_Y(r); + _filterCombo.Move(r.left, y - my - yFilterSize, xLim - r.left, yFilterSize); + } + { + RECT r; + GetClientRectOfItem(IDL_BROWSE2, r); + _list.Move(r.left, r.top, xLim - r.left, y - my - yFilterSize - my - r.top); + } + return false; +} + + +bool CBrowseDialog2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + /* + if (message == k_Message_RefreshPathEdit) + { + // SetPathEditText(); + return true; + } + */ + if (message == WM_CONTEXTMENU) + { + if (OnContextMenu((HANDLE)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) + return true; + } + return CModalDialog::OnMessage(message, wParam, lParam); +} + + +/* +bool CBrowseDialog2::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_BROWSE2_FILTER: + { + Reload(); + return true; + } + } + } + return CModalDialog::OnCommand(code, itemID, lParam); +} +*/ + +bool CBrowseDialog2::OnNotify(UINT /* controlID */, LPNMHDR header) +{ + if (header->hwndFrom != _list) + { + if (::GetParent(header->hwndFrom) == _list) + { + // NMHDR:code is UINT + // NM_RCLICK is unsigned in windows sdk + // NM_RCLICK is int in MinGW + if (header->code == (UINT)NM_RCLICK) + { +#ifdef UNDER_CE +#define MY_NMLISTVIEW_NMITEMACTIVATE NMLISTVIEW +#else +#define MY_NMLISTVIEW_NMITEMACTIVATE NMITEMACTIVATE +#endif + MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate = (MY_NMLISTVIEW_NMITEMACTIVATE *)header; + if (itemActivate->hdr.hwndFrom == HWND(_list)) + return false; + /* + POINT point; + ::GetCursorPos(&point); + ShowColumnsContextMenu(point.x, point.y); + */ + // we want to disable menu for columns. + // to return the value from a dialog procedure we must + // call SetMsgResult(val) and return true; + // NM_RCLICK : Return nonzero to not allow the default processing + SetMsgResult(TRUE); // do not allow default processing + return true; + } + } + return false; + } + + switch (header->code) + { + case LVN_ITEMACTIVATE: + if (g_LVN_ITEMACTIVATE_Support) + OnItemEnter(); + break; + case NM_DBLCLK: + case NM_RETURN: // probably it's unused + if (!g_LVN_ITEMACTIVATE_Support) + OnItemEnter(); + break; + case LVN_COLUMNCLICK: + { + const int index = LPNMLISTVIEW(header)->iSubItem; + ChangeSorting_and_Reload(index); + return false; + } + case LVN_KEYDOWN: + { + bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header)); + // Post_RefreshPathEdit(); + return boolResult; + } + /* + case NM_RCLICK: + case NM_CLICK: + case LVN_BEGINDRAG: + Post_RefreshPathEdit(); + break; + */ + } + + return false; +} + +bool CBrowseDialog2::OnKeyDown(LPNMLVKEYDOWN keyDownInfo) +{ + const bool ctrl = IsKeyDown(VK_CONTROL); + // const bool alt = IsKeyDown(VK_MENU); + // const bool leftCtrl = IsKeyDown(VK_LCONTROL); + // const bool rightCtrl = IsKeyDown(VK_RCONTROL); + // const bool shift = IsKeyDown(VK_SHIFT); + + switch (keyDownInfo->wVKey) + { + case VK_BACK: + OpenParentFolder(); + return true; + case 'R': + if (ctrl) + { + Reload_WithErrorMessage(); + return true; + } + return false; + case VK_F3: + case VK_F5: + case VK_F6: + if (ctrl) + { + int index = 0; // name + if (keyDownInfo->wVKey == VK_F5) index = 1; // MTime + else if (keyDownInfo->wVKey == VK_F6) index = 2; // Size + ChangeSorting_and_Reload(index); + Reload_WithErrorMessage(); + return true; + } + return false; + case 'A': + if (ctrl) + { + // if (TempMode) + _list.SelectAll(); + return true; + } + return false; + + case VK_DELETE: + // if (TempMode) + OnDelete(/* !shift */); + return true; +#if 0 + case VK_NEXT: + case VK_PRIOR: + { + if (ctrl && !alt && !shift) + { + if (keyDownInfo->wVKey == VK_NEXT) + OnItemEnter(); + else + OpenParentFolder(); + SetMsgResult(TRUE); // to disable processing + return true; + } + break; + } +#endif + } + return false; +} + + +bool CBrowseDialog2::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_BROWSE2_PARENT: OpenParentFolder(); break; + case IDS_BUTTON_DELETE: + { + OnDelete(/* !IsKeyDown(VK_SHIFT) */); + break; + } + case IDM_VIEW_REFRESH: + { + Reload_WithErrorMessage(); + break; + } + default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND); + } + _list.SetFocus(); + return true; +} + + + +static void PrintPropsPrefix(UString &s, UInt32 id) +{ + s.Add_LF(); + s += " "; + AddLangString(s, id); + s += ": "; +} + +wchar_t *Browse_ConvertSizeToString(UInt64 v, wchar_t *s); + +static void Browse_ConvertSizeToString(const CBrowseItem &bi, wchar_t *s) +{ + s = Browse_ConvertSizeToString(bi.Size, s); + if (bi.WasInterrupted) + { + *s++ = '+'; + *s = 0; + } +} + +void AddSizeValue(UString &s, UInt64 value); + +static void PrintProps_Size(UString &s, UInt64 size) +{ + PrintPropsPrefix(s, IDS_PROP_SIZE); +#if 1 + AddSizeValue(s, size); +#else + s.Add_UInt64(size); + if (size >= 10000) + { + s += " ("; + wchar_t temp[64]; + Browse_ConvertSizeToString(size, temp); + s += temp; + s.Add_Char(')'); + } +#endif +} + +static void PrintProps_MTime(UString &s, const CFileInfo &fi) +{ + PrintPropsPrefix(s, IDS_PROP_MTIME); + char t[64]; + ConvertUtcFileTimeToString(fi.MTime, t); + s += t; +} + + +static void PrintProps_Name(UString &s, const CFileInfo &fi) +{ + s += fs2us(fi.Name); + if (fi.IsDir()) + s.Add_PathSepar(); +} + +static void PrintProps_Attrib(UString &s, const CFileInfo &fi) +{ + PrintPropsPrefix(s, IDS_PROP_ATTRIBUTES); + char props[64]; + ConvertWinAttribToString(props, fi.Attrib); + s += props; +#if 0 + if (fi.HasReparsePoint()) + { + s.Add_LF(); + s += "IsLink: +"; + } +#endif +} + +static void PrintProps(UString &s, const CBrowseItem &bi, + const CFileInfo &fi, const CFileInfo *fi2) +{ + PrintProps_Name(s, fi); + PrintProps_Attrib(s, fi); + if (bi.NumDirs != 0) + { + PrintPropsPrefix(s, IDS_PROP_FOLDERS); + s.Add_UInt32(bi.NumDirs); + if (bi.WasInterrupted) + s += "+"; + } + if (bi.NumFiles != 0) + { + PrintPropsPrefix(s, IDS_PROP_FILES); + s.Add_UInt32(bi.NumFiles); + if (bi.WasInterrupted) + s += "+"; + } + { + PrintProps_Size(s, bi.Size); + if (bi.WasInterrupted) + s += "+"; + } + + PrintProps_MTime(s, fi); + + if (fi2) + { + s.Add_LF(); + s += "----------------"; + s.Add_LF(); + PrintProps_Name(s, *fi2); + PrintProps_Attrib(s, *fi2); + if (!fi2->IsDir()) + PrintProps_Size(s, fi2->Size); + PrintProps_MTime(s, *fi2); + } +} + + +void CBrowseDialog2::GetSelected_RealIndexes(CUIntVector &vector) +{ + vector.Clear(); + int index = -1; + for (;;) + { + index = _list.GetNextSelectedItem(index); + if (index < 0) + break; + const int realIndex = GetRealItemIndex(index); + if (realIndex >= 0) + vector.Add((unsigned)realIndex); + } +} + + +void CBrowseDialog2::PrintFileProps(UString &s, const CFileInfo &file) +{ + CFileInfo file2; + FString path = us2fs(DirPrefix); + path += file.Name; + if (!file2.Find(path)) + { + MessageBox_LastError_path(*this, path); + Reload_WithErrorMessage(); + return; + } + CBrowseEnumerator enumer; + enumer.bi.Size = file2.Size; + if (file2.IsDir() && !file2.HasReparsePoint()) + { + enumer.Path = path; + enumer.Enumerate(0); // level + } + PrintProps(s, enumer.bi, file2, + enumer.bi.NumRootItems == 1 ? &enumer.fi_SubFile : NULL); +} + + +void CBrowseDialog2::Show_FileProps_Window(const CFileInfo &file) +{ + UString s; + PrintFileProps(s, file); + MessageBoxW(*this, s, LangString(IDS_PROPERTIES), MB_OK); +} + + +void CBrowseDialog2::OnDelete(/* bool toRecycleBin */) +{ +#if 1 + // we don't want deleting in non temp folders + if (!DirPrefix.IsPrefixedBy(TempFolderPath)) + return; +#endif + + CUIntVector indices; + GetSelected_RealIndexes(indices); + if (indices.Size() == 0) + return; + { + UInt32 titleID, messageID; + UString messageParam; + UString s2; + if (indices.Size() == 1) + { + const unsigned index = indices[0]; + const CBrowseItem &bi = _items[index]; + const CFileInfo &file = _files[bi.MainFileIndex]; + PrintFileProps(s2, file); + messageParam = fs2us(file.Name); + if (file.IsDir()) + { + titleID = IDS_CONFIRM_FOLDER_DELETE; + messageID = IDS_WANT_TO_DELETE_FOLDER; + } + else + { + titleID = IDS_CONFIRM_FILE_DELETE; + messageID = IDS_WANT_TO_DELETE_FILE; + } + } + else + { + titleID = IDS_CONFIRM_ITEMS_DELETE; + messageID = IDS_WANT_TO_DELETE_ITEMS; + messageParam = NumberToString(indices.Size()); + + for (UInt32 i = 0; i < indices.Size(); i++) + { + if (i >= 10) + { + s2 += "..."; + break; + } + const CBrowseItem &bi = _items[indices[i]]; + const CFileInfo &fi = _files[bi.MainFileIndex]; + PrintProps_Name(s2, fi); + s2.Add_LF(); + } + } + UString s = MyFormatNew(messageID, messageParam); + if (!s2.IsEmpty()) + { + s.Add_LF(); + s.Add_LF(); + s += s2; + } + if (::MessageBoxW((HWND)*this, s, LangString(titleID), + MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) + return; + } + + for (UInt32 i = 0; i < indices.Size(); i++) + { + const unsigned index = indices[i]; + bool result = true; + const CBrowseItem &bi = _items[index]; + const CFileInfo &fi = _files[bi.MainFileIndex]; + if (fi.Name.IsEmpty()) + return; // some error + const FString fullPath = us2fs(DirPrefix) + fi.Name; + if (fi.IsDir()) + result = NFile::NDir::RemoveDirWithSubItems(fullPath); + else + result = NFile::NDir::DeleteFileAlways(fullPath); + if (!result) + { + MessageBox_LastError_path(*this, fullPath); + return; + } + } + + Reload_WithErrorMessage(); +} + + +#ifndef Z7_NO_REGISTRY +#define kHelpTopic "fm/temp.htm" +void CBrowseDialog2::OnHelp() +{ + ShowHelpWindow(kHelpTopic); + CModalDialog::OnHelp(); +} +#endif + + +HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process); +HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process) +{ + UString path2 = path; + + #ifdef _WIN32 + { + const int dot = path2.ReverseFind_Dot(); + const int separ = path2.ReverseFind_PathSepar(); + if (dot < 0 || dot < separ) + path2.Add_Dot(); + } + #endif + + UINT32 result; + +#ifndef _UNICODE + if (g_IsNT) + { + SHELLEXECUTEINFOW execInfo; + execInfo.cbSize = sizeof(execInfo); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; + execInfo.hwnd = NULL; + execInfo.lpVerb = NULL; + execInfo.lpFile = path2; + execInfo.lpParameters = NULL; + execInfo.lpDirectory = dir.IsEmpty() ? NULL : (LPCWSTR)dir; + execInfo.nShow = SW_SHOWNORMAL; + execInfo.hProcess = NULL; +typedef BOOL (WINAPI * Func_ShellExecuteExW)(LPSHELLEXECUTEINFOW lpExecInfo); +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + const + Func_ShellExecuteExW + f_ShellExecuteExW = Z7_GET_PROC_ADDRESS( + Func_ShellExecuteExW, ::GetModuleHandleW(L"shell32.dll"), + "ShellExecuteExW"); + if (!f_ShellExecuteExW) + return 0; + f_ShellExecuteExW(&execInfo); + result = (UINT32)(UINT_PTR)execInfo.hInstApp; + process.Attach(execInfo.hProcess); + } + else +#endif + { + SHELLEXECUTEINFO execInfo; + execInfo.cbSize = sizeof(execInfo); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS + #ifndef UNDER_CE + | SEE_MASK_FLAG_DDEWAIT + #endif + ; + execInfo.hwnd = NULL; + execInfo.lpVerb = NULL; + const CSysString sysPath (GetSystemString(path2)); + const CSysString sysDir (GetSystemString(dir)); + execInfo.lpFile = sysPath; + execInfo.lpParameters = NULL; + execInfo.lpDirectory = + #ifdef UNDER_CE + NULL + #else + sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir + #endif + ; + execInfo.nShow = SW_SHOWNORMAL; + execInfo.hProcess = NULL; + ::ShellExecuteEx(&execInfo); + result = (UINT32)(UINT_PTR)execInfo.hInstApp; + process.Attach(execInfo.hProcess); + } + + // DEBUG_PRINT_NUM("-- ShellExecuteEx -- execInfo.hInstApp = ", result) + + if (result <= 32) + { + switch (result) + { + case SE_ERR_NOASSOC: + MessageBox_HResError(window, + GetLastError_noZero_HRESULT(), + NULL + // L"There is no application associated with the given file name extension", + ); + } + + return E_FAIL; // fixed in 15.13. Can we use it for any Windows version? + } + + return S_OK; +} + +void StartApplicationDontWait(const UString &dir, const UString &path, HWND window); +void StartApplicationDontWait(const UString &dir, const UString &path, HWND window) +{ + CProcess process; + StartApplication(dir, path, window, process); +} + + +static UString GetQuotedString2(const UString &s) +{ + UString s2 ('\"'); + s2 += s; + s2.Add_Char('\"'); + return s2; +} + + +bool CBrowseDialog2::OnContextMenu(HANDLE windowHandle, int xPos, int yPos) +{ + if (windowHandle != _list) + return false; + + CUIntVector indices; + GetSelected_RealIndexes(indices); + + // negative x,y are possible for multi-screen modes. + // x=-1 && y=-1 for keyboard call (SHIFT+F10 and others). +#if 1 // 0 : for debug + if (xPos == -1 && yPos == -1) +#endif + { +/* + if (indices.Size() == 0) + { + xPos = 0; + yPos = 0; + } + else +*/ + { + const int itemIndex = _list.GetFocusedItem(); + if (itemIndex == -1) + return false; + RECT rect; + if (!_list.GetItemRect(itemIndex, &rect, LVIR_ICON)) + return false; + // rect : rect of file icon relative to listVeiw. + xPos = (rect.left + rect.right) / 2; + yPos = (rect.top + rect.bottom) / 2; + RECT r; + GetClientRectOfItem(IDL_BROWSE2, r); + if (yPos < 0 || yPos >= RECT_SIZE_Y(r)) + yPos = 0; + } + POINT point = {xPos, yPos}; + _list.ClientToScreen(&point); + xPos = point.x; + yPos = point.y; + } + + const UInt32 k_CmdId_Delete = 1; + const UInt32 k_CmdId_Open_Explorer = 2; + const UInt32 k_CmdId_Open_7zip = 3; + const UInt32 k_CmdId_Props = 4; + int menuResult; + { + CMenu menu; + CMenuDestroyer menuDestroyer(menu); + menu.CreatePopup(); + + unsigned numMenuItems = 0; + // unsigned defaultCmd = 0; + + for (unsigned cmd = k_CmdId_Delete; cmd <= k_CmdId_Props; cmd++) + { + if (cmd == k_CmdId_Delete) + { + if (/* !TempMode || */ indices.Size() == 0) + continue; + // defaultCmd = cmd; + } + else if (indices.Size() > 1) + break; + + + if (numMenuItems != 0) + { + if (cmd == k_CmdId_Open_Explorer) + menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); + if (cmd == k_CmdId_Props) + menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); + } + + const UINT flags = MF_STRING; + UString s; + if (cmd == k_CmdId_Delete) + { + s = LangString(IDS_BUTTON_DELETE); + s += "\tDelete"; + } + else if (cmd == k_CmdId_Open_Explorer) + { + s = LangString(IDM_OPEN_OUTSIDE); + if (s.IsEmpty()) + s = "Open Outside"; + s += "\tShift+Enter"; + } + else if (cmd == k_CmdId_Open_7zip) + { + s = LangString(IDM_OPEN_OUTSIDE); + if (s.IsEmpty()) + s = "Open Outside"; + s += " : 7-Zip"; + } + else if (cmd == k_CmdId_Props) + { + s = LangString(IDS_PROPERTIES); + if (s.IsEmpty()) + s = "Properties"; + s += "\tAlt+Enter"; + } + else + break; + s.RemoveChar(L'&'); + menu.AppendItem(flags, cmd, s); + numMenuItems++; + } + // default item is useless for us + /* + if (defaultCmd != 0) + SetMenuDefaultItem(menu, (unsigned)defaultCmd, + FALSE); // byPos + */ + /* hwnd for TrackPopupMenuEx(): DOCS: + A handle to the window that owns the shortcut menu. + This window receives all messages from the menu. + The window does not receive a WM_COMMAND message from the menu + until the function returns. + If you specify TPM_NONOTIFY in the fuFlags parameter, + the function does not send messages to the window identified by hwnd. + */ + if (numMenuItems == 0) + return true; + menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, + xPos, yPos, *this); + /* menu.Track() return value is zero, if the user cancels + the menu without making a selection, or if an error occurs */ + if (menuResult <= 0) + return true; + } + + if (menuResult == k_CmdId_Delete) + { + OnDelete(/* !IsKeyDown(VK_SHIFT) */); + return true; + } + + if (indices.Size() <= 1) + { + UString fullPath = DirPrefix; + if (indices.Size() != 0) + { + const CBrowseItem &bi = _items[indices[0]]; + const CFileInfo &file = _files[bi.MainFileIndex]; + if (file.HasReparsePoint()) + { + // we don't want external program was used to work with Links + ShowErrorMessage(*this, k_Message_Link_operation_was_Blocked); + return true; + } + fullPath += fs2us(file.Name); + } + if (menuResult == k_CmdId_Open_Explorer) + { + StartApplicationDontWait(DirPrefix, fullPath, (HWND)*this); + return true; + } + + if (menuResult == k_CmdId_Open_7zip) + { + UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix()); + imageName += "7zFM.exe"; + WRes wres; + { + CProcess process; + wres = process.Create(imageName, GetQuotedString2(fullPath), NULL); // curDir + } + if (wres != 0) + { + const HRESULT hres = HRESULT_FROM_WIN32(wres); + MessageBox_HResError(*this, hres, imageName); + } + return true; + } + + if (indices.Size() == 1) + if (menuResult == k_CmdId_Props) + { + const CBrowseItem &bi = _items[indices[0]]; + const CFileInfo &file = _files[bi.MainFileIndex]; + Show_FileProps_Window(file); + return true; + } + } + + return true; +} + + + +struct CWaitCursor2 +{ + HCURSOR _waitCursor; + HCURSOR _oldCursor; + + CWaitCursor2(): + _waitCursor(NULL), + _oldCursor(NULL) + {} + void Set() + { + if (!_waitCursor) + { + _waitCursor = LoadCursor(NULL, IDC_WAIT); + if (_waitCursor) + _oldCursor = SetCursor(_waitCursor); + } + } + ~CWaitCursor2() + { + if (_waitCursor) + SetCursor(_oldCursor); + } +}; + + +void CBrowseDialog2::OnOK() +{ + /* DOCS: + If a dialog box or one of its controls currently has the input focus, + then pressing the ENTER key causes Windows to send a WM_COMMAND message + with the idItem (wParam) parameter set to the ID of the default command button. + If the dialog box does not have a default command button, + then the idItem parameter is set to IDOK by default. + + We process IDOK here for Enter pressing, because we have no DEFPUSHBUTTON. + */ + if (GetFocus() == _list) + { + OnItemEnter(); + return; + } + // Enter can be pressed in another controls (Edit). + // So we don't need End() call here +} + + +bool CBrowseDialog2::GetParentPath(const UString &path, UString &parentPrefix, UString &name) +{ + parentPrefix.Empty(); + name.Empty(); + if (path.IsEmpty()) + return false; + if (_topDirPrefix == path) + return false; + UString s = path; + if (IS_PATH_SEPAR(s.Back())) + s.DeleteBack(); + if (s.IsEmpty()) + return false; + if (IS_PATH_SEPAR(s.Back())) + return false; + const unsigned pos1 = (unsigned)(s.ReverseFind_PathSepar() + 1); + parentPrefix.SetFrom(s, pos1); + name = s.Ptr(pos1); + return true; +} + + +int CBrowseDialog2::CompareItems(LPARAM lParam1, LPARAM lParam2) const +{ + if (lParam1 == lParam2) return 0; + if (lParam1 == kParentIndex) return -1; + if (lParam2 == kParentIndex) return 1; + + const int index1 = (int)lParam1; + const int index2 = (int)lParam2; + + const CBrowseItem &item1 = _items[index1]; + const CBrowseItem &item2 = _items[index2]; + + const CFileInfo &f1 = _files[item1.MainFileIndex]; + const CFileInfo &f2 = _files[item2.MainFileIndex]; + + const bool isDir2 = f2.IsDir(); + if (f1.IsDir()) + { + if (!isDir2) return -1; + } + else if (isDir2) return 1; + + const int res2 = MyCompare(index1, index2); + int res = 0; + switch (_sortIndex) + { + case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break; + case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break; + case 2: res = MyCompare(item1.Size, item2.Size); break; + case 3: res = MyCompare(item1.NumFiles, item2.NumFiles); break; + case 4: res = MyCompare(item1.NumDirs, item2.NumDirs); break; + case 5: + { + const int sub1 = item1.SubFileIndex; + const int sub2 = item2.SubFileIndex; + if (sub1 < 0) + { + if (sub2 >= 0) + res = -1; + } + else if (sub2 < 0) + res = 1; + else + res = CompareFileNames(fs2us(_files[sub1].Name), fs2us(_files[sub2].Name)); + break; + } + } + if (res == 0) + res = res2; + return _ascending ? res: -res; +} + +static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) +{ + return ((CBrowseDialog2 *)lpData)->CompareItems(lParam1, lParam2); +} + + +static const FChar *FindNonHexChar_F(const FChar *s) throw() +{ + for (;;) + { + const FChar c = (FChar)*s++; // pointer can go 1 byte after end + if ( (c < '0' || c > '9') + && (c < 'a' || c > 'z') + && (c < 'A' || c > 'Z')) + return s - 1; + } +} + + +void CBrowseDialog2::Reload_WithErrorMessage() +{ + const HRESULT res = Reload(); + if (res != S_OK) + MessageBox_HResError(*this, res, DirPrefix); +} + +void CBrowseDialog2::ChangeSorting_and_Reload(int columnIndex) +{ + if (columnIndex == _sortIndex) + _ascending = !_ascending; + else + { + _ascending = (columnIndex == 0 || columnIndex == _columnIndex_fileNameInDir); // for name columns + _sortIndex = columnIndex; + } + Reload_WithErrorMessage(); +} + + +// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter +HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UString &selectedName) +{ + UStringVector selectedVector; + if (!selectedName.IsEmpty()) + selectedVector.Add(selectedName); + return Reload(pathPrefix, selectedVector, selectedName); +} + + +HRESULT CBrowseDialog2::Reload(const UString &pathPrefix, const UStringVector &selectedVector2, const UString &focusedName) +{ + UStringVector selectedVector = selectedVector2; + selectedVector.Sort(); + CObjectVector files; + CRecordVector items; + CWaitCursor2 waitCursor; + + #ifndef UNDER_CE + bool isDrive = false; + if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix)) + { + isDrive = true; + FStringVector drives; + if (!MyGetLogicalDriveStrings(drives)) + return GetLastError_noZero_HRESULT(); + FOR_VECTOR (i, drives) + { + const FString &d = drives[i]; + if (d.Len() < 2 || d.Back() != '\\') + return E_FAIL; + CBrowseItem item; + item.MainFileIndex = files.Size(); + CFileInfo &fi = files.AddNew(); + fi.SetAsDir(); + fi.Name = d; + fi.Name.DeleteBack(); + items.Add(item); + } + } + else + #endif + { + { + CEnumerator enumerator; + enumerator.SetDirPrefix(us2fs(pathPrefix)); + CFileInfo fi; + FString tail; + + const bool isTempFolder = ( + // TempMode && + IsExactTempFolder(pathPrefix) + ); + for (;;) + { + { + bool found; + if (!enumerator.Next(fi, found)) + return GetLastError_noZero_HRESULT(); + if (!found) + break; + } + if (isTempFolder) + { + // if (!Show_Non7zDirs_InTemp) + { + if (!fi.Name.IsPrefixedBy_Ascii_NoCase("7z")) + continue; + tail = fi.Name.Ptr(2); + if ( !tail.IsPrefixedBy_Ascii_NoCase("E") // drag and drop / Copy / create to email + && !tail.IsPrefixedBy_Ascii_NoCase("O") // open + && !tail.IsPrefixedBy_Ascii_NoCase("S")) // SFXSetup + continue; + const FChar *beg = tail.Ptr(1); + const FChar *end = FindNonHexChar_F(beg); + if (end - beg != 8 || *end != 0) + continue; + } + } + CBrowseItem item; + item.MainFileIndex = files.Size(); + item.Size = fi.Size; + files.Add(fi); + items.Add(item); + } + } + + UInt64 cnt = items.Size(); + // if (TempMode) + { + FOR_VECTOR (i, items) + { + CBrowseItem &item = items[i]; + const CFileInfo &fi = files[item.MainFileIndex]; + if (!fi.IsDir() || fi.HasReparsePoint()) + continue; + + CBrowseEnumerator enumer; + // we need to keep MainFileIndex and Size value of item: + enumer.bi = item; // don't change it + enumer.Path = us2fs(pathPrefix); + enumer.Path += fi.Name; + enumer.Enumerate(0); // level + item = enumer.bi; + if (item.NumRootItems == 1) + { + item.SubFileIndex = (int)files.Size(); + files.Add(enumer.fi_SubFile); + } + cnt += item.NumDirs; + cnt += item.NumFiles; + if (cnt > 1000) + waitCursor.Set(); + } + } + } + _items = items; + _files = files; + + DirPrefix = pathPrefix; + + EnableItem(IDB_BROWSE2_PARENT, !IsExactTempFolder(pathPrefix)); + + SetItemText(IDT_BROWSE2_FOLDER, DirPrefix); + + _list.SetRedraw(false); + _list.DeleteAllItems(); + + LVITEMW item; + + unsigned index = 0; + int cursorIndex = -1; + + #ifndef Z7_SFX + if (_showDots && _topDirPrefix != DirPrefix) + { + item.iItem = (int)index; + const UString itemName (".."); + if (focusedName == itemName) + cursorIndex = (int)index; + /* + if (selectedVector.IsEmpty() + // && focusedName.IsEmpty() + // && focusedName == ".." + ) + cursorIndex = (int)index; + */ + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + unsigned subItem = 0; + item.iSubItem = (int)(subItem++); + item.lParam = kParentIndex; + item.pszText = itemName.Ptr_non_const(); + item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix); + if (item.iImage < 0) + item.iImage = 0; + _list.InsertItem(&item); +#if 0 + for (int k = 1; k < 6; k++) + _list.SetSubItem(index, subItem++, L"2"); +#endif + index++; + } + #endif + + for (unsigned i = 0; i < _items.Size(); i++, index++) + { + item.iItem = (int)index; + const CBrowseItem &bi = _items[i]; + const CFileInfo &fi = _files[bi.MainFileIndex]; + const UString name = fs2us(fi.Name); + // if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0) + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + item.state = 0; + if (selectedVector.FindInSorted(name) != -1) + { + /* + if (cursorIndex == -1) + cursorIndex = (int)index; + */ + item.mask |= LVIF_STATE; + item.state |= LVIS_SELECTED; + } + if (focusedName == name) + { + if (cursorIndex == -1) + cursorIndex = (int)index; + item.mask |= LVIF_STATE; + item.state |= LVIS_FOCUSED; + } + + unsigned subItem = 0; + item.iSubItem = (int)(subItem++); + item.lParam = (LPARAM)i; + item.pszText = name.Ptr_non_const(); + + const UString fullPath = DirPrefix + name; + #ifndef UNDER_CE + if (isDrive) + { + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path( + fi.Name + FCHAR_PATH_SEPARATOR, + FILE_ATTRIBUTE_DIRECTORY); + } + else + #endif + item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath); + if (item.iImage < 0) + item.iImage = 0; + _list.InsertItem(&item); + wchar_t s[64]; + { + s[0] = 0; + if (!FILETIME_IsZero(fi.MTime)) + ConvertUtcFileTimeToString(fi.MTime, s, + #ifndef UNDER_CE + kTimestampPrintLevel_MIN + #else + kTimestampPrintLevel_DAY + #endif + ); + _list.SetSubItem(index, subItem++, s); + } + { + s[0] = 0; + Browse_ConvertSizeToString(bi, s); + _list.SetSubItem(index, subItem++, s); + } + if (_columnIndex_NumFiles >= 0) + { + UString s2; + if (fi.HasReparsePoint()) + { + s2 = "Link"; + } + else if (bi.NumFiles != 0) + { + s2.Add_UInt32(bi.NumFiles); + if (bi.WasInterrupted) + s2 += "+"; + } + _list.SetSubItem(index, subItem, s2); + } + subItem++; + if (_columnIndex_NumDirs >= 0 && bi.NumDirs != 0) + { + UString s2; + s2.Add_UInt32(bi.NumDirs); + if (bi.WasInterrupted) + s2 += "+"; + _list.SetSubItem(index, subItem, s2); + } + subItem++; + if (_columnIndex_fileNameInDir >= 0 && bi.SubFileIndex >= 0) + { + _list.SetSubItem(index, subItem, fs2us(_files[bi.SubFileIndex].Name)); + } + subItem++; + } + + if (_list.GetItemCount() > 0 && cursorIndex >= 0) + { + // _list.SetItemState_FocusedSelected(cursorIndex); + // _list.SetItemState_Focused(cursorIndex); + } + _list.SortItems(CompareItems2, (LPARAM)this); + if (_list.GetItemCount() > 0 && cursorIndex < 0) + { + if (selectedVector.IsEmpty()) + _list.SetItemState_FocusedSelected(0); + else + _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); + } + _list.EnsureVisible(_list.GetFocusedItem(), false); + _list.SetRedraw(true); + _list.InvalidateRect(NULL, true); + return S_OK; +} + + + +HRESULT CBrowseDialog2::Reload() +{ + UStringVector selected; + { + CUIntVector indexes; + GetSelected_RealIndexes(indexes); + FOR_VECTOR (i, indexes) + selected.Add(fs2us(Get_MainFileName_for_realIndex(indexes[i]))); + } + UString focusedName; + const int focusedItem = _list.GetFocusedItem(); + if (focusedItem >= 0) + { + const int realIndex = GetRealItemIndex(focusedItem); + if (realIndex != kParentIndex) + focusedName = fs2us(Get_MainFileName_for_realIndex((unsigned)realIndex)); + } + const UString dirPathTemp = DirPrefix; + return Reload(dirPathTemp, selected, focusedName); +} + + +void CBrowseDialog2::OpenParentFolder() +{ +#if 1 // 0 : for debug + // we don't allow to go to parent of TempFolder. + // if (TempMode) + { + if (IsExactTempFolder(DirPrefix)) + return; + } +#endif + + UString parent, selected; + if (GetParentPath(DirPrefix, parent, selected)) + Reload(parent, selected); +} + + +void CBrowseDialog2::OnItemEnter() +{ + const bool alt = IsKeyDown(VK_MENU); + const bool ctrl = IsKeyDown(VK_CONTROL); + const bool shift = IsKeyDown(VK_SHIFT); + + const int index = _list.GetNextSelectedItem(-1); + if (index < 0) + return; + if (_list.GetNextSelectedItem(index) >= 0) + return; // more than one selected + const int realIndex = GetRealItemIndex(index); + if (realIndex == kParentIndex) + OpenParentFolder(); + else + { + const CBrowseItem &bi = _items[realIndex]; + const CFileInfo &file = _files[bi.MainFileIndex]; + if (alt) + { + Show_FileProps_Window(file); + return; + } + if (file.HasReparsePoint()) + { + // we don't want Link open operation, + // because user can think that it's usual folder/file (non-link). + ShowErrorMessage(*this, k_Message_Link_operation_was_Blocked); + return; + } + bool needExternal = true; + if (file.IsDir()) + { + if (!shift || alt || ctrl) // open folder in Explorer: + needExternal = false; + } + const UString fullPath = DirPrefix + fs2us(file.Name); + if (needExternal) + { + StartApplicationDontWait(DirPrefix, fullPath, (HWND)*this); + return; + } + UString s = fullPath; + s.Add_PathSepar(); + const HRESULT res = Reload(s, UString()); + if (res != S_OK) + MessageBox_HResError(*this, res, s); + // SetPathEditText(); + } +} + + +void MyBrowseForTempFolder(HWND owner) +{ + FString tempPathF; + if (!NFile::NDir::MyGetTempPath(tempPathF) || tempPathF.IsEmpty()) + { + MessageBox_LastError_path(owner, tempPathF); + return; + } + CBrowseDialog2 dialog; + + LangString_OnlyFromLangFile(IDM_TEMP_DIR, dialog.Title); + dialog.Title.Replace(L"...", L""); + if (dialog.Title.IsEmpty()) + dialog.Title = "Delete Temporary Files"; + + dialog.TempFolderPath = fs2us(tempPathF); + dialog.Create(owner); + // we can exit from dialog with 2 ways: + // IDCANCEL : Esc Key, or close icons + // IDCLOSE : with Close button +} diff --git a/CPP/7zip/UI/FileManager/BrowseDialog2.h b/CPP/7zip/UI/FileManager/BrowseDialog2.h index 187080e66..6d5fb2375 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog2.h +++ b/CPP/7zip/UI/FileManager/BrowseDialog2.h @@ -1,10 +1,10 @@ -// BrowseDialog2.h - -#ifndef ZIP7_INC_BROWSE_DIALOG2_H -#define ZIP7_INC_BROWSE_DIALOG2_H - -#include "../../../Windows/Window.h" - -void MyBrowseForTempFolder(HWND owner); - -#endif +// BrowseDialog2.h + +#ifndef ZIP7_INC_BROWSE_DIALOG2_H +#define ZIP7_INC_BROWSE_DIALOG2_H + +#include "../../../Windows/Window.h" + +void MyBrowseForTempFolder(HWND owner); + +#endif diff --git a/CPP/7zip/UI/FileManager/BrowseDialog2.rc b/CPP/7zip/UI/FileManager/BrowseDialog2.rc index c69248a23..2ce2e4581 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog2.rc +++ b/CPP/7zip/UI/FileManager/BrowseDialog2.rc @@ -1,32 +1,32 @@ -#include "BrowseDialog2Res.h" -#include "../../GuiCommon.rc" -// #include "resource.h" - -#define xc 450 -#define yc 328 - -#define k_BROWSE2_y_CtrlSize 14 - -#define k_BROWSE2_y_List 40 - -IDD_BROWSE2 DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "7-Zip: Browse Temp Files" -{ -// EDITTEXT IDE_BROWSE_PATH, m, by - m - k_BROWSE_y_CtrlSize - k_BROWSE_y_CtrlSize - m, xc, k_BROWSE_y_CtrlSize, ES_AUTOHSCROLL - COMBOBOX IDC_BROWSE2_FILTER, m, by - m - k_BROWSE2_y_CtrlSize, xc, 30, MY_COMBO - -// DON'T USE DEFPUSHBUTTON here, because we use IDOK as default action for Enter key. - PUSHBUTTON "Close", IDCLOSE, bx2, by, bxs, bys, WS_GROUP - PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys - - PUSHBUTTON "Delete", IDS_BUTTON_DELETE, m , m, 64, bys - PUSHBUTTON "Refresh", IDM_VIEW_REFRESH, m + 64 + 8, m, 64, bys - - PUSHBUTTON "<--", IDB_BROWSE2_PARENT, m, m + 21, 24, bys -// LTEXT "", IDT_BROWSE_FOLDER, m + 30, m + 24, xc - 30, 8 - EDITTEXT IDT_BROWSE2_FOLDER, m + 28, m + 22, xc - 28, 14, ES_AUTOHSCROLL | ES_READONLY - - CONTROL "List1", IDL_BROWSE2, "SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | WS_BORDER | WS_TABSTOP, - m, m + k_BROWSE2_y_List, xc, yc - bys - m - k_BROWSE2_y_List - k_BROWSE2_y_CtrlSize - m -} +#include "BrowseDialog2Res.h" +#include "../../GuiCommon.rc" +// #include "resource.h" + +#define xc 450 +#define yc 328 + +#define k_BROWSE2_y_CtrlSize 14 + +#define k_BROWSE2_y_List 40 + +IDD_BROWSE2 DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "7-Zip: Browse Temp Files" +{ +// EDITTEXT IDE_BROWSE_PATH, m, by - m - k_BROWSE_y_CtrlSize - k_BROWSE_y_CtrlSize - m, xc, k_BROWSE_y_CtrlSize, ES_AUTOHSCROLL + COMBOBOX IDC_BROWSE2_FILTER, m, by - m - k_BROWSE2_y_CtrlSize, xc, 30, MY_COMBO + +// DON'T USE DEFPUSHBUTTON here, because we use IDOK as default action for Enter key. + PUSHBUTTON "Close", IDCLOSE, bx2, by, bxs, bys, WS_GROUP + PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys + + PUSHBUTTON "Delete", IDS_BUTTON_DELETE, m , m, 64, bys + PUSHBUTTON "Refresh", IDM_VIEW_REFRESH, m + 64 + 8, m, 64, bys + + PUSHBUTTON "<--", IDB_BROWSE2_PARENT, m, m + 21, 24, bys +// LTEXT "", IDT_BROWSE_FOLDER, m + 30, m + 24, xc - 30, 8 + EDITTEXT IDT_BROWSE2_FOLDER, m + 28, m + 22, xc - 28, 14, ES_AUTOHSCROLL | ES_READONLY + + CONTROL "List1", IDL_BROWSE2, "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | WS_BORDER | WS_TABSTOP, + m, m + k_BROWSE2_y_List, xc, yc - bys - m - k_BROWSE2_y_List - k_BROWSE2_y_CtrlSize - m +} diff --git a/CPP/7zip/UI/FileManager/BrowseDialog2Res.h b/CPP/7zip/UI/FileManager/BrowseDialog2Res.h index 09b62d30b..add915891 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialog2Res.h +++ b/CPP/7zip/UI/FileManager/BrowseDialog2Res.h @@ -1,9 +1,9 @@ -#define IDD_BROWSE2 93 - -#define IDL_BROWSE2 100 -#define IDT_BROWSE2_FOLDER 101 -// #define IDE_BROWSE2_PATH 102 -#define IDC_BROWSE2_FILTER 103 - -#define IDB_BROWSE2_PARENT 110 -// #define IDB_BROWSE2_CREATE_DIR 112 +#define IDD_BROWSE2 93 + +#define IDL_BROWSE2 100 +#define IDT_BROWSE2_FOLDER 101 +// #define IDE_BROWSE2_PATH 102 +#define IDC_BROWSE2_FILTER 103 + +#define IDB_BROWSE2_PARENT 110 +// #define IDB_BROWSE2_CREATE_DIR 112 diff --git a/CPP/7zip/UI/FileManager/BrowseDialogRes.h b/CPP/7zip/UI/FileManager/BrowseDialogRes.h index f211b7374..aff84ec9a 100644 --- a/CPP/7zip/UI/FileManager/BrowseDialogRes.h +++ b/CPP/7zip/UI/FileManager/BrowseDialogRes.h @@ -1,9 +1,9 @@ -#define IDD_BROWSE 95 - -#define IDL_BROWSE 100 -#define IDT_BROWSE_FOLDER 101 -#define IDE_BROWSE_PATH 102 -#define IDC_BROWSE_FILTER 103 - -#define IDB_BROWSE_PARENT 110 -#define IDB_BROWSE_CREATE_DIR 112 +#define IDD_BROWSE 95 + +#define IDL_BROWSE 100 +#define IDT_BROWSE_FOLDER 101 +#define IDE_BROWSE_PATH 102 +#define IDC_BROWSE_FILTER 103 + +#define IDB_BROWSE_PARENT 110 +#define IDB_BROWSE_CREATE_DIR 112 diff --git a/CPP/7zip/UI/FileManager/ClassDefs.cpp b/CPP/7zip/UI/FileManager/ClassDefs.cpp index 24b91cf00..5c2690437 100644 --- a/CPP/7zip/UI/FileManager/ClassDefs.cpp +++ b/CPP/7zip/UI/FileManager/ClassDefs.cpp @@ -1,12 +1,12 @@ -// ClassDefs.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include "../../../Common/MyInitGuid.h" - -#include "../Agent/Agent.h" - -#include "MyWindowsNew.h" -#include "../Explorer/MyExplorerCommand.h" +// ClassDefs.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include "../../../Common/MyInitGuid.h" + +#include "../Agent/Agent.h" + +#include "MyWindowsNew.h" +#include "../Explorer/MyExplorerCommand.h" diff --git a/CPP/7zip/UI/FileManager/ComboDialog.cpp b/CPP/7zip/UI/FileManager/ComboDialog.cpp index cfcad6c29..921972eab 100644 --- a/CPP/7zip/UI/FileManager/ComboDialog.cpp +++ b/CPP/7zip/UI/FileManager/ComboDialog.cpp @@ -1,64 +1,64 @@ -// ComboDialog.cpp - -#include "StdAfx.h" -#include "ComboDialog.h" - -#include "../../../Windows/Control/Static.h" - -#ifdef Z7_LANG -#include "LangUtils.h" -#endif - -using namespace NWindows; - -bool CComboDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetDlgItems(*this, NULL, 0); - #endif - _comboBox.Attach(GetItem(IDC_COMBO)); - - /* - // why it doesn't work ? - DWORD style = _comboBox.GetStyle(); - if (Sorted) - style |= CBS_SORT; - else - style &= ~CBS_SORT; - _comboBox.SetStyle(style); - */ - SetText(Title); - - NControl::CStatic staticContol; - staticContol.Attach(GetItem(IDT_COMBO)); - staticContol.SetText(Static); - _comboBox.SetText(Value); - FOR_VECTOR (i, Strings) - _comboBox.AddString(Strings[i]); - NormalizeSize(); - return CModalDialog::OnInit(); -} - -bool CComboDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx1, bx2, by; - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDOK, bx2, by); - int y = ySize - my - by; - int x = xSize - mx - bx1; - - InvalidateRect(NULL); - - MoveItem(IDCANCEL, x, y, bx1, by); - MoveItem(IDOK, x - mx - bx2, y, bx2, by); - ChangeSubWindowSizeX(_comboBox, xSize - mx * 2); - return false; -} - -void CComboDialog::OnOK() -{ - _comboBox.GetText(Value); - CModalDialog::OnOK(); -} +// ComboDialog.cpp + +#include "StdAfx.h" +#include "ComboDialog.h" + +#include "../../../Windows/Control/Static.h" + +#ifdef Z7_LANG +#include "LangUtils.h" +#endif + +using namespace NWindows; + +bool CComboDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetDlgItems(*this, NULL, 0); + #endif + _comboBox.Attach(GetItem(IDC_COMBO)); + + /* + // why it doesn't work ? + DWORD style = _comboBox.GetStyle(); + if (Sorted) + style |= CBS_SORT; + else + style &= ~CBS_SORT; + _comboBox.SetStyle(style); + */ + SetText(Title); + + NControl::CStatic staticContol; + staticContol.Attach(GetItem(IDT_COMBO)); + staticContol.SetText(Static); + _comboBox.SetText(Value); + FOR_VECTOR (i, Strings) + _comboBox.AddString(Strings[i]); + NormalizeSize(); + return CModalDialog::OnInit(); +} + +bool CComboDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDOK, bx2, by); + int y = ySize - my - by; + int x = xSize - mx - bx1; + + InvalidateRect(NULL); + + MoveItem(IDCANCEL, x, y, bx1, by); + MoveItem(IDOK, x - mx - bx2, y, bx2, by); + ChangeSubWindowSizeX(_comboBox, xSize - mx * 2); + return false; +} + +void CComboDialog::OnOK() +{ + _comboBox.GetText(Value); + CModalDialog::OnOK(); +} diff --git a/CPP/7zip/UI/FileManager/ComboDialog.h b/CPP/7zip/UI/FileManager/ComboDialog.h index d582ac7f8..bb0fda80e 100644 --- a/CPP/7zip/UI/FileManager/ComboDialog.h +++ b/CPP/7zip/UI/FileManager/ComboDialog.h @@ -1,28 +1,28 @@ -// ComboDialog.h - -#ifndef ZIP7_INC_COMBO_DIALOG_H -#define ZIP7_INC_COMBO_DIALOG_H - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Dialog.h" - -#include "ComboDialogRes.h" - -class CComboDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox _comboBox; - virtual void OnOK() Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; -public: - // bool Sorted; - UString Title; - UString Static; - UString Value; - UStringVector Strings; - - // CComboDialog(): Sorted(false) {}; - INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_COMBO, parentWindow); } -}; - -#endif +// ComboDialog.h + +#ifndef ZIP7_INC_COMBO_DIALOG_H +#define ZIP7_INC_COMBO_DIALOG_H + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Dialog.h" + +#include "ComboDialogRes.h" + +class CComboDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CComboBox _comboBox; + virtual void OnOK() Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; +public: + // bool Sorted; + UString Title; + UString Static; + UString Value; + UStringVector Strings; + + // CComboDialog(): Sorted(false) {}; + INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_COMBO, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/ComboDialog.rc b/CPP/7zip/UI/FileManager/ComboDialog.rc index 1706ffe0f..fddb7484a 100644 --- a/CPP/7zip/UI/FileManager/ComboDialog.rc +++ b/CPP/7zip/UI/FileManager/ComboDialog.rc @@ -1,16 +1,16 @@ -#include "ComboDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 240 -#define yc 64 - -IDD_COMBO DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Combo" -{ - LTEXT "", IDT_COMBO, m, m, xc, 8 - COMBOBOX IDC_COMBO, m, 20, xc, 65, MY_COMBO_WITH_EDIT - OK_CANCEL -} - -#undef xc -#undef yc +#include "ComboDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 240 +#define yc 64 + +IDD_COMBO DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Combo" +{ + LTEXT "", IDT_COMBO, m, m, xc, 8 + COMBOBOX IDC_COMBO, m, 20, xc, 65, MY_COMBO_WITH_EDIT + OK_CANCEL +} + +#undef xc +#undef yc diff --git a/CPP/7zip/UI/FileManager/ComboDialogRes.h b/CPP/7zip/UI/FileManager/ComboDialogRes.h index 98938b63b..a044797e4 100644 --- a/CPP/7zip/UI/FileManager/ComboDialogRes.h +++ b/CPP/7zip/UI/FileManager/ComboDialogRes.h @@ -1,4 +1,4 @@ -#define IDD_COMBO 98 - -#define IDT_COMBO 100 -#define IDC_COMBO 101 +#define IDD_COMBO 98 + +#define IDT_COMBO 100 +#define IDC_COMBO 101 diff --git a/CPP/7zip/UI/FileManager/CopyDialog.cpp b/CPP/7zip/UI/FileManager/CopyDialog.cpp index f0bd79e52..9bc01d064 100644 --- a/CPP/7zip/UI/FileManager/CopyDialog.cpp +++ b/CPP/7zip/UI/FileManager/CopyDialog.cpp @@ -1,103 +1,103 @@ -// CopyDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileName.h" - -#include "../../../Windows/Control/Static.h" - -#include "BrowseDialog.h" -#include "CopyDialog.h" -#include "LangUtils.h" - -using namespace NWindows; - -bool CCopyDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetDlgItems(*this, NULL, 0); - #endif - _path.Attach(GetItem(IDC_COPY)); - SetText(Title); - - NControl::CStatic staticContol; - staticContol.Attach(GetItem(IDT_COPY)); - staticContol.SetText(Static); - #ifdef UNDER_CE - // we do it, since WinCE selects Value\something instead of Value !!!! - _path.AddString(Value); - #endif - FOR_VECTOR (i, Strings) - _path.AddString(Strings[i]); - _path.SetText(Value); - SetItemText(IDT_COPY_INFO, Info); - NormalizeSize(true); - return CModalDialog::OnInit(); -} - -bool CCopyDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx1, bx2, by; - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDOK, bx2, by); - const int y = ySize - my - by; - const int x = xSize - mx - bx1; - - InvalidateRect(NULL); - - { - RECT r; - GetClientRectOfItem(IDB_COPY_SET_PATH, r); - const int bx = RECT_SIZE_X(r); - MoveItem(IDB_COPY_SET_PATH, xSize - mx - bx, r.top, bx, RECT_SIZE_Y(r)); - ChangeSubWindowSizeX(_path, xSize - mx - mx - bx - mx); - } - - { - RECT r; - GetClientRectOfItem(IDT_COPY_INFO, r); - NControl::CStatic staticContol; - staticContol.Attach(GetItem(IDT_COPY_INFO)); - const int yPos = r.top; - staticContol.Move(mx, yPos, xSize - mx * 2, y - 2 - yPos); - } - - MoveItem(IDCANCEL, x, y, bx1, by); - MoveItem(IDOK, x - mx - bx2, y, bx2, by); - - return false; -} - -bool CCopyDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_COPY_SET_PATH: - OnButtonSetPath(); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CCopyDialog::OnButtonSetPath() -{ - UString currentPath; - _path.GetText(currentPath); - - const UString title = LangString(IDS_SET_FOLDER); - - UString resultPath; - if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) - return; - NFile::NName::NormalizeDirPathPrefix(resultPath); - _path.SetCurSel(-1); - _path.SetText(resultPath); -} - -void CCopyDialog::OnOK() -{ - _path.GetText(Value); - CModalDialog::OnOK(); -} +// CopyDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileName.h" + +#include "../../../Windows/Control/Static.h" + +#include "BrowseDialog.h" +#include "CopyDialog.h" +#include "LangUtils.h" + +using namespace NWindows; + +bool CCopyDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetDlgItems(*this, NULL, 0); + #endif + _path.Attach(GetItem(IDC_COPY)); + SetText(Title); + + NControl::CStatic staticContol; + staticContol.Attach(GetItem(IDT_COPY)); + staticContol.SetText(Static); + #ifdef UNDER_CE + // we do it, since WinCE selects Value\something instead of Value !!!! + _path.AddString(Value); + #endif + FOR_VECTOR (i, Strings) + _path.AddString(Strings[i]); + _path.SetText(Value); + SetItemText(IDT_COPY_INFO, Info); + NormalizeSize(true); + return CModalDialog::OnInit(); +} + +bool CCopyDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDOK, bx2, by); + const int y = ySize - my - by; + const int x = xSize - mx - bx1; + + InvalidateRect(NULL); + + { + RECT r; + GetClientRectOfItem(IDB_COPY_SET_PATH, r); + const int bx = RECT_SIZE_X(r); + MoveItem(IDB_COPY_SET_PATH, xSize - mx - bx, r.top, bx, RECT_SIZE_Y(r)); + ChangeSubWindowSizeX(_path, xSize - mx - mx - bx - mx); + } + + { + RECT r; + GetClientRectOfItem(IDT_COPY_INFO, r); + NControl::CStatic staticContol; + staticContol.Attach(GetItem(IDT_COPY_INFO)); + const int yPos = r.top; + staticContol.Move(mx, yPos, xSize - mx * 2, y - 2 - yPos); + } + + MoveItem(IDCANCEL, x, y, bx1, by); + MoveItem(IDOK, x - mx - bx2, y, bx2, by); + + return false; +} + +bool CCopyDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_COPY_SET_PATH: + OnButtonSetPath(); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CCopyDialog::OnButtonSetPath() +{ + UString currentPath; + _path.GetText(currentPath); + + const UString title = LangString(IDS_SET_FOLDER); + + UString resultPath; + if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) + return; + NFile::NName::NormalizeDirPathPrefix(resultPath); + _path.SetCurSel(-1); + _path.SetText(resultPath); +} + +void CCopyDialog::OnOK() +{ + _path.GetText(Value); + CModalDialog::OnOK(); +} diff --git a/CPP/7zip/UI/FileManager/CopyDialog.h b/CPP/7zip/UI/FileManager/CopyDialog.h index e14a532cf..378242085 100644 --- a/CPP/7zip/UI/FileManager/CopyDialog.h +++ b/CPP/7zip/UI/FileManager/CopyDialog.h @@ -1,31 +1,31 @@ -// CopyDialog.h - -#ifndef ZIP7_INC_COPY_DIALOG_H -#define ZIP7_INC_COPY_DIALOG_H - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Dialog.h" - -#include "CopyDialogRes.h" - -const int kCopyDialog_NumInfoLines = 11; - -class CCopyDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox _path; - virtual void OnOK() Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - void OnButtonSetPath(); -public: - UString Title; - UString Static; - UString Value; - UString Info; - UStringVector Strings; - - INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_COPY, parentWindow); } -}; - -#endif +// CopyDialog.h + +#ifndef ZIP7_INC_COPY_DIALOG_H +#define ZIP7_INC_COPY_DIALOG_H + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Dialog.h" + +#include "CopyDialogRes.h" + +const int kCopyDialog_NumInfoLines = 11; + +class CCopyDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CComboBox _path; + virtual void OnOK() Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + void OnButtonSetPath(); +public: + UString Title; + UString Static; + UString Value; + UString Info; + UStringVector Strings; + + INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_COPY, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/CopyDialog.rc b/CPP/7zip/UI/FileManager/CopyDialog.rc index 378761f0d..73d3ea80d 100644 --- a/CPP/7zip/UI/FileManager/CopyDialog.rc +++ b/CPP/7zip/UI/FileManager/CopyDialog.rc @@ -1,20 +1,20 @@ -#include "CopyDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 320 -#define yc 144 - -#define y 40 - -IDD_COPY DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Copy" -{ - LTEXT "", IDT_COPY, m, m, xc, 8 - COMBOBOX IDC_COPY, m, 20, xc - bxsDots - m, 65, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_COPY_SET_PATH, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP - LTEXT "", IDT_COPY_INFO, m, y, xc, by - y - 1, SS_NOPREFIX | SS_LEFTNOWORDWRAP - OK_CANCEL -} - -#undef xc -#undef yc +#include "CopyDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 320 +#define yc 144 + +#define y 40 + +IDD_COPY DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Copy" +{ + LTEXT "", IDT_COPY, m, m, xc, 8 + COMBOBOX IDC_COPY, m, 20, xc - bxsDots - m, 65, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_COPY_SET_PATH, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP + LTEXT "", IDT_COPY_INFO, m, y, xc, by - y - 1, SS_NOPREFIX | SS_LEFTNOWORDWRAP + OK_CANCEL +} + +#undef xc +#undef yc diff --git a/CPP/7zip/UI/FileManager/CopyDialogRes.h b/CPP/7zip/UI/FileManager/CopyDialogRes.h index c2e4da9de..85f5a39a4 100644 --- a/CPP/7zip/UI/FileManager/CopyDialogRes.h +++ b/CPP/7zip/UI/FileManager/CopyDialogRes.h @@ -1,8 +1,8 @@ -#define IDD_COPY 96 - -#define IDT_COPY 100 -#define IDC_COPY 101 -#define IDB_COPY_SET_PATH 102 -#define IDT_COPY_INFO 103 - -#define IDS_SET_FOLDER 6007 +#define IDD_COPY 96 + +#define IDT_COPY 100 +#define IDC_COPY 101 +#define IDB_COPY_SET_PATH 102 +#define IDT_COPY_INFO 103 + +#define IDS_SET_FOLDER 6007 diff --git a/CPP/7zip/UI/FileManager/DialogSize.h b/CPP/7zip/UI/FileManager/DialogSize.h index 2f6aa52ba..9f2270bd4 100644 --- a/CPP/7zip/UI/FileManager/DialogSize.h +++ b/CPP/7zip/UI/FileManager/DialogSize.h @@ -1,16 +1,16 @@ -// DialogSize.h - -#ifndef ZIP7_INC_DIALOG_SIZE_H -#define ZIP7_INC_DIALOG_SIZE_H - -#include "../../../Windows/Control/Dialog.h" - -#ifdef UNDER_CE -#define BIG_DIALOG_SIZE(x, y) bool isBig = NWindows::NControl::IsDialogSizeOK(x, y); -#define SIZED_DIALOG(big) (isBig ? big : big ## _2) -#else -#define BIG_DIALOG_SIZE(x, y) -#define SIZED_DIALOG(big) big -#endif - -#endif +// DialogSize.h + +#ifndef ZIP7_INC_DIALOG_SIZE_H +#define ZIP7_INC_DIALOG_SIZE_H + +#include "../../../Windows/Control/Dialog.h" + +#ifdef UNDER_CE +#define BIG_DIALOG_SIZE(x, y) bool isBig = NWindows::NControl::IsDialogSizeOK(x, y); +#define SIZED_DIALOG(big) (isBig ? big : big ## _2) +#else +#define BIG_DIALOG_SIZE(x, y) +#define SIZED_DIALOG(big) big +#endif + +#endif diff --git a/CPP/7zip/UI/FileManager/EditDialog.cpp b/CPP/7zip/UI/FileManager/EditDialog.cpp index 49c1eb16e..e97d9ea5c 100644 --- a/CPP/7zip/UI/FileManager/EditDialog.cpp +++ b/CPP/7zip/UI/FileManager/EditDialog.cpp @@ -1,57 +1,57 @@ -// EditDialog.cpp - -#include "StdAfx.h" - -#include "EditDialog.h" - -#ifdef Z7_LANG -#include "LangUtils.h" -#endif - -bool CEditDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetDlgItems(*this, NULL, 0); - #endif - _edit.Attach(GetItem(IDE_EDIT)); - - SetText(Title); - _edit.SetText(Text); - - NormalizeSize(); - return CModalDialog::OnInit(); -} - -// #define MY_CLOSE_BUTTON_ID IDCANCEL -#define MY_CLOSE_BUTTON_ID IDCLOSE - -bool CEditDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx1, by; - GetItemSizes(MY_CLOSE_BUTTON_ID, bx1, by); - - // int bx2; - // GetItemSizes(IDOK, bx2, by); - - const int y = ySize - my - by; - const int x = xSize - mx - bx1; - - /* - RECT rect; - GetClientRect(&rect); - rect.top = y - my; - InvalidateRect(&rect); - */ - InvalidateRect(NULL); - - MoveItem(MY_CLOSE_BUTTON_ID, x, y, bx1, by); - // MoveItem(IDOK, x - mx - bx2, y, bx2, by); - /* - if (wParam == SIZE_MAXSHOW || wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXHIDE) - mx = 0; - */ - _edit.Move(mx, my, xSize - mx * 2, y - my * 2); - return false; -} +// EditDialog.cpp + +#include "StdAfx.h" + +#include "EditDialog.h" + +#ifdef Z7_LANG +#include "LangUtils.h" +#endif + +bool CEditDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetDlgItems(*this, NULL, 0); + #endif + _edit.Attach(GetItem(IDE_EDIT)); + + SetText(Title); + _edit.SetText(Text); + + NormalizeSize(); + return CModalDialog::OnInit(); +} + +// #define MY_CLOSE_BUTTON_ID IDCANCEL +#define MY_CLOSE_BUTTON_ID IDCLOSE + +bool CEditDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx1, by; + GetItemSizes(MY_CLOSE_BUTTON_ID, bx1, by); + + // int bx2; + // GetItemSizes(IDOK, bx2, by); + + const int y = ySize - my - by; + const int x = xSize - mx - bx1; + + /* + RECT rect; + GetClientRect(&rect); + rect.top = y - my; + InvalidateRect(&rect); + */ + InvalidateRect(NULL); + + MoveItem(MY_CLOSE_BUTTON_ID, x, y, bx1, by); + // MoveItem(IDOK, x - mx - bx2, y, bx2, by); + /* + if (wParam == SIZE_MAXSHOW || wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXHIDE) + mx = 0; + */ + _edit.Move(mx, my, xSize - mx * 2, y - my * 2); + return false; +} diff --git a/CPP/7zip/UI/FileManager/EditDialog.h b/CPP/7zip/UI/FileManager/EditDialog.h index 49a696092..6970b14dd 100644 --- a/CPP/7zip/UI/FileManager/EditDialog.h +++ b/CPP/7zip/UI/FileManager/EditDialog.h @@ -1,25 +1,25 @@ -// EditDialog.h - -#ifndef ZIP7_INC_EDIT_DIALOG_H -#define ZIP7_INC_EDIT_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/Edit.h" - -#include "EditDialogRes.h" - -class CEditDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CEdit _edit; - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; -public: - UString Title; - UString Text; - - INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_EDIT_DLG, wndParent); } - - CEditDialog() {} -}; - -#endif +// EditDialog.h + +#ifndef ZIP7_INC_EDIT_DIALOG_H +#define ZIP7_INC_EDIT_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/Edit.h" + +#include "EditDialogRes.h" + +class CEditDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CEdit _edit; + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; +public: + UString Title; + UString Text; + + INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_EDIT_DLG, wndParent); } + + CEditDialog() {} +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/EditDialog.rc b/CPP/7zip/UI/FileManager/EditDialog.rc index 40d19966d..cdb0b4450 100644 --- a/CPP/7zip/UI/FileManager/EditDialog.rc +++ b/CPP/7zip/UI/FileManager/EditDialog.rc @@ -1,15 +1,15 @@ -#include "EditDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 320 -#define yc 240 - -IDD_EDIT_DLG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Edit" -{ - // OK_CANCEL - MY_BUTTON__CLOSE - - EDITTEXT IDE_EDIT, m, m, xc, yc - bys - m, - ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL | ES_WANTRETURN -} +#include "EditDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 320 +#define yc 240 + +IDD_EDIT_DLG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Edit" +{ + // OK_CANCEL + MY_BUTTON__CLOSE + + EDITTEXT IDE_EDIT, m, m, xc, yc - bys - m, + ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL | ES_WANTRETURN +} diff --git a/CPP/7zip/UI/FileManager/EditDialogRes.h b/CPP/7zip/UI/FileManager/EditDialogRes.h index 1bbcf916c..58c5ca911 100644 --- a/CPP/7zip/UI/FileManager/EditDialogRes.h +++ b/CPP/7zip/UI/FileManager/EditDialogRes.h @@ -1,2 +1,2 @@ -#define IDD_EDIT_DLG 94 -#define IDE_EDIT 100 +#define IDD_EDIT_DLG 94 +#define IDE_EDIT 100 diff --git a/CPP/7zip/UI/FileManager/EditPage.cpp b/CPP/7zip/UI/FileManager/EditPage.cpp index 303fe5715..a2a032152 100644 --- a/CPP/7zip/UI/FileManager/EditPage.cpp +++ b/CPP/7zip/UI/FileManager/EditPage.cpp @@ -1,159 +1,159 @@ -// EditPage.cpp - -#include "StdAfx.h" - -#include "EditPage.h" -#include "EditPageRes.h" - -#include "BrowseDialog.h" -#include "HelpUtils.h" -#include "LangUtils.h" -#include "RegistryUtils.h" - -using namespace NWindows; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_EDIT_EDITOR, - IDT_EDIT_DIFF -}; - -static const UInt32 kLangIDs_Colon[] = -{ - IDT_EDIT_VIEWER -}; -#endif - -#define kEditTopic "FM/options.htm#editor" - -bool CEditPage::OnInit() -{ - _initMode = true; - - #ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon)); - #endif - - _ctrls[0].Ctrl = IDE_EDIT_VIEWER; _ctrls[0].Button = IDB_EDIT_VIEWER; - _ctrls[1].Ctrl = IDE_EDIT_EDITOR; _ctrls[1].Button = IDB_EDIT_EDITOR; - _ctrls[2].Ctrl = IDE_EDIT_DIFF; _ctrls[2].Button = IDB_EDIT_DIFF; - - for (unsigned i = 0; i < 3; i++) - { - CEditPageCtrl &c = _ctrls[i]; - c.WasChanged = false; - c.Edit.Attach(GetItem(c.Ctrl)); - UString path; - if (i < 2) - ReadRegEditor(i > 0, path); - else - ReadRegDiff(path); - c.Edit.SetText(path); - } - - _initMode = false; - - return CPropertyPage::OnInit(); -} - -LONG CEditPage::OnApply() -{ - for (unsigned i = 0; i < 3; i++) - { - CEditPageCtrl &c = _ctrls[i]; - if (c.WasChanged) - { - UString path; - c.Edit.GetText(path); - if (i < 2) - SaveRegEditor(i > 0, path); - else - SaveRegDiff(path); - c.WasChanged = false; - } - } - - return PSNRET_NOERROR; -} - -void CEditPage::OnNotifyHelp() -{ - ShowHelpWindow(kEditTopic); -} - -void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms); - -static void Edit_BrowseForFile(NWindows::NControl::CEdit &edit, HWND hwnd) -{ - UString cmd; - edit.GetText(cmd); - - UString param; - UString prg; - - SplitCmdLineSmart(cmd, prg, param); - - CObjectVector filters; - CBrowseFilterInfo &bfi = filters.AddNew(); - bfi.Description = "*.exe"; - bfi.Masks.Add(UString("*.exe")); - - CBrowseInfo bi; - bi.FilterIndex = 0; - bi.FilePath = prg; - bi.hwndOwner = hwnd; - - if (bi.BrowseForFile(filters)) - { - cmd = bi.FilePath; - cmd.Trim(); - /* - if (!param.IsEmpty() && !resPath.IsEmpty()) - { - cmd.InsertAtFront(L'\"'); - cmd += L'\"'; - cmd.Add_Space(); - cmd += param; - } - */ - - edit.SetText(cmd); - // Changed(); - } -} - -bool CEditPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - for (unsigned i = 0; i < 3; i++) - { - CEditPageCtrl &c = _ctrls[i]; - if (buttonID == c.Button) - { - Edit_BrowseForFile(c.Edit, *this); - return true; - } - } - - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); -} - -bool CEditPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) -{ - if (!_initMode && code == EN_CHANGE) - { - for (unsigned i = 0; i < 3; i++) - { - CEditPageCtrl &c = _ctrls[i]; - if (itemID == c.Ctrl) - { - c.WasChanged = true; - Changed(); - return true; - } - } - } - - return CPropertyPage::OnCommand(code, itemID, param); -} +// EditPage.cpp + +#include "StdAfx.h" + +#include "EditPage.h" +#include "EditPageRes.h" + +#include "BrowseDialog.h" +#include "HelpUtils.h" +#include "LangUtils.h" +#include "RegistryUtils.h" + +using namespace NWindows; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_EDIT_EDITOR, + IDT_EDIT_DIFF +}; + +static const UInt32 kLangIDs_Colon[] = +{ + IDT_EDIT_VIEWER +}; +#endif + +#define kEditTopic "FM/options.htm#editor" + +bool CEditPage::OnInit() +{ + _initMode = true; + + #ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon)); + #endif + + _ctrls[0].Ctrl = IDE_EDIT_VIEWER; _ctrls[0].Button = IDB_EDIT_VIEWER; + _ctrls[1].Ctrl = IDE_EDIT_EDITOR; _ctrls[1].Button = IDB_EDIT_EDITOR; + _ctrls[2].Ctrl = IDE_EDIT_DIFF; _ctrls[2].Button = IDB_EDIT_DIFF; + + for (unsigned i = 0; i < 3; i++) + { + CEditPageCtrl &c = _ctrls[i]; + c.WasChanged = false; + c.Edit.Attach(GetItem(c.Ctrl)); + UString path; + if (i < 2) + ReadRegEditor(i > 0, path); + else + ReadRegDiff(path); + c.Edit.SetText(path); + } + + _initMode = false; + + return CPropertyPage::OnInit(); +} + +LONG CEditPage::OnApply() +{ + for (unsigned i = 0; i < 3; i++) + { + CEditPageCtrl &c = _ctrls[i]; + if (c.WasChanged) + { + UString path; + c.Edit.GetText(path); + if (i < 2) + SaveRegEditor(i > 0, path); + else + SaveRegDiff(path); + c.WasChanged = false; + } + } + + return PSNRET_NOERROR; +} + +void CEditPage::OnNotifyHelp() +{ + ShowHelpWindow(kEditTopic); +} + +void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms); + +static void Edit_BrowseForFile(NWindows::NControl::CEdit &edit, HWND hwnd) +{ + UString cmd; + edit.GetText(cmd); + + UString param; + UString prg; + + SplitCmdLineSmart(cmd, prg, param); + + CObjectVector filters; + CBrowseFilterInfo &bfi = filters.AddNew(); + bfi.Description = "*.exe"; + bfi.Masks.Add(UString("*.exe")); + + CBrowseInfo bi; + bi.FilterIndex = 0; + bi.FilePath = prg; + bi.hwndOwner = hwnd; + + if (bi.BrowseForFile(filters)) + { + cmd = bi.FilePath; + cmd.Trim(); + /* + if (!param.IsEmpty() && !resPath.IsEmpty()) + { + cmd.InsertAtFront(L'\"'); + cmd += L'\"'; + cmd.Add_Space(); + cmd += param; + } + */ + + edit.SetText(cmd); + // Changed(); + } +} + +bool CEditPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + for (unsigned i = 0; i < 3; i++) + { + CEditPageCtrl &c = _ctrls[i]; + if (buttonID == c.Button) + { + Edit_BrowseForFile(c.Edit, *this); + return true; + } + } + + return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); +} + +bool CEditPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) +{ + if (!_initMode && code == EN_CHANGE) + { + for (unsigned i = 0; i < 3; i++) + { + CEditPageCtrl &c = _ctrls[i]; + if (itemID == c.Ctrl) + { + c.WasChanged = true; + Changed(); + return true; + } + } + } + + return CPropertyPage::OnCommand(code, itemID, param); +} diff --git a/CPP/7zip/UI/FileManager/EditPage.h b/CPP/7zip/UI/FileManager/EditPage.h index 98d61e3ab..a70fad7ff 100644 --- a/CPP/7zip/UI/FileManager/EditPage.h +++ b/CPP/7zip/UI/FileManager/EditPage.h @@ -1,30 +1,30 @@ -// EditPage.h - -#ifndef ZIP7_INC_EDIT_PAGE_H -#define ZIP7_INC_EDIT_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/Edit.h" - -struct CEditPageCtrl -{ - NWindows::NControl::CEdit Edit; - bool WasChanged; - unsigned Ctrl; - unsigned Button; -}; - -class CEditPage: public NWindows::NControl::CPropertyPage -{ - CEditPageCtrl _ctrls[3]; - - bool _initMode; -public: - virtual bool OnInit() Z7_override; - virtual void OnNotifyHelp() Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; - virtual LONG OnApply() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; -}; - -#endif +// EditPage.h + +#ifndef ZIP7_INC_EDIT_PAGE_H +#define ZIP7_INC_EDIT_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/Edit.h" + +struct CEditPageCtrl +{ + NWindows::NControl::CEdit Edit; + bool WasChanged; + unsigned Ctrl; + unsigned Button; +}; + +class CEditPage: public NWindows::NControl::CPropertyPage +{ + CEditPageCtrl _ctrls[3]; + + bool _initMode; +public: + virtual bool OnInit() Z7_override; + virtual void OnNotifyHelp() Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; + virtual LONG OnApply() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/EditPage.rc b/CPP/7zip/UI/FileManager/EditPage.rc index 7d4421efb..56c1ec0a7 100644 --- a/CPP/7zip/UI/FileManager/EditPage.rc +++ b/CPP/7zip/UI/FileManager/EditPage.rc @@ -1,19 +1,19 @@ -#include "EditPageRes.h" -#include "../../GuiCommon.rc" - -#define xc OPTIONS_PAGE_XC_SIZE -#define yc 100 - -IDD_EDIT MY_PAGE -#include "EditPage2.rc" - -#ifdef UNDER_CE - -#undef xc - -#define xc SMALL_PAGE_SIZE_X - -IDD_EDIT_2 MY_PAGE -#include "EditPage2.rc" - -#endif +#include "EditPageRes.h" +#include "../../GuiCommon.rc" + +#define xc OPTIONS_PAGE_XC_SIZE +#define yc 100 + +IDD_EDIT MY_PAGE +#include "EditPage2.rc" + +#ifdef UNDER_CE + +#undef xc + +#define xc SMALL_PAGE_SIZE_X + +IDD_EDIT_2 MY_PAGE +#include "EditPage2.rc" + +#endif diff --git a/CPP/7zip/UI/FileManager/EditPage2.rc b/CPP/7zip/UI/FileManager/EditPage2.rc index 1c175fadb..2d6554fbb 100644 --- a/CPP/7zip/UI/FileManager/EditPage2.rc +++ b/CPP/7zip/UI/FileManager/EditPage2.rc @@ -1,14 +1,14 @@ -CAPTION "Editor" -{ - LTEXT "&View:", IDT_EDIT_VIEWER, m, m, xc, 8 - EDITTEXT IDE_EDIT_VIEWER, m, m + 12, xc - m - bxsDots, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_EDIT_VIEWER, xs - m - bxsDots, m + 11, bxsDots, bys - - LTEXT "&Editor:", IDT_EDIT_EDITOR, m, m + 32, xc, 8 - EDITTEXT IDE_EDIT_EDITOR, m, m + 44, xc - m - bxsDots, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_EDIT_EDITOR, xs - m - bxsDots, m + 43, bxsDots, bys - - LTEXT "&Diff:", IDT_EDIT_DIFF, m, m + 64, xc, 8 - EDITTEXT IDE_EDIT_DIFF, m, m + 76, xc - m - bxsDots, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_EDIT_DIFF, xs - m - bxsDots, m + 75, bxsDots, bys -} +CAPTION "Editor" +{ + LTEXT "&View:", IDT_EDIT_VIEWER, m, m, xc, 8 + EDITTEXT IDE_EDIT_VIEWER, m, m + 12, xc - m - bxsDots, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_EDIT_VIEWER, xs - m - bxsDots, m + 11, bxsDots, bys + + LTEXT "&Editor:", IDT_EDIT_EDITOR, m, m + 32, xc, 8 + EDITTEXT IDE_EDIT_EDITOR, m, m + 44, xc - m - bxsDots, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_EDIT_EDITOR, xs - m - bxsDots, m + 43, bxsDots, bys + + LTEXT "&Diff:", IDT_EDIT_DIFF, m, m + 64, xc, 8 + EDITTEXT IDE_EDIT_DIFF, m, m + 76, xc - m - bxsDots, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_EDIT_DIFF, xs - m - bxsDots, m + 75, bxsDots, bys +} diff --git a/CPP/7zip/UI/FileManager/EditPageRes.h b/CPP/7zip/UI/FileManager/EditPageRes.h index 4baf6801f..017d7024f 100644 --- a/CPP/7zip/UI/FileManager/EditPageRes.h +++ b/CPP/7zip/UI/FileManager/EditPageRes.h @@ -1,15 +1,15 @@ -#define IDD_EDIT 2103 -#define IDD_EDIT_2 12103 - -#define IDT_EDIT_VIEWER 543 -#define IDT_EDIT_EDITOR 2104 -#define IDT_EDIT_DIFF 2105 - -#define IDE_EDIT_VIEWER 100 -#define IDB_EDIT_VIEWER 101 - -#define IDE_EDIT_EDITOR 102 -#define IDB_EDIT_EDITOR 103 - -#define IDE_EDIT_DIFF 104 -#define IDB_EDIT_DIFF 105 +#define IDD_EDIT 2103 +#define IDD_EDIT_2 12103 + +#define IDT_EDIT_VIEWER 543 +#define IDT_EDIT_EDITOR 2104 +#define IDT_EDIT_DIFF 2105 + +#define IDE_EDIT_VIEWER 100 +#define IDB_EDIT_VIEWER 101 + +#define IDE_EDIT_EDITOR 102 +#define IDB_EDIT_EDITOR 103 + +#define IDE_EDIT_DIFF 104 +#define IDB_EDIT_DIFF 105 diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp index 9a49f20f7..fc2fd6c48 100644 --- a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp +++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp @@ -1,107 +1,107 @@ -// EnumFormatEtc.cpp - -#include "StdAfx.h" - -#include "EnumFormatEtc.h" -#include "../../IDecl.h" -#include "MyCom2.h" - -class CEnumFormatEtc Z7_final: - public IEnumFORMATETC, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1_MT(IEnumFORMATETC) - - STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) Z7_override; - STDMETHOD(Skip)(ULONG celt) Z7_override; - STDMETHOD(Reset)(void) Z7_override; - STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc) Z7_override; - - LONG m_RefCount; - ULONG m_NumFormats; - FORMATETC *m_Formats; - ULONG m_Index; -public: - CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats); - ~CEnumFormatEtc(); -}; - -static void DeepCopyFormatEtc(FORMATETC *dest, const FORMATETC *src) -{ - *dest = *src; - if (src->ptd) - { - dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); - *(dest->ptd) = *(src->ptd); - } -} - -CEnumFormatEtc::CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats) -{ - m_RefCount = 1; - m_Index = 0; - m_NumFormats = 0; - m_Formats = new FORMATETC[numFormats]; - // if (m_Formats) - { - m_NumFormats = numFormats; - for (ULONG i = 0; i < numFormats; i++) - DeepCopyFormatEtc(&m_Formats[i], &pFormatEtc[i]); - } -} - -CEnumFormatEtc::~CEnumFormatEtc() -{ - if (m_Formats) - { - for (ULONG i = 0; i < m_NumFormats; i++) - if (m_Formats[i].ptd) - CoTaskMemFree(m_Formats[i].ptd); - delete []m_Formats; - } -} - -Z7_COMWF_B CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched) -{ - ULONG copied = 0; - if (celt == 0 || !pFormatEtc) - return E_INVALIDARG; - while (m_Index < m_NumFormats && copied < celt) - { - DeepCopyFormatEtc(&pFormatEtc[copied], &m_Formats[m_Index]); - copied++; - m_Index++; - } - if (pceltFetched) - *pceltFetched = copied; - return (copied == celt) ? S_OK : S_FALSE; -} - -Z7_COMWF_B CEnumFormatEtc::Skip(ULONG celt) -{ - m_Index += celt; - return (m_Index <= m_NumFormats) ? S_OK : S_FALSE; -} - -Z7_COMWF_B CEnumFormatEtc::Reset(void) -{ - m_Index = 0; - return S_OK; -} - -Z7_COMWF_B CEnumFormatEtc::Clone(IEnumFORMATETC ** ppEnumFormatEtc) -{ - HRESULT hResult = CreateEnumFormatEtc(m_NumFormats, m_Formats, ppEnumFormatEtc); - if (hResult == S_OK) - ((CEnumFormatEtc *)*ppEnumFormatEtc)->m_Index = m_Index; - return hResult; -} - -// replacement for SHCreateStdEnumFmtEtc -HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat) -{ - if (numFormats == 0 || !formats || !enumFormat) - return E_INVALIDARG; - *enumFormat = new CEnumFormatEtc(formats, numFormats); - return (*enumFormat) ? S_OK : E_OUTOFMEMORY; -} +// EnumFormatEtc.cpp + +#include "StdAfx.h" + +#include "EnumFormatEtc.h" +#include "../../IDecl.h" +#include "MyCom2.h" + +class CEnumFormatEtc Z7_final: + public IEnumFORMATETC, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1_MT(IEnumFORMATETC) + + STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) Z7_override; + STDMETHOD(Skip)(ULONG celt) Z7_override; + STDMETHOD(Reset)(void) Z7_override; + STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc) Z7_override; + + LONG m_RefCount; + ULONG m_NumFormats; + FORMATETC *m_Formats; + ULONG m_Index; +public: + CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats); + ~CEnumFormatEtc(); +}; + +static void DeepCopyFormatEtc(FORMATETC *dest, const FORMATETC *src) +{ + *dest = *src; + if (src->ptd) + { + dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); + *(dest->ptd) = *(src->ptd); + } +} + +CEnumFormatEtc::CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats) +{ + m_RefCount = 1; + m_Index = 0; + m_NumFormats = 0; + m_Formats = new FORMATETC[numFormats]; + // if (m_Formats) + { + m_NumFormats = numFormats; + for (ULONG i = 0; i < numFormats; i++) + DeepCopyFormatEtc(&m_Formats[i], &pFormatEtc[i]); + } +} + +CEnumFormatEtc::~CEnumFormatEtc() +{ + if (m_Formats) + { + for (ULONG i = 0; i < m_NumFormats; i++) + if (m_Formats[i].ptd) + CoTaskMemFree(m_Formats[i].ptd); + delete []m_Formats; + } +} + +Z7_COMWF_B CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched) +{ + ULONG copied = 0; + if (celt == 0 || !pFormatEtc) + return E_INVALIDARG; + while (m_Index < m_NumFormats && copied < celt) + { + DeepCopyFormatEtc(&pFormatEtc[copied], &m_Formats[m_Index]); + copied++; + m_Index++; + } + if (pceltFetched) + *pceltFetched = copied; + return (copied == celt) ? S_OK : S_FALSE; +} + +Z7_COMWF_B CEnumFormatEtc::Skip(ULONG celt) +{ + m_Index += celt; + return (m_Index <= m_NumFormats) ? S_OK : S_FALSE; +} + +Z7_COMWF_B CEnumFormatEtc::Reset(void) +{ + m_Index = 0; + return S_OK; +} + +Z7_COMWF_B CEnumFormatEtc::Clone(IEnumFORMATETC ** ppEnumFormatEtc) +{ + HRESULT hResult = CreateEnumFormatEtc(m_NumFormats, m_Formats, ppEnumFormatEtc); + if (hResult == S_OK) + ((CEnumFormatEtc *)*ppEnumFormatEtc)->m_Index = m_Index; + return hResult; +} + +// replacement for SHCreateStdEnumFmtEtc +HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat) +{ + if (numFormats == 0 || !formats || !enumFormat) + return E_INVALIDARG; + *enumFormat = new CEnumFormatEtc(formats, numFormats); + return (*enumFormat) ? S_OK : E_OUTOFMEMORY; +} diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.h b/CPP/7zip/UI/FileManager/EnumFormatEtc.h index ffbc6820e..12df225d8 100644 --- a/CPP/7zip/UI/FileManager/EnumFormatEtc.h +++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.h @@ -1,10 +1,10 @@ -// EnumFormatEtc.h - -#ifndef ZIP7_INC_ENUMFORMATETC_H -#define ZIP7_INC_ENUMFORMATETC_H - -#include "../../../Common/MyWindows.h" - -HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat); - -#endif +// EnumFormatEtc.h + +#ifndef ZIP7_INC_ENUMFORMATETC_H +#define ZIP7_INC_ENUMFORMATETC_H + +#include "../../../Common/MyWindows.h" + +HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat); + +#endif diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp index e262ee381..da25969c0 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp +++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp @@ -1,1182 +1,1272 @@ -// ExtractCallback.cpp - -#include "StdAfx.h" - - -#include "../../../Common/ComTry.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/Lang.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../Common/FilePathAutoRename.h" -#include "../../Common/StreamUtils.h" -#include "../Common/ExtractingFilePath.h" - -#ifndef Z7_SFX -#include "../Common/ZipRegistry.h" -#endif - -#include "../GUI/ExtractRes.h" -#include "resourceGui.h" - -#include "ExtractCallback.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "OverwriteDialog.h" -#ifndef Z7_NO_CRYPTO -#include "PasswordDialog.h" -#endif -#include "MemDialog.h" -#include "PropertyName.h" - -using namespace NWindows; -using namespace NFile; -using namespace NFind; - -extern bool g_DisableUserQuestions; - -CExtractCallbackImp::~CExtractCallbackImp() {} - -void CExtractCallbackImp::Init() -{ - _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING); - _lang_Testing = LangString(IDS_PROGRESS_TESTING); - _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING); - _lang_Reading = "Reading"; - - NumArchiveErrors = 0; - ThereAreMessageErrors = false; - #ifndef Z7_SFX - NumFolders = NumFiles = 0; - NeedAddFile = false; - #endif -} - -void CExtractCallbackImp::AddError_Message(LPCWSTR s) -{ - ThereAreMessageErrors = true; - ProgressDialog->Sync.AddError_Message(s); -} - -void CExtractCallbackImp::AddError_Message_ShowArcPath(LPCWSTR s) -{ - Add_ArchiveName_Error(); - AddError_Message(s); -} - - -#ifndef Z7_SFX - -Z7_COM7F_IMF(CExtractCallbackImp::SetNumFiles(UInt64 numFiles)) -{ - #ifdef Z7_SFX - UNUSED_VAR(numFiles) - #else - ProgressDialog->Sync.Set_NumFilesTotal(numFiles); - #endif - return S_OK; -} - -#endif - -Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 total)) -{ - ProgressDialog->Sync.Set_NumBytesTotal(total); - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *value)) -{ - return ProgressDialog->Sync.Set_NumBytesCur(value); -} - -HRESULT CExtractCallbackImp::Open_CheckBreak() -{ - return ProgressDialog->Sync.CheckStop(); -} - -HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) -{ - HRESULT res = S_OK; - if (!MultiArcMode) - { - if (files) - { - _totalFilesDefined = true; - // res = ProgressDialog->Sync.Set_NumFilesTotal(*files); - } - else - _totalFilesDefined = false; - - if (bytes) - { - _totalBytesDefined = true; - ProgressDialog->Sync.Set_NumBytesTotal(*bytes); - } - else - _totalBytesDefined = false; - } - - return res; -} - -HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) -{ - if (!MultiArcMode) - { - if (files) - { - ProgressDialog->Sync.Set_NumFilesCur(*files); - } - - if (bytes) - { - } - } - - return ProgressDialog->Sync.CheckStop(); -} - -HRESULT CExtractCallbackImp::Open_Finished() -{ - return ProgressDialog->Sync.CheckStop(); -} - -#ifndef Z7_NO_CRYPTO - -HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password) -{ - return CryptoGetTextPassword(password); -} - -/* -HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) -{ - passwordIsDefined = PasswordIsDefined; - password = Password; - return S_OK; -} - -bool CExtractCallbackImp::Open_WasPasswordAsked() -{ - return PasswordWasAsked; -} - -void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag() -{ - PasswordWasAsked = false; -} -*/ - -#endif - - -#ifndef Z7_SFX -Z7_COM7F_IMF(CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - ProgressDialog->Sync.Set_Ratio(inSize, outSize); - return S_OK; -} -#endif - -/* -Z7_COM7F_IMF(CExtractCallbackImp::SetTotalFiles(UInt64 total) -{ - ProgressDialog->Sync.SetNumFilesTotal(total); - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetCompletedFiles(const UInt64 *value) -{ - if (value != NULL) - ProgressDialog->Sync.SetNumFilesCur(*value); - return S_OK; -} -*/ - -Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite( - const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, - const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, - Int32 *answer)) -{ - COverwriteDialog dialog; - - dialog.OldFileInfo.SetTime2(existTime); - dialog.OldFileInfo.SetSize2(existSize); - dialog.OldFileInfo.Path = existName; - dialog.OldFileInfo.Is_FileSystemFile = true; - - dialog.NewFileInfo.SetTime2(newTime); - dialog.NewFileInfo.SetSize2(newSize); - dialog.NewFileInfo.Path = newName; - dialog.NewFileInfo.Is_FileSystemFile = Src_Is_IO_FS_Folder; - - ProgressDialog->WaitCreating(); - INT_PTR writeAnswer = dialog.Create(*ProgressDialog); - - switch (writeAnswer) - { - case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT; - case IDYES: *answer = NOverwriteAnswer::kYes; break; - case IDNO: *answer = NOverwriteAnswer::kNo; break; - case IDB_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break; - case IDB_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break; - case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break; - default: return E_FAIL; - } - return S_OK; -} - - -Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */)) -{ - _isFolder = IntToBool(isFolder); - _currentFilePath = name; - - const UString *msg = &_lang_Empty; - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break; - case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break; - case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break; - case NArchive::NExtract::NAskMode::kReadExternal: msg = &_lang_Reading; break; - // default: s = "Unknown operation"; - } - - return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder)); -} - -Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *s)) -{ - AddError_Message(s); - return S_OK; -} - -HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path) -{ - ThereAreMessageErrors = true; - ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path)); - return S_OK; -} - -#ifndef Z7_SFX - -Z7_COM7F_IMF(CExtractCallbackImp::ShowMessage(const wchar_t *s)) -{ - AddError_Message(s); - return S_OK; -} - -#endif - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s) -{ - s.Empty(); - - if (opRes == NArchive::NExtract::NOperationResult::kOK) - return; - - #ifndef Z7_SFX - UINT messageID = 0; - #endif - UINT id = 0; - - switch (opRes) - { - case NArchive::NExtract::NOperationResult::kUnsupportedMethod: - #ifndef Z7_SFX - messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD; - #endif - id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD; - break; - case NArchive::NExtract::NOperationResult::kDataError: - #ifndef Z7_SFX - messageID = encrypted ? - IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED: - IDS_EXTRACT_MESSAGE_DATA_ERROR; - #endif - id = IDS_EXTRACT_MSG_DATA_ERROR; - break; - case NArchive::NExtract::NOperationResult::kCRCError: - #ifndef Z7_SFX - messageID = encrypted ? - IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED: - IDS_EXTRACT_MESSAGE_CRC_ERROR; - #endif - id = IDS_EXTRACT_MSG_CRC_ERROR; - break; - case NArchive::NExtract::NOperationResult::kUnavailable: - id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA; - break; - case NArchive::NExtract::NOperationResult::kUnexpectedEnd: - id = IDS_EXTRACT_MSG_UEXPECTED_END; - break; - case NArchive::NExtract::NOperationResult::kDataAfterEnd: - id = IDS_EXTRACT_MSG_DATA_AFTER_END; - break; - case NArchive::NExtract::NOperationResult::kIsNotArc: - id = IDS_EXTRACT_MSG_IS_NOT_ARC; - break; - case NArchive::NExtract::NOperationResult::kHeadersError: - id = IDS_EXTRACT_MSG_HEADERS_ERROR; - break; - case NArchive::NExtract::NOperationResult::kWrongPassword: - id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM; - break; - /* - default: - messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR; - break; - */ - } - - UString msg; - - #ifndef Z7_SFX - UString msgOld; - #ifdef Z7_LANG - if (id != 0) - LangString_OnlyFromLangFile(id, msg); - if (messageID != 0 && msg.IsEmpty()) - LangString_OnlyFromLangFile(messageID, msgOld); - #endif - if (msg.IsEmpty() && !msgOld.IsEmpty()) - s = MyFormatNew(msgOld, fileName); - else - #endif - { - if (msg.IsEmpty() && id != 0) - LangString(id, msg); - if (!msg.IsEmpty()) - s += msg; - else - { - s += "Error #"; - s.Add_UInt32((UInt32)opRes); - } - - if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword) - { - // s += " : "; - // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED); - s += " : "; - AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); - } - s += " : "; - s += fileName; - } -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)) -{ - switch (opRes) - { - case NArchive::NExtract::NOperationResult::kOK: - break; - default: - { - UString s; - SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s); - AddError_Message_ShowArcPath(s); - } - } - - _currentFilePath.Empty(); - #ifndef Z7_SFX - if (_isFolder) - NumFolders++; - else - NumFiles++; - ProgressDialog->Sync.Set_NumFilesCur(NumFiles); - #endif - - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) -{ - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - UString s; - SetExtractErrorMessage(opRes, encrypted, name, s); - AddError_Message_ShowArcPath(s); - } - return S_OK; -} - -//////////////////////////////////////// -// IExtractCallbackUI - -HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */) -{ - _currentArchivePath = name; - _needWriteArchivePath = true; - #ifndef Z7_SFX - RINOK(ProgressDialog->Sync.CheckStop()) - ProgressDialog->Sync.Set_TitleFileName(name); - #endif - return S_OK; -} - -HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path) -{ - _currentFilePath = path; - #ifndef Z7_SFX - ProgressDialog->Sync.Set_FilePath(path); - #endif - return S_OK; -} - -#ifndef Z7_SFX - -Z7_COM7F_IMF(CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)) -{ - #ifndef Z7_SFX - if (NeedAddFile) - NumFiles++; - NeedAddFile = true; - ProgressDialog->Sync.Set_NumFilesCur(NumFiles); - #endif - return SetCurrentFilePath2(path); -} - -#endif - -UString HResultToMessage(HRESULT errorCode); - -static const UInt32 k_ErrorFlagsIds[] = -{ - IDS_EXTRACT_MSG_IS_NOT_ARC, - IDS_EXTRACT_MSG_HEADERS_ERROR, - IDS_EXTRACT_MSG_HEADERS_ERROR, - IDS_OPEN_MSG_UNAVAILABLE_START, - IDS_OPEN_MSG_UNCONFIRMED_START, - IDS_EXTRACT_MSG_UEXPECTED_END, - IDS_EXTRACT_MSG_DATA_AFTER_END, - IDS_EXTRACT_MSG_UNSUPPORTED_METHOD, - IDS_OPEN_MSG_UNSUPPORTED_FEATURE, - IDS_EXTRACT_MSG_DATA_ERROR, - IDS_EXTRACT_MSG_CRC_ERROR -}; - -static void AddNewLineString(UString &s, const UString &m) -{ - s += m; - s.Add_LF(); -} - -UString GetOpenArcErrorMessage(UInt32 errorFlags); -UString GetOpenArcErrorMessage(UInt32 errorFlags) -{ - UString s; - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsIds); i++) - { - UInt32 f = ((UInt32)1 << i); - if ((errorFlags & f) == 0) - continue; - UInt32 id = k_ErrorFlagsIds[i]; - UString m = LangString(id); - if (m.IsEmpty()) - continue; - if (f == kpv_ErrorFlags_EncryptedHeadersError) - { - m += " : "; - AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); - } - if (!s.IsEmpty()) - s.Add_LF(); - s += m; - errorFlags &= ~f; - } - - if (errorFlags != 0) - { - char sz[16]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt32ToHex(errorFlags, sz + 2); - if (!s.IsEmpty()) - s.Add_LF(); - s += sz; - } - - return s; -} - -static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er) -{ - UInt32 errorFlags = er.GetErrorFlags(); - UInt32 warningFlags = er.GetWarningFlags(); - - if (errorFlags != 0) - AddNewLineString(s, GetOpenArcErrorMessage(errorFlags)); - - if (!er.ErrorMessage.IsEmpty()) - AddNewLineString(s, er.ErrorMessage); - - if (warningFlags != 0) - { - s += GetNameOfProperty(kpidWarningFlags, L"Warnings"); - s += ":"; - s.Add_LF(); - AddNewLineString(s, GetOpenArcErrorMessage(warningFlags)); - } - - if (!er.WarningMessage.IsEmpty()) - { - s += GetNameOfProperty(kpidWarning, L"Warning"); - s += ": "; - s += er.WarningMessage; - s.Add_LF(); - } -} - -static UString GetBracedType(const wchar_t *type) -{ - UString s ('['); - s += type; - s.Add_Char(']'); - return s; -} - -void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result); -void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) -{ - FOR_VECTOR (level, arcLink.Arcs) - { - const CArc &arc = arcLink.Arcs[level]; - const CArcErrorInfo &er = arc.ErrorInfo; - - if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0) - continue; - - if (s.IsEmpty()) - { - s += name; - s.Add_LF(); - } - - if (level != 0) - { - AddNewLineString(s, arc.Path); - } - - ErrorInfo_Print(s, er); - - if (er.ErrorFormatIndex >= 0) - { - AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning")); - if (arc.FormatIndex == er.ErrorFormatIndex) - { - AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET)); - } - else - { - AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex)))); - AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex)))); - } - } - } - - if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK) - { - s += name; - s.Add_LF(); - if (!arcLink.Arcs.IsEmpty()) - AddNewLineString(s, arcLink.NonOpen_ArcPath); - - if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE) - { - UINT id = IDS_CANT_OPEN_ARCHIVE; - UString param; - if (arcLink.PasswordWasAsked) - id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE; - else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) - { - id = IDS_CANT_OPEN_AS_TYPE; - param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex)); - } - UString s2 = MyFormatNew(id, param); - s2.Replace(L" ''", L""); - s2.Replace(L"''", L""); - s += s2; - } - else - s += HResultToMessage(result); - - s.Add_LF(); - ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo); - } - - if (!s.IsEmpty() && s.Back() == '\n') - s.DeleteBack(); -} - -HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) -{ - _currentArchivePath = name; - _needWriteArchivePath = true; - - UString s; - OpenResult_GUI(s, codecs, arcLink, name, result); - if (!s.IsEmpty()) - { - NumArchiveErrors++; - AddError_Message(s); - _needWriteArchivePath = false; - } - - return S_OK; -} - -HRESULT CExtractCallbackImp::ThereAreNoFiles() -{ - return S_OK; -} - -void CExtractCallbackImp::Add_ArchiveName_Error() -{ - if (_needWriteArchivePath) - { - if (!_currentArchivePath.IsEmpty()) - AddError_Message(_currentArchivePath); - _needWriteArchivePath = false; - } -} - -HRESULT CExtractCallbackImp::ExtractResult(HRESULT result) -{ - #ifndef Z7_SFX - ProgressDialog->Sync.Set_FilePath(L""); - #endif - - if (result == S_OK) - return result; - NumArchiveErrors++; - if (result == E_ABORT - || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL) - ) - return result; - - Add_ArchiveName_Error(); - if (!_currentFilePath.IsEmpty()) - MessageError(_currentFilePath); - MessageError(NError::MyFormatMessage(result)); - return S_OK; -} - -#ifndef Z7_NO_CRYPTO - -HRESULT CExtractCallbackImp::SetPassword(const UString &password) -{ - PasswordIsDefined = true; - Password = password; - return S_OK; -} - -Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)) -{ - PasswordWasAsked = true; - if (!PasswordIsDefined) - { - CPasswordDialog dialog; - #ifndef Z7_SFX - const bool showPassword = NExtract::Read_ShowPassword(); - dialog.ShowPassword = showPassword; - #endif - ProgressDialog->WaitCreating(); - if (dialog.Create(*ProgressDialog) != IDOK) - return E_ABORT; - Password = dialog.Password; - PasswordIsDefined = true; - #ifndef Z7_SFX - if (dialog.ShowPassword != showPassword) - NExtract::Save_ShowPassword(dialog.ShowPassword); - #endif - } - return StringToBstr(Password, password); -} - -#endif - -#ifndef Z7_SFX - -Z7_COM7F_IMF(CExtractCallbackImp::AskWrite( - const wchar_t *srcPath, Int32 srcIsFolder, - const FILETIME *srcTime, const UInt64 *srcSize, - const wchar_t *destPath, - BSTR *destPathResult, - Int32 *writeAnswer)) -{ - UString destPathResultTemp = destPath; - - // RINOK(StringToBstr(destPath, destPathResult)); - - *destPathResult = NULL; - *writeAnswer = BoolToInt(false); - - FString destPathSys = us2fs(destPath); - const bool srcIsFolderSpec = IntToBool(srcIsFolder); - CFileInfo destFileInfo; - - if (destFileInfo.Find(destPathSys)) - { - if (srcIsFolderSpec) - { - if (!destFileInfo.IsDir()) - { - RINOK(MessageError("Cannot replace file with folder with same name", destPathSys)) - return E_ABORT; - } - *writeAnswer = BoolToInt(false); - return S_OK; - } - - if (destFileInfo.IsDir()) - { - RINOK(MessageError("Cannot replace folder with file with same name", destPathSys)) - *writeAnswer = BoolToInt(false); - return S_OK; - } - - switch ((int)OverwriteMode) - { - case NExtract::NOverwriteMode::kSkip: - return S_OK; - case NExtract::NOverwriteMode::kAsk: - { - Int32 overwriteResult; - UString destPathSpec = destPath; - const int slashPos = destPathSpec.ReverseFind_PathSepar(); - destPathSpec.DeleteFrom((unsigned)(slashPos + 1)); - destPathSpec += fs2us(destFileInfo.Name); - - RINOK(AskOverwrite( - destPathSpec, - &destFileInfo.MTime, &destFileInfo.Size, - srcPath, - srcTime, srcSize, - &overwriteResult)) - - switch (overwriteResult) - { - case NOverwriteAnswer::kCancel: return E_ABORT; - case NOverwriteAnswer::kNo: return S_OK; - case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; - case NOverwriteAnswer::kYes: break; - case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break; - case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break; - default: - return E_FAIL; - } - break; - } - default: - break; - } - - if (OverwriteMode == NExtract::NOverwriteMode::kRename) - { - if (!AutoRenamePath(destPathSys)) - { - RINOK(MessageError("Cannot create name for file", destPathSys)) - return E_ABORT; - } - destPathResultTemp = fs2us(destPathSys); - } - else - { - if (NFind::DoesFileExist_Raw(destPathSys)) - if (!NDir::DeleteFileAlways(destPathSys)) - if (GetLastError() != ERROR_FILE_NOT_FOUND) - { - RINOK(MessageError("Cannot delete output file", destPathSys)) - return E_ABORT; - } - } - } - *writeAnswer = BoolToInt(true); - return StringToBstr(destPathResultTemp, destPathResult); -} - - -Z7_COM7F_IMF(CExtractCallbackImp::UseExtractToStream(Int32 *res)) -{ - *res = BoolToInt(StreamMode); - return S_OK; -} - -static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined) -{ - ftDefined = false; - NCOM::CPropVariant prop; - RINOK(getProp->GetProp(propID, &prop)) - if (prop.vt == VT_FILETIME) - { - ft = prop.filetime; - ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - - -static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result) -{ - NCOM::CPropVariant prop; - result = false; - RINOK(getProp->GetProp(propID, &prop)) - if (prop.vt == VT_BOOL) - result = VARIANT_BOOLToBool(prop.boolVal); - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - - -Z7_COM7F_IMF(CExtractCallbackImp::GetStream7(const wchar_t *name, - Int32 isDir, - ISequentialOutStream **outStream, Int32 askExtractMode, - IGetProp *getProp)) -{ - COM_TRY_BEGIN - *outStream = NULL; - _newVirtFileWasAdded = false; - _hashStream_WasUsed = false; - _needUpdateStat = false; - - if (_hashStream) - _hashStream->ReleaseStream(); - - GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream); - - if (!ProcessAltStreams && _isAltStream) - return S_OK; - - _filePath = name; - _isFolder = IntToBool(isDir); - _curSize = 0; - _curSize_Defined = false; - - UInt64 size = 0; - bool sizeDefined; - { - NCOM::CPropVariant prop; - RINOK(getProp->GetProp(kpidSize, &prop)) - sizeDefined = ConvertPropVariantToUInt64(prop, size); - } - - if (sizeDefined) - { - _curSize = size; - _curSize_Defined = true; - } - - if (askExtractMode != NArchive::NExtract::NAskMode::kExtract && - askExtractMode != NArchive::NExtract::NAskMode::kTest) - return S_OK; - - _needUpdateStat = true; - - CMyComPtr outStreamLoc; - - if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract) - { - CVirtFile &file = VirtFileSystemSpec->AddNewFile(); - _newVirtFileWasAdded = true; - file.Name = name; - file.IsDir = IntToBool(isDir); - file.IsAltStream = _isAltStream; - file.Size = 0; - - RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined)) - RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined)) - RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined)) - - NCOM::CPropVariant prop; - RINOK(getProp->GetProp(kpidAttrib, &prop)) - if (prop.vt == VT_UI4) - { - file.Attrib = prop.ulVal; - file.AttribDefined = true; - } - // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY; - - file.ExpectedSize = 0; - if (sizeDefined) - file.ExpectedSize = size; - outStreamLoc = VirtFileSystem; - } - - if (_hashStream) - { - { - _hashStream->SetStream(outStreamLoc); - outStreamLoc = _hashStream; - _hashStream->Init(true); - _hashStream_WasUsed = true; - } - } - - if (outStreamLoc) - *outStream = outStreamLoc.Detach(); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)) -{ - COM_TRY_BEGIN - _needUpdateStat = ( - askExtractMode == NArchive::NExtract::NAskMode::kExtract - || askExtractMode == NArchive::NExtract::NAskMode::kTest - || askExtractMode == NArchive::NExtract::NAskMode::kReadExternal - ); - - /* - _extractMode = false; - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: - if (_testMode) - askExtractMode = NArchive::NExtract::NAskMode::kTest; - else - _extractMode = true; - break; - }; - */ - return SetCurrentFilePath2(_filePath); - COM_TRY_END -} - -Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult8(Int32 opRes, Int32 encrypted, UInt64 size)) -{ - COM_TRY_BEGIN - if (VirtFileSystem && _newVirtFileWasAdded) - { - // FIXME: probably we must request file size from VirtFileSystem - // _curSize = VirtFileSystem->GetLastFileSize() - // _curSize_Defined = true; - RINOK(VirtFileSystemSpec->CloseMemFile()) - } - if (_hashStream && _hashStream_WasUsed) - { - _hashStream->_hash->Final(_isFolder, _isAltStream, _filePath); - _curSize = _hashStream->GetSize(); - _curSize_Defined = true; - _hashStream->ReleaseStream(); - _hashStream_WasUsed = false; - } - else if (_hashCalc && _needUpdateStat) - { - _hashCalc->SetSize(size); // (_curSize) before 21.04 - _hashCalc->Final(_isFolder, _isAltStream, _filePath); - } - return SetOperationResult(opRes, encrypted); - COM_TRY_END -} - - -Z7_COM7F_IMF(CExtractCallbackImp::RequestMemoryUse( - UInt32 flags, UInt32 indexType, UInt32 /* index */, const wchar_t *path, - UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) -{ - UInt32 limit_GB = (UInt32)((*allowedSize + ((1u << 30) - 1)) >> 30); - - if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) - { - UInt64 limit_bytes = *allowedSize; - const UInt32 limit_GB_Registry = NExtract::Read_LimitGB(); - if (limit_GB_Registry != 0 && limit_GB_Registry != (UInt32)(Int32)-1) - { - const UInt64 limit_bytes_Registry = (UInt64)limit_GB_Registry << 30; - // registry_WasForced = true; - if ((flags & NRequestMemoryUseFlags::k_AllowedSize_WasForced) == 0 - || limit_bytes < limit_bytes_Registry) - { - limit_bytes = limit_bytes_Registry; - limit_GB = limit_GB_Registry; - } - } - *allowedSize = limit_bytes; - if (requiredSize <= limit_bytes) - { - *answerFlags = NRequestMemoryAnswerFlags::k_Allow; - return S_OK; - } - // default answer can be k_Allow, if limit was not forced, - // so we change answer to non-allowed here, - // because user has chance to change limit in GUI. - *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded; - if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) - *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc; - } - - const UInt32 required_GB = (UInt32)((requiredSize + ((1u << 30) - 1)) >> 30); - - CMemDialog dialog; - dialog.Limit_GB = limit_GB; - dialog.Required_GB = required_GB; - dialog.TestMode = TestMode; - if (MultiArcMode) - dialog.ArcPath = _currentArchivePath; - if (path) - dialog.FilePath = path; - - if (!g_DisableUserQuestions - && (flags & NRequestMemoryUseFlags::k_IsReport) == 0) - { - if (_remember) - dialog.SkipArc = _skipArc; - else - { - dialog.ShowRemember = - (MultiArcMode - || indexType != NArchive::NEventIndexType::kNoIndex - || path); - ProgressDialog->WaitCreating(); - if (dialog.Create(*ProgressDialog) != IDCONTINUE) - { - *answerFlags = NRequestMemoryAnswerFlags::k_Stop; - return E_ABORT; - } - if (dialog.NeedSave) - NExtract::Save_LimitGB(dialog.Limit_GB); - if (dialog.Remember) - { - _remember = true; - _skipArc = dialog.SkipArc; - } - } - - *allowedSize = (UInt64)dialog.Limit_GB << 30; - if (!dialog.SkipArc) - { - *answerFlags = NRequestMemoryAnswerFlags::k_Allow; - return S_OK; - } - *answerFlags = - NRequestMemoryAnswerFlags::k_SkipArc - | NRequestMemoryAnswerFlags::k_Limit_Exceeded; - flags |= NRequestMemoryUseFlags::k_Report_SkipArc; - } - - if ((flags & NRequestMemoryUseFlags::k_NoErrorMessage) == 0) - { - UString s ("ERROR: "); - dialog.AddInfoMessage_To_String(s); - s.Add_LF(); - // if (indexType == NArchive::NEventIndexType::kNoIndex) - if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) || - (flags & NRequestMemoryUseFlags::k_Report_SkipArc)) - s += LangString(IDS_MSG_ARC_UNPACKING_WAS_SKIPPED); -/* - else - s += LangString(IDS_MSG_ARC_FILES_UNPACKING_WAS_SKIPPED); -*/ - AddError_Message_ShowArcPath(s); - } - -/* - if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) - *answerFlags |= NRequestMemoryAnswerFlags::k_Limit_Exceeded; -*/ - return S_OK; -} - - - -// static const UInt32 kBlockSize = ((UInt32)1 << 31); - -Z7_COM7F_IMF(CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)) -{ - if (processedSize) - *processedSize = 0; - if (size == 0) - return S_OK; - if (!_fileMode) - { - CVirtFile &file = Files.Back(); - size_t rem = file.Data.Size() - (size_t)file.Size; - bool useMem = true; - if (rem < size) - { - UInt64 b = 0; - if (file.Data.Size() == 0) - b = file.ExpectedSize; - UInt64 a = file.Size + size; - if (b < a) - b = a; - a = (UInt64)file.Data.Size() * 2; - if (b < a) - b = a; - useMem = false; - const size_t b_sizet = (size_t)b; - if (b == b_sizet && b <= MaxTotalAllocSize) - useMem = file.Data.ReAlloc_KeepData(b_sizet, (size_t)file.Size); - } - if (useMem) - { - memcpy(file.Data + file.Size, data, size); - file.Size += size; - if (processedSize) - *processedSize = (UInt32)size; - return S_OK; - } - _fileMode = true; - } - RINOK(FlushToDisk(false)) - return _outFileStream.Interface()->Write(data, size, processedSize); -} - - -HRESULT CVirtFileSystem::FlushToDisk(bool closeLast) -{ - _outFileStream.Create_if_Empty(); - while (_numFlushed < Files.Size()) - { - const CVirtFile &file = Files[_numFlushed]; - const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name)); - if (!_fileIsOpen) - { - if (!_outFileStream->Create_NEW(path)) - { - // do we need to release stream here? - // _outFileStream.Release(); - return E_FAIL; - // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath)); - } - _fileIsOpen = true; - RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size)) - } - if (_numFlushed == Files.Size() - 1 && !closeLast) - break; - if (file.CTimeDefined || - file.ATimeDefined || - file.MTimeDefined) - _outFileStream->SetTime( - file.CTimeDefined ? &file.CTime : NULL, - file.ATimeDefined ? &file.ATime : NULL, - file.MTimeDefined ? &file.MTime : NULL); - _outFileStream->Close(); - _numFlushed++; - _fileIsOpen = false; - - if (ZoneBuf.Size() != 0) - WriteZoneFile_To_BaseFile(path, ZoneBuf); - - if (file.AttribDefined) - NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib); - } - return S_OK; -} - -#endif +// ExtractCallback.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/Lang.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../Common/FilePathAutoRename.h" +#include "../../Common/StreamUtils.h" +#include "../Common/ExtractingFilePath.h" + +#ifndef Z7_SFX +#include "../Common/ZipRegistry.h" +#endif + +#include "../GUI/ExtractRes.h" +#include "resourceGui.h" + +#include "ExtractCallback.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "MemDialog.h" +#include "OverwriteDialog.h" +#ifndef Z7_NO_CRYPTO +#include "PasswordDialog.h" +#endif +#include "PropertyName.h" + +using namespace NWindows; +using namespace NFile; +using namespace NFind; + +extern bool g_DisableUserQuestions; + +CExtractCallbackImp::~CExtractCallbackImp() {} + +void CExtractCallbackImp::Init() +{ + LangString(IDS_PROGRESS_EXTRACTING, _lang_Extracting); + LangString(IDS_PROGRESS_TESTING, _lang_Testing); + LangString(IDS_PROGRESS_SKIPPING, _lang_Skipping); + _lang_Reading = "Reading"; + + NumArchiveErrors = 0; + ThereAreMessageErrors = false; + #ifndef Z7_SFX + NumFolders = NumFiles = 0; + NeedAddFile = false; + #endif +} + +void CExtractCallbackImp::AddError_Message(LPCWSTR s) +{ + ThereAreMessageErrors = true; + ProgressDialog->Sync.AddError_Message(s); +} + +void CExtractCallbackImp::AddError_Message_ShowArcPath(LPCWSTR s) +{ + Add_ArchiveName_Error(); + AddError_Message(s); +} + + +#ifndef Z7_SFX + +Z7_COM7F_IMF(CExtractCallbackImp::SetNumFiles(UInt64 numFiles)) +{ + #ifdef Z7_SFX + UNUSED_VAR(numFiles) + #else + ProgressDialog->Sync.Set_NumFilesTotal(numFiles); + #endif + return S_OK; +} + +#endif + +Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 total)) +{ + ProgressDialog->Sync.Set_NumBytesTotal(total); + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *value)) +{ + return ProgressDialog->Sync.Set_NumBytesCur(value); +} + +HRESULT CExtractCallbackImp::Open_CheckBreak() +{ + return ProgressDialog->Sync.CheckStop(); +} + +HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) +{ + HRESULT res = S_OK; + if (!MultiArcMode) + { + if (files) + { + _totalFiles_Defined = true; + // res = ProgressDialog->Sync.Set_NumFilesTotal(*files); + } + else + _totalFiles_Defined = false; + + if (bytes) + { + _totalBytes_Defined = true; + ProgressDialog->Sync.Set_NumBytesTotal(*bytes); + } + else + _totalBytes_Defined = false; + } + + return res; +} + +HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) +{ + if (!MultiArcMode) + { + if (files) + { + ProgressDialog->Sync.Set_NumFilesCur(*files); + } + + if (bytes) + { + } + } + + return ProgressDialog->Sync.CheckStop(); +} + +HRESULT CExtractCallbackImp::Open_Finished() +{ + return ProgressDialog->Sync.CheckStop(); +} + +#ifndef Z7_NO_CRYPTO + +HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password) +{ + return CryptoGetTextPassword(password); +} + +/* +HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) +{ + passwordIsDefined = PasswordIsDefined; + password = Password; + return S_OK; +} + +bool CExtractCallbackImp::Open_WasPasswordAsked() +{ + return PasswordWasAsked; +} + +void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag() +{ + PasswordWasAsked = false; +} +*/ + +#endif + + +#ifndef Z7_SFX +Z7_COM7F_IMF(CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + ProgressDialog->Sync.Set_Ratio(inSize, outSize); + return S_OK; +} +#endif + +/* +Z7_COM7F_IMF(CExtractCallbackImp::SetTotalFiles(UInt64 total) +{ + ProgressDialog->Sync.SetNumFilesTotal(total); + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetCompletedFiles(const UInt64 *value) +{ + if (value != NULL) + ProgressDialog->Sync.SetNumFilesCur(*value); + return S_OK; +} +*/ + +Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite( + const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, + const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, + Int32 *answer)) +{ + COverwriteDialog dialog; + + dialog.OldFileInfo.SetTime2(existTime); + dialog.OldFileInfo.SetSize2(existSize); + dialog.OldFileInfo.Path = existName; + dialog.OldFileInfo.Is_FileSystemFile = true; + + dialog.NewFileInfo.SetTime2(newTime); + dialog.NewFileInfo.SetSize2(newSize); + dialog.NewFileInfo.Path = newName; + dialog.NewFileInfo.Is_FileSystemFile = Src_Is_IO_FS_Folder; + + ProgressDialog->WaitCreating(); + const INT_PTR writeAnswer = dialog.Create(*ProgressDialog); + + switch (writeAnswer) + { + case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT; + case IDYES: *answer = NOverwriteAnswer::kYes; break; + case IDNO: *answer = NOverwriteAnswer::kNo; break; + case IDB_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break; + case IDB_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break; + case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break; + default: return E_FAIL; + } + return S_OK; +} + + +Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */)) +{ + _isFolder = IntToBool(isFolder); + _currentFilePath = name; + + const UString *msg = &_lang_Empty; + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break; + case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break; + case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break; + case NArchive::NExtract::NAskMode::kReadExternal: msg = &_lang_Reading; break; + // default: s = "Unknown operation"; + } + + return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder)); +} + +Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *s)) +{ + AddError_Message(s); + return S_OK; +} + +HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path) +{ + ThereAreMessageErrors = true; + ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path)); + return S_OK; +} + +#ifndef Z7_SFX + +Z7_COM7F_IMF(CExtractCallbackImp::ShowMessage(const wchar_t *s)) +{ + AddError_Message(s); + return S_OK; +} + +#endif + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s) +{ + s.Empty(); + + if (opRes == NArchive::NExtract::NOperationResult::kOK) + return; + + #ifndef Z7_SFX + UINT messageID = 0; + #endif + UINT id = 0; + + switch (opRes) + { + case NArchive::NExtract::NOperationResult::kUnsupportedMethod: + #ifndef Z7_SFX + messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD; + #endif + id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD; + break; + case NArchive::NExtract::NOperationResult::kDataError: + #ifndef Z7_SFX + messageID = encrypted ? + IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED: + IDS_EXTRACT_MESSAGE_DATA_ERROR; + #endif + id = IDS_EXTRACT_MSG_DATA_ERROR; + break; + case NArchive::NExtract::NOperationResult::kCRCError: + #ifndef Z7_SFX + messageID = encrypted ? + IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED: + IDS_EXTRACT_MESSAGE_CRC_ERROR; + #endif + id = IDS_EXTRACT_MSG_CRC_ERROR; + break; + case NArchive::NExtract::NOperationResult::kUnavailable: + id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA; + break; + case NArchive::NExtract::NOperationResult::kUnexpectedEnd: + id = IDS_EXTRACT_MSG_UEXPECTED_END; + break; + case NArchive::NExtract::NOperationResult::kDataAfterEnd: + id = IDS_EXTRACT_MSG_DATA_AFTER_END; + break; + case NArchive::NExtract::NOperationResult::kIsNotArc: + id = IDS_EXTRACT_MSG_IS_NOT_ARC; + break; + case NArchive::NExtract::NOperationResult::kHeadersError: + id = IDS_EXTRACT_MSG_HEADERS_ERROR; + break; + case NArchive::NExtract::NOperationResult::kWrongPassword: + id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM; + break; + /* + default: + messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR; + break; + */ + } + + UString msg; + + #ifndef Z7_SFX + UString msgOld; + #ifdef Z7_LANG + if (id != 0) + LangString_OnlyFromLangFile(id, msg); + if (messageID != 0 && msg.IsEmpty()) + LangString_OnlyFromLangFile(messageID, msgOld); + #endif + if (msg.IsEmpty() && !msgOld.IsEmpty()) + s = MyFormatNew(msgOld, fileName); + else + #endif + { + if (msg.IsEmpty() && id != 0) + LangString(id, msg); + if (!msg.IsEmpty()) + s += msg; + else + { + s += "Error #"; + s.Add_UInt32((UInt32)opRes); + } + + if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword) + { + // s += " : "; + // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED); + s += " : "; + AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); + } + s += " : "; + s += fileName; + } +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)) +{ + switch (opRes) + { + case NArchive::NExtract::NOperationResult::kOK: + break; + default: + { + UString s; + SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s); + AddError_Message_ShowArcPath(s); + } + } + + _currentFilePath.Empty(); + #ifndef Z7_SFX + if (_isFolder) + NumFolders++; + else + NumFiles++; + ProgressDialog->Sync.Set_NumFilesCur(NumFiles); + #endif + + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) +{ + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + UString s; + SetExtractErrorMessage(opRes, encrypted, name, s); + AddError_Message_ShowArcPath(s); + } + return S_OK; +} + +//////////////////////////////////////// +// IExtractCallbackUI + +HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */) +{ + _currentArchivePath = name; + _needWriteArchivePath = true; + #ifndef Z7_SFX + RINOK(ProgressDialog->Sync.CheckStop()) + ProgressDialog->Sync.Set_TitleFileName(name); + #endif + return S_OK; +} + +HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path) +{ + _currentFilePath = path; + #ifndef Z7_SFX + ProgressDialog->Sync.Set_FilePath(path); + #endif + return S_OK; +} + +#ifndef Z7_SFX + +Z7_COM7F_IMF(CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)) +{ + #ifndef Z7_SFX + if (NeedAddFile) + NumFiles++; + NeedAddFile = true; + ProgressDialog->Sync.Set_NumFilesCur(NumFiles); + #endif + return SetCurrentFilePath2(path); +} + +#endif + +UString HResultToMessage(HRESULT errorCode); + +static const UInt32 k_ErrorFlagsIds[] = +{ + IDS_EXTRACT_MSG_IS_NOT_ARC, + IDS_EXTRACT_MSG_HEADERS_ERROR, + IDS_EXTRACT_MSG_HEADERS_ERROR, + IDS_OPEN_MSG_UNAVAILABLE_START, + IDS_OPEN_MSG_UNCONFIRMED_START, + IDS_EXTRACT_MSG_UEXPECTED_END, + IDS_EXTRACT_MSG_DATA_AFTER_END, + IDS_EXTRACT_MSG_UNSUPPORTED_METHOD, + IDS_OPEN_MSG_UNSUPPORTED_FEATURE, + IDS_EXTRACT_MSG_DATA_ERROR, + IDS_EXTRACT_MSG_CRC_ERROR +}; + +static void AddNewLineString(UString &s, const UString &m) +{ + s += m; + s.Add_LF(); +} + +UString GetOpenArcErrorMessage(UInt32 errorFlags); +UString GetOpenArcErrorMessage(UInt32 errorFlags) +{ + UString s; + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsIds); i++) + { + const UInt32 f = (UInt32)1 << i; + if ((errorFlags & f) == 0) + continue; + const UInt32 id = k_ErrorFlagsIds[i]; + UString m = LangString(id); + if (m.IsEmpty()) + continue; + if (f == kpv_ErrorFlags_EncryptedHeadersError) + { + m += " : "; + AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); + } + if (!s.IsEmpty()) + s.Add_LF(); + s += m; + errorFlags &= ~f; + } + + if (errorFlags != 0) + { + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(errorFlags, sz + 2); + if (!s.IsEmpty()) + s.Add_LF(); + s += sz; + } + + return s; +} + +static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er) +{ + const UInt32 errorFlags = er.GetErrorFlags(); + const UInt32 warningFlags = er.GetWarningFlags(); + + if (errorFlags != 0) + AddNewLineString(s, GetOpenArcErrorMessage(errorFlags)); + + if (!er.ErrorMessage.IsEmpty()) + AddNewLineString(s, er.ErrorMessage); + + if (warningFlags != 0) + { + s += GetNameOfProperty(kpidWarningFlags, L"Warnings"); + s.Add_Colon(); + s.Add_LF(); + AddNewLineString(s, GetOpenArcErrorMessage(warningFlags)); + } + + if (!er.WarningMessage.IsEmpty()) + { + s += GetNameOfProperty(kpidWarning, L"Warning"); + s += ": "; + s += er.WarningMessage; + s.Add_LF(); + } +} + +static UString GetBracedType(const wchar_t *type) +{ + UString s ('['); + s += type; + s.Add_Char(']'); + return s; +} + +void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result); +void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) +{ + FOR_VECTOR (level, arcLink.Arcs) + { + const CArc &arc = arcLink.Arcs[level]; + const CArcErrorInfo &er = arc.ErrorInfo; + + if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0) + continue; + + if (s.IsEmpty()) + { + s += name; + s.Add_LF(); + } + + if (level != 0) + { + AddNewLineString(s, arc.Path); + } + + ErrorInfo_Print(s, er); + + if (er.ErrorFormatIndex >= 0) + { + AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning")); + if (arc.FormatIndex == er.ErrorFormatIndex) + { + AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET)); + } + else + { + AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex)))); + AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex)))); + } + } + } + + if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK) + { + s += name; + s.Add_LF(); + if (!arcLink.Arcs.IsEmpty()) + AddNewLineString(s, arcLink.NonOpen_ArcPath); + + if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE) + { + UINT id = IDS_CANT_OPEN_ARCHIVE; + UString param; + if (arcLink.PasswordWasAsked) + id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE; + else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + { + id = IDS_CANT_OPEN_AS_TYPE; + param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex)); + } + UString s2 = MyFormatNew(id, param); + s2.Replace(L" ''", L""); + s2.Replace(L"''", L""); + s += s2; + } + else + s += HResultToMessage(result); + + s.Add_LF(); + ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo); + } + + if (!s.IsEmpty() && s.Back() == '\n') + s.DeleteBack(); +} + +HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) +{ + _currentArchivePath = name; + _needWriteArchivePath = true; + + UString s; + OpenResult_GUI(s, codecs, arcLink, name, result); + if (!s.IsEmpty()) + { + NumArchiveErrors++; + AddError_Message(s); + _needWriteArchivePath = false; + } + + return S_OK; +} + +HRESULT CExtractCallbackImp::ThereAreNoFiles() +{ + return S_OK; +} + +void CExtractCallbackImp::Add_ArchiveName_Error() +{ + if (_needWriteArchivePath) + { + if (!_currentArchivePath.IsEmpty()) + AddError_Message(_currentArchivePath); + _needWriteArchivePath = false; + } +} + +HRESULT CExtractCallbackImp::ExtractResult(HRESULT result) +{ + #ifndef Z7_SFX + ProgressDialog->Sync.Set_FilePath(L""); + #endif + + if (result == S_OK) + return result; + NumArchiveErrors++; + if (result == E_ABORT + || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL) + ) + return result; + + Add_ArchiveName_Error(); + if (!_currentFilePath.IsEmpty()) + MessageError(_currentFilePath); + MessageError(NError::MyFormatMessage(result)); + return S_OK; +} + +#ifndef Z7_NO_CRYPTO + +HRESULT CExtractCallbackImp::SetPassword(const UString &password) +{ + PasswordIsDefined = true; + Password = password; + return S_OK; +} + +Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)) +{ + PasswordWasAsked = true; + if (!PasswordIsDefined) + { + CPasswordDialog dialog; + #ifndef Z7_SFX + const bool showPassword = NExtract::Read_ShowPassword(); + dialog.ShowPassword = showPassword; + #endif + ProgressDialog->WaitCreating(); + if (dialog.Create(*ProgressDialog) != IDOK) + return E_ABORT; + Password = dialog.Password; + PasswordIsDefined = true; + #ifndef Z7_SFX + if (dialog.ShowPassword != showPassword) + NExtract::Save_ShowPassword(dialog.ShowPassword); + #endif + } + return StringToBstr(Password, password); +} + +#endif + +#ifndef Z7_SFX + +Z7_COM7F_IMF(CExtractCallbackImp::AskWrite( + const wchar_t *srcPath, Int32 srcIsFolder, + const FILETIME *srcTime, const UInt64 *srcSize, + const wchar_t *destPath, + BSTR *destPathResult, + Int32 *writeAnswer)) +{ + UString destPathResultTemp = destPath; + + // RINOK(StringToBstr(destPath, destPathResult)); + + *destPathResult = NULL; + *writeAnswer = BoolToInt(false); + + FString destPathSys = us2fs(destPath); + const bool srcIsFolderSpec = IntToBool(srcIsFolder); + CFileInfo destFileInfo; + + if (destFileInfo.Find(destPathSys)) + { + if (srcIsFolderSpec) + { + if (!destFileInfo.IsDir()) + { + RINOK(MessageError("Cannot replace file with folder with same name", destPathSys)) + return E_ABORT; + } + *writeAnswer = BoolToInt(false); + return S_OK; + } + + if (destFileInfo.IsDir()) + { + RINOK(MessageError("Cannot replace folder with file with same name", destPathSys)) + *writeAnswer = BoolToInt(false); + return S_OK; + } + + switch ((int)OverwriteMode) + { + case NExtract::NOverwriteMode::kSkip: + return S_OK; + case NExtract::NOverwriteMode::kAsk: + { + Int32 overwriteResult; + UString destPathSpec = destPath; + const int slashPos = destPathSpec.ReverseFind_PathSepar(); + destPathSpec.DeleteFrom((unsigned)(slashPos + 1)); + destPathSpec += fs2us(destFileInfo.Name); + + RINOK(AskOverwrite( + destPathSpec, + &destFileInfo.MTime, &destFileInfo.Size, + srcPath, + srcTime, srcSize, + &overwriteResult)) + + switch (overwriteResult) + { + case NOverwriteAnswer::kCancel: return E_ABORT; + case NOverwriteAnswer::kNo: return S_OK; + case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; + case NOverwriteAnswer::kYes: break; + case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break; + case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break; + default: + return E_FAIL; + } + break; + } + default: + break; + } + + if (OverwriteMode == NExtract::NOverwriteMode::kRename) + { + if (!AutoRenamePath(destPathSys)) + { + RINOK(MessageError("Cannot create name for file", destPathSys)) + return E_ABORT; + } + destPathResultTemp = fs2us(destPathSys); + } + else + { + if (NFind::DoesFileExist_Raw(destPathSys)) + if (!NDir::DeleteFileAlways(destPathSys)) + if (GetLastError() != ERROR_FILE_NOT_FOUND) + { + RINOK(MessageError("Cannot delete output file", destPathSys)) + return E_ABORT; + } + } + } + *writeAnswer = BoolToInt(true); + return StringToBstr(destPathResultTemp, destPathResult); +} + + +Z7_COM7F_IMF(CExtractCallbackImp::UseExtractToStream(Int32 *res)) +{ + *res = BoolToInt(StreamMode); + return S_OK; +} + +static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined) +{ + ftDefined = false; + NCOM::CPropVariant prop; + RINOK(getProp->GetProp(propID, &prop)) + if (prop.vt == VT_FILETIME) + { + ft = prop.filetime; + ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + + +static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result) +{ + NCOM::CPropVariant prop; + result = false; + RINOK(getProp->GetProp(propID, &prop)) + if (prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + + +Z7_COM7F_IMF(CExtractCallbackImp::GetStream7(const wchar_t *name, + Int32 isDir, + ISequentialOutStream **outStream, Int32 askExtractMode, + IGetProp *getProp)) +{ + COM_TRY_BEGIN + *outStream = NULL; + _newVirtFileWasAdded = false; + _hashStream_WasUsed = false; + _needUpdateStat = false; + _isFolder = IntToBool(isDir); + _curSize_Defined = false; + _curSize = 0; + + if (_hashStream) + _hashStream->ReleaseStream(); + + _filePath = name; + + UInt64 size = 0; + bool size_Defined; + { + NCOM::CPropVariant prop; + RINOK(getProp->GetProp(kpidSize, &prop)) + size_Defined = ConvertPropVariantToUInt64(prop, size); + } + if (size_Defined) + { + _curSize = size; + _curSize_Defined = true; + } + + GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream); + if (!ProcessAltStreams && _isAltStream) + return S_OK; + + if (isDir) // we don't support dir items extraction in this code + return S_OK; + + if (askExtractMode != NArchive::NExtract::NAskMode::kExtract && + askExtractMode != NArchive::NExtract::NAskMode::kTest) + return S_OK; + + _needUpdateStat = true; + + CMyComPtr outStreamLoc; + + if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract) + { + if (!VirtFileSystemSpec->Files.IsEmpty()) + VirtFileSystemSpec->MaxTotalAllocSize -= VirtFileSystemSpec->Files.Back().Data.Size(); + CVirtFile &file = VirtFileSystemSpec->Files.AddNew(); + _newVirtFileWasAdded = true; + // file.IsDir = _isFolder; + file.IsAltStream = _isAltStream; + file.WrittenSize = 0; + file.ExpectedSize = 0; + if (size_Defined) + file.ExpectedSize = size; + + if (VirtFileSystemSpec->Index_of_MainExtractedFile_in_Files < 0) + if (!file.IsAltStream || VirtFileSystemSpec->IsAltStreamFile) + VirtFileSystemSpec->Index_of_MainExtractedFile_in_Files = + (int)(VirtFileSystemSpec->Files.Size() - 1); + + /* if we open only AltStream, then (name) contains only name without "fileName:" prefix */ + file.BaseName = name; + + if (file.IsAltStream + && !VirtFileSystemSpec->IsAltStreamFile + && file.BaseName.IsPrefixedBy_NoCase(VirtFileSystemSpec->FileName)) + { + const unsigned colonPos = VirtFileSystemSpec->FileName.Len(); + if (file.BaseName[colonPos] == ':') + { + file.ColonWasUsed = true; + file.AltStreamName = name + (size_t)colonPos + 1; + file.BaseName.DeleteFrom(colonPos); + if (Is_ZoneId_StreamName(file.AltStreamName)) + { + if (VirtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files < 0) + VirtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files = + (int)(VirtFileSystemSpec->Files.Size() - 1); + } + } + } + RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTime_Defined)) + RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATime_Defined)) + RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTime_Defined)) + { + NCOM::CPropVariant prop; + RINOK(getProp->GetProp(kpidAttrib, &prop)) + if (prop.vt == VT_UI4) + { + file.Attrib = prop.ulVal; + file.Attrib_Defined = true; + } + } + outStreamLoc = VirtFileSystem; + } + + if (_hashStream) + { + _hashStream->SetStream(outStreamLoc); + outStreamLoc = _hashStream; + _hashStream->Init(true); + _hashStream_WasUsed = true; + } + + if (outStreamLoc) + *outStream = outStreamLoc.Detach(); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)) +{ + COM_TRY_BEGIN + _needUpdateStat = ( + askExtractMode == NArchive::NExtract::NAskMode::kExtract + || askExtractMode == NArchive::NExtract::NAskMode::kTest + || askExtractMode == NArchive::NExtract::NAskMode::kReadExternal + ); + + /* + _extractMode = false; + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: + if (_testMode) + askExtractMode = NArchive::NExtract::NAskMode::kTest; + else + _extractMode = true; + break; + }; + */ + return SetCurrentFilePath2(_filePath); + COM_TRY_END +} + +Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult8(Int32 opRes, Int32 encrypted, UInt64 size)) +{ + COM_TRY_BEGIN + if (VirtFileSystem && _newVirtFileWasAdded) + { + // FIXME: probably we must request file size from VirtFileSystem + // _curSize = VirtFileSystem->GetLastFileSize() + // _curSize_Defined = true; + RINOK(VirtFileSystemSpec->CloseMemFile()) + } + if (_hashStream && _hashStream_WasUsed) + { + _hashStream->_hash->Final(_isFolder, _isAltStream, _filePath); + _curSize = _hashStream->GetSize(); + _curSize_Defined = true; + _hashStream->ReleaseStream(); + _hashStream_WasUsed = false; + } + else if (_hashCalc && _needUpdateStat) + { + _hashCalc->SetSize(size); // (_curSize) before 21.04 + _hashCalc->Final(_isFolder, _isAltStream, _filePath); + } + return SetOperationResult(opRes, encrypted); + COM_TRY_END +} + + +Z7_COM7F_IMF(CExtractCallbackImp::RequestMemoryUse( + UInt32 flags, UInt32 indexType, UInt32 /* index */, const wchar_t *path, + UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) +{ + UInt32 limit_GB = (UInt32)((*allowedSize + ((1u << 30) - 1)) >> 30); + + if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) + { + UInt64 limit_bytes = *allowedSize; + const UInt32 limit_GB_Registry = NExtract::Read_LimitGB(); + if (limit_GB_Registry != 0 && limit_GB_Registry != (UInt32)(Int32)-1) + { + const UInt64 limit_bytes_Registry = (UInt64)limit_GB_Registry << 30; + // registry_WasForced = true; + if ((flags & NRequestMemoryUseFlags::k_AllowedSize_WasForced) == 0 + || limit_bytes < limit_bytes_Registry) + { + limit_bytes = limit_bytes_Registry; + limit_GB = limit_GB_Registry; + } + } + *allowedSize = limit_bytes; + if (requiredSize <= limit_bytes) + { + *answerFlags = NRequestMemoryAnswerFlags::k_Allow; + return S_OK; + } + // default answer can be k_Allow, if limit was not forced, + // so we change answer to non-allowed here, + // because user has chance to change limit in GUI. + *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded; + if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) + *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc; + } + + const UInt32 required_GB = (UInt32)((requiredSize + ((1u << 30) - 1)) >> 30); + + CMemDialog dialog; + dialog.Limit_GB = limit_GB; + dialog.Required_GB = required_GB; + dialog.TestMode = TestMode; + if (MultiArcMode) + dialog.ArcPath = _currentArchivePath; + if (path) + dialog.FilePath = path; + + if (!g_DisableUserQuestions + && (flags & NRequestMemoryUseFlags::k_IsReport) == 0) + { + if (_remember) + dialog.SkipArc = _skipArc; + else + { + dialog.ShowRemember = + (MultiArcMode + || indexType != NArchive::NEventIndexType::kNoIndex + || path); + ProgressDialog->WaitCreating(); + if (dialog.Create(*ProgressDialog) != IDCONTINUE) + { + *answerFlags = NRequestMemoryAnswerFlags::k_Stop; + return E_ABORT; + } + if (dialog.NeedSave) + NExtract::Save_LimitGB(dialog.Limit_GB); + if (dialog.Remember) + { + _remember = true; + _skipArc = dialog.SkipArc; + } + } + + *allowedSize = (UInt64)dialog.Limit_GB << 30; + if (!dialog.SkipArc) + { + *answerFlags = NRequestMemoryAnswerFlags::k_Allow; + return S_OK; + } + *answerFlags = + NRequestMemoryAnswerFlags::k_SkipArc + | NRequestMemoryAnswerFlags::k_Limit_Exceeded; + flags |= NRequestMemoryUseFlags::k_Report_SkipArc; + } + + if ((flags & NRequestMemoryUseFlags::k_NoErrorMessage) == 0) + { + UString s ("ERROR: "); + dialog.AddInfoMessage_To_String(s); + s.Add_LF(); + // if (indexType == NArchive::NEventIndexType::kNoIndex) + if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) || + (flags & NRequestMemoryUseFlags::k_Report_SkipArc)) + AddLangString(s, IDS_MSG_ARC_UNPACKING_WAS_SKIPPED); +/* + else + AddLangString(, IDS_MSG_ARC_FILES_UNPACKING_WAS_SKIPPED); +*/ + AddError_Message_ShowArcPath(s); + } + +/* + if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0) + *answerFlags |= NRequestMemoryAnswerFlags::k_Limit_Exceeded; +*/ + return S_OK; +} + + +Z7_COM7F_IMF(CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)) +{ + if (processedSize) + *processedSize = 0; + if (size == 0) + return S_OK; + if (!_wasSwitchedToFsMode) + { + CVirtFile &file = Files.Back(); + const size_t rem = file.Data.Size() - file.WrittenSize; + bool useMem = true; + if (rem < size) + { + UInt64 b = 0; + if (file.Data.Size() == 0) + b = file.ExpectedSize; + UInt64 a = (UInt64)file.WrittenSize + size; + if (b < a) + b = a; + a = (UInt64)file.Data.Size() * 2; + if (b < a) + b = a; + useMem = false; + if (b <= MaxTotalAllocSize) + useMem = file.Data.ReAlloc_KeepData((size_t)b, file.WrittenSize); + } + +#if 0 // 1 for debug : FLUSHING TO FS + useMem = false; +#endif + + if (useMem) + { + memcpy(file.Data + file.WrittenSize, data, size); + file.WrittenSize += size; + if (processedSize) + *processedSize = (UInt32)size; + return S_OK; + } + _wasSwitchedToFsMode = true; + } + + if (!_newVirtFileStream_IsReadyToWrite) // we check for _newVirtFileStream_IsReadyToWrite to optimize execution + { + RINOK(FlushToDisk(false)) + } + + if (_needWriteToRealFile) + return _outFileStream.Interface()->Write(data, size, processedSize); + if (processedSize) + *processedSize = size; + return S_OK; +} + + +HRESULT CVirtFileSystem::FlushToDisk(bool closeLast) +{ + while (_numFlushed < Files.Size()) + { + CVirtFile &file = Files[_numFlushed]; + const FString basePath = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.BaseName)); + FString path = basePath; + + if (file.ColonWasUsed) + { + if (ZoneBuf.Size() != 0 + && Is_ZoneId_StreamName(file.AltStreamName)) + { + // it's expected that + // CArchiveExtractCallback::GetStream() have excluded + // ZoneId alt stream from extraction already. + // But we exclude alt stream extraction here too. + _numFlushed++; + continue; + } + path.Add_Colon(); + path += us2fs(Get_Correct_FsFile_Name(file.AltStreamName)); + } + + if (!_newVirtFileStream_IsReadyToWrite) + { + if (file.ColonWasUsed) + { + NFind::CFileInfo parentFi; + if (parentFi.Find(basePath) + && parentFi.IsReadOnly()) + { + _altStream_NeedRestore_Attrib_bool = true; + _altStream_NeedRestore_AttribVal = parentFi.Attrib; + NDir::SetFileAttrib(basePath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY); + } + } + _outFileStream.Create_if_Empty(); + _needWriteToRealFile = _outFileStream->Create_NEW(path); + if (!_needWriteToRealFile) + { + if (!file.ColonWasUsed) + return GetLastError_noZero_HRESULT(); // it's main file and we can't ignore such error. + // (file.ColonWasUsed == true) + // So it's additional alt stream. + // And we ignore file creation error for additional alt stream. + // ShowErrorMessage(UString("Can't create file ") + fs2us(path)); + } + _newVirtFileStream_IsReadyToWrite = true; + // _openFilePath = path; + HRESULT hres = S_OK; + if (_needWriteToRealFile) + hres = WriteStream(_outFileStream, file.Data, file.WrittenSize); + // we free allocated memory buffer after data flushing: + file.WrittenSize = 0; + file.Data.Free(); + RINOK(hres) + } + + if (_numFlushed == Files.Size() - 1 && !closeLast) + break; + + if (_needWriteToRealFile) + { + if (file.CTime_Defined || + file.ATime_Defined || + file.MTime_Defined) + _outFileStream->SetTime( + file.CTime_Defined ? &file.CTime : NULL, + file.ATime_Defined ? &file.ATime : NULL, + file.MTime_Defined ? &file.MTime : NULL); + _outFileStream->Close(); + } + + _numFlushed++; + _newVirtFileStream_IsReadyToWrite = false; + + if (_needWriteToRealFile) + { + if (!file.ColonWasUsed + && ZoneBuf.Size() != 0) + WriteZoneFile_To_BaseFile(path, ZoneBuf); + if (file.Attrib_Defined) + NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib); + // _openFilePath.Empty(); + _needWriteToRealFile = false; + } + + if (_altStream_NeedRestore_Attrib_bool) + { + _altStream_NeedRestore_Attrib_bool = false; + NDir::SetFileAttrib(basePath, _altStream_NeedRestore_AttribVal); + } + } + return S_OK; +} + +#endif diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h index e037eac9f..8b4dcb394 100644 --- a/CPP/7zip/UI/FileManager/ExtractCallback.h +++ b/CPP/7zip/UI/FileManager/ExtractCallback.h @@ -1,331 +1,347 @@ -// ExtractCallback.h - -#ifndef ZIP7_INC_EXTRACT_CALLBACK_H -#define ZIP7_INC_EXTRACT_CALLBACK_H - -#include "../../../../C/Alloc.h" - -#include "../../../Common/MyCom.h" -#include "../../../Common/StringConvert.h" - -#ifndef Z7_SFX -#include "../Agent/IFolderArchive.h" -#endif - -#include "../Common/ArchiveExtractCallback.h" -#include "../Common/ArchiveOpenCallback.h" - -#ifndef Z7_NO_CRYPTO -#include "../../IPassword.h" -#endif - -#ifndef Z7_SFX -#include "IFolder.h" -#endif - -#include "ProgressDialog2.h" - -#ifdef Z7_LANG -// #include "LangUtils.h" -#endif - -#ifndef Z7_SFX - -class CGrowBuf -{ - Byte *_items; - size_t _size; - - Z7_CLASS_NO_COPY(CGrowBuf) - -public: - bool ReAlloc_KeepData(size_t newSize, size_t keepSize) - { - void *buf = MyAlloc(newSize); - if (!buf) - return false; - if (keepSize != 0) - memcpy(buf, _items, keepSize); - MyFree(_items); - _items = (Byte *)buf; - _size = newSize; - return true; - } - - CGrowBuf(): _items(NULL), _size(0) {} - ~CGrowBuf() { MyFree(_items); } - - operator Byte *() { return _items; } - operator const Byte *() const { return _items; } - size_t Size() const { return _size; } -}; - -struct CVirtFile -{ - CGrowBuf Data; - - UInt64 Size; // real size - UInt64 ExpectedSize; // the size from props request. 0 if unknown - - UString Name; - - bool CTimeDefined; - bool ATimeDefined; - bool MTimeDefined; - bool AttribDefined; - - bool IsDir; - bool IsAltStream; - - DWORD Attrib; - - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - - CVirtFile(): - CTimeDefined(false), - ATimeDefined(false), - MTimeDefined(false), - AttribDefined(false), - IsDir(false), - IsAltStream(false) {} -}; - - -Z7_CLASS_IMP_NOQIB_1( - CVirtFileSystem, - ISequentialOutStream -) - UInt64 _totalAllocSize; - - size_t _pos; - unsigned _numFlushed; - bool _fileIsOpen; - bool _fileMode; - CMyComPtr2 _outFileStream; -public: - CObjectVector Files; - UInt64 MaxTotalAllocSize; - FString DirPrefix; - CByteBuffer ZoneBuf; - - - CVirtFile &AddNewFile() - { - if (!Files.IsEmpty()) - { - MaxTotalAllocSize -= Files.Back().Data.Size(); - } - return Files.AddNew(); - } - HRESULT CloseMemFile() - { - if (_fileMode) - { - return FlushToDisk(true); - } - CVirtFile &file = Files.Back(); - if (file.Data.Size() != file.Size) - { - file.Data.ReAlloc_KeepData((size_t)file.Size, (size_t)file.Size); - } - return S_OK; - } - - bool IsStreamInMem() const - { - if (_fileMode) - return false; - if (Files.Size() < 1 || /* Files[0].IsAltStream || */ Files[0].IsDir) - return false; - return true; - } - - size_t GetMemStreamWrittenSize() const { return _pos; } - - CVirtFileSystem(): - MaxTotalAllocSize((UInt64)0 - 1) - {} - - void Init() - { - _totalAllocSize = 0; - _fileMode = false; - _pos = 0; - _numFlushed = 0; - _fileIsOpen = false; - } - - HRESULT CloseFile(const FString &path); - HRESULT FlushToDisk(bool closeLast); - size_t GetPos() const { return _pos; } -}; - -#endif - - - -class CExtractCallbackImp Z7_final: - public IFolderArchiveExtractCallback, - /* IExtractCallbackUI: - before v23.00 : it included IFolderArchiveExtractCallback - since v23.00 : it doesn't include IFolderArchiveExtractCallback - */ - public IExtractCallbackUI, // NON-COM interface since 23.00 - public IOpenCallbackUI, // NON-COM interface - public IFolderArchiveExtractCallback2, - #ifndef Z7_SFX - public IFolderOperationsExtractCallback, - public IFolderExtractToStreamCallback, - public ICompressProgressInfo, - public IArchiveRequestMemoryUseCallback, - #endif - #ifndef Z7_NO_CRYPTO - public ICryptoGetTextPassword, - #endif - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback) - Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2) - #ifndef Z7_SFX - Z7_COM_QI_ENTRY(IFolderOperationsExtractCallback) - Z7_COM_QI_ENTRY(IFolderExtractToStreamCallback) - Z7_COM_QI_ENTRY(ICompressProgressInfo) - Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback) - #endif - #ifndef Z7_NO_CRYPTO - Z7_COM_QI_ENTRY(ICryptoGetTextPassword) - #endif - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_IMP(IExtractCallbackUI) - Z7_IFACE_IMP(IOpenCallbackUI) - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback) - Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2) - #ifndef Z7_SFX - Z7_IFACE_COM7_IMP(IFolderOperationsExtractCallback) - Z7_IFACE_COM7_IMP(IFolderExtractToStreamCallback) - Z7_IFACE_COM7_IMP(ICompressProgressInfo) - Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) - #endif - #ifndef Z7_NO_CRYPTO - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - #endif - - bool _needWriteArchivePath; - bool _isFolder; - bool _totalFilesDefined; - bool _totalBytesDefined; -public: - bool MultiArcMode; - bool ProcessAltStreams; - bool StreamMode; - bool ThereAreMessageErrors; - bool Src_Is_IO_FS_Folder; - -#ifndef Z7_NO_CRYPTO - bool PasswordIsDefined; - bool PasswordWasAsked; -#endif - -private: -#ifndef Z7_SFX - bool _needUpdateStat; - bool _newVirtFileWasAdded; - bool _isAltStream; - // bool _extractMode; - // bool _testMode; - bool _hashStream_WasUsed; - bool _curSize_Defined; - bool NeedAddFile; - - bool _remember; - bool _skipArc; -#endif - - UString _currentArchivePath; - UString _currentFilePath; - UString _filePath; - -#ifndef Z7_SFX - UInt64 _curSize; - CMyComPtr2 _hashStream; - IHashCalc *_hashCalc; // it's for stat in Test operation -#endif - -public: - CProgressDialog *ProgressDialog; - -#ifndef Z7_SFX - CVirtFileSystem *VirtFileSystemSpec; - CMyComPtr VirtFileSystem; - UInt64 NumFolders; - UInt64 NumFiles; -#endif - - UInt32 NumArchiveErrors; - NExtract::NOverwriteMode::EEnum OverwriteMode; - - bool YesToAll; - bool TestMode; - -#ifndef Z7_NO_CRYPTO - UString Password; -#endif - - UString _lang_Extracting; - UString _lang_Testing; - UString _lang_Skipping; - UString _lang_Reading; - UString _lang_Empty; - - CExtractCallbackImp(): - _totalFilesDefined(false) - , _totalBytesDefined(false) - , MultiArcMode(false) - , ProcessAltStreams(true) - , StreamMode(false) - , ThereAreMessageErrors(false) - , Src_Is_IO_FS_Folder(false) -#ifndef Z7_NO_CRYPTO - , PasswordIsDefined(false) - , PasswordWasAsked(false) -#endif -#ifndef Z7_SFX - , _remember(false) - , _skipArc(false) - , _hashCalc(NULL) -#endif - , OverwriteMode(NExtract::NOverwriteMode::kAsk) - , YesToAll(false) - , TestMode(false) - {} - - ~CExtractCallbackImp(); - void Init(); - - HRESULT SetCurrentFilePath2(const wchar_t *filePath); - void AddError_Message(LPCWSTR message); - void AddError_Message_ShowArcPath(LPCWSTR message); - HRESULT MessageError(const char *message, const FString &path); - void Add_ArchiveName_Error(); - - #ifndef Z7_SFX - void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; } - - void SetHashMethods(IHashCalc *hash) - { - if (!hash) - return; - _hashStream.Create_if_Empty(); - _hashStream->_hash = hash; - } - #endif - - bool IsOK() const { return NumArchiveErrors == 0 && !ThereAreMessageErrors; } -}; - -#endif +// ExtractCallback.h + +#ifndef ZIP7_INC_EXTRACT_CALLBACK_H +#define ZIP7_INC_EXTRACT_CALLBACK_H + +#include "../../../../C/Alloc.h" + +#include "../../../Common/MyCom.h" +#include "../../../Common/StringConvert.h" + +#ifndef Z7_SFX +#include "../Agent/IFolderArchive.h" +#endif + +#include "../Common/ArchiveExtractCallback.h" +#include "../Common/ArchiveOpenCallback.h" + +#ifndef Z7_NO_CRYPTO +#include "../../IPassword.h" +#endif + +#ifndef Z7_SFX +#include "IFolder.h" +#endif + +#include "ProgressDialog2.h" + +#ifndef Z7_SFX + +class CGrowBuf +{ + Byte *_items; + size_t _size; + + Z7_CLASS_NO_COPY(CGrowBuf) + +public: + void Free() + { + MyFree(_items); + _items = NULL; + _size = 0; + } + + // newSize >= keepSize + bool ReAlloc_KeepData(size_t newSize, size_t keepSize) + { + void *buf = NULL; + if (newSize) + { + buf = MyAlloc(newSize); + if (!buf) + return false; + } + if (keepSize) + memcpy(buf, _items, keepSize); + MyFree(_items); + _items = (Byte *)buf; + _size = newSize; + return true; + } + + CGrowBuf(): _items(NULL), _size(0) {} + ~CGrowBuf() { MyFree(_items); } + + operator Byte *() { return _items; } + operator const Byte *() const { return _items; } + size_t Size() const { return _size; } +}; + + +struct CVirtFile +{ + CGrowBuf Data; + + UInt64 ExpectedSize; // size from props request. 0 if unknown + size_t WrittenSize; // size of written data in (Data) buffer + // use (WrittenSize) only if (CVirtFileSystem::_newVirtFileStream_IsReadyToWrite == false) + UString BaseName; // original name of file inside archive, + // It's not path. So any path separators + // should be treated as part of name (or as incorrect chars) + UString AltStreamName; + + bool CTime_Defined; + bool ATime_Defined; + bool MTime_Defined; + bool Attrib_Defined; + + // bool IsDir; + bool IsAltStream; + bool ColonWasUsed; + DWORD Attrib; + + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + + CVirtFile(): + CTime_Defined(false), + ATime_Defined(false), + MTime_Defined(false), + Attrib_Defined(false), + // IsDir(false), + IsAltStream(false), + ColonWasUsed(false) + {} +}; + + +/* + We use CVirtFileSystem only for single file extraction: + It supports the following cases and names: + - "fileName" : single file + - "fileName" item (main base file) and additional "fileName:altStream" items + - "altStream" : single item without "fileName:" prefix. + If file is flushed to disk, it uses Get_Correct_FsFile_Name(name). +*/ + +Z7_CLASS_IMP_NOQIB_1( + CVirtFileSystem, + ISequentialOutStream +) + unsigned _numFlushed; +public: + bool IsAltStreamFile; // in: + // = true, if extracting file is alt stream without "fileName:" prefix. + // = false, if extracting file is normal file, but additional + // alt streams "fileName:altStream" items are possible. +private: + bool _newVirtFileStream_IsReadyToWrite; // it can non real file (if can't open alt stream) + bool _needWriteToRealFile; // we need real writing to open file. + bool _wasSwitchedToFsMode; + bool _altStream_NeedRestore_Attrib_bool; + DWORD _altStream_NeedRestore_AttribVal; + + CMyComPtr2 _outFileStream; +public: + CObjectVector Files; + size_t MaxTotalAllocSize; // remain size, including Files.Back() + FString DirPrefix; // files will be flushed to this FS directory. + UString FileName; // name of file that will be extracted. + // it can be name of alt stream without "fileName:" prefix, if (IsAltStreamFile == trye). + // we use that name to detect altStream part in "FileName:altStream". + CByteBuffer ZoneBuf; + int Index_of_MainExtractedFile_in_Files; // out: index in Files. == -1, if expected file was not extracted + int Index_of_ZoneBuf_AltStream_in_Files; // out: index in Files. == -1, if no zonbuf alt stream + + + CVirtFileSystem() + { + _numFlushed = 0; + IsAltStreamFile = false; + _newVirtFileStream_IsReadyToWrite = false; + _needWriteToRealFile = false; + _wasSwitchedToFsMode = false; + _altStream_NeedRestore_Attrib_bool = false; + MaxTotalAllocSize = (size_t)0 - 1; + Index_of_MainExtractedFile_in_Files = -1; + Index_of_ZoneBuf_AltStream_in_Files = -1; + } + + bool WasStreamFlushedToFS() const { return _wasSwitchedToFsMode; } + + HRESULT CloseMemFile() + { + if (_wasSwitchedToFsMode) + return FlushToDisk(true); // closeLast + CVirtFile &file = Files.Back(); + if (file.Data.Size() != file.WrittenSize) + file.Data.ReAlloc_KeepData(file.WrittenSize, file.WrittenSize); + return S_OK; + } + + HRESULT FlushToDisk(bool closeLast); +}; + +#endif + + + +class CExtractCallbackImp Z7_final: + public IFolderArchiveExtractCallback, + /* IExtractCallbackUI: + before v23.00 : it included IFolderArchiveExtractCallback + since v23.00 : it doesn't include IFolderArchiveExtractCallback + */ + public IExtractCallbackUI, // NON-COM interface since 23.00 + public IOpenCallbackUI, // NON-COM interface + public IFolderArchiveExtractCallback2, + #ifndef Z7_SFX + public IFolderOperationsExtractCallback, + public IFolderExtractToStreamCallback, + public ICompressProgressInfo, + public IArchiveRequestMemoryUseCallback, + #endif + #ifndef Z7_NO_CRYPTO + public ICryptoGetTextPassword, + #endif + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback) + Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2) + #ifndef Z7_SFX + Z7_COM_QI_ENTRY(IFolderOperationsExtractCallback) + Z7_COM_QI_ENTRY(IFolderExtractToStreamCallback) + Z7_COM_QI_ENTRY(ICompressProgressInfo) + Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback) + #endif + #ifndef Z7_NO_CRYPTO + Z7_COM_QI_ENTRY(ICryptoGetTextPassword) + #endif + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_IMP(IExtractCallbackUI) + Z7_IFACE_IMP(IOpenCallbackUI) + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback) + Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2) + #ifndef Z7_SFX + Z7_IFACE_COM7_IMP(IFolderOperationsExtractCallback) + Z7_IFACE_COM7_IMP(IFolderExtractToStreamCallback) + Z7_IFACE_COM7_IMP(ICompressProgressInfo) + Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) + #endif + #ifndef Z7_NO_CRYPTO + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + #endif + + bool _needWriteArchivePath; + bool _isFolder; + bool _totalFiles_Defined; + bool _totalBytes_Defined; +public: + bool MultiArcMode; + bool ProcessAltStreams; + bool StreamMode; // set to true, if you want the callee to call GetStream7() + bool ThereAreMessageErrors; + bool Src_Is_IO_FS_Folder; + +#ifndef Z7_NO_CRYPTO + bool PasswordIsDefined; + bool PasswordWasAsked; +#endif + +private: +#ifndef Z7_SFX + bool _needUpdateStat; + bool _newVirtFileWasAdded; + bool _isAltStream; + // bool _extractMode; + // bool _testMode; + bool _hashStream_WasUsed; + bool _curSize_Defined; + bool NeedAddFile; + + bool _remember; + bool _skipArc; +#endif + +public: + bool YesToAll; + bool TestMode; + + UInt32 NumArchiveErrors; + NExtract::NOverwriteMode::EEnum OverwriteMode; + +private: + UString _currentArchivePath; + UString _currentFilePath; + UString _filePath; // virtual path than will be sent via IFolderExtractToStreamCallback + +#ifndef Z7_SFX + UInt64 _curSize; + CMyComPtr2 _hashStream; + IHashCalc *_hashCalc; // it's for stat in Test operation +#endif + +public: + CProgressDialog *ProgressDialog; + +#ifndef Z7_SFX + CVirtFileSystem *VirtFileSystemSpec; + CMyComPtr VirtFileSystem; + UInt64 NumFolders; + UInt64 NumFiles; +#endif + +#ifndef Z7_NO_CRYPTO + UString Password; +#endif + + UString _lang_Extracting; + UString _lang_Testing; + UString _lang_Skipping; + UString _lang_Reading; + UString _lang_Empty; + + CExtractCallbackImp(): + _totalFiles_Defined(false) + , _totalBytes_Defined(false) + , MultiArcMode(false) + , ProcessAltStreams(true) + , StreamMode(false) + , ThereAreMessageErrors(false) + , Src_Is_IO_FS_Folder(false) +#ifndef Z7_NO_CRYPTO + , PasswordIsDefined(false) + , PasswordWasAsked(false) +#endif +#ifndef Z7_SFX + , _remember(false) + , _skipArc(false) +#endif + , YesToAll(false) + , TestMode(false) + , OverwriteMode(NExtract::NOverwriteMode::kAsk) +#ifndef Z7_SFX + , _hashCalc(NULL) +#endif + {} + + ~CExtractCallbackImp(); + void Init(); + + HRESULT SetCurrentFilePath2(const wchar_t *filePath); + void AddError_Message(LPCWSTR message); + void AddError_Message_ShowArcPath(LPCWSTR message); + HRESULT MessageError(const char *message, const FString &path); + void Add_ArchiveName_Error(); + + #ifndef Z7_SFX + void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; } + + void SetHashMethods(IHashCalc *hash) + { + if (!hash) + return; + _hashStream.Create_if_Empty(); + _hashStream->_hash = hash; + } + #endif + + bool IsOK() const { return NumArchiveErrors == 0 && !ThereAreMessageErrors; } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/FM.cpp b/CPP/7zip/UI/FileManager/FM.cpp index ab4f98c9f..731080240 100644 --- a/CPP/7zip/UI/FileManager/FM.cpp +++ b/CPP/7zip/UI/FileManager/FM.cpp @@ -1,1214 +1,1223 @@ -// FM.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../../C/Compiler.h" -#include "../../../../C/Alloc.h" -#ifdef _WIN32 -#include "../../../../C/DllSecur.h" -#endif - -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/MemoryLock.h" -#include "../../../Windows/NtCheck.h" -#include "../../../Windows/System.h" - -#ifndef UNDER_CE -#include "../../../Windows/SecurityUtils.h" -#endif - -#include "../GUI/ExtractRes.h" - -#include "resource.h" - -#include "App.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "MyLoadMenu.h" -#include "Panel.h" -#include "RegistryUtils.h" -#include "StringUtils.h" -#include "ViewSettings.h" - -using namespace NWindows; -using namespace NFile; -using namespace NFind; - -// #define MAX_LOADSTRING 100 - -extern -bool g_DisableUserQuestions; -bool g_DisableUserQuestions; - -extern -bool g_RAM_Size_Defined; -bool g_RAM_Size_Defined; - -extern -bool g_LargePagesMode; -bool g_LargePagesMode = false; -// static bool g_OpenArchive = false; - -static bool g_Maximized = false; - -extern -UInt64 g_RAM_Size; -UInt64 g_RAM_Size; - -#ifdef _WIN32 -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance; -#endif - -HWND g_HWND; - -static UString g_MainPath; -static UString g_ArcFormat; - -// HRESULT LoadGlobalCodecs(); -void FreeGlobalCodecs(); - -#ifndef UNDER_CE - -#ifdef Z7_USE_DYN_ComCtl32Version -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -DWORD g_ComCtl32Version; - -static DWORD GetDllVersion(LPCTSTR dllName) -{ - DWORD dwVersion = 0; - const HMODULE hmodule = LoadLibrary(dllName); - if (hmodule) - { - const - DLLGETVERSIONPROC f_DllGetVersion = Z7_GET_PROC_ADDRESS( - DLLGETVERSIONPROC, hmodule, - "DllGetVersion"); - if (f_DllGetVersion) - { - DLLVERSIONINFO dvi; - ZeroMemory(&dvi, sizeof(dvi)); - dvi.cbSize = sizeof(dvi); - const HRESULT hr = f_DllGetVersion(&dvi); - if (SUCCEEDED(hr)) - dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); - } - FreeLibrary(hmodule); - } - return dwVersion; -} - -#endif -#endif - -bool g_IsSmallScreen = false; - -extern -bool g_LVN_ITEMACTIVATE_Support; -bool g_LVN_ITEMACTIVATE_Support = true; -// LVN_ITEMACTIVATE replaces both NM_DBLCLK & NM_RETURN -// Windows 2000 -// NT/98 + IE 3 (g_ComCtl32Version >= 4.70) - - -static const int kNumDefaultPanels = 1; -static const int kSplitterWidth = 4; -static const int kSplitterRateMax = 1 << 16; -static const int kPanelSizeMin = 120; - - -class CSplitterPos -{ - int _ratio; // 10000 is max - int _pos; - int _fullWidth; - void SetRatioFromPos(HWND hWnd) - { _ratio = (_pos + kSplitterWidth / 2) * kSplitterRateMax / - MyMax(GetWidth(hWnd), 1); } -public: - int GetPos() const - { return _pos; } - int GetWidth(HWND hWnd) const - { - RECT rect; - ::GetClientRect(hWnd, &rect); - return rect.right; - } - void SetRatio(HWND hWnd, int aRatio) - { - _ratio = aRatio; - SetPosFromRatio(hWnd); - } - void SetPosPure(HWND hWnd, int pos) - { - int posMax = GetWidth(hWnd) - kSplitterWidth; - if (posMax < kPanelSizeMin * 2) - pos = posMax / 2; - else - { - if (pos > posMax - kPanelSizeMin) - pos = posMax - kPanelSizeMin; - else if (pos < kPanelSizeMin) - pos = kPanelSizeMin; - } - _pos = pos; - } - void SetPos(HWND hWnd, int pos) - { - _fullWidth = GetWidth(hWnd); - SetPosPure(hWnd, pos); - SetRatioFromPos(hWnd); - } - void SetPosFromRatio(HWND hWnd) - { - int fullWidth = GetWidth(hWnd); - if (_fullWidth != fullWidth && fullWidth != 0) - { - _fullWidth = fullWidth; - SetPosPure(hWnd, GetWidth(hWnd) * _ratio / kSplitterRateMax - kSplitterWidth / 2); - } - } -}; - -static bool g_CanChangeSplitter = false; -static UInt32 g_SplitterPos = 0; -static CSplitterPos g_Splitter; -static bool g_PanelsInfoDefined = false; -static bool g_WindowWasCreated = false; - -static int g_StartCaptureMousePos; -static int g_StartCaptureSplitterPos; - -CApp g_App; - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); - -static const wchar_t * const kWindowClass = L"7-Zip::FM"; - -#ifdef UNDER_CE -#define WS_OVERLAPPEDWINDOW ( \ - WS_OVERLAPPED | \ - WS_CAPTION | \ - WS_SYSMENU | \ - WS_THICKFRAME | \ - WS_MINIMIZEBOX | \ - WS_MAXIMIZEBOX) -#endif - - -/* -typedef HRESULT (WINAPI *Func_SetWindowTheme)( - HWND hwnd, - LPCWSTR pszSubAppName, - LPCWSTR pszSubIdList -); - -typedef BOOL (WINAPI *Func_AllowDarkModeForWindow)( - HWND a_HWND, BOOL a_Allow); - -enum PreferredAppMode -{ - Default, - AllowDark, - ForceDark, - ForceLight, - Max -}; -// ordinal 135, in 1903 -typedef BOOL (WINAPI *Func_SetPreferredAppMode)(PreferredAppMode appMode); - -typedef HRESULT (WINAPI *Func_DwmSetWindowAttribute)( - HWND hwnd, - DWORD dwAttribute, - LPCVOID pvAttribute, - DWORD cbAttribute -); -*/ - -static BOOL InitInstance(int nCmdShow) -{ - CWindow wnd; - - // LoadString(hInstance, IDS_CLASS, windowClass, MAX_LOADSTRING); - - UString title ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); - - /* - //If it is already running, then focus on the window - hWnd = FindWindow(windowClass, title); - if (hWnd) - { - SetForegroundWindow ((HWND) (((DWORD)hWnd) | 0x01)); - return 0; - } - */ - - WNDCLASSW wc; - - // wc.style = CS_HREDRAW | CS_VREDRAW; - wc.style = 0; - wc.lpfnWndProc = (WNDPROC) WndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = g_hInstance; - wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); - - // wc.hCursor = LoadCursor (NULL, IDC_ARROW); - wc.hCursor = ::LoadCursor(NULL, IDC_SIZEWE); - // wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - - wc.lpszMenuName = - #ifdef UNDER_CE - 0 - #else - MAKEINTRESOURCEW(IDM_MENU) - #endif - ; - - wc.lpszClassName = kWindowClass; - - if (MyRegisterClass(&wc) == 0) - return FALSE; - - // RECT rect; - // GetClientRect(hWnd, &rect); - - DWORD style = WS_OVERLAPPEDWINDOW; - // DWORD style = 0; - - CWindowInfo info; - info.maximized = false; - int x, y, xSize, ySize; - x = y = xSize = ySize = CW_USEDEFAULT; - bool windowPosIsRead; - info.Read(windowPosIsRead, g_PanelsInfoDefined); - - if (windowPosIsRead) - { - x = info.rect.left; - y = info.rect.top; - - xSize = RECT_SIZE_X(info.rect); - ySize = RECT_SIZE_Y(info.rect); - } - - - if (g_PanelsInfoDefined) - { - g_SplitterPos = info.splitterPos; - if (info.numPanels < 1 || info.numPanels > 2) - info.numPanels = kNumDefaultPanels; - if (info.currentPanel >= 2) - info.currentPanel = 0; - } - else - { - info.numPanels = kNumDefaultPanels; - info.currentPanel = 0; - } - - g_App.NumPanels = info.numPanels; - g_App.LastFocusedPanel = info.currentPanel; - - if (!wnd.Create(kWindowClass, title, style, - x, y, xSize, ySize, NULL, NULL, g_hInstance, NULL)) - return FALSE; - - /* - // doesn't work - { - const HMODULE hmodule = LoadLibrary("UxTheme.dll"); - if (hmodule) - { - { - const - Func_AllowDarkModeForWindow f = Z7_GET_PROC_ADDRESS( - Func_AllowDarkModeForWindow, hmodule, - MAKEINTRESOURCEA(133)); - if (f) - { - BOOL res = f((HWND)wnd, TRUE); - res = res; - } - } - { - const - Func_SetPreferredAppMode f = Z7_GET_PROC_ADDRESS( - Func_SetPreferredAppMode, hmodule, - MAKEINTRESOURCEA(135)); - if (f) - { - f(ForceDark); - } - } - { - const - Func_SetWindowTheme f = Z7_GET_PROC_ADDRESS( - Func_SetWindowTheme, hmodule, - "SetWindowTheme"); - if (f) - { - // HRESULT hres = f((HWND)wnd, L"DarkMode_Explorer", NULL); - HRESULT hres = f((HWND)wnd, L"Explorer", NULL); - hres = hres; - } - } - FreeLibrary(hmodule); - } - } - { - const HMODULE hmodule = LoadLibrary("Dwmapi.dll"); - if (hmodule) - { - const - Func_DwmSetWindowAttribute f = Z7_GET_PROC_ADDRESS( - Func_DwmSetWindowAttribute, hmodule, - "DwmSetWindowAttribute"); - if (f) - { - #ifndef Z7_WIN_DWMWA_USE_IMMERSIVE_DARK_MODE - #define Z7_WIN_DWMWA_USE_IMMERSIVE_DARK_MODE 20 - #endif - BOOL value = TRUE; - f((HWND)wnd, Z7_WIN_DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); - } - FreeLibrary(hmodule); - } - } - */ - - if (nCmdShow == SW_SHOWNORMAL || - nCmdShow == SW_SHOW - #ifndef UNDER_CE - || nCmdShow == SW_SHOWDEFAULT - #endif - ) - { - if (info.maximized) - nCmdShow = SW_SHOWMAXIMIZED; - else - nCmdShow = SW_SHOWNORMAL; - } - - if (nCmdShow == SW_SHOWMAXIMIZED) - g_Maximized = true; - - #ifndef UNDER_CE - WINDOWPLACEMENT placement; - placement.length = sizeof(placement); - if (wnd.GetPlacement(&placement)) - { - if (windowPosIsRead) - placement.rcNormalPosition = info.rect; - placement.showCmd = (UINT)nCmdShow; - wnd.SetPlacement(&placement); - } - else - #endif - wnd.Show(nCmdShow); - - return TRUE; -} - -/* -static void GetCommands(const UString &aCommandLine, UString &aCommands) -{ - UString aProgramName; - aCommands.Empty(); - bool aQuoteMode = false; - for (int i = 0; i < aCommandLine.Length(); i++) - { - wchar_t aChar = aCommandLine[i]; - if (aChar == L'\"') - aQuoteMode = !aQuoteMode; - else if (aChar == L' ' && !aQuoteMode) - { - if (!aQuoteMode) - { - i++; - break; - } - } - else - aProgramName += aChar; - } - aCommands = aCommandLine.Ptr(i); -} -*/ - -#if defined(_WIN32) && !defined(_WIN64) && !defined(UNDER_CE) - -extern -bool g_Is_Wow64; -bool g_Is_Wow64; - -typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); - -static void Set_Wow64() -{ - g_Is_Wow64 = false; - const - Func_IsWow64Process fn = Z7_GET_PROC_ADDRESS( - Func_IsWow64Process, GetModuleHandleA("kernel32.dll"), - "IsWow64Process"); - if (fn) - { - BOOL isWow; - if (fn(GetCurrentProcess(), &isWow)) - g_Is_Wow64 = (isWow != FALSE); - } -} - -#endif - -#if _MSC_VER > 1400 /* && _MSC_VER <= 1900 */ - // GetVersion was declared deprecated - #pragma warning(disable : 4996) -#endif -#ifdef __clang__ - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -bool IsLargePageSupported(); -bool IsLargePageSupported() -{ - #ifdef _WIN64 - return true; - #else - - DWORD v = GetVersion(); - // low byte is major version: - // next byte is minor version: - v = ((v & 0xff) << 8) | ((v >> 8) & 0xFF); - return (v > 0x501); - // if ((Byte)v < 5) return false; - // if ((Byte)v > 5) return true; - // return ((Byte)(v >> 8) > 1); - /* large pages work in 5.1 (XP-32bit) if it's (g_Is_Wow64) mode; - but here we don't enable them in (XP-32bit). */ - #endif -} - -#ifndef UNDER_CE - -static void SetMemoryLock() -{ - if (!IsLargePageSupported()) - return; - // if (ReadLockMemoryAdd()) - NSecurity::AddLockMemoryPrivilege(); - - if (ReadLockMemoryEnable()) - if (NSecurity::Get_LargePages_RiskLevel() == 0) - { - // note: child processes can inherit that Privilege - g_LargePagesMode = NSecurity::EnablePrivilege_LockMemory(); - } -} - -extern -bool g_SymLink_Supported; -bool g_SymLink_Supported = false; - -static void Set_SymLink_Supported() -{ - // g_SymLink_Supported = false; - const DWORD v = GetVersion(); - // low byte is major version: - if ((Byte)v < 6) - return; - g_SymLink_Supported = true; - // if (g_SymLink_Supported) - { - NSecurity::EnablePrivilege_SymLink(); - } -} - -#endif - -/* -static const int kNumSwitches = 1; - -namespace NKey { -enum Enum -{ - kOpenArachive = 0 -}; - -} - -static const CSwitchForm kSwitchForms[kNumSwitches] = - { - { L"SOA", NSwitchType::kSimple, false }, - }; -*/ - -// int APIENTRY WinMain2(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */, int /* nCmdShow */); - -static void ErrorMessage(const wchar_t *s) -{ - MessageBoxW(NULL, s, L"7-Zip", MB_ICONERROR); -} - -static void ErrorMessage(const char *s) -{ - ErrorMessage(GetUnicodeString(s)); -} - - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return 1; -#endif - -static int WINAPI WinMain2(int nCmdShow) -{ - g_RAM_Size_Defined = NSystem::GetRamSize(g_RAM_Size); - - #ifdef _WIN32 - - /* - #ifndef _WIN64 - #ifndef UNDER_CE - { - HMODULE hMod = GetModuleHandle("Kernel32.dll"); - if (hMod) - { - typedef BOOL (WINAPI *PSETDEP)(DWORD); - #define MY_PROCESS_DEP_ENABLE 1 - PSETDEP procSet = (PSETDEP)GetProcAddress(hMod,"SetProcessDEPPolicy"); - if (procSet) - procSet(MY_PROCESS_DEP_ENABLE); - - typedef BOOL (WINAPI *HSI)(HANDLE, HEAP_INFORMATION_CLASS ,PVOID, SIZE_T); - HSI hsi = (HSI)GetProcAddress(hMod, "HeapSetInformation"); - #define MY_HeapEnableTerminationOnCorruption ((HEAP_INFORMATION_CLASS)1) - if (hsi) - hsi(NULL, MY_HeapEnableTerminationOnCorruption, NULL, 0); - } - } - #endif - #endif - */ - - NT_CHECK - #ifdef Z7_LARGE_PAGES - SetLargePageSize(); - #endif - - #endif - - #ifdef Z7_LANG - LoadLangOneTime(); - #endif - - InitCommonControls(); - -#ifdef Z7_USE_DYN_ComCtl32Version - g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); - g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); -#endif - - #if defined(_WIN32) && !defined(_WIN64) && !defined(UNDER_CE) - Set_Wow64(); - #endif - - - g_IsSmallScreen = !NWindows::NControl::IsDialogSizeOK(200, 200); - - // OleInitialize is required for drag and drop. - #ifndef UNDER_CE - OleInitialize(NULL); - #endif - // Maybe needs CoInitializeEx also ? - // NCOM::CComInitializer comInitializer; - - UString commandsString; - // MessageBoxW(NULL, GetCommandLineW(), L"", 0); - - #ifdef UNDER_CE - commandsString = GetCommandLineW(); - #else - UString programString; - SplitStringToTwoStrings(GetCommandLineW(), programString, commandsString); - #endif - - commandsString.Trim(); - UString paramString, tailString; - SplitStringToTwoStrings(commandsString, paramString, tailString); - paramString.Trim(); - tailString.Trim(); - if (tailString.IsPrefixedBy(L"-t")) - g_ArcFormat = tailString.Ptr(2); - - /* - UStringVector switches; - for (;;) - { - if (tailString.IsEmpty()) - break; - UString s1, s2; - SplitStringToTwoStrings(tailString, s1, s2); - if (s2.IsEmpty()) - { - tailString.Trim(); - switches.Add(tailString); - break; - } - s1.Trim(); - switches.Add(s1); - tailString = s2; - } - - FOR_VECTOR(i, switches) - { - const UString &sw = switches[i]; - if (sw.IsPrefixedBy(L"-t")) - g_ArcFormat = sw.Ptr(2); - // - else if (sw.IsPrefixedBy(L"-stp")) - { - const wchar_t *end; - UInt32 val = ConvertStringToUInt32(sw.Ptr(4), &end); - if (*end != 0) - throw 111; - g_TypeParseLevel = val; - } - else - // - throw 112; - } - */ - - if (!paramString.IsEmpty()) - { - g_MainPath = paramString; - // return WinMain2(hInstance, hPrevInstance, lpCmdLine, nCmdShow); - - // MessageBoxW(NULL, paramString, L"", 0); - } - /* - UStringVector commandStrings; - NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); - NCommandLineParser::CParser parser(kNumSwitches); - try - { - parser.ParseStrings(kSwitchForms, commandStrings); - const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; - if (nonSwitchStrings.Size() > 1) - { - g_MainPath = nonSwitchStrings[1]; - // g_OpenArchive = parser[NKey::kOpenArachive].ThereIs; - CFileInfoW fileInfo; - if (FindFile(g_MainPath, fileInfo)) - { - if (!fileInfo.IsDir()) - g_OpenArchive = true; - } - } - } - catch(...) { } - */ - - - #if defined(_WIN32) && !defined(UNDER_CE) - SetMemoryLock(); - Set_SymLink_Supported(); - #endif - - g_App.ReloadLangItems(); - - MSG msg; - if (!InitInstance (nCmdShow)) - return FALSE; - - // we will load Global_Codecs at first use instead. - /* - OutputDebugStringW(L"Before LoadGlobalCodecs"); - LoadGlobalCodecs(); - OutputDebugStringW(L"After LoadGlobalCodecs"); - */ - - #ifndef _UNICODE - if (g_IsNT) - { - HACCEL hAccels = LoadAcceleratorsW(g_hInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR1)); - while (GetMessageW(&msg, NULL, 0, 0)) - { - if (TranslateAcceleratorW(g_HWND, hAccels, &msg) == 0) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - } - else - #endif - { - HACCEL hAccels = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); - while (GetMessage(&msg, NULL, 0, 0)) - { - if (TranslateAccelerator(g_HWND, hAccels, &msg) == 0) - { - // if (g_Hwnd != NULL || !IsDialogMessage(g_Hwnd, &msg)) - // if (!IsDialogMessage(g_Hwnd, &msg)) - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - - // Destructor of g_CodecsReleaser can release DLLs. - // But we suppose that it's better to release DLLs here (before destructor). - FreeGlobalCodecs(); - - g_HWND = NULL; - #ifndef UNDER_CE - OleUninitialize(); - #endif - return (int)msg.wParam; -} - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - /* lpCmdLine */, int nCmdShow) -{ - g_hInstance = hInstance; - - try - { - try - { - #ifdef _WIN32 - My_SetDefaultDllDirectories(); - #endif - return WinMain2(nCmdShow); - } - catch (...) - { - g_ExitEventLauncher.Exit(true); - throw; - } - } - catch(const CNewException &) - { - ErrorMessage(LangString(IDS_MEM_ERROR)); - return 1; - } - catch(const UString &s) - { - ErrorMessage(s); - return 1; - } - catch(const AString &s) - { - ErrorMessage(s.Ptr()); - return 1; - } - catch(const wchar_t *s) - { - ErrorMessage(s); - return 1; - } - catch(const char *s) - { - ErrorMessage(s); - return 1; - } - catch(int v) - { - AString e ("Error: "); - e.Add_UInt32((unsigned)v); - ErrorMessage(e); - return 1; - } - catch(...) - { - ErrorMessage("Unknown error"); - return 1; - } -} - -static void SaveWindowInfo(HWND aWnd) -{ - CWindowInfo info; - - #ifdef UNDER_CE - - if (!::GetWindowRect(aWnd, &info.rect)) - return; - info.maximized = g_Maximized; - - #else - - WINDOWPLACEMENT placement; - placement.length = sizeof(placement); - if (!::GetWindowPlacement(aWnd, &placement)) - return; - info.rect = placement.rcNormalPosition; - info.maximized = BOOLToBool(::IsZoomed(aWnd)); - - #endif - - info.numPanels = g_App.NumPanels; - info.currentPanel = g_App.LastFocusedPanel; - info.splitterPos = (unsigned)g_Splitter.GetPos(); - - info.Save(); -} - -static void ExecuteCommand(UINT commandID) -{ - CPanel::CDisableTimerProcessing disableTimerProcessing1(g_App.Panels[0]); - CPanel::CDisableTimerProcessing disableTimerProcessing2(g_App.Panels[1]); - - switch (commandID) - { - case kMenuCmdID_Toolbar_Add: g_App.AddToArchive(); break; - case kMenuCmdID_Toolbar_Extract: g_App.ExtractArchives(); break; - case kMenuCmdID_Toolbar_Test: g_App.TestArchives(); break; - } -} - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_COMMAND: - { - unsigned wmId = LOWORD(wParam); - unsigned wmEvent = HIWORD(wParam); - if ((HWND) lParam != NULL && wmEvent != 0) - break; - if (wmId >= kMenuCmdID_Toolbar_Start && wmId < kMenuCmdID_Toolbar_End) - { - ExecuteCommand(wmId); - return 0; - } - if (OnMenuCommand(hWnd, wmId)) - return 0; - break; - } - case WM_INITMENUPOPUP: - OnMenuActivating(hWnd, HMENU(wParam), LOWORD(lParam)); - break; - - /* - It doesn't help - case WM_EXITMENULOOP: - { - OnMenuUnActivating(hWnd); - break; - } - case WM_UNINITMENUPOPUP: - OnMenuUnActivating(hWnd, HMENU(wParam), lParam); - break; - */ - - case WM_CREATE: - { - g_HWND = hWnd; - /* - INITCOMMONCONTROLSEX icex; - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = ICC_BAR_CLASSES; - InitCommonControlsEx(&icex); - - // Toolbar buttons used to create the first 4 buttons. - TBBUTTON tbb [ ] = - { - // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, - // {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}, - // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, - {VIEW_NEWFOLDER, ID_FILE_CREATEFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}, - }; - - int baseID = 100; - NWindows::NControl::CToolBar aToolBar; - aToolBar.Attach(::CreateToolbarEx (hWnd, - WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS, // | TBSTYLE_FLAT - baseID + 2, 11, - (HINSTANCE)HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR, - (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb), - 0, 0, 100, 30, sizeof (TBBUTTON))); - */ - // HCURSOR cursor = ::LoadCursor(0, IDC_SIZEWE); - // ::SetCursor(cursor); - - if (g_PanelsInfoDefined) - g_Splitter.SetPos(hWnd, (int)g_SplitterPos); - else - { - g_Splitter.SetRatio(hWnd, kSplitterRateMax / 2); - g_SplitterPos = (unsigned)g_Splitter.GetPos(); - } - - RECT rect; - ::GetClientRect(hWnd, &rect); - const int xSize = rect.right; - int xSizes[2]; - xSizes[0] = g_Splitter.GetPos(); - xSizes[1] = xSize - kSplitterWidth - xSizes[0]; - if (xSizes[1] < 0) - xSizes[1] = 0; - - g_App.CreateDragTarget(); - - COpenResult openRes; - bool needOpenArc = false; - - UString fullPath = g_MainPath; - if (!fullPath.IsEmpty() /* && g_OpenArchive */) - { - if (!NFile::NName::IsAbsolutePath(fullPath)) - { - FString fullPathF; - if (NFile::NName::GetFullPath(us2fs(fullPath), fullPathF)) - fullPath = fs2us(fullPathF); - } - if (NFile::NFind::DoesFileExist_FollowLink(us2fs(fullPath))) - needOpenArc = true; - } - - HRESULT res = g_App.Create(hWnd, fullPath, g_ArcFormat, xSizes, - needOpenArc, - openRes); - - if (res == E_ABORT) - return -1; - - if ((needOpenArc && !openRes.ArchiveIsOpened) || res != S_OK) - { - UString m ("Error"); - if (res == S_FALSE || res == S_OK) - { - m = MyFormatNew(openRes.Encrypted ? - IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : - IDS_CANT_OPEN_ARCHIVE, - fullPath); - } - else if (res != S_OK) - m = HResultToMessage(res); - if (!openRes.ErrorMessage.IsEmpty()) - { - m.Add_LF(); - m += openRes.ErrorMessage; - } - ErrorMessage(m); - return -1; - } - - g_WindowWasCreated = true; - - // g_SplitterPos = 0; - - // ::DragAcceptFiles(hWnd, TRUE); - RegisterDragDrop(hWnd, g_App._dropTarget); - - break; - } - - case WM_DESTROY: - { - // ::DragAcceptFiles(hWnd, FALSE); - RevokeDragDrop(hWnd); - g_App._dropTarget.Release(); - - if (g_WindowWasCreated) - g_App.Save(); - - g_App.Release(); - - if (g_WindowWasCreated) - SaveWindowInfo(hWnd); - - g_ExitEventLauncher.Exit(true); - PostQuitMessage(0); - break; - } - - // case WM_MOVE: break; - - case WM_LBUTTONDOWN: - g_StartCaptureMousePos = LOWORD(lParam); - g_StartCaptureSplitterPos = g_Splitter.GetPos(); - ::SetCapture(hWnd); - break; - - case WM_LBUTTONUP: - { - ::ReleaseCapture(); - break; - } - - case WM_MOUSEMOVE: - { - if ((wParam & MK_LBUTTON) != 0 && ::GetCapture() == hWnd) - { - g_Splitter.SetPos(hWnd, g_StartCaptureSplitterPos + - (short)LOWORD(lParam) - g_StartCaptureMousePos); - g_App.MoveSubWindows(); - } - break; - } - - case WM_SIZE: - { - if (g_CanChangeSplitter) - g_Splitter.SetPosFromRatio(hWnd); - else - { - g_Splitter.SetPos(hWnd, (int)g_SplitterPos ); - g_CanChangeSplitter = true; - } - - g_Maximized = (wParam == SIZE_MAXIMIZED) || (wParam == SIZE_MAXSHOW); - - g_App.MoveSubWindows(); - /* - int xSize = LOWORD(lParam); - int ySize = HIWORD(lParam); - // int xSplitter = 2; - int xWidth = g_SplitPos; - // int xSplitPos = xWidth; - g_Panel[0]._listView.MoveWindow(0, 0, xWidth, ySize); - g_Panel[1]._listView.MoveWindow(xSize - xWidth, 0, xWidth, ySize); - */ - return 0; - // break; - } - - case WM_SETFOCUS: - // g_App.SetFocus(g_App.LastFocusedPanel); - g_App.SetFocusToLastItem(); - break; - - /* - case WM_ACTIVATE: - { - int fActive = LOWORD(wParam); - switch (fActive) - { - case WA_INACTIVE: - { - // g_FocusIndex = g_App.LastFocusedPanel; - // g_App.LastFocusedPanel = g_App.GetFocusedPanelIndex(); - // return 0; - } - } - break; - } - */ - - /* - case kLangWasChangedMessage: - MyLoadMenu(); - return 0; - */ - - /* - case WM_SETTINGCHANGE: - break; - */ - - case WM_NOTIFY: - { - g_App.OnNotify((int)wParam, (LPNMHDR)lParam); - break; - } - - /* - case WM_DROPFILES: - { - g_App.GetFocusedPanel().CompressDropFiles((HDROP)wParam); - return 0 ; - } - */ - } - #ifndef _UNICODE - if (g_IsNT) - return DefWindowProcW(hWnd, message, wParam, lParam); - else - #endif - return DefWindowProc(hWnd, message, wParam, lParam); - -} - -static int Window_GetRealHeight(NWindows::CWindow &w) -{ - RECT rect; - w.GetWindowRect(&rect); - int res = RECT_SIZE_Y(rect); - #ifndef UNDER_CE - WINDOWPLACEMENT placement; - if (w.GetPlacement(&placement)) - res += placement.rcNormalPosition.top; - #endif - return res; -} - -void CApp::MoveSubWindows() -{ - HWND hWnd = _window; - RECT rect; - if (!hWnd) - return; - ::GetClientRect(hWnd, &rect); - int xSize = rect.right; - if (xSize == 0) - return; - int headerSize = 0; - - #ifdef UNDER_CE - _commandBar.AutoSize(); - { - _commandBar.Show(true); // maybe we need it for - headerSize += _commandBar.Height(); - } - #endif - - if (_toolBar) - { - _toolBar.AutoSize(); - #ifdef UNDER_CE - int h2 = Window_GetRealHeight(_toolBar); - _toolBar.Move(0, headerSize, xSize, h2); - #endif - headerSize += Window_GetRealHeight(_toolBar); - } - - int ySize = MyMax((int)(rect.bottom - headerSize), 0); - - if (NumPanels > 1) - { - Panels[0].Move(0, headerSize, g_Splitter.GetPos(), ySize); - int xWidth1 = g_Splitter.GetPos() + kSplitterWidth; - Panels[1].Move(xWidth1, headerSize, xSize - xWidth1, ySize); - } - else - { - /* - int otherPanel = 1 - LastFocusedPanel; - if (PanelsCreated[otherPanel]) - Panels[otherPanel].Move(0, headerSize, 0, ySize); - */ - Panels[LastFocusedPanel].Move(0, headerSize, xSize, ySize); - } -} +// FM.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../../C/Compiler.h" +#include "../../../../C/Alloc.h" +#ifdef _WIN32 +#include "../../../../C/DllSecur.h" +#endif + +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/MemoryLock.h" +#include "../../../Windows/NtCheck.h" +#include "../../../Windows/System.h" + +#ifndef UNDER_CE +#include "../../../Windows/SecurityUtils.h" +#endif + +#include "../GUI/ExtractRes.h" + +#include "resource.h" + +#include "App.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "MyLoadMenu.h" +#include "Panel.h" +#include "RegistryUtils.h" +#include "StringUtils.h" +#include "ViewSettings.h" + +using namespace NWindows; +using namespace NFile; +using namespace NFind; + +// #define MAX_LOADSTRING 100 + +extern +bool g_DisableUserQuestions; +bool g_DisableUserQuestions; + +extern +bool g_RAM_Size_Defined; +bool g_RAM_Size_Defined; + +extern +bool g_LargePagesMode; +bool g_LargePagesMode = false; +// static bool g_OpenArchive = false; + +static bool g_Maximized = false; + +extern +size_t g_RAM_Size; +size_t g_RAM_Size; + +#ifdef _WIN32 +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance; +#endif + +HWND g_HWND; + +static UString g_MainPath; +static UString g_ArcFormat; + +// HRESULT LoadGlobalCodecs(); +void FreeGlobalCodecs(); + +#ifndef UNDER_CE + +#ifdef Z7_USE_DYN_ComCtl32Version +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +DWORD g_ComCtl32Version; + +static DWORD GetDllVersion(LPCTSTR dllName) +{ + DWORD dwVersion = 0; + const HMODULE hmodule = LoadLibrary(dllName); + if (hmodule) + { + const + DLLGETVERSIONPROC f_DllGetVersion = Z7_GET_PROC_ADDRESS( + DLLGETVERSIONPROC, hmodule, + "DllGetVersion"); + if (f_DllGetVersion) + { + DLLVERSIONINFO dvi; + ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + const HRESULT hr = f_DllGetVersion(&dvi); + if (SUCCEEDED(hr)) + dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); + } + FreeLibrary(hmodule); + } + return dwVersion; +} + +#endif +#endif + +bool g_IsSmallScreen = false; + +extern +bool g_LVN_ITEMACTIVATE_Support; +bool g_LVN_ITEMACTIVATE_Support = true; +// LVN_ITEMACTIVATE replaces both NM_DBLCLK & NM_RETURN +// Windows 2000 +// NT/98 + IE 3 (g_ComCtl32Version >= 4.70) + + +static const int kNumDefaultPanels = 1; +static const int kSplitterWidth = 4; +static const int kSplitterRateMax = 1 << 16; +static const int kPanelSizeMin = 120; + + +class CSplitterPos +{ + int _ratio; // 10000 is max + int _pos; + int _fullWidth; + void SetRatioFromPos(HWND hWnd) + { _ratio = (_pos + kSplitterWidth / 2) * kSplitterRateMax / + MyMax(GetWidth(hWnd), 1); } +public: + int GetPos() const + { return _pos; } + int GetWidth(HWND hWnd) const + { + RECT rect; + ::GetClientRect(hWnd, &rect); + return rect.right; + } + void SetRatio(HWND hWnd, int aRatio) + { + _ratio = aRatio; + SetPosFromRatio(hWnd); + } + void SetPosPure(HWND hWnd, int pos) + { + int posMax = GetWidth(hWnd) - kSplitterWidth; + if (posMax < kPanelSizeMin * 2) + pos = posMax / 2; + else + { + if (pos > posMax - kPanelSizeMin) + pos = posMax - kPanelSizeMin; + else if (pos < kPanelSizeMin) + pos = kPanelSizeMin; + } + _pos = pos; + } + void SetPos(HWND hWnd, int pos) + { + _fullWidth = GetWidth(hWnd); + SetPosPure(hWnd, pos); + SetRatioFromPos(hWnd); + } + void SetPosFromRatio(HWND hWnd) + { + int fullWidth = GetWidth(hWnd); + if (_fullWidth != fullWidth && fullWidth != 0) + { + _fullWidth = fullWidth; + SetPosPure(hWnd, GetWidth(hWnd) * _ratio / kSplitterRateMax - kSplitterWidth / 2); + } + } +}; + +static bool g_CanChangeSplitter = false; +static UInt32 g_SplitterPos = 0; +static CSplitterPos g_Splitter; +static bool g_PanelsInfoDefined = false; +static bool g_WindowWasCreated = false; + +static int g_StartCaptureMousePos; +static int g_StartCaptureSplitterPos; + +CApp g_App; + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +static const wchar_t * const kWindowClass = L"7-Zip::FM"; + +#ifdef UNDER_CE +#define WS_OVERLAPPEDWINDOW ( \ + WS_OVERLAPPED | \ + WS_CAPTION | \ + WS_SYSMENU | \ + WS_THICKFRAME | \ + WS_MINIMIZEBOX | \ + WS_MAXIMIZEBOX) +#endif + + +/* +typedef HRESULT (WINAPI *Func_SetWindowTheme)( + HWND hwnd, + LPCWSTR pszSubAppName, + LPCWSTR pszSubIdList +); + +typedef BOOL (WINAPI *Func_AllowDarkModeForWindow)( + HWND a_HWND, BOOL a_Allow); + +enum PreferredAppMode +{ + Default, + AllowDark, + ForceDark, + ForceLight, + Max +}; +// ordinal 135, in 1903 +typedef BOOL (WINAPI *Func_SetPreferredAppMode)(PreferredAppMode appMode); + +typedef HRESULT (WINAPI *Func_DwmSetWindowAttribute)( + HWND hwnd, + DWORD dwAttribute, + LPCVOID pvAttribute, + DWORD cbAttribute +); +*/ + +static BOOL InitInstance(int nCmdShow) +{ + CWindow wnd; + + // LoadString(hInstance, IDS_CLASS, windowClass, MAX_LOADSTRING); + + UString title ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); + + /* + //If it is already running, then focus on the window + hWnd = FindWindow(windowClass, title); + if (hWnd) + { + SetForegroundWindow ((HWND) (((DWORD)hWnd) | 0x01)); + return 0; + } + */ + + WNDCLASSW wc; + + // wc.style = CS_HREDRAW | CS_VREDRAW; + wc.style = 0; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_hInstance; + wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); + + // wc.hCursor = LoadCursor (NULL, IDC_ARROW); + wc.hCursor = ::LoadCursor(NULL, IDC_SIZEWE); + // wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + + wc.lpszMenuName = + #ifdef UNDER_CE + 0 + #else + MAKEINTRESOURCEW(IDM_MENU) + #endif + ; + + wc.lpszClassName = kWindowClass; + + if (MyRegisterClass(&wc) == 0) + return FALSE; + + // RECT rect; + // GetClientRect(hWnd, &rect); + + DWORD style = WS_OVERLAPPEDWINDOW; + // DWORD style = 0; + + CWindowInfo info; + info.maximized = false; + int x, y, xSize, ySize; + x = y = xSize = ySize = CW_USEDEFAULT; + bool windowPosIsRead; + info.Read(windowPosIsRead, g_PanelsInfoDefined); + + if (windowPosIsRead) + { + x = info.rect.left; + y = info.rect.top; + + xSize = RECT_SIZE_X(info.rect); + ySize = RECT_SIZE_Y(info.rect); + } + + + if (g_PanelsInfoDefined) + { + g_SplitterPos = info.splitterPos; + if (info.numPanels < 1 || info.numPanels > 2) + info.numPanels = kNumDefaultPanels; + if (info.currentPanel >= 2) + info.currentPanel = 0; + } + else + { + info.numPanels = kNumDefaultPanels; + info.currentPanel = 0; + } + + g_App.NumPanels = info.numPanels; + g_App.LastFocusedPanel = info.currentPanel; + + if (!wnd.Create(kWindowClass, title, style, + x, y, xSize, ySize, NULL, NULL, g_hInstance, NULL)) + return FALSE; + + /* + // doesn't work + { + const HMODULE hmodule = LoadLibrary("UxTheme.dll"); + if (hmodule) + { + { + const + Func_AllowDarkModeForWindow f = Z7_GET_PROC_ADDRESS( + Func_AllowDarkModeForWindow, hmodule, + MAKEINTRESOURCEA(133)); + if (f) + { + BOOL res = f((HWND)wnd, TRUE); + res = res; + } + } + { + const + Func_SetPreferredAppMode f = Z7_GET_PROC_ADDRESS( + Func_SetPreferredAppMode, hmodule, + MAKEINTRESOURCEA(135)); + if (f) + { + f(ForceDark); + } + } + { + const + Func_SetWindowTheme f = Z7_GET_PROC_ADDRESS( + Func_SetWindowTheme, hmodule, + "SetWindowTheme"); + if (f) + { + // HRESULT hres = f((HWND)wnd, L"DarkMode_Explorer", NULL); + HRESULT hres = f((HWND)wnd, L"Explorer", NULL); + hres = hres; + } + } + FreeLibrary(hmodule); + } + } + { + const HMODULE hmodule = LoadLibrary("Dwmapi.dll"); + if (hmodule) + { + const + Func_DwmSetWindowAttribute f = Z7_GET_PROC_ADDRESS( + Func_DwmSetWindowAttribute, hmodule, + "DwmSetWindowAttribute"); + if (f) + { + #ifndef Z7_WIN_DWMWA_USE_IMMERSIVE_DARK_MODE + #define Z7_WIN_DWMWA_USE_IMMERSIVE_DARK_MODE 20 + #endif + BOOL value = TRUE; + f((HWND)wnd, Z7_WIN_DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); + } + FreeLibrary(hmodule); + } + } + */ + + if (nCmdShow == SW_SHOWNORMAL || + nCmdShow == SW_SHOW + #ifndef UNDER_CE + || nCmdShow == SW_SHOWDEFAULT + #endif + ) + { + if (info.maximized) + nCmdShow = SW_SHOWMAXIMIZED; + else + nCmdShow = SW_SHOWNORMAL; + } + + if (nCmdShow == SW_SHOWMAXIMIZED) + g_Maximized = true; + + #ifndef UNDER_CE + WINDOWPLACEMENT placement; + placement.length = sizeof(placement); + if (wnd.GetPlacement(&placement)) + { + if (windowPosIsRead) + placement.rcNormalPosition = info.rect; + placement.showCmd = (UINT)nCmdShow; + wnd.SetPlacement(&placement); + } + else + #endif + wnd.Show(nCmdShow); + + return TRUE; +} + +/* +static void GetCommands(const UString &aCommandLine, UString &aCommands) +{ + UString aProgramName; + aCommands.Empty(); + bool aQuoteMode = false; + for (int i = 0; i < aCommandLine.Length(); i++) + { + wchar_t aChar = aCommandLine[i]; + if (aChar == L'\"') + aQuoteMode = !aQuoteMode; + else if (aChar == L' ' && !aQuoteMode) + { + if (!aQuoteMode) + { + i++; + break; + } + } + else + aProgramName += aChar; + } + aCommands = aCommandLine.Ptr(i); +} +*/ + +#if defined(_WIN32) && !defined(_WIN64) && !defined(UNDER_CE) + +extern +bool g_Is_Wow64; +bool g_Is_Wow64; + +typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL); + +static void Set_Wow64() +{ + g_Is_Wow64 = false; + const + Func_IsWow64Process fn = Z7_GET_PROC_ADDRESS( + Func_IsWow64Process, GetModuleHandleA("kernel32.dll"), + "IsWow64Process"); + if (fn) + { + BOOL isWow; + if (fn(GetCurrentProcess(), &isWow)) + g_Is_Wow64 = (isWow != FALSE); + } +} + +#endif + +#if _MSC_VER > 1400 /* && _MSC_VER <= 1900 */ + // GetVersion was declared deprecated + #pragma warning(disable : 4996) +#endif +#ifdef __clang__ + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +bool IsLargePageSupported(); +bool IsLargePageSupported() +{ + #ifdef _WIN64 + return true; + #else + + DWORD v = GetVersion(); + // low byte is major version: + // next byte is minor version: + v = ((v & 0xff) << 8) | ((v >> 8) & 0xFF); + return (v > 0x501); + // if ((Byte)v < 5) return false; + // if ((Byte)v > 5) return true; + // return ((Byte)(v >> 8) > 1); + /* large pages work in 5.1 (XP-32bit) if it's (g_Is_Wow64) mode; + but here we don't enable them in (XP-32bit). */ + #endif +} + +#ifndef UNDER_CE + +static void SetMemoryLock() +{ + if (!IsLargePageSupported()) + return; + // if (ReadLockMemoryAdd()) + NSecurity::AddLockMemoryPrivilege(); + + if (ReadLockMemoryEnable()) + if (NSecurity::Get_LargePages_RiskLevel() == 0) + { + // note: child processes can inherit that Privilege + g_LargePagesMode = NSecurity::EnablePrivilege_LockMemory(); + } +} + +extern +bool g_SymLink_Supported; +bool g_SymLink_Supported = false; + +static void Set_SymLink_Supported() +{ + // g_SymLink_Supported = false; + const DWORD v = GetVersion(); + // low byte is major version: + if ((Byte)v < 6) + return; + g_SymLink_Supported = true; + // if (g_SymLink_Supported) + { + NSecurity::EnablePrivilege_SymLink(); + } +} + +#endif + +/* +static const int kNumSwitches = 1; + +namespace NKey { +enum Enum +{ + kOpenArachive = 0 +}; + +} + +static const CSwitchForm kSwitchForms[kNumSwitches] = + { + { L"SOA", NSwitchType::kSimple, false }, + }; +*/ + +// int APIENTRY WinMain2(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */, int /* nCmdShow */); + +static void ErrorMessage(const wchar_t *s) +{ + MessageBoxW(NULL, s, L"7-Zip", MB_ICONERROR); +} + +static void ErrorMessage(const char *s) +{ + ErrorMessage(GetUnicodeString(s)); +} + + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return 1; +#endif + +static int WINAPI WinMain2(int nCmdShow) +{ + g_RAM_Size_Defined = NSystem::GetRamSize(g_RAM_Size); + + #ifdef _WIN32 + + /* + #ifndef _WIN64 + #ifndef UNDER_CE + { + HMODULE hMod = GetModuleHandle("Kernel32.dll"); + if (hMod) + { + typedef BOOL (WINAPI *PSETDEP)(DWORD); + #define MY_PROCESS_DEP_ENABLE 1 + PSETDEP procSet = (PSETDEP)GetProcAddress(hMod,"SetProcessDEPPolicy"); + if (procSet) + procSet(MY_PROCESS_DEP_ENABLE); + + typedef BOOL (WINAPI *HSI)(HANDLE, HEAP_INFORMATION_CLASS ,PVOID, SIZE_T); + HSI hsi = (HSI)GetProcAddress(hMod, "HeapSetInformation"); + #define MY_HeapEnableTerminationOnCorruption ((HEAP_INFORMATION_CLASS)1) + if (hsi) + hsi(NULL, MY_HeapEnableTerminationOnCorruption, NULL, 0); + } + } + #endif + #endif + */ + + NT_CHECK + #ifdef Z7_LARGE_PAGES + SetLargePageSize(); + #endif + + #endif + + #ifdef Z7_LANG + LoadLangOneTime(); + #endif + + InitCommonControls(); + +#ifdef Z7_USE_DYN_ComCtl32Version + g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); + g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); +#endif + + #if defined(_WIN32) && !defined(_WIN64) && !defined(UNDER_CE) + Set_Wow64(); + #endif + + + g_IsSmallScreen = !NWindows::NControl::IsDialogSizeOK(200, 200); + + // OleInitialize is required for drag and drop. + #ifndef UNDER_CE + OleInitialize(NULL); + #endif + // Maybe needs CoInitializeEx also ? + // NCOM::CComInitializer comInitializer; + + UString commandsString; + // MessageBoxW(NULL, GetCommandLineW(), L"", 0); + + #ifdef UNDER_CE + commandsString = GetCommandLineW(); + #else + UString programString; + SplitStringToTwoStrings(GetCommandLineW(), programString, commandsString); + #endif + + commandsString.Trim(); + UString paramString, tailString; + SplitStringToTwoStrings(commandsString, paramString, tailString); + paramString.Trim(); + tailString.Trim(); + if (tailString.IsPrefixedBy(L"-t")) + g_ArcFormat = tailString.Ptr(2); + + /* + UStringVector switches; + for (;;) + { + if (tailString.IsEmpty()) + break; + UString s1, s2; + SplitStringToTwoStrings(tailString, s1, s2); + if (s2.IsEmpty()) + { + tailString.Trim(); + switches.Add(tailString); + break; + } + s1.Trim(); + switches.Add(s1); + tailString = s2; + } + + FOR_VECTOR(i, switches) + { + const UString &sw = switches[i]; + if (sw.IsPrefixedBy(L"-t")) + g_ArcFormat = sw.Ptr(2); + // + else if (sw.IsPrefixedBy(L"-stp")) + { + const wchar_t *end; + UInt32 val = ConvertStringToUInt32(sw.Ptr(4), &end); + if (*end != 0) + throw 111; + g_TypeParseLevel = val; + } + else + // + throw 112; + } + */ + + if (!paramString.IsEmpty()) + { + g_MainPath = paramString; + // return WinMain2(hInstance, hPrevInstance, lpCmdLine, nCmdShow); + + // MessageBoxW(NULL, paramString, L"", 0); + } + /* + UStringVector commandStrings; + NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); + NCommandLineParser::CParser parser(kNumSwitches); + try + { + parser.ParseStrings(kSwitchForms, commandStrings); + const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; + if (nonSwitchStrings.Size() > 1) + { + g_MainPath = nonSwitchStrings[1]; + // g_OpenArchive = parser[NKey::kOpenArachive].ThereIs; + CFileInfoW fileInfo; + if (FindFile(g_MainPath, fileInfo)) + { + if (!fileInfo.IsDir()) + g_OpenArchive = true; + } + } + } + catch(...) { } + */ + + + #if defined(_WIN32) && !defined(UNDER_CE) + SetMemoryLock(); + Set_SymLink_Supported(); + #endif + + g_App.ReloadLangItems(); + + MSG msg; + if (!InitInstance (nCmdShow)) + return FALSE; + + // we will load Global_Codecs at first use instead. + /* + OutputDebugStringW(L"Before LoadGlobalCodecs"); + LoadGlobalCodecs(); + OutputDebugStringW(L"After LoadGlobalCodecs"); + */ + + #ifndef _UNICODE + if (g_IsNT) + { + HACCEL hAccels = LoadAcceleratorsW(g_hInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR1)); + while (GetMessageW(&msg, NULL, 0, 0)) + { + if (TranslateAcceleratorW(g_HWND, hAccels, &msg) == 0) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + } + else + #endif + { + HACCEL hAccels = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); + while (GetMessage(&msg, NULL, 0, 0)) + { + if (TranslateAccelerator(g_HWND, hAccels, &msg) == 0) + { + // if (g_Hwnd != NULL || !IsDialogMessage(g_Hwnd, &msg)) + // if (!IsDialogMessage(g_Hwnd, &msg)) + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + + // Destructor of g_CodecsReleaser can release DLLs. + // But we suppose that it's better to release DLLs here (before destructor). + FreeGlobalCodecs(); + + g_HWND = NULL; + #ifndef UNDER_CE + OleUninitialize(); + #endif + return (int)msg.wParam; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + /* lpCmdLine */, int nCmdShow) +{ + g_hInstance = hInstance; + + try + { + try + { + #ifdef _WIN32 + My_SetDefaultDllDirectories(); + #endif + return WinMain2(nCmdShow); + } + catch (...) + { + g_ExitEventLauncher.Exit(true); + throw; + } + } + catch(const CNewException &) + { + ErrorMessage(LangString(IDS_MEM_ERROR)); + return 1; + } + catch(const UString &s) + { + ErrorMessage(s); + return 1; + } + catch(const AString &s) + { + ErrorMessage(s.Ptr()); + return 1; + } + catch(const wchar_t *s) + { + ErrorMessage(s); + return 1; + } + catch(const char *s) + { + ErrorMessage(s); + return 1; + } + catch(int v) + { + AString e ("Error: "); + e.Add_UInt32((unsigned)v); + ErrorMessage(e); + return 1; + } + catch(...) + { + ErrorMessage("Unknown error"); + return 1; + } +} + +static void SaveWindowInfo(HWND aWnd) +{ + CWindowInfo info; + + #ifdef UNDER_CE + + if (!::GetWindowRect(aWnd, &info.rect)) + return; + info.maximized = g_Maximized; + + #else + + WINDOWPLACEMENT placement; + placement.length = sizeof(placement); + if (!::GetWindowPlacement(aWnd, &placement)) + return; + info.rect = placement.rcNormalPosition; + info.maximized = BOOLToBool(::IsZoomed(aWnd)); + + #endif + + info.numPanels = g_App.NumPanels; + info.currentPanel = g_App.LastFocusedPanel; + info.splitterPos = (unsigned)g_Splitter.GetPos(); + + info.Save(); +} + +static void ExecuteCommand(UINT commandID) +{ + CPanel::CDisableTimerProcessing disableTimerProcessing1(g_App.Panels[0]); + CPanel::CDisableTimerProcessing disableTimerProcessing2(g_App.Panels[1]); + + switch (commandID) + { + case kMenuCmdID_Toolbar_Add: g_App.AddToArchive(); break; + case kMenuCmdID_Toolbar_Extract: g_App.ExtractArchives(); break; + case kMenuCmdID_Toolbar_Test: g_App.TestArchives(); break; + } +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_COMMAND: + { + unsigned wmId = LOWORD(wParam); + unsigned wmEvent = HIWORD(wParam); + if ((HWND) lParam != NULL && wmEvent != 0) + break; + if (wmId >= kMenuCmdID_Toolbar_Start && wmId < kMenuCmdID_Toolbar_End) + { + ExecuteCommand(wmId); + return 0; + } + if (OnMenuCommand(hWnd, wmId)) + return 0; + break; + } + case WM_INITMENUPOPUP: + OnMenuActivating(hWnd, HMENU(wParam), LOWORD(lParam)); + break; + + /* + It doesn't help + case WM_EXITMENULOOP: + { + OnMenuUnActivating(hWnd); + break; + } + case WM_UNINITMENUPOPUP: + OnMenuUnActivating(hWnd, HMENU(wParam), lParam); + break; + */ + + case WM_CREATE: + { + g_HWND = hWnd; + /* + INITCOMMONCONTROLSEX icex; + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_BAR_CLASSES; + InitCommonControlsEx(&icex); + + // Toolbar buttons used to create the first 4 buttons. + TBBUTTON tbb [ ] = + { + // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, + // {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}, + // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, + {VIEW_NEWFOLDER, ID_FILE_CREATEFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}, + }; + + int baseID = 100; + NWindows::NControl::CToolBar aToolBar; + aToolBar.Attach(::CreateToolbarEx (hWnd, + WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS, // | TBSTYLE_FLAT + baseID + 2, 11, + (HINSTANCE)HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR, + (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb), + 0, 0, 100, 30, sizeof (TBBUTTON))); + */ + // HCURSOR cursor = ::LoadCursor(0, IDC_SIZEWE); + // ::SetCursor(cursor); + + if (g_PanelsInfoDefined) + g_Splitter.SetPos(hWnd, (int)g_SplitterPos); + else + { + g_Splitter.SetRatio(hWnd, kSplitterRateMax / 2); + g_SplitterPos = (unsigned)g_Splitter.GetPos(); + } + + RECT rect; + ::GetClientRect(hWnd, &rect); + const int xSize = rect.right; + int xSizes[2]; + xSizes[0] = g_Splitter.GetPos(); + xSizes[1] = xSize - kSplitterWidth - xSizes[0]; + if (xSizes[1] < 0) + xSizes[1] = 0; + + g_App.CreateDragTarget(); + + COpenResult openRes; + bool needOpenArc = false; + + UString fullPath = g_MainPath; + if (!fullPath.IsEmpty() /* && g_OpenArchive */) + { + if (!NFile::NName::IsAbsolutePath(fullPath)) + { + FString fullPathF; + if (NFile::NName::GetFullPath(us2fs(fullPath), fullPathF)) + fullPath = fs2us(fullPathF); + } + if (NFile::NFind::DoesFileExist_FollowLink(us2fs(fullPath))) + needOpenArc = true; + } + + HRESULT res = g_App.Create(hWnd, fullPath, g_ArcFormat, xSizes, + needOpenArc, + openRes); + + if (res == E_ABORT) + return -1; + + if ((needOpenArc && !openRes.ArchiveIsOpened) || res != S_OK) + { + UString m ("Error"); + if (res == S_FALSE || res == S_OK) + { + m = MyFormatNew(openRes.Encrypted ? + IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : + IDS_CANT_OPEN_ARCHIVE, + fullPath); + } + else if (res != S_OK) + m = HResultToMessage(res); + if (!openRes.ErrorMessage.IsEmpty()) + { + m.Add_LF(); + m += openRes.ErrorMessage; + } + ErrorMessage(m); + return -1; + } + + g_WindowWasCreated = true; + + // g_SplitterPos = 0; + + // ::DragAcceptFiles(hWnd, TRUE); + RegisterDragDrop(hWnd, g_App._dropTarget); + + break; + } + + case WM_CLOSE: + { + // why do we use WA_INACTIVE here ? + SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd); + g_ExitEventLauncher.Exit(false); + // ::DragAcceptFiles(hWnd, FALSE); + RevokeDragDrop(hWnd); + g_App._dropTarget.Release(); + + if (g_WindowWasCreated) + g_App.Save(); + + g_App.ReleaseApp(); + + if (g_WindowWasCreated) + SaveWindowInfo(hWnd); + + g_ExitEventLauncher.Exit(true); + // default DefWindowProc will call DestroyWindow / WM_DESTROY + break; + } + + case WM_DESTROY: + { + PostQuitMessage(0); + break; + } + + // case WM_MOVE: break; + + case WM_LBUTTONDOWN: + g_StartCaptureMousePos = LOWORD(lParam); + g_StartCaptureSplitterPos = g_Splitter.GetPos(); + ::SetCapture(hWnd); + break; + + case WM_LBUTTONUP: + { + ::ReleaseCapture(); + break; + } + + case WM_MOUSEMOVE: + { + if ((wParam & MK_LBUTTON) != 0 && ::GetCapture() == hWnd) + { + g_Splitter.SetPos(hWnd, g_StartCaptureSplitterPos + + (short)LOWORD(lParam) - g_StartCaptureMousePos); + g_App.MoveSubWindows(); + } + break; + } + + case WM_SIZE: + { + if (g_CanChangeSplitter) + g_Splitter.SetPosFromRatio(hWnd); + else + { + g_Splitter.SetPos(hWnd, (int)g_SplitterPos ); + g_CanChangeSplitter = true; + } + + g_Maximized = (wParam == SIZE_MAXIMIZED) || (wParam == SIZE_MAXSHOW); + + g_App.MoveSubWindows(); + /* + int xSize = LOWORD(lParam); + int ySize = HIWORD(lParam); + // int xSplitter = 2; + int xWidth = g_SplitPos; + // int xSplitPos = xWidth; + g_Panel[0]._listView.MoveWindow(0, 0, xWidth, ySize); + g_Panel[1]._listView.MoveWindow(xSize - xWidth, 0, xWidth, ySize); + */ + return 0; + // break; + } + + case WM_SETFOCUS: + // g_App.SetFocus(g_App.LastFocusedPanel); + g_App.SetFocusToLastItem(); + break; + + /* + case WM_ACTIVATE: + { + int fActive = LOWORD(wParam); + switch (fActive) + { + case WA_INACTIVE: + { + // g_FocusIndex = g_App.LastFocusedPanel; + // g_App.LastFocusedPanel = g_App.GetFocusedPanelIndex(); + // return 0; + } + } + break; + } + */ + + /* + case kLangWasChangedMessage: + MyLoadMenu(); + return 0; + */ + + /* + case WM_SETTINGCHANGE: + break; + */ + + case WM_NOTIFY: + { + g_App.OnNotify((int)wParam, (LPNMHDR)lParam); + break; + } + + /* + case WM_DROPFILES: + { + g_App.GetFocusedPanel().CompressDropFiles((HDROP)wParam); + return 0 ; + } + */ + } + #ifndef _UNICODE + if (g_IsNT) + return DefWindowProcW(hWnd, message, wParam, lParam); + else + #endif + return DefWindowProc(hWnd, message, wParam, lParam); + +} + +static int Window_GetRealHeight(NWindows::CWindow &w) +{ + RECT rect; + w.GetWindowRect(&rect); + int res = RECT_SIZE_Y(rect); + #ifndef UNDER_CE + WINDOWPLACEMENT placement; + if (w.GetPlacement(&placement)) + res += placement.rcNormalPosition.top; + #endif + return res; +} + +void CApp::MoveSubWindows() +{ + HWND hWnd = _window; + RECT rect; + if (!hWnd) + return; + ::GetClientRect(hWnd, &rect); + int xSize = rect.right; + if (xSize == 0) + return; + int headerSize = 0; + + #ifdef UNDER_CE + _commandBar.AutoSize(); + { + _commandBar.Show(true); // maybe we need it for + headerSize += _commandBar.Height(); + } + #endif + + if (_toolBar) + { + _toolBar.AutoSize(); + #ifdef UNDER_CE + int h2 = Window_GetRealHeight(_toolBar); + _toolBar.Move(0, headerSize, xSize, h2); + #endif + headerSize += Window_GetRealHeight(_toolBar); + } + + int ySize = MyMax((int)(rect.bottom - headerSize), 0); + + if (NumPanels > 1) + { + Panels[0].Move(0, headerSize, g_Splitter.GetPos(), ySize); + int xWidth1 = g_Splitter.GetPos() + kSplitterWidth; + Panels[1].Move(xWidth1, headerSize, xSize - xWidth1, ySize); + } + else + { + /* + int otherPanel = 1 - LastFocusedPanel; + if (PanelsCreated[otherPanel]) + Panels[otherPanel].Move(0, headerSize, 0, ySize); + */ + Panels[LastFocusedPanel].Move(0, headerSize, xSize, ySize); + } +} diff --git a/CPP/7zip/UI/FileManager/FM.dsp b/CPP/7zip/UI/FileManager/FM.dsp index bfd0060b6..4c549d6f1 100644 --- a/CPP/7zip/UI/FileManager/FM.dsp +++ b/CPP/7zip/UI/FileManager/FM.dsp @@ -1,1699 +1,1699 @@ -# Microsoft Developer Studio Project File - Name="FM" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=FM - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "FM.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "FM.mak" CFG="FM - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "FM - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "FM - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE "FM - Win32 ReleaseU" (based on "Win32 (x86) Application") -!MESSAGE "FM - Win32 DebugU" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "FM - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "FM - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseU" -# PROP BASE Intermediate_Dir "ReleaseU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /c -# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "FM - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "DebugU" -# PROP BASE Intermediate_Dir "DebugU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c -# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "FM - Win32 Release" -# Name "FM - Win32 Debug" -# Name "FM - Win32 ReleaseU" -# Name "FM - Win32 DebugU" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\7zipLogo.ico -# End Source File -# Begin Source File - -SOURCE=.\add.bmp -# End Source File -# Begin Source File - -SOURCE=.\ClassDefs.cpp -# End Source File -# Begin Source File - -SOURCE=.\Copy.bmp -# End Source File -# Begin Source File - -SOURCE=.\Delete.bmp -# End Source File -# Begin Source File - -SOURCE=.\Extract.bmp -# End Source File -# Begin Source File - -SOURCE=.\FM.ico -# End Source File -# Begin Source File - -SOURCE=.\Move.bmp -# End Source File -# Begin Source File - -SOURCE=.\MyWindowsNew.h -# End Source File -# Begin Source File - -SOURCE=.\Parent.bmp -# End Source File -# Begin Source File - -SOURCE=.\Properties.bmp -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# ADD BASE RSC /l 0x419 -# ADD RSC /l 0x409 -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"StdAfx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# Begin Source File - -SOURCE=.\Test.bmp -# End Source File -# End Group -# Begin Group "Folders" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\AltStreamsFolder.cpp -# End Source File -# Begin Source File - -SOURCE=.\AltStreamsFolder.h -# End Source File -# Begin Source File - -SOURCE=.\FSDrives.cpp -# End Source File -# Begin Source File - -SOURCE=.\FSDrives.h -# End Source File -# Begin Source File - -SOURCE=.\FSFolder.cpp -# End Source File -# Begin Source File - -SOURCE=.\FSFolder.h -# End Source File -# Begin Source File - -SOURCE=.\FSFolderCopy.cpp -# End Source File -# Begin Source File - -SOURCE=.\IFolder.h -# End Source File -# Begin Source File - -SOURCE=.\NetFolder.cpp -# End Source File -# Begin Source File - -SOURCE=.\NetFolder.h -# End Source File -# Begin Source File - -SOURCE=.\RootFolder.cpp -# End Source File -# Begin Source File - -SOURCE=.\RootFolder.h -# End Source File -# End Group -# Begin Group "Registry" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\RegistryAssociations.cpp -# End Source File -# Begin Source File - -SOURCE=.\RegistryAssociations.h -# End Source File -# Begin Source File - -SOURCE=.\RegistryPlugins.cpp -# End Source File -# Begin Source File - -SOURCE=.\RegistryPlugins.h -# End Source File -# Begin Source File - -SOURCE=.\RegistryUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\RegistryUtils.h -# End Source File -# Begin Source File - -SOURCE=.\ViewSettings.cpp -# End Source File -# Begin Source File - -SOURCE=.\ViewSettings.h -# End Source File -# End Group -# Begin Group "Panel" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\App.cpp -# End Source File -# Begin Source File - -SOURCE=.\App.h -# End Source File -# Begin Source File - -SOURCE=.\AppState.h -# End Source File -# Begin Source File - -SOURCE=.\EnumFormatEtc.cpp -# End Source File -# Begin Source File - -SOURCE=.\EnumFormatEtc.h -# End Source File -# Begin Source File - -SOURCE=.\FileFolderPluginOpen.cpp -# End Source File -# Begin Source File - -SOURCE=.\FileFolderPluginOpen.h -# End Source File -# Begin Source File - -SOURCE=.\Panel.cpp -# End Source File -# Begin Source File - -SOURCE=.\Panel.h -# End Source File -# Begin Source File - -SOURCE=.\PanelCopy.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelCrc.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelDrag.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelFolderChange.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelItemOpen.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelItems.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelKey.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelListNotify.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelMenu.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelOperations.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelSelect.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelSort.cpp -# End Source File -# Begin Source File - -SOURCE=.\PanelSplitFile.cpp -# End Source File -# Begin Source File - -SOURCE=.\VerCtrl.cpp -# End Source File -# End Group -# Begin Group "Dialog" - -# PROP Default_Filter "" -# Begin Group "Options" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\EditPage.cpp -# End Source File -# Begin Source File - -SOURCE=.\EditPage.h -# End Source File -# Begin Source File - -SOURCE=.\FoldersPage.cpp -# End Source File -# Begin Source File - -SOURCE=.\FoldersPage.h -# End Source File -# Begin Source File - -SOURCE=.\LangPage.cpp -# End Source File -# Begin Source File - -SOURCE=.\LangPage.h -# End Source File -# Begin Source File - -SOURCE=.\MenuPage.cpp -# End Source File -# Begin Source File - -SOURCE=.\MenuPage.h -# End Source File -# Begin Source File - -SOURCE=.\OptionsDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\SettingsPage.cpp -# End Source File -# Begin Source File - -SOURCE=.\SettingsPage.h -# End Source File -# Begin Source File - -SOURCE=.\SystemPage.cpp -# End Source File -# Begin Source File - -SOURCE=.\SystemPage.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\AboutDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\AboutDialog.h -# End Source File -# Begin Source File - -SOURCE=.\BrowseDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\BrowseDialog.h -# End Source File -# Begin Source File - -SOURCE=.\BrowseDialog2.cpp -# End Source File -# Begin Source File - -SOURCE=.\BrowseDialog2.h -# End Source File -# Begin Source File - -SOURCE=.\ComboDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\ComboDialog.h -# End Source File -# Begin Source File - -SOURCE=CopyDialog.cpp -# End Source File -# Begin Source File - -SOURCE=CopyDialog.h -# End Source File -# Begin Source File - -SOURCE=.\DialogSize.h -# End Source File -# Begin Source File - -SOURCE=.\EditDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\EditDialog.h -# End Source File -# Begin Source File - -SOURCE=.\LinkDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\LinkDialog.h -# End Source File -# Begin Source File - -SOURCE=.\ListViewDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\ListViewDialog.h -# End Source File -# Begin Source File - -SOURCE=.\MemDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\MemDialog.h -# End Source File -# Begin Source File - -SOURCE=MessagesDialog.cpp -# End Source File -# Begin Source File - -SOURCE=MessagesDialog.h -# End Source File -# Begin Source File - -SOURCE=OverwriteDialog.cpp -# End Source File -# Begin Source File - -SOURCE=OverwriteDialog.h -# End Source File -# Begin Source File - -SOURCE=.\PasswordDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\PasswordDialog.h -# End Source File -# Begin Source File - -SOURCE=.\ProgressDialog2.cpp -# End Source File -# Begin Source File - -SOURCE=.\ProgressDialog2.h -# End Source File -# Begin Source File - -SOURCE=.\SplitDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\SplitDialog.h -# End Source File -# End Group -# Begin Group "FM Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\ExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=.\FormatUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\FormatUtils.h -# End Source File -# Begin Source File - -SOURCE=.\HelpUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\HelpUtils.h -# End Source File -# Begin Source File - -SOURCE=.\LangUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\LangUtils.h -# End Source File -# Begin Source File - -SOURCE=.\ProgramLocation.cpp -# End Source File -# Begin Source File - -SOURCE=.\ProgramLocation.h -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallback100.cpp -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallback100.h -# End Source File -# End Group -# Begin Group "7-Zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Group "Control" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\CommandBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Edit.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ImageList.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ProgressBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\PropertyPage.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\PropertyPage.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ReBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Static.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\StatusBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ToolBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Window2.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Window2.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\COM.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Device.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Handle.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Menu.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Menu.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Net.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Net.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\NtCheck.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ProcessUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ProcessUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SecurityUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\AutoPtr.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common0.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ComTry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Defs.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynamicBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Exception.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyCom.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyInitGuid.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Random.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Random.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "UI" - -# PROP Default_Filter "" -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveName.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveName.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\CompressCall.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\CompressCall.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\Common\IFileExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Property.h -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\StdAfx.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.h -# End Source File -# Begin Source File - -SOURCE=..\Common\WorkDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\WorkDir.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.h -# End Source File -# End Group -# Begin Group "Agent" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Agent\Agent.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\Agent.h -# End Source File -# Begin Source File - -SOURCE=..\Agent\AgentOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\AgentProxy.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\AgentProxy.h -# End Source File -# Begin Source File - -SOURCE=..\Agent\ArchiveFolder.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\ArchiveFolderOpen.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\ArchiveFolderOut.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\IFolderArchive.h -# End Source File -# Begin Source File - -SOURCE=..\Agent\UpdateCallbackAgent.cpp -# End Source File -# Begin Source File - -SOURCE=..\Agent\UpdateCallbackAgent.h -# End Source File -# End Group -# Begin Group "Explorer" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Explorer\ContextMenu.cpp -# End Source File -# Begin Source File - -SOURCE=..\Explorer\ContextMenu.h -# End Source File -# Begin Source File - -SOURCE=..\Explorer\ContextMenuFlags.h -# End Source File -# Begin Source File - -SOURCE=..\Explorer\MyExplorerCommand.h -# End Source File -# Begin Source File - -SOURCE=..\Explorer\MyMessages.cpp -# End Source File -# Begin Source File - -SOURCE=..\Explorer\MyMessages.h -# End Source File -# Begin Source File - -SOURCE=..\Explorer\RegistryContextMenu.cpp -# End Source File -# Begin Source File - -SOURCE=..\Explorer\RegistryContextMenu.h -# End Source File -# End Group -# Begin Group "GUI" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\GUI\HashGUI.cpp -# End Source File -# Begin Source File - -SOURCE=..\GUI\HashGUI.h -# End Source File -# Begin Source File - -SOURCE=..\GUI\UpdateCallbackGUI2.cpp -# End Source File -# Begin Source File - -SOURCE=..\GUI\UpdateCallbackGUI2.h -# End Source File -# End Group -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# End Group -# Begin Group "Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IPassword.h -# End Source File -# Begin Source File - -SOURCE=..\..\IProgress.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\PropID.h -# End Source File -# End Group -# Begin Group "ArchiveCommon" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# End Group -# Begin Source File - -SOURCE=.\7zFM.exe.manifest -# End Source File -# Begin Source File - -SOURCE=.\7zipLogo.ico -# End Source File -# Begin Source File - -SOURCE=.\Add2.bmp -# End Source File -# Begin Source File - -SOURCE=.\Copy2.bmp -# End Source File -# Begin Source File - -SOURCE=.\Delete2.bmp -# End Source File -# Begin Source File - -SOURCE=.\Extract2.bmp -# End Source File -# Begin Source File - -SOURCE=.\FilePlugins.cpp -# End Source File -# Begin Source File - -SOURCE=.\FilePlugins.h -# End Source File -# Begin Source File - -SOURCE=.\FM.cpp -# End Source File -# Begin Source File - -SOURCE=.\Info.bmp -# End Source File -# Begin Source File - -SOURCE=.\Info2.bmp -# End Source File -# Begin Source File - -SOURCE=.\Move2.bmp -# End Source File -# Begin Source File - -SOURCE=.\MyCom2.h -# End Source File -# Begin Source File - -SOURCE=.\MyLoadMenu.cpp -# End Source File -# Begin Source File - -SOURCE=.\MyLoadMenu.h -# End Source File -# Begin Source File - -SOURCE=.\OpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=.\OpenCallback.h -# End Source File -# Begin Source File - -SOURCE=.\PluginInterface.h -# End Source File -# Begin Source File - -SOURCE=.\PluginLoader.h -# End Source File -# Begin Source File - -SOURCE=.\PropertyName.cpp -# End Source File -# Begin Source File - -SOURCE=.\PropertyName.h -# End Source File -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\SplitUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\SplitUtils.h -# End Source File -# Begin Source File - -SOURCE=.\StringUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\StringUtils.h -# End Source File -# Begin Source File - -SOURCE=.\SysIconUtils.cpp -# End Source File -# Begin Source File - -SOURCE=.\SysIconUtils.h -# End Source File -# Begin Source File - -SOURCE=.\Test2.bmp -# End Source File -# Begin Source File - -SOURCE=.\TextPairs.cpp -# End Source File -# Begin Source File - -SOURCE=.\TextPairs.h -# End Source File -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="FM" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=FM - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "FM.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "FM.mak" CFG="FM - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "FM - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "FM - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "FM - Win32 ReleaseU" (based on "Win32 (x86) Application") +!MESSAGE "FM - Win32 DebugU" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "FM - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "FM - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "FM - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c +# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "FM - Win32 Release" +# Name "FM - Win32 Debug" +# Name "FM - Win32 ReleaseU" +# Name "FM - Win32 DebugU" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\7zipLogo.ico +# End Source File +# Begin Source File + +SOURCE=.\add.bmp +# End Source File +# Begin Source File + +SOURCE=.\ClassDefs.cpp +# End Source File +# Begin Source File + +SOURCE=.\Copy.bmp +# End Source File +# Begin Source File + +SOURCE=.\Delete.bmp +# End Source File +# Begin Source File + +SOURCE=.\Extract.bmp +# End Source File +# Begin Source File + +SOURCE=.\FM.ico +# End Source File +# Begin Source File + +SOURCE=.\Move.bmp +# End Source File +# Begin Source File + +SOURCE=.\MyWindowsNew.h +# End Source File +# Begin Source File + +SOURCE=.\Parent.bmp +# End Source File +# Begin Source File + +SOURCE=.\Properties.bmp +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# ADD BASE RSC /l 0x419 +# ADD RSC /l 0x409 +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=.\Test.bmp +# End Source File +# End Group +# Begin Group "Folders" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\AltStreamsFolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\AltStreamsFolder.h +# End Source File +# Begin Source File + +SOURCE=.\FSDrives.cpp +# End Source File +# Begin Source File + +SOURCE=.\FSDrives.h +# End Source File +# Begin Source File + +SOURCE=.\FSFolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\FSFolder.h +# End Source File +# Begin Source File + +SOURCE=.\FSFolderCopy.cpp +# End Source File +# Begin Source File + +SOURCE=.\IFolder.h +# End Source File +# Begin Source File + +SOURCE=.\NetFolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\NetFolder.h +# End Source File +# Begin Source File + +SOURCE=.\RootFolder.cpp +# End Source File +# Begin Source File + +SOURCE=.\RootFolder.h +# End Source File +# End Group +# Begin Group "Registry" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\RegistryAssociations.cpp +# End Source File +# Begin Source File + +SOURCE=.\RegistryAssociations.h +# End Source File +# Begin Source File + +SOURCE=.\RegistryPlugins.cpp +# End Source File +# Begin Source File + +SOURCE=.\RegistryPlugins.h +# End Source File +# Begin Source File + +SOURCE=.\RegistryUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\RegistryUtils.h +# End Source File +# Begin Source File + +SOURCE=.\ViewSettings.cpp +# End Source File +# Begin Source File + +SOURCE=.\ViewSettings.h +# End Source File +# End Group +# Begin Group "Panel" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\App.cpp +# End Source File +# Begin Source File + +SOURCE=.\App.h +# End Source File +# Begin Source File + +SOURCE=.\AppState.h +# End Source File +# Begin Source File + +SOURCE=.\EnumFormatEtc.cpp +# End Source File +# Begin Source File + +SOURCE=.\EnumFormatEtc.h +# End Source File +# Begin Source File + +SOURCE=.\FileFolderPluginOpen.cpp +# End Source File +# Begin Source File + +SOURCE=.\FileFolderPluginOpen.h +# End Source File +# Begin Source File + +SOURCE=.\Panel.cpp +# End Source File +# Begin Source File + +SOURCE=.\Panel.h +# End Source File +# Begin Source File + +SOURCE=.\PanelCopy.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelCrc.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelDrag.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelFolderChange.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelItemOpen.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelItems.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelKey.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelListNotify.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelMenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelOperations.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelSelect.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelSort.cpp +# End Source File +# Begin Source File + +SOURCE=.\PanelSplitFile.cpp +# End Source File +# Begin Source File + +SOURCE=.\VerCtrl.cpp +# End Source File +# End Group +# Begin Group "Dialog" + +# PROP Default_Filter "" +# Begin Group "Options" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\EditPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\EditPage.h +# End Source File +# Begin Source File + +SOURCE=.\FoldersPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\FoldersPage.h +# End Source File +# Begin Source File + +SOURCE=.\LangPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\LangPage.h +# End Source File +# Begin Source File + +SOURCE=.\MenuPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\MenuPage.h +# End Source File +# Begin Source File + +SOURCE=.\OptionsDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\SettingsPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\SettingsPage.h +# End Source File +# Begin Source File + +SOURCE=.\SystemPage.cpp +# End Source File +# Begin Source File + +SOURCE=.\SystemPage.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\AboutDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\AboutDialog.h +# End Source File +# Begin Source File + +SOURCE=.\BrowseDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\BrowseDialog.h +# End Source File +# Begin Source File + +SOURCE=.\BrowseDialog2.cpp +# End Source File +# Begin Source File + +SOURCE=.\BrowseDialog2.h +# End Source File +# Begin Source File + +SOURCE=.\ComboDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\ComboDialog.h +# End Source File +# Begin Source File + +SOURCE=CopyDialog.cpp +# End Source File +# Begin Source File + +SOURCE=CopyDialog.h +# End Source File +# Begin Source File + +SOURCE=.\DialogSize.h +# End Source File +# Begin Source File + +SOURCE=.\EditDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\EditDialog.h +# End Source File +# Begin Source File + +SOURCE=.\LinkDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\LinkDialog.h +# End Source File +# Begin Source File + +SOURCE=.\ListViewDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\ListViewDialog.h +# End Source File +# Begin Source File + +SOURCE=.\MemDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\MemDialog.h +# End Source File +# Begin Source File + +SOURCE=MessagesDialog.cpp +# End Source File +# Begin Source File + +SOURCE=MessagesDialog.h +# End Source File +# Begin Source File + +SOURCE=OverwriteDialog.cpp +# End Source File +# Begin Source File + +SOURCE=OverwriteDialog.h +# End Source File +# Begin Source File + +SOURCE=.\PasswordDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\PasswordDialog.h +# End Source File +# Begin Source File + +SOURCE=.\ProgressDialog2.cpp +# End Source File +# Begin Source File + +SOURCE=.\ProgressDialog2.h +# End Source File +# Begin Source File + +SOURCE=.\SplitDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\SplitDialog.h +# End Source File +# End Group +# Begin Group "FM Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=.\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\FormatUtils.h +# End Source File +# Begin Source File + +SOURCE=.\HelpUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\HelpUtils.h +# End Source File +# Begin Source File + +SOURCE=.\LangUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\LangUtils.h +# End Source File +# Begin Source File + +SOURCE=.\ProgramLocation.cpp +# End Source File +# Begin Source File + +SOURCE=.\ProgramLocation.h +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallback100.cpp +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallback100.h +# End Source File +# End Group +# Begin Group "7-Zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\CommandBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Edit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ImageList.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ProgressBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\PropertyPage.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\PropertyPage.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ReBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Static.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\StatusBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ToolBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Window2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Window2.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\COM.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Device.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Handle.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Menu.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Menu.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Net.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Net.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\NtCheck.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ProcessUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ProcessUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\AutoPtr.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common0.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ComTry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Defs.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynamicBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Exception.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyCom.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyInitGuid.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Random.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Random.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "UI" + +# PROP Default_Filter "" +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveName.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveName.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\CompressCall.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\CompressCall.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\Common\IFileExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Property.h +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\StdAfx.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.h +# End Source File +# Begin Source File + +SOURCE=..\Common\WorkDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\WorkDir.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.h +# End Source File +# End Group +# Begin Group "Agent" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Agent\Agent.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\Agent.h +# End Source File +# Begin Source File + +SOURCE=..\Agent\AgentOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\AgentProxy.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\AgentProxy.h +# End Source File +# Begin Source File + +SOURCE=..\Agent\ArchiveFolder.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\ArchiveFolderOpen.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\ArchiveFolderOut.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\IFolderArchive.h +# End Source File +# Begin Source File + +SOURCE=..\Agent\UpdateCallbackAgent.cpp +# End Source File +# Begin Source File + +SOURCE=..\Agent\UpdateCallbackAgent.h +# End Source File +# End Group +# Begin Group "Explorer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Explorer\ContextMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\Explorer\ContextMenu.h +# End Source File +# Begin Source File + +SOURCE=..\Explorer\ContextMenuFlags.h +# End Source File +# Begin Source File + +SOURCE=..\Explorer\MyExplorerCommand.h +# End Source File +# Begin Source File + +SOURCE=..\Explorer\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=..\Explorer\MyMessages.h +# End Source File +# Begin Source File + +SOURCE=..\Explorer\RegistryContextMenu.cpp +# End Source File +# Begin Source File + +SOURCE=..\Explorer\RegistryContextMenu.h +# End Source File +# End Group +# Begin Group "GUI" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\GUI\HashGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\GUI\HashGUI.h +# End Source File +# Begin Source File + +SOURCE=..\GUI\UpdateCallbackGUI2.cpp +# End Source File +# Begin Source File + +SOURCE=..\GUI\UpdateCallbackGUI2.h +# End Source File +# End Group +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IPassword.h +# End Source File +# Begin Source File + +SOURCE=..\..\IProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\PropID.h +# End Source File +# End Group +# Begin Group "ArchiveCommon" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\7zFM.exe.manifest +# End Source File +# Begin Source File + +SOURCE=.\7zipLogo.ico +# End Source File +# Begin Source File + +SOURCE=.\Add2.bmp +# End Source File +# Begin Source File + +SOURCE=.\Copy2.bmp +# End Source File +# Begin Source File + +SOURCE=.\Delete2.bmp +# End Source File +# Begin Source File + +SOURCE=.\Extract2.bmp +# End Source File +# Begin Source File + +SOURCE=.\FilePlugins.cpp +# End Source File +# Begin Source File + +SOURCE=.\FilePlugins.h +# End Source File +# Begin Source File + +SOURCE=.\FM.cpp +# End Source File +# Begin Source File + +SOURCE=.\Info.bmp +# End Source File +# Begin Source File + +SOURCE=.\Info2.bmp +# End Source File +# Begin Source File + +SOURCE=.\Move2.bmp +# End Source File +# Begin Source File + +SOURCE=.\MyCom2.h +# End Source File +# Begin Source File + +SOURCE=.\MyLoadMenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\MyLoadMenu.h +# End Source File +# Begin Source File + +SOURCE=.\OpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=.\OpenCallback.h +# End Source File +# Begin Source File + +SOURCE=.\PluginInterface.h +# End Source File +# Begin Source File + +SOURCE=.\PluginLoader.h +# End Source File +# Begin Source File + +SOURCE=.\PropertyName.cpp +# End Source File +# Begin Source File + +SOURCE=.\PropertyName.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\SplitUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\SplitUtils.h +# End Source File +# Begin Source File + +SOURCE=.\StringUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\StringUtils.h +# End Source File +# Begin Source File + +SOURCE=.\SysIconUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\SysIconUtils.h +# End Source File +# Begin Source File + +SOURCE=.\Test2.bmp +# End Source File +# Begin Source File + +SOURCE=.\TextPairs.cpp +# End Source File +# Begin Source File + +SOURCE=.\TextPairs.h +# End Source File +# End Target +# End Project diff --git a/CPP/7zip/UI/FileManager/FM.dsw b/CPP/7zip/UI/FileManager/FM.dsw index 38f65d224..1c955d956 100644 --- a/CPP/7zip/UI/FileManager/FM.dsw +++ b/CPP/7zip/UI/FileManager/FM.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "FM"=.\FM.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "FM"=.\FM.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/UI/FileManager/FM.mak b/CPP/7zip/UI/FileManager/FM.mak index d068c814f..d8e2469a8 100644 --- a/CPP/7zip/UI/FileManager/FM.mak +++ b/CPP/7zip/UI/FileManager/FM.mak @@ -1,103 +1,103 @@ -CFLAGS = $(CFLAGS) \ - -DZ7_LANG \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) ceshell.lib Commctrl.lib -!ELSE -LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib -CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE -# -DZ7_LONG_PATH -LFLAGS = $(LFLAGS) /DELAYLOAD:mpr.dll -LIBS = $(LIBS) delayimp.lib -!ENDIF - -FM_OBJS = \ - $O\App.obj \ - $O\BrowseDialog.obj \ - $O\BrowseDialog2.obj \ - $O\ClassDefs.obj \ - $O\EnumFormatEtc.obj \ - $O\ExtractCallback.obj \ - $O\FileFolderPluginOpen.obj \ - $O\FilePlugins.obj \ - $O\FM.obj \ - $O\FoldersPage.obj \ - $O\FormatUtils.obj \ - $O\FSFolder.obj \ - $O\FSFolderCopy.obj \ - $O\HelpUtils.obj \ - $O\LangUtils.obj \ - $O\MemDialog.obj \ - $O\MenuPage.obj \ - $O\MyLoadMenu.obj \ - $O\OpenCallback.obj \ - $O\OptionsDialog.obj \ - $O\Panel.obj \ - $O\PanelCopy.obj \ - $O\PanelCrc.obj \ - $O\PanelDrag.obj \ - $O\PanelFolderChange.obj \ - $O\PanelItemOpen.obj \ - $O\PanelItems.obj \ - $O\PanelKey.obj \ - $O\PanelListNotify.obj \ - $O\PanelMenu.obj \ - $O\PanelOperations.obj \ - $O\PanelSelect.obj \ - $O\PanelSort.obj \ - $O\PanelSplitFile.obj \ - $O\ProgramLocation.obj \ - $O\PropertyName.obj \ - $O\RegistryAssociations.obj \ - $O\RegistryUtils.obj \ - $O\RootFolder.obj \ - $O\SplitUtils.obj \ - $O\StringUtils.obj \ - $O\SysIconUtils.obj \ - $O\TextPairs.obj \ - $O\UpdateCallback100.obj \ - $O\ViewSettings.obj \ - $O\AboutDialog.obj \ - $O\ComboDialog.obj \ - $O\CopyDialog.obj \ - $O\EditDialog.obj \ - $O\EditPage.obj \ - $O\LangPage.obj \ - $O\ListViewDialog.obj \ - $O\MessagesDialog.obj \ - $O\OverwriteDialog.obj \ - $O\PasswordDialog.obj \ - $O\ProgressDialog2.obj \ - $O\SettingsPage.obj \ - $O\SplitDialog.obj \ - $O\SystemPage.obj \ - $O\VerCtrl.obj \ - -!IFNDEF UNDER_CE - -FM_OBJS = $(FM_OBJS) \ - $O\AltStreamsFolder.obj \ - $O\FSDrives.obj \ - $O\LinkDialog.obj \ - $O\NetFolder.obj \ - -WIN_OBJS = $(WIN_OBJS) \ - $O\FileSystem.obj \ - $O\Net.obj \ - $O\SecurityUtils.obj \ - -!ENDIF - -C_OBJS = $(C_OBJS) \ - $O\DllSecur.obj \ - -AGENT_OBJS = \ - $O\Agent.obj \ - $O\AgentOut.obj \ - $O\AgentProxy.obj \ - $O\ArchiveFolder.obj \ - $O\ArchiveFolderOpen.obj \ - $O\ArchiveFolderOut.obj \ - $O\UpdateCallbackAgent.obj \ - -# we need empty line after last line above +CFLAGS = $(CFLAGS) \ + -DZ7_LANG \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) ceshell.lib Commctrl.lib +!ELSE +LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib +CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE +# -DZ7_LONG_PATH +LFLAGS = $(LFLAGS) /DELAYLOAD:mpr.dll +LIBS = $(LIBS) delayimp.lib +!ENDIF + +FM_OBJS = \ + $O\App.obj \ + $O\BrowseDialog.obj \ + $O\BrowseDialog2.obj \ + $O\ClassDefs.obj \ + $O\EnumFormatEtc.obj \ + $O\ExtractCallback.obj \ + $O\FileFolderPluginOpen.obj \ + $O\FilePlugins.obj \ + $O\FM.obj \ + $O\FoldersPage.obj \ + $O\FormatUtils.obj \ + $O\FSFolder.obj \ + $O\FSFolderCopy.obj \ + $O\HelpUtils.obj \ + $O\LangUtils.obj \ + $O\MemDialog.obj \ + $O\MenuPage.obj \ + $O\MyLoadMenu.obj \ + $O\OpenCallback.obj \ + $O\OptionsDialog.obj \ + $O\Panel.obj \ + $O\PanelCopy.obj \ + $O\PanelCrc.obj \ + $O\PanelDrag.obj \ + $O\PanelFolderChange.obj \ + $O\PanelItemOpen.obj \ + $O\PanelItems.obj \ + $O\PanelKey.obj \ + $O\PanelListNotify.obj \ + $O\PanelMenu.obj \ + $O\PanelOperations.obj \ + $O\PanelSelect.obj \ + $O\PanelSort.obj \ + $O\PanelSplitFile.obj \ + $O\ProgramLocation.obj \ + $O\PropertyName.obj \ + $O\RegistryAssociations.obj \ + $O\RegistryUtils.obj \ + $O\RootFolder.obj \ + $O\SplitUtils.obj \ + $O\StringUtils.obj \ + $O\SysIconUtils.obj \ + $O\TextPairs.obj \ + $O\UpdateCallback100.obj \ + $O\ViewSettings.obj \ + $O\AboutDialog.obj \ + $O\ComboDialog.obj \ + $O\CopyDialog.obj \ + $O\EditDialog.obj \ + $O\EditPage.obj \ + $O\LangPage.obj \ + $O\ListViewDialog.obj \ + $O\MessagesDialog.obj \ + $O\OverwriteDialog.obj \ + $O\PasswordDialog.obj \ + $O\ProgressDialog2.obj \ + $O\SettingsPage.obj \ + $O\SplitDialog.obj \ + $O\SystemPage.obj \ + $O\VerCtrl.obj \ + +!IFNDEF UNDER_CE + +FM_OBJS = $(FM_OBJS) \ + $O\AltStreamsFolder.obj \ + $O\FSDrives.obj \ + $O\LinkDialog.obj \ + $O\NetFolder.obj \ + +WIN_OBJS = $(WIN_OBJS) \ + $O\FileSystem.obj \ + $O\Net.obj \ + $O\SecurityUtils.obj \ + +!ENDIF + +C_OBJS = $(C_OBJS) \ + $O\DllSecur.obj \ + +AGENT_OBJS = \ + $O\Agent.obj \ + $O\AgentOut.obj \ + $O\AgentProxy.obj \ + $O\ArchiveFolder.obj \ + $O\ArchiveFolderOpen.obj \ + $O\ArchiveFolderOut.obj \ + $O\UpdateCallbackAgent.obj \ + +# we need empty line after last line above diff --git a/CPP/7zip/UI/FileManager/FSDrives.cpp b/CPP/7zip/UI/FileManager/FSDrives.cpp index d80c6db16..70354c7f9 100644 --- a/CPP/7zip/UI/FileManager/FSDrives.cpp +++ b/CPP/7zip/UI/FileManager/FSDrives.cpp @@ -1,512 +1,512 @@ -// FSDrives.cpp - -#include "StdAfx.h" - -#include "../../../../C/Alloc.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/Defs.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileSystem.h" -#include "../../../Windows/PropVariant.h" - -#include "../../PropID.h" - -#include "FSDrives.h" -#include "FSFolder.h" -#include "LangUtils.h" -#include "SysIconUtils.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NFind; - -static const char * const kVolPrefix = "\\\\.\\"; -static const char * const kSuperPrefix = "\\\\?\\"; - -FString CDriveInfo::GetDeviceFileIoName() const -{ - FString f (kVolPrefix); - f += Name; - return f; -} - -struct CPhysTempBuffer -{ - void *buffer; - CPhysTempBuffer(): buffer(NULL) {} - ~CPhysTempBuffer() { MidFree(buffer); } -}; - -static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, - bool writeToDisk, UInt64 fileSize, - UInt32 bufferSize, UInt64 progressStart, IProgress *progress) -{ - NIO::CInFile inFile; - if (!inFile.Open(fromPath)) - return GetLastError_noZero_HRESULT(); - if (fileSize == (UInt64)(Int64)-1) - { - if (!inFile.GetLength(fileSize)) - return GetLastError_noZero_HRESULT(); - } - - NIO::COutFile outFile; - if (writeToDisk) - { - if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0)) - return GetLastError_noZero_HRESULT(); - } - else - if (!outFile.Create_ALWAYS(toPath)) - return GetLastError_noZero_HRESULT(); - - CPhysTempBuffer tempBuffer; - tempBuffer.buffer = MidAlloc(bufferSize); - if (!tempBuffer.buffer) - return E_OUTOFMEMORY; - - for (UInt64 pos = 0; pos < fileSize;) - { - { - const UInt64 progressCur = progressStart + pos; - RINOK(progress->SetCompleted(&progressCur)) - } - const UInt64 rem = fileSize - pos; - UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize); - UInt32 processedSize; - if (!inFile.Read(tempBuffer.buffer, curSize, processedSize)) - return GetLastError_noZero_HRESULT(); - if (processedSize == 0) - break; - curSize = processedSize; - if (writeToDisk) - { - const UInt32 kMask = 0x1FF; - curSize = (curSize + kMask) & ~kMask; - if (curSize > bufferSize) - return E_FAIL; - } - if (!outFile.Write(tempBuffer.buffer, curSize, processedSize)) - return GetLastError_noZero_HRESULT(); - if (curSize != processedSize) - return E_FAIL; - pos += curSize; - } - - return S_OK; -} - -static const Byte kProps[] = -{ - kpidName, - // kpidOutName, - kpidTotalSize, - kpidFreeSpace, - kpidType, - kpidVolumeName, - kpidFileSystem, - kpidClusterSize -}; - -static const char * const kDriveTypes[] = -{ - "Unknown" - , "No Root Dir" - , "Removable" - , "Fixed" - , "Remote" - , "CD-ROM" - , "RAM disk" -}; - -Z7_COM7F_IMF(CFSDrives::LoadItems()) -{ - _drives.Clear(); - - FStringVector driveStrings; - MyGetLogicalDriveStrings(driveStrings); - - FOR_VECTOR (i, driveStrings) - { - CDriveInfo di; - const FString &driveName = driveStrings[i]; - di.FullSystemName = driveName; - if (!driveName.IsEmpty()) - di.Name.SetFrom(driveName, driveName.Len() - 1); - di.ClusterSize = 0; - di.DriveSize = 0; - di.FreeSpace = 0; - di.DriveType = NSystem::MyGetDriveType(driveName); - bool needRead = true; - - if (di.DriveType == DRIVE_CDROM || di.DriveType == DRIVE_REMOVABLE) - { - /* - DWORD dwSerialNumber;` - if (!::GetVolumeInformation(di.FullSystemName, - NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0)) - */ - { - needRead = false; - } - } - - if (needRead) - { - DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags; - NSystem::MyGetVolumeInformation(driveName, - di.VolumeName, - &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags, - di.FileSystemName); - - NSystem::MyGetDiskFreeSpace(driveName, - di.ClusterSize, di.DriveSize, di.FreeSpace); - di.KnownSizes = true; - di.KnownSize = true; - } - - _drives.Add(di); - } - - if (_volumeMode) - { - // we must use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS - for (unsigned n = 0; n < 16; n++) // why 16 ? - { - FString name ("PhysicalDrive"); - name.Add_UInt32(n); - FString fullPath (kVolPrefix); - fullPath += name; - CFileInfo fi; - if (!fi.Find(fullPath)) - continue; - - CDriveInfo di; - di.Name = name; - // if (_volumeMode == true) we use CDriveInfo::FullSystemName only in GetSystemIconIndex(). - // And we need name without "\\\\.\\" prefix in GetSystemIconIndex(). - // So we don't set di.FullSystemName = fullPath; - di.FullSystemName = name; - di.ClusterSize = 0; - di.DriveSize = fi.Size; - di.FreeSpace = 0; - di.DriveType = 0; - di.IsPhysicalDrive = true; - di.KnownSize = true; - _drives.Add(di); - } - } - - return S_OK; -} - -Z7_COM7F_IMF(CFSDrives::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _drives.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) -{ - if (itemIndex >= _drives.Size()) - return E_INVALIDARG; - NCOM::CPropVariant prop; - const CDriveInfo &di = _drives[itemIndex]; - switch (propID) - { - case kpidIsDir: prop = !_volumeMode; break; - case kpidName: prop = fs2us(di.Name); break; - case kpidOutName: - if (!di.Name.IsEmpty() && di.Name.Back() == ':') - { - FString s = di.Name; - s.DeleteBack(); - AddExt(s, itemIndex); - prop = fs2us(s); - } - break; - - case kpidTotalSize: if (di.KnownSize) prop = di.DriveSize; break; - case kpidFreeSpace: if (di.KnownSizes) prop = di.FreeSpace; break; - case kpidClusterSize: if (di.KnownSizes) prop = di.ClusterSize; break; - case kpidType: - if (di.DriveType < Z7_ARRAY_SIZE(kDriveTypes)) - prop = kDriveTypes[di.DriveType]; - break; - case kpidVolumeName: prop = di.VolumeName; break; - case kpidFileSystem: prop = di.FileSystemName; break; - } - prop.Detach(value); - return S_OK; -} - -HRESULT CFSDrives::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder) -{ - *resultFolder = NULL; - if (_volumeMode) - return S_OK; - NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; - CMyComPtr subFolder = fsFolderSpec; - FString path; - if (_superMode) - path = kSuperPrefix; - path += name; - RINOK(fsFolderSpec->Init(path)) - *resultFolder = subFolder.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - if (index >= _drives.Size()) - return E_INVALIDARG; - const CDriveInfo &di = _drives[index]; - /* - if (_volumeMode) - { - *resultFolder = 0; - CPhysDriveFolder *folderSpec = new CPhysDriveFolder; - CMyComPtr subFolder = folderSpec; - RINOK(folderSpec->Init(di.Name)); - *resultFolder = subFolder.Detach(); - return S_OK; - } - */ - return BindToFolderSpec(di.FullSystemName, resultFolder); -} - -Z7_COM7F_IMF(CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) -{ - return BindToFolderSpec(us2fs(name), resultFolder); -} - -Z7_COM7F_IMF(CFSDrives::BindToParentFolder(IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - return S_OK; -} - -IMP_IFolderFolder_Props(CFSDrives) - -Z7_COM7F_IMF(CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NCOM::CPropVariant prop; - switch (propID) - { - case kpidType: prop = "FSDrives"; break; - case kpidPath: - if (_volumeMode) - prop = kVolPrefix; - else if (_superMode) - prop = kSuperPrefix; - else - prop = (UString)LangString(IDS_COMPUTER) + WCHAR_PATH_SEPARATOR; - break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - - -Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) -{ - *iconIndex = -1; - const CDriveInfo &di = _drives[index]; - return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - di.FullSystemName, - _volumeMode ? - FILE_ATTRIBUTE_ARCHIVE: - FILE_ATTRIBUTE_DIRECTORY, - iconIndex); -} - -void CFSDrives::AddExt(FString &s, unsigned index) const -{ - s.Add_Dot(); - const CDriveInfo &di = _drives[index]; - UString n = di.FileSystemName; - n.MakeLower_Ascii(); - const char *ext; - if (di.DriveType == DRIVE_CDROM) - ext = "iso"; - else - { - unsigned i; - for (i = 0; i < n.Len(); i++) - { - const wchar_t c = n[i]; - if (c < 'a' || c > 'z') - break; - } - if (i != 0) - { - n.DeleteFrom(i); - s += us2fs(n); - return; - } - ext = "img"; - } - /* - if (n.IsPrefixedBy_Ascii_NoCase("NTFS")) ext = "ntfs"; - else if (n.IsPrefixedBy_Ascii_NoCase("UDF")) ext = "udf"; - else if (n.IsPrefixedBy_Ascii_NoCase("exFAT")) ext = "exfat"; - */ - s += ext; -} - -HRESULT CFSDrives::GetFileSize(unsigned index, UInt64& fileSize) const -{ -#ifdef Z7_DEVICE_FILE - NIO::CInFile inFile; - if (!inFile.Open(_drives[index].GetDeviceFileIoName())) - return GetLastError_noZero_HRESULT(); - if (inFile.SizeDefined) - { - fileSize = inFile.Size; - return S_OK; - } -#else - UNUSED_VAR(index) -#endif - fileSize = 0; - return E_FAIL; -} - -Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, - Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */, - const wchar_t *path, IFolderOperationsExtractCallback *callback)) -{ - if (numItems == 0) - return S_OK; - if (moveMode) - return E_NOTIMPL; - if (!_volumeMode) - return E_NOTIMPL; - - UInt64 totalSize = 0; - UInt32 i; - for (i = 0; i < numItems; i++) - { - const CDriveInfo &di = _drives[indices[i]]; - if (di.KnownSize) - totalSize += di.DriveSize; - } - RINOK(callback->SetTotal(totalSize)) - RINOK(callback->SetNumFiles(numItems)) - - const FString destPath = us2fs(path); - if (destPath.IsEmpty()) - return E_INVALIDARG; - - const bool isAltDest = NName::IsAltPathPrefix(destPath); - const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); - - if (isDirectPath) - { - if (numItems > 1) - return E_INVALIDARG; - } - - UInt64 completedSize = 0; - RINOK(callback->SetCompleted(&completedSize)) - for (i = 0; i < numItems; i++) - { - const unsigned index = indices[i]; - const CDriveInfo &di = _drives[index]; - FString destPath2 = destPath; - - if (!isDirectPath) - { - FString destName = di.Name; - if (!destName.IsEmpty() && destName.Back() == ':') - { - destName.DeleteBack(); - AddExt(destName, index); - } - destPath2 += destName; - } - - const FString srcPath = di.GetDeviceFileIoName(); - - UInt64 fileSize = 0; - if (GetFileSize(index, fileSize) != S_OK) - { - return E_FAIL; - } - if (!di.KnownSize) - { - totalSize += fileSize; - RINOK(callback->SetTotal(totalSize)) - } - - Int32 writeAskResult; - CMyComBSTR destPathResult; - RINOK(callback->AskWrite(fs2us(srcPath), BoolToInt(false), NULL, &fileSize, - fs2us(destPath2), &destPathResult, &writeAskResult)) - - if (!IntToBool(writeAskResult)) - { - if (totalSize >= fileSize) - totalSize -= fileSize; - RINOK(callback->SetTotal(totalSize)) - continue; - } - - RINOK(callback->SetCurrentFilePath(fs2us(srcPath))) - - const UInt32 kBufferSize = (4 << 20); - const UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize; - RINOK(CopyFileSpec(srcPath, us2fs(destPathResult), false, fileSize, bufferSize, completedSize, callback)) - completedSize += fileSize; - } - - return S_OK; -} - -Z7_COM7F_IMF(CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, - const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */, - const PROPVARIANT * /* value */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} +// FSDrives.cpp + +#include "StdAfx.h" + +#include "../../../../C/Alloc.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/Defs.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileSystem.h" +#include "../../../Windows/PropVariant.h" + +#include "../../PropID.h" + +#include "FSDrives.h" +#include "FSFolder.h" +#include "LangUtils.h" +#include "SysIconUtils.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NFind; + +static const char * const kVolPrefix = "\\\\.\\"; +static const char * const kSuperPrefix = "\\\\?\\"; + +FString CDriveInfo::GetDeviceFileIoName() const +{ + FString f (kVolPrefix); + f += Name; + return f; +} + +struct CPhysTempBuffer +{ + void *buffer; + CPhysTempBuffer(): buffer(NULL) {} + ~CPhysTempBuffer() { MidFree(buffer); } +}; + +static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, + bool writeToDisk, UInt64 fileSize, + UInt32 bufferSize, UInt64 progressStart, IProgress *progress) +{ + NIO::CInFile inFile; + if (!inFile.Open(fromPath)) + return GetLastError_noZero_HRESULT(); + if (fileSize == (UInt64)(Int64)-1) + { + if (!inFile.GetLength(fileSize)) + return GetLastError_noZero_HRESULT(); + } + + NIO::COutFile outFile; + if (writeToDisk) + { + if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0)) + return GetLastError_noZero_HRESULT(); + } + else + if (!outFile.Create_ALWAYS(toPath)) + return GetLastError_noZero_HRESULT(); + + CPhysTempBuffer tempBuffer; + tempBuffer.buffer = MidAlloc(bufferSize); + if (!tempBuffer.buffer) + return E_OUTOFMEMORY; + + for (UInt64 pos = 0; pos < fileSize;) + { + { + const UInt64 progressCur = progressStart + pos; + RINOK(progress->SetCompleted(&progressCur)) + } + const UInt64 rem = fileSize - pos; + UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize); + UInt32 processedSize; + if (!inFile.Read(tempBuffer.buffer, curSize, processedSize)) + return GetLastError_noZero_HRESULT(); + if (processedSize == 0) + break; + curSize = processedSize; + if (writeToDisk) + { + const UInt32 kMask = 0x1FF; + curSize = (curSize + kMask) & ~kMask; + if (curSize > bufferSize) + return E_FAIL; + } + if (!outFile.Write(tempBuffer.buffer, curSize, processedSize)) + return GetLastError_noZero_HRESULT(); + if (curSize != processedSize) + return E_FAIL; + pos += curSize; + } + + return S_OK; +} + +static const Byte kProps[] = +{ + kpidName, + // kpidOutName, + kpidTotalSize, + kpidFreeSpace, + kpidType, + kpidVolumeName, + kpidFileSystem, + kpidClusterSize +}; + +static const char * const kDriveTypes[] = +{ + "Unknown" + , "No Root Dir" + , "Removable" + , "Fixed" + , "Remote" + , "CD-ROM" + , "RAM disk" +}; + +Z7_COM7F_IMF(CFSDrives::LoadItems()) +{ + _drives.Clear(); + + FStringVector driveStrings; + MyGetLogicalDriveStrings(driveStrings); + + FOR_VECTOR (i, driveStrings) + { + CDriveInfo di; + const FString &driveName = driveStrings[i]; + di.FullSystemName = driveName; + if (!driveName.IsEmpty()) + di.Name.SetFrom(driveName, driveName.Len() - 1); + di.ClusterSize = 0; + di.DriveSize = 0; + di.FreeSpace = 0; + di.DriveType = NSystem::MyGetDriveType(driveName); + bool needRead = true; + + if (di.DriveType == DRIVE_CDROM || di.DriveType == DRIVE_REMOVABLE) + { + /* + DWORD dwSerialNumber;` + if (!::GetVolumeInformation(di.FullSystemName, + NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0)) + */ + { + needRead = false; + } + } + + if (needRead) + { + DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags; + NSystem::MyGetVolumeInformation(driveName, + di.VolumeName, + &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags, + di.FileSystemName); + + NSystem::MyGetDiskFreeSpace(driveName, + di.ClusterSize, di.DriveSize, di.FreeSpace); + di.KnownSizes = true; + di.KnownSize = true; + } + + _drives.Add(di); + } + + if (_volumeMode) + { + // we must use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS + for (unsigned n = 0; n < 16; n++) // why 16 ? + { + FString name ("PhysicalDrive"); + name.Add_UInt32(n); + FString fullPath (kVolPrefix); + fullPath += name; + CFileInfo fi; + if (!fi.Find(fullPath)) + continue; + + CDriveInfo di; + di.Name = name; + // if (_volumeMode == true) we use CDriveInfo::FullSystemName only in GetSystemIconIndex(). + // And we need name without "\\\\.\\" prefix in GetSystemIconIndex(). + // So we don't set di.FullSystemName = fullPath; + di.FullSystemName = name; + di.ClusterSize = 0; + di.DriveSize = fi.Size; + di.FreeSpace = 0; + di.DriveType = 0; + di.IsPhysicalDrive = true; + di.KnownSize = true; + _drives.Add(di); + } + } + + return S_OK; +} + +Z7_COM7F_IMF(CFSDrives::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _drives.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) +{ + if (itemIndex >= _drives.Size()) + return E_INVALIDARG; + NCOM::CPropVariant prop; + const CDriveInfo &di = _drives[itemIndex]; + switch (propID) + { + case kpidIsDir: prop = !_volumeMode; break; + case kpidName: prop = fs2us(di.Name); break; + case kpidOutName: + if (!di.Name.IsEmpty() && di.Name.Back() == ':') + { + FString s = di.Name; + s.DeleteBack(); + AddExt(s, itemIndex); + prop = fs2us(s); + } + break; + + case kpidTotalSize: if (di.KnownSize) prop = di.DriveSize; break; + case kpidFreeSpace: if (di.KnownSizes) prop = di.FreeSpace; break; + case kpidClusterSize: if (di.KnownSizes) prop = di.ClusterSize; break; + case kpidType: + if (di.DriveType < Z7_ARRAY_SIZE(kDriveTypes)) + prop = kDriveTypes[di.DriveType]; + break; + case kpidVolumeName: prop = di.VolumeName; break; + case kpidFileSystem: prop = di.FileSystemName; break; + } + prop.Detach(value); + return S_OK; +} + +HRESULT CFSDrives::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder) +{ + *resultFolder = NULL; + if (_volumeMode) + return S_OK; + NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; + CMyComPtr subFolder = fsFolderSpec; + FString path; + if (_superMode) + path = kSuperPrefix; + path += name; + RINOK(fsFolderSpec->Init(path)) + *resultFolder = subFolder.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + if (index >= _drives.Size()) + return E_INVALIDARG; + const CDriveInfo &di = _drives[index]; + /* + if (_volumeMode) + { + *resultFolder = 0; + CPhysDriveFolder *folderSpec = new CPhysDriveFolder; + CMyComPtr subFolder = folderSpec; + RINOK(folderSpec->Init(di.Name)); + *resultFolder = subFolder.Detach(); + return S_OK; + } + */ + return BindToFolderSpec(di.FullSystemName, resultFolder); +} + +Z7_COM7F_IMF(CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) +{ + return BindToFolderSpec(us2fs(name), resultFolder); +} + +Z7_COM7F_IMF(CFSDrives::BindToParentFolder(IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + return S_OK; +} + +IMP_IFolderFolder_Props(CFSDrives) + +Z7_COM7F_IMF(CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidType: prop = "FSDrives"; break; + case kpidPath: + if (_volumeMode) + prop = kVolPrefix; + else if (_superMode) + prop = kSuperPrefix; + else + prop = (UString)LangString(IDS_COMPUTER) + WCHAR_PATH_SEPARATOR; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) +{ + *iconIndex = -1; + const CDriveInfo &di = _drives[index]; + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + di.FullSystemName, + _volumeMode ? + FILE_ATTRIBUTE_ARCHIVE: + FILE_ATTRIBUTE_DIRECTORY, + iconIndex); +} + +void CFSDrives::AddExt(FString &s, unsigned index) const +{ + s.Add_Dot(); + const CDriveInfo &di = _drives[index]; + UString n = di.FileSystemName; + n.MakeLower_Ascii(); + const char *ext; + if (di.DriveType == DRIVE_CDROM) + ext = "iso"; + else + { + unsigned i; + for (i = 0; i < n.Len(); i++) + { + const wchar_t c = n[i]; + if (c < 'a' || c > 'z') + break; + } + if (i != 0) + { + n.DeleteFrom(i); + s += us2fs(n); + return; + } + ext = "img"; + } + /* + if (n.IsPrefixedBy_Ascii_NoCase("NTFS")) ext = "ntfs"; + else if (n.IsPrefixedBy_Ascii_NoCase("UDF")) ext = "udf"; + else if (n.IsPrefixedBy_Ascii_NoCase("exFAT")) ext = "exfat"; + */ + s += ext; +} + +HRESULT CFSDrives::GetFileSize(unsigned index, UInt64& fileSize) const +{ +#ifdef Z7_DEVICE_FILE + NIO::CInFile inFile; + if (!inFile.Open(_drives[index].GetDeviceFileIoName())) + return GetLastError_noZero_HRESULT(); + if (inFile.SizeDefined) + { + fileSize = inFile.Size; + return S_OK; + } +#else + UNUSED_VAR(index) +#endif + fileSize = 0; + return E_FAIL; +} + +Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, + Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */, + const wchar_t *path, IFolderOperationsExtractCallback *callback)) +{ + if (numItems == 0) + return S_OK; + if (moveMode) + return E_NOTIMPL; + if (!_volumeMode) + return E_NOTIMPL; + + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const CDriveInfo &di = _drives[indices[i]]; + if (di.KnownSize) + totalSize += di.DriveSize; + } + RINOK(callback->SetTotal(totalSize)) + RINOK(callback->SetNumFiles(numItems)) + + const FString destPath = us2fs(path); + if (destPath.IsEmpty()) + return E_INVALIDARG; + + const bool isAltDest = NName::IsAltPathPrefix(destPath); + const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); + + if (isDirectPath) + { + if (numItems > 1) + return E_INVALIDARG; + } + + UInt64 completedSize = 0; + RINOK(callback->SetCompleted(&completedSize)) + for (i = 0; i < numItems; i++) + { + const unsigned index = indices[i]; + const CDriveInfo &di = _drives[index]; + FString destPath2 = destPath; + + if (!isDirectPath) + { + FString destName = di.Name; + if (!destName.IsEmpty() && destName.Back() == ':') + { + destName.DeleteBack(); + AddExt(destName, index); + } + destPath2 += destName; + } + + const FString srcPath = di.GetDeviceFileIoName(); + + UInt64 fileSize = 0; + if (GetFileSize(index, fileSize) != S_OK) + { + return E_FAIL; + } + if (!di.KnownSize) + { + totalSize += fileSize; + RINOK(callback->SetTotal(totalSize)) + } + + Int32 writeAskResult; + CMyComBSTR destPathResult; + RINOK(callback->AskWrite(fs2us(srcPath), BoolToInt(false), NULL, &fileSize, + fs2us(destPath2), &destPathResult, &writeAskResult)) + + if (!IntToBool(writeAskResult)) + { + if (totalSize >= fileSize) + totalSize -= fileSize; + RINOK(callback->SetTotal(totalSize)) + continue; + } + + RINOK(callback->SetCurrentFilePath(fs2us(srcPath))) + + const UInt32 kBufferSize = (4 << 20); + const UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize; + RINOK(CopyFileSpec(srcPath, us2fs(destPathResult), false, fileSize, bufferSize, completedSize, callback)) + completedSize += fileSize; + } + + return S_OK; +} + +Z7_COM7F_IMF(CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, + const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */, + const PROPVARIANT * /* value */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} diff --git a/CPP/7zip/UI/FileManager/FSDrives.h b/CPP/7zip/UI/FileManager/FSDrives.h index c6576f6d5..8ae831cf0 100644 --- a/CPP/7zip/UI/FileManager/FSDrives.h +++ b/CPP/7zip/UI/FileManager/FSDrives.h @@ -1,52 +1,52 @@ -// FSDrives.h - -#ifndef ZIP7_INC_FS_DRIVES_H -#define ZIP7_INC_FS_DRIVES_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyString.h" - -#include "IFolder.h" - -struct CDriveInfo -{ - FString Name; - FString FullSystemName; - UInt64 DriveSize; - UInt64 FreeSpace; - UInt64 ClusterSize; - // UString Type; - UString VolumeName; - UString FileSystemName; - UINT DriveType; - - bool KnownSize; - bool KnownSizes; - bool IsPhysicalDrive; - - FString GetDeviceFileIoName() const; - CDriveInfo(): KnownSize(false), KnownSizes(false), IsPhysicalDrive(false) {} -}; - -Z7_CLASS_IMP_NOQIB_3( - CFSDrives - , IFolderFolder - , IFolderOperations - , IFolderGetSystemIconIndex -) - CObjectVector _drives; - bool _volumeMode; - bool _superMode; - - HRESULT BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder); - void AddExt(FString &s, unsigned index) const; - HRESULT GetFileSize(unsigned index, UInt64 &fileSize) const; -public: - void Init(bool volMode = false, bool superMode = false) - { - _volumeMode = volMode; - _superMode = superMode; - } -}; - -#endif +// FSDrives.h + +#ifndef ZIP7_INC_FS_DRIVES_H +#define ZIP7_INC_FS_DRIVES_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" + +#include "IFolder.h" + +struct CDriveInfo +{ + FString Name; + FString FullSystemName; + UInt64 DriveSize; + UInt64 FreeSpace; + UInt64 ClusterSize; + // UString Type; + UString VolumeName; + UString FileSystemName; + UINT DriveType; + + bool KnownSize; + bool KnownSizes; + bool IsPhysicalDrive; + + FString GetDeviceFileIoName() const; + CDriveInfo(): KnownSize(false), KnownSizes(false), IsPhysicalDrive(false) {} +}; + +Z7_CLASS_IMP_NOQIB_3( + CFSDrives + , IFolderFolder + , IFolderOperations + , IFolderGetSystemIconIndex +) + CObjectVector _drives; + bool _volumeMode; + bool _superMode; + + HRESULT BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder); + void AddExt(FString &s, unsigned index) const; + HRESULT GetFileSize(unsigned index, UInt64 &fileSize) const; +public: + void Init(bool volMode = false, bool superMode = false) + { + _volumeMode = volMode; + _superMode = superMode; + } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp index e528bb5d8..7956d8624 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.cpp +++ b/CPP/7zip/UI/FileManager/FSFolder.cpp @@ -1,1197 +1,1197 @@ -// FSFolder.cpp - -#include "StdAfx.h" - -#ifdef __MINGW32_VERSION -// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) -// for old mingw -#include -#else -#ifndef Z7_OLD_WIN_SDK - #if !defined(_M_IA64) - #include - #endif -#else -typedef LONG NTSTATUS; -typedef struct _IO_STATUS_BLOCK { - union { - NTSTATUS Status; - PVOID Pointer; - }; - ULONG_PTR Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; -#endif -#endif - -#include "../../../Common/ComTry.h" -#include "../../../Common/Defs.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "../../PropID.h" - -#include "FSDrives.h" -#include "FSFolder.h" - -#ifndef UNDER_CE -#include "NetFolder.h" -#endif - -#include "SysIconUtils.h" - -#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501 -#ifdef _APISETFILE_ -// Windows SDK 8.1 defines in fileapi.h the function GetCompressedFileSizeW only if _WIN32_WINNT >= 0x0501 -// But real support version for that function is NT 3.1 (probably) -// So we must define GetCompressedFileSizeW -EXTERN_C_BEGIN -WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName, LPDWORD lpFileSizeHigh); -EXTERN_C_END -#endif -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NFind; -using namespace NDir; -using namespace NName; - -#ifndef USE_UNICODE_FSTRING -int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); -int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2) -{ - return CompareFileNames_ForFolderList(fs2us(s1), fs2us(s2)); -} -#endif - -namespace NFsFolder { - -static const Byte kProps[] = -{ - kpidName, - kpidSize, - kpidMTime, - kpidCTime, - kpidATime, - #ifdef FS_SHOW_LINKS_INFO - kpidChangeTime, - #endif - kpidAttrib, - kpidPackSize, - #ifdef FS_SHOW_LINKS_INFO - kpidINode, - kpidLinks, - #endif - kpidComment, - kpidNumSubDirs, - kpidNumSubFiles, - kpidPrefix -}; - -HRESULT CFSFolder::Init(const FString &path /* , IFolderFolder *parentFolder */) -{ - // _parentFolder = parentFolder; - _path = path; - - #ifdef _WIN32 - - _findChangeNotification.FindFirst(_path, false, - FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_ATTRIBUTES - | FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_LAST_WRITE - /* - | FILE_NOTIFY_CHANGE_LAST_ACCESS - | FILE_NOTIFY_CHANGE_CREATION - | FILE_NOTIFY_CHANGE_SECURITY - */ - ); - - if (!_findChangeNotification.IsHandleAllocated()) - { - const HRESULT lastError = GetLastError_noZero_HRESULT(); - CFindFile findFile; - CFileInfo fi; - FString path2 = _path; - path2.Add_Char('*'); // CHAR_ANY_MASK; - if (!findFile.FindFirst(path2, fi)) - return lastError; - } - - #endif - - return S_OK; -} - - -HRESULT CFsFolderStat::Enumerate() -{ - if (Progress) - { - RINOK(Progress->SetCompleted(NULL)) - } - Path.Add_PathSepar(); - const unsigned len = Path.Len(); - CEnumerator enumerator; - enumerator.SetDirPrefix(Path); - CDirEntry fi; - while (enumerator.Next(fi)) - { - if (fi.IsDir()) - { - NumFolders++; - Path.DeleteFrom(len); - Path += fi.Name; - RINOK(Enumerate()) - } - else - { - NumFiles++; - Size += fi.Size; - } - } - return S_OK; -} - -#ifndef UNDER_CE - -bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size); -bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size) -{ - DWORD highPart; - DWORD lowPart = INVALID_FILE_SIZE; - IF_USE_MAIN_PATH - { - lowPart = ::GetCompressedFileSizeW(fs2us(path), &highPart); - if (lowPart != INVALID_FILE_SIZE || ::GetLastError() == NO_ERROR) - { - size = ((UInt64)highPart << 32) | lowPart; - return true; - } - } - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - { - lowPart = ::GetCompressedFileSizeW(superPath, &highPart); - if (lowPart != INVALID_FILE_SIZE || ::GetLastError() == NO_ERROR) - { - size = ((UInt64)highPart << 32) | lowPart; - return true; - } - } - } - #endif - return false; -} - -#endif - -HRESULT CFSFolder::LoadSubItems(int dirItem, const FString &relPrefix) -{ - const unsigned startIndex = Folders.Size(); - { - CEnumerator enumerator; - enumerator.SetDirPrefix(_path + relPrefix); - CDirItem fi; - fi.FolderStat_Defined = false; - fi.NumFolders = 0; - fi.NumFiles = 0; - fi.Parent = dirItem; - - while (enumerator.Next(fi)) - { - if (fi.IsDir()) - { - fi.Size = 0; - if (_flatMode) - Folders.Add(relPrefix + fi.Name + FCHAR_PATH_SEPARATOR); - } - else - { - /* - fi.PackSize_Defined = true; - if (!MyGetCompressedFileSizeW(_path + relPrefix + fi.Name, fi.PackSize)) - fi.PackSize = fi.Size; - */ - } - - #ifndef UNDER_CE - - fi.Reparse.Free(); - fi.PackSize_Defined = false; - - #ifdef FS_SHOW_LINKS_INFO - fi.FileInfo_Defined = false; - fi.FileInfo_WasRequested = false; - fi.FileIndex = 0; - fi.NumLinks = 0; - fi.ChangeTime_Defined = false; - fi.ChangeTime_WasRequested = false; - #endif - - fi.PackSize = fi.Size; - - #ifdef FS_SHOW_LINKS_INFO - if (fi.HasReparsePoint()) - { - fi.FileInfo_WasRequested = true; - BY_HANDLE_FILE_INFORMATION info; - NIO::GetReparseData(_path + relPrefix + fi.Name, fi.Reparse, &info); - fi.NumLinks = info.nNumberOfLinks; - fi.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; - fi.FileInfo_Defined = true; - } - #endif - - #endif // UNDER_CE - - /* unsigned fileIndex = */ Files.Add(fi); - - #if defined(_WIN32) && !defined(UNDER_CE) - /* - if (_scanAltStreams) - { - CStreamEnumerator enumerator(_path + relPrefix + fi.Name); - CStreamInfo si; - for (;;) - { - bool found; - if (!enumerator.Next(si, found)) - { - // if (GetLastError() == ERROR_ACCESS_DENIED) - // break; - // return E_FAIL; - break; - } - if (!found) - break; - if (si.IsMainStream()) - continue; - CAltStream ss; - ss.Parent = fileIndex; - ss.Name = si.GetReducedName(); - ss.Size = si.Size; - ss.PackSize_Defined = false; - ss.PackSize = si.Size; - Streams.Add(ss); - } - } - */ - #endif - } - } - if (!_flatMode) - return S_OK; - - const unsigned endIndex = Folders.Size(); - for (unsigned i = startIndex; i < endIndex; i++) - LoadSubItems((int)i, Folders[i]); - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::LoadItems()) -{ - Int32 dummy; - WasChanged(&dummy); - Clear(); - RINOK(LoadSubItems(-1, FString())) - _commentsAreLoaded = false; - return S_OK; -} - -static CFSTR const kDescriptionFileName = FTEXT("descript.ion"); - -bool CFSFolder::LoadComments() -{ - _comments.Clear(); - _commentsAreLoaded = true; - NIO::CInFile file; - if (!file.Open(_path + kDescriptionFileName)) - return false; - UInt64 len; - if (!file.GetLength(len)) - return false; - if (len >= (1 << 28)) - return false; - AString s; - char *p = s.GetBuf((unsigned)(size_t)len); - size_t processedSize; - if (!file.ReadFull(p, (unsigned)(size_t)len, processedSize)) - return false; - s.ReleaseBuf_CalcLen((unsigned)(size_t)len); - if (processedSize != len) - return false; - file.Close(); - UString unicodeString; - if (!ConvertUTF8ToUnicode(s, unicodeString)) - return false; - return _comments.ReadFromString(unicodeString); -} - -bool CFSFolder::SaveComments() -{ - AString utf; - { - UString unicode; - _comments.SaveToString(unicode); - ConvertUnicodeToUTF8(unicode, utf); - } - if (!utf.IsAscii()) - utf.Insert(0, "\xEF\xBB\xBF" "\r\n"); - - FString path = _path + kDescriptionFileName; - // We must set same attrib. COutFile::CreateAlways can fail, if file has another attrib. - DWORD attrib = FILE_ATTRIBUTE_NORMAL; - { - CFileInfo fi; - if (fi.Find(path)) - attrib = fi.Attrib; - } - NIO::COutFile file; - if (!file.Create_ALWAYS_with_Attribs(path, attrib)) - return false; - UInt32 processed; - file.Write(utf, utf.Len(), processed); - _commentsAreLoaded = false; - return true; -} - -Z7_COM7F_IMF(CFSFolder::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = Files.Size() /* + Streams.Size() */; - return S_OK; -} - -#ifdef USE_UNICODE_FSTRING - -Z7_COM7F_IMF(CFSFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) -{ - *name = NULL; - *len = 0; - /* - if (index >= Files.Size()) - index = Streams[index - Files.Size()].Parent; - */ - CDirItem &fi = Files[index]; - if (fi.Parent >= 0) - { - const FString &fo = Folders[fi.Parent]; - USE_UNICODE_FSTRING - *name = fo; - *len = fo.Len(); - } - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) -{ - *name = NULL; - *len = 0; - if (index < Files.Size()) - { - CDirItem &fi = Files[index]; - *name = fi.Name; - *len = fi.Name.Len(); - return S_OK; - } - else - { - // const CAltStream &ss = Streams[index - Files.Size()]; - // *name = ss.Name; - // *len = ss.Name.Len(); - // - // change it; - } - return S_OK; -} - -Z7_COM7F_IMF2(UInt64, CFSFolder::GetItemSize(UInt32 index)) -{ - /* - if (index >= Files.Size()) - return Streams[index - Files.Size()].Size; - */ - CDirItem &fi = Files[index]; - return fi.IsDir() ? 0 : fi.Size; -} - -#endif - - -#ifdef FS_SHOW_LINKS_INFO - -bool CFSFolder::ReadFileInfo(CDirItem &di) -{ - di.FileInfo_WasRequested = true; - BY_HANDLE_FILE_INFORMATION info; - memset(&info, 0, sizeof(info)); // for vc6-O2 - if (!NIO::CFileBase::GetFileInformation(_path + GetRelPath(di), &info)) - return false; - di.NumLinks = info.nNumberOfLinks; - di.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; - di.FileInfo_Defined = true; - return true; -} - - -EXTERN_C_BEGIN - -typedef struct -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - ULONG FileAttributes; - UInt32 Reserved; // it's expected for alignment -} -Z7_WIN_FILE_BASIC_INFORMATION; - - -typedef enum -{ - Z7_WIN_FileDirectoryInformation = 1, - Z7_WIN_FileFullDirectoryInformation, - Z7_WIN_FileBothDirectoryInformation, - Z7_WIN_FileBasicInformation -} -Z7_WIN_FILE_INFORMATION_CLASS; - - -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) -#define Z7_WIN_NTSTATUS NTSTATUS -#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK -#else -typedef LONG Z7_WIN_NTSTATUS; -typedef struct -{ - union - { - Z7_WIN_NTSTATUS Status; - PVOID Pointer; - } DUMMYUNIONNAME; - ULONG_PTR Information; -} Z7_WIN_IO_STATUS_BLOCK; -#endif - - -typedef Z7_WIN_NTSTATUS (WINAPI * Func_NtQueryInformationFile)( - HANDLE handle, Z7_WIN_IO_STATUS_BLOCK *io, - void *ptr, LONG len, Z7_WIN_FILE_INFORMATION_CLASS cls); - -#define MY_STATUS_SUCCESS 0 - -EXTERN_C_END - -static Func_NtQueryInformationFile f_NtQueryInformationFile; -static bool g_NtQueryInformationFile_WasRequested = false; - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -void CFSFolder::ReadChangeTime(CDirItem &di) -{ - di.ChangeTime_WasRequested = true; - - if (!g_NtQueryInformationFile_WasRequested) - { - g_NtQueryInformationFile_WasRequested = true; - f_NtQueryInformationFile = Z7_GET_PROC_ADDRESS( - Func_NtQueryInformationFile, ::GetModuleHandleW(L"ntdll.dll"), - "NtQueryInformationFile"); - } - if (!f_NtQueryInformationFile) - return; - - NIO::CInFile file; - if (!file.Open_for_ReadAttributes(_path + GetRelPath(di))) - return; - Z7_WIN_FILE_BASIC_INFORMATION fbi; - Z7_WIN_IO_STATUS_BLOCK IoStatusBlock; - const Z7_WIN_NTSTATUS status = f_NtQueryInformationFile(file.GetHandle(), &IoStatusBlock, - &fbi, sizeof(fbi), Z7_WIN_FileBasicInformation); - if (status != MY_STATUS_SUCCESS) - return; - if (IoStatusBlock.Information != sizeof(fbi)) - return; - di.ChangeTime.dwLowDateTime = fbi.ChangeTime.u.LowPart; - di.ChangeTime.dwHighDateTime = (DWORD)fbi.ChangeTime.u.HighPart; - di.ChangeTime_Defined = true; -} - -#endif // FS_SHOW_LINKS_INFO - - -Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - /* - if (index >= Files.Size()) - { - CAltStream &ss = Streams[index - Files.Size()]; - CDirItem &fi = Files[ss.Parent]; - switch (propID) - { - case kpidIsDir: prop = false; break; - case kpidIsAltStream: prop = true; break; - case kpidName: prop = fs2us(fi.Name) + ss.Name; break; - case kpidSize: prop = ss.Size; break; - case kpidPackSize: - #ifdef UNDER_CE - prop = ss.Size; - #else - if (!ss.PackSize_Defined) - { - ss.PackSize_Defined = true; - if (!MyGetCompressedFileSizeW(_path + GetRelPath(fi) + us2fs(ss.Name), ss.PackSize)) - ss.PackSize = ss.Size; - } - prop = ss.PackSize; - #endif - break; - case kpidComment: break; - default: index = ss.Parent; - } - if (index >= Files.Size()) - { - prop.Detach(value); - return S_OK; - } - } - */ - CDirItem &fi = Files[index]; - switch (propID) - { - case kpidIsDir: prop = fi.IsDir(); break; - case kpidIsAltStream: prop = false; break; - case kpidName: prop = fs2us(fi.Name); break; - case kpidSize: if (!fi.IsDir() || fi.FolderStat_Defined) prop = fi.Size; break; - case kpidPackSize: - #ifdef UNDER_CE - prop = fi.Size; - #else - if (!fi.PackSize_Defined) - { - fi.PackSize_Defined = true; - if (fi.IsDir () || !MyGetCompressedFileSizeW(_path + GetRelPath(fi), fi.PackSize)) - fi.PackSize = fi.Size; - } - prop = fi.PackSize; - #endif - break; - - #ifdef FS_SHOW_LINKS_INFO - - case kpidLinks: - #ifdef UNDER_CE - // prop = fi.NumLinks; - #else - if (!fi.FileInfo_WasRequested) - ReadFileInfo(fi); - if (fi.FileInfo_Defined) - prop = fi.NumLinks; - #endif - break; - - case kpidINode: - #ifdef UNDER_CE - // prop = fi.FileIndex; - #else - if (!fi.FileInfo_WasRequested) - ReadFileInfo(fi); - if (fi.FileInfo_Defined) - prop = fi.FileIndex; - #endif - break; - - case kpidChangeTime: - if (!fi.ChangeTime_WasRequested) - ReadChangeTime(fi); - if (fi.ChangeTime_Defined) - prop = fi.ChangeTime; - break; - - #endif - - case kpidAttrib: prop = (UInt32)fi.Attrib; break; - case kpidCTime: prop = fi.CTime; break; - case kpidATime: prop = fi.ATime; break; - case kpidMTime: prop = fi.MTime; break; - case kpidComment: - { - if (!_commentsAreLoaded) - LoadComments(); - UString comment; - if (_comments.GetValue(fs2us(GetRelPath(fi)), comment)) - { - int pos = comment.Find((wchar_t)4); - if (pos >= 0) - comment.DeleteFrom((unsigned)pos); - prop = comment; - } - break; - } - case kpidPrefix: - if (fi.Parent >= 0) - prop = fs2us(Folders[fi.Parent]); - break; - case kpidNumSubDirs: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFolders; break; - case kpidNumSubFiles: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFiles; break; - } - prop.Detach(value); - return S_OK; -} - - -// ---------- IArchiveGetRawProps ---------- - - -Z7_COM7F_IMF(CFSFolder::GetNumRawProps(UInt32 *numProps)) -{ - *numProps = 1; - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) -{ - *name = NULL; - *propID = kpidNtReparse; - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */)) -{ - return E_FAIL; -} - -Z7_COM7F_IMF(CFSFolder::GetRawProp(UInt32 index, PROPID propID, - const void **data, UInt32 *dataSize, UInt32 *propType)) -{ - #ifdef UNDER_CE - UNUSED(index) - UNUSED(propID) - #endif - - *data = NULL; - *dataSize = 0; - *propType = 0; - - #ifndef UNDER_CE - if (propID == kpidNtReparse) - { - const CDirItem &fi = Files[index]; - const CByteBuffer &buf = fi.Reparse; - if (buf.Size() == 0) - return S_OK; - *data = buf; - *dataSize = (UInt32)buf.Size(); - *propType = NPropDataType::kRaw; - return S_OK; - } - #endif - - return S_OK; -} - - -// returns Position of extension including '.' - -static inline CFSTR GetExtensionPtr(const FString &name) -{ - const int dotPos = name.ReverseFind_Dot(); - return name.Ptr((dotPos < 0) ? name.Len() : (unsigned)dotPos); -} - -Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */)) -{ - /* - const CAltStream *ss1 = NULL; - const CAltStream *ss2 = NULL; - if (index1 >= Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; } - if (index2 >= Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; } - */ - CDirItem &fi1 = Files[index1]; - CDirItem &fi2 = Files[index2]; - - switch (propID) - { - case kpidName: - { - const int comp = CompareFileNames_ForFolderList(fi1.Name, fi2.Name); - /* - if (comp != 0) - return comp; - if (!ss1) - return ss2 ? -1 : 0; - if (!ss2) - return 1; - return MyStringCompareNoCase(ss1->Name, ss2->Name); - */ - return comp; - } - case kpidSize: - return MyCompare( - /* ss1 ? ss1->Size : */ fi1.Size, - /* ss2 ? ss2->Size : */ fi2.Size); - case kpidAttrib: return MyCompare(fi1.Attrib, fi2.Attrib); - case kpidCTime: return CompareFileTime(&fi1.CTime, &fi2.CTime); - case kpidATime: return CompareFileTime(&fi1.ATime, &fi2.ATime); - case kpidMTime: return CompareFileTime(&fi1.MTime, &fi2.MTime); - case kpidIsDir: - { - bool isDir1 = /* ss1 ? false : */ fi1.IsDir(); - bool isDir2 = /* ss2 ? false : */ fi2.IsDir(); - if (isDir1 == isDir2) - return 0; - return isDir1 ? -1 : 1; - } - case kpidPackSize: - { - #ifdef UNDER_CE - return MyCompare(fi1.Size, fi2.Size); - #else - // PackSize can be undefined here - return MyCompare( - /* ss1 ? ss1->PackSize : */ fi1.PackSize, - /* ss2 ? ss2->PackSize : */ fi2.PackSize); - #endif - } - - #ifdef FS_SHOW_LINKS_INFO - case kpidINode: - { - #ifndef UNDER_CE - if (!fi1.FileInfo_WasRequested) ReadFileInfo(fi1); - if (!fi2.FileInfo_WasRequested) ReadFileInfo(fi2); - return MyCompare( - fi1.FileIndex, - fi2.FileIndex); - #endif - } - case kpidLinks: - { - #ifndef UNDER_CE - if (!fi1.FileInfo_WasRequested) ReadFileInfo(fi1); - if (!fi2.FileInfo_WasRequested) ReadFileInfo(fi2); - return MyCompare( - fi1.NumLinks, - fi2.NumLinks); - #endif - } - #endif - - case kpidComment: - { - // change it ! - UString comment1, comment2; - _comments.GetValue(fs2us(GetRelPath(fi1)), comment1); - _comments.GetValue(fs2us(GetRelPath(fi2)), comment2); - return MyStringCompareNoCase(comment1, comment2); - } - case kpidPrefix: - if (fi1.Parent < 0) return (fi2.Parent < 0) ? 0 : -1; - if (fi2.Parent < 0) return 1; - return CompareFileNames_ForFolderList( - Folders[fi1.Parent], - Folders[fi2.Parent]); - case kpidExtension: - return CompareFileNames_ForFolderList( - GetExtensionPtr(fi1.Name), - GetExtensionPtr(fi2.Name)); - } - - return 0; -} - -HRESULT CFSFolder::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder) -{ - *resultFolder = NULL; - CFSFolder *folderSpec = new CFSFolder; - CMyComPtr subFolder = folderSpec; - RINOK(folderSpec->Init(_path + name + FCHAR_PATH_SEPARATOR)) - *resultFolder = subFolder.Detach(); - return S_OK; -} - -/* -void CFSFolder::GetPrefix(const CDirItem &item, FString &prefix) const -{ - if (item.Parent >= 0) - prefix = Folders[item.Parent]; - else - prefix.Empty(); -} -*/ - -/* -void CFSFolder::GetPrefix(const CDirItem &item, FString &prefix) const -{ - int parent = item.Parent; - - unsigned len = 0; - - while (parent >= 0) - { - const CDirItem &cur = Files[parent]; - len += cur.Name.Len() + 1; - parent = cur.Parent; - } - - wchar_t *p = prefix.GetBuf_SetEnd(len) + len; - parent = item.Parent; - - while (parent >= 0) - { - const CDirItem &cur = Files[parent]; - *(--p) = FCHAR_PATH_SEPARATOR; - p -= cur.Name.Len(); - wmemcpy(p, cur.Name, cur.Name.Len()); - parent = cur.Parent; - } -} -*/ - -FString CFSFolder::GetRelPath(const CDirItem &item) const -{ - if (item.Parent < 0) - return item.Name; - return Folders[item.Parent] + item.Name; -} - -Z7_COM7F_IMF(CFSFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - const CDirItem &fi = Files[index]; - if (!fi.IsDir()) - return E_INVALIDARG; - return BindToFolderSpec(GetRelPath(fi), resultFolder); -} - -Z7_COM7F_IMF(CFSFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) -{ - return BindToFolderSpec(us2fs(name), resultFolder); -} - -Z7_COM7F_IMF(CFSFolder::BindToParentFolder(IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - /* - if (_parentFolder) - { - CMyComPtr parentFolder = _parentFolder; - *resultFolder = parentFolder.Detach(); - return S_OK; - } - */ - if (_path.IsEmpty()) - return E_INVALIDARG; - - #ifndef UNDER_CE - - if (IsDriveRootPath_SuperAllowed(_path)) - { - CFSDrives *drivesFolderSpec = new CFSDrives; - CMyComPtr drivesFolder = drivesFolderSpec; - drivesFolderSpec->Init(false, IsSuperPath(_path)); - *resultFolder = drivesFolder.Detach(); - return S_OK; - } - - int pos = _path.ReverseFind_PathSepar(); - if (pos < 0 || pos != (int)_path.Len() - 1) - return E_FAIL; - FString parentPath = _path.Left((unsigned)pos); - pos = parentPath.ReverseFind_PathSepar(); - parentPath.DeleteFrom((unsigned)(pos + 1)); - - if (NName::IsDrivePath_SuperAllowed(parentPath)) - { - CFSFolder *parentFolderSpec = new CFSFolder; - CMyComPtr parentFolder = parentFolderSpec; - if (parentFolderSpec->Init(parentPath) == S_OK) - { - *resultFolder = parentFolder.Detach(); - return S_OK; - } - } - - /* - FString parentPathReduced = parentPath.Left(pos); - - pos = parentPathReduced.ReverseFind_PathSepar(); - if (pos == 1) - { - if (!IS_PATH_SEPAR_CHAR(parentPath[0])) - return E_FAIL; - CNetFolder *netFolderSpec = new CNetFolder; - CMyComPtr netFolder = netFolderSpec; - netFolderSpec->Init(fs2us(parentPath)); - *resultFolder = netFolder.Detach(); - return S_OK; - } - */ - - #endif - - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::GetNumberOfProperties(UInt32 *numProperties)) -{ - *numProperties = Z7_ARRAY_SIZE(kProps); - if (!_flatMode) - (*numProperties)--; - return S_OK; -} - -IMP_IFolderFolder_GetProp(CFSFolder::GetPropertyInfo, kProps) - -Z7_COM7F_IMF(CFSFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) -{ - COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidType: prop = "FSFolder"; break; - case kpidPath: prop = fs2us(_path); break; - } - prop.Detach(value); - return S_OK; - COM_TRY_END -} - -Z7_COM7F_IMF(CFSFolder::WasChanged(Int32 *wasChanged)) -{ - bool wasChangedMain = false; - - #ifdef _WIN32 - - for (;;) - { - if (!_findChangeNotification.IsHandleAllocated()) - break; - DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); - if (waitResult != WAIT_OBJECT_0) - break; - _findChangeNotification.FindNext(); - wasChangedMain = true; - } - - #endif - - *wasChanged = BoolToInt(wasChangedMain); - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::Clone(IFolderFolder **resultFolder)) -{ - CFSFolder *fsFolderSpec = new CFSFolder; - CMyComPtr folderNew = fsFolderSpec; - fsFolderSpec->Init(_path); - *resultFolder = folderNew.Detach(); - return S_OK; -} - - -/* -HRESULT CFSFolder::GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress) -{ - if (index >= Files.Size()) - { - size = Streams[index - Files.Size()].Size; - return S_OK; - } - const CDirItem &fi = Files[index]; - if (fi.IsDir()) - { - UInt64 numFolders = 0, numFiles = 0; - size = 0; - return GetFolderSize(_path + GetRelPath(fi), numFolders, numFiles, size, progress); - } - size = fi.Size; - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress) -{ - NCOM::CPropVariant prop; - UInt64 size = 0; - HRESULT result = GetItemFullSize(index, size, progress); - prop = size; - prop.Detach(value); - return result; -} -*/ - -Z7_COM7F_IMF(CFSFolder::CalcItemFullSize(UInt32 index, IProgress *progress)) -{ - if (index >= Files.Size()) - return S_OK; - CDirItem &fi = Files[index]; - if (!fi.IsDir()) - return S_OK; - CFsFolderStat stat(_path + GetRelPath(fi), progress); - RINOK(stat.Enumerate()) - fi.Size = stat.Size; - fi.NumFolders = stat.NumFolders; - fi.NumFiles = stat.NumFiles; - fi.FolderStat_Defined = true; - return S_OK; -} - -void CFSFolder::GetAbsPath(const wchar_t *name, FString &absPath) -{ - absPath.Empty(); - if (!IsAbsolutePath(name)) - absPath += _path; - absPath += us2fs(name); -} - -Z7_COM7F_IMF(CFSFolder::CreateFolder(const wchar_t *name, IProgress * /* progress */)) -{ - FString absPath; - GetAbsPath(name, absPath); - if (CreateDir(absPath)) - return S_OK; - if (::GetLastError() != ERROR_ALREADY_EXISTS) - if (CreateComplexDir(absPath)) - return S_OK; - return GetLastError_noZero_HRESULT(); -} - -Z7_COM7F_IMF(CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress */)) -{ - FString absPath; - GetAbsPath(name, absPath); - NIO::COutFile outFile; - if (!outFile.Create_NEW(absPath)) - return GetLastError_noZero_HRESULT(); - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::Rename(UInt32 index, const wchar_t *newName, IProgress * /* progress */)) -{ - if (index >= Files.Size()) - return E_NOTIMPL; - const CDirItem &fi = Files[index]; - // FString prefix; - // GetPrefix(fi, prefix); - FString fullPrefix = _path; - if (fi.Parent >= 0) - fullPrefix += Folders[fi.Parent]; - if (!MyMoveFile(fullPrefix + fi.Name, fullPrefix + us2fs(newName))) - return GetLastError_noZero_HRESULT(); - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress)) -{ - RINOK(progress->SetTotal(numItems)) - // int prevDeletedFileIndex = -1; - for (UInt32 i = 0; i < numItems; i++) - { - // Sleep(200); - UInt32 index = indices[i]; - bool result = true; - /* - if (index >= Files.Size()) - { - const CAltStream &ss = Streams[index - Files.Size()]; - if (prevDeletedFileIndex != ss.Parent) - { - const CDirItem &fi = Files[ss.Parent]; - result = DeleteFileAlways(_path + GetRelPath(fi) + us2fs(ss.Name)); - } - } - else - */ - { - const CDirItem &fi = Files[index]; - const FString fullPath = _path + GetRelPath(fi); - // prevDeletedFileIndex = index; - if (fi.IsDir()) - result = RemoveDirWithSubItems(fullPath); - else - result = DeleteFileAlways(fullPath); - } - if (!result) - return GetLastError_noZero_HRESULT(); - const UInt64 completed = i; - RINOK(progress->SetCompleted(&completed)) - } - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::SetProperty(UInt32 index, PROPID propID, - const PROPVARIANT *value, IProgress * /* progress */)) -{ - if (index >= Files.Size()) - return E_INVALIDARG; - CDirItem &fi = Files[index]; - if (fi.Parent >= 0) - return E_NOTIMPL; - switch (propID) - { - case kpidComment: - { - UString filename = fs2us(fi.Name); - filename.Trim(); - if (value->vt == VT_EMPTY) - _comments.DeletePair(filename); - else if (value->vt == VT_BSTR) - { - CTextPair pair; - pair.ID = filename; - pair.ID.Trim(); - pair.Value.SetFromBstr(value->bstrVal); - pair.Value.Trim(); - if (pair.Value.IsEmpty()) - _comments.DeletePair(filename); - else - _comments.AddPair(pair); - } - else - return E_INVALIDARG; - SaveComments(); - break; - } - default: - return E_NOTIMPL; - } - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) -{ - *iconIndex = -1; - if (index >= Files.Size()) - return E_INVALIDARG; - const CDirItem &fi = Files[index]; - return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - _path + GetRelPath(fi), fi.Attrib, iconIndex); -} - -Z7_COM7F_IMF(CFSFolder::SetFlatMode(Int32 flatMode)) -{ - _flatMode = IntToBool(flatMode); - return S_OK; -} - -/* -Z7_COM7F_IMF(CFSFolder::SetShowNtfsStreamsMode(Int32 showStreamsMode) -{ - _scanAltStreams = IntToBool(showStreamsMode); - return S_OK; -} -*/ - -} +// FSFolder.cpp + +#include "StdAfx.h" + +#ifdef __MINGW32_VERSION +// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) +// for old mingw +#include +#else +#ifndef Z7_OLD_WIN_SDK + #if !defined(_M_IA64) + #include + #endif +#else +typedef LONG NTSTATUS; +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +#endif +#endif + +#include "../../../Common/ComTry.h" +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "../../PropID.h" + +#include "FSDrives.h" +#include "FSFolder.h" + +#ifndef UNDER_CE +#include "NetFolder.h" +#endif + +#include "SysIconUtils.h" + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501 +#ifdef _APISETFILE_ +// Windows SDK 8.1 defines in fileapi.h the function GetCompressedFileSizeW only if _WIN32_WINNT >= 0x0501 +// But real support version for that function is NT 3.1 (probably) +// So we must define GetCompressedFileSizeW +EXTERN_C_BEGIN +WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName, LPDWORD lpFileSizeHigh); +EXTERN_C_END +#endif +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NFind; +using namespace NDir; +using namespace NName; + +#ifndef USE_UNICODE_FSTRING +int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); +int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2) +{ + return CompareFileNames_ForFolderList(fs2us(s1), fs2us(s2)); +} +#endif + +namespace NFsFolder { + +static const Byte kProps[] = +{ + kpidName, + kpidSize, + kpidMTime, + kpidCTime, + kpidATime, + #ifdef FS_SHOW_LINKS_INFO + kpidChangeTime, + #endif + kpidAttrib, + kpidPackSize, + #ifdef FS_SHOW_LINKS_INFO + kpidINode, + kpidLinks, + #endif + kpidComment, + kpidNumSubDirs, + kpidNumSubFiles, + kpidPrefix +}; + +HRESULT CFSFolder::Init(const FString &path /* , IFolderFolder *parentFolder */) +{ + // _parentFolder = parentFolder; + _path = path; + + #ifdef _WIN32 + + _findChangeNotification.FindFirst(_path, false, + FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_LAST_WRITE + /* + | FILE_NOTIFY_CHANGE_LAST_ACCESS + | FILE_NOTIFY_CHANGE_CREATION + | FILE_NOTIFY_CHANGE_SECURITY + */ + ); + + if (!_findChangeNotification.IsHandleAllocated()) + { + const HRESULT lastError = GetLastError_noZero_HRESULT(); + CFindFile findFile; + CFileInfo fi; + FString path2 = _path; + path2.Add_Char('*'); // CHAR_ANY_MASK; + if (!findFile.FindFirst(path2, fi)) + return lastError; + } + + #endif + + return S_OK; +} + + +HRESULT CFsFolderStat::Enumerate() +{ + if (Progress) + { + RINOK(Progress->SetCompleted(NULL)) + } + Path.Add_PathSepar(); + const unsigned len = Path.Len(); + CEnumerator enumerator; + enumerator.SetDirPrefix(Path); + CDirEntry fi; + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + { + NumFolders++; + Path.DeleteFrom(len); + Path += fi.Name; + RINOK(Enumerate()) + } + else + { + NumFiles++; + Size += fi.Size; + } + } + return S_OK; +} + +#ifndef UNDER_CE + +bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size); +bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size) +{ + DWORD highPart; + DWORD lowPart = INVALID_FILE_SIZE; + IF_USE_MAIN_PATH + { + lowPart = ::GetCompressedFileSizeW(fs2us(path), &highPart); + if (lowPart != INVALID_FILE_SIZE || ::GetLastError() == NO_ERROR) + { + size = ((UInt64)highPart << 32) | lowPart; + return true; + } + } + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + { + lowPart = ::GetCompressedFileSizeW(superPath, &highPart); + if (lowPart != INVALID_FILE_SIZE || ::GetLastError() == NO_ERROR) + { + size = ((UInt64)highPart << 32) | lowPart; + return true; + } + } + } + #endif + return false; +} + +#endif + +HRESULT CFSFolder::LoadSubItems(int dirItem, const FString &relPrefix) +{ + const unsigned startIndex = Folders.Size(); + { + CEnumerator enumerator; + enumerator.SetDirPrefix(_path + relPrefix); + CDirItem fi; + fi.FolderStat_Defined = false; + fi.NumFolders = 0; + fi.NumFiles = 0; + fi.Parent = dirItem; + + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + { + fi.Size = 0; + if (_flatMode) + Folders.Add(relPrefix + fi.Name + FCHAR_PATH_SEPARATOR); + } + else + { + /* + fi.PackSize_Defined = true; + if (!MyGetCompressedFileSizeW(_path + relPrefix + fi.Name, fi.PackSize)) + fi.PackSize = fi.Size; + */ + } + + #ifndef UNDER_CE + + fi.Reparse.Free(); + fi.PackSize_Defined = false; + + #ifdef FS_SHOW_LINKS_INFO + fi.FileInfo_Defined = false; + fi.FileInfo_WasRequested = false; + fi.FileIndex = 0; + fi.NumLinks = 0; + fi.ChangeTime_Defined = false; + fi.ChangeTime_WasRequested = false; + #endif + + fi.PackSize = fi.Size; + + #ifdef FS_SHOW_LINKS_INFO + if (fi.HasReparsePoint()) + { + fi.FileInfo_WasRequested = true; + BY_HANDLE_FILE_INFORMATION info; + NIO::GetReparseData(_path + relPrefix + fi.Name, fi.Reparse, &info); + fi.NumLinks = info.nNumberOfLinks; + fi.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; + fi.FileInfo_Defined = true; + } + #endif + + #endif // UNDER_CE + + /* unsigned fileIndex = */ Files.Add(fi); + + #if defined(_WIN32) && !defined(UNDER_CE) + /* + if (_scanAltStreams) + { + CStreamEnumerator enumerator(_path + relPrefix + fi.Name); + CStreamInfo si; + for (;;) + { + bool found; + if (!enumerator.Next(si, found)) + { + // if (GetLastError() == ERROR_ACCESS_DENIED) + // break; + // return E_FAIL; + break; + } + if (!found) + break; + if (si.IsMainStream()) + continue; + CAltStream ss; + ss.Parent = fileIndex; + ss.Name = si.GetReducedName(); + ss.Size = si.Size; + ss.PackSize_Defined = false; + ss.PackSize = si.Size; + Streams.Add(ss); + } + } + */ + #endif + } + } + if (!_flatMode) + return S_OK; + + const unsigned endIndex = Folders.Size(); + for (unsigned i = startIndex; i < endIndex; i++) + LoadSubItems((int)i, Folders[i]); + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::LoadItems()) +{ + Int32 dummy; + WasChanged(&dummy); + Clear(); + RINOK(LoadSubItems(-1, FString())) + _commentsAreLoaded = false; + return S_OK; +} + +static CFSTR const kDescriptionFileName = FTEXT("descript.ion"); + +bool CFSFolder::LoadComments() +{ + _comments.Clear(); + _commentsAreLoaded = true; + NIO::CInFile file; + if (!file.Open(_path + kDescriptionFileName)) + return false; + UInt64 len; + if (!file.GetLength(len)) + return false; + if (len >= (1 << 28)) + return false; + AString s; + char *p = s.GetBuf((unsigned)(size_t)len); + size_t processedSize; + if (!file.ReadFull(p, (unsigned)(size_t)len, processedSize)) + return false; + s.ReleaseBuf_CalcLen((unsigned)(size_t)len); + if (processedSize != len) + return false; + file.Close(); + UString unicodeString; + if (!ConvertUTF8ToUnicode(s, unicodeString)) + return false; + return _comments.ReadFromString(unicodeString); +} + +bool CFSFolder::SaveComments() +{ + AString utf; + { + UString unicode; + _comments.SaveToString(unicode); + ConvertUnicodeToUTF8(unicode, utf); + } + if (!utf.IsAscii()) + utf.Insert(0, "\xEF\xBB\xBF" "\r\n"); + + FString path = _path + kDescriptionFileName; + // We must set same attrib. COutFile::CreateAlways can fail, if file has another attrib. + DWORD attrib = FILE_ATTRIBUTE_NORMAL; + { + CFileInfo fi; + if (fi.Find(path)) + attrib = fi.Attrib; + } + NIO::COutFile file; + if (!file.Create_ALWAYS_with_Attribs(path, attrib)) + return false; + UInt32 processed; + file.Write(utf, utf.Len(), processed); + _commentsAreLoaded = false; + return true; +} + +Z7_COM7F_IMF(CFSFolder::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = Files.Size() /* + Streams.Size() */; + return S_OK; +} + +#ifdef USE_UNICODE_FSTRING + +Z7_COM7F_IMF(CFSFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) +{ + *name = NULL; + *len = 0; + /* + if (index >= Files.Size()) + index = Streams[index - Files.Size()].Parent; + */ + CDirItem &fi = Files[index]; + if (fi.Parent >= 0) + { + const FString &fo = Folders[fi.Parent]; + USE_UNICODE_FSTRING + *name = fo; + *len = fo.Len(); + } + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) +{ + *name = NULL; + *len = 0; + if (index < Files.Size()) + { + CDirItem &fi = Files[index]; + *name = fi.Name; + *len = fi.Name.Len(); + return S_OK; + } + else + { + // const CAltStream &ss = Streams[index - Files.Size()]; + // *name = ss.Name; + // *len = ss.Name.Len(); + // + // change it; + } + return S_OK; +} + +Z7_COM7F_IMF2(UInt64, CFSFolder::GetItemSize(UInt32 index)) +{ + /* + if (index >= Files.Size()) + return Streams[index - Files.Size()].Size; + */ + CDirItem &fi = Files[index]; + return fi.IsDir() ? 0 : fi.Size; +} + +#endif + + +#ifdef FS_SHOW_LINKS_INFO + +bool CFSFolder::ReadFileInfo(CDirItem &di) +{ + di.FileInfo_WasRequested = true; + BY_HANDLE_FILE_INFORMATION info; + memset(&info, 0, sizeof(info)); // for vc6-O2 + if (!NIO::CFileBase::GetFileInformation(_path + GetRelPath(di), &info)) + return false; + di.NumLinks = info.nNumberOfLinks; + di.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; + di.FileInfo_Defined = true; + return true; +} + + +EXTERN_C_BEGIN + +typedef struct +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; + UInt32 Reserved; // it's expected for alignment +} +Z7_WIN_FILE_BASIC_INFORMATION; + + +typedef enum +{ + Z7_WIN_FileDirectoryInformation = 1, + Z7_WIN_FileFullDirectoryInformation, + Z7_WIN_FileBothDirectoryInformation, + Z7_WIN_FileBasicInformation +} +Z7_WIN_FILE_INFORMATION_CLASS; + + +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) +#define Z7_WIN_NTSTATUS NTSTATUS +#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK +#else +typedef LONG Z7_WIN_NTSTATUS; +typedef struct +{ + union + { + Z7_WIN_NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} Z7_WIN_IO_STATUS_BLOCK; +#endif + + +typedef Z7_WIN_NTSTATUS (WINAPI * Func_NtQueryInformationFile)( + HANDLE handle, Z7_WIN_IO_STATUS_BLOCK *io, + void *ptr, LONG len, Z7_WIN_FILE_INFORMATION_CLASS cls); + +#define MY_STATUS_SUCCESS 0 + +EXTERN_C_END + +static Func_NtQueryInformationFile f_NtQueryInformationFile; +static bool g_NtQueryInformationFile_WasRequested = false; + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +void CFSFolder::ReadChangeTime(CDirItem &di) +{ + di.ChangeTime_WasRequested = true; + + if (!g_NtQueryInformationFile_WasRequested) + { + g_NtQueryInformationFile_WasRequested = true; + f_NtQueryInformationFile = Z7_GET_PROC_ADDRESS( + Func_NtQueryInformationFile, ::GetModuleHandleW(L"ntdll.dll"), + "NtQueryInformationFile"); + } + if (!f_NtQueryInformationFile) + return; + + NIO::CInFile file; + if (!file.Open_for_ReadAttributes(_path + GetRelPath(di))) + return; + Z7_WIN_FILE_BASIC_INFORMATION fbi; + Z7_WIN_IO_STATUS_BLOCK IoStatusBlock; + const Z7_WIN_NTSTATUS status = f_NtQueryInformationFile(file.GetHandle(), &IoStatusBlock, + &fbi, sizeof(fbi), Z7_WIN_FileBasicInformation); + if (status != MY_STATUS_SUCCESS) + return; + if (IoStatusBlock.Information != sizeof(fbi)) + return; + di.ChangeTime.dwLowDateTime = fbi.ChangeTime.u.LowPart; + di.ChangeTime.dwHighDateTime = (DWORD)fbi.ChangeTime.u.HighPart; + di.ChangeTime_Defined = true; +} + +#endif // FS_SHOW_LINKS_INFO + + +Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + /* + if (index >= Files.Size()) + { + CAltStream &ss = Streams[index - Files.Size()]; + CDirItem &fi = Files[ss.Parent]; + switch (propID) + { + case kpidIsDir: prop = false; break; + case kpidIsAltStream: prop = true; break; + case kpidName: prop = fs2us(fi.Name) + ss.Name; break; + case kpidSize: prop = ss.Size; break; + case kpidPackSize: + #ifdef UNDER_CE + prop = ss.Size; + #else + if (!ss.PackSize_Defined) + { + ss.PackSize_Defined = true; + if (!MyGetCompressedFileSizeW(_path + GetRelPath(fi) + us2fs(ss.Name), ss.PackSize)) + ss.PackSize = ss.Size; + } + prop = ss.PackSize; + #endif + break; + case kpidComment: break; + default: index = ss.Parent; + } + if (index >= Files.Size()) + { + prop.Detach(value); + return S_OK; + } + } + */ + CDirItem &fi = Files[index]; + switch (propID) + { + case kpidIsDir: prop = fi.IsDir(); break; + case kpidIsAltStream: prop = false; break; + case kpidName: prop = fs2us(fi.Name); break; + case kpidSize: if (!fi.IsDir() || fi.FolderStat_Defined) prop = fi.Size; break; + case kpidPackSize: + #ifdef UNDER_CE + prop = fi.Size; + #else + if (!fi.PackSize_Defined) + { + fi.PackSize_Defined = true; + if (fi.IsDir () || !MyGetCompressedFileSizeW(_path + GetRelPath(fi), fi.PackSize)) + fi.PackSize = fi.Size; + } + prop = fi.PackSize; + #endif + break; + + #ifdef FS_SHOW_LINKS_INFO + + case kpidLinks: + #ifdef UNDER_CE + // prop = fi.NumLinks; + #else + if (!fi.FileInfo_WasRequested) + ReadFileInfo(fi); + if (fi.FileInfo_Defined) + prop = fi.NumLinks; + #endif + break; + + case kpidINode: + #ifdef UNDER_CE + // prop = fi.FileIndex; + #else + if (!fi.FileInfo_WasRequested) + ReadFileInfo(fi); + if (fi.FileInfo_Defined) + prop = fi.FileIndex; + #endif + break; + + case kpidChangeTime: + if (!fi.ChangeTime_WasRequested) + ReadChangeTime(fi); + if (fi.ChangeTime_Defined) + prop = fi.ChangeTime; + break; + + #endif + + case kpidAttrib: prop = (UInt32)fi.Attrib; break; + case kpidCTime: prop = fi.CTime; break; + case kpidATime: prop = fi.ATime; break; + case kpidMTime: prop = fi.MTime; break; + case kpidComment: + { + if (!_commentsAreLoaded) + LoadComments(); + UString comment; + if (_comments.GetValue(fs2us(GetRelPath(fi)), comment)) + { + int pos = comment.Find((wchar_t)4); + if (pos >= 0) + comment.DeleteFrom((unsigned)pos); + prop = comment; + } + break; + } + case kpidPrefix: + if (fi.Parent >= 0) + prop = fs2us(Folders[fi.Parent]); + break; + case kpidNumSubDirs: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFolders; break; + case kpidNumSubFiles: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFiles; break; + } + prop.Detach(value); + return S_OK; +} + + +// ---------- IArchiveGetRawProps ---------- + + +Z7_COM7F_IMF(CFSFolder::GetNumRawProps(UInt32 *numProps)) +{ + *numProps = 1; + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) +{ + *name = NULL; + *propID = kpidNtReparse; + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */)) +{ + return E_FAIL; +} + +Z7_COM7F_IMF(CFSFolder::GetRawProp(UInt32 index, PROPID propID, + const void **data, UInt32 *dataSize, UInt32 *propType)) +{ + #ifdef UNDER_CE + UNUSED(index) + UNUSED(propID) + #endif + + *data = NULL; + *dataSize = 0; + *propType = 0; + + #ifndef UNDER_CE + if (propID == kpidNtReparse) + { + const CDirItem &fi = Files[index]; + const CByteBuffer &buf = fi.Reparse; + if (buf.Size() == 0) + return S_OK; + *data = buf; + *dataSize = (UInt32)buf.Size(); + *propType = NPropDataType::kRaw; + return S_OK; + } + #endif + + return S_OK; +} + + +// returns Position of extension including '.' + +static inline CFSTR GetExtensionPtr(const FString &name) +{ + const int dotPos = name.ReverseFind_Dot(); + return name.Ptr((dotPos < 0) ? name.Len() : (unsigned)dotPos); +} + +Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */)) +{ + /* + const CAltStream *ss1 = NULL; + const CAltStream *ss2 = NULL; + if (index1 >= Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; } + if (index2 >= Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; } + */ + CDirItem &fi1 = Files[index1]; + CDirItem &fi2 = Files[index2]; + + switch (propID) + { + case kpidName: + { + const int comp = CompareFileNames_ForFolderList(fi1.Name, fi2.Name); + /* + if (comp != 0) + return comp; + if (!ss1) + return ss2 ? -1 : 0; + if (!ss2) + return 1; + return MyStringCompareNoCase(ss1->Name, ss2->Name); + */ + return comp; + } + case kpidSize: + return MyCompare( + /* ss1 ? ss1->Size : */ fi1.Size, + /* ss2 ? ss2->Size : */ fi2.Size); + case kpidAttrib: return MyCompare(fi1.Attrib, fi2.Attrib); + case kpidCTime: return CompareFileTime(&fi1.CTime, &fi2.CTime); + case kpidATime: return CompareFileTime(&fi1.ATime, &fi2.ATime); + case kpidMTime: return CompareFileTime(&fi1.MTime, &fi2.MTime); + case kpidIsDir: + { + bool isDir1 = /* ss1 ? false : */ fi1.IsDir(); + bool isDir2 = /* ss2 ? false : */ fi2.IsDir(); + if (isDir1 == isDir2) + return 0; + return isDir1 ? -1 : 1; + } + case kpidPackSize: + { + #ifdef UNDER_CE + return MyCompare(fi1.Size, fi2.Size); + #else + // PackSize can be undefined here + return MyCompare( + /* ss1 ? ss1->PackSize : */ fi1.PackSize, + /* ss2 ? ss2->PackSize : */ fi2.PackSize); + #endif + } + + #ifdef FS_SHOW_LINKS_INFO + case kpidINode: + { + #ifndef UNDER_CE + if (!fi1.FileInfo_WasRequested) ReadFileInfo(fi1); + if (!fi2.FileInfo_WasRequested) ReadFileInfo(fi2); + return MyCompare( + fi1.FileIndex, + fi2.FileIndex); + #endif + } + case kpidLinks: + { + #ifndef UNDER_CE + if (!fi1.FileInfo_WasRequested) ReadFileInfo(fi1); + if (!fi2.FileInfo_WasRequested) ReadFileInfo(fi2); + return MyCompare( + fi1.NumLinks, + fi2.NumLinks); + #endif + } + #endif + + case kpidComment: + { + // change it ! + UString comment1, comment2; + _comments.GetValue(fs2us(GetRelPath(fi1)), comment1); + _comments.GetValue(fs2us(GetRelPath(fi2)), comment2); + return MyStringCompareNoCase(comment1, comment2); + } + case kpidPrefix: + if (fi1.Parent < 0) return (fi2.Parent < 0) ? 0 : -1; + if (fi2.Parent < 0) return 1; + return CompareFileNames_ForFolderList( + Folders[fi1.Parent], + Folders[fi2.Parent]); + case kpidExtension: + return CompareFileNames_ForFolderList( + GetExtensionPtr(fi1.Name), + GetExtensionPtr(fi2.Name)); + } + + return 0; +} + +HRESULT CFSFolder::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder) +{ + *resultFolder = NULL; + CFSFolder *folderSpec = new CFSFolder; + CMyComPtr subFolder = folderSpec; + RINOK(folderSpec->Init(_path + name + FCHAR_PATH_SEPARATOR)) + *resultFolder = subFolder.Detach(); + return S_OK; +} + +/* +void CFSFolder::GetPrefix(const CDirItem &item, FString &prefix) const +{ + if (item.Parent >= 0) + prefix = Folders[item.Parent]; + else + prefix.Empty(); +} +*/ + +/* +void CFSFolder::GetPrefix(const CDirItem &item, FString &prefix) const +{ + int parent = item.Parent; + + unsigned len = 0; + + while (parent >= 0) + { + const CDirItem &cur = Files[parent]; + len += cur.Name.Len() + 1; + parent = cur.Parent; + } + + wchar_t *p = prefix.GetBuf_SetEnd(len) + len; + parent = item.Parent; + + while (parent >= 0) + { + const CDirItem &cur = Files[parent]; + *(--p) = FCHAR_PATH_SEPARATOR; + p -= cur.Name.Len(); + wmemcpy(p, cur.Name, cur.Name.Len()); + parent = cur.Parent; + } +} +*/ + +FString CFSFolder::GetRelPath(const CDirItem &item) const +{ + if (item.Parent < 0) + return item.Name; + return Folders[item.Parent] + item.Name; +} + +Z7_COM7F_IMF(CFSFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + const CDirItem &fi = Files[index]; + if (!fi.IsDir()) + return E_INVALIDARG; + return BindToFolderSpec(GetRelPath(fi), resultFolder); +} + +Z7_COM7F_IMF(CFSFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) +{ + return BindToFolderSpec(us2fs(name), resultFolder); +} + +Z7_COM7F_IMF(CFSFolder::BindToParentFolder(IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + /* + if (_parentFolder) + { + CMyComPtr parentFolder = _parentFolder; + *resultFolder = parentFolder.Detach(); + return S_OK; + } + */ + if (_path.IsEmpty()) + return E_INVALIDARG; + + #ifndef UNDER_CE + + if (IsDriveRootPath_SuperAllowed(_path)) + { + CFSDrives *drivesFolderSpec = new CFSDrives; + CMyComPtr drivesFolder = drivesFolderSpec; + drivesFolderSpec->Init(false, IsSuperPath(_path)); + *resultFolder = drivesFolder.Detach(); + return S_OK; + } + + int pos = _path.ReverseFind_PathSepar(); + if (pos < 0 || pos != (int)_path.Len() - 1) + return E_FAIL; + FString parentPath = _path.Left((unsigned)pos); + pos = parentPath.ReverseFind_PathSepar(); + parentPath.DeleteFrom((unsigned)(pos + 1)); + + if (NName::IsDrivePath_SuperAllowed(parentPath)) + { + CFSFolder *parentFolderSpec = new CFSFolder; + CMyComPtr parentFolder = parentFolderSpec; + if (parentFolderSpec->Init(parentPath) == S_OK) + { + *resultFolder = parentFolder.Detach(); + return S_OK; + } + } + + /* + FString parentPathReduced = parentPath.Left(pos); + + pos = parentPathReduced.ReverseFind_PathSepar(); + if (pos == 1) + { + if (!IS_PATH_SEPAR_CHAR(parentPath[0])) + return E_FAIL; + CNetFolder *netFolderSpec = new CNetFolder; + CMyComPtr netFolder = netFolderSpec; + netFolderSpec->Init(fs2us(parentPath)); + *resultFolder = netFolder.Detach(); + return S_OK; + } + */ + + #endif + + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::GetNumberOfProperties(UInt32 *numProperties)) +{ + *numProperties = Z7_ARRAY_SIZE(kProps); + if (!_flatMode) + (*numProperties)--; + return S_OK; +} + +IMP_IFolderFolder_GetProp(CFSFolder::GetPropertyInfo, kProps) + +Z7_COM7F_IMF(CFSFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidType: prop = "FSFolder"; break; + case kpidPath: prop = fs2us(_path); break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + +Z7_COM7F_IMF(CFSFolder::WasChanged(Int32 *wasChanged)) +{ + bool wasChangedMain = false; + + #ifdef _WIN32 + + for (;;) + { + if (!_findChangeNotification.IsHandleAllocated()) + break; + DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0); + if (waitResult != WAIT_OBJECT_0) + break; + _findChangeNotification.FindNext(); + wasChangedMain = true; + } + + #endif + + *wasChanged = BoolToInt(wasChangedMain); + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::Clone(IFolderFolder **resultFolder)) +{ + CFSFolder *fsFolderSpec = new CFSFolder; + CMyComPtr folderNew = fsFolderSpec; + fsFolderSpec->Init(_path); + *resultFolder = folderNew.Detach(); + return S_OK; +} + + +/* +HRESULT CFSFolder::GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress) +{ + if (index >= Files.Size()) + { + size = Streams[index - Files.Size()].Size; + return S_OK; + } + const CDirItem &fi = Files[index]; + if (fi.IsDir()) + { + UInt64 numFolders = 0, numFiles = 0; + size = 0; + return GetFolderSize(_path + GetRelPath(fi), numFolders, numFiles, size, progress); + } + size = fi.Size; + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress) +{ + NCOM::CPropVariant prop; + UInt64 size = 0; + HRESULT result = GetItemFullSize(index, size, progress); + prop = size; + prop.Detach(value); + return result; +} +*/ + +Z7_COM7F_IMF(CFSFolder::CalcItemFullSize(UInt32 index, IProgress *progress)) +{ + if (index >= Files.Size()) + return S_OK; + CDirItem &fi = Files[index]; + if (!fi.IsDir()) + return S_OK; + CFsFolderStat stat(_path + GetRelPath(fi), progress); + RINOK(stat.Enumerate()) + fi.Size = stat.Size; + fi.NumFolders = stat.NumFolders; + fi.NumFiles = stat.NumFiles; + fi.FolderStat_Defined = true; + return S_OK; +} + +void CFSFolder::GetAbsPath(const wchar_t *name, FString &absPath) +{ + absPath.Empty(); + if (!IsAbsolutePath(name)) + absPath += _path; + absPath += us2fs(name); +} + +Z7_COM7F_IMF(CFSFolder::CreateFolder(const wchar_t *name, IProgress * /* progress */)) +{ + FString absPath; + GetAbsPath(name, absPath); + if (CreateDir(absPath)) + return S_OK; + if (::GetLastError() != ERROR_ALREADY_EXISTS) + if (CreateComplexDir(absPath)) + return S_OK; + return GetLastError_noZero_HRESULT(); +} + +Z7_COM7F_IMF(CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress */)) +{ + FString absPath; + GetAbsPath(name, absPath); + NIO::COutFile outFile; + if (!outFile.Create_NEW(absPath)) + return GetLastError_noZero_HRESULT(); + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::Rename(UInt32 index, const wchar_t *newName, IProgress * /* progress */)) +{ + if (index >= Files.Size()) + return E_NOTIMPL; + const CDirItem &fi = Files[index]; + // FString prefix; + // GetPrefix(fi, prefix); + FString fullPrefix = _path; + if (fi.Parent >= 0) + fullPrefix += Folders[fi.Parent]; + if (!MyMoveFile(fullPrefix + fi.Name, fullPrefix + us2fs(newName))) + return GetLastError_noZero_HRESULT(); + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress)) +{ + RINOK(progress->SetTotal(numItems)) + // int prevDeletedFileIndex = -1; + for (UInt32 i = 0; i < numItems; i++) + { + // Sleep(200); + UInt32 index = indices[i]; + bool result = true; + /* + if (index >= Files.Size()) + { + const CAltStream &ss = Streams[index - Files.Size()]; + if (prevDeletedFileIndex != ss.Parent) + { + const CDirItem &fi = Files[ss.Parent]; + result = DeleteFileAlways(_path + GetRelPath(fi) + us2fs(ss.Name)); + } + } + else + */ + { + const CDirItem &fi = Files[index]; + const FString fullPath = _path + GetRelPath(fi); + // prevDeletedFileIndex = index; + if (fi.IsDir()) + result = RemoveDirWithSubItems(fullPath); + else + result = DeleteFileAlways(fullPath); + } + if (!result) + return GetLastError_noZero_HRESULT(); + const UInt64 completed = i; + RINOK(progress->SetCompleted(&completed)) + } + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::SetProperty(UInt32 index, PROPID propID, + const PROPVARIANT *value, IProgress * /* progress */)) +{ + if (index >= Files.Size()) + return E_INVALIDARG; + CDirItem &fi = Files[index]; + if (fi.Parent >= 0) + return E_NOTIMPL; + switch (propID) + { + case kpidComment: + { + UString filename = fs2us(fi.Name); + filename.Trim(); + if (value->vt == VT_EMPTY) + _comments.DeletePair(filename); + else if (value->vt == VT_BSTR) + { + CTextPair pair; + pair.ID = filename; + pair.ID.Trim(); + pair.Value.SetFromBstr(value->bstrVal); + pair.Value.Trim(); + if (pair.Value.IsEmpty()) + _comments.DeletePair(filename); + else + _comments.AddPair(pair); + } + else + return E_INVALIDARG; + SaveComments(); + break; + } + default: + return E_NOTIMPL; + } + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) +{ + *iconIndex = -1; + if (index >= Files.Size()) + return E_INVALIDARG; + const CDirItem &fi = Files[index]; + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + _path + GetRelPath(fi), fi.Attrib, iconIndex); +} + +Z7_COM7F_IMF(CFSFolder::SetFlatMode(Int32 flatMode)) +{ + _flatMode = IntToBool(flatMode); + return S_OK; +} + +/* +Z7_COM7F_IMF(CFSFolder::SetShowNtfsStreamsMode(Int32 showStreamsMode) +{ + _scanAltStreams = IntToBool(showStreamsMode); + return S_OK; +} +*/ + +} diff --git a/CPP/7zip/UI/FileManager/FSFolder.h b/CPP/7zip/UI/FileManager/FSFolder.h index 4fe257a38..e2edf5fdb 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.h +++ b/CPP/7zip/UI/FileManager/FSFolder.h @@ -1,220 +1,220 @@ -// FSFolder.h - -#ifndef ZIP7_INC_FS_FOLDER_H -#define ZIP7_INC_FS_FOLDER_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyBuffer.h" - -#include "../../../Windows/FileFind.h" - -#include "../../Archive/IArchive.h" - -#include "IFolder.h" -#include "TextPairs.h" - -namespace NFsFolder { - -class CFSFolder; - -#define FS_SHOW_LINKS_INFO -// #define FS_SHOW_CHANGE_TIME - -struct CDirItem: public NWindows::NFile::NFind::CFileInfo -{ -#ifndef UNDER_CE - UInt64 PackSize; -#endif - -#ifdef FS_SHOW_LINKS_INFO - FILETIME ChangeTime; - UInt64 FileIndex; - UInt32 NumLinks; - bool FileInfo_Defined; - bool FileInfo_WasRequested; - bool ChangeTime_Defined; - bool ChangeTime_WasRequested; -#endif - -#ifndef UNDER_CE - bool PackSize_Defined; -#endif - - bool FolderStat_Defined; - int Parent; - -#ifndef UNDER_CE - CByteBuffer Reparse; -#endif - - UInt64 NumFolders; - UInt64 NumFiles; -}; - -/* -struct CAltStream -{ - UInt64 Size; - UInt64 PackSize; - bool PackSize_Defined; - int Parent; - UString Name; -}; -*/ - -struct CFsFolderStat -{ - UInt64 NumFolders; - UInt64 NumFiles; - UInt64 Size; - IProgress *Progress; - FString Path; - - CFsFolderStat(): NumFolders(0), NumFiles(0), Size(0), Progress(NULL) {} - CFsFolderStat(const FString &path, IProgress *progress = NULL): - NumFolders(0), NumFiles(0), Size(0), Progress(progress), Path(path) {} - - HRESULT Enumerate(); -}; - -class CFSFolder Z7_final: - public IFolderFolder, - public IArchiveGetRawProps, - public IFolderCompare, - #ifdef USE_UNICODE_FSTRING - public IFolderGetItemName, - #endif - public IFolderWasChanged, - public IFolderOperations, - // public IFolderOperationsDeleteToRecycleBin, - public IFolderCalcItemFullSize, - public IFolderClone, - public IFolderGetSystemIconIndex, - public IFolderSetFlatMode, - // public IFolderSetShowNtfsStreamsMode, - public CMyUnknownImp -{ - Z7_COM_QI_BEGIN2(IFolderFolder) - Z7_COM_QI_ENTRY(IArchiveGetRawProps) - Z7_COM_QI_ENTRY(IFolderCompare) - #ifdef USE_UNICODE_FSTRING - Z7_COM_QI_ENTRY(IFolderGetItemName) - #endif - Z7_COM_QI_ENTRY(IFolderWasChanged) - // Z7_COM_QI_ENTRY(IFolderOperationsDeleteToRecycleBin) - Z7_COM_QI_ENTRY(IFolderOperations) - Z7_COM_QI_ENTRY(IFolderCalcItemFullSize) - Z7_COM_QI_ENTRY(IFolderClone) - Z7_COM_QI_ENTRY(IFolderGetSystemIconIndex) - Z7_COM_QI_ENTRY(IFolderSetFlatMode) - // Z7_COM_QI_ENTRY(IFolderSetShowNtfsStreamsMode) - Z7_COM_QI_END - Z7_COM_ADDREF_RELEASE - - Z7_IFACE_COM7_IMP(IFolderFolder) - Z7_IFACE_COM7_IMP(IArchiveGetRawProps) - Z7_IFACE_COM7_IMP(IFolderCompare) - #ifdef USE_UNICODE_FSTRING - Z7_IFACE_COM7_IMP(IFolderGetItemName) - #endif - Z7_IFACE_COM7_IMP(IFolderWasChanged) - Z7_IFACE_COM7_IMP(IFolderOperations) - Z7_IFACE_COM7_IMP(IFolderCalcItemFullSize) - Z7_IFACE_COM7_IMP(IFolderClone) - Z7_IFACE_COM7_IMP(IFolderGetSystemIconIndex) - Z7_IFACE_COM7_IMP(IFolderSetFlatMode) - // Z7_IFACE_COM7_IMP(IFolderSetShowNtfsStreamsMode) - - bool _flatMode; - bool _commentsAreLoaded; - // bool _scanAltStreams; - - FString _path; - CObjectVector Files; - FStringVector Folders; - // CObjectVector Streams; - // CMyComPtr _parentFolder; - - CPairsStorage _comments; - - #ifdef _WIN32 - NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; - #endif - - // HRESULT GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress); - void GetAbsPath(const wchar_t *name, FString &absPath); - HRESULT BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder); - - bool LoadComments(); - bool SaveComments(); - HRESULT LoadSubItems(int dirItem, const FString &path); - - #ifdef FS_SHOW_LINKS_INFO - bool ReadFileInfo(CDirItem &di); - void ReadChangeTime(CDirItem &di); - #endif - -public: - HRESULT Init(const FString &path /* , IFolderFolder *parentFolder */); - #if !defined(_WIN32) || defined(UNDER_CE) - HRESULT InitToRoot() { return Init((FString) FSTRING_PATH_SEPARATOR /* , NULL */); } - #endif - - CFSFolder(): - _flatMode(false), - _commentsAreLoaded(false) - // , _scanAltStreams(false) - {} - - void GetFullPath(const CDirItem &item, FString &path) const - { - // FString prefix; - // GetPrefix(item, prefix); - path = _path; - if (item.Parent >= 0) - path += Folders[item.Parent]; - path += item.Name; - } - - // void GetPrefix(const CDirItem &item, FString &prefix) const; - - FString GetRelPath(const CDirItem &item) const; - - void Clear() - { - Files.Clear(); - Folders.Clear(); - // Streams.Clear(); - } -}; - -struct CCopyStateIO -{ - IProgress *Progress; - UInt64 TotalSize; - UInt64 StartPos; - UInt64 CurrentSize; - bool DeleteSrcFile; - - int ErrorFileIndex; - UString ErrorMessage; - - CCopyStateIO(): TotalSize(0), StartPos(0), DeleteSrcFile(false) {} - - HRESULT MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib = INVALID_FILE_ATTRIBUTES); -}; - -HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName); - -/* destDirPrefix is allowed to be: - "full_path\" or "full_path:" for alt streams */ - -HRESULT CopyFileSystemItems( - const UStringVector &itemsPaths, - const FString &destDirPrefix, - bool moveMode, - IFolderOperationsExtractCallback *callback); - -} - -#endif +// FSFolder.h + +#ifndef ZIP7_INC_FS_FOLDER_H +#define ZIP7_INC_FS_FOLDER_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyBuffer.h" + +#include "../../../Windows/FileFind.h" + +#include "../../Archive/IArchive.h" + +#include "IFolder.h" +#include "TextPairs.h" + +namespace NFsFolder { + +class CFSFolder; + +#define FS_SHOW_LINKS_INFO +// #define FS_SHOW_CHANGE_TIME + +struct CDirItem: public NWindows::NFile::NFind::CFileInfo +{ +#ifndef UNDER_CE + UInt64 PackSize; +#endif + +#ifdef FS_SHOW_LINKS_INFO + FILETIME ChangeTime; + UInt64 FileIndex; + UInt32 NumLinks; + bool FileInfo_Defined; + bool FileInfo_WasRequested; + bool ChangeTime_Defined; + bool ChangeTime_WasRequested; +#endif + +#ifndef UNDER_CE + bool PackSize_Defined; +#endif + + bool FolderStat_Defined; + int Parent; + +#ifndef UNDER_CE + CByteBuffer Reparse; +#endif + + UInt64 NumFolders; + UInt64 NumFiles; +}; + +/* +struct CAltStream +{ + UInt64 Size; + UInt64 PackSize; + bool PackSize_Defined; + int Parent; + UString Name; +}; +*/ + +struct CFsFolderStat +{ + UInt64 NumFolders; + UInt64 NumFiles; + UInt64 Size; + IProgress *Progress; + FString Path; + + CFsFolderStat(): NumFolders(0), NumFiles(0), Size(0), Progress(NULL) {} + CFsFolderStat(const FString &path, IProgress *progress = NULL): + NumFolders(0), NumFiles(0), Size(0), Progress(progress), Path(path) {} + + HRESULT Enumerate(); +}; + +class CFSFolder Z7_final: + public IFolderFolder, + public IArchiveGetRawProps, + public IFolderCompare, + #ifdef USE_UNICODE_FSTRING + public IFolderGetItemName, + #endif + public IFolderWasChanged, + public IFolderOperations, + // public IFolderOperationsDeleteToRecycleBin, + public IFolderCalcItemFullSize, + public IFolderClone, + public IFolderGetSystemIconIndex, + public IFolderSetFlatMode, + // public IFolderSetShowNtfsStreamsMode, + public CMyUnknownImp +{ + Z7_COM_QI_BEGIN2(IFolderFolder) + Z7_COM_QI_ENTRY(IArchiveGetRawProps) + Z7_COM_QI_ENTRY(IFolderCompare) + #ifdef USE_UNICODE_FSTRING + Z7_COM_QI_ENTRY(IFolderGetItemName) + #endif + Z7_COM_QI_ENTRY(IFolderWasChanged) + // Z7_COM_QI_ENTRY(IFolderOperationsDeleteToRecycleBin) + Z7_COM_QI_ENTRY(IFolderOperations) + Z7_COM_QI_ENTRY(IFolderCalcItemFullSize) + Z7_COM_QI_ENTRY(IFolderClone) + Z7_COM_QI_ENTRY(IFolderGetSystemIconIndex) + Z7_COM_QI_ENTRY(IFolderSetFlatMode) + // Z7_COM_QI_ENTRY(IFolderSetShowNtfsStreamsMode) + Z7_COM_QI_END + Z7_COM_ADDREF_RELEASE + + Z7_IFACE_COM7_IMP(IFolderFolder) + Z7_IFACE_COM7_IMP(IArchiveGetRawProps) + Z7_IFACE_COM7_IMP(IFolderCompare) + #ifdef USE_UNICODE_FSTRING + Z7_IFACE_COM7_IMP(IFolderGetItemName) + #endif + Z7_IFACE_COM7_IMP(IFolderWasChanged) + Z7_IFACE_COM7_IMP(IFolderOperations) + Z7_IFACE_COM7_IMP(IFolderCalcItemFullSize) + Z7_IFACE_COM7_IMP(IFolderClone) + Z7_IFACE_COM7_IMP(IFolderGetSystemIconIndex) + Z7_IFACE_COM7_IMP(IFolderSetFlatMode) + // Z7_IFACE_COM7_IMP(IFolderSetShowNtfsStreamsMode) + + bool _flatMode; + bool _commentsAreLoaded; + // bool _scanAltStreams; + + FString _path; + CObjectVector Files; + FStringVector Folders; + // CObjectVector Streams; + // CMyComPtr _parentFolder; + + CPairsStorage _comments; + + #ifdef _WIN32 + NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification; + #endif + + // HRESULT GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress); + void GetAbsPath(const wchar_t *name, FString &absPath); + HRESULT BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder); + + bool LoadComments(); + bool SaveComments(); + HRESULT LoadSubItems(int dirItem, const FString &path); + + #ifdef FS_SHOW_LINKS_INFO + bool ReadFileInfo(CDirItem &di); + void ReadChangeTime(CDirItem &di); + #endif + +public: + HRESULT Init(const FString &path /* , IFolderFolder *parentFolder */); + #if !defined(_WIN32) || defined(UNDER_CE) + HRESULT InitToRoot() { return Init((FString) FSTRING_PATH_SEPARATOR /* , NULL */); } + #endif + + CFSFolder(): + _flatMode(false), + _commentsAreLoaded(false) + // , _scanAltStreams(false) + {} + + void GetFullPath(const CDirItem &item, FString &path) const + { + // FString prefix; + // GetPrefix(item, prefix); + path = _path; + if (item.Parent >= 0) + path += Folders[item.Parent]; + path += item.Name; + } + + // void GetPrefix(const CDirItem &item, FString &prefix) const; + + FString GetRelPath(const CDirItem &item) const; + + void Clear() + { + Files.Clear(); + Folders.Clear(); + // Streams.Clear(); + } +}; + +struct CCopyStateIO +{ + IProgress *Progress; + UInt64 TotalSize; + UInt64 StartPos; + UInt64 CurrentSize; + bool DeleteSrcFile; + + int ErrorFileIndex; + UString ErrorMessage; + + CCopyStateIO(): TotalSize(0), StartPos(0), DeleteSrcFile(false) {} + + HRESULT MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib = INVALID_FILE_ATTRIBUTES); +}; + +HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName); + +/* destDirPrefix is allowed to be: + "full_path\" or "full_path:" for alt streams */ + +HRESULT CopyFileSystemItems( + const UStringVector &itemsPaths, + const FString &destDirPrefix, + bool moveMode, + IFolderOperationsExtractCallback *callback); + +} + +#endif diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp index f69a0efce..3582be0c4 100644 --- a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp +++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp @@ -1,871 +1,871 @@ -// FSFolderCopy.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include "../../../Common/Defs.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" - -#include "../../Common/FilePathAutoRename.h" - -#include "FSFolder.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; -using namespace NName; -using namespace NFind; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NFsFolder { - -static const char * const k_CannotCopyDirToAltStream = "Cannot copy folder as alternate stream"; - - -HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib) -{ - ErrorFileIndex = -1; - ErrorMessage.Empty(); - CurrentSize = 0; - - { - const size_t kBufSize = 1 << 16; - CByteArr buf(kBufSize); - - NIO::CInFile inFile; - NIO::COutFile outFile; - - if (!inFile.Open(inPath)) - { - ErrorFileIndex = 0; - return S_OK; - } - - if (!outFile.Create_ALWAYS(outPath)) - { - ErrorFileIndex = 1; - return S_OK; - } - - for (;;) - { - UInt32 num; - if (!inFile.Read(buf, kBufSize, num)) - { - ErrorFileIndex = 0; - return S_OK; - } - if (num == 0) - break; - - UInt32 written = 0; - if (!outFile.Write(buf, num, written)) - { - ErrorFileIndex = 1; - return S_OK; - } - if (written != num) - { - ErrorMessage = "Write error"; - return S_OK; - } - CurrentSize += num; - if (Progress) - { - UInt64 completed = StartPos + CurrentSize; - RINOK(Progress->SetCompleted(&completed)) - } - } - } - - /* SetFileAttrib("path:alt_stream_name") sets attributes for main file "path". - But we don't want to change attributes of main file, when we write alt stream. - So we need INVALID_FILE_ATTRIBUTES for alt stream here */ - - if (attrib != INVALID_FILE_ATTRIBUTES) - SetFileAttrib(outPath, attrib); - - if (DeleteSrcFile) - { - if (!DeleteFileAlways(inPath)) - { - ErrorFileIndex = 0; - return S_OK; - } - } - - return S_OK; -} - - -/* -static bool IsItWindows2000orHigher() -{ - OSVERSIONINFO versionInfo; - versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); - if (!::GetVersionEx(&versionInfo)) - return false; - return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && - (versionInfo.dwMajorVersion >= 5); -} -*/ - -struct CProgressInfo -{ - UInt64 TotalSize; - UInt64 StartPos; - UInt64 FileSize; - IProgress *Progress; - HRESULT ProgressResult; - - void Init() { ProgressResult = S_OK; } -}; - -#ifndef PROGRESS_CONTINUE - -#define PROGRESS_CONTINUE 0 -#define PROGRESS_CANCEL 1 - -#define COPY_FILE_FAIL_IF_EXISTS 0x00000001 - -typedef -DWORD -(WINAPI* LPPROGRESS_ROUTINE)( - LARGE_INTEGER TotalFileSize, - LARGE_INTEGER TotalBytesTransferred, - LARGE_INTEGER StreamSize, - LARGE_INTEGER StreamBytesTransferred, - DWORD dwStreamNumber, - DWORD dwCallbackReason, - HANDLE hSourceFile, - HANDLE hDestinationFile, - LPVOID lpData - ); - -#endif - -static DWORD CALLBACK CopyProgressRoutine( - LARGE_INTEGER TotalFileSize, // file size - LARGE_INTEGER TotalBytesTransferred, // bytes transferred - LARGE_INTEGER /* StreamSize */, // bytes in stream - LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream - DWORD /* dwStreamNumber */, // current stream - DWORD /* dwCallbackReason */, // callback reason - HANDLE /* hSourceFile */, // handle to source file - HANDLE /* hDestinationFile */, // handle to destination file - LPVOID lpData // from CopyFileEx -) -{ - // StreamSize = StreamSize; - // StreamBytesTransferred = StreamBytesTransferred; - // dwStreamNumber = dwStreamNumber; - // dwCallbackReason = dwCallbackReason; - - CProgressInfo &pi = *(CProgressInfo *)lpData; - - if ((UInt64)TotalFileSize.QuadPart > pi.FileSize) - { - pi.TotalSize += (UInt64)TotalFileSize.QuadPart - pi.FileSize; - pi.FileSize = (UInt64)TotalFileSize.QuadPart; - pi.ProgressResult = pi.Progress->SetTotal(pi.TotalSize); - } - const UInt64 completed = pi.StartPos + (UInt64)TotalBytesTransferred.QuadPart; - pi.ProgressResult = pi.Progress->SetCompleted(&completed); - return (pi.ProgressResult == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL); -} - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // win2000 -#define Z7_USE_DYN_MoveFileWithProgressW -#endif - -#ifdef Z7_USE_DYN_MoveFileWithProgressW -// nt4 -typedef BOOL (WINAPI * Func_CopyFileExA)( - IN LPCSTR lpExistingFileName, - IN LPCSTR lpNewFileName, - IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, - IN LPVOID lpData OPTIONAL, - IN LPBOOL pbCancel OPTIONAL, - IN DWORD dwCopyFlags - ); - -// nt4 -typedef BOOL (WINAPI * Func_CopyFileExW)( - IN LPCWSTR lpExistingFileName, - IN LPCWSTR lpNewFileName, - IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, - IN LPVOID lpData OPTIONAL, - IN LPBOOL pbCancel OPTIONAL, - IN DWORD dwCopyFlags - ); - -// win2000 -typedef BOOL (WINAPI * Func_MoveFileWithProgressW)( - IN LPCWSTR lpExistingFileName, - IN LPCWSTR lpNewFileName, - IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, - IN LPVOID lpData OPTIONAL, - IN DWORD dwFlags - ); -#endif - -struct CCopyState -{ - CProgressInfo ProgressInfo; - IFolderOperationsExtractCallback *Callback; - bool MoveMode; - bool UseReadWriteMode; - bool IsAltStreamsDest; - -#ifdef Z7_USE_DYN_MoveFileWithProgressW -private: - Func_CopyFileExW my_CopyFileExW; - #ifndef UNDER_CE - Func_MoveFileWithProgressW my_MoveFileWithProgressW; - #endif - #ifndef _UNICODE - Func_CopyFileExA my_CopyFileExA; - #endif -public: - CCopyState(); -#endif - - bool CopyFile_NT(const wchar_t *oldFile, const wchar_t *newFile); - bool CopyFile_Sys(CFSTR oldFile, CFSTR newFile); - bool MoveFile_Sys(CFSTR oldFile, CFSTR newFile); - - HRESULT CallProgress(); - - bool IsCallbackProgressError() { return ProgressInfo.ProgressResult != S_OK; } -}; - -HRESULT CCopyState::CallProgress() -{ - return ProgressInfo.Progress->SetCompleted(&ProgressInfo.StartPos); -} - -#ifdef Z7_USE_DYN_MoveFileWithProgressW - -CCopyState::CCopyState() -{ - my_CopyFileExW = NULL; - #ifndef UNDER_CE - my_MoveFileWithProgressW = NULL; - #endif - #ifndef _UNICODE - my_CopyFileExA = NULL; - if (!g_IsNT) - { - my_CopyFileExA = Z7_GET_PROC_ADDRESS( - Func_CopyFileExA, ::GetModuleHandleA("kernel32.dll"), - "CopyFileExA"); - } - else - #endif - { - const HMODULE module = ::GetModuleHandleW( - #ifdef UNDER_CE - L"coredll.dll" - #else - L"kernel32.dll" - #endif - ); - my_CopyFileExW = Z7_GET_PROC_ADDRESS( - Func_CopyFileExW, module, - "CopyFileExW"); - #ifndef UNDER_CE - my_MoveFileWithProgressW = Z7_GET_PROC_ADDRESS( - Func_MoveFileWithProgressW, module, - "MoveFileWithProgressW"); - #endif - } -} - -#endif - -/* WinXP-64: - CopyFileW(fromFile, toFile:altStream) - OK - there are NO alt streams in fromFile - ERROR_INVALID_PARAMETER - there are alt streams in fromFile -*/ - -bool CCopyState::CopyFile_NT(const wchar_t *oldFile, const wchar_t *newFile) -{ - BOOL cancelFlag = FALSE; -#ifdef Z7_USE_DYN_MoveFileWithProgressW - if (my_CopyFileExW) -#endif - return BOOLToBool( -#ifdef Z7_USE_DYN_MoveFileWithProgressW - my_CopyFileExW -#else - CopyFileExW -#endif - (oldFile, newFile, CopyProgressRoutine, - &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS)); -#ifdef Z7_USE_DYN_MoveFileWithProgressW - return BOOLToBool(::CopyFileW(oldFile, newFile, TRUE)); -#endif -} - -bool CCopyState::CopyFile_Sys(CFSTR oldFile, CFSTR newFile) -{ - #ifndef _UNICODE - if (!g_IsNT) - { -#ifdef Z7_USE_DYN_MoveFileWithProgressW - if (my_CopyFileExA) -#endif - { - BOOL cancelFlag = FALSE; - if ( -#ifdef Z7_USE_DYN_MoveFileWithProgressW - my_CopyFileExA -#else - CopyFileExA -#endif - (fs2fas(oldFile), fs2fas(newFile), - CopyProgressRoutine, &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS)) - return true; - if (::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - return false; - } - return BOOLToBool(::CopyFile(fs2fas(oldFile), fs2fas(newFile), TRUE)); - } - else - #endif - { - IF_USE_MAIN_PATH_2(oldFile, newFile) - { - if (CopyFile_NT(fs2us(oldFile), fs2us(newFile))) - return true; - } - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH_2) - { - if (IsCallbackProgressError()) - return false; - UString superPathOld, superPathNew; - if (!GetSuperPaths(oldFile, newFile, superPathOld, superPathNew, USE_MAIN_PATH_2)) - return false; - if (CopyFile_NT(superPathOld, superPathNew)) - return true; - } - #endif - return false; - } -} - -bool CCopyState::MoveFile_Sys(CFSTR oldFile, CFSTR newFile) -{ - #ifndef UNDER_CE - // if (IsItWindows2000orHigher()) - // { -#ifdef Z7_USE_DYN_MoveFileWithProgressW - if (my_MoveFileWithProgressW) -#endif - { - IF_USE_MAIN_PATH_2(oldFile, newFile) - { - if ( -#ifdef Z7_USE_DYN_MoveFileWithProgressW - my_MoveFileWithProgressW -#else - MoveFileWithProgressW -#endif - (fs2us(oldFile), fs2us(newFile), CopyProgressRoutine, - &ProgressInfo, MOVEFILE_COPY_ALLOWED)) - return true; - } - #ifdef Z7_LONG_PATH - if ((!(USE_MAIN_PATH_2) || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) && USE_SUPER_PATH_2) - { - if (IsCallbackProgressError()) - return false; - UString superPathOld, superPathNew; - if (!GetSuperPaths(oldFile, newFile, superPathOld, superPathNew, USE_MAIN_PATH_2)) - return false; - if ( -#ifdef Z7_USE_DYN_MoveFileWithProgressW - my_MoveFileWithProgressW -#else - MoveFileWithProgressW -#endif - (superPathOld, superPathNew, CopyProgressRoutine, - &ProgressInfo, MOVEFILE_COPY_ALLOWED)) - return true; - } - #endif - if (::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - return false; - } - // } - // else - #endif - return MyMoveFile(oldFile, newFile); -} - -static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, - const wchar_t *message, const FString &fileName) -{ - UString s = message; - s += " : "; - s += fs2us(fileName); - return callback->ShowMessage(s); -} - -static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, - const char *message, const FString &fileName) -{ - return SendMessageError(callback, MultiByteToUnicodeString(message), fileName); -} - -static DWORD Return_LastError_or_FAIL() -{ - DWORD errorCode = GetLastError(); - if (errorCode == 0) - errorCode = (DWORD)E_FAIL; - return errorCode; -} - -static UString GetLastErrorMessage() -{ - return NError::MyFormatMessage(Return_LastError_or_FAIL()); -} - -HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName) -{ - return SendMessageError(callback, GetLastErrorMessage(), fileName); -} - -static HRESULT CopyFile_Ask( - CCopyState &state, - const FString &srcPath, - const CFileInfo &srcFileInfo, - const FString &destPath) -{ - if (CompareFileNames(destPath, srcPath) == 0) - { - RINOK(SendMessageError(state.Callback, - state.MoveMode ? - "Cannot move file onto itself" : - "Cannot copy file onto itself" - , destPath)) - return E_ABORT; - } - - Int32 writeAskResult; - CMyComBSTR destPathResult; - RINOK(state.Callback->AskWrite( - fs2us(srcPath), - BoolToInt(false), - &srcFileInfo.MTime, &srcFileInfo.Size, - fs2us(destPath), - &destPathResult, - &writeAskResult)) - - if (IntToBool(writeAskResult)) - { - FString destPathNew = us2fs((LPCOLESTR)destPathResult); - RINOK(state.Callback->SetCurrentFilePath(fs2us(srcPath))) - - if (state.UseReadWriteMode) - { - NFsFolder::CCopyStateIO state2; - state2.Progress = state.Callback; - state2.DeleteSrcFile = state.MoveMode; - state2.TotalSize = state.ProgressInfo.TotalSize; - state2.StartPos = state.ProgressInfo.StartPos; - - RINOK(state2.MyCopyFile(srcPath, destPathNew, - state.IsAltStreamsDest ? INVALID_FILE_ATTRIBUTES: srcFileInfo.Attrib)) - - if (state2.ErrorFileIndex >= 0) - { - if (state2.ErrorMessage.IsEmpty()) - state2.ErrorMessage = GetLastErrorMessage(); - FString errorName; - if (state2.ErrorFileIndex == 0) - errorName = srcPath; - else - errorName = destPathNew; - RINOK(SendMessageError(state.Callback, state2.ErrorMessage, errorName)) - return E_ABORT; - } - state.ProgressInfo.StartPos += state2.CurrentSize; - } - else - { - state.ProgressInfo.FileSize = srcFileInfo.Size; - bool res; - if (state.MoveMode) - res = state.MoveFile_Sys(srcPath, destPathNew); - else - res = state.CopyFile_Sys(srcPath, destPathNew); - RINOK(state.ProgressInfo.ProgressResult) - if (!res) - { - const DWORD errorCode = GetLastError(); - UString errorMessage = NError::MyFormatMessage(Return_LastError_or_FAIL()); - if (errorCode == ERROR_INVALID_PARAMETER) - { - NFind::CFileInfo fi; - if (fi.Find(srcPath) && - fi.Size > (UInt32)(Int32)-1) - { - // bool isFsDetected = false; - // if (NSystem::Is_File_LimitedBy_4GB(destPathNew, isFsDetected) || !isFsDetected) - errorMessage += " File size exceeds 4 GB"; - } - } - - // GetLastError() is ERROR_REQUEST_ABORTED in case of PROGRESS_CANCEL. - RINOK(SendMessageError(state.Callback, errorMessage, destPathNew)) - return E_ABORT; - } - state.ProgressInfo.StartPos += state.ProgressInfo.FileSize; - } - } - else - { - if (state.ProgressInfo.TotalSize >= srcFileInfo.Size) - { - state.ProgressInfo.TotalSize -= srcFileInfo.Size; - RINOK(state.ProgressInfo.Progress->SetTotal(state.ProgressInfo.TotalSize)) - } - } - return state.CallProgress(); -} - -static FString CombinePath(const FString &folderPath, const FString &fileName) -{ - FString s (folderPath); - s.Add_PathSepar(); // FCHAR_PATH_SEPARATOR - s += fileName; - return s; -} - -static bool IsDestChild(const FString &src, const FString &dest) -{ - unsigned len = src.Len(); - if (dest.Len() < len) - return false; - if (dest.Len() != len && dest[len] != FCHAR_PATH_SEPARATOR) - return false; - return CompareFileNames(dest.Left(len), src) == 0; -} - -static HRESULT CopyFolder( - CCopyState &state, - const FString &srcPath, // without TAIL separator - const FString &destPath) // without TAIL separator -{ - RINOK(state.CallProgress()) - - if (IsDestChild(srcPath, destPath)) - { - RINOK(SendMessageError(state.Callback, - state.MoveMode ? - "Cannot copy folder onto itself" : - "Cannot move folder onto itself" - , destPath)) - return E_ABORT; - } - - if (state.MoveMode) - { - if (state.MoveFile_Sys(srcPath, destPath)) - return S_OK; - - // MSDN: MoveFile() fails for dirs on different volumes. - } - - if (!CreateComplexDir(destPath)) - { - RINOK(SendMessageError(state.Callback, "Cannot create folder", destPath)) - return E_ABORT; - } - - CEnumerator enumerator; - enumerator.SetDirPrefix(CombinePath(srcPath, FString())); - - for (;;) - { - NFind::CFileInfo fi; - bool found; - if (!enumerator.Next(fi, found)) - { - SendLastErrorMessage(state.Callback, srcPath); - return S_OK; - } - if (!found) - break; - const FString srcPath2 = CombinePath(srcPath, fi.Name); - const FString destPath2 = CombinePath(destPath, fi.Name); - if (fi.IsDir()) - { - RINOK(CopyFolder(state, srcPath2, destPath2)) - } - else - { - RINOK(CopyFile_Ask(state, srcPath2, fi, destPath2)) - } - } - - if (state.MoveMode) - { - if (!RemoveDir(srcPath)) - { - RINOK(SendMessageError(state.Callback, "Cannot remove folder", srcPath)) - return E_ABORT; - } - } - - return S_OK; -} - -Z7_COM7F_IMF(CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, - Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */, - const wchar_t *path, IFolderOperationsExtractCallback *callback)) -{ - if (numItems == 0) - return S_OK; - - const FString destPath = us2fs(path); - if (destPath.IsEmpty()) - return E_INVALIDARG; - - const bool isAltDest = NName::IsAltPathPrefix(destPath); - const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); - - if (isDirectPath) - if (numItems > 1) - return E_INVALIDARG; - - CFsFolderStat stat; - stat.Progress = callback; - - UInt32 i; - for (i = 0; i < numItems; i++) - { - const UInt32 index = indices[i]; - /* - if (index >= Files.Size()) - { - size += Streams[index - Files.Size()].Size; - // numFiles++; - continue; - } - */ - const CDirItem &fi = Files[index]; - if (fi.IsDir()) - { - if (!isAltDest) - { - stat.Path = _path; - stat.Path += GetRelPath(fi); - RINOK(stat.Enumerate()) - } - stat.NumFolders++; - } - else - { - stat.NumFiles++; - stat.Size += fi.Size; - } - } - - /* - if (stat.NumFolders != 0 && isAltDest) - return E_NOTIMPL; - */ - - RINOK(callback->SetTotal(stat.Size)) - RINOK(callback->SetNumFiles(stat.NumFiles)) - - UInt64 completedSize = 0; - RINOK(callback->SetCompleted(&completedSize)) - - CCopyState state; - state.ProgressInfo.TotalSize = stat.Size; - state.ProgressInfo.StartPos = 0; - state.ProgressInfo.Progress = callback; - state.ProgressInfo.Init(); - state.Callback = callback; - state.MoveMode = IntToBool(moveMode); - state.IsAltStreamsDest = isAltDest; - /* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER, - if there are alt streams in fromFile. - So we don't use CopyFileW() for alt Streams. */ - state.UseReadWriteMode = isAltDest; - - for (i = 0; i < numItems; i++) - { - const UInt32 index = indices[i]; - if (index >= (UInt32)Files.Size()) - continue; - const CDirItem &fi = Files[index]; - FString destPath2 = destPath; - if (!isDirectPath) - destPath2 += fi.Name; - FString srcPath; - GetFullPath(fi, srcPath); - - if (fi.IsDir()) - { - if (isAltDest) - { - RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, srcPath)) - } - else - { - RINOK(CopyFolder(state, srcPath, destPath2)) - } - } - else - { - RINOK(CopyFile_Ask(state, srcPath, fi, destPath2)) - } - } - return S_OK; -} - - - -/* we can call CopyFileSystemItems() from CDropTarget::Drop() */ - -HRESULT CopyFileSystemItems( - const UStringVector &itemsPaths, - const FString &destDirPrefix, - bool moveMode, - IFolderOperationsExtractCallback *callback) -{ - if (itemsPaths.IsEmpty()) - return S_OK; - - if (destDirPrefix.IsEmpty()) - return E_INVALIDARG; - - const bool isAltDest = NName::IsAltPathPrefix(destDirPrefix); - - CFsFolderStat stat; - stat.Progress = callback; - - { - FOR_VECTOR (i, itemsPaths) - { - const UString &path = itemsPaths[i]; - CFileInfo fi; - if (!fi.Find(us2fs(path))) - continue; - if (fi.IsDir()) - { - if (!isAltDest) - { - stat.Path = us2fs(path); - RINOK(stat.Enumerate()) - } - stat.NumFolders++; - } - else - { - stat.NumFiles++; - stat.Size += fi.Size; - } - } - } - - /* - if (stat.NumFolders != 0 && isAltDest) - return E_NOTIMPL; - */ - - RINOK(callback->SetTotal(stat.Size)) - // RINOK(progress->SetNumFiles(stat.NumFiles)); - - UInt64 completedSize = 0; - RINOK(callback->SetCompleted(&completedSize)) - - CCopyState state; - state.ProgressInfo.TotalSize = stat.Size; - state.ProgressInfo.StartPos = 0; - state.ProgressInfo.Progress = callback; - state.ProgressInfo.Init(); - state.Callback = callback; - state.MoveMode = moveMode; - state.IsAltStreamsDest = isAltDest; - /* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER, - if there are alt streams in fromFile. - So we don't use CopyFileW() for alt Streams. */ - state.UseReadWriteMode = isAltDest; - - FOR_VECTOR (i, itemsPaths) - { - const UString path = itemsPaths[i]; - CFileInfo fi; - - if (!fi.Find(us2fs(path))) - { - RINOK(SendMessageError(callback, "Cannot find the file", us2fs(path))) - continue; - } - - FString destPath = destDirPrefix; - destPath += fi.Name; - - if (fi.IsDir()) - { - if (isAltDest) - { - RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, us2fs(path))) - } - else - { - RINOK(CopyFolder(state, us2fs(path), destPath)) - } - } - else - { - RINOK(CopyFile_Ask(state, us2fs(path), fi, destPath)) - } - } - return S_OK; -} - - -/* we don't use CFSFolder::CopyFrom() because the caller of CopyFrom() - is optimized for IFolderArchiveUpdateCallback interface, - but we want to use IFolderOperationsExtractCallback interface instead */ - -Z7_COM7F_IMF(CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, - const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)) -{ - /* - Z7_DECL_CMyComPtr_QI_FROM( - IFolderOperationsExtractCallback, - callback, progress) - if (!callback) - return E_NOTIMPL; - return CopyFileSystemItems(_path, - moveMode, fromDirPrefix, - itemsPaths, numItems, callback); - */ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CFSFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)) -{ - return E_NOTIMPL; -} - -} +// FSFolderCopy.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" + +#include "../../Common/FilePathAutoRename.h" + +#include "FSFolder.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; +using namespace NName; +using namespace NFind; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NFsFolder { + +static const char * const k_CannotCopyDirToAltStream = "Cannot copy folder as alternate stream"; + + +HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib) +{ + ErrorFileIndex = -1; + ErrorMessage.Empty(); + CurrentSize = 0; + + { + const size_t kBufSize = 1 << 16; + CByteArr buf(kBufSize); + + NIO::CInFile inFile; + NIO::COutFile outFile; + + if (!inFile.Open(inPath)) + { + ErrorFileIndex = 0; + return S_OK; + } + + if (!outFile.Create_ALWAYS(outPath)) + { + ErrorFileIndex = 1; + return S_OK; + } + + for (;;) + { + UInt32 num; + if (!inFile.Read(buf, kBufSize, num)) + { + ErrorFileIndex = 0; + return S_OK; + } + if (num == 0) + break; + + UInt32 written = 0; + if (!outFile.Write(buf, num, written)) + { + ErrorFileIndex = 1; + return S_OK; + } + if (written != num) + { + ErrorMessage = "Write error"; + return S_OK; + } + CurrentSize += num; + if (Progress) + { + UInt64 completed = StartPos + CurrentSize; + RINOK(Progress->SetCompleted(&completed)) + } + } + } + + /* SetFileAttrib("path:alt_stream_name") sets attributes for main file "path". + But we don't want to change attributes of main file, when we write alt stream. + So we need INVALID_FILE_ATTRIBUTES for alt stream here */ + + if (attrib != INVALID_FILE_ATTRIBUTES) + SetFileAttrib(outPath, attrib); + + if (DeleteSrcFile) + { + if (!DeleteFileAlways(inPath)) + { + ErrorFileIndex = 0; + return S_OK; + } + } + + return S_OK; +} + + +/* +static bool IsItWindows2000orHigher() +{ + OSVERSIONINFO versionInfo; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + if (!::GetVersionEx(&versionInfo)) + return false; + return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && + (versionInfo.dwMajorVersion >= 5); +} +*/ + +struct CProgressInfo +{ + UInt64 TotalSize; + UInt64 StartPos; + UInt64 FileSize; + IProgress *Progress; + HRESULT ProgressResult; + + void Init() { ProgressResult = S_OK; } +}; + +#ifndef PROGRESS_CONTINUE + +#define PROGRESS_CONTINUE 0 +#define PROGRESS_CANCEL 1 + +#define COPY_FILE_FAIL_IF_EXISTS 0x00000001 + +typedef +DWORD +(WINAPI* LPPROGRESS_ROUTINE)( + LARGE_INTEGER TotalFileSize, + LARGE_INTEGER TotalBytesTransferred, + LARGE_INTEGER StreamSize, + LARGE_INTEGER StreamBytesTransferred, + DWORD dwStreamNumber, + DWORD dwCallbackReason, + HANDLE hSourceFile, + HANDLE hDestinationFile, + LPVOID lpData + ); + +#endif + +static DWORD CALLBACK CopyProgressRoutine( + LARGE_INTEGER TotalFileSize, // file size + LARGE_INTEGER TotalBytesTransferred, // bytes transferred + LARGE_INTEGER /* StreamSize */, // bytes in stream + LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream + DWORD /* dwStreamNumber */, // current stream + DWORD /* dwCallbackReason */, // callback reason + HANDLE /* hSourceFile */, // handle to source file + HANDLE /* hDestinationFile */, // handle to destination file + LPVOID lpData // from CopyFileEx +) +{ + // StreamSize = StreamSize; + // StreamBytesTransferred = StreamBytesTransferred; + // dwStreamNumber = dwStreamNumber; + // dwCallbackReason = dwCallbackReason; + + CProgressInfo &pi = *(CProgressInfo *)lpData; + + if ((UInt64)TotalFileSize.QuadPart > pi.FileSize) + { + pi.TotalSize += (UInt64)TotalFileSize.QuadPart - pi.FileSize; + pi.FileSize = (UInt64)TotalFileSize.QuadPart; + pi.ProgressResult = pi.Progress->SetTotal(pi.TotalSize); + } + const UInt64 completed = pi.StartPos + (UInt64)TotalBytesTransferred.QuadPart; + pi.ProgressResult = pi.Progress->SetCompleted(&completed); + return (pi.ProgressResult == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL); +} + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // win2000 +#define Z7_USE_DYN_MoveFileWithProgressW +#endif + +#ifdef Z7_USE_DYN_MoveFileWithProgressW +// nt4 +typedef BOOL (WINAPI * Func_CopyFileExA)( + IN LPCSTR lpExistingFileName, + IN LPCSTR lpNewFileName, + IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, + IN LPVOID lpData OPTIONAL, + IN LPBOOL pbCancel OPTIONAL, + IN DWORD dwCopyFlags + ); + +// nt4 +typedef BOOL (WINAPI * Func_CopyFileExW)( + IN LPCWSTR lpExistingFileName, + IN LPCWSTR lpNewFileName, + IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, + IN LPVOID lpData OPTIONAL, + IN LPBOOL pbCancel OPTIONAL, + IN DWORD dwCopyFlags + ); + +// win2000 +typedef BOOL (WINAPI * Func_MoveFileWithProgressW)( + IN LPCWSTR lpExistingFileName, + IN LPCWSTR lpNewFileName, + IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, + IN LPVOID lpData OPTIONAL, + IN DWORD dwFlags + ); +#endif + +struct CCopyState +{ + CProgressInfo ProgressInfo; + IFolderOperationsExtractCallback *Callback; + bool MoveMode; + bool UseReadWriteMode; + bool IsAltStreamsDest; + +#ifdef Z7_USE_DYN_MoveFileWithProgressW +private: + Func_CopyFileExW my_CopyFileExW; + #ifndef UNDER_CE + Func_MoveFileWithProgressW my_MoveFileWithProgressW; + #endif + #ifndef _UNICODE + Func_CopyFileExA my_CopyFileExA; + #endif +public: + CCopyState(); +#endif + + bool CopyFile_NT(const wchar_t *oldFile, const wchar_t *newFile); + bool CopyFile_Sys(CFSTR oldFile, CFSTR newFile); + bool MoveFile_Sys(CFSTR oldFile, CFSTR newFile); + + HRESULT CallProgress(); + + bool IsCallbackProgressError() { return ProgressInfo.ProgressResult != S_OK; } +}; + +HRESULT CCopyState::CallProgress() +{ + return ProgressInfo.Progress->SetCompleted(&ProgressInfo.StartPos); +} + +#ifdef Z7_USE_DYN_MoveFileWithProgressW + +CCopyState::CCopyState() +{ + my_CopyFileExW = NULL; + #ifndef UNDER_CE + my_MoveFileWithProgressW = NULL; + #endif + #ifndef _UNICODE + my_CopyFileExA = NULL; + if (!g_IsNT) + { + my_CopyFileExA = Z7_GET_PROC_ADDRESS( + Func_CopyFileExA, ::GetModuleHandleA("kernel32.dll"), + "CopyFileExA"); + } + else + #endif + { + const HMODULE module = ::GetModuleHandleW( + #ifdef UNDER_CE + L"coredll.dll" + #else + L"kernel32.dll" + #endif + ); + my_CopyFileExW = Z7_GET_PROC_ADDRESS( + Func_CopyFileExW, module, + "CopyFileExW"); + #ifndef UNDER_CE + my_MoveFileWithProgressW = Z7_GET_PROC_ADDRESS( + Func_MoveFileWithProgressW, module, + "MoveFileWithProgressW"); + #endif + } +} + +#endif + +/* WinXP-64: + CopyFileW(fromFile, toFile:altStream) + OK - there are NO alt streams in fromFile + ERROR_INVALID_PARAMETER - there are alt streams in fromFile +*/ + +bool CCopyState::CopyFile_NT(const wchar_t *oldFile, const wchar_t *newFile) +{ + BOOL cancelFlag = FALSE; +#ifdef Z7_USE_DYN_MoveFileWithProgressW + if (my_CopyFileExW) +#endif + return BOOLToBool( +#ifdef Z7_USE_DYN_MoveFileWithProgressW + my_CopyFileExW +#else + CopyFileExW +#endif + (oldFile, newFile, CopyProgressRoutine, + &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS)); +#ifdef Z7_USE_DYN_MoveFileWithProgressW + return BOOLToBool(::CopyFileW(oldFile, newFile, TRUE)); +#endif +} + +bool CCopyState::CopyFile_Sys(CFSTR oldFile, CFSTR newFile) +{ + #ifndef _UNICODE + if (!g_IsNT) + { +#ifdef Z7_USE_DYN_MoveFileWithProgressW + if (my_CopyFileExA) +#endif + { + BOOL cancelFlag = FALSE; + if ( +#ifdef Z7_USE_DYN_MoveFileWithProgressW + my_CopyFileExA +#else + CopyFileExA +#endif + (fs2fas(oldFile), fs2fas(newFile), + CopyProgressRoutine, &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS)) + return true; + if (::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return false; + } + return BOOLToBool(::CopyFile(fs2fas(oldFile), fs2fas(newFile), TRUE)); + } + else + #endif + { + IF_USE_MAIN_PATH_2(oldFile, newFile) + { + if (CopyFile_NT(fs2us(oldFile), fs2us(newFile))) + return true; + } + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH_2) + { + if (IsCallbackProgressError()) + return false; + UString superPathOld, superPathNew; + if (!GetSuperPaths(oldFile, newFile, superPathOld, superPathNew, USE_MAIN_PATH_2)) + return false; + if (CopyFile_NT(superPathOld, superPathNew)) + return true; + } + #endif + return false; + } +} + +bool CCopyState::MoveFile_Sys(CFSTR oldFile, CFSTR newFile) +{ + #ifndef UNDER_CE + // if (IsItWindows2000orHigher()) + // { +#ifdef Z7_USE_DYN_MoveFileWithProgressW + if (my_MoveFileWithProgressW) +#endif + { + IF_USE_MAIN_PATH_2(oldFile, newFile) + { + if ( +#ifdef Z7_USE_DYN_MoveFileWithProgressW + my_MoveFileWithProgressW +#else + MoveFileWithProgressW +#endif + (fs2us(oldFile), fs2us(newFile), CopyProgressRoutine, + &ProgressInfo, MOVEFILE_COPY_ALLOWED)) + return true; + } + #ifdef Z7_LONG_PATH + if ((!(USE_MAIN_PATH_2) || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) && USE_SUPER_PATH_2) + { + if (IsCallbackProgressError()) + return false; + UString superPathOld, superPathNew; + if (!GetSuperPaths(oldFile, newFile, superPathOld, superPathNew, USE_MAIN_PATH_2)) + return false; + if ( +#ifdef Z7_USE_DYN_MoveFileWithProgressW + my_MoveFileWithProgressW +#else + MoveFileWithProgressW +#endif + (superPathOld, superPathNew, CopyProgressRoutine, + &ProgressInfo, MOVEFILE_COPY_ALLOWED)) + return true; + } + #endif + if (::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return false; + } + // } + // else + #endif + return MyMoveFile(oldFile, newFile); +} + +static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, + const wchar_t *message, const FString &fileName) +{ + UString s = message; + s += " : "; + s += fs2us(fileName); + return callback->ShowMessage(s); +} + +static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback, + const char *message, const FString &fileName) +{ + return SendMessageError(callback, MultiByteToUnicodeString(message), fileName); +} + +static DWORD Return_LastError_or_FAIL() +{ + DWORD errorCode = GetLastError(); + if (errorCode == 0) + errorCode = (DWORD)E_FAIL; + return errorCode; +} + +static UString GetLastErrorMessage() +{ + return NError::MyFormatMessage(Return_LastError_or_FAIL()); +} + +HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName) +{ + return SendMessageError(callback, GetLastErrorMessage(), fileName); +} + +static HRESULT CopyFile_Ask( + CCopyState &state, + const FString &srcPath, + const CFileInfo &srcFileInfo, + const FString &destPath) +{ + if (CompareFileNames(destPath, srcPath) == 0) + { + RINOK(SendMessageError(state.Callback, + state.MoveMode ? + "Cannot move file onto itself" : + "Cannot copy file onto itself" + , destPath)) + return E_ABORT; + } + + Int32 writeAskResult; + CMyComBSTR destPathResult; + RINOK(state.Callback->AskWrite( + fs2us(srcPath), + BoolToInt(false), + &srcFileInfo.MTime, &srcFileInfo.Size, + fs2us(destPath), + &destPathResult, + &writeAskResult)) + + if (IntToBool(writeAskResult)) + { + FString destPathNew = us2fs((LPCOLESTR)destPathResult); + RINOK(state.Callback->SetCurrentFilePath(fs2us(srcPath))) + + if (state.UseReadWriteMode) + { + NFsFolder::CCopyStateIO state2; + state2.Progress = state.Callback; + state2.DeleteSrcFile = state.MoveMode; + state2.TotalSize = state.ProgressInfo.TotalSize; + state2.StartPos = state.ProgressInfo.StartPos; + + RINOK(state2.MyCopyFile(srcPath, destPathNew, + state.IsAltStreamsDest ? INVALID_FILE_ATTRIBUTES: srcFileInfo.Attrib)) + + if (state2.ErrorFileIndex >= 0) + { + if (state2.ErrorMessage.IsEmpty()) + state2.ErrorMessage = GetLastErrorMessage(); + FString errorName; + if (state2.ErrorFileIndex == 0) + errorName = srcPath; + else + errorName = destPathNew; + RINOK(SendMessageError(state.Callback, state2.ErrorMessage, errorName)) + return E_ABORT; + } + state.ProgressInfo.StartPos += state2.CurrentSize; + } + else + { + state.ProgressInfo.FileSize = srcFileInfo.Size; + bool res; + if (state.MoveMode) + res = state.MoveFile_Sys(srcPath, destPathNew); + else + res = state.CopyFile_Sys(srcPath, destPathNew); + RINOK(state.ProgressInfo.ProgressResult) + if (!res) + { + const DWORD errorCode = GetLastError(); + UString errorMessage = NError::MyFormatMessage(Return_LastError_or_FAIL()); + if (errorCode == ERROR_INVALID_PARAMETER) + { + NFind::CFileInfo fi; + if (fi.Find(srcPath) && + fi.Size > (UInt32)(Int32)-1) + { + // bool isFsDetected = false; + // if (NSystem::Is_File_LimitedBy_4GB(destPathNew, isFsDetected) || !isFsDetected) + errorMessage += " File size exceeds 4 GB"; + } + } + + // GetLastError() is ERROR_REQUEST_ABORTED in case of PROGRESS_CANCEL. + RINOK(SendMessageError(state.Callback, errorMessage, destPathNew)) + return E_ABORT; + } + state.ProgressInfo.StartPos += state.ProgressInfo.FileSize; + } + } + else + { + if (state.ProgressInfo.TotalSize >= srcFileInfo.Size) + { + state.ProgressInfo.TotalSize -= srcFileInfo.Size; + RINOK(state.ProgressInfo.Progress->SetTotal(state.ProgressInfo.TotalSize)) + } + } + return state.CallProgress(); +} + +static FString CombinePath(const FString &folderPath, const FString &fileName) +{ + FString s (folderPath); + s.Add_PathSepar(); // FCHAR_PATH_SEPARATOR + s += fileName; + return s; +} + +static bool IsDestChild(const FString &src, const FString &dest) +{ + unsigned len = src.Len(); + if (dest.Len() < len) + return false; + if (dest.Len() != len && dest[len] != FCHAR_PATH_SEPARATOR) + return false; + return CompareFileNames(dest.Left(len), src) == 0; +} + +static HRESULT CopyFolder( + CCopyState &state, + const FString &srcPath, // without TAIL separator + const FString &destPath) // without TAIL separator +{ + RINOK(state.CallProgress()) + + if (IsDestChild(srcPath, destPath)) + { + RINOK(SendMessageError(state.Callback, + state.MoveMode ? + "Cannot copy folder onto itself" : + "Cannot move folder onto itself" + , destPath)) + return E_ABORT; + } + + if (state.MoveMode) + { + if (state.MoveFile_Sys(srcPath, destPath)) + return S_OK; + + // MSDN: MoveFile() fails for dirs on different volumes. + } + + if (!CreateComplexDir(destPath)) + { + RINOK(SendMessageError(state.Callback, "Cannot create folder", destPath)) + return E_ABORT; + } + + CEnumerator enumerator; + enumerator.SetDirPrefix(CombinePath(srcPath, FString())); + + for (;;) + { + NFind::CFileInfo fi; + bool found; + if (!enumerator.Next(fi, found)) + { + SendLastErrorMessage(state.Callback, srcPath); + return S_OK; + } + if (!found) + break; + const FString srcPath2 = CombinePath(srcPath, fi.Name); + const FString destPath2 = CombinePath(destPath, fi.Name); + if (fi.IsDir()) + { + RINOK(CopyFolder(state, srcPath2, destPath2)) + } + else + { + RINOK(CopyFile_Ask(state, srcPath2, fi, destPath2)) + } + } + + if (state.MoveMode) + { + if (!RemoveDir(srcPath)) + { + RINOK(SendMessageError(state.Callback, "Cannot remove folder", srcPath)) + return E_ABORT; + } + } + + return S_OK; +} + +Z7_COM7F_IMF(CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, + Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */, + const wchar_t *path, IFolderOperationsExtractCallback *callback)) +{ + if (numItems == 0) + return S_OK; + + const FString destPath = us2fs(path); + if (destPath.IsEmpty()) + return E_INVALIDARG; + + const bool isAltDest = NName::IsAltPathPrefix(destPath); + const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back())); + + if (isDirectPath) + if (numItems > 1) + return E_INVALIDARG; + + CFsFolderStat stat; + stat.Progress = callback; + + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = indices[i]; + /* + if (index >= Files.Size()) + { + size += Streams[index - Files.Size()].Size; + // numFiles++; + continue; + } + */ + const CDirItem &fi = Files[index]; + if (fi.IsDir()) + { + if (!isAltDest) + { + stat.Path = _path; + stat.Path += GetRelPath(fi); + RINOK(stat.Enumerate()) + } + stat.NumFolders++; + } + else + { + stat.NumFiles++; + stat.Size += fi.Size; + } + } + + /* + if (stat.NumFolders != 0 && isAltDest) + return E_NOTIMPL; + */ + + RINOK(callback->SetTotal(stat.Size)) + RINOK(callback->SetNumFiles(stat.NumFiles)) + + UInt64 completedSize = 0; + RINOK(callback->SetCompleted(&completedSize)) + + CCopyState state; + state.ProgressInfo.TotalSize = stat.Size; + state.ProgressInfo.StartPos = 0; + state.ProgressInfo.Progress = callback; + state.ProgressInfo.Init(); + state.Callback = callback; + state.MoveMode = IntToBool(moveMode); + state.IsAltStreamsDest = isAltDest; + /* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER, + if there are alt streams in fromFile. + So we don't use CopyFileW() for alt Streams. */ + state.UseReadWriteMode = isAltDest; + + for (i = 0; i < numItems; i++) + { + const UInt32 index = indices[i]; + if (index >= (UInt32)Files.Size()) + continue; + const CDirItem &fi = Files[index]; + FString destPath2 = destPath; + if (!isDirectPath) + destPath2 += fi.Name; + FString srcPath; + GetFullPath(fi, srcPath); + + if (fi.IsDir()) + { + if (isAltDest) + { + RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, srcPath)) + } + else + { + RINOK(CopyFolder(state, srcPath, destPath2)) + } + } + else + { + RINOK(CopyFile_Ask(state, srcPath, fi, destPath2)) + } + } + return S_OK; +} + + + +/* we can call CopyFileSystemItems() from CDropTarget::Drop() */ + +HRESULT CopyFileSystemItems( + const UStringVector &itemsPaths, + const FString &destDirPrefix, + bool moveMode, + IFolderOperationsExtractCallback *callback) +{ + if (itemsPaths.IsEmpty()) + return S_OK; + + if (destDirPrefix.IsEmpty()) + return E_INVALIDARG; + + const bool isAltDest = NName::IsAltPathPrefix(destDirPrefix); + + CFsFolderStat stat; + stat.Progress = callback; + + { + FOR_VECTOR (i, itemsPaths) + { + const UString &path = itemsPaths[i]; + CFileInfo fi; + if (!fi.Find(us2fs(path))) + continue; + if (fi.IsDir()) + { + if (!isAltDest) + { + stat.Path = us2fs(path); + RINOK(stat.Enumerate()) + } + stat.NumFolders++; + } + else + { + stat.NumFiles++; + stat.Size += fi.Size; + } + } + } + + /* + if (stat.NumFolders != 0 && isAltDest) + return E_NOTIMPL; + */ + + RINOK(callback->SetTotal(stat.Size)) + // RINOK(progress->SetNumFiles(stat.NumFiles)); + + UInt64 completedSize = 0; + RINOK(callback->SetCompleted(&completedSize)) + + CCopyState state; + state.ProgressInfo.TotalSize = stat.Size; + state.ProgressInfo.StartPos = 0; + state.ProgressInfo.Progress = callback; + state.ProgressInfo.Init(); + state.Callback = callback; + state.MoveMode = moveMode; + state.IsAltStreamsDest = isAltDest; + /* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER, + if there are alt streams in fromFile. + So we don't use CopyFileW() for alt Streams. */ + state.UseReadWriteMode = isAltDest; + + FOR_VECTOR (i, itemsPaths) + { + const UString path = itemsPaths[i]; + CFileInfo fi; + + if (!fi.Find(us2fs(path))) + { + RINOK(SendMessageError(callback, "Cannot find the file", us2fs(path))) + continue; + } + + FString destPath = destDirPrefix; + destPath += fi.Name; + + if (fi.IsDir()) + { + if (isAltDest) + { + RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, us2fs(path))) + } + else + { + RINOK(CopyFolder(state, us2fs(path), destPath)) + } + } + else + { + RINOK(CopyFile_Ask(state, us2fs(path), fi, destPath)) + } + } + return S_OK; +} + + +/* we don't use CFSFolder::CopyFrom() because the caller of CopyFrom() + is optimized for IFolderArchiveUpdateCallback interface, + but we want to use IFolderOperationsExtractCallback interface instead */ + +Z7_COM7F_IMF(CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */, + const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */)) +{ + /* + Z7_DECL_CMyComPtr_QI_FROM( + IFolderOperationsExtractCallback, + callback, progress) + if (!callback) + return E_NOTIMPL; + return CopyFileSystemItems(_path, + moveMode, fromDirPrefix, + itemsPaths, numItems, callback); + */ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CFSFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */)) +{ + return E_NOTIMPL; +} + +} diff --git a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp index 569a6c1e1..1c33464c8 100644 --- a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp +++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp @@ -1,394 +1,394 @@ -// FileFolderPluginOpen.cpp - -#include "StdAfx.h" - -#include "resource.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/Thread.h" - -#include "../Agent/Agent.h" -#include "../GUI/ExtractRes.h" - -#include "FileFolderPluginOpen.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "OpenCallback.h" -#include "PluginLoader.h" -#include "PropertyName.h" -#include "RegistryPlugins.h" - -using namespace NWindows; - -struct CThreadArchiveOpen -{ - UString Path; - UString ArcFormat; - CMyComPtr InStream; - CMyComPtr FolderManager; - CMyComPtr OpenCallbackProgress; - - COpenArchiveCallback *OpenCallbackSpec; - /* - CMyComPtr - // CMyComPtr - // CMyComPtr - OpenCallbackSpec_Ref; - */ - - CMyComPtr Folder; - HRESULT Result; - - void Process() - { - try - { - CProgressCloser closer(OpenCallbackSpec->ProgressDialog); - Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallbackProgress); - } - catch(...) { Result = E_FAIL; } - } - - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - ((CThreadArchiveOpen *)param)->Process(); - return 0; - } -}; - -/* -static int FindPlugin(const CObjectVector &plugins, const UString &pluginName) -{ - for (int i = 0; i < plugins.Size(); i++) - if (plugins[i].Name.CompareNoCase(pluginName) == 0) - return i; - return -1; -} -*/ - -static void SplitNameToPureNameAndExtension(const FString &fullName, - FString &pureName, FString &extensionDelimiter, FString &extension) -{ - const int index = fullName.ReverseFind_Dot(); - if (index < 0) - { - pureName = fullName; - extensionDelimiter.Empty(); - extension.Empty(); - } - else - { - pureName.SetFrom(fullName, (unsigned)index); - extensionDelimiter = '.'; - extension = fullName.Ptr((unsigned)index + 1); - } -} - - -struct CArcLevelInfo -{ - UString Error; - UString Path; - UString Type; - UString ErrorType; - UString ErrorFlags; -}; - - -struct CArcLevelsInfo -{ - CObjectVector Levels; // LastLevel Is NON-OPEN -}; - - -UString GetOpenArcErrorMessage(UInt32 errorFlags); - - -static void GetFolderLevels(CMyComPtr &folder, CArcLevelsInfo &levels) -{ - levels.Levels.Clear(); - - CMyComPtr getFolderArcProps; - folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - - if (!getFolderArcProps) - return; - CMyComPtr arcProps; - getFolderArcProps->GetFolderArcProps(&arcProps); - if (!arcProps) - return; - - UInt32 numLevels; - if (arcProps->GetArcNumLevels(&numLevels) != S_OK) - numLevels = 0; - - for (UInt32 level = 0; level <= numLevels; level++) - { - const PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType }; - - CArcLevelInfo lev; - - for (Int32 i = 0; i < 4; i++) - { - CMyComBSTR name; - NCOM::CPropVariant prop; - if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK) - continue; - if (prop.vt != VT_EMPTY) - { - UString *s = NULL; - switch (propIDs[i]) - { - case kpidError: s = &lev.Error; break; - case kpidPath: s = &lev.Path; break; - case kpidType: s = &lev.Type; break; - case kpidErrorType: s = &lev.ErrorType; break; - } - *s = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; - } - } - - { - NCOM::CPropVariant prop; - if (arcProps->GetArcProp(level, kpidErrorFlags, &prop) == S_OK) - { - UInt32 flags = GetOpenArcErrorFlags(prop); - if (flags != 0) - lev.ErrorFlags = GetOpenArcErrorMessage(flags); - } - } - - levels.Levels.Add(lev); - } -} - -static UString GetBracedType(const wchar_t *type) -{ - UString s ('['); - s += type; - s.Add_Char(']'); - return s; -} - -static void GetFolderError(CMyComPtr &folder, UString &open_Errors, UString &nonOpen_Errors) -{ - CArcLevelsInfo levs; - GetFolderLevels(folder, levs); - open_Errors.Empty(); - nonOpen_Errors.Empty(); - - FOR_VECTOR (i, levs.Levels) - { - bool isNonOpenLevel = (i == 0); - const CArcLevelInfo &lev = levs.Levels[levs.Levels.Size() - 1 - i]; - - UString m; - - if (!lev.ErrorType.IsEmpty()) - { - m = MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(lev.ErrorType)); - if (!isNonOpenLevel) - { - m.Add_LF(); - m += MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(lev.Type)); - } - } - - if (!lev.Error.IsEmpty()) - { - if (!m.IsEmpty()) - m.Add_LF(); - m += GetBracedType(lev.Type); - m += " : "; - m += GetNameOfProperty(kpidError, L"Error"); - m += " : "; - m += lev.Error; - } - - if (!lev.ErrorFlags.IsEmpty()) - { - if (!m.IsEmpty()) - m.Add_LF(); - m += GetNameOfProperty(kpidErrorFlags, L"Errors"); - m += ": "; - m += lev.ErrorFlags; - } - - if (!m.IsEmpty()) - { - if (isNonOpenLevel) - { - UString &s = nonOpen_Errors; - s += lev.Path; - s.Add_LF(); - s += m; - } - else - { - UString &s = open_Errors; - if (!s.IsEmpty()) - s += "--------------------\n"; - s += lev.Path; - s.Add_LF(); - s += m; - } - } - } -} - -#ifdef _MSC_VER -#pragma warning(error : 4702) // unreachable code -#endif - -HRESULT CFfpOpen::OpenFileFolderPlugin(IInStream *inStream, - const FString &path, const UString &arcFormat, HWND parentWindow) -{ - /* - CObjectVector plugins; - ReadFileFolderPluginInfoList(plugins); - */ - - FString extension, name, pureName, dot; - - const int slashPos = path.ReverseFind_PathSepar(); - FString dirPrefix; - FString fileName; - if (slashPos >= 0) - { - dirPrefix.SetFrom(path, (unsigned)(slashPos + 1)); - fileName = path.Ptr((unsigned)(slashPos + 1)); - } - else - fileName = path; - - SplitNameToPureNameAndExtension(fileName, pureName, dot, extension); - - /* - if (!extension.IsEmpty()) - { - CExtInfo extInfo; - if (ReadInternalAssociation(extension, extInfo)) - { - for (int i = extInfo.Plugins.Size() - 1; i >= 0; i--) - { - int pluginIndex = FindPlugin(plugins, extInfo.Plugins[i]); - if (pluginIndex >= 0) - { - const CPluginInfo plugin = plugins[pluginIndex]; - plugins.Delete(pluginIndex); - plugins.Insert(0, plugin); - } - } - } - } - */ - - ErrorMessage.Empty(); - - // FOR_VECTOR (i, plugins) - // { - /* - const CPluginInfo &plugin = plugins[i]; - if (!plugin.ClassID_Defined && !plugin.FilePath.IsEmpty()) - continue; - */ - CPluginLibrary library; - - CThreadArchiveOpen t; - - // if (plugin.FilePath.IsEmpty()) - t.FolderManager = new CArchiveFolderManager; - /* - else if (library.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &t.FolderManager) != S_OK) - continue; - */ - - COpenArchiveCallback OpenCallbackSpec_loc; - t.OpenCallbackSpec = &OpenCallbackSpec_loc; - /* - t.OpenCallbackSpec = new COpenArchiveCallback; - t.OpenCallbackSpec_Ref = t.OpenCallbackSpec; - */ - t.OpenCallbackSpec->PasswordIsDefined = Encrypted; - t.OpenCallbackSpec->Password = Password; - t.OpenCallbackSpec->ParentWindow = parentWindow; - - /* COpenCallbackImp object will exist after Open stage for multivolume archives */ - COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; - t.OpenCallbackProgress = openCallbackSpec; - // openCallbackSpec->Callback_Ref = t.OpenCallbackSpec; - // we set pointer without reference counter: - openCallbackSpec->Callback = - // openCallbackSpec->ReOpenCallback = - t.OpenCallbackSpec; - - if (inStream) - openCallbackSpec->SetSubArchiveName(fs2us(fileName)); - else - { - RINOK(openCallbackSpec->Init2(dirPrefix, fileName)) - } - - t.InStream = inStream; - t.Path = fs2us(path); - t.ArcFormat = arcFormat; - - const UString progressTitle = LangString(IDS_OPENNING); - { - CProgressDialog &pd = t.OpenCallbackSpec->ProgressDialog; - pd.MainWindow = parentWindow; - pd.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); - pd.MainAddTitle = progressTitle + L' '; - pd.WaitMode = true; - } - - { - NWindows::CThread thread; - const WRes wres = thread.Create(CThreadArchiveOpen::MyThreadFunction, &t); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread); - } - - /* - if archive is multivolume: - COpenCallbackImp object will exist after Open stage. - COpenCallbackImp object will be deleted when last reference - from each volume object (CInFileStreamVol) will be closed (when archive will be closed). - */ - t.OpenCallbackProgress.Release(); - - if (t.Result != S_FALSE && t.Result != S_OK) - return t.Result; - - if (t.Folder) - { - UString open_Errors, nonOpen_Errors; - GetFolderError(t.Folder, open_Errors, nonOpen_Errors); - if (!nonOpen_Errors.IsEmpty()) - { - ErrorMessage = nonOpen_Errors; - // if (t.Result != S_OK) return t.Result; - /* if there are good open leves, and non0open level, - we could force error as critical error and return error here - but it's better to allow to open such rachives */ - // return S_FALSE; - } - } - - // if (openCallbackSpec->PasswordWasAsked) - { - Encrypted = t.OpenCallbackSpec->PasswordIsDefined; - Password = t.OpenCallbackSpec->Password; - } - - if (t.Result == S_OK) - { - Library.Attach(library.Detach()); - // Folder.Attach(t.Folder.Detach()); - Folder = t.Folder; - } - - return t.Result; - // } -} +// FileFolderPluginOpen.cpp + +#include "StdAfx.h" + +#include "resource.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/Thread.h" + +#include "../Agent/Agent.h" +#include "../GUI/ExtractRes.h" + +#include "FileFolderPluginOpen.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "OpenCallback.h" +#include "PluginLoader.h" +#include "PropertyName.h" +#include "RegistryPlugins.h" + +using namespace NWindows; + +struct CThreadArchiveOpen +{ + UString Path; + UString ArcFormat; + CMyComPtr InStream; + CMyComPtr FolderManager; + CMyComPtr OpenCallbackProgress; + + COpenArchiveCallback *OpenCallbackSpec; + /* + CMyComPtr + // CMyComPtr + // CMyComPtr + OpenCallbackSpec_Ref; + */ + + CMyComPtr Folder; + HRESULT Result; + + void Process() + { + try + { + CProgressCloser closer(OpenCallbackSpec->ProgressDialog); + Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallbackProgress); + } + catch(...) { Result = E_FAIL; } + } + + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + ((CThreadArchiveOpen *)param)->Process(); + return 0; + } +}; + +/* +static int FindPlugin(const CObjectVector &plugins, const UString &pluginName) +{ + for (int i = 0; i < plugins.Size(); i++) + if (plugins[i].Name.CompareNoCase(pluginName) == 0) + return i; + return -1; +} +*/ + +static void SplitNameToPureNameAndExtension(const FString &fullName, + FString &pureName, FString &extensionDelimiter, FString &extension) +{ + const int index = fullName.ReverseFind_Dot(); + if (index < 0) + { + pureName = fullName; + extensionDelimiter.Empty(); + extension.Empty(); + } + else + { + pureName.SetFrom(fullName, (unsigned)index); + extensionDelimiter = '.'; + extension = fullName.Ptr((unsigned)index + 1); + } +} + + +struct CArcLevelInfo +{ + UString Error; + UString Path; + UString Type; + UString ErrorType; + UString ErrorFlags; +}; + + +struct CArcLevelsInfo +{ + CObjectVector Levels; // LastLevel Is NON-OPEN +}; + + +UString GetOpenArcErrorMessage(UInt32 errorFlags); + + +static void GetFolderLevels(CMyComPtr &folder, CArcLevelsInfo &levels) +{ + levels.Levels.Clear(); + + CMyComPtr getFolderArcProps; + folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + + if (!getFolderArcProps) + return; + CMyComPtr arcProps; + getFolderArcProps->GetFolderArcProps(&arcProps); + if (!arcProps) + return; + + UInt32 numLevels; + if (arcProps->GetArcNumLevels(&numLevels) != S_OK) + numLevels = 0; + + for (UInt32 level = 0; level <= numLevels; level++) + { + const PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType }; + + CArcLevelInfo lev; + + for (Int32 i = 0; i < 4; i++) + { + CMyComBSTR name; + NCOM::CPropVariant prop; + if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK) + continue; + if (prop.vt != VT_EMPTY) + { + UString *s = NULL; + switch (propIDs[i]) + { + case kpidError: s = &lev.Error; break; + case kpidPath: s = &lev.Path; break; + case kpidType: s = &lev.Type; break; + case kpidErrorType: s = &lev.ErrorType; break; + } + *s = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?"; + } + } + + { + NCOM::CPropVariant prop; + if (arcProps->GetArcProp(level, kpidErrorFlags, &prop) == S_OK) + { + UInt32 flags = GetOpenArcErrorFlags(prop); + if (flags != 0) + lev.ErrorFlags = GetOpenArcErrorMessage(flags); + } + } + + levels.Levels.Add(lev); + } +} + +static UString GetBracedType(const wchar_t *type) +{ + UString s ('['); + s += type; + s.Add_Char(']'); + return s; +} + +static void GetFolderError(CMyComPtr &folder, UString &open_Errors, UString &nonOpen_Errors) +{ + CArcLevelsInfo levs; + GetFolderLevels(folder, levs); + open_Errors.Empty(); + nonOpen_Errors.Empty(); + + FOR_VECTOR (i, levs.Levels) + { + bool isNonOpenLevel = (i == 0); + const CArcLevelInfo &lev = levs.Levels[levs.Levels.Size() - 1 - i]; + + UString m; + + if (!lev.ErrorType.IsEmpty()) + { + m = MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(lev.ErrorType)); + if (!isNonOpenLevel) + { + m.Add_LF(); + m += MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(lev.Type)); + } + } + + if (!lev.Error.IsEmpty()) + { + if (!m.IsEmpty()) + m.Add_LF(); + m += GetBracedType(lev.Type); + m += " : "; + m += GetNameOfProperty(kpidError, L"Error"); + m += " : "; + m += lev.Error; + } + + if (!lev.ErrorFlags.IsEmpty()) + { + if (!m.IsEmpty()) + m.Add_LF(); + m += GetNameOfProperty(kpidErrorFlags, L"Errors"); + m += ": "; + m += lev.ErrorFlags; + } + + if (!m.IsEmpty()) + { + if (isNonOpenLevel) + { + UString &s = nonOpen_Errors; + s += lev.Path; + s.Add_LF(); + s += m; + } + else + { + UString &s = open_Errors; + if (!s.IsEmpty()) + s += "--------------------\n"; + s += lev.Path; + s.Add_LF(); + s += m; + } + } + } +} + +#ifdef _MSC_VER +#pragma warning(error : 4702) // unreachable code +#endif + +HRESULT CFfpOpen::OpenFileFolderPlugin(IInStream *inStream, + const FString &path, const UString &arcFormat, HWND parentWindow) +{ + /* + CObjectVector plugins; + ReadFileFolderPluginInfoList(plugins); + */ + + FString extension, name, pureName, dot; + + const int slashPos = path.ReverseFind_PathSepar(); + FString dirPrefix; + FString fileName; + if (slashPos >= 0) + { + dirPrefix.SetFrom(path, (unsigned)(slashPos + 1)); + fileName = path.Ptr((unsigned)(slashPos + 1)); + } + else + fileName = path; + + SplitNameToPureNameAndExtension(fileName, pureName, dot, extension); + + /* + if (!extension.IsEmpty()) + { + CExtInfo extInfo; + if (ReadInternalAssociation(extension, extInfo)) + { + for (int i = extInfo.Plugins.Size() - 1; i >= 0; i--) + { + int pluginIndex = FindPlugin(plugins, extInfo.Plugins[i]); + if (pluginIndex >= 0) + { + const CPluginInfo plugin = plugins[pluginIndex]; + plugins.Delete(pluginIndex); + plugins.Insert(0, plugin); + } + } + } + } + */ + + ErrorMessage.Empty(); + + // FOR_VECTOR (i, plugins) + // { + /* + const CPluginInfo &plugin = plugins[i]; + if (!plugin.ClassID_Defined && !plugin.FilePath.IsEmpty()) + continue; + */ + CPluginLibrary library; + + CThreadArchiveOpen t; + + // if (plugin.FilePath.IsEmpty()) + t.FolderManager = new CArchiveFolderManager; + /* + else if (library.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &t.FolderManager) != S_OK) + continue; + */ + + COpenArchiveCallback OpenCallbackSpec_loc; + t.OpenCallbackSpec = &OpenCallbackSpec_loc; + /* + t.OpenCallbackSpec = new COpenArchiveCallback; + t.OpenCallbackSpec_Ref = t.OpenCallbackSpec; + */ + t.OpenCallbackSpec->PasswordIsDefined = Encrypted; + t.OpenCallbackSpec->Password = Password; + t.OpenCallbackSpec->ParentWindow = parentWindow; + + /* COpenCallbackImp object will exist after Open stage for multivolume archives */ + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + t.OpenCallbackProgress = openCallbackSpec; + // openCallbackSpec->Callback_Ref = t.OpenCallbackSpec; + // we set pointer without reference counter: + openCallbackSpec->Callback = + // openCallbackSpec->ReOpenCallback = + t.OpenCallbackSpec; + + if (inStream) + openCallbackSpec->SetSubArchiveName(fs2us(fileName)); + else + { + RINOK(openCallbackSpec->Init2(dirPrefix, fileName)) + } + + t.InStream = inStream; + t.Path = fs2us(path); + t.ArcFormat = arcFormat; + + const UString progressTitle = LangString(IDS_OPENNING); + { + CProgressDialog &pd = t.OpenCallbackSpec->ProgressDialog; + pd.MainWindow = parentWindow; + pd.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); + pd.MainAddTitle = progressTitle + L' '; + pd.WaitMode = true; + } + + { + NWindows::CThread thread; + const WRes wres = thread.Create(CThreadArchiveOpen::MyThreadFunction, &t); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread); + } + + /* + if archive is multivolume: + COpenCallbackImp object will exist after Open stage. + COpenCallbackImp object will be deleted when last reference + from each volume object (CInFileStreamVol) will be closed (when archive will be closed). + */ + t.OpenCallbackProgress.Release(); + + if (t.Result != S_FALSE && t.Result != S_OK) + return t.Result; + + if (t.Folder) + { + UString open_Errors, nonOpen_Errors; + GetFolderError(t.Folder, open_Errors, nonOpen_Errors); + if (!nonOpen_Errors.IsEmpty()) + { + ErrorMessage = nonOpen_Errors; + // if (t.Result != S_OK) return t.Result; + /* if there are good open leves, and non0open level, + we could force error as critical error and return error here + but it's better to allow to open such rachives */ + // return S_FALSE; + } + } + + // if (openCallbackSpec->PasswordWasAsked) + { + Encrypted = t.OpenCallbackSpec->PasswordIsDefined; + Password = t.OpenCallbackSpec->Password; + } + + if (t.Result == S_OK) + { + Library.Attach(library.Detach()); + // Folder.Attach(t.Folder.Detach()); + Folder = t.Folder; + } + + return t.Result; + // } +} diff --git a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h index fc645473b..88027659d 100644 --- a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h +++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h @@ -1,27 +1,27 @@ -// FileFolderPluginOpen.h - -#ifndef ZIP7_INC_FILE_FOLDER_PLUGIN_OPEN_H -#define ZIP7_INC_FILE_FOLDER_PLUGIN_OPEN_H - -#include "../../../Windows/DLL.h" - -struct CFfpOpen -{ - Z7_CLASS_NO_COPY(CFfpOpen) -public: - // out: - bool Encrypted; - UString Password; - - NWindows::NDLL::CLibrary Library; - CMyComPtr Folder; - UString ErrorMessage; - - CFfpOpen(): Encrypted (false) {} - - HRESULT OpenFileFolderPlugin(IInStream *inStream, - const FString &path, const UString &arcFormat, HWND parentWindow); -}; - - -#endif +// FileFolderPluginOpen.h + +#ifndef ZIP7_INC_FILE_FOLDER_PLUGIN_OPEN_H +#define ZIP7_INC_FILE_FOLDER_PLUGIN_OPEN_H + +#include "../../../Windows/DLL.h" + +struct CFfpOpen +{ + Z7_CLASS_NO_COPY(CFfpOpen) +public: + // out: + bool Encrypted; + UString Password; + + NWindows::NDLL::CLibrary Library; + CMyComPtr Folder; + UString ErrorMessage; + + CFfpOpen(): Encrypted (false) {} + + HRESULT OpenFileFolderPlugin(IInStream *inStream, + const FString &path, const UString &arcFormat, HWND parentWindow); +}; + + +#endif diff --git a/CPP/7zip/UI/FileManager/FilePlugins.cpp b/CPP/7zip/UI/FileManager/FilePlugins.cpp index 184a2dfb5..cf20970f0 100644 --- a/CPP/7zip/UI/FileManager/FilePlugins.cpp +++ b/CPP/7zip/UI/FileManager/FilePlugins.cpp @@ -1,78 +1,78 @@ -// FilePlugins.cpp - -#include "StdAfx.h" - -#include "../Agent/Agent.h" - -#include "FilePlugins.h" -#include "PluginLoader.h" -#include "StringUtils.h" - -int CExtDatabase::FindExt(const UString &ext) const -{ - FOR_VECTOR (i, Exts) - if (Exts[i].Ext.IsEqualTo_NoCase(ext)) - return (int)i; - return -1; -} - -void CExtDatabase::Read() -{ - /* - ReadFileFolderPluginInfoList(Plugins); - FOR_VECTOR (pluginIndex, Plugins) - */ - { - // const CPluginInfo &plugin = Plugins[pluginIndex]; - - CPluginLibrary pluginLib; - CMyComPtr folderManager; - - // if (plugin.FilePath.IsEmpty()) - folderManager = new CArchiveFolderManager; - /* - else - { - if (!plugin.ClassID_Defined) - continue; - if (pluginLib.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &folderManager) != S_OK) - continue; - } - */ - CMyComBSTR extBSTR; - if (folderManager->GetExtensions(&extBSTR) != S_OK) - return; - UStringVector exts; - SplitString((const wchar_t *)extBSTR, exts); - FOR_VECTOR (i, exts) - { - const UString &ext = exts[i]; - #ifdef UNDER_CE - if (ext == L"cab") - continue; - #endif - - Int32 iconIndex; - CMyComBSTR iconPath; - CPluginToIcon plugPair; - // plugPair.PluginIndex = pluginIndex; - if (folderManager->GetIconPath(ext, &iconPath, &iconIndex) == S_OK) - if (iconPath) - { - plugPair.IconPath = (const wchar_t *)iconPath; - plugPair.IconIndex = iconIndex; - } - - const int index = FindExt(ext); - if (index >= 0) - Exts[index].Plugins.Add(plugPair); - else - { - CExtPlugins extInfo; - extInfo.Plugins.Add(plugPair); - extInfo.Ext = ext; - Exts.Add(extInfo); - } - } - } -} +// FilePlugins.cpp + +#include "StdAfx.h" + +#include "../Agent/Agent.h" + +#include "FilePlugins.h" +#include "PluginLoader.h" +#include "StringUtils.h" + +int CExtDatabase::FindExt(const UString &ext) const +{ + FOR_VECTOR (i, Exts) + if (Exts[i].Ext.IsEqualTo_NoCase(ext)) + return (int)i; + return -1; +} + +void CExtDatabase::Read() +{ + /* + ReadFileFolderPluginInfoList(Plugins); + FOR_VECTOR (pluginIndex, Plugins) + */ + { + // const CPluginInfo &plugin = Plugins[pluginIndex]; + + CPluginLibrary pluginLib; + CMyComPtr folderManager; + + // if (plugin.FilePath.IsEmpty()) + folderManager = new CArchiveFolderManager; + /* + else + { + if (!plugin.ClassID_Defined) + continue; + if (pluginLib.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &folderManager) != S_OK) + continue; + } + */ + CMyComBSTR extBSTR; + if (folderManager->GetExtensions(&extBSTR) != S_OK) + return; + UStringVector exts; + SplitString((const wchar_t *)extBSTR, exts); + FOR_VECTOR (i, exts) + { + const UString &ext = exts[i]; + #ifdef UNDER_CE + if (ext == L"cab") + continue; + #endif + + Int32 iconIndex; + CMyComBSTR iconPath; + CPluginToIcon plugPair; + // plugPair.PluginIndex = pluginIndex; + if (folderManager->GetIconPath(ext, &iconPath, &iconIndex) == S_OK) + if (iconPath) + { + plugPair.IconPath = (const wchar_t *)iconPath; + plugPair.IconIndex = iconIndex; + } + + const int index = FindExt(ext); + if (index >= 0) + Exts[index].Plugins.Add(plugPair); + else + { + CExtPlugins extInfo; + extInfo.Plugins.Add(plugPair); + extInfo.Ext = ext; + Exts.Add(extInfo); + } + } + } +} diff --git a/CPP/7zip/UI/FileManager/FilePlugins.h b/CPP/7zip/UI/FileManager/FilePlugins.h index 52d0288a5..db8ec396f 100644 --- a/CPP/7zip/UI/FileManager/FilePlugins.h +++ b/CPP/7zip/UI/FileManager/FilePlugins.h @@ -1,33 +1,33 @@ -// FilePlugins.h - -#ifndef ZIP7_INC_FILE_PLUGINS_H -#define ZIP7_INC_FILE_PLUGINS_H - -#include "RegistryPlugins.h" - -struct CPluginToIcon -{ - // unsigned PluginIndex; - int IconIndex; - UString IconPath; - - CPluginToIcon(): IconIndex(-1) {} -}; - -struct CExtPlugins -{ - UString Ext; - CObjectVector Plugins; -}; - -class CExtDatabase -{ - int FindExt(const UString &ext) const; -public: - CObjectVector Exts; - // CObjectVector Plugins; - - void Read(); -}; - -#endif +// FilePlugins.h + +#ifndef ZIP7_INC_FILE_PLUGINS_H +#define ZIP7_INC_FILE_PLUGINS_H + +#include "RegistryPlugins.h" + +struct CPluginToIcon +{ + // unsigned PluginIndex; + int IconIndex; + UString IconPath; + + CPluginToIcon(): IconIndex(-1) {} +}; + +struct CExtPlugins +{ + UString Ext; + CObjectVector Plugins; +}; + +class CExtDatabase +{ + int FindExt(const UString &ext) const; +public: + CObjectVector Exts; + // CObjectVector Plugins; + + void Read(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/FoldersPage.cpp b/CPP/7zip/UI/FileManager/FoldersPage.cpp index 07f66573b..7e74635b0 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage.cpp +++ b/CPP/7zip/UI/FileManager/FoldersPage.cpp @@ -1,172 +1,172 @@ -// FoldersPage.cpp - -#include "StdAfx.h" - -#include "FoldersPageRes.h" -#include "FoldersPage.h" - -#include "../FileManager/BrowseDialog.h" -#include "../FileManager/HelpUtils.h" -#include "../FileManager/LangUtils.h" - -using namespace NWindows; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_FOLDERS_WORKING_FOLDER, - IDR_FOLDERS_WORK_SYSTEM, - IDR_FOLDERS_WORK_CURRENT, - IDR_FOLDERS_WORK_SPECIFIED, - IDX_FOLDERS_WORK_FOR_REMOVABLE -}; -#endif - -static const unsigned kWorkModeButtons[] = -{ - IDR_FOLDERS_WORK_SYSTEM, - IDR_FOLDERS_WORK_CURRENT, - IDR_FOLDERS_WORK_SPECIFIED -}; - -#define kFoldersTopic "fm/options.htm#folders" - -static const unsigned kNumWorkModeButtons = Z7_ARRAY_SIZE(kWorkModeButtons); - -bool CFoldersPage::OnInit() -{ - _initMode = true; - _needSave = false; - - #ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - m_WorkDirInfo.Load(); - - CheckButton(IDX_FOLDERS_WORK_FOR_REMOVABLE, m_WorkDirInfo.ForRemovableOnly); - - CheckRadioButton( - kWorkModeButtons[0], - kWorkModeButtons[kNumWorkModeButtons - 1], - kWorkModeButtons[m_WorkDirInfo.Mode]); - - m_WorkPath.Init(*this, IDE_FOLDERS_WORK_PATH); - - m_WorkPath.SetText(fs2us(m_WorkDirInfo.Path)); - - MyEnableControls(); - - _initMode = false; - return CPropertyPage::OnInit(); -} - -int CFoldersPage::GetWorkMode() const -{ - for (unsigned i = 0; i < kNumWorkModeButtons; i++) - if (IsButtonCheckedBool(kWorkModeButtons[i])) - return (int)i; - throw 0; -} - -void CFoldersPage::MyEnableControls() -{ - bool enablePath = (GetWorkMode() == NWorkDir::NMode::kSpecified); - m_WorkPath.Enable(enablePath); - EnableItem(IDB_FOLDERS_WORK_PATH, enablePath); -} - -void CFoldersPage::GetWorkDir(NWorkDir::CInfo &workDirInfo) -{ - UString s; - m_WorkPath.GetText(s); - workDirInfo.Path = us2fs(s); - workDirInfo.ForRemovableOnly = IsButtonCheckedBool(IDX_FOLDERS_WORK_FOR_REMOVABLE); - workDirInfo.Mode = NWorkDir::NMode::EEnum(GetWorkMode()); -} - -/* -bool CFoldersPage::WasChanged() -{ - NWorkDir::CInfo workDirInfo; - GetWorkDir(workDirInfo); - return (workDirInfo.Mode != m_WorkDirInfo.Mode || - workDirInfo.ForRemovableOnly != m_WorkDirInfo.ForRemovableOnly || - workDirInfo.Path.Compare(m_WorkDirInfo.Path) != 0); -} -*/ - -void CFoldersPage::ModifiedEvent() -{ - if (!_initMode) - { - _needSave = true; - Changed(); - } - /* - if (WasChanged()) - Changed(); - else - UnChanged(); - */ -} - -bool CFoldersPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - for (unsigned i = 0; i < kNumWorkModeButtons; i++) - if (buttonID == kWorkModeButtons[i]) - { - MyEnableControls(); - ModifiedEvent(); - return true; - } - - switch (buttonID) - { - case IDB_FOLDERS_WORK_PATH: - OnFoldersWorkButtonPath(); - return true; - case IDX_FOLDERS_WORK_FOR_REMOVABLE: - break; - default: - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); - } - - ModifiedEvent(); - return true; -} - -bool CFoldersPage::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == EN_CHANGE && itemID == IDE_FOLDERS_WORK_PATH) - { - ModifiedEvent(); - return true; - } - return CPropertyPage::OnCommand(code, itemID, lParam); -} - -void CFoldersPage::OnFoldersWorkButtonPath() -{ - UString currentPath; - m_WorkPath.GetText(currentPath); - UString title = LangString(IDS_FOLDERS_SET_WORK_PATH_TITLE); - UString resultPath; - if (MyBrowseForFolder(*this, title, currentPath, resultPath)) - m_WorkPath.SetText(resultPath); -} - -LONG CFoldersPage::OnApply() -{ - if (_needSave) - { - GetWorkDir(m_WorkDirInfo); - m_WorkDirInfo.Save(); - _needSave = false; - } - return PSNRET_NOERROR; -} - -void CFoldersPage::OnNotifyHelp() -{ - ShowHelpWindow(kFoldersTopic); -} +// FoldersPage.cpp + +#include "StdAfx.h" + +#include "FoldersPageRes.h" +#include "FoldersPage.h" + +#include "../FileManager/BrowseDialog.h" +#include "../FileManager/HelpUtils.h" +#include "../FileManager/LangUtils.h" + +using namespace NWindows; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_FOLDERS_WORKING_FOLDER, + IDR_FOLDERS_WORK_SYSTEM, + IDR_FOLDERS_WORK_CURRENT, + IDR_FOLDERS_WORK_SPECIFIED, + IDX_FOLDERS_WORK_FOR_REMOVABLE +}; +#endif + +static const unsigned kWorkModeButtons[] = +{ + IDR_FOLDERS_WORK_SYSTEM, + IDR_FOLDERS_WORK_CURRENT, + IDR_FOLDERS_WORK_SPECIFIED +}; + +#define kFoldersTopic "fm/options.htm#folders" + +static const unsigned kNumWorkModeButtons = Z7_ARRAY_SIZE(kWorkModeButtons); + +bool CFoldersPage::OnInit() +{ + _initMode = true; + _needSave = false; + + #ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + m_WorkDirInfo.Load(); + + CheckButton(IDX_FOLDERS_WORK_FOR_REMOVABLE, m_WorkDirInfo.ForRemovableOnly); + + CheckRadioButton( + kWorkModeButtons[0], + kWorkModeButtons[kNumWorkModeButtons - 1], + kWorkModeButtons[m_WorkDirInfo.Mode]); + + m_WorkPath.Init(*this, IDE_FOLDERS_WORK_PATH); + + m_WorkPath.SetText(fs2us(m_WorkDirInfo.Path)); + + MyEnableControls(); + + _initMode = false; + return CPropertyPage::OnInit(); +} + +int CFoldersPage::GetWorkMode() const +{ + for (unsigned i = 0; i < kNumWorkModeButtons; i++) + if (IsButtonCheckedBool(kWorkModeButtons[i])) + return (int)i; + throw 0; +} + +void CFoldersPage::MyEnableControls() +{ + bool enablePath = (GetWorkMode() == NWorkDir::NMode::kSpecified); + m_WorkPath.Enable(enablePath); + EnableItem(IDB_FOLDERS_WORK_PATH, enablePath); +} + +void CFoldersPage::GetWorkDir(NWorkDir::CInfo &workDirInfo) +{ + UString s; + m_WorkPath.GetText(s); + workDirInfo.Path = us2fs(s); + workDirInfo.ForRemovableOnly = IsButtonCheckedBool(IDX_FOLDERS_WORK_FOR_REMOVABLE); + workDirInfo.Mode = NWorkDir::NMode::EEnum(GetWorkMode()); +} + +/* +bool CFoldersPage::WasChanged() +{ + NWorkDir::CInfo workDirInfo; + GetWorkDir(workDirInfo); + return (workDirInfo.Mode != m_WorkDirInfo.Mode || + workDirInfo.ForRemovableOnly != m_WorkDirInfo.ForRemovableOnly || + workDirInfo.Path.Compare(m_WorkDirInfo.Path) != 0); +} +*/ + +void CFoldersPage::ModifiedEvent() +{ + if (!_initMode) + { + _needSave = true; + Changed(); + } + /* + if (WasChanged()) + Changed(); + else + UnChanged(); + */ +} + +bool CFoldersPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + for (unsigned i = 0; i < kNumWorkModeButtons; i++) + if (buttonID == kWorkModeButtons[i]) + { + MyEnableControls(); + ModifiedEvent(); + return true; + } + + switch (buttonID) + { + case IDB_FOLDERS_WORK_PATH: + OnFoldersWorkButtonPath(); + return true; + case IDX_FOLDERS_WORK_FOR_REMOVABLE: + break; + default: + return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); + } + + ModifiedEvent(); + return true; +} + +bool CFoldersPage::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == EN_CHANGE && itemID == IDE_FOLDERS_WORK_PATH) + { + ModifiedEvent(); + return true; + } + return CPropertyPage::OnCommand(code, itemID, lParam); +} + +void CFoldersPage::OnFoldersWorkButtonPath() +{ + UString currentPath; + m_WorkPath.GetText(currentPath); + UString title = LangString(IDS_FOLDERS_SET_WORK_PATH_TITLE); + UString resultPath; + if (MyBrowseForFolder(*this, title, currentPath, resultPath)) + m_WorkPath.SetText(resultPath); +} + +LONG CFoldersPage::OnApply() +{ + if (_needSave) + { + GetWorkDir(m_WorkDirInfo); + m_WorkDirInfo.Save(); + _needSave = false; + } + return PSNRET_NOERROR; +} + +void CFoldersPage::OnNotifyHelp() +{ + ShowHelpWindow(kFoldersTopic); +} diff --git a/CPP/7zip/UI/FileManager/FoldersPage.h b/CPP/7zip/UI/FileManager/FoldersPage.h index 14e38e2cb..09b6cddb4 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage.h +++ b/CPP/7zip/UI/FileManager/FoldersPage.h @@ -1,32 +1,32 @@ -// FoldersPage.h - -#ifndef ZIP7_INC_FOLDERS_PAGE_H -#define ZIP7_INC_FOLDERS_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" - -#include "../Common/ZipRegistry.h" - -class CFoldersPage : public NWindows::NControl::CPropertyPage -{ - NWorkDir::CInfo m_WorkDirInfo; - NWindows::NControl::CDialogChildControl m_WorkPath; - - bool _needSave; - bool _initMode; - - void MyEnableControls(); - void ModifiedEvent(); - - void OnFoldersWorkButtonPath(); - int GetWorkMode() const; - void GetWorkDir(NWorkDir::CInfo &workDirInfo); - // bool WasChanged(); - virtual bool OnInit() Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; - virtual void OnNotifyHelp() Z7_override; - virtual LONG OnApply() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; -}; - -#endif +// FoldersPage.h + +#ifndef ZIP7_INC_FOLDERS_PAGE_H +#define ZIP7_INC_FOLDERS_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" + +#include "../Common/ZipRegistry.h" + +class CFoldersPage : public NWindows::NControl::CPropertyPage +{ + NWorkDir::CInfo m_WorkDirInfo; + NWindows::NControl::CDialogChildControl m_WorkPath; + + bool _needSave; + bool _initMode; + + void MyEnableControls(); + void ModifiedEvent(); + + void OnFoldersWorkButtonPath(); + int GetWorkMode() const; + void GetWorkDir(NWorkDir::CInfo &workDirInfo); + // bool WasChanged(); + virtual bool OnInit() Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; + virtual void OnNotifyHelp() Z7_override; + virtual LONG OnApply() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/FoldersPage.rc b/CPP/7zip/UI/FileManager/FoldersPage.rc index f9fbcd3ad..3317a088f 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage.rc +++ b/CPP/7zip/UI/FileManager/FoldersPage.rc @@ -1,23 +1,23 @@ -#include "FoldersPageRes.h" -#include "../../GuiCommon.rc" - -#define xc OPTIONS_PAGE_XC_SIZE -#define yc 100 - -IDD_FOLDERS MY_PAGE -#include "FoldersPage2.rc" - -#ifdef UNDER_CE - -#undef xc -#define xc SMALL_PAGE_SIZE_X - -IDD_FOLDERS_2 MY_PAGE -#include "FoldersPage2.rc" - -#endif - -STRINGTABLE -BEGIN - IDS_FOLDERS_SET_WORK_PATH_TITLE "Specify a location for temporary archive files." -END +#include "FoldersPageRes.h" +#include "../../GuiCommon.rc" + +#define xc OPTIONS_PAGE_XC_SIZE +#define yc 100 + +IDD_FOLDERS MY_PAGE +#include "FoldersPage2.rc" + +#ifdef UNDER_CE + +#undef xc +#define xc SMALL_PAGE_SIZE_X + +IDD_FOLDERS_2 MY_PAGE +#include "FoldersPage2.rc" + +#endif + +STRINGTABLE +BEGIN + IDS_FOLDERS_SET_WORK_PATH_TITLE "Specify a location for temporary archive files." +END diff --git a/CPP/7zip/UI/FileManager/FoldersPage2.rc b/CPP/7zip/UI/FileManager/FoldersPage2.rc index c2a17e7cc..70f832e42 100644 --- a/CPP/7zip/UI/FileManager/FoldersPage2.rc +++ b/CPP/7zip/UI/FileManager/FoldersPage2.rc @@ -1,11 +1,11 @@ -CAPTION "Folders" -BEGIN - // GROUPBOX "&Working folder", IDT_FOLDERS_WORKING_FOLDER, m, m, xc, 98 - LTEXT "&Working folder", IDT_FOLDERS_WORKING_FOLDER, m, m, xc, 8 - MY_CONTROL_AUTORADIOBUTTON_GROUP ( "&System temp folder", IDR_FOLDERS_WORK_SYSTEM, m, 20, xc) - MY_CONTROL_AUTORADIOBUTTON ( "&Current", IDR_FOLDERS_WORK_CURRENT, m, 34, xc) - MY_CONTROL_AUTORADIOBUTTON ( "Specified:", IDR_FOLDERS_WORK_SPECIFIED, m, 48, xc) - EDITTEXT IDE_FOLDERS_WORK_PATH, m + m, 62, xc - m - m - bxsDots, 14, ES_AUTOHSCROLL - PUSHBUTTON "...", IDB_FOLDERS_WORK_PATH, xs - m - bxsDots, 61, bxsDots, bys - MY_CONTROL_CHECKBOX ( "Use for removable drives only", IDX_FOLDERS_WORK_FOR_REMOVABLE, m, 86, xc) -END +CAPTION "Folders" +BEGIN + // GROUPBOX "&Working folder", IDT_FOLDERS_WORKING_FOLDER, m, m, xc, 98 + LTEXT "&Working folder", IDT_FOLDERS_WORKING_FOLDER, m, m, xc, 8 + MY_CONTROL_AUTORADIOBUTTON_GROUP ( "&System temp folder", IDR_FOLDERS_WORK_SYSTEM, m, 20, xc) + MY_CONTROL_AUTORADIOBUTTON ( "&Current", IDR_FOLDERS_WORK_CURRENT, m, 34, xc) + MY_CONTROL_AUTORADIOBUTTON ( "Specified:", IDR_FOLDERS_WORK_SPECIFIED, m, 48, xc) + EDITTEXT IDE_FOLDERS_WORK_PATH, m + m, 62, xc - m - m - bxsDots, 14, ES_AUTOHSCROLL + PUSHBUTTON "...", IDB_FOLDERS_WORK_PATH, xs - m - bxsDots, 61, bxsDots, bys + MY_CONTROL_CHECKBOX ( "Use for removable drives only", IDX_FOLDERS_WORK_FOR_REMOVABLE, m, 86, xc) +END diff --git a/CPP/7zip/UI/FileManager/FoldersPageRes.h b/CPP/7zip/UI/FileManager/FoldersPageRes.h index 8049ec2fe..ba9ab73ef 100644 --- a/CPP/7zip/UI/FileManager/FoldersPageRes.h +++ b/CPP/7zip/UI/FileManager/FoldersPageRes.h @@ -1,12 +1,12 @@ -#define IDD_FOLDERS 2400 -#define IDD_FOLDERS_2 12400 - -#define IDT_FOLDERS_WORKING_FOLDER 2401 -#define IDR_FOLDERS_WORK_SYSTEM 2402 -#define IDR_FOLDERS_WORK_CURRENT 2403 -#define IDR_FOLDERS_WORK_SPECIFIED 2404 -#define IDX_FOLDERS_WORK_FOR_REMOVABLE 2405 -#define IDS_FOLDERS_SET_WORK_PATH_TITLE 2406 - -#define IDE_FOLDERS_WORK_PATH 100 -#define IDB_FOLDERS_WORK_PATH 101 +#define IDD_FOLDERS 2400 +#define IDD_FOLDERS_2 12400 + +#define IDT_FOLDERS_WORKING_FOLDER 2401 +#define IDR_FOLDERS_WORK_SYSTEM 2402 +#define IDR_FOLDERS_WORK_CURRENT 2403 +#define IDR_FOLDERS_WORK_SPECIFIED 2404 +#define IDX_FOLDERS_WORK_FOR_REMOVABLE 2405 +#define IDS_FOLDERS_SET_WORK_PATH_TITLE 2406 + +#define IDE_FOLDERS_WORK_PATH 100 +#define IDB_FOLDERS_WORK_PATH 101 diff --git a/CPP/7zip/UI/FileManager/FormatUtils.cpp b/CPP/7zip/UI/FileManager/FormatUtils.cpp index 4f7ef74e5..2143c3f1b 100644 --- a/CPP/7zip/UI/FileManager/FormatUtils.cpp +++ b/CPP/7zip/UI/FileManager/FormatUtils.cpp @@ -1,28 +1,28 @@ -// FormatUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "FormatUtils.h" - -#include "LangUtils.h" - -UString NumberToString(UInt64 number) -{ - wchar_t numberString[32]; - ConvertUInt64ToString(number, numberString); - return numberString; -} - -UString MyFormatNew(const UString &format, const UString &argument) -{ - UString result = format; - result.Replace(L"{0}", argument); - return result; -} - -UString MyFormatNew(UINT resourceID, const UString &argument) -{ - return MyFormatNew(LangString(resourceID), argument); -} +// FormatUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "FormatUtils.h" + +#include "LangUtils.h" + +UString NumberToString(UInt64 number) +{ + wchar_t numberString[32]; + ConvertUInt64ToString(number, numberString); + return numberString; +} + +UString MyFormatNew(const UString &format, const UString &argument) +{ + UString result = format; + result.Replace(L"{0}", argument); + return result; +} + +UString MyFormatNew(UINT resourceID, const UString &argument) +{ + return MyFormatNew(LangString(resourceID), argument); +} diff --git a/CPP/7zip/UI/FileManager/FormatUtils.h b/CPP/7zip/UI/FileManager/FormatUtils.h index 7cfd48054..1db08eff3 100644 --- a/CPP/7zip/UI/FileManager/FormatUtils.h +++ b/CPP/7zip/UI/FileManager/FormatUtils.h @@ -1,14 +1,14 @@ -// FormatUtils.h - -#ifndef ZIP7_INC_FORMAT_UTILS_H -#define ZIP7_INC_FORMAT_UTILS_H - -#include "../../../Common/MyTypes.h" -#include "../../../Common/MyString.h" - -UString NumberToString(UInt64 number); - -UString MyFormatNew(const UString &format, const UString &argument); -UString MyFormatNew(UINT resourceID, const UString &argument); - -#endif +// FormatUtils.h + +#ifndef ZIP7_INC_FORMAT_UTILS_H +#define ZIP7_INC_FORMAT_UTILS_H + +#include "../../../Common/MyTypes.h" +#include "../../../Common/MyString.h" + +UString NumberToString(UInt64 number); + +UString MyFormatNew(const UString &format, const UString &argument); +UString MyFormatNew(UINT resourceID, const UString &argument); + +#endif diff --git a/CPP/7zip/UI/FileManager/HelpUtils.cpp b/CPP/7zip/UI/FileManager/HelpUtils.cpp index 2b6c4851f..d5b6a580b 100644 --- a/CPP/7zip/UI/FileManager/HelpUtils.cpp +++ b/CPP/7zip/UI/FileManager/HelpUtils.cpp @@ -1,78 +1,78 @@ -// HelpUtils.cpp - -#include "StdAfx.h" - -#include "HelpUtils.h" - -#if defined(UNDER_CE) || defined(__MINGW32_VERSION) - -void ShowHelpWindow(LPCSTR) -{ -} - -#else - -/* USE_EXTERNAL_HELP creates new help process window for each HtmlHelp() call. - HtmlHelp() call uses one window. */ - -#if defined(__MINGW32_VERSION) /* || defined(Z7_OLD_WIN_SDK) */ -#define USE_EXTERNAL_HELP -#endif - -// #define USE_EXTERNAL_HELP - -#ifdef USE_EXTERNAL_HELP - -#include "../../../Windows/ProcessUtils.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" - -#else -#include -#endif - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" - -#define kHelpFileName "7-zip.chm::/" - -void ShowHelpWindow(LPCSTR topicFile) -{ - FString path = NWindows::NDLL::GetModuleDirPrefix(); - path += kHelpFileName; - path += topicFile; - #ifdef USE_EXTERNAL_HELP - FString prog; - - #ifdef UNDER_CE - prog = "\\Windows\\"; - #else - if (!NWindows::NFile::NDir::GetWindowsDir(prog)) - return; - NWindows::NFile::NName::NormalizeDirPathPrefix(prog); - #endif - prog += "hh.exe"; - - UString params; - params += '"'; - params += fs2us(path); - params += '"'; - - NWindows::CProcess process; - const WRes wres = process.Create(fs2us(prog), params, NULL); // curDir); - if (wres != 0) - { - /* - HRESULT hres = HRESULT_FROM_WIN32(wres); - ErrorMessageHRESULT(hres, imageName); - return hres; - */ - } - #else - // HWND hwnd = NULL; - HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0); - #endif -} - -#endif +// HelpUtils.cpp + +#include "StdAfx.h" + +#include "HelpUtils.h" + +#if defined(UNDER_CE) || defined(__MINGW32_VERSION) + +void ShowHelpWindow(LPCSTR) +{ +} + +#else + +/* USE_EXTERNAL_HELP creates new help process window for each HtmlHelp() call. + HtmlHelp() call uses one window. */ + +#if defined(__MINGW32_VERSION) /* || defined(Z7_OLD_WIN_SDK) */ +#define USE_EXTERNAL_HELP +#endif + +// #define USE_EXTERNAL_HELP + +#ifdef USE_EXTERNAL_HELP + +#include "../../../Windows/ProcessUtils.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" + +#else +#include +#endif + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" + +#define kHelpFileName "7-zip.chm::/" + +void ShowHelpWindow(LPCSTR topicFile) +{ + FString path = NWindows::NDLL::GetModuleDirPrefix(); + path += kHelpFileName; + path += topicFile; + #ifdef USE_EXTERNAL_HELP + FString prog; + + #ifdef UNDER_CE + prog = "\\Windows\\"; + #else + if (!NWindows::NFile::NDir::GetWindowsDir(prog)) + return; + NWindows::NFile::NName::NormalizeDirPathPrefix(prog); + #endif + prog += "hh.exe"; + + UString params; + params += '"'; + params += fs2us(path); + params += '"'; + + NWindows::CProcess process; + const WRes wres = process.Create(fs2us(prog), params, NULL); // curDir); + if (wres != 0) + { + /* + HRESULT hres = HRESULT_FROM_WIN32(wres); + ErrorMessageHRESULT(hres, imageName); + return hres; + */ + } + #else + // HWND hwnd = NULL; + HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0); + #endif +} + +#endif diff --git a/CPP/7zip/UI/FileManager/HelpUtils.h b/CPP/7zip/UI/FileManager/HelpUtils.h index cb912d6a6..d7bdf453b 100644 --- a/CPP/7zip/UI/FileManager/HelpUtils.h +++ b/CPP/7zip/UI/FileManager/HelpUtils.h @@ -1,10 +1,10 @@ -// HelpUtils.h - -#ifndef ZIP7_INC_HELP_UTILS_H -#define ZIP7_INC_HELP_UTILS_H - -#include "../../../Common/MyString.h" - -void ShowHelpWindow(LPCSTR topicFile); - -#endif +// HelpUtils.h + +#ifndef ZIP7_INC_HELP_UTILS_H +#define ZIP7_INC_HELP_UTILS_H + +#include "../../../Common/MyString.h" + +void ShowHelpWindow(LPCSTR topicFile); + +#endif diff --git a/CPP/7zip/UI/FileManager/IFolder.h b/CPP/7zip/UI/FileManager/IFolder.h index 9ef965b3d..1ebdf7e52 100644 --- a/CPP/7zip/UI/FileManager/IFolder.h +++ b/CPP/7zip/UI/FileManager/IFolder.h @@ -1,187 +1,187 @@ -// IFolder.h - -#ifndef ZIP7_INC_IFOLDER_H -#define ZIP7_INC_IFOLDER_H - -#include "../../IProgress.h" -#include "../../IStream.h" - -Z7_PURE_INTERFACES_BEGIN - -#define Z7_IFACE_CONSTR_FOLDER_SUB(i, base, n) \ - Z7_DECL_IFACE_7ZIP_SUB(i, base, 8, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -#define Z7_IFACE_CONSTR_FOLDER(i, n) \ - Z7_IFACE_CONSTR_FOLDER_SUB(i, IUnknown, n) - -namespace NPlugin -{ - enum - { - kName = 0, - kType, - kClassID, - kOptionsClassID - }; -} - -#define Z7_IFACEM_IFolderFolder(x) \ - x(LoadItems()) \ - x(GetNumberOfItems(UInt32 *numItems)) \ - x(GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) \ - x(BindToFolder(UInt32 index, IFolderFolder **resultFolder)) \ - x(BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) \ - x(BindToParentFolder(IFolderFolder **resultFolder)) \ - x(GetNumberOfProperties(UInt32 *numProperties)) \ - x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - x(GetFolderProperty(PROPID propID, PROPVARIANT *value)) \ - -Z7_IFACE_CONSTR_FOLDER(IFolderFolder, 0x00) - -/* - IFolderAltStreams:: - BindToAltStreams((UInt32)(Int32)-1, ... ) means alt streams of that folder -*/ - -#define Z7_IFACEM_IFolderAltStreams(x) \ - x(BindToAltStreams(UInt32 index, IFolderFolder **resultFolder)) \ - x(BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder)) \ - x(AreAltStreamsSupported(UInt32 index, Int32 *isSupported)) \ - -Z7_IFACE_CONSTR_FOLDER(IFolderAltStreams, 0x17) - -#define Z7_IFACEM_IFolderWasChanged(x) \ - x(WasChanged(Int32 *wasChanged)) -Z7_IFACE_CONSTR_FOLDER(IFolderWasChanged, 0x04) - - /* x(SetTotalFiles(UInt64 total)) */ \ - /* x(SetCompletedFiles(const UInt64 *completedValue)) */ \ -#define Z7_IFACEM_IFolderOperationsExtractCallback(x) \ - x(AskWrite( \ - const wchar_t *srcPath, \ - Int32 srcIsFolder, \ - const FILETIME *srcTime, \ - const UInt64 *srcSize, \ - const wchar_t *destPathRequest, \ - BSTR *destPathResult, \ - Int32 *writeAnswer)) \ - x(ShowMessage(const wchar_t *message)) \ - x(SetCurrentFilePath(const wchar_t *filePath)) \ - x(SetNumFiles(UInt64 numFiles)) \ - -Z7_IFACE_CONSTR_FOLDER_SUB(IFolderOperationsExtractCallback, IProgress, 0x0B) - - -#define Z7_IFACEM_IFolderOperations(x) \ - x(CreateFolder(const wchar_t *name, IProgress *progress)) \ - x(CreateFile(const wchar_t *name, IProgress *progress)) \ - x(Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) \ - x(Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress)) \ - x(CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, \ - Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, \ - const wchar_t *path, IFolderOperationsExtractCallback *callback)) \ - x(CopyFrom(Int32 moveMode, const wchar_t *fromFolderPath, \ - const wchar_t * const *itemsPaths, UInt32 numItems, IProgress *progress)) \ - x(SetProperty(UInt32 index, PROPID propID, const PROPVARIANT *value, IProgress *progress)) \ - x(CopyFromFile(UInt32 index, const wchar_t *fullFilePath, IProgress *progress)) \ - -Z7_IFACE_CONSTR_FOLDER(IFolderOperations, 0x13) - -/* -FOLDER_INTERFACE2(IFolderOperationsDeleteToRecycleBin, 0x06, 0x03) -{ - x(DeleteToRecycleBin(const UInt32 *indices, UInt32 numItems, IProgress *progress)) \ -}; -*/ - -#define Z7_IFACEM_IFolderGetSystemIconIndex(x) \ - x(GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) -Z7_IFACE_CONSTR_FOLDER(IFolderGetSystemIconIndex, 0x07) - -#define Z7_IFACEM_IFolderGetItemFullSize(x) \ - x(GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress)) -Z7_IFACE_CONSTR_FOLDER(IFolderGetItemFullSize, 0x08) - -#define Z7_IFACEM_IFolderCalcItemFullSize(x) \ - x(CalcItemFullSize(UInt32 index, IProgress *progress)) -Z7_IFACE_CONSTR_FOLDER(IFolderCalcItemFullSize, 0x14) - -#define Z7_IFACEM_IFolderClone(x) \ - x(Clone(IFolderFolder **resultFolder)) -Z7_IFACE_CONSTR_FOLDER(IFolderClone, 0x09) - -#define Z7_IFACEM_IFolderSetFlatMode(x) \ - x(SetFlatMode(Int32 flatMode)) -Z7_IFACE_CONSTR_FOLDER(IFolderSetFlatMode, 0x0A) - -/* -#define Z7_IFACEM_IFolderSetShowNtfsStreamsMode(x) \ - x(SetShowNtfsStreamsMode(Int32 showStreamsMode)) -Z7_IFACE_CONSTR_FOLDER(IFolderSetShowNtfsStreamsMode, 0xFA) -*/ - -#define Z7_IFACEM_IFolderProperties(x) \ - x(GetNumberOfFolderProperties(UInt32 *numProperties)) \ - x(GetFolderPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - -Z7_IFACE_CONSTR_FOLDER(IFolderProperties, 0x0E) - -#define Z7_IFACEM_IFolderArcProps(x) \ - x(GetArcNumLevels(UInt32 *numLevels)) \ - x(GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value)) \ - x(GetArcNumProps(UInt32 level, UInt32 *numProps)) \ - x(GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - x(GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value)) \ - x(GetArcNumProps2(UInt32 level, UInt32 *numProps)) \ - x(GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - -Z7_IFACE_CONSTR_FOLDER(IFolderArcProps, 0x10) - -#define Z7_IFACEM_IGetFolderArcProps(x) \ - x(GetFolderArcProps(IFolderArcProps **object)) -Z7_IFACE_CONSTR_FOLDER(IGetFolderArcProps, 0x11) - -#define Z7_IFACEM_IFolderCompare(x) \ - x##2(Int32, CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)) -Z7_IFACE_CONSTR_FOLDER(IFolderCompare, 0x15) - -#define Z7_IFACEM_IFolderGetItemName(x) \ - x(GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) \ - x(GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) \ - x##2(UInt64, GetItemSize(UInt32 index)) \ - -Z7_IFACE_CONSTR_FOLDER(IFolderGetItemName, 0x16) - - -#define Z7_IFACEM_IFolderManager(x) \ - x(OpenFolderFile(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, IFolderFolder **resultFolder, IProgress *progress)) \ - x(GetExtensions(BSTR *extensions)) \ - x(GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex)) \ - - // x(GetTypes(BSTR *types)) - // x(CreateFolderFile(const wchar_t *type, const wchar_t *filePath, IProgress *progress)) - -Z7_DECL_IFACE_7ZIP(IFolderManager, 9, 5) - { Z7_IFACE_COM7_PURE(IFolderManager) }; - -/* - const CMy_STATPROPSTG_2 &srcItem = k[index]; \ - *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \ -*/ -#define IMP_IFolderFolder_GetProp(fn, k) \ - Z7_COM7F_IMF(fn(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ - { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \ - *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = NULL; return S_OK; } \ - -#define IMP_IFolderFolder_Props(c) \ - Z7_COM7F_IMF(c::GetNumberOfProperties(UInt32 *numProperties)) \ - { *numProperties = Z7_ARRAY_SIZE(kProps); return S_OK; } \ - IMP_IFolderFolder_GetProp(c::GetPropertyInfo, kProps) - - -int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2); -// int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); - -Z7_PURE_INTERFACES_END -#endif +// IFolder.h + +#ifndef ZIP7_INC_IFOLDER_H +#define ZIP7_INC_IFOLDER_H + +#include "../../IProgress.h" +#include "../../IStream.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_FOLDER_SUB(i, base, n) \ + Z7_DECL_IFACE_7ZIP_SUB(i, base, 8, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACE_CONSTR_FOLDER(i, n) \ + Z7_IFACE_CONSTR_FOLDER_SUB(i, IUnknown, n) + +namespace NPlugin +{ + enum + { + kName = 0, + kType, + kClassID, + kOptionsClassID + }; +} + +#define Z7_IFACEM_IFolderFolder(x) \ + x(LoadItems()) \ + x(GetNumberOfItems(UInt32 *numItems)) \ + x(GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) \ + x(BindToFolder(UInt32 index, IFolderFolder **resultFolder)) \ + x(BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) \ + x(BindToParentFolder(IFolderFolder **resultFolder)) \ + x(GetNumberOfProperties(UInt32 *numProperties)) \ + x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(GetFolderProperty(PROPID propID, PROPVARIANT *value)) \ + +Z7_IFACE_CONSTR_FOLDER(IFolderFolder, 0x00) + +/* + IFolderAltStreams:: + BindToAltStreams((UInt32)(Int32)-1, ... ) means alt streams of that folder +*/ + +#define Z7_IFACEM_IFolderAltStreams(x) \ + x(BindToAltStreams(UInt32 index, IFolderFolder **resultFolder)) \ + x(BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder)) \ + x(AreAltStreamsSupported(UInt32 index, Int32 *isSupported)) \ + +Z7_IFACE_CONSTR_FOLDER(IFolderAltStreams, 0x17) + +#define Z7_IFACEM_IFolderWasChanged(x) \ + x(WasChanged(Int32 *wasChanged)) +Z7_IFACE_CONSTR_FOLDER(IFolderWasChanged, 0x04) + + /* x(SetTotalFiles(UInt64 total)) */ \ + /* x(SetCompletedFiles(const UInt64 *completedValue)) */ \ +#define Z7_IFACEM_IFolderOperationsExtractCallback(x) \ + x(AskWrite( \ + const wchar_t *srcPath, \ + Int32 srcIsFolder, \ + const FILETIME *srcTime, \ + const UInt64 *srcSize, \ + const wchar_t *destPathRequest, \ + BSTR *destPathResult, \ + Int32 *writeAnswer)) \ + x(ShowMessage(const wchar_t *message)) \ + x(SetCurrentFilePath(const wchar_t *filePath)) \ + x(SetNumFiles(UInt64 numFiles)) \ + +Z7_IFACE_CONSTR_FOLDER_SUB(IFolderOperationsExtractCallback, IProgress, 0x0B) + + +#define Z7_IFACEM_IFolderOperations(x) \ + x(CreateFolder(const wchar_t *name, IProgress *progress)) \ + x(CreateFile(const wchar_t *name, IProgress *progress)) \ + x(Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) \ + x(Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress)) \ + x(CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, \ + Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, \ + const wchar_t *path, IFolderOperationsExtractCallback *callback)) \ + x(CopyFrom(Int32 moveMode, const wchar_t *fromFolderPath, \ + const wchar_t * const *itemsPaths, UInt32 numItems, IProgress *progress)) \ + x(SetProperty(UInt32 index, PROPID propID, const PROPVARIANT *value, IProgress *progress)) \ + x(CopyFromFile(UInt32 index, const wchar_t *fullFilePath, IProgress *progress)) \ + +Z7_IFACE_CONSTR_FOLDER(IFolderOperations, 0x13) + +/* +FOLDER_INTERFACE2(IFolderOperationsDeleteToRecycleBin, 0x06, 0x03) +{ + x(DeleteToRecycleBin(const UInt32 *indices, UInt32 numItems, IProgress *progress)) \ +}; +*/ + +#define Z7_IFACEM_IFolderGetSystemIconIndex(x) \ + x(GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) +Z7_IFACE_CONSTR_FOLDER(IFolderGetSystemIconIndex, 0x07) + +#define Z7_IFACEM_IFolderGetItemFullSize(x) \ + x(GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress)) +Z7_IFACE_CONSTR_FOLDER(IFolderGetItemFullSize, 0x08) + +#define Z7_IFACEM_IFolderCalcItemFullSize(x) \ + x(CalcItemFullSize(UInt32 index, IProgress *progress)) +Z7_IFACE_CONSTR_FOLDER(IFolderCalcItemFullSize, 0x14) + +#define Z7_IFACEM_IFolderClone(x) \ + x(Clone(IFolderFolder **resultFolder)) +Z7_IFACE_CONSTR_FOLDER(IFolderClone, 0x09) + +#define Z7_IFACEM_IFolderSetFlatMode(x) \ + x(SetFlatMode(Int32 flatMode)) +Z7_IFACE_CONSTR_FOLDER(IFolderSetFlatMode, 0x0A) + +/* +#define Z7_IFACEM_IFolderSetShowNtfsStreamsMode(x) \ + x(SetShowNtfsStreamsMode(Int32 showStreamsMode)) +Z7_IFACE_CONSTR_FOLDER(IFolderSetShowNtfsStreamsMode, 0xFA) +*/ + +#define Z7_IFACEM_IFolderProperties(x) \ + x(GetNumberOfFolderProperties(UInt32 *numProperties)) \ + x(GetFolderPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + +Z7_IFACE_CONSTR_FOLDER(IFolderProperties, 0x0E) + +#define Z7_IFACEM_IFolderArcProps(x) \ + x(GetArcNumLevels(UInt32 *numLevels)) \ + x(GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value)) \ + x(GetArcNumProps(UInt32 level, UInt32 *numProps)) \ + x(GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value)) \ + x(GetArcNumProps2(UInt32 level, UInt32 *numProps)) \ + x(GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + +Z7_IFACE_CONSTR_FOLDER(IFolderArcProps, 0x10) + +#define Z7_IFACEM_IGetFolderArcProps(x) \ + x(GetFolderArcProps(IFolderArcProps **object)) +Z7_IFACE_CONSTR_FOLDER(IGetFolderArcProps, 0x11) + +#define Z7_IFACEM_IFolderCompare(x) \ + x##2(Int32, CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)) +Z7_IFACE_CONSTR_FOLDER(IFolderCompare, 0x15) + +#define Z7_IFACEM_IFolderGetItemName(x) \ + x(GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) \ + x(GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) \ + x##2(UInt64, GetItemSize(UInt32 index)) \ + +Z7_IFACE_CONSTR_FOLDER(IFolderGetItemName, 0x16) + + +#define Z7_IFACEM_IFolderManager(x) \ + x(OpenFolderFile(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, IFolderFolder **resultFolder, IProgress *progress)) \ + x(GetExtensions(BSTR *extensions)) \ + x(GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex)) \ + + // x(GetTypes(BSTR *types)) + // x(CreateFolderFile(const wchar_t *type, const wchar_t *filePath, IProgress *progress)) + +Z7_DECL_IFACE_7ZIP(IFolderManager, 9, 5) + { Z7_IFACE_COM7_PURE(IFolderManager) }; + +/* + const CMy_STATPROPSTG_2 &srcItem = k[index]; \ + *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \ +*/ +#define IMP_IFolderFolder_GetProp(fn, k) \ + Z7_COM7F_IMF(fn(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \ + *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = NULL; return S_OK; } \ + +#define IMP_IFolderFolder_Props(c) \ + Z7_COM7F_IMF(c::GetNumberOfProperties(UInt32 *numProperties)) \ + { *numProperties = Z7_ARRAY_SIZE(kProps); return S_OK; } \ + IMP_IFolderFolder_GetProp(c::GetPropertyInfo, kProps) + + +int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2); +// int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2); + +Z7_PURE_INTERFACES_END +#endif diff --git a/CPP/7zip/UI/FileManager/LangPage.cpp b/CPP/7zip/UI/FileManager/LangPage.cpp index 816f21199..3aeaf13c3 100644 --- a/CPP/7zip/UI/FileManager/LangPage.cpp +++ b/CPP/7zip/UI/FileManager/LangPage.cpp @@ -1,361 +1,361 @@ -// LangPage.cpp - -#include "StdAfx.h" - -#include "../../../Common/Lang.h" - -#include "../../../Windows/FileFind.h" -#include "../../../Windows/ResourceString.h" - -#include "HelpUtils.h" -#include "LangPage.h" -#include "LangPageRes.h" -#include "LangUtils.h" -#include "RegistryUtils.h" - -using namespace NWindows; - - -static const unsigned k_NumLangLines_EN = 443; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_LANG_LANG -}; -#endif - -#define kLangTopic "fm/options.htm#language" - - -struct CLangListRecord -{ - int Order; - unsigned LangInfoIndex; - bool IsSelected; - UString Mark; - UString Name; - - CLangListRecord(): Order (10), IsSelected(false) {} - int Compare(const CLangListRecord &a) const - { - if (Order < a.Order) return -1; - if (Order > a.Order) return 1; - return MyStringCompareNoCase(Name, a.Name); - } -}; - - -static void NativeLangString(UString &dest, const wchar_t *s) -{ - dest += " ("; - dest += s; - dest.Add_Char(')'); -} - -bool LangOpen(CLang &lang, CFSTR fileName); - -bool CLangPage::OnInit() -{ -#ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); -#endif - _langCombo.Attach(GetItem(IDC_LANG_LANG)); - - - unsigned listRecords_SelectedIndex = 0; - - CObjectVector listRecords; - { - CLangListRecord listRecord; - listRecord.Order = 0; - listRecord.Mark = "---"; - listRecord.Name = MyLoadString(IDS_LANG_ENGLISH); - NativeLangString(listRecord.Name, MyLoadString(IDS_LANG_NATIVE)); - listRecord.LangInfoIndex = _langs.Size(); - listRecords.Add(listRecord); - } - - AStringVector names; - unsigned subLangIndex = 0; - Lang_GetShortNames_for_DefaultLang(names, subLangIndex); - - const FString dirPrefix = GetLangDirPrefix(); - NFile::NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(dirPrefix); - NFile::NFind::CFileInfo fi; - - CLang lang_en; - { - CLangInfo &langInfo = _langs.AddNew(); - langInfo.Name = "-"; - if (LangOpen(lang_en, dirPrefix + FTEXT("en.ttt"))) - { - langInfo.NumLines = lang_en._ids.Size(); - // langInfo.Comments = lang_en.Comments; - } - else - langInfo.NumLines = k_NumLangLines_EN; - NumLangLines_EN = langInfo.NumLines; - } - - CLang lang; - UString error; - UString n; - - while (enumerator.Next(fi)) - { - if (fi.IsDir()) - continue; - const unsigned kExtSize = 4; - if (fi.Name.Len() < kExtSize) - continue; - const unsigned pos = fi.Name.Len() - kExtSize; - if (!StringsAreEqualNoCase_Ascii(fi.Name.Ptr(pos), ".txt")) - { - // if (!StringsAreEqualNoCase_Ascii(fi.Name.Ptr(pos), ".ttt")) - continue; - } - - if (!LangOpen(lang, dirPrefix + fi.Name)) - { - error.Add_Space_if_NotEmpty(); - error += fs2us(fi.Name); - continue; - } - - const UString shortName = fs2us(fi.Name.Left(pos)); - - CLangListRecord listRecord; - if (!names.IsEmpty()) - { - for (unsigned i = 0; i < names.Size(); i++) - if (shortName.IsEqualTo_Ascii_NoCase(names[i])) - { - if (subLangIndex == i || names.Size() == 1) - { - listRecord.Mark = "***"; - // listRecord.Order = 1; - } - else - { - listRecord.Mark = "+++"; - // listRecord.Order = 2; - } - break; - } - if (listRecord.Mark.IsEmpty()) - { - const int minusPos = shortName.Find(L'-'); - if (minusPos >= 0) - { - const UString shortName2 = shortName.Left(minusPos); - if (shortName2.IsEqualTo_Ascii_NoCase(names[0])) - { - listRecord.Mark = "+++"; - // listRecord.Order = 3; - } - } - } - } - UString s = shortName; - const wchar_t *eng = lang.Get(IDS_LANG_ENGLISH); - if (eng) - s = eng; - const wchar_t *native = lang.Get(IDS_LANG_NATIVE); - if (native) - NativeLangString(s, native); - - listRecord.Name = s; - listRecord.LangInfoIndex = _langs.Size(); - listRecords.Add(listRecord); - if (g_LangID.IsEqualTo_NoCase(shortName)) - listRecords_SelectedIndex = listRecords.Size() - 1; - - CLangInfo &langInfo = _langs.AddNew(); - langInfo.Comments = lang.Comments; - langInfo.Name = shortName; - unsigned numLines = lang._ids.Size(); - if (!lang_en.IsEmpty()) - { - numLines = 0; - unsigned i1 = 0; - unsigned i2 = 0; - for (;;) - { - UInt32 id1 = (UInt32)0 - 1; - UInt32 id2 = (UInt32)0 - 1; - bool id1_defined = false; - bool id2_defined = false; - if (i1 < lang_en._ids.Size()) - { - id1 = lang_en._ids[i1]; - id1_defined = true; - } - if (i2 < lang._ids.Size()) - { - id2 = lang._ids[i2]; - id2_defined = true; - } - - bool id1_is_smaller = true; - if (id1_defined) - { - if (id2_defined) - { - if (id1 == id2) - { - i1++; - i2++; - numLines++; - continue; - } - if (id1 > id2) - id1_is_smaller = false; - } - } - else if (!id2_defined) - break; - else - id1_is_smaller = false; - - n.Empty(); - if (id1_is_smaller) - { - n.Add_UInt32(id1); - n += " : "; - n += lang_en.Get_by_index(i1); - langInfo.MissingLines.Add(n); - i1++; - } - else - { - n.Add_UInt32(id2); - n += " : "; - n += lang.Get_by_index(i2); - langInfo.ExtraLines.Add(n); - i2++; - } - } - } - langInfo.NumLines = numLines + langInfo.ExtraLines.Size(); - } - - listRecords[listRecords_SelectedIndex].IsSelected = true; - - listRecords.Sort(); - FOR_VECTOR (i, listRecords) - { - const CLangListRecord &rec= listRecords[i]; - UString temp = rec.Name; - if (!rec.Mark.IsEmpty()) - { - temp += " "; - temp += rec.Mark; - } - const int index = (int)_langCombo.AddString(temp); - _langCombo.SetItemData(index, (LPARAM)rec.LangInfoIndex); - if (rec.IsSelected) - _langCombo.SetCurSel(index); - } - - ShowLangInfo(); - - if (!error.IsEmpty()) - MessageBoxW(NULL, error, L"Error in Lang file", MB_ICONERROR); - return CPropertyPage::OnInit(); -} - -LONG CLangPage::OnApply() -{ - if (_needSave) - { - const int pathIndex = (int)_langCombo.GetItemData_of_CurSel(); - if ((unsigned)pathIndex < _langs.Size()) - SaveRegLang(_langs[pathIndex].Name); - } - _needSave = false; - #ifdef Z7_LANG - ReloadLang(); - #endif - LangWasChanged = true; - return PSNRET_NOERROR; -} - -void CLangPage::OnNotifyHelp() -{ - ShowHelpWindow(kLangTopic); -} - -bool CLangPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) -{ - if (code == CBN_SELCHANGE && itemID == IDC_LANG_LANG) - { - _needSave = true; - Changed(); - ShowLangInfo(); - return true; - } - return CPropertyPage::OnCommand(code, itemID, param); -} - -static void AddVectorToString(UString &s, const UStringVector &v) -{ - UString a; - FOR_VECTOR (i, v) - { - if (i >= 50) - break; - a = v[i]; - if (a.Len() > 1500) - continue; - if (a[0] == ';') - { - a.DeleteFrontal(1); - a.Trim(); - } - s += a; - s.Add_LF(); - } -} - -static void AddVectorToString2(UString &s, const char *name, const UStringVector &v) -{ - if (v.IsEmpty()) - return; - s.Add_LF(); - s += "------ "; - s += name; - s += ": "; - s.Add_UInt32(v.Size()); - s += " :"; - s.Add_LF(); - AddVectorToString(s, v); -} - -void CLangPage::ShowLangInfo() -{ - UString s; - const int pathIndex = (int)_langCombo.GetItemData_of_CurSel(); - if ((unsigned)pathIndex < _langs.Size()) - { - const CLangInfo &langInfo = _langs[pathIndex]; - const unsigned numLines = langInfo.NumLines; - s += langInfo.Name; - s += " : "; - s.Add_UInt32(numLines); - if (NumLangLines_EN != 0) - { - s += " / "; - s.Add_UInt32(NumLangLines_EN); - s += " = "; - s.Add_UInt32(numLines * 100 / NumLangLines_EN); - s += "%"; - } - s.Add_LF(); - AddVectorToString(s, langInfo.Comments); - AddVectorToString2(s, "Missing lines", langInfo.MissingLines); - AddVectorToString2(s, "Extra lines", langInfo.ExtraLines); - } - SetItemText(IDT_LANG_INFO, s); -} +// LangPage.cpp + +#include "StdAfx.h" + +#include "../../../Common/Lang.h" + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/ResourceString.h" + +#include "HelpUtils.h" +#include "LangPage.h" +#include "LangPageRes.h" +#include "LangUtils.h" +#include "RegistryUtils.h" + +using namespace NWindows; + + +static const unsigned k_NumLangLines_EN = 443; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_LANG_LANG +}; +#endif + +#define kLangTopic "fm/options.htm#language" + + +struct CLangListRecord +{ + int Order; + unsigned LangInfoIndex; + bool IsSelected; + UString Mark; + UString Name; + + CLangListRecord(): Order (10), IsSelected(false) {} + int Compare(const CLangListRecord &a) const + { + if (Order < a.Order) return -1; + if (Order > a.Order) return 1; + return MyStringCompareNoCase(Name, a.Name); + } +}; + + +static void NativeLangString(UString &dest, const wchar_t *s) +{ + dest += " ("; + dest += s; + dest.Add_Char(')'); +} + +bool LangOpen(CLang &lang, CFSTR fileName); + +bool CLangPage::OnInit() +{ +#ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); +#endif + _langCombo.Attach(GetItem(IDC_LANG_LANG)); + + + unsigned listRecords_SelectedIndex = 0; + + CObjectVector listRecords; + { + CLangListRecord listRecord; + listRecord.Order = 0; + listRecord.Mark = "---"; + listRecord.Name = MyLoadString(IDS_LANG_ENGLISH); + NativeLangString(listRecord.Name, MyLoadString(IDS_LANG_NATIVE)); + listRecord.LangInfoIndex = _langs.Size(); + listRecords.Add(listRecord); + } + + AStringVector names; + unsigned subLangIndex = 0; + Lang_GetShortNames_for_DefaultLang(names, subLangIndex); + + const FString dirPrefix = GetLangDirPrefix(); + NFile::NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(dirPrefix); + NFile::NFind::CFileInfo fi; + + CLang lang_en; + { + CLangInfo &langInfo = _langs.AddNew(); + langInfo.Name = "-"; + if (LangOpen(lang_en, dirPrefix + FTEXT("en.ttt"))) + { + langInfo.NumLines = lang_en._ids.Size(); + // langInfo.Comments = lang_en.Comments; + } + else + langInfo.NumLines = k_NumLangLines_EN; + NumLangLines_EN = langInfo.NumLines; + } + + CLang lang; + UString error; + UString n; + + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + continue; + const unsigned kExtSize = 4; + if (fi.Name.Len() < kExtSize) + continue; + const unsigned pos = fi.Name.Len() - kExtSize; + if (!StringsAreEqualNoCase_Ascii(fi.Name.Ptr(pos), ".txt")) + { + // if (!StringsAreEqualNoCase_Ascii(fi.Name.Ptr(pos), ".ttt")) + continue; + } + + if (!LangOpen(lang, dirPrefix + fi.Name)) + { + error.Add_Space_if_NotEmpty(); + error += fs2us(fi.Name); + continue; + } + + const UString shortName = fs2us(fi.Name.Left(pos)); + + CLangListRecord listRecord; + if (!names.IsEmpty()) + { + for (unsigned i = 0; i < names.Size(); i++) + if (shortName.IsEqualTo_Ascii_NoCase(names[i])) + { + if (subLangIndex == i || names.Size() == 1) + { + listRecord.Mark = "***"; + // listRecord.Order = 1; + } + else + { + listRecord.Mark = "+++"; + // listRecord.Order = 2; + } + break; + } + if (listRecord.Mark.IsEmpty()) + { + const int minusPos = shortName.Find(L'-'); + if (minusPos >= 0) + { + const UString shortName2 = shortName.Left(minusPos); + if (shortName2.IsEqualTo_Ascii_NoCase(names[0])) + { + listRecord.Mark = "+++"; + // listRecord.Order = 3; + } + } + } + } + UString s = shortName; + const wchar_t *eng = lang.Get(IDS_LANG_ENGLISH); + if (eng) + s = eng; + const wchar_t *native = lang.Get(IDS_LANG_NATIVE); + if (native) + NativeLangString(s, native); + + listRecord.Name = s; + listRecord.LangInfoIndex = _langs.Size(); + listRecords.Add(listRecord); + if (g_LangID.IsEqualTo_NoCase(shortName)) + listRecords_SelectedIndex = listRecords.Size() - 1; + + CLangInfo &langInfo = _langs.AddNew(); + langInfo.Comments = lang.Comments; + langInfo.Name = shortName; + unsigned numLines = lang._ids.Size(); + if (!lang_en.IsEmpty()) + { + numLines = 0; + unsigned i1 = 0; + unsigned i2 = 0; + for (;;) + { + UInt32 id1 = (UInt32)0 - 1; + UInt32 id2 = (UInt32)0 - 1; + bool id1_defined = false; + bool id2_defined = false; + if (i1 < lang_en._ids.Size()) + { + id1 = lang_en._ids[i1]; + id1_defined = true; + } + if (i2 < lang._ids.Size()) + { + id2 = lang._ids[i2]; + id2_defined = true; + } + + bool id1_is_smaller = true; + if (id1_defined) + { + if (id2_defined) + { + if (id1 == id2) + { + i1++; + i2++; + numLines++; + continue; + } + if (id1 > id2) + id1_is_smaller = false; + } + } + else if (!id2_defined) + break; + else + id1_is_smaller = false; + + n.Empty(); + if (id1_is_smaller) + { + n.Add_UInt32(id1); + n += " : "; + n += lang_en.Get_by_index(i1); + langInfo.MissingLines.Add(n); + i1++; + } + else + { + n.Add_UInt32(id2); + n += " : "; + n += lang.Get_by_index(i2); + langInfo.ExtraLines.Add(n); + i2++; + } + } + } + langInfo.NumLines = numLines + langInfo.ExtraLines.Size(); + } + + listRecords[listRecords_SelectedIndex].IsSelected = true; + + listRecords.Sort(); + FOR_VECTOR (i, listRecords) + { + const CLangListRecord &rec= listRecords[i]; + UString temp = rec.Name; + if (!rec.Mark.IsEmpty()) + { + temp += " "; + temp += rec.Mark; + } + const int index = (int)_langCombo.AddString(temp); + _langCombo.SetItemData(index, (LPARAM)rec.LangInfoIndex); + if (rec.IsSelected) + _langCombo.SetCurSel(index); + } + + ShowLangInfo(); + + if (!error.IsEmpty()) + MessageBoxW(NULL, error, L"Error in Lang file", MB_ICONERROR); + return CPropertyPage::OnInit(); +} + +LONG CLangPage::OnApply() +{ + if (_needSave) + { + const int pathIndex = (int)_langCombo.GetItemData_of_CurSel(); + if ((unsigned)pathIndex < _langs.Size()) + SaveRegLang(_langs[pathIndex].Name); + } + _needSave = false; + #ifdef Z7_LANG + ReloadLang(); + #endif + LangWasChanged = true; + return PSNRET_NOERROR; +} + +void CLangPage::OnNotifyHelp() +{ + ShowHelpWindow(kLangTopic); +} + +bool CLangPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) +{ + if (code == CBN_SELCHANGE && itemID == IDC_LANG_LANG) + { + _needSave = true; + Changed(); + ShowLangInfo(); + return true; + } + return CPropertyPage::OnCommand(code, itemID, param); +} + +static void AddVectorToString(UString &s, const UStringVector &v) +{ + UString a; + FOR_VECTOR (i, v) + { + if (i >= 50) + break; + a = v[i]; + if (a.Len() > 1500) + continue; + if (a[0] == ';') + { + a.DeleteFrontal(1); + a.Trim(); + } + s += a; + s.Add_LF(); + } +} + +static void AddVectorToString2(UString &s, const char *name, const UStringVector &v) +{ + if (v.IsEmpty()) + return; + s.Add_LF(); + s += "------ "; + s += name; + s += ": "; + s.Add_UInt32(v.Size()); + s += " :"; + s.Add_LF(); + AddVectorToString(s, v); +} + +void CLangPage::ShowLangInfo() +{ + UString s; + const int pathIndex = (int)_langCombo.GetItemData_of_CurSel(); + if ((unsigned)pathIndex < _langs.Size()) + { + const CLangInfo &langInfo = _langs[pathIndex]; + const unsigned numLines = langInfo.NumLines; + s += langInfo.Name; + s += " : "; + s.Add_UInt32(numLines); + if (NumLangLines_EN != 0) + { + s += " / "; + s.Add_UInt32(NumLangLines_EN); + s += " = "; + s.Add_UInt32(numLines * 100 / NumLangLines_EN); + s += "%"; + } + s.Add_LF(); + AddVectorToString(s, langInfo.Comments); + AddVectorToString2(s, "Missing lines", langInfo.MissingLines); + AddVectorToString2(s, "Extra lines", langInfo.ExtraLines); + } + SetItemText(IDT_LANG_INFO, s); +} diff --git a/CPP/7zip/UI/FileManager/LangPage.h b/CPP/7zip/UI/FileManager/LangPage.h index 617fec67b..e37ba0586 100644 --- a/CPP/7zip/UI/FileManager/LangPage.h +++ b/CPP/7zip/UI/FileManager/LangPage.h @@ -1,36 +1,36 @@ -// LangPage.h - -#ifndef ZIP7_INC_LANG_PAGE_H -#define ZIP7_INC_LANG_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/ComboBox.h" - -struct CLangInfo -{ - unsigned NumLines; - UString Name; - UStringVector Comments; - UStringVector MissingLines; - UStringVector ExtraLines; -}; - -class CLangPage: public NWindows::NControl::CPropertyPage -{ - NWindows::NControl::CComboBox _langCombo; - CObjectVector _langs; - unsigned NumLangLines_EN; - bool _needSave; - - void ShowLangInfo(); -public: - bool LangWasChanged; - - CLangPage(): _needSave(false), LangWasChanged(false) {} - virtual bool OnInit() Z7_override; - virtual void OnNotifyHelp() Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; - virtual LONG OnApply() Z7_override; -}; - -#endif +// LangPage.h + +#ifndef ZIP7_INC_LANG_PAGE_H +#define ZIP7_INC_LANG_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/ComboBox.h" + +struct CLangInfo +{ + unsigned NumLines; + UString Name; + UStringVector Comments; + UStringVector MissingLines; + UStringVector ExtraLines; +}; + +class CLangPage: public NWindows::NControl::CPropertyPage +{ + NWindows::NControl::CComboBox _langCombo; + CObjectVector _langs; + unsigned NumLangLines_EN; + bool _needSave; + + void ShowLangInfo(); +public: + bool LangWasChanged; + + CLangPage(): _needSave(false), LangWasChanged(false) {} + virtual bool OnInit() Z7_override; + virtual void OnNotifyHelp() Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; + virtual LONG OnApply() Z7_override; +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/LangPage.rc b/CPP/7zip/UI/FileManager/LangPage.rc index d6b43b27b..60d730f5e 100644 --- a/CPP/7zip/UI/FileManager/LangPage.rc +++ b/CPP/7zip/UI/FileManager/LangPage.rc @@ -1,40 +1,40 @@ -#include "LangPageRes.h" -#include "../../GuiCommon.rc" - -#define xc OPTIONS_PAGE_XC_SIZE -#define yc OPTIONS_PAGE_YC_SIZE - -#define y 32 - -IDD_LANG DIALOG MY_PAGE_POSTFIX -CAPTION "Language" -{ - LTEXT "Language:", IDT_LANG_LANG, m, m, xc, 8 - COMBOBOX IDC_LANG_LANG, m, 20, 160, yc - 20, MY_COMBO // MY_COMBO_SORTED - LTEXT "", IDT_LANG_INFO, m, m + y, xc, yc - y, SS_NOPREFIX -} - - -#ifdef UNDER_CE - -#undef m -#undef xc - -#define m 4 -#define xc (SMALL_PAGE_SIZE_X + 8) - -IDD_LANG_2 MY_PAGE -CAPTION "Language" -{ - LTEXT "Language:", IDT_LANG_LANG, m, m, xc, 8 - COMBOBOX IDC_LANG_LANG, m, 20, xc, yc - 20, MY_COMBO // MY_COMBO_SORTED -} - -#endif - - -STRINGTABLE -BEGIN - IDS_LANG_ENGLISH "English" - IDS_LANG_NATIVE "English" -END +#include "LangPageRes.h" +#include "../../GuiCommon.rc" + +#define xc OPTIONS_PAGE_XC_SIZE +#define yc OPTIONS_PAGE_YC_SIZE + +#define y 32 + +IDD_LANG DIALOG MY_PAGE_POSTFIX +CAPTION "Language" +{ + LTEXT "Language:", IDT_LANG_LANG, m, m, xc, 8 + COMBOBOX IDC_LANG_LANG, m, 20, 160, yc - 20, MY_COMBO // MY_COMBO_SORTED + LTEXT "", IDT_LANG_INFO, m, m + y, xc, yc - y, SS_NOPREFIX +} + + +#ifdef UNDER_CE + +#undef m +#undef xc + +#define m 4 +#define xc (SMALL_PAGE_SIZE_X + 8) + +IDD_LANG_2 MY_PAGE +CAPTION "Language" +{ + LTEXT "Language:", IDT_LANG_LANG, m, m, xc, 8 + COMBOBOX IDC_LANG_LANG, m, 20, xc, yc - 20, MY_COMBO // MY_COMBO_SORTED +} + +#endif + + +STRINGTABLE +BEGIN + IDS_LANG_ENGLISH "English" + IDS_LANG_NATIVE "English" +END diff --git a/CPP/7zip/UI/FileManager/LangPageRes.h b/CPP/7zip/UI/FileManager/LangPageRes.h index 2c07801d3..a1ad30faf 100644 --- a/CPP/7zip/UI/FileManager/LangPageRes.h +++ b/CPP/7zip/UI/FileManager/LangPageRes.h @@ -1,9 +1,9 @@ -#define IDD_LANG 2101 -#define IDD_LANG_2 12101 - -#define IDS_LANG_ENGLISH 1 -#define IDS_LANG_NATIVE 2 - -#define IDT_LANG_LANG 2102 -#define IDC_LANG_LANG 100 -#define IDT_LANG_INFO 101 +#define IDD_LANG 2101 +#define IDD_LANG_2 12101 + +#define IDS_LANG_ENGLISH 1 +#define IDS_LANG_NATIVE 2 + +#define IDT_LANG_LANG 2102 +#define IDC_LANG_LANG 100 +#define IDT_LANG_INFO 101 diff --git a/CPP/7zip/UI/FileManager/LangUtils.cpp b/CPP/7zip/UI/FileManager/LangUtils.cpp index 92937997e..8fcb50756 100644 --- a/CPP/7zip/UI/FileManager/LangUtils.cpp +++ b/CPP/7zip/UI/FileManager/LangUtils.cpp @@ -1,335 +1,335 @@ -// LangUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/Lang.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/Synchronization.h" -#include "../../../Windows/Window.h" - -#include "LangUtils.h" -#include "RegistryUtils.h" - -using namespace NWindows; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -UString g_LangID; - -// static -CLang g_Lang; -static bool g_Loaded = false; -static NSynchronization::CCriticalSection g_CriticalSection; - -bool LangOpen(CLang &lang, CFSTR fileName); -bool LangOpen(CLang &lang, CFSTR fileName) -{ - return lang.Open(fileName, "7-Zip"); -} - -FString GetLangDirPrefix() -{ - return NDLL::GetModuleDirPrefix() + FTEXT("Lang") FSTRING_PATH_SEPARATOR; -} - -#ifdef Z7_LANG - -void LoadLangOneTime() -{ - NSynchronization::CCriticalSectionLock lock(g_CriticalSection); - if (g_Loaded) - return; - g_Loaded = true; - ReloadLang(); -} - -void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID) -{ - const wchar_t *s = g_Lang.Get(langID); - if (s) - { - CWindow window(GetDlgItem(dialog, (int)controlID)); - window.SetText(s); - } -} - -#ifndef IDCONTINUE -#define IDCONTINUE 11 -#endif - -static const CIDLangPair kLangPairs[] = -{ - { IDOK, 401 }, - { IDCANCEL, 402 }, - { IDYES, 406 }, - { IDNO, 407 }, - { IDCLOSE, 408 }, - { IDHELP, 409 }, - { IDCONTINUE, 411 } -}; - - -void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems) -{ - unsigned i; - for (i = 0; i < Z7_ARRAY_SIZE(kLangPairs); i++) - { - const CIDLangPair &pair = kLangPairs[i]; - CWindow window(GetDlgItem(dialog, (int)pair.ControlID)); - if (window) - { - const wchar_t *s = g_Lang.Get(pair.LangID); - if (s) - window.SetText(s); - } - } - - for (i = 0; i < numItems; i++) - { - const UInt32 id = ids[i]; - LangSetDlgItemText(dialog, id, id); - } -} - -void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems) -{ - for (unsigned i = 0; i < numItems; i++) - { - const UInt32 id = ids[i]; - const wchar_t *s = g_Lang.Get(id); - if (s) - { - CWindow window(GetDlgItem(dialog, (int)id)); - UString s2 = s; - s2.Add_Colon(); - window.SetText(s2); - } - } -} - -void LangSetDlgItems_RemoveColon(HWND dialog, const UInt32 *ids, unsigned numItems) -{ - for (unsigned i = 0; i < numItems; i++) - { - const UInt32 id = ids[i]; - const wchar_t *s = g_Lang.Get(id); - if (s) - { - CWindow window(GetDlgItem(dialog, (int)id)); - UString s2 = s; - if (!s2.IsEmpty() && s2.Back() == ':') - s2.DeleteBack(); - window.SetText(s2); - } - } -} - -void LangSetWindowText(HWND window, UInt32 langID) -{ - const wchar_t *s = g_Lang.Get(langID); - if (s) - MySetWindowText(window, s); -} - -UString LangString(UInt32 langID) -{ - const wchar_t *s = g_Lang.Get(langID); - if (s) - return s; - return MyLoadString(langID); -} - -void AddLangString(UString &s, UInt32 langID) -{ - s += LangString(langID); -} - -void LangString(UInt32 langID, UString &dest) -{ - const wchar_t *s = g_Lang.Get(langID); - if (s) - { - dest = s; - return; - } - MyLoadString(langID, dest); -} - -void LangString_OnlyFromLangFile(UInt32 langID, UString &dest) -{ - dest.Empty(); - const wchar_t *s = g_Lang.Get(langID); - if (s) - dest = s; -} - -static const char * const kLangs = - "ar.bg.ca.zh.-tw.-cn.cs.da.de.el.en.es.fi.fr.he.hu.is." - "it.ja.ko.nl.no.=nb.=nn.pl.pt.-br.rm.ro.ru.sr.=hr.-spl.-spc.=hr.=bs.sk.sq.sv.th.tr." - "ur.id.uk.be.sl.et.lv.lt.tg.fa.vi.hy.az.eu.hsb.mk." - "st.ts.tn.ve.xh.zu.af.ka.fo.hi.mt.se.ga.yi.ms.kk." - "ky.sw.tk.uz.-latn.-cyrl.tt.bn.pa.-in.gu.or.ta.te.kn.ml.as.mr.sa." - "mn.=mn.=mng.bo.cy.kh.lo.my.gl.kok..sd.syr.si..iu.am.tzm." - "ks.ne.fy.ps.tl.dv..ff.ha..yo.qu.st.ba.lb.kl." - "ig.kr.om.ti.gn..la.so.ii..arn..moh..br.." - "ug.mi.oc.co." - // "gsw.sah.qut.rw.wo....prs...." - // ".gd." - ; - -static void FindShortNames(UInt32 primeLang, AStringVector &names) -{ - UInt32 index = 0; - for (const char *p = kLangs; *p != 0;) - { - const char *p2 = p; - for (; *p2 != '.'; p2++); - bool isSub = (p[0] == '-' || p[0] == '='); - if (!isSub) - index++; - if (index >= primeLang) - { - if (index > primeLang) - break; - AString s; - if (isSub) - { - if (p[0] == '-') - s = names[0]; - else - p++; - } - while (p != p2) - s.Add_Char((char)(Byte)*p++); - names.Add(s); - } - p = p2 + 1; - } -} - -/* -#include "../../../Common/IntToString.h" - -static struct CC1Lang -{ - CC1Lang() - { - for (int i = 1; i < 150; i++) - { - UString s; - char ttt[32]; - ConvertUInt32ToHex(i, ttt); - s += ttt; - UStringVector names; - FindShortNames(i, names); - - FOR_VECTOR (k, names) - { - s.Add_Space(); - s += names[k]; - } - OutputDebugStringW(s); - } - } -} g_cc1; -*/ - -// typedef LANGID (WINAPI *GetUserDefaultUILanguageP)(); - -void Lang_GetShortNames_for_DefaultLang(AStringVector &names, unsigned &subLang) -{ - names.Clear(); - subLang = 0; - // Region / Administative / Language for non-Unicode programs: - const LANGID sysLang = GetSystemDefaultLangID(); - - // Region / Formats / Format: - const LANGID userLang = GetUserDefaultLangID(); - - if (PRIMARYLANGID(sysLang) != - PRIMARYLANGID(userLang)) - return; - const LANGID langID = userLang; - - // const LANGID langID = MAKELANGID(0x1a, 1); // for debug - - /* - LANGID sysUILang; // english in XP64 - LANGID userUILang; // english in XP64 - - GetUserDefaultUILanguageP fn = (GetUserDefaultUILanguageP)GetProcAddress( - GetModuleHandle("kernel32"), "GetUserDefaultUILanguage"); - if (fn) - userUILang = fn(); - fn = (GetUserDefaultUILanguageP)GetProcAddress( - GetModuleHandle("kernel32"), "GetSystemDefaultUILanguage"); - if (fn) - sysUILang = fn(); - */ - - const WORD primLang = (WORD)(PRIMARYLANGID(langID)); - subLang = SUBLANGID(langID); - FindShortNames(primLang, names); -} - - -static void OpenDefaultLang() -{ - AStringVector names; - unsigned subLang; - Lang_GetShortNames_for_DefaultLang(names, subLang); - { - const FString dirPrefix (GetLangDirPrefix()); - for (unsigned i = 0; i < 2; i++) - { - const unsigned index = (i == 0 ? subLang : 0); - if (index < names.Size()) - { - const AString &name = names[index]; - if (!name.IsEmpty()) - { - FString path (dirPrefix); - path += name; - path += ".txt"; - if (LangOpen(g_Lang, path)) - { - g_LangID = name; - return; - } - } - } - } - } -} - -void ReloadLang() -{ - g_Lang.Clear(); - ReadRegLang(g_LangID); - #ifndef _UNICODE - if (g_IsNT) - #endif - { - if (g_LangID.IsEmpty()) - { - OpenDefaultLang(); - return; - } - } - if (g_LangID.Len() > 1 || g_LangID[0] != L'-') - { - FString s = us2fs(g_LangID); - if (s.ReverseFind_PathSepar() < 0) - { - if (s.ReverseFind_Dot() < 0) - s += ".txt"; - s.Insert(0, GetLangDirPrefix()); - LangOpen(g_Lang, s); - } - } -} - -#endif +// LangUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/Lang.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/Window.h" + +#include "LangUtils.h" +#include "RegistryUtils.h" + +using namespace NWindows; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +UString g_LangID; + +// static +CLang g_Lang; +static bool g_Loaded = false; +static NSynchronization::CCriticalSection g_CriticalSection; + +bool LangOpen(CLang &lang, CFSTR fileName); +bool LangOpen(CLang &lang, CFSTR fileName) +{ + return lang.Open(fileName, "7-Zip"); +} + +FString GetLangDirPrefix() +{ + return NDLL::GetModuleDirPrefix() + FTEXT("Lang") FSTRING_PATH_SEPARATOR; +} + +#ifdef Z7_LANG + +void LoadLangOneTime() +{ + NSynchronization::CCriticalSectionLock lock(g_CriticalSection); + if (g_Loaded) + return; + g_Loaded = true; + ReloadLang(); +} + +void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID) +{ + const wchar_t *s = g_Lang.Get(langID); + if (s) + { + CWindow window(GetDlgItem(dialog, (int)controlID)); + window.SetText(s); + } +} + +#ifndef IDCONTINUE +#define IDCONTINUE 11 +#endif + +static const CIDLangPair kLangPairs[] = +{ + { IDOK, 401 }, + { IDCANCEL, 402 }, + { IDYES, 406 }, + { IDNO, 407 }, + { IDCLOSE, 408 }, + { IDHELP, 409 }, + { IDCONTINUE, 411 } +}; + + +void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems) +{ + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(kLangPairs); i++) + { + const CIDLangPair &pair = kLangPairs[i]; + CWindow window(GetDlgItem(dialog, (int)pair.ControlID)); + if (window) + { + const wchar_t *s = g_Lang.Get(pair.LangID); + if (s) + window.SetText(s); + } + } + + for (i = 0; i < numItems; i++) + { + const UInt32 id = ids[i]; + LangSetDlgItemText(dialog, id, id); + } +} + +void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems) +{ + for (unsigned i = 0; i < numItems; i++) + { + const UInt32 id = ids[i]; + const wchar_t *s = g_Lang.Get(id); + if (s) + { + CWindow window(GetDlgItem(dialog, (int)id)); + UString s2 = s; + s2.Add_Colon(); + window.SetText(s2); + } + } +} + +void LangSetDlgItems_RemoveColon(HWND dialog, const UInt32 *ids, unsigned numItems) +{ + for (unsigned i = 0; i < numItems; i++) + { + const UInt32 id = ids[i]; + const wchar_t *s = g_Lang.Get(id); + if (s) + { + CWindow window(GetDlgItem(dialog, (int)id)); + UString s2 = s; + if (!s2.IsEmpty() && s2.Back() == ':') + s2.DeleteBack(); + window.SetText(s2); + } + } +} + +void LangSetWindowText(HWND window, UInt32 langID) +{ + const wchar_t *s = g_Lang.Get(langID); + if (s) + MySetWindowText(window, s); +} + +UString LangString(UInt32 langID) +{ + const wchar_t *s = g_Lang.Get(langID); + if (s) + return s; + return MyLoadString(langID); +} + +void AddLangString(UString &s, UInt32 langID) +{ + s += LangString(langID); +} + +void LangString(UInt32 langID, UString &dest) +{ + const wchar_t *s = g_Lang.Get(langID); + if (s) + { + dest = s; + return; + } + MyLoadString(langID, dest); +} + +void LangString_OnlyFromLangFile(UInt32 langID, UString &dest) +{ + dest.Empty(); + const wchar_t *s = g_Lang.Get(langID); + if (s) + dest = s; +} + +static const char * const kLangs = + "ar.bg.ca.zh.-tw.-cn.cs.da.de.el.en.es.fi.fr.he.hu.is." + "it.ja.ko.nl.no.=nb.=nn.pl.pt.-br.rm.ro.ru.sr.=hr.-spl.-spc.=hr.=bs.sk.sq.sv.th.tr." + "ur.id.uk.be.sl.et.lv.lt.tg.fa.vi.hy.az.eu.hsb.mk." + "st.ts.tn.ve.xh.zu.af.ka.fo.hi.mt.se.ga.yi.ms.kk." + "ky.sw.tk.uz.-latn.-cyrl.tt.bn.pa.-in.gu.or.ta.te.kn.ml.as.mr.sa." + "mn.=mn.=mng.bo.cy.kh.lo.my.gl.kok..sd.syr.si..iu.am.tzm." + "ks.ne.fy.ps.tl.dv..ff.ha..yo.qu.st.ba.lb.kl." + "ig.kr.om.ti.gn..la.so.ii..arn..moh..br.." + "ug.mi.oc.co." + // "gsw.sah.qut.rw.wo....prs...." + // ".gd." + ; + +static void FindShortNames(UInt32 primeLang, AStringVector &names) +{ + UInt32 index = 0; + for (const char *p = kLangs; *p != 0;) + { + const char *p2 = p; + for (; *p2 != '.'; p2++); + bool isSub = (p[0] == '-' || p[0] == '='); + if (!isSub) + index++; + if (index >= primeLang) + { + if (index > primeLang) + break; + AString s; + if (isSub) + { + if (p[0] == '-') + s = names[0]; + else + p++; + } + while (p != p2) + s.Add_Char((char)(Byte)*p++); + names.Add(s); + } + p = p2 + 1; + } +} + +/* +#include "../../../Common/IntToString.h" + +static struct CC1Lang +{ + CC1Lang() + { + for (int i = 1; i < 150; i++) + { + UString s; + char ttt[32]; + ConvertUInt32ToHex(i, ttt); + s += ttt; + UStringVector names; + FindShortNames(i, names); + + FOR_VECTOR (k, names) + { + s.Add_Space(); + s += names[k]; + } + OutputDebugStringW(s); + } + } +} g_cc1; +*/ + +// typedef LANGID (WINAPI *GetUserDefaultUILanguageP)(); + +void Lang_GetShortNames_for_DefaultLang(AStringVector &names, unsigned &subLang) +{ + names.Clear(); + subLang = 0; + // Region / Administative / Language for non-Unicode programs: + const LANGID sysLang = GetSystemDefaultLangID(); + + // Region / Formats / Format: + const LANGID userLang = GetUserDefaultLangID(); + + if (PRIMARYLANGID(sysLang) != + PRIMARYLANGID(userLang)) + return; + const LANGID langID = userLang; + + // const LANGID langID = MAKELANGID(0x1a, 1); // for debug + + /* + LANGID sysUILang; // english in XP64 + LANGID userUILang; // english in XP64 + + GetUserDefaultUILanguageP fn = (GetUserDefaultUILanguageP)GetProcAddress( + GetModuleHandle("kernel32"), "GetUserDefaultUILanguage"); + if (fn) + userUILang = fn(); + fn = (GetUserDefaultUILanguageP)GetProcAddress( + GetModuleHandle("kernel32"), "GetSystemDefaultUILanguage"); + if (fn) + sysUILang = fn(); + */ + + const WORD primLang = (WORD)(PRIMARYLANGID(langID)); + subLang = SUBLANGID(langID); + FindShortNames(primLang, names); +} + + +static void OpenDefaultLang() +{ + AStringVector names; + unsigned subLang; + Lang_GetShortNames_for_DefaultLang(names, subLang); + { + const FString dirPrefix (GetLangDirPrefix()); + for (unsigned i = 0; i < 2; i++) + { + const unsigned index = (i == 0 ? subLang : 0); + if (index < names.Size()) + { + const AString &name = names[index]; + if (!name.IsEmpty()) + { + FString path (dirPrefix); + path += name; + path += ".txt"; + if (LangOpen(g_Lang, path)) + { + g_LangID = name; + return; + } + } + } + } + } +} + +void ReloadLang() +{ + g_Lang.Clear(); + ReadRegLang(g_LangID); + #ifndef _UNICODE + if (g_IsNT) + #endif + { + if (g_LangID.IsEmpty()) + { + OpenDefaultLang(); + return; + } + } + if (g_LangID.Len() > 1 || g_LangID[0] != L'-') + { + FString s = us2fs(g_LangID); + if (s.ReverseFind_PathSepar() < 0) + { + if (s.ReverseFind_Dot() < 0) + s += ".txt"; + s.Insert(0, GetLangDirPrefix()); + LangOpen(g_Lang, s); + } + } +} + +#endif diff --git a/CPP/7zip/UI/FileManager/LangUtils.h b/CPP/7zip/UI/FileManager/LangUtils.h index 15e0ed99e..d53d270ea 100644 --- a/CPP/7zip/UI/FileManager/LangUtils.h +++ b/CPP/7zip/UI/FileManager/LangUtils.h @@ -1,48 +1,48 @@ -// LangUtils.h - -#ifndef ZIP7_INC_LANG_UTILS_H -#define ZIP7_INC_LANG_UTILS_H - -#include "../../../Common/Lang.h" - -#include "../../../Windows/ResourceString.h" - -extern UString g_LangID; -extern CLang g_Lang; - -#ifdef Z7_LANG - -struct CIDLangPair -{ - UInt32 ControlID; - UInt32 LangID; -}; - -void ReloadLang(); -void LoadLangOneTime(); - -void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID); -void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems); -void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems); -void LangSetDlgItems_RemoveColon(HWND dialog, const UInt32 *ids, unsigned numItems); -void LangSetWindowText(HWND window, UInt32 langID); - -UString LangString(UInt32 langID); -void AddLangString(UString &s, UInt32 langID); -void LangString(UInt32 langID, UString &dest); -void LangString_OnlyFromLangFile(UInt32 langID, UString &dest); - -#else - -inline UString LangString(UInt32 langID) { return NWindows::MyLoadString(langID); } -inline void LangString(UInt32 langID, UString &dest) { NWindows::MyLoadString(langID, dest); } -inline void AddLangString(UString &s, UInt32 langID) { s += NWindows::MyLoadString(langID); } - -#endif - -FString GetLangDirPrefix(); -// bool LangOpen(CLang &lang, CFSTR fileName); - -void Lang_GetShortNames_for_DefaultLang(AStringVector &names, unsigned &subLang); - -#endif +// LangUtils.h + +#ifndef ZIP7_INC_LANG_UTILS_H +#define ZIP7_INC_LANG_UTILS_H + +#include "../../../Common/Lang.h" + +#include "../../../Windows/ResourceString.h" + +extern UString g_LangID; +extern CLang g_Lang; + +#ifdef Z7_LANG + +struct CIDLangPair +{ + UInt32 ControlID; + UInt32 LangID; +}; + +void ReloadLang(); +void LoadLangOneTime(); + +void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID); +void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems); +void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems); +void LangSetDlgItems_RemoveColon(HWND dialog, const UInt32 *ids, unsigned numItems); +void LangSetWindowText(HWND window, UInt32 langID); + +UString LangString(UInt32 langID); +void AddLangString(UString &s, UInt32 langID); +void LangString(UInt32 langID, UString &dest); +void LangString_OnlyFromLangFile(UInt32 langID, UString &dest); + +#else + +inline UString LangString(UInt32 langID) { return NWindows::MyLoadString(langID); } +inline void LangString(UInt32 langID, UString &dest) { NWindows::MyLoadString(langID, dest); } +inline void AddLangString(UString &s, UInt32 langID) { s += NWindows::MyLoadString(langID); } + +#endif + +FString GetLangDirPrefix(); +// bool LangOpen(CLang &lang, CFSTR fileName); + +void Lang_GetShortNames_for_DefaultLang(AStringVector &names, unsigned &subLang); + +#endif diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp index 9492009a7..0f2476170 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.cpp +++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp @@ -1,400 +1,400 @@ -// LinkDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" - -#include "LangUtils.h" - -#include "BrowseDialog.h" -#include "CopyDialogRes.h" -#include "LinkDialog.h" -#include "resourceGui.h" - -#include "App.h" - -#include "resource.h" - -extern bool g_SymLink_Supported; - -using namespace NWindows; -using namespace NFile; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDB_LINK_LINK, - IDT_LINK_PATH_FROM, - IDT_LINK_PATH_TO, - IDG_LINK_TYPE, - IDR_LINK_TYPE_HARD, - IDR_LINK_TYPE_SYM_FILE, - IDR_LINK_TYPE_SYM_DIR, - IDR_LINK_TYPE_JUNCTION, - IDR_LINK_TYPE_WSL -}; -#endif - - -static bool GetSymLink(CFSTR path, CReparseAttr &attr, UString &errorMessage) -{ - CByteBuffer buf; - if (!NIO::GetReparseData(path, buf, NULL)) - return false; - - if (!attr.Parse(buf, buf.Size())) - { - SetLastError(attr.ErrorCode); - return false; - } - - CByteBuffer data2; - if (!FillLinkData(data2, attr.GetPath(), - !attr.IsMountPoint(), attr.IsSymLink_WSL())) - { - errorMessage = "Cannot reproduce reparse point"; - return false; - } - - if (data2.Size() != buf.Size() || - memcmp(data2, buf, buf.Size()) != 0) - { - errorMessage = "mismatch for reproduced reparse point"; - return false; - } - - return true; -} - - -static const unsigned k_LinkType_Buttons[] = -{ - IDR_LINK_TYPE_HARD, - IDR_LINK_TYPE_SYM_FILE, - IDR_LINK_TYPE_SYM_DIR, - IDR_LINK_TYPE_JUNCTION, - IDR_LINK_TYPE_WSL -}; - -void CLinkDialog::Set_LinkType_Radio(unsigned idb) -{ - CheckRadioButton( - k_LinkType_Buttons[0], - k_LinkType_Buttons[Z7_ARRAY_SIZE(k_LinkType_Buttons) - 1], - idb); -} - -bool CLinkDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_LINK); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - - _pathFromCombo.Attach(GetItem(IDC_LINK_PATH_FROM)); - _pathToCombo.Attach(GetItem(IDC_LINK_PATH_TO)); - - if (!FilePath.IsEmpty()) - { - NFind::CFileInfo fi; - unsigned linkType = 0; - if (!fi.Find(us2fs(FilePath))) - linkType = IDR_LINK_TYPE_SYM_FILE; - else - { - if (fi.HasReparsePoint()) - { - CReparseAttr attr; - UString error; - const bool res = GetSymLink(us2fs(FilePath), attr, error); - if (!res && error.IsEmpty()) - { - DWORD lastError = GetLastError(); - if (lastError != 0) - error = NError::MyFormatMessage(lastError); - } - - UString s = attr.GetPath(); - if (!attr.IsSymLink_WSL()) - if (!attr.IsOkNamePair()) - { - s += " : "; - s += attr.PrintName; - } - - if (!res) - { - s.Insert(0, L"ERROR: "); - if (!error.IsEmpty()) - { - s += " : "; - s += error; - } - } - - - SetItemText(IDT_LINK_PATH_TO_CUR, s); - - const UString destPath = attr.GetPath(); - _pathFromCombo.SetText(FilePath); - _pathToCombo.SetText(destPath); - - // if (res) - { - if (attr.IsMountPoint()) - linkType = IDR_LINK_TYPE_JUNCTION; - else if (attr.IsSymLink_WSL()) - linkType = IDR_LINK_TYPE_WSL; - else if (attr.IsSymLink_Win()) - { - linkType = - fi.IsDir() ? - IDR_LINK_TYPE_SYM_DIR : - IDR_LINK_TYPE_SYM_FILE; - // if (attr.IsRelative()) linkType = IDR_LINK_TYPE_SYM_RELATIVE; - } - - if (linkType != 0) - Set_LinkType_Radio(linkType); - } - } - else - { - // no ReparsePoint - _pathFromCombo.SetText(AnotherPath); - _pathToCombo.SetText(FilePath); - if (fi.IsDir()) - linkType = g_SymLink_Supported ? - IDR_LINK_TYPE_SYM_DIR : - IDR_LINK_TYPE_JUNCTION; - else - linkType = IDR_LINK_TYPE_HARD; - } - } - if (linkType != 0) - Set_LinkType_Radio(linkType); - } - - NormalizeSize(); - return CModalDialog::OnInit(); -} - -bool CLinkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx1, bx2, by; - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDB_LINK_LINK, bx2, by); - int yPos = ySize - my - by; - int xPos = xSize - mx - bx1; - - InvalidateRect(NULL); - - { - RECT r, r2; - GetClientRectOfItem(IDB_LINK_PATH_FROM, r); - GetClientRectOfItem(IDB_LINK_PATH_TO, r2); - int bx = RECT_SIZE_X(r); - int newButtonXpos = xSize - mx - bx; - - MoveItem(IDB_LINK_PATH_FROM, newButtonXpos, r.top, bx, RECT_SIZE_Y(r)); - MoveItem(IDB_LINK_PATH_TO, newButtonXpos, r2.top, bx, RECT_SIZE_Y(r2)); - - int newComboXsize = newButtonXpos - mx - mx; - ChangeSubWindowSizeX(_pathFromCombo, newComboXsize); - ChangeSubWindowSizeX(_pathToCombo, newComboXsize); - } - - MoveItem(IDCANCEL, xPos, yPos, bx1, by); - MoveItem(IDB_LINK_LINK, xPos - mx - bx2, yPos, bx2, by); - - return false; -} - -bool CLinkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_LINK_PATH_FROM: - OnButton_SetPath(false); - return true; - case IDB_LINK_PATH_TO: - OnButton_SetPath(true); - return true; - case IDB_LINK_LINK: - OnButton_Link(); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CLinkDialog::OnButton_SetPath(bool to) -{ - UString currentPath; - NWindows::NControl::CComboBox &combo = to ? - _pathToCombo : - _pathFromCombo; - combo.GetText(currentPath); - // UString title = "Specify a location for output folder"; - const UString title = LangString(IDS_SET_FOLDER); - - UString resultPath; - if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) - return; - NName::NormalizeDirPathPrefix(resultPath); - combo.SetCurSel(-1); - combo.SetText(resultPath); -} - -void CLinkDialog::ShowError(const wchar_t *s) -{ - ::MessageBoxW(*this, s, L"7-Zip", MB_ICONERROR); -} - -void CLinkDialog::ShowLastErrorMessage() -{ - ShowError(NError::MyFormatMessage(GetLastError())); -} - -void CLinkDialog::OnButton_Link() -{ - UString from, to; - _pathFromCombo.GetText(from); - _pathToCombo.GetText(to); - - if (from.IsEmpty()) - return; - if (!NName::IsAbsolutePath(from)) - from.Insert(0, CurDirPrefix); - - unsigned idb = 0; - for (unsigned i = 0;; i++) - { - if (i >= Z7_ARRAY_SIZE(k_LinkType_Buttons)) - return; - idb = k_LinkType_Buttons[i]; - if (IsButtonCheckedBool(idb)) - break; - } - - NFind::CFileInfo info1, info2; - const bool finded1 = info1.Find(us2fs(from)); - const bool finded2 = info2.Find(us2fs(to)); - - const bool isDirLink = ( - idb == IDR_LINK_TYPE_SYM_DIR || - idb == IDR_LINK_TYPE_JUNCTION); - - const bool isWSL = (idb == IDR_LINK_TYPE_WSL); - - if (!isWSL) - if ((finded1 && info1.IsDir() != isDirLink) || - (finded2 && info2.IsDir() != isDirLink)) - { - ShowError(L"Incorrect link type"); - return; - } - - if (idb == IDR_LINK_TYPE_HARD) - { - if (!NDir::MyCreateHardLink(us2fs(from), us2fs(to))) - { - ShowLastErrorMessage(); - return; - } - } - else - { - if (finded1 && !info1.IsDir() && !info1.HasReparsePoint() && info1.Size != 0) - { - UString s ("WARNING: reparse point will hide the data of existing file"); - s.Add_LF(); - s += from; - ShowError(s); - return; - } - - const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION); - - CByteBuffer data; - if (!FillLinkData(data, to, isSymLink, isWSL)) - { - ShowError(L"Incorrect link"); - return; - } - - CReparseAttr attr; - if (!attr.Parse(data, data.Size())) - { - ShowError(L"Internal conversion error"); - return; - } - - bool res; - if (to.IsEmpty()) - { - // res = NIO::SetReparseData(us2fs(from), isDirLink, NULL, 0); - res = NIO::DeleteReparseData(us2fs(from)); - } - else - res = NIO::SetReparseData(us2fs(from), isDirLink, data, (DWORD)data.Size()); - - if (!res) - { - ShowLastErrorMessage(); - return; - } - } - - End(IDOK); -} - -void CApp::Link() -{ - const unsigned srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - if (!srcPanel.IsFSFolder()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - CRecordVector indices; - srcPanel.Get_ItemIndices_Operated(indices); - if (indices.IsEmpty()) - return; - if (indices.Size() != 1) - { - srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); - return; - } - const UInt32 index = indices[0]; - const UString itemName = srcPanel.GetItemName(index); - - const UString fsPrefix = srcPanel.GetFsPath(); - const UString srcPath = fsPrefix + srcPanel.GetItemPrefix(index); - UString path = srcPath; - { - const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); - CPanel &destPanel = Panels[destPanelIndex]; - if (NumPanels > 1) - if (destPanel.IsFSFolder()) - path = destPanel.GetFsPath(); - } - - CLinkDialog dlg; - dlg.CurDirPrefix = fsPrefix; - dlg.FilePath = srcPath + itemName; - dlg.AnotherPath = path; - - if (dlg.Create(srcPanel.GetParent()) != IDOK) - return; - - // fix it: we should refresh panel with changed link - - RefreshTitleAlways(); -} +// LinkDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" + +#include "LangUtils.h" + +#include "BrowseDialog.h" +#include "CopyDialogRes.h" +#include "LinkDialog.h" +#include "resourceGui.h" + +#include "App.h" + +#include "resource.h" + +extern bool g_SymLink_Supported; + +using namespace NWindows; +using namespace NFile; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDB_LINK_LINK, + IDT_LINK_PATH_FROM, + IDT_LINK_PATH_TO, + IDG_LINK_TYPE, + IDR_LINK_TYPE_HARD, + IDR_LINK_TYPE_SYM_FILE, + IDR_LINK_TYPE_SYM_DIR, + IDR_LINK_TYPE_JUNCTION, + IDR_LINK_TYPE_WSL +}; +#endif + + +static bool GetSymLink(CFSTR path, CReparseAttr &attr, UString &errorMessage) +{ + CByteBuffer buf; + if (!NIO::GetReparseData(path, buf, NULL)) + return false; + + if (!attr.Parse(buf, buf.Size())) + { + SetLastError(attr.ErrorCode); + return false; + } + + CByteBuffer data2; + if (!FillLinkData(data2, attr.GetPath(), + !attr.IsMountPoint(), attr.IsSymLink_WSL())) + { + errorMessage = "Cannot reproduce reparse point"; + return false; + } + + if (data2.Size() != buf.Size() || + memcmp(data2, buf, buf.Size()) != 0) + { + errorMessage = "mismatch for reproduced reparse point"; + return false; + } + + return true; +} + + +static const unsigned k_LinkType_Buttons[] = +{ + IDR_LINK_TYPE_HARD, + IDR_LINK_TYPE_SYM_FILE, + IDR_LINK_TYPE_SYM_DIR, + IDR_LINK_TYPE_JUNCTION, + IDR_LINK_TYPE_WSL +}; + +void CLinkDialog::Set_LinkType_Radio(unsigned idb) +{ + CheckRadioButton( + k_LinkType_Buttons[0], + k_LinkType_Buttons[Z7_ARRAY_SIZE(k_LinkType_Buttons) - 1], + idb); +} + +bool CLinkDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_LINK); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + + _pathFromCombo.Attach(GetItem(IDC_LINK_PATH_FROM)); + _pathToCombo.Attach(GetItem(IDC_LINK_PATH_TO)); + + if (!FilePath.IsEmpty()) + { + NFind::CFileInfo fi; + unsigned linkType = 0; + if (!fi.Find(us2fs(FilePath))) + linkType = IDR_LINK_TYPE_SYM_FILE; + else + { + if (fi.HasReparsePoint()) + { + CReparseAttr attr; + UString error; + const bool res = GetSymLink(us2fs(FilePath), attr, error); + if (!res && error.IsEmpty()) + { + DWORD lastError = GetLastError(); + if (lastError != 0) + error = NError::MyFormatMessage(lastError); + } + + UString s = attr.GetPath(); + if (!attr.IsSymLink_WSL()) + if (!attr.IsOkNamePair()) + { + s += " : "; + s += attr.PrintName; + } + + if (!res) + { + s.Insert(0, L"ERROR: "); + if (!error.IsEmpty()) + { + s += " : "; + s += error; + } + } + + + SetItemText(IDT_LINK_PATH_TO_CUR, s); + + const UString destPath = attr.GetPath(); + _pathFromCombo.SetText(FilePath); + _pathToCombo.SetText(destPath); + + // if (res) + { + if (attr.IsMountPoint()) + linkType = IDR_LINK_TYPE_JUNCTION; + else if (attr.IsSymLink_WSL()) + linkType = IDR_LINK_TYPE_WSL; + else if (attr.IsSymLink_Win()) + { + linkType = + fi.IsDir() ? + IDR_LINK_TYPE_SYM_DIR : + IDR_LINK_TYPE_SYM_FILE; + // if (attr.IsRelative()) linkType = IDR_LINK_TYPE_SYM_RELATIVE; + } + + if (linkType != 0) + Set_LinkType_Radio(linkType); + } + } + else + { + // no ReparsePoint + _pathFromCombo.SetText(AnotherPath); + _pathToCombo.SetText(FilePath); + if (fi.IsDir()) + linkType = g_SymLink_Supported ? + IDR_LINK_TYPE_SYM_DIR : + IDR_LINK_TYPE_JUNCTION; + else + linkType = IDR_LINK_TYPE_HARD; + } + } + if (linkType != 0) + Set_LinkType_Radio(linkType); + } + + NormalizeSize(); + return CModalDialog::OnInit(); +} + +bool CLinkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDB_LINK_LINK, bx2, by); + int yPos = ySize - my - by; + int xPos = xSize - mx - bx1; + + InvalidateRect(NULL); + + { + RECT r, r2; + GetClientRectOfItem(IDB_LINK_PATH_FROM, r); + GetClientRectOfItem(IDB_LINK_PATH_TO, r2); + int bx = RECT_SIZE_X(r); + int newButtonXpos = xSize - mx - bx; + + MoveItem(IDB_LINK_PATH_FROM, newButtonXpos, r.top, bx, RECT_SIZE_Y(r)); + MoveItem(IDB_LINK_PATH_TO, newButtonXpos, r2.top, bx, RECT_SIZE_Y(r2)); + + int newComboXsize = newButtonXpos - mx - mx; + ChangeSubWindowSizeX(_pathFromCombo, newComboXsize); + ChangeSubWindowSizeX(_pathToCombo, newComboXsize); + } + + MoveItem(IDCANCEL, xPos, yPos, bx1, by); + MoveItem(IDB_LINK_LINK, xPos - mx - bx2, yPos, bx2, by); + + return false; +} + +bool CLinkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_LINK_PATH_FROM: + OnButton_SetPath(false); + return true; + case IDB_LINK_PATH_TO: + OnButton_SetPath(true); + return true; + case IDB_LINK_LINK: + OnButton_Link(); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CLinkDialog::OnButton_SetPath(bool to) +{ + UString currentPath; + NWindows::NControl::CComboBox &combo = to ? + _pathToCombo : + _pathFromCombo; + combo.GetText(currentPath); + // UString title = "Specify a location for output folder"; + const UString title = LangString(IDS_SET_FOLDER); + + UString resultPath; + if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) + return; + NName::NormalizeDirPathPrefix(resultPath); + combo.SetCurSel(-1); + combo.SetText(resultPath); +} + +void CLinkDialog::ShowError(const wchar_t *s) +{ + ::MessageBoxW(*this, s, L"7-Zip", MB_ICONERROR); +} + +void CLinkDialog::ShowLastErrorMessage() +{ + ShowError(NError::MyFormatMessage(GetLastError())); +} + +void CLinkDialog::OnButton_Link() +{ + UString from, to; + _pathFromCombo.GetText(from); + _pathToCombo.GetText(to); + + if (from.IsEmpty()) + return; + if (!NName::IsAbsolutePath(from)) + from.Insert(0, CurDirPrefix); + + unsigned idb = 0; + for (unsigned i = 0;; i++) + { + if (i >= Z7_ARRAY_SIZE(k_LinkType_Buttons)) + return; + idb = k_LinkType_Buttons[i]; + if (IsButtonCheckedBool(idb)) + break; + } + + NFind::CFileInfo info1, info2; + const bool finded1 = info1.Find(us2fs(from)); + const bool finded2 = info2.Find(us2fs(to)); + + const bool isDirLink = ( + idb == IDR_LINK_TYPE_SYM_DIR || + idb == IDR_LINK_TYPE_JUNCTION); + + const bool isWSL = (idb == IDR_LINK_TYPE_WSL); + + if (!isWSL) + if ((finded1 && info1.IsDir() != isDirLink) || + (finded2 && info2.IsDir() != isDirLink)) + { + ShowError(L"Incorrect link type"); + return; + } + + if (idb == IDR_LINK_TYPE_HARD) + { + if (!NDir::MyCreateHardLink(us2fs(from), us2fs(to))) + { + ShowLastErrorMessage(); + return; + } + } + else + { + if (finded1 && !info1.IsDir() && !info1.HasReparsePoint() && info1.Size != 0) + { + UString s ("WARNING: reparse point will hide the data of existing file"); + s.Add_LF(); + s += from; + ShowError(s); + return; + } + + const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION); + + CByteBuffer data; + if (!FillLinkData(data, to, isSymLink, isWSL)) + { + ShowError(L"Incorrect link"); + return; + } + + CReparseAttr attr; + if (!attr.Parse(data, data.Size())) + { + ShowError(L"Internal conversion error"); + return; + } + + bool res; + if (to.IsEmpty()) + { + // res = NIO::SetReparseData(us2fs(from), isDirLink, NULL, 0); + res = NIO::DeleteReparseData(us2fs(from)); + } + else + res = NIO::SetReparseData(us2fs(from), isDirLink, data, (DWORD)data.Size()); + + if (!res) + { + ShowLastErrorMessage(); + return; + } + } + + End(IDOK); +} + +void CApp::Link() +{ + const unsigned srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + if (!srcPanel.IsFSFolder()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + CRecordVector indices; + srcPanel.Get_ItemIndices_Operated(indices); + if (indices.IsEmpty()) + return; + if (indices.Size() != 1) + { + srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); + return; + } + const UInt32 index = indices[0]; + const UString itemName = srcPanel.GetItemName(index); + + const UString fsPrefix = srcPanel.GetFsPath(); + const UString srcPath = fsPrefix + srcPanel.GetItemPrefix(index); + UString path = srcPath; + { + const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); + CPanel &destPanel = Panels[destPanelIndex]; + if (NumPanels > 1) + if (destPanel.IsFSFolder()) + path = destPanel.GetFsPath(); + } + + CLinkDialog dlg; + dlg.CurDirPrefix = fsPrefix; + dlg.FilePath = srcPath + itemName; + dlg.AnotherPath = path; + + if (dlg.Create(srcPanel.GetParent()) != IDOK) + return; + + // fix it: we should refresh panel with changed link + + RefreshTitleAlways(); +} diff --git a/CPP/7zip/UI/FileManager/LinkDialog.h b/CPP/7zip/UI/FileManager/LinkDialog.h index dbc11790d..dd768f7e4 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.h +++ b/CPP/7zip/UI/FileManager/LinkDialog.h @@ -1,34 +1,34 @@ -// LinkDialog.h - -#ifndef ZIP7_INC_LINK_DIALOG_H -#define ZIP7_INC_LINK_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/ComboBox.h" - -#include "LinkDialogRes.h" - -class CLinkDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox _pathFromCombo; - NWindows::NControl::CComboBox _pathToCombo; - - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - void OnButton_SetPath(bool to); - void OnButton_Link(); - - void ShowLastErrorMessage(); - void ShowError(const wchar_t *s); - void Set_LinkType_Radio(unsigned idb); -public: - UString CurDirPrefix; - UString FilePath; - UString AnotherPath; - - INT_PTR Create(HWND parentWindow = NULL) - { return CModalDialog::Create(IDD_LINK, parentWindow); } -}; - -#endif +// LinkDialog.h + +#ifndef ZIP7_INC_LINK_DIALOG_H +#define ZIP7_INC_LINK_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/ComboBox.h" + +#include "LinkDialogRes.h" + +class CLinkDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CComboBox _pathFromCombo; + NWindows::NControl::CComboBox _pathToCombo; + + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + void OnButton_SetPath(bool to); + void OnButton_Link(); + + void ShowLastErrorMessage(); + void ShowError(const wchar_t *s); + void Set_LinkType_Radio(unsigned idb); +public: + UString CurDirPrefix; + UString FilePath; + UString AnotherPath; + + INT_PTR Create(HWND parentWindow = NULL) + { return CModalDialog::Create(IDD_LINK, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/LinkDialog.rc b/CPP/7zip/UI/FileManager/LinkDialog.rc index fddfd33d5..a9e220bae 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.rc +++ b/CPP/7zip/UI/FileManager/LinkDialog.rc @@ -1,38 +1,38 @@ -#include "LinkDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 288 -#define yc 214 - -#undef xRadioSize -#define xRadioSize xc - m - 2 - -IDD_LINK DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Link" -BEGIN - LTEXT "Link from:", IDT_LINK_PATH_FROM, m, m, xc, 8 - COMBOBOX IDC_LINK_PATH_FROM, m, 20, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_LINK_PATH_FROM, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP - - LTEXT "Link to:", IDT_LINK_PATH_TO, m, 48, xc, 8 - COMBOBOX IDC_LINK_PATH_TO, m, 60, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_LINK_PATH_TO, xs - m - bxsDots, 58, bxsDots, bys, WS_GROUP - - LTEXT "", IDT_LINK_PATH_TO_CUR, m, 78, xc, 8 - - GROUPBOX "Link Type", IDG_LINK_TYPE, m, 104, xc, 90 - - CONTROL "Hard Link", IDR_LINK_TYPE_HARD, "Button", BS_AUTORADIOBUTTON | WS_GROUP, - m + m, 120, xRadioSize, 10 - CONTROL "File Symbolic Link", IDR_LINK_TYPE_SYM_FILE, "Button", BS_AUTORADIOBUTTON, - m + m, 134, xRadioSize, 10 - CONTROL "Directory Symbolic Link", IDR_LINK_TYPE_SYM_DIR, "Button", BS_AUTORADIOBUTTON, - m + m, 148, xRadioSize, 10 - CONTROL "Directory Junction", IDR_LINK_TYPE_JUNCTION, "Button", BS_AUTORADIOBUTTON, - m + m, 162, xRadioSize, 10 - CONTROL "WSL", IDR_LINK_TYPE_WSL, "Button", BS_AUTORADIOBUTTON, - m + m, 176, xRadioSize, 10 - - DEFPUSHBUTTON "Link", IDB_LINK_LINK, bx2, by, bxs, bys - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -END +#include "LinkDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 288 +#define yc 214 + +#undef xRadioSize +#define xRadioSize xc - m - 2 + +IDD_LINK DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Link" +BEGIN + LTEXT "Link from:", IDT_LINK_PATH_FROM, m, m, xc, 8 + COMBOBOX IDC_LINK_PATH_FROM, m, 20, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_LINK_PATH_FROM, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP + + LTEXT "Link to:", IDT_LINK_PATH_TO, m, 48, xc, 8 + COMBOBOX IDC_LINK_PATH_TO, m, 60, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_LINK_PATH_TO, xs - m - bxsDots, 58, bxsDots, bys, WS_GROUP + + LTEXT "", IDT_LINK_PATH_TO_CUR, m, 78, xc, 8 + + GROUPBOX "Link Type", IDG_LINK_TYPE, m, 104, xc, 90 + + CONTROL "Hard Link", IDR_LINK_TYPE_HARD, "Button", BS_AUTORADIOBUTTON | WS_GROUP, + m + m, 120, xRadioSize, 10 + CONTROL "File Symbolic Link", IDR_LINK_TYPE_SYM_FILE, "Button", BS_AUTORADIOBUTTON, + m + m, 134, xRadioSize, 10 + CONTROL "Directory Symbolic Link", IDR_LINK_TYPE_SYM_DIR, "Button", BS_AUTORADIOBUTTON, + m + m, 148, xRadioSize, 10 + CONTROL "Directory Junction", IDR_LINK_TYPE_JUNCTION, "Button", BS_AUTORADIOBUTTON, + m + m, 162, xRadioSize, 10 + CONTROL "WSL", IDR_LINK_TYPE_WSL, "Button", BS_AUTORADIOBUTTON, + m + m, 176, xRadioSize, 10 + + DEFPUSHBUTTON "Link", IDB_LINK_LINK, bx2, by, bxs, bys + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys +END diff --git a/CPP/7zip/UI/FileManager/LinkDialogRes.h b/CPP/7zip/UI/FileManager/LinkDialogRes.h index 1ca4894fa..3f7b3f230 100644 --- a/CPP/7zip/UI/FileManager/LinkDialogRes.h +++ b/CPP/7zip/UI/FileManager/LinkDialogRes.h @@ -1,22 +1,22 @@ -#define IDD_LINK 7700 - -#define IDB_LINK_LINK 7701 - -#define IDT_LINK_PATH_FROM 7702 -#define IDT_LINK_PATH_TO 7703 - -#define IDG_LINK_TYPE 7710 -#define IDR_LINK_TYPE_HARD 7711 -#define IDR_LINK_TYPE_SYM_FILE 7712 -#define IDR_LINK_TYPE_SYM_DIR 7713 -#define IDR_LINK_TYPE_JUNCTION 7714 -#define IDR_LINK_TYPE_WSL 7715 - - -#define IDC_LINK_PATH_FROM 100 -#define IDC_LINK_PATH_TO 101 - -#define IDT_LINK_PATH_TO_CUR 102 - -#define IDB_LINK_PATH_FROM 103 -#define IDB_LINK_PATH_TO 104 +#define IDD_LINK 7700 + +#define IDB_LINK_LINK 7701 + +#define IDT_LINK_PATH_FROM 7702 +#define IDT_LINK_PATH_TO 7703 + +#define IDG_LINK_TYPE 7710 +#define IDR_LINK_TYPE_HARD 7711 +#define IDR_LINK_TYPE_SYM_FILE 7712 +#define IDR_LINK_TYPE_SYM_DIR 7713 +#define IDR_LINK_TYPE_JUNCTION 7714 +#define IDR_LINK_TYPE_WSL 7715 + + +#define IDC_LINK_PATH_FROM 100 +#define IDC_LINK_PATH_TO 101 + +#define IDT_LINK_PATH_TO_CUR 102 + +#define IDB_LINK_PATH_FROM 103 +#define IDB_LINK_PATH_TO 104 diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.cpp b/CPP/7zip/UI/FileManager/ListViewDialog.cpp index db16b547c..6767e4c0c 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.cpp +++ b/CPP/7zip/UI/FileManager/ListViewDialog.cpp @@ -1,321 +1,321 @@ -// ListViewDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/Clipboard.h" - -#include "EditDialog.h" -#include "ListViewDialog.h" -#include "RegistryUtils.h" - -#ifdef Z7_LANG -#include "LangUtils.h" -#endif - -using namespace NWindows; - -static const unsigned kOneStringMaxSize = 1024; - - -static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector) -{ - vector.Clear(); - int index = -1; - for (;;) - { - index = listView.GetNextSelectedItem(index); - if (index < 0) - break; - vector.Add((unsigned)index); - } -} - - -bool CListViewDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetDlgItems(*this, NULL, 0); - #endif - _listView.Attach(GetItem(IDL_LISTVIEW)); - - if (NumColumns > 1) - { - LONG_PTR style = _listView.GetStyle(); - style &= ~(LONG_PTR)LVS_NOCOLUMNHEADER; - _listView.SetStyle(style); - } - - CFmSettings st; - st.Load(); - - DWORD exStyle = 0; - - if (st.SingleClick) - exStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT; - - exStyle |= LVS_EX_FULLROWSELECT; - if (exStyle != 0) - _listView.SetExtendedListViewStyle(exStyle); - - - SetText(Title); - - const int kWidth = 400; - - LVCOLUMN columnInfo; - columnInfo.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; - columnInfo.fmt = LVCFMT_LEFT; - columnInfo.iSubItem = 0; - columnInfo.cx = kWidth; - columnInfo.pszText = NULL; // (TCHAR *)(const TCHAR *)""; // "Property" - - if (NumColumns > 1) - { - columnInfo.cx = 100; - /* - // Windows always uses LVCFMT_LEFT for first column. - // if we need LVCFMT_RIGHT, we can create dummy column and then remove it - - // columnInfo.mask |= LVCF_TEXT; - _listView.InsertColumn(0, &columnInfo); - - columnInfo.iSubItem = 1; - columnInfo.fmt = LVCFMT_RIGHT; - _listView.InsertColumn(1, &columnInfo); - _listView.DeleteColumn(0); - */ - } - // else - _listView.InsertColumn(0, &columnInfo); - - if (NumColumns > 1) - { - // columnInfo.fmt = LVCFMT_LEFT; - columnInfo.cx = kWidth - columnInfo.cx; - columnInfo.iSubItem = 1; - // columnInfo.pszText = NULL; // (TCHAR *)(const TCHAR *)""; // "Value" - _listView.InsertColumn(1, &columnInfo); - } - - - UString s; - - FOR_VECTOR (i, Strings) - { - _listView.InsertItem(i, Strings[i]); - - if (NumColumns > 1 && i < Values.Size()) - { - s = Values[i]; - if (s.Len() > kOneStringMaxSize) - { - s.DeleteFrom(kOneStringMaxSize); - s += " ..."; - } - s.Replace(L"\r\n", L" "); - s.Replace(L"\n", L" "); - _listView.SetSubItem(i, 1, s); - } - } - - if (SelectFirst && Strings.Size() > 0) - _listView.SetItemState_FocusedSelected(0); - - _listView.SetColumnWidthAuto(0); - if (NumColumns > 1) - _listView.SetColumnWidthAuto(1); - StringsWereChanged = false; - - NormalizeSize(); - return CModalDialog::OnInit(); -} - -bool CListViewDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx1, bx2, by; - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDOK, bx2, by); - int y = ySize - my - by; - int x = xSize - mx - bx1; - - /* - RECT rect; - GetClientRect(&rect); - rect.top = y - my; - InvalidateRect(&rect); - */ - InvalidateRect(NULL); - - MoveItem(IDCANCEL, x, y, bx1, by); - MoveItem(IDOK, x - mx - bx2, y, bx2, by); - /* - if (wParam == SIZE_MAXSHOW || wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXHIDE) - mx = 0; - */ - _listView.Move(mx, my, xSize - mx * 2, y - my * 2); - return false; -} - - -extern bool g_LVN_ITEMACTIVATE_Support; - -void CListViewDialog::CopyToClipboard() -{ - CUIntVector indexes; - ListView_GetSelected(_listView, indexes); - UString s; - - FOR_VECTOR (i, indexes) - { - unsigned index = indexes[i]; - s += Strings[index]; - if (NumColumns > 1 && index < Values.Size()) - { - const UString &v = Values[index]; - // if (!v.IsEmpty()) - { - s += ": "; - s += v; - } - } - // if (indexes.Size() > 1) - { - s += - #ifdef _WIN32 - "\r\n" - #else - "\n" - #endif - ; - } - } - - ClipboardSetText(*this, s); -} - - -void CListViewDialog::ShowItemInfo() -{ - CUIntVector indexes; - ListView_GetSelected(_listView, indexes); - if (indexes.Size() != 1) - return; - unsigned index = indexes[0]; - - CEditDialog dlg; - if (NumColumns == 1) - dlg.Text = Strings[index]; - else - { - dlg.Title = Strings[index]; - if (index < Values.Size()) - dlg.Text = Values[index]; - } - - #ifdef _WIN32 - if (dlg.Text.Find(L'\r') < 0) - dlg.Text.Replace(L"\n", L"\r\n"); - #endif - - dlg.Create(*this); -} - - -void CListViewDialog::DeleteItems() -{ - for (;;) - { - const int index = _listView.GetNextSelectedItem(-1); - if (index < 0) - break; - StringsWereChanged = true; - _listView.DeleteItem((unsigned)index); - if ((unsigned)index < Strings.Size()) - Strings.Delete((unsigned)index); - if ((unsigned)index < Values.Size()) - Values.Delete((unsigned)index); - } - const int focusedIndex = _listView.GetFocusedItem(); - if (focusedIndex >= 0) - _listView.SetItemState_FocusedSelected(focusedIndex); - _listView.SetColumnWidthAuto(0); -} - - -void CListViewDialog::OnEnter() -{ - if (IsKeyDown(VK_MENU) - || NumColumns > 1) - { - ShowItemInfo(); - return; - } - OnOK(); -} - -bool CListViewDialog::OnNotify(UINT /* controlID */, LPNMHDR header) -{ - if (header->hwndFrom != _listView) - return false; - switch (header->code) - { - case LVN_ITEMACTIVATE: - if (g_LVN_ITEMACTIVATE_Support) - { - OnEnter(); - return true; - } - break; - case NM_DBLCLK: - case NM_RETURN: // probabably it's unused - if (!g_LVN_ITEMACTIVATE_Support) - { - OnEnter(); - return true; - } - break; - - case LVN_KEYDOWN: - { - LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); - switch (keyDownInfo->wVKey) - { - case VK_DELETE: - { - if (!DeleteIsAllowed) - return false; - DeleteItems(); - return true; - } - case 'A': - { - if (IsKeyDown(VK_CONTROL)) - { - _listView.SelectAll(); - return true; - } - break; - } - case VK_INSERT: - case 'C': - { - if (IsKeyDown(VK_CONTROL)) - { - CopyToClipboard(); - return true; - } - break; - } - } - } - } - return false; -} - -void CListViewDialog::OnOK() -{ - FocusedItemIndex = _listView.GetFocusedItem(); - CModalDialog::OnOK(); -} +// ListViewDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/Clipboard.h" + +#include "EditDialog.h" +#include "ListViewDialog.h" +#include "RegistryUtils.h" + +#ifdef Z7_LANG +#include "LangUtils.h" +#endif + +using namespace NWindows; + +static const unsigned kOneStringMaxSize = 1024; + + +static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector) +{ + vector.Clear(); + int index = -1; + for (;;) + { + index = listView.GetNextSelectedItem(index); + if (index < 0) + break; + vector.Add((unsigned)index); + } +} + + +bool CListViewDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetDlgItems(*this, NULL, 0); + #endif + _listView.Attach(GetItem(IDL_LISTVIEW)); + + if (NumColumns > 1) + { + LONG_PTR style = _listView.GetStyle(); + style &= ~(LONG_PTR)LVS_NOCOLUMNHEADER; + _listView.SetStyle(style); + } + + CFmSettings st; + st.Load(); + + DWORD exStyle = 0; + + if (st.SingleClick) + exStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT; + + exStyle |= LVS_EX_FULLROWSELECT; + if (exStyle != 0) + _listView.SetExtendedListViewStyle(exStyle); + + + SetText(Title); + + const int kWidth = 400; + + LVCOLUMN columnInfo; + columnInfo.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; + columnInfo.fmt = LVCFMT_LEFT; + columnInfo.iSubItem = 0; + columnInfo.cx = kWidth; + columnInfo.pszText = NULL; // (TCHAR *)(const TCHAR *)""; // "Property" + + if (NumColumns > 1) + { + columnInfo.cx = 100; + /* + // Windows always uses LVCFMT_LEFT for first column. + // if we need LVCFMT_RIGHT, we can create dummy column and then remove it + + // columnInfo.mask |= LVCF_TEXT; + _listView.InsertColumn(0, &columnInfo); + + columnInfo.iSubItem = 1; + columnInfo.fmt = LVCFMT_RIGHT; + _listView.InsertColumn(1, &columnInfo); + _listView.DeleteColumn(0); + */ + } + // else + _listView.InsertColumn(0, &columnInfo); + + if (NumColumns > 1) + { + // columnInfo.fmt = LVCFMT_LEFT; + columnInfo.cx = kWidth - columnInfo.cx; + columnInfo.iSubItem = 1; + // columnInfo.pszText = NULL; // (TCHAR *)(const TCHAR *)""; // "Value" + _listView.InsertColumn(1, &columnInfo); + } + + + UString s; + + FOR_VECTOR (i, Strings) + { + _listView.InsertItem(i, Strings[i]); + + if (NumColumns > 1 && i < Values.Size()) + { + s = Values[i]; + if (s.Len() > kOneStringMaxSize) + { + s.DeleteFrom(kOneStringMaxSize); + s += " ..."; + } + s.Replace(L"\r\n", L" "); + s.Replace(L"\n", L" "); + _listView.SetSubItem(i, 1, s); + } + } + + if (SelectFirst && Strings.Size() > 0) + _listView.SetItemState_FocusedSelected(0); + + _listView.SetColumnWidthAuto(0); + if (NumColumns > 1) + _listView.SetColumnWidthAuto(1); + StringsWereChanged = false; + + NormalizeSize(); + return CModalDialog::OnInit(); +} + +bool CListViewDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDOK, bx2, by); + int y = ySize - my - by; + int x = xSize - mx - bx1; + + /* + RECT rect; + GetClientRect(&rect); + rect.top = y - my; + InvalidateRect(&rect); + */ + InvalidateRect(NULL); + + MoveItem(IDCANCEL, x, y, bx1, by); + MoveItem(IDOK, x - mx - bx2, y, bx2, by); + /* + if (wParam == SIZE_MAXSHOW || wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXHIDE) + mx = 0; + */ + _listView.Move(mx, my, xSize - mx * 2, y - my * 2); + return false; +} + + +extern bool g_LVN_ITEMACTIVATE_Support; + +void CListViewDialog::CopyToClipboard() +{ + CUIntVector indexes; + ListView_GetSelected(_listView, indexes); + UString s; + + FOR_VECTOR (i, indexes) + { + unsigned index = indexes[i]; + s += Strings[index]; + if (NumColumns > 1 && index < Values.Size()) + { + const UString &v = Values[index]; + // if (!v.IsEmpty()) + { + s += ": "; + s += v; + } + } + // if (indexes.Size() > 1) + { + s += + #ifdef _WIN32 + "\r\n" + #else + "\n" + #endif + ; + } + } + + ClipboardSetText(*this, s); +} + + +void CListViewDialog::ShowItemInfo() +{ + CUIntVector indexes; + ListView_GetSelected(_listView, indexes); + if (indexes.Size() != 1) + return; + unsigned index = indexes[0]; + + CEditDialog dlg; + if (NumColumns == 1) + dlg.Text = Strings[index]; + else + { + dlg.Title = Strings[index]; + if (index < Values.Size()) + dlg.Text = Values[index]; + } + + #ifdef _WIN32 + if (dlg.Text.Find(L'\r') < 0) + dlg.Text.Replace(L"\n", L"\r\n"); + #endif + + dlg.Create(*this); +} + + +void CListViewDialog::DeleteItems() +{ + for (;;) + { + const int index = _listView.GetNextSelectedItem(-1); + if (index < 0) + break; + StringsWereChanged = true; + _listView.DeleteItem((unsigned)index); + if ((unsigned)index < Strings.Size()) + Strings.Delete((unsigned)index); + if ((unsigned)index < Values.Size()) + Values.Delete((unsigned)index); + } + const int focusedIndex = _listView.GetFocusedItem(); + if (focusedIndex >= 0) + _listView.SetItemState_FocusedSelected(focusedIndex); + _listView.SetColumnWidthAuto(0); +} + + +void CListViewDialog::OnEnter() +{ + if (IsKeyDown(VK_MENU) + || NumColumns > 1) + { + ShowItemInfo(); + return; + } + OnOK(); +} + +bool CListViewDialog::OnNotify(UINT /* controlID */, LPNMHDR header) +{ + if (header->hwndFrom != _listView) + return false; + switch (header->code) + { + case LVN_ITEMACTIVATE: + if (g_LVN_ITEMACTIVATE_Support) + { + OnEnter(); + return true; + } + break; + case NM_DBLCLK: + case NM_RETURN: // probabably it's unused + if (!g_LVN_ITEMACTIVATE_Support) + { + OnEnter(); + return true; + } + break; + + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); + switch (keyDownInfo->wVKey) + { + case VK_DELETE: + { + if (!DeleteIsAllowed) + return false; + DeleteItems(); + return true; + } + case 'A': + { + if (IsKeyDown(VK_CONTROL)) + { + _listView.SelectAll(); + return true; + } + break; + } + case VK_INSERT: + case 'C': + { + if (IsKeyDown(VK_CONTROL)) + { + CopyToClipboard(); + return true; + } + break; + } + } + } + } + return false; +} + +void CListViewDialog::OnOK() +{ + FocusedItemIndex = _listView.GetFocusedItem(); + CModalDialog::OnOK(); +} diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.h b/CPP/7zip/UI/FileManager/ListViewDialog.h index 1f8fdcca2..5f0b66de3 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.h +++ b/CPP/7zip/UI/FileManager/ListViewDialog.h @@ -1,46 +1,46 @@ -// ListViewDialog.h - -#ifndef ZIP7_INC_LISTVIEW_DIALOG_H -#define ZIP7_INC_LISTVIEW_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/ListView.h" - -#include "ListViewDialogRes.h" - -class CListViewDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CListView _listView; - virtual void OnOK() Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; - void CopyToClipboard(); - void DeleteItems(); - void ShowItemInfo(); - void OnEnter(); -public: - UString Title; - - bool SelectFirst; - bool DeleteIsAllowed; - bool StringsWereChanged; - - UStringVector Strings; - UStringVector Values; - - int FocusedItemIndex; - unsigned NumColumns; - - INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_LISTVIEW, wndParent); } - - CListViewDialog(): - SelectFirst(false), - DeleteIsAllowed(false), - StringsWereChanged(false), - FocusedItemIndex(-1), - NumColumns(1) - {} -}; - -#endif +// ListViewDialog.h + +#ifndef ZIP7_INC_LISTVIEW_DIALOG_H +#define ZIP7_INC_LISTVIEW_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/ListView.h" + +#include "ListViewDialogRes.h" + +class CListViewDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CListView _listView; + virtual void OnOK() Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override; + void CopyToClipboard(); + void DeleteItems(); + void ShowItemInfo(); + void OnEnter(); +public: + UString Title; + + bool SelectFirst; + bool DeleteIsAllowed; + bool StringsWereChanged; + + UStringVector Strings; + UStringVector Values; + + int FocusedItemIndex; + unsigned NumColumns; + + INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_LISTVIEW, wndParent); } + + CListViewDialog(): + SelectFirst(false), + DeleteIsAllowed(false), + StringsWereChanged(false), + FocusedItemIndex(-1), + NumColumns(1) + {} +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.rc b/CPP/7zip/UI/FileManager/ListViewDialog.rc index 71ee4bb2f..4343b7558 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialog.rc +++ b/CPP/7zip/UI/FileManager/ListViewDialog.rc @@ -1,14 +1,14 @@ -#include "ListViewDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 480 -#define yc 320 - -IDD_LISTVIEW DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "ListView" -{ - CONTROL "List1", IDL_LISTVIEW, "SysListView32", LVS_REPORT | LVS_SHOWSELALWAYS | - LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP, - m, m, xc, yc - bys - m - OK_CANCEL -} +#include "ListViewDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 480 +#define yc 320 + +IDD_LISTVIEW DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "ListView" +{ + CONTROL "List1", IDL_LISTVIEW, "SysListView32", LVS_REPORT | LVS_SHOWSELALWAYS | + LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP, + m, m, xc, yc - bys - m + OK_CANCEL +} diff --git a/CPP/7zip/UI/FileManager/ListViewDialogRes.h b/CPP/7zip/UI/FileManager/ListViewDialogRes.h index 1143be8cb..9abdb9d2e 100644 --- a/CPP/7zip/UI/FileManager/ListViewDialogRes.h +++ b/CPP/7zip/UI/FileManager/ListViewDialogRes.h @@ -1,2 +1,2 @@ -#define IDD_LISTVIEW 99 -#define IDL_LISTVIEW 100 +#define IDD_LISTVIEW 99 +#define IDL_LISTVIEW 100 diff --git a/CPP/7zip/UI/FileManager/MemDialog.cpp b/CPP/7zip/UI/FileManager/MemDialog.cpp index aea21f908..5d26d3a10 100644 --- a/CPP/7zip/UI/FileManager/MemDialog.cpp +++ b/CPP/7zip/UI/FileManager/MemDialog.cpp @@ -1,218 +1,218 @@ -// MemDialog.cpp - -#include "StdAfx.h" - -#include - -#include "MemDialog.h" - -#include "../../../Common/StringToInt.h" -#include "../../../Windows/System.h" -#include "../../../Windows/ErrorMsg.h" - -#include "../Explorer/MyMessages.h" -#include "../GUI/ExtractRes.h" - -#include "resourceGui.h" - -#ifdef Z7_LANG -#include "LangUtils.h" -#endif - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDX_MEM_SAVE_LIMIT, - IDX_MEM_REMEMBER, - IDG_MEM_ACTION, - IDR_MEM_ACTION_ALLOW, - IDR_MEM_ACTION_SKIP_ARC - // , IDR_MEM_SKIP_FILE -}; -#endif - -static const unsigned k_Action_Buttons[] = -{ - IDR_MEM_ACTION_ALLOW, - IDR_MEM_ACTION_SKIP_ARC - // , IDR_MEM_SKIP_FILE -}; - - -void CMemDialog::EnableSpin(bool enable) -{ - EnableItem(IDC_MEM_SPIN, enable); - EnableItem(IDE_MEM_SPIN_EDIT, enable); -} - - -static void AddSize_GB(UString &s, UInt32 size_GB, UInt32 id) -{ - s.Add_LF(); - s += " "; - s.Add_UInt32(size_GB); - s += " GB : "; - AddLangString(s, id); -} - -void CMemDialog::AddInfoMessage_To_String(UString &s, UInt64 *ramSize_GB) -{ - AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM); - AddSize_GB(s, Required_GB, IDS_MEM_REQUIRED_MEM_SIZE); - AddSize_GB(s, Limit_GB, IDS_MEM_CURRENT_MEM_LIMIT); - if (ramSize_GB) - AddSize_GB(s, (UInt32)*ramSize_GB, IDS_MEM_RAM_SIZE); - if (!FilePath.IsEmpty()) - { - s.Add_LF(); - s += "File: "; - s += FilePath; - } -} - -/* -int CMemDialog::AddAction(UINT id) -{ - const int index = (int)m_Action.AddString(LangString(id)); - m_Action.SetItemData(index, (LPARAM)id); - return index; -} -*/ - -bool CMemDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_MEM); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - - // m_Action.Attach(GetItem(IDC_MEM_ACTION)); - - UInt64 ramSize = (UInt64)sizeof(size_t) << 29; - const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize); - // ramSize *= 10; // for debug - - UInt64 ramSize_GB = (ramSize + (1u << 29)) >> 30; - if (ramSize_GB == 0) - ramSize_GB = 1; - - const bool is_Allowed = (!ramSize_defined || ramSize > ((UInt64)Required_GB << 30)); - { - UString s; - if (!is_Allowed) - { - AddLangString(s, IDS_MEM_ERROR); - s.Add_LF(); - } - AddInfoMessage_To_String(s, is_Allowed ? NULL : &ramSize_GB); - if (!ArcPath.IsEmpty()) - // for (int i = 0; i < 10; i++) - { - s.Add_LF(); - AddLangString(s, TestMode ? - IDS_PROGRESS_TESTING : - IDS_PROGRESS_EXTRACTING); - s += ": "; - s += ArcPath; - } - SetItemText(IDT_MEM_MESSAGE, s); - - s = "GB"; - if (ramSize_defined) - { - s += " / "; - s.Add_UInt64(ramSize_GB); - s += " GB (RAM)"; - } - SetItemText(IDT_MEM_GB, s); - } - const UINT valMin = 1; - UINT valMax = 64; // 64GB for RAR7 - if (ramSize_defined /* && ramSize_GB > valMax */) - { - const UINT k_max_val = 1u << 14; - if (ramSize_GB >= k_max_val) - valMax = k_max_val; - else if (ramSize_GB > 1) - valMax = (UINT)ramSize_GB - 1; - else - valMax = 1; - } - - SendItemMessage(IDC_MEM_SPIN, UDM_SETRANGE, 0, MAKELPARAM(valMax, valMin)); // Sets the controls direction - // UDM_SETPOS doesn't set value larger than max value (valMax) of range: - SendItemMessage(IDC_MEM_SPIN, UDM_SETPOS, 0, Required_GB); - { - UString s; - s.Add_UInt32(Required_GB); - SetItemText(IDE_MEM_SPIN_EDIT, s); - } - - EnableSpin(false); - - /* - AddAction(IDB_ALLOW_OPERATION); - m_Action.SetCurSel(0); - AddAction(IDB_MEM_SKIP_ARC); - AddAction(IDB_MEM_SKIP_FILE); - */ - - const UINT buttonId = is_Allowed ? - IDR_MEM_ACTION_ALLOW : - IDR_MEM_ACTION_SKIP_ARC; - - CheckRadioButton( - k_Action_Buttons[0], - k_Action_Buttons[Z7_ARRAY_SIZE(k_Action_Buttons) - 1], - buttonId); - /* - if (!ShowSkipFile) - HideItem(IDR_MEM_SKIP_FILE); - */ - if (!ShowRemember) - HideItem(IDX_MEM_REMEMBER); - return CModalDialog::OnInit(); -} - - -bool CMemDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - if (buttonID == IDX_MEM_SAVE_LIMIT) - { - EnableSpin(IsButtonCheckedBool(IDX_MEM_SAVE_LIMIT)); - return true; - } - return CDialog::OnButtonClicked(buttonID, buttonHWND); -} - - -void CMemDialog::OnContinue() -{ - Remember = IsButtonCheckedBool(IDX_MEM_REMEMBER); - NeedSave = IsButtonCheckedBool(IDX_MEM_SAVE_LIMIT); - SkipArc = IsButtonCheckedBool(IDR_MEM_ACTION_SKIP_ARC); - if (NeedSave) - { -#if 0 - // UDM_GETPOS doesn't support value outside of range that was set: - LRESULT lresult = SendItemMessage(IDC_MEM_SPIN, UDM_GETPOS, 0, 0); - const UInt32 val = LOWORD(lresult); - if (HIWORD(lresult) != 0) // the value outside of allowed range -#else - UString s; - GetItemText(IDE_MEM_SPIN_EDIT, s); - const wchar_t *end; - const UInt32 val = ConvertStringToUInt32(s.Ptr(), &end); - if (s.IsEmpty() || *end != 0 || val > (1u << 30)) -#endif - { - ShowErrorMessage(*this, - NWindows::NError::MyFormatMessage(E_INVALIDARG) - // L"Incorrect value" - ); - return; - } - Limit_GB = val; - } - CModalDialog::OnContinue(); -} +// MemDialog.cpp + +#include "StdAfx.h" + +#include + +#include "MemDialog.h" + +#include "../../../Common/StringToInt.h" +#include "../../../Windows/System.h" +#include "../../../Windows/ErrorMsg.h" + +#include "../Explorer/MyMessages.h" +#include "../GUI/ExtractRes.h" + +#include "resourceGui.h" + +#ifdef Z7_LANG +#include "LangUtils.h" +#endif + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDX_MEM_SAVE_LIMIT, + IDX_MEM_REMEMBER, + IDG_MEM_ACTION, + IDR_MEM_ACTION_ALLOW, + IDR_MEM_ACTION_SKIP_ARC + // , IDR_MEM_SKIP_FILE +}; +#endif + +static const unsigned k_Action_Buttons[] = +{ + IDR_MEM_ACTION_ALLOW, + IDR_MEM_ACTION_SKIP_ARC + // , IDR_MEM_SKIP_FILE +}; + + +void CMemDialog::EnableSpin(bool enable) +{ + EnableItem(IDC_MEM_SPIN, enable); + EnableItem(IDE_MEM_SPIN_EDIT, enable); +} + + +static void AddSize_GB(UString &s, UInt32 size_GB, UInt32 id) +{ + s.Add_LF(); + s += " "; + s.Add_UInt32(size_GB); + s += " GB : "; + AddLangString(s, id); +} + +void CMemDialog::AddInfoMessage_To_String(UString &s, const UInt32 *ramSize_GB) +{ + AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM); + AddSize_GB(s, Required_GB, IDS_MEM_REQUIRED_MEM_SIZE); + AddSize_GB(s, Limit_GB, IDS_MEM_CURRENT_MEM_LIMIT); + if (ramSize_GB) + AddSize_GB(s, *ramSize_GB, IDS_MEM_RAM_SIZE); + if (!FilePath.IsEmpty()) + { + s.Add_LF(); + s += "File: "; + s += FilePath; + } +} + +/* +int CMemDialog::AddAction(UINT id) +{ + const int index = (int)m_Action.AddString(LangString(id)); + m_Action.SetItemData(index, (LPARAM)id); + return index; +} +*/ + +bool CMemDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_MEM); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + + // m_Action.Attach(GetItem(IDC_MEM_ACTION)); + + size_t ramSize = (size_t)sizeof(size_t) << 29; + const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize); + // ramSize *= 10; // for debug + + UInt32 ramSize_GB = (UInt32)(((UInt64)ramSize + (1u << 29)) >> 30); + if (ramSize_GB == 0) + ramSize_GB = 1; + + const bool is_Allowed = (!ramSize_defined || ramSize > ((UInt64)Required_GB << 30)); + { + UString s; + if (!is_Allowed) + { + AddLangString(s, IDS_MEM_ERROR); + s.Add_LF(); + } + AddInfoMessage_To_String(s, is_Allowed ? NULL : &ramSize_GB); + if (!ArcPath.IsEmpty()) + // for (int i = 0; i < 10; i++) + { + s.Add_LF(); + AddLangString(s, TestMode ? + IDS_PROGRESS_TESTING : + IDS_PROGRESS_EXTRACTING); + s += ": "; + s += ArcPath; + } + SetItemText(IDT_MEM_MESSAGE, s); + + s = "GB"; + if (ramSize_defined) + { + s += " / "; + s.Add_UInt32(ramSize_GB); + s += " GB (RAM)"; + } + SetItemText(IDT_MEM_GB, s); + } + const UINT valMin = 1; + UINT valMax = 64; // 64GB for RAR7 + if (ramSize_defined /* && ramSize_GB > valMax */) + { + const UINT k_max_val = 1u << 14; + if (ramSize_GB >= k_max_val) + valMax = k_max_val; + else if (ramSize_GB > 1) + valMax = (UINT)ramSize_GB - 1; + else + valMax = 1; + } + + SendItemMessage(IDC_MEM_SPIN, UDM_SETRANGE, 0, MAKELPARAM(valMax, valMin)); // Sets the controls direction + // UDM_SETPOS doesn't set value larger than max value (valMax) of range: + SendItemMessage(IDC_MEM_SPIN, UDM_SETPOS, 0, Required_GB); + { + UString s; + s.Add_UInt32(Required_GB); + SetItemText(IDE_MEM_SPIN_EDIT, s); + } + + EnableSpin(false); + + /* + AddAction(IDB_ALLOW_OPERATION); + m_Action.SetCurSel(0); + AddAction(IDB_MEM_SKIP_ARC); + AddAction(IDB_MEM_SKIP_FILE); + */ + + const UINT buttonId = is_Allowed ? + IDR_MEM_ACTION_ALLOW : + IDR_MEM_ACTION_SKIP_ARC; + + CheckRadioButton( + k_Action_Buttons[0], + k_Action_Buttons[Z7_ARRAY_SIZE(k_Action_Buttons) - 1], + buttonId); + /* + if (!ShowSkipFile) + HideItem(IDR_MEM_SKIP_FILE); + */ + if (!ShowRemember) + HideItem(IDX_MEM_REMEMBER); + return CModalDialog::OnInit(); +} + + +bool CMemDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + if (buttonID == IDX_MEM_SAVE_LIMIT) + { + EnableSpin(IsButtonCheckedBool(IDX_MEM_SAVE_LIMIT)); + return true; + } + return CDialog::OnButtonClicked(buttonID, buttonHWND); +} + + +void CMemDialog::OnContinue() +{ + Remember = IsButtonCheckedBool(IDX_MEM_REMEMBER); + NeedSave = IsButtonCheckedBool(IDX_MEM_SAVE_LIMIT); + SkipArc = IsButtonCheckedBool(IDR_MEM_ACTION_SKIP_ARC); + if (NeedSave) + { +#if 0 + // UDM_GETPOS doesn't support value outside of range that was set: + LRESULT lresult = SendItemMessage(IDC_MEM_SPIN, UDM_GETPOS, 0, 0); + const UInt32 val = LOWORD(lresult); + if (HIWORD(lresult) != 0) // the value outside of allowed range +#else + UString s; + GetItemText(IDE_MEM_SPIN_EDIT, s); + const wchar_t *end; + const UInt32 val = ConvertStringToUInt32(s.Ptr(), &end); + if (s.IsEmpty() || *end != 0 || val > (1u << 30)) +#endif + { + ShowErrorMessage(*this, + NWindows::NError::MyFormatMessage(E_INVALIDARG) + // L"Incorrect value" + ); + return; + } + Limit_GB = val; + } + CModalDialog::OnContinue(); +} diff --git a/CPP/7zip/UI/FileManager/MemDialog.h b/CPP/7zip/UI/FileManager/MemDialog.h index 63ff499a2..67f6b3347 100644 --- a/CPP/7zip/UI/FileManager/MemDialog.h +++ b/CPP/7zip/UI/FileManager/MemDialog.h @@ -1,48 +1,48 @@ -// MemDialog.h - -#ifndef ZIP7_INC_MEM_DIALOG_H -#define ZIP7_INC_MEM_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -// #include "../../../Windows/Control/ComboBox.h" - -#include "MemDialogRes.h" - -class CMemDialog: public NWindows::NControl::CModalDialog -{ - // NWindows::NControl::CComboBox m_Action; - // we can disable default OnOK() when we press Enter - // virtual void OnOK() Z7_override { } - virtual void OnContinue() Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - void EnableSpin(bool enable); - // int AddAction(UINT id); -public: - bool NeedSave; - bool Remember; - bool SkipArc; - bool TestMode; - bool ShowRemember; - // bool ShowSkipFile; - UInt32 Required_GB; - UInt32 Limit_GB; - UString ArcPath; - UString FilePath; - - void AddInfoMessage_To_String(UString &s, UInt64 *ramSize_GB = NULL); - - CMemDialog(): - NeedSave(false), - Remember(false), - SkipArc(false), - TestMode(false), - ShowRemember(true), - // ShowSkipFile(true), - Required_GB(4), - Limit_GB(4) - {} - INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_MEM, parentWindow); } -}; - -#endif +// MemDialog.h + +#ifndef ZIP7_INC_MEM_DIALOG_H +#define ZIP7_INC_MEM_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +// #include "../../../Windows/Control/ComboBox.h" + +#include "MemDialogRes.h" + +class CMemDialog: public NWindows::NControl::CModalDialog +{ + // NWindows::NControl::CComboBox m_Action; + // we can disable default OnOK() when we press Enter + // virtual void OnOK() Z7_override { } + virtual void OnContinue() Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + void EnableSpin(bool enable); + // int AddAction(UINT id); +public: + bool NeedSave; + bool Remember; + bool SkipArc; + bool TestMode; + bool ShowRemember; + // bool ShowSkipFile; + UInt32 Required_GB; + UInt32 Limit_GB; + UString ArcPath; + UString FilePath; + + void AddInfoMessage_To_String(UString &s, const UInt32 *ramSize_GB = NULL); + + CMemDialog(): + NeedSave(false), + Remember(false), + SkipArc(false), + TestMode(false), + ShowRemember(true), + // ShowSkipFile(true), + Required_GB(4), + Limit_GB(4) + {} + INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_MEM, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/MemDialog.rc b/CPP/7zip/UI/FileManager/MemDialog.rc index 7898071b1..d8bcb5448 100644 --- a/CPP/7zip/UI/FileManager/MemDialog.rc +++ b/CPP/7zip/UI/FileManager/MemDialog.rc @@ -1,49 +1,49 @@ -#include "MemDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 320 -#define yc 200 - -#define spin_x_size 50 -#define info_y_size 72 -#define save_y (m + info_y_size + 4) -#define spin_y (save_y + 16) - -#define xsg (xc - m - m) -#define xg (m + m) -#define yg (spin_y + 20) - -IDD_MEM DIALOG MY_MODAL_DIALOG_POSTFIX -CAPTION "Memory usage request" -BEGIN - LTEXT "", IDT_MEM_MESSAGE, m, m, xc, info_y_size, SS_NOPREFIX - CONTROL "Change allowed limit for next operations", IDX_MEM_SAVE_LIMIT, MY_CHECKBOX, - m, save_y, xc, 10 - - MY_CONTROL_EDIT_WITH_SPIN( - IDE_MEM_SPIN_EDIT, - IDC_MEM_SPIN, - "4", m + 10, spin_y, spin_x_size) - - LTEXT "GB", IDT_MEM_GB, m + 10 + spin_x_size + 8, spin_y + 2, 160, 10 - - GROUPBOX "Action", IDG_MEM_ACTION, m, yg, xc, 62 - - MY_CONTROL_AUTORADIOBUTTON_GROUP ( - "&Allow archive unpacking", IDR_MEM_ACTION_ALLOW, - xg, yg + 14, xsg) - MY_CONTROL_AUTORADIOBUTTON ( - "&Skip archive unpacking", IDR_MEM_ACTION_SKIP_ARC, - xg, yg + 28, xsg) -// CONTROL "&Skip file extracting", IDR_MEM_SKIP_FILE, MY_AUTORADIOBUTTON, -// xg, yg + 42, xsg, 10 - - CONTROL "&Repeat selected action for current operation", IDX_MEM_REMEMBER, MY_CHECKBOX, - xg + 10, yg + 44, xsg - 10, 10 - - CONTINUE_CANCEL -END - -#undef save_y -#undef spin_y -#undef spin_x_size +#include "MemDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 320 +#define yc 200 + +#define spin_x_size 50 +#define info_y_size 72 +#define save_y (m + info_y_size + 4) +#define spin_y (save_y + 16) + +#define xsg (xc - m - m) +#define xg (m + m) +#define yg (spin_y + 20) + +IDD_MEM DIALOG MY_MODAL_DIALOG_POSTFIX +CAPTION "Memory usage request" +BEGIN + LTEXT "", IDT_MEM_MESSAGE, m, m, xc, info_y_size, SS_NOPREFIX + CONTROL "Change allowed limit for next operations", IDX_MEM_SAVE_LIMIT, MY_CHECKBOX, + m, save_y, xc, 10 + + MY_CONTROL_EDIT_WITH_SPIN( + IDE_MEM_SPIN_EDIT, + IDC_MEM_SPIN, + "4", m + 10, spin_y, spin_x_size) + + LTEXT "GB", IDT_MEM_GB, m + 10 + spin_x_size + 8, spin_y + 2, 160, 10 + + GROUPBOX "Action", IDG_MEM_ACTION, m, yg, xc, 62 + + MY_CONTROL_AUTORADIOBUTTON_GROUP ( + "&Allow archive unpacking", IDR_MEM_ACTION_ALLOW, + xg, yg + 14, xsg) + MY_CONTROL_AUTORADIOBUTTON ( + "&Skip archive unpacking", IDR_MEM_ACTION_SKIP_ARC, + xg, yg + 28, xsg) +// CONTROL "&Skip file extracting", IDR_MEM_SKIP_FILE, MY_AUTORADIOBUTTON, +// xg, yg + 42, xsg, 10 + + CONTROL "&Repeat selected action for current operation", IDX_MEM_REMEMBER, MY_CHECKBOX, + xg + 10, yg + 44, xsg - 10, 10 + + CONTINUE_CANCEL +END + +#undef save_y +#undef spin_y +#undef spin_x_size diff --git a/CPP/7zip/UI/FileManager/MemDialogRes.h b/CPP/7zip/UI/FileManager/MemDialogRes.h index fccb4d6f6..9ece82d3d 100644 --- a/CPP/7zip/UI/FileManager/MemDialogRes.h +++ b/CPP/7zip/UI/FileManager/MemDialogRes.h @@ -1,13 +1,13 @@ -#define IDD_MEM 7800 - -#define IDX_MEM_SAVE_LIMIT 7801 -#define IDX_MEM_REMEMBER 7802 -#define IDG_MEM_ACTION 7803 - -#define IDR_MEM_ACTION_ALLOW 7820 -#define IDR_MEM_ACTION_SKIP_ARC 7821 - -#define IDT_MEM_MESSAGE 101 -#define IDE_MEM_SPIN_EDIT 110 -#define IDC_MEM_SPIN 111 -#define IDT_MEM_GB 112 +#define IDD_MEM 7800 + +#define IDX_MEM_SAVE_LIMIT 7801 +#define IDX_MEM_REMEMBER 7802 +#define IDG_MEM_ACTION 7803 + +#define IDR_MEM_ACTION_ALLOW 7820 +#define IDR_MEM_ACTION_SKIP_ARC 7821 + +#define IDT_MEM_MESSAGE 101 +#define IDE_MEM_SPIN_EDIT 110 +#define IDC_MEM_SPIN 111 +#define IDT_MEM_GB 112 diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp index 3473607c9..e8736b844 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.cpp +++ b/CPP/7zip/UI/FileManager/MenuPage.cpp @@ -1,440 +1,440 @@ -// MenuPage.cpp - -#include "StdAfx.h" - -#include "../Common/ZipRegistry.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileFind.h" - -#include "../Explorer/ContextMenuFlags.h" -#include "../Explorer/RegistryContextMenu.h" -#include "../Explorer/resource.h" - -#include "../FileManager/PropertyNameRes.h" - -#include "../GUI/ExtractDialogRes.h" - -#include "FormatUtils.h" -#include "HelpUtils.h" -#include "LangUtils.h" -#include "MenuPage.h" -#include "MenuPageRes.h" - - -using namespace NWindows; -using namespace NContextMenuFlags; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDX_SYSTEM_INTEGRATE_TO_MENU, - IDX_SYSTEM_CASCADED_MENU, - IDX_SYSTEM_ICON_IN_MENU, - IDX_EXTRACT_ELIM_DUP, - IDT_SYSTEM_ZONE, - IDT_SYSTEM_CONTEXT_MENU_ITEMS -}; -#endif - -#define kMenuTopic "fm/options.htm#sevenZip" - -struct CContextMenuItem -{ - unsigned ControlID; - UInt32 Flag; -}; - -static const CContextMenuItem kMenuItems[] = -{ - { IDS_CONTEXT_OPEN, kOpen }, - { IDS_CONTEXT_OPEN, kOpenAs }, - { IDS_CONTEXT_EXTRACT, kExtract }, - { IDS_CONTEXT_EXTRACT_HERE, kExtractHere }, - { IDS_CONTEXT_EXTRACT_TO, kExtractTo }, - - { IDS_CONTEXT_TEST, kTest }, - - { IDS_CONTEXT_COMPRESS, kCompress }, - { IDS_CONTEXT_COMPRESS_TO, kCompressTo7z }, - { IDS_CONTEXT_COMPRESS_TO, kCompressToZip }, - - #ifndef UNDER_CE - { IDS_CONTEXT_COMPRESS_EMAIL, kCompressEmail }, - { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressTo7zEmail }, - { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressToZipEmail }, - #endif - - { IDS_PROP_CHECKSUM, kCRC }, - { IDS_PROP_CHECKSUM, kCRC_Cascaded }, -}; - - -#if !defined(_WIN64) -extern bool g_Is_Wow64; -#endif - -#ifndef KEY_WOW64_64KEY - #define KEY_WOW64_64KEY (0x0100) -#endif - -#ifndef KEY_WOW64_32KEY - #define KEY_WOW64_32KEY (0x0200) -#endif - - -static void LoadLang_Spec(UString &s, UInt32 id, const char *eng) -{ - LangString(id, s); - if (s.IsEmpty()) - s = eng; - s.RemoveChar(L'&'); -} - - -bool CMenuPage::OnInit() -{ - _initMode = true; - - Clear_MenuChanged(); - -#ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); -#endif - - #ifdef UNDER_CE - - HideItem(IDX_SYSTEM_INTEGRATE_TO_MENU); - HideItem(IDX_SYSTEM_INTEGRATE_TO_MENU_2); - - #else - - { - UString s; - { - CWindow window(GetItem(IDX_SYSTEM_INTEGRATE_TO_MENU)); - window.GetText(s); - } - UString bit64 = LangString(IDS_PROP_BIT64); - if (bit64.IsEmpty()) - bit64 = "64-bit"; - #ifdef _WIN64 - bit64.Replace(L"64", L"32"); - #endif - s.Add_Space(); - s.Add_Char('('); - s += bit64; - s.Add_Char(')'); - SetItemText(IDX_SYSTEM_INTEGRATE_TO_MENU_2, s); - } - - const FString prefix = NDLL::GetModuleDirPrefix(); - - _dlls[0].ctrl = IDX_SYSTEM_INTEGRATE_TO_MENU; - _dlls[1].ctrl = IDX_SYSTEM_INTEGRATE_TO_MENU_2; - - _dlls[0].wow = 0; - _dlls[1].wow = - #ifdef _WIN64 - KEY_WOW64_32KEY - #else - KEY_WOW64_64KEY - #endif - ; - - for (unsigned d = 0; d < 2; d++) - { - CShellDll &dll = _dlls[d]; - - dll.wasChanged = false; - - #ifndef _WIN64 - if (d != 0 && !g_Is_Wow64) - { - HideItem(dll.ctrl); - continue; - } - #endif - - FString &path = dll.Path; - path = prefix; - path += (d == 0 ? "7-zip.dll" : - #ifdef _WIN64 - "7-zip32.dll" - #else - "7-zip64.dll" - #endif - ); - - - if (!NFile::NFind::DoesFileExist_Raw(path)) - { - path.Empty(); - EnableItem(dll.ctrl, false); - } - else - { - dll.prevValue = CheckContextMenuHandler(fs2us(path), dll.wow); - CheckButton(dll.ctrl, dll.prevValue); - } - } - - #endif - - - CContextMenuInfo ci; - ci.Load(); - - CheckButton(IDX_SYSTEM_CASCADED_MENU, ci.Cascaded.Val); - CheckButton(IDX_SYSTEM_ICON_IN_MENU, ci.MenuIcons.Val); - CheckButton(IDX_EXTRACT_ELIM_DUP, ci.ElimDup.Val); - - _listView.Attach(GetItem(IDL_SYSTEM_OPTIONS)); - _zoneCombo.Attach(GetItem(IDC_SYSTEM_ZONE)); - - { - unsigned wz = ci.WriteZone; - if (wz == (UInt32)(Int32)-1) - wz = 0; - for (unsigned i = 0; i <= 3; i++) - { - unsigned val = i; - UString s; - if (i == 3) - { - if (wz < 3) - break; - val = wz; - } - else - { - #define MY_IDYES 406 - #define MY_IDNO 407 - if (i == 0) - LoadLang_Spec(s, MY_IDNO, "No"); - else if (i == 1) - LoadLang_Spec(s, MY_IDYES, "Yes"); - else - LangString(IDT_ZONE_FOR_OFFICE, s); - } - if (s.IsEmpty()) - s.Add_UInt32(val); - if (i == 0) - s.Insert(0, L"* "); - const int index = (int)_zoneCombo.AddString(s); - _zoneCombo.SetItemData(index, (LPARAM)val); - if (val == wz) - _zoneCombo.SetCurSel(index); - } - } - - - const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT; - _listView.SetExtendedListViewStyle(newFlags, newFlags); - - _listView.InsertColumn(0, L"", 200); - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kMenuItems); i++) - { - const CContextMenuItem &menuItem = kMenuItems[i]; - - UString s = LangString(menuItem.ControlID); - if (menuItem.Flag == kCRC) - s = "CRC SHA"; - else if (menuItem.Flag == kCRC_Cascaded) - s = "7-Zip > CRC SHA"; - if (menuItem.Flag == kOpenAs - || menuItem.Flag == kCRC - || menuItem.Flag == kCRC_Cascaded) - s += " >"; - - switch (menuItem.ControlID) - { - case IDS_CONTEXT_EXTRACT_TO: - { - s = MyFormatNew(s, LangString(IDS_CONTEXT_FOLDER)); - break; - } - case IDS_CONTEXT_COMPRESS_TO: - case IDS_CONTEXT_COMPRESS_TO_EMAIL: - { - UString s2 = LangString(IDS_CONTEXT_ARCHIVE); - switch (menuItem.Flag) - { - case kCompressTo7z: - case kCompressTo7zEmail: - s2 += (".7z"); - break; - case kCompressToZip: - case kCompressToZipEmail: - s2 += (".zip"); - break; - } - s = MyFormatNew(s, s2); - break; - } - } - - const int itemIndex = _listView.InsertItem(i, s); - _listView.SetCheckState((unsigned)itemIndex, ((ci.Flags & menuItem.Flag) != 0)); - } - - _listView.SetColumnWidthAuto(0); - _initMode = false; - - return CPropertyPage::OnInit(); -} - - -#ifndef UNDER_CE - -static void ShowMenuErrorMessage(const wchar_t *m, HWND hwnd) -{ - MessageBoxW(hwnd, m, L"7-Zip", MB_ICONERROR); -} - -#endif - - -LONG CMenuPage::OnApply() -{ - #ifndef UNDER_CE - - for (unsigned d = 2; d != 0;) - { - d--; - CShellDll &dll = _dlls[d]; - if (dll.wasChanged && !dll.Path.IsEmpty()) - { - const bool newVal = IsButtonCheckedBool(dll.ctrl); - const LONG res = SetContextMenuHandler(newVal, fs2us(dll.Path), dll.wow); - if (res != ERROR_SUCCESS && (dll.prevValue != newVal || newVal)) - ShowMenuErrorMessage(NError::MyFormatMessage(res), *this); - dll.prevValue = CheckContextMenuHandler(fs2us(dll.Path), dll.wow); - CheckButton(dll.ctrl, dll.prevValue); - dll.wasChanged = false; - } - } - - #endif - - if (_cascaded_Changed - || _menuIcons_Changed - || _elimDup_Changed - || _writeZone_Changed - || _flags_Changed) - { - CContextMenuInfo ci; - ci.Cascaded.Val = IsButtonCheckedBool(IDX_SYSTEM_CASCADED_MENU); - ci.Cascaded.Def = _cascaded_Changed; - - ci.MenuIcons.Val = IsButtonCheckedBool(IDX_SYSTEM_ICON_IN_MENU); - ci.MenuIcons.Def = _menuIcons_Changed; - - ci.ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP); - ci.ElimDup.Def = _elimDup_Changed; - - { - int zoneIndex = (int)_zoneCombo.GetItemData_of_CurSel(); - if (zoneIndex <= 0) - zoneIndex = -1; - ci.WriteZone = (UInt32)(Int32)zoneIndex; - } - - ci.Flags = 0; - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kMenuItems); i++) - if (_listView.GetCheckState(i)) - ci.Flags |= kMenuItems[i].Flag; - - ci.Flags_Def = _flags_Changed; - ci.Save(); - - Clear_MenuChanged(); - } - - // UnChanged(); - - return PSNRET_NOERROR; -} - -void CMenuPage::OnNotifyHelp() -{ - ShowHelpWindow(kMenuTopic); -} - -bool CMenuPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - #ifndef UNDER_CE - case IDX_SYSTEM_INTEGRATE_TO_MENU: - case IDX_SYSTEM_INTEGRATE_TO_MENU_2: - { - for (unsigned d = 0; d < 2; d++) - { - CShellDll &dll = _dlls[d]; - if (buttonID == dll.ctrl && !dll.Path.IsEmpty()) - dll.wasChanged = true; - } - break; - } - #endif - - case IDX_SYSTEM_CASCADED_MENU: _cascaded_Changed = true; break; - case IDX_SYSTEM_ICON_IN_MENU: _menuIcons_Changed = true; break; - case IDX_EXTRACT_ELIM_DUP: _elimDup_Changed = true; break; - // case IDX_EXTRACT_WRITE_ZONE: _writeZone_Changed = true; break; - - default: - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); - } - - Changed(); - return true; -} - - -bool CMenuPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) -{ - if (code == CBN_SELCHANGE && itemID == IDC_SYSTEM_ZONE) - { - _writeZone_Changed = true; - Changed(); - return true; - } - return CPropertyPage::OnCommand(code, itemID, param); -} - - -bool CMenuPage::OnNotify(UINT controlID, LPNMHDR lParam) -{ - if (lParam->hwndFrom == HWND(_listView)) - { - switch (lParam->code) - { - case (LVN_ITEMCHANGED): - return OnItemChanged((const NMLISTVIEW *)lParam); - } - } - return CPropertyPage::OnNotify(controlID, lParam); -} - - -bool CMenuPage::OnItemChanged(const NMLISTVIEW *info) -{ - if (_initMode) - return true; - if ((info->uChanged & LVIF_STATE) != 0) - { - UINT oldState = info->uOldState & LVIS_STATEIMAGEMASK; - UINT newState = info->uNewState & LVIS_STATEIMAGEMASK; - if (oldState != newState) - { - _flags_Changed = true; - Changed(); - } - } - return true; -} +// MenuPage.cpp + +#include "StdAfx.h" + +#include "../Common/ZipRegistry.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileFind.h" + +#include "../Explorer/ContextMenuFlags.h" +#include "../Explorer/RegistryContextMenu.h" +#include "../Explorer/resource.h" + +#include "../FileManager/PropertyNameRes.h" + +#include "../GUI/ExtractDialogRes.h" + +#include "FormatUtils.h" +#include "HelpUtils.h" +#include "LangUtils.h" +#include "MenuPage.h" +#include "MenuPageRes.h" + + +using namespace NWindows; +using namespace NContextMenuFlags; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDX_SYSTEM_INTEGRATE_TO_MENU, + IDX_SYSTEM_CASCADED_MENU, + IDX_SYSTEM_ICON_IN_MENU, + IDX_EXTRACT_ELIM_DUP, + IDT_SYSTEM_ZONE, + IDT_SYSTEM_CONTEXT_MENU_ITEMS +}; +#endif + +#define kMenuTopic "fm/options.htm#sevenZip" + +struct CContextMenuItem +{ + unsigned ControlID; + UInt32 Flag; +}; + +static const CContextMenuItem kMenuItems[] = +{ + { IDS_CONTEXT_OPEN, kOpen }, + { IDS_CONTEXT_OPEN, kOpenAs }, + { IDS_CONTEXT_EXTRACT, kExtract }, + { IDS_CONTEXT_EXTRACT_HERE, kExtractHere }, + { IDS_CONTEXT_EXTRACT_TO, kExtractTo }, + + { IDS_CONTEXT_TEST, kTest }, + + { IDS_CONTEXT_COMPRESS, kCompress }, + { IDS_CONTEXT_COMPRESS_TO, kCompressTo7z }, + { IDS_CONTEXT_COMPRESS_TO, kCompressToZip }, + + #ifndef UNDER_CE + { IDS_CONTEXT_COMPRESS_EMAIL, kCompressEmail }, + { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressTo7zEmail }, + { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressToZipEmail }, + #endif + + { IDS_PROP_CHECKSUM, kCRC }, + { IDS_PROP_CHECKSUM, kCRC_Cascaded }, +}; + + +#if !defined(_WIN64) +extern bool g_Is_Wow64; +#endif + +#ifndef KEY_WOW64_64KEY + #define KEY_WOW64_64KEY (0x0100) +#endif + +#ifndef KEY_WOW64_32KEY + #define KEY_WOW64_32KEY (0x0200) +#endif + + +static void LoadLang_Spec(UString &s, UInt32 id, const char *eng) +{ + LangString(id, s); + if (s.IsEmpty()) + s = eng; + s.RemoveChar(L'&'); +} + + +bool CMenuPage::OnInit() +{ + _initMode = true; + + Clear_MenuChanged(); + +#ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); +#endif + + #ifdef UNDER_CE + + HideItem(IDX_SYSTEM_INTEGRATE_TO_MENU); + HideItem(IDX_SYSTEM_INTEGRATE_TO_MENU_2); + + #else + + { + UString s; + { + CWindow window(GetItem(IDX_SYSTEM_INTEGRATE_TO_MENU)); + window.GetText(s); + } + UString bit64 = LangString(IDS_PROP_BIT64); + if (bit64.IsEmpty()) + bit64 = "64-bit"; + #ifdef _WIN64 + bit64.Replace(L"64", L"32"); + #endif + s.Add_Space(); + s.Add_Char('('); + s += bit64; + s.Add_Char(')'); + SetItemText(IDX_SYSTEM_INTEGRATE_TO_MENU_2, s); + } + + const FString prefix = NDLL::GetModuleDirPrefix(); + + _dlls[0].ctrl = IDX_SYSTEM_INTEGRATE_TO_MENU; + _dlls[1].ctrl = IDX_SYSTEM_INTEGRATE_TO_MENU_2; + + _dlls[0].wow = 0; + _dlls[1].wow = + #ifdef _WIN64 + KEY_WOW64_32KEY + #else + KEY_WOW64_64KEY + #endif + ; + + for (unsigned d = 0; d < 2; d++) + { + CShellDll &dll = _dlls[d]; + + dll.wasChanged = false; + + #ifndef _WIN64 + if (d != 0 && !g_Is_Wow64) + { + HideItem(dll.ctrl); + continue; + } + #endif + + FString &path = dll.Path; + path = prefix; + path += (d == 0 ? "7-zip.dll" : + #ifdef _WIN64 + "7-zip32.dll" + #else + "7-zip64.dll" + #endif + ); + + + if (!NFile::NFind::DoesFileExist_Raw(path)) + { + path.Empty(); + EnableItem(dll.ctrl, false); + } + else + { + dll.prevValue = CheckContextMenuHandler(fs2us(path), dll.wow); + CheckButton(dll.ctrl, dll.prevValue); + } + } + + #endif + + + CContextMenuInfo ci; + ci.Load(); + + CheckButton(IDX_SYSTEM_CASCADED_MENU, ci.Cascaded.Val); + CheckButton(IDX_SYSTEM_ICON_IN_MENU, ci.MenuIcons.Val); + CheckButton(IDX_EXTRACT_ELIM_DUP, ci.ElimDup.Val); + + _listView.Attach(GetItem(IDL_SYSTEM_OPTIONS)); + _zoneCombo.Attach(GetItem(IDC_SYSTEM_ZONE)); + + { + unsigned wz = ci.WriteZone; + if (wz == (UInt32)(Int32)-1) + wz = 0; + for (unsigned i = 0; i <= 3; i++) + { + unsigned val = i; + UString s; + if (i == 3) + { + if (wz < 3) + break; + val = wz; + } + else + { + #define MY_IDYES 406 + #define MY_IDNO 407 + if (i == 0) + LoadLang_Spec(s, MY_IDNO, "No"); + else if (i == 1) + LoadLang_Spec(s, MY_IDYES, "Yes"); + else + LangString(IDT_ZONE_FOR_OFFICE, s); + } + if (s.IsEmpty()) + s.Add_UInt32(val); + if (i == 0) + s.Insert(0, L"* "); + const int index = (int)_zoneCombo.AddString(s); + _zoneCombo.SetItemData(index, (LPARAM)val); + if (val == wz) + _zoneCombo.SetCurSel(index); + } + } + + + const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT; + _listView.SetExtendedListViewStyle(newFlags, newFlags); + + _listView.InsertColumn(0, L"", 200); + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kMenuItems); i++) + { + const CContextMenuItem &menuItem = kMenuItems[i]; + + UString s = LangString(menuItem.ControlID); + if (menuItem.Flag == kCRC) + s = "CRC SHA"; + else if (menuItem.Flag == kCRC_Cascaded) + s = "7-Zip > CRC SHA"; + if (menuItem.Flag == kOpenAs + || menuItem.Flag == kCRC + || menuItem.Flag == kCRC_Cascaded) + s += " >"; + + switch (menuItem.ControlID) + { + case IDS_CONTEXT_EXTRACT_TO: + { + s = MyFormatNew(s, LangString(IDS_CONTEXT_FOLDER)); + break; + } + case IDS_CONTEXT_COMPRESS_TO: + case IDS_CONTEXT_COMPRESS_TO_EMAIL: + { + UString s2 = LangString(IDS_CONTEXT_ARCHIVE); + switch (menuItem.Flag) + { + case kCompressTo7z: + case kCompressTo7zEmail: + s2 += (".7z"); + break; + case kCompressToZip: + case kCompressToZipEmail: + s2 += (".zip"); + break; + } + s = MyFormatNew(s, s2); + break; + } + } + + const int itemIndex = _listView.InsertItem(i, s); + _listView.SetCheckState((unsigned)itemIndex, ((ci.Flags & menuItem.Flag) != 0)); + } + + _listView.SetColumnWidthAuto(0); + _initMode = false; + + return CPropertyPage::OnInit(); +} + + +#ifndef UNDER_CE + +static void ShowMenuErrorMessage(const wchar_t *m, HWND hwnd) +{ + MessageBoxW(hwnd, m, L"7-Zip", MB_ICONERROR); +} + +#endif + + +LONG CMenuPage::OnApply() +{ + #ifndef UNDER_CE + + for (unsigned d = 2; d != 0;) + { + d--; + CShellDll &dll = _dlls[d]; + if (dll.wasChanged && !dll.Path.IsEmpty()) + { + const bool newVal = IsButtonCheckedBool(dll.ctrl); + const LONG res = SetContextMenuHandler(newVal, fs2us(dll.Path), dll.wow); + if (res != ERROR_SUCCESS && (dll.prevValue != newVal || newVal)) + ShowMenuErrorMessage(NError::MyFormatMessage(res), *this); + dll.prevValue = CheckContextMenuHandler(fs2us(dll.Path), dll.wow); + CheckButton(dll.ctrl, dll.prevValue); + dll.wasChanged = false; + } + } + + #endif + + if (_cascaded_Changed + || _menuIcons_Changed + || _elimDup_Changed + || _writeZone_Changed + || _flags_Changed) + { + CContextMenuInfo ci; + ci.Cascaded.Val = IsButtonCheckedBool(IDX_SYSTEM_CASCADED_MENU); + ci.Cascaded.Def = _cascaded_Changed; + + ci.MenuIcons.Val = IsButtonCheckedBool(IDX_SYSTEM_ICON_IN_MENU); + ci.MenuIcons.Def = _menuIcons_Changed; + + ci.ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP); + ci.ElimDup.Def = _elimDup_Changed; + + { + int zoneIndex = (int)_zoneCombo.GetItemData_of_CurSel(); + if (zoneIndex <= 0) + zoneIndex = -1; + ci.WriteZone = (UInt32)(Int32)zoneIndex; + } + + ci.Flags = 0; + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kMenuItems); i++) + if (_listView.GetCheckState(i)) + ci.Flags |= kMenuItems[i].Flag; + + ci.Flags_Def = _flags_Changed; + ci.Save(); + + Clear_MenuChanged(); + } + + // UnChanged(); + + return PSNRET_NOERROR; +} + +void CMenuPage::OnNotifyHelp() +{ + ShowHelpWindow(kMenuTopic); +} + +bool CMenuPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + #ifndef UNDER_CE + case IDX_SYSTEM_INTEGRATE_TO_MENU: + case IDX_SYSTEM_INTEGRATE_TO_MENU_2: + { + for (unsigned d = 0; d < 2; d++) + { + CShellDll &dll = _dlls[d]; + if (buttonID == dll.ctrl && !dll.Path.IsEmpty()) + dll.wasChanged = true; + } + break; + } + #endif + + case IDX_SYSTEM_CASCADED_MENU: _cascaded_Changed = true; break; + case IDX_SYSTEM_ICON_IN_MENU: _menuIcons_Changed = true; break; + case IDX_EXTRACT_ELIM_DUP: _elimDup_Changed = true; break; + // case IDX_EXTRACT_WRITE_ZONE: _writeZone_Changed = true; break; + + default: + return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); + } + + Changed(); + return true; +} + + +bool CMenuPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) +{ + if (code == CBN_SELCHANGE && itemID == IDC_SYSTEM_ZONE) + { + _writeZone_Changed = true; + Changed(); + return true; + } + return CPropertyPage::OnCommand(code, itemID, param); +} + + +bool CMenuPage::OnNotify(UINT controlID, LPNMHDR lParam) +{ + if (lParam->hwndFrom == HWND(_listView)) + { + switch (lParam->code) + { + case (LVN_ITEMCHANGED): + return OnItemChanged((const NMLISTVIEW *)lParam); + } + } + return CPropertyPage::OnNotify(controlID, lParam); +} + + +bool CMenuPage::OnItemChanged(const NMLISTVIEW *info) +{ + if (_initMode) + return true; + if ((info->uChanged & LVIF_STATE) != 0) + { + UINT oldState = info->uOldState & LVIS_STATEIMAGEMASK; + UINT newState = info->uNewState & LVIS_STATEIMAGEMASK; + if (oldState != newState) + { + _flags_Changed = true; + Changed(); + } + } + return true; +} diff --git a/CPP/7zip/UI/FileManager/MenuPage.h b/CPP/7zip/UI/FileManager/MenuPage.h index efffc8605..3b62a8bd1 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.h +++ b/CPP/7zip/UI/FileManager/MenuPage.h @@ -1,57 +1,57 @@ -// MenuPage.h - -#ifndef ZIP7_INC_MENU_PAGE_H -#define ZIP7_INC_MENU_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/ListView.h" - -struct CShellDll -{ - FString Path; - bool wasChanged; - bool prevValue; - unsigned ctrl; - UInt32 wow; - - CShellDll(): wasChanged (false), prevValue(false), ctrl(0), wow(0) {} -}; - -class CMenuPage: public NWindows::NControl::CPropertyPage -{ - bool _initMode; - - bool _cascaded_Changed; - bool _menuIcons_Changed; - bool _elimDup_Changed; - bool _writeZone_Changed; - bool _flags_Changed; - - void Clear_MenuChanged() - { - _cascaded_Changed = false; - _menuIcons_Changed = false; - _elimDup_Changed = false; - _writeZone_Changed = false; - _flags_Changed = false; - } - - #ifndef UNDER_CE - CShellDll _dlls[2]; - #endif - - NWindows::NControl::CListView _listView; - NWindows::NControl::CComboBox _zoneCombo; - - virtual bool OnInit() Z7_override; - virtual void OnNotifyHelp() Z7_override; - virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override; - virtual LONG OnApply() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; - - bool OnItemChanged(const NMLISTVIEW* info); -}; - -#endif +// MenuPage.h + +#ifndef ZIP7_INC_MENU_PAGE_H +#define ZIP7_INC_MENU_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/ListView.h" + +struct CShellDll +{ + FString Path; + bool wasChanged; + bool prevValue; + unsigned ctrl; + UInt32 wow; + + CShellDll(): wasChanged (false), prevValue(false), ctrl(0), wow(0) {} +}; + +class CMenuPage: public NWindows::NControl::CPropertyPage +{ + bool _initMode; + + bool _cascaded_Changed; + bool _menuIcons_Changed; + bool _elimDup_Changed; + bool _writeZone_Changed; + bool _flags_Changed; + + void Clear_MenuChanged() + { + _cascaded_Changed = false; + _menuIcons_Changed = false; + _elimDup_Changed = false; + _writeZone_Changed = false; + _flags_Changed = false; + } + + #ifndef UNDER_CE + CShellDll _dlls[2]; + #endif + + NWindows::NControl::CListView _listView; + NWindows::NControl::CComboBox _zoneCombo; + + virtual bool OnInit() Z7_override; + virtual void OnNotifyHelp() Z7_override; + virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override; + virtual LONG OnApply() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; + + bool OnItemChanged(const NMLISTVIEW* info); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/MenuPage.rc b/CPP/7zip/UI/FileManager/MenuPage.rc index 64880da11..66162f64d 100644 --- a/CPP/7zip/UI/FileManager/MenuPage.rc +++ b/CPP/7zip/UI/FileManager/MenuPage.rc @@ -1,24 +1,24 @@ -#include "MenuPageRes.h" -#include "../../GuiCommon.rc" - -#define xc OPTIONS_PAGE_XC_SIZE -#define yc OPTIONS_PAGE_YC_SIZE - -IDD_MENU MY_PAGE -#include "MenuPage2.rc" - -#ifdef UNDER_CE - -#undef m -#undef xc -#undef yc - -#define m 4 -#define xc (SMALL_PAGE_SIZE_X + 8) - -#define yc 112 - -IDD_MENU_2 MY_PAGE -#include "MenuPage2.rc" - -#endif +#include "MenuPageRes.h" +#include "../../GuiCommon.rc" + +#define xc OPTIONS_PAGE_XC_SIZE +#define yc OPTIONS_PAGE_YC_SIZE + +IDD_MENU MY_PAGE +#include "MenuPage2.rc" + +#ifdef UNDER_CE + +#undef m +#undef xc +#undef yc + +#define m 4 +#define xc (SMALL_PAGE_SIZE_X + 8) + +#define yc 112 + +IDD_MENU_2 MY_PAGE +#include "MenuPage2.rc" + +#endif diff --git a/CPP/7zip/UI/FileManager/MenuPage2.rc b/CPP/7zip/UI/FileManager/MenuPage2.rc index 322d2f117..df0cc5457 100644 --- a/CPP/7zip/UI/FileManager/MenuPage2.rc +++ b/CPP/7zip/UI/FileManager/MenuPage2.rc @@ -1,28 +1,28 @@ -#include "../GUI/ExtractDialogRes.h" - -#define y 96 - -#define zoneX 100 - -CAPTION "7-Zip" -BEGIN - MY_CONTROL_CHECKBOX ( "Integrate 7-Zip to shell context menu", IDX_SYSTEM_INTEGRATE_TO_MENU, m, m, xc) - MY_CONTROL_CHECKBOX ( "(32-bit)", IDX_SYSTEM_INTEGRATE_TO_MENU_2, m, m + 14, xc) - MY_CONTROL_CHECKBOX ( "Cascaded context menu", IDX_SYSTEM_CASCADED_MENU, m, m + 28, xc) - MY_CONTROL_CHECKBOX ( "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, m, m + 42, xc) - MY_CONTROL_CHECKBOX ( "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, m, m + 56, xc) - - LTEXT "Propagate Zone.Id stream:", IDT_SYSTEM_ZONE, m, m + 70, xc - zoneX, 8 - COMBOBOX IDC_SYSTEM_ZONE, m + xc - zoneX, m + 70 - 2, zoneX, 50, MY_COMBO - - LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 84, xc, 8 - CONTROL "List", IDL_SYSTEM_OPTIONS, "SysListView32", - LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP, - m, m + y, xc, yc - y -END - - -STRINGTABLE -BEGIN - IDT_ZONE_FOR_OFFICE "For Office files" -END +#include "../GUI/ExtractDialogRes.h" + +#define y 96 + +#define zoneX 100 + +CAPTION "7-Zip" +BEGIN + MY_CONTROL_CHECKBOX ( "Integrate 7-Zip to shell context menu", IDX_SYSTEM_INTEGRATE_TO_MENU, m, m, xc) + MY_CONTROL_CHECKBOX ( "(32-bit)", IDX_SYSTEM_INTEGRATE_TO_MENU_2, m, m + 14, xc) + MY_CONTROL_CHECKBOX ( "Cascaded context menu", IDX_SYSTEM_CASCADED_MENU, m, m + 28, xc) + MY_CONTROL_CHECKBOX ( "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, m, m + 42, xc) + MY_CONTROL_CHECKBOX ( "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, m, m + 56, xc) + + LTEXT "Propagate Zone.Id stream:", IDT_SYSTEM_ZONE, m, m + 70, xc - zoneX, 8 + COMBOBOX IDC_SYSTEM_ZONE, m + xc - zoneX, m + 70 - 2, zoneX, 50, MY_COMBO + + LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 84, xc, 8 + CONTROL "List", IDL_SYSTEM_OPTIONS, "SysListView32", + LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP, + m, m + y, xc, yc - y +END + + +STRINGTABLE +BEGIN + IDT_ZONE_FOR_OFFICE "For Office files" +END diff --git a/CPP/7zip/UI/FileManager/MenuPageRes.h b/CPP/7zip/UI/FileManager/MenuPageRes.h index a8dd79d80..e2cf79852 100644 --- a/CPP/7zip/UI/FileManager/MenuPageRes.h +++ b/CPP/7zip/UI/FileManager/MenuPageRes.h @@ -1,15 +1,15 @@ -#define IDD_MENU 2300 -#define IDD_MENU_2 12300 - -#define IDX_SYSTEM_INTEGRATE_TO_MENU 2301 -#define IDX_SYSTEM_CASCADED_MENU 2302 -#define IDT_SYSTEM_CONTEXT_MENU_ITEMS 2303 -#define IDX_SYSTEM_ICON_IN_MENU 2304 - -#define IDX_SYSTEM_INTEGRATE_TO_MENU_2 2310 - -#define IDT_SYSTEM_ZONE 3440 -#define IDT_ZONE_FOR_OFFICE 3441 - -#define IDL_SYSTEM_OPTIONS 100 -#define IDC_SYSTEM_ZONE 101 +#define IDD_MENU 2300 +#define IDD_MENU_2 12300 + +#define IDX_SYSTEM_INTEGRATE_TO_MENU 2301 +#define IDX_SYSTEM_CASCADED_MENU 2302 +#define IDT_SYSTEM_CONTEXT_MENU_ITEMS 2303 +#define IDX_SYSTEM_ICON_IN_MENU 2304 + +#define IDX_SYSTEM_INTEGRATE_TO_MENU_2 2310 + +#define IDT_SYSTEM_ZONE 3440 +#define IDT_ZONE_FOR_OFFICE 3441 + +#define IDL_SYSTEM_OPTIONS 100 +#define IDC_SYSTEM_ZONE 101 diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.cpp b/CPP/7zip/UI/FileManager/MessagesDialog.cpp index 4c3a7f9ed..57e56bcf7 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialog.cpp +++ b/CPP/7zip/UI/FileManager/MessagesDialog.cpp @@ -1,76 +1,76 @@ -// MessagesDialog.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/ResourceString.h" - -#include "MessagesDialog.h" - -#include "LangUtils.h" - -#include "ProgressDialog2Res.h" - -using namespace NWindows; - -void CMessagesDialog::AddMessageDirect(LPCWSTR message) -{ - const unsigned i = (unsigned)_messageList.GetItemCount(); - wchar_t sz[16]; - ConvertUInt32ToString(i, sz); - _messageList.InsertItem(i, sz); - _messageList.SetSubItem(i, 1, message); -} - -void CMessagesDialog::AddMessage(LPCWSTR message) -{ - UString s = message; - while (!s.IsEmpty()) - { - const int pos = s.Find(L'\n'); - if (pos < 0) - break; - AddMessageDirect(s.Left(pos)); - s.DeleteFrontal((unsigned)pos + 1); - } - AddMessageDirect(s); -} - -bool CMessagesDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_MESSAGES); - LangSetDlgItems(*this, NULL, 0); - SetItemText(IDOK, LangString(IDS_CLOSE)); - #endif - _messageList.Attach(GetItem(IDL_MESSAGE)); - _messageList.SetUnicodeFormat(); - - _messageList.InsertColumn(0, L"", 30); - _messageList.InsertColumn(1, LangString(IDS_MESSAGE), 600); - - FOR_VECTOR (i, *Messages) - AddMessage((*Messages)[i]); - - _messageList.SetColumnWidthAuto(0); - _messageList.SetColumnWidthAuto(1); - NormalizeSize(); - return CModalDialog::OnInit(); -} - -bool CMessagesDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx, by; - GetItemSizes(IDOK, bx, by); - int y = ySize - my - by; - int x = xSize - mx - bx; - - InvalidateRect(NULL); - - MoveItem(IDOK, x, y, bx, by); - _messageList.Move(mx, my, xSize - mx * 2, y - my * 2); - return false; -} +// MessagesDialog.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/ResourceString.h" + +#include "MessagesDialog.h" + +#include "LangUtils.h" + +#include "ProgressDialog2Res.h" + +using namespace NWindows; + +void CMessagesDialog::AddMessageDirect(LPCWSTR message) +{ + const unsigned i = (unsigned)_messageList.GetItemCount(); + wchar_t sz[16]; + ConvertUInt32ToString(i, sz); + _messageList.InsertItem(i, sz); + _messageList.SetSubItem(i, 1, message); +} + +void CMessagesDialog::AddMessage(LPCWSTR message) +{ + UString s = message; + while (!s.IsEmpty()) + { + const int pos = s.Find(L'\n'); + if (pos < 0) + break; + AddMessageDirect(s.Left(pos)); + s.DeleteFrontal((unsigned)pos + 1); + } + AddMessageDirect(s); +} + +bool CMessagesDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_MESSAGES); + LangSetDlgItems(*this, NULL, 0); + SetItemText(IDOK, LangString(IDS_CLOSE)); + #endif + _messageList.Attach(GetItem(IDL_MESSAGE)); + _messageList.SetUnicodeFormat(); + + _messageList.InsertColumn(0, L"", 30); + _messageList.InsertColumn(1, LangString(IDS_MESSAGE), 600); + + FOR_VECTOR (i, *Messages) + AddMessage((*Messages)[i]); + + _messageList.SetColumnWidthAuto(0); + _messageList.SetColumnWidthAuto(1); + NormalizeSize(); + return CModalDialog::OnInit(); +} + +bool CMessagesDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx, by; + GetItemSizes(IDOK, bx, by); + int y = ySize - my - by; + int x = xSize - mx - bx; + + InvalidateRect(NULL); + + MoveItem(IDOK, x, y, bx, by); + _messageList.Move(mx, my, xSize - mx * 2, y - my * 2); + return false; +} diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.h b/CPP/7zip/UI/FileManager/MessagesDialog.h index a28f60bc1..40b0379bf 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialog.h +++ b/CPP/7zip/UI/FileManager/MessagesDialog.h @@ -1,25 +1,25 @@ -// MessagesDialog.h - -#ifndef ZIP7_INC_MESSAGES_DIALOG_H -#define ZIP7_INC_MESSAGES_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/ListView.h" - -#include "MessagesDialogRes.h" - -class CMessagesDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CListView _messageList; - - void AddMessageDirect(LPCWSTR message); - void AddMessage(LPCWSTR message); - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; -public: - const UStringVector *Messages; - - INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_MESSAGES, parent); } -}; - -#endif +// MessagesDialog.h + +#ifndef ZIP7_INC_MESSAGES_DIALOG_H +#define ZIP7_INC_MESSAGES_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/ListView.h" + +#include "MessagesDialogRes.h" + +class CMessagesDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CListView _messageList; + + void AddMessageDirect(LPCWSTR message); + void AddMessage(LPCWSTR message); + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; +public: + const UStringVector *Messages; + + INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_MESSAGES, parent); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.rc b/CPP/7zip/UI/FileManager/MessagesDialog.rc index d7d404319..49b73e843 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialog.rc +++ b/CPP/7zip/UI/FileManager/MessagesDialog.rc @@ -1,14 +1,14 @@ -#include "MessagesDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 440 -#define yc 160 - -IDD_MESSAGES DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "7-Zip: Diagnostic messages" -{ - DEFPUSHBUTTON "&Close", IDOK, bx, by, bxs, bys - CONTROL "List1", IDL_MESSAGE, "SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, - m, m, xc, yc - bys - m -} +#include "MessagesDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 440 +#define yc 160 + +IDD_MESSAGES DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "7-Zip: Diagnostic messages" +{ + DEFPUSHBUTTON "&Close", IDOK, bx, by, bxs, bys + CONTROL "List1", IDL_MESSAGE, "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, + m, m, xc, yc - bys - m +} diff --git a/CPP/7zip/UI/FileManager/MessagesDialogRes.h b/CPP/7zip/UI/FileManager/MessagesDialogRes.h index 5bd8184e0..c8fffff6e 100644 --- a/CPP/7zip/UI/FileManager/MessagesDialogRes.h +++ b/CPP/7zip/UI/FileManager/MessagesDialogRes.h @@ -1,3 +1,3 @@ -#define IDD_MESSAGES 6602 -#define IDS_MESSAGE 6603 -#define IDL_MESSAGE 100 +#define IDD_MESSAGES 6602 +#define IDS_MESSAGE 6603 +#define IDL_MESSAGE 100 diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h index e38ebbbf9..a0cbd4538 100644 --- a/CPP/7zip/UI/FileManager/MyCom2.h +++ b/CPP/7zip/UI/FileManager/MyCom2.h @@ -1,46 +1,46 @@ -// MyCom2.h - -#ifndef ZIP7_INC_MYCOM2_H -#define ZIP7_INC_MYCOM2_H - -#include "../../../Common/MyCom.h" - -#define Z7_COM_UNKNOWN_IMP_SPEC_MT2(i1, i) \ - Z7_COM_QI_BEGIN \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - i \ - Z7_COM_QI_END_MT \ - Z7_COM_ADDREF_RELEASE_MT - - -#define Z7_COM_UNKNOWN_IMP_1_MT(i) \ - Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ - i, \ - Z7_COM_QI_ENTRY(i) \ - ) - -#define Z7_COM_UNKNOWN_IMP_2_MT(i1, i2) \ - Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ - i1, \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - ) - -#define Z7_COM_UNKNOWN_IMP_3_MT(i1, i2, i3) \ - Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ - i1, \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - ) - -#define Z7_COM_UNKNOWN_IMP_4_MT(i1, i2, i3, i4) \ - Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ - i1, \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - Z7_COM_QI_ENTRY(i4) \ - ) - -#endif +// MyCom2.h + +#ifndef ZIP7_INC_MYCOM2_H +#define ZIP7_INC_MYCOM2_H + +#include "../../../Common/MyCom.h" + +#define Z7_COM_UNKNOWN_IMP_SPEC_MT2(i1, i) \ + Z7_COM_QI_BEGIN \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + i \ + Z7_COM_QI_END_MT \ + Z7_COM_ADDREF_RELEASE_MT + + +#define Z7_COM_UNKNOWN_IMP_1_MT(i) \ + Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ + i, \ + Z7_COM_QI_ENTRY(i) \ + ) + +#define Z7_COM_UNKNOWN_IMP_2_MT(i1, i2) \ + Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ + i1, \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + ) + +#define Z7_COM_UNKNOWN_IMP_3_MT(i1, i2, i3) \ + Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ + i1, \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + ) + +#define Z7_COM_UNKNOWN_IMP_4_MT(i1, i2, i3, i4) \ + Z7_COM_UNKNOWN_IMP_SPEC_MT2( \ + i1, \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + Z7_COM_QI_ENTRY(i4) \ + ) + +#endif diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp index 07f0cf45f..f190929f7 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp @@ -1,960 +1,964 @@ -// MyLoadMenu.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/TimeUtils.h" -#include "../../../Windows/Control/Dialog.h" - -#include "../../PropID.h" - -#include "../Common/CompressCall.h" - -#include "AboutDialog.h" -#include "App.h" -#include "BrowseDialog2.h" -#include "HelpUtils.h" -#include "LangUtils.h" -#include "MyLoadMenu.h" -#include "RegistryUtils.h" - -#include "PropertyNameRes.h" -#include "resource.h" - -using namespace NWindows; - -static const UINT k_MenuID_OpenBookmark = 830; -static const UINT k_MenuID_SetBookmark = 810; -static const UINT k_MenuID_TimePopup = IDM_VIEW_TIME_POPUP; -static const UINT k_MenuID_Time = IDM_VIEW_TIME; - -#if 0 -// static const UINT k_MenuID_Bookmark_Temp = 850; -#endif - -extern HINSTANCE g_hInstance; - -#define kFMHelpTopic "FM/index.htm" - -extern void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance); - -enum -{ - k_MenuIndex_File = 0, - k_MenuIndex_Edit, - k_MenuIndex_View, - k_MenuIndex_Bookmarks -}; - -#ifdef Z7_LANG -static const UInt32 k_LangID_TopMenuItems[] = -{ - IDM_FILE, - IDM_EDIT, - IDM_VIEW, - IDM_FAVORITES, - IDM_TOOLS, - IDM_HELP -}; - -static const UInt32 k_LangID_Toolbars = IDM_VIEW_TOOLBARS; -static const UInt32 k_LangID_AddToFavorites = IDM_ADD_TO_FAVORITES; - -static const CIDLangPair kIDLangPairs[] = -{ - { IDCLOSE, 557 }, // IDM_EXIT - { IDM_VIEW_ARANGE_BY_NAME, IDS_PROP_NAME }, - { IDM_VIEW_ARANGE_BY_TYPE, IDS_PROP_FILE_TYPE }, - { IDM_VIEW_ARANGE_BY_DATE, IDS_PROP_MTIME }, - { IDM_VIEW_ARANGE_BY_SIZE, IDS_PROP_SIZE } -}; - -static int FindLangItem(unsigned controlID) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDLangPairs); i++) - if (kIDLangPairs[i].ControlID == controlID) - return (int)i; - return -1; -} -#endif - -static unsigned GetSortControlID(PROPID propID) -{ - switch (propID) - { - case kpidName: return IDM_VIEW_ARANGE_BY_NAME; - case kpidExtension: return IDM_VIEW_ARANGE_BY_TYPE; - case kpidMTime: return IDM_VIEW_ARANGE_BY_DATE; - case kpidSize: return IDM_VIEW_ARANGE_BY_SIZE; - case kpidNoProperty: return IDM_VIEW_ARANGE_NO_SORT; - } - return IDM_VIEW_ARANGE_BY_NAME; - // IDM_VIEW_ARANGE_NO_SORT; - // return -1; -} - -/* -#if _MSC_VER > 1400 -// GetVersion was declared deprecated -#pragma warning(disable : 4996) -#endif - -static bool g_IsNew_fMask = false; -static class CInit_fMask -{ -public: - CInit_fMask() - { - DWORD v = GetVersion(); - v = ((v & 0xff) << 8) | ((v >> 8) & 0xFF); - g_IsNew_fMask = (v > 0x400); // (win98/win2000) or newer - } -} g_Init_fMask; -static UINT Get_fMask_for_String() - { return g_IsNew_fMask ? MIIM_STRING : MIIM_TYPE; } -static UINT Get_fMask_for_FType_and_String() - { return g_IsNew_fMask ? (MIIM_STRING | MIIM_FTYPE) : MIIM_TYPE; } -*/ - -/* -We can use new MIIM_STRING / MIIM_FTYPE flags in the following conditions: - 1) we run at new Windows (win98/win2000) or newer - 2) also we probably must set MENUITEMINFO::cbSize as sizeof of full - (MENUITEMINFO) that was compiled with (WINVER >= 0x0500) -But it's simpler to use old MIIM_TYPE without these complex checks. -*/ - -// /* -static inline UINT Get_fMask_for_String() { return MIIM_TYPE; } -static inline UINT Get_fMask_for_FType_and_String() { return MIIM_TYPE; } -// */ - -static bool Is_MenuItem_TimePopup(const CMenuItem &item) -{ - return item.wID == k_MenuID_TimePopup || - item.StringValue.IsPrefixedBy_Ascii_NoCase("20"); -} - -#ifdef Z7_LANG -static void MyChangeMenu(HMENU menuLoc, unsigned menuID, unsigned level, unsigned menuIndex) -{ - CMenu menu; - menu.Attach(menuLoc); - - for (unsigned i = 0;; i++) - { - CMenuItem item; - /* here we can use - Get_fMask_for_String() or - Get_fMask_for_FType_and_String() - We want to change only String of menu item. - It's not required to change (fType) of menu item. - We can look (fType) to check for SEPARATOR item. - But String of separator is empty and (wID == 0). - So we can check for SEPARATOR without (fType) requesting. - So it's enough to use Get_fMask_for_String() here */ - item.fMask = - Get_fMask_for_String() - // Get_fMask_for_FType_and_String() - | MIIM_SUBMENU | MIIM_ID; - if (!menu.GetItem(i, true, item)) - break; - { - UString newString; - if (item.hSubMenu) - { - /* in win10: - MENU+POPUP: - (wID == item.hSubMenu) - MENUEX+POPUP where ID is not set: - (wID == 0) - MENU+SEPARATOR - (wID == 0) - */ - UInt32 langID = item.wID; - if (langID >= (1 << 16)) - { - // here we try to exclude the case (wID == item.hSubMenu) if (MENU+POPUP) - continue; - } - if (langID == 0) - { - if (level == 0) - { - if (i < Z7_ARRAY_SIZE(k_LangID_TopMenuItems)) - langID = k_LangID_TopMenuItems[i]; - } - else if (level == 1) - { - if (menuID == IDM_FAVORITES || (menuID == 0 && menuIndex == k_MenuIndex_Bookmarks)) - langID = k_LangID_AddToFavorites; - else if (menuID == IDM_VIEW || (menuID == 0 && menuIndex == k_MenuIndex_View)) - { - if (Is_MenuItem_TimePopup(item)) - langID = k_MenuID_TimePopup; - else - langID = k_LangID_Toolbars; - } - } - } - if (langID == k_MenuID_TimePopup) - continue; - if (langID != k_LangID_AddToFavorites) - MyChangeMenu(item.hSubMenu, langID, level + 1, i); - if (langID == 0) - continue; - LangString_OnlyFromLangFile(langID, newString); - if (newString.IsEmpty()) - continue; - } - else - { - if (item.fMask & (MIIM_TYPE | MIIM_FTYPE)) - if (item.IsSeparator()) - continue; - if (item.StringValue.IsEmpty()) - continue; - const int langPos = FindLangItem(item.wID); - // we don't need lang change for CRC items!!! - const UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID; - if (langID == 0) - continue; - - if (langID == IDM_OPEN_INSIDE_ONE || - langID == IDM_OPEN_INSIDE_PARSER) - { - LangString_OnlyFromLangFile(IDM_OPEN_INSIDE, newString); - if (newString.IsEmpty()) - continue; - newString.Replace(L"&", L""); - const int tabPos = newString.Find(L"\t"); - if (tabPos >= 0) - newString.DeleteFrom(tabPos); - newString += (langID == IDM_OPEN_INSIDE_ONE ? " *" : " #"); - } - else if (langID == IDM_BENCHMARK2) - { - LangString_OnlyFromLangFile(IDM_BENCHMARK, newString); - if (newString.IsEmpty()) - continue; - newString.Replace(L"&", L""); - const int tabPos = newString.Find(L"\t"); - if (tabPos >= 0) - newString.DeleteFrom(tabPos); - newString += " 2"; - } - else - { - LangString_OnlyFromLangFile(langID, newString); - } - - if (newString.IsEmpty()) - continue; - - const int tabPos = item.StringValue.ReverseFind(L'\t'); - if (tabPos >= 0) - newString += item.StringValue.Ptr(tabPos); - } - - { - item.StringValue = newString; - // we want to change only String - item.fMask = Get_fMask_for_String(); - menu.SetItem(i, true, item); - } - } - } -} -#endif - -static CMenu g_FileMenu; - -static struct CFileMenuDestroyer -{ - ~CFileMenuDestroyer() { if ((HMENU)g_FileMenu) g_FileMenu.Destroy(); } -} g_FileMenuDestroyer; - - -static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec); - -static void CopyPopMenu_IfRequired(CMenuItem &item) -{ - /* if (item.hSubMenu) is defined - { - - it creates new (popup) menu - - it copies menu items from old item.hSubMenu menu to new (popup) menu - - it sets item.hSubMenu to handle of created (popup) menu - } */ - if (item.hSubMenu) - { - CMenu popup; - popup.CreatePopup(); - CopyMenu(item.hSubMenu, popup); - item.hSubMenu = popup; - } -} - -/* destMenuSpec must be non-NULL handle to created empty popup menu */ -static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec) -{ - CMenu srcMenu; - srcMenu.Attach(srcMenuSpec); - CMenu destMenu; - destMenu.Attach(destMenuSpec); - unsigned startPos = 0; - for (unsigned i = 0;; i++) - { - CMenuItem item; - item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String(); - if (!srcMenu.GetItem(i, true, item)) - break; - CopyPopMenu_IfRequired(item); - if (destMenu.InsertItem(startPos, true, item)) - startPos++; - } -} - - -/* use for (needResetMenu): - false : for call from program window creation code - true : for another calls : (from Options language change) -*/ -void MyLoadMenu(bool needResetMenu) -{ - #ifdef UNDER_CE - - const HMENU oldMenu = g_App._commandBar.GetMenu(0); - if (oldMenu) - ::DestroyMenu(oldMenu); - /* BOOL b = */ g_App._commandBar.InsertMenubar(g_hInstance, IDM_MENU, 0); - const HMENU baseMenu = g_App._commandBar.GetMenu(0); - // if (startInit) - // SetIdsForSubMenus(baseMenu, 0, 0); - if (!g_LangID.IsEmpty()) - MyChangeMenu(baseMenu, 0, 0); - g_App._commandBar.DrawMenuBar(0); - - #else // UNDER_CE - - const HWND hWnd = g_HWND; - bool menuWasChanged = false; - /* - We must reload to english default menu for at least two cases: - - if some submenu was changed (File or another submenu can be changed after menu activating). - - for change from non-english lang to another partial non-english lang, - where we still need some english strings. - But we reload menu to default menu everytime except of program starting stage. - That scheme is simpler than complex checks for exact conditions for menu reload. - */ - if (needResetMenu) - { - const HMENU oldMenu = ::GetMenu(hWnd); - const HMENU newMenu = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_MENU)); - // docs for SetMenu(): the window is redrawn to reflect the menu change. - if (newMenu && ::SetMenu(hWnd, newMenu)) - ::DestroyMenu(oldMenu); - menuWasChanged = true; - } - const HMENU baseMenu = ::GetMenu(hWnd); - // if (startInit) - // SetIdsForSubMenus(baseMenu, 0, 0); - #ifdef Z7_LANG - if (!g_Lang.IsEmpty()) // !g_LangID.IsEmpty() && - { - MyChangeMenu(baseMenu, 0, 0, 0); - menuWasChanged = true; - } - #endif - - if (menuWasChanged) - ::DrawMenuBar(hWnd); - - #endif // UNDER_CE - - // menuWasChanged = false; // for debug - if (menuWasChanged || !(HMENU)g_FileMenu) - { - if ((HMENU)g_FileMenu) - g_FileMenu.Destroy(); - g_FileMenu.CreatePopup(); - CopyMenu(::GetSubMenu(baseMenu, k_MenuIndex_File), g_FileMenu); - } -} - -void OnMenuActivating(HWND /* hWnd */, HMENU hMenu, int position) -{ - HMENU mainMenu = - #ifdef UNDER_CE - g_App._commandBar.GetMenu(0); - #else - ::GetMenu(g_HWND) - #endif - ; - - if (::GetSubMenu(mainMenu, position) != hMenu) - return; - - if (position == k_MenuIndex_File) - { - CMenu menu; - menu.Attach(hMenu); - menu.RemoveAllItems(); - g_App.GetFocusedPanel().CreateFileMenu(hMenu); - } - else if (position == k_MenuIndex_Edit) - { - /* - CMenu menu; - menu.Attach(hMenu); - menu.EnableItem(IDM_EDIT_CUT, MF_ENABLED); - menu.EnableItem(IDM_EDIT_COPY, MF_ENABLED); - menu.EnableItem(IDM_EDIT_PASTE, IsClipboardFormatAvailableHDROP() ? MF_ENABLED : MF_GRAYED); - */ - } - else if (position == k_MenuIndex_View) - { - // View; - CMenu menu; - menu.Attach(hMenu); - menu.CheckRadioItem( - IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS, - IDM_VIEW_LARGE_ICONS + g_App.GetListViewMode(), MF_BYCOMMAND); - - menu.CheckRadioItem( - IDM_VIEW_ARANGE_BY_NAME, - IDM_VIEW_ARANGE_NO_SORT, - GetSortControlID(g_App.GetSortID()), - MF_BYCOMMAND); - - menu.CheckItemByID(IDM_VIEW_TWO_PANELS, g_App.NumPanels == 2); - menu.CheckItemByID(IDM_VIEW_FLAT_VIEW, g_App.GetFlatMode()); - menu.CheckItemByID(IDM_VIEW_ARCHIVE_TOOLBAR, g_App.ShowArchiveToolbar); - menu.CheckItemByID(IDM_VIEW_STANDARD_TOOLBAR, g_App.ShowStandardToolbar); - menu.CheckItemByID(IDM_VIEW_TOOLBARS_LARGE_BUTTONS, g_App.LargeButtons); - menu.CheckItemByID(IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT, g_App.ShowButtonsLables); - menu.CheckItemByID(IDM_VIEW_AUTO_REFRESH, g_App.Get_AutoRefresh_Mode()); - // menu.CheckItemByID(IDM_VIEW_SHOW_STREAMS, g_App.Get_ShowNtfsStrems_Mode()); - // menu.CheckItemByID(IDM_VIEW_SHOW_DELETED, g_App.ShowDeletedFiles); - - for (unsigned i = 0;; i++) - { - CMenuItem item; - item.fMask = Get_fMask_for_String() | MIIM_SUBMENU | MIIM_ID; - item.fType = MFT_STRING; - if (!menu.GetItem(i, true, item)) - break; - if (item.hSubMenu && Is_MenuItem_TimePopup(item)) - { - FILETIME ft; - NTime::GetCurUtcFileTime(ft); - - { - wchar_t s[64]; - s[0] = 0; - if (ConvertUtcFileTimeToString(ft, s, kTimestampPrintLevel_DAY)) - item.StringValue = s; - } - - item.fMask = Get_fMask_for_String() | MIIM_ID; - item.fType = MFT_STRING; - item.wID = k_MenuID_TimePopup; - menu.SetItem(i, true, item); - - CMenu subMenu; - subMenu.Attach(menu.GetSubMenu((int)i)); - subMenu.RemoveAllItems(); - - const int k_TimeLevels[] = - { - kTimestampPrintLevel_DAY, - kTimestampPrintLevel_MIN, - kTimestampPrintLevel_SEC, - // 1,2,3,4,5,6, - kTimestampPrintLevel_NTFS, - kTimestampPrintLevel_NS - }; - - unsigned last = k_MenuID_Time; - unsigned selectedCommand = 0; - g_App._timestampLevels.Clear(); - unsigned id = k_MenuID_Time; - - for (unsigned k = 0; k < Z7_ARRAY_SIZE(k_TimeLevels); k++) - { - wchar_t s[64]; - s[0] = 0; - const int timestampLevel = k_TimeLevels[k]; - if (ConvertUtcFileTimeToString(ft, s, timestampLevel)) - { - if (subMenu.AppendItem(MF_STRING, id, s)) - { - last = id; - g_App._timestampLevels.Add(timestampLevel); - if (g_App.GetTimestampLevel() == timestampLevel) - selectedCommand = id; - id++; - } - } - } - if (selectedCommand != 0) - menu.CheckRadioItem(k_MenuID_Time, last, selectedCommand, MF_BYCOMMAND); - - if (subMenu.AppendItem(MF_STRING, IDM_VIEW_TIME_UTC, L"UTC")) - subMenu.CheckItemByID(IDM_VIEW_TIME_UTC, g_Timestamp_Show_UTC); - } - } - } - else if (position == k_MenuIndex_Bookmarks) - { - CMenu menu; - menu.Attach(hMenu); - - CMenu subMenu; - subMenu.Attach(menu.GetSubMenu(0)); - subMenu.RemoveAllItems(); - unsigned i; - - for (i = 0; i < 10; i++) - { - UString s = LangString(IDS_BOOKMARK); - s.Add_Space(); - const char c = (char)(L'0' + i); - s.Add_Char(c); - s += "\tAlt+Shift+"; - s.Add_Char(c); - subMenu.AppendItem(MF_STRING, k_MenuID_SetBookmark + i, s); - } - - menu.RemoveAllItemsFrom(2); - - for (i = 0; i < 10; i++) - { - UString s = g_App.AppState.FastFolders.GetString(i); - const int kMaxSize = 100; - const int kFirstPartSize = kMaxSize / 2; - if (s.Len() > kMaxSize) - { - s.Delete(kFirstPartSize, s.Len() - kMaxSize); - s.Insert(kFirstPartSize, L" ... "); - } - if (s.IsEmpty()) - s = '-'; - s += "\tAlt+"; - s.Add_Char((char)('0' + i)); - menu.AppendItem(MF_STRING, k_MenuID_OpenBookmark + i, s); - } -#if 0 - { - FString tempPathF; - if (NFile::NDir::MyGetTempPath(tempPathF)) - { - menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); - UString s; - s = "Temp : "; - s += fs2us(tempPathF); - menu.AppendItem(MF_STRING, k_MenuID_Bookmark_Temp, s); - } - } -#endif - } -} - -/* -It doesn't help -void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id) -{ - if (::GetSubMenu(::GetMenu(g_HWND), 0) != hMenu) - return; -} -*/ - -static const unsigned g_Zvc_IDs[] = -{ - IDM_VER_EDIT, - IDM_VER_COMMIT, - IDM_VER_REVERT, - IDM_VER_DIFF -}; - -static const char * const g_Zvc_Strings[] = -{ - "Ver Edit (&1)" - , "Ver Commit" - , "Ver Revert" - , "Ver Diff (&0)" -}; - -void CFileMenu::Load(HMENU hMenu, unsigned startPos) -{ - CMenu destMenu; - destMenu.Attach(hMenu); - - UString diffPath; - ReadRegDiff(diffPath); - - unsigned numRealItems = startPos; - - const bool isBigScreen = NControl::IsDialogSizeOK(40, 200, g_HWND); - - for (unsigned i = 0;; i++) - { - CMenuItem item; - - item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String(); - item.fType = MFT_STRING; - - if (!g_FileMenu.GetItem(i, true, item)) - break; - - { - if (!programMenu && item.wID == IDCLOSE) - continue; - - if (item.wID == IDM_DIFF && diffPath.IsEmpty()) - continue; - - if (item.wID == IDM_OPEN_INSIDE_ONE || item.wID == IDM_OPEN_INSIDE_PARSER) - { - // We use diff as "super mode" marker for additional commands. - /* - if (diffPath.IsEmpty()) - continue; - */ - } - - if (item.wID == IDM_BENCHMARK2) - { - // We use diff as "super mode" marker for additional commands. - if (diffPath.IsEmpty()) - continue; - } - - bool isOneFsFile = (isFsFolder && numItems == 1 && allAreFiles); - bool disable = (!isOneFsFile && (item.wID == IDM_SPLIT || item.wID == IDM_COMBINE)); - - if (readOnly) - { - switch (item.wID) - { - case IDM_RENAME: - case IDM_MOVE_TO: - case IDM_DELETE: - case IDM_COMMENT: - case IDM_CREATE_FOLDER: - case IDM_CREATE_FILE: - disable = true; - } - } - - if (isHashFolder) - { - switch (item.wID) - { - case IDM_OPEN: - case IDM_OPEN_INSIDE: - case IDM_OPEN_INSIDE_ONE: - case IDM_OPEN_INSIDE_PARSER: - case IDM_OPEN_OUTSIDE: - case IDM_FILE_VIEW: - case IDM_FILE_EDIT: - // case IDM_RENAME: - case IDM_COPY_TO: - case IDM_MOVE_TO: - // case IDM_DELETE: - case IDM_COMMENT: - case IDM_CREATE_FOLDER: - case IDM_CREATE_FILE: - case IDM_LINK: - case IDM_DIFF: - disable = true; - } - } - - - if (item.wID == IDM_LINK && numItems != 1) - disable = true; - - if (item.wID == IDM_ALT_STREAMS) - disable = !isAltStreamsSupported; - - if (!isBigScreen && (disable || item.IsSeparator())) - continue; - - CopyPopMenu_IfRequired(item); - if (destMenu.InsertItem(startPos, true, item)) - { - if (disable) - destMenu.EnableItem(startPos, MF_BYPOSITION | MF_GRAYED); - startPos++; - } - - if (!item.IsSeparator()) - numRealItems = startPos; - } - } - - UString vercPath; - if (!diffPath.IsEmpty() && isFsFolder && allAreFiles && numItems == 1) - ReadReg_VerCtrlPath(vercPath); - - if (!vercPath.IsEmpty()) - { - NFile::NFind::CFileInfo fi; - if (fi.Find(FilePath) && fi.Size < ((UInt32)1 << 31) && !fi.IsDir()) - { - for (unsigned k = 0; k < Z7_ARRAY_SIZE(g_Zvc_IDs); k++) - { - const unsigned id = g_Zvc_IDs[k]; - if (fi.IsReadOnly()) - { - if (id == IDM_VER_COMMIT || - id == IDM_VER_REVERT || - id == IDM_VER_DIFF) - continue; - } - else - { - if (id == IDM_VER_EDIT) - continue; - } - - CMenuItem item; - UString s (g_Zvc_Strings[k]); - if (destMenu.AppendItem(MF_STRING, id, s)) - { - startPos++; - numRealItems = startPos; - } - } - } - } - - destMenu.RemoveAllItemsFrom(numRealItems); -} - -bool ExecuteFileCommand(unsigned id) -{ - if (id >= kMenuCmdID_Plugin_Start) - { - g_App.GetFocusedPanel().InvokePluginCommand(id); - g_App.GetFocusedPanel()._sevenZipContextMenu.Release(); - g_App.GetFocusedPanel()._systemContextMenu.Release(); - return true; - } - - switch (id) - { - // File - case IDM_OPEN: g_App.OpenItem(); break; - - case IDM_OPEN_INSIDE: g_App.OpenItemInside(NULL); break; - case IDM_OPEN_INSIDE_ONE: g_App.OpenItemInside(L"*"); break; - case IDM_OPEN_INSIDE_PARSER: g_App.OpenItemInside(L"#"); break; - - case IDM_OPEN_OUTSIDE: g_App.OpenItemOutside(); break; - case IDM_FILE_VIEW: g_App.EditItem(false); break; - case IDM_FILE_EDIT: g_App.EditItem(true); break; - case IDM_RENAME: g_App.Rename(); break; - case IDM_COPY_TO: g_App.CopyTo(); break; - case IDM_MOVE_TO: g_App.MoveTo(); break; - case IDM_DELETE: g_App.Delete(!IsKeyDown(VK_SHIFT)); break; - - case IDM_HASH_ALL: g_App.CalculateCrc("*"); break; - case IDM_CRC32: g_App.CalculateCrc("CRC32"); break; - case IDM_CRC64: g_App.CalculateCrc("CRC64"); break; - case IDM_XXH64: g_App.CalculateCrc("XXH64"); break; - case IDM_SHA1: g_App.CalculateCrc("SHA1"); break; - case IDM_SHA256: g_App.CalculateCrc("SHA256"); break; - case IDM_BLAKE2SP: g_App.CalculateCrc("BLAKE2sp"); break; - - case IDM_DIFF: g_App.DiffFiles(); break; - - case IDM_VER_EDIT: - case IDM_VER_COMMIT: - case IDM_VER_REVERT: - case IDM_VER_DIFF: - g_App.VerCtrl(id); break; - - case IDM_SPLIT: g_App.Split(); break; - case IDM_COMBINE: g_App.Combine(); break; - case IDM_PROPERTIES: g_App.Properties(); break; - case IDM_COMMENT: g_App.Comment(); break; - case IDM_CREATE_FOLDER: g_App.CreateFolder(); break; - case IDM_CREATE_FILE: g_App.CreateFile(); break; - #ifndef UNDER_CE - case IDM_LINK: g_App.Link(); break; - case IDM_ALT_STREAMS: g_App.OpenAltStreams(); break; - #endif - default: return false; - } - return true; -} - -static void MyBenchmark(bool totalMode) -{ - CPanel::CDisableTimerProcessing disableTimerProcessing1(g_App.Panels[0]); - CPanel::CDisableTimerProcessing disableTimerProcessing2(g_App.Panels[1]); - Benchmark(totalMode); -} - -bool OnMenuCommand(HWND hWnd, unsigned id) -{ - if (ExecuteFileCommand(id)) - return true; - - switch (id) - { - // File - case IDCLOSE: - SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd); - g_ExitEventLauncher.Exit(false); - SendMessage(hWnd, WM_CLOSE, 0, 0); - break; - - // Edit - /* - case IDM_EDIT_CUT: - g_App.EditCut(); - break; - case IDM_EDIT_COPY: - g_App.EditCopy(); - break; - case IDM_EDIT_PASTE: - g_App.EditPaste(); - break; - */ - case IDM_SELECT_ALL: - g_App.SelectAll(true); - g_App.Refresh_StatusBar(); - break; - case IDM_DESELECT_ALL: - g_App.SelectAll(false); - g_App.Refresh_StatusBar(); - break; - case IDM_INVERT_SELECTION: - g_App.InvertSelection(); - g_App.Refresh_StatusBar(); - break; - case IDM_SELECT: - g_App.SelectSpec(true); - g_App.Refresh_StatusBar(); - break; - case IDM_DESELECT: - g_App.SelectSpec(false); - g_App.Refresh_StatusBar(); - break; - case IDM_SELECT_BY_TYPE: - g_App.SelectByType(true); - g_App.Refresh_StatusBar(); - break; - case IDM_DESELECT_BY_TYPE: - g_App.SelectByType(false); - g_App.Refresh_StatusBar(); - break; - - //View - case IDM_VIEW_LARGE_ICONS: - case IDM_VIEW_SMALL_ICONS: - case IDM_VIEW_LIST: - case IDM_VIEW_DETAILS: - { - UINT index = id - IDM_VIEW_LARGE_ICONS; - if (index < 4) - { - g_App.SetListViewMode(index); - /* - CMenu menu; - menu.Attach(::GetSubMenu(::GetMenu(hWnd), k_MenuIndex_View)); - menu.CheckRadioItem(IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS, - id, MF_BYCOMMAND); - */ - } - break; - } - case IDM_VIEW_ARANGE_BY_NAME: g_App.SortItemsWithPropID(kpidName); break; - case IDM_VIEW_ARANGE_BY_TYPE: g_App.SortItemsWithPropID(kpidExtension); break; - case IDM_VIEW_ARANGE_BY_DATE: g_App.SortItemsWithPropID(kpidMTime); break; - case IDM_VIEW_ARANGE_BY_SIZE: g_App.SortItemsWithPropID(kpidSize); break; - case IDM_VIEW_ARANGE_NO_SORT: g_App.SortItemsWithPropID(kpidNoProperty); break; - - case IDM_OPEN_ROOT_FOLDER: g_App.OpenRootFolder(); break; - case IDM_OPEN_PARENT_FOLDER: g_App.OpenParentFolder(); break; - case IDM_FOLDERS_HISTORY: g_App.FoldersHistory(); break; - case IDM_VIEW_FLAT_VIEW: g_App.ChangeFlatMode(); break; - case IDM_VIEW_REFRESH: g_App.RefreshView(); break; - case IDM_VIEW_AUTO_REFRESH: g_App.Change_AutoRefresh_Mode(); break; - - // case IDM_VIEW_SHOW_STREAMS: g_App.Change_ShowNtfsStrems_Mode(); break; - /* - case IDM_VIEW_SHOW_DELETED: - { - g_App.Change_ShowDeleted(); - bool isChecked = g_App.ShowDeletedFiles; - Save_ShowDeleted(isChecked); - } - */ - - case IDM_VIEW_TWO_PANELS: g_App.SwitchOnOffOnePanel(); break; - case IDM_VIEW_STANDARD_TOOLBAR: g_App.SwitchStandardToolbar(); break; - case IDM_VIEW_ARCHIVE_TOOLBAR: g_App.SwitchArchiveToolbar(); break; - - case IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT: g_App.SwitchButtonsLables(); break; - case IDM_VIEW_TOOLBARS_LARGE_BUTTONS: g_App.SwitchLargeButtons(); break; - - case IDM_VIEW_TIME_UTC: - g_Timestamp_Show_UTC = !g_Timestamp_Show_UTC; - g_App.RedrawListItems_InPanels(); - break; - - // Tools - case IDM_OPTIONS: OptionsDialog(hWnd, g_hInstance); break; - - case IDM_BENCHMARK: MyBenchmark(false); break; - case IDM_BENCHMARK2: MyBenchmark(true); break; - - // Help - case IDM_HELP_CONTENTS: - ShowHelpWindow(kFMHelpTopic); - break; - case IDM_ABOUT: - { - CAboutDialog dialog; - dialog.Create(hWnd); - break; - } - - case IDM_TEMP_DIR: - { - /* - CPanel &panel = g_App.GetFocusedPanel(); - FString tempPathF; - if (NFile::NDir::MyGetTempPath(tempPathF)) - panel.BindToPathAndRefresh(tempPathF); - */ - MyBrowseForTempFolder(g_HWND); - break; - } - - default: - { - if (id >= k_MenuID_OpenBookmark && id <= k_MenuID_OpenBookmark + 9) - { - g_App.OpenBookmark(id - k_MenuID_OpenBookmark); - return true; - } - else if (id >= k_MenuID_SetBookmark && id <= k_MenuID_SetBookmark + 9) - { - g_App.SetBookmark(id - k_MenuID_SetBookmark); - return true; - } - else if (id >= k_MenuID_Time && (unsigned)id < k_MenuID_Time + g_App._timestampLevels.Size()) - { - g_App.SetTimestampLevel(g_App._timestampLevels[id - k_MenuID_Time]); - return true; - } - return false; - } - } - return true; -} +// MyLoadMenu.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/TimeUtils.h" +#include "../../../Windows/Control/Dialog.h" + +#include "../../PropID.h" + +#include "../Common/CompressCall.h" + +#include "AboutDialog.h" +#include "App.h" +#include "BrowseDialog2.h" +#include "HelpUtils.h" +#include "LangUtils.h" +#include "MyLoadMenu.h" +#include "RegistryUtils.h" + +#include "PropertyNameRes.h" +#include "resource.h" + +using namespace NWindows; + +static const UINT k_MenuID_OpenBookmark = 830; +static const UINT k_MenuID_SetBookmark = 810; +static const UINT k_MenuID_TimePopup = IDM_VIEW_TIME_POPUP; +static const UINT k_MenuID_Time = IDM_VIEW_TIME; + +#if 0 +// static const UINT k_MenuID_Bookmark_Temp = 850; +#endif + +extern HINSTANCE g_hInstance; + +#define kFMHelpTopic "FM/index.htm" + +extern void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance); + +enum +{ + k_MenuIndex_File = 0, + k_MenuIndex_Edit, + k_MenuIndex_View, + k_MenuIndex_Bookmarks +}; + +#ifdef Z7_LANG +static const UInt32 k_LangID_TopMenuItems[] = +{ + IDM_FILE, + IDM_EDIT, + IDM_VIEW, + IDM_FAVORITES, + IDM_TOOLS, + IDM_HELP +}; + +static const UInt32 k_LangID_Toolbars = IDM_VIEW_TOOLBARS; +static const UInt32 k_LangID_AddToFavorites = IDM_ADD_TO_FAVORITES; + +static const CIDLangPair kIDLangPairs[] = +{ + { IDCLOSE, 557 }, // IDM_EXIT + { IDM_VIEW_ARANGE_BY_NAME, IDS_PROP_NAME }, + { IDM_VIEW_ARANGE_BY_TYPE, IDS_PROP_FILE_TYPE }, + { IDM_VIEW_ARANGE_BY_DATE, IDS_PROP_MTIME }, + { IDM_VIEW_ARANGE_BY_SIZE, IDS_PROP_SIZE } +}; + +static int FindLangItem(unsigned controlID) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDLangPairs); i++) + if (kIDLangPairs[i].ControlID == controlID) + return (int)i; + return -1; +} +#endif + +static unsigned GetSortControlID(PROPID propID) +{ + switch (propID) + { + case kpidName: return IDM_VIEW_ARANGE_BY_NAME; + case kpidExtension: return IDM_VIEW_ARANGE_BY_TYPE; + case kpidMTime: return IDM_VIEW_ARANGE_BY_DATE; + case kpidSize: return IDM_VIEW_ARANGE_BY_SIZE; + case kpidNoProperty: return IDM_VIEW_ARANGE_NO_SORT; + } + return IDM_VIEW_ARANGE_BY_NAME; + // IDM_VIEW_ARANGE_NO_SORT; + // return -1; +} + +/* +#if _MSC_VER > 1400 +// GetVersion was declared deprecated +#pragma warning(disable : 4996) +#endif + +static bool g_IsNew_fMask = false; +static class CInit_fMask +{ +public: + CInit_fMask() + { + DWORD v = GetVersion(); + v = ((v & 0xff) << 8) | ((v >> 8) & 0xFF); + g_IsNew_fMask = (v > 0x400); // (win98/win2000) or newer + } +} g_Init_fMask; +static UINT Get_fMask_for_String() + { return g_IsNew_fMask ? MIIM_STRING : MIIM_TYPE; } +static UINT Get_fMask_for_FType_and_String() + { return g_IsNew_fMask ? (MIIM_STRING | MIIM_FTYPE) : MIIM_TYPE; } +*/ + +/* +We can use new MIIM_STRING / MIIM_FTYPE flags in the following conditions: + 1) we run at new Windows (win98/win2000) or newer + 2) also we probably must set MENUITEMINFO::cbSize as sizeof of full + (MENUITEMINFO) that was compiled with (WINVER >= 0x0500) +But it's simpler to use old MIIM_TYPE without these complex checks. +*/ + +// /* +static inline UINT Get_fMask_for_String() { return MIIM_TYPE; } +static inline UINT Get_fMask_for_FType_and_String() { return MIIM_TYPE; } +// */ + +static bool Is_MenuItem_TimePopup(const CMenuItem &item) +{ + return item.wID == k_MenuID_TimePopup || + item.StringValue.IsPrefixedBy_Ascii_NoCase("20"); +} + +#ifdef Z7_LANG +static void MyChangeMenu(HMENU menuLoc, unsigned menuID, unsigned level, unsigned menuIndex) +{ + CMenu menu; + menu.Attach(menuLoc); + + for (unsigned i = 0;; i++) + { + CMenuItem item; + /* here we can use + Get_fMask_for_String() or + Get_fMask_for_FType_and_String() + We want to change only String of menu item. + It's not required to change (fType) of menu item. + We can look (fType) to check for SEPARATOR item. + But String of separator is empty and (wID == 0). + So we can check for SEPARATOR without (fType) requesting. + So it's enough to use Get_fMask_for_String() here */ + item.fMask = + Get_fMask_for_String() + // Get_fMask_for_FType_and_String() + | MIIM_SUBMENU | MIIM_ID; + if (!menu.GetItem(i, true, item)) + break; + { + UString newString; + if (item.hSubMenu) + { + /* in win10: + MENU+POPUP: + (wID == item.hSubMenu) + MENUEX+POPUP where ID is not set: + (wID == 0) + MENU+SEPARATOR + (wID == 0) + */ + UInt32 langID = item.wID; + if (langID >= (1 << 16)) + { + // here we try to exclude the case (wID == item.hSubMenu) if (MENU+POPUP) + continue; + } + if (langID == 0) + { + if (level == 0) + { + if (i < Z7_ARRAY_SIZE(k_LangID_TopMenuItems)) + langID = k_LangID_TopMenuItems[i]; + } + else if (level == 1) + { + if (menuID == IDM_FAVORITES || (menuID == 0 && menuIndex == k_MenuIndex_Bookmarks)) + langID = k_LangID_AddToFavorites; + else if (menuID == IDM_VIEW || (menuID == 0 && menuIndex == k_MenuIndex_View)) + { + if (Is_MenuItem_TimePopup(item)) + langID = k_MenuID_TimePopup; + else + langID = k_LangID_Toolbars; + } + } + } + if (langID == k_MenuID_TimePopup) + continue; + if (langID != k_LangID_AddToFavorites) + MyChangeMenu(item.hSubMenu, langID, level + 1, i); + if (langID == 0) + continue; + LangString_OnlyFromLangFile(langID, newString); + if (newString.IsEmpty()) + continue; + } + else + { + if (item.fMask & (MIIM_TYPE | MIIM_FTYPE)) + if (item.IsSeparator()) + continue; + if (item.StringValue.IsEmpty()) + continue; + const int langPos = FindLangItem(item.wID); + // we don't need lang change for CRC items!!! + const UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID; + if (langID == 0) + continue; + + if (langID == IDM_OPEN_INSIDE_ONE || + langID == IDM_OPEN_INSIDE_PARSER) + { + LangString_OnlyFromLangFile(IDM_OPEN_INSIDE, newString); + if (newString.IsEmpty()) + continue; + newString.Replace(L"&", L""); + const int tabPos = newString.Find(L"\t"); + if (tabPos >= 0) + newString.DeleteFrom(tabPos); + newString += (langID == IDM_OPEN_INSIDE_ONE ? " *" : " #"); + } + else if (langID == IDM_BENCHMARK2) + { + LangString_OnlyFromLangFile(IDM_BENCHMARK, newString); + if (newString.IsEmpty()) + continue; + newString.Replace(L"&", L""); + const int tabPos = newString.Find(L"\t"); + if (tabPos >= 0) + newString.DeleteFrom(tabPos); + newString += " 2"; + } + else + { + LangString_OnlyFromLangFile(langID, newString); + } + + if (newString.IsEmpty()) + continue; + + const int tabPos = item.StringValue.ReverseFind(L'\t'); + if (tabPos >= 0) + newString += item.StringValue.Ptr(tabPos); + } + + { + item.StringValue = newString; + // we want to change only String + item.fMask = Get_fMask_for_String(); + menu.SetItem(i, true, item); + } + } + } +} +#endif + +static CMenu g_FileMenu; + +static struct CFileMenuDestroyer +{ + ~CFileMenuDestroyer() { if ((HMENU)g_FileMenu) g_FileMenu.Destroy(); } +} g_FileMenuDestroyer; + + +static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec); + +static void CopyPopMenu_IfRequired(CMenuItem &item) +{ + /* if (item.hSubMenu) is defined + { + - it creates new (popup) menu + - it copies menu items from old item.hSubMenu menu to new (popup) menu + - it sets item.hSubMenu to handle of created (popup) menu + } */ + if (item.hSubMenu) + { + CMenu popup; + popup.CreatePopup(); + CopyMenu(item.hSubMenu, popup); + item.hSubMenu = popup; + } +} + +/* destMenuSpec must be non-NULL handle to created empty popup menu */ +static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec) +{ + CMenu srcMenu; + srcMenu.Attach(srcMenuSpec); + CMenu destMenu; + destMenu.Attach(destMenuSpec); + unsigned startPos = 0; + for (unsigned i = 0;; i++) + { + CMenuItem item; + item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String(); + if (!srcMenu.GetItem(i, true, item)) + break; + CopyPopMenu_IfRequired(item); + if (destMenu.InsertItem(startPos, true, item)) + startPos++; + } +} + + +/* use for (needResetMenu): + false : for call from program window creation code + true : for another calls : (from Options language change) +*/ +void MyLoadMenu(bool needResetMenu) +{ + #ifdef UNDER_CE + + const HMENU oldMenu = g_App._commandBar.GetMenu(0); + if (oldMenu) + ::DestroyMenu(oldMenu); + /* BOOL b = */ g_App._commandBar.InsertMenubar(g_hInstance, IDM_MENU, 0); + const HMENU baseMenu = g_App._commandBar.GetMenu(0); + // if (startInit) + // SetIdsForSubMenus(baseMenu, 0, 0); + if (!g_LangID.IsEmpty()) + MyChangeMenu(baseMenu, 0, 0); + g_App._commandBar.DrawMenuBar(0); + + #else // UNDER_CE + + const HWND hWnd = g_HWND; + bool menuWasChanged = false; + /* + We must reload to english default menu for at least two cases: + - if some submenu was changed (File or another submenu can be changed after menu activating). + - for change from non-english lang to another partial non-english lang, + where we still need some english strings. + But we reload menu to default menu everytime except of program starting stage. + That scheme is simpler than complex checks for exact conditions for menu reload. + */ + if (needResetMenu) + { + const HMENU oldMenu = ::GetMenu(hWnd); + const HMENU newMenu = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_MENU)); + // docs for SetMenu(): the window is redrawn to reflect the menu change. + if (newMenu && ::SetMenu(hWnd, newMenu)) + ::DestroyMenu(oldMenu); + menuWasChanged = true; + } + const HMENU baseMenu = ::GetMenu(hWnd); + // if (startInit) + // SetIdsForSubMenus(baseMenu, 0, 0); + #ifdef Z7_LANG + if (!g_Lang.IsEmpty()) // !g_LangID.IsEmpty() && + { + MyChangeMenu(baseMenu, 0, 0, 0); + menuWasChanged = true; + } + #endif + + if (menuWasChanged) + ::DrawMenuBar(hWnd); + + #endif // UNDER_CE + + // menuWasChanged = false; // for debug + if (menuWasChanged || !(HMENU)g_FileMenu) + { + if ((HMENU)g_FileMenu) + g_FileMenu.Destroy(); + g_FileMenu.CreatePopup(); + CopyMenu(::GetSubMenu(baseMenu, k_MenuIndex_File), g_FileMenu); + } +} + +void OnMenuActivating(HWND /* hWnd */, HMENU hMenu, int position) +{ + HMENU mainMenu = + #ifdef UNDER_CE + g_App._commandBar.GetMenu(0); + #else + ::GetMenu(g_HWND) + #endif + ; + + if (::GetSubMenu(mainMenu, position) != hMenu) + return; + + if (position == k_MenuIndex_File) + { + CMenu menu; + menu.Attach(hMenu); + menu.RemoveAllItems(); + g_App.GetFocusedPanel().CreateFileMenu(hMenu); + } + else if (position == k_MenuIndex_Edit) + { + /* + CMenu menu; + menu.Attach(hMenu); + menu.EnableItem(IDM_EDIT_CUT, MF_ENABLED); + menu.EnableItem(IDM_EDIT_COPY, MF_ENABLED); + menu.EnableItem(IDM_EDIT_PASTE, IsClipboardFormatAvailableHDROP() ? MF_ENABLED : MF_GRAYED); + */ + } + else if (position == k_MenuIndex_View) + { + // View; + CMenu menu; + menu.Attach(hMenu); + menu.CheckRadioItem( + IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS, + IDM_VIEW_LARGE_ICONS + g_App.GetListViewMode(), MF_BYCOMMAND); + + menu.CheckRadioItem( + IDM_VIEW_ARANGE_BY_NAME, + IDM_VIEW_ARANGE_NO_SORT, + GetSortControlID(g_App.GetSortID()), + MF_BYCOMMAND); + + menu.CheckItemByID(IDM_VIEW_TWO_PANELS, g_App.NumPanels == 2); + menu.CheckItemByID(IDM_VIEW_FLAT_VIEW, g_App.GetFlatMode()); + menu.CheckItemByID(IDM_VIEW_ARCHIVE_TOOLBAR, g_App.ShowArchiveToolbar); + menu.CheckItemByID(IDM_VIEW_STANDARD_TOOLBAR, g_App.ShowStandardToolbar); + menu.CheckItemByID(IDM_VIEW_TOOLBARS_LARGE_BUTTONS, g_App.LargeButtons); + menu.CheckItemByID(IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT, g_App.ShowButtonsLables); + menu.CheckItemByID(IDM_VIEW_AUTO_REFRESH, g_App.Get_AutoRefresh_Mode()); + // menu.CheckItemByID(IDM_VIEW_SHOW_STREAMS, g_App.Get_ShowNtfsStrems_Mode()); + // menu.CheckItemByID(IDM_VIEW_SHOW_DELETED, g_App.ShowDeletedFiles); + + for (unsigned i = 0;; i++) + { + CMenuItem item; + item.fMask = Get_fMask_for_String() | MIIM_SUBMENU | MIIM_ID; + item.fType = MFT_STRING; + if (!menu.GetItem(i, true, item)) + break; + if (item.hSubMenu && Is_MenuItem_TimePopup(item)) + { + FILETIME ft; + NTime::GetCurUtcFileTime(ft); + + { + wchar_t s[64]; + s[0] = 0; + if (ConvertUtcFileTimeToString(ft, s, kTimestampPrintLevel_DAY)) + item.StringValue = s; + } + + item.fMask = Get_fMask_for_String() | MIIM_ID; + item.fType = MFT_STRING; + item.wID = k_MenuID_TimePopup; + menu.SetItem(i, true, item); + + CMenu subMenu; + subMenu.Attach(menu.GetSubMenu((int)i)); + subMenu.RemoveAllItems(); + + const int k_TimeLevels[] = + { + kTimestampPrintLevel_DAY, + kTimestampPrintLevel_MIN, + kTimestampPrintLevel_SEC, + // 1,2,3,4,5,6, + kTimestampPrintLevel_NTFS, + kTimestampPrintLevel_NS + }; + + unsigned last = k_MenuID_Time; + unsigned selectedCommand = 0; + g_App._timestampLevels.Clear(); + unsigned id = k_MenuID_Time; + + for (unsigned k = 0; k < Z7_ARRAY_SIZE(k_TimeLevels); k++) + { + wchar_t s[64]; + s[0] = 0; + const int timestampLevel = k_TimeLevels[k]; + if (ConvertUtcFileTimeToString(ft, s, timestampLevel)) + { + if (subMenu.AppendItem(MF_STRING, id, s)) + { + last = id; + g_App._timestampLevels.Add(timestampLevel); + if (g_App.GetTimestampLevel() == timestampLevel) + selectedCommand = id; + id++; + } + } + } + if (selectedCommand != 0) + menu.CheckRadioItem(k_MenuID_Time, last, selectedCommand, MF_BYCOMMAND); + + if (subMenu.AppendItem(MF_STRING, IDM_VIEW_TIME_UTC, L"UTC")) + subMenu.CheckItemByID(IDM_VIEW_TIME_UTC, g_Timestamp_Show_UTC); + } + } + } + else if (position == k_MenuIndex_Bookmarks) + { + CMenu menu; + menu.Attach(hMenu); + + CMenu subMenu; + subMenu.Attach(menu.GetSubMenu(0)); + subMenu.RemoveAllItems(); + unsigned i; + + for (i = 0; i < 10; i++) + { + UString s = LangString(IDS_BOOKMARK); + s.Add_Space(); + const char c = (char)(L'0' + i); + s.Add_Char(c); + s += "\tAlt+Shift+"; + s.Add_Char(c); + subMenu.AppendItem(MF_STRING, k_MenuID_SetBookmark + i, s); + } + + menu.RemoveAllItemsFrom(2); + + for (i = 0; i < 10; i++) + { + UString s = g_App.AppState.FastFolders.GetString(i); + const int kMaxSize = 100; + const int kFirstPartSize = kMaxSize / 2; + if (s.Len() > kMaxSize) + { + s.Delete(kFirstPartSize, s.Len() - kMaxSize); + s.Insert(kFirstPartSize, L" ... "); + } + if (s.IsEmpty()) + s = '-'; + s += "\tAlt+"; + s.Add_Char((char)('0' + i)); + menu.AppendItem(MF_STRING, k_MenuID_OpenBookmark + i, s); + } +#if 0 + { + FString tempPathF; + if (NFile::NDir::MyGetTempPath(tempPathF)) + { + menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); + UString s; + s = "Temp : "; + s += fs2us(tempPathF); + menu.AppendItem(MF_STRING, k_MenuID_Bookmark_Temp, s); + } + } +#endif + } +} + +/* +It doesn't help +void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id) +{ + if (::GetSubMenu(::GetMenu(g_HWND), 0) != hMenu) + return; +} +*/ + +static const unsigned g_Zvc_IDs[] = +{ + IDM_VER_EDIT, + IDM_VER_COMMIT, + IDM_VER_REVERT, + IDM_VER_DIFF +}; + +static const char * const g_Zvc_Strings[] = +{ + "Ver Edit (&1)" + , "Ver Commit" + , "Ver Revert" + , "Ver Diff (&0)" +}; + +void CFileMenu::Load(HMENU hMenu, unsigned startPos) +{ + CMenu destMenu; + destMenu.Attach(hMenu); + + UString diffPath; + ReadRegDiff(diffPath); + + unsigned numRealItems = startPos; + + const bool isBigScreen = NControl::IsDialogSizeOK(40, 200, g_HWND); + + for (unsigned i = 0;; i++) + { + CMenuItem item; + + item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String(); + item.fType = MFT_STRING; + + if (!g_FileMenu.GetItem(i, true, item)) + break; + + { + if (!programMenu && item.wID == IDCLOSE) + continue; + + if (item.wID == IDM_DIFF && diffPath.IsEmpty()) + continue; + + if (item.wID == IDM_OPEN_INSIDE_ONE || item.wID == IDM_OPEN_INSIDE_PARSER) + { + // We use diff as "super mode" marker for additional commands. + /* + if (diffPath.IsEmpty()) + continue; + */ + } + + if (item.wID == IDM_BENCHMARK2) + { + // We use diff as "super mode" marker for additional commands. + if (diffPath.IsEmpty()) + continue; + } + + bool isOneFsFile = (isFsFolder && numItems == 1 && allAreFiles); + bool disable = (!isOneFsFile && (item.wID == IDM_SPLIT || item.wID == IDM_COMBINE)); + + if (readOnly) + { + switch (item.wID) + { + case IDM_RENAME: + case IDM_MOVE_TO: + case IDM_DELETE: + case IDM_COMMENT: + case IDM_CREATE_FOLDER: + case IDM_CREATE_FILE: + disable = true; + } + } + + if (isHashFolder) + { + switch (item.wID) + { + case IDM_OPEN: + case IDM_OPEN_INSIDE: + case IDM_OPEN_INSIDE_ONE: + case IDM_OPEN_INSIDE_PARSER: + case IDM_OPEN_OUTSIDE: + case IDM_FILE_VIEW: + case IDM_FILE_EDIT: + // case IDM_RENAME: + case IDM_COPY_TO: + case IDM_MOVE_TO: + // case IDM_DELETE: + case IDM_COMMENT: + case IDM_CREATE_FOLDER: + case IDM_CREATE_FILE: + case IDM_LINK: + case IDM_DIFF: + disable = true; + } + } + + + if (item.wID == IDM_LINK && numItems != 1) + disable = true; + + if (item.wID == IDM_ALT_STREAMS) + disable = !isAltStreamsSupported; + + if (!isBigScreen && (disable || item.IsSeparator())) + continue; + + CopyPopMenu_IfRequired(item); + if (destMenu.InsertItem(startPos, true, item)) + { + if (disable) + destMenu.EnableItem(startPos, MF_BYPOSITION | MF_GRAYED); + startPos++; + } + + if (!item.IsSeparator()) + numRealItems = startPos; + } + } + + UString vercPath; + if (!diffPath.IsEmpty() && isFsFolder && allAreFiles && numItems == 1) + ReadReg_VerCtrlPath(vercPath); + + if (!vercPath.IsEmpty()) + { + NFile::NFind::CFileInfo fi; + if (fi.Find(FilePath) && fi.Size < ((UInt32)1 << 31) && !fi.IsDir()) + { + for (unsigned k = 0; k < Z7_ARRAY_SIZE(g_Zvc_IDs); k++) + { + const unsigned id = g_Zvc_IDs[k]; + if (fi.IsReadOnly()) + { + if (id == IDM_VER_COMMIT || + id == IDM_VER_REVERT || + id == IDM_VER_DIFF) + continue; + } + else + { + if (id == IDM_VER_EDIT) + continue; + } + + CMenuItem item; + UString s (g_Zvc_Strings[k]); + if (destMenu.AppendItem(MF_STRING, id, s)) + { + startPos++; + numRealItems = startPos; + } + } + } + } + + destMenu.RemoveAllItemsFrom(numRealItems); +} + +bool ExecuteFileCommand(unsigned id) +{ + if (id >= kMenuCmdID_Plugin_Start) + { + g_App.GetFocusedPanel().InvokePluginCommand(id); + g_App.GetFocusedPanel()._sevenZipContextMenu.Release(); + g_App.GetFocusedPanel()._systemContextMenu.Release(); + return true; + } + + switch (id) + { + // File + case IDM_OPEN: g_App.OpenItem(); break; + + case IDM_OPEN_INSIDE: g_App.OpenItemInside(NULL); break; + case IDM_OPEN_INSIDE_ONE: g_App.OpenItemInside(L"*"); break; + case IDM_OPEN_INSIDE_PARSER: g_App.OpenItemInside(L"#"); break; + + case IDM_OPEN_OUTSIDE: g_App.OpenItemOutside(); break; + case IDM_FILE_VIEW: g_App.EditItem(false); break; + case IDM_FILE_EDIT: g_App.EditItem(true); break; + case IDM_RENAME: g_App.Rename(); break; + case IDM_COPY_TO: g_App.CopyTo(); break; + case IDM_MOVE_TO: g_App.MoveTo(); break; + case IDM_DELETE: g_App.Delete(!IsKeyDown(VK_SHIFT)); break; + + case IDM_HASH_ALL: g_App.CalculateCrc("*"); break; + case IDM_CRC32: g_App.CalculateCrc("CRC32"); break; + case IDM_CRC64: g_App.CalculateCrc("CRC64"); break; + case IDM_XXH64: g_App.CalculateCrc("XXH64"); break; + case IDM_MD5: g_App.CalculateCrc("MD5"); break; + case IDM_SHA1: g_App.CalculateCrc("SHA1"); break; + case IDM_SHA256: g_App.CalculateCrc("SHA256"); break; + case IDM_SHA384: g_App.CalculateCrc("SHA384"); break; + case IDM_SHA512: g_App.CalculateCrc("SHA512"); break; + case IDM_SHA3_256: g_App.CalculateCrc("SHA3-256"); break; + case IDM_BLAKE2SP: g_App.CalculateCrc("BLAKE2sp"); break; + + case IDM_DIFF: g_App.DiffFiles(); break; + + case IDM_VER_EDIT: + case IDM_VER_COMMIT: + case IDM_VER_REVERT: + case IDM_VER_DIFF: + g_App.VerCtrl(id); break; + + case IDM_SPLIT: g_App.Split(); break; + case IDM_COMBINE: g_App.Combine(); break; + case IDM_PROPERTIES: g_App.Properties(); break; + case IDM_COMMENT: g_App.Comment(); break; + case IDM_CREATE_FOLDER: g_App.CreateFolder(); break; + case IDM_CREATE_FILE: g_App.CreateFile(); break; + #ifndef UNDER_CE + case IDM_LINK: g_App.Link(); break; + case IDM_ALT_STREAMS: g_App.OpenAltStreams(); break; + #endif + default: return false; + } + return true; +} + +static void MyBenchmark(bool totalMode) +{ + CPanel::CDisableTimerProcessing disableTimerProcessing1(g_App.Panels[0]); + CPanel::CDisableTimerProcessing disableTimerProcessing2(g_App.Panels[1]); + Benchmark(totalMode); +} + +bool OnMenuCommand(HWND hWnd, unsigned id) +{ + if (ExecuteFileCommand(id)) + return true; + + switch (id) + { + // File + case IDCLOSE: + // SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd); + // g_ExitEventLauncher.Exit(false); + SendMessage(hWnd, WM_CLOSE, 0, 0); + break; + + // Edit + /* + case IDM_EDIT_CUT: + g_App.EditCut(); + break; + case IDM_EDIT_COPY: + g_App.EditCopy(); + break; + case IDM_EDIT_PASTE: + g_App.EditPaste(); + break; + */ + case IDM_SELECT_ALL: + g_App.SelectAll(true); + g_App.Refresh_StatusBar(); + break; + case IDM_DESELECT_ALL: + g_App.SelectAll(false); + g_App.Refresh_StatusBar(); + break; + case IDM_INVERT_SELECTION: + g_App.InvertSelection(); + g_App.Refresh_StatusBar(); + break; + case IDM_SELECT: + g_App.SelectSpec(true); + g_App.Refresh_StatusBar(); + break; + case IDM_DESELECT: + g_App.SelectSpec(false); + g_App.Refresh_StatusBar(); + break; + case IDM_SELECT_BY_TYPE: + g_App.SelectByType(true); + g_App.Refresh_StatusBar(); + break; + case IDM_DESELECT_BY_TYPE: + g_App.SelectByType(false); + g_App.Refresh_StatusBar(); + break; + + //View + case IDM_VIEW_LARGE_ICONS: + case IDM_VIEW_SMALL_ICONS: + case IDM_VIEW_LIST: + case IDM_VIEW_DETAILS: + { + UINT index = id - IDM_VIEW_LARGE_ICONS; + if (index < 4) + { + g_App.SetListViewMode(index); + /* + CMenu menu; + menu.Attach(::GetSubMenu(::GetMenu(hWnd), k_MenuIndex_View)); + menu.CheckRadioItem(IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS, + id, MF_BYCOMMAND); + */ + } + break; + } + case IDM_VIEW_ARANGE_BY_NAME: g_App.SortItemsWithPropID(kpidName); break; + case IDM_VIEW_ARANGE_BY_TYPE: g_App.SortItemsWithPropID(kpidExtension); break; + case IDM_VIEW_ARANGE_BY_DATE: g_App.SortItemsWithPropID(kpidMTime); break; + case IDM_VIEW_ARANGE_BY_SIZE: g_App.SortItemsWithPropID(kpidSize); break; + case IDM_VIEW_ARANGE_NO_SORT: g_App.SortItemsWithPropID(kpidNoProperty); break; + + case IDM_OPEN_ROOT_FOLDER: g_App.OpenRootFolder(); break; + case IDM_OPEN_PARENT_FOLDER: g_App.OpenParentFolder(); break; + case IDM_FOLDERS_HISTORY: g_App.FoldersHistory(); break; + case IDM_VIEW_FLAT_VIEW: g_App.ChangeFlatMode(); break; + case IDM_VIEW_REFRESH: g_App.RefreshView(); break; + case IDM_VIEW_AUTO_REFRESH: g_App.Change_AutoRefresh_Mode(); break; + + // case IDM_VIEW_SHOW_STREAMS: g_App.Change_ShowNtfsStrems_Mode(); break; + /* + case IDM_VIEW_SHOW_DELETED: + { + g_App.Change_ShowDeleted(); + bool isChecked = g_App.ShowDeletedFiles; + Save_ShowDeleted(isChecked); + } + */ + + case IDM_VIEW_TWO_PANELS: g_App.SwitchOnOffOnePanel(); break; + case IDM_VIEW_STANDARD_TOOLBAR: g_App.SwitchStandardToolbar(); break; + case IDM_VIEW_ARCHIVE_TOOLBAR: g_App.SwitchArchiveToolbar(); break; + + case IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT: g_App.SwitchButtonsLables(); break; + case IDM_VIEW_TOOLBARS_LARGE_BUTTONS: g_App.SwitchLargeButtons(); break; + + case IDM_VIEW_TIME_UTC: + g_Timestamp_Show_UTC = !g_Timestamp_Show_UTC; + g_App.RedrawListItems_InPanels(); + break; + + // Tools + case IDM_OPTIONS: OptionsDialog(hWnd, g_hInstance); break; + + case IDM_BENCHMARK: MyBenchmark(false); break; + case IDM_BENCHMARK2: MyBenchmark(true); break; + + // Help + case IDM_HELP_CONTENTS: + ShowHelpWindow(kFMHelpTopic); + break; + case IDM_ABOUT: + { + CAboutDialog dialog; + dialog.Create(hWnd); + break; + } + + case IDM_TEMP_DIR: + { + /* + CPanel &panel = g_App.GetFocusedPanel(); + FString tempPathF; + if (NFile::NDir::MyGetTempPath(tempPathF)) + panel.BindToPathAndRefresh(tempPathF); + */ + MyBrowseForTempFolder(g_HWND); + break; + } + + default: + { + if (id >= k_MenuID_OpenBookmark && id <= k_MenuID_OpenBookmark + 9) + { + g_App.OpenBookmark(id - k_MenuID_OpenBookmark); + return true; + } + else if (id >= k_MenuID_SetBookmark && id <= k_MenuID_SetBookmark + 9) + { + g_App.SetBookmark(id - k_MenuID_SetBookmark); + return true; + } + else if (id >= k_MenuID_Time && (unsigned)id < k_MenuID_Time + g_App._timestampLevels.Size()) + { + g_App.SetTimestampLevel(g_App._timestampLevels[id - k_MenuID_Time]); + return true; + } + return false; + } + } + return true; +} diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.h b/CPP/7zip/UI/FileManager/MyLoadMenu.h index 31f41b0d4..e71dbbf66 100644 --- a/CPP/7zip/UI/FileManager/MyLoadMenu.h +++ b/CPP/7zip/UI/FileManager/MyLoadMenu.h @@ -1,40 +1,40 @@ -// MyLoadMenu.h - -#ifndef ZIP7_INC_MY_LOAD_MENU_H -#define ZIP7_INC_MY_LOAD_MENU_H - -void OnMenuActivating(HWND hWnd, HMENU hMenu, int position); -// void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id); -// void OnMenuUnActivating(HWND hWnd); - -bool OnMenuCommand(HWND hWnd, unsigned id); -void MyLoadMenu(bool needResetMenu); - -struct CFileMenu -{ - bool programMenu; - bool readOnly; - bool isHashFolder; - bool isFsFolder; - bool allAreFiles; - bool isAltStreamsSupported; - unsigned numItems; - - FString FilePath; - - CFileMenu(): - programMenu(false), - readOnly(false), - isHashFolder(false), - isFsFolder(false), - allAreFiles(false), - isAltStreamsSupported(true), - numItems(0) - {} - - void Load(HMENU hMenu, unsigned startPos); -}; - -bool ExecuteFileCommand(unsigned id); - -#endif +// MyLoadMenu.h + +#ifndef ZIP7_INC_MY_LOAD_MENU_H +#define ZIP7_INC_MY_LOAD_MENU_H + +void OnMenuActivating(HWND hWnd, HMENU hMenu, int position); +// void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id); +// void OnMenuUnActivating(HWND hWnd); + +bool OnMenuCommand(HWND hWnd, unsigned id); +void MyLoadMenu(bool needResetMenu); + +struct CFileMenu +{ + bool programMenu; + bool readOnly; + bool isHashFolder; + bool isFsFolder; + bool allAreFiles; + bool isAltStreamsSupported; + unsigned numItems; + + FString FilePath; + + CFileMenu(): + programMenu(false), + readOnly(false), + isHashFolder(false), + isFsFolder(false), + allAreFiles(false), + isAltStreamsSupported(true), + numItems(0) + {} + + void Load(HMENU hMenu, unsigned startPos); +}; + +bool ExecuteFileCommand(unsigned id); + +#endif diff --git a/CPP/7zip/UI/FileManager/MyWindowsNew.h b/CPP/7zip/UI/FileManager/MyWindowsNew.h index 129ecec11..325babcd4 100644 --- a/CPP/7zip/UI/FileManager/MyWindowsNew.h +++ b/CPP/7zip/UI/FileManager/MyWindowsNew.h @@ -1,119 +1,119 @@ -// MyWindowsNew.h - -#ifndef ZIP7_INC_MY_WINDOWS_NEW_H -#define ZIP7_INC_MY_WINDOWS_NEW_H - -#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__MINGW32_VERSION) -#include - -#if defined(__MINGW32_VERSION) && !defined(__ITaskbarList3_INTERFACE_DEFINED__) -// for old mingw -extern "C" { -DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF); -DEFINE_GUID(CLSID_TaskbarList, 0x56fdf344, 0xfd6d, 0x11d0, 0x95,0x8a, 0x00,0x60,0x97,0xc9,0xa0,0x90); -} -#endif - -#else // is not __MINGW* - -#ifndef Z7_OLD_WIN_SDK -#include -#else - -#ifndef HIMAGELIST -struct _IMAGELIST; -typedef struct _IMAGELIST* HIMAGELIST; -#endif - -#ifndef __ITaskbarList_INTERFACE_DEFINED__ -#define __ITaskbarList_INTERFACE_DEFINED__ -DEFINE_GUID(IID_ITaskbarList, 0x56FDF342, 0xFD6D, 0x11d0, 0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90); -struct ITaskbarList: public IUnknown -{ - STDMETHOD(HrInit)(void) = 0; - STDMETHOD(AddTab)(HWND hwnd) = 0; - STDMETHOD(DeleteTab)(HWND hwnd) = 0; - STDMETHOD(ActivateTab)(HWND hwnd) = 0; - STDMETHOD(SetActiveAlt)(HWND hwnd) = 0; -}; -#endif // __ITaskbarList_INTERFACE_DEFINED__ - -#ifndef __ITaskbarList2_INTERFACE_DEFINED__ -#define __ITaskbarList2_INTERFACE_DEFINED__ -DEFINE_GUID(IID_ITaskbarList2, 0x602D4995, 0xB13A, 0x429b, 0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17); -struct ITaskbarList2: public ITaskbarList -{ - STDMETHOD(MarkFullscreenWindow)(HWND hwnd, BOOL fFullscreen) = 0; -}; -#endif // __ITaskbarList2_INTERFACE_DEFINED__ - -#endif // Z7_OLD_WIN_SDK - - -#ifndef __ITaskbarList3_INTERFACE_DEFINED__ -#define __ITaskbarList3_INTERFACE_DEFINED__ - -typedef enum THUMBBUTTONFLAGS -{ - THBF_ENABLED = 0, - THBF_DISABLED = 0x1, - THBF_DISMISSONCLICK = 0x2, - THBF_NOBACKGROUND = 0x4, - THBF_HIDDEN = 0x8, - THBF_NONINTERACTIVE = 0x10 -} THUMBBUTTONFLAGS; - -typedef enum THUMBBUTTONMASK -{ - THB_BITMAP = 0x1, - THB_ICON = 0x2, - THB_TOOLTIP = 0x4, - THB_FLAGS = 0x8 -} THUMBBUTTONMASK; - -// #include - -typedef struct THUMBBUTTON -{ - THUMBBUTTONMASK dwMask; - UINT iId; - UINT iBitmap; - HICON hIcon; - WCHAR szTip[260]; - THUMBBUTTONFLAGS dwFlags; -} THUMBBUTTON; - -typedef struct THUMBBUTTON *LPTHUMBBUTTON; - -typedef enum TBPFLAG -{ - TBPF_NOPROGRESS = 0, - TBPF_INDETERMINATE = 0x1, - TBPF_NORMAL = 0x2, - TBPF_ERROR = 0x4, - TBPF_PAUSED = 0x8 -} TBPFLAG; - -DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF); - -struct ITaskbarList3: public ITaskbarList2 -{ - STDMETHOD(SetProgressValue)(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) = 0; - STDMETHOD(SetProgressState)(HWND hwnd, TBPFLAG tbpFlags) = 0; - STDMETHOD(RegisterTab)(HWND hwndTab, HWND hwndMDI) = 0; - STDMETHOD(UnregisterTab)(HWND hwndTab) = 0; - STDMETHOD(SetTabOrder)(HWND hwndTab, HWND hwndInsertBefore) = 0; - STDMETHOD(SetTabActive)(HWND hwndTab, HWND hwndMDI, DWORD dwReserved) = 0; - STDMETHOD(ThumbBarAddButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0; - STDMETHOD(ThumbBarUpdateButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0; - STDMETHOD(ThumbBarSetImageList)(HWND hwnd, HIMAGELIST himl) = 0; - STDMETHOD(SetOverlayIcon)(HWND hwnd, HICON hIcon, LPCWSTR pszDescription) = 0; - STDMETHOD(SetThumbnailTooltip)(HWND hwnd, LPCWSTR pszTip) = 0; - STDMETHOD(SetThumbnailClip)(HWND hwnd, RECT *prcClip) = 0; -}; - -#endif // __ITaskbarList3_INTERFACE_DEFINED__ - -#endif // __MINGW* - -#endif +// MyWindowsNew.h + +#ifndef ZIP7_INC_MY_WINDOWS_NEW_H +#define ZIP7_INC_MY_WINDOWS_NEW_H + +#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__MINGW32_VERSION) +#include + +#if defined(__MINGW32_VERSION) && !defined(__ITaskbarList3_INTERFACE_DEFINED__) +// for old mingw +extern "C" { +DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF); +DEFINE_GUID(CLSID_TaskbarList, 0x56fdf344, 0xfd6d, 0x11d0, 0x95,0x8a, 0x00,0x60,0x97,0xc9,0xa0,0x90); +} +#endif + +#else // is not __MINGW* + +#ifndef Z7_OLD_WIN_SDK +#include +#else + +#ifndef HIMAGELIST +struct _IMAGELIST; +typedef struct _IMAGELIST* HIMAGELIST; +#endif + +#ifndef __ITaskbarList_INTERFACE_DEFINED__ +#define __ITaskbarList_INTERFACE_DEFINED__ +DEFINE_GUID(IID_ITaskbarList, 0x56FDF342, 0xFD6D, 0x11d0, 0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90); +struct ITaskbarList: public IUnknown +{ + STDMETHOD(HrInit)(void) = 0; + STDMETHOD(AddTab)(HWND hwnd) = 0; + STDMETHOD(DeleteTab)(HWND hwnd) = 0; + STDMETHOD(ActivateTab)(HWND hwnd) = 0; + STDMETHOD(SetActiveAlt)(HWND hwnd) = 0; +}; +#endif // __ITaskbarList_INTERFACE_DEFINED__ + +#ifndef __ITaskbarList2_INTERFACE_DEFINED__ +#define __ITaskbarList2_INTERFACE_DEFINED__ +DEFINE_GUID(IID_ITaskbarList2, 0x602D4995, 0xB13A, 0x429b, 0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17); +struct ITaskbarList2: public ITaskbarList +{ + STDMETHOD(MarkFullscreenWindow)(HWND hwnd, BOOL fFullscreen) = 0; +}; +#endif // __ITaskbarList2_INTERFACE_DEFINED__ + +#endif // Z7_OLD_WIN_SDK + + +#ifndef __ITaskbarList3_INTERFACE_DEFINED__ +#define __ITaskbarList3_INTERFACE_DEFINED__ + +typedef enum THUMBBUTTONFLAGS +{ + THBF_ENABLED = 0, + THBF_DISABLED = 0x1, + THBF_DISMISSONCLICK = 0x2, + THBF_NOBACKGROUND = 0x4, + THBF_HIDDEN = 0x8, + THBF_NONINTERACTIVE = 0x10 +} THUMBBUTTONFLAGS; + +typedef enum THUMBBUTTONMASK +{ + THB_BITMAP = 0x1, + THB_ICON = 0x2, + THB_TOOLTIP = 0x4, + THB_FLAGS = 0x8 +} THUMBBUTTONMASK; + +// #include + +typedef struct THUMBBUTTON +{ + THUMBBUTTONMASK dwMask; + UINT iId; + UINT iBitmap; + HICON hIcon; + WCHAR szTip[260]; + THUMBBUTTONFLAGS dwFlags; +} THUMBBUTTON; + +typedef struct THUMBBUTTON *LPTHUMBBUTTON; + +typedef enum TBPFLAG +{ + TBPF_NOPROGRESS = 0, + TBPF_INDETERMINATE = 0x1, + TBPF_NORMAL = 0x2, + TBPF_ERROR = 0x4, + TBPF_PAUSED = 0x8 +} TBPFLAG; + +DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF); + +struct ITaskbarList3: public ITaskbarList2 +{ + STDMETHOD(SetProgressValue)(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) = 0; + STDMETHOD(SetProgressState)(HWND hwnd, TBPFLAG tbpFlags) = 0; + STDMETHOD(RegisterTab)(HWND hwndTab, HWND hwndMDI) = 0; + STDMETHOD(UnregisterTab)(HWND hwndTab) = 0; + STDMETHOD(SetTabOrder)(HWND hwndTab, HWND hwndInsertBefore) = 0; + STDMETHOD(SetTabActive)(HWND hwndTab, HWND hwndMDI, DWORD dwReserved) = 0; + STDMETHOD(ThumbBarAddButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0; + STDMETHOD(ThumbBarUpdateButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0; + STDMETHOD(ThumbBarSetImageList)(HWND hwnd, HIMAGELIST himl) = 0; + STDMETHOD(SetOverlayIcon)(HWND hwnd, HICON hIcon, LPCWSTR pszDescription) = 0; + STDMETHOD(SetThumbnailTooltip)(HWND hwnd, LPCWSTR pszTip) = 0; + STDMETHOD(SetThumbnailClip)(HWND hwnd, RECT *prcClip) = 0; +}; + +#endif // __ITaskbarList3_INTERFACE_DEFINED__ + +#endif // __MINGW* + +#endif diff --git a/CPP/7zip/UI/FileManager/NetFolder.cpp b/CPP/7zip/UI/FileManager/NetFolder.cpp index ccd722ba7..e91e67fc1 100644 --- a/CPP/7zip/UI/FileManager/NetFolder.cpp +++ b/CPP/7zip/UI/FileManager/NetFolder.cpp @@ -1,276 +1,276 @@ -// NetFolder.cpp - -#include "StdAfx.h" - -#include "../../../Windows/PropVariant.h" - -#include "../../PropID.h" - -#include "FSFolder.h" -#include "NetFolder.h" -#include "SysIconUtils.h" - -using namespace NWindows; -using namespace NNet; - -static const Byte kProps[] = -{ - kpidName, - kpidLocalName, - kpidComment, - kpidProvider -}; - -void CNetFolder::Init(const UString &path) -{ - /* - if (path.Len() > 2) - { - if (path[0] == L'\\' && path[1] == L'\\') - { - CResource netResource; - netResource.RemoteName = GetSystemString(path.Left(path.Len() - 1)); - netResource.Scope = RESOURCE_GLOBALNET; - netResource.Type = RESOURCETYPE_DISK; - netResource.DisplayType = RESOURCEDISPLAYTYPE_SERVER; - netResource.Usage = RESOURCEUSAGE_CONTAINER; - Init(&netResource, 0, path); - return; - } - } - Init(0, 0 , L""); - */ - CResourceW resource; - resource.RemoteNameIsDefined = true; - if (!path.IsEmpty()) - resource.RemoteName.SetFrom(path, path.Len() - 1); - resource.ProviderIsDefined = false; - resource.LocalNameIsDefined = false; - resource.CommentIsDefined = false; - resource.Type = RESOURCETYPE_DISK; - resource.Scope = RESOURCE_GLOBALNET; - resource.Usage = 0; - resource.DisplayType = 0; - CResourceW destResource; - UString systemPathPart; - DWORD result = GetResourceInformation(resource, destResource, systemPathPart); - if (result == NO_ERROR) - Init(&destResource, NULL, path); - else - Init(NULL, NULL , L""); - return; -} - -void CNetFolder::Init(const NWindows::NNet::CResourceW *netResource, - IFolderFolder *parentFolder, const UString &path) -{ - _path = path; - if (!netResource) - _netResourcePointer = NULL; - else - { - _netResource = *netResource; - _netResourcePointer = &_netResource; - - // if (_netResource.DisplayType == RESOURCEDISPLAYTYPE_SERVER) - _path = _netResource.RemoteName; - - /* WinXP-64: When we move UP from Network share without _parentFolder chain, - we can get empty _netResource.RemoteName. Do we need to use Provider there ? */ - if (_path.IsEmpty()) - _path = _netResource.Provider; - - if (!_path.IsEmpty()) - _path.Add_PathSepar(); - } - _parentFolder = parentFolder; -} - -Z7_COM7F_IMF(CNetFolder::LoadItems()) -{ - _items.Clear(); - CEnum enumerator; - - for (;;) - { - DWORD result = enumerator.Open( - RESOURCE_GLOBALNET, - RESOURCETYPE_DISK, - 0, // enumerate all resources - _netResourcePointer - ); - if (result == NO_ERROR) - break; - if (result != ERROR_ACCESS_DENIED) - return HRESULT_FROM_WIN32(result); - if (_netResourcePointer) - result = AddConnection2(_netResource, - NULL, NULL, CONNECT_INTERACTIVE); - if (result != NO_ERROR) - return HRESULT_FROM_WIN32(result); - } - - for (;;) - { - CResourceEx resource; - const DWORD result = enumerator.Next(resource); - if (result == NO_ERROR) - { - if (!resource.RemoteNameIsDefined) // For Win 98, I don't know what's wrong - resource.RemoteName = resource.Comment; - resource.Name = resource.RemoteName; - const int pos = resource.Name.ReverseFind_PathSepar(); - if (pos >= 0) - { - // _path = resource.Name.Left(pos + 1); - resource.Name.DeleteFrontal((unsigned)pos + 1); - } - _items.Add(resource); - } - else if (result == ERROR_NO_MORE_ITEMS) - break; - else - return HRESULT_FROM_WIN32(result); - } - - /* - It's too slow for some systems. - if (_netResourcePointer && _netResource.DisplayType == RESOURCEDISPLAYTYPE_SERVER) - { - for (char c = 'a'; c <= 'z'; c++) - { - CResourceEx resource; - resource.Name = UString(wchar_t(c)) + L'$'; - resource.RemoteNameIsDefined = true; - resource.RemoteName = _path + resource.Name; - - NFile::NFind::CFindFile findFile; - NFile::NFind::CFileInfo fileInfo; - if (!findFile.FindFirst(us2fs(resource.RemoteName) + FString(FCHAR_PATH_SEPARATOR) + FCHAR_ANY_MASK, fileInfo)) - continue; - resource.Usage = RESOURCEUSAGE_CONNECTABLE; - resource.LocalNameIsDefined = false; - resource.CommentIsDefined = false; - resource.ProviderIsDefined = false; - _items.Add(resource); - } - } - */ - return S_OK; -} - - -Z7_COM7F_IMF(CNetFolder::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = _items.Size(); - return S_OK; -} - -Z7_COM7F_IMF(CNetFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - const CResourceEx &item = _items[itemIndex]; - switch (propID) - { - case kpidIsDir: prop = true; break; - case kpidName: - // if (item.RemoteNameIsDefined) - prop = item.Name; - break; - case kpidLocalName: if (item.LocalNameIsDefined) prop = item.LocalName; break; - case kpidComment: if (item.CommentIsDefined) prop = item.Comment; break; - case kpidProvider: if (item.ProviderIsDefined) prop = item.Provider; break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CNetFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - const CResourceEx &resource = _items[index]; - if (resource.Usage == RESOURCEUSAGE_CONNECTABLE || - resource.DisplayType == RESOURCEDISPLAYTYPE_SHARE) - { - NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; - CMyComPtr subFolder = fsFolderSpec; - RINOK(fsFolderSpec->Init(us2fs(resource.RemoteName + WCHAR_PATH_SEPARATOR))) // , this - *resultFolder = subFolder.Detach(); - } - else - { - CNetFolder *netFolder = new CNetFolder; - CMyComPtr subFolder = netFolder; - netFolder->Init(&resource, this, resource.Name + WCHAR_PATH_SEPARATOR); - *resultFolder = subFolder.Detach(); - } - return S_OK; -} - -Z7_COM7F_IMF(CNetFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder ** /* resultFolder */)) -{ - return E_NOTIMPL; -} - -Z7_COM7F_IMF(CNetFolder::BindToParentFolder(IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - if (_parentFolder) - { - CMyComPtr parentFolder = _parentFolder; - *resultFolder = parentFolder.Detach(); - return S_OK; - } - if (_netResourcePointer) - { - CResourceW resourceParent; - const DWORD result = GetResourceParent(_netResource, resourceParent); - if (result != NO_ERROR) - return HRESULT_FROM_WIN32(result); - if (!_netResource.RemoteNameIsDefined) - return S_OK; - - CNetFolder *netFolder = new CNetFolder; - CMyComPtr subFolder = netFolder; - netFolder->Init(&resourceParent, NULL, WSTRING_PATH_SEPARATOR); - *resultFolder = subFolder.Detach(); - } - return S_OK; -} - -IMP_IFolderFolder_Props(CNetFolder) - -Z7_COM7F_IMF(CNetFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) -{ - NWindows::NCOM::CPropVariant prop; - switch (propID) - { - case kpidType: prop = "NetFolder"; break; - case kpidPath: prop = _path; break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CNetFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) -{ - *iconIndex = -1; - if (index >= _items.Size()) - return E_INVALIDARG; - const CResourceW &resource = _items[index]; - if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER || - resource.Usage == RESOURCEUSAGE_CONNECTABLE) - { - return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - us2fs(resource.RemoteName), FILE_ATTRIBUTE_DIRECTORY, iconIndex); - } - else - { -#if 0 - return S_FALSE; -#else - return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - FTEXT("__DIR__"), FILE_ATTRIBUTE_DIRECTORY, iconIndex); -#endif - } -} +// NetFolder.cpp + +#include "StdAfx.h" + +#include "../../../Windows/PropVariant.h" + +#include "../../PropID.h" + +#include "FSFolder.h" +#include "NetFolder.h" +#include "SysIconUtils.h" + +using namespace NWindows; +using namespace NNet; + +static const Byte kProps[] = +{ + kpidName, + kpidLocalName, + kpidComment, + kpidProvider +}; + +void CNetFolder::Init(const UString &path) +{ + /* + if (path.Len() > 2) + { + if (path[0] == L'\\' && path[1] == L'\\') + { + CResource netResource; + netResource.RemoteName = GetSystemString(path.Left(path.Len() - 1)); + netResource.Scope = RESOURCE_GLOBALNET; + netResource.Type = RESOURCETYPE_DISK; + netResource.DisplayType = RESOURCEDISPLAYTYPE_SERVER; + netResource.Usage = RESOURCEUSAGE_CONTAINER; + Init(&netResource, 0, path); + return; + } + } + Init(0, 0 , L""); + */ + CResourceW resource; + resource.RemoteNameIsDefined = true; + if (!path.IsEmpty()) + resource.RemoteName.SetFrom(path, path.Len() - 1); + resource.ProviderIsDefined = false; + resource.LocalNameIsDefined = false; + resource.CommentIsDefined = false; + resource.Type = RESOURCETYPE_DISK; + resource.Scope = RESOURCE_GLOBALNET; + resource.Usage = 0; + resource.DisplayType = 0; + CResourceW destResource; + UString systemPathPart; + DWORD result = GetResourceInformation(resource, destResource, systemPathPart); + if (result == NO_ERROR) + Init(&destResource, NULL, path); + else + Init(NULL, NULL , L""); + return; +} + +void CNetFolder::Init(const NWindows::NNet::CResourceW *netResource, + IFolderFolder *parentFolder, const UString &path) +{ + _path = path; + if (!netResource) + _netResourcePointer = NULL; + else + { + _netResource = *netResource; + _netResourcePointer = &_netResource; + + // if (_netResource.DisplayType == RESOURCEDISPLAYTYPE_SERVER) + _path = _netResource.RemoteName; + + /* WinXP-64: When we move UP from Network share without _parentFolder chain, + we can get empty _netResource.RemoteName. Do we need to use Provider there ? */ + if (_path.IsEmpty()) + _path = _netResource.Provider; + + if (!_path.IsEmpty()) + _path.Add_PathSepar(); + } + _parentFolder = parentFolder; +} + +Z7_COM7F_IMF(CNetFolder::LoadItems()) +{ + _items.Clear(); + CEnum enumerator; + + for (;;) + { + DWORD result = enumerator.Open( + RESOURCE_GLOBALNET, + RESOURCETYPE_DISK, + 0, // enumerate all resources + _netResourcePointer + ); + if (result == NO_ERROR) + break; + if (result != ERROR_ACCESS_DENIED) + return HRESULT_FROM_WIN32(result); + if (_netResourcePointer) + result = AddConnection2(_netResource, + NULL, NULL, CONNECT_INTERACTIVE); + if (result != NO_ERROR) + return HRESULT_FROM_WIN32(result); + } + + for (;;) + { + CResourceEx resource; + const DWORD result = enumerator.Next(resource); + if (result == NO_ERROR) + { + if (!resource.RemoteNameIsDefined) // For Win 98, I don't know what's wrong + resource.RemoteName = resource.Comment; + resource.Name = resource.RemoteName; + const int pos = resource.Name.ReverseFind_PathSepar(); + if (pos >= 0) + { + // _path = resource.Name.Left(pos + 1); + resource.Name.DeleteFrontal((unsigned)pos + 1); + } + _items.Add(resource); + } + else if (result == ERROR_NO_MORE_ITEMS) + break; + else + return HRESULT_FROM_WIN32(result); + } + + /* + It's too slow for some systems. + if (_netResourcePointer && _netResource.DisplayType == RESOURCEDISPLAYTYPE_SERVER) + { + for (char c = 'a'; c <= 'z'; c++) + { + CResourceEx resource; + resource.Name = UString(wchar_t(c)) + L'$'; + resource.RemoteNameIsDefined = true; + resource.RemoteName = _path + resource.Name; + + NFile::NFind::CFindFile findFile; + NFile::NFind::CFileInfo fileInfo; + if (!findFile.FindFirst(us2fs(resource.RemoteName) + FString(FCHAR_PATH_SEPARATOR) + FCHAR_ANY_MASK, fileInfo)) + continue; + resource.Usage = RESOURCEUSAGE_CONNECTABLE; + resource.LocalNameIsDefined = false; + resource.CommentIsDefined = false; + resource.ProviderIsDefined = false; + _items.Add(resource); + } + } + */ + return S_OK; +} + + +Z7_COM7F_IMF(CNetFolder::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = _items.Size(); + return S_OK; +} + +Z7_COM7F_IMF(CNetFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + const CResourceEx &item = _items[itemIndex]; + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidName: + // if (item.RemoteNameIsDefined) + prop = item.Name; + break; + case kpidLocalName: if (item.LocalNameIsDefined) prop = item.LocalName; break; + case kpidComment: if (item.CommentIsDefined) prop = item.Comment; break; + case kpidProvider: if (item.ProviderIsDefined) prop = item.Provider; break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CNetFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + const CResourceEx &resource = _items[index]; + if (resource.Usage == RESOURCEUSAGE_CONNECTABLE || + resource.DisplayType == RESOURCEDISPLAYTYPE_SHARE) + { + NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; + CMyComPtr subFolder = fsFolderSpec; + RINOK(fsFolderSpec->Init(us2fs(resource.RemoteName + WCHAR_PATH_SEPARATOR))) // , this + *resultFolder = subFolder.Detach(); + } + else + { + CNetFolder *netFolder = new CNetFolder; + CMyComPtr subFolder = netFolder; + netFolder->Init(&resource, this, resource.Name + WCHAR_PATH_SEPARATOR); + *resultFolder = subFolder.Detach(); + } + return S_OK; +} + +Z7_COM7F_IMF(CNetFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder ** /* resultFolder */)) +{ + return E_NOTIMPL; +} + +Z7_COM7F_IMF(CNetFolder::BindToParentFolder(IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + if (_parentFolder) + { + CMyComPtr parentFolder = _parentFolder; + *resultFolder = parentFolder.Detach(); + return S_OK; + } + if (_netResourcePointer) + { + CResourceW resourceParent; + const DWORD result = GetResourceParent(_netResource, resourceParent); + if (result != NO_ERROR) + return HRESULT_FROM_WIN32(result); + if (!_netResource.RemoteNameIsDefined) + return S_OK; + + CNetFolder *netFolder = new CNetFolder; + CMyComPtr subFolder = netFolder; + netFolder->Init(&resourceParent, NULL, WSTRING_PATH_SEPARATOR); + *resultFolder = subFolder.Detach(); + } + return S_OK; +} + +IMP_IFolderFolder_Props(CNetFolder) + +Z7_COM7F_IMF(CNetFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) +{ + NWindows::NCOM::CPropVariant prop; + switch (propID) + { + case kpidType: prop = "NetFolder"; break; + case kpidPath: prop = _path; break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CNetFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) +{ + *iconIndex = -1; + if (index >= _items.Size()) + return E_INVALIDARG; + const CResourceW &resource = _items[index]; + if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER || + resource.Usage == RESOURCEUSAGE_CONNECTABLE) + { + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + us2fs(resource.RemoteName), FILE_ATTRIBUTE_DIRECTORY, iconIndex); + } + else + { +#if 0 + return S_FALSE; +#else + return Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + FTEXT("__DIR__"), FILE_ATTRIBUTE_DIRECTORY, iconIndex); +#endif + } +} diff --git a/CPP/7zip/UI/FileManager/NetFolder.h b/CPP/7zip/UI/FileManager/NetFolder.h index 10892da0b..352f5bd8e 100644 --- a/CPP/7zip/UI/FileManager/NetFolder.h +++ b/CPP/7zip/UI/FileManager/NetFolder.h @@ -1,36 +1,36 @@ -// NetFolder.h - -#ifndef ZIP7_INC_NET_FOLDER_H -#define ZIP7_INC_NET_FOLDER_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/Net.h" - -#include "IFolder.h" - -struct CResourceEx: public NWindows::NNet::CResourceW -{ - UString Name; -}; - -Z7_CLASS_IMP_NOQIB_2( - CNetFolder - , IFolderFolder - , IFolderGetSystemIconIndex -) - NWindows::NNet::CResourceW _netResource; - NWindows::NNet::CResourceW *_netResourcePointer; - - CObjectVector _items; - - CMyComPtr _parentFolder; - UString _path; -public: - CNetFolder(): _netResourcePointer(NULL) {} - void Init(const UString &path); - void Init(const NWindows::NNet::CResourceW *netResource, - IFolderFolder *parentFolder, const UString &path); -}; - -#endif +// NetFolder.h + +#ifndef ZIP7_INC_NET_FOLDER_H +#define ZIP7_INC_NET_FOLDER_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/Net.h" + +#include "IFolder.h" + +struct CResourceEx: public NWindows::NNet::CResourceW +{ + UString Name; +}; + +Z7_CLASS_IMP_NOQIB_2( + CNetFolder + , IFolderFolder + , IFolderGetSystemIconIndex +) + NWindows::NNet::CResourceW _netResource; + NWindows::NNet::CResourceW *_netResourcePointer; + + CObjectVector _items; + + CMyComPtr _parentFolder; + UString _path; +public: + CNetFolder(): _netResourcePointer(NULL) {} + void Init(const UString &path); + void Init(const NWindows::NNet::CResourceW *netResource, + IFolderFolder *parentFolder, const UString &path); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/OpenCallback.cpp b/CPP/7zip/UI/FileManager/OpenCallback.cpp index 55486c624..e3cb2ecf0 100644 --- a/CPP/7zip/UI/FileManager/OpenCallback.cpp +++ b/CPP/7zip/UI/FileManager/OpenCallback.cpp @@ -1,86 +1,86 @@ -// OpenCallback.cpp - -#include "StdAfx.h" - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "../../Common/FileStreams.h" - -#include "../Common/ZipRegistry.h" - -#include "OpenCallback.h" -#include "PasswordDialog.h" - -using namespace NWindows; - -HRESULT COpenArchiveCallback::Open_SetTotal(const UInt64 *numFiles, const UInt64 *numBytes) -// Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes)) -{ - // COM_TRY_BEGIN - RINOK(ProgressDialog.Sync.CheckStop()) - { - // NSynchronization::CCriticalSectionLock lock(_criticalSection); - ProgressDialog.Sync.Set_NumFilesTotal(numFiles ? *numFiles : (UInt64)(Int64)-1); - // if (numFiles) - { - ProgressDialog.Sync.Set_BytesProgressMode(numFiles == NULL); - } - if (numBytes) - ProgressDialog.Sync.Set_NumBytesTotal(*numBytes); - } - return S_OK; - // COM_TRY_END -} - -HRESULT COpenArchiveCallback::Open_SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes) -// Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes)) -{ - // COM_TRY_BEGIN - // NSynchronization::CCriticalSectionLock lock(_criticalSection); - if (numFiles) - ProgressDialog.Sync.Set_NumFilesCur(*numFiles); - if (numBytes) - ProgressDialog.Sync.Set_NumBytesCur(*numBytes); - return ProgressDialog.Sync.CheckStop(); - // COM_TRY_END -} - -HRESULT COpenArchiveCallback::Open_CheckBreak() -{ - return ProgressDialog.Sync.CheckStop(); -} - -HRESULT COpenArchiveCallback::Open_Finished() -{ - return ProgressDialog.Sync.CheckStop(); -} - -#ifndef Z7_NO_CRYPTO -HRESULT COpenArchiveCallback::Open_CryptoGetTextPassword(BSTR *password) -// Z7_COM7F_IMF(COpenArchiveCallback::CryptoGetTextPassword(BSTR *password)) -{ - // COM_TRY_BEGIN - PasswordWasAsked = true; - if (!PasswordIsDefined) - { - CPasswordDialog dialog; - bool showPassword = NExtract::Read_ShowPassword(); - dialog.ShowPassword = showPassword; - - ProgressDialog.WaitCreating(); - if (dialog.Create(ProgressDialog) != IDOK) - return E_ABORT; - - Password = dialog.Password; - PasswordIsDefined = true; - if (dialog.ShowPassword != showPassword) - NExtract::Save_ShowPassword(dialog.ShowPassword); - } - return StringToBstr(Password, password); - // COM_TRY_END -} -#endif +// OpenCallback.cpp + +#include "StdAfx.h" + +#include "../../../Common/ComTry.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "../../Common/FileStreams.h" + +#include "../Common/ZipRegistry.h" + +#include "OpenCallback.h" +#include "PasswordDialog.h" + +using namespace NWindows; + +HRESULT COpenArchiveCallback::Open_SetTotal(const UInt64 *numFiles, const UInt64 *numBytes) +// Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes)) +{ + // COM_TRY_BEGIN + RINOK(ProgressDialog.Sync.CheckStop()) + { + // NSynchronization::CCriticalSectionLock lock(_criticalSection); + ProgressDialog.Sync.Set_NumFilesTotal(numFiles ? *numFiles : (UInt64)(Int64)-1); + // if (numFiles) + { + ProgressDialog.Sync.Set_FilesProgressMode(numFiles != NULL); + } + if (numBytes) + ProgressDialog.Sync.Set_NumBytesTotal(*numBytes); + } + return S_OK; + // COM_TRY_END +} + +HRESULT COpenArchiveCallback::Open_SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes) +// Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes)) +{ + // COM_TRY_BEGIN + // NSynchronization::CCriticalSectionLock lock(_criticalSection); + if (numFiles) + ProgressDialog.Sync.Set_NumFilesCur(*numFiles); + if (numBytes) + ProgressDialog.Sync.Set_NumBytesCur(*numBytes); + return ProgressDialog.Sync.CheckStop(); + // COM_TRY_END +} + +HRESULT COpenArchiveCallback::Open_CheckBreak() +{ + return ProgressDialog.Sync.CheckStop(); +} + +HRESULT COpenArchiveCallback::Open_Finished() +{ + return ProgressDialog.Sync.CheckStop(); +} + +#ifndef Z7_NO_CRYPTO +HRESULT COpenArchiveCallback::Open_CryptoGetTextPassword(BSTR *password) +// Z7_COM7F_IMF(COpenArchiveCallback::CryptoGetTextPassword(BSTR *password)) +{ + // COM_TRY_BEGIN + PasswordWasAsked = true; + if (!PasswordIsDefined) + { + CPasswordDialog dialog; + bool showPassword = NExtract::Read_ShowPassword(); + dialog.ShowPassword = showPassword; + + ProgressDialog.WaitCreating(); + if (dialog.Create(ProgressDialog) != IDOK) + return E_ABORT; + + Password = dialog.Password; + PasswordIsDefined = true; + if (dialog.ShowPassword != showPassword) + NExtract::Save_ShowPassword(dialog.ShowPassword); + } + return StringToBstr(Password, password); + // COM_TRY_END +} +#endif diff --git a/CPP/7zip/UI/FileManager/OpenCallback.h b/CPP/7zip/UI/FileManager/OpenCallback.h index e731901be..8f4638cfc 100644 --- a/CPP/7zip/UI/FileManager/OpenCallback.h +++ b/CPP/7zip/UI/FileManager/OpenCallback.h @@ -1,69 +1,69 @@ -// OpenCallback.h - -#ifndef ZIP7_INC_OPEN_CALLBACK_H -#define ZIP7_INC_OPEN_CALLBACK_H - -#include "../Common/ArchiveOpenCallback.h" - -#ifdef Z7_SFX -#include "ProgressDialog.h" -#else -#include "ProgressDialog2.h" -#endif - -/* we can use IArchiveOpenCallback or IOpenCallbackUI here */ - -class COpenArchiveCallback Z7_final: - /* - public IArchiveOpenCallback, - public IProgress, - public ICryptoGetTextPassword, - public CMyUnknownImp - */ - public IOpenCallbackUI -{ - // NWindows::NSynchronization::CCriticalSection _criticalSection; -public: - bool PasswordIsDefined; - bool PasswordWasAsked; - UString Password; - HWND ParentWindow; - CProgressDialog ProgressDialog; - - /* - Z7_COM_UNKNOWN_IMP_3( - IArchiveOpenVolumeCallback, - IProgress - ICryptoGetTextPassword - ) - - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IArchiveOpenCallback) - // ICryptoGetTextPassword - Z7_COM7F_IMP(CryptoGetTextPassword(BSTR *password)) - */ - - Z7_IFACE_IMP(IOpenCallbackUI) - - COpenArchiveCallback(): - ParentWindow(NULL) - { - // _subArchiveMode = false; - PasswordIsDefined = false; - PasswordWasAsked = false; - } - /* - void Init() - { - PasswordIsDefined = false; - _subArchiveMode = false; - } - */ - - INT_PTR StartProgressDialog(const UString &title, NWindows::CThread &thread) - { - return ProgressDialog.Create(title, thread, ParentWindow); - } -}; - -#endif +// OpenCallback.h + +#ifndef ZIP7_INC_OPEN_CALLBACK_H +#define ZIP7_INC_OPEN_CALLBACK_H + +#include "../Common/ArchiveOpenCallback.h" + +#ifdef Z7_SFX +#include "ProgressDialog.h" +#else +#include "ProgressDialog2.h" +#endif + +/* we can use IArchiveOpenCallback or IOpenCallbackUI here */ + +class COpenArchiveCallback Z7_final: + /* + public IArchiveOpenCallback, + public IProgress, + public ICryptoGetTextPassword, + public CMyUnknownImp + */ + public IOpenCallbackUI +{ + // NWindows::NSynchronization::CCriticalSection _criticalSection; +public: + bool PasswordIsDefined; + bool PasswordWasAsked; + UString Password; + HWND ParentWindow; + CProgressDialog ProgressDialog; + + /* + Z7_COM_UNKNOWN_IMP_3( + IArchiveOpenVolumeCallback, + IProgress + ICryptoGetTextPassword + ) + + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IArchiveOpenCallback) + // ICryptoGetTextPassword + Z7_COM7F_IMP(CryptoGetTextPassword(BSTR *password)) + */ + + Z7_IFACE_IMP(IOpenCallbackUI) + + COpenArchiveCallback(): + ParentWindow(NULL) + { + // _subArchiveMode = false; + PasswordIsDefined = false; + PasswordWasAsked = false; + } + /* + void Init() + { + PasswordIsDefined = false; + _subArchiveMode = false; + } + */ + + INT_PTR StartProgressDialog(const UString &title, NWindows::CThread &thread) + { + return ProgressDialog.Create(title, thread, ParentWindow); + } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/OptionsDialog.cpp b/CPP/7zip/UI/FileManager/OptionsDialog.cpp index 138232894..b71c32335 100644 --- a/CPP/7zip/UI/FileManager/OptionsDialog.cpp +++ b/CPP/7zip/UI/FileManager/OptionsDialog.cpp @@ -1,89 +1,89 @@ -// OptionsDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/PropertyPage.h" - -#include "DialogSize.h" - -#include "EditPage.h" -#include "EditPageRes.h" -#include "FoldersPage.h" -#include "FoldersPageRes.h" -#include "LangPage.h" -#include "LangPageRes.h" -#include "MenuPage.h" -#include "MenuPageRes.h" -#include "SettingsPage.h" -#include "SettingsPageRes.h" -#include "SystemPage.h" -#include "SystemPageRes.h" - -#include "App.h" -#include "LangUtils.h" -#include "MyLoadMenu.h" - -#include "resource.h" - -using namespace NWindows; - -void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance); -void OptionsDialog(HWND hwndOwner, HINSTANCE /* hInstance */) -{ - CSystemPage systemPage; - CMenuPage menuPage; - CFoldersPage foldersPage; - CEditPage editPage; - CSettingsPage settingsPage; - CLangPage langPage; - - CObjectVector pages; - BIG_DIALOG_SIZE(200, 200); - - const UINT pageIDs[] = { - SIZED_DIALOG(IDD_SYSTEM), - SIZED_DIALOG(IDD_MENU), - SIZED_DIALOG(IDD_FOLDERS), - SIZED_DIALOG(IDD_EDIT), - SIZED_DIALOG(IDD_SETTINGS), - SIZED_DIALOG(IDD_LANG) }; - - NControl::CPropertyPage *pagePointers[] = { &systemPage, &menuPage, &foldersPage, &editPage, &settingsPage, &langPage }; - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(pageIDs); i++) - { - NControl::CPageInfo &page = pages.AddNew(); - page.ID = pageIDs[i]; - #ifdef Z7_LANG - LangString_OnlyFromLangFile(page.ID, page.Title); - #endif - page.Page = pagePointers[i]; - } - - const INT_PTR res = NControl::MyPropertySheet(pages, hwndOwner, LangString(IDS_OPTIONS)); - - if (res != -1 && res != 0) - { - if (langPage.LangWasChanged) - { - // g_App._window.SetText(LangString(IDS_APP_TITLE, 0x03000000)); - MyLoadMenu(true); // needResetMenu - g_App.ReloadToolbars(); - g_App.MoveSubWindows(); // we need it to change list window aafter _toolBar.AutoSize(); - g_App.ReloadLangItems(); - } - - /* - if (systemPage.WasChanged) - { - // probably it doesn't work, since image list is locked? - g_App.SysIconsWereChanged(); - } - */ - - g_App.SetListSettings(); - g_App.RefreshAllPanels(); - // ::PostMessage(hwndOwner, kLangWasChangedMessage, 0 , 0); - } -} +// OptionsDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/PropertyPage.h" + +#include "DialogSize.h" + +#include "EditPage.h" +#include "EditPageRes.h" +#include "FoldersPage.h" +#include "FoldersPageRes.h" +#include "LangPage.h" +#include "LangPageRes.h" +#include "MenuPage.h" +#include "MenuPageRes.h" +#include "SettingsPage.h" +#include "SettingsPageRes.h" +#include "SystemPage.h" +#include "SystemPageRes.h" + +#include "App.h" +#include "LangUtils.h" +#include "MyLoadMenu.h" + +#include "resource.h" + +using namespace NWindows; + +void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance); +void OptionsDialog(HWND hwndOwner, HINSTANCE /* hInstance */) +{ + CSystemPage systemPage; + CMenuPage menuPage; + CFoldersPage foldersPage; + CEditPage editPage; + CSettingsPage settingsPage; + CLangPage langPage; + + CObjectVector pages; + BIG_DIALOG_SIZE(200, 200); + + const UINT pageIDs[] = { + SIZED_DIALOG(IDD_SYSTEM), + SIZED_DIALOG(IDD_MENU), + SIZED_DIALOG(IDD_FOLDERS), + SIZED_DIALOG(IDD_EDIT), + SIZED_DIALOG(IDD_SETTINGS), + SIZED_DIALOG(IDD_LANG) }; + + NControl::CPropertyPage *pagePointers[] = { &systemPage, &menuPage, &foldersPage, &editPage, &settingsPage, &langPage }; + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(pageIDs); i++) + { + NControl::CPageInfo &page = pages.AddNew(); + page.ID = pageIDs[i]; + #ifdef Z7_LANG + LangString_OnlyFromLangFile(page.ID, page.Title); + #endif + page.Page = pagePointers[i]; + } + + const INT_PTR res = NControl::MyPropertySheet(pages, hwndOwner, LangString(IDS_OPTIONS)); + + if (res != -1 && res != 0) + { + if (langPage.LangWasChanged) + { + // g_App._window.SetText(LangString(IDS_APP_TITLE, 0x03000000)); + MyLoadMenu(true); // needResetMenu + g_App.ReloadToolbars(); + g_App.MoveSubWindows(); // we need it to change list window aafter _toolBar.AutoSize(); + g_App.ReloadLangItems(); + } + + /* + if (systemPage.WasChanged) + { + // probably it doesn't work, since image list is locked? + g_App.SysIconsWereChanged(); + } + */ + + g_App.SetListSettings(); + g_App.RefreshAllPanels(); + // ::PostMessage(hwndOwner, kLangWasChangedMessage, 0 , 0); + } +} diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp index 50e65afee..b15c70298 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp +++ b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp @@ -1,288 +1,288 @@ -// OverwriteDialog.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileFind.h" -#include "../../../Windows/PropVariantConv.h" -#include "../../../Windows/ResourceString.h" - -#include "../../../Windows/Control/Static.h" - -#include "FormatUtils.h" -#include "LangUtils.h" -#include "OverwriteDialog.h" - -#include "PropertyNameRes.h" - -using namespace NWindows; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_OVERWRITE_HEADER, - IDT_OVERWRITE_QUESTION_BEGIN, - IDT_OVERWRITE_QUESTION_END, - IDB_YES_TO_ALL, - IDB_NO_TO_ALL, - IDB_AUTO_RENAME -}; -#endif - -static const unsigned kCurrentFileNameSizeLimit = 72; - -void COverwriteDialog::ReduceString(UString &s) -{ - const unsigned size = -#ifdef UNDER_CE - !_isBig ? 30 : // kCurrentFileNameSizeLimit2 -#endif - kCurrentFileNameSizeLimit; - - if (s.Len() > size) - { - s.Delete(size / 2, s.Len() - size); - s.Insert(size / 2, L" ... "); - } - if (!s.IsEmpty() && s.Back() == ' ') - { - // s += (wchar_t)(0x2423); // visible space - s.InsertAtFront(L'\"'); - s.Add_Char('\"'); - } -} - - -void COverwriteDialog::SetItemIcon(unsigned iconID, HICON hIcon) -{ - NControl::CStatic staticContol; - staticContol.Attach(GetItem(iconID)); - hIcon = staticContol.SetIcon(hIcon); - if (hIcon) - DestroyIcon(hIcon); -} - -void AddSizeValue(UString &s, UInt64 value); -void AddSizeValue(UString &s, UInt64 value) -{ - { - wchar_t sz[32]; - ConvertUInt64ToString(value, sz); - s += MyFormatNew(IDS_FILE_SIZE, sz); - } - if (value >= (1 << 10)) - { - char c; - if (value >= ((UInt64)10 << 30)) { value >>= 30; c = 'G'; } - else if (value >= (10 << 20)) { value >>= 20; c = 'M'; } - else { value >>= 10; c = 'K'; } - s += " : "; - s.Add_UInt64(value); - s.Add_Space(); - s.Add_Char(c); - s += "iB"; - } -} - - -void COverwriteDialog::SetFileInfoControl( - const NOverwriteDialog::CFileInfo &fileInfo, - unsigned textID, - unsigned iconID, - unsigned iconID_2) -{ - { - const UString &path = fileInfo.Path; - const int slashPos = path.ReverseFind_PathSepar(); - UString s = path.Left((unsigned)(slashPos + 1)); - ReduceString(s); - s.Add_LF(); - { - UString s2 = path.Ptr((unsigned)(slashPos + 1)); - ReduceString(s2); - s += s2; - } - s.Add_LF(); - if (fileInfo.Size_IsDefined) - AddSizeValue(s, fileInfo.Size); - s.Add_LF(); - if (fileInfo.Time_IsDefined) - { - AddLangString(s, IDS_PROP_MTIME); - s += ": "; - char t[64]; - ConvertUtcFileTimeToString(fileInfo.Time, t); - s += t; - } - SetItemText(textID, s); - } -/* - SHGetFileInfo(): - DOCs: If uFlags does not contain SHGFI_EXETYPE or SHGFI_SYSICONINDEX, - the return value is nonzero if successful, or zero otherwise. - We don't use SHGFI_EXETYPE or SHGFI_SYSICONINDEX here. - win10: we call with SHGFI_ICON flag set. - it returns 0: if error : (shFileInfo::*) members are not set. - it returns non_0, if successful, and retrieve: - { shFileInfo.hIcon != NULL : the handle to icon (must be destroyed by our code) - shFileInfo.iIcon is index of the icon image within the system image list. - } - Note: - If we send path to ".exe" file, - SHGFI_USEFILEATTRIBUTES flag is ignored, and it tries to open file. - and return icon from that exe file. - So we still need to reduce path, if want to get raw icon of exe file. - - if (name.Len() >= MAX_PATH)) - { - it can return: - return 0. - return 1 and: - { shFileInfo.hIcon != NULL : is some default icon for file - shFileInfo.iIcon == 0 - } - return results (0 or 1) can depend from: - - unicode/non-unicode - - (SHGFI_USEFILEATTRIBUTES) flag - - exact file extension (.exe). - } -*/ - int iconIndex = -1; - for (unsigned i = 0; i < 2; i++) - { - CSysString name = GetSystemString(fileInfo.Path); - if (i != 0) - { - if (!fileInfo.Is_FileSystemFile) - break; - if (name.Len() < 4 || - (!StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".exe") && - !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".ico"))) - break; - // if path for ".exe" file is long, it returns default icon (shFileInfo.iIcon == 0). - // We don't want to show that default icon. - // But we will check for default icon later instead of MAX_PATH check here. - // if (name.Len() >= MAX_PATH) break; // optional - } - else - { - // we need only file extension with dot - const int separ = name.ReverseFind_PathSepar(); - name.DeleteFrontal((unsigned)(separ + 1)); - // if (name.Len() >= MAX_PATH) - { - const int dot = name.ReverseFind_Dot(); - if (dot >= 0) - name.DeleteFrontal((unsigned)dot); - // else name.Empty(); to set default name below - } - // name.Empty(); // for debug - } - - if (name.IsEmpty()) - { - // If we send empty name, SHGetFileInfo() returns some strange icon. - // So we use common dummy name without extension, - // and SHGetFileInfo() will return default icon (iIcon == 0) - name = "__file__"; - } - - DWORD attrib = FILE_ATTRIBUTE_ARCHIVE; - if (fileInfo.Is_FileSystemFile) - { - NFile::NFind::CFileInfo fi; - if (fi.Find(us2fs(fileInfo.Path)) && !fi.IsAltStream && !fi.IsDir()) - attrib = fi.Attrib; - } - - SHFILEINFO shFileInfo; - // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); // optional - shFileInfo.hIcon = NULL; // optional - shFileInfo.iIcon = -1; // optional - // memset(&shFileInfo, 1, sizeof(shFileInfo)); // for debug - const DWORD_PTR res = ::SHGetFileInfo(name, attrib, - &shFileInfo, sizeof(shFileInfo), - SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SHELLICONSIZE | - // (i == 0 ? SHGFI_USEFILEATTRIBUTES : 0) - SHGFI_USEFILEATTRIBUTES - // we use SHGFI_USEFILEATTRIBUTES for second icon, because - // it still returns real icon from exe files - ); - if (res && shFileInfo.hIcon) - { - // we don't show second icon, if icon index (iIcon) is same - // as first icon index of first shown icon (exe file without icon) - if ( shFileInfo.iIcon >= 0 - && shFileInfo.iIcon != iconIndex - && (shFileInfo.iIcon != 0 || i == 0)) // we don't want default icon for second icon - { - iconIndex = shFileInfo.iIcon; - SetItemIcon(i == 0 ? iconID : iconID_2, shFileInfo.hIcon); - } - else - DestroyIcon(shFileInfo.hIcon); - } - } -} - - - -bool COverwriteDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_OVERWRITE); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - SetFileInfoControl(OldFileInfo, - IDT_OVERWRITE_OLD_FILE_SIZE_TIME, - IDI_OVERWRITE_OLD_FILE, - IDI_OVERWRITE_OLD_FILE_2); - SetFileInfoControl(NewFileInfo, - IDT_OVERWRITE_NEW_FILE_SIZE_TIME, - IDI_OVERWRITE_NEW_FILE, - IDI_OVERWRITE_NEW_FILE_2); - NormalizePosition(); - - if (!ShowExtraButtons) - { - HideItem(IDB_YES_TO_ALL); - HideItem(IDB_NO_TO_ALL); - HideItem(IDB_AUTO_RENAME); - } - - if (DefaultButton_is_NO) - { - PostMsg(DM_SETDEFID, IDNO); - HWND h = GetItem(IDNO); - PostMsg(WM_NEXTDLGCTL, (WPARAM)h, TRUE); - // ::SetFocus(h); - } - - return CModalDialog::OnInit(); -} - -bool COverwriteDialog::OnDestroy() -{ - SetItemIcon(IDI_OVERWRITE_OLD_FILE, NULL); - SetItemIcon(IDI_OVERWRITE_OLD_FILE_2, NULL); - SetItemIcon(IDI_OVERWRITE_NEW_FILE, NULL); - SetItemIcon(IDI_OVERWRITE_NEW_FILE_2, NULL); - return false; // we return (false) to perform default dialog operation -} - -bool COverwriteDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDYES: - case IDNO: - case IDB_YES_TO_ALL: - case IDB_NO_TO_ALL: - case IDB_AUTO_RENAME: - End((INT_PTR)buttonID); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} +// OverwriteDialog.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/ResourceString.h" + +#include "../../../Windows/Control/Static.h" + +#include "FormatUtils.h" +#include "LangUtils.h" +#include "OverwriteDialog.h" + +#include "PropertyNameRes.h" + +using namespace NWindows; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_OVERWRITE_HEADER, + IDT_OVERWRITE_QUESTION_BEGIN, + IDT_OVERWRITE_QUESTION_END, + IDB_YES_TO_ALL, + IDB_NO_TO_ALL, + IDB_AUTO_RENAME +}; +#endif + +static const unsigned kCurrentFileNameSizeLimit = 72; + +void COverwriteDialog::ReduceString(UString &s) +{ + const unsigned size = +#ifdef UNDER_CE + !_isBig ? 30 : // kCurrentFileNameSizeLimit2 +#endif + kCurrentFileNameSizeLimit; + + if (s.Len() > size) + { + s.Delete(size / 2, s.Len() - size); + s.Insert(size / 2, L" ... "); + } + if (!s.IsEmpty() && s.Back() == ' ') + { + // s += (wchar_t)(0x2423); // visible space + s.InsertAtFront(L'\"'); + s.Add_Char('\"'); + } +} + + +void COverwriteDialog::SetItemIcon(unsigned iconID, HICON hIcon) +{ + NControl::CStatic staticContol; + staticContol.Attach(GetItem(iconID)); + hIcon = staticContol.SetIcon(hIcon); + if (hIcon) + DestroyIcon(hIcon); +} + +void AddSizeValue(UString &s, UInt64 value); +void AddSizeValue(UString &s, UInt64 value) +{ + { + wchar_t sz[32]; + ConvertUInt64ToString(value, sz); + s += MyFormatNew(IDS_FILE_SIZE, sz); + } + if (value >= (1 << 10)) + { + char c; + if (value >= ((UInt64)10 << 30)) { value >>= 30; c = 'G'; } + else if (value >= (10 << 20)) { value >>= 20; c = 'M'; } + else { value >>= 10; c = 'K'; } + s += " : "; + s.Add_UInt64(value); + s.Add_Space(); + s.Add_Char(c); + s += "iB"; + } +} + + +void COverwriteDialog::SetFileInfoControl( + const NOverwriteDialog::CFileInfo &fileInfo, + unsigned textID, + unsigned iconID, + unsigned iconID_2) +{ + { + const UString &path = fileInfo.Path; + const int slashPos = path.ReverseFind_PathSepar(); + UString s = path.Left((unsigned)(slashPos + 1)); + ReduceString(s); + s.Add_LF(); + { + UString s2 = path.Ptr((unsigned)(slashPos + 1)); + ReduceString(s2); + s += s2; + } + s.Add_LF(); + if (fileInfo.Size_IsDefined) + AddSizeValue(s, fileInfo.Size); + s.Add_LF(); + if (fileInfo.Time_IsDefined) + { + AddLangString(s, IDS_PROP_MTIME); + s += ": "; + char t[64]; + ConvertUtcFileTimeToString(fileInfo.Time, t); + s += t; + } + SetItemText(textID, s); + } +/* + SHGetFileInfo(): + DOCs: If uFlags does not contain SHGFI_EXETYPE or SHGFI_SYSICONINDEX, + the return value is nonzero if successful, or zero otherwise. + We don't use SHGFI_EXETYPE or SHGFI_SYSICONINDEX here. + win10: we call with SHGFI_ICON flag set. + it returns 0: if error : (shFileInfo::*) members are not set. + it returns non_0, if successful, and retrieve: + { shFileInfo.hIcon != NULL : the handle to icon (must be destroyed by our code) + shFileInfo.iIcon is index of the icon image within the system image list. + } + Note: + If we send path to ".exe" file, + SHGFI_USEFILEATTRIBUTES flag is ignored, and it tries to open file. + and return icon from that exe file. + So we still need to reduce path, if want to get raw icon of exe file. + + if (name.Len() >= MAX_PATH)) + { + it can return: + return 0. + return 1 and: + { shFileInfo.hIcon != NULL : is some default icon for file + shFileInfo.iIcon == 0 + } + return results (0 or 1) can depend from: + - unicode/non-unicode + - (SHGFI_USEFILEATTRIBUTES) flag + - exact file extension (.exe). + } +*/ + int iconIndex = -1; + for (unsigned i = 0; i < 2; i++) + { + CSysString name = GetSystemString(fileInfo.Path); + if (i != 0) + { + if (!fileInfo.Is_FileSystemFile) + break; + if (name.Len() < 4 || + (!StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".exe") && + !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".ico"))) + break; + // if path for ".exe" file is long, it returns default icon (shFileInfo.iIcon == 0). + // We don't want to show that default icon. + // But we will check for default icon later instead of MAX_PATH check here. + // if (name.Len() >= MAX_PATH) break; // optional + } + else + { + // we need only file extension with dot + const int separ = name.ReverseFind_PathSepar(); + name.DeleteFrontal((unsigned)(separ + 1)); + // if (name.Len() >= MAX_PATH) + { + const int dot = name.ReverseFind_Dot(); + if (dot >= 0) + name.DeleteFrontal((unsigned)dot); + // else name.Empty(); to set default name below + } + // name.Empty(); // for debug + } + + if (name.IsEmpty()) + { + // If we send empty name, SHGetFileInfo() returns some strange icon. + // So we use common dummy name without extension, + // and SHGetFileInfo() will return default icon (iIcon == 0) + name = "__file__"; + } + + DWORD attrib = FILE_ATTRIBUTE_ARCHIVE; + if (fileInfo.Is_FileSystemFile) + { + NFile::NFind::CFileInfo fi; + if (fi.Find(us2fs(fileInfo.Path)) && !fi.IsAltStream && !fi.IsDir()) + attrib = fi.Attrib; + } + + SHFILEINFO shFileInfo; + // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); // optional + shFileInfo.hIcon = NULL; // optional + shFileInfo.iIcon = -1; // optional + // memset(&shFileInfo, 1, sizeof(shFileInfo)); // for debug + const DWORD_PTR res = ::SHGetFileInfo(name, attrib, + &shFileInfo, sizeof(shFileInfo), + SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SHELLICONSIZE | + // (i == 0 ? SHGFI_USEFILEATTRIBUTES : 0) + SHGFI_USEFILEATTRIBUTES + // we use SHGFI_USEFILEATTRIBUTES for second icon, because + // it still returns real icon from exe files + ); + if (res && shFileInfo.hIcon) + { + // we don't show second icon, if icon index (iIcon) is same + // as first icon index of first shown icon (exe file without icon) + if ( shFileInfo.iIcon >= 0 + && shFileInfo.iIcon != iconIndex + && (shFileInfo.iIcon != 0 || i == 0)) // we don't want default icon for second icon + { + iconIndex = shFileInfo.iIcon; + SetItemIcon(i == 0 ? iconID : iconID_2, shFileInfo.hIcon); + } + else + DestroyIcon(shFileInfo.hIcon); + } + } +} + + + +bool COverwriteDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_OVERWRITE); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + SetFileInfoControl(OldFileInfo, + IDT_OVERWRITE_OLD_FILE_SIZE_TIME, + IDI_OVERWRITE_OLD_FILE, + IDI_OVERWRITE_OLD_FILE_2); + SetFileInfoControl(NewFileInfo, + IDT_OVERWRITE_NEW_FILE_SIZE_TIME, + IDI_OVERWRITE_NEW_FILE, + IDI_OVERWRITE_NEW_FILE_2); + NormalizePosition(); + + if (!ShowExtraButtons) + { + HideItem(IDB_YES_TO_ALL); + HideItem(IDB_NO_TO_ALL); + HideItem(IDB_AUTO_RENAME); + } + + if (DefaultButton_is_NO) + { + PostMsg(DM_SETDEFID, IDNO); + HWND h = GetItem(IDNO); + PostMsg(WM_NEXTDLGCTL, (WPARAM)h, TRUE); + // ::SetFocus(h); + } + + return CModalDialog::OnInit(); +} + +bool COverwriteDialog::OnDestroy() +{ + SetItemIcon(IDI_OVERWRITE_OLD_FILE, NULL); + SetItemIcon(IDI_OVERWRITE_OLD_FILE_2, NULL); + SetItemIcon(IDI_OVERWRITE_NEW_FILE, NULL); + SetItemIcon(IDI_OVERWRITE_NEW_FILE_2, NULL); + return false; // we return (false) to perform default dialog operation +} + +bool COverwriteDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDYES: + case IDNO: + case IDB_YES_TO_ALL: + case IDB_NO_TO_ALL: + case IDB_AUTO_RENAME: + End((INT_PTR)buttonID); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.h b/CPP/7zip/UI/FileManager/OverwriteDialog.h index a7f6ae010..9f0801d92 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.h +++ b/CPP/7zip/UI/FileManager/OverwriteDialog.h @@ -1,89 +1,89 @@ -// OverwriteDialog.h - -#ifndef ZIP7_INC_OVERWRITE_DIALOG_H -#define ZIP7_INC_OVERWRITE_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" - -#include "DialogSize.h" -#include "OverwriteDialogRes.h" - -namespace NOverwriteDialog -{ - struct CFileInfo - { - bool Size_IsDefined; - bool Time_IsDefined; - bool Is_FileSystemFile; - UInt64 Size; - FILETIME Time; - UString Path; - - void SetTime(const FILETIME &t) - { - Time = t; - Time_IsDefined = true; - } - - void SetTime2(const FILETIME *t) - { - if (!t) - Time_IsDefined = false; - else - SetTime(*t); - } - - void SetSize(UInt64 size) - { - Size = size; - Size_IsDefined = true; - } - - void SetSize2(const UInt64 *size) - { - if (!size) - Size_IsDefined = false; - else - SetSize(*size); - } - - CFileInfo(): - Size_IsDefined(false), - Time_IsDefined(false), - Is_FileSystemFile(false) - {} - }; -} - -class COverwriteDialog: public NWindows::NControl::CModalDialog -{ -#ifdef UNDER_CE - bool _isBig; -#endif - - void SetItemIcon(unsigned iconID, HICON hIcon); - void SetFileInfoControl(const NOverwriteDialog::CFileInfo &fileInfo, unsigned textID, unsigned iconID, unsigned iconID_2); - virtual bool OnInit() Z7_override; - virtual bool OnDestroy() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - void ReduceString(UString &s); - -public: - bool ShowExtraButtons; - bool DefaultButton_is_NO; - NOverwriteDialog::CFileInfo OldFileInfo; - NOverwriteDialog::CFileInfo NewFileInfo; - - COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {} - - INT_PTR Create(HWND parent = NULL) - { -#ifdef UNDER_CE - BIG_DIALOG_SIZE(280, 200); - _isBig = isBig; -#endif - return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent); - } -}; - -#endif +// OverwriteDialog.h + +#ifndef ZIP7_INC_OVERWRITE_DIALOG_H +#define ZIP7_INC_OVERWRITE_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" + +#include "DialogSize.h" +#include "OverwriteDialogRes.h" + +namespace NOverwriteDialog +{ + struct CFileInfo + { + bool Size_IsDefined; + bool Time_IsDefined; + bool Is_FileSystemFile; + UInt64 Size; + FILETIME Time; + UString Path; + + void SetTime(const FILETIME &t) + { + Time = t; + Time_IsDefined = true; + } + + void SetTime2(const FILETIME *t) + { + if (!t) + Time_IsDefined = false; + else + SetTime(*t); + } + + void SetSize(UInt64 size) + { + Size = size; + Size_IsDefined = true; + } + + void SetSize2(const UInt64 *size) + { + if (!size) + Size_IsDefined = false; + else + SetSize(*size); + } + + CFileInfo(): + Size_IsDefined(false), + Time_IsDefined(false), + Is_FileSystemFile(false) + {} + }; +} + +class COverwriteDialog: public NWindows::NControl::CModalDialog +{ +#ifdef UNDER_CE + bool _isBig; +#endif + + void SetItemIcon(unsigned iconID, HICON hIcon); + void SetFileInfoControl(const NOverwriteDialog::CFileInfo &fileInfo, unsigned textID, unsigned iconID, unsigned iconID_2); + virtual bool OnInit() Z7_override; + virtual bool OnDestroy() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + void ReduceString(UString &s); + +public: + bool ShowExtraButtons; + bool DefaultButton_is_NO; + NOverwriteDialog::CFileInfo OldFileInfo; + NOverwriteDialog::CFileInfo NewFileInfo; + + COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {} + + INT_PTR Create(HWND parent = NULL) + { +#ifdef UNDER_CE + BIG_DIALOG_SIZE(280, 200); + _isBig = isBig; +#endif + return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent); + } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/CPP/7zip/UI/FileManager/OverwriteDialog.rc index 9f102bf00..112d5d890 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialog.rc +++ b/CPP/7zip/UI/FileManager/OverwriteDialog.rc @@ -1,93 +1,93 @@ -#include "OverwriteDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 340 -#define yc 200 - -#undef iconSize -#define iconSize 24 - -#undef x -#undef fx -#undef fy -#define x (m + iconSize + m) -#define fx (xc - iconSize - m) -#define fy 50 - -#define bSizeBig 104 -#undef bx1 -#define bx1 (xs - m - bSizeBig) - -IDD_OVERWRITE DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Confirm File Replace" -BEGIN - LTEXT "Destination folder already contains processed file.", IDT_OVERWRITE_HEADER, m, 7, xc, 8 - LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, 28, xc, 8 - - ICON "", IDI_OVERWRITE_OLD_FILE, m, 44, iconSize, iconSize - ICON "", IDI_OVERWRITE_OLD_FILE_2, m, 44 + iconSize, iconSize, iconSize - LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 44, fx, fy, SS_NOPREFIX - - LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 98, xc, 8 - - ICON "", IDI_OVERWRITE_NEW_FILE, m, 114, iconSize, iconSize - ICON "", IDI_OVERWRITE_NEW_FILE_2, m, 114 + iconSize, iconSize, iconSize - LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 114, fx, fy, SS_NOPREFIX - - PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys - PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys - PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bSizeBig, bys - PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys - PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys - PUSHBUTTON "&Cancel", IDCANCEL, xs - m - bxs, by1, bxs, bys -END - - -#ifdef UNDER_CE - -#undef m -#undef xc -#undef yc - -#define m 4 -#define xc 152 -#define yc 144 - -#undef fy -#define fy 40 - -#undef bxs -#define bxs 48 - -#undef bx1 - -#define bx1 (xs - m - bxs) - -IDD_OVERWRITE_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Confirm File Replace" -BEGIN - LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, m, xc, 8 - - ICON "", IDI_OVERWRITE_OLD_FILE, m, 20, iconSize, iconSize - LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 20, fx, fy, SS_NOPREFIX - - LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 60, xc, 8 - - ICON "", IDI_OVERWRITE_NEW_FILE, m, 72, iconSize, iconSize - LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 72, fx, fy, SS_NOPREFIX - - PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys - PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys - PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bxs, bys - PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys - PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys - PUSHBUTTON "&Cancel", IDCANCEL, bx1, by1, bxs, bys -END - -#endif - - -STRINGTABLE -BEGIN - IDS_FILE_SIZE "{0} bytes" -END +#include "OverwriteDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 340 +#define yc 200 + +#undef iconSize +#define iconSize 24 + +#undef x +#undef fx +#undef fy +#define x (m + iconSize + m) +#define fx (xc - iconSize - m) +#define fy 50 + +#define bSizeBig 104 +#undef bx1 +#define bx1 (xs - m - bSizeBig) + +IDD_OVERWRITE DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Confirm File Replace" +BEGIN + LTEXT "Destination folder already contains processed file.", IDT_OVERWRITE_HEADER, m, 7, xc, 8 + LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, 28, xc, 8 + + ICON "", IDI_OVERWRITE_OLD_FILE, m, 44, iconSize, iconSize + ICON "", IDI_OVERWRITE_OLD_FILE_2, m, 44 + iconSize, iconSize, iconSize + LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 44, fx, fy, SS_NOPREFIX + + LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 98, xc, 8 + + ICON "", IDI_OVERWRITE_NEW_FILE, m, 114, iconSize, iconSize + ICON "", IDI_OVERWRITE_NEW_FILE_2, m, 114 + iconSize, iconSize, iconSize + LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 114, fx, fy, SS_NOPREFIX + + PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys + PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys + PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bSizeBig, bys + PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys + PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys + PUSHBUTTON "&Cancel", IDCANCEL, xs - m - bxs, by1, bxs, bys +END + + +#ifdef UNDER_CE + +#undef m +#undef xc +#undef yc + +#define m 4 +#define xc 152 +#define yc 144 + +#undef fy +#define fy 40 + +#undef bxs +#define bxs 48 + +#undef bx1 + +#define bx1 (xs - m - bxs) + +IDD_OVERWRITE_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Confirm File Replace" +BEGIN + LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, m, xc, 8 + + ICON "", IDI_OVERWRITE_OLD_FILE, m, 20, iconSize, iconSize + LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 20, fx, fy, SS_NOPREFIX + + LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 60, xc, 8 + + ICON "", IDI_OVERWRITE_NEW_FILE, m, 72, iconSize, iconSize + LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 72, fx, fy, SS_NOPREFIX + + PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys + PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys + PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bxs, bys + PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys + PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys + PUSHBUTTON "&Cancel", IDCANCEL, bx1, by1, bxs, bys +END + +#endif + + +STRINGTABLE +BEGIN + IDS_FILE_SIZE "{0} bytes" +END diff --git a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h b/CPP/7zip/UI/FileManager/OverwriteDialogRes.h index 2dec5ad24..24beb333d 100644 --- a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h +++ b/CPP/7zip/UI/FileManager/OverwriteDialogRes.h @@ -1,19 +1,19 @@ -#define IDD_OVERWRITE 3500 -#define IDD_OVERWRITE_2 13500 - -#define IDT_OVERWRITE_HEADER 3501 -#define IDT_OVERWRITE_QUESTION_BEGIN 3502 -#define IDT_OVERWRITE_QUESTION_END 3503 -#define IDS_FILE_SIZE 3504 - -#define IDB_AUTO_RENAME 3505 -#define IDB_YES_TO_ALL 440 -#define IDB_NO_TO_ALL 441 - -#define IDI_OVERWRITE_OLD_FILE 100 -#define IDI_OVERWRITE_OLD_FILE_2 101 -#define IDT_OVERWRITE_OLD_FILE_SIZE_TIME 102 - -#define IDI_OVERWRITE_NEW_FILE 110 -#define IDI_OVERWRITE_NEW_FILE_2 111 -#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME 112 +#define IDD_OVERWRITE 3500 +#define IDD_OVERWRITE_2 13500 + +#define IDT_OVERWRITE_HEADER 3501 +#define IDT_OVERWRITE_QUESTION_BEGIN 3502 +#define IDT_OVERWRITE_QUESTION_END 3503 +#define IDS_FILE_SIZE 3504 + +#define IDB_AUTO_RENAME 3505 +#define IDB_YES_TO_ALL 440 +#define IDB_NO_TO_ALL 441 + +#define IDI_OVERWRITE_OLD_FILE 100 +#define IDI_OVERWRITE_OLD_FILE_2 101 +#define IDT_OVERWRITE_OLD_FILE_SIZE_TIME 102 + +#define IDI_OVERWRITE_NEW_FILE 110 +#define IDI_OVERWRITE_NEW_FILE_2 111 +#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME 112 diff --git a/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp index 0f04b06cd..84bd88c5a 100644 --- a/CPP/7zip/UI/FileManager/Panel.cpp +++ b/CPP/7zip/UI/FileManager/Panel.cpp @@ -1,1176 +1,1177 @@ -// Panel.cpp - -#include "StdAfx.h" - -#include - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/Thread.h" - -#include "../../PropID.h" - -#include "resource.h" -#include "../GUI/ExtractRes.h" - -#include "../Common/ArchiveName.h" -#include "../Common/CompressCall.h" -#include "../Common/ZipRegistry.h" - -#include "../Agent/IFolderArchive.h" - -#include "App.h" -#include "ExtractCallback.h" -#include "FSFolder.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "Panel.h" -#include "RootFolder.h" - -#include "PropertyNameRes.h" - -using namespace NWindows; -using namespace NControl; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -static const UINT_PTR kTimerID = 1; -static const UINT kTimerElapse = 1000; - -static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT }; - -// static const int kCreateFolderID = 101; - -extern HINSTANCE g_hInstance; - -void CPanel::Release() -{ - // It's for unloading COM dll's: don't change it. - CloseOpenFolders(); - _sevenZipContextMenu.Release(); - _systemContextMenu.Release(); -} - -CPanel::~CPanel() -{ - CloseOpenFolders(); -} - -HWND CPanel::GetParent() const -{ - const HWND h = CWindow2::GetParent(); - return h ? h : _mainWindow; -} - -#define kClassName L"7-Zip::Panel" - - -HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id, - const UString ¤tFolderPrefix, - const UString &arcFormat, - CPanelCallback *panelCallback, CAppState *appState, - bool needOpenArc, - COpenResult &openRes) -{ - _mainWindow = mainWindow; - _processTimer = true; - _processNotify = true; - _processStatusBar = true; - - _panelCallback = panelCallback; - _appState = appState; - // _index = index; - _baseID = id; - _comboBoxID = _baseID + 3; - _statusBarID = _comboBoxID + 1; - - UString cfp = currentFolderPrefix; - - if (!currentFolderPrefix.IsEmpty()) - if (currentFolderPrefix[0] == L'.') - { - FString cfpF; - if (NFile::NDir::MyGetFullPathName(us2fs(currentFolderPrefix), cfpF)) - cfp = fs2us(cfpF); - } - - RINOK(BindToPath(cfp, arcFormat, openRes)) - - if (needOpenArc && !openRes.ArchiveIsOpened) - return S_OK; - - if (!CreateEx(0, kClassName, NULL, WS_CHILD | WS_VISIBLE, - 0, 0, _xSize, 260, - parentWindow, (HMENU)(UINT_PTR)id, g_hInstance)) - return E_FAIL; - PanelCreated = true; - - return S_OK; -} - -// extern UInt32 g_NumMessages; - -LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - // g_NumMessages++; - switch (message) - { - case kShiftSelectMessage: - OnShiftSelectMessage(); - return 0; - case kReLoadMessage: - RefreshListCtrl(_selectedState); - return 0; - case kSetFocusToListView: - _listView.SetFocus(); - return 0; - case kOpenItemChanged: - return OnOpenItemChanged(lParam); - case kRefresh_StatusBar: - if (_processStatusBar) - Refresh_StatusBar(); - return 0; - #ifdef UNDER_CE - case kRefresh_HeaderComboBox: - LoadFullPathAndShow(); - return 0; - #endif - case WM_TIMER: - OnTimer(); - return 0; - case WM_CONTEXTMENU: - if (OnContextMenu(HANDLE(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) - return 0; - break; - /* - case WM_DROPFILES: - CompressDropFiles(HDROP(wParam)); - return 0; - */ - } - return CWindow2::OnMessage(message, wParam, lParam); -} - -LRESULT CMyListView::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message == WM_CHAR) - { - UINT scanCode = (UINT)((lParam >> 16) & 0xFF); - bool extended = ((lParam & 0x1000000) != 0); - UINT virtualKey = MapVirtualKey(scanCode, 1); - if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD || - virtualKey == VK_SUBTRACT) - return 0; - if ((wParam == '/' && extended) - || wParam == '\\' || wParam == '/') - { - _panel->OpenDrivesFolder(); - return 0; - } - } - else if (message == WM_SYSCHAR) - { - // For Alt+Enter Beep disabling - UINT scanCode = (UINT)(lParam >> 16) & 0xFF; - UINT virtualKey = MapVirtualKey(scanCode, 1); - if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY || - virtualKey == VK_ADD || virtualKey == VK_SUBTRACT) - return 0; - } - /* - else if (message == WM_SYSKEYDOWN) - { - // return 0; - } - */ - else if (message == WM_KEYDOWN) - { - bool alt = IsKeyDown(VK_MENU); - bool ctrl = IsKeyDown(VK_CONTROL); - bool shift = IsKeyDown(VK_SHIFT); - switch (wParam) - { - /* - case VK_RETURN: - { - if (shift && !alt && !ctrl) - { - _panel->OpenSelectedItems(false); - return 0; - } - break; - } - */ - case VK_NEXT: - { - if (ctrl && !alt && !shift) - { - _panel->OpenFocusedItemAsInternal(); - return 0; - } - break; - } - case VK_PRIOR: - if (ctrl && !alt && !shift) - { - _panel->OpenParentFolder(); - return 0; - } - } - } - #ifdef UNDER_CE - else if (message == WM_KEYUP) - { - if (wParam == VK_F2) // it's VK_TSOFT2 - { - // Activate Menu - ::PostMessage(g_HWND, WM_SYSCOMMAND, SC_KEYMENU, 0); - return 0; - } - } - #endif - else if (message == WM_SETFOCUS) - { - _panel->_lastFocusedIsList = true; - _panel->_panelCallback->PanelWasFocused(); - } - return CListView2::OnMessage(message, wParam, lParam); -} - -/* -static LRESULT APIENTRY ComboBoxSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - CWindow tempDialog(hwnd); - CMyComboBox *w = (CMyComboBox *)(tempDialog.GetUserDataLongPtr()); - if (w == NULL) - return 0; - return w->OnMessage(message, wParam, lParam); -} - -LRESULT CMyComboBox::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); -} -*/ - -#ifndef UNDER_CE - -static LRESULT APIENTRY ComboBoxEditSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - CWindow tempDialog(hwnd); - CMyComboBoxEdit *w = (CMyComboBoxEdit *)(tempDialog.GetUserDataLongPtr()); - if (w == NULL) - return 0; - return w->OnMessage(message, wParam, lParam); -} - -#endif - -LRESULT CMyComboBoxEdit::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - // See MSDN / Subclassing a Combo Box / Creating a Combo-box Toolbar - switch (message) - { - case WM_SYSKEYDOWN: - switch (wParam) - { - case VK_F1: - case VK_F2: - { - // check ALT - if ((lParam & (1<<29)) == 0) - break; - bool alt = IsKeyDown(VK_MENU); - bool ctrl = IsKeyDown(VK_CONTROL); - bool shift = IsKeyDown(VK_SHIFT); - if (alt && !ctrl && !shift) - { - _panel->_panelCallback->SetFocusToPath(wParam == VK_F1 ? 0 : 1); - return 0; - } - break; - } - } - break; - case WM_KEYDOWN: - switch (wParam) - { - case VK_TAB: - // SendMessage(hwndMain, WM_ENTER, 0, 0); - _panel->SetFocusToList(); - return 0; - case VK_F9: - { - bool alt = IsKeyDown(VK_MENU); - bool ctrl = IsKeyDown(VK_CONTROL); - bool shift = IsKeyDown(VK_SHIFT); - if (!alt && !ctrl && !shift) - { - g_App.SwitchOnOffOnePanel(); - return 0; - } - break; - } - case 'W': - { - bool ctrl = IsKeyDown(VK_CONTROL); - if (ctrl) - { - PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0); - return 0; - } - break; - } - } - break; - case WM_CHAR: - switch (wParam) - { - case VK_TAB: - case VK_ESCAPE: - return 0; - } - } - #ifndef _UNICODE - if (g_IsNT) - return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam); - else - #endif - return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); -} - - -/* - REBARBANDINFO in vista (_WIN32_WINNT >= 0x0600) has additional fields - we want 2000/xp compatibility. - so we must use reduced structure, if we compile with (_WIN32_WINNT >= 0x0600) - Also there are additional fields, if (_WIN32_IE >= 0x0400). - but (_WIN32_IE >= 0x0400) is expected. - note: - in x64 (64-bit): - { - (108 == REBARBANDINFO_V6_SIZE) - (112 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT < 0x0600) - (128 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT >= 0x0600) - there is difference in sizes, because REBARBANDINFO size was - not aligned for 8-bytes in (_WIN32_WINNT < 0x0600). - We hope that WinVista+ support support both (108 and 112) sizes. - But does WinXP-x64 support (108 == REBARBANDINFO_V6_SIZE)? - { - 96 LPARAM lParam; - 104 UINT cxHeader; - #if (_WIN32_WINNT >= 0x0600) - 108 RECT rcChevronLocation; - 124 UINT uChevronState; - #endif - } -*/ - -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && defined(REBARBANDINFOA_V6_SIZE) - #define my_compatib_REBARBANDINFO_size REBARBANDINFO_V6_SIZE -#else - #define my_compatib_REBARBANDINFO_size sizeof(REBARBANDINFO) -#endif - - -bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */) -{ - // _virtualMode = false; - // _sortIndex = 0; - _sortID = kpidName; - _ascending = true; - _lastFocusedIsList = true; - - DWORD style = WS_CHILD | WS_VISIBLE; // | WS_BORDER ; // | LVS_SHAREIMAGELISTS; // | LVS_SHOWSELALWAYS; - - style |= LVS_SHAREIMAGELISTS; - // style |= LVS_AUTOARRANGE; - style |= WS_CLIPCHILDREN; - style |= WS_CLIPSIBLINGS; - - const UInt32 kNumListModes = Z7_ARRAY_SIZE(kStyles); - if (_listViewMode >= kNumListModes) - _listViewMode = kNumListModes - 1; - - style |= kStyles[_listViewMode] - | WS_TABSTOP - | LVS_EDITLABELS; - if (_mySelectMode) - style |= LVS_SINGLESEL; - - /* - if (_virtualMode) - style |= LVS_OWNERDATA; - */ - - DWORD exStyle; - exStyle = WS_EX_CLIENTEDGE; - - if (!_listView.CreateEx(exStyle, style, 0, 0, 116, 260, - *this, (HMENU)(UINT_PTR)(_baseID + 1), g_hInstance, NULL)) - return false; - - _listView.SetUnicodeFormat(); - _listView._panel = this; - _listView.SetWindowProc(); - - _listView.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); - _listView.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); - - // _exStyle |= LVS_EX_HEADERDRAGDROP; - // DWORD extendedStyle = _listView.GetExtendedListViewStyle(); - // extendedStyle |= _exStyle; - // _listView.SetExtendedListViewStyle(extendedStyle); - SetExtendedStyle(); - - _listView.Show(SW_SHOW); - _listView.InvalidateRect(NULL, true); - _listView.Update(); - - // Ensure that the common control DLL is loaded. - INITCOMMONCONTROLSEX icex; - - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = ICC_BAR_CLASSES; - InitCommonControlsEx(&icex); - - const TBBUTTON tbb[] = - { - // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, - {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, 0 }, - // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, - // {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}, - }; - -#ifdef Z7_USE_DYN_ComCtl32Version - if (g_ComCtl32Version >= MAKELONG(71, 4)) -#endif - { - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES; - InitCommonControlsEx(&icex); - - // if there is no CCS_NOPARENTALIGN, there is space of some pixels after rebar (Incorrect GetWindowRect ?) - - _headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW, - REBARCLASSNAME, - NULL, WS_VISIBLE | WS_BORDER | WS_CHILD | - WS_CLIPCHILDREN | WS_CLIPSIBLINGS - | CCS_NODIVIDER - | CCS_NOPARENTALIGN - | CCS_TOP - | RBS_VARHEIGHT - | RBS_BANDBORDERS - ,0,0,0,0, *this, NULL, g_hInstance, NULL)); - } - - DWORD toolbarStyle = WS_CHILD | WS_VISIBLE ; - if (_headerReBar) - { - toolbarStyle |= 0 - // | WS_CLIPCHILDREN - // | WS_CLIPSIBLINGS - - | TBSTYLE_TOOLTIPS - | CCS_NODIVIDER - | CCS_NORESIZE - | TBSTYLE_FLAT - ; - } - - _headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle, - _baseID + 2, 11, - (HINSTANCE)HINST_COMMCTRL, - IDB_VIEW_SMALL_COLOR, - (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb), - 0, 0, 0, 0, sizeof (TBBUTTON))); - - #ifndef UNDER_CE - // Load ComboBoxEx class - icex.dwSize = sizeof(INITCOMMONCONTROLSEX); - icex.dwICC = ICC_USEREX_CLASSES; - InitCommonControlsEx(&icex); - #endif - - _headerComboBox.CreateEx(0, - #ifdef UNDER_CE - WC_COMBOBOXW - #else - WC_COMBOBOXEXW - #endif - , NULL, - WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL, - 0, 0, 100, 620, - (_headerReBar ? _headerToolBar : (HWND)*this), - (HMENU)(UINT_PTR)(_comboBoxID), - g_hInstance, NULL); - -#ifndef UNDER_CE - _headerComboBox.SetUnicodeFormat(true); - _headerComboBox.SetImageList(Shell_Get_SysImageList_smallIcons(true)); - _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC); - /* - _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox)); - _headerComboBox._panel = this; - _headerComboBox._origWindowProc = - (WNDPROC)_headerComboBox.SetLongPtr(GWLP_WNDPROC, - LONG_PTR(ComboBoxSubclassProc)); - */ - _comboBoxEdit.Attach(_headerComboBox.GetEditControl()); - // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0); - _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit)); - _comboBoxEdit._panel = this; - #ifndef _UNICODE - if (g_IsNT) - _comboBoxEdit._origWindowProc = - (WNDPROC)_comboBoxEdit.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc)); - else - #endif - _comboBoxEdit._origWindowProc = - (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc)); -#endif - - if (_headerReBar) - { - REBARINFO rbi; - rbi.cbSize = sizeof(REBARINFO); // Required when using this struct. - rbi.fMask = 0; - rbi.himl = (HIMAGELIST)NULL; - _headerReBar.SetBarInfo(&rbi); - - // Send the TB_BUTTONSTRUCTSIZE message, which is required for - // backward compatibility. - // _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); - SIZE size; - _headerToolBar.GetMaxSize(&size); - - REBARBANDINFO rbBand; - memset(&rbBand, 0, sizeof(rbBand)); - // rbBand.cbSize = sizeof(rbBand); // for debug - // rbBand.cbSize = REBARBANDINFO_V3_SIZE; // for debug - rbBand.cbSize = my_compatib_REBARBANDINFO_size; - rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; - rbBand.fStyle = RBBS_NOGRIPPER; - rbBand.cxMinChild = (UINT)size.cx; - rbBand.cyMinChild = (UINT)size.cy; - rbBand.cyChild = (UINT)size.cy; - rbBand.cx = (UINT)size.cx; - rbBand.hwndChild = _headerToolBar; - _headerReBar.InsertBand(-1, &rbBand); - - RECT rc; - ::GetWindowRect(_headerComboBox, &rc); - rbBand.cxMinChild = 30; - rbBand.cyMinChild = (UINT)(rc.bottom - rc.top); - rbBand.cx = 1000; - rbBand.hwndChild = _headerComboBox; - _headerReBar.InsertBand(-1, &rbBand); - // _headerReBar.MaximizeBand(1, false); - } - - _statusBar.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID); - // _statusBar2.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID + 1); - - const int sizes[] = {220, 320, 420, -1}; - _statusBar.SetParts(4, sizes); - // _statusBar2.SetParts(5, sizes); - - /* - RECT rect; - GetClientRect(&rect); - OnSize(0, RECT_SIZE_X(rect), RECT_SIZE_Y(rect)); - */ - - SetTimer(kTimerID, kTimerElapse); - - // InitListCtrl(); - RefreshListCtrl(); - - return true; -} - -void CPanel::OnDestroy() -{ - SaveListViewInfo(); - CWindow2::OnDestroy(); -} - -void CPanel::ChangeWindowSize(int xSize, int ySize) -{ - if (!(HWND)*this) - return; - int kHeaderSize; - int kStatusBarSize; - // int kStatusBar2Size; - RECT rect; - if (_headerReBar) - _headerReBar.GetWindowRect(&rect); - else - _headerToolBar.GetWindowRect(&rect); - - kHeaderSize = RECT_SIZE_Y(rect); - - _statusBar.GetWindowRect(&rect); - kStatusBarSize = RECT_SIZE_Y(rect); - - // _statusBar2.GetWindowRect(&rect); - // kStatusBar2Size = RECT_SIZE_Y(rect); - - int yListViewSize = MyMax(ySize - kHeaderSize - kStatusBarSize, 0); - const int kStartXPos = 32; - if (_headerReBar) - { - } - else - { - _headerToolBar.Move(0, 0, xSize, 0); - _headerComboBox.Move(kStartXPos, 2, - MyMax(xSize - kStartXPos - 10, kStartXPos), 0); - } - _listView.Move(0, kHeaderSize, xSize, yListViewSize); - _statusBar.Move(0, kHeaderSize + yListViewSize, xSize, kStatusBarSize); - // _statusBar2.MoveWindow(0, kHeaderSize + yListViewSize + kStatusBarSize, xSize, kStatusBar2Size); - // _statusBar.MoveWindow(0, 100, xSize, kStatusBarSize); - // _statusBar2.MoveWindow(0, 200, xSize, kStatusBar2Size); -} - -bool CPanel::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - if (!(HWND)*this) - return true; - if (_headerReBar) - _headerReBar.Move(0, 0, xSize, 0); - ChangeWindowSize(xSize, ySize); - return true; -} - -bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */) -{ - switch (header->code) - { - case RBN_HEIGHTCHANGE: - { - RECT rect; - GetWindowRect(&rect); - ChangeWindowSize(RECT_SIZE_X(rect), RECT_SIZE_Y(rect)); - return false; - } - } - return false; -} - -/* -UInt32 g_OnNotify = 0; -UInt32 g_LVIF_TEXT = 0; -UInt32 g_Time = 0; - -void Print_OnNotify(const char *name) -{ - char s[256]; - DWORD tim = GetTickCount(); - sprintf(s, - "Time = %7u ms, Notify = %9u, TEXT = %9u, %s", - tim - g_Time, - g_OnNotify, - g_LVIF_TEXT, - name); - g_Time = tim; - OutputDebugStringA(s); - g_OnNotify = 0; - g_LVIF_TEXT = 0; -} -*/ - -bool CPanel::OnNotify(UINT /* controlID */, LPNMHDR header, LRESULT &result) -{ - /* - g_OnNotify++; - - if (header->hwndFrom == _listView) - { - if (header->code == LVN_GETDISPINFOW) - { - LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header; - if ((dispInfo->item.mask & LVIF_TEXT)) - g_LVIF_TEXT++; - } - } - */ - - if (!_processNotify) - return false; - - if (header->hwndFrom == _headerComboBox) - return OnNotifyComboBox(header, result); - else if (header->hwndFrom == _headerReBar) - return OnNotifyReBar(header, result); - else if (header->hwndFrom == _listView) - return OnNotifyList(header, result); - else if (::GetParent(header->hwndFrom) == _listView) - { - // NMHDR:code is UINT - // NM_RCLICK is unsigned in windows sdk - // NM_RCLICK is int in MinGW - if (header->code == (UINT)NM_RCLICK) - return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result); - } - return false; -} - -bool CPanel::OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) -{ - if (itemID == kParentFolderID) - { - OpenParentFolder(); - result = 0; - return true; - } - /* - if (itemID == kCreateFolderID) - { - CreateFolder(); - result = 0; - return true; - } - */ - if (itemID == _comboBoxID) - { - if (OnComboBoxCommand(code, lParam, result)) - return true; - } - return CWindow2::OnCommand(code, itemID, lParam, result); -} - - - -/* -void CPanel::MessageBox_Info(LPCWSTR message, LPCWSTR caption) const - { ::MessageBoxW((HWND)*this, message, caption, MB_OK); } -void CPanel::MessageBox_Warning(LPCWSTR message) const - { ::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OK | MB_ICONWARNING); } -*/ - -void CPanel::MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const - { ::MessageBoxW((HWND)*this, message, caption, MB_OK | MB_ICONSTOP); } - -void CPanel::MessageBox_Error(LPCWSTR message) const - { MessageBox_Error_Caption(message, L"7-Zip"); } - -static UString ErrorHResult_To_Message(HRESULT errorCode) -{ - if (errorCode == 0) - errorCode = E_FAIL; - return HResultToMessage(errorCode); -} - -void CPanel::MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const -{ - MessageBox_Error_Caption(ErrorHResult_To_Message(errorCode), caption); -} - -void CPanel::MessageBox_Error_HRESULT(HRESULT errorCode) const - { MessageBox_Error_HRESULT_Caption(errorCode, L"7-Zip"); } - -void CPanel::MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const -{ - UString m = message; - m.Add_LF(); - m += ErrorHResult_To_Message(errorCode); - MessageBox_Error(m); -} - -void CPanel::MessageBox_LastError(LPCWSTR caption) const - { MessageBox_Error_HRESULT_Caption(GetLastError_noZero_HRESULT(), caption); } - -void CPanel::MessageBox_LastError() const - { MessageBox_LastError(L"7-Zip"); } - -void CPanel::MessageBox_Error_LangID(UINT resourceID) const - { MessageBox_Error(LangString(resourceID)); } - -void CPanel::MessageBox_Error_UnsupportOperation() const - { MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); } - - - - -void CPanel::SetFocusToList() -{ - _listView.SetFocus(); - // SetCurrentPathText(); -} - -void CPanel::SetFocusToLastRememberedItem() -{ - if (_lastFocusedIsList) - SetFocusToList(); - else - _headerComboBox.SetFocus(); -} - -UString CPanel::GetFolderTypeID() const -{ - { - NCOM::CPropVariant prop; - if (_folder->GetFolderProperty(kpidType, &prop) == S_OK) - if (prop.vt == VT_BSTR) - return (const wchar_t *)prop.bstrVal; - } - return UString(); -} - -bool CPanel::IsFolderTypeEqTo(const char *s) const -{ - return StringsAreEqual_Ascii(GetFolderTypeID(), s); -} - -bool CPanel::IsRootFolder() const { return IsFolderTypeEqTo("RootFolder"); } -bool CPanel::IsFSFolder() const { return IsFolderTypeEqTo("FSFolder"); } -bool CPanel::IsFSDrivesFolder() const { return IsFolderTypeEqTo("FSDrives"); } -bool CPanel::IsAltStreamsFolder() const { return IsFolderTypeEqTo("AltStreamsFolder"); } -bool CPanel::IsArcFolder() const -{ - return GetFolderTypeID().IsPrefixedBy_Ascii_NoCase("7-Zip"); -} - -bool CPanel::IsHashFolder() const -{ - if (_folder) - { - NCOM::CPropVariant prop; - if (_folder->GetFolderProperty(kpidIsHash, &prop) == S_OK) - if (prop.vt == VT_BOOL) - return VARIANT_BOOLToBool(prop.boolVal); - } - return false; -} - -UString CPanel::GetFsPath() const -{ - if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix() && !IsSuperDrivesPrefix()) - return UString(); - return _currentFolderPrefix; -} - -UString CPanel::GetDriveOrNetworkPrefix() const -{ - if (!IsFSFolder()) - return UString(); - UString drive = GetFsPath(); - drive.DeleteFrom(NFile::NName::GetRootPrefixSize(drive)); - return drive; -} - -void CPanel::SetListViewMode(UInt32 index) -{ - if (index >= 4) - return; - _listViewMode = index; - const LONG_PTR oldStyle = _listView.GetStyle(); - const DWORD newStyle = kStyles[index]; - - // DWORD tickCount1 = GetTickCount(); - if ((oldStyle & LVS_TYPEMASK) != (LONG_PTR)newStyle) - _listView.SetStyle((oldStyle & ~(LONG_PTR)(DWORD)LVS_TYPEMASK) | (LONG_PTR)newStyle); - // RefreshListCtrlSaveFocused(); - /* - DWORD tickCount2 = GetTickCount(); - char s[256]; - sprintf(s, "SetStyle = %5d", - tickCount2 - tickCount1 - ); - OutputDebugStringA(s); - */ - -} - -void CPanel::ChangeFlatMode() -{ - _flatMode = !_flatMode; - if (_parentFolders.Size() > 0) - _flatModeForArc = _flatMode; - else - _flatModeForDisk = _flatMode; - RefreshListCtrl_SaveFocused(); -} - -/* -void CPanel::Change_ShowNtfsStrems_Mode() -{ - _showNtfsStrems_Mode = !_showNtfsStrems_Mode; - if (_parentFolders.Size() > 0) - _showNtfsStrems_ModeForArc = _showNtfsStrems_Mode; - else - _showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode; - RefreshListCtrlSaveFocused(); -} -*/ - -void CPanel::Post_Refresh_StatusBar() -{ - if (_processStatusBar) - PostMsg(kRefresh_StatusBar); -} - -void CPanel::AddToArchive() -{ - if (!Is_IO_FS_Folder()) - { - MessageBox_Error_UnsupportOperation(); - return; - } - CRecordVector indices; - Get_ItemIndices_Operated(indices); - if (indices.Size() == 0) - { - MessageBox_Error_LangID(IDS_SELECT_FILES); - return; - } - UString destCurDirPrefix = GetFsPath(); - if (IsFSDrivesFolder()) - destCurDirPrefix = ROOT_FS_FOLDER; - UStringVector names; - GetFilePaths(indices, names); - UString baseName; - const UString arcName = CreateArchiveName(names, - false, // isHash - NULL, // CFileInfo *fi - baseName); - const HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"", - true, // addExtension - names, - false, // email - true, // showDialog - false); // waitFinish - if (res != S_OK) - { - if (destCurDirPrefix.Len() >= MAX_PATH) - MessageBox_Error_LangID(IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER); - } - // KillSelection(); -} - -// function from ContextMenu.cpp -UString GetSubFolderNameForExtract(const UString &arcPath); - -static UString GetSubFolderNameForExtract2(const UString &arcPath) -{ - int slashPos = arcPath.ReverseFind_PathSepar(); - UString s; - UString name = arcPath; - if (slashPos >= 0) - { - s = arcPath.Left((unsigned)(slashPos + 1)); - name = arcPath.Ptr((unsigned)(slashPos + 1)); - } - s += GetSubFolderNameForExtract(name); - return s; -} - - -int CPanel::FindDir_InOperatedList(const CRecordVector &operatedIndices) const -{ - const bool *isDirVector = _isDirVector.ConstData(); - const UInt32 *indices = operatedIndices.ConstData(); - const unsigned numItems = operatedIndices.Size(); - for (unsigned i = 0; i < numItems; i++) - if (isDirVector[indices[i]]) - return (int)i; - return -1; -} - - -void CPanel::GetFilePaths(const CRecordVector &operatedIndices, UStringVector &paths) const -{ - paths.ClearAndReserve(operatedIndices.Size()); - UString path = GetFsPath(); - const unsigned prefixLen = path.Len(); - const UInt32 *indices = operatedIndices.ConstData(); - const unsigned numItems = operatedIndices.Size(); - // for (unsigned y = 0; y < 10000; y++, paths.Clear()) - for (unsigned i = 0; i < numItems; i++) - { - path.DeleteFrom(prefixLen); - Add_ItemRelPath2_To_String(indices[i], path); - // ODS_U(path) - paths.AddInReserved(path); - } -} - - -void CPanel::ExtractArchives() -{ - if (_parentFolders.Size() > 0) - { - _panelCallback->OnCopy(false, false); - return; - } - CRecordVector indices; - Get_ItemIndices_Operated(indices); - if (indices.IsEmpty() || FindDir_InOperatedList(indices) != -1) - { - MessageBox_Error_LangID(IDS_SELECT_FILES); - return; - } - UStringVector paths; - GetFilePaths(indices, paths); - UString outFolder = GetFsPath(); - if (indices.Size() == 1) - outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0])); - else - outFolder.Add_Char('*'); - outFolder.Add_PathSepar(); - - CContextMenuInfo ci; - ci.Load(); - - ::ExtractArchives(paths, outFolder - , true // showDialog - , false // elimDup - , ci.WriteZone - ); -} - -/* -static void AddValuePair(UINT resourceID, UInt64 value, UString &s) -{ - AddLangString(s, resourceID); - char sz[32]; - s += ": "; - ConvertUInt64ToString(value, sz); - s += sz; - s.Add_LF(); -} - -// now we don't need CThreadTest, since now we call CopyTo for "test command - -class CThreadTest: public CProgressThreadVirt -{ - HRESULT ProcessVirt(); -public: - CRecordVector Indices; - CExtractCallbackImp *ExtractCallbackSpec; - CMyComPtr ExtractCallback; - CMyComPtr ArchiveFolder; -}; - -HRESULT CThreadTest::ProcessVirt() -{ - RINOK(ArchiveFolder->Extract(&Indices[0], Indices.Size(), - true, // includeAltStreams - false, // replaceAltStreamColon - NExtract::NPathMode::kFullPathnames, - NExtract::NOverwriteMode::kAskBefore, - NULL, // path - BoolToInt(true), // testMode - ExtractCallback)); - if (ExtractCallbackSpec->IsOK()) - { - UString s; - AddValuePair(IDS_PROP_FOLDERS, ExtractCallbackSpec->NumFolders, s); - AddValuePair(IDS_PROP_FILES, ExtractCallbackSpec->NumFiles, s); - // AddValuePair(IDS_PROP_SIZE, ExtractCallbackSpec->UnpackSize, s); - // AddSizePair(IDS_COMPRESSED_COLON, Stat.PackSize, s); - s.Add_LF(); - AddLangString(s, IDS_MESSAGE_NO_ERRORS); - FinalMessage.OkMessage.Message = s; - } - return S_OK; -} - -static void AddSizePair(UInt32 langID, UInt64 value, UString &s) -{ - char sz[32]; - AddLangString(s, langID); - s += L' '; - ConvertUInt64ToString(value, sz); - s += sz; - ConvertUInt64ToString(value >> 20, sz); - s += " ("; - s += sz; - s += " MB)"; - s.Add_LF(); -} -*/ - -void CPanel::TestArchives() -{ - CRecordVector indices; - Get_ItemIndices_OperSmart(indices); - CMyComPtr archiveFolder; - _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder); - if (archiveFolder) - { - CCopyToOptions options; - options.streamMode = true; - options.showErrorMessages = true; - options.testMode = true; - - UStringVector messages; - HRESULT res = CopyTo(options, indices, &messages); - if (res != S_OK) - { - if (res != E_ABORT) - MessageBox_Error_HRESULT(res); - } - return; - - /* - { - CThreadTest extracter; - - extracter.ArchiveFolder = archiveFolder; - extracter.ExtractCallbackSpec = new CExtractCallbackImp; - extracter.ExtractCallback = extracter.ExtractCallbackSpec; - extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog; - if (!_parentFolders.IsEmpty()) - { - const CFolderLink &fl = _parentFolders.Back(); - extracter.ExtractCallbackSpec->PasswordIsDefined = fl.UsePassword; - extracter.ExtractCallbackSpec->Password = fl.Password; - } - - if (indices.IsEmpty()) - return; - - extracter.Indices = indices; - - const UString title = LangString(IDS_PROGRESS_TESTING); - - extracter.ProgressDialog.CompressingMode = false; - extracter.ProgressDialog.MainWindow = GetParent(); - extracter.ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); - extracter.ProgressDialog.MainAddTitle = title + L' '; - - extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAskBefore; - extracter.ExtractCallbackSpec->Init(); - - if (extracter.Create(title, GetParent()) != S_OK) - return; - - } - RefreshTitleAlways(); - return; - */ - } - - if (!IsFSFolder()) - { - MessageBox_Error_UnsupportOperation(); - return; - } - UStringVector paths; - GetFilePaths(indices, paths); - if (paths.IsEmpty()) - { - MessageBox_Error_LangID(IDS_SELECT_FILES); - return; - } - ::TestArchives(paths); -} +// Panel.cpp + +#include "StdAfx.h" + +#include + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/Thread.h" + +#include "../../PropID.h" + +#include "resource.h" +#include "../GUI/ExtractRes.h" + +#include "../Common/ArchiveName.h" +#include "../Common/CompressCall.h" +#include "../Common/ZipRegistry.h" + +#include "../Agent/IFolderArchive.h" + +#include "App.h" +#include "ExtractCallback.h" +#include "FSFolder.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "Panel.h" +#include "RootFolder.h" + +#include "PropertyNameRes.h" + +using namespace NWindows; +using namespace NControl; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +static const UINT_PTR kTimerID = 1; +static const UINT kTimerElapse = 1000; + +static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT }; + +// static const int kCreateFolderID = 101; + +extern HINSTANCE g_hInstance; + +void CPanel::ReleasePanel() +{ + Disable_Processing_Timer_Notify_StatusBar(); + // It's for unloading COM dll's: don't change it. + CloseOpenFolders(); + _sevenZipContextMenu.Release(); + _systemContextMenu.Release(); +} + +CPanel::~CPanel() +{ + CloseOpenFolders(); +} + +HWND CPanel::GetParent() const +{ + const HWND h = CWindow2::GetParent(); + return h ? h : _mainWindow; +} + +#define kClassName L"7-Zip::Panel" + + +HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id, + const UString ¤tFolderPrefix, + const UString &arcFormat, + CPanelCallback *panelCallback, CAppState *appState, + bool needOpenArc, + COpenResult &openRes) +{ + _mainWindow = mainWindow; + _processTimer = true; + _processNotify = true; + _processStatusBar = true; + + _panelCallback = panelCallback; + _appState = appState; + // _index = index; + _baseID = id; + _comboBoxID = _baseID + 3; + _statusBarID = _comboBoxID + 1; + + UString cfp = currentFolderPrefix; + + if (!currentFolderPrefix.IsEmpty()) + if (currentFolderPrefix[0] == L'.') + { + FString cfpF; + if (NFile::NDir::MyGetFullPathName(us2fs(currentFolderPrefix), cfpF)) + cfp = fs2us(cfpF); + } + + RINOK(BindToPath(cfp, arcFormat, openRes)) + + if (needOpenArc && !openRes.ArchiveIsOpened) + return S_OK; + + if (!CreateEx(0, kClassName, NULL, WS_CHILD | WS_VISIBLE, + 0, 0, _xSize, 260, + parentWindow, (HMENU)(UINT_PTR)id, g_hInstance)) + return E_FAIL; + PanelCreated = true; + + return S_OK; +} + +// extern UInt32 g_NumMessages; + +LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + // g_NumMessages++; + switch (message) + { + case kShiftSelectMessage: + OnShiftSelectMessage(); + return 0; + case kReLoadMessage: + RefreshListCtrl(_selectedState); + return 0; + case kSetFocusToListView: + _listView.SetFocus(); + return 0; + case kOpenItemChanged: + return OnOpenItemChanged(lParam); + case kRefresh_StatusBar: + if (_processStatusBar) + Refresh_StatusBar(); + return 0; + #ifdef UNDER_CE + case kRefresh_HeaderComboBox: + LoadFullPathAndShow(); + return 0; + #endif + case WM_TIMER: + OnTimer(); + return 0; + case WM_CONTEXTMENU: + if (OnContextMenu(HANDLE(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))) + return 0; + break; + /* + case WM_DROPFILES: + CompressDropFiles(HDROP(wParam)); + return 0; + */ + } + return CWindow2::OnMessage(message, wParam, lParam); +} + +LRESULT CMyListView::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == WM_CHAR) + { + UINT scanCode = (UINT)((lParam >> 16) & 0xFF); + bool extended = ((lParam & 0x1000000) != 0); + UINT virtualKey = MapVirtualKey(scanCode, 1); + if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD || + virtualKey == VK_SUBTRACT) + return 0; + if ((wParam == '/' && extended) + || wParam == '\\' || wParam == '/') + { + _panel->OpenDrivesFolder(); + return 0; + } + } + else if (message == WM_SYSCHAR) + { + // For Alt+Enter Beep disabling + UINT scanCode = (UINT)(lParam >> 16) & 0xFF; + UINT virtualKey = MapVirtualKey(scanCode, 1); + if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY || + virtualKey == VK_ADD || virtualKey == VK_SUBTRACT) + return 0; + } + /* + else if (message == WM_SYSKEYDOWN) + { + // return 0; + } + */ + else if (message == WM_KEYDOWN) + { + bool alt = IsKeyDown(VK_MENU); + bool ctrl = IsKeyDown(VK_CONTROL); + bool shift = IsKeyDown(VK_SHIFT); + switch (wParam) + { + /* + case VK_RETURN: + { + if (shift && !alt && !ctrl) + { + _panel->OpenSelectedItems(false); + return 0; + } + break; + } + */ + case VK_NEXT: + { + if (ctrl && !alt && !shift) + { + _panel->OpenFocusedItemAsInternal(); + return 0; + } + break; + } + case VK_PRIOR: + if (ctrl && !alt && !shift) + { + _panel->OpenParentFolder(); + return 0; + } + } + } + #ifdef UNDER_CE + else if (message == WM_KEYUP) + { + if (wParam == VK_F2) // it's VK_TSOFT2 + { + // Activate Menu + ::PostMessage(g_HWND, WM_SYSCOMMAND, SC_KEYMENU, 0); + return 0; + } + } + #endif + else if (message == WM_SETFOCUS) + { + _panel->_lastFocusedIsList = true; + _panel->_panelCallback->PanelWasFocused(); + } + return CListView2::OnMessage(message, wParam, lParam); +} + +/* +static LRESULT APIENTRY ComboBoxSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + CWindow tempDialog(hwnd); + CMyComboBox *w = (CMyComboBox *)(tempDialog.GetUserDataLongPtr()); + if (w == NULL) + return 0; + return w->OnMessage(message, wParam, lParam); +} + +LRESULT CMyComboBox::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); +} +*/ + +#ifndef UNDER_CE + +static LRESULT APIENTRY ComboBoxEditSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + CWindow tempDialog(hwnd); + CMyComboBoxEdit *w = (CMyComboBoxEdit *)(tempDialog.GetUserDataLongPtr()); + if (w == NULL) + return 0; + return w->OnMessage(message, wParam, lParam); +} + +#endif + +LRESULT CMyComboBoxEdit::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + // See MSDN / Subclassing a Combo Box / Creating a Combo-box Toolbar + switch (message) + { + case WM_SYSKEYDOWN: + switch (wParam) + { + case VK_F1: + case VK_F2: + { + // check ALT + if ((lParam & (1<<29)) == 0) + break; + bool alt = IsKeyDown(VK_MENU); + bool ctrl = IsKeyDown(VK_CONTROL); + bool shift = IsKeyDown(VK_SHIFT); + if (alt && !ctrl && !shift) + { + _panel->_panelCallback->SetFocusToPath(wParam == VK_F1 ? 0 : 1); + return 0; + } + break; + } + } + break; + case WM_KEYDOWN: + switch (wParam) + { + case VK_TAB: + // SendMessage(hwndMain, WM_ENTER, 0, 0); + _panel->SetFocusToList(); + return 0; + case VK_F9: + { + bool alt = IsKeyDown(VK_MENU); + bool ctrl = IsKeyDown(VK_CONTROL); + bool shift = IsKeyDown(VK_SHIFT); + if (!alt && !ctrl && !shift) + { + g_App.SwitchOnOffOnePanel(); + return 0; + } + break; + } + case 'W': + { + bool ctrl = IsKeyDown(VK_CONTROL); + if (ctrl) + { + PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0); + return 0; + } + break; + } + } + break; + case WM_CHAR: + switch (wParam) + { + case VK_TAB: + case VK_ESCAPE: + return 0; + } + } + #ifndef _UNICODE + if (g_IsNT) + return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam); + else + #endif + return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); +} + + +/* + REBARBANDINFO in vista (_WIN32_WINNT >= 0x0600) has additional fields + we want 2000/xp compatibility. + so we must use reduced structure, if we compile with (_WIN32_WINNT >= 0x0600) + Also there are additional fields, if (_WIN32_IE >= 0x0400). + but (_WIN32_IE >= 0x0400) is expected. + note: + in x64 (64-bit): + { + (108 == REBARBANDINFO_V6_SIZE) + (112 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT < 0x0600) + (128 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT >= 0x0600) + there is difference in sizes, because REBARBANDINFO size was + not aligned for 8-bytes in (_WIN32_WINNT < 0x0600). + We hope that WinVista+ support support both (108 and 112) sizes. + But does WinXP-x64 support (108 == REBARBANDINFO_V6_SIZE)? + { + 96 LPARAM lParam; + 104 UINT cxHeader; + #if (_WIN32_WINNT >= 0x0600) + 108 RECT rcChevronLocation; + 124 UINT uChevronState; + #endif + } +*/ + +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && defined(REBARBANDINFOA_V6_SIZE) + #define my_compatib_REBARBANDINFO_size REBARBANDINFO_V6_SIZE +#else + #define my_compatib_REBARBANDINFO_size sizeof(REBARBANDINFO) +#endif + + +bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */) +{ + // _virtualMode = false; + // _sortIndex = 0; + _sortID = kpidName; + _ascending = true; + _lastFocusedIsList = true; + + DWORD style = WS_CHILD | WS_VISIBLE; // | WS_BORDER ; // | LVS_SHAREIMAGELISTS; // | LVS_SHOWSELALWAYS; + + style |= LVS_SHAREIMAGELISTS; + // style |= LVS_AUTOARRANGE; + style |= WS_CLIPCHILDREN; + style |= WS_CLIPSIBLINGS; + + const UInt32 kNumListModes = Z7_ARRAY_SIZE(kStyles); + if (_listViewMode >= kNumListModes) + _listViewMode = kNumListModes - 1; + + style |= kStyles[_listViewMode] + | WS_TABSTOP + | LVS_EDITLABELS; + if (_mySelectMode) + style |= LVS_SINGLESEL; + + /* + if (_virtualMode) + style |= LVS_OWNERDATA; + */ + + DWORD exStyle; + exStyle = WS_EX_CLIENTEDGE; + + if (!_listView.CreateEx(exStyle, style, 0, 0, 116, 260, + *this, (HMENU)(UINT_PTR)(_baseID + 1), g_hInstance, NULL)) + return false; + + _listView.SetUnicodeFormat(); + _listView._panel = this; + _listView.SetWindowProc(); + + _listView.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL); + _listView.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL); + + // _exStyle |= LVS_EX_HEADERDRAGDROP; + // DWORD extendedStyle = _listView.GetExtendedListViewStyle(); + // extendedStyle |= _exStyle; + // _listView.SetExtendedListViewStyle(extendedStyle); + SetExtendedStyle(); + + _listView.Show(SW_SHOW); + _listView.InvalidateRect(NULL, true); + _listView.Update(); + + // Ensure that the common control DLL is loaded. + INITCOMMONCONTROLSEX icex; + + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_BAR_CLASSES; + InitCommonControlsEx(&icex); + + const TBBUTTON tbb[] = + { + // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, + {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, 0 }, + // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0}, + // {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0}, + }; + +#ifdef Z7_USE_DYN_ComCtl32Version + if (g_ComCtl32Version >= MAKELONG(71, 4)) +#endif + { + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES; + InitCommonControlsEx(&icex); + + // if there is no CCS_NOPARENTALIGN, there is space of some pixels after rebar (Incorrect GetWindowRect ?) + + _headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW, + REBARCLASSNAME, + NULL, WS_VISIBLE | WS_BORDER | WS_CHILD | + WS_CLIPCHILDREN | WS_CLIPSIBLINGS + | CCS_NODIVIDER + | CCS_NOPARENTALIGN + | CCS_TOP + | RBS_VARHEIGHT + | RBS_BANDBORDERS + ,0,0,0,0, *this, NULL, g_hInstance, NULL)); + } + + DWORD toolbarStyle = WS_CHILD | WS_VISIBLE ; + if (_headerReBar) + { + toolbarStyle |= 0 + // | WS_CLIPCHILDREN + // | WS_CLIPSIBLINGS + + | TBSTYLE_TOOLTIPS + | CCS_NODIVIDER + | CCS_NORESIZE + | TBSTYLE_FLAT + ; + } + + _headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle, + _baseID + 2, 11, + (HINSTANCE)HINST_COMMCTRL, + IDB_VIEW_SMALL_COLOR, + (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb), + 0, 0, 0, 0, sizeof (TBBUTTON))); + + #ifndef UNDER_CE + // Load ComboBoxEx class + icex.dwSize = sizeof(INITCOMMONCONTROLSEX); + icex.dwICC = ICC_USEREX_CLASSES; + InitCommonControlsEx(&icex); + #endif + + _headerComboBox.CreateEx(0, + #ifdef UNDER_CE + WC_COMBOBOXW + #else + WC_COMBOBOXEXW + #endif + , NULL, + WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL, + 0, 0, 100, 620, + (_headerReBar ? _headerToolBar : (HWND)*this), + (HMENU)(UINT_PTR)(_comboBoxID), + g_hInstance, NULL); + +#ifndef UNDER_CE + _headerComboBox.SetUnicodeFormat(true); + _headerComboBox.SetImageList(Shell_Get_SysImageList_smallIcons(true)); + _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC); + /* + _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox)); + _headerComboBox._panel = this; + _headerComboBox._origWindowProc = + (WNDPROC)_headerComboBox.SetLongPtr(GWLP_WNDPROC, + LONG_PTR(ComboBoxSubclassProc)); + */ + _comboBoxEdit.Attach(_headerComboBox.GetEditControl()); + // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0); + _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit)); + _comboBoxEdit._panel = this; + #ifndef _UNICODE + if (g_IsNT) + _comboBoxEdit._origWindowProc = + (WNDPROC)_comboBoxEdit.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc)); + else + #endif + _comboBoxEdit._origWindowProc = + (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc)); +#endif + + if (_headerReBar) + { + REBARINFO rbi; + rbi.cbSize = sizeof(REBARINFO); // Required when using this struct. + rbi.fMask = 0; + rbi.himl = (HIMAGELIST)NULL; + _headerReBar.SetBarInfo(&rbi); + + // Send the TB_BUTTONSTRUCTSIZE message, which is required for + // backward compatibility. + // _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); + SIZE size; + _headerToolBar.GetMaxSize(&size); + + REBARBANDINFO rbBand; + memset(&rbBand, 0, sizeof(rbBand)); + // rbBand.cbSize = sizeof(rbBand); // for debug + // rbBand.cbSize = REBARBANDINFO_V3_SIZE; // for debug + rbBand.cbSize = my_compatib_REBARBANDINFO_size; + rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; + rbBand.fStyle = RBBS_NOGRIPPER; + rbBand.cxMinChild = (UINT)size.cx; + rbBand.cyMinChild = (UINT)size.cy; + rbBand.cyChild = (UINT)size.cy; + rbBand.cx = (UINT)size.cx; + rbBand.hwndChild = _headerToolBar; + _headerReBar.InsertBand(-1, &rbBand); + + RECT rc; + ::GetWindowRect(_headerComboBox, &rc); + rbBand.cxMinChild = 30; + rbBand.cyMinChild = (UINT)(rc.bottom - rc.top); + rbBand.cx = 1000; + rbBand.hwndChild = _headerComboBox; + _headerReBar.InsertBand(-1, &rbBand); + // _headerReBar.MaximizeBand(1, false); + } + + _statusBar.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID); + // _statusBar2.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID + 1); + + const int sizes[] = {220, 320, 420, -1}; + _statusBar.SetParts(4, sizes); + // _statusBar2.SetParts(5, sizes); + + /* + RECT rect; + GetClientRect(&rect); + OnSize(0, RECT_SIZE_X(rect), RECT_SIZE_Y(rect)); + */ + + SetTimer(kTimerID, kTimerElapse); + + // InitListCtrl(); + RefreshListCtrl(); + + return true; +} + +void CPanel::OnDestroy() +{ + SaveListViewInfo(); + CWindow2::OnDestroy(); +} + +void CPanel::ChangeWindowSize(int xSize, int ySize) +{ + if (!(HWND)*this) + return; + int kHeaderSize; + int kStatusBarSize; + // int kStatusBar2Size; + RECT rect; + if (_headerReBar) + _headerReBar.GetWindowRect(&rect); + else + _headerToolBar.GetWindowRect(&rect); + + kHeaderSize = RECT_SIZE_Y(rect); + + _statusBar.GetWindowRect(&rect); + kStatusBarSize = RECT_SIZE_Y(rect); + + // _statusBar2.GetWindowRect(&rect); + // kStatusBar2Size = RECT_SIZE_Y(rect); + + int yListViewSize = MyMax(ySize - kHeaderSize - kStatusBarSize, 0); + const int kStartXPos = 32; + if (_headerReBar) + { + } + else + { + _headerToolBar.Move(0, 0, xSize, 0); + _headerComboBox.Move(kStartXPos, 2, + MyMax(xSize - kStartXPos - 10, kStartXPos), 0); + } + _listView.Move(0, kHeaderSize, xSize, yListViewSize); + _statusBar.Move(0, kHeaderSize + yListViewSize, xSize, kStatusBarSize); + // _statusBar2.MoveWindow(0, kHeaderSize + yListViewSize + kStatusBarSize, xSize, kStatusBar2Size); + // _statusBar.MoveWindow(0, 100, xSize, kStatusBarSize); + // _statusBar2.MoveWindow(0, 200, xSize, kStatusBar2Size); +} + +bool CPanel::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + if (!(HWND)*this) + return true; + if (_headerReBar) + _headerReBar.Move(0, 0, xSize, 0); + ChangeWindowSize(xSize, ySize); + return true; +} + +bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */) +{ + switch (header->code) + { + case RBN_HEIGHTCHANGE: + { + RECT rect; + GetWindowRect(&rect); + ChangeWindowSize(RECT_SIZE_X(rect), RECT_SIZE_Y(rect)); + return false; + } + } + return false; +} + +/* +UInt32 g_OnNotify = 0; +UInt32 g_LVIF_TEXT = 0; +UInt32 g_Time = 0; + +void Print_OnNotify(const char *name) +{ + char s[256]; + DWORD tim = GetTickCount(); + sprintf(s, + "Time = %7u ms, Notify = %9u, TEXT = %9u, %s", + tim - g_Time, + g_OnNotify, + g_LVIF_TEXT, + name); + g_Time = tim; + OutputDebugStringA(s); + g_OnNotify = 0; + g_LVIF_TEXT = 0; +} +*/ + +bool CPanel::OnNotify(UINT /* controlID */, LPNMHDR header, LRESULT &result) +{ + /* + g_OnNotify++; + + if (header->hwndFrom == _listView) + { + if (header->code == LVN_GETDISPINFOW) + { + LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header; + if ((dispInfo->item.mask & LVIF_TEXT)) + g_LVIF_TEXT++; + } + } + */ + + if (!_processNotify) + return false; + + if (header->hwndFrom == _headerComboBox) + return OnNotifyComboBox(header, result); + else if (header->hwndFrom == _headerReBar) + return OnNotifyReBar(header, result); + else if (header->hwndFrom == _listView) + return OnNotifyList(header, result); + else if (::GetParent(header->hwndFrom) == _listView) + { + // NMHDR:code is UINT + // NM_RCLICK is unsigned in windows sdk + // NM_RCLICK is int in MinGW + if (header->code == (UINT)NM_RCLICK) + return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result); + } + return false; +} + +bool CPanel::OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) +{ + if (itemID == kParentFolderID) + { + OpenParentFolder(); + result = 0; + return true; + } + /* + if (itemID == kCreateFolderID) + { + CreateFolder(); + result = 0; + return true; + } + */ + if (itemID == _comboBoxID) + { + if (OnComboBoxCommand(code, lParam, result)) + return true; + } + return CWindow2::OnCommand(code, itemID, lParam, result); +} + + + +/* +void CPanel::MessageBox_Info(LPCWSTR message, LPCWSTR caption) const + { ::MessageBoxW((HWND)*this, message, caption, MB_OK); } +void CPanel::MessageBox_Warning(LPCWSTR message) const + { ::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OK | MB_ICONWARNING); } +*/ + +void CPanel::MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const + { ::MessageBoxW((HWND)*this, message, caption, MB_OK | MB_ICONSTOP); } + +void CPanel::MessageBox_Error(LPCWSTR message) const + { MessageBox_Error_Caption(message, L"7-Zip"); } + +static UString ErrorHResult_To_Message(HRESULT errorCode) +{ + if (errorCode == 0) + errorCode = E_FAIL; + return HResultToMessage(errorCode); +} + +void CPanel::MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const +{ + MessageBox_Error_Caption(ErrorHResult_To_Message(errorCode), caption); +} + +void CPanel::MessageBox_Error_HRESULT(HRESULT errorCode) const + { MessageBox_Error_HRESULT_Caption(errorCode, L"7-Zip"); } + +void CPanel::MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const +{ + UString m = message; + m.Add_LF(); + m += ErrorHResult_To_Message(errorCode); + MessageBox_Error(m); +} + +void CPanel::MessageBox_LastError(LPCWSTR caption) const + { MessageBox_Error_HRESULT_Caption(GetLastError_noZero_HRESULT(), caption); } + +void CPanel::MessageBox_LastError() const + { MessageBox_LastError(L"7-Zip"); } + +void CPanel::MessageBox_Error_LangID(UINT resourceID) const + { MessageBox_Error(LangString(resourceID)); } + +void CPanel::MessageBox_Error_UnsupportOperation() const + { MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); } + + + + +void CPanel::SetFocusToList() +{ + _listView.SetFocus(); + // SetCurrentPathText(); +} + +void CPanel::SetFocusToLastRememberedItem() +{ + if (_lastFocusedIsList) + SetFocusToList(); + else + _headerComboBox.SetFocus(); +} + +UString CPanel::GetFolderTypeID() const +{ + { + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(kpidType, &prop) == S_OK) + if (prop.vt == VT_BSTR) + return (const wchar_t *)prop.bstrVal; + } + return UString(); +} + +bool CPanel::IsFolderTypeEqTo(const char *s) const +{ + return StringsAreEqual_Ascii(GetFolderTypeID(), s); +} + +bool CPanel::IsRootFolder() const { return IsFolderTypeEqTo("RootFolder"); } +bool CPanel::IsFSFolder() const { return IsFolderTypeEqTo("FSFolder"); } +bool CPanel::IsFSDrivesFolder() const { return IsFolderTypeEqTo("FSDrives"); } +bool CPanel::IsAltStreamsFolder() const { return IsFolderTypeEqTo("AltStreamsFolder"); } +bool CPanel::IsArcFolder() const +{ + return GetFolderTypeID().IsPrefixedBy_Ascii_NoCase("7-Zip"); +} + +bool CPanel::IsHashFolder() const +{ + if (_folder) + { + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(kpidIsHash, &prop) == S_OK) + if (prop.vt == VT_BOOL) + return VARIANT_BOOLToBool(prop.boolVal); + } + return false; +} + +UString CPanel::GetFsPath() const +{ + if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix() && !IsSuperDrivesPrefix()) + return UString(); + return _currentFolderPrefix; +} + +UString CPanel::GetDriveOrNetworkPrefix() const +{ + if (!IsFSFolder()) + return UString(); + UString drive = GetFsPath(); + drive.DeleteFrom(NFile::NName::GetRootPrefixSize(drive)); + return drive; +} + +void CPanel::SetListViewMode(UInt32 index) +{ + if (index >= 4) + return; + _listViewMode = index; + const LONG_PTR oldStyle = _listView.GetStyle(); + const DWORD newStyle = kStyles[index]; + + // DWORD tickCount1 = GetTickCount(); + if ((oldStyle & LVS_TYPEMASK) != (LONG_PTR)newStyle) + _listView.SetStyle((oldStyle & ~(LONG_PTR)(DWORD)LVS_TYPEMASK) | (LONG_PTR)newStyle); + // RefreshListCtrlSaveFocused(); + /* + DWORD tickCount2 = GetTickCount(); + char s[256]; + sprintf(s, "SetStyle = %5d", + tickCount2 - tickCount1 + ); + OutputDebugStringA(s); + */ + +} + +void CPanel::ChangeFlatMode() +{ + _flatMode = !_flatMode; + if (!_parentFolders.IsEmpty()) + _flatModeForArc = _flatMode; + else + _flatModeForDisk = _flatMode; + RefreshListCtrl_SaveFocused(); +} + +/* +void CPanel::Change_ShowNtfsStrems_Mode() +{ + _showNtfsStrems_Mode = !_showNtfsStrems_Mode; + if (!_parentFolders.IsEmpty()) + _showNtfsStrems_ModeForArc = _showNtfsStrems_Mode; + else + _showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode; + RefreshListCtrlSaveFocused(); +} +*/ + +void CPanel::Post_Refresh_StatusBar() +{ + if (_processStatusBar) + PostMsg(kRefresh_StatusBar); +} + +void CPanel::AddToArchive() +{ + if (!Is_IO_FS_Folder()) + { + MessageBox_Error_UnsupportOperation(); + return; + } + CRecordVector indices; + Get_ItemIndices_Operated(indices); + if (indices.Size() == 0) + { + MessageBox_Error_LangID(IDS_SELECT_FILES); + return; + } + UString destCurDirPrefix = GetFsPath(); + if (IsFSDrivesFolder()) + destCurDirPrefix = ROOT_FS_FOLDER; + UStringVector names; + GetFilePaths(indices, names); + UString baseName; + const UString arcName = CreateArchiveName(names, + false, // isHash + NULL, // CFileInfo *fi + baseName); + const HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"", + true, // addExtension + names, + false, // email + true, // showDialog + false); // waitFinish + if (res != S_OK) + { + if (destCurDirPrefix.Len() >= MAX_PATH) + MessageBox_Error_LangID(IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER); + } + // KillSelection(); +} + +// function from ContextMenu.cpp +UString GetSubFolderNameForExtract(const UString &arcPath); + +static UString GetSubFolderNameForExtract2(const UString &arcPath) +{ + int slashPos = arcPath.ReverseFind_PathSepar(); + UString s; + UString name = arcPath; + if (slashPos >= 0) + { + s = arcPath.Left((unsigned)(slashPos + 1)); + name = arcPath.Ptr((unsigned)(slashPos + 1)); + } + s += GetSubFolderNameForExtract(name); + return s; +} + + +int CPanel::FindDir_InOperatedList(const CRecordVector &operatedIndices) const +{ + const bool *isDirVector = _isDirVector.ConstData(); + const UInt32 *indices = operatedIndices.ConstData(); + const unsigned numItems = operatedIndices.Size(); + for (unsigned i = 0; i < numItems; i++) + if (isDirVector[indices[i]]) + return (int)i; + return -1; +} + + +void CPanel::GetFilePaths(const CRecordVector &operatedIndices, UStringVector &paths) const +{ + paths.ClearAndReserve(operatedIndices.Size()); + UString path = GetFsPath(); + const unsigned prefixLen = path.Len(); + const UInt32 *indices = operatedIndices.ConstData(); + const unsigned numItems = operatedIndices.Size(); + // for (unsigned y = 0; y < 10000; y++, paths.Clear()) + for (unsigned i = 0; i < numItems; i++) + { + path.DeleteFrom(prefixLen); + Add_ItemRelPath2_To_String(indices[i], path); + // ODS_U(path) + paths.AddInReserved(path); + } +} + + +void CPanel::ExtractArchives() +{ + if (!_parentFolders.IsEmpty()) + { + _panelCallback->OnCopy(false, false); + return; + } + CRecordVector indices; + Get_ItemIndices_Operated(indices); + if (indices.IsEmpty() || FindDir_InOperatedList(indices) != -1) + { + MessageBox_Error_LangID(IDS_SELECT_FILES); + return; + } + UStringVector paths; + GetFilePaths(indices, paths); + UString outFolder = GetFsPath(); + if (indices.Size() == 1) + outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0])); + else + outFolder.Add_Char('*'); + outFolder.Add_PathSepar(); + + CContextMenuInfo ci; + ci.Load(); + + ::ExtractArchives(paths, outFolder + , true // showDialog + , false // elimDup + , ci.WriteZone + ); +} + +/* +static void AddValuePair(UINT resourceID, UInt64 value, UString &s) +{ + AddLangString(s, resourceID); + char sz[32]; + s += ": "; + ConvertUInt64ToString(value, sz); + s += sz; + s.Add_LF(); +} + +// now we don't need CThreadTest, since now we call CopyTo for "test command + +class CThreadTest: public CProgressThreadVirt +{ + HRESULT ProcessVirt(); +public: + CRecordVector Indices; + CExtractCallbackImp *ExtractCallbackSpec; + CMyComPtr ExtractCallback; + CMyComPtr ArchiveFolder; +}; + +HRESULT CThreadTest::ProcessVirt() +{ + RINOK(ArchiveFolder->Extract(&Indices[0], Indices.Size(), + true, // includeAltStreams + false, // replaceAltStreamColon + NExtract::NPathMode::kFullPathnames, + NExtract::NOverwriteMode::kAskBefore, + NULL, // path + BoolToInt(true), // testMode + ExtractCallback)); + if (ExtractCallbackSpec->IsOK()) + { + UString s; + AddValuePair(IDS_PROP_FOLDERS, ExtractCallbackSpec->NumFolders, s); + AddValuePair(IDS_PROP_FILES, ExtractCallbackSpec->NumFiles, s); + // AddValuePair(IDS_PROP_SIZE, ExtractCallbackSpec->UnpackSize, s); + // AddSizePair(IDS_COMPRESSED_COLON, Stat.PackSize, s); + s.Add_LF(); + AddLangString(s, IDS_MESSAGE_NO_ERRORS); + FinalMessage.OkMessage.Message = s; + } + return S_OK; +} + +static void AddSizePair(UInt32 langID, UInt64 value, UString &s) +{ + char sz[32]; + AddLangString(s, langID); + s += L' '; + ConvertUInt64ToString(value, sz); + s += sz; + ConvertUInt64ToString(value >> 20, sz); + s += " ("; + s += sz; + s += " MB)"; + s.Add_LF(); +} +*/ + +void CPanel::TestArchives() +{ + CRecordVector indices; + Get_ItemIndices_OperSmart(indices); + CMyComPtr archiveFolder; + _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder); + if (archiveFolder) + { + CCopyToOptions options; + options.streamMode = true; + options.showErrorMessages = true; + options.testMode = true; + + UStringVector messages; + HRESULT res = CopyTo(options, indices, &messages); + if (res != S_OK) + { + if (res != E_ABORT) + MessageBox_Error_HRESULT(res); + } + return; + + /* + { + CThreadTest extracter; + + extracter.ArchiveFolder = archiveFolder; + extracter.ExtractCallbackSpec = new CExtractCallbackImp; + extracter.ExtractCallback = extracter.ExtractCallbackSpec; + extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog; + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &fl = _parentFolders.Back(); + extracter.ExtractCallbackSpec->PasswordIsDefined = fl.UsePassword; + extracter.ExtractCallbackSpec->Password = fl.Password; + } + + if (indices.IsEmpty()) + return; + + extracter.Indices = indices; + + const UString title = LangString(IDS_PROGRESS_TESTING); + + extracter.ProgressDialog.CompressingMode = false; + extracter.ProgressDialog.MainWindow = GetParent(); + extracter.ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); + extracter.ProgressDialog.MainAddTitle = title + L' '; + + extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAskBefore; + extracter.ExtractCallbackSpec->Init(); + + if (extracter.Create(title, GetParent()) != S_OK) + return; + + } + RefreshTitleAlways(); + return; + */ + } + + if (!IsFSFolder()) + { + MessageBox_Error_UnsupportOperation(); + return; + } + UStringVector paths; + GetFilePaths(indices, paths); + if (paths.IsEmpty()) + { + MessageBox_Error_LangID(IDS_SELECT_FILES); + return; + } + ::TestArchives(paths); +} diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h index 7ad169760..9c5304880 100644 --- a/CPP/7zip/UI/FileManager/Panel.h +++ b/CPP/7zip/UI/FileManager/Panel.h @@ -1,1021 +1,1020 @@ -// Panel.h - -#ifndef ZIP7_INC_PANEL_H -#define ZIP7_INC_PANEL_H - -#include "../../../Common/MyWindows.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../../C/Alloc.h" - -#include "../../../Common/Defs.h" -#include "../../../Common/MyCom.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Handle.h" -#include "../../../Windows/PropVariantConv.h" -#include "../../../Windows/Synchronization.h" - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Edit.h" -#include "../../../Windows/Control/ListView.h" -#include "../../../Windows/Control/ReBar.h" -#include "../../../Windows/Control/Static.h" -#include "../../../Windows/Control/StatusBar.h" -#include "../../../Windows/Control/ToolBar.h" -#include "../../../Windows/Control/Window2.h" - -#include "../../Archive/IArchive.h" - -#include "ExtractCallback.h" - -#include "AppState.h" -#include "IFolder.h" -#include "MyCom2.h" -#include "ProgressDialog2.h" -#include "SysIconUtils.h" - -#ifdef UNDER_CE -#define NON_CE_VAR(_v_) -#else -#define NON_CE_VAR(_v_) _v_ -#endif - -const int kParentFolderID = 100; - -const unsigned kParentIndex = (unsigned)(int)-1; -const UInt32 kParentIndex_UInt32 = (UInt32)(Int32)kParentIndex; - -#if !defined(_WIN32) || defined(UNDER_CE) -#define ROOT_FS_FOLDER L"\\" -#else -#define ROOT_FS_FOLDER L"C:\\" -#endif - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // < win2000 -#define Z7_USE_DYN_ComCtl32Version -extern DWORD g_ComCtl32Version; -#endif - -Z7_PURE_INTERFACES_BEGIN - -DECLARE_INTERFACE(CPanelCallback) -{ - virtual void OnTab() = 0; - virtual void SetFocusToPath(unsigned index) = 0; - virtual void OnCopy(bool move, bool copyToSame) = 0; - virtual void OnSetSameFolder() = 0; - virtual void OnSetSubFolder() = 0; - virtual void PanelWasFocused() = 0; - virtual void DragBegin() = 0; - virtual void DragEnd() = 0; - virtual void RefreshTitle(bool always) = 0; -}; -Z7_PURE_INTERFACES_END - -void PanelCopyItems(); - - -struct CPropColumn -{ - int Order; - PROPID ID; - VARTYPE Type; - bool IsVisible; - bool IsRawProp; - UInt32 Width; - UString Name; - - bool IsEqualTo(const CPropColumn &a) const - { - return Order == a.Order - && ID == a.ID - && Type == a.Type - && IsVisible == a.IsVisible - && IsRawProp == a.IsRawProp - && Width == a.Width - && Name == a.Name; - } - - int Compare(const CPropColumn &a) const { return MyCompare(Order, a.Order); } - - int Compare_NameFirst(const CPropColumn &a) const - { - if (ID == kpidName) - { - if (a.ID != kpidName) - return -1; - } - else if (a.ID == kpidName) - return 1; - return MyCompare(Order, a.Order); - } -}; - - -class CPropColumns: public CObjectVector -{ -public: - int FindItem_for_PropID(PROPID id) const - { - FOR_VECTOR (i, (*this)) - if ((*this)[i].ID == id) - return (int)i; - return -1; - } - - bool IsEqualTo(const CPropColumns &props) const - { - if (Size() != props.Size()) - return false; - FOR_VECTOR (i, (*this)) - if (!(*this)[i].IsEqualTo(props[i])) - return false; - return true; - } -}; - - -struct CTempFileInfo -{ - UInt32 FileIndex; // index of file in folder - bool NeedDelete; - UString RelPath; // Relative path of file from Folder - FString FolderPath; - FString FilePath; - NWindows::NFile::NFind::CFileInfo FileInfo; - - CTempFileInfo(): FileIndex((UInt32)(Int32)-1), NeedDelete(false) {} - void DeleteDirAndFile() const - { - if (NeedDelete) - { - NWindows::NFile::NDir::DeleteFileAlways(FilePath); - NWindows::NFile::NDir::RemoveDir(FolderPath); - } - } - bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const - { - return newFileInfo.Size != FileInfo.Size || - CompareFileTime(&newFileInfo.MTime, &FileInfo.MTime) != 0; - } -}; - -struct CFolderLink: public CTempFileInfo -{ - bool IsVirtual; - bool UsePassword; - NWindows::NDLL::CLibrary Library; - CMyComPtr ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0]) - UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level) - UString Password; - - UString VirtualPath; // without tail slash - CFolderLink(): IsVirtual(false), UsePassword(false) {} - - bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const - { - return IsVirtual || CTempFileInfo::WasChanged(newFileInfo); - } - -}; - -enum MyMessages -{ - // we can use WM_USER, since we have defined new window class. - // so we don't need WM_APP. - kShiftSelectMessage = WM_USER + 1, - kReLoadMessage, - kSetFocusToListView, - kOpenItemChanged, - kRefresh_StatusBar - #ifdef UNDER_CE - , kRefresh_HeaderComboBox - #endif -}; - -UString GetFolderPath(IFolderFolder *folder); - -class CPanel; - -class CMyListView Z7_final: public NWindows::NControl::CListView2 -{ - // ~CMyListView() ZIP7_eq_delete; - // CMyListView() ZIP7_eq_delete; -public: - // CMyListView() {} - // ~CMyListView() Z7_DESTRUCTOR_override {} // change it - CPanel *_panel; - LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; -}; - -/* -class CMyComboBox: public NWindows::NControl::CComboBoxEx -{ -public: - WNDPROC _origWindowProc; - CPanel *_panel; - LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); -}; -*/ -class CMyComboBoxEdit: public NWindows::NControl::CEdit -{ -public: - WNDPROC _origWindowProc; - CPanel *_panel; - LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); -}; - -struct CSelectedState -{ - int FocusedItem; - bool SelectFocused; - bool FocusedName_Defined; - bool CalledFromTimer; - UString FocusedName; - UStringVector SelectedNames; - - CSelectedState(): - FocusedItem(-1), - SelectFocused(true), - FocusedName_Defined(false), - CalledFromTimer(false) - {} -}; - -#ifdef UNDER_CE -#define MY_NMLISTVIEW_NMITEMACTIVATE NMLISTVIEW -#else -#define MY_NMLISTVIEW_NMITEMACTIVATE NMITEMACTIVATE -#endif - -struct CCopyToOptions -{ - bool streamMode; - bool moveMode; - bool testMode; - bool includeAltStreams; - bool replaceAltStreamChars; - bool showErrorMessages; - - bool NeedRegistryZone; - NExtract::NZoneIdMode::EEnum ZoneIdMode; - - UString folder; - - UStringVector hashMethods; - - CVirtFileSystem *VirtFileSystemSpec; - ISequentialOutStream *VirtFileSystem; - - CCopyToOptions(): - streamMode(false), - moveMode(false), - testMode(false), - includeAltStreams(true), - replaceAltStreamChars(false), - showErrorMessages(false), - NeedRegistryZone(true), - ZoneIdMode(NExtract::NZoneIdMode::kNone), - VirtFileSystemSpec(NULL), - VirtFileSystem(NULL) - {} -}; - - - -struct COpenResult -{ - // bool needOpenArc; - // out: - bool ArchiveIsOpened; - bool Encrypted; - UString ErrorMessage; - - COpenResult(): - // needOpenArc(false), - ArchiveIsOpened(false), Encrypted(false) {} -}; - - - - -class CPanel Z7_final: public NWindows::NControl::CWindow2 -{ - // CExtToIconMap _extToIconMap; - UINT _baseID; - unsigned _comboBoxID; - UINT _statusBarID; - - CAppState *_appState; - - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) Z7_override; - virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - virtual bool OnCreate(CREATESTRUCT *createStruct) Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual void OnDestroy() Z7_override; - virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result) Z7_override; - - void AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList); - - bool OnComboBoxCommand(UINT code, LPARAM param, LRESULT &result); - - #ifndef UNDER_CE - - LRESULT OnNotifyComboBoxEnter(const UString &s); - bool OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result); - #ifndef _UNICODE - bool OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result); - #endif - - #endif - - bool OnNotifyReBar(LPNMHDR lParam, LRESULT &result); - bool OnNotifyComboBox(LPNMHDR lParam, LRESULT &result); - void OnItemChanged(NMLISTVIEW *item); - void OnNotifyActivateItems(); - bool OnNotifyList(LPNMHDR lParam, LRESULT &result); - void OnDrag(LPNMLISTVIEW nmListView, bool isRightButton = false); - bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result); - BOOL OnBeginLabelEdit(LV_DISPINFOW * lpnmh); - BOOL OnEndLabelEdit(LV_DISPINFOW * lpnmh); - void OnColumnClick(LPNMLISTVIEW info); - bool OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result); - - -public: - HWND _mainWindow; - CPanelCallback *_panelCallback; - - // void SysIconsWereChanged() { _extToIconMap.Clear(); } - - void DeleteItems(bool toRecycleBin); - void CreateFolder(); - void CreateFile(); - bool CorrectFsPath(const UString &path, UString &result); - // bool IsPathForPlugin(const UString &path); - -private: - - void ChangeWindowSize(int xSize, int ySize); - - HRESULT InitColumns(); - void DeleteColumn(unsigned index); - void AddColumn(const CPropColumn &prop); - - void SetFocusedSelectedItem(int index, bool select); - - void OnShiftSelectMessage(); - void OnArrowWithShift(); - - void OnInsert(); - // void OnUpWithShift(); - // void OnDownWithShift(); -public: - void UpdateSelection(); - void SelectSpec(bool selectMode); - void SelectByType(bool selectMode); - void SelectAll(bool selectMode); - void InvertSelection(); -private: - - // UString GetFileType(UInt32 index); - LRESULT SetItemText(LVITEMW &item); - - // CRecordVector m_ColumnsPropIDs; - -public: - NWindows::NControl::CReBar _headerReBar; - NWindows::NControl::CToolBar _headerToolBar; - NWindows::NControl:: - #ifdef UNDER_CE - CComboBox - #else - CComboBoxEx - #endif - _headerComboBox; - UStringVector ComboBoxPaths; - // CMyComboBox _headerComboBox; - CMyComboBoxEdit _comboBoxEdit; - CMyListView _listView; - bool _thereAre_ListView_Items; - NWindows::NControl::CStatusBar _statusBar; - bool _lastFocusedIsList; - // NWindows::NControl::CStatusBar _statusBar2; - - DWORD _exStyle; - bool _showDots; - bool _showRealFileIcons; - // bool _virtualMode; - // CUIntVector _realIndices; - bool _enableItemChangeNotify; - bool _mySelectMode; - - int _timestampLevel; - - - void RedrawListItems() - { - _listView.RedrawAllItems(); - } - - - CBoolVector _selectedStatusVector; - - CSelectedState _selectedState; - bool _thereAreDeletedItems; - bool _markDeletedItems; - - bool PanelCreated; - - void DeleteListItems() - { - if (_thereAre_ListView_Items) - { - bool b = _enableItemChangeNotify; - _enableItemChangeNotify = false; - _listView.DeleteAllItems(); - _thereAre_ListView_Items = false; - _enableItemChangeNotify = b; - } - } - - HWND GetParent() const; - - UInt32 GetRealIndex(const LVITEMW &item) const - { - /* - if (_virtualMode) - return _realIndices[item.iItem]; - */ - return (UInt32)item.lParam; - } - - unsigned GetRealItemIndex(int indexInListView) const - { - /* - if (_virtualMode) - return indexInListView; - */ - LPARAM param; - if (!_listView.GetItemParam((unsigned)indexInListView, param)) - throw 1; - return (unsigned)param; - } - - UInt32 _listViewMode; - int _xSize; - - bool _flatMode; - bool _flatModeForDisk; - bool _flatModeForArc; - - // bool _showNtfsStrems_Mode; - // bool _showNtfsStrems_ModeForDisk; - // bool _showNtfsStrems_ModeForArc; - - bool _dontShowMode; - - - UString _currentFolderPrefix; - - CObjectVector _parentFolders; - NWindows::NDLL::CLibrary _library; - - CMyComPtr _folder; - CBoolVector _isDirVector; - CMyComPtr _folderCompare; - CMyComPtr _folderGetItemName; - CMyComPtr _folderRawProps; - CMyComPtr _folderAltStreams; - CMyComPtr _folderOperations; - - - // for drag and drop highliting - int m_DropHighlighted_SelectionIndex; - // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item) - UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder) - - void ReleaseFolder(); - void SetNewFolder(IFolderFolder *newFolder); - - // CMyComPtr _folderGetSystemIconIndex; - - UStringVector _fastFolders; - - void GetSelectedNames(UStringVector &selectedNames); - void SaveSelectedState(CSelectedState &s); - HRESULT RefreshListCtrl(const CSelectedState &s); - HRESULT RefreshListCtrl_SaveFocused(bool onTimer = false); - - // UInt32 GetItem_Attrib(UInt32 itemIndex) const; - - bool GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const; - - bool IsItem_Deleted(unsigned itemIndex) const; - bool IsItem_Folder(unsigned itemIndex) const; - bool IsItem_AltStream(unsigned itemIndex) const; - - UString GetItemName(unsigned itemIndex) const; - UString GetItemName_for_Copy(unsigned itemIndex) const; - void GetItemName(unsigned itemIndex, UString &s) const; - UString GetItemPrefix(unsigned itemIndex) const; - UString GetItemRelPath(unsigned itemIndex) const; - UString GetItemRelPath2(unsigned itemIndex) const; - - void Add_ItemRelPath2_To_String(unsigned itemIndex, UString &s) const; - - UString GetItemFullPath(unsigned itemIndex) const; - UInt64 GetItem_UInt64Prop(unsigned itemIndex, PROPID propID) const; - UInt64 GetItemSize(unsigned itemIndex) const; - - //////////////////////// - // PanelFolderChange.cpp - - void SetToRootFolder(); - HRESULT BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes); // can be prefix - HRESULT BindToPathAndRefresh(const UString &path); - void OpenDrivesFolder(); - - void SetBookmark(unsigned index); - void OpenBookmark(unsigned index); - - void LoadFullPath(); - void LoadFullPathAndShow(); - void FoldersHistory(); - void OpenParentFolder(); - void CloseOneLevel(); - void CloseOpenFolders(); - void OpenRootFolder(); - - UString GetParentDirPrefix() const; - - HRESULT Create(HWND mainWindow, HWND parentWindow, - UINT id, - const UString ¤tFolderPrefix, - const UString &arcFormat, - CPanelCallback *panelCallback, - CAppState *appState, - bool needOpenArc, - COpenResult &openRes); - - void SetFocusToList(); - void SetFocusToLastRememberedItem(); - - - void SaveListViewInfo(); - - CPanel() : - _thereAre_ListView_Items(false), - _exStyle(0), - _showDots(false), - _showRealFileIcons(false), - // _virtualMode(flase), - _enableItemChangeNotify(true), - _mySelectMode(false), - _timestampLevel(kTimestampPrintLevel_MIN), - - _thereAreDeletedItems(false), - _markDeletedItems(true), - PanelCreated(false), - - _listViewMode(3), - _xSize(300), - - _flatMode(false), - _flatModeForDisk(false), - _flatModeForArc(false), - - // _showNtfsStrems_Mode(false), - // _showNtfsStrems_ModeForDisk(false), - // _showNtfsStrems_ModeForArc(false), - - _dontShowMode(false), - - m_DropHighlighted_SelectionIndex(-1), - - _needSaveInfo(false), - _startGroupSelect(0), - _selectionIsDefined(false) - {} - - void SetExtendedStyle() - { - if (_listView) - _listView.SetExtendedListViewStyle(_exStyle); - } - - - bool _needSaveInfo; - UString _typeIDString; - CListViewInfo _listViewInfo; - - CPropColumns _columns; - CPropColumns _visibleColumns; - - PROPID _sortID; - // int _sortIndex; - bool _ascending; - Int32 _isRawSortProp; - - void SetSortRawStatus(); - - void Release(); - ~CPanel() Z7_DESTRUCTOR_override; - void OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate); - bool OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result); - void ShowColumnsContextMenu(int x, int y); - - void OnTimer(); - void OnReload(bool onTimer = false); - bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos); - - CMyComPtr _sevenZipContextMenu; - CMyComPtr _systemContextMenu; - - HRESULT CreateShellContextMenu( - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu); - - void CreateSystemMenu(HMENU menu, - bool showExtendedVerbs, - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu); - - void CreateSevenZipMenu(HMENU menu, - bool showExtendedVerbs, - const CRecordVector &operatedIndices, - int firstDirIndex, - CMyComPtr &sevenZipContextMenu); - - void CreateFileMenu(HMENU menu, - CMyComPtr &sevenZipContextMenu, - CMyComPtr &systemContextMenu, - bool programMenu); - - void CreateFileMenu(HMENU menu); - bool InvokePluginCommand(unsigned id); - bool InvokePluginCommand(unsigned id, IContextMenu *sevenZipContextMenu, - IContextMenu *systemContextMenu); - - void InvokeSystemCommand(const char *command); - void Properties(); - void EditCut(); - void EditCopy(); - void EditPaste(); - - int _startGroupSelect; - - bool _selectionIsDefined; - bool _selectMark; - int _prevFocusedItem; - - - // void SortItems(int index); - void SortItemsWithPropID(PROPID propID); - - void Get_ItemIndices_Selected(CRecordVector &indices) const; - void Get_ItemIndices_Operated(CRecordVector &indices) const; - void Get_ItemIndices_All(CRecordVector &indices) const; - void Get_ItemIndices_OperSmart(CRecordVector &indices) const; - // void GetOperatedListViewIndices(CRecordVector &indices) const; - void KillSelection(); - - UString GetFolderTypeID() const; - - bool IsFolderTypeEqTo(const char *s) const; - bool IsRootFolder() const; - bool IsFSFolder() const; - bool IsFSDrivesFolder() const; - bool IsAltStreamsFolder() const; - bool IsArcFolder() const; - bool IsHashFolder() const; - - /* - c:\Dir - Computer\ - \\?\ - \\.\ - */ - bool Is_IO_FS_Folder() const - { - return IsFSFolder() || IsFSDrivesFolder() || IsAltStreamsFolder(); - } - - bool Is_Slow_Icon_Folder() const - { - return IsFSFolder() || IsAltStreamsFolder(); - } - - // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); } - bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; } - bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; } - - /* - c:\Dir - Computer\ - \\?\ - */ - bool IsFsOrPureDrivesFolder() const { return IsFSFolder() || (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()); } - - /* - c:\Dir - Computer\ - \\?\ - \\SERVER\ - */ - bool IsFolder_with_FsItems() const - { - if (IsFsOrPureDrivesFolder()) - return true; - #if defined(_WIN32) && !defined(UNDER_CE) - FString prefix = us2fs(GetFsPath()); - return (prefix.Len() == NWindows::NFile::NName::GetNetworkServerPrefixSize(prefix)); - #else - return false; - #endif - } - - UString GetFsPath() const; - UString GetDriveOrNetworkPrefix() const; - - bool DoesItSupportOperations() const { return _folderOperations != NULL; } - bool IsThereReadOnlyFolder() const; - bool CheckBeforeUpdate(UINT resourceID); - - bool _processTimer; - bool _processNotify; - bool _processStatusBar; - - class CDisableTimerProcessing - { - Z7_CLASS_NO_COPY(CDisableTimerProcessing) - - bool _processTimer; - CPanel &_panel; - - public: - - CDisableTimerProcessing(CPanel &panel): _panel(panel) { Disable(); } - ~CDisableTimerProcessing() { Restore(); } - void Disable() - { - _processTimer = _panel._processTimer; - _panel._processTimer = false; - } - void Restore() - { - _panel._processTimer = _processTimer; - } - }; - - class CDisableTimerProcessing2 - { - Z7_CLASS_NO_COPY(CDisableTimerProcessing2) - - bool _processTimer; - CPanel *_panel; - - public: - - CDisableTimerProcessing2(CPanel *panel): _processTimer(true), _panel(panel) { Disable(); } - ~CDisableTimerProcessing2() { Restore(); } - void Disable() - { - if (_panel) - { - _processTimer = _panel->_processTimer; - _panel->_processTimer = false; - } - } - void Restore() - { - if (_panel) - { - _panel->_processTimer = _processTimer; - _panel = NULL; - } - } - }; - - class CDisableNotify - { - Z7_CLASS_NO_COPY(CDisableNotify) - - bool _processNotify; - bool _processStatusBar; - - CPanel &_panel; - - public: - - CDisableNotify(CPanel &panel): _panel(panel) { Disable(); } - ~CDisableNotify() { Restore(); } - void Disable() - { - _processNotify = _panel._processNotify; - _processStatusBar = _panel._processStatusBar; - _panel._processNotify = false; - _panel._processStatusBar = false; - } - void SetMemMode_Enable() - { - _processNotify = true; - _processStatusBar = true; - } - void Restore() - { - _panel._processNotify = _processNotify; - _panel._processStatusBar = _processStatusBar; - } - }; - - void InvalidateList() { _listView.InvalidateRect(NULL, true); } - - HRESULT RefreshListCtrl(); - - - // void MessageBox_Info(LPCWSTR message, LPCWSTR caption) const; - // void MessageBox_Warning(LPCWSTR message) const; - void MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const; - void MessageBox_Error(LPCWSTR message) const; - void MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const; - void MessageBox_Error_HRESULT(HRESULT errorCode) const; - void MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const; - void MessageBox_LastError(LPCWSTR caption) const; - void MessageBox_LastError() const; - void MessageBox_Error_LangID(UINT resourceID) const; - void MessageBox_Error_UnsupportOperation() const; - // void MessageBoxErrorForUpdate(HRESULT errorCode, UINT resourceID); - - - void OpenAltStreams(); - - void OpenFocusedItemAsInternal(const wchar_t *type = NULL); - void OpenSelectedItems(bool internal); - - void OpenFolderExternal(unsigned index); - - void OpenFolder(unsigned index); - HRESULT OpenParentArchiveFolder(); - - HRESULT OpenAsArc(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat, - COpenResult &openRes); - - HRESULT OpenAsArc_Msg(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat - // , bool showErrorMessage - ); - - HRESULT OpenAsArc_Name(const UString &relPath, const UString &arcFormat - // , bool showErrorMessage - ); - HRESULT OpenAsArc_Index(unsigned index, const wchar_t *type /* = NULL */ - // , bool showErrorMessage - ); - - void OpenItemInArchive(unsigned index, bool tryInternal, bool tryExternal, - bool editMode, bool useEditor, const wchar_t *type = NULL); - - HRESULT OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, bool usePassword, const UString &password); - LRESULT OnOpenItemChanged(LPARAM lParam); - - bool IsVirus_Message(const UString &name); - void OpenItem(unsigned index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL); - void EditItem(bool useEditor); - void EditItem(unsigned index, bool useEditor); - - void RenameFile(); - void ChangeComment(); - - void SetListViewMode(UInt32 index); - UInt32 GetListViewMode() const { return _listViewMode; } - PROPID GetSortID() const { return _sortID; } - - void ChangeFlatMode(); - void Change_ShowNtfsStrems_Mode(); - bool GetFlatMode() const { return _flatMode; } - // bool Get_ShowNtfsStrems_Mode() const { return _showNtfsStrems_Mode; } - - bool AutoRefresh_Mode; - void Set_AutoRefresh_Mode(bool mode) - { - AutoRefresh_Mode = mode; - } - - void Post_Refresh_StatusBar(); - void Refresh_StatusBar(); - - void AddToArchive(); - - int FindDir_InOperatedList(const CRecordVector &indices) const; - void GetFilePaths(const CRecordVector &indices, UStringVector &paths) const; - void ExtractArchives(); - void TestArchives(); - - - HRESULT CopyTo(CCopyToOptions &options, - const CRecordVector &indices, - UStringVector *messages, - bool &usePassword, UString &password, - const UStringVector *filePaths = NULL); - - HRESULT CopyTo(CCopyToOptions &options, - const CRecordVector &indices, - UStringVector *messages) - { - bool usePassword = false; - UString password; - if (_parentFolders.Size() > 0) - { - const CFolderLink &fl = _parentFolders.Back(); - usePassword = fl.UsePassword; - password = fl.Password; - } - return CopyTo(options, indices, messages, usePassword, password); - } - - HRESULT CopyFsItems(CCopyToOptions &options, - const UStringVector &filePaths, - UStringVector *messages) - { - bool usePassword = false; - UString password; - CRecordVector indices; - return CopyTo(options, indices, messages, usePassword, password, &filePaths); - } - - - HRESULT CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, - bool showErrorMessages, UStringVector *messages); - - void CopyFromNoAsk(bool moveMode, const UStringVector &filePaths); - - void CompressDropFiles( - const UStringVector &filePaths, - const UString &folderPath, - bool createNewArchive, - bool moveMode, - UInt32 sourceFlags, - UInt32 &targetFlags); - - void RefreshTitle(bool always = false) { _panelCallback->RefreshTitle(always); } - void RefreshTitleAlways() { RefreshTitle(true); } - - UString GetItemsInfoString(const CRecordVector &indices); -}; - -class CMyBuffer -{ - void *_data; -public: - CMyBuffer(): _data(NULL) {} - operator void *() { return _data; } - bool Allocate(size_t size) - { - if (_data) - return false; - _data = ::MidAlloc(size); - return _data != NULL; - } - ~CMyBuffer() { ::MidFree(_data); } -}; - -class CExitEventLauncher -{ -public: - NWindows::NSynchronization::CManualResetEvent _exitEvent; - bool _needExit; - CRecordVector< ::CThread > _threads; - unsigned _numActiveThreads; - - CExitEventLauncher() - { - _needExit = false; - if (_exitEvent.Create(false) != S_OK) - throw 9387173; - _needExit = true; - _numActiveThreads = 0; - } - - ~CExitEventLauncher() { Exit(true); } - - void Exit(bool hardExit); -}; - -extern CExitEventLauncher g_ExitEventLauncher; - -#endif +// Panel.h + +#ifndef ZIP7_INC_PANEL_H +#define ZIP7_INC_PANEL_H + +#include "../../../Common/MyWindows.h" + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../../C/Alloc.h" + +#include "../../../Common/Defs.h" +#include "../../../Common/MyCom.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Handle.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/Synchronization.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" +#include "../../../Windows/Control/ListView.h" +#include "../../../Windows/Control/ReBar.h" +#include "../../../Windows/Control/Static.h" +#include "../../../Windows/Control/StatusBar.h" +#include "../../../Windows/Control/ToolBar.h" +#include "../../../Windows/Control/Window2.h" + +#include "../../Archive/IArchive.h" + +#include "ExtractCallback.h" + +#include "AppState.h" +#include "IFolder.h" +#include "MyCom2.h" +#include "ProgressDialog2.h" +#include "SysIconUtils.h" + +#ifdef UNDER_CE +#define NON_CE_VAR(_v_) +#else +#define NON_CE_VAR(_v_) _v_ +#endif + +const int kParentFolderID = 100; + +const unsigned kParentIndex = (unsigned)(int)-1; +const UInt32 kParentIndex_UInt32 = (UInt32)(Int32)kParentIndex; + +#if !defined(_WIN32) || defined(UNDER_CE) +#define ROOT_FS_FOLDER L"\\" +#else +#define ROOT_FS_FOLDER L"C:\\" +#endif + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // < win2000 +#define Z7_USE_DYN_ComCtl32Version +extern DWORD g_ComCtl32Version; +#endif + +Z7_PURE_INTERFACES_BEGIN + +DECLARE_INTERFACE(CPanelCallback) +{ + virtual void OnTab() = 0; + virtual void SetFocusToPath(unsigned index) = 0; + virtual void OnCopy(bool move, bool copyToSame) = 0; + virtual void OnSetSameFolder() = 0; + virtual void OnSetSubFolder() = 0; + virtual void PanelWasFocused() = 0; + virtual void DragBegin() = 0; + virtual void DragEnd() = 0; + virtual void RefreshTitle(bool always) = 0; +}; +Z7_PURE_INTERFACES_END + +void PanelCopyItems(); + + +struct CPropColumn +{ + int Order; + PROPID ID; + VARTYPE Type; + bool IsVisible; + bool IsRawProp; + UInt32 Width; + UString Name; + + bool IsEqualTo(const CPropColumn &a) const + { + return Order == a.Order + && ID == a.ID + && Type == a.Type + && IsVisible == a.IsVisible + && IsRawProp == a.IsRawProp + && Width == a.Width + && Name == a.Name; + } + + int Compare(const CPropColumn &a) const { return MyCompare(Order, a.Order); } + + int Compare_NameFirst(const CPropColumn &a) const + { + if (ID == kpidName) + { + if (a.ID != kpidName) + return -1; + } + else if (a.ID == kpidName) + return 1; + return MyCompare(Order, a.Order); + } +}; + + +class CPropColumns: public CObjectVector +{ +public: + int FindItem_for_PropID(PROPID id) const + { + FOR_VECTOR (i, (*this)) + if ((*this)[i].ID == id) + return (int)i; + return -1; + } + + bool IsEqualTo(const CPropColumns &props) const + { + if (Size() != props.Size()) + return false; + FOR_VECTOR (i, (*this)) + if (!(*this)[i].IsEqualTo(props[i])) + return false; + return true; + } +}; + + +struct CTempFileInfo +{ + UInt32 FileIndex; // index of file in folder + bool NeedDelete; + UString RelPath; // Relative path of file from Folder + FString FolderPath; + FString FilePath; + NWindows::NFile::NFind::CFileInfo FileInfo; + + CTempFileInfo(): FileIndex((UInt32)(Int32)-1), NeedDelete(false) {} + void DeleteDirAndFile() const + { + if (NeedDelete) + { + NWindows::NFile::NDir::DeleteFileAlways(FilePath); + NWindows::NFile::NDir::RemoveDir(FolderPath); + } + } + bool WasChanged_from_TempFileInfo(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const + { + return newFileInfo.Size != FileInfo.Size || + CompareFileTime(&newFileInfo.MTime, &FileInfo.MTime) != 0; + } +}; + + +struct CFolderLink: public CTempFileInfo +{ + bool IsVirtual; // == true (if archive was open via IInStream): + // archive was open from another archive, + // archive size meets the size conditions derived from g_RAM_Size. + // VirtFileSystem was used + // archive was fully extracted to memory. + bool UsePassword; + NWindows::NDLL::CLibrary Library; + CMyComPtr ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0]) + UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level) + UString Password; + UString VirtualPath; // without tail slash + CByteBuffer ZoneBuf; // ZoneBuf for virtaul stream (IsVirtual) + + CFolderLink(): IsVirtual(false), UsePassword(false) {} + bool WasChanged_from_FolderLink(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const + { + // we call it, if we have two real files. + // if archive was virtual, it means that we have updated that virtual to real file. + return IsVirtual || CTempFileInfo::WasChanged_from_TempFileInfo(newFileInfo); + } +}; + + +enum MyMessages +{ + // we can use WM_USER, since we have defined new window class. + // so we don't need WM_APP. + kShiftSelectMessage = WM_USER + 1, + kReLoadMessage, + kSetFocusToListView, + kOpenItemChanged, + kRefresh_StatusBar + #ifdef UNDER_CE + , kRefresh_HeaderComboBox + #endif +}; + +UString GetFolderPath(IFolderFolder *folder); + +class CPanel; + +class CMyListView Z7_final: public NWindows::NControl::CListView2 +{ + // ~CMyListView() ZIP7_eq_delete; + // CMyListView() ZIP7_eq_delete; +public: + // CMyListView() {} + // ~CMyListView() Z7_DESTRUCTOR_override {} // change it + CPanel *_panel; + LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; +}; + +/* +class CMyComboBox: public NWindows::NControl::CComboBoxEx +{ +public: + WNDPROC _origWindowProc; + CPanel *_panel; + LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); +}; +*/ +class CMyComboBoxEdit: public NWindows::NControl::CEdit +{ +public: + WNDPROC _origWindowProc; + CPanel *_panel; + LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); +}; + +struct CSelectedState +{ + int FocusedItem; + bool SelectFocused; + bool FocusedName_Defined; + bool CalledFromTimer; + UString FocusedName; + UStringVector SelectedNames; + + CSelectedState(): + FocusedItem(-1), + SelectFocused(true), + FocusedName_Defined(false), + CalledFromTimer(false) + {} +}; + +#ifdef UNDER_CE +#define MY_NMLISTVIEW_NMITEMACTIVATE NMLISTVIEW +#else +#define MY_NMLISTVIEW_NMITEMACTIVATE NMITEMACTIVATE +#endif + +struct CCopyToOptions +{ + bool streamMode; + bool moveMode; + bool testMode; + bool includeAltStreams; + bool replaceAltStreamChars; + bool showErrorMessages; + + bool NeedRegistryZone; + NExtract::NZoneIdMode::EEnum ZoneIdMode; + CByteBuffer ZoneBuf; + + UString folder; + + UStringVector hashMethods; + + CVirtFileSystem *VirtFileSystemSpec; + // ISequentialOutStream *VirtFileSystem; + + CCopyToOptions(): + streamMode(false), + moveMode(false), + testMode(false), + includeAltStreams(true), + replaceAltStreamChars(false), + showErrorMessages(false), + NeedRegistryZone(true), + ZoneIdMode(NExtract::NZoneIdMode::kNone), + VirtFileSystemSpec(NULL) + // , VirtFileSystem(NULL) + {} +}; + + + +struct COpenResult +{ + // bool needOpenArc; + // out: + bool ArchiveIsOpened; + bool Encrypted; + UString ErrorMessage; + + COpenResult(): + // needOpenArc(false), + ArchiveIsOpened(false), Encrypted(false) {} +}; + + + + +class CPanel Z7_final: public NWindows::NControl::CWindow2 +{ + bool _thereAre_ListView_Items; + // bool _virtualMode; + bool _enableItemChangeNotify; + bool _thereAreDeletedItems; + bool _markDeletedItems; + bool _dontShowMode; + bool _needSaveInfo; + +public: + bool PanelCreated; + bool _mySelectMode; + bool _showDots; + bool _showRealFileIcons; + bool _flatMode; + bool _flatModeForArc; + bool _flatModeForDisk; + bool _selectionIsDefined; + // bool _showNtfsStrems_Mode; + // bool _showNtfsStrems_ModeForDisk; + // bool _showNtfsStrems_ModeForArc; + + bool _selectMark; + bool _lastFocusedIsList; + + bool _processTimer; + bool _processNotify; + bool _processStatusBar; + +public: + bool _ascending; + PROPID _sortID; + // int _sortIndex; + Int32 _isRawSortProp; + + CMyListView _listView; + CPanelCallback *_panelCallback; + +private: + + // CExtToIconMap _extToIconMap; + UINT _baseID; + unsigned _comboBoxID; + UINT _statusBarID; + +public: + DWORD _exStyle; + // CUIntVector _realIndices; + int _timestampLevel; + UInt32 _listViewMode; + int _xSize; +private: + int _startGroupSelect; + int _prevFocusedItem; + + CAppState *_appState; + + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) Z7_override; + virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + virtual bool OnCreate(CREATESTRUCT *createStruct) Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual void OnDestroy() Z7_override; + virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result) Z7_override; + + void AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList); + + bool OnComboBoxCommand(UINT code, LPARAM param, LRESULT &result); + + #ifndef UNDER_CE + + LRESULT OnNotifyComboBoxEnter(const UString &s); + bool OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result); + #ifndef _UNICODE + bool OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result); + #endif + + #endif + + bool OnNotifyReBar(LPNMHDR lParam, LRESULT &result); + bool OnNotifyComboBox(LPNMHDR lParam, LRESULT &result); + void OnItemChanged(NMLISTVIEW *item); + void OnNotifyActivateItems(); + bool OnNotifyList(LPNMHDR lParam, LRESULT &result); + void OnDrag(LPNMLISTVIEW nmListView, bool isRightButton = false); + bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result); + BOOL OnBeginLabelEdit(LV_DISPINFOW * lpnmh); + BOOL OnEndLabelEdit(LV_DISPINFOW * lpnmh); + void OnColumnClick(LPNMLISTVIEW info); + bool OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result); + + + void ChangeWindowSize(int xSize, int ySize); + HRESULT InitColumns(); + void DeleteColumn(unsigned index); + void AddColumn(const CPropColumn &prop); + + void SetFocusedSelectedItem(int index, bool select); + + void OnShiftSelectMessage(); + void OnArrowWithShift(); + + void OnInsert(); + // void OnUpWithShift(); + // void OnDownWithShift(); + // UString GetFileType(UInt32 index); + LRESULT SetItemText(LVITEMW &item); + // CRecordVector m_ColumnsPropIDs; + +public: + HWND _mainWindow; + + NWindows::NControl::CReBar _headerReBar; + NWindows::NControl::CToolBar _headerToolBar; + NWindows::NControl:: + #ifdef UNDER_CE + CComboBox + #else + CComboBoxEx + #endif + _headerComboBox; + UStringVector ComboBoxPaths; + // CMyComboBox _headerComboBox; + CMyComboBoxEdit _comboBoxEdit; + NWindows::NControl::CStatusBar _statusBar; + // NWindows::NControl::CStatusBar _statusBar2; + + CBoolVector _selectedStatusVector; + CSelectedState _selectedState; + + UString _currentFolderPrefix; + + CObjectVector _parentFolders; + NWindows::NDLL::CLibrary _library; + + CMyComPtr _folder; + CBoolVector _isDirVector; + CMyComPtr _folderCompare; + CMyComPtr _folderGetItemName; + CMyComPtr _folderRawProps; + CMyComPtr _folderAltStreams; + CMyComPtr _folderOperations; + + // for drag and drop highliting + int m_DropHighlighted_SelectionIndex; + // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item) + UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder) + + // CMyComPtr _folderGetSystemIconIndex; + UStringVector _fastFolders; + + UString _typeIDString; + CListViewInfo _listViewInfo; + + CPropColumns _columns; + CPropColumns _visibleColumns; + + CMyComPtr _sevenZipContextMenu; + CMyComPtr _systemContextMenu; + + void UpdateSelection(); + void SelectSpec(bool selectMode); + void SelectByType(bool selectMode); + void SelectAll(bool selectMode); + void InvertSelection(); + + void RedrawListItems() + { + _listView.RedrawAllItems(); + } + void DeleteListItems() + { + if (_thereAre_ListView_Items) + { + const bool b = _enableItemChangeNotify; + _enableItemChangeNotify = false; + _listView.DeleteAllItems(); + _thereAre_ListView_Items = false; + _enableItemChangeNotify = b; + } + } + + // void SysIconsWereChanged() { _extToIconMap.Clear(); } + + void DeleteItems(bool toRecycleBin); + void CreateFolder(); + void CreateFile(); + bool CorrectFsPath(const UString &path, UString &result); + // bool IsPathForPlugin(const UString &path); + + + HWND GetParent() const; + + UInt32 GetRealIndex(const LVITEMW &item) const + { + /* + if (_virtualMode) + return _realIndices[item.iItem]; + */ + return (UInt32)item.lParam; + } + + unsigned GetRealItemIndex(int indexInListView) const + { + /* + if (_virtualMode) + return indexInListView; + */ + LPARAM param; + if (!_listView.GetItemParam((unsigned)indexInListView, param)) + throw 1; + return (unsigned)param; + } + + void ReleaseFolder(); + void SetNewFolder(IFolderFolder *newFolder); + void GetSelectedNames(UStringVector &selectedNames); + void SaveSelectedState(CSelectedState &s); + HRESULT RefreshListCtrl(const CSelectedState &s); + HRESULT RefreshListCtrl_SaveFocused(bool onTimer = false); + + // UInt32 GetItem_Attrib(UInt32 itemIndex) const; + + bool GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const; + + bool IsItem_Deleted(unsigned itemIndex) const; + bool IsItem_Folder(unsigned itemIndex) const; + bool IsItem_AltStream(unsigned itemIndex) const; + + UString GetItemName(unsigned itemIndex) const; + UString GetItemName_for_Copy(unsigned itemIndex) const; + void GetItemName(unsigned itemIndex, UString &s) const; + UString GetItemPrefix(unsigned itemIndex) const; + UString GetItemRelPath(unsigned itemIndex) const; + UString GetItemRelPath2(unsigned itemIndex) const; + + void Add_ItemRelPath2_To_String(unsigned itemIndex, UString &s) const; + + UString GetItemFullPath(unsigned itemIndex) const; + UInt64 GetItem_UInt64Prop(unsigned itemIndex, PROPID propID) const; + UInt64 GetItemSize(unsigned itemIndex) const; + + //////////////////////// + // PanelFolderChange.cpp + + void SetToRootFolder(); + HRESULT BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes); // can be prefix + HRESULT BindToPathAndRefresh(const UString &path); + void OpenDrivesFolder(); + + void SetBookmark(unsigned index); + void OpenBookmark(unsigned index); + + void LoadFullPath(); + void LoadFullPathAndShow(); + void FoldersHistory(); + void OpenParentFolder(); + void CloseOneLevel(); + void CloseOpenFolders(); + void OpenRootFolder(); + + UString GetParentDirPrefix() const; + + HRESULT Create(HWND mainWindow, HWND parentWindow, + UINT id, + const UString ¤tFolderPrefix, + const UString &arcFormat, + CPanelCallback *panelCallback, + CAppState *appState, + bool needOpenArc, + COpenResult &openRes); + + void SetFocusToList(); + void SetFocusToLastRememberedItem(); + + + void SaveListViewInfo(); + + CPanel() : + _thereAre_ListView_Items(false), + // _virtualMode(false), + _enableItemChangeNotify(true), + _thereAreDeletedItems(false), + _markDeletedItems(true), + _dontShowMode(false), + _needSaveInfo(false), + + PanelCreated(false), + _mySelectMode(false), + _showDots(false), + _showRealFileIcons(false), + _flatMode(false), + _flatModeForArc(false), + _flatModeForDisk(false), + _selectionIsDefined(false), + // _showNtfsStrems_Mode(false), + // _showNtfsStrems_ModeForDisk(false), + // _showNtfsStrems_ModeForArc(false), + + _exStyle(0), + _timestampLevel(kTimestampPrintLevel_MIN), + _listViewMode(3), + _xSize(300), + _startGroupSelect(0), + m_DropHighlighted_SelectionIndex(-1) + {} + + ~CPanel() Z7_DESTRUCTOR_override; + + void ReleasePanel(); + + void SetExtendedStyle() + { + if (_listView) + _listView.SetExtendedListViewStyle(_exStyle); + } + + void SetSortRawStatus(); + void OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate); + bool OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result); + void ShowColumnsContextMenu(int x, int y); + + void OnTimer(); + void OnReload(bool onTimer = false); + bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos); + + HRESULT CreateShellContextMenu( + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu); + + void CreateSystemMenu(HMENU menu, + bool showExtendedVerbs, + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu); + + void CreateSevenZipMenu(HMENU menu, + bool showExtendedVerbs, + const CRecordVector &operatedIndices, + int firstDirIndex, + CMyComPtr &sevenZipContextMenu); + + void CreateFileMenu(HMENU menu, + CMyComPtr &sevenZipContextMenu, + CMyComPtr &systemContextMenu, + bool programMenu); + + void CreateFileMenu(HMENU menu); + bool InvokePluginCommand(unsigned id); + bool InvokePluginCommand(unsigned id, IContextMenu *sevenZipContextMenu, + IContextMenu *systemContextMenu); + + void InvokeSystemCommand(const char *command); + void Properties(); + void EditCut(); + void EditCopy(); + void EditPaste(); + + + // void SortItems(int index); + void SortItemsWithPropID(PROPID propID); + + void Get_ItemIndices_Selected(CRecordVector &indices) const; + void Get_ItemIndices_Operated(CRecordVector &indices) const; + void Get_ItemIndices_All(CRecordVector &indices) const; + void Get_ItemIndices_OperSmart(CRecordVector &indices) const; + // void GetOperatedListViewIndices(CRecordVector &indices) const; + void KillSelection(); + + UString GetFolderTypeID() const; + + bool IsFolderTypeEqTo(const char *s) const; + bool IsRootFolder() const; + bool IsFSFolder() const; + bool IsFSDrivesFolder() const; + bool IsAltStreamsFolder() const; + bool IsArcFolder() const; + bool IsHashFolder() const; + + /* + c:\Dir + Computer\ + \\?\ + \\.\ + */ + bool Is_IO_FS_Folder() const + { + return IsFSFolder() || IsFSDrivesFolder() || IsAltStreamsFolder(); + } + + bool Is_Slow_Icon_Folder() const + { + return IsFSFolder() || IsAltStreamsFolder(); + } + + // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); } + bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; } + bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; } + + /* + c:\Dir + Computer\ + \\?\ + */ + bool IsFsOrPureDrivesFolder() const { return IsFSFolder() || (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()); } + + /* + c:\Dir + Computer\ + \\?\ + \\SERVER\ + */ + bool IsFolder_with_FsItems() const + { + if (IsFsOrPureDrivesFolder()) + return true; + #if defined(_WIN32) && !defined(UNDER_CE) + FString prefix = us2fs(GetFsPath()); + return (prefix.Len() == NWindows::NFile::NName::GetNetworkServerPrefixSize(prefix)); + #else + return false; + #endif + } + + UString GetFsPath() const; + UString GetDriveOrNetworkPrefix() const; + + bool DoesItSupportOperations() const { return _folderOperations != NULL; } + bool IsThereReadOnlyFolder() const; + bool CheckBeforeUpdate(UINT resourceID); + + void Disable_Processing_Timer_Notify_StatusBar() + { + _processTimer = false; + _processNotify = false; + _processStatusBar = false; + } + + class CDisableTimerProcessing + { + Z7_CLASS_NO_COPY(CDisableTimerProcessing) + + bool _processTimer; + CPanel &_panel; + + public: + + CDisableTimerProcessing(CPanel &panel): _panel(panel) { Disable(); } + ~CDisableTimerProcessing() { Restore(); } + void Disable() + { + _processTimer = _panel._processTimer; + _panel._processTimer = false; + } + void Restore() + { + _panel._processTimer = _processTimer; + } + }; + + class CDisableTimerProcessing2 + { + Z7_CLASS_NO_COPY(CDisableTimerProcessing2) + + bool _processTimer; + CPanel *_panel; + + public: + + CDisableTimerProcessing2(CPanel *panel): _processTimer(true), _panel(panel) { Disable(); } + ~CDisableTimerProcessing2() { Restore(); } + void Disable() + { + if (_panel) + { + _processTimer = _panel->_processTimer; + _panel->_processTimer = false; + } + } + void Restore() + { + if (_panel) + { + _panel->_processTimer = _processTimer; + _panel = NULL; + } + } + }; + + class CDisableNotify + { + Z7_CLASS_NO_COPY(CDisableNotify) + + bool _processNotify; + bool _processStatusBar; + + CPanel &_panel; + + public: + + CDisableNotify(CPanel &panel): _panel(panel) { Disable(); } + ~CDisableNotify() { Restore(); } + void Disable() + { + _processNotify = _panel._processNotify; + _processStatusBar = _panel._processStatusBar; + _panel._processNotify = false; + _panel._processStatusBar = false; + } + void SetMemMode_Enable() + { + _processNotify = true; + _processStatusBar = true; + } + void Restore() + { + _panel._processNotify = _processNotify; + _panel._processStatusBar = _processStatusBar; + } + }; + + void InvalidateList() { _listView.InvalidateRect(NULL, true); } + + HRESULT RefreshListCtrl(); + + + // void MessageBox_Info(LPCWSTR message, LPCWSTR caption) const; + // void MessageBox_Warning(LPCWSTR message) const; + void MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const; + void MessageBox_Error(LPCWSTR message) const; + void MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const; + void MessageBox_Error_HRESULT(HRESULT errorCode) const; + void MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const; + void MessageBox_LastError(LPCWSTR caption) const; + void MessageBox_LastError() const; + void MessageBox_Error_LangID(UINT resourceID) const; + void MessageBox_Error_UnsupportOperation() const; + // void MessageBoxErrorForUpdate(HRESULT errorCode, UINT resourceID); + + + void OpenAltStreams(); + + void OpenFocusedItemAsInternal(const wchar_t *type = NULL); + void OpenSelectedItems(bool internal); + + void OpenFolderExternal(unsigned index); + + void OpenFolder(unsigned index); + HRESULT OpenParentArchiveFolder(); + + HRESULT OpenAsArc(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat, + COpenResult &openRes); + + HRESULT OpenAsArc_Msg(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat + // , bool showErrorMessage + ); + + HRESULT OpenAsArc_Name(const UString &relPath, const UString &arcFormat + // , bool showErrorMessage + ); + HRESULT OpenAsArc_Index(unsigned index, const wchar_t *type /* = NULL */ + // , bool showErrorMessage + ); + + void OpenItemInArchive(unsigned index, bool tryInternal, bool tryExternal, + bool editMode, bool useEditor, const wchar_t *type = NULL); + + HRESULT OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, bool usePassword, const UString &password); + LRESULT OnOpenItemChanged(LPARAM lParam); + + bool IsVirus_Message(const UString &name); + void OpenItem(unsigned index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL); + void EditItem(bool useEditor); + void EditItem(unsigned index, bool useEditor); + + void RenameFile(); + void ChangeComment(); + + void SetListViewMode(UInt32 index); + UInt32 GetListViewMode() const { return _listViewMode; } + PROPID GetSortID() const { return _sortID; } + + void ChangeFlatMode(); + void Change_ShowNtfsStrems_Mode(); + bool GetFlatMode() const { return _flatMode; } + // bool Get_ShowNtfsStrems_Mode() const { return _showNtfsStrems_Mode; } + + bool AutoRefresh_Mode; + void Set_AutoRefresh_Mode(bool mode) + { + AutoRefresh_Mode = mode; + } + + void Post_Refresh_StatusBar(); + void Refresh_StatusBar(); + + void AddToArchive(); + + int FindDir_InOperatedList(const CRecordVector &indices) const; + void GetFilePaths(const CRecordVector &indices, UStringVector &paths) const; + void ExtractArchives(); + void TestArchives(); + + void Get_ZoneId_Stream_from_ParentFolders(CByteBuffer &buf); + + HRESULT CopyTo(CCopyToOptions &options, + const CRecordVector &indices, + UStringVector *messages, + bool &usePassword, UString &password, + const UStringVector *filePaths = NULL); + + HRESULT CopyTo(CCopyToOptions &options, + const CRecordVector &indices, + UStringVector *messages) + { + bool usePassword = false; + UString password; + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &fl = _parentFolders.Back(); + usePassword = fl.UsePassword; + password = fl.Password; + } + return CopyTo(options, indices, messages, usePassword, password); + } + + HRESULT CopyFsItems(CCopyToOptions &options, + const UStringVector &filePaths, + UStringVector *messages) + { + bool usePassword = false; + UString password; + CRecordVector indices; + return CopyTo(options, indices, messages, usePassword, password, &filePaths); + } + + + HRESULT CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, + bool showErrorMessages, UStringVector *messages); + + void CopyFromNoAsk(bool moveMode, const UStringVector &filePaths); + + void CompressDropFiles( + const UStringVector &filePaths, + const UString &folderPath, + bool createNewArchive, + bool moveMode, + UInt32 sourceFlags, + UInt32 &targetFlags); + + void RefreshTitle(bool always = false) { _panelCallback->RefreshTitle(always); } + void RefreshTitleAlways() { RefreshTitle(true); } + + UString GetItemsInfoString(const CRecordVector &indices); +}; + + +class CMyBuffer +{ + void *_data; +public: + CMyBuffer(): _data(NULL) {} + operator void *() { return _data; } + bool Allocate(size_t size) + { + if (_data) + return false; + _data = ::MidAlloc(size); + return _data != NULL; + } + ~CMyBuffer() { ::MidFree(_data); } +}; + +struct CExitEventLauncher +{ + NWindows::NSynchronization::CManualResetEvent _exitEvent; + bool _needExit; + unsigned _numActiveThreads; + CRecordVector< ::CThread > _threads; + + CExitEventLauncher() + { + _needExit = false; + if (_exitEvent.Create(false) != S_OK) + throw 9387173; + _needExit = true; + _numActiveThreads = 0; + } + + ~CExitEventLauncher() { Exit(true); } + + void Exit(bool hardExit); +}; + +extern CExitEventLauncher g_ExitEventLauncher; + +#endif diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp index 4e17f69b4..d4f1db7b8 100644 --- a/CPP/7zip/UI/FileManager/PanelCopy.cpp +++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp @@ -1,437 +1,477 @@ -/// PanelCopy.cpp - -#include "StdAfx.h" - -#include "../Common/ZipRegistry.h" - -#include "../GUI/HashGUI.h" - -#include "FSFolder.h" -#include "ExtractCallback.h" -#include "LangUtils.h" -#include "Panel.h" -#include "UpdateCallback100.h" - -#include "resource.h" - - -class CPanelCopyThread: public CProgressThreadVirt -{ - bool ResultsWereShown; - bool NeedShowRes; - - HRESULT ProcessVirt() Z7_override; - virtual void ProcessWasFinished_GuiVirt() Z7_override; -public: - const CCopyToOptions *options; - const UStringVector *CopyFrom_Paths; - CMyComPtr FolderOperations; - CRecordVector Indices; - CExtractCallbackImp *ExtractCallbackSpec; - CMyComPtr ExtractCallback; - - CHashBundle Hash; - // UString FirstFilePath; - - // HRESULT Result2; - - void ShowFinalResults(HWND hwnd); - - CPanelCopyThread(): - ResultsWereShown(false), - NeedShowRes(false), - CopyFrom_Paths(NULL) - // , Result2(E_FAIL) - {} -}; - -void CPanelCopyThread::ShowFinalResults(HWND hwnd) -{ - if (NeedShowRes) - if (!ResultsWereShown) - { - ResultsWereShown = true; - ShowHashResults(Hash, hwnd); - } -} - -void CPanelCopyThread::ProcessWasFinished_GuiVirt() -{ - ShowFinalResults(*this); -} - -HRESULT CPanelCopyThread::ProcessVirt() -{ - /* - CMyComPtr iReplace; - FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace); - if (iReplace) - { - RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0)); - } - */ - - HRESULT result2; - - if (FolderOperations) - { - CMyComPtr setZoneMode; - FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode); - if (setZoneMode) - { - RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode)) - } - } - - if (CopyFrom_Paths) - { - result2 = NFsFolder::CopyFileSystemItems( - *CopyFrom_Paths, - us2fs(options->folder), - options->moveMode, - (IFolderOperationsExtractCallback *)ExtractCallbackSpec); - } - else if (options->testMode) - { - CMyComPtr archiveFolder; - FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder); - if (!archiveFolder) - return E_NOTIMPL; - CMyComPtr extractCallback2; - RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2)) - NExtract::NPathMode::EEnum pathMode = - NExtract::NPathMode::kCurPaths; - // NExtract::NPathMode::kFullPathnames; - result2 = archiveFolder->Extract(Indices.ConstData(), Indices.Size(), - BoolToInt(options->includeAltStreams), - BoolToInt(options->replaceAltStreamChars), - pathMode, NExtract::NOverwriteMode::kAsk, - options->folder, BoolToInt(true), extractCallback2); - } - else - result2 = FolderOperations->CopyTo( - BoolToInt(options->moveMode), - Indices.ConstData(), Indices.Size(), - BoolToInt(options->includeAltStreams), - BoolToInt(options->replaceAltStreamChars), - options->folder, ExtractCallback); - - if (result2 == S_OK && !ExtractCallbackSpec->ThereAreMessageErrors) - { - if (!options->hashMethods.IsEmpty()) - NeedShowRes = true; - else if (options->testMode) - { - CProgressMessageBoxPair &pair = GetMessagePair(false); // GetMessagePair(ExtractCallbackSpec->Hash.NumErrors != 0); - AddHashBundleRes(pair.Message, Hash); - } - } - - return result2; -} - - -/* -#ifdef Z7_EXTERNAL_CODECS - -static void ThrowException_if_Error(HRESULT res) -{ - if (res != S_OK) - throw CSystemException(res); -} - -#endif -*/ - -HRESULT CPanel::CopyTo(CCopyToOptions &options, - const CRecordVector &indices, - UStringVector *messages, - bool &usePassword, UString &password, - const UStringVector *filePaths) -{ - if (options.NeedRegistryZone && !options.testMode) - { - CContextMenuInfo ci; - ci.Load(); - if (ci.WriteZone != (UInt32)(Int32)-1) - options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone; - } - - if (IsHashFolder()) - { - if (!options.testMode) - return E_NOTIMPL; - } - - if (!filePaths) - if (!_folderOperations) - { - const UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED); - if (options.showErrorMessages) - MessageBox_Error(errorMessage); - else if (messages) - messages->Add(errorMessage); - return E_FAIL; - } - - HRESULT res = S_OK; - - { - /* - #ifdef Z7_EXTERNAL_CODECS - CExternalCodecs g_ExternalCodecs; - #endif - */ - /* extracter.Hash uses g_ExternalCodecs - extracter must be declared after g_ExternalCodecs for correct destructor order !!! */ - - CPanelCopyThread extracter; - - extracter.ExtractCallbackSpec = new CExtractCallbackImp; - extracter.ExtractCallback = extracter.ExtractCallbackSpec; - extracter.ExtractCallbackSpec->Src_Is_IO_FS_Folder = - IsFSFolder() || IsAltStreamsFolder(); - // options.src_Is_IO_FS_Folder; - extracter.options = &options; - extracter.ExtractCallbackSpec->ProgressDialog = &extracter; - extracter.CompressingMode = false; - - extracter.ExtractCallbackSpec->StreamMode = options.streamMode; - - - if (indices.Size() == 1) - { - extracter.Hash.FirstFileName = GetItemRelPath(indices[0]); - extracter.Hash.MainName = extracter.Hash.FirstFileName; - } - - if (options.VirtFileSystem) - { - extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystem; - extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec; - } - extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams; - - if (!options.hashMethods.IsEmpty()) - { - /* this code is used when we call CRC calculation for files in side archive - But new code uses global codecs so we don't need to call LoadGlobalCodecs again */ - - /* - #ifdef Z7_EXTERNAL_CODECS - ThrowException_if_Error(LoadGlobalCodecs()); - #endif - */ - - extracter.Hash.SetMethods(EXTERNAL_CODECS_VARS_G options.hashMethods); - extracter.ExtractCallbackSpec->SetHashMethods(&extracter.Hash); - } - else if (options.testMode) - { - extracter.ExtractCallbackSpec->SetHashCalc(&extracter.Hash); - } - - // extracter.Hash.Init(); - - UString title; - { - UInt32 titleID = IDS_COPYING; - if (options.moveMode) - titleID = IDS_MOVING; - else if (!options.hashMethods.IsEmpty() && options.streamMode) - { - titleID = IDS_CHECKSUM_CALCULATING; - if (options.hashMethods.Size() == 1) - { - const UString &s = options.hashMethods[0]; - if (s != L"*") - title = s; - } - } - else if (options.testMode) - titleID = IDS_PROGRESS_TESTING; - - if (title.IsEmpty()) - title = LangString(titleID); - } - - const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); - - extracter.MainWindow = GetParent(); - extracter.MainTitle = progressWindowTitle; - extracter.MainAddTitle = title + L' '; - - extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAsk; - extracter.ExtractCallbackSpec->Init(); - - extracter.CopyFrom_Paths = filePaths; - if (!filePaths) - { - extracter.Indices = indices; - extracter.FolderOperations = _folderOperations; - } - - extracter.ExtractCallbackSpec->PasswordIsDefined = usePassword; - extracter.ExtractCallbackSpec->Password = password; - - RINOK(extracter.Create(title, GetParent())) - - - if (messages) - *messages = extracter.Sync.Messages; - - // res = extracter.Result2; - res = extracter.Result; - - if (res == S_OK && extracter.ExtractCallbackSpec->IsOK()) - { - usePassword = extracter.ExtractCallbackSpec->PasswordIsDefined; - password = extracter.ExtractCallbackSpec->Password; - } - - extracter.ShowFinalResults(_window); - - } - - RefreshTitleAlways(); - return res; -} - - -struct CThreadUpdate -{ - CMyComPtr FolderOperations; - UString FolderPrefix; - UStringVector FileNames; - CRecordVector FileNamePointers; - CProgressDialog ProgressDialog; - CMyComPtr UpdateCallback; - CUpdateCallback100Imp *UpdateCallbackSpec; - HRESULT Result; - bool MoveMode; - - void Process() - { - try - { - CProgressCloser closer(ProgressDialog); - Result = FolderOperations->CopyFrom( - MoveMode, - FolderPrefix, - FileNamePointers.ConstData(), - FileNamePointers.Size(), - UpdateCallback); - } - catch(...) { Result = E_FAIL; } - } - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - ((CThreadUpdate *)param)->Process(); - return 0; - } -}; - - -HRESULT CPanel::CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, - bool showErrorMessages, UStringVector *messages) -{ - if (IsHashFolder()) - { - if (moveMode) - return E_NOTIMPL; - } - // CDisableNotify disableNotify(*this); - - HRESULT res; - if (!_folderOperations) - res = E_NOINTERFACE; - else - { - CThreadUpdate updater; - updater.MoveMode = moveMode; - updater.UpdateCallbackSpec = new CUpdateCallback100Imp; - updater.UpdateCallback = updater.UpdateCallbackSpec; - updater.UpdateCallbackSpec->Init(); - - updater.UpdateCallbackSpec->ProgressDialog = &updater.ProgressDialog; - - const UString title = LangString(IDS_COPYING); - const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); - - updater.ProgressDialog.MainWindow = GetParent(); - updater.ProgressDialog.MainTitle = progressWindowTitle; - updater.ProgressDialog.MainAddTitle = title + L' '; - - { - if (!_parentFolders.IsEmpty()) - { - const CFolderLink &fl = _parentFolders.Back(); - updater.UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword; - updater.UpdateCallbackSpec->Password = fl.Password; - } - } - - updater.FolderOperations = _folderOperations; - updater.FolderPrefix = folderPrefix; - updater.FileNames.ClearAndReserve(filePaths.Size()); - unsigned i; - for (i = 0; i < filePaths.Size(); i++) - updater.FileNames.AddInReserved(filePaths[i]); - updater.FileNamePointers.ClearAndReserve(updater.FileNames.Size()); - for (i = 0; i < updater.FileNames.Size(); i++) - updater.FileNamePointers.AddInReserved(updater.FileNames[i]); - - { - NWindows::CThread thread; - const WRes wres = thread.Create(CThreadUpdate::MyThreadFunction, &updater); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - updater.ProgressDialog.Create(title, thread, GetParent()); - } - - if (messages) - *messages = updater.ProgressDialog.Sync.Messages; - - res = updater.Result; - } - - if (res == E_NOINTERFACE) - { - const UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED); - if (showErrorMessages) - MessageBox_Error(errorMessage); - else if (messages) - messages->Add(errorMessage); - return E_ABORT; - } - - RefreshTitleAlways(); - return res; -} - -void CPanel::CopyFromNoAsk(bool moveMode, const UStringVector &filePaths) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - - CSelectedState srcSelState; - SaveSelectedState(srcSelState); - - CDisableNotify disableNotify(*this); - - const HRESULT result = CopyFrom(moveMode, L"", filePaths, true, NULL); - - if (result != S_OK) - { - disableNotify.Restore(); - // For Password: - SetFocusToList(); - if (result != E_ABORT) - MessageBox_Error_HRESULT(result); - return; - } - - RefreshListCtrl(srcSelState); - - disableNotify.Restore(); - SetFocusToList(); -} +/// PanelCopy.cpp + +#include "StdAfx.h" + +#include "../Common/ZipRegistry.h" + +#include "../GUI/HashGUI.h" + +#include "FSFolder.h" +#include "ExtractCallback.h" +#include "LangUtils.h" +#include "Panel.h" +#include "UpdateCallback100.h" + +#include "resource.h" + + +class CPanelCopyThread: public CProgressThreadVirt +{ + bool ResultsWereShown; + bool NeedShowRes; + + HRESULT ProcessVirt() Z7_override; + virtual void ProcessWasFinished_GuiVirt() Z7_override; +public: + const CCopyToOptions *options; + const UStringVector *CopyFrom_Paths; + CMyComPtr FolderOperations; + CRecordVector Indices; + CExtractCallbackImp *ExtractCallbackSpec; + CMyComPtr ExtractCallback; + + CHashBundle Hash; + // UString FirstFilePath; + + // HRESULT Result2; + + void ShowFinalResults(HWND hwnd); + + CPanelCopyThread(): + ResultsWereShown(false), + NeedShowRes(false), + CopyFrom_Paths(NULL) + // , Result2(E_FAIL) + {} +}; + +void CPanelCopyThread::ShowFinalResults(HWND hwnd) +{ + if (NeedShowRes) + if (!ResultsWereShown) + { + ResultsWereShown = true; + ShowHashResults(Hash, hwnd); + } +} + +void CPanelCopyThread::ProcessWasFinished_GuiVirt() +{ + ShowFinalResults(*this); +} + +HRESULT CPanelCopyThread::ProcessVirt() +{ + /* + CMyComPtr iReplace; + FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace); + if (iReplace) + { + RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0)); + } + */ + + HRESULT result2; + + if (FolderOperations) + { + { + CMyComPtr setZoneMode; + FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode); + if (setZoneMode) + { + RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode)) + } + } + { + CMyComPtr setZoneFile; + FolderOperations.QueryInterface(IID_IFolderSetZoneIdFile, &setZoneFile); + if (setZoneFile) + { + RINOK(setZoneFile->SetZoneIdFile(options->ZoneBuf, (UInt32)options->ZoneBuf.Size())) + } + } + } + + if (CopyFrom_Paths) + { + result2 = NFsFolder::CopyFileSystemItems( + *CopyFrom_Paths, + us2fs(options->folder), + options->moveMode, + (IFolderOperationsExtractCallback *)ExtractCallbackSpec); + } + else if (options->testMode) + { + CMyComPtr archiveFolder; + FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder); + if (!archiveFolder) + return E_NOTIMPL; + CMyComPtr extractCallback2; + RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2)) + NExtract::NPathMode::EEnum pathMode = + NExtract::NPathMode::kCurPaths; + // NExtract::NPathMode::kFullPathnames; + result2 = archiveFolder->Extract(Indices.ConstData(), Indices.Size(), + BoolToInt(options->includeAltStreams), + BoolToInt(options->replaceAltStreamChars), + pathMode, NExtract::NOverwriteMode::kAsk, + options->folder, BoolToInt(true), extractCallback2); + } + else + result2 = FolderOperations->CopyTo( + BoolToInt(options->moveMode), + Indices.ConstData(), Indices.Size(), + BoolToInt(options->includeAltStreams), + BoolToInt(options->replaceAltStreamChars), + options->folder, ExtractCallback); + + if (result2 == S_OK && !ExtractCallbackSpec->ThereAreMessageErrors) + { + if (!options->hashMethods.IsEmpty()) + NeedShowRes = true; + else if (options->testMode) + { + CProgressMessageBoxPair &pair = GetMessagePair(false); // GetMessagePair(ExtractCallbackSpec->Hash.NumErrors != 0); + AddHashBundleRes(pair.Message, Hash); + } + } + + return result2; +} + + +/* +#ifdef Z7_EXTERNAL_CODECS + +static void ThrowException_if_Error(HRESULT res) +{ + if (res != S_OK) + throw CSystemException(res); +} + +#endif +*/ + +void CPanel::Get_ZoneId_Stream_from_ParentFolders(CByteBuffer &buf) +{ + // we suppose that ZoneId of top parent has priority over ZoneId from childs. + FOR_VECTOR (i, _parentFolders) + { + // _parentFolders[0] = is top level archive + // _parentFolders[1 ... ].isVirtual == true is possible + // if extracted size meets size conditions derived from g_RAM_Size. + const CFolderLink &fl = _parentFolders[i]; + if (fl.IsVirtual) + { + if (fl.ZoneBuf.Size() != 0) + { + buf = fl.ZoneBuf; + return; + } + } + else if (!fl.FilePath.IsEmpty()) + { + ReadZoneFile_Of_BaseFile(fl.FilePath, buf); + if (buf.Size() != 0) + return; + } + } +} + +HRESULT CPanel::CopyTo(CCopyToOptions &options, + const CRecordVector &indices, + UStringVector *messages, + bool &usePassword, UString &password, + const UStringVector *filePaths) +{ + if (options.NeedRegistryZone && !options.testMode) + { + CContextMenuInfo ci; + ci.Load(); + if (ci.WriteZone != (UInt32)(Int32)-1) + options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone; + } + + if (options.ZoneBuf.Size() == 0 + && options.ZoneIdMode != NExtract::NZoneIdMode::kNone) + Get_ZoneId_Stream_from_ParentFolders(options.ZoneBuf); + + if (IsHashFolder()) + { + if (!options.testMode) + return E_NOTIMPL; + } + + if (!filePaths) + if (!_folderOperations) + { + const UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED); + if (options.showErrorMessages) + MessageBox_Error(errorMessage); + else if (messages) + messages->Add(errorMessage); + return E_FAIL; + } + + HRESULT res = S_OK; + + { + /* + #ifdef Z7_EXTERNAL_CODECS + CExternalCodecs g_ExternalCodecs; + #endif + */ + /* extracter.Hash uses g_ExternalCodecs + extracter must be declared after g_ExternalCodecs for correct destructor order !!! */ + + CPanelCopyThread extracter; + + extracter.ExtractCallbackSpec = new CExtractCallbackImp; + extracter.ExtractCallback = extracter.ExtractCallbackSpec; + extracter.ExtractCallbackSpec->Src_Is_IO_FS_Folder = + IsFSFolder() || IsAltStreamsFolder(); + // options.src_Is_IO_FS_Folder; + extracter.options = &options; + extracter.ExtractCallbackSpec->ProgressDialog = &extracter; + extracter.CompressingMode = false; + + extracter.ExtractCallbackSpec->StreamMode = options.streamMode; + + + if (indices.Size() == 1) + { + extracter.Hash.FirstFileName = GetItemRelPath(indices[0]); + extracter.Hash.MainName = extracter.Hash.FirstFileName; + } + + if (options.VirtFileSystemSpec) + { + extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystemSpec; + extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec; + } + extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams; + + if (!options.hashMethods.IsEmpty()) + { + /* this code is used when we call CRC calculation for files in side archive + But new code uses global codecs so we don't need to call LoadGlobalCodecs again */ + + /* + #ifdef Z7_EXTERNAL_CODECS + ThrowException_if_Error(LoadGlobalCodecs()); + #endif + */ + + extracter.Hash.SetMethods(EXTERNAL_CODECS_VARS_G options.hashMethods); + extracter.ExtractCallbackSpec->SetHashMethods(&extracter.Hash); + } + else if (options.testMode) + { + extracter.ExtractCallbackSpec->SetHashCalc(&extracter.Hash); + } + + // extracter.Hash.Init(); + + UString title; + { + UInt32 titleID = IDS_COPYING; + if (options.moveMode) + titleID = IDS_MOVING; + else if (!options.hashMethods.IsEmpty() && options.streamMode) + { + titleID = IDS_CHECKSUM_CALCULATING; + if (options.hashMethods.Size() == 1) + { + const UString &s = options.hashMethods[0]; + if (s != L"*") + title = s; + } + } + else if (options.testMode) + titleID = IDS_PROGRESS_TESTING; + + if (title.IsEmpty()) + title = LangString(titleID); + } + + const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); + + extracter.MainWindow = GetParent(); + extracter.MainTitle = progressWindowTitle; + extracter.MainAddTitle = title + L' '; + + extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAsk; + extracter.ExtractCallbackSpec->Init(); + + extracter.CopyFrom_Paths = filePaths; + if (!filePaths) + { + extracter.Indices = indices; + extracter.FolderOperations = _folderOperations; + } + + extracter.ExtractCallbackSpec->PasswordIsDefined = usePassword; + extracter.ExtractCallbackSpec->Password = password; + + RINOK(extracter.Create(title, GetParent())) + + + if (messages) + *messages = extracter.Sync.Messages; + + // res = extracter.Result2; + res = extracter.Result; + + if (res == S_OK && extracter.ExtractCallbackSpec->IsOK()) + { + usePassword = extracter.ExtractCallbackSpec->PasswordIsDefined; + password = extracter.ExtractCallbackSpec->Password; + } + + extracter.ShowFinalResults(_window); + + } + + RefreshTitleAlways(); + return res; +} + + +struct CThreadUpdate +{ + CMyComPtr FolderOperations; + UString FolderPrefix; + UStringVector FileNames; + CRecordVector FileNamePointers; + CProgressDialog ProgressDialog; + CMyComPtr UpdateCallback; + CUpdateCallback100Imp *UpdateCallbackSpec; + HRESULT Result; + bool MoveMode; + + void Process() + { + try + { + CProgressCloser closer(ProgressDialog); + Result = FolderOperations->CopyFrom( + MoveMode, + FolderPrefix, + FileNamePointers.ConstData(), + FileNamePointers.Size(), + UpdateCallback); + } + catch(...) { Result = E_FAIL; } + } + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + ((CThreadUpdate *)param)->Process(); + return 0; + } +}; + + +HRESULT CPanel::CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths, + bool showErrorMessages, UStringVector *messages) +{ + if (IsHashFolder()) + { + if (moveMode) + return E_NOTIMPL; + } + // CDisableNotify disableNotify(*this); + + HRESULT res; + if (!_folderOperations) + res = E_NOINTERFACE; + else + { + CThreadUpdate updater; + updater.MoveMode = moveMode; + updater.UpdateCallbackSpec = new CUpdateCallback100Imp; + updater.UpdateCallback = updater.UpdateCallbackSpec; + updater.UpdateCallbackSpec->Init(); + + updater.UpdateCallbackSpec->ProgressDialog = &updater.ProgressDialog; + + const UString title = LangString(IDS_COPYING); + const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); + + updater.ProgressDialog.MainWindow = GetParent(); + updater.ProgressDialog.MainTitle = progressWindowTitle; + updater.ProgressDialog.MainAddTitle = title + L' '; + + { + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &fl = _parentFolders.Back(); + updater.UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword; + updater.UpdateCallbackSpec->Password = fl.Password; + } + } + + updater.FolderOperations = _folderOperations; + updater.FolderPrefix = folderPrefix; + updater.FileNames.ClearAndReserve(filePaths.Size()); + unsigned i; + for (i = 0; i < filePaths.Size(); i++) + updater.FileNames.AddInReserved(filePaths[i]); + updater.FileNamePointers.ClearAndReserve(updater.FileNames.Size()); + for (i = 0; i < updater.FileNames.Size(); i++) + updater.FileNamePointers.AddInReserved(updater.FileNames[i]); + + { + NWindows::CThread thread; + const WRes wres = thread.Create(CThreadUpdate::MyThreadFunction, &updater); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + updater.ProgressDialog.Create(title, thread, GetParent()); + } + + if (messages) + *messages = updater.ProgressDialog.Sync.Messages; + + res = updater.Result; + } + + if (res == E_NOINTERFACE) + { + const UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED); + if (showErrorMessages) + MessageBox_Error(errorMessage); + else if (messages) + messages->Add(errorMessage); + return E_ABORT; + } + + RefreshTitleAlways(); + return res; +} + +void CPanel::CopyFromNoAsk(bool moveMode, const UStringVector &filePaths) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + + CSelectedState srcSelState; + SaveSelectedState(srcSelState); + + CDisableNotify disableNotify(*this); + + const HRESULT result = CopyFrom(moveMode, L"", filePaths, true, NULL); + + if (result != S_OK) + { + disableNotify.Restore(); + // For Password: + SetFocusToList(); + if (result != E_ABORT) + MessageBox_Error_HRESULT(result); + return; + } + + RefreshListCtrl(srcSelState); + + disableNotify.Restore(); + SetFocusToList(); +} diff --git a/CPP/7zip/UI/FileManager/PanelCrc.cpp b/CPP/7zip/UI/FileManager/PanelCrc.cpp index 87559daa6..df0b73384 100644 --- a/CPP/7zip/UI/FileManager/PanelCrc.cpp +++ b/CPP/7zip/UI/FileManager/PanelCrc.cpp @@ -1,422 +1,422 @@ -// PanelCrc.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyException.h" - -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileIO.h" -#include "../../../Windows/FileName.h" - -#include "../Common/LoadCodecs.h" - -#include "../GUI/HashGUI.h" - -#include "App.h" -#include "LangUtils.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; - -#ifdef Z7_EXTERNAL_CODECS -extern CExternalCodecs g_ExternalCodecs; -HRESULT LoadGlobalCodecs(); -#endif - -static const UInt32 kBufSize = (1 << 15); - -struct CDirEnumerator -{ - bool EnterToDirs; - FString BasePrefix; - FString BasePrefix_for_Open; - FStringVector FilePaths; - - CObjectVector Enumerators; - FStringVector Prefixes; - unsigned Index; - - CDirEnumerator(): EnterToDirs(false), Index(0) {} - - void Init(); - DWORD GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath); -}; - -void CDirEnumerator::Init() -{ - Enumerators.Clear(); - Prefixes.Clear(); - Index = 0; -} - -static DWORD GetNormalizedError() -{ - const DWORD error = GetLastError(); - return (error == 0) ? (DWORD)E_FAIL : error; -} - -DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath) -{ - filled = false; - resPath.Empty(); - - for (;;) - { - #if defined(_WIN32) && !defined(UNDER_CE) - bool isRootPrefix = (BasePrefix.IsEmpty() || (NName::IsSuperPath(BasePrefix) && BasePrefix[NName::kSuperPathPrefixSize] == 0)); - #endif - - if (Enumerators.IsEmpty()) - { - if (Index >= FilePaths.Size()) - return S_OK; - const FString &path = FilePaths[Index++]; - const int pos = path.ReverseFind_PathSepar(); - if (pos >= 0) - resPath.SetFrom(path, (unsigned)pos + 1); - - #if defined(_WIN32) && !defined(UNDER_CE) - if (isRootPrefix && path.Len() == 2 && NName::IsDrivePath2(path)) - { - // we use "c:" item as directory item - fi.ClearBase(); - fi.Name = path; - fi.SetAsDir(); - fi.Size = 0; - } - else - #endif - if (!fi.Find(BasePrefix + path)) - { - const DWORD error = GetNormalizedError(); - resPath = path; - return error; - } - - break; - } - - bool found; - - if (Enumerators.Back().Next(fi, found)) - { - if (found) - { - resPath = Prefixes.Back(); - break; - } - } - else - { - const DWORD error = GetNormalizedError(); - resPath = Prefixes.Back(); - Enumerators.DeleteBack(); - Prefixes.DeleteBack(); - return error; - } - - Enumerators.DeleteBack(); - Prefixes.DeleteBack(); - } - - resPath += fi.Name; - - if (EnterToDirs && fi.IsDir()) - { - FString s = resPath; - s.Add_PathSepar(); - Prefixes.Add(s); - Enumerators.AddNew().SetDirPrefix(BasePrefix + s); - } - - filled = true; - return S_OK; -} - - - -class CThreadCrc: public CProgressThreadVirt -{ - bool ResultsWereShown; - bool WasFinished; - - HRESULT ProcessVirt() Z7_override; - virtual void ProcessWasFinished_GuiVirt() Z7_override; -public: - CDirEnumerator Enumerator; - CHashBundle Hash; - // FString FirstFilePath; - - void SetStatus(const UString &s); - void AddErrorMessage(DWORD systemError, const FChar *name); - void ShowFinalResults(HWND hwnd); - - CThreadCrc(): - ResultsWereShown(false), - WasFinished(false) - {} -}; - -void CThreadCrc::ShowFinalResults(HWND hwnd) -{ - if (WasFinished) - if (!ResultsWereShown) - { - ResultsWereShown = true; - ShowHashResults(Hash, hwnd); - } -} - -void CThreadCrc::ProcessWasFinished_GuiVirt() -{ - ShowFinalResults(*this); -} - -void CThreadCrc::AddErrorMessage(DWORD systemError, const FChar *name) -{ - Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(Enumerator.BasePrefix + name)); - Hash.NumErrors++; -} - -void CThreadCrc::SetStatus(const UString &s2) -{ - UString s = s2; - if (!Enumerator.BasePrefix.IsEmpty()) - { - s.Add_Space_if_NotEmpty(); - s += fs2us(Enumerator.BasePrefix); - } - Sync.Set_Status(s); -} - -HRESULT CThreadCrc::ProcessVirt() -{ - // Hash.Init(); - - CMyBuffer buf; - if (!buf.Allocate(kBufSize)) - return E_OUTOFMEMORY; - - CProgressSync &sync = Sync; - - SetStatus(LangString(IDS_SCANNING)); - - Enumerator.Init(); - - FString path; - NFind::CFileInfo fi; - UInt64 numFiles = 0; - UInt64 numItems = 0, numItems_Prev = 0; - UInt64 totalSize = 0; - - for (;;) - { - bool filled; - const DWORD error = Enumerator.GetNextFile(fi, filled, path); - if (error != 0) - { - AddErrorMessage(error, path); - continue; - } - if (!filled) - break; - if (!fi.IsDir()) - { - totalSize += fi.Size; - numFiles++; - } - numItems++; - bool needPrint = false; - // if (fi.IsDir()) - { - if (numItems - numItems_Prev >= 100) - { - needPrint = true; - numItems_Prev = numItems; - } - } - /* - else if (numFiles - numFiles_Prev >= 200) - { - needPrint = true; - numFiles_Prev = numFiles; - } - */ - if (needPrint) - { - RINOK(sync.ScanProgress(numFiles, totalSize, path, fi.IsDir())) - } - } - RINOK(sync.ScanProgress(numFiles, totalSize, FString(), false)) - // sync.SetNumFilesTotal(numFiles); - // sync.SetProgress(totalSize, 0); - // SetStatus(LangString(IDS_CHECKSUM_CALCULATING)); - // sync.SetCurFilePath(L""); - SetStatus(L""); - - Enumerator.Init(); - - FString tempPath; - bool isFirstFile = true; - UInt64 errorsFilesSize = 0; - - for (;;) - { - bool filled; - DWORD error = Enumerator.GetNextFile(fi, filled, path); - if (error != 0) - { - AddErrorMessage(error, path); - continue; - } - if (!filled) - break; - - error = 0; - Hash.InitForNewFile(); - if (!fi.IsDir()) - { - NIO::CInFile inFile; - tempPath = Enumerator.BasePrefix_for_Open; - tempPath += path; - if (!inFile.Open(tempPath)) - { - error = GetNormalizedError(); - AddErrorMessage(error, path); - continue; - } - if (isFirstFile) - { - Hash.FirstFileName = fs2us(path); - isFirstFile = false; - } - sync.Set_FilePath(fs2us(path)); - sync.Set_NumFilesCur(Hash.NumFiles); - UInt64 progress_Prev = 0; - for (;;) - { - UInt32 size; - if (!inFile.Read(buf, kBufSize, size)) - { - error = GetNormalizedError(); - AddErrorMessage(error, path); - UInt64 errorSize = 0; - if (inFile.GetLength(errorSize)) - errorsFilesSize += errorSize; - break; - } - if (size == 0) - break; - Hash.Update(buf, size); - if (Hash.CurSize - progress_Prev >= ((UInt32)1 << 21)) - { - RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize + Hash.CurSize)) - progress_Prev = Hash.CurSize; - } - } - } - if (error == 0) - Hash.Final(fi.IsDir(), false, fs2us(path)); - RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize)) - } - RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize)) - sync.Set_NumFilesCur(Hash.NumFiles); - if (Hash.NumFiles != 1) - sync.Set_FilePath(L""); - SetStatus(L""); - - CProgressMessageBoxPair &pair = GetMessagePair(Hash.NumErrors != 0); - WasFinished = true; - LangString(IDS_CHECKSUM_INFORMATION, pair.Title); - return S_OK; -} - - - -HRESULT CApp::CalculateCrc2(const UString &methodName) -{ - unsigned srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - - CRecordVector indices; - srcPanel.Get_ItemIndices_OperSmart(indices); - if (indices.IsEmpty()) - return S_OK; - - if (!srcPanel.Is_IO_FS_Folder()) - { - CCopyToOptions options; - options.streamMode = true; - options.showErrorMessages = true; - options.hashMethods.Add(methodName); - options.NeedRegistryZone = false; - - UStringVector messages; - return srcPanel.CopyTo(options, indices, &messages); - } - - #ifdef Z7_EXTERNAL_CODECS - - LoadGlobalCodecs(); - - #endif - - { - CThreadCrc t; - - { - UStringVector methods; - methods.Add(methodName); - RINOK(t.Hash.SetMethods(EXTERNAL_CODECS_VARS_G methods)) - } - - FOR_VECTOR (i, indices) - t.Enumerator.FilePaths.Add(us2fs(srcPanel.GetItemRelPath(indices[i]))); - - if (t.Enumerator.FilePaths.Size() == 1) - t.Hash.MainName = fs2us(t.Enumerator.FilePaths[0]); - - UString basePrefix = srcPanel.GetFsPath(); - UString basePrefix2 = basePrefix; - if (basePrefix2.Back() == ':') - { - const int pos = basePrefix2.ReverseFind_PathSepar(); - if (pos >= 0) - basePrefix2.DeleteFrom((unsigned)(pos + 1)); - } - - t.Enumerator.BasePrefix = us2fs(basePrefix); - t.Enumerator.BasePrefix_for_Open = us2fs(basePrefix2); - - t.Enumerator.EnterToDirs = !GetFlatMode(); - - t.ShowCompressionInfo = false; - - const UString title = LangString(IDS_CHECKSUM_CALCULATING); - - t.MainWindow = _window; - t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); - t.MainAddTitle = title; - t.MainAddTitle.Add_Space(); - - RINOK(t.Create(title, _window)) - - t.ShowFinalResults(_window); - } - - RefreshTitleAlways(); - return S_OK; -} - -void CApp::CalculateCrc(const char *methodName) -{ - HRESULT res = CalculateCrc2(UString(methodName)); - if (res != S_OK && res != E_ABORT) - { - unsigned srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - srcPanel.MessageBox_Error_HRESULT(res); - } -} +// PanelCrc.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyException.h" + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileIO.h" +#include "../../../Windows/FileName.h" + +#include "../Common/LoadCodecs.h" + +#include "../GUI/HashGUI.h" + +#include "App.h" +#include "LangUtils.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; + +#ifdef Z7_EXTERNAL_CODECS +extern CExternalCodecs g_ExternalCodecs; +HRESULT LoadGlobalCodecs(); +#endif + +static const UInt32 kBufSize = (1 << 15); + +struct CDirEnumerator +{ + bool EnterToDirs; + FString BasePrefix; + FString BasePrefix_for_Open; + FStringVector FilePaths; + + CObjectVector Enumerators; + FStringVector Prefixes; + unsigned Index; + + CDirEnumerator(): EnterToDirs(false), Index(0) {} + + void Init(); + DWORD GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath); +}; + +void CDirEnumerator::Init() +{ + Enumerators.Clear(); + Prefixes.Clear(); + Index = 0; +} + +static DWORD GetNormalizedError() +{ + const DWORD error = GetLastError(); + return (error == 0) ? (DWORD)E_FAIL : error; +} + +DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath) +{ + filled = false; + resPath.Empty(); + + for (;;) + { + #if defined(_WIN32) && !defined(UNDER_CE) + bool isRootPrefix = (BasePrefix.IsEmpty() || (NName::IsSuperPath(BasePrefix) && BasePrefix[NName::kSuperPathPrefixSize] == 0)); + #endif + + if (Enumerators.IsEmpty()) + { + if (Index >= FilePaths.Size()) + return S_OK; + const FString &path = FilePaths[Index++]; + const int pos = path.ReverseFind_PathSepar(); + if (pos >= 0) + resPath.SetFrom(path, (unsigned)pos + 1); + + #if defined(_WIN32) && !defined(UNDER_CE) + if (isRootPrefix && path.Len() == 2 && NName::IsDrivePath2(path)) + { + // we use "c:" item as directory item + fi.ClearBase(); + fi.Name = path; + fi.SetAsDir(); + fi.Size = 0; + } + else + #endif + if (!fi.Find(BasePrefix + path)) + { + const DWORD error = GetNormalizedError(); + resPath = path; + return error; + } + + break; + } + + bool found; + + if (Enumerators.Back().Next(fi, found)) + { + if (found) + { + resPath = Prefixes.Back(); + break; + } + } + else + { + const DWORD error = GetNormalizedError(); + resPath = Prefixes.Back(); + Enumerators.DeleteBack(); + Prefixes.DeleteBack(); + return error; + } + + Enumerators.DeleteBack(); + Prefixes.DeleteBack(); + } + + resPath += fi.Name; + + if (EnterToDirs && fi.IsDir()) + { + FString s = resPath; + s.Add_PathSepar(); + Prefixes.Add(s); + Enumerators.AddNew().SetDirPrefix(BasePrefix + s); + } + + filled = true; + return S_OK; +} + + + +class CThreadCrc: public CProgressThreadVirt +{ + bool ResultsWereShown; + bool WasFinished; + + HRESULT ProcessVirt() Z7_override; + virtual void ProcessWasFinished_GuiVirt() Z7_override; +public: + CDirEnumerator Enumerator; + CHashBundle Hash; + // FString FirstFilePath; + + void SetStatus(const UString &s); + void AddErrorMessage(DWORD systemError, const FChar *name); + void ShowFinalResults(HWND hwnd); + + CThreadCrc(): + ResultsWereShown(false), + WasFinished(false) + {} +}; + +void CThreadCrc::ShowFinalResults(HWND hwnd) +{ + if (WasFinished) + if (!ResultsWereShown) + { + ResultsWereShown = true; + ShowHashResults(Hash, hwnd); + } +} + +void CThreadCrc::ProcessWasFinished_GuiVirt() +{ + ShowFinalResults(*this); +} + +void CThreadCrc::AddErrorMessage(DWORD systemError, const FChar *name) +{ + Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(Enumerator.BasePrefix + name)); + Hash.NumErrors++; +} + +void CThreadCrc::SetStatus(const UString &s2) +{ + UString s = s2; + if (!Enumerator.BasePrefix.IsEmpty()) + { + s.Add_Space_if_NotEmpty(); + s += fs2us(Enumerator.BasePrefix); + } + Sync.Set_Status(s); +} + +HRESULT CThreadCrc::ProcessVirt() +{ + // Hash.Init(); + + CMyBuffer buf; + if (!buf.Allocate(kBufSize)) + return E_OUTOFMEMORY; + + CProgressSync &sync = Sync; + + SetStatus(LangString(IDS_SCANNING)); + + Enumerator.Init(); + + FString path; + NFind::CFileInfo fi; + UInt64 numFiles = 0; + UInt64 numItems = 0, numItems_Prev = 0; + UInt64 totalSize = 0; + + for (;;) + { + bool filled; + const DWORD error = Enumerator.GetNextFile(fi, filled, path); + if (error != 0) + { + AddErrorMessage(error, path); + continue; + } + if (!filled) + break; + if (!fi.IsDir()) + { + totalSize += fi.Size; + numFiles++; + } + numItems++; + bool needPrint = false; + // if (fi.IsDir()) + { + if (numItems - numItems_Prev >= 100) + { + needPrint = true; + numItems_Prev = numItems; + } + } + /* + else if (numFiles - numFiles_Prev >= 200) + { + needPrint = true; + numFiles_Prev = numFiles; + } + */ + if (needPrint) + { + RINOK(sync.ScanProgress(numFiles, totalSize, path, fi.IsDir())) + } + } + RINOK(sync.ScanProgress(numFiles, totalSize, FString(), false)) + // sync.SetNumFilesTotal(numFiles); + // sync.SetProgress(totalSize, 0); + // SetStatus(LangString(IDS_CHECKSUM_CALCULATING)); + // sync.SetCurFilePath(L""); + SetStatus(L""); + + Enumerator.Init(); + + FString tempPath; + bool isFirstFile = true; + UInt64 errorsFilesSize = 0; + + for (;;) + { + bool filled; + DWORD error = Enumerator.GetNextFile(fi, filled, path); + if (error != 0) + { + AddErrorMessage(error, path); + continue; + } + if (!filled) + break; + + error = 0; + Hash.InitForNewFile(); + if (!fi.IsDir()) + { + NIO::CInFile inFile; + tempPath = Enumerator.BasePrefix_for_Open; + tempPath += path; + if (!inFile.Open(tempPath)) + { + error = GetNormalizedError(); + AddErrorMessage(error, path); + continue; + } + if (isFirstFile) + { + Hash.FirstFileName = fs2us(path); + isFirstFile = false; + } + sync.Set_FilePath(fs2us(path)); + sync.Set_NumFilesCur(Hash.NumFiles); + UInt64 progress_Prev = 0; + for (;;) + { + UInt32 size; + if (!inFile.Read(buf, kBufSize, size)) + { + error = GetNormalizedError(); + AddErrorMessage(error, path); + UInt64 errorSize = 0; + if (inFile.GetLength(errorSize)) + errorsFilesSize += errorSize; + break; + } + if (size == 0) + break; + Hash.Update(buf, size); + if (Hash.CurSize - progress_Prev >= ((UInt32)1 << 21)) + { + RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize + Hash.CurSize)) + progress_Prev = Hash.CurSize; + } + } + } + if (error == 0) + Hash.Final(fi.IsDir(), false, fs2us(path)); + RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize)) + } + RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize)) + sync.Set_NumFilesCur(Hash.NumFiles); + if (Hash.NumFiles != 1) + sync.Set_FilePath(L""); + SetStatus(L""); + + CProgressMessageBoxPair &pair = GetMessagePair(Hash.NumErrors != 0); + WasFinished = true; + LangString(IDS_CHECKSUM_INFORMATION, pair.Title); + return S_OK; +} + + + +HRESULT CApp::CalculateCrc2(const UString &methodName) +{ + unsigned srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + + CRecordVector indices; + srcPanel.Get_ItemIndices_OperSmart(indices); + if (indices.IsEmpty()) + return S_OK; + + if (!srcPanel.Is_IO_FS_Folder()) + { + CCopyToOptions options; + options.streamMode = true; + options.showErrorMessages = true; + options.hashMethods.Add(methodName); + options.NeedRegistryZone = false; + + UStringVector messages; + return srcPanel.CopyTo(options, indices, &messages); + } + + #ifdef Z7_EXTERNAL_CODECS + + LoadGlobalCodecs(); + + #endif + + { + CThreadCrc t; + + { + UStringVector methods; + methods.Add(methodName); + RINOK(t.Hash.SetMethods(EXTERNAL_CODECS_VARS_G methods)) + } + + FOR_VECTOR (i, indices) + t.Enumerator.FilePaths.Add(us2fs(srcPanel.GetItemRelPath(indices[i]))); + + if (t.Enumerator.FilePaths.Size() == 1) + t.Hash.MainName = fs2us(t.Enumerator.FilePaths[0]); + + UString basePrefix = srcPanel.GetFsPath(); + UString basePrefix2 = basePrefix; + if (basePrefix2.Back() == ':') + { + const int pos = basePrefix2.ReverseFind_PathSepar(); + if (pos >= 0) + basePrefix2.DeleteFrom((unsigned)(pos + 1)); + } + + t.Enumerator.BasePrefix = us2fs(basePrefix); + t.Enumerator.BasePrefix_for_Open = us2fs(basePrefix2); + + t.Enumerator.EnterToDirs = !GetFlatMode(); + + t.ShowCompressionInfo = false; + + const UString title = LangString(IDS_CHECKSUM_CALCULATING); + + t.MainWindow = _window; + t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); + t.MainAddTitle = title; + t.MainAddTitle.Add_Space(); + + RINOK(t.Create(title, _window)) + + t.ShowFinalResults(_window); + } + + RefreshTitleAlways(); + return S_OK; +} + +void CApp::CalculateCrc(const char *methodName) +{ + HRESULT res = CalculateCrc2(UString(methodName)); + if (res != S_OK && res != E_ABORT) + { + unsigned srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + srcPanel.MessageBox_Error_HRESULT(res); + } +} diff --git a/CPP/7zip/UI/FileManager/PanelDrag.cpp b/CPP/7zip/UI/FileManager/PanelDrag.cpp index c46965335..f9b0a6c7a 100644 --- a/CPP/7zip/UI/FileManager/PanelDrag.cpp +++ b/CPP/7zip/UI/FileManager/PanelDrag.cpp @@ -1,3006 +1,3006 @@ -// PanelDrag.cpp - -#include "StdAfx.h" - -#ifdef UNDER_CE -#include -#endif - -#include "../../../../C/7zVersion.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/COM.h" -#include "../../../Windows/MemoryGlobal.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Shell.h" - -#include "../Common/ArchiveName.h" -#include "../Common/CompressCall.h" -#include "../Common/ExtractingFilePath.h" - -#include "MessagesDialog.h" - -#include "App.h" -#include "EnumFormatEtc.h" -#include "FormatUtils.h" -#include "LangUtils.h" - -#include "resource.h" -#include "../Explorer/resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -#define PRF(x) -#define PRF_W(x) -// #define PRF2(x) -#define PRF3(x) -#define PRF3_W(x) -#define PRF4(x) -// #define PRF4(x) OutputDebugStringA(x) -// #define PRF4_W(x) OutputDebugStringW(x) - -// #define SHOW_DEBUG_DRAG - -#ifdef SHOW_DEBUG_DRAG - -#define PRF_(x) { x; } - -static void Print_Point(const char *name, DWORD keyState, const POINTL &pt, DWORD effect) -{ - AString s (name); - s += " x="; s.Add_UInt32((unsigned)pt.x); - s += " y="; s.Add_UInt32((unsigned)pt.y); - s += " k="; s.Add_UInt32(keyState); - s += " e="; s.Add_UInt32(effect); - PRF4(s); -} - -#else - -#define PRF_(x) - -#endif - - -#define kTempDirPrefix FTEXT("7zE") - -// all versions: k_Format_7zip_SetTargetFolder format to transfer folder path from target to source -static LPCTSTR const k_Format_7zip_SetTargetFolder = TEXT("7-Zip::SetTargetFolder"); -// new v23 formats: -static LPCTSTR const k_Format_7zip_SetTransfer = TEXT("7-Zip::SetTransfer"); -static LPCTSTR const k_Format_7zip_GetTransfer = TEXT("7-Zip::GetTransfer"); - -/* - Win10: clipboard formats. - There are about 16K free ids (formats) per system that can be - registered with RegisterClipboardFormat() with different names. - Probably that 16K ids space is common for ids registering for both - formats: RegisterClipboardFormat(), and registered window classes: - RegisterClass(). But ids for window classes will be deleted from - the list after process finishing. And registered clipboard - formats probably will be deleted from the list only after reboot. -*/ - -// static bool const g_CreateArchive_for_Drag_from_7zip = false; -// static bool const g_CreateArchive_for_Drag_from_Explorer = true; - // = false; // for debug - -/* -How DoDragDrop() works: -{ - IDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0 - IDropTarget::Enter() - IDropSource::GiveFeedback() - IDropTarget::DragOver() - IDropSource::GiveFeedback() - - for() - { - IDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0 - IDropTarget::DragOver() (keyState & MK_LBUTTON) != 0 - IDropSource::GiveFeedback() - } - - { - // DoDragDrop() in Win10 before calling // QueryContinueDrag() - // with (*(keyState & MK_LBUTTON) == 0) probably calls: - // 1) IDropTarget::DragOver() with same point values (x,y), but (keyState & MK_LBUTTON) != 0) - // 2) IDropSource::GiveFeedback(). - // so DropSource can know exact GiveFeedback(effect) mode just before LBUTTON releasing. - - if (IDropSource::QueryContinueDrag() for (keyState & MK_LBUTTON) == 0 - returns DRAGDROP_S_DROP), it will call - IDropTarget::Drop() - } - or - { - IDropSource::QueryContinueDrag() - IDropTarget::DragLeave() - IDropSource::GiveFeedback(0) - } - or - { - if (IDropSource::QueryContinueDrag() - returns DRAGDROP_S_CANCEL) - IDropTarget::DragLeave() - } -} -*/ - - -// ---------- CDropTarget ---------- - -static const UInt32 k_Struct_Id_SetTranfer = 2; // it's our selected id -static const UInt32 k_Struct_Id_GetTranfer = 3; // it's our selected id - -static const UInt64 k_Program_Id = 1; // "7-Zip" - -enum E_Program_ISA -{ - k_Program_ISA_x86 = 2, - k_Program_ISA_x64 = 3, - k_Program_ISA_armt = 4, - k_Program_ISA_arm64 = 5, - k_Program_ISA_arm32 = 6, - k_Program_ISA_ia64 = 9 -}; - -#define k_Program_Ver ((MY_VER_MAJOR << 16) | MY_VER_MINOR) - - -// k_SourceFlags_* are flags that are sent from Source to Target - -static const UInt32 k_SourceFlags_DoNotProcessInTarget = 1 << 1; -/* Do not process in Target. Source will process operation instead of Target. - By default Target processes Drop opearation. */ -// static const UInt32 k_SourceFlags_ProcessInTarget = 1 << 2; - -static const UInt32 k_SourceFlags_DoNotWaitFinish = 1 << 3; -static const UInt32 k_SourceFlags_WaitFinish = 1 << 4; -/* usually Source needs WaitFinish, if temp files were created. */ - -static const UInt32 k_SourceFlags_TempFiles = 1 << 6; -static const UInt32 k_SourceFlags_NamesAreParent = 1 << 7; -/* if returned path list for GetData(CF_HDROP) contains - path of parent temp folder instead of final paths of items - that will be extracted later from archive */ - -static const UInt32 k_SourceFlags_SetTargetFolder = 1 << 8; -/* SetData::("SetTargetFolder") was called (with empty or non-empty string) */ - -static const UInt32 k_SourceFlags_SetTargetFolder_NonEmpty = 1 << 9; -/* SetData::("SetTargetFolder") was called with non-empty string */ - -static const UInt32 k_SourceFlags_NeedExtractOpToFs = 1 << 10; - -static const UInt32 k_SourceFlags_Copy_WasCalled = 1 << 11; - -static const UInt32 k_SourceFlags_LeftButton = 1 << 14; -static const UInt32 k_SourceFlags_RightButton = 1 << 15; - - -static const UInt32 k_TargetFlags_WasCanceled = 1 << 0; -static const UInt32 k_TargetFlags_MustBeProcessedBySource = 1 << 1; -static const UInt32 k_TargetFlags_WasProcessed = 1 << 2; -static const UInt32 k_TargetFlags_DoNotWaitFinish = 1 << 3; -static const UInt32 k_TargetFlags_WaitFinish = 1 << 4; -static const UInt32 k_TargetFlags_MenuWasShown = 1 << 16; - -struct CDataObject_TransferBase -{ - UInt32 Struct_Id; - UInt32 Struct_Size; - - UInt64 Program_Id; - UInt32 Program_Ver_Main; - UInt32 Program_Ver_Build; - UInt32 Program_ISA; - UInt32 Program_Flags; - - UInt32 ProcessId; - UInt32 _reserved1[7]; - -protected: - void Init_Program(); -}; - - -void CDataObject_TransferBase::Init_Program() -{ - Program_Id = k_Program_Id; - Program_ISA = - #if defined(MY_CPU_AMD64) - k_Program_ISA_x64 - #elif defined(MY_CPU_X86) - k_Program_ISA_x86 - #elif defined(MY_CPU_ARM64) - k_Program_ISA_arm64 - #elif defined(MY_CPU_ARM32) - k_Program_ISA_arm32 - #elif defined(MY_CPU_ARMT) || defined(MY_CPU_ARM) - k_Program_ISA_armt - #elif defined(MY_CPU_IA64) - k_Program_ISA_ia64 - #else - 0 - #endif - ; - Program_Flags = sizeof(size_t); - Program_Ver_Main = k_Program_Ver; - // Program_Ver_Build = 0; - ProcessId = GetCurrentProcessId(); -} - - -#if defined(__GNUC__) && !defined(__clang__) -/* 'void* memset(void*, int, size_t)' clearing an object - of non-trivial type 'struct CDataObject_SetTransfer' */ -#pragma GCC diagnostic ignored "-Wclass-memaccess" -#endif - - -struct CDataObject_GetTransfer: -public CDataObject_TransferBase -{ - UInt32 Flags; - - UInt32 _reserved2[11]; - - CDataObject_GetTransfer() - { - memset(this, 0, sizeof(*this)); - Init_Program(); - Struct_Id = k_Struct_Id_GetTranfer; - Struct_Size = sizeof(*this); - } - - bool Check() const - { - return Struct_Size >= sizeof(*this) && Struct_Id == k_Struct_Id_GetTranfer; - } -}; - - -enum Enum_FolderType -{ - k_FolderType_None, - k_FolderType_Unknown = 1, - k_FolderType_Fs = 2, - k_FolderType_AltStreams = 3, - k_FolderType_Archive = 4 -}; - -struct CTargetTransferInfo -{ - UInt32 Flags; - UInt32 FuncType; - - UInt32 KeyState; - UInt32 OkEffects; - POINTL Point; - - UInt32 Cmd_Effect; - UInt32 Cmd_Type; - UInt32 FolderType; - UInt32 _reserved3[3]; - - CTargetTransferInfo() - { - memset(this, 0, sizeof(*this)); - } -}; - -struct CDataObject_SetTransfer: -public CDataObject_TransferBase -{ - CTargetTransferInfo Target; - - void Init() - { - memset(this, 0, sizeof(*this)); - Init_Program(); - Struct_Id = k_Struct_Id_SetTranfer; - Struct_Size = sizeof(*this); - } - - bool Check() const - { - return Struct_Size >= sizeof(*this) && Struct_Id == k_Struct_Id_SetTranfer; - } -}; - - - - - -enum Enum_DragTargetMode -{ - k_DragTargetMode_None = 0, - k_DragTargetMode_Leave = 1, - k_DragTargetMode_Enter = 2, - k_DragTargetMode_Over = 3, - k_DragTargetMode_Drop_Begin = 4, - k_DragTargetMode_Drop_End = 5 -}; - - -// ---- menu ---- - -namespace NDragMenu { - -enum Enum_CmdId -{ - k_None = 0, - k_Cancel = 1, - k_Copy_Base = 2, // to fs - k_Copy_ToArc = 3, - k_AddToArc = 4 - /* - k_OpenArc = 8, - k_TestArc = 9, - k_ExtractFiles = 10, - k_ExtractHere = 11 - */ -}; - -struct CCmdLangPair -{ - unsigned CmdId_and_Flags; - unsigned LangId; -}; - -static const UInt32 k_MenuFlags_CmdMask = (1 << 7) - 1; -static const UInt32 k_MenuFlag_Copy = 1 << 14; -static const UInt32 k_MenuFlag_Move = 1 << 15; -// #define IDS_CANCEL (IDCANCEL + 400) -#define IDS_CANCEL 402 - -static const CCmdLangPair g_Pairs[] = -{ - { k_Copy_Base | k_MenuFlag_Copy, IDS_COPY }, - { k_Copy_Base | k_MenuFlag_Move, IDS_MOVE }, - { k_Copy_ToArc | k_MenuFlag_Copy, IDS_COPY_TO }, - // { k_Copy_ToArc | k_MenuFlag_Move, IDS_MOVE_TO }, // IDS_CONTEXT_COMPRESS_TO - // { k_OpenArc, IDS_CONTEXT_OPEN }, - // { k_ExtractFiles, IDS_CONTEXT_EXTRACT }, - // { k_ExtractHere, IDS_CONTEXT_EXTRACT_HERE }, - // { k_TestArc, IDS_CONTEXT_TEST }, - { k_AddToArc | k_MenuFlag_Copy, IDS_CONTEXT_COMPRESS }, - { k_Cancel, IDS_CANCEL } -}; - -} - - -class CDropTarget Z7_final: - public IDropTarget, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1_MT(IDropTarget) - STDMETHOD(DragEnter)(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) Z7_override; - STDMETHOD(DragOver)(DWORD keyState, POINTL pt, DWORD *effect) Z7_override; - STDMETHOD(DragLeave)() Z7_override; - STDMETHOD(Drop)(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) Z7_override; - - bool m_IsRightButton; - bool m_GetTransfer_WasSuccess; - bool m_DropIsAllowed; // = true, if data IDataObject can return CF_HDROP (so we can get list of paths) - bool m_PanelDropIsAllowed; // = false, if current target_panel is source_panel. - // check it only if m_DropIsAllowed == true - // we use it to show icon effect that drop is not allowed here. - - CMyComPtr m_DataObject; // we set it in DragEnter() - UStringVector m_SourcePaths; - - // int m_DropHighlighted_SelectionIndex; - // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item) - // UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder) - - CPanel *m_Panel; - bool m_IsAppTarget; // true, if we want to drop to app window (not to panel) - - bool m_TargetPath_WasSent_ToDataObject; // true, if TargetPath was sent - bool m_TargetPath_NonEmpty_WasSent_ToDataObject; // true, if non-empty TargetPath was sent - bool m_Transfer_WasSent_ToDataObject; // true, if Transfer was sent - UINT m_Format_7zip_SetTargetFolder; - UINT m_Format_7zip_SetTransfer; - UINT m_Format_7zip_GetTransfer; - - UInt32 m_ProcessId; // for sending - - bool IsItSameDrive() const; - - // void Try_QueryGetData(IDataObject *dataObject); - void LoadNames_From_DataObject(IDataObject *dataObject); - - UInt32 GetFolderType() const; - bool IsFsFolderPath() const; - DWORD GetEffect(DWORD keyState, POINTL pt, DWORD allowedEffect) const; - void RemoveSelection(); - void PositionCursor(const POINTL &ptl); - UString GetTargetPath() const; - bool SendToSource_TargetPath_enable(IDataObject *dataObject, bool enablePath); - bool SendToSource_UInt32(IDataObject *dataObject, UINT format, UInt32 value); - bool SendToSource_TransferInfo(IDataObject *dataObject, - const CTargetTransferInfo &info); - void SendToSource_auto(IDataObject *dataObject, - const CTargetTransferInfo &info); - void SendToSource_Drag(CTargetTransferInfo &info) - { - SendToSource_auto(m_DataObject, info); - } - - void ClearState(); - -public: - CDropTarget(); - - CApp *App; - int SrcPanelIndex; // index of D&D source_panel - int TargetPanelIndex; // what panel to use as target_panel of Application -}; - - - - -// ---------- CDataObject ---------- - -/* - Some programs (like Sticky Notes in Win10) do not like - virtual non-existing items (files/dirs) in CF_HDROP format. - So we use two versions of CF_HDROP data: - m_hGlobal_HDROP_Pre : the list contains only destination path of temp directory. - That directory later will be filled with extracted items. - m_hGlobal_HDROP_Final : the list contains paths of all root items that - will be created in temp directory by archive extraction operation, - or the list of existing fs items, if source is filesystem directory. - - The DRAWBACK: some programs (like Edge in Win10) can use names from IDataObject::GetData() - call that was called before IDropSource::QueryContinueDrag() where we set (UseFinalGlobal = true) - So such programs will use non-relevant m_hGlobal_HDROP_Pre item, - instead of m_hGlobal_HDROP_Final items. -*/ - -class CDataObject Z7_final: - public IDataObject, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1_MT(IDataObject) - - Z7_COMWF_B GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium) Z7_override; - Z7_COMWF_B GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium) Z7_override; - Z7_COMWF_B QueryGetData(LPFORMATETC pformatetc) Z7_override; - - Z7_COMWF_B GetCanonicalFormatEtc(LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut) Z7_override - { - if (!pformatetcOut) - return E_INVALIDARG; - pformatetcOut->ptd = NULL; - return E_NOTIMPL; - } - - Z7_COMWF_B SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) Z7_override; - Z7_COMWF_B EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc) Z7_override; - - Z7_COMWF_B DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */) Z7_override - { return OLE_E_ADVISENOTSUPPORTED; } - Z7_COMWF_B DUnadvise(DWORD /* dwConnection */) Z7_override - { return OLE_E_ADVISENOTSUPPORTED; } - Z7_COMWF_B EnumDAdvise(LPENUMSTATDATA *ppenumAdvise) Z7_override - { - if (ppenumAdvise) - *ppenumAdvise = NULL; - return OLE_E_ADVISENOTSUPPORTED; - } - - bool m_PerformedDropEffect_WasSet; - bool m_LogicalPerformedDropEffect_WasSet; - bool m_DestDirPrefix_FromTarget_WasSet; -public: - bool m_Transfer_WasSet; -private: - // GetData formats (source to target): - FORMATETC m_Etc; - // UINT m_Format_FileOpFlags; - // UINT m_Format_PreferredDropEffect; - - // SetData() formats (target to source): - // 7-Zip's format: - UINT m_Format_7zip_SetTargetFolder; - UINT m_Format_7zip_SetTransfer; - UINT m_Format_7zip_GetTransfer; // for GetData() - - UINT m_Format_PerformedDropEffect; - UINT m_Format_LogicalPerformedDropEffect; - UINT m_Format_DisableDragText; - UINT m_Format_IsShowingLayered; - UINT m_Format_IsShowingText; - UINT m_Format_DropDescription; - UINT m_Format_TargetCLSID; - - DWORD m_PerformedDropEffect; - DWORD m_LogicalPerformedDropEffect; - - void CopyFromPanelTo_Folder(); - HRESULT SetData2(const FORMATETC *formatetc, const STGMEDIUM *medium); - -public: - bool IsRightButton; - bool IsTempFiles; - - bool UsePreGlobal; - bool DoNotProcessInTarget; - - bool NeedCall_Copy; - bool Copy_WasCalled; - - NMemory::CGlobal m_hGlobal_HDROP_Pre; - NMemory::CGlobal m_hGlobal_HDROP_Final; - // NMemory::CGlobal m_hGlobal_FileOpFlags; - // NMemory::CGlobal m_hGlobal_PreferredDropEffect; - - CPanel *Panel; - CRecordVector Indices; - - UString SrcDirPrefix_Temp; // FS directory with source files or Temp - UString DestDirPrefix_FromTarget; - /* destination Path that was sent by Target via SetData(). - it can be altstreams prefix. - if (!DestDirPrefix_FromTarget.IsEmpty()) m_Panel->CompressDropFiles() was not called by Target. - So we must do drop actions in Source */ - HRESULT Copy_HRESULT; - UStringVector Messages; - - CDataObject(); -public: - CDataObject_SetTransfer m_Transfer; -}; - - -// for old mingw: -#ifndef CFSTR_LOGICALPERFORMEDDROPEFFECT -#define CFSTR_LOGICALPERFORMEDDROPEFFECT TEXT("Logical Performed DropEffect") -#endif -#ifndef CFSTR_TARGETCLSID -#define CFSTR_TARGETCLSID TEXT("TargetCLSID") // HGLOBAL with a CLSID of the drop target -#endif - - - -CDataObject::CDataObject() -{ - // GetData formats (source to target): - // and we use CF_HDROP format to transfer file paths from source to target: - m_Etc.cfFormat = CF_HDROP; - m_Etc.ptd = NULL; - m_Etc.dwAspect = DVASPECT_CONTENT; - m_Etc.lindex = -1; - m_Etc.tymed = TYMED_HGLOBAL; - - // m_Format_FileOpFlags = RegisterClipboardFormat(TEXT("FileOpFlags")); - // m_Format_PreferredDropEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); // "Preferred DropEffect" - - // SetData() formats (target to source): - m_Format_7zip_SetTargetFolder = RegisterClipboardFormat(k_Format_7zip_SetTargetFolder); - m_Format_7zip_SetTransfer = RegisterClipboardFormat(k_Format_7zip_SetTransfer); - m_Format_7zip_GetTransfer = RegisterClipboardFormat(k_Format_7zip_GetTransfer); - - m_Format_PerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); // "Performed DropEffect" - m_Format_LogicalPerformedDropEffect = RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT); // "Logical Performed DropEffect" - m_Format_DisableDragText = RegisterClipboardFormat(TEXT("DisableDragText")); - m_Format_IsShowingLayered = RegisterClipboardFormat(TEXT("IsShowingLayered")); - m_Format_IsShowingText = RegisterClipboardFormat(TEXT("IsShowingText")); - m_Format_DropDescription = RegisterClipboardFormat(TEXT("DropDescription")); - m_Format_TargetCLSID = RegisterClipboardFormat(CFSTR_TARGETCLSID); - - m_PerformedDropEffect = 0; - m_LogicalPerformedDropEffect = 0; - - m_PerformedDropEffect_WasSet = false; - m_LogicalPerformedDropEffect_WasSet = false; - - m_DestDirPrefix_FromTarget_WasSet = false; - m_Transfer_WasSet = false; - - IsRightButton = false; - IsTempFiles = false; - - UsePreGlobal = false; - DoNotProcessInTarget = false; - - NeedCall_Copy = false; - Copy_WasCalled = false; - - Copy_HRESULT = S_OK; -} - - - -void CDataObject::CopyFromPanelTo_Folder() -{ - try - { - CCopyToOptions options; - options.folder = SrcDirPrefix_Temp; - /* 15.13: fixed problem with mouse cursor for password window. - DoDragDrop() probably calls SetCapture() to some hidden window. - But it's problem, if we show some modal window, like MessageBox. - So we return capture to our window. - If you know better way to solve the problem, please notify 7-Zip developer. - */ - // MessageBoxW(*Panel, L"test", L"test", 0); - /* HWND oldHwnd = */ SetCapture(*Panel); - Copy_WasCalled = true; - Copy_HRESULT = E_FAIL; - Copy_HRESULT = Panel->CopyTo(options, Indices, &Messages); - // do we need to restore capture? - // ReleaseCapture(); - // oldHwnd = SetCapture(oldHwnd); - } - catch(...) - { - Copy_HRESULT = E_FAIL; - } -} - - -#ifdef SHOW_DEBUG_DRAG - -static void PrintFormat2(AString &s, unsigned format) -{ - s += " "; - s += "= format="; - s.Add_UInt32(format); - s += " "; - const int k_len = 512; - CHAR temp[k_len]; - if (GetClipboardFormatNameA(format, temp, k_len) && strlen(temp) != 0) - s += temp; -} - -static void PrintFormat(const char *title, unsigned format) -{ - AString s (title); - PrintFormat2(s, format); - PRF4(s); -} - -static void PrintFormat_AndData(const char *title, unsigned format, const void *data, size_t size) -{ - AString s (title); - PrintFormat2(s, format); - s += " size="; - s.Add_UInt32((UInt32)size); - for (size_t i = 0; i < size && i < 16; i++) - { - s += " "; - s.Add_UInt32(((const Byte *)data)[i]); - } - PRF4(s); -} - -static void PrintFormat_GUIDToStringW(const void *p) -{ - const GUID *guid = (const GUID *)p; - UString s; - const unsigned kSize = 48; - StringFromGUID2(*guid, s.GetBuf(kSize), kSize); - s.ReleaseBuf_CalcLen(kSize); - PRF3_W(s); -} - -// Vista -typedef enum -{ - MY_DROPIMAGE_INVALID = -1, // no image preference (use default) - MY_DROPIMAGE_NONE = 0, // red "no" circle - MY_DROPIMAGE_COPY = DROPEFFECT_COPY, // plus for copy - MY_DROPIMAGE_MOVE = DROPEFFECT_MOVE, // movement arrow for move - MY_DROPIMAGE_LINK = DROPEFFECT_LINK, // link arrow for link - MY_DROPIMAGE_LABEL = 6, // tag icon to indicate metadata will be changed - MY_DROPIMAGE_WARNING = 7, // yellow exclamation, something is amiss with the operation - MY_DROPIMAGE_NOIMAGE = 8 // no image at all -} MY_DROPIMAGETYPE; - -typedef struct { - MY_DROPIMAGETYPE type; - WCHAR szMessage[MAX_PATH]; - WCHAR szInsert[MAX_PATH]; -} MY_DROPDESCRIPTION; - -#endif - - -/* -IDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) -====================================================================== - - Main purpose of CDataObject is to transfer data from source to target - of drag and drop operation. - But also CDataObject can be used to transfer data in backward direction - from target to source (even if target and source are different processes). - There are some predefined Explorer's formats to transfer some data from target to source. - And 7-Zip uses 7-Zip's format k_Format_7zip_SetTargetFolder to transfer - destination directory path from target to source. - - Our CDataObject::SetData() function here is used only to transfer data from target to source. - Usual source_to_target data is filled to m_hGlobal_* objects directly without SetData() calling. - -The main problem of SetData() is ownership of medium for (release == TRUE) case. - -SetData(,, release = TRUE) from different processes (DropSource and DropTarget) -=============================================================================== -{ - MS DOCs about (STGMEDIUM *medium) ownership: - The data object called does not take ownership of the data - until it has successfully received it and no error code is returned. - - Each of processes (Source and Target) has own copy of medium allocated. - Windows code creates proxy IDataObject object in Target process to transferr - SetData() call between Target and Source processes via special proxies: - DropTarget -> - proxy_DataObject_in_Target -> - proxy_in_Source -> - DataObject_in_Source - when Target calls SetData() with proxy_DataObject_in_Target, - the system and proxy_in_Source - - allocates proxy-medium-in-Source process - - copies medium data from Target to that proxy-medium-in-Source - - sends proxy-medium-in-Source to DataObject_in_Source->SetData(). - - after returning from SetData() to Target process: - Win10 proxy_DataObject_in_Target releases original medium in Target process, - only if SetData() in Source returns S_OK. It's consistent with DOCs above. - - for unsupported cfFormat: - [DropSource is 7-Zip 22.01 (old) : (etc->cfFormat != m_Format_7zip_SetTargetFolder && release == TRUE)] - (DropSource is WinRAR case): - Source doesn't release medium and returns error (for example, E_NOTIMPL) - { - Then Win10 proxy_in_Source also doesn't release proxy-medium-in-Source. - So there is memory leak in Source process. - Probably Win10 proxy_in_Source tries to avoid possible double releasing - that can be more fatal than memory leak. - - Then Win10 proxy_DataObject_in_Target also doesn't release - original medium, that was allocated by DropTarget. - So if DropTarget also doesn't release medium, there is memory leak in - DropTarget process too. - DropTarget is Win10-Explorer probably doesn't release medium in that case. - } - - [DropSource is 7-Zip 22.01 (old) : (etc->cfFormat == m_Format_7zip_SetTargetFolder && release == TRUE)] - DropSource returns S_OK and doesn't release medium: - { - then there is memory leak in DropSource process only. - } - - (DropSource is 7-Zip v23 (new)): - (DropSource is Win10-Explorer case) - { - Win10-Explorer-DropSource probably always releases medium, - and then it always returns S_OK. - So Win10 proxy_DataObject_in_Target also releases - original medium, that was allocated by DropTarget. - So there is no memory leak in Source and Target processes. - } - - if (DropTarget is Win10-Explorer) - { - Explorer Target uses SetData(,, (release = TRUE)) and - Explorer Target probably doesn't free memory after SetData(), - even if SetData(,, (release = TRUE)) returns E_NOTIMPL; - } - - if (DropSource is Win10-Explorer) - { - (release == FALSE) doesn't work, and SetData() returns E_NOTIMPL; - (release == TRUE) works, and SetData() returns S_OK, and - it returns S_OK even for formats unsupported by Explorer. - } - - To be more compatible with DOCs and Win10-Explorer and to avoid memory leaks, - we use the following scheme for our IDataObject::SetData(,, release == TRUE) - in DropSource code: - if (release == TRUE) { our SetData() always releases medium - with ReleaseStgMedium() and returns S_OK; } - The DRAWBACK of that scheme: - The caller always receives S_OK, - so the caller doesn't know about any error in SetData() in that case. - -for 7zip-Target to 7zip-Source calls: - we use (release == FALSE) - So we avoid (release == TRUE) memory leak problems, - and we can get real return code from SetData(). - -for 7zip-Target to Explorer-Source calls: - we use (release == TRUE). - beacuse Explorer-Source doesn't accept (release == FALSE). -} -*/ - -/* -https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/shell/datascenarios.md -CFSTR_PERFORMEDDROPEFFECT: - is used by the target to inform the data object through its - IDataObject::SetData method of the outcome of a data transfer. -CFSTR_PREFERREDDROPEFFECT: - is used by the source to specify whether its preferred method of data transfer is move or copy. -*/ - -Z7_COMWF_B CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) -{ - try { - const HRESULT hres = SetData2(etc, medium); - // PrintFormat(release ? "SetData RELEASE=TRUE" : "SetData RELEASE=FALSE" , etc->cfFormat); - if (release) - { - /* - const DWORD tymed = medium->tymed; - IUnknown *pUnkForRelease = medium->pUnkForRelease; - */ - // medium->tymed = NULL; // for debug - // return E_NOTIMPL; // for debug - ReleaseStgMedium(medium); - /* ReleaseStgMedium() will change STGMEDIUM::tymed to (TYMED_NULL = 0). - but we also can clear (medium.hGlobal = NULL), - to prevent some incorrect releasing, if the caller will try to release the data */ - /* - if (medium->tymed == TYMED_NULL && tymed == TYMED_HGLOBAL && !pUnkForRelease) - medium->hGlobal = NULL; - */ - // do we need return S_OK; for (tymed != TYMED_HGLOBAL) cases ? - /* we return S_OK here to shows that we take ownership of the data in (medium), - so the caller will not try to release (medium) */ - return S_OK; // to be more compatible with Win10-Explorer and DOCs. - } - return hres; - } catch(...) { return E_FAIL; } -} - - - -HRESULT CDataObject::SetData2(const FORMATETC *etc, const STGMEDIUM *medium) -{ - // PRF3("== CDataObject::SetData()"); - - HRESULT hres = S_OK; - - if (etc->cfFormat == 0) - return DV_E_FORMATETC; - if (etc->tymed != TYMED_HGLOBAL) - return E_NOTIMPL; // DV_E_TYMED; - if (etc->dwAspect != DVASPECT_CONTENT) - return E_NOTIMPL; // DV_E_DVASPECT; - if (medium->tymed != TYMED_HGLOBAL) - return E_NOTIMPL; // DV_E_TYMED; - - if (!medium->hGlobal) - return S_OK; - - if (etc->cfFormat == m_Format_7zip_SetTargetFolder) - { - DestDirPrefix_FromTarget.Empty(); - m_DestDirPrefix_FromTarget_WasSet = true; - } - else if (etc->cfFormat == m_Format_7zip_SetTransfer) - m_Transfer_WasSet = false; - - const size_t size = GlobalSize(medium->hGlobal); - // GlobalLock() can return NULL, if memory block has a zero size - if (size == 0) - return S_OK; - const void *src = (const Byte *)GlobalLock(medium->hGlobal); - if (!src) - return E_FAIL; - - PRF_(PrintFormat_AndData("SetData", etc->cfFormat, src, size)) - - if (etc->cfFormat == m_Format_7zip_SetTargetFolder) - { - /* this is our registered k_Format_7zip_SetTargetFolder format. - so it's call from 7-zip's CDropTarget */ - /* 7-zip's CDropTarget calls SetData() for m_Format_7zip_SetTargetFolder - with (release == FALSE) */ - const size_t num = size / sizeof(wchar_t); - if (size != num * sizeof(wchar_t)) - return E_FAIL; - // if (num == 0) return S_OK; - // GlobalLock() can return NULL, if memory block has a zero-byte size - const wchar_t *s = (const wchar_t *)src; - UString &dest = DestDirPrefix_FromTarget; - for (size_t i = 0; i < num; i++) - { - const wchar_t c = s[i]; - if (c == 0) - break; - dest += c; - } - // PRF_(PrintFormat_AndData("SetData", etc->cfFormat, src, size)) - PRF3_W(DestDirPrefix_FromTarget); - } - else if (etc->cfFormat == m_Format_7zip_SetTransfer) - { - /* 7-zip's CDropTarget calls SetData() for m_Format_7zip_SetTransfer - with (release == FALSE) */ - if (size < sizeof(CDataObject_SetTransfer)) - return E_FAIL; - const CDataObject_SetTransfer *t = (const CDataObject_SetTransfer *)src; - if (!t->Check()) - return E_FAIL; - m_Transfer = *t; - if (t->Target.FuncType != k_DragTargetMode_Leave) - m_Transfer_WasSet = true; - bool needProcessBySource = !DestDirPrefix_FromTarget.IsEmpty(); - if (t->Target.FuncType == k_DragTargetMode_Drop_Begin) - { - if (t->Target.Cmd_Type != NDragMenu::k_Copy_Base - // || t->Target.Cmd_Effect != DROPEFFECT_COPY - ) - needProcessBySource = false; - } - if (t->Target.FuncType == k_DragTargetMode_Drop_End) - { - if (t->Target.Flags & k_TargetFlags_MustBeProcessedBySource) - needProcessBySource = true; - else if (t->Target.Flags & k_TargetFlags_WasProcessed) - needProcessBySource = false; - } - DoNotProcessInTarget = needProcessBySource; - } - else - { - // SetData() from Explorer Target: - if (etc->cfFormat == m_Format_PerformedDropEffect) - { - m_PerformedDropEffect_WasSet = false; - if (size == sizeof(DWORD)) - { - m_PerformedDropEffect = *(const DWORD *)src; - m_PerformedDropEffect_WasSet = true; - } - } - else if (etc->cfFormat == m_Format_LogicalPerformedDropEffect) - { - m_LogicalPerformedDropEffect_WasSet = false; - if (size == sizeof(DWORD)) - { - m_LogicalPerformedDropEffect = *(const DWORD *)src; - m_LogicalPerformedDropEffect_WasSet = true; - } - } - else if (etc->cfFormat == m_Format_DropDescription) - { - // drop description contains only name of dest folder without full path - #ifdef SHOW_DEBUG_DRAG - if (size == sizeof(MY_DROPDESCRIPTION)) - { - // const MY_DROPDESCRIPTION *s = (const MY_DROPDESCRIPTION *)src; - // PRF3_W(s->szMessage); - // PRF3_W(s->szInsert); - } - #endif - } - else if (etc->cfFormat == m_Format_TargetCLSID) - { - // it's called after call QueryContinueDrag() (keyState & MK_LBUTTON) == 0 - // Shell File System Folder (explorer) guid: F3364BA0-65B9-11CE-A9BA-00AA004AE837 - #ifdef SHOW_DEBUG_DRAG - if (size == 16) - { - PrintFormat_GUIDToStringW((const Byte *)src); - } - #endif - } - else if (etc->cfFormat == m_Format_DisableDragText) - { - // (size == 4) (UInt32 value) - // value==0 : if drag to folder item or folder - // value==1 : if drag to file or non list_view */ - } - else if ( - etc->cfFormat == m_Format_IsShowingLayered || - etc->cfFormat == m_Format_IsShowingText) - { - // (size == 4) (UInt32 value) value==0 : - } - else - hres = DV_E_FORMATETC; - // hres = E_NOTIMPL; // for debug - // hres = DV_E_FORMATETC; // for debug - } - - GlobalUnlock(medium->hGlobal); - return hres; -} - - - -static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal) -{ - /* GlobalSize() returns 0: If the specified handle - is not valid or if the object has been discarded */ - const SIZE_T size = GlobalSize(srcGlobal); - if (size == 0) - return NULL; - // GlobalLock() can return NULL, if memory block has a zero-byte size - const void *src = GlobalLock(srcGlobal); - if (!src) - return NULL; - HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); - if (destGlobal) - { - void *dest = GlobalLock(destGlobal); - if (!dest) - { - GlobalFree(destGlobal); - destGlobal = NULL; - } - else - { - memcpy(dest, src, size); - GlobalUnlock(destGlobal); - } - } - GlobalUnlock(srcGlobal); - return destGlobal; -} - - -static bool Medium_CopyFrom(LPSTGMEDIUM medium, const void *data, size_t size) -{ - medium->tymed = TYMED_NULL; - medium->pUnkForRelease = NULL; - medium->hGlobal = NULL; - const HGLOBAL global = GlobalAlloc(GHND | GMEM_SHARE, size); - if (!global) - return false; - void *dest = GlobalLock(global); - if (!dest) - { - GlobalFree(global); - return false; - } - memcpy(dest, data, size); - GlobalUnlock(global); - medium->hGlobal = global; - medium->tymed = TYMED_HGLOBAL; - return true; -} - - -Z7_COMWF_B CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium) -{ - try { - PRF_(PrintFormat("-- GetData", etc->cfFormat)) - - medium->tymed = TYMED_NULL; - medium->pUnkForRelease = NULL; - medium->hGlobal = NULL; - - if (NeedCall_Copy && !Copy_WasCalled) - CopyFromPanelTo_Folder(); - - // PRF3("+ CDataObject::GetData"); - // PrintFormat(etc->cfFormat); - HGLOBAL global; - RINOK(QueryGetData(etc)) - - /* - if (etc->cfFormat == m_Format_FileOpFlags) - global = m_hGlobal_FileOpFlags; - else if (etc->cfFormat == m_Format_PreferredDropEffect) - { - // Explorer requests PreferredDropEffect only if Move/Copy selection is possible: - // Shift is not pressed and Ctrl is not pressed - PRF3("------ CDataObject::GetData() PreferredDropEffect"); - global = m_hGlobal_PreferredDropEffect; - } - else - */ - if (etc->cfFormat == m_Etc.cfFormat) // CF_HDROP - global = UsePreGlobal ? m_hGlobal_HDROP_Pre : m_hGlobal_HDROP_Final; - else if (etc->cfFormat == m_Format_7zip_GetTransfer) - { - CDataObject_GetTransfer transfer; - if (m_DestDirPrefix_FromTarget_WasSet) - { - transfer.Flags |= k_SourceFlags_SetTargetFolder; - } - if (!DestDirPrefix_FromTarget.IsEmpty()) - { - transfer.Flags |= k_SourceFlags_SetTargetFolder_NonEmpty; - } - if (IsTempFiles) - { - transfer.Flags |= k_SourceFlags_TempFiles; - transfer.Flags |= k_SourceFlags_WaitFinish; - transfer.Flags |= k_SourceFlags_NeedExtractOpToFs; - if (UsePreGlobal) - transfer.Flags |= k_SourceFlags_NamesAreParent; - } - else - transfer.Flags |= k_SourceFlags_DoNotWaitFinish; - - if (IsRightButton) - transfer.Flags |= k_SourceFlags_RightButton; - else - transfer.Flags |= k_SourceFlags_LeftButton; - - if (DoNotProcessInTarget) - transfer.Flags |= k_SourceFlags_DoNotProcessInTarget; - if (Copy_WasCalled) - transfer.Flags |= k_SourceFlags_Copy_WasCalled; - - if (Medium_CopyFrom(medium, &transfer, sizeof(transfer))) - return S_OK; - return E_OUTOFMEMORY; - } - else - return DV_E_FORMATETC; - - if (!global) - return DV_E_FORMATETC; - medium->tymed = m_Etc.tymed; - medium->hGlobal = DuplicateGlobalMem(global); - if (!medium->hGlobal) - return E_OUTOFMEMORY; - return S_OK; - } catch(...) { return E_FAIL; } -} - -Z7_COMWF_B CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */) -{ - PRF3("CDataObject::GetDataHere()"); - // Seems Windows doesn't call it, so we will not implement it. - return E_UNEXPECTED; -} - - -/* - IDataObject::QueryGetData() Determines whether the data object is capable of - rendering the data as specified. Objects attempting a paste or drop - operation can call this method before calling IDataObject::GetData - to get an indication of whether the operation may be successful. - - The client of a data object calls QueryGetData to determine whether - passing the specified FORMATETC structure to a subsequent call to - IDataObject::GetData is likely to be successful. - - we check Try_QueryGetData with CF_HDROP -*/ - -Z7_COMWF_B CDataObject::QueryGetData(LPFORMATETC etc) -{ - PRF3("-- CDataObject::QueryGetData()"); - if ( etc->cfFormat == m_Etc.cfFormat // CF_HDROP - || etc->cfFormat == m_Format_7zip_GetTransfer - // || (etc->cfFormat == m_Format_FileOpFlags && (HGLOBAL)m_hGlobal_FileOpFlags) - // || (etc->cfFormat == m_Format_PreferredDropEffect && (HGLOBAL)m_hGlobal_PreferredDropEffect) - ) - { - } - else - return DV_E_FORMATETC; - if (etc->dwAspect != m_Etc.dwAspect) - return DV_E_DVASPECT; - /* GetData(): It is possible to specify more than one medium by using the Boolean OR - operator, allowing the method to choose the best medium among those specified. */ - if ((etc->tymed & m_Etc.tymed) == 0) - return DV_E_TYMED; - return S_OK; -} - -Z7_COMWF_B CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc) -{ - // we don't enumerate for DATADIR_SET. Seems it can work without it. - if (direction != DATADIR_GET) - return E_NOTIMPL; - // we don't enumerate for m_Format_FileOpFlags also. Seems it can work without it. - return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc); -} - - - -//////////////////////////////////////////////////////// - -class CDropSource Z7_final: - public IDropSource, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_1_MT(IDropSource) - STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState) Z7_override; - STDMETHOD(GiveFeedback)(DWORD effect) Z7_override; - - DWORD m_Effect; -public: - CDataObject *DataObjectSpec; - CMyComPtr DataObject; - - HRESULT DragProcessing_HRESULT; - bool DragProcessing_WasFinished; - - CDropSource(): - m_Effect(DROPEFFECT_NONE), - // Panel(NULL), - DragProcessing_HRESULT(S_OK), - DragProcessing_WasFinished(false) - {} -}; - -// static bool g_Debug = 0; - - -Z7_COMWF_B CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState) -{ - // try { - - /* Determines whether a drag-and-drop operation should be continued, canceled, or completed. - escapePressed : Indicates whether the Esc key has been pressed - since the previous call to QueryContinueDrag - or to DoDragDrop if this is the first call to QueryContinueDrag: - TRUE : the end user has pressed the escape key; - FALSE : it has not been pressed. - keyState : The current state of the keyboard modifier keys on the keyboard. - Possible values can be a combination of any of the flags: - MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON. - */ - #ifdef SHOW_DEBUG_DRAG - { - AString s ("CDropSource::QueryContinueDrag()"); - s.Add_Space(); - s += "keystate="; - s.Add_UInt32(keyState); - PRF4(s); - } - #endif - - /* - if ((keyState & MK_LBUTTON) == 0) - { - // PRF4("CDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) == 0"); - g_Debug = true; - } - else - { - // PRF4("CDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0"); - } - */ - - if (escapePressed) - { - // The drag operation should be canceled with no drop operation occurring. - DragProcessing_WasFinished = true; - DragProcessing_HRESULT = DRAGDROP_S_CANCEL; - return DRAGDROP_S_CANCEL; - } - - if (DragProcessing_WasFinished) - return DragProcessing_HRESULT; - - if ((keyState & MK_RBUTTON) != 0) - { - if (!DataObjectSpec->IsRightButton) - { - DragProcessing_WasFinished = true; - DragProcessing_HRESULT = DRAGDROP_S_CANCEL; - return DRAGDROP_S_CANCEL; - } - return S_OK; - } - - if ((keyState & MK_LBUTTON) != 0) - { - if (DataObjectSpec->IsRightButton) - { - DragProcessing_WasFinished = true; - DragProcessing_HRESULT = DRAGDROP_S_CANCEL; - return DRAGDROP_S_CANCEL; - } - /* The drag operation should continue. This result occurs if no errors are detected, - the mouse button starting the drag-and-drop operation has not been released, - and the Esc key has not been detected. */ - return S_OK; - } - { - // the mouse button starting the drag-and-drop operation has been released. - - /* Win10 probably calls DragOver()/GiveFeedback() just before LBUTTON releasing. - so m_Effect is effect returned by DropTarget::DragOver() - just before LBUTTON releasing. - So here we can use Effect sent to last GiveFeedback() */ - - if (m_Effect == DROPEFFECT_NONE) - { - DragProcessing_WasFinished = true; - DragProcessing_HRESULT = DRAGDROP_S_CANCEL; - // Drop target cannot accept the data. So we cancel drag and drop - // maybe return DRAGDROP_S_DROP also OK here ? - // return DRAGDROP_S_DROP; // for debug - return DRAGDROP_S_CANCEL; - } - - // we switch to real names for items that will be created in temp folder - DataObjectSpec->UsePreGlobal = false; - DataObjectSpec->Copy_HRESULT = S_OK; - // MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed); - /* - if (DataObjectSpec->IsRightButton) - return DRAGDROP_S_DROP; - */ - - if (DataObjectSpec->IsTempFiles) - { - if (!DataObjectSpec->DestDirPrefix_FromTarget.IsEmpty()) - { - /* we know the destination Path. - So we can copy or extract items later in Source with simpler code. */ - DataObjectSpec->DoNotProcessInTarget = true; - // return DRAGDROP_S_CANCEL; - } - else - { - DataObjectSpec->NeedCall_Copy = true; - /* - if (Copy_HRESULT != S_OK || !Messages.IsEmpty()) - { - DragProcessing_WasFinished = true; - DragProcessing_HRESULT = DRAGDROP_S_CANCEL; - return DRAGDROP_S_CANCEL; - } - */ - } - } - DragProcessing_HRESULT = DRAGDROP_S_DROP; - DragProcessing_WasFinished = true; - return DRAGDROP_S_DROP; - } - // } catch(...) { return E_FAIL; } -} - - -Z7_COMWF_B CDropSource::GiveFeedback(DWORD effect) -{ - // PRF3("CDropSource::GiveFeedback"); - /* Enables a source application to give visual feedback to the end user - during a drag-and-drop operation by providing the DoDragDrop function - with an enumeration value specifying the visual effect. - in (effect): - The DROPEFFECT value returned by the most recent call to - IDropTarget::DragEnter, - IDropTarget::DragOver, - or DROPEFFECT_NONE after IDropTarget::DragLeave. - 0: DROPEFFECT_NONE - 1: DROPEFFECT_COPY - 2: DROPEFFECT_MOVE - 4: DROPEFFECT_LINK - 0x80000000: DROPEFFECT_SCROLL - The dwEffect parameter can include DROPEFFECT_SCROLL, indicating that the - source should put up the drag-scrolling variation of the appropriate pointer. - */ - m_Effect = effect; - - #ifdef SHOW_DEBUG_DRAG - AString w ("GiveFeedback effect="); - if (effect & DROPEFFECT_SCROLL) - w += " SCROLL "; - w.Add_UInt32(effect & ~DROPEFFECT_SCROLL); - // if (g_Debug) - PRF4(w); - #endif - - /* S_OK : no special drag and drop cursors. - Maybe it's for case where we created custom custom cursors. - DRAGDROP_S_USEDEFAULTCURSORS: Indicates successful completion of the method, - and requests OLE to update the cursor using the OLE-provided default cursors. */ - // return S_OK; // for debug - return DRAGDROP_S_USEDEFAULTCURSORS; -} - - - -/* -static bool Global_SetUInt32(NMemory::CGlobal &hg, const UInt32 v) -{ - if (!hg.Alloc(GHND | GMEM_SHARE, sizeof(v))) - return false; - NMemory::CGlobalLock dropLock(hg); - *(UInt32 *)dropLock.GetPointer() = v; - return true; -} -*/ - -static bool CopyNamesToHGlobal(NMemory::CGlobal &hgDrop, const UStringVector &names) -{ - size_t totalLen = 1; - - #ifndef _UNICODE - if (!g_IsNT) - { - AStringVector namesA; - unsigned i; - for (i = 0; i < names.Size(); i++) - namesA.Add(GetSystemString(names[i])); - for (i = 0; i < namesA.Size(); i++) - totalLen += namesA[i].Len() + 1; - - if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLen * sizeof(CHAR) + sizeof(DROPFILES))) - return false; - - NMemory::CGlobalLock dropLock(hgDrop); - DROPFILES *dropFiles = (DROPFILES *)dropLock.GetPointer(); - if (!dropFiles) - return false; - dropFiles->fNC = FALSE; - dropFiles->pt.x = 0; - dropFiles->pt.y = 0; - dropFiles->pFiles = sizeof(DROPFILES); - dropFiles->fWide = FALSE; - CHAR *p = (CHAR *) (void *) ((BYTE *)dropFiles + sizeof(DROPFILES)); - for (i = 0; i < namesA.Size(); i++) - { - const AString &s = namesA[i]; - const unsigned fullLen = s.Len() + 1; - MyStringCopy(p, (const char *)s); - p += fullLen; - totalLen -= fullLen; - } - *p = 0; - } - else - #endif - { - unsigned i; - for (i = 0; i < names.Size(); i++) - totalLen += names[i].Len() + 1; - - if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLen * sizeof(WCHAR) + sizeof(DROPFILES))) - return false; - - NMemory::CGlobalLock dropLock(hgDrop); - DROPFILES *dropFiles = (DROPFILES *)dropLock.GetPointer(); - if (!dropFiles) - return false; - /* fNC: - TRUE : pt specifies the screen coordinates of a point in a window's nonclient area. - FALSE : pt specifies the client coordinates of a point in the client area. - */ - dropFiles->fNC = FALSE; - dropFiles->pt.x = 0; - dropFiles->pt.y = 0; - dropFiles->pFiles = sizeof(DROPFILES); - dropFiles->fWide = TRUE; - WCHAR *p = (WCHAR *) (void *) ((BYTE *)dropFiles + sizeof(DROPFILES)); - for (i = 0; i < names.Size(); i++) - { - const UString &s = names[i]; - const unsigned fullLen = s.Len() + 1; - MyStringCopy(p, (const WCHAR *)s); - p += fullLen; - totalLen -= fullLen; - } - *p = 0; - } - // if (totalLen != 1) return false; - return true; -} - - -void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */, bool isRightButton) -{ - PRF("CPanel::OnDrag"); - if (!DoesItSupportOperations()) - return; - - CDisableTimerProcessing disableTimerProcessing2(*this); - - CRecordVector indices; - Get_ItemIndices_Operated(indices); - if (indices.Size() == 0) - return; - - // CSelectedState selState; - // SaveSelectedState(selState); - - const bool isFSFolder = IsFSFolder(); - // why we don't allow drag with rightButton from archive? - if (!isFSFolder && isRightButton) - return; - - UString dirPrefix; - CTempDir tempDirectory; - - CDataObject *dataObjectSpec = new CDataObject; - CMyComPtr dataObject = dataObjectSpec; - dataObjectSpec->IsRightButton = isRightButton; - - { - /* we can change confirmation mode and another options. - Explorer target requests that FILEOP_FLAGS value. */ - /* - const FILEOP_FLAGS fopFlags = - FOF_NOCONFIRMATION - | FOF_NOCONFIRMMKDIR - | FOF_NOERRORUI - | FOF_SILENT; - // | FOF_SIMPLEPROGRESS; // it doesn't work as expected in Win10 - Global_SetUInt32(dataObjectSpec->m_hGlobal_FileOpFlags, fopFlags); - // dataObjectSpec->m_hGlobal_FileOpFlags.Free(); // for debug : disable these options - */ - } - { - /* we can change Preferred DropEffect. - Explorer target requests that FILEOP_FLAGS value. */ - /* - const DWORD effect = DROPEFFECT_MOVE; // DROPEFFECT_COPY; - Global_SetUInt32(dataObjectSpec->m_hGlobal_PreferredDropEffect, effect); - */ - } - if (isFSFolder) - { - dirPrefix = GetFsPath(); // why this in 22.01 ? - dataObjectSpec->UsePreGlobal = false; - // dataObjectSpec->IsTempFiles = false; - } - else - { - if (!tempDirectory.Create(kTempDirPrefix)) - { - MessageBox_Error(L"Can't create temp folder"); - return; - } - dirPrefix = fs2us(tempDirectory.GetPath()); - { - UStringVector names; - names.Add(dirPrefix); - dataObjectSpec->IsTempFiles = true; - dataObjectSpec->UsePreGlobal = true; - if (!CopyNamesToHGlobal(dataObjectSpec->m_hGlobal_HDROP_Pre, names)) - return; - } - NFile::NName::NormalizeDirPathPrefix(dirPrefix); - /* - { - FString path2 = dirPrefix; - path2 += "1.txt"; - CopyFileW(L"C:\\1\\1.txt", path2, FALSE); - } - */ - } - - { - UStringVector names; - // names variable is USED for drag and drop from 7-zip to Explorer or to 7-zip archive folder. - // names variable is NOT USED for drag and drop from 7-zip to 7-zip File System folder. - FOR_VECTOR (i, indices) - { - const UInt32 index = indices[i]; - UString s; - if (isFSFolder) - s = GetItemRelPath(index); - else - { - s = GetItemName(index); - /* - // We use (keepAndReplaceEmptyPrefixes = true) in CAgentFolder::Extract - // So the following code is not required. - // Maybe we also can change IFolder interface and send some flag also. - if (s.IsEmpty()) - { - // Correct_FsFile_Name("") returns "_". - // If extracting code removes empty folder prefixes from path (as it was in old version), - // Explorer can't find "_" folder in temp folder. - // We can ask Explorer to copy parent temp folder "7zE" instead. - names.Clear(); - names.Add(dirPrefix2); - break; - } - */ - s = Get_Correct_FsFile_Name(s); - } - names.Add(dirPrefix + s); - } - if (!CopyNamesToHGlobal(dataObjectSpec->m_hGlobal_HDROP_Final, names)) - return; - } - - CDropSource *dropSourceSpec = new CDropSource; - CMyComPtr dropSource = dropSourceSpec; - dataObjectSpec->Panel = this; - dataObjectSpec->Indices = indices; - dataObjectSpec->SrcDirPrefix_Temp = dirPrefix; - - dropSourceSpec->DataObjectSpec = dataObjectSpec; - dropSourceSpec->DataObject = dataObjectSpec; - - - /* - CTime - file creation timestamp. - There are two operations in Windows with Drag and Drop: - COPY_OPERATION : icon with Plus sign : CTime will be set as current_time. - MOVE_OPERATION : icon without Plus sign : CTime will be preserved. - - Note: if we call DoDragDrop() with (effectsOK = DROPEFFECT_MOVE), then - it will use MOVE_OPERATION and CTime will be preserved. - But MoveFile() function doesn't preserve CTime, if different volumes are used. - Why it's so? - Does DoDragDrop() use some another function (not MoveFile())? - - if (effectsOK == DROPEFFECT_COPY) it works as COPY_OPERATION - - if (effectsOK == DROPEFFECT_MOVE) drag works as MOVE_OPERATION - - if (effectsOK == (DROPEFFECT_COPY | DROPEFFECT_MOVE)) - { - if we drag file to same volume, then Windows suggests: - CTRL - COPY_OPERATION - [default] - MOVE_OPERATION - - if we drag file to another volume, then Windows suggests - [default] - COPY_OPERATION - SHIFT - MOVE_OPERATION - } - - We want to use MOVE_OPERATION for extracting from archive (open in 7-Zip) to Explorer: - It has the following advantages: - 1) it uses fast MOVE_OPERATION instead of slow COPY_OPERATION and DELETE, if same volume. - 2) it preserves CTime - - Some another programs support only COPY_OPERATION. - So we can use (DROPEFFECT_COPY | DROPEFFECT_MOVE) - - Also another program can return from DoDragDrop() before - files using. But we delete temp folder after DoDragDrop(), - and another program can't open input files in that case. - - We create objects: - IDropSource *dropSource - IDataObject *dataObject - if DropTarget is 7-Zip window, then 7-Zip's - IDropTarget::DragOver() sets DestDirPrefix_FromTarget in IDataObject. - and - IDropSource::QueryContinueDrag() sets DoNotProcessInTarget, if DestDirPrefix_FromTarget is not empty. - So we can detect destination path after DoDragDrop(). - Now we don't know any good way to detect destination path for D&D to Explorer. - */ - - /* - DWORD effectsOK = DROPEFFECT_COPY; - if (moveIsAllowed) - effectsOK |= DROPEFFECT_MOVE; - */ - const bool moveIsAllowed = isFSFolder; - _panelCallback->DragBegin(); - PRF("=== DoDragDrop()"); - DWORD effect = 0; - // 18.04: was changed - const DWORD effectsOK = DROPEFFECT_MOVE | DROPEFFECT_COPY; - // effectsOK |= (1 << 8); // for debug - HRESULT res = ::DoDragDrop(dataObject, dropSource, effectsOK, &effect); - PRF("=== After DoDragDrop()"); - _panelCallback->DragEnd(); - - /* - Win10 drag and drop to Explorer: - DoDragDrop() output variables: - for MOVE operation: - { - effect == DROPEFFECT_NONE; - dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_MOVE; - } - for COPY operation: - { - effect == DROPEFFECT_COPY; - dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_COPY; - } - DOCs: The source inspects the two values that can be returned by the target. - If both are set to DROPEFFECT_MOVE, it completes the unoptimized move - by deleting the original data. Otherwise, the target did an optimized - move and the original data has been deleted. - - We didn't see "unoptimized move" case (two values of DROPEFFECT_MOVE), - where we still need to delete source files. - So we don't delete files after DoDragDrop(). - - Also DOCs say for "optimized move": - The target also calls the data object's IDataObject::SetData method and passes - it a CFSTR_PERFORMEDDROPEFFECT format identifier set to DROPEFFECT_NONE. - but actually in Win10 we always have - (dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_MOVE) - for any MOVE operation. - */ - - const bool canceled = (res == DRAGDROP_S_CANCEL); - - CDisableNotify disableNotify(*this); - - if (res == DRAGDROP_S_DROP) - { - /* DRAGDROP_S_DROP is returned. It means that - - IDropTarget::Drop() was called, - - IDropTarget::Drop() returned (ret_code >= 0) - */ - res = dataObjectSpec->Copy_HRESULT; - bool need_Process = dataObjectSpec->DoNotProcessInTarget; - if (dataObjectSpec->m_Transfer_WasSet) - { - if (dataObjectSpec->m_Transfer.Target.FuncType == k_DragTargetMode_Drop_End) - { - if (dataObjectSpec->m_Transfer.Target.Flags & k_TargetFlags_MustBeProcessedBySource) - need_Process = true; - } - } - - if (need_Process) - if (!dataObjectSpec->DestDirPrefix_FromTarget.IsEmpty()) - { - if (!NFile::NName::IsAltStreamPrefixWithColon(dataObjectSpec->DestDirPrefix_FromTarget)) - NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->DestDirPrefix_FromTarget); - CCopyToOptions options; - options.folder = dataObjectSpec->DestDirPrefix_FromTarget; - // if MOVE is not allowed, we just use COPY operation - /* it was 7-zip's Target that set non-empty dataObjectSpec->DestDirPrefix_FromTarget. - it means that target didn't completed operation, - and we can use (effect) value returned by target via DoDragDrop(). - as indicator of type of operation - */ - // options.moveMode = (moveIsAllowed && effect == DROPEFFECT_MOVE) // before v23.00: - options.moveMode = moveIsAllowed; - if (moveIsAllowed) - { - if (dataObjectSpec->m_Transfer_WasSet) - options.moveMode = ( - dataObjectSpec->m_Transfer.Target.Cmd_Effect == DROPEFFECT_MOVE); - else - options.moveMode = (effect == DROPEFFECT_MOVE); - // we expect (DROPEFFECT_MOVE) as indicator of move operation for Drag&Drop MOVE ver 22.01. - } - res = CopyTo(options, indices, &dataObjectSpec->Messages); - } - /* - if (effect & DROPEFFECT_MOVE) - RefreshListCtrl(selState); - */ - } - else - { - // we ignore E_UNEXPECTED that is returned if we drag file to printer - if (res != DRAGDROP_S_CANCEL - && res != S_OK - && res != E_UNEXPECTED) - MessageBox_Error_HRESULT(res); - res = dataObjectSpec->Copy_HRESULT; - } - - if (!dataObjectSpec->Messages.IsEmpty()) - { - CMessagesDialog messagesDialog; - messagesDialog.Messages = &dataObjectSpec->Messages; - messagesDialog.Create((*this)); - } - - if (res != S_OK && res != E_ABORT) - { - // we restore Notify before MessageBox_Error_HRESULT. So we will see files selection - disableNotify.Restore(); - // SetFocusToList(); - MessageBox_Error_HRESULT(res); - } - if (res == S_OK && dataObjectSpec->Messages.IsEmpty() && !canceled) - KillSelection(); -} - - - - - -CDropTarget::CDropTarget(): - m_IsRightButton(false), - m_GetTransfer_WasSuccess(false), - m_DropIsAllowed(false), - m_PanelDropIsAllowed(false), - // m_DropHighlighted_SelectionIndex(-1), - // m_SubFolderIndex(-1), - m_Panel(NULL), - m_IsAppTarget(false), - m_TargetPath_WasSent_ToDataObject(false), - m_TargetPath_NonEmpty_WasSent_ToDataObject(false), - m_Transfer_WasSent_ToDataObject(false), - App(NULL), - SrcPanelIndex(-1), - TargetPanelIndex(-1) -{ - m_Format_7zip_SetTargetFolder = RegisterClipboardFormat(k_Format_7zip_SetTargetFolder); - m_Format_7zip_SetTransfer = RegisterClipboardFormat(k_Format_7zip_SetTransfer); - m_Format_7zip_GetTransfer = RegisterClipboardFormat(k_Format_7zip_GetTransfer); - - m_ProcessId = GetCurrentProcessId(); - // m_TransactionId = ((UInt64)m_ProcessId << 32) + 1; - // ClearState(); -} - -// clear internal state -void CDropTarget::ClearState() -{ - m_DataObject.Release(); - m_SourcePaths.Clear(); - - m_IsRightButton = false; - - m_GetTransfer_WasSuccess = false; - m_DropIsAllowed = false; - - m_PanelDropIsAllowed = false; - // m_SubFolderIndex = -1; - // m_DropHighlighted_SubFolderName.Empty(); - m_Panel = NULL; - m_IsAppTarget = false; - m_TargetPath_WasSent_ToDataObject = false; - m_TargetPath_NonEmpty_WasSent_ToDataObject = false; - m_Transfer_WasSent_ToDataObject = false; -} - -/* - IDataObject::QueryGetData() Determines whether the data object is capable of - rendering the data as specified. Objects attempting a paste or drop - operation can call this method before calling IDataObject::GetData - to get an indication of whether the operation may be successful. - - The client of a data object calls QueryGetData to determine whether - passing the specified FORMATETC structure to a subsequent call to - IDataObject::GetData is likely to be successful. - - We check Try_QueryGetData with CF_HDROP -*/ -/* -void CDropTarget::Try_QueryGetData(IDataObject *dataObject) -{ - FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK); -} -*/ - -static void ListView_SetItemState_DropHighlighted( - NControl::CListView &listView, int index, bool highlighted) -{ - // LVIS_DROPHILITED : The item is highlighted as a drag-and-drop target - /* - LVITEM item; - item.mask = LVIF_STATE; - item.iItem = index; - item.iSubItem = 0; - item.state = enable ? LVIS_DROPHILITED : 0; - item.stateMask = LVIS_DROPHILITED; - item.pszText = NULL; - listView.SetItem(&item); - */ - listView.SetItemState(index, highlighted ? LVIS_DROPHILITED : 0, LVIS_DROPHILITED); -} - -// Removes DropHighlighted state in ListView item, if it was set before -void CDropTarget::RemoveSelection() -{ - if (m_Panel) - { - m_Panel->m_DropHighlighted_SubFolderName.Empty(); - if (m_Panel->m_DropHighlighted_SelectionIndex >= 0) - { - ListView_SetItemState_DropHighlighted(m_Panel->_listView, - m_Panel->m_DropHighlighted_SelectionIndex, false); - m_Panel->m_DropHighlighted_SelectionIndex = -1; - } - } -} - -#ifdef UNDER_CE -#define ChildWindowFromPointEx(hwndParent, pt, uFlags) ChildWindowFromPoint(hwndParent, pt) -#endif - - -/* - PositionCursor() function sets m_Panel under cursor drop, and - m_SubFolderIndex/m_DropHighlighted_SubFolderName, if drop to some folder in Panel list. -*/ -/* -PositionCursor() uses as input variables: - m_DropIsAllowed must be set before PositionCursor() - if (m_DropHighlighted_SelectionIndex >= 0 && m_Panel) it uses m_Panel and removes previous selection -PositionCursor() sets - m_PanelDropIsAllowed - m_Panel - m_IsAppTarget - m_SubFolderIndex - m_DropHighlighted_SubFolderName - m_DropHighlighted_SelectionIndex -*/ -void CDropTarget::PositionCursor(const POINTL &ptl) -{ - RemoveSelection(); - - // m_SubFolderIndex = -1; - // m_DropHighlighted_SubFolderName.Empty(); - m_IsAppTarget = true; - m_Panel = NULL; - m_PanelDropIsAllowed = false; - - if (!m_DropIsAllowed) - return; - - POINT pt; - pt.x = ptl.x; - pt.y = ptl.y; - { - POINT pt2 = pt; - if (App->_window.ScreenToClient(&pt2)) - for (unsigned i = 0; i < kNumPanelsMax; i++) - if (App->IsPanelVisible(i)) - { - CPanel *panel = &App->Panels[i]; - if (panel->IsEnabled()) - if (::ChildWindowFromPointEx(App->_window, pt2, - CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) == (HWND)*panel) - { - m_Panel = panel; - m_IsAppTarget = false; - if ((int)i == SrcPanelIndex) - return; // we don't allow to drop to source panel - break; - } - } - } - - m_PanelDropIsAllowed = true; - - if (!m_Panel) - { - if (TargetPanelIndex >= 0) - m_Panel = &App->Panels[TargetPanelIndex]; - // we don't need to find item in panel - return; - } - - // we will try to find and highlight drop folder item in listView under cursor - /* - m_PanelDropIsAllowed = m_Panel->DoesItSupportOperations(); - if (!m_PanelDropIsAllowed) - return; - */ - /* now we don't allow drop to subfolder under cursor, if dest panel is archive. - Another code must be fixed for that case, where we must use m_SubFolderIndex/m_DropHighlighted_SubFolderName */ - if (!m_Panel->IsFsOrPureDrivesFolder()) - return; - - if (::WindowFromPoint(pt) != (HWND)m_Panel->_listView) - return; - - LVHITTESTINFO info; - m_Panel->_listView.ScreenToClient(&pt); - info.pt = pt; - const int index = ListView_HitTest(m_Panel->_listView, &info); - if (index < 0) - return; - const unsigned realIndex = m_Panel->GetRealItemIndex(index); - if (realIndex == kParentIndex) - return; - if (!m_Panel->IsItem_Folder(realIndex)) - return; - // m_SubFolderIndex = (int)realIndex; - m_Panel->m_DropHighlighted_SubFolderName = m_Panel->GetItemName(realIndex); - ListView_SetItemState_DropHighlighted(m_Panel->_listView, index, true); - m_Panel->m_DropHighlighted_SelectionIndex = index; -} - - -/* returns true, if !m_IsAppTarget - and target is FS folder or altStream folder -*/ - -UInt32 CDropTarget::GetFolderType() const -{ - if (m_IsAppTarget || !m_Panel) - return k_FolderType_None; - if (m_Panel->IsFSFolder() || - (m_Panel->IsFSDrivesFolder() - && m_Panel->m_DropHighlighted_SelectionIndex >= 0)) - return k_FolderType_Fs; - if (m_Panel->IsAltStreamsFolder()) - return k_FolderType_AltStreams; - if (m_Panel->IsArcFolder()) - return k_FolderType_Archive; - return k_FolderType_Unknown; -} - -bool CDropTarget::IsFsFolderPath() const -{ - if (m_IsAppTarget || !m_Panel) - return false; - if (m_Panel->IsFSFolder()) - return true; - if (m_Panel->IsAltStreamsFolder()) - return true; - return m_Panel->IsFSDrivesFolder() && - m_Panel->m_DropHighlighted_SelectionIndex >= 0; -} - - -#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } - -static bool DataObject_GetData_GetTransfer(IDataObject *dataObject, - UINT a_Format_7zip_GetTransfer, CDataObject_GetTransfer &transfer) -{ - FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)a_Format_7zip_GetTransfer); - NCOM::CStgMedium medium; - const HRESULT res = dataObject->GetData(&etc, &medium); - if (res != S_OK) - return false; - if (medium.tymed != TYMED_HGLOBAL) - return false; - const size_t size = GlobalSize(medium.hGlobal); - if (size < sizeof(transfer)) - return false; - NMemory::CGlobalLock dropLock(medium.hGlobal); - const CDataObject_GetTransfer *t = (const CDataObject_GetTransfer *)dropLock.GetPointer(); - if (!t) - return false; - if (!t->Check()) // isSetData - return false; - transfer = *t; - return true; -} - -/* - returns true, if all m_SourcePaths[] items are same drive - as destination drop path in m_Panel -*/ -bool CDropTarget::IsItSameDrive() const -{ - if (!m_Panel) - return false; - if (!IsFsFolderPath()) - return false; - - UString drive; - - if (m_Panel->IsFSFolder()) - { - drive = m_Panel->GetDriveOrNetworkPrefix(); - if (drive.IsEmpty()) - return false; - } - else if (m_Panel->IsFSDrivesFolder() - && m_Panel->m_DropHighlighted_SelectionIndex >= 0) - { - drive = m_Panel->m_DropHighlighted_SubFolderName; - drive.Add_PathSepar(); - } - else - return false; - - if (m_SourcePaths.Size() == 0) - return false; - - FOR_VECTOR (i, m_SourcePaths) - { - if (!m_SourcePaths[i].IsPrefixedBy_NoCase(drive)) - return false; - } - return true; -} - - -/* - There are 2 different actions, when we drag to 7-Zip: - 1) if target panel is "7-Zip" FS and any of the 2 cases: - - Drag from any non "7-Zip" program; - or - - Drag from "7-Zip" to non-panel area of "7-Zip". - We want to create new archive for that operation with "Add to Archive" window. - 2) all another operations work as usual file COPY/MOVE - - Drag from "7-Zip" FS to "7-Zip" FS. - COPY/MOVE are supported. - - Drag to open archive in 7-Zip. - We want to update archive. - We replace COPY to MOVE. - - Drag from "7-Zip" archive to "7-Zip" FS. - We replace COPY to MOVE. -*/ - -// we try to repeat Explorer's effects. -// out: 0 - means that use default effect -static DWORD GetEffect_ForKeys(DWORD keyState) -{ - if (keyState & MK_CONTROL) - { - if (keyState & MK_ALT) - return 0; - if (keyState & MK_SHIFT) - return DROPEFFECT_LINK; // CONTROL + SHIFT - return DROPEFFECT_COPY; // CONTROL - } - // no CONTROL - if (keyState & MK_SHIFT) - { - if (keyState & MK_ALT) - return 0; - return DROPEFFECT_MOVE; // SHIFT - } - // no CONTROL, no SHIFT - if (keyState & MK_ALT) - return DROPEFFECT_LINK; // ALT - return 0; -} - - -/* GetEffect() uses m_TargetPath_WasSentToDataObject - to disale MOVE operation, if Source is not 7-Zip -*/ -DWORD CDropTarget::GetEffect(DWORD keyState, POINTL /* pt */, DWORD allowedEffect) const -{ - // (DROPEFFECT_NONE == 0) - if (!m_DropIsAllowed || !m_PanelDropIsAllowed) - return 0; - if (!IsFsFolderPath() || !m_TargetPath_WasSent_ToDataObject) - { - // we don't allow MOVE, if Target is archive or Source is not 7-Zip - // disabled for debug: - // allowedEffect &= ~DROPEFFECT_MOVE; - } - DWORD effect; - { - effect = GetEffect_ForKeys(keyState); - if (effect == DROPEFFECT_LINK) - return 0; - effect &= allowedEffect; - } - if (effect == 0) - { - if (allowedEffect & DROPEFFECT_COPY) - effect = DROPEFFECT_COPY; - if (allowedEffect & DROPEFFECT_MOVE) - { - /* MOVE operation can be optimized. So MOVE is preferred way - for default action, if Source and Target are at same drive */ - if (IsItSameDrive()) - effect = DROPEFFECT_MOVE; - } - } - return effect; -} - - -/* returns: - - target folder path prefix, if target is FS folder - - empty string, if target is not FS folder -*/ -UString CDropTarget::GetTargetPath() const -{ - if (!IsFsFolderPath()) - return UString(); - UString path = m_Panel->GetFsPath(); - if (/* m_SubFolderIndex >= 0 && */ - !m_Panel->m_DropHighlighted_SubFolderName.IsEmpty()) - { - path += m_Panel->m_DropHighlighted_SubFolderName; - path.Add_PathSepar(); - } - return path; -} - - -/* -if IDropSource is Win10-Explorer --------------------------------- - As in MS DOCs: - The source inspects the two (effect) values that can be returned by the target: - 1) SetData(CFSTR_PERFORMEDDROPEFFECT) - 2) returned value (*effect) by - CDropTarget::Drop(IDataObject *dataObject, DWORD keyState, - POINTL pt, DWORD *effect) - If both are set to DROPEFFECT_MOVE, Explorer completes the unoptimized move by deleting - the original data. - // Otherwise, the target did an optimized move and the original data has been deleted. -*/ - - -/* - Send targetPath from target to dataObject (to Source) - input: set (enablePath = false) to send empty path - returns true, if SetData() returns S_OK : (source is 7-zip) - returns false, if SetData() doesn't return S_OK : (source is Explorer) -*/ -bool CDropTarget::SendToSource_TargetPath_enable(IDataObject *dataObject, bool enablePath) -{ - m_TargetPath_NonEmpty_WasSent_ToDataObject = false; - UString path; - if (enablePath) - path = GetTargetPath(); - PRF("CDropTarget::SetPath"); - PRF_W(path); - if (!dataObject || m_Format_7zip_SetTargetFolder == 0) - return false; - FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)m_Format_7zip_SetTargetFolder); - STGMEDIUM medium; - medium.tymed = etc.tymed; - medium.pUnkForRelease = NULL; - const size_t num = path.Len() + 1; // + (1 << 19) // for debug - medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, num * sizeof(wchar_t)); - if (!medium.hGlobal) - return false; - // Sleep(1000); - wchar_t *dest = (wchar_t *)GlobalLock(medium.hGlobal); - // Sleep(1000); - bool res = false; - if (dest) - { - MyStringCopy(dest, (const wchar_t *)path); - GlobalUnlock(medium.hGlobal); - // OutputDebugString("m_DataObject->SetData"); - const BOOL release = FALSE; // that way is more simple for correct releasing. - // TRUE; // for debug : is not good for some cases. - /* If DropSource is Win10-Explorer, dataObject->SetData() returns E_NOTIMPL; */ - const HRESULT hres = dataObject->SetData(&etc, &medium, release); - // Sleep(1000); - res = (hres == S_OK); - } - - ReleaseStgMedium(&medium); - if (res && !path.IsEmpty()) - m_TargetPath_NonEmpty_WasSent_ToDataObject = true; - // Sleep(1000); - return res; -} - - -void CDropTarget::SendToSource_auto(IDataObject *dataObject, - const CTargetTransferInfo &info) -{ - /* we try to send target path to Source. - If Source is 7-Zip, then it will accept k_Format_7zip_SetTargetFolder. - That sent path will be non-Empty, if this target is FS folder and drop is allowed */ - bool need_Send = false; - if ( info.FuncType == k_DragTargetMode_Enter - || info.FuncType == k_DragTargetMode_Over - || (info.FuncType == k_DragTargetMode_Drop_Begin - // && targetOp_Cmd != NDragMenu::k_None - && info.Cmd_Type != NDragMenu::k_Cancel)) - // if (!g_CreateArchive_for_Drag_from_7zip) - need_Send = m_DropIsAllowed && m_PanelDropIsAllowed && IsFsFolderPath(); - m_TargetPath_WasSent_ToDataObject = SendToSource_TargetPath_enable(dataObject, need_Send); - SendToSource_TransferInfo(dataObject, info); -} - - -bool CDropTarget::SendToSource_TransferInfo(IDataObject *dataObject, - const CTargetTransferInfo &info) -{ - m_Transfer_WasSent_ToDataObject = false; - PRF("CDropTarget::SendToSource_TransferInfo"); - - if (!dataObject || m_Format_7zip_SetTransfer == 0) - return false; - FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)m_Format_7zip_SetTransfer); - STGMEDIUM medium; - medium.tymed = etc.tymed; - medium.pUnkForRelease = NULL; - CDataObject_SetTransfer transfer; - const size_t size = sizeof(transfer); // + (1 << 19) // for debug - // OutputDebugString("GlobalAlloc"); - medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); - // Sleep(1000); - if (!medium.hGlobal) - return false; - // OutputDebugString("GlobalLock"); - void *dest = (wchar_t *)GlobalLock(medium.hGlobal); - // Sleep(1000); - bool res = false; - if (dest) - { - transfer.Init(); - transfer.Target = info; - - memcpy(dest, &transfer, sizeof(transfer)); - GlobalUnlock(medium.hGlobal); - // OutputDebugString("m_DataObject->SetData"); - const BOOL release = FALSE; // that way is more simple for correct releasing. - // TRUE; // for debug : is not good for some cases - const HRESULT hres = dataObject->SetData(&etc, &medium, release); - res = (hres == S_OK); - } - - ReleaseStgMedium(&medium); - if (res) - m_Transfer_WasSent_ToDataObject = true; - return res; -} - - -bool CDropTarget::SendToSource_UInt32(IDataObject *dataObject, UINT format, UInt32 value) -{ - PRF("CDropTarget::Send_UInt32 (Performed)"); - - if (!dataObject || format == 0) - return false; - FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)format); - STGMEDIUM medium; - medium.tymed = etc.tymed; - medium.pUnkForRelease = NULL; - const size_t size = 4; - medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); - if (!medium.hGlobal) - return false; - void *dest = GlobalLock(medium.hGlobal); - bool res = false; - if (dest) - { - *(UInt32 *)dest = value; - GlobalUnlock(medium.hGlobal); - // OutputDebugString("m_DataObject->SetData"); - const BOOL release = TRUE; - // FALSE; // for debug - /* If DropSource is Win10-Explorer, then (release == FALSE) doesn't work - and dataObject->SetData() returns E_NOTIMPL; - So we use release = TRUE; here */ - const HRESULT hres = dataObject->SetData(&etc, &medium, release); - // we return here without calling ReleaseStgMedium(). - return (hres == S_OK); - // Sleep(1000); - /* - if (we use release = TRUE), we expect that - - SetData() will release medium, and - - SetData() will set STGMEDIUM::tymed to (TYMED_NULL = 0). - but some "incorrect" SetData() implementations can keep STGMEDIUM::tymed unchanged. - And it's not safe to call ReleaseStgMedium() here for that case, - because DropSource also could release medium. - We can reset (medium.tymed = TYMED_NULL) manually here to disable - unsafe medium releasing in ReleaseStgMedium(). - */ - /* - if (release) - { - medium.tymed = TYMED_NULL; - medium.pUnkForRelease = NULL; - medium.hGlobal = NULL; - } - res = (hres == S_OK); - */ - } - ReleaseStgMedium(&medium); - return res; -} - - -void CDropTarget::LoadNames_From_DataObject(IDataObject *dataObject) -{ - // "\\\\.\\" prefix is possible for long names - m_DropIsAllowed = NShell::DataObject_GetData_HDROP_or_IDLIST_Names(dataObject, m_SourcePaths) == S_OK; -} - - -Z7_COMWF_B CDropTarget::DragEnter(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) -{ - /* *(effect): - - on input : value of the dwOKEffects parameter of the DoDragDrop() function. - - on return : must contain one of the DROPEFFECT flags, which indicates - what the result of the drop operation would be. - (pt): the current cursor coordinates in screen coordinates. - */ - PRF_(Print_Point("CDropTarget::DragEnter", keyState, pt, *effect)) - try { - - if ((keyState & (MK_RBUTTON | MK_MBUTTON)) != 0) - m_IsRightButton = true; - - LoadNames_From_DataObject(dataObject); - // Try_QueryGetData(dataObject); - // we will use (m_DataObject) later in DragOver() and DragLeave(). - m_DataObject = dataObject; - // return DragOver(keyState, pt, effect); - PositionCursor(pt); - CTargetTransferInfo target; - target.FuncType = k_DragTargetMode_Enter; - target.KeyState = keyState; - target.Point = pt; - target.OkEffects = *effect; - SendToSource_Drag(target); - - CDataObject_GetTransfer transfer; - m_GetTransfer_WasSuccess = DataObject_GetData_GetTransfer( - dataObject, m_Format_7zip_GetTransfer, transfer); - if (m_GetTransfer_WasSuccess) - { - if (transfer.Flags & k_SourceFlags_LeftButton) - m_IsRightButton = false; - else if (transfer.Flags & k_SourceFlags_RightButton) - m_IsRightButton = true; - } - - *effect = GetEffect(keyState, pt, *effect); - return S_OK; - } catch(...) { return E_FAIL; } -} - - -Z7_COMWF_B CDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD *effect) -{ - PRF_(Print_Point("CDropTarget::DragOver", keyState, pt, *effect)) - /* - For efficiency reasons, a data object is not passed in IDropTarget::DragOver. - The data object passed in the most recent call to IDropTarget::DragEnter - is available and can be used. - - When IDropTarget::DragOver has completed its operation, the DoDragDrop - function calls IDropSource::GiveFeedback so the source application can display - the appropriate visual feedback to the user. - */ - /* - we suppose that it's unexpected that (keyState) shows that mouse - button is not pressed, because such cases will be processed by - IDropSource::QueryContinueDrag() that returns DRAGDROP_S_DROP or DRAGDROP_S_CANCEL. - So DragOver() will not be called. - */ - - if ((keyState & MK_LBUTTON) == 0) - { - PRF4("CDropTarget::DragOver() (keyState & MK_LBUTTON) == 0"); - // g_Debug = true; - } - - try { - /* we suppose that source names were not changed after DragEnter() - so we don't request GetNames_From_DataObject() for each call of DragOver() */ - PositionCursor(pt); - CTargetTransferInfo target; - target.FuncType = k_DragTargetMode_Over; - target.KeyState = keyState; - target.Point = pt; - target.OkEffects = *effect; - SendToSource_Drag(target); - *effect = GetEffect(keyState, pt, *effect); - // *effect = 1 << 8; // for debug - return S_OK; - } catch(...) { return E_FAIL; } -} - - -Z7_COMWF_B CDropTarget::DragLeave() -{ - PRF4("CDropTarget::DragLeave"); - try { - RemoveSelection(); - // we send empty TargetPath to 7-Zip Source to clear value of TargetPath that was sent before - - CTargetTransferInfo target; - target.FuncType = k_DragTargetMode_Leave; - /* - target.KeyState = 0; - target.Point = pt; - pt.x = 0; // -1 - pt.y = 0; // -1 - target.Effect = 0; - */ - SendToSource_Drag(target); - ClearState(); - return S_OK; - } catch(...) { return E_FAIL; } -} - - -static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags); - -/* - We suppose that there was DragEnter/DragOver for same (POINTL pt) before Drop(). - But we can work without DragEnter/DragOver too. -*/ -Z7_COMWF_B CDropTarget::Drop(IDataObject *dataObject, DWORD keyState, - POINTL pt, DWORD *effect) -{ - PRF_(Print_Point("CDropTarget::Drop", keyState, pt, *effect)) - /* Drop() is called after SourceDrop::QueryContinueDrag() returned DRAGDROP_S_DROP. - So it's possible that Source have done some operations already. - */ - HRESULT hres = S_OK; - bool needDrop_by_Source = false; - DWORD opEffect = DROPEFFECT_NONE; - - try { - // we don't need m_DataObject reference anymore, because we use local (dataObject) - m_DataObject.Release(); - - /* in normal case : we called LoadNames_From_DataObject() in DragEnter() already. - But if by some reason DragEnter() was not called, - we need to call LoadNames_From_DataObject() before PositionCursor(). - */ - if (!m_DropIsAllowed) LoadNames_From_DataObject(dataObject); - PositionCursor(pt); - - CPanel::CDisableTimerProcessing2 disableTimerProcessing(m_Panel); - // CDisableNotify disableNotify2(m_Panel); - - UInt32 cmd = NDragMenu::k_None; - UInt32 cmdEffect = DROPEFFECT_NONE; - bool menu_WasShown = false; - if (m_IsRightButton && m_Panel) - { - UInt32 flagsMask; - if (m_Panel->IsArcFolder()) - flagsMask = (UInt32)1 << NDragMenu::k_Copy_ToArc; - else - { - flagsMask = (UInt32)1 << NDragMenu::k_AddToArc; - if (IsFsFolderPath()) - flagsMask |= (UInt32)1 << NDragMenu::k_Copy_Base; - } - // flagsMask |= (UInt32)1 << NDragMenu::k_Cancel; - const UInt32 cmd32 = Drag_OnContextMenu(pt.x, pt.y, flagsMask); - cmd = cmd32 & NDragMenu::k_MenuFlags_CmdMask; - if (cmd32 & NDragMenu::k_MenuFlag_Copy) - cmdEffect = DROPEFFECT_COPY; - else if (cmd32 & NDragMenu::k_MenuFlag_Move) - cmdEffect = DROPEFFECT_MOVE; - opEffect = cmdEffect; - menu_WasShown = true; - } - else - { - opEffect = GetEffect(keyState, pt, *effect); - if (m_IsAppTarget) - cmd = NDragMenu::k_AddToArc; - else if (m_Panel) - { - if (IsFsFolderPath()) - { - const bool is7zip = m_TargetPath_WasSent_ToDataObject; - bool createNewArchive = false; - if (is7zip) - createNewArchive = false; // g_CreateArchive_for_Drag_from_7zip; - else - createNewArchive = true; // g_CreateArchive_for_Drag_from_Explorer; - - if (createNewArchive) - cmd = NDragMenu::k_AddToArc; - else - { - if (opEffect != 0) - cmd = NDragMenu::k_Copy_Base; - cmdEffect = opEffect; - } - } - else - { - /* if we are inside open archive: - if archive support operations -> we will call operations - if archive doesn't support operations -> we will create new archove - */ - if (m_Panel->IsArcFolder() - || m_Panel->DoesItSupportOperations()) - { - cmd = NDragMenu::k_Copy_ToArc; - // we don't want move to archive operation here. - // so we force to DROPEFFECT_COPY. - if (opEffect != DROPEFFECT_NONE) - opEffect = DROPEFFECT_COPY; - cmdEffect = opEffect; - } - else - cmd = NDragMenu::k_AddToArc; - } - } - } - - if (cmd == 0) - cmd = NDragMenu::k_AddToArc; - - if (cmd == NDragMenu::k_AddToArc) - { - opEffect = DROPEFFECT_COPY; - cmdEffect = DROPEFFECT_COPY; - } - - if (m_Panel) - if (cmd == NDragMenu::k_Copy_ToArc) - { - const UString title = LangString(IDS_CONFIRM_FILE_COPY); - UString s = LangString(cmdEffect == DROPEFFECT_MOVE ? - IDS_MOVE_TO : IDS_COPY_TO); - s.Add_LF(); - s += "\'"; - s += m_Panel->_currentFolderPrefix; - s += "\'"; - s.Add_LF(); - s += LangString(IDS_WANT_TO_COPY_FILES); - s += " ?"; - const int res = ::MessageBoxW(*m_Panel, s, title, MB_YESNOCANCEL | MB_ICONQUESTION); - if (res != IDYES) - cmd = NDragMenu::k_Cancel; - } - - CTargetTransferInfo target; - target.FuncType = k_DragTargetMode_Drop_Begin; - target.KeyState = keyState; - target.Point = pt; - target.OkEffects = *effect; - target.Flags = 0; - - target.Cmd_Effect = cmdEffect; - target.Cmd_Type = cmd; - target.FolderType = GetFolderType(); - - if (cmd == NDragMenu::k_Cancel) - target.Flags |= k_TargetFlags_WasCanceled; - if (menu_WasShown) - target.Flags |= k_TargetFlags_MenuWasShown; - - SendToSource_auto(dataObject, target); - - CDataObject_GetTransfer transfer; - m_GetTransfer_WasSuccess = DataObject_GetData_GetTransfer( - dataObject, m_Format_7zip_GetTransfer, transfer); - - /* The Source (for example, 7-zip) could change file names when drop was confirmed. - So we must reload source file paths here */ - if (cmd != NDragMenu::k_Cancel) - LoadNames_From_DataObject(dataObject); - - if (cmd == NDragMenu::k_Cancel) - { - opEffect = DROPEFFECT_NONE; - cmdEffect = DROPEFFECT_NONE; - } - else - { - if (m_GetTransfer_WasSuccess) - needDrop_by_Source = ((transfer.Flags & k_SourceFlags_DoNotProcessInTarget) != 0); - if (!needDrop_by_Source) - { - bool moveMode = (cmdEffect == DROPEFFECT_MOVE); - bool needDrop = false; - if (m_IsRightButton && m_Panel) - needDrop = true; - if (m_DropIsAllowed && m_PanelDropIsAllowed) - { - /* if non-empty TargetPath was sent successfully to DataObject, - then the Source is 7-Zip, and that 7zip-Source can copy to FS operation. - So we can disable Drop operation here for such case. - */ - needDrop_by_Source = (cmd != NDragMenu::k_AddToArc - && m_TargetPath_WasSent_ToDataObject - && m_TargetPath_NonEmpty_WasSent_ToDataObject); - needDrop = !(needDrop_by_Source); - } - if (needDrop) - { - UString path = GetTargetPath(); - if (m_IsAppTarget && m_Panel) - if (m_Panel->IsFSFolder()) - path = m_Panel->GetFsPath(); - - UInt32 sourceFlags = 0; - if (m_GetTransfer_WasSuccess) - sourceFlags = transfer.Flags; - - if (menu_WasShown) - target.Flags |= k_TargetFlags_MenuWasShown; - - target.Flags |= k_TargetFlags_WasProcessed; - - RemoveSelection(); - // disableTimerProcessing.Restore(); - m_Panel->CompressDropFiles(m_SourcePaths, path, - (cmd == NDragMenu::k_AddToArc), // createNewArchive, - moveMode, sourceFlags, - target.Flags - ); - } - } - } // end of if (cmd != NDragMenu::k_Cancel) - { - /* note that, if (we send CFSTR_PERFORMEDDROPEFFECT as DROPEFFECT_MOVE - and Drop() returns (*effect == DROPEFFECT_MOVE), then - Win10-Explorer-Source will try to remove files just after Drop() exit. - But our CompressFiles() could be run without waiting finishing. - DOCs say, that we must send CFSTR_PERFORMEDDROPEFFECT - - DROPEFFECT_NONE : for optimized move - - DROPEFFECT_MOVE : for unoptimized move. - But actually Win10-Explorer-Target sends (DROPEFFECT_MOVE) for move operation. - And it still works as in optimized mode, because "unoptimized" deleting by Source will be performed - if both conditions are met: - 1) DROPEFFECT_MOVE is sent to (CFSTR_PERFORMEDDROPEFFECT) and - 2) (*effect == DROPEFFECT_MOVE) is returend by Drop(). - We don't want to send DROPEFFECT_MOVE here to protect from - deleting file by Win10-Explorer. - We are not sure that allfile fieree processed by move. - */ - - // for debug: we test the case when source tries to delete original files - // bool res; - // only CFSTR_PERFORMEDDROPEFFECT affects file removing in Win10-Explorer. - // res = SendToSource_UInt32(dataObject, RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT), DROPEFFECT_MOVE); // for debug - /* res = */ SendToSource_UInt32(dataObject, - RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT), - cmd == NDragMenu::k_Cancel ? DROPEFFECT_NONE : DROPEFFECT_COPY); - // res = res; - } - RemoveSelection(); - - target.FuncType = k_DragTargetMode_Drop_End; - target.Cmd_Type = cmd; - if (needDrop_by_Source) - target.Flags |= k_TargetFlags_MustBeProcessedBySource; - - SendToSource_TransferInfo(dataObject, target); - } catch(...) { hres = E_FAIL; } - - ClearState(); - // *effect |= (1 << 10); // for debug - // *effect = DROPEFFECT_COPY; // for debug - - /* - if we return (*effect == DROPEFFECT_MOVE) here, - Explorer-Source at some conditions can treat it as (unoptimized move) mode, - and Explorer-Source will remove source files after DoDragDrop() - in that (unoptimized move) mode. - We want to avoid such (unoptimized move) cases. - So we don't return (*effect == DROPEFFECT_MOVE), here if Source is not 7-Zip. - If source is 7-Zip that will do acual opeartion, then we can return DROPEFFECT_MOVE. - */ - if (hres != S_OK || (opEffect == DROPEFFECT_MOVE && !needDrop_by_Source)) - { - // opEffect = opEffect; - // opEffect = DROPEFFECT_NONE; // for debug disabled - } - - *effect = opEffect; - /* if (hres < 0), DoDragDrop() also will return (hres). - if (hres >= 0), DoDragDrop() will return DRAGDROP_S_DROP; - */ - return hres; -} - - - -// ---------- CPanel ---------- - - -static bool Is_Path1_Prefixed_by_Path2(const UString &path, const UString &prefix) -{ - const unsigned len = prefix.Len(); - if (path.Len() < len) - return false; - return CompareFileNames(path.Left(len), prefix) == 0; -} - -static bool IsFolderInTemp(const UString &path) -{ - FString tempPathF; - if (!MyGetTempPath(tempPathF)) - return false; - const UString tempPath = fs2us(tempPathF); - if (tempPath.IsEmpty()) - return false; - return Is_Path1_Prefixed_by_Path2(path, tempPath); -} - -static bool AreThereNamesFromTemp(const UStringVector &filePaths) -{ - FString tempPathF; - if (!MyGetTempPath(tempPathF)) - return false; - const UString tempPath = fs2us(tempPathF); - if (tempPath.IsEmpty()) - return false; - FOR_VECTOR (i, filePaths) - if (Is_Path1_Prefixed_by_Path2(filePaths[i], tempPath)) - return true; - return false; -} - - -/* - empty folderPath means create new Archive to path of first fileName. - createNewArchive == true : show "Add to archive ..." dialog with external program - folderPath.IsEmpty() : create archive in folder of filePaths[0]. - createNewArchive == false : - folderPath.IsEmpty() : copy to archive folder that is open in panel - !folderPath.IsEmpty() : CopyFsItems() to folderPath. -*/ -void CPanel::CompressDropFiles( - const UStringVector &filePaths, - const UString &folderPath, - bool createNewArchive, - bool moveMode, - UInt32 sourceFlags, - UInt32 &targetFlags - ) -{ - if (filePaths.Size() == 0) - return; - // createNewArchive = false; // for debug - - if (createNewArchive) - { - UString folderPath2 = folderPath; - // folderPath2.Empty(); // for debug - if (folderPath2.IsEmpty()) - { - { - FString folderPath2F; - GetOnlyDirPrefix(us2fs(filePaths.Front()), folderPath2F); - folderPath2 = fs2us(folderPath2F); - } - if (IsFolderInTemp(folderPath2)) - { - /* we don't want archive to be created in temp directory. - so we change the path to root folder (non-temp) */ - folderPath2 = ROOT_FS_FOLDER; - } - } - - UString arcName_base; - const UString arcName = CreateArchiveName(filePaths, - false, // isHash - NULL, // CFileInfo *fi - arcName_base); - - bool needWait; - if (sourceFlags & k_SourceFlags_WaitFinish) - needWait = true; - else if (sourceFlags & k_SourceFlags_DoNotWaitFinish) - needWait = false; - else if (sourceFlags & k_SourceFlags_TempFiles) - needWait = true; - else - needWait = AreThereNamesFromTemp(filePaths); - - targetFlags |= (needWait ? - k_TargetFlags_WaitFinish : - k_TargetFlags_DoNotWaitFinish); - - CompressFiles(folderPath2, arcName, - L"", // arcType - true, // addExtension - filePaths, - false, // email - true, // showDialog - needWait); - } - else - { - targetFlags |= k_TargetFlags_WaitFinish; - if (!folderPath.IsEmpty()) - { - CCopyToOptions options; - options.moveMode = moveMode; - options.folder = folderPath; - options.showErrorMessages = true; // showErrorMessages is not used for this operation - options.NeedRegistryZone = false; - options.ZoneIdMode = NExtract::NZoneIdMode::kNone; - // maybe we need more options here: FIXME - /* HRESULT hres = */ CopyFsItems(options, - filePaths, - NULL // UStringVector *messages - ); - // hres = hres; - } - else - { - CopyFromNoAsk(moveMode, filePaths); - } - } -} - - - -static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags) -{ - CMenu menu; - CMenuDestroyer menuDestroyer(menu); - /* - Esc key in shown menu doesn't work if we call Drag_OnContextMenu from ::Drop(). - We call SetFocus() tp solve that problem. - But the focus will be changed to Target Window after Drag and Drop. - Is it OK to use SetFocus() here ? - Is there another way to enable Esc key ? - */ - // _listView.SetFocus(); // for debug - ::SetFocus(g_HWND); - menu.CreatePopup(); - /* - int defaultCmd; // = NDragMenu::k_Move; - defaultCmd = NDragMenu::k_None; - */ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(NDragMenu::g_Pairs); i++) - { - const NDragMenu::CCmdLangPair &pair = NDragMenu::g_Pairs[i]; - const UInt32 cmdAndFlags = pair.CmdId_and_Flags; - const UInt32 cmdId = cmdAndFlags & NDragMenu::k_MenuFlags_CmdMask; - if (cmdId != NDragMenu::k_Cancel) - if ((cmdFlags & ((UInt32)1 << cmdId)) == 0) - continue; - const UINT flags = MF_STRING; - /* - if (prop.IsVisible) - flags |= MF_CHECKED; - if (i == 0) - flags |= MF_GRAYED; - */ - // MF_DEFAULT doesn't work - // if (i == 2) flags |= MF_DEFAULT; - // if (i == 4) flags |= MF_HILITE; - // if (cmd == defaultCmd) flags |= MF_HILITE; - UString name = LangString(pair.LangId); - if (name.IsEmpty()) - { - if (cmdId == NDragMenu::k_Cancel) - name = "Cancel"; - else - name.Add_UInt32(pair.LangId); - } - if (cmdId == NDragMenu::k_Copy_ToArc) - { - // UString destPath = _currentFolderPrefix; - /* - UString destPath = LangString(IDS_CONTEXT_ARCHIVE); - name = MyFormatNew(name, destPath); - */ - name.Add_Space(); - name += LangString(IDS_CONTEXT_ARCHIVE); - } - if (cmdId == NDragMenu::k_Cancel) - menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); - menu.AppendItem(flags, cmdAndFlags, name); - } - /* - if (defaultCmd != 0) - SetMenuDefaultItem(menu, (unsigned)defaultCmd, - FALSE); // byPos - */ - int menuResult = menu.Track( - TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, - xPos, yPos, - g_HWND - // _listView // for debug - ); - /* menu.Track() return value is zero, if the user cancels - the menu without making a selection, or if an error occurs */ - if (menuResult <= 0) - menuResult = NDragMenu::k_Cancel; - return (unsigned)menuResult; -} - - - -void CApp::CreateDragTarget() -{ - _dropTargetSpec = new CDropTarget(); - _dropTarget = _dropTargetSpec; - _dropTargetSpec->App = (this); -} - -void CApp::SetFocusedPanel(unsigned index) -{ - LastFocusedPanel = index; - _dropTargetSpec->TargetPanelIndex = (int)LastFocusedPanel; -} - -void CApp::DragBegin(unsigned panelIndex) -{ - _dropTargetSpec->TargetPanelIndex = (int)(NumPanels > 1 ? 1 - panelIndex : panelIndex); - _dropTargetSpec->SrcPanelIndex = (int)panelIndex; -} - -void CApp::DragEnd() -{ - _dropTargetSpec->TargetPanelIndex = (int)LastFocusedPanel; - _dropTargetSpec->SrcPanelIndex = -1; -} +// PanelDrag.cpp + +#include "StdAfx.h" + +#ifdef UNDER_CE +#include +#endif + +#include "../../../../C/7zVersion.h" +#include "../../../../C/CpuArch.h" + +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/COM.h" +#include "../../../Windows/MemoryGlobal.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Shell.h" + +#include "../Common/ArchiveName.h" +#include "../Common/CompressCall.h" +#include "../Common/ExtractingFilePath.h" + +#include "MessagesDialog.h" + +#include "App.h" +#include "EnumFormatEtc.h" +#include "FormatUtils.h" +#include "LangUtils.h" + +#include "resource.h" +#include "../Explorer/resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +#define PRF(x) +#define PRF_W(x) +// #define PRF2(x) +#define PRF3(x) +#define PRF3_W(x) +#define PRF4(x) +// #define PRF4(x) OutputDebugStringA(x) +// #define PRF4_W(x) OutputDebugStringW(x) + +// #define SHOW_DEBUG_DRAG + +#ifdef SHOW_DEBUG_DRAG + +#define PRF_(x) { x; } + +static void Print_Point(const char *name, DWORD keyState, const POINTL &pt, DWORD effect) +{ + AString s (name); + s += " x="; s.Add_UInt32((unsigned)pt.x); + s += " y="; s.Add_UInt32((unsigned)pt.y); + s += " k="; s.Add_UInt32(keyState); + s += " e="; s.Add_UInt32(effect); + PRF4(s); +} + +#else + +#define PRF_(x) + +#endif + + +#define kTempDirPrefix FTEXT("7zE") + +// all versions: k_Format_7zip_SetTargetFolder format to transfer folder path from target to source +static LPCTSTR const k_Format_7zip_SetTargetFolder = TEXT("7-Zip::SetTargetFolder"); +// new v23 formats: +static LPCTSTR const k_Format_7zip_SetTransfer = TEXT("7-Zip::SetTransfer"); +static LPCTSTR const k_Format_7zip_GetTransfer = TEXT("7-Zip::GetTransfer"); + +/* + Win10: clipboard formats. + There are about 16K free ids (formats) per system that can be + registered with RegisterClipboardFormat() with different names. + Probably that 16K ids space is common for ids registering for both + formats: RegisterClipboardFormat(), and registered window classes: + RegisterClass(). But ids for window classes will be deleted from + the list after process finishing. And registered clipboard + formats probably will be deleted from the list only after reboot. +*/ + +// static bool const g_CreateArchive_for_Drag_from_7zip = false; +// static bool const g_CreateArchive_for_Drag_from_Explorer = true; + // = false; // for debug + +/* +How DoDragDrop() works: +{ + IDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0 + IDropTarget::Enter() + IDropSource::GiveFeedback() + IDropTarget::DragOver() + IDropSource::GiveFeedback() + + for() + { + IDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0 + IDropTarget::DragOver() (keyState & MK_LBUTTON) != 0 + IDropSource::GiveFeedback() + } + + { + // DoDragDrop() in Win10 before calling // QueryContinueDrag() + // with (*(keyState & MK_LBUTTON) == 0) probably calls: + // 1) IDropTarget::DragOver() with same point values (x,y), but (keyState & MK_LBUTTON) != 0) + // 2) IDropSource::GiveFeedback(). + // so DropSource can know exact GiveFeedback(effect) mode just before LBUTTON releasing. + + if (IDropSource::QueryContinueDrag() for (keyState & MK_LBUTTON) == 0 + returns DRAGDROP_S_DROP), it will call + IDropTarget::Drop() + } + or + { + IDropSource::QueryContinueDrag() + IDropTarget::DragLeave() + IDropSource::GiveFeedback(0) + } + or + { + if (IDropSource::QueryContinueDrag() + returns DRAGDROP_S_CANCEL) + IDropTarget::DragLeave() + } +} +*/ + + +// ---------- CDropTarget ---------- + +static const UInt32 k_Struct_Id_SetTranfer = 2; // it's our selected id +static const UInt32 k_Struct_Id_GetTranfer = 3; // it's our selected id + +static const UInt64 k_Program_Id = 1; // "7-Zip" + +enum E_Program_ISA +{ + k_Program_ISA_x86 = 2, + k_Program_ISA_x64 = 3, + k_Program_ISA_armt = 4, + k_Program_ISA_arm64 = 5, + k_Program_ISA_arm32 = 6, + k_Program_ISA_ia64 = 9 +}; + +#define k_Program_Ver ((MY_VER_MAJOR << 16) | MY_VER_MINOR) + + +// k_SourceFlags_* are flags that are sent from Source to Target + +static const UInt32 k_SourceFlags_DoNotProcessInTarget = 1 << 1; +/* Do not process in Target. Source will process operation instead of Target. + By default Target processes Drop opearation. */ +// static const UInt32 k_SourceFlags_ProcessInTarget = 1 << 2; + +static const UInt32 k_SourceFlags_DoNotWaitFinish = 1 << 3; +static const UInt32 k_SourceFlags_WaitFinish = 1 << 4; +/* usually Source needs WaitFinish, if temp files were created. */ + +static const UInt32 k_SourceFlags_TempFiles = 1 << 6; +static const UInt32 k_SourceFlags_NamesAreParent = 1 << 7; +/* if returned path list for GetData(CF_HDROP) contains + path of parent temp folder instead of final paths of items + that will be extracted later from archive */ + +static const UInt32 k_SourceFlags_SetTargetFolder = 1 << 8; +/* SetData::("SetTargetFolder") was called (with empty or non-empty string) */ + +static const UInt32 k_SourceFlags_SetTargetFolder_NonEmpty = 1 << 9; +/* SetData::("SetTargetFolder") was called with non-empty string */ + +static const UInt32 k_SourceFlags_NeedExtractOpToFs = 1 << 10; + +static const UInt32 k_SourceFlags_Copy_WasCalled = 1 << 11; + +static const UInt32 k_SourceFlags_LeftButton = 1 << 14; +static const UInt32 k_SourceFlags_RightButton = 1 << 15; + + +static const UInt32 k_TargetFlags_WasCanceled = 1 << 0; +static const UInt32 k_TargetFlags_MustBeProcessedBySource = 1 << 1; +static const UInt32 k_TargetFlags_WasProcessed = 1 << 2; +static const UInt32 k_TargetFlags_DoNotWaitFinish = 1 << 3; +static const UInt32 k_TargetFlags_WaitFinish = 1 << 4; +static const UInt32 k_TargetFlags_MenuWasShown = 1 << 16; + +struct CDataObject_TransferBase +{ + UInt32 Struct_Id; + UInt32 Struct_Size; + + UInt64 Program_Id; + UInt32 Program_Ver_Main; + UInt32 Program_Ver_Build; + UInt32 Program_ISA; + UInt32 Program_Flags; + + UInt32 ProcessId; + UInt32 _reserved1[7]; + +protected: + void Init_Program(); +}; + + +void CDataObject_TransferBase::Init_Program() +{ + Program_Id = k_Program_Id; + Program_ISA = + #if defined(MY_CPU_AMD64) + k_Program_ISA_x64 + #elif defined(MY_CPU_X86) + k_Program_ISA_x86 + #elif defined(MY_CPU_ARM64) + k_Program_ISA_arm64 + #elif defined(MY_CPU_ARM32) + k_Program_ISA_arm32 + #elif defined(MY_CPU_ARMT) || defined(MY_CPU_ARM) + k_Program_ISA_armt + #elif defined(MY_CPU_IA64) + k_Program_ISA_ia64 + #else + 0 + #endif + ; + Program_Flags = sizeof(size_t); + Program_Ver_Main = k_Program_Ver; + // Program_Ver_Build = 0; + ProcessId = GetCurrentProcessId(); +} + + +#if defined(__GNUC__) && !defined(__clang__) +/* 'void* memset(void*, int, size_t)' clearing an object + of non-trivial type 'struct CDataObject_SetTransfer' */ +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + + +struct CDataObject_GetTransfer: +public CDataObject_TransferBase +{ + UInt32 Flags; + + UInt32 _reserved2[11]; + + CDataObject_GetTransfer() + { + memset(this, 0, sizeof(*this)); + Init_Program(); + Struct_Id = k_Struct_Id_GetTranfer; + Struct_Size = sizeof(*this); + } + + bool Check() const + { + return Struct_Size >= sizeof(*this) && Struct_Id == k_Struct_Id_GetTranfer; + } +}; + + +enum Enum_FolderType +{ + k_FolderType_None, + k_FolderType_Unknown = 1, + k_FolderType_Fs = 2, + k_FolderType_AltStreams = 3, + k_FolderType_Archive = 4 +}; + +struct CTargetTransferInfo +{ + UInt32 Flags; + UInt32 FuncType; + + UInt32 KeyState; + UInt32 OkEffects; + POINTL Point; + + UInt32 Cmd_Effect; + UInt32 Cmd_Type; + UInt32 FolderType; + UInt32 _reserved3[3]; + + CTargetTransferInfo() + { + memset(this, 0, sizeof(*this)); + } +}; + +struct CDataObject_SetTransfer: +public CDataObject_TransferBase +{ + CTargetTransferInfo Target; + + void Init() + { + memset(this, 0, sizeof(*this)); + Init_Program(); + Struct_Id = k_Struct_Id_SetTranfer; + Struct_Size = sizeof(*this); + } + + bool Check() const + { + return Struct_Size >= sizeof(*this) && Struct_Id == k_Struct_Id_SetTranfer; + } +}; + + + + + +enum Enum_DragTargetMode +{ + k_DragTargetMode_None = 0, + k_DragTargetMode_Leave = 1, + k_DragTargetMode_Enter = 2, + k_DragTargetMode_Over = 3, + k_DragTargetMode_Drop_Begin = 4, + k_DragTargetMode_Drop_End = 5 +}; + + +// ---- menu ---- + +namespace NDragMenu { + +enum Enum_CmdId +{ + k_None = 0, + k_Cancel = 1, + k_Copy_Base = 2, // to fs + k_Copy_ToArc = 3, + k_AddToArc = 4 + /* + k_OpenArc = 8, + k_TestArc = 9, + k_ExtractFiles = 10, + k_ExtractHere = 11 + */ +}; + +struct CCmdLangPair +{ + unsigned CmdId_and_Flags; + unsigned LangId; +}; + +static const UInt32 k_MenuFlags_CmdMask = (1 << 7) - 1; +static const UInt32 k_MenuFlag_Copy = 1 << 14; +static const UInt32 k_MenuFlag_Move = 1 << 15; +// #define IDS_CANCEL (IDCANCEL + 400) +#define IDS_CANCEL 402 + +static const CCmdLangPair g_Pairs[] = +{ + { k_Copy_Base | k_MenuFlag_Copy, IDS_COPY }, + { k_Copy_Base | k_MenuFlag_Move, IDS_MOVE }, + { k_Copy_ToArc | k_MenuFlag_Copy, IDS_COPY_TO }, + // { k_Copy_ToArc | k_MenuFlag_Move, IDS_MOVE_TO }, // IDS_CONTEXT_COMPRESS_TO + // { k_OpenArc, IDS_CONTEXT_OPEN }, + // { k_ExtractFiles, IDS_CONTEXT_EXTRACT }, + // { k_ExtractHere, IDS_CONTEXT_EXTRACT_HERE }, + // { k_TestArc, IDS_CONTEXT_TEST }, + { k_AddToArc | k_MenuFlag_Copy, IDS_CONTEXT_COMPRESS }, + { k_Cancel, IDS_CANCEL } +}; + +} + + +class CDropTarget Z7_final: + public IDropTarget, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1_MT(IDropTarget) + STDMETHOD(DragEnter)(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) Z7_override; + STDMETHOD(DragOver)(DWORD keyState, POINTL pt, DWORD *effect) Z7_override; + STDMETHOD(DragLeave)() Z7_override; + STDMETHOD(Drop)(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) Z7_override; + + bool m_IsRightButton; + bool m_GetTransfer_WasSuccess; + bool m_DropIsAllowed; // = true, if data IDataObject can return CF_HDROP (so we can get list of paths) + bool m_PanelDropIsAllowed; // = false, if current target_panel is source_panel. + // check it only if m_DropIsAllowed == true + // we use it to show icon effect that drop is not allowed here. + + CMyComPtr m_DataObject; // we set it in DragEnter() + UStringVector m_SourcePaths; + + // int m_DropHighlighted_SelectionIndex; + // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item) + // UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder) + + CPanel *m_Panel; + bool m_IsAppTarget; // true, if we want to drop to app window (not to panel) + + bool m_TargetPath_WasSent_ToDataObject; // true, if TargetPath was sent + bool m_TargetPath_NonEmpty_WasSent_ToDataObject; // true, if non-empty TargetPath was sent + bool m_Transfer_WasSent_ToDataObject; // true, if Transfer was sent + UINT m_Format_7zip_SetTargetFolder; + UINT m_Format_7zip_SetTransfer; + UINT m_Format_7zip_GetTransfer; + + UInt32 m_ProcessId; // for sending + + bool IsItSameDrive() const; + + // void Try_QueryGetData(IDataObject *dataObject); + void LoadNames_From_DataObject(IDataObject *dataObject); + + UInt32 GetFolderType() const; + bool IsFsFolderPath() const; + DWORD GetEffect(DWORD keyState, POINTL pt, DWORD allowedEffect) const; + void RemoveSelection(); + void PositionCursor(const POINTL &ptl); + UString GetTargetPath() const; + bool SendToSource_TargetPath_enable(IDataObject *dataObject, bool enablePath); + bool SendToSource_UInt32(IDataObject *dataObject, UINT format, UInt32 value); + bool SendToSource_TransferInfo(IDataObject *dataObject, + const CTargetTransferInfo &info); + void SendToSource_auto(IDataObject *dataObject, + const CTargetTransferInfo &info); + void SendToSource_Drag(CTargetTransferInfo &info) + { + SendToSource_auto(m_DataObject, info); + } + + void ClearState(); + +public: + CDropTarget(); + + CApp *App; + int SrcPanelIndex; // index of D&D source_panel + int TargetPanelIndex; // what panel to use as target_panel of Application +}; + + + + +// ---------- CDataObject ---------- + +/* + Some programs (like Sticky Notes in Win10) do not like + virtual non-existing items (files/dirs) in CF_HDROP format. + So we use two versions of CF_HDROP data: + m_hGlobal_HDROP_Pre : the list contains only destination path of temp directory. + That directory later will be filled with extracted items. + m_hGlobal_HDROP_Final : the list contains paths of all root items that + will be created in temp directory by archive extraction operation, + or the list of existing fs items, if source is filesystem directory. + + The DRAWBACK: some programs (like Edge in Win10) can use names from IDataObject::GetData() + call that was called before IDropSource::QueryContinueDrag() where we set (UseFinalGlobal = true) + So such programs will use non-relevant m_hGlobal_HDROP_Pre item, + instead of m_hGlobal_HDROP_Final items. +*/ + +class CDataObject Z7_final: + public IDataObject, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1_MT(IDataObject) + + Z7_COMWF_B GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium) Z7_override; + Z7_COMWF_B GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium) Z7_override; + Z7_COMWF_B QueryGetData(LPFORMATETC pformatetc) Z7_override; + + Z7_COMWF_B GetCanonicalFormatEtc(LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut) Z7_override + { + if (!pformatetcOut) + return E_INVALIDARG; + pformatetcOut->ptd = NULL; + return E_NOTIMPL; + } + + Z7_COMWF_B SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) Z7_override; + Z7_COMWF_B EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc) Z7_override; + + Z7_COMWF_B DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */) Z7_override + { return OLE_E_ADVISENOTSUPPORTED; } + Z7_COMWF_B DUnadvise(DWORD /* dwConnection */) Z7_override + { return OLE_E_ADVISENOTSUPPORTED; } + Z7_COMWF_B EnumDAdvise(LPENUMSTATDATA *ppenumAdvise) Z7_override + { + if (ppenumAdvise) + *ppenumAdvise = NULL; + return OLE_E_ADVISENOTSUPPORTED; + } + + bool m_PerformedDropEffect_WasSet; + bool m_LogicalPerformedDropEffect_WasSet; + bool m_DestDirPrefix_FromTarget_WasSet; +public: + bool m_Transfer_WasSet; +private: + // GetData formats (source to target): + FORMATETC m_Etc; + // UINT m_Format_FileOpFlags; + // UINT m_Format_PreferredDropEffect; + + // SetData() formats (target to source): + // 7-Zip's format: + UINT m_Format_7zip_SetTargetFolder; + UINT m_Format_7zip_SetTransfer; + UINT m_Format_7zip_GetTransfer; // for GetData() + + UINT m_Format_PerformedDropEffect; + UINT m_Format_LogicalPerformedDropEffect; + UINT m_Format_DisableDragText; + UINT m_Format_IsShowingLayered; + UINT m_Format_IsShowingText; + UINT m_Format_DropDescription; + UINT m_Format_TargetCLSID; + + DWORD m_PerformedDropEffect; + DWORD m_LogicalPerformedDropEffect; + + void CopyFromPanelTo_Folder(); + HRESULT SetData2(const FORMATETC *formatetc, const STGMEDIUM *medium); + +public: + bool IsRightButton; + bool IsTempFiles; + + bool UsePreGlobal; + bool DoNotProcessInTarget; + + bool NeedCall_Copy; + bool Copy_WasCalled; + + NMemory::CGlobal m_hGlobal_HDROP_Pre; + NMemory::CGlobal m_hGlobal_HDROP_Final; + // NMemory::CGlobal m_hGlobal_FileOpFlags; + // NMemory::CGlobal m_hGlobal_PreferredDropEffect; + + CPanel *Panel; + CRecordVector Indices; + + UString SrcDirPrefix_Temp; // FS directory with source files or Temp + UString DestDirPrefix_FromTarget; + /* destination Path that was sent by Target via SetData(). + it can be altstreams prefix. + if (!DestDirPrefix_FromTarget.IsEmpty()) m_Panel->CompressDropFiles() was not called by Target. + So we must do drop actions in Source */ + HRESULT Copy_HRESULT; + UStringVector Messages; + + CDataObject(); +public: + CDataObject_SetTransfer m_Transfer; +}; + + +// for old mingw: +#ifndef CFSTR_LOGICALPERFORMEDDROPEFFECT +#define CFSTR_LOGICALPERFORMEDDROPEFFECT TEXT("Logical Performed DropEffect") +#endif +#ifndef CFSTR_TARGETCLSID +#define CFSTR_TARGETCLSID TEXT("TargetCLSID") // HGLOBAL with a CLSID of the drop target +#endif + + + +CDataObject::CDataObject() +{ + // GetData formats (source to target): + // and we use CF_HDROP format to transfer file paths from source to target: + m_Etc.cfFormat = CF_HDROP; + m_Etc.ptd = NULL; + m_Etc.dwAspect = DVASPECT_CONTENT; + m_Etc.lindex = -1; + m_Etc.tymed = TYMED_HGLOBAL; + + // m_Format_FileOpFlags = RegisterClipboardFormat(TEXT("FileOpFlags")); + // m_Format_PreferredDropEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); // "Preferred DropEffect" + + // SetData() formats (target to source): + m_Format_7zip_SetTargetFolder = RegisterClipboardFormat(k_Format_7zip_SetTargetFolder); + m_Format_7zip_SetTransfer = RegisterClipboardFormat(k_Format_7zip_SetTransfer); + m_Format_7zip_GetTransfer = RegisterClipboardFormat(k_Format_7zip_GetTransfer); + + m_Format_PerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); // "Performed DropEffect" + m_Format_LogicalPerformedDropEffect = RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT); // "Logical Performed DropEffect" + m_Format_DisableDragText = RegisterClipboardFormat(TEXT("DisableDragText")); + m_Format_IsShowingLayered = RegisterClipboardFormat(TEXT("IsShowingLayered")); + m_Format_IsShowingText = RegisterClipboardFormat(TEXT("IsShowingText")); + m_Format_DropDescription = RegisterClipboardFormat(TEXT("DropDescription")); + m_Format_TargetCLSID = RegisterClipboardFormat(CFSTR_TARGETCLSID); + + m_PerformedDropEffect = 0; + m_LogicalPerformedDropEffect = 0; + + m_PerformedDropEffect_WasSet = false; + m_LogicalPerformedDropEffect_WasSet = false; + + m_DestDirPrefix_FromTarget_WasSet = false; + m_Transfer_WasSet = false; + + IsRightButton = false; + IsTempFiles = false; + + UsePreGlobal = false; + DoNotProcessInTarget = false; + + NeedCall_Copy = false; + Copy_WasCalled = false; + + Copy_HRESULT = S_OK; +} + + + +void CDataObject::CopyFromPanelTo_Folder() +{ + try + { + CCopyToOptions options; + options.folder = SrcDirPrefix_Temp; + /* 15.13: fixed problem with mouse cursor for password window. + DoDragDrop() probably calls SetCapture() to some hidden window. + But it's problem, if we show some modal window, like MessageBox. + So we return capture to our window. + If you know better way to solve the problem, please notify 7-Zip developer. + */ + // MessageBoxW(*Panel, L"test", L"test", 0); + /* HWND oldHwnd = */ SetCapture(*Panel); + Copy_WasCalled = true; + Copy_HRESULT = E_FAIL; + Copy_HRESULT = Panel->CopyTo(options, Indices, &Messages); + // do we need to restore capture? + // ReleaseCapture(); + // oldHwnd = SetCapture(oldHwnd); + } + catch(...) + { + Copy_HRESULT = E_FAIL; + } +} + + +#ifdef SHOW_DEBUG_DRAG + +static void PrintFormat2(AString &s, unsigned format) +{ + s += " "; + s += "= format="; + s.Add_UInt32(format); + s += " "; + const int k_len = 512; + CHAR temp[k_len]; + if (GetClipboardFormatNameA(format, temp, k_len) && strlen(temp) != 0) + s += temp; +} + +static void PrintFormat(const char *title, unsigned format) +{ + AString s (title); + PrintFormat2(s, format); + PRF4(s); +} + +static void PrintFormat_AndData(const char *title, unsigned format, const void *data, size_t size) +{ + AString s (title); + PrintFormat2(s, format); + s += " size="; + s.Add_UInt32((UInt32)size); + for (size_t i = 0; i < size && i < 16; i++) + { + s += " "; + s.Add_UInt32(((const Byte *)data)[i]); + } + PRF4(s); +} + +static void PrintFormat_GUIDToStringW(const void *p) +{ + const GUID *guid = (const GUID *)p; + UString s; + const unsigned kSize = 48; + StringFromGUID2(*guid, s.GetBuf(kSize), kSize); + s.ReleaseBuf_CalcLen(kSize); + PRF3_W(s); +} + +// Vista +typedef enum +{ + MY_DROPIMAGE_INVALID = -1, // no image preference (use default) + MY_DROPIMAGE_NONE = 0, // red "no" circle + MY_DROPIMAGE_COPY = DROPEFFECT_COPY, // plus for copy + MY_DROPIMAGE_MOVE = DROPEFFECT_MOVE, // movement arrow for move + MY_DROPIMAGE_LINK = DROPEFFECT_LINK, // link arrow for link + MY_DROPIMAGE_LABEL = 6, // tag icon to indicate metadata will be changed + MY_DROPIMAGE_WARNING = 7, // yellow exclamation, something is amiss with the operation + MY_DROPIMAGE_NOIMAGE = 8 // no image at all +} MY_DROPIMAGETYPE; + +typedef struct { + MY_DROPIMAGETYPE type; + WCHAR szMessage[MAX_PATH]; + WCHAR szInsert[MAX_PATH]; +} MY_DROPDESCRIPTION; + +#endif + + +/* +IDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) +====================================================================== + + Main purpose of CDataObject is to transfer data from source to target + of drag and drop operation. + But also CDataObject can be used to transfer data in backward direction + from target to source (even if target and source are different processes). + There are some predefined Explorer's formats to transfer some data from target to source. + And 7-Zip uses 7-Zip's format k_Format_7zip_SetTargetFolder to transfer + destination directory path from target to source. + + Our CDataObject::SetData() function here is used only to transfer data from target to source. + Usual source_to_target data is filled to m_hGlobal_* objects directly without SetData() calling. + +The main problem of SetData() is ownership of medium for (release == TRUE) case. + +SetData(,, release = TRUE) from different processes (DropSource and DropTarget) +=============================================================================== +{ + MS DOCs about (STGMEDIUM *medium) ownership: + The data object called does not take ownership of the data + until it has successfully received it and no error code is returned. + + Each of processes (Source and Target) has own copy of medium allocated. + Windows code creates proxy IDataObject object in Target process to transferr + SetData() call between Target and Source processes via special proxies: + DropTarget -> + proxy_DataObject_in_Target -> + proxy_in_Source -> + DataObject_in_Source + when Target calls SetData() with proxy_DataObject_in_Target, + the system and proxy_in_Source + - allocates proxy-medium-in-Source process + - copies medium data from Target to that proxy-medium-in-Source + - sends proxy-medium-in-Source to DataObject_in_Source->SetData(). + + after returning from SetData() to Target process: + Win10 proxy_DataObject_in_Target releases original medium in Target process, + only if SetData() in Source returns S_OK. It's consistent with DOCs above. + + for unsupported cfFormat: + [DropSource is 7-Zip 22.01 (old) : (etc->cfFormat != m_Format_7zip_SetTargetFolder && release == TRUE)] + (DropSource is WinRAR case): + Source doesn't release medium and returns error (for example, E_NOTIMPL) + { + Then Win10 proxy_in_Source also doesn't release proxy-medium-in-Source. + So there is memory leak in Source process. + Probably Win10 proxy_in_Source tries to avoid possible double releasing + that can be more fatal than memory leak. + + Then Win10 proxy_DataObject_in_Target also doesn't release + original medium, that was allocated by DropTarget. + So if DropTarget also doesn't release medium, there is memory leak in + DropTarget process too. + DropTarget is Win10-Explorer probably doesn't release medium in that case. + } + + [DropSource is 7-Zip 22.01 (old) : (etc->cfFormat == m_Format_7zip_SetTargetFolder && release == TRUE)] + DropSource returns S_OK and doesn't release medium: + { + then there is memory leak in DropSource process only. + } + + (DropSource is 7-Zip v23 (new)): + (DropSource is Win10-Explorer case) + { + Win10-Explorer-DropSource probably always releases medium, + and then it always returns S_OK. + So Win10 proxy_DataObject_in_Target also releases + original medium, that was allocated by DropTarget. + So there is no memory leak in Source and Target processes. + } + + if (DropTarget is Win10-Explorer) + { + Explorer Target uses SetData(,, (release = TRUE)) and + Explorer Target probably doesn't free memory after SetData(), + even if SetData(,, (release = TRUE)) returns E_NOTIMPL; + } + + if (DropSource is Win10-Explorer) + { + (release == FALSE) doesn't work, and SetData() returns E_NOTIMPL; + (release == TRUE) works, and SetData() returns S_OK, and + it returns S_OK even for formats unsupported by Explorer. + } + + To be more compatible with DOCs and Win10-Explorer and to avoid memory leaks, + we use the following scheme for our IDataObject::SetData(,, release == TRUE) + in DropSource code: + if (release == TRUE) { our SetData() always releases medium + with ReleaseStgMedium() and returns S_OK; } + The DRAWBACK of that scheme: + The caller always receives S_OK, + so the caller doesn't know about any error in SetData() in that case. + +for 7zip-Target to 7zip-Source calls: + we use (release == FALSE) + So we avoid (release == TRUE) memory leak problems, + and we can get real return code from SetData(). + +for 7zip-Target to Explorer-Source calls: + we use (release == TRUE). + beacuse Explorer-Source doesn't accept (release == FALSE). +} +*/ + +/* +https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/shell/datascenarios.md +CFSTR_PERFORMEDDROPEFFECT: + is used by the target to inform the data object through its + IDataObject::SetData method of the outcome of a data transfer. +CFSTR_PREFERREDDROPEFFECT: + is used by the source to specify whether its preferred method of data transfer is move or copy. +*/ + +Z7_COMWF_B CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) +{ + try { + const HRESULT hres = SetData2(etc, medium); + // PrintFormat(release ? "SetData RELEASE=TRUE" : "SetData RELEASE=FALSE" , etc->cfFormat); + if (release) + { + /* + const DWORD tymed = medium->tymed; + IUnknown *pUnkForRelease = medium->pUnkForRelease; + */ + // medium->tymed = NULL; // for debug + // return E_NOTIMPL; // for debug + ReleaseStgMedium(medium); + /* ReleaseStgMedium() will change STGMEDIUM::tymed to (TYMED_NULL = 0). + but we also can clear (medium.hGlobal = NULL), + to prevent some incorrect releasing, if the caller will try to release the data */ + /* + if (medium->tymed == TYMED_NULL && tymed == TYMED_HGLOBAL && !pUnkForRelease) + medium->hGlobal = NULL; + */ + // do we need return S_OK; for (tymed != TYMED_HGLOBAL) cases ? + /* we return S_OK here to shows that we take ownership of the data in (medium), + so the caller will not try to release (medium) */ + return S_OK; // to be more compatible with Win10-Explorer and DOCs. + } + return hres; + } catch(...) { return E_FAIL; } +} + + + +HRESULT CDataObject::SetData2(const FORMATETC *etc, const STGMEDIUM *medium) +{ + // PRF3("== CDataObject::SetData()"); + + HRESULT hres = S_OK; + + if (etc->cfFormat == 0) + return DV_E_FORMATETC; + if (etc->tymed != TYMED_HGLOBAL) + return E_NOTIMPL; // DV_E_TYMED; + if (etc->dwAspect != DVASPECT_CONTENT) + return E_NOTIMPL; // DV_E_DVASPECT; + if (medium->tymed != TYMED_HGLOBAL) + return E_NOTIMPL; // DV_E_TYMED; + + if (!medium->hGlobal) + return S_OK; + + if (etc->cfFormat == m_Format_7zip_SetTargetFolder) + { + DestDirPrefix_FromTarget.Empty(); + m_DestDirPrefix_FromTarget_WasSet = true; + } + else if (etc->cfFormat == m_Format_7zip_SetTransfer) + m_Transfer_WasSet = false; + + const size_t size = GlobalSize(medium->hGlobal); + // GlobalLock() can return NULL, if memory block has a zero size + if (size == 0) + return S_OK; + const void *src = (const Byte *)GlobalLock(medium->hGlobal); + if (!src) + return E_FAIL; + + PRF_(PrintFormat_AndData("SetData", etc->cfFormat, src, size)) + + if (etc->cfFormat == m_Format_7zip_SetTargetFolder) + { + /* this is our registered k_Format_7zip_SetTargetFolder format. + so it's call from 7-zip's CDropTarget */ + /* 7-zip's CDropTarget calls SetData() for m_Format_7zip_SetTargetFolder + with (release == FALSE) */ + const size_t num = size / sizeof(wchar_t); + if (size != num * sizeof(wchar_t)) + return E_FAIL; + // if (num == 0) return S_OK; + // GlobalLock() can return NULL, if memory block has a zero-byte size + const wchar_t *s = (const wchar_t *)src; + UString &dest = DestDirPrefix_FromTarget; + for (size_t i = 0; i < num; i++) + { + const wchar_t c = s[i]; + if (c == 0) + break; + dest += c; + } + // PRF_(PrintFormat_AndData("SetData", etc->cfFormat, src, size)) + PRF3_W(DestDirPrefix_FromTarget); + } + else if (etc->cfFormat == m_Format_7zip_SetTransfer) + { + /* 7-zip's CDropTarget calls SetData() for m_Format_7zip_SetTransfer + with (release == FALSE) */ + if (size < sizeof(CDataObject_SetTransfer)) + return E_FAIL; + const CDataObject_SetTransfer *t = (const CDataObject_SetTransfer *)src; + if (!t->Check()) + return E_FAIL; + m_Transfer = *t; + if (t->Target.FuncType != k_DragTargetMode_Leave) + m_Transfer_WasSet = true; + bool needProcessBySource = !DestDirPrefix_FromTarget.IsEmpty(); + if (t->Target.FuncType == k_DragTargetMode_Drop_Begin) + { + if (t->Target.Cmd_Type != NDragMenu::k_Copy_Base + // || t->Target.Cmd_Effect != DROPEFFECT_COPY + ) + needProcessBySource = false; + } + if (t->Target.FuncType == k_DragTargetMode_Drop_End) + { + if (t->Target.Flags & k_TargetFlags_MustBeProcessedBySource) + needProcessBySource = true; + else if (t->Target.Flags & k_TargetFlags_WasProcessed) + needProcessBySource = false; + } + DoNotProcessInTarget = needProcessBySource; + } + else + { + // SetData() from Explorer Target: + if (etc->cfFormat == m_Format_PerformedDropEffect) + { + m_PerformedDropEffect_WasSet = false; + if (size == sizeof(DWORD)) + { + m_PerformedDropEffect = *(const DWORD *)src; + m_PerformedDropEffect_WasSet = true; + } + } + else if (etc->cfFormat == m_Format_LogicalPerformedDropEffect) + { + m_LogicalPerformedDropEffect_WasSet = false; + if (size == sizeof(DWORD)) + { + m_LogicalPerformedDropEffect = *(const DWORD *)src; + m_LogicalPerformedDropEffect_WasSet = true; + } + } + else if (etc->cfFormat == m_Format_DropDescription) + { + // drop description contains only name of dest folder without full path + #ifdef SHOW_DEBUG_DRAG + if (size == sizeof(MY_DROPDESCRIPTION)) + { + // const MY_DROPDESCRIPTION *s = (const MY_DROPDESCRIPTION *)src; + // PRF3_W(s->szMessage); + // PRF3_W(s->szInsert); + } + #endif + } + else if (etc->cfFormat == m_Format_TargetCLSID) + { + // it's called after call QueryContinueDrag() (keyState & MK_LBUTTON) == 0 + // Shell File System Folder (explorer) guid: F3364BA0-65B9-11CE-A9BA-00AA004AE837 + #ifdef SHOW_DEBUG_DRAG + if (size == 16) + { + PrintFormat_GUIDToStringW((const Byte *)src); + } + #endif + } + else if (etc->cfFormat == m_Format_DisableDragText) + { + // (size == 4) (UInt32 value) + // value==0 : if drag to folder item or folder + // value==1 : if drag to file or non list_view */ + } + else if ( + etc->cfFormat == m_Format_IsShowingLayered || + etc->cfFormat == m_Format_IsShowingText) + { + // (size == 4) (UInt32 value) value==0 : + } + else + hres = DV_E_FORMATETC; + // hres = E_NOTIMPL; // for debug + // hres = DV_E_FORMATETC; // for debug + } + + GlobalUnlock(medium->hGlobal); + return hres; +} + + + +static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal) +{ + /* GlobalSize() returns 0: If the specified handle + is not valid or if the object has been discarded */ + const SIZE_T size = GlobalSize(srcGlobal); + if (size == 0) + return NULL; + // GlobalLock() can return NULL, if memory block has a zero-byte size + const void *src = GlobalLock(srcGlobal); + if (!src) + return NULL; + HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); + if (destGlobal) + { + void *dest = GlobalLock(destGlobal); + if (!dest) + { + GlobalFree(destGlobal); + destGlobal = NULL; + } + else + { + memcpy(dest, src, size); + GlobalUnlock(destGlobal); + } + } + GlobalUnlock(srcGlobal); + return destGlobal; +} + + +static bool Medium_CopyFrom(LPSTGMEDIUM medium, const void *data, size_t size) +{ + medium->tymed = TYMED_NULL; + medium->pUnkForRelease = NULL; + medium->hGlobal = NULL; + const HGLOBAL global = GlobalAlloc(GHND | GMEM_SHARE, size); + if (!global) + return false; + void *dest = GlobalLock(global); + if (!dest) + { + GlobalFree(global); + return false; + } + memcpy(dest, data, size); + GlobalUnlock(global); + medium->hGlobal = global; + medium->tymed = TYMED_HGLOBAL; + return true; +} + + +Z7_COMWF_B CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium) +{ + try { + PRF_(PrintFormat("-- GetData", etc->cfFormat)) + + medium->tymed = TYMED_NULL; + medium->pUnkForRelease = NULL; + medium->hGlobal = NULL; + + if (NeedCall_Copy && !Copy_WasCalled) + CopyFromPanelTo_Folder(); + + // PRF3("+ CDataObject::GetData"); + // PrintFormat(etc->cfFormat); + HGLOBAL global; + RINOK(QueryGetData(etc)) + + /* + if (etc->cfFormat == m_Format_FileOpFlags) + global = m_hGlobal_FileOpFlags; + else if (etc->cfFormat == m_Format_PreferredDropEffect) + { + // Explorer requests PreferredDropEffect only if Move/Copy selection is possible: + // Shift is not pressed and Ctrl is not pressed + PRF3("------ CDataObject::GetData() PreferredDropEffect"); + global = m_hGlobal_PreferredDropEffect; + } + else + */ + if (etc->cfFormat == m_Etc.cfFormat) // CF_HDROP + global = UsePreGlobal ? m_hGlobal_HDROP_Pre : m_hGlobal_HDROP_Final; + else if (etc->cfFormat == m_Format_7zip_GetTransfer) + { + CDataObject_GetTransfer transfer; + if (m_DestDirPrefix_FromTarget_WasSet) + { + transfer.Flags |= k_SourceFlags_SetTargetFolder; + } + if (!DestDirPrefix_FromTarget.IsEmpty()) + { + transfer.Flags |= k_SourceFlags_SetTargetFolder_NonEmpty; + } + if (IsTempFiles) + { + transfer.Flags |= k_SourceFlags_TempFiles; + transfer.Flags |= k_SourceFlags_WaitFinish; + transfer.Flags |= k_SourceFlags_NeedExtractOpToFs; + if (UsePreGlobal) + transfer.Flags |= k_SourceFlags_NamesAreParent; + } + else + transfer.Flags |= k_SourceFlags_DoNotWaitFinish; + + if (IsRightButton) + transfer.Flags |= k_SourceFlags_RightButton; + else + transfer.Flags |= k_SourceFlags_LeftButton; + + if (DoNotProcessInTarget) + transfer.Flags |= k_SourceFlags_DoNotProcessInTarget; + if (Copy_WasCalled) + transfer.Flags |= k_SourceFlags_Copy_WasCalled; + + if (Medium_CopyFrom(medium, &transfer, sizeof(transfer))) + return S_OK; + return E_OUTOFMEMORY; + } + else + return DV_E_FORMATETC; + + if (!global) + return DV_E_FORMATETC; + medium->tymed = m_Etc.tymed; + medium->hGlobal = DuplicateGlobalMem(global); + if (!medium->hGlobal) + return E_OUTOFMEMORY; + return S_OK; + } catch(...) { return E_FAIL; } +} + +Z7_COMWF_B CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */) +{ + PRF3("CDataObject::GetDataHere()"); + // Seems Windows doesn't call it, so we will not implement it. + return E_UNEXPECTED; +} + + +/* + IDataObject::QueryGetData() Determines whether the data object is capable of + rendering the data as specified. Objects attempting a paste or drop + operation can call this method before calling IDataObject::GetData + to get an indication of whether the operation may be successful. + + The client of a data object calls QueryGetData to determine whether + passing the specified FORMATETC structure to a subsequent call to + IDataObject::GetData is likely to be successful. + + we check Try_QueryGetData with CF_HDROP +*/ + +Z7_COMWF_B CDataObject::QueryGetData(LPFORMATETC etc) +{ + PRF3("-- CDataObject::QueryGetData()"); + if ( etc->cfFormat == m_Etc.cfFormat // CF_HDROP + || etc->cfFormat == m_Format_7zip_GetTransfer + // || (etc->cfFormat == m_Format_FileOpFlags && (HGLOBAL)m_hGlobal_FileOpFlags) + // || (etc->cfFormat == m_Format_PreferredDropEffect && (HGLOBAL)m_hGlobal_PreferredDropEffect) + ) + { + } + else + return DV_E_FORMATETC; + if (etc->dwAspect != m_Etc.dwAspect) + return DV_E_DVASPECT; + /* GetData(): It is possible to specify more than one medium by using the Boolean OR + operator, allowing the method to choose the best medium among those specified. */ + if ((etc->tymed & m_Etc.tymed) == 0) + return DV_E_TYMED; + return S_OK; +} + +Z7_COMWF_B CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc) +{ + // we don't enumerate for DATADIR_SET. Seems it can work without it. + if (direction != DATADIR_GET) + return E_NOTIMPL; + // we don't enumerate for m_Format_FileOpFlags also. Seems it can work without it. + return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc); +} + + + +//////////////////////////////////////////////////////// + +class CDropSource Z7_final: + public IDropSource, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_1_MT(IDropSource) + STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState) Z7_override; + STDMETHOD(GiveFeedback)(DWORD effect) Z7_override; + + DWORD m_Effect; +public: + CDataObject *DataObjectSpec; + CMyComPtr DataObject; + + HRESULT DragProcessing_HRESULT; + bool DragProcessing_WasFinished; + + CDropSource(): + m_Effect(DROPEFFECT_NONE), + // Panel(NULL), + DragProcessing_HRESULT(S_OK), + DragProcessing_WasFinished(false) + {} +}; + +// static bool g_Debug = 0; + + +Z7_COMWF_B CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState) +{ + // try { + + /* Determines whether a drag-and-drop operation should be continued, canceled, or completed. + escapePressed : Indicates whether the Esc key has been pressed + since the previous call to QueryContinueDrag + or to DoDragDrop if this is the first call to QueryContinueDrag: + TRUE : the end user has pressed the escape key; + FALSE : it has not been pressed. + keyState : The current state of the keyboard modifier keys on the keyboard. + Possible values can be a combination of any of the flags: + MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON. + */ + #ifdef SHOW_DEBUG_DRAG + { + AString s ("CDropSource::QueryContinueDrag()"); + s.Add_Space(); + s += "keystate="; + s.Add_UInt32(keyState); + PRF4(s); + } + #endif + + /* + if ((keyState & MK_LBUTTON) == 0) + { + // PRF4("CDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) == 0"); + g_Debug = true; + } + else + { + // PRF4("CDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0"); + } + */ + + if (escapePressed) + { + // The drag operation should be canceled with no drop operation occurring. + DragProcessing_WasFinished = true; + DragProcessing_HRESULT = DRAGDROP_S_CANCEL; + return DRAGDROP_S_CANCEL; + } + + if (DragProcessing_WasFinished) + return DragProcessing_HRESULT; + + if ((keyState & MK_RBUTTON) != 0) + { + if (!DataObjectSpec->IsRightButton) + { + DragProcessing_WasFinished = true; + DragProcessing_HRESULT = DRAGDROP_S_CANCEL; + return DRAGDROP_S_CANCEL; + } + return S_OK; + } + + if ((keyState & MK_LBUTTON) != 0) + { + if (DataObjectSpec->IsRightButton) + { + DragProcessing_WasFinished = true; + DragProcessing_HRESULT = DRAGDROP_S_CANCEL; + return DRAGDROP_S_CANCEL; + } + /* The drag operation should continue. This result occurs if no errors are detected, + the mouse button starting the drag-and-drop operation has not been released, + and the Esc key has not been detected. */ + return S_OK; + } + { + // the mouse button starting the drag-and-drop operation has been released. + + /* Win10 probably calls DragOver()/GiveFeedback() just before LBUTTON releasing. + so m_Effect is effect returned by DropTarget::DragOver() + just before LBUTTON releasing. + So here we can use Effect sent to last GiveFeedback() */ + + if (m_Effect == DROPEFFECT_NONE) + { + DragProcessing_WasFinished = true; + DragProcessing_HRESULT = DRAGDROP_S_CANCEL; + // Drop target cannot accept the data. So we cancel drag and drop + // maybe return DRAGDROP_S_DROP also OK here ? + // return DRAGDROP_S_DROP; // for debug + return DRAGDROP_S_CANCEL; + } + + // we switch to real names for items that will be created in temp folder + DataObjectSpec->UsePreGlobal = false; + DataObjectSpec->Copy_HRESULT = S_OK; + // MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed); + /* + if (DataObjectSpec->IsRightButton) + return DRAGDROP_S_DROP; + */ + + if (DataObjectSpec->IsTempFiles) + { + if (!DataObjectSpec->DestDirPrefix_FromTarget.IsEmpty()) + { + /* we know the destination Path. + So we can copy or extract items later in Source with simpler code. */ + DataObjectSpec->DoNotProcessInTarget = true; + // return DRAGDROP_S_CANCEL; + } + else + { + DataObjectSpec->NeedCall_Copy = true; + /* + if (Copy_HRESULT != S_OK || !Messages.IsEmpty()) + { + DragProcessing_WasFinished = true; + DragProcessing_HRESULT = DRAGDROP_S_CANCEL; + return DRAGDROP_S_CANCEL; + } + */ + } + } + DragProcessing_HRESULT = DRAGDROP_S_DROP; + DragProcessing_WasFinished = true; + return DRAGDROP_S_DROP; + } + // } catch(...) { return E_FAIL; } +} + + +Z7_COMWF_B CDropSource::GiveFeedback(DWORD effect) +{ + // PRF3("CDropSource::GiveFeedback"); + /* Enables a source application to give visual feedback to the end user + during a drag-and-drop operation by providing the DoDragDrop function + with an enumeration value specifying the visual effect. + in (effect): + The DROPEFFECT value returned by the most recent call to + IDropTarget::DragEnter, + IDropTarget::DragOver, + or DROPEFFECT_NONE after IDropTarget::DragLeave. + 0: DROPEFFECT_NONE + 1: DROPEFFECT_COPY + 2: DROPEFFECT_MOVE + 4: DROPEFFECT_LINK + 0x80000000: DROPEFFECT_SCROLL + The dwEffect parameter can include DROPEFFECT_SCROLL, indicating that the + source should put up the drag-scrolling variation of the appropriate pointer. + */ + m_Effect = effect; + + #ifdef SHOW_DEBUG_DRAG + AString w ("GiveFeedback effect="); + if (effect & DROPEFFECT_SCROLL) + w += " SCROLL "; + w.Add_UInt32(effect & ~DROPEFFECT_SCROLL); + // if (g_Debug) + PRF4(w); + #endif + + /* S_OK : no special drag and drop cursors. + Maybe it's for case where we created custom custom cursors. + DRAGDROP_S_USEDEFAULTCURSORS: Indicates successful completion of the method, + and requests OLE to update the cursor using the OLE-provided default cursors. */ + // return S_OK; // for debug + return DRAGDROP_S_USEDEFAULTCURSORS; +} + + + +/* +static bool Global_SetUInt32(NMemory::CGlobal &hg, const UInt32 v) +{ + if (!hg.Alloc(GHND | GMEM_SHARE, sizeof(v))) + return false; + NMemory::CGlobalLock dropLock(hg); + *(UInt32 *)dropLock.GetPointer() = v; + return true; +} +*/ + +static bool CopyNamesToHGlobal(NMemory::CGlobal &hgDrop, const UStringVector &names) +{ + size_t totalLen = 1; + + #ifndef _UNICODE + if (!g_IsNT) + { + AStringVector namesA; + unsigned i; + for (i = 0; i < names.Size(); i++) + namesA.Add(GetSystemString(names[i])); + for (i = 0; i < namesA.Size(); i++) + totalLen += namesA[i].Len() + 1; + + if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLen * sizeof(CHAR) + sizeof(DROPFILES))) + return false; + + NMemory::CGlobalLock dropLock(hgDrop); + DROPFILES *dropFiles = (DROPFILES *)dropLock.GetPointer(); + if (!dropFiles) + return false; + dropFiles->fNC = FALSE; + dropFiles->pt.x = 0; + dropFiles->pt.y = 0; + dropFiles->pFiles = sizeof(DROPFILES); + dropFiles->fWide = FALSE; + CHAR *p = (CHAR *) (void *) ((BYTE *)dropFiles + sizeof(DROPFILES)); + for (i = 0; i < namesA.Size(); i++) + { + const AString &s = namesA[i]; + const unsigned fullLen = s.Len() + 1; + MyStringCopy(p, (const char *)s); + p += fullLen; + totalLen -= fullLen; + } + *p = 0; + } + else + #endif + { + unsigned i; + for (i = 0; i < names.Size(); i++) + totalLen += names[i].Len() + 1; + + if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLen * sizeof(WCHAR) + sizeof(DROPFILES))) + return false; + + NMemory::CGlobalLock dropLock(hgDrop); + DROPFILES *dropFiles = (DROPFILES *)dropLock.GetPointer(); + if (!dropFiles) + return false; + /* fNC: + TRUE : pt specifies the screen coordinates of a point in a window's nonclient area. + FALSE : pt specifies the client coordinates of a point in the client area. + */ + dropFiles->fNC = FALSE; + dropFiles->pt.x = 0; + dropFiles->pt.y = 0; + dropFiles->pFiles = sizeof(DROPFILES); + dropFiles->fWide = TRUE; + WCHAR *p = (WCHAR *) (void *) ((BYTE *)dropFiles + sizeof(DROPFILES)); + for (i = 0; i < names.Size(); i++) + { + const UString &s = names[i]; + const unsigned fullLen = s.Len() + 1; + MyStringCopy(p, (const WCHAR *)s); + p += fullLen; + totalLen -= fullLen; + } + *p = 0; + } + // if (totalLen != 1) return false; + return true; +} + + +void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */, bool isRightButton) +{ + PRF("CPanel::OnDrag"); + if (!DoesItSupportOperations()) + return; + + CDisableTimerProcessing disableTimerProcessing2(*this); + + CRecordVector indices; + Get_ItemIndices_Operated(indices); + if (indices.Size() == 0) + return; + + // CSelectedState selState; + // SaveSelectedState(selState); + + const bool isFSFolder = IsFSFolder(); + // why we don't allow drag with rightButton from archive? + if (!isFSFolder && isRightButton) + return; + + UString dirPrefix; + CTempDir tempDirectory; + + CDataObject *dataObjectSpec = new CDataObject; + CMyComPtr dataObject = dataObjectSpec; + dataObjectSpec->IsRightButton = isRightButton; + + { + /* we can change confirmation mode and another options. + Explorer target requests that FILEOP_FLAGS value. */ + /* + const FILEOP_FLAGS fopFlags = + FOF_NOCONFIRMATION + | FOF_NOCONFIRMMKDIR + | FOF_NOERRORUI + | FOF_SILENT; + // | FOF_SIMPLEPROGRESS; // it doesn't work as expected in Win10 + Global_SetUInt32(dataObjectSpec->m_hGlobal_FileOpFlags, fopFlags); + // dataObjectSpec->m_hGlobal_FileOpFlags.Free(); // for debug : disable these options + */ + } + { + /* we can change Preferred DropEffect. + Explorer target requests that FILEOP_FLAGS value. */ + /* + const DWORD effect = DROPEFFECT_MOVE; // DROPEFFECT_COPY; + Global_SetUInt32(dataObjectSpec->m_hGlobal_PreferredDropEffect, effect); + */ + } + if (isFSFolder) + { + dirPrefix = GetFsPath(); // why this in 22.01 ? + dataObjectSpec->UsePreGlobal = false; + // dataObjectSpec->IsTempFiles = false; + } + else + { + if (!tempDirectory.Create(kTempDirPrefix)) + { + MessageBox_Error(L"Can't create temp folder"); + return; + } + dirPrefix = fs2us(tempDirectory.GetPath()); + { + UStringVector names; + names.Add(dirPrefix); + dataObjectSpec->IsTempFiles = true; + dataObjectSpec->UsePreGlobal = true; + if (!CopyNamesToHGlobal(dataObjectSpec->m_hGlobal_HDROP_Pre, names)) + return; + } + NFile::NName::NormalizeDirPathPrefix(dirPrefix); + /* + { + FString path2 = dirPrefix; + path2 += "1.txt"; + CopyFileW(L"C:\\1\\1.txt", path2, FALSE); + } + */ + } + + { + UStringVector names; + // names variable is USED for drag and drop from 7-zip to Explorer or to 7-zip archive folder. + // names variable is NOT USED for drag and drop from 7-zip to 7-zip File System folder. + FOR_VECTOR (i, indices) + { + const UInt32 index = indices[i]; + UString s; + if (isFSFolder) + s = GetItemRelPath(index); + else + { + s = GetItemName(index); + /* + // We use (keepAndReplaceEmptyPrefixes = true) in CAgentFolder::Extract + // So the following code is not required. + // Maybe we also can change IFolder interface and send some flag also. + if (s.IsEmpty()) + { + // Correct_FsFile_Name("") returns "_". + // If extracting code removes empty folder prefixes from path (as it was in old version), + // Explorer can't find "_" folder in temp folder. + // We can ask Explorer to copy parent temp folder "7zE" instead. + names.Clear(); + names.Add(dirPrefix2); + break; + } + */ + s = Get_Correct_FsFile_Name(s); + } + names.Add(dirPrefix + s); + } + if (!CopyNamesToHGlobal(dataObjectSpec->m_hGlobal_HDROP_Final, names)) + return; + } + + CDropSource *dropSourceSpec = new CDropSource; + CMyComPtr dropSource = dropSourceSpec; + dataObjectSpec->Panel = this; + dataObjectSpec->Indices = indices; + dataObjectSpec->SrcDirPrefix_Temp = dirPrefix; + + dropSourceSpec->DataObjectSpec = dataObjectSpec; + dropSourceSpec->DataObject = dataObjectSpec; + + + /* + CTime - file creation timestamp. + There are two operations in Windows with Drag and Drop: + COPY_OPERATION : icon with Plus sign : CTime will be set as current_time. + MOVE_OPERATION : icon without Plus sign : CTime will be preserved. + + Note: if we call DoDragDrop() with (effectsOK = DROPEFFECT_MOVE), then + it will use MOVE_OPERATION and CTime will be preserved. + But MoveFile() function doesn't preserve CTime, if different volumes are used. + Why it's so? + Does DoDragDrop() use some another function (not MoveFile())? + + if (effectsOK == DROPEFFECT_COPY) it works as COPY_OPERATION + + if (effectsOK == DROPEFFECT_MOVE) drag works as MOVE_OPERATION + + if (effectsOK == (DROPEFFECT_COPY | DROPEFFECT_MOVE)) + { + if we drag file to same volume, then Windows suggests: + CTRL - COPY_OPERATION + [default] - MOVE_OPERATION + + if we drag file to another volume, then Windows suggests + [default] - COPY_OPERATION + SHIFT - MOVE_OPERATION + } + + We want to use MOVE_OPERATION for extracting from archive (open in 7-Zip) to Explorer: + It has the following advantages: + 1) it uses fast MOVE_OPERATION instead of slow COPY_OPERATION and DELETE, if same volume. + 2) it preserves CTime + + Some another programs support only COPY_OPERATION. + So we can use (DROPEFFECT_COPY | DROPEFFECT_MOVE) + + Also another program can return from DoDragDrop() before + files using. But we delete temp folder after DoDragDrop(), + and another program can't open input files in that case. + + We create objects: + IDropSource *dropSource + IDataObject *dataObject + if DropTarget is 7-Zip window, then 7-Zip's + IDropTarget::DragOver() sets DestDirPrefix_FromTarget in IDataObject. + and + IDropSource::QueryContinueDrag() sets DoNotProcessInTarget, if DestDirPrefix_FromTarget is not empty. + So we can detect destination path after DoDragDrop(). + Now we don't know any good way to detect destination path for D&D to Explorer. + */ + + /* + DWORD effectsOK = DROPEFFECT_COPY; + if (moveIsAllowed) + effectsOK |= DROPEFFECT_MOVE; + */ + const bool moveIsAllowed = isFSFolder; + _panelCallback->DragBegin(); + PRF("=== DoDragDrop()"); + DWORD effect = 0; + // 18.04: was changed + const DWORD effectsOK = DROPEFFECT_MOVE | DROPEFFECT_COPY; + // effectsOK |= (1 << 8); // for debug + HRESULT res = ::DoDragDrop(dataObject, dropSource, effectsOK, &effect); + PRF("=== After DoDragDrop()"); + _panelCallback->DragEnd(); + + /* + Win10 drag and drop to Explorer: + DoDragDrop() output variables: + for MOVE operation: + { + effect == DROPEFFECT_NONE; + dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_MOVE; + } + for COPY operation: + { + effect == DROPEFFECT_COPY; + dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_COPY; + } + DOCs: The source inspects the two values that can be returned by the target. + If both are set to DROPEFFECT_MOVE, it completes the unoptimized move + by deleting the original data. Otherwise, the target did an optimized + move and the original data has been deleted. + + We didn't see "unoptimized move" case (two values of DROPEFFECT_MOVE), + where we still need to delete source files. + So we don't delete files after DoDragDrop(). + + Also DOCs say for "optimized move": + The target also calls the data object's IDataObject::SetData method and passes + it a CFSTR_PERFORMEDDROPEFFECT format identifier set to DROPEFFECT_NONE. + but actually in Win10 we always have + (dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_MOVE) + for any MOVE operation. + */ + + const bool canceled = (res == DRAGDROP_S_CANCEL); + + CDisableNotify disableNotify(*this); + + if (res == DRAGDROP_S_DROP) + { + /* DRAGDROP_S_DROP is returned. It means that + - IDropTarget::Drop() was called, + - IDropTarget::Drop() returned (ret_code >= 0) + */ + res = dataObjectSpec->Copy_HRESULT; + bool need_Process = dataObjectSpec->DoNotProcessInTarget; + if (dataObjectSpec->m_Transfer_WasSet) + { + if (dataObjectSpec->m_Transfer.Target.FuncType == k_DragTargetMode_Drop_End) + { + if (dataObjectSpec->m_Transfer.Target.Flags & k_TargetFlags_MustBeProcessedBySource) + need_Process = true; + } + } + + if (need_Process) + if (!dataObjectSpec->DestDirPrefix_FromTarget.IsEmpty()) + { + if (!NFile::NName::IsAltStreamPrefixWithColon(dataObjectSpec->DestDirPrefix_FromTarget)) + NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->DestDirPrefix_FromTarget); + CCopyToOptions options; + options.folder = dataObjectSpec->DestDirPrefix_FromTarget; + // if MOVE is not allowed, we just use COPY operation + /* it was 7-zip's Target that set non-empty dataObjectSpec->DestDirPrefix_FromTarget. + it means that target didn't completed operation, + and we can use (effect) value returned by target via DoDragDrop(). + as indicator of type of operation + */ + // options.moveMode = (moveIsAllowed && effect == DROPEFFECT_MOVE) // before v23.00: + options.moveMode = moveIsAllowed; + if (moveIsAllowed) + { + if (dataObjectSpec->m_Transfer_WasSet) + options.moveMode = ( + dataObjectSpec->m_Transfer.Target.Cmd_Effect == DROPEFFECT_MOVE); + else + options.moveMode = (effect == DROPEFFECT_MOVE); + // we expect (DROPEFFECT_MOVE) as indicator of move operation for Drag&Drop MOVE ver 22.01. + } + res = CopyTo(options, indices, &dataObjectSpec->Messages); + } + /* + if (effect & DROPEFFECT_MOVE) + RefreshListCtrl(selState); + */ + } + else + { + // we ignore E_UNEXPECTED that is returned if we drag file to printer + if (res != DRAGDROP_S_CANCEL + && res != S_OK + && res != E_UNEXPECTED) + MessageBox_Error_HRESULT(res); + res = dataObjectSpec->Copy_HRESULT; + } + + if (!dataObjectSpec->Messages.IsEmpty()) + { + CMessagesDialog messagesDialog; + messagesDialog.Messages = &dataObjectSpec->Messages; + messagesDialog.Create((*this)); + } + + if (res != S_OK && res != E_ABORT) + { + // we restore Notify before MessageBox_Error_HRESULT. So we will see files selection + disableNotify.Restore(); + // SetFocusToList(); + MessageBox_Error_HRESULT(res); + } + if (res == S_OK && dataObjectSpec->Messages.IsEmpty() && !canceled) + KillSelection(); +} + + + + + +CDropTarget::CDropTarget(): + m_IsRightButton(false), + m_GetTransfer_WasSuccess(false), + m_DropIsAllowed(false), + m_PanelDropIsAllowed(false), + // m_DropHighlighted_SelectionIndex(-1), + // m_SubFolderIndex(-1), + m_Panel(NULL), + m_IsAppTarget(false), + m_TargetPath_WasSent_ToDataObject(false), + m_TargetPath_NonEmpty_WasSent_ToDataObject(false), + m_Transfer_WasSent_ToDataObject(false), + App(NULL), + SrcPanelIndex(-1), + TargetPanelIndex(-1) +{ + m_Format_7zip_SetTargetFolder = RegisterClipboardFormat(k_Format_7zip_SetTargetFolder); + m_Format_7zip_SetTransfer = RegisterClipboardFormat(k_Format_7zip_SetTransfer); + m_Format_7zip_GetTransfer = RegisterClipboardFormat(k_Format_7zip_GetTransfer); + + m_ProcessId = GetCurrentProcessId(); + // m_TransactionId = ((UInt64)m_ProcessId << 32) + 1; + // ClearState(); +} + +// clear internal state +void CDropTarget::ClearState() +{ + m_DataObject.Release(); + m_SourcePaths.Clear(); + + m_IsRightButton = false; + + m_GetTransfer_WasSuccess = false; + m_DropIsAllowed = false; + + m_PanelDropIsAllowed = false; + // m_SubFolderIndex = -1; + // m_DropHighlighted_SubFolderName.Empty(); + m_Panel = NULL; + m_IsAppTarget = false; + m_TargetPath_WasSent_ToDataObject = false; + m_TargetPath_NonEmpty_WasSent_ToDataObject = false; + m_Transfer_WasSent_ToDataObject = false; +} + +/* + IDataObject::QueryGetData() Determines whether the data object is capable of + rendering the data as specified. Objects attempting a paste or drop + operation can call this method before calling IDataObject::GetData + to get an indication of whether the operation may be successful. + + The client of a data object calls QueryGetData to determine whether + passing the specified FORMATETC structure to a subsequent call to + IDataObject::GetData is likely to be successful. + + We check Try_QueryGetData with CF_HDROP +*/ +/* +void CDropTarget::Try_QueryGetData(IDataObject *dataObject) +{ + FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK); +} +*/ + +static void ListView_SetItemState_DropHighlighted( + NControl::CListView &listView, int index, bool highlighted) +{ + // LVIS_DROPHILITED : The item is highlighted as a drag-and-drop target + /* + LVITEM item; + item.mask = LVIF_STATE; + item.iItem = index; + item.iSubItem = 0; + item.state = enable ? LVIS_DROPHILITED : 0; + item.stateMask = LVIS_DROPHILITED; + item.pszText = NULL; + listView.SetItem(&item); + */ + listView.SetItemState(index, highlighted ? LVIS_DROPHILITED : 0, LVIS_DROPHILITED); +} + +// Removes DropHighlighted state in ListView item, if it was set before +void CDropTarget::RemoveSelection() +{ + if (m_Panel) + { + m_Panel->m_DropHighlighted_SubFolderName.Empty(); + if (m_Panel->m_DropHighlighted_SelectionIndex >= 0) + { + ListView_SetItemState_DropHighlighted(m_Panel->_listView, + m_Panel->m_DropHighlighted_SelectionIndex, false); + m_Panel->m_DropHighlighted_SelectionIndex = -1; + } + } +} + +#ifdef UNDER_CE +#define ChildWindowFromPointEx(hwndParent, pt, uFlags) ChildWindowFromPoint(hwndParent, pt) +#endif + + +/* + PositionCursor() function sets m_Panel under cursor drop, and + m_SubFolderIndex/m_DropHighlighted_SubFolderName, if drop to some folder in Panel list. +*/ +/* +PositionCursor() uses as input variables: + m_DropIsAllowed must be set before PositionCursor() + if (m_DropHighlighted_SelectionIndex >= 0 && m_Panel) it uses m_Panel and removes previous selection +PositionCursor() sets + m_PanelDropIsAllowed + m_Panel + m_IsAppTarget + m_SubFolderIndex + m_DropHighlighted_SubFolderName + m_DropHighlighted_SelectionIndex +*/ +void CDropTarget::PositionCursor(const POINTL &ptl) +{ + RemoveSelection(); + + // m_SubFolderIndex = -1; + // m_DropHighlighted_SubFolderName.Empty(); + m_IsAppTarget = true; + m_Panel = NULL; + m_PanelDropIsAllowed = false; + + if (!m_DropIsAllowed) + return; + + POINT pt; + pt.x = ptl.x; + pt.y = ptl.y; + { + POINT pt2 = pt; + if (App->_window.ScreenToClient(&pt2)) + for (unsigned i = 0; i < kNumPanelsMax; i++) + if (App->IsPanelVisible(i)) + { + CPanel *panel = &App->Panels[i]; + if (panel->IsEnabled()) + if (::ChildWindowFromPointEx(App->_window, pt2, + CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) == (HWND)*panel) + { + m_Panel = panel; + m_IsAppTarget = false; + if ((int)i == SrcPanelIndex) + return; // we don't allow to drop to source panel + break; + } + } + } + + m_PanelDropIsAllowed = true; + + if (!m_Panel) + { + if (TargetPanelIndex >= 0) + m_Panel = &App->Panels[TargetPanelIndex]; + // we don't need to find item in panel + return; + } + + // we will try to find and highlight drop folder item in listView under cursor + /* + m_PanelDropIsAllowed = m_Panel->DoesItSupportOperations(); + if (!m_PanelDropIsAllowed) + return; + */ + /* now we don't allow drop to subfolder under cursor, if dest panel is archive. + Another code must be fixed for that case, where we must use m_SubFolderIndex/m_DropHighlighted_SubFolderName */ + if (!m_Panel->IsFsOrPureDrivesFolder()) + return; + + if (::WindowFromPoint(pt) != (HWND)m_Panel->_listView) + return; + + LVHITTESTINFO info; + m_Panel->_listView.ScreenToClient(&pt); + info.pt = pt; + const int index = ListView_HitTest(m_Panel->_listView, &info); + if (index < 0) + return; + const unsigned realIndex = m_Panel->GetRealItemIndex(index); + if (realIndex == kParentIndex) + return; + if (!m_Panel->IsItem_Folder(realIndex)) + return; + // m_SubFolderIndex = (int)realIndex; + m_Panel->m_DropHighlighted_SubFolderName = m_Panel->GetItemName(realIndex); + ListView_SetItemState_DropHighlighted(m_Panel->_listView, index, true); + m_Panel->m_DropHighlighted_SelectionIndex = index; +} + + +/* returns true, if !m_IsAppTarget + and target is FS folder or altStream folder +*/ + +UInt32 CDropTarget::GetFolderType() const +{ + if (m_IsAppTarget || !m_Panel) + return k_FolderType_None; + if (m_Panel->IsFSFolder() || + (m_Panel->IsFSDrivesFolder() + && m_Panel->m_DropHighlighted_SelectionIndex >= 0)) + return k_FolderType_Fs; + if (m_Panel->IsAltStreamsFolder()) + return k_FolderType_AltStreams; + if (m_Panel->IsArcFolder()) + return k_FolderType_Archive; + return k_FolderType_Unknown; +} + +bool CDropTarget::IsFsFolderPath() const +{ + if (m_IsAppTarget || !m_Panel) + return false; + if (m_Panel->IsFSFolder()) + return true; + if (m_Panel->IsAltStreamsFolder()) + return true; + return m_Panel->IsFSDrivesFolder() && + m_Panel->m_DropHighlighted_SelectionIndex >= 0; +} + + +#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } + +static bool DataObject_GetData_GetTransfer(IDataObject *dataObject, + UINT a_Format_7zip_GetTransfer, CDataObject_GetTransfer &transfer) +{ + FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)a_Format_7zip_GetTransfer); + NCOM::CStgMedium medium; + const HRESULT res = dataObject->GetData(&etc, &medium); + if (res != S_OK) + return false; + if (medium.tymed != TYMED_HGLOBAL) + return false; + const size_t size = GlobalSize(medium.hGlobal); + if (size < sizeof(transfer)) + return false; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const CDataObject_GetTransfer *t = (const CDataObject_GetTransfer *)dropLock.GetPointer(); + if (!t) + return false; + if (!t->Check()) // isSetData + return false; + transfer = *t; + return true; +} + +/* + returns true, if all m_SourcePaths[] items are same drive + as destination drop path in m_Panel +*/ +bool CDropTarget::IsItSameDrive() const +{ + if (!m_Panel) + return false; + if (!IsFsFolderPath()) + return false; + + UString drive; + + if (m_Panel->IsFSFolder()) + { + drive = m_Panel->GetDriveOrNetworkPrefix(); + if (drive.IsEmpty()) + return false; + } + else if (m_Panel->IsFSDrivesFolder() + && m_Panel->m_DropHighlighted_SelectionIndex >= 0) + { + drive = m_Panel->m_DropHighlighted_SubFolderName; + drive.Add_PathSepar(); + } + else + return false; + + if (m_SourcePaths.Size() == 0) + return false; + + FOR_VECTOR (i, m_SourcePaths) + { + if (!m_SourcePaths[i].IsPrefixedBy_NoCase(drive)) + return false; + } + return true; +} + + +/* + There are 2 different actions, when we drag to 7-Zip: + 1) if target panel is "7-Zip" FS and any of the 2 cases: + - Drag from any non "7-Zip" program; + or + - Drag from "7-Zip" to non-panel area of "7-Zip". + We want to create new archive for that operation with "Add to Archive" window. + 2) all another operations work as usual file COPY/MOVE + - Drag from "7-Zip" FS to "7-Zip" FS. + COPY/MOVE are supported. + - Drag to open archive in 7-Zip. + We want to update archive. + We replace COPY to MOVE. + - Drag from "7-Zip" archive to "7-Zip" FS. + We replace COPY to MOVE. +*/ + +// we try to repeat Explorer's effects. +// out: 0 - means that use default effect +static DWORD GetEffect_ForKeys(DWORD keyState) +{ + if (keyState & MK_CONTROL) + { + if (keyState & MK_ALT) + return 0; + if (keyState & MK_SHIFT) + return DROPEFFECT_LINK; // CONTROL + SHIFT + return DROPEFFECT_COPY; // CONTROL + } + // no CONTROL + if (keyState & MK_SHIFT) + { + if (keyState & MK_ALT) + return 0; + return DROPEFFECT_MOVE; // SHIFT + } + // no CONTROL, no SHIFT + if (keyState & MK_ALT) + return DROPEFFECT_LINK; // ALT + return 0; +} + + +/* GetEffect() uses m_TargetPath_WasSentToDataObject + to disale MOVE operation, if Source is not 7-Zip +*/ +DWORD CDropTarget::GetEffect(DWORD keyState, POINTL /* pt */, DWORD allowedEffect) const +{ + // (DROPEFFECT_NONE == 0) + if (!m_DropIsAllowed || !m_PanelDropIsAllowed) + return 0; + if (!IsFsFolderPath() || !m_TargetPath_WasSent_ToDataObject) + { + // we don't allow MOVE, if Target is archive or Source is not 7-Zip + // disabled for debug: + // allowedEffect &= ~DROPEFFECT_MOVE; + } + DWORD effect; + { + effect = GetEffect_ForKeys(keyState); + if (effect == DROPEFFECT_LINK) + return 0; + effect &= allowedEffect; + } + if (effect == 0) + { + if (allowedEffect & DROPEFFECT_COPY) + effect = DROPEFFECT_COPY; + if (allowedEffect & DROPEFFECT_MOVE) + { + /* MOVE operation can be optimized. So MOVE is preferred way + for default action, if Source and Target are at same drive */ + if (IsItSameDrive()) + effect = DROPEFFECT_MOVE; + } + } + return effect; +} + + +/* returns: + - target folder path prefix, if target is FS folder + - empty string, if target is not FS folder +*/ +UString CDropTarget::GetTargetPath() const +{ + if (!IsFsFolderPath()) + return UString(); + UString path = m_Panel->GetFsPath(); + if (/* m_SubFolderIndex >= 0 && */ + !m_Panel->m_DropHighlighted_SubFolderName.IsEmpty()) + { + path += m_Panel->m_DropHighlighted_SubFolderName; + path.Add_PathSepar(); + } + return path; +} + + +/* +if IDropSource is Win10-Explorer +-------------------------------- + As in MS DOCs: + The source inspects the two (effect) values that can be returned by the target: + 1) SetData(CFSTR_PERFORMEDDROPEFFECT) + 2) returned value (*effect) by + CDropTarget::Drop(IDataObject *dataObject, DWORD keyState, + POINTL pt, DWORD *effect) + If both are set to DROPEFFECT_MOVE, Explorer completes the unoptimized move by deleting + the original data. + // Otherwise, the target did an optimized move and the original data has been deleted. +*/ + + +/* + Send targetPath from target to dataObject (to Source) + input: set (enablePath = false) to send empty path + returns true, if SetData() returns S_OK : (source is 7-zip) + returns false, if SetData() doesn't return S_OK : (source is Explorer) +*/ +bool CDropTarget::SendToSource_TargetPath_enable(IDataObject *dataObject, bool enablePath) +{ + m_TargetPath_NonEmpty_WasSent_ToDataObject = false; + UString path; + if (enablePath) + path = GetTargetPath(); + PRF("CDropTarget::SetPath"); + PRF_W(path); + if (!dataObject || m_Format_7zip_SetTargetFolder == 0) + return false; + FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)m_Format_7zip_SetTargetFolder); + STGMEDIUM medium; + medium.tymed = etc.tymed; + medium.pUnkForRelease = NULL; + const size_t num = path.Len() + 1; // + (1 << 19) // for debug + medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, num * sizeof(wchar_t)); + if (!medium.hGlobal) + return false; + // Sleep(1000); + wchar_t *dest = (wchar_t *)GlobalLock(medium.hGlobal); + // Sleep(1000); + bool res = false; + if (dest) + { + MyStringCopy(dest, (const wchar_t *)path); + GlobalUnlock(medium.hGlobal); + // OutputDebugString("m_DataObject->SetData"); + const BOOL release = FALSE; // that way is more simple for correct releasing. + // TRUE; // for debug : is not good for some cases. + /* If DropSource is Win10-Explorer, dataObject->SetData() returns E_NOTIMPL; */ + const HRESULT hres = dataObject->SetData(&etc, &medium, release); + // Sleep(1000); + res = (hres == S_OK); + } + + ReleaseStgMedium(&medium); + if (res && !path.IsEmpty()) + m_TargetPath_NonEmpty_WasSent_ToDataObject = true; + // Sleep(1000); + return res; +} + + +void CDropTarget::SendToSource_auto(IDataObject *dataObject, + const CTargetTransferInfo &info) +{ + /* we try to send target path to Source. + If Source is 7-Zip, then it will accept k_Format_7zip_SetTargetFolder. + That sent path will be non-Empty, if this target is FS folder and drop is allowed */ + bool need_Send = false; + if ( info.FuncType == k_DragTargetMode_Enter + || info.FuncType == k_DragTargetMode_Over + || (info.FuncType == k_DragTargetMode_Drop_Begin + // && targetOp_Cmd != NDragMenu::k_None + && info.Cmd_Type != NDragMenu::k_Cancel)) + // if (!g_CreateArchive_for_Drag_from_7zip) + need_Send = m_DropIsAllowed && m_PanelDropIsAllowed && IsFsFolderPath(); + m_TargetPath_WasSent_ToDataObject = SendToSource_TargetPath_enable(dataObject, need_Send); + SendToSource_TransferInfo(dataObject, info); +} + + +bool CDropTarget::SendToSource_TransferInfo(IDataObject *dataObject, + const CTargetTransferInfo &info) +{ + m_Transfer_WasSent_ToDataObject = false; + PRF("CDropTarget::SendToSource_TransferInfo"); + + if (!dataObject || m_Format_7zip_SetTransfer == 0) + return false; + FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)m_Format_7zip_SetTransfer); + STGMEDIUM medium; + medium.tymed = etc.tymed; + medium.pUnkForRelease = NULL; + CDataObject_SetTransfer transfer; + const size_t size = sizeof(transfer); // + (1 << 19) // for debug + // OutputDebugString("GlobalAlloc"); + medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); + // Sleep(1000); + if (!medium.hGlobal) + return false; + // OutputDebugString("GlobalLock"); + void *dest = (wchar_t *)GlobalLock(medium.hGlobal); + // Sleep(1000); + bool res = false; + if (dest) + { + transfer.Init(); + transfer.Target = info; + + memcpy(dest, &transfer, sizeof(transfer)); + GlobalUnlock(medium.hGlobal); + // OutputDebugString("m_DataObject->SetData"); + const BOOL release = FALSE; // that way is more simple for correct releasing. + // TRUE; // for debug : is not good for some cases + const HRESULT hres = dataObject->SetData(&etc, &medium, release); + res = (hres == S_OK); + } + + ReleaseStgMedium(&medium); + if (res) + m_Transfer_WasSent_ToDataObject = true; + return res; +} + + +bool CDropTarget::SendToSource_UInt32(IDataObject *dataObject, UINT format, UInt32 value) +{ + PRF("CDropTarget::Send_UInt32 (Performed)"); + + if (!dataObject || format == 0) + return false; + FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)format); + STGMEDIUM medium; + medium.tymed = etc.tymed; + medium.pUnkForRelease = NULL; + const size_t size = 4; + medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size); + if (!medium.hGlobal) + return false; + void *dest = GlobalLock(medium.hGlobal); + bool res = false; + if (dest) + { + *(UInt32 *)dest = value; + GlobalUnlock(medium.hGlobal); + // OutputDebugString("m_DataObject->SetData"); + const BOOL release = TRUE; + // FALSE; // for debug + /* If DropSource is Win10-Explorer, then (release == FALSE) doesn't work + and dataObject->SetData() returns E_NOTIMPL; + So we use release = TRUE; here */ + const HRESULT hres = dataObject->SetData(&etc, &medium, release); + // we return here without calling ReleaseStgMedium(). + return (hres == S_OK); + // Sleep(1000); + /* + if (we use release = TRUE), we expect that + - SetData() will release medium, and + - SetData() will set STGMEDIUM::tymed to (TYMED_NULL = 0). + but some "incorrect" SetData() implementations can keep STGMEDIUM::tymed unchanged. + And it's not safe to call ReleaseStgMedium() here for that case, + because DropSource also could release medium. + We can reset (medium.tymed = TYMED_NULL) manually here to disable + unsafe medium releasing in ReleaseStgMedium(). + */ + /* + if (release) + { + medium.tymed = TYMED_NULL; + medium.pUnkForRelease = NULL; + medium.hGlobal = NULL; + } + res = (hres == S_OK); + */ + } + ReleaseStgMedium(&medium); + return res; +} + + +void CDropTarget::LoadNames_From_DataObject(IDataObject *dataObject) +{ + // "\\\\.\\" prefix is possible for long names + m_DropIsAllowed = NShell::DataObject_GetData_HDROP_or_IDLIST_Names(dataObject, m_SourcePaths) == S_OK; +} + + +Z7_COMWF_B CDropTarget::DragEnter(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) +{ + /* *(effect): + - on input : value of the dwOKEffects parameter of the DoDragDrop() function. + - on return : must contain one of the DROPEFFECT flags, which indicates + what the result of the drop operation would be. + (pt): the current cursor coordinates in screen coordinates. + */ + PRF_(Print_Point("CDropTarget::DragEnter", keyState, pt, *effect)) + try { + + if ((keyState & (MK_RBUTTON | MK_MBUTTON)) != 0) + m_IsRightButton = true; + + LoadNames_From_DataObject(dataObject); + // Try_QueryGetData(dataObject); + // we will use (m_DataObject) later in DragOver() and DragLeave(). + m_DataObject = dataObject; + // return DragOver(keyState, pt, effect); + PositionCursor(pt); + CTargetTransferInfo target; + target.FuncType = k_DragTargetMode_Enter; + target.KeyState = keyState; + target.Point = pt; + target.OkEffects = *effect; + SendToSource_Drag(target); + + CDataObject_GetTransfer transfer; + m_GetTransfer_WasSuccess = DataObject_GetData_GetTransfer( + dataObject, m_Format_7zip_GetTransfer, transfer); + if (m_GetTransfer_WasSuccess) + { + if (transfer.Flags & k_SourceFlags_LeftButton) + m_IsRightButton = false; + else if (transfer.Flags & k_SourceFlags_RightButton) + m_IsRightButton = true; + } + + *effect = GetEffect(keyState, pt, *effect); + return S_OK; + } catch(...) { return E_FAIL; } +} + + +Z7_COMWF_B CDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD *effect) +{ + PRF_(Print_Point("CDropTarget::DragOver", keyState, pt, *effect)) + /* + For efficiency reasons, a data object is not passed in IDropTarget::DragOver. + The data object passed in the most recent call to IDropTarget::DragEnter + is available and can be used. + + When IDropTarget::DragOver has completed its operation, the DoDragDrop + function calls IDropSource::GiveFeedback so the source application can display + the appropriate visual feedback to the user. + */ + /* + we suppose that it's unexpected that (keyState) shows that mouse + button is not pressed, because such cases will be processed by + IDropSource::QueryContinueDrag() that returns DRAGDROP_S_DROP or DRAGDROP_S_CANCEL. + So DragOver() will not be called. + */ + + if ((keyState & MK_LBUTTON) == 0) + { + PRF4("CDropTarget::DragOver() (keyState & MK_LBUTTON) == 0"); + // g_Debug = true; + } + + try { + /* we suppose that source names were not changed after DragEnter() + so we don't request GetNames_From_DataObject() for each call of DragOver() */ + PositionCursor(pt); + CTargetTransferInfo target; + target.FuncType = k_DragTargetMode_Over; + target.KeyState = keyState; + target.Point = pt; + target.OkEffects = *effect; + SendToSource_Drag(target); + *effect = GetEffect(keyState, pt, *effect); + // *effect = 1 << 8; // for debug + return S_OK; + } catch(...) { return E_FAIL; } +} + + +Z7_COMWF_B CDropTarget::DragLeave() +{ + PRF4("CDropTarget::DragLeave"); + try { + RemoveSelection(); + // we send empty TargetPath to 7-Zip Source to clear value of TargetPath that was sent before + + CTargetTransferInfo target; + target.FuncType = k_DragTargetMode_Leave; + /* + target.KeyState = 0; + target.Point = pt; + pt.x = 0; // -1 + pt.y = 0; // -1 + target.Effect = 0; + */ + SendToSource_Drag(target); + ClearState(); + return S_OK; + } catch(...) { return E_FAIL; } +} + + +static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags); + +/* + We suppose that there was DragEnter/DragOver for same (POINTL pt) before Drop(). + But we can work without DragEnter/DragOver too. +*/ +Z7_COMWF_B CDropTarget::Drop(IDataObject *dataObject, DWORD keyState, + POINTL pt, DWORD *effect) +{ + PRF_(Print_Point("CDropTarget::Drop", keyState, pt, *effect)) + /* Drop() is called after SourceDrop::QueryContinueDrag() returned DRAGDROP_S_DROP. + So it's possible that Source have done some operations already. + */ + HRESULT hres = S_OK; + bool needDrop_by_Source = false; + DWORD opEffect = DROPEFFECT_NONE; + + try { + // we don't need m_DataObject reference anymore, because we use local (dataObject) + m_DataObject.Release(); + + /* in normal case : we called LoadNames_From_DataObject() in DragEnter() already. + But if by some reason DragEnter() was not called, + we need to call LoadNames_From_DataObject() before PositionCursor(). + */ + if (!m_DropIsAllowed) LoadNames_From_DataObject(dataObject); + PositionCursor(pt); + + CPanel::CDisableTimerProcessing2 disableTimerProcessing(m_Panel); + // CDisableNotify disableNotify2(m_Panel); + + UInt32 cmd = NDragMenu::k_None; + UInt32 cmdEffect = DROPEFFECT_NONE; + bool menu_WasShown = false; + if (m_IsRightButton && m_Panel) + { + UInt32 flagsMask; + if (m_Panel->IsArcFolder()) + flagsMask = (UInt32)1 << NDragMenu::k_Copy_ToArc; + else + { + flagsMask = (UInt32)1 << NDragMenu::k_AddToArc; + if (IsFsFolderPath()) + flagsMask |= (UInt32)1 << NDragMenu::k_Copy_Base; + } + // flagsMask |= (UInt32)1 << NDragMenu::k_Cancel; + const UInt32 cmd32 = Drag_OnContextMenu(pt.x, pt.y, flagsMask); + cmd = cmd32 & NDragMenu::k_MenuFlags_CmdMask; + if (cmd32 & NDragMenu::k_MenuFlag_Copy) + cmdEffect = DROPEFFECT_COPY; + else if (cmd32 & NDragMenu::k_MenuFlag_Move) + cmdEffect = DROPEFFECT_MOVE; + opEffect = cmdEffect; + menu_WasShown = true; + } + else + { + opEffect = GetEffect(keyState, pt, *effect); + if (m_IsAppTarget) + cmd = NDragMenu::k_AddToArc; + else if (m_Panel) + { + if (IsFsFolderPath()) + { + const bool is7zip = m_TargetPath_WasSent_ToDataObject; + bool createNewArchive = false; + if (is7zip) + createNewArchive = false; // g_CreateArchive_for_Drag_from_7zip; + else + createNewArchive = true; // g_CreateArchive_for_Drag_from_Explorer; + + if (createNewArchive) + cmd = NDragMenu::k_AddToArc; + else + { + if (opEffect != 0) + cmd = NDragMenu::k_Copy_Base; + cmdEffect = opEffect; + } + } + else + { + /* if we are inside open archive: + if archive support operations -> we will call operations + if archive doesn't support operations -> we will create new archove + */ + if (m_Panel->IsArcFolder() + || m_Panel->DoesItSupportOperations()) + { + cmd = NDragMenu::k_Copy_ToArc; + // we don't want move to archive operation here. + // so we force to DROPEFFECT_COPY. + if (opEffect != DROPEFFECT_NONE) + opEffect = DROPEFFECT_COPY; + cmdEffect = opEffect; + } + else + cmd = NDragMenu::k_AddToArc; + } + } + } + + if (cmd == 0) + cmd = NDragMenu::k_AddToArc; + + if (cmd == NDragMenu::k_AddToArc) + { + opEffect = DROPEFFECT_COPY; + cmdEffect = DROPEFFECT_COPY; + } + + if (m_Panel) + if (cmd == NDragMenu::k_Copy_ToArc) + { + const UString title = LangString(IDS_CONFIRM_FILE_COPY); + UString s = LangString(cmdEffect == DROPEFFECT_MOVE ? + IDS_MOVE_TO : IDS_COPY_TO); + s.Add_LF(); + // s += "\'"; + s += m_Panel->_currentFolderPrefix; + // s += "\'"; + s.Add_LF(); + AddLangString(s, IDS_WANT_TO_COPY_FILES); + s += " ?"; + const int res = ::MessageBoxW(*m_Panel, s, title, MB_YESNOCANCEL | MB_ICONQUESTION); + if (res != IDYES) + cmd = NDragMenu::k_Cancel; + } + + CTargetTransferInfo target; + target.FuncType = k_DragTargetMode_Drop_Begin; + target.KeyState = keyState; + target.Point = pt; + target.OkEffects = *effect; + target.Flags = 0; + + target.Cmd_Effect = cmdEffect; + target.Cmd_Type = cmd; + target.FolderType = GetFolderType(); + + if (cmd == NDragMenu::k_Cancel) + target.Flags |= k_TargetFlags_WasCanceled; + if (menu_WasShown) + target.Flags |= k_TargetFlags_MenuWasShown; + + SendToSource_auto(dataObject, target); + + CDataObject_GetTransfer transfer; + m_GetTransfer_WasSuccess = DataObject_GetData_GetTransfer( + dataObject, m_Format_7zip_GetTransfer, transfer); + + /* The Source (for example, 7-zip) could change file names when drop was confirmed. + So we must reload source file paths here */ + if (cmd != NDragMenu::k_Cancel) + LoadNames_From_DataObject(dataObject); + + if (cmd == NDragMenu::k_Cancel) + { + opEffect = DROPEFFECT_NONE; + cmdEffect = DROPEFFECT_NONE; + } + else + { + if (m_GetTransfer_WasSuccess) + needDrop_by_Source = ((transfer.Flags & k_SourceFlags_DoNotProcessInTarget) != 0); + if (!needDrop_by_Source) + { + bool moveMode = (cmdEffect == DROPEFFECT_MOVE); + bool needDrop = false; + if (m_IsRightButton && m_Panel) + needDrop = true; + if (m_DropIsAllowed && m_PanelDropIsAllowed) + { + /* if non-empty TargetPath was sent successfully to DataObject, + then the Source is 7-Zip, and that 7zip-Source can copy to FS operation. + So we can disable Drop operation here for such case. + */ + needDrop_by_Source = (cmd != NDragMenu::k_AddToArc + && m_TargetPath_WasSent_ToDataObject + && m_TargetPath_NonEmpty_WasSent_ToDataObject); + needDrop = !(needDrop_by_Source); + } + if (needDrop) + { + UString path = GetTargetPath(); + if (m_IsAppTarget && m_Panel) + if (m_Panel->IsFSFolder()) + path = m_Panel->GetFsPath(); + + UInt32 sourceFlags = 0; + if (m_GetTransfer_WasSuccess) + sourceFlags = transfer.Flags; + + if (menu_WasShown) + target.Flags |= k_TargetFlags_MenuWasShown; + + target.Flags |= k_TargetFlags_WasProcessed; + + RemoveSelection(); + // disableTimerProcessing.Restore(); + m_Panel->CompressDropFiles(m_SourcePaths, path, + (cmd == NDragMenu::k_AddToArc), // createNewArchive, + moveMode, sourceFlags, + target.Flags + ); + } + } + } // end of if (cmd != NDragMenu::k_Cancel) + { + /* note that, if (we send CFSTR_PERFORMEDDROPEFFECT as DROPEFFECT_MOVE + and Drop() returns (*effect == DROPEFFECT_MOVE), then + Win10-Explorer-Source will try to remove files just after Drop() exit. + But our CompressFiles() could be run without waiting finishing. + DOCs say, that we must send CFSTR_PERFORMEDDROPEFFECT + - DROPEFFECT_NONE : for optimized move + - DROPEFFECT_MOVE : for unoptimized move. + But actually Win10-Explorer-Target sends (DROPEFFECT_MOVE) for move operation. + And it still works as in optimized mode, because "unoptimized" deleting by Source will be performed + if both conditions are met: + 1) DROPEFFECT_MOVE is sent to (CFSTR_PERFORMEDDROPEFFECT) and + 2) (*effect == DROPEFFECT_MOVE) is returend by Drop(). + We don't want to send DROPEFFECT_MOVE here to protect from + deleting file by Win10-Explorer. + We are not sure that allfile fieree processed by move. + */ + + // for debug: we test the case when source tries to delete original files + // bool res; + // only CFSTR_PERFORMEDDROPEFFECT affects file removing in Win10-Explorer. + // res = SendToSource_UInt32(dataObject, RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT), DROPEFFECT_MOVE); // for debug + /* res = */ SendToSource_UInt32(dataObject, + RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT), + cmd == NDragMenu::k_Cancel ? DROPEFFECT_NONE : DROPEFFECT_COPY); + // res = res; + } + RemoveSelection(); + + target.FuncType = k_DragTargetMode_Drop_End; + target.Cmd_Type = cmd; + if (needDrop_by_Source) + target.Flags |= k_TargetFlags_MustBeProcessedBySource; + + SendToSource_TransferInfo(dataObject, target); + } catch(...) { hres = E_FAIL; } + + ClearState(); + // *effect |= (1 << 10); // for debug + // *effect = DROPEFFECT_COPY; // for debug + + /* + if we return (*effect == DROPEFFECT_MOVE) here, + Explorer-Source at some conditions can treat it as (unoptimized move) mode, + and Explorer-Source will remove source files after DoDragDrop() + in that (unoptimized move) mode. + We want to avoid such (unoptimized move) cases. + So we don't return (*effect == DROPEFFECT_MOVE), here if Source is not 7-Zip. + If source is 7-Zip that will do acual opeartion, then we can return DROPEFFECT_MOVE. + */ + if (hres != S_OK || (opEffect == DROPEFFECT_MOVE && !needDrop_by_Source)) + { + // opEffect = opEffect; + // opEffect = DROPEFFECT_NONE; // for debug disabled + } + + *effect = opEffect; + /* if (hres < 0), DoDragDrop() also will return (hres). + if (hres >= 0), DoDragDrop() will return DRAGDROP_S_DROP; + */ + return hres; +} + + + +// ---------- CPanel ---------- + + +static bool Is_Path1_Prefixed_by_Path2(const UString &path, const UString &prefix) +{ + const unsigned len = prefix.Len(); + if (path.Len() < len) + return false; + return CompareFileNames(path.Left(len), prefix) == 0; +} + +static bool IsFolderInTemp(const UString &path) +{ + FString tempPathF; + if (!MyGetTempPath(tempPathF)) + return false; + const UString tempPath = fs2us(tempPathF); + if (tempPath.IsEmpty()) + return false; + return Is_Path1_Prefixed_by_Path2(path, tempPath); +} + +static bool AreThereNamesFromTemp(const UStringVector &filePaths) +{ + FString tempPathF; + if (!MyGetTempPath(tempPathF)) + return false; + const UString tempPath = fs2us(tempPathF); + if (tempPath.IsEmpty()) + return false; + FOR_VECTOR (i, filePaths) + if (Is_Path1_Prefixed_by_Path2(filePaths[i], tempPath)) + return true; + return false; +} + + +/* + empty folderPath means create new Archive to path of first fileName. + createNewArchive == true : show "Add to archive ..." dialog with external program + folderPath.IsEmpty() : create archive in folder of filePaths[0]. + createNewArchive == false : + folderPath.IsEmpty() : copy to archive folder that is open in panel + !folderPath.IsEmpty() : CopyFsItems() to folderPath. +*/ +void CPanel::CompressDropFiles( + const UStringVector &filePaths, + const UString &folderPath, + bool createNewArchive, + bool moveMode, + UInt32 sourceFlags, + UInt32 &targetFlags + ) +{ + if (filePaths.Size() == 0) + return; + // createNewArchive = false; // for debug + + if (createNewArchive) + { + UString folderPath2 = folderPath; + // folderPath2.Empty(); // for debug + if (folderPath2.IsEmpty()) + { + { + FString folderPath2F; + GetOnlyDirPrefix(us2fs(filePaths.Front()), folderPath2F); + folderPath2 = fs2us(folderPath2F); + } + if (IsFolderInTemp(folderPath2)) + { + /* we don't want archive to be created in temp directory. + so we change the path to root folder (non-temp) */ + folderPath2 = ROOT_FS_FOLDER; + } + } + + UString arcName_base; + const UString arcName = CreateArchiveName(filePaths, + false, // isHash + NULL, // CFileInfo *fi + arcName_base); + + bool needWait; + if (sourceFlags & k_SourceFlags_WaitFinish) + needWait = true; + else if (sourceFlags & k_SourceFlags_DoNotWaitFinish) + needWait = false; + else if (sourceFlags & k_SourceFlags_TempFiles) + needWait = true; + else + needWait = AreThereNamesFromTemp(filePaths); + + targetFlags |= (needWait ? + k_TargetFlags_WaitFinish : + k_TargetFlags_DoNotWaitFinish); + + CompressFiles(folderPath2, arcName, + L"", // arcType + true, // addExtension + filePaths, + false, // email + true, // showDialog + needWait); + } + else + { + targetFlags |= k_TargetFlags_WaitFinish; + if (!folderPath.IsEmpty()) + { + CCopyToOptions options; + options.moveMode = moveMode; + options.folder = folderPath; + options.showErrorMessages = true; // showErrorMessages is not used for this operation + options.NeedRegistryZone = false; + options.ZoneIdMode = NExtract::NZoneIdMode::kNone; + // maybe we need more options here: FIXME + /* HRESULT hres = */ CopyFsItems(options, + filePaths, + NULL // UStringVector *messages + ); + // hres = hres; + } + else + { + CopyFromNoAsk(moveMode, filePaths); + } + } +} + + + +static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags) +{ + CMenu menu; + CMenuDestroyer menuDestroyer(menu); + /* + Esc key in shown menu doesn't work if we call Drag_OnContextMenu from ::Drop(). + We call SetFocus() tp solve that problem. + But the focus will be changed to Target Window after Drag and Drop. + Is it OK to use SetFocus() here ? + Is there another way to enable Esc key ? + */ + // _listView.SetFocus(); // for debug + ::SetFocus(g_HWND); + menu.CreatePopup(); + /* + int defaultCmd; // = NDragMenu::k_Move; + defaultCmd = NDragMenu::k_None; + */ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(NDragMenu::g_Pairs); i++) + { + const NDragMenu::CCmdLangPair &pair = NDragMenu::g_Pairs[i]; + const UInt32 cmdAndFlags = pair.CmdId_and_Flags; + const UInt32 cmdId = cmdAndFlags & NDragMenu::k_MenuFlags_CmdMask; + if (cmdId != NDragMenu::k_Cancel) + if ((cmdFlags & ((UInt32)1 << cmdId)) == 0) + continue; + const UINT flags = MF_STRING; + /* + if (prop.IsVisible) + flags |= MF_CHECKED; + if (i == 0) + flags |= MF_GRAYED; + */ + // MF_DEFAULT doesn't work + // if (i == 2) flags |= MF_DEFAULT; + // if (i == 4) flags |= MF_HILITE; + // if (cmd == defaultCmd) flags |= MF_HILITE; + UString name = LangString(pair.LangId); + if (name.IsEmpty()) + { + if (cmdId == NDragMenu::k_Cancel) + name = "Cancel"; + else + name.Add_UInt32(pair.LangId); + } + if (cmdId == NDragMenu::k_Copy_ToArc) + { + // UString destPath = _currentFolderPrefix; + /* + UString destPath = LangString(IDS_CONTEXT_ARCHIVE); + name = MyFormatNew(name, destPath); + */ + name.Add_Space(); + AddLangString(name, IDS_CONTEXT_ARCHIVE); + } + if (cmdId == NDragMenu::k_Cancel) + menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL); + menu.AppendItem(flags, cmdAndFlags, name); + } + /* + if (defaultCmd != 0) + SetMenuDefaultItem(menu, (unsigned)defaultCmd, + FALSE); // byPos + */ + int menuResult = menu.Track( + TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, + xPos, yPos, + g_HWND + // _listView // for debug + ); + /* menu.Track() return value is zero, if the user cancels + the menu without making a selection, or if an error occurs */ + if (menuResult <= 0) + menuResult = NDragMenu::k_Cancel; + return (unsigned)menuResult; +} + + + +void CApp::CreateDragTarget() +{ + _dropTargetSpec = new CDropTarget(); + _dropTarget = _dropTargetSpec; + _dropTargetSpec->App = (this); +} + +void CApp::SetFocusedPanel(unsigned index) +{ + LastFocusedPanel = index; + _dropTargetSpec->TargetPanelIndex = (int)LastFocusedPanel; +} + +void CApp::DragBegin(unsigned panelIndex) +{ + _dropTargetSpec->TargetPanelIndex = (int)(NumPanels > 1 ? 1 - panelIndex : panelIndex); + _dropTargetSpec->SrcPanelIndex = (int)panelIndex; +} + +void CApp::DragEnd() +{ + _dropTargetSpec->TargetPanelIndex = (int)LastFocusedPanel; + _dropTargetSpec->SrcPanelIndex = -1; +} diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp index 6921e22ff..c34cb74e3 100644 --- a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp +++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp @@ -1,1122 +1,1122 @@ -// PanelFolderChange.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/PropVariant.h" - -#include "../../PropID.h" - -#ifdef UNDER_CE -#include "FSFolder.h" -#else -#include "FSDrives.h" -#endif -#include "LangUtils.h" -#include "ListViewDialog.h" -#include "Panel.h" -#include "RootFolder.h" -#include "ViewSettings.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NFind; - -void CPanel::ReleaseFolder() -{ - DeleteListItems(); - - _folder.Release(); - - _folderCompare.Release(); - _folderGetItemName.Release(); - _folderRawProps.Release(); - _folderAltStreams.Release(); - _folderOperations.Release(); - - _thereAreDeletedItems = false; -} - -void CPanel::SetNewFolder(IFolderFolder *newFolder) -{ - ReleaseFolder(); - _folder = newFolder; - if (_folder) - { - _folder.QueryInterface(IID_IFolderCompare, &_folderCompare); - _folder.QueryInterface(IID_IFolderGetItemName, &_folderGetItemName); - _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps); - _folder.QueryInterface(IID_IFolderAltStreams, &_folderAltStreams); - _folder.QueryInterface(IID_IFolderOperations, &_folderOperations); - } -} - -void CPanel::SetToRootFolder() -{ - ReleaseFolder(); - _library.Free(); - - CRootFolder *rootFolderSpec = new CRootFolder; - SetNewFolder(rootFolderSpec); - rootFolderSpec->Init(); -} - - -static bool DoesNameContainWildcard_SkipRoot(const UString &path) -{ - return DoesNameContainWildcard(path.Ptr(NName::GetRootPrefixSize(path))); -} - -HRESULT CPanel::BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes) -{ - UString path = fullPath; - #ifdef _WIN32 - path.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - - openRes.ArchiveIsOpened = false; - openRes.Encrypted = false; - - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - - for (; !_parentFolders.IsEmpty(); CloseOneLevel()) - { - // ---------- we try to use open archive ---------- - - const CFolderLink &link = _parentFolders.Back(); - const UString &virtPath = link.VirtualPath; - if (!path.IsPrefixedBy(virtPath)) - continue; - UString relatPath = path.Ptr(virtPath.Len()); - if (!relatPath.IsEmpty()) - { - if (!IS_PATH_SEPAR(relatPath[0])) - continue; - else - relatPath.Delete(0); - } - - UString relatPath2 = relatPath; - if (!relatPath2.IsEmpty() && !IS_PATH_SEPAR(relatPath2.Back())) - relatPath2.Add_PathSepar(); - - for (;;) - { - const UString foldPath = GetFolderPath(_folder); - if (relatPath2 == foldPath) - break; - if (relatPath.IsPrefixedBy(foldPath)) - { - path = relatPath.Ptr(foldPath.Len()); - break; - } - CMyComPtr newFolder; - if (_folder->BindToParentFolder(&newFolder) != S_OK) - throw 20140918; - if (!newFolder) // we exit from loop above if (relatPath.IsPrefixedBy(empty path for root folder) - throw 20140918; - SetNewFolder(newFolder); - } - break; - } - - if (_parentFolders.IsEmpty()) - { - // ---------- we open file or folder from file system ---------- - - CloseOpenFolders(); - UString sysPath = path; - /* we will Empty() sysPath variable, if we need to BindToFolder() - directly with (path) variable */ - const unsigned prefixSize = NName::GetRootPrefixSize(sysPath); - if (prefixSize == 0 || sysPath[prefixSize] == 0) - sysPath.Empty(); - - #if defined(_WIN32) && !defined(UNDER_CE) - if (!sysPath.IsEmpty() && sysPath.Back() == ':' && - (sysPath.Len() != 2 || !NName::IsDrivePath2(sysPath))) - { - // if base item for alt streams prefix "base:" exists, we will use it - UString baseFile = sysPath; - baseFile.DeleteBack(); - if (NFind::DoesFileOrDirExist(us2fs(baseFile))) - sysPath.Empty(); - } - #endif - - CFileInfo fileInfo; - - while (!sysPath.IsEmpty()) - { - if (sysPath.Len() <= prefixSize) - { - path.DeleteFrom(prefixSize); - sysPath.Empty(); - break; - } - - fileInfo.ClearBase(); - if (IsPathSepar(sysPath.Back())) - { - /* Windows 10 by default doesn't allow look "Local Settings" that is junction to "AppData\Local", - but it does allow look "Local Settings\Temp\*" - 22.02: at first we try to use paths with slashes "path\" */ - CFileInfo fi; - // CFindFile findFile; - // FString path2 = us2fs(sysPath); - // path2 += '*'; // CHAR_ANY_MASK; - // if (findFile.FindFirst(path2, fi)) - CEnumerator enumerator; - enumerator.SetDirPrefix(us2fs(sysPath)); - bool found = false; - if (enumerator.Next(fi, found)) - { - // sysPath.DeleteBack(); - fileInfo.SetAsDir(); - fileInfo.Size = 0; - fileInfo.Name.Empty(); - break; - } - sysPath.DeleteBack(); - continue; - } - - if (fileInfo.Find(us2fs(sysPath))) - break; - int pos = sysPath.ReverseFind_PathSepar(); - if (pos < 0) - { - sysPath.Empty(); - break; - } - { - if ((unsigned)pos != sysPath.Len() - 1) - pos++; - sysPath.DeleteFrom((unsigned)pos); - } - } - - SetToRootFolder(); - - CMyComPtr newFolder; - - if (sysPath.IsEmpty()) - { - _folder->BindToFolder(path, &newFolder); - } - else if (fileInfo.IsDir()) - { - #ifdef _WIN32 - if (DoesNameContainWildcard_SkipRoot(sysPath)) - { - FString dirPrefix, fileName; - NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName); - if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix))) - return E_INVALIDARG; - sysPath = fs2us(dirPrefix + fileInfo.Name); - } - #endif - - NName::NormalizeDirPathPrefix(sysPath); - _folder->BindToFolder(sysPath, &newFolder); - } - else - { - FString dirPrefix, fileName; - - NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName); - - HRESULT res = S_OK; - - #ifdef _WIN32 - if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix))) - return E_INVALIDARG; - - if (DoesNameContainWildcard(fs2us(fileName))) - res = S_FALSE; - else - #endif - { - CTempFileInfo tfi; - tfi.RelPath = fs2us(fileName); - tfi.FolderPath = dirPrefix; - tfi.FilePath = us2fs(sysPath); - res = OpenAsArc(NULL, tfi, sysPath, arcFormat, openRes); - } - - if (res == S_FALSE) - _folder->BindToFolder(fs2us(dirPrefix), &newFolder); - else - { - RINOK(res) - openRes.ArchiveIsOpened = true; - _parentFolders.Back().ParentFolderPath = fs2us(dirPrefix); - path.DeleteFrontal(sysPath.Len()); - if (!path.IsEmpty() && IS_PATH_SEPAR(path[0])) - path.Delete(0); - } - } - - if (newFolder) - { - SetNewFolder(newFolder); - // LoadFullPath(); - return S_OK; - } - } - - { - // ---------- we open folder remPath in archive and sub archives ---------- - - for (unsigned curPos = 0; curPos != path.Len();) - { - UString s = path.Ptr(curPos); - const int slashPos = NName::FindSepar(s); - unsigned skipLen = s.Len(); - if (slashPos >= 0) - { - s.DeleteFrom((unsigned)slashPos); - skipLen = (unsigned)slashPos + 1; - } - - CMyComPtr newFolder; - _folder->BindToFolder(s, &newFolder); - if (newFolder) - curPos += skipLen; - else if (_folderAltStreams) - { - const int pos = s.Find(L':'); - if (pos >= 0) - { - UString baseName = s; - baseName.DeleteFrom((unsigned)pos); - if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder) - curPos += (unsigned)pos + 1; - } - } - - if (!newFolder) - break; - - SetNewFolder(newFolder); - } - } - - return S_OK; -} - -HRESULT CPanel::BindToPathAndRefresh(const UString &path) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - COpenResult openRes; - UString s = path; - - #ifdef _WIN32 - if (!s.IsEmpty() && s[0] == '\"' && s.Back() == '\"') - { - s.DeleteBack(); - s.Delete(0); - } - #endif - - HRESULT res = BindToPath(s, UString(), openRes); - RefreshListCtrl(); - return res; -} - -void CPanel::SetBookmark(unsigned index) -{ - _appState->FastFolders.SetString(index, _currentFolderPrefix); -} - -void CPanel::OpenBookmark(unsigned index) -{ - BindToPathAndRefresh(_appState->FastFolders.GetString(index)); -} - -UString GetFolderPath(IFolderFolder *folder) -{ - { - NCOM::CPropVariant prop; - if (folder->GetFolderProperty(kpidPath, &prop) == S_OK) - if (prop.vt == VT_BSTR) - return (wchar_t *)prop.bstrVal; - } - return UString(); -} - -void CPanel::LoadFullPath() -{ - _currentFolderPrefix.Empty(); - FOR_VECTOR (i, _parentFolders) - { - const CFolderLink &folderLink = _parentFolders[i]; - _currentFolderPrefix += folderLink.ParentFolderPath; - // GetFolderPath(folderLink.ParentFolder); - _currentFolderPrefix += folderLink.RelPath; - _currentFolderPrefix.Add_PathSepar(); - } - if (_folder) - _currentFolderPrefix += GetFolderPath(_folder); -} - - - -static int GetRealIconIndex_for_DirPath(CFSTR path, DWORD attrib) -{ - attrib |= FILE_ATTRIBUTE_DIRECTORY; // optional - int index = -1; - if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(path, attrib, index)) - if (index >= 0) - return index; - return g_Ext_to_Icon_Map.GetIconIndex_DIR(attrib); -} - - -extern UString RootFolder_GetName_Computer(int &iconIndex); -extern UString RootFolder_GetName_Network(int &iconIndex); -extern UString RootFolder_GetName_Documents(int &iconIndex); - - -static int Find_FileExtension_DotPos_in_path(const wchar_t *path) -{ - int dotPos = -1; - unsigned i; - for (i = 0;; i++) - { - const wchar_t c = path[i]; - if (c == 0) - return dotPos; - if (c == '.') - dotPos = (int)i; - else if (IS_PATH_SEPAR(c) || c == ':') - dotPos = -1; - } -} - - -void CPanel::LoadFullPathAndShow() -{ - LoadFullPath(); - _appState->FolderHistory.AddString(_currentFolderPrefix); - - _headerComboBox.SetText(_currentFolderPrefix); - - #ifndef UNDER_CE - - COMBOBOXEXITEM item; - item.mask = 0; - item.iImage = -1; - - UString path = _currentFolderPrefix; - // path = "\\\\.\\PhysicalDrive1\\"; // for debug - // path = "\\\\.\\y:\\"; // for debug - if (!path.IsEmpty()) - { - const unsigned rootPrefixSize = NName::GetRootPrefixSize(path); - if (rootPrefixSize == 0 && path[0] != '\\') - { - int iconIndex = -1; - UString name_Computer = RootFolder_GetName_Computer(iconIndex); - name_Computer.Add_PathSepar(); - if (path == name_Computer - || path == L"\\\\?\\") - item.iImage = iconIndex; - else - { - UString name = RootFolder_GetName_Network(iconIndex); - name.Add_PathSepar(); - if (path == name) - item.iImage = iconIndex; - } - } - - if (item.iImage < 0) - { - if (rootPrefixSize == 0 || rootPrefixSize == path.Len()) - { - DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; - CFileInfo info; - if (info.Find(us2fs(path))) - attrib = info.Attrib; - NName::If_IsSuperPath_RemoveSuperPrefix(path); - item.iImage = GetRealIconIndex_for_DirPath(us2fs(path), attrib); - } - else if (rootPrefixSize == NName::kDevicePathPrefixSize - && NName::IsDevicePath(us2fs(path.Left(path.Len() - 1)))) - { - if (path.IsPrefixedBy_Ascii_NoCase("\\\\.\\")) - path.DeleteFrontal(4); - if (path.Len() > 3) // is not "c:\\" - { - // PhysicalDrive - if (path.Back() == '\\') - path.DeleteBack(); - } - item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), FILE_ATTRIBUTE_ARCHIVE); - } - else - { - if (path.Back() == '\\') - path.DeleteBack(); - bool need_Fs_Check = true; - bool is_File = false; - if (!_parentFolders.IsEmpty()) - { - const CFolderLink &link = _parentFolders.Back(); - if (link.VirtualPath == path) - { - is_File = true; - if (_parentFolders.Size() != 1) - need_Fs_Check = false; - } - else - need_Fs_Check = false; - } - if (need_Fs_Check) - { - CFileInfo info; - const bool finded = info.Find(us2fs(path)); - DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; - if (finded) - attrib = info.Attrib; - item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), attrib); - } - if (item.iImage <= 0 && is_File) - { - int dotPos = Find_FileExtension_DotPos_in_path(path); - if (dotPos < 0) - dotPos = (int)path.Len(); - item.iImage = g_Ext_to_Icon_Map.GetIconIndex(FILE_ATTRIBUTE_ARCHIVE, path.Ptr(dotPos)); - } - } - } - } - - if (item.iImage < 0) - item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR(); - // if (item.iImage < 0) item.iImage = 0; - // item.iImage = -1; // for debug - if (item.iImage >= 0) - { - item.iSelectedImage = item.iImage; - item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE); - } - item.iItem = -1; - _headerComboBox.SetItem(&item); - - #endif - - RefreshTitle(); -} - -#ifndef UNDER_CE -LRESULT CPanel::OnNotifyComboBoxEnter(const UString &s) -{ - if (BindToPathAndRefresh(GetUnicodeString(s)) == S_OK) - { - PostMsg(kSetFocusToListView); - return TRUE; - } - return FALSE; -} - -bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result) -{ - if (info->iWhy == CBENF_ESCAPE) - { - _headerComboBox.SetText(_currentFolderPrefix); - PostMsg(kSetFocusToListView); - result = FALSE; - return true; - } - - /* - if (info->iWhy == CBENF_DROPDOWN) - { - result = FALSE; - return true; - } - */ - - if (info->iWhy == CBENF_RETURN) - { - // When we use Edit control and press Enter. - UString s; - _headerComboBox.GetText(s); - result = OnNotifyComboBoxEnter(s); - return true; - } - return false; -} -#endif - -#ifndef _UNICODE -bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result) -{ - if (info->iWhy == CBENF_ESCAPE) - { - _headerComboBox.SetText(_currentFolderPrefix); - PostMsg(kSetFocusToListView); - result = FALSE; - return true; - } - /* - if (info->iWhy == CBENF_DROPDOWN) - { - result = FALSE; - return true; - } - */ - - if (info->iWhy == CBENF_RETURN) - { - UString s; - _headerComboBox.GetText(s); - // GetUnicodeString(info->szText) - result = OnNotifyComboBoxEnter(s); - return true; - } - return false; -} -#endif - -void CPanel::AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList) -{ - #ifdef UNDER_CE - - UString s; - iconIndex = iconIndex; - for (unsigned i = 0; i < indent; i++) - s += " "; - _headerComboBox.AddString(s + name); - - #else - - COMBOBOXEXITEMW item; - item.mask = CBEIF_TEXT | CBEIF_INDENT; - if (iconIndex < 0) - iconIndex = g_Ext_to_Icon_Map.GetIconIndex_DIR(); - item.iSelectedImage = item.iImage = iconIndex; - if (iconIndex >= 0) - item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE); - item.iItem = -1; - item.iIndent = (int)indent; - item.pszText = name.Ptr_non_const(); - _headerComboBox.InsertItem(&item); - - #endif - - if (addToList) - { - UString s = name; - s.Add_PathSepar(); - ComboBoxPaths.Add(s); - } -} - - -bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) -{ - result = FALSE; - switch (code) - { - case CBN_DROPDOWN: - { - ComboBoxPaths.Clear(); - _headerComboBox.ResetContent(); - - UString sumPath; - UStringVector pathParts; - unsigned indent = 0; - { - UString path = _currentFolderPrefix; - // path = L"\\\\.\\y:\\"; // for debug - UString prefix0; - if (path.IsPrefixedBy_Ascii_NoCase("\\\\")) - { - const int separ = FindCharPosInString(path.Ptr(2), '\\'); - if (separ > 0 - && (separ > 1 || path[2] != '.')) // "\\\\.\\" will be processed later - { - const UString s = path.Left(2 + separ); - prefix0 = s; - prefix0.Add_PathSepar(); - AddComboBoxItem(s, - GetRealIconIndex_for_DirPath(us2fs(prefix0), FILE_ATTRIBUTE_DIRECTORY), - indent++, - false); // addToList - ComboBoxPaths.Add(prefix0); - } - } - - unsigned rootPrefixSize = NName::GetRootPrefixSize(path); - - sumPath = path; - - if (rootPrefixSize <= prefix0.Len()) - { - rootPrefixSize = prefix0.Len(); - sumPath.DeleteFrom(rootPrefixSize); - } - else - { - // rootPrefixSize > prefix0.Len() - sumPath.DeleteFrom(rootPrefixSize); - - CFileInfo info; - DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; - if (info.Find(us2fs(sumPath)) && info.IsDir()) - attrib = info.Attrib; - UString s = sumPath.Ptr(prefix0.Len()); - if (!s.IsEmpty()) - { - const wchar_t c = s.Back(); - if (IS_PATH_SEPAR(c)) - s.DeleteBack(); - } - UString path_for_icon = sumPath; - NName::If_IsSuperPath_RemoveSuperPrefix(path_for_icon); - - AddComboBoxItem(s, - GetRealIconIndex_for_DirPath(us2fs(path_for_icon), attrib), - indent++, - false); // addToList - ComboBoxPaths.Add(sumPath); - } - - path.DeleteFrontal(rootPrefixSize); - SplitPathToParts(path, pathParts); - } - - // it's expected that pathParts.Back() is empty, because _currentFolderPrefix has PathSeparator. - unsigned next_Arc_index = 0; - int iconIndex_Computer; - const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer); - - // const bool is_devicePrefix = (sumPath == L"\\\\.\\"); - - if (pathParts.Size() > 1) - if (!sumPath.IsEmpty() - || pathParts.Size() != 2 - || pathParts[0] != name_Computer) - for (unsigned i = 0; i + 1 < pathParts.Size(); i++) - { - UString name = pathParts[i]; - sumPath += name; - - bool isRootDir_inLink = false; - if (next_Arc_index < _parentFolders.Size()) - { - const CFolderLink &link = _parentFolders[next_Arc_index]; - if (link.VirtualPath == sumPath) - { - isRootDir_inLink = true; - next_Arc_index++; - } - } - - int iconIndex = -1; - DWORD attrib = isRootDir_inLink ? - FILE_ATTRIBUTE_ARCHIVE: - FILE_ATTRIBUTE_DIRECTORY; - if (next_Arc_index == 0 - || (next_Arc_index == 1 && isRootDir_inLink)) - { - if (i == 0 && NName::IsDevicePath(us2fs(sumPath))) - { - UString path = name; - path.Add_PathSepar(); - attrib = FILE_ATTRIBUTE_ARCHIVE; - // FILE_ATTRIBUTE_DIRECTORY; - } - else - { - CFileInfo info; - if (info.Find(us2fs(sumPath))) - attrib = info.Attrib; - } - iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(sumPath), attrib); - } - - if (iconIndex < 0) - iconIndex = g_Ext_to_Icon_Map.GetIconIndex(attrib, name); - // iconIndex = -1; // for debug - if (iconIndex < 0 && isRootDir_inLink) - iconIndex = 0; // default file - - sumPath.Add_PathSepar(); - - ComboBoxPaths.Add(sumPath); - if (name.IsEmpty()) - name.Add_PathSepar(); - AddComboBoxItem(name, iconIndex, indent++, - false); // addToList - } - -#ifndef UNDER_CE - - { - int iconIndex; - const UString name = RootFolder_GetName_Documents(iconIndex); - // iconIndex = -1; // for debug - AddComboBoxItem(name, iconIndex, 0, true); - } - AddComboBoxItem(name_Computer, iconIndex_Computer, 0, true); - { - FStringVector driveStrings; - MyGetLogicalDriveStrings(driveStrings); - FOR_VECTOR (i, driveStrings) - { - FString s = driveStrings[i]; - ComboBoxPaths.Add(fs2us(s)); - int iconIndex2 = GetRealIconIndex_for_DirPath(s, FILE_ATTRIBUTE_DIRECTORY); - if (!s.IsEmpty()) - { - const FChar c = s.Back(); - if (IS_PATH_SEPAR(c)) - s.DeleteBack(); - } - // iconIndex2 = -1; // for debug - AddComboBoxItem(fs2us(s), iconIndex2, 1, false); - } - } - { - int iconIndex; - const UString name = RootFolder_GetName_Network(iconIndex); - AddComboBoxItem(name, iconIndex, 0, true); - } - -#endif - - return false; - } - - case CBN_SELENDOK: - { - int index = _headerComboBox.GetCurSel(); - if (index >= 0) - { - const UString path = ComboBoxPaths[index]; - _headerComboBox.SetCurSel(-1); - // _headerComboBox.SetText(pass); // it's fix for selecting by mouse. - if (BindToPathAndRefresh(path) == S_OK) - { - PostMsg(kSetFocusToListView); - #ifdef UNDER_CE - PostMsg(kRefresh_HeaderComboBox); - #endif - return true; - } - } - return false; - } - /* - case CBN_CLOSEUP: - { - LoadFullPathAndShow(); - true; - - } - case CBN_SELCHANGE: - { - // LoadFullPathAndShow(); - return true; - } - */ - } - return false; -} - -bool CPanel::OnNotifyComboBox(LPNMHDR NON_CE_VAR(header), LRESULT & NON_CE_VAR(result)) -{ - #ifndef UNDER_CE - switch (header->code) - { - case CBEN_BEGINEDIT: - { - _lastFocusedIsList = false; - _panelCallback->PanelWasFocused(); - break; - } - #ifndef _UNICODE - case CBEN_ENDEDIT: - { - return OnNotifyComboBoxEndEdit((PNMCBEENDEDIT)header, result); - } - #endif - case CBEN_ENDEDITW: - { - return OnNotifyComboBoxEndEdit((PNMCBEENDEDITW)header, result); - } - } - #endif - return false; -} - - -void CPanel::FoldersHistory() -{ - CListViewDialog listViewDialog; - listViewDialog.DeleteIsAllowed = true; - listViewDialog.SelectFirst = true; - LangString(IDS_FOLDERS_HISTORY, listViewDialog.Title); - _appState->FolderHistory.GetList(listViewDialog.Strings); - if (listViewDialog.Create(GetParent()) != IDOK) - return; - UString selectString; - if (listViewDialog.StringsWereChanged) - { - _appState->FolderHistory.RemoveAll(); - for (int i = (int)listViewDialog.Strings.Size() - 1; i >= 0; i--) - _appState->FolderHistory.AddString(listViewDialog.Strings[i]); - if (listViewDialog.FocusedItemIndex >= 0) - selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex]; - } - else - { - if (listViewDialog.FocusedItemIndex >= 0) - selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex]; - } - if (listViewDialog.FocusedItemIndex >= 0) - BindToPathAndRefresh(selectString); -} - - -UString CPanel::GetParentDirPrefix() const -{ - UString s; - if (!_currentFolderPrefix.IsEmpty()) - { - wchar_t c = _currentFolderPrefix.Back(); - if (IS_PATH_SEPAR(c) || c == ':') - { - s = _currentFolderPrefix; - s.DeleteBack(); - if (s != L"\\\\." && - s != L"\\\\?") - { - int pos = s.ReverseFind_PathSepar(); - if (pos >= 0) - s.DeleteFrom((unsigned)(pos + 1)); - } - } - } - return s; -} - - -void CPanel::OpenParentFolder() -{ - LoadFullPath(); // Maybe we don't need it ?? - - UString parentFolderPrefix; - UString focusedName; - - if (!_currentFolderPrefix.IsEmpty()) - { - wchar_t c = _currentFolderPrefix.Back(); - if (IS_PATH_SEPAR(c) || c == ':') - { - focusedName = _currentFolderPrefix; - focusedName.DeleteBack(); - /* - if (c == ':' && !focusedName.IsEmpty() && IS_PATH_SEPAR(focusedName.Back())) - { - focusedName.DeleteBack(); - } - else - */ - if (focusedName != L"\\\\." && - focusedName != L"\\\\?") - { - const int pos = focusedName.ReverseFind_PathSepar(); - if (pos >= 0) - { - parentFolderPrefix = focusedName; - parentFolderPrefix.DeleteFrom((unsigned)(pos + 1)); - focusedName.DeleteFrontal((unsigned)(pos + 1)); - } - } - } - } - - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - - CMyComPtr newFolder; - _folder->BindToParentFolder(&newFolder); - - // newFolder.Release(); // for test - - if (newFolder) - SetNewFolder(newFolder); - else - { - bool needSetFolder = true; - if (!_parentFolders.IsEmpty()) - { - { - const CFolderLink &link = _parentFolders.Back(); - parentFolderPrefix = link.ParentFolderPath; - focusedName = link.RelPath; - } - CloseOneLevel(); - needSetFolder = (!_folder); - } - - if (needSetFolder) - { - { - COpenResult openRes; - BindToPath(parentFolderPrefix, UString(), openRes); - } - } - } - - CSelectedState state; - state.FocusedName = focusedName; - state.FocusedName_Defined = true; - /* - if (!focusedName.IsEmpty()) - state.SelectedNames.Add(focusedName); - */ - LoadFullPath(); - // ::SetCurrentDirectory(::_currentFolderPrefix); - RefreshListCtrl(state); - // _listView.EnsureVisible(_listView.GetFocusedItem(), false); -} - - -void CPanel::CloseOneLevel() -{ - ReleaseFolder(); - _library.Free(); - { - CFolderLink &link = _parentFolders.Back(); - if (link.ParentFolder) - SetNewFolder(link.ParentFolder); - _library.Attach(link.Library.Detach()); - } - if (_parentFolders.Size() > 1) - OpenParentArchiveFolder(); - _parentFolders.DeleteBack(); - if (_parentFolders.IsEmpty()) - _flatMode = _flatModeForDisk; -} - -void CPanel::CloseOpenFolders() -{ - while (!_parentFolders.IsEmpty()) - CloseOneLevel(); - _flatMode = _flatModeForDisk; - ReleaseFolder(); - _library.Free(); -} - -void CPanel::OpenRootFolder() -{ - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - _parentFolders.Clear(); - SetToRootFolder(); - RefreshListCtrl(); - // ::SetCurrentDirectory(::_currentFolderPrefix); - /* - BeforeChangeFolder(); - _currentFolderPrefix.Empty(); - AfterChangeFolder(); - SetCurrentPathText(); - RefreshListCtrl(UString(), 0, UStringVector()); - _listView.EnsureVisible(_listView.GetFocusedItem(), false); - */ -} - -void CPanel::OpenDrivesFolder() -{ - CloseOpenFolders(); - #ifdef UNDER_CE - NFsFolder::CFSFolder *folderSpec = new NFsFolder::CFSFolder; - SetNewFolder(folderSpec); - folderSpec->InitToRoot(); - #else - CFSDrives *folderSpec = new CFSDrives; - SetNewFolder(folderSpec); - folderSpec->Init(); - #endif - RefreshListCtrl(); -} - -void CPanel::OpenFolder(unsigned index) -{ - if (index == kParentIndex) - { - OpenParentFolder(); - return; - } - CMyComPtr newFolder; - const HRESULT res = _folder->BindToFolder((unsigned)index, &newFolder); - if (res != 0) - { - MessageBox_Error_HRESULT(res); - return; - } - if (!newFolder) - return; - SetNewFolder(newFolder); - LoadFullPath(); - RefreshListCtrl(); - // 17.02: fixed : now we don't select first item - // _listView.SetItemState_Selected(_listView.GetFocusedItem()); - _listView.EnsureVisible(_listView.GetFocusedItem(), false); -} - -void CPanel::OpenAltStreams() -{ - CRecordVector indices; - Get_ItemIndices_Operated(indices); - Int32 realIndex = -1; - if (indices.Size() > 1) - return; - if (indices.Size() == 1) - realIndex = (Int32)indices[0]; - - if (_folderAltStreams) - { - CMyComPtr newFolder; - _folderAltStreams->BindToAltStreams((UInt32)realIndex, &newFolder); - if (newFolder) - { - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - SetNewFolder(newFolder); - RefreshListCtrl(); - return; - } - return; - } - - #if defined(_WIN32) && !defined(UNDER_CE) - UString path; - if (realIndex >= 0) - path = GetItemFullPath((UInt32)realIndex); - else - { - path = GetFsPath(); - if (!NName::IsDriveRootPath_SuperAllowed(us2fs(path))) - if (!path.IsEmpty() && IS_PATH_SEPAR(path.Back())) - path.DeleteBack(); - } - - path.Add_Colon(); - BindToPathAndRefresh(path); - #endif -} +// PanelFolderChange.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/PropVariant.h" + +#include "../../PropID.h" + +#ifdef UNDER_CE +#include "FSFolder.h" +#else +#include "FSDrives.h" +#endif +#include "LangUtils.h" +#include "ListViewDialog.h" +#include "Panel.h" +#include "RootFolder.h" +#include "ViewSettings.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NFind; + +void CPanel::ReleaseFolder() +{ + DeleteListItems(); + + _folder.Release(); + + _folderCompare.Release(); + _folderGetItemName.Release(); + _folderRawProps.Release(); + _folderAltStreams.Release(); + _folderOperations.Release(); + + _thereAreDeletedItems = false; +} + +void CPanel::SetNewFolder(IFolderFolder *newFolder) +{ + ReleaseFolder(); + _folder = newFolder; + if (_folder) + { + _folder.QueryInterface(IID_IFolderCompare, &_folderCompare); + _folder.QueryInterface(IID_IFolderGetItemName, &_folderGetItemName); + _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps); + _folder.QueryInterface(IID_IFolderAltStreams, &_folderAltStreams); + _folder.QueryInterface(IID_IFolderOperations, &_folderOperations); + } +} + +void CPanel::SetToRootFolder() +{ + ReleaseFolder(); + _library.Free(); + + CRootFolder *rootFolderSpec = new CRootFolder; + SetNewFolder(rootFolderSpec); + rootFolderSpec->Init(); +} + + +static bool DoesNameContainWildcard_SkipRoot(const UString &path) +{ + return DoesNameContainWildcard(path.Ptr(NName::GetRootPrefixSize(path))); +} + +HRESULT CPanel::BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes) +{ + UString path = fullPath; + #ifdef _WIN32 + path.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + + openRes.ArchiveIsOpened = false; + openRes.Encrypted = false; + + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + + for (; !_parentFolders.IsEmpty(); CloseOneLevel()) + { + // ---------- we try to use open archive ---------- + + const CFolderLink &link = _parentFolders.Back(); + const UString &virtPath = link.VirtualPath; + if (!path.IsPrefixedBy(virtPath)) + continue; + UString relatPath = path.Ptr(virtPath.Len()); + if (!relatPath.IsEmpty()) + { + if (!IS_PATH_SEPAR(relatPath[0])) + continue; + else + relatPath.Delete(0); + } + + UString relatPath2 = relatPath; + if (!relatPath2.IsEmpty() && !IS_PATH_SEPAR(relatPath2.Back())) + relatPath2.Add_PathSepar(); + + for (;;) + { + const UString foldPath = GetFolderPath(_folder); + if (relatPath2 == foldPath) + break; + if (relatPath.IsPrefixedBy(foldPath)) + { + path = relatPath.Ptr(foldPath.Len()); + break; + } + CMyComPtr newFolder; + if (_folder->BindToParentFolder(&newFolder) != S_OK) + throw 20140918; + if (!newFolder) // we exit from loop above if (relatPath.IsPrefixedBy(empty path for root folder) + throw 20140918; + SetNewFolder(newFolder); + } + break; + } + + if (_parentFolders.IsEmpty()) + { + // ---------- we open file or folder from file system ---------- + + CloseOpenFolders(); + UString sysPath = path; + /* we will Empty() sysPath variable, if we need to BindToFolder() + directly with (path) variable */ + const unsigned prefixSize = NName::GetRootPrefixSize(sysPath); + if (prefixSize == 0 || sysPath[prefixSize] == 0) + sysPath.Empty(); + + #if defined(_WIN32) && !defined(UNDER_CE) + if (!sysPath.IsEmpty() && sysPath.Back() == ':' && + (sysPath.Len() != 2 || !NName::IsDrivePath2(sysPath))) + { + // if base item for alt streams prefix "base:" exists, we will use it + UString baseFile = sysPath; + baseFile.DeleteBack(); + if (NFind::DoesFileOrDirExist(us2fs(baseFile))) + sysPath.Empty(); + } + #endif + + CFileInfo fileInfo; + + while (!sysPath.IsEmpty()) + { + if (sysPath.Len() <= prefixSize) + { + path.DeleteFrom(prefixSize); + sysPath.Empty(); + break; + } + + fileInfo.ClearBase(); + if (IsPathSepar(sysPath.Back())) + { + /* Windows 10 by default doesn't allow look "Local Settings" that is junction to "AppData\Local", + but it does allow look "Local Settings\Temp\*" + 22.02: at first we try to use paths with slashes "path\" */ + CFileInfo fi; + // CFindFile findFile; + // FString path2 = us2fs(sysPath); + // path2 += '*'; // CHAR_ANY_MASK; + // if (findFile.FindFirst(path2, fi)) + CEnumerator enumerator; + enumerator.SetDirPrefix(us2fs(sysPath)); + bool found = false; + if (enumerator.Next(fi, found)) + { + // sysPath.DeleteBack(); + fileInfo.SetAsDir(); + fileInfo.Size = 0; + fileInfo.Name.Empty(); + break; + } + sysPath.DeleteBack(); + continue; + } + + if (fileInfo.Find(us2fs(sysPath))) + break; + int pos = sysPath.ReverseFind_PathSepar(); + if (pos < 0) + { + sysPath.Empty(); + break; + } + { + if ((unsigned)pos != sysPath.Len() - 1) + pos++; + sysPath.DeleteFrom((unsigned)pos); + } + } + + SetToRootFolder(); + + CMyComPtr newFolder; + + if (sysPath.IsEmpty()) + { + _folder->BindToFolder(path, &newFolder); + } + else if (fileInfo.IsDir()) + { + #ifdef _WIN32 + if (DoesNameContainWildcard_SkipRoot(sysPath)) + { + FString dirPrefix, fileName; + NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName); + if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix))) + return E_INVALIDARG; + sysPath = fs2us(dirPrefix + fileInfo.Name); + } + #endif + + NName::NormalizeDirPathPrefix(sysPath); + _folder->BindToFolder(sysPath, &newFolder); + } + else + { + FString dirPrefix, fileName; + + NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName); + + HRESULT res = S_OK; + + #ifdef _WIN32 + if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix))) + return E_INVALIDARG; + + if (DoesNameContainWildcard(fs2us(fileName))) + res = S_FALSE; + else + #endif + { + CTempFileInfo tfi; + tfi.RelPath = fs2us(fileName); + tfi.FolderPath = dirPrefix; + tfi.FilePath = us2fs(sysPath); + res = OpenAsArc(NULL, tfi, sysPath, arcFormat, openRes); + } + + if (res == S_FALSE) + _folder->BindToFolder(fs2us(dirPrefix), &newFolder); + else + { + RINOK(res) + openRes.ArchiveIsOpened = true; + _parentFolders.Back().ParentFolderPath = fs2us(dirPrefix); + path.DeleteFrontal(sysPath.Len()); + if (!path.IsEmpty() && IS_PATH_SEPAR(path[0])) + path.Delete(0); + } + } + + if (newFolder) + { + SetNewFolder(newFolder); + // LoadFullPath(); + return S_OK; + } + } + + { + // ---------- we open folder remPath in archive and sub archives ---------- + + for (unsigned curPos = 0; curPos != path.Len();) + { + UString s = path.Ptr(curPos); + const int slashPos = NName::FindSepar(s); + unsigned skipLen = s.Len(); + if (slashPos >= 0) + { + s.DeleteFrom((unsigned)slashPos); + skipLen = (unsigned)slashPos + 1; + } + + CMyComPtr newFolder; + _folder->BindToFolder(s, &newFolder); + if (newFolder) + curPos += skipLen; + else if (_folderAltStreams) + { + const int pos = s.Find(L':'); + if (pos >= 0) + { + UString baseName = s; + baseName.DeleteFrom((unsigned)pos); + if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder) + curPos += (unsigned)pos + 1; + } + } + + if (!newFolder) + break; + + SetNewFolder(newFolder); + } + } + + return S_OK; +} + +HRESULT CPanel::BindToPathAndRefresh(const UString &path) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + COpenResult openRes; + UString s = path; + + #ifdef _WIN32 + if (!s.IsEmpty() && s[0] == '\"' && s.Back() == '\"') + { + s.DeleteBack(); + s.Delete(0); + } + #endif + + HRESULT res = BindToPath(s, UString(), openRes); + RefreshListCtrl(); + return res; +} + +void CPanel::SetBookmark(unsigned index) +{ + _appState->FastFolders.SetString(index, _currentFolderPrefix); +} + +void CPanel::OpenBookmark(unsigned index) +{ + BindToPathAndRefresh(_appState->FastFolders.GetString(index)); +} + +UString GetFolderPath(IFolderFolder *folder) +{ + { + NCOM::CPropVariant prop; + if (folder->GetFolderProperty(kpidPath, &prop) == S_OK) + if (prop.vt == VT_BSTR) + return (wchar_t *)prop.bstrVal; + } + return UString(); +} + +void CPanel::LoadFullPath() +{ + _currentFolderPrefix.Empty(); + FOR_VECTOR (i, _parentFolders) + { + const CFolderLink &folderLink = _parentFolders[i]; + _currentFolderPrefix += folderLink.ParentFolderPath; + // GetFolderPath(folderLink.ParentFolder); + _currentFolderPrefix += folderLink.RelPath; + _currentFolderPrefix.Add_PathSepar(); + } + if (_folder) + _currentFolderPrefix += GetFolderPath(_folder); +} + + + +static int GetRealIconIndex_for_DirPath(CFSTR path, DWORD attrib) +{ + attrib |= FILE_ATTRIBUTE_DIRECTORY; // optional + int index = -1; + if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(path, attrib, index)) + if (index >= 0) + return index; + return g_Ext_to_Icon_Map.GetIconIndex_DIR(attrib); +} + + +extern UString RootFolder_GetName_Computer(int &iconIndex); +extern UString RootFolder_GetName_Network(int &iconIndex); +extern UString RootFolder_GetName_Documents(int &iconIndex); + + +static int Find_FileExtension_DotPos_in_path(const wchar_t *path) +{ + int dotPos = -1; + unsigned i; + for (i = 0;; i++) + { + const wchar_t c = path[i]; + if (c == 0) + return dotPos; + if (c == '.') + dotPos = (int)i; + else if (IS_PATH_SEPAR(c) || c == ':') + dotPos = -1; + } +} + + +void CPanel::LoadFullPathAndShow() +{ + LoadFullPath(); + _appState->FolderHistory.AddString(_currentFolderPrefix); + + _headerComboBox.SetText(_currentFolderPrefix); + + #ifndef UNDER_CE + + COMBOBOXEXITEM item; + item.mask = 0; + item.iImage = -1; + + UString path = _currentFolderPrefix; + // path = "\\\\.\\PhysicalDrive1\\"; // for debug + // path = "\\\\.\\y:\\"; // for debug + if (!path.IsEmpty()) + { + const unsigned rootPrefixSize = NName::GetRootPrefixSize(path); + if (rootPrefixSize == 0 && path[0] != '\\') + { + int iconIndex = -1; + UString name_Computer = RootFolder_GetName_Computer(iconIndex); + name_Computer.Add_PathSepar(); + if (path == name_Computer + || path == L"\\\\?\\") + item.iImage = iconIndex; + else + { + UString name = RootFolder_GetName_Network(iconIndex); + name.Add_PathSepar(); + if (path == name) + item.iImage = iconIndex; + } + } + + if (item.iImage < 0) + { + if (rootPrefixSize == 0 || rootPrefixSize == path.Len()) + { + DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; + CFileInfo info; + if (info.Find(us2fs(path))) + attrib = info.Attrib; + NName::If_IsSuperPath_RemoveSuperPrefix(path); + item.iImage = GetRealIconIndex_for_DirPath(us2fs(path), attrib); + } + else if (rootPrefixSize == NName::kDevicePathPrefixSize + && NName::IsDevicePath(us2fs(path.Left(path.Len() - 1)))) + { + if (path.IsPrefixedBy_Ascii_NoCase("\\\\.\\")) + path.DeleteFrontal(4); + if (path.Len() > 3) // is not "c:\\" + { + // PhysicalDrive + if (path.Back() == '\\') + path.DeleteBack(); + } + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), FILE_ATTRIBUTE_ARCHIVE); + } + else + { + if (path.Back() == '\\') + path.DeleteBack(); + bool need_Fs_Check = true; + bool is_File = false; + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &link = _parentFolders.Back(); + if (link.VirtualPath == path) + { + is_File = true; + if (_parentFolders.Size() != 1) + need_Fs_Check = false; + } + else + need_Fs_Check = false; + } + if (need_Fs_Check) + { + CFileInfo info; + const bool finded = info.Find(us2fs(path)); + DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; + if (finded) + attrib = info.Attrib; + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), attrib); + } + if (item.iImage <= 0 && is_File) + { + int dotPos = Find_FileExtension_DotPos_in_path(path); + if (dotPos < 0) + dotPos = (int)path.Len(); + item.iImage = g_Ext_to_Icon_Map.GetIconIndex(FILE_ATTRIBUTE_ARCHIVE, path.Ptr(dotPos)); + } + } + } + } + + if (item.iImage < 0) + item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR(); + // if (item.iImage < 0) item.iImage = 0; + // item.iImage = -1; // for debug + if (item.iImage >= 0) + { + item.iSelectedImage = item.iImage; + item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE); + } + item.iItem = -1; + _headerComboBox.SetItem(&item); + + #endif + + RefreshTitle(); +} + +#ifndef UNDER_CE +LRESULT CPanel::OnNotifyComboBoxEnter(const UString &s) +{ + if (BindToPathAndRefresh(GetUnicodeString(s)) == S_OK) + { + PostMsg(kSetFocusToListView); + return TRUE; + } + return FALSE; +} + +bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result) +{ + if (info->iWhy == CBENF_ESCAPE) + { + _headerComboBox.SetText(_currentFolderPrefix); + PostMsg(kSetFocusToListView); + result = FALSE; + return true; + } + + /* + if (info->iWhy == CBENF_DROPDOWN) + { + result = FALSE; + return true; + } + */ + + if (info->iWhy == CBENF_RETURN) + { + // When we use Edit control and press Enter. + UString s; + _headerComboBox.GetText(s); + result = OnNotifyComboBoxEnter(s); + return true; + } + return false; +} +#endif + +#ifndef _UNICODE +bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result) +{ + if (info->iWhy == CBENF_ESCAPE) + { + _headerComboBox.SetText(_currentFolderPrefix); + PostMsg(kSetFocusToListView); + result = FALSE; + return true; + } + /* + if (info->iWhy == CBENF_DROPDOWN) + { + result = FALSE; + return true; + } + */ + + if (info->iWhy == CBENF_RETURN) + { + UString s; + _headerComboBox.GetText(s); + // GetUnicodeString(info->szText) + result = OnNotifyComboBoxEnter(s); + return true; + } + return false; +} +#endif + +void CPanel::AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList) +{ + #ifdef UNDER_CE + + UString s; + iconIndex = iconIndex; + for (unsigned i = 0; i < indent; i++) + s += " "; + _headerComboBox.AddString(s + name); + + #else + + COMBOBOXEXITEMW item; + item.mask = CBEIF_TEXT | CBEIF_INDENT; + if (iconIndex < 0) + iconIndex = g_Ext_to_Icon_Map.GetIconIndex_DIR(); + item.iSelectedImage = item.iImage = iconIndex; + if (iconIndex >= 0) + item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE); + item.iItem = -1; + item.iIndent = (int)indent; + item.pszText = name.Ptr_non_const(); + _headerComboBox.InsertItem(&item); + + #endif + + if (addToList) + { + UString s = name; + s.Add_PathSepar(); + ComboBoxPaths.Add(s); + } +} + + +bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result) +{ + result = FALSE; + switch (code) + { + case CBN_DROPDOWN: + { + ComboBoxPaths.Clear(); + _headerComboBox.ResetContent(); + + UString sumPath; + UStringVector pathParts; + unsigned indent = 0; + { + UString path = _currentFolderPrefix; + // path = L"\\\\.\\y:\\"; // for debug + UString prefix0; + if (path.IsPrefixedBy_Ascii_NoCase("\\\\")) + { + const int separ = FindCharPosInString(path.Ptr(2), '\\'); + if (separ > 0 + && (separ > 1 || path[2] != '.')) // "\\\\.\\" will be processed later + { + const UString s = path.Left(2 + separ); + prefix0 = s; + prefix0.Add_PathSepar(); + AddComboBoxItem(s, + GetRealIconIndex_for_DirPath(us2fs(prefix0), FILE_ATTRIBUTE_DIRECTORY), + indent++, + false); // addToList + ComboBoxPaths.Add(prefix0); + } + } + + unsigned rootPrefixSize = NName::GetRootPrefixSize(path); + + sumPath = path; + + if (rootPrefixSize <= prefix0.Len()) + { + rootPrefixSize = prefix0.Len(); + sumPath.DeleteFrom(rootPrefixSize); + } + else + { + // rootPrefixSize > prefix0.Len() + sumPath.DeleteFrom(rootPrefixSize); + + CFileInfo info; + DWORD attrib = FILE_ATTRIBUTE_DIRECTORY; + if (info.Find(us2fs(sumPath)) && info.IsDir()) + attrib = info.Attrib; + UString s = sumPath.Ptr(prefix0.Len()); + if (!s.IsEmpty()) + { + const wchar_t c = s.Back(); + if (IS_PATH_SEPAR(c)) + s.DeleteBack(); + } + UString path_for_icon = sumPath; + NName::If_IsSuperPath_RemoveSuperPrefix(path_for_icon); + + AddComboBoxItem(s, + GetRealIconIndex_for_DirPath(us2fs(path_for_icon), attrib), + indent++, + false); // addToList + ComboBoxPaths.Add(sumPath); + } + + path.DeleteFrontal(rootPrefixSize); + SplitPathToParts(path, pathParts); + } + + // it's expected that pathParts.Back() is empty, because _currentFolderPrefix has PathSeparator. + unsigned next_Arc_index = 0; + int iconIndex_Computer; + const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer); + + // const bool is_devicePrefix = (sumPath == L"\\\\.\\"); + + if (pathParts.Size() > 1) + if (!sumPath.IsEmpty() + || pathParts.Size() != 2 + || pathParts[0] != name_Computer) + for (unsigned i = 0; i + 1 < pathParts.Size(); i++) + { + UString name = pathParts[i]; + sumPath += name; + + bool isRootDir_inLink = false; + if (next_Arc_index < _parentFolders.Size()) + { + const CFolderLink &link = _parentFolders[next_Arc_index]; + if (link.VirtualPath == sumPath) + { + isRootDir_inLink = true; + next_Arc_index++; + } + } + + int iconIndex = -1; + DWORD attrib = isRootDir_inLink ? + FILE_ATTRIBUTE_ARCHIVE: + FILE_ATTRIBUTE_DIRECTORY; + if (next_Arc_index == 0 + || (next_Arc_index == 1 && isRootDir_inLink)) + { + if (i == 0 && NName::IsDevicePath(us2fs(sumPath))) + { + UString path = name; + path.Add_PathSepar(); + attrib = FILE_ATTRIBUTE_ARCHIVE; + // FILE_ATTRIBUTE_DIRECTORY; + } + else + { + CFileInfo info; + if (info.Find(us2fs(sumPath))) + attrib = info.Attrib; + } + iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(sumPath), attrib); + } + + if (iconIndex < 0) + iconIndex = g_Ext_to_Icon_Map.GetIconIndex(attrib, name); + // iconIndex = -1; // for debug + if (iconIndex < 0 && isRootDir_inLink) + iconIndex = 0; // default file + + sumPath.Add_PathSepar(); + + ComboBoxPaths.Add(sumPath); + if (name.IsEmpty()) + name.Add_PathSepar(); + AddComboBoxItem(name, iconIndex, indent++, + false); // addToList + } + +#ifndef UNDER_CE + + { + int iconIndex; + const UString name = RootFolder_GetName_Documents(iconIndex); + // iconIndex = -1; // for debug + AddComboBoxItem(name, iconIndex, 0, true); + } + AddComboBoxItem(name_Computer, iconIndex_Computer, 0, true); + { + FStringVector driveStrings; + MyGetLogicalDriveStrings(driveStrings); + FOR_VECTOR (i, driveStrings) + { + FString s = driveStrings[i]; + ComboBoxPaths.Add(fs2us(s)); + int iconIndex2 = GetRealIconIndex_for_DirPath(s, FILE_ATTRIBUTE_DIRECTORY); + if (!s.IsEmpty()) + { + const FChar c = s.Back(); + if (IS_PATH_SEPAR(c)) + s.DeleteBack(); + } + // iconIndex2 = -1; // for debug + AddComboBoxItem(fs2us(s), iconIndex2, 1, false); + } + } + { + int iconIndex; + const UString name = RootFolder_GetName_Network(iconIndex); + AddComboBoxItem(name, iconIndex, 0, true); + } + +#endif + + return false; + } + + case CBN_SELENDOK: + { + int index = _headerComboBox.GetCurSel(); + if (index >= 0) + { + const UString path = ComboBoxPaths[index]; + _headerComboBox.SetCurSel(-1); + // _headerComboBox.SetText(pass); // it's fix for selecting by mouse. + if (BindToPathAndRefresh(path) == S_OK) + { + PostMsg(kSetFocusToListView); + #ifdef UNDER_CE + PostMsg(kRefresh_HeaderComboBox); + #endif + return true; + } + } + return false; + } + /* + case CBN_CLOSEUP: + { + LoadFullPathAndShow(); + true; + + } + case CBN_SELCHANGE: + { + // LoadFullPathAndShow(); + return true; + } + */ + } + return false; +} + +bool CPanel::OnNotifyComboBox(LPNMHDR NON_CE_VAR(header), LRESULT & NON_CE_VAR(result)) +{ + #ifndef UNDER_CE + switch (header->code) + { + case CBEN_BEGINEDIT: + { + _lastFocusedIsList = false; + _panelCallback->PanelWasFocused(); + break; + } + #ifndef _UNICODE + case CBEN_ENDEDIT: + { + return OnNotifyComboBoxEndEdit((PNMCBEENDEDIT)header, result); + } + #endif + case CBEN_ENDEDITW: + { + return OnNotifyComboBoxEndEdit((PNMCBEENDEDITW)header, result); + } + } + #endif + return false; +} + + +void CPanel::FoldersHistory() +{ + CListViewDialog listViewDialog; + listViewDialog.DeleteIsAllowed = true; + listViewDialog.SelectFirst = true; + LangString(IDS_FOLDERS_HISTORY, listViewDialog.Title); + _appState->FolderHistory.GetList(listViewDialog.Strings); + if (listViewDialog.Create(GetParent()) != IDOK) + return; + UString selectString; + if (listViewDialog.StringsWereChanged) + { + _appState->FolderHistory.RemoveAll(); + for (int i = (int)listViewDialog.Strings.Size() - 1; i >= 0; i--) + _appState->FolderHistory.AddString(listViewDialog.Strings[i]); + if (listViewDialog.FocusedItemIndex >= 0) + selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex]; + } + else + { + if (listViewDialog.FocusedItemIndex >= 0) + selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex]; + } + if (listViewDialog.FocusedItemIndex >= 0) + BindToPathAndRefresh(selectString); +} + + +UString CPanel::GetParentDirPrefix() const +{ + UString s; + if (!_currentFolderPrefix.IsEmpty()) + { + wchar_t c = _currentFolderPrefix.Back(); + if (IS_PATH_SEPAR(c) || c == ':') + { + s = _currentFolderPrefix; + s.DeleteBack(); + if (s != L"\\\\." && + s != L"\\\\?") + { + int pos = s.ReverseFind_PathSepar(); + if (pos >= 0) + s.DeleteFrom((unsigned)(pos + 1)); + } + } + } + return s; +} + + +void CPanel::OpenParentFolder() +{ + LoadFullPath(); // Maybe we don't need it ?? + + UString parentFolderPrefix; + UString focusedName; + + if (!_currentFolderPrefix.IsEmpty()) + { + wchar_t c = _currentFolderPrefix.Back(); + if (IS_PATH_SEPAR(c) || c == ':') + { + focusedName = _currentFolderPrefix; + focusedName.DeleteBack(); + /* + if (c == ':' && !focusedName.IsEmpty() && IS_PATH_SEPAR(focusedName.Back())) + { + focusedName.DeleteBack(); + } + else + */ + if (focusedName != L"\\\\." && + focusedName != L"\\\\?") + { + const int pos = focusedName.ReverseFind_PathSepar(); + if (pos >= 0) + { + parentFolderPrefix = focusedName; + parentFolderPrefix.DeleteFrom((unsigned)(pos + 1)); + focusedName.DeleteFrontal((unsigned)(pos + 1)); + } + } + } + } + + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + + CMyComPtr newFolder; + _folder->BindToParentFolder(&newFolder); + + // newFolder.Release(); // for test + + if (newFolder) + SetNewFolder(newFolder); + else + { + bool needSetFolder = true; + if (!_parentFolders.IsEmpty()) + { + { + const CFolderLink &link = _parentFolders.Back(); + parentFolderPrefix = link.ParentFolderPath; + focusedName = link.RelPath; + } + CloseOneLevel(); + needSetFolder = (!_folder); + } + + if (needSetFolder) + { + { + COpenResult openRes; + BindToPath(parentFolderPrefix, UString(), openRes); + } + } + } + + CSelectedState state; + state.FocusedName = focusedName; + state.FocusedName_Defined = true; + /* + if (!focusedName.IsEmpty()) + state.SelectedNames.Add(focusedName); + */ + LoadFullPath(); + // ::SetCurrentDirectory(::_currentFolderPrefix); + RefreshListCtrl(state); + // _listView.EnsureVisible(_listView.GetFocusedItem(), false); +} + + +void CPanel::CloseOneLevel() +{ + ReleaseFolder(); + _library.Free(); + { + CFolderLink &link = _parentFolders.Back(); + if (link.ParentFolder) + SetNewFolder(link.ParentFolder); + _library.Attach(link.Library.Detach()); + } + if (_parentFolders.Size() > 1) + OpenParentArchiveFolder(); + _parentFolders.DeleteBack(); + if (_parentFolders.IsEmpty()) + _flatMode = _flatModeForDisk; +} + +void CPanel::CloseOpenFolders() +{ + while (!_parentFolders.IsEmpty()) + CloseOneLevel(); + _flatMode = _flatModeForDisk; + ReleaseFolder(); + _library.Free(); +} + +void CPanel::OpenRootFolder() +{ + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + _parentFolders.Clear(); + SetToRootFolder(); + RefreshListCtrl(); + // ::SetCurrentDirectory(::_currentFolderPrefix); + /* + BeforeChangeFolder(); + _currentFolderPrefix.Empty(); + AfterChangeFolder(); + SetCurrentPathText(); + RefreshListCtrl(UString(), 0, UStringVector()); + _listView.EnsureVisible(_listView.GetFocusedItem(), false); + */ +} + +void CPanel::OpenDrivesFolder() +{ + CloseOpenFolders(); + #ifdef UNDER_CE + NFsFolder::CFSFolder *folderSpec = new NFsFolder::CFSFolder; + SetNewFolder(folderSpec); + folderSpec->InitToRoot(); + #else + CFSDrives *folderSpec = new CFSDrives; + SetNewFolder(folderSpec); + folderSpec->Init(); + #endif + RefreshListCtrl(); +} + +void CPanel::OpenFolder(unsigned index) +{ + if (index == kParentIndex) + { + OpenParentFolder(); + return; + } + CMyComPtr newFolder; + const HRESULT res = _folder->BindToFolder((unsigned)index, &newFolder); + if (res != 0) + { + MessageBox_Error_HRESULT(res); + return; + } + if (!newFolder) + return; + SetNewFolder(newFolder); + LoadFullPath(); + RefreshListCtrl(); + // 17.02: fixed : now we don't select first item + // _listView.SetItemState_Selected(_listView.GetFocusedItem()); + _listView.EnsureVisible(_listView.GetFocusedItem(), false); +} + +void CPanel::OpenAltStreams() +{ + CRecordVector indices; + Get_ItemIndices_Operated(indices); + Int32 realIndex = -1; + if (indices.Size() > 1) + return; + if (indices.Size() == 1) + realIndex = (Int32)indices[0]; + + if (_folderAltStreams) + { + CMyComPtr newFolder; + _folderAltStreams->BindToAltStreams((UInt32)realIndex, &newFolder); + if (newFolder) + { + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + SetNewFolder(newFolder); + RefreshListCtrl(); + return; + } + return; + } + + #if defined(_WIN32) && !defined(UNDER_CE) + UString path; + if (realIndex >= 0) + path = GetItemFullPath((UInt32)realIndex); + else + { + path = GetFsPath(); + if (!NName::IsDriveRootPath_SuperAllowed(us2fs(path))) + if (!path.IsEmpty() && IS_PATH_SEPAR(path.Back())) + path.DeleteBack(); + } + + path.Add_Colon(); + BindToPathAndRefresh(path); + #endif +} diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index b50a451fe..aa56ef5fa 100644 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -1,1785 +1,1798 @@ -// PanelItemOpen.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#include - -#include "../../../Common/IntToString.h" - -#include "../../../Common/AutoPtr.h" - -#include "../../../Windows/ProcessUtils.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../Common/FileStreams.h" -#include "../../Common/StreamObjects.h" - -#include "../Common/ExtractingFilePath.h" - -#include "App.h" - -#include "FileFolderPluginOpen.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "PropertyNameRes.h" -#include "RegistryUtils.h" -#include "UpdateCallback100.h" - -#include "../GUI/ExtractRes.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NSynchronization; -using namespace NFile; -using namespace NDir; - -extern bool g_RAM_Size_Defined; -extern UInt64 g_RAM_Size; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -#define kTempDirPrefix FTEXT("7zO") - -// #define SHOW_DEBUG_INFO - -#ifdef SHOW_DEBUG_INFO - #define DEBUG_PRINT(s) OutputDebugStringA(s); - #define DEBUG_PRINT_W(s) OutputDebugStringW(s); - #define DEBUG_PRINT_NUM(s, num) { char ttt[32]; ConvertUInt32ToString(num, ttt); OutputDebugStringA(s); OutputDebugStringA(ttt); } -#else - #define DEBUG_PRINT(s) - #define DEBUG_PRINT_W(s) - #define DEBUG_PRINT_NUM(s, num) -#endif - - - -#ifndef UNDER_CE - -class CProcessSnapshot -{ - HANDLE _handle; -public: - CProcessSnapshot(): _handle(INVALID_HANDLE_VALUE) {} - ~CProcessSnapshot() { Close(); } - - bool Close() - { - if (_handle == INVALID_HANDLE_VALUE) - return true; - if (!::CloseHandle(_handle)) - return false; - _handle = INVALID_HANDLE_VALUE; - return true; - } - - bool Create() - { - _handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - return (_handle != INVALID_HANDLE_VALUE); - } - - bool GetFirstProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32First(_handle, pe)); } - bool GetNextProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32Next(_handle, pe)); } -}; - -#endif - - -/* -struct COpenExtProg -{ - const char *Ext; - const char *Prog; -}; - -static const COpenExtProg g_Progs[] = -{ - { "jpeg jpg png bmp gif", "Microsoft.Photos.exe" }, - { "html htm pdf", "MicrosoftEdge.exe" }, - // , { "rrr", "notepad.exe" } -}; - -static bool FindExtProg(const char *exts, const char *ext) -{ - unsigned len = (unsigned)strlen(ext); - for (;;) - { - const char *p = exts; - for (;; p++) - { - const char c = *p; - if (c == 0 || c == ' ') - break; - } - if (len == (unsigned)(p - exts) && IsString1PrefixedByString2(exts, ext)) - return true; - if (*p == 0) - return false; - exts = p + 1; - } -} - -class CPossibleProgs -{ -public: - AStringVector ProgNames; - - void SetFromExtension(const char *ext) // ext must be low case - { - ProgNames.Clear(); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Progs); i++) - if (FindExtProg(g_Progs[i].Ext, ext)) - { - ProgNames.Add(g_Progs[i].Prog); - } - } - - bool IsFromList(const UString &progName) const - { - FOR_VECTOR (i, ProgNames) - if (progName.IsEqualTo_Ascii_NoCase(ProgNames[i])) - return true; - return false; - } -}; -*/ - - -#ifndef UNDER_CE - -EXTERN_C_BEGIN - -/* -GetProcessImageFileName - returns the path in device form, rather than drive letters: - \Device\HarddiskVolume1\WINDOWS\SysWOW64\notepad.exe - -GetModuleFileNameEx works only after Sleep(something). Why? - returns the path - C:\WINDOWS\system32\NOTEPAD.EXE -*/ - -/* Kernel32.dll: Win7, Win2008R2; - Psapi.dll: (if PSAPI_VERSION=1) on Win7 and Win2008R2; - Psapi.dll: XP, Win2003, Vista, 2008; -*/ - -typedef DWORD (WINAPI *Func_GetProcessImageFileNameW)( - HANDLE hProcess, LPWSTR lpFilename, DWORD nSize); - -typedef DWORD (WINAPI *Func_GetModuleFileNameExW)( - HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize); - -typedef DWORD (WINAPI *Func_GetProcessId)(HANDLE process); - -EXTERN_C_END - - -static HMODULE g_Psapi_dll_module; - -/* -static void My_GetProcessFileName_2(HANDLE hProcess, UString &path) -{ - path.Empty(); - const unsigned maxPath = 1024; - WCHAR temp[maxPath + 1]; - - const char *func_name = "GetModuleFileNameExW"; - Func_GetModuleFileNameExW my_func = (Func_GetModuleFileNameExW) - ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), func_name); - if (!my_func) - { - if (!g_Psapi_dll_module) - g_Psapi_dll_module = LoadLibraryW(L"Psapi.dll"); - if (g_Psapi_dll_module) - my_func = (Func_GetModuleFileNameExW)::GetProcAddress(g_Psapi_dll_module, func_name); - } - if (my_func) - { - // DWORD num = GetModuleFileNameEx(hProcess, NULL, temp, maxPath); - DWORD num = my_func(hProcess, NULL, temp, maxPath); - if (num != 0) - path = temp; - } - // FreeLibrary(lib); -} -*/ - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -static void My_GetProcessFileName(HANDLE hProcess, UString &path) -{ - path.Empty(); - const unsigned maxPath = 1024; - WCHAR temp[maxPath + 1]; - - const char *func_name = - "GetProcessImageFileNameW"; - Func_GetProcessImageFileNameW my_func = Z7_GET_PROC_ADDRESS( - Func_GetProcessImageFileNameW, ::GetModuleHandleA("kernel32.dll"), func_name); - - if (!my_func) - { - if (!g_Psapi_dll_module) - g_Psapi_dll_module = LoadLibraryW(L"Psapi.dll"); - if (g_Psapi_dll_module) - my_func = Z7_GET_PROC_ADDRESS( - Func_GetProcessImageFileNameW, g_Psapi_dll_module, func_name); - } - - if (my_func) - { - const DWORD num = - // GetProcessImageFileNameW(hProcess, temp, maxPath); - my_func(hProcess, temp, maxPath); - if (num != 0) - path = temp; - } - // FreeLibrary(lib); -} - -struct CSnapshotProcess -{ - DWORD Id; - DWORD ParentId; - UString Name; -}; - -static void GetSnapshot(CObjectVector &items) -{ - items.Clear(); - - CProcessSnapshot snapshot; - if (!snapshot.Create()) - return; - - DEBUG_PRINT("snapshot.Create() OK"); - PROCESSENTRY32 pe; - CSnapshotProcess item; - memset(&pe, 0, sizeof(pe)); - pe.dwSize = sizeof(pe); - BOOL res = snapshot.GetFirstProcess(&pe); - while (res) - { - item.Id = pe.th32ProcessID; - item.ParentId = pe.th32ParentProcessID; - item.Name = GetUnicodeString(pe.szExeFile); - items.Add(item); - res = snapshot.GetNextProcess(&pe); - } -} - -#endif - - -class CChildProcesses -{ - #ifndef UNDER_CE - CRecordVector _ids; - #endif - -public: - // bool ProgsWereUsed; - CRecordVector Handles; - CRecordVector NeedWait; - // UStringVector Names; - - #ifndef UNDER_CE - UString Path; - #endif - - // CChildProcesses(): ProgsWereUsed(false) {} - ~CChildProcesses() { CloseAll(); } - void DisableWait(unsigned index) { NeedWait[index] = false; } - - void CloseAll() - { - FOR_VECTOR (i, Handles) - { - HANDLE h = Handles[i]; - if (h != NULL) - CloseHandle(h); - } - - Handles.Clear(); - NeedWait.Clear(); - // Names.Clear(); - - #ifndef UNDER_CE - // Path.Empty(); - _ids.Clear(); - #endif - } - - void SetMainProcess(HANDLE h) - { - #ifndef UNDER_CE - const - Func_GetProcessId func = Z7_GET_PROC_ADDRESS( - Func_GetProcessId, ::GetModuleHandleA("kernel32.dll"), - "GetProcessId"); - if (func) - { - const DWORD id = func(h); - if (id != 0) - _ids.AddToUniqueSorted(id); - } - - My_GetProcessFileName(h, Path); - DEBUG_PRINT_W(Path); - - #endif - - Handles.Add(h); - NeedWait.Add(true); - } - - #ifndef UNDER_CE - - void Update(bool needFindProcessByPath /* , const CPossibleProgs &progs */) - { - /* - if (_ids.IsEmpty()) - return; - */ - - CObjectVector sps; - GetSnapshot(sps); - - const int separ = Path.ReverseFind_PathSepar(); - const UString mainName = Path.Ptr((unsigned)(separ + 1)); - if (mainName.IsEmpty()) - needFindProcessByPath = false; - - const DWORD currentProcessId = GetCurrentProcessId(); - - for (;;) - { - bool wasAdded = false; - - FOR_VECTOR (i, sps) - { - const CSnapshotProcess &sp = sps[i]; - const DWORD id = sp.Id; - - if (id == currentProcessId) - continue; - if (_ids.FindInSorted(id) >= 0) - continue; - - bool isSameName = false; - const UString &name = sp.Name; - - if (needFindProcessByPath) - isSameName = mainName.IsEqualTo_NoCase(name); - - bool needAdd = false; - // bool isFromProgs = false; - - if (isSameName || _ids.FindInSorted(sp.ParentId) >= 0) - needAdd = true; - /* - else if (progs.IsFromList(name)) - { - needAdd = true; - isFromProgs = true; - } - */ - - if (needAdd) - { - DEBUG_PRINT("----- OpenProcess -----"); - DEBUG_PRINT_W(name); - HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, id); - if (hProcess) - { - DEBUG_PRINT("----- OpenProcess OK -----"); - // if (!isFromProgs) - _ids.AddToUniqueSorted(id); - Handles.Add(hProcess); - NeedWait.Add(true); - // Names.Add(name); - wasAdded = true; - // ProgsWereUsed = isFromProgs; - } - } - } - - if (!wasAdded) - break; - } - } - - #endif -}; - - -struct CTmpProcessInfo: public CTempFileInfo -{ - CChildProcesses Processes; - HWND Window; - UString FullPathFolderPrefix; - bool UsePassword; - UString Password; - - bool ReadOnly; - - CTmpProcessInfo(): UsePassword(false), ReadOnly(false) {} -}; - - -class CTmpProcessInfoRelease -{ - CTmpProcessInfo *_tmpProcessInfo; -public: - bool _needDelete; - CTmpProcessInfoRelease(CTmpProcessInfo &tpi): - _tmpProcessInfo(&tpi), _needDelete(true) {} - ~CTmpProcessInfoRelease() - { - if (_needDelete) - _tmpProcessInfo->DeleteDirAndFile(); - } -}; - -void GetFolderError(CMyComPtr &folder, UString &s); - - -HRESULT CPanel::OpenAsArc(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat, - COpenResult &openRes) -{ - openRes.Encrypted = false; - CFolderLink folderLink; - (CTempFileInfo &)folderLink = tempFileInfo; - - if (inStream) - folderLink.IsVirtual = true; - else - { - if (!folderLink.FileInfo.Find(folderLink.FilePath)) - return GetLastError_noZero_HRESULT(); - if (folderLink.FileInfo.IsDir()) - return S_FALSE; - folderLink.IsVirtual = false; - } - - folderLink.VirtualPath = virtualFilePath; - - CFfpOpen ffp; - const HRESULT res = ffp.OpenFileFolderPlugin(inStream, - folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath, - arcFormat, GetParent()); - - openRes.Encrypted = ffp.Encrypted; - openRes.ErrorMessage = ffp.ErrorMessage; - - RINOK(res) - - folderLink.Password = ffp.Password; - folderLink.UsePassword = ffp.Encrypted; - - if (_folder) - folderLink.ParentFolderPath = GetFolderPath(_folder); - else - folderLink.ParentFolderPath = _currentFolderPrefix; - - if (!_parentFolders.IsEmpty()) - folderLink.ParentFolder = _folder; - - _parentFolders.Add(folderLink); - _parentFolders.Back().Library.Attach(_library.Detach()); - - ReleaseFolder(); - _library.Free(); - SetNewFolder(ffp.Folder); - _library.Attach(ffp.Library.Detach()); - - _flatMode = _flatModeForArc; - - _thereAreDeletedItems = false; - - if (!openRes.ErrorMessage.IsEmpty()) - MessageBox_Error(openRes.ErrorMessage); - /* - UString s; - GetFolderError(_folder, s); - if (!s.IsEmpty()) - MessageBox_Error(s); - */ - // we don't show error here by some reasons: - // after MessageBox_Warning it throws exception in nested archives in Debug Mode. why ?. - // MessageBox_Warning(L"test error"); - - return S_OK; -} - - -HRESULT CPanel::OpenAsArc_Msg(IInStream *inStream, - const CTempFileInfo &tempFileInfo, - const UString &virtualFilePath, - const UString &arcFormat - // , bool &encrypted - // , bool showErrorMessage - ) -{ - COpenResult opRes; - - HRESULT res = OpenAsArc(inStream, tempFileInfo, virtualFilePath, arcFormat, opRes); - - if (res == S_OK) - return res; - if (res == E_ABORT) - return res; - - // if (showErrorMessage) - if (opRes.Encrypted || res != S_FALSE) // 17.01 : we show message also for (res != S_FALSE) - { - UString message; - if (res == S_FALSE) - { - message = MyFormatNew( - opRes.Encrypted ? - IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : - IDS_CANT_OPEN_ARCHIVE, - virtualFilePath); - } - else - message = HResultToMessage(res); - MessageBox_Error(message); - } - - return res; -} - - -HRESULT CPanel::OpenAsArc_Name(const UString &relPath, const UString &arcFormat - // , bool &encrypted, - // , bool showErrorMessage - ) -{ - CTempFileInfo tfi; - tfi.RelPath = relPath; - tfi.FolderPath = us2fs(GetFsPath()); - const UString fullPath = GetFsPath() + relPath; - tfi.FilePath = us2fs(fullPath); - return OpenAsArc_Msg(NULL, tfi, fullPath, arcFormat /* , encrypted, showErrorMessage */); -} - - -HRESULT CPanel::OpenAsArc_Index(unsigned index, const wchar_t *type - // , bool showErrorMessage - ) -{ - CDisableTimerProcessing disableTimerProcessing1(*this); - CDisableNotify disableNotify(*this); - - HRESULT res = OpenAsArc_Name(GetItemRelPath2(index), type ? type : L"" /* , encrypted, showErrorMessage */); - if (res != S_OK) - { - RefreshTitle(true); // in case of error we must refresh changed title of 7zFM - return res; - } - RefreshListCtrl(); - return S_OK; -} - - -HRESULT CPanel::OpenParentArchiveFolder() -{ - CDisableTimerProcessing disableTimerProcessing(*this); - CDisableNotify disableNotify(*this); - if (_parentFolders.Size() < 2) - return S_OK; - const CFolderLink &folderLinkPrev = _parentFolders[_parentFolders.Size() - 2]; - const CFolderLink &folderLink = _parentFolders.Back(); - NFind::CFileInfo newFileInfo; - if (newFileInfo.Find(folderLink.FilePath)) - { - if (folderLink.WasChanged(newFileInfo)) - { - UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath); - if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) == IDYES) - { - if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath), - folderLinkPrev.UsePassword, folderLinkPrev.Password) != S_OK) - { - ::MessageBoxW((HWND)*this, MyFormatNew(IDS_CANNOT_UPDATE_FILE, - fs2us(folderLink.FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP); - return S_OK; - } - } - } - } - folderLink.DeleteDirAndFile(); - return S_OK; -} - - -static const char * const kExeExtensions = - " exe bat ps1 com lnk" - " "; - -static const char * const kStartExtensions = - #ifdef UNDER_CE - " cab" - #endif - " exe bat ps1 com lnk" - " chm" - " msi doc dot xls ppt pps wps wpt wks xlr wdb vsd pub" - - " docx docm dotx dotm xlsx xlsm xltx xltm xlsb xps" - " xlam pptx pptm potx potm ppam ppsx ppsm vsdx xsn" - " mpp" - " msg" - " dwf" - - " flv swf" - - " epub" - " odt ods" - " wb3" - " pdf" - " ps" - " txt" - " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" - " h hpp hxx c cpp cxx m mm go swift" - " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs" - " asm" - " mak clw csproj vcproj sln dsp dsw" - " "; - -// bool FindExt(const char *p, const UString &name, AString &s); -bool FindExt(const char *p, const UString &name, CStringFinder &finder); - -static bool DoItemAlwaysStart(const UString &name) -{ - CStringFinder finder; - return FindExt(kStartExtensions, name, finder); -} - -UString GetQuotedString(const UString &s); - - -void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms); -void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms) -{ - params.Empty(); - prg = cmd; - prg.Trim(); - if (prg.Len() >= 2 && prg[0] == L'"') - { - int pos = prg.Find(L'"', 1); - if (pos >= 0) - { - if ((unsigned)(pos + 1) == prg.Len() || prg[pos + 1] == ' ') - { - params = prg.Ptr((unsigned)(pos + 1)); - params.Trim(); - prg.DeleteFrom((unsigned)pos); - prg.DeleteFrontal(1); - } - } - } -} - - -static WRes StartAppWithParams(const UString &cmd, const UStringVector ¶mVector, CProcess &process) -{ - UString param; - UString prg; - - SplitCmdLineSmart(cmd, prg, param); - - param.Trim(); - - // int pos = params.Find(L"%1"); - - FOR_VECTOR (i, paramVector) - { - if (!param.IsEmpty() && param.Back() != ' ') - param.Add_Space(); - param += GetQuotedString(paramVector[i]); - } - - return process.Create(prg, param, NULL); -} - - -static HRESULT StartEditApplication(const UString &path, bool useEditor, HWND window, CProcess &process) -{ - UString command; - ReadRegEditor(useEditor, command); - if (command.IsEmpty()) - { - #ifdef UNDER_CE - command = "\\Windows\\"; - #else - FString winDir; - if (!GetWindowsDir(winDir)) - return 0; - NName::NormalizeDirPathPrefix(winDir); - command = fs2us(winDir); - #endif - command += "notepad.exe"; - } - - UStringVector params; - params.Add(path); - - const WRes res = StartAppWithParams(command, params, process); - if (res != 0) - ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); - return HRESULT_FROM_WIN32(res); -} - - -void CApp::DiffFiles() -{ - const CPanel &panel = GetFocusedPanel(); - - if (!panel.Is_IO_FS_Folder()) - { - panel.MessageBox_Error_UnsupportOperation(); - return; - } - - CRecordVector indices; - panel.Get_ItemIndices_Selected(indices); - - UString path1, path2; - if (indices.Size() == 2) - { - path1 = panel.GetItemFullPath(indices[0]); - path2 = panel.GetItemFullPath(indices[1]); - } - else if (indices.Size() == 1 && NumPanels >= 2) - { - const CPanel &destPanel = Panels[1 - LastFocusedPanel]; - - if (!destPanel.Is_IO_FS_Folder()) - { - panel.MessageBox_Error_UnsupportOperation(); - return; - } - - path1 = panel.GetItemFullPath(indices[0]); - CRecordVector indices2; - destPanel.Get_ItemIndices_Selected(indices2); - if (indices2.Size() == 1) - path2 = destPanel.GetItemFullPath(indices2[0]); - else - { - UString relPath = panel.GetItemRelPath2(indices[0]); - if (panel._flatMode && !destPanel._flatMode) - relPath = panel.GetItemName(indices[0]); - path2 = destPanel._currentFolderPrefix + relPath; - } - } - else - return; - - DiffFiles(path1, path2); -} - -void CApp::DiffFiles(const UString &path1, const UString &path2) -{ - UString command; - ReadRegDiff(command); - if (command.IsEmpty()) - return; - - UStringVector params; - params.Add(path1); - params.Add(path2); - - WRes res; - { - CProcess process; - res = StartAppWithParams(command, params, process); - } - if (res == 0) - return; - ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); -} - - -HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process); -void StartApplicationDontWait(const UString &dir, const UString &path, HWND window); - -void CPanel::EditItem(unsigned index, bool useEditor) -{ - if (!_parentFolders.IsEmpty()) - { - OpenItemInArchive(index, false, true, true, useEditor); - return; - } - CProcess process; - StartEditApplication(GetItemFullPath(index), useEditor, (HWND)*this, process); -} - - -void CPanel::OpenFolderExternal(unsigned index) -{ - UString prefix = GetFsPath(); - UString path = prefix; - - if (index == kParentIndex) - { - if (prefix.IsEmpty()) - return; - const wchar_t c = prefix.Back(); - if (!IS_PATH_SEPAR(c) && c != ':') - return; - prefix.DeleteBack(); - int pos = prefix.ReverseFind_PathSepar(); - if (pos < 0) - return; - prefix.DeleteFrom((unsigned)(pos + 1)); - path = prefix; - } - else - { - path += GetItemRelPath(index); - path.Add_PathSepar(); - } - - StartApplicationDontWait(prefix, path, (HWND)*this); -} - - -bool CPanel::IsVirus_Message(const UString &name) -{ - UString name2; - - const wchar_t cRLO = (wchar_t)0x202E; - bool isVirus = false; - bool isSpaceError = false; - name2 = name; - - if (name2.Find(cRLO) >= 0) - { - const UString badString(cRLO); - name2.Replace(badString, L"[RLO]"); - isVirus = true; - } - { - const wchar_t * const kVirusSpaces = L" "; - // const unsigned kNumSpaces = strlen(kVirusSpaces); - for (;;) - { - int pos = name2.Find(kVirusSpaces); - if (pos < 0) - break; - isVirus = true; - isSpaceError = true; - name2.Replace(kVirusSpaces, L" "); - } - } - - #ifdef _WIN32 - { - unsigned i; - for (i = name2.Len(); i != 0;) - { - wchar_t c = name2[i - 1]; - if (c != '.' && c != ' ') - break; - i--; - name2.ReplaceOneCharAtPos(i, '_'); - } - if (i != name2.Len()) - { - CStringFinder finder; - UString name3 = name2; - name3.DeleteFrom(i); - if (FindExt(kExeExtensions, name3, finder)) - isVirus = true; - } - } - #endif - - if (!isVirus) - return false; - - UString s = LangString(IDS_VIRUS); - - if (!isSpaceError) - { - const int pos1 = s.Find(L'('); - if (pos1 >= 0) - { - const int pos2 = s.Find(L')', (unsigned)pos1 + 1); - if (pos2 >= 0) - { - s.Delete((unsigned)pos1, (unsigned)pos2 + 1 - (unsigned)pos1); - if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.') - s.Delete(pos1 - 1); - } - } - } - - UString name3 = name; - name3.Replace(L'\n', L'_'); - name2.Replace(L'\n', L'_'); - - s.Add_LF(); s += name2; - s.Add_LF(); s += name3; - - MessageBox_Error(s); - return true; -} - - -void CPanel::OpenItem(unsigned index, bool tryInternal, bool tryExternal, const wchar_t *type) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - const UString name = GetItemRelPath2(index); - - if (tryExternal) - if (IsVirus_Message(name)) - return; - - if (!_parentFolders.IsEmpty()) - { - OpenItemInArchive(index, tryInternal, tryExternal, false, false, type); - return; - } - - CDisableNotify disableNotify(*this); - UString prefix = GetFsPath(); - UString fullPath = prefix + name; - - if (tryInternal) - if (!tryExternal || !DoItemAlwaysStart(name)) - { - HRESULT res = OpenAsArc_Index(index, type - // , true - ); - disableNotify.Restore(); // we must restore to allow text notification update - InvalidateList(); - if (res == S_OK || res == E_ABORT) - return; - if (res != S_FALSE) - { - MessageBox_Error_HRESULT(res); - return; - } - } - - if (tryExternal) - { - // SetCurrentDirectory opens HANDLE to folder!!! - // NDirectory::MySetCurrentDirectory(prefix); - StartApplicationDontWait(prefix, fullPath, (HWND)*this); - } -} - -class CThreadCopyFrom: public CProgressThreadVirt -{ - HRESULT ProcessVirt() Z7_override; -public: - UString FullPath; - UInt32 ItemIndex; - - CMyComPtr FolderOperations; - CMyComPtr UpdateCallback; - CUpdateCallback100Imp *UpdateCallbackSpec; -}; - -HRESULT CThreadCopyFrom::ProcessVirt() -{ - return FolderOperations->CopyFromFile(ItemIndex, FullPath, UpdateCallback); -} - -HRESULT CPanel::OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, - bool usePassword, const UString &password) -{ - if (!_folderOperations) - { - MessageBox_Error_UnsupportOperation(); - return E_FAIL; - } - - CThreadCopyFrom t; - t.UpdateCallbackSpec = new CUpdateCallback100Imp; - t.UpdateCallback = t.UpdateCallbackSpec; - t.UpdateCallbackSpec->ProgressDialog = &t; - t.ItemIndex = index; - t.FullPath = fullFilePath; - t.FolderOperations = _folderOperations; - - t.UpdateCallbackSpec->Init(); - t.UpdateCallbackSpec->PasswordIsDefined = usePassword; - t.UpdateCallbackSpec->Password = password; - - - RINOK(t.Create(GetItemName(index), (HWND)*this)) - return t.Result; -} - -LRESULT CPanel::OnOpenItemChanged(LPARAM lParam) -{ - // DEBUG_PRINT_NUM("OnOpenItemChanged", GetCurrentThreadId()); - - CTmpProcessInfo &tpi = *(CTmpProcessInfo *)lParam; - if (tpi.FullPathFolderPrefix != _currentFolderPrefix) - return 0; - UInt32 fileIndex = tpi.FileIndex; - UInt32 numItems; - _folder->GetNumberOfItems(&numItems); - - // This code is not 100% OK for cases when there are several files with - // tpi.RelPath name and there are changes in archive before update. - // So tpi.FileIndex can point to another file. - - if (fileIndex >= numItems || GetItemRelPath(fileIndex) != tpi.RelPath) - { - UInt32 i; - for (i = 0; i < numItems; i++) - if (GetItemRelPath(i) == tpi.RelPath) - break; - if (i == numItems) - return 0; - fileIndex = i; - } - - CSelectedState state; - SaveSelectedState(state); - - CDisableNotify disableNotify(*this); // do we need it?? - - HRESULT result = OnOpenItemChanged(fileIndex, fs2us(tpi.FilePath), tpi.UsePassword, tpi.Password); - RefreshListCtrl(state); - if (result != S_OK) - return 0; - return 1; -} - - -CExitEventLauncher g_ExitEventLauncher; - -void CExitEventLauncher::Exit(bool hardExit) -{ - if (_needExit) - { - _exitEvent.Set(); - _needExit = false; - } - - if (_numActiveThreads == 0) - return; - - FOR_VECTOR (i, _threads) - { - ::CThread &th = _threads[i]; - DWORD wait = (hardExit ? 100 : INFINITE); - if (Thread_WasCreated(&th)) - { - DWORD waitResult = WaitForSingleObject(th, wait); - // Thread_Wait(&th); - if (waitResult == WAIT_TIMEOUT) - wait = 1; - if (!hardExit && waitResult != WAIT_OBJECT_0) - continue; - Thread_Close(&th); - _numActiveThreads--; - } - } -} - - - -static THREAD_FUNC_DECL MyThreadFunction(void *param) -{ - DEBUG_PRINT("==== MyThreadFunction ===="); - - CMyUniquePtr tpi((CTmpProcessInfo *)param); - CChildProcesses &processes = tpi->Processes; - - bool mainProcessWasSet = !processes.Handles.IsEmpty(); - - bool isComplexMode = true; - - if (!processes.Handles.IsEmpty()) - { - - const DWORD startTime = GetTickCount(); - - /* - CPossibleProgs progs; - { - const UString &name = tpi->RelPath; - int slashPos = name.ReverseFind_PathSepar(); - int dotPos = name.ReverseFind_Dot(); - if (dotPos > slashPos) - { - const UString ext = name.Ptr(dotPos + 1); - AString extA = UnicodeStringToMultiByte(ext); - extA.MakeLower_Ascii(); - progs.SetFromExtension(extA); - } - } - */ - - bool firstPass = true; - - for (;;) - { - CRecordVector handles; - CUIntVector indices; - - FOR_VECTOR (i, processes.Handles) - { - if (handles.Size() > 60) - break; - if (processes.NeedWait[i]) - { - handles.Add(processes.Handles[i]); - indices.Add(i); - } - } - - bool needFindProcessByPath = false; - - if (handles.IsEmpty()) - { - if (!firstPass) - break; - } - else - { - handles.Add(g_ExitEventLauncher._exitEvent); - - DWORD waitResult = WaitForMultiObj_Any_Infinite(handles.Size(), handles.ConstData()); - - waitResult -= WAIT_OBJECT_0; - - if (waitResult >= handles.Size() - 1) - { - processes.CloseAll(); - /* - if (waitResult == handles.Size() - 1) - { - // exit event - // we want to delete temp files, if progs were used - if (processes.ProgsWereUsed) - break; - } - */ - return waitResult >= (DWORD)handles.Size() ? 1 : 0; - } - - if (firstPass && indices.Size() == 1) - { - const DWORD curTime = GetTickCount() - startTime; - - /* - if (curTime > 5 * 1000) - progs.ProgNames.Clear(); - */ - - needFindProcessByPath = (curTime < 2 * 1000); - - if (needFindProcessByPath) - { - NFind::CFileInfo newFileInfo; - if (newFileInfo.Find(tpi->FilePath)) - if (tpi->WasChanged(newFileInfo)) - needFindProcessByPath = false; - } - - DEBUG_PRINT_NUM(" -- firstPass -- time = ", curTime) - } - - processes.DisableWait(indices[(unsigned)waitResult]); - } - - firstPass = false; - - // Sleep(300); - #ifndef UNDER_CE - processes.Update(needFindProcessByPath /* , progs */); - #endif - } - - - const DWORD curTime = GetTickCount() - startTime; - - DEBUG_PRINT_NUM("after time = ", curTime) - - processes.CloseAll(); - - isComplexMode = (curTime < 2 * 1000); - - } - - bool needCheckTimestamp = true; - - for (;;) - { - NFind::CFileInfo newFileInfo; - - if (!newFileInfo.Find(tpi->FilePath)) - break; - - if (mainProcessWasSet) - { - if (tpi->WasChanged(newFileInfo)) - { - UString m = MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(tpi->FilePath)); - if (tpi->ReadOnly) - { - m.Add_LF(); - AddLangString(m, IDS_PROP_READ_ONLY); - m.Add_LF(); - m += tpi->FullPathFolderPrefix; - ::MessageBoxW(g_HWND, m, L"7-Zip", MB_OK | MB_ICONSTOP); - return 0; - } - { - const UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, tpi->RelPath); - if (::MessageBoxW(g_HWND, message, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) == IDYES) - { - // DEBUG_PRINT_NUM("SendMessage", GetCurrentThreadId()); - if (SendMessage(tpi->Window, kOpenItemChanged, 0, (LONG_PTR)tpi.get()) != 1) - { - ::MessageBoxW(g_HWND, m, L"7-Zip", MB_OK | MB_ICONSTOP); - return 0; - } - } - needCheckTimestamp = false; - break; - } - } - - if (!isComplexMode) - break; - } - - // DEBUG_PRINT("WaitForSingleObject"); - DWORD waitResult = ::WaitForSingleObject(g_ExitEventLauncher._exitEvent, INFINITE); - // DEBUG_PRINT("---"); - - if (waitResult == WAIT_OBJECT_0) - break; - - return 1; - } - - { - NFind::CFileInfo newFileInfo; - - bool finded = newFileInfo.Find(tpi->FilePath); - - if (!needCheckTimestamp || !finded || !tpi->WasChanged(newFileInfo)) - { - DEBUG_PRINT("Delete Temp file"); - tpi->DeleteDirAndFile(); - } - } - - return 0; -} - - -/* -#if defined(_WIN32) && !defined(UNDER_CE) -static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); -#endif - - -#ifndef UNDER_CE - -static void ReadZoneFile(CFSTR fileName, CByteBuffer &buf) -{ - buf.Free(); - NIO::CInFile file; - if (!file.Open(fileName)) - return; - UInt64 fileSize; - if (!file.GetLength(fileSize)) - return; - if (fileSize == 0 || fileSize >= ((UInt32)1 << 20)) - return; - buf.Alloc((size_t)fileSize); - size_t processed; - if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize) - return; - buf.Free(); -} - -static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf) -{ - NIO::COutFile file; - if (!file.Create(fileName, true)) - return false; - UInt32 processed; - if (!file.Write(buf, (UInt32)buf.Size(), processed)) - return false; - return processed == buf.Size(); -} - -#endif -*/ - -/* -Z7_CLASS_IMP_COM_1( - CBufSeqOutStream_WithFile - , ISequentialOutStream -) - Byte *_buffer; - size_t _size; - size_t _pos; - - size_t _fileWritePos; - bool fileMode; -public: - - bool IsStreamInMem() const { return !fileMode; } - size_t GetMemStreamWrittenSize() const { return _pos; } - - // ISequentialOutStream *FileStream; - FString FilePath; - COutFileStream *outFileStreamSpec; - CMyComPtr outFileStream; - - CBufSeqOutStream_WithFile(): outFileStreamSpec(NULL) {} - - void Init(Byte *buffer, size_t size) - { - fileMode = false; - _buffer = buffer; - _pos = 0; - _size = size; - _fileWritePos = 0; - } - - HRESULT FlushToFile(); - size_t GetPos() const { return _pos; } -}; - -static const UInt32 kBlockSize = ((UInt32)1 << 31); - -STDMETHODIMP CBufSeqOutStream_WithFile::Write(const void *data, UInt32 size, UInt32 *processedSize) -{ - if (processedSize) - *processedSize = 0; - if (!fileMode) - { - if (_size - _pos >= size) - { - if (size != 0) - { - memcpy(_buffer + _pos, data, size); - _pos += size; - } - if (processedSize) - *processedSize = (UInt32)size; - return S_OK; - } - - fileMode = true; - } - RINOK(FlushToFile()); - return outFileStream->Write(data, size, processedSize); -} - -HRESULT CBufSeqOutStream_WithFile::FlushToFile() -{ - if (!outFileStream) - { - outFileStreamSpec = new COutFileStream; - outFileStream = outFileStreamSpec; - if (!outFileStreamSpec->Create(FilePath, false)) - { - outFileStream.Release(); - return E_FAIL; - // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath)); - } - } - while (_fileWritePos != _pos) - { - size_t cur = _pos - _fileWritePos; - UInt32 curSize = (cur < kBlockSize) ? (UInt32)cur : kBlockSize; - UInt32 processedSizeLoc = 0; - HRESULT res = outFileStream->Write(_buffer + _fileWritePos, curSize, &processedSizeLoc); - _fileWritePos += processedSizeLoc; - RINOK(res); - if (processedSizeLoc == 0) - return E_FAIL; - } - return S_OK; -} -*/ - -/* -static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) -{ - filetimeIsDefined = false; - NCOM::CPropVariant prop; - RINOK(folder->GetProperty(index, propID, &prop)); - if (prop.vt == VT_FILETIME) - { - filetime = prop.filetime; - filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} -*/ - - -/* -tryInternal tryExternal - false false : unused - false true : external - true false : internal - true true : smart based on file extension: - !alwaysStart(name) : both - alwaysStart(name) : external -*/ - -void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) -{ - // we don't want to change hash data here - if (IsHashFolder()) - return; - - const UString name = GetItemName(index); - const UString relPath = GetItemRelPath(index); - - if (tryExternal) - if (IsVirus_Message(name)) - return; - - if (!_folderOperations) - { - MessageBox_Error_UnsupportOperation(); - return; - } - - bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name)); - - const UString fullVirtPath = _currentFolderPrefix + relPath; - - CTempDir tempDirectory; - if (!tempDirectory.Create(kTempDirPrefix)) - { - MessageBox_LastError(); - return; - } - - FString tempDir = tempDirectory.GetPath(); - FString tempDirNorm = tempDir; - NName::NormalizeDirPathPrefix(tempDirNorm); - const FString tempFilePath = tempDirNorm + us2fs(Get_Correct_FsFile_Name(name)); - - CTempFileInfo tempFileInfo; - tempFileInfo.FileIndex = index; - tempFileInfo.RelPath = relPath; - tempFileInfo.FolderPath = tempDir; - tempFileInfo.FilePath = tempFilePath; - tempFileInfo.NeedDelete = true; - - if (tryAsArchive) - { - CMyComPtr getStream; - _folder.QueryInterface(IID_IInArchiveGetStream, &getStream); - if (getStream) - { - CMyComPtr subSeqStream; - getStream->GetStream(index, &subSeqStream); - if (subSeqStream) - { - CMyComPtr subStream; - subSeqStream.QueryInterface(IID_IInStream, &subStream); - if (subStream) - { - HRESULT res = OpenAsArc_Msg(subStream, tempFileInfo, fullVirtPath, type ? type : L"" - // , true // showErrorMessage - ); - if (res == S_OK) - { - tempDirectory.DisableDeleting(); - RefreshListCtrl(); - return; - } - if (res == E_ABORT || res != S_FALSE) - return; - if (!tryExternal) - return; - tryAsArchive = false; - } - } - } - } - - - CRecordVector indices; - indices.Add(index); - - UStringVector messages; - - bool usePassword = false; - UString password; - if (_parentFolders.Size() > 0) - { - const CFolderLink &fl = _parentFolders.Back(); - usePassword = fl.UsePassword; - password = fl.Password; - } - - /* - #if defined(_WIN32) && !defined(UNDER_CE) - CByteBuffer zoneBuf; - #ifndef _UNICODE - if (g_IsNT) - #endif - if (_parentFolders.Size() > 0) - { - const CFolderLink &fl = _parentFolders.Front(); - if (!fl.IsVirtual && !fl.FilePath.IsEmpty()) - ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf); - } - #endif - */ - - - CVirtFileSystem *virtFileSystemSpec = NULL; - CMyComPtr virtFileSystem; - - const bool isAltStream = IsItem_AltStream(index); - - CCopyToOptions options; - options.includeAltStreams = true; - options.replaceAltStreamChars = isAltStream; - { - // CContextMenuInfo ci; - // ci.Load(); - // if (ci.WriteZone != (UInt32)(Int32)-1) - // we use kAll when we unpack just one file. - options.ZoneIdMode = NExtract::NZoneIdMode::kAll; - options.NeedRegistryZone = false; - } - - if (tryAsArchive) - { - NCOM::CPropVariant prop; - _folder->GetProperty(index, kpidSize, &prop); - UInt64 fileLimit = 1 << 22; - if (g_RAM_Size_Defined) - fileLimit = g_RAM_Size / 4; - - UInt64 fileSize = 0; - if (!ConvertPropVariantToUInt64(prop, fileSize)) - fileSize = fileLimit; - if (fileSize <= fileLimit && fileSize > 0) - { - options.streamMode = true; - virtFileSystemSpec = new CVirtFileSystem; - virtFileSystem = virtFileSystemSpec; - -#if defined(_WIN32) && !defined(UNDER_CE) -#ifndef _UNICODE - if (g_IsNT) -#endif - if (_parentFolders.Size() > 0) - { - const CFolderLink &fl = _parentFolders.Front(); - if (!fl.IsVirtual && !fl.FilePath.IsEmpty()) - ReadZoneFile_Of_BaseFile(fl.FilePath, virtFileSystemSpec->ZoneBuf); - } -#endif - - // we allow additional total size for small alt streams; - virtFileSystemSpec->MaxTotalAllocSize = fileSize + (1 << 10); - - virtFileSystemSpec->DirPrefix = tempDirNorm; - virtFileSystemSpec->Init(); - options.VirtFileSystem = virtFileSystem; - options.VirtFileSystemSpec = virtFileSystemSpec; - } - } - - options.folder = fs2us(tempDirNorm); - options.showErrorMessages = true; - - const HRESULT result = CopyTo(options, indices, &messages, usePassword, password); - - if (_parentFolders.Size() > 0) - { - CFolderLink &fl = _parentFolders.Back(); - fl.UsePassword = usePassword; - fl.Password = password; - } - - if (!messages.IsEmpty()) - return; - if (result != S_OK) - { - if (result != E_ABORT) - MessageBox_Error_HRESULT(result); - return; - } - - if (options.VirtFileSystem) - { - if (virtFileSystemSpec->IsStreamInMem()) - { - const CVirtFile &file = virtFileSystemSpec->Files[0]; - - size_t streamSize = (size_t)file.Size; - CBufInStream *bufInStreamSpec = new CBufInStream; - CMyComPtr bufInStream = bufInStreamSpec; - bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem); - - HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"" - // , encrypted - // , true // showErrorMessage - ); - - if (res == S_OK) - { - tempDirectory.DisableDeleting(); - RefreshListCtrl(); - return; - } - - if (res == E_ABORT || res != S_FALSE) - return; - if (!tryExternal) - return; - - tryAsArchive = false; - if (virtFileSystemSpec->FlushToDisk(true) != S_OK) - return; - } - } - - - /* - #if defined(_WIN32) && !defined(UNDER_CE) - if (zoneBuf.Size() != 0) - { - if (NFind::DoesFileExist_Raw(tempFilePath)) - { - WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf); - } - } - #endif - */ - - - if (tryAsArchive) - { - HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L"" - // , encrypted - // , true // showErrorMessage - ); - if (res == S_OK) - { - tempDirectory.DisableDeleting(); - RefreshListCtrl(); - return; - } - if (res == E_ABORT || res != S_FALSE) - return; - } - - if (!tryExternal) - return; - - CMyUniquePtr tpi(new CTmpProcessInfo()); - tpi->FolderPath = tempDir; - tpi->FilePath = tempFilePath; - tpi->NeedDelete = true; - tpi->UsePassword = usePassword; - tpi->Password = password; - tpi->ReadOnly = IsThereReadOnlyFolder(); - if (IsHashFolder()) - tpi->ReadOnly = true; - - if (!tpi->FileInfo.Find(tempFilePath)) - return; - - CTmpProcessInfoRelease tmpProcessInfoRelease(*tpi); - - CProcess process; - HRESULT res; - if (editMode) - res = StartEditApplication(fs2us(tempFilePath), useEditor, (HWND)*this, process); - else - res = StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath), (HWND)*this, process); - - if ((HANDLE)process == NULL) - { - // win7 / win10 work so for some extensions (pdf, html ..); - DEBUG_PRINT("#### (HANDLE)process == 0"); - // return; - if (res != S_OK) - return; - } - - tpi->Window = (HWND)(*this); - tpi->FullPathFolderPrefix = _currentFolderPrefix; - tpi->FileIndex = index; - tpi->RelPath = relPath; - - if ((HANDLE)process) - tpi->Processes.SetMainProcess(process.Detach()); - - ::CThread th; - if (Thread_Create(&th, MyThreadFunction, tpi.get()) != 0) - throw 271824; - g_ExitEventLauncher._threads.Add(th); - g_ExitEventLauncher._numActiveThreads++; - - tempDirectory.DisableDeleting(); - tpi.release(); - tmpProcessInfoRelease._needDelete = false; -} - - -/* -static const UINT64 kTimeLimit = UINT64(10000000) * 3600 * 24; - -static bool CheckDeleteItem(UINT64 currentFileTime, UINT64 folderFileTime) -{ - return (currentFileTime - folderFileTime > kTimeLimit && - folderFileTime - currentFileTime > kTimeLimit); -} - -void DeleteOldTempFiles() -{ - UString tempPath; - if (!MyGetTempPath(tempPath)) - throw 1; - - UINT64 currentFileTime; - NTime::GetCurUtcFileTime(currentFileTime); - UString searchWildCard = tempPath + kTempDirPrefix + L"*.tmp"; - searchWildCard += WCHAR(NName::kAnyStringWildcard); - NFind::CEnumeratorW enumerator(searchWildCard); - NFind::CFileInfo fileInfo; - while (enumerator.Next(fileInfo)) - { - if (!fileInfo.IsDir()) - continue; - const UINT64 &cTime = *(const UINT64 *)(&fileInfo.CTime); - if (CheckDeleteItem(cTime, currentFileTime)) - RemoveDirectoryWithSubItems(tempPath + fileInfo.Name); - } -} -*/ +// PanelItemOpen.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#include + +#include "../../../Common/IntToString.h" + +#include "../../../Common/AutoPtr.h" + +#include "../../../Windows/ProcessUtils.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamObjects.h" + +#include "../Common/ExtractingFilePath.h" + +#include "App.h" + +#include "FileFolderPluginOpen.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "PropertyNameRes.h" +#include "RegistryUtils.h" +#include "UpdateCallback100.h" + +#include "../GUI/ExtractRes.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NSynchronization; +using namespace NFile; +using namespace NDir; + +extern bool g_RAM_Size_Defined; +extern size_t g_RAM_Size; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +#define kTempDirPrefix FTEXT("7zO") + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO + #define DEBUG_PRINT(s) OutputDebugStringA(s); + #define DEBUG_PRINT_W(s) OutputDebugStringW(s); + #define DEBUG_PRINT_NUM(s, num) { char ttt[32]; ConvertUInt32ToString(num, ttt); OutputDebugStringA(s); OutputDebugStringA(ttt); } +#else + #define DEBUG_PRINT(s) + #define DEBUG_PRINT_W(s) + #define DEBUG_PRINT_NUM(s, num) +#endif + + + +#ifndef UNDER_CE + +class CProcessSnapshot +{ + HANDLE _handle; +public: + CProcessSnapshot(): _handle(INVALID_HANDLE_VALUE) {} + ~CProcessSnapshot() { Close(); } + + bool Close() + { + if (_handle == INVALID_HANDLE_VALUE) + return true; + if (!::CloseHandle(_handle)) + return false; + _handle = INVALID_HANDLE_VALUE; + return true; + } + + bool Create() + { + _handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + return (_handle != INVALID_HANDLE_VALUE); + } + + bool GetFirstProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32First(_handle, pe)); } + bool GetNextProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32Next(_handle, pe)); } +}; + +#endif + + +/* +struct COpenExtProg +{ + const char *Ext; + const char *Prog; +}; + +static const COpenExtProg g_Progs[] = +{ + { "jpeg jpg png bmp gif", "Microsoft.Photos.exe" }, + { "html htm pdf", "MicrosoftEdge.exe" }, + // , { "rrr", "notepad.exe" } +}; + +static bool FindExtProg(const char *exts, const char *ext) +{ + unsigned len = (unsigned)strlen(ext); + for (;;) + { + const char *p = exts; + for (;; p++) + { + const char c = *p; + if (c == 0 || c == ' ') + break; + } + if (len == (unsigned)(p - exts) && IsString1PrefixedByString2(exts, ext)) + return true; + if (*p == 0) + return false; + exts = p + 1; + } +} + +class CPossibleProgs +{ +public: + AStringVector ProgNames; + + void SetFromExtension(const char *ext) // ext must be low case + { + ProgNames.Clear(); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Progs); i++) + if (FindExtProg(g_Progs[i].Ext, ext)) + { + ProgNames.Add(g_Progs[i].Prog); + } + } + + bool IsFromList(const UString &progName) const + { + FOR_VECTOR (i, ProgNames) + if (progName.IsEqualTo_Ascii_NoCase(ProgNames[i])) + return true; + return false; + } +}; +*/ + + +#ifndef UNDER_CE + +EXTERN_C_BEGIN + +/* +GetProcessImageFileName + returns the path in device form, rather than drive letters: + \Device\HarddiskVolume1\WINDOWS\SysWOW64\notepad.exe + +GetModuleFileNameEx works only after Sleep(something). Why? + returns the path + C:\WINDOWS\system32\NOTEPAD.EXE +*/ + +/* Kernel32.dll: Win7, Win2008R2; + Psapi.dll: (if PSAPI_VERSION=1) on Win7 and Win2008R2; + Psapi.dll: XP, Win2003, Vista, 2008; +*/ + +typedef DWORD (WINAPI *Func_GetProcessImageFileNameW)( + HANDLE hProcess, LPWSTR lpFilename, DWORD nSize); + +typedef DWORD (WINAPI *Func_GetModuleFileNameExW)( + HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize); + +typedef DWORD (WINAPI *Func_GetProcessId)(HANDLE process); + +EXTERN_C_END + + +static HMODULE g_Psapi_dll_module; + +/* +static void My_GetProcessFileName_2(HANDLE hProcess, UString &path) +{ + path.Empty(); + const unsigned maxPath = 1024; + WCHAR temp[maxPath + 1]; + + const char *func_name = "GetModuleFileNameExW"; + Func_GetModuleFileNameExW my_func = (Func_GetModuleFileNameExW) + ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), func_name); + if (!my_func) + { + if (!g_Psapi_dll_module) + g_Psapi_dll_module = LoadLibraryW(L"Psapi.dll"); + if (g_Psapi_dll_module) + my_func = (Func_GetModuleFileNameExW)::GetProcAddress(g_Psapi_dll_module, func_name); + } + if (my_func) + { + // DWORD num = GetModuleFileNameEx(hProcess, NULL, temp, maxPath); + DWORD num = my_func(hProcess, NULL, temp, maxPath); + if (num != 0) + path = temp; + } + // FreeLibrary(lib); +} +*/ + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +static void My_GetProcessFileName(HANDLE hProcess, UString &path) +{ + path.Empty(); + const unsigned maxPath = 1024; + WCHAR temp[maxPath + 1]; + + const char *func_name = + "GetProcessImageFileNameW"; + Func_GetProcessImageFileNameW my_func = Z7_GET_PROC_ADDRESS( + Func_GetProcessImageFileNameW, ::GetModuleHandleA("kernel32.dll"), func_name); + + if (!my_func) + { + if (!g_Psapi_dll_module) + g_Psapi_dll_module = LoadLibraryW(L"Psapi.dll"); + if (g_Psapi_dll_module) + my_func = Z7_GET_PROC_ADDRESS( + Func_GetProcessImageFileNameW, g_Psapi_dll_module, func_name); + } + + if (my_func) + { + const DWORD num = + // GetProcessImageFileNameW(hProcess, temp, maxPath); + my_func(hProcess, temp, maxPath); + if (num != 0) + path = temp; + } + // FreeLibrary(lib); +} + +struct CSnapshotProcess +{ + DWORD Id; + DWORD ParentId; + UString Name; +}; + +static void GetSnapshot(CObjectVector &items) +{ + items.Clear(); + + CProcessSnapshot snapshot; + if (!snapshot.Create()) + return; + + DEBUG_PRINT("snapshot.Create() OK"); + PROCESSENTRY32 pe; + CSnapshotProcess item; + memset(&pe, 0, sizeof(pe)); + pe.dwSize = sizeof(pe); + BOOL res = snapshot.GetFirstProcess(&pe); + while (res) + { + item.Id = pe.th32ProcessID; + item.ParentId = pe.th32ParentProcessID; + item.Name = GetUnicodeString(pe.szExeFile); + items.Add(item); + res = snapshot.GetNextProcess(&pe); + } +} + +#endif + + +class CChildProcesses +{ + #ifndef UNDER_CE + CRecordVector _ids; + #endif + +public: + // bool ProgsWereUsed; + CRecordVector Handles; + CRecordVector NeedWait; + // UStringVector Names; + + #ifndef UNDER_CE + UString Path; + #endif + + // CChildProcesses(): ProgsWereUsed(false) {} + ~CChildProcesses() { CloseAll(); } + void DisableWait(unsigned index) { NeedWait[index] = false; } + + void CloseAll() + { + FOR_VECTOR (i, Handles) + { + HANDLE h = Handles[i]; + if (h != NULL) + CloseHandle(h); + } + + Handles.Clear(); + NeedWait.Clear(); + // Names.Clear(); + + #ifndef UNDER_CE + // Path.Empty(); + _ids.Clear(); + #endif + } + + void SetMainProcess(HANDLE h) + { + #ifndef UNDER_CE + const + Func_GetProcessId func = Z7_GET_PROC_ADDRESS( + Func_GetProcessId, ::GetModuleHandleA("kernel32.dll"), + "GetProcessId"); + if (func) + { + const DWORD id = func(h); + if (id != 0) + _ids.AddToUniqueSorted(id); + } + + My_GetProcessFileName(h, Path); + DEBUG_PRINT_W(Path); + + #endif + + Handles.Add(h); + NeedWait.Add(true); + } + + #ifndef UNDER_CE + + void Update(bool needFindProcessByPath /* , const CPossibleProgs &progs */) + { + /* + if (_ids.IsEmpty()) + return; + */ + + CObjectVector sps; + GetSnapshot(sps); + + const int separ = Path.ReverseFind_PathSepar(); + const UString mainName = Path.Ptr((unsigned)(separ + 1)); + if (mainName.IsEmpty()) + needFindProcessByPath = false; + + const DWORD currentProcessId = GetCurrentProcessId(); + + for (;;) + { + bool wasAdded = false; + + FOR_VECTOR (i, sps) + { + const CSnapshotProcess &sp = sps[i]; + const DWORD id = sp.Id; + + if (id == currentProcessId) + continue; + if (_ids.FindInSorted(id) >= 0) + continue; + + bool isSameName = false; + const UString &name = sp.Name; + + if (needFindProcessByPath) + isSameName = mainName.IsEqualTo_NoCase(name); + + bool needAdd = false; + // bool isFromProgs = false; + + if (isSameName || _ids.FindInSorted(sp.ParentId) >= 0) + needAdd = true; + /* + else if (progs.IsFromList(name)) + { + needAdd = true; + isFromProgs = true; + } + */ + + if (needAdd) + { + DEBUG_PRINT("----- OpenProcess -----"); + DEBUG_PRINT_W(name); + HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, id); + if (hProcess) + { + DEBUG_PRINT("----- OpenProcess OK -----"); + // if (!isFromProgs) + _ids.AddToUniqueSorted(id); + Handles.Add(hProcess); + NeedWait.Add(true); + // Names.Add(name); + wasAdded = true; + // ProgsWereUsed = isFromProgs; + } + } + } + + if (!wasAdded) + break; + } + } + + #endif +}; + + +struct CTmpProcessInfo: public CTempFileInfo +{ + CChildProcesses Processes; + HWND Window; + UString FullPathFolderPrefix; + bool UsePassword; + UString Password; + + bool ReadOnly; + + CTmpProcessInfo(): UsePassword(false), ReadOnly(false) {} +}; + + +class CTmpProcessInfoRelease +{ + CTmpProcessInfo *_tmpProcessInfo; +public: + bool _needDelete; + CTmpProcessInfoRelease(CTmpProcessInfo &tpi): + _tmpProcessInfo(&tpi), _needDelete(true) {} + ~CTmpProcessInfoRelease() + { + if (_needDelete) + _tmpProcessInfo->DeleteDirAndFile(); + } +}; + +void GetFolderError(CMyComPtr &folder, UString &s); + + +HRESULT CPanel::OpenAsArc(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat, + COpenResult &openRes) +{ + openRes.Encrypted = false; + CFolderLink folderLink; + (CTempFileInfo &)folderLink = tempFileInfo; + + if (inStream) + folderLink.IsVirtual = true; + else + { + if (!folderLink.FileInfo.Find(folderLink.FilePath)) + return GetLastError_noZero_HRESULT(); + if (folderLink.FileInfo.IsDir()) + return S_FALSE; + folderLink.IsVirtual = false; + } + + folderLink.VirtualPath = virtualFilePath; + + CFfpOpen ffp; + const HRESULT res = ffp.OpenFileFolderPlugin(inStream, + folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath, + arcFormat, GetParent()); + + openRes.Encrypted = ffp.Encrypted; + openRes.ErrorMessage = ffp.ErrorMessage; + + RINOK(res) + + folderLink.Password = ffp.Password; + folderLink.UsePassword = ffp.Encrypted; + + if (_folder) + folderLink.ParentFolderPath = GetFolderPath(_folder); + else + folderLink.ParentFolderPath = _currentFolderPrefix; + + if (!_parentFolders.IsEmpty()) + folderLink.ParentFolder = _folder; + + _parentFolders.Add(folderLink); + _parentFolders.Back().Library.Attach(_library.Detach()); + + ReleaseFolder(); + _library.Free(); + SetNewFolder(ffp.Folder); + _library.Attach(ffp.Library.Detach()); + + _flatMode = _flatModeForArc; + + _thereAreDeletedItems = false; + + if (!openRes.ErrorMessage.IsEmpty()) + MessageBox_Error(openRes.ErrorMessage); + /* + UString s; + GetFolderError(_folder, s); + if (!s.IsEmpty()) + MessageBox_Error(s); + */ + // we don't show error here by some reasons: + // after MessageBox_Warning it throws exception in nested archives in Debug Mode. why ?. + // MessageBox_Warning(L"test error"); + + return S_OK; +} + + +HRESULT CPanel::OpenAsArc_Msg(IInStream *inStream, + const CTempFileInfo &tempFileInfo, + const UString &virtualFilePath, + const UString &arcFormat + // , bool &encrypted + // , bool showErrorMessage + ) +{ + COpenResult opRes; + + HRESULT res = OpenAsArc(inStream, tempFileInfo, virtualFilePath, arcFormat, opRes); + + if (res == S_OK) + return res; + if (res == E_ABORT) + return res; + + // if (showErrorMessage) + if (opRes.Encrypted || res != S_FALSE) // 17.01 : we show message also for (res != S_FALSE) + { + UString message; + if (res == S_FALSE) + { + message = MyFormatNew( + opRes.Encrypted ? + IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : + IDS_CANT_OPEN_ARCHIVE, + virtualFilePath); + } + else + message = HResultToMessage(res); + MessageBox_Error(message); + } + + return res; +} + + +HRESULT CPanel::OpenAsArc_Name(const UString &relPath, const UString &arcFormat + // , bool &encrypted, + // , bool showErrorMessage + ) +{ + CTempFileInfo tfi; + tfi.RelPath = relPath; + tfi.FolderPath = us2fs(GetFsPath()); + const UString fullPath = GetFsPath() + relPath; + tfi.FilePath = us2fs(fullPath); + return OpenAsArc_Msg(NULL, tfi, fullPath, arcFormat /* , encrypted, showErrorMessage */); +} + + +HRESULT CPanel::OpenAsArc_Index(unsigned index, const wchar_t *type + // , bool showErrorMessage + ) +{ + CDisableTimerProcessing disableTimerProcessing1(*this); + CDisableNotify disableNotify(*this); + + HRESULT res = OpenAsArc_Name(GetItemRelPath2(index), type ? type : L"" /* , encrypted, showErrorMessage */); + if (res != S_OK) + { + RefreshTitle(true); // in case of error we must refresh changed title of 7zFM + return res; + } + RefreshListCtrl(); + return S_OK; +} + + +HRESULT CPanel::OpenParentArchiveFolder() +{ + CDisableTimerProcessing disableTimerProcessing(*this); + CDisableNotify disableNotify(*this); + if (_parentFolders.Size() < 2) + return S_OK; + const CFolderLink &folderLinkPrev = _parentFolders[_parentFolders.Size() - 2]; + const CFolderLink &folderLink = _parentFolders.Back(); + NFind::CFileInfo newFileInfo; + if (newFileInfo.Find(folderLink.FilePath)) + { + if (folderLink.WasChanged_from_FolderLink(newFileInfo)) + { + const UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath); + if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) == IDYES) + { + if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath), + folderLinkPrev.UsePassword, folderLinkPrev.Password) != S_OK) + { + ::MessageBoxW((HWND)*this, MyFormatNew(IDS_CANNOT_UPDATE_FILE, + fs2us(folderLink.FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP); + return S_OK; + } + } + } + } + folderLink.DeleteDirAndFile(); + return S_OK; +} + + +static const char * const kExeExtensions = + " exe bat ps1 com lnk" + " "; + +static const char * const kStartExtensions = + #ifdef UNDER_CE + " cab" + #endif + " exe bat ps1 com lnk" + " chm" + " msi doc dot xls ppt pps wps wpt wks xlr wdb vsd pub" + + " docx docm dotx dotm xlsx xlsm xltx xltm xlsb xps" + " xlam pptx pptm potx potm ppam ppsx ppsm vsdx xsn" + " mpp" + " msg" + " dwf" + + " flv swf" + + " epub" + " odt ods" + " wb3" + " pdf" + " ps" + " txt" + " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" + " h hpp hxx c cpp cxx m mm go swift" + " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs" + " asm" + " mak clw csproj vcproj sln dsp dsw" + " "; + +// bool FindExt(const char *p, const UString &name, AString &s); +bool FindExt(const char *p, const UString &name, CStringFinder &finder); + +static bool DoItemAlwaysStart(const UString &name) +{ + CStringFinder finder; + return FindExt(kStartExtensions, name, finder); +} + +UString GetQuotedString(const UString &s); + + +void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms); +void SplitCmdLineSmart(const UString &cmd, UString &prg, UString ¶ms) +{ + params.Empty(); + prg = cmd; + prg.Trim(); + if (prg.Len() >= 2 && prg[0] == L'"') + { + int pos = prg.Find(L'"', 1); + if (pos >= 0) + { + if ((unsigned)(pos + 1) == prg.Len() || prg[pos + 1] == ' ') + { + params = prg.Ptr((unsigned)(pos + 1)); + params.Trim(); + prg.DeleteFrom((unsigned)pos); + prg.DeleteFrontal(1); + } + } + } +} + + +static WRes StartAppWithParams(const UString &cmd, const UStringVector ¶mVector, CProcess &process) +{ + UString param; + UString prg; + + SplitCmdLineSmart(cmd, prg, param); + + param.Trim(); + + // int pos = params.Find(L"%1"); + + FOR_VECTOR (i, paramVector) + { + if (!param.IsEmpty() && param.Back() != ' ') + param.Add_Space(); + param += GetQuotedString(paramVector[i]); + } + + return process.Create(prg, param, NULL); +} + + +static HRESULT StartEditApplication(const UString &path, bool useEditor, HWND window, CProcess &process) +{ + UString command; + ReadRegEditor(useEditor, command); + if (command.IsEmpty()) + { + #ifdef UNDER_CE + command = "\\Windows\\"; + #else + FString winDir; + if (!GetWindowsDir(winDir)) + return 0; + NName::NormalizeDirPathPrefix(winDir); + command = fs2us(winDir); + #endif + command += "notepad.exe"; + } + + UStringVector params; + params.Add(path); + + const WRes res = StartAppWithParams(command, params, process); + if (res != 0) + ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); + return HRESULT_FROM_WIN32(res); +} + + +void CApp::DiffFiles() +{ + const CPanel &panel = GetFocusedPanel(); + + if (!panel.Is_IO_FS_Folder()) + { + panel.MessageBox_Error_UnsupportOperation(); + return; + } + + CRecordVector indices; + panel.Get_ItemIndices_Selected(indices); + + UString path1, path2; + if (indices.Size() == 2) + { + path1 = panel.GetItemFullPath(indices[0]); + path2 = panel.GetItemFullPath(indices[1]); + } + else if (indices.Size() == 1 && NumPanels >= 2) + { + const CPanel &destPanel = Panels[1 - LastFocusedPanel]; + + if (!destPanel.Is_IO_FS_Folder()) + { + panel.MessageBox_Error_UnsupportOperation(); + return; + } + + path1 = panel.GetItemFullPath(indices[0]); + CRecordVector indices2; + destPanel.Get_ItemIndices_Selected(indices2); + if (indices2.Size() == 1) + path2 = destPanel.GetItemFullPath(indices2[0]); + else + { + UString relPath = panel.GetItemRelPath2(indices[0]); + if (panel._flatMode && !destPanel._flatMode) + relPath = panel.GetItemName(indices[0]); + path2 = destPanel._currentFolderPrefix + relPath; + } + } + else + return; + + DiffFiles(path1, path2); +} + +void CApp::DiffFiles(const UString &path1, const UString &path2) +{ + UString command; + ReadRegDiff(command); + if (command.IsEmpty()) + return; + + UStringVector params; + params.Add(path1); + params.Add(path2); + + WRes res; + { + CProcess process; + res = StartAppWithParams(command, params, process); + } + if (res == 0) + return; + ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP); +} + + +HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process); +void StartApplicationDontWait(const UString &dir, const UString &path, HWND window); + +void CPanel::EditItem(unsigned index, bool useEditor) +{ + if (!_parentFolders.IsEmpty()) + { + OpenItemInArchive(index, false, true, true, useEditor); + return; + } + CProcess process; + StartEditApplication(GetItemFullPath(index), useEditor, (HWND)*this, process); +} + + +void CPanel::OpenFolderExternal(unsigned index) +{ + UString prefix = GetFsPath(); + UString path = prefix; + + if (index == kParentIndex) + { + if (prefix.IsEmpty()) + return; + const wchar_t c = prefix.Back(); + if (!IS_PATH_SEPAR(c) && c != ':') + return; + prefix.DeleteBack(); + int pos = prefix.ReverseFind_PathSepar(); + if (pos < 0) + return; + prefix.DeleteFrom((unsigned)(pos + 1)); + path = prefix; + } + else + { + path += GetItemRelPath(index); + path.Add_PathSepar(); + } + + StartApplicationDontWait(prefix, path, (HWND)*this); +} + + +bool CPanel::IsVirus_Message(const UString &name) +{ + UString name2; + + const wchar_t cRLO = (wchar_t)0x202E; + bool isVirus = false; + bool isSpaceError = false; + name2 = name; + + if (name2.Find(cRLO) >= 0) + { + const UString badString(cRLO); + name2.Replace(badString, L"[RLO]"); + isVirus = true; + } + { + const wchar_t * const kVirusSpaces = L" "; + // const unsigned kNumSpaces = strlen(kVirusSpaces); + for (;;) + { + int pos = name2.Find(kVirusSpaces); + if (pos < 0) + break; + isVirus = true; + isSpaceError = true; + name2.Replace(kVirusSpaces, L" "); + } + } + + #ifdef _WIN32 + { + unsigned i; + for (i = name2.Len(); i != 0;) + { + wchar_t c = name2[i - 1]; + if (c != '.' && c != ' ') + break; + i--; + name2.ReplaceOneCharAtPos(i, '_'); + } + if (i != name2.Len()) + { + CStringFinder finder; + UString name3 = name2; + name3.DeleteFrom(i); + if (FindExt(kExeExtensions, name3, finder)) + isVirus = true; + } + } + #endif + + if (!isVirus) + return false; + + UString s = LangString(IDS_VIRUS); + + if (!isSpaceError) + { + const int pos1 = s.Find(L'('); + if (pos1 >= 0) + { + const int pos2 = s.Find(L')', (unsigned)pos1 + 1); + if (pos2 >= 0) + { + s.Delete((unsigned)pos1, (unsigned)pos2 + 1 - (unsigned)pos1); + if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.') + s.Delete(pos1 - 1); + } + } + } + + UString name3 = name; + name3.Replace(L'\n', L'_'); + name2.Replace(L'\n', L'_'); + + s.Add_LF(); s += name2; + s.Add_LF(); s += name3; + + MessageBox_Error(s); + return true; +} + + +void CPanel::OpenItem(unsigned index, bool tryInternal, bool tryExternal, const wchar_t *type) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + const UString name = GetItemRelPath2(index); + + if (tryExternal) + if (IsVirus_Message(name)) + return; + + if (!_parentFolders.IsEmpty()) + { + OpenItemInArchive(index, tryInternal, tryExternal, false, false, type); + return; + } + + CDisableNotify disableNotify(*this); + UString prefix = GetFsPath(); + UString fullPath = prefix + name; + + if (tryInternal) + if (!tryExternal || !DoItemAlwaysStart(name)) + { + HRESULT res = OpenAsArc_Index(index, type + // , true + ); + disableNotify.Restore(); // we must restore to allow text notification update + InvalidateList(); + if (res == S_OK || res == E_ABORT) + return; + if (res != S_FALSE) + { + MessageBox_Error_HRESULT(res); + return; + } + } + + if (tryExternal) + { + // SetCurrentDirectory opens HANDLE to folder!!! + // NDirectory::MySetCurrentDirectory(prefix); + StartApplicationDontWait(prefix, fullPath, (HWND)*this); + } +} + +class CThreadCopyFrom: public CProgressThreadVirt +{ + HRESULT ProcessVirt() Z7_override; +public: + UString FullPath; + UInt32 ItemIndex; + + CMyComPtr FolderOperations; + CMyComPtr UpdateCallback; + CUpdateCallback100Imp *UpdateCallbackSpec; +}; + +HRESULT CThreadCopyFrom::ProcessVirt() +{ + return FolderOperations->CopyFromFile(ItemIndex, FullPath, UpdateCallback); +} + +HRESULT CPanel::OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, + bool usePassword, const UString &password) +{ + if (!_folderOperations) + { + MessageBox_Error_UnsupportOperation(); + return E_FAIL; + } + + CThreadCopyFrom t; + t.UpdateCallbackSpec = new CUpdateCallback100Imp; + t.UpdateCallback = t.UpdateCallbackSpec; + t.UpdateCallbackSpec->ProgressDialog = &t; + t.ItemIndex = index; + t.FullPath = fullFilePath; + t.FolderOperations = _folderOperations; + + t.UpdateCallbackSpec->Init(); + t.UpdateCallbackSpec->PasswordIsDefined = usePassword; + t.UpdateCallbackSpec->Password = password; + + + RINOK(t.Create(GetItemName(index), (HWND)*this)) + return t.Result; +} + +LRESULT CPanel::OnOpenItemChanged(LPARAM lParam) +{ + // DEBUG_PRINT_NUM("OnOpenItemChanged", GetCurrentThreadId()); + + CTmpProcessInfo &tpi = *(CTmpProcessInfo *)lParam; + if (tpi.FullPathFolderPrefix != _currentFolderPrefix) + return 0; + UInt32 fileIndex = tpi.FileIndex; + UInt32 numItems; + _folder->GetNumberOfItems(&numItems); + + // This code is not 100% OK for cases when there are several files with + // tpi.RelPath name and there are changes in archive before update. + // So tpi.FileIndex can point to another file. + + if (fileIndex >= numItems || GetItemRelPath(fileIndex) != tpi.RelPath) + { + UInt32 i; + for (i = 0; i < numItems; i++) + if (GetItemRelPath(i) == tpi.RelPath) + break; + if (i == numItems) + return 0; + fileIndex = i; + } + + CSelectedState state; + SaveSelectedState(state); + + CDisableNotify disableNotify(*this); // do we need it?? + + HRESULT result = OnOpenItemChanged(fileIndex, fs2us(tpi.FilePath), tpi.UsePassword, tpi.Password); + RefreshListCtrl(state); + if (result != S_OK) + return 0; + return 1; +} + + +CExitEventLauncher g_ExitEventLauncher; + +void CExitEventLauncher::Exit(bool hardExit) +{ + if (_needExit) + { + _exitEvent.Set(); + _needExit = false; + } + + if (_numActiveThreads == 0) + return; + + FOR_VECTOR (i, _threads) + { + ::CThread &th = _threads[i]; + if (Thread_WasCreated(&th)) + { + const DWORD waitResult = WaitForSingleObject(th, hardExit ? 100 : INFINITE); + // Thread_Wait(&th); + // if (waitResult == WAIT_TIMEOUT) wait = 1; + if (!hardExit && waitResult != WAIT_OBJECT_0) + continue; + Thread_Close(&th); + _numActiveThreads--; + } + } +} + + + +static THREAD_FUNC_DECL MyThreadFunction(void *param) +{ + DEBUG_PRINT("==== MyThreadFunction ===="); + + CMyUniquePtr tpi((CTmpProcessInfo *)param); + CChildProcesses &processes = tpi->Processes; + + const bool mainProcessWasSet = !processes.Handles.IsEmpty(); + + bool isComplexMode = true; + + if (!processes.Handles.IsEmpty()) + { + + const DWORD startTime = GetTickCount(); + + /* + CPossibleProgs progs; + { + const UString &name = tpi->RelPath; + int slashPos = name.ReverseFind_PathSepar(); + int dotPos = name.ReverseFind_Dot(); + if (dotPos > slashPos) + { + const UString ext = name.Ptr(dotPos + 1); + AString extA = UnicodeStringToMultiByte(ext); + extA.MakeLower_Ascii(); + progs.SetFromExtension(extA); + } + } + */ + + bool firstPass = true; + + for (;;) + { + CRecordVector handles; + CUIntVector indices; + + FOR_VECTOR (i, processes.Handles) + { + if (handles.Size() > 60) + break; + if (processes.NeedWait[i]) + { + handles.Add(processes.Handles[i]); + indices.Add(i); + } + } + + bool needFindProcessByPath = false; + + if (handles.IsEmpty()) + { + if (!firstPass) + break; + } + else + { + handles.Add(g_ExitEventLauncher._exitEvent); + + DWORD waitResult = WaitForMultiObj_Any_Infinite(handles.Size(), handles.ConstData()); + + waitResult -= WAIT_OBJECT_0; + + if (waitResult >= handles.Size() - 1) + { + processes.CloseAll(); + /* + if (waitResult == handles.Size() - 1) + { + // exit event + // we want to delete temp files, if progs were used + if (processes.ProgsWereUsed) + break; + } + */ + return waitResult >= (DWORD)handles.Size() ? 1 : 0; + } + + if (firstPass && indices.Size() == 1) + { + const DWORD curTime = GetTickCount() - startTime; + + /* + if (curTime > 5 * 1000) + progs.ProgNames.Clear(); + */ + + needFindProcessByPath = (curTime < 2 * 1000); + + if (needFindProcessByPath) + { + NFind::CFileInfo newFileInfo; + if (newFileInfo.Find(tpi->FilePath)) + if (tpi->WasChanged_from_TempFileInfo(newFileInfo)) + needFindProcessByPath = false; + } + + DEBUG_PRINT_NUM(" -- firstPass -- time = ", curTime) + } + + processes.DisableWait(indices[(unsigned)waitResult]); + } + + firstPass = false; + + // Sleep(300); + #ifndef UNDER_CE + processes.Update(needFindProcessByPath /* , progs */); + #endif + } + + + const DWORD curTime = GetTickCount() - startTime; + + DEBUG_PRINT_NUM("after time = ", curTime) + + processes.CloseAll(); + + isComplexMode = (curTime < 2 * 1000); + + } + + bool needCheckTimestamp = true; + + for (;;) + { + NFind::CFileInfo newFileInfo; + + if (!newFileInfo.Find(tpi->FilePath)) + break; + + if (mainProcessWasSet) + { + if (tpi->WasChanged_from_TempFileInfo(newFileInfo)) + { + UString m = MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(tpi->FilePath)); + if (tpi->ReadOnly) + { + m.Add_LF(); + AddLangString(m, IDS_PROP_READ_ONLY); + m.Add_LF(); + m += tpi->FullPathFolderPrefix; + ::MessageBoxW(g_HWND, m, L"7-Zip", MB_OK | MB_ICONSTOP); + return 0; + } + { + const UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, tpi->RelPath); + if (::MessageBoxW(g_HWND, message, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) == IDYES) + { + // DEBUG_PRINT_NUM("SendMessage", GetCurrentThreadId()); + if (SendMessage(tpi->Window, kOpenItemChanged, 0, (LONG_PTR)tpi.get()) != 1) + { + ::MessageBoxW(g_HWND, m, L"7-Zip", MB_OK | MB_ICONSTOP); + return 0; + } + } + needCheckTimestamp = false; + break; + } + } + + if (!isComplexMode) + break; + } + + // DEBUG_PRINT("WaitForSingleObject"); + DWORD waitResult = ::WaitForSingleObject(g_ExitEventLauncher._exitEvent, INFINITE); + // DEBUG_PRINT("---"); + + if (waitResult == WAIT_OBJECT_0) + break; + + return 1; + } + + { + NFind::CFileInfo newFileInfo; + const bool finded = newFileInfo.Find(tpi->FilePath); + if (!needCheckTimestamp + || !finded + || !tpi->WasChanged_from_TempFileInfo(newFileInfo)) + { + DEBUG_PRINT("Delete Temp file"); + tpi->DeleteDirAndFile(); + } + } + + return 0; +} + + +/* +#if defined(_WIN32) && !defined(UNDER_CE) +static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); +#endif + + +#ifndef UNDER_CE + +static void ReadZoneFile(CFSTR fileName, CByteBuffer &buf) +{ + buf.Free(); + NIO::CInFile file; + if (!file.Open(fileName)) + return; + UInt64 fileSize; + if (!file.GetLength(fileSize)) + return; + if (fileSize == 0 || fileSize >= ((UInt32)1 << 20)) + return; + buf.Alloc((size_t)fileSize); + size_t processed; + if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize) + return; + buf.Free(); +} + +static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf) +{ + NIO::COutFile file; + if (!file.Create(fileName, true)) + return false; + UInt32 processed; + if (!file.Write(buf, (UInt32)buf.Size(), processed)) + return false; + return processed == buf.Size(); +} + +#endif +*/ + +/* +Z7_CLASS_IMP_COM_1( + CBufSeqOutStream_WithFile + , ISequentialOutStream +) + Byte *_buffer; + size_t _size; + size_t _pos; + + size_t _fileWritePos; + bool fileMode; +public: + + bool IsStreamInMem() const { return !fileMode; } + size_t GetMemStreamWrittenSize() const { return _pos; } + + // ISequentialOutStream *FileStream; + FString FilePath; + COutFileStream *outFileStreamSpec; + CMyComPtr outFileStream; + + CBufSeqOutStream_WithFile(): outFileStreamSpec(NULL) {} + + void Init(Byte *buffer, size_t size) + { + fileMode = false; + _buffer = buffer; + _pos = 0; + _size = size; + _fileWritePos = 0; + } + + HRESULT FlushToFile(); + size_t GetPos() const { return _pos; } +}; + +static const UInt32 kBlockSize = ((UInt32)1 << 31); + +STDMETHODIMP CBufSeqOutStream_WithFile::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + if (!fileMode) + { + if (_size - _pos >= size) + { + if (size != 0) + { + memcpy(_buffer + _pos, data, size); + _pos += size; + } + if (processedSize) + *processedSize = (UInt32)size; + return S_OK; + } + + fileMode = true; + } + RINOK(FlushToFile()); + return outFileStream->Write(data, size, processedSize); +} + +HRESULT CBufSeqOutStream_WithFile::FlushToFile() +{ + if (!outFileStream) + { + outFileStreamSpec = new COutFileStream; + outFileStream = outFileStreamSpec; + if (!outFileStreamSpec->Create(FilePath, false)) + { + outFileStream.Release(); + return E_FAIL; + // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath)); + } + } + while (_fileWritePos != _pos) + { + size_t cur = _pos - _fileWritePos; + UInt32 curSize = (cur < kBlockSize) ? (UInt32)cur : kBlockSize; + UInt32 processedSizeLoc = 0; + HRESULT res = outFileStream->Write(_buffer + _fileWritePos, curSize, &processedSizeLoc); + _fileWritePos += processedSizeLoc; + RINOK(res); + if (processedSizeLoc == 0) + return E_FAIL; + } + return S_OK; +} +*/ + +/* +static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) +{ + filetimeIsDefined = false; + NCOM::CPropVariant prop; + RINOK(folder->GetProperty(index, propID, &prop)); + if (prop.vt == VT_FILETIME) + { + filetime = prop.filetime; + filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} +*/ + + +/* +tryInternal tryExternal + false false : unused + false true : external + true false : internal + true true : smart based on file extension: + !alwaysStart(name) : both + alwaysStart(name) : external +*/ + +void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) +{ + // we don't want to change hash data here + if (IsHashFolder()) + return; + + const UString name = GetItemName(index); + const UString relPath = GetItemRelPath(index); + + if (tryExternal) + if (IsVirus_Message(name)) + return; + + if (!_folderOperations) + { + MessageBox_Error_UnsupportOperation(); + return; + } + + bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name)); + + const UString fullVirtPath = _currentFolderPrefix + relPath; + + CTempDir tempDirectory; + if (!tempDirectory.Create(kTempDirPrefix)) + { + MessageBox_LastError(); + return; + } + + FString tempDir = tempDirectory.GetPath(); + FString tempDirNorm = tempDir; + NName::NormalizeDirPathPrefix(tempDirNorm); + const FString tempFilePath = tempDirNorm + us2fs(Get_Correct_FsFile_Name(name)); + + CTempFileInfo tempFileInfo; + tempFileInfo.FileIndex = index; + tempFileInfo.RelPath = relPath; + tempFileInfo.FolderPath = tempDir; + tempFileInfo.FilePath = tempFilePath; + tempFileInfo.NeedDelete = true; + + if (tryAsArchive) + { + CMyComPtr getStream; + _folder.QueryInterface(IID_IInArchiveGetStream, &getStream); + if (getStream) + { + CMyComPtr subSeqStream; + getStream->GetStream(index, &subSeqStream); + if (subSeqStream) + { + CMyComPtr subStream; + subSeqStream.QueryInterface(IID_IInStream, &subStream); + if (subStream) + { + HRESULT res = OpenAsArc_Msg(subStream, tempFileInfo, fullVirtPath, type ? type : L"" + // , true // showErrorMessage + ); + if (res == S_OK) + { + tempDirectory.DisableDeleting(); + RefreshListCtrl(); + return; + } + if (res == E_ABORT || res != S_FALSE) + return; + if (!tryExternal) + return; + tryAsArchive = false; + } + } + } + } + + + CRecordVector indices; + indices.Add(index); + + UStringVector messages; + + bool usePassword = false; + UString password; + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &fl = _parentFolders.Back(); + usePassword = fl.UsePassword; + password = fl.Password; + } + + /* + #if defined(_WIN32) && !defined(UNDER_CE) + CByteBuffer zoneBuf; + #ifndef _UNICODE + if (g_IsNT) + #endif + if (!_parentFolders.IsEmpty()) + { + const CFolderLink &fl = _parentFolders.Front(); + if (!fl.IsVirtual && !fl.FilePath.IsEmpty()) + ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf); + } + #endif + */ + + + CVirtFileSystem *virtFileSystemSpec = NULL; + CMyComPtr virtFileSystem; + + const bool isAltStream = IsItem_AltStream(index); + + CCopyToOptions options; + options.includeAltStreams = true; + options.replaceAltStreamChars = isAltStream; + { + // CContextMenuInfo ci; + // ci.Load(); + // if (ci.WriteZone != (UInt32)(Int32)-1) + // we use kAll when we unpack just one file. + options.ZoneIdMode = NExtract::NZoneIdMode::kAll; + options.NeedRegistryZone = false; + } + + if (tryAsArchive) + { + // actually we want to get sum: size of main file plus sizes of altStreams. + // but now there is no interface to get altStreams sizes. + NCOM::CPropVariant prop; + _folder->GetProperty(index, kpidSize, &prop); + const size_t fileLimit = g_RAM_Size_Defined ? + g_RAM_Size >> MyMax(_parentFolders.Size() + 1, 8u): + 1u << 22; + UInt64 fileSize = 0; + if (!ConvertPropVariantToUInt64(prop, fileSize)) + fileSize = fileLimit; +#if 0 // 1 : for debug + fileLimit = 1; +#endif + + if (fileSize <= fileLimit) + { + options.streamMode = true; + virtFileSystemSpec = new CVirtFileSystem; + virtFileSystem = virtFileSystemSpec; + virtFileSystemSpec->FileName = name; + virtFileSystemSpec->IsAltStreamFile = isAltStream; + +#if defined(_WIN32) && !defined(UNDER_CE) +#ifndef _UNICODE + if (g_IsNT) +#endif + { + Get_ZoneId_Stream_from_ParentFolders(virtFileSystemSpec->ZoneBuf); + options.ZoneBuf = virtFileSystemSpec->ZoneBuf; + } +#endif + + virtFileSystemSpec->MaxTotalAllocSize = (size_t)fileSize + + (1 << 16); // we allow additional total size for small alt streams. + virtFileSystemSpec->DirPrefix = tempDirNorm; + // options.VirtFileSystem = virtFileSystem; + options.VirtFileSystemSpec = virtFileSystemSpec; + } + } + + options.folder = fs2us(tempDirNorm); + options.showErrorMessages = true; + + const HRESULT result = CopyTo(options, indices, &messages, usePassword, password); + + if (!_parentFolders.IsEmpty()) + { + CFolderLink &fl = _parentFolders.Back(); + fl.UsePassword = usePassword; + fl.Password = password; + } + + if (!messages.IsEmpty()) + return; + if (result != S_OK) + { + if (result != E_ABORT) + MessageBox_Error_HRESULT(result); + return; + } + + if (virtFileSystemSpec && !virtFileSystemSpec->WasStreamFlushedToFS()) + { + int index_in_Files = virtFileSystemSpec->Index_of_MainExtractedFile_in_Files; + if (index_in_Files < 0) + { + if (virtFileSystemSpec->Files.Size() != 1) + { + MessageBox_Error_HRESULT(E_FAIL); + return; + } + // it's not expected case that index was not set, but we support that case + index_in_Files = 0; + } + { + const CVirtFile &file = virtFileSystemSpec->Files[index_in_Files]; + CMyComPtr2_Create bufInStream; + bufInStream->Init(file.Data, file.WrittenSize, virtFileSystem); + const HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo, + fullVirtPath, type ? type : L"" + // , encrypted + // , true // showErrorMessage + ); + if (res == S_OK) + { + if (virtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files >= 0 + && !_parentFolders.IsEmpty()) + { + const CVirtFile &fileZone = virtFileSystemSpec->Files[ + virtFileSystemSpec->Index_of_ZoneBuf_AltStream_in_Files]; + _parentFolders.Back().ZoneBuf.CopyFrom(fileZone.Data, fileZone.WrittenSize); + } + + tempDirectory.DisableDeleting(); + RefreshListCtrl(); + return; + } + if (res == E_ABORT || res != S_FALSE) + return; + if (!tryExternal) + return; + tryAsArchive = false; + if (virtFileSystemSpec->FlushToDisk(true) != S_OK) + return; + } + } + + + /* + #if defined(_WIN32) && !defined(UNDER_CE) + if (zoneBuf.Size() != 0) + { + if (NFind::DoesFileExist_Raw(tempFilePath)) + { + WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf); + } + } + #endif + */ + + + if (tryAsArchive) + { + const HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L"" + // , encrypted + // , true // showErrorMessage + ); + if (res == S_OK) + { + tempDirectory.DisableDeleting(); + RefreshListCtrl(); + return; + } + if (res == E_ABORT || res != S_FALSE) + return; + } + + if (!tryExternal) + return; + + CMyUniquePtr tpi(new CTmpProcessInfo()); + tpi->FolderPath = tempDir; + tpi->FilePath = tempFilePath; + tpi->NeedDelete = true; + tpi->UsePassword = usePassword; + tpi->Password = password; + tpi->ReadOnly = IsThereReadOnlyFolder(); + if (IsHashFolder()) + tpi->ReadOnly = true; + + if (!tpi->FileInfo.Find(tempFilePath)) + return; + + CTmpProcessInfoRelease tmpProcessInfoRelease(*tpi); + + CProcess process; + HRESULT res; + if (editMode) + res = StartEditApplication(fs2us(tempFilePath), useEditor, (HWND)*this, process); + else + res = StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath), (HWND)*this, process); + + if ((HANDLE)process == NULL) + { + // win7 / win10 work so for some extensions (pdf, html ..); + DEBUG_PRINT("#### (HANDLE)process == 0"); + // return; + if (res != S_OK) + return; + } + + tpi->Window = (HWND)*this; + tpi->FullPathFolderPrefix = _currentFolderPrefix; + tpi->FileIndex = index; + tpi->RelPath = relPath; + + if ((HANDLE)process) + tpi->Processes.SetMainProcess(process.Detach()); + + ::CThread th; + if (Thread_Create(&th, MyThreadFunction, tpi.get()) != 0) + throw 271824; + g_ExitEventLauncher._threads.Add(th); + g_ExitEventLauncher._numActiveThreads++; + + tempDirectory.DisableDeleting(); + tpi.release(); + tmpProcessInfoRelease._needDelete = false; +} + + +/* +static const UINT64 kTimeLimit = UINT64(10000000) * 3600 * 24; + +static bool CheckDeleteItem(UINT64 currentFileTime, UINT64 folderFileTime) +{ + return (currentFileTime - folderFileTime > kTimeLimit && + folderFileTime - currentFileTime > kTimeLimit); +} + +void DeleteOldTempFiles() +{ + UString tempPath; + if (!MyGetTempPath(tempPath)) + throw 1; + + UINT64 currentFileTime; + NTime::GetCurUtcFileTime(currentFileTime); + UString searchWildCard = tempPath + kTempDirPrefix + L"*.tmp"; + searchWildCard += WCHAR(NName::kAnyStringWildcard); + NFind::CEnumeratorW enumerator(searchWildCard); + NFind::CFileInfo fileInfo; + while (enumerator.Next(fileInfo)) + { + if (!fileInfo.IsDir()) + continue; + const UINT64 &cTime = *(const UINT64 *)(&fileInfo.CTime); + if (CheckDeleteItem(cTime, currentFileTime)) + RemoveDirectoryWithSubItems(tempPath + fileInfo.Name); + } +} +*/ diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp index a056353ad..868ad227d 100644 --- a/CPP/7zip/UI/FileManager/PanelItems.cpp +++ b/CPP/7zip/UI/FileManager/PanelItems.cpp @@ -1,1450 +1,1453 @@ -// PanelItems.cpp - -#include "StdAfx.h" - -#include "../../../../C/Sort.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../PropID.h" - -#include "../Common/ExtractingFilePath.h" - -#include "resource.h" - -#include "LangUtils.h" -#include "Panel.h" -#include "PropertyName.h" -#include "RootFolder.h" - -using namespace NWindows; - -static bool GetColumnVisible(PROPID propID, bool isFsFolder) -{ - if (isFsFolder) - { - switch (propID) - { - case kpidATime: - case kpidChangeTime: - case kpidAttrib: - case kpidPackSize: - case kpidINode: - case kpidLinks: - case kpidNtReparse: - return false; - } - } - return true; -} - -static unsigned GetColumnWidth(PROPID propID, VARTYPE /* varType */) -{ - switch (propID) - { - case kpidName: return 160; - } - return 100; -} - -static int GetColumnAlign(PROPID propID, VARTYPE varType) -{ - switch (propID) - { - case kpidCTime: - case kpidATime: - case kpidMTime: - case kpidChangeTime: - return LVCFMT_LEFT; - } - - switch (varType) - { - case VT_UI1: - case VT_I2: - case VT_UI2: - case VT_I4: - case VT_INT: - case VT_UI4: - case VT_UINT: - case VT_I8: - case VT_UI8: - case VT_BOOL: - return LVCFMT_RIGHT; - - case VT_EMPTY: - case VT_I1: - case VT_FILETIME: - case VT_BSTR: - return LVCFMT_LEFT; - - default: - return LVCFMT_CENTER; - } -} - - -static int ItemProperty_Compare_NameFirst(void *const *a1, void *const *a2, void * /* param */) -{ - return (*(*((const CPropColumn *const *)a1))).Compare_NameFirst - (*(*((const CPropColumn *const *)a2))); -} - -HRESULT CPanel::InitColumns() -{ - SaveListViewInfo(); - - // DeleteListItems(); - _selectedStatusVector.Clear(); - - { - // ReadListViewInfo(); - const UString oldType = _typeIDString; - _typeIDString = GetFolderTypeID(); - // an empty _typeIDString is allowed. - - // we read registry only for new FolderTypeID - if (!_needSaveInfo || _typeIDString != oldType) - _listViewInfo.Read(_typeIDString); - - // folders with same FolderTypeID can have different columns - // so we still read columns for that case. - // if (_needSaveInfo && _typeIDString == oldType) return S_OK; - } - - // PROPID sortID; - /* - if (_listViewInfo.SortIndex >= 0) - sortID = _listViewInfo.Columns[_listViewInfo.SortIndex].PropID; - */ - // sortID = _listViewInfo.SortID; - - _ascending = _listViewInfo.Ascending; - - _columns.Clear(); - - const bool isFsFolder = IsFSFolder() || IsAltStreamsFolder(); - - { - UInt32 numProps; - _folder->GetNumberOfProperties(&numProps); - - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE varType; - HRESULT res = _folder->GetPropertyInfo(i, &name, &propID, &varType); - - if (res != S_OK) - { - /* We can return ERROR, but in that case, other code will not be called, - and user can see empty window without error message. So we just ignore that field */ - continue; - } - if (propID == kpidIsDir) - continue; - CPropColumn prop; - prop.Type = varType; - prop.ID = propID; - prop.Name = GetNameOfProperty(propID, name); - prop.Order = -1; - prop.IsVisible = GetColumnVisible(propID, isFsFolder); - prop.Width = GetColumnWidth(propID, varType); - prop.IsRawProp = false; - _columns.Add(prop); - } - - /* - { - // debug column - CPropColumn prop; - prop.Type = VT_BSTR; - prop.ID = 2000; - prop.Name = "Debug"; - prop.Order = -1; - prop.IsVisible = true; - prop.Width = 300; - prop.IsRawProp = false; - _columns.Add(prop); - } - */ - } - - if (_folderRawProps) - { - UInt32 numProps; - _folderRawProps->GetNumRawProps(&numProps); - - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - const HRESULT res = _folderRawProps->GetRawPropInfo(i, &name, &propID); - if (res != S_OK) - continue; - CPropColumn prop; - prop.Type = VT_EMPTY; - prop.ID = propID; - prop.Name = GetNameOfProperty(propID, name); - prop.Order = -1; - prop.IsVisible = GetColumnVisible(propID, isFsFolder); - prop.Width = GetColumnWidth(propID, VT_BSTR); - prop.IsRawProp = true; - _columns.Add(prop); - } - } - - unsigned order = 0; - unsigned i; - - for (i = 0; i < _listViewInfo.Columns.Size(); i++) - { - const CColumnInfo &columnInfo = _listViewInfo.Columns[i]; - const int index = _columns.FindItem_for_PropID(columnInfo.PropID); - if (index >= 0) - { - CPropColumn &item = _columns[index]; - if (item.Order >= 0) - continue; // we ignore duplicated items - bool isVisible = columnInfo.IsVisible; - // we enable kpidName, if it was disabled by some incorrect code - if (columnInfo.PropID == kpidName) - isVisible = true; - item.IsVisible = isVisible; - item.Width = columnInfo.Width; - if (isVisible) - item.Order = (int)(order++); - continue; - } - } - - for (i = 0; i < _columns.Size(); i++) - { - CPropColumn &item = _columns[i]; - if (item.IsVisible && item.Order < 0) - item.Order = (int)(order++); - } - - for (i = 0; i < _columns.Size(); i++) - { - CPropColumn &item = _columns[i]; - if (item.Order < 0) - item.Order = (int)(order++); - } - - CPropColumns newColumns; - - for (i = 0; i < _columns.Size(); i++) - { - const CPropColumn &prop = _columns[i]; - if (prop.IsVisible) - newColumns.Add(prop); - } - - - /* - _sortIndex = 0; - if (_listViewInfo.SortIndex >= 0) - { - int sortIndex = _columns.FindItem_for_PropID(sortID); - if (sortIndex >= 0) - _sortIndex = sortIndex; - } - */ - - if (_listViewInfo.IsLoaded) - _sortID = _listViewInfo.SortID; - else - { - _sortID = 0; - if (IsFSFolder() || IsAltStreamsFolder() || IsArcFolder()) - _sortID = kpidName; - } - - /* There are restrictions in ListView control: - 1) main column (kpidName) must have (LV_COLUMNW::iSubItem = 0) - So we need special sorting for columns. - 2) when we add new column, LV_COLUMNW::iOrder cannot be larger than already inserted columns) - So we set column order after all columns are added. - */ - newColumns.Sort(ItemProperty_Compare_NameFirst, NULL); - - if (newColumns.IsEqualTo(_visibleColumns)) - return S_OK; - - CIntArr columns(newColumns.Size()); - for (i = 0; i < newColumns.Size(); i++) - columns[i] = -1; - - bool orderError = false; - - for (i = 0; i < newColumns.Size(); i++) - { - const CPropColumn &prop = newColumns[i]; - if (prop.Order < (int)newColumns.Size() && columns[prop.Order] == -1) - columns[prop.Order] = (int)i; - else - orderError = true; - } - - for (;;) - { - const unsigned numColumns = _visibleColumns.Size(); - if (numColumns == 0) - break; - DeleteColumn(numColumns - 1); - } - - for (i = 0; i < newColumns.Size(); i++) - AddColumn(newColumns[i]); - - // columns[0], columns[1], .... should be displayed from left to right: - if (!orderError) - _listView.SetColumnOrderArray(_visibleColumns.Size(), columns); - - _needSaveInfo = true; - - return S_OK; -} - - -void CPanel::DeleteColumn(unsigned index) -{ - _visibleColumns.Delete(index); - _listView.DeleteColumn(index); -} - -void CPanel::AddColumn(const CPropColumn &prop) -{ - const unsigned index = _visibleColumns.Size(); - - LV_COLUMNW column; - column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; - column.cx = (int)prop.Width; - column.fmt = GetColumnAlign(prop.ID, prop.Type); - column.iOrder = (int)index; // must be <= _listView.ItemCount - column.iSubItem = (int)index; // must be <= _listView.ItemCount - column.pszText = const_cast((const wchar_t *)prop.Name); - - _visibleColumns.Add(prop); - _listView.InsertColumn(index, &column); -} - - -HRESULT CPanel::RefreshListCtrl() -{ - CSelectedState state; - return RefreshListCtrl(state); -} - -int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData); - - -void CPanel::GetSelectedNames(UStringVector &selectedNames) -{ - CRecordVector indices; - Get_ItemIndices_Selected(indices); - selectedNames.ClearAndReserve(indices.Size()); - FOR_VECTOR (i, indices) - selectedNames.AddInReserved(GetItemRelPath(indices[i])); - - /* - for (int i = 0; i < _listView.GetItemCount(); i++) - { - const int kSize = 1024; - WCHAR name[kSize + 1]; - LVITEMW item; - item.iItem = i; - item.pszText = name; - item.cchTextMax = kSize; - item.iSubItem = 0; - item.mask = LVIF_TEXT | LVIF_PARAM; - if (!_listView.GetItem(&item)) - continue; - const unsigned realIndex = GetRealIndex(item); - if (realIndex == kParentIndex) - continue; - if (_selectedStatusVector[realIndex]) - selectedNames.Add(item.pszText); - } - */ - selectedNames.Sort(); -} - -void CPanel::SaveSelectedState(CSelectedState &s) -{ - s.FocusedName_Defined = false; - s.FocusedName.Empty(); - s.SelectFocused = true; // false; - s.SelectedNames.Clear(); - s.FocusedItem = _listView.GetFocusedItem(); - { - if (s.FocusedItem >= 0) - { - const unsigned realIndex = GetRealItemIndex(s.FocusedItem); - if (realIndex != kParentIndex) - { - s.FocusedName = GetItemRelPath(realIndex); - s.FocusedName_Defined = true; - - s.SelectFocused = _listView.IsItemSelected(s.FocusedItem); - - /* - const int kSize = 1024; - WCHAR name[kSize + 1]; - LVITEMW item; - item.iItem = focusedItem; - item.pszText = name; - item.cchTextMax = kSize; - item.iSubItem = 0; - item.mask = LVIF_TEXT; - if (_listView.GetItem(&item)) - focusedName = item.pszText; - */ - } - } - } - GetSelectedNames(s.SelectedNames); -} - -/* -HRESULT CPanel::RefreshListCtrl(const CSelectedState &s) -{ - bool selectFocused = s.SelectFocused; - if (_mySelectMode) - selectFocused = true; - return RefreshListCtrl2( - s.FocusedItem >= 0, // allowEmptyFocusedName - s.FocusedName, s.FocusedItem, selectFocused, s.SelectedNames); -} -*/ - -HRESULT CPanel::RefreshListCtrl_SaveFocused(bool onTimer) -{ - CSelectedState state; - SaveSelectedState(state); - state.CalledFromTimer = onTimer; - return RefreshListCtrl(state); -} - -void CPanel::SetFocusedSelectedItem(int index, bool select) -{ - UINT state = LVIS_FOCUSED; - if (select) - state |= LVIS_SELECTED; - _listView.SetItemState(index, state, state); - if (!_mySelectMode && select) - { - const unsigned realIndex = GetRealItemIndex(index); - if (realIndex != kParentIndex) - _selectedStatusVector[realIndex] = true; - } -} - -// #define PRINT_STAT - -#ifdef PRINT_STAT - void Print_OnNotify(const char *name); -#else - #define Print_OnNotify(x) -#endif - - - -/* - -extern UInt32 g_NumGroups; -extern DWORD g_start_tick; -extern DWORD g_prev_tick; -extern DWORD g_Num_SetItemText; -extern UInt32 g_NumMessages; -*/ - -HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) -{ - m_DropHighlighted_SelectionIndex = -1; - m_DropHighlighted_SubFolderName.Empty(); - - if (!_folder) - return S_OK; - - /* - g_start_tick = GetTickCount(); - g_Num_SetItemText = 0; - g_NumMessages = 0; - */ - - _dontShowMode = false; - if (!state.CalledFromTimer) - LoadFullPathAndShow(); - // OutputDebugStringA("=======\n"); - // OutputDebugStringA("s1 \n"); - CDisableTimerProcessing timerProcessing(*this); - CDisableNotify disableNotify(*this); - - int focusedPos = state.FocusedItem; - if (focusedPos < 0) - focusedPos = 0; - - _listView.SetRedraw(false); - // m_RedrawEnabled = false; - - LVITEMW item; - ZeroMemory(&item, sizeof(item)); - - // DWORD tickCount0 = GetTickCount(); - - // _enableItemChangeNotify = false; - DeleteListItems(); - _enableItemChangeNotify = true; - - int listViewItemCount = 0; - - _selectedStatusVector.Clear(); - // _realIndices.Clear(); - _startGroupSelect = 0; - - _selectionIsDefined = false; - - // m_Files.Clear(); - - /* - if (!_folder) - { - // throw 1; - SetToRootFolder(); - } - */ - - _headerToolBar.EnableButton(kParentFolderID, !IsRootFolder()); - - { - CMyComPtr folderSetFlatMode; - _folder.QueryInterface(IID_IFolderSetFlatMode, &folderSetFlatMode); - if (folderSetFlatMode) - folderSetFlatMode->SetFlatMode(BoolToInt(_flatMode)); - } - - /* - { - CMyComPtr setShow; - _folder.QueryInterface(IID_IFolderSetShowNtfsStreamsMode, &setShow); - if (setShow) - setShow->SetShowNtfsStreamsMode(BoolToInt(_showNtfsStrems_Mode)); - } - */ - - _isDirVector.Clear(); - // DWORD tickCount1 = GetTickCount(); - IFolderFolder *folder = _folder; - RINOK(_folder->LoadItems()) - // DWORD tickCount2 = GetTickCount(); - // OutputDebugString(TEXT("Start Dir\n")); - RINOK(InitColumns()) - - UInt32 numItems; - _folder->GetNumberOfItems(&numItems); - { - NCOM::CPropVariant prop; - _isDirVector.ClearAndSetSize(numItems); - bool *vec = _isDirVector.NonConstData(); - HRESULT hres = S_OK; - unsigned i; - for (i = 0; i < numItems; i++) - { - hres = folder->GetProperty(i, kpidIsDir, &prop); - if (hres != S_OK) - break; - bool v = false; - if (prop.vt == VT_BOOL) - v = VARIANT_BOOLToBool(prop.boolVal); - else if (prop.vt != VT_EMPTY) - break; - vec[i] = v; - } - if (i != numItems) - { - _isDirVector.Clear(); - if (hres == S_OK) - hres = E_FAIL; - } - RINOK(hres) - } - - const bool showDots = _showDots && !IsRootFolder(); - - _listView.SetItemCount(numItems + (showDots ? 1 : 0)); - - _selectedStatusVector.ClearAndReserve(numItems); - int cursorIndex = -1; - - CMyComPtr folderGetSystemIconIndex; -#if 1 // 0 : for debug local icons loading - if (!Is_Slow_Icon_Folder() || _showRealFileIcons) - _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex); -#endif - - const bool isFSDrivesFolder = IsFSDrivesFolder(); - const bool isArcFolder = IsArcFolder(); - - if (!IsFSFolder()) - { - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - _thereAreDeletedItems = false; - if (getFolderArcProps) - { - CMyComPtr arcProps; - getFolderArcProps->GetFolderArcProps(&arcProps); - if (arcProps) - { - UInt32 numLevels; - if (arcProps->GetArcNumLevels(&numLevels) != S_OK) - numLevels = 0; - NCOM::CPropVariant prop; - if (arcProps->GetArcProp(numLevels - 1, kpidIsDeleted, &prop) == S_OK) - if (prop.vt == VT_BOOL && VARIANT_BOOLToBool(prop.boolVal)) - _thereAreDeletedItems = true; - } - } - } - - _thereAre_ListView_Items = true; - - // OutputDebugStringA("\n\n"); - - Print_OnNotify("===== Before Load"); - - // #define USE_EMBED_ITEM - - if (showDots) - { - const UString itemName (".."); - item.iItem = listViewItemCount; - if (itemName == state.FocusedName) - cursorIndex = listViewItemCount; - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - int subItem = 0; - item.iSubItem = subItem++; - item.lParam = (LPARAM)(int)kParentIndex; - #ifdef USE_EMBED_ITEM - item.pszText = const_cast((const wchar_t *)itemName); - #else - item.pszText = LPSTR_TEXTCALLBACKW; - #endif - // const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY; - item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR(); - // g_Ext_to_Icon_Map.GetIconIndex(attrib, itemName); - if (item.iImage < 0) - item.iImage = 0; - if (_listView.InsertItem(&item) == -1) - return E_FAIL; - listViewItemCount++; - } - - // OutputDebugStringA("S1\n"); - - UString correctedName; - UString itemName; - UString relPath; - - for (UInt32 i = 0; i < numItems; i++) - { - const wchar_t *name = NULL; - unsigned nameLen = 0; - - if (_folderGetItemName) - _folderGetItemName->GetItemName(i, &name, &nameLen); - if (!name) - { - GetItemName(i, itemName); - name = itemName; - nameLen = itemName.Len(); - } - - bool selected = false; - - if (state.FocusedName_Defined || !state.SelectedNames.IsEmpty()) - { - relPath.Empty(); - // relPath += GetItemPrefix(i); - if (_flatMode) - { - const wchar_t *prefix = NULL; - if (_folderGetItemName) - { - unsigned prefixLen = 0; - _folderGetItemName->GetItemPrefix(i, &prefix, &prefixLen); - if (prefix) - relPath = prefix; - } - if (!prefix) - { - NCOM::CPropVariant prop; - if (_folder->GetProperty(i, kpidPrefix, &prop) != S_OK) - throw 2723400; - if (prop.vt == VT_BSTR) - relPath.SetFromBstr(prop.bstrVal); - } - } - relPath += name; - if (relPath == state.FocusedName) - cursorIndex = listViewItemCount; - if (state.SelectedNames.FindInSorted(relPath) != -1) - selected = true; - } - - _selectedStatusVector.AddInReserved(selected); - - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - - if (!_mySelectMode) - if (selected) - { - item.mask |= LVIF_STATE; - item.state = LVIS_SELECTED; - } - - int subItem = 0; - item.iItem = listViewItemCount; - - item.iSubItem = subItem++; - item.lParam = (LPARAM)i; - - /* - int finish = nameLen - 4; - int j; - for (j = 0; j < finish; j++) - { - if (name[j ] == ' ' && - name[j + 1] == ' ' && - name[j + 2] == ' ' && - name[j + 3] == ' ' && - name[j + 4] == ' ') - break; - } - if (j < finish) - { - correctedName.Empty(); - correctedName = "virus"; - int pos = 0; - for (;;) - { - int posNew = itemName.Find(L" ", pos); - if (posNew < 0) - { - correctedName += itemName.Ptr(pos); - break; - } - correctedName += itemName.Mid(pos, posNew - pos); - correctedName += " ... "; - pos = posNew; - while (itemName[++pos] == ' '); - } - item.pszText = const_cast((const wchar_t *)correctedName); - } - else - */ - { - #ifdef USE_EMBED_ITEM - item.pszText = const_cast((const wchar_t *)name); - #else - item.pszText = LPSTR_TEXTCALLBACKW; - #endif - /* LPSTR_TEXTCALLBACKW works, but in some cases there are problems, - since we block notify handler. - LPSTR_TEXTCALLBACKW can be 2-3 times faster for loading in this loop. */ - } - - bool defined = false; - item.iImage = -1; - - if (folderGetSystemIconIndex) - { - const HRESULT res = folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage); - if (res == S_OK) - { - // item.iImage = -1; // for debug - defined = (item.iImage > 0); -#if 0 // 0: can be slower: 2 attempts for some paths. - // 1: faster, but we can get default icon for some cases (where non default icon is possible) - - if (item.iImage == 0) - { - // (item.iImage == 0) means default icon. - // But (item.iImage == 0) also can be returned for exe/ico files, - // if filePath is LONG PATH (path_len() >= MAX_PATH). - // Also we want to show split icon (.001) for any split extension: 001 002 003. - // Are there another cases for (item.iImage == 0) for files with known extensions? - // We don't want to do second attempt to request icon, - // if it also will return (item.iImage == 0). - - int dotPos = -1; - for (unsigned k = 0;; k++) - { - const wchar_t c = name[k]; - if (c == 0) - break; - if (c == '.') - dotPos = (int)i; - // we don't need IS_PATH_SEPAR check, because we have only (fileName) doesn't include path prefix. - // if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1; - } - defined = true; - if (dotPos >= 0) - { -#if 0 - const wchar_t *ext = name + dotPos; - if (StringsAreEqualNoCase_Ascii(ext, ".exe") || - StringsAreEqualNoCase_Ascii(ext, ".ico")) -#endif - defined = false; - } - } -#endif - } - } - - if (!defined) - { - UInt32 attrib = 0; - { - NCOM::CPropVariant prop; - RINOK(_folder->GetProperty(i, kpidAttrib, &prop)) - if (prop.vt == VT_UI4) - { - attrib = prop.ulVal; - if (isArcFolder) - { - // if attrib (high 16-bits) is supposed from posix, - // we keep only low bits (basic Windows attrib flags): - if (attrib & 0xF0000000) - attrib &= 0x3FFF; - } - } - } - if (IsItem_Folder(i)) - attrib |= FILE_ATTRIBUTE_DIRECTORY; - else - attrib &= ~(UInt32)FILE_ATTRIBUTE_DIRECTORY; - - item.iImage = -1; - if (isFSDrivesFolder) - { - FString fs (us2fs((UString)name)); - fs.Add_PathSepar(); - item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(fs, attrib); - // item.iImage = 0; // for debug - } - if (item.iImage < 0) // <= 0 check? - item.iImage = g_Ext_to_Icon_Map.GetIconIndex(attrib, name); - } - - // item.iImage = -1; // for debug - if (item.iImage < 0) - item.iImage = 0; // default image - if (_listView.InsertItem(&item) == -1) - return E_FAIL; - listViewItemCount++; - } - - /* - xp-64: there is different order when Windows calls CPanel::OnNotify for _listView modes: - Details : after whole code - List : 2 times: - 1) - ListView.SotRedraw() - 2) - after whole code - Small Icons : - Large icons : 2 times: - 1) - ListView.Sort() - 2) - after whole code (calls with reverse order of items) - - So we need to allow Notify(), when windows requests names during the following code. - */ - - Print_OnNotify("after Load"); - - disableNotify.SetMemMode_Enable(); - disableNotify.Restore(); - - if (_listView.GetItemCount() > 0 && cursorIndex >= 0) - SetFocusedSelectedItem(cursorIndex, state.SelectFocused); - - Print_OnNotify("after SetFocusedSelectedItem"); - - SetSortRawStatus(); - _listView.SortItems(CompareItems, (LPARAM)this); - - Print_OnNotify("after Sort"); - - if (cursorIndex < 0 && _listView.GetItemCount() > 0) - { - if (focusedPos >= _listView.GetItemCount()) - focusedPos = _listView.GetItemCount() - 1; - // we select item only in showDots mode. - SetFocusedSelectedItem(focusedPos, showDots && (focusedPos == 0)); - } - - // m_RedrawEnabled = true; - - Print_OnNotify("after SetFocusedSelectedItem2"); - - _listView.EnsureVisible(_listView.GetFocusedItem(), false); - - // disableNotify.SetMemMode_Enable(); - // disableNotify.Restore(); - - Print_OnNotify("after EnsureVisible"); - - _listView.SetRedraw(true); - - Print_OnNotify("after SetRedraw"); - - _listView.InvalidateRect(NULL, true); - - Print_OnNotify("after InvalidateRect"); - /* - _listView.UpdateWindow(); - */ - Refresh_StatusBar(); - /* - char s[256]; - sprintf(s, - // "attribMap = %5d, extMap = %5d, " - "delete = %5d, load = %5d, list = %5d, sort = %5d, end = %5d", - // g_Ext_to_Icon_Map._attribMap.Size(), - // g_Ext_to_Icon_Map._extMap.Size(), - tickCount1 - tickCount0, - tickCount2 - tickCount1, - tickCount3 - tickCount2, - tickCount4 - tickCount3, - tickCount5 - tickCount4 - ); - sprintf(s, - "5 = %5d, 6 = %5d, 7 = %5d, 8 = %5d, 9 = %5d", - tickCount5 - tickCount4, - tickCount6 - tickCount5, - tickCount7 - tickCount6, - tickCount8 - tickCount7, - tickCount9 - tickCount8 - ); - OutputDebugStringA(s); - */ - return S_OK; -} - - -void CPanel::Get_ItemIndices_Selected(CRecordVector &indices) const -{ - indices.Clear(); - /* - int itemIndex = -1; - while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1) - { - LPARAM param; - if (_listView.GetItemParam(itemIndex, param)) - indices.Add(param); - } - HeapSort(&indices.Front(), indices.Size()); - */ - const bool *v = _selectedStatusVector.ConstData(); - const unsigned size = _selectedStatusVector.Size(); - for (unsigned i = 0; i < size; i++) - if (v[i]) - indices.Add(i); -} - - -void CPanel::Get_ItemIndices_Operated(CRecordVector &indices) const -{ - Get_ItemIndices_Selected(indices); - if (!indices.IsEmpty()) - return; - if (_listView.GetSelectedCount() == 0) - return; - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem >= 0) - { - if (_listView.IsItemSelected(focusedItem)) - { - const unsigned realIndex = GetRealItemIndex(focusedItem); - if (realIndex != kParentIndex) - indices.Add(realIndex); - } - } -} - -void CPanel::Get_ItemIndices_All(CRecordVector &indices) const -{ - indices.Clear(); - UInt32 numItems; - if (_folder->GetNumberOfItems(&numItems) != S_OK) - return; - indices.ClearAndSetSize(numItems); - UInt32 *vec = indices.NonConstData(); - for (UInt32 i = 0; i < numItems; i++) - vec[i] = i; -} - -void CPanel::Get_ItemIndices_OperSmart(CRecordVector &indices) const -{ - Get_ItemIndices_Operated(indices); - if (indices.IsEmpty() || (indices.Size() == 1 && indices[0] == (UInt32)(Int32)-1)) - Get_ItemIndices_All(indices); -} - -/* -void CPanel::GetOperatedListViewIndices(CRecordVector &indices) const -{ - indices.Clear(); - int numItems = _listView.GetItemCount(); - for (int i = 0; i < numItems; i++) - { - const unsigned realIndex = GetRealItemIndex(i); - if (realIndex >= 0) - if (_selectedStatusVector[realIndex]) - indices.Add(i); - } - if (indices.IsEmpty()) - { - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem >= 0) - indices.Add(focusedItem); - } -} -*/ - -void CPanel::EditItem(bool useEditor) -{ - if (!useEditor) - { - CMyComPtr calcItemFullSize; - _folder.QueryInterface(IID_IFolderCalcItemFullSize, &calcItemFullSize); - if (calcItemFullSize) - { - bool needRefresh = false; - CRecordVector indices; - Get_ItemIndices_Operated(indices); - FOR_VECTOR (i, indices) - { - UInt32 index = indices[i]; - if (IsItem_Folder(index)) - { - calcItemFullSize->CalcItemFullSize(index, NULL); - needRefresh = true; - } - } - if (needRefresh) - { - // _listView.RedrawItem(0); - // _listView.RedrawAllItems(); - InvalidateList(); - return; - } - } - } - - - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const unsigned realIndex = GetRealItemIndex(focusedItem); - if (realIndex == kParentIndex) - return; - if (!IsItem_Folder(realIndex)) - EditItem(realIndex, useEditor); -} - -void CPanel::OpenFocusedItemAsInternal(const wchar_t *type) -{ - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const unsigned realIndex = GetRealItemIndex(focusedItem); - if (IsItem_Folder(realIndex)) - OpenFolder(realIndex); - else - OpenItem(realIndex, true, false, type); -} - -void CPanel::OpenSelectedItems(bool tryInternal) -{ - CRecordVector indices; - Get_ItemIndices_Operated(indices); - if (indices.Size() > 20) - { - MessageBox_Error_LangID(IDS_TOO_MANY_ITEMS); - return; - } - - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem >= 0) - { - const unsigned realIndex = GetRealItemIndex(focusedItem); - if (realIndex == kParentIndex && (tryInternal || indices.Size() == 0) && _listView.IsItemSelected(focusedItem)) - indices.Insert(0, realIndex); - } - - bool dirIsStarted = false; - FOR_VECTOR (i, indices) - { - UInt32 index = indices[i]; - // CFileInfo &aFile = m_Files[index]; - if (IsItem_Folder(index)) - { - if (!dirIsStarted) - { - if (tryInternal) - { - OpenFolder(index); - dirIsStarted = true; - break; - } - else - OpenFolderExternal(index); - } - } - else - OpenItem(index, (tryInternal && indices.Size() == 1), true); - } -} - -UString CPanel::GetItemName(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return L".."; - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) - throw 2723400; - if (prop.vt != VT_BSTR) - throw 2723401; - return prop.bstrVal; -} - -UString CPanel::GetItemName_for_Copy(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return L".."; - UString s; - { - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidOutName, &prop) == S_OK) - { - if (prop.vt == VT_BSTR) - s = prop.bstrVal; - else if (prop.vt != VT_EMPTY) - throw 2723401; - } - if (s.IsEmpty()) - s = GetItemName(itemIndex); - } - return Get_Correct_FsFile_Name(s); -} - -void CPanel::GetItemName(unsigned itemIndex, UString &s) const -{ - if (itemIndex == kParentIndex) - { - s = ".."; - return; - } - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) - throw 2723400; - if (prop.vt != VT_BSTR) - throw 2723401; - s.SetFromBstr(prop.bstrVal); -} - -UString CPanel::GetItemPrefix(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return UString(); - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK) - throw 2723400; - UString prefix; - if (prop.vt == VT_BSTR) - prefix.SetFromBstr(prop.bstrVal); - return prefix; -} - -UString CPanel::GetItemRelPath(unsigned itemIndex) const -{ - return GetItemPrefix(itemIndex) + GetItemName(itemIndex); -} - -UString CPanel::GetItemRelPath2(unsigned itemIndex) const -{ - UString s = GetItemRelPath(itemIndex); - #if defined(_WIN32) && !defined(UNDER_CE) - if (s.Len() == 2 && NFile::NName::IsDrivePath2(s)) - { - if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()) - s.Add_PathSepar(); - } - #endif - return s; -} - - -void CPanel::Add_ItemRelPath2_To_String(unsigned itemIndex, UString &s) const -{ - if (itemIndex == kParentIndex) - { - s += ".."; - return; - } - - const unsigned start = s.Len(); - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK) - throw 2723400; - if (prop.vt == VT_BSTR) - s += prop.bstrVal; - - const wchar_t *name = NULL; - unsigned nameLen = 0; - - if (_folderGetItemName) - _folderGetItemName->GetItemName(itemIndex, &name, &nameLen); - if (name) - s += name; - else - { - prop.Clear(); - if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) - throw 2723400; - if (prop.vt != VT_BSTR) - throw 2723401; - s += prop.bstrVal; - } - - #if defined(_WIN32) && !defined(UNDER_CE) - if (s.Len() - start == 2 && NFile::NName::IsDrivePath2(s.Ptr(start))) - { - if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()) - s.Add_PathSepar(); - } - #endif -} - - -UString CPanel::GetItemFullPath(unsigned itemIndex) const -{ - return GetFsPath() + GetItemRelPath2(itemIndex); -} - -bool CPanel::GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const -{ - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, propID, &prop) != S_OK) - throw 2723400; - if (prop.vt == VT_BOOL) - return VARIANT_BOOLToBool(prop.boolVal); - if (prop.vt == VT_EMPTY) - return false; - throw 2723401; -} - -bool CPanel::IsItem_Deleted(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return false; - return GetItem_BoolProp(itemIndex, kpidIsDeleted); -} - -bool CPanel::IsItem_Folder(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return true; - if (itemIndex < _isDirVector.Size()) - return _isDirVector[itemIndex]; - return GetItem_BoolProp(itemIndex, kpidIsDir); -} - -bool CPanel::IsItem_AltStream(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return false; - return GetItem_BoolProp(itemIndex, kpidIsAltStream); -} - -UInt64 CPanel::GetItem_UInt64Prop(unsigned itemIndex, PROPID propID) const -{ - if (itemIndex == kParentIndex) - return 0; - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, propID, &prop) != S_OK) - throw 2723400; - UInt64 val = 0; - if (ConvertPropVariantToUInt64(prop, val)) - return val; - return 0; -} - -UInt64 CPanel::GetItemSize(unsigned itemIndex) const -{ - if (itemIndex == kParentIndex) - return 0; - if (_folderGetItemName) - return _folderGetItemName->GetItemSize(itemIndex); - return GetItem_UInt64Prop(itemIndex, kpidSize); -} - -void CPanel::SaveListViewInfo() -{ - if (!_needSaveInfo) - return; - - unsigned i; - - for (i = 0; i < _visibleColumns.Size(); i++) - { - CPropColumn &prop = _visibleColumns[i]; - LVCOLUMN winColumnInfo; - winColumnInfo.mask = LVCF_ORDER | LVCF_WIDTH; - if (!_listView.GetColumn(i, &winColumnInfo)) - throw 1; - prop.Order = winColumnInfo.iOrder; - prop.Width = (UInt32)(Int32)winColumnInfo.cx; - } - - CListViewInfo viewInfo; - - // PROPID sortPropID = _columns[_sortIndex].ID; - const PROPID sortPropID = _sortID; - - // we save columns as "sorted by order" to registry - - CPropColumns sortedProperties = _visibleColumns; - - sortedProperties.Sort(); - - for (i = 0; i < sortedProperties.Size(); i++) - { - const CPropColumn &prop = sortedProperties[i]; - CColumnInfo columnInfo; - columnInfo.IsVisible = prop.IsVisible; - columnInfo.PropID = prop.ID; - columnInfo.Width = prop.Width; - viewInfo.Columns.Add(columnInfo); - } - - for (i = 0; i < _columns.Size(); i++) - { - const CPropColumn &prop = _columns[i]; - if (sortedProperties.FindItem_for_PropID(prop.ID) < 0) - { - CColumnInfo columnInfo; - columnInfo.IsVisible = false; - columnInfo.PropID = prop.ID; - columnInfo.Width = prop.Width; - viewInfo.Columns.Add(columnInfo); - } - } - - viewInfo.SortID = sortPropID; - viewInfo.Ascending = _ascending; - viewInfo.IsLoaded = true; - if (!_listViewInfo.IsEqual(viewInfo)) - { - viewInfo.Save(_typeIDString); - _listViewInfo = viewInfo; - } -} - - -bool CPanel::OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result) -{ - if (itemActivate->hdr.hwndFrom == HWND(_listView)) - return false; - POINT point; - ::GetCursorPos(&point); - ShowColumnsContextMenu(point.x, point.y); - result = TRUE; - return true; -} - -void CPanel::ShowColumnsContextMenu(int x, int y) -{ - CMenu menu; - CMenuDestroyer menuDestroyer(menu); - - menu.CreatePopup(); - - const int kCommandStart = 100; - FOR_VECTOR (i, _columns) - { - const CPropColumn &prop = _columns[i]; - UINT flags = MF_STRING; - if (prop.IsVisible) - flags |= MF_CHECKED; - if (i == 0) - flags |= MF_GRAYED; - menu.AppendItem(flags, kCommandStart + i, prop.Name); - } - - const int menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, x, y, _listView); - - if (menuResult >= kCommandStart && menuResult <= kCommandStart + (int)_columns.Size()) - { - const unsigned index = (unsigned)(menuResult - kCommandStart); - CPropColumn &prop = _columns[index]; - prop.IsVisible = !prop.IsVisible; - - if (prop.IsVisible) - { - prop.Order = (int)_visibleColumns.Size(); - AddColumn(prop); - } - else - { - const int visibleIndex = _visibleColumns.FindItem_for_PropID(prop.ID); - if (visibleIndex >= 0) - { - /* - if (_sortIndex == index) - { - _sortIndex = 0; - _ascending = true; - } - */ - if (_sortID == prop.ID) - { - _sortID = kpidName; - _ascending = true; - } - DeleteColumn((unsigned)visibleIndex); - } - } - } -} - -void CPanel::OnReload(bool onTimer) -{ - const HRESULT res = RefreshListCtrl_SaveFocused(onTimer); - if (res != S_OK) - MessageBox_Error_HRESULT(res); -} - -void CPanel::OnTimer() -{ - if (!_processTimer) - return; - if (!AutoRefresh_Mode) - return; - CMyComPtr folderWasChanged; - if (_folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged) != S_OK) - return; - Int32 wasChanged; - if (folderWasChanged->WasChanged(&wasChanged) != S_OK) - return; - if (wasChanged == 0) - return; - OnReload(true); // onTimer -} +// PanelItems.cpp + +#include "StdAfx.h" + +#include "../../../../C/Sort.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../PropID.h" + +#include "../Common/ExtractingFilePath.h" + +#include "resource.h" + +#include "LangUtils.h" +#include "Panel.h" +#include "PropertyName.h" +#include "RootFolder.h" + +using namespace NWindows; + +static bool GetColumnVisible(PROPID propID, bool isFsFolder) +{ + if (isFsFolder) + { + switch (propID) + { + case kpidATime: + case kpidChangeTime: + case kpidAttrib: + case kpidPackSize: + case kpidINode: + case kpidLinks: + case kpidNtReparse: + return false; + } + } + return true; +} + +static unsigned GetColumnWidth(PROPID propID, VARTYPE /* varType */) +{ + switch (propID) + { + case kpidName: return 160; + } + return 100; +} + +static int GetColumnAlign(PROPID propID, VARTYPE varType) +{ + switch (propID) + { + case kpidCTime: + case kpidATime: + case kpidMTime: + case kpidChangeTime: + return LVCFMT_LEFT; + } + + switch (varType) + { + case VT_UI1: + case VT_I2: + case VT_UI2: + case VT_I4: + case VT_INT: + case VT_UI4: + case VT_UINT: + case VT_I8: + case VT_UI8: + case VT_BOOL: + return LVCFMT_RIGHT; + + case VT_EMPTY: + case VT_I1: + case VT_FILETIME: + case VT_BSTR: + return LVCFMT_LEFT; + + default: + return LVCFMT_CENTER; + } +} + + +static int ItemProperty_Compare_NameFirst(void *const *a1, void *const *a2, void * /* param */) +{ + return (*(*((const CPropColumn *const *)a1))).Compare_NameFirst + (*(*((const CPropColumn *const *)a2))); +} + +HRESULT CPanel::InitColumns() +{ + SaveListViewInfo(); + + // DeleteListItems(); + _selectedStatusVector.Clear(); + + { + // ReadListViewInfo(); + const UString oldType = _typeIDString; + _typeIDString = GetFolderTypeID(); + // an empty _typeIDString is allowed. + + // we read registry only for new FolderTypeID + if (!_needSaveInfo || _typeIDString != oldType) + _listViewInfo.Read(_typeIDString); + + // folders with same FolderTypeID can have different columns + // so we still read columns for that case. + // if (_needSaveInfo && _typeIDString == oldType) return S_OK; + } + + // PROPID sortID; + /* + if (_listViewInfo.SortIndex >= 0) + sortID = _listViewInfo.Columns[_listViewInfo.SortIndex].PropID; + */ + // sortID = _listViewInfo.SortID; + + _ascending = _listViewInfo.Ascending; + + _columns.Clear(); + + const bool isFsFolder = IsFSFolder() || IsAltStreamsFolder(); + + { + UInt32 numProps; + _folder->GetNumberOfProperties(&numProps); + + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE varType; + HRESULT res = _folder->GetPropertyInfo(i, &name, &propID, &varType); + + if (res != S_OK) + { + /* We can return ERROR, but in that case, other code will not be called, + and user can see empty window without error message. So we just ignore that field */ + continue; + } + if (propID == kpidIsDir) + continue; + CPropColumn prop; + prop.Type = varType; + prop.ID = propID; + prop.Name = GetNameOfProperty(propID, name); + prop.Order = -1; + prop.IsVisible = GetColumnVisible(propID, isFsFolder); + prop.Width = GetColumnWidth(propID, varType); + prop.IsRawProp = false; + _columns.Add(prop); + } + + /* + { + // debug column + CPropColumn prop; + prop.Type = VT_BSTR; + prop.ID = 2000; + prop.Name = "Debug"; + prop.Order = -1; + prop.IsVisible = true; + prop.Width = 300; + prop.IsRawProp = false; + _columns.Add(prop); + } + */ + } + + if (_folderRawProps) + { + UInt32 numProps; + _folderRawProps->GetNumRawProps(&numProps); + + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + const HRESULT res = _folderRawProps->GetRawPropInfo(i, &name, &propID); + if (res != S_OK) + continue; + CPropColumn prop; + prop.Type = VT_EMPTY; + prop.ID = propID; + prop.Name = GetNameOfProperty(propID, name); + prop.Order = -1; + prop.IsVisible = GetColumnVisible(propID, isFsFolder); + prop.Width = GetColumnWidth(propID, VT_BSTR); + prop.IsRawProp = true; + _columns.Add(prop); + } + } + + unsigned order = 0; + unsigned i; + + for (i = 0; i < _listViewInfo.Columns.Size(); i++) + { + const CColumnInfo &columnInfo = _listViewInfo.Columns[i]; + const int index = _columns.FindItem_for_PropID(columnInfo.PropID); + if (index >= 0) + { + CPropColumn &item = _columns[index]; + if (item.Order >= 0) + continue; // we ignore duplicated items + bool isVisible = columnInfo.IsVisible; + // we enable kpidName, if it was disabled by some incorrect code + if (columnInfo.PropID == kpidName) + isVisible = true; + item.IsVisible = isVisible; + item.Width = columnInfo.Width; + if (isVisible) + item.Order = (int)(order++); + continue; + } + } + + for (i = 0; i < _columns.Size(); i++) + { + CPropColumn &item = _columns[i]; + if (item.IsVisible && item.Order < 0) + item.Order = (int)(order++); + } + + for (i = 0; i < _columns.Size(); i++) + { + CPropColumn &item = _columns[i]; + if (item.Order < 0) + item.Order = (int)(order++); + } + + CPropColumns newColumns; + + for (i = 0; i < _columns.Size(); i++) + { + const CPropColumn &prop = _columns[i]; + if (prop.IsVisible) + newColumns.Add(prop); + } + + + /* + _sortIndex = 0; + if (_listViewInfo.SortIndex >= 0) + { + int sortIndex = _columns.FindItem_for_PropID(sortID); + if (sortIndex >= 0) + _sortIndex = sortIndex; + } + */ + + if (_listViewInfo.IsLoaded) + _sortID = _listViewInfo.SortID; + else + { + _sortID = 0; + if (IsFSFolder() || IsAltStreamsFolder() || IsArcFolder()) + _sortID = kpidName; + } + + /* There are restrictions in ListView control: + 1) main column (kpidName) must have (LV_COLUMNW::iSubItem = 0) + So we need special sorting for columns. + 2) when we add new column, LV_COLUMNW::iOrder cannot be larger than already inserted columns) + So we set column order after all columns are added. + */ + newColumns.Sort(ItemProperty_Compare_NameFirst, NULL); + + if (newColumns.IsEqualTo(_visibleColumns)) + return S_OK; + + CIntArr columns(newColumns.Size()); + for (i = 0; i < newColumns.Size(); i++) + columns[i] = -1; + + bool orderError = false; + + for (i = 0; i < newColumns.Size(); i++) + { + const CPropColumn &prop = newColumns[i]; + if (prop.Order < (int)newColumns.Size() && columns[prop.Order] == -1) + columns[prop.Order] = (int)i; + else + orderError = true; + } + + for (;;) + { + const unsigned numColumns = _visibleColumns.Size(); + if (numColumns == 0) + break; + DeleteColumn(numColumns - 1); + } + + for (i = 0; i < newColumns.Size(); i++) + AddColumn(newColumns[i]); + + // columns[0], columns[1], .... should be displayed from left to right: + if (!orderError) + _listView.SetColumnOrderArray(_visibleColumns.Size(), columns); + + _needSaveInfo = true; + + return S_OK; +} + + +void CPanel::DeleteColumn(unsigned index) +{ + _visibleColumns.Delete(index); + _listView.DeleteColumn(index); +} + +void CPanel::AddColumn(const CPropColumn &prop) +{ + const unsigned index = _visibleColumns.Size(); + + LV_COLUMNW column; + column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; + column.cx = (int)prop.Width; + column.fmt = GetColumnAlign(prop.ID, prop.Type); + column.iOrder = (int)index; // must be <= _listView.ItemCount + column.iSubItem = (int)index; // must be <= _listView.ItemCount + column.pszText = const_cast((const wchar_t *)prop.Name); + + _visibleColumns.Add(prop); + _listView.InsertColumn(index, &column); +} + + +HRESULT CPanel::RefreshListCtrl() +{ + CSelectedState state; + return RefreshListCtrl(state); +} + +int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData); + + +void CPanel::GetSelectedNames(UStringVector &selectedNames) +{ + CRecordVector indices; + Get_ItemIndices_Selected(indices); + selectedNames.ClearAndReserve(indices.Size()); + FOR_VECTOR (i, indices) + selectedNames.AddInReserved(GetItemRelPath(indices[i])); + + /* + for (int i = 0; i < _listView.GetItemCount(); i++) + { + const int kSize = 1024; + WCHAR name[kSize + 1]; + LVITEMW item; + item.iItem = i; + item.pszText = name; + item.cchTextMax = kSize; + item.iSubItem = 0; + item.mask = LVIF_TEXT | LVIF_PARAM; + if (!_listView.GetItem(&item)) + continue; + const unsigned realIndex = GetRealIndex(item); + if (realIndex == kParentIndex) + continue; + if (_selectedStatusVector[realIndex]) + selectedNames.Add(item.pszText); + } + */ + selectedNames.Sort(); +} + +void CPanel::SaveSelectedState(CSelectedState &s) +{ + s.FocusedName_Defined = false; + s.FocusedName.Empty(); + s.SelectFocused = true; // false; + s.SelectedNames.Clear(); + s.FocusedItem = _listView.GetFocusedItem(); + { + if (s.FocusedItem >= 0) + { + const unsigned realIndex = GetRealItemIndex(s.FocusedItem); + if (realIndex != kParentIndex) + { + s.FocusedName = GetItemRelPath(realIndex); + s.FocusedName_Defined = true; + + s.SelectFocused = _listView.IsItemSelected(s.FocusedItem); + + /* + const int kSize = 1024; + WCHAR name[kSize + 1]; + LVITEMW item; + item.iItem = focusedItem; + item.pszText = name; + item.cchTextMax = kSize; + item.iSubItem = 0; + item.mask = LVIF_TEXT; + if (_listView.GetItem(&item)) + focusedName = item.pszText; + */ + } + } + } + GetSelectedNames(s.SelectedNames); +} + +/* +HRESULT CPanel::RefreshListCtrl(const CSelectedState &s) +{ + bool selectFocused = s.SelectFocused; + if (_mySelectMode) + selectFocused = true; + return RefreshListCtrl2( + s.FocusedItem >= 0, // allowEmptyFocusedName + s.FocusedName, s.FocusedItem, selectFocused, s.SelectedNames); +} +*/ + +HRESULT CPanel::RefreshListCtrl_SaveFocused(bool onTimer) +{ + CSelectedState state; + SaveSelectedState(state); + state.CalledFromTimer = onTimer; + return RefreshListCtrl(state); +} + +void CPanel::SetFocusedSelectedItem(int index, bool select) +{ + UINT state = LVIS_FOCUSED; + if (select) + state |= LVIS_SELECTED; + _listView.SetItemState(index, state, state); + if (!_mySelectMode && select) + { + const unsigned realIndex = GetRealItemIndex(index); + if (realIndex != kParentIndex) + _selectedStatusVector[realIndex] = true; + } +} + +// #define PRINT_STAT + +#ifdef PRINT_STAT + void Print_OnNotify(const char *name); +#else + #define Print_OnNotify(x) +#endif + + + +/* + +extern UInt32 g_NumGroups; +extern DWORD g_start_tick; +extern DWORD g_prev_tick; +extern DWORD g_Num_SetItemText; +extern UInt32 g_NumMessages; +*/ + +HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) +{ + m_DropHighlighted_SelectionIndex = -1; + m_DropHighlighted_SubFolderName.Empty(); + + if (!_folder) + return S_OK; + + /* + g_start_tick = GetTickCount(); + g_Num_SetItemText = 0; + g_NumMessages = 0; + */ + + _dontShowMode = false; + if (!state.CalledFromTimer) + LoadFullPathAndShow(); + // OutputDebugStringA("=======\n"); + // OutputDebugStringA("s1 \n"); + CDisableTimerProcessing timerProcessing(*this); + CDisableNotify disableNotify(*this); + + int focusedPos = state.FocusedItem; + if (focusedPos < 0) + focusedPos = 0; + + _listView.SetRedraw(false); + // m_RedrawEnabled = false; + + LVITEMW item; + ZeroMemory(&item, sizeof(item)); + + // DWORD tickCount0 = GetTickCount(); + + // _enableItemChangeNotify = false; + DeleteListItems(); + _enableItemChangeNotify = true; + + int listViewItemCount = 0; + + _selectedStatusVector.Clear(); + // _realIndices.Clear(); + _startGroupSelect = 0; + + _selectionIsDefined = false; + + // m_Files.Clear(); + + /* + if (!_folder) + { + // throw 1; + SetToRootFolder(); + } + */ + + _headerToolBar.EnableButton(kParentFolderID, !IsRootFolder()); + + { + CMyComPtr folderSetFlatMode; + _folder.QueryInterface(IID_IFolderSetFlatMode, &folderSetFlatMode); + if (folderSetFlatMode) + folderSetFlatMode->SetFlatMode(BoolToInt(_flatMode)); + } + + /* + { + CMyComPtr setShow; + _folder.QueryInterface(IID_IFolderSetShowNtfsStreamsMode, &setShow); + if (setShow) + setShow->SetShowNtfsStreamsMode(BoolToInt(_showNtfsStrems_Mode)); + } + */ + + _isDirVector.Clear(); + // DWORD tickCount1 = GetTickCount(); + IFolderFolder *folder = _folder; + RINOK(_folder->LoadItems()) + // DWORD tickCount2 = GetTickCount(); + // OutputDebugString(TEXT("Start Dir\n")); + RINOK(InitColumns()) + + UInt32 numItems; + _folder->GetNumberOfItems(&numItems); + { + NCOM::CPropVariant prop; + _isDirVector.ClearAndSetSize(numItems); + bool *vec = _isDirVector.NonConstData(); + HRESULT hres = S_OK; + unsigned i; + for (i = 0; i < numItems; i++) + { + hres = folder->GetProperty(i, kpidIsDir, &prop); + if (hres != S_OK) + break; + bool v = false; + if (prop.vt == VT_BOOL) + v = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt != VT_EMPTY) + break; + vec[i] = v; + } + if (i != numItems) + { + _isDirVector.Clear(); + if (hres == S_OK) + hres = E_FAIL; + } + RINOK(hres) + } + + const bool showDots = _showDots && !IsRootFolder(); + + _listView.SetItemCount(numItems + (showDots ? 1 : 0)); + + _selectedStatusVector.ClearAndReserve(numItems); + int cursorIndex = -1; + + CMyComPtr folderGetSystemIconIndex; +#if 1 // 0 : for debug local icons loading + if (!Is_Slow_Icon_Folder() || _showRealFileIcons) + _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex); +#endif + + const bool isFSDrivesFolder = IsFSDrivesFolder(); + const bool isArcFolder = IsArcFolder(); + + if (!IsFSFolder()) + { + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + _thereAreDeletedItems = false; + if (getFolderArcProps) + { + CMyComPtr arcProps; + getFolderArcProps->GetFolderArcProps(&arcProps); + if (arcProps) + { + UInt32 numLevels; + if (arcProps->GetArcNumLevels(&numLevels) != S_OK) + numLevels = 0; + NCOM::CPropVariant prop; + if (arcProps->GetArcProp(numLevels - 1, kpidIsDeleted, &prop) == S_OK) + if (prop.vt == VT_BOOL && VARIANT_BOOLToBool(prop.boolVal)) + _thereAreDeletedItems = true; + } + } + } + + _thereAre_ListView_Items = true; + + // OutputDebugStringA("\n\n"); + + Print_OnNotify("===== Before Load"); + + // #define USE_EMBED_ITEM + + if (showDots) + { + const UString itemName (".."); + item.iItem = listViewItemCount; + if (itemName == state.FocusedName) + cursorIndex = listViewItemCount; + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + int subItem = 0; + item.iSubItem = subItem++; + item.lParam = (LPARAM)(int)kParentIndex; + #ifdef USE_EMBED_ITEM + item.pszText = const_cast((const wchar_t *)itemName); + #else + item.pszText = LPSTR_TEXTCALLBACKW; + #endif + // const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY; + item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR(); + // g_Ext_to_Icon_Map.GetIconIndex(attrib, itemName); + if (item.iImage < 0) + item.iImage = 0; + if (_listView.InsertItem(&item) == -1) + return E_FAIL; + listViewItemCount++; + } + + // OutputDebugStringA("S1\n"); + + UString correctedName; + UString itemName; + UString relPath; + + for (UInt32 i = 0; i < numItems; i++) + { + const wchar_t *name = NULL; + unsigned nameLen = 0; + + if (_folderGetItemName) + _folderGetItemName->GetItemName(i, &name, &nameLen); + if (!name) + { + GetItemName(i, itemName); + name = itemName; + nameLen = itemName.Len(); + } + + bool selected = false; + + if (state.FocusedName_Defined || !state.SelectedNames.IsEmpty()) + { + relPath.Empty(); + // relPath += GetItemPrefix(i); + if (_flatMode) + { + const wchar_t *prefix = NULL; + if (_folderGetItemName) + { + unsigned prefixLen = 0; + _folderGetItemName->GetItemPrefix(i, &prefix, &prefixLen); + if (prefix) + relPath = prefix; + } + if (!prefix) + { + NCOM::CPropVariant prop; + if (_folder->GetProperty(i, kpidPrefix, &prop) != S_OK) + throw 2723400; + if (prop.vt == VT_BSTR) + relPath.SetFromBstr(prop.bstrVal); + } + } + relPath += name; + if (relPath == state.FocusedName) + cursorIndex = listViewItemCount; + if (state.SelectedNames.FindInSorted(relPath) != -1) + selected = true; + } + + _selectedStatusVector.AddInReserved(selected); + + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + + if (!_mySelectMode) + if (selected) + { + item.mask |= LVIF_STATE; + item.state = LVIS_SELECTED; + } + + int subItem = 0; + item.iItem = listViewItemCount; + + item.iSubItem = subItem++; + item.lParam = (LPARAM)i; + + /* + int finish = nameLen - 4; + int j; + for (j = 0; j < finish; j++) + { + if (name[j ] == ' ' && + name[j + 1] == ' ' && + name[j + 2] == ' ' && + name[j + 3] == ' ' && + name[j + 4] == ' ') + break; + } + if (j < finish) + { + correctedName.Empty(); + correctedName = "virus"; + int pos = 0; + for (;;) + { + int posNew = itemName.Find(L" ", pos); + if (posNew < 0) + { + correctedName += itemName.Ptr(pos); + break; + } + correctedName += itemName.Mid(pos, posNew - pos); + correctedName += " ... "; + pos = posNew; + while (itemName[++pos] == ' '); + } + item.pszText = const_cast((const wchar_t *)correctedName); + } + else + */ + { + #ifdef USE_EMBED_ITEM + item.pszText = const_cast((const wchar_t *)name); + #else + item.pszText = LPSTR_TEXTCALLBACKW; + #endif + /* LPSTR_TEXTCALLBACKW works, but in some cases there are problems, + since we block notify handler. + LPSTR_TEXTCALLBACKW can be 2-3 times faster for loading in this loop. */ + } + + bool defined = false; + item.iImage = -1; + + if (folderGetSystemIconIndex) + { + const HRESULT res = folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage); + if (res == S_OK) + { + // item.iImage = -1; // for debug + defined = (item.iImage > 0); +#if 0 // 0: can be slower: 2 attempts for some paths. + // 1: faster, but we can get default icon for some cases (where non default icon is possible) + + if (item.iImage == 0) + { + // (item.iImage == 0) means default icon. + // But (item.iImage == 0) also can be returned for exe/ico files, + // if filePath is LONG PATH (path_len() >= MAX_PATH). + // Also we want to show split icon (.001) for any split extension: 001 002 003. + // Are there another cases for (item.iImage == 0) for files with known extensions? + // We don't want to do second attempt to request icon, + // if it also will return (item.iImage == 0). + + int dotPos = -1; + for (unsigned k = 0;; k++) + { + const wchar_t c = name[k]; + if (c == 0) + break; + if (c == '.') + dotPos = (int)i; + // we don't need IS_PATH_SEPAR check, because we have only (fileName) doesn't include path prefix. + // if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1; + } + defined = true; + if (dotPos >= 0) + { +#if 0 + const wchar_t *ext = name + dotPos; + if (StringsAreEqualNoCase_Ascii(ext, ".exe") || + StringsAreEqualNoCase_Ascii(ext, ".ico")) +#endif + defined = false; + } + } +#endif + } + } + + if (!defined) + { + UInt32 attrib = 0; + { + NCOM::CPropVariant prop; + RINOK(_folder->GetProperty(i, kpidAttrib, &prop)) + if (prop.vt == VT_UI4) + { + attrib = prop.ulVal; + if (isArcFolder) + { + // if attrib (high 16-bits) is supposed from posix, + // we keep only low bits (basic Windows attrib flags): + if (attrib & 0xF0000000) + attrib &= 0x3FFF; + } + } + } + if (IsItem_Folder(i)) + attrib |= FILE_ATTRIBUTE_DIRECTORY; + else + attrib &= ~(UInt32)FILE_ATTRIBUTE_DIRECTORY; + + item.iImage = -1; + if (isFSDrivesFolder) + { + FString fs (us2fs((UString)name)); + fs.Add_PathSepar(); + item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(fs, attrib); + // item.iImage = 0; // for debug + } + if (item.iImage < 0) // <= 0 check? + item.iImage = g_Ext_to_Icon_Map.GetIconIndex(attrib, name); + } + + // item.iImage = -1; // for debug + if (item.iImage < 0) + item.iImage = 0; // default image + if (_listView.InsertItem(&item) == -1) + return E_FAIL; + listViewItemCount++; + } + + /* + xp-64: there is different order when Windows calls CPanel::OnNotify for _listView modes: + Details : after whole code + List : 2 times: + 1) - ListView.SotRedraw() + 2) - after whole code + Small Icons : + Large icons : 2 times: + 1) - ListView.Sort() + 2) - after whole code (calls with reverse order of items) + + So we need to allow Notify(), when windows requests names during the following code. + */ + + Print_OnNotify("after Load"); + + disableNotify.SetMemMode_Enable(); + disableNotify.Restore(); + + if (_listView.GetItemCount() > 0 && cursorIndex >= 0) + SetFocusedSelectedItem(cursorIndex, state.SelectFocused); + + Print_OnNotify("after SetFocusedSelectedItem"); + + SetSortRawStatus(); + _listView.SortItems(CompareItems, (LPARAM)this); + + Print_OnNotify("after Sort"); + + if (cursorIndex < 0 && _listView.GetItemCount() > 0) + { + if (focusedPos >= _listView.GetItemCount()) + focusedPos = _listView.GetItemCount() - 1; + // we select item only in showDots mode. + SetFocusedSelectedItem(focusedPos, showDots && (focusedPos == 0)); + } + + // m_RedrawEnabled = true; + + Print_OnNotify("after SetFocusedSelectedItem2"); + + _listView.EnsureVisible(_listView.GetFocusedItem(), false); + + // disableNotify.SetMemMode_Enable(); + // disableNotify.Restore(); + + Print_OnNotify("after EnsureVisible"); + + _listView.SetRedraw(true); + + Print_OnNotify("after SetRedraw"); + + _listView.InvalidateRect(NULL, true); + + Print_OnNotify("after InvalidateRect"); + /* + _listView.UpdateWindow(); + */ + Refresh_StatusBar(); + /* + char s[256]; + sprintf(s, + // "attribMap = %5d, extMap = %5d, " + "delete = %5d, load = %5d, list = %5d, sort = %5d, end = %5d", + // g_Ext_to_Icon_Map._attribMap.Size(), + // g_Ext_to_Icon_Map._extMap.Size(), + tickCount1 - tickCount0, + tickCount2 - tickCount1, + tickCount3 - tickCount2, + tickCount4 - tickCount3, + tickCount5 - tickCount4 + ); + sprintf(s, + "5 = %5d, 6 = %5d, 7 = %5d, 8 = %5d, 9 = %5d", + tickCount5 - tickCount4, + tickCount6 - tickCount5, + tickCount7 - tickCount6, + tickCount8 - tickCount7, + tickCount9 - tickCount8 + ); + OutputDebugStringA(s); + */ + return S_OK; +} + + +void CPanel::Get_ItemIndices_Selected(CRecordVector &indices) const +{ + indices.Clear(); + /* + int itemIndex = -1; + while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1) + { + LPARAM param; + if (_listView.GetItemParam(itemIndex, param)) + indices.Add(param); + } + HeapSort(&indices.Front(), indices.Size()); + */ + const bool *v = _selectedStatusVector.ConstData(); + const unsigned size = _selectedStatusVector.Size(); + for (unsigned i = 0; i < size; i++) + if (v[i]) + indices.Add(i); +} + + +void CPanel::Get_ItemIndices_Operated(CRecordVector &indices) const +{ + Get_ItemIndices_Selected(indices); + if (!indices.IsEmpty()) + return; + if (_listView.GetSelectedCount() == 0) + return; + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem >= 0) + { + if (_listView.IsItemSelected(focusedItem)) + { + const unsigned realIndex = GetRealItemIndex(focusedItem); + if (realIndex != kParentIndex) + indices.Add(realIndex); + } + } +} + +void CPanel::Get_ItemIndices_All(CRecordVector &indices) const +{ + indices.Clear(); + UInt32 numItems; + if (_folder->GetNumberOfItems(&numItems) != S_OK) + return; + indices.ClearAndSetSize(numItems); + UInt32 *vec = indices.NonConstData(); + for (UInt32 i = 0; i < numItems; i++) + vec[i] = i; +} + +void CPanel::Get_ItemIndices_OperSmart(CRecordVector &indices) const +{ + Get_ItemIndices_Operated(indices); + if (indices.IsEmpty() || (indices.Size() == 1 && indices[0] == (UInt32)(Int32)-1)) + Get_ItemIndices_All(indices); +} + +/* +void CPanel::GetOperatedListViewIndices(CRecordVector &indices) const +{ + indices.Clear(); + int numItems = _listView.GetItemCount(); + for (int i = 0; i < numItems; i++) + { + const unsigned realIndex = GetRealItemIndex(i); + if (realIndex >= 0) + if (_selectedStatusVector[realIndex]) + indices.Add(i); + } + if (indices.IsEmpty()) + { + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem >= 0) + indices.Add(focusedItem); + } +} +*/ + +void CPanel::EditItem(bool useEditor) +{ + if (!useEditor) + { + CMyComPtr calcItemFullSize; + _folder.QueryInterface(IID_IFolderCalcItemFullSize, &calcItemFullSize); + if (calcItemFullSize) + { + bool needRefresh = false; + CRecordVector indices; + Get_ItemIndices_Operated(indices); + FOR_VECTOR (i, indices) + { + UInt32 index = indices[i]; + if (IsItem_Folder(index)) + { + calcItemFullSize->CalcItemFullSize(index, NULL); + needRefresh = true; + } + } + if (needRefresh) + { + // _listView.RedrawItem(0); + // _listView.RedrawAllItems(); + InvalidateList(); + return; + } + } + } + + + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const unsigned realIndex = GetRealItemIndex(focusedItem); + if (realIndex == kParentIndex) + return; + if (!IsItem_Folder(realIndex)) + EditItem(realIndex, useEditor); +} + +void CPanel::OpenFocusedItemAsInternal(const wchar_t *type) +{ + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const unsigned realIndex = GetRealItemIndex(focusedItem); + if (IsItem_Folder(realIndex)) + OpenFolder(realIndex); + else + OpenItem(realIndex, true, false, type); +} + +void CPanel::OpenSelectedItems(bool tryInternal) +{ + CRecordVector indices; + Get_ItemIndices_Operated(indices); + if (indices.Size() > 20) + { + MessageBox_Error_LangID(IDS_TOO_MANY_ITEMS); + return; + } + + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem >= 0) + { + const unsigned realIndex = GetRealItemIndex(focusedItem); + if (realIndex == kParentIndex && (tryInternal || indices.Size() == 0) && _listView.IsItemSelected(focusedItem)) + indices.Insert(0, realIndex); + } + + bool dirIsStarted = false; + FOR_VECTOR (i, indices) + { + UInt32 index = indices[i]; + // CFileInfo &aFile = m_Files[index]; + if (IsItem_Folder(index)) + { + if (!dirIsStarted) + { + if (tryInternal) + { + OpenFolder(index); + dirIsStarted = true; + break; + } + else + OpenFolderExternal(index); + } + } + else + OpenItem(index, (tryInternal && indices.Size() == 1), true); + } +} + +UString CPanel::GetItemName(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return L".."; + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) + throw 2723400; + if (prop.vt != VT_BSTR) + throw 2723401; + return prop.bstrVal; +} + +UString CPanel::GetItemName_for_Copy(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return L".."; + UString s; + { + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidOutName, &prop) == S_OK) + { + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + else if (prop.vt != VT_EMPTY) + throw 2723401; + } + if (s.IsEmpty()) + s = GetItemName(itemIndex); + } + return Get_Correct_FsFile_Name(s); +} + +void CPanel::GetItemName(unsigned itemIndex, UString &s) const +{ + if (itemIndex == kParentIndex) + { + s = ".."; + return; + } + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) + throw 2723400; + if (prop.vt != VT_BSTR) + throw 2723401; + s.SetFromBstr(prop.bstrVal); +} + +UString CPanel::GetItemPrefix(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return UString(); + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK) + throw 2723400; + UString prefix; + if (prop.vt == VT_BSTR) + prefix.SetFromBstr(prop.bstrVal); + return prefix; +} + +UString CPanel::GetItemRelPath(unsigned itemIndex) const +{ + return GetItemPrefix(itemIndex) + GetItemName(itemIndex); +} + +UString CPanel::GetItemRelPath2(unsigned itemIndex) const +{ + UString s = GetItemRelPath(itemIndex); + #if defined(_WIN32) && !defined(UNDER_CE) + if (s.Len() == 2 && NFile::NName::IsDrivePath2(s)) + { + if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()) + s.Add_PathSepar(); + } + #endif + return s; +} + + +void CPanel::Add_ItemRelPath2_To_String(unsigned itemIndex, UString &s) const +{ + if (itemIndex == kParentIndex) + { + s += ".."; + return; + } + + const unsigned start = s.Len(); + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK) + throw 2723400; + if (prop.vt == VT_BSTR) + s += prop.bstrVal; + + const wchar_t *name = NULL; + unsigned nameLen = 0; + + if (_folderGetItemName) + _folderGetItemName->GetItemName(itemIndex, &name, &nameLen); + if (name) + s += name; + else + { + prop.Clear(); + if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK) + throw 2723400; + if (prop.vt != VT_BSTR) + throw 2723401; + s += prop.bstrVal; + } + + #if defined(_WIN32) && !defined(UNDER_CE) + if (s.Len() - start == 2 && NFile::NName::IsDrivePath2(s.Ptr(start))) + { + if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()) + s.Add_PathSepar(); + } + #endif +} + + +UString CPanel::GetItemFullPath(unsigned itemIndex) const +{ + return GetFsPath() + GetItemRelPath2(itemIndex); +} + +bool CPanel::GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const +{ + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, propID, &prop) != S_OK) + throw 2723400; + if (prop.vt == VT_BOOL) + return VARIANT_BOOLToBool(prop.boolVal); + if (prop.vt == VT_EMPTY) + return false; + throw 2723401; +} + +bool CPanel::IsItem_Deleted(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return false; + return GetItem_BoolProp(itemIndex, kpidIsDeleted); +} + +bool CPanel::IsItem_Folder(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return true; + if (itemIndex < _isDirVector.Size()) + return _isDirVector[itemIndex]; + return GetItem_BoolProp(itemIndex, kpidIsDir); +} + +bool CPanel::IsItem_AltStream(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return false; + return GetItem_BoolProp(itemIndex, kpidIsAltStream); +} + +UInt64 CPanel::GetItem_UInt64Prop(unsigned itemIndex, PROPID propID) const +{ + if (itemIndex == kParentIndex) + return 0; + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, propID, &prop) != S_OK) + throw 2723400; + UInt64 val = 0; + if (ConvertPropVariantToUInt64(prop, val)) + return val; + return 0; +} + +UInt64 CPanel::GetItemSize(unsigned itemIndex) const +{ + if (itemIndex == kParentIndex) + return 0; + if (_folderGetItemName) + return _folderGetItemName->GetItemSize(itemIndex); + return GetItem_UInt64Prop(itemIndex, kpidSize); +} + +void CPanel::SaveListViewInfo() +{ + if (!_needSaveInfo) + return; + + unsigned i; + + for (i = 0; i < _visibleColumns.Size(); i++) + { + CPropColumn &prop = _visibleColumns[i]; + LVCOLUMN winColumnInfo; + winColumnInfo.mask = LVCF_ORDER | LVCF_WIDTH; + if (!_listView.GetColumn(i, &winColumnInfo)) + throw 1; + prop.Order = winColumnInfo.iOrder; + prop.Width = (UInt32)(Int32)winColumnInfo.cx; + } + + CListViewInfo viewInfo; + + // PROPID sortPropID = _columns[_sortIndex].ID; + const PROPID sortPropID = _sortID; + + // we save columns as "sorted by order" to registry + + CPropColumns sortedProperties = _visibleColumns; + + sortedProperties.Sort(); + + for (i = 0; i < sortedProperties.Size(); i++) + { + const CPropColumn &prop = sortedProperties[i]; + CColumnInfo columnInfo; + columnInfo.IsVisible = prop.IsVisible; + columnInfo.PropID = prop.ID; + columnInfo.Width = prop.Width; + viewInfo.Columns.Add(columnInfo); + } + + for (i = 0; i < _columns.Size(); i++) + { + const CPropColumn &prop = _columns[i]; + if (sortedProperties.FindItem_for_PropID(prop.ID) < 0) + { + CColumnInfo columnInfo; + columnInfo.IsVisible = false; + columnInfo.PropID = prop.ID; + columnInfo.Width = prop.Width; + viewInfo.Columns.Add(columnInfo); + } + } + + viewInfo.SortID = sortPropID; + viewInfo.Ascending = _ascending; + viewInfo.IsLoaded = true; + if (!_listViewInfo.IsEqual(viewInfo)) + { + viewInfo.Save(_typeIDString); + _listViewInfo = viewInfo; + } +} + + +bool CPanel::OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result) +{ + if (itemActivate->hdr.hwndFrom == HWND(_listView)) + return false; + POINT point; + ::GetCursorPos(&point); + ShowColumnsContextMenu(point.x, point.y); + result = TRUE; + return true; +} + +void CPanel::ShowColumnsContextMenu(int x, int y) +{ + CMenu menu; + CMenuDestroyer menuDestroyer(menu); + + menu.CreatePopup(); + + const int kCommandStart = 100; + FOR_VECTOR (i, _columns) + { + const CPropColumn &prop = _columns[i]; + UINT flags = MF_STRING; + if (prop.IsVisible) + flags |= MF_CHECKED; + if (i == 0) + flags |= MF_GRAYED; + menu.AppendItem(flags, kCommandStart + i, prop.Name); + } + + const int menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, x, y, _listView); + + if (menuResult >= kCommandStart && menuResult <= kCommandStart + (int)_columns.Size()) + { + const unsigned index = (unsigned)(menuResult - kCommandStart); + CPropColumn &prop = _columns[index]; + prop.IsVisible = !prop.IsVisible; + + if (prop.IsVisible) + { + prop.Order = (int)_visibleColumns.Size(); + AddColumn(prop); + } + else + { + const int visibleIndex = _visibleColumns.FindItem_for_PropID(prop.ID); + if (visibleIndex >= 0) + { + /* + if (_sortIndex == index) + { + _sortIndex = 0; + _ascending = true; + } + */ + if (_sortID == prop.ID) + { + _sortID = kpidName; + _ascending = true; + } + DeleteColumn((unsigned)visibleIndex); + } + } + } +} + +void CPanel::OnReload(bool onTimer) +{ + const HRESULT res = RefreshListCtrl_SaveFocused(onTimer); + if (res != S_OK) + MessageBox_Error_HRESULT(res); +} + +void CPanel::OnTimer() +{ + if (!_processTimer) + return; + if (!AutoRefresh_Mode) + return; + if (!_folder) // it's unexpected case, but we use it as additional protection. + return; + { + CMyComPtr folderWasChanged; + _folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged); + if (!folderWasChanged) + return; + Int32 wasChanged; + if (folderWasChanged->WasChanged(&wasChanged) != S_OK || wasChanged == 0) + return; + } + OnReload(true); // onTimer +} diff --git a/CPP/7zip/UI/FileManager/PanelKey.cpp b/CPP/7zip/UI/FileManager/PanelKey.cpp index d29fe62c5..a4ea489ae 100644 --- a/CPP/7zip/UI/FileManager/PanelKey.cpp +++ b/CPP/7zip/UI/FileManager/PanelKey.cpp @@ -1,357 +1,357 @@ -// PanelKey.cpp - -#include "StdAfx.h" - -#include "Panel.h" -#include "HelpUtils.h" - -#include "../../PropID.h" -#include "App.h" - -using namespace NWindows; - -// #define kHelpTopic "FM/index.htm" - -struct CVKeyPropIDPair -{ - WORD VKey; - PROPID PropID; -}; - -static const CVKeyPropIDPair g_VKeyPropIDPairs[] = -{ - { VK_F3, kpidName }, - { VK_F4, kpidExtension }, - { VK_F5, kpidMTime }, - { VK_F6, kpidSize }, - { VK_F7, kpidNoProperty } -}; - -static int FindVKeyPropIDPair(WORD vKey) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_VKeyPropIDPairs); i++) - if (g_VKeyPropIDPairs[i].VKey == vKey) - return (int)i; - return -1; -} - - -bool CPanel::OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result) -{ - if (keyDownInfo->wVKey == VK_TAB && keyDownInfo->hdr.hwndFrom == _listView) - { - _panelCallback->OnTab(); - return false; - } - const bool alt = IsKeyDown(VK_MENU); - const bool ctrl = IsKeyDown(VK_CONTROL); - // const bool leftCtrl = IsKeyDown(VK_LCONTROL); - const bool rightCtrl = IsKeyDown(VK_RCONTROL); - const bool shift = IsKeyDown(VK_SHIFT); - result = 0; - - if (keyDownInfo->wVKey >= '0' && - keyDownInfo->wVKey <= '9' && - (rightCtrl || alt)) - { - const unsigned index = (unsigned)(keyDownInfo->wVKey - '0'); - if (shift) - { - SetBookmark(index); - return true; - } - else - { - OpenBookmark(index); - return true; - } - } - - if ((keyDownInfo->wVKey == VK_F2 || - keyDownInfo->wVKey == VK_F1) - && alt && !ctrl && !shift) - { - _panelCallback->SetFocusToPath(keyDownInfo->wVKey == VK_F1 ? 0 : 1); - return true; - } - - if ((keyDownInfo->wVKey == VK_F9) && !alt && !ctrl && !shift) - { - g_App.SwitchOnOffOnePanel(); - } - - if (keyDownInfo->wVKey >= VK_F3 && keyDownInfo->wVKey <= VK_F12 && ctrl) - { - const int index = FindVKeyPropIDPair(keyDownInfo->wVKey); - if (index >= 0) - SortItemsWithPropID(g_VKeyPropIDPairs[index].PropID); - } - - switch (keyDownInfo->wVKey) - { - case VK_SHIFT: - { - _selectionIsDefined = false; - _prevFocusedItem = _listView.GetFocusedItem(); - break; - } - /* - case VK_F1: - { - // ShowHelpWindow(NULL, kHelpTopic); - break; - } - */ - case VK_F2: - { - if (!alt && !ctrl &&!shift) - { - RenameFile(); - return true; - } - break; - } - case VK_F3: - { - if (!alt && !ctrl && !shift) - { - EditItem(false); - return true; - } - break; - } - case VK_F4: - { - if (!alt && !ctrl && !shift) - { - EditItem(true); - return true; - } - if (!alt && !ctrl && shift) - { - CreateFile(); - return true; - } - break; - } - case VK_F5: - { - if (!alt && !ctrl) - { - _panelCallback->OnCopy(false, shift); - return true; - } - break; - } - case VK_F6: - { - if (!alt && !ctrl) - { - _panelCallback->OnCopy(true, shift); - return true; - } - break; - } - case VK_F7: - { - if (!alt && !ctrl && !shift) - { - /* we can process F7 via menu ACCELERATOR. - But menu loading can be slow in case of UNC paths and system menu. - So we use don't use ACCELERATOR */ - CreateFolder(); - return true; - } - break; - } - case VK_DELETE: - { - DeleteItems(!shift); - return true; - } - case VK_INSERT: - { - if (!alt) - { - if (ctrl && !shift) - { - EditCopy(); - return true; - } - if (shift && !ctrl) - { - EditPaste(); - return true; - } - if (!shift && !ctrl && _mySelectMode) - { - OnInsert(); - return true; - } - } - return false; - } - case VK_DOWN: - { - if (shift) - OnArrowWithShift(); - return false; - } - case VK_UP: - { - if (alt) - _panelCallback->OnSetSameFolder(); - else if (shift) - OnArrowWithShift(); - return false; - } - case VK_RIGHT: - { - if (alt) - _panelCallback->OnSetSubFolder(); - else if (shift) - OnArrowWithShift(); - return false; - } - case VK_LEFT: - { - if (alt) - _panelCallback->OnSetSubFolder(); - else if (shift) - OnArrowWithShift(); - return false; - } - case VK_NEXT: - { - if (ctrl && !alt && !shift) - { - // EnterToFocused(); - return true; - } - break; - } - case VK_ADD: - { - if (alt) - SelectByType(true); - else if (shift) - SelectAll(true); - else if (!ctrl) - SelectSpec(true); - return true; - } - case VK_SUBTRACT: - { - if (alt) - SelectByType(false); - else if (shift) - SelectAll(false); - else - SelectSpec(false); - return true; - } - /* - case VK_DELETE: - CommandDelete(); - return 0; - case VK_F1: - CommandHelp(); - return 0; - */ - case VK_BACK: - OpenParentFolder(); - return true; - /* - case VK_DIVIDE: - case '\\': - case '/': - case VK_OEM_5: - { - // OpenRootFolder(); - OpenDrivesFolder(); - - return true; - } - */ - case 'A': - if (ctrl) - { - SelectAll(true); - return true; - } - return false; - case 'X': - if (ctrl) - { - EditCut(); - return true; - } - return false; - case 'C': - if (ctrl) - { - EditCopy(); - return true; - } - return false; - case 'V': - if (ctrl) - { - EditPaste(); - return true; - } - return false; - case 'N': - if (ctrl) - { - CreateFile(); - return true; - } - return false; - case 'R': - if (ctrl) - { - OnReload(); - return true; - } - return false; - case 'W': - if (ctrl) - { - // SendMessage(); - PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0); - return true; - } - return false; - case 'Z': - if (ctrl) - { - ChangeComment(); - return true; - } - return false; - case '1': - case '2': - case '3': - case '4': - if (ctrl) - { - const unsigned styleIndex = (unsigned)(keyDownInfo->wVKey - '1'); - SetListViewMode(styleIndex); - return true; - } - return false; - case VK_MULTIPLY: - { - InvertSelection(); - return true; - } - case VK_F12: - if (alt && !ctrl && !shift) - { - FoldersHistory(); - return true; - } - } - return false; -} +// PanelKey.cpp + +#include "StdAfx.h" + +#include "Panel.h" +#include "HelpUtils.h" + +#include "../../PropID.h" +#include "App.h" + +using namespace NWindows; + +// #define kHelpTopic "FM/index.htm" + +struct CVKeyPropIDPair +{ + WORD VKey; + PROPID PropID; +}; + +static const CVKeyPropIDPair g_VKeyPropIDPairs[] = +{ + { VK_F3, kpidName }, + { VK_F4, kpidExtension }, + { VK_F5, kpidMTime }, + { VK_F6, kpidSize }, + { VK_F7, kpidNoProperty } +}; + +static int FindVKeyPropIDPair(WORD vKey) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_VKeyPropIDPairs); i++) + if (g_VKeyPropIDPairs[i].VKey == vKey) + return (int)i; + return -1; +} + + +bool CPanel::OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result) +{ + if (keyDownInfo->wVKey == VK_TAB && keyDownInfo->hdr.hwndFrom == _listView) + { + _panelCallback->OnTab(); + return false; + } + const bool alt = IsKeyDown(VK_MENU); + const bool ctrl = IsKeyDown(VK_CONTROL); + // const bool leftCtrl = IsKeyDown(VK_LCONTROL); + const bool rightCtrl = IsKeyDown(VK_RCONTROL); + const bool shift = IsKeyDown(VK_SHIFT); + result = 0; + + if (keyDownInfo->wVKey >= '0' && + keyDownInfo->wVKey <= '9' && + (rightCtrl || alt)) + { + const unsigned index = (unsigned)(keyDownInfo->wVKey - '0'); + if (shift) + { + SetBookmark(index); + return true; + } + else + { + OpenBookmark(index); + return true; + } + } + + if ((keyDownInfo->wVKey == VK_F2 || + keyDownInfo->wVKey == VK_F1) + && alt && !ctrl && !shift) + { + _panelCallback->SetFocusToPath(keyDownInfo->wVKey == VK_F1 ? 0 : 1); + return true; + } + + if ((keyDownInfo->wVKey == VK_F9) && !alt && !ctrl && !shift) + { + g_App.SwitchOnOffOnePanel(); + } + + if (keyDownInfo->wVKey >= VK_F3 && keyDownInfo->wVKey <= VK_F12 && ctrl) + { + const int index = FindVKeyPropIDPair(keyDownInfo->wVKey); + if (index >= 0) + SortItemsWithPropID(g_VKeyPropIDPairs[index].PropID); + } + + switch (keyDownInfo->wVKey) + { + case VK_SHIFT: + { + _selectionIsDefined = false; + _prevFocusedItem = _listView.GetFocusedItem(); + break; + } + /* + case VK_F1: + { + // ShowHelpWindow(NULL, kHelpTopic); + break; + } + */ + case VK_F2: + { + if (!alt && !ctrl &&!shift) + { + RenameFile(); + return true; + } + break; + } + case VK_F3: + { + if (!alt && !ctrl && !shift) + { + EditItem(false); + return true; + } + break; + } + case VK_F4: + { + if (!alt && !ctrl && !shift) + { + EditItem(true); + return true; + } + if (!alt && !ctrl && shift) + { + CreateFile(); + return true; + } + break; + } + case VK_F5: + { + if (!alt && !ctrl) + { + _panelCallback->OnCopy(false, shift); + return true; + } + break; + } + case VK_F6: + { + if (!alt && !ctrl) + { + _panelCallback->OnCopy(true, shift); + return true; + } + break; + } + case VK_F7: + { + if (!alt && !ctrl && !shift) + { + /* we can process F7 via menu ACCELERATOR. + But menu loading can be slow in case of UNC paths and system menu. + So we use don't use ACCELERATOR */ + CreateFolder(); + return true; + } + break; + } + case VK_DELETE: + { + DeleteItems(!shift); + return true; + } + case VK_INSERT: + { + if (!alt) + { + if (ctrl && !shift) + { + EditCopy(); + return true; + } + if (shift && !ctrl) + { + EditPaste(); + return true; + } + if (!shift && !ctrl && _mySelectMode) + { + OnInsert(); + return true; + } + } + return false; + } + case VK_DOWN: + { + if (shift) + OnArrowWithShift(); + return false; + } + case VK_UP: + { + if (alt) + _panelCallback->OnSetSameFolder(); + else if (shift) + OnArrowWithShift(); + return false; + } + case VK_RIGHT: + { + if (alt) + _panelCallback->OnSetSubFolder(); + else if (shift) + OnArrowWithShift(); + return false; + } + case VK_LEFT: + { + if (alt) + _panelCallback->OnSetSubFolder(); + else if (shift) + OnArrowWithShift(); + return false; + } + case VK_NEXT: + { + if (ctrl && !alt && !shift) + { + // EnterToFocused(); + return true; + } + break; + } + case VK_ADD: + { + if (alt) + SelectByType(true); + else if (shift) + SelectAll(true); + else if (!ctrl) + SelectSpec(true); + return true; + } + case VK_SUBTRACT: + { + if (alt) + SelectByType(false); + else if (shift) + SelectAll(false); + else + SelectSpec(false); + return true; + } + /* + case VK_DELETE: + CommandDelete(); + return 0; + case VK_F1: + CommandHelp(); + return 0; + */ + case VK_BACK: + OpenParentFolder(); + return true; + /* + case VK_DIVIDE: + case '\\': + case '/': + case VK_OEM_5: + { + // OpenRootFolder(); + OpenDrivesFolder(); + + return true; + } + */ + case 'A': + if (ctrl) + { + SelectAll(true); + return true; + } + return false; + case 'X': + if (ctrl) + { + EditCut(); + return true; + } + return false; + case 'C': + if (ctrl) + { + EditCopy(); + return true; + } + return false; + case 'V': + if (ctrl) + { + EditPaste(); + return true; + } + return false; + case 'N': + if (ctrl) + { + CreateFile(); + return true; + } + return false; + case 'R': + if (ctrl) + { + OnReload(); + return true; + } + return false; + case 'W': + if (ctrl) + { + // SendMessage(); + PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0); + return true; + } + return false; + case 'Z': + if (ctrl) + { + ChangeComment(); + return true; + } + return false; + case '1': + case '2': + case '3': + case '4': + if (ctrl) + { + const unsigned styleIndex = (unsigned)(keyDownInfo->wVKey - '1'); + SetListViewMode(styleIndex); + return true; + } + return false; + case VK_MULTIPLY: + { + InvertSelection(); + return true; + } + case VK_F12: + if (alt && !ctrl && !shift) + { + FoldersHistory(); + return true; + } + } + return false; +} diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp index 2652a98f7..05ab36bcd 100644 --- a/CPP/7zip/UI/FileManager/PanelListNotify.cpp +++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp @@ -1,838 +1,838 @@ -// PanelListNotify.cpp - -#include "StdAfx.h" - -#include "resource.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../Common/PropIDUtils.h" -#include "../../PropID.h" - -#include "App.h" -#include "Panel.h" -#include "FormatUtils.h" - -using namespace NWindows; - -/* Unicode characters for space: -0x009C STRING TERMINATOR -0x00B7 Middle dot -0x237D Shouldered open box -0x2420 Symbol for space -0x2422 Blank symbol -0x2423 Open box -*/ - -#define SPACE_REPLACE_CHAR (wchar_t)(0x2423) -#define SPACE_TERMINATOR_CHAR (wchar_t)(0x9C) - -#define INT_TO_STR_SPEC(v) \ - while (v >= 10) { temp[i++] = (Byte)('0' + (unsigned)(v % 10)); v /= 10; } \ - *s++ = (Byte)('0' + (unsigned)v); - -static void ConvertSizeToString(UInt64 val, wchar_t *s) throw() -{ - Byte temp[32]; - unsigned i = 0; - - if (val <= (UInt32)0xFFFFFFFF) - { - UInt32 val32 = (UInt32)val; - INT_TO_STR_SPEC(val32) - } - else - { - INT_TO_STR_SPEC(val) - } - - if (i < 3) - { - if (i != 0) - { - *s++ = temp[(size_t)i - 1]; - if (i == 2) - *s++ = temp[0]; - } - *s = 0; - return; - } - - unsigned r = i % 3; - if (r != 0) - { - s[0] = temp[--i]; - if (r == 2) - s[1] = temp[--i]; - s += r; - } - - do - { - s[0] = ' '; - s[1] = temp[(size_t)i - 1]; - s[2] = temp[(size_t)i - 2]; - s[3] = temp[(size_t)i - 3]; - s += 4; - } - while (i -= 3); - - *s = 0; -} - -UString ConvertSizeToString(UInt64 value); -UString ConvertSizeToString(UInt64 value) -{ - wchar_t s[32]; - ConvertSizeToString(value, s); - return s; -} - -bool IsSizeProp(UINT propID) throw(); -bool IsSizeProp(UINT propID) throw() -{ - switch (propID) - { - case kpidSize: - case kpidPackSize: - case kpidNumSubDirs: - case kpidNumSubFiles: - case kpidOffset: - case kpidLinks: - case kpidNumBlocks: - case kpidNumVolumes: - case kpidPhySize: - case kpidHeadersSize: - case kpidTotalSize: - case kpidFreeSpace: - case kpidClusterSize: - case kpidNumErrors: - case kpidNumStreams: - case kpidNumAltStreams: - case kpidAltStreamsSize: - case kpidVirtualSize: - case kpidUnpackSize: - case kpidTotalPhySize: - case kpidTailSize: - case kpidEmbeddedStubSize: - return true; - } - return false; -} - - - -/* -#include - -UInt64 GetCpuTicks() -{ - #ifdef _WIN64 - return __rdtsc(); - #else - UInt32 lowVal, highVal; - __asm RDTSC; - __asm mov lowVal, EAX; - __asm mov highVal, EDX; - return ((UInt64)highVal << 32) | lowVal; - #endif -} - -UInt32 g_NumGroups; -UInt64 g_start_tick; -UInt64 g_prev_tick; -DWORD g_Num_SetItemText; -UInt32 g_NumMessages; -*/ - -LRESULT CPanel::SetItemText(LVITEMW &item) -{ - if (_dontShowMode) - return 0; - UInt32 realIndex = GetRealIndex(item); - - // g_Num_SetItemText++; - - /* - if ((item.mask & LVIF_IMAGE) != 0) - { - bool defined = false; - CComPtr folderGetSystemIconIndex; - _folder.QueryInterface(&folderGetSystemIconIndex); - if (folderGetSystemIconIndex) - { - folderGetSystemIconIndex->GetSystemIconIndex(index, &item.iImage); - defined = (item.iImage > 0); - } - if (!defined) - { - NCOM::CPropVariant prop; - _folder->GetProperty(index, kpidAttrib, &prop); - UINT32 attrib = 0; - if (prop.vt == VT_UI4) - attrib = prop.ulVal; - else if (IsItemFolder(index)) - attrib |= FILE_ATTRIBUTE_DIRECTORY; - if (_currentFolderPrefix.IsEmpty()) - throw 1; - else - item.iImage = _extToIconMap.GetIconIndex(attrib, GetSystemString(GetItemName(index))); - } - // item.iImage = 1; - } - */ - - if ((item.mask & LVIF_TEXT) == 0) - return 0; - - LPWSTR text = item.pszText; - - if (item.cchTextMax > 0) - text[0] = 0; - - if (item.cchTextMax <= 1) - return 0; - - // item.cchTextMax > 1 - - const CPropColumn &property = _visibleColumns[item.iSubItem]; - PROPID propID = property.ID; - - if (realIndex == kParentIndex_UInt32) - { - if (propID == kpidName) - { - if (item.cchTextMax > 2) - { - text[0] = '.'; - text[1] = '.'; - text[2] = 0; - } - } - return 0; - } - - /* - // List-view in report-view in Windows 10 is slow (50+ ms) for page change. - // that code shows the time of page reload for items - // if you know how to improve the speed of list view refresh, notify 7-Zip developer - - // if (propID == 2000) - // if (propID == kpidName) - { - // debug column; - // DWORD dw = GetCpuTicks(); - UInt64 dw = GetCpuTicks(); - UInt64 deltaLast = dw - g_prev_tick; - #define conv_ticks(t) ((unsigned)((t) / 100000)) - if (deltaLast > 1000u * 1000 * 1000) - { - UInt64 deltaFull = g_prev_tick - g_start_tick; - char s[128]; - sprintf(s, "%d", conv_ticks(deltaFull)); - OutputDebugStringA(s); - g_start_tick = dw; - g_NumGroups++; - } - g_prev_tick = dw; - UString u; - char s[128]; - UInt64 deltaFull = dw - g_start_tick; - // for (int i = 0; i < 100000; i++) - sprintf(s, "%d %d %d-%d ", g_NumMessages, g_Num_SetItemText, g_NumGroups, conv_ticks(deltaFull)); - // sprintf(s, "%d-%d ", g_NumGroups, conv_ticks(deltaFull)); - u = s; - lstrcpyW(text, u.Ptr()); - text += u.Len(); - - // dw = GetCpuTicks(); - // deltaFull = dw - g_prev_tick; - // sprintf(s, "-%d ", conv_ticks(deltaFull)); - // u = s; - // lstrcpyW(text, u.Ptr()); - // text += u.Len(); - - if (propID != kpidName) - return 0; - } - */ - - - if (property.IsRawProp) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - RINOK(_folderRawProps->GetRawProp(realIndex, propID, &data, &dataSize, &propType)) - unsigned limit = (unsigned)item.cchTextMax - 1; - // limit != 0 - if (dataSize == 0) - return 0; - - if (propID == kpidNtReparse) - { - UString s; - ConvertNtReparseToString((const Byte *)data, dataSize, s); - if (!s.IsEmpty()) - { - unsigned i; - for (i = 0; i < limit; i++) - { - const wchar_t c = s[i]; - if (c == 0) - break; - text[i] = c; - } - text[i] = 0; - return 0; - } - } - else if (propID == kpidNtSecure) - { - AString s; - ConvertNtSecureToString((const Byte *)data, dataSize, s); - if (!s.IsEmpty()) - { - unsigned i; - for (i = 0; i < limit; i++) - { - const wchar_t c = (Byte)s[i]; - if (c == 0) - break; - text[i] = c; - } - text[i] = 0; - return 0; - } - } - { - const unsigned kMaxDataSize = 64; - if (dataSize > kMaxDataSize) - { - char temp[32]; - MyStringCopy(temp, "data:"); - ConvertUInt32ToString(dataSize, temp + 5); - unsigned i; - for (i = 0; i < limit; i++) - { - wchar_t c = (Byte)temp[i]; - if (c == 0) - break; - *text++ = c; - } - *text = 0; - } - else - { - const char * const k_Hex = - (dataSize <= 8 - && (propID == kpidCRC || propID == kpidChecksum)) - ? k_Hex_Upper : k_Hex_Lower; - limit /= 2; - if (limit > dataSize) - limit = dataSize; - const Byte *data2 = (const Byte *)data; - do - { - const size_t b = *data2++; - text[0] = (Byte)k_Hex[b >> 4]; - text[1] = (Byte)k_Hex[b & 15]; - text += 2; - } - while (--limit); - *text = 0; - } - } - return 0; - } - /* - { - NCOM::CPropVariant prop; - if (propID == kpidType) - string = GetFileType(index); - else - { - HRESULT result = m_ArchiveFolder->GetProperty(index, propID, &prop); - if (result != S_OK) - { - // PrintMessage("GetPropertyValue error"); - return 0; - } - string = ConvertPropertyToString(prop, propID, false); - } - } - */ - // const NFind::CFileInfo &aFileInfo = m_Files[index]; - - NCOM::CPropVariant prop; - /* - bool needRead = true; - if (propID == kpidSize) - { - CComPtr getItemFullSize; - if (_folder.QueryInterface(&getItemFullSize) == S_OK) - { - if (getItemFullSize->GetItemFullSize(index, &prop) == S_OK) - needRead = false; - } - } - if (needRead) - */ - - if (item.cchTextMax < 32) - return 0; - - if (propID == kpidName) - { - if (_folderGetItemName) - { - const wchar_t *name = NULL; - unsigned nameLen = 0; - _folderGetItemName->GetItemName(realIndex, &name, &nameLen); - - if (name) - { - unsigned dest = 0; - const unsigned limit = (unsigned)item.cchTextMax - 1; - - for (unsigned i = 0; dest < limit;) - { - const wchar_t c = name[i++]; - if (c == 0) - break; - text[dest++] = c; - - if (c != ' ') - { - if (c != 0x202E) // RLO - continue; - text[(size_t)dest - 1] = '_'; - continue; - } - - if (name[i] != ' ') - continue; - - unsigned t = 1; - for (; name[i + t] == ' '; t++); - - if (t >= 4 && dest + 4 < limit) - { - text[dest++] = '.'; - text[dest++] = '.'; - text[dest++] = '.'; - text[dest++] = ' '; - i += t; - } - } - - if (dest == 0) - text[dest++]= '_'; - - #ifdef _WIN32 - else if (text[(size_t)dest - 1] == ' ') - { - if (dest < limit) - text[dest++] = SPACE_TERMINATOR_CHAR; - else - text[dest - 1] = SPACE_REPLACE_CHAR; - } - #endif - - text[dest] = 0; - // OutputDebugStringW(text); - return 0; - } - } - } - - if (propID == kpidPrefix) - { - if (_folderGetItemName) - { - const wchar_t *name = NULL; - unsigned nameLen = 0; - _folderGetItemName->GetItemPrefix(realIndex, &name, &nameLen); - if (name) - { - unsigned dest = 0; - const unsigned limit = (unsigned)item.cchTextMax - 1; - for (unsigned i = 0; dest < limit;) - { - const wchar_t c = name[i++]; - if (c == 0) - break; - text[dest++] = c; - } - text[dest] = 0; - return 0; - } - } - } - - const HRESULT res = _folder->GetProperty(realIndex, propID, &prop); - - if (res != S_OK) - { - MyStringCopy(text, L"Error: "); - // s = UString("Error: ") + HResultToMessage(res); - } - else if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID)) - { - UInt64 v = 0; - ConvertPropVariantToUInt64(prop, v); - ConvertSizeToString(v, text); - } - else if (prop.vt == VT_BSTR) - { - const unsigned limit = (unsigned)item.cchTextMax - 1; - const wchar_t *src = prop.bstrVal; - unsigned i; - for (i = 0; i < limit; i++) - { - wchar_t c = src[i]; - if (c == 0) break; - if (c == 0xA) c = ' '; - if (c == 0xD) c = ' '; - text[i] = c; - } - text[i] = 0; - } - else - { - char temp[64]; - ConvertPropertyToShortString2(temp, prop, propID, _timestampLevel); - unsigned i; - const unsigned limit = (unsigned)item.cchTextMax - 1; - for (i = 0; i < limit; i++) - { - const wchar_t c = (Byte)temp[i]; - if (c == 0) - break; - text[i] = c; - } - text[i] = 0; - } - - return 0; -} - -void CPanel::OnItemChanged(NMLISTVIEW *item) -{ - const unsigned index = (unsigned)item->lParam; - if (index == kParentIndex) - return; - const bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0; - const bool newSelected = (item->uNewState & LVIS_SELECTED) != 0; - // Don't change this code. It works only with such check - if (oldSelected != newSelected) - _selectedStatusVector[index] = newSelected; -} - -extern bool g_LVN_ITEMACTIVATE_Support; - -void CPanel::OnNotifyActivateItems() -{ - bool alt = IsKeyDown(VK_MENU); - bool ctrl = IsKeyDown(VK_CONTROL); - bool shift = IsKeyDown(VK_SHIFT); - if (!shift && alt && !ctrl) - Properties(); - else - OpenSelectedItems(!shift || alt || ctrl); -} - -bool CPanel::OnNotifyList(LPNMHDR header, LRESULT &result) -{ - switch (header->code) - { - case LVN_ITEMCHANGED: - { - if (_enableItemChangeNotify) - { - if (!_mySelectMode) - OnItemChanged((LPNMLISTVIEW)header); - - // Post_Refresh_StatusBar(); - /* 9.26: we don't call Post_Refresh_StatusBar. - it was very slow if we select big number of files - and then clead slection by selecting just new file. - probably it called slow Refresh_StatusBar for each item deselection. - I hope Refresh_StatusBar still will be called for each key / mouse action. - */ - } - return false; - } - /* - - case LVN_ODSTATECHANGED: - { - break; - } - */ - - case LVN_GETDISPINFOW: - { - LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header; - - //is the sub-item information being requested? - - if ((dispInfo->item.mask & LVIF_TEXT) != 0 || - (dispInfo->item.mask & LVIF_IMAGE) != 0) - SetItemText(dispInfo->item); - { - // 20.03: - result = 0; - return true; - // old 7-Zip: - // return false; - } - } - case LVN_KEYDOWN: - { - LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); - bool boolResult = OnKeyDown(keyDownInfo, result); - switch (keyDownInfo->wVKey) - { - case VK_CONTROL: - case VK_SHIFT: - case VK_MENU: - break; - default: - Post_Refresh_StatusBar(); - } - return boolResult; - } - - case LVN_COLUMNCLICK: - OnColumnClick(LPNMLISTVIEW(header)); - return false; - - case LVN_ITEMACTIVATE: - if (g_LVN_ITEMACTIVATE_Support) - { - OnNotifyActivateItems(); - return false; - } - break; - case NM_DBLCLK: - case NM_RETURN: - if (!g_LVN_ITEMACTIVATE_Support) - { - OnNotifyActivateItems(); - return false; - } - break; - - case NM_RCLICK: - Post_Refresh_StatusBar(); - break; - - /* - return OnRightClick((LPNMITEMACTIVATE)header, result); - */ - /* - case NM_CLICK: - SendRefreshStatusBarMessage(); - return 0; - - // TODO : Handler default action... - return 0; - case LVN_ITEMCHANGED: - { - NMLISTVIEW *pNMLV = (NMLISTVIEW *) lpnmh; - SelChange(pNMLV); - return TRUE; - } - case NM_SETFOCUS: - return onSetFocus(NULL); - case NM_KILLFOCUS: - return onKillFocus(NULL); - */ - case NM_CLICK: - { - // we need SetFocusToList, if we drag-select items from other panel. - SetFocusToList(); - Post_Refresh_StatusBar(); - if (_mySelectMode) -#ifdef Z7_USE_DYN_ComCtl32Version - if (g_ComCtl32Version >= MAKELONG(71, 4)) -#endif - OnLeftClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header); - return false; - } - case LVN_BEGINLABELEDITW: - result = OnBeginLabelEdit((LV_DISPINFOW *)header); - return true; - case LVN_ENDLABELEDITW: - result = OnEndLabelEdit((LV_DISPINFOW *)header); - return true; - - case NM_CUSTOMDRAW: - { - if (_mySelectMode || (_markDeletedItems && _thereAreDeletedItems)) - return OnCustomDraw((LPNMLVCUSTOMDRAW)header, result); - break; - } - case LVN_BEGINDRAG: - { - OnDrag((LPNMLISTVIEW)header, false); - Post_Refresh_StatusBar(); - break; - } - case LVN_BEGINRDRAG: - { - OnDrag((LPNMLISTVIEW)header, true); - Post_Refresh_StatusBar(); - break; - } - // case LVN_BEGINRDRAG: - } - return false; -} - -bool CPanel::OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result) -{ - switch (lplvcd->nmcd.dwDrawStage) - { - case CDDS_PREPAINT : - result = CDRF_NOTIFYITEMDRAW; - return true; - - case CDDS_ITEMPREPAINT: - /* - SelectObject(lplvcd->nmcd.hdc, - GetFontForItem(lplvcd->nmcd.dwItemSpec, - lplvcd->nmcd.lItemlParam) ); - lplvcd->clrText = GetColorForItem(lplvcd->nmcd.dwItemSpec, - lplvcd->nmcd.lItemlParam); - lplvcd->clrTextBk = GetBkColorForItem(lplvcd->nmcd.dwItemSpec, - lplvcd->nmcd.lItemlParam); - */ - const unsigned realIndex = (unsigned)lplvcd->nmcd.lItemlParam; - lplvcd->clrTextBk = _listView.GetBkColor(); - if (_mySelectMode) - { - if (realIndex != kParentIndex && _selectedStatusVector[realIndex]) - lplvcd->clrTextBk = RGB(255, 192, 192); - } - - if (_markDeletedItems && _thereAreDeletedItems) - { - if (IsItem_Deleted(realIndex)) - lplvcd->clrText = RGB(255, 0, 0); - } - // lplvcd->clrText = RGB(0, 0, 0); - // result = CDRF_NEWFONT; - result = CDRF_NOTIFYITEMDRAW; - return true; - - // return false; - // return true; - /* - case CDDS_SUBITEM | CDDS_ITEMPREPAINT: - if (lplvcd->iSubItem == 0) - { - // lplvcd->clrText = RGB(255, 0, 0); - lplvcd->clrTextBk = RGB(192, 192, 192); - } - else - { - lplvcd->clrText = RGB(0, 0, 0); - lplvcd->clrTextBk = RGB(255, 255, 255); - } - return true; - */ - - /* At this point, you can change the background colors for the item - and any subitems and return CDRF_NEWFONT. If the list-view control - is in report mode, you can simply return CDRF_NOTIFYSUBITEMREDRAW - to customize the item's subitems individually */ - } - return false; -} - -void CPanel::Refresh_StatusBar() -{ - /* - g_name_cnt++; - char s[256]; - sprintf(s, "g_name_cnt = %8d", g_name_cnt); - OutputDebugStringA(s); - */ - // DWORD dw = GetTickCount(); - - CRecordVector indices; - Get_ItemIndices_Operated(indices); - - { - UString s; - s.Add_UInt32(indices.Size()); - s += " / "; - s.Add_UInt32(_selectedStatusVector.Size()); - - // UString s1 = MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, NumberToString(indices.Size())); - // UString s1 = MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size())); - _statusBar.SetText(0, MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, s)); - // _statusBar.SetText(0, MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size()))); - } - - { - wchar_t selectSizeString[32]; - selectSizeString[0] = 0; - - if (indices.Size() > 0) - { - // for (unsigned ttt = 0; ttt < 1000; ttt++) { - UInt64 totalSize = 0; - FOR_VECTOR (i, indices) - totalSize += GetItemSize(indices[i]); - ConvertSizeToString(totalSize, selectSizeString); - // } - } - _statusBar.SetText(1, selectSizeString); - } - - const int focusedItem = _listView.GetFocusedItem(); - wchar_t sizeString[32]; - sizeString[0] = 0; - wchar_t dateString[32]; - dateString[0] = 0; - if (focusedItem >= 0 && _listView.GetSelectedCount() > 0) - { - const unsigned realIndex = GetRealItemIndex(focusedItem); - if (realIndex != kParentIndex) - { - ConvertSizeToString(GetItemSize(realIndex), sizeString); - NCOM::CPropVariant prop; - if (_folder->GetProperty(realIndex, kpidMTime, &prop) == S_OK) - { - char dateString2[64]; - dateString2[0] = 0; - ConvertPropertyToShortString2(dateString2, prop, kpidMTime); - for (unsigned i = 0;; i++) - { - char c = dateString2[i]; - dateString[i] = (Byte)c; - if (c == 0) - break; - } - } - } - } - _statusBar.SetText(2, sizeString); - _statusBar.SetText(3, dateString); - - // _statusBar.SetText(4, nameString); - // _statusBar2.SetText(1, MyFormatNew(L"{0} bytes", NumberToStringW(totalSize))); - // } - /* - dw = GetTickCount() - dw; - sprintf(s, "status = %8d ms", dw); - OutputDebugStringA(s); - */ -} +// PanelListNotify.cpp + +#include "StdAfx.h" + +#include "resource.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../Common/PropIDUtils.h" +#include "../../PropID.h" + +#include "App.h" +#include "Panel.h" +#include "FormatUtils.h" + +using namespace NWindows; + +/* Unicode characters for space: +0x009C STRING TERMINATOR +0x00B7 Middle dot +0x237D Shouldered open box +0x2420 Symbol for space +0x2422 Blank symbol +0x2423 Open box +*/ + +#define SPACE_REPLACE_CHAR (wchar_t)(0x2423) +#define SPACE_TERMINATOR_CHAR (wchar_t)(0x9C) + +#define INT_TO_STR_SPEC(v) \ + while (v >= 10) { temp[i++] = (Byte)('0' + (unsigned)(v % 10)); v /= 10; } \ + *s++ = (Byte)('0' + (unsigned)v); + +static void ConvertSizeToString(UInt64 val, wchar_t *s) throw() +{ + Byte temp[32]; + unsigned i = 0; + + if (val <= (UInt32)0xFFFFFFFF) + { + UInt32 val32 = (UInt32)val; + INT_TO_STR_SPEC(val32) + } + else + { + INT_TO_STR_SPEC(val) + } + + if (i < 3) + { + if (i != 0) + { + *s++ = temp[(size_t)i - 1]; + if (i == 2) + *s++ = temp[0]; + } + *s = 0; + return; + } + + unsigned r = i % 3; + if (r != 0) + { + s[0] = temp[--i]; + if (r == 2) + s[1] = temp[--i]; + s += r; + } + + do + { + s[0] = ' '; + s[1] = temp[(size_t)i - 1]; + s[2] = temp[(size_t)i - 2]; + s[3] = temp[(size_t)i - 3]; + s += 4; + } + while (i -= 3); + + *s = 0; +} + +UString ConvertSizeToString(UInt64 value); +UString ConvertSizeToString(UInt64 value) +{ + wchar_t s[32]; + ConvertSizeToString(value, s); + return s; +} + +bool IsSizeProp(UINT propID) throw(); +bool IsSizeProp(UINT propID) throw() +{ + switch (propID) + { + case kpidSize: + case kpidPackSize: + case kpidNumSubDirs: + case kpidNumSubFiles: + case kpidOffset: + case kpidLinks: + case kpidNumBlocks: + case kpidNumVolumes: + case kpidPhySize: + case kpidHeadersSize: + case kpidTotalSize: + case kpidFreeSpace: + case kpidClusterSize: + case kpidNumErrors: + case kpidNumStreams: + case kpidNumAltStreams: + case kpidAltStreamsSize: + case kpidVirtualSize: + case kpidUnpackSize: + case kpidTotalPhySize: + case kpidTailSize: + case kpidEmbeddedStubSize: + return true; + } + return false; +} + + + +/* +#include + +UInt64 GetCpuTicks() +{ + #ifdef _WIN64 + return __rdtsc(); + #else + UInt32 lowVal, highVal; + __asm RDTSC; + __asm mov lowVal, EAX; + __asm mov highVal, EDX; + return ((UInt64)highVal << 32) | lowVal; + #endif +} + +UInt32 g_NumGroups; +UInt64 g_start_tick; +UInt64 g_prev_tick; +DWORD g_Num_SetItemText; +UInt32 g_NumMessages; +*/ + +LRESULT CPanel::SetItemText(LVITEMW &item) +{ + if (_dontShowMode) + return 0; + UInt32 realIndex = GetRealIndex(item); + + // g_Num_SetItemText++; + + /* + if ((item.mask & LVIF_IMAGE) != 0) + { + bool defined = false; + CComPtr folderGetSystemIconIndex; + _folder.QueryInterface(&folderGetSystemIconIndex); + if (folderGetSystemIconIndex) + { + folderGetSystemIconIndex->GetSystemIconIndex(index, &item.iImage); + defined = (item.iImage > 0); + } + if (!defined) + { + NCOM::CPropVariant prop; + _folder->GetProperty(index, kpidAttrib, &prop); + UINT32 attrib = 0; + if (prop.vt == VT_UI4) + attrib = prop.ulVal; + else if (IsItemFolder(index)) + attrib |= FILE_ATTRIBUTE_DIRECTORY; + if (_currentFolderPrefix.IsEmpty()) + throw 1; + else + item.iImage = _extToIconMap.GetIconIndex(attrib, GetSystemString(GetItemName(index))); + } + // item.iImage = 1; + } + */ + + if ((item.mask & LVIF_TEXT) == 0) + return 0; + + LPWSTR text = item.pszText; + + if (item.cchTextMax > 0) + text[0] = 0; + + if (item.cchTextMax <= 1) + return 0; + + // item.cchTextMax > 1 + + const CPropColumn &property = _visibleColumns[item.iSubItem]; + PROPID propID = property.ID; + + if (realIndex == kParentIndex_UInt32) + { + if (propID == kpidName) + { + if (item.cchTextMax > 2) + { + text[0] = '.'; + text[1] = '.'; + text[2] = 0; + } + } + return 0; + } + + /* + // List-view in report-view in Windows 10 is slow (50+ ms) for page change. + // that code shows the time of page reload for items + // if you know how to improve the speed of list view refresh, notify 7-Zip developer + + // if (propID == 2000) + // if (propID == kpidName) + { + // debug column; + // DWORD dw = GetCpuTicks(); + UInt64 dw = GetCpuTicks(); + UInt64 deltaLast = dw - g_prev_tick; + #define conv_ticks(t) ((unsigned)((t) / 100000)) + if (deltaLast > 1000u * 1000 * 1000) + { + UInt64 deltaFull = g_prev_tick - g_start_tick; + char s[128]; + sprintf(s, "%d", conv_ticks(deltaFull)); + OutputDebugStringA(s); + g_start_tick = dw; + g_NumGroups++; + } + g_prev_tick = dw; + UString u; + char s[128]; + UInt64 deltaFull = dw - g_start_tick; + // for (int i = 0; i < 100000; i++) + sprintf(s, "%d %d %d-%d ", g_NumMessages, g_Num_SetItemText, g_NumGroups, conv_ticks(deltaFull)); + // sprintf(s, "%d-%d ", g_NumGroups, conv_ticks(deltaFull)); + u = s; + lstrcpyW(text, u.Ptr()); + text += u.Len(); + + // dw = GetCpuTicks(); + // deltaFull = dw - g_prev_tick; + // sprintf(s, "-%d ", conv_ticks(deltaFull)); + // u = s; + // lstrcpyW(text, u.Ptr()); + // text += u.Len(); + + if (propID != kpidName) + return 0; + } + */ + + + if (property.IsRawProp) + { + const void *data; + UInt32 dataSize; + UInt32 propType; + RINOK(_folderRawProps->GetRawProp(realIndex, propID, &data, &dataSize, &propType)) + unsigned limit = (unsigned)item.cchTextMax - 1; + // limit != 0 + if (dataSize == 0) + return 0; + + if (propID == kpidNtReparse) + { + UString s; + ConvertNtReparseToString((const Byte *)data, dataSize, s); + if (!s.IsEmpty()) + { + unsigned i; + for (i = 0; i < limit; i++) + { + const wchar_t c = s[i]; + if (c == 0) + break; + text[i] = c; + } + text[i] = 0; + return 0; + } + } + else if (propID == kpidNtSecure) + { + AString s; + ConvertNtSecureToString((const Byte *)data, dataSize, s); + if (!s.IsEmpty()) + { + unsigned i; + for (i = 0; i < limit; i++) + { + const wchar_t c = (Byte)s[i]; + if (c == 0) + break; + text[i] = c; + } + text[i] = 0; + return 0; + } + } + { + const unsigned kMaxDataSize = 64; + if (dataSize > kMaxDataSize) + { + char temp[32]; + MyStringCopy(temp, "data:"); + ConvertUInt32ToString(dataSize, temp + 5); + unsigned i; + for (i = 0; i < limit; i++) + { + wchar_t c = (Byte)temp[i]; + if (c == 0) + break; + *text++ = c; + } + *text = 0; + } + else + { + const char * const k_Hex = + (dataSize <= 8 + && (propID == kpidCRC || propID == kpidChecksum)) + ? k_Hex_Upper : k_Hex_Lower; + limit /= 2; + if (limit > dataSize) + limit = dataSize; + const Byte *data2 = (const Byte *)data; + do + { + const size_t b = *data2++; + text[0] = (Byte)k_Hex[b >> 4]; + text[1] = (Byte)k_Hex[b & 15]; + text += 2; + } + while (--limit); + *text = 0; + } + } + return 0; + } + /* + { + NCOM::CPropVariant prop; + if (propID == kpidType) + string = GetFileType(index); + else + { + HRESULT result = m_ArchiveFolder->GetProperty(index, propID, &prop); + if (result != S_OK) + { + // PrintMessage("GetPropertyValue error"); + return 0; + } + string = ConvertPropertyToString(prop, propID, false); + } + } + */ + // const NFind::CFileInfo &aFileInfo = m_Files[index]; + + NCOM::CPropVariant prop; + /* + bool needRead = true; + if (propID == kpidSize) + { + CComPtr getItemFullSize; + if (_folder.QueryInterface(&getItemFullSize) == S_OK) + { + if (getItemFullSize->GetItemFullSize(index, &prop) == S_OK) + needRead = false; + } + } + if (needRead) + */ + + if (item.cchTextMax < 32) + return 0; + + if (propID == kpidName) + { + if (_folderGetItemName) + { + const wchar_t *name = NULL; + unsigned nameLen = 0; + _folderGetItemName->GetItemName(realIndex, &name, &nameLen); + + if (name) + { + unsigned dest = 0; + const unsigned limit = (unsigned)item.cchTextMax - 1; + + for (unsigned i = 0; dest < limit;) + { + const wchar_t c = name[i++]; + if (c == 0) + break; + text[dest++] = c; + + if (c != ' ') + { + if (c != 0x202E) // RLO + continue; + text[(size_t)dest - 1] = '_'; + continue; + } + + if (name[i] != ' ') + continue; + + unsigned t = 1; + for (; name[i + t] == ' '; t++); + + if (t >= 4 && dest + 4 < limit) + { + text[dest++] = '.'; + text[dest++] = '.'; + text[dest++] = '.'; + text[dest++] = ' '; + i += t; + } + } + + if (dest == 0) + text[dest++]= '_'; + + #ifdef _WIN32 + else if (text[(size_t)dest - 1] == ' ') + { + if (dest < limit) + text[dest++] = SPACE_TERMINATOR_CHAR; + else + text[dest - 1] = SPACE_REPLACE_CHAR; + } + #endif + + text[dest] = 0; + // OutputDebugStringW(text); + return 0; + } + } + } + + if (propID == kpidPrefix) + { + if (_folderGetItemName) + { + const wchar_t *name = NULL; + unsigned nameLen = 0; + _folderGetItemName->GetItemPrefix(realIndex, &name, &nameLen); + if (name) + { + unsigned dest = 0; + const unsigned limit = (unsigned)item.cchTextMax - 1; + for (unsigned i = 0; dest < limit;) + { + const wchar_t c = name[i++]; + if (c == 0) + break; + text[dest++] = c; + } + text[dest] = 0; + return 0; + } + } + } + + const HRESULT res = _folder->GetProperty(realIndex, propID, &prop); + + if (res != S_OK) + { + MyStringCopy(text, L"Error: "); + // s = UString("Error: ") + HResultToMessage(res); + } + else if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID)) + { + UInt64 v = 0; + ConvertPropVariantToUInt64(prop, v); + ConvertSizeToString(v, text); + } + else if (prop.vt == VT_BSTR) + { + const unsigned limit = (unsigned)item.cchTextMax - 1; + const wchar_t *src = prop.bstrVal; + unsigned i; + for (i = 0; i < limit; i++) + { + wchar_t c = src[i]; + if (c == 0) break; + if (c == 0xA) c = ' '; + if (c == 0xD) c = ' '; + text[i] = c; + } + text[i] = 0; + } + else + { + char temp[64]; + ConvertPropertyToShortString2(temp, prop, propID, _timestampLevel); + unsigned i; + const unsigned limit = (unsigned)item.cchTextMax - 1; + for (i = 0; i < limit; i++) + { + const wchar_t c = (Byte)temp[i]; + if (c == 0) + break; + text[i] = c; + } + text[i] = 0; + } + + return 0; +} + +void CPanel::OnItemChanged(NMLISTVIEW *item) +{ + const unsigned index = (unsigned)item->lParam; + if (index == kParentIndex) + return; + const bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0; + const bool newSelected = (item->uNewState & LVIS_SELECTED) != 0; + // Don't change this code. It works only with such check + if (oldSelected != newSelected) + _selectedStatusVector[index] = newSelected; +} + +extern bool g_LVN_ITEMACTIVATE_Support; + +void CPanel::OnNotifyActivateItems() +{ + bool alt = IsKeyDown(VK_MENU); + bool ctrl = IsKeyDown(VK_CONTROL); + bool shift = IsKeyDown(VK_SHIFT); + if (!shift && alt && !ctrl) + Properties(); + else + OpenSelectedItems(!shift || alt || ctrl); +} + +bool CPanel::OnNotifyList(LPNMHDR header, LRESULT &result) +{ + switch (header->code) + { + case LVN_ITEMCHANGED: + { + if (_enableItemChangeNotify) + { + if (!_mySelectMode) + OnItemChanged((LPNMLISTVIEW)header); + + // Post_Refresh_StatusBar(); + /* 9.26: we don't call Post_Refresh_StatusBar. + it was very slow if we select big number of files + and then clead slection by selecting just new file. + probably it called slow Refresh_StatusBar for each item deselection. + I hope Refresh_StatusBar still will be called for each key / mouse action. + */ + } + return false; + } + /* + + case LVN_ODSTATECHANGED: + { + break; + } + */ + + case LVN_GETDISPINFOW: + { + LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header; + + //is the sub-item information being requested? + + if ((dispInfo->item.mask & LVIF_TEXT) != 0 || + (dispInfo->item.mask & LVIF_IMAGE) != 0) + SetItemText(dispInfo->item); + { + // 20.03: + result = 0; + return true; + // old 7-Zip: + // return false; + } + } + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); + bool boolResult = OnKeyDown(keyDownInfo, result); + switch (keyDownInfo->wVKey) + { + case VK_CONTROL: + case VK_SHIFT: + case VK_MENU: + break; + default: + Post_Refresh_StatusBar(); + } + return boolResult; + } + + case LVN_COLUMNCLICK: + OnColumnClick(LPNMLISTVIEW(header)); + return false; + + case LVN_ITEMACTIVATE: + if (g_LVN_ITEMACTIVATE_Support) + { + OnNotifyActivateItems(); + return false; + } + break; + case NM_DBLCLK: + case NM_RETURN: + if (!g_LVN_ITEMACTIVATE_Support) + { + OnNotifyActivateItems(); + return false; + } + break; + + case NM_RCLICK: + Post_Refresh_StatusBar(); + break; + + /* + return OnRightClick((LPNMITEMACTIVATE)header, result); + */ + /* + case NM_CLICK: + SendRefreshStatusBarMessage(); + return 0; + + // TODO : Handler default action... + return 0; + case LVN_ITEMCHANGED: + { + NMLISTVIEW *pNMLV = (NMLISTVIEW *) lpnmh; + SelChange(pNMLV); + return TRUE; + } + case NM_SETFOCUS: + return onSetFocus(NULL); + case NM_KILLFOCUS: + return onKillFocus(NULL); + */ + case NM_CLICK: + { + // we need SetFocusToList, if we drag-select items from other panel. + SetFocusToList(); + Post_Refresh_StatusBar(); + if (_mySelectMode) +#ifdef Z7_USE_DYN_ComCtl32Version + if (g_ComCtl32Version >= MAKELONG(71, 4)) +#endif + OnLeftClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header); + return false; + } + case LVN_BEGINLABELEDITW: + result = OnBeginLabelEdit((LV_DISPINFOW *)header); + return true; + case LVN_ENDLABELEDITW: + result = OnEndLabelEdit((LV_DISPINFOW *)header); + return true; + + case NM_CUSTOMDRAW: + { + if (_mySelectMode || (_markDeletedItems && _thereAreDeletedItems)) + return OnCustomDraw((LPNMLVCUSTOMDRAW)header, result); + break; + } + case LVN_BEGINDRAG: + { + OnDrag((LPNMLISTVIEW)header, false); + Post_Refresh_StatusBar(); + break; + } + case LVN_BEGINRDRAG: + { + OnDrag((LPNMLISTVIEW)header, true); + Post_Refresh_StatusBar(); + break; + } + // case LVN_BEGINRDRAG: + } + return false; +} + +bool CPanel::OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result) +{ + switch (lplvcd->nmcd.dwDrawStage) + { + case CDDS_PREPAINT : + result = CDRF_NOTIFYITEMDRAW; + return true; + + case CDDS_ITEMPREPAINT: + /* + SelectObject(lplvcd->nmcd.hdc, + GetFontForItem(lplvcd->nmcd.dwItemSpec, + lplvcd->nmcd.lItemlParam) ); + lplvcd->clrText = GetColorForItem(lplvcd->nmcd.dwItemSpec, + lplvcd->nmcd.lItemlParam); + lplvcd->clrTextBk = GetBkColorForItem(lplvcd->nmcd.dwItemSpec, + lplvcd->nmcd.lItemlParam); + */ + const unsigned realIndex = (unsigned)lplvcd->nmcd.lItemlParam; + lplvcd->clrTextBk = _listView.GetBkColor(); + if (_mySelectMode) + { + if (realIndex != kParentIndex && _selectedStatusVector[realIndex]) + lplvcd->clrTextBk = RGB(255, 192, 192); + } + + if (_markDeletedItems && _thereAreDeletedItems) + { + if (IsItem_Deleted(realIndex)) + lplvcd->clrText = RGB(255, 0, 0); + } + // lplvcd->clrText = RGB(0, 0, 0); + // result = CDRF_NEWFONT; + result = CDRF_NOTIFYITEMDRAW; + return true; + + // return false; + // return true; + /* + case CDDS_SUBITEM | CDDS_ITEMPREPAINT: + if (lplvcd->iSubItem == 0) + { + // lplvcd->clrText = RGB(255, 0, 0); + lplvcd->clrTextBk = RGB(192, 192, 192); + } + else + { + lplvcd->clrText = RGB(0, 0, 0); + lplvcd->clrTextBk = RGB(255, 255, 255); + } + return true; + */ + + /* At this point, you can change the background colors for the item + and any subitems and return CDRF_NEWFONT. If the list-view control + is in report mode, you can simply return CDRF_NOTIFYSUBITEMREDRAW + to customize the item's subitems individually */ + } + return false; +} + +void CPanel::Refresh_StatusBar() +{ + /* + g_name_cnt++; + char s[256]; + sprintf(s, "g_name_cnt = %8d", g_name_cnt); + OutputDebugStringA(s); + */ + // DWORD dw = GetTickCount(); + + CRecordVector indices; + Get_ItemIndices_Operated(indices); + + { + UString s; + s.Add_UInt32(indices.Size()); + s += " / "; + s.Add_UInt32(_selectedStatusVector.Size()); + + // UString s1 = MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, NumberToString(indices.Size())); + // UString s1 = MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size())); + _statusBar.SetText(0, MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, s)); + // _statusBar.SetText(0, MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size()))); + } + + { + wchar_t selectSizeString[32]; + selectSizeString[0] = 0; + + if (!indices.IsEmpty()) + { + // for (unsigned ttt = 0; ttt < 1000; ttt++) { + UInt64 totalSize = 0; + FOR_VECTOR (i, indices) + totalSize += GetItemSize(indices[i]); + ConvertSizeToString(totalSize, selectSizeString); + // } + } + _statusBar.SetText(1, selectSizeString); + } + + const int focusedItem = _listView.GetFocusedItem(); + wchar_t sizeString[32]; + sizeString[0] = 0; + wchar_t dateString[32]; + dateString[0] = 0; + if (focusedItem >= 0 && _listView.GetSelectedCount() > 0) + { + const unsigned realIndex = GetRealItemIndex(focusedItem); + if (realIndex != kParentIndex) + { + ConvertSizeToString(GetItemSize(realIndex), sizeString); + NCOM::CPropVariant prop; + if (_folder->GetProperty(realIndex, kpidMTime, &prop) == S_OK) + { + char dateString2[64]; + dateString2[0] = 0; + ConvertPropertyToShortString2(dateString2, prop, kpidMTime); + for (unsigned i = 0;; i++) + { + char c = dateString2[i]; + dateString[i] = (Byte)c; + if (c == 0) + break; + } + } + } + } + _statusBar.SetText(2, sizeString); + _statusBar.SetText(3, dateString); + + // _statusBar.SetText(4, nameString); + // _statusBar2.SetText(1, MyFormatNew(L"{0} bytes", NumberToStringW(totalSize))); + // } + /* + dw = GetTickCount() - dw; + sprintf(s, "status = %8d ms", dw); + OutputDebugStringA(s); + */ +} diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp index 3b4a4a3a9..908699646 100644 --- a/CPP/7zip/UI/FileManager/PanelMenu.cpp +++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp @@ -1,1156 +1,1156 @@ -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/COM.h" -#include "../../../Windows/Clipboard.h" -#include "../../../Windows/Menu.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/PropVariantConv.h" - -#include "../../PropID.h" -#include "../Common/PropIDUtils.h" -#include "../Explorer/ContextMenu.h" - -#include "App.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "ListViewDialog.h" -#include "MyLoadMenu.h" -#include "PropertyName.h" - -#include "PropertyNameRes.h" -#include "resource.h" - -// #define SHOW_DEBUG_PANEL_MENU - -using namespace NWindows; - -extern -LONG g_DllRefCount; -LONG g_DllRefCount = 0; - -static const UINT kSevenZipStartMenuID = kMenuCmdID_Plugin_Start; -static const UINT kSystemStartMenuID = kMenuCmdID_Plugin_Start + 400; - - -#ifdef SHOW_DEBUG_PANEL_MENU -static void Print_Ptr(void *p, const char *s) -{ - char temp[32]; - ConvertUInt64ToHex((UInt64)(void *)p, temp); - AString m; - m += temp; - m.Add_Space(); - m += s; - OutputDebugStringA(m); -} -#define ODS(sz) { Print_Ptr(this, sz); } -#define ODS_U(s) { OutputDebugStringW(s); } -#else -#define ODS(sz) -#define ODS_U(s) -#endif - - -void CPanel::InvokeSystemCommand(const char *command) -{ - NCOM::CComInitializer comInitializer; - if (!IsFsOrPureDrivesFolder()) - return; - CRecordVector operatedIndices; - Get_ItemIndices_Operated(operatedIndices); - if (operatedIndices.IsEmpty()) - return; - CMyComPtr contextMenu; - if (CreateShellContextMenu(operatedIndices, contextMenu) != S_OK) - return; - - CMINVOKECOMMANDINFO ci; - ZeroMemory(&ci, sizeof(ci)); - ci.cbSize = sizeof(CMINVOKECOMMANDINFO); - ci.hwnd = GetParent(); - ci.lpVerb = command; - contextMenu->InvokeCommand(&ci); -} - -static const char * const kSeparator = "------------------------"; -static const char * const kSeparatorSmall = "----------------"; - -extern UString ConvertSizeToString(UInt64 value) throw(); -bool IsSizeProp(UINT propID) throw(); - -UString GetOpenArcErrorMessage(UInt32 errorFlags); - - -static void AddListAscii(CListViewDialog &dialog, const char *s) -{ - dialog.Strings.Add((UString)s); - dialog.Values.AddNew(); -} - -static void AddSeparator(CListViewDialog &dialog) -{ - AddListAscii(dialog, kSeparator); -} - -static void AddSeparatorSmall(CListViewDialog &dialog) -{ - AddListAscii(dialog, kSeparatorSmall); -} - -static void AddPropertyPair(const UString &name, const UString &val, CListViewDialog &dialog) -{ - dialog.Strings.Add(name); - dialog.Values.Add(val); -} - - -static void AddPropertyString(PROPID propID, const wchar_t *nameBSTR, - const NCOM::CPropVariant &prop, CListViewDialog &dialog) -{ - if (prop.vt != VT_EMPTY) - { - UString val; - - if (propID == kpidErrorFlags || - propID == kpidWarningFlags) - { - UInt32 flags = GetOpenArcErrorFlags(prop); - if (flags == 0) - return; - if (flags != 0) - val = GetOpenArcErrorMessage(flags); - } - - if (val.IsEmpty()) - { - if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID)) - { - UInt64 v = 0; - ConvertPropVariantToUInt64(prop, v); - val = ConvertSizeToString(v); - } - else - ConvertPropertyToString2(val, prop, propID, 9); // we send 9 - is ns precision - } - - if (!val.IsEmpty()) - { - if (propID == kpidErrorType) - { - AddPropertyPair(L"Open WARNING:", L"Cannot open the file as expected archive type", dialog); - } - AddPropertyPair(GetNameOfProperty(propID, nameBSTR), val, dialog); - } - } -} - - -static void AddPropertyString(PROPID propID, UInt64 val, CListViewDialog &dialog) -{ - NCOM::CPropVariant prop = val; - AddPropertyString(propID, NULL, prop, dialog); -} - - -static const Byte kSpecProps[] = -{ - kpidPath, - kpidType, - kpidErrorType, - kpidError, - kpidErrorFlags, - kpidWarning, - kpidWarningFlags, - kpidOffset, - kpidPhySize, - kpidTailSize -}; - -void CPanel::Properties() -{ - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - if (!getFolderArcProps) - { - InvokeSystemCommand("properties"); - return; - } - - { - CListViewDialog message; - // message.DeleteIsAllowed = false; - // message.SelectFirst = false; - - CRecordVector operatedIndices; - Get_ItemIndices_Operated(operatedIndices); - - if (operatedIndices.Size() == 1) - { - UInt32 index = operatedIndices[0]; - // message += "Item:\n"); - UInt32 numProps; - if (_folder->GetNumberOfProperties(&numProps) == S_OK) - { - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE varType; - - if (_folder->GetPropertyInfo(i, &name, &propID, &varType) != S_OK) - continue; - - NCOM::CPropVariant prop; - if (_folder->GetProperty(index, propID, &prop) != S_OK) - continue; - AddPropertyString(propID, name, prop, message); - } - } - - - if (_folderRawProps) - { - _folderRawProps->GetNumRawProps(&numProps); - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK) - continue; - - const void *data; - UInt32 dataSize; - UInt32 propType; - if (_folderRawProps->GetRawProp(index, propID, &data, &dataSize, &propType) != S_OK) - continue; - - if (dataSize != 0) - { - AString s; - if (propID == kpidNtSecure) - ConvertNtSecureToString((const Byte *)data, dataSize, s); - else - { - const unsigned kMaxDataSize = 1 << 8; - if (dataSize > kMaxDataSize) - { - s += "data:"; - s.Add_UInt32(dataSize); - } - else - { - char temp[kMaxDataSize * 2 + 2]; - if (dataSize <= 8 && (propID == kpidCRC || propID == kpidChecksum)) - ConvertDataToHex_Upper(temp, (const Byte *)data, dataSize); - else - ConvertDataToHex_Lower(temp, (const Byte *)data, dataSize); - s += temp; - } - } - AddPropertyPair(GetNameOfProperty(propID, name), (UString)s.Ptr(), message); - } - } - } - - AddSeparator(message); - } - else if (operatedIndices.Size() >= 1) - { - UInt64 packSize = 0; - UInt64 unpackSize = 0; - UInt64 numFiles = 0; - UInt64 numDirs = 0; - - FOR_VECTOR (i, operatedIndices) - { - const UInt32 index = operatedIndices[i]; - unpackSize += GetItemSize(index); - packSize += GetItem_UInt64Prop(index, kpidPackSize); - if (IsItem_Folder(index)) - { - numDirs++; - numDirs += GetItem_UInt64Prop(index, kpidNumSubDirs); - numFiles += GetItem_UInt64Prop(index, kpidNumSubFiles); - } - else - numFiles++; - } - { - wchar_t temp[32]; - ConvertUInt32ToString(operatedIndices.Size(), temp); - AddPropertyPair(L"", MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, temp), message); - } - - if (numDirs != 0) - AddPropertyString(kpidNumSubDirs, numDirs, message); - if (numFiles != 0) - AddPropertyString(kpidNumSubFiles, numFiles, message); - AddPropertyString(kpidSize, unpackSize, message); - AddPropertyString(kpidPackSize, packSize, message); - - AddSeparator(message); - } - - - /* - AddLangString(message, IDS_PROP_FILE_TYPE); - message += kPropValueSeparator; - message += GetFolderTypeID(); - message.Add_LF(); - */ - - { - NCOM::CPropVariant prop; - if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK) - { - AddPropertyString(kpidName, L"Path", prop, message); - } - } - - CMyComPtr folderProperties; - _folder.QueryInterface(IID_IFolderProperties, &folderProperties); - if (folderProperties) - { - UInt32 numProps; - if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK) - { - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK) - continue; - NCOM::CPropVariant prop; - if (_folder->GetFolderProperty(propID, &prop) != S_OK) - continue; - AddPropertyString(propID, name, prop, message); - } - } - } - - if (getFolderArcProps) - { - CMyComPtr getProps; - getFolderArcProps->GetFolderArcProps(&getProps); - if (getProps) - { - UInt32 numLevels; - if (getProps->GetArcNumLevels(&numLevels) != S_OK) - numLevels = 0; - for (UInt32 level2 = 0; level2 < numLevels; level2++) - { - { - UInt32 level = numLevels - 1 - level2; - UInt32 numProps; - if (getProps->GetArcNumProps(level, &numProps) == S_OK) - { - const int kNumSpecProps = Z7_ARRAY_SIZE(kSpecProps); - - AddSeparator(message); - - for (Int32 i = -(int)kNumSpecProps; i < (Int32)numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - if (i < 0) - propID = kSpecProps[i + kNumSpecProps]; - else if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK) - continue; - NCOM::CPropVariant prop; - if (getProps->GetArcProp(level, propID, &prop) != S_OK) - continue; - AddPropertyString(propID, name, prop, message); - } - } - } - - if (level2 < numLevels - 1) - { - const UInt32 level = numLevels - 1 - level2; - UInt32 numProps; - if (getProps->GetArcNumProps2(level, &numProps) == S_OK) - { - AddSeparatorSmall(message); - for (UInt32 i = 0; i < numProps; i++) - { - CMyComBSTR name; - PROPID propID; - VARTYPE vt; - if (getProps->GetArcPropInfo2(level, i, &name, &propID, &vt) != S_OK) - continue; - NCOM::CPropVariant prop; - if (getProps->GetArcProp2(level, propID, &prop) != S_OK) - continue; - AddPropertyString(propID, name, prop, message); - } - } - } - } - - { - // we ERROR message for NonOpen level - bool needSep = true; - const int kNumSpecProps = Z7_ARRAY_SIZE(kSpecProps); - for (Int32 i = -(int)kNumSpecProps; i < 0; i++) - { - CMyComBSTR name; - const PROPID propID = kSpecProps[i + kNumSpecProps]; - NCOM::CPropVariant prop; - if (getProps->GetArcProp(numLevels, propID, &prop) != S_OK) - continue; - if (needSep) - { - AddSeparator(message); - AddSeparator(message); - needSep = false; - } - AddPropertyString(propID, name, prop, message); - } - } - - } - } - - message.Title = LangString(IDS_PROPERTIES); - message.NumColumns = 2; - message.Create(GetParent()); - } -} - - - -void CPanel::EditCut() -{ - // InvokeSystemCommand("cut"); -} - -void CPanel::EditCopy() -{ - /* - CMyComPtr getFolderArcProps; - _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); - if (!getFolderArcProps) - { - InvokeSystemCommand("copy"); - return; - } - */ - UString s; - CRecordVector indices; - Get_ItemIndices_Selected(indices); - FOR_VECTOR (i, indices) - { - if (i != 0) - s += "\xD\n"; - s += GetItemName(indices[i]); - } - ClipboardSetText(_mainWindow, s); -} - -void CPanel::EditPaste() -{ - /* - UStringVector names; - ClipboardGetFileNames(names); - CopyFromNoAsk(names); - UString s; - for (int i = 0; i < names.Size(); i++) - { - s += L' '; - s += names[i]; - } - - MessageBoxW(0, s, L"", 0); - */ - - // InvokeSystemCommand("paste"); -} - - - -struct CFolderPidls -{ - LPITEMIDLIST parent; - CRecordVector items; - - CFolderPidls(): parent(NULL) {} - ~CFolderPidls() - { - FOR_VECTOR (i, items) - CoTaskMemFree(items[i]); - CoTaskMemFree(parent); - } -}; - - -static HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder, - HWND hwnd, const UString &path, LPITEMIDLIST *ppidl) -{ - ULONG eaten = 0; - return shellFolder->ParseDisplayName(hwnd, NULL, - path.Ptr_non_const(), &eaten, ppidl, NULL); -} - - -HRESULT CPanel::CreateShellContextMenu( - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu) -{ - ODS("==== CPanel::CreateShellContextMenu"); - systemContextMenu.Release(); - UString folderPath = GetFsPath(); - - CMyComPtr desktopFolder; - RINOK(::SHGetDesktopFolder(&desktopFolder)) - if (!desktopFolder) - { - // ShowMessage("Failed to get Desktop folder"); - return E_FAIL; - } - - CFolderPidls pidls; - // NULL is allowed for parentHWND in ParseDisplayName() - const HWND parentHWND_for_ParseDisplayName = GetParent(); - // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer" - /* win10: ParseDisplayName() supports folder path with tail slash - ParseDisplayName() returns { - E_INVALIDARG : path with super path prefix "\\\\?\\" - ERROR_FILE_NOT_FOUND : path for network share (\\server\path1\long path2") larger than MAX_PATH - } */ - const HRESULT res = ShellFolder_ParseDisplayName(desktopFolder, - parentHWND_for_ParseDisplayName, - folderPath, &pidls.parent); - if (res != S_OK) - { - ODS_U(folderPath); - if (res != E_INVALIDARG) - return res; - if (!NFile::NName::If_IsSuperPath_RemoveSuperPrefix(folderPath)) - return res; - RINOK(ShellFolder_ParseDisplayName(desktopFolder, - parentHWND_for_ParseDisplayName, - folderPath, &pidls.parent)) - } - if (!pidls.parent) - return E_FAIL; - - /* - UString path2; - NShell::GetPathFromIDList(pidls.parent, path2); - ODS_U(path2); - */ - - if (operatedIndices.IsEmpty()) - { - // how to get IContextMenu, if there are no selected files? - return E_FAIL; - - /* - xp64 : - 1) we can't use GetUIObjectOf() with (numItems == 0), it throws exception - 2) we can't use desktopFolder->GetUIObjectOf() with absolute pidls of folder - context menu items are different in that case: - "Open / Explorer" for folder - "Delete" for "My Computer" icon - "Preperties" for "System" - */ - /* - parentFolder = desktopFolder; - pidls.items.AddInReserved(pidls.parent); - pidls.parent = NULL; - */ - - // CreateViewObject() doesn't show all context menu items - /* - HRESULT res = parentFolder->CreateViewObject( - GetParent(), IID_IContextMenu, (void**)&systemContextMenu); - */ - } - - CMyComPtr parentFolder; - RINOK(desktopFolder->BindToObject(pidls.parent, - NULL, IID_IShellFolder, (void**)&parentFolder)) - if (!parentFolder) - return E_FAIL; - - ODS("==== CPanel::CreateShellContextMenu pidls START"); - - pidls.items.ClearAndReserve(operatedIndices.Size()); - UString fileName; - FOR_VECTOR (i, operatedIndices) - { - fileName.Empty(); - Add_ItemRelPath2_To_String(operatedIndices[i], fileName); - /* ParseDisplayName() in win10 returns: - E_INVALIDARG : if empty name, or path with dots only: "." , ".." - HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) : if there is no such file - */ - LPITEMIDLIST pidl = NULL; - RINOK(ShellFolder_ParseDisplayName(parentFolder, - parentHWND_for_ParseDisplayName, - fileName, &pidl)) - if (!pidl) - return E_FAIL; - pidls.items.AddInReserved(pidl); - } - - ODS("==== CPanel::CreateShellContextMenu pidls END"); - // Get IContextMenu for items - RINOK(parentFolder->GetUIObjectOf(GetParent(), - pidls.items.Size(), (LPCITEMIDLIST *)(void *)pidls.items.ConstData(), - IID_IContextMenu, NULL, (void**)&systemContextMenu)) - ODS("==== CPanel::CreateShellContextMenu GetUIObjectOf finished"); - if (!systemContextMenu) - { - // ShowMessage("Unable to get context menu interface"); - return E_FAIL; - } - return S_OK; -} - - -// #define SHOW_DEBUG_FM_CTX_MENU - -#ifdef SHOW_DEBUG_FM_CTX_MENU - -static void PrintHex(UString &s, UInt32 v) -{ - char sz[32]; - ConvertUInt32ToHex(v, sz); - s += sz; -} - -static void PrintContextStr(UString &s, IContextMenu *ctxm, unsigned i, unsigned id, const char *name) -{ - s += " | "; - s += name; - s += ": "; - UString s1; - { - char buf[256]; - buf[0] = 0; - const HRESULT res = ctxm->GetCommandString(i, id, - NULL, buf, Z7_ARRAY_SIZE(buf) - 1); - if (res != S_OK) - { - PrintHex(s1, res); - s1.Add_Space(); - } - s1 += GetUnicodeString(buf); - } - UString s2; - { - wchar_t buf2[256]; - buf2[0] = 0; - const HRESULT res = ctxm->GetCommandString(i, id | GCS_UNICODE, - NULL, (char *)buf2, Z7_ARRAY_SIZE(buf2) - sizeof(wchar_t)); - if (res != S_OK) - { - PrintHex(s2, res); - s2.Add_Space(); - } - s2 += buf2; - } - s += s1; - if (s2.Compare(s1) != 0) - { - s += " Unicode: "; - s += s2; - } -} - -static void PrintAllContextItems(IContextMenu *ctxm, unsigned num) -{ - for (unsigned i = 0; i < num; i++) - { - UString s; - s.Add_UInt32(i); - s += ": "; - PrintContextStr(s, ctxm, i, GCS_VALIDATEA, "valid"); - PrintContextStr(s, ctxm, i, GCS_VERBA, "verb"); - PrintContextStr(s, ctxm, i, GCS_HELPTEXTA, "helptext"); - OutputDebugStringW(s); - } -} - -#endif - - -void CPanel::CreateSystemMenu(HMENU menuSpec, - bool showExtendedVerbs, - const CRecordVector &operatedIndices, - CMyComPtr &systemContextMenu) -{ - systemContextMenu.Release(); - - CreateShellContextMenu(operatedIndices, systemContextMenu); - - if (!systemContextMenu) - return; - - /* - // Set up a CMINVOKECOMMANDINFO structure. - CMINVOKECOMMANDINFO ci; - ZeroMemory(&ci, sizeof(ci)); - ci.cbSize = sizeof(CMINVOKECOMMANDINFO); - ci.hwnd = GetParent(); - */ - - /* - if (Sender == GoBtn) - { - // Verbs that can be used are cut, paste, - // properties, delete, and so on. - String action; - if (CutRb->Checked) - action = "cut"; - else if (CopyRb->Checked) - action = "copy"; - else if (DeleteRb->Checked) - action = "delete"; - else if (PropertiesRb->Checked) - action = "properties"; - - ci.lpVerb = action.c_str(); - result = cm->InvokeCommand(&ci); - if (result) - ShowMessage( - "Error copying file to clipboard."); - - } - else - */ - { - // HMENU hMenu = CreatePopupMenu(); - CMenu popupMenu; - CMenuDestroyer menuDestroyer(popupMenu); - if (!popupMenu.CreatePopup()) - throw 210503; - const HMENU hMenu = popupMenu; - DWORD flags = CMF_EXPLORE; - if (showExtendedVerbs) - flags |= Z7_WIN_CMF_EXTENDEDVERBS; - ODS("=== systemContextMenu->QueryContextMenu START"); - const HRESULT res = systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, flags); - ODS("=== systemContextMenu->QueryContextMenu END"); - if (SUCCEEDED(res)) - { - #ifdef SHOW_DEBUG_FM_CTX_MENU - PrintAllContextItems(systemContextMenu, (unsigned)res); - #endif - - CMenu menu; - menu.Attach(menuSpec); - CMenuItem menuItem; - menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; - menuItem.fType = MFT_STRING; - menuItem.hSubMenu = popupMenu.Detach(); - menuDestroyer.Disable(); - LangString(IDS_SYSTEM, menuItem.StringValue); - menu.InsertItem(0, true, menuItem); - } - /* - if (Cmd < 100 && Cmd != 0) - { - ci.lpVerb = MAKEINTRESOURCE(Cmd - 1); - ci.lpParameters = ""; - ci.lpDirectory = ""; - ci.nShow = SW_SHOWNORMAL; - cm->InvokeCommand(&ci); - } - // If Cmd is > 100 then it's one of our - // inserted menu items. - else - // Find the menu item. - for (int i = 0; i < popupMenu1->Items->Count; i++) - { - TMenuItem* menu = popupMenu1->Items->Items[i]; - // Call its OnClick handler. - if (menu->Command == Cmd - 100) - menu->OnClick(this); - } - // Release the memory allocated for the menu. - DestroyMenu(hMenu); - */ - } -} - -void CPanel::CreateFileMenu(HMENU menuSpec) -{ - CreateFileMenu(menuSpec, _sevenZipContextMenu, _systemContextMenu, true); // programMenu -} - -void CPanel::CreateSevenZipMenu(HMENU menuSpec, - bool showExtendedVerbs, - const CRecordVector &operatedIndices, - int firstDirIndex, - CMyComPtr &sevenZipContextMenu) -{ - sevenZipContextMenu.Release(); - - CMenu menu; - menu.Attach(menuSpec); - // CMenuDestroyer menuDestroyer(menu); - // menu.CreatePopup(); - - CZipContextMenu *contextMenuSpec = new CZipContextMenu; - CMyComPtr contextMenu = contextMenuSpec; - // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK) - { - /* - CMyComPtr initContextMenu; - if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK) - return; - */ - ODS("=== FileName List Add START") - // for (unsigned y = 0; y < 10000; y++, contextMenuSpec->_fileNames.Clear()) - GetFilePaths(operatedIndices, contextMenuSpec->_fileNames); - ODS("=== FileName List Add END") - contextMenuSpec->Init_For_7zFM(); - contextMenuSpec->_attribs.FirstDirIndex = firstDirIndex; - { - DWORD flags = CMF_EXPLORE; - if (showExtendedVerbs) - flags |= Z7_WIN_CMF_EXTENDEDVERBS; - const HRESULT res = contextMenu->QueryContextMenu(menu, - 0, // indexMenu - kSevenZipStartMenuID, // first - kSystemStartMenuID - 1, // last - flags); - ODS("=== contextMenu->QueryContextMenu END") - const bool sevenZipMenuCreated = SUCCEEDED(res); - if (sevenZipMenuCreated) - { - // if (res != 0) - { - // some "non-good" implementation of QueryContextMenu() could add some items to menu, but it return 0. - // so we still allow these items - sevenZipContextMenu = contextMenu; - #ifdef SHOW_DEBUG_FM_CTX_MENU - PrintAllContextItems(contextMenu, (unsigned)res); - #endif - } - } - else - { - // MessageBox_Error_HRESULT_Caption(res, L"QueryContextMenu"); - } - // int code = HRESULT_CODE(res); - // int nextItemID = code; - } - } -} - -static bool IsReadOnlyFolder(IFolderFolder *folder) -{ - if (!folder) - return false; - - bool res = false; - { - NCOM::CPropVariant prop; - if (folder->GetFolderProperty(kpidReadOnly, &prop) == S_OK) - if (prop.vt == VT_BOOL) - res = VARIANT_BOOLToBool(prop.boolVal); - } - return res; -} - -bool CPanel::IsThereReadOnlyFolder() const -{ - if (!_folderOperations) - return true; - if (IsReadOnlyFolder(_folder)) - return true; - FOR_VECTOR (i, _parentFolders) - { - if (IsReadOnlyFolder(_parentFolders[i].ParentFolder)) - return true; - } - return false; -} - -bool CPanel::CheckBeforeUpdate(UINT resourceID) -{ - if (!_folderOperations) - { - MessageBox_Error_UnsupportOperation(); - // resourceID = resourceID; - // MessageBoxErrorForUpdate(E_NOINTERFACE, resourceID); - return false; - } - - for (int i = (int)_parentFolders.Size(); i >= 0; i--) - { - IFolderFolder *folder; - if (i == (int)_parentFolders.Size()) - folder = _folder; - else - folder = _parentFolders[i].ParentFolder; - - if (!IsReadOnlyFolder(folder)) - continue; - - UString s; - AddLangString(s, resourceID); - s.Add_LF(); - AddLangString(s, IDS_OPERATION_IS_NOT_SUPPORTED); - s.Add_LF(); - if (i == 0) - s += GetFolderPath(folder); - else - s += _parentFolders[i - 1].VirtualPath; - s.Add_LF(); - AddLangString(s, IDS_PROP_READ_ONLY); - MessageBox_Error(s); - return false; - } - - return true; -} - -void CPanel::CreateFileMenu(HMENU menuSpec, - CMyComPtr &sevenZipContextMenu, - CMyComPtr &systemContextMenu, - bool programMenu) -{ - sevenZipContextMenu.Release(); - systemContextMenu.Release(); - - const bool showExtendedVerbs = IsKeyDown(VK_SHIFT); - - CRecordVector operatedIndices; - Get_ItemIndices_Operated(operatedIndices); - const int firstDirIndex = FindDir_InOperatedList(operatedIndices); - - CMenu menu; - menu.Attach(menuSpec); - - if (!IsArcFolder()) - { - CreateSevenZipMenu(menu, showExtendedVerbs, operatedIndices, firstDirIndex, sevenZipContextMenu); - // CreateSystemMenu is very slow if you call it inside ZIP archive with big number of files - // Windows probably can parse items inside ZIP archive. - if (g_App.ShowSystemMenu) - CreateSystemMenu(menu, showExtendedVerbs, operatedIndices, systemContextMenu); - } - - /* - if (menu.GetItemCount() > 0) - menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0); - */ - - CFileMenu fm; - - fm.readOnly = IsThereReadOnlyFolder(); - fm.isHashFolder = IsHashFolder(); - fm.isFsFolder = Is_IO_FS_Folder(); - fm.programMenu = programMenu; - fm.allAreFiles = (firstDirIndex == -1); - fm.numItems = operatedIndices.Size(); - - fm.isAltStreamsSupported = false; - - if (fm.numItems == 1) - fm.FilePath = us2fs(GetItemFullPath(operatedIndices[0])); - - if (_folderAltStreams) - { - if (operatedIndices.Size() <= 1) - { - UInt32 realIndex = (UInt32)(Int32)-1; - if (operatedIndices.Size() == 1) - realIndex = operatedIndices[0]; - Int32 val = 0; - if (_folderAltStreams->AreAltStreamsSupported(realIndex, &val) == S_OK) - fm.isAltStreamsSupported = IntToBool(val); - } - } - else - { - if (fm.numItems == 0) - fm.isAltStreamsSupported = IsFSFolder(); - else - fm.isAltStreamsSupported = IsFolder_with_FsItems(); - } - - fm.Load(menu, (unsigned)menu.GetItemCount()); -} - -bool CPanel::InvokePluginCommand(unsigned id) -{ - return InvokePluginCommand(id, _sevenZipContextMenu, _systemContextMenu); -} - -#if defined(_MSC_VER) && !defined(UNDER_CE) -#define use_CMINVOKECOMMANDINFOEX -/* CMINVOKECOMMANDINFOEX depends from (_WIN32_IE >= 0x0400) */ -#endif - -bool CPanel::InvokePluginCommand(unsigned id, - IContextMenu *sevenZipContextMenu, IContextMenu *systemContextMenu) -{ - UInt32 offset; - const bool isSystemMenu = (id >= kSystemStartMenuID); - if (isSystemMenu) - { - if (!systemContextMenu) - return false; - offset = id - kSystemStartMenuID; - } - else - { - if (!sevenZipContextMenu) - return false; - offset = id - kSevenZipStartMenuID; - } - - #ifdef use_CMINVOKECOMMANDINFOEX - CMINVOKECOMMANDINFOEX - #else - CMINVOKECOMMANDINFO - #endif - commandInfo; - - memset(&commandInfo, 0, sizeof(commandInfo)); - commandInfo.cbSize = sizeof(commandInfo); - - commandInfo.fMask = 0 - #ifdef use_CMINVOKECOMMANDINFOEX - | CMIC_MASK_UNICODE - #endif - ; - - commandInfo.hwnd = GetParent(); - commandInfo.lpVerb = (LPCSTR)(MAKEINTRESOURCE(offset)); - commandInfo.lpParameters = NULL; - // 19.01: fixed CSysString to AString - // MSDN suggest to send NULL: lpDirectory: This member is always NULL for menu items inserted by a Shell extension. - const AString currentFolderA (GetAnsiString(_currentFolderPrefix)); - commandInfo.lpDirectory = (LPCSTR)(currentFolderA); - commandInfo.nShow = SW_SHOW; - - #ifdef use_CMINVOKECOMMANDINFOEX - - commandInfo.lpParametersW = NULL; - commandInfo.lpTitle = ""; - - /* - system ContextMenu handler supports ContextMenu subhandlers. - so InvokeCommand() converts (command_offset) from global number to subhandler number. - XP-64 / win10: - system ContextMenu converts (command_offset) in lpVerb only, - and it keeps lpVerbW unchanged. - also explorer.exe sends 0 in lpVerbW. - We try to keep compatibility with Windows Explorer here. - */ - commandInfo.lpVerbW = NULL; - - const UString currentFolderUnicode = _currentFolderPrefix; - commandInfo.lpDirectoryW = currentFolderUnicode; - commandInfo.lpTitleW = L""; - // commandInfo.ptInvoke.x = xPos; - // commandInfo.ptInvoke.y = yPos; - commandInfo.ptInvoke.x = 0; - commandInfo.ptInvoke.y = 0; - - #endif - - HRESULT result; - if (isSystemMenu) - result = systemContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo)); - else - result = sevenZipContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo)); - if (result == NOERROR) - { - KillSelection(); - return true; - } - else - MessageBox_Error_HRESULT_Caption(result, L"InvokeCommand"); - return false; -} - -bool CPanel::OnContextMenu(HANDLE windowHandle, int xPos, int yPos) -{ - if (::GetParent((HWND)windowHandle) == _listView) - { - ShowColumnsContextMenu(xPos, yPos); - return true; - } - - if (windowHandle != _listView) - return false; - /* - POINT point; - point.x = xPos; - point.y = yPos; - if (!_listView.ScreenToClient(&point)) - return false; - - LVHITTESTINFO info; - info.pt = point; - int index = _listView.HitTest(&info); - */ - - CRecordVector operatedIndices; - Get_ItemIndices_Operated(operatedIndices); - - // negative x,y are possible for multi-screen modes. - // x=-1 && y=-1 for keyboard call (SHIFT+F10 and others). - if (xPos == -1 && yPos == -1) - { - if (operatedIndices.Size() == 0) - { - xPos = 0; - yPos = 0; - } - else - { - int itemIndex = _listView.GetNextItem(-1, LVNI_FOCUSED); - if (itemIndex == -1) - return false; - RECT rect; - if (!_listView.GetItemRect(itemIndex, &rect, LVIR_ICON)) - return false; - xPos = (rect.left + rect.right) / 2; - yPos = (rect.top + rect.bottom) / 2; - } - POINT point = {xPos, yPos}; - _listView.ClientToScreen(&point); - xPos = point.x; - yPos = point.y; - } - - CMenu menu; - CMenuDestroyer menuDestroyer(menu); - menu.CreatePopup(); - - CMyComPtr sevenZipContextMenu; - CMyComPtr systemContextMenu; - CreateFileMenu(menu, sevenZipContextMenu, systemContextMenu, false); // programMenu - - const unsigned id = (unsigned)menu.Track(TPM_LEFTALIGN - #ifndef UNDER_CE - | TPM_RIGHTBUTTON - #endif - | TPM_RETURNCMD | TPM_NONOTIFY, - xPos, yPos, _listView); - - if (id == 0) - return true; - - if (id >= kMenuCmdID_Plugin_Start) - { - InvokePluginCommand(id, sevenZipContextMenu, systemContextMenu); - return true; - } - if (ExecuteFileCommand(id)) - return true; - return true; -} +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/COM.h" +#include "../../../Windows/Clipboard.h" +#include "../../../Windows/Menu.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" + +#include "../../PropID.h" +#include "../Common/PropIDUtils.h" +#include "../Explorer/ContextMenu.h" + +#include "App.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "ListViewDialog.h" +#include "MyLoadMenu.h" +#include "PropertyName.h" + +#include "PropertyNameRes.h" +#include "resource.h" + +// #define SHOW_DEBUG_PANEL_MENU + +using namespace NWindows; + +extern +LONG g_DllRefCount; +LONG g_DllRefCount = 0; + +static const UINT kSevenZipStartMenuID = kMenuCmdID_Plugin_Start; +static const UINT kSystemStartMenuID = kMenuCmdID_Plugin_Start + 400; + + +#ifdef SHOW_DEBUG_PANEL_MENU +static void Print_Ptr(void *p, const char *s) +{ + char temp[32]; + ConvertUInt64ToHex((UInt64)(void *)p, temp); + AString m; + m += temp; + m.Add_Space(); + m += s; + OutputDebugStringA(m); +} +#define ODS(sz) { Print_Ptr(this, sz); } +#define ODS_U(s) { OutputDebugStringW(s); } +#else +#define ODS(sz) +#define ODS_U(s) +#endif + + +void CPanel::InvokeSystemCommand(const char *command) +{ + NCOM::CComInitializer comInitializer; + if (!IsFsOrPureDrivesFolder()) + return; + CRecordVector operatedIndices; + Get_ItemIndices_Operated(operatedIndices); + if (operatedIndices.IsEmpty()) + return; + CMyComPtr contextMenu; + if (CreateShellContextMenu(operatedIndices, contextMenu) != S_OK) + return; + + CMINVOKECOMMANDINFO ci; + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(CMINVOKECOMMANDINFO); + ci.hwnd = GetParent(); + ci.lpVerb = command; + contextMenu->InvokeCommand(&ci); +} + +static const char * const kSeparator = "------------------------"; +static const char * const kSeparatorSmall = "----------------"; + +extern UString ConvertSizeToString(UInt64 value) throw(); +bool IsSizeProp(UINT propID) throw(); + +UString GetOpenArcErrorMessage(UInt32 errorFlags); + + +static void AddListAscii(CListViewDialog &dialog, const char *s) +{ + dialog.Strings.Add((UString)s); + dialog.Values.AddNew(); +} + +static void AddSeparator(CListViewDialog &dialog) +{ + AddListAscii(dialog, kSeparator); +} + +static void AddSeparatorSmall(CListViewDialog &dialog) +{ + AddListAscii(dialog, kSeparatorSmall); +} + +static void AddPropertyPair(const UString &name, const UString &val, CListViewDialog &dialog) +{ + dialog.Strings.Add(name); + dialog.Values.Add(val); +} + + +static void AddPropertyString(PROPID propID, const wchar_t *nameBSTR, + const NCOM::CPropVariant &prop, CListViewDialog &dialog) +{ + if (prop.vt != VT_EMPTY) + { + UString val; + + if (propID == kpidErrorFlags || + propID == kpidWarningFlags) + { + UInt32 flags = GetOpenArcErrorFlags(prop); + if (flags == 0) + return; + if (flags != 0) + val = GetOpenArcErrorMessage(flags); + } + + if (val.IsEmpty()) + { + if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID)) + { + UInt64 v = 0; + ConvertPropVariantToUInt64(prop, v); + val = ConvertSizeToString(v); + } + else + ConvertPropertyToString2(val, prop, propID, 9); // we send 9 - is ns precision + } + + if (!val.IsEmpty()) + { + if (propID == kpidErrorType) + { + AddPropertyPair(L"Open WARNING:", L"Cannot open the file as expected archive type", dialog); + } + AddPropertyPair(GetNameOfProperty(propID, nameBSTR), val, dialog); + } + } +} + + +static void AddPropertyString(PROPID propID, UInt64 val, CListViewDialog &dialog) +{ + NCOM::CPropVariant prop = val; + AddPropertyString(propID, NULL, prop, dialog); +} + + +static const Byte kSpecProps[] = +{ + kpidPath, + kpidType, + kpidErrorType, + kpidError, + kpidErrorFlags, + kpidWarning, + kpidWarningFlags, + kpidOffset, + kpidPhySize, + kpidTailSize +}; + +void CPanel::Properties() +{ + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (!getFolderArcProps) + { + InvokeSystemCommand("properties"); + return; + } + + { + CListViewDialog message; + // message.DeleteIsAllowed = false; + // message.SelectFirst = false; + + CRecordVector operatedIndices; + Get_ItemIndices_Operated(operatedIndices); + + if (operatedIndices.Size() == 1) + { + UInt32 index = operatedIndices[0]; + // message += "Item:\n"); + UInt32 numProps; + if (_folder->GetNumberOfProperties(&numProps) == S_OK) + { + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE varType; + + if (_folder->GetPropertyInfo(i, &name, &propID, &varType) != S_OK) + continue; + + NCOM::CPropVariant prop; + if (_folder->GetProperty(index, propID, &prop) != S_OK) + continue; + AddPropertyString(propID, name, prop, message); + } + } + + + if (_folderRawProps) + { + _folderRawProps->GetNumRawProps(&numProps); + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK) + continue; + + const void *data; + UInt32 dataSize; + UInt32 propType; + if (_folderRawProps->GetRawProp(index, propID, &data, &dataSize, &propType) != S_OK) + continue; + + if (dataSize != 0) + { + AString s; + if (propID == kpidNtSecure) + ConvertNtSecureToString((const Byte *)data, dataSize, s); + else + { + const unsigned kMaxDataSize = 1 << 8; + if (dataSize > kMaxDataSize) + { + s += "data:"; + s.Add_UInt32(dataSize); + } + else + { + char temp[kMaxDataSize * 2 + 2]; + if (dataSize <= 8 && (propID == kpidCRC || propID == kpidChecksum)) + ConvertDataToHex_Upper(temp, (const Byte *)data, dataSize); + else + ConvertDataToHex_Lower(temp, (const Byte *)data, dataSize); + s += temp; + } + } + AddPropertyPair(GetNameOfProperty(propID, name), (UString)s.Ptr(), message); + } + } + } + + AddSeparator(message); + } + else if (operatedIndices.Size() >= 1) + { + UInt64 packSize = 0; + UInt64 unpackSize = 0; + UInt64 numFiles = 0; + UInt64 numDirs = 0; + + FOR_VECTOR (i, operatedIndices) + { + const UInt32 index = operatedIndices[i]; + unpackSize += GetItemSize(index); + packSize += GetItem_UInt64Prop(index, kpidPackSize); + if (IsItem_Folder(index)) + { + numDirs++; + numDirs += GetItem_UInt64Prop(index, kpidNumSubDirs); + numFiles += GetItem_UInt64Prop(index, kpidNumSubFiles); + } + else + numFiles++; + } + { + wchar_t temp[32]; + ConvertUInt32ToString(operatedIndices.Size(), temp); + AddPropertyPair(L"", MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, temp), message); + } + + if (numDirs != 0) + AddPropertyString(kpidNumSubDirs, numDirs, message); + if (numFiles != 0) + AddPropertyString(kpidNumSubFiles, numFiles, message); + AddPropertyString(kpidSize, unpackSize, message); + AddPropertyString(kpidPackSize, packSize, message); + + AddSeparator(message); + } + + + /* + AddLangString(message, IDS_PROP_FILE_TYPE); + message += kPropValueSeparator; + message += GetFolderTypeID(); + message.Add_LF(); + */ + + { + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK) + { + AddPropertyString(kpidName, L"Path", prop, message); + } + } + + CMyComPtr folderProperties; + _folder.QueryInterface(IID_IFolderProperties, &folderProperties); + if (folderProperties) + { + UInt32 numProps; + if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK) + { + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK) + continue; + NCOM::CPropVariant prop; + if (_folder->GetFolderProperty(propID, &prop) != S_OK) + continue; + AddPropertyString(propID, name, prop, message); + } + } + } + + if (getFolderArcProps) + { + CMyComPtr getProps; + getFolderArcProps->GetFolderArcProps(&getProps); + if (getProps) + { + UInt32 numLevels; + if (getProps->GetArcNumLevels(&numLevels) != S_OK) + numLevels = 0; + for (UInt32 level2 = 0; level2 < numLevels; level2++) + { + { + UInt32 level = numLevels - 1 - level2; + UInt32 numProps; + if (getProps->GetArcNumProps(level, &numProps) == S_OK) + { + const int kNumSpecProps = Z7_ARRAY_SIZE(kSpecProps); + + AddSeparator(message); + + for (Int32 i = -(int)kNumSpecProps; i < (Int32)numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + if (i < 0) + propID = kSpecProps[i + kNumSpecProps]; + else if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK) + continue; + NCOM::CPropVariant prop; + if (getProps->GetArcProp(level, propID, &prop) != S_OK) + continue; + AddPropertyString(propID, name, prop, message); + } + } + } + + if (level2 < numLevels - 1) + { + const UInt32 level = numLevels - 1 - level2; + UInt32 numProps; + if (getProps->GetArcNumProps2(level, &numProps) == S_OK) + { + AddSeparatorSmall(message); + for (UInt32 i = 0; i < numProps; i++) + { + CMyComBSTR name; + PROPID propID; + VARTYPE vt; + if (getProps->GetArcPropInfo2(level, i, &name, &propID, &vt) != S_OK) + continue; + NCOM::CPropVariant prop; + if (getProps->GetArcProp2(level, propID, &prop) != S_OK) + continue; + AddPropertyString(propID, name, prop, message); + } + } + } + } + + { + // we ERROR message for NonOpen level + bool needSep = true; + const int kNumSpecProps = Z7_ARRAY_SIZE(kSpecProps); + for (Int32 i = -(int)kNumSpecProps; i < 0; i++) + { + CMyComBSTR name; + const PROPID propID = kSpecProps[i + kNumSpecProps]; + NCOM::CPropVariant prop; + if (getProps->GetArcProp(numLevels, propID, &prop) != S_OK) + continue; + if (needSep) + { + AddSeparator(message); + AddSeparator(message); + needSep = false; + } + AddPropertyString(propID, name, prop, message); + } + } + + } + } + + message.Title = LangString(IDS_PROPERTIES); + message.NumColumns = 2; + message.Create(GetParent()); + } +} + + + +void CPanel::EditCut() +{ + // InvokeSystemCommand("cut"); +} + +void CPanel::EditCopy() +{ + /* + CMyComPtr getFolderArcProps; + _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps); + if (!getFolderArcProps) + { + InvokeSystemCommand("copy"); + return; + } + */ + UString s; + CRecordVector indices; + Get_ItemIndices_Selected(indices); + FOR_VECTOR (i, indices) + { + if (i != 0) + s += "\xD\n"; + s += GetItemName(indices[i]); + } + ClipboardSetText(_mainWindow, s); +} + +void CPanel::EditPaste() +{ + /* + UStringVector names; + ClipboardGetFileNames(names); + CopyFromNoAsk(names); + UString s; + for (int i = 0; i < names.Size(); i++) + { + s += L' '; + s += names[i]; + } + + MessageBoxW(0, s, L"", 0); + */ + + // InvokeSystemCommand("paste"); +} + + + +struct CFolderPidls +{ + LPITEMIDLIST parent; + CRecordVector items; + + CFolderPidls(): parent(NULL) {} + ~CFolderPidls() + { + FOR_VECTOR (i, items) + CoTaskMemFree(items[i]); + CoTaskMemFree(parent); + } +}; + + +static HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder, + HWND hwnd, const UString &path, LPITEMIDLIST *ppidl) +{ + ULONG eaten = 0; + return shellFolder->ParseDisplayName(hwnd, NULL, + path.Ptr_non_const(), &eaten, ppidl, NULL); +} + + +HRESULT CPanel::CreateShellContextMenu( + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu) +{ + ODS("==== CPanel::CreateShellContextMenu"); + systemContextMenu.Release(); + UString folderPath = GetFsPath(); + + CMyComPtr desktopFolder; + RINOK(::SHGetDesktopFolder(&desktopFolder)) + if (!desktopFolder) + { + // ShowMessage("Failed to get Desktop folder"); + return E_FAIL; + } + + CFolderPidls pidls; + // NULL is allowed for parentHWND in ParseDisplayName() + const HWND parentHWND_for_ParseDisplayName = GetParent(); + // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer" + /* win10: ParseDisplayName() supports folder path with tail slash + ParseDisplayName() returns { + E_INVALIDARG : path with super path prefix "\\\\?\\" + ERROR_FILE_NOT_FOUND : path for network share (\\server\path1\long path2") larger than MAX_PATH + } */ + const HRESULT res = ShellFolder_ParseDisplayName(desktopFolder, + parentHWND_for_ParseDisplayName, + folderPath, &pidls.parent); + if (res != S_OK) + { + ODS_U(folderPath); + if (res != E_INVALIDARG) + return res; + if (!NFile::NName::If_IsSuperPath_RemoveSuperPrefix(folderPath)) + return res; + RINOK(ShellFolder_ParseDisplayName(desktopFolder, + parentHWND_for_ParseDisplayName, + folderPath, &pidls.parent)) + } + if (!pidls.parent) + return E_FAIL; + + /* + UString path2; + NShell::GetPathFromIDList(pidls.parent, path2); + ODS_U(path2); + */ + + if (operatedIndices.IsEmpty()) + { + // how to get IContextMenu, if there are no selected files? + return E_FAIL; + + /* + xp64 : + 1) we can't use GetUIObjectOf() with (numItems == 0), it throws exception + 2) we can't use desktopFolder->GetUIObjectOf() with absolute pidls of folder + context menu items are different in that case: + "Open / Explorer" for folder + "Delete" for "My Computer" icon + "Preperties" for "System" + */ + /* + parentFolder = desktopFolder; + pidls.items.AddInReserved(pidls.parent); + pidls.parent = NULL; + */ + + // CreateViewObject() doesn't show all context menu items + /* + HRESULT res = parentFolder->CreateViewObject( + GetParent(), IID_IContextMenu, (void**)&systemContextMenu); + */ + } + + CMyComPtr parentFolder; + RINOK(desktopFolder->BindToObject(pidls.parent, + NULL, IID_IShellFolder, (void**)&parentFolder)) + if (!parentFolder) + return E_FAIL; + + ODS("==== CPanel::CreateShellContextMenu pidls START"); + + pidls.items.ClearAndReserve(operatedIndices.Size()); + UString fileName; + FOR_VECTOR (i, operatedIndices) + { + fileName.Empty(); + Add_ItemRelPath2_To_String(operatedIndices[i], fileName); + /* ParseDisplayName() in win10 returns: + E_INVALIDARG : if empty name, or path with dots only: "." , ".." + HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) : if there is no such file + */ + LPITEMIDLIST pidl = NULL; + RINOK(ShellFolder_ParseDisplayName(parentFolder, + parentHWND_for_ParseDisplayName, + fileName, &pidl)) + if (!pidl) + return E_FAIL; + pidls.items.AddInReserved(pidl); + } + + ODS("==== CPanel::CreateShellContextMenu pidls END"); + // Get IContextMenu for items + RINOK(parentFolder->GetUIObjectOf(GetParent(), + pidls.items.Size(), (LPCITEMIDLIST *)(void *)pidls.items.ConstData(), + IID_IContextMenu, NULL, (void**)&systemContextMenu)) + ODS("==== CPanel::CreateShellContextMenu GetUIObjectOf finished"); + if (!systemContextMenu) + { + // ShowMessage("Unable to get context menu interface"); + return E_FAIL; + } + return S_OK; +} + + +// #define SHOW_DEBUG_FM_CTX_MENU + +#ifdef SHOW_DEBUG_FM_CTX_MENU + +static void PrintHex(UString &s, UInt32 v) +{ + char sz[32]; + ConvertUInt32ToHex(v, sz); + s += sz; +} + +static void PrintContextStr(UString &s, IContextMenu *ctxm, unsigned i, unsigned id, const char *name) +{ + s += " | "; + s += name; + s += ": "; + UString s1; + { + char buf[256]; + buf[0] = 0; + const HRESULT res = ctxm->GetCommandString(i, id, + NULL, buf, Z7_ARRAY_SIZE(buf) - 1); + if (res != S_OK) + { + PrintHex(s1, res); + s1.Add_Space(); + } + s1 += GetUnicodeString(buf); + } + UString s2; + { + wchar_t buf2[256]; + buf2[0] = 0; + const HRESULT res = ctxm->GetCommandString(i, id | GCS_UNICODE, + NULL, (char *)buf2, Z7_ARRAY_SIZE(buf2) - sizeof(wchar_t)); + if (res != S_OK) + { + PrintHex(s2, res); + s2.Add_Space(); + } + s2 += buf2; + } + s += s1; + if (s2.Compare(s1) != 0) + { + s += " Unicode: "; + s += s2; + } +} + +static void PrintAllContextItems(IContextMenu *ctxm, unsigned num) +{ + for (unsigned i = 0; i < num; i++) + { + UString s; + s.Add_UInt32(i); + s += ": "; + PrintContextStr(s, ctxm, i, GCS_VALIDATEA, "valid"); + PrintContextStr(s, ctxm, i, GCS_VERBA, "verb"); + PrintContextStr(s, ctxm, i, GCS_HELPTEXTA, "helptext"); + OutputDebugStringW(s); + } +} + +#endif + + +void CPanel::CreateSystemMenu(HMENU menuSpec, + bool showExtendedVerbs, + const CRecordVector &operatedIndices, + CMyComPtr &systemContextMenu) +{ + systemContextMenu.Release(); + + CreateShellContextMenu(operatedIndices, systemContextMenu); + + if (!systemContextMenu) + return; + + /* + // Set up a CMINVOKECOMMANDINFO structure. + CMINVOKECOMMANDINFO ci; + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(CMINVOKECOMMANDINFO); + ci.hwnd = GetParent(); + */ + + /* + if (Sender == GoBtn) + { + // Verbs that can be used are cut, paste, + // properties, delete, and so on. + String action; + if (CutRb->Checked) + action = "cut"; + else if (CopyRb->Checked) + action = "copy"; + else if (DeleteRb->Checked) + action = "delete"; + else if (PropertiesRb->Checked) + action = "properties"; + + ci.lpVerb = action.c_str(); + result = cm->InvokeCommand(&ci); + if (result) + ShowMessage( + "Error copying file to clipboard."); + + } + else + */ + { + // HMENU hMenu = CreatePopupMenu(); + CMenu popupMenu; + CMenuDestroyer menuDestroyer(popupMenu); + if (!popupMenu.CreatePopup()) + throw 210503; + const HMENU hMenu = popupMenu; + DWORD flags = CMF_EXPLORE; + if (showExtendedVerbs) + flags |= Z7_WIN_CMF_EXTENDEDVERBS; + ODS("=== systemContextMenu->QueryContextMenu START"); + const HRESULT res = systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, flags); + ODS("=== systemContextMenu->QueryContextMenu END"); + if (SUCCEEDED(res)) + { + #ifdef SHOW_DEBUG_FM_CTX_MENU + PrintAllContextItems(systemContextMenu, (unsigned)res); + #endif + + CMenu menu; + menu.Attach(menuSpec); + CMenuItem menuItem; + menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID; + menuItem.fType = MFT_STRING; + menuItem.hSubMenu = popupMenu.Detach(); + menuDestroyer.Disable(); + LangString(IDS_SYSTEM, menuItem.StringValue); + menu.InsertItem(0, true, menuItem); + } + /* + if (Cmd < 100 && Cmd != 0) + { + ci.lpVerb = MAKEINTRESOURCE(Cmd - 1); + ci.lpParameters = ""; + ci.lpDirectory = ""; + ci.nShow = SW_SHOWNORMAL; + cm->InvokeCommand(&ci); + } + // If Cmd is > 100 then it's one of our + // inserted menu items. + else + // Find the menu item. + for (int i = 0; i < popupMenu1->Items->Count; i++) + { + TMenuItem* menu = popupMenu1->Items->Items[i]; + // Call its OnClick handler. + if (menu->Command == Cmd - 100) + menu->OnClick(this); + } + // Release the memory allocated for the menu. + DestroyMenu(hMenu); + */ + } +} + +void CPanel::CreateFileMenu(HMENU menuSpec) +{ + CreateFileMenu(menuSpec, _sevenZipContextMenu, _systemContextMenu, true); // programMenu +} + +void CPanel::CreateSevenZipMenu(HMENU menuSpec, + bool showExtendedVerbs, + const CRecordVector &operatedIndices, + int firstDirIndex, + CMyComPtr &sevenZipContextMenu) +{ + sevenZipContextMenu.Release(); + + CMenu menu; + menu.Attach(menuSpec); + // CMenuDestroyer menuDestroyer(menu); + // menu.CreatePopup(); + + CZipContextMenu *contextMenuSpec = new CZipContextMenu; + CMyComPtr contextMenu = contextMenuSpec; + // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK) + { + /* + CMyComPtr initContextMenu; + if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK) + return; + */ + ODS("=== FileName List Add START") + // for (unsigned y = 0; y < 10000; y++, contextMenuSpec->_fileNames.Clear()) + GetFilePaths(operatedIndices, contextMenuSpec->_fileNames); + ODS("=== FileName List Add END") + contextMenuSpec->Init_For_7zFM(); + contextMenuSpec->_attribs.FirstDirIndex = firstDirIndex; + { + DWORD flags = CMF_EXPLORE; + if (showExtendedVerbs) + flags |= Z7_WIN_CMF_EXTENDEDVERBS; + const HRESULT res = contextMenu->QueryContextMenu(menu, + 0, // indexMenu + kSevenZipStartMenuID, // first + kSystemStartMenuID - 1, // last + flags); + ODS("=== contextMenu->QueryContextMenu END") + const bool sevenZipMenuCreated = SUCCEEDED(res); + if (sevenZipMenuCreated) + { + // if (res != 0) + { + // some "non-good" implementation of QueryContextMenu() could add some items to menu, but it return 0. + // so we still allow these items + sevenZipContextMenu = contextMenu; + #ifdef SHOW_DEBUG_FM_CTX_MENU + PrintAllContextItems(contextMenu, (unsigned)res); + #endif + } + } + else + { + // MessageBox_Error_HRESULT_Caption(res, L"QueryContextMenu"); + } + // int code = HRESULT_CODE(res); + // int nextItemID = code; + } + } +} + +static bool IsReadOnlyFolder(IFolderFolder *folder) +{ + if (!folder) + return false; + + bool res = false; + { + NCOM::CPropVariant prop; + if (folder->GetFolderProperty(kpidReadOnly, &prop) == S_OK) + if (prop.vt == VT_BOOL) + res = VARIANT_BOOLToBool(prop.boolVal); + } + return res; +} + +bool CPanel::IsThereReadOnlyFolder() const +{ + if (!_folderOperations) + return true; + if (IsReadOnlyFolder(_folder)) + return true; + FOR_VECTOR (i, _parentFolders) + { + if (IsReadOnlyFolder(_parentFolders[i].ParentFolder)) + return true; + } + return false; +} + +bool CPanel::CheckBeforeUpdate(UINT resourceID) +{ + if (!_folderOperations) + { + MessageBox_Error_UnsupportOperation(); + // resourceID = resourceID; + // MessageBoxErrorForUpdate(E_NOINTERFACE, resourceID); + return false; + } + + for (int i = (int)_parentFolders.Size(); i >= 0; i--) + { + IFolderFolder *folder; + if (i == (int)_parentFolders.Size()) + folder = _folder; + else + folder = _parentFolders[i].ParentFolder; + + if (!IsReadOnlyFolder(folder)) + continue; + + UString s; + AddLangString(s, resourceID); + s.Add_LF(); + AddLangString(s, IDS_OPERATION_IS_NOT_SUPPORTED); + s.Add_LF(); + if (i == 0) + s += GetFolderPath(folder); + else + s += _parentFolders[i - 1].VirtualPath; + s.Add_LF(); + AddLangString(s, IDS_PROP_READ_ONLY); + MessageBox_Error(s); + return false; + } + + return true; +} + +void CPanel::CreateFileMenu(HMENU menuSpec, + CMyComPtr &sevenZipContextMenu, + CMyComPtr &systemContextMenu, + bool programMenu) +{ + sevenZipContextMenu.Release(); + systemContextMenu.Release(); + + const bool showExtendedVerbs = IsKeyDown(VK_SHIFT); + + CRecordVector operatedIndices; + Get_ItemIndices_Operated(operatedIndices); + const int firstDirIndex = FindDir_InOperatedList(operatedIndices); + + CMenu menu; + menu.Attach(menuSpec); + + if (!IsArcFolder()) + { + CreateSevenZipMenu(menu, showExtendedVerbs, operatedIndices, firstDirIndex, sevenZipContextMenu); + // CreateSystemMenu is very slow if you call it inside ZIP archive with big number of files + // Windows probably can parse items inside ZIP archive. + if (g_App.ShowSystemMenu) + CreateSystemMenu(menu, showExtendedVerbs, operatedIndices, systemContextMenu); + } + + /* + if (menu.GetItemCount() > 0) + menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0); + */ + + CFileMenu fm; + + fm.readOnly = IsThereReadOnlyFolder(); + fm.isHashFolder = IsHashFolder(); + fm.isFsFolder = Is_IO_FS_Folder(); + fm.programMenu = programMenu; + fm.allAreFiles = (firstDirIndex == -1); + fm.numItems = operatedIndices.Size(); + + fm.isAltStreamsSupported = false; + + if (fm.numItems == 1) + fm.FilePath = us2fs(GetItemFullPath(operatedIndices[0])); + + if (_folderAltStreams) + { + if (operatedIndices.Size() <= 1) + { + UInt32 realIndex = (UInt32)(Int32)-1; + if (operatedIndices.Size() == 1) + realIndex = operatedIndices[0]; + Int32 val = 0; + if (_folderAltStreams->AreAltStreamsSupported(realIndex, &val) == S_OK) + fm.isAltStreamsSupported = IntToBool(val); + } + } + else + { + if (fm.numItems == 0) + fm.isAltStreamsSupported = IsFSFolder(); + else + fm.isAltStreamsSupported = IsFolder_with_FsItems(); + } + + fm.Load(menu, (unsigned)menu.GetItemCount()); +} + +bool CPanel::InvokePluginCommand(unsigned id) +{ + return InvokePluginCommand(id, _sevenZipContextMenu, _systemContextMenu); +} + +#if defined(_MSC_VER) && !defined(UNDER_CE) +#define use_CMINVOKECOMMANDINFOEX +/* CMINVOKECOMMANDINFOEX depends from (_WIN32_IE >= 0x0400) */ +#endif + +bool CPanel::InvokePluginCommand(unsigned id, + IContextMenu *sevenZipContextMenu, IContextMenu *systemContextMenu) +{ + UInt32 offset; + const bool isSystemMenu = (id >= kSystemStartMenuID); + if (isSystemMenu) + { + if (!systemContextMenu) + return false; + offset = id - kSystemStartMenuID; + } + else + { + if (!sevenZipContextMenu) + return false; + offset = id - kSevenZipStartMenuID; + } + + #ifdef use_CMINVOKECOMMANDINFOEX + CMINVOKECOMMANDINFOEX + #else + CMINVOKECOMMANDINFO + #endif + commandInfo; + + memset(&commandInfo, 0, sizeof(commandInfo)); + commandInfo.cbSize = sizeof(commandInfo); + + commandInfo.fMask = 0 + #ifdef use_CMINVOKECOMMANDINFOEX + | CMIC_MASK_UNICODE + #endif + ; + + commandInfo.hwnd = GetParent(); + commandInfo.lpVerb = (LPCSTR)(MAKEINTRESOURCE(offset)); + commandInfo.lpParameters = NULL; + // 19.01: fixed CSysString to AString + // MSDN suggest to send NULL: lpDirectory: This member is always NULL for menu items inserted by a Shell extension. + const AString currentFolderA (GetAnsiString(_currentFolderPrefix)); + commandInfo.lpDirectory = (LPCSTR)(currentFolderA); + commandInfo.nShow = SW_SHOW; + + #ifdef use_CMINVOKECOMMANDINFOEX + + commandInfo.lpParametersW = NULL; + commandInfo.lpTitle = ""; + + /* + system ContextMenu handler supports ContextMenu subhandlers. + so InvokeCommand() converts (command_offset) from global number to subhandler number. + XP-64 / win10: + system ContextMenu converts (command_offset) in lpVerb only, + and it keeps lpVerbW unchanged. + also explorer.exe sends 0 in lpVerbW. + We try to keep compatibility with Windows Explorer here. + */ + commandInfo.lpVerbW = NULL; + + const UString currentFolderUnicode = _currentFolderPrefix; + commandInfo.lpDirectoryW = currentFolderUnicode; + commandInfo.lpTitleW = L""; + // commandInfo.ptInvoke.x = xPos; + // commandInfo.ptInvoke.y = yPos; + commandInfo.ptInvoke.x = 0; + commandInfo.ptInvoke.y = 0; + + #endif + + HRESULT result; + if (isSystemMenu) + result = systemContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo)); + else + result = sevenZipContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo)); + if (result == NOERROR) + { + KillSelection(); + return true; + } + else + MessageBox_Error_HRESULT_Caption(result, L"InvokeCommand"); + return false; +} + +bool CPanel::OnContextMenu(HANDLE windowHandle, int xPos, int yPos) +{ + if (::GetParent((HWND)windowHandle) == _listView) + { + ShowColumnsContextMenu(xPos, yPos); + return true; + } + + if (windowHandle != _listView) + return false; + /* + POINT point; + point.x = xPos; + point.y = yPos; + if (!_listView.ScreenToClient(&point)) + return false; + + LVHITTESTINFO info; + info.pt = point; + int index = _listView.HitTest(&info); + */ + + CRecordVector operatedIndices; + Get_ItemIndices_Operated(operatedIndices); + + // negative x,y are possible for multi-screen modes. + // x=-1 && y=-1 for keyboard call (SHIFT+F10 and others). + if (xPos == -1 && yPos == -1) + { + if (operatedIndices.Size() == 0) + { + xPos = 0; + yPos = 0; + } + else + { + int itemIndex = _listView.GetNextItem(-1, LVNI_FOCUSED); + if (itemIndex == -1) + return false; + RECT rect; + if (!_listView.GetItemRect(itemIndex, &rect, LVIR_ICON)) + return false; + xPos = (rect.left + rect.right) / 2; + yPos = (rect.top + rect.bottom) / 2; + } + POINT point = {xPos, yPos}; + _listView.ClientToScreen(&point); + xPos = point.x; + yPos = point.y; + } + + CMenu menu; + CMenuDestroyer menuDestroyer(menu); + menu.CreatePopup(); + + CMyComPtr sevenZipContextMenu; + CMyComPtr systemContextMenu; + CreateFileMenu(menu, sevenZipContextMenu, systemContextMenu, false); // programMenu + + const unsigned id = (unsigned)menu.Track(TPM_LEFTALIGN + #ifndef UNDER_CE + | TPM_RIGHTBUTTON + #endif + | TPM_RETURNCMD | TPM_NONOTIFY, + xPos, yPos, _listView); + + if (id == 0) + return true; + + if (id >= kMenuCmdID_Plugin_Start) + { + InvokePluginCommand(id, sevenZipContextMenu, systemContextMenu); + return true; + } + if (ExecuteFileCommand(id)) + return true; + return true; +} diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp index 231a8898d..8b162244d 100644 --- a/CPP/7zip/UI/FileManager/PanelOperations.cpp +++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp @@ -1,533 +1,533 @@ -// PanelOperations.cpp - -#include "StdAfx.h" - -#include "../../../Common/DynamicBuffer.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/COM.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "ComboDialog.h" - -#include "FSFolder.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "Panel.h" -#include "UpdateCallback100.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NName; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -enum EFolderOpType -{ - FOLDER_TYPE_CREATE_FOLDER = 0, - FOLDER_TYPE_DELETE = 1, - FOLDER_TYPE_RENAME = 2 -}; - -class CThreadFolderOperations: public CProgressThreadVirt -{ - HRESULT ProcessVirt() Z7_override; -public: - EFolderOpType OpType; - UString Name; - UInt32 Index; - CRecordVector Indices; - - CMyComPtr FolderOperations; - CMyComPtr UpdateCallback; - CUpdateCallback100Imp *UpdateCallbackSpec; - - CThreadFolderOperations(EFolderOpType opType): OpType(opType) {} - HRESULT DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError); -}; - -HRESULT CThreadFolderOperations::ProcessVirt() -{ - NCOM::CComInitializer comInitializer; - switch ((int)OpType) - { - case FOLDER_TYPE_CREATE_FOLDER: - return FolderOperations->CreateFolder(Name, UpdateCallback); - case FOLDER_TYPE_DELETE: - return FolderOperations->Delete(Indices.ConstData(), Indices.Size(), UpdateCallback); - case FOLDER_TYPE_RENAME: - return FolderOperations->Rename(Index, Name, UpdateCallback); - default: - return E_FAIL; - } -} - - -HRESULT CThreadFolderOperations::DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError) -{ - UpdateCallbackSpec = new CUpdateCallback100Imp; - UpdateCallback = UpdateCallbackSpec; - UpdateCallbackSpec->ProgressDialog = this; - - WaitMode = true; - Sync.FinalMessage.ErrorMessage.Title = titleError; - - UpdateCallbackSpec->Init(); - - if (panel._parentFolders.Size() > 0) - { - const CFolderLink &fl = panel._parentFolders.Back(); - UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword; - UpdateCallbackSpec->Password = fl.Password; - } - - MainWindow = panel._mainWindow; // panel.GetParent() - MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); - MainAddTitle = progressTitle + L' '; - - RINOK(Create(progressTitle, MainWindow)) - return Result; -} - -#ifndef _UNICODE -typedef int (WINAPI * Func_SHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp); -#endif - -/* -void CPanel::MessageBoxErrorForUpdate(HRESULT errorCode, UINT resourceID) -{ - if (errorCode == E_NOINTERFACE) - MessageBox_Error_UnsupportOperation(); - else - MessageBox_Error_HRESULT_Caption(errorCode, LangString(resourceID)); -} -*/ - -void CPanel::DeleteItems(bool NON_CE_VAR(toRecycleBin)) -{ - CDisableTimerProcessing disableTimerProcessing(*this); - CRecordVector indices; - Get_ItemIndices_Operated(indices); - if (indices.IsEmpty()) - return; - CSelectedState state; - SaveSelectedState(state); - - #ifndef UNDER_CE - // WM6 / SHFileOperationW doesn't ask user! So we use internal delete - if (IsFSFolder() && toRecycleBin) - { - bool useInternalDelete = false; - #ifndef _UNICODE - if (!g_IsNT) - { - CDynamicBuffer buffer; - FOR_VECTOR (i, indices) - { - const AString path (GetSystemString(GetItemFullPath(indices[i]))); - buffer.AddData(path, path.Len() + 1); - } - *buffer.GetCurPtrAndGrow(1) = 0; - SHFILEOPSTRUCTA fo; - fo.hwnd = GetParent(); - fo.wFunc = FO_DELETE; - fo.pFrom = (const CHAR *)buffer; - fo.pTo = NULL; - fo.fFlags = 0; - if (toRecycleBin) - fo.fFlags |= FOF_ALLOWUNDO; - // fo.fFlags |= FOF_NOCONFIRMATION; - // fo.fFlags |= FOF_NOERRORUI; - // fo.fFlags |= FOF_SILENT; - // fo.fFlags |= FOF_WANTNUKEWARNING; - fo.fAnyOperationsAborted = FALSE; - fo.hNameMappings = NULL; - fo.lpszProgressTitle = NULL; - /* int res = */ ::SHFileOperationA(&fo); - } - else - #endif - { - CDynamicBuffer buffer; - unsigned maxLen = 0; - const UString prefix = GetFsPath(); - FOR_VECTOR (i, indices) - { - // L"\\\\?\\") doesn't work here. - const UString path = prefix + GetItemRelPath2(indices[i]); - if (path.Len() > maxLen) - maxLen = path.Len(); - buffer.AddData(path, path.Len() + 1); - } - *buffer.GetCurPtrAndGrow(1) = 0; - if (maxLen >= MAX_PATH) - { - if (toRecycleBin) - { - MessageBox_Error_LangID(IDS_ERROR_LONG_PATH_TO_RECYCLE); - return; - } - useInternalDelete = true; - } - else - { - SHFILEOPSTRUCTW fo; - fo.hwnd = GetParent(); - fo.wFunc = FO_DELETE; - fo.pFrom = (const WCHAR *)buffer; - fo.pTo = NULL; - fo.fFlags = 0; - if (toRecycleBin) - fo.fFlags |= FOF_ALLOWUNDO; - fo.fAnyOperationsAborted = FALSE; - fo.hNameMappings = NULL; - fo.lpszProgressTitle = NULL; - // int res; - #ifdef _UNICODE - /* res = */ ::SHFileOperationW(&fo); - #else -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - const - Func_SHFileOperationW - f_SHFileOperationW = Z7_GET_PROC_ADDRESS( - Func_SHFileOperationW, ::GetModuleHandleW(L"shell32.dll"), - "SHFileOperationW"); - if (!f_SHFileOperationW) - return; - /* res = */ f_SHFileOperationW(&fo); - #endif - } - } - /* - if (fo.fAnyOperationsAborted) - MessageBox_Error_HRESULT_Caption(result, LangString(IDS_ERROR_DELETING)); - */ - if (!useInternalDelete) - { - RefreshListCtrl(state); - return; - } - } - #endif - - // DeleteItemsInternal - - if (!CheckBeforeUpdate(IDS_ERROR_DELETING)) - return; - - UInt32 titleID, messageID; - UString messageParam; - if (indices.Size() == 1) - { - const unsigned index = indices[0]; - messageParam = GetItemRelPath2(index); - if (IsItem_Folder(index)) - { - titleID = IDS_CONFIRM_FOLDER_DELETE; - messageID = IDS_WANT_TO_DELETE_FOLDER; - } - else - { - titleID = IDS_CONFIRM_FILE_DELETE; - messageID = IDS_WANT_TO_DELETE_FILE; - } - } - else - { - titleID = IDS_CONFIRM_ITEMS_DELETE; - messageID = IDS_WANT_TO_DELETE_ITEMS; - messageParam = NumberToString(indices.Size()); - } - if (::MessageBoxW(GetParent(), MyFormatNew(messageID, messageParam), LangString(titleID), - MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) - return; - - CDisableNotify disableNotify(*this); - { - CThreadFolderOperations op(FOLDER_TYPE_DELETE); - op.FolderOperations = _folderOperations; - op.Indices = indices; - op.DoOperation(*this, - LangString(IDS_DELETING), - LangString(IDS_ERROR_DELETING)); - } - RefreshTitleAlways(); - RefreshListCtrl(state); -} - -BOOL CPanel::OnBeginLabelEdit(LV_DISPINFOW * lpnmh) -{ - const unsigned realIndex = GetRealIndex(lpnmh->item); - if (realIndex == kParentIndex) - return TRUE; - if (IsThereReadOnlyFolder()) - return TRUE; - return FALSE; -} - -static bool IsCorrectFsName(const UString &name) -{ - const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1)); - return - lastPart != L"." && - lastPart != L".."; -} - -bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); - -bool CPanel::CorrectFsPath(const UString &path2, UString &result) -{ - return ::CorrectFsPath(GetFsPath(), path2, result); -} - -BOOL CPanel::OnEndLabelEdit(LV_DISPINFOW * lpnmh) -{ - if (lpnmh->item.pszText == NULL) - return FALSE; - CDisableTimerProcessing disableTimerProcessing2(*this); - - if (!CheckBeforeUpdate(IDS_ERROR_RENAMING)) - return FALSE; - - UString newName = lpnmh->item.pszText; - if (!IsCorrectFsName(newName)) - { - MessageBox_Error_HRESULT(E_INVALIDARG); - return FALSE; - } - - if (IsFSFolder()) - { - UString correctName; - if (!CorrectFsPath(newName, correctName)) - { - MessageBox_Error_HRESULT(E_INVALIDARG); - return FALSE; - } - newName = correctName; - } - - SaveSelectedState(_selectedState); - - const unsigned realIndex = GetRealIndex(lpnmh->item); - if (realIndex == kParentIndex) - return FALSE; - const UString prefix = GetItemPrefix(realIndex); - const UString oldName = GetItemName(realIndex); - - CDisableNotify disableNotify(*this); - { - CThreadFolderOperations op(FOLDER_TYPE_RENAME); - op.FolderOperations = _folderOperations; - op.Index = realIndex; - op.Name = newName; - const HRESULT res = op.DoOperation(*this, - LangString(IDS_RENAMING), - LangString(IDS_ERROR_RENAMING)); - // fixed in 9.26: we refresh list even after errors - // (it's more safe, since error can be at different stages, so list can be incorrect). - if (res == S_OK) - _selectedState.FocusedName = prefix + newName; - else - { - _selectedState.FocusedName = prefix + oldName; - // return FALSE; - } - } - - // Can't use RefreshListCtrl here. - // RefreshListCtrlSaveFocused(); - _selectedState.FocusedName_Defined = true; - _selectedState.SelectFocused = true; - - // We need clear all items to disable GetText before Reload: - // number of items can change. - // DeleteListItems(); - // But seems it can still call GetText (maybe for current item) - // so we can't delete items. - - _dontShowMode = true; - - PostMsg(kReLoadMessage); - return TRUE; -} - -bool Dlg_CreateFolder(HWND wnd, UString &destName); - -void CPanel::CreateFolder() -{ - if (IsHashFolder()) - return; - - if (!CheckBeforeUpdate(IDS_CREATE_FOLDER_ERROR)) - return; - - CDisableTimerProcessing disableTimerProcessing2(*this); - CSelectedState state; - SaveSelectedState(state); - - UString newName; - if (!Dlg_CreateFolder(GetParent(), newName)) - return; - - if (!IsCorrectFsName(newName)) - { - MessageBox_Error_HRESULT(E_INVALIDARG); - return; - } - - if (IsFSFolder()) - { - UString correctName; - if (!CorrectFsPath(newName, correctName)) - { - MessageBox_Error_HRESULT(E_INVALIDARG); - return; - } - newName = correctName; - } - - HRESULT res; - CDisableNotify disableNotify(*this); - { - CThreadFolderOperations op(FOLDER_TYPE_CREATE_FOLDER); - op.FolderOperations = _folderOperations; - op.Name = newName; - res = op.DoOperation(*this, - LangString(IDS_CREATE_FOLDER), - LangString(IDS_CREATE_FOLDER_ERROR)); - /* - // fixed for 9.26: we must refresh always - if (res != S_OK) - return; - */ - } - if (res == S_OK) - { - int pos = newName.Find(WCHAR_PATH_SEPARATOR); - if (pos >= 0) - newName.DeleteFrom((unsigned)(pos)); - if (!_mySelectMode) - state.SelectedNames.Clear(); - state.FocusedName = newName; - state.FocusedName_Defined = true; - state.SelectFocused = true; - } - RefreshTitleAlways(); - RefreshListCtrl(state); -} - -void CPanel::CreateFile() -{ - if (IsHashFolder()) - return; - - if (!CheckBeforeUpdate(IDS_CREATE_FILE_ERROR)) - return; - - CDisableTimerProcessing disableTimerProcessing2(*this); - CSelectedState state; - SaveSelectedState(state); - CComboDialog dlg; - LangString(IDS_CREATE_FILE, dlg.Title); - LangString(IDS_CREATE_FILE_NAME, dlg.Static); - LangString(IDS_CREATE_FILE_DEFAULT_NAME, dlg.Value); - - if (dlg.Create(GetParent()) != IDOK) - return; - - CDisableNotify disableNotify(*this); - - UString newName = dlg.Value; - - if (IsFSFolder()) - { - UString correctName; - if (!CorrectFsPath(newName, correctName)) - { - MessageBox_Error_HRESULT(E_INVALIDARG); - return; - } - newName = correctName; - } - - const HRESULT result = _folderOperations->CreateFile(newName, NULL); - if (result != S_OK) - { - MessageBox_Error_HRESULT_Caption(result, LangString(IDS_CREATE_FILE_ERROR)); - // MessageBoxErrorForUpdate(result, IDS_CREATE_FILE_ERROR); - return; - } - const int pos = newName.Find(WCHAR_PATH_SEPARATOR); - if (pos >= 0) - newName.DeleteFrom((unsigned)pos); - if (!_mySelectMode) - state.SelectedNames.Clear(); - state.FocusedName = newName; - state.FocusedName_Defined = true; - state.SelectFocused = true; - RefreshListCtrl(state); -} - -void CPanel::RenameFile() -{ - if (!CheckBeforeUpdate(IDS_ERROR_RENAMING)) - return; - int index = _listView.GetFocusedItem(); - if (index >= 0) - _listView.EditLabel(index); -} - -void CPanel::ChangeComment() -{ - if (IsHashFolder()) - return; - if (!CheckBeforeUpdate(IDS_COMMENT)) - return; - CDisableTimerProcessing disableTimerProcessing2(*this); - const int index = _listView.GetFocusedItem(); - if (index < 0) - return; - const unsigned realIndex = GetRealItemIndex(index); - if (realIndex == kParentIndex) - return; - CSelectedState state; - SaveSelectedState(state); - UString comment; - { - NCOM::CPropVariant propVariant; - if (_folder->GetProperty(realIndex, kpidComment, &propVariant) != S_OK) - return; - if (propVariant.vt == VT_BSTR) - comment = propVariant.bstrVal; - else if (propVariant.vt != VT_EMPTY) - return; - } - const UString name = GetItemRelPath2(realIndex); - CComboDialog dlg; - dlg.Title = name; - dlg.Title += " : "; - AddLangString(dlg.Title, IDS_COMMENT); - dlg.Value = comment; - LangString(IDS_COMMENT2, dlg.Static); - if (dlg.Create(GetParent()) != IDOK) - return; - NCOM::CPropVariant propVariant (dlg.Value); - - CDisableNotify disableNotify(*this); - const HRESULT result = _folderOperations->SetProperty(realIndex, kpidComment, &propVariant, NULL); - if (result != S_OK) - { - if (result == E_NOINTERFACE) - MessageBox_Error_UnsupportOperation(); - else - MessageBox_Error_HRESULT_Caption(result, L"Set Comment Error"); - } - RefreshListCtrl(state); -} +// PanelOperations.cpp + +#include "StdAfx.h" + +#include "../../../Common/DynamicBuffer.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/COM.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "ComboDialog.h" + +#include "FSFolder.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "Panel.h" +#include "UpdateCallback100.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +enum EFolderOpType +{ + FOLDER_TYPE_CREATE_FOLDER = 0, + FOLDER_TYPE_DELETE = 1, + FOLDER_TYPE_RENAME = 2 +}; + +class CThreadFolderOperations: public CProgressThreadVirt +{ + HRESULT ProcessVirt() Z7_override; +public: + EFolderOpType OpType; + UString Name; + UInt32 Index; + CRecordVector Indices; + + CMyComPtr FolderOperations; + CMyComPtr UpdateCallback; + CUpdateCallback100Imp *UpdateCallbackSpec; + + CThreadFolderOperations(EFolderOpType opType): OpType(opType) {} + HRESULT DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError); +}; + +HRESULT CThreadFolderOperations::ProcessVirt() +{ + NCOM::CComInitializer comInitializer; + switch ((int)OpType) + { + case FOLDER_TYPE_CREATE_FOLDER: + return FolderOperations->CreateFolder(Name, UpdateCallback); + case FOLDER_TYPE_DELETE: + return FolderOperations->Delete(Indices.ConstData(), Indices.Size(), UpdateCallback); + case FOLDER_TYPE_RENAME: + return FolderOperations->Rename(Index, Name, UpdateCallback); + default: + return E_FAIL; + } +} + + +HRESULT CThreadFolderOperations::DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError) +{ + UpdateCallbackSpec = new CUpdateCallback100Imp; + UpdateCallback = UpdateCallbackSpec; + UpdateCallbackSpec->ProgressDialog = this; + + WaitMode = true; + Sync.FinalMessage.ErrorMessage.Title = titleError; + + UpdateCallbackSpec->Init(); + + if (!panel._parentFolders.IsEmpty()) + { + const CFolderLink &fl = panel._parentFolders.Back(); + UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword; + UpdateCallbackSpec->Password = fl.Password; + } + + MainWindow = panel._mainWindow; // panel.GetParent() + MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); + MainAddTitle = progressTitle + L' '; + + RINOK(Create(progressTitle, MainWindow)) + return Result; +} + +#ifndef _UNICODE +typedef int (WINAPI * Func_SHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp); +#endif + +/* +void CPanel::MessageBoxErrorForUpdate(HRESULT errorCode, UINT resourceID) +{ + if (errorCode == E_NOINTERFACE) + MessageBox_Error_UnsupportOperation(); + else + MessageBox_Error_HRESULT_Caption(errorCode, LangString(resourceID)); +} +*/ + +void CPanel::DeleteItems(bool NON_CE_VAR(toRecycleBin)) +{ + CDisableTimerProcessing disableTimerProcessing(*this); + CRecordVector indices; + Get_ItemIndices_Operated(indices); + if (indices.IsEmpty()) + return; + CSelectedState state; + SaveSelectedState(state); + + #ifndef UNDER_CE + // WM6 / SHFileOperationW doesn't ask user! So we use internal delete + if (IsFSFolder() && toRecycleBin) + { + bool useInternalDelete = false; + #ifndef _UNICODE + if (!g_IsNT) + { + CDynamicBuffer buffer; + FOR_VECTOR (i, indices) + { + const AString path (GetSystemString(GetItemFullPath(indices[i]))); + buffer.AddData(path, path.Len() + 1); + } + *buffer.GetCurPtrAndGrow(1) = 0; + SHFILEOPSTRUCTA fo; + fo.hwnd = GetParent(); + fo.wFunc = FO_DELETE; + fo.pFrom = (const CHAR *)buffer; + fo.pTo = NULL; + fo.fFlags = 0; + if (toRecycleBin) + fo.fFlags |= FOF_ALLOWUNDO; + // fo.fFlags |= FOF_NOCONFIRMATION; + // fo.fFlags |= FOF_NOERRORUI; + // fo.fFlags |= FOF_SILENT; + // fo.fFlags |= FOF_WANTNUKEWARNING; + fo.fAnyOperationsAborted = FALSE; + fo.hNameMappings = NULL; + fo.lpszProgressTitle = NULL; + /* int res = */ ::SHFileOperationA(&fo); + } + else + #endif + { + CDynamicBuffer buffer; + unsigned maxLen = 0; + const UString prefix = GetFsPath(); + FOR_VECTOR (i, indices) + { + // L"\\\\?\\") doesn't work here. + const UString path = prefix + GetItemRelPath2(indices[i]); + if (path.Len() > maxLen) + maxLen = path.Len(); + buffer.AddData(path, path.Len() + 1); + } + *buffer.GetCurPtrAndGrow(1) = 0; + if (maxLen >= MAX_PATH) + { + if (toRecycleBin) + { + MessageBox_Error_LangID(IDS_ERROR_LONG_PATH_TO_RECYCLE); + return; + } + useInternalDelete = true; + } + else + { + SHFILEOPSTRUCTW fo; + fo.hwnd = GetParent(); + fo.wFunc = FO_DELETE; + fo.pFrom = (const WCHAR *)buffer; + fo.pTo = NULL; + fo.fFlags = 0; + if (toRecycleBin) + fo.fFlags |= FOF_ALLOWUNDO; + fo.fAnyOperationsAborted = FALSE; + fo.hNameMappings = NULL; + fo.lpszProgressTitle = NULL; + // int res; + #ifdef _UNICODE + /* res = */ ::SHFileOperationW(&fo); + #else +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + const + Func_SHFileOperationW + f_SHFileOperationW = Z7_GET_PROC_ADDRESS( + Func_SHFileOperationW, ::GetModuleHandleW(L"shell32.dll"), + "SHFileOperationW"); + if (!f_SHFileOperationW) + return; + /* res = */ f_SHFileOperationW(&fo); + #endif + } + } + /* + if (fo.fAnyOperationsAborted) + MessageBox_Error_HRESULT_Caption(result, LangString(IDS_ERROR_DELETING)); + */ + if (!useInternalDelete) + { + RefreshListCtrl(state); + return; + } + } + #endif + + // DeleteItemsInternal + + if (!CheckBeforeUpdate(IDS_ERROR_DELETING)) + return; + + UInt32 titleID, messageID; + UString messageParam; + if (indices.Size() == 1) + { + const unsigned index = indices[0]; + messageParam = GetItemRelPath2(index); + if (IsItem_Folder(index)) + { + titleID = IDS_CONFIRM_FOLDER_DELETE; + messageID = IDS_WANT_TO_DELETE_FOLDER; + } + else + { + titleID = IDS_CONFIRM_FILE_DELETE; + messageID = IDS_WANT_TO_DELETE_FILE; + } + } + else + { + titleID = IDS_CONFIRM_ITEMS_DELETE; + messageID = IDS_WANT_TO_DELETE_ITEMS; + messageParam = NumberToString(indices.Size()); + } + if (::MessageBoxW(GetParent(), MyFormatNew(messageID, messageParam), LangString(titleID), + MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) + return; + + CDisableNotify disableNotify(*this); + { + CThreadFolderOperations op(FOLDER_TYPE_DELETE); + op.FolderOperations = _folderOperations; + op.Indices = indices; + op.DoOperation(*this, + LangString(IDS_DELETING), + LangString(IDS_ERROR_DELETING)); + } + RefreshTitleAlways(); + RefreshListCtrl(state); +} + +BOOL CPanel::OnBeginLabelEdit(LV_DISPINFOW * lpnmh) +{ + const unsigned realIndex = GetRealIndex(lpnmh->item); + if (realIndex == kParentIndex) + return TRUE; + if (IsThereReadOnlyFolder()) + return TRUE; + return FALSE; +} + +static bool IsCorrectFsName(const UString &name) +{ + const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1)); + return + lastPart != L"." && + lastPart != L".."; +} + +bool CorrectFsPath(const UString &relBase, const UString &path, UString &result); + +bool CPanel::CorrectFsPath(const UString &path2, UString &result) +{ + return ::CorrectFsPath(GetFsPath(), path2, result); +} + +BOOL CPanel::OnEndLabelEdit(LV_DISPINFOW * lpnmh) +{ + if (lpnmh->item.pszText == NULL) + return FALSE; + CDisableTimerProcessing disableTimerProcessing2(*this); + + if (!CheckBeforeUpdate(IDS_ERROR_RENAMING)) + return FALSE; + + UString newName = lpnmh->item.pszText; + if (!IsCorrectFsName(newName)) + { + MessageBox_Error_HRESULT(E_INVALIDARG); + return FALSE; + } + + if (IsFSFolder()) + { + UString correctName; + if (!CorrectFsPath(newName, correctName)) + { + MessageBox_Error_HRESULT(E_INVALIDARG); + return FALSE; + } + newName = correctName; + } + + SaveSelectedState(_selectedState); + + const unsigned realIndex = GetRealIndex(lpnmh->item); + if (realIndex == kParentIndex) + return FALSE; + const UString prefix = GetItemPrefix(realIndex); + const UString oldName = GetItemName(realIndex); + + CDisableNotify disableNotify(*this); + { + CThreadFolderOperations op(FOLDER_TYPE_RENAME); + op.FolderOperations = _folderOperations; + op.Index = realIndex; + op.Name = newName; + const HRESULT res = op.DoOperation(*this, + LangString(IDS_RENAMING), + LangString(IDS_ERROR_RENAMING)); + // fixed in 9.26: we refresh list even after errors + // (it's more safe, since error can be at different stages, so list can be incorrect). + if (res == S_OK) + _selectedState.FocusedName = prefix + newName; + else + { + _selectedState.FocusedName = prefix + oldName; + // return FALSE; + } + } + + // Can't use RefreshListCtrl here. + // RefreshListCtrlSaveFocused(); + _selectedState.FocusedName_Defined = true; + _selectedState.SelectFocused = true; + + // We need clear all items to disable GetText before Reload: + // number of items can change. + // DeleteListItems(); + // But seems it can still call GetText (maybe for current item) + // so we can't delete items. + + _dontShowMode = true; + + PostMsg(kReLoadMessage); + return TRUE; +} + +bool Dlg_CreateFolder(HWND wnd, UString &destName); + +void CPanel::CreateFolder() +{ + if (IsHashFolder()) + return; + + if (!CheckBeforeUpdate(IDS_CREATE_FOLDER_ERROR)) + return; + + CDisableTimerProcessing disableTimerProcessing2(*this); + CSelectedState state; + SaveSelectedState(state); + + UString newName; + if (!Dlg_CreateFolder(GetParent(), newName)) + return; + + if (!IsCorrectFsName(newName)) + { + MessageBox_Error_HRESULT(E_INVALIDARG); + return; + } + + if (IsFSFolder()) + { + UString correctName; + if (!CorrectFsPath(newName, correctName)) + { + MessageBox_Error_HRESULT(E_INVALIDARG); + return; + } + newName = correctName; + } + + HRESULT res; + CDisableNotify disableNotify(*this); + { + CThreadFolderOperations op(FOLDER_TYPE_CREATE_FOLDER); + op.FolderOperations = _folderOperations; + op.Name = newName; + res = op.DoOperation(*this, + LangString(IDS_CREATE_FOLDER), + LangString(IDS_CREATE_FOLDER_ERROR)); + /* + // fixed for 9.26: we must refresh always + if (res != S_OK) + return; + */ + } + if (res == S_OK) + { + int pos = newName.Find(WCHAR_PATH_SEPARATOR); + if (pos >= 0) + newName.DeleteFrom((unsigned)(pos)); + if (!_mySelectMode) + state.SelectedNames.Clear(); + state.FocusedName = newName; + state.FocusedName_Defined = true; + state.SelectFocused = true; + } + RefreshTitleAlways(); + RefreshListCtrl(state); +} + +void CPanel::CreateFile() +{ + if (IsHashFolder()) + return; + + if (!CheckBeforeUpdate(IDS_CREATE_FILE_ERROR)) + return; + + CDisableTimerProcessing disableTimerProcessing2(*this); + CSelectedState state; + SaveSelectedState(state); + CComboDialog dlg; + LangString(IDS_CREATE_FILE, dlg.Title); + LangString(IDS_CREATE_FILE_NAME, dlg.Static); + LangString(IDS_CREATE_FILE_DEFAULT_NAME, dlg.Value); + + if (dlg.Create(GetParent()) != IDOK) + return; + + CDisableNotify disableNotify(*this); + + UString newName = dlg.Value; + + if (IsFSFolder()) + { + UString correctName; + if (!CorrectFsPath(newName, correctName)) + { + MessageBox_Error_HRESULT(E_INVALIDARG); + return; + } + newName = correctName; + } + + const HRESULT result = _folderOperations->CreateFile(newName, NULL); + if (result != S_OK) + { + MessageBox_Error_HRESULT_Caption(result, LangString(IDS_CREATE_FILE_ERROR)); + // MessageBoxErrorForUpdate(result, IDS_CREATE_FILE_ERROR); + return; + } + const int pos = newName.Find(WCHAR_PATH_SEPARATOR); + if (pos >= 0) + newName.DeleteFrom((unsigned)pos); + if (!_mySelectMode) + state.SelectedNames.Clear(); + state.FocusedName = newName; + state.FocusedName_Defined = true; + state.SelectFocused = true; + RefreshListCtrl(state); +} + +void CPanel::RenameFile() +{ + if (!CheckBeforeUpdate(IDS_ERROR_RENAMING)) + return; + int index = _listView.GetFocusedItem(); + if (index >= 0) + _listView.EditLabel(index); +} + +void CPanel::ChangeComment() +{ + if (IsHashFolder()) + return; + if (!CheckBeforeUpdate(IDS_COMMENT)) + return; + CDisableTimerProcessing disableTimerProcessing2(*this); + const int index = _listView.GetFocusedItem(); + if (index < 0) + return; + const unsigned realIndex = GetRealItemIndex(index); + if (realIndex == kParentIndex) + return; + CSelectedState state; + SaveSelectedState(state); + UString comment; + { + NCOM::CPropVariant propVariant; + if (_folder->GetProperty(realIndex, kpidComment, &propVariant) != S_OK) + return; + if (propVariant.vt == VT_BSTR) + comment = propVariant.bstrVal; + else if (propVariant.vt != VT_EMPTY) + return; + } + const UString name = GetItemRelPath2(realIndex); + CComboDialog dlg; + dlg.Title = name; + dlg.Title += " : "; + AddLangString(dlg.Title, IDS_COMMENT); + dlg.Value = comment; + LangString(IDS_COMMENT2, dlg.Static); + if (dlg.Create(GetParent()) != IDOK) + return; + NCOM::CPropVariant propVariant (dlg.Value); + + CDisableNotify disableNotify(*this); + const HRESULT result = _folderOperations->SetProperty(realIndex, kpidComment, &propVariant, NULL); + if (result != S_OK) + { + if (result == E_NOINTERFACE) + MessageBox_Error_UnsupportOperation(); + else + MessageBox_Error_HRESULT_Caption(result, L"Set Comment Error"); + } + RefreshListCtrl(state); +} diff --git a/CPP/7zip/UI/FileManager/PanelSelect.cpp b/CPP/7zip/UI/FileManager/PanelSelect.cpp index b5b67fcb6..f7a16dd56 100644 --- a/CPP/7zip/UI/FileManager/PanelSelect.cpp +++ b/CPP/7zip/UI/FileManager/PanelSelect.cpp @@ -1,317 +1,317 @@ -// PanelSelect.cpp - -#include "StdAfx.h" - -#include "resource.h" - -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "ComboDialog.h" -#include "LangUtils.h" -#include "Panel.h" - -void CPanel::OnShiftSelectMessage() -{ - if (!_mySelectMode) - return; - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - if (!_selectionIsDefined) - return; - int startItem = MyMin(focusedItem, _prevFocusedItem); - int finishItem = MyMax(focusedItem, _prevFocusedItem); - - int numItems = _listView.GetItemCount(); - for (int i = 0; i < numItems; i++) - { - const unsigned realIndex = GetRealItemIndex(i); - if (realIndex == kParentIndex) - continue; - if (i >= startItem && i <= finishItem) - if (_selectedStatusVector[realIndex] != _selectMark) - { - _selectedStatusVector[realIndex] = _selectMark; - _listView.RedrawItem(i); - } - } - - _prevFocusedItem = focusedItem; -} - -void CPanel::OnArrowWithShift() -{ - if (!_mySelectMode) - return; - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const unsigned realIndex = GetRealItemIndex(focusedItem); - - if (_selectionIsDefined) - { - if (realIndex != kParentIndex) - _selectedStatusVector[realIndex] = _selectMark; - } - else - { - if (realIndex == kParentIndex) - { - _selectionIsDefined = true; - _selectMark = true; - } - else - { - _selectionIsDefined = true; - _selectMark = !_selectedStatusVector[realIndex]; - _selectedStatusVector[realIndex] = _selectMark; - } - } - - _prevFocusedItem = focusedItem; - PostMsg(kShiftSelectMessage); - _listView.RedrawItem(focusedItem); -} - -void CPanel::OnInsert() -{ - /* - const int kState = CDIS_MARKED; // LVIS_DROPHILITED; - UINT state = (_listView.GetItemState(focusedItem, LVIS_CUT) == 0) ? - LVIS_CUT : 0; - _listView.SetItemState(focusedItem, state, LVIS_CUT); - // _listView.SetItemState_Selected(focusedItem); - */ - - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - - const unsigned realIndex = GetRealItemIndex(focusedItem); - if (realIndex != kParentIndex) - { - bool isSelected = !_selectedStatusVector[realIndex]; - _selectedStatusVector[realIndex] = isSelected; - if (!_mySelectMode) - _listView.SetItemState_Selected(focusedItem, isSelected); - _listView.RedrawItem(focusedItem); - } - - int nextIndex = focusedItem + 1; - if (nextIndex < _listView.GetItemCount()) - { - _listView.SetItemState_FocusedSelected(nextIndex); - _listView.EnsureVisible(nextIndex, false); - } -} - -/* -void CPanel::OnUpWithShift() -{ - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const int index = GetRealItemIndex(focusedItem); - if (index == kParentIndex) - return; - _selectedStatusVector[index] = !_selectedStatusVector[index]; - _listView.RedrawItem(index); -} - -void CPanel::OnDownWithShift() -{ - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const int index = GetRealItemIndex(focusedItem); - if (index == kParentIndex) - return; - _selectedStatusVector[index] = !_selectedStatusVector[index]; - _listView.RedrawItem(index); -} -*/ - -void CPanel::UpdateSelection() -{ - if (!_mySelectMode) - { - bool enableTemp = _enableItemChangeNotify; - _enableItemChangeNotify = false; - int numItems = _listView.GetItemCount(); - for (int i = 0; i < numItems; i++) - { - const unsigned realIndex = GetRealItemIndex(i); - if (realIndex != kParentIndex) - _listView.SetItemState_Selected(i, _selectedStatusVector[realIndex]); - } - _enableItemChangeNotify = enableTemp; - } - _listView.RedrawAllItems(); -} - - -void CPanel::SelectSpec(bool selectMode) -{ - CComboDialog dlg; - LangString(selectMode ? IDS_SELECT : IDS_DESELECT, dlg.Title ); - LangString(IDS_SELECT_MASK, dlg.Static); - dlg.Value = '*'; - if (dlg.Create(GetParent()) != IDOK) - return; - const UString &mask = dlg.Value; - FOR_VECTOR (i, _selectedStatusVector) - if (DoesWildcardMatchName(mask, GetItemName(i))) - _selectedStatusVector[i] = selectMode; - UpdateSelection(); -} - -void CPanel::SelectByType(bool selectMode) -{ - const int focusedItem = _listView.GetFocusedItem(); - if (focusedItem < 0) - return; - const unsigned realIndex = GetRealItemIndex(focusedItem); - UString name = GetItemName(realIndex); - bool isItemFolder = IsItem_Folder(realIndex); - - if (isItemFolder) - { - FOR_VECTOR (i, _selectedStatusVector) - if (IsItem_Folder(i) == isItemFolder) - _selectedStatusVector[i] = selectMode; - } - else - { - int pos = name.ReverseFind_Dot(); - if (pos < 0) - { - FOR_VECTOR (i, _selectedStatusVector) - if (IsItem_Folder(i) == isItemFolder && GetItemName(i).ReverseFind_Dot() < 0) - _selectedStatusVector[i] = selectMode; - } - else - { - UString mask ('*'); - mask += name.Ptr((unsigned)pos); - FOR_VECTOR (i, _selectedStatusVector) - if (IsItem_Folder(i) == isItemFolder && DoesWildcardMatchName(mask, GetItemName(i))) - _selectedStatusVector[i] = selectMode; - } - } - - UpdateSelection(); -} - -void CPanel::SelectAll(bool selectMode) -{ - FOR_VECTOR (i, _selectedStatusVector) - _selectedStatusVector[i] = selectMode; - UpdateSelection(); -} - -void CPanel::InvertSelection() -{ - if (!_mySelectMode) - { - /* - unsigned numSelected = 0; - FOR_VECTOR (i, _selectedStatusVector) - if (_selectedStatusVector[i]) - numSelected++; - */ - // 17.02: fixed : now we invert item even, if single item is selected - /* - if (numSelected == 1) - { - int focused = _listView.GetFocusedItem(); - if (focused >= 0) - { - const unsigned realIndex = GetRealItemIndex(focused); - if (realIndex >= 0) - if (_selectedStatusVector[realIndex]) - _selectedStatusVector[realIndex] = false; - } - } - */ - } - FOR_VECTOR (i, _selectedStatusVector) - _selectedStatusVector[i] = !_selectedStatusVector[i]; - UpdateSelection(); -} - -void CPanel::KillSelection() -{ - SelectAll(false); - // ver 20.01: now we don't like that focused will be selected item. - // So the following code was disabled: - /* - if (!_mySelectMode) - { - int focused = _listView.GetFocusedItem(); - if (focused >= 0) - { - // CPanel::OnItemChanged notify for LVIS_SELECTED change doesn't work here. Why? - // so we change _selectedStatusVector[realIndex] here. - const unsigned realIndex = GetRealItemIndex(focused); - if (realIndex != kParentIndex) - _selectedStatusVector[realIndex] = true; - _listView.SetItemState_Selected(focused); - } - } - */ -} - -void CPanel::OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate) -{ - if (itemActivate->hdr.hwndFrom != HWND(_listView)) - return; - // It will work only for Version 4.71 (IE 4); - int indexInList = itemActivate->iItem; - if (indexInList < 0) - return; - - #ifndef UNDER_CE - if ((itemActivate->uKeyFlags & LVKF_SHIFT) != 0) - { - // int focusedIndex = _listView.GetFocusedItem(); - const int focusedIndex = _startGroupSelect; - if (focusedIndex < 0) - return; - const int startItem = MyMin(focusedIndex, indexInList); - const int finishItem = MyMax(focusedIndex, indexInList); - - const int numItems = _listView.GetItemCount(); - for (int i = 0; i < numItems; i++) - { - const unsigned realIndex = GetRealItemIndex(i); - if (realIndex == kParentIndex) - continue; - const bool selected = (i >= startItem && i <= finishItem); - if (_selectedStatusVector[realIndex] != selected) - { - _selectedStatusVector[realIndex] = selected; - _listView.RedrawItem(i); - } - } - } - else - #endif - { - _startGroupSelect = indexInList; - - #ifndef UNDER_CE - if ((itemActivate->uKeyFlags & LVKF_CONTROL) != 0) - { - const unsigned realIndex = GetRealItemIndex(indexInList); - if (realIndex != kParentIndex) - { - _selectedStatusVector[realIndex] = !_selectedStatusVector[realIndex]; - _listView.RedrawItem(indexInList); - } - } - #endif - } - - return; -} +// PanelSelect.cpp + +#include "StdAfx.h" + +#include "resource.h" + +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "ComboDialog.h" +#include "LangUtils.h" +#include "Panel.h" + +void CPanel::OnShiftSelectMessage() +{ + if (!_mySelectMode) + return; + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + if (!_selectionIsDefined) + return; + int startItem = MyMin(focusedItem, _prevFocusedItem); + int finishItem = MyMax(focusedItem, _prevFocusedItem); + + int numItems = _listView.GetItemCount(); + for (int i = 0; i < numItems; i++) + { + const unsigned realIndex = GetRealItemIndex(i); + if (realIndex == kParentIndex) + continue; + if (i >= startItem && i <= finishItem) + if (_selectedStatusVector[realIndex] != _selectMark) + { + _selectedStatusVector[realIndex] = _selectMark; + _listView.RedrawItem(i); + } + } + + _prevFocusedItem = focusedItem; +} + +void CPanel::OnArrowWithShift() +{ + if (!_mySelectMode) + return; + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const unsigned realIndex = GetRealItemIndex(focusedItem); + + if (_selectionIsDefined) + { + if (realIndex != kParentIndex) + _selectedStatusVector[realIndex] = _selectMark; + } + else + { + if (realIndex == kParentIndex) + { + _selectionIsDefined = true; + _selectMark = true; + } + else + { + _selectionIsDefined = true; + _selectMark = !_selectedStatusVector[realIndex]; + _selectedStatusVector[realIndex] = _selectMark; + } + } + + _prevFocusedItem = focusedItem; + PostMsg(kShiftSelectMessage); + _listView.RedrawItem(focusedItem); +} + +void CPanel::OnInsert() +{ + /* + const int kState = CDIS_MARKED; // LVIS_DROPHILITED; + UINT state = (_listView.GetItemState(focusedItem, LVIS_CUT) == 0) ? + LVIS_CUT : 0; + _listView.SetItemState(focusedItem, state, LVIS_CUT); + // _listView.SetItemState_Selected(focusedItem); + */ + + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + + const unsigned realIndex = GetRealItemIndex(focusedItem); + if (realIndex != kParentIndex) + { + bool isSelected = !_selectedStatusVector[realIndex]; + _selectedStatusVector[realIndex] = isSelected; + if (!_mySelectMode) + _listView.SetItemState_Selected(focusedItem, isSelected); + _listView.RedrawItem(focusedItem); + } + + int nextIndex = focusedItem + 1; + if (nextIndex < _listView.GetItemCount()) + { + _listView.SetItemState_FocusedSelected(nextIndex); + _listView.EnsureVisible(nextIndex, false); + } +} + +/* +void CPanel::OnUpWithShift() +{ + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const int index = GetRealItemIndex(focusedItem); + if (index == kParentIndex) + return; + _selectedStatusVector[index] = !_selectedStatusVector[index]; + _listView.RedrawItem(index); +} + +void CPanel::OnDownWithShift() +{ + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const int index = GetRealItemIndex(focusedItem); + if (index == kParentIndex) + return; + _selectedStatusVector[index] = !_selectedStatusVector[index]; + _listView.RedrawItem(index); +} +*/ + +void CPanel::UpdateSelection() +{ + if (!_mySelectMode) + { + bool enableTemp = _enableItemChangeNotify; + _enableItemChangeNotify = false; + int numItems = _listView.GetItemCount(); + for (int i = 0; i < numItems; i++) + { + const unsigned realIndex = GetRealItemIndex(i); + if (realIndex != kParentIndex) + _listView.SetItemState_Selected(i, _selectedStatusVector[realIndex]); + } + _enableItemChangeNotify = enableTemp; + } + _listView.RedrawAllItems(); +} + + +void CPanel::SelectSpec(bool selectMode) +{ + CComboDialog dlg; + LangString(selectMode ? IDS_SELECT : IDS_DESELECT, dlg.Title ); + LangString(IDS_SELECT_MASK, dlg.Static); + dlg.Value = '*'; + if (dlg.Create(GetParent()) != IDOK) + return; + const UString &mask = dlg.Value; + FOR_VECTOR (i, _selectedStatusVector) + if (DoesWildcardMatchName(mask, GetItemName(i))) + _selectedStatusVector[i] = selectMode; + UpdateSelection(); +} + +void CPanel::SelectByType(bool selectMode) +{ + const int focusedItem = _listView.GetFocusedItem(); + if (focusedItem < 0) + return; + const unsigned realIndex = GetRealItemIndex(focusedItem); + UString name = GetItemName(realIndex); + bool isItemFolder = IsItem_Folder(realIndex); + + if (isItemFolder) + { + FOR_VECTOR (i, _selectedStatusVector) + if (IsItem_Folder(i) == isItemFolder) + _selectedStatusVector[i] = selectMode; + } + else + { + int pos = name.ReverseFind_Dot(); + if (pos < 0) + { + FOR_VECTOR (i, _selectedStatusVector) + if (IsItem_Folder(i) == isItemFolder && GetItemName(i).ReverseFind_Dot() < 0) + _selectedStatusVector[i] = selectMode; + } + else + { + UString mask ('*'); + mask += name.Ptr((unsigned)pos); + FOR_VECTOR (i, _selectedStatusVector) + if (IsItem_Folder(i) == isItemFolder && DoesWildcardMatchName(mask, GetItemName(i))) + _selectedStatusVector[i] = selectMode; + } + } + + UpdateSelection(); +} + +void CPanel::SelectAll(bool selectMode) +{ + FOR_VECTOR (i, _selectedStatusVector) + _selectedStatusVector[i] = selectMode; + UpdateSelection(); +} + +void CPanel::InvertSelection() +{ + if (!_mySelectMode) + { + /* + unsigned numSelected = 0; + FOR_VECTOR (i, _selectedStatusVector) + if (_selectedStatusVector[i]) + numSelected++; + */ + // 17.02: fixed : now we invert item even, if single item is selected + /* + if (numSelected == 1) + { + int focused = _listView.GetFocusedItem(); + if (focused >= 0) + { + const unsigned realIndex = GetRealItemIndex(focused); + if (realIndex >= 0) + if (_selectedStatusVector[realIndex]) + _selectedStatusVector[realIndex] = false; + } + } + */ + } + FOR_VECTOR (i, _selectedStatusVector) + _selectedStatusVector[i] = !_selectedStatusVector[i]; + UpdateSelection(); +} + +void CPanel::KillSelection() +{ + SelectAll(false); + // ver 20.01: now we don't like that focused will be selected item. + // So the following code was disabled: + /* + if (!_mySelectMode) + { + int focused = _listView.GetFocusedItem(); + if (focused >= 0) + { + // CPanel::OnItemChanged notify for LVIS_SELECTED change doesn't work here. Why? + // so we change _selectedStatusVector[realIndex] here. + const unsigned realIndex = GetRealItemIndex(focused); + if (realIndex != kParentIndex) + _selectedStatusVector[realIndex] = true; + _listView.SetItemState_Selected(focused); + } + } + */ +} + +void CPanel::OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate) +{ + if (itemActivate->hdr.hwndFrom != HWND(_listView)) + return; + // It will work only for Version 4.71 (IE 4); + int indexInList = itemActivate->iItem; + if (indexInList < 0) + return; + + #ifndef UNDER_CE + if ((itemActivate->uKeyFlags & LVKF_SHIFT) != 0) + { + // int focusedIndex = _listView.GetFocusedItem(); + const int focusedIndex = _startGroupSelect; + if (focusedIndex < 0) + return; + const int startItem = MyMin(focusedIndex, indexInList); + const int finishItem = MyMax(focusedIndex, indexInList); + + const int numItems = _listView.GetItemCount(); + for (int i = 0; i < numItems; i++) + { + const unsigned realIndex = GetRealItemIndex(i); + if (realIndex == kParentIndex) + continue; + const bool selected = (i >= startItem && i <= finishItem); + if (_selectedStatusVector[realIndex] != selected) + { + _selectedStatusVector[realIndex] = selected; + _listView.RedrawItem(i); + } + } + } + else + #endif + { + _startGroupSelect = indexInList; + + #ifndef UNDER_CE + if ((itemActivate->uKeyFlags & LVKF_CONTROL) != 0) + { + const unsigned realIndex = GetRealItemIndex(indexInList); + if (realIndex != kParentIndex) + { + _selectedStatusVector[realIndex] = !_selectedStatusVector[realIndex]; + _listView.RedrawItem(indexInList); + } + } + #endif + } + + return; +} diff --git a/CPP/7zip/UI/FileManager/PanelSort.cpp b/CPP/7zip/UI/FileManager/PanelSort.cpp index fca844840..f95f8ee98 100644 --- a/CPP/7zip/UI/FileManager/PanelSort.cpp +++ b/CPP/7zip/UI/FileManager/PanelSort.cpp @@ -1,269 +1,269 @@ -// PanelSort.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" -#include "../../../Windows/PropVariant.h" - -#include "../../PropID.h" - -#include "Panel.h" - -using namespace NWindows; - -int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2) -{ - for (;;) - { - wchar_t c1 = *s1; - wchar_t c2 = *s2; - if ((c1 >= '0' && c1 <= '9') && - (c2 >= '0' && c2 <= '9')) - { - for (; *s1 == '0'; s1++); - for (; *s2 == '0'; s2++); - size_t len1 = 0; - size_t len2 = 0; - for (; (s1[len1] >= '0' && s1[len1] <= '9'); len1++); - for (; (s2[len2] >= '0' && s2[len2] <= '9'); len2++); - if (len1 < len2) return -1; - if (len1 > len2) return 1; - for (; len1 > 0; s1++, s2++, len1--) - { - if (*s1 == *s2) continue; - return (*s1 < *s2) ? -1 : 1; - } - c1 = *s1; - c2 = *s2; - } - s1++; - s2++; - if (c1 != c2) - { - // Probably we need to change the order for special characters like in Explorer. - wchar_t u1 = MyCharUpper(c1); - wchar_t u2 = MyCharUpper(c2); - if (u1 < u2) return -1; - if (u1 > u2) return 1; - } - if (c1 == 0) return 0; - } -} - -static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2) -{ - size1 &= ~1u; - size2 &= ~1u; - for (unsigned i = 0;; i += 2) - { - if (i >= size1) - return (i >= size2) ? 0 : -1; - if (i >= size2) - return 1; - UInt16 c1 = GetUi16(s1 + i); - UInt16 c2 = GetUi16(s2 + i); - if (c1 == c2) - { - if (c1 == 0) - return 0; - continue; - } - if (c1 < c2) - return -1; - return 1; - } -} - -static inline const wchar_t *GetExtensionPtr(const UString &name) -{ - const int dotPos = name.ReverseFind_Dot(); - return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos); -} - -void CPanel::SetSortRawStatus() -{ - _isRawSortProp = false; - FOR_VECTOR (i, _columns) - { - const CPropColumn &prop = _columns[i]; - if (prop.ID == _sortID) - { - _isRawSortProp = prop.IsRawProp ? 1 : 0; - return; - } - } -} - - -static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) -{ - if (lpData == 0) - return 0; - CPanel *panel = (CPanel*)lpData; - - - PROPID propID = panel->_sortID; - - if (propID == kpidNoProperty) - return MyCompare(lParam1, lParam2); - - if (panel->_isRawSortProp) - { - // Sha1, NtSecurity, NtReparse - const void *data1; - const void *data2; - UInt32 dataSize1; - UInt32 dataSize2; - UInt32 propType1; - UInt32 propType2; - if (panel->_folderRawProps->GetRawProp((UInt32)lParam1, propID, &data1, &dataSize1, &propType1) != 0) return 0; - if (panel->_folderRawProps->GetRawProp((UInt32)lParam2, propID, &data2, &dataSize2, &propType2) != 0) return 0; - if (dataSize1 == 0) - return (dataSize2 == 0) ? 0 : -1; - if (dataSize2 == 0) - return 1; - if (propType1 != NPropDataType::kRaw) return 0; - if (propType2 != NPropDataType::kRaw) return 0; - if (propID == kpidNtReparse) - { - NFile::CReparseShortInfo r1; r1.Parse((const Byte *)data1, dataSize1); - NFile::CReparseShortInfo r2; r2.Parse((const Byte *)data2, dataSize2); - return CompareFileNames_Le16( - (const Byte *)data1 + r1.Offset, r1.Size, - (const Byte *)data2 + r2.Offset, r2.Size); - } - } - - if (panel->_folderCompare) - return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp); - - switch (propID) - { - // if (panel->_sortIndex == 0) - case kpidName: - { - const UString name1 = panel->GetItemName((unsigned)lParam1); - const UString name2 = panel->GetItemName((unsigned)lParam2); - const int res = CompareFileNames_ForFolderList(name1, name2); - /* - if (res != 0 || !panel->_flatMode) - return res; - const UString prefix1 = panel->GetItemPrefix(lParam1); - const UString prefix2 = panel->GetItemPrefix(lParam2); - return res = CompareFileNames_ForFolderList(prefix1, prefix2); - */ - return res; - } - case kpidExtension: - { - const UString name1 = panel->GetItemName((unsigned)lParam1); - const UString name2 = panel->GetItemName((unsigned)lParam2); - return CompareFileNames_ForFolderList( - GetExtensionPtr(name1), - GetExtensionPtr(name2)); - } - } - /* - if (panel->_sortIndex == 1) - return MyCompare(file1.Size, file2.Size); - return ::CompareFileTime(&file1.MTime, &file2.MTime); - */ - - // PROPID propID = panel->_columns[panel->_sortIndex].ID; - - NCOM::CPropVariant prop1, prop2; - // Name must be first property - panel->_folder->GetProperty((UInt32)lParam1, propID, &prop1); - panel->_folder->GetProperty((UInt32)lParam2, propID, &prop2); - if (prop1.vt != prop2.vt) - return MyCompare(prop1.vt, prop2.vt); - if (prop1.vt == VT_BSTR) - return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal); - return prop1.Compare(prop2); -} - -int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData); -int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) -{ - if (lpData == 0) return 0; - if (lParam1 == (int)kParentIndex) return -1; - if (lParam2 == (int)kParentIndex) return 1; - - CPanel *panel = (CPanel*)lpData; - - const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1); - const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2); - - if (isDir1 && !isDir2) return -1; - if (isDir2 && !isDir1) return 1; - - const int result = CompareItems2(lParam1, lParam2, lpData); - return panel->_ascending ? result: (-result); -} - - -/* -void CPanel::SortItems(int index) -{ - if (index == _sortIndex) - _ascending = !_ascending; - else - { - _sortIndex = index; - _ascending = true; - switch (_columns[_sortIndex].ID) - { - case kpidSize: - case kpidPackedSize: - case kpidCTime: - case kpidATime: - case kpidMTime: - _ascending = false; - break; - } - } - _listView.SortItems(CompareItems, (LPARAM)this); - _listView.EnsureVisible(_listView.GetFocusedItem(), false); -} - -void CPanel::SortItemsWithPropID(PROPID propID) -{ - int index = _columns.FindItem_for_PropID(propID); - if (index >= 0) - SortItems(index); -} -*/ - -void CPanel::SortItemsWithPropID(PROPID propID) -{ - if (propID == _sortID) - _ascending = !_ascending; - else - { - _sortID = propID; - _ascending = true; - switch (propID) - { - case kpidSize: - case kpidPackSize: - case kpidCTime: - case kpidATime: - case kpidMTime: - _ascending = false; - break; - } - } - SetSortRawStatus(); - _listView.SortItems(CompareItems, (LPARAM)this); - _listView.EnsureVisible(_listView.GetFocusedItem(), false); -} - - -void CPanel::OnColumnClick(LPNMLISTVIEW info) -{ - /* - int index = _columns.FindItem_for_PropID(_visibleColumns[info->iSubItem].ID); - SortItems(index); - */ - SortItemsWithPropID(_visibleColumns[info->iSubItem].ID); -} +// PanelSort.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" +#include "../../../Windows/PropVariant.h" + +#include "../../PropID.h" + +#include "Panel.h" + +using namespace NWindows; + +int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2) +{ + for (;;) + { + wchar_t c1 = *s1; + wchar_t c2 = *s2; + if ((c1 >= '0' && c1 <= '9') && + (c2 >= '0' && c2 <= '9')) + { + for (; *s1 == '0'; s1++); + for (; *s2 == '0'; s2++); + size_t len1 = 0; + size_t len2 = 0; + for (; (s1[len1] >= '0' && s1[len1] <= '9'); len1++); + for (; (s2[len2] >= '0' && s2[len2] <= '9'); len2++); + if (len1 < len2) return -1; + if (len1 > len2) return 1; + for (; len1 > 0; s1++, s2++, len1--) + { + if (*s1 == *s2) continue; + return (*s1 < *s2) ? -1 : 1; + } + c1 = *s1; + c2 = *s2; + } + s1++; + s2++; + if (c1 != c2) + { + // Probably we need to change the order for special characters like in Explorer. + wchar_t u1 = MyCharUpper(c1); + wchar_t u2 = MyCharUpper(c2); + if (u1 < u2) return -1; + if (u1 > u2) return 1; + } + if (c1 == 0) return 0; + } +} + +static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2) +{ + size1 &= ~1u; + size2 &= ~1u; + for (unsigned i = 0;; i += 2) + { + if (i >= size1) + return (i >= size2) ? 0 : -1; + if (i >= size2) + return 1; + UInt16 c1 = GetUi16(s1 + i); + UInt16 c2 = GetUi16(s2 + i); + if (c1 == c2) + { + if (c1 == 0) + return 0; + continue; + } + if (c1 < c2) + return -1; + return 1; + } +} + +static inline const wchar_t *GetExtensionPtr(const UString &name) +{ + const int dotPos = name.ReverseFind_Dot(); + return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos); +} + +void CPanel::SetSortRawStatus() +{ + _isRawSortProp = false; + FOR_VECTOR (i, _columns) + { + const CPropColumn &prop = _columns[i]; + if (prop.ID == _sortID) + { + _isRawSortProp = prop.IsRawProp ? 1 : 0; + return; + } + } +} + + +static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) +{ + if (lpData == 0) + return 0; + CPanel *panel = (CPanel*)lpData; + + + PROPID propID = panel->_sortID; + + if (propID == kpidNoProperty) + return MyCompare(lParam1, lParam2); + + if (panel->_isRawSortProp) + { + // Sha1, NtSecurity, NtReparse + const void *data1; + const void *data2; + UInt32 dataSize1; + UInt32 dataSize2; + UInt32 propType1; + UInt32 propType2; + if (panel->_folderRawProps->GetRawProp((UInt32)lParam1, propID, &data1, &dataSize1, &propType1) != 0) return 0; + if (panel->_folderRawProps->GetRawProp((UInt32)lParam2, propID, &data2, &dataSize2, &propType2) != 0) return 0; + if (dataSize1 == 0) + return (dataSize2 == 0) ? 0 : -1; + if (dataSize2 == 0) + return 1; + if (propType1 != NPropDataType::kRaw) return 0; + if (propType2 != NPropDataType::kRaw) return 0; + if (propID == kpidNtReparse) + { + NFile::CReparseShortInfo r1; r1.Parse((const Byte *)data1, dataSize1); + NFile::CReparseShortInfo r2; r2.Parse((const Byte *)data2, dataSize2); + return CompareFileNames_Le16( + (const Byte *)data1 + r1.Offset, r1.Size, + (const Byte *)data2 + r2.Offset, r2.Size); + } + } + + if (panel->_folderCompare) + return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp); + + switch (propID) + { + // if (panel->_sortIndex == 0) + case kpidName: + { + const UString name1 = panel->GetItemName((unsigned)lParam1); + const UString name2 = panel->GetItemName((unsigned)lParam2); + const int res = CompareFileNames_ForFolderList(name1, name2); + /* + if (res != 0 || !panel->_flatMode) + return res; + const UString prefix1 = panel->GetItemPrefix(lParam1); + const UString prefix2 = panel->GetItemPrefix(lParam2); + return res = CompareFileNames_ForFolderList(prefix1, prefix2); + */ + return res; + } + case kpidExtension: + { + const UString name1 = panel->GetItemName((unsigned)lParam1); + const UString name2 = panel->GetItemName((unsigned)lParam2); + return CompareFileNames_ForFolderList( + GetExtensionPtr(name1), + GetExtensionPtr(name2)); + } + } + /* + if (panel->_sortIndex == 1) + return MyCompare(file1.Size, file2.Size); + return ::CompareFileTime(&file1.MTime, &file2.MTime); + */ + + // PROPID propID = panel->_columns[panel->_sortIndex].ID; + + NCOM::CPropVariant prop1, prop2; + // Name must be first property + panel->_folder->GetProperty((UInt32)lParam1, propID, &prop1); + panel->_folder->GetProperty((UInt32)lParam2, propID, &prop2); + if (prop1.vt != prop2.vt) + return MyCompare(prop1.vt, prop2.vt); + if (prop1.vt == VT_BSTR) + return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal); + return prop1.Compare(prop2); +} + +int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData); +int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData) +{ + if (lpData == 0) return 0; + if (lParam1 == (int)kParentIndex) return -1; + if (lParam2 == (int)kParentIndex) return 1; + + CPanel *panel = (CPanel*)lpData; + + const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1); + const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2); + + if (isDir1 && !isDir2) return -1; + if (isDir2 && !isDir1) return 1; + + const int result = CompareItems2(lParam1, lParam2, lpData); + return panel->_ascending ? result: (-result); +} + + +/* +void CPanel::SortItems(int index) +{ + if (index == _sortIndex) + _ascending = !_ascending; + else + { + _sortIndex = index; + _ascending = true; + switch (_columns[_sortIndex].ID) + { + case kpidSize: + case kpidPackedSize: + case kpidCTime: + case kpidATime: + case kpidMTime: + _ascending = false; + break; + } + } + _listView.SortItems(CompareItems, (LPARAM)this); + _listView.EnsureVisible(_listView.GetFocusedItem(), false); +} + +void CPanel::SortItemsWithPropID(PROPID propID) +{ + int index = _columns.FindItem_for_PropID(propID); + if (index >= 0) + SortItems(index); +} +*/ + +void CPanel::SortItemsWithPropID(PROPID propID) +{ + if (propID == _sortID) + _ascending = !_ascending; + else + { + _sortID = propID; + _ascending = true; + switch (propID) + { + case kpidSize: + case kpidPackSize: + case kpidCTime: + case kpidATime: + case kpidMTime: + _ascending = false; + break; + } + } + SetSortRawStatus(); + _listView.SortItems(CompareItems, (LPARAM)this); + _listView.EnsureVisible(_listView.GetFocusedItem(), false); +} + + +void CPanel::OnColumnClick(LPNMLISTVIEW info) +{ + /* + int index = _columns.FindItem_for_PropID(_visibleColumns[info->iSubItem].ID); + SortItems(index); + */ + SortItemsWithPropID(_visibleColumns[info->iSubItem].ID); +} diff --git a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp index 03ecebbf3..c452d41c1 100644 --- a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp +++ b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp @@ -1,562 +1,562 @@ -// PanelSplitFile.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/FileName.h" - -#include "../GUI/ExtractRes.h" - -#include "resource.h" - -#include "App.h" -#include "CopyDialog.h" -#include "FormatUtils.h" -#include "LangUtils.h" -#include "SplitDialog.h" -#include "SplitUtils.h" - -#include "PropertyNameRes.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static const char * const g_Message_FileWriteError = "File write error"; - -struct CVolSeqName -{ - UString UnchangedPart; - UString ChangedPart; - CVolSeqName(): ChangedPart("000") {} - - void SetNumDigits(UInt64 numVolumes) - { - ChangedPart = "000"; - while (numVolumes > 999) - { - numVolumes /= 10; - ChangedPart.Add_Char('0'); - } - } - - bool ParseName(const UString &name) - { - if (name.Len() < 2) - return false; - if (name.Back() != L'1' || name[name.Len() - 2] != L'0') - return false; - - unsigned pos = name.Len() - 2; - for (; pos > 0 && name[pos - 1] == '0'; pos--); - UnchangedPart.SetFrom(name, pos); - ChangedPart = name.Ptr(pos); - return true; - } - - UString GetNextName(); -}; - - -UString CVolSeqName::GetNextName() -{ - for (int i = (int)ChangedPart.Len() - 1; i >= 0; i--) - { - const wchar_t c = ChangedPart[i]; - if (c != L'9') - { - ChangedPart.ReplaceOneCharAtPos((unsigned)i, (wchar_t)(c + 1)); - break; - } - ChangedPart.ReplaceOneCharAtPos((unsigned)i, L'0'); - if (i == 0) - ChangedPart.InsertAtFront(L'1'); - } - return UnchangedPart + ChangedPart; -} - -class CThreadSplit: public CProgressThreadVirt -{ - HRESULT ProcessVirt() Z7_override; -public: - FString FilePath; - FString VolBasePath; - UInt64 NumVolumes; - CRecordVector VolumeSizes; -}; - - -class CPreAllocOutFile -{ - UInt64 _preAllocSize; -public: - NIO::COutFile File; - UInt64 Written; - - CPreAllocOutFile(): _preAllocSize(0), Written(0) {} - - ~CPreAllocOutFile() - { - SetCorrectFileLength(); - } - - void PreAlloc(UInt64 preAllocSize) - { - _preAllocSize = 0; - if (File.SetLength(preAllocSize)) - _preAllocSize = preAllocSize; - File.SeekToBegin(); - } - - bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw() - { - bool res = File.Write(data, size, processedSize); - Written += processedSize; - return res; - } - - void Close() - { - SetCorrectFileLength(); - Written = 0; - _preAllocSize = 0; - File.Close(); - } - - void SetCorrectFileLength() - { - if (Written < _preAllocSize) - { - File.SetLength(Written); - _preAllocSize = 0; - } - } -}; - - -static const UInt32 kBufSize = (1 << 20); - -HRESULT CThreadSplit::ProcessVirt() -{ - NIO::CInFile inFile; - if (!inFile.Open(FilePath)) - return GetLastError_noZero_HRESULT(); - - CPreAllocOutFile outFile; - - CMyBuffer buffer; - if (!buffer.Allocate(kBufSize)) - return E_OUTOFMEMORY; - - CVolSeqName seqName; - seqName.SetNumDigits(NumVolumes); - - UInt64 length; - if (!inFile.GetLength(length)) - return GetLastError_noZero_HRESULT(); - - CProgressSync &sync = Sync; - sync.Set_NumBytesTotal(length); - - UInt64 pos = 0; - UInt64 prev = 0; - UInt64 numFiles = 0; - unsigned volIndex = 0; - - for (;;) - { - UInt64 volSize; - if (volIndex < VolumeSizes.Size()) - volSize = VolumeSizes[volIndex]; - else - volSize = VolumeSizes.Back(); - - UInt32 needSize = kBufSize; - { - const UInt64 rem = volSize - outFile.Written; - if (needSize > rem) - needSize = (UInt32)rem; - } - UInt32 processedSize; - if (!inFile.Read(buffer, needSize, processedSize)) - return GetLastError_noZero_HRESULT(); - if (processedSize == 0) - return S_OK; - needSize = processedSize; - - if (outFile.Written == 0) - { - FString name = VolBasePath; - name.Add_Dot(); - name += us2fs(seqName.GetNextName()); - sync.Set_FilePath(fs2us(name)); - if (!outFile.File.Create_NEW(name)) - { - const HRESULT res = GetLastError_noZero_HRESULT(); - AddErrorPath(name); - return res; - } - UInt64 expectSize = volSize; - if (pos < length) - { - const UInt64 rem = length - pos; - if (expectSize > rem) - expectSize = rem; - } - outFile.PreAlloc(expectSize); - } - - if (!outFile.Write(buffer, needSize, processedSize)) - return GetLastError_noZero_HRESULT(); - if (needSize != processedSize) - throw g_Message_FileWriteError; - - pos += processedSize; - - if (outFile.Written == volSize) - { - outFile.Close(); - sync.Set_NumFilesCur(++numFiles); - if (volIndex < VolumeSizes.Size()) - volIndex++; - } - - if (pos - prev >= ((UInt32)1 << 22) || outFile.Written == 0) - { - RINOK(sync.Set_NumBytesCur(pos)) - prev = pos; - } - } -} - - -void CApp::Split() -{ - const unsigned srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - if (!srcPanel.Is_IO_FS_Folder()) - { - srcPanel.MessageBox_Error_UnsupportOperation(); - return; - } - CRecordVector indices; - srcPanel.Get_ItemIndices_Operated(indices); - if (indices.IsEmpty()) - return; - if (indices.Size() != 1) - { - srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); - return; - } - const unsigned index = indices[0]; - if (srcPanel.IsItem_Folder(index)) - { - srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); - return; - } - const UString itemName = srcPanel.GetItemName(index); - - const UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index); - UString path = srcPath; - unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); - CPanel &destPanel = Panels[destPanelIndex]; - if (NumPanels > 1) - if (destPanel.IsFSFolder()) - path = destPanel.GetFsPath(); - CSplitDialog splitDialog; - splitDialog.FilePath = srcPanel.GetItemRelPath(index); - splitDialog.Path = path; - if (splitDialog.Create(srcPanel.GetParent()) != IDOK) - return; - - NFind::CFileInfo fileInfo; - if (!fileInfo.Find(us2fs(srcPath + itemName))) - { - srcPanel.MessageBox_Error(L"Cannot find file"); - return; - } - if (fileInfo.Size <= splitDialog.VolumeSizes.FrontItem()) - { - srcPanel.MessageBox_Error_LangID(IDS_SPLIT_VOL_MUST_BE_SMALLER); - return; - } - const UInt64 numVolumes = GetNumberOfVolumes(fileInfo.Size, splitDialog.VolumeSizes); - if (numVolumes >= 100) - { - wchar_t s[32]; - ConvertUInt64ToString(numVolumes, s); - if (::MessageBoxW(srcPanel, MyFormatNew(IDS_SPLIT_CONFIRM_MESSAGE, s), - LangString(IDS_SPLIT_CONFIRM_TITLE), - MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) - return; - } - - path = splitDialog.Path; - NName::NormalizeDirPathPrefix(path); - if (!CreateComplexDir(us2fs(path))) - { - const HRESULT lastError = GetLastError_noZero_HRESULT(); - srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError); - return; - } - - { - CThreadSplit spliter; - spliter.NumVolumes = numVolumes; - - CProgressDialog &progressDialog = spliter; - - const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); - const UString title = LangString(IDS_SPLITTING); - - progressDialog.ShowCompressionInfo = false; - - progressDialog.MainWindow = _window; - progressDialog.MainTitle = progressWindowTitle; - progressDialog.MainAddTitle = title; - progressDialog.MainAddTitle.Add_Space(); - progressDialog.Sync.Set_TitleFileName(itemName); - - - spliter.FilePath = us2fs(srcPath + itemName); - spliter.VolBasePath = us2fs(path + srcPanel.GetItemName_for_Copy(index)); - spliter.VolumeSizes = splitDialog.VolumeSizes; - - // if (splitDialog.VolumeSizes.Size() == 0) return; - - // CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel); - // CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel); - - if (spliter.Create(title, _window) != 0) - return; - } - RefreshTitleAlways(); - - - // disableNotify.Restore(); - // disableNotify.Restore(); - // srcPanel.SetFocusToList(); - // srcPanel.RefreshListCtrlSaveFocused(); -} - - -class CThreadCombine: public CProgressThreadVirt -{ - HRESULT ProcessVirt() Z7_override; -public: - FString InputDirPrefix; - FStringVector Names; - FString OutputPath; - UInt64 TotalSize; -}; - -HRESULT CThreadCombine::ProcessVirt() -{ - NIO::COutFile outFile; - if (!outFile.Create_NEW(OutputPath)) - { - const HRESULT res = GetLastError_noZero_HRESULT(); - AddErrorPath(OutputPath); - return res; - } - - CProgressSync &sync = Sync; - sync.Set_NumBytesTotal(TotalSize); - - CMyBuffer bufferObject; - if (!bufferObject.Allocate(kBufSize)) - return E_OUTOFMEMORY; - Byte *buffer = (Byte *)(void *)bufferObject; - UInt64 pos = 0; - FOR_VECTOR (i, Names) - { - NIO::CInFile inFile; - const FString nextName = InputDirPrefix + Names[i]; - if (!inFile.Open(nextName)) - { - const HRESULT res = GetLastError_noZero_HRESULT(); - AddErrorPath(nextName); - return res; - } - sync.Set_FilePath(fs2us(nextName)); - for (;;) - { - UInt32 processedSize; - if (!inFile.Read(buffer, kBufSize, processedSize)) - { - const HRESULT res = GetLastError_noZero_HRESULT(); - AddErrorPath(nextName); - return res; - } - if (processedSize == 0) - break; - const UInt32 needSize = processedSize; - if (!outFile.Write(buffer, needSize, processedSize)) - { - const HRESULT res = GetLastError_noZero_HRESULT(); - AddErrorPath(OutputPath); - return res; - } - if (needSize != processedSize) - throw g_Message_FileWriteError; - pos += processedSize; - RINOK(sync.Set_NumBytesCur(pos)) - } - } - return S_OK; -} - -extern void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size); - -static void AddInfoFileName(UString &dest, const UString &name) -{ - dest += "\n "; - dest += name; -} - -void CApp::Combine() -{ - const unsigned srcPanelIndex = GetFocusedPanelIndex(); - CPanel &srcPanel = Panels[srcPanelIndex]; - if (!srcPanel.IsFSFolder()) - { - srcPanel.MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); - return; - } - CRecordVector indices; - srcPanel.Get_ItemIndices_Operated(indices); - if (indices.IsEmpty()) - return; - const unsigned index = indices[0]; - if (indices.Size() != 1 || srcPanel.IsItem_Folder(index)) - { - srcPanel.MessageBox_Error_LangID(IDS_COMBINE_SELECT_ONE_FILE); - return; - } - const UString itemName = srcPanel.GetItemName(index); - - UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index); - UString path = srcPath; - unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); - CPanel &destPanel = Panels[destPanelIndex]; - if (NumPanels > 1) - if (destPanel.IsFSFolder()) - path = destPanel.GetFsPath(); - - CVolSeqName volSeqName; - if (!volSeqName.ParseName(itemName)) - { - srcPanel.MessageBox_Error_LangID(IDS_COMBINE_CANT_DETECT_SPLIT_FILE); - return; - } - - { - CThreadCombine combiner; - - UString nextName = itemName; - combiner.TotalSize = 0; - for (;;) - { - NFind::CFileInfo fileInfo; - if (!fileInfo.Find(us2fs(srcPath + nextName)) || fileInfo.IsDir()) - break; - combiner.Names.Add(us2fs(nextName)); - combiner.TotalSize += fileInfo.Size; - nextName = volSeqName.GetNextName(); - } - if (combiner.Names.Size() == 1) - { - srcPanel.MessageBox_Error_LangID(IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART); - return; - } - - if (combiner.TotalSize == 0) - { - srcPanel.MessageBox_Error(L"No data"); - return; - } - - UString info; - AddValuePair2(info, IDS_PROP_FILES, combiner.Names.Size(), combiner.TotalSize); - - info.Add_LF(); - info += srcPath; - - unsigned i; - for (i = 0; i < combiner.Names.Size() && i < 2; i++) - AddInfoFileName(info, fs2us(combiner.Names[i])); - if (i != combiner.Names.Size()) - { - if (i + 1 != combiner.Names.Size()) - AddInfoFileName(info, L"..."); - AddInfoFileName(info, fs2us(combiner.Names.Back())); - } - - { - CCopyDialog copyDialog; - copyDialog.Value = path; - LangString(IDS_COMBINE, copyDialog.Title); - copyDialog.Title.Add_Space(); - copyDialog.Title += srcPanel.GetItemRelPath(index); - LangString(IDS_COMBINE_TO, copyDialog.Static); - copyDialog.Info = info; - if (copyDialog.Create(srcPanel.GetParent()) != IDOK) - return; - path = copyDialog.Value; - } - - NName::NormalizeDirPathPrefix(path); - if (!CreateComplexDir(us2fs(path))) - { - const HRESULT lastError = GetLastError_noZero_HRESULT(); - srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError); - return; - } - - UString outName = volSeqName.UnchangedPart; - while (!outName.IsEmpty()) - { - if (outName.Back() != L'.') - break; - outName.DeleteBack(); - } - if (outName.IsEmpty()) - outName = "file"; - - NFind::CFileInfo fileInfo; - UString destFilePath = path + outName; - combiner.OutputPath = us2fs(destFilePath); - if (fileInfo.Find(combiner.OutputPath)) - { - srcPanel.MessageBox_Error(MyFormatNew(IDS_FILE_EXIST, destFilePath)); - return; - } - - CProgressDialog &progressDialog = combiner; - progressDialog.ShowCompressionInfo = false; - - const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); - const UString title = LangString(IDS_COMBINING); - - progressDialog.MainWindow = _window; - progressDialog.MainTitle = progressWindowTitle; - progressDialog.MainAddTitle = title; - progressDialog.MainAddTitle.Add_Space(); - - combiner.InputDirPrefix = us2fs(srcPath); - - // CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel); - // CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel); - - if (combiner.Create(title, _window) != 0) - return; - } - RefreshTitleAlways(); - - // disableNotify.Restore(); - // disableNotify.Restore(); - // srcPanel.SetFocusToList(); - // srcPanel.RefreshListCtrlSaveFocused(); -} +// PanelSplitFile.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/FileName.h" + +#include "../GUI/ExtractRes.h" + +#include "resource.h" + +#include "App.h" +#include "CopyDialog.h" +#include "FormatUtils.h" +#include "LangUtils.h" +#include "SplitDialog.h" +#include "SplitUtils.h" + +#include "PropertyNameRes.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static const char * const g_Message_FileWriteError = "File write error"; + +struct CVolSeqName +{ + UString UnchangedPart; + UString ChangedPart; + CVolSeqName(): ChangedPart("000") {} + + void SetNumDigits(UInt64 numVolumes) + { + ChangedPart = "000"; + while (numVolumes > 999) + { + numVolumes /= 10; + ChangedPart.Add_Char('0'); + } + } + + bool ParseName(const UString &name) + { + if (name.Len() < 2) + return false; + if (name.Back() != L'1' || name[name.Len() - 2] != L'0') + return false; + + unsigned pos = name.Len() - 2; + for (; pos > 0 && name[pos - 1] == '0'; pos--); + UnchangedPart.SetFrom(name, pos); + ChangedPart = name.Ptr(pos); + return true; + } + + UString GetNextName(); +}; + + +UString CVolSeqName::GetNextName() +{ + for (int i = (int)ChangedPart.Len() - 1; i >= 0; i--) + { + const wchar_t c = ChangedPart[i]; + if (c != L'9') + { + ChangedPart.ReplaceOneCharAtPos((unsigned)i, (wchar_t)(c + 1)); + break; + } + ChangedPart.ReplaceOneCharAtPos((unsigned)i, L'0'); + if (i == 0) + ChangedPart.InsertAtFront(L'1'); + } + return UnchangedPart + ChangedPart; +} + +class CThreadSplit: public CProgressThreadVirt +{ + HRESULT ProcessVirt() Z7_override; +public: + FString FilePath; + FString VolBasePath; + UInt64 NumVolumes; + CRecordVector VolumeSizes; +}; + + +class CPreAllocOutFile +{ + UInt64 _preAllocSize; +public: + NIO::COutFile File; + UInt64 Written; + + CPreAllocOutFile(): _preAllocSize(0), Written(0) {} + + ~CPreAllocOutFile() + { + SetCorrectFileLength(); + } + + void PreAlloc(UInt64 preAllocSize) + { + _preAllocSize = 0; + if (File.SetLength(preAllocSize)) + _preAllocSize = preAllocSize; + File.SeekToBegin(); + } + + bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw() + { + bool res = File.Write(data, size, processedSize); + Written += processedSize; + return res; + } + + void Close() + { + SetCorrectFileLength(); + Written = 0; + _preAllocSize = 0; + File.Close(); + } + + void SetCorrectFileLength() + { + if (Written < _preAllocSize) + { + File.SetLength(Written); + _preAllocSize = 0; + } + } +}; + + +static const UInt32 kBufSize = (1 << 20); + +HRESULT CThreadSplit::ProcessVirt() +{ + NIO::CInFile inFile; + if (!inFile.Open(FilePath)) + return GetLastError_noZero_HRESULT(); + + CPreAllocOutFile outFile; + + CMyBuffer buffer; + if (!buffer.Allocate(kBufSize)) + return E_OUTOFMEMORY; + + CVolSeqName seqName; + seqName.SetNumDigits(NumVolumes); + + UInt64 length; + if (!inFile.GetLength(length)) + return GetLastError_noZero_HRESULT(); + + CProgressSync &sync = Sync; + sync.Set_NumBytesTotal(length); + + UInt64 pos = 0; + UInt64 prev = 0; + UInt64 numFiles = 0; + unsigned volIndex = 0; + + for (;;) + { + UInt64 volSize; + if (volIndex < VolumeSizes.Size()) + volSize = VolumeSizes[volIndex]; + else + volSize = VolumeSizes.Back(); + + UInt32 needSize = kBufSize; + { + const UInt64 rem = volSize - outFile.Written; + if (needSize > rem) + needSize = (UInt32)rem; + } + UInt32 processedSize; + if (!inFile.Read(buffer, needSize, processedSize)) + return GetLastError_noZero_HRESULT(); + if (processedSize == 0) + return S_OK; + needSize = processedSize; + + if (outFile.Written == 0) + { + FString name = VolBasePath; + name.Add_Dot(); + name += us2fs(seqName.GetNextName()); + sync.Set_FilePath(fs2us(name)); + if (!outFile.File.Create_NEW(name)) + { + const HRESULT res = GetLastError_noZero_HRESULT(); + AddErrorPath(name); + return res; + } + UInt64 expectSize = volSize; + if (pos < length) + { + const UInt64 rem = length - pos; + if (expectSize > rem) + expectSize = rem; + } + outFile.PreAlloc(expectSize); + } + + if (!outFile.Write(buffer, needSize, processedSize)) + return GetLastError_noZero_HRESULT(); + if (needSize != processedSize) + throw g_Message_FileWriteError; + + pos += processedSize; + + if (outFile.Written == volSize) + { + outFile.Close(); + sync.Set_NumFilesCur(++numFiles); + if (volIndex < VolumeSizes.Size()) + volIndex++; + } + + if (pos - prev >= ((UInt32)1 << 22) || outFile.Written == 0) + { + RINOK(sync.Set_NumBytesCur(pos)) + prev = pos; + } + } +} + + +void CApp::Split() +{ + const unsigned srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + if (!srcPanel.Is_IO_FS_Folder()) + { + srcPanel.MessageBox_Error_UnsupportOperation(); + return; + } + CRecordVector indices; + srcPanel.Get_ItemIndices_Operated(indices); + if (indices.IsEmpty()) + return; + if (indices.Size() != 1) + { + srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); + return; + } + const unsigned index = indices[0]; + if (srcPanel.IsItem_Folder(index)) + { + srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE); + return; + } + const UString itemName = srcPanel.GetItemName(index); + + const UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index); + UString path = srcPath; + unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); + CPanel &destPanel = Panels[destPanelIndex]; + if (NumPanels > 1) + if (destPanel.IsFSFolder()) + path = destPanel.GetFsPath(); + CSplitDialog splitDialog; + splitDialog.FilePath = srcPanel.GetItemRelPath(index); + splitDialog.Path = path; + if (splitDialog.Create(srcPanel.GetParent()) != IDOK) + return; + + NFind::CFileInfo fileInfo; + if (!fileInfo.Find(us2fs(srcPath + itemName))) + { + srcPanel.MessageBox_Error(L"Cannot find file"); + return; + } + if (fileInfo.Size <= splitDialog.VolumeSizes.FrontItem()) + { + srcPanel.MessageBox_Error_LangID(IDS_SPLIT_VOL_MUST_BE_SMALLER); + return; + } + const UInt64 numVolumes = GetNumberOfVolumes(fileInfo.Size, splitDialog.VolumeSizes); + if (numVolumes >= 100) + { + wchar_t s[32]; + ConvertUInt64ToString(numVolumes, s); + if (::MessageBoxW(srcPanel, MyFormatNew(IDS_SPLIT_CONFIRM_MESSAGE, s), + LangString(IDS_SPLIT_CONFIRM_TITLE), + MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) + return; + } + + path = splitDialog.Path; + NName::NormalizeDirPathPrefix(path); + if (!CreateComplexDir(us2fs(path))) + { + const HRESULT lastError = GetLastError_noZero_HRESULT(); + srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError); + return; + } + + { + CThreadSplit spliter; + spliter.NumVolumes = numVolumes; + + CProgressDialog &progressDialog = spliter; + + const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); + const UString title = LangString(IDS_SPLITTING); + + progressDialog.ShowCompressionInfo = false; + + progressDialog.MainWindow = _window; + progressDialog.MainTitle = progressWindowTitle; + progressDialog.MainAddTitle = title; + progressDialog.MainAddTitle.Add_Space(); + progressDialog.Sync.Set_TitleFileName(itemName); + + + spliter.FilePath = us2fs(srcPath + itemName); + spliter.VolBasePath = us2fs(path + srcPanel.GetItemName_for_Copy(index)); + spliter.VolumeSizes = splitDialog.VolumeSizes; + + // if (splitDialog.VolumeSizes.Size() == 0) return; + + // CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel); + // CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel); + + if (spliter.Create(title, _window) != 0) + return; + } + RefreshTitleAlways(); + + + // disableNotify.Restore(); + // disableNotify.Restore(); + // srcPanel.SetFocusToList(); + // srcPanel.RefreshListCtrlSaveFocused(); +} + + +class CThreadCombine: public CProgressThreadVirt +{ + HRESULT ProcessVirt() Z7_override; +public: + FString InputDirPrefix; + FStringVector Names; + FString OutputPath; + UInt64 TotalSize; +}; + +HRESULT CThreadCombine::ProcessVirt() +{ + NIO::COutFile outFile; + if (!outFile.Create_NEW(OutputPath)) + { + const HRESULT res = GetLastError_noZero_HRESULT(); + AddErrorPath(OutputPath); + return res; + } + + CProgressSync &sync = Sync; + sync.Set_NumBytesTotal(TotalSize); + + CMyBuffer bufferObject; + if (!bufferObject.Allocate(kBufSize)) + return E_OUTOFMEMORY; + Byte *buffer = (Byte *)(void *)bufferObject; + UInt64 pos = 0; + FOR_VECTOR (i, Names) + { + NIO::CInFile inFile; + const FString nextName = InputDirPrefix + Names[i]; + if (!inFile.Open(nextName)) + { + const HRESULT res = GetLastError_noZero_HRESULT(); + AddErrorPath(nextName); + return res; + } + sync.Set_FilePath(fs2us(nextName)); + for (;;) + { + UInt32 processedSize; + if (!inFile.Read(buffer, kBufSize, processedSize)) + { + const HRESULT res = GetLastError_noZero_HRESULT(); + AddErrorPath(nextName); + return res; + } + if (processedSize == 0) + break; + const UInt32 needSize = processedSize; + if (!outFile.Write(buffer, needSize, processedSize)) + { + const HRESULT res = GetLastError_noZero_HRESULT(); + AddErrorPath(OutputPath); + return res; + } + if (needSize != processedSize) + throw g_Message_FileWriteError; + pos += processedSize; + RINOK(sync.Set_NumBytesCur(pos)) + } + } + return S_OK; +} + +extern void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size); + +static void AddInfoFileName(UString &dest, const UString &name) +{ + dest += "\n "; + dest += name; +} + +void CApp::Combine() +{ + const unsigned srcPanelIndex = GetFocusedPanelIndex(); + CPanel &srcPanel = Panels[srcPanelIndex]; + if (!srcPanel.IsFSFolder()) + { + srcPanel.MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); + return; + } + CRecordVector indices; + srcPanel.Get_ItemIndices_Operated(indices); + if (indices.IsEmpty()) + return; + const unsigned index = indices[0]; + if (indices.Size() != 1 || srcPanel.IsItem_Folder(index)) + { + srcPanel.MessageBox_Error_LangID(IDS_COMBINE_SELECT_ONE_FILE); + return; + } + const UString itemName = srcPanel.GetItemName(index); + + UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index); + UString path = srcPath; + unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex); + CPanel &destPanel = Panels[destPanelIndex]; + if (NumPanels > 1) + if (destPanel.IsFSFolder()) + path = destPanel.GetFsPath(); + + CVolSeqName volSeqName; + if (!volSeqName.ParseName(itemName)) + { + srcPanel.MessageBox_Error_LangID(IDS_COMBINE_CANT_DETECT_SPLIT_FILE); + return; + } + + { + CThreadCombine combiner; + + UString nextName = itemName; + combiner.TotalSize = 0; + for (;;) + { + NFind::CFileInfo fileInfo; + if (!fileInfo.Find(us2fs(srcPath + nextName)) || fileInfo.IsDir()) + break; + combiner.Names.Add(us2fs(nextName)); + combiner.TotalSize += fileInfo.Size; + nextName = volSeqName.GetNextName(); + } + if (combiner.Names.Size() == 1) + { + srcPanel.MessageBox_Error_LangID(IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART); + return; + } + + if (combiner.TotalSize == 0) + { + srcPanel.MessageBox_Error(L"No data"); + return; + } + + UString info; + AddValuePair2(info, IDS_PROP_FILES, combiner.Names.Size(), combiner.TotalSize); + + info.Add_LF(); + info += srcPath; + + unsigned i; + for (i = 0; i < combiner.Names.Size() && i < 2; i++) + AddInfoFileName(info, fs2us(combiner.Names[i])); + if (i != combiner.Names.Size()) + { + if (i + 1 != combiner.Names.Size()) + AddInfoFileName(info, L"..."); + AddInfoFileName(info, fs2us(combiner.Names.Back())); + } + + { + CCopyDialog copyDialog; + copyDialog.Value = path; + LangString(IDS_COMBINE, copyDialog.Title); + copyDialog.Title.Add_Space(); + copyDialog.Title += srcPanel.GetItemRelPath(index); + LangString(IDS_COMBINE_TO, copyDialog.Static); + copyDialog.Info = info; + if (copyDialog.Create(srcPanel.GetParent()) != IDOK) + return; + path = copyDialog.Value; + } + + NName::NormalizeDirPathPrefix(path); + if (!CreateComplexDir(us2fs(path))) + { + const HRESULT lastError = GetLastError_noZero_HRESULT(); + srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError); + return; + } + + UString outName = volSeqName.UnchangedPart; + while (!outName.IsEmpty()) + { + if (outName.Back() != L'.') + break; + outName.DeleteBack(); + } + if (outName.IsEmpty()) + outName = "file"; + + NFind::CFileInfo fileInfo; + UString destFilePath = path + outName; + combiner.OutputPath = us2fs(destFilePath); + if (fileInfo.Find(combiner.OutputPath)) + { + srcPanel.MessageBox_Error(MyFormatNew(IDS_FILE_EXIST, destFilePath)); + return; + } + + CProgressDialog &progressDialog = combiner; + progressDialog.ShowCompressionInfo = false; + + const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000); + const UString title = LangString(IDS_COMBINING); + + progressDialog.MainWindow = _window; + progressDialog.MainTitle = progressWindowTitle; + progressDialog.MainAddTitle = title; + progressDialog.MainAddTitle.Add_Space(); + + combiner.InputDirPrefix = us2fs(srcPath); + + // CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel); + // CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel); + + if (combiner.Create(title, _window) != 0) + return; + } + RefreshTitleAlways(); + + // disableNotify.Restore(); + // disableNotify.Restore(); + // srcPanel.SetFocusToList(); + // srcPanel.RefreshListCtrlSaveFocused(); +} diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.cpp b/CPP/7zip/UI/FileManager/PasswordDialog.cpp index 3c7eecb88..bf995802a 100644 --- a/CPP/7zip/UI/FileManager/PasswordDialog.cpp +++ b/CPP/7zip/UI/FileManager/PasswordDialog.cpp @@ -1,58 +1,58 @@ -// PasswordDialog.cpp - -#include "StdAfx.h" - -#include "PasswordDialog.h" - -#ifdef Z7_LANG -#include "LangUtils.h" -#endif - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_PASSWORD_ENTER, - IDX_PASSWORD_SHOW -}; -#endif - -void CPasswordDialog::ReadControls() -{ - _passwordEdit.GetText(Password); - ShowPassword = IsButtonCheckedBool(IDX_PASSWORD_SHOW); -} - -void CPasswordDialog::SetTextSpec() -{ - _passwordEdit.SetPasswordChar(ShowPassword ? 0: TEXT('*')); - _passwordEdit.SetText(Password); -} - -bool CPasswordDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_PASSWORD); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - _passwordEdit.Attach(GetItem(IDE_PASSWORD_PASSWORD)); - CheckButton(IDX_PASSWORD_SHOW, ShowPassword); - SetTextSpec(); - return CModalDialog::OnInit(); -} - -bool CPasswordDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - if (buttonID == IDX_PASSWORD_SHOW) - { - ReadControls(); - SetTextSpec(); - return true; - } - return CDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CPasswordDialog::OnOK() -{ - ReadControls(); - CModalDialog::OnOK(); -} +// PasswordDialog.cpp + +#include "StdAfx.h" + +#include "PasswordDialog.h" + +#ifdef Z7_LANG +#include "LangUtils.h" +#endif + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_PASSWORD_ENTER, + IDX_PASSWORD_SHOW +}; +#endif + +void CPasswordDialog::ReadControls() +{ + _passwordEdit.GetText(Password); + ShowPassword = IsButtonCheckedBool(IDX_PASSWORD_SHOW); +} + +void CPasswordDialog::SetTextSpec() +{ + _passwordEdit.SetPasswordChar(ShowPassword ? 0: TEXT('*')); + _passwordEdit.SetText(Password); +} + +bool CPasswordDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_PASSWORD); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + _passwordEdit.Attach(GetItem(IDE_PASSWORD_PASSWORD)); + CheckButton(IDX_PASSWORD_SHOW, ShowPassword); + SetTextSpec(); + return CModalDialog::OnInit(); +} + +bool CPasswordDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + if (buttonID == IDX_PASSWORD_SHOW) + { + ReadControls(); + SetTextSpec(); + return true; + } + return CDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CPasswordDialog::OnOK() +{ + ReadControls(); + CModalDialog::OnOK(); +} diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.h b/CPP/7zip/UI/FileManager/PasswordDialog.h index e98dae755..e05c4adf7 100644 --- a/CPP/7zip/UI/FileManager/PasswordDialog.h +++ b/CPP/7zip/UI/FileManager/PasswordDialog.h @@ -1,28 +1,28 @@ -// PasswordDialog.h - -#ifndef ZIP7_INC_PASSWORD_DIALOG_H -#define ZIP7_INC_PASSWORD_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/Edit.h" - -#include "PasswordDialogRes.h" - -class CPasswordDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CEdit _passwordEdit; - - virtual void OnOK() Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - void SetTextSpec(); - void ReadControls(); -public: - UString Password; - bool ShowPassword; - - CPasswordDialog(): ShowPassword(false) {} - INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_PASSWORD, parentWindow); } -}; - -#endif +// PasswordDialog.h + +#ifndef ZIP7_INC_PASSWORD_DIALOG_H +#define ZIP7_INC_PASSWORD_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/Edit.h" + +#include "PasswordDialogRes.h" + +class CPasswordDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CEdit _passwordEdit; + + virtual void OnOK() Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + void SetTextSpec(); + void ReadControls(); +public: + UString Password; + bool ShowPassword; + + CPasswordDialog(): ShowPassword(false) {} + INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_PASSWORD, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.rc b/CPP/7zip/UI/FileManager/PasswordDialog.rc index 609976de3..fa42f929a 100644 --- a/CPP/7zip/UI/FileManager/PasswordDialog.rc +++ b/CPP/7zip/UI/FileManager/PasswordDialog.rc @@ -1,18 +1,18 @@ -#include "PasswordDialogRes.h" -#include "../../GuiCommon.rc" - -#ifdef UNDER_CE -#define xc 140 -#else -#define xc 200 -#endif -#define yc 72 - -IDD_PASSWORD DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Enter password" -BEGIN - LTEXT "&Enter password:", IDT_PASSWORD_ENTER, m, m, xc, 8 - EDITTEXT IDE_PASSWORD_PASSWORD, m, 20, xc, 14, ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "&Show password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, 42, xc, 10 - OK_CANCEL -END +#include "PasswordDialogRes.h" +#include "../../GuiCommon.rc" + +#ifdef UNDER_CE +#define xc 140 +#else +#define xc 200 +#endif +#define yc 72 + +IDD_PASSWORD DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Enter password" +BEGIN + LTEXT "&Enter password:", IDT_PASSWORD_ENTER, m, m, xc, 8 + EDITTEXT IDE_PASSWORD_PASSWORD, m, 20, xc, 14, ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "&Show password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, 42, xc, 10 + OK_CANCEL +END diff --git a/CPP/7zip/UI/FileManager/PasswordDialogRes.h b/CPP/7zip/UI/FileManager/PasswordDialogRes.h index f9300d6bc..1fe32e10a 100644 --- a/CPP/7zip/UI/FileManager/PasswordDialogRes.h +++ b/CPP/7zip/UI/FileManager/PasswordDialogRes.h @@ -1,5 +1,5 @@ -#define IDD_PASSWORD 3800 -#define IDT_PASSWORD_ENTER 3801 -#define IDX_PASSWORD_SHOW 3803 - -#define IDE_PASSWORD_PASSWORD 120 +#define IDD_PASSWORD 3800 +#define IDT_PASSWORD_ENTER 3801 +#define IDX_PASSWORD_SHOW 3803 + +#define IDE_PASSWORD_PASSWORD 120 diff --git a/CPP/7zip/UI/FileManager/PluginInterface.h b/CPP/7zip/UI/FileManager/PluginInterface.h index e6c54ed65..dcb1b4b84 100644 --- a/CPP/7zip/UI/FileManager/PluginInterface.h +++ b/CPP/7zip/UI/FileManager/PluginInterface.h @@ -1,32 +1,32 @@ -// PluginInterface.h - -#ifndef ZIP7_INC_PLUGIN_INTERFACE_H -#define ZIP7_INC_PLUGIN_INTERFACE_H - -/* -#include "../../../../C/7zTypes.h" -#include "../../IDecl.h" - -#define Z7_IFACE_CONSTR_PLUGIN(i, n) \ - Z7_DECL_IFACE_7ZIP(i, 0x0A, n) \ - { Z7_IFACE_COM7_PURE(i) }; - -#define Z7_IFACEM_IInitContextMenu(x) \ - x(InitContextMenu(const wchar_t *folder, const wchar_t * const *names, UInt32 numFiles)) \ - -Z7_IFACE_CONSTR_PLUGIN(IInitContextMenu, 0x00) - -#define Z7_IFACEM_IPluginOptionsCallback(x) \ - x(GetProgramFolderPath(BSTR *value)) \ - x(GetProgramPath(BSTR *value)) \ - x(GetRegistryCUPath(BSTR *value)) \ - -Z7_IFACE_CONSTR_PLUGIN(IPluginOptionsCallback, 0x01) - -#define Z7_IFACEM_IPluginOptions(x) \ - x(PluginOptions(HWND hWnd, IPluginOptionsCallback *callback)) \ - // x(GetFileExtensions(BSTR *extensions)) - -Z7_IFACE_CONSTR_PLUGIN(IPluginOptions, 0x02) -*/ -#endif +// PluginInterface.h + +#ifndef ZIP7_INC_PLUGIN_INTERFACE_H +#define ZIP7_INC_PLUGIN_INTERFACE_H + +/* +#include "../../../../C/7zTypes.h" +#include "../../IDecl.h" + +#define Z7_IFACE_CONSTR_PLUGIN(i, n) \ + Z7_DECL_IFACE_7ZIP(i, 0x0A, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACEM_IInitContextMenu(x) \ + x(InitContextMenu(const wchar_t *folder, const wchar_t * const *names, UInt32 numFiles)) \ + +Z7_IFACE_CONSTR_PLUGIN(IInitContextMenu, 0x00) + +#define Z7_IFACEM_IPluginOptionsCallback(x) \ + x(GetProgramFolderPath(BSTR *value)) \ + x(GetProgramPath(BSTR *value)) \ + x(GetRegistryCUPath(BSTR *value)) \ + +Z7_IFACE_CONSTR_PLUGIN(IPluginOptionsCallback, 0x01) + +#define Z7_IFACEM_IPluginOptions(x) \ + x(PluginOptions(HWND hWnd, IPluginOptionsCallback *callback)) \ + // x(GetFileExtensions(BSTR *extensions)) + +Z7_IFACE_CONSTR_PLUGIN(IPluginOptions, 0x02) +*/ +#endif diff --git a/CPP/7zip/UI/FileManager/PluginLoader.h b/CPP/7zip/UI/FileManager/PluginLoader.h index 77b738999..476a7b747 100644 --- a/CPP/7zip/UI/FileManager/PluginLoader.h +++ b/CPP/7zip/UI/FileManager/PluginLoader.h @@ -1,33 +1,33 @@ -// PluginLoader.h - -#ifndef ZIP7_INC_PLUGIN_LOADER_H -#define ZIP7_INC_PLUGIN_LOADER_H - -#include "../../../Windows/DLL.h" - -#include "IFolder.h" - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -class CPluginLibrary: public NWindows::NDLL::CLibrary -{ -public: - HRESULT CreateManager(REFGUID clsID, IFolderManager **manager) - { - const - Func_CreateObject createObject = Z7_GET_PROC_ADDRESS( - Func_CreateObject, Get_HMODULE(), - "CreateObject"); - if (!createObject) - return GetLastError_noZero_HRESULT(); - return createObject(&clsID, &IID_IFolderManager, (void **)manager); - } - HRESULT LoadAndCreateManager(CFSTR filePath, REFGUID clsID, IFolderManager **manager) - { - if (!Load(filePath)) - return GetLastError_noZero_HRESULT(); - return CreateManager(clsID, manager); - } -}; - -#endif +// PluginLoader.h + +#ifndef ZIP7_INC_PLUGIN_LOADER_H +#define ZIP7_INC_PLUGIN_LOADER_H + +#include "../../../Windows/DLL.h" + +#include "IFolder.h" + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +class CPluginLibrary: public NWindows::NDLL::CLibrary +{ +public: + HRESULT CreateManager(REFGUID clsID, IFolderManager **manager) + { + const + Func_CreateObject createObject = Z7_GET_PROC_ADDRESS( + Func_CreateObject, Get_HMODULE(), + "CreateObject"); + if (!createObject) + return GetLastError_noZero_HRESULT(); + return createObject(&clsID, &IID_IFolderManager, (void **)manager); + } + HRESULT LoadAndCreateManager(CFSTR filePath, REFGUID clsID, IFolderManager **manager) + { + if (!Load(filePath)) + return GetLastError_noZero_HRESULT(); + return CreateManager(clsID, manager); + } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.cpp b/CPP/7zip/UI/FileManager/ProgramLocation.cpp index ea6cd8da0..50ca5ca5e 100644 --- a/CPP/7zip/UI/FileManager/ProgramLocation.cpp +++ b/CPP/7zip/UI/FileManager/ProgramLocation.cpp @@ -1,3 +1,3 @@ -// ProgramLocation.cpp - -#include "StdAfx.h" +// ProgramLocation.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.h b/CPP/7zip/UI/FileManager/ProgramLocation.h index e816d44b7..0cd9c747e 100644 --- a/CPP/7zip/UI/FileManager/ProgramLocation.h +++ b/CPP/7zip/UI/FileManager/ProgramLocation.h @@ -1,6 +1,6 @@ -// ProgramLocation.h - -#ifndef ZIP7_INC_PROGRAM_LOCATION_H -#define ZIP7_INC_PROGRAM_LOCATION_H - -#endif +// ProgramLocation.h + +#ifndef ZIP7_INC_PROGRAM_LOCATION_H +#define ZIP7_INC_PROGRAM_LOCATION_H + +#endif diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.cpp b/CPP/7zip/UI/FileManager/ProgressDialog.cpp index a0fbd54e1..fc6f55992 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog.cpp +++ b/CPP/7zip/UI/FileManager/ProgressDialog.cpp @@ -1,201 +1,201 @@ -// ProgressDialog.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "resource.h" - -#include "ProgressDialog.h" - -using namespace NWindows; - -extern HINSTANCE g_hInstance; - -static const UINT_PTR kTimerID = 3; -static const UINT kTimerElapse = 100; - -#ifdef Z7_LANG -#include "LangUtils.h" -#endif - -HRESULT CProgressSync::ProcessStopAndPause() -{ - for (;;) - { - if (GetStopped()) - return E_ABORT; - if (!GetPaused()) - break; - ::Sleep(100); - } - return S_OK; -} - -#ifndef Z7_SFX -CProgressDialog::~CProgressDialog() -{ - AddToTitle(L""); -} -void CProgressDialog::AddToTitle(LPCWSTR s) -{ - if (MainWindow != 0) - MySetWindowText(MainWindow, UString(s) + MainTitle); -} -#endif - - -#define UNDEFINED_VAL ((UInt64)(Int64)-1) - -bool CProgressDialog::OnInit() -{ - _range = UNDEFINED_VAL; - _prevPercentValue = UNDEFINED_VAL; - - _wasCreated = true; - _dialogCreatedEvent.Set(); - - #ifdef Z7_LANG - LangSetDlgItems(*this, NULL, 0); - #endif - - m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); - - if (IconID >= 0) - { - HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID)); - SetIcon(ICON_BIG, icon); - } - - _timer = SetTimer(kTimerID, kTimerElapse); - SetText(_title); - CheckNeedClose(); - return CModalDialog::OnInit(); -} - -void CProgressDialog::OnCancel() { Sync.SetStopped(true); } -void CProgressDialog::OnOK() { } - -void CProgressDialog::SetRange(UInt64 range) -{ - _range = range; - _peviousPos = (UInt64)(Int64)-1; - _converter.Init(range); - m_ProgressBar.SetRange32(0 , _converter.Count(range)); // Test it for 100% -} - -void CProgressDialog::SetPos(UInt64 pos) -{ - bool redraw = true; - if (pos < _range && pos > _peviousPos) - { - UInt64 posDelta = pos - _peviousPos; - if (posDelta < (_range >> 10)) - redraw = false; - } - if (redraw) - { - m_ProgressBar.SetPos(_converter.Count(pos)); // Test it for 100% - _peviousPos = pos; - } -} - -bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) -{ - if (Sync.GetPaused()) - return true; - - CheckNeedClose(); - - UInt64 total, completed; - Sync.GetProgress(total, completed); - if (total != _range) - SetRange(total); - SetPos(completed); - - if (total == 0) - total = 1; - - const UInt64 percentValue = completed * 100 / total; - if (percentValue != _prevPercentValue) - { - wchar_t s[64]; - ConvertUInt64ToString(percentValue, s); - UString title = s; - title += "% "; - SetText(title + _title); - #ifndef Z7_SFX - AddToTitle(title + MainAddTitle); - #endif - _prevPercentValue = percentValue; - } - return true; -} - -bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case kCloseMessage: - { - if (_timer) - { - KillTimer(kTimerID); - _timer = 0; - } - if (_inCancelMessageBox) - { - _externalCloseMessageWasReceived = true; - break; - } - return OnExternalCloseMessage(); - } - /* - case WM_SETTEXT: - { - if (_timer == 0) - return true; - } - */ - } - return CModalDialog::OnMessage(message, wParam, lParam); -} - -bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDCANCEL: - { - bool paused = Sync.GetPaused(); - Sync.SetPaused(true); - _inCancelMessageBox = true; - int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNOCANCEL); - _inCancelMessageBox = false; - Sync.SetPaused(paused); - if (res == IDCANCEL || res == IDNO) - { - if (_externalCloseMessageWasReceived) - OnExternalCloseMessage(); - return true; - } - break; - } - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CProgressDialog::CheckNeedClose() -{ - if (_needClose) - { - PostMsg(kCloseMessage); - _needClose = false; - } -} - -bool CProgressDialog::OnExternalCloseMessage() -{ - End(0); - return true; -} +// ProgressDialog.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "resource.h" + +#include "ProgressDialog.h" + +using namespace NWindows; + +extern HINSTANCE g_hInstance; + +static const UINT_PTR kTimerID = 3; +static const UINT kTimerElapse = 100; + +#ifdef Z7_LANG +#include "LangUtils.h" +#endif + +HRESULT CProgressSync::ProcessStopAndPause() +{ + for (;;) + { + if (GetStopped()) + return E_ABORT; + if (!GetPaused()) + break; + ::Sleep(100); + } + return S_OK; +} + +#ifndef Z7_SFX +CProgressDialog::~CProgressDialog() +{ + AddToTitle(L""); +} +void CProgressDialog::AddToTitle(LPCWSTR s) +{ + if (MainWindow != 0) + MySetWindowText(MainWindow, UString(s) + MainTitle); +} +#endif + + +#define UNDEFINED_VAL ((UInt64)(Int64)-1) + +bool CProgressDialog::OnInit() +{ + _range = UNDEFINED_VAL; + _prevPercentValue = UNDEFINED_VAL; + + _wasCreated = true; + _dialogCreatedEvent.Set(); + + #ifdef Z7_LANG + LangSetDlgItems(*this, NULL, 0); + #endif + + m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); + + if (IconID >= 0) + { + HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID)); + SetIcon(ICON_BIG, icon); + } + + _timer = SetTimer(kTimerID, kTimerElapse); + SetText(_title); + CheckNeedClose(); + return CModalDialog::OnInit(); +} + +void CProgressDialog::OnCancel() { Sync.SetStopped(true); } +void CProgressDialog::OnOK() { } + +void CProgressDialog::SetRange(UInt64 range) +{ + _range = range; + _peviousPos = (UInt64)(Int64)-1; + _converter.Init(range); + m_ProgressBar.SetRange32(0 , _converter.Count(range)); // Test it for 100% +} + +void CProgressDialog::SetPos(UInt64 pos) +{ + bool redraw = true; + if (pos < _range && pos > _peviousPos) + { + UInt64 posDelta = pos - _peviousPos; + if (posDelta < (_range >> 10)) + redraw = false; + } + if (redraw) + { + m_ProgressBar.SetPos(_converter.Count(pos)); // Test it for 100% + _peviousPos = pos; + } +} + +bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) +{ + if (Sync.GetPaused()) + return true; + + CheckNeedClose(); + + UInt64 total, completed; + Sync.GetProgress(total, completed); + if (total != _range) + SetRange(total); + SetPos(completed); + + if (total == 0) + total = 1; + + const UInt64 percentValue = completed * 100 / total; + if (percentValue != _prevPercentValue) + { + wchar_t s[64]; + ConvertUInt64ToString(percentValue, s); + UString title = s; + title += "% "; + SetText(title + _title); + #ifndef Z7_SFX + AddToTitle(title + MainAddTitle); + #endif + _prevPercentValue = percentValue; + } + return true; +} + +bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case kCloseMessage: + { + if (_timer) + { + KillTimer(kTimerID); + _timer = 0; + } + if (_inCancelMessageBox) + { + _externalCloseMessageWasReceived = true; + break; + } + return OnExternalCloseMessage(); + } + /* + case WM_SETTEXT: + { + if (_timer == 0) + return true; + } + */ + } + return CModalDialog::OnMessage(message, wParam, lParam); +} + +bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDCANCEL: + { + bool paused = Sync.GetPaused(); + Sync.SetPaused(true); + _inCancelMessageBox = true; + int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNOCANCEL); + _inCancelMessageBox = false; + Sync.SetPaused(paused); + if (res == IDCANCEL || res == IDNO) + { + if (_externalCloseMessageWasReceived) + OnExternalCloseMessage(); + return true; + } + break; + } + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CProgressDialog::CheckNeedClose() +{ + if (_needClose) + { + PostMsg(kCloseMessage); + _needClose = false; + } +} + +bool CProgressDialog::OnExternalCloseMessage() +{ + End(0); + return true; +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.h b/CPP/7zip/UI/FileManager/ProgressDialog.h index 403c96c00..1fe9587a5 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog.h @@ -1,171 +1,171 @@ -// ProgressDialog.h - -#ifndef ZIP7_INC_PROGRESS_DIALOG_H -#define ZIP7_INC_PROGRESS_DIALOG_H - -#include "../../../Windows/Synchronization.h" -#include "../../../Windows/Thread.h" - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/ProgressBar.h" - -#include "ProgressDialogRes.h" - -class CProgressSync -{ - NWindows::NSynchronization::CCriticalSection _cs; - bool _stopped; - bool _paused; - UInt64 _total; - UInt64 _completed; -public: - CProgressSync(): _stopped(false), _paused(false), _total(1), _completed(0) {} - - HRESULT ProcessStopAndPause(); - bool GetStopped() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - return _stopped; - } - void SetStopped(bool value) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _stopped = value; - } - bool GetPaused() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - return _paused; - } - void SetPaused(bool value) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _paused = value; - } - void SetProgress(UInt64 total, UInt64 completed) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _total = total; - _completed = completed; - } - void SetPos(UInt64 completed) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _completed = completed; - } - void GetProgress(UInt64 &total, UInt64 &completed) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - total = _total; - completed = _completed; - } -}; - -class CU64ToI32Converter -{ - UInt64 _numShiftBits; -public: - void Init(UInt64 range) - { - // Windows CE doesn't like big number here. - for (_numShiftBits = 0; range > (1 << 15); _numShiftBits++) - range >>= 1; - } - int Count(UInt64 value) { return int(value >> _numShiftBits); } -}; - -class CProgressDialog: public NWindows::NControl::CModalDialog -{ -private: - UINT_PTR _timer; - - UString _title; - CU64ToI32Converter _converter; - UInt64 _peviousPos; - UInt64 _range; - NWindows::NControl::CProgressBar m_ProgressBar; - - UInt64 _prevPercentValue; - - bool _wasCreated; - bool _needClose; - bool _inCancelMessageBox; - bool _externalCloseMessageWasReceived; - - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override; - virtual bool OnInit() Z7_override; - virtual void OnCancel() Z7_override; - virtual void OnOK() Z7_override; - virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - - void SetRange(UInt64 range); - void SetPos(UInt64 pos); - - NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent; - #ifndef Z7_SFX - void AddToTitle(LPCWSTR string); - #endif - - void WaitCreating() { _dialogCreatedEvent.Lock(); } - void CheckNeedClose(); - bool OnExternalCloseMessage(); -public: - CProgressSync Sync; - int IconID; - - #ifndef Z7_SFX - HWND MainWindow; - UString MainTitle; - UString MainAddTitle; - ~CProgressDialog(); - #endif - - CProgressDialog(): _timer(0) - #ifndef Z7_SFX - ,MainWindow(NULL) - #endif - { - IconID = -1; - _wasCreated = false; - _needClose = false; - _inCancelMessageBox = false; - _externalCloseMessageWasReceived = false; - - if (_dialogCreatedEvent.Create() != S_OK) - throw 1334987; - } - - INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = NULL) - { - _title = title; - INT_PTR res = CModalDialog::Create(IDD_PROGRESS, wndParent); - thread.Wait_Close(); - return res; - } - - enum - { - kCloseMessage = WM_APP + 1 - }; - - void ProcessWasFinished() - { - WaitCreating(); - if (_wasCreated) - PostMsg(kCloseMessage); - else - _needClose = true; - } -}; - - -class CProgressCloser -{ - CProgressDialog *_p; -public: - CProgressCloser(CProgressDialog &p) : _p(&p) {} - ~CProgressCloser() { _p->ProcessWasFinished(); } -}; - -#endif +// ProgressDialog.h + +#ifndef ZIP7_INC_PROGRESS_DIALOG_H +#define ZIP7_INC_PROGRESS_DIALOG_H + +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/Thread.h" + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/ProgressBar.h" + +#include "ProgressDialogRes.h" + +class CProgressSync +{ + NWindows::NSynchronization::CCriticalSection _cs; + bool _stopped; + bool _paused; + UInt64 _total; + UInt64 _completed; +public: + CProgressSync(): _stopped(false), _paused(false), _total(1), _completed(0) {} + + HRESULT ProcessStopAndPause(); + bool GetStopped() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + return _stopped; + } + void SetStopped(bool value) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _stopped = value; + } + bool GetPaused() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + return _paused; + } + void SetPaused(bool value) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _paused = value; + } + void SetProgress(UInt64 total, UInt64 completed) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _total = total; + _completed = completed; + } + void SetPos(UInt64 completed) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _completed = completed; + } + void GetProgress(UInt64 &total, UInt64 &completed) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + total = _total; + completed = _completed; + } +}; + +class CU64ToI32Converter +{ + UInt64 _numShiftBits; +public: + void Init(UInt64 range) + { + // Windows CE doesn't like big number here. + for (_numShiftBits = 0; range > (1 << 15); _numShiftBits++) + range >>= 1; + } + int Count(UInt64 value) { return int(value >> _numShiftBits); } +}; + +class CProgressDialog: public NWindows::NControl::CModalDialog +{ +private: + UINT_PTR _timer; + + UString _title; + CU64ToI32Converter _converter; + UInt64 _peviousPos; + UInt64 _range; + NWindows::NControl::CProgressBar m_ProgressBar; + + UInt64 _prevPercentValue; + + bool _wasCreated; + bool _needClose; + bool _inCancelMessageBox; + bool _externalCloseMessageWasReceived; + + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override; + virtual bool OnInit() Z7_override; + virtual void OnCancel() Z7_override; + virtual void OnOK() Z7_override; + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + + void SetRange(UInt64 range); + void SetPos(UInt64 pos); + + NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent; + #ifndef Z7_SFX + void AddToTitle(LPCWSTR string); + #endif + + void WaitCreating() { _dialogCreatedEvent.Lock(); } + void CheckNeedClose(); + bool OnExternalCloseMessage(); +public: + CProgressSync Sync; + int IconID; + + #ifndef Z7_SFX + HWND MainWindow; + UString MainTitle; + UString MainAddTitle; + ~CProgressDialog(); + #endif + + CProgressDialog(): _timer(0) + #ifndef Z7_SFX + ,MainWindow(NULL) + #endif + { + IconID = -1; + _wasCreated = false; + _needClose = false; + _inCancelMessageBox = false; + _externalCloseMessageWasReceived = false; + + if (_dialogCreatedEvent.Create() != S_OK) + throw 1334987; + } + + INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = NULL) + { + _title = title; + INT_PTR res = CModalDialog::Create(IDD_PROGRESS, wndParent); + thread.Wait_Close(); + return res; + } + + enum + { + kCloseMessage = WM_APP + 1 + }; + + void ProcessWasFinished() + { + WaitCreating(); + if (_wasCreated) + PostMsg(kCloseMessage); + else + _needClose = true; + } +}; + + +class CProgressCloser +{ + CProgressDialog *_p; +public: + CProgressCloser(CProgressDialog &p) : _p(&p) {} + ~CProgressCloser() { _p->ProcessWasFinished(); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.rc b/CPP/7zip/UI/FileManager/ProgressDialog.rc index 5af370f74..55d99233b 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog.rc +++ b/CPP/7zip/UI/FileManager/ProgressDialog.rc @@ -1,12 +1,12 @@ -#include "ProgressDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 172 -#define yc 44 - -IDD_PROGRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Progress" -BEGIN - PUSHBUTTON "Cancel", IDCANCEL, bx, by, bxs, bys - CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, m, xc, 14 -END +#include "ProgressDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 172 +#define yc 44 + +IDD_PROGRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Progress" +BEGIN + PUSHBUTTON "Cancel", IDCANCEL, bx, by, bxs, bys + CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, m, xc, 14 +END diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp index 5e60df6a1..a070a0a37 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp @@ -1,1472 +1,1483 @@ -// ProgressDialog2.cpp - -#include "StdAfx.h" - -#ifdef Z7_OLD_WIN_SDK -#include -#endif - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/Clipboard.h" -#include "../../../Windows/ErrorMsg.h" - -#include "../GUI/ExtractRes.h" - -#include "LangUtils.h" - -#include "DialogSize.h" -#include "ProgressDialog2.h" -#include "ProgressDialog2Res.h" - -using namespace NWindows; - -extern HINSTANCE g_hInstance; -extern bool g_DisableUserQuestions; - -static const UINT_PTR kTimerID = 3; - -static const UINT kCloseMessage = WM_APP + 1; -// we can't use WM_USER, since WM_USER can be used by standard Windows procedure for Dialog - -static const UINT kTimerElapse = - #ifdef UNDER_CE - 500 - #else - 200 - #endif - ; - -static const UINT kCreateDelay = - #ifdef UNDER_CE - 2500 - #else - 500 - #endif - ; - -static const DWORD kPauseSleepTime = 100; - -#ifdef Z7_LANG - -static const UInt32 kLangIDs[] = -{ - IDT_PROGRESS_ELAPSED, - IDT_PROGRESS_REMAINING, - IDT_PROGRESS_TOTAL, - IDT_PROGRESS_SPEED, - IDT_PROGRESS_PROCESSED, - IDT_PROGRESS_RATIO, - IDT_PROGRESS_ERRORS, - IDB_PROGRESS_BACKGROUND, - IDB_PAUSE -}; - -static const UInt32 kLangIDs_Colon[] = -{ - IDT_PROGRESS_PACKED, - IDT_PROGRESS_FILES -}; - -#endif - - -#define UNDEFINED_VAL ((UInt64)(Int64)-1) -#define INIT_AS_UNDEFINED(v) v = UNDEFINED_VAL; -#define IS_UNDEFINED_VAL(v) ((v) == UNDEFINED_VAL) -#define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL) - -CProgressSync::CProgressSync(): - _stopped(false), _paused(false), - _bytesProgressMode(true), - _isDir(false), - _totalBytes(UNDEFINED_VAL), _completedBytes(0), - _totalFiles(UNDEFINED_VAL), _curFiles(0), - _inSize(UNDEFINED_VAL), - _outSize(UNDEFINED_VAL) - {} - -#define CHECK_STOP if (_stopped) return E_ABORT; if (!_paused) return S_OK; -#define CRITICAL_LOCK NSynchronization::CCriticalSectionLock lock(_cs); - -bool CProgressSync::Get_Paused() -{ - CRITICAL_LOCK - return _paused; -} - -HRESULT CProgressSync::CheckStop() -{ - for (;;) - { - { - CRITICAL_LOCK - CHECK_STOP - } - ::Sleep(kPauseSleepTime); - } -} - -HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir) -{ - { - CRITICAL_LOCK - _totalFiles = numFiles; - _totalBytes = totalSize; - _filePath = fs2us(fileName); - _isDir = isDir; - // _completedBytes = 0; - CHECK_STOP - } - return CheckStop(); -} - -HRESULT CProgressSync::Set_NumFilesTotal(UInt64 val) -{ - { - CRITICAL_LOCK - _totalFiles = val; - CHECK_STOP - } - return CheckStop(); -} - -void CProgressSync::Set_NumBytesTotal(UInt64 val) -{ - CRITICAL_LOCK - _totalBytes = val; -} - -void CProgressSync::Set_NumFilesCur(UInt64 val) -{ - CRITICAL_LOCK - _curFiles = val; -} - -HRESULT CProgressSync::Set_NumBytesCur(const UInt64 *val) -{ - { - CRITICAL_LOCK - if (val) - _completedBytes = *val; - CHECK_STOP - } - return CheckStop(); -} - -HRESULT CProgressSync::Set_NumBytesCur(UInt64 val) -{ - { - CRITICAL_LOCK - _completedBytes = val; - CHECK_STOP - } - return CheckStop(); -} - -void CProgressSync::Set_Ratio(const UInt64 *inSize, const UInt64 *outSize) -{ - CRITICAL_LOCK - if (inSize) - _inSize = *inSize; - if (outSize) - _outSize = *outSize; -} - -void CProgressSync::Set_TitleFileName(const UString &fileName) -{ - CRITICAL_LOCK - _titleFileName = fileName; -} - -void CProgressSync::Set_Status(const UString &s) -{ - CRITICAL_LOCK - _status = s; -} - -HRESULT CProgressSync::Set_Status2(const UString &s, const wchar_t *path, bool isDir) -{ - { - CRITICAL_LOCK - _status = s; - if (path) - _filePath = path; - else - _filePath.Empty(); - _isDir = isDir; - } - return CheckStop(); -} - -void CProgressSync::Set_FilePath(const wchar_t *path, bool isDir) -{ - CRITICAL_LOCK - if (path) - _filePath = path; - else - _filePath.Empty(); - _isDir = isDir; -} - - -void CProgressSync::AddError_Message(const wchar_t *message) -{ - CRITICAL_LOCK - Messages.Add(message); -} - -void CProgressSync::AddError_Message_Name(const wchar_t *message, const wchar_t *name) -{ - UString s; - if (name && *name != 0) - s += name; - if (message && *message != 0) - { - if (!s.IsEmpty()) - s.Add_LF(); - s += message; - if (!s.IsEmpty() && s.Back() == L'\n') - s.DeleteBack(); - } - AddError_Message(s); -} - -void CProgressSync::AddError_Code_Name(HRESULT systemError, const wchar_t *name) -{ - UString s = NError::MyFormatMessage(systemError); - if (systemError == 0) - s = "Error"; - AddError_Message_Name(s, name); -} - -CProgressDialog::CProgressDialog(): - _timer(0), - CompressingMode(true), - MainWindow(NULL) -{ - _isDir = false; - - _numMessages = 0; - IconID = -1; - MessagesDisplayed = false; - _wasCreated = false; - _needClose = false; - _inCancelMessageBox = false; - _externalCloseMessageWasReceived = false; - - _numPostedMessages = 0; - _numAutoSizeMessages = 0; - _errorsWereDisplayed = false; - _waitCloseByCancelButton = false; - _cancelWasPressed = false; - ShowCompressionInfo = true; - WaitMode = false; - if (_dialogCreatedEvent.Create() != S_OK) - throw 1334987; - if (_createDialogEvent.Create() != S_OK) - throw 1334987; - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&_taskbarList); - if (_taskbarList) - _taskbarList->HrInit(); - // #endif -} - -#ifndef Z7_SFX - -CProgressDialog::~CProgressDialog() -{ - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - SetTaskbarProgressState(TBPF_NOPROGRESS); - // #endif - AddToTitle(L""); -} -void CProgressDialog::AddToTitle(LPCWSTR s) -{ - if (MainWindow) - { - CWindow window(MainWindow); - window.SetText((UString)s + MainTitle); - } -} - -#endif - - -void CProgressDialog::SetTaskbarProgressState() -{ - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - if (_taskbarList && _hwndForTaskbar) - { - TBPFLAG tbpFlags; - if (Sync.Get_Paused()) - tbpFlags = TBPF_PAUSED; - else - tbpFlags = _errorsWereDisplayed ? TBPF_ERROR: TBPF_NORMAL; - SetTaskbarProgressState(tbpFlags); - } - // #endif -} - -static const unsigned kTitleFileNameSizeLimit = 36; -static const unsigned kCurrentFileNameSizeLimit = 82; - -static void ReduceString(UString &s, unsigned size) -{ - if (s.Len() <= size) - return; - s.Delete(size / 2, s.Len() - size); - s.Insert(size / 2, L" ... "); -} - -void CProgressDialog::EnableErrorsControls(bool enable) -{ - ShowItem_Bool(IDT_PROGRESS_ERRORS, enable); - ShowItem_Bool(IDT_PROGRESS_ERRORS_VAL, enable); - ShowItem_Bool(IDL_PROGRESS_MESSAGES, enable); -} - -bool CProgressDialog::OnInit() -{ - _hwndForTaskbar = MainWindow; - if (!_hwndForTaskbar) - _hwndForTaskbar = GetParent(); - if (!_hwndForTaskbar) - _hwndForTaskbar = *this; - - INIT_AS_UNDEFINED(_progressBar_Range) - INIT_AS_UNDEFINED(_progressBar_Pos) - - INIT_AS_UNDEFINED(_prevPercentValue) - INIT_AS_UNDEFINED(_prevElapsedSec) - INIT_AS_UNDEFINED(_prevRemainingSec) - - INIT_AS_UNDEFINED(_prevSpeed) - _prevSpeed_MoveBits = 0; - - _prevTime = ::GetTickCount(); - _elapsedTime = 0; - - INIT_AS_UNDEFINED(_totalBytes_Prev) - INIT_AS_UNDEFINED(_processed_Prev) - INIT_AS_UNDEFINED(_packed_Prev) - INIT_AS_UNDEFINED(_ratio_Prev) - - _filesStr_Prev.Empty(); - _filesTotStr_Prev.Empty(); - - _foreground = true; - - m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); - _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES)); - _messageList.SetUnicodeFormat(); - _messageList.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT); - - _wasCreated = true; - _dialogCreatedEvent.Set(); - - #ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon)); - #endif - - CWindow window(GetItem(IDB_PROGRESS_BACKGROUND)); - window.GetText(_background_String); - _backgrounded_String = _background_String; - _backgrounded_String.RemoveChar(L'&'); - - window = GetItem(IDB_PAUSE); - window.GetText(_pause_String); - - LangString(IDS_PROGRESS_FOREGROUND, _foreground_String); - LangString(IDS_CONTINUE, _continue_String); - LangString(IDS_PROGRESS_PAUSED, _paused_String); - - SetText(_title); - SetPauseText(); - SetPriorityText(); - - _messageList.InsertColumn(0, L"", 30); - _messageList.InsertColumn(1, L"", 600); - - _messageList.SetColumnWidthAuto(0); - _messageList.SetColumnWidthAuto(1); - - EnableErrorsControls(false); - - GetItemSizes(IDCANCEL, _buttonSizeX, _buttonSizeY); - _numReduceSymbols = kCurrentFileNameSizeLimit; - NormalizeSize(true); - - if (!ShowCompressionInfo) - { - HideItem(IDT_PROGRESS_PACKED); - HideItem(IDT_PROGRESS_PACKED_VAL); - HideItem(IDT_PROGRESS_RATIO); - HideItem(IDT_PROGRESS_RATIO_VAL); - } - - if (IconID >= 0) - { - HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID)); - // SetIcon(ICON_SMALL, icon); - SetIcon(ICON_BIG, icon); - } - _timer = SetTimer(kTimerID, kTimerElapse); - #ifdef UNDER_CE - Foreground(); - #endif - - CheckNeedClose(); - - SetTaskbarProgressState(); - - return CModalDialog::OnInit(); -} - -static const UINT kIDs[] = -{ - IDT_PROGRESS_ELAPSED, IDT_PROGRESS_ELAPSED_VAL, - IDT_PROGRESS_REMAINING, IDT_PROGRESS_REMAINING_VAL, - IDT_PROGRESS_FILES, IDT_PROGRESS_FILES_VAL, - 0, IDT_PROGRESS_FILES_TOTAL, - IDT_PROGRESS_ERRORS, IDT_PROGRESS_ERRORS_VAL, - - IDT_PROGRESS_TOTAL, IDT_PROGRESS_TOTAL_VAL, - IDT_PROGRESS_SPEED, IDT_PROGRESS_SPEED_VAL, - IDT_PROGRESS_PROCESSED, IDT_PROGRESS_PROCESSED_VAL, - IDT_PROGRESS_PACKED, IDT_PROGRESS_PACKED_VAL, - IDT_PROGRESS_RATIO, IDT_PROGRESS_RATIO_VAL -}; - -bool CProgressDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int sY; - int sStep; - int mx, my; - { - RECT r; - GetClientRectOfItem(IDT_PROGRESS_ELAPSED, r); - mx = r.left; - my = r.top; - sY = RECT_SIZE_Y(r); - GetClientRectOfItem(IDT_PROGRESS_REMAINING, r); - sStep = r.top - my; - } - - InvalidateRect(NULL); - - const int xSizeClient = xSize - mx * 2; - - { - unsigned i; - for (i = 800; i > 40; i = i * 9 / 10) - if (Units_To_Pixels_X((int)i) <= xSizeClient) - break; - _numReduceSymbols = i / 4; - } - - int yPos = ySize - my - _buttonSizeY; - - ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_STATUS), xSize - mx * 2); - ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_FILE_NAME), xSize - mx * 2); - ChangeSubWindowSizeX(GetItem(IDC_PROGRESS1), xSize - mx * 2); - - int bSizeX = _buttonSizeX; - int mx2 = mx; - for (;; mx2--) - { - const int bSize2 = bSizeX * 3 + mx2 * 2; - if (bSize2 <= xSizeClient) - break; - if (mx2 < 5) - { - bSizeX = (xSizeClient - mx2 * 2) / 3; - break; - } - } - if (bSizeX < 2) - bSizeX = 2; - - { - RECT r; - GetClientRectOfItem(IDL_PROGRESS_MESSAGES, r); - const int y = r.top; - int ySize2 = yPos - my - y; - const int kMinYSize = _buttonSizeY + _buttonSizeY * 3 / 4; - int xx = xSize - mx * 2; - if (ySize2 < kMinYSize) - { - ySize2 = kMinYSize; - if (xx > bSizeX * 2) - xx -= bSizeX; - } - - _messageList.Move(mx, y, xx, ySize2); - } - - { - int xPos = xSize - mx; - xPos -= bSizeX; - MoveItem(IDCANCEL, xPos, yPos, bSizeX, _buttonSizeY); - xPos -= (mx2 + bSizeX); - MoveItem(IDB_PAUSE, xPos, yPos, bSizeX, _buttonSizeY); - xPos -= (mx2 + bSizeX); - MoveItem(IDB_PROGRESS_BACKGROUND, xPos, yPos, bSizeX, _buttonSizeY); - } - - int valueSize; - int labelSize; - int padSize; - - labelSize = Units_To_Pixels_X(MY_PROGRESS_LABEL_UNITS_MIN); - valueSize = Units_To_Pixels_X(MY_PROGRESS_VAL_UNITS); - padSize = Units_To_Pixels_X(MY_PROGRESS_PAD_UNITS); - const int requiredSize = (labelSize + valueSize) * 2 + padSize; - - int gSize; - { - if (requiredSize < xSizeClient) - { - const int incr = (xSizeClient - requiredSize) / 3; - labelSize += incr; - } - else - labelSize = (xSizeClient - valueSize * 2 - padSize) / 2; - if (labelSize < 0) - labelSize = 0; - - gSize = labelSize + valueSize; - padSize = xSizeClient - gSize * 2; - } - - labelSize = gSize - valueSize; - - yPos = my; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDs); i += 2) - { - int x = mx; - const unsigned kNumColumn1Items = 5 * 2; - if (i >= kNumColumn1Items) - { - if (i == kNumColumn1Items) - yPos = my; - x = mx + gSize + padSize; - } - if (kIDs[i] != 0) - MoveItem(kIDs[i], x, yPos, labelSize, sY); - MoveItem(kIDs[i + 1], x + labelSize, yPos, valueSize, sY); - yPos += sStep; - } - return false; -} - -void CProgressDialog::OnCancel() { Sync.Set_Stopped(true); } -void CProgressDialog::OnOK() { } - -void CProgressDialog::SetProgressRange(UInt64 range) -{ - if (range == _progressBar_Range) - return; - _progressBar_Range = range; - INIT_AS_UNDEFINED(_progressBar_Pos) - _progressConv.Init(range); - m_ProgressBar.SetRange32(0, _progressConv.Count(range)); -} - -void CProgressDialog::SetProgressPos(UInt64 pos) -{ - if (pos >= _progressBar_Range || - pos <= _progressBar_Pos || - pos - _progressBar_Pos >= (_progressBar_Range >> 10)) - { - m_ProgressBar.SetPos(_progressConv.Count(pos)); - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - if (_taskbarList && _hwndForTaskbar) - _taskbarList->SetProgressValue(_hwndForTaskbar, pos, _progressBar_Range); - // #endif - _progressBar_Pos = pos; - } -} - -#define UINT_TO_STR_2(val) { s[0] = (wchar_t)('0' + (val) / 10); s[1] = (wchar_t)('0' + (val) % 10); s += 2; } - -void GetTimeString(UInt64 timeValue, wchar_t *s); -void GetTimeString(UInt64 timeValue, wchar_t *s) -{ - UInt64 hours = timeValue / 3600; - UInt32 seconds = (UInt32)(timeValue - hours * 3600); - UInt32 minutes = seconds / 60; - seconds %= 60; - if (hours > 99) - { - ConvertUInt64ToString(hours, s); - for (; *s != 0; s++); - } - else - { - UInt32 hours32 = (UInt32)hours; - UINT_TO_STR_2(hours32) - } - *s++ = ':'; UINT_TO_STR_2(minutes) - *s++ = ':'; UINT_TO_STR_2(seconds) - *s = 0; -} - -static void ConvertSizeToString(UInt64 v, wchar_t *s) -{ - Byte c = 0; - if (v >= ((UInt64)100000 << 20)) { v >>= 30; c = 'G'; } - else if (v >= ((UInt64)100000 << 10)) { v >>= 20; c = 'M'; } - else if (v >= ((UInt64)100000 << 0)) { v >>= 10; c = 'K'; } - ConvertUInt64ToString(v, s); - if (c != 0) - { - s += MyStringLen(s); - *s++ = ' '; - *s++ = c; - *s++ = 'B'; - *s++ = 0; - } -} - -void CProgressDialog::ShowSize(unsigned id, UInt64 val, UInt64 &prev) -{ - if (val == prev) - return; - prev = val; - wchar_t s[40]; - s[0] = 0; - if (IS_DEFINED_VAL(val)) - ConvertSizeToString(val, s); - SetItemText(id, s); -} - -static void GetChangedString(const UString &newStr, UString &prevStr, bool &hasChanged) -{ - hasChanged = !(prevStr == newStr); - if (hasChanged) - prevStr = newStr; -} - -static unsigned GetPower32(UInt32 val) -{ - const unsigned kStart = 32; - UInt32 mask = ((UInt32)1 << (kStart - 1)); - for (unsigned i = kStart;; i--) - { - if (i == 0 || (val & mask) != 0) - return i; - mask >>= 1; - } -} - -static unsigned GetPower64(UInt64 val) -{ - UInt32 high = (UInt32)(val >> 32); - if (high == 0) - return GetPower32((UInt32)val); - return GetPower32(high) + 32; -} - -static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider) -{ - unsigned pow1 = GetPower64(mult1); - unsigned pow2 = GetPower64(mult2); - while (pow1 + pow2 > 64) - { - if (pow1 > pow2) { pow1--; mult1 >>= 1; } - else { pow2--; mult2 >>= 1; } - divider >>= 1; - } - UInt64 res = mult1 * mult2; - if (divider != 0) - res /= divider; - return res; -} - -void CProgressDialog::UpdateStatInfo(bool showAll) -{ - UInt64 total, completed, totalFiles, completedFiles, inSize, outSize; - bool bytesProgressMode; - - bool titleFileName_Changed; - bool curFilePath_Changed; - bool status_Changed; - unsigned numErrors; - { - NSynchronization::CCriticalSectionLock lock(Sync._cs); - total = Sync._totalBytes; - completed = Sync._completedBytes; - totalFiles = Sync._totalFiles; - completedFiles = Sync._curFiles; - inSize = Sync._inSize; - outSize = Sync._outSize; - bytesProgressMode = Sync._bytesProgressMode; - - GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed); - GetChangedString(Sync._filePath, _filePath, curFilePath_Changed); - GetChangedString(Sync._status, _status, status_Changed); - if (_isDir != Sync._isDir) - { - curFilePath_Changed = true; - _isDir = Sync._isDir; - } - numErrors = Sync.Messages.Size(); - } - - UInt32 curTime = ::GetTickCount(); - - const UInt64 progressTotal = bytesProgressMode ? total : totalFiles; - const UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles; - { - if (IS_UNDEFINED_VAL(progressTotal)) - { - // SetPos(0); - // SetRange(progressCompleted); - } - else - { - if (_progressBar_Pos != 0 || progressCompleted != 0 || - (_progressBar_Range == 0 && progressTotal != 0)) - { - SetProgressRange(progressTotal); - SetProgressPos(progressCompleted); - } - } - } - - ShowSize(IDT_PROGRESS_TOTAL_VAL, total, _totalBytes_Prev); - - _elapsedTime += (curTime - _prevTime); - _prevTime = curTime; - UInt64 elapsedSec = _elapsedTime / 1000; - bool elapsedChanged = false; - if (elapsedSec != _prevElapsedSec) - { - _prevElapsedSec = elapsedSec; - elapsedChanged = true; - wchar_t s[40]; - GetTimeString(elapsedSec, s); - SetItemText(IDT_PROGRESS_ELAPSED_VAL, s); - } - - bool needSetTitle = false; - if (elapsedChanged || showAll) - { - if (numErrors > _numPostedMessages) - { - UpdateMessagesDialog(); - wchar_t s[32]; - ConvertUInt64ToString(numErrors, s); - SetItemText(IDT_PROGRESS_ERRORS_VAL, s); - if (!_errorsWereDisplayed) - { - _errorsWereDisplayed = true; - EnableErrorsControls(true); - SetTaskbarProgressState(); - } - } - - if (progressCompleted != 0) - { - if (IS_UNDEFINED_VAL(progressTotal)) - { - if (IS_DEFINED_VAL(_prevRemainingSec)) - { - INIT_AS_UNDEFINED(_prevRemainingSec) - SetItemText(IDT_PROGRESS_REMAINING_VAL, L""); - } - } - else - { - UInt64 remainingTime = 0; - if (progressCompleted < progressTotal) - remainingTime = MyMultAndDiv(_elapsedTime, progressTotal - progressCompleted, progressCompleted); - UInt64 remainingSec = remainingTime / 1000; - if (remainingSec != _prevRemainingSec) - { - _prevRemainingSec = remainingSec; - wchar_t s[40]; - GetTimeString(remainingSec, s); - SetItemText(IDT_PROGRESS_REMAINING_VAL, s); - } - } - { - const UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime; - // 22.02: progressCompleted can be for number of files - UInt64 v = (completed * 1000) / elapsedTime; - Byte c = 0; - unsigned moveBits = 0; - if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; } - else if (v >= ((UInt64)10000 << 0)) { moveBits = 10; c = 'K'; } - v >>= moveBits; - if (moveBits != _prevSpeed_MoveBits || v != _prevSpeed) - { - _prevSpeed_MoveBits = moveBits; - _prevSpeed = v; - wchar_t s[40]; - ConvertUInt64ToString(v, s); - unsigned pos = MyStringLen(s); - s[pos++] = ' '; - if (moveBits != 0) - s[pos++] = c; - s[pos++] = 'B'; - s[pos++] = '/'; - s[pos++] = 's'; - s[pos++] = 0; - SetItemText(IDT_PROGRESS_SPEED_VAL, s); - } - } - } - - { - UInt64 percent = 0; - { - if (IS_DEFINED_VAL(progressTotal)) - { - percent = progressCompleted * 100; - if (progressTotal != 0) - percent /= progressTotal; - } - } - if (percent != _prevPercentValue) - { - _prevPercentValue = percent; - needSetTitle = true; - } - } - - { - wchar_t s[64]; - - ConvertUInt64ToString(completedFiles, s); - if (_filesStr_Prev != s) - { - _filesStr_Prev = s; - SetItemText(IDT_PROGRESS_FILES_VAL, s); - } - - s[0] = 0; - if (IS_DEFINED_VAL(totalFiles)) - { - MyStringCopy(s, L" / "); - ConvertUInt64ToString(totalFiles, s + MyStringLen(s)); - } - if (_filesTotStr_Prev != s) - { - _filesTotStr_Prev = s; - SetItemText(IDT_PROGRESS_FILES_TOTAL, s); - } - } - - const UInt64 packSize = CompressingMode ? outSize : inSize; - const UInt64 unpackSize = CompressingMode ? inSize : outSize; - - if (IS_UNDEFINED_VAL(unpackSize) && - IS_UNDEFINED_VAL(packSize)) - { - ShowSize(IDT_PROGRESS_PROCESSED_VAL, completed, _processed_Prev); - ShowSize(IDT_PROGRESS_PACKED_VAL, UNDEFINED_VAL, _packed_Prev); - } - else - { - ShowSize(IDT_PROGRESS_PROCESSED_VAL, unpackSize, _processed_Prev); - ShowSize(IDT_PROGRESS_PACKED_VAL, packSize, _packed_Prev); - - if (IS_DEFINED_VAL(packSize) && - IS_DEFINED_VAL(unpackSize) && - unpackSize != 0) - { - wchar_t s[32]; - UInt64 ratio = packSize * 100 / unpackSize; - if (_ratio_Prev != ratio) - { - _ratio_Prev = ratio; - ConvertUInt64ToString(ratio, s); - MyStringCat(s, L"%"); - SetItemText(IDT_PROGRESS_RATIO_VAL, s); - } - } - } - } - - if (needSetTitle || titleFileName_Changed) - SetTitleText(); - - if (status_Changed) - { - UString s = _status; - ReduceString(s, _numReduceSymbols); - SetItemText(IDT_PROGRESS_STATUS, _status); - } - - if (curFilePath_Changed) - { - UString s1, s2; - if (_isDir) - s1 = _filePath; - else - { - int slashPos = _filePath.ReverseFind_PathSepar(); - if (slashPos >= 0) - { - s1.SetFrom(_filePath, (unsigned)(slashPos + 1)); - s2 = _filePath.Ptr((unsigned)(slashPos + 1)); - } - else - s2 = _filePath; - } - ReduceString(s1, _numReduceSymbols); - ReduceString(s2, _numReduceSymbols); - s1.Add_LF(); - s1 += s2; - SetItemText(IDT_PROGRESS_FILE_NAME, s1); - } -} - -bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) -{ - if (Sync.Get_Paused()) - return true; - CheckNeedClose(); - UpdateStatInfo(false); - return true; -} - -struct CWaitCursor -{ - HCURSOR _waitCursor; - HCURSOR _oldCursor; - CWaitCursor() - { - _waitCursor = LoadCursor(NULL, IDC_WAIT); - if (_waitCursor != NULL) - _oldCursor = SetCursor(_waitCursor); - } - ~CWaitCursor() - { - if (_waitCursor != NULL) - SetCursor(_oldCursor); - } -}; - -INT_PTR CProgressDialog::Create(const UString &title, NWindows::CThread &thread, HWND wndParent) -{ - INT_PTR res = 0; - try - { - if (WaitMode) - { - CWaitCursor waitCursor; - HANDLE h[] = { thread, _createDialogEvent }; - - const DWORD res2 = WaitForMultipleObjects(Z7_ARRAY_SIZE(h), h, FALSE, kCreateDelay); - if (res2 == WAIT_OBJECT_0 && !Sync.ThereIsMessage()) - return 0; - } - _title = title; - BIG_DIALOG_SIZE(360, 192); - res = CModalDialog::Create(SIZED_DIALOG(IDD_PROGRESS), wndParent); - } - catch(...) - { - _wasCreated = true; - _dialogCreatedEvent.Set(); - } - thread.Wait_Close(); - if (!MessagesDisplayed) - if (!g_DisableUserQuestions) - MessageBoxW(wndParent, L"Progress Error", L"7-Zip", MB_ICONERROR); - return res; -} - -bool CProgressDialog::OnExternalCloseMessage() -{ - // it doesn't work if there is MessageBox. - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - SetTaskbarProgressState(TBPF_NOPROGRESS); - // #endif - // AddToTitle(L"Finished "); - // SetText(L"Finished2 "); - - UpdateStatInfo(true); - - SetItemText(IDCANCEL, LangString(IDS_CLOSE)); - ::SendMessage(GetItem(IDCANCEL), BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0)); - HideItem(IDB_PROGRESS_BACKGROUND); - HideItem(IDB_PAUSE); - - ProcessWasFinished_GuiVirt(); - - bool thereAreMessages; - CProgressFinalMessage fm; - { - NSynchronization::CCriticalSectionLock lock(Sync._cs); - thereAreMessages = !Sync.Messages.IsEmpty(); - fm = Sync.FinalMessage; - } - - if (!fm.ErrorMessage.Message.IsEmpty()) - { - MessagesDisplayed = true; - if (fm.ErrorMessage.Title.IsEmpty()) - fm.ErrorMessage.Title = "7-Zip"; - if (!g_DisableUserQuestions) - MessageBoxW(*this, fm.ErrorMessage.Message, fm.ErrorMessage.Title, MB_ICONERROR); - } - else if (!thereAreMessages) - { - MessagesDisplayed = true; - - if (!fm.OkMessage.Message.IsEmpty()) - { - if (fm.OkMessage.Title.IsEmpty()) - fm.OkMessage.Title = "7-Zip"; - if (!g_DisableUserQuestions) - MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK); - } - } - - if (!g_DisableUserQuestions) - if (thereAreMessages && !_cancelWasPressed) - { - _waitCloseByCancelButton = true; - UpdateMessagesDialog(); - return true; - } - - End(0); - return true; -} - -bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case kCloseMessage: - { - if (_timer) - { - /* 21.03 : KillTimer(kTimerID) instead of KillTimer(_timer). - But (_timer == kTimerID) in Win10. So it worked too */ - KillTimer(kTimerID); - _timer = 0; - } - if (_inCancelMessageBox) - { - /* if user is in MessageBox(), we will call OnExternalCloseMessage() - later, when MessageBox() will be closed */ - _externalCloseMessageWasReceived = true; - break; - } - return OnExternalCloseMessage(); - } - /* - case WM_SETTEXT: - { - if (_timer == 0) - return true; - break; - } - */ - } - return CModalDialog::OnMessage(message, wParam, lParam); -} - -void CProgressDialog::SetTitleText() -{ - UString s; - if (Sync.Get_Paused()) - { - s += _paused_String; - s.Add_Space(); - } - if (IS_DEFINED_VAL(_prevPercentValue)) - { - char temp[32]; - ConvertUInt64ToString(_prevPercentValue, temp); - s += temp; - s.Add_Char('%'); - } - if (!_foreground) - { - s.Add_Space(); - s += _backgrounded_String; - } - - s.Add_Space(); - #ifndef Z7_SFX - { - unsigned len = s.Len(); - s += MainAddTitle; - AddToTitle(s); - s.DeleteFrom(len); - } - #endif - - s += _title; - if (!_titleFileName.IsEmpty()) - { - UString fileName = _titleFileName; - ReduceString(fileName, kTitleFileNameSizeLimit); - s.Add_Space(); - s += fileName; - } - SetText(s); -} - -void CProgressDialog::SetPauseText() -{ - SetItemText(IDB_PAUSE, Sync.Get_Paused() ? _continue_String : _pause_String); - SetTitleText(); -} - -void CProgressDialog::OnPauseButton() -{ - bool paused = !Sync.Get_Paused(); - Sync.Set_Paused(paused); - UInt32 curTime = ::GetTickCount(); - if (paused) - _elapsedTime += (curTime - _prevTime); - SetTaskbarProgressState(); - _prevTime = curTime; - SetPauseText(); -} - -void CProgressDialog::SetPriorityText() -{ - SetItemText(IDB_PROGRESS_BACKGROUND, _foreground ? - _background_String : - _foreground_String); - SetTitleText(); -} - -void CProgressDialog::OnPriorityButton() -{ - _foreground = !_foreground; - #ifndef UNDER_CE - SetPriorityClass(GetCurrentProcess(), _foreground ? NORMAL_PRIORITY_CLASS: IDLE_PRIORITY_CLASS); - #endif - SetPriorityText(); -} - -void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber) -{ - wchar_t sz[16]; - sz[0] = 0; - if (needNumber) - ConvertUInt32ToString(_numMessages + 1, sz); - const unsigned itemIndex = _messageStrings.Size(); // _messageList.GetItemCount(); - if (_messageList.InsertItem(itemIndex, sz) == (int)itemIndex) - { - _messageList.SetSubItem(itemIndex, 1, message); - _messageStrings.Add(message); - } -} - -void CProgressDialog::AddMessage(LPCWSTR message) -{ - UString s = message; - bool needNumber = true; - while (!s.IsEmpty()) - { - const int pos = s.Find(L'\n'); - if (pos < 0) - break; - AddMessageDirect(s.Left((unsigned)pos), needNumber); - needNumber = false; - s.DeleteFrontal((unsigned)pos + 1); - } - AddMessageDirect(s, needNumber); - _numMessages++; -} - -static unsigned GetNumDigits(UInt32 val) -{ - unsigned i; - for (i = 0; val >= 10; i++) - val /= 10; - return i; -} - -void CProgressDialog::UpdateMessagesDialog() -{ - UStringVector messages; - { - NSynchronization::CCriticalSectionLock lock(Sync._cs); - unsigned num = Sync.Messages.Size(); - if (num > _numPostedMessages) - { - messages.ClearAndReserve(num - _numPostedMessages); - for (unsigned i = _numPostedMessages; i < num; i++) - messages.AddInReserved(Sync.Messages[i]); - _numPostedMessages = num; - } - } - if (!messages.IsEmpty()) - { - FOR_VECTOR (i, messages) - AddMessage(messages[i]); - if (_numAutoSizeMessages < 256 || GetNumDigits(_numPostedMessages) > GetNumDigits(_numAutoSizeMessages)) - { - _messageList.SetColumnWidthAuto(0); - _messageList.SetColumnWidthAuto(1); - _numAutoSizeMessages = _numPostedMessages; - } - } -} - - -bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON - case IDCANCEL: - { - if (_waitCloseByCancelButton) - { - MessagesDisplayed = true; - End(IDCLOSE); - break; - } - - if (_cancelWasPressed) - return true; - - const bool paused = Sync.Get_Paused(); - - if (!paused) - { - OnPauseButton(); - } - - _inCancelMessageBox = true; - const int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL); - _inCancelMessageBox = false; - if (res == IDYES) - _cancelWasPressed = true; - - if (!paused) - { - OnPauseButton(); - } - - if (_externalCloseMessageWasReceived) - { - /* we have received kCloseMessage while we were in MessageBoxW(). - so we call OnExternalCloseMessage() here. - it can show MessageBox and it can close dialog */ - OnExternalCloseMessage(); - return true; - } - - if (!_cancelWasPressed) - return true; - - MessagesDisplayed = true; - // we will call Sync.Set_Stopped(true) in OnButtonClicked() : OnCancel() - break; - } - - case IDB_PAUSE: - OnPauseButton(); - return true; - case IDB_PROGRESS_BACKGROUND: - OnPriorityButton(); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CProgressDialog::CheckNeedClose() -{ - if (_needClose) - { - PostMsg(kCloseMessage); - _needClose = false; - } -} - -void CProgressDialog::ProcessWasFinished() -{ - // Set Window title here. - if (!WaitMode) - WaitCreating(); - - if (_wasCreated) - PostMsg(kCloseMessage); - else - _needClose = true; -} - - -bool CProgressDialog::OnNotify(UINT /* controlID */, LPNMHDR header) -{ - if (header->hwndFrom != _messageList) - return false; - switch (header->code) - { - case LVN_KEYDOWN: - { - LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); - switch (keyDownInfo->wVKey) - { - case 'A': - { - if (IsKeyDown(VK_CONTROL)) - { - _messageList.SelectAll(); - return true; - } - break; - } - case VK_INSERT: - case 'C': - { - if (IsKeyDown(VK_CONTROL)) - { - CopyToClipboard(); - return true; - } - break; - } - } - } - } - return false; -} - - -static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector) -{ - vector.Clear(); - int index = -1; - for (;;) - { - index = listView.GetNextSelectedItem(index); - if (index < 0) - break; - vector.Add((unsigned)index); - } -} - - -void CProgressDialog::CopyToClipboard() -{ - CUIntVector indexes; - ListView_GetSelected(_messageList, indexes); - UString s; - unsigned numIndexes = indexes.Size(); - if (numIndexes == 0) - numIndexes = (unsigned)_messageList.GetItemCount(); - - for (unsigned i = 0; i < numIndexes; i++) - { - const unsigned index = (i < indexes.Size() ? indexes[i] : i); - // s.Add_UInt32(index); - // s += ": "; - s += _messageStrings[index]; - { - s += - #ifdef _WIN32 - "\r\n" - #else - "\n" - #endif - ; - } - } - - ClipboardSetText(*this, s); -} - - -static THREAD_FUNC_DECL MyThreadFunction(void *param) -{ - CProgressThreadVirt *p = (CProgressThreadVirt *)param; - try - { - p->Process(); - p->ThreadFinishedOK = true; - } - catch (...) { p->Result = E_FAIL; } - return 0; -} - - -HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow) -{ - NWindows::CThread thread; - const WRes wres = thread.Create(MyThreadFunction, this); - if (wres != 0) - return HRESULT_FROM_WIN32(wres); - CProgressDialog::Create(title, thread, parentWindow); - return S_OK; -} - -static void AddMessageToString(UString &dest, const UString &src) -{ - if (!src.IsEmpty()) - { - if (!dest.IsEmpty()) - dest.Add_LF(); - dest += src; - } -} - -void CProgressThreadVirt::Process() -{ - CProgressCloser closer(*this); - UString m; - try { Result = ProcessVirt(); } - catch(const wchar_t *s) { m = s; } - catch(const UString &s) { m = s; } - catch(const char *s) { m = GetUnicodeString(s); } - catch(int v) - { - m = "Error #"; - m.Add_UInt32((unsigned)v); - } - catch(...) { m = "Error"; } - if (Result != E_ABORT) - { - if (m.IsEmpty() && Result != S_OK) - m = HResultToMessage(Result); - } - AddMessageToString(m, FinalMessage.ErrorMessage.Message); - - { - FOR_VECTOR(i, ErrorPaths) - { - if (i >= 32) - break; - AddMessageToString(m, fs2us(ErrorPaths[i])); - } - } - - CProgressSync &sync = Sync; - NSynchronization::CCriticalSectionLock lock(sync._cs); - if (m.IsEmpty()) - { - if (!FinalMessage.OkMessage.Message.IsEmpty()) - sync.FinalMessage.OkMessage = FinalMessage.OkMessage; - } - else - { - sync.FinalMessage.ErrorMessage.Message = m; - if (Result == S_OK) - Result = E_FAIL; - } -} - -UString HResultToMessage(HRESULT errorCode) -{ - if (errorCode == E_OUTOFMEMORY) - return LangString(IDS_MEM_ERROR); - else - return NError::MyFormatMessage(errorCode); -} +// ProgressDialog2.cpp + +#include "StdAfx.h" + +#ifdef Z7_OLD_WIN_SDK +#include +#endif + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/Clipboard.h" +#include "../../../Windows/ErrorMsg.h" + +#include "../GUI/ExtractRes.h" + +#include "LangUtils.h" + +#include "DialogSize.h" +#include "ProgressDialog2.h" +#include "ProgressDialog2Res.h" + +using namespace NWindows; + +extern HINSTANCE g_hInstance; +extern bool g_DisableUserQuestions; + +static const UINT_PTR kTimerID = 3; + +static const UINT kCloseMessage = WM_APP + 1; +// we can't use WM_USER, since WM_USER can be used by standard Windows procedure for Dialog + +static const UINT kTimerElapse = + #ifdef UNDER_CE + 500 + #else + 200 + #endif + ; + +static const UINT kCreateDelay = + #ifdef UNDER_CE + 2500 + #else + 500 + #endif + ; + +static const DWORD kPauseSleepTime = 100; + +#ifdef Z7_LANG + +static const UInt32 kLangIDs[] = +{ + IDT_PROGRESS_ELAPSED, + IDT_PROGRESS_REMAINING, + IDT_PROGRESS_TOTAL, + IDT_PROGRESS_SPEED, + IDT_PROGRESS_PROCESSED, + IDT_PROGRESS_RATIO, + IDT_PROGRESS_ERRORS, + IDB_PROGRESS_BACKGROUND, + IDB_PAUSE +}; + +static const UInt32 kLangIDs_Colon[] = +{ + IDT_PROGRESS_PACKED, + IDT_PROGRESS_FILES +}; + +#endif + + +#define UNDEFINED_VAL ((UInt64)(Int64)-1) +#define INIT_AS_UNDEFINED(v) v = UNDEFINED_VAL; +#define IS_UNDEFINED_VAL(v) ((v) == UNDEFINED_VAL) +#define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL) + +CProgressSync::CProgressSync(): + _stopped(false), + _paused(false), + _filesProgressMode(false), + _isDir(false), + _totalBytes(UNDEFINED_VAL), _completedBytes(0), + _totalFiles(UNDEFINED_VAL), _curFiles(0), + _inSize(UNDEFINED_VAL), + _outSize(UNDEFINED_VAL) + {} + +#define CHECK_STOP if (_stopped) return E_ABORT; if (!_paused) return S_OK; +#define CRITICAL_LOCK NSynchronization::CCriticalSectionLock lock(_cs); + +bool CProgressSync::Get_Paused() +{ + CRITICAL_LOCK + return _paused; +} + +HRESULT CProgressSync::CheckStop() +{ + for (;;) + { + { + CRITICAL_LOCK + CHECK_STOP + } + ::Sleep(kPauseSleepTime); + } +} + +void CProgressSync::Clear_Stop_Status() +{ + CRITICAL_LOCK + if (_stopped) + _stopped = false; +} + +HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir) +{ + { + CRITICAL_LOCK + _totalFiles = numFiles; + _totalBytes = totalSize; + _filePath = fs2us(fileName); + _isDir = isDir; + // _completedBytes = 0; + CHECK_STOP + } + return CheckStop(); +} + +HRESULT CProgressSync::Set_NumFilesTotal(UInt64 val) +{ + { + CRITICAL_LOCK + _totalFiles = val; + CHECK_STOP + } + return CheckStop(); +} + +void CProgressSync::Set_NumBytesTotal(UInt64 val) +{ + CRITICAL_LOCK + _totalBytes = val; +} + +void CProgressSync::Set_NumFilesCur(UInt64 val) +{ + CRITICAL_LOCK + _curFiles = val; +} + +HRESULT CProgressSync::Set_NumBytesCur(const UInt64 *val) +{ + { + CRITICAL_LOCK + if (val) + _completedBytes = *val; + CHECK_STOP + } + return CheckStop(); +} + +HRESULT CProgressSync::Set_NumBytesCur(UInt64 val) +{ + { + CRITICAL_LOCK + _completedBytes = val; + CHECK_STOP + } + return CheckStop(); +} + +void CProgressSync::Set_Ratio(const UInt64 *inSize, const UInt64 *outSize) +{ + CRITICAL_LOCK + if (inSize) + _inSize = *inSize; + if (outSize) + _outSize = *outSize; +} + +void CProgressSync::Set_TitleFileName(const UString &fileName) +{ + CRITICAL_LOCK + _titleFileName = fileName; +} + +void CProgressSync::Set_Status(const UString &s) +{ + CRITICAL_LOCK + _status = s; +} + +HRESULT CProgressSync::Set_Status2(const UString &s, const wchar_t *path, bool isDir) +{ + { + CRITICAL_LOCK + _status = s; + if (path) + _filePath = path; + else + _filePath.Empty(); + _isDir = isDir; + } + return CheckStop(); +} + +void CProgressSync::Set_FilePath(const wchar_t *path, bool isDir) +{ + CRITICAL_LOCK + if (path) + _filePath = path; + else + _filePath.Empty(); + _isDir = isDir; +} + + +void CProgressSync::AddError_Message(const wchar_t *message) +{ + CRITICAL_LOCK + Messages.Add(message); +} + +void CProgressSync::AddError_Message_Name(const wchar_t *message, const wchar_t *name) +{ + UString s; + if (name && *name != 0) + s += name; + if (message && *message != 0) + { + if (!s.IsEmpty()) + s.Add_LF(); + s += message; + if (!s.IsEmpty() && s.Back() == L'\n') + s.DeleteBack(); + } + AddError_Message(s); +} + +void CProgressSync::AddError_Code_Name(HRESULT systemError, const wchar_t *name) +{ + UString s = NError::MyFormatMessage(systemError); + if (systemError == 0) + s = "Error"; + AddError_Message_Name(s, name); +} + +CProgressDialog::CProgressDialog(): + _isDir(false), + _wasCreated(false), + _needClose(false), + _errorsWereDisplayed(false), + _waitCloseByCancelButton(false), + _cancelWasPressed(false), + _inCancelMessageBox(false), + _externalCloseMessageWasReceived(false), + _background(false), + WaitMode(false), + MessagesDisplayed(false), + CompressingMode(true), + ShowCompressionInfo(true), + _numPostedMessages(0), + _numAutoSizeMessages(0), + _numMessages(0), + _timer(0), + IconID(-1), + MainWindow(NULL) +{ + + if (_dialogCreatedEvent.Create() != S_OK) + throw 1334987; + if (_createDialogEvent.Create() != S_OK) + throw 1334987; + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&_taskbarList); + if (_taskbarList) + _taskbarList->HrInit(); + // #endif +} + +#ifndef Z7_SFX + +CProgressDialog::~CProgressDialog() +{ + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + SetTaskbarProgressState(TBPF_NOPROGRESS); + // #endif + AddToTitle(L""); +} +void CProgressDialog::AddToTitle(LPCWSTR s) +{ + if (MainWindow) + { + CWindow window(MainWindow); + window.SetText((UString)s + MainTitle); + } +} + +#endif + + +void CProgressDialog::SetTaskbarProgressState() +{ + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + if (_taskbarList && _hwndForTaskbar) + { + TBPFLAG tbpFlags; + if (Sync.Get_Paused()) + tbpFlags = TBPF_PAUSED; + else + tbpFlags = _errorsWereDisplayed ? TBPF_ERROR: TBPF_NORMAL; + SetTaskbarProgressState(tbpFlags); + } + // #endif +} + +static const unsigned kTitleFileNameSizeLimit = 36; +static const unsigned kCurrentFileNameSizeLimit = 82; + +static void ReduceString(UString &s, unsigned size) +{ + if (s.Len() <= size) + return; + s.Delete(size / 2, s.Len() - size); + s.Insert(size / 2, L" ... "); +} + +void CProgressDialog::EnableErrorsControls(bool enable) +{ + ShowItem_Bool(IDT_PROGRESS_ERRORS, enable); + ShowItem_Bool(IDT_PROGRESS_ERRORS_VAL, enable); + ShowItem_Bool(IDL_PROGRESS_MESSAGES, enable); +} + +bool CProgressDialog::OnInit() +{ + _hwndForTaskbar = MainWindow; + if (!_hwndForTaskbar) + _hwndForTaskbar = GetParent(); + if (!_hwndForTaskbar) + _hwndForTaskbar = *this; + + INIT_AS_UNDEFINED(_progressBar_Range) + INIT_AS_UNDEFINED(_progressBar_Pos) + + INIT_AS_UNDEFINED(_prevPercentValue) + INIT_AS_UNDEFINED(_prevElapsedSec) + INIT_AS_UNDEFINED(_prevRemainingSec) + + INIT_AS_UNDEFINED(_prevSpeed) + _prevSpeed_MoveBits = 0; + + _prevTime = ::GetTickCount(); + _elapsedTime = 0; + + INIT_AS_UNDEFINED(_totalBytes_Prev) + INIT_AS_UNDEFINED(_processed_Prev) + INIT_AS_UNDEFINED(_packed_Prev) + INIT_AS_UNDEFINED(_ratio_Prev) + + _filesStr_Prev.Empty(); + _filesTotStr_Prev.Empty(); + + m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); + _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES)); + _messageList.SetUnicodeFormat(); + _messageList.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT); + + _wasCreated = true; + _dialogCreatedEvent.Set(); + + #ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon)); + #endif + + CWindow window(GetItem(IDB_PROGRESS_BACKGROUND)); + window.GetText(_background_String); + _backgrounded_String = _background_String; + _backgrounded_String.RemoveChar(L'&'); + + window = GetItem(IDB_PAUSE); + window.GetText(_pause_String); + + LangString(IDS_PROGRESS_FOREGROUND, _foreground_String); + LangString(IDS_CONTINUE, _continue_String); + LangString(IDS_PROGRESS_PAUSED, _paused_String); + + SetText(_title); + SetPauseText(); + SetPriorityText(); + + _messageList.InsertColumn(0, L"", 40); + _messageList.InsertColumn(1, L"", 460); + _messageList.SetColumnWidthAuto(0); + _messageList.SetColumnWidthAuto(1); + + EnableErrorsControls(false); + + GetItemSizes(IDCANCEL, _buttonSizeX, _buttonSizeY); + _numReduceSymbols = kCurrentFileNameSizeLimit; + NormalizeSize(true); + + if (!ShowCompressionInfo) + { + HideItem(IDT_PROGRESS_PACKED); + HideItem(IDT_PROGRESS_PACKED_VAL); + HideItem(IDT_PROGRESS_RATIO); + HideItem(IDT_PROGRESS_RATIO_VAL); + } + + if (IconID >= 0) + { + HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID)); + // SetIcon(ICON_SMALL, icon); + SetIcon(ICON_BIG, icon); + } + _timer = SetTimer(kTimerID, kTimerElapse); + #ifdef UNDER_CE + Foreground(); + #endif + + CheckNeedClose(); + + SetTaskbarProgressState(); + + return CModalDialog::OnInit(); +} + +static const UINT kIDs[] = +{ + IDT_PROGRESS_ELAPSED, IDT_PROGRESS_ELAPSED_VAL, + IDT_PROGRESS_REMAINING, IDT_PROGRESS_REMAINING_VAL, + IDT_PROGRESS_FILES, IDT_PROGRESS_FILES_VAL, + 0, IDT_PROGRESS_FILES_TOTAL, + IDT_PROGRESS_ERRORS, IDT_PROGRESS_ERRORS_VAL, + + IDT_PROGRESS_TOTAL, IDT_PROGRESS_TOTAL_VAL, + IDT_PROGRESS_SPEED, IDT_PROGRESS_SPEED_VAL, + IDT_PROGRESS_PROCESSED, IDT_PROGRESS_PROCESSED_VAL, + IDT_PROGRESS_PACKED, IDT_PROGRESS_PACKED_VAL, + IDT_PROGRESS_RATIO, IDT_PROGRESS_RATIO_VAL +}; + +bool CProgressDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int sY; + int sStep; + int mx, my; + { + RECT r; + GetClientRectOfItem(IDT_PROGRESS_ELAPSED, r); + mx = r.left; + my = r.top; + sY = RECT_SIZE_Y(r); + GetClientRectOfItem(IDT_PROGRESS_REMAINING, r); + sStep = r.top - my; + } + + InvalidateRect(NULL); + + const int xSizeClient = xSize - mx * 2; + + { + unsigned i; + for (i = 800; i > 40; i = i * 9 / 10) + if (Units_To_Pixels_X((int)i) <= xSizeClient) + break; + _numReduceSymbols = i / 4; + } + + int yPos = ySize - my - _buttonSizeY; + + ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_STATUS), xSize - mx * 2); + ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_FILE_NAME), xSize - mx * 2); + ChangeSubWindowSizeX(GetItem(IDC_PROGRESS1), xSize - mx * 2); + + int bSizeX = _buttonSizeX; + int mx2 = mx; + for (;; mx2--) + { + const int bSize2 = bSizeX * 3 + mx2 * 2; + if (bSize2 <= xSizeClient) + break; + if (mx2 < 5) + { + bSizeX = (xSizeClient - mx2 * 2) / 3; + break; + } + } + if (bSizeX < 2) + bSizeX = 2; + + { + RECT r; + GetClientRectOfItem(IDL_PROGRESS_MESSAGES, r); + const int y = r.top; + int ySize2 = yPos - my - y; + const int kMinYSize = _buttonSizeY + _buttonSizeY * 3 / 4; + int xx = xSize - mx * 2; + if (ySize2 < kMinYSize) + { + ySize2 = kMinYSize; + if (xx > bSizeX * 2) + xx -= bSizeX; + } + + _messageList.Move(mx, y, xx, ySize2); + } + + { + int xPos = xSize - mx; + xPos -= bSizeX; + MoveItem(IDCANCEL, xPos, yPos, bSizeX, _buttonSizeY); + xPos -= (mx2 + bSizeX); + MoveItem(IDB_PAUSE, xPos, yPos, bSizeX, _buttonSizeY); + xPos -= (mx2 + bSizeX); + MoveItem(IDB_PROGRESS_BACKGROUND, xPos, yPos, bSizeX, _buttonSizeY); + } + + int valueSize; + int labelSize; + int padSize; + + labelSize = Units_To_Pixels_X(MY_PROGRESS_LABEL_UNITS_MIN); + valueSize = Units_To_Pixels_X(MY_PROGRESS_VAL_UNITS); + padSize = Units_To_Pixels_X(MY_PROGRESS_PAD_UNITS); + const int requiredSize = (labelSize + valueSize) * 2 + padSize; + + int gSize; + { + if (requiredSize < xSizeClient) + { + const int incr = (xSizeClient - requiredSize) / 3; + labelSize += incr; + } + else + labelSize = (xSizeClient - valueSize * 2 - padSize) / 2; + if (labelSize < 0) + labelSize = 0; + + gSize = labelSize + valueSize; + padSize = xSizeClient - gSize * 2; + } + + labelSize = gSize - valueSize; + + yPos = my; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDs); i += 2) + { + int x = mx; + const unsigned kNumColumn1Items = 5 * 2; + if (i >= kNumColumn1Items) + { + if (i == kNumColumn1Items) + yPos = my; + x = mx + gSize + padSize; + } + if (kIDs[i] != 0) + MoveItem(kIDs[i], x, yPos, labelSize, sY); + MoveItem(kIDs[i + 1], x + labelSize, yPos, valueSize, sY); + yPos += sStep; + } + return false; +} + +void CProgressDialog::OnCancel() { Sync.Set_Stopped(true); } +void CProgressDialog::OnOK() { } + +void CProgressDialog::SetProgressRange(UInt64 range) +{ + if (range == _progressBar_Range) + return; + _progressBar_Range = range; + INIT_AS_UNDEFINED(_progressBar_Pos) + _progressConv.Init(range); + m_ProgressBar.SetRange32(0, _progressConv.Count(range)); +} + +void CProgressDialog::SetProgressPos(UInt64 pos) +{ + if (pos >= _progressBar_Range || + pos <= _progressBar_Pos || + pos - _progressBar_Pos >= (_progressBar_Range >> 10)) + { + m_ProgressBar.SetPos(_progressConv.Count(pos)); + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + if (_taskbarList && _hwndForTaskbar) + _taskbarList->SetProgressValue(_hwndForTaskbar, pos, _progressBar_Range); + // #endif + _progressBar_Pos = pos; + } +} + +#define UINT_TO_STR_2(val) { s[0] = (wchar_t)('0' + (val) / 10); s[1] = (wchar_t)('0' + (val) % 10); s += 2; } + +void GetTimeString(UInt64 timeValue, wchar_t *s); +void GetTimeString(UInt64 timeValue, wchar_t *s) +{ + UInt64 hours = timeValue / 3600; + UInt32 seconds = (UInt32)(timeValue - hours * 3600); + UInt32 minutes = seconds / 60; + seconds %= 60; + if (hours > 99) + { + ConvertUInt64ToString(hours, s); + for (; *s != 0; s++); + } + else + { + UInt32 hours32 = (UInt32)hours; + UINT_TO_STR_2(hours32) + } + *s++ = ':'; UINT_TO_STR_2(minutes) + *s++ = ':'; UINT_TO_STR_2(seconds) + *s = 0; +} + +static void ConvertSizeToString(UInt64 v, wchar_t *s) +{ + Byte c = 0; + if (v >= ((UInt64)100000 << 20)) { v >>= 30; c = 'G'; } + else if (v >= ((UInt64)100000 << 10)) { v >>= 20; c = 'M'; } + else if (v >= ((UInt64)100000 << 0)) { v >>= 10; c = 'K'; } + ConvertUInt64ToString(v, s); + if (c != 0) + { + s += MyStringLen(s); + *s++ = ' '; + *s++ = c; + *s++ = 'B'; + *s++ = 0; + } +} + +void CProgressDialog::ShowSize(unsigned id, UInt64 val, UInt64 &prev) +{ + if (val == prev) + return; + prev = val; + wchar_t s[40]; + s[0] = 0; + if (IS_DEFINED_VAL(val)) + ConvertSizeToString(val, s); + SetItemText(id, s); +} + +static void GetChangedString(const UString &newStr, UString &prevStr, bool &hasChanged) +{ + hasChanged = !(prevStr == newStr); + if (hasChanged) + prevStr = newStr; +} + +static unsigned GetPower32(UInt32 val) +{ + const unsigned kStart = 32; + UInt32 mask = ((UInt32)1 << (kStart - 1)); + for (unsigned i = kStart;; i--) + { + if (i == 0 || (val & mask) != 0) + return i; + mask >>= 1; + } +} + +static unsigned GetPower64(UInt64 val) +{ + UInt32 high = (UInt32)(val >> 32); + if (high == 0) + return GetPower32((UInt32)val); + return GetPower32(high) + 32; +} + +static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider) +{ + unsigned pow1 = GetPower64(mult1); + unsigned pow2 = GetPower64(mult2); + while (pow1 + pow2 > 64) + { + if (pow1 > pow2) { pow1--; mult1 >>= 1; } + else { pow2--; mult2 >>= 1; } + divider >>= 1; + } + UInt64 res = mult1 * mult2; + if (divider != 0) + res /= divider; + return res; +} + +void CProgressDialog::UpdateStatInfo(bool showAll) +{ + UInt64 total, completed, totalFiles, completedFiles, inSize, outSize; + bool filesProgressMode; + + bool titleFileName_Changed; + bool curFilePath_Changed; + bool status_Changed; + unsigned numErrors; + { + NSynchronization::CCriticalSectionLock lock(Sync._cs); + total = Sync._totalBytes; + completed = Sync._completedBytes; + totalFiles = Sync._totalFiles; + completedFiles = Sync._curFiles; + inSize = Sync._inSize; + outSize = Sync._outSize; + filesProgressMode = Sync._filesProgressMode; + + GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed); + GetChangedString(Sync._filePath, _filePath, curFilePath_Changed); + GetChangedString(Sync._status, _status, status_Changed); + if (_isDir != Sync._isDir) + { + curFilePath_Changed = true; + _isDir = Sync._isDir; + } + numErrors = Sync.Messages.Size(); + } + + UInt32 curTime = ::GetTickCount(); + + const UInt64 progressTotal = filesProgressMode ? totalFiles : total; + const UInt64 progressCompleted = filesProgressMode ? completedFiles : completed; + { + if (IS_UNDEFINED_VAL(progressTotal)) + { + // SetPos(0); + // SetRange(progressCompleted); + } + else + { + if (_progressBar_Pos != 0 || progressCompleted != 0 || + (_progressBar_Range == 0 && progressTotal != 0)) + { + SetProgressRange(progressTotal); + SetProgressPos(progressCompleted); + } + } + } + + ShowSize(IDT_PROGRESS_TOTAL_VAL, total, _totalBytes_Prev); + + _elapsedTime += (curTime - _prevTime); + _prevTime = curTime; + UInt64 elapsedSec = _elapsedTime / 1000; + bool elapsedChanged = false; + if (elapsedSec != _prevElapsedSec) + { + _prevElapsedSec = elapsedSec; + elapsedChanged = true; + wchar_t s[40]; + GetTimeString(elapsedSec, s); + SetItemText(IDT_PROGRESS_ELAPSED_VAL, s); + } + + bool needSetTitle = false; + if (elapsedChanged || showAll) + { + if (numErrors > _numPostedMessages) + { + UpdateMessagesDialog(); + wchar_t s[32]; + ConvertUInt64ToString(numErrors, s); + SetItemText(IDT_PROGRESS_ERRORS_VAL, s); + if (!_errorsWereDisplayed) + { + _errorsWereDisplayed = true; + EnableErrorsControls(true); + SetTaskbarProgressState(); + } + } + + if (progressCompleted != 0) + { + if (IS_UNDEFINED_VAL(progressTotal)) + { + if (IS_DEFINED_VAL(_prevRemainingSec)) + { + INIT_AS_UNDEFINED(_prevRemainingSec) + SetItemText(IDT_PROGRESS_REMAINING_VAL, L""); + } + } + else + { + UInt64 remainingTime = 0; + if (progressCompleted < progressTotal) + remainingTime = MyMultAndDiv(_elapsedTime, progressTotal - progressCompleted, progressCompleted); + UInt64 remainingSec = remainingTime / 1000; + if (remainingSec != _prevRemainingSec) + { + _prevRemainingSec = remainingSec; + wchar_t s[40]; + GetTimeString(remainingSec, s); + SetItemText(IDT_PROGRESS_REMAINING_VAL, s); + } + } + { + const UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime; + // 22.02: progressCompleted can be for number of files + UInt64 v = (completed * 1000) / elapsedTime; + Byte c = 0; + unsigned moveBits = 0; + if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; } + else if (v >= ((UInt64)10000 << 0)) { moveBits = 10; c = 'K'; } + v >>= moveBits; + if (moveBits != _prevSpeed_MoveBits || v != _prevSpeed) + { + _prevSpeed_MoveBits = moveBits; + _prevSpeed = v; + wchar_t s[40]; + ConvertUInt64ToString(v, s); + unsigned pos = MyStringLen(s); + s[pos++] = ' '; + if (moveBits != 0) + s[pos++] = c; + s[pos++] = 'B'; + s[pos++] = '/'; + s[pos++] = 's'; + s[pos++] = 0; + SetItemText(IDT_PROGRESS_SPEED_VAL, s); + } + } + } + + { + UInt64 percent = 0; + { + if (IS_DEFINED_VAL(progressTotal)) + { + percent = progressCompleted * 100; + if (progressTotal != 0) + percent /= progressTotal; + } + } + if (percent != _prevPercentValue) + { + _prevPercentValue = percent; + needSetTitle = true; + } + } + + { + wchar_t s[64]; + + ConvertUInt64ToString(completedFiles, s); + if (_filesStr_Prev != s) + { + _filesStr_Prev = s; + SetItemText(IDT_PROGRESS_FILES_VAL, s); + } + + s[0] = 0; + if (IS_DEFINED_VAL(totalFiles)) + { + MyStringCopy(s, L" / "); + ConvertUInt64ToString(totalFiles, s + MyStringLen(s)); + } + if (_filesTotStr_Prev != s) + { + _filesTotStr_Prev = s; + SetItemText(IDT_PROGRESS_FILES_TOTAL, s); + } + } + + const UInt64 packSize = CompressingMode ? outSize : inSize; + const UInt64 unpackSize = CompressingMode ? inSize : outSize; + + if (IS_UNDEFINED_VAL(unpackSize) && + IS_UNDEFINED_VAL(packSize)) + { + ShowSize(IDT_PROGRESS_PROCESSED_VAL, completed, _processed_Prev); + ShowSize(IDT_PROGRESS_PACKED_VAL, UNDEFINED_VAL, _packed_Prev); + } + else + { + ShowSize(IDT_PROGRESS_PROCESSED_VAL, unpackSize, _processed_Prev); + ShowSize(IDT_PROGRESS_PACKED_VAL, packSize, _packed_Prev); + + if (IS_DEFINED_VAL(packSize) && + IS_DEFINED_VAL(unpackSize) && + unpackSize != 0) + { + wchar_t s[32]; + UInt64 ratio = packSize * 100 / unpackSize; + if (_ratio_Prev != ratio) + { + _ratio_Prev = ratio; + ConvertUInt64ToString(ratio, s); + MyStringCat(s, L"%"); + SetItemText(IDT_PROGRESS_RATIO_VAL, s); + } + } + } + } + + if (needSetTitle || titleFileName_Changed) + SetTitleText(); + + if (status_Changed) + { + UString s = _status; + ReduceString(s, _numReduceSymbols); + SetItemText(IDT_PROGRESS_STATUS, s); + } + + if (curFilePath_Changed) + { + UString s1, s2; + if (_isDir) + s1 = _filePath; + else + { + int slashPos = _filePath.ReverseFind_PathSepar(); + if (slashPos >= 0) + { + s1.SetFrom(_filePath, (unsigned)(slashPos + 1)); + s2 = _filePath.Ptr((unsigned)(slashPos + 1)); + } + else + s2 = _filePath; + } + ReduceString(s1, _numReduceSymbols); + ReduceString(s2, _numReduceSymbols); + s1.Add_LF(); + s1 += s2; + SetItemText(IDT_PROGRESS_FILE_NAME, s1); + } +} + +bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) +{ + if (Sync.Get_Paused()) + return true; + CheckNeedClose(); + UpdateStatInfo(false); + return true; +} + +struct CWaitCursor +{ + HCURSOR _waitCursor; + HCURSOR _oldCursor; + CWaitCursor() + { + _waitCursor = LoadCursor(NULL, IDC_WAIT); + if (_waitCursor != NULL) + _oldCursor = SetCursor(_waitCursor); + } + ~CWaitCursor() + { + if (_waitCursor != NULL) + SetCursor(_oldCursor); + } +}; + +INT_PTR CProgressDialog::Create(const UString &title, NWindows::CThread &thread, HWND wndParent) +{ + INT_PTR res = 0; + try + { + if (WaitMode) + { + CWaitCursor waitCursor; + HANDLE h[] = { thread, _createDialogEvent }; + + const DWORD res2 = WaitForMultipleObjects(Z7_ARRAY_SIZE(h), h, FALSE, kCreateDelay); + if (res2 == WAIT_OBJECT_0 && !Sync.ThereIsMessage()) + return 0; + } + _title = title; + BIG_DIALOG_SIZE(360, 192); + res = CModalDialog::Create(SIZED_DIALOG(IDD_PROGRESS), wndParent); + } + catch(...) + { + _wasCreated = true; + _dialogCreatedEvent.Set(); + } + thread.Wait_Close(); + if (!MessagesDisplayed) + if (!g_DisableUserQuestions) + MessageBoxW(wndParent, L"Progress Error", L"7-Zip", MB_ICONERROR); + return res; +} + +bool CProgressDialog::OnExternalCloseMessage() +{ + // it doesn't work if there is MessageBox. + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + SetTaskbarProgressState(TBPF_NOPROGRESS); + // #endif + // AddToTitle(L"Finished "); + // SetText(L"Finished2 "); + + UpdateStatInfo(true); + + SetItemText(IDCANCEL, LangString(IDS_CLOSE)); + ::SendMessage(GetItem(IDCANCEL), BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0)); + HideItem(IDB_PROGRESS_BACKGROUND); + HideItem(IDB_PAUSE); + + ProcessWasFinished_GuiVirt(); + + bool thereAreMessages; + CProgressFinalMessage fm; + { + NSynchronization::CCriticalSectionLock lock(Sync._cs); + thereAreMessages = !Sync.Messages.IsEmpty(); + fm = Sync.FinalMessage; + } + + if (!fm.ErrorMessage.Message.IsEmpty()) + { + MessagesDisplayed = true; + if (fm.ErrorMessage.Title.IsEmpty()) + fm.ErrorMessage.Title = "7-Zip"; + if (!g_DisableUserQuestions) + MessageBoxW(*this, fm.ErrorMessage.Message, fm.ErrorMessage.Title, MB_ICONERROR); + } + else if (!thereAreMessages) + { + MessagesDisplayed = true; + + if (!fm.OkMessage.Message.IsEmpty()) + { + if (fm.OkMessage.Title.IsEmpty()) + fm.OkMessage.Title = "7-Zip"; + if (!g_DisableUserQuestions) + MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK); + } + } + + if (!g_DisableUserQuestions) + if (thereAreMessages && !_cancelWasPressed) + { + _waitCloseByCancelButton = true; + UpdateMessagesDialog(); + return true; + } + + End(0); + return true; +} + +bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case kCloseMessage: + { + if (_timer) + { + /* 21.03 : KillTimer(kTimerID) instead of KillTimer(_timer). + But (_timer == kTimerID) in Win10. So it worked too */ + KillTimer(kTimerID); + _timer = 0; + } + if (_inCancelMessageBox) + { + /* if user is in MessageBox(), we will call OnExternalCloseMessage() + later, when MessageBox() will be closed */ + _externalCloseMessageWasReceived = true; + break; + } + return OnExternalCloseMessage(); + } + /* + case WM_SETTEXT: + { + if (_timer == 0) + return true; + break; + } + */ + } + return CModalDialog::OnMessage(message, wParam, lParam); +} + +void CProgressDialog::SetTitleText() +{ + UString s; + if (Sync.Get_Paused()) + { + s += _paused_String; + s.Add_Space(); + } + if (IS_DEFINED_VAL(_prevPercentValue)) + { + s.Add_UInt64(_prevPercentValue); + s.Add_Char('%'); + } + if (_background) + { + s.Add_Space(); + s += _backgrounded_String; + } + + s.Add_Space(); + #ifndef Z7_SFX + { + unsigned len = s.Len(); + s += MainAddTitle; + AddToTitle(s); + s.DeleteFrom(len); + } + #endif + + s += _title; + if (!_titleFileName.IsEmpty()) + { + UString fileName = _titleFileName; + ReduceString(fileName, kTitleFileNameSizeLimit); + s.Add_Space(); + s += fileName; + } + SetText(s); +} + +void CProgressDialog::SetPauseText() +{ + SetItemText(IDB_PAUSE, Sync.Get_Paused() ? _continue_String : _pause_String); + SetTitleText(); +} + +void CProgressDialog::OnPauseButton() +{ + bool paused = !Sync.Get_Paused(); + Sync.Set_Paused(paused); + UInt32 curTime = ::GetTickCount(); + if (paused) + _elapsedTime += (curTime - _prevTime); + SetTaskbarProgressState(); + _prevTime = curTime; + SetPauseText(); +} + +void CProgressDialog::SetPriorityText() +{ + SetItemText(IDB_PROGRESS_BACKGROUND, _background ? + _foreground_String : + _background_String); + SetTitleText(); +} + +void CProgressDialog::OnPriorityButton() +{ + _background = !_background; + #ifndef UNDER_CE + SetPriorityClass(GetCurrentProcess(), _background ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS); + #endif + SetPriorityText(); +} + +void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber) +{ + wchar_t sz[16]; + sz[0] = 0; + if (needNumber) + ConvertUInt32ToString(_numMessages + 1, sz); + const unsigned itemIndex = _messageStrings.Size(); // _messageList.GetItemCount(); + if (_messageList.InsertItem(itemIndex, sz) == (int)itemIndex) + { + _messageList.SetSubItem(itemIndex, 1, message); + _messageStrings.Add(message); + } +} + +void CProgressDialog::AddMessage(LPCWSTR message) +{ + UString s = message; + bool needNumber = true; + while (!s.IsEmpty()) + { + const int pos = s.Find(L'\n'); + if (pos < 0) + break; + AddMessageDirect(s.Left((unsigned)pos), needNumber); + needNumber = false; + s.DeleteFrontal((unsigned)pos + 1); + } + AddMessageDirect(s, needNumber); + _numMessages++; +} + +static unsigned GetNumDigits(unsigned val) +{ + unsigned i = 0; + for (;;) + { + i++; + val /= 10; + if (val == 0) + return i; + } +} + +void CProgressDialog::UpdateMessagesDialog() +{ + UStringVector messages; + { + NSynchronization::CCriticalSectionLock lock(Sync._cs); + const unsigned num = Sync.Messages.Size(); + if (num > _numPostedMessages) + { + messages.ClearAndReserve(num - _numPostedMessages); + for (unsigned i = _numPostedMessages; i < num; i++) + messages.AddInReserved(Sync.Messages[i]); + _numPostedMessages = num; + } + } + if (!messages.IsEmpty()) + { + FOR_VECTOR (i, messages) + AddMessage(messages[i]); + // SetColumnWidthAuto() can be slow for big number of files. + if (_numPostedMessages < 1000000 || _numAutoSizeMessages < 100) + if (_numAutoSizeMessages < 100 || + GetNumDigits(_numPostedMessages) > + GetNumDigits(_numAutoSizeMessages)) + { + _messageList.SetColumnWidthAuto(0); + _messageList.SetColumnWidthAuto(1); + _numAutoSizeMessages = _numPostedMessages; + } + } +} + + +bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON + case IDCANCEL: + { + if (_waitCloseByCancelButton) + { + MessagesDisplayed = true; + End(IDCLOSE); + break; + } + + if (_cancelWasPressed) + return true; + + const bool paused = Sync.Get_Paused(); + + if (!paused) + { + OnPauseButton(); + } + + _inCancelMessageBox = true; + const int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL); + _inCancelMessageBox = false; + if (res == IDYES) + _cancelWasPressed = true; + + if (!paused) + { + OnPauseButton(); + } + + if (_externalCloseMessageWasReceived) + { + /* we have received kCloseMessage while we were in MessageBoxW(). + so we call OnExternalCloseMessage() here. + it can show MessageBox and it can close dialog */ + OnExternalCloseMessage(); + return true; + } + + if (!_cancelWasPressed) + return true; + + MessagesDisplayed = true; + // we will call Sync.Set_Stopped(true) in OnButtonClicked() : OnCancel() + break; + } + + case IDB_PAUSE: + OnPauseButton(); + return true; + case IDB_PROGRESS_BACKGROUND: + OnPriorityButton(); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CProgressDialog::CheckNeedClose() +{ + if (_needClose) + { + PostMsg(kCloseMessage); + _needClose = false; + } +} + +void CProgressDialog::ProcessWasFinished() +{ + // Set Window title here. + if (!WaitMode) + WaitCreating(); + + if (_wasCreated) + PostMsg(kCloseMessage); + else + _needClose = true; +} + + +bool CProgressDialog::OnNotify(UINT /* controlID */, LPNMHDR header) +{ + if (header->hwndFrom != _messageList) + return false; + switch (header->code) + { + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header); + switch (keyDownInfo->wVKey) + { + case 'A': + { + if (IsKeyDown(VK_CONTROL)) + { + _messageList.SelectAll(); + return true; + } + break; + } + case VK_INSERT: + case 'C': + { + if (IsKeyDown(VK_CONTROL)) + { + CopyToClipboard(); + return true; + } + break; + } + } + } + } + return false; +} + + +static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector) +{ + vector.Clear(); + int index = -1; + for (;;) + { + index = listView.GetNextSelectedItem(index); + if (index < 0) + break; + vector.Add((unsigned)index); + } +} + + +void CProgressDialog::CopyToClipboard() +{ + CUIntVector indexes; + ListView_GetSelected(_messageList, indexes); + UString s; + unsigned numIndexes = indexes.Size(); + if (numIndexes == 0) + numIndexes = (unsigned)_messageList.GetItemCount(); + + for (unsigned i = 0; i < numIndexes; i++) + { + const unsigned index = (i < indexes.Size() ? indexes[i] : i); + // s.Add_UInt32(index); + // s += ": "; + s += _messageStrings[index]; + { + s += + #ifdef _WIN32 + "\r\n" + #else + "\n" + #endif + ; + } + } + + ClipboardSetText(*this, s); +} + + +static THREAD_FUNC_DECL MyThreadFunction(void *param) +{ + CProgressThreadVirt *p = (CProgressThreadVirt *)param; + try + { + p->Process(); + p->ThreadFinishedOK = true; + } + catch (...) { p->Result = E_FAIL; } + return 0; +} + + +HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow) +{ + NWindows::CThread thread; + const WRes wres = thread.Create(MyThreadFunction, this); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + CProgressDialog::Create(title, thread, parentWindow); + return S_OK; +} + +static void AddMessageToString(UString &dest, const UString &src) +{ + if (!src.IsEmpty()) + { + if (!dest.IsEmpty()) + dest.Add_LF(); + dest += src; + } +} + +void CProgressThreadVirt::Process() +{ + CProgressCloser closer(*this); + UString m; + try { Result = ProcessVirt(); } + catch(const wchar_t *s) { m = s; } + catch(const UString &s) { m = s; } + catch(const char *s) { m = GetUnicodeString(s); } + catch(int v) + { + m = "Error #"; + m.Add_UInt32((unsigned)v); + } + catch(...) { m = "Error"; } + if (Result != E_ABORT) + { + if (m.IsEmpty() && Result != S_OK) + m = HResultToMessage(Result); + } + AddMessageToString(m, FinalMessage.ErrorMessage.Message); + + { + FOR_VECTOR(i, ErrorPaths) + { + if (i >= 32) + break; + AddMessageToString(m, fs2us(ErrorPaths[i])); + } + } + + CProgressSync &sync = Sync; + NSynchronization::CCriticalSectionLock lock(sync._cs); + if (m.IsEmpty()) + { + if (!FinalMessage.OkMessage.Message.IsEmpty()) + sync.FinalMessage.OkMessage = FinalMessage.OkMessage; + } + else + { + sync.FinalMessage.ErrorMessage.Message = m; + if (Result == S_OK) + Result = E_FAIL; + } +} + +UString HResultToMessage(HRESULT errorCode) +{ + if (errorCode == E_OUTOFMEMORY) + return LangString(IDS_MEM_ERROR); + else + return NError::MyFormatMessage(errorCode); +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.h b/CPP/7zip/UI/FileManager/ProgressDialog2.h index 6e07ab5bd..60a5ca62a 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.h @@ -1,358 +1,355 @@ -// ProgressDialog2.h - -#ifndef ZIP7_INC_PROGRESS_DIALOG_2_H -#define ZIP7_INC_PROGRESS_DIALOG_2_H - -#include "../../../Common/MyCom.h" - -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/Synchronization.h" -#include "../../../Windows/Thread.h" - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/ListView.h" -#include "../../../Windows/Control/ProgressBar.h" - -#include "MyWindowsNew.h" - -struct CProgressMessageBoxPair -{ - UString Title; - UString Message; -}; - -struct CProgressFinalMessage -{ - CProgressMessageBoxPair ErrorMessage; - CProgressMessageBoxPair OkMessage; - - bool ThereIsMessage() const { return !ErrorMessage.Message.IsEmpty() || !OkMessage.Message.IsEmpty(); } -}; - -class CProgressSync -{ - bool _stopped; - bool _paused; - -public: - bool _bytesProgressMode; - bool _isDir; - UInt64 _totalBytes; - UInt64 _completedBytes; - UInt64 _totalFiles; - UInt64 _curFiles; - UInt64 _inSize; - UInt64 _outSize; - - UString _titleFileName; - UString _status; - UString _filePath; - - UStringVector Messages; - CProgressFinalMessage FinalMessage; - - NWindows::NSynchronization::CCriticalSection _cs; - - CProgressSync(); - - bool Get_Stopped() - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - return _stopped; - } - void Set_Stopped(bool val) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _stopped = val; - } - - bool Get_Paused(); - void Set_Paused(bool val) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _paused = val; - } - - void Set_BytesProgressMode(bool bytesProgressMode) - { - NWindows::NSynchronization::CCriticalSectionLock lock(_cs); - _bytesProgressMode = bytesProgressMode; - } - - HRESULT CheckStop(); - HRESULT ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir = false); - - HRESULT Set_NumFilesTotal(UInt64 val); - void Set_NumBytesTotal(UInt64 val); - void Set_NumFilesCur(UInt64 val); - HRESULT Set_NumBytesCur(const UInt64 *val); - HRESULT Set_NumBytesCur(UInt64 val); - void Set_Ratio(const UInt64 *inSize, const UInt64 *outSize); - - void Set_TitleFileName(const UString &fileName); - void Set_Status(const UString &s); - HRESULT Set_Status2(const UString &s, const wchar_t *path, bool isDir = false); - void Set_FilePath(const wchar_t *path, bool isDir = false); - - void AddError_Message(const wchar_t *message); - void AddError_Message_Name(const wchar_t *message, const wchar_t *name); - // void AddError_Code_Name(DWORD systemError, const wchar_t *name); - void AddError_Code_Name(HRESULT systemError, const wchar_t *name); - - bool ThereIsMessage() const { return !Messages.IsEmpty() || FinalMessage.ThereIsMessage(); } -}; - -class CProgressDialog: public NWindows::NControl::CModalDialog -{ - UString _titleFileName; - UString _filePath; - UString _status; - bool _isDir; - - UString _background_String; - UString _backgrounded_String; - UString _foreground_String; - UString _pause_String; - UString _continue_String; - UString _paused_String; - - int _buttonSizeX; - int _buttonSizeY; - - UINT_PTR _timer; - - UString _title; - - class CU64ToI32Converter - { - unsigned _numShiftBits; - UInt64 _range; - public: - CU64ToI32Converter(): _numShiftBits(0), _range(1) {} - void Init(UInt64 range) - { - _range = range; - // Windows CE doesn't like big number for ProgressBar. - for (_numShiftBits = 0; range >= ((UInt32)1 << 15); _numShiftBits++) - range >>= 1; - } - int Count(UInt64 val) - { - int res = (int)(val >> _numShiftBits); - if (val == _range) - res++; - return res; - } - }; - - CU64ToI32Converter _progressConv; - UInt64 _progressBar_Pos; - UInt64 _progressBar_Range; - - NWindows::NControl::CProgressBar m_ProgressBar; - NWindows::NControl::CListView _messageList; - - unsigned _numMessages; - UStringVector _messageStrings; - - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - CMyComPtr _taskbarList; - // #endif - HWND _hwndForTaskbar; - - UInt32 _prevTime; - UInt64 _elapsedTime; - - UInt64 _prevPercentValue; - UInt64 _prevElapsedSec; - UInt64 _prevRemainingSec; - - UInt64 _totalBytes_Prev; - UInt64 _processed_Prev; - UInt64 _packed_Prev; - UInt64 _ratio_Prev; - - UString _filesStr_Prev; - UString _filesTotStr_Prev; - - unsigned _prevSpeed_MoveBits; - UInt64 _prevSpeed; - - bool _foreground; - - unsigned _numReduceSymbols; - - bool _wasCreated; - bool _needClose; - - unsigned _numPostedMessages; - UInt32 _numAutoSizeMessages; - - bool _errorsWereDisplayed; - - bool _waitCloseByCancelButton; - bool _cancelWasPressed; - - bool _inCancelMessageBox; - bool _externalCloseMessageWasReceived; - - - // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ - void SetTaskbarProgressState(TBPFLAG tbpFlags) - { - if (_taskbarList && _hwndForTaskbar) - _taskbarList->SetProgressState(_hwndForTaskbar, tbpFlags); - } - // #endif - void SetTaskbarProgressState(); - - void UpdateStatInfo(bool showAll); - void SetProgressRange(UInt64 range); - void SetProgressPos(UInt64 pos); - virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual void OnCancel() Z7_override; - virtual void OnOK() Z7_override; - virtual bool OnNotify(UINT /* controlID */, LPNMHDR header) Z7_override; - void CopyToClipboard(); - - NWindows::NSynchronization::CManualResetEvent _createDialogEvent; - NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent; - #ifndef Z7_SFX - void AddToTitle(LPCWSTR string); - #endif - - void SetPauseText(); - void SetPriorityText(); - void OnPauseButton(); - void OnPriorityButton(); - bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - - void SetTitleText(); - void ShowSize(unsigned id, UInt64 val, UInt64 &prev); - - void UpdateMessagesDialog(); - - void AddMessageDirect(LPCWSTR message, bool needNumber); - void AddMessage(LPCWSTR message); - - bool OnExternalCloseMessage(); - void EnableErrorsControls(bool enable); - - void ShowAfterMessages(HWND wndParent); - - void CheckNeedClose(); -public: - CProgressSync Sync; - bool CompressingMode; - bool WaitMode; - bool ShowCompressionInfo; - bool MessagesDisplayed; // = true if user pressed OK on all messages or there are no messages. - int IconID; - - HWND MainWindow; - #ifndef Z7_SFX - UString MainTitle; - UString MainAddTitle; - ~CProgressDialog() Z7_DESTRUCTOR_override; - #endif - - CProgressDialog(); - void WaitCreating() - { - _createDialogEvent.Set(); - _dialogCreatedEvent.Lock(); - } - - INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = NULL); - - - /* how it works: - 1) the working thread calls ProcessWasFinished() - that sends kCloseMessage message to CProgressDialog (GUI) thread - 2) CProgressDialog (GUI) thread receives kCloseMessage message and - calls ProcessWasFinished_GuiVirt(); - So we can implement ProcessWasFinished_GuiVirt() and show special - results window in GUI thread with CProgressDialog as parent window - */ - - void ProcessWasFinished(); - virtual void ProcessWasFinished_GuiVirt() {} -}; - - -class CProgressCloser -{ - CProgressDialog *_p; -public: - CProgressCloser(CProgressDialog &p) : _p(&p) {} - ~CProgressCloser() { _p->ProcessWasFinished(); } -}; - - -class CProgressThreadVirt: public CProgressDialog -{ -protected: - FStringVector ErrorPaths; - CProgressFinalMessage FinalMessage; - - // error if any of HRESULT, ErrorMessage, ErrorPath - virtual HRESULT ProcessVirt() = 0; -public: - HRESULT Result; - bool ThreadFinishedOK; // if there is no fatal exception - - void Process(); - void AddErrorPath(const FString &path) { ErrorPaths.Add(path); } - - HRESULT Create(const UString &title, HWND parentWindow = NULL); - CProgressThreadVirt(): Result(E_FAIL), ThreadFinishedOK(false) {} - - CProgressMessageBoxPair &GetMessagePair(bool isError) { return isError ? FinalMessage.ErrorMessage : FinalMessage.OkMessage; } -}; - -UString HResultToMessage(HRESULT errorCode); - -/* -how it works: - -client code inherits CProgressThreadVirt and calls -CProgressThreadVirt::Create() -{ - it creates new thread that calls CProgressThreadVirt::Process(); - it creates modal progress dialog window with ProgressDialog.Create() -} - -CProgressThreadVirt::Process() -{ - { - Result = ProcessVirt(); // virtual function that must implement real work - } - if (exceptions) or FinalMessage.ErrorMessage.Message - { - set message to ProgressDialog.Sync.FinalMessage.ErrorMessage.Message - } - else if (FinalMessage.OkMessage.Message) - { - set message to ProgressDialog.Sync.FinalMessage.OkMessage - } - - PostMsg(kCloseMessage); -} - - -CProgressDialog::OnExternalCloseMessage() -{ - if (ProgressDialog.Sync.FinalMessage) - { - WorkWasFinishedVirt(); - Show (ProgressDialog.Sync.FinalMessage) - MessagesDisplayed = true; - } -} - -*/ - -#endif +// ProgressDialog2.h + +#ifndef ZIP7_INC_PROGRESS_DIALOG_2_H +#define ZIP7_INC_PROGRESS_DIALOG_2_H + +#include "../../../Common/MyCom.h" + +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/Thread.h" + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/ListView.h" +#include "../../../Windows/Control/ProgressBar.h" + +#include "MyWindowsNew.h" + +struct CProgressMessageBoxPair +{ + UString Title; + UString Message; +}; + +struct CProgressFinalMessage +{ + CProgressMessageBoxPair ErrorMessage; + CProgressMessageBoxPair OkMessage; + + bool ThereIsMessage() const { return !ErrorMessage.Message.IsEmpty() || !OkMessage.Message.IsEmpty(); } +}; + +class CProgressSync +{ + bool _stopped; + bool _paused; +public: + bool _filesProgressMode; + bool _isDir; + UInt64 _totalBytes; + UInt64 _completedBytes; + UInt64 _totalFiles; + UInt64 _curFiles; + UInt64 _inSize; + UInt64 _outSize; + + UString _titleFileName; + UString _status; + UString _filePath; + + UStringVector Messages; + CProgressFinalMessage FinalMessage; + + NWindows::NSynchronization::CCriticalSection _cs; + + CProgressSync(); + + bool Get_Stopped() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + return _stopped; + } + void Set_Stopped(bool val) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _stopped = val; + } + + bool Get_Paused(); + void Set_Paused(bool val) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _paused = val; + } + + void Set_FilesProgressMode(bool filesProgressMode) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_cs); + _filesProgressMode = filesProgressMode; + } + + HRESULT CheckStop(); + void Clear_Stop_Status(); + HRESULT ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir = false); + + HRESULT Set_NumFilesTotal(UInt64 val); + void Set_NumBytesTotal(UInt64 val); + void Set_NumFilesCur(UInt64 val); + HRESULT Set_NumBytesCur(const UInt64 *val); + HRESULT Set_NumBytesCur(UInt64 val); + void Set_Ratio(const UInt64 *inSize, const UInt64 *outSize); + + void Set_TitleFileName(const UString &fileName); + void Set_Status(const UString &s); + HRESULT Set_Status2(const UString &s, const wchar_t *path, bool isDir = false); + void Set_FilePath(const wchar_t *path, bool isDir = false); + + void AddError_Message(const wchar_t *message); + void AddError_Message_Name(const wchar_t *message, const wchar_t *name); + // void AddError_Code_Name(DWORD systemError, const wchar_t *name); + void AddError_Code_Name(HRESULT systemError, const wchar_t *name); + + bool ThereIsMessage() const { return !Messages.IsEmpty() || FinalMessage.ThereIsMessage(); } +}; + + +class CProgressDialog: public NWindows::NControl::CModalDialog +{ + bool _isDir; + bool _wasCreated; + bool _needClose; + bool _errorsWereDisplayed; + bool _waitCloseByCancelButton; + bool _cancelWasPressed; + bool _inCancelMessageBox; + bool _externalCloseMessageWasReceived; + bool _background; +public: + bool WaitMode; + bool MessagesDisplayed; // = true if user pressed OK on all messages or there are no messages. + bool CompressingMode; + bool ShowCompressionInfo; + +private: + unsigned _numPostedMessages; + unsigned _numAutoSizeMessages; + unsigned _numMessages; + + UString _titleFileName; + UString _filePath; + UString _status; + + UString _background_String; + UString _backgrounded_String; + UString _foreground_String; + UString _pause_String; + UString _continue_String; + UString _paused_String; + + int _buttonSizeX; + int _buttonSizeY; + + UINT_PTR _timer; + + UString _title; + + class CU64ToI32Converter + { + unsigned _numShiftBits; + UInt64 _range; + public: + CU64ToI32Converter(): _numShiftBits(0), _range(1) {} + void Init(UInt64 range) + { + _range = range; + // Windows CE doesn't like big number for ProgressBar. + for (_numShiftBits = 0; range >= ((UInt32)1 << 15); _numShiftBits++) + range >>= 1; + } + int Count(UInt64 val) + { + int res = (int)(val >> _numShiftBits); + if (val == _range) + res++; + return res; + } + }; + + CU64ToI32Converter _progressConv; + UInt64 _progressBar_Pos; + UInt64 _progressBar_Range; + + NWindows::NControl::CProgressBar m_ProgressBar; + NWindows::NControl::CListView _messageList; + + UStringVector _messageStrings; + + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + CMyComPtr _taskbarList; + // #endif + HWND _hwndForTaskbar; + + UInt32 _prevTime; + UInt64 _elapsedTime; + + UInt64 _prevPercentValue; + UInt64 _prevElapsedSec; + UInt64 _prevRemainingSec; + + UInt64 _totalBytes_Prev; + UInt64 _processed_Prev; + UInt64 _packed_Prev; + UInt64 _ratio_Prev; + + UString _filesStr_Prev; + UString _filesTotStr_Prev; + + unsigned _numReduceSymbols; + unsigned _prevSpeed_MoveBits; + UInt64 _prevSpeed; + + // #ifdef __ITaskbarList3_INTERFACE_DEFINED__ + void SetTaskbarProgressState(TBPFLAG tbpFlags) + { + if (_taskbarList && _hwndForTaskbar) + _taskbarList->SetProgressState(_hwndForTaskbar, tbpFlags); + } + // #endif + void SetTaskbarProgressState(); + + void UpdateStatInfo(bool showAll); + void SetProgressRange(UInt64 range); + void SetProgressPos(UInt64 pos); + virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual void OnCancel() Z7_override; + virtual void OnOK() Z7_override; + virtual bool OnNotify(UINT /* controlID */, LPNMHDR header) Z7_override; + void CopyToClipboard(); + + NWindows::NSynchronization::CManualResetEvent _createDialogEvent; + NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent; + #ifndef Z7_SFX + void AddToTitle(LPCWSTR string); + #endif + + void SetPauseText(); + void SetPriorityText(); + void OnPauseButton(); + void OnPriorityButton(); + bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + + void SetTitleText(); + void ShowSize(unsigned id, UInt64 val, UInt64 &prev); + + void UpdateMessagesDialog(); + + void AddMessageDirect(LPCWSTR message, bool needNumber); + void AddMessage(LPCWSTR message); + + bool OnExternalCloseMessage(); + void EnableErrorsControls(bool enable); + + void ShowAfterMessages(HWND wndParent); + + void CheckNeedClose(); + +public: + CProgressSync Sync; + int IconID; + HWND MainWindow; + #ifndef Z7_SFX + UString MainTitle; + UString MainAddTitle; + ~CProgressDialog() Z7_DESTRUCTOR_override; + #endif + + CProgressDialog(); + void WaitCreating() + { + _createDialogEvent.Set(); + _dialogCreatedEvent.Lock(); + } + + INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = NULL); + + + /* how it works: + 1) the working thread calls ProcessWasFinished() + that sends kCloseMessage message to CProgressDialog (GUI) thread + 2) CProgressDialog (GUI) thread receives kCloseMessage message and + calls ProcessWasFinished_GuiVirt(); + So we can implement ProcessWasFinished_GuiVirt() and show special + results window in GUI thread with CProgressDialog as parent window + */ + + void ProcessWasFinished(); + virtual void ProcessWasFinished_GuiVirt() {} +}; + + +class CProgressCloser +{ + CProgressDialog *_p; +public: + CProgressCloser(CProgressDialog &p) : _p(&p) {} + ~CProgressCloser() { _p->ProcessWasFinished(); } +}; + + +class CProgressThreadVirt: public CProgressDialog +{ +protected: + FStringVector ErrorPaths; + CProgressFinalMessage FinalMessage; + + // error if any of HRESULT, ErrorMessage, ErrorPath + virtual HRESULT ProcessVirt() = 0; +public: + HRESULT Result; + bool ThreadFinishedOK; // if there is no fatal exception + + void Process(); + void AddErrorPath(const FString &path) { ErrorPaths.Add(path); } + + HRESULT Create(const UString &title, HWND parentWindow = NULL); + CProgressThreadVirt(): Result(E_FAIL), ThreadFinishedOK(false) {} + + CProgressMessageBoxPair &GetMessagePair(bool isError) { return isError ? FinalMessage.ErrorMessage : FinalMessage.OkMessage; } +}; + +UString HResultToMessage(HRESULT errorCode); + +/* +how it works: + +client code inherits CProgressThreadVirt and calls +CProgressThreadVirt::Create() +{ + it creates new thread that calls CProgressThreadVirt::Process(); + it creates modal progress dialog window with ProgressDialog.Create() +} + +CProgressThreadVirt::Process() +{ + { + Result = ProcessVirt(); // virtual function that must implement real work + } + if (exceptions) or FinalMessage.ErrorMessage.Message + { + set message to ProgressDialog.Sync.FinalMessage.ErrorMessage.Message + } + else if (FinalMessage.OkMessage.Message) + { + set message to ProgressDialog.Sync.FinalMessage.OkMessage + } + + PostMsg(kCloseMessage); +} + + +CProgressDialog::OnExternalCloseMessage() +{ + if (ProgressDialog.Sync.FinalMessage) + { + WorkWasFinishedVirt(); + Show (ProgressDialog.Sync.FinalMessage) + MessagesDisplayed = true; + } +} + +*/ + +#endif diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.rc b/CPP/7zip/UI/FileManager/ProgressDialog2.rc index 535a00817..4d0e0c7bf 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.rc +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.rc @@ -1,40 +1,40 @@ -#include "ProgressDialog2Res.h" -#include "../../GuiCommon.rc" - -#undef DIALOG_ID -#define DIALOG_ID IDD_PROGRESS -#define xc 360 -#define k 11 -#define z1s 16 - -#include "ProgressDialog2a.rc" - -#ifdef UNDER_CE - -#include "../../GuiCommon.rc" - - -#undef DIALOG_ID -#undef m -#undef k -#undef z1s - -#define DIALOG_ID IDD_PROGRESS_2 -#define m 4 -#define k 8 -#define z1s 12 - -#define xc 280 - -#include "ProgressDialog2a.rc" - -#endif - -STRINGTABLE DISCARDABLE -{ - IDS_PROGRESS_PAUSED "Paused" - IDS_PROGRESS_FOREGROUND "&Foreground" - IDS_CONTINUE "&Continue" - IDS_PROGRESS_ASK_CANCEL "Are you sure you want to cancel?" - IDS_CLOSE "&Close" -} +#include "ProgressDialog2Res.h" +#include "../../GuiCommon.rc" + +#undef DIALOG_ID +#define DIALOG_ID IDD_PROGRESS +#define xc 360 +#define k 11 +#define z1s 16 + +#include "ProgressDialog2a.rc" + +#ifdef UNDER_CE + +#include "../../GuiCommon.rc" + + +#undef DIALOG_ID +#undef m +#undef k +#undef z1s + +#define DIALOG_ID IDD_PROGRESS_2 +#define m 4 +#define k 8 +#define z1s 12 + +#define xc 280 + +#include "ProgressDialog2a.rc" + +#endif + +STRINGTABLE DISCARDABLE +{ + IDS_PROGRESS_PAUSED "Paused" + IDS_PROGRESS_FOREGROUND "&Foreground" + IDS_CONTINUE "&Continue" + IDS_PROGRESS_ASK_CANCEL "Are you sure you want to cancel?" + IDS_CLOSE "&Close" +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2Res.h b/CPP/7zip/UI/FileManager/ProgressDialog2Res.h index c5440dd5a..736c7179a 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2Res.h +++ b/CPP/7zip/UI/FileManager/ProgressDialog2Res.h @@ -1,49 +1,49 @@ -#define IDD_PROGRESS 97 -#define IDD_PROGRESS_2 10097 - -#define IDS_CLOSE 408 -#define IDS_CONTINUE 411 - -#define IDB_PROGRESS_BACKGROUND 444 -#define IDS_PROGRESS_FOREGROUND 445 -#define IDB_PAUSE 446 -#define IDS_PROGRESS_PAUSED 447 -#define IDS_PROGRESS_ASK_CANCEL 448 - -#define IDT_PROGRESS_PACKED 1008 -#define IDT_PROGRESS_FILES 1032 - -#define IDT_PROGRESS_ELAPSED 3900 -#define IDT_PROGRESS_REMAINING 3901 -#define IDT_PROGRESS_TOTAL 3902 -#define IDT_PROGRESS_SPEED 3903 -#define IDT_PROGRESS_PROCESSED 3904 -#define IDT_PROGRESS_RATIO 3905 -#define IDT_PROGRESS_ERRORS 3906 - -#define IDC_PROGRESS1 100 -#define IDL_PROGRESS_MESSAGES 101 -#define IDT_PROGRESS_FILE_NAME 102 -#define IDT_PROGRESS_STATUS 103 - -#define IDT_PROGRESS_PACKED_VAL 110 -#define IDT_PROGRESS_FILES_VAL 111 -#define IDT_PROGRESS_FILES_TOTAL 112 - -#define IDT_PROGRESS_ELAPSED_VAL 120 -#define IDT_PROGRESS_REMAINING_VAL 121 -#define IDT_PROGRESS_TOTAL_VAL 122 -#define IDT_PROGRESS_SPEED_VAL 123 -#define IDT_PROGRESS_PROCESSED_VAL 124 -#define IDT_PROGRESS_RATIO_VAL 125 -#define IDT_PROGRESS_ERRORS_VAL 126 - - -#ifdef UNDER_CE -#define MY_PROGRESS_VAL_UNITS 44 -#else -#define MY_PROGRESS_VAL_UNITS 72 -#endif -#define MY_PROGRESS_LABEL_UNITS_MIN 60 -#define MY_PROGRESS_LABEL_UNITS_START 90 -#define MY_PROGRESS_PAD_UNITS 4 +#define IDD_PROGRESS 97 +#define IDD_PROGRESS_2 10097 + +#define IDS_CLOSE 408 +#define IDS_CONTINUE 411 + +#define IDB_PROGRESS_BACKGROUND 444 +#define IDS_PROGRESS_FOREGROUND 445 +#define IDB_PAUSE 446 +#define IDS_PROGRESS_PAUSED 447 +#define IDS_PROGRESS_ASK_CANCEL 448 + +#define IDT_PROGRESS_PACKED 1008 +#define IDT_PROGRESS_FILES 1032 + +#define IDT_PROGRESS_ELAPSED 3900 +#define IDT_PROGRESS_REMAINING 3901 +#define IDT_PROGRESS_TOTAL 3902 +#define IDT_PROGRESS_SPEED 3903 +#define IDT_PROGRESS_PROCESSED 3904 +#define IDT_PROGRESS_RATIO 3905 +#define IDT_PROGRESS_ERRORS 3906 + +#define IDC_PROGRESS1 100 +#define IDL_PROGRESS_MESSAGES 101 +#define IDT_PROGRESS_FILE_NAME 102 +#define IDT_PROGRESS_STATUS 103 + +#define IDT_PROGRESS_PACKED_VAL 110 +#define IDT_PROGRESS_FILES_VAL 111 +#define IDT_PROGRESS_FILES_TOTAL 112 + +#define IDT_PROGRESS_ELAPSED_VAL 120 +#define IDT_PROGRESS_REMAINING_VAL 121 +#define IDT_PROGRESS_TOTAL_VAL 122 +#define IDT_PROGRESS_SPEED_VAL 123 +#define IDT_PROGRESS_PROCESSED_VAL 124 +#define IDT_PROGRESS_RATIO_VAL 125 +#define IDT_PROGRESS_ERRORS_VAL 126 + + +#ifdef UNDER_CE +#define MY_PROGRESS_VAL_UNITS 44 +#else +#define MY_PROGRESS_VAL_UNITS 72 +#endif +#define MY_PROGRESS_LABEL_UNITS_MIN 60 +#define MY_PROGRESS_LABEL_UNITS_START 90 +#define MY_PROGRESS_PAD_UNITS 4 diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc index 703038a13..dc7d797ff 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc +++ b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc @@ -1,85 +1,85 @@ -#undef bxs -#define bxs 80 - -#define x0s MY_PROGRESS_LABEL_UNITS_START -#define x1s MY_PROGRESS_VAL_UNITS -#define x2s MY_PROGRESS_LABEL_UNITS_START -#define x3s MY_PROGRESS_VAL_UNITS - -#define x1 (m + x0s) -#define x3 (xs - m - x3s) -#define x2 (x3 - x2s) - -#undef y0 -#undef y1 -#undef y2 -#undef y3 -#undef y4 - -#undef z0 -#undef z1 -#undef z2 -#undef z3 - -#define y0 m -#define y1 (y0 + k) -#define y2 (y1 + k) -#define y3 (y2 + k) -#define y4 (y3 + k) - -#define z3 (y4 + k + 1) - -#define z2 (z3 + k + 1) -#define z2s 24 - -#define z1 (z2 + z2s) - -#define z0 (z1 + z1s + m) -#define z0s 48 - -#define yc (z0 + z0s + bys) - - -DIALOG_ID DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Progress" -{ - DEFPUSHBUTTON "&Background", IDB_PROGRESS_BACKGROUND, bx3, by, bxs, bys - PUSHBUTTON "&Pause", IDB_PAUSE, bx2, by, bxs, bys - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys - - - LTEXT "Elapsed time:", IDT_PROGRESS_ELAPSED, m, y0, x0s, 8 - LTEXT "Remaining time:", IDT_PROGRESS_REMAINING, m, y1, x0s, 8 - LTEXT "Files:", IDT_PROGRESS_FILES, m, y2, x0s, 8 - - LTEXT "Errors:", IDT_PROGRESS_ERRORS, m, y4, x0s, 8 - - - LTEXT "Total size:", IDT_PROGRESS_TOTAL, x2, y0, x2s, 8 - LTEXT "Speed:", IDT_PROGRESS_SPEED, x2, y1, x2s, 8 - LTEXT "Processed:", IDT_PROGRESS_PROCESSED,x2, y2, x2s, 8 - LTEXT "Compressed size:" , IDT_PROGRESS_PACKED, x2, y3, x2s, 8 - LTEXT "Compression ratio:", IDT_PROGRESS_RATIO, x2, y4, x2s, 8 - - - RTEXT "", IDT_PROGRESS_ELAPSED_VAL, x1, y0, x1s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_REMAINING_VAL, x1, y1, x1s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_FILES_VAL, x1, y2, x1s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_FILES_TOTAL, x1, y3, x1s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_ERRORS_VAL, x1, y4, x1s, MY_TEXT_NOPREFIX - - RTEXT "", IDT_PROGRESS_TOTAL_VAL, x3, y0, x3s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_SPEED_VAL, x3, y1, x3s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_PROCESSED_VAL, x3, y2, x3s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_PACKED_VAL, x3, y3, x3s, MY_TEXT_NOPREFIX - RTEXT "", IDT_PROGRESS_RATIO_VAL, x3, y4, x3s, MY_TEXT_NOPREFIX - - LTEXT "", IDT_PROGRESS_STATUS, m, z3, xc, MY_TEXT_NOPREFIX - CONTROL "", IDT_PROGRESS_FILE_NAME, "Static", SS_NOPREFIX | SS_LEFTNOWORDWRAP, m, z2, xc, z2s - - CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, z1, xc, z1s - - CONTROL "List1", IDL_PROGRESS_MESSAGES, "SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, - m, z0, xc, z0s -} +#undef bxs +#define bxs 80 + +#define x0s MY_PROGRESS_LABEL_UNITS_START +#define x1s MY_PROGRESS_VAL_UNITS +#define x2s MY_PROGRESS_LABEL_UNITS_START +#define x3s MY_PROGRESS_VAL_UNITS + +#define x1 (m + x0s) +#define x3 (xs - m - x3s) +#define x2 (x3 - x2s) + +#undef y0 +#undef y1 +#undef y2 +#undef y3 +#undef y4 + +#undef z0 +#undef z1 +#undef z2 +#undef z3 + +#define y0 m +#define y1 (y0 + k) +#define y2 (y1 + k) +#define y3 (y2 + k) +#define y4 (y3 + k) + +#define z3 (y4 + k + 1) + +#define z2 (z3 + k + 1) +#define z2s 24 + +#define z1 (z2 + z2s) + +#define z0 (z1 + z1s + m) +#define z0s 48 + +#define yc (z0 + z0s + bys) + + +DIALOG_ID DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Progress" +{ + DEFPUSHBUTTON "&Background", IDB_PROGRESS_BACKGROUND, bx3, by, bxs, bys + PUSHBUTTON "&Pause", IDB_PAUSE, bx2, by, bxs, bys + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys + + + LTEXT "Elapsed time:", IDT_PROGRESS_ELAPSED, m, y0, x0s, 8 + LTEXT "Remaining time:", IDT_PROGRESS_REMAINING, m, y1, x0s, 8 + LTEXT "Files:", IDT_PROGRESS_FILES, m, y2, x0s, 8 + + LTEXT "Errors:", IDT_PROGRESS_ERRORS, m, y4, x0s, 8 + + + LTEXT "Total size:", IDT_PROGRESS_TOTAL, x2, y0, x2s, 8 + LTEXT "Speed:", IDT_PROGRESS_SPEED, x2, y1, x2s, 8 + LTEXT "Processed:", IDT_PROGRESS_PROCESSED,x2, y2, x2s, 8 + LTEXT "Compressed size:" , IDT_PROGRESS_PACKED, x2, y3, x2s, 8 + LTEXT "Compression ratio:", IDT_PROGRESS_RATIO, x2, y4, x2s, 8 + + + RTEXT "", IDT_PROGRESS_ELAPSED_VAL, x1, y0, x1s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_REMAINING_VAL, x1, y1, x1s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_FILES_VAL, x1, y2, x1s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_FILES_TOTAL, x1, y3, x1s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_ERRORS_VAL, x1, y4, x1s, MY_TEXT_NOPREFIX + + RTEXT "", IDT_PROGRESS_TOTAL_VAL, x3, y0, x3s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_SPEED_VAL, x3, y1, x3s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_PROCESSED_VAL, x3, y2, x3s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_PACKED_VAL, x3, y3, x3s, MY_TEXT_NOPREFIX + RTEXT "", IDT_PROGRESS_RATIO_VAL, x3, y4, x3s, MY_TEXT_NOPREFIX + + LTEXT "", IDT_PROGRESS_STATUS, m, z3, xc, MY_TEXT_NOPREFIX + CONTROL "", IDT_PROGRESS_FILE_NAME, "Static", SS_NOPREFIX | SS_LEFTNOWORDWRAP, m, z2, xc, z2s + + CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, z1, xc, z1s + + CONTROL "List1", IDL_PROGRESS_MESSAGES, "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, + m, z0, xc, z0s +} diff --git a/CPP/7zip/UI/FileManager/ProgressDialogRes.h b/CPP/7zip/UI/FileManager/ProgressDialogRes.h index a2814188a..cbf3beb21 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialogRes.h +++ b/CPP/7zip/UI/FileManager/ProgressDialogRes.h @@ -1,3 +1,3 @@ -#define IDD_PROGRESS 97 - -#define IDC_PROGRESS1 100 +#define IDD_PROGRESS 97 + +#define IDC_PROGRESS1 100 diff --git a/CPP/7zip/UI/FileManager/PropertyName.cpp b/CPP/7zip/UI/FileManager/PropertyName.cpp index a9552415f..838b6e3f6 100644 --- a/CPP/7zip/UI/FileManager/PropertyName.cpp +++ b/CPP/7zip/UI/FileManager/PropertyName.cpp @@ -1,23 +1,23 @@ -// PropertyName.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "LangUtils.h" -#include "PropertyName.h" - -UString GetNameOfProperty(PROPID propID, const wchar_t *name) -{ - if (propID < 1000) - { - UString s = LangString(1000 + propID); - if (!s.IsEmpty()) - return s; - } - if (name) - return name; - wchar_t temp[16]; - ConvertUInt32ToString(propID, temp); - return temp; -} +// PropertyName.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "LangUtils.h" +#include "PropertyName.h" + +UString GetNameOfProperty(PROPID propID, const wchar_t *name) +{ + if (propID < 1000) + { + UString s = LangString(1000 + propID); + if (!s.IsEmpty()) + return s; + } + if (name) + return name; + wchar_t temp[16]; + ConvertUInt32ToString(propID, temp); + return temp; +} diff --git a/CPP/7zip/UI/FileManager/PropertyName.h b/CPP/7zip/UI/FileManager/PropertyName.h index 9c3415799..fa6e5c540 100644 --- a/CPP/7zip/UI/FileManager/PropertyName.h +++ b/CPP/7zip/UI/FileManager/PropertyName.h @@ -1,10 +1,10 @@ -// PropertyName.h - -#ifndef ZIP7_INC_PROPERTY_NAME_H -#define ZIP7_INC_PROPERTY_NAME_H - -#include "../../../Common/MyString.h" - -UString GetNameOfProperty(PROPID propID, const wchar_t *name); - -#endif +// PropertyName.h + +#ifndef ZIP7_INC_PROPERTY_NAME_H +#define ZIP7_INC_PROPERTY_NAME_H + +#include "../../../Common/MyString.h" + +UString GetNameOfProperty(PROPID propID, const wchar_t *name); + +#endif diff --git a/CPP/7zip/UI/FileManager/PropertyName.rc b/CPP/7zip/UI/FileManager/PropertyName.rc index 1c6ae42ec..618875bf4 100644 --- a/CPP/7zip/UI/FileManager/PropertyName.rc +++ b/CPP/7zip/UI/FileManager/PropertyName.rc @@ -1,109 +1,109 @@ -#include "PropertyNameRes.h" - -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -STRINGTABLE -BEGIN - IDS_PROP_PATH "Path" - IDS_PROP_NAME "Name" - IDS_PROP_EXTENSION "Extension" - IDS_PROP_IS_FOLDER "Folder" - IDS_PROP_SIZE "Size" - IDS_PROP_PACKED_SIZE "Packed Size" - IDS_PROP_ATTRIBUTES "Attributes" - IDS_PROP_CTIME "Created" - IDS_PROP_ATIME "Accessed" - IDS_PROP_MTIME "Modified" - IDS_PROP_SOLID "Solid" - IDS_PROP_C0MMENTED "Commented" - IDS_PROP_ENCRYPTED "Encrypted" - IDS_PROP_SPLIT_BEFORE "Split Before" - IDS_PROP_SPLIT_AFTER "Split After" - IDS_PROP_DICTIONARY_SIZE "Dictionary" - IDS_PROP_CRC "CRC" - IDS_PROP_FILE_TYPE "Type" - IDS_PROP_ANTI "Anti" - IDS_PROP_METHOD "Method" - IDS_PROP_HOST_OS "Host OS" - IDS_PROP_FILE_SYSTEM "File System" - IDS_PROP_USER "User" - IDS_PROP_GROUP "Group" - IDS_PROP_BLOCK "Block" - IDS_PROP_COMMENT "Comment" - IDS_PROP_POSITION "Position" - IDS_PROP_PREFIX "Path Prefix" - IDS_PROP_FOLDERS "Folders" - IDS_PROP_FILES "Files" - IDS_PROP_VERSION "Version" - IDS_PROP_VOLUME "Volume" - IDS_PROP_IS_VOLUME "Multivolume" - IDS_PROP_OFFSET "Offset" - IDS_PROP_LINKS "Links" - IDS_PROP_NUM_BLOCKS "Blocks" - IDS_PROP_NUM_VOLUMES "Volumes" - - IDS_PROP_BIT64 "64-bit" - IDS_PROP_BIG_ENDIAN "Big-endian" - IDS_PROP_CPU "CPU" - IDS_PROP_PHY_SIZE "Physical Size" - IDS_PROP_HEADERS_SIZE "Headers Size" - IDS_PROP_CHECKSUM "Checksum" - IDS_PROP_CHARACTS "Characteristics" - IDS_PROP_VA "Virtual Address" - IDS_PROP_ID "ID" - IDS_PROP_SHORT_NAME "Short Name" - IDS_PROP_CREATOR_APP "Creator Application" - IDS_PROP_SECTOR_SIZE "Sector Size" - IDS_PROP_POSIX_ATTRIB "Mode" - IDS_PROP_SYM_LINK "Symbolic Link" - IDS_PROP_ERROR "Error" - IDS_PROP_TOTAL_SIZE "Total Size" - IDS_PROP_FREE_SPACE "Free Space" - IDS_PROP_CLUSTER_SIZE "Cluster Size" - IDS_PROP_VOLUME_NAME "Label" - IDS_PROP_LOCAL_NAME "Local Name" - IDS_PROP_PROVIDER "Provider" - IDS_PROP_NT_SECURITY "NT Security" - IDS_PROP_ALT_STREAM "Alternate Stream" - IDS_PROP_AUX "Aux" - IDS_PROP_DELETED "Deleted" - IDS_PROP_IS_TREE "Is Tree" - IDS_PROP_SHA1 "SHA-1" - IDS_PROP_SHA256 "SHA-256" - IDS_PROP_ERROR_TYPE "Error Type" - IDS_PROP_NUM_ERRORS "Errors" - IDS_PROP_ERROR_FLAGS "Errors" - IDS_PROP_WARNING_FLAGS "Warnings" - IDS_PROP_WARNING "Warning" - IDS_PROP_NUM_STREAMS "Streams" - IDS_PROP_NUM_ALT_STREAMS "Alternate Streams" - IDS_PROP_ALT_STREAMS_SIZE "Alternate Streams Size" - IDS_PROP_VIRTUAL_SIZE "Virtual Size" - IDS_PROP_UNPACK_SIZE "Unpack Size" - IDS_PROP_TOTAL_PHY_SIZE "Total Physical Size" - IDS_PROP_VOLUME_INDEX "Volume Index" - IDS_PROP_SUBTYPE "SubType" - IDS_PROP_SHORT_COMMENT "Short Comment" - IDS_PROP_CODE_PAGE "Code Page" - IDS_PROP_IS_NOT_ARC_TYPE "Is not archive type" - IDS_PROP_PHY_SIZE_CANT_BE_DETECTED "Physical Size can't be detected" - IDS_PROP_ZEROS_TAIL_IS_ALLOWED "Zeros Tail Is Allowed" - IDS_PROP_TAIL_SIZE "Tail Size" - IDS_PROP_EMB_STUB_SIZE "Embedded Stub Size" - IDS_PROP_NT_REPARSE "Link" - IDS_PROP_HARD_LINK "Hard Link" - IDS_PROP_INODE "iNode" - IDS_PROP_STREAM_ID "Stream ID" - IDS_PROP_READ_ONLY "Read-only" - IDS_PROP_OUT_NAME "Out Name" - IDS_PROP_COPY_LINK "Copy Link" - IDS_PROP_ARC_FILE_NAME "ArcFileName" - IDS_PROP_IS_HASH "IsHash" - IDS_PROP_CHANGE_TIME "Metadata Changed" - IDS_PROP_USER_ID "User ID" - IDS_PROP_GROUP_ID "Group ID" - IDS_PROP_DEVICE_MAJOR "Device Major" - IDS_PROP_DEVICE_MINOR "Device Minor" - IDS_PROP_DEV_MAJOR "Dev Major" - IDS_PROP_DEV_MINOR "Dev Minor" -END +#include "PropertyNameRes.h" + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE +BEGIN + IDS_PROP_PATH "Path" + IDS_PROP_NAME "Name" + IDS_PROP_EXTENSION "Extension" + IDS_PROP_IS_FOLDER "Folder" + IDS_PROP_SIZE "Size" + IDS_PROP_PACKED_SIZE "Packed Size" + IDS_PROP_ATTRIBUTES "Attributes" + IDS_PROP_CTIME "Created" + IDS_PROP_ATIME "Accessed" + IDS_PROP_MTIME "Modified" + IDS_PROP_SOLID "Solid" + IDS_PROP_C0MMENTED "Commented" + IDS_PROP_ENCRYPTED "Encrypted" + IDS_PROP_SPLIT_BEFORE "Split Before" + IDS_PROP_SPLIT_AFTER "Split After" + IDS_PROP_DICTIONARY_SIZE "Dictionary" + IDS_PROP_CRC "CRC" + IDS_PROP_FILE_TYPE "Type" + IDS_PROP_ANTI "Anti" + IDS_PROP_METHOD "Method" + IDS_PROP_HOST_OS "Host OS" + IDS_PROP_FILE_SYSTEM "File System" + IDS_PROP_USER "User" + IDS_PROP_GROUP "Group" + IDS_PROP_BLOCK "Block" + IDS_PROP_COMMENT "Comment" + IDS_PROP_POSITION "Position" + IDS_PROP_PREFIX "Path Prefix" + IDS_PROP_FOLDERS "Folders" + IDS_PROP_FILES "Files" + IDS_PROP_VERSION "Version" + IDS_PROP_VOLUME "Volume" + IDS_PROP_IS_VOLUME "Multivolume" + IDS_PROP_OFFSET "Offset" + IDS_PROP_LINKS "Links" + IDS_PROP_NUM_BLOCKS "Blocks" + IDS_PROP_NUM_VOLUMES "Volumes" + + IDS_PROP_BIT64 "64-bit" + IDS_PROP_BIG_ENDIAN "Big-endian" + IDS_PROP_CPU "CPU" + IDS_PROP_PHY_SIZE "Physical Size" + IDS_PROP_HEADERS_SIZE "Headers Size" + IDS_PROP_CHECKSUM "Checksum" + IDS_PROP_CHARACTS "Characteristics" + IDS_PROP_VA "Virtual Address" + IDS_PROP_ID "ID" + IDS_PROP_SHORT_NAME "Short Name" + IDS_PROP_CREATOR_APP "Creator Application" + IDS_PROP_SECTOR_SIZE "Sector Size" + IDS_PROP_POSIX_ATTRIB "Mode" + IDS_PROP_SYM_LINK "Symbolic Link" + IDS_PROP_ERROR "Error" + IDS_PROP_TOTAL_SIZE "Total Size" + IDS_PROP_FREE_SPACE "Free Space" + IDS_PROP_CLUSTER_SIZE "Cluster Size" + IDS_PROP_VOLUME_NAME "Label" + IDS_PROP_LOCAL_NAME "Local Name" + IDS_PROP_PROVIDER "Provider" + IDS_PROP_NT_SECURITY "NT Security" + IDS_PROP_ALT_STREAM "Alternate Stream" + IDS_PROP_AUX "Aux" + IDS_PROP_DELETED "Deleted" + IDS_PROP_IS_TREE "Is Tree" + IDS_PROP_SHA1 "SHA-1" + IDS_PROP_SHA256 "SHA-256" + IDS_PROP_ERROR_TYPE "Error Type" + IDS_PROP_NUM_ERRORS "Errors" + IDS_PROP_ERROR_FLAGS "Errors" + IDS_PROP_WARNING_FLAGS "Warnings" + IDS_PROP_WARNING "Warning" + IDS_PROP_NUM_STREAMS "Streams" + IDS_PROP_NUM_ALT_STREAMS "Alternate Streams" + IDS_PROP_ALT_STREAMS_SIZE "Alternate Streams Size" + IDS_PROP_VIRTUAL_SIZE "Virtual Size" + IDS_PROP_UNPACK_SIZE "Unpack Size" + IDS_PROP_TOTAL_PHY_SIZE "Total Physical Size" + IDS_PROP_VOLUME_INDEX "Volume Index" + IDS_PROP_SUBTYPE "SubType" + IDS_PROP_SHORT_COMMENT "Short Comment" + IDS_PROP_CODE_PAGE "Code Page" + IDS_PROP_IS_NOT_ARC_TYPE "Is not archive type" + IDS_PROP_PHY_SIZE_CANT_BE_DETECTED "Physical Size can't be detected" + IDS_PROP_ZEROS_TAIL_IS_ALLOWED "Zeros Tail Is Allowed" + IDS_PROP_TAIL_SIZE "Tail Size" + IDS_PROP_EMB_STUB_SIZE "Embedded Stub Size" + IDS_PROP_NT_REPARSE "Link" + IDS_PROP_HARD_LINK "Hard Link" + IDS_PROP_INODE "iNode" + IDS_PROP_STREAM_ID "Stream ID" + IDS_PROP_READ_ONLY "Read-only" + IDS_PROP_OUT_NAME "Out Name" + IDS_PROP_COPY_LINK "Copy Link" + IDS_PROP_ARC_FILE_NAME "ArcFileName" + IDS_PROP_IS_HASH "IsHash" + IDS_PROP_CHANGE_TIME "Metadata Changed" + IDS_PROP_USER_ID "User ID" + IDS_PROP_GROUP_ID "Group ID" + IDS_PROP_DEVICE_MAJOR "Device Major" + IDS_PROP_DEVICE_MINOR "Device Minor" + IDS_PROP_DEV_MAJOR "Dev Major" + IDS_PROP_DEV_MINOR "Dev Minor" +END diff --git a/CPP/7zip/UI/FileManager/PropertyNameRes.h b/CPP/7zip/UI/FileManager/PropertyNameRes.h index 49cd8a746..913887e4a 100644 --- a/CPP/7zip/UI/FileManager/PropertyNameRes.h +++ b/CPP/7zip/UI/FileManager/PropertyNameRes.h @@ -1,104 +1,104 @@ - - -#define IDS_PROP_PATH 1003 -#define IDS_PROP_NAME 1004 -#define IDS_PROP_EXTENSION 1005 -#define IDS_PROP_IS_FOLDER 1006 -#define IDS_PROP_SIZE 1007 -#define IDS_PROP_PACKED_SIZE 1008 -#define IDS_PROP_ATTRIBUTES 1009 -#define IDS_PROP_CTIME 1010 -#define IDS_PROP_ATIME 1011 -#define IDS_PROP_MTIME 1012 -#define IDS_PROP_SOLID 1013 -#define IDS_PROP_C0MMENTED 1014 -#define IDS_PROP_ENCRYPTED 1015 -#define IDS_PROP_SPLIT_BEFORE 1016 -#define IDS_PROP_SPLIT_AFTER 1017 -#define IDS_PROP_DICTIONARY_SIZE 1018 -#define IDS_PROP_CRC 1019 -#define IDS_PROP_FILE_TYPE 1020 -#define IDS_PROP_ANTI 1021 -#define IDS_PROP_METHOD 1022 -#define IDS_PROP_HOST_OS 1023 -#define IDS_PROP_FILE_SYSTEM 1024 -#define IDS_PROP_USER 1025 -#define IDS_PROP_GROUP 1026 -#define IDS_PROP_BLOCK 1027 -#define IDS_PROP_COMMENT 1028 -#define IDS_PROP_POSITION 1029 -#define IDS_PROP_PREFIX 1030 -#define IDS_PROP_FOLDERS 1031 -#define IDS_PROP_FILES 1032 -#define IDS_PROP_VERSION 1033 -#define IDS_PROP_VOLUME 1034 -#define IDS_PROP_IS_VOLUME 1035 -#define IDS_PROP_OFFSET 1036 -#define IDS_PROP_LINKS 1037 -#define IDS_PROP_NUM_BLOCKS 1038 -#define IDS_PROP_NUM_VOLUMES 1039 - -#define IDS_PROP_BIT64 1041 -#define IDS_PROP_BIG_ENDIAN 1042 -#define IDS_PROP_CPU 1043 -#define IDS_PROP_PHY_SIZE 1044 -#define IDS_PROP_HEADERS_SIZE 1045 -#define IDS_PROP_CHECKSUM 1046 -#define IDS_PROP_CHARACTS 1047 -#define IDS_PROP_VA 1048 -#define IDS_PROP_ID 1049 -#define IDS_PROP_SHORT_NAME 1050 -#define IDS_PROP_CREATOR_APP 1051 -#define IDS_PROP_SECTOR_SIZE 1052 -#define IDS_PROP_POSIX_ATTRIB 1053 -#define IDS_PROP_SYM_LINK 1054 -#define IDS_PROP_ERROR 1055 -#define IDS_PROP_TOTAL_SIZE 1056 -#define IDS_PROP_FREE_SPACE 1057 -#define IDS_PROP_CLUSTER_SIZE 1058 -#define IDS_PROP_VOLUME_NAME 1059 -#define IDS_PROP_LOCAL_NAME 1060 -#define IDS_PROP_PROVIDER 1061 -#define IDS_PROP_NT_SECURITY 1062 -#define IDS_PROP_ALT_STREAM 1063 -#define IDS_PROP_AUX 1064 -#define IDS_PROP_DELETED 1065 -#define IDS_PROP_IS_TREE 1066 -#define IDS_PROP_SHA1 1067 -#define IDS_PROP_SHA256 1068 -#define IDS_PROP_ERROR_TYPE 1069 -#define IDS_PROP_NUM_ERRORS 1070 -#define IDS_PROP_ERROR_FLAGS 1071 -#define IDS_PROP_WARNING_FLAGS 1072 -#define IDS_PROP_WARNING 1073 -#define IDS_PROP_NUM_STREAMS 1074 -#define IDS_PROP_NUM_ALT_STREAMS 1075 -#define IDS_PROP_ALT_STREAMS_SIZE 1076 -#define IDS_PROP_VIRTUAL_SIZE 1077 -#define IDS_PROP_UNPACK_SIZE 1078 -#define IDS_PROP_TOTAL_PHY_SIZE 1079 -#define IDS_PROP_VOLUME_INDEX 1080 -#define IDS_PROP_SUBTYPE 1081 -#define IDS_PROP_SHORT_COMMENT 1082 -#define IDS_PROP_CODE_PAGE 1083 -#define IDS_PROP_IS_NOT_ARC_TYPE 1084 -#define IDS_PROP_PHY_SIZE_CANT_BE_DETECTED 1085 -#define IDS_PROP_ZEROS_TAIL_IS_ALLOWED 1086 -#define IDS_PROP_TAIL_SIZE 1087 -#define IDS_PROP_EMB_STUB_SIZE 1088 -#define IDS_PROP_NT_REPARSE 1089 -#define IDS_PROP_HARD_LINK 1090 -#define IDS_PROP_INODE 1091 -#define IDS_PROP_STREAM_ID 1092 -#define IDS_PROP_READ_ONLY 1093 -#define IDS_PROP_OUT_NAME 1094 -#define IDS_PROP_COPY_LINK 1095 -#define IDS_PROP_ARC_FILE_NAME 1096 -#define IDS_PROP_IS_HASH 1097 -#define IDS_PROP_CHANGE_TIME 1098 -#define IDS_PROP_USER_ID 1099 -#define IDS_PROP_GROUP_ID 1100 -#define IDS_PROP_DEVICE_MAJOR 1101 -#define IDS_PROP_DEVICE_MINOR 1102 -#define IDS_PROP_DEV_MAJOR 1103 -#define IDS_PROP_DEV_MINOR 1104 + + +#define IDS_PROP_PATH 1003 +#define IDS_PROP_NAME 1004 +#define IDS_PROP_EXTENSION 1005 +#define IDS_PROP_IS_FOLDER 1006 +#define IDS_PROP_SIZE 1007 +#define IDS_PROP_PACKED_SIZE 1008 +#define IDS_PROP_ATTRIBUTES 1009 +#define IDS_PROP_CTIME 1010 +#define IDS_PROP_ATIME 1011 +#define IDS_PROP_MTIME 1012 +#define IDS_PROP_SOLID 1013 +#define IDS_PROP_C0MMENTED 1014 +#define IDS_PROP_ENCRYPTED 1015 +#define IDS_PROP_SPLIT_BEFORE 1016 +#define IDS_PROP_SPLIT_AFTER 1017 +#define IDS_PROP_DICTIONARY_SIZE 1018 +#define IDS_PROP_CRC 1019 +#define IDS_PROP_FILE_TYPE 1020 +#define IDS_PROP_ANTI 1021 +#define IDS_PROP_METHOD 1022 +#define IDS_PROP_HOST_OS 1023 +#define IDS_PROP_FILE_SYSTEM 1024 +#define IDS_PROP_USER 1025 +#define IDS_PROP_GROUP 1026 +#define IDS_PROP_BLOCK 1027 +#define IDS_PROP_COMMENT 1028 +#define IDS_PROP_POSITION 1029 +#define IDS_PROP_PREFIX 1030 +#define IDS_PROP_FOLDERS 1031 +#define IDS_PROP_FILES 1032 +#define IDS_PROP_VERSION 1033 +#define IDS_PROP_VOLUME 1034 +#define IDS_PROP_IS_VOLUME 1035 +#define IDS_PROP_OFFSET 1036 +#define IDS_PROP_LINKS 1037 +#define IDS_PROP_NUM_BLOCKS 1038 +#define IDS_PROP_NUM_VOLUMES 1039 + +#define IDS_PROP_BIT64 1041 +#define IDS_PROP_BIG_ENDIAN 1042 +#define IDS_PROP_CPU 1043 +#define IDS_PROP_PHY_SIZE 1044 +#define IDS_PROP_HEADERS_SIZE 1045 +#define IDS_PROP_CHECKSUM 1046 +#define IDS_PROP_CHARACTS 1047 +#define IDS_PROP_VA 1048 +#define IDS_PROP_ID 1049 +#define IDS_PROP_SHORT_NAME 1050 +#define IDS_PROP_CREATOR_APP 1051 +#define IDS_PROP_SECTOR_SIZE 1052 +#define IDS_PROP_POSIX_ATTRIB 1053 +#define IDS_PROP_SYM_LINK 1054 +#define IDS_PROP_ERROR 1055 +#define IDS_PROP_TOTAL_SIZE 1056 +#define IDS_PROP_FREE_SPACE 1057 +#define IDS_PROP_CLUSTER_SIZE 1058 +#define IDS_PROP_VOLUME_NAME 1059 +#define IDS_PROP_LOCAL_NAME 1060 +#define IDS_PROP_PROVIDER 1061 +#define IDS_PROP_NT_SECURITY 1062 +#define IDS_PROP_ALT_STREAM 1063 +#define IDS_PROP_AUX 1064 +#define IDS_PROP_DELETED 1065 +#define IDS_PROP_IS_TREE 1066 +#define IDS_PROP_SHA1 1067 +#define IDS_PROP_SHA256 1068 +#define IDS_PROP_ERROR_TYPE 1069 +#define IDS_PROP_NUM_ERRORS 1070 +#define IDS_PROP_ERROR_FLAGS 1071 +#define IDS_PROP_WARNING_FLAGS 1072 +#define IDS_PROP_WARNING 1073 +#define IDS_PROP_NUM_STREAMS 1074 +#define IDS_PROP_NUM_ALT_STREAMS 1075 +#define IDS_PROP_ALT_STREAMS_SIZE 1076 +#define IDS_PROP_VIRTUAL_SIZE 1077 +#define IDS_PROP_UNPACK_SIZE 1078 +#define IDS_PROP_TOTAL_PHY_SIZE 1079 +#define IDS_PROP_VOLUME_INDEX 1080 +#define IDS_PROP_SUBTYPE 1081 +#define IDS_PROP_SHORT_COMMENT 1082 +#define IDS_PROP_CODE_PAGE 1083 +#define IDS_PROP_IS_NOT_ARC_TYPE 1084 +#define IDS_PROP_PHY_SIZE_CANT_BE_DETECTED 1085 +#define IDS_PROP_ZEROS_TAIL_IS_ALLOWED 1086 +#define IDS_PROP_TAIL_SIZE 1087 +#define IDS_PROP_EMB_STUB_SIZE 1088 +#define IDS_PROP_NT_REPARSE 1089 +#define IDS_PROP_HARD_LINK 1090 +#define IDS_PROP_INODE 1091 +#define IDS_PROP_STREAM_ID 1092 +#define IDS_PROP_READ_ONLY 1093 +#define IDS_PROP_OUT_NAME 1094 +#define IDS_PROP_COPY_LINK 1095 +#define IDS_PROP_ARC_FILE_NAME 1096 +#define IDS_PROP_IS_HASH 1097 +#define IDS_PROP_CHANGE_TIME 1098 +#define IDS_PROP_USER_ID 1099 +#define IDS_PROP_GROUP_ID 1100 +#define IDS_PROP_DEVICE_MAJOR 1101 +#define IDS_PROP_DEVICE_MINOR 1102 +#define IDS_PROP_DEV_MAJOR 1103 +#define IDS_PROP_DEV_MINOR 1104 diff --git a/CPP/7zip/UI/FileManager/RegistryAssociations.cpp b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp index 8f6edc2a4..c4465da7c 100644 --- a/CPP/7zip/UI/FileManager/RegistryAssociations.cpp +++ b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp @@ -1,167 +1,167 @@ -// RegistryAssociations.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/Registry.h" - -#include "RegistryAssociations.h" - -using namespace NWindows; -using namespace NRegistry; - -namespace NRegistryAssoc { - -// static NSynchronization::CCriticalSection g_CriticalSection; - -static const TCHAR * const kClasses = TEXT("Software\\Classes\\"); -// static const TCHAR * const kShellNewKeyName = TEXT("ShellNew"); -// static const TCHAR * const kShellNewDataValueName = TEXT("Data"); -static const TCHAR * const kDefaultIconKeyName = TEXT("DefaultIcon"); -static const TCHAR * const kShellKeyName = TEXT("shell"); -static const TCHAR * const kOpenKeyName = TEXT("open"); -static const TCHAR * const kCommandKeyName = TEXT("command"); -static const char * const k7zipPrefix = "7-Zip."; - -static CSysString GetExtProgramKeyName(const CSysString &ext) -{ - return CSysString(k7zipPrefix) + ext; -} - -static CSysString GetFullKeyPath(HKEY hkey, const CSysString &name) -{ - CSysString s; - if (hkey != HKEY_CLASSES_ROOT) - s = kClasses; - return s + name; -} - -static CSysString GetExtKeyPath(HKEY hkey, const CSysString &ext) -{ - return GetFullKeyPath(hkey, (TEXT(".")) + ext); -} - -bool CShellExtInfo::ReadFromRegistry(HKEY hkey, const CSysString &ext) -{ - ProgramKey.Empty(); - IconPath.Empty(); - IconIndex = -1; - // NSynchronization::CCriticalSectionLock lock(g_CriticalSection); - { - CKey extKey; - if (extKey.Open(hkey, GetExtKeyPath(hkey, ext), KEY_READ) != ERROR_SUCCESS) - return false; - if (extKey.QueryValue(NULL, ProgramKey) != ERROR_SUCCESS) - return false; - } - { - CKey iconKey; - - if (iconKey.Open(hkey, GetFullKeyPath(hkey, ProgramKey + CSysString(CHAR_PATH_SEPARATOR) + kDefaultIconKeyName), KEY_READ) == ERROR_SUCCESS) - { - UString value; - if (iconKey.QueryValue(NULL, value) == ERROR_SUCCESS) - { - const int pos = value.ReverseFind(L','); - IconPath = value; - if (pos >= 0) - { - const wchar_t *end; - const Int32 index = ConvertStringToInt32((const wchar_t *)value + pos + 1, &end); - if (*end == 0) - { - // 9.31: if there is no icon index, we use -1. Is it OK? - if (pos != (int)value.Len() - 1) - IconIndex = (int)index; - IconPath.SetFrom(value, (unsigned)pos); - } - } - } - } - } - return true; -} - -bool CShellExtInfo::IsIt7Zip() const -{ - return ProgramKey.IsPrefixedBy_Ascii_NoCase(k7zipPrefix); -} - -LONG DeleteShellExtensionInfo(HKEY hkey, const CSysString &ext) -{ - // NSynchronization::CCriticalSectionLock lock(g_CriticalSection); - CKey rootKey; - rootKey.Attach(hkey); - LONG res = rootKey.RecurseDeleteKey(GetExtKeyPath(hkey, ext)); - // then we delete only 7-Zip.* key. - rootKey.RecurseDeleteKey(GetFullKeyPath(hkey, GetExtProgramKeyName(ext))); - rootKey.Detach(); - return res; -} - -LONG AddShellExtensionInfo(HKEY hkey, - const CSysString &ext, - const UString &programTitle, - const UString &programOpenCommand, - const UString &iconPath, int iconIndex - // , const void *shellNewData, int shellNewDataSize - ) -{ - LONG res = 0; - DeleteShellExtensionInfo(hkey, ext); - // NSynchronization::CCriticalSectionLock lock(g_CriticalSection); - CSysString programKeyName; - { - CSysString ext2 (ext); - if (iconIndex < 0) - ext2 = "*"; - programKeyName = GetExtProgramKeyName(ext2); - } - { - CKey extKey; - res = extKey.Create(hkey, GetExtKeyPath(hkey, ext)); - extKey.SetValue(NULL, programKeyName); - /* - if (shellNewData != NULL) - { - CKey shellNewKey; - shellNewKey.Create(extKey, kShellNewKeyName); - shellNewKey.SetValue(kShellNewDataValueName, shellNewData, shellNewDataSize); - } - */ - } - CKey programKey; - programKey.Create(hkey, GetFullKeyPath(hkey, programKeyName)); - programKey.SetValue(NULL, programTitle); - { - CKey iconKey; - UString iconPathFull = iconPath; - if (iconIndex < 0) - iconIndex = 0; - // if (iconIndex >= 0) - { - iconPathFull.Add_Char(','); - iconPathFull.Add_UInt32((UInt32)iconIndex); - } - iconKey.Create(programKey, kDefaultIconKeyName); - iconKey.SetValue(NULL, iconPathFull); - } - - CKey shellKey; - shellKey.Create(programKey, kShellKeyName); - shellKey.SetValue(NULL, TEXT("")); - - CKey openKey; - openKey.Create(shellKey, kOpenKeyName); - openKey.SetValue(NULL, TEXT("")); - - CKey commandKey; - commandKey.Create(openKey, kCommandKeyName); - commandKey.SetValue(NULL, programOpenCommand); - return res; -} - -} +// RegistryAssociations.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/Registry.h" + +#include "RegistryAssociations.h" + +using namespace NWindows; +using namespace NRegistry; + +namespace NRegistryAssoc { + +// static NSynchronization::CCriticalSection g_CriticalSection; + +static const TCHAR * const kClasses = TEXT("Software\\Classes\\"); +// static const TCHAR * const kShellNewKeyName = TEXT("ShellNew"); +// static const TCHAR * const kShellNewDataValueName = TEXT("Data"); +static const TCHAR * const kDefaultIconKeyName = TEXT("DefaultIcon"); +static const TCHAR * const kShellKeyName = TEXT("shell"); +static const TCHAR * const kOpenKeyName = TEXT("open"); +static const TCHAR * const kCommandKeyName = TEXT("command"); +static const char * const k7zipPrefix = "7-Zip."; + +static CSysString GetExtProgramKeyName(const CSysString &ext) +{ + return CSysString(k7zipPrefix) + ext; +} + +static CSysString GetFullKeyPath(HKEY hkey, const CSysString &name) +{ + CSysString s; + if (hkey != HKEY_CLASSES_ROOT) + s = kClasses; + return s + name; +} + +static CSysString GetExtKeyPath(HKEY hkey, const CSysString &ext) +{ + return GetFullKeyPath(hkey, (TEXT(".")) + ext); +} + +bool CShellExtInfo::ReadFromRegistry(HKEY hkey, const CSysString &ext) +{ + ProgramKey.Empty(); + IconPath.Empty(); + IconIndex = -1; + // NSynchronization::CCriticalSectionLock lock(g_CriticalSection); + { + CKey extKey; + if (extKey.Open(hkey, GetExtKeyPath(hkey, ext), KEY_READ) != ERROR_SUCCESS) + return false; + if (extKey.QueryValue(NULL, ProgramKey) != ERROR_SUCCESS) + return false; + } + { + CKey iconKey; + + if (iconKey.Open(hkey, GetFullKeyPath(hkey, ProgramKey + CSysString(CHAR_PATH_SEPARATOR) + kDefaultIconKeyName), KEY_READ) == ERROR_SUCCESS) + { + UString value; + if (iconKey.QueryValue(NULL, value) == ERROR_SUCCESS) + { + const int pos = value.ReverseFind(L','); + IconPath = value; + if (pos >= 0) + { + const wchar_t *end; + const Int32 index = ConvertStringToInt32((const wchar_t *)value + pos + 1, &end); + if (*end == 0) + { + // 9.31: if there is no icon index, we use -1. Is it OK? + if (pos != (int)value.Len() - 1) + IconIndex = (int)index; + IconPath.SetFrom(value, (unsigned)pos); + } + } + } + } + } + return true; +} + +bool CShellExtInfo::IsIt7Zip() const +{ + return ProgramKey.IsPrefixedBy_Ascii_NoCase(k7zipPrefix); +} + +LONG DeleteShellExtensionInfo(HKEY hkey, const CSysString &ext) +{ + // NSynchronization::CCriticalSectionLock lock(g_CriticalSection); + CKey rootKey; + rootKey.Attach(hkey); + LONG res = rootKey.RecurseDeleteKey(GetExtKeyPath(hkey, ext)); + // then we delete only 7-Zip.* key. + rootKey.RecurseDeleteKey(GetFullKeyPath(hkey, GetExtProgramKeyName(ext))); + rootKey.Detach(); + return res; +} + +LONG AddShellExtensionInfo(HKEY hkey, + const CSysString &ext, + const UString &programTitle, + const UString &programOpenCommand, + const UString &iconPath, int iconIndex + // , const void *shellNewData, int shellNewDataSize + ) +{ + LONG res = 0; + DeleteShellExtensionInfo(hkey, ext); + // NSynchronization::CCriticalSectionLock lock(g_CriticalSection); + CSysString programKeyName; + { + CSysString ext2 (ext); + if (iconIndex < 0) + ext2 = "*"; + programKeyName = GetExtProgramKeyName(ext2); + } + { + CKey extKey; + res = extKey.Create(hkey, GetExtKeyPath(hkey, ext)); + extKey.SetValue(NULL, programKeyName); + /* + if (shellNewData != NULL) + { + CKey shellNewKey; + shellNewKey.Create(extKey, kShellNewKeyName); + shellNewKey.SetValue(kShellNewDataValueName, shellNewData, shellNewDataSize); + } + */ + } + CKey programKey; + programKey.Create(hkey, GetFullKeyPath(hkey, programKeyName)); + programKey.SetValue(NULL, programTitle); + { + CKey iconKey; + UString iconPathFull = iconPath; + if (iconIndex < 0) + iconIndex = 0; + // if (iconIndex >= 0) + { + iconPathFull.Add_Char(','); + iconPathFull.Add_UInt32((UInt32)iconIndex); + } + iconKey.Create(programKey, kDefaultIconKeyName); + iconKey.SetValue(NULL, iconPathFull); + } + + CKey shellKey; + shellKey.Create(programKey, kShellKeyName); + shellKey.SetValue(NULL, TEXT("")); + + CKey openKey; + openKey.Create(shellKey, kOpenKeyName); + openKey.SetValue(NULL, TEXT("")); + + CKey commandKey; + commandKey.Create(openKey, kCommandKeyName); + commandKey.SetValue(NULL, programOpenCommand); + return res; +} + +} diff --git a/CPP/7zip/UI/FileManager/RegistryAssociations.h b/CPP/7zip/UI/FileManager/RegistryAssociations.h index 2ccea83fb..3d7b63db6 100644 --- a/CPP/7zip/UI/FileManager/RegistryAssociations.h +++ b/CPP/7zip/UI/FileManager/RegistryAssociations.h @@ -1,31 +1,31 @@ -// RegistryAssociations.h - -#ifndef ZIP7_INC_REGISTRY_ASSOCIATIONS_H -#define ZIP7_INC_REGISTRY_ASSOCIATIONS_H - -#include "../../../Common/MyString.h" - -namespace NRegistryAssoc { - - struct CShellExtInfo - { - CSysString ProgramKey; - UString IconPath; - int IconIndex; - - bool ReadFromRegistry(HKEY hkey, const CSysString &ext); - bool IsIt7Zip() const; - }; - - LONG DeleteShellExtensionInfo(HKEY hkey, const CSysString &ext); - - LONG AddShellExtensionInfo(HKEY hkey, - const CSysString &ext, - const UString &programTitle, - const UString &programOpenCommand, - const UString &iconPath, int iconIndex - // , const void *shellNewData, int shellNewDataSize - ); -} - -#endif +// RegistryAssociations.h + +#ifndef ZIP7_INC_REGISTRY_ASSOCIATIONS_H +#define ZIP7_INC_REGISTRY_ASSOCIATIONS_H + +#include "../../../Common/MyString.h" + +namespace NRegistryAssoc { + + struct CShellExtInfo + { + CSysString ProgramKey; + UString IconPath; + int IconIndex; + + bool ReadFromRegistry(HKEY hkey, const CSysString &ext); + bool IsIt7Zip() const; + }; + + LONG DeleteShellExtensionInfo(HKEY hkey, const CSysString &ext); + + LONG AddShellExtensionInfo(HKEY hkey, + const CSysString &ext, + const UString &programTitle, + const UString &programOpenCommand, + const UString &iconPath, int iconIndex + // , const void *shellNewData, int shellNewDataSize + ); +} + +#endif diff --git a/CPP/7zip/UI/FileManager/RegistryPlugins.cpp b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp index 00758a951..87e5fa164 100644 --- a/CPP/7zip/UI/FileManager/RegistryPlugins.cpp +++ b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp @@ -1,145 +1,145 @@ -// RegistryPlugins.cpp - -#include "StdAfx.h" - -/* -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/PropVariant.h" - -#include "IFolder.h" -*/ -#include "RegistryPlugins.h" - -// using namespace NWindows; -// using namespace NFile; - -/* -typedef UINT32 (WINAPI * Func_GetPluginProperty)(PROPID propID, PROPVARIANT *value); - -static bool ReadPluginInfo(CPluginInfo &plugin, bool needCheckDll) -{ - if (needCheckDll) - { - NDLL::CLibrary lib; - if (!lib.LoadEx(plugin.FilePath, LOAD_LIBRARY_AS_DATAFILE)) - return false; - } - NDLL::CLibrary lib; - if (!lib.Load(plugin.FilePath)) - return false; - const - Func_GetPluginProperty - f_GetPluginProperty = ZIP7_GET_PROC_ADDRESS( - Func_GetPluginProperty, lib.Get_HMODULE(), - "GetPluginProperty"); - if (!f_GetPluginProperty) - return false; - - NCOM::CPropVariant prop; - if (f_GetPluginProperty(NPlugin::kType, &prop) != S_OK) - return false; - if (prop.vt == VT_EMPTY) - plugin.Type = kPluginTypeFF; - else if (prop.vt == VT_UI4) - plugin.Type = (EPluginType)prop.ulVal; - else - return false; - prop.Clear(); - - if (f_GetPluginProperty(NPlugin::kName, &prop) != S_OK) - return false; - if (prop.vt != VT_BSTR) - return false; - plugin.Name = prop.bstrVal; - prop.Clear(); - - if (f_GetPluginProperty(NPlugin::kClassID, &prop) != S_OK) - return false; - if (prop.vt == VT_EMPTY) - plugin.ClassID_Defined = false; - else if (prop.vt != VT_BSTR) - return false; - else - { - plugin.ClassID_Defined = true; - plugin.ClassID = *(const GUID *)(const void *)prop.bstrVal; - } - prop.Clear(); - return true; -*/ - -/* -{ - if (f_GetPluginProperty(NPlugin::kOptionsClassID, &prop) != S_OK) - return false; - if (prop.vt == VT_EMPTY) - plugin.OptionsClassID_Defined = false; - else if (prop.vt != VT_BSTR) - return false; - else - { - plugin.OptionsClassID_Defined = true; - plugin.OptionsClassID = *(const GUID *)(const void *)prop.bstrVal; - } -} -*/ - - /* - { - // very old 7-zip used agent plugin in "7-zip.dll" - // but then agent code was moved to 7zfm. - // so now we don't need to load "7-zip.dll" here - CPluginInfo plugin; - plugin.FilePath = baseFolderPrefix + FTEXT("7-zip.dll"); - if (::ReadPluginInfo(plugin, false)) - if (plugin.Type == kPluginTypeFF) - plugins.Add(plugin); - } - */ - /* - FString folderPath = NDLL::GetModuleDirPrefix(); - folderPath += "Plugins" STRING_PATH_SEPARATOR; - NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(folderPath); - NFind::CFileInfo fi; - while (enumerator.Next(fi)) - { - if (fi.IsDir()) - continue; - CPluginInfo plugin; - plugin.FilePath = folderPath + fi.Name; - if (::ReadPluginInfo(plugin, true)) - if (plugin.Type == kPluginTypeFF) - plugins.Add(plugin); - } - */ - - /* - ReadPluginInfoList(plugins); - for (unsigned i = 0; i < plugins.Size();) - if (plugins[i].Type != kPluginTypeFF) - plugins.Delete(i); - else - i++; - */ - -/* -void ReadFileFolderPluginInfoList(CObjectVector &plugins) -{ - plugins.Clear(); - { - } - - { - CPluginInfo &plugin = plugins.AddNew(); - // p.FilePath.Empty(); - plugin.Type = kPluginTypeFF; - plugin.Name = "7-Zip"; - // plugin.ClassID = CLSID_CAgentArchiveHandler; - // plugin.ClassID_Defined = true; - // plugin.ClassID_Defined = false; - // plugin.OptionsClassID_Defined = false; - } -} -*/ +// RegistryPlugins.cpp + +#include "StdAfx.h" + +/* +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/PropVariant.h" + +#include "IFolder.h" +*/ +#include "RegistryPlugins.h" + +// using namespace NWindows; +// using namespace NFile; + +/* +typedef UINT32 (WINAPI * Func_GetPluginProperty)(PROPID propID, PROPVARIANT *value); + +static bool ReadPluginInfo(CPluginInfo &plugin, bool needCheckDll) +{ + if (needCheckDll) + { + NDLL::CLibrary lib; + if (!lib.LoadEx(plugin.FilePath, LOAD_LIBRARY_AS_DATAFILE)) + return false; + } + NDLL::CLibrary lib; + if (!lib.Load(plugin.FilePath)) + return false; + const + Func_GetPluginProperty + f_GetPluginProperty = ZIP7_GET_PROC_ADDRESS( + Func_GetPluginProperty, lib.Get_HMODULE(), + "GetPluginProperty"); + if (!f_GetPluginProperty) + return false; + + NCOM::CPropVariant prop; + if (f_GetPluginProperty(NPlugin::kType, &prop) != S_OK) + return false; + if (prop.vt == VT_EMPTY) + plugin.Type = kPluginTypeFF; + else if (prop.vt == VT_UI4) + plugin.Type = (EPluginType)prop.ulVal; + else + return false; + prop.Clear(); + + if (f_GetPluginProperty(NPlugin::kName, &prop) != S_OK) + return false; + if (prop.vt != VT_BSTR) + return false; + plugin.Name = prop.bstrVal; + prop.Clear(); + + if (f_GetPluginProperty(NPlugin::kClassID, &prop) != S_OK) + return false; + if (prop.vt == VT_EMPTY) + plugin.ClassID_Defined = false; + else if (prop.vt != VT_BSTR) + return false; + else + { + plugin.ClassID_Defined = true; + plugin.ClassID = *(const GUID *)(const void *)prop.bstrVal; + } + prop.Clear(); + return true; +*/ + +/* +{ + if (f_GetPluginProperty(NPlugin::kOptionsClassID, &prop) != S_OK) + return false; + if (prop.vt == VT_EMPTY) + plugin.OptionsClassID_Defined = false; + else if (prop.vt != VT_BSTR) + return false; + else + { + plugin.OptionsClassID_Defined = true; + plugin.OptionsClassID = *(const GUID *)(const void *)prop.bstrVal; + } +} +*/ + + /* + { + // very old 7-zip used agent plugin in "7-zip.dll" + // but then agent code was moved to 7zfm. + // so now we don't need to load "7-zip.dll" here + CPluginInfo plugin; + plugin.FilePath = baseFolderPrefix + FTEXT("7-zip.dll"); + if (::ReadPluginInfo(plugin, false)) + if (plugin.Type == kPluginTypeFF) + plugins.Add(plugin); + } + */ + /* + FString folderPath = NDLL::GetModuleDirPrefix(); + folderPath += "Plugins" STRING_PATH_SEPARATOR; + NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(folderPath); + NFind::CFileInfo fi; + while (enumerator.Next(fi)) + { + if (fi.IsDir()) + continue; + CPluginInfo plugin; + plugin.FilePath = folderPath + fi.Name; + if (::ReadPluginInfo(plugin, true)) + if (plugin.Type == kPluginTypeFF) + plugins.Add(plugin); + } + */ + + /* + ReadPluginInfoList(plugins); + for (unsigned i = 0; i < plugins.Size();) + if (plugins[i].Type != kPluginTypeFF) + plugins.Delete(i); + else + i++; + */ + +/* +void ReadFileFolderPluginInfoList(CObjectVector &plugins) +{ + plugins.Clear(); + { + } + + { + CPluginInfo &plugin = plugins.AddNew(); + // p.FilePath.Empty(); + plugin.Type = kPluginTypeFF; + plugin.Name = "7-Zip"; + // plugin.ClassID = CLSID_CAgentArchiveHandler; + // plugin.ClassID_Defined = true; + // plugin.ClassID_Defined = false; + // plugin.OptionsClassID_Defined = false; + } +} +*/ diff --git a/CPP/7zip/UI/FileManager/RegistryPlugins.h b/CPP/7zip/UI/FileManager/RegistryPlugins.h index 1f969210b..1cb765a88 100644 --- a/CPP/7zip/UI/FileManager/RegistryPlugins.h +++ b/CPP/7zip/UI/FileManager/RegistryPlugins.h @@ -1,29 +1,29 @@ -// RegistryPlugins.h - -#ifndef ZIP7_INC_REGISTRY_PLUGINS_H -#define ZIP7_INC_REGISTRY_PLUGINS_H - -#include "../../../Common/MyString.h" - -/* -enum EPluginType -{ - kPluginTypeFF = 0 -}; - -struct CPluginInfo -{ - EPluginType Type; - // bool ClassID_Defined; - // bool OptionsClassID_Defined; - // FString FilePath; - // UString Name; - // CLSID ClassID; - // CLSID OptionsClassID; -}; - -// void ReadPluginInfoList(CObjectVector &plugins); -// void ReadFileFolderPluginInfoList(CObjectVector &plugins); -*/ - -#endif +// RegistryPlugins.h + +#ifndef ZIP7_INC_REGISTRY_PLUGINS_H +#define ZIP7_INC_REGISTRY_PLUGINS_H + +#include "../../../Common/MyString.h" + +/* +enum EPluginType +{ + kPluginTypeFF = 0 +}; + +struct CPluginInfo +{ + EPluginType Type; + // bool ClassID_Defined; + // bool OptionsClassID_Defined; + // FString FilePath; + // UString Name; + // CLSID ClassID; + // CLSID OptionsClassID; +}; + +// void ReadPluginInfoList(CObjectVector &plugins); +// void ReadFileFolderPluginInfoList(CObjectVector &plugins); +*/ + +#endif diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.cpp b/CPP/7zip/UI/FileManager/RegistryUtils.cpp index d9db5d04e..0284591e4 100644 --- a/CPP/7zip/UI/FileManager/RegistryUtils.cpp +++ b/CPP/7zip/UI/FileManager/RegistryUtils.cpp @@ -1,196 +1,194 @@ -// RegistryUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" - -#include "../../../Windows/Registry.h" - -#include "RegistryUtils.h" - -using namespace NWindows; -using namespace NRegistry; - -#define REG_PATH_7Z TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") - -static LPCTSTR const kCUBasePath = REG_PATH_7Z; -static LPCTSTR const kCU_FMPath = REG_PATH_7Z TEXT(STRING_PATH_SEPARATOR) TEXT("FM"); -// static LPCTSTR const kLM_Path = REG_PATH_7Z TEXT(STRING_PATH_SEPARATOR) TEXT("FM"); - -static LPCWSTR const kLangValueName = L"Lang"; - -static LPCWSTR const kViewer = L"Viewer"; -static LPCWSTR const kEditor = L"Editor"; -static LPCWSTR const kDiff = L"Diff"; -static LPCWSTR const kVerCtrlPath = L"7vc"; - -static LPCTSTR const kShowDots = TEXT("ShowDots"); -static LPCTSTR const kShowRealFileIcons = TEXT("ShowRealFileIcons"); -static LPCTSTR const kFullRow = TEXT("FullRow"); -static LPCTSTR const kShowGrid = TEXT("ShowGrid"); -static LPCTSTR const kSingleClick = TEXT("SingleClick"); -static LPCTSTR const kAlternativeSelection = TEXT("AlternativeSelection"); -// static LPCTSTR const kUnderline = TEXT("Underline"); - -static LPCTSTR const kShowSystemMenu = TEXT("ShowSystemMenu"); - -// static LPCTSTR const kLockMemoryAdd = TEXT("LockMemoryAdd"); -static LPCTSTR const kLargePages = TEXT("LargePages"); - -static LPCTSTR const kFlatViewName = TEXT("FlatViewArc"); -// static LPCTSTR const kShowDeletedFiles = TEXT("ShowDeleted"); - -static void SaveCuString(LPCTSTR keyPath, LPCWSTR valuePath, LPCWSTR value) -{ - CKey key; - key.Create(HKEY_CURRENT_USER, keyPath); - key.SetValue(valuePath, value); -} - -static void ReadCuString(LPCTSTR keyPath, LPCWSTR valuePath, UString &res) -{ - res.Empty(); - CKey key; - if (key.Open(HKEY_CURRENT_USER, keyPath, KEY_READ) == ERROR_SUCCESS) - key.QueryValue(valuePath, res); -} - -void SaveRegLang(const UString &path) { SaveCuString(kCUBasePath, kLangValueName, path); } -void ReadRegLang(UString &path) { ReadCuString(kCUBasePath, kLangValueName, path); } - -void SaveRegEditor(bool useEditor, const UString &path) { SaveCuString(kCU_FMPath, useEditor ? kEditor : kViewer, path); } -void ReadRegEditor(bool useEditor, UString &path) { ReadCuString(kCU_FMPath, useEditor ? kEditor : kViewer, path); } - -void SaveRegDiff(const UString &path) { SaveCuString(kCU_FMPath, kDiff, path); } -void ReadRegDiff(UString &path) { ReadCuString(kCU_FMPath, kDiff, path); } - -void ReadReg_VerCtrlPath(UString &path) { ReadCuString(kCU_FMPath, kVerCtrlPath, path); } - -static void Save7ZipOption(LPCTSTR value, bool enabled) -{ - CKey key; - key.Create(HKEY_CURRENT_USER, kCUBasePath); - key.SetValue(value, enabled); -} - -static void SaveOption(LPCTSTR value, bool enabled) -{ - CKey key; - key.Create(HKEY_CURRENT_USER, kCU_FMPath); - key.SetValue(value, enabled); -} - -static bool Read7ZipOption(LPCTSTR value, bool defaultValue) -{ - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS) - { - bool enabled; - if (key.QueryValue(value, enabled) == ERROR_SUCCESS) - return enabled; - } - return defaultValue; -} - -static void ReadOption(CKey &key, LPCTSTR value, bool &dest) -{ - bool enabled = false; - if (key.QueryValue(value, enabled) == ERROR_SUCCESS) - dest = enabled; -} - -/* -static void SaveLmOption(LPCTSTR value, bool enabled) -{ - CKey key; - key.Create(HKEY_LOCAL_MACHINE, kLM_Path); - key.SetValue(value, enabled); -} - -static bool ReadLmOption(LPCTSTR value, bool defaultValue) -{ - CKey key; - if (key.Open(HKEY_LOCAL_MACHINE, kLM_Path, KEY_READ) == ERROR_SUCCESS) - { - bool enabled; - if (key.QueryValue(value, enabled) == ERROR_SUCCESS) - return enabled; - } - return defaultValue; -} -*/ - -void CFmSettings::Save() const -{ - SaveOption(kShowDots, ShowDots); - SaveOption(kShowRealFileIcons, ShowRealFileIcons); - SaveOption(kFullRow, FullRow); - SaveOption(kShowGrid, ShowGrid); - SaveOption(kSingleClick, SingleClick); - SaveOption(kAlternativeSelection, AlternativeSelection); - // SaveOption(kUnderline, Underline); - - SaveOption(kShowSystemMenu, ShowSystemMenu); -} - -void CFmSettings::Load() -{ - ShowDots = false; - ShowRealFileIcons = false; - /* if (FullRow == false), we can use mouse click on another columns - to select group of files. We need to implement additional - way to select files in any column as in Explorer. - Then we can enable (FullRow == true) default mode. */ - // FullRow = true; - FullRow = false; - ShowGrid = false; - SingleClick = false; - AlternativeSelection = false; - // Underline = false; - - ShowSystemMenu = false; - - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS) - { - ReadOption(key, kShowDots, ShowDots); - ReadOption(key, kShowRealFileIcons, ShowRealFileIcons); - ReadOption(key, kFullRow, FullRow); - ReadOption(key, kShowGrid, ShowGrid); - ReadOption(key, kSingleClick, SingleClick); - ReadOption(key, kAlternativeSelection, AlternativeSelection); - // ReadOption(key, kUnderline, Underline); - - ReadOption(key, kShowSystemMenu, ShowSystemMenu ); - } -} - - -// void SaveLockMemoryAdd(bool enable) { SaveLmOption(kLockMemoryAdd, enable); } -// bool ReadLockMemoryAdd() { return ReadLmOption(kLockMemoryAdd, true); } - -void SaveLockMemoryEnable(bool enable) { Save7ZipOption(kLargePages, enable); } -bool ReadLockMemoryEnable() { return Read7ZipOption(kLargePages, false); } - -static CSysString GetFlatViewName(UInt32 panelIndex) -{ - TCHAR panelString[16]; - ConvertUInt32ToString(panelIndex, panelString); - return (CSysString)kFlatViewName + panelString; -} - -void SaveFlatView(UInt32 panelIndex, bool enable) { SaveOption(GetFlatViewName(panelIndex), enable); } - -bool ReadFlatView(UInt32 panelIndex) -{ - bool enabled = false; - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS) - ReadOption(key, GetFlatViewName(panelIndex), enabled); - return enabled; -} - -/* -void Save_ShowDeleted(bool enable) { SaveOption(kShowDeletedFiles, enable); } -bool Read_ShowDeleted() { return ReadOption(kShowDeletedFiles, false); } -*/ +// RegistryUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" + +#include "../../../Windows/Registry.h" + +#include "RegistryUtils.h" + +using namespace NWindows; +using namespace NRegistry; + +#define REG_PATH_7Z TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") + +static LPCTSTR const kCUBasePath = REG_PATH_7Z; +static LPCTSTR const kCU_FMPath = REG_PATH_7Z TEXT(STRING_PATH_SEPARATOR) TEXT("FM"); +// static LPCTSTR const kLM_Path = REG_PATH_7Z TEXT(STRING_PATH_SEPARATOR) TEXT("FM"); + +static LPCWSTR const kLangValueName = L"Lang"; + +static LPCWSTR const kViewer = L"Viewer"; +static LPCWSTR const kEditor = L"Editor"; +static LPCWSTR const kDiff = L"Diff"; +static LPCWSTR const kVerCtrlPath = L"7vc"; + +static LPCTSTR const kShowDots = TEXT("ShowDots"); +static LPCTSTR const kShowRealFileIcons = TEXT("ShowRealFileIcons"); +static LPCTSTR const kFullRow = TEXT("FullRow"); +static LPCTSTR const kShowGrid = TEXT("ShowGrid"); +static LPCTSTR const kSingleClick = TEXT("SingleClick"); +static LPCTSTR const kAlternativeSelection = TEXT("AlternativeSelection"); +// static LPCTSTR const kUnderline = TEXT("Underline"); + +static LPCTSTR const kShowSystemMenu = TEXT("ShowSystemMenu"); + +// static LPCTSTR const kLockMemoryAdd = TEXT("LockMemoryAdd"); +static LPCTSTR const kLargePages = TEXT("LargePages"); + +static LPCTSTR const kFlatViewName = TEXT("FlatViewArc"); +// static LPCTSTR const kShowDeletedFiles = TEXT("ShowDeleted"); + +static void SaveCuString(LPCTSTR keyPath, LPCWSTR valuePath, LPCWSTR value) +{ + CKey key; + key.Create(HKEY_CURRENT_USER, keyPath); + key.SetValue(valuePath, value); +} + +static void ReadCuString(LPCTSTR keyPath, LPCWSTR valuePath, UString &res) +{ + res.Empty(); + CKey key; + if (key.Open(HKEY_CURRENT_USER, keyPath, KEY_READ) == ERROR_SUCCESS) + key.QueryValue(valuePath, res); +} + +void SaveRegLang(const UString &path) { SaveCuString(kCUBasePath, kLangValueName, path); } +void ReadRegLang(UString &path) { ReadCuString(kCUBasePath, kLangValueName, path); } + +void SaveRegEditor(bool useEditor, const UString &path) { SaveCuString(kCU_FMPath, useEditor ? kEditor : kViewer, path); } +void ReadRegEditor(bool useEditor, UString &path) { ReadCuString(kCU_FMPath, useEditor ? kEditor : kViewer, path); } + +void SaveRegDiff(const UString &path) { SaveCuString(kCU_FMPath, kDiff, path); } +void ReadRegDiff(UString &path) { ReadCuString(kCU_FMPath, kDiff, path); } + +void ReadReg_VerCtrlPath(UString &path) { ReadCuString(kCU_FMPath, kVerCtrlPath, path); } + +static void Save7ZipOption(LPCTSTR value, bool enabled) +{ + CKey key; + key.Create(HKEY_CURRENT_USER, kCUBasePath); + key.SetValue(value, enabled); +} + +static void SaveOption(LPCTSTR value, bool enabled) +{ + CKey key; + key.Create(HKEY_CURRENT_USER, kCU_FMPath); + key.SetValue(value, enabled); +} + +static bool Read7ZipOption(LPCTSTR value, bool defaultValue) +{ + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS) + { + bool enabled; + if (key.GetValue_bool_IfOk(value, enabled) == ERROR_SUCCESS) + return enabled; + } + return defaultValue; +} + +static void ReadOption(CKey &key, LPCTSTR name, bool &dest) +{ + key.GetValue_bool_IfOk(name, dest); +} + +/* +static void SaveLmOption(LPCTSTR value, bool enabled) +{ + CKey key; + key.Create(HKEY_LOCAL_MACHINE, kLM_Path); + key.SetValue(value, enabled); +} + +static bool ReadLmOption(LPCTSTR value, bool defaultValue) +{ + CKey key; + if (key.Open(HKEY_LOCAL_MACHINE, kLM_Path, KEY_READ) == ERROR_SUCCESS) + { + bool enabled; + if (key.QueryValue(value, enabled) == ERROR_SUCCESS) + return enabled; + } + return defaultValue; +} +*/ + +void CFmSettings::Save() const +{ + SaveOption(kShowDots, ShowDots); + SaveOption(kShowRealFileIcons, ShowRealFileIcons); + SaveOption(kFullRow, FullRow); + SaveOption(kShowGrid, ShowGrid); + SaveOption(kSingleClick, SingleClick); + SaveOption(kAlternativeSelection, AlternativeSelection); + // SaveOption(kUnderline, Underline); + + SaveOption(kShowSystemMenu, ShowSystemMenu); +} + +void CFmSettings::Load() +{ + ShowDots = false; + ShowRealFileIcons = false; + /* if (FullRow == false), we can use mouse click on another columns + to select group of files. We need to implement additional + way to select files in any column as in Explorer. + Then we can enable (FullRow == true) default mode. */ + // FullRow = true; + FullRow = false; + ShowGrid = false; + SingleClick = false; + AlternativeSelection = false; + // Underline = false; + + ShowSystemMenu = false; + + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS) + { + ReadOption(key, kShowDots, ShowDots); + ReadOption(key, kShowRealFileIcons, ShowRealFileIcons); + ReadOption(key, kFullRow, FullRow); + ReadOption(key, kShowGrid, ShowGrid); + ReadOption(key, kSingleClick, SingleClick); + ReadOption(key, kAlternativeSelection, AlternativeSelection); + // ReadOption(key, kUnderline, Underline); + + ReadOption(key, kShowSystemMenu, ShowSystemMenu ); + } +} + + +// void SaveLockMemoryAdd(bool enable) { SaveLmOption(kLockMemoryAdd, enable); } +// bool ReadLockMemoryAdd() { return ReadLmOption(kLockMemoryAdd, true); } + +void SaveLockMemoryEnable(bool enable) { Save7ZipOption(kLargePages, enable); } +bool ReadLockMemoryEnable() { return Read7ZipOption(kLargePages, false); } + +static CSysString GetFlatViewName(UInt32 panelIndex) +{ + TCHAR panelString[16]; + ConvertUInt32ToString(panelIndex, panelString); + return (CSysString)kFlatViewName + panelString; +} + +void SaveFlatView(UInt32 panelIndex, bool enable) { SaveOption(GetFlatViewName(panelIndex), enable); } + +bool ReadFlatView(UInt32 panelIndex) +{ + bool enabled = false; + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS) + ReadOption(key, GetFlatViewName(panelIndex), enabled); + return enabled; +} + +/* +void Save_ShowDeleted(bool enable) { SaveOption(kShowDeletedFiles, enable); } +bool Read_ShowDeleted() { return ReadOption(kShowDeletedFiles, false); } +*/ diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.h b/CPP/7zip/UI/FileManager/RegistryUtils.h index 01b259265..8b4cdf0af 100644 --- a/CPP/7zip/UI/FileManager/RegistryUtils.h +++ b/CPP/7zip/UI/FileManager/RegistryUtils.h @@ -1,50 +1,50 @@ -// RegistryUtils.h - -#ifndef ZIP7_INC_REGISTRY_UTILS_H -#define ZIP7_INC_REGISTRY_UTILS_H - -#include "../../../Common/MyTypes.h" -#include "../../../Common/MyString.h" - -void SaveRegLang(const UString &path); -void ReadRegLang(UString &path); - -void SaveRegEditor(bool useEditor, const UString &path); -void ReadRegEditor(bool useEditor, UString &path); - -void SaveRegDiff(const UString &path); -void ReadRegDiff(UString &path); - -void ReadReg_VerCtrlPath(UString &path); - -struct CFmSettings -{ - bool ShowDots; - bool ShowRealFileIcons; - bool FullRow; - bool ShowGrid; - bool SingleClick; - bool AlternativeSelection; - // bool Underline; - - bool ShowSystemMenu; - - void Save() const; - void Load(); -}; - -// void SaveLockMemoryAdd(bool enable); -// bool ReadLockMemoryAdd(); - -bool ReadLockMemoryEnable(); -void SaveLockMemoryEnable(bool enable); - -void SaveFlatView(UInt32 panelIndex, bool enable); -bool ReadFlatView(UInt32 panelIndex); - -/* -void Save_ShowDeleted(bool enable); -bool Read_ShowDeleted(); -*/ - -#endif +// RegistryUtils.h + +#ifndef ZIP7_INC_REGISTRY_UTILS_H +#define ZIP7_INC_REGISTRY_UTILS_H + +#include "../../../Common/MyTypes.h" +#include "../../../Common/MyString.h" + +void SaveRegLang(const UString &path); +void ReadRegLang(UString &path); + +void SaveRegEditor(bool useEditor, const UString &path); +void ReadRegEditor(bool useEditor, UString &path); + +void SaveRegDiff(const UString &path); +void ReadRegDiff(UString &path); + +void ReadReg_VerCtrlPath(UString &path); + +struct CFmSettings +{ + bool ShowDots; + bool ShowRealFileIcons; + bool FullRow; + bool ShowGrid; + bool SingleClick; + bool AlternativeSelection; + // bool Underline; + + bool ShowSystemMenu; + + void Save() const; + void Load(); +}; + +// void SaveLockMemoryAdd(bool enable); +// bool ReadLockMemoryAdd(); + +bool ReadLockMemoryEnable(); +void SaveLockMemoryEnable(bool enable); + +void SaveFlatView(UInt32 panelIndex, bool enable); +bool ReadFlatView(UInt32 panelIndex); + +/* +void Save_ShowDeleted(bool enable); +bool Read_ShowDeleted(); +*/ + +#endif diff --git a/CPP/7zip/UI/FileManager/RootFolder.cpp b/CPP/7zip/UI/FileManager/RootFolder.cpp index 8e88da72a..192f66048 100644 --- a/CPP/7zip/UI/FileManager/RootFolder.cpp +++ b/CPP/7zip/UI/FileManager/RootFolder.cpp @@ -1,342 +1,342 @@ -// RootFolder.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/PropVariant.h" - -#include "../../PropID.h" - -#if defined(_WIN32) && !defined(UNDER_CE) -#define USE_WIN_PATHS -#endif - -static const unsigned kNumRootFolderItems = - #ifdef USE_WIN_PATHS - 4 - #else - 1 - #endif - ; - - -#include "FSFolder.h" -#include "LangUtils.h" -#ifdef USE_WIN_PATHS -#include "NetFolder.h" -#include "FSDrives.h" -#include "AltStreamsFolder.h" -#endif -#include "RootFolder.h" -#include "SysIconUtils.h" - -#include "resource.h" - -using namespace NWindows; - -static const Byte kProps[] = -{ - kpidName -}; - -UString RootFolder_GetName_Computer(int &iconIndex); -UString RootFolder_GetName_Computer(int &iconIndex) -{ - #ifdef USE_WIN_PATHS - iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES); - #else - iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY); - #endif - return LangString(IDS_COMPUTER); -} - -UString RootFolder_GetName_Network(int &iconIndex); -UString RootFolder_GetName_Network(int &iconIndex) -{ - iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_NETWORK); - return LangString(IDS_NETWORK); -} - -UString RootFolder_GetName_Documents(int &iconIndex); -UString RootFolder_GetName_Documents(int &iconIndex) -{ - iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_PERSONAL); - return LangString(IDS_DOCUMENTS); -} - -enum -{ - ROOT_INDEX_COMPUTER = 0 - #ifdef USE_WIN_PATHS - , ROOT_INDEX_DOCUMENTS - , ROOT_INDEX_NETWORK - , ROOT_INDEX_VOLUMES - #endif -}; - -#ifdef USE_WIN_PATHS -static const char * const kVolPrefix = "\\\\."; -#endif - -void CRootFolder::Init() -{ - _names[ROOT_INDEX_COMPUTER] = RootFolder_GetName_Computer(_iconIndices[ROOT_INDEX_COMPUTER]); - #ifdef USE_WIN_PATHS - _names[ROOT_INDEX_DOCUMENTS] = RootFolder_GetName_Documents(_iconIndices[ROOT_INDEX_DOCUMENTS]); - _names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]); - _names[ROOT_INDEX_VOLUMES] = kVolPrefix; - _iconIndices[ROOT_INDEX_VOLUMES] = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES); - #endif -} - -Z7_COM7F_IMF(CRootFolder::LoadItems()) -{ - Init(); - return S_OK; -} - -Z7_COM7F_IMF(CRootFolder::GetNumberOfItems(UInt32 *numItems)) -{ - *numItems = kNumRootFolderItems; - return S_OK; -} - -Z7_COM7F_IMF(CRootFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidIsDir: prop = true; break; - case kpidName: prop = _names[itemIndex]; break; - } - prop.Detach(value); - return S_OK; -} - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0400 // nt4 -#define Z7_USE_DYN_SHGetSpecialFolderPath -#endif - -#ifdef Z7_USE_DYN_SHGetSpecialFolderPath -typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathW)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate); -typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathA)(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate); -#endif - -static UString GetMyDocsPath() -{ - UString us; - WCHAR s[MAX_PATH + 1]; -#ifdef Z7_USE_DYN_SHGetSpecialFolderPath -#ifdef UNDER_CE - #define shell_name TEXT("coredll.dll") -#else - #define shell_name TEXT("shell32.dll") -#endif - Func_SHGetSpecialFolderPathW getW = Z7_GET_PROC_ADDRESS( - Func_SHGetSpecialFolderPathW, GetModuleHandle(shell_name), - "SHGetSpecialFolderPathW"); - if (getW && getW -#else - if (SHGetSpecialFolderPathW -#endif - (NULL, s, CSIDL_PERSONAL, FALSE)) - us = s; - #ifndef _UNICODE - else - { - CHAR s2[MAX_PATH + 1]; -#ifdef Z7_USE_DYN_SHGetSpecialFolderPath - Func_SHGetSpecialFolderPathA getA = Z7_GET_PROC_ADDRESS( - Func_SHGetSpecialFolderPathA, ::GetModuleHandleA("shell32.dll"), - "SHGetSpecialFolderPathA"); - if (getA && getA -#else - if (SHGetSpecialFolderPathA -#endif - (NULL, s2, CSIDL_PERSONAL, FALSE)) - us = GetUnicodeString(s2); - } - #endif - NFile::NName::NormalizeDirPathPrefix(us); - return us; -} - -Z7_COM7F_IMF(CRootFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - CMyComPtr subFolder; - - #ifdef USE_WIN_PATHS - if (index == ROOT_INDEX_COMPUTER || index == ROOT_INDEX_VOLUMES) - { - CFSDrives *fsDrivesSpec = new CFSDrives; - subFolder = fsDrivesSpec; - fsDrivesSpec->Init(index == ROOT_INDEX_VOLUMES); - } - else if (index == ROOT_INDEX_NETWORK) - { - CNetFolder *netFolderSpec = new CNetFolder; - subFolder = netFolderSpec; - netFolderSpec->Init(NULL, NULL, _names[ROOT_INDEX_NETWORK] + WCHAR_PATH_SEPARATOR); - } - else if (index == ROOT_INDEX_DOCUMENTS) - { - UString s = GetMyDocsPath(); - if (!s.IsEmpty()) - { - NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; - subFolder = fsFolderSpec; - RINOK(fsFolderSpec->Init(us2fs(s))) - } - } - #else - if (index == ROOT_INDEX_COMPUTER) - { - NFsFolder::CFSFolder *fsFolder = new NFsFolder::CFSFolder; - subFolder = fsFolder; - fsFolder->InitToRoot(); - } - #endif - else - return E_INVALIDARG; - - *resultFolder = subFolder.Detach(); - return S_OK; -} - -static bool AreEqualNames(const UString &path, const wchar_t *name) -{ - unsigned len = MyStringLen(name); - if (len > path.Len() || len + 1 < path.Len()) - return false; - if (len + 1 == path.Len() && !IS_PATH_SEPAR(path[len])) - return false; - return path.IsPrefixedBy(name); -} - -Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - UString name2 = name; - name2.Trim(); - - if (name2.IsEmpty()) - { - CRootFolder *rootFolderSpec = new CRootFolder; - CMyComPtr rootFolder = rootFolderSpec; - rootFolderSpec->Init(); - *resultFolder = rootFolder.Detach(); - return S_OK; - } - - for (unsigned i = 0; i < kNumRootFolderItems; i++) - if (AreEqualNames(name2, _names[i])) - return BindToFolder((UInt32)i, resultFolder); - - #ifdef USE_WIN_PATHS - if (AreEqualNames(name2, L"My Documents") || - AreEqualNames(name2, L"Documents")) - return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder); - #else - if (name2 == WSTRING_PATH_SEPARATOR) - return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); - #endif - - if (AreEqualNames(name2, L"My Computer") || - AreEqualNames(name2, L"Computer")) - return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); - - if (name2 == WSTRING_PATH_SEPARATOR) - { - CMyComPtr subFolder = this; - *resultFolder = subFolder.Detach(); - return S_OK; - } - - if (name2.Len() < 2) - return E_INVALIDARG; - - CMyComPtr subFolder; - - #ifdef USE_WIN_PATHS - if (name2.IsPrefixedBy_Ascii_NoCase(kVolPrefix)) - { - CFSDrives *folderSpec = new CFSDrives; - subFolder = folderSpec; - folderSpec->Init(true); - } - else if (name2.IsEqualTo(NFile::NName::kSuperPathPrefix)) - { - CFSDrives *folderSpec = new CFSDrives; - subFolder = folderSpec; - folderSpec->Init(false, true); - } - else if (name2.Back() == ':' - && (name2.Len() != 2 || !NFile::NName::IsDrivePath2(name2))) - { - NAltStreamsFolder::CAltStreamsFolder *folderSpec = new NAltStreamsFolder::CAltStreamsFolder; - subFolder = folderSpec; - if (folderSpec->Init(us2fs(name2)) != S_OK) - return E_INVALIDARG; - } - else - #endif - { - NFile::NName::NormalizeDirPathPrefix(name2); - NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; - subFolder = fsFolderSpec; - if (fsFolderSpec->Init(us2fs(name2)) != S_OK) - { - #ifdef USE_WIN_PATHS - if (IS_PATH_SEPAR(name2[0])) - { - CNetFolder *netFolderSpec = new CNetFolder; - subFolder = netFolderSpec; - netFolderSpec->Init(name2); - } - else - #endif - return E_INVALIDARG; - } - } - - *resultFolder = subFolder.Detach(); - return S_OK; -} - -Z7_COM7F_IMF(CRootFolder::BindToParentFolder(IFolderFolder **resultFolder)) -{ - *resultFolder = NULL; - return S_OK; -} - -IMP_IFolderFolder_Props(CRootFolder) - -Z7_COM7F_IMF(CRootFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) -{ - NCOM::CPropVariant prop; - switch (propID) - { - case kpidType: prop = "RootFolder"; break; - case kpidPath: prop = ""; break; - } - prop.Detach(value); - return S_OK; -} - -Z7_COM7F_IMF(CRootFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) -{ - *iconIndex = _iconIndices[index]; - return S_OK; -} +// RootFolder.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" + +#include "../../PropID.h" + +#if defined(_WIN32) && !defined(UNDER_CE) +#define USE_WIN_PATHS +#endif + +static const unsigned kNumRootFolderItems = + #ifdef USE_WIN_PATHS + 4 + #else + 1 + #endif + ; + + +#include "FSFolder.h" +#include "LangUtils.h" +#ifdef USE_WIN_PATHS +#include "NetFolder.h" +#include "FSDrives.h" +#include "AltStreamsFolder.h" +#endif +#include "RootFolder.h" +#include "SysIconUtils.h" + +#include "resource.h" + +using namespace NWindows; + +static const Byte kProps[] = +{ + kpidName +}; + +UString RootFolder_GetName_Computer(int &iconIndex); +UString RootFolder_GetName_Computer(int &iconIndex) +{ + #ifdef USE_WIN_PATHS + iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES); + #else + iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY); + #endif + return LangString(IDS_COMPUTER); +} + +UString RootFolder_GetName_Network(int &iconIndex); +UString RootFolder_GetName_Network(int &iconIndex) +{ + iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_NETWORK); + return LangString(IDS_NETWORK); +} + +UString RootFolder_GetName_Documents(int &iconIndex); +UString RootFolder_GetName_Documents(int &iconIndex) +{ + iconIndex = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_PERSONAL); + return LangString(IDS_DOCUMENTS); +} + +enum +{ + ROOT_INDEX_COMPUTER = 0 + #ifdef USE_WIN_PATHS + , ROOT_INDEX_DOCUMENTS + , ROOT_INDEX_NETWORK + , ROOT_INDEX_VOLUMES + #endif +}; + +#ifdef USE_WIN_PATHS +static const char * const kVolPrefix = "\\\\."; +#endif + +void CRootFolder::Init() +{ + _names[ROOT_INDEX_COMPUTER] = RootFolder_GetName_Computer(_iconIndices[ROOT_INDEX_COMPUTER]); + #ifdef USE_WIN_PATHS + _names[ROOT_INDEX_DOCUMENTS] = RootFolder_GetName_Documents(_iconIndices[ROOT_INDEX_DOCUMENTS]); + _names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]); + _names[ROOT_INDEX_VOLUMES] = kVolPrefix; + _iconIndices[ROOT_INDEX_VOLUMES] = Shell_GetFileInfo_SysIconIndex_for_CSIDL(CSIDL_DRIVES); + #endif +} + +Z7_COM7F_IMF(CRootFolder::LoadItems()) +{ + Init(); + return S_OK; +} + +Z7_COM7F_IMF(CRootFolder::GetNumberOfItems(UInt32 *numItems)) +{ + *numItems = kNumRootFolderItems; + return S_OK; +} + +Z7_COM7F_IMF(CRootFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidIsDir: prop = true; break; + case kpidName: prop = _names[itemIndex]; break; + } + prop.Detach(value); + return S_OK; +} + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0400 // nt4 +#define Z7_USE_DYN_SHGetSpecialFolderPath +#endif + +#ifdef Z7_USE_DYN_SHGetSpecialFolderPath +typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathW)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate); +typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathA)(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate); +#endif + +static UString GetMyDocsPath() +{ + UString us; + WCHAR s[MAX_PATH + 1]; +#ifdef Z7_USE_DYN_SHGetSpecialFolderPath +#ifdef UNDER_CE + #define shell_name TEXT("coredll.dll") +#else + #define shell_name TEXT("shell32.dll") +#endif + Func_SHGetSpecialFolderPathW getW = Z7_GET_PROC_ADDRESS( + Func_SHGetSpecialFolderPathW, GetModuleHandle(shell_name), + "SHGetSpecialFolderPathW"); + if (getW && getW +#else + if (SHGetSpecialFolderPathW +#endif + (NULL, s, CSIDL_PERSONAL, FALSE)) + us = s; + #ifndef _UNICODE + else + { + CHAR s2[MAX_PATH + 1]; +#ifdef Z7_USE_DYN_SHGetSpecialFolderPath + Func_SHGetSpecialFolderPathA getA = Z7_GET_PROC_ADDRESS( + Func_SHGetSpecialFolderPathA, ::GetModuleHandleA("shell32.dll"), + "SHGetSpecialFolderPathA"); + if (getA && getA +#else + if (SHGetSpecialFolderPathA +#endif + (NULL, s2, CSIDL_PERSONAL, FALSE)) + us = GetUnicodeString(s2); + } + #endif + NFile::NName::NormalizeDirPathPrefix(us); + return us; +} + +Z7_COM7F_IMF(CRootFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + CMyComPtr subFolder; + + #ifdef USE_WIN_PATHS + if (index == ROOT_INDEX_COMPUTER || index == ROOT_INDEX_VOLUMES) + { + CFSDrives *fsDrivesSpec = new CFSDrives; + subFolder = fsDrivesSpec; + fsDrivesSpec->Init(index == ROOT_INDEX_VOLUMES); + } + else if (index == ROOT_INDEX_NETWORK) + { + CNetFolder *netFolderSpec = new CNetFolder; + subFolder = netFolderSpec; + netFolderSpec->Init(NULL, NULL, _names[ROOT_INDEX_NETWORK] + WCHAR_PATH_SEPARATOR); + } + else if (index == ROOT_INDEX_DOCUMENTS) + { + UString s = GetMyDocsPath(); + if (!s.IsEmpty()) + { + NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; + subFolder = fsFolderSpec; + RINOK(fsFolderSpec->Init(us2fs(s))) + } + } + #else + if (index == ROOT_INDEX_COMPUTER) + { + NFsFolder::CFSFolder *fsFolder = new NFsFolder::CFSFolder; + subFolder = fsFolder; + fsFolder->InitToRoot(); + } + #endif + else + return E_INVALIDARG; + + *resultFolder = subFolder.Detach(); + return S_OK; +} + +static bool AreEqualNames(const UString &path, const wchar_t *name) +{ + unsigned len = MyStringLen(name); + if (len > path.Len() || len + 1 < path.Len()) + return false; + if (len + 1 == path.Len() && !IS_PATH_SEPAR(path[len])) + return false; + return path.IsPrefixedBy(name); +} + +Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + UString name2 = name; + name2.Trim(); + + if (name2.IsEmpty()) + { + CRootFolder *rootFolderSpec = new CRootFolder; + CMyComPtr rootFolder = rootFolderSpec; + rootFolderSpec->Init(); + *resultFolder = rootFolder.Detach(); + return S_OK; + } + + for (unsigned i = 0; i < kNumRootFolderItems; i++) + if (AreEqualNames(name2, _names[i])) + return BindToFolder((UInt32)i, resultFolder); + + #ifdef USE_WIN_PATHS + if (AreEqualNames(name2, L"My Documents") || + AreEqualNames(name2, L"Documents")) + return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder); + #else + if (name2 == WSTRING_PATH_SEPARATOR) + return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); + #endif + + if (AreEqualNames(name2, L"My Computer") || + AreEqualNames(name2, L"Computer")) + return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder); + + if (name2 == WSTRING_PATH_SEPARATOR) + { + CMyComPtr subFolder = this; + *resultFolder = subFolder.Detach(); + return S_OK; + } + + if (name2.Len() < 2) + return E_INVALIDARG; + + CMyComPtr subFolder; + + #ifdef USE_WIN_PATHS + if (name2.IsPrefixedBy_Ascii_NoCase(kVolPrefix)) + { + CFSDrives *folderSpec = new CFSDrives; + subFolder = folderSpec; + folderSpec->Init(true); + } + else if (name2.IsEqualTo(NFile::NName::kSuperPathPrefix)) + { + CFSDrives *folderSpec = new CFSDrives; + subFolder = folderSpec; + folderSpec->Init(false, true); + } + else if (name2.Back() == ':' + && (name2.Len() != 2 || !NFile::NName::IsDrivePath2(name2))) + { + NAltStreamsFolder::CAltStreamsFolder *folderSpec = new NAltStreamsFolder::CAltStreamsFolder; + subFolder = folderSpec; + if (folderSpec->Init(us2fs(name2)) != S_OK) + return E_INVALIDARG; + } + else + #endif + { + NFile::NName::NormalizeDirPathPrefix(name2); + NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder; + subFolder = fsFolderSpec; + if (fsFolderSpec->Init(us2fs(name2)) != S_OK) + { + #ifdef USE_WIN_PATHS + if (IS_PATH_SEPAR(name2[0])) + { + CNetFolder *netFolderSpec = new CNetFolder; + subFolder = netFolderSpec; + netFolderSpec->Init(name2); + } + else + #endif + return E_INVALIDARG; + } + } + + *resultFolder = subFolder.Detach(); + return S_OK; +} + +Z7_COM7F_IMF(CRootFolder::BindToParentFolder(IFolderFolder **resultFolder)) +{ + *resultFolder = NULL; + return S_OK; +} + +IMP_IFolderFolder_Props(CRootFolder) + +Z7_COM7F_IMF(CRootFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) +{ + NCOM::CPropVariant prop; + switch (propID) + { + case kpidType: prop = "RootFolder"; break; + case kpidPath: prop = ""; break; + } + prop.Detach(value); + return S_OK; +} + +Z7_COM7F_IMF(CRootFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex)) +{ + *iconIndex = _iconIndices[index]; + return S_OK; +} diff --git a/CPP/7zip/UI/FileManager/RootFolder.h b/CPP/7zip/UI/FileManager/RootFolder.h index 78a64f2fb..3f0a31b32 100644 --- a/CPP/7zip/UI/FileManager/RootFolder.h +++ b/CPP/7zip/UI/FileManager/RootFolder.h @@ -1,24 +1,24 @@ -// RootFolder.h - -#ifndef ZIP7_INC_ROOT_FOLDER_H -#define ZIP7_INC_ROOT_FOLDER_H - -#include "../../../Common/MyCom.h" -#include "../../../Common/MyString.h" - -#include "IFolder.h" - -const unsigned kNumRootFolderItems_Max = 4; - -Z7_CLASS_IMP_NOQIB_2( - CRootFolder - , IFolderFolder - , IFolderGetSystemIconIndex -) - UString _names[kNumRootFolderItems_Max]; - int _iconIndices[kNumRootFolderItems_Max]; -public: - void Init(); -}; - -#endif +// RootFolder.h + +#ifndef ZIP7_INC_ROOT_FOLDER_H +#define ZIP7_INC_ROOT_FOLDER_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/MyString.h" + +#include "IFolder.h" + +const unsigned kNumRootFolderItems_Max = 4; + +Z7_CLASS_IMP_NOQIB_2( + CRootFolder + , IFolderFolder + , IFolderGetSystemIconIndex +) + UString _names[kNumRootFolderItems_Max]; + int _iconIndices[kNumRootFolderItems_Max]; +public: + void Init(); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SettingsPage.cpp b/CPP/7zip/UI/FileManager/SettingsPage.cpp index 2eaa8fe01..8b5983af5 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage.cpp +++ b/CPP/7zip/UI/FileManager/SettingsPage.cpp @@ -1,453 +1,453 @@ -// SettingsPage.cpp - -#include "StdAfx.h" - -#include - -// #include "../../../Common/IntToString.h" -// #include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#ifndef UNDER_CE -#include "../../../Windows/ErrorMsg.h" -#include "../../../Windows/MemoryLock.h" -#include "../../../Windows/System.h" -#endif - -#include "../Explorer/MyMessages.h" - -#include "../Common/ZipRegistry.h" - -#include "HelpUtils.h" -#include "LangUtils.h" -#include "RegistryUtils.h" -#include "SettingsPage.h" -#include "SettingsPageRes.h" - -using namespace NWindows; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDX_SETTINGS_SHOW_DOTS, - IDX_SETTINGS_SHOW_REAL_FILE_ICONS, - IDX_SETTINGS_SHOW_SYSTEM_MENU, - IDX_SETTINGS_FULL_ROW, - IDX_SETTINGS_SHOW_GRID, - IDX_SETTINGS_SINGLE_CLICK, - IDX_SETTINGS_ALTERNATIVE_SELECTION, - IDX_SETTINGS_LARGE_PAGES, - IDT_MEM_USAGE_EXTRACT - // , IDT_COMPRESS_MEMORY -}; -#endif - -#define kSettingsTopic "FM/options.htm#settings" - -extern bool IsLargePageSupported(); - -/* -static void AddMemSize(UString &res, UInt64 size, bool needRound = false) -{ - char c; - unsigned moveBits = 0; - if (needRound) - { - UInt64 rn = 0; - if (size >= (1 << 31)) - rn = (1 << 28) - 1; - UInt32 kRound = (1 << 20) - 1; - if (rn < kRound) - rn = kRound; - size += rn; - size &= ~rn; - } - if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0) - { moveBits = 30; c = 'G'; } - else - { moveBits = 20; c = 'M'; } - res.Add_UInt64(size >> moveBits); - res.Add_Space(); - if (moveBits != 0) - res += c; - res += 'B'; -} - - -int CSettingsPage::AddMemComboItem(UInt64 size, UInt64 percents, bool isDefault) -{ - UString sUser; - UString sRegistry; - if (size == 0) - { - UString s; - s.Add_UInt64(percents); - s += '%'; - if (isDefault) - sUser = "* "; - else - sRegistry = s; - sUser += s; - } - else - { - AddMemSize(sUser, size); - sRegistry = sUser; - for (;;) - { - int pos = sRegistry.Find(L' '); - if (pos < 0) - break; - sRegistry.Delete(pos); - } - if (!sRegistry.IsEmpty()) - if (sRegistry.Back() == 'B') - sRegistry.DeleteBack(); - } - const int index = (int)_memCombo.AddString(sUser); - _memCombo.SetItemData(index, _memLimitStrings.Size()); - _memLimitStrings.Add(sRegistry); - return index; -} -*/ - -bool CSettingsPage::OnInit() -{ - _initMode = true; - _wasChanged = false; - _largePages_wasChanged = false; - _memx_wasChanged = false; - /* - _wasChanged_MemLimit = false; - _memLimitStrings.Clear(); - _memCombo.Attach(GetItem(IDC_SETTINGS_MEM)); - */ - -#ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); -#endif - - CFmSettings st; - st.Load(); - - CheckButton(IDX_SETTINGS_SHOW_DOTS, st.ShowDots); - CheckButton(IDX_SETTINGS_SHOW_REAL_FILE_ICONS, st.ShowRealFileIcons); - CheckButton(IDX_SETTINGS_FULL_ROW, st.FullRow); - CheckButton(IDX_SETTINGS_SHOW_GRID, st.ShowGrid); - CheckButton(IDX_SETTINGS_SINGLE_CLICK, st.SingleClick); - CheckButton(IDX_SETTINGS_ALTERNATIVE_SELECTION, st.AlternativeSelection); - // CheckButton(IDX_SETTINGS_UNDERLINE, st.Underline); - - CheckButton(IDX_SETTINGS_SHOW_SYSTEM_MENU, st.ShowSystemMenu); - - if (IsLargePageSupported()) - CheckButton(IDX_SETTINGS_LARGE_PAGES, ReadLockMemoryEnable()); - else - EnableItem(IDX_SETTINGS_LARGE_PAGES, false); - - - /* - NCompression::CMemUse mu; - bool needSetCur = NCompression::MemLimit_Load(mu); - UInt64 curMemLimit; - { - AddMemComboItem(0, 90, true); - _memCombo.SetCurSel(0); - } - if (mu.IsPercent) - { - const int index = AddMemComboItem(0, mu.Val); - _memCombo.SetCurSel(index); - needSetCur = false; - } - { - _ramSize = (UInt64)(sizeof(size_t)) << 29; - _ramSize_Defined = NSystem::GetRamSize(_ramSize); - UString s; - if (_ramSize_Defined) - { - s += "/ "; - AddMemSize(s, _ramSize, true); - } - SetItemText(IDT_SETTINGS_MEM_RAM, s); - - curMemLimit = mu.GetBytes(_ramSize); - - // size = 100 << 20; // for debug only; - for (unsigned i = (27) * 2;; i++) - { - UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2); - if (i > (20 + sizeof(size_t) * 3 * 1 - 1) * 2) - size = (UInt64)(Int64)-1; - if (needSetCur && (size >= curMemLimit)) - { - const int index = AddMemComboItem(curMemLimit); - _memCombo.SetCurSel(index); - needSetCur = false; - if (size == curMemLimit) - continue; - } - if (size == (UInt64)(Int64)-1) - break; - AddMemComboItem(size); - } - } - */ - - // EnableSubItems(); - - - { - UInt64 ramSize = (UInt64)sizeof(size_t) << 29; - const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize); - // ramSize *= 10; // for debug - UInt64 ramSize_GB = (ramSize + (1u << 29)) >> 30; - if (ramSize_GB == 0) - ramSize_GB = 1; - UString s ("GB"); - if (ramSize_defined) - { - s += " / "; - s.Add_UInt64(ramSize_GB); - s += " GB (RAM)"; - } - SetItemText(IDT_SETTINGS_MEM_GB, s); - - const UINT valMin = 1; - UINT valMax = 64; // 64GB for RAR7 - if (ramSize_defined /* && ramSize_GB > valMax */) - { - const UINT k_max_val = 1u << 14; - if (ramSize_GB >= k_max_val) - valMax = k_max_val; - else if (ramSize_GB > 1) - valMax = (UINT)ramSize_GB - 1; - else - valMax = 1; - } - - UInt32 limit = NExtract::Read_LimitGB(); - if (limit != 0 && limit != (UInt32)(Int32)-1) - CheckButton(IDX_SETTINGS_MEM_SET, true); - else - { - limit = 4; - EnableSpin(false); - } - SendItemMessage(IDC_SETTINGS_MEM_SPIN, UDM_SETRANGE, 0, MAKELPARAM(valMax, valMin)); // Sets the controls direction - // UDM_SETPOS doesn't set value larger than max value (valMax) of range: - SendItemMessage(IDC_SETTINGS_MEM_SPIN, UDM_SETPOS, 0, limit); - s.Empty(); - s.Add_UInt32(limit); - SetItemText(IDE_SETTINGS_MEM_SPIN_EDIT, s); - } - - _initMode = false; - return CPropertyPage::OnInit(); -} - - -void CSettingsPage::EnableSpin(bool enable) -{ - EnableItem(IDC_SETTINGS_MEM_SPIN, enable); - EnableItem(IDE_SETTINGS_MEM_SPIN_EDIT, enable); -} - - -/* -void CSettingsPage::EnableSubItems() -{ - EnableItem(IDX_SETTINGS_UNDERLINE, IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK)); -} -*/ - -/* -static void AddSize_MB(UString &s, UInt64 size) -{ - s.Add_UInt64((size + (1 << 20) - 1) >> 20); - s += " MB"; -} -*/ - -LONG CSettingsPage::OnApply() -{ - if (_wasChanged) - { - CFmSettings st; - st.ShowDots = IsButtonCheckedBool(IDX_SETTINGS_SHOW_DOTS); - st.ShowRealFileIcons = IsButtonCheckedBool(IDX_SETTINGS_SHOW_REAL_FILE_ICONS); - st.FullRow = IsButtonCheckedBool(IDX_SETTINGS_FULL_ROW); - st.ShowGrid = IsButtonCheckedBool(IDX_SETTINGS_SHOW_GRID); - st.SingleClick = IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK); - st.AlternativeSelection = IsButtonCheckedBool(IDX_SETTINGS_ALTERNATIVE_SELECTION); - // st.Underline = IsButtonCheckedBool(IDX_SETTINGS_UNDERLINE); - - st.ShowSystemMenu = IsButtonCheckedBool(IDX_SETTINGS_SHOW_SYSTEM_MENU); - - st.Save(); - _wasChanged = false; - } - - #ifndef UNDER_CE - if (_largePages_wasChanged) - { - if (IsLargePageSupported()) - { - const bool enable = IsButtonCheckedBool(IDX_SETTINGS_LARGE_PAGES); - NSecurity::EnablePrivilege_LockMemory(enable); - SaveLockMemoryEnable(enable); - } - _largePages_wasChanged = false; - } - #endif - - if (_memx_wasChanged) - { - UInt32 val = (UInt32)(Int32)-1; - if (IsButtonCheckedBool(IDX_SETTINGS_MEM_SET)) - { - UString s; - GetItemText(IDE_SETTINGS_MEM_SPIN_EDIT, s); - const wchar_t *end; - val = ConvertStringToUInt32(s.Ptr(), &end); - if (s.IsEmpty() || *end != 0 || val > (1u << 30)) - { - // L"Incorrect value" - ShowErrorMessage(*this, NError::MyFormatMessage(E_INVALIDARG)); - return PSNRET_INVALID; - } - } - NExtract::Save_LimitGB(val); - _memx_wasChanged = false; - } - - /* - if (_wasChanged_MemLimit) - { - const unsigned index = (int)_memCombo.GetItemData_of_CurSel(); - const UString str = _memLimitStrings[index]; - - bool needSave = true; - - NCompression::CMemUse mu; - - if (_ramSize_Defined) - mu.Parse(str); - if (mu.IsDefined) - { - const UInt64 usage64 = mu.GetBytes(_ramSize); - if (_ramSize <= usage64) - { - UString s2 = LangString(IDT_COMPRESS_MEMORY); - if (s2.IsEmpty()) - GetItemText(IDT_COMPRESS_MEMORY, s2); - UString s; - - s += "The selected value is not safe for system performance."; - s.Add_LF(); - s += "The memory consumption for compression operation will exceed RAM size."; - s.Add_LF(); - s.Add_LF(); - AddSize_MB(s, usage64); - - if (!s2.IsEmpty()) - { - s += " : "; - s += s2; - } - - s.Add_LF(); - AddSize_MB(s, _ramSize); - s += " : RAM"; - - s.Add_LF(); - s.Add_LF(); - s += "Are you sure you want set that unsafe value for memory usage?"; - - int res = MessageBoxW(*this, s, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION); - if (res != IDYES) - needSave = false; - } - } - - if (needSave) - { - NCompression::MemLimit_Save(str); - _wasChanged_MemLimit = false; - } - else - return PSNRET_INVALID_NOCHANGEPAGE; - } - */ - - return PSNRET_NOERROR; -} - -void CSettingsPage::OnNotifyHelp() -{ - ShowHelpWindow(kSettingsTopic); -} - -bool CSettingsPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) -{ - if (!_initMode) - { - if (code == EN_CHANGE && itemID == IDE_SETTINGS_MEM_SPIN_EDIT) - { - _memx_wasChanged = true; - Changed(); - } - /* - if (code == CBN_SELCHANGE) - { - switch (itemID) - { - case IDC_SETTINGS_MEM: - { - _wasChanged_MemLimit = true; - Changed(); - break; - } - } - } - */ - } - return CPropertyPage::OnCommand(code, itemID, param); -} - -bool CSettingsPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDX_SETTINGS_SINGLE_CLICK: - /* - EnableSubItems(); - break; - */ - case IDX_SETTINGS_SHOW_DOTS: - case IDX_SETTINGS_SHOW_SYSTEM_MENU: - case IDX_SETTINGS_SHOW_REAL_FILE_ICONS: - case IDX_SETTINGS_FULL_ROW: - case IDX_SETTINGS_SHOW_GRID: - case IDX_SETTINGS_ALTERNATIVE_SELECTION: - _wasChanged = true; - break; - - case IDX_SETTINGS_LARGE_PAGES: - _largePages_wasChanged = true; - break; - - case IDX_SETTINGS_MEM_SET: - { - _memx_wasChanged = true; - EnableSpin(IsButtonCheckedBool(IDX_SETTINGS_MEM_SET)); - break; - } - - default: - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); - } - - Changed(); - return true; -} +// SettingsPage.cpp + +#include "StdAfx.h" + +#include + +// #include "../../../Common/IntToString.h" +// #include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#ifndef UNDER_CE +#include "../../../Windows/ErrorMsg.h" +#include "../../../Windows/MemoryLock.h" +#include "../../../Windows/System.h" +#endif + +#include "../Explorer/MyMessages.h" + +#include "../Common/ZipRegistry.h" + +#include "HelpUtils.h" +#include "LangUtils.h" +#include "RegistryUtils.h" +#include "SettingsPage.h" +#include "SettingsPageRes.h" + +using namespace NWindows; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDX_SETTINGS_SHOW_DOTS, + IDX_SETTINGS_SHOW_REAL_FILE_ICONS, + IDX_SETTINGS_SHOW_SYSTEM_MENU, + IDX_SETTINGS_FULL_ROW, + IDX_SETTINGS_SHOW_GRID, + IDX_SETTINGS_SINGLE_CLICK, + IDX_SETTINGS_ALTERNATIVE_SELECTION, + IDX_SETTINGS_LARGE_PAGES, + IDT_MEM_USAGE_EXTRACT + // , IDT_COMPRESS_MEMORY +}; +#endif + +#define kSettingsTopic "FM/options.htm#settings" + +extern bool IsLargePageSupported(); + +/* +static void AddMemSize(UString &res, UInt64 size, bool needRound = false) +{ + char c; + unsigned moveBits = 0; + if (needRound) + { + UInt64 rn = 0; + if (size >= (1 << 31)) + rn = (1 << 28) - 1; + UInt32 kRound = (1 << 20) - 1; + if (rn < kRound) + rn = kRound; + size += rn; + size &= ~rn; + } + if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0) + { moveBits = 30; c = 'G'; } + else + { moveBits = 20; c = 'M'; } + res.Add_UInt64(size >> moveBits); + res.Add_Space(); + if (moveBits != 0) + res += c; + res += 'B'; +} + + +int CSettingsPage::AddMemComboItem(UInt64 size, UInt64 percents, bool isDefault) +{ + UString sUser; + UString sRegistry; + if (size == 0) + { + UString s; + s.Add_UInt64(percents); + s += '%'; + if (isDefault) + sUser = "* "; + else + sRegistry = s; + sUser += s; + } + else + { + AddMemSize(sUser, size); + sRegistry = sUser; + for (;;) + { + int pos = sRegistry.Find(L' '); + if (pos < 0) + break; + sRegistry.Delete(pos); + } + if (!sRegistry.IsEmpty()) + if (sRegistry.Back() == 'B') + sRegistry.DeleteBack(); + } + const int index = (int)_memCombo.AddString(sUser); + _memCombo.SetItemData(index, _memLimitStrings.Size()); + _memLimitStrings.Add(sRegistry); + return index; +} +*/ + +bool CSettingsPage::OnInit() +{ + _initMode = true; + _wasChanged = false; + _largePages_wasChanged = false; + _memx_wasChanged = false; + /* + _wasChanged_MemLimit = false; + _memLimitStrings.Clear(); + _memCombo.Attach(GetItem(IDC_SETTINGS_MEM)); + */ + +#ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); +#endif + + CFmSettings st; + st.Load(); + + CheckButton(IDX_SETTINGS_SHOW_DOTS, st.ShowDots); + CheckButton(IDX_SETTINGS_SHOW_REAL_FILE_ICONS, st.ShowRealFileIcons); + CheckButton(IDX_SETTINGS_FULL_ROW, st.FullRow); + CheckButton(IDX_SETTINGS_SHOW_GRID, st.ShowGrid); + CheckButton(IDX_SETTINGS_SINGLE_CLICK, st.SingleClick); + CheckButton(IDX_SETTINGS_ALTERNATIVE_SELECTION, st.AlternativeSelection); + // CheckButton(IDX_SETTINGS_UNDERLINE, st.Underline); + + CheckButton(IDX_SETTINGS_SHOW_SYSTEM_MENU, st.ShowSystemMenu); + + if (IsLargePageSupported()) + CheckButton(IDX_SETTINGS_LARGE_PAGES, ReadLockMemoryEnable()); + else + EnableItem(IDX_SETTINGS_LARGE_PAGES, false); + + + /* + NCompression::CMemUse mu; + bool needSetCur = NCompression::MemLimit_Load(mu); + UInt64 curMemLimit; + { + AddMemComboItem(0, 90, true); + _memCombo.SetCurSel(0); + } + if (mu.IsPercent) + { + const int index = AddMemComboItem(0, mu.Val); + _memCombo.SetCurSel(index); + needSetCur = false; + } + { + _ramSize = (size_t)sizeof(size_t) << 29; + _ramSize_Defined = NSystem::GetRamSize(_ramSize); + UString s; + if (_ramSize_Defined) + { + s += "/ "; + AddMemSize(s, _ramSize, true); + } + SetItemText(IDT_SETTINGS_MEM_RAM, s); + + curMemLimit = mu.GetBytes(_ramSize); + + // size = 100 << 20; // for debug only; + for (unsigned i = (27) * 2;; i++) + { + UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2); + if (i > (20 + sizeof(size_t) * 3 * 1 - 1) * 2) + size = (UInt64)(Int64)-1; + if (needSetCur && (size >= curMemLimit)) + { + const int index = AddMemComboItem(curMemLimit); + _memCombo.SetCurSel(index); + needSetCur = false; + if (size == curMemLimit) + continue; + } + if (size == (UInt64)(Int64)-1) + break; + AddMemComboItem(size); + } + } + */ + + // EnableSubItems(); + + + { + size_t ramSize = (size_t)sizeof(size_t) << 29; + const bool ramSize_defined = NWindows::NSystem::GetRamSize(ramSize); + // ramSize *= 10; // for debug + UInt32 ramSize_GB = (UInt32)(((UInt64)ramSize + (1u << 29)) >> 30); + if (ramSize_GB == 0) + ramSize_GB = 1; + UString s ("GB"); + if (ramSize_defined) + { + s += " / "; + s.Add_UInt64(ramSize_GB); + s += " GB (RAM)"; + } + SetItemText(IDT_SETTINGS_MEM_GB, s); + + const UINT valMin = 1; + UINT valMax = 64; // 64GB for RAR7 + if (ramSize_defined /* && ramSize_GB > valMax */) + { + const UINT k_max_val = 1u << 14; + if (ramSize_GB >= k_max_val) + valMax = k_max_val; + else if (ramSize_GB > 1) + valMax = (UINT)ramSize_GB - 1; + else + valMax = 1; + } + + UInt32 limit = NExtract::Read_LimitGB(); + if (limit != 0 && limit != (UInt32)(Int32)-1) + CheckButton(IDX_SETTINGS_MEM_SET, true); + else + { + limit = 4; + EnableSpin(false); + } + SendItemMessage(IDC_SETTINGS_MEM_SPIN, UDM_SETRANGE, 0, MAKELPARAM(valMax, valMin)); // Sets the controls direction + // UDM_SETPOS doesn't set value larger than max value (valMax) of range: + SendItemMessage(IDC_SETTINGS_MEM_SPIN, UDM_SETPOS, 0, limit); + s.Empty(); + s.Add_UInt32(limit); + SetItemText(IDE_SETTINGS_MEM_SPIN_EDIT, s); + } + + _initMode = false; + return CPropertyPage::OnInit(); +} + + +void CSettingsPage::EnableSpin(bool enable) +{ + EnableItem(IDC_SETTINGS_MEM_SPIN, enable); + EnableItem(IDE_SETTINGS_MEM_SPIN_EDIT, enable); +} + + +/* +void CSettingsPage::EnableSubItems() +{ + EnableItem(IDX_SETTINGS_UNDERLINE, IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK)); +} +*/ + +/* +static void AddSize_MB(UString &s, UInt64 size) +{ + s.Add_UInt64((size + (1 << 20) - 1) >> 20); + s += " MB"; +} +*/ + +LONG CSettingsPage::OnApply() +{ + if (_wasChanged) + { + CFmSettings st; + st.ShowDots = IsButtonCheckedBool(IDX_SETTINGS_SHOW_DOTS); + st.ShowRealFileIcons = IsButtonCheckedBool(IDX_SETTINGS_SHOW_REAL_FILE_ICONS); + st.FullRow = IsButtonCheckedBool(IDX_SETTINGS_FULL_ROW); + st.ShowGrid = IsButtonCheckedBool(IDX_SETTINGS_SHOW_GRID); + st.SingleClick = IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK); + st.AlternativeSelection = IsButtonCheckedBool(IDX_SETTINGS_ALTERNATIVE_SELECTION); + // st.Underline = IsButtonCheckedBool(IDX_SETTINGS_UNDERLINE); + + st.ShowSystemMenu = IsButtonCheckedBool(IDX_SETTINGS_SHOW_SYSTEM_MENU); + + st.Save(); + _wasChanged = false; + } + + #ifndef UNDER_CE + if (_largePages_wasChanged) + { + if (IsLargePageSupported()) + { + const bool enable = IsButtonCheckedBool(IDX_SETTINGS_LARGE_PAGES); + NSecurity::EnablePrivilege_LockMemory(enable); + SaveLockMemoryEnable(enable); + } + _largePages_wasChanged = false; + } + #endif + + if (_memx_wasChanged) + { + UInt32 val = (UInt32)(Int32)-1; + if (IsButtonCheckedBool(IDX_SETTINGS_MEM_SET)) + { + UString s; + GetItemText(IDE_SETTINGS_MEM_SPIN_EDIT, s); + const wchar_t *end; + val = ConvertStringToUInt32(s.Ptr(), &end); + if (s.IsEmpty() || *end != 0 || val > (1u << 30)) + { + // L"Incorrect value" + ShowErrorMessage(*this, NError::MyFormatMessage(E_INVALIDARG)); + return PSNRET_INVALID; + } + } + NExtract::Save_LimitGB(val); + _memx_wasChanged = false; + } + + /* + if (_wasChanged_MemLimit) + { + const unsigned index = (int)_memCombo.GetItemData_of_CurSel(); + const UString str = _memLimitStrings[index]; + + bool needSave = true; + + NCompression::CMemUse mu; + + if (_ramSize_Defined) + mu.Parse(str); + if (mu.IsDefined) + { + const UInt64 usage64 = mu.GetBytes(_ramSize); + if (_ramSize <= usage64) + { + UString s2 = LangString(IDT_COMPRESS_MEMORY); + if (s2.IsEmpty()) + GetItemText(IDT_COMPRESS_MEMORY, s2); + UString s; + + s += "The selected value is not safe for system performance."; + s.Add_LF(); + s += "The memory consumption for compression operation will exceed RAM size."; + s.Add_LF(); + s.Add_LF(); + AddSize_MB(s, usage64); + + if (!s2.IsEmpty()) + { + s += " : "; + s += s2; + } + + s.Add_LF(); + AddSize_MB(s, _ramSize); + s += " : RAM"; + + s.Add_LF(); + s.Add_LF(); + s += "Are you sure you want set that unsafe value for memory usage?"; + + int res = MessageBoxW(*this, s, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION); + if (res != IDYES) + needSave = false; + } + } + + if (needSave) + { + NCompression::MemLimit_Save(str); + _wasChanged_MemLimit = false; + } + else + return PSNRET_INVALID_NOCHANGEPAGE; + } + */ + + return PSNRET_NOERROR; +} + +void CSettingsPage::OnNotifyHelp() +{ + ShowHelpWindow(kSettingsTopic); +} + +bool CSettingsPage::OnCommand(unsigned code, unsigned itemID, LPARAM param) +{ + if (!_initMode) + { + if (code == EN_CHANGE && itemID == IDE_SETTINGS_MEM_SPIN_EDIT) + { + _memx_wasChanged = true; + Changed(); + } + /* + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_SETTINGS_MEM: + { + _wasChanged_MemLimit = true; + Changed(); + break; + } + } + } + */ + } + return CPropertyPage::OnCommand(code, itemID, param); +} + +bool CSettingsPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDX_SETTINGS_SINGLE_CLICK: + /* + EnableSubItems(); + break; + */ + case IDX_SETTINGS_SHOW_DOTS: + case IDX_SETTINGS_SHOW_SYSTEM_MENU: + case IDX_SETTINGS_SHOW_REAL_FILE_ICONS: + case IDX_SETTINGS_FULL_ROW: + case IDX_SETTINGS_SHOW_GRID: + case IDX_SETTINGS_ALTERNATIVE_SELECTION: + _wasChanged = true; + break; + + case IDX_SETTINGS_LARGE_PAGES: + _largePages_wasChanged = true; + break; + + case IDX_SETTINGS_MEM_SET: + { + _memx_wasChanged = true; + EnableSpin(IsButtonCheckedBool(IDX_SETTINGS_MEM_SET)); + break; + } + + default: + return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); + } + + Changed(); + return true; +} diff --git a/CPP/7zip/UI/FileManager/SettingsPage.h b/CPP/7zip/UI/FileManager/SettingsPage.h index fe97926ca..586b25352 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage.h +++ b/CPP/7zip/UI/FileManager/SettingsPage.h @@ -1,37 +1,37 @@ -// SettingsPage.h - -#ifndef ZIP7_INC_SETTINGS_PAGE_H -#define ZIP7_INC_SETTINGS_PAGE_H - -#include "../../../Windows/Control/PropertyPage.h" -// #include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Edit.h" - -class CSettingsPage: public NWindows::NControl::CPropertyPage -{ - bool _wasChanged; - bool _largePages_wasChanged; - bool _memx_wasChanged; - bool _initMode; - /* - bool _wasChanged_MemLimit; - NWindows::NControl::CComboBox _memCombo; - UStringVector _memLimitStrings; - UInt64 _ramSize; - UInt64 _ramSize_Defined; - - int AddMemComboItem(UInt64 size, UInt64 percents = 0, bool isDefault = false); - */ - - // void EnableSubItems(); - bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual bool OnInit() Z7_override; - virtual void OnNotifyHelp() Z7_override; - virtual LONG OnApply() Z7_override; - - void EnableSpin(bool enable); -public: -}; - -#endif +// SettingsPage.h + +#ifndef ZIP7_INC_SETTINGS_PAGE_H +#define ZIP7_INC_SETTINGS_PAGE_H + +#include "../../../Windows/Control/PropertyPage.h" +// #include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" + +class CSettingsPage: public NWindows::NControl::CPropertyPage +{ + bool _wasChanged; + bool _largePages_wasChanged; + bool _memx_wasChanged; + bool _initMode; + /* + bool _wasChanged_MemLimit; + NWindows::NControl::CComboBox _memCombo; + UStringVector _memLimitStrings; + UInt64 _ramSize; + UInt64 _ramSize_Defined; + + int AddMemComboItem(UInt64 size, UInt64 percents = 0, bool isDefault = false); + */ + + // void EnableSubItems(); + bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual bool OnInit() Z7_override; + virtual void OnNotifyHelp() Z7_override; + virtual LONG OnApply() Z7_override; + + void EnableSpin(bool enable); +public: +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SettingsPage.rc b/CPP/7zip/UI/FileManager/SettingsPage.rc index 6b4d3ba68..59ea5ee23 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage.rc +++ b/CPP/7zip/UI/FileManager/SettingsPage.rc @@ -1,22 +1,22 @@ -#include "SettingsPageRes.h" -#include "../../GuiCommon.rc" - -#define xc OPTIONS_PAGE_XC_SIZE -#define yc OPTIONS_PAGE_YC_SIZE - -IDD_SETTINGS MY_PAGE -#include "SettingsPage2.rc" - - -#ifdef UNDER_CE - -#undef m -#undef xc - -#define m 4 -#define xc (SMALL_PAGE_SIZE_X + 8) - -IDD_SETTINGS_2 MY_PAGE -#include "SettingsPage2.rc" - -#endif +#include "SettingsPageRes.h" +#include "../../GuiCommon.rc" + +#define xc OPTIONS_PAGE_XC_SIZE +#define yc OPTIONS_PAGE_YC_SIZE + +IDD_SETTINGS MY_PAGE +#include "SettingsPage2.rc" + + +#ifdef UNDER_CE + +#undef m +#undef xc + +#define m 4 +#define xc (SMALL_PAGE_SIZE_X + 8) + +IDD_SETTINGS_2 MY_PAGE +#include "SettingsPage2.rc" + +#endif diff --git a/CPP/7zip/UI/FileManager/SettingsPage2.rc b/CPP/7zip/UI/FileManager/SettingsPage2.rc index 10b341241..f67ee8099 100644 --- a/CPP/7zip/UI/FileManager/SettingsPage2.rc +++ b/CPP/7zip/UI/FileManager/SettingsPage2.rc @@ -1,37 +1,37 @@ -// #define g1xs 60 -// #include "MemDialogRes.h" - -#define save_y 144 -#define spin_y (save_y + 12) -#define spin_x_size 50 - -CAPTION "Settings" -BEGIN - MY_CONTROL_CHECKBOX ( "Show "".."" item", IDX_SETTINGS_SHOW_DOTS, m, 8, xc) - MY_CONTROL_CHECKBOX ( "Show real file &icons", IDX_SETTINGS_SHOW_REAL_FILE_ICONS, m, 22, xc) - MY_CONTROL_CHECKBOX ( "&Full row select", IDX_SETTINGS_FULL_ROW, m, 36, xc) - MY_CONTROL_CHECKBOX ( "Show &grid lines", IDX_SETTINGS_SHOW_GRID, m, 50, xc) - MY_CONTROL_CHECKBOX ( "&Single-click to open an item", IDX_SETTINGS_SINGLE_CLICK, m, 64, xc) - MY_CONTROL_CHECKBOX ( "&Alternative selection mode", IDX_SETTINGS_ALTERNATIVE_SELECTION, m, 78, xc) - - MY_CONTROL_CHECKBOX ( "Show system &menu", IDX_SETTINGS_SHOW_SYSTEM_MENU, m, 100, xc) - - MY_CONTROL_CHECKBOX ( "Use &large memory pages", IDX_SETTINGS_LARGE_PAGES, m, 122, xc) - - LTEXT "Maximum amount of RAM memory usage allowed to unpack archives:", - IDT_MEM_USAGE_EXTRACT, m, save_y, xc, 8 - MY_CONTROL_CHECKBOX_COLON(IDX_SETTINGS_MEM_SET, m + 10, spin_y + 1) - MY_CONTROL_EDIT_WITH_SPIN( - IDE_SETTINGS_MEM_SPIN_EDIT, - IDC_SETTINGS_MEM_SPIN, - "4", m + 30, spin_y, spin_x_size) - LTEXT "GB", IDT_SETTINGS_MEM_GB, m + 30 + spin_x_size + 8, spin_y + 2, xc - m - 30 - spin_x_size - 8, 8 - - // LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 140, xc, 8 - // COMBOBOX IDC_SETTINGS_MEM, m , 152, g1xs, yc - 152, MY_COMBO - // LTEXT "/ RAM", IDT_SETTINGS_MEM_RAM, m + g1xs + m, 154, xc - g1xs - m, MY_TEXT_NOPREFIX -END - -#undef save_y -#undef spin_y -#undef spin_x_size +// #define g1xs 60 +// #include "MemDialogRes.h" + +#define save_y 144 +#define spin_y (save_y + 12) +#define spin_x_size 50 + +CAPTION "Settings" +BEGIN + MY_CONTROL_CHECKBOX ( "Show "".."" item", IDX_SETTINGS_SHOW_DOTS, m, 8, xc) + MY_CONTROL_CHECKBOX ( "Show real file &icons", IDX_SETTINGS_SHOW_REAL_FILE_ICONS, m, 22, xc) + MY_CONTROL_CHECKBOX ( "&Full row select", IDX_SETTINGS_FULL_ROW, m, 36, xc) + MY_CONTROL_CHECKBOX ( "Show &grid lines", IDX_SETTINGS_SHOW_GRID, m, 50, xc) + MY_CONTROL_CHECKBOX ( "&Single-click to open an item", IDX_SETTINGS_SINGLE_CLICK, m, 64, xc) + MY_CONTROL_CHECKBOX ( "&Alternative selection mode", IDX_SETTINGS_ALTERNATIVE_SELECTION, m, 78, xc) + + MY_CONTROL_CHECKBOX ( "Show system &menu", IDX_SETTINGS_SHOW_SYSTEM_MENU, m, 100, xc) + + MY_CONTROL_CHECKBOX ( "Use &large memory pages", IDX_SETTINGS_LARGE_PAGES, m, 122, xc) + + LTEXT "Maximum amount of RAM memory usage allowed to unpack archives:", + IDT_MEM_USAGE_EXTRACT, m, save_y, xc, 8 + MY_CONTROL_CHECKBOX_COLON(IDX_SETTINGS_MEM_SET, m + 10, spin_y + 1) + MY_CONTROL_EDIT_WITH_SPIN( + IDE_SETTINGS_MEM_SPIN_EDIT, + IDC_SETTINGS_MEM_SPIN, + "4", m + 30, spin_y, spin_x_size) + LTEXT "GB", IDT_SETTINGS_MEM_GB, m + 30 + spin_x_size + 8, spin_y + 2, xc - m - 30 - spin_x_size - 8, 8 + + // LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 140, xc, 8 + // COMBOBOX IDC_SETTINGS_MEM, m , 152, g1xs, yc - 152, MY_COMBO + // LTEXT "/ RAM", IDT_SETTINGS_MEM_RAM, m + g1xs + m, 154, xc - g1xs - m, MY_TEXT_NOPREFIX +END + +#undef save_y +#undef spin_y +#undef spin_x_size diff --git a/CPP/7zip/UI/FileManager/SettingsPageRes.h b/CPP/7zip/UI/FileManager/SettingsPageRes.h index 483e51684..205daee74 100644 --- a/CPP/7zip/UI/FileManager/SettingsPageRes.h +++ b/CPP/7zip/UI/FileManager/SettingsPageRes.h @@ -1,23 +1,23 @@ -#define IDD_SETTINGS 2500 -#define IDD_SETTINGS_2 12500 - -#define IDX_SETTINGS_SHOW_DOTS 2501 -#define IDX_SETTINGS_SHOW_REAL_FILE_ICONS 2502 -#define IDX_SETTINGS_SHOW_SYSTEM_MENU 2503 -#define IDX_SETTINGS_FULL_ROW 2504 -#define IDX_SETTINGS_SHOW_GRID 2505 -#define IDX_SETTINGS_SINGLE_CLICK 2506 -#define IDX_SETTINGS_ALTERNATIVE_SELECTION 2507 -#define IDX_SETTINGS_LARGE_PAGES 2508 - -#define IDT_MEM_USAGE_EXTRACT 7816 - -#define IDX_SETTINGS_MEM_SET 100 -#define IDE_SETTINGS_MEM_SPIN_EDIT 101 -#define IDC_SETTINGS_MEM_SPIN 102 -#define IDT_SETTINGS_MEM_GB 103 - -// #define IDT_SETTINGS_MEM 100 -// #define IDC_SETTINGS_MEM 101 -// #define IDT_SETTINGS_MEM_RAM 102 -// #define IDT_COMPRESS_MEMORY 4017 +#define IDD_SETTINGS 2500 +#define IDD_SETTINGS_2 12500 + +#define IDX_SETTINGS_SHOW_DOTS 2501 +#define IDX_SETTINGS_SHOW_REAL_FILE_ICONS 2502 +#define IDX_SETTINGS_SHOW_SYSTEM_MENU 2503 +#define IDX_SETTINGS_FULL_ROW 2504 +#define IDX_SETTINGS_SHOW_GRID 2505 +#define IDX_SETTINGS_SINGLE_CLICK 2506 +#define IDX_SETTINGS_ALTERNATIVE_SELECTION 2507 +#define IDX_SETTINGS_LARGE_PAGES 2508 + +#define IDT_MEM_USAGE_EXTRACT 7816 + +#define IDX_SETTINGS_MEM_SET 100 +#define IDE_SETTINGS_MEM_SPIN_EDIT 101 +#define IDC_SETTINGS_MEM_SPIN 102 +#define IDT_SETTINGS_MEM_GB 103 + +// #define IDT_SETTINGS_MEM 100 +// #define IDC_SETTINGS_MEM 101 +// #define IDT_SETTINGS_MEM_RAM 102 +// #define IDT_COMPRESS_MEMORY 4017 diff --git a/CPP/7zip/UI/FileManager/SplitDialog.cpp b/CPP/7zip/UI/FileManager/SplitDialog.cpp index f92697b54..21d812c5e 100644 --- a/CPP/7zip/UI/FileManager/SplitDialog.cpp +++ b/CPP/7zip/UI/FileManager/SplitDialog.cpp @@ -1,114 +1,114 @@ -// SplitDialog.cpp - -#include "StdAfx.h" - -#include "../../../Windows/FileName.h" - -#include "LangUtils.h" - -#include "BrowseDialog.h" -#include "CopyDialogRes.h" -#include "SplitDialog.h" -#include "SplitUtils.h" -#include "resourceGui.h" - -using namespace NWindows; - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_SPLIT_PATH, - IDT_SPLIT_VOLUME -}; -#endif - - -bool CSplitDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_SPLIT); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - #endif - _pathCombo.Attach(GetItem(IDC_SPLIT_PATH)); - _volumeCombo.Attach(GetItem(IDC_SPLIT_VOLUME)); - - if (!FilePath.IsEmpty()) - { - UString title; - GetText(title); - title.Add_Space(); - title += FilePath; - SetText(title); - } - _pathCombo.SetText(Path); - AddVolumeItems(_volumeCombo); - _volumeCombo.SetCurSel(0); - NormalizeSize(); - return CModalDialog::OnInit(); -} - -bool CSplitDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - int bx1, bx2, by; - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDOK, bx2, by); - int yPos = ySize - my - by; - int xPos = xSize - mx - bx1; - - InvalidateRect(NULL); - - { - RECT r; - GetClientRectOfItem(IDB_SPLIT_PATH, r); - int bx = RECT_SIZE_X(r); - MoveItem(IDB_SPLIT_PATH, xSize - mx - bx, r.top, bx, RECT_SIZE_Y(r)); - ChangeSubWindowSizeX(_pathCombo, xSize - mx - mx - bx - mx); - } - - MoveItem(IDCANCEL, xPos, yPos, bx1, by); - MoveItem(IDOK, xPos - mx - bx2, yPos, bx2, by); - - return false; -} - -bool CSplitDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_SPLIT_PATH: - OnButtonSetPath(); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CSplitDialog::OnButtonSetPath() -{ - UString currentPath; - _pathCombo.GetText(currentPath); - // UString title = "Specify a location for output folder"; - const UString title = LangString(IDS_SET_FOLDER); - - UString resultPath; - if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) - return; - NFile::NName::NormalizeDirPathPrefix(resultPath); - _pathCombo.SetCurSel(-1); - _pathCombo.SetText(resultPath); -} - -void CSplitDialog::OnOK() -{ - _pathCombo.GetText(Path); - UString volumeString; - _volumeCombo.GetText(volumeString); - volumeString.Trim(); - if (!ParseVolumeSizes(volumeString, VolumeSizes) || VolumeSizes.Size() == 0) - { - ::MessageBoxW(*this, LangString(IDS_INCORRECT_VOLUME_SIZE), L"7-Zip", MB_ICONERROR); - return; - } - CModalDialog::OnOK(); -} +// SplitDialog.cpp + +#include "StdAfx.h" + +#include "../../../Windows/FileName.h" + +#include "LangUtils.h" + +#include "BrowseDialog.h" +#include "CopyDialogRes.h" +#include "SplitDialog.h" +#include "SplitUtils.h" +#include "resourceGui.h" + +using namespace NWindows; + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_SPLIT_PATH, + IDT_SPLIT_VOLUME +}; +#endif + + +bool CSplitDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_SPLIT); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + #endif + _pathCombo.Attach(GetItem(IDC_SPLIT_PATH)); + _volumeCombo.Attach(GetItem(IDC_SPLIT_VOLUME)); + + if (!FilePath.IsEmpty()) + { + UString title; + GetText(title); + title.Add_Space(); + title += FilePath; + SetText(title); + } + _pathCombo.SetText(Path); + AddVolumeItems(_volumeCombo); + _volumeCombo.SetCurSel(0); + NormalizeSize(); + return CModalDialog::OnInit(); +} + +bool CSplitDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDOK, bx2, by); + int yPos = ySize - my - by; + int xPos = xSize - mx - bx1; + + InvalidateRect(NULL); + + { + RECT r; + GetClientRectOfItem(IDB_SPLIT_PATH, r); + int bx = RECT_SIZE_X(r); + MoveItem(IDB_SPLIT_PATH, xSize - mx - bx, r.top, bx, RECT_SIZE_Y(r)); + ChangeSubWindowSizeX(_pathCombo, xSize - mx - mx - bx - mx); + } + + MoveItem(IDCANCEL, xPos, yPos, bx1, by); + MoveItem(IDOK, xPos - mx - bx2, yPos, bx2, by); + + return false; +} + +bool CSplitDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_SPLIT_PATH: + OnButtonSetPath(); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CSplitDialog::OnButtonSetPath() +{ + UString currentPath; + _pathCombo.GetText(currentPath); + // UString title = "Specify a location for output folder"; + const UString title = LangString(IDS_SET_FOLDER); + + UString resultPath; + if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) + return; + NFile::NName::NormalizeDirPathPrefix(resultPath); + _pathCombo.SetCurSel(-1); + _pathCombo.SetText(resultPath); +} + +void CSplitDialog::OnOK() +{ + _pathCombo.GetText(Path); + UString volumeString; + _volumeCombo.GetText(volumeString); + volumeString.Trim(); + if (!ParseVolumeSizes(volumeString, VolumeSizes) || VolumeSizes.Size() == 0) + { + ::MessageBoxW(*this, LangString(IDS_INCORRECT_VOLUME_SIZE), L"7-Zip", MB_ICONERROR); + return; + } + CModalDialog::OnOK(); +} diff --git a/CPP/7zip/UI/FileManager/SplitDialog.h b/CPP/7zip/UI/FileManager/SplitDialog.h index 82ddfaa72..f89713658 100644 --- a/CPP/7zip/UI/FileManager/SplitDialog.h +++ b/CPP/7zip/UI/FileManager/SplitDialog.h @@ -1,28 +1,28 @@ -// SplitDialog.h - -#ifndef ZIP7_INC_SPLIT_DIALOG_H -#define ZIP7_INC_SPLIT_DIALOG_H - -#include "../../../Windows/Control/Dialog.h" -#include "../../../Windows/Control/ComboBox.h" - -#include "SplitDialogRes.h" - -class CSplitDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox _pathCombo; - NWindows::NControl::CComboBox _volumeCombo; - virtual void OnOK() Z7_override; - virtual bool OnInit() Z7_override; - virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - void OnButtonSetPath(); -public: - UString FilePath; - UString Path; - CRecordVector VolumeSizes; - INT_PTR Create(HWND parentWindow = NULL) - { return CModalDialog::Create(IDD_SPLIT, parentWindow); } -}; - -#endif +// SplitDialog.h + +#ifndef ZIP7_INC_SPLIT_DIALOG_H +#define ZIP7_INC_SPLIT_DIALOG_H + +#include "../../../Windows/Control/Dialog.h" +#include "../../../Windows/Control/ComboBox.h" + +#include "SplitDialogRes.h" + +class CSplitDialog: public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CComboBox _pathCombo; + NWindows::NControl::CComboBox _volumeCombo; + virtual void OnOK() Z7_override; + virtual bool OnInit() Z7_override; + virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + void OnButtonSetPath(); +public: + UString FilePath; + UString Path; + CRecordVector VolumeSizes; + INT_PTR Create(HWND parentWindow = NULL) + { return CModalDialog::Create(IDD_SPLIT, parentWindow); } +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SplitDialog.rc b/CPP/7zip/UI/FileManager/SplitDialog.rc index cee8b650f..5a026e8ab 100644 --- a/CPP/7zip/UI/FileManager/SplitDialog.rc +++ b/CPP/7zip/UI/FileManager/SplitDialog.rc @@ -1,16 +1,16 @@ -#include "SplitDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 288 -#define yc 96 - -IDD_SPLIT DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Split File" -BEGIN - LTEXT "&Split to:", IDT_SPLIT_PATH, m, m, xc, 8 - COMBOBOX IDC_SPLIT_PATH, m, 20, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_SPLIT_PATH, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP - LTEXT "Split to &volumes, bytes:", IDT_SPLIT_VOLUME, m, 44, xc, 8 - COMBOBOX IDC_SPLIT_VOLUME, m, 56, 96, 52, MY_COMBO_WITH_EDIT - OK_CANCEL -END +#include "SplitDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 288 +#define yc 96 + +IDD_SPLIT DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Split File" +BEGIN + LTEXT "&Split to:", IDT_SPLIT_PATH, m, m, xc, 8 + COMBOBOX IDC_SPLIT_PATH, m, 20, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_SPLIT_PATH, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP + LTEXT "Split to &volumes, bytes:", IDT_SPLIT_VOLUME, m, 44, xc, 8 + COMBOBOX IDC_SPLIT_VOLUME, m, 56, 96, 52, MY_COMBO_WITH_EDIT + OK_CANCEL +END diff --git a/CPP/7zip/UI/FileManager/SplitDialogRes.h b/CPP/7zip/UI/FileManager/SplitDialogRes.h index f9747da9f..50584a147 100644 --- a/CPP/7zip/UI/FileManager/SplitDialogRes.h +++ b/CPP/7zip/UI/FileManager/SplitDialogRes.h @@ -1,8 +1,8 @@ -#define IDD_SPLIT 7300 - -#define IDT_SPLIT_PATH 7301 -#define IDT_SPLIT_VOLUME 7302 - -#define IDC_SPLIT_PATH 100 -#define IDB_SPLIT_PATH 101 -#define IDC_SPLIT_VOLUME 102 +#define IDD_SPLIT 7300 + +#define IDT_SPLIT_PATH 7301 +#define IDT_SPLIT_VOLUME 7302 + +#define IDC_SPLIT_PATH 100 +#define IDB_SPLIT_PATH 101 +#define IDC_SPLIT_VOLUME 102 diff --git a/CPP/7zip/UI/FileManager/SplitUtils.cpp b/CPP/7zip/UI/FileManager/SplitUtils.cpp index 0d0675e2f..1982afba9 100644 --- a/CPP/7zip/UI/FileManager/SplitUtils.cpp +++ b/CPP/7zip/UI/FileManager/SplitUtils.cpp @@ -1,96 +1,96 @@ -// SplitUtils.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringToInt.h" - -#include "SplitUtils.h" - -bool ParseVolumeSizes(const UString &s, CRecordVector &values) -{ - values.Clear(); - bool prevIsNumber = false; - for (unsigned i = 0; i < s.Len();) - { - wchar_t c = s[i++]; - if (c == L' ') - continue; - if (c == L'-') - return true; - if (prevIsNumber) - { - prevIsNumber = false; - unsigned numBits = 0; - switch (MyCharLower_Ascii(c)) - { - case 'b': continue; - case 'k': numBits = 10; break; - case 'm': numBits = 20; break; - case 'g': numBits = 30; break; - case 't': numBits = 40; break; - } - if (numBits != 0) - { - UInt64 &val = values.Back(); - if (val >= ((UInt64)1 << (64 - numBits))) - return false; - val <<= numBits; - - for (; i < s.Len(); i++) - if (s[i] == L' ') - break; - continue; - } - } - i--; - const wchar_t *start = s.Ptr(i); - const wchar_t *end; - UInt64 val = ConvertStringToUInt64(start, &end); - if (start == end) - return false; - if (val == 0) - return false; - values.Add(val); - prevIsNumber = true; - i += (unsigned)(end - start); - } - return true; -} - - -static const char * const k_Sizes[] = -{ - "10M" - , "100M" - , "1000M" - , "650M - CD" - , "700M - CD" - , "4092M - FAT" - , "4480M - DVD" // 4489 MiB limit - , "8128M - DVD DL" // 8147 MiB limit - , "23040M - BD" // 23866 MiB limit - // , "1457664 - 3.5\" floppy" -}; - -void AddVolumeItems(NWindows::NControl::CComboBox &combo) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Sizes); i++) - combo.AddString(CSysString(k_Sizes[i])); -} - -UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &volSizes) -{ - if (size == 0 || volSizes.Size() == 0) - return 1; - FOR_VECTOR (i, volSizes) - { - UInt64 volSize = volSizes[i]; - if (volSize >= size) - return i + 1; - size -= volSize; - } - UInt64 volSize = volSizes.Back(); - if (volSize == 0) - return (UInt64)(Int64)-1; - return volSizes.Size() + (size - 1) / volSize + 1; -} +// SplitUtils.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringToInt.h" + +#include "SplitUtils.h" + +bool ParseVolumeSizes(const UString &s, CRecordVector &values) +{ + values.Clear(); + bool prevIsNumber = false; + for (unsigned i = 0; i < s.Len();) + { + wchar_t c = s[i++]; + if (c == L' ') + continue; + if (c == L'-') + return true; + if (prevIsNumber) + { + prevIsNumber = false; + unsigned numBits = 0; + switch (MyCharLower_Ascii(c)) + { + case 'b': continue; + case 'k': numBits = 10; break; + case 'm': numBits = 20; break; + case 'g': numBits = 30; break; + case 't': numBits = 40; break; + } + if (numBits != 0) + { + UInt64 &val = values.Back(); + if (val >= ((UInt64)1 << (64 - numBits))) + return false; + val <<= numBits; + + for (; i < s.Len(); i++) + if (s[i] == L' ') + break; + continue; + } + } + i--; + const wchar_t *start = s.Ptr(i); + const wchar_t *end; + UInt64 val = ConvertStringToUInt64(start, &end); + if (start == end) + return false; + if (val == 0) + return false; + values.Add(val); + prevIsNumber = true; + i += (unsigned)(end - start); + } + return true; +} + + +static const char * const k_Sizes[] = +{ + "10M" + , "100M" + , "1000M" + , "650M - CD" + , "700M - CD" + , "4092M - FAT" + , "4480M - DVD" // 4489 MiB limit + , "8128M - DVD DL" // 8147 MiB limit + , "23040M - BD" // 23866 MiB limit + // , "1457664 - 3.5\" floppy" +}; + +void AddVolumeItems(NWindows::NControl::CComboBox &combo) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Sizes); i++) + combo.AddString(CSysString(k_Sizes[i])); +} + +UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &volSizes) +{ + if (size == 0 || volSizes.Size() == 0) + return 1; + FOR_VECTOR (i, volSizes) + { + UInt64 volSize = volSizes[i]; + if (volSize >= size) + return i + 1; + size -= volSize; + } + UInt64 volSize = volSizes.Back(); + if (volSize == 0) + return (UInt64)(Int64)-1; + return volSizes.Size() + (size - 1) / volSize + 1; +} diff --git a/CPP/7zip/UI/FileManager/SplitUtils.h b/CPP/7zip/UI/FileManager/SplitUtils.h index 80b6ef9ee..d1d44e460 100644 --- a/CPP/7zip/UI/FileManager/SplitUtils.h +++ b/CPP/7zip/UI/FileManager/SplitUtils.h @@ -1,15 +1,15 @@ -// SplitUtils.h - -#ifndef ZIP7_INC_SPLIT_UTILS_H -#define ZIP7_INC_SPLIT_UTILS_H - -#include "../../../Common/MyTypes.h" -#include "../../../Common/MyString.h" - -#include "../../../Windows/Control/ComboBox.h" - -bool ParseVolumeSizes(const UString &s, CRecordVector &values); -void AddVolumeItems(NWindows::NControl::CComboBox &volumeCombo); -UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &volSizes); - -#endif +// SplitUtils.h + +#ifndef ZIP7_INC_SPLIT_UTILS_H +#define ZIP7_INC_SPLIT_UTILS_H + +#include "../../../Common/MyTypes.h" +#include "../../../Common/MyString.h" + +#include "../../../Windows/Control/ComboBox.h" + +bool ParseVolumeSizes(const UString &s, CRecordVector &values); +void AddVolumeItems(NWindows::NControl::CComboBox &volumeCombo); +UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector &volSizes); + +#endif diff --git a/CPP/7zip/UI/FileManager/StdAfx.cpp b/CPP/7zip/UI/FileManager/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/FileManager/StdAfx.cpp +++ b/CPP/7zip/UI/FileManager/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/FileManager/StdAfx.h b/CPP/7zip/UI/FileManager/StdAfx.h index 2b98a3a0b..7790eae66 100644 --- a/CPP/7zip/UI/FileManager/StdAfx.h +++ b/CPP/7zip/UI/FileManager/StdAfx.h @@ -1,67 +1,67 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#include "../../../Common/Common.h" - -#endif - -/* -WINVER and _WIN32_WINNT - -MSVC6 / 2003sdk: -{ - doesn't set _WIN32_WINNT - if WINVER is not set sets WINVER to value: - 0x0400 : MSVC6 - 0x0501 : Windows Server 2003 PSDK / 2003 R2 PSDK -} - -SDK for Win7 (and later) -{ - sets _WIN32_WINNT if it's not set. - sets WINVER if it's not set. - includes that does: -#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_) - #define _WIN32_WINNT 0x0601 // in win7 sdk - #define _WIN32_WINNT 0x0A00 // in win10 sdk -#endif -#ifndef WINVER - #ifdef _WIN32_WINNT - #define WINVER _WIN32_WINNT - else - #define WINVER 0x0601 // in win7 sdk - #define WINVER 0x0A00 // in win10 sdk - endif -#endif -} - -Some GUI structures defined by windows will be larger, -If (_WIN32_WINNT) value is larger. - -Also if we send sizeof(win_gui_struct) to some windows function, -and we compile that code with big (_WIN32_WINNT) value, -the window function in old Windows can fail, if that old Windows -doesn't understand new big version of (win_gui_struct) compiled -with big (_WIN32_WINNT) value. - -So it's better to define smallest (_WIN32_WINNT) value here. -In 7-Zip FM we use some functions that require (_WIN32_WINNT == 0x0500). -So it's simpler to define (_WIN32_WINNT == 0x0500) here. -If we define (_WIN32_WINNT == 0x0400) here, we need some manual -declarations for functions and macros that require (0x0500) functions. -Also libs must contain these (0x0500+) functions. - -Some code in 7-zip FM uses also CommCtrl.h structures -that depend from (_WIN32_IE) value. But default -(_WIN32_IE) value from probably is OK for us. -So we don't set _WIN32_IE here. -default _WIN32_IE value set by : - 0x501 2003sdk - 0xa00 win10 sdk -*/ +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#include "../../../Common/Common.h" + +#endif + +/* +WINVER and _WIN32_WINNT + +MSVC6 / 2003sdk: +{ + doesn't set _WIN32_WINNT + if WINVER is not set sets WINVER to value: + 0x0400 : MSVC6 + 0x0501 : Windows Server 2003 PSDK / 2003 R2 PSDK +} + +SDK for Win7 (and later) +{ + sets _WIN32_WINNT if it's not set. + sets WINVER if it's not set. + includes that does: +#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_) + #define _WIN32_WINNT 0x0601 // in win7 sdk + #define _WIN32_WINNT 0x0A00 // in win10 sdk +#endif +#ifndef WINVER + #ifdef _WIN32_WINNT + #define WINVER _WIN32_WINNT + else + #define WINVER 0x0601 // in win7 sdk + #define WINVER 0x0A00 // in win10 sdk + endif +#endif +} + +Some GUI structures defined by windows will be larger, +If (_WIN32_WINNT) value is larger. + +Also if we send sizeof(win_gui_struct) to some windows function, +and we compile that code with big (_WIN32_WINNT) value, +the window function in old Windows can fail, if that old Windows +doesn't understand new big version of (win_gui_struct) compiled +with big (_WIN32_WINNT) value. + +So it's better to define smallest (_WIN32_WINNT) value here. +In 7-Zip FM we use some functions that require (_WIN32_WINNT == 0x0500). +So it's simpler to define (_WIN32_WINNT == 0x0500) here. +If we define (_WIN32_WINNT == 0x0400) here, we need some manual +declarations for functions and macros that require (0x0500) functions. +Also libs must contain these (0x0500+) functions. + +Some code in 7-zip FM uses also CommCtrl.h structures +that depend from (_WIN32_IE) value. But default +(_WIN32_IE) value from probably is OK for us. +So we don't set _WIN32_IE here. +default _WIN32_IE value set by : + 0x501 2003sdk + 0xa00 win10 sdk +*/ diff --git a/CPP/7zip/UI/FileManager/StringUtils.cpp b/CPP/7zip/UI/FileManager/StringUtils.cpp index 2e37afb22..4641d1511 100644 --- a/CPP/7zip/UI/FileManager/StringUtils.cpp +++ b/CPP/7zip/UI/FileManager/StringUtils.cpp @@ -1,39 +1,39 @@ -// StringUtils.cpp - -#include "StdAfx.h" - -#include "StringUtils.h" - -void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2) -{ - dest1.Empty(); - dest2.Empty(); - bool quoteMode = false; - for (unsigned i = 0; i < src.Len(); i++) - { - const wchar_t c = src[i]; - if (c == '\"') - quoteMode = !quoteMode; - else if (c == ' ' && !quoteMode) - { - dest2 = src.Ptr(i + 1); - return; - } - else - dest1 += c; - } -} - -/* -UString JoinStrings(const UStringVector &srcStrings) -{ - UString s; - FOR_VECTOR (i, srcStrings) - { - if (i != 0) - s.Add_Space(); - s += srcStrings[i]; - } - return s; -} -*/ +// StringUtils.cpp + +#include "StdAfx.h" + +#include "StringUtils.h" + +void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2) +{ + dest1.Empty(); + dest2.Empty(); + bool quoteMode = false; + for (unsigned i = 0; i < src.Len(); i++) + { + const wchar_t c = src[i]; + if (c == '\"') + quoteMode = !quoteMode; + else if (c == ' ' && !quoteMode) + { + dest2 = src.Ptr(i + 1); + return; + } + else + dest1 += c; + } +} + +/* +UString JoinStrings(const UStringVector &srcStrings) +{ + UString s; + FOR_VECTOR (i, srcStrings) + { + if (i != 0) + s.Add_Space(); + s += srcStrings[i]; + } + return s; +} +*/ diff --git a/CPP/7zip/UI/FileManager/StringUtils.h b/CPP/7zip/UI/FileManager/StringUtils.h index faca08e0d..37aad3ae6 100644 --- a/CPP/7zip/UI/FileManager/StringUtils.h +++ b/CPP/7zip/UI/FileManager/StringUtils.h @@ -1,11 +1,11 @@ -// StringUtils.h - -#ifndef ZIP7_INC_STRING_UTILS_H -#define ZIP7_INC_STRING_UTILS_H - -#include "../../../Common/MyString.h" - -void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2); -// UString JoinStrings(const UStringVector &srcStrings); - -#endif +// StringUtils.h + +#ifndef ZIP7_INC_STRING_UTILS_H +#define ZIP7_INC_STRING_UTILS_H + +#include "../../../Common/MyString.h" + +void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2); +// UString JoinStrings(const UStringVector &srcStrings); + +#endif diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp index 91e4b008c..72fe5e727 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp +++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp @@ -1,351 +1,351 @@ -// SysIconUtils.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../../../Common/StringConvert.h" -#endif - -#include "../../../Windows/FileDir.h" - -#include "SysIconUtils.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -CExtToIconMap g_Ext_to_Icon_Map; - -int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl) -{ - LPITEMIDLIST pidl = NULL; - SHGetSpecialFolderLocation(NULL, csidl, &pidl); - if (pidl) - { - SHFILEINFO shFileInfo; - shFileInfo.iIcon = -1; - const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), - FILE_ATTRIBUTE_DIRECTORY, - &shFileInfo, sizeof(shFileInfo), - SHGFI_PIDL | SHGFI_SYSICONINDEX); - /* - IMalloc *pMalloc; - SHGetMalloc(&pMalloc); - if (pMalloc) - { - pMalloc->Free(pidl); - pMalloc->Release(); - } - */ - // we use OLE2.dll function here - CoTaskMemFree(pidl); - if (res) - return shFileInfo.iIcon; - } - return -1; -} - -#ifndef _UNICODE -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -typedef DWORD_PTR (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); - -static struct C_SHGetFileInfo_Init -{ - Func_SHGetFileInfoW f_SHGetFileInfoW; - C_SHGetFileInfo_Init() - { - f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS( - Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"), - "SHGetFileInfoW"); - // f_SHGetFileInfoW = NULL; // for debug - } -} g_SHGetFileInfo_Init; -#endif - -#ifdef _UNICODE -#define My_SHGetFileInfoW SHGetFileInfoW -#else -static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags) -{ - if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW) - return 0; - return g_SHGetFileInfo_Init.f_SHGetFileInfoW(pszPath, attrib, psfi, cbFileInfo, uFlags); -} -#endif - -DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( - CFSTR path, DWORD attrib, int &iconIndex) -{ -#ifndef _UNICODE - if (!g_IsNT || !g_SHGetFileInfo_Init.f_SHGetFileInfoW) - { - SHFILEINFO shFileInfo; - // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); - shFileInfo.iIcon = -1; // optional - const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), - attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE, - &shFileInfo, sizeof(shFileInfo), - SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); - iconIndex = shFileInfo.iIcon; - return res; - } - else -#endif - { - SHFILEINFOW shFileInfo; - // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); - shFileInfo.iIcon = -1; // optional - const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), - attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE, - &shFileInfo, sizeof(shFileInfo), - SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); - // (shFileInfo.iIcon == 0) returned for unknown extensions and files without extension - iconIndex = shFileInfo.iIcon; - // we use SHGFI_USEFILEATTRIBUTES, and - // (res != 0) is expected for main cases, even if there are no such file. - // (res == 0) for path with kSuperPrefix \\?\ - // Also SHGFI_USEFILEATTRIBUTES still returns icon inside exe. - // So we can use SHGFI_USEFILEATTRIBUTES for any case. - // UString temp = fs2us(path); // for debug - // UString tempName = temp.Ptr(temp.ReverseFind_PathSepar() + 1); // for debug - // iconIndex = -1; // for debug - return res; - } -} - -int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib) -{ - int iconIndex = -1; - if (!Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( - path, attrib, iconIndex)) - iconIndex = -1; - return iconIndex; -} - - -HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - CFSTR path, DWORD attrib, Int32 *iconIndex) -{ - *iconIndex = -1; - int iconIndexTemp; - if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( - path, attrib, iconIndexTemp)) - { - *iconIndex = iconIndexTemp; - return S_OK; - } - return GetLastError_noZero_HRESULT(); -} - -/* -DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - SHFILEINFO shFileInfo; - shFileInfo.szTypeName[0] = 0; - DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo, - sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); - if (typeName) - *typeName = GetUnicodeString(shFileInfo.szTypeName); - iconIndex = shFileInfo.iIcon; - return res; - } - else - #endif - { - SHFILEINFOW shFileInfo; - shFileInfo.szTypeName[0] = 0; - DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo, - sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); - if (typeName) - *typeName = shFileInfo.szTypeName; - iconIndex = shFileInfo.iIcon; - return res; - } -} -*/ - -static int FindInSorted_Attrib(const CRecordVector &vect, DWORD attrib, unsigned &insertPos) -{ - unsigned left = 0, right = vect.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const DWORD midAttrib = vect[mid].Attrib; - if (attrib == midAttrib) - return (int)mid; - if (attrib < midAttrib) - right = mid; - else - left = mid + 1; - } - insertPos = left; - return -1; -} - -static int FindInSorted_Ext(const CObjectVector &vect, const wchar_t *ext, unsigned &insertPos) -{ - unsigned left = 0, right = vect.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const int compare = MyStringCompareNoCase(ext, vect[mid].Ext); - if (compare == 0) - return (int)mid; - if (compare < 0) - right = mid; - else - left = mid + 1; - } - insertPos = left; - return -1; -} - - -// bool DoItemAlwaysStart(const UString &name); - -int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */) -{ - int dotPos = -1; - unsigned i; - for (i = 0;; i++) - { - const wchar_t c = fileName[i]; - if (c == 0) - break; - if (c == '.') - dotPos = (int)i; - // we don't need IS_PATH_SEPAR check, because (fileName) doesn't include path prefix. - // if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1; - } - - /* - if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0) - { - char s[256]; - sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib); - OutputDebugStringA(s); - OutputDebugStringW(fileName); - } - */ - - if ((attrib & FILE_ATTRIBUTE_DIRECTORY) || dotPos < 0) - for (unsigned k = 0;; k++) - { - if (k >= 2) - return -1; - unsigned insertPos = 0; - const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos); - if (index >= 0) - { - // if (typeName) *typeName = _attribMap[index].TypeName; - return _attribMap[(unsigned)index].IconIndex; - } - CAttribIconPair pair; - pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path( - #ifdef UNDER_CE - FTEXT("\\") - #endif - FTEXT("__DIR__") - , attrib - // , pair.TypeName - ); - if (_attribMap.Size() < (1u << 16) // we limit cache size - || attrib < (1u << 15)) // we want to put all items with basic attribs to cache - { - /* - char s[256]; - sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib); - OutputDebugStringA(s); - */ - pair.Attrib = attrib; - _attribMap.Insert(insertPos, pair); - // if (typeName) *typeName = pair.TypeName; - return pair.IconIndex; - } - if (pair.IconIndex >= 0) - return pair.IconIndex; - attrib = (attrib & FILE_ATTRIBUTE_DIRECTORY) ? - FILE_ATTRIBUTE_DIRECTORY : - FILE_ATTRIBUTE_ARCHIVE; - } - - CObjectVector &map = - (attrib & FILE_ATTRIBUTE_COMPRESSED) ? - _extMap_Compressed : _extMap_Normal; - const wchar_t *ext = fileName + dotPos + 1; - unsigned insertPos = 0; - const int index = FindInSorted_Ext(map, ext, insertPos); - if (index >= 0) - { - const CExtIconPair &pa = map[index]; - // if (typeName) *typeName = pa.TypeName; - return pa.IconIndex; - } - - for (i = 0;; i++) - { - const wchar_t c = ext[i]; - if (c == 0) - break; - if (c < L'0' || c > L'9') - break; - } - if (i != 0 && ext[i] == 0) - { - // Shell_GetFileInfo_SysIconIndex_for_Path is too slow for big number of split extensions: .001, .002, .003 - if (!SplitIconIndex_Defined) - { - Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( - #ifdef UNDER_CE - FTEXT("\\") - #endif - FTEXT("__FILE__.001"), FILE_ATTRIBUTE_ARCHIVE, SplitIconIndex); - SplitIconIndex_Defined = true; - } - return SplitIconIndex; - } - - CExtIconPair pair; - pair.Ext = ext; - pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path( - us2fs(fileName + dotPos), - attrib & FILE_ATTRIBUTE_COMPRESSED ? - FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED: - FILE_ATTRIBUTE_ARCHIVE); - if (map.Size() < (1u << 16) // we limit cache size - // || DoItemAlwaysStart(fileName + dotPos) // we want some popular extensions in cache - ) - map.Insert(insertPos, pair); - // if (typeName) *typeName = pair.TypeName; - return pair.IconIndex; -} - - -HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons) -{ - SHFILEINFO shFileInfo; - // shFileInfo.hIcon = NULL; // optional - const DWORD_PTR res = SHGetFileInfo(TEXT(""), - /* FILE_ATTRIBUTE_ARCHIVE | */ - FILE_ATTRIBUTE_DIRECTORY, - &shFileInfo, sizeof(shFileInfo), - SHGFI_USEFILEATTRIBUTES | - SHGFI_SYSICONINDEX | - (smallIcons ? SHGFI_SMALLICON : SHGFI_LARGEICON)); -#if 0 - // (shFileInfo.hIcon == NULL), because we don't use SHGFI_ICON. - // so DestroyIcon() is not required - if (res && shFileInfo.hIcon) // unexpected - DestroyIcon(shFileInfo.hIcon); -#endif - return (HIMAGELIST)res; -} +// SysIconUtils.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../../../Common/StringConvert.h" +#endif + +#include "../../../Windows/FileDir.h" + +#include "SysIconUtils.h" + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +CExtToIconMap g_Ext_to_Icon_Map; + +int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl) +{ + LPITEMIDLIST pidl = NULL; + SHGetSpecialFolderLocation(NULL, csidl, &pidl); + if (pidl) + { + SHFILEINFO shFileInfo; + shFileInfo.iIcon = -1; + const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), + FILE_ATTRIBUTE_DIRECTORY, + &shFileInfo, sizeof(shFileInfo), + SHGFI_PIDL | SHGFI_SYSICONINDEX); + /* + IMalloc *pMalloc; + SHGetMalloc(&pMalloc); + if (pMalloc) + { + pMalloc->Free(pidl); + pMalloc->Release(); + } + */ + // we use OLE2.dll function here + CoTaskMemFree(pidl); + if (res) + return shFileInfo.iIcon; + } + return -1; +} + +#ifndef _UNICODE +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +typedef DWORD_PTR (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); + +static struct C_SHGetFileInfo_Init +{ + Func_SHGetFileInfoW f_SHGetFileInfoW; + C_SHGetFileInfo_Init() + { + f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS( + Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"), + "SHGetFileInfoW"); + // f_SHGetFileInfoW = NULL; // for debug + } +} g_SHGetFileInfo_Init; +#endif + +#ifdef _UNICODE +#define My_SHGetFileInfoW SHGetFileInfoW +#else +static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags) +{ + if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW) + return 0; + return g_SHGetFileInfo_Init.f_SHGetFileInfoW(pszPath, attrib, psfi, cbFileInfo, uFlags); +} +#endif + +DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + CFSTR path, DWORD attrib, int &iconIndex) +{ +#ifndef _UNICODE + if (!g_IsNT || !g_SHGetFileInfo_Init.f_SHGetFileInfoW) + { + SHFILEINFO shFileInfo; + // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); + shFileInfo.iIcon = -1; // optional + const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), + attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE, + &shFileInfo, sizeof(shFileInfo), + SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); + iconIndex = shFileInfo.iIcon; + return res; + } + else +#endif + { + SHFILEINFOW shFileInfo; + // ZeroMemory(&shFileInfo, sizeof(shFileInfo)); + shFileInfo.iIcon = -1; // optional + const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), + attrib ? attrib : FILE_ATTRIBUTE_ARCHIVE, + &shFileInfo, sizeof(shFileInfo), + SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX); + // (shFileInfo.iIcon == 0) returned for unknown extensions and files without extension + iconIndex = shFileInfo.iIcon; + // we use SHGFI_USEFILEATTRIBUTES, and + // (res != 0) is expected for main cases, even if there are no such file. + // (res == 0) for path with kSuperPrefix "\\?\" + // Also SHGFI_USEFILEATTRIBUTES still returns icon inside exe. + // So we can use SHGFI_USEFILEATTRIBUTES for any case. + // UString temp = fs2us(path); // for debug + // UString tempName = temp.Ptr(temp.ReverseFind_PathSepar() + 1); // for debug + // iconIndex = -1; // for debug + return res; + } +} + +int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib) +{ + int iconIndex = -1; + if (!Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + path, attrib, iconIndex)) + iconIndex = -1; + return iconIndex; +} + + +HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + CFSTR path, DWORD attrib, Int32 *iconIndex) +{ + *iconIndex = -1; + int iconIndexTemp; + if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + path, attrib, iconIndexTemp)) + { + *iconIndex = iconIndexTemp; + return S_OK; + } + return GetLastError_noZero_HRESULT(); +} + +/* +DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + SHFILEINFO shFileInfo; + shFileInfo.szTypeName[0] = 0; + DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo, + sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); + if (typeName) + *typeName = GetUnicodeString(shFileInfo.szTypeName); + iconIndex = shFileInfo.iIcon; + return res; + } + else + #endif + { + SHFILEINFOW shFileInfo; + shFileInfo.szTypeName[0] = 0; + DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_ARCHIVE | attrib, &shFileInfo, + sizeof(shFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME); + if (typeName) + *typeName = shFileInfo.szTypeName; + iconIndex = shFileInfo.iIcon; + return res; + } +} +*/ + +static int FindInSorted_Attrib(const CRecordVector &vect, DWORD attrib, unsigned &insertPos) +{ + unsigned left = 0, right = vect.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const DWORD midAttrib = vect[mid].Attrib; + if (attrib == midAttrib) + return (int)mid; + if (attrib < midAttrib) + right = mid; + else + left = mid + 1; + } + insertPos = left; + return -1; +} + +static int FindInSorted_Ext(const CObjectVector &vect, const wchar_t *ext, unsigned &insertPos) +{ + unsigned left = 0, right = vect.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const int compare = MyStringCompareNoCase(ext, vect[mid].Ext); + if (compare == 0) + return (int)mid; + if (compare < 0) + right = mid; + else + left = mid + 1; + } + insertPos = left; + return -1; +} + + +// bool DoItemAlwaysStart(const UString &name); + +int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */) +{ + int dotPos = -1; + unsigned i; + for (i = 0;; i++) + { + const wchar_t c = fileName[i]; + if (c == 0) + break; + if (c == '.') + dotPos = (int)i; + // we don't need IS_PATH_SEPAR check, because (fileName) doesn't include path prefix. + // if (IS_PATH_SEPAR(c) || c == ':') dotPos = -1; + } + + /* + if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0) + { + char s[256]; + sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib); + OutputDebugStringA(s); + OutputDebugStringW(fileName); + } + */ + + if ((attrib & FILE_ATTRIBUTE_DIRECTORY) || dotPos < 0) + for (unsigned k = 0;; k++) + { + if (k >= 2) + return -1; + unsigned insertPos = 0; + const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos); + if (index >= 0) + { + // if (typeName) *typeName = _attribMap[index].TypeName; + return _attribMap[(unsigned)index].IconIndex; + } + CAttribIconPair pair; + pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path( + #ifdef UNDER_CE + FTEXT("\\") + #endif + FTEXT("__DIR__") + , attrib + // , pair.TypeName + ); + if (_attribMap.Size() < (1u << 16) // we limit cache size + || attrib < (1u << 15)) // we want to put all items with basic attribs to cache + { + /* + char s[256]; + sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib); + OutputDebugStringA(s); + */ + pair.Attrib = attrib; + _attribMap.Insert(insertPos, pair); + // if (typeName) *typeName = pair.TypeName; + return pair.IconIndex; + } + if (pair.IconIndex >= 0) + return pair.IconIndex; + attrib = (attrib & FILE_ATTRIBUTE_DIRECTORY) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + } + + CObjectVector &map = + (attrib & FILE_ATTRIBUTE_COMPRESSED) ? + _extMap_Compressed : _extMap_Normal; + const wchar_t *ext = fileName + dotPos + 1; + unsigned insertPos = 0; + const int index = FindInSorted_Ext(map, ext, insertPos); + if (index >= 0) + { + const CExtIconPair &pa = map[index]; + // if (typeName) *typeName = pa.TypeName; + return pa.IconIndex; + } + + for (i = 0;; i++) + { + const wchar_t c = ext[i]; + if (c == 0) + break; + if (c < L'0' || c > L'9') + break; + } + if (i != 0 && ext[i] == 0) + { + // Shell_GetFileInfo_SysIconIndex_for_Path is too slow for big number of split extensions: .001, .002, .003 + if (!SplitIconIndex_Defined) + { + Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + #ifdef UNDER_CE + FTEXT("\\") + #endif + FTEXT("__FILE__.001"), FILE_ATTRIBUTE_ARCHIVE, SplitIconIndex); + SplitIconIndex_Defined = true; + } + return SplitIconIndex; + } + + CExtIconPair pair; + pair.Ext = ext; + pair.IconIndex = Shell_GetFileInfo_SysIconIndex_for_Path( + us2fs(fileName + dotPos), + attrib & FILE_ATTRIBUTE_COMPRESSED ? + FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED: + FILE_ATTRIBUTE_ARCHIVE); + if (map.Size() < (1u << 16) // we limit cache size + // || DoItemAlwaysStart(fileName + dotPos) // we want some popular extensions in cache + ) + map.Insert(insertPos, pair); + // if (typeName) *typeName = pair.TypeName; + return pair.IconIndex; +} + + +HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons) +{ + SHFILEINFO shFileInfo; + // shFileInfo.hIcon = NULL; // optional + const DWORD_PTR res = SHGetFileInfo(TEXT(""), + /* FILE_ATTRIBUTE_ARCHIVE | */ + FILE_ATTRIBUTE_DIRECTORY, + &shFileInfo, sizeof(shFileInfo), + SHGFI_USEFILEATTRIBUTES | + SHGFI_SYSICONINDEX | + (smallIcons ? SHGFI_SMALLICON : SHGFI_LARGEICON)); +#if 0 + // (shFileInfo.hIcon == NULL), because we don't use SHGFI_ICON. + // so DestroyIcon() is not required + if (res && shFileInfo.hIcon) // unexpected + DestroyIcon(shFileInfo.hIcon); +#endif + return (HIMAGELIST)res; +} diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.h b/CPP/7zip/UI/FileManager/SysIconUtils.h index 080fc98f3..975ce255b 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.h +++ b/CPP/7zip/UI/FileManager/SysIconUtils.h @@ -1,65 +1,65 @@ -// SysIconUtils.h - -#ifndef ZIP7_INC_SYS_ICON_UTILS_H -#define ZIP7_INC_SYS_ICON_UTILS_H - -#include "../../../Common/MyWindows.h" - -#include - -#include "../../../Common/MyString.h" - -struct CExtIconPair -{ - UString Ext; - int IconIndex; - // UString TypeName; - // int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); } -}; - -struct CAttribIconPair -{ - DWORD Attrib; - int IconIndex; - // UString TypeName; - // int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); } -}; - - -struct CExtToIconMap -{ - CRecordVector _attribMap; - CObjectVector _extMap_Normal; - CObjectVector _extMap_Compressed; - int SplitIconIndex; - int SplitIconIndex_Defined; - - CExtToIconMap(): SplitIconIndex_Defined(false) {} - - void Clear() - { - SplitIconIndex_Defined = false; - _extMap_Normal.Clear(); - _extMap_Compressed.Clear(); - _attribMap.Clear(); - } - int GetIconIndex_DIR(DWORD attrib = FILE_ATTRIBUTE_DIRECTORY) - { - return GetIconIndex(attrib, L"__DIR__"); - } - int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */); -}; - -extern CExtToIconMap g_Ext_to_Icon_Map; - -DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( - CFSTR path, DWORD attrib, int &iconIndex); -HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( - CFSTR path, DWORD attrib, Int32 *iconIndex); -int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib); - -int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl); - -HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons); - -#endif +// SysIconUtils.h + +#ifndef ZIP7_INC_SYS_ICON_UTILS_H +#define ZIP7_INC_SYS_ICON_UTILS_H + +#include "../../../Common/MyWindows.h" + +#include + +#include "../../../Common/MyString.h" + +struct CExtIconPair +{ + UString Ext; + int IconIndex; + // UString TypeName; + // int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); } +}; + +struct CAttribIconPair +{ + DWORD Attrib; + int IconIndex; + // UString TypeName; + // int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); } +}; + + +struct CExtToIconMap +{ + CRecordVector _attribMap; + CObjectVector _extMap_Normal; + CObjectVector _extMap_Compressed; + int SplitIconIndex; + int SplitIconIndex_Defined; + + CExtToIconMap(): SplitIconIndex_Defined(false) {} + + void Clear() + { + SplitIconIndex_Defined = false; + _extMap_Normal.Clear(); + _extMap_Compressed.Clear(); + _attribMap.Clear(); + } + int GetIconIndex_DIR(DWORD attrib = FILE_ATTRIBUTE_DIRECTORY) + { + return GetIconIndex(attrib, L"__DIR__"); + } + int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */); +}; + +extern CExtToIconMap g_Ext_to_Icon_Map; + +DWORD_PTR Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef( + CFSTR path, DWORD attrib, int &iconIndex); +HRESULT Shell_GetFileInfo_SysIconIndex_for_Path_return_HRESULT( + CFSTR path, DWORD attrib, Int32 *iconIndex); +int Shell_GetFileInfo_SysIconIndex_for_Path(CFSTR path, DWORD attrib); + +int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl); + +HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons); + +#endif diff --git a/CPP/7zip/UI/FileManager/SystemPage.cpp b/CPP/7zip/UI/FileManager/SystemPage.cpp index db1190904..efa98a8cc 100644 --- a/CPP/7zip/UI/FileManager/SystemPage.cpp +++ b/CPP/7zip/UI/FileManager/SystemPage.cpp @@ -1,472 +1,472 @@ -// SystemPage.cpp - -#include "StdAfx.h" - -#include "../../../Common/MyWindows.h" - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../Common/Defs.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/ErrorMsg.h" - -#include "HelpUtils.h" -#include "IFolder.h" -#include "LangUtils.h" -#include "PropertyNameRes.h" -#include "SystemPage.h" -#include "SystemPageRes.h" - -using namespace NWindows; - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_SYSTEM_ASSOCIATE -}; -#endif - -#define kSystemTopic "FM/options.htm#system" - -CSysString CModifiedExtInfo::GetString() const -{ - const char *s; - if (State == kExtState_7Zip) - s = "7-Zip"; - else if (State == kExtState_Clear) - s = ""; - else if (Other7Zip) - s = "[7-Zip]"; - else - return ProgramKey; - return CSysString (s); -} - - -int CSystemPage::AddIcon(const UString &iconPath, int iconIndex) -{ - if (iconPath.IsEmpty()) - return -1; - if (iconIndex == -1) - iconIndex = 0; - - HICON hicon; - - #ifdef UNDER_CE - ExtractIconExW(iconPath, iconIndex, NULL, &hicon, 1); - if (!hicon) - #else - // we expand path from REG_EXPAND_SZ registry item. - UString path; - const DWORD size = MAX_PATH + 10; - const DWORD needLen = ::ExpandEnvironmentStringsW(iconPath, path.GetBuf(size + 2), size); - path.ReleaseBuf_CalcLen(size); - if (needLen == 0 || needLen >= size) - path = iconPath; - const UINT num = ExtractIconExW(path, iconIndex, NULL, &hicon, 1); - if (num != 1 || !hicon) - #endif - return -1; - - _imageList.AddIcon(hicon); - DestroyIcon(hicon); - return (int)(_numIcons++); -} - - -void CSystemPage::RefreshListItem(unsigned group, unsigned listIndex) -{ - const CAssoc &assoc = _items[GetRealIndex(listIndex)]; - _listView.SetSubItem(listIndex, group + 1, assoc.Pair[group].GetString()); - LVITEMW newItem; - memset(&newItem, 0, sizeof(newItem)); - newItem.iItem = (int)listIndex; - newItem.mask = LVIF_IMAGE; - newItem.iImage = assoc.GetIconIndex(); - _listView.SetItem(&newItem); -} - - -void CSystemPage::ChangeState(unsigned group, const CUIntVector &indices) -{ - if (indices.IsEmpty()) - return; - - bool thereAreClearItems = false; - unsigned counters[3] = { 0, 0, 0 }; - - unsigned i; - for (i = 0; i < indices.Size(); i++) - { - const CModifiedExtInfo &mi = _items[GetRealIndex(indices[i])].Pair[group]; - int state = kExtState_7Zip; - if (mi.State == kExtState_7Zip) - state = kExtState_Clear; - else if (mi.State == kExtState_Clear) - { - thereAreClearItems = true; - if (mi.Other) - state = kExtState_Other; - } - counters[state]++; - } - - int state = kExtState_Clear; - if (counters[kExtState_Other] != 0) - state = kExtState_Other; - else if (counters[kExtState_7Zip] != 0) - state = kExtState_7Zip; - - for (i = 0; i < indices.Size(); i++) - { - unsigned listIndex = indices[i]; - CAssoc &assoc = _items[GetRealIndex(listIndex)]; - CModifiedExtInfo &mi = assoc.Pair[group]; - bool change = false; - - switch (state) - { - case kExtState_Clear: change = true; break; - case kExtState_Other: change = mi.Other; break; - default: change = !(mi.Other && thereAreClearItems); break; - } - - if (change) - { - mi.State = state; - RefreshListItem(group, listIndex); - } - } - - _needSave = true; - Changed(); -} - - -bool CSystemPage::OnInit() -{ - _needSave = false; - -#ifdef Z7_LANG - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); -#endif - - _listView.Attach(GetItem(IDL_SYSTEM_ASSOCIATE)); - _listView.SetUnicodeFormat(); - DWORD newFlags = LVS_EX_FULLROWSELECT; - _listView.SetExtendedListViewStyle(newFlags, newFlags); - - _numIcons = 0; - _imageList.Create(16, 16, ILC_MASK | ILC_COLOR32, 0, 0); - - _listView.SetImageList(_imageList, LVSIL_SMALL); - - _listView.InsertColumn(0, LangString(IDS_PROP_FILE_TYPE), 80); - - UString s; - - #if NUM_EXT_GROUPS == 1 - s = "Program"; - #else - #ifndef UNDER_CE - const unsigned kSize = 256; - BOOL res; - - DWORD size = kSize; - - #ifndef _UNICODE - if (!g_IsNT) - { - AString s2; - res = GetUserNameA(s2.GetBuf(size), &size); - s2.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize)); - s = GetUnicodeString(s2); - } - else - #endif - { - res = GetUserNameW(s.GetBuf(size), &size); - s.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize)); - } - - if (!res) - #endif - s = "Current User"; - #endif - - LV_COLUMNW ci; - ci.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; - ci.cx = 152; - ci.fmt = LVCFMT_CENTER; - ci.pszText = s.Ptr_non_const(); - ci.iSubItem = 1; - _listView.InsertColumn(1, &ci); - - #if NUM_EXT_GROUPS > 1 - { - LangString(IDS_SYSTEM_ALL_USERS, s); - ci.pszText = s.Ptr_non_const(); - ci.iSubItem = 2; - _listView.InsertColumn(2, &ci); - } - #endif - - _extDB.Read(); - _items.Clear(); - - FOR_VECTOR (i, _extDB.Exts) - { - const CExtPlugins &extInfo = _extDB.Exts[i]; - - LVITEMW item; - item.iItem = (int)i; - item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; - item.lParam = (LPARAM)i; - item.iSubItem = 0; - // ListView always uses internal iImage that is 0 by default? - // so we always use LVIF_IMAGE. - item.iImage = -1; - item.pszText = extInfo.Ext.Ptr_non_const(); - - CAssoc assoc; - const CPluginToIcon &plug = extInfo.Plugins[0]; - assoc.SevenZipImageIndex = AddIcon(plug.IconPath, plug.IconIndex); - - CSysString texts[NUM_EXT_GROUPS]; - unsigned g; - for (g = 0; g < NUM_EXT_GROUPS; g++) - { - CModifiedExtInfo &mi = assoc.Pair[g]; - mi.ReadFromRegistry(GetHKey(g), GetSystemString(extInfo.Ext)); - mi.SetState(plug.IconPath); - mi.ImageIndex = AddIcon(mi.IconPath, mi.IconIndex); - texts[g] = mi.GetString(); - } - item.iImage = assoc.GetIconIndex(); - const int itemIndex = _listView.InsertItem(&item); - for (g = 0; g < NUM_EXT_GROUPS; g++) - _listView.SetSubItem((unsigned)itemIndex, 1 + g, texts[g]); - _items.Add(assoc); - } - - if (_listView.GetItemCount() > 0) - _listView.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); - - return CPropertyPage::OnInit(); -} - - -static UString GetProgramCommand() -{ - UString s ('\"'); - s += fs2us(NDLL::GetModuleDirPrefix()); - s += "7zFM.exe\" \"%1\""; - return s; -} - - -LONG CSystemPage::OnApply() -{ - if (!_needSave) - return PSNRET_NOERROR; - - const UString command = GetProgramCommand(); - - LONG res = 0; - - FOR_VECTOR (listIndex, _extDB.Exts) - { - unsigned realIndex = GetRealIndex(listIndex); - const CExtPlugins &extInfo = _extDB.Exts[realIndex]; - CAssoc &assoc = _items[realIndex]; - - for (unsigned g = 0; g < NUM_EXT_GROUPS; g++) - { - CModifiedExtInfo &mi = assoc.Pair[g]; - HKEY key = GetHKey(g); - - if (mi.OldState != mi.State) - { - LONG res2 = 0; - - if (mi.State == kExtState_7Zip) - { - UString title = extInfo.Ext; - title += " Archive"; - const CPluginToIcon &plug = extInfo.Plugins[0]; - res2 = NRegistryAssoc::AddShellExtensionInfo(key, GetSystemString(extInfo.Ext), - title, command, plug.IconPath, plug.IconIndex); - } - else if (mi.State == kExtState_Clear) - res2 = NRegistryAssoc::DeleteShellExtensionInfo(key, GetSystemString(extInfo.Ext)); - - if (res == 0) - res = res2; - if (res2 == 0) - mi.OldState = mi.State; - - mi.State = mi.OldState; - RefreshListItem(g, listIndex); - } - } - } - - #ifndef UNDER_CE - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); - #endif - - WasChanged = true; - - _needSave = false; - - if (res != 0) - MessageBoxW(*this, NError::MyFormatMessage(res), L"7-Zip", MB_ICONERROR); - - return PSNRET_NOERROR; -} - - -void CSystemPage::OnNotifyHelp() -{ - ShowHelpWindow(kSystemTopic); -} - - -bool CSystemPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - /* - case IDC_SYSTEM_SELECT_ALL: - _listView.SelectAll(); - return true; - */ - case IDB_SYSTEM_CURRENT: - case IDB_SYSTEM_ALL: - ChangeState(buttonID == IDB_SYSTEM_CURRENT ? 0 : 1); - return true; - } - return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); -} - - -bool CSystemPage::OnNotify(UINT controlID, LPNMHDR lParam) -{ - if (lParam->hwndFrom == HWND(_listView)) - { - switch (lParam->code) - { - case NM_RETURN: - { - ChangeState(0); - return true; - } - - case NM_CLICK: - { - #ifdef UNDER_CE - NMLISTVIEW *item = (NMLISTVIEW *)lParam; - #else - NMITEMACTIVATE *item = (NMITEMACTIVATE *)lParam; - if (item->uKeyFlags == 0) - #endif - { - if (item->iItem >= 0) - { - // unsigned realIndex = GetRealIndex(item->iItem); - if (item->iSubItem >= 1 && item->iSubItem <= 2) - { - CUIntVector indices; - indices.Add((unsigned)item->iItem); - ChangeState(item->iSubItem < 2 ? 0 : 1, indices); - } - } - } - break; - } - - case LVN_KEYDOWN: - { - if (OnListKeyDown(LPNMLVKEYDOWN(lParam))) - return true; - break; - } - - /* - case NM_RCLICK: - case NM_DBLCLK: - case LVN_BEGINRDRAG: - // PostMessage(kRefreshpluginsListMessage, 0); - PostMessage(kUpdateDatabase, 0); - break; - */ - } - } - return CPropertyPage::OnNotify(controlID, lParam); -} - - -void CSystemPage::ChangeState(unsigned group) -{ - CUIntVector indices; - - int itemIndex = -1; - while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1) - indices.Add((unsigned)itemIndex); - - if (indices.IsEmpty()) - FOR_VECTOR (i, _items) - indices.Add(i); - - ChangeState(group, indices); -} - - -bool CSystemPage::OnListKeyDown(LPNMLVKEYDOWN keyDownInfo) -{ - bool ctrl = IsKeyDown(VK_CONTROL); - bool alt = IsKeyDown(VK_MENU); - - if (alt) - return false; - - if ((ctrl && keyDownInfo->wVKey == 'A') - || (!ctrl && keyDownInfo->wVKey == VK_MULTIPLY)) - { - _listView.SelectAll(); - return true; - } - - switch (keyDownInfo->wVKey) - { - case VK_SPACE: - case VK_ADD: - case VK_SUBTRACT: - case VK_SEPARATOR: - case VK_DIVIDE: - - #ifndef UNDER_CE - case VK_OEM_PLUS: - case VK_OEM_MINUS: - #endif - - if (!ctrl) - { - ChangeState(keyDownInfo->wVKey == VK_SPACE ? 0 : 1); - return true; - } - break; - } - - return false; -} +// SystemPage.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../Common/Defs.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/ErrorMsg.h" + +#include "HelpUtils.h" +#include "IFolder.h" +#include "LangUtils.h" +#include "PropertyNameRes.h" +#include "SystemPage.h" +#include "SystemPageRes.h" + +using namespace NWindows; + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_SYSTEM_ASSOCIATE +}; +#endif + +#define kSystemTopic "FM/options.htm#system" + +CSysString CModifiedExtInfo::GetString() const +{ + const char *s; + if (State == kExtState_7Zip) + s = "7-Zip"; + else if (State == kExtState_Clear) + s = ""; + else if (Other7Zip) + s = "[7-Zip]"; + else + return ProgramKey; + return CSysString (s); +} + + +int CSystemPage::AddIcon(const UString &iconPath, int iconIndex) +{ + if (iconPath.IsEmpty()) + return -1; + if (iconIndex == -1) + iconIndex = 0; + + HICON hicon; + + #ifdef UNDER_CE + ExtractIconExW(iconPath, iconIndex, NULL, &hicon, 1); + if (!hicon) + #else + // we expand path from REG_EXPAND_SZ registry item. + UString path; + const DWORD size = MAX_PATH + 10; + const DWORD needLen = ::ExpandEnvironmentStringsW(iconPath, path.GetBuf(size + 2), size); + path.ReleaseBuf_CalcLen(size); + if (needLen == 0 || needLen >= size) + path = iconPath; + const UINT num = ExtractIconExW(path, iconIndex, NULL, &hicon, 1); + if (num != 1 || !hicon) + #endif + return -1; + + _imageList.AddIcon(hicon); + DestroyIcon(hicon); + return (int)(_numIcons++); +} + + +void CSystemPage::RefreshListItem(unsigned group, unsigned listIndex) +{ + const CAssoc &assoc = _items[GetRealIndex(listIndex)]; + _listView.SetSubItem(listIndex, group + 1, assoc.Pair[group].GetString()); + LVITEMW newItem; + memset(&newItem, 0, sizeof(newItem)); + newItem.iItem = (int)listIndex; + newItem.mask = LVIF_IMAGE; + newItem.iImage = assoc.GetIconIndex(); + _listView.SetItem(&newItem); +} + + +void CSystemPage::ChangeState(unsigned group, const CUIntVector &indices) +{ + if (indices.IsEmpty()) + return; + + bool thereAreClearItems = false; + unsigned counters[3] = { 0, 0, 0 }; + + unsigned i; + for (i = 0; i < indices.Size(); i++) + { + const CModifiedExtInfo &mi = _items[GetRealIndex(indices[i])].Pair[group]; + int state = kExtState_7Zip; + if (mi.State == kExtState_7Zip) + state = kExtState_Clear; + else if (mi.State == kExtState_Clear) + { + thereAreClearItems = true; + if (mi.Other) + state = kExtState_Other; + } + counters[state]++; + } + + int state = kExtState_Clear; + if (counters[kExtState_Other] != 0) + state = kExtState_Other; + else if (counters[kExtState_7Zip] != 0) + state = kExtState_7Zip; + + for (i = 0; i < indices.Size(); i++) + { + unsigned listIndex = indices[i]; + CAssoc &assoc = _items[GetRealIndex(listIndex)]; + CModifiedExtInfo &mi = assoc.Pair[group]; + bool change = false; + + switch (state) + { + case kExtState_Clear: change = true; break; + case kExtState_Other: change = mi.Other; break; + default: change = !(mi.Other && thereAreClearItems); break; + } + + if (change) + { + mi.State = state; + RefreshListItem(group, listIndex); + } + } + + _needSave = true; + Changed(); +} + + +bool CSystemPage::OnInit() +{ + _needSave = false; + +#ifdef Z7_LANG + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); +#endif + + _listView.Attach(GetItem(IDL_SYSTEM_ASSOCIATE)); + _listView.SetUnicodeFormat(); + DWORD newFlags = LVS_EX_FULLROWSELECT; + _listView.SetExtendedListViewStyle(newFlags, newFlags); + + _numIcons = 0; + _imageList.Create(16, 16, ILC_MASK | ILC_COLOR32, 0, 0); + + _listView.SetImageList(_imageList, LVSIL_SMALL); + + _listView.InsertColumn(0, LangString(IDS_PROP_FILE_TYPE), 80); + + UString s; + + #if NUM_EXT_GROUPS == 1 + s = "Program"; + #else + #ifndef UNDER_CE + const unsigned kSize = 256; + BOOL res; + + DWORD size = kSize; + + #ifndef _UNICODE + if (!g_IsNT) + { + AString s2; + res = GetUserNameA(s2.GetBuf(size), &size); + s2.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize)); + s = GetUnicodeString(s2); + } + else + #endif + { + res = GetUserNameW(s.GetBuf(size), &size); + s.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize)); + } + + if (!res) + #endif + s = "Current User"; + #endif + + LV_COLUMNW ci; + ci.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; + ci.cx = 152; + ci.fmt = LVCFMT_CENTER; + ci.pszText = s.Ptr_non_const(); + ci.iSubItem = 1; + _listView.InsertColumn(1, &ci); + + #if NUM_EXT_GROUPS > 1 + { + LangString(IDS_SYSTEM_ALL_USERS, s); + ci.pszText = s.Ptr_non_const(); + ci.iSubItem = 2; + _listView.InsertColumn(2, &ci); + } + #endif + + _extDB.Read(); + _items.Clear(); + + FOR_VECTOR (i, _extDB.Exts) + { + const CExtPlugins &extInfo = _extDB.Exts[i]; + + LVITEMW item; + item.iItem = (int)i; + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; + item.lParam = (LPARAM)i; + item.iSubItem = 0; + // ListView always uses internal iImage that is 0 by default? + // so we always use LVIF_IMAGE. + item.iImage = -1; + item.pszText = extInfo.Ext.Ptr_non_const(); + + CAssoc assoc; + const CPluginToIcon &plug = extInfo.Plugins[0]; + assoc.SevenZipImageIndex = AddIcon(plug.IconPath, plug.IconIndex); + + CSysString texts[NUM_EXT_GROUPS]; + unsigned g; + for (g = 0; g < NUM_EXT_GROUPS; g++) + { + CModifiedExtInfo &mi = assoc.Pair[g]; + mi.ReadFromRegistry(GetHKey(g), GetSystemString(extInfo.Ext)); + mi.SetState(plug.IconPath); + mi.ImageIndex = AddIcon(mi.IconPath, mi.IconIndex); + texts[g] = mi.GetString(); + } + item.iImage = assoc.GetIconIndex(); + const int itemIndex = _listView.InsertItem(&item); + for (g = 0; g < NUM_EXT_GROUPS; g++) + _listView.SetSubItem((unsigned)itemIndex, 1 + g, texts[g]); + _items.Add(assoc); + } + + if (_listView.GetItemCount() > 0) + _listView.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); + + return CPropertyPage::OnInit(); +} + + +static UString GetProgramCommand() +{ + UString s ('\"'); + s += fs2us(NDLL::GetModuleDirPrefix()); + s += "7zFM.exe\" \"%1\""; + return s; +} + + +LONG CSystemPage::OnApply() +{ + if (!_needSave) + return PSNRET_NOERROR; + + const UString command = GetProgramCommand(); + + LONG res = 0; + + FOR_VECTOR (listIndex, _extDB.Exts) + { + unsigned realIndex = GetRealIndex(listIndex); + const CExtPlugins &extInfo = _extDB.Exts[realIndex]; + CAssoc &assoc = _items[realIndex]; + + for (unsigned g = 0; g < NUM_EXT_GROUPS; g++) + { + CModifiedExtInfo &mi = assoc.Pair[g]; + HKEY key = GetHKey(g); + + if (mi.OldState != mi.State) + { + LONG res2 = 0; + + if (mi.State == kExtState_7Zip) + { + UString title = extInfo.Ext; + title += " Archive"; + const CPluginToIcon &plug = extInfo.Plugins[0]; + res2 = NRegistryAssoc::AddShellExtensionInfo(key, GetSystemString(extInfo.Ext), + title, command, plug.IconPath, plug.IconIndex); + } + else if (mi.State == kExtState_Clear) + res2 = NRegistryAssoc::DeleteShellExtensionInfo(key, GetSystemString(extInfo.Ext)); + + if (res == 0) + res = res2; + if (res2 == 0) + mi.OldState = mi.State; + + mi.State = mi.OldState; + RefreshListItem(g, listIndex); + } + } + } + + #ifndef UNDER_CE + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); + #endif + + WasChanged = true; + + _needSave = false; + + if (res != 0) + MessageBoxW(*this, NError::MyFormatMessage(res), L"7-Zip", MB_ICONERROR); + + return PSNRET_NOERROR; +} + + +void CSystemPage::OnNotifyHelp() +{ + ShowHelpWindow(kSystemTopic); +} + + +bool CSystemPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + /* + case IDC_SYSTEM_SELECT_ALL: + _listView.SelectAll(); + return true; + */ + case IDB_SYSTEM_CURRENT: + case IDB_SYSTEM_ALL: + ChangeState(buttonID == IDB_SYSTEM_CURRENT ? 0 : 1); + return true; + } + return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); +} + + +bool CSystemPage::OnNotify(UINT controlID, LPNMHDR lParam) +{ + if (lParam->hwndFrom == HWND(_listView)) + { + switch (lParam->code) + { + case NM_RETURN: + { + ChangeState(0); + return true; + } + + case NM_CLICK: + { + #ifdef UNDER_CE + NMLISTVIEW *item = (NMLISTVIEW *)lParam; + #else + NMITEMACTIVATE *item = (NMITEMACTIVATE *)lParam; + if (item->uKeyFlags == 0) + #endif + { + if (item->iItem >= 0) + { + // unsigned realIndex = GetRealIndex(item->iItem); + if (item->iSubItem >= 1 && item->iSubItem <= 2) + { + CUIntVector indices; + indices.Add((unsigned)item->iItem); + ChangeState(item->iSubItem < 2 ? 0 : 1, indices); + } + } + } + break; + } + + case LVN_KEYDOWN: + { + if (OnListKeyDown(LPNMLVKEYDOWN(lParam))) + return true; + break; + } + + /* + case NM_RCLICK: + case NM_DBLCLK: + case LVN_BEGINRDRAG: + // PostMessage(kRefreshpluginsListMessage, 0); + PostMessage(kUpdateDatabase, 0); + break; + */ + } + } + return CPropertyPage::OnNotify(controlID, lParam); +} + + +void CSystemPage::ChangeState(unsigned group) +{ + CUIntVector indices; + + int itemIndex = -1; + while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1) + indices.Add((unsigned)itemIndex); + + if (indices.IsEmpty()) + FOR_VECTOR (i, _items) + indices.Add(i); + + ChangeState(group, indices); +} + + +bool CSystemPage::OnListKeyDown(LPNMLVKEYDOWN keyDownInfo) +{ + bool ctrl = IsKeyDown(VK_CONTROL); + bool alt = IsKeyDown(VK_MENU); + + if (alt) + return false; + + if ((ctrl && keyDownInfo->wVKey == 'A') + || (!ctrl && keyDownInfo->wVKey == VK_MULTIPLY)) + { + _listView.SelectAll(); + return true; + } + + switch (keyDownInfo->wVKey) + { + case VK_SPACE: + case VK_ADD: + case VK_SUBTRACT: + case VK_SEPARATOR: + case VK_DIVIDE: + + #ifndef UNDER_CE + case VK_OEM_PLUS: + case VK_OEM_MINUS: + #endif + + if (!ctrl) + { + ChangeState(keyDownInfo->wVKey == VK_SPACE ? 0 : 1); + return true; + } + break; + } + + return false; +} diff --git a/CPP/7zip/UI/FileManager/SystemPage.h b/CPP/7zip/UI/FileManager/SystemPage.h index 0c700f807..6f2ed0c1a 100644 --- a/CPP/7zip/UI/FileManager/SystemPage.h +++ b/CPP/7zip/UI/FileManager/SystemPage.h @@ -1,126 +1,126 @@ -// SystemPage.h - -#ifndef ZIP7_INC_SYSTEM_PAGE_H -#define ZIP7_INC_SYSTEM_PAGE_H - -#include "../../../Windows/Control/ImageList.h" -#include "../../../Windows/Control/ListView.h" -#include "../../../Windows/Control/PropertyPage.h" - -#include "FilePlugins.h" -#include "RegistryAssociations.h" - -enum EExtState -{ - kExtState_Clear = 0, - kExtState_Other, - kExtState_7Zip -}; - -struct CModifiedExtInfo: public NRegistryAssoc::CShellExtInfo -{ - int OldState; - int State; - int ImageIndex; - bool Other; - bool Other7Zip; - - CModifiedExtInfo(): ImageIndex(-1) {} - - CSysString GetString() const; - - void SetState(const UString &iconPath) - { - State = kExtState_Clear; - Other = false; - Other7Zip = false; - if (!ProgramKey.IsEmpty()) - { - State = kExtState_Other; - Other = true; - if (IsIt7Zip()) - { - Other7Zip = !iconPath.IsEqualTo_NoCase(IconPath); - if (!Other7Zip) - { - State = kExtState_7Zip; - Other = false; - } - } - } - OldState = State; - } -}; - -struct CAssoc -{ - CModifiedExtInfo Pair[2]; - int SevenZipImageIndex; - - int GetIconIndex() const - { - for (unsigned i = 0; i < 2; i++) - { - const CModifiedExtInfo &pair = Pair[i]; - if (pair.State == kExtState_Clear) - continue; - if (pair.State == kExtState_7Zip) - return SevenZipImageIndex; - if (pair.ImageIndex != -1) - return pair.ImageIndex; - } - return -1; - } -}; - -#ifdef UNDER_CE - #define NUM_EXT_GROUPS 1 -#else - #define NUM_EXT_GROUPS 2 -#endif - -class CSystemPage: public NWindows::NControl::CPropertyPage -{ - CExtDatabase _extDB; - CObjectVector _items; - - unsigned _numIcons; - NWindows::NControl::CImageList _imageList; - NWindows::NControl::CListView _listView; - - bool _needSave; - - HKEY GetHKey(unsigned - #if NUM_EXT_GROUPS != 1 - group - #endif - ) const - { - #if NUM_EXT_GROUPS == 1 - return HKEY_CLASSES_ROOT; - #else - return group == 0 ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; - #endif - } - - int AddIcon(const UString &path, int iconIndex); - unsigned GetRealIndex(unsigned listIndex) const { return listIndex; } - void RefreshListItem(unsigned group, unsigned listIndex); - void ChangeState(unsigned group, const CUIntVector &indices); - void ChangeState(unsigned group); - - bool OnListKeyDown(LPNMLVKEYDOWN keyDownInfo); - -public: - bool WasChanged; - - CSystemPage(): WasChanged(false) {} - - virtual bool OnInit() Z7_override; - virtual void OnNotifyHelp() Z7_override; - virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override; - virtual LONG OnApply() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; -}; - -#endif +// SystemPage.h + +#ifndef ZIP7_INC_SYSTEM_PAGE_H +#define ZIP7_INC_SYSTEM_PAGE_H + +#include "../../../Windows/Control/ImageList.h" +#include "../../../Windows/Control/ListView.h" +#include "../../../Windows/Control/PropertyPage.h" + +#include "FilePlugins.h" +#include "RegistryAssociations.h" + +enum EExtState +{ + kExtState_Clear = 0, + kExtState_Other, + kExtState_7Zip +}; + +struct CModifiedExtInfo: public NRegistryAssoc::CShellExtInfo +{ + int OldState; + int State; + int ImageIndex; + bool Other; + bool Other7Zip; + + CModifiedExtInfo(): ImageIndex(-1) {} + + CSysString GetString() const; + + void SetState(const UString &iconPath) + { + State = kExtState_Clear; + Other = false; + Other7Zip = false; + if (!ProgramKey.IsEmpty()) + { + State = kExtState_Other; + Other = true; + if (IsIt7Zip()) + { + Other7Zip = !iconPath.IsEqualTo_NoCase(IconPath); + if (!Other7Zip) + { + State = kExtState_7Zip; + Other = false; + } + } + } + OldState = State; + } +}; + +struct CAssoc +{ + CModifiedExtInfo Pair[2]; + int SevenZipImageIndex; + + int GetIconIndex() const + { + for (unsigned i = 0; i < 2; i++) + { + const CModifiedExtInfo &pair = Pair[i]; + if (pair.State == kExtState_Clear) + continue; + if (pair.State == kExtState_7Zip) + return SevenZipImageIndex; + if (pair.ImageIndex != -1) + return pair.ImageIndex; + } + return -1; + } +}; + +#ifdef UNDER_CE + #define NUM_EXT_GROUPS 1 +#else + #define NUM_EXT_GROUPS 2 +#endif + +class CSystemPage: public NWindows::NControl::CPropertyPage +{ + CExtDatabase _extDB; + CObjectVector _items; + + unsigned _numIcons; + NWindows::NControl::CImageList _imageList; + NWindows::NControl::CListView _listView; + + bool _needSave; + + HKEY GetHKey(unsigned + #if NUM_EXT_GROUPS != 1 + group + #endif + ) const + { + #if NUM_EXT_GROUPS == 1 + return HKEY_CLASSES_ROOT; + #else + return group == 0 ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; + #endif + } + + int AddIcon(const UString &path, int iconIndex); + unsigned GetRealIndex(unsigned listIndex) const { return listIndex; } + void RefreshListItem(unsigned group, unsigned listIndex); + void ChangeState(unsigned group, const CUIntVector &indices); + void ChangeState(unsigned group); + + bool OnListKeyDown(LPNMLVKEYDOWN keyDownInfo); + +public: + bool WasChanged; + + CSystemPage(): WasChanged(false) {} + + virtual bool OnInit() Z7_override; + virtual void OnNotifyHelp() Z7_override; + virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override; + virtual LONG OnApply() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/SystemPage.rc b/CPP/7zip/UI/FileManager/SystemPage.rc index a23e9dbac..108e5241d 100644 --- a/CPP/7zip/UI/FileManager/SystemPage.rc +++ b/CPP/7zip/UI/FileManager/SystemPage.rc @@ -1,43 +1,43 @@ -#include "SystemPageRes.h" -#include "../../GuiCommon.rc" - -#define xc OPTIONS_PAGE_XC_SIZE -#define yc OPTIONS_PAGE_YC_SIZE - -IDD_SYSTEM DIALOG MY_PAGE_POSTFIX -CAPTION "System" -BEGIN - LTEXT "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8 - PUSHBUTTON "+", IDB_SYSTEM_CURRENT, 92, m + 12, 40, bys - PUSHBUTTON "+", IDB_SYSTEM_ALL, 194, m + 12, 40, bys - CONTROL "List1", IDL_SYSTEM_ASSOCIATE, "SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, - m, m + 32, xc, (yc - 32) -END - -#ifdef UNDER_CE - -#undef m -#undef xc -#undef yc - -#define m 4 -#define xc (SMALL_PAGE_SIZE_X + 8) -#define yc (128 + 8) - -IDD_SYSTEM_2 DIALOG MY_PAGE_POSTFIX -CAPTION "System" -BEGIN - LTEXT "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8 - PUSHBUTTON "+", IDB_SYSTEM_CURRENT, 60, m + 12, 40, bys - CONTROL "List1", IDL_SYSTEM_ASSOCIATE, "SysListView32", - LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, - m, m + 32, xc, (yc - 32) -END - -#endif - -STRINGTABLE -BEGIN - IDS_SYSTEM_ALL_USERS "All users" -END +#include "SystemPageRes.h" +#include "../../GuiCommon.rc" + +#define xc OPTIONS_PAGE_XC_SIZE +#define yc OPTIONS_PAGE_YC_SIZE + +IDD_SYSTEM DIALOG MY_PAGE_POSTFIX +CAPTION "System" +BEGIN + LTEXT "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8 + PUSHBUTTON "+", IDB_SYSTEM_CURRENT, 92, m + 12, 40, bys + PUSHBUTTON "+", IDB_SYSTEM_ALL, 194, m + 12, 40, bys + CONTROL "List1", IDL_SYSTEM_ASSOCIATE, "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, + m, m + 32, xc, (yc - 32) +END + +#ifdef UNDER_CE + +#undef m +#undef xc +#undef yc + +#define m 4 +#define xc (SMALL_PAGE_SIZE_X + 8) +#define yc (128 + 8) + +IDD_SYSTEM_2 DIALOG MY_PAGE_POSTFIX +CAPTION "System" +BEGIN + LTEXT "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8 + PUSHBUTTON "+", IDB_SYSTEM_CURRENT, 60, m + 12, 40, bys + CONTROL "List1", IDL_SYSTEM_ASSOCIATE, "SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, + m, m + 32, xc, (yc - 32) +END + +#endif + +STRINGTABLE +BEGIN + IDS_SYSTEM_ALL_USERS "All users" +END diff --git a/CPP/7zip/UI/FileManager/SystemPageRes.h b/CPP/7zip/UI/FileManager/SystemPageRes.h index 13f6cd708..c89444825 100644 --- a/CPP/7zip/UI/FileManager/SystemPageRes.h +++ b/CPP/7zip/UI/FileManager/SystemPageRes.h @@ -1,9 +1,9 @@ -#define IDD_SYSTEM 2200 -#define IDD_SYSTEM_2 12200 - -#define IDT_SYSTEM_ASSOCIATE 2201 -#define IDS_SYSTEM_ALL_USERS 2202 - -#define IDL_SYSTEM_ASSOCIATE 100 -#define IDB_SYSTEM_CURRENT 101 -#define IDB_SYSTEM_ALL 102 +#define IDD_SYSTEM 2200 +#define IDD_SYSTEM_2 12200 + +#define IDT_SYSTEM_ASSOCIATE 2201 +#define IDS_SYSTEM_ALL_USERS 2202 + +#define IDL_SYSTEM_ASSOCIATE 100 +#define IDB_SYSTEM_CURRENT 101 +#define IDB_SYSTEM_ALL 102 diff --git a/CPP/7zip/UI/FileManager/TextPairs.cpp b/CPP/7zip/UI/FileManager/TextPairs.cpp index da05ff037..6bf84cf85 100644 --- a/CPP/7zip/UI/FileManager/TextPairs.cpp +++ b/CPP/7zip/UI/FileManager/TextPairs.cpp @@ -1,193 +1,193 @@ -// TextPairs.cpp - -#include "StdAfx.h" - -#include "TextPairs.h" - -static const wchar_t kNewLineChar = '\n'; -static const wchar_t kQuoteChar = '\"'; - -static const wchar_t kBOM = (wchar_t)0xFEFF; - -static bool IsSeparatorChar(wchar_t c) -{ - return (c == ' ' || c == '\t'); -} - -static void RemoveCr(UString &s) -{ - s.RemoveChar(L'\x0D'); -} - -static UString GetIDString(const wchar_t *srcString, unsigned &finishPos) -{ - UString result; - bool quotes = false; - for (finishPos = 0;;) - { - wchar_t c = srcString[finishPos]; - if (c == 0) - break; - finishPos++; - bool isSeparatorChar = IsSeparatorChar(c); - if (c == kNewLineChar || (isSeparatorChar && !quotes) - || (c == kQuoteChar && quotes)) - break; - else if (c == kQuoteChar) - quotes = true; - else - result += c; - } - result.Trim(); - RemoveCr(result); - return result; -} - -static UString GetValueString(const wchar_t *srcString, unsigned &finishPos) -{ - UString result; - for (finishPos = 0;;) - { - wchar_t c = srcString[finishPos]; - if (c == 0) - break; - finishPos++; - if (c == kNewLineChar) - break; - result += c; - } - result.Trim(); - RemoveCr(result); - return result; -} - -static bool GetTextPairs(const UString &srcString, CObjectVector &pairs) -{ - pairs.Clear(); - unsigned pos = 0; - - if (srcString.Len() > 0) - { - if (srcString[0] == kBOM) - pos++; - } - while (pos < srcString.Len()) - { - unsigned finishPos; - UString id = GetIDString((const wchar_t *)srcString + pos, finishPos); - pos += finishPos; - if (id.IsEmpty()) - continue; - UString value = GetValueString((const wchar_t *)srcString + pos, finishPos); - pos += finishPos; - if (!id.IsEmpty()) - { - CTextPair pair; - pair.ID = id; - pair.Value = value; - pairs.Add(pair); - } - } - return true; -} - -static int ComparePairIDs(const UString &s1, const UString &s2) - { return MyStringCompareNoCase(s1, s2); } - -static int ComparePairItems(const CTextPair &p1, const CTextPair &p2) - { return ComparePairIDs(p1.ID, p2.ID); } - -static int ComparePairItems(void *const *a1, void *const *a2, void * /* param */) - { return ComparePairItems(**(const CTextPair *const *)a1, **(const CTextPair *const *)a2); } - -void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, NULL); } - -int CPairsStorage::FindID(const UString &id, unsigned &insertPos) const -{ - unsigned left = 0, right = Pairs.Size(); - while (left != right) - { - const unsigned mid = (left + right) / 2; - const int compResult = ComparePairIDs(id, Pairs[mid].ID); - if (compResult == 0) - { - insertPos = mid; // to disable GCC warning - return (int)mid; - } - if (compResult < 0) - right = mid; - else - left = mid + 1; - } - insertPos = left; - return -1; -} - -int CPairsStorage::FindID(const UString &id) const -{ - unsigned pos; - return FindID(id, pos); -} - -void CPairsStorage::AddPair(const CTextPair &pair) -{ - unsigned insertPos; - const int pos = FindID(pair.ID, insertPos); - if (pos >= 0) - Pairs[pos] = pair; - else - Pairs.Insert(insertPos, pair); -} - -void CPairsStorage::DeletePair(const UString &id) -{ - const int pos = FindID(id); - if (pos >= 0) - Pairs.Delete((unsigned)pos); -} - -bool CPairsStorage::GetValue(const UString &id, UString &value) const -{ - value.Empty(); - const int pos = FindID(id); - if (pos < 0) - return false; - value = Pairs[pos].Value; - return true; -} - -UString CPairsStorage::GetValue(const UString &id) const -{ - const int pos = FindID(id); - if (pos < 0) - return UString(); - return Pairs[pos].Value; -} - -bool CPairsStorage::ReadFromString(const UString &text) -{ - bool result = ::GetTextPairs(text, Pairs); - if (result) - Sort(); - else - Pairs.Clear(); - return result; -} - -void CPairsStorage::SaveToString(UString &text) const -{ - FOR_VECTOR (i, Pairs) - { - const CTextPair &pair = Pairs[i]; - bool multiWord = (pair.ID.Find(L' ') >= 0); - if (multiWord) - text.Add_Char('\"'); - text += pair.ID; - if (multiWord) - text.Add_Char('\"'); - text.Add_Space(); - text += pair.Value; - text.Add_Char('\x0D'); - text.Add_LF(); - } -} +// TextPairs.cpp + +#include "StdAfx.h" + +#include "TextPairs.h" + +static const wchar_t kNewLineChar = '\n'; +static const wchar_t kQuoteChar = '\"'; + +static const wchar_t kBOM = (wchar_t)0xFEFF; + +static bool IsSeparatorChar(wchar_t c) +{ + return (c == ' ' || c == '\t'); +} + +static void RemoveCr(UString &s) +{ + s.RemoveChar(L'\x0D'); +} + +static UString GetIDString(const wchar_t *srcString, unsigned &finishPos) +{ + UString result; + bool quotes = false; + for (finishPos = 0;;) + { + wchar_t c = srcString[finishPos]; + if (c == 0) + break; + finishPos++; + bool isSeparatorChar = IsSeparatorChar(c); + if (c == kNewLineChar || (isSeparatorChar && !quotes) + || (c == kQuoteChar && quotes)) + break; + else if (c == kQuoteChar) + quotes = true; + else + result += c; + } + result.Trim(); + RemoveCr(result); + return result; +} + +static UString GetValueString(const wchar_t *srcString, unsigned &finishPos) +{ + UString result; + for (finishPos = 0;;) + { + wchar_t c = srcString[finishPos]; + if (c == 0) + break; + finishPos++; + if (c == kNewLineChar) + break; + result += c; + } + result.Trim(); + RemoveCr(result); + return result; +} + +static bool GetTextPairs(const UString &srcString, CObjectVector &pairs) +{ + pairs.Clear(); + unsigned pos = 0; + + if (srcString.Len() > 0) + { + if (srcString[0] == kBOM) + pos++; + } + while (pos < srcString.Len()) + { + unsigned finishPos; + UString id = GetIDString((const wchar_t *)srcString + pos, finishPos); + pos += finishPos; + if (id.IsEmpty()) + continue; + UString value = GetValueString((const wchar_t *)srcString + pos, finishPos); + pos += finishPos; + if (!id.IsEmpty()) + { + CTextPair pair; + pair.ID = id; + pair.Value = value; + pairs.Add(pair); + } + } + return true; +} + +static int ComparePairIDs(const UString &s1, const UString &s2) + { return MyStringCompareNoCase(s1, s2); } + +static int ComparePairItems(const CTextPair &p1, const CTextPair &p2) + { return ComparePairIDs(p1.ID, p2.ID); } + +static int ComparePairItems(void *const *a1, void *const *a2, void * /* param */) + { return ComparePairItems(**(const CTextPair *const *)a1, **(const CTextPair *const *)a2); } + +void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, NULL); } + +int CPairsStorage::FindID(const UString &id, unsigned &insertPos) const +{ + unsigned left = 0, right = Pairs.Size(); + while (left != right) + { + const unsigned mid = (left + right) / 2; + const int compResult = ComparePairIDs(id, Pairs[mid].ID); + if (compResult == 0) + { + insertPos = mid; // to disable GCC warning + return (int)mid; + } + if (compResult < 0) + right = mid; + else + left = mid + 1; + } + insertPos = left; + return -1; +} + +int CPairsStorage::FindID(const UString &id) const +{ + unsigned pos; + return FindID(id, pos); +} + +void CPairsStorage::AddPair(const CTextPair &pair) +{ + unsigned insertPos; + const int pos = FindID(pair.ID, insertPos); + if (pos >= 0) + Pairs[pos] = pair; + else + Pairs.Insert(insertPos, pair); +} + +void CPairsStorage::DeletePair(const UString &id) +{ + const int pos = FindID(id); + if (pos >= 0) + Pairs.Delete((unsigned)pos); +} + +bool CPairsStorage::GetValue(const UString &id, UString &value) const +{ + value.Empty(); + const int pos = FindID(id); + if (pos < 0) + return false; + value = Pairs[pos].Value; + return true; +} + +UString CPairsStorage::GetValue(const UString &id) const +{ + const int pos = FindID(id); + if (pos < 0) + return UString(); + return Pairs[pos].Value; +} + +bool CPairsStorage::ReadFromString(const UString &text) +{ + bool result = ::GetTextPairs(text, Pairs); + if (result) + Sort(); + else + Pairs.Clear(); + return result; +} + +void CPairsStorage::SaveToString(UString &text) const +{ + FOR_VECTOR (i, Pairs) + { + const CTextPair &pair = Pairs[i]; + bool multiWord = (pair.ID.Find(L' ') >= 0); + if (multiWord) + text.Add_Char('\"'); + text += pair.ID; + if (multiWord) + text.Add_Char('\"'); + text.Add_Space(); + text += pair.Value; + text.Add_Char('\x0D'); + text.Add_LF(); + } +} diff --git a/CPP/7zip/UI/FileManager/TextPairs.h b/CPP/7zip/UI/FileManager/TextPairs.h index aef4e59f6..d18233d1c 100644 --- a/CPP/7zip/UI/FileManager/TextPairs.h +++ b/CPP/7zip/UI/FileManager/TextPairs.h @@ -1,32 +1,32 @@ -// TextPairs.h - -#ifndef ZIP7_INC_FM_TEXT_PAIRS_H -#define ZIP7_INC_FM_TEXT_PAIRS_H - -#include "../../../Common/MyString.h" - -struct CTextPair -{ - UString ID; - UString Value; -}; - -class CPairsStorage -{ - CObjectVector Pairs; - - int FindID(const UString &id, unsigned &insertPos) const; - int FindID(const UString &id) const; - void Sort(); -public: - void Clear() { Pairs.Clear(); } - bool ReadFromString(const UString &text); - void SaveToString(UString &text) const; - - bool GetValue(const UString &id, UString &value) const; - UString GetValue(const UString &id) const; - void AddPair(const CTextPair &pair); - void DeletePair(const UString &id); -}; - -#endif +// TextPairs.h + +#ifndef ZIP7_INC_FM_TEXT_PAIRS_H +#define ZIP7_INC_FM_TEXT_PAIRS_H + +#include "../../../Common/MyString.h" + +struct CTextPair +{ + UString ID; + UString Value; +}; + +class CPairsStorage +{ + CObjectVector Pairs; + + int FindID(const UString &id, unsigned &insertPos) const; + int FindID(const UString &id) const; + void Sort(); +public: + void Clear() { Pairs.Clear(); } + bool ReadFromString(const UString &text); + void SaveToString(UString &text) const; + + bool GetValue(const UString &id, UString &value) const; + UString GetValue(const UString &id) const; + void AddPair(const CTextPair &pair); + void DeletePair(const UString &id); +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.cpp b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp index ac03ef467..0796eba35 100644 --- a/CPP/7zip/UI/FileManager/UpdateCallback100.cpp +++ b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp @@ -1,124 +1,147 @@ -// UpdateCallback100.cpp - -#include "StdAfx.h" - -#include "../../../Windows/ErrorMsg.h" - -#include "../GUI/resource3.h" - -#include "LangUtils.h" -#include "UpdateCallback100.h" - -Z7_COM7F_IMF(CUpdateCallback100Imp::ScanProgress(UInt64 /* numFolders */, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */)) -{ - return ProgressDialog->Sync.ScanProgress(numFiles, totalSize, us2fs(path)); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode)) -{ - ProgressDialog->Sync.AddError_Code_Name(errorCode, path); - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles)) -{ - return ProgressDialog->Sync.Set_NumFilesTotal(numFiles); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(UInt64 size)) -{ - ProgressDialog->Sync.Set_NumBytesTotal(size); - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 *completed)) -{ - return ProgressDialog->Sync.Set_NumBytesCur(completed); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) -{ - ProgressDialog->Sync.Set_Ratio(inSize, outSize); - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::CompressOperation(const wchar_t *name)) -{ - return SetOperation_Base(NUpdateNotifyOp::kAdd, name, false); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::DeleteOperation(const wchar_t *name)) -{ - return SetOperation_Base(NUpdateNotifyOp::kDelete, name, false); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::OperationResult(Int32 /* operationResult */)) -{ - ProgressDialog->Sync.Set_NumFilesCur(++NumFiles); - return S_OK; -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); - -Z7_COM7F_IMF(CUpdateCallback100Imp::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)) -{ - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - UString s; - SetExtractErrorMessage(opRes, isEncrypted, name, s); - ProgressDialog->Sync.AddError_Message(s); - } - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 notifyOp, const wchar_t *name, Int32 isDir)) -{ - return SetOperation_Base(notifyOp, name, IntToBool(isDir)); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message)) -{ - ProgressDialog->Sync.AddError_Message(message); - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode)) -{ - ProgressDialog->Sync.AddError_Code_Name(errorCode, path); - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode)) -{ - ProgressDialog->Sync.AddError_Code_Name(errorCode, path); - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) -{ - *password = NULL; - *passwordIsDefined = BoolToInt(PasswordIsDefined); - if (!PasswordIsDefined) - return S_OK; - return StringToBstr(Password, password); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)) -{ - return S_OK; -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)) -{ - return ProgressDialog->Sync.CheckStop(); -} - -Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password)) -{ - *password = NULL; - if (!PasswordIsDefined) - { - RINOK(ShowAskPasswordDialog()) - } - return StringToBstr(Password, password); -} +// UpdateCallback100.cpp + +#include "StdAfx.h" + +#include "../../../Windows/ErrorMsg.h" + +#include "../GUI/resource3.h" + +#include "LangUtils.h" +#include "UpdateCallback100.h" + +Z7_COM7F_IMF(CUpdateCallback100Imp::ScanProgress(UInt64 /* numFolders */, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */)) +{ + return ProgressDialog->Sync.ScanProgress(numFiles, totalSize, us2fs(path)); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode)) +{ + ProgressDialog->Sync.AddError_Code_Name(errorCode, path); + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles)) +{ + return ProgressDialog->Sync.Set_NumFilesTotal(numFiles); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(UInt64 size)) +{ + ProgressDialog->Sync.Set_NumBytesTotal(size); + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 *completed)) +{ + return ProgressDialog->Sync.Set_NumBytesCur(completed); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +{ + ProgressDialog->Sync.Set_Ratio(inSize, outSize); + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::CompressOperation(const wchar_t *name)) +{ + return SetOperation_Base(NUpdateNotifyOp::kAdd, name, false); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::DeleteOperation(const wchar_t *name)) +{ + return SetOperation_Base(NUpdateNotifyOp::kDelete, name, false); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::OperationResult(Int32 /* operationResult */)) +{ + ProgressDialog->Sync.Set_NumFilesCur(++NumFiles); + return S_OK; +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); + +Z7_COM7F_IMF(CUpdateCallback100Imp::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)) +{ + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + UString s; + SetExtractErrorMessage(opRes, isEncrypted, name, s); + ProgressDialog->Sync.AddError_Message(s); + } + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 notifyOp, const wchar_t *name, Int32 isDir)) +{ + return SetOperation_Base(notifyOp, name, IntToBool(isDir)); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message)) +{ + ProgressDialog->Sync.AddError_Message(message); + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode)) +{ + ProgressDialog->Sync.AddError_Code_Name(errorCode, path); + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode)) +{ + ProgressDialog->Sync.AddError_Code_Name(errorCode, path); + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) +{ + *password = NULL; + *passwordIsDefined = BoolToInt(PasswordIsDefined); + if (!PasswordIsDefined) + return S_OK; + return StringToBstr(Password, password); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)) +{ + return S_OK; +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)) +{ + return ProgressDialog->Sync.CheckStop(); +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode)) +{ + return MoveArc_Start_Base(srcTempPath, destFinalPath, size, updateMode); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)) +{ + return MoveArc_Progress_Base(totalSize, currentSize); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::MoveArc_Finish()) +{ + return MoveArc_Finish_Base(); +} + +Z7_COM7F_IMF(CUpdateCallback100Imp::Before_ArcReopen()) +{ + ProgressDialog->Sync.Clear_Stop_Status(); + return S_OK; +} + + +Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password)) +{ + *password = NULL; + if (!PasswordIsDefined) + { + RINOK(ShowAskPasswordDialog()) + } + return StringToBstr(Password, password); +} diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.h b/CPP/7zip/UI/FileManager/UpdateCallback100.h index f32ec27c5..adae94fab 100644 --- a/CPP/7zip/UI/FileManager/UpdateCallback100.h +++ b/CPP/7zip/UI/FileManager/UpdateCallback100.h @@ -1,46 +1,49 @@ -// UpdateCallback100.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK100_H -#define ZIP7_INC_UPDATE_CALLBACK100_H - -#include "../../../Common/MyCom.h" - -#include "../../IPassword.h" - -#include "../Agent/IFolderArchive.h" - -#include "../GUI/UpdateCallbackGUI2.h" - -#include "ProgressDialog2.h" - -class CUpdateCallback100Imp Z7_final: - public IFolderArchiveUpdateCallback, - public IFolderArchiveUpdateCallback2, - public IFolderScanProgress, - public ICryptoGetTextPassword2, - public ICryptoGetTextPassword, - public IArchiveOpenCallback, - public ICompressProgressInfo, - public CUpdateCallbackGUI2, - public CMyUnknownImp -{ - Z7_COM_UNKNOWN_IMP_7( - IFolderArchiveUpdateCallback, - IFolderArchiveUpdateCallback2, - IFolderScanProgress, - ICryptoGetTextPassword2, - ICryptoGetTextPassword, - IArchiveOpenCallback, - ICompressProgressInfo) - - Z7_IFACE_COM7_IMP(IProgress) - Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback) - Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback2) - Z7_IFACE_COM7_IMP(IFolderScanProgress) - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2) - Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) - Z7_IFACE_COM7_IMP(IArchiveOpenCallback) - Z7_IFACE_COM7_IMP(ICompressProgressInfo) -}; - -#endif +// UpdateCallback100.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK100_H +#define ZIP7_INC_UPDATE_CALLBACK100_H + +#include "../../../Common/MyCom.h" + +#include "../../IPassword.h" + +#include "../Agent/IFolderArchive.h" + +#include "../GUI/UpdateCallbackGUI2.h" + +#include "ProgressDialog2.h" + +class CUpdateCallback100Imp Z7_final: + public IFolderArchiveUpdateCallback, + public IFolderArchiveUpdateCallback2, + public IFolderArchiveUpdateCallback_MoveArc, + public IFolderScanProgress, + public ICryptoGetTextPassword2, + public ICryptoGetTextPassword, + public IArchiveOpenCallback, + public ICompressProgressInfo, + public CUpdateCallbackGUI2, + public CMyUnknownImp +{ + Z7_COM_UNKNOWN_IMP_8( + IFolderArchiveUpdateCallback, + IFolderArchiveUpdateCallback2, + IFolderArchiveUpdateCallback_MoveArc, + IFolderScanProgress, + ICryptoGetTextPassword2, + ICryptoGetTextPassword, + IArchiveOpenCallback, + ICompressProgressInfo) + + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback) + Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback2) + Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback_MoveArc) + Z7_IFACE_COM7_IMP(IFolderScanProgress) + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2) + Z7_IFACE_COM7_IMP(ICryptoGetTextPassword) + Z7_IFACE_COM7_IMP(IArchiveOpenCallback) + Z7_IFACE_COM7_IMP(ICompressProgressInfo) +}; + +#endif diff --git a/CPP/7zip/UI/FileManager/VerCtrl.cpp b/CPP/7zip/UI/FileManager/VerCtrl.cpp index 231d54af6..c1ca643a7 100644 --- a/CPP/7zip/UI/FileManager/VerCtrl.cpp +++ b/CPP/7zip/UI/FileManager/VerCtrl.cpp @@ -1,428 +1,428 @@ -// VerCtrl.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileFind.h" - -#include "App.h" -#include "RegistryUtils.h" -#include "OverwriteDialog.h" - -#include "resource.h" - -using namespace NWindows; -using namespace NFile; -using namespace NFind; -using namespace NDir; - -static FString ConvertPath_to_Ctrl(const FString &path) -{ - FString s = path; - s.Replace(FChar(':'), FChar('_')); - return s; -} - -struct CFileDataInfo -{ - CByteBuffer Data; - BY_HANDLE_FILE_INFORMATION Info; - bool IsOpen; - - CFileDataInfo(): IsOpen (false) {} - UInt64 GetSize() const { return (((UInt64)Info.nFileSizeHigh) << 32) + Info.nFileSizeLow; } - bool Read(const FString &path); -}; - - -bool CFileDataInfo::Read(const FString &path) -{ - IsOpen = false; - NIO::CInFile file; - if (!file.Open(path)) - return false; - if (!file.GetFileInformation(&Info)) - return false; - - const UInt64 size = GetSize(); - const size_t size2 = (size_t)size; - if (size2 != size || size2 > (1 << 28)) - { - SetLastError(1); - return false; - } - - Data.Alloc(size2); - - size_t processedSize; - if (!file.ReadFull(Data, size2, processedSize)) - return false; - if (processedSize != size2) - { - SetLastError(1); - return false; - } - IsOpen = true; - return true; -} - - -static bool CreateComplexDir_for_File(const FString &path) -{ - FString resDirPrefix; - FString resFileName; - if (!GetFullPathAndSplit(path, resDirPrefix, resFileName)) - return false; - return CreateComplexDir(resDirPrefix); -} - - -static bool ParseNumberString(const FString &s, UInt32 &number) -{ - const FChar *end; - UInt64 result = ConvertStringToUInt64(s, &end); - if (*end != 0 || s.IsEmpty() || result > (UInt32)0x7FFFFFFF) - return false; - number = (UInt32)result; - return true; -} - - -static void WriteFile(const FString &path, bool createAlways, const CFileDataInfo &fdi, const CPanel &panel) -{ - NIO::COutFile outFile; - if (!outFile.Create_ALWAYS_or_NEW(path, createAlways)) // (createAlways = false) means CREATE_NEW - { - panel.MessageBox_LastError(); - return; - } - UInt32 processedSize; - if (!outFile.Write(fdi.Data, (UInt32)fdi.Data.Size(), processedSize)) - { - panel.MessageBox_LastError(); - return; - } - if (processedSize != fdi.Data.Size()) - { - panel.MessageBox_Error(L"Write error"); - return; - } - if (!outFile.SetTime( - &fdi.Info.ftCreationTime, - &fdi.Info.ftLastAccessTime, - &fdi.Info.ftLastWriteTime)) - { - panel.MessageBox_LastError(); - return; - } - - if (!SetFileAttrib(path, fdi.Info.dwFileAttributes)) - { - panel.MessageBox_LastError(); - return; - } -} - - -static UInt64 FILETIME_to_UInt64(const FILETIME &ft) -{ - return ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); -} - -static void UInt64_TO_FILETIME(UInt64 v, FILETIME &ft) -{ - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - - -void CApp::VerCtrl(unsigned id) -{ - const CPanel &panel = GetFocusedPanel(); - - if (!panel.Is_IO_FS_Folder()) - { - panel.MessageBox_Error_UnsupportOperation(); - return; - } - - CRecordVector indices; - panel.Get_ItemIndices_Selected(indices); - - if (indices.Size() != 1) - { - // panel.MessageBox_Error_UnsupportOperation(); - return; - } - - const FString path = us2fs(panel.GetItemFullPath(indices[0])); - - UString vercPath; - ReadReg_VerCtrlPath(vercPath); - if (vercPath.IsEmpty()) - return; - NName::NormalizeDirPathPrefix(vercPath); - - FString dirPrefix; - FString fileName; - if (!GetFullPathAndSplit(path, dirPrefix, fileName)) - { - panel.MessageBox_LastError(); - return; - } - - const FString dirPrefix2 = us2fs(vercPath) + ConvertPath_to_Ctrl(dirPrefix); - const FString path2 = dirPrefix2 + fileName; - - bool sameTime = false; - bool sameData = false; - bool areIdentical = false; - - CFileDataInfo fdi, fdi2; - if (!fdi.Read(path)) - { - panel.MessageBox_LastError(); - return; - } - - if (fdi2.Read(path2)) - { - sameData = (fdi.Data == fdi2.Data); - sameTime = (CompareFileTime(&fdi.Info.ftLastWriteTime, &fdi2.Info.ftLastWriteTime) == 0); - areIdentical = (sameData && sameTime); - } - - const bool isReadOnly = NAttributes::IsReadOnly(fdi.Info.dwFileAttributes); - - if (id == IDM_VER_EDIT) - { - if (!isReadOnly) - { - panel.MessageBox_Error(L"File is not read-only"); - return; - } - - if (!areIdentical) - { - if (fdi2.IsOpen) - { - NFind::CEnumerator enumerator; - FString d2 = dirPrefix2; - d2 += "_7vc"; - d2.Add_PathSepar(); - d2 += fileName; - d2.Add_PathSepar(); - enumerator.SetDirPrefix(d2); - NFind::CDirEntry fi; - Int32 maxVal = -1; - while (enumerator.Next(fi)) - { - UInt32 val; - if (!ParseNumberString(fi.Name, val)) - continue; - if ((Int32)val > maxVal) - maxVal = (Int32)val; - } - - UInt32 next = (UInt32)maxVal + 1; - if (maxVal < 0) - { - next = 1; - if (!::CreateComplexDir_for_File(path2)) - { - panel.MessageBox_LastError(); - return; - } - } - - // we rename old file2 to some name; - FString path_num = d2; - { - AString t; - t.Add_UInt32((UInt32)next); - while (t.Len() < 3) - t.InsertAtFront('0'); - path_num += t; - } - - if (maxVal < 0) - { - if (!::CreateComplexDir_for_File(path_num)) - { - panel.MessageBox_LastError(); - return; - } - } - - if (!NDir::MyMoveFile(path2, path_num)) - { - panel.MessageBox_LastError(); - return; - } - } - else - { - if (!::CreateComplexDir_for_File(path2)) - { - panel.MessageBox_LastError(); - return; - } - } - /* - if (!::CopyFile(fs2fas(path), fs2fas(path2), TRUE)) - { - panel.MessageBox_LastError(); - return; - } - */ - WriteFile(path2, - false, // (createAlways = false) means CREATE_NEW - fdi, panel); - } - - if (!SetFileAttrib(path, fdi.Info.dwFileAttributes & ~(DWORD)FILE_ATTRIBUTE_READONLY)) - { - panel.MessageBox_LastError(); - return; - } - - return; - } - - if (isReadOnly) - { - panel.MessageBox_Error(L"File is read-only"); - return; - } - - if (id == IDM_VER_COMMIT) - { - if (sameData) - { - if (!sameTime) - { - panel.MessageBox_Error( - L"Same data, but different timestamps.\n" - L"Use `Revert` to recover timestamp."); - return; - } - } - - const UInt64 timeStampOriginal = FILETIME_to_UInt64(fdi.Info.ftLastWriteTime); - UInt64 timeStamp2 = 0; - if (fdi2.IsOpen) - timeStamp2 = FILETIME_to_UInt64(fdi2.Info.ftLastWriteTime); - - if (timeStampOriginal > timeStamp2) - { - const UInt64 k_Ntfs_prec = 10000000; - UInt64 timeStamp = timeStampOriginal; - const UInt32 k_precs[] = { 60 * 60, 60, 2, 1 }; - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_precs); i++) - { - timeStamp = timeStampOriginal; - const UInt64 prec = k_Ntfs_prec * k_precs[i]; - // timeStamp += prec - 1; // for rounding up - timeStamp /= prec; - timeStamp *= prec; - if (timeStamp > timeStamp2) - break; - } - - if (timeStamp != timeStampOriginal - && timeStamp > timeStamp2) - { - FILETIME mTime; - UInt64_TO_FILETIME(timeStamp, mTime); - // NDir::SetFileAttrib(path, 0); - { - NIO::COutFile outFile; - if (!outFile.Open_EXISTING(path)) - { - panel.MessageBox_LastError(); - return; - // if (::GetLastError() != ERROR_SUCCESS) - // throw "open error"; - } - else - { - const UInt64 cTime = FILETIME_to_UInt64(fdi.Info.ftCreationTime); - if (cTime > timeStamp) - outFile.SetTime(&mTime, NULL, &mTime); - else - outFile.SetMTime(&mTime); - } - } - } - } - - if (!SetFileAttrib(path, fdi.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) - { - panel.MessageBox_LastError(); - return; - } - return; - } - - if (id == IDM_VER_REVERT) - { - if (!fdi2.IsOpen) - { - panel.MessageBox_Error(L"No file to revert"); - return; - } - if (!sameData || !sameTime) - { - if (!sameData) - { - /* - UString m; - m = "Are you sure you want to revert file ?"; - m.Add_LF(); - m += path; - if (::MessageBoxW(panel.GetParent(), m, L"Version Control: File Revert", MB_OKCANCEL | MB_ICONQUESTION) != IDOK) - return; - */ - COverwriteDialog dialog; - - dialog.OldFileInfo.SetTime(fdi.Info.ftLastWriteTime); - dialog.OldFileInfo.SetSize(fdi.GetSize()); - dialog.OldFileInfo.Path = fs2us(path); - - dialog.NewFileInfo.SetTime(fdi2.Info.ftLastWriteTime); - dialog.NewFileInfo.SetSize(fdi2.GetSize()); - dialog.NewFileInfo.Path = fs2us(path2); - - dialog.ShowExtraButtons = false; - dialog.DefaultButton_is_NO = true; - - INT_PTR writeAnswer = dialog.Create(panel.GetParent()); - - if (writeAnswer != IDYES) - return; - } - - WriteFile(path, - true, // (createAlways = true) means CREATE_ALWAYS - fdi2, panel); - } - else - { - if (!SetFileAttrib(path, fdi2.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) - { - panel.MessageBox_LastError(); - return; - } - } - return; - } - - // if (id == IDM_VER_DIFF) - { - if (!fdi2.IsOpen) - return; - DiffFiles(fs2us(path2), fs2us(path)); - } -} +// VerCtrl.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileFind.h" + +#include "App.h" +#include "RegistryUtils.h" +#include "OverwriteDialog.h" + +#include "resource.h" + +using namespace NWindows; +using namespace NFile; +using namespace NFind; +using namespace NDir; + +static FString ConvertPath_to_Ctrl(const FString &path) +{ + FString s = path; + s.Replace(FChar(':'), FChar('_')); + return s; +} + +struct CFileDataInfo +{ + CByteBuffer Data; + BY_HANDLE_FILE_INFORMATION Info; + bool IsOpen; + + CFileDataInfo(): IsOpen (false) {} + UInt64 GetSize() const { return (((UInt64)Info.nFileSizeHigh) << 32) + Info.nFileSizeLow; } + bool Read(const FString &path); +}; + + +bool CFileDataInfo::Read(const FString &path) +{ + IsOpen = false; + NIO::CInFile file; + if (!file.Open(path)) + return false; + if (!file.GetFileInformation(&Info)) + return false; + + const UInt64 size = GetSize(); + const size_t size2 = (size_t)size; + if (size2 != size || size2 > (1 << 28)) + { + SetLastError(1); + return false; + } + + Data.Alloc(size2); + + size_t processedSize; + if (!file.ReadFull(Data, size2, processedSize)) + return false; + if (processedSize != size2) + { + SetLastError(1); + return false; + } + IsOpen = true; + return true; +} + + +static bool CreateComplexDir_for_File(const FString &path) +{ + FString resDirPrefix; + FString resFileName; + if (!GetFullPathAndSplit(path, resDirPrefix, resFileName)) + return false; + return CreateComplexDir(resDirPrefix); +} + + +static bool ParseNumberString(const FString &s, UInt32 &number) +{ + const FChar *end; + UInt64 result = ConvertStringToUInt64(s, &end); + if (*end != 0 || s.IsEmpty() || result > (UInt32)0x7FFFFFFF) + return false; + number = (UInt32)result; + return true; +} + + +static void WriteFile(const FString &path, bool createAlways, const CFileDataInfo &fdi, const CPanel &panel) +{ + NIO::COutFile outFile; + if (!outFile.Create_ALWAYS_or_NEW(path, createAlways)) // (createAlways = false) means CREATE_NEW + { + panel.MessageBox_LastError(); + return; + } + UInt32 processedSize; + if (!outFile.Write(fdi.Data, (UInt32)fdi.Data.Size(), processedSize)) + { + panel.MessageBox_LastError(); + return; + } + if (processedSize != fdi.Data.Size()) + { + panel.MessageBox_Error(L"Write error"); + return; + } + if (!outFile.SetTime( + &fdi.Info.ftCreationTime, + &fdi.Info.ftLastAccessTime, + &fdi.Info.ftLastWriteTime)) + { + panel.MessageBox_LastError(); + return; + } + + if (!SetFileAttrib(path, fdi.Info.dwFileAttributes)) + { + panel.MessageBox_LastError(); + return; + } +} + + +static UInt64 FILETIME_to_UInt64(const FILETIME &ft) +{ + return ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); +} + +static void UInt64_TO_FILETIME(UInt64 v, FILETIME &ft) +{ + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + + +void CApp::VerCtrl(unsigned id) +{ + const CPanel &panel = GetFocusedPanel(); + + if (!panel.Is_IO_FS_Folder()) + { + panel.MessageBox_Error_UnsupportOperation(); + return; + } + + CRecordVector indices; + panel.Get_ItemIndices_Selected(indices); + + if (indices.Size() != 1) + { + // panel.MessageBox_Error_UnsupportOperation(); + return; + } + + const FString path = us2fs(panel.GetItemFullPath(indices[0])); + + UString vercPath; + ReadReg_VerCtrlPath(vercPath); + if (vercPath.IsEmpty()) + return; + NName::NormalizeDirPathPrefix(vercPath); + + FString dirPrefix; + FString fileName; + if (!GetFullPathAndSplit(path, dirPrefix, fileName)) + { + panel.MessageBox_LastError(); + return; + } + + const FString dirPrefix2 = us2fs(vercPath) + ConvertPath_to_Ctrl(dirPrefix); + const FString path2 = dirPrefix2 + fileName; + + bool sameTime = false; + bool sameData = false; + bool areIdentical = false; + + CFileDataInfo fdi, fdi2; + if (!fdi.Read(path)) + { + panel.MessageBox_LastError(); + return; + } + + if (fdi2.Read(path2)) + { + sameData = (fdi.Data == fdi2.Data); + sameTime = (CompareFileTime(&fdi.Info.ftLastWriteTime, &fdi2.Info.ftLastWriteTime) == 0); + areIdentical = (sameData && sameTime); + } + + const bool isReadOnly = NAttributes::IsReadOnly(fdi.Info.dwFileAttributes); + + if (id == IDM_VER_EDIT) + { + if (!isReadOnly) + { + panel.MessageBox_Error(L"File is not read-only"); + return; + } + + if (!areIdentical) + { + if (fdi2.IsOpen) + { + NFind::CEnumerator enumerator; + FString d2 = dirPrefix2; + d2 += "_7vc"; + d2.Add_PathSepar(); + d2 += fileName; + d2.Add_PathSepar(); + enumerator.SetDirPrefix(d2); + NFind::CDirEntry fi; + Int32 maxVal = -1; + while (enumerator.Next(fi)) + { + UInt32 val; + if (!ParseNumberString(fi.Name, val)) + continue; + if ((Int32)val > maxVal) + maxVal = (Int32)val; + } + + UInt32 next = (UInt32)maxVal + 1; + if (maxVal < 0) + { + next = 1; + if (!::CreateComplexDir_for_File(path2)) + { + panel.MessageBox_LastError(); + return; + } + } + + // we rename old file2 to some name; + FString path_num = d2; + { + AString t; + t.Add_UInt32((UInt32)next); + while (t.Len() < 3) + t.InsertAtFront('0'); + path_num += t; + } + + if (maxVal < 0) + { + if (!::CreateComplexDir_for_File(path_num)) + { + panel.MessageBox_LastError(); + return; + } + } + + if (!NDir::MyMoveFile(path2, path_num)) + { + panel.MessageBox_LastError(); + return; + } + } + else + { + if (!::CreateComplexDir_for_File(path2)) + { + panel.MessageBox_LastError(); + return; + } + } + /* + if (!::CopyFile(fs2fas(path), fs2fas(path2), TRUE)) + { + panel.MessageBox_LastError(); + return; + } + */ + WriteFile(path2, + false, // (createAlways = false) means CREATE_NEW + fdi, panel); + } + + if (!SetFileAttrib(path, fdi.Info.dwFileAttributes & ~(DWORD)FILE_ATTRIBUTE_READONLY)) + { + panel.MessageBox_LastError(); + return; + } + + return; + } + + if (isReadOnly) + { + panel.MessageBox_Error(L"File is read-only"); + return; + } + + if (id == IDM_VER_COMMIT) + { + if (sameData) + { + if (!sameTime) + { + panel.MessageBox_Error( + L"Same data, but different timestamps.\n" + L"Use `Revert` to recover timestamp."); + return; + } + } + + const UInt64 timeStampOriginal = FILETIME_to_UInt64(fdi.Info.ftLastWriteTime); + UInt64 timeStamp2 = 0; + if (fdi2.IsOpen) + timeStamp2 = FILETIME_to_UInt64(fdi2.Info.ftLastWriteTime); + + if (timeStampOriginal > timeStamp2) + { + const UInt64 k_Ntfs_prec = 10000000; + UInt64 timeStamp = timeStampOriginal; + const UInt32 k_precs[] = { 60 * 60, 60, 2, 1 }; + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_precs); i++) + { + timeStamp = timeStampOriginal; + const UInt64 prec = k_Ntfs_prec * k_precs[i]; + // timeStamp += prec - 1; // for rounding up + timeStamp /= prec; + timeStamp *= prec; + if (timeStamp > timeStamp2) + break; + } + + if (timeStamp != timeStampOriginal + && timeStamp > timeStamp2) + { + FILETIME mTime; + UInt64_TO_FILETIME(timeStamp, mTime); + // NDir::SetFileAttrib(path, 0); + { + NIO::COutFile outFile; + if (!outFile.Open_EXISTING(path)) + { + panel.MessageBox_LastError(); + return; + // if (::GetLastError() != ERROR_SUCCESS) + // throw "open error"; + } + else + { + const UInt64 cTime = FILETIME_to_UInt64(fdi.Info.ftCreationTime); + if (cTime > timeStamp) + outFile.SetTime(&mTime, NULL, &mTime); + else + outFile.SetMTime(&mTime); + } + } + } + } + + if (!SetFileAttrib(path, fdi.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) + { + panel.MessageBox_LastError(); + return; + } + return; + } + + if (id == IDM_VER_REVERT) + { + if (!fdi2.IsOpen) + { + panel.MessageBox_Error(L"No file to revert"); + return; + } + if (!sameData || !sameTime) + { + if (!sameData) + { + /* + UString m; + m = "Are you sure you want to revert file ?"; + m.Add_LF(); + m += path; + if (::MessageBoxW(panel.GetParent(), m, L"Version Control: File Revert", MB_OKCANCEL | MB_ICONQUESTION) != IDOK) + return; + */ + COverwriteDialog dialog; + + dialog.OldFileInfo.SetTime(fdi.Info.ftLastWriteTime); + dialog.OldFileInfo.SetSize(fdi.GetSize()); + dialog.OldFileInfo.Path = fs2us(path); + + dialog.NewFileInfo.SetTime(fdi2.Info.ftLastWriteTime); + dialog.NewFileInfo.SetSize(fdi2.GetSize()); + dialog.NewFileInfo.Path = fs2us(path2); + + dialog.ShowExtraButtons = false; + dialog.DefaultButton_is_NO = true; + + INT_PTR writeAnswer = dialog.Create(panel.GetParent()); + + if (writeAnswer != IDYES) + return; + } + + WriteFile(path, + true, // (createAlways = true) means CREATE_ALWAYS + fdi2, panel); + } + else + { + if (!SetFileAttrib(path, fdi2.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) + { + panel.MessageBox_LastError(); + return; + } + } + return; + } + + // if (id == IDM_VER_DIFF) + { + if (!fdi2.IsOpen) + return; + DiffFiles(fs2us(path2), fs2us(path)); + } +} diff --git a/CPP/7zip/UI/FileManager/ViewSettings.cpp b/CPP/7zip/UI/FileManager/ViewSettings.cpp index 08880765d..4a8f58dac 100644 --- a/CPP/7zip/UI/FileManager/ViewSettings.cpp +++ b/CPP/7zip/UI/FileManager/ViewSettings.cpp @@ -1,314 +1,315 @@ -// ViewSettings.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/Registry.h" -#include "../../../Windows/Synchronization.h" - -#include "ViewSettings.h" - -using namespace NWindows; -using namespace NRegistry; - -#define REG_PATH_FM TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR) TEXT("FM") - -static LPCTSTR const kCUBasePath = REG_PATH_FM; -static LPCTSTR const kCulumnsKeyName = REG_PATH_FM TEXT(STRING_PATH_SEPARATOR) TEXT("Columns"); - -static LPCTSTR const kPositionValueName = TEXT("Position"); -static LPCTSTR const kPanelsInfoValueName = TEXT("Panels"); -static LPCTSTR const kToolbars = TEXT("Toolbars"); - -static LPCWSTR const kPanelPathValueName = L"PanelPath"; - -static LPCTSTR const kListMode = TEXT("ListMode"); -static LPCTSTR const kFolderHistoryValueName = TEXT("FolderHistory"); -static LPCTSTR const kFastFoldersValueName = TEXT("FolderShortcuts"); -static LPCTSTR const kCopyHistoryValueName = TEXT("CopyHistory"); - -static NSynchronization::CCriticalSection g_CS; - -#define Set32(p, v) SetUi32(((Byte *)p), v) -#define SetBool(p, v) Set32(p, ((v) ? 1 : 0)) - -#define Get32(p, dest) dest = GetUi32((const Byte *)p); -#define Get32_LONG(p, dest) dest = (LONG)GetUi32((const Byte *)p); -#define GetBool(p, dest) dest = (GetUi32(p) != 0); - -/* -struct CColumnHeader -{ - UInt32 Version; - UInt32 SortID; - UInt32 Ascending; // bool -}; -*/ - -static const UInt32 kListViewHeaderSize = 3 * 4; -static const UInt32 kColumnInfoSize = 3 * 4; -static const UInt32 kListViewVersion = 1; - -void CListViewInfo::Save(const UString &id) const -{ - const UInt32 dataSize = kListViewHeaderSize + kColumnInfoSize * Columns.Size(); - CByteArr buf(dataSize); - - Set32(buf, kListViewVersion) - Set32(buf + 4, SortID) - SetBool(buf + 8, Ascending) - FOR_VECTOR (i, Columns) - { - const CColumnInfo &column = Columns[i]; - Byte *p = buf + kListViewHeaderSize + i * kColumnInfoSize; - Set32(p, column.PropID) - SetBool(p + 4, column.IsVisible) - Set32(p + 8, column.Width) - } - { - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - key.Create(HKEY_CURRENT_USER, kCulumnsKeyName); - key.SetValue(GetSystemString(id), (const Byte *)buf, dataSize); - } -} - -void CListViewInfo::Read(const UString &id) -{ - Clear(); - CByteBuffer buf; - UInt32 size; - { - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCulumnsKeyName, KEY_READ) != ERROR_SUCCESS) - return; - if (key.QueryValue(GetSystemString(id), buf, size) != ERROR_SUCCESS) - return; - } - if (size < kListViewHeaderSize) - return; - UInt32 version; - Get32(buf, version) - if (version != kListViewVersion) - return; - Get32(buf + 4, SortID) - GetBool(buf + 8, Ascending) - - IsLoaded = true; - - size -= kListViewHeaderSize; - if (size % kColumnInfoSize != 0) - return; - unsigned numItems = size / kColumnInfoSize; - Columns.ClearAndReserve(numItems); - for (unsigned i = 0; i < numItems; i++) - { - CColumnInfo column; - const Byte *p = buf + kListViewHeaderSize + i * kColumnInfoSize; - Get32(p, column.PropID) - GetBool(p + 4, column.IsVisible) - Get32(p + 8, column.Width) - Columns.AddInReserved(column); - } -} - - -/* -struct CWindowPosition -{ - RECT Rect; - UInt32 Maximized; // bool -}; - -struct CPanelsInfo -{ - UInt32 NumPanels; - UInt32 CurrentPanel; - UInt32 SplitterPos; -}; -*/ - -static const UInt32 kWindowPositionHeaderSize = 5 * 4; -static const UInt32 kPanelsInfoHeaderSize = 3 * 4; - -void CWindowInfo::Save() const -{ - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - key.Create(HKEY_CURRENT_USER, kCUBasePath); - { - Byte buf[kWindowPositionHeaderSize]; - Set32(buf, (UInt32)rect.left) - Set32(buf + 4, (UInt32)rect.top) - Set32(buf + 8, (UInt32)rect.right) - Set32(buf + 12, (UInt32)rect.bottom) - SetBool(buf + 16, maximized) - key.SetValue(kPositionValueName, buf, kWindowPositionHeaderSize); - } - { - Byte buf[kPanelsInfoHeaderSize]; - Set32(buf, numPanels) - Set32(buf + 4, currentPanel) - Set32(buf + 8, splitterPos) - key.SetValue(kPanelsInfoValueName, buf, kPanelsInfoHeaderSize); - } -} - -static bool QueryBuf(CKey &key, LPCTSTR name, CByteBuffer &buf, UInt32 dataSize) -{ - UInt32 size; - return key.QueryValue(name, buf, size) == ERROR_SUCCESS && size == dataSize; -} - -void CWindowInfo::Read(bool &windowPosDefined, bool &panelInfoDefined) -{ - windowPosDefined = false; - panelInfoDefined = false; - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) - return; - CByteBuffer buf; - if (QueryBuf(key, kPositionValueName, buf, kWindowPositionHeaderSize)) - { - Get32_LONG(buf, rect.left) - Get32_LONG(buf + 4, rect.top) - Get32_LONG(buf + 8, rect.right) - Get32_LONG(buf + 12, rect.bottom) - GetBool(buf + 16, maximized) - windowPosDefined = true; - } - if (QueryBuf(key, kPanelsInfoValueName, buf, kPanelsInfoHeaderSize)) - { - Get32(buf, numPanels) - Get32(buf + 4, currentPanel) - Get32(buf + 8, splitterPos) - panelInfoDefined = true; - } - return; -} - - -static void SaveUi32Val(const TCHAR *name, UInt32 value) -{ - CKey key; - key.Create(HKEY_CURRENT_USER, kCUBasePath); - key.SetValue(name, value); -} - -static bool ReadUi32Val(const TCHAR *name, UInt32 &value) -{ - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) - return false; - return key.QueryValue(name, value) == ERROR_SUCCESS; -} - -void SaveToolbarsMask(UInt32 toolbarMask) -{ - SaveUi32Val(kToolbars, toolbarMask); -} - -static const UInt32 kDefaultToolbarMask = ((UInt32)1 << 31) | 8 | 4 | 1; - -UInt32 ReadToolbarsMask() -{ - UInt32 mask; - if (!ReadUi32Val(kToolbars, mask)) - return kDefaultToolbarMask; - return mask; -} - - -void CListMode::Save() const -{ - UInt32 t = 0; - for (int i = 0; i < 2; i++) - t |= ((Panels[i]) & 0xFF) << (i * 8); - SaveUi32Val(kListMode, t); -} - -void CListMode::Read() -{ - Init(); - UInt32 t; - if (!ReadUi32Val(kListMode, t)) - return; - for (int i = 0; i < 2; i++) - { - Panels[i] = (t & 0xFF); - t >>= 8; - } -} - -static UString GetPanelPathName(UInt32 panelIndex) -{ - UString s (kPanelPathValueName); - s.Add_UInt32(panelIndex); - return s; -} - -void SavePanelPath(UInt32 panel, const UString &path) -{ - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - key.Create(HKEY_CURRENT_USER, kCUBasePath); - key.SetValue(GetPanelPathName(panel), path); -} - -bool ReadPanelPath(UInt32 panel, UString &path) -{ - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) - return false; - return (key.QueryValue(GetPanelPathName(panel), path) == ERROR_SUCCESS); -} - - -static void SaveStringList(LPCTSTR valueName, const UStringVector &folders) -{ - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - key.Create(HKEY_CURRENT_USER, kCUBasePath); - key.SetValue_Strings(valueName, folders); -} - -static void ReadStringList(LPCTSTR valueName, UStringVector &folders) -{ - folders.Clear(); - NSynchronization::CCriticalSectionLock lock(g_CS); - CKey key; - if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS) - key.GetValue_Strings(valueName, folders); -} - -void SaveFolderHistory(const UStringVector &folders) - { SaveStringList(kFolderHistoryValueName, folders); } -void ReadFolderHistory(UStringVector &folders) - { ReadStringList(kFolderHistoryValueName, folders); } - -void SaveFastFolders(const UStringVector &folders) - { SaveStringList(kFastFoldersValueName, folders); } -void ReadFastFolders(UStringVector &folders) - { ReadStringList(kFastFoldersValueName, folders); } - -void SaveCopyHistory(const UStringVector &folders) - { SaveStringList(kCopyHistoryValueName, folders); } -void ReadCopyHistory(UStringVector &folders) - { ReadStringList(kCopyHistoryValueName, folders); } - -void AddUniqueStringToHeadOfList(UStringVector &list, const UString &s) -{ - for (unsigned i = 0; i < list.Size();) - if (s.IsEqualTo_NoCase(list[i])) - list.Delete(i); - else - i++; - list.Insert(0, s); -} +// ViewSettings.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/Registry.h" +#include "../../../Windows/Synchronization.h" + +#include "ViewSettings.h" + +using namespace NWindows; +using namespace NRegistry; + +#define REG_PATH_FM TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR) TEXT("FM") + +static LPCTSTR const kCUBasePath = REG_PATH_FM; +static LPCTSTR const kCulumnsKeyName = REG_PATH_FM TEXT(STRING_PATH_SEPARATOR) TEXT("Columns"); + +static LPCTSTR const kPositionValueName = TEXT("Position"); +static LPCTSTR const kPanelsInfoValueName = TEXT("Panels"); +static LPCTSTR const kToolbars = TEXT("Toolbars"); + +static LPCWSTR const kPanelPathValueName = L"PanelPath"; + +static LPCTSTR const kListMode = TEXT("ListMode"); +static LPCTSTR const kFolderHistoryValueName = TEXT("FolderHistory"); +static LPCTSTR const kFastFoldersValueName = TEXT("FolderShortcuts"); +static LPCTSTR const kCopyHistoryValueName = TEXT("CopyHistory"); + +static NSynchronization::CCriticalSection g_CS; + +#define Set32(p, v) SetUi32(((Byte *)p), v) +#define SetBool(p, v) Set32(p, ((v) ? 1 : 0)) + +#define Get32(p, dest) dest = GetUi32((const Byte *)p); +#define Get32_LONG(p, dest) dest = (LONG)GetUi32((const Byte *)p); +#define GetBool(p, dest) dest = (GetUi32(p) != 0); + +/* +struct CColumnHeader +{ + UInt32 Version; + UInt32 SortID; + UInt32 Ascending; // bool +}; +*/ + +static const UInt32 kListViewHeaderSize = 3 * 4; +static const UInt32 kColumnInfoSize = 3 * 4; +static const UInt32 kListViewVersion = 1; + +void CListViewInfo::Save(const UString &id) const +{ + const UInt32 dataSize = kListViewHeaderSize + kColumnInfoSize * Columns.Size(); + CByteArr buf(dataSize); + + Set32(buf, kListViewVersion) + Set32(buf + 4, SortID) + SetBool(buf + 8, Ascending) + FOR_VECTOR (i, Columns) + { + const CColumnInfo &column = Columns[i]; + Byte *p = buf + kListViewHeaderSize + i * kColumnInfoSize; + Set32(p, column.PropID) + SetBool(p + 4, column.IsVisible) + Set32(p + 8, column.Width) + } + { + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + key.Create(HKEY_CURRENT_USER, kCulumnsKeyName); + key.SetValue(GetSystemString(id), (const Byte *)buf, dataSize); + } +} + +void CListViewInfo::Read(const UString &id) +{ + Clear(); + CByteBuffer buf; + { + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCulumnsKeyName, KEY_READ) != ERROR_SUCCESS) + return; + if (key.QueryValue_Binary(GetSystemString(id), buf) != ERROR_SUCCESS) + return; + } + unsigned size = (unsigned)buf.Size(); + if (size < kListViewHeaderSize) + return; + UInt32 version; + Get32(buf, version) + if (version != kListViewVersion) + return; + Get32(buf + 4, SortID) + GetBool(buf + 8, Ascending) + + IsLoaded = true; + + size -= kListViewHeaderSize; + if (size % kColumnInfoSize != 0) + return; + if (size > 1000 * kColumnInfoSize) + return; + const unsigned numItems = size / kColumnInfoSize; + Columns.ClearAndReserve(numItems); + for (unsigned i = 0; i < numItems; i++) + { + CColumnInfo column; + const Byte *p = buf + kListViewHeaderSize + i * kColumnInfoSize; + Get32(p, column.PropID) + GetBool(p + 4, column.IsVisible) + Get32(p + 8, column.Width) + Columns.AddInReserved(column); + } +} + + +/* +struct CWindowPosition +{ + RECT Rect; + UInt32 Maximized; // bool +}; + +struct CPanelsInfo +{ + UInt32 NumPanels; + UInt32 CurrentPanel; + UInt32 SplitterPos; +}; +*/ + +static const UInt32 kWindowPositionHeaderSize = 5 * 4; +static const UInt32 kPanelsInfoHeaderSize = 3 * 4; + +void CWindowInfo::Save() const +{ + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + key.Create(HKEY_CURRENT_USER, kCUBasePath); + { + Byte buf[kWindowPositionHeaderSize]; + Set32(buf, (UInt32)rect.left) + Set32(buf + 4, (UInt32)rect.top) + Set32(buf + 8, (UInt32)rect.right) + Set32(buf + 12, (UInt32)rect.bottom) + SetBool(buf + 16, maximized) + key.SetValue(kPositionValueName, buf, kWindowPositionHeaderSize); + } + { + Byte buf[kPanelsInfoHeaderSize]; + Set32(buf, numPanels) + Set32(buf + 4, currentPanel) + Set32(buf + 8, splitterPos) + key.SetValue(kPanelsInfoValueName, buf, kPanelsInfoHeaderSize); + } +} + +static bool QueryBuf(CKey &key, LPCTSTR name, CByteBuffer &buf, UInt32 dataSize) +{ + return key.QueryValue_Binary(name, buf) == ERROR_SUCCESS && buf.Size() == dataSize; +} + +void CWindowInfo::Read(bool &windowPosDefined, bool &panelInfoDefined) +{ + windowPosDefined = false; + panelInfoDefined = false; + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) + return; + CByteBuffer buf; + if (QueryBuf(key, kPositionValueName, buf, kWindowPositionHeaderSize)) + { + Get32_LONG(buf, rect.left) + Get32_LONG(buf + 4, rect.top) + Get32_LONG(buf + 8, rect.right) + Get32_LONG(buf + 12, rect.bottom) + GetBool(buf + 16, maximized) + windowPosDefined = true; + } + if (QueryBuf(key, kPanelsInfoValueName, buf, kPanelsInfoHeaderSize)) + { + Get32(buf, numPanels) + Get32(buf + 4, currentPanel) + Get32(buf + 8, splitterPos) + panelInfoDefined = true; + } + return; +} + + +static void SaveUi32Val(const TCHAR *name, UInt32 value) +{ + CKey key; + key.Create(HKEY_CURRENT_USER, kCUBasePath); + key.SetValue(name, value); +} + +static bool ReadUi32Val(const TCHAR *name, UInt32 &value) +{ + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) + return false; + return key.GetValue_UInt32_IfOk(name, value) == ERROR_SUCCESS; +} + +void SaveToolbarsMask(UInt32 toolbarMask) +{ + SaveUi32Val(kToolbars, toolbarMask); +} + +static const UInt32 kDefaultToolbarMask = ((UInt32)1 << 31) | 8 | 4 | 1; + +UInt32 ReadToolbarsMask() +{ + UInt32 mask; + if (!ReadUi32Val(kToolbars, mask)) + return kDefaultToolbarMask; + return mask; +} + + +void CListMode::Save() const +{ + UInt32 t = 0; + for (int i = 0; i < 2; i++) + t |= (Panels[i] & 0xFF) << (i * 8); + SaveUi32Val(kListMode, t); +} + +void CListMode::Read() +{ + Init(); + UInt32 t; + if (!ReadUi32Val(kListMode, t)) + return; + for (int i = 0; i < 2; i++) + { + Panels[i] = t & 0xFF; + t >>= 8; + } +} + +static UString GetPanelPathName(UInt32 panelIndex) +{ + UString s (kPanelPathValueName); + s.Add_UInt32(panelIndex); + return s; +} + +void SavePanelPath(UInt32 panel, const UString &path) +{ + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + key.Create(HKEY_CURRENT_USER, kCUBasePath); + key.SetValue(GetPanelPathName(panel), path); +} + +bool ReadPanelPath(UInt32 panel, UString &path) +{ + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS) + return false; + return (key.QueryValue(GetPanelPathName(panel), path) == ERROR_SUCCESS); +} + + +static void SaveStringList(LPCTSTR valueName, const UStringVector &folders) +{ + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + key.Create(HKEY_CURRENT_USER, kCUBasePath); + key.SetValue_Strings(valueName, folders); +} + +static void ReadStringList(LPCTSTR valueName, UStringVector &folders) +{ + folders.Clear(); + NSynchronization::CCriticalSectionLock lock(g_CS); + CKey key; + if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS) + key.GetValue_Strings(valueName, folders); +} + +void SaveFolderHistory(const UStringVector &folders) + { SaveStringList(kFolderHistoryValueName, folders); } +void ReadFolderHistory(UStringVector &folders) + { ReadStringList(kFolderHistoryValueName, folders); } + +void SaveFastFolders(const UStringVector &folders) + { SaveStringList(kFastFoldersValueName, folders); } +void ReadFastFolders(UStringVector &folders) + { ReadStringList(kFastFoldersValueName, folders); } + +void SaveCopyHistory(const UStringVector &folders) + { SaveStringList(kCopyHistoryValueName, folders); } +void ReadCopyHistory(UStringVector &folders) + { ReadStringList(kCopyHistoryValueName, folders); } + +void AddUniqueStringToHeadOfList(UStringVector &list, const UString &s) +{ + for (unsigned i = 0; i < list.Size();) + if (s.IsEqualTo_NoCase(list[i])) + list.Delete(i); + else + i++; + list.Insert(0, s); +} diff --git a/CPP/7zip/UI/FileManager/ViewSettings.h b/CPP/7zip/UI/FileManager/ViewSettings.h index 5b4ea5928..02af0a155 100644 --- a/CPP/7zip/UI/FileManager/ViewSettings.h +++ b/CPP/7zip/UI/FileManager/ViewSettings.h @@ -1,115 +1,115 @@ -// ViewSettings.h - -#ifndef ZIP7_INC_VIEW_SETTINGS_H -#define ZIP7_INC_VIEW_SETTINGS_H - -#include "../../../Common/MyTypes.h" -#include "../../../Common/MyString.h" - -struct CColumnInfo -{ - PROPID PropID; - bool IsVisible; - UInt32 Width; - - bool IsEqual(const CColumnInfo &a) const - { - return PropID == a.PropID && IsVisible == a.IsVisible && Width == a.Width; - } -}; - -struct CListViewInfo -{ - CRecordVector Columns; - PROPID SortID; - bool Ascending; - bool IsLoaded; - - void Clear() - { - SortID = 0; - Ascending = true; - IsLoaded = false; - Columns.Clear(); - } - - CListViewInfo(): - SortID(0), - Ascending(true), - IsLoaded(false) - {} - - /* - int FindColumnWithID(PROPID propID) const - { - FOR_VECTOR (i, Columns) - if (Columns[i].PropID == propID) - return i; - return -1; - } - */ - - bool IsEqual(const CListViewInfo &info) const - { - if (Columns.Size() != info.Columns.Size() || - SortID != info.SortID || - Ascending != info.Ascending) - return false; - FOR_VECTOR (i, Columns) - if (!Columns[i].IsEqual(info.Columns[i])) - return false; - return true; - } - - void Save(const UString &id) const; - void Read(const UString &id); -}; - - -struct CWindowInfo -{ - RECT rect; - bool maximized; - - UInt32 numPanels; - UInt32 currentPanel; - UInt32 splitterPos; - - void Save() const; - void Read(bool &windowPosDefined, bool &panelInfoDefined); -}; - -void SaveToolbarsMask(UInt32 toolbarMask); -UInt32 ReadToolbarsMask(); - -const UInt32 kListMode_Report = 3; - -struct CListMode -{ - UInt32 Panels[2]; - - void Init() { Panels[0] = Panels[1] = kListMode_Report; } - CListMode() { Init(); } - - void Save() const ; - void Read(); -}; - - - -void SavePanelPath(UInt32 panel, const UString &path); -bool ReadPanelPath(UInt32 panel, UString &path); - - -void SaveFolderHistory(const UStringVector &folders); -void ReadFolderHistory(UStringVector &folders); - -void SaveFastFolders(const UStringVector &folders); -void ReadFastFolders(UStringVector &folders); - -void SaveCopyHistory(const UStringVector &folders); -void ReadCopyHistory(UStringVector &folders); - -void AddUniqueStringToHeadOfList(UStringVector &list, const UString &s); - -#endif +// ViewSettings.h + +#ifndef ZIP7_INC_VIEW_SETTINGS_H +#define ZIP7_INC_VIEW_SETTINGS_H + +#include "../../../Common/MyTypes.h" +#include "../../../Common/MyString.h" + +struct CColumnInfo +{ + PROPID PropID; + bool IsVisible; + UInt32 Width; + + bool IsEqual(const CColumnInfo &a) const + { + return PropID == a.PropID && IsVisible == a.IsVisible && Width == a.Width; + } +}; + +struct CListViewInfo +{ + CRecordVector Columns; + PROPID SortID; + bool Ascending; + bool IsLoaded; + + void Clear() + { + SortID = 0; + Ascending = true; + IsLoaded = false; + Columns.Clear(); + } + + CListViewInfo(): + SortID(0), + Ascending(true), + IsLoaded(false) + {} + + /* + int FindColumnWithID(PROPID propID) const + { + FOR_VECTOR (i, Columns) + if (Columns[i].PropID == propID) + return i; + return -1; + } + */ + + bool IsEqual(const CListViewInfo &info) const + { + if (Columns.Size() != info.Columns.Size() || + SortID != info.SortID || + Ascending != info.Ascending) + return false; + FOR_VECTOR (i, Columns) + if (!Columns[i].IsEqual(info.Columns[i])) + return false; + return true; + } + + void Save(const UString &id) const; + void Read(const UString &id); +}; + + +struct CWindowInfo +{ + RECT rect; + bool maximized; + + UInt32 numPanels; + UInt32 currentPanel; + UInt32 splitterPos; + + void Save() const; + void Read(bool &windowPosDefined, bool &panelInfoDefined); +}; + +void SaveToolbarsMask(UInt32 toolbarMask); +UInt32 ReadToolbarsMask(); + +const UInt32 kListMode_Report = 3; + +struct CListMode +{ + UInt32 Panels[2]; + + void Init() { Panels[0] = Panels[1] = kListMode_Report; } + CListMode() { Init(); } + + void Save() const ; + void Read(); +}; + + + +void SavePanelPath(UInt32 panel, const UString &path); +bool ReadPanelPath(UInt32 panel, UString &path); + + +void SaveFolderHistory(const UStringVector &folders); +void ReadFolderHistory(UStringVector &folders); + +void SaveFastFolders(const UStringVector &folders); +void ReadFastFolders(UStringVector &folders); + +void SaveCopyHistory(const UStringVector &folders); +void ReadCopyHistory(UStringVector &folders); + +void AddUniqueStringToHeadOfList(UStringVector &list, const UString &s); + +#endif diff --git a/CPP/7zip/UI/FileManager/makefile b/CPP/7zip/UI/FileManager/makefile index 9e33fa40c..0ca5caad1 100644 --- a/CPP/7zip/UI/FileManager/makefile +++ b/CPP/7zip/UI/FileManager/makefile @@ -1,110 +1,110 @@ -PROG = 7zFM.exe -CFLAGS = $(CFLAGS) \ - -DZ7_EXTERNAL_CODECS \ - -# -DZ7_NO_LARGE_PAGES - -!include "FM.mak" - -COMMON_OBJS = \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\Lang.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\NewHandler.obj \ - $O\Random.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = $(WIN_OBJS) \ - $O\Clipboard.obj \ - $O\CommonDialog.obj \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\MemoryGlobal.obj \ - $O\MemoryLock.obj \ - $O\Menu.obj \ - $O\ProcessUtils.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Registry.obj \ - $O\ResourceString.obj \ - $O\Shell.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\TimeUtils.obj \ - $O\Window.obj \ - - -WIN_CTRL_OBJS = \ - $O\ComboBox.obj \ - $O\Dialog.obj \ - $O\ListView.obj \ - $O\PropertyPage.obj \ - $O\Window2.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodProps.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveName.obj \ - $O\ArchiveOpenCallback.obj \ - $O\CompressCall.obj \ - $O\DefaultName.obj \ - $O\EnumDirItems.obj \ - $O\ExtractingFilePath.obj \ - $O\HashCalc.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - $O\PropIDUtils.obj \ - $O\SetProperties.obj \ - $O\SortUtils.obj \ - $O\UpdateAction.obj \ - $O\UpdateCallback.obj \ - $O\UpdatePair.obj \ - $O\UpdateProduce.obj \ - $O\WorkDir.obj \ - $O\ZipRegistry.obj \ - -EXPLORER_OBJS = \ - $O\ContextMenu.obj \ - $O\MyMessages.obj \ - $O\RegistryContextMenu.obj \ - -GUI_OBJS = \ - $O\HashGUI.obj \ - $O\UpdateCallbackGUI2.obj \ - -COMPRESS_OBJS = \ - $O\CopyCoder.obj \ - -AR_COMMON_OBJS = \ - $O\ItemNameUtils.obj \ - - -C_OBJS = $(C_OBJS) \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../7zip.mak" +PROG = 7zFM.exe +CFLAGS = $(CFLAGS) \ + -DZ7_EXTERNAL_CODECS \ + +# -DZ7_NO_LARGE_PAGES + +!include "FM.mak" + +COMMON_OBJS = \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\Lang.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\NewHandler.obj \ + $O\Random.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = $(WIN_OBJS) \ + $O\Clipboard.obj \ + $O\CommonDialog.obj \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\MemoryGlobal.obj \ + $O\MemoryLock.obj \ + $O\Menu.obj \ + $O\ProcessUtils.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Registry.obj \ + $O\ResourceString.obj \ + $O\Shell.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\TimeUtils.obj \ + $O\Window.obj \ + + +WIN_CTRL_OBJS = \ + $O\ComboBox.obj \ + $O\Dialog.obj \ + $O\ListView.obj \ + $O\PropertyPage.obj \ + $O\Window2.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodProps.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveName.obj \ + $O\ArchiveOpenCallback.obj \ + $O\CompressCall.obj \ + $O\DefaultName.obj \ + $O\EnumDirItems.obj \ + $O\ExtractingFilePath.obj \ + $O\HashCalc.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + $O\PropIDUtils.obj \ + $O\SetProperties.obj \ + $O\SortUtils.obj \ + $O\UpdateAction.obj \ + $O\UpdateCallback.obj \ + $O\UpdatePair.obj \ + $O\UpdateProduce.obj \ + $O\WorkDir.obj \ + $O\ZipRegistry.obj \ + +EXPLORER_OBJS = \ + $O\ContextMenu.obj \ + $O\MyMessages.obj \ + $O\RegistryContextMenu.obj \ + +GUI_OBJS = \ + $O\HashGUI.obj \ + $O\UpdateCallbackGUI2.obj \ + +COMPRESS_OBJS = \ + $O\CopyCoder.obj \ + +AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ + + +C_OBJS = $(C_OBJS) \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/FileManager/resource.h b/CPP/7zip/UI/FileManager/resource.h index 99e606127..36c4b531a 100644 --- a/CPP/7zip/UI/FileManager/resource.h +++ b/CPP/7zip/UI/FileManager/resource.h @@ -1,196 +1,199 @@ -#include "resourceGui.h" - -#define IDR_MENUBAR1 70 -#define IDM_MENU 71 -#define IDR_ACCELERATOR1 72 - -#define IDB_ADD 100 -#define IDB_EXTRACT 101 -#define IDB_TEST 102 -#define IDB_COPY 103 -#define IDB_MOVE 104 -#define IDB_DELETE 105 -#define IDB_INFO 106 - -#define IDB_ADD2 150 -#define IDB_EXTRACT2 151 -#define IDB_TEST2 152 -#define IDB_COPY2 153 -#define IDB_MOVE2 154 -#define IDB_DELETE2 155 -#define IDB_INFO2 156 - -#define IDM_HASH_ALL 101 -#define IDM_CRC32 102 -#define IDM_CRC64 103 -#define IDM_SHA1 104 -#define IDM_SHA256 105 -#define IDM_XXH64 106 -#define IDM_BLAKE2SP 107 - - -#define IDM_FILE 500 -#define IDM_EDIT 501 -#define IDM_VIEW 502 -#define IDM_FAVORITES 503 -#define IDM_TOOLS 504 -#define IDM_HELP 505 - -#define IDM_OPEN 540 -#define IDM_OPEN_INSIDE 541 -#define IDM_OPEN_OUTSIDE 542 -#define IDM_FILE_VIEW 543 -#define IDM_FILE_EDIT 544 -#define IDM_RENAME 545 -#define IDM_COPY_TO 546 -#define IDM_MOVE_TO 547 -#define IDM_DELETE 548 -#define IDM_SPLIT 549 -#define IDM_COMBINE 550 -#define IDM_PROPERTIES 551 -#define IDM_COMMENT 552 -#define IDM_CRC 553 -#define IDM_DIFF 554 -#define IDM_CREATE_FOLDER 555 -#define IDM_CREATE_FILE 556 -// #define IDM_EXIT 557 -#define IDM_LINK 558 -#define IDM_ALT_STREAMS 559 - -#define IDM_VER_EDIT 580 -#define IDM_VER_COMMIT 581 -#define IDM_VER_REVERT 582 -#define IDM_VER_DIFF 583 - -#define IDM_OPEN_INSIDE_ONE 590 -#define IDM_OPEN_INSIDE_PARSER 591 - -#define IDM_SELECT_ALL 600 -#define IDM_DESELECT_ALL 601 -#define IDM_INVERT_SELECTION 602 -#define IDM_SELECT 603 -#define IDM_DESELECT 604 -#define IDM_SELECT_BY_TYPE 605 -#define IDM_DESELECT_BY_TYPE 606 - -#define IDM_VIEW_LARGE_ICONS 700 -#define IDM_VIEW_SMALL_ICONS 701 -#define IDM_VIEW_LIST 702 -#define IDM_VIEW_DETAILS 703 - -#define IDM_VIEW_ARANGE_BY_NAME 710 -#define IDM_VIEW_ARANGE_BY_TYPE 711 -#define IDM_VIEW_ARANGE_BY_DATE 712 -#define IDM_VIEW_ARANGE_BY_SIZE 713 - -#define IDM_VIEW_ARANGE_NO_SORT 730 -#define IDM_VIEW_FLAT_VIEW 731 -#define IDM_VIEW_TWO_PANELS 732 -#define IDM_VIEW_TOOLBARS 733 -#define IDM_OPEN_ROOT_FOLDER 734 -#define IDM_OPEN_PARENT_FOLDER 735 -#define IDM_FOLDERS_HISTORY 736 -#define IDM_VIEW_REFRESH 737 -#define IDM_VIEW_AUTO_REFRESH 738 -// #define IDM_VIEW_SHOW_DELETED 739 -// #define IDM_VIEW_SHOW_STREAMS 740 - -#define IDM_VIEW_ARCHIVE_TOOLBAR 750 -#define IDM_VIEW_STANDARD_TOOLBAR 751 -#define IDM_VIEW_TOOLBARS_LARGE_BUTTONS 752 -#define IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT 753 - -#define IDM_VIEW_TIME_POPUP 760 -#define IDM_VIEW_TIME 761 -#define IDM_VIEW_TIME_UTC 799 - -#define IDM_ADD_TO_FAVORITES 800 -#define IDS_BOOKMARK 801 - -#define IDM_OPTIONS 900 -#define IDM_BENCHMARK 901 -#define IDM_BENCHMARK2 902 -#define IDM_TEMP_DIR 910 - -#define IDM_HELP_CONTENTS 960 -#define IDM_ABOUT 961 - -#define IDS_OPTIONS 2100 - -#define IDS_N_SELECTED_ITEMS 3002 - -#define IDS_FILE_EXIST 3008 -#define IDS_WANT_UPDATE_MODIFIED_FILE 3009 -#define IDS_CANNOT_UPDATE_FILE 3010 -#define IDS_CANNOT_START_EDITOR 3011 -#define IDS_VIRUS 3012 -#define IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER 3013 -#define IDS_SELECT_ONE_FILE 3014 -#define IDS_SELECT_FILES 3015 -#define IDS_TOO_MANY_ITEMS 3016 - -#define IDS_COPY 6000 -#define IDS_MOVE 6001 -#define IDS_COPY_TO 6002 -#define IDS_MOVE_TO 6003 -#define IDS_COPYING 6004 -#define IDS_MOVING 6005 -#define IDS_RENAMING 6006 - -#define IDS_OPERATION_IS_NOT_SUPPORTED 6008 -#define IDS_ERROR_RENAMING 6009 -#define IDS_CONFIRM_FILE_COPY 6010 -#define IDS_WANT_TO_COPY_FILES 6011 - -#define IDS_CONFIRM_FILE_DELETE 6100 -#define IDS_CONFIRM_FOLDER_DELETE 6101 -#define IDS_CONFIRM_ITEMS_DELETE 6102 -#define IDS_WANT_TO_DELETE_FILE 6103 -#define IDS_WANT_TO_DELETE_FOLDER 6104 -#define IDS_WANT_TO_DELETE_ITEMS 6105 -#define IDS_DELETING 6106 -#define IDS_ERROR_DELETING 6107 -#define IDS_ERROR_LONG_PATH_TO_RECYCLE 6108 - -#define IDS_CREATE_FOLDER 6300 -#define IDS_CREATE_FILE 6301 -#define IDS_CREATE_FOLDER_NAME 6302 -#define IDS_CREATE_FILE_NAME 6303 -#define IDS_CREATE_FOLDER_DEFAULT_NAME 6304 -#define IDS_CREATE_FILE_DEFAULT_NAME 6305 -#define IDS_CREATE_FOLDER_ERROR 6306 -#define IDS_CREATE_FILE_ERROR 6307 - -#define IDS_COMMENT 6400 -#define IDS_COMMENT2 6401 -#define IDS_SELECT 6402 -#define IDS_DESELECT 6403 -#define IDS_SELECT_MASK 6404 - -#define IDS_PROPERTIES 6600 -#define IDS_FOLDERS_HISTORY 6601 - -#define IDS_COMPUTER 7100 -#define IDS_NETWORK 7101 -#define IDS_DOCUMENTS 7102 -#define IDS_SYSTEM 7103 - -#define IDS_ADD 7200 -#define IDS_EXTRACT 7201 -#define IDS_TEST 7202 -#define IDS_BUTTON_COPY 7203 -#define IDS_BUTTON_MOVE 7204 -#define IDS_BUTTON_DELETE 7205 -#define IDS_BUTTON_INFO 7206 - -#define IDS_SPLITTING 7303 -#define IDS_SPLIT_CONFIRM_TITLE 7304 -#define IDS_SPLIT_CONFIRM_MESSAGE 7305 -#define IDS_SPLIT_VOL_MUST_BE_SMALLER 7306 - -#define IDS_COMBINE 7400 -#define IDS_COMBINE_TO 7401 -#define IDS_COMBINING 7402 -#define IDS_COMBINE_SELECT_ONE_FILE 7403 -#define IDS_COMBINE_CANT_DETECT_SPLIT_FILE 7404 -#define IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART 7405 +#include "resourceGui.h" + +#define IDR_MENUBAR1 70 +#define IDM_MENU 71 +#define IDR_ACCELERATOR1 72 + +#define IDB_ADD 100 +#define IDB_EXTRACT 101 +#define IDB_TEST 102 +#define IDB_COPY 103 +#define IDB_MOVE 104 +#define IDB_DELETE 105 +#define IDB_INFO 106 + +#define IDB_ADD2 150 +#define IDB_EXTRACT2 151 +#define IDB_TEST2 152 +#define IDB_COPY2 153 +#define IDB_MOVE2 154 +#define IDB_DELETE2 155 +#define IDB_INFO2 156 + +#define IDM_HASH_ALL 101 +#define IDM_CRC32 102 +#define IDM_CRC64 103 +#define IDM_SHA1 104 +#define IDM_SHA256 105 +#define IDM_SHA384 106 +#define IDM_SHA512 107 +#define IDM_SHA3_256 108 +#define IDM_XXH64 120 +#define IDM_BLAKE2SP 121 +#define IDM_MD5 122 + +#define IDM_FILE 500 +#define IDM_EDIT 501 +#define IDM_VIEW 502 +#define IDM_FAVORITES 503 +#define IDM_TOOLS 504 +#define IDM_HELP 505 + +#define IDM_OPEN 540 +#define IDM_OPEN_INSIDE 541 +#define IDM_OPEN_OUTSIDE 542 +#define IDM_FILE_VIEW 543 +#define IDM_FILE_EDIT 544 +#define IDM_RENAME 545 +#define IDM_COPY_TO 546 +#define IDM_MOVE_TO 547 +#define IDM_DELETE 548 +#define IDM_SPLIT 549 +#define IDM_COMBINE 550 +#define IDM_PROPERTIES 551 +#define IDM_COMMENT 552 +#define IDM_CRC 553 +#define IDM_DIFF 554 +#define IDM_CREATE_FOLDER 555 +#define IDM_CREATE_FILE 556 +// #define IDM_EXIT 557 +#define IDM_LINK 558 +#define IDM_ALT_STREAMS 559 + +#define IDM_VER_EDIT 580 +#define IDM_VER_COMMIT 581 +#define IDM_VER_REVERT 582 +#define IDM_VER_DIFF 583 + +#define IDM_OPEN_INSIDE_ONE 590 +#define IDM_OPEN_INSIDE_PARSER 591 + +#define IDM_SELECT_ALL 600 +#define IDM_DESELECT_ALL 601 +#define IDM_INVERT_SELECTION 602 +#define IDM_SELECT 603 +#define IDM_DESELECT 604 +#define IDM_SELECT_BY_TYPE 605 +#define IDM_DESELECT_BY_TYPE 606 + +#define IDM_VIEW_LARGE_ICONS 700 +#define IDM_VIEW_SMALL_ICONS 701 +#define IDM_VIEW_LIST 702 +#define IDM_VIEW_DETAILS 703 + +#define IDM_VIEW_ARANGE_BY_NAME 710 +#define IDM_VIEW_ARANGE_BY_TYPE 711 +#define IDM_VIEW_ARANGE_BY_DATE 712 +#define IDM_VIEW_ARANGE_BY_SIZE 713 + +#define IDM_VIEW_ARANGE_NO_SORT 730 +#define IDM_VIEW_FLAT_VIEW 731 +#define IDM_VIEW_TWO_PANELS 732 +#define IDM_VIEW_TOOLBARS 733 +#define IDM_OPEN_ROOT_FOLDER 734 +#define IDM_OPEN_PARENT_FOLDER 735 +#define IDM_FOLDERS_HISTORY 736 +#define IDM_VIEW_REFRESH 737 +#define IDM_VIEW_AUTO_REFRESH 738 +// #define IDM_VIEW_SHOW_DELETED 739 +// #define IDM_VIEW_SHOW_STREAMS 740 + +#define IDM_VIEW_ARCHIVE_TOOLBAR 750 +#define IDM_VIEW_STANDARD_TOOLBAR 751 +#define IDM_VIEW_TOOLBARS_LARGE_BUTTONS 752 +#define IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT 753 + +#define IDM_VIEW_TIME_POPUP 760 +#define IDM_VIEW_TIME 761 +#define IDM_VIEW_TIME_UTC 799 + +#define IDM_ADD_TO_FAVORITES 800 +#define IDS_BOOKMARK 801 + +#define IDM_OPTIONS 900 +#define IDM_BENCHMARK 901 +#define IDM_BENCHMARK2 902 +#define IDM_TEMP_DIR 910 + +#define IDM_HELP_CONTENTS 960 +#define IDM_ABOUT 961 + +#define IDS_OPTIONS 2100 + +#define IDS_N_SELECTED_ITEMS 3002 + +#define IDS_FILE_EXIST 3008 +#define IDS_WANT_UPDATE_MODIFIED_FILE 3009 +#define IDS_CANNOT_UPDATE_FILE 3010 +#define IDS_CANNOT_START_EDITOR 3011 +#define IDS_VIRUS 3012 +#define IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER 3013 +#define IDS_SELECT_ONE_FILE 3014 +#define IDS_SELECT_FILES 3015 +#define IDS_TOO_MANY_ITEMS 3016 + +#define IDS_COPY 6000 +#define IDS_MOVE 6001 +#define IDS_COPY_TO 6002 +#define IDS_MOVE_TO 6003 +#define IDS_COPYING 6004 +// #define IDS_MOVING 6005 +#define IDS_RENAMING 6006 + +#define IDS_OPERATION_IS_NOT_SUPPORTED 6008 +#define IDS_ERROR_RENAMING 6009 +#define IDS_CONFIRM_FILE_COPY 6010 +#define IDS_WANT_TO_COPY_FILES 6011 + +#define IDS_CONFIRM_FILE_DELETE 6100 +#define IDS_CONFIRM_FOLDER_DELETE 6101 +#define IDS_CONFIRM_ITEMS_DELETE 6102 +#define IDS_WANT_TO_DELETE_FILE 6103 +#define IDS_WANT_TO_DELETE_FOLDER 6104 +#define IDS_WANT_TO_DELETE_ITEMS 6105 +#define IDS_DELETING 6106 +#define IDS_ERROR_DELETING 6107 +#define IDS_ERROR_LONG_PATH_TO_RECYCLE 6108 + +#define IDS_CREATE_FOLDER 6300 +#define IDS_CREATE_FILE 6301 +#define IDS_CREATE_FOLDER_NAME 6302 +#define IDS_CREATE_FILE_NAME 6303 +#define IDS_CREATE_FOLDER_DEFAULT_NAME 6304 +#define IDS_CREATE_FILE_DEFAULT_NAME 6305 +#define IDS_CREATE_FOLDER_ERROR 6306 +#define IDS_CREATE_FILE_ERROR 6307 + +#define IDS_COMMENT 6400 +#define IDS_COMMENT2 6401 +#define IDS_SELECT 6402 +#define IDS_DESELECT 6403 +#define IDS_SELECT_MASK 6404 + +#define IDS_PROPERTIES 6600 +#define IDS_FOLDERS_HISTORY 6601 + +#define IDS_COMPUTER 7100 +#define IDS_NETWORK 7101 +#define IDS_DOCUMENTS 7102 +#define IDS_SYSTEM 7103 + +#define IDS_ADD 7200 +#define IDS_EXTRACT 7201 +#define IDS_TEST 7202 +#define IDS_BUTTON_COPY 7203 +#define IDS_BUTTON_MOVE 7204 +#define IDS_BUTTON_DELETE 7205 +#define IDS_BUTTON_INFO 7206 + +#define IDS_SPLITTING 7303 +#define IDS_SPLIT_CONFIRM_TITLE 7304 +#define IDS_SPLIT_CONFIRM_MESSAGE 7305 +#define IDS_SPLIT_VOL_MUST_BE_SMALLER 7306 + +#define IDS_COMBINE 7400 +#define IDS_COMBINE_TO 7401 +#define IDS_COMBINING 7402 +#define IDS_COMBINE_SELECT_ONE_FILE 7403 +#define IDS_COMBINE_CANT_DETECT_SPLIT_FILE 7404 +#define IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART 7405 diff --git a/CPP/7zip/UI/FileManager/resource.rc b/CPP/7zip/UI/FileManager/resource.rc index a6d2e86dc..d9fc6f25e 100644 --- a/CPP/7zip/UI/FileManager/resource.rc +++ b/CPP/7zip/UI/FileManager/resource.rc @@ -1,292 +1,296 @@ -#include "../../MyVersionInfo.rc" -#include "../../GuiCommon.rc" -#include "resource.h" - -MY_VERSION_INFO_APP("7-Zip File Manager", "7zFM") - -IDR_ACCELERATOR1 ACCELERATORS -BEGIN -// "N", IDM_CREATE_FILE, VIRTKEY, CONTROL, NOINVERT - VK_F1, IDM_HELP_CONTENTS, VIRTKEY, NOINVERT - VK_F12, IDM_FOLDERS_HISTORY, VIRTKEY, ALT, NOINVERT -// VK_F7, IDM_CREATE_FOLDER, VIRTKEY, NOINVERT -END - -// for MENUEX: -// /* -#define MY_MENUITEM_SEPARATOR MENUITEM "", 0, MFT_SEPARATOR -#define MY_MFT_MENUBREAK MFT_MENUBREAK -#define MY_MFT_MENUBARBREAK MFT_MENUBARBREAK -#define MY_MFS_CHECKED MFT_STRING, MFS_CHECKED -#define MY_MENUITEM_ID(x) , x -// */ - -// for MENU: -/* -#define MY_MENUITEM_SEPARATOR MENUITEM SEPARATOR -#define MY_MFT_MENUBREAK MENUBREAK -#define MY_MFT_MENUBARBREAK MENUBARBREAK -#define MY_MFS_CHECKED CHECKED -#define MY_MENUITEM_ID(x) -*/ - -IDM_MENU MENUEX -BEGIN - POPUP "&File" MY_MENUITEM_ID(IDM_FILE) - BEGIN - MENUITEM "&Open\tEnter", IDM_OPEN - MENUITEM "Open &Inside\tCtrl+PgDn", IDM_OPEN_INSIDE - MENUITEM "Open Inside *", IDM_OPEN_INSIDE_ONE - MENUITEM "Open Inside #", IDM_OPEN_INSIDE_PARSER - MENUITEM "Open O&utside\tShift+Enter", IDM_OPEN_OUTSIDE - MENUITEM "&View\tF3", IDM_FILE_VIEW - MENUITEM "&Edit\tF4", IDM_FILE_EDIT - MY_MENUITEM_SEPARATOR - MENUITEM "Rena&me\tF2", IDM_RENAME - MENUITEM "&Copy To...\tF5", IDM_COPY_TO - MENUITEM "&Move To...\tF6", IDM_MOVE_TO - MENUITEM "&Delete\tDel", IDM_DELETE - MY_MENUITEM_SEPARATOR - MENUITEM "&Split file...", IDM_SPLIT - MENUITEM "Com&bine files...", IDM_COMBINE - MY_MENUITEM_SEPARATOR - MENUITEM "P&roperties\tAlt+Enter", IDM_PROPERTIES - MENUITEM "Comme&nt...\tCtrl+Z", IDM_COMMENT - // MENUITEM "Calculate checksum", IDM_CRC - POPUP "CRC" MY_MENUITEM_ID(0) - BEGIN - MENUITEM "CRC-32", IDM_CRC32 - MENUITEM "CRC-64", IDM_CRC64 - MENUITEM "XXH64", IDM_XXH64 - MENUITEM "SHA-1", IDM_SHA1 - MENUITEM "SHA-256", IDM_SHA256 - MENUITEM "BLAKE2sp", IDM_BLAKE2SP - MENUITEM "*", IDM_HASH_ALL - END - MENUITEM "Di&ff", IDM_DIFF - MY_MENUITEM_SEPARATOR - MENUITEM "Create Folder\tF7", IDM_CREATE_FOLDER - MENUITEM "Create File\tCtrl+N", IDM_CREATE_FILE - MY_MENUITEM_SEPARATOR - MENUITEM "&Link...", IDM_LINK - MENUITEM "&Alternate streams", IDM_ALT_STREAMS - MY_MENUITEM_SEPARATOR - MENUITEM "E&xit\tAlt+F4", IDCLOSE - END - POPUP "&Edit" MY_MENUITEM_ID(IDM_EDIT) - BEGIN - // MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT, GRAYED - // MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY, GRAYED - // MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE, GRAYED - // MY_MENUITEM_SEPARATOR - MENUITEM "Select &All\tShift+[Grey +]", IDM_SELECT_ALL - MENUITEM "Deselect All\tShift+[Grey -]", IDM_DESELECT_ALL - MENUITEM "&Invert Selection\tGrey *", IDM_INVERT_SELECTION - MENUITEM "Select...\tGrey +", IDM_SELECT - MENUITEM "Deselect...\tGrey -", IDM_DESELECT - MENUITEM "", 0, MY_MFT_MENUBARBREAK - MENUITEM "Select by Type\tAlt+[Grey+]", IDM_SELECT_BY_TYPE - MENUITEM "Deselect by Type\tAlt+[Grey -]", IDM_DESELECT_BY_TYPE - END - POPUP "&View" MY_MENUITEM_ID(IDM_VIEW) - BEGIN - MENUITEM "Lar&ge Icons\tCtrl+1", IDM_VIEW_LARGE_ICONS - MENUITEM "S&mall Icons\tCtrl+2", IDM_VIEW_SMALL_ICONS - MENUITEM "&List\tCtrl+3", IDM_VIEW_LIST - MENUITEM "&Details\tCtrl+4", IDM_VIEW_DETAILS, MY_MFS_CHECKED - MY_MENUITEM_SEPARATOR - MENUITEM "Name\tCtrl+F3", IDM_VIEW_ARANGE_BY_NAME - MENUITEM "Type\tCtrl+F4", IDM_VIEW_ARANGE_BY_TYPE - MENUITEM "Date\tCtrl+F5", IDM_VIEW_ARANGE_BY_DATE - MENUITEM "Size\tCtrl+F6", IDM_VIEW_ARANGE_BY_SIZE - MENUITEM "Unsorted\tCtrl+F7", IDM_VIEW_ARANGE_NO_SORT - MY_MENUITEM_SEPARATOR - MENUITEM "Flat View", IDM_VIEW_FLAT_VIEW - MENUITEM "&2 Panels\tF9", IDM_VIEW_TWO_PANELS - - POPUP "2017" MY_MENUITEM_ID(IDM_VIEW_TIME_POPUP) - BEGIN - MENUITEM "Time", IDM_VIEW_TIME - END - - POPUP "Toolbars" MY_MENUITEM_ID(IDM_VIEW_TOOLBARS) - BEGIN - MENUITEM "Archive Toolbar", IDM_VIEW_ARCHIVE_TOOLBAR - MENUITEM "Standard Toolbar", IDM_VIEW_STANDARD_TOOLBAR - MY_MENUITEM_SEPARATOR - MENUITEM "Large Buttons", IDM_VIEW_TOOLBARS_LARGE_BUTTONS - MENUITEM "Show Buttons Text", IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT - END - MENUITEM "Open Root Folder\t\\", IDM_OPEN_ROOT_FOLDER - MENUITEM "Up One Level\tBackspace", IDM_OPEN_PARENT_FOLDER - MENUITEM "Folders History...\tAlt+F12", IDM_FOLDERS_HISTORY - MENUITEM "&Refresh\tCtrl+R", IDM_VIEW_REFRESH - MENUITEM "Auto Refresh", IDM_VIEW_AUTO_REFRESH - - // MENUITEM "Show NTFS streams", IDM_VIEW_SHOW_STREAMS - // MENUITEM "Show deleted files", IDM_VIEW_SHOW_DELETED - - END - POPUP "F&avorites" MY_MENUITEM_ID(IDM_FAVORITES) - BEGIN - POPUP "&Add folder to Favorites as" MY_MENUITEM_ID(IDM_ADD_TO_FAVORITES) - BEGIN - MY_MENUITEM_SEPARATOR - END - MY_MENUITEM_SEPARATOR - END - POPUP "&Tools" MY_MENUITEM_ID(IDM_TOOLS) - BEGIN - MENUITEM "&Options...", IDM_OPTIONS - MY_MENUITEM_SEPARATOR - MENUITEM "&Benchmark", IDM_BENCHMARK - #ifdef UNDER_CE - MENUITEM "Benchmark 2", IDM_BENCHMARK2 - #endif - MY_MENUITEM_SEPARATOR - MENUITEM "Delete Temporary Files...", IDM_TEMP_DIR - #ifndef UNDER_CE - END - POPUP "&Help" MY_MENUITEM_ID(IDM_HELP) - BEGIN - MENUITEM "&Contents...\tF1", IDM_HELP_CONTENTS - #endif - MY_MENUITEM_SEPARATOR - MENUITEM "&About 7-Zip...", IDM_ABOUT - END -END - - -IDI_ICON ICON "../../UI/FileManager/FM.ico" - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "../../UI/FileManager/7zFM.exe.manifest" -#endif - -IDB_ADD BITMAP "../../UI/FileManager/Add.bmp" -IDB_EXTRACT BITMAP "../../UI/FileManager/Extract.bmp" -IDB_TEST BITMAP "../../UI/FileManager/Test.bmp" -IDB_COPY BITMAP "../../UI/FileManager/Copy.bmp" -IDB_MOVE BITMAP "../../UI/FileManager/Move.bmp" -IDB_DELETE BITMAP "../../UI/FileManager/Delete.bmp" -IDB_INFO BITMAP "../../UI/FileManager/Info.bmp" -IDB_ADD2 BITMAP "../../UI/FileManager/Add2.bmp" -IDB_EXTRACT2 BITMAP "../../UI/FileManager/Extract2.bmp" -IDB_TEST2 BITMAP "../../UI/FileManager/Test2.bmp" -IDB_COPY2 BITMAP "../../UI/FileManager/Copy2.bmp" -IDB_MOVE2 BITMAP "../../UI/FileManager/Move2.bmp" -IDB_DELETE2 BITMAP "../../UI/FileManager/Delete2.bmp" -IDB_INFO2 BITMAP "../../UI/FileManager/Info2.bmp" - - -STRINGTABLE -BEGIN - IDS_BOOKMARK "Bookmark" - - IDS_OPTIONS "Options" - - IDS_N_SELECTED_ITEMS "{0} object(s) selected" - - IDS_FILE_EXIST "File {0} is already exist" - IDS_WANT_UPDATE_MODIFIED_FILE "File '{0}' was modified.\nDo you want to update it in the archive?" - IDS_CANNOT_UPDATE_FILE "Cannot update file\n'{0}'" - IDS_CANNOT_START_EDITOR "Cannot start editor." - IDS_VIRUS "The file looks like a virus (the file name contains long spaces in name)." - IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER "The operation cannot be called from a folder that has a long path." - IDS_SELECT_ONE_FILE "You must select one file" - // IDS_SELECT_FILES "You must select one or more files" - IDS_TOO_MANY_ITEMS "Too many items" - - IDS_COPY "Copy" - IDS_MOVE "Move" - IDS_COPY_TO "Copy to:" - IDS_MOVE_TO "Move to:" - IDS_COPYING "Copying..." - IDS_MOVING "Moving..." - IDS_RENAMING "Renaming..." - - IDS_OPERATION_IS_NOT_SUPPORTED "Operation is not supported." - IDS_ERROR_RENAMING "Error Renaming File or Folder" - IDS_CONFIRM_FILE_COPY "Confirm File Copy" - IDS_WANT_TO_COPY_FILES "Are you sure you want to copy files to archive" - - IDS_CONFIRM_FILE_DELETE "Confirm File Delete" - IDS_CONFIRM_FOLDER_DELETE "Confirm Folder Delete" - IDS_CONFIRM_ITEMS_DELETE "Confirm Multiple File Delete" - IDS_WANT_TO_DELETE_FILE "Are you sure you want to delete '{0}'?" - IDS_WANT_TO_DELETE_FOLDER "Are you sure you want to delete the folder '{0}' and all its contents?" - IDS_WANT_TO_DELETE_ITEMS "Are you sure you want to delete these {0} items?" - IDS_DELETING "Deleting..." - IDS_ERROR_DELETING "Error Deleting File or Folder" - IDS_ERROR_LONG_PATH_TO_RECYCLE "The system cannot move a file with long path to the Recycle Bin" - - IDS_CREATE_FOLDER "Create Folder" - IDS_CREATE_FILE "Create File" - IDS_CREATE_FOLDER_NAME "Folder name:" - IDS_CREATE_FILE_NAME "File Name:" - IDS_CREATE_FOLDER_DEFAULT_NAME "New Folder" - IDS_CREATE_FILE_DEFAULT_NAME "New File" - IDS_CREATE_FOLDER_ERROR "Error Creating Folder" - IDS_CREATE_FILE_ERROR "Error Creating File" - - IDS_COMMENT "Comment" - IDS_COMMENT2 "&Comment:" - IDS_SELECT "Select" - IDS_DESELECT "Deselect" - IDS_SELECT_MASK "Mask:" - - IDS_PROPERTIES "Properties" - IDS_FOLDERS_HISTORY "Folders History" - - IDS_COMPUTER "Computer" - IDS_NETWORK "Network" - IDS_DOCUMENTS "Documents" - IDS_SYSTEM "System" - - IDS_ADD "Add" - IDS_EXTRACT "Extract" - IDS_TEST "Test" - IDS_BUTTON_COPY "Copy" - IDS_BUTTON_MOVE "Move" - IDS_BUTTON_DELETE "Delete" - IDS_BUTTON_INFO "Info" - - IDS_SPLITTING "Splitting..." - IDS_SPLIT_CONFIRM_TITLE "Confirm Splitting" - IDS_SPLIT_CONFIRM_MESSAGE "Are you sure you want to split file into {0} volumes?" - IDS_SPLIT_VOL_MUST_BE_SMALLER "Volume size must be smaller than size of original file" - - IDS_COMBINE "Combine Files" - IDS_COMBINE_TO "&Combine to:" - IDS_COMBINING "Combining..." - IDS_COMBINE_SELECT_ONE_FILE "Select only first part of split file" - IDS_COMBINE_CANT_DETECT_SPLIT_FILE "Cannot detect file as split file" - IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART "Cannot find more than one part of split file" - -END - -#include "AboutDialog.rc" -#include "BrowseDialog.rc" -#include "BrowseDialog2.rc" -#include "ComboDialog.rc" -#include "CopyDialog.rc" -#include "EditDialog.rc" -#include "EditPage.rc" -#include "FoldersPage.rc" -#include "LangPage.rc" -#include "LinkDialog.rc" -#include "ListViewDialog.rc" -#include "MemDialog.rc" -#include "MenuPage.rc" -#include "MessagesDialog.rc" -#include "OverwriteDialog.rc" -#include "PasswordDialog.rc" -#include "ProgressDialog2.rc" -#include "PropertyName.rc" -#include "SettingsPage.rc" -#include "SplitDialog.rc" -#include "SystemPage.rc" -#include "../GUI/Extract.rc" -#include "../GUI/resource3.rc" -#include "../Explorer/resource2.rc" -#include "resourceGui.rc" +#include "../../MyVersionInfo.rc" +#include "../../GuiCommon.rc" +#include "resource.h" + +MY_VERSION_INFO_APP("7-Zip File Manager", "7zFM") + +IDR_ACCELERATOR1 ACCELERATORS +BEGIN +// "N", IDM_CREATE_FILE, VIRTKEY, CONTROL, NOINVERT + VK_F1, IDM_HELP_CONTENTS, VIRTKEY, NOINVERT + VK_F12, IDM_FOLDERS_HISTORY, VIRTKEY, ALT, NOINVERT +// VK_F7, IDM_CREATE_FOLDER, VIRTKEY, NOINVERT +END + +// for MENUEX: +// /* +#define MY_MENUITEM_SEPARATOR MENUITEM "", 0, MFT_SEPARATOR +#define MY_MFT_MENUBREAK MFT_MENUBREAK +#define MY_MFT_MENUBARBREAK MFT_MENUBARBREAK +#define MY_MFS_CHECKED MFT_STRING, MFS_CHECKED +#define MY_MENUITEM_ID(x) , x +// */ + +// for MENU: +/* +#define MY_MENUITEM_SEPARATOR MENUITEM SEPARATOR +#define MY_MFT_MENUBREAK MENUBREAK +#define MY_MFT_MENUBARBREAK MENUBARBREAK +#define MY_MFS_CHECKED CHECKED +#define MY_MENUITEM_ID(x) +*/ + +IDM_MENU MENUEX +BEGIN + POPUP "&File" MY_MENUITEM_ID(IDM_FILE) + BEGIN + MENUITEM "&Open\tEnter", IDM_OPEN + MENUITEM "Open &Inside\tCtrl+PgDn", IDM_OPEN_INSIDE + MENUITEM "Open Inside *", IDM_OPEN_INSIDE_ONE + MENUITEM "Open Inside #", IDM_OPEN_INSIDE_PARSER + MENUITEM "Open O&utside\tShift+Enter", IDM_OPEN_OUTSIDE + MENUITEM "&View\tF3", IDM_FILE_VIEW + MENUITEM "&Edit\tF4", IDM_FILE_EDIT + MY_MENUITEM_SEPARATOR + MENUITEM "Rena&me\tF2", IDM_RENAME + MENUITEM "&Copy To...\tF5", IDM_COPY_TO + MENUITEM "&Move To...\tF6", IDM_MOVE_TO + MENUITEM "&Delete\tDel", IDM_DELETE + MY_MENUITEM_SEPARATOR + MENUITEM "&Split file...", IDM_SPLIT + MENUITEM "Com&bine files...", IDM_COMBINE + MY_MENUITEM_SEPARATOR + MENUITEM "P&roperties\tAlt+Enter", IDM_PROPERTIES + MENUITEM "Comme&nt...\tCtrl+Z", IDM_COMMENT + // MENUITEM "Calculate checksum", IDM_CRC + POPUP "CRC" MY_MENUITEM_ID(0) + BEGIN + MENUITEM "CRC-32", IDM_CRC32 + MENUITEM "CRC-64", IDM_CRC64 + MENUITEM "XXH64", IDM_XXH64 + MENUITEM "MD5", IDM_MD5 + MENUITEM "SHA-1", IDM_SHA1 + MENUITEM "SHA-256", IDM_SHA256 + MENUITEM "SHA-384", IDM_SHA384 + MENUITEM "SHA-512", IDM_SHA512 + MENUITEM "SHA3-256", IDM_SHA3_256 + MENUITEM "BLAKE2sp", IDM_BLAKE2SP + MENUITEM "*", IDM_HASH_ALL + END + MENUITEM "Di&ff", IDM_DIFF + MY_MENUITEM_SEPARATOR + MENUITEM "Create Folder\tF7", IDM_CREATE_FOLDER + MENUITEM "Create File\tCtrl+N", IDM_CREATE_FILE + MY_MENUITEM_SEPARATOR + MENUITEM "&Link...", IDM_LINK + MENUITEM "&Alternate streams", IDM_ALT_STREAMS + MY_MENUITEM_SEPARATOR + MENUITEM "E&xit\tAlt+F4", IDCLOSE + END + POPUP "&Edit" MY_MENUITEM_ID(IDM_EDIT) + BEGIN + // MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT, GRAYED + // MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY, GRAYED + // MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE, GRAYED + // MY_MENUITEM_SEPARATOR + MENUITEM "Select &All\tShift+[Grey +]", IDM_SELECT_ALL + MENUITEM "Deselect All\tShift+[Grey -]", IDM_DESELECT_ALL + MENUITEM "&Invert Selection\tGrey *", IDM_INVERT_SELECTION + MENUITEM "Select...\tGrey +", IDM_SELECT + MENUITEM "Deselect...\tGrey -", IDM_DESELECT + MENUITEM "", 0, MY_MFT_MENUBARBREAK + MENUITEM "Select by Type\tAlt+[Grey+]", IDM_SELECT_BY_TYPE + MENUITEM "Deselect by Type\tAlt+[Grey -]", IDM_DESELECT_BY_TYPE + END + POPUP "&View" MY_MENUITEM_ID(IDM_VIEW) + BEGIN + MENUITEM "Lar&ge Icons\tCtrl+1", IDM_VIEW_LARGE_ICONS + MENUITEM "S&mall Icons\tCtrl+2", IDM_VIEW_SMALL_ICONS + MENUITEM "&List\tCtrl+3", IDM_VIEW_LIST + MENUITEM "&Details\tCtrl+4", IDM_VIEW_DETAILS, MY_MFS_CHECKED + MY_MENUITEM_SEPARATOR + MENUITEM "Name\tCtrl+F3", IDM_VIEW_ARANGE_BY_NAME + MENUITEM "Type\tCtrl+F4", IDM_VIEW_ARANGE_BY_TYPE + MENUITEM "Date\tCtrl+F5", IDM_VIEW_ARANGE_BY_DATE + MENUITEM "Size\tCtrl+F6", IDM_VIEW_ARANGE_BY_SIZE + MENUITEM "Unsorted\tCtrl+F7", IDM_VIEW_ARANGE_NO_SORT + MY_MENUITEM_SEPARATOR + MENUITEM "Flat View", IDM_VIEW_FLAT_VIEW + MENUITEM "&2 Panels\tF9", IDM_VIEW_TWO_PANELS + + POPUP "2017" MY_MENUITEM_ID(IDM_VIEW_TIME_POPUP) + BEGIN + MENUITEM "Time", IDM_VIEW_TIME + END + + POPUP "Toolbars" MY_MENUITEM_ID(IDM_VIEW_TOOLBARS) + BEGIN + MENUITEM "Archive Toolbar", IDM_VIEW_ARCHIVE_TOOLBAR + MENUITEM "Standard Toolbar", IDM_VIEW_STANDARD_TOOLBAR + MY_MENUITEM_SEPARATOR + MENUITEM "Large Buttons", IDM_VIEW_TOOLBARS_LARGE_BUTTONS + MENUITEM "Show Buttons Text", IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT + END + MENUITEM "Open Root Folder\t\\", IDM_OPEN_ROOT_FOLDER + MENUITEM "Up One Level\tBackspace", IDM_OPEN_PARENT_FOLDER + MENUITEM "Folders History...\tAlt+F12", IDM_FOLDERS_HISTORY + MENUITEM "&Refresh\tCtrl+R", IDM_VIEW_REFRESH + MENUITEM "Auto Refresh", IDM_VIEW_AUTO_REFRESH + + // MENUITEM "Show NTFS streams", IDM_VIEW_SHOW_STREAMS + // MENUITEM "Show deleted files", IDM_VIEW_SHOW_DELETED + + END + POPUP "F&avorites" MY_MENUITEM_ID(IDM_FAVORITES) + BEGIN + POPUP "&Add folder to Favorites as" MY_MENUITEM_ID(IDM_ADD_TO_FAVORITES) + BEGIN + MY_MENUITEM_SEPARATOR + END + MY_MENUITEM_SEPARATOR + END + POPUP "&Tools" MY_MENUITEM_ID(IDM_TOOLS) + BEGIN + MENUITEM "&Options...", IDM_OPTIONS + MY_MENUITEM_SEPARATOR + MENUITEM "&Benchmark", IDM_BENCHMARK + #ifdef UNDER_CE + MENUITEM "Benchmark 2", IDM_BENCHMARK2 + #endif + MY_MENUITEM_SEPARATOR + MENUITEM "Delete Temporary Files...", IDM_TEMP_DIR + #ifndef UNDER_CE + END + POPUP "&Help" MY_MENUITEM_ID(IDM_HELP) + BEGIN + MENUITEM "&Contents...\tF1", IDM_HELP_CONTENTS + #endif + MY_MENUITEM_SEPARATOR + MENUITEM "&About 7-Zip...", IDM_ABOUT + END +END + + +IDI_ICON ICON "../../UI/FileManager/FM.ico" + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "../../UI/FileManager/7zFM.exe.manifest" +#endif + +IDB_ADD BITMAP "../../UI/FileManager/Add.bmp" +IDB_EXTRACT BITMAP "../../UI/FileManager/Extract.bmp" +IDB_TEST BITMAP "../../UI/FileManager/Test.bmp" +IDB_COPY BITMAP "../../UI/FileManager/Copy.bmp" +IDB_MOVE BITMAP "../../UI/FileManager/Move.bmp" +IDB_DELETE BITMAP "../../UI/FileManager/Delete.bmp" +IDB_INFO BITMAP "../../UI/FileManager/Info.bmp" +IDB_ADD2 BITMAP "../../UI/FileManager/Add2.bmp" +IDB_EXTRACT2 BITMAP "../../UI/FileManager/Extract2.bmp" +IDB_TEST2 BITMAP "../../UI/FileManager/Test2.bmp" +IDB_COPY2 BITMAP "../../UI/FileManager/Copy2.bmp" +IDB_MOVE2 BITMAP "../../UI/FileManager/Move2.bmp" +IDB_DELETE2 BITMAP "../../UI/FileManager/Delete2.bmp" +IDB_INFO2 BITMAP "../../UI/FileManager/Info2.bmp" + + +STRINGTABLE +BEGIN + IDS_BOOKMARK "Bookmark" + + IDS_OPTIONS "Options" + + IDS_N_SELECTED_ITEMS "{0} object(s) selected" + + IDS_FILE_EXIST "File {0} is already exist" + IDS_WANT_UPDATE_MODIFIED_FILE "File '{0}' was modified.\nDo you want to update it in the archive?" + IDS_CANNOT_UPDATE_FILE "Cannot update file\n'{0}'" + IDS_CANNOT_START_EDITOR "Cannot start editor." + IDS_VIRUS "The file looks like a virus (the file name contains long spaces in name)." + IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER "The operation cannot be called from a folder that has a long path." + IDS_SELECT_ONE_FILE "You must select one file" + // IDS_SELECT_FILES "You must select one or more files" + IDS_TOO_MANY_ITEMS "Too many items" + + IDS_COPY "Copy" + IDS_MOVE "Move" + IDS_COPY_TO "Copy to:" + IDS_MOVE_TO "Move to:" + IDS_COPYING "Copying..." +// IDS_MOVING "Moving..." + IDS_RENAMING "Renaming..." + + IDS_OPERATION_IS_NOT_SUPPORTED "Operation is not supported." + IDS_ERROR_RENAMING "Error Renaming File or Folder" + IDS_CONFIRM_FILE_COPY "Confirm File Copy" + IDS_WANT_TO_COPY_FILES "Are you sure you want to copy files to archive" + + IDS_CONFIRM_FILE_DELETE "Confirm File Delete" + IDS_CONFIRM_FOLDER_DELETE "Confirm Folder Delete" + IDS_CONFIRM_ITEMS_DELETE "Confirm Multiple File Delete" + IDS_WANT_TO_DELETE_FILE "Are you sure you want to delete '{0}'?" + IDS_WANT_TO_DELETE_FOLDER "Are you sure you want to delete the folder '{0}' and all its contents?" + IDS_WANT_TO_DELETE_ITEMS "Are you sure you want to delete these {0} items?" + IDS_DELETING "Deleting..." + IDS_ERROR_DELETING "Error Deleting File or Folder" + IDS_ERROR_LONG_PATH_TO_RECYCLE "The system cannot move a file with long path to the Recycle Bin" + + IDS_CREATE_FOLDER "Create Folder" + IDS_CREATE_FILE "Create File" + IDS_CREATE_FOLDER_NAME "Folder name:" + IDS_CREATE_FILE_NAME "File Name:" + IDS_CREATE_FOLDER_DEFAULT_NAME "New Folder" + IDS_CREATE_FILE_DEFAULT_NAME "New File" + IDS_CREATE_FOLDER_ERROR "Error Creating Folder" + IDS_CREATE_FILE_ERROR "Error Creating File" + + IDS_COMMENT "Comment" + IDS_COMMENT2 "&Comment:" + IDS_SELECT "Select" + IDS_DESELECT "Deselect" + IDS_SELECT_MASK "Mask:" + + IDS_PROPERTIES "Properties" + IDS_FOLDERS_HISTORY "Folders History" + + IDS_COMPUTER "Computer" + IDS_NETWORK "Network" + IDS_DOCUMENTS "Documents" + IDS_SYSTEM "System" + + IDS_ADD "Add" + IDS_EXTRACT "Extract" + IDS_TEST "Test" + IDS_BUTTON_COPY "Copy" + IDS_BUTTON_MOVE "Move" + IDS_BUTTON_DELETE "Delete" + IDS_BUTTON_INFO "Info" + + IDS_SPLITTING "Splitting..." + IDS_SPLIT_CONFIRM_TITLE "Confirm Splitting" + IDS_SPLIT_CONFIRM_MESSAGE "Are you sure you want to split file into {0} volumes?" + IDS_SPLIT_VOL_MUST_BE_SMALLER "Volume size must be smaller than size of original file" + + IDS_COMBINE "Combine Files" + IDS_COMBINE_TO "&Combine to:" + IDS_COMBINING "Combining..." + IDS_COMBINE_SELECT_ONE_FILE "Select only first part of split file" + IDS_COMBINE_CANT_DETECT_SPLIT_FILE "Cannot detect file as split file" + IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART "Cannot find more than one part of split file" + +END + +#include "AboutDialog.rc" +#include "BrowseDialog.rc" +#include "BrowseDialog2.rc" +#include "ComboDialog.rc" +#include "CopyDialog.rc" +#include "EditDialog.rc" +#include "EditPage.rc" +#include "FoldersPage.rc" +#include "LangPage.rc" +#include "LinkDialog.rc" +#include "ListViewDialog.rc" +#include "MemDialog.rc" +#include "MenuPage.rc" +#include "MessagesDialog.rc" +#include "OverwriteDialog.rc" +#include "PasswordDialog.rc" +#include "ProgressDialog2.rc" +#include "PropertyName.rc" +#include "SettingsPage.rc" +#include "SplitDialog.rc" +#include "SystemPage.rc" +#include "../GUI/Extract.rc" +#include "../GUI/resource3.rc" +#include "../Explorer/resource2.rc" +#include "resourceGui.rc" diff --git a/CPP/7zip/UI/FileManager/resourceGui.h b/CPP/7zip/UI/FileManager/resourceGui.h index e4a86949a..2e1bab394 100644 --- a/CPP/7zip/UI/FileManager/resourceGui.h +++ b/CPP/7zip/UI/FileManager/resourceGui.h @@ -1,23 +1,25 @@ -#define IDI_ICON 1 - -#define IDS_MESSAGE_NO_ERRORS 3001 - -#define IDS_PROGRESS_TESTING 3302 -#define IDS_OPENNING 3303 -#define IDS_SCANNING 3304 - -#define IDS_CHECKSUM_CALCULATING 7500 -#define IDS_CHECKSUM_INFORMATION 7501 -#define IDS_CHECKSUM_CRC_DATA 7502 -#define IDS_CHECKSUM_CRC_DATA_NAMES 7503 -#define IDS_CHECKSUM_CRC_STREAMS_NAMES 7504 - -#define IDS_INCORRECT_VOLUME_SIZE 7307 - -#define IDS_MEM_REQUIRES_BIG_MEM 7811 -#define IDS_MEM_REQUIRED_MEM_SIZE 7812 -#define IDS_MEM_CURRENT_MEM_LIMIT 7813 -#define IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP 7814 -#define IDS_MEM_RAM_SIZE 7815 - -#define IDS_MSG_ARC_UNPACKING_WAS_SKIPPED 7822 +#define IDI_ICON 1 + +#define IDS_MESSAGE_NO_ERRORS 3001 + +#define IDS_PROGRESS_TESTING 3302 +#define IDS_OPENNING 3303 +#define IDS_SCANNING 3304 + +#define IDS_MOVING 6005 + +#define IDS_CHECKSUM_CALCULATING 7500 +#define IDS_CHECKSUM_INFORMATION 7501 +#define IDS_CHECKSUM_CRC_DATA 7502 +#define IDS_CHECKSUM_CRC_DATA_NAMES 7503 +#define IDS_CHECKSUM_CRC_STREAMS_NAMES 7504 + +#define IDS_INCORRECT_VOLUME_SIZE 7307 + +#define IDS_MEM_REQUIRES_BIG_MEM 7811 +#define IDS_MEM_REQUIRED_MEM_SIZE 7812 +#define IDS_MEM_CURRENT_MEM_LIMIT 7813 +#define IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP 7814 +#define IDS_MEM_RAM_SIZE 7815 + +#define IDS_MSG_ARC_UNPACKING_WAS_SKIPPED 7822 diff --git a/CPP/7zip/UI/FileManager/resourceGui.rc b/CPP/7zip/UI/FileManager/resourceGui.rc index 69d3e066f..ad0d1f474 100644 --- a/CPP/7zip/UI/FileManager/resourceGui.rc +++ b/CPP/7zip/UI/FileManager/resourceGui.rc @@ -1,28 +1,30 @@ -#include "resourceGui.h" - -STRINGTABLE -BEGIN - IDS_MESSAGE_NO_ERRORS "There are no errors" - - IDS_PROGRESS_TESTING "Testing" - - IDS_CHECKSUM_CALCULATING "Checksum calculating..." - IDS_CHECKSUM_INFORMATION "Checksum information" - IDS_CHECKSUM_CRC_DATA "CRC checksum for data:" - IDS_CHECKSUM_CRC_DATA_NAMES "CRC checksum for data and names:" - IDS_CHECKSUM_CRC_STREAMS_NAMES "CRC checksum for streams and names:" - - IDS_INCORRECT_VOLUME_SIZE "Incorrect volume size" - - IDS_OPENNING "Opening..." - IDS_SCANNING "Scanning..." - IDS_MEM_REQUIRES_BIG_MEM "The operation requires big amount of memory (RAM)." - IDS_MEM_REQUIRED_MEM_SIZE "required memory usage size" - IDS_MEM_CURRENT_MEM_LIMIT "allowed memory usage limit" - IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP "memory usage limit set by 7-Zip" - IDS_MEM_RAM_SIZE "RAM size" - - IDS_MSG_ARC_UNPACKING_WAS_SKIPPED "Archive extraction was skipped." -// IDS_MSG_ARC_FILES_UNPACKING_WAS_SKIPPED "Files extraction was skipped." - -END +#include "resourceGui.h" + +STRINGTABLE +BEGIN + IDS_MESSAGE_NO_ERRORS "There are no errors" + + IDS_PROGRESS_TESTING "Testing" + + IDS_MOVING "Moving..." + + IDS_CHECKSUM_CALCULATING "Checksum calculating..." + IDS_CHECKSUM_INFORMATION "Checksum information" + IDS_CHECKSUM_CRC_DATA "CRC checksum for data:" + IDS_CHECKSUM_CRC_DATA_NAMES "CRC checksum for data and names:" + IDS_CHECKSUM_CRC_STREAMS_NAMES "CRC checksum for streams and names:" + + IDS_INCORRECT_VOLUME_SIZE "Incorrect volume size" + + IDS_OPENNING "Opening..." + IDS_SCANNING "Scanning..." + IDS_MEM_REQUIRES_BIG_MEM "The operation requires big amount of memory (RAM)." + IDS_MEM_REQUIRED_MEM_SIZE "required memory usage size" + IDS_MEM_CURRENT_MEM_LIMIT "allowed memory usage limit" + IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP "memory usage limit set by 7-Zip" + IDS_MEM_RAM_SIZE "RAM size" + + IDS_MSG_ARC_UNPACKING_WAS_SKIPPED "Archive extraction was skipped." +// IDS_MSG_ARC_FILES_UNPACKING_WAS_SKIPPED "Files extraction was skipped." + +END diff --git a/CPP/7zip/UI/GUI/7zG.exe.manifest b/CPP/7zip/UI/GUI/7zG.exe.manifest index 93d0c096c..ae964d820 100644 --- a/CPP/7zip/UI/GUI/7zG.exe.manifest +++ b/CPP/7zip/UI/GUI/7zG.exe.manifest @@ -1,23 +1,23 @@ - - - - 7-Zip GUI. - - - - - - - - - - - - - true - - - - -true - + + + + 7-Zip GUI. + + + + + + + + + + + + + true + + + + +true + diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp index d3ea070cc..ce5473ae1 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp @@ -1,1927 +1,1932 @@ -// BenchmarkDialog.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/Defs.h" -#include "../../../Common/IntToString.h" -#include "../../../Common/MyException.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/Synchronization.h" -#include "../../../Windows/System.h" -#include "../../../Windows/Thread.h" -#include "../../../Windows/SystemInfo.h" - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Edit.h" - -#include "../../Common/MethodProps.h" - -#include "../FileManager/DialogSize.h" -#include "../FileManager/HelpUtils.h" -#include "../FileManager/LangUtils.h" -#include "../FileManager/resourceGui.h" - -#include "../../MyVersion.h" - -#include "../Common/Bench.h" - -#include "BenchmarkDialogRes.h" -#include "BenchmarkDialog.h" - -using namespace NWindows; - -#define kHelpTopic "fm/benchmark.htm" - -static const UINT_PTR kTimerID = 4; -static const UINT kTimerElapse = 1000; // 1000 - -// use PRINT_ITER_TIME to show time of each iteration in log box -// #define PRINT_ITER_TIME - -static const unsigned kRatingVector_NumBundlesMax = 20; - -enum MyBenchMessages -{ - k_Message_Finished = WM_APP + 1 -}; - -enum My_Message_WPARAM -{ - k_Msg_WPARM_Thread_Finished = 0, - k_Msg_WPARM_Iter_Finished, - k_Msg_WPARM_Enc1_Finished -}; - - -struct CBenchPassResult -{ - CTotalBenchRes Enc; - CTotalBenchRes Dec; - #ifdef PRINT_ITER_TIME - DWORD Ticks; - #endif - // CBenchInfo EncInfo; // for debug - // CBenchPassResult() {}; -}; - - -struct CTotalBenchRes2: public CTotalBenchRes -{ - UInt64 UnpackSize; - - void Init() - { - CTotalBenchRes::Init(); - UnpackSize = 0; - } - - void SetFrom_BenchInfo(const CBenchInfo &info) - { - NumIterations2 = 1; - Generate_From_BenchInfo(info); - UnpackSize = info.Get_UnpackSize_Full(); - } - - void Update_With_Res2(const CTotalBenchRes2 &r) - { - Update_With_Res(r); - UnpackSize += r.UnpackSize; - } -}; - - -struct CSyncData -{ - UInt32 NumPasses_Finished; - - // UInt64 NumEncProgress; // for debug - // UInt64 NumDecProgress; // for debug - // CBenchInfo EncInfo; // for debug - - CTotalBenchRes2 Enc_BenchRes_1; - CTotalBenchRes2 Enc_BenchRes; - - CTotalBenchRes2 Dec_BenchRes_1; - CTotalBenchRes2 Dec_BenchRes; - - #ifdef PRINT_ITER_TIME - DWORD TotalTicks; - #endif - - int RatingVector_DeletedIndex; - // UInt64 RatingVector_NumDeleted; - - bool BenchWasFinished; // all passes were finished - bool NeedPrint_Freq; - bool NeedPrint_RatingVector; - bool NeedPrint_Enc_1; - bool NeedPrint_Enc; - bool NeedPrint_Dec_1; - bool NeedPrint_Dec; - bool NeedPrint_Tot; // intermediate Total was updated after current pass - - void Init(); -}; - - -void CSyncData::Init() -{ - NumPasses_Finished = 0; - - // NumEncProgress = 0; - // NumDecProgress = 0; - - Enc_BenchRes.Init(); - Enc_BenchRes_1.Init(); - Dec_BenchRes.Init(); - Dec_BenchRes_1.Init(); - - #ifdef PRINT_ITER_TIME - TotalTicks = 0; - #endif - - RatingVector_DeletedIndex = -1; - // RatingVector_NumDeleted = 0; - - BenchWasFinished = - NeedPrint_Freq = - NeedPrint_RatingVector = - NeedPrint_Enc_1 = - NeedPrint_Enc = - NeedPrint_Dec_1 = - NeedPrint_Dec = - NeedPrint_Tot = false; -} - - -struct CBenchProgressSync -{ - bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable - UInt32 NumThreads; - UInt64 DictSize; - UInt32 NumPasses_Limit; - int Level; - - // must be written by benchmark thread, read by GUI thread */ - CSyncData sd; - CRecordVector RatingVector; - - NWindows::NSynchronization::CCriticalSection CS; - - AString Text; - bool TextWasChanged; - - /* BenchFinish_Task_HRESULT - for result from benchmark code - BenchFinish_Thread_HRESULT - for Exceptions and service errors - these arreos must be shown even if user escapes benchmark */ - - HRESULT BenchFinish_Task_HRESULT; - HRESULT BenchFinish_Thread_HRESULT; - - UInt32 NumFreqThreadsPrev; - UString FreqString_Sync; - UString FreqString_GUI; - - CBenchProgressSync() - { - NumPasses_Limit = 1; - } - - void Init(); - - void SendExit() - { - NWindows::NSynchronization::CCriticalSectionLock lock(CS); - Exit = true; - } -}; - - -void CBenchProgressSync::Init() -{ - Exit = false; - - BenchFinish_Task_HRESULT = S_OK; - BenchFinish_Thread_HRESULT = S_OK; - - sd.Init(); - RatingVector.Clear(); - - NumFreqThreadsPrev = 0; - FreqString_Sync.Empty(); - FreqString_GUI.Empty(); - - Text.Empty(); - TextWasChanged = true; -} - - - -struct CMyFont -{ - HFONT _font; - CMyFont(): _font(NULL) {} - ~CMyFont() - { - if (_font) - DeleteObject(_font); - } - void Create(const LOGFONT *lplf) - { - _font = CreateFontIndirect(lplf); - } -}; - - -class CBenchmarkDialog; - -struct CThreadBenchmark -{ - CBenchmarkDialog *BenchmarkDialog; - DECL_EXTERNAL_CODECS_LOC_VARS_DECL - // HRESULT Result; - - HRESULT Process(); - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - /* ((CThreadBenchmark *)param)->Result = */ - ((CThreadBenchmark *)param)->Process(); - return 0; - } -}; - - -class CBenchmarkDialog: - public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox m_Dictionary; - NWindows::NControl::CComboBox m_NumThreads; - NWindows::NControl::CComboBox m_NumPasses; - NWindows::NControl::CEdit _consoleEdit; - UINT_PTR _timer; - - UInt32 _startTime; - UInt32 _finishTime; - bool _finishTime_WasSet; - - bool WasStopped_in_GUI; - bool ExitWasAsked_in_GUI; - bool NeedRestart; - - CMyFont _font; - - UInt64 RamSize; - UInt64 RamSize_Limit; - bool RamSize_Defined; - - UInt32 NumPasses_Finished_Prev; - - UString ElapsedSec_Prev; - - void InitSyncNew() - { - NumPasses_Finished_Prev = (UInt32)(Int32)-1; - ElapsedSec_Prev.Empty(); - Sync.Init(); - } - - virtual bool OnInit() Z7_override; - virtual bool OnDestroy() Z7_override; - virtual bool OnSize(WPARAM /* wParam */, int xSize, int ySize) Z7_override; - virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; - virtual void OnHelp() Z7_override; - virtual void OnCancel() Z7_override; - virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - - void Disable_Stop_Button(); - void OnStopButton(); - void RestartBenchmark(); - void StartBenchmark(); - - void UpdateGui(); - - void PrintTime(); - void PrintRating(UInt64 rating, UINT controlID); - void PrintUsage(UInt64 usage, UINT controlID); - void PrintBenchRes(const CTotalBenchRes2 &info, const UINT ids[]); - - UInt32 GetNumberOfThreads(); - size_t OnChangeDictionary(); - - void SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post = NULL); - void Print_MemUsage(UString &s, UInt64 memUsage) const; - bool IsMemoryUsageOK(UInt64 memUsage) const - { return memUsage + (1 << 20) <= RamSize_Limit; } - - void MyKillTimer(); - - void SendExit_Status(const wchar_t *message) - { - SetItemText(IDT_BENCH_ERROR_MESSAGE, message); - Sync.SendExit(); - } - -public: - CBenchProgressSync Sync; - - bool TotalMode; - CObjectVector Props; - - CSysString Bench2Text; - - NWindows::CThread _thread; - CThreadBenchmark _threadBenchmark; - - CBenchmarkDialog(): - _timer(0), - WasStopped_in_GUI(false), - ExitWasAsked_in_GUI(false), - NeedRestart(false), - TotalMode(false) - {} - - ~CBenchmarkDialog() Z7_DESTRUCTOR_override; - - bool PostMsg_Finish(WPARAM wparam) - { - if ((HWND)*this) - return PostMsg(k_Message_Finished, wparam); - // the (HWND)*this is NULL only for some internal code failure - return true; - } - - INT_PTR Create(HWND wndParent = NULL) - { - BIG_DIALOG_SIZE(332, 228); - return CModalDialog::Create(TotalMode ? IDD_BENCH_TOTAL : SIZED_DIALOG(IDD_BENCH), wndParent); - } - void MessageBoxError(LPCWSTR message) - { - MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); - } - void MessageBoxError_Status(LPCWSTR message) - { - UString s ("ERROR: "); - s += message; - MessageBoxError(s); - SetItemText(IDT_BENCH_ERROR_MESSAGE, s); - } -}; - - - - - - - - - -UString HResultToMessage(HRESULT errorCode); - -#ifdef Z7_LANG -static const UInt32 kLangIDs[] = -{ - IDT_BENCH_DICTIONARY, - IDT_BENCH_MEMORY, - IDT_BENCH_NUM_THREADS, - IDT_BENCH_SIZE, - IDT_BENCH_RATING_LABEL, - IDT_BENCH_USAGE_LABEL, - IDT_BENCH_RPU_LABEL, - IDG_BENCH_COMPRESSING, - IDG_BENCH_DECOMPRESSING, - IDG_BENCH_TOTAL_RATING, - IDT_BENCH_CURRENT, - IDT_BENCH_RESULTING, - IDT_BENCH_ELAPSED, - IDT_BENCH_PASSES, - IDB_STOP, - IDB_RESTART -}; - -static const UInt32 kLangIDs_RemoveColon[] = -{ - IDT_BENCH_SPEED -}; - -#endif - -static LPCTSTR const kProcessingString = TEXT("..."); -static LPCTSTR const kGB = TEXT(" GB"); -static LPCTSTR const kMB = TEXT(" MB"); -static LPCTSTR const kKB = TEXT(" KB"); -// static LPCTSTR const kMIPS = TEXT(" MIPS"); -static LPCTSTR const kKBs = TEXT(" KB/s"); - -static const unsigned kMinDicLogSize = 18; - -static const UInt32 kMinDicSize = (UInt32)1 << kMinDicLogSize; -static const size_t kMaxDicSize = (size_t)1 << (22 + sizeof(size_t) / 4 * 5); -// static const size_t kMaxDicSize = (size_t)1 << 16; - /* - #ifdef MY_CPU_64BIT - (UInt32)(Int32)-1; // we can use it, if we want 4 GB buffer - // (UInt32)15 << 28; - #else - (UInt32)1 << 27; - #endif - */ - - -static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v) -{ - TCHAR s[16]; - ConvertUInt32ToString(v, s); - const int index = (int)cb.AddString(s); - cb.SetItemData(index, (LPARAM)v); - return index; -} - - -bool CBenchmarkDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_BENCH); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - LangSetDlgItems_RemoveColon(*this, kLangIDs_RemoveColon, Z7_ARRAY_SIZE(kLangIDs_RemoveColon)); - LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT); - LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING); - #endif - - InitSyncNew(); - - if (TotalMode) - { - _consoleEdit.Attach(GetItem(IDE_BENCH2_EDIT)); - LOGFONT f; - memset(&f, 0, sizeof(f)); - f.lfHeight = 14; - f.lfWidth = 0; - f.lfWeight = FW_DONTCARE; - f.lfCharSet = DEFAULT_CHARSET; - f.lfOutPrecision = OUT_DEFAULT_PRECIS; - f.lfClipPrecision = CLIP_DEFAULT_PRECIS; - f.lfQuality = DEFAULT_QUALITY; - - f.lfPitchAndFamily = FIXED_PITCH; - // MyStringCopy(f.lfFaceName, TEXT("")); - // f.lfFaceName[0] = 0; - _font.Create(&f); - if (_font._font) - _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE); - } - - UInt32 numCPUs = 1; - - { - AString s ("/ "); - - NSystem::CProcessAffinity threadsInfo; - threadsInfo.InitST(); - - #ifndef Z7_ST - if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0) - numCPUs = threadsInfo.GetNumProcessThreads(); - else - numCPUs = NSystem::GetNumberOfProcessors(); - #endif - - s.Add_UInt32(numCPUs); - s += GetProcessThreadsInfo(threadsInfo); - SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s); - - { - AString s2; - GetSysInfo(s, s2); - SetItemTextA(IDT_BENCH_SYS1, s); - if (s != s2 && !s2.IsEmpty()) - SetItemTextA(IDT_BENCH_SYS2, s2); - } - { - GetCpuName_MultiLine(s); - SetItemTextA(IDT_BENCH_CPU, s); - } - { - GetOsInfoText(s); - s += " : "; - AddCpuFeatures(s); - SetItemTextA(IDT_BENCH_CPU_FEATURE, s); - } - - s = "7-Zip " MY_VERSION_CPU; - SetItemTextA(IDT_BENCH_VER, s); - } - - - // ----- Num Threads ---------- - - if (numCPUs < 1) - numCPUs = 1; - numCPUs = MyMin(numCPUs, (UInt32)(1 << 6)); // it's WIN32 limit - - UInt32 numThreads = Sync.NumThreads; - - if (numThreads == (UInt32)(Int32)-1) - numThreads = numCPUs; - if (numThreads > 1) - numThreads &= ~(UInt32)1; - const UInt32 kNumThreadsMax = (1 << 12); - if (numThreads > kNumThreadsMax) - numThreads = kNumThreadsMax; - - m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS)); - const UInt32 numTheads_Combo = numCPUs * 2; - UInt32 v = 1; - int cur = 0; - for (; v <= numTheads_Combo;) - { - int index = ComboBox_Add_UInt32(m_NumThreads, v); - const UInt32 vNext = v + (v < 2 ? 1 : 2); - if (v <= numThreads) - if (numThreads < vNext || vNext > numTheads_Combo) - { - if (v != numThreads) - index = ComboBox_Add_UInt32(m_NumThreads, numThreads); - cur = index; - } - v = vNext; - } - m_NumThreads.SetCurSel(cur); - Sync.NumThreads = GetNumberOfThreads(); - - - // ----- Dictionary ---------- - - m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY)); - - RamSize = (UInt64)(sizeof(size_t)) << 29; - RamSize_Defined = NSystem::GetRamSize(RamSize); - - - #ifdef UNDER_CE - const UInt32 kNormalizedCeSize = (16 << 20); - if (RamSize > kNormalizedCeSize && RamSize < (33 << 20)) - RamSize = kNormalizedCeSize; - #endif - RamSize_Limit = RamSize / 16 * 15; - - if (Sync.DictSize == (UInt64)(Int64)-1) - { - unsigned dicSizeLog = 25; - #ifdef UNDER_CE - dicSizeLog = 20; - #endif - if (RamSize_Defined) - for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) - if (IsMemoryUsageOK(GetBenchMemoryUsage( - Sync.NumThreads, Sync.Level, (UInt64)1 << dicSizeLog, TotalMode))) - break; - Sync.DictSize = (UInt64)1 << dicSizeLog; - } - - if (Sync.DictSize < kMinDicSize) Sync.DictSize = kMinDicSize; - if (Sync.DictSize > kMaxDicSize) Sync.DictSize = kMaxDicSize; - - cur = 0; - for (unsigned i = (kMinDicLogSize - 1) * 2; i <= (32 - 1) * 2; i++) - { - const size_t dict = (size_t)(2 + (i & 1)) << (i / 2); - // if (i == (32 - 1) * 2) dict = kMaxDicSize; - TCHAR s[32]; - const TCHAR *post; - UInt32 d; - if (dict >= ((UInt32)1 << 31)) { d = (UInt32)(dict >> 30); post = kGB; } - else if (dict >= ((UInt32)1 << 21)) { d = (UInt32)(dict >> 20); post = kMB; } - else { d = (UInt32)(dict >> 10); post = kKB; } - ConvertUInt32ToString(d, s); - lstrcat(s, post); - const int index = (int)m_Dictionary.AddString(s); - m_Dictionary.SetItemData(index, (LPARAM)dict); - if (dict <= Sync.DictSize) - cur = index; - if (dict >= kMaxDicSize) - break; - } - m_Dictionary.SetCurSel(cur); - - - // ----- Num Passes ---------- - - m_NumPasses.Attach(GetItem(IDC_BENCH_NUM_PASSES)); - cur = 0; - v = 1; - for (;;) - { - int index = ComboBox_Add_UInt32(m_NumPasses, v); - const bool isLast = (v >= 10000000); - UInt32 vNext = v * 10; - if (v < 2) vNext = 2; - else if (v < 5) vNext = 5; - else if (v < 10) vNext = 10; - - if (v <= Sync.NumPasses_Limit) - if (isLast || Sync.NumPasses_Limit < vNext) - { - if (v != Sync.NumPasses_Limit) - index = ComboBox_Add_UInt32(m_NumPasses, Sync.NumPasses_Limit); - cur = index; - } - v = vNext; - if (isLast) - break; - } - m_NumPasses.SetCurSel(cur); - - if (TotalMode) - NormalizeSize(true); - else - NormalizePosition(); - - RestartBenchmark(); - - return CModalDialog::OnInit(); -} - - -bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) -{ - int mx, my; - GetMargins(8, mx, my); - - if (!TotalMode) - { - RECT rect; - GetClientRectOfItem(IDT_BENCH_LOG, rect); - int x = xSize - rect.left - mx; - int y = ySize - rect.top - my; - if (x < 0) x = 0; - if (y < 0) y = 0; - MoveItem(IDT_BENCH_LOG, rect.left, rect.top, x, y, true); - return false; - } - - int bx1, bx2, by; - - GetItemSizes(IDCANCEL, bx1, by); - GetItemSizes(IDHELP, bx2, by); - - { - int y = ySize - my - by; - int x = xSize - mx - bx1; - - InvalidateRect(NULL); - - MoveItem(IDCANCEL, x, y, bx1, by); - MoveItem(IDHELP, x - mx - bx2, y, bx2, by); - } - - if (_consoleEdit) - { - int yPos = ySize - my - by; - RECT rect; - GetClientRectOfItem(IDE_BENCH2_EDIT, rect); - int y = rect.top; - int ySize2 = yPos - my - y; - const int kMinYSize = 20; - int xx = xSize - mx * 2; - if (ySize2 < kMinYSize) - { - ySize2 = kMinYSize; - } - _consoleEdit.Move(mx, y, xx, ySize2); - } - return false; -} - - -UInt32 CBenchmarkDialog::GetNumberOfThreads() -{ - return (UInt32)m_NumThreads.GetItemData_of_CurSel(); -} - - -#define UINT_TO_STR_3(s, val) { \ - s[0] = (wchar_t)('0' + (val) / 100); \ - s[1] = (wchar_t)('0' + (val) % 100 / 10); \ - s[2] = (wchar_t)('0' + (val) % 10); \ - s += 3; s[0] = 0; } - -static WCHAR *NumberToDot3(UInt64 val, WCHAR *s) -{ - s = ConvertUInt64ToString(val / 1000, s); - const UInt32 rem = (UInt32)(val % 1000); - *s++ = '.'; - UINT_TO_STR_3(s, rem) - return s; -} - -void CBenchmarkDialog::SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post) -{ - TCHAR s[64]; - ConvertUInt64ToString(val, s); - if (post) - lstrcat(s, post); - SetItemText(itemID, s); -} - -static void AddSize_MB(UString &s, UInt64 size) -{ - s.Add_UInt64((size + (1 << 20) - 1) >> 20); - s += kMB; -} - -void CBenchmarkDialog::Print_MemUsage(UString &s, UInt64 memUsage) const -{ - AddSize_MB(s, memUsage); - if (RamSize_Defined) - { - s += " / "; - AddSize_MB(s, RamSize); - } -} - -size_t CBenchmarkDialog::OnChangeDictionary() -{ - const size_t dict = (size_t)m_Dictionary.GetItemData_of_CurSel(); - const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), - Sync.Level, - dict, - false); // totalBench mode - - UString s; - Print_MemUsage(s, memUsage); - - #ifdef Z7_LARGE_PAGES - { - AString s2; - Add_LargePages_String(s2); - if (!s2.IsEmpty()) - { - s.Add_Space(); - s += s2; - } - } - #endif - - SetItemText(IDT_BENCH_MEMORY_VAL, s); - - return dict; -} - - -static const UInt32 g_IDs[] = -{ - IDT_BENCH_COMPRESS_SIZE1, - IDT_BENCH_COMPRESS_SIZE2, - IDT_BENCH_COMPRESS_USAGE1, - IDT_BENCH_COMPRESS_USAGE2, - IDT_BENCH_COMPRESS_SPEED1, - IDT_BENCH_COMPRESS_SPEED2, - IDT_BENCH_COMPRESS_RATING1, - IDT_BENCH_COMPRESS_RATING2, - IDT_BENCH_COMPRESS_RPU1, - IDT_BENCH_COMPRESS_RPU2, - - IDT_BENCH_DECOMPR_SIZE1, - IDT_BENCH_DECOMPR_SIZE2, - IDT_BENCH_DECOMPR_SPEED1, - IDT_BENCH_DECOMPR_SPEED2, - IDT_BENCH_DECOMPR_RATING1, - IDT_BENCH_DECOMPR_RATING2, - IDT_BENCH_DECOMPR_USAGE1, - IDT_BENCH_DECOMPR_USAGE2, - IDT_BENCH_DECOMPR_RPU1, - IDT_BENCH_DECOMPR_RPU2, - - IDT_BENCH_TOTAL_USAGE_VAL, - IDT_BENCH_TOTAL_RATING_VAL, - IDT_BENCH_TOTAL_RPU_VAL -}; - - -static const unsigned k_Ids_Enc_1[] = { - IDT_BENCH_COMPRESS_USAGE1, - IDT_BENCH_COMPRESS_SPEED1, - IDT_BENCH_COMPRESS_RPU1, - IDT_BENCH_COMPRESS_RATING1, - IDT_BENCH_COMPRESS_SIZE1 }; - -static const unsigned k_Ids_Enc[] = { - IDT_BENCH_COMPRESS_USAGE2, - IDT_BENCH_COMPRESS_SPEED2, - IDT_BENCH_COMPRESS_RPU2, - IDT_BENCH_COMPRESS_RATING2, - IDT_BENCH_COMPRESS_SIZE2 }; - -static const unsigned k_Ids_Dec_1[] = { - IDT_BENCH_DECOMPR_USAGE1, - IDT_BENCH_DECOMPR_SPEED1, - IDT_BENCH_DECOMPR_RPU1, - IDT_BENCH_DECOMPR_RATING1, - IDT_BENCH_DECOMPR_SIZE1 }; - -static const unsigned k_Ids_Dec[] = { - IDT_BENCH_DECOMPR_USAGE2, - IDT_BENCH_DECOMPR_SPEED2, - IDT_BENCH_DECOMPR_RPU2, - IDT_BENCH_DECOMPR_RATING2, - IDT_BENCH_DECOMPR_SIZE2 }; - -static const unsigned k_Ids_Tot[] = { - IDT_BENCH_TOTAL_USAGE_VAL, - 0, - IDT_BENCH_TOTAL_RPU_VAL, - IDT_BENCH_TOTAL_RATING_VAL, - 0 }; - - -void CBenchmarkDialog::MyKillTimer() -{ - if (_timer != 0) - { - KillTimer(kTimerID); - _timer = 0; - } -} - - -bool CBenchmarkDialog::OnDestroy() -{ - /* actually timer was removed before. - also the timer must be removed by Windows, when window will be removed. */ - MyKillTimer(); // it's optional code - return false; // we return (false) to perform default dialog operation -} - -void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString); - -void CBenchmarkDialog::StartBenchmark() -{ - NeedRestart = false; - WasStopped_in_GUI = false; - - SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); - - MyKillTimer(); // optional code. timer was killed before - - const size_t dict = OnChangeDictionary(); - const UInt32 numThreads = GetNumberOfThreads(); - const UInt32 numPasses = (UInt32)m_NumPasses.GetItemData_of_CurSel(); - - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_IDs); i++) - SetItemText(g_IDs[i], kProcessingString); - - SetItemText_Empty(IDT_BENCH_LOG); - SetItemText_Empty(IDT_BENCH_ELAPSED_VAL); - SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); - - const UInt64 memUsage = GetBenchMemoryUsage(numThreads, Sync.Level, dict, - false); // totalBench - if (!IsMemoryUsageOK(memUsage)) - { - UString s2; - LangString_OnlyFromLangFile(IDS_MEM_REQUIRED_MEM_SIZE, s2); - if (s2.IsEmpty()) - { - s2 = LangString(IDT_BENCH_MEMORY); - if (s2.IsEmpty()) - GetItemText(IDT_BENCH_MEMORY, s2); - s2.RemoveChar(L':'); - } - UString s; - SetErrorMessage_MemUsage(s, memUsage, RamSize, RamSize_Limit, s2); - MessageBoxError_Status(s); - return; - } - - EnableItem(IDB_STOP, true); - - _startTime = GetTickCount(); - _finishTime = _startTime; - _finishTime_WasSet = false; - - { - NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); - InitSyncNew(); - Sync.DictSize = dict; - Sync.NumThreads = numThreads; - Sync.NumPasses_Limit = numPasses; - } - - PrintTime(); - - _timer = SetTimer(kTimerID, kTimerElapse); - if (_thread.Create(CThreadBenchmark::MyThreadFunction, &_threadBenchmark) != 0) - { - MyKillTimer(); - MessageBoxError_Status(L"Can't create thread"); - } - return; -} - - -void CBenchmarkDialog::RestartBenchmark() -{ - if (ExitWasAsked_in_GUI) - return; - - if (_thread.IsCreated()) - { - NeedRestart = true; - SendExit_Status(L"Stop for restart ..."); - } - else - StartBenchmark(); -} - - -void CBenchmarkDialog::Disable_Stop_Button() -{ - // if we disable focused button, then focus will be lost - if (GetFocus() == GetItem(IDB_STOP)) - { - // SendMsg_NextDlgCtl_Prev(); - SendMsg_NextDlgCtl_CtlId(IDB_RESTART); - } - EnableItem(IDB_STOP, false); -} - - -void CBenchmarkDialog::OnStopButton() -{ - if (ExitWasAsked_in_GUI) - return; - - Disable_Stop_Button(); - - WasStopped_in_GUI = true; - if (_thread.IsCreated()) - { - SendExit_Status(L"Stop ..."); - } -} - - - -void CBenchmarkDialog::OnCancel() -{ - ExitWasAsked_in_GUI = true; - - /* - SendMsg_NextDlgCtl_Prev(); - EnableItem(IDCANCEL, false); - */ - - if (_thread.IsCreated()) - SendExit_Status(L"Cancel ..."); - else - CModalDialog::OnCancel(); -} - - -void CBenchmarkDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); -} - - - -// void GetTimeString(UInt64 timeValue, wchar_t *s); - -void CBenchmarkDialog::PrintTime() -{ - const UInt32 curTime = - _finishTime_WasSet ? - _finishTime : - ::GetTickCount(); - - const UInt32 elapsedTime = (curTime - _startTime); - - WCHAR s[64]; - - WCHAR *p = ConvertUInt32ToString(elapsedTime / 1000, s); - - if (_finishTime_WasSet) - { - *p++ = '.'; - UINT_TO_STR_3(p, elapsedTime % 1000) - } - - // p = NumberToDot3((UInt64)elapsedTime, s); - - MyStringCopy(p, L" s"); - - // if (WasStopped_in_GUI) wcscat(s, L" X"); // for debug - - if (s == ElapsedSec_Prev) - return; - - ElapsedSec_Prev = s; - - // static cnt = 0; cnt++; wcscat(s, L" "); - // UString s2; s2.Add_UInt32(cnt); wcscat(s, s2.Ptr()); - - SetItemText(IDT_BENCH_ELAPSED_VAL, s); -} - - -static UInt64 GetMips(UInt64 ips) -{ - return (ips + 500000) / 1000000; -} - - -static UInt64 GetUsagePercents(UInt64 usage) -{ - return Benchmark_GetUsage_Percents(usage); -} - - -static UInt32 GetRating(const CTotalBenchRes &info) -{ - UInt64 numIter = info.NumIterations2; - if (numIter == 0) - numIter = 1000000; - const UInt64 rating64 = GetMips(info.Rating / numIter); - // return rating64; - UInt32 rating32 = (UInt32)rating64; - if (rating32 != rating64) - rating32 = (UInt32)(Int32)-1; - return rating32; -} - - -static void AddUsageString(UString &s, const CTotalBenchRes &info) -{ - UInt64 numIter = info.NumIterations2; - if (numIter == 0) - numIter = 1000000; - UInt64 usage = GetUsagePercents(info.Usage / numIter); - - wchar_t w[64]; - ConvertUInt64ToString(usage, w); - unsigned len = MyStringLen(w); - while (len < 5) - { - s.Add_Space(); - len++; - } - s += w; - s += "%"; -} - - -static void Add_Dot3String(UString &s, UInt64 val) -{ - WCHAR temp[32]; - NumberToDot3(val, temp); - s += temp; -} - - -static void AddRatingString(UString &s, const CTotalBenchRes &info) -{ - // AddUsageString(s, info); - // s.Add_Space(); - // s.Add_UInt32(GetRating(info)); - Add_Dot3String(s, GetRating(info)); -} - - -static void AddRatingsLine(UString &s, const CTotalBenchRes &enc, const CTotalBenchRes &dec - #ifdef PRINT_ITER_TIME - , DWORD ticks - #endif - ) -{ - // AddUsageString(s, enc); s.Add_Space(); - - AddRatingString(s, enc); - s += " "; - AddRatingString(s, dec); - - CTotalBenchRes tot_BenchRes; - tot_BenchRes.SetSum(enc, dec); - - s += " "; - AddRatingString(s, tot_BenchRes); - - s.Add_Space(); AddUsageString(s, tot_BenchRes); - - - #ifdef PRINT_ITER_TIME - s.Add_Space(); - { - Add_Dot3String(s, ticks; - s += " s"; - // s.Add_UInt32(ticks); s += " ms"; - } - #endif -} - - -void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID) -{ - // SetItemText_Number(controlID, GetMips(rating), kMIPS); - WCHAR s[64]; - MyStringCopy(NumberToDot3(GetMips(rating), s), L" GIPS"); - SetItemText(controlID, s); -} - -void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID) -{ - SetItemText_Number(controlID, GetUsagePercents(usage), TEXT("%")); -} - - -// void SetItemText_Number - -void CBenchmarkDialog::PrintBenchRes( - const CTotalBenchRes2 &info, - const UINT ids[]) -{ - if (info.NumIterations2 == 0) - return; - if (ids[1] != 0) - SetItemText_Number(ids[1], (info.Speed >> 10) / info.NumIterations2, kKBs); - PrintRating(info.Rating / info.NumIterations2, ids[3]); - PrintRating(info.RPU / info.NumIterations2, ids[2]); - PrintUsage(info.Usage / info.NumIterations2, ids[0]); - if (ids[4] != 0) - { - UInt64 val = info.UnpackSize; - LPCTSTR kPostfix; - if (val >= ((UInt64)1 << 40)) - { - kPostfix = kGB; - val >>= 30; - } - else - { - kPostfix = kMB; - val >>= 20; - } - SetItemText_Number(ids[4], val, kPostfix); - } -} - - -// static UInt32 k_Message_Finished_cnt = 0; -// static UInt32 k_OnTimer_cnt = 0; - -bool CBenchmarkDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - if (message != k_Message_Finished) - return CModalDialog::OnMessage(message, wParam, lParam); - - { - if (wParam == k_Msg_WPARM_Thread_Finished) - { - _finishTime = GetTickCount(); - _finishTime_WasSet = true; - MyKillTimer(); - - if (_thread.Wait_Close() != 0) - { - MessageBoxError_Status(L"Thread Wait Error"); - } - - if (!WasStopped_in_GUI) - { - WasStopped_in_GUI = true; - Disable_Stop_Button(); - } - - HRESULT res = Sync.BenchFinish_Thread_HRESULT; - if (res != S_OK) - // if (!ExitWasAsked_in_GUI || res != E_ABORT) - MessageBoxError_Status(HResultToMessage(res)); - - if (ExitWasAsked_in_GUI) - { - // SetItemText(IDT_BENCH_ERROR_MESSAGE, "before CModalDialog::OnCancel()"); - // Sleep (2000); - // MessageBoxError(L"test"); - CModalDialog::OnCancel(); - return true; - } - - SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); - - res = Sync.BenchFinish_Task_HRESULT; - if (res != S_OK) - { - if (!WasStopped_in_GUI || res != E_ABORT) - { - UString m; - if (res == S_FALSE) - m = "Decoding error"; - else if (res == CLASS_E_CLASSNOTAVAILABLE) - m = "Can't find 7z.dll"; - else - m = HResultToMessage(res); - MessageBoxError_Status(m); - } - } - - if (NeedRestart) - { - StartBenchmark(); - return true; - } - } - // k_Message_Finished_cnt++; - UpdateGui(); - return true; - } -} - - -bool CBenchmarkDialog::OnTimer(WPARAM timerID, LPARAM /* callback */) -{ - // k_OnTimer_cnt++; - if (timerID == kTimerID) - UpdateGui(); - return true; -} - - -void CBenchmarkDialog::UpdateGui() -{ - PrintTime(); - - if (TotalMode) - { - bool wasChanged = false; - { - NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); - - if (Sync.TextWasChanged) - { - wasChanged = true; - Bench2Text += Sync.Text; - Sync.Text.Empty(); - Sync.TextWasChanged = false; - } - } - if (wasChanged) - _consoleEdit.SetText(Bench2Text); - return; - } - - CSyncData sd; - CRecordVector RatingVector; - - { - NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); - sd = Sync.sd; - - if (sd.NeedPrint_RatingVector) - RatingVector = Sync.RatingVector; - - if (sd.NeedPrint_Freq) - { - Sync.FreqString_GUI = Sync.FreqString_Sync; - sd.NeedPrint_RatingVector = true; - } - - Sync.sd.NeedPrint_RatingVector = false; - Sync.sd.NeedPrint_Enc_1 = false; - Sync.sd.NeedPrint_Enc = false; - Sync.sd.NeedPrint_Dec_1 = false; - Sync.sd.NeedPrint_Dec = false; - Sync.sd.NeedPrint_Tot = false; - Sync.sd.NeedPrint_Freq = false; - } - - if (sd.NumPasses_Finished != NumPasses_Finished_Prev) - { - SetItemText_Number(IDT_BENCH_PASSES_VAL, sd.NumPasses_Finished, TEXT(" /")); - NumPasses_Finished_Prev = sd.NumPasses_Finished; - } - - if (sd.NeedPrint_Enc_1) PrintBenchRes(sd.Enc_BenchRes_1, k_Ids_Enc_1); - if (sd.NeedPrint_Enc) PrintBenchRes(sd.Enc_BenchRes, k_Ids_Enc); - if (sd.NeedPrint_Dec_1) PrintBenchRes(sd.Dec_BenchRes_1, k_Ids_Dec_1); - if (sd.NeedPrint_Dec) PrintBenchRes(sd.Dec_BenchRes, k_Ids_Dec); - - if (sd.BenchWasFinished && sd.NeedPrint_Tot) - { - CTotalBenchRes2 tot_BenchRes = sd.Enc_BenchRes; - tot_BenchRes.Update_With_Res2(sd.Dec_BenchRes); - PrintBenchRes(tot_BenchRes, k_Ids_Tot); - } - - - if (sd.NeedPrint_RatingVector) - // for (unsigned k = 0; k < 1; k++) - { - UString s; - s += Sync.FreqString_GUI; - if (!RatingVector.IsEmpty()) - { - if (!s.IsEmpty()) - s.Add_LF(); - s += "Compr Decompr Total CPU" - #ifdef PRINT_ITER_TIME - " Time" - #endif - ; - s.Add_LF(); - } - // s += "GIPS GIPS GIPS % s"; s.Add_LF(); - for (unsigned i = 0; i < RatingVector.Size(); i++) - { - if (i != 0) - s.Add_LF(); - if ((int)i == sd.RatingVector_DeletedIndex) - { - s += "..."; - s.Add_LF(); - } - const CBenchPassResult &pair = RatingVector[i]; - /* - s += "g:"; s.Add_UInt32((UInt32)pair.EncInfo.GlobalTime); - s += " u:"; s.Add_UInt32((UInt32)pair.EncInfo.UserTime); - s.Add_Space(); - */ - AddRatingsLine(s, pair.Enc, pair.Dec - #ifdef PRINT_ITER_TIME - , pair.Ticks - #endif - ); - /* - { - UInt64 v = i + 1; - if (sd.RatingVector_DeletedIndex >= 0 && i >= (unsigned)sd.RatingVector_DeletedIndex) - v += sd.RatingVector_NumDeleted; - char temp[64]; - ConvertUInt64ToString(v, temp); - s += " : "; - s += temp; - } - */ - } - - if (sd.BenchWasFinished) - { - s.Add_LF(); - s += "-------------"; - s.Add_LF(); - { - // average time is not correct because of freq detection in first iteration - AddRatingsLine(s, sd.Enc_BenchRes, sd.Dec_BenchRes - #ifdef PRINT_ITER_TIME - , (DWORD)(sd.TotalTicks / (sd.NumPasses_Finished ? sd.NumPasses_Finished : 1)) - #endif - ); - } - } - // s.Add_LF(); s += "OnTimer: "; s.Add_UInt32(k_OnTimer_cnt); - // s.Add_LF(); s += "finished Message: "; s.Add_UInt32(k_Message_Finished_cnt); - // static cnt = 0; cnt++; s.Add_LF(); s += "Print: "; s.Add_UInt32(cnt); - // s.Add_LF(); s += "NumEncProgress: "; s.Add_UInt32((UInt32)sd.NumEncProgress); - // s.Add_LF(); s += "NumDecProgress: "; s.Add_UInt32((UInt32)sd.NumDecProgress); - SetItemText(IDT_BENCH_LOG, s); - } -} - - -bool CBenchmarkDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE && - (itemID == IDC_BENCH_DICTIONARY || - itemID == IDC_BENCH_NUM_PASSES || - itemID == IDC_BENCH_NUM_THREADS)) - { - RestartBenchmark(); - return true; - } - return CModalDialog::OnCommand(code, itemID, lParam); -} - - -bool CBenchmarkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_RESTART: - RestartBenchmark(); - return true; - case IDB_STOP: - OnStopButton(); - return true; - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - - - - - -// ---------- Benchmark Thread ---------- - -struct CBenchCallback Z7_final: public IBenchCallback -{ - UInt64 dictionarySize; - CBenchProgressSync *Sync; - CBenchmarkDialog *BenchmarkDialog; - - HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override; - HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override; -}; - -HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final) -{ - bool needPost = false; - { - NSynchronization::CCriticalSectionLock lock(Sync->CS); - if (Sync->Exit) - return E_ABORT; - CSyncData &sd = Sync->sd; - // sd.NumEncProgress++; - CTotalBenchRes2 &br = sd.Enc_BenchRes_1; - { - UInt64 dictSize = Sync->DictSize; - if (final) - { - // sd.EncInfo = info; - } - else - { - /* if (!final), then CBenchInfo::NumIterations means totalNumber of threads. - so we can reduce the dictionary */ - if (dictSize > info.UnpackSize) - dictSize = info.UnpackSize; - } - br.Rating = info.GetRating_LzmaEnc(dictSize); - } - br.SetFrom_BenchInfo(info); - sd.NeedPrint_Enc_1 = true; - if (final) - { - sd.Enc_BenchRes.Update_With_Res2(br); - sd.NeedPrint_Enc = true; - needPost = true; - } - } - - if (needPost) - BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); - - return S_OK; -} - - -HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final) -{ - NSynchronization::CCriticalSectionLock lock(Sync->CS); - if (Sync->Exit) - return E_ABORT; - CSyncData &sd = Sync->sd; - // sd.NumDecProgress++; - CTotalBenchRes2 &br = sd.Dec_BenchRes_1; - br.Rating = info.GetRating_LzmaDec(); - br.SetFrom_BenchInfo(info); - sd.NeedPrint_Dec_1 = true; - if (final) - sd.Dec_BenchRes.Update_With_Res2(br); - return S_OK; -} - - -struct CBenchCallback2 Z7_final: public IBenchPrintCallback -{ - CBenchProgressSync *Sync; - bool TotalMode; - - void Print(const char *s) Z7_override; - void NewLine() Z7_override; - HRESULT CheckBreak() Z7_override; -}; - -void CBenchCallback2::Print(const char *s) -{ - if (TotalMode) - { - NSynchronization::CCriticalSectionLock lock(Sync->CS); - Sync->Text += s; - Sync->TextWasChanged = true; - } -} - -void CBenchCallback2::NewLine() -{ - Print("\xD\n"); -} - -HRESULT CBenchCallback2::CheckBreak() -{ - if (Sync->Exit) - return E_ABORT; - return S_OK; -} - - - -struct CFreqCallback Z7_final: public IBenchFreqCallback -{ - CBenchmarkDialog *BenchmarkDialog; - - virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) Z7_override; - virtual HRESULT FreqsFinished(unsigned numThreads) Z7_override; -}; - -HRESULT CFreqCallback::AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) -{ - HRESULT res; - { - CBenchProgressSync &sync = BenchmarkDialog->Sync; - NSynchronization::CCriticalSectionLock lock(sync.CS); - UString &s = sync.FreqString_Sync; - if (sync.NumFreqThreadsPrev != numThreads) - { - sync.NumFreqThreadsPrev = numThreads; - if (!s.IsEmpty()) - s.Add_LF(); - s.Add_UInt32(numThreads); - s += "T Frequency (MHz):"; - s.Add_LF(); - } - s.Add_Space(); - if (numThreads != 1) - { - s.Add_UInt64(GetUsagePercents(usage)); - s.Add_Char('%'); - s.Add_Space(); - } - s.Add_UInt64(GetMips(freq)); - // BenchmarkDialog->Sync.sd.NeedPrint_Freq = true; - res = sync.Exit ? E_ABORT : S_OK; - } - // BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); - return res; -} - -HRESULT CFreqCallback::FreqsFinished(unsigned /* numThreads */) -{ - HRESULT res; - { - CBenchProgressSync &sync = BenchmarkDialog->Sync; - NSynchronization::CCriticalSectionLock lock(sync.CS); - sync.sd.NeedPrint_Freq = true; - BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); - res = sync.Exit ? E_ABORT : S_OK; - } - BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); - return res; -} - - - -// define USE_DUMMY only for debug -// #define USE_DUMMY -#ifdef USE_DUMMY -static unsigned dummy = 1; -static unsigned Dummy(unsigned limit) -{ - unsigned sum = 0; - for (unsigned k = 0; k < limit; k++) - { - sum += dummy; - if (sum == 0) - break; - } - return sum; -} -#endif - - -HRESULT CThreadBenchmark::Process() -{ - /* the first benchmark pass can be slow, - if we run benchmark while the window is being created, - and (no freq detecion loop) && (dictionary is small) (-mtic is small) */ - - // Sleep(300); // for debug - #ifdef USE_DUMMY - Dummy(1000 * 1000 * 1000); // for debug - #endif - - CBenchProgressSync &sync = BenchmarkDialog->Sync; - HRESULT finishHRESULT = S_OK; - - try - { - for (UInt32 passIndex = 0;; passIndex++) - { - // throw 1; // to debug - // throw CSystemException(E_INVALIDARG); // to debug - - UInt64 dictionarySize; - UInt32 numThreads; - { - NSynchronization::CCriticalSectionLock lock(sync.CS); - if (sync.Exit) - break; - dictionarySize = sync.DictSize; - numThreads = sync.NumThreads; - } - - #ifdef PRINT_ITER_TIME - const DWORD startTick = GetTickCount(); - #endif - - CBenchCallback callback; - - callback.dictionarySize = dictionarySize; - callback.Sync = &sync; - callback.BenchmarkDialog = BenchmarkDialog; - - CBenchCallback2 callback2; - callback2.TotalMode = BenchmarkDialog->TotalMode; - callback2.Sync = &sync; - - CFreqCallback freqCallback; - freqCallback.BenchmarkDialog = BenchmarkDialog; - - HRESULT result; - - try - { - CObjectVector props; - - props = BenchmarkDialog->Props; - - if (BenchmarkDialog->TotalMode) - { - props = BenchmarkDialog->Props; - } - else - { - { - CProperty prop; - prop.Name = "mt"; - prop.Value.Add_UInt32(numThreads); - props.Add(prop); - } - { - CProperty prop; - prop.Name = 'd'; - prop.Name.Add_UInt32((UInt32)(dictionarySize >> 10)); - prop.Name.Add_Char('k'); - props.Add(prop); - } - } - - result = Bench(EXTERNAL_CODECS_LOC_VARS - BenchmarkDialog->TotalMode ? &callback2 : NULL, - BenchmarkDialog->TotalMode ? NULL : &callback, - props, 1, false, - (!BenchmarkDialog->TotalMode) && passIndex == 0 ? &freqCallback: NULL); - - // result = S_FALSE; // for debug; - // throw 1; - } - catch(...) - { - result = E_FAIL; - } - - #ifdef PRINT_ITER_TIME - const DWORD numTicks = GetTickCount() - startTick; - #endif - - bool finished = true; - - NSynchronization::CCriticalSectionLock lock(sync.CS); - - if (result != S_OK) - { - sync.BenchFinish_Task_HRESULT = result; - break; - } - - { - CSyncData &sd = sync.sd; - - sd.NumPasses_Finished++; - #ifdef PRINT_ITER_TIME - sd.TotalTicks += numTicks; - #endif - - if (BenchmarkDialog->TotalMode) - break; - - { - CTotalBenchRes tot_BenchRes = sd.Enc_BenchRes_1; - tot_BenchRes.Update_With_Res(sd.Dec_BenchRes_1); - - sd.NeedPrint_RatingVector = true; - { - CBenchPassResult pair; - // pair.EncInfo = sd.EncInfo; // for debug - pair.Enc = sd.Enc_BenchRes_1; - pair.Dec = sd.Dec_BenchRes_1; - #ifdef PRINT_ITER_TIME - pair.Ticks = numTicks; - #endif - sync.RatingVector.Add(pair); - // pair.Dec_Defined = true; - } - } - - sd.NeedPrint_Dec = true; - sd.NeedPrint_Tot = true; - - if (sync.RatingVector.Size() > kRatingVector_NumBundlesMax) - { - // sd.RatingVector_NumDeleted++; - sd.RatingVector_DeletedIndex = (int)(kRatingVector_NumBundlesMax / 4); - sync.RatingVector.Delete((unsigned)(sd.RatingVector_DeletedIndex)); - } - - if (sync.sd.NumPasses_Finished < sync.NumPasses_Limit) - finished = false; - else - { - sync.sd.BenchWasFinished = true; - // BenchmarkDialog->_finishTime = GetTickCount(); - // return 0; - } - } - - if (BenchmarkDialog->TotalMode) - break; - - /* - if (newTick - prevTick < 1000) - numSameTick++; - if (numSameTick > 5 || finished) - { - prevTick = newTick; - numSameTick = 0; - */ - // for (unsigned i = 0; i < 1; i++) - { - // we suppose that PostMsg messages will be processed in order. - if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Iter_Finished)) - { - finished = true; - finishHRESULT = E_FAIL; - // throw 1234567; - } - } - if (finished) - break; - } - // return S_OK; - } - catch(CSystemException &e) - { - finishHRESULT = e.ErrorCode; - // BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode)); - // return E_FAIL; - } - catch(...) - { - finishHRESULT = E_FAIL; - // BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL)); - // return E_FAIL; - } - - if (finishHRESULT != S_OK) - { - NSynchronization::CCriticalSectionLock lock(sync.CS); - sync.BenchFinish_Thread_HRESULT = finishHRESULT; - } - if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Thread_Finished)) - { - // sync.BenchFinish_Thread_HRESULT = E_FAIL; - } - return 0; -} - - - -static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) -{ - const wchar_t *end; - UInt64 result = ConvertStringToUInt64(s, &end); - if (*end != 0 || s.IsEmpty()) - prop = s; - else if (result <= (UInt32)0xFFFFFFFF) - prop = (UInt32)result; - else - prop = result; -} - - -HRESULT Benchmark( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &props, UInt32 numIterations, HWND hwndParent) -{ - CBenchmarkDialog bd; - - bd.TotalMode = false; - bd.Props = props; - if (numIterations == 0) - numIterations = 1; - bd.Sync.NumPasses_Limit = numIterations; - bd.Sync.DictSize = (UInt64)(Int64)-1; - bd.Sync.NumThreads = (UInt32)(Int32)-1; - bd.Sync.Level = -1; - - COneMethodInfo method; - - UInt32 numCPUs = 1; - #ifndef Z7_ST - numCPUs = NSystem::GetNumberOfProcessors(); - #endif - UInt32 numThreads = numCPUs; - - FOR_VECTOR (i, props) - { - const CProperty &prop = props[i]; - UString name = prop.Name; - name.MakeLower_Ascii(); - if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*") - { - bd.TotalMode = true; - continue; - } - - NCOM::CPropVariant propVariant; - if (!prop.Value.IsEmpty()) - ParseNumberString(prop.Value, propVariant); - if (name.IsPrefixedBy(L"mt")) - { - #ifndef Z7_ST - RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)) - if (numThreads != numCPUs) - bd.Sync.NumThreads = numThreads; - #endif - continue; - } - /* - if (name.IsEqualTo("time")) - { - // UInt32 testTime = 4; - // RINOK(ParsePropToUInt32(L"", propVariant, testTime)); - continue; - } - RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)); - */ - // here we need to parse DictSize property, and ignore unknown properties - method.ParseMethodFromPROPVARIANT(name, propVariant); - } - - if (bd.TotalMode) - { - // bd.Bench2Text.Empty(); - bd.Bench2Text = "7-Zip " MY_VERSION_CPU; - // bd.Bench2Text.Add_Char((char)0xD); - bd.Bench2Text.Add_LF(); - } - - { - UInt64 dict; - if (method.Get_DicSize(dict)) - bd.Sync.DictSize = dict; - } - bd.Sync.Level = (int)method.GetLevel(); - - // Dummy(1000 * 1000 * 1); - - { - CThreadBenchmark &benchmarker = bd._threadBenchmark; - #ifdef Z7_EXTERNAL_CODECS - benchmarker._externalCodecs = _externalCodecs; - #endif - benchmarker.BenchmarkDialog = &bd; - } - - bd.Create(hwndParent); - - return S_OK; -} - - -CBenchmarkDialog::~CBenchmarkDialog() -{ - if (_thread.IsCreated()) - { - /* the following code will be not executed in normal code flow. - it can be called, if there is some internal failure in dialog code. */ - Attach(NULL); - MessageBoxError(L"The flaw in benchmark thread code"); - Sync.SendExit(); - _thread.Wait_Close(); - } -} +// BenchmarkDialog.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/Defs.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/MyException.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/System.h" +#include "../../../Windows/Thread.h" +#include "../../../Windows/SystemInfo.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" + +#include "../../Common/MethodProps.h" + +#include "../FileManager/DialogSize.h" +#include "../FileManager/HelpUtils.h" +#include "../FileManager/LangUtils.h" +#include "../FileManager/resourceGui.h" + +#include "../../MyVersion.h" + +#include "../Common/Bench.h" + +#include "BenchmarkDialogRes.h" +#include "BenchmarkDialog.h" + +using namespace NWindows; + +#define kHelpTopic "fm/benchmark.htm" + +static const UINT_PTR kTimerID = 4; +static const UINT kTimerElapse = 1000; // 1000 + +// use PRINT_ITER_TIME to show time of each iteration in log box +// #define PRINT_ITER_TIME + +static const unsigned kRatingVector_NumBundlesMax = 20; + +enum MyBenchMessages +{ + k_Message_Finished = WM_APP + 1 +}; + +enum My_Message_WPARAM +{ + k_Msg_WPARM_Thread_Finished = 0, + k_Msg_WPARM_Iter_Finished, + k_Msg_WPARM_Enc1_Finished +}; + + +struct CBenchPassResult +{ + CTotalBenchRes Enc; + CTotalBenchRes Dec; +#ifdef PRINT_ITER_TIME + DWORD Ticks; +#endif + // CBenchInfo EncInfo; // for debug + // CBenchPassResult() {}; +}; + + +struct CTotalBenchRes2: public CTotalBenchRes +{ + UInt64 UnpackSize; + + void Init() + { + CTotalBenchRes::Init(); + UnpackSize = 0; + } + + void SetFrom_BenchInfo(const CBenchInfo &info) + { + NumIterations2 = 1; + Generate_From_BenchInfo(info); + UnpackSize = info.Get_UnpackSize_Full(); + } + + void Update_With_Res2(const CTotalBenchRes2 &r) + { + Update_With_Res(r); + UnpackSize += r.UnpackSize; + } +}; + + +struct CSyncData +{ + UInt32 NumPasses_Finished; +#ifdef PRINT_ITER_TIME + DWORD TotalTicks; +#endif + int RatingVector_DeletedIndex; + // UInt64 RatingVector_NumDeleted; + + bool BenchWasFinished; // all passes were finished + bool NeedPrint_Freq; + bool NeedPrint_RatingVector; + bool NeedPrint_Enc_1; + bool NeedPrint_Enc; + bool NeedPrint_Dec_1; + bool NeedPrint_Dec; + bool NeedPrint_Tot; // intermediate Total was updated after current pass + + // UInt64 NumEncProgress; // for debug + // UInt64 NumDecProgress; // for debug + // CBenchInfo EncInfo; // for debug + + CTotalBenchRes2 Enc_BenchRes_1; + CTotalBenchRes2 Enc_BenchRes; + + CTotalBenchRes2 Dec_BenchRes_1; + CTotalBenchRes2 Dec_BenchRes; + + void Init(); +}; + + +void CSyncData::Init() +{ + NumPasses_Finished = 0; + + // NumEncProgress = 0; + // NumDecProgress = 0; + + Enc_BenchRes.Init(); + Enc_BenchRes_1.Init(); + Dec_BenchRes.Init(); + Dec_BenchRes_1.Init(); + + #ifdef PRINT_ITER_TIME + TotalTicks = 0; + #endif + + RatingVector_DeletedIndex = -1; + // RatingVector_NumDeleted = 0; + + BenchWasFinished = + NeedPrint_Freq = + NeedPrint_RatingVector = + NeedPrint_Enc_1 = + NeedPrint_Enc = + NeedPrint_Dec_1 = + NeedPrint_Dec = + NeedPrint_Tot = false; +} + + +struct CBenchProgressSync +{ + bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable + bool TextWasChanged; + + UInt32 NumThreads; + UInt64 DictSize; + UInt32 NumPasses_Limit; + int Level; + + AString Text; + + /* BenchFinish_Task_HRESULT - for result from benchmark code + BenchFinish_Thread_HRESULT - for Exceptions and service errors + these arreos must be shown even if user escapes benchmark */ + HRESULT BenchFinish_Task_HRESULT; + HRESULT BenchFinish_Thread_HRESULT; + + UInt32 NumFreqThreadsPrev; + UString FreqString_Sync; + UString FreqString_GUI; + + // must be written by benchmark thread, read by GUI thread */ + CRecordVector RatingVector; + CSyncData sd; + + NWindows::NSynchronization::CCriticalSection CS; + + CBenchProgressSync() + { + NumPasses_Limit = 1; + } + + void Init(); + + void SendExit() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + Exit = true; + } +}; + + +void CBenchProgressSync::Init() +{ + Exit = false; + + BenchFinish_Task_HRESULT = S_OK; + BenchFinish_Thread_HRESULT = S_OK; + + sd.Init(); + RatingVector.Clear(); + + NumFreqThreadsPrev = 0; + FreqString_Sync.Empty(); + FreqString_GUI.Empty(); + + Text.Empty(); + TextWasChanged = true; +} + + + +struct CMyFont +{ + HFONT _font; + CMyFont(): _font(NULL) {} + ~CMyFont() + { + if (_font) + DeleteObject(_font); + } + void Create(const LOGFONT *lplf) + { + _font = CreateFontIndirect(lplf); + } +}; + + +class CBenchmarkDialog; + +struct CThreadBenchmark +{ + CBenchmarkDialog *BenchmarkDialog; + DECL_EXTERNAL_CODECS_LOC_VARS_DECL + // HRESULT Result; + + HRESULT Process(); + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + /* ((CThreadBenchmark *)param)->Result = */ + ((CThreadBenchmark *)param)->Process(); + return 0; + } +}; + + +class CBenchmarkDialog: + public NWindows::NControl::CModalDialog +{ + bool _finishTime_WasSet; + + bool WasStopped_in_GUI; + bool ExitWasAsked_in_GUI; + bool NeedRestart; + + bool RamSize_Defined; + +public: + bool TotalMode; + +private: + + NWindows::NControl::CComboBox m_Dictionary; + NWindows::NControl::CComboBox m_NumThreads; + NWindows::NControl::CComboBox m_NumPasses; + NWindows::NControl::CEdit _consoleEdit; + UINT_PTR _timer; + + UInt32 _startTime; + UInt32 _finishTime; + + CMyFont _font; + + size_t RamSize; + size_t RamSize_Limit; + + UInt32 NumPasses_Finished_Prev; + + UString ElapsedSec_Prev; + + void InitSyncNew() + { + NumPasses_Finished_Prev = (UInt32)(Int32)-1; + ElapsedSec_Prev.Empty(); + Sync.Init(); + } + + virtual bool OnInit() Z7_override; + virtual bool OnDestroy() Z7_override; + virtual bool OnSize(WPARAM /* wParam */, int xSize, int ySize) Z7_override; + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; + virtual void OnHelp() Z7_override; + virtual void OnCancel() Z7_override; + virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + + void Disable_Stop_Button(); + void OnStopButton(); + void RestartBenchmark(); + void StartBenchmark(); + + void UpdateGui(); + + void PrintTime(); + void PrintRating(UInt64 rating, UINT controlID); + void PrintUsage(UInt64 usage, UINT controlID); + void PrintBenchRes(const CTotalBenchRes2 &info, const UINT ids[]); + + UInt32 GetNumberOfThreads(); + size_t OnChangeDictionary(); + + void SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post = NULL); + void Print_MemUsage(UString &s, UInt64 memUsage) const; + bool IsMemoryUsageOK(UInt64 memUsage) const + { return memUsage + (1 << 20) <= RamSize_Limit; } + + void MyKillTimer(); + + void SendExit_Status(const wchar_t *message) + { + SetItemText(IDT_BENCH_ERROR_MESSAGE, message); + Sync.SendExit(); + } + +public: + CBenchProgressSync Sync; + + CObjectVector Props; + + CSysString Bench2Text; + + NWindows::CThread _thread; + CThreadBenchmark _threadBenchmark; + + CBenchmarkDialog(): + WasStopped_in_GUI(false), + ExitWasAsked_in_GUI(false), + NeedRestart(false), + TotalMode(false), + _timer(0) + {} + + ~CBenchmarkDialog() Z7_DESTRUCTOR_override; + + bool PostMsg_Finish(WPARAM wparam) + { + if ((HWND)*this) + return PostMsg(k_Message_Finished, wparam); + // the (HWND)*this is NULL only for some internal code failure + return true; + } + + INT_PTR Create(HWND wndParent = NULL) + { + BIG_DIALOG_SIZE(332, 228); + return CModalDialog::Create(TotalMode ? IDD_BENCH_TOTAL : SIZED_DIALOG(IDD_BENCH), wndParent); + } + void MessageBoxError(LPCWSTR message) + { + MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); + } + void MessageBoxError_Status(LPCWSTR message) + { + UString s ("ERROR: "); + s += message; + MessageBoxError(s); + SetItemText(IDT_BENCH_ERROR_MESSAGE, s); + } +}; + + + + + + + + + +UString HResultToMessage(HRESULT errorCode); + +#ifdef Z7_LANG +static const UInt32 kLangIDs[] = +{ + IDT_BENCH_DICTIONARY, + IDT_BENCH_MEMORY, + IDT_BENCH_NUM_THREADS, + IDT_BENCH_SIZE, + IDT_BENCH_RATING_LABEL, + IDT_BENCH_USAGE_LABEL, + IDT_BENCH_RPU_LABEL, + IDG_BENCH_COMPRESSING, + IDG_BENCH_DECOMPRESSING, + IDG_BENCH_TOTAL_RATING, + IDT_BENCH_CURRENT, + IDT_BENCH_RESULTING, + IDT_BENCH_ELAPSED, + IDT_BENCH_PASSES, + IDB_STOP, + IDB_RESTART +}; + +static const UInt32 kLangIDs_RemoveColon[] = +{ + IDT_BENCH_SPEED +}; + +#endif + +static LPCTSTR const kProcessingString = TEXT("..."); +static LPCTSTR const kGB = TEXT(" GB"); +static LPCTSTR const kMB = TEXT(" MB"); +static LPCTSTR const kKB = TEXT(" KB"); +// static LPCTSTR const kMIPS = TEXT(" MIPS"); +static LPCTSTR const kKBs = TEXT(" KB/s"); + +static const unsigned kMinDicLogSize = 18; + +static const UInt32 kMinDicSize = (UInt32)1 << kMinDicLogSize; +static const size_t kMaxDicSize = (size_t)1 << (22 + sizeof(size_t) / 4 * 5); +// static const size_t kMaxDicSize = (size_t)1 << 16; + /* + #ifdef MY_CPU_64BIT + (UInt32)(Int32)-1; // we can use it, if we want 4 GB buffer + // (UInt32)15 << 28; + #else + (UInt32)1 << 27; + #endif + */ + + +static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v) +{ + TCHAR s[16]; + ConvertUInt32ToString(v, s); + const int index = (int)cb.AddString(s); + cb.SetItemData(index, (LPARAM)v); + return index; +} + + +bool CBenchmarkDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_BENCH); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + LangSetDlgItems_RemoveColon(*this, kLangIDs_RemoveColon, Z7_ARRAY_SIZE(kLangIDs_RemoveColon)); + LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT); + LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING); + #endif + + InitSyncNew(); + + if (TotalMode) + { + _consoleEdit.Attach(GetItem(IDE_BENCH2_EDIT)); + LOGFONT f; + memset(&f, 0, sizeof(f)); + f.lfHeight = 14; + f.lfWidth = 0; + f.lfWeight = FW_DONTCARE; + f.lfCharSet = DEFAULT_CHARSET; + f.lfOutPrecision = OUT_DEFAULT_PRECIS; + f.lfClipPrecision = CLIP_DEFAULT_PRECIS; + f.lfQuality = DEFAULT_QUALITY; + + f.lfPitchAndFamily = FIXED_PITCH; + // MyStringCopy(f.lfFaceName, TEXT("")); + // f.lfFaceName[0] = 0; + _font.Create(&f); + if (_font._font) + _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE); + } + + UInt32 numCPUs = 1; + + { + AString s ("/ "); + + NSystem::CProcessAffinity threadsInfo; + threadsInfo.InitST(); + + #ifndef Z7_ST + if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0) + numCPUs = threadsInfo.GetNumProcessThreads(); + else + numCPUs = NSystem::GetNumberOfProcessors(); + #endif + + s.Add_UInt32(numCPUs); + s += GetProcessThreadsInfo(threadsInfo); + SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s); + + { + AString s2; + GetSysInfo(s, s2); + SetItemTextA(IDT_BENCH_SYS1, s); + if (s != s2 && !s2.IsEmpty()) + SetItemTextA(IDT_BENCH_SYS2, s2); + } + { + AString registers; + GetCpuName_MultiLine(s, registers); + SetItemTextA(IDT_BENCH_CPU, s); + } + { + GetOsInfoText(s); + s += " : "; + AddCpuFeatures(s); + SetItemTextA(IDT_BENCH_CPU_FEATURE, s); + } + + s = "7-Zip " MY_VERSION_CPU; + SetItemTextA(IDT_BENCH_VER, s); + } + + + // ----- Num Threads ---------- + + if (numCPUs < 1) + numCPUs = 1; + numCPUs = MyMin(numCPUs, (UInt32)(1 << 6)); // it's WIN32 limit + + UInt32 numThreads = Sync.NumThreads; + + if (numThreads == (UInt32)(Int32)-1) + numThreads = numCPUs; + if (numThreads > 1) + numThreads &= ~(UInt32)1; + const UInt32 kNumThreadsMax = (1 << 12); + if (numThreads > kNumThreadsMax) + numThreads = kNumThreadsMax; + + m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS)); + const UInt32 numTheads_Combo = numCPUs * 2; + UInt32 v = 1; + int cur = 0; + for (; v <= numTheads_Combo;) + { + int index = ComboBox_Add_UInt32(m_NumThreads, v); + const UInt32 vNext = v + (v < 2 ? 1 : 2); + if (v <= numThreads) + if (numThreads < vNext || vNext > numTheads_Combo) + { + if (v != numThreads) + index = ComboBox_Add_UInt32(m_NumThreads, numThreads); + cur = index; + } + v = vNext; + } + m_NumThreads.SetCurSel(cur); + Sync.NumThreads = GetNumberOfThreads(); + + + // ----- Dictionary ---------- + + m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY)); + + RamSize = (UInt64)(sizeof(size_t)) << 29; + RamSize_Defined = NSystem::GetRamSize(RamSize); + + + #ifdef UNDER_CE + const UInt32 kNormalizedCeSize = (16 << 20); + if (RamSize > kNormalizedCeSize && RamSize < (33 << 20)) + RamSize = kNormalizedCeSize; + #endif + RamSize_Limit = RamSize / 16 * 15; + + if (Sync.DictSize == (UInt64)(Int64)-1) + { + unsigned dicSizeLog = 25; + #ifdef UNDER_CE + dicSizeLog = 20; + #endif + if (RamSize_Defined) + for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) + if (IsMemoryUsageOK(GetBenchMemoryUsage( + Sync.NumThreads, Sync.Level, (UInt64)1 << dicSizeLog, TotalMode))) + break; + Sync.DictSize = (UInt64)1 << dicSizeLog; + } + + if (Sync.DictSize < kMinDicSize) Sync.DictSize = kMinDicSize; + if (Sync.DictSize > kMaxDicSize) Sync.DictSize = kMaxDicSize; + + cur = 0; + for (unsigned i = (kMinDicLogSize - 1) * 2; i <= (32 - 1) * 2; i++) + { + const size_t dict = (size_t)(2 + (i & 1)) << (i / 2); + // if (i == (32 - 1) * 2) dict = kMaxDicSize; + TCHAR s[32]; + const TCHAR *post; + UInt32 d; + if (dict >= ((UInt32)1 << 31)) { d = (UInt32)(dict >> 30); post = kGB; } + else if (dict >= ((UInt32)1 << 21)) { d = (UInt32)(dict >> 20); post = kMB; } + else { d = (UInt32)(dict >> 10); post = kKB; } + ConvertUInt32ToString(d, s); + lstrcat(s, post); + const int index = (int)m_Dictionary.AddString(s); + m_Dictionary.SetItemData(index, (LPARAM)dict); + if (dict <= Sync.DictSize) + cur = index; + if (dict >= kMaxDicSize) + break; + } + m_Dictionary.SetCurSel(cur); + + + // ----- Num Passes ---------- + + m_NumPasses.Attach(GetItem(IDC_BENCH_NUM_PASSES)); + cur = 0; + v = 1; + for (;;) + { + int index = ComboBox_Add_UInt32(m_NumPasses, v); + const bool isLast = (v >= 10000000); + UInt32 vNext = v * 10; + if (v < 2) vNext = 2; + else if (v < 5) vNext = 5; + else if (v < 10) vNext = 10; + + if (v <= Sync.NumPasses_Limit) + if (isLast || Sync.NumPasses_Limit < vNext) + { + if (v != Sync.NumPasses_Limit) + index = ComboBox_Add_UInt32(m_NumPasses, Sync.NumPasses_Limit); + cur = index; + } + v = vNext; + if (isLast) + break; + } + m_NumPasses.SetCurSel(cur); + + if (TotalMode) + NormalizeSize(true); + else + NormalizePosition(); + + RestartBenchmark(); + + return CModalDialog::OnInit(); +} + + +bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) +{ + int mx, my; + GetMargins(8, mx, my); + + if (!TotalMode) + { + RECT rect; + GetClientRectOfItem(IDT_BENCH_LOG, rect); + int x = xSize - rect.left - mx; + int y = ySize - rect.top - my; + if (x < 0) x = 0; + if (y < 0) y = 0; + MoveItem(IDT_BENCH_LOG, rect.left, rect.top, x, y, true); + return false; + } + + int bx1, bx2, by; + + GetItemSizes(IDCANCEL, bx1, by); + GetItemSizes(IDHELP, bx2, by); + + { + int y = ySize - my - by; + int x = xSize - mx - bx1; + + InvalidateRect(NULL); + + MoveItem(IDCANCEL, x, y, bx1, by); + MoveItem(IDHELP, x - mx - bx2, y, bx2, by); + } + + if (_consoleEdit) + { + int yPos = ySize - my - by; + RECT rect; + GetClientRectOfItem(IDE_BENCH2_EDIT, rect); + int y = rect.top; + int ySize2 = yPos - my - y; + const int kMinYSize = 20; + int xx = xSize - mx * 2; + if (ySize2 < kMinYSize) + { + ySize2 = kMinYSize; + } + _consoleEdit.Move(mx, y, xx, ySize2); + } + return false; +} + + +UInt32 CBenchmarkDialog::GetNumberOfThreads() +{ + return (UInt32)m_NumThreads.GetItemData_of_CurSel(); +} + + +#define UINT_TO_STR_3(s, val) { \ + s[0] = (wchar_t)('0' + (val) / 100); \ + s[1] = (wchar_t)('0' + (val) % 100 / 10); \ + s[2] = (wchar_t)('0' + (val) % 10); \ + s += 3; s[0] = 0; } + +static WCHAR *NumberToDot3(UInt64 val, WCHAR *s) +{ + s = ConvertUInt64ToString(val / 1000, s); + const UInt32 rem = (UInt32)(val % 1000); + *s++ = '.'; + UINT_TO_STR_3(s, rem) + return s; +} + +void CBenchmarkDialog::SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post) +{ + TCHAR s[64]; + ConvertUInt64ToString(val, s); + if (post) + lstrcat(s, post); + SetItemText(itemID, s); +} + +static void AddSize_MB(UString &s, UInt64 size) +{ + s.Add_UInt64((size + (1 << 20) - 1) >> 20); + s += kMB; +} + +void CBenchmarkDialog::Print_MemUsage(UString &s, UInt64 memUsage) const +{ + AddSize_MB(s, memUsage); + if (RamSize_Defined) + { + s += " / "; + AddSize_MB(s, RamSize); + } +} + +size_t CBenchmarkDialog::OnChangeDictionary() +{ + const size_t dict = (size_t)m_Dictionary.GetItemData_of_CurSel(); + const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), + Sync.Level, + dict, + false); // totalBench mode + + UString s; + Print_MemUsage(s, memUsage); + + #ifdef Z7_LARGE_PAGES + { + AString s2; + Add_LargePages_String(s2); + if (!s2.IsEmpty()) + { + s.Add_Space(); + s += s2; + } + } + #endif + + SetItemText(IDT_BENCH_MEMORY_VAL, s); + + return dict; +} + + +static const UInt32 g_IDs[] = +{ + IDT_BENCH_COMPRESS_SIZE1, + IDT_BENCH_COMPRESS_SIZE2, + IDT_BENCH_COMPRESS_USAGE1, + IDT_BENCH_COMPRESS_USAGE2, + IDT_BENCH_COMPRESS_SPEED1, + IDT_BENCH_COMPRESS_SPEED2, + IDT_BENCH_COMPRESS_RATING1, + IDT_BENCH_COMPRESS_RATING2, + IDT_BENCH_COMPRESS_RPU1, + IDT_BENCH_COMPRESS_RPU2, + + IDT_BENCH_DECOMPR_SIZE1, + IDT_BENCH_DECOMPR_SIZE2, + IDT_BENCH_DECOMPR_SPEED1, + IDT_BENCH_DECOMPR_SPEED2, + IDT_BENCH_DECOMPR_RATING1, + IDT_BENCH_DECOMPR_RATING2, + IDT_BENCH_DECOMPR_USAGE1, + IDT_BENCH_DECOMPR_USAGE2, + IDT_BENCH_DECOMPR_RPU1, + IDT_BENCH_DECOMPR_RPU2, + + IDT_BENCH_TOTAL_USAGE_VAL, + IDT_BENCH_TOTAL_RATING_VAL, + IDT_BENCH_TOTAL_RPU_VAL +}; + + +static const unsigned k_Ids_Enc_1[] = { + IDT_BENCH_COMPRESS_USAGE1, + IDT_BENCH_COMPRESS_SPEED1, + IDT_BENCH_COMPRESS_RPU1, + IDT_BENCH_COMPRESS_RATING1, + IDT_BENCH_COMPRESS_SIZE1 }; + +static const unsigned k_Ids_Enc[] = { + IDT_BENCH_COMPRESS_USAGE2, + IDT_BENCH_COMPRESS_SPEED2, + IDT_BENCH_COMPRESS_RPU2, + IDT_BENCH_COMPRESS_RATING2, + IDT_BENCH_COMPRESS_SIZE2 }; + +static const unsigned k_Ids_Dec_1[] = { + IDT_BENCH_DECOMPR_USAGE1, + IDT_BENCH_DECOMPR_SPEED1, + IDT_BENCH_DECOMPR_RPU1, + IDT_BENCH_DECOMPR_RATING1, + IDT_BENCH_DECOMPR_SIZE1 }; + +static const unsigned k_Ids_Dec[] = { + IDT_BENCH_DECOMPR_USAGE2, + IDT_BENCH_DECOMPR_SPEED2, + IDT_BENCH_DECOMPR_RPU2, + IDT_BENCH_DECOMPR_RATING2, + IDT_BENCH_DECOMPR_SIZE2 }; + +static const unsigned k_Ids_Tot[] = { + IDT_BENCH_TOTAL_USAGE_VAL, + 0, + IDT_BENCH_TOTAL_RPU_VAL, + IDT_BENCH_TOTAL_RATING_VAL, + 0 }; + + +void CBenchmarkDialog::MyKillTimer() +{ + if (_timer != 0) + { + KillTimer(kTimerID); + _timer = 0; + } +} + + +bool CBenchmarkDialog::OnDestroy() +{ + /* actually timer was removed before. + also the timer must be removed by Windows, when window will be removed. */ + MyKillTimer(); // it's optional code + return false; // we return (false) to perform default dialog operation +} + +void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString); + +void CBenchmarkDialog::StartBenchmark() +{ + NeedRestart = false; + WasStopped_in_GUI = false; + + SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); + + MyKillTimer(); // optional code. timer was killed before + + const size_t dict = OnChangeDictionary(); + const UInt32 numThreads = GetNumberOfThreads(); + const UInt32 numPasses = (UInt32)m_NumPasses.GetItemData_of_CurSel(); + + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_IDs); i++) + SetItemText(g_IDs[i], kProcessingString); + + SetItemText_Empty(IDT_BENCH_LOG); + SetItemText_Empty(IDT_BENCH_ELAPSED_VAL); + SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); + + const UInt64 memUsage = GetBenchMemoryUsage(numThreads, Sync.Level, dict, + false); // totalBench + if (!IsMemoryUsageOK(memUsage)) + { + UString s2; + LangString_OnlyFromLangFile(IDS_MEM_REQUIRED_MEM_SIZE, s2); + if (s2.IsEmpty()) + { + s2 = LangString(IDT_BENCH_MEMORY); + if (s2.IsEmpty()) + GetItemText(IDT_BENCH_MEMORY, s2); + s2.RemoveChar(L':'); + } + UString s; + SetErrorMessage_MemUsage(s, memUsage, RamSize, RamSize_Limit, s2); + MessageBoxError_Status(s); + return; + } + + EnableItem(IDB_STOP, true); + + _startTime = GetTickCount(); + _finishTime = _startTime; + _finishTime_WasSet = false; + + { + NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); + InitSyncNew(); + Sync.DictSize = dict; + Sync.NumThreads = numThreads; + Sync.NumPasses_Limit = numPasses; + } + + PrintTime(); + + _timer = SetTimer(kTimerID, kTimerElapse); + if (_thread.Create(CThreadBenchmark::MyThreadFunction, &_threadBenchmark) != 0) + { + MyKillTimer(); + MessageBoxError_Status(L"Can't create thread"); + } + return; +} + + +void CBenchmarkDialog::RestartBenchmark() +{ + if (ExitWasAsked_in_GUI) + return; + + if (_thread.IsCreated()) + { + NeedRestart = true; + SendExit_Status(L"Stop for restart ..."); + } + else + StartBenchmark(); +} + + +void CBenchmarkDialog::Disable_Stop_Button() +{ + // if we disable focused button, then focus will be lost + if (GetFocus() == GetItem(IDB_STOP)) + { + // SendMsg_NextDlgCtl_Prev(); + SendMsg_NextDlgCtl_CtlId(IDB_RESTART); + } + EnableItem(IDB_STOP, false); +} + + +void CBenchmarkDialog::OnStopButton() +{ + if (ExitWasAsked_in_GUI) + return; + + Disable_Stop_Button(); + + WasStopped_in_GUI = true; + if (_thread.IsCreated()) + { + SendExit_Status(L"Stop ..."); + } +} + + + +void CBenchmarkDialog::OnCancel() +{ + ExitWasAsked_in_GUI = true; + + /* + SendMsg_NextDlgCtl_Prev(); + EnableItem(IDCANCEL, false); + */ + + if (_thread.IsCreated()) + SendExit_Status(L"Cancel ..."); + else + CModalDialog::OnCancel(); +} + + +void CBenchmarkDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + + + +// void GetTimeString(UInt64 timeValue, wchar_t *s); + +void CBenchmarkDialog::PrintTime() +{ + const UInt32 curTime = + _finishTime_WasSet ? + _finishTime : + ::GetTickCount(); + + const UInt32 elapsedTime = (curTime - _startTime); + + WCHAR s[64]; + + WCHAR *p = ConvertUInt32ToString(elapsedTime / 1000, s); + + if (_finishTime_WasSet) + { + *p++ = '.'; + UINT_TO_STR_3(p, elapsedTime % 1000) + } + + // p = NumberToDot3((UInt64)elapsedTime, s); + + MyStringCopy(p, L" s"); + + // if (WasStopped_in_GUI) wcscat(s, L" X"); // for debug + + if (s == ElapsedSec_Prev) + return; + + ElapsedSec_Prev = s; + + // static cnt = 0; cnt++; wcscat(s, L" "); + // UString s2; s2.Add_UInt32(cnt); wcscat(s, s2.Ptr()); + + SetItemText(IDT_BENCH_ELAPSED_VAL, s); +} + + +static UInt64 GetMips(UInt64 ips) +{ + return (ips + 500000) / 1000000; +} + + +static UInt64 GetUsagePercents(UInt64 usage) +{ + return Benchmark_GetUsage_Percents(usage); +} + + +static UInt32 GetRating(const CTotalBenchRes &info) +{ + UInt64 numIter = info.NumIterations2; + if (numIter == 0) + numIter = 1000000; + const UInt64 rating64 = GetMips(info.Rating / numIter); + // return rating64; + UInt32 rating32 = (UInt32)rating64; + if (rating32 != rating64) + rating32 = (UInt32)(Int32)-1; + return rating32; +} + + +static void AddUsageString(UString &s, const CTotalBenchRes &info) +{ + UInt64 numIter = info.NumIterations2; + if (numIter == 0) + numIter = 1000000; + UInt64 usage = GetUsagePercents(info.Usage / numIter); + + wchar_t w[64]; + ConvertUInt64ToString(usage, w); + unsigned len = MyStringLen(w); + while (len < 5) + { + s.Add_Space(); + len++; + } + s += w; + s += "%"; +} + + +static void Add_Dot3String(UString &s, UInt64 val) +{ + WCHAR temp[32]; + NumberToDot3(val, temp); + s += temp; +} + + +static void AddRatingString(UString &s, const CTotalBenchRes &info) +{ + // AddUsageString(s, info); + // s.Add_Space(); + // s.Add_UInt32(GetRating(info)); + Add_Dot3String(s, GetRating(info)); +} + + +static void AddRatingsLine(UString &s, const CTotalBenchRes &enc, const CTotalBenchRes &dec + #ifdef PRINT_ITER_TIME + , DWORD ticks + #endif + ) +{ + // AddUsageString(s, enc); s.Add_Space(); + + AddRatingString(s, enc); + s += " "; + AddRatingString(s, dec); + + CTotalBenchRes tot_BenchRes; + tot_BenchRes.SetSum(enc, dec); + + s += " "; + AddRatingString(s, tot_BenchRes); + + s.Add_Space(); AddUsageString(s, tot_BenchRes); + + + #ifdef PRINT_ITER_TIME + s.Add_Space(); + { + Add_Dot3String(s, ticks; + s += " s"; + // s.Add_UInt32(ticks); s += " ms"; + } + #endif +} + + +void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID) +{ + // SetItemText_Number(controlID, GetMips(rating), kMIPS); + WCHAR s[64]; + MyStringCopy(NumberToDot3(GetMips(rating), s), L" GIPS"); + SetItemText(controlID, s); +} + +void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID) +{ + SetItemText_Number(controlID, GetUsagePercents(usage), TEXT("%")); +} + + +// void SetItemText_Number + +void CBenchmarkDialog::PrintBenchRes( + const CTotalBenchRes2 &info, + const UINT ids[]) +{ + if (info.NumIterations2 == 0) + return; + if (ids[1] != 0) + SetItemText_Number(ids[1], (info.Speed >> 10) / info.NumIterations2, kKBs); + PrintRating(info.Rating / info.NumIterations2, ids[3]); + PrintRating(info.RPU / info.NumIterations2, ids[2]); + PrintUsage(info.Usage / info.NumIterations2, ids[0]); + if (ids[4] != 0) + { + UInt64 val = info.UnpackSize; + LPCTSTR kPostfix; + if (val >= ((UInt64)1 << 40)) + { + kPostfix = kGB; + val >>= 30; + } + else + { + kPostfix = kMB; + val >>= 20; + } + SetItemText_Number(ids[4], val, kPostfix); + } +} + + +// static UInt32 k_Message_Finished_cnt = 0; +// static UInt32 k_OnTimer_cnt = 0; + +bool CBenchmarkDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message != k_Message_Finished) + return CModalDialog::OnMessage(message, wParam, lParam); + + { + if (wParam == k_Msg_WPARM_Thread_Finished) + { + _finishTime = GetTickCount(); + _finishTime_WasSet = true; + MyKillTimer(); + + if (_thread.Wait_Close() != 0) + { + MessageBoxError_Status(L"Thread Wait Error"); + } + + if (!WasStopped_in_GUI) + { + WasStopped_in_GUI = true; + Disable_Stop_Button(); + } + + HRESULT res = Sync.BenchFinish_Thread_HRESULT; + if (res != S_OK) + // if (!ExitWasAsked_in_GUI || res != E_ABORT) + MessageBoxError_Status(HResultToMessage(res)); + + if (ExitWasAsked_in_GUI) + { + // SetItemText(IDT_BENCH_ERROR_MESSAGE, "before CModalDialog::OnCancel()"); + // Sleep (2000); + // MessageBoxError(L"test"); + CModalDialog::OnCancel(); + return true; + } + + SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); + + res = Sync.BenchFinish_Task_HRESULT; + if (res != S_OK) + { + if (!WasStopped_in_GUI || res != E_ABORT) + { + UString m; + if (res == S_FALSE) + m = "Decoding error"; + else if (res == CLASS_E_CLASSNOTAVAILABLE) + m = "Can't find 7z.dll"; + else + m = HResultToMessage(res); + MessageBoxError_Status(m); + } + } + + if (NeedRestart) + { + StartBenchmark(); + return true; + } + } + // k_Message_Finished_cnt++; + UpdateGui(); + return true; + } +} + + +bool CBenchmarkDialog::OnTimer(WPARAM timerID, LPARAM /* callback */) +{ + // k_OnTimer_cnt++; + if (timerID == kTimerID) + UpdateGui(); + return true; +} + + +void CBenchmarkDialog::UpdateGui() +{ + PrintTime(); + + if (TotalMode) + { + bool wasChanged = false; + { + NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); + + if (Sync.TextWasChanged) + { + wasChanged = true; + Bench2Text += Sync.Text; + Sync.Text.Empty(); + Sync.TextWasChanged = false; + } + } + if (wasChanged) + _consoleEdit.SetText(Bench2Text); + return; + } + + CSyncData sd; + CRecordVector RatingVector; + + { + NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); + sd = Sync.sd; + + if (sd.NeedPrint_RatingVector) + RatingVector = Sync.RatingVector; + + if (sd.NeedPrint_Freq) + { + Sync.FreqString_GUI = Sync.FreqString_Sync; + sd.NeedPrint_RatingVector = true; + } + + Sync.sd.NeedPrint_RatingVector = false; + Sync.sd.NeedPrint_Enc_1 = false; + Sync.sd.NeedPrint_Enc = false; + Sync.sd.NeedPrint_Dec_1 = false; + Sync.sd.NeedPrint_Dec = false; + Sync.sd.NeedPrint_Tot = false; + Sync.sd.NeedPrint_Freq = false; + } + + if (sd.NumPasses_Finished != NumPasses_Finished_Prev) + { + SetItemText_Number(IDT_BENCH_PASSES_VAL, sd.NumPasses_Finished, TEXT(" /")); + NumPasses_Finished_Prev = sd.NumPasses_Finished; + } + + if (sd.NeedPrint_Enc_1) PrintBenchRes(sd.Enc_BenchRes_1, k_Ids_Enc_1); + if (sd.NeedPrint_Enc) PrintBenchRes(sd.Enc_BenchRes, k_Ids_Enc); + if (sd.NeedPrint_Dec_1) PrintBenchRes(sd.Dec_BenchRes_1, k_Ids_Dec_1); + if (sd.NeedPrint_Dec) PrintBenchRes(sd.Dec_BenchRes, k_Ids_Dec); + + if (sd.BenchWasFinished && sd.NeedPrint_Tot) + { + CTotalBenchRes2 tot_BenchRes = sd.Enc_BenchRes; + tot_BenchRes.Update_With_Res2(sd.Dec_BenchRes); + PrintBenchRes(tot_BenchRes, k_Ids_Tot); + } + + + if (sd.NeedPrint_RatingVector) + // for (unsigned k = 0; k < 1; k++) + { + UString s; + s += Sync.FreqString_GUI; + if (!RatingVector.IsEmpty()) + { + if (!s.IsEmpty()) + s.Add_LF(); + s += "Compr Decompr Total CPU" + #ifdef PRINT_ITER_TIME + " Time" + #endif + ; + s.Add_LF(); + } + // s += "GIPS GIPS GIPS % s"; s.Add_LF(); + for (unsigned i = 0; i < RatingVector.Size(); i++) + { + if (i != 0) + s.Add_LF(); + if ((int)i == sd.RatingVector_DeletedIndex) + { + s += "..."; + s.Add_LF(); + } + const CBenchPassResult &pair = RatingVector[i]; + /* + s += "g:"; s.Add_UInt32((UInt32)pair.EncInfo.GlobalTime); + s += " u:"; s.Add_UInt32((UInt32)pair.EncInfo.UserTime); + s.Add_Space(); + */ + AddRatingsLine(s, pair.Enc, pair.Dec + #ifdef PRINT_ITER_TIME + , pair.Ticks + #endif + ); + /* + { + UInt64 v = i + 1; + if (sd.RatingVector_DeletedIndex >= 0 && i >= (unsigned)sd.RatingVector_DeletedIndex) + v += sd.RatingVector_NumDeleted; + char temp[64]; + ConvertUInt64ToString(v, temp); + s += " : "; + s += temp; + } + */ + } + + if (sd.BenchWasFinished) + { + s.Add_LF(); + s += "-------------"; + s.Add_LF(); + { + // average time is not correct because of freq detection in first iteration + AddRatingsLine(s, sd.Enc_BenchRes, sd.Dec_BenchRes + #ifdef PRINT_ITER_TIME + , (DWORD)(sd.TotalTicks / (sd.NumPasses_Finished ? sd.NumPasses_Finished : 1)) + #endif + ); + } + } + // s.Add_LF(); s += "OnTimer: "; s.Add_UInt32(k_OnTimer_cnt); + // s.Add_LF(); s += "finished Message: "; s.Add_UInt32(k_Message_Finished_cnt); + // static cnt = 0; cnt++; s.Add_LF(); s += "Print: "; s.Add_UInt32(cnt); + // s.Add_LF(); s += "NumEncProgress: "; s.Add_UInt32((UInt32)sd.NumEncProgress); + // s.Add_LF(); s += "NumDecProgress: "; s.Add_UInt32((UInt32)sd.NumDecProgress); + SetItemText(IDT_BENCH_LOG, s); + } +} + + +bool CBenchmarkDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE && + (itemID == IDC_BENCH_DICTIONARY || + itemID == IDC_BENCH_NUM_PASSES || + itemID == IDC_BENCH_NUM_THREADS)) + { + RestartBenchmark(); + return true; + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + + +bool CBenchmarkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_RESTART: + RestartBenchmark(); + return true; + case IDB_STOP: + OnStopButton(); + return true; + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + + + + + +// ---------- Benchmark Thread ---------- + +struct CBenchCallback Z7_final: public IBenchCallback +{ + UInt64 dictionarySize; + CBenchProgressSync *Sync; + CBenchmarkDialog *BenchmarkDialog; + + HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override; + HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override; +}; + +HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final) +{ + bool needPost = false; + { + NSynchronization::CCriticalSectionLock lock(Sync->CS); + if (Sync->Exit) + return E_ABORT; + CSyncData &sd = Sync->sd; + // sd.NumEncProgress++; + CTotalBenchRes2 &br = sd.Enc_BenchRes_1; + { + UInt64 dictSize = Sync->DictSize; + if (final) + { + // sd.EncInfo = info; + } + else + { + /* if (!final), then CBenchInfo::NumIterations means totalNumber of threads. + so we can reduce the dictionary */ + if (dictSize > info.UnpackSize) + dictSize = info.UnpackSize; + } + br.Rating = info.GetRating_LzmaEnc(dictSize); + } + br.SetFrom_BenchInfo(info); + sd.NeedPrint_Enc_1 = true; + if (final) + { + sd.Enc_BenchRes.Update_With_Res2(br); + sd.NeedPrint_Enc = true; + needPost = true; + } + } + + if (needPost) + BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + + return S_OK; +} + + +HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final) +{ + NSynchronization::CCriticalSectionLock lock(Sync->CS); + if (Sync->Exit) + return E_ABORT; + CSyncData &sd = Sync->sd; + // sd.NumDecProgress++; + CTotalBenchRes2 &br = sd.Dec_BenchRes_1; + br.Rating = info.GetRating_LzmaDec(); + br.SetFrom_BenchInfo(info); + sd.NeedPrint_Dec_1 = true; + if (final) + sd.Dec_BenchRes.Update_With_Res2(br); + return S_OK; +} + + +struct CBenchCallback2 Z7_final: public IBenchPrintCallback +{ + CBenchProgressSync *Sync; + bool TotalMode; + + void Print(const char *s) Z7_override; + void NewLine() Z7_override; + HRESULT CheckBreak() Z7_override; +}; + +void CBenchCallback2::Print(const char *s) +{ + if (TotalMode) + { + NSynchronization::CCriticalSectionLock lock(Sync->CS); + Sync->Text += s; + Sync->TextWasChanged = true; + } +} + +void CBenchCallback2::NewLine() +{ + Print("\xD\n"); +} + +HRESULT CBenchCallback2::CheckBreak() +{ + if (Sync->Exit) + return E_ABORT; + return S_OK; +} + + + +struct CFreqCallback Z7_final: public IBenchFreqCallback +{ + CBenchmarkDialog *BenchmarkDialog; + + virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) Z7_override; + virtual HRESULT FreqsFinished(unsigned numThreads) Z7_override; +}; + +HRESULT CFreqCallback::AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) +{ + HRESULT res; + { + CBenchProgressSync &sync = BenchmarkDialog->Sync; + NSynchronization::CCriticalSectionLock lock(sync.CS); + UString &s = sync.FreqString_Sync; + if (sync.NumFreqThreadsPrev != numThreads) + { + sync.NumFreqThreadsPrev = numThreads; + if (!s.IsEmpty()) + s.Add_LF(); + s.Add_UInt32(numThreads); + s += "T Frequency (MHz):"; + s.Add_LF(); + } + s.Add_Space(); + if (numThreads != 1) + { + s.Add_UInt64(GetUsagePercents(usage)); + s.Add_Char('%'); + s.Add_Space(); + } + s.Add_UInt64(GetMips(freq)); + // BenchmarkDialog->Sync.sd.NeedPrint_Freq = true; + res = sync.Exit ? E_ABORT : S_OK; + } + // BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + return res; +} + +HRESULT CFreqCallback::FreqsFinished(unsigned /* numThreads */) +{ + HRESULT res; + { + CBenchProgressSync &sync = BenchmarkDialog->Sync; + NSynchronization::CCriticalSectionLock lock(sync.CS); + sync.sd.NeedPrint_Freq = true; + BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + res = sync.Exit ? E_ABORT : S_OK; + } + BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + return res; +} + + + +// define USE_DUMMY only for debug +// #define USE_DUMMY +#ifdef USE_DUMMY +static unsigned dummy = 1; +static unsigned Dummy(unsigned limit) +{ + unsigned sum = 0; + for (unsigned k = 0; k < limit; k++) + { + sum += dummy; + if (sum == 0) + break; + } + return sum; +} +#endif + + +HRESULT CThreadBenchmark::Process() +{ + /* the first benchmark pass can be slow, + if we run benchmark while the window is being created, + and (no freq detecion loop) && (dictionary is small) (-mtic is small) */ + + // Sleep(300); // for debug + #ifdef USE_DUMMY + Dummy(1000 * 1000 * 1000); // for debug + #endif + + CBenchProgressSync &sync = BenchmarkDialog->Sync; + HRESULT finishHRESULT = S_OK; + + try + { + for (UInt32 passIndex = 0;; passIndex++) + { + // throw 1; // to debug + // throw CSystemException(E_INVALIDARG); // to debug + + UInt64 dictionarySize; + UInt32 numThreads; + { + NSynchronization::CCriticalSectionLock lock(sync.CS); + if (sync.Exit) + break; + dictionarySize = sync.DictSize; + numThreads = sync.NumThreads; + } + + #ifdef PRINT_ITER_TIME + const DWORD startTick = GetTickCount(); + #endif + + CBenchCallback callback; + + callback.dictionarySize = dictionarySize; + callback.Sync = &sync; + callback.BenchmarkDialog = BenchmarkDialog; + + CBenchCallback2 callback2; + callback2.TotalMode = BenchmarkDialog->TotalMode; + callback2.Sync = &sync; + + CFreqCallback freqCallback; + freqCallback.BenchmarkDialog = BenchmarkDialog; + + HRESULT result; + + try + { + CObjectVector props; + + props = BenchmarkDialog->Props; + + if (BenchmarkDialog->TotalMode) + { + props = BenchmarkDialog->Props; + } + else + { + { + CProperty prop; + prop.Name = "mt"; + prop.Value.Add_UInt32(numThreads); + props.Add(prop); + } + { + CProperty prop; + prop.Name = 'd'; + prop.Name.Add_UInt32((UInt32)(dictionarySize >> 10)); + prop.Name.Add_Char('k'); + props.Add(prop); + } + } + + result = Bench(EXTERNAL_CODECS_LOC_VARS + BenchmarkDialog->TotalMode ? &callback2 : NULL, + BenchmarkDialog->TotalMode ? NULL : &callback, + props, 1, false, + (!BenchmarkDialog->TotalMode) && passIndex == 0 ? &freqCallback: NULL); + + // result = S_FALSE; // for debug; + // throw 1; + } + catch(...) + { + result = E_FAIL; + } + + #ifdef PRINT_ITER_TIME + const DWORD numTicks = GetTickCount() - startTick; + #endif + + bool finished = true; + + NSynchronization::CCriticalSectionLock lock(sync.CS); + + if (result != S_OK) + { + sync.BenchFinish_Task_HRESULT = result; + break; + } + + { + CSyncData &sd = sync.sd; + + sd.NumPasses_Finished++; + #ifdef PRINT_ITER_TIME + sd.TotalTicks += numTicks; + #endif + + if (BenchmarkDialog->TotalMode) + break; + + { + CTotalBenchRes tot_BenchRes = sd.Enc_BenchRes_1; + tot_BenchRes.Update_With_Res(sd.Dec_BenchRes_1); + + sd.NeedPrint_RatingVector = true; + { + CBenchPassResult pair; + // pair.EncInfo = sd.EncInfo; // for debug + pair.Enc = sd.Enc_BenchRes_1; + pair.Dec = sd.Dec_BenchRes_1; + #ifdef PRINT_ITER_TIME + pair.Ticks = numTicks; + #endif + sync.RatingVector.Add(pair); + // pair.Dec_Defined = true; + } + } + + sd.NeedPrint_Dec = true; + sd.NeedPrint_Tot = true; + + if (sync.RatingVector.Size() > kRatingVector_NumBundlesMax) + { + // sd.RatingVector_NumDeleted++; + sd.RatingVector_DeletedIndex = (int)(kRatingVector_NumBundlesMax / 4); + sync.RatingVector.Delete((unsigned)(sd.RatingVector_DeletedIndex)); + } + + if (sync.sd.NumPasses_Finished < sync.NumPasses_Limit) + finished = false; + else + { + sync.sd.BenchWasFinished = true; + // BenchmarkDialog->_finishTime = GetTickCount(); + // return 0; + } + } + + if (BenchmarkDialog->TotalMode) + break; + + /* + if (newTick - prevTick < 1000) + numSameTick++; + if (numSameTick > 5 || finished) + { + prevTick = newTick; + numSameTick = 0; + */ + // for (unsigned i = 0; i < 1; i++) + { + // we suppose that PostMsg messages will be processed in order. + if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Iter_Finished)) + { + finished = true; + finishHRESULT = E_FAIL; + // throw 1234567; + } + } + if (finished) + break; + } + // return S_OK; + } + catch(CSystemException &e) + { + finishHRESULT = e.ErrorCode; + // BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode)); + // return E_FAIL; + } + catch(...) + { + finishHRESULT = E_FAIL; + // BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL)); + // return E_FAIL; + } + + if (finishHRESULT != S_OK) + { + NSynchronization::CCriticalSectionLock lock(sync.CS); + sync.BenchFinish_Thread_HRESULT = finishHRESULT; + } + if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Thread_Finished)) + { + // sync.BenchFinish_Thread_HRESULT = E_FAIL; + } + return 0; +} + + + +static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) +{ + const wchar_t *end; + UInt64 result = ConvertStringToUInt64(s, &end); + if (*end != 0 || s.IsEmpty()) + prop = s; + else if (result <= (UInt32)0xFFFFFFFF) + prop = (UInt32)result; + else + prop = result; +} + + +HRESULT Benchmark( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &props, UInt32 numIterations, HWND hwndParent) +{ + CBenchmarkDialog bd; + + bd.TotalMode = false; + bd.Props = props; + if (numIterations == 0) + numIterations = 1; + bd.Sync.NumPasses_Limit = numIterations; + bd.Sync.DictSize = (UInt64)(Int64)-1; + bd.Sync.NumThreads = (UInt32)(Int32)-1; + bd.Sync.Level = -1; + + COneMethodInfo method; + + UInt32 numCPUs = 1; + #ifndef Z7_ST + numCPUs = NSystem::GetNumberOfProcessors(); + #endif + UInt32 numThreads = numCPUs; + + FOR_VECTOR (i, props) + { + const CProperty &prop = props[i]; + UString name = prop.Name; + name.MakeLower_Ascii(); + if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*") + { + bd.TotalMode = true; + continue; + } + + NCOM::CPropVariant propVariant; + if (!prop.Value.IsEmpty()) + ParseNumberString(prop.Value, propVariant); + if (name.IsPrefixedBy(L"mt")) + { + #ifndef Z7_ST + RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads)) + if (numThreads != numCPUs) + bd.Sync.NumThreads = numThreads; + #endif + continue; + } + /* + if (name.IsEqualTo("time")) + { + // UInt32 testTime = 4; + // RINOK(ParsePropToUInt32(L"", propVariant, testTime)); + continue; + } + RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)); + */ + // here we need to parse DictSize property, and ignore unknown properties + method.ParseMethodFromPROPVARIANT(name, propVariant); + } + + if (bd.TotalMode) + { + // bd.Bench2Text.Empty(); + bd.Bench2Text = "7-Zip " MY_VERSION_CPU; + // bd.Bench2Text.Add_Char((char)0xD); + bd.Bench2Text.Add_LF(); + } + + { + UInt64 dict; + if (method.Get_DicSize(dict)) + bd.Sync.DictSize = dict; + } + bd.Sync.Level = (int)method.GetLevel(); + + // Dummy(1000 * 1000 * 1); + + { + CThreadBenchmark &benchmarker = bd._threadBenchmark; + #ifdef Z7_EXTERNAL_CODECS + benchmarker._externalCodecs = _externalCodecs; + #endif + benchmarker.BenchmarkDialog = &bd; + } + + bd.Create(hwndParent); + + return S_OK; +} + + +CBenchmarkDialog::~CBenchmarkDialog() +{ + if (_thread.IsCreated()) + { + /* the following code will be not executed in normal code flow. + it can be called, if there is some internal failure in dialog code. */ + Attach(NULL); + MessageBoxError(L"The flaw in benchmark thread code"); + Sync.SendExit(); + _thread.Wait_Close(); + } +} diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.h b/CPP/7zip/UI/GUI/BenchmarkDialog.h index 4638d21b8..63c6dedee 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.h +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.h @@ -1,15 +1,15 @@ -// BenchmarkDialog.h - -#ifndef ZIP7_INC_BENCHMARK_DIALOG_H -#define ZIP7_INC_BENCHMARK_DIALOG_H - -#include "../../Common/CreateCoder.h" -#include "../../UI/Common/Property.h" - -const UInt32 k_NumBenchIterations_Default = 10; - -HRESULT Benchmark( - DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector &props, UInt32 numIterations, HWND hwndParent = NULL); - -#endif +// BenchmarkDialog.h + +#ifndef ZIP7_INC_BENCHMARK_DIALOG_H +#define ZIP7_INC_BENCHMARK_DIALOG_H + +#include "../../Common/CreateCoder.h" +#include "../../UI/Common/Property.h" + +const UInt32 k_NumBenchIterations_Default = 10; + +HRESULT Benchmark( + DECL_EXTERNAL_CODECS_LOC_VARS + const CObjectVector &props, UInt32 numIterations, HWND hwndParent = NULL); + +#endif diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.rc b/CPP/7zip/UI/GUI/BenchmarkDialog.rc index cd78c3103..3e73e46d3 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.rc +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.rc @@ -1,288 +1,288 @@ -#include "BenchmarkDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 332 -#define yc 248 - -#undef g0xs -#undef g1x -#undef g1xs -#undef g2xs -#undef g3x -#undef g3xs -#undef g4x - -#define gs 160 -#define gSpace 24 - -#define g0xs 90 -#define g1xs 48 -#define g1x (m + g0xs) -#define gc2x (g1x + g1xs + m) -#define gc2xs 80 - -#define g4x (m + m) - -#define sRating 58 -#define sSpeed 60 -#define sUsage 46 -#define sRpu 58 -#define sSize 52 -// #define sFreq 34 - -#define xRating (xs - m - m - sRating) -#define xRpu (xRating - sRpu) -#define xUsage (xRpu - sUsage) -#define xSpeed (xUsage - sSpeed) -#define xSize (xSpeed - sSize) - -// #define xFreq (xUsage - sFreq) - -#define sLabel (xSize - g4x) -#define sTotalRating (sUsage + sRpu + sRating + m + m) -#define xTotalRating (xs - m - sTotalRating) - -#define sPasses 60 - -#define g2xs 60 -#define g3xs 64 -#define g3x (m + g2xs) - -#undef GROUP_Y_SIZE -#undef GROUP_Y2_SIZE -#ifdef UNDER_CE -#define GROUP_Y_SIZE 8 -#define GROUP_Y2_SIZE 8 -#else -#define GROUP_Y_SIZE 40 -#define GROUP_Y2_SIZE 32 -#endif - -#define g7xs bx1 - m - g0xs - g1xs - m - -#define sLog 140 + 0 - -// MY_MODAL_DIALOG_STYLE -IDD_BENCH DIALOG 0, 0, xs + sLog, ys MY_MODAL_RESIZE_DIALOG_STYLE | WS_MINIMIZEBOX -CAPTION "Benchmark" -MY_FONT -BEGIN - PUSHBUTTON "&Restart", IDB_RESTART, bx1, m, bxs, bys - PUSHBUTTON "&Stop", IDB_STOP, bx1, m + bys + 6, bxs, bys - - PUSHBUTTON "&Help", IDHELP, bx2, by, bxs, bys - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys - - LTEXT "&Dictionary size:", IDT_BENCH_DICTIONARY, m, m + 1, g0xs, 8 - COMBOBOX IDC_BENCH_DICTIONARY, g1x, m, g1xs, 140, MY_COMBO - - LTEXT "Memory usage:", IDT_BENCH_MEMORY, gc2x, m - 2, g7xs, 8 - LTEXT "", IDT_BENCH_MEMORY_VAL, gc2x, m + 8, g7xs, MY_TEXT_NOPREFIX - - LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8 - COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO - LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, MY_TEXT_NOPREFIX - - RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX - RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX - RTEXT "Speed", IDT_BENCH_SPEED, xSpeed, 54, sSpeed, MY_TEXT_NOPREFIX - RTEXT "Rating / Usage", IDT_BENCH_RPU_LABEL, xRpu, 54, sRpu, MY_TEXT_NOPREFIX - RTEXT "Rating", IDT_BENCH_RATING_LABEL, xRating, 54, sRating, MY_TEXT_NOPREFIX - - GROUPBOX "Compressing", IDG_BENCH_COMPRESSING, m, 64, xc, GROUP_Y_SIZE - - LTEXT "Current", IDT_BENCH_CURRENT, g4x, 76, sLabel, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_SIZE1, xSize, 76, sSize, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 76, sUsage, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_SPEED1, xSpeed, 76, sSpeed, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 76, sRpu, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 76, sRating, MY_TEXT_NOPREFIX - - LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 89, sLabel, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_SIZE2, xSize, 89, sSize, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 89, sUsage, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_SPEED2, xSpeed, 89, sSpeed, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 89, sRpu, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 89, sRating, MY_TEXT_NOPREFIX - - GROUPBOX "Decompressing", IDG_BENCH_DECOMPRESSING, m, 111, xc, GROUP_Y_SIZE - - LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 123, sLabel, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_SIZE1, xSize, 123, sSize, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 123, sUsage, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_SPEED1, xSpeed, 123, sSpeed, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 123, sRpu, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 123, sRating, MY_TEXT_NOPREFIX - - LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 136, sLabel, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_SIZE2, xSize, 136, sSize, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 136, sUsage, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_SPEED2, xSpeed, 136, sSpeed, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 136, sRpu, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 136, sRating, MY_TEXT_NOPREFIX - - RTEXT "", IDT_BENCH_ERROR_MESSAGE, m, 155, xc, MY_TEXT_NOPREFIX - - GROUPBOX "Total Rating", IDG_BENCH_TOTAL_RATING, xTotalRating, 163, sTotalRating, GROUP_Y2_SIZE - - RTEXT "", IDT_BENCH_TOTAL_USAGE_VAL, xUsage, 176, sUsage, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 176, sRpu, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 176, sRating, MY_TEXT_NOPREFIX - - - // RTEXT "", IDT_BENCH_CPU, m + sPasses, 202, xc - sPasses, 16, SS_NOPREFIX - RTEXT "", IDT_BENCH_CPU, m + 0, 202, xc - 0, 16, SS_NOPREFIX - RTEXT "", IDT_BENCH_VER, m + xc - 100, 222, 100, MY_TEXT_NOPREFIX - - LTEXT "", IDT_BENCH_CPU_FEATURE, m, 222, xc - 100, 16, SS_NOPREFIX // - 100 - LTEXT "", IDT_BENCH_SYS1, m, 238, xc - 140, MY_TEXT_NOPREFIX - LTEXT "", IDT_BENCH_SYS2, m, 248, xc - 140, MY_TEXT_NOPREFIX - - LTEXT "", IDT_BENCH_LOG, m + xc + m, m, sLog - m, yc, SS_LEFTNOWORDWRAP | SS_NOPREFIX - - - LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, 163, g2xs, 8 -// LTEXT "Size:", IDT_BENCH_SIZE, m, 176, g2xs, 8 - LTEXT "Passes:", IDT_BENCH_PASSES, m, 176, g2xs, 8 - COMBOBOX IDC_BENCH_NUM_PASSES, m, 187, sPasses, 140, MY_COMBO - - RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 163, g3xs, MY_TEXT_NOPREFIX - // RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 176, g3xs, MY_TEXT_NOPREFIX - RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 176, g3xs, MY_TEXT_NOPREFIX - -END - -#ifdef UNDER_CE - -#undef m -#define m 4 - -#undef xc -#undef yc - -#define xc 154 -#define yc 160 - -#undef g0xs -#undef g1x -#undef g1xs -#undef g2xs -#undef g3x -#undef g3xs - -#undef bxs -#undef bys - -#define bxs 60 -#define bys 14 - -#undef gs -#undef gSpace - -#define gs 160 -#define gSpace 24 - -#define g0xs (xc - bxs) -#define g1xs 44 - -#undef g4x -#define g4x (m) - -#undef xRpu -#undef xUsage -#undef xRating -#undef xTotalRating - -#undef sRpu -#undef sRating -#undef sUsage -#undef sLabel -#undef sTotalRating - -#define sRating 40 -#define sUsage 24 -#define sRpu 40 - -#define xRating (xs - m - sRating) -#define xRpu (xRating - sRpu) -#define xUsage (xRpu - sUsage) - -#define sLabel (xUsage - g4x) -#define sTotalRating (sRpu + sRating) -#define xTotalRating (xs - m - sTotalRating) - -#define g3xs 32 -#define g3x (xRpu - g3xs) -#define g2xs (g3x - m) - - -IDD_BENCH_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX -CAPTION "Benchmark" -MY_FONT -BEGIN - PUSHBUTTON "&Restart", IDB_RESTART, bx1, m, bxs, bys - PUSHBUTTON "&Stop", IDB_STOP, bx1, m + bys + m, bxs, bys - - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys - - LTEXT "&Dictionary size:", IDT_BENCH_DICTIONARY, m, m, g0xs, 8 - COMBOBOX IDC_BENCH_DICTIONARY, m, m + 11, g1xs, 140, MY_COMBO - - LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 31, g0xs, 8 - COMBOBOX IDC_BENCH_NUM_THREADS, m, 42, g1xs, 140, MY_COMBO - - LTEXT "", IDT_BENCH_MEMORY_VAL, m + g1xs + 8, m + 13, xc - bxs - g1xs - 8, 8 - LTEXT "", IDT_BENCH_HARDWARE_THREADS, m + g1xs + 8, 44, xc - bxs - g1xs - 8, 8 - - LTEXT "Current", IDT_BENCH_CURRENT, g4x, 70, sLabel, 8 - RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 70, sUsage, 8 - RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 70, sRpu, 8 - RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 70, sRating, 8 - - LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 80, sLabel, 8 - RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 80, sUsage, 8 - RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 80, sRpu, 8 - RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 80, sRating, 8 - - LTEXT "Compressing", IDG_BENCH_COMPRESSING, m, 60, xc - bxs, 8 - - LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 104, sLabel, 8 - RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 104, sUsage, 8 - RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 104, sRpu, 8 - RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 104, sRating, 8 - - LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 114, sLabel, 8 - RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 114, sUsage, 8 - RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 114, sRpu, 8 - RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 114, sRating, 8 - - LTEXT "Decompressing", IDG_BENCH_DECOMPRESSING, m, 94, xc, 8 - - RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 140, sRpu, 8 - RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 140, sRating, 8 - - LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, 130, g2xs, 8 - LTEXT "Size:", IDT_BENCH_SIZE, m, 140, g2xs, 8 - LTEXT "Passes:", IDT_BENCH_PASSES, m, 150, g2xs, 8 - - RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 130, g3xs, 8 - RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 140, g3xs, 8 - RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 150, g3xs, 8 -END - -#endif - -#include "../../GuiCommon.rc" - -#define xc 360 -#define yc 260 - -IDD_BENCH_TOTAL DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT -CAPTION "Benchmark" -{ - LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, m, 58, 8 - RTEXT "", IDT_BENCH_ELAPSED_VAL, m + 58, m, 38, 8 - EDITTEXT IDE_BENCH2_EDIT, m, m + 14, xc, yc - bys - m - 14, ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL | WS_HSCROLL - PUSHBUTTON "&Help", IDHELP, bx2, by, bxs, bys - PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys -} +#include "BenchmarkDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 332 +#define yc 248 + +#undef g0xs +#undef g1x +#undef g1xs +#undef g2xs +#undef g3x +#undef g3xs +#undef g4x + +#define gs 160 +#define gSpace 24 + +#define g0xs 90 +#define g1xs 48 +#define g1x (m + g0xs) +#define gc2x (g1x + g1xs + m) +#define gc2xs 80 + +#define g4x (m + m) + +#define sRating 58 +#define sSpeed 60 +#define sUsage 46 +#define sRpu 58 +#define sSize 52 +// #define sFreq 34 + +#define xRating (xs - m - m - sRating) +#define xRpu (xRating - sRpu) +#define xUsage (xRpu - sUsage) +#define xSpeed (xUsage - sSpeed) +#define xSize (xSpeed - sSize) + +// #define xFreq (xUsage - sFreq) + +#define sLabel (xSize - g4x) +#define sTotalRating (sUsage + sRpu + sRating + m + m) +#define xTotalRating (xs - m - sTotalRating) + +#define sPasses 60 + +#define g2xs 60 +#define g3xs 64 +#define g3x (m + g2xs) + +#undef GROUP_Y_SIZE +#undef GROUP_Y2_SIZE +#ifdef UNDER_CE +#define GROUP_Y_SIZE 8 +#define GROUP_Y2_SIZE 8 +#else +#define GROUP_Y_SIZE 40 +#define GROUP_Y2_SIZE 32 +#endif + +#define g7xs bx1 - m - g0xs - g1xs - m + +#define sLog 140 + 0 + +// MY_MODAL_DIALOG_STYLE +IDD_BENCH DIALOG 0, 0, xs + sLog, ys MY_MODAL_RESIZE_DIALOG_STYLE | WS_MINIMIZEBOX +CAPTION "Benchmark" +MY_FONT +BEGIN + PUSHBUTTON "&Restart", IDB_RESTART, bx1, m, bxs, bys + PUSHBUTTON "&Stop", IDB_STOP, bx1, m + bys + 6, bxs, bys + + PUSHBUTTON "&Help", IDHELP, bx2, by, bxs, bys + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys + + LTEXT "&Dictionary size:", IDT_BENCH_DICTIONARY, m, m + 1, g0xs, 8 + COMBOBOX IDC_BENCH_DICTIONARY, g1x, m, g1xs, 140, MY_COMBO + + LTEXT "Memory usage:", IDT_BENCH_MEMORY, gc2x, m - 2, g7xs, 8 + LTEXT "", IDT_BENCH_MEMORY_VAL, gc2x, m + 8, g7xs, MY_TEXT_NOPREFIX + + LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8 + COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO + LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, MY_TEXT_NOPREFIX + + RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX + RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX + RTEXT "Speed", IDT_BENCH_SPEED, xSpeed, 54, sSpeed, MY_TEXT_NOPREFIX + RTEXT "Rating / Usage", IDT_BENCH_RPU_LABEL, xRpu, 54, sRpu, MY_TEXT_NOPREFIX + RTEXT "Rating", IDT_BENCH_RATING_LABEL, xRating, 54, sRating, MY_TEXT_NOPREFIX + + GROUPBOX "Compressing", IDG_BENCH_COMPRESSING, m, 64, xc, GROUP_Y_SIZE + + LTEXT "Current", IDT_BENCH_CURRENT, g4x, 76, sLabel, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_SIZE1, xSize, 76, sSize, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 76, sUsage, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_SPEED1, xSpeed, 76, sSpeed, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 76, sRpu, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 76, sRating, MY_TEXT_NOPREFIX + + LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 89, sLabel, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_SIZE2, xSize, 89, sSize, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 89, sUsage, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_SPEED2, xSpeed, 89, sSpeed, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 89, sRpu, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 89, sRating, MY_TEXT_NOPREFIX + + GROUPBOX "Decompressing", IDG_BENCH_DECOMPRESSING, m, 111, xc, GROUP_Y_SIZE + + LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 123, sLabel, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_SIZE1, xSize, 123, sSize, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 123, sUsage, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_SPEED1, xSpeed, 123, sSpeed, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 123, sRpu, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 123, sRating, MY_TEXT_NOPREFIX + + LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 136, sLabel, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_SIZE2, xSize, 136, sSize, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 136, sUsage, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_SPEED2, xSpeed, 136, sSpeed, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 136, sRpu, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 136, sRating, MY_TEXT_NOPREFIX + + RTEXT "", IDT_BENCH_ERROR_MESSAGE, m, 155, xc, MY_TEXT_NOPREFIX + + GROUPBOX "Total Rating", IDG_BENCH_TOTAL_RATING, xTotalRating, 163, sTotalRating, GROUP_Y2_SIZE + + RTEXT "", IDT_BENCH_TOTAL_USAGE_VAL, xUsage, 176, sUsage, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 176, sRpu, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 176, sRating, MY_TEXT_NOPREFIX + + + // RTEXT "", IDT_BENCH_CPU, m + sPasses, 202, xc - sPasses, 16, SS_NOPREFIX + RTEXT "", IDT_BENCH_CPU, m + 0, 202, xc - 0, 16, SS_NOPREFIX + RTEXT "", IDT_BENCH_VER, m + xc - 100, 222, 100, MY_TEXT_NOPREFIX + + LTEXT "", IDT_BENCH_CPU_FEATURE, m, 222, xc - 100, 16, SS_NOPREFIX // - 100 + LTEXT "", IDT_BENCH_SYS1, m, 238, xc - 140, MY_TEXT_NOPREFIX + LTEXT "", IDT_BENCH_SYS2, m, 248, xc - 140, MY_TEXT_NOPREFIX + + LTEXT "", IDT_BENCH_LOG, m + xc + m, m, sLog - m, yc, SS_LEFTNOWORDWRAP | SS_NOPREFIX + + + LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, 163, g2xs, 8 +// LTEXT "Size:", IDT_BENCH_SIZE, m, 176, g2xs, 8 + LTEXT "Passes:", IDT_BENCH_PASSES, m, 176, g2xs, 8 + COMBOBOX IDC_BENCH_NUM_PASSES, m, 187, sPasses, 140, MY_COMBO + + RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 163, g3xs, MY_TEXT_NOPREFIX + // RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 176, g3xs, MY_TEXT_NOPREFIX + RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 176, g3xs, MY_TEXT_NOPREFIX + +END + +#ifdef UNDER_CE + +#undef m +#define m 4 + +#undef xc +#undef yc + +#define xc 154 +#define yc 160 + +#undef g0xs +#undef g1x +#undef g1xs +#undef g2xs +#undef g3x +#undef g3xs + +#undef bxs +#undef bys + +#define bxs 60 +#define bys 14 + +#undef gs +#undef gSpace + +#define gs 160 +#define gSpace 24 + +#define g0xs (xc - bxs) +#define g1xs 44 + +#undef g4x +#define g4x (m) + +#undef xRpu +#undef xUsage +#undef xRating +#undef xTotalRating + +#undef sRpu +#undef sRating +#undef sUsage +#undef sLabel +#undef sTotalRating + +#define sRating 40 +#define sUsage 24 +#define sRpu 40 + +#define xRating (xs - m - sRating) +#define xRpu (xRating - sRpu) +#define xUsage (xRpu - sUsage) + +#define sLabel (xUsage - g4x) +#define sTotalRating (sRpu + sRating) +#define xTotalRating (xs - m - sTotalRating) + +#define g3xs 32 +#define g3x (xRpu - g3xs) +#define g2xs (g3x - m) + + +IDD_BENCH_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX +CAPTION "Benchmark" +MY_FONT +BEGIN + PUSHBUTTON "&Restart", IDB_RESTART, bx1, m, bxs, bys + PUSHBUTTON "&Stop", IDB_STOP, bx1, m + bys + m, bxs, bys + + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys + + LTEXT "&Dictionary size:", IDT_BENCH_DICTIONARY, m, m, g0xs, 8 + COMBOBOX IDC_BENCH_DICTIONARY, m, m + 11, g1xs, 140, MY_COMBO + + LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 31, g0xs, 8 + COMBOBOX IDC_BENCH_NUM_THREADS, m, 42, g1xs, 140, MY_COMBO + + LTEXT "", IDT_BENCH_MEMORY_VAL, m + g1xs + 8, m + 13, xc - bxs - g1xs - 8, 8 + LTEXT "", IDT_BENCH_HARDWARE_THREADS, m + g1xs + 8, 44, xc - bxs - g1xs - 8, 8 + + LTEXT "Current", IDT_BENCH_CURRENT, g4x, 70, sLabel, 8 + RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 70, sUsage, 8 + RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 70, sRpu, 8 + RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 70, sRating, 8 + + LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 80, sLabel, 8 + RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 80, sUsage, 8 + RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 80, sRpu, 8 + RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 80, sRating, 8 + + LTEXT "Compressing", IDG_BENCH_COMPRESSING, m, 60, xc - bxs, 8 + + LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 104, sLabel, 8 + RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 104, sUsage, 8 + RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 104, sRpu, 8 + RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 104, sRating, 8 + + LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 114, sLabel, 8 + RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 114, sUsage, 8 + RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 114, sRpu, 8 + RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 114, sRating, 8 + + LTEXT "Decompressing", IDG_BENCH_DECOMPRESSING, m, 94, xc, 8 + + RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 140, sRpu, 8 + RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 140, sRating, 8 + + LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, 130, g2xs, 8 + LTEXT "Size:", IDT_BENCH_SIZE, m, 140, g2xs, 8 + LTEXT "Passes:", IDT_BENCH_PASSES, m, 150, g2xs, 8 + + RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 130, g3xs, 8 + RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 140, g3xs, 8 + RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 150, g3xs, 8 +END + +#endif + +#include "../../GuiCommon.rc" + +#define xc 360 +#define yc 260 + +IDD_BENCH_TOTAL DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT +CAPTION "Benchmark" +{ + LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, m, 58, 8 + RTEXT "", IDT_BENCH_ELAPSED_VAL, m + 58, m, 38, 8 + EDITTEXT IDE_BENCH2_EDIT, m, m + 14, xc, yc - bys - m - 14, ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL | WS_HSCROLL + PUSHBUTTON "&Help", IDHELP, bx2, by, bxs, bys + PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys +} diff --git a/CPP/7zip/UI/GUI/BenchmarkDialogRes.h b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h index aa3846afa..b7d54b779 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialogRes.h +++ b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h @@ -1,79 +1,79 @@ -#define IDD_BENCH 7600 -#define IDD_BENCH_2 17600 -#define IDD_BENCH_TOTAL 7699 - -#define IDE_BENCH2_EDIT 100 - -#define IDC_BENCH_DICTIONARY 101 -#define IDT_BENCH_MEMORY_VAL 102 -#define IDC_BENCH_NUM_THREADS 103 -#define IDT_BENCH_HARDWARE_THREADS 104 - -#define IDT_BENCH_VER 105 -#define IDT_BENCH_CPU 106 -#define IDT_BENCH_SYS1 107 -#define IDT_BENCH_SYS2 108 -#define IDT_BENCH_CPU_FEATURE 109 - -#define IDT_BENCH_COMPRESS_SPEED1 110 -#define IDT_BENCH_COMPRESS_SPEED2 111 -#define IDT_BENCH_COMPRESS_RATING1 112 -#define IDT_BENCH_COMPRESS_RATING2 113 -#define IDT_BENCH_COMPRESS_USAGE1 114 -#define IDT_BENCH_COMPRESS_USAGE2 115 -#define IDT_BENCH_COMPRESS_RPU1 116 -#define IDT_BENCH_COMPRESS_RPU2 117 - -#define IDT_BENCH_DECOMPR_SPEED1 118 -#define IDT_BENCH_DECOMPR_SPEED2 119 -#define IDT_BENCH_DECOMPR_RATING1 120 -#define IDT_BENCH_DECOMPR_RATING2 121 -#define IDT_BENCH_DECOMPR_USAGE1 122 -#define IDT_BENCH_DECOMPR_USAGE2 123 -#define IDT_BENCH_DECOMPR_RPU1 124 -#define IDT_BENCH_DECOMPR_RPU2 125 - -#define IDT_BENCH_TOTAL_RATING_VAL 130 -#define IDT_BENCH_TOTAL_RPU_VAL 131 -#define IDT_BENCH_TOTAL_USAGE_VAL 133 - -#define IDT_BENCH_ELAPSED_VAL 140 -// #define IDT_BENCH_SIZE_VAL 141 -#define IDT_BENCH_PASSES_VAL 142 -#define IDC_BENCH_NUM_PASSES 143 - -#define IDT_BENCH_LOG 160 -#define IDT_BENCH_ERROR_MESSAGE 161 - -#define IDT_BENCH_COMPRESS_SIZE1 170 -#define IDT_BENCH_COMPRESS_SIZE2 171 -#define IDT_BENCH_DECOMPR_SIZE1 172 -#define IDT_BENCH_DECOMPR_SIZE2 173 - -// #define IDT_BENCH_FREQ_CUR 150 -// #define IDT_BENCH_FREQ_RES 151 - -#define IDB_STOP 442 -#define IDB_RESTART 443 - -#define IDT_BENCH_DICTIONARY 4006 -#define IDT_BENCH_NUM_THREADS 4009 - -#define IDT_BENCH_SIZE 1007 -#define IDT_BENCH_ELAPSED 3900 -#define IDT_BENCH_SPEED 3903 - -#define IDT_BENCH_MEMORY 7601 - -#define IDG_BENCH_COMPRESSING 7602 -#define IDG_BENCH_DECOMPRESSING 7603 -#define IDG_BENCH_TOTAL_RATING 7605 - -#define IDT_BENCH_RATING_LABEL 7604 -#define IDT_BENCH_CURRENT 7606 -#define IDT_BENCH_RESULTING 7607 -#define IDT_BENCH_USAGE_LABEL 7608 -#define IDT_BENCH_RPU_LABEL 7609 -#define IDT_BENCH_PASSES 7610 -#define IDT_BENCH_CURRENT2 (7606+50) -#define IDT_BENCH_RESULTING2 (7607+50) +#define IDD_BENCH 7600 +#define IDD_BENCH_2 17600 +#define IDD_BENCH_TOTAL 7699 + +#define IDE_BENCH2_EDIT 100 + +#define IDC_BENCH_DICTIONARY 101 +#define IDT_BENCH_MEMORY_VAL 102 +#define IDC_BENCH_NUM_THREADS 103 +#define IDT_BENCH_HARDWARE_THREADS 104 + +#define IDT_BENCH_VER 105 +#define IDT_BENCH_CPU 106 +#define IDT_BENCH_SYS1 107 +#define IDT_BENCH_SYS2 108 +#define IDT_BENCH_CPU_FEATURE 109 + +#define IDT_BENCH_COMPRESS_SPEED1 110 +#define IDT_BENCH_COMPRESS_SPEED2 111 +#define IDT_BENCH_COMPRESS_RATING1 112 +#define IDT_BENCH_COMPRESS_RATING2 113 +#define IDT_BENCH_COMPRESS_USAGE1 114 +#define IDT_BENCH_COMPRESS_USAGE2 115 +#define IDT_BENCH_COMPRESS_RPU1 116 +#define IDT_BENCH_COMPRESS_RPU2 117 + +#define IDT_BENCH_DECOMPR_SPEED1 118 +#define IDT_BENCH_DECOMPR_SPEED2 119 +#define IDT_BENCH_DECOMPR_RATING1 120 +#define IDT_BENCH_DECOMPR_RATING2 121 +#define IDT_BENCH_DECOMPR_USAGE1 122 +#define IDT_BENCH_DECOMPR_USAGE2 123 +#define IDT_BENCH_DECOMPR_RPU1 124 +#define IDT_BENCH_DECOMPR_RPU2 125 + +#define IDT_BENCH_TOTAL_RATING_VAL 130 +#define IDT_BENCH_TOTAL_RPU_VAL 131 +#define IDT_BENCH_TOTAL_USAGE_VAL 133 + +#define IDT_BENCH_ELAPSED_VAL 140 +// #define IDT_BENCH_SIZE_VAL 141 +#define IDT_BENCH_PASSES_VAL 142 +#define IDC_BENCH_NUM_PASSES 143 + +#define IDT_BENCH_LOG 160 +#define IDT_BENCH_ERROR_MESSAGE 161 + +#define IDT_BENCH_COMPRESS_SIZE1 170 +#define IDT_BENCH_COMPRESS_SIZE2 171 +#define IDT_BENCH_DECOMPR_SIZE1 172 +#define IDT_BENCH_DECOMPR_SIZE2 173 + +// #define IDT_BENCH_FREQ_CUR 150 +// #define IDT_BENCH_FREQ_RES 151 + +#define IDB_STOP 442 +#define IDB_RESTART 443 + +#define IDT_BENCH_DICTIONARY 4006 +#define IDT_BENCH_NUM_THREADS 4009 + +#define IDT_BENCH_SIZE 1007 +#define IDT_BENCH_ELAPSED 3900 +#define IDT_BENCH_SPEED 3903 + +#define IDT_BENCH_MEMORY 7601 + +#define IDG_BENCH_COMPRESSING 7602 +#define IDG_BENCH_DECOMPRESSING 7603 +#define IDG_BENCH_TOTAL_RATING 7605 + +#define IDT_BENCH_RATING_LABEL 7604 +#define IDT_BENCH_CURRENT 7606 +#define IDT_BENCH_RESULTING 7607 +#define IDT_BENCH_USAGE_LABEL 7608 +#define IDT_BENCH_RPU_LABEL 7609 +#define IDT_BENCH_PASSES 7610 +#define IDT_BENCH_CURRENT2 (7606+50) +#define IDT_BENCH_RESULTING2 (7607+50) diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 80d4e991e..58f863e8e 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -1,3820 +1,3829 @@ -// CompressDialog.cpp - -#include "StdAfx.h" - -#include "../../../../C/CpuArch.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/System.h" - -#include "../../Common/MethodProps.h" - -#include "../FileManager/BrowseDialog.h" -#include "../FileManager/FormatUtils.h" -#include "../FileManager/HelpUtils.h" -#include "../FileManager/PropertyName.h" -#include "../FileManager/SplitUtils.h" -#include "../FileManager/resourceGui.h" - -#include "../Explorer/MyMessages.h" - -#include "../Common/ZipRegistry.h" - -#include "CompressDialog.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -#include "../FileManager/LangUtils.h" - -#include "CompressDialogRes.h" -#include "ExtractRes.h" -#include "resource2.h" - -// #define PRINT_PARAMS - -#ifdef Z7_LANG - -// #define IDS_OPTIONS 2100 - -static const UInt32 kLangIDs[] = -{ - IDT_COMPRESS_ARCHIVE, - IDT_COMPRESS_UPDATE_MODE, - IDT_COMPRESS_FORMAT, - IDT_COMPRESS_LEVEL, - IDT_COMPRESS_METHOD, - IDT_COMPRESS_DICTIONARY, - IDT_COMPRESS_ORDER, - IDT_COMPRESS_SOLID, - IDT_COMPRESS_THREADS, - IDT_COMPRESS_PARAMETERS, - - IDB_COMPRESS_OPTIONS, // IDS_OPTIONS - - IDG_COMPRESS_OPTIONS, - IDX_COMPRESS_SFX, - IDX_COMPRESS_SHARED, - IDX_COMPRESS_DEL, - - IDT_COMPRESS_MEMORY, - IDT_COMPRESS_MEMORY_DE, - - IDG_COMPRESS_ENCRYPTION, - IDT_COMPRESS_ENCRYPTION_METHOD, - IDX_COMPRESS_ENCRYPT_FILE_NAMES, - - IDT_PASSWORD_ENTER, - IDT_PASSWORD_REENTER, - IDX_PASSWORD_SHOW, - - IDT_SPLIT_TO_VOLUMES, - IDT_COMPRESS_PATH_MODE, -}; -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NName; -using namespace NDir; - -static const unsigned kHistorySize = 20; - -static const UInt32 kSolidLog_NoSolid = 0; -static const UInt32 kSolidLog_FullSolid = 64; - -static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28; - -static const UINT k_Message_ArcChanged = WM_APP + 1; - -/* -static const UInt32 kZstd_MAX_DictSize = (UInt32)1 << MY_ZSTD_WINDOWLOG_MAX; -*/ - -/* The top value for windowLog_Chain: - (MY_ZSTD_CHAINLOG_MAX - 1): in BT mode - (MY_ZSTD_CHAINLOG_MAX) : in non-BT mode. But such big value is useless in most cases. - So we always reduce top value to (MY_ZSTD_CHAINLOG_MAX - 1) */ -/* -static const unsigned kMaxDictChain = MY_ZSTD_CHAINLOG_MAX - 1; -static const UInt32 kZstd_MAX_DictSize_Chain = (UInt32)1 << kMaxDictChain; -*/ - -static LPCSTR const kExeExt = ".exe"; - -static const UInt32 g_Levels[] = -{ - IDS_METHOD_STORE, - IDS_METHOD_FASTEST, - 0, - IDS_METHOD_FAST, - 0, - IDS_METHOD_NORMAL, - 0, - IDS_METHOD_MAXIMUM, - 0, - IDS_METHOD_ULTRA -}; - -enum EMethodID -{ - kCopy, - kLZMA, - kLZMA2, - kPPMd, - kBZip2, - kDeflate, - kDeflate64, - kPPMdZip, - // kZSTD, - kSha256, - kSha1, - kCrc32, - kCrc64, - kGnu, - kPosix -}; - -static LPCSTR const kMethodsNames[] = -{ - "Copy" - , "LZMA" - , "LZMA2" - , "PPMd" - , "BZip2" - , "Deflate" - , "Deflate64" - , "PPMd" - // , "ZSTD" - , "SHA256" - , "SHA1" - , "CRC32" - , "CRC64" - , "GNU" - , "POSIX" -}; - -static const EMethodID g_7zMethods[] = -{ - kLZMA2, - kLZMA, - kPPMd, - kBZip2 - , kDeflate - , kDeflate64 - // , kZSTD - , kCopy -}; - -static const EMethodID g_7zSfxMethods[] = -{ - kCopy, - kLZMA, - kLZMA2, - kPPMd -}; - -static const EMethodID g_ZipMethods[] = -{ - kDeflate, - kDeflate64, - kBZip2, - kLZMA, - kPPMdZip - // , kZSTD -}; - -static const EMethodID g_GZipMethods[] = -{ - kDeflate -}; - -static const EMethodID g_BZip2Methods[] = -{ - kBZip2 -}; - -static const EMethodID g_XzMethods[] = -{ - kLZMA2 -}; - -/* -static const EMethodID g_ZstdMethods[] = -{ - kZSTD -}; -*/ - -static const EMethodID g_SwfcMethods[] = -{ - kDeflate - // kLZMA -}; - -static const EMethodID g_TarMethods[] = -{ - kGnu, - kPosix -}; - -static const EMethodID g_HashMethods[] = -{ - kSha256 - , kSha1 - // , kCrc32 - // , kCrc64 -}; - -static const UInt32 kFF_Filter = 1 << 0; -static const UInt32 kFF_Solid = 1 << 1; -static const UInt32 kFF_MultiThread = 1 << 2; -static const UInt32 kFF_Encrypt = 1 << 3; -static const UInt32 kFF_EncryptFileNames = 1 << 4; -static const UInt32 kFF_MemUse = 1 << 5; -static const UInt32 kFF_SFX = 1 << 6; - -/* -static const UInt32 kFF_Time_Win = 1 << 10; -static const UInt32 kFF_Time_Unix = 1 << 11; -static const UInt32 kFF_Time_DOS = 1 << 12; -static const UInt32 kFF_Time_1ns = 1 << 13; -*/ - -struct CFormatInfo -{ - LPCSTR Name; - UInt32 LevelsMask; - unsigned NumMethods; - const EMethodID *MethodIDs; - - UInt32 Flags; - - bool Filter_() const { return (Flags & kFF_Filter) != 0; } - bool Solid_() const { return (Flags & kFF_Solid) != 0; } - bool MultiThread_() const { return (Flags & kFF_MultiThread) != 0; } - bool Encrypt_() const { return (Flags & kFF_Encrypt) != 0; } - bool EncryptFileNames_() const { return (Flags & kFF_EncryptFileNames) != 0; } - bool MemUse_() const { return (Flags & kFF_MemUse) != 0; } - bool SFX_() const { return (Flags & kFF_SFX) != 0; } -}; - -#define METHODS_PAIR(x) Z7_ARRAY_SIZE(x), x - -static const CFormatInfo g_Formats[] = -{ - { - "", - // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - ((UInt32)1 << 10) - 1, - // (UInt32)(Int32)-1, - 0, NULL, - kFF_MultiThread | kFF_MemUse - }, - { - "7z", - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_7zMethods), - kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt | - kFF_EncryptFileNames | kFF_MemUse | kFF_SFX - // | kFF_Time_Win - }, - { - "Zip", - (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_ZipMethods), - kFF_MultiThread | kFF_Encrypt | kFF_MemUse - // | kFF_Time_Win | kFF_Time_Unix | kFF_Time_DOS - }, - { - "GZip", - (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_GZipMethods), - kFF_MemUse - // | kFF_Time_Unix - }, - { - "BZip2", - (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_BZip2Methods), - kFF_MultiThread | kFF_MemUse - }, - { - "xz", - (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_XzMethods), - kFF_Solid | kFF_MultiThread | kFF_MemUse - }, - /* - { - "zstd", - // (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1, - (1 << (9 + 1)) - 1, - METHODS_PAIR(g_ZstdMethods), - // kFF_Solid | - kFF_MultiThread - | kFF_MemUse - }, - */ - { - "Swfc", - (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), - METHODS_PAIR(g_SwfcMethods), - 0 - }, - { - "Tar", - (1 << 0), - METHODS_PAIR(g_TarMethods), - 0 - // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns - }, - { - "wim", - (1 << 0), - 0, NULL, - 0 - // | kFF_Time_Win - }, - { - "Hash", - (0 << 0), - METHODS_PAIR(g_HashMethods), - 0 - } -}; - -static bool IsMethodSupportedBySfx(int methodID) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_7zSfxMethods); i++) - if (methodID == g_7zSfxMethods[i]) - return true; - return false; -} - - -static const - // NCompressDialog::NUpdateMode::EEnum - int - k_UpdateMode_Vals[] = -{ - NCompressDialog::NUpdateMode::kAdd, - NCompressDialog::NUpdateMode::kUpdate, - NCompressDialog::NUpdateMode::kFresh, - NCompressDialog::NUpdateMode::kSync -}; - -static const UInt32 k_UpdateMode_IDs[] = -{ - IDS_COMPRESS_UPDATE_MODE_ADD, - IDS_COMPRESS_UPDATE_MODE_UPDATE, - IDS_COMPRESS_UPDATE_MODE_FRESH, - IDS_COMPRESS_UPDATE_MODE_SYNC -}; - -static const - // NWildcard::ECensorPathMode - int - k_PathMode_Vals[] = -{ - NWildcard::k_RelatPath, - NWildcard::k_FullPath, - NWildcard::k_AbsPath, -}; - -static const UInt32 k_PathMode_IDs[] = -{ - IDS_PATH_MODE_RELAT, - IDS_EXTRACT_PATHS_FULL, - IDS_EXTRACT_PATHS_ABS -}; - -void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal); - -void CCompressDialog::SetMethods(const CObjectVector &userCodecs) -{ - ExternalMethods.Clear(); - { - FOR_VECTOR (i, userCodecs) - { - const CCodecInfoUser &c = userCodecs[i]; - if (!c.EncoderIsAssigned - || !c.IsFilter_Assigned - || c.IsFilter - || c.NumStreams != 1) - continue; - unsigned k; - for (k = 0; k < Z7_ARRAY_SIZE(g_7zMethods); k++) - if (c.Name.IsEqualTo_Ascii_NoCase(kMethodsNames[g_7zMethods[k]])) - break; - if (k != Z7_ARRAY_SIZE(g_7zMethods)) - continue; - ExternalMethods.Add(c.Name); - } - } -} - - -bool CCompressDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDD_COMPRESS); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - // LangSetDlgItemText(*this, IDB_COMPRESS_OPTIONS, IDS_OPTIONS); // IDG_COMPRESS_OPTIONS - #endif - - { - UInt64 size = (UInt64)(sizeof(size_t)) << 29; - _ramSize_Defined = NSystem::GetRamSize(size); - // size = (UInt64)3 << 62; // for debug only; - _ramSize = size; - const UInt64 kMinUseSize = (1 << 26); - if (size < kMinUseSize) - size = kMinUseSize; - - unsigned bits = sizeof(size_t) * 8; - if (bits == 32) - { - const UInt32 limit2 = (UInt32)7 << 28; - if (size > limit2) - size = limit2; - } - - _ramSize_Reduced = size; - - // 80% - is auto usage limit in handlers - _ramUsage_Auto = Calc_From_Val_Percents(size, 80); - } - - _password1Control.Attach(GetItem(IDE_COMPRESS_PASSWORD1)); - _password2Control.Attach(GetItem(IDE_COMPRESS_PASSWORD2)); - _password1Control.SetText(Info.Password); - _password2Control.SetText(Info.Password); - _encryptionMethod.Attach(GetItem(IDC_COMPRESS_ENCRYPTION_METHOD)); - _default_encryptionMethod_Index = -1; - - m_ArchivePath.Attach(GetItem(IDC_COMPRESS_ARCHIVE)); - m_Format.Attach(GetItem(IDC_COMPRESS_FORMAT)); // that combo has CBS_SORT style in resources - m_Level.Attach(GetItem(IDC_COMPRESS_LEVEL)); - m_Method.Attach(GetItem(IDC_COMPRESS_METHOD)); - m_Dictionary.Attach(GetItem(IDC_COMPRESS_DICTIONARY)); - - /* - { - RECT r; - GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r); - _dictionaryCombo_left = r.left; - } - */ - _dictionaryCombo_left = 0; // 230; - - // m_Dictionary_Chain.Attach(GetItem(IDC_COMPRESS_DICTIONARY2)); - m_Order.Attach(GetItem(IDC_COMPRESS_ORDER)); - m_Solid.Attach(GetItem(IDC_COMPRESS_SOLID)); - m_NumThreads.Attach(GetItem(IDC_COMPRESS_THREADS)); - m_MemUse.Attach(GetItem(IDC_COMPRESS_MEM_USE)); - - m_UpdateMode.Attach(GetItem(IDC_COMPRESS_UPDATE_MODE)); - m_PathMode.Attach(GetItem(IDC_COMPRESS_PATH_MODE)); - - m_Volume.Attach(GetItem(IDC_COMPRESS_VOLUME)); - m_Params.Attach(GetItem(IDE_COMPRESS_PARAMETERS)); - - AddVolumeItems(m_Volume); - - m_RegistryInfo.Load(); - CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword); - CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders); - - UpdatePasswordControl(); - - { - const bool needSetMain = (Info.FormatIndex < 0); - FOR_VECTOR(i, ArcIndices) - { - const unsigned arcIndex = ArcIndices[i]; - const CArcInfoEx &ai = (*ArcFormats)[arcIndex]; - const int index = (int)m_Format.AddString(ai.Name); - m_Format.SetItemData(index, (LPARAM)arcIndex); - if (!needSetMain) - { - if (Info.FormatIndex == (int)arcIndex) - m_Format.SetCurSel(index); - continue; - } - if (i == 0 || ai.Name.IsEqualTo_NoCase(m_RegistryInfo.ArcType)) - { - m_Format.SetCurSel(index); - Info.FormatIndex = (int)arcIndex; - } - } - } - - CheckButton(IDX_COMPRESS_SFX, Info.SFXMode); - - { - UString fileName; - SetArcPathFields(Info.ArcPath, fileName, true); - StartDirPrefix = DirPrefix; - SetArchiveName(fileName); - } - - for (unsigned i = 0; i < m_RegistryInfo.ArcPaths.Size() && i < kHistorySize; i++) - m_ArchivePath.AddString(m_RegistryInfo.ArcPaths[i]); - - AddComboItems(m_UpdateMode, k_UpdateMode_IDs, Z7_ARRAY_SIZE(k_UpdateMode_IDs), - k_UpdateMode_Vals, Info.UpdateMode); - - AddComboItems(m_PathMode, k_PathMode_IDs, Z7_ARRAY_SIZE(k_PathMode_IDs), - k_PathMode_Vals, Info.PathMode); - - - TCHAR s[32] = { TEXT('/'), TEXT(' '), 0 }; - ConvertUInt32ToString(NSystem::GetNumberOfProcessors(), s + 2); - SetItemText(IDT_COMPRESS_HARDWARE_THREADS, s); - - CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite); - CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing); - - FormatChanged(false); // isChanged - - // OnButtonSFX(); - - NormalizePosition(); - - return CModalDialog::OnInit(); -} - -/* -namespace NCompressDialog -{ - bool CInfo::GetFullPathName(UString &result) const - { - #ifndef UNDER_CE - // NDirectory::MySetCurrentDirectory(CurrentDirPrefix); - #endif - FString resultF; - bool res = MyGetFullPathName(us2fs(ArchiveName), resultF); - result = fs2us(resultF); - return res; - } -} -*/ - -void CCompressDialog::UpdatePasswordControl() -{ - const bool showPassword = IsShowPasswordChecked(); - const TCHAR c = showPassword ? (TCHAR)0: TEXT('*'); - _password1Control.SetPasswordChar((WPARAM)c); - _password2Control.SetPasswordChar((WPARAM)c); - UString password; - _password1Control.GetText(password); - _password1Control.SetText(password); - _password2Control.GetText(password); - _password2Control.SetText(password); - - ShowItem_Bool(IDT_PASSWORD_REENTER, !showPassword); - _password2Control.Show_Bool(!showPassword); -} - -bool CCompressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_COMPRESS_SET_ARCHIVE: - { - OnButtonSetArchive(); - return true; - } - case IDX_COMPRESS_SFX: - { - SetMethod(GetMethodID()); - OnButtonSFX(); - SetMemoryUsage(); - return true; - } - case IDX_PASSWORD_SHOW: - { - UpdatePasswordControl(); - return true; - } - case IDB_COMPRESS_OPTIONS: - { - COptionsDialog dialog(this); - if (dialog.Create(*this) == IDOK) - ShowOptionsString(); - return true; - } - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CCompressDialog::CheckSFXControlsEnable() -{ - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - bool enable = fi.SFX_(); - if (enable) - { - const int methodID = GetMethodID(); - enable = (methodID == -1 || IsMethodSupportedBySfx(methodID)); - } - if (!enable) - CheckButton(IDX_COMPRESS_SFX, false); - EnableItem(IDX_COMPRESS_SFX, enable); -} - -/* -void CCompressDialog::CheckVolumeEnable() -{ - bool isSFX = IsSFX(); - m_Volume.Enable(!isSFX); - if (isSFX) - m_Volume.SetText(TEXT("")); -} -*/ - -void CCompressDialog::EnableMultiCombo(unsigned id) -{ - NWindows::NControl::CComboBox combo; - combo.Attach(GetItem(id)); - const bool enable = (combo.GetCount() > 1); - EnableItem(id, enable); -} - -static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s); - -static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res) -{ - if (!b1.Def && b2.Def) - res.Val = b2.Val; - else - res.Val = b1.Val; -} - -#define SET_GUI_BOOL(name) \ - Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name) - - -static void Set_Final_BoolPairs( - const CBool1 &gui, - CBoolPair &cmd, - CBoolPair ®) -{ - if (!cmd.Def) - { - reg.Val = gui.Val; - reg.Def = gui.Val; - } - if (gui.Supported) - { - cmd.Val = gui.Val; - cmd.Def = gui.Val; - } - else - cmd.Init(); -} - -#define SET_FINAL_BOOL_PAIRS(name) \ - Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name) - -void CCompressDialog::FormatChanged(bool isChanged) -{ - SetLevel(); - SetSolidBlockSize(); - SetParams(); - SetMemUseCombo(); - SetNumThreads(); - - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - Info.SolidIsSpecified = fi.Solid_(); - Info.EncryptHeadersIsAllowed = fi.EncryptFileNames_(); - - /* - const bool multiThreadEnable = fi.MultiThread; - Info.MultiThreadIsAllowed = multiThreadEnable; - EnableItem(IDC_COMPRESS_SOLID, fi.Solid); - EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable); - const bool methodEnable = (fi.MethodIDs != NULL); - EnableItem(IDC_COMPRESS_METHOD, methodEnable); - EnableMultiCombo(IDC_COMPRESS_DICTIONARY, methodEnable); - EnableItem(IDC_COMPRESS_ORDER, methodEnable); - */ - - CheckSFXControlsEnable(); - - { - if (!isChanged) - { - SET_GUI_BOOL (SymLinks); - SET_GUI_BOOL (HardLinks); - SET_GUI_BOOL (AltStreams); - SET_GUI_BOOL (NtSecurity); - SET_GUI_BOOL (PreserveATime); - } - - PreserveATime.Supported = true; - - { - const CArcInfoEx &ai = Get_ArcInfoEx(); - SymLinks.Supported = ai.Flags_SymLinks(); - HardLinks.Supported = ai.Flags_HardLinks(); - AltStreams.Supported = ai.Flags_AltStreams(); - NtSecurity.Supported = ai.Flags_NtSecurity(); - } - - ShowOptionsString(); - } - // CheckVolumeEnable(); - - const bool encrypt = fi.Encrypt_(); - EnableItem(IDG_COMPRESS_ENCRYPTION, encrypt); - - EnableItem(IDT_PASSWORD_ENTER, encrypt); - EnableItem(IDT_PASSWORD_REENTER, encrypt); - EnableItem(IDE_COMPRESS_PASSWORD1, encrypt); - EnableItem(IDE_COMPRESS_PASSWORD2, encrypt); - EnableItem(IDX_PASSWORD_SHOW, encrypt); - - EnableItem(IDT_COMPRESS_ENCRYPTION_METHOD, encrypt); - EnableItem(IDC_COMPRESS_ENCRYPTION_METHOD, encrypt); - EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_()); - - ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_()); - - SetEncryptionMethod(); - SetMemoryUsage(); -} - - -bool CCompressDialog::IsSFX() -{ - return IsWindowEnabled(GetItem(IDX_COMPRESS_SFX)) - && IsButtonCheckedBool(IDX_COMPRESS_SFX); -} - -static int GetExtDotPos(const UString &s) -{ - const int dotPos = s.ReverseFind_Dot(); - if (dotPos > s.ReverseFind_PathSepar() + 1) - return dotPos; - return -1; -} - -void CCompressDialog::OnButtonSFX() -{ - UString fileName; - m_ArchivePath.GetText(fileName); - const int dotPos = GetExtDotPos(fileName); - if (IsSFX()) - { - if (dotPos >= 0) - fileName.DeleteFrom(dotPos); - fileName += kExeExt; - m_ArchivePath.SetText(fileName); - } - else - { - if (dotPos >= 0) - { - const UString ext = fileName.Ptr(dotPos); - if (ext.IsEqualTo_Ascii_NoCase(kExeExt)) - { - fileName.DeleteFrom(dotPos); - m_ArchivePath.SetText(fileName); - } - } - SetArchiveName2(false); // it's for OnInit - } - - // CheckVolumeEnable(); -} - - -bool CCompressDialog::GetFinalPath_Smart(UString &resPath) const -{ - resPath.Empty(); - UString name; - m_ArchivePath.GetText(name); - name.Trim(); - FString fullPath; - UString dirPrefx = DirPrefix; - if (dirPrefx.IsEmpty()) - dirPrefx = StartDirPrefix; - const bool res = !dirPrefx.IsEmpty() ? - NName::GetFullPath(us2fs(dirPrefx), us2fs(name), fullPath): - NName::GetFullPath( us2fs(name), fullPath); - if (res) - resPath = fs2us(fullPath); - return res; -} - - -bool CCompressDialog::SetArcPathFields(const UString &path) -{ - UString name; - return SetArcPathFields(path, name, true); // always -} - - -bool CCompressDialog::SetArcPathFields(const UString &path, UString &name, bool always) -{ - FString resDirPrefix; - FString resFileName; - const bool res = GetFullPathAndSplit(us2fs(path), resDirPrefix, resFileName); - if (res) - { - DirPrefix = fs2us(resDirPrefix); - name = fs2us(resFileName); - } - else - { - if (!always) - return false; - DirPrefix.Empty(); - name = path; - } - SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix); - m_ArchivePath.SetText(name); - return res; -} - - -static const wchar_t * const k_IncorrectPathMessage = L"Incorrect archive path"; - -static void AddFilter(CObjectVector &filters, - const UString &description, const UString &ext) -{ - CBrowseFilterInfo &f = filters.AddNew(); - UString mask ("*."); - mask += ext; - f.Masks.Add(mask); - f.Description = description; - f.Description += " ("; - f.Description += mask; - f.Description += ")"; -} - - -static const char * const k_DontSave_Exts = - "xpi odt ods docx xlsx "; - -void CCompressDialog::OnButtonSetArchive() -{ - UString path; - if (!GetFinalPath_Smart(path)) - { - ShowErrorMessage(*this, k_IncorrectPathMessage); - return; - } - - int filterIndex; - CObjectVector filters; - unsigned numFormats = 0; - - const bool isSFX = IsSFX(); - if (isSFX) - { - filterIndex = 0; - const UString ext ("exe"); - AddFilter(filters, ext, ext); - } - else - { - filterIndex = m_Format.GetCurSel(); - numFormats = (unsigned)m_Format.GetCount(); - - // filters [0, ... numFormats - 1] corresponds to items in m_Format combo - UString desc; - UStringVector masks; - CStringFinder finder; - - for (unsigned i = 0; i < numFormats; i++) - { - const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)]; - CBrowseFilterInfo &f = filters.AddNew(); - f.Description = ai.Name; - f.Description += " ("; - bool needSpace_desc = false; - - FOR_VECTOR (k, ai.Exts) - { - const UString &ext = ai.Exts[k].Ext; - UString mask ("*."); - mask += ext; - - if (finder.FindWord_In_LowCaseAsciiList_NoCase(k_DontSave_Exts, ext)) - continue; - - f.Masks.Add(mask); - masks.Add(mask); - if (needSpace_desc) - f.Description.Add_Space(); - needSpace_desc = true; - f.Description += ext; - } - f.Description += ")"; - // we use only main ext in desc to reduce the size of list - if (i != 0) - desc.Add_Space(); - desc += ai.GetMainExt(); - } - - CBrowseFilterInfo &f = filters.AddNew(); - f.Description = LangString(IDT_COMPRESS_ARCHIVE); // IDS_ARCHIVES_COLON; - if (f.Description.IsEmpty()) - GetItemText(IDT_COMPRESS_ARCHIVE, f.Description); - f.Description.RemoveChar(L'&'); - // f.Description = "archive"; - f.Description += " ("; - f.Description += desc; - f.Description += ")"; - f.Masks = masks; - } - - AddFilter(filters, LangString(IDS_OPEN_TYPE_ALL_FILES), UString("*")); - if (filterIndex < 0) - filterIndex = (int)filters.Size() - 1; - - const UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_BROWSE); - CBrowseInfo bi; - bi.lpstrTitle = title; - bi.SaveMode = true; - bi.FilterIndex = filterIndex; - bi.hwndOwner = *this; - bi.FilePath = path; - - if (!bi.BrowseForFile(filters)) - return; - - path = bi.FilePath; - - if (isSFX) - { - const int dotPos = GetExtDotPos(path); - if (dotPos >= 0) - path.DeleteFrom(dotPos); - path += kExeExt; - } - else - // if (bi.FilterIndex >= 0) - // if (bi.FilterIndex != filterIndex) - if ((unsigned)bi.FilterIndex < numFormats) - { - // archive format was confirmed. So we try to set format extension - bool needAddExt = true; - const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData((unsigned)bi.FilterIndex)]; - const int dotPos = GetExtDotPos(path); - if (dotPos >= 0) - { - const UString ext = path.Ptr(dotPos + 1); - if (ai.FindExtension(ext) >= 0) - needAddExt = false; - } - if (needAddExt) - { - if (path.IsEmpty() || path.Back() != '.') - path.Add_Dot(); - path += ai.GetMainExt(); - } - } - - SetArcPathFields(path); - - if (!isSFX) - if ((unsigned)bi.FilterIndex < numFormats) - if (bi.FilterIndex != m_Format.GetCurSel()) - { - m_Format.SetCurSel(bi.FilterIndex); - SaveOptionsInMem(); - FormatChanged(true); // isChanged - return; - } - - ArcPath_WasChanged(path); -} - - -// in ExtractDialog.cpp -extern void AddUniqueString(UStringVector &strings, const UString &srcString); - -static bool IsAsciiString(const UString &s) -{ - for (unsigned i = 0; i < s.Len(); i++) - { - const wchar_t c = s[i]; - if (c < 0x20 || c > 0x7F) - return false; - } - return true; -} - - -static void AddSize_MB(UString &s, UInt64 size) -{ - s.Add_LF(); - const UInt64 v2 = size + ((UInt32)1 << 20) - 1; - if (size < v2) - size = v2; - s.Add_UInt64(size >> 20); - s += " MB : "; -} - -static void AddSize_MB_id(UString &s, UInt64 size, UInt32 id) -{ - AddSize_MB(s, size); - AddLangString(s, id); -} - -void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString); -void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString) -{ - AddLangString(s, IDS_MEM_OPERATION_BLOCKED); - s.Add_LF(); - AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM); - s.Add_LF(); - AddSize_MB(s, reqSize); - s += usageString; - AddSize_MB_id(s, ramSize, IDS_MEM_RAM_SIZE); - // if (ramLimit != 0) - { - AddSize_MB_id(s, ramLimit, IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP); - } - s.Add_LF(); - s.Add_LF(); - AddLangString(s, IDS_MEM_ERROR); -} - - -void CCompressDialog::OnOK() -{ - _password1Control.GetText(Info.Password); - if (IsZipFormat()) - { - if (!IsAsciiString(Info.Password)) - { - ShowErrorMessageHwndRes(*this, IDS_PASSWORD_USE_ASCII); - return; - } - UString method = GetEncryptionMethodSpec(); - if (method.IsPrefixedBy_Ascii_NoCase("aes")) - { - if (Info.Password.Len() > 99) - { - ShowErrorMessageHwndRes(*this, IDS_PASSWORD_TOO_LONG); - return; - } - } - } - if (!IsShowPasswordChecked()) - { - UString password2; - _password2Control.GetText(password2); - if (password2 != Info.Password) - { - ShowErrorMessageHwndRes(*this, IDS_PASSWORD_NOT_MATCH); - return; - } - } - - { - UInt64 decompressMem; - const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem); - if (memUsage != (UInt64)(Int64)-1) - { - const UInt64 limit = Get_MemUse_Bytes(); - if (memUsage > limit) - { - UString s2; - LangString_OnlyFromLangFile(IDS_MEM_REQUIRED_MEM_SIZE, s2); - if (s2.IsEmpty()) - { - s2 = LangString(IDT_COMPRESS_MEMORY); - if (s2.IsEmpty()) - GetItemText(IDT_COMPRESS_MEMORY, s2); - s2.RemoveChar(L':'); - } - UString s; - SetErrorMessage_MemUsage(s, memUsage, _ramSize, limit, s2); - MessageBoxError(s); - return; - } - } - } - - SaveOptionsInMem(); - - UStringVector arcPaths; - { - UString s; - if (!GetFinalPath_Smart(s)) - { - ShowErrorMessage(*this, k_IncorrectPathMessage); - return; - } - Info.ArcPath = s; - AddUniqueString(arcPaths, s); - } - - Info.UpdateMode = (NCompressDialog::NUpdateMode::EEnum)k_UpdateMode_Vals[m_UpdateMode.GetCurSel()]; - Info.PathMode = (NWildcard::ECensorPathMode)k_PathMode_Vals[m_PathMode.GetCurSel()]; - - Info.Level = GetLevelSpec(); - Info.Dict64 = GetDictSpec(); - // Info.Dict64_Chain = GetDictChainSpec(); - Info.Order = GetOrderSpec(); - Info.OrderMode = GetOrderMode(); - Info.NumThreads = GetNumThreadsSpec(); - - Info.MemUsage.Clear(); - { - const UString mus = Get_MemUse_Spec(); - if (!mus.IsEmpty()) - { - NCompression::CMemUse mu; - mu.Parse(mus); - if (mu.IsDefined) - Info.MemUsage = mu; - } - } - - { - // Info.SolidIsSpecified = g_Formats[GetStaticFormatIndex()].Solid; - const UInt32 solidLogSize = GetBlockSizeSpec(); - Info.SolidBlockSize = 0; - if (solidLogSize == (UInt32)(Int32)-1) - Info.SolidIsSpecified = false; - else if (solidLogSize > 0) - Info.SolidBlockSize = (solidLogSize >= 64) ? - (UInt64)(Int64)-1 : - ((UInt64)1 << solidLogSize); - } - - Info.Method = GetMethodSpec(); - Info.EncryptionMethod = GetEncryptionMethodSpec(); - Info.FormatIndex = (int)GetFormatIndex(); - Info.SFXMode = IsSFX(); - Info.OpenShareForWrite = IsButtonCheckedBool(IDX_COMPRESS_SHARED); - Info.DeleteAfterCompressing = IsButtonCheckedBool(IDX_COMPRESS_DEL); - - m_RegistryInfo.EncryptHeaders = - Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES); - - - /* (Info) is for saving to registry: - (CBoolPair::Val) will be set as (false), if it was (false) - in registry at dialog creation, and user didn't click checkbox. - in another case (CBoolPair::Val) will be set as (true) */ - - { - /* Info properties could be for another archive types. - so we disable unsupported properties in Info */ - // const CArcInfoEx &ai = Get_ArcInfoEx(); - - SET_FINAL_BOOL_PAIRS (SymLinks); - SET_FINAL_BOOL_PAIRS (HardLinks); - SET_FINAL_BOOL_PAIRS (AltStreams); - SET_FINAL_BOOL_PAIRS (NtSecurity); - - SET_FINAL_BOOL_PAIRS (PreserveATime); - } - - { - const NCompression::CFormatOptions &fo = Get_FormatOptions(); - - Info.TimePrec = fo.TimePrec; - Info.MTime = fo.MTime; - Info.CTime = fo.CTime; - Info.ATime = fo.ATime; - Info.SetArcMTime = fo.SetArcMTime; - } - - m_Params.GetText(Info.Options); - - UString volumeString; - m_Volume.GetText(volumeString); - volumeString.Trim(); - Info.VolumeSizes.Clear(); - - if (!volumeString.IsEmpty()) - { - if (!ParseVolumeSizes(volumeString, Info.VolumeSizes)) - { - ShowErrorMessageHwndRes(*this, IDS_INCORRECT_VOLUME_SIZE); - return; - } - if (!Info.VolumeSizes.IsEmpty()) - { - const UInt64 volumeSize = Info.VolumeSizes.Back(); - if (volumeSize < (100 << 10)) - { - wchar_t s[32]; - ConvertUInt64ToString(volumeSize, s); - if (::MessageBoxW(*this, MyFormatNew(IDS_SPLIT_CONFIRM, s), - L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) - return; - } - } - } - - if (Info.FormatIndex >= 0) - m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name; - m_RegistryInfo.ShowPassword = IsShowPasswordChecked(); - - FOR_VECTOR (i, m_RegistryInfo.ArcPaths) - { - if (arcPaths.Size() >= kHistorySize) - break; - AddUniqueString(arcPaths, m_RegistryInfo.ArcPaths[i]); - } - m_RegistryInfo.ArcPaths = arcPaths; - - m_RegistryInfo.Save(); - - CModalDialog::OnOK(); -} - -#define kHelpTopic "fm/plugins/7-zip/add.htm" -#define kHelpTopic_Options "fm/plugins/7-zip/add.htm#options" - -void CCompressDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); -} - - -void CCompressDialog::ArcPath_WasChanged(const UString &path) -{ - const int dotPos = GetExtDotPos(path); - if (dotPos < 0) - return; - const UString ext = path.Ptr(dotPos + 1); - { - const CArcInfoEx &ai = Get_ArcInfoEx(); - if (ai.FindExtension(ext) >= 0) - return; - } - - const unsigned count = (unsigned)m_Format.GetCount(); - for (unsigned i = 0; i < count; i++) - { - const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)]; - if (ai.FindExtension(ext) >= 0) - { - m_Format.SetCurSel(i); - SaveOptionsInMem(); - FormatChanged(true); // isChanged - return; - } - } -} - - -bool CCompressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case k_Message_ArcChanged: - { - // UString path; - // m_ArchivePath.GetText(path); - const int select = m_ArchivePath.GetCurSel(); - if ((unsigned)select < m_RegistryInfo.ArcPaths.Size()) - // if (path == m_RegistryInfo.ArcPaths[select]) - { - const UString &path = m_RegistryInfo.ArcPaths[select]; - SetArcPathFields(path); - // ArcPath_WasChanged(path); - } - return 0; - } - } - return CModalDialog::OnMessage(message, wParam, lParam); -} - - -bool CCompressDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE) - { - switch (itemID) - { - case IDC_COMPRESS_ARCHIVE: - { - /* CBN_SELCHANGE is called before actual value of combo text will be changed. - So GetText() here returns old value (before change) of combo text. - So here we can change all controls except of m_ArchivePath. - */ - const int select = m_ArchivePath.GetCurSel(); - if ((unsigned)select < m_RegistryInfo.ArcPaths.Size()) - { - // DirPrefix.Empty(); - // SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix); - const UString &path = m_RegistryInfo.ArcPaths[select]; - // SetArcPathFields(path); - ArcPath_WasChanged(path); - // we use PostMessage(k_Message_ArcChanged) here that later will change m_ArchivePath control - PostMsg(k_Message_ArcChanged); - } - return true; - } - - case IDC_COMPRESS_FORMAT: - { - const bool isSFX = IsSFX(); - SaveOptionsInMem(); - FormatChanged(true); // isChanged - SetArchiveName2(isSFX); - return true; - } - - case IDC_COMPRESS_LEVEL: - { - Get_FormatOptions().ResetForLevelChange(); - - SetMethod(); // call it if level changes method - - // call the following if level change keeps old method - /* - { - // try to keep old method - SetMethod(GetMethodID()); - MethodChanged(); - } - */ - - SetSolidBlockSize(); - SetNumThreads(); - CheckSFXNameChange(); - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_METHOD: - { - MethodChanged(); - SetSolidBlockSize(); - SetNumThreads(); - CheckSFXNameChange(); - SetMemoryUsage(); - if (Get_ArcInfoEx().Flags_HashHandler()) - SetArchiveName2(false); - - return true; - } - - case IDC_COMPRESS_DICTIONARY: - // case IDC_COMPRESS_DICTIONARY2: - { - /* we want to change the reported threads for Auto line - and keep selected NumThreads option - So we save selected NumThreads option in memory */ - SaveOptionsInMem(); - const UInt32 blockSizeLog = GetBlockSizeSpec(); - if (// blockSizeLog != (UInt32)(Int32)-1 && - blockSizeLog != kSolidLog_NoSolid - && blockSizeLog != kSolidLog_FullSolid) - { - Get_FormatOptions().Reset_BlockLogSize(); - // SetSolidBlockSize(true); - } - - SetDictionary2(); - SetSolidBlockSize(); - SetNumThreads(); // we want to change the reported threads for Auto line only - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_ORDER: - { - #ifdef PRINT_PARAMS - Print_Params(); - #endif - return true; - } - - case IDC_COMPRESS_SOLID: - { - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_THREADS: - { - SetMemoryUsage(); - return true; - } - - case IDC_COMPRESS_MEM_USE: - { - /* we want to change the reported threads for Auto line - and keep selected NumThreads option - So we save selected NumThreads option in memory */ - SaveOptionsInMem(); - - SetNumThreads(); // we want to change the reported threads for Auto line only - SetMemoryUsage(); - return true; - } - } - } - return CModalDialog::OnCommand(code, itemID, lParam); -} - -void CCompressDialog::CheckSFXNameChange() -{ - const bool isSFX = IsSFX(); - CheckSFXControlsEnable(); - if (isSFX != IsSFX()) - SetArchiveName2(isSFX); -} - -void CCompressDialog::SetArchiveName2(bool prevWasSFX) -{ - UString fileName; - m_ArchivePath.GetText(fileName); - const CArcInfoEx &prevArchiverInfo = (*ArcFormats)[m_PrevFormat]; - if (prevArchiverInfo.Flags_KeepName() || Info.KeepName) - { - UString prevExtension; - if (prevWasSFX) - prevExtension = kExeExt; - else - { - prevExtension.Add_Dot(); - prevExtension += prevArchiverInfo.GetMainExt(); - } - const unsigned prevExtensionLen = prevExtension.Len(); - if (fileName.Len() >= prevExtensionLen) - if (StringsAreEqualNoCase(fileName.RightPtr(prevExtensionLen), prevExtension)) - fileName.DeleteFrom(fileName.Len() - prevExtensionLen); - } - SetArchiveName(fileName); -} - -// if type.KeepName then use OriginalFileName -// else if !KeepName remove extension -// add new extension - -void CCompressDialog::SetArchiveName(const UString &name) -{ - UString fileName = name; - Info.FormatIndex = (int)GetFormatIndex(); - const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; - m_PrevFormat = Info.FormatIndex; - if (ai.Flags_KeepName()) - { - fileName = OriginalFileName; - } - else - { - if (!Info.KeepName) - { - int dotPos = GetExtDotPos(fileName); - if (dotPos >= 0) - fileName.DeleteFrom(dotPos); - } - } - - if (IsSFX()) - fileName += kExeExt; - else - { - fileName.Add_Dot(); - UString ext = ai.GetMainExt(); - if (ai.Flags_HashHandler()) - { - UString estimatedName; - GetMethodSpec(estimatedName); - if (!estimatedName.IsEmpty()) - { - ext = estimatedName; - ext.MakeLower_Ascii(); - } - } - fileName += ext; - } - m_ArchivePath.SetText(fileName); -} - - -int CCompressDialog::FindRegistryFormat(const UString &name) -{ - FOR_VECTOR (i, m_RegistryInfo.Formats) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[i]; - if (name.IsEqualTo_NoCase(GetUnicodeString(fo.FormatID))) - return (int)i; - } - return -1; -} - - -unsigned CCompressDialog::FindRegistryFormat_Always(const UString &name) -{ - const int index = FindRegistryFormat(name); - if (index >= 0) - return (unsigned)index; - { - NCompression::CFormatOptions fo; - fo.FormatID = GetSystemString(name); - return m_RegistryInfo.Formats.Add(fo); - } -} - - -NCompression::CFormatOptions &CCompressDialog::Get_FormatOptions() -{ - const CArcInfoEx &ai = Get_ArcInfoEx(); - return m_RegistryInfo.Formats[FindRegistryFormat_Always(ai.Name)]; -} - - -unsigned CCompressDialog::GetStaticFormatIndex() -{ - const CArcInfoEx &ai = Get_ArcInfoEx(); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Formats); i++) - if (ai.Name.IsEqualTo_Ascii_NoCase(g_Formats[i].Name)) - return i; - return 0; // -1; -} - -void CCompressDialog::SetNearestSelectComboBox(NControl::CComboBox &comboBox, UInt32 value) -{ - for (int i = comboBox.GetCount() - 1; i >= 0; i--) - if ((UInt32)comboBox.GetItemData(i) <= value) - { - comboBox.SetCurSel(i); - return; - } - if (comboBox.GetCount() > 0) - comboBox.SetCurSel(0); -} - -void CCompressDialog::SetLevel2() -{ - m_Level.ResetContent(); - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - const CArcInfoEx &ai = Get_ArcInfoEx(); - UInt32 level = 5; - { - int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (fo.Level <= 9) - level = fo.Level; - else if (fo.Level == (UInt32)(Int32)-1) - level = 5; - else - level = 9; - } - } - - const bool isZstd = ai.Is_Zstd(); - - for (unsigned i = 0; i < sizeof(UInt32) * 8; i++) - { - const UInt32 mask = (UInt32)1 << i; - if ((fi.LevelsMask & mask) != 0) - { - const UInt32 langID = g_Levels[i]; - UString s; - s.Add_UInt32(i); - // if (fi.LevelsMask < (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1) - if (langID) - if (i != 0 || !isZstd) - { - s += " - "; - s += LangString(langID); - } - const int index = (int)m_Level.AddString(s); - m_Level.SetItemData(index, (LPARAM)i); - } - if (fi.LevelsMask <= mask) - break; - } - SetNearestSelectComboBox(m_Level, level); -} - - -static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s) -{ - return cb.AddString((CSysString)s); -} - -static const char *k_Auto_Prefix = "* "; - -static void Modify_Auto(AString &s) -{ - s.Insert(0, k_Auto_Prefix); -} - -void CCompressDialog::SetMethod2(int keepMethodId) -{ - m_Method.ResetContent(); - _auto_MethodId = -1; - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - const CArcInfoEx &ai = Get_ArcInfoEx(); - if (GetLevel() == 0 && !ai.Flags_HashHandler()) - { - if (!ai.Is_Tar() && - !ai.Is_Zstd()) - { - MethodChanged(); - return; - } - } - UString defaultMethod; - { - const int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - defaultMethod = fo.Method; - } - } - const bool isSfx = IsSFX(); - bool weUseSameMethod = false; - - const bool is7z = ai.Is_7z(); - - for (unsigned m = 0;; m++) - { - int methodID; - const char *method; - if (m < fi.NumMethods) - { - methodID = fi.MethodIDs[m]; - method = kMethodsNames[methodID]; - if (is7z) - if (methodID == kCopy - || methodID == kDeflate - || methodID == kDeflate64 - ) - continue; - } - else - { - if (!is7z) - break; - const unsigned extIndex = m - fi.NumMethods; - if (extIndex >= ExternalMethods.Size()) - break; - methodID = (int)(Z7_ARRAY_SIZE(kMethodsNames) + extIndex); - method = ExternalMethods[extIndex].Ptr(); - } - if (isSfx) - if (!IsMethodSupportedBySfx(methodID)) - continue; - - AString s (method); - int writtenMethodId = methodID; - if (m == 0) - { - _auto_MethodId = methodID; - writtenMethodId = -1; - Modify_Auto(s); - } - const int itemIndex = (int)ComboBox_AddStringAscii(m_Method, s); - m_Method.SetItemData(itemIndex, writtenMethodId); - if (keepMethodId == methodID) - { - m_Method.SetCurSel(itemIndex); - weUseSameMethod = true; - continue; - } - if ((defaultMethod.IsEqualTo_Ascii_NoCase(method) || m == 0) && !weUseSameMethod) - m_Method.SetCurSel(itemIndex); - } - - if (!weUseSameMethod) - MethodChanged(); -} - - - -bool CCompressDialog::IsZipFormat() -{ - return Get_ArcInfoEx().Is_Zip(); -} - -bool CCompressDialog::IsXzFormat() -{ - return Get_ArcInfoEx().Is_Xz(); -} - -void CCompressDialog::SetEncryptionMethod() -{ - _encryptionMethod.ResetContent(); - _default_encryptionMethod_Index = -1; - const CArcInfoEx &ai = Get_ArcInfoEx(); - if (ai.Is_7z()) - { - ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); - _encryptionMethod.SetCurSel(0); - _default_encryptionMethod_Index = 0; - } - else if (ai.Is_Zip()) - { - int index = FindRegistryFormat(ai.Name); - UString encryptionMethod; - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - encryptionMethod = fo.EncryptionMethod; - } - int sel = 0; - // if (ZipCryptoIsAllowed) - { - ComboBox_AddStringAscii(_encryptionMethod, "ZipCrypto"); - sel = (encryptionMethod.IsPrefixedBy_Ascii_NoCase("aes") ? 1 : 0); - _default_encryptionMethod_Index = 0; - } - ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); - _encryptionMethod.SetCurSel(sel); - } -} - - -int CCompressDialog::GetMethodID_RAW() -{ - if (m_Method.GetCount() <= 0) - return -1; - return (int)(Int32)(UInt32)m_Method.GetItemData_of_CurSel(); -} - -int CCompressDialog::GetMethodID() -{ - int raw = GetMethodID_RAW(); - if (raw < 0) - return _auto_MethodId; - return raw; -} - - -UString CCompressDialog::GetMethodSpec(UString &estimatedName) -{ - estimatedName.Empty(); - if (m_Method.GetCount() < 1) - return estimatedName; - const int methodIdRaw = GetMethodID_RAW(); - int methodId = methodIdRaw; - if (methodIdRaw < 0) - methodId = _auto_MethodId; - UString s; - if (methodId >= 0) - { - if ((unsigned)methodId < Z7_ARRAY_SIZE(kMethodsNames)) - estimatedName = kMethodsNames[methodId]; - else - estimatedName = ExternalMethods[(unsigned)methodId - (unsigned)Z7_ARRAY_SIZE(kMethodsNames)]; - if (methodIdRaw >= 0) - s = estimatedName; - } - return s; -} - - -UString CCompressDialog::GetMethodSpec() -{ - UString estimatedName; - UString s = GetMethodSpec(estimatedName); - return s; -} - -bool CCompressDialog::IsMethodEqualTo(const UString &s) -{ - UString estimatedName; - const UString shortName = GetMethodSpec(estimatedName); - if (s.IsEmpty()) - return shortName.IsEmpty(); - return s.IsEqualTo_NoCase(estimatedName); -} - - -UString CCompressDialog::GetEncryptionMethodSpec() -{ - UString s; - if (_encryptionMethod.GetCount() > 0 - && _encryptionMethod.GetCurSel() != _default_encryptionMethod_Index) - { - _encryptionMethod.GetText(s); - s.RemoveChar(L'-'); - } - return s; -} - - -static const size_t k_Auto_Dict = (size_t)0 - 1; - -static int Combo_AddDict2(NWindows::NControl::CComboBox &cb, size_t sizeReal, size_t sizeShow) -{ - char c = 0; - unsigned moveBits = 0; - if ((sizeShow & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } - else if ((sizeShow & 0x3FF) == 0) { moveBits = 10; c = 'K'; } - AString s; - s.Add_UInt64(sizeShow >> moveBits); - s.Add_Space(); - if (c != 0) - s.Add_Char(c); - s.Add_Char('B'); - if (sizeReal == k_Auto_Dict) - Modify_Auto(s); - const int index = (int)ComboBox_AddStringAscii(cb, s); - cb.SetItemData(index, (LPARAM)sizeReal); - return index; -} - -int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow) -{ - return Combo_AddDict2(m_Dictionary, sizeReal, sizeShow); -} - -int CCompressDialog::AddDict(size_t size) -{ - return AddDict2(size, size); -} - -/* -int CCompressDialog::AddDict_Chain(size_t size) -{ - return Combo_AddDict2(m_Dictionary_Chain, size, size); -} -*/ - -void CCompressDialog::SetDictionary2() -{ - m_Dictionary.ResetContent(); - // m_Dictionary_Chain.ResetContent(); - - // _auto_Dict = (UInt32)1 << 24; // we can use this dictSize to calculate _auto_Solid for unknown method for 7z - _auto_Dict = (UInt32)(Int32)-1; // for debug - // _auto_Dict_Chain = (UInt32)(Int32)-1; // for debug - - const CArcInfoEx &ai = Get_ArcInfoEx(); - UInt32 defaultDict = (UInt32)(Int32)-1; - // UInt32 defaultDict_Chain = (UInt32)(Int32)-1; - { - const int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (IsMethodEqualTo(fo.Method)) - { - defaultDict = fo.Dictionary; - // defaultDict_Chain = fo.DictionaryChain; - } - } - } - - const int methodID = GetMethodID(); - const UInt32 level = GetLevel2(); - - { - RECT r, rLabel; - GetClientRectOfItem(IDT_COMPRESS_DICTIONARY, rLabel); - GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r); - if (_dictionaryCombo_left == 0) - _dictionaryCombo_left = r.left; - - // bool showDict2; - int newLableRight; - int newDictLeft; - - /* - if (methodID == kZSTD) - { - showDict2 = true; - newDictLeft = _dictionaryCombo_left; - RECT r2; - GetClientRectOfItem(IDC_COMPRESS_DICTIONARY2, r2); - newLableRight = r2.left; - } - else - */ - { - // showDict2 = false; - RECT rBig; - GetClientRectOfItem(IDC_COMPRESS_METHOD, rBig); - newDictLeft= rBig.left; - newLableRight = newDictLeft; - } - - if (newLableRight != rLabel.right) - { - rLabel.right = newLableRight; - MoveItem_RECT(IDT_COMPRESS_DICTIONARY, rLabel); - InvalidateRect(&rLabel); - } - if (newDictLeft != r.left) - { - r.left = newDictLeft; - MoveItem_RECT(IDC_COMPRESS_DICTIONARY, r); - // InvalidateRect(&r); - } - // ShowItem_Bool(IDC_COMPRESS_DICTIONARY2, showDict2); - } - - if (methodID < 0) - return; - - switch (methodID) - { - case kLZMA: - case kLZMA2: - { - { - _auto_Dict = - ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) : - ( level <= 6 ? ((UInt32)1 << (level + 19)) : - ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26) - ))); - } - - // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize. - if (defaultDict != (UInt32)(Int32)-1 - && defaultDict >= ((UInt32)15 << 28)) - defaultDict = kLzmaMaxDictSize; - - const size_t kLzmaMaxDictSize_Up = (size_t)1 << (20 + sizeof(size_t) / 4 * 6); - - int curSel = AddDict2(k_Auto_Dict, _auto_Dict); - - for (unsigned i = (16 - 1) * 2; i <= (32 - 1) * 2; i++) - { - if (i < (20 - 1) * 2 - && i != (16 - 1) * 2 - && i != (18 - 1) * 2) - continue; - if (i == (20 - 1) * 2 + 1) - continue; - const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2); - size_t dict = dict_up; - if (dict_up >= kLzmaMaxDictSize) - dict = kLzmaMaxDictSize; // we reduce dictionary - - const int index = AddDict(dict); - // AddDict2(dict, dict_up); // for debug : we show 4 GB - - // const UInt32 numThreads = 2; - // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(numThreads, dict); - if (defaultDict != (UInt32)(Int32)-1) - if (dict <= defaultDict || curSel <= 0) - // if (!maxRamSize_Defined || memUsage <= maxRamSize) - curSel = index; - if (dict_up >= kLzmaMaxDictSize_Up) - break; - } - - m_Dictionary.SetCurSel(curSel); - break; - } - - /* - case kZSTD: - { - if (defaultDict != (UInt32)(Int32)-1 && - defaultDict > kZstd_MAX_DictSize) - defaultDict = kZstd_MAX_DictSize; - - if (defaultDict_Chain != (UInt32)(Int32)-1 && - defaultDict_Chain > kZstd_MAX_DictSize_Chain) - defaultDict_Chain = kZstd_MAX_DictSize_Chain; - - { - CZstdEncProps props; - ZstdEncProps_Init(&props); - // props.level_zstd = level; - props.level_7z = level; - ZstdEncProps_Set_WindowSize(&props, defaultDict != (UInt32)(Int32)-1 ? defaultDict: 0); - ZstdEncProps_NormalizeFull(&props); - _auto_Dict_Chain = (UInt32)1 << props.windowLog_Chain; - } - { - CZstdEncProps props; - ZstdEncProps_Init(&props); - // props.level_zstd = level; - props.level_7z = level; - ZstdEncProps_Set_WindowChainSize(&props, defaultDict_Chain != (UInt32)(Int32)-1 ? defaultDict_Chain: 0); - ZstdEncProps_NormalizeFull(&props); - _auto_Dict = (UInt32)1 << props.windowLog; - } - - // if there is collision of two window sizes, we reduce dict_Chain - if (defaultDict != (UInt32)(Int32)-1 && - defaultDict_Chain != (UInt32)(Int32)-1 && - defaultDict < defaultDict_Chain) - defaultDict_Chain = defaultDict; - - { - int curSel = AddDict2(k_Auto_Dict, _auto_Dict); - - // defaultDict = 12 << 10; // for debug - const UInt32 kWinStart = 18; - if (defaultDict != 0 && defaultDict < ((UInt32)1 << kWinStart)) - curSel = AddDict(defaultDict); - - for (unsigned i = kWinStart; i <= MY_ZSTD_WINDOWLOG_MAX; i++) - { - const size_t dict = (size_t)1 << i; - const int index = AddDict(dict); - if (defaultDict != (UInt32)(Int32)-1) - if (dict <= defaultDict || curSel <= 0) - curSel = index; - } - m_Dictionary.SetCurSel(curSel); - } - - { - int curSel = Combo_AddDict2(m_Dictionary_Chain, k_Auto_Dict, _auto_Dict_Chain); - - // defaultDict_Chain = 10 << 10; // for debug - const UInt32 kWinChainStart = 15; - if (defaultDict_Chain != 0 && defaultDict_Chain < ((UInt32)1 << kWinChainStart)) - curSel = AddDict_Chain(defaultDict_Chain); - - for (unsigned i = kWinChainStart; i <= kMaxDictChain; i++) - { - const size_t dict = (size_t)1 << i; - if (defaultDict != (UInt32)(Int32)-1 && dict > defaultDict) - break; - const int index = AddDict_Chain(dict); - if (defaultDict_Chain != (UInt32)(Int32)-1) - if (dict <= defaultDict_Chain || curSel <= 0) - curSel = index; - } - m_Dictionary_Chain.SetCurSel(curSel); - } - - break; - } - */ - - case kPPMd: - { - _auto_Dict = (UInt32)1 << (level + 19); - - const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10); - const size_t kPpmd_MaxDictSize_Up = (size_t)1 << (29 + sizeof(size_t) / 8); - - if (defaultDict != (UInt32)(Int32)-1 - && defaultDict >= ((UInt32)15 << 28)) // threshold - defaultDict = kPpmd_Default_4g; - - int curSel = AddDict2(k_Auto_Dict, _auto_Dict); - - for (unsigned i = (20 - 1) * 2; i <= (32 - 1) * 2; i++) - { - if (i == (20 - 1) * 2 + 1) - continue; - - const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2); - size_t dict = dict_up; - if (dict_up >= kPpmd_Default_4g) - dict = kPpmd_Default_4g; - - const int index = AddDict2(dict, dict_up); - // AddDict2((UInt32)((UInt32)0 - 2), dict_up); // for debug - // AddDict(dict_up); // for debug - // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict); - if (defaultDict != (UInt32)(Int32)-1) - if (dict <= defaultDict || curSel <= 0) - // if (!maxRamSize_Defined || memUsage <= maxRamSize) - curSel = index; - if (dict_up >= kPpmd_MaxDictSize_Up) - break; - } - m_Dictionary.SetCurSel(curSel); - break; - } - - case kPPMdZip: - { - _auto_Dict = (UInt32)1 << (level + 19); - - int curSel = AddDict2(k_Auto_Dict, _auto_Dict); - - for (unsigned i = 20; i <= 28; i++) - { - const UInt32 dict = (UInt32)1 << i; - const int index = AddDict(dict); - // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict); - if (defaultDict != (UInt32)(Int32)-1) - if (dict <= defaultDict || curSel <= 0) - // if (!maxRamSize_Defined || memUsage <= maxRamSize) - curSel = index; - } - m_Dictionary.SetCurSel(curSel); - break; - } - - case kDeflate: - case kDeflate64: - { - const UInt32 dict = (methodID == kDeflate ? (UInt32)(1 << 15) : (UInt32)(1 << 16)); - _auto_Dict = dict; - AddDict2(k_Auto_Dict, _auto_Dict); - m_Dictionary.SetCurSel(0); - // EnableItem(IDC_COMPRESS_DICTIONARY, false); - break; - } - - case kBZip2: - { - { - if (level >= 5) _auto_Dict = (900 << 10); - else if (level >= 3) _auto_Dict = (500 << 10); - else _auto_Dict = (100 << 10); - } - - int curSel = AddDict2(k_Auto_Dict, _auto_Dict); - - for (unsigned i = 1; i <= 9; i++) - { - const UInt32 dict = ((UInt32)i * 100) << 10; - AddDict(dict); - // AddDict2(i * 100000, dict); - if (defaultDict != (UInt32)(Int32)-1) - if (i <= defaultDict / 100000 || curSel <= 0) - curSel = m_Dictionary.GetCount() - 1; - } - m_Dictionary.SetCurSel(curSel); - break; - } - - case kCopy: - { - _auto_Dict = 0; - AddDict(0); - m_Dictionary.SetCurSel(0); - break; - } - } -} - - -UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) -{ - if (c.GetCount() <= defMax) - return (UInt32)(Int32)-1; - return (UInt32)c.GetItemData_of_CurSel(); -} - - -UInt64 CCompressDialog::GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax) -{ - if (c.GetCount() <= defMax) - return (UInt64)(Int64)-1; - // LRESULT is signed. so we cast it to unsigned size_t at first: - LRESULT val = c.GetItemData_of_CurSel(); - if (val == (LPARAM)(INT_PTR)(-1)) - return (UInt64)(Int64)-1; - return (UInt64)(size_t)c.GetItemData_of_CurSel(); -} - -UInt32 CCompressDialog::GetLevel2() -{ - UInt32 level = GetLevel(); - if (level == (UInt32)(Int32)-1) - level = 5; - return level; -} - - -int CCompressDialog::AddOrder(UInt32 size) -{ - char s[32]; - ConvertUInt32ToString(size, s); - const int index = (int)ComboBox_AddStringAscii(m_Order, s); - m_Order.SetItemData(index, (LPARAM)size); - return index; -} - -int CCompressDialog::AddOrder_Auto() -{ - AString s; - s.Add_UInt32(_auto_Order); - Modify_Auto(s); - int index = (int)ComboBox_AddStringAscii(m_Order, s); - m_Order.SetItemData(index, (LPARAM)(INT_PTR)(-1)); - return index; -} - -void CCompressDialog::SetOrder2() -{ - m_Order.ResetContent(); - - _auto_Order = 1; - - const CArcInfoEx &ai = Get_ArcInfoEx(); - UInt32 defaultOrder = (UInt32)(Int32)-1; - - { - const int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (IsMethodEqualTo(fo.Method)) - defaultOrder = fo.Order; - } - } - - const int methodID = GetMethodID(); - const UInt32 level = GetLevel2(); - if (methodID < 0) - return; - - switch (methodID) - { - case kLZMA: - case kLZMA2: - { - _auto_Order = (level < 7 ? 32 : 64); - int curSel = AddOrder_Auto(); - for (unsigned i = 2 * 2; i < 8 * 2; i++) - { - UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); - if (order > 256) - order = 273; - const int index = AddOrder(order); - if (defaultOrder != (UInt32)(Int32)-1) - if (order <= defaultOrder || curSel <= 0) - curSel = index; - } - m_Order.SetCurSel(curSel); - break; - } - - /* - case kZSTD: - { - { - CZstdEncProps props; - ZstdEncProps_Init(&props); - // props.level_zstd = level; - props.level_7z = level; - ZstdEncProps_NormalizeFull(&props); - _auto_Order = props.targetLength; - if (props.strategy < ZSTD_strategy_btopt) - { - // ZSTD_strategy_fast uses targetLength to change fast level. - // targetLength probably is used only in ZSTD_strategy_btopt and higher - break; - } - } - int curSel = AddOrder_Auto(); - - for (unsigned i = 6; i <= 9 * 2; i++) - { - UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); - // if (order > 999) order = 999; - const int index = AddOrder(order); - if (defaultOrder != (UInt32)(Int32)-1) - if (order <= defaultOrder || curSel <= 0) - curSel = index; - } - m_Order.SetCurSel(curSel); - break; - } - */ - - case kDeflate: - case kDeflate64: - { - { - if (level >= 9) _auto_Order = 128; - else if (level >= 7) _auto_Order = 64; - else _auto_Order = 32; - } - int curSel = AddOrder_Auto(); - for (unsigned i = 2 * 2; i < 8 * 2; i++) - { - UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); - if (order > 256) - order = (methodID == kDeflate64 ? 257 : 258); - const int index = AddOrder(order); - if (defaultOrder != (UInt32)(Int32)-1) - if (order <= defaultOrder || curSel <= 0) - curSel = index; - } - - m_Order.SetCurSel(curSel); - break; - } - - case kPPMd: - { - { - if (level >= 9) _auto_Order = 32; - else if (level >= 7) _auto_Order = 16; - else if (level >= 5) _auto_Order = 6; - else _auto_Order = 4; - } - - int curSel = AddOrder_Auto(); - - for (unsigned i = 0;; i++) - { - UInt32 order = i + 2; - if (i >= 2) - order = (4 + ((i - 2) & 3)) << ((i - 2) / 4); - const int index = AddOrder(order); - if (defaultOrder != (UInt32)(Int32)-1) - if (order <= defaultOrder || curSel <= 0) - curSel = index; - if (order >= 32) - break; - } - m_Order.SetCurSel(curSel); - break; - } - - case kPPMdZip: - { - _auto_Order = level + 3; - int curSel = AddOrder_Auto(); - for (unsigned i = 2; i <= 16; i++) - { - const int index = AddOrder(i); - if (defaultOrder != (UInt32)(Int32)-1) - if (i <= defaultOrder || curSel <= 0) - curSel = index; - } - m_Order.SetCurSel(curSel); - break; - } - - // case kBZip2: - default: - break; - } -} - -bool CCompressDialog::GetOrderMode() -{ - switch (GetMethodID()) - { - case kPPMd: - case kPPMdZip: - return true; - } - return false; -} - - -static UInt64 Get_Lzma2_ChunkSize(UInt64 dict) -{ - // we use same default chunk sizes as defined in 7z encoder and lzma2 encoder - UInt64 cs = (UInt64)dict << 2; - const UInt32 kMinSize = (UInt32)1 << 20; - const UInt32 kMaxSize = (UInt32)1 << 28; - if (cs < kMinSize) cs = kMinSize; - if (cs > kMaxSize) cs = kMaxSize; - if (cs < dict) cs = dict; - cs += (kMinSize - 1); - cs &= ~(UInt64)(kMinSize - 1); - return cs; -} - - -static void Add_Size(AString &s, UInt64 val) -{ - unsigned moveBits = 0; - char c = 0; - if ((val & 0x3FFFFFFF) == 0) { moveBits = 30; c = 'G'; } - else if ((val & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } - else if ((val & 0x3FF) == 0) { moveBits = 10; c = 'K'; } - s.Add_UInt64(val >> moveBits); - s.Add_Space(); - if (moveBits != 0) - s.Add_Char(c); - s.Add_Char('B'); -} - - -void CCompressDialog::SetSolidBlockSize2() -{ - m_Solid.ResetContent(); - _auto_Solid = 1 << 20; - - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - if (!fi.Solid_()) - return; - - const UInt32 level = GetLevel2(); - if (level == 0) - return; - - UInt64 dict = GetDict2(); - if (dict == (UInt64)(Int64)-1) - { - dict = 1 << 25; // default dict for unknown methods - // return; - } - - - UInt32 defaultBlockSize = (UInt32)(Int32)-1; - - const CArcInfoEx &ai = Get_ArcInfoEx(); - - /* - if (usePrevDictionary) - defaultBlockSize = GetBlockSizeSpec(); - else - */ - { - const int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (IsMethodEqualTo(fo.Method)) - defaultBlockSize = fo.BlockLogSize; - } - } - - const bool is7z = ai.Is_7z(); - - const UInt64 cs = Get_Lzma2_ChunkSize(dict); - - // Solid Block Size - UInt64 blockSize = cs; // for xz - - if (is7z) - { - // we use same default block sizes as defined in 7z encoder - UInt64 kMaxSize = (UInt64)1 << 32; - const int methodId = GetMethodID(); - if (methodId == kLZMA2) - { - blockSize = cs << 6; - kMaxSize = (UInt64)1 << 34; - } - else - { - UInt64 dict2 = dict; - if (methodId == kBZip2) - { - dict2 /= 100000; - if (dict2 < 1) - dict2 = 1; - dict2 *= 100000; - } - blockSize = dict2 << 7; - } - - const UInt32 kMinSize = (UInt32)1 << 24; - if (blockSize < kMinSize) blockSize = kMinSize; - if (blockSize > kMaxSize) blockSize = kMaxSize; - } - - _auto_Solid = blockSize; - - int curSel; - { - AString s; - Add_Size(s, _auto_Solid); - Modify_Auto(s); - const int index = (int)ComboBox_AddStringAscii(m_Solid, s); - m_Solid.SetItemData(index, (LPARAM)(UInt32)(Int32)-1); - curSel = index; - } - - if (is7z) - { - UString s ('-'); - // kSolidLog_NoSolid = 0 for xz means default blockSize - if (is7z) - LangString(IDS_COMPRESS_NON_SOLID, s); - const int index = (int)m_Solid.AddString(s); - m_Solid.SetItemData(index, (LPARAM)(UInt32)kSolidLog_NoSolid); - if (defaultBlockSize == kSolidLog_NoSolid) - curSel = index; - } - - for (unsigned i = 20; i <= 36; i++) - { - AString s; - Add_Size(s, (UInt64)1 << i); - const int index = (int)ComboBox_AddStringAscii(m_Solid, s); - m_Solid.SetItemData(index, (LPARAM)(UInt32)i); - if (defaultBlockSize != (UInt32)(Int32)-1) - if (i <= defaultBlockSize || index <= 1) - curSel = index; - } - - { - const int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); - m_Solid.SetItemData(index, (LPARAM)kSolidLog_FullSolid); - if (defaultBlockSize == kSolidLog_FullSolid) - curSel = index; - } - - m_Solid.SetCurSel(curSel); -} - - -/* -static void ZstdEncProps_SetDictProps_From_CompressDialog(CZstdEncProps *props, CCompressDialog &cd) -{ - { - const UInt64 d64 = cd.GetDictSpec(); - UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog - if (d64 != (UInt64)(Int64)-1) - { - d32 = (UInt32)d64; - if (d32 != d64) - d32 = (UInt32)(Int32)-2; - } - ZstdEncProps_Set_WindowSize(props, d32); - } - { - const UInt64 d64 = cd.GetDictChainSpec(); - UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog_Chain - if (d64 != (UInt64)(Int64)-1) - { - d32 = (UInt32)d64; - if (d32 != d64) - d32 = (UInt32)(Int32)-2; - } - ZstdEncProps_Set_WindowChainSize(props, d32); - } -} - -static bool Is_Zstd_Mt_Supported() -{ - if (!GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "InitializeConditionVariable")) - return false; - return true; -} -*/ - -static const char *k_ST_Threads = " (ST)"; - -void CCompressDialog::SetNumThreads2() -{ - _auto_NumThreads = 1; - - m_NumThreads.ResetContent(); - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - if (!fi.MultiThread_()) - return; - - const UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); - // 64; // for debug: - - UInt32 defaultValue = numHardwareThreads; - bool useAutoThreads = true; - - { - const CArcInfoEx &ai = Get_ArcInfoEx(); - int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - if (IsMethodEqualTo(fo.Method) && fo.NumThreads != (UInt32)(Int32)-1) - { - defaultValue = fo.NumThreads; - useAutoThreads = false; - } - } - } - - // const UInt32 num_ZSTD_threads_MAX = Is_Zstd_Mt_Supported() ? MY_ZSTDMT_NBWORKERS_MAX : 0; - - UInt32 numAlgoThreadsMax = numHardwareThreads * 2; - const int methodID = GetMethodID(); - - switch (methodID) - { - case kLZMA: numAlgoThreadsMax = 2; break; - case kLZMA2: numAlgoThreadsMax = 256; break; - case kBZip2: numAlgoThreadsMax = 32; break; - // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; - case kCopy: - case kPPMd: - case kDeflate: - case kDeflate64: - case kPPMdZip: - numAlgoThreadsMax = 1; - } - const bool isZip = IsZipFormat(); - if (isZip) - { - numAlgoThreadsMax = - #ifdef _WIN32 - 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here - #else - 128; - #endif - } - - UInt32 autoThreads = numHardwareThreads; - if (autoThreads > numAlgoThreadsMax) - autoThreads = numAlgoThreadsMax; - - const UInt64 memUse_Limit = Get_MemUse_Bytes(); - - if (_ramSize_Defined) - if (autoThreads > 1 - // || (autoThreads == 0 && methodID == kZSTD) - ) - { - if (isZip) - { - for (; autoThreads > 1; autoThreads--) - { - const UInt64 dict64 = GetDict2(); - UInt64 decompressMemory; - const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory); - if (usage <= memUse_Limit) - break; - } - } - else if (methodID == kLZMA2) - { - const UInt64 dict64 = GetDict2(); - const UInt32 numThreads1 = (GetLevel2() >= 5 ? 2 : 1); - UInt32 numBlockThreads = autoThreads / numThreads1; - for (; numBlockThreads > 1; numBlockThreads--) - { - autoThreads = numBlockThreads * numThreads1; - UInt64 decompressMemory; - const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory); - if (usage <= memUse_Limit) - break; - } - autoThreads = numBlockThreads * numThreads1; - } - /* - else if (methodID == kZSTD) - { - if (num_ZSTD_threads_MAX != 0) - { - CZstdEncProps props; - ZstdEncProps_Init(&props); - // props.level_zstd = level; - props.level_7z = GetLevel2(); - ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this); - autoThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(&props, memUse_Limit, autoThreads); - } - } - */ - } - - _auto_NumThreads = autoThreads; - - int curSel = -1; - { - AString s; - s.Add_UInt32(autoThreads); - if (autoThreads == 0) s += k_ST_Threads; - Modify_Auto(s); - const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); - m_NumThreads.SetItemData(index, (LPARAM)(INT_PTR)(-1)); - // m_NumThreads.SetItemData(index, autoThreads); - if (useAutoThreads) - curSel = index; - } - - if (numAlgoThreadsMax != autoThreads || autoThreads != 1) - for (UInt32 i = - // (methodID == kZSTD) ? 0 : - 1; - i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) - { - AString s; - s.Add_UInt32(i); - if (i == 0) s += k_ST_Threads; - const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); - m_NumThreads.SetItemData(index, (LPARAM)(UInt32)i); - if (!useAutoThreads && i == defaultValue) - curSel = index; - } - - m_NumThreads.SetCurSel(curSel); -} - - -static void AddMemSize(UString &res, UInt64 size) -{ - char c; - unsigned moveBits = 0; - if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0) - { moveBits = 30; c = 'G'; } - else // if (size >= ((UInt32)1 << 21) && (size & 0xFFFFF) == 0) - { moveBits = 20; c = 'M'; } - // else { moveBits = 10; c = 'K'; } - res.Add_UInt64(size >> moveBits); - res.Add_Space(); - if (moveBits != 0) - res.Add_Char(c); - res.Add_Char('B'); -} - - -int CCompressDialog::AddMemComboItem(UInt64 val, bool isPercent, bool isDefault) -{ - UString sUser; - UString sRegistry; - if (isPercent) - { - UString s; - s.Add_UInt64(val); - s.Add_Char('%'); - if (isDefault) - sUser = k_Auto_Prefix; - else - sRegistry = s; - sUser += s; - } - else - { - AddMemSize(sUser, val); - sRegistry = sUser; - for (;;) - { - const int pos = sRegistry.Find(L' '); - if (pos < 0) - break; - sRegistry.Delete(pos); - } - if (!sRegistry.IsEmpty()) - if (sRegistry.Back() == 'B') - sRegistry.DeleteBack(); - } - const unsigned dataIndex = _memUse_Strings.Add(sRegistry); - const int index = (int)m_MemUse.AddString(sUser); - m_MemUse.SetItemData(index, (LPARAM)dataIndex); - return index; -} - - - -void CCompressDialog::SetMemUseCombo() -{ - _memUse_Strings.Clear(); - m_MemUse.ResetContent(); - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - - { - const bool enable = fi.MemUse_(); - ShowItem_Bool(IDT_COMPRESS_MEMORY, enable); - ShowItem_Bool(IDT_COMPRESS_MEMORY_VALUE, enable); - ShowItem_Bool(IDT_COMPRESS_MEMORY_DE, enable); - ShowItem_Bool(IDT_COMPRESS_MEMORY_DE_VALUE, enable); - ShowItem_Bool(IDC_COMPRESS_MEM_USE, enable); - EnableItem(IDC_COMPRESS_MEM_USE, enable); - if (!enable) - return; - } - - UInt64 curMem_Bytes = 0; - UInt64 curMem_Percents = 0; - bool needSetCur_Bytes = false; - bool needSetCur_Percents = false; - { - const NCompression::CFormatOptions &fo = Get_FormatOptions(); - if (!fo.MemUse.IsEmpty()) - { - NCompression::CMemUse mu; - mu.Parse(fo.MemUse); - if (mu.IsDefined) - { - if (mu.IsPercent) - { - curMem_Percents = mu.Val; - needSetCur_Percents = true; - } - else - { - curMem_Bytes = mu.GetBytes(_ramSize_Reduced); - needSetCur_Bytes = true; - } - } - } - } - - - // 80% - is auto usage limit in handlers - AddMemComboItem(80, true, true); - m_MemUse.SetCurSel(0); - - { - for (unsigned i = 10;; i += 10) - { - UInt64 size = i; - if (i > 100) - size = (UInt64)(Int64)-1; - if (needSetCur_Percents && size >= curMem_Percents) - { - const int index = AddMemComboItem(curMem_Percents, true); - m_MemUse.SetCurSel(index); - needSetCur_Percents = false; - if (size == curMem_Percents) - continue; - } - if (size == (UInt64)(Int64)-1) - break; - AddMemComboItem(size, true); - } - } - { - for (unsigned i = (27) * 2;; i++) - { - UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2); - if (i > (20 + sizeof(size_t) * 3 - 1) * 2) - size = (UInt64)(Int64)-1; - if (needSetCur_Bytes && size >= curMem_Bytes) - { - const int index = AddMemComboItem(curMem_Bytes); - m_MemUse.SetCurSel(index); - needSetCur_Bytes = false; - if (size == curMem_Bytes) - continue; - } - if (size == (UInt64)(Int64)-1) - break; - AddMemComboItem(size); - } - } -} - - -UString CCompressDialog::Get_MemUse_Spec() -{ - if (m_MemUse.GetCount() < 1) - return UString(); - return _memUse_Strings[(unsigned)m_MemUse.GetItemData_of_CurSel()]; -} - - -UInt64 CCompressDialog::Get_MemUse_Bytes() -{ - const UString mus = Get_MemUse_Spec(); - NCompression::CMemUse mu; - if (!mus.IsEmpty()) - { - mu.Parse(mus); - if (mu.IsDefined) - return mu.GetBytes(_ramSize_Reduced); - } - return _ramUsage_Auto; // _ramSize_Reduced; // _ramSize;; -} - - - -UInt64 CCompressDialog::GetMemoryUsage_DecompMem(UInt64 &decompressMemory) -{ - return GetMemoryUsage_Dict_DecompMem(GetDict2(), decompressMemory); -} - - -/* -we could use that function to reduce the dictionary if small RAM -UInt64 CCompressDialog::GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64) -{ - UInt64 decompressMemory; - return GetMemoryUsage_Threads_Dict_DecompMem(numThreads, dict64, decompressMemory); -} -*/ - - -UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &decompressMemory) -{ - return GetMemoryUsage_Threads_Dict_DecompMem(GetNumThreads2(), dict64, decompressMemory); -} - -UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict64, UInt64 &decompressMemory) -{ - decompressMemory = (UInt64)(Int64)-1; - - const UInt32 level = GetLevel2(); - if (level == 0 && !Get_ArcInfoEx().Is_Zstd()) - { - decompressMemory = (1 << 20); - return decompressMemory; - } - UInt64 size = 0; - - const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; - if (fi.Filter_() && level >= 9) - size += (12 << 20) * 2 + (5 << 20); - // UInt32 numThreads = GetNumThreads2(); - - UInt32 numMainZipThreads = 1; - - if (IsZipFormat()) - { - UInt32 numSubThreads = 1; - if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5) - numSubThreads = 2; - numMainZipThreads = numThreads / numSubThreads; - if (numMainZipThreads > 1) - size += (UInt64)numMainZipThreads * ((size_t)sizeof(size_t) << 23); - else - numMainZipThreads = 1; - } - - const int methodId = GetMethodID(); - - if (dict64 == (UInt64)(Int64)-1 - // && methodId != kZSTD - ) - return (UInt64)(Int64)-1; - - - switch (methodId) - { - case kLZMA: - case kLZMA2: - { - const UInt32 dict = (dict64 >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dict64); - UInt32 hs = dict - 1; - hs |= (hs >> 1); - hs |= (hs >> 2); - hs |= (hs >> 4); - hs |= (hs >> 8); - hs >>= 1; - if (hs >= (1 << 24)) - hs >>= 1; - hs |= (1 << 16) - 1; - // if (numHashBytes >= 5) - if (level < 5) - hs |= (256 << 10) - 1; - hs++; - UInt64 size1 = (UInt64)hs * 4; - size1 += (UInt64)dict * 4; - if (level >= 5) - size1 += (UInt64)dict * 4; - size1 += (2 << 20); - - UInt32 numThreads1 = 1; - if (numThreads > 1 && level >= 5) - { - size1 += (2 << 20) + (4 << 20); - numThreads1 = 2; - } - - UInt32 numBlockThreads = numThreads / numThreads1; - - UInt64 chunkSize = 0; // it's solid chunk - - if (methodId != kLZMA && numBlockThreads != 1) - { - chunkSize = Get_Lzma2_ChunkSize(dict); - - if (IsXzFormat()) - { - UInt32 blockSizeLog = GetBlockSizeSpec(); - if (blockSizeLog != (UInt32)(Int32)-1) - { - if (blockSizeLog == kSolidLog_FullSolid) - { - numBlockThreads = 1; - chunkSize = 0; - } - else if (blockSizeLog != kSolidLog_NoSolid) - chunkSize = (UInt64)1 << blockSizeLog; - } - } - } - - if (chunkSize == 0) - { - const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); - UInt64 blockSize = (UInt64)dict + (1 << 16) - + (numThreads1 > 1 ? (1 << 20) : 0); - blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); - if (blockSize >= kBlockSizeMax) - blockSize = kBlockSizeMax; - size += numBlockThreads * (size1 + blockSize); - } - else - { - size += numBlockThreads * (size1 + chunkSize); - UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; - if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; - if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; - if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; - size += numPackChunks * chunkSize; - } - - decompressMemory = dict + (2 << 20); - return size; - } - - /* - case kZSTD: - { - CZstdEncProps props; - ZstdEncProps_Init(&props); - // props.level_zstd = level; - props.level_7z = level; - props.nbWorkers = numThreads; - ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this); - ZstdEncProps_NormalizeFull(&props); - size = ZstdEncProps_GetMemUsage(&props); - decompressMemory = (UInt64)1 << props.windowLog; - return size; - } - */ - - case kPPMd: - { - decompressMemory = dict64 + (2 << 20); - return size + decompressMemory; - } - - case kDeflate: - case kDeflate64: - { - UInt64 size1 = 3 << 20; - // if (level >= 7) - size1 += (1 << 20); - size += size1 * numMainZipThreads; - decompressMemory = (2 << 20); - return size; - } - - case kBZip2: - { - decompressMemory = (7 << 20); - UInt64 memForOneThread = (10 << 20); - return size + memForOneThread * numThreads; - } - - case kPPMdZip: - { - decompressMemory = dict64 + (2 << 20); - return size + (UInt64)decompressMemory * numThreads; - } - } - - return (UInt64)(Int64)-1; -} - - - -static void AddMemUsage(UString &s, UInt64 v) -{ - const char *post; - if (v <= ((UInt64)16 << 30)) - { - v = (v + (1 << 20) - 1) >> 20; - post = "MB"; - } - else if (v <= ((UInt64)64 << 40)) - { - v = (v + (1 << 30) - 1) >> 30; - post = "GB"; - } - else - { - const UInt64 v2 = v + ((UInt64)1 << 40) - 1; - if (v <= v2) - v = v2; - v >>= 40; - post = "TB"; - } - s.Add_UInt64(v); - s.Add_Space(); - s += post; -} - - -void CCompressDialog::PrintMemUsage(UINT res, UInt64 value) -{ - if (value == (UInt64)(Int64)-1) - { - SetItemText(res, TEXT("?")); - return; - } - UString s; - AddMemUsage(s, value); - if (res == IDT_COMPRESS_MEMORY_VALUE) - { - const UString mus = Get_MemUse_Spec(); - NCompression::CMemUse mu; - if (!mus.IsEmpty()) - mu.Parse(mus); - if (mu.IsDefined) - { - s += " / "; - AddMemUsage(s, mu.GetBytes(_ramSize_Reduced)); - } - else if (_ramSize_Defined) - { - s += " / "; - AddMemUsage(s, _ramUsage_Auto); - } - - if (_ramSize_Defined) - { - s += " / "; - AddMemUsage(s, _ramSize); - } - } - SetItemText(res, s); -} - - -void CCompressDialog::SetMemoryUsage() -{ - UInt64 decompressMem; - const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem); - PrintMemUsage(IDT_COMPRESS_MEMORY_VALUE, memUsage); - PrintMemUsage(IDT_COMPRESS_MEMORY_DE_VALUE, decompressMem); - #ifdef PRINT_PARAMS - Print_Params(); - #endif -} - - - -#ifdef PRINT_PARAMS - -static const char kPropDelimeter = ' '; // ':' - -static void AddPropName(AString &s, const char *name) -{ - if (!s.IsEmpty()) - s += kPropDelimeter; - s += name; -} - -static void AddProp(AString &s, const char *name, unsigned v) -{ - AddPropName(s, name); - s.Add_UInt32(v); -} - -static void AddProp_switch(AString &s, const char *name, E_ZSTD_paramSwitch_e e) -{ - AddPropName(s, name); - s += e == k_ZSTD_ps_enable ? "" : "-"; -} - -static void PrintPropAsLog(AString &s, const char *name, size_t v) -{ - AddPropName(s, name); - for (unsigned i = 0; i < sizeof(size_t) * 8; i++) - { - if (((size_t)1 << i) == v) - { - s.Add_UInt32(i); - return; - } - } - char c = 'b'; - if ((v & 0x3FFFFFFF) == 0) { v >>= 30; c = 'G'; } - else if ((v & 0xFFFFF) == 0) { v >>= 20; c = 'M'; } - else if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; } - s.Add_UInt64(v); - s += c; -} - -static void ZstdEncProps_Print(CZstdEncProps *props, AString &s) -{ - if (props->level_zstd >= 0) - AddProp(s, "zx", props->level_zstd); - else - AddProp(s, "zf", -(props->level_zstd)); - AddProp(s, "a", props->strategy); - AddProp(s, "d", props->windowLog); - AddProp(s, "zclog", props->chainLog); - AddProp(s, "zhb", props->hashLog); - AddProp(s, "mml", props->minMatch); - AddProp(s, "mcb", props->searchLog); - AddProp(s, "fb", props->targetLength); - AddProp(s, "mt", props->nbWorkers); - PrintPropAsLog(s, "c", props->jobSize); - AddProp(s, "zov", props->overlapLog); - PrintPropAsLog(s, "ztps", props->targetPrefixSize); - AddProp_switch(s, "zmfr", props->useRowMatchFinder); - if (props->ldmParams.enableLdm == k_ZSTD_ps_enable) - { - AddProp_switch(s, "zle", props->ldmParams.enableLdm); - AddProp(s, "zlhb", props->ldmParams.hashLog); - AddProp(s, "zlbb", props->ldmParams.bucketSizeLog); - AddProp(s, "zlmml", props->ldmParams.minMatchLength); - AddProp(s, "zlhrb", props->ldmParams.hashRateLog); - } -} - -void CCompressDialog::Print_Params() -{ - { - CZstdEncProps props; - ZstdEncProps_Init(&props); - // props.level_zstd = level; - props.level_7z = GetLevel2(); - ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this); - { - UInt32 order = GetOrderSpec(); - if (order != (UInt32)(Int32)-1) - props.targetLength = GetOrderSpec(); - } - props.nbWorkers = GetNumThreads2(); - // props.windowLog = 18; // for debug - ZstdEncProps_NormalizeFull(&props); - AString s; - ZstdEncProps_Print(&props, s); - SetItemTextA(IDT_COMPRESS_PARAMS_INFO, s); - } -} - -#endif // PRINT_PARAMS - - - -void CCompressDialog::SetParams() -{ - const CArcInfoEx &ai = Get_ArcInfoEx(); - m_Params.SetText(TEXT("")); - const int index = FindRegistryFormat(ai.Name); - if (index >= 0) - { - const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - m_Params.SetText(fo.Options); - } -} - -void CCompressDialog::SaveOptionsInMem() -{ - /* these options are for (Info.FormatIndex). - If it's called just after format changing, - then it's format that was selected before format changing - So we store previous format properties */ - - m_Params.GetText(Info.Options); - Info.Options.Trim(); - - const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; - const unsigned index = FindRegistryFormat_Always(ai.Name); - NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; - fo.Options = Info.Options; - fo.Level = GetLevelSpec(); - { - const UInt64 dict64 = GetDictSpec(); - UInt32 dict32; - if (dict64 == (UInt64)(Int64)-1) - dict32 = (UInt32)(Int32)-1; - else - { - dict32 = (UInt32)dict64; - if (dict64 != dict32) - { - /* here we must write 32-bit value for registry that indicates big_value - (UInt32)(Int32)-1 : is used as marker for default size - (UInt32)(Int32)-2 : it can be used to indicate big value (4 GiB) - the value must be larger than threshold - */ - dict32 = (UInt32)(Int32)-2; - // dict32 = kLzmaMaxDictSize; // it must be larger than threshold - } - } - fo.Dictionary = dict32; - } - /* - { - const UInt64 dict64 = GetDictChainSpec(); - UInt32 dict32; - if (dict64 == (UInt64)(Int64)-1) - dict32 = (UInt32)(Int32)-1; - else - { - dict32 = (UInt32)dict64; - if (dict64 != dict32) - { - dict32 = (UInt32)(Int32)-2; - // dict32 = k_Zstd_MAX_DictSize; // it must be larger than threshold - } - } - fo.DictionaryChain = dict32; - } - */ - - fo.Order = GetOrderSpec(); - fo.Method = GetMethodSpec(); - fo.EncryptionMethod = GetEncryptionMethodSpec(); - fo.NumThreads = GetNumThreadsSpec(); - fo.BlockLogSize = GetBlockSizeSpec(); - fo.MemUse = Get_MemUse_Spec(); -} - - -unsigned CCompressDialog::GetFormatIndex() -{ - return (unsigned)m_Format.GetItemData_of_CurSel(); -} - - - -static void AddText_from_BoolPair(AString &s, const char *name, const CBoolPair &bp) -{ - if (bp.Def) - { - s.Add_OptSpaced(name); - if (!bp.Val) - s += "-"; - } - /* - else if (bp.Val) - { - s.Add_OptSpaced("["); - s += name; - s += "]"; - } - */ -} - - -static void AddText_from_Bool1(AString &s, const char *name, const CBool1 &b) -{ - if (b.Supported && b.Val) - s.Add_OptSpaced(name); -} - - -void CCompressDialog::ShowOptionsString() -{ - NCompression::CFormatOptions &fo = Get_FormatOptions(); - - AString s; - if (fo.IsSet_TimePrec()) - { - s.Add_OptSpaced("tp"); - s.Add_UInt32(fo.TimePrec); - } - AddText_from_BoolPair(s, "tm", fo.MTime); - AddText_from_BoolPair(s, "tc", fo.CTime); - AddText_from_BoolPair(s, "ta", fo.ATime); - AddText_from_BoolPair(s, "-stl", fo.SetArcMTime); - - // const CArcInfoEx &ai = Get_ArcInfoEx(); - AddText_from_Bool1(s, "SL", SymLinks); - AddText_from_Bool1(s, "HL", HardLinks); - AddText_from_Bool1(s, "AS", AltStreams); - AddText_from_Bool1(s, "Sec", NtSecurity); - - // AddText_from_Bool1(s, "Preserve", PreserveATime); - - SetItemText(IDT_COMPRESS_OPTIONS, GetUnicodeString(s)); -} - - - - - -// ---------- OPTIONS ---------- - - -void COptionsDialog::CheckButton_Bool1(UINT id, const CBool1 &b1) -{ - CheckButton(id, b1.Val); -} - -void COptionsDialog::GetButton_Bool1(UINT id, CBool1 &b1) -{ - b1.Val = IsButtonCheckedBool(id); -} - - -void COptionsDialog::CheckButton_BoolBox( - bool supported, const CBoolPair &b2, CBoolBox &bb) -{ - const bool isSet = b2.Def; - const bool val = isSet ? b2.Val : bb.DefaultVal; - - bb.IsSupported = supported; - - CheckButton (bb.Set_Id, isSet); - ShowItem_Bool (bb.Set_Id, supported); - CheckButton (bb.Id, val); - EnableItem (bb.Id, isSet); - ShowItem_Bool (bb.Id, supported); -} - -void COptionsDialog::GetButton_BoolBox(CBoolBox &bb) -{ - // we save value for invisible buttons too - bb.BoolPair.Val = IsButtonCheckedBool (bb.Id); - bb.BoolPair.Def = IsButtonCheckedBool (bb.Set_Id); -} - - -void COptionsDialog::Store_TimeBoxes() -{ - TimePrec = GetPrecSpec(); - GetButton_BoolBox (MTime); - GetButton_BoolBox (CTime); - GetButton_BoolBox (ATime); - GetButton_BoolBox (ZTime); -} - - -UInt32 COptionsDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) -{ - if (c.GetCount() <= defMax) - return (UInt32)(Int32)-1; - return (UInt32)c.GetItemData_of_CurSel(); -} - -static const unsigned kTimePrec_Win = 0; -static const unsigned kTimePrec_Unix = 1; -static const unsigned kTimePrec_DOS = 2; -static const unsigned kTimePrec_1ns = 3; - -static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL) -{ - // s += " : "; - { - AString s2; - s2.Add_UInt32(val); - s += s2; - } - s.Add_Space(); - s += unit; - if (sys) - { - s += " : "; - s += sys; - } -} - -int COptionsDialog::AddPrec(unsigned prec, bool isDefault) -{ - UString s; - UInt32 writePrec = prec; - if (isDefault) - { - // s += "* "; - // writePrec = (UInt32)(Int32)-1; - } - if (prec == kTimePrec_Win) AddTimeOption(s, 100, NsString, "Windows"); - else if (prec == kTimePrec_Unix) AddTimeOption(s, 1, SecString, "Unix"); - else if (prec == kTimePrec_DOS) AddTimeOption(s, 2, SecString, "DOS"); - else if (prec == kTimePrec_1ns) AddTimeOption(s, 1, NsString, "Linux"); - else if (prec == k_PropVar_TimePrec_Base) AddTimeOption(s, 1, SecString); - else if (prec >= k_PropVar_TimePrec_Base) - { - UInt32 d = 1; - for (unsigned i = prec; i < k_PropVar_TimePrec_Base + 9; i++) - d *= 10; - AddTimeOption(s, d, NsString); - } - else - s.Add_UInt32(prec); - const int index = (int)m_Prec.AddString(s); - m_Prec.SetItemData(index, (LPARAM)writePrec); - return index; -} - - -void COptionsDialog::SetPrec() -{ - // const CFormatInfo &fi = g_Formats[cd->GetStaticFormatIndex()]; - const CArcInfoEx &ai = cd->Get_ArcInfoEx(); - - // UInt32 flags = fi.Flags; - - UInt32 flags = ai.Get_TimePrecFlags(); - UInt32 defaultPrec = ai.Get_DefaultTimePrec(); - if (defaultPrec != 0) - flags |= ((UInt32)1 << defaultPrec); - - // const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); - - // unsigned defaultPrec = kTimePrec_Win; - - if (ai.Is_GZip()) - defaultPrec = kTimePrec_Unix; - - { - UString s; - s += GetNameOfProperty(kpidType, L"type"); - s += ": "; - s += ai.Name; - if (ai.Is_Tar()) - { - const int methodID = cd->GetMethodID(); - - // for debug - // defaultPrec = kTimePrec_Unix; - // flags = (UInt32)1 << kTimePrec_Unix; - - s.Add_Colon(); - if (methodID >= 0 && (unsigned)methodID < Z7_ARRAY_SIZE(kMethodsNames)) - s += kMethodsNames[methodID]; - if (methodID == kPosix) - { - // for debug - // flags |= (UInt32)1 << kTimePrec_Win; - // flags |= (UInt32)1 << kTimePrec_1ns; - } - } - else - { - // if (is_for_MethodChanging) return; - } - - SetItemText(IDT_COMPRESS_TIME_INFO, s); - } - - m_Prec.ResetContent(); - _auto_Prec = defaultPrec; - - unsigned selectedPrec = defaultPrec; - { - // if (TimePrec >= kTimePrec_Win && TimePrec <= kTimePrec_DOS) - if ((Int32)TimePrec >= 0) - selectedPrec = TimePrec; - } - - int curSel = -1; - int defaultPrecIndex = -1; - for (unsigned prec = 0; - // prec <= k_PropVar_TimePrec_HighPrec; - prec <= k_PropVar_TimePrec_1ns; - prec++) - { - if (((flags >> prec) & 1) == 0) - continue; - const bool isDefault = (defaultPrec == prec); - const int index = AddPrec(prec, isDefault); - if (isDefault) - defaultPrecIndex = index; - if (selectedPrec == prec) - curSel = index; - } - - if (curSel < 0 && selectedPrec > kTimePrec_DOS) - curSel = AddPrec(selectedPrec, false); // isDefault - if (curSel < 0) - curSel = defaultPrecIndex; - if (curSel >= 0) - m_Prec.SetCurSel(curSel); - - { - const bool isSet = IsSet_TimePrec(); - const int count = m_Prec.GetCount(); - const bool showPrec = (count != 0); - ShowItem_Bool(IDC_COMPRESS_TIME_PREC, showPrec); - ShowItem_Bool(IDT_COMPRESS_TIME_PREC, showPrec); - EnableItem(IDC_COMPRESS_TIME_PREC, isSet && (count > 1)); - - CheckButton(IDX_COMPRESS_PREC_SET, isSet); - const bool setIsSupported = isSet || (count > 1); - EnableItem(IDX_COMPRESS_PREC_SET, setIsSupported); - ShowItem_Bool(IDX_COMPRESS_PREC_SET, setIsSupported); - } - - SetTimeMAC(); -} - - -void COptionsDialog::SetTimeMAC() -{ - const CArcInfoEx &ai = cd->Get_ArcInfoEx(); - - const - bool m_allow = ai.Flags_MTime(); - bool c_allow = ai.Flags_CTime(); - bool a_allow = ai.Flags_ATime(); - - if (ai.Is_Tar()) - { - const int methodID = cd->GetMethodID(); - c_allow = false; - a_allow = false; - if (methodID == kPosix) - { - // c_allow = true; // do we need it as change time ? - a_allow = true; - } - } - - if (ai.Is_Zip()) - { - // const int methodID = GetMethodID(); - UInt32 prec = GetPrec(); - if (prec == (UInt32)(Int32)-1) - prec = _auto_Prec; - if (prec != kTimePrec_Win) - { - c_allow = false; - a_allow = false; - } - } - - - /* - MTime.DefaultVal = true; - CTime.DefaultVal = false; - ATime.DefaultVal = false; - */ - - MTime.DefaultVal = ai.Flags_MTime_Default(); - CTime.DefaultVal = ai.Flags_CTime_Default(); - ATime.DefaultVal = ai.Flags_ATime_Default(); - - ZTime.DefaultVal = false; - - const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); - - CheckButton_BoolBox (m_allow, fo.MTime, MTime ); - CheckButton_BoolBox (c_allow, fo.CTime, CTime ); - CheckButton_BoolBox (a_allow, fo.ATime, ATime ); - CheckButton_BoolBox (true, fo.SetArcMTime, ZTime); - - if (m_allow && !fo.MTime.Def) - { - const bool isSingleFile = ai.Flags_KeepName(); - if (!isSingleFile) - { - // we can hide changing checkboxes for MTime here: - ShowItem_Bool (MTime.Set_Id, false); - EnableItem (MTime.Id, false); - } - } - // On_CheckBoxSet_Prec_Clicked(); - // const bool isSingleFile = ai.Flags_KeepName(); - // mtime for Gz can be -} - - - -void COptionsDialog::On_CheckBoxSet_Prec_Clicked() -{ - const bool isSet = IsButtonCheckedBool(IDX_COMPRESS_PREC_SET); - if (!isSet) - { - // We save current MAC boxes to memory before SetPrec() - Store_TimeBoxes(); - Reset_TimePrec(); - SetPrec(); - } - EnableItem(IDC_COMPRESS_TIME_PREC, isSet); -} - -void COptionsDialog::On_CheckBoxSet_Clicked(const CBoolBox &bb) -{ - const bool isSet = IsButtonCheckedBool(bb.Set_Id); - if (!isSet) - CheckButton(bb.Id, bb.DefaultVal); - EnableItem(bb.Id, isSet); -} - - - - -#ifdef Z7_LANG -static const UInt32 kLangIDs_Options[] = -{ - IDX_COMPRESS_NT_SYM_LINKS, - IDX_COMPRESS_NT_HARD_LINKS, - IDX_COMPRESS_NT_ALT_STREAMS, - IDX_COMPRESS_NT_SECUR, - - IDG_COMPRESS_TIME, - IDT_COMPRESS_TIME_PREC, - IDX_COMPRESS_MTIME, - IDX_COMPRESS_CTIME, - IDX_COMPRESS_ATIME, - IDX_COMPRESS_ZTIME, - IDX_COMPRESS_PRESERVE_ATIME -}; -#endif - - -bool COptionsDialog::OnInit() -{ - #ifdef Z7_LANG - LangSetWindowText(*this, IDB_COMPRESS_OPTIONS); // IDS_OPTIONS - LangSetDlgItems(*this, kLangIDs_Options, Z7_ARRAY_SIZE(kLangIDs_Options)); - // LangSetDlgItemText(*this, IDB_COMPRESS_TIME_DEFAULT, IDB_COMPRESS_TIME_DEFAULT); - // LangSetDlgItemText(*this, IDX_COMPRESS_TIME_DEFAULT, IDX_COMPRESS_TIME_DEFAULT); - #endif - - LangString(IDS_COMPRESS_SEC, SecString); - if (SecString.IsEmpty()) - SecString = "sec"; - LangString(IDS_COMPRESS_NS, NsString); - if (NsString.IsEmpty()) - NsString = "ns"; - - { - // const CArcInfoEx &ai = cd->Get_ArcInfoEx(); - - ShowItem_Bool ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks.Supported); - ShowItem_Bool ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks.Supported); - ShowItem_Bool ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams.Supported); - ShowItem_Bool ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity.Supported); - - ShowItem_Bool ( IDG_COMPRESS_NTFS, - cd->SymLinks.Supported - || cd->HardLinks.Supported - || cd->AltStreams.Supported - || cd->NtSecurity.Supported); - } - - /* we read property from two sources: - 1) command line : (Info) - 2) registry : (m_RegistryInfo) - (Info) has priority, if both are no defined */ - - CheckButton_Bool1 ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks); - CheckButton_Bool1 ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks); - CheckButton_Bool1 ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams); - CheckButton_Bool1 ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity); - - CheckButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime); - - m_Prec.Attach (GetItem(IDC_COMPRESS_TIME_PREC)); - - MTime.SetIDs ( IDX_COMPRESS_MTIME, IDX_COMPRESS_MTIME_SET); - CTime.SetIDs ( IDX_COMPRESS_CTIME, IDX_COMPRESS_CTIME_SET); - ATime.SetIDs ( IDX_COMPRESS_ATIME, IDX_COMPRESS_ATIME_SET); - ZTime.SetIDs ( IDX_COMPRESS_ZTIME, IDX_COMPRESS_ZTIME_SET); - - { - const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); - TimePrec = fo.TimePrec; - MTime.BoolPair = fo.MTime; - CTime.BoolPair = fo.CTime; - ATime.BoolPair = fo.ATime; - ZTime.BoolPair = fo.SetArcMTime; - } - - SetPrec(); - - NormalizePosition(); - - return CModalDialog::OnInit(); -} - - -bool COptionsDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == CBN_SELCHANGE) - { - switch (itemID) - { - case IDC_COMPRESS_TIME_PREC: - { - Store_TimeBoxes(); - SetTimeMAC(); // for zip/tar - return true; - } - } - } - return CModalDialog::OnCommand(code, itemID, lParam); -} - - -bool COptionsDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDX_COMPRESS_PREC_SET: { On_CheckBoxSet_Prec_Clicked(); return true; } - case IDX_COMPRESS_MTIME_SET: { On_CheckBoxSet_Clicked (MTime); return true; } - case IDX_COMPRESS_CTIME_SET: { On_CheckBoxSet_Clicked (CTime); return true; } - case IDX_COMPRESS_ATIME_SET: { On_CheckBoxSet_Clicked (ATime); return true; } - case IDX_COMPRESS_ZTIME_SET: { On_CheckBoxSet_Clicked (ZTime); return true; } - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - - -void COptionsDialog::OnOK() -{ - GetButton_Bool1 (IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks); - GetButton_Bool1 (IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks); - GetButton_Bool1 (IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams); - GetButton_Bool1 (IDX_COMPRESS_NT_SECUR, cd->NtSecurity); - GetButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime); - - Store_TimeBoxes(); - { - NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); - fo.TimePrec = TimePrec; - fo.MTime = MTime.BoolPair; - fo.CTime = CTime.BoolPair; - fo.ATime = ATime.BoolPair; - fo.SetArcMTime = ZTime.BoolPair; - } - - CModalDialog::OnOK(); -} - -void COptionsDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic_Options); -} +// CompressDialog.cpp + +#include "StdAfx.h" + +#include "../../../../C/CpuArch.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/System.h" + +#include "../../Common/MethodProps.h" + +#include "../FileManager/BrowseDialog.h" +#include "../FileManager/FormatUtils.h" +#include "../FileManager/HelpUtils.h" +#include "../FileManager/PropertyName.h" +#include "../FileManager/SplitUtils.h" +#include "../FileManager/resourceGui.h" + +#include "../Explorer/MyMessages.h" + +#include "../Common/ZipRegistry.h" + +#include "CompressDialog.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +#include "../FileManager/LangUtils.h" + +#include "CompressDialogRes.h" +#include "ExtractRes.h" +#include "resource2.h" + +// #define PRINT_PARAMS + +#ifdef Z7_LANG + +// #define IDS_OPTIONS 2100 + +static const UInt32 kLangIDs[] = +{ + IDT_COMPRESS_ARCHIVE, + IDT_COMPRESS_UPDATE_MODE, + IDT_COMPRESS_FORMAT, + IDT_COMPRESS_LEVEL, + IDT_COMPRESS_METHOD, + IDT_COMPRESS_DICTIONARY, + IDT_COMPRESS_ORDER, + IDT_COMPRESS_SOLID, + IDT_COMPRESS_THREADS, + IDT_COMPRESS_PARAMETERS, + + IDB_COMPRESS_OPTIONS, // IDS_OPTIONS + + IDG_COMPRESS_OPTIONS, + IDX_COMPRESS_SFX, + IDX_COMPRESS_SHARED, + IDX_COMPRESS_DEL, + + IDT_COMPRESS_MEMORY, + IDT_COMPRESS_MEMORY_DE, + + IDG_COMPRESS_ENCRYPTION, + IDT_COMPRESS_ENCRYPTION_METHOD, + IDX_COMPRESS_ENCRYPT_FILE_NAMES, + + IDT_PASSWORD_ENTER, + IDT_PASSWORD_REENTER, + IDX_PASSWORD_SHOW, + + IDT_SPLIT_TO_VOLUMES, + IDT_COMPRESS_PATH_MODE, +}; +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NName; +using namespace NDir; + +static const unsigned kHistorySize = 20; + +static const UInt32 kSolidLog_NoSolid = 0; +static const UInt32 kSolidLog_FullSolid = 64; + +static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28; + +static const UINT k_Message_ArcChanged = WM_APP + 1; + +/* +static const UInt32 kZstd_MAX_DictSize = (UInt32)1 << MY_ZSTD_WINDOWLOG_MAX; +*/ + +/* The top value for windowLog_Chain: + (MY_ZSTD_CHAINLOG_MAX - 1): in BT mode + (MY_ZSTD_CHAINLOG_MAX) : in non-BT mode. But such big value is useless in most cases. + So we always reduce top value to (MY_ZSTD_CHAINLOG_MAX - 1) */ +/* +static const unsigned kMaxDictChain = MY_ZSTD_CHAINLOG_MAX - 1; +static const UInt32 kZstd_MAX_DictSize_Chain = (UInt32)1 << kMaxDictChain; +*/ + +static LPCSTR const kExeExt = ".exe"; + +static const UInt32 g_Levels[] = +{ + IDS_METHOD_STORE, + IDS_METHOD_FASTEST, + 0, + IDS_METHOD_FAST, + 0, + IDS_METHOD_NORMAL, + 0, + IDS_METHOD_MAXIMUM, + 0, + IDS_METHOD_ULTRA +}; + +enum EMethodID +{ + kCopy, + kLZMA, + kLZMA2, + kPPMd, + kBZip2, + kDeflate, + kDeflate64, + kPPMdZip, + // kZSTD, + kSha256, + kSha1, + kCrc32, + kCrc64, + kGnu, + kPosix +}; + +static LPCSTR const kMethodsNames[] = +{ + "Copy" + , "LZMA" + , "LZMA2" + , "PPMd" + , "BZip2" + , "Deflate" + , "Deflate64" + , "PPMd" + // , "ZSTD" + , "SHA256" + , "SHA1" + , "CRC32" + , "CRC64" + , "GNU" + , "POSIX" +}; + +static const EMethodID g_7zMethods[] = +{ + kLZMA2, + kLZMA, + kPPMd, + kBZip2 + , kDeflate + , kDeflate64 + // , kZSTD + , kCopy +}; + +static const EMethodID g_7zSfxMethods[] = +{ + kCopy, + kLZMA, + kLZMA2, + kPPMd +}; + +static const EMethodID g_ZipMethods[] = +{ + kDeflate, + kDeflate64, + kBZip2, + kLZMA, + kPPMdZip + // , kZSTD +}; + +static const EMethodID g_GZipMethods[] = +{ + kDeflate +}; + +static const EMethodID g_BZip2Methods[] = +{ + kBZip2 +}; + +static const EMethodID g_XzMethods[] = +{ + kLZMA2 +}; + +/* +static const EMethodID g_ZstdMethods[] = +{ + kZSTD +}; +*/ + +/* +static const EMethodID g_SwfcMethods[] = +{ + kDeflate + // kLZMA +}; +*/ + +static const EMethodID g_TarMethods[] = +{ + kGnu, + kPosix +}; + +static const EMethodID g_HashMethods[] = +{ + kSha256 + , kSha1 + // , kCrc32 + // , kCrc64 +}; + +static const UInt32 kFF_Filter = 1 << 0; +static const UInt32 kFF_Solid = 1 << 1; +static const UInt32 kFF_MultiThread = 1 << 2; +static const UInt32 kFF_Encrypt = 1 << 3; +static const UInt32 kFF_EncryptFileNames = 1 << 4; +static const UInt32 kFF_MemUse = 1 << 5; +static const UInt32 kFF_SFX = 1 << 6; + +/* +static const UInt32 kFF_Time_Win = 1 << 10; +static const UInt32 kFF_Time_Unix = 1 << 11; +static const UInt32 kFF_Time_DOS = 1 << 12; +static const UInt32 kFF_Time_1ns = 1 << 13; +*/ + +struct CFormatInfo +{ + LPCSTR Name; + UInt32 LevelsMask; + unsigned NumMethods; + const EMethodID *MethodIDs; + + UInt32 Flags; + + bool Filter_() const { return (Flags & kFF_Filter) != 0; } + bool Solid_() const { return (Flags & kFF_Solid) != 0; } + bool MultiThread_() const { return (Flags & kFF_MultiThread) != 0; } + bool Encrypt_() const { return (Flags & kFF_Encrypt) != 0; } + bool EncryptFileNames_() const { return (Flags & kFF_EncryptFileNames) != 0; } + bool MemUse_() const { return (Flags & kFF_MemUse) != 0; } + bool SFX_() const { return (Flags & kFF_SFX) != 0; } +}; + +#define METHODS_PAIR(x) Z7_ARRAY_SIZE(x), x + +static const CFormatInfo g_Formats[] = +{ + { + "", + // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + ((UInt32)1 << 10) - 1, + // (UInt32)(Int32)-1, + 0, NULL, + kFF_MultiThread | kFF_MemUse + }, + { + "7z", + // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + (1 << 10) - 1, + METHODS_PAIR(g_7zMethods), + kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt | + kFF_EncryptFileNames | kFF_MemUse | kFF_SFX + // | kFF_Time_Win + }, + { + "Zip", + (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_ZipMethods), + kFF_MultiThread | kFF_Encrypt | kFF_MemUse + // | kFF_Time_Win | kFF_Time_Unix | kFF_Time_DOS + }, + { + "GZip", + (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_GZipMethods), + kFF_MemUse + // | kFF_Time_Unix + }, + { + "BZip2", + (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_BZip2Methods), + kFF_MultiThread | kFF_MemUse + }, + { + "xz", + // (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + (1 << 10) - 1 - (1 << 0), // store (1 << 0) is not supported + METHODS_PAIR(g_XzMethods), + kFF_Solid | kFF_MultiThread | kFF_MemUse + }, + /* + { + "zstd", + // (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1, + (1 << (9 + 1)) - 1, + METHODS_PAIR(g_ZstdMethods), + // kFF_Solid | + kFF_MultiThread + | kFF_MemUse + }, + */ +/* + { + "Swfc", + (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), + METHODS_PAIR(g_SwfcMethods), + 0 + }, +*/ + { + "Tar", + (1 << 0), + METHODS_PAIR(g_TarMethods), + 0 + // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns + }, + { + "wim", + (1 << 0), + 0, NULL, + 0 + // | kFF_Time_Win + }, + { + "Hash", + (0 << 0), + METHODS_PAIR(g_HashMethods), + 0 + } +}; + +static bool IsMethodSupportedBySfx(int methodID) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_7zSfxMethods); i++) + if (methodID == g_7zSfxMethods[i]) + return true; + return false; +} + + +static const + // NCompressDialog::NUpdateMode::EEnum + int + k_UpdateMode_Vals[] = +{ + NCompressDialog::NUpdateMode::kAdd, + NCompressDialog::NUpdateMode::kUpdate, + NCompressDialog::NUpdateMode::kFresh, + NCompressDialog::NUpdateMode::kSync +}; + +static const UInt32 k_UpdateMode_IDs[] = +{ + IDS_COMPRESS_UPDATE_MODE_ADD, + IDS_COMPRESS_UPDATE_MODE_UPDATE, + IDS_COMPRESS_UPDATE_MODE_FRESH, + IDS_COMPRESS_UPDATE_MODE_SYNC +}; + +static const + // NWildcard::ECensorPathMode + int + k_PathMode_Vals[] = +{ + NWildcard::k_RelatPath, + NWildcard::k_FullPath, + NWildcard::k_AbsPath, +}; + +static const UInt32 k_PathMode_IDs[] = +{ + IDS_PATH_MODE_RELAT, + IDS_EXTRACT_PATHS_FULL, + IDS_EXTRACT_PATHS_ABS +}; + +void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal); + +void CCompressDialog::SetMethods(const CObjectVector &userCodecs) +{ + ExternalMethods.Clear(); + { + FOR_VECTOR (i, userCodecs) + { + const CCodecInfoUser &c = userCodecs[i]; + if (!c.EncoderIsAssigned + || !c.IsFilter_Assigned + || c.IsFilter + || c.NumStreams != 1) + continue; + unsigned k; + for (k = 0; k < Z7_ARRAY_SIZE(g_7zMethods); k++) + if (c.Name.IsEqualTo_Ascii_NoCase(kMethodsNames[g_7zMethods[k]])) + break; + if (k != Z7_ARRAY_SIZE(g_7zMethods)) + continue; + ExternalMethods.Add(c.Name); + } + } +} + + +bool CCompressDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDD_COMPRESS); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + // LangSetDlgItemText(*this, IDB_COMPRESS_OPTIONS, IDS_OPTIONS); // IDG_COMPRESS_OPTIONS + #endif + + { + size_t size = (size_t)sizeof(size_t) << 29; + _ramSize_Defined = NSystem::GetRamSize(size); + // size = (UInt64)3 << 62; // for debug only; + { + // we use reduced limit for 32-bit version: + unsigned bits = sizeof(size_t) * 8; + if (bits == 32) + { + const UInt32 limit2 = (UInt32)7 << 28; + if (size > limit2) + size = limit2; + } + } + _ramSize = size; + const size_t kMinUseSize = 1 << 26; + if (size < kMinUseSize) + size = kMinUseSize; + _ramSize_Reduced = size; + + // 80% - is auto usage limit in handlers + _ramUsage_Auto = Calc_From_Val_Percents(size, 80); + } + + _password1Control.Attach(GetItem(IDE_COMPRESS_PASSWORD1)); + _password2Control.Attach(GetItem(IDE_COMPRESS_PASSWORD2)); + _password1Control.SetText(Info.Password); + _password2Control.SetText(Info.Password); + _encryptionMethod.Attach(GetItem(IDC_COMPRESS_ENCRYPTION_METHOD)); + _default_encryptionMethod_Index = -1; + + m_ArchivePath.Attach(GetItem(IDC_COMPRESS_ARCHIVE)); + m_Format.Attach(GetItem(IDC_COMPRESS_FORMAT)); // that combo has CBS_SORT style in resources + m_Level.Attach(GetItem(IDC_COMPRESS_LEVEL)); + m_Method.Attach(GetItem(IDC_COMPRESS_METHOD)); + m_Dictionary.Attach(GetItem(IDC_COMPRESS_DICTIONARY)); + + /* + { + RECT r; + GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r); + _dictionaryCombo_left = r.left; + } + */ + _dictionaryCombo_left = 0; // 230; + + // m_Dictionary_Chain.Attach(GetItem(IDC_COMPRESS_DICTIONARY2)); + m_Order.Attach(GetItem(IDC_COMPRESS_ORDER)); + m_Solid.Attach(GetItem(IDC_COMPRESS_SOLID)); + m_NumThreads.Attach(GetItem(IDC_COMPRESS_THREADS)); + m_MemUse.Attach(GetItem(IDC_COMPRESS_MEM_USE)); + + m_UpdateMode.Attach(GetItem(IDC_COMPRESS_UPDATE_MODE)); + m_PathMode.Attach(GetItem(IDC_COMPRESS_PATH_MODE)); + + m_Volume.Attach(GetItem(IDC_COMPRESS_VOLUME)); + m_Params.Attach(GetItem(IDE_COMPRESS_PARAMETERS)); + + AddVolumeItems(m_Volume); + + m_RegistryInfo.Load(); + CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword); + CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders); + + UpdatePasswordControl(); + + { + const bool needSetMain = (Info.FormatIndex < 0); + FOR_VECTOR(i, ArcIndices) + { + const unsigned arcIndex = ArcIndices[i]; + const CArcInfoEx &ai = (*ArcFormats)[arcIndex]; + const int index = (int)m_Format.AddString(ai.Name); + m_Format.SetItemData(index, (LPARAM)arcIndex); + if (!needSetMain) + { + if (Info.FormatIndex == (int)arcIndex) + m_Format.SetCurSel(index); + continue; + } + if (i == 0 || ai.Name.IsEqualTo_NoCase(m_RegistryInfo.ArcType)) + { + m_Format.SetCurSel(index); + Info.FormatIndex = (int)arcIndex; + } + } + } + + CheckButton(IDX_COMPRESS_SFX, Info.SFXMode); + + { + UString fileName; + SetArcPathFields(Info.ArcPath, fileName, true); + StartDirPrefix = DirPrefix; + SetArchiveName(fileName); + } + + for (unsigned i = 0; i < m_RegistryInfo.ArcPaths.Size() && i < kHistorySize; i++) + m_ArchivePath.AddString(m_RegistryInfo.ArcPaths[i]); + + AddComboItems(m_UpdateMode, k_UpdateMode_IDs, Z7_ARRAY_SIZE(k_UpdateMode_IDs), + k_UpdateMode_Vals, Info.UpdateMode); + + AddComboItems(m_PathMode, k_PathMode_IDs, Z7_ARRAY_SIZE(k_PathMode_IDs), + k_PathMode_Vals, Info.PathMode); + + + TCHAR s[32] = { TEXT('/'), TEXT(' '), 0 }; + ConvertUInt32ToString(NSystem::GetNumberOfProcessors(), s + 2); + SetItemText(IDT_COMPRESS_HARDWARE_THREADS, s); + + CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite); + CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing); + + FormatChanged(false); // isChanged + + // OnButtonSFX(); + + NormalizePosition(); + + return CModalDialog::OnInit(); +} + +/* +namespace NCompressDialog +{ + bool CInfo::GetFullPathName(UString &result) const + { + #ifndef UNDER_CE + // NDirectory::MySetCurrentDirectory(CurrentDirPrefix); + #endif + FString resultF; + bool res = MyGetFullPathName(us2fs(ArchiveName), resultF); + result = fs2us(resultF); + return res; + } +} +*/ + +void CCompressDialog::UpdatePasswordControl() +{ + const bool showPassword = IsShowPasswordChecked(); + const TCHAR c = showPassword ? (TCHAR)0: TEXT('*'); + _password1Control.SetPasswordChar((WPARAM)c); + _password2Control.SetPasswordChar((WPARAM)c); + UString password; + _password1Control.GetText(password); + _password1Control.SetText(password); + _password2Control.GetText(password); + _password2Control.SetText(password); + + ShowItem_Bool(IDT_PASSWORD_REENTER, !showPassword); + _password2Control.Show_Bool(!showPassword); +} + +bool CCompressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_COMPRESS_SET_ARCHIVE: + { + OnButtonSetArchive(); + return true; + } + case IDX_COMPRESS_SFX: + { + SetMethod(GetMethodID()); + OnButtonSFX(); + SetMemoryUsage(); + return true; + } + case IDX_PASSWORD_SHOW: + { + UpdatePasswordControl(); + return true; + } + case IDB_COMPRESS_OPTIONS: + { + COptionsDialog dialog(this); + if (dialog.Create(*this) == IDOK) + ShowOptionsString(); + return true; + } + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CCompressDialog::CheckSFXControlsEnable() +{ + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + bool enable = fi.SFX_(); + if (enable) + { + const int methodID = GetMethodID(); + enable = (methodID == -1 || IsMethodSupportedBySfx(methodID)); + } + if (!enable) + CheckButton(IDX_COMPRESS_SFX, false); + EnableItem(IDX_COMPRESS_SFX, enable); +} + +/* +void CCompressDialog::CheckVolumeEnable() +{ + bool isSFX = IsSFX(); + m_Volume.Enable(!isSFX); + if (isSFX) + m_Volume.SetText(TEXT("")); +} +*/ + +void CCompressDialog::EnableMultiCombo(unsigned id) +{ + NWindows::NControl::CComboBox combo; + combo.Attach(GetItem(id)); + const bool enable = (combo.GetCount() > 1); + EnableItem(id, enable); +} + +static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s); + +static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res) +{ + if (!b1.Def && b2.Def) + res.Val = b2.Val; + else + res.Val = b1.Val; +} + +#define SET_GUI_BOOL(name) \ + Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name) + + +static void Set_Final_BoolPairs( + const CBool1 &gui, + CBoolPair &cmd, + CBoolPair ®) +{ + if (!cmd.Def) + { + reg.Val = gui.Val; + reg.Def = gui.Val; + } + if (gui.Supported) + { + cmd.Val = gui.Val; + cmd.Def = gui.Val; + } + else + cmd.Init(); +} + +#define SET_FINAL_BOOL_PAIRS(name) \ + Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name) + +void CCompressDialog::FormatChanged(bool isChanged) +{ + SetLevel(); + SetSolidBlockSize(); + SetParams(); + SetMemUseCombo(); + SetNumThreads(); + + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + Info.SolidIsSpecified = fi.Solid_(); + Info.EncryptHeadersIsAllowed = fi.EncryptFileNames_(); + + /* + const bool multiThreadEnable = fi.MultiThread; + Info.MultiThreadIsAllowed = multiThreadEnable; + EnableItem(IDC_COMPRESS_SOLID, fi.Solid); + EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable); + const bool methodEnable = (fi.MethodIDs != NULL); + EnableItem(IDC_COMPRESS_METHOD, methodEnable); + EnableMultiCombo(IDC_COMPRESS_DICTIONARY, methodEnable); + EnableItem(IDC_COMPRESS_ORDER, methodEnable); + */ + + CheckSFXControlsEnable(); + + { + if (!isChanged) + { + SET_GUI_BOOL (SymLinks); + SET_GUI_BOOL (HardLinks); + SET_GUI_BOOL (AltStreams); + SET_GUI_BOOL (NtSecurity); + SET_GUI_BOOL (PreserveATime); + } + + PreserveATime.Supported = true; + + { + const CArcInfoEx &ai = Get_ArcInfoEx(); + SymLinks.Supported = ai.Flags_SymLinks(); + HardLinks.Supported = ai.Flags_HardLinks(); + AltStreams.Supported = ai.Flags_AltStreams(); + NtSecurity.Supported = ai.Flags_NtSecurity(); + } + + ShowOptionsString(); + } + // CheckVolumeEnable(); + + const bool encrypt = fi.Encrypt_(); + EnableItem(IDG_COMPRESS_ENCRYPTION, encrypt); + + EnableItem(IDT_PASSWORD_ENTER, encrypt); + EnableItem(IDT_PASSWORD_REENTER, encrypt); + EnableItem(IDE_COMPRESS_PASSWORD1, encrypt); + EnableItem(IDE_COMPRESS_PASSWORD2, encrypt); + EnableItem(IDX_PASSWORD_SHOW, encrypt); + + EnableItem(IDT_COMPRESS_ENCRYPTION_METHOD, encrypt); + EnableItem(IDC_COMPRESS_ENCRYPTION_METHOD, encrypt); + EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_()); + + ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_()); + + SetEncryptionMethod(); + SetMemoryUsage(); +} + + +bool CCompressDialog::IsSFX() +{ + return IsWindowEnabled(GetItem(IDX_COMPRESS_SFX)) + && IsButtonCheckedBool(IDX_COMPRESS_SFX); +} + +static int GetExtDotPos(const UString &s) +{ + const int dotPos = s.ReverseFind_Dot(); + if (dotPos > s.ReverseFind_PathSepar() + 1) + return dotPos; + return -1; +} + +void CCompressDialog::OnButtonSFX() +{ + UString fileName; + m_ArchivePath.GetText(fileName); + const int dotPos = GetExtDotPos(fileName); + if (IsSFX()) + { + if (dotPos >= 0) + fileName.DeleteFrom(dotPos); + fileName += kExeExt; + m_ArchivePath.SetText(fileName); + } + else + { + if (dotPos >= 0) + { + const UString ext = fileName.Ptr(dotPos); + if (ext.IsEqualTo_Ascii_NoCase(kExeExt)) + { + fileName.DeleteFrom(dotPos); + m_ArchivePath.SetText(fileName); + } + } + SetArchiveName2(false); // it's for OnInit + } + + // CheckVolumeEnable(); +} + + +bool CCompressDialog::GetFinalPath_Smart(UString &resPath) const +{ + resPath.Empty(); + UString name; + m_ArchivePath.GetText(name); + name.Trim(); + FString fullPath; + UString dirPrefx = DirPrefix; + if (dirPrefx.IsEmpty()) + dirPrefx = StartDirPrefix; + const bool res = !dirPrefx.IsEmpty() ? + NName::GetFullPath(us2fs(dirPrefx), us2fs(name), fullPath): + NName::GetFullPath( us2fs(name), fullPath); + if (res) + resPath = fs2us(fullPath); + return res; +} + + +bool CCompressDialog::SetArcPathFields(const UString &path) +{ + UString name; + return SetArcPathFields(path, name, true); // always +} + + +bool CCompressDialog::SetArcPathFields(const UString &path, UString &name, bool always) +{ + FString resDirPrefix; + FString resFileName; + const bool res = GetFullPathAndSplit(us2fs(path), resDirPrefix, resFileName); + if (res) + { + DirPrefix = fs2us(resDirPrefix); + name = fs2us(resFileName); + } + else + { + if (!always) + return false; + DirPrefix.Empty(); + name = path; + } + SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix); + m_ArchivePath.SetText(name); + return res; +} + + +static const wchar_t * const k_IncorrectPathMessage = L"Incorrect archive path"; + +static void AddFilter(CObjectVector &filters, + const UString &description, const UString &ext) +{ + CBrowseFilterInfo &f = filters.AddNew(); + UString mask ("*."); + mask += ext; + f.Masks.Add(mask); + f.Description = description; + f.Description += " ("; + f.Description += mask; + f.Description += ")"; +} + + +static const char * const k_DontSave_Exts = + "xpi odt ods docx xlsx "; + +void CCompressDialog::OnButtonSetArchive() +{ + UString path; + if (!GetFinalPath_Smart(path)) + { + ShowErrorMessage(*this, k_IncorrectPathMessage); + return; + } + + int filterIndex; + CObjectVector filters; + unsigned numFormats = 0; + + const bool isSFX = IsSFX(); + if (isSFX) + { + filterIndex = 0; + const UString ext ("exe"); + AddFilter(filters, ext, ext); + } + else + { + filterIndex = m_Format.GetCurSel(); + numFormats = (unsigned)m_Format.GetCount(); + + // filters [0, ... numFormats - 1] corresponds to items in m_Format combo + UString desc; + UStringVector masks; + CStringFinder finder; + + for (unsigned i = 0; i < numFormats; i++) + { + const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)]; + CBrowseFilterInfo &f = filters.AddNew(); + f.Description = ai.Name; + f.Description += " ("; + bool needSpace_desc = false; + + FOR_VECTOR (k, ai.Exts) + { + const UString &ext = ai.Exts[k].Ext; + UString mask ("*."); + mask += ext; + + if (finder.FindWord_In_LowCaseAsciiList_NoCase(k_DontSave_Exts, ext)) + continue; + + f.Masks.Add(mask); + masks.Add(mask); + if (needSpace_desc) + f.Description.Add_Space(); + needSpace_desc = true; + f.Description += ext; + } + f.Description += ")"; + // we use only main ext in desc to reduce the size of list + if (i != 0) + desc.Add_Space(); + desc += ai.GetMainExt(); + } + + CBrowseFilterInfo &f = filters.AddNew(); + f.Description = LangString(IDT_COMPRESS_ARCHIVE); // IDS_ARCHIVES_COLON; + if (f.Description.IsEmpty()) + GetItemText(IDT_COMPRESS_ARCHIVE, f.Description); + f.Description.RemoveChar(L'&'); + // f.Description = "archive"; + f.Description += " ("; + f.Description += desc; + f.Description += ")"; + f.Masks = masks; + } + + AddFilter(filters, LangString(IDS_OPEN_TYPE_ALL_FILES), UString("*")); + if (filterIndex < 0) + filterIndex = (int)filters.Size() - 1; + + const UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_BROWSE); + CBrowseInfo bi; + bi.lpstrTitle = title; + bi.SaveMode = true; + bi.FilterIndex = filterIndex; + bi.hwndOwner = *this; + bi.FilePath = path; + + if (!bi.BrowseForFile(filters)) + return; + + path = bi.FilePath; + + if (isSFX) + { + const int dotPos = GetExtDotPos(path); + if (dotPos >= 0) + path.DeleteFrom(dotPos); + path += kExeExt; + } + else + // if (bi.FilterIndex >= 0) + // if (bi.FilterIndex != filterIndex) + if ((unsigned)bi.FilterIndex < numFormats) + { + // archive format was confirmed. So we try to set format extension + bool needAddExt = true; + const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData((unsigned)bi.FilterIndex)]; + const int dotPos = GetExtDotPos(path); + if (dotPos >= 0) + { + const UString ext = path.Ptr(dotPos + 1); + if (ai.FindExtension(ext) >= 0) + needAddExt = false; + } + if (needAddExt) + { + if (path.IsEmpty() || path.Back() != '.') + path.Add_Dot(); + path += ai.GetMainExt(); + } + } + + SetArcPathFields(path); + + if (!isSFX) + if ((unsigned)bi.FilterIndex < numFormats) + if (bi.FilterIndex != m_Format.GetCurSel()) + { + m_Format.SetCurSel(bi.FilterIndex); + SaveOptionsInMem(); + FormatChanged(true); // isChanged + return; + } + + ArcPath_WasChanged(path); +} + + +// in ExtractDialog.cpp +extern void AddUniqueString(UStringVector &strings, const UString &srcString); + +static bool IsAsciiString(const UString &s) +{ + for (unsigned i = 0; i < s.Len(); i++) + { + const wchar_t c = s[i]; + if (c < 0x20 || c > 0x7F) + return false; + } + return true; +} + + +static void AddSize_MB(UString &s, UInt64 size) +{ + s.Add_LF(); + const UInt64 v2 = size + ((UInt32)1 << 20) - 1; + if (size < v2) + size = v2; + s.Add_UInt64(size >> 20); + s += " MB : "; +} + +static void AddSize_MB_id(UString &s, UInt64 size, UInt32 id) +{ + AddSize_MB(s, size); + AddLangString(s, id); +} + +void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString); +void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString) +{ + AddLangString(s, IDS_MEM_OPERATION_BLOCKED); + s.Add_LF(); + AddLangString(s, IDS_MEM_REQUIRES_BIG_MEM); + s.Add_LF(); + AddSize_MB(s, reqSize); + s += usageString; + AddSize_MB_id(s, ramSize, IDS_MEM_RAM_SIZE); + // if (ramLimit != 0) + { + AddSize_MB_id(s, ramLimit, IDS_MEM_USAGE_LIMIT_SET_BY_7ZIP); + } + s.Add_LF(); + s.Add_LF(); + AddLangString(s, IDS_MEM_ERROR); +} + + +void CCompressDialog::OnOK() +{ + _password1Control.GetText(Info.Password); + if (IsZipFormat()) + { + if (!IsAsciiString(Info.Password)) + { + ShowErrorMessageHwndRes(*this, IDS_PASSWORD_USE_ASCII); + return; + } + UString method = GetEncryptionMethodSpec(); + if (method.IsPrefixedBy_Ascii_NoCase("aes")) + { + if (Info.Password.Len() > 99) + { + ShowErrorMessageHwndRes(*this, IDS_PASSWORD_TOO_LONG); + return; + } + } + } + if (!IsShowPasswordChecked()) + { + UString password2; + _password2Control.GetText(password2); + if (password2 != Info.Password) + { + ShowErrorMessageHwndRes(*this, IDS_PASSWORD_NOT_MATCH); + return; + } + } + + { + UInt64 decompressMem; + const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem); + if (memUsage != (UInt64)(Int64)-1) + { + const UInt64 limit = Get_MemUse_Bytes(); + if (memUsage > limit) + { + UString s2; + LangString_OnlyFromLangFile(IDS_MEM_REQUIRED_MEM_SIZE, s2); + if (s2.IsEmpty()) + { + s2 = LangString(IDT_COMPRESS_MEMORY); + if (s2.IsEmpty()) + GetItemText(IDT_COMPRESS_MEMORY, s2); + s2.RemoveChar(L':'); + } + UString s; + SetErrorMessage_MemUsage(s, memUsage, _ramSize, limit, s2); + MessageBoxError(s); + return; + } + } + } + + SaveOptionsInMem(); + + UStringVector arcPaths; + { + UString s; + if (!GetFinalPath_Smart(s)) + { + ShowErrorMessage(*this, k_IncorrectPathMessage); + return; + } + Info.ArcPath = s; + AddUniqueString(arcPaths, s); + } + + Info.UpdateMode = (NCompressDialog::NUpdateMode::EEnum)k_UpdateMode_Vals[m_UpdateMode.GetCurSel()]; + Info.PathMode = (NWildcard::ECensorPathMode)k_PathMode_Vals[m_PathMode.GetCurSel()]; + + Info.Level = GetLevelSpec(); + Info.Dict64 = GetDictSpec(); + // Info.Dict64_Chain = GetDictChainSpec(); + Info.Order = GetOrderSpec(); + Info.OrderMode = GetOrderMode(); + Info.NumThreads = GetNumThreadsSpec(); + + Info.MemUsage.Clear(); + { + const UString mus = Get_MemUse_Spec(); + if (!mus.IsEmpty()) + { + NCompression::CMemUse mu; + mu.Parse(mus); + if (mu.IsDefined) + Info.MemUsage = mu; + } + } + + { + // Info.SolidIsSpecified = g_Formats[GetStaticFormatIndex()].Solid; + const UInt32 solidLogSize = GetBlockSizeSpec(); + Info.SolidBlockSize = 0; + if (solidLogSize == (UInt32)(Int32)-1) + Info.SolidIsSpecified = false; + else if (solidLogSize > 0) + Info.SolidBlockSize = (solidLogSize >= 64) ? + (UInt64)(Int64)-1 : + ((UInt64)1 << solidLogSize); + } + + Info.Method = GetMethodSpec(); + Info.EncryptionMethod = GetEncryptionMethodSpec(); + Info.FormatIndex = (int)GetFormatIndex(); + Info.SFXMode = IsSFX(); + Info.OpenShareForWrite = IsButtonCheckedBool(IDX_COMPRESS_SHARED); + Info.DeleteAfterCompressing = IsButtonCheckedBool(IDX_COMPRESS_DEL); + + m_RegistryInfo.EncryptHeaders = + Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES); + + + /* (Info) is for saving to registry: + (CBoolPair::Val) will be set as (false), if it was (false) + in registry at dialog creation, and user didn't click checkbox. + in another case (CBoolPair::Val) will be set as (true) */ + + { + /* Info properties could be for another archive types. + so we disable unsupported properties in Info */ + // const CArcInfoEx &ai = Get_ArcInfoEx(); + + SET_FINAL_BOOL_PAIRS (SymLinks); + SET_FINAL_BOOL_PAIRS (HardLinks); + SET_FINAL_BOOL_PAIRS (AltStreams); + SET_FINAL_BOOL_PAIRS (NtSecurity); + + SET_FINAL_BOOL_PAIRS (PreserveATime); + } + + { + const NCompression::CFormatOptions &fo = Get_FormatOptions(); + + Info.TimePrec = fo.TimePrec; + Info.MTime = fo.MTime; + Info.CTime = fo.CTime; + Info.ATime = fo.ATime; + Info.SetArcMTime = fo.SetArcMTime; + } + + m_Params.GetText(Info.Options); + + UString volumeString; + m_Volume.GetText(volumeString); + volumeString.Trim(); + Info.VolumeSizes.Clear(); + + if (!volumeString.IsEmpty()) + { + if (!ParseVolumeSizes(volumeString, Info.VolumeSizes)) + { + ShowErrorMessageHwndRes(*this, IDS_INCORRECT_VOLUME_SIZE); + return; + } + if (!Info.VolumeSizes.IsEmpty()) + { + const UInt64 volumeSize = Info.VolumeSizes.Back(); + if (volumeSize < (100 << 10)) + { + wchar_t s[32]; + ConvertUInt64ToString(volumeSize, s); + if (::MessageBoxW(*this, MyFormatNew(IDS_SPLIT_CONFIRM, s), + L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES) + return; + } + } + } + + if (Info.FormatIndex >= 0) + m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name; + m_RegistryInfo.ShowPassword = IsShowPasswordChecked(); + + FOR_VECTOR (i, m_RegistryInfo.ArcPaths) + { + if (arcPaths.Size() >= kHistorySize) + break; + AddUniqueString(arcPaths, m_RegistryInfo.ArcPaths[i]); + } + m_RegistryInfo.ArcPaths = arcPaths; + + m_RegistryInfo.Save(); + + CModalDialog::OnOK(); +} + +#define kHelpTopic "fm/plugins/7-zip/add.htm" +#define kHelpTopic_Options "fm/plugins/7-zip/add.htm#options" + +void CCompressDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + + +void CCompressDialog::ArcPath_WasChanged(const UString &path) +{ + const int dotPos = GetExtDotPos(path); + if (dotPos < 0) + return; + const UString ext = path.Ptr(dotPos + 1); + { + const CArcInfoEx &ai = Get_ArcInfoEx(); + if (ai.FindExtension(ext) >= 0) + return; + } + + const unsigned count = (unsigned)m_Format.GetCount(); + for (unsigned i = 0; i < count; i++) + { + const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)]; + if (ai.FindExtension(ext) >= 0) + { + m_Format.SetCurSel(i); + SaveOptionsInMem(); + FormatChanged(true); // isChanged + return; + } + } +} + + +bool CCompressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case k_Message_ArcChanged: + { + // UString path; + // m_ArchivePath.GetText(path); + const int select = m_ArchivePath.GetCurSel(); + if ((unsigned)select < m_RegistryInfo.ArcPaths.Size()) + // if (path == m_RegistryInfo.ArcPaths[select]) + { + const UString &path = m_RegistryInfo.ArcPaths[select]; + SetArcPathFields(path); + // ArcPath_WasChanged(path); + } + return 0; + } + } + return CModalDialog::OnMessage(message, wParam, lParam); +} + + +bool CCompressDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_COMPRESS_ARCHIVE: + { + /* CBN_SELCHANGE is called before actual value of combo text will be changed. + So GetText() here returns old value (before change) of combo text. + So here we can change all controls except of m_ArchivePath. + */ + const int select = m_ArchivePath.GetCurSel(); + if ((unsigned)select < m_RegistryInfo.ArcPaths.Size()) + { + // DirPrefix.Empty(); + // SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix); + const UString &path = m_RegistryInfo.ArcPaths[select]; + // SetArcPathFields(path); + ArcPath_WasChanged(path); + // we use PostMessage(k_Message_ArcChanged) here that later will change m_ArchivePath control + PostMsg(k_Message_ArcChanged); + } + return true; + } + + case IDC_COMPRESS_FORMAT: + { + const bool isSFX = IsSFX(); + SaveOptionsInMem(); + FormatChanged(true); // isChanged + SetArchiveName2(isSFX); + return true; + } + + case IDC_COMPRESS_LEVEL: + { + Get_FormatOptions().ResetForLevelChange(); + + SetMethod(); // call it if level changes method + + // call the following if level change keeps old method + /* + { + // try to keep old method + SetMethod(GetMethodID()); + MethodChanged(); + } + */ + + SetSolidBlockSize(); + SetNumThreads(); + CheckSFXNameChange(); + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_METHOD: + { + MethodChanged(); + SetSolidBlockSize(); + SetNumThreads(); + CheckSFXNameChange(); + SetMemoryUsage(); + if (Get_ArcInfoEx().Flags_HashHandler()) + SetArchiveName2(false); + + return true; + } + + case IDC_COMPRESS_DICTIONARY: + // case IDC_COMPRESS_DICTIONARY2: + { + /* we want to change the reported threads for Auto line + and keep selected NumThreads option + So we save selected NumThreads option in memory */ + SaveOptionsInMem(); + const UInt32 blockSizeLog = GetBlockSizeSpec(); + if (// blockSizeLog != (UInt32)(Int32)-1 && + blockSizeLog != kSolidLog_NoSolid + && blockSizeLog != kSolidLog_FullSolid) + { + Get_FormatOptions().Reset_BlockLogSize(); + // SetSolidBlockSize(true); + } + + SetDictionary2(); + SetSolidBlockSize(); + SetNumThreads(); // we want to change the reported threads for Auto line only + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_ORDER: + { + #ifdef PRINT_PARAMS + Print_Params(); + #endif + return true; + } + + case IDC_COMPRESS_SOLID: + { + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_THREADS: + { + SetMemoryUsage(); + return true; + } + + case IDC_COMPRESS_MEM_USE: + { + /* we want to change the reported threads for Auto line + and keep selected NumThreads option + So we save selected NumThreads option in memory */ + SaveOptionsInMem(); + + SetNumThreads(); // we want to change the reported threads for Auto line only + SetMemoryUsage(); + return true; + } + } + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + +void CCompressDialog::CheckSFXNameChange() +{ + const bool isSFX = IsSFX(); + CheckSFXControlsEnable(); + if (isSFX != IsSFX()) + SetArchiveName2(isSFX); +} + +void CCompressDialog::SetArchiveName2(bool prevWasSFX) +{ + UString fileName; + m_ArchivePath.GetText(fileName); + const CArcInfoEx &prevArchiverInfo = (*ArcFormats)[m_PrevFormat]; + if (prevArchiverInfo.Flags_KeepName() || Info.KeepName) + { + UString prevExtension; + if (prevWasSFX) + prevExtension = kExeExt; + else + { + prevExtension.Add_Dot(); + prevExtension += prevArchiverInfo.GetMainExt(); + } + const unsigned prevExtensionLen = prevExtension.Len(); + if (fileName.Len() >= prevExtensionLen) + if (StringsAreEqualNoCase(fileName.RightPtr(prevExtensionLen), prevExtension)) + fileName.DeleteFrom(fileName.Len() - prevExtensionLen); + } + SetArchiveName(fileName); +} + +// if type.KeepName then use OriginalFileName +// else if !KeepName remove extension +// add new extension + +void CCompressDialog::SetArchiveName(const UString &name) +{ + UString fileName = name; + Info.FormatIndex = (int)GetFormatIndex(); + const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; + m_PrevFormat = Info.FormatIndex; + if (ai.Flags_KeepName()) + { + fileName = OriginalFileName; + } + else + { + if (!Info.KeepName) + { + int dotPos = GetExtDotPos(fileName); + if (dotPos >= 0) + fileName.DeleteFrom(dotPos); + } + } + + if (IsSFX()) + fileName += kExeExt; + else + { + fileName.Add_Dot(); + UString ext = ai.GetMainExt(); + if (ai.Flags_HashHandler()) + { + UString estimatedName; + GetMethodSpec(estimatedName); + if (!estimatedName.IsEmpty()) + { + ext = estimatedName; + ext.MakeLower_Ascii(); + } + } + fileName += ext; + } + m_ArchivePath.SetText(fileName); +} + + +int CCompressDialog::FindRegistryFormat(const UString &name) +{ + FOR_VECTOR (i, m_RegistryInfo.Formats) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[i]; + if (name.IsEqualTo_NoCase(GetUnicodeString(fo.FormatID))) + return (int)i; + } + return -1; +} + + +unsigned CCompressDialog::FindRegistryFormat_Always(const UString &name) +{ + const int index = FindRegistryFormat(name); + if (index >= 0) + return (unsigned)index; + { + NCompression::CFormatOptions fo; + fo.FormatID = GetSystemString(name); + return m_RegistryInfo.Formats.Add(fo); + } +} + + +NCompression::CFormatOptions &CCompressDialog::Get_FormatOptions() +{ + const CArcInfoEx &ai = Get_ArcInfoEx(); + return m_RegistryInfo.Formats[FindRegistryFormat_Always(ai.Name)]; +} + + +unsigned CCompressDialog::GetStaticFormatIndex() +{ + const CArcInfoEx &ai = Get_ArcInfoEx(); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Formats); i++) + if (ai.Name.IsEqualTo_Ascii_NoCase(g_Formats[i].Name)) + return i; + return 0; // -1; +} + +void CCompressDialog::SetNearestSelectComboBox(NControl::CComboBox &comboBox, UInt32 value) +{ + for (int i = comboBox.GetCount() - 1; i >= 0; i--) + if ((UInt32)comboBox.GetItemData(i) <= value) + { + comboBox.SetCurSel(i); + return; + } + if (comboBox.GetCount() > 0) + comboBox.SetCurSel(0); +} + +void CCompressDialog::SetLevel2() +{ + m_Level.ResetContent(); + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); + UInt32 level = 5; + { + int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (fo.Level <= 9) + level = fo.Level; + else if (fo.Level == (UInt32)(Int32)-1) + level = 5; + else + level = 9; + } + } + + const bool isZstd = ai.Is_Zstd(); + + for (unsigned i = 0; i < sizeof(UInt32) * 8; i++) + { + const UInt32 mask = fi.LevelsMask >> i; + // if (mask == 0) break; + if (mask & 1) + { + UString s; + s.Add_UInt32(i); + if (i < Z7_ARRAY_SIZE(g_Levels)) + { + const UInt32 langID = g_Levels[i]; + // if (fi.LevelsMask < (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1) + if (langID) + if (i != 0 || !isZstd) + { + s += " - "; + AddLangString(s, langID); + } + } + const int index = (int)m_Level.AddString(s); + m_Level.SetItemData(index, (LPARAM)i); + } + } + SetNearestSelectComboBox(m_Level, level); +} + + +static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s) +{ + return cb.AddString((CSysString)s); +} + +static const char *k_Auto_Prefix = "* "; + +static void Modify_Auto(AString &s) +{ + s.Insert(0, k_Auto_Prefix); +} + +void CCompressDialog::SetMethod2(int keepMethodId) +{ + m_Method.ResetContent(); + _auto_MethodId = -1; + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + const CArcInfoEx &ai = Get_ArcInfoEx(); + if (GetLevel() == 0 && !ai.Flags_HashHandler()) + { + if (!ai.Is_Tar() && + !ai.Is_Zstd()) + { + MethodChanged(); + return; + } + } + UString defaultMethod; + { + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + defaultMethod = fo.Method; + } + } + const bool isSfx = IsSFX(); + bool weUseSameMethod = false; + + const bool is7z = ai.Is_7z(); + + for (unsigned m = 0;; m++) + { + int methodID; + const char *method; + if (m < fi.NumMethods) + { + methodID = fi.MethodIDs[m]; + method = kMethodsNames[methodID]; + if (is7z) + if (methodID == kCopy + || methodID == kDeflate + || methodID == kDeflate64 + ) + continue; + } + else + { + if (!is7z) + break; + const unsigned extIndex = m - fi.NumMethods; + if (extIndex >= ExternalMethods.Size()) + break; + methodID = (int)(Z7_ARRAY_SIZE(kMethodsNames) + extIndex); + method = ExternalMethods[extIndex].Ptr(); + } + if (isSfx) + if (!IsMethodSupportedBySfx(methodID)) + continue; + + AString s (method); + int writtenMethodId = methodID; + if (m == 0) + { + _auto_MethodId = methodID; + writtenMethodId = -1; + Modify_Auto(s); + } + const int itemIndex = (int)ComboBox_AddStringAscii(m_Method, s); + m_Method.SetItemData(itemIndex, writtenMethodId); + if (keepMethodId == methodID) + { + m_Method.SetCurSel(itemIndex); + weUseSameMethod = true; + continue; + } + if ((defaultMethod.IsEqualTo_Ascii_NoCase(method) || m == 0) && !weUseSameMethod) + m_Method.SetCurSel(itemIndex); + } + + if (!weUseSameMethod) + MethodChanged(); +} + + + +bool CCompressDialog::IsZipFormat() +{ + return Get_ArcInfoEx().Is_Zip(); +} + +bool CCompressDialog::IsXzFormat() +{ + return Get_ArcInfoEx().Is_Xz(); +} + +void CCompressDialog::SetEncryptionMethod() +{ + _encryptionMethod.ResetContent(); + _default_encryptionMethod_Index = -1; + const CArcInfoEx &ai = Get_ArcInfoEx(); + if (ai.Is_7z()) + { + ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); + _encryptionMethod.SetCurSel(0); + _default_encryptionMethod_Index = 0; + } + else if (ai.Is_Zip()) + { + int index = FindRegistryFormat(ai.Name); + UString encryptionMethod; + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + encryptionMethod = fo.EncryptionMethod; + } + int sel = 0; + // if (ZipCryptoIsAllowed) + { + ComboBox_AddStringAscii(_encryptionMethod, "ZipCrypto"); + sel = (encryptionMethod.IsPrefixedBy_Ascii_NoCase("aes") ? 1 : 0); + _default_encryptionMethod_Index = 0; + } + ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); + _encryptionMethod.SetCurSel(sel); + } +} + + +int CCompressDialog::GetMethodID_RAW() +{ + if (m_Method.GetCount() <= 0) + return -1; + return (int)(Int32)(UInt32)m_Method.GetItemData_of_CurSel(); +} + +int CCompressDialog::GetMethodID() +{ + int raw = GetMethodID_RAW(); + if (raw < 0) + return _auto_MethodId; + return raw; +} + + +UString CCompressDialog::GetMethodSpec(UString &estimatedName) +{ + estimatedName.Empty(); + if (m_Method.GetCount() < 1) + return estimatedName; + const int methodIdRaw = GetMethodID_RAW(); + int methodId = methodIdRaw; + if (methodIdRaw < 0) + methodId = _auto_MethodId; + UString s; + if (methodId >= 0) + { + if ((unsigned)methodId < Z7_ARRAY_SIZE(kMethodsNames)) + estimatedName = kMethodsNames[methodId]; + else + estimatedName = ExternalMethods[(unsigned)methodId - (unsigned)Z7_ARRAY_SIZE(kMethodsNames)]; + if (methodIdRaw >= 0) + s = estimatedName; + } + return s; +} + + +UString CCompressDialog::GetMethodSpec() +{ + UString estimatedName; + UString s = GetMethodSpec(estimatedName); + return s; +} + +bool CCompressDialog::IsMethodEqualTo(const UString &s) +{ + UString estimatedName; + const UString shortName = GetMethodSpec(estimatedName); + if (s.IsEmpty()) + return shortName.IsEmpty(); + return s.IsEqualTo_NoCase(estimatedName); +} + + +UString CCompressDialog::GetEncryptionMethodSpec() +{ + UString s; + if (_encryptionMethod.GetCount() > 0 + && _encryptionMethod.GetCurSel() != _default_encryptionMethod_Index) + { + _encryptionMethod.GetText(s); + s.RemoveChar(L'-'); + } + return s; +} + + +static const size_t k_Auto_Dict = (size_t)0 - 1; + +static int Combo_AddDict2(NWindows::NControl::CComboBox &cb, size_t sizeReal, size_t sizeShow) +{ + char c = 0; + unsigned moveBits = 0; + if ((sizeShow & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } + else if ((sizeShow & 0x3FF) == 0) { moveBits = 10; c = 'K'; } + AString s; + s.Add_UInt64(sizeShow >> moveBits); + s.Add_Space(); + if (c != 0) + s.Add_Char(c); + s.Add_Char('B'); + if (sizeReal == k_Auto_Dict) + Modify_Auto(s); + const int index = (int)ComboBox_AddStringAscii(cb, s); + cb.SetItemData(index, (LPARAM)sizeReal); + return index; +} + +int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow) +{ + return Combo_AddDict2(m_Dictionary, sizeReal, sizeShow); +} + +int CCompressDialog::AddDict(size_t size) +{ + return AddDict2(size, size); +} + +/* +int CCompressDialog::AddDict_Chain(size_t size) +{ + return Combo_AddDict2(m_Dictionary_Chain, size, size); +} +*/ + +void CCompressDialog::SetDictionary2() +{ + m_Dictionary.ResetContent(); + // m_Dictionary_Chain.ResetContent(); + + // _auto_Dict = (UInt32)1 << 24; // we can use this dictSize to calculate _auto_Solid for unknown method for 7z + _auto_Dict = (UInt32)(Int32)-1; // for debug + // _auto_Dict_Chain = (UInt32)(Int32)-1; // for debug + + const CArcInfoEx &ai = Get_ArcInfoEx(); + UInt32 defaultDict = (UInt32)(Int32)-1; + // UInt32 defaultDict_Chain = (UInt32)(Int32)-1; + { + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (IsMethodEqualTo(fo.Method)) + { + defaultDict = fo.Dictionary; + // defaultDict_Chain = fo.DictionaryChain; + } + } + } + + const int methodID = GetMethodID(); + const UInt32 level = GetLevel2(); + + { + RECT r, rLabel; + GetClientRectOfItem(IDT_COMPRESS_DICTIONARY, rLabel); + GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r); + if (_dictionaryCombo_left == 0) + _dictionaryCombo_left = r.left; + + // bool showDict2; + int newLableRight; + int newDictLeft; + + /* + if (methodID == kZSTD) + { + showDict2 = true; + newDictLeft = _dictionaryCombo_left; + RECT r2; + GetClientRectOfItem(IDC_COMPRESS_DICTIONARY2, r2); + newLableRight = r2.left; + } + else + */ + { + // showDict2 = false; + RECT rBig; + GetClientRectOfItem(IDC_COMPRESS_METHOD, rBig); + newDictLeft= rBig.left; + newLableRight = newDictLeft; + } + + if (newLableRight != rLabel.right) + { + rLabel.right = newLableRight; + MoveItem_RECT(IDT_COMPRESS_DICTIONARY, rLabel); + InvalidateRect(&rLabel); + } + if (newDictLeft != r.left) + { + r.left = newDictLeft; + MoveItem_RECT(IDC_COMPRESS_DICTIONARY, r); + // InvalidateRect(&r); + } + // ShowItem_Bool(IDC_COMPRESS_DICTIONARY2, showDict2); + } + + if (methodID < 0) + return; + + switch (methodID) + { + case kLZMA: + case kLZMA2: + { + { + _auto_Dict = level <= 4 ? + (UInt32)1 << (level * 2 + 16) : + level <= sizeof(size_t) / 2 + 4 ? + (UInt32)1 << (level + 20) : + (UInt32)1 << (sizeof(size_t) / 2 + 24); + } + + // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize. + if (defaultDict != (UInt32)(Int32)-1 + && defaultDict >= ((UInt32)15 << 28)) + defaultDict = kLzmaMaxDictSize; + + const size_t kLzmaMaxDictSize_Up = (size_t)1 << (20 + sizeof(size_t) / 4 * 6); + + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + + for (unsigned i = (16 - 1) * 2; i <= (32 - 1) * 2; i++) + { + if (i < (20 - 1) * 2 + && i != (16 - 1) * 2 + && i != (18 - 1) * 2) + continue; + if (i == (20 - 1) * 2 + 1) + continue; + const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2); + size_t dict = dict_up; + if (dict_up >= kLzmaMaxDictSize) + dict = kLzmaMaxDictSize; // we reduce dictionary + + const int index = AddDict(dict); + // AddDict2(dict, dict_up); // for debug : we show 4 GB + + // const UInt32 numThreads = 2; + // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(numThreads, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + // if (!maxRamSize_Defined || memUsage <= maxRamSize) + curSel = index; + if (dict_up >= kLzmaMaxDictSize_Up) + break; + } + + m_Dictionary.SetCurSel(curSel); + break; + } + + /* + case kZSTD: + { + if (defaultDict != (UInt32)(Int32)-1 && + defaultDict > kZstd_MAX_DictSize) + defaultDict = kZstd_MAX_DictSize; + + if (defaultDict_Chain != (UInt32)(Int32)-1 && + defaultDict_Chain > kZstd_MAX_DictSize_Chain) + defaultDict_Chain = kZstd_MAX_DictSize_Chain; + + { + CZstdEncProps props; + ZstdEncProps_Init(&props); + // props.level_zstd = level; + props.level_7z = level; + ZstdEncProps_Set_WindowSize(&props, defaultDict != (UInt32)(Int32)-1 ? defaultDict: 0); + ZstdEncProps_NormalizeFull(&props); + _auto_Dict_Chain = (UInt32)1 << props.windowLog_Chain; + } + { + CZstdEncProps props; + ZstdEncProps_Init(&props); + // props.level_zstd = level; + props.level_7z = level; + ZstdEncProps_Set_WindowChainSize(&props, defaultDict_Chain != (UInt32)(Int32)-1 ? defaultDict_Chain: 0); + ZstdEncProps_NormalizeFull(&props); + _auto_Dict = (UInt32)1 << props.windowLog; + } + + // if there is collision of two window sizes, we reduce dict_Chain + if (defaultDict != (UInt32)(Int32)-1 && + defaultDict_Chain != (UInt32)(Int32)-1 && + defaultDict < defaultDict_Chain) + defaultDict_Chain = defaultDict; + + { + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + + // defaultDict = 12 << 10; // for debug + const UInt32 kWinStart = 18; + if (defaultDict != 0 && defaultDict < ((UInt32)1 << kWinStart)) + curSel = AddDict(defaultDict); + + for (unsigned i = kWinStart; i <= MY_ZSTD_WINDOWLOG_MAX; i++) + { + const size_t dict = (size_t)1 << i; + const int index = AddDict(dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + curSel = index; + } + m_Dictionary.SetCurSel(curSel); + } + + { + int curSel = Combo_AddDict2(m_Dictionary_Chain, k_Auto_Dict, _auto_Dict_Chain); + + // defaultDict_Chain = 10 << 10; // for debug + const UInt32 kWinChainStart = 15; + if (defaultDict_Chain != 0 && defaultDict_Chain < ((UInt32)1 << kWinChainStart)) + curSel = AddDict_Chain(defaultDict_Chain); + + for (unsigned i = kWinChainStart; i <= kMaxDictChain; i++) + { + const size_t dict = (size_t)1 << i; + if (defaultDict != (UInt32)(Int32)-1 && dict > defaultDict) + break; + const int index = AddDict_Chain(dict); + if (defaultDict_Chain != (UInt32)(Int32)-1) + if (dict <= defaultDict_Chain || curSel <= 0) + curSel = index; + } + m_Dictionary_Chain.SetCurSel(curSel); + } + + break; + } + */ + + case kPPMd: + { + _auto_Dict = (UInt32)1 << (level + 19); + + const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10); + const size_t kPpmd_MaxDictSize_Up = (size_t)1 << (29 + sizeof(size_t) / 8); + + if (defaultDict != (UInt32)(Int32)-1 + && defaultDict >= ((UInt32)15 << 28)) // threshold + defaultDict = kPpmd_Default_4g; + + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + + for (unsigned i = (20 - 1) * 2; i <= (32 - 1) * 2; i++) + { + if (i == (20 - 1) * 2 + 1) + continue; + + const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2); + size_t dict = dict_up; + if (dict_up >= kPpmd_Default_4g) + dict = kPpmd_Default_4g; + + const int index = AddDict2(dict, dict_up); + // AddDict2((UInt32)((UInt32)0 - 2), dict_up); // for debug + // AddDict(dict_up); // for debug + // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + // if (!maxRamSize_Defined || memUsage <= maxRamSize) + curSel = index; + if (dict_up >= kPpmd_MaxDictSize_Up) + break; + } + m_Dictionary.SetCurSel(curSel); + break; + } + + case kPPMdZip: + { + _auto_Dict = (UInt32)1 << (level + 19); + + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + + for (unsigned i = 20; i <= 28; i++) + { + const UInt32 dict = (UInt32)1 << i; + const int index = AddDict(dict); + // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (dict <= defaultDict || curSel <= 0) + // if (!maxRamSize_Defined || memUsage <= maxRamSize) + curSel = index; + } + m_Dictionary.SetCurSel(curSel); + break; + } + + case kDeflate: + case kDeflate64: + { + const UInt32 dict = (methodID == kDeflate ? (UInt32)(1 << 15) : (UInt32)(1 << 16)); + _auto_Dict = dict; + AddDict2(k_Auto_Dict, _auto_Dict); + m_Dictionary.SetCurSel(0); + // EnableItem(IDC_COMPRESS_DICTIONARY, false); + break; + } + + case kBZip2: + { + { + if (level >= 5) _auto_Dict = (900 << 10); + else if (level >= 3) _auto_Dict = (500 << 10); + else _auto_Dict = (100 << 10); + } + + int curSel = AddDict2(k_Auto_Dict, _auto_Dict); + + for (unsigned i = 1; i <= 9; i++) + { + const UInt32 dict = ((UInt32)i * 100) << 10; + AddDict(dict); + // AddDict2(i * 100000, dict); + if (defaultDict != (UInt32)(Int32)-1) + if (i <= defaultDict / 100000 || curSel <= 0) + curSel = m_Dictionary.GetCount() - 1; + } + m_Dictionary.SetCurSel(curSel); + break; + } + + case kCopy: + { + _auto_Dict = 0; + AddDict(0); + m_Dictionary.SetCurSel(0); + break; + } + } +} + + +UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) +{ + if (c.GetCount() <= defMax) + return (UInt32)(Int32)-1; + return (UInt32)c.GetItemData_of_CurSel(); +} + + +UInt64 CCompressDialog::GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax) +{ + if (c.GetCount() <= defMax) + return (UInt64)(Int64)-1; + // LRESULT is signed. so we cast it to unsigned size_t at first: + LRESULT val = c.GetItemData_of_CurSel(); + if (val == (LPARAM)(INT_PTR)(-1)) + return (UInt64)(Int64)-1; + return (UInt64)(size_t)c.GetItemData_of_CurSel(); +} + +UInt32 CCompressDialog::GetLevel2() +{ + UInt32 level = GetLevel(); + if (level == (UInt32)(Int32)-1) + level = 5; + return level; +} + + +int CCompressDialog::AddOrder(UInt32 size) +{ + char s[32]; + ConvertUInt32ToString(size, s); + const int index = (int)ComboBox_AddStringAscii(m_Order, s); + m_Order.SetItemData(index, (LPARAM)size); + return index; +} + +int CCompressDialog::AddOrder_Auto() +{ + AString s; + s.Add_UInt32(_auto_Order); + Modify_Auto(s); + int index = (int)ComboBox_AddStringAscii(m_Order, s); + m_Order.SetItemData(index, (LPARAM)(INT_PTR)(-1)); + return index; +} + +void CCompressDialog::SetOrder2() +{ + m_Order.ResetContent(); + + _auto_Order = 1; + + const CArcInfoEx &ai = Get_ArcInfoEx(); + UInt32 defaultOrder = (UInt32)(Int32)-1; + + { + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (IsMethodEqualTo(fo.Method)) + defaultOrder = fo.Order; + } + } + + const int methodID = GetMethodID(); + const UInt32 level = GetLevel2(); + if (methodID < 0) + return; + + switch (methodID) + { + case kLZMA: + case kLZMA2: + { + _auto_Order = (level < 7 ? 32 : 64); + int curSel = AddOrder_Auto(); + for (unsigned i = 2 * 2; i < 8 * 2; i++) + { + UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); + if (order > 256) + order = 273; + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; + } + m_Order.SetCurSel(curSel); + break; + } + + /* + case kZSTD: + { + { + CZstdEncProps props; + ZstdEncProps_Init(&props); + // props.level_zstd = level; + props.level_7z = level; + ZstdEncProps_NormalizeFull(&props); + _auto_Order = props.targetLength; + if (props.strategy < ZSTD_strategy_btopt) + { + // ZSTD_strategy_fast uses targetLength to change fast level. + // targetLength probably is used only in ZSTD_strategy_btopt and higher + break; + } + } + int curSel = AddOrder_Auto(); + + for (unsigned i = 6; i <= 9 * 2; i++) + { + UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); + // if (order > 999) order = 999; + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; + } + m_Order.SetCurSel(curSel); + break; + } + */ + + case kDeflate: + case kDeflate64: + { + { + if (level >= 9) _auto_Order = 128; + else if (level >= 7) _auto_Order = 64; + else _auto_Order = 32; + } + int curSel = AddOrder_Auto(); + for (unsigned i = 2 * 2; i < 8 * 2; i++) + { + UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2)); + if (order > 256) + order = (methodID == kDeflate64 ? 257 : 258); + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; + } + + m_Order.SetCurSel(curSel); + break; + } + + case kPPMd: + { + { + if (level >= 9) _auto_Order = 32; + else if (level >= 7) _auto_Order = 16; + else if (level >= 5) _auto_Order = 6; + else _auto_Order = 4; + } + + int curSel = AddOrder_Auto(); + + for (unsigned i = 0;; i++) + { + UInt32 order = i + 2; + if (i >= 2) + order = (4 + ((i - 2) & 3)) << ((i - 2) / 4); + const int index = AddOrder(order); + if (defaultOrder != (UInt32)(Int32)-1) + if (order <= defaultOrder || curSel <= 0) + curSel = index; + if (order >= 32) + break; + } + m_Order.SetCurSel(curSel); + break; + } + + case kPPMdZip: + { + _auto_Order = level + 3; + int curSel = AddOrder_Auto(); + for (unsigned i = 2; i <= 16; i++) + { + const int index = AddOrder(i); + if (defaultOrder != (UInt32)(Int32)-1) + if (i <= defaultOrder || curSel <= 0) + curSel = index; + } + m_Order.SetCurSel(curSel); + break; + } + + // case kBZip2: + default: + break; + } +} + +bool CCompressDialog::GetOrderMode() +{ + switch (GetMethodID()) + { + case kPPMd: + case kPPMdZip: + return true; + } + return false; +} + + +static UInt64 Get_Lzma2_ChunkSize(UInt64 dict) +{ + // we use same default chunk sizes as defined in 7z encoder and lzma2 encoder + UInt64 cs = (UInt64)dict << 2; + const UInt32 kMinSize = (UInt32)1 << 20; + const UInt32 kMaxSize = (UInt32)1 << 28; + if (cs < kMinSize) cs = kMinSize; + if (cs > kMaxSize) cs = kMaxSize; + if (cs < dict) cs = dict; + cs += (kMinSize - 1); + cs &= ~(UInt64)(kMinSize - 1); + return cs; +} + + +static void Add_Size(AString &s, UInt64 val) +{ + unsigned moveBits = 0; + char c = 0; + if ((val & 0x3FFFFFFF) == 0) { moveBits = 30; c = 'G'; } + else if ((val & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; } + else if ((val & 0x3FF) == 0) { moveBits = 10; c = 'K'; } + s.Add_UInt64(val >> moveBits); + s.Add_Space(); + if (moveBits != 0) + s.Add_Char(c); + s.Add_Char('B'); +} + + +void CCompressDialog::SetSolidBlockSize2() +{ + m_Solid.ResetContent(); + _auto_Solid = 1 << 20; + + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + if (!fi.Solid_()) + return; + + const UInt32 level = GetLevel2(); + if (level == 0) + return; + + UInt64 dict = GetDict2(); + if (dict == (UInt64)(Int64)-1) + { + dict = 1 << 25; // default dict for unknown methods + // return; + } + + + UInt32 defaultBlockSize = (UInt32)(Int32)-1; + + const CArcInfoEx &ai = Get_ArcInfoEx(); + + /* + if (usePrevDictionary) + defaultBlockSize = GetBlockSizeSpec(); + else + */ + { + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (IsMethodEqualTo(fo.Method)) + defaultBlockSize = fo.BlockLogSize; + } + } + + const bool is7z = ai.Is_7z(); + + const UInt64 cs = Get_Lzma2_ChunkSize(dict); + + // Solid Block Size + UInt64 blockSize = cs; // for xz + + if (is7z) + { + // we use same default block sizes as defined in 7z encoder + UInt64 kMaxSize = (UInt64)1 << 32; + const int methodId = GetMethodID(); + if (methodId == kLZMA2) + { + blockSize = cs << 6; + kMaxSize = (UInt64)1 << 34; + } + else + { + UInt64 dict2 = dict; + if (methodId == kBZip2) + { + dict2 /= 100000; + if (dict2 < 1) + dict2 = 1; + dict2 *= 100000; + } + blockSize = dict2 << 7; + } + + const UInt32 kMinSize = (UInt32)1 << 24; + if (blockSize < kMinSize) blockSize = kMinSize; + if (blockSize > kMaxSize) blockSize = kMaxSize; + } + + _auto_Solid = blockSize; + + int curSel; + { + AString s; + Add_Size(s, _auto_Solid); + Modify_Auto(s); + const int index = (int)ComboBox_AddStringAscii(m_Solid, s); + m_Solid.SetItemData(index, (LPARAM)(UInt32)(Int32)-1); + curSel = index; + } + + if (is7z) + { + UString s ('-'); + // kSolidLog_NoSolid = 0 for xz means default blockSize + if (is7z) + LangString(IDS_COMPRESS_NON_SOLID, s); + const int index = (int)m_Solid.AddString(s); + m_Solid.SetItemData(index, (LPARAM)(UInt32)kSolidLog_NoSolid); + if (defaultBlockSize == kSolidLog_NoSolid) + curSel = index; + } + + for (unsigned i = 20; i <= 36; i++) + { + AString s; + Add_Size(s, (UInt64)1 << i); + const int index = (int)ComboBox_AddStringAscii(m_Solid, s); + m_Solid.SetItemData(index, (LPARAM)(UInt32)i); + if (defaultBlockSize != (UInt32)(Int32)-1) + if (i <= defaultBlockSize || index <= 1) + curSel = index; + } + + { + const int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID)); + m_Solid.SetItemData(index, (LPARAM)kSolidLog_FullSolid); + if (defaultBlockSize == kSolidLog_FullSolid) + curSel = index; + } + + m_Solid.SetCurSel(curSel); +} + + +/* +static void ZstdEncProps_SetDictProps_From_CompressDialog(CZstdEncProps *props, CCompressDialog &cd) +{ + { + const UInt64 d64 = cd.GetDictSpec(); + UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog + if (d64 != (UInt64)(Int64)-1) + { + d32 = (UInt32)d64; + if (d32 != d64) + d32 = (UInt32)(Int32)-2; + } + ZstdEncProps_Set_WindowSize(props, d32); + } + { + const UInt64 d64 = cd.GetDictChainSpec(); + UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog_Chain + if (d64 != (UInt64)(Int64)-1) + { + d32 = (UInt32)d64; + if (d32 != d64) + d32 = (UInt32)(Int32)-2; + } + ZstdEncProps_Set_WindowChainSize(props, d32); + } +} + +static bool Is_Zstd_Mt_Supported() +{ + if (!GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "InitializeConditionVariable")) + return false; + return true; +} +*/ + +static const char *k_ST_Threads = " (ST)"; + +void CCompressDialog::SetNumThreads2() +{ + _auto_NumThreads = 1; + + m_NumThreads.ResetContent(); + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + if (!fi.MultiThread_()) + return; + + const UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors(); + // 64; // for debug: + + UInt32 defaultValue = numHardwareThreads; + bool useAutoThreads = true; + + { + const CArcInfoEx &ai = Get_ArcInfoEx(); + int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + if (IsMethodEqualTo(fo.Method) && fo.NumThreads != (UInt32)(Int32)-1) + { + defaultValue = fo.NumThreads; + useAutoThreads = false; + } + } + } + + // const UInt32 num_ZSTD_threads_MAX = Is_Zstd_Mt_Supported() ? MY_ZSTDMT_NBWORKERS_MAX : 0; + + UInt32 numAlgoThreadsMax = numHardwareThreads * 2; + const int methodID = GetMethodID(); + + switch (methodID) + { + case kLZMA: numAlgoThreadsMax = 2; break; + case kLZMA2: numAlgoThreadsMax = 256; break; + case kBZip2: numAlgoThreadsMax = 32; break; + // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break; + case kCopy: + case kPPMd: + case kDeflate: + case kDeflate64: + case kPPMdZip: + numAlgoThreadsMax = 1; + } + const bool isZip = IsZipFormat(); + if (isZip) + { + numAlgoThreadsMax = + #ifdef _WIN32 + 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here + #else + 128; + #endif + } + + UInt32 autoThreads = numHardwareThreads; + if (autoThreads > numAlgoThreadsMax) + autoThreads = numAlgoThreadsMax; + + const UInt64 memUse_Limit = Get_MemUse_Bytes(); + + if (_ramSize_Defined) + if (autoThreads > 1 + // || (autoThreads == 0 && methodID == kZSTD) + ) + { + if (isZip) + { + for (; autoThreads > 1; autoThreads--) + { + const UInt64 dict64 = GetDict2(); + UInt64 decompressMemory; + const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory); + if (usage <= memUse_Limit) + break; + } + } + else if (methodID == kLZMA2) + { + const UInt64 dict64 = GetDict2(); + const UInt32 numThreads1 = (GetLevel2() >= 5 ? 2 : 1); + UInt32 numBlockThreads = autoThreads / numThreads1; + for (; numBlockThreads > 1; numBlockThreads--) + { + autoThreads = numBlockThreads * numThreads1; + UInt64 decompressMemory; + const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory); + if (usage <= memUse_Limit) + break; + } + autoThreads = numBlockThreads * numThreads1; + } + /* + else if (methodID == kZSTD) + { + if (num_ZSTD_threads_MAX != 0) + { + CZstdEncProps props; + ZstdEncProps_Init(&props); + // props.level_zstd = level; + props.level_7z = GetLevel2(); + ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this); + autoThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(&props, memUse_Limit, autoThreads); + } + } + */ + } + + _auto_NumThreads = autoThreads; + + int curSel = -1; + { + AString s; + s.Add_UInt32(autoThreads); + if (autoThreads == 0) s += k_ST_Threads; + Modify_Auto(s); + const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); + m_NumThreads.SetItemData(index, (LPARAM)(INT_PTR)(-1)); + // m_NumThreads.SetItemData(index, autoThreads); + if (useAutoThreads) + curSel = index; + } + + if (numAlgoThreadsMax != autoThreads || autoThreads != 1) + for (UInt32 i = + // (methodID == kZSTD) ? 0 : + 1; + i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++) + { + AString s; + s.Add_UInt32(i); + if (i == 0) s += k_ST_Threads; + const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s); + m_NumThreads.SetItemData(index, (LPARAM)(UInt32)i); + if (!useAutoThreads && i == defaultValue) + curSel = index; + } + + m_NumThreads.SetCurSel(curSel); +} + + +static void AddMemSize(UString &res, UInt64 size) +{ + char c; + unsigned moveBits = 0; + if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0) + { moveBits = 30; c = 'G'; } + else // if (size >= ((UInt32)1 << 21) && (size & 0xFFFFF) == 0) + { moveBits = 20; c = 'M'; } + // else { moveBits = 10; c = 'K'; } + res.Add_UInt64(size >> moveBits); + res.Add_Space(); + if (moveBits != 0) + res.Add_Char(c); + res.Add_Char('B'); +} + + +int CCompressDialog::AddMemComboItem(UInt64 val, bool isPercent, bool isDefault) +{ + UString sUser; + UString sRegistry; + if (isPercent) + { + UString s; + s.Add_UInt64(val); + s.Add_Char('%'); + if (isDefault) + sUser = k_Auto_Prefix; + else + sRegistry = s; + sUser += s; + } + else + { + AddMemSize(sUser, val); + sRegistry = sUser; + for (;;) + { + const int pos = sRegistry.Find(L' '); + if (pos < 0) + break; + sRegistry.Delete(pos); + } + if (!sRegistry.IsEmpty()) + if (sRegistry.Back() == 'B') + sRegistry.DeleteBack(); + } + const unsigned dataIndex = _memUse_Strings.Add(sRegistry); + const int index = (int)m_MemUse.AddString(sUser); + m_MemUse.SetItemData(index, (LPARAM)dataIndex); + return index; +} + + + +void CCompressDialog::SetMemUseCombo() +{ + _memUse_Strings.Clear(); + m_MemUse.ResetContent(); + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + + { + const bool enable = fi.MemUse_(); + ShowItem_Bool(IDT_COMPRESS_MEMORY, enable); + ShowItem_Bool(IDT_COMPRESS_MEMORY_VALUE, enable); + ShowItem_Bool(IDT_COMPRESS_MEMORY_DE, enable); + ShowItem_Bool(IDT_COMPRESS_MEMORY_DE_VALUE, enable); + ShowItem_Bool(IDC_COMPRESS_MEM_USE, enable); + EnableItem(IDC_COMPRESS_MEM_USE, enable); + if (!enable) + return; + } + + UInt64 curMem_Bytes = 0; + UInt64 curMem_Percents = 0; + bool needSetCur_Bytes = false; + bool needSetCur_Percents = false; + { + const NCompression::CFormatOptions &fo = Get_FormatOptions(); + if (!fo.MemUse.IsEmpty()) + { + NCompression::CMemUse mu; + mu.Parse(fo.MemUse); + if (mu.IsDefined) + { + if (mu.IsPercent) + { + curMem_Percents = mu.Val; + needSetCur_Percents = true; + } + else + { + curMem_Bytes = mu.GetBytes(_ramSize_Reduced); + needSetCur_Bytes = true; + } + } + } + } + + + // 80% - is auto usage limit in handlers + AddMemComboItem(80, true, true); + m_MemUse.SetCurSel(0); + + { + for (unsigned i = 10;; i += 10) + { + UInt64 size = i; + if (i > 100) + size = (UInt64)(Int64)-1; + if (needSetCur_Percents && size >= curMem_Percents) + { + const int index = AddMemComboItem(curMem_Percents, true); + m_MemUse.SetCurSel(index); + needSetCur_Percents = false; + if (size == curMem_Percents) + continue; + } + if (size == (UInt64)(Int64)-1) + break; + AddMemComboItem(size, true); + } + } + { + for (unsigned i = (27) * 2;; i++) + { + UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2); + if (i > (20 + sizeof(size_t) * 3 - 1) * 2) + size = (UInt64)(Int64)-1; + if (needSetCur_Bytes && size >= curMem_Bytes) + { + const int index = AddMemComboItem(curMem_Bytes); + m_MemUse.SetCurSel(index); + needSetCur_Bytes = false; + if (size == curMem_Bytes) + continue; + } + if (size == (UInt64)(Int64)-1) + break; + AddMemComboItem(size); + } + } +} + + +UString CCompressDialog::Get_MemUse_Spec() +{ + if (m_MemUse.GetCount() < 1) + return UString(); + return _memUse_Strings[(unsigned)m_MemUse.GetItemData_of_CurSel()]; +} + + +UInt64 CCompressDialog::Get_MemUse_Bytes() +{ + const UString mus = Get_MemUse_Spec(); + NCompression::CMemUse mu; + if (!mus.IsEmpty()) + { + mu.Parse(mus); + if (mu.IsDefined) + return mu.GetBytes(_ramSize_Reduced); + } + return _ramUsage_Auto; // _ramSize_Reduced; // _ramSize;; +} + + + +UInt64 CCompressDialog::GetMemoryUsage_DecompMem(UInt64 &decompressMemory) +{ + return GetMemoryUsage_Dict_DecompMem(GetDict2(), decompressMemory); +} + + +/* +we could use that function to reduce the dictionary if small RAM +UInt64 CCompressDialog::GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64) +{ + UInt64 decompressMemory; + return GetMemoryUsage_Threads_Dict_DecompMem(numThreads, dict64, decompressMemory); +} +*/ + + +UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &decompressMemory) +{ + return GetMemoryUsage_Threads_Dict_DecompMem(GetNumThreads2(), dict64, decompressMemory); +} + +UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict64, UInt64 &decompressMemory) +{ + decompressMemory = (UInt64)(Int64)-1; + + const UInt32 level = GetLevel2(); + if (level == 0 && !Get_ArcInfoEx().Is_Zstd()) + { + decompressMemory = (1 << 20); + return decompressMemory; + } + UInt64 size = 0; + + const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()]; + if (fi.Filter_() && level >= 9) + size += (12 << 20) * 2 + (5 << 20); + // UInt32 numThreads = GetNumThreads2(); + + UInt32 numMainZipThreads = 1; + + if (IsZipFormat()) + { + UInt32 numSubThreads = 1; + if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5) + numSubThreads = 2; + numMainZipThreads = numThreads / numSubThreads; + if (numMainZipThreads > 1) + size += (UInt64)numMainZipThreads * ((size_t)sizeof(size_t) << 23); + else + numMainZipThreads = 1; + } + + const int methodId = GetMethodID(); + + if (dict64 == (UInt64)(Int64)-1 + // && methodId != kZSTD + ) + return (UInt64)(Int64)-1; + + + switch (methodId) + { + case kLZMA: + case kLZMA2: + { + const UInt32 dict = (dict64 >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dict64); + UInt32 hs = dict - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + if (hs >= (1 << 24)) + hs >>= 1; + hs |= (1 << 16) - 1; + // if (numHashBytes >= 5) + if (level < 5) + hs |= (256 << 10) - 1; + hs++; + UInt64 size1 = (UInt64)hs * 4; + size1 += (UInt64)dict * 4; + if (level >= 5) + size1 += (UInt64)dict * 4; + size1 += (2 << 20); + + UInt32 numThreads1 = 1; + if (numThreads > 1 && level >= 5) + { + size1 += (2 << 20) + (4 << 20); + numThreads1 = 2; + } + + UInt32 numBlockThreads = numThreads / numThreads1; + + UInt64 chunkSize = 0; // it's solid chunk + + if (methodId != kLZMA && numBlockThreads != 1) + { + chunkSize = Get_Lzma2_ChunkSize(dict); + + if (IsXzFormat()) + { + UInt32 blockSizeLog = GetBlockSizeSpec(); + if (blockSizeLog != (UInt32)(Int32)-1) + { + if (blockSizeLog == kSolidLog_FullSolid) + { + numBlockThreads = 1; + chunkSize = 0; + } + else if (blockSizeLog != kSolidLog_NoSolid) + chunkSize = (UInt64)1 << blockSizeLog; + } + } + } + + if (chunkSize == 0) + { + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); + UInt64 blockSize = (UInt64)dict + (1 << 16) + + (numThreads1 > 1 ? (1 << 20) : 0); + blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); + if (blockSize >= kBlockSizeMax) + blockSize = kBlockSizeMax; + size += numBlockThreads * (size1 + blockSize); + } + else + { + size += numBlockThreads * (size1 + chunkSize); + UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1; + if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++; + if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++; + if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++; + size += numPackChunks * chunkSize; + } + + decompressMemory = dict + (2 << 20); + return size; + } + + /* + case kZSTD: + { + CZstdEncProps props; + ZstdEncProps_Init(&props); + // props.level_zstd = level; + props.level_7z = level; + props.nbWorkers = numThreads; + ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this); + ZstdEncProps_NormalizeFull(&props); + size = ZstdEncProps_GetMemUsage(&props); + decompressMemory = (UInt64)1 << props.windowLog; + return size; + } + */ + + case kPPMd: + { + decompressMemory = dict64 + (2 << 20); + return size + decompressMemory; + } + + case kDeflate: + case kDeflate64: + { + UInt64 size1 = 3 << 20; + // if (level >= 7) + size1 += (1 << 20); + size += size1 * numMainZipThreads; + decompressMemory = (2 << 20); + return size; + } + + case kBZip2: + { + decompressMemory = (7 << 20); + UInt64 memForOneThread = (10 << 20); + return size + memForOneThread * numThreads; + } + + case kPPMdZip: + { + decompressMemory = dict64 + (2 << 20); + return size + (UInt64)decompressMemory * numThreads; + } + } + + return (UInt64)(Int64)-1; +} + + + +static void AddMemUsage(UString &s, UInt64 v) +{ + const char *post; + if (v <= ((UInt64)16 << 30)) + { + v = (v + (1 << 20) - 1) >> 20; + post = "MB"; + } + else if (v <= ((UInt64)64 << 40)) + { + v = (v + (1 << 30) - 1) >> 30; + post = "GB"; + } + else + { + const UInt64 v2 = v + ((UInt64)1 << 40) - 1; + if (v <= v2) + v = v2; + v >>= 40; + post = "TB"; + } + s.Add_UInt64(v); + s.Add_Space(); + s += post; +} + + +void CCompressDialog::PrintMemUsage(UINT res, UInt64 value) +{ + if (value == (UInt64)(Int64)-1) + { + SetItemText(res, TEXT("?")); + return; + } + UString s; + AddMemUsage(s, value); + if (res == IDT_COMPRESS_MEMORY_VALUE) + { + const UString mus = Get_MemUse_Spec(); + NCompression::CMemUse mu; + if (!mus.IsEmpty()) + mu.Parse(mus); + if (mu.IsDefined) + { + s += " / "; + AddMemUsage(s, mu.GetBytes(_ramSize_Reduced)); + } + else if (_ramSize_Defined) + { + s += " / "; + AddMemUsage(s, _ramUsage_Auto); + } + + if (_ramSize_Defined) + { + s += " / "; + AddMemUsage(s, _ramSize); + } + } + SetItemText(res, s); +} + + +void CCompressDialog::SetMemoryUsage() +{ + UInt64 decompressMem; + const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem); + PrintMemUsage(IDT_COMPRESS_MEMORY_VALUE, memUsage); + PrintMemUsage(IDT_COMPRESS_MEMORY_DE_VALUE, decompressMem); + #ifdef PRINT_PARAMS + Print_Params(); + #endif +} + + + +#ifdef PRINT_PARAMS + +static const char kPropDelimeter = ' '; // ':' + +static void AddPropName(AString &s, const char *name) +{ + if (!s.IsEmpty()) + s += kPropDelimeter; + s += name; +} + +static void AddProp(AString &s, const char *name, unsigned v) +{ + AddPropName(s, name); + s.Add_UInt32(v); +} + +static void AddProp_switch(AString &s, const char *name, E_ZSTD_paramSwitch_e e) +{ + AddPropName(s, name); + s += e == k_ZSTD_ps_enable ? "" : "-"; +} + +static void PrintPropAsLog(AString &s, const char *name, size_t v) +{ + AddPropName(s, name); + for (unsigned i = 0; i < sizeof(size_t) * 8; i++) + { + if (((size_t)1 << i) == v) + { + s.Add_UInt32(i); + return; + } + } + char c = 'b'; + if ((v & 0x3FFFFFFF) == 0) { v >>= 30; c = 'G'; } + else if ((v & 0xFFFFF) == 0) { v >>= 20; c = 'M'; } + else if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; } + s.Add_UInt64(v); + s += c; +} + +static void ZstdEncProps_Print(CZstdEncProps *props, AString &s) +{ + if (props->level_zstd >= 0) + AddProp(s, "zx", props->level_zstd); + else + AddProp(s, "zf", -(props->level_zstd)); + AddProp(s, "a", props->strategy); + AddProp(s, "d", props->windowLog); + AddProp(s, "zclog", props->chainLog); + AddProp(s, "zhb", props->hashLog); + AddProp(s, "mml", props->minMatch); + AddProp(s, "mcb", props->searchLog); + AddProp(s, "fb", props->targetLength); + AddProp(s, "mt", props->nbWorkers); + PrintPropAsLog(s, "c", props->jobSize); + AddProp(s, "zov", props->overlapLog); + PrintPropAsLog(s, "ztps", props->targetPrefixSize); + AddProp_switch(s, "zmfr", props->useRowMatchFinder); + if (props->ldmParams.enableLdm == k_ZSTD_ps_enable) + { + AddProp_switch(s, "zle", props->ldmParams.enableLdm); + AddProp(s, "zlhb", props->ldmParams.hashLog); + AddProp(s, "zlbb", props->ldmParams.bucketSizeLog); + AddProp(s, "zlmml", props->ldmParams.minMatchLength); + AddProp(s, "zlhrb", props->ldmParams.hashRateLog); + } +} + +void CCompressDialog::Print_Params() +{ + { + CZstdEncProps props; + ZstdEncProps_Init(&props); + // props.level_zstd = level; + props.level_7z = GetLevel2(); + ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this); + { + UInt32 order = GetOrderSpec(); + if (order != (UInt32)(Int32)-1) + props.targetLength = GetOrderSpec(); + } + props.nbWorkers = GetNumThreads2(); + // props.windowLog = 18; // for debug + ZstdEncProps_NormalizeFull(&props); + AString s; + ZstdEncProps_Print(&props, s); + SetItemTextA(IDT_COMPRESS_PARAMS_INFO, s); + } +} + +#endif // PRINT_PARAMS + + + +void CCompressDialog::SetParams() +{ + const CArcInfoEx &ai = Get_ArcInfoEx(); + m_Params.SetText(TEXT("")); + const int index = FindRegistryFormat(ai.Name); + if (index >= 0) + { + const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + m_Params.SetText(fo.Options); + } +} + +void CCompressDialog::SaveOptionsInMem() +{ + /* these options are for (Info.FormatIndex). + If it's called just after format changing, + then it's format that was selected before format changing + So we store previous format properties */ + + m_Params.GetText(Info.Options); + Info.Options.Trim(); + + const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; + const unsigned index = FindRegistryFormat_Always(ai.Name); + NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; + fo.Options = Info.Options; + fo.Level = GetLevelSpec(); + { + const UInt64 dict64 = GetDictSpec(); + UInt32 dict32; + if (dict64 == (UInt64)(Int64)-1) + dict32 = (UInt32)(Int32)-1; + else + { + dict32 = (UInt32)dict64; + if (dict64 != dict32) + { + /* here we must write 32-bit value for registry that indicates big_value + (UInt32)(Int32)-1 : is used as marker for default size + (UInt32)(Int32)-2 : it can be used to indicate big value (4 GiB) + the value must be larger than threshold + */ + dict32 = (UInt32)(Int32)-2; + // dict32 = kLzmaMaxDictSize; // it must be larger than threshold + } + } + fo.Dictionary = dict32; + } + /* + { + const UInt64 dict64 = GetDictChainSpec(); + UInt32 dict32; + if (dict64 == (UInt64)(Int64)-1) + dict32 = (UInt32)(Int32)-1; + else + { + dict32 = (UInt32)dict64; + if (dict64 != dict32) + { + dict32 = (UInt32)(Int32)-2; + // dict32 = k_Zstd_MAX_DictSize; // it must be larger than threshold + } + } + fo.DictionaryChain = dict32; + } + */ + + fo.Order = GetOrderSpec(); + fo.Method = GetMethodSpec(); + fo.EncryptionMethod = GetEncryptionMethodSpec(); + fo.NumThreads = GetNumThreadsSpec(); + fo.BlockLogSize = GetBlockSizeSpec(); + fo.MemUse = Get_MemUse_Spec(); +} + + +unsigned CCompressDialog::GetFormatIndex() +{ + return (unsigned)m_Format.GetItemData_of_CurSel(); +} + + + +static void AddText_from_BoolPair(AString &s, const char *name, const CBoolPair &bp) +{ + if (bp.Def) + { + s.Add_OptSpaced(name); + if (!bp.Val) + s += "-"; + } + /* + else if (bp.Val) + { + s.Add_OptSpaced("["); + s += name; + s += "]"; + } + */ +} + + +static void AddText_from_Bool1(AString &s, const char *name, const CBool1 &b) +{ + if (b.Supported && b.Val) + s.Add_OptSpaced(name); +} + + +void CCompressDialog::ShowOptionsString() +{ + NCompression::CFormatOptions &fo = Get_FormatOptions(); + + AString s; + if (fo.IsSet_TimePrec()) + { + s.Add_OptSpaced("tp"); + s.Add_UInt32(fo.TimePrec); + } + AddText_from_BoolPair(s, "tm", fo.MTime); + AddText_from_BoolPair(s, "tc", fo.CTime); + AddText_from_BoolPair(s, "ta", fo.ATime); + AddText_from_BoolPair(s, "-stl", fo.SetArcMTime); + + // const CArcInfoEx &ai = Get_ArcInfoEx(); + AddText_from_Bool1(s, "SL", SymLinks); + AddText_from_Bool1(s, "HL", HardLinks); + AddText_from_Bool1(s, "AS", AltStreams); + AddText_from_Bool1(s, "Sec", NtSecurity); + + // AddText_from_Bool1(s, "Preserve", PreserveATime); + + SetItemText(IDT_COMPRESS_OPTIONS, GetUnicodeString(s)); +} + + + + + +// ---------- OPTIONS ---------- + + +void COptionsDialog::CheckButton_Bool1(UINT id, const CBool1 &b1) +{ + CheckButton(id, b1.Val); +} + +void COptionsDialog::GetButton_Bool1(UINT id, CBool1 &b1) +{ + b1.Val = IsButtonCheckedBool(id); +} + + +void COptionsDialog::CheckButton_BoolBox( + bool supported, const CBoolPair &b2, CBoolBox &bb) +{ + const bool isSet = b2.Def; + const bool val = isSet ? b2.Val : bb.DefaultVal; + + bb.IsSupported = supported; + + CheckButton (bb.Set_Id, isSet); + ShowItem_Bool (bb.Set_Id, supported); + CheckButton (bb.Id, val); + EnableItem (bb.Id, isSet); + ShowItem_Bool (bb.Id, supported); +} + +void COptionsDialog::GetButton_BoolBox(CBoolBox &bb) +{ + // we save value for invisible buttons too + bb.BoolPair.Val = IsButtonCheckedBool (bb.Id); + bb.BoolPair.Def = IsButtonCheckedBool (bb.Set_Id); +} + + +void COptionsDialog::Store_TimeBoxes() +{ + TimePrec = GetPrecSpec(); + GetButton_BoolBox (MTime); + GetButton_BoolBox (CTime); + GetButton_BoolBox (ATime); + GetButton_BoolBox (ZTime); +} + + +UInt32 COptionsDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) +{ + if (c.GetCount() <= defMax) + return (UInt32)(Int32)-1; + return (UInt32)c.GetItemData_of_CurSel(); +} + +static const unsigned kTimePrec_Win = 0; +static const unsigned kTimePrec_Unix = 1; +static const unsigned kTimePrec_DOS = 2; +static const unsigned kTimePrec_1ns = 3; + +static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL) +{ + // s += " : "; + { + AString s2; + s2.Add_UInt32(val); + s += s2; + } + s.Add_Space(); + s += unit; + if (sys) + { + s += " : "; + s += sys; + } +} + +int COptionsDialog::AddPrec(unsigned prec, bool isDefault) +{ + UString s; + UInt32 writePrec = prec; + if (isDefault) + { + // s += "* "; + // writePrec = (UInt32)(Int32)-1; + } + if (prec == kTimePrec_Win) AddTimeOption(s, 100, NsString, "Windows"); + else if (prec == kTimePrec_Unix) AddTimeOption(s, 1, SecString, "Unix"); + else if (prec == kTimePrec_DOS) AddTimeOption(s, 2, SecString, "DOS"); + else if (prec == kTimePrec_1ns) AddTimeOption(s, 1, NsString, "Linux"); + else if (prec == k_PropVar_TimePrec_Base) AddTimeOption(s, 1, SecString); + else if (prec >= k_PropVar_TimePrec_Base) + { + UInt32 d = 1; + for (unsigned i = prec; i < k_PropVar_TimePrec_Base + 9; i++) + d *= 10; + AddTimeOption(s, d, NsString); + } + else + s.Add_UInt32(prec); + const int index = (int)m_Prec.AddString(s); + m_Prec.SetItemData(index, (LPARAM)writePrec); + return index; +} + + +void COptionsDialog::SetPrec() +{ + // const CFormatInfo &fi = g_Formats[cd->GetStaticFormatIndex()]; + const CArcInfoEx &ai = cd->Get_ArcInfoEx(); + + // UInt32 flags = fi.Flags; + + UInt32 flags = ai.Get_TimePrecFlags(); + UInt32 defaultPrec = ai.Get_DefaultTimePrec(); + if (defaultPrec != 0) + flags |= ((UInt32)1 << defaultPrec); + + // const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + + // unsigned defaultPrec = kTimePrec_Win; + + if (ai.Is_GZip()) + defaultPrec = kTimePrec_Unix; + + { + UString s; + s += GetNameOfProperty(kpidType, L"type"); + s += ": "; + s += ai.Name; + if (ai.Is_Tar()) + { + const int methodID = cd->GetMethodID(); + + // for debug + // defaultPrec = kTimePrec_Unix; + // flags = (UInt32)1 << kTimePrec_Unix; + + s.Add_Colon(); + if (methodID >= 0 && (unsigned)methodID < Z7_ARRAY_SIZE(kMethodsNames)) + s += kMethodsNames[methodID]; + if (methodID == kPosix) + { + // for debug + // flags |= (UInt32)1 << kTimePrec_Win; + // flags |= (UInt32)1 << kTimePrec_1ns; + } + } + else + { + // if (is_for_MethodChanging) return; + } + + SetItemText(IDT_COMPRESS_TIME_INFO, s); + } + + m_Prec.ResetContent(); + _auto_Prec = defaultPrec; + + unsigned selectedPrec = defaultPrec; + { + // if (TimePrec >= kTimePrec_Win && TimePrec <= kTimePrec_DOS) + if ((Int32)TimePrec >= 0) + selectedPrec = TimePrec; + } + + int curSel = -1; + int defaultPrecIndex = -1; + for (unsigned prec = 0; + // prec <= k_PropVar_TimePrec_HighPrec; + prec <= k_PropVar_TimePrec_1ns; + prec++) + { + if (((flags >> prec) & 1) == 0) + continue; + const bool isDefault = (defaultPrec == prec); + const int index = AddPrec(prec, isDefault); + if (isDefault) + defaultPrecIndex = index; + if (selectedPrec == prec) + curSel = index; + } + + if (curSel < 0 && selectedPrec > kTimePrec_DOS) + curSel = AddPrec(selectedPrec, false); // isDefault + if (curSel < 0) + curSel = defaultPrecIndex; + if (curSel >= 0) + m_Prec.SetCurSel(curSel); + + { + const bool isSet = IsSet_TimePrec(); + const int count = m_Prec.GetCount(); + const bool showPrec = (count != 0); + ShowItem_Bool(IDC_COMPRESS_TIME_PREC, showPrec); + ShowItem_Bool(IDT_COMPRESS_TIME_PREC, showPrec); + EnableItem(IDC_COMPRESS_TIME_PREC, isSet && (count > 1)); + + CheckButton(IDX_COMPRESS_PREC_SET, isSet); + const bool setIsSupported = isSet || (count > 1); + EnableItem(IDX_COMPRESS_PREC_SET, setIsSupported); + ShowItem_Bool(IDX_COMPRESS_PREC_SET, setIsSupported); + } + + SetTimeMAC(); +} + + +void COptionsDialog::SetTimeMAC() +{ + const CArcInfoEx &ai = cd->Get_ArcInfoEx(); + + const + bool m_allow = ai.Flags_MTime(); + bool c_allow = ai.Flags_CTime(); + bool a_allow = ai.Flags_ATime(); + + if (ai.Is_Tar()) + { + const int methodID = cd->GetMethodID(); + c_allow = false; + a_allow = false; + if (methodID == kPosix) + { + // c_allow = true; // do we need it as change time ? + a_allow = true; + } + } + + if (ai.Is_Zip()) + { + // const int methodID = GetMethodID(); + UInt32 prec = GetPrec(); + if (prec == (UInt32)(Int32)-1) + prec = _auto_Prec; + if (prec != kTimePrec_Win) + { + c_allow = false; + a_allow = false; + } + } + + + /* + MTime.DefaultVal = true; + CTime.DefaultVal = false; + ATime.DefaultVal = false; + */ + + MTime.DefaultVal = ai.Flags_MTime_Default(); + CTime.DefaultVal = ai.Flags_CTime_Default(); + ATime.DefaultVal = ai.Flags_ATime_Default(); + + ZTime.DefaultVal = false; + + const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + + CheckButton_BoolBox (m_allow, fo.MTime, MTime ); + CheckButton_BoolBox (c_allow, fo.CTime, CTime ); + CheckButton_BoolBox (a_allow, fo.ATime, ATime ); + CheckButton_BoolBox (true, fo.SetArcMTime, ZTime); + + if (m_allow && !fo.MTime.Def) + { + const bool isSingleFile = ai.Flags_KeepName(); + if (!isSingleFile) + { + // we can hide changing checkboxes for MTime here: + ShowItem_Bool (MTime.Set_Id, false); + EnableItem (MTime.Id, false); + } + } + // On_CheckBoxSet_Prec_Clicked(); + // const bool isSingleFile = ai.Flags_KeepName(); + // mtime for Gz can be +} + + + +void COptionsDialog::On_CheckBoxSet_Prec_Clicked() +{ + const bool isSet = IsButtonCheckedBool(IDX_COMPRESS_PREC_SET); + if (!isSet) + { + // We save current MAC boxes to memory before SetPrec() + Store_TimeBoxes(); + Reset_TimePrec(); + SetPrec(); + } + EnableItem(IDC_COMPRESS_TIME_PREC, isSet); +} + +void COptionsDialog::On_CheckBoxSet_Clicked(const CBoolBox &bb) +{ + const bool isSet = IsButtonCheckedBool(bb.Set_Id); + if (!isSet) + CheckButton(bb.Id, bb.DefaultVal); + EnableItem(bb.Id, isSet); +} + + + + +#ifdef Z7_LANG +static const UInt32 kLangIDs_Options[] = +{ + IDX_COMPRESS_NT_SYM_LINKS, + IDX_COMPRESS_NT_HARD_LINKS, + IDX_COMPRESS_NT_ALT_STREAMS, + IDX_COMPRESS_NT_SECUR, + + IDG_COMPRESS_TIME, + IDT_COMPRESS_TIME_PREC, + IDX_COMPRESS_MTIME, + IDX_COMPRESS_CTIME, + IDX_COMPRESS_ATIME, + IDX_COMPRESS_ZTIME, + IDX_COMPRESS_PRESERVE_ATIME +}; +#endif + + +bool COptionsDialog::OnInit() +{ + #ifdef Z7_LANG + LangSetWindowText(*this, IDB_COMPRESS_OPTIONS); // IDS_OPTIONS + LangSetDlgItems(*this, kLangIDs_Options, Z7_ARRAY_SIZE(kLangIDs_Options)); + // LangSetDlgItemText(*this, IDB_COMPRESS_TIME_DEFAULT, IDB_COMPRESS_TIME_DEFAULT); + // LangSetDlgItemText(*this, IDX_COMPRESS_TIME_DEFAULT, IDX_COMPRESS_TIME_DEFAULT); + #endif + + LangString(IDS_COMPRESS_SEC, SecString); + if (SecString.IsEmpty()) + SecString = "sec"; + LangString(IDS_COMPRESS_NS, NsString); + if (NsString.IsEmpty()) + NsString = "ns"; + + { + // const CArcInfoEx &ai = cd->Get_ArcInfoEx(); + + ShowItem_Bool ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks.Supported); + ShowItem_Bool ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks.Supported); + ShowItem_Bool ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams.Supported); + ShowItem_Bool ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity.Supported); + + ShowItem_Bool ( IDG_COMPRESS_NTFS, + cd->SymLinks.Supported + || cd->HardLinks.Supported + || cd->AltStreams.Supported + || cd->NtSecurity.Supported); + } + + /* we read property from two sources: + 1) command line : (Info) + 2) registry : (m_RegistryInfo) + (Info) has priority, if both are no defined */ + + CheckButton_Bool1 ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks); + CheckButton_Bool1 ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks); + CheckButton_Bool1 ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams); + CheckButton_Bool1 ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity); + + CheckButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime); + + m_Prec.Attach (GetItem(IDC_COMPRESS_TIME_PREC)); + + MTime.SetIDs ( IDX_COMPRESS_MTIME, IDX_COMPRESS_MTIME_SET); + CTime.SetIDs ( IDX_COMPRESS_CTIME, IDX_COMPRESS_CTIME_SET); + ATime.SetIDs ( IDX_COMPRESS_ATIME, IDX_COMPRESS_ATIME_SET); + ZTime.SetIDs ( IDX_COMPRESS_ZTIME, IDX_COMPRESS_ZTIME_SET); + + { + const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + TimePrec = fo.TimePrec; + MTime.BoolPair = fo.MTime; + CTime.BoolPair = fo.CTime; + ATime.BoolPair = fo.ATime; + ZTime.BoolPair = fo.SetArcMTime; + } + + SetPrec(); + + NormalizePosition(); + + return CModalDialog::OnInit(); +} + + +bool COptionsDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_COMPRESS_TIME_PREC: + { + Store_TimeBoxes(); + SetTimeMAC(); // for zip/tar + return true; + } + } + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + + +bool COptionsDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDX_COMPRESS_PREC_SET: { On_CheckBoxSet_Prec_Clicked(); return true; } + case IDX_COMPRESS_MTIME_SET: { On_CheckBoxSet_Clicked (MTime); return true; } + case IDX_COMPRESS_CTIME_SET: { On_CheckBoxSet_Clicked (CTime); return true; } + case IDX_COMPRESS_ATIME_SET: { On_CheckBoxSet_Clicked (ATime); return true; } + case IDX_COMPRESS_ZTIME_SET: { On_CheckBoxSet_Clicked (ZTime); return true; } + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + + +void COptionsDialog::OnOK() +{ + GetButton_Bool1 (IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks); + GetButton_Bool1 (IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks); + GetButton_Bool1 (IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams); + GetButton_Bool1 (IDX_COMPRESS_NT_SECUR, cd->NtSecurity); + GetButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime); + + Store_TimeBoxes(); + { + NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + fo.TimePrec = TimePrec; + fo.MTime = MTime.BoolPair; + fo.CTime = CTime.BoolPair; + fo.ATime = ATime.BoolPair; + fo.SetArcMTime = ZTime.BoolPair; + } + + CModalDialog::OnOK(); +} + +void COptionsDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic_Options); +} diff --git a/CPP/7zip/UI/GUI/CompressDialog.h b/CPP/7zip/UI/GUI/CompressDialog.h index 54826c6b1..e0f3aa536 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.h +++ b/CPP/7zip/UI/GUI/CompressDialog.h @@ -1,481 +1,483 @@ -// CompressDialog.h - -#ifndef ZIP7_INC_COMPRESS_DIALOG_H -#define ZIP7_INC_COMPRESS_DIALOG_H - -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Edit.h" - -#include "../Common/LoadCodecs.h" -#include "../Common/ZipRegistry.h" - -#include "../FileManager/DialogSize.h" - -#include "CompressDialogRes.h" - -namespace NCompressDialog -{ - namespace NUpdateMode - { - enum EEnum - { - kAdd, - kUpdate, - kFresh, - kSync - }; - } - - struct CInfo - { - NUpdateMode::EEnum UpdateMode; - NWildcard::ECensorPathMode PathMode; - - bool SolidIsSpecified; - // bool MultiThreadIsAllowed; - UInt64 SolidBlockSize; - UInt32 NumThreads; - - NCompression::CMemUse MemUsage; - - CRecordVector VolumeSizes; - - UInt32 Level; - UString Method; - UInt64 Dict64; - // UInt64 Dict64_Chain; - bool OrderMode; - UInt32 Order; - UString Options; - - UString EncryptionMethod; - - bool SFXMode; - bool OpenShareForWrite; - bool DeleteAfterCompressing; - - CBoolPair SymLinks; - CBoolPair HardLinks; - CBoolPair AltStreams; - CBoolPair NtSecurity; - - CBoolPair PreserveATime; - - UInt32 TimePrec; - CBoolPair MTime; - CBoolPair CTime; - CBoolPair ATime; - CBoolPair SetArcMTime; - - UString ArcPath; // in: Relative or abs ; out: Relative or abs - - // FString CurrentDirPrefix; - bool KeepName; - - bool GetFullPathName(UString &result) const; - - int FormatIndex; - - UString Password; - bool EncryptHeadersIsAllowed; - bool EncryptHeaders; - - CInfo(): - UpdateMode(NCompressDialog::NUpdateMode::kAdd), - PathMode(NWildcard::k_RelatPath), - SFXMode(false), - OpenShareForWrite(false), - DeleteAfterCompressing(false), - FormatIndex(-1) - { - Level = Order = (UInt32)(Int32)-1; - NumThreads = (UInt32)(Int32)-1; - SolidIsSpecified = false; - Dict64 = (UInt64)(Int64)(-1); - // Dict64_Chain = (UInt64)(Int64)(-1); - OrderMode = false; - Method.Empty(); - Options.Empty(); - EncryptionMethod.Empty(); - TimePrec = (UInt32)(Int32)(-1); - } - }; -} - - -struct CBool1 -{ - bool Val; - bool Supported; - - CBool1(): Val(false), Supported(false) {} - - void Init() - { - Val = false; - Supported = false; - } - - void SetTrueTrue() - { - Val = true; - Supported = true; - } - - void SetVal_as_Supported(bool val) - { - Val = val; - Supported = true; - } - - /* - bool IsVal_True_and_Defined() const - { - return Def && Val; - } - */ -}; - - -class CCompressDialog: public NWindows::NControl::CModalDialog -{ - NWindows::NControl::CComboBox m_ArchivePath; - NWindows::NControl::CComboBox m_Format; - NWindows::NControl::CComboBox m_Level; - NWindows::NControl::CComboBox m_Method; - NWindows::NControl::CComboBox m_Dictionary; - // NWindows::NControl::CComboBox m_Dictionary_Chain; - NWindows::NControl::CComboBox m_Order; - NWindows::NControl::CComboBox m_Solid; - NWindows::NControl::CComboBox m_NumThreads; - NWindows::NControl::CComboBox m_MemUse; - NWindows::NControl::CComboBox m_Volume; - - int _dictionaryCombo_left; - - UStringVector _memUse_Strings; - - NWindows::NControl::CDialogChildControl m_Params; - - NWindows::NControl::CComboBox m_UpdateMode; - NWindows::NControl::CComboBox m_PathMode; - - NWindows::NControl::CEdit _password1Control; - NWindows::NControl::CEdit _password2Control; - NWindows::NControl::CComboBox _encryptionMethod; - - int _auto_MethodId; - UInt32 _auto_Dict; // (UInt32)(Int32)-1 means unknown - UInt32 _auto_Dict_Chain; // (UInt32)(Int32)-1 means unknown - UInt32 _auto_Order; - UInt64 _auto_Solid; - UInt32 _auto_NumThreads; - - int _default_encryptionMethod_Index; - - int m_PrevFormat; - UString DirPrefix; - UString StartDirPrefix; - - bool _ramSize_Defined; - UInt64 _ramSize; // full RAM size avail - UInt64 _ramSize_Reduced; // full for 64-bit and reduced for 32-bit - UInt64 _ramUsage_Auto; - -public: - NCompression::CInfo m_RegistryInfo; - - CBool1 SymLinks; - CBool1 HardLinks; - CBool1 AltStreams; - CBool1 NtSecurity; - CBool1 PreserveATime; - - void SetArchiveName(const UString &name); - int FindRegistryFormat(const UString &name); - unsigned FindRegistryFormat_Always(const UString &name); - - const CArcInfoEx &Get_ArcInfoEx() - { - return (*ArcFormats)[GetFormatIndex()]; - } - - NCompression::CFormatOptions &Get_FormatOptions(); - - void CheckSFXNameChange(); - void SetArchiveName2(bool prevWasSFX); - - unsigned GetStaticFormatIndex(); - - void SetNearestSelectComboBox(NWindows::NControl::CComboBox &comboBox, UInt32 value); - - void SetLevel2(); - void SetLevel() - { - SetLevel2(); - EnableMultiCombo(IDC_COMPRESS_LEVEL); - SetMethod(); - } - - void SetMethod2(int keepMethodId); - void SetMethod(int keepMethodId = -1) - { - SetMethod2(keepMethodId); - EnableMultiCombo(IDC_COMPRESS_METHOD); - } - - void MethodChanged() - { - SetDictionary2(); - EnableMultiCombo(IDC_COMPRESS_DICTIONARY); - // EnableMultiCombo(IDC_COMPRESS_DICTIONARY2); - SetOrder2(); - EnableMultiCombo(IDC_COMPRESS_ORDER); - } - - int GetMethodID_RAW(); - int GetMethodID(); - - UString GetMethodSpec(UString &estimatedName); - UString GetMethodSpec(); - bool IsMethodEqualTo(const UString &s); - UString GetEncryptionMethodSpec(); - - bool IsZipFormat(); - bool IsXzFormat(); - - void SetEncryptionMethod(); - - int AddDict2(size_t sizeReal, size_t sizeShow); - int AddDict(size_t size); - // int AddDict_Chain(size_t size); - - void SetDictionary2(); - - UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); - UInt64 GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax = 0); - - UInt32 GetLevel() { return GetComboValue(m_Level); } - UInt32 GetLevelSpec() { return GetComboValue(m_Level, 1); } - UInt32 GetLevel2(); - - UInt64 GetDictSpec() { return GetComboValue_64(m_Dictionary, 1); } - // UInt64 GetDictChainSpec() { return GetComboValue_64(m_Dictionary_Chain, 1); } - - UInt64 GetDict2() - { - UInt64 num = GetDictSpec(); - if (num == (UInt64)(Int64)-1) - { - if (_auto_Dict == (UInt32)(Int32)-1) - return (UInt64)(Int64)-1; // unknown - num = _auto_Dict; - } - return num; - } - - // UInt32 GetOrder() { return GetComboValue(m_Order); } - UInt32 GetOrderSpec() { return GetComboValue(m_Order, 1); } - UInt32 GetNumThreadsSpec() { return GetComboValue(m_NumThreads, 1); } - - UInt32 GetNumThreads2() - { - UInt32 num = GetNumThreadsSpec(); - if (num == (UInt32)(Int32)-1) - num = _auto_NumThreads; - return num; - } - - UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } - - /* - UInt32 GetPrecSpec() { return GetComboValue(m_Prec, 1); } - UInt32 GetPrec() { return GetComboValue(m_Prec, 0); } - */ - - - int AddOrder(UInt32 size); - int AddOrder_Auto(); - - void SetOrder2(); - - bool GetOrderMode(); - - void SetSolidBlockSize2(); - void SetSolidBlockSize(/* bool useDictionary = false */) - { - SetSolidBlockSize2(); - EnableMultiCombo(IDC_COMPRESS_SOLID); - } - - void SetNumThreads2(); - void SetNumThreads() - { - SetNumThreads2(); - EnableMultiCombo(IDC_COMPRESS_THREADS); - } - - int AddMemComboItem(UInt64 val, bool isPercent = false, bool isDefault = false); - void SetMemUseCombo(); - UString Get_MemUse_Spec(); - UInt64 Get_MemUse_Bytes(); - - UInt64 GetMemoryUsage_Dict_DecompMem(UInt64 dict, UInt64 &decompressMemory); - UInt64 GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict, UInt64 &decompressMemory); - UInt64 GetMemoryUsage_DecompMem(UInt64 &decompressMemory); - UInt64 GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64); - - void PrintMemUsage(UINT res, UInt64 value); - void SetMemoryUsage(); - void Print_Params(); - - void SetParams(); - - void SaveOptionsInMem(); - - void UpdatePasswordControl(); - bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); } - - unsigned GetFormatIndex(); - bool SetArcPathFields(const UString &path, UString &name, bool always); - bool SetArcPathFields(const UString &path); - bool GetFinalPath_Smart(UString &resPath) const; - void ArcPath_WasChanged(const UString &newPath); - - void CheckSFXControlsEnable(); - // void CheckVolumeEnable(); - void EnableMultiCombo(unsigned id); - void FormatChanged(bool isChanged); - - void OnButtonSetArchive(); - bool IsSFX(); - void OnButtonSFX(); - - virtual bool OnInit() Z7_override; - virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual void OnOK() Z7_override; - virtual void OnHelp() Z7_override; - - void MessageBoxError(LPCWSTR message) - { - MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); - } - - void ShowOptionsString(); - -public: - const CObjectVector *ArcFormats; - CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 - AStringVector ExternalMethods; - - void SetMethods(const CObjectVector &userCodecs); - - NCompressDialog::CInfo Info; - UString OriginalFileName; // for bzip2, gzip2 - - INT_PTR Create(HWND wndParent = NULL) - { - BIG_DIALOG_SIZE(400, 320); - return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent); - } - - CCompressDialog() {} -}; - - - - -class COptionsDialog: public NWindows::NControl::CModalDialog -{ - struct CBoolBox - { - bool IsSupported; - bool DefaultVal; - CBoolPair BoolPair; - - unsigned Id; - unsigned Set_Id; - - void SetIDs(unsigned id, unsigned set_Id) - { - Id = id; - Set_Id = set_Id; - } - - CBoolBox(): - IsSupported(false), - DefaultVal(false) - {} - }; - - CCompressDialog *cd; - - NWindows::NControl::CComboBox m_Prec; - - UInt32 _auto_Prec; - UInt32 TimePrec; - - void Reset_TimePrec() { TimePrec = (UInt32)(Int32)-1; } - bool IsSet_TimePrec() const { return TimePrec != (UInt32)(Int32)-1; } - - CBoolBox MTime; - CBoolBox CTime; - CBoolBox ATime; - CBoolBox ZTime; - - UString SecString; - UString NsString; - - - void CheckButton_Bool1(UINT id, const CBool1 &b1); - void GetButton_Bool1(UINT id, CBool1 &b1); - void CheckButton_BoolBox(bool supported, const CBoolPair &b2, CBoolBox &bb); - void GetButton_BoolBox(CBoolBox &bb); - - void Store_TimeBoxes(); - - UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); - UInt32 GetPrecSpec() - { - UInt32 prec = GetComboValue(m_Prec, 1); - if (prec == _auto_Prec) - prec = (UInt32)(Int32)-1; - return prec; - } - UInt32 GetPrec() { return GetComboValue(m_Prec, 0); } - - // void OnButton_TimeDefault(); - int AddPrec(unsigned prec, bool isDefault); - void SetPrec(); - void SetTimeMAC(); - - void On_CheckBoxSet_Prec_Clicked(); - void On_CheckBoxSet_Clicked(const CBoolBox &bb); - - virtual bool OnInit() Z7_override; - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual void OnOK() Z7_override; - virtual void OnHelp() Z7_override; - -public: - - INT_PTR Create(HWND wndParent = NULL) - { - BIG_DIALOG_SIZE(240, 232); - return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS_OPTIONS), wndParent); - } - - COptionsDialog(CCompressDialog *cdLoc): - cd(cdLoc) - // , TimePrec(0) - { - Reset_TimePrec(); - } -}; - -#endif +// CompressDialog.h + +#ifndef ZIP7_INC_COMPRESS_DIALOG_H +#define ZIP7_INC_COMPRESS_DIALOG_H + +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" + +#include "../Common/LoadCodecs.h" +#include "../Common/ZipRegistry.h" + +#include "../FileManager/DialogSize.h" + +#include "CompressDialogRes.h" + +namespace NCompressDialog +{ + namespace NUpdateMode + { + enum EEnum + { + kAdd, + kUpdate, + kFresh, + kSync + }; + } + + struct CInfo + { + NUpdateMode::EEnum UpdateMode; + NWildcard::ECensorPathMode PathMode; + + bool SolidIsSpecified; + // bool MultiThreadIsAllowed; + UInt64 SolidBlockSize; + UInt32 NumThreads; + + NCompression::CMemUse MemUsage; + + CRecordVector VolumeSizes; + + UInt32 Level; + UString Method; + UInt64 Dict64; + // UInt64 Dict64_Chain; + bool OrderMode; + UInt32 Order; + UString Options; + + UString EncryptionMethod; + + bool SFXMode; + bool OpenShareForWrite; + bool DeleteAfterCompressing; + + CBoolPair SymLinks; + CBoolPair HardLinks; + CBoolPair AltStreams; + CBoolPair NtSecurity; + + CBoolPair PreserveATime; + + UInt32 TimePrec; + CBoolPair MTime; + CBoolPair CTime; + CBoolPair ATime; + CBoolPair SetArcMTime; + + UString ArcPath; // in: Relative or abs ; out: Relative or abs + + // FString CurrentDirPrefix; + bool KeepName; + + bool GetFullPathName(UString &result) const; + + int FormatIndex; + + UString Password; + bool EncryptHeadersIsAllowed; + bool EncryptHeaders; + + CInfo(): + UpdateMode(NCompressDialog::NUpdateMode::kAdd), + PathMode(NWildcard::k_RelatPath), + SFXMode(false), + OpenShareForWrite(false), + DeleteAfterCompressing(false), + FormatIndex(-1) + { + Level = Order = (UInt32)(Int32)-1; + NumThreads = (UInt32)(Int32)-1; + SolidIsSpecified = false; + Dict64 = (UInt64)(Int64)(-1); + // Dict64_Chain = (UInt64)(Int64)(-1); + OrderMode = false; + Method.Empty(); + Options.Empty(); + EncryptionMethod.Empty(); + TimePrec = (UInt32)(Int32)(-1); + } + }; +} + + +struct CBool1 +{ + bool Val; + bool Supported; + + CBool1(): Val(false), Supported(false) {} + + void Init() + { + Val = false; + Supported = false; + } + + void SetTrueTrue() + { + Val = true; + Supported = true; + } + + void SetVal_as_Supported(bool val) + { + Val = val; + Supported = true; + } + + /* + bool IsVal_True_and_Defined() const + { + return Def && Val; + } + */ +}; + + +class CCompressDialog: public NWindows::NControl::CModalDialog +{ +public: + CBool1 SymLinks; + CBool1 HardLinks; + CBool1 AltStreams; + CBool1 NtSecurity; + CBool1 PreserveATime; +private: + bool _ramSize_Defined; + + NWindows::NControl::CComboBox m_ArchivePath; + NWindows::NControl::CComboBox m_Format; + NWindows::NControl::CComboBox m_Level; + NWindows::NControl::CComboBox m_Method; + NWindows::NControl::CComboBox m_Dictionary; + // NWindows::NControl::CComboBox m_Dictionary_Chain; + NWindows::NControl::CComboBox m_Order; + NWindows::NControl::CComboBox m_Solid; + NWindows::NControl::CComboBox m_NumThreads; + NWindows::NControl::CComboBox m_MemUse; + NWindows::NControl::CComboBox m_Volume; + + int _dictionaryCombo_left; + + UStringVector _memUse_Strings; + + NWindows::NControl::CDialogChildControl m_Params; + + NWindows::NControl::CComboBox m_UpdateMode; + NWindows::NControl::CComboBox m_PathMode; + + NWindows::NControl::CEdit _password1Control; + NWindows::NControl::CEdit _password2Control; + NWindows::NControl::CComboBox _encryptionMethod; + + int _auto_MethodId; + UInt32 _auto_Dict; // (UInt32)(Int32)-1 means unknown + UInt32 _auto_Dict_Chain; // (UInt32)(Int32)-1 means unknown + UInt32 _auto_Order; + UInt64 _auto_Solid; + UInt32 _auto_NumThreads; + + int _default_encryptionMethod_Index; + + int m_PrevFormat; + UString DirPrefix; + UString StartDirPrefix; + + size_t _ramSize; // full RAM size avail + size_t _ramSize_Reduced; // full for 64-bit and reduced for 32-bit + UInt64 _ramUsage_Auto; + +public: + NCompression::CInfo m_RegistryInfo; + + void SetArchiveName(const UString &name); + int FindRegistryFormat(const UString &name); + unsigned FindRegistryFormat_Always(const UString &name); + + const CArcInfoEx &Get_ArcInfoEx() + { + return (*ArcFormats)[GetFormatIndex()]; + } + + NCompression::CFormatOptions &Get_FormatOptions(); + + void CheckSFXNameChange(); + void SetArchiveName2(bool prevWasSFX); + + unsigned GetStaticFormatIndex(); + + void SetNearestSelectComboBox(NWindows::NControl::CComboBox &comboBox, UInt32 value); + + void SetLevel2(); + void SetLevel() + { + SetLevel2(); + EnableMultiCombo(IDC_COMPRESS_LEVEL); + SetMethod(); + } + + void SetMethod2(int keepMethodId); + void SetMethod(int keepMethodId = -1) + { + SetMethod2(keepMethodId); + EnableMultiCombo(IDC_COMPRESS_METHOD); + } + + void MethodChanged() + { + SetDictionary2(); + EnableMultiCombo(IDC_COMPRESS_DICTIONARY); + // EnableMultiCombo(IDC_COMPRESS_DICTIONARY2); + SetOrder2(); + EnableMultiCombo(IDC_COMPRESS_ORDER); + } + + int GetMethodID_RAW(); + int GetMethodID(); + + UString GetMethodSpec(UString &estimatedName); + UString GetMethodSpec(); + bool IsMethodEqualTo(const UString &s); + UString GetEncryptionMethodSpec(); + + bool IsZipFormat(); + bool IsXzFormat(); + + void SetEncryptionMethod(); + + int AddDict2(size_t sizeReal, size_t sizeShow); + int AddDict(size_t size); + // int AddDict_Chain(size_t size); + + void SetDictionary2(); + + UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); + UInt64 GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax = 0); + + UInt32 GetLevel() { return GetComboValue(m_Level); } + UInt32 GetLevelSpec() { return GetComboValue(m_Level, 1); } + UInt32 GetLevel2(); + + UInt64 GetDictSpec() { return GetComboValue_64(m_Dictionary, 1); } + // UInt64 GetDictChainSpec() { return GetComboValue_64(m_Dictionary_Chain, 1); } + + UInt64 GetDict2() + { + UInt64 num = GetDictSpec(); + if (num == (UInt64)(Int64)-1) + { + if (_auto_Dict == (UInt32)(Int32)-1) + return (UInt64)(Int64)-1; // unknown + num = _auto_Dict; + } + return num; + } + + // UInt32 GetOrder() { return GetComboValue(m_Order); } + UInt32 GetOrderSpec() { return GetComboValue(m_Order, 1); } + UInt32 GetNumThreadsSpec() { return GetComboValue(m_NumThreads, 1); } + + UInt32 GetNumThreads2() + { + UInt32 num = GetNumThreadsSpec(); + if (num == (UInt32)(Int32)-1) + num = _auto_NumThreads; + return num; + } + + UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } + + /* + UInt32 GetPrecSpec() { return GetComboValue(m_Prec, 1); } + UInt32 GetPrec() { return GetComboValue(m_Prec, 0); } + */ + + + int AddOrder(UInt32 size); + int AddOrder_Auto(); + + void SetOrder2(); + + bool GetOrderMode(); + + void SetSolidBlockSize2(); + void SetSolidBlockSize(/* bool useDictionary = false */) + { + SetSolidBlockSize2(); + EnableMultiCombo(IDC_COMPRESS_SOLID); + } + + void SetNumThreads2(); + void SetNumThreads() + { + SetNumThreads2(); + EnableMultiCombo(IDC_COMPRESS_THREADS); + } + + int AddMemComboItem(UInt64 val, bool isPercent = false, bool isDefault = false); + void SetMemUseCombo(); + UString Get_MemUse_Spec(); + UInt64 Get_MemUse_Bytes(); + + UInt64 GetMemoryUsage_Dict_DecompMem(UInt64 dict, UInt64 &decompressMemory); + UInt64 GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict, UInt64 &decompressMemory); + UInt64 GetMemoryUsage_DecompMem(UInt64 &decompressMemory); + UInt64 GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64); + + void PrintMemUsage(UINT res, UInt64 value); + void SetMemoryUsage(); + void Print_Params(); + + void SetParams(); + + void SaveOptionsInMem(); + + void UpdatePasswordControl(); + bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); } + + unsigned GetFormatIndex(); + bool SetArcPathFields(const UString &path, UString &name, bool always); + bool SetArcPathFields(const UString &path); + bool GetFinalPath_Smart(UString &resPath) const; + void ArcPath_WasChanged(const UString &newPath); + + void CheckSFXControlsEnable(); + // void CheckVolumeEnable(); + void EnableMultiCombo(unsigned id); + void FormatChanged(bool isChanged); + + void OnButtonSetArchive(); + bool IsSFX(); + void OnButtonSFX(); + + virtual bool OnInit() Z7_override; + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual void OnOK() Z7_override; + virtual void OnHelp() Z7_override; + + void MessageBoxError(LPCWSTR message) + { + MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); + } + + void ShowOptionsString(); + +public: + const CObjectVector *ArcFormats; + CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 + AStringVector ExternalMethods; + + void SetMethods(const CObjectVector &userCodecs); + + NCompressDialog::CInfo Info; + UString OriginalFileName; // for bzip2, gzip2 + + INT_PTR Create(HWND wndParent = NULL) + { + BIG_DIALOG_SIZE(400, 320); + return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent); + } + + CCompressDialog() {} +}; + + + + +class COptionsDialog: public NWindows::NControl::CModalDialog +{ + struct CBoolBox + { + bool IsSupported; + bool DefaultVal; + CBoolPair BoolPair; + + unsigned Id; + unsigned Set_Id; + + void SetIDs(unsigned id, unsigned set_Id) + { + Id = id; + Set_Id = set_Id; + } + + CBoolBox(): + IsSupported(false), + DefaultVal(false) + {} + }; + + CCompressDialog *cd; + + NWindows::NControl::CComboBox m_Prec; + + UInt32 _auto_Prec; + UInt32 TimePrec; + + void Reset_TimePrec() { TimePrec = (UInt32)(Int32)-1; } + bool IsSet_TimePrec() const { return TimePrec != (UInt32)(Int32)-1; } + + CBoolBox MTime; + CBoolBox CTime; + CBoolBox ATime; + CBoolBox ZTime; + + UString SecString; + UString NsString; + + + void CheckButton_Bool1(UINT id, const CBool1 &b1); + void GetButton_Bool1(UINT id, CBool1 &b1); + void CheckButton_BoolBox(bool supported, const CBoolPair &b2, CBoolBox &bb); + void GetButton_BoolBox(CBoolBox &bb); + + void Store_TimeBoxes(); + + UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); + UInt32 GetPrecSpec() + { + UInt32 prec = GetComboValue(m_Prec, 1); + if (prec == _auto_Prec) + prec = (UInt32)(Int32)-1; + return prec; + } + UInt32 GetPrec() { return GetComboValue(m_Prec, 0); } + + // void OnButton_TimeDefault(); + int AddPrec(unsigned prec, bool isDefault); + void SetPrec(); + void SetTimeMAC(); + + void On_CheckBoxSet_Prec_Clicked(); + void On_CheckBoxSet_Clicked(const CBoolBox &bb); + + virtual bool OnInit() Z7_override; + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual void OnOK() Z7_override; + virtual void OnHelp() Z7_override; + +public: + + INT_PTR Create(HWND wndParent = NULL) + { + BIG_DIALOG_SIZE(240, 232); + return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS_OPTIONS), wndParent); + } + + COptionsDialog(CCompressDialog *cdLoc): + cd(cdLoc) + // , TimePrec(0) + { + Reset_TimePrec(); + } +}; + +#endif diff --git a/CPP/7zip/UI/GUI/CompressDialog.rc b/CPP/7zip/UI/GUI/CompressDialog.rc index dd895a85a..9c3ed887c 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.rc +++ b/CPP/7zip/UI/GUI/CompressDialog.rc @@ -1,233 +1,233 @@ -#include "CompressDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 400 -#define yc 320 - -#undef gSize -#undef gSpace -#undef g0xs -#undef g1x -#undef g1xs -#undef g2xs -#undef g3x -#undef g3xs -#undef g4x -#undef g4x2 -#undef g4xs -#undef g4xs2 - -#define gSize 192 -#define gSpace 24 - - -#define g1xs 88 -#define g0xs (gSize - g1xs) -#define g1x (m + g0xs) - -#define g3xs 52 -#define g2xs (gSize - g3xs) -#define g3x (m + g2xs) - -#define g4x (m + gSize + gSpace) -#define g4x2 (g4x + m) -#define g4xs (xc - gSize - gSpace) -#define g4xs2 (g4xs - m - m) - -#define yOpt 80 - -#define xArcFolderOffs 40 - -#undef GROUP_Y_SIZE -#undef GROUP_Y_SIZE_ENCRYPT -#ifdef UNDER_CE -#define GROUP_Y_SIZE 8 -#define GROUP_Y_SIZE_ENCRYPT 8 -#else -#define GROUP_Y_SIZE 64 -#define GROUP_Y_SIZE_ENCRYPT 128 -#endif - -// #define DICT_SIZE_SPACE 8 -// #define DICT_SIZE 54 -// #define DICT_x (g1x + g1xs - DICT_SIZE) -// #define DICT2_x (DICT_x - DICT_SIZE_SPACE - DICT_SIZE) - -#define yPsw (yOpt + GROUP_Y_SIZE + 8) - -IDD_COMPRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Add to Archive" -BEGIN - LTEXT "", IDT_COMPRESS_ARCHIVE_FOLDER, m + xArcFolderOffs, m, xc - xArcFolderOffs, 8 - LTEXT "&Archive:", IDT_COMPRESS_ARCHIVE, m, 12, xArcFolderOffs, 8 - COMBOBOX IDC_COMPRESS_ARCHIVE, m + xArcFolderOffs, 18, xc - bxsDots - 12 - xArcFolderOffs, 126, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_COMPRESS_SET_ARCHIVE, xs - m - bxsDots, 16, bxsDots, bys, WS_GROUP - - LTEXT "Archive &format:", IDT_COMPRESS_FORMAT, m, 41, g0xs, 8 - COMBOBOX IDC_COMPRESS_FORMAT, g1x, 39, g1xs, 80, MY_COMBO | CBS_SORT - - LTEXT "Compression &level:", IDT_COMPRESS_LEVEL, m, 62, g0xs, 8 - COMBOBOX IDC_COMPRESS_LEVEL, g1x, 60, g1xs, 80, MY_COMBO - - LTEXT "Compression &method:", IDT_COMPRESS_METHOD, m, 83, g0xs, 8 - COMBOBOX IDC_COMPRESS_METHOD, g1x, 81, g1xs, 80, MY_COMBO - - LTEXT "&Dictionary size:", IDT_COMPRESS_DICTIONARY, m, 104, g0xs, 8 - COMBOBOX IDC_COMPRESS_DICTIONARY, g1x, 102, g1xs, 167, MY_COMBO - // LTEXT "&Dictionary size:", IDT_COMPRESS_DICTIONARY, m, 104, DICT_x - m, 16 // 8, SS_LEFTNOWORDWRAP - // LTEXT "", IDT_COMPRESS_PARAMS_INFO, m, 283, xs, MY_TEXT_NOPREFIX - // CTEXT "-", 0, DICT_x - DICT_SIZE_SPACE, 104, DICT_SIZE_SPACE, 8 - // COMBOBOX IDC_COMPRESS_DICTIONARY2, DICT2_x, 102, DICT_SIZE, 140, MY_COMBO - // COMBOBOX IDC_COMPRESS_DICTIONARY, DICT_x, 102, DICT_SIZE, 140, MY_COMBO - - LTEXT "&Word size:", IDT_COMPRESS_ORDER, m, 125, g0xs, 8 - COMBOBOX IDC_COMPRESS_ORDER, g1x, 123, g1xs, 140, MY_COMBO - - LTEXT "&Solid Block size:", IDT_COMPRESS_SOLID, m, 146, g0xs, 8 - COMBOBOX IDC_COMPRESS_SOLID, g1x, 144, g1xs, 140, MY_COMBO - - LTEXT "Number of CPU &threads:", IDT_COMPRESS_THREADS, m, 167, g0xs, 8 - COMBOBOX IDC_COMPRESS_THREADS, g1x, 165, g1xs - 35, 140, MY_COMBO - RTEXT "", IDT_COMPRESS_HARDWARE_THREADS, g1x + g1xs - 35 + 10, 167, 25, MY_TEXT_NOPREFIX - - - LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 184, g2xs, 8 - COMBOBOX IDC_COMPRESS_MEM_USE, g3x, 188, g3xs, 140, MY_COMBO - LTEXT "", IDT_COMPRESS_MEMORY_VALUE, m, 194, g2xs, MY_TEXT_NOPREFIX - - LTEXT "Memory usage for Decompressing:", IDT_COMPRESS_MEMORY_DE, m, 208, g2xs, 8 - RTEXT "", IDT_COMPRESS_MEMORY_DE_VALUE, g3x, 208, g3xs, MY_TEXT_NOPREFIX - - - LTEXT "Split to &volumes, bytes:", IDT_SPLIT_TO_VOLUMES, m, 225, gSize, 8 - COMBOBOX IDC_COMPRESS_VOLUME, m, 237, gSize, 73, MY_COMBO_WITH_EDIT - - LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m, 256, gSize, 8 - EDITTEXT IDE_COMPRESS_PARAMETERS, m, 268, gSize, 14, ES_AUTOHSCROLL - - PUSHBUTTON "Options", IDB_COMPRESS_OPTIONS, m, 292, bxs, bys - LTEXT "", IDT_COMPRESS_OPTIONS, m + bxs + m, 294, gSize - bxs - m, 16, SS_NOPREFIX - - - LTEXT "&Update mode:", IDT_COMPRESS_UPDATE_MODE, g4x, 41, 80, 8 - COMBOBOX IDC_COMPRESS_UPDATE_MODE, g4x + 84, 39, g4xs - 84, 80, MY_COMBO - - LTEXT "Path mode:", IDT_COMPRESS_PATH_MODE, g4x, 61, 80, 8 - COMBOBOX IDC_COMPRESS_PATH_MODE, g4x + 84, 59, g4xs - 84, 80, MY_COMBO - - - GROUPBOX "Options", IDG_COMPRESS_OPTIONS, g4x, yOpt, g4xs, GROUP_Y_SIZE - - CONTROL "Create SF&X archive", IDX_COMPRESS_SFX, MY_CHECKBOX, - g4x2, yOpt + 14, g4xs2, 10 - CONTROL "Compress shared files", IDX_COMPRESS_SHARED, MY_CHECKBOX, - g4x2, yOpt + 30, g4xs2, 10 - CONTROL "Delete files after compression", IDX_COMPRESS_DEL, MY_CHECKBOX, - g4x2, yOpt + 46, g4xs2, 10 - - - GROUPBOX "Encryption", IDG_COMPRESS_ENCRYPTION, g4x, yPsw, g4xs, GROUP_Y_SIZE_ENCRYPT - - LTEXT "Enter &password:", IDT_PASSWORD_ENTER, g4x2, yPsw + 14, g4xs2, 8 - EDITTEXT IDE_COMPRESS_PASSWORD1, g4x2, yPsw + 26, g4xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL - LTEXT "Reenter password:", IDT_PASSWORD_REENTER, g4x2, yPsw + 46, g4xs2, 8 - EDITTEXT IDE_COMPRESS_PASSWORD2, g4x2, yPsw + 58, g4xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL - - CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, - g4x2, yPsw + 79, g4xs2, 10 - - LTEXT "&Encryption method:", IDT_COMPRESS_ENCRYPTION_METHOD, g4x2, yPsw + 95, 100, 8 - COMBOBOX IDC_COMPRESS_ENCRYPTION_METHOD, g4x2 + 100, yPsw + 93, g4xs2 - 100, 198, MY_COMBO - - CONTROL "Encrypt file &names", IDX_COMPRESS_ENCRYPT_FILE_NAMES, MY_CHECKBOX, - g4x2, yPsw + 111, g4xs2, 10 - - DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys - PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys -END - - -#ifdef UNDER_CE - -#undef m -#undef xc -#undef yc - -#define m 4 -#define xc 152 -#define yc 160 - - -IDD_COMPRESS_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Add to Archive" -MY_FONT -BEGIN - COMBOBOX IDC_COMPRESS_ARCHIVE, m, m, xc - bxsDots - m, 126, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_COMPRESS_SET_ARCHIVE, xs - m - bxsDots, m, bxsDots, 12, WS_GROUP - - COMBOBOX IDC_COMPRESS_FORMAT, m , 22, 32, 80, MY_COMBO | CBS_SORT - COMBOBOX IDC_COMPRESS_LEVEL, m + 36, 22, 68, 80, MY_COMBO - COMBOBOX IDC_COMPRESS_METHOD, m + 108, 22, 44, 80, MY_COMBO - - COMBOBOX IDC_COMPRESS_DICTIONARY, m, 40, 40, 80, MY_COMBO - COMBOBOX IDC_COMPRESS_ORDER, m + 44, 40, 32, 80, MY_COMBO - COMBOBOX IDC_COMPRESS_SOLID, m + 80, 40, 40, 80, MY_COMBO - COMBOBOX IDC_COMPRESS_THREADS, m + 124, 40, 28, 80, MY_COMBO - - LTEXT "Split to &volumes, bytes:", IDT_SPLIT_TO_VOLUMES, m, 60, 32, 8 - COMBOBOX IDC_COMPRESS_VOLUME, m + 32, 58, 44, 73, MY_COMBO_WITH_EDIT - LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m + 80, 60, 48, 8 - EDITTEXT IDE_COMPRESS_PARAMETERS, m + 128, 58, 24, 13, ES_AUTOHSCROLL - - COMBOBOX IDC_COMPRESS_UPDATE_MODE, m, 76, 88, 80, MY_COMBO - CONTROL "SF&X", IDX_COMPRESS_SFX, MY_CHECKBOX, m + 92, 77, 60, 10 - - CONTROL "Compress shared files", IDX_COMPRESS_SHARED, MY_CHECKBOX, m, 94, xc, 10 - - LTEXT "Enter &password:", IDT_PASSWORD_ENTER, m, 112, 60, 8 - EDITTEXT IDE_COMPRESS_PASSWORD1, m + 60, 110, 44, 13, ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m + 108, 112, 44, 10 - - COMBOBOX IDC_COMPRESS_ENCRYPTION_METHOD, m, 128, 48, 198, MY_COMBO - CONTROL "Encrypt file &names", IDX_COMPRESS_ENCRYPT_FILE_NAMES, MY_CHECKBOX, m + 52, 130, 100, 10 - - OK_CANCEL -END - -#endif - -STRINGTABLE -BEGIN - IDS_PASSWORD_NOT_MATCH "Passwords do not match" - IDS_PASSWORD_USE_ASCII "Use only English letters, numbers and special characters (!, #, $, ...) for password." - IDS_PASSWORD_TOO_LONG "Password is too long" - - IDS_METHOD_STORE "Store" - IDS_METHOD_FASTEST "Fastest" - IDS_METHOD_FAST "Fast" - IDS_METHOD_NORMAL "Normal" - IDS_METHOD_MAXIMUM "Maximum" - IDS_METHOD_ULTRA "Ultra" - - IDS_COMPRESS_UPDATE_MODE_ADD "Add and replace files" - IDS_COMPRESS_UPDATE_MODE_UPDATE "Update and add files" - IDS_COMPRESS_UPDATE_MODE_FRESH "Freshen existing files" - IDS_COMPRESS_UPDATE_MODE_SYNC "Synchronize files" - - IDS_OPEN_TYPE_ALL_FILES "All Files" - IDS_COMPRESS_SET_ARCHIVE_BROWSE "Browse" - - IDS_COMPRESS_NON_SOLID "Non-solid" - IDS_COMPRESS_SOLID "Solid" - - IDS_SPLIT_CONFIRM "Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?" - - IDS_COMPRESS_SEC "sec" - IDS_COMPRESS_NS "ns" - - IDS_MEM_OPERATION_BLOCKED "The operation was blocked by 7-Zip." -END - - -#include "CompressOptionsDialog.rc" +#include "CompressDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 400 +#define yc 320 + +#undef gSize +#undef gSpace +#undef g0xs +#undef g1x +#undef g1xs +#undef g2xs +#undef g3x +#undef g3xs +#undef g4x +#undef g4x2 +#undef g4xs +#undef g4xs2 + +#define gSize 192 +#define gSpace 24 + + +#define g1xs 88 +#define g0xs (gSize - g1xs) +#define g1x (m + g0xs) + +#define g3xs 52 +#define g2xs (gSize - g3xs) +#define g3x (m + g2xs) + +#define g4x (m + gSize + gSpace) +#define g4x2 (g4x + m) +#define g4xs (xc - gSize - gSpace) +#define g4xs2 (g4xs - m - m) + +#define yOpt 80 + +#define xArcFolderOffs 40 + +#undef GROUP_Y_SIZE +#undef GROUP_Y_SIZE_ENCRYPT +#ifdef UNDER_CE +#define GROUP_Y_SIZE 8 +#define GROUP_Y_SIZE_ENCRYPT 8 +#else +#define GROUP_Y_SIZE 64 +#define GROUP_Y_SIZE_ENCRYPT 128 +#endif + +// #define DICT_SIZE_SPACE 8 +// #define DICT_SIZE 54 +// #define DICT_x (g1x + g1xs - DICT_SIZE) +// #define DICT2_x (DICT_x - DICT_SIZE_SPACE - DICT_SIZE) + +#define yPsw (yOpt + GROUP_Y_SIZE + 8) + +IDD_COMPRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Add to Archive" +BEGIN + LTEXT "", IDT_COMPRESS_ARCHIVE_FOLDER, m + xArcFolderOffs, m, xc - xArcFolderOffs, 8 + LTEXT "&Archive:", IDT_COMPRESS_ARCHIVE, m, 12, xArcFolderOffs, 8 + COMBOBOX IDC_COMPRESS_ARCHIVE, m + xArcFolderOffs, 18, xc - bxsDots - 12 - xArcFolderOffs, 126, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_COMPRESS_SET_ARCHIVE, xs - m - bxsDots, 16, bxsDots, bys, WS_GROUP + + LTEXT "Archive &format:", IDT_COMPRESS_FORMAT, m, 41, g0xs, 8 + COMBOBOX IDC_COMPRESS_FORMAT, g1x, 39, g1xs, 80, MY_COMBO | CBS_SORT + + LTEXT "Compression &level:", IDT_COMPRESS_LEVEL, m, 62, g0xs, 8 + COMBOBOX IDC_COMPRESS_LEVEL, g1x, 60, g1xs, 80, MY_COMBO + + LTEXT "Compression &method:", IDT_COMPRESS_METHOD, m, 83, g0xs, 8 + COMBOBOX IDC_COMPRESS_METHOD, g1x, 81, g1xs, 80, MY_COMBO + + LTEXT "&Dictionary size:", IDT_COMPRESS_DICTIONARY, m, 104, g0xs, 8 + COMBOBOX IDC_COMPRESS_DICTIONARY, g1x, 102, g1xs, 167, MY_COMBO + // LTEXT "&Dictionary size:", IDT_COMPRESS_DICTIONARY, m, 104, DICT_x - m, 16 // 8, SS_LEFTNOWORDWRAP + // LTEXT "", IDT_COMPRESS_PARAMS_INFO, m, 283, xs, MY_TEXT_NOPREFIX + // CTEXT "-", 0, DICT_x - DICT_SIZE_SPACE, 104, DICT_SIZE_SPACE, 8 + // COMBOBOX IDC_COMPRESS_DICTIONARY2, DICT2_x, 102, DICT_SIZE, 140, MY_COMBO + // COMBOBOX IDC_COMPRESS_DICTIONARY, DICT_x, 102, DICT_SIZE, 140, MY_COMBO + + LTEXT "&Word size:", IDT_COMPRESS_ORDER, m, 125, g0xs, 8 + COMBOBOX IDC_COMPRESS_ORDER, g1x, 123, g1xs, 140, MY_COMBO + + LTEXT "&Solid Block size:", IDT_COMPRESS_SOLID, m, 146, g0xs, 8 + COMBOBOX IDC_COMPRESS_SOLID, g1x, 144, g1xs, 140, MY_COMBO + + LTEXT "Number of CPU &threads:", IDT_COMPRESS_THREADS, m, 167, g0xs, 8 + COMBOBOX IDC_COMPRESS_THREADS, g1x, 165, g1xs - 35, 140, MY_COMBO + RTEXT "", IDT_COMPRESS_HARDWARE_THREADS, g1x + g1xs - 35 + 10, 167, 25, MY_TEXT_NOPREFIX + + + LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 184, g2xs, 8 + COMBOBOX IDC_COMPRESS_MEM_USE, g3x, 188, g3xs, 140, MY_COMBO + LTEXT "", IDT_COMPRESS_MEMORY_VALUE, m, 194, g2xs, MY_TEXT_NOPREFIX + + LTEXT "Memory usage for Decompressing:", IDT_COMPRESS_MEMORY_DE, m, 208, g2xs, 8 + RTEXT "", IDT_COMPRESS_MEMORY_DE_VALUE, g3x, 208, g3xs, MY_TEXT_NOPREFIX + + + LTEXT "Split to &volumes, bytes:", IDT_SPLIT_TO_VOLUMES, m, 225, gSize, 8 + COMBOBOX IDC_COMPRESS_VOLUME, m, 237, gSize, 73, MY_COMBO_WITH_EDIT + + LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m, 256, gSize, 8 + EDITTEXT IDE_COMPRESS_PARAMETERS, m, 268, gSize, 14, ES_AUTOHSCROLL + + PUSHBUTTON "Options", IDB_COMPRESS_OPTIONS, m, 292, bxs, bys + LTEXT "", IDT_COMPRESS_OPTIONS, m + bxs + m, 294, gSize - bxs - m, 16, SS_NOPREFIX + + + LTEXT "&Update mode:", IDT_COMPRESS_UPDATE_MODE, g4x, 41, 80, 8 + COMBOBOX IDC_COMPRESS_UPDATE_MODE, g4x + 84, 39, g4xs - 84, 80, MY_COMBO + + LTEXT "Path mode:", IDT_COMPRESS_PATH_MODE, g4x, 61, 80, 8 + COMBOBOX IDC_COMPRESS_PATH_MODE, g4x + 84, 59, g4xs - 84, 80, MY_COMBO + + + GROUPBOX "Options", IDG_COMPRESS_OPTIONS, g4x, yOpt, g4xs, GROUP_Y_SIZE + + CONTROL "Create SF&X archive", IDX_COMPRESS_SFX, MY_CHECKBOX, + g4x2, yOpt + 14, g4xs2, 10 + CONTROL "Compress shared files", IDX_COMPRESS_SHARED, MY_CHECKBOX, + g4x2, yOpt + 30, g4xs2, 10 + CONTROL "Delete files after compression", IDX_COMPRESS_DEL, MY_CHECKBOX, + g4x2, yOpt + 46, g4xs2, 10 + + + GROUPBOX "Encryption", IDG_COMPRESS_ENCRYPTION, g4x, yPsw, g4xs, GROUP_Y_SIZE_ENCRYPT + + LTEXT "Enter &password:", IDT_PASSWORD_ENTER, g4x2, yPsw + 14, g4xs2, 8 + EDITTEXT IDE_COMPRESS_PASSWORD1, g4x2, yPsw + 26, g4xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL + LTEXT "Reenter password:", IDT_PASSWORD_REENTER, g4x2, yPsw + 46, g4xs2, 8 + EDITTEXT IDE_COMPRESS_PASSWORD2, g4x2, yPsw + 58, g4xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL + + CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, + g4x2, yPsw + 79, g4xs2, 10 + + LTEXT "&Encryption method:", IDT_COMPRESS_ENCRYPTION_METHOD, g4x2, yPsw + 95, 100, 8 + COMBOBOX IDC_COMPRESS_ENCRYPTION_METHOD, g4x2 + 100, yPsw + 93, g4xs2 - 100, 198, MY_COMBO + + CONTROL "Encrypt file &names", IDX_COMPRESS_ENCRYPT_FILE_NAMES, MY_CHECKBOX, + g4x2, yPsw + 111, g4xs2, 10 + + DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys + PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys +END + + +#ifdef UNDER_CE + +#undef m +#undef xc +#undef yc + +#define m 4 +#define xc 152 +#define yc 160 + + +IDD_COMPRESS_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Add to Archive" +MY_FONT +BEGIN + COMBOBOX IDC_COMPRESS_ARCHIVE, m, m, xc - bxsDots - m, 126, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_COMPRESS_SET_ARCHIVE, xs - m - bxsDots, m, bxsDots, 12, WS_GROUP + + COMBOBOX IDC_COMPRESS_FORMAT, m , 22, 32, 80, MY_COMBO | CBS_SORT + COMBOBOX IDC_COMPRESS_LEVEL, m + 36, 22, 68, 80, MY_COMBO + COMBOBOX IDC_COMPRESS_METHOD, m + 108, 22, 44, 80, MY_COMBO + + COMBOBOX IDC_COMPRESS_DICTIONARY, m, 40, 40, 80, MY_COMBO + COMBOBOX IDC_COMPRESS_ORDER, m + 44, 40, 32, 80, MY_COMBO + COMBOBOX IDC_COMPRESS_SOLID, m + 80, 40, 40, 80, MY_COMBO + COMBOBOX IDC_COMPRESS_THREADS, m + 124, 40, 28, 80, MY_COMBO + + LTEXT "Split to &volumes, bytes:", IDT_SPLIT_TO_VOLUMES, m, 60, 32, 8 + COMBOBOX IDC_COMPRESS_VOLUME, m + 32, 58, 44, 73, MY_COMBO_WITH_EDIT + LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m + 80, 60, 48, 8 + EDITTEXT IDE_COMPRESS_PARAMETERS, m + 128, 58, 24, 13, ES_AUTOHSCROLL + + COMBOBOX IDC_COMPRESS_UPDATE_MODE, m, 76, 88, 80, MY_COMBO + CONTROL "SF&X", IDX_COMPRESS_SFX, MY_CHECKBOX, m + 92, 77, 60, 10 + + CONTROL "Compress shared files", IDX_COMPRESS_SHARED, MY_CHECKBOX, m, 94, xc, 10 + + LTEXT "Enter &password:", IDT_PASSWORD_ENTER, m, 112, 60, 8 + EDITTEXT IDE_COMPRESS_PASSWORD1, m + 60, 110, 44, 13, ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m + 108, 112, 44, 10 + + COMBOBOX IDC_COMPRESS_ENCRYPTION_METHOD, m, 128, 48, 198, MY_COMBO + CONTROL "Encrypt file &names", IDX_COMPRESS_ENCRYPT_FILE_NAMES, MY_CHECKBOX, m + 52, 130, 100, 10 + + OK_CANCEL +END + +#endif + +STRINGTABLE +BEGIN + IDS_PASSWORD_NOT_MATCH "Passwords do not match" + IDS_PASSWORD_USE_ASCII "Use only English letters, numbers and special characters (!, #, $, ...) for password." + IDS_PASSWORD_TOO_LONG "Password is too long" + + IDS_METHOD_STORE "Store" + IDS_METHOD_FASTEST "Fastest" + IDS_METHOD_FAST "Fast" + IDS_METHOD_NORMAL "Normal" + IDS_METHOD_MAXIMUM "Maximum" + IDS_METHOD_ULTRA "Ultra" + + IDS_COMPRESS_UPDATE_MODE_ADD "Add and replace files" + IDS_COMPRESS_UPDATE_MODE_UPDATE "Update and add files" + IDS_COMPRESS_UPDATE_MODE_FRESH "Freshen existing files" + IDS_COMPRESS_UPDATE_MODE_SYNC "Synchronize files" + + IDS_OPEN_TYPE_ALL_FILES "All Files" + IDS_COMPRESS_SET_ARCHIVE_BROWSE "Browse" + + IDS_COMPRESS_NON_SOLID "Non-solid" + IDS_COMPRESS_SOLID "Solid" + + IDS_SPLIT_CONFIRM "Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?" + + IDS_COMPRESS_SEC "sec" + IDS_COMPRESS_NS "ns" + + IDS_MEM_OPERATION_BLOCKED "The operation was blocked by 7-Zip." +END + + +#include "CompressOptionsDialog.rc" diff --git a/CPP/7zip/UI/GUI/CompressDialogRes.h b/CPP/7zip/UI/GUI/CompressDialogRes.h index bef4e23fa..d04d4b9c1 100644 --- a/CPP/7zip/UI/GUI/CompressDialogRes.h +++ b/CPP/7zip/UI/GUI/CompressDialogRes.h @@ -1,125 +1,125 @@ -#define IDD_COMPRESS 4000 -#define IDD_COMPRESS_2 14000 -#define IDD_COMPRESS_OPTIONS 14001 - -#define IDC_COMPRESS_ARCHIVE 100 -#define IDB_COMPRESS_SET_ARCHIVE 101 -#define IDC_COMPRESS_LEVEL 102 -#define IDC_COMPRESS_UPDATE_MODE 103 -#define IDC_COMPRESS_FORMAT 104 -#define IDC_COMPRESS_VOLUME 105 -#define IDC_COMPRESS_METHOD 106 -#define IDC_COMPRESS_DICTIONARY 107 -#define IDC_COMPRESS_ORDER 108 -#define IDC_COMPRESS_SOLID 109 -#define IDC_COMPRESS_THREADS 110 -#define IDE_COMPRESS_PARAMETERS 111 - -#define IDT_COMPRESS_HARDWARE_THREADS 112 -#define IDT_COMPRESS_MEMORY_VALUE 113 -#define IDT_COMPRESS_MEMORY_DE_VALUE 114 - -#define IDG_COMPRESS_NTFS 115 -#define IDC_COMPRESS_PATH_MODE 116 -#define IDC_COMPRESS_MEM_USE 117 -// #define IDC_COMPRESS_DICTIONARY2 118 - -#define IDE_COMPRESS_PASSWORD1 120 -#define IDE_COMPRESS_PASSWORD2 121 -#define IDC_COMPRESS_ENCRYPTION_METHOD 122 - -#define IDT_COMPRESS_ARCHIVE_FOLDER 130 - -// #define IDB_COMPRESS_OPTIONS 140 -#define IDB_COMPRESS_OPTIONS 2100 -#define IDT_COMPRESS_OPTIONS 141 -// #define IDT_COMPRESS_PARAMS_INFO 142 - -#define IDT_COMPRESS_PATH_MODE 3410 - -#define IDT_PASSWORD_ENTER 3801 -#define IDT_PASSWORD_REENTER 3802 -#define IDX_PASSWORD_SHOW 3803 -#define IDS_PASSWORD_NOT_MATCH 3804 -#define IDS_PASSWORD_USE_ASCII 3805 -#define IDS_PASSWORD_TOO_LONG 3806 - -#define IDT_COMPRESS_ARCHIVE 4001 -#define IDT_COMPRESS_UPDATE_MODE 4002 -#define IDT_COMPRESS_FORMAT 4003 -#define IDT_COMPRESS_LEVEL 4004 -#define IDT_COMPRESS_METHOD 4005 -#define IDT_COMPRESS_DICTIONARY 4006 -#define IDT_COMPRESS_ORDER 4007 -#define IDT_COMPRESS_SOLID 4008 -#define IDT_COMPRESS_THREADS 4009 -#define IDT_COMPRESS_PARAMETERS 4010 -#define IDG_COMPRESS_OPTIONS 4011 - -#define IDX_COMPRESS_SFX 4012 -#define IDX_COMPRESS_SHARED 4013 - -#define IDG_COMPRESS_ENCRYPTION 4014 -#define IDT_COMPRESS_ENCRYPTION_METHOD 4015 -#define IDX_COMPRESS_ENCRYPT_FILE_NAMES 4016 - -#define IDT_COMPRESS_MEMORY 4017 -#define IDT_COMPRESS_MEMORY_DE 4018 - -#define IDX_COMPRESS_DEL 4019 - -#define IDX_COMPRESS_NT_SYM_LINKS 4040 -#define IDX_COMPRESS_NT_HARD_LINKS 4041 -#define IDX_COMPRESS_NT_ALT_STREAMS 4042 -#define IDX_COMPRESS_NT_SECUR 4043 - -#define IDS_METHOD_STORE 4050 -#define IDS_METHOD_FASTEST 4051 -#define IDS_METHOD_FAST 4052 -#define IDS_METHOD_NORMAL 4053 -#define IDS_METHOD_MAXIMUM 4054 -#define IDS_METHOD_ULTRA 4055 - -#define IDS_COMPRESS_UPDATE_MODE_ADD 4060 -#define IDS_COMPRESS_UPDATE_MODE_UPDATE 4061 -#define IDS_COMPRESS_UPDATE_MODE_FRESH 4062 -#define IDS_COMPRESS_UPDATE_MODE_SYNC 4063 - -#define IDS_COMPRESS_SET_ARCHIVE_BROWSE 4070 -#define IDS_OPEN_TYPE_ALL_FILES 4071 -#define IDS_COMPRESS_NON_SOLID 4072 -#define IDS_COMPRESS_SOLID 4073 - -#define IDT_SPLIT_TO_VOLUMES 7302 -#define IDS_INCORRECT_VOLUME_SIZE 7307 -#define IDS_SPLIT_CONFIRM 7308 - - -// Options Dialog - -#define IDG_COMPRESS_TIME 4080 -#define IDT_COMPRESS_TIME_PREC 4081 -#define IDX_COMPRESS_MTIME 4082 -#define IDX_COMPRESS_CTIME 4083 -#define IDX_COMPRESS_ATIME 4084 -#define IDX_COMPRESS_ZTIME 4085 -#define IDX_COMPRESS_PRESERVE_ATIME 4086 - -#define IDS_COMPRESS_SEC 4090 -#define IDS_COMPRESS_NS 4091 - -#define IDC_COMPRESS_TIME_PREC 190 -#define IDT_COMPRESS_TIME_INFO 191 - -#define IDX_COMPRESS_PREC_SET 201 -#define IDX_COMPRESS_MTIME_SET 202 -#define IDX_COMPRESS_CTIME_SET 203 -#define IDX_COMPRESS_ATIME_SET 204 -#define IDX_COMPRESS_ZTIME_SET 205 - -// #define IDX_COMPRESS_NT_SYM_LINKS_SET 210 -// #define IDX_COMPRESS_NT_HARD_LINKS_SET 211 -// #define IDX_COMPRESS_NT_ALT_STREAMS_SET 212 -// #define IDX_COMPRESS_NT_SECUR_SET 213 - -#define IDS_MEM_OPERATION_BLOCKED 7810 +#define IDD_COMPRESS 4000 +#define IDD_COMPRESS_2 14000 +#define IDD_COMPRESS_OPTIONS 14001 + +#define IDC_COMPRESS_ARCHIVE 100 +#define IDB_COMPRESS_SET_ARCHIVE 101 +#define IDC_COMPRESS_LEVEL 102 +#define IDC_COMPRESS_UPDATE_MODE 103 +#define IDC_COMPRESS_FORMAT 104 +#define IDC_COMPRESS_VOLUME 105 +#define IDC_COMPRESS_METHOD 106 +#define IDC_COMPRESS_DICTIONARY 107 +#define IDC_COMPRESS_ORDER 108 +#define IDC_COMPRESS_SOLID 109 +#define IDC_COMPRESS_THREADS 110 +#define IDE_COMPRESS_PARAMETERS 111 + +#define IDT_COMPRESS_HARDWARE_THREADS 112 +#define IDT_COMPRESS_MEMORY_VALUE 113 +#define IDT_COMPRESS_MEMORY_DE_VALUE 114 + +#define IDG_COMPRESS_NTFS 115 +#define IDC_COMPRESS_PATH_MODE 116 +#define IDC_COMPRESS_MEM_USE 117 +// #define IDC_COMPRESS_DICTIONARY2 118 + +#define IDE_COMPRESS_PASSWORD1 120 +#define IDE_COMPRESS_PASSWORD2 121 +#define IDC_COMPRESS_ENCRYPTION_METHOD 122 + +#define IDT_COMPRESS_ARCHIVE_FOLDER 130 + +// #define IDB_COMPRESS_OPTIONS 140 +#define IDB_COMPRESS_OPTIONS 2100 +#define IDT_COMPRESS_OPTIONS 141 +// #define IDT_COMPRESS_PARAMS_INFO 142 + +#define IDT_COMPRESS_PATH_MODE 3410 + +#define IDT_PASSWORD_ENTER 3801 +#define IDT_PASSWORD_REENTER 3802 +#define IDX_PASSWORD_SHOW 3803 +#define IDS_PASSWORD_NOT_MATCH 3804 +#define IDS_PASSWORD_USE_ASCII 3805 +#define IDS_PASSWORD_TOO_LONG 3806 + +#define IDT_COMPRESS_ARCHIVE 4001 +#define IDT_COMPRESS_UPDATE_MODE 4002 +#define IDT_COMPRESS_FORMAT 4003 +#define IDT_COMPRESS_LEVEL 4004 +#define IDT_COMPRESS_METHOD 4005 +#define IDT_COMPRESS_DICTIONARY 4006 +#define IDT_COMPRESS_ORDER 4007 +#define IDT_COMPRESS_SOLID 4008 +#define IDT_COMPRESS_THREADS 4009 +#define IDT_COMPRESS_PARAMETERS 4010 +#define IDG_COMPRESS_OPTIONS 4011 + +#define IDX_COMPRESS_SFX 4012 +#define IDX_COMPRESS_SHARED 4013 + +#define IDG_COMPRESS_ENCRYPTION 4014 +#define IDT_COMPRESS_ENCRYPTION_METHOD 4015 +#define IDX_COMPRESS_ENCRYPT_FILE_NAMES 4016 + +#define IDT_COMPRESS_MEMORY 4017 +#define IDT_COMPRESS_MEMORY_DE 4018 + +#define IDX_COMPRESS_DEL 4019 + +#define IDX_COMPRESS_NT_SYM_LINKS 4040 +#define IDX_COMPRESS_NT_HARD_LINKS 4041 +#define IDX_COMPRESS_NT_ALT_STREAMS 4042 +#define IDX_COMPRESS_NT_SECUR 4043 + +#define IDS_METHOD_STORE 4050 +#define IDS_METHOD_FASTEST 4051 +#define IDS_METHOD_FAST 4052 +#define IDS_METHOD_NORMAL 4053 +#define IDS_METHOD_MAXIMUM 4054 +#define IDS_METHOD_ULTRA 4055 + +#define IDS_COMPRESS_UPDATE_MODE_ADD 4060 +#define IDS_COMPRESS_UPDATE_MODE_UPDATE 4061 +#define IDS_COMPRESS_UPDATE_MODE_FRESH 4062 +#define IDS_COMPRESS_UPDATE_MODE_SYNC 4063 + +#define IDS_COMPRESS_SET_ARCHIVE_BROWSE 4070 +#define IDS_OPEN_TYPE_ALL_FILES 4071 +#define IDS_COMPRESS_NON_SOLID 4072 +#define IDS_COMPRESS_SOLID 4073 + +#define IDT_SPLIT_TO_VOLUMES 7302 +#define IDS_INCORRECT_VOLUME_SIZE 7307 +#define IDS_SPLIT_CONFIRM 7308 + + +// Options Dialog + +#define IDG_COMPRESS_TIME 4080 +#define IDT_COMPRESS_TIME_PREC 4081 +#define IDX_COMPRESS_MTIME 4082 +#define IDX_COMPRESS_CTIME 4083 +#define IDX_COMPRESS_ATIME 4084 +#define IDX_COMPRESS_ZTIME 4085 +#define IDX_COMPRESS_PRESERVE_ATIME 4086 + +#define IDS_COMPRESS_SEC 4090 +#define IDS_COMPRESS_NS 4091 + +#define IDC_COMPRESS_TIME_PREC 190 +#define IDT_COMPRESS_TIME_INFO 191 + +#define IDX_COMPRESS_PREC_SET 201 +#define IDX_COMPRESS_MTIME_SET 202 +#define IDX_COMPRESS_CTIME_SET 203 +#define IDX_COMPRESS_ATIME_SET 204 +#define IDX_COMPRESS_ZTIME_SET 205 + +// #define IDX_COMPRESS_NT_SYM_LINKS_SET 210 +// #define IDX_COMPRESS_NT_HARD_LINKS_SET 211 +// #define IDX_COMPRESS_NT_ALT_STREAMS_SET 212 +// #define IDX_COMPRESS_NT_SECUR_SET 213 + +#define IDS_MEM_OPERATION_BLOCKED 7810 diff --git a/CPP/7zip/UI/GUI/CompressOptionsDialog.rc b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc index 522b8e6c2..682775e9c 100644 --- a/CPP/7zip/UI/GUI/CompressOptionsDialog.rc +++ b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc @@ -1,79 +1,79 @@ -#include "CompressDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 240 -#define yc 232 - -#define g5x m -#define g5x2 (g5x + m) -#define g5xs (xc) -#define g5xs2 (g5xs - m - m) - -#define ntPosX g5x2 -#define ntPosY m -#define ntSizeX g5xs2 -#define precSizeX 76 - -#define ntSizeY 72 -#define timePosY (ntPosY + ntSizeY + 20) - - -IDD_COMPRESS_OPTIONS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Options" -BEGIN - GROUPBOX "NTFS", IDG_COMPRESS_NTFS, g5x, ntPosY, g5xs, ntSizeY - - MY_CONTROL_CHECKBOX ("Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, - ntPosX, ntPosY + 12, ntSizeX) - MY_CONTROL_CHECKBOX ("Store hard links", IDX_COMPRESS_NT_HARD_LINKS, - ntPosX, ntPosY + 26, ntSizeX) - MY_CONTROL_CHECKBOX ("Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, - ntPosX, ntPosY + 40, ntSizeX) - MY_CONTROL_CHECKBOX ("Store file security", IDX_COMPRESS_NT_SECUR, - ntPosX, ntPosY + 54, ntSizeX) - - LTEXT "", IDT_COMPRESS_TIME_INFO, g5x, timePosY - 14, g5xs, 8 - - - GROUPBOX "Time", IDG_COMPRESS_TIME, g5x, timePosY, g5xs, 112 - -// MY_CONTROL_CHECKBOX ("Default", IDX_COMPRESS_TIME_DEFAULT, -// ntPosX, timePosY + 10, ntSizeX) - - MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_PREC_SET, ntPosX, timePosY + 14) - LTEXT "Timestamp precision:", IDT_COMPRESS_TIME_PREC, - ntPosX + cboxColonSize, timePosY + 14, ntSizeX - precSizeX - cboxColonSize, 8 - COMBOBOX IDC_COMPRESS_TIME_PREC, ntPosX + ntSizeX - precSizeX, timePosY + 12, precSizeX, 70, MY_COMBO - - // PUSHBUTTON "Default", IDB_COMPRESS_TIME_DEFAULT, ntPosX + ntSizeX - bxs, timePosY + 22, bxs, bys, WS_GROUP - - MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_MTIME_SET, ntPosX, timePosY + 28) - MY_CONTROL_CHECKBOX ("Store modification time", IDX_COMPRESS_MTIME, - ntPosX + cboxColonSize, timePosY + 28, ntSizeX - cboxColonSize) - - MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_CTIME_SET, ntPosX, timePosY + 42) - MY_CONTROL_CHECKBOX ("Store creation time", IDX_COMPRESS_CTIME, - ntPosX + cboxColonSize, timePosY + 42, ntSizeX - cboxColonSize) - - MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_ATIME_SET, ntPosX, timePosY + 56) - MY_CONTROL_CHECKBOX ("Store last access time", IDX_COMPRESS_ATIME, - ntPosX + cboxColonSize, timePosY + 56, ntSizeX - cboxColonSize) - - MY_CONTROL_CHECKBOX_2LINES(colonString, - IDX_COMPRESS_ZTIME_SET, - ntPosX, timePosY + 72, cboxColonSize) - MY_CONTROL_CHECKBOX_2LINES( - "Set archive time to latest file time", - IDX_COMPRESS_ZTIME, - ntPosX + cboxColonSize, timePosY + 72, ntSizeX - cboxColonSize) - - MY_CONTROL_CHECKBOX_2LINES( - "Do not change source files last access time", - IDX_COMPRESS_PRESERVE_ATIME, - ntPosX, timePosY + 92, ntSizeX) - - - DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys - PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys -END +#include "CompressDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 240 +#define yc 232 + +#define g5x m +#define g5x2 (g5x + m) +#define g5xs (xc) +#define g5xs2 (g5xs - m - m) + +#define ntPosX g5x2 +#define ntPosY m +#define ntSizeX g5xs2 +#define precSizeX 76 + +#define ntSizeY 72 +#define timePosY (ntPosY + ntSizeY + 20) + + +IDD_COMPRESS_OPTIONS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Options" +BEGIN + GROUPBOX "NTFS", IDG_COMPRESS_NTFS, g5x, ntPosY, g5xs, ntSizeY + + MY_CONTROL_CHECKBOX ("Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, + ntPosX, ntPosY + 12, ntSizeX) + MY_CONTROL_CHECKBOX ("Store hard links", IDX_COMPRESS_NT_HARD_LINKS, + ntPosX, ntPosY + 26, ntSizeX) + MY_CONTROL_CHECKBOX ("Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, + ntPosX, ntPosY + 40, ntSizeX) + MY_CONTROL_CHECKBOX ("Store file security", IDX_COMPRESS_NT_SECUR, + ntPosX, ntPosY + 54, ntSizeX) + + LTEXT "", IDT_COMPRESS_TIME_INFO, g5x, timePosY - 14, g5xs, 8 + + + GROUPBOX "Time", IDG_COMPRESS_TIME, g5x, timePosY, g5xs, 112 + +// MY_CONTROL_CHECKBOX ("Default", IDX_COMPRESS_TIME_DEFAULT, +// ntPosX, timePosY + 10, ntSizeX) + + MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_PREC_SET, ntPosX, timePosY + 14) + LTEXT "Timestamp precision:", IDT_COMPRESS_TIME_PREC, + ntPosX + cboxColonSize, timePosY + 14, ntSizeX - precSizeX - cboxColonSize, 8 + COMBOBOX IDC_COMPRESS_TIME_PREC, ntPosX + ntSizeX - precSizeX, timePosY + 12, precSizeX, 70, MY_COMBO + + // PUSHBUTTON "Default", IDB_COMPRESS_TIME_DEFAULT, ntPosX + ntSizeX - bxs, timePosY + 22, bxs, bys, WS_GROUP + + MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_MTIME_SET, ntPosX, timePosY + 28) + MY_CONTROL_CHECKBOX ("Store modification time", IDX_COMPRESS_MTIME, + ntPosX + cboxColonSize, timePosY + 28, ntSizeX - cboxColonSize) + + MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_CTIME_SET, ntPosX, timePosY + 42) + MY_CONTROL_CHECKBOX ("Store creation time", IDX_COMPRESS_CTIME, + ntPosX + cboxColonSize, timePosY + 42, ntSizeX - cboxColonSize) + + MY_CONTROL_CHECKBOX_COLON (IDX_COMPRESS_ATIME_SET, ntPosX, timePosY + 56) + MY_CONTROL_CHECKBOX ("Store last access time", IDX_COMPRESS_ATIME, + ntPosX + cboxColonSize, timePosY + 56, ntSizeX - cboxColonSize) + + MY_CONTROL_CHECKBOX_2LINES(colonString, + IDX_COMPRESS_ZTIME_SET, + ntPosX, timePosY + 72, cboxColonSize) + MY_CONTROL_CHECKBOX_2LINES( + "Set archive time to latest file time", + IDX_COMPRESS_ZTIME, + ntPosX + cboxColonSize, timePosY + 72, ntSizeX - cboxColonSize) + + MY_CONTROL_CHECKBOX_2LINES( + "Do not change source files last access time", + IDX_COMPRESS_PRESERVE_ATIME, + ntPosX, timePosY + 92, ntSizeX) + + + DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys + PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys +END diff --git a/CPP/7zip/UI/GUI/Extract.rc b/CPP/7zip/UI/GUI/Extract.rc index 809288f1b..36bfb0094 100644 --- a/CPP/7zip/UI/GUI/Extract.rc +++ b/CPP/7zip/UI/GUI/Extract.rc @@ -1,59 +1,59 @@ -#include "ExtractRes.h" - -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -STRINGTABLE DISCARDABLE -BEGIN - IDS_MEM_ERROR "The system cannot allocate the required amount of memory" - IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'" - IDS_UPDATE_NOT_SUPPORTED "Update operations are not supported for this archive." - IDS_CANT_OPEN_ARCHIVE "Cannot open file '{0}' as archive" - IDS_CANT_OPEN_ENCRYPTED_ARCHIVE "Cannot open encrypted archive '{0}'. Wrong password?" - IDS_UNSUPPORTED_ARCHIVE_TYPE "Unsupported archive type" - - IDS_CANT_OPEN_AS_TYPE "Cannot open the file as {0} archive" - IDS_IS_OPEN_AS_TYPE "The file is open as {0} archive" - IDS_IS_OPEN_WITH_OFFSET "The archive is open with offset" - - IDS_PROGRESS_EXTRACTING "Extracting" - - IDS_PROGRESS_SKIPPING "Skipping" - - IDS_EXTRACT_SET_FOLDER "Specify a location for extracted files." - - IDS_EXTRACT_PATHS_FULL "Full pathnames" - IDS_EXTRACT_PATHS_NO "No pathnames" - IDS_EXTRACT_PATHS_ABS "Absolute pathnames" - IDS_PATH_MODE_RELAT "Relative pathnames" - - IDS_EXTRACT_OVERWRITE_ASK "Ask before overwrite" - IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT "Overwrite without prompt" - IDS_EXTRACT_OVERWRITE_SKIP_EXISTING "Skip existing files" - IDS_EXTRACT_OVERWRITE_RENAME "Auto rename" - IDS_EXTRACT_OVERWRITE_RENAME_EXISTING "Auto rename existing files" - - IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD "Unsupported compression method for '{0}'." - IDS_EXTRACT_MESSAGE_DATA_ERROR "Data error in '{0}'. File is broken" - IDS_EXTRACT_MESSAGE_CRC_ERROR "CRC failed in '{0}'. File is broken." - IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED "Data error in encrypted file '{0}'. Wrong password?" - IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED "CRC failed in encrypted file '{0}'. Wrong password?" - - IDS_EXTRACT_MSG_WRONG_PSW_GUESS "Wrong password?" - // IDS_EXTRACT_MSG_ENCRYPTED "Encrypted file" - - IDS_EXTRACT_MSG_UNSUPPORTED_METHOD "Unsupported compression method" - IDS_EXTRACT_MSG_DATA_ERROR "Data error" - IDS_EXTRACT_MSG_CRC_ERROR "CRC failed" - IDS_EXTRACT_MSG_UNAVAILABLE_DATA "Unavailable data" - IDS_EXTRACT_MSG_UEXPECTED_END "Unexpected end of data" - IDS_EXTRACT_MSG_DATA_AFTER_END "There are some data after the end of the payload data" - IDS_EXTRACT_MSG_IS_NOT_ARC "Is not archive" - IDS_EXTRACT_MSG_HEADERS_ERROR "Headers Error" - IDS_EXTRACT_MSG_WRONG_PSW_CLAIM "Wrong password" - - IDS_OPEN_MSG_UNAVAILABLE_START "Unavailable start of archive" - IDS_OPEN_MSG_UNCONFIRMED_START "Unconfirmed start of archive" - // IDS_OPEN_MSG_ERROR_FLAGS + 5 "Unexpected end of archive" - // IDS_OPEN_MSG_ERROR_FLAGS + 6 "There are data after the end of archive" - IDS_OPEN_MSG_UNSUPPORTED_FEATURE "Unsupported feature" -END +#include "ExtractRes.h" + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MEM_ERROR "The system cannot allocate the required amount of memory" + IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'" + IDS_UPDATE_NOT_SUPPORTED "Update operations are not supported for this archive." + IDS_CANT_OPEN_ARCHIVE "Cannot open file '{0}' as archive" + IDS_CANT_OPEN_ENCRYPTED_ARCHIVE "Cannot open encrypted archive '{0}'. Wrong password?" + IDS_UNSUPPORTED_ARCHIVE_TYPE "Unsupported archive type" + + IDS_CANT_OPEN_AS_TYPE "Cannot open the file as {0} archive" + IDS_IS_OPEN_AS_TYPE "The file is open as {0} archive" + IDS_IS_OPEN_WITH_OFFSET "The archive is open with offset" + + IDS_PROGRESS_EXTRACTING "Extracting" + + IDS_PROGRESS_SKIPPING "Skipping" + + IDS_EXTRACT_SET_FOLDER "Specify a location for extracted files." + + IDS_EXTRACT_PATHS_FULL "Full pathnames" + IDS_EXTRACT_PATHS_NO "No pathnames" + IDS_EXTRACT_PATHS_ABS "Absolute pathnames" + IDS_PATH_MODE_RELAT "Relative pathnames" + + IDS_EXTRACT_OVERWRITE_ASK "Ask before overwrite" + IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT "Overwrite without prompt" + IDS_EXTRACT_OVERWRITE_SKIP_EXISTING "Skip existing files" + IDS_EXTRACT_OVERWRITE_RENAME "Auto rename" + IDS_EXTRACT_OVERWRITE_RENAME_EXISTING "Auto rename existing files" + + IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD "Unsupported compression method for '{0}'." + IDS_EXTRACT_MESSAGE_DATA_ERROR "Data error in '{0}'. File is broken" + IDS_EXTRACT_MESSAGE_CRC_ERROR "CRC failed in '{0}'. File is broken." + IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED "Data error in encrypted file '{0}'. Wrong password?" + IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED "CRC failed in encrypted file '{0}'. Wrong password?" + + IDS_EXTRACT_MSG_WRONG_PSW_GUESS "Wrong password?" + // IDS_EXTRACT_MSG_ENCRYPTED "Encrypted file" + + IDS_EXTRACT_MSG_UNSUPPORTED_METHOD "Unsupported compression method" + IDS_EXTRACT_MSG_DATA_ERROR "Data error" + IDS_EXTRACT_MSG_CRC_ERROR "CRC failed" + IDS_EXTRACT_MSG_UNAVAILABLE_DATA "Unavailable data" + IDS_EXTRACT_MSG_UEXPECTED_END "Unexpected end of data" + IDS_EXTRACT_MSG_DATA_AFTER_END "There are some data after the end of the payload data" + IDS_EXTRACT_MSG_IS_NOT_ARC "Is not archive" + IDS_EXTRACT_MSG_HEADERS_ERROR "Headers Error" + IDS_EXTRACT_MSG_WRONG_PSW_CLAIM "Wrong password" + + IDS_OPEN_MSG_UNAVAILABLE_START "Unavailable start of archive" + IDS_OPEN_MSG_UNCONFIRMED_START "Unconfirmed start of archive" + // IDS_OPEN_MSG_ERROR_FLAGS + 5 "Unexpected end of archive" + // IDS_OPEN_MSG_ERROR_FLAGS + 6 "There are data after the end of archive" + IDS_OPEN_MSG_UNSUPPORTED_FEATURE "Unsupported feature" +END diff --git a/CPP/7zip/UI/GUI/ExtractDialog.cpp b/CPP/7zip/UI/GUI/ExtractDialog.cpp index 0112ddb7c..462848203 100644 --- a/CPP/7zip/UI/GUI/ExtractDialog.cpp +++ b/CPP/7zip/UI/GUI/ExtractDialog.cpp @@ -1,421 +1,421 @@ -// ExtractDialog.cpp - -#include "StdAfx.h" - -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.h" - -#include "../../../Windows/FileName.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/ResourceString.h" - -#ifndef Z7_NO_REGISTRY -#include "../FileManager/HelpUtils.h" -#endif - - -#include "../FileManager/BrowseDialog.h" -#include "../FileManager/LangUtils.h" -#include "../FileManager/resourceGui.h" - -#include "ExtractDialog.h" -#include "ExtractDialogRes.h" -#include "ExtractRes.h" - -using namespace NWindows; -using namespace NFile; -using namespace NName; - -extern HINSTANCE g_hInstance; - -#ifndef Z7_SFX - -static const UInt32 kPathMode_IDs[] = -{ - IDS_EXTRACT_PATHS_FULL, - IDS_EXTRACT_PATHS_NO, - IDS_EXTRACT_PATHS_ABS -}; - -static const UInt32 kOverwriteMode_IDs[] = -{ - IDS_EXTRACT_OVERWRITE_ASK, - IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT, - IDS_EXTRACT_OVERWRITE_SKIP_EXISTING, - IDS_EXTRACT_OVERWRITE_RENAME, - IDS_EXTRACT_OVERWRITE_RENAME_EXISTING -}; - -static const - // NExtract::NPathMode::EEnum - int - kPathModeButtonsVals[] = -{ - NExtract::NPathMode::kFullPaths, - NExtract::NPathMode::kNoPaths, - NExtract::NPathMode::kAbsPaths -}; - -static const - int - // NExtract::NOverwriteMode::EEnum - kOverwriteButtonsVals[] = -{ - NExtract::NOverwriteMode::kAsk, - NExtract::NOverwriteMode::kOverwrite, - NExtract::NOverwriteMode::kSkip, - NExtract::NOverwriteMode::kRename, - NExtract::NOverwriteMode::kRenameExisting -}; - -#endif - -#ifdef Z7_LANG - -static const UInt32 kLangIDs[] = -{ - IDT_EXTRACT_EXTRACT_TO, - IDT_EXTRACT_PATH_MODE, - IDT_EXTRACT_OVERWRITE_MODE, - // IDX_EXTRACT_ALT_STREAMS, - IDX_EXTRACT_NT_SECUR, - IDX_EXTRACT_ELIM_DUP, - IDG_PASSWORD, - IDX_PASSWORD_SHOW -}; -#endif - -// static const int kWildcardsButtonIndex = 2; - -#ifndef Z7_NO_REGISTRY -static const unsigned kHistorySize = 16; -#endif - -#ifndef Z7_SFX - -// it's used in CompressDialog also -void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal); -void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal) -{ - unsigned curSel = 0; - for (unsigned i = 0; i < numItems; i++) - { - UString s = LangString(langIDs[i]); - s.RemoveChar(L'&'); - const int index = (int)combo.AddString(s); - combo.SetItemData(index, (LPARAM)i); - if (values[i] == curVal) - curSel = i; - } - combo.SetCurSel(curSel); -} - -// it's used in CompressDialog also -bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2); -bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2) -{ - if (b1.Def) return b1.Val; - if (b2.Def) return b2.Val; - return b1.Val; -} - -void CExtractDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2) -{ - CheckButton(id, GetBoolsVal(b1, b2)); -} - -void CExtractDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2) -{ - const bool val = IsButtonCheckedBool(id); - const bool oldVal = GetBoolsVal(b1, b2); - if (val != oldVal) - b1.Def = b2.Def = true; - b1.Val = b2.Val = val; -} - -#endif - -bool CExtractDialog::OnInit() -{ - #ifdef Z7_LANG - { - UString s; - LangString_OnlyFromLangFile(IDD_EXTRACT, s); - if (s.IsEmpty()) - GetText(s); - if (!ArcPath.IsEmpty()) - { - s += " : "; - s += ArcPath; - } - SetText(s); - // LangSetWindowText(*this, IDD_EXTRACT); - LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); - } - #endif - - #ifndef Z7_SFX - _passwordControl.Attach(GetItem(IDE_EXTRACT_PASSWORD)); - _passwordControl.SetText(Password); - _passwordControl.SetPasswordChar(TEXT('*')); - _pathName.Attach(GetItem(IDE_EXTRACT_NAME)); - #endif - - #ifdef Z7_NO_REGISTRY - - PathMode = NExtract::NPathMode::kFullPaths; - OverwriteMode = NExtract::NOverwriteMode::kAsk; - - #else - - _info.Load(); - - if (_info.PathMode == NExtract::NPathMode::kCurPaths) - _info.PathMode = NExtract::NPathMode::kFullPaths; - - if (!PathMode_Force && _info.PathMode_Force) - PathMode = _info.PathMode; - if (!OverwriteMode_Force && _info.OverwriteMode_Force) - OverwriteMode = _info.OverwriteMode; - - // CheckButton_TwoBools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams); - CheckButton_TwoBools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity); - CheckButton_TwoBools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup); - - CheckButton(IDX_PASSWORD_SHOW, _info.ShowPassword.Val); - UpdatePasswordControl(); - - #endif - - _path.Attach(GetItem(IDC_EXTRACT_PATH)); - - UString pathPrefix = DirPath; - - #ifndef Z7_SFX - - if (_info.SplitDest.Val) - { - CheckButton(IDX_EXTRACT_NAME_ENABLE, true); - UString pathName; - SplitPathToParts_Smart(DirPath, pathPrefix, pathName); - if (pathPrefix.IsEmpty()) - pathPrefix = pathName; - else - _pathName.SetText(pathName); - } - else - ShowItem_Bool(IDE_EXTRACT_NAME, false); - - #endif - - _path.SetText(pathPrefix); - - #ifndef Z7_NO_REGISTRY - for (unsigned i = 0; i < _info.Paths.Size() && i < kHistorySize; i++) - _path.AddString(_info.Paths[i]); - #endif - - /* - if (_info.Paths.Size() > 0) - _path.SetCurSel(0); - else - _path.SetCurSel(-1); - */ - - #ifndef Z7_SFX - - _pathMode.Attach(GetItem(IDC_EXTRACT_PATH_MODE)); - _overwriteMode.Attach(GetItem(IDC_EXTRACT_OVERWRITE_MODE)); - - AddComboItems(_pathMode, kPathMode_IDs, Z7_ARRAY_SIZE(kPathMode_IDs), kPathModeButtonsVals, PathMode); - AddComboItems(_overwriteMode, kOverwriteMode_IDs, Z7_ARRAY_SIZE(kOverwriteMode_IDs), kOverwriteButtonsVals, OverwriteMode); - - #endif - - HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); - SetIcon(ICON_BIG, icon); - - // CWindow filesWindow = GetItem(IDC_EXTRACT_RADIO_FILES); - // filesWindow.Enable(_enableFilesButton); - - NormalizePosition(); - - return CModalDialog::OnInit(); -} - -#ifndef Z7_SFX -void CExtractDialog::UpdatePasswordControl() -{ - _passwordControl.SetPasswordChar(IsShowPasswordChecked() ? 0 : TEXT('*')); - UString password; - _passwordControl.GetText(password); - _passwordControl.SetText(password); -} -#endif - -bool CExtractDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDB_EXTRACT_SET_PATH: - OnButtonSetPath(); - return true; - #ifndef Z7_SFX - case IDX_EXTRACT_NAME_ENABLE: - ShowItem_Bool(IDE_EXTRACT_NAME, IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE)); - return true; - case IDX_PASSWORD_SHOW: - { - UpdatePasswordControl(); - return true; - } - #endif - } - return CModalDialog::OnButtonClicked(buttonID, buttonHWND); -} - -void CExtractDialog::OnButtonSetPath() -{ - UString currentPath; - _path.GetText(currentPath); - UString title = LangString(IDS_EXTRACT_SET_FOLDER); - UString resultPath; - if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) - return; - #ifndef Z7_NO_REGISTRY - _path.SetCurSel(-1); - #endif - _path.SetText(resultPath); -} - -void AddUniqueString(UStringVector &list, const UString &s); -void AddUniqueString(UStringVector &list, const UString &s) -{ - FOR_VECTOR (i, list) - if (s.IsEqualTo_NoCase(list[i])) - return; - list.Add(s); -} - -void CExtractDialog::OnOK() -{ - #ifndef Z7_SFX - int pathMode2 = kPathModeButtonsVals[_pathMode.GetCurSel()]; - if (PathMode != NExtract::NPathMode::kCurPaths || - pathMode2 != NExtract::NPathMode::kFullPaths) - PathMode = (NExtract::NPathMode::EEnum)pathMode2; - - OverwriteMode = (NExtract::NOverwriteMode::EEnum)kOverwriteButtonsVals[_overwriteMode.GetCurSel()]; - - // _filesMode = (NExtractionDialog::NFilesMode::EEnum)GetFilesMode(); - - _passwordControl.GetText(Password); - - #endif - - #ifndef Z7_NO_REGISTRY - - // GetButton_Bools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams); - GetButton_Bools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity); - GetButton_Bools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup); - - bool showPassword = IsShowPasswordChecked(); - if (showPassword != _info.ShowPassword.Val) - { - _info.ShowPassword.Def = true; - _info.ShowPassword.Val = showPassword; - } - - if (_info.PathMode != pathMode2) - { - _info.PathMode_Force = true; - _info.PathMode = (NExtract::NPathMode::EEnum)pathMode2; - /* - // we allow kAbsPaths in registry. - if (_info.PathMode == NExtract::NPathMode::kAbsPaths) - _info.PathMode = NExtract::NPathMode::kFullPaths; - */ - } - - if (!OverwriteMode_Force && _info.OverwriteMode != OverwriteMode) - _info.OverwriteMode_Force = true; - _info.OverwriteMode = OverwriteMode; - - - #else - - ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP); - - #endif - - UString s; - - #ifdef Z7_NO_REGISTRY - - _path.GetText(s); - - #else - - int currentItem = _path.GetCurSel(); - if (currentItem == CB_ERR) - { - _path.GetText(s); - if (_path.GetCount() >= (int)kHistorySize) - currentItem = _path.GetCount() - 1; - } - else - _path.GetLBText(currentItem, s); - - #endif - - s.Trim(); - NName::NormalizeDirPathPrefix(s); - - #ifndef Z7_SFX - - const bool splitDest = IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE); - if (splitDest) - { - UString pathName; - _pathName.GetText(pathName); - pathName.Trim(); - s += pathName; - NName::NormalizeDirPathPrefix(s); - } - if (splitDest != _info.SplitDest.Val) - { - _info.SplitDest.Def = true; - _info.SplitDest.Val = splitDest; - } - - #endif - - DirPath = s; - - #ifndef Z7_NO_REGISTRY - _info.Paths.Clear(); - #ifndef Z7_SFX - AddUniqueString(_info.Paths, s); - #endif - for (int i = 0; i < _path.GetCount(); i++) - if (i != currentItem) - { - UString sTemp; - _path.GetLBText(i, sTemp); - sTemp.Trim(); - AddUniqueString(_info.Paths, sTemp); - } - _info.Save(); - #endif - - CModalDialog::OnOK(); -} - -#ifndef Z7_NO_REGISTRY -#define kHelpTopic "fm/plugins/7-zip/extract.htm" -void CExtractDialog::OnHelp() -{ - ShowHelpWindow(kHelpTopic); - CModalDialog::OnHelp(); -} -#endif +// ExtractDialog.cpp + +#include "StdAfx.h" + +#include "../../../Common/StringConvert.h" +#include "../../../Common/Wildcard.h" + +#include "../../../Windows/FileName.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/ResourceString.h" + +#ifndef Z7_NO_REGISTRY +#include "../FileManager/HelpUtils.h" +#endif + + +#include "../FileManager/BrowseDialog.h" +#include "../FileManager/LangUtils.h" +#include "../FileManager/resourceGui.h" + +#include "ExtractDialog.h" +#include "ExtractDialogRes.h" +#include "ExtractRes.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +extern HINSTANCE g_hInstance; + +#ifndef Z7_SFX + +static const UInt32 kPathMode_IDs[] = +{ + IDS_EXTRACT_PATHS_FULL, + IDS_EXTRACT_PATHS_NO, + IDS_EXTRACT_PATHS_ABS +}; + +static const UInt32 kOverwriteMode_IDs[] = +{ + IDS_EXTRACT_OVERWRITE_ASK, + IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT, + IDS_EXTRACT_OVERWRITE_SKIP_EXISTING, + IDS_EXTRACT_OVERWRITE_RENAME, + IDS_EXTRACT_OVERWRITE_RENAME_EXISTING +}; + +static const + // NExtract::NPathMode::EEnum + int + kPathModeButtonsVals[] = +{ + NExtract::NPathMode::kFullPaths, + NExtract::NPathMode::kNoPaths, + NExtract::NPathMode::kAbsPaths +}; + +static const + int + // NExtract::NOverwriteMode::EEnum + kOverwriteButtonsVals[] = +{ + NExtract::NOverwriteMode::kAsk, + NExtract::NOverwriteMode::kOverwrite, + NExtract::NOverwriteMode::kSkip, + NExtract::NOverwriteMode::kRename, + NExtract::NOverwriteMode::kRenameExisting +}; + +#endif + +#ifdef Z7_LANG + +static const UInt32 kLangIDs[] = +{ + IDT_EXTRACT_EXTRACT_TO, + IDT_EXTRACT_PATH_MODE, + IDT_EXTRACT_OVERWRITE_MODE, + // IDX_EXTRACT_ALT_STREAMS, + IDX_EXTRACT_NT_SECUR, + IDX_EXTRACT_ELIM_DUP, + IDG_PASSWORD, + IDX_PASSWORD_SHOW +}; +#endif + +// static const int kWildcardsButtonIndex = 2; + +#ifndef Z7_NO_REGISTRY +static const unsigned kHistorySize = 16; +#endif + +#ifndef Z7_SFX + +// it's used in CompressDialog also +void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal); +void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal) +{ + unsigned curSel = 0; + for (unsigned i = 0; i < numItems; i++) + { + UString s = LangString(langIDs[i]); + s.RemoveChar(L'&'); + const int index = (int)combo.AddString(s); + combo.SetItemData(index, (LPARAM)i); + if (values[i] == curVal) + curSel = i; + } + combo.SetCurSel(curSel); +} + +// it's used in CompressDialog also +bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2); +bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2) +{ + if (b1.Def) return b1.Val; + if (b2.Def) return b2.Val; + return b1.Val; +} + +void CExtractDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2) +{ + CheckButton(id, GetBoolsVal(b1, b2)); +} + +void CExtractDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2) +{ + const bool val = IsButtonCheckedBool(id); + const bool oldVal = GetBoolsVal(b1, b2); + if (val != oldVal) + b1.Def = b2.Def = true; + b1.Val = b2.Val = val; +} + +#endif + +bool CExtractDialog::OnInit() +{ + #ifdef Z7_LANG + { + UString s; + LangString_OnlyFromLangFile(IDD_EXTRACT, s); + if (s.IsEmpty()) + GetText(s); + if (!ArcPath.IsEmpty()) + { + s += " : "; + s += ArcPath; + } + SetText(s); + // LangSetWindowText(*this, IDD_EXTRACT); + LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs)); + } + #endif + + #ifndef Z7_SFX + _passwordControl.Attach(GetItem(IDE_EXTRACT_PASSWORD)); + _passwordControl.SetText(Password); + _passwordControl.SetPasswordChar(TEXT('*')); + _pathName.Attach(GetItem(IDE_EXTRACT_NAME)); + #endif + + #ifdef Z7_NO_REGISTRY + + PathMode = NExtract::NPathMode::kFullPaths; + OverwriteMode = NExtract::NOverwriteMode::kAsk; + + #else + + _info.Load(); + + if (_info.PathMode == NExtract::NPathMode::kCurPaths) + _info.PathMode = NExtract::NPathMode::kFullPaths; + + if (!PathMode_Force && _info.PathMode_Force) + PathMode = _info.PathMode; + if (!OverwriteMode_Force && _info.OverwriteMode_Force) + OverwriteMode = _info.OverwriteMode; + + // CheckButton_TwoBools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams); + CheckButton_TwoBools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity); + CheckButton_TwoBools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup); + + CheckButton(IDX_PASSWORD_SHOW, _info.ShowPassword.Val); + UpdatePasswordControl(); + + #endif + + _path.Attach(GetItem(IDC_EXTRACT_PATH)); + + UString pathPrefix = DirPath; + + #ifndef Z7_SFX + + if (_info.SplitDest.Val) + { + CheckButton(IDX_EXTRACT_NAME_ENABLE, true); + UString pathName; + SplitPathToParts_Smart(DirPath, pathPrefix, pathName); + if (pathPrefix.IsEmpty()) + pathPrefix = pathName; + else + _pathName.SetText(pathName); + } + else + ShowItem_Bool(IDE_EXTRACT_NAME, false); + + #endif + + _path.SetText(pathPrefix); + + #ifndef Z7_NO_REGISTRY + for (unsigned i = 0; i < _info.Paths.Size() && i < kHistorySize; i++) + _path.AddString(_info.Paths[i]); + #endif + + /* + if (_info.Paths.Size() > 0) + _path.SetCurSel(0); + else + _path.SetCurSel(-1); + */ + + #ifndef Z7_SFX + + _pathMode.Attach(GetItem(IDC_EXTRACT_PATH_MODE)); + _overwriteMode.Attach(GetItem(IDC_EXTRACT_OVERWRITE_MODE)); + + AddComboItems(_pathMode, kPathMode_IDs, Z7_ARRAY_SIZE(kPathMode_IDs), kPathModeButtonsVals, PathMode); + AddComboItems(_overwriteMode, kOverwriteMode_IDs, Z7_ARRAY_SIZE(kOverwriteMode_IDs), kOverwriteButtonsVals, OverwriteMode); + + #endif + + HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); + SetIcon(ICON_BIG, icon); + + // CWindow filesWindow = GetItem(IDC_EXTRACT_RADIO_FILES); + // filesWindow.Enable(_enableFilesButton); + + NormalizePosition(); + + return CModalDialog::OnInit(); +} + +#ifndef Z7_SFX +void CExtractDialog::UpdatePasswordControl() +{ + _passwordControl.SetPasswordChar(IsShowPasswordChecked() ? 0 : TEXT('*')); + UString password; + _passwordControl.GetText(password); + _passwordControl.SetText(password); +} +#endif + +bool CExtractDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDB_EXTRACT_SET_PATH: + OnButtonSetPath(); + return true; + #ifndef Z7_SFX + case IDX_EXTRACT_NAME_ENABLE: + ShowItem_Bool(IDE_EXTRACT_NAME, IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE)); + return true; + case IDX_PASSWORD_SHOW: + { + UpdatePasswordControl(); + return true; + } + #endif + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + +void CExtractDialog::OnButtonSetPath() +{ + UString currentPath; + _path.GetText(currentPath); + UString title = LangString(IDS_EXTRACT_SET_FOLDER); + UString resultPath; + if (!MyBrowseForFolder(*this, title, currentPath, resultPath)) + return; + #ifndef Z7_NO_REGISTRY + _path.SetCurSel(-1); + #endif + _path.SetText(resultPath); +} + +void AddUniqueString(UStringVector &list, const UString &s); +void AddUniqueString(UStringVector &list, const UString &s) +{ + FOR_VECTOR (i, list) + if (s.IsEqualTo_NoCase(list[i])) + return; + list.Add(s); +} + +void CExtractDialog::OnOK() +{ + #ifndef Z7_SFX + int pathMode2 = kPathModeButtonsVals[_pathMode.GetCurSel()]; + if (PathMode != NExtract::NPathMode::kCurPaths || + pathMode2 != NExtract::NPathMode::kFullPaths) + PathMode = (NExtract::NPathMode::EEnum)pathMode2; + + OverwriteMode = (NExtract::NOverwriteMode::EEnum)kOverwriteButtonsVals[_overwriteMode.GetCurSel()]; + + // _filesMode = (NExtractionDialog::NFilesMode::EEnum)GetFilesMode(); + + _passwordControl.GetText(Password); + + #endif + + #ifndef Z7_NO_REGISTRY + + // GetButton_Bools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams); + GetButton_Bools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity); + GetButton_Bools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup); + + bool showPassword = IsShowPasswordChecked(); + if (showPassword != _info.ShowPassword.Val) + { + _info.ShowPassword.Def = true; + _info.ShowPassword.Val = showPassword; + } + + if (_info.PathMode != pathMode2) + { + _info.PathMode_Force = true; + _info.PathMode = (NExtract::NPathMode::EEnum)pathMode2; + /* + // we allow kAbsPaths in registry. + if (_info.PathMode == NExtract::NPathMode::kAbsPaths) + _info.PathMode = NExtract::NPathMode::kFullPaths; + */ + } + + if (!OverwriteMode_Force && _info.OverwriteMode != OverwriteMode) + _info.OverwriteMode_Force = true; + _info.OverwriteMode = OverwriteMode; + + + #else + + ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP); + + #endif + + UString s; + + #ifdef Z7_NO_REGISTRY + + _path.GetText(s); + + #else + + int currentItem = _path.GetCurSel(); + if (currentItem == CB_ERR) + { + _path.GetText(s); + if (_path.GetCount() >= (int)kHistorySize) + currentItem = _path.GetCount() - 1; + } + else + _path.GetLBText(currentItem, s); + + #endif + + s.Trim(); + NName::NormalizeDirPathPrefix(s); + + #ifndef Z7_SFX + + const bool splitDest = IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE); + if (splitDest) + { + UString pathName; + _pathName.GetText(pathName); + pathName.Trim(); + s += pathName; + NName::NormalizeDirPathPrefix(s); + } + if (splitDest != _info.SplitDest.Val) + { + _info.SplitDest.Def = true; + _info.SplitDest.Val = splitDest; + } + + #endif + + DirPath = s; + + #ifndef Z7_NO_REGISTRY + _info.Paths.Clear(); + #ifndef Z7_SFX + AddUniqueString(_info.Paths, s); + #endif + for (int i = 0; i < _path.GetCount(); i++) + if (i != currentItem) + { + UString sTemp; + _path.GetLBText(i, sTemp); + sTemp.Trim(); + AddUniqueString(_info.Paths, sTemp); + } + _info.Save(); + #endif + + CModalDialog::OnOK(); +} + +#ifndef Z7_NO_REGISTRY +#define kHelpTopic "fm/plugins/7-zip/extract.htm" +void CExtractDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); + CModalDialog::OnHelp(); +} +#endif diff --git a/CPP/7zip/UI/GUI/ExtractDialog.h b/CPP/7zip/UI/GUI/ExtractDialog.h index 331889e24..1565fb8ab 100644 --- a/CPP/7zip/UI/GUI/ExtractDialog.h +++ b/CPP/7zip/UI/GUI/ExtractDialog.h @@ -1,113 +1,113 @@ -// ExtractDialog.h - -#ifndef ZIP7_INC_EXTRACT_DIALOG_H -#define ZIP7_INC_EXTRACT_DIALOG_H - -#include "ExtractDialogRes.h" - -#include "../../../Windows/Control/ComboBox.h" -#include "../../../Windows/Control/Edit.h" - -#include "../Common/ExtractMode.h" - -#include "../FileManager/DialogSize.h" - -#ifndef Z7_NO_REGISTRY -#include "../Common/ZipRegistry.h" -#endif - -namespace NExtractionDialog -{ - /* - namespace NFilesMode - { - enum EEnum - { - kSelected, - kAll, - kSpecified - }; - } - */ -} - -class CExtractDialog: public NWindows::NControl::CModalDialog -{ - #ifdef Z7_NO_REGISTRY - NWindows::NControl::CDialogChildControl _path; - #else - NWindows::NControl::CComboBox _path; - #endif - - #ifndef Z7_SFX - NWindows::NControl::CEdit _pathName; - NWindows::NControl::CEdit _passwordControl; - NWindows::NControl::CComboBox _pathMode; - NWindows::NControl::CComboBox _overwriteMode; - #endif - - #ifndef Z7_SFX - // int GetFilesMode() const; - void UpdatePasswordControl(); - #endif - - void OnButtonSetPath(); - - void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); - void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); - virtual bool OnInit() Z7_override; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; - virtual void OnOK() Z7_override; - - #ifndef Z7_NO_REGISTRY - - virtual void OnHelp() Z7_override; - - NExtract::CInfo _info; - - #endif - - bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); } -public: - // bool _enableSelectedFilesButton; - // bool _enableFilesButton; - // NExtractionDialog::NFilesMode::EEnum FilesMode; - - UString DirPath; - UString ArcPath; - - #ifndef Z7_SFX - UString Password; - #endif - bool PathMode_Force; - bool OverwriteMode_Force; - NExtract::NPathMode::EEnum PathMode; - NExtract::NOverwriteMode::EEnum OverwriteMode; - - #ifndef Z7_SFX - // CBoolPair AltStreams; - CBoolPair NtSecurity; - #endif - - CBoolPair ElimDup; - - INT_PTR Create(HWND aWndParent = NULL) - { - #ifdef Z7_SFX - BIG_DIALOG_SIZE(240, 64); - #else - BIG_DIALOG_SIZE(300, 160); - #endif - return CModalDialog::Create(SIZED_DIALOG(IDD_EXTRACT), aWndParent); - } - - CExtractDialog(): - PathMode_Force(false), - OverwriteMode_Force(false) - { - ElimDup.Val = true; - } - -}; - -#endif +// ExtractDialog.h + +#ifndef ZIP7_INC_EXTRACT_DIALOG_H +#define ZIP7_INC_EXTRACT_DIALOG_H + +#include "ExtractDialogRes.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" + +#include "../Common/ExtractMode.h" + +#include "../FileManager/DialogSize.h" + +#ifndef Z7_NO_REGISTRY +#include "../Common/ZipRegistry.h" +#endif + +namespace NExtractionDialog +{ + /* + namespace NFilesMode + { + enum EEnum + { + kSelected, + kAll, + kSpecified + }; + } + */ +} + +class CExtractDialog: public NWindows::NControl::CModalDialog +{ + #ifdef Z7_NO_REGISTRY + NWindows::NControl::CDialogChildControl _path; + #else + NWindows::NControl::CComboBox _path; + #endif + + #ifndef Z7_SFX + NWindows::NControl::CEdit _pathName; + NWindows::NControl::CEdit _passwordControl; + NWindows::NControl::CComboBox _pathMode; + NWindows::NControl::CComboBox _overwriteMode; + #endif + + #ifndef Z7_SFX + // int GetFilesMode() const; + void UpdatePasswordControl(); + #endif + + void OnButtonSetPath(); + + void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); + void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); + virtual bool OnInit() Z7_override; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override; + virtual void OnOK() Z7_override; + + #ifndef Z7_NO_REGISTRY + + virtual void OnHelp() Z7_override; + + NExtract::CInfo _info; + + #endif + + bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); } +public: + // bool _enableSelectedFilesButton; + // bool _enableFilesButton; + // NExtractionDialog::NFilesMode::EEnum FilesMode; + + UString DirPath; + UString ArcPath; + + #ifndef Z7_SFX + UString Password; + #endif + bool PathMode_Force; + bool OverwriteMode_Force; + NExtract::NPathMode::EEnum PathMode; + NExtract::NOverwriteMode::EEnum OverwriteMode; + + #ifndef Z7_SFX + // CBoolPair AltStreams; + CBoolPair NtSecurity; + #endif + + CBoolPair ElimDup; + + INT_PTR Create(HWND aWndParent = NULL) + { + #ifdef Z7_SFX + BIG_DIALOG_SIZE(240, 64); + #else + BIG_DIALOG_SIZE(300, 160); + #endif + return CModalDialog::Create(SIZED_DIALOG(IDD_EXTRACT), aWndParent); + } + + CExtractDialog(): + PathMode_Force(false), + OverwriteMode_Force(false) + { + ElimDup.Val = true; + } + +}; + +#endif diff --git a/CPP/7zip/UI/GUI/ExtractDialog.rc b/CPP/7zip/UI/GUI/ExtractDialog.rc index f5d65281c..3728b96d2 100644 --- a/CPP/7zip/UI/GUI/ExtractDialog.rc +++ b/CPP/7zip/UI/GUI/ExtractDialog.rc @@ -1,98 +1,98 @@ -#include "ExtractDialogRes.h" -#include "../../GuiCommon.rc" - -#define xc 336 -#define yc 168 - -#undef g1xs -#undef g2x -#undef g2x2 -#undef g2xs -#undef g2xs2 - -#define g1xs 160 - -#define gSpace 20 -#define g2x (m + g1xs + gSpace) -#define g2x2 (g2x + m) -#define g2xs (xc - g1xs - gSpace) -#define g2xs2 (g2xs - m - m) - -#undef GROUP_Y_SIZE -#ifdef UNDER_CE -#define GROUP_Y_SIZE 8 -#else -#define GROUP_Y_SIZE 56 -#endif - -IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Extract" -BEGIN - LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 - COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 12, 100, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 2, bxsDots, bys, WS_GROUP - - CONTROL "", IDX_EXTRACT_NAME_ENABLE, MY_CHECKBOX, m, m + 34, 12, 10 - EDITTEXT IDE_EXTRACT_NAME, m + 12 + 2, m + 32, g1xs - 12 - 2, 14, ES_AUTOHSCROLL - - LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 52, g1xs, 8 - COMBOBOX IDC_EXTRACT_PATH_MODE, m, m + 64, g1xs, 140, MY_COMBO - - CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, - m, m + 84, g1xs, 10 - - LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 104, g1xs, 8 - COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m, m + 116, g1xs, 140, MY_COMBO - - - GROUPBOX "Password", IDG_PASSWORD, g2x, m + 36, g2xs, GROUP_Y_SIZE - EDITTEXT IDE_EXTRACT_PASSWORD, g2x2, m + 50, g2xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, g2x2, m + 72, g2xs2, 10 - -// CONTROL "Restore alternate data streams", IDX_EXTRACT_ALT_STREAMS, MY_CHECKBOX, -// g2x, m + 104, g2xs, 10 - CONTROL "Restore file security", IDX_EXTRACT_NT_SECUR, MY_CHECKBOX, - g2x, m + 104, g2xs, 10 - - DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys - PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys -END - - -#ifdef UNDER_CE - -#undef m -#define m 4 - -#undef xc -#undef yc - -#define xc 152 -#define yc 128 - -#undef g1xs - -#define g1xs 64 - -IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT -CAPTION "Extract" -BEGIN - LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 8, 8 - COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 8, 100, MY_COMBO_WITH_EDIT - PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 3, bxsDots, bys, WS_GROUP - - LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 36, g1xs, 8 - COMBOBOX IDC_EXTRACT_PATH_MODE, m + g1xs, m + 36, xc - g1xs, 100, MY_COMBO - - LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 56, g1xs, 8 - COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m + g1xs, m + 56, xc - g1xs, 100, MY_COMBO - - LTEXT "Password", IDG_PASSWORD, m, m + 76, g1xs, 8 - EDITTEXT IDE_EXTRACT_PASSWORD, m + g1xs, m + 76, xc - g1xs, 14, ES_PASSWORD | ES_AUTOHSCROLL - CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, m + 92, xc, 10 - - OK_CANCEL -END - -#endif +#include "ExtractDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 336 +#define yc 168 + +#undef g1xs +#undef g2x +#undef g2x2 +#undef g2xs +#undef g2xs2 + +#define g1xs 160 + +#define gSpace 20 +#define g2x (m + g1xs + gSpace) +#define g2x2 (g2x + m) +#define g2xs (xc - g1xs - gSpace) +#define g2xs2 (g2xs - m - m) + +#undef GROUP_Y_SIZE +#ifdef UNDER_CE +#define GROUP_Y_SIZE 8 +#else +#define GROUP_Y_SIZE 56 +#endif + +IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Extract" +BEGIN + LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8 + COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 12, 100, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 2, bxsDots, bys, WS_GROUP + + CONTROL "", IDX_EXTRACT_NAME_ENABLE, MY_CHECKBOX, m, m + 34, 12, 10 + EDITTEXT IDE_EXTRACT_NAME, m + 12 + 2, m + 32, g1xs - 12 - 2, 14, ES_AUTOHSCROLL + + LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 52, g1xs, 8 + COMBOBOX IDC_EXTRACT_PATH_MODE, m, m + 64, g1xs, 140, MY_COMBO + + CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, + m, m + 84, g1xs, 10 + + LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 104, g1xs, 8 + COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m, m + 116, g1xs, 140, MY_COMBO + + + GROUPBOX "Password", IDG_PASSWORD, g2x, m + 36, g2xs, GROUP_Y_SIZE + EDITTEXT IDE_EXTRACT_PASSWORD, g2x2, m + 50, g2xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, g2x2, m + 72, g2xs2, 10 + +// CONTROL "Restore alternate data streams", IDX_EXTRACT_ALT_STREAMS, MY_CHECKBOX, +// g2x, m + 104, g2xs, 10 + CONTROL "Restore file security", IDX_EXTRACT_NT_SECUR, MY_CHECKBOX, + g2x, m + 104, g2xs, 10 + + DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys + PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys +END + + +#ifdef UNDER_CE + +#undef m +#define m 4 + +#undef xc +#undef yc + +#define xc 152 +#define yc 128 + +#undef g1xs + +#define g1xs 64 + +IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Extract" +BEGIN + LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 8, 8 + COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 8, 100, MY_COMBO_WITH_EDIT + PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 3, bxsDots, bys, WS_GROUP + + LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 36, g1xs, 8 + COMBOBOX IDC_EXTRACT_PATH_MODE, m + g1xs, m + 36, xc - g1xs, 100, MY_COMBO + + LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 56, g1xs, 8 + COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m + g1xs, m + 56, xc - g1xs, 100, MY_COMBO + + LTEXT "Password", IDG_PASSWORD, m, m + 76, g1xs, 8 + EDITTEXT IDE_EXTRACT_PASSWORD, m + g1xs, m + 76, xc - g1xs, 14, ES_PASSWORD | ES_AUTOHSCROLL + CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, m + 92, xc, 10 + + OK_CANCEL +END + +#endif diff --git a/CPP/7zip/UI/GUI/ExtractDialogRes.h b/CPP/7zip/UI/GUI/ExtractDialogRes.h index e198796aa..ed12bfb31 100644 --- a/CPP/7zip/UI/GUI/ExtractDialogRes.h +++ b/CPP/7zip/UI/GUI/ExtractDialogRes.h @@ -1,24 +1,24 @@ -#define IDD_EXTRACT 3400 -#define IDD_EXTRACT_2 13400 - -#define IDC_EXTRACT_PATH 100 -#define IDB_EXTRACT_SET_PATH 101 -#define IDC_EXTRACT_PATH_MODE 102 -#define IDC_EXTRACT_OVERWRITE_MODE 103 - -#define IDE_EXTRACT_PASSWORD 120 - -#define IDE_EXTRACT_NAME 130 -#define IDX_EXTRACT_NAME_ENABLE 131 - - -#define IDT_EXTRACT_EXTRACT_TO 3401 -#define IDT_EXTRACT_PATH_MODE 3410 -#define IDT_EXTRACT_OVERWRITE_MODE 3420 - -#define IDX_EXTRACT_ELIM_DUP 3430 -#define IDX_EXTRACT_NT_SECUR 3431 -// #define IDX_EXTRACT_ALT_STREAMS 3432 - -#define IDX_PASSWORD_SHOW 3803 -#define IDG_PASSWORD 3807 +#define IDD_EXTRACT 3400 +#define IDD_EXTRACT_2 13400 + +#define IDC_EXTRACT_PATH 100 +#define IDB_EXTRACT_SET_PATH 101 +#define IDC_EXTRACT_PATH_MODE 102 +#define IDC_EXTRACT_OVERWRITE_MODE 103 + +#define IDE_EXTRACT_PASSWORD 120 + +#define IDE_EXTRACT_NAME 130 +#define IDX_EXTRACT_NAME_ENABLE 131 + + +#define IDT_EXTRACT_EXTRACT_TO 3401 +#define IDT_EXTRACT_PATH_MODE 3410 +#define IDT_EXTRACT_OVERWRITE_MODE 3420 + +#define IDX_EXTRACT_ELIM_DUP 3430 +#define IDX_EXTRACT_NT_SECUR 3431 +// #define IDX_EXTRACT_ALT_STREAMS 3432 + +#define IDX_PASSWORD_SHOW 3803 +#define IDG_PASSWORD 3807 diff --git a/CPP/7zip/UI/GUI/ExtractGUI.cpp b/CPP/7zip/UI/GUI/ExtractGUI.cpp index 8cbcad919..bafff2bac 100644 --- a/CPP/7zip/UI/GUI/ExtractGUI.cpp +++ b/CPP/7zip/UI/GUI/ExtractGUI.cpp @@ -1,297 +1,297 @@ -// ExtractGUI.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileFind.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Thread.h" - -#include "../FileManager/ExtractCallback.h" -#include "../FileManager/FormatUtils.h" -#include "../FileManager/LangUtils.h" -#include "../FileManager/resourceGui.h" -#include "../FileManager/OverwriteDialogRes.h" - -#include "../Common/ArchiveExtractCallback.h" -#include "../Common/PropIDUtils.h" - -#include "../Explorer/MyMessages.h" - -#include "resource2.h" -#include "ExtractRes.h" - -#include "ExtractDialog.h" -#include "ExtractGUI.h" -#include "HashGUI.h" - -#include "../FileManager/PropertyNameRes.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static const wchar_t * const kIncorrectOutDir = L"Incorrect output directory path"; - -#ifndef Z7_SFX - -static void AddValuePair(UString &s, UINT resourceID, UInt64 value, bool addColon = true) -{ - AddLangString(s, resourceID); - if (addColon) - s.Add_Colon(); - s.Add_Space(); - s.Add_UInt64(value); - s.Add_LF(); -} - -static void AddSizePair(UString &s, UINT resourceID, UInt64 value) -{ - AddLangString(s, resourceID); - s += ": "; - AddSizeValue(s, value); - s.Add_LF(); -} - -#endif - -class CThreadExtracting: public CProgressThreadVirt -{ - HRESULT ProcessVirt() Z7_override; -public: - /* - #ifdef Z7_EXTERNAL_CODECS - const CExternalCodecs *externalCodecs; - #endif - */ - - CCodecs *codecs; - CExtractCallbackImp *ExtractCallbackSpec; - const CObjectVector *FormatIndices; - const CIntVector *ExcludedFormatIndices; - - UStringVector *ArchivePaths; - UStringVector *ArchivePathsFull; - const NWildcard::CCensorNode *WildcardCensor; - const CExtractOptions *Options; - - #ifndef Z7_SFX - CHashBundle *HashBundle; - virtual void ProcessWasFinished_GuiVirt() Z7_override; - #endif - - CMyComPtr FolderArchiveExtractCallback; - UString Title; - - CPropNameValPairs Pairs; -}; - - -#ifndef Z7_SFX -void CThreadExtracting::ProcessWasFinished_GuiVirt() -{ - if (HashBundle && !Pairs.IsEmpty()) - ShowHashResults(Pairs, *this); -} -#endif - -HRESULT CThreadExtracting::ProcessVirt() -{ - CDecompressStat Stat; - - #ifndef Z7_SFX - /* - if (HashBundle) - HashBundle->Init(); - */ - #endif - - HRESULT res = Extract( - /* - #ifdef Z7_EXTERNAL_CODECS - externalCodecs, - #endif - */ - codecs, - *FormatIndices, *ExcludedFormatIndices, - *ArchivePaths, *ArchivePathsFull, - *WildcardCensor, *Options, - ExtractCallbackSpec, ExtractCallbackSpec, FolderArchiveExtractCallback, - #ifndef Z7_SFX - HashBundle, - #endif - FinalMessage.ErrorMessage.Message, Stat); - - #ifndef Z7_SFX - if (res == S_OK && ExtractCallbackSpec->IsOK()) - { - if (HashBundle) - { - AddValuePair(Pairs, IDS_ARCHIVES_COLON, Stat.NumArchives); - AddSizeValuePair(Pairs, IDS_PROP_PACKED_SIZE, Stat.PackSize); - AddHashBundleRes(Pairs, *HashBundle); - } - else if (Options->TestMode) - { - UString s; - - AddValuePair(s, IDS_ARCHIVES_COLON, Stat.NumArchives, false); - AddSizePair(s, IDS_PROP_PACKED_SIZE, Stat.PackSize); - - if (Stat.NumFolders != 0) - AddValuePair(s, IDS_PROP_FOLDERS, Stat.NumFolders); - AddValuePair(s, IDS_PROP_FILES, Stat.NumFiles); - AddSizePair(s, IDS_PROP_SIZE, Stat.UnpackSize); - if (Stat.NumAltStreams != 0) - { - s.Add_LF(); - AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, Stat.NumAltStreams); - AddSizePair(s, IDS_PROP_ALT_STREAMS_SIZE, Stat.AltStreams_UnpackSize); - } - s.Add_LF(); - AddLangString(s, IDS_MESSAGE_NO_ERRORS); - FinalMessage.OkMessage.Title = Title; - FinalMessage.OkMessage.Message = s; - } - } - #endif - - return res; -} - - - -HRESULT ExtractGUI( - // DECL_EXTERNAL_CODECS_LOC_VARS - CCodecs *codecs, - const CObjectVector &formatIndices, - const CIntVector &excludedFormatIndices, - UStringVector &archivePaths, - UStringVector &archivePathsFull, - const NWildcard::CCensorNode &wildcardCensor, - CExtractOptions &options, - #ifndef Z7_SFX - CHashBundle *hb, - #endif - bool showDialog, - bool &messageWasDisplayed, - CExtractCallbackImp *extractCallback, - HWND hwndParent) -{ - messageWasDisplayed = false; - - CThreadExtracting extracter; - /* - #ifdef Z7_EXTERNAL_CODECS - extracter.externalCodecs = _externalCodecs; - #endif - */ - extracter.codecs = codecs; - extracter.FormatIndices = &formatIndices; - extracter.ExcludedFormatIndices = &excludedFormatIndices; - - if (!options.TestMode) - { - FString outputDir = options.OutputDir; - #ifndef UNDER_CE - if (outputDir.IsEmpty()) - GetCurrentDir(outputDir); - #endif - if (showDialog) - { - CExtractDialog dialog; - FString outputDirFull; - if (!MyGetFullPathName(outputDir, outputDirFull)) - { - ShowErrorMessage(kIncorrectOutDir); - messageWasDisplayed = true; - return E_FAIL; - } - NName::NormalizeDirPathPrefix(outputDirFull); - - dialog.DirPath = fs2us(outputDirFull); - - dialog.OverwriteMode = options.OverwriteMode; - dialog.OverwriteMode_Force = options.OverwriteMode_Force; - dialog.PathMode = options.PathMode; - dialog.PathMode_Force = options.PathMode_Force; - dialog.ElimDup = options.ElimDup; - - if (archivePathsFull.Size() == 1) - dialog.ArcPath = archivePathsFull[0]; - - #ifndef Z7_SFX - // dialog.AltStreams = options.NtOptions.AltStreams; - dialog.NtSecurity = options.NtOptions.NtSecurity; - if (extractCallback->PasswordIsDefined) - dialog.Password = extractCallback->Password; - #endif - - if (dialog.Create(hwndParent) != IDOK) - return E_ABORT; - - outputDir = us2fs(dialog.DirPath); - - options.OverwriteMode = dialog.OverwriteMode; - options.PathMode = dialog.PathMode; - options.ElimDup = dialog.ElimDup; - - #ifndef Z7_SFX - // options.NtOptions.AltStreams = dialog.AltStreams; - options.NtOptions.NtSecurity = dialog.NtSecurity; - extractCallback->Password = dialog.Password; - extractCallback->PasswordIsDefined = !dialog.Password.IsEmpty(); - #endif - } - if (!MyGetFullPathName(outputDir, options.OutputDir)) - { - ShowErrorMessage(kIncorrectOutDir); - messageWasDisplayed = true; - return E_FAIL; - } - NName::NormalizeDirPathPrefix(options.OutputDir); - - /* - if (!CreateComplexDirectory(options.OutputDir)) - { - UString s = GetUnicodeString(NError::MyFormatMessage(GetLastError())); - UString s2 = MyFormatNew(IDS_CANNOT_CREATE_FOLDER, - #ifdef Z7_LANG - 0x02000603, - #endif - options.OutputDir); - s2.Add_LF(); - s2 += s; - MyMessageBox(s2); - return E_FAIL; - } - */ - } - - UString title = LangString(options.TestMode ? IDS_PROGRESS_TESTING : IDS_PROGRESS_EXTRACTING); - - extracter.Title = title; - extracter.ExtractCallbackSpec = extractCallback; - extracter.ExtractCallbackSpec->ProgressDialog = &extracter; - extracter.FolderArchiveExtractCallback = extractCallback; - extracter.ExtractCallbackSpec->Init(); - - extracter.CompressingMode = false; - - extracter.ArchivePaths = &archivePaths; - extracter.ArchivePathsFull = &archivePathsFull; - extracter.WildcardCensor = &wildcardCensor; - extracter.Options = &options; - #ifndef Z7_SFX - extracter.HashBundle = hb; - #endif - - extracter.IconID = IDI_ICON; - - RINOK(extracter.Create(title, hwndParent)) - messageWasDisplayed = extracter.ThreadFinishedOK && extracter.MessagesDisplayed; - return extracter.Result; -} +// ExtractGUI.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Thread.h" + +#include "../FileManager/ExtractCallback.h" +#include "../FileManager/FormatUtils.h" +#include "../FileManager/LangUtils.h" +#include "../FileManager/resourceGui.h" +#include "../FileManager/OverwriteDialogRes.h" + +#include "../Common/ArchiveExtractCallback.h" +#include "../Common/PropIDUtils.h" + +#include "../Explorer/MyMessages.h" + +#include "resource2.h" +#include "ExtractRes.h" + +#include "ExtractDialog.h" +#include "ExtractGUI.h" +#include "HashGUI.h" + +#include "../FileManager/PropertyNameRes.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static const wchar_t * const kIncorrectOutDir = L"Incorrect output directory path"; + +#ifndef Z7_SFX + +static void AddValuePair(UString &s, UINT resourceID, UInt64 value, bool addColon = true) +{ + AddLangString(s, resourceID); + if (addColon) + s.Add_Colon(); + s.Add_Space(); + s.Add_UInt64(value); + s.Add_LF(); +} + +static void AddSizePair(UString &s, UINT resourceID, UInt64 value) +{ + AddLangString(s, resourceID); + s += ": "; + AddSizeValue(s, value); + s.Add_LF(); +} + +#endif + +class CThreadExtracting: public CProgressThreadVirt +{ + HRESULT ProcessVirt() Z7_override; +public: + /* + #ifdef Z7_EXTERNAL_CODECS + const CExternalCodecs *externalCodecs; + #endif + */ + + CCodecs *codecs; + CExtractCallbackImp *ExtractCallbackSpec; + const CObjectVector *FormatIndices; + const CIntVector *ExcludedFormatIndices; + + UStringVector *ArchivePaths; + UStringVector *ArchivePathsFull; + const NWildcard::CCensorNode *WildcardCensor; + const CExtractOptions *Options; + + #ifndef Z7_SFX + CHashBundle *HashBundle; + virtual void ProcessWasFinished_GuiVirt() Z7_override; + #endif + + CMyComPtr FolderArchiveExtractCallback; + UString Title; + + CPropNameValPairs Pairs; +}; + + +#ifndef Z7_SFX +void CThreadExtracting::ProcessWasFinished_GuiVirt() +{ + if (HashBundle && !Pairs.IsEmpty()) + ShowHashResults(Pairs, *this); +} +#endif + +HRESULT CThreadExtracting::ProcessVirt() +{ + CDecompressStat Stat; + + #ifndef Z7_SFX + /* + if (HashBundle) + HashBundle->Init(); + */ + #endif + + HRESULT res = Extract( + /* + #ifdef Z7_EXTERNAL_CODECS + externalCodecs, + #endif + */ + codecs, + *FormatIndices, *ExcludedFormatIndices, + *ArchivePaths, *ArchivePathsFull, + *WildcardCensor, *Options, + ExtractCallbackSpec, ExtractCallbackSpec, FolderArchiveExtractCallback, + #ifndef Z7_SFX + HashBundle, + #endif + FinalMessage.ErrorMessage.Message, Stat); + + #ifndef Z7_SFX + if (res == S_OK && ExtractCallbackSpec->IsOK()) + { + if (HashBundle) + { + AddValuePair(Pairs, IDS_ARCHIVES_COLON, Stat.NumArchives); + AddSizeValuePair(Pairs, IDS_PROP_PACKED_SIZE, Stat.PackSize); + AddHashBundleRes(Pairs, *HashBundle); + } + else if (Options->TestMode) + { + UString s; + + AddValuePair(s, IDS_ARCHIVES_COLON, Stat.NumArchives, false); + AddSizePair(s, IDS_PROP_PACKED_SIZE, Stat.PackSize); + + if (Stat.NumFolders != 0) + AddValuePair(s, IDS_PROP_FOLDERS, Stat.NumFolders); + AddValuePair(s, IDS_PROP_FILES, Stat.NumFiles); + AddSizePair(s, IDS_PROP_SIZE, Stat.UnpackSize); + if (Stat.NumAltStreams != 0) + { + s.Add_LF(); + AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, Stat.NumAltStreams); + AddSizePair(s, IDS_PROP_ALT_STREAMS_SIZE, Stat.AltStreams_UnpackSize); + } + s.Add_LF(); + AddLangString(s, IDS_MESSAGE_NO_ERRORS); + FinalMessage.OkMessage.Title = Title; + FinalMessage.OkMessage.Message = s; + } + } + #endif + + return res; +} + + + +HRESULT ExtractGUI( + // DECL_EXTERNAL_CODECS_LOC_VARS + CCodecs *codecs, + const CObjectVector &formatIndices, + const CIntVector &excludedFormatIndices, + UStringVector &archivePaths, + UStringVector &archivePathsFull, + const NWildcard::CCensorNode &wildcardCensor, + CExtractOptions &options, + #ifndef Z7_SFX + CHashBundle *hb, + #endif + bool showDialog, + bool &messageWasDisplayed, + CExtractCallbackImp *extractCallback, + HWND hwndParent) +{ + messageWasDisplayed = false; + + CThreadExtracting extracter; + /* + #ifdef Z7_EXTERNAL_CODECS + extracter.externalCodecs = _externalCodecs; + #endif + */ + extracter.codecs = codecs; + extracter.FormatIndices = &formatIndices; + extracter.ExcludedFormatIndices = &excludedFormatIndices; + + if (!options.TestMode) + { + FString outputDir = options.OutputDir; + #ifndef UNDER_CE + if (outputDir.IsEmpty()) + GetCurrentDir(outputDir); + #endif + if (showDialog) + { + CExtractDialog dialog; + FString outputDirFull; + if (!MyGetFullPathName(outputDir, outputDirFull)) + { + ShowErrorMessage(kIncorrectOutDir); + messageWasDisplayed = true; + return E_FAIL; + } + NName::NormalizeDirPathPrefix(outputDirFull); + + dialog.DirPath = fs2us(outputDirFull); + + dialog.OverwriteMode = options.OverwriteMode; + dialog.OverwriteMode_Force = options.OverwriteMode_Force; + dialog.PathMode = options.PathMode; + dialog.PathMode_Force = options.PathMode_Force; + dialog.ElimDup = options.ElimDup; + + if (archivePathsFull.Size() == 1) + dialog.ArcPath = archivePathsFull[0]; + + #ifndef Z7_SFX + // dialog.AltStreams = options.NtOptions.AltStreams; + dialog.NtSecurity = options.NtOptions.NtSecurity; + if (extractCallback->PasswordIsDefined) + dialog.Password = extractCallback->Password; + #endif + + if (dialog.Create(hwndParent) != IDOK) + return E_ABORT; + + outputDir = us2fs(dialog.DirPath); + + options.OverwriteMode = dialog.OverwriteMode; + options.PathMode = dialog.PathMode; + options.ElimDup = dialog.ElimDup; + + #ifndef Z7_SFX + // options.NtOptions.AltStreams = dialog.AltStreams; + options.NtOptions.NtSecurity = dialog.NtSecurity; + extractCallback->Password = dialog.Password; + extractCallback->PasswordIsDefined = !dialog.Password.IsEmpty(); + #endif + } + if (!MyGetFullPathName(outputDir, options.OutputDir)) + { + ShowErrorMessage(kIncorrectOutDir); + messageWasDisplayed = true; + return E_FAIL; + } + NName::NormalizeDirPathPrefix(options.OutputDir); + + /* + if (!CreateComplexDirectory(options.OutputDir)) + { + UString s = GetUnicodeString(NError::MyFormatMessage(GetLastError())); + UString s2 = MyFormatNew(IDS_CANNOT_CREATE_FOLDER, + #ifdef Z7_LANG + 0x02000603, + #endif + options.OutputDir); + s2.Add_LF(); + s2 += s; + MyMessageBox(s2); + return E_FAIL; + } + */ + } + + UString title = LangString(options.TestMode ? IDS_PROGRESS_TESTING : IDS_PROGRESS_EXTRACTING); + + extracter.Title = title; + extracter.ExtractCallbackSpec = extractCallback; + extracter.ExtractCallbackSpec->ProgressDialog = &extracter; + extracter.FolderArchiveExtractCallback = extractCallback; + extracter.ExtractCallbackSpec->Init(); + + extracter.CompressingMode = false; + + extracter.ArchivePaths = &archivePaths; + extracter.ArchivePathsFull = &archivePathsFull; + extracter.WildcardCensor = &wildcardCensor; + extracter.Options = &options; + #ifndef Z7_SFX + extracter.HashBundle = hb; + #endif + + extracter.IconID = IDI_ICON; + + RINOK(extracter.Create(title, hwndParent)) + messageWasDisplayed = extracter.ThreadFinishedOK && extracter.MessagesDisplayed; + return extracter.Result; +} diff --git a/CPP/7zip/UI/GUI/ExtractGUI.h b/CPP/7zip/UI/GUI/ExtractGUI.h index 398ddf3b5..13ca6abf8 100644 --- a/CPP/7zip/UI/GUI/ExtractGUI.h +++ b/CPP/7zip/UI/GUI/ExtractGUI.h @@ -1,39 +1,39 @@ -// GUI/ExtractGUI.h - -#ifndef ZIP7_INC_EXTRACT_GUI_H -#define ZIP7_INC_EXTRACT_GUI_H - -#include "../Common/Extract.h" - -#include "../FileManager/ExtractCallback.h" - -/* - RESULT can be S_OK, even if there are errors!!! - if RESULT == S_OK, check extractCallback->IsOK() after ExtractGUI(). - - RESULT = E_ABORT - user break. - RESULT != E_ABORT: - { - messageWasDisplayed = true - message was displayed already. - messageWasDisplayed = false - there was some internal error, so you must show error message. - } -*/ - -HRESULT ExtractGUI( - // DECL_EXTERNAL_CODECS_LOC_VARS - CCodecs *codecs, - const CObjectVector &formatIndices, - const CIntVector &excludedFormatIndices, - UStringVector &archivePaths, - UStringVector &archivePathsFull, - const NWildcard::CCensorNode &wildcardCensor, - CExtractOptions &options, - #ifndef Z7_SFX - CHashBundle *hb, - #endif - bool showDialog, - bool &messageWasDisplayed, - CExtractCallbackImp *extractCallback, - HWND hwndParent = NULL); - -#endif +// GUI/ExtractGUI.h + +#ifndef ZIP7_INC_EXTRACT_GUI_H +#define ZIP7_INC_EXTRACT_GUI_H + +#include "../Common/Extract.h" + +#include "../FileManager/ExtractCallback.h" + +/* + RESULT can be S_OK, even if there are errors!!! + if RESULT == S_OK, check extractCallback->IsOK() after ExtractGUI(). + + RESULT = E_ABORT - user break. + RESULT != E_ABORT: + { + messageWasDisplayed = true - message was displayed already. + messageWasDisplayed = false - there was some internal error, so you must show error message. + } +*/ + +HRESULT ExtractGUI( + // DECL_EXTERNAL_CODECS_LOC_VARS + CCodecs *codecs, + const CObjectVector &formatIndices, + const CIntVector &excludedFormatIndices, + UStringVector &archivePaths, + UStringVector &archivePathsFull, + const NWildcard::CCensorNode &wildcardCensor, + CExtractOptions &options, + #ifndef Z7_SFX + CHashBundle *hb, + #endif + bool showDialog, + bool &messageWasDisplayed, + CExtractCallbackImp *extractCallback, + HWND hwndParent = NULL); + +#endif diff --git a/CPP/7zip/UI/GUI/ExtractRes.h b/CPP/7zip/UI/GUI/ExtractRes.h index 6437d953f..634ba6b5f 100644 --- a/CPP/7zip/UI/GUI/ExtractRes.h +++ b/CPP/7zip/UI/GUI/ExtractRes.h @@ -1,51 +1,51 @@ -#define IDS_MEM_ERROR 3000 - -#define IDS_CANNOT_CREATE_FOLDER 3003 -#define IDS_UPDATE_NOT_SUPPORTED 3004 -#define IDS_CANT_OPEN_ARCHIVE 3005 -#define IDS_CANT_OPEN_ENCRYPTED_ARCHIVE 3006 -#define IDS_UNSUPPORTED_ARCHIVE_TYPE 3007 - -#define IDS_CANT_OPEN_AS_TYPE 3017 -#define IDS_IS_OPEN_AS_TYPE 3018 -#define IDS_IS_OPEN_WITH_OFFSET 3019 - -#define IDS_PROGRESS_EXTRACTING 3300 - -#define IDS_PROGRESS_SKIPPING 3325 - -#define IDS_EXTRACT_SET_FOLDER 3402 - -#define IDS_EXTRACT_PATHS_FULL 3411 -#define IDS_EXTRACT_PATHS_NO 3412 -#define IDS_EXTRACT_PATHS_ABS 3413 -#define IDS_PATH_MODE_RELAT 3414 - -#define IDS_EXTRACT_OVERWRITE_ASK 3421 -#define IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT 3422 -#define IDS_EXTRACT_OVERWRITE_SKIP_EXISTING 3423 -#define IDS_EXTRACT_OVERWRITE_RENAME 3424 -#define IDS_EXTRACT_OVERWRITE_RENAME_EXISTING 3425 - -#define IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD 3700 -#define IDS_EXTRACT_MESSAGE_DATA_ERROR 3701 -#define IDS_EXTRACT_MESSAGE_CRC_ERROR 3702 -#define IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED 3703 -#define IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED 3704 - -#define IDS_EXTRACT_MSG_WRONG_PSW_GUESS 3710 -// #define IDS_EXTRACT_MSG_ENCRYPTED 3711 - -#define IDS_EXTRACT_MSG_UNSUPPORTED_METHOD 3721 -#define IDS_EXTRACT_MSG_DATA_ERROR 3722 -#define IDS_EXTRACT_MSG_CRC_ERROR 3723 -#define IDS_EXTRACT_MSG_UNAVAILABLE_DATA 3724 -#define IDS_EXTRACT_MSG_UEXPECTED_END 3725 -#define IDS_EXTRACT_MSG_DATA_AFTER_END 3726 -#define IDS_EXTRACT_MSG_IS_NOT_ARC 3727 -#define IDS_EXTRACT_MSG_HEADERS_ERROR 3728 -#define IDS_EXTRACT_MSG_WRONG_PSW_CLAIM 3729 - -#define IDS_OPEN_MSG_UNAVAILABLE_START 3763 -#define IDS_OPEN_MSG_UNCONFIRMED_START 3764 -#define IDS_OPEN_MSG_UNSUPPORTED_FEATURE 3768 +#define IDS_MEM_ERROR 3000 + +#define IDS_CANNOT_CREATE_FOLDER 3003 +#define IDS_UPDATE_NOT_SUPPORTED 3004 +#define IDS_CANT_OPEN_ARCHIVE 3005 +#define IDS_CANT_OPEN_ENCRYPTED_ARCHIVE 3006 +#define IDS_UNSUPPORTED_ARCHIVE_TYPE 3007 + +#define IDS_CANT_OPEN_AS_TYPE 3017 +#define IDS_IS_OPEN_AS_TYPE 3018 +#define IDS_IS_OPEN_WITH_OFFSET 3019 + +#define IDS_PROGRESS_EXTRACTING 3300 + +#define IDS_PROGRESS_SKIPPING 3325 + +#define IDS_EXTRACT_SET_FOLDER 3402 + +#define IDS_EXTRACT_PATHS_FULL 3411 +#define IDS_EXTRACT_PATHS_NO 3412 +#define IDS_EXTRACT_PATHS_ABS 3413 +#define IDS_PATH_MODE_RELAT 3414 + +#define IDS_EXTRACT_OVERWRITE_ASK 3421 +#define IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT 3422 +#define IDS_EXTRACT_OVERWRITE_SKIP_EXISTING 3423 +#define IDS_EXTRACT_OVERWRITE_RENAME 3424 +#define IDS_EXTRACT_OVERWRITE_RENAME_EXISTING 3425 + +#define IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD 3700 +#define IDS_EXTRACT_MESSAGE_DATA_ERROR 3701 +#define IDS_EXTRACT_MESSAGE_CRC_ERROR 3702 +#define IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED 3703 +#define IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED 3704 + +#define IDS_EXTRACT_MSG_WRONG_PSW_GUESS 3710 +// #define IDS_EXTRACT_MSG_ENCRYPTED 3711 + +#define IDS_EXTRACT_MSG_UNSUPPORTED_METHOD 3721 +#define IDS_EXTRACT_MSG_DATA_ERROR 3722 +#define IDS_EXTRACT_MSG_CRC_ERROR 3723 +#define IDS_EXTRACT_MSG_UNAVAILABLE_DATA 3724 +#define IDS_EXTRACT_MSG_UEXPECTED_END 3725 +#define IDS_EXTRACT_MSG_DATA_AFTER_END 3726 +#define IDS_EXTRACT_MSG_IS_NOT_ARC 3727 +#define IDS_EXTRACT_MSG_HEADERS_ERROR 3728 +#define IDS_EXTRACT_MSG_WRONG_PSW_CLAIM 3729 + +#define IDS_OPEN_MSG_UNAVAILABLE_START 3763 +#define IDS_OPEN_MSG_UNCONFIRMED_START 3764 +#define IDS_OPEN_MSG_UNSUPPORTED_FEATURE 3768 diff --git a/CPP/7zip/UI/GUI/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp index 389ec0281..6bb66936e 100644 --- a/CPP/7zip/UI/GUI/GUI.cpp +++ b/CPP/7zip/UI/GUI/GUI.cpp @@ -1,494 +1,494 @@ -// GUI.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include "../../../../C/DllSecur.h" -#endif - -#include "../../../Common/MyWindows.h" -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../../../Common/MyInitGuid.h" - -#include "../../../Common/CommandLineParser.h" -#include "../../../Common/MyException.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/FileDir.h" -#include "../../../Windows/NtCheck.h" - -#include "../Common/ArchiveCommandLine.h" -#include "../Common/ExitCode.h" - -#include "../FileManager/StringUtils.h" -#include "../FileManager/LangUtils.h" - -#include "BenchmarkDialog.h" -#include "ExtractGUI.h" -#include "HashGUI.h" -#include "UpdateGUI.h" - -#include "ExtractRes.h" - -using namespace NWindows; - -#ifdef Z7_EXTERNAL_CODECS -extern -const CExternalCodecs *g_ExternalCodecs_Ptr; -const CExternalCodecs *g_ExternalCodecs_Ptr; -#endif - -extern -HINSTANCE g_hInstance; -HINSTANCE g_hInstance; -extern -bool g_DisableUserQuestions; -bool g_DisableUserQuestions; - -#ifndef UNDER_CE - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // win2000 -#define Z7_USE_DYN_ComCtl32Version -#endif - -#ifdef Z7_USE_DYN_ComCtl32Version -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -extern -DWORD g_ComCtl32Version; -DWORD g_ComCtl32Version; - -static DWORD GetDllVersion(LPCTSTR dllName) -{ - DWORD dwVersion = 0; - const HMODULE hmodule = LoadLibrary(dllName); - if (hmodule) - { - const - DLLGETVERSIONPROC f_DllGetVersion = Z7_GET_PROC_ADDRESS( - DLLGETVERSIONPROC, hmodule, - "DllGetVersion"); - if (f_DllGetVersion) - { - DLLVERSIONINFO dvi; - ZeroMemory(&dvi, sizeof(dvi)); - dvi.cbSize = sizeof(dvi); - const HRESULT hr = (*f_DllGetVersion)(&dvi); - if (SUCCEEDED(hr)) - dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); - } - FreeLibrary(hmodule); - } - return dwVersion; -} - -#endif -#endif - -extern -bool g_LVN_ITEMACTIVATE_Support; -bool g_LVN_ITEMACTIVATE_Support = true; - -DECLARE_AND_SET_CLIENT_VERSION_VAR - -static void ErrorMessage(LPCWSTR message) -{ - if (!g_DisableUserQuestions) - MessageBoxW(NULL, message, L"7-Zip", MB_ICONERROR | MB_OK); -} - -static void ErrorMessage(const char *s) -{ - ErrorMessage(GetUnicodeString(s)); -} - -static void ErrorLangMessage(UINT resourceID) -{ - ErrorMessage(LangString(resourceID)); -} - -static const char * const kNoFormats = "7-Zip cannot find the code that works with archives."; - -static int ShowMemErrorMessage() -{ - ErrorLangMessage(IDS_MEM_ERROR); - return NExitCode::kMemoryError; -} - -static int ShowSysErrorMessage(HRESULT errorCode) -{ - if (errorCode == E_OUTOFMEMORY) - return ShowMemErrorMessage(); - ErrorMessage(HResultToMessage(errorCode)); - return NExitCode::kFatalError; -} - -static void ThrowException_if_Error(HRESULT res) -{ - if (res != S_OK) - throw CSystemException(res); -} - -static int Main2() -{ - UStringVector commandStrings; - NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); - - #ifndef UNDER_CE - if (commandStrings.Size() > 0) - commandStrings.Delete(0); - #endif - if (commandStrings.Size() == 0) - { - MessageBoxW(NULL, L"Specify command", L"7-Zip", 0); - return 0; - } - - CArcCmdLineOptions options; - CArcCmdLineParser parser; - - parser.Parse1(commandStrings, options); - g_DisableUserQuestions = options.YesToAll; - parser.Parse2(options); - - CREATE_CODECS_OBJECT - - codecs->CaseSensitive_Change = options.CaseSensitive_Change; - codecs->CaseSensitive = options.CaseSensitive; - ThrowException_if_Error(codecs->Load()); - Codecs_AddHashArcHandler(codecs); - - #ifdef Z7_EXTERNAL_CODECS - { - g_ExternalCodecs_Ptr = &_externalCodecs; - UString s; - codecs->GetCodecsErrorMessage(s); - if (!s.IsEmpty()) - { - if (!g_DisableUserQuestions) - MessageBoxW(NULL, s, L"7-Zip", MB_ICONERROR); - } - - } - #endif - - const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); - - if (codecs->Formats.Size() == 0 && - (isExtractGroupCommand - - || options.Command.IsFromUpdateGroup())) - { - #ifdef Z7_EXTERNAL_CODECS - if (!codecs->MainDll_ErrorPath.IsEmpty()) - { - UString s ("7-Zip cannot load module: "); - s += fs2us(codecs->MainDll_ErrorPath); - throw s; - } - #endif - throw kNoFormats; - } - - CObjectVector formatIndices; - if (!ParseOpenTypes(*codecs, options.ArcType, formatIndices)) - { - ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); - return NExitCode::kFatalError; - } - - CIntVector excludedFormats; - FOR_VECTOR (k, options.ExcludedArcTypes) - { - CIntVector tempIndices; - if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices) - || tempIndices.Size() != 1) - { - ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); - return NExitCode::kFatalError; - } - excludedFormats.AddToUniqueSorted(tempIndices[0]); - // excludedFormats.Sort(); - } - - #ifdef Z7_EXTERNAL_CODECS - if (isExtractGroupCommand - || options.Command.IsFromUpdateGroup() - || options.Command.CommandType == NCommandType::kHash - || options.Command.CommandType == NCommandType::kBenchmark) - ThrowException_if_Error(_externalCodecs.Load()); - #endif - - if (options.Command.CommandType == NCommandType::kBenchmark) - { - HRESULT res = Benchmark( - EXTERNAL_CODECS_VARS_L - options.Properties, - options.NumIterations_Defined ? - options.NumIterations : - k_NumBenchIterations_Default); - /* - if (res == S_FALSE) - { - stdStream << "\nDecoding Error\n"; - return NExitCode::kFatalError; - } - */ - ThrowException_if_Error(res); - } - else if (isExtractGroupCommand) - { - UStringVector ArchivePathsSorted; - UStringVector ArchivePathsFullSorted; - - CExtractCallbackImp *ecs = new CExtractCallbackImp; - CMyComPtr extractCallback = ecs; - - #ifndef Z7_NO_CRYPTO - ecs->PasswordIsDefined = options.PasswordEnabled; - ecs->Password = options.Password; - #endif - - ecs->Init(); - - CExtractOptions eo; - (CExtractOptionsBase &)eo = options.ExtractOptions; - eo.StdInMode = options.StdInMode; - eo.StdOutMode = options.StdOutMode; - eo.YesToAll = options.YesToAll; - ecs->YesToAll = options.YesToAll; - eo.TestMode = options.Command.IsTestCommand(); - ecs->TestMode = eo.TestMode; - - #ifndef Z7_SFX - eo.Properties = options.Properties; - #endif - - bool messageWasDisplayed = false; - - #ifndef Z7_SFX - CHashBundle hb; - CHashBundle *hb_ptr = NULL; - - if (!options.HashMethods.IsEmpty()) - { - hb_ptr = &hb; - ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods)); - } - #endif - - { - CDirItemsStat st; - HRESULT hresultMain = EnumerateDirItemsAndSort( - options.arcCensor, - NWildcard::k_RelatPath, - UString(), // addPathPrefix - ArchivePathsSorted, - ArchivePathsFullSorted, - st, - NULL // &scan: change it!!!! - ); - if (hresultMain != S_OK) - { - /* - if (hresultMain != E_ABORT && messageWasDisplayed) - return NExitCode::kFatalError; - */ - throw CSystemException(hresultMain); - } - } - - ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); - - HRESULT result = ExtractGUI( - // EXTERNAL_CODECS_VARS_L - codecs, - formatIndices, excludedFormats, - ArchivePathsSorted, - ArchivePathsFullSorted, - options.Censor.Pairs.Front().Head, - eo, - #ifndef Z7_SFX - hb_ptr, - #endif - options.ShowDialog, messageWasDisplayed, ecs); - if (result != S_OK) - { - if (result != E_ABORT && messageWasDisplayed) - return NExitCode::kFatalError; - throw CSystemException(result); - } - if (!ecs->IsOK()) - return NExitCode::kFatalError; - } - else if (options.Command.IsFromUpdateGroup()) - { - #ifndef Z7_NO_CRYPTO - bool passwordIsDefined = options.PasswordEnabled && !options.Password.IsEmpty(); - #endif - - CUpdateCallbackGUI callback; - // callback.EnablePercents = options.EnablePercents; - - #ifndef Z7_NO_CRYPTO - callback.PasswordIsDefined = passwordIsDefined; - callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty(); - callback.Password = options.Password; - #endif - - // callback.StdOutMode = options.UpdateOptions.StdOutMode; - callback.Init(); - - if (!options.UpdateOptions.InitFormatIndex(codecs, formatIndices, options.ArchiveName) || - !options.UpdateOptions.SetArcPath(codecs, options.ArchiveName)) - { - ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED); - return NExitCode::kFatalError; - } - bool messageWasDisplayed = false; - HRESULT result = UpdateGUI( - codecs, formatIndices, - options.ArchiveName, - options.Censor, - options.UpdateOptions, - options.ShowDialog, - messageWasDisplayed, - &callback); - - if (result != S_OK) - { - if (result != E_ABORT && messageWasDisplayed) - return NExitCode::kFatalError; - throw CSystemException(result); - } - if (callback.FailedFiles.Size() > 0) - { - if (!messageWasDisplayed) - throw CSystemException(E_FAIL); - return NExitCode::kWarning; - } - } - else if (options.Command.CommandType == NCommandType::kHash) - { - bool messageWasDisplayed = false; - HRESULT result = HashCalcGUI(EXTERNAL_CODECS_VARS_L - options.Censor, options.HashOptions, messageWasDisplayed); - - if (result != S_OK) - { - if (result != E_ABORT && messageWasDisplayed) - return NExitCode::kFatalError; - throw CSystemException(result); - } - /* - if (callback.FailedFiles.Size() > 0) - { - if (!messageWasDisplayed) - throw CSystemException(E_FAIL); - return NExitCode::kWarning; - } - */ - } - else - { - throw "Unsupported command"; - } - return 0; -} - -#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) -#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return NExitCode::kFatalError; -#endif - -int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, - #ifdef UNDER_CE - LPWSTR - #else - LPSTR - #endif - /* lpCmdLine */, int /* nCmdShow */) -{ - g_hInstance = hInstance; - - #ifdef _WIN32 - NT_CHECK - #endif - - InitCommonControls(); - -#ifdef Z7_USE_DYN_ComCtl32Version - g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); - g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); -#endif - - // OleInitialize is required for ProgressBar in TaskBar. - #ifndef UNDER_CE - OleInitialize(NULL); - #endif - - #ifdef Z7_LANG - LoadLangOneTime(); - #endif - - // setlocale(LC_COLLATE, ".ACP"); - try - { - #ifdef _WIN32 - My_SetDefaultDllDirectories(); - #endif - - return Main2(); - } - catch(const CNewException &) - { - return ShowMemErrorMessage(); - } - catch(const CMessagePathException &e) - { - ErrorMessage(e); - return NExitCode::kUserError; - } - catch(const CSystemException &systemError) - { - if (systemError.ErrorCode == E_ABORT) - return NExitCode::kUserBreak; - return ShowSysErrorMessage(systemError.ErrorCode); - } - catch(const UString &s) - { - ErrorMessage(s); - return NExitCode::kFatalError; - } - catch(const AString &s) - { - ErrorMessage(s); - return NExitCode::kFatalError; - } - catch(const wchar_t *s) - { - ErrorMessage(s); - return NExitCode::kFatalError; - } - catch(const char *s) - { - ErrorMessage(s); - return NExitCode::kFatalError; - } - catch(int v) - { - AString e ("Error: "); - e.Add_UInt32((unsigned)v); - ErrorMessage(e); - return NExitCode::kFatalError; - } - catch(...) - { - ErrorMessage("Unknown error"); - return NExitCode::kFatalError; - } -} +// GUI.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include "../../../../C/DllSecur.h" +#endif + +#include "../../../Common/MyWindows.h" +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../../../Common/MyInitGuid.h" + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/MyException.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/NtCheck.h" + +#include "../Common/ArchiveCommandLine.h" +#include "../Common/ExitCode.h" + +#include "../FileManager/StringUtils.h" +#include "../FileManager/LangUtils.h" + +#include "BenchmarkDialog.h" +#include "ExtractGUI.h" +#include "HashGUI.h" +#include "UpdateGUI.h" + +#include "ExtractRes.h" + +using namespace NWindows; + +#ifdef Z7_EXTERNAL_CODECS +extern +const CExternalCodecs *g_ExternalCodecs_Ptr; +const CExternalCodecs *g_ExternalCodecs_Ptr; +#endif + +extern +HINSTANCE g_hInstance; +HINSTANCE g_hInstance; +extern +bool g_DisableUserQuestions; +bool g_DisableUserQuestions; + +#ifndef UNDER_CE + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // win2000 +#define Z7_USE_DYN_ComCtl32Version +#endif + +#ifdef Z7_USE_DYN_ComCtl32Version +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +extern +DWORD g_ComCtl32Version; +DWORD g_ComCtl32Version; + +static DWORD GetDllVersion(LPCTSTR dllName) +{ + DWORD dwVersion = 0; + const HMODULE hmodule = LoadLibrary(dllName); + if (hmodule) + { + const + DLLGETVERSIONPROC f_DllGetVersion = Z7_GET_PROC_ADDRESS( + DLLGETVERSIONPROC, hmodule, + "DllGetVersion"); + if (f_DllGetVersion) + { + DLLVERSIONINFO dvi; + ZeroMemory(&dvi, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + const HRESULT hr = (*f_DllGetVersion)(&dvi); + if (SUCCEEDED(hr)) + dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); + } + FreeLibrary(hmodule); + } + return dwVersion; +} + +#endif +#endif + +extern +bool g_LVN_ITEMACTIVATE_Support; +bool g_LVN_ITEMACTIVATE_Support = true; + +DECLARE_AND_SET_CLIENT_VERSION_VAR + +static void ErrorMessage(LPCWSTR message) +{ + if (!g_DisableUserQuestions) + MessageBoxW(NULL, message, L"7-Zip", MB_ICONERROR | MB_OK); +} + +static void ErrorMessage(const char *s) +{ + ErrorMessage(GetUnicodeString(s)); +} + +static void ErrorLangMessage(UINT resourceID) +{ + ErrorMessage(LangString(resourceID)); +} + +static const char * const kNoFormats = "7-Zip cannot find the code that works with archives."; + +static int ShowMemErrorMessage() +{ + ErrorLangMessage(IDS_MEM_ERROR); + return NExitCode::kMemoryError; +} + +static int ShowSysErrorMessage(HRESULT errorCode) +{ + if (errorCode == E_OUTOFMEMORY) + return ShowMemErrorMessage(); + ErrorMessage(HResultToMessage(errorCode)); + return NExitCode::kFatalError; +} + +static void ThrowException_if_Error(HRESULT res) +{ + if (res != S_OK) + throw CSystemException(res); +} + +static int Main2() +{ + UStringVector commandStrings; + NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); + + #ifndef UNDER_CE + if (commandStrings.Size() > 0) + commandStrings.Delete(0); + #endif + if (commandStrings.Size() == 0) + { + MessageBoxW(NULL, L"Specify command", L"7-Zip", 0); + return 0; + } + + CArcCmdLineOptions options; + CArcCmdLineParser parser; + + parser.Parse1(commandStrings, options); + g_DisableUserQuestions = options.YesToAll; + parser.Parse2(options); + + CREATE_CODECS_OBJECT + + codecs->CaseSensitive_Change = options.CaseSensitive_Change; + codecs->CaseSensitive = options.CaseSensitive; + ThrowException_if_Error(codecs->Load()); + Codecs_AddHashArcHandler(codecs); + + #ifdef Z7_EXTERNAL_CODECS + { + g_ExternalCodecs_Ptr = &_externalCodecs; + UString s; + codecs->GetCodecsErrorMessage(s); + if (!s.IsEmpty()) + { + if (!g_DisableUserQuestions) + MessageBoxW(NULL, s, L"7-Zip", MB_ICONERROR); + } + + } + #endif + + const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); + + if (codecs->Formats.Size() == 0 && + (isExtractGroupCommand + + || options.Command.IsFromUpdateGroup())) + { + #ifdef Z7_EXTERNAL_CODECS + if (!codecs->MainDll_ErrorPath.IsEmpty()) + { + UString s ("7-Zip cannot load module: "); + s += fs2us(codecs->MainDll_ErrorPath); + throw s; + } + #endif + throw kNoFormats; + } + + CObjectVector formatIndices; + if (!ParseOpenTypes(*codecs, options.ArcType, formatIndices)) + { + ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); + return NExitCode::kFatalError; + } + + CIntVector excludedFormats; + FOR_VECTOR (k, options.ExcludedArcTypes) + { + CIntVector tempIndices; + if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices) + || tempIndices.Size() != 1) + { + ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE); + return NExitCode::kFatalError; + } + excludedFormats.AddToUniqueSorted(tempIndices[0]); + // excludedFormats.Sort(); + } + + #ifdef Z7_EXTERNAL_CODECS + if (isExtractGroupCommand + || options.Command.IsFromUpdateGroup() + || options.Command.CommandType == NCommandType::kHash + || options.Command.CommandType == NCommandType::kBenchmark) + ThrowException_if_Error(_externalCodecs.Load()); + #endif + + if (options.Command.CommandType == NCommandType::kBenchmark) + { + HRESULT res = Benchmark( + EXTERNAL_CODECS_VARS_L + options.Properties, + options.NumIterations_Defined ? + options.NumIterations : + k_NumBenchIterations_Default); + /* + if (res == S_FALSE) + { + stdStream << "\nDecoding Error\n"; + return NExitCode::kFatalError; + } + */ + ThrowException_if_Error(res); + } + else if (isExtractGroupCommand) + { + UStringVector ArchivePathsSorted; + UStringVector ArchivePathsFullSorted; + + CExtractCallbackImp *ecs = new CExtractCallbackImp; + CMyComPtr extractCallback = ecs; + + #ifndef Z7_NO_CRYPTO + ecs->PasswordIsDefined = options.PasswordEnabled; + ecs->Password = options.Password; + #endif + + ecs->Init(); + + CExtractOptions eo; + (CExtractOptionsBase &)eo = options.ExtractOptions; + eo.StdInMode = options.StdInMode; + eo.StdOutMode = options.StdOutMode; + eo.YesToAll = options.YesToAll; + ecs->YesToAll = options.YesToAll; + eo.TestMode = options.Command.IsTestCommand(); + ecs->TestMode = eo.TestMode; + + #ifndef Z7_SFX + eo.Properties = options.Properties; + #endif + + bool messageWasDisplayed = false; + + #ifndef Z7_SFX + CHashBundle hb; + CHashBundle *hb_ptr = NULL; + + if (!options.HashMethods.IsEmpty()) + { + hb_ptr = &hb; + ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods)); + } + #endif + + { + CDirItemsStat st; + HRESULT hresultMain = EnumerateDirItemsAndSort( + options.arcCensor, + NWildcard::k_RelatPath, + UString(), // addPathPrefix + ArchivePathsSorted, + ArchivePathsFullSorted, + st, + NULL // &scan: change it!!!! + ); + if (hresultMain != S_OK) + { + /* + if (hresultMain != E_ABORT && messageWasDisplayed) + return NExitCode::kFatalError; + */ + throw CSystemException(hresultMain); + } + } + + ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1); + + HRESULT result = ExtractGUI( + // EXTERNAL_CODECS_VARS_L + codecs, + formatIndices, excludedFormats, + ArchivePathsSorted, + ArchivePathsFullSorted, + options.Censor.Pairs.Front().Head, + eo, + #ifndef Z7_SFX + hb_ptr, + #endif + options.ShowDialog, messageWasDisplayed, ecs); + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return NExitCode::kFatalError; + throw CSystemException(result); + } + if (!ecs->IsOK()) + return NExitCode::kFatalError; + } + else if (options.Command.IsFromUpdateGroup()) + { + #ifndef Z7_NO_CRYPTO + bool passwordIsDefined = options.PasswordEnabled && !options.Password.IsEmpty(); + #endif + + CUpdateCallbackGUI callback; + // callback.EnablePercents = options.EnablePercents; + + #ifndef Z7_NO_CRYPTO + callback.PasswordIsDefined = passwordIsDefined; + callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty(); + callback.Password = options.Password; + #endif + + // callback.StdOutMode = options.UpdateOptions.StdOutMode; + callback.Init(); + + if (!options.UpdateOptions.InitFormatIndex(codecs, formatIndices, options.ArchiveName) || + !options.UpdateOptions.SetArcPath(codecs, options.ArchiveName)) + { + ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED); + return NExitCode::kFatalError; + } + bool messageWasDisplayed = false; + HRESULT result = UpdateGUI( + codecs, formatIndices, + options.ArchiveName, + options.Censor, + options.UpdateOptions, + options.ShowDialog, + messageWasDisplayed, + &callback); + + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return NExitCode::kFatalError; + throw CSystemException(result); + } + if (callback.FailedFiles.Size() > 0) + { + if (!messageWasDisplayed) + throw CSystemException(E_FAIL); + return NExitCode::kWarning; + } + } + else if (options.Command.CommandType == NCommandType::kHash) + { + bool messageWasDisplayed = false; + HRESULT result = HashCalcGUI(EXTERNAL_CODECS_VARS_L + options.Censor, options.HashOptions, messageWasDisplayed); + + if (result != S_OK) + { + if (result != E_ABORT && messageWasDisplayed) + return NExitCode::kFatalError; + throw CSystemException(result); + } + /* + if (callback.FailedFiles.Size() > 0) + { + if (!messageWasDisplayed) + throw CSystemException(E_FAIL); + return NExitCode::kWarning; + } + */ + } + else + { + throw "Unsupported command"; + } + return 0; +} + +#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE) +#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return NExitCode::kFatalError; +#endif + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, + #ifdef UNDER_CE + LPWSTR + #else + LPSTR + #endif + /* lpCmdLine */, int /* nCmdShow */) +{ + g_hInstance = hInstance; + + #ifdef _WIN32 + NT_CHECK + #endif + + InitCommonControls(); + +#ifdef Z7_USE_DYN_ComCtl32Version + g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll")); + g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4)); +#endif + + // OleInitialize is required for ProgressBar in TaskBar. + #ifndef UNDER_CE + OleInitialize(NULL); + #endif + + #ifdef Z7_LANG + LoadLangOneTime(); + #endif + + // setlocale(LC_COLLATE, ".ACP"); + try + { + #ifdef _WIN32 + My_SetDefaultDllDirectories(); + #endif + + return Main2(); + } + catch(const CNewException &) + { + return ShowMemErrorMessage(); + } + catch(const CMessagePathException &e) + { + ErrorMessage(e); + return NExitCode::kUserError; + } + catch(const CSystemException &systemError) + { + if (systemError.ErrorCode == E_ABORT) + return NExitCode::kUserBreak; + return ShowSysErrorMessage(systemError.ErrorCode); + } + catch(const UString &s) + { + ErrorMessage(s); + return NExitCode::kFatalError; + } + catch(const AString &s) + { + ErrorMessage(s); + return NExitCode::kFatalError; + } + catch(const wchar_t *s) + { + ErrorMessage(s); + return NExitCode::kFatalError; + } + catch(const char *s) + { + ErrorMessage(s); + return NExitCode::kFatalError; + } + catch(int v) + { + AString e ("Error: "); + e.Add_UInt32((unsigned)v); + ErrorMessage(e); + return NExitCode::kFatalError; + } + catch(...) + { + ErrorMessage("Unknown error"); + return NExitCode::kFatalError; + } +} diff --git a/CPP/7zip/UI/GUI/GUI.dsp b/CPP/7zip/UI/GUI/GUI.dsp index 5e7496d83..1742f26c9 100644 --- a/CPP/7zip/UI/GUI/GUI.dsp +++ b/CPP/7zip/UI/GUI/GUI.dsp @@ -1,1275 +1,1275 @@ -# Microsoft Developer Studio Project File - Name="GUI" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=GUI - Win32 DebugU -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "GUI.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "GUI.mak" CFG="GUI - Win32 DebugU" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "GUI - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "GUI - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE "GUI - Win32 ReleaseU" (based on "Win32 (x86) Application") -!MESSAGE "GUI - Win32 DebugU" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "GUI - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /FAcs /Yu"stdafx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zg.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "GUI - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zg.exe" /pdbtype:sept - -!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "ReleaseU" -# PROP BASE Intermediate_Dir "ReleaseU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "ReleaseU" -# PROP Intermediate_Dir "ReleaseU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "NDEBUG" -# ADD RSC /l 0x419 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zg.exe" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zg.exe" /opt:NOWIN98 -# SUBTRACT LINK32 /pdb:none - -!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "DebugU" -# PROP BASE Intermediate_Dir "DebugU" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "DebugU" -# PROP Intermediate_Dir "DebugU" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x419 /d "_DEBUG" -# ADD RSC /l 0x419 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zg.exe" /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zg.exe" /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "GUI - Win32 Release" -# Name "GUI - Win32 Debug" -# Name "GUI - Win32 ReleaseU" -# Name "GUI - Win32 DebugU" -# Begin Group "Spec" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\7zG.exe.manifest -# End Source File -# Begin Source File - -SOURCE=.\ExtractRes.h -# End Source File -# Begin Source File - -SOURCE=.\FM.ico -# End Source File -# Begin Source File - -SOURCE=.\resource.rc -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"stdafx.h" -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "UI Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Common\ArchiveCommandLine.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveCommandLine.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ArchiveOpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Bench.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\Bench.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\DefaultName.h -# End Source File -# Begin Source File - -SOURCE=..\Common\DirItem.h -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\EnumDirItems.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExitCode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Extract.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\Extract.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractingFilePath.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ExtractMode.h -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\HashCalc.h -# End Source File -# Begin Source File - -SOURCE=..\Common\IFileExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\LoadCodecs.h -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\OpenArchive.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Property.h -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\PropIDUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SetProperties.h -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\SortUtils.h -# End Source File -# Begin Source File - -SOURCE=..\Common\TempFiles.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\TempFiles.h -# End Source File -# Begin Source File - -SOURCE=..\Common\Update.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\Update.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateAction.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateCallback.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdatePair.h -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\UpdateProduce.h -# End Source File -# Begin Source File - -SOURCE=..\Common\WorkDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\WorkDir.h -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.cpp -# End Source File -# Begin Source File - -SOURCE=..\Common\ZipRegistry.h -# End Source File -# End Group -# Begin Group "Explorer" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\Explorer\MyMessages.cpp -# End Source File -# Begin Source File - -SOURCE=..\Explorer\MyMessages.h -# End Source File -# End Group -# Begin Group "Dialogs" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\BenchmarkDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\BenchmarkDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\BrowseDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\BrowseDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ComboDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ComboDialog.h -# End Source File -# Begin Source File - -SOURCE=.\CompressDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\CompressDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\EditDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\EditDialog.h -# End Source File -# Begin Source File - -SOURCE=.\ExtractDialog.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ListViewDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ListViewDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\MemDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\MemDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\OverwriteDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\OverwriteDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\PasswordDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\PasswordDialog.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgressDialog2.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgressDialog2.h -# End Source File -# End Group -# Begin Group "FM Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\FileManager\ExtractCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ExtractCallback.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\FormatUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\FormatUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\HelpUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\HelpUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\LangUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\LangUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\OpenCallback.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\OpenCallback.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgramLocation.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\ProgramLocation.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\PropertyName.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\PropertyName.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\RegistryUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\RegistryUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\SplitUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\SplitUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\StringUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\StringUtils.h -# End Source File -# Begin Source File - -SOURCE=..\FileManager\SysIconUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\FileManager\SysIconUtils.h -# End Source File -# End Group -# Begin Group "Engine" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\ExtractGUI.cpp -# End Source File -# Begin Source File - -SOURCE=.\ExtractGUI.h -# End Source File -# Begin Source File - -SOURCE=.\GUI.cpp -# End Source File -# Begin Source File - -SOURCE=.\HashGUI.cpp -# End Source File -# Begin Source File - -SOURCE=.\HashGUI.h -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackGUI.cpp -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackGUI.h -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackGUI2.cpp -# End Source File -# Begin Source File - -SOURCE=.\UpdateCallbackGUI2.h -# End Source File -# Begin Source File - -SOURCE=.\UpdateGUI.cpp -# End Source File -# Begin Source File - -SOURCE=.\UpdateGUI.h -# End Source File -# End Group -# Begin Group "7-zip Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\CreateCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilePathAutoRename.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FileStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\FilterCoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\LimitedStreams.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MethodProps.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\MultiOutStream.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\ProgressUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\PropId.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamObjects.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\StreamUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Common\UniqBlocks.h -# End Source File -# End Group -# Begin Group "Compress" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Compress\CopyCoder.h -# End Source File -# End Group -# Begin Group "C" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.c - -!IF "$(CFG)" == "GUI - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zCrcOpt.c - -!IF "$(CFG)" == "GUI - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zTypes.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zVersion.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\7zWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Alloc.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Compiler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.c - -!IF "$(CFG)" == "GUI - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\CpuArch.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\DllSecur.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Precomp.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.c - -!IF "$(CFG)" == "GUI - Win32 Release" - -# ADD CPP /O2 -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 Debug" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" - -# SUBTRACT CPP /YX /Yc /Yu - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Sort.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.c -# SUBTRACT CPP /YX /Yc /Yu -# End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Threads.h -# End Source File -# End Group -# Begin Group "Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CommandLineParser.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Common.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\CRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\DynLimBuf.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\IntToString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Lang.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\ListFileUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyBuffer.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyVector.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\MyWindows.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\NewHandler.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\StringToInt.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\UTFConvert.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Common\Wildcard.h -# End Source File -# End Group -# Begin Group "Windows" - -# PROP Default_Filter "" -# Begin Group "Control" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ComboBox.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Dialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Edit.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ListView.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\ProgressBar.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Control\Static.h -# End Source File -# End Group -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Clipboard.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\COM.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\CommonDialog.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\DLL.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ErrorMsg.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileDir.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileFind.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileIO.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileLink.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileMapping.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileName.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\FileSystem.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryGlobal.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\MemoryLock.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariant.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\PropVariantConv.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Registry.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\ResourceString.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Shell.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Synchronization.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\System.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\SystemInfo.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Thread.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\TimeUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\..\Windows\Window.h -# End Source File -# End Group -# Begin Group "Archive Common" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\ItemNameUtils.h -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp -# End Source File -# Begin Source File - -SOURCE=..\..\Archive\Common\OutStreamWithCRC.h -# End Source File -# End Group -# Begin Group "7-Zip" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\Archive\IArchive.h -# End Source File -# Begin Source File - -SOURCE=..\..\ICoder.h -# End Source File -# Begin Source File - -SOURCE=..\..\IDecl.h -# End Source File -# Begin Source File - -SOURCE=..\..\IStream.h -# End Source File -# End Group -# End Target -# End Project +# Microsoft Developer Studio Project File - Name="GUI" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=GUI - Win32 DebugU +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "GUI.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "GUI.mak" CFG="GUI - Win32 DebugU" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "GUI - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "GUI - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "GUI - Win32 ReleaseU" (based on "Win32 (x86) Application") +!MESSAGE "GUI - Win32 DebugU" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "GUI - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /FAcs /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zg.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "GUI - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zg.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zg.exe" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zg.exe" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zg.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zg.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "GUI - Win32 Release" +# Name "GUI - Win32 Debug" +# Name "GUI - Win32 ReleaseU" +# Name "GUI - Win32 DebugU" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\7zG.exe.manifest +# End Source File +# Begin Source File + +SOURCE=.\ExtractRes.h +# End Source File +# Begin Source File + +SOURCE=.\FM.ico +# End Source File +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Common\ArchiveCommandLine.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveCommandLine.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Bench.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\Bench.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\Common\DirItem.h +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\EnumDirItems.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExitCode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Extract.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\Extract.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractingFilePath.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\HashCalc.h +# End Source File +# Begin Source File + +SOURCE=..\Common\IFileExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\LoadCodecs.h +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\OpenArchive.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Property.h +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\PropIDUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SetProperties.h +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\SortUtils.h +# End Source File +# Begin Source File + +SOURCE=..\Common\TempFiles.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\TempFiles.h +# End Source File +# Begin Source File + +SOURCE=..\Common\Update.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\Update.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateAction.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateCallback.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdatePair.h +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\UpdateProduce.h +# End Source File +# Begin Source File + +SOURCE=..\Common\WorkDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\WorkDir.h +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.cpp +# End Source File +# Begin Source File + +SOURCE=..\Common\ZipRegistry.h +# End Source File +# End Group +# Begin Group "Explorer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\Explorer\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=..\Explorer\MyMessages.h +# End Source File +# End Group +# Begin Group "Dialogs" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\BenchmarkDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\BenchmarkDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\BrowseDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\BrowseDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ComboDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ComboDialog.h +# End Source File +# Begin Source File + +SOURCE=.\CompressDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\CompressDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\EditDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\EditDialog.h +# End Source File +# Begin Source File + +SOURCE=.\ExtractDialog.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ListViewDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ListViewDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\MemDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\MemDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\OverwriteDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\OverwriteDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PasswordDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PasswordDialog.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgressDialog2.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgressDialog2.h +# End Source File +# End Group +# Begin Group "FM Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\FileManager\ExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\FormatUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\HelpUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\HelpUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\LangUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\LangUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\OpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\OpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgramLocation.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\ProgramLocation.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PropertyName.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\PropertyName.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\RegistryUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\RegistryUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\SplitUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\SplitUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\StringUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\StringUtils.h +# End Source File +# Begin Source File + +SOURCE=..\FileManager\SysIconUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\FileManager\SysIconUtils.h +# End Source File +# End Group +# Begin Group "Engine" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ExtractGUI.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractGUI.h +# End Source File +# Begin Source File + +SOURCE=.\GUI.cpp +# End Source File +# Begin Source File + +SOURCE=.\HashGUI.cpp +# End Source File +# Begin Source File + +SOURCE=.\HashGUI.h +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackGUI.cpp +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackGUI.h +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackGUI2.cpp +# End Source File +# Begin Source File + +SOURCE=.\UpdateCallbackGUI2.h +# End Source File +# Begin Source File + +SOURCE=.\UpdateGUI.cpp +# End Source File +# Begin Source File + +SOURCE=.\UpdateGUI.h +# End Source File +# End Group +# Begin Group "7-zip Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\CreateCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilePathAutoRename.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MethodProps.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\MultiOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\PropId.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\UniqBlocks.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\CopyCoder.h +# End Source File +# End Group +# Begin Group "C" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.c + +!IF "$(CFG)" == "GUI - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zCrcOpt.c + +!IF "$(CFG)" == "GUI - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zVersion.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\7zWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Compiler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.c + +!IF "$(CFG)" == "GUI - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\DllSecur.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Precomp.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.c + +!IF "$(CFG)" == "GUI - Win32 Release" + +# ADD CPP /O2 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 Debug" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "GUI - Win32 DebugU" + +# SUBTRACT CPP /YX /Yc /Yu + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Sort.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.c +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\C\Threads.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Common.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\DynLimBuf.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Lang.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\ListFileUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyVector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\MyWindows.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringToInt.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ComboBox.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Edit.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ListView.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\ProgressBar.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Static.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Clipboard.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\COM.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\CommonDialog.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ErrorMsg.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileLink.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileMapping.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileSystem.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryGlobal.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\MemoryLock.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Registry.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Shell.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\System.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\SystemInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Thread.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\TimeUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "7-Zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\IDecl.h +# End Source File +# Begin Source File + +SOURCE=..\..\IStream.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CPP/7zip/UI/GUI/GUI.dsw b/CPP/7zip/UI/GUI/GUI.dsw index 465622e44..85d33484b 100644 --- a/CPP/7zip/UI/GUI/GUI.dsw +++ b/CPP/7zip/UI/GUI/GUI.dsw @@ -1,29 +1,29 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "GUI"=.\GUI.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "GUI"=.\GUI.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CPP/7zip/UI/GUI/HashGUI.cpp b/CPP/7zip/UI/GUI/HashGUI.cpp index 1cb903984..231bab587 100644 --- a/CPP/7zip/UI/GUI/HashGUI.cpp +++ b/CPP/7zip/UI/GUI/HashGUI.cpp @@ -1,341 +1,341 @@ -// HashGUI.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/ErrorMsg.h" - -#include "../FileManager/FormatUtils.h" -#include "../FileManager/LangUtils.h" -#include "../FileManager/ListViewDialog.h" -#include "../FileManager/OverwriteDialogRes.h" -#include "../FileManager/ProgressDialog2.h" -#include "../FileManager/ProgressDialog2Res.h" -#include "../FileManager/PropertyNameRes.h" -#include "../FileManager/resourceGui.h" - -#include "HashGUI.h" - -using namespace NWindows; - - - -class CHashCallbackGUI Z7_final: public CProgressThreadVirt, public IHashCallbackUI -{ - UInt64 NumFiles; - bool _curIsFolder; - UString FirstFileName; - // UString MainPath; - - CPropNameValPairs PropNameValPairs; - - HRESULT ProcessVirt() Z7_override; - virtual void ProcessWasFinished_GuiVirt() Z7_override; - -public: - const NWildcard::CCensor *censor; - const CHashOptions *options; - - DECL_EXTERNAL_CODECS_LOC_VARS_DECL - - Z7_IFACE_IMP(IDirItemsCallback) - Z7_IFACE_IMP(IHashCallbackUI) - - /* - void AddErrorMessage(DWORD systemError, const wchar_t *name) - { - Sync.AddError_Code_Name(systemError, name); - } - */ - void AddErrorMessage(HRESULT systemError, const wchar_t *name) - { - Sync.AddError_Code_Name(systemError, name); - } -}; - - -void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value) -{ - CProperty &pair = pairs.AddNew(); - AddLangString(pair.Name, resourceID); - char sz[32]; - ConvertUInt64ToString(value, sz); - pair.Value = sz; -} - - -void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value) -{ - CProperty &pair = pairs.AddNew(); - LangString(resourceID, pair.Name); - AddSizeValue(pair.Value, value); -} - - -HRESULT CHashCallbackGUI::StartScanning() -{ - CProgressSync &sync = Sync; - sync.Set_Status(LangString(IDS_SCANNING)); - return CheckBreak(); -} - -HRESULT CHashCallbackGUI::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) -{ - return Sync.ScanProgress(st.NumFiles, st.GetTotalBytes(), path, isDir); -} - -HRESULT CHashCallbackGUI::ScanError(const FString &path, DWORD systemError) -{ - AddErrorMessage(HRESULT_FROM_WIN32(systemError), fs2us(path)); - return CheckBreak(); -} - -HRESULT CHashCallbackGUI::FinishScanning(const CDirItemsStat &st) -{ - return ScanProgress(st, FString(), false); // isDir -} - -HRESULT CHashCallbackGUI::CheckBreak() -{ - return Sync.CheckStop(); -} - -HRESULT CHashCallbackGUI::SetNumFiles(UInt64 numFiles) -{ - CProgressSync &sync = Sync; - sync.Set_NumFilesTotal(numFiles); - return CheckBreak(); -} - -HRESULT CHashCallbackGUI::SetTotal(UInt64 size) -{ - CProgressSync &sync = Sync; - sync.Set_NumBytesTotal(size); - return CheckBreak(); -} - -HRESULT CHashCallbackGUI::SetCompleted(const UInt64 *completed) -{ - return Sync.Set_NumBytesCur(completed); -} - -HRESULT CHashCallbackGUI::BeforeFirstFile(const CHashBundle & /* hb */) -{ - return S_OK; -} - -HRESULT CHashCallbackGUI::GetStream(const wchar_t *name, bool isFolder) -{ - if (NumFiles == 0) - FirstFileName = name; - _curIsFolder = isFolder; - CProgressSync &sync = Sync; - sync.Set_FilePath(name, isFolder); - return CheckBreak(); -} - -HRESULT CHashCallbackGUI::OpenFileError(const FString &path, DWORD systemError) -{ - // if (systemError == ERROR_SHARING_VIOLATION) - { - AddErrorMessage(HRESULT_FROM_WIN32(systemError), fs2us(path)); - return S_FALSE; - } - // return systemError; -} - -HRESULT CHashCallbackGUI::SetOperationResult(UInt64 /* fileSize */, const CHashBundle & /* hb */, bool /* showHash */) -{ - CProgressSync &sync = Sync; - if (!_curIsFolder) - NumFiles++; - sync.Set_NumFilesCur(NumFiles); - return CheckBreak(); -} - -static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16; - -static void AddHashString(CProperty &s, const CHasherState &h, unsigned digestIndex) -{ - char temp[k_DigestStringSize]; - h.WriteToString(digestIndex, temp); - s.Value = temp; -} - -static void AddHashResString(CPropNameValPairs &s, const CHasherState &h, unsigned digestIndex, UInt32 resID) -{ - CProperty &pair = s.AddNew(); - UString &s2 = pair.Name; - LangString(resID, s2); - UString name (h.Name); - s2.Replace(L"CRC", name); - s2.Replace(L":", L""); - AddHashString(pair, h, digestIndex); -} - - -void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb) -{ - if (hb.NumErrors != 0) - AddValuePair(s, IDS_PROP_NUM_ERRORS, hb.NumErrors); - - if (hb.NumFiles == 1 && hb.NumDirs == 0 && !hb.FirstFileName.IsEmpty()) - { - CProperty &pair = s.AddNew(); - LangString(IDS_PROP_NAME, pair.Name); - pair.Value = hb.FirstFileName; - } - else - { - if (!hb.MainName.IsEmpty()) - { - CProperty &pair = s.AddNew(); - LangString(IDS_PROP_NAME, pair.Name); - pair.Value = hb.MainName; - } - if (hb.NumDirs != 0) - AddValuePair(s, IDS_PROP_FOLDERS, hb.NumDirs); - AddValuePair(s, IDS_PROP_FILES, hb.NumFiles); - } - - AddSizeValuePair(s, IDS_PROP_SIZE, hb.FilesSize); - - if (hb.NumAltStreams != 0) - { - AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, hb.NumAltStreams); - AddSizeValuePair(s, IDS_PROP_ALT_STREAMS_SIZE, hb.AltStreamsSize); - } - - FOR_VECTOR (i, hb.Hashers) - { - const CHasherState &h = hb.Hashers[i]; - if (hb.NumFiles == 1 && hb.NumDirs == 0) - { - CProperty &pair = s.AddNew(); - pair.Name += h.Name; - AddHashString(pair, h, k_HashCalc_Index_DataSum); - } - else - { - AddHashResString(s, h, k_HashCalc_Index_DataSum, IDS_CHECKSUM_CRC_DATA); - AddHashResString(s, h, k_HashCalc_Index_NamesSum, IDS_CHECKSUM_CRC_DATA_NAMES); - } - if (hb.NumAltStreams != 0) - { - AddHashResString(s, h, k_HashCalc_Index_StreamsSum, IDS_CHECKSUM_CRC_STREAMS_NAMES); - } - } -} - - -void AddHashBundleRes(UString &s, const CHashBundle &hb) -{ - CPropNameValPairs pairs; - AddHashBundleRes(pairs, hb); - - FOR_VECTOR (i, pairs) - { - const CProperty &pair = pairs[i]; - s += pair.Name; - s += ": "; - s += pair.Value; - s.Add_LF(); - } - - if (hb.NumErrors == 0 && hb.Hashers.IsEmpty()) - { - s.Add_LF(); - AddLangString(s, IDS_MESSAGE_NO_ERRORS); - s.Add_LF(); - } -} - - -HRESULT CHashCallbackGUI::AfterLastFile(CHashBundle &hb) -{ - hb.FirstFileName = FirstFileName; - // MainPath - AddHashBundleRes(PropNameValPairs, hb); - - CProgressSync &sync = Sync; - sync.Set_NumFilesCur(hb.NumFiles); - - // CProgressMessageBoxPair &pair = GetMessagePair(hb.NumErrors != 0); - // pair.Message = s; - // LangString(IDS_CHECKSUM_INFORMATION, pair.Title); - - return S_OK; -} - - -HRESULT CHashCallbackGUI::ProcessVirt() -{ - NumFiles = 0; - AString errorInfo; - HRESULT res = HashCalc(EXTERNAL_CODECS_LOC_VARS - *censor, *options, errorInfo, this); - return res; -} - - -HRESULT HashCalcGUI( - DECL_EXTERNAL_CODECS_LOC_VARS - const NWildcard::CCensor &censor, - const CHashOptions &options, - bool &messageWasDisplayed) -{ - CHashCallbackGUI t; - #ifdef Z7_EXTERNAL_CODECS - t._externalCodecs = _externalCodecs; - #endif - t.censor = &censor; - t.options = &options; - - t.ShowCompressionInfo = false; - - const UString title = LangString(IDS_CHECKSUM_CALCULATING); - - t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); - t.MainAddTitle = title; - t.MainAddTitle.Add_Space(); - - RINOK(t.Create(title)) - messageWasDisplayed = t.ThreadFinishedOK && t.MessagesDisplayed; - return S_OK; -} - - -void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd) -{ - CListViewDialog lv; - - FOR_VECTOR (i, propPairs) - { - const CProperty &pair = propPairs[i]; - lv.Strings.Add(pair.Name); - lv.Values.Add(pair.Value); - } - - lv.Title = LangString(IDS_CHECKSUM_INFORMATION); - lv.DeleteIsAllowed = true; - lv.SelectFirst = false; - lv.NumColumns = 2; - - lv.Create(hwnd); -} - - -void ShowHashResults(const CHashBundle &hb, HWND hwnd) -{ - CPropNameValPairs propPairs; - AddHashBundleRes(propPairs, hb); - ShowHashResults(propPairs, hwnd); -} - -void CHashCallbackGUI::ProcessWasFinished_GuiVirt() -{ - if (Result != E_ABORT) - ShowHashResults(PropNameValPairs, *this); -} +// HashGUI.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/ErrorMsg.h" + +#include "../FileManager/FormatUtils.h" +#include "../FileManager/LangUtils.h" +#include "../FileManager/ListViewDialog.h" +#include "../FileManager/OverwriteDialogRes.h" +#include "../FileManager/ProgressDialog2.h" +#include "../FileManager/ProgressDialog2Res.h" +#include "../FileManager/PropertyNameRes.h" +#include "../FileManager/resourceGui.h" + +#include "HashGUI.h" + +using namespace NWindows; + + + +class CHashCallbackGUI Z7_final: public CProgressThreadVirt, public IHashCallbackUI +{ + UInt64 NumFiles; + bool _curIsFolder; + UString FirstFileName; + // UString MainPath; + + CPropNameValPairs PropNameValPairs; + + HRESULT ProcessVirt() Z7_override; + virtual void ProcessWasFinished_GuiVirt() Z7_override; + +public: + const NWildcard::CCensor *censor; + const CHashOptions *options; + + DECL_EXTERNAL_CODECS_LOC_VARS_DECL + + Z7_IFACE_IMP(IDirItemsCallback) + Z7_IFACE_IMP(IHashCallbackUI) + + /* + void AddErrorMessage(DWORD systemError, const wchar_t *name) + { + Sync.AddError_Code_Name(systemError, name); + } + */ + void AddErrorMessage(HRESULT systemError, const wchar_t *name) + { + Sync.AddError_Code_Name(systemError, name); + } +}; + + +void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value) +{ + CProperty &pair = pairs.AddNew(); + AddLangString(pair.Name, resourceID); + char sz[32]; + ConvertUInt64ToString(value, sz); + pair.Value = sz; +} + + +void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value) +{ + CProperty &pair = pairs.AddNew(); + LangString(resourceID, pair.Name); + AddSizeValue(pair.Value, value); +} + + +HRESULT CHashCallbackGUI::StartScanning() +{ + CProgressSync &sync = Sync; + sync.Set_Status(LangString(IDS_SCANNING)); + return CheckBreak(); +} + +HRESULT CHashCallbackGUI::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) +{ + return Sync.ScanProgress(st.NumFiles, st.GetTotalBytes(), path, isDir); +} + +HRESULT CHashCallbackGUI::ScanError(const FString &path, DWORD systemError) +{ + AddErrorMessage(HRESULT_FROM_WIN32(systemError), fs2us(path)); + return CheckBreak(); +} + +HRESULT CHashCallbackGUI::FinishScanning(const CDirItemsStat &st) +{ + return ScanProgress(st, FString(), false); // isDir +} + +HRESULT CHashCallbackGUI::CheckBreak() +{ + return Sync.CheckStop(); +} + +HRESULT CHashCallbackGUI::SetNumFiles(UInt64 numFiles) +{ + CProgressSync &sync = Sync; + sync.Set_NumFilesTotal(numFiles); + return CheckBreak(); +} + +HRESULT CHashCallbackGUI::SetTotal(UInt64 size) +{ + CProgressSync &sync = Sync; + sync.Set_NumBytesTotal(size); + return CheckBreak(); +} + +HRESULT CHashCallbackGUI::SetCompleted(const UInt64 *completed) +{ + return Sync.Set_NumBytesCur(completed); +} + +HRESULT CHashCallbackGUI::BeforeFirstFile(const CHashBundle & /* hb */) +{ + return S_OK; +} + +HRESULT CHashCallbackGUI::GetStream(const wchar_t *name, bool isFolder) +{ + if (NumFiles == 0) + FirstFileName = name; + _curIsFolder = isFolder; + CProgressSync &sync = Sync; + sync.Set_FilePath(name, isFolder); + return CheckBreak(); +} + +HRESULT CHashCallbackGUI::OpenFileError(const FString &path, DWORD systemError) +{ + // if (systemError == ERROR_SHARING_VIOLATION) + { + AddErrorMessage(HRESULT_FROM_WIN32(systemError), fs2us(path)); + return S_FALSE; + } + // return systemError; +} + +HRESULT CHashCallbackGUI::SetOperationResult(UInt64 /* fileSize */, const CHashBundle & /* hb */, bool /* showHash */) +{ + CProgressSync &sync = Sync; + if (!_curIsFolder) + NumFiles++; + sync.Set_NumFilesCur(NumFiles); + return CheckBreak(); +} + +static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16; + +static void AddHashString(CProperty &s, const CHasherState &h, unsigned digestIndex) +{ + char temp[k_DigestStringSize]; + h.WriteToString(digestIndex, temp); + s.Value = temp; +} + +static void AddHashResString(CPropNameValPairs &s, const CHasherState &h, unsigned digestIndex, UInt32 resID) +{ + CProperty &pair = s.AddNew(); + UString &s2 = pair.Name; + LangString(resID, s2); + UString name (h.Name); + s2.Replace(L"CRC", name); + s2.Replace(L":", L""); + AddHashString(pair, h, digestIndex); +} + + +void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb) +{ + if (hb.NumErrors != 0) + AddValuePair(s, IDS_PROP_NUM_ERRORS, hb.NumErrors); + + if (hb.NumFiles == 1 && hb.NumDirs == 0 && !hb.FirstFileName.IsEmpty()) + { + CProperty &pair = s.AddNew(); + LangString(IDS_PROP_NAME, pair.Name); + pair.Value = hb.FirstFileName; + } + else + { + if (!hb.MainName.IsEmpty()) + { + CProperty &pair = s.AddNew(); + LangString(IDS_PROP_NAME, pair.Name); + pair.Value = hb.MainName; + } + if (hb.NumDirs != 0) + AddValuePair(s, IDS_PROP_FOLDERS, hb.NumDirs); + AddValuePair(s, IDS_PROP_FILES, hb.NumFiles); + } + + AddSizeValuePair(s, IDS_PROP_SIZE, hb.FilesSize); + + if (hb.NumAltStreams != 0) + { + AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, hb.NumAltStreams); + AddSizeValuePair(s, IDS_PROP_ALT_STREAMS_SIZE, hb.AltStreamsSize); + } + + FOR_VECTOR (i, hb.Hashers) + { + const CHasherState &h = hb.Hashers[i]; + if (hb.NumFiles == 1 && hb.NumDirs == 0) + { + CProperty &pair = s.AddNew(); + pair.Name += h.Name; + AddHashString(pair, h, k_HashCalc_Index_DataSum); + } + else + { + AddHashResString(s, h, k_HashCalc_Index_DataSum, IDS_CHECKSUM_CRC_DATA); + AddHashResString(s, h, k_HashCalc_Index_NamesSum, IDS_CHECKSUM_CRC_DATA_NAMES); + } + if (hb.NumAltStreams != 0) + { + AddHashResString(s, h, k_HashCalc_Index_StreamsSum, IDS_CHECKSUM_CRC_STREAMS_NAMES); + } + } +} + + +void AddHashBundleRes(UString &s, const CHashBundle &hb) +{ + CPropNameValPairs pairs; + AddHashBundleRes(pairs, hb); + + FOR_VECTOR (i, pairs) + { + const CProperty &pair = pairs[i]; + s += pair.Name; + s += ": "; + s += pair.Value; + s.Add_LF(); + } + + if (hb.NumErrors == 0 && hb.Hashers.IsEmpty()) + { + s.Add_LF(); + AddLangString(s, IDS_MESSAGE_NO_ERRORS); + s.Add_LF(); + } +} + + +HRESULT CHashCallbackGUI::AfterLastFile(CHashBundle &hb) +{ + hb.FirstFileName = FirstFileName; + // MainPath + AddHashBundleRes(PropNameValPairs, hb); + + CProgressSync &sync = Sync; + sync.Set_NumFilesCur(hb.NumFiles); + + // CProgressMessageBoxPair &pair = GetMessagePair(hb.NumErrors != 0); + // pair.Message = s; + // LangString(IDS_CHECKSUM_INFORMATION, pair.Title); + + return S_OK; +} + + +HRESULT CHashCallbackGUI::ProcessVirt() +{ + NumFiles = 0; + AString errorInfo; + HRESULT res = HashCalc(EXTERNAL_CODECS_LOC_VARS + *censor, *options, errorInfo, this); + return res; +} + + +HRESULT HashCalcGUI( + DECL_EXTERNAL_CODECS_LOC_VARS + const NWildcard::CCensor &censor, + const CHashOptions &options, + bool &messageWasDisplayed) +{ + CHashCallbackGUI t; + #ifdef Z7_EXTERNAL_CODECS + t._externalCodecs = _externalCodecs; + #endif + t.censor = &censor; + t.options = &options; + + t.ShowCompressionInfo = false; + + const UString title = LangString(IDS_CHECKSUM_CALCULATING); + + t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE); + t.MainAddTitle = title; + t.MainAddTitle.Add_Space(); + + RINOK(t.Create(title)) + messageWasDisplayed = t.ThreadFinishedOK && t.MessagesDisplayed; + return S_OK; +} + + +void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd) +{ + CListViewDialog lv; + + FOR_VECTOR (i, propPairs) + { + const CProperty &pair = propPairs[i]; + lv.Strings.Add(pair.Name); + lv.Values.Add(pair.Value); + } + + lv.Title = LangString(IDS_CHECKSUM_INFORMATION); + lv.DeleteIsAllowed = true; + lv.SelectFirst = false; + lv.NumColumns = 2; + + lv.Create(hwnd); +} + + +void ShowHashResults(const CHashBundle &hb, HWND hwnd) +{ + CPropNameValPairs propPairs; + AddHashBundleRes(propPairs, hb); + ShowHashResults(propPairs, hwnd); +} + +void CHashCallbackGUI::ProcessWasFinished_GuiVirt() +{ + if (Result != E_ABORT) + ShowHashResults(PropNameValPairs, *this); +} diff --git a/CPP/7zip/UI/GUI/HashGUI.h b/CPP/7zip/UI/GUI/HashGUI.h index f35993c03..1ec9c4756 100644 --- a/CPP/7zip/UI/GUI/HashGUI.h +++ b/CPP/7zip/UI/GUI/HashGUI.h @@ -1,27 +1,27 @@ -// HashGUI.h - -#ifndef ZIP7_INC_HASH_GUI_H -#define ZIP7_INC_HASH_GUI_H - -#include "../Common/HashCalc.h" -#include "../Common/Property.h" - -HRESULT HashCalcGUI( - DECL_EXTERNAL_CODECS_LOC_VARS - const NWildcard::CCensor &censor, - const CHashOptions &options, - bool &messageWasDisplayed); - -typedef CObjectVector CPropNameValPairs; - -void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value); -void AddSizeValue(UString &s, UInt64 value); -void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value); - -void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb); -void AddHashBundleRes(UString &s, const CHashBundle &hb); - -void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd); -void ShowHashResults(const CHashBundle &hb, HWND hwnd); - -#endif +// HashGUI.h + +#ifndef ZIP7_INC_HASH_GUI_H +#define ZIP7_INC_HASH_GUI_H + +#include "../Common/HashCalc.h" +#include "../Common/Property.h" + +HRESULT HashCalcGUI( + DECL_EXTERNAL_CODECS_LOC_VARS + const NWildcard::CCensor &censor, + const CHashOptions &options, + bool &messageWasDisplayed); + +typedef CObjectVector CPropNameValPairs; + +void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value); +void AddSizeValue(UString &s, UInt64 value); +void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value); + +void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb); +void AddHashBundleRes(UString &s, const CHashBundle &hb); + +void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd); +void ShowHashResults(const CHashBundle &hb, HWND hwnd); + +#endif diff --git a/CPP/7zip/UI/GUI/StdAfx.cpp b/CPP/7zip/UI/GUI/StdAfx.cpp index c6d3b1fa6..d0feea85c 100644 --- a/CPP/7zip/UI/GUI/StdAfx.cpp +++ b/CPP/7zip/UI/GUI/StdAfx.cpp @@ -1,3 +1,3 @@ -// StdAfx.cpp - -#include "StdAfx.h" +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/CPP/7zip/UI/GUI/StdAfx.h b/CPP/7zip/UI/GUI/StdAfx.h index 6c2379d6f..130db8aab 100644 --- a/CPP/7zip/UI/GUI/StdAfx.h +++ b/CPP/7zip/UI/GUI/StdAfx.h @@ -1,6 +1,6 @@ -// StdAfx.h - -#if _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../FileManager/StdAfx.h" +// StdAfx.h + +#if _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../FileManager/StdAfx.h" diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp index f674a6a47..424c6e49b 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp @@ -1,280 +1,295 @@ -// UpdateCallbackGUI.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" - -#include "../../../Windows/PropVariant.h" - -#include "../FileManager/FormatUtils.h" -#include "../FileManager/LangUtils.h" - -#include "../FileManager/resourceGui.h" - -#include "resource2.h" - -#include "UpdateCallbackGUI.h" - -using namespace NWindows; - -// CUpdateCallbackGUI::~CUpdateCallbackGUI() {} - -void CUpdateCallbackGUI::Init() -{ - CUpdateCallbackGUI2::Init(); - FailedFiles.Clear(); -} - -void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result); - -HRESULT CUpdateCallbackGUI::OpenResult( - const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) -{ - UString s; - OpenResult_GUI(s, codecs, arcLink, name, result); - if (!s.IsEmpty()) - { - ProgressDialog->Sync.AddError_Message(s); - } - - return S_OK; -} - -HRESULT CUpdateCallbackGUI::StartScanning() -{ - CProgressSync &sync = ProgressDialog->Sync; - sync.Set_Status(LangString(IDS_SCANNING)); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::ScanError(const FString &path, DWORD systemError) -{ - FailedFiles.Add(path); - ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path)); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::FinishScanning(const CDirItemsStat &st) -{ - CProgressSync &sync = ProgressDialog->Sync; - RINOK(ProgressDialog->Sync.ScanProgress(st.NumFiles + st.NumAltStreams, - st.GetTotalBytes(), FString(), true)) - sync.Set_Status(L""); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::StartArchive(const wchar_t *name, bool /* updating */) -{ - CProgressSync &sync = ProgressDialog->Sync; - sync.Set_Status(LangString(IDS_PROGRESS_COMPRESSING)); - sync.Set_TitleFileName(name); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::FinishArchive(const CFinishArchiveStat & /* st */) -{ - CProgressSync &sync = ProgressDialog->Sync; - sync.Set_Status(L""); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::CheckBreak() -{ - return ProgressDialog->Sync.CheckStop(); -} - -HRESULT CUpdateCallbackGUI::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) -{ - return ProgressDialog->Sync.ScanProgress(st.NumFiles + st.NumAltStreams, - st.GetTotalBytes(), path, isDir); -} - -/* -HRESULT CUpdateCallbackGUI::Finalize() -{ - return S_OK; -} -*/ - -HRESULT CUpdateCallbackGUI::SetNumItems(const CArcToDoStat &stat) -{ - ProgressDialog->Sync.Set_NumFilesTotal(stat.Get_NumDataItems_Total()); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::SetTotal(UInt64 total) -{ - ProgressDialog->Sync.Set_NumBytesTotal(total); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::SetCompleted(const UInt64 *completed) -{ - return ProgressDialog->Sync.Set_NumBytesCur(completed); -} - -HRESULT CUpdateCallbackGUI::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - ProgressDialog->Sync.Set_Ratio(inSize, outSize); - return CheckBreak(); -} - -HRESULT CUpdateCallbackGUI::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode) -{ - return SetOperation_Base(mode, name, isDir); -} - -HRESULT CUpdateCallbackGUI::OpenFileError(const FString &path, DWORD systemError) -{ - FailedFiles.Add(path); - // if (systemError == ERROR_SHARING_VIOLATION) - { - ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path)); - return S_FALSE; - } - // return systemError; -} - -HRESULT CUpdateCallbackGUI::SetOperationResult(Int32 /* operationResult */) -{ - NumFiles++; - ProgressDialog->Sync.Set_NumFilesCur(NumFiles); - return S_OK; -} - -void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); - -HRESULT CUpdateCallbackGUI::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) -{ - if (opRes != NArchive::NExtract::NOperationResult::kOK) - { - UString s; - SetExtractErrorMessage(opRes, isEncrypted, name, s); - ProgressDialog->Sync.AddError_Message(s); - } - return S_OK; -} - -HRESULT CUpdateCallbackGUI::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) -{ - return SetOperation_Base(op, name, isDir); -} - -HRESULT CUpdateCallbackGUI::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) -{ - *password = NULL; - if (passwordIsDefined) - *passwordIsDefined = BoolToInt(PasswordIsDefined); - if (!PasswordIsDefined) - { - if (AskPassword) - { - RINOK(ShowAskPasswordDialog()) - } - } - if (passwordIsDefined) - *passwordIsDefined = BoolToInt(PasswordIsDefined); - return StringToBstr(Password, password); -} - -HRESULT CUpdateCallbackGUI::CryptoGetTextPassword(BSTR *password) -{ - return CryptoGetTextPassword2(NULL, password); -} - -/* -It doesn't work, since main stream waits Dialog -HRESULT CUpdateCallbackGUI::CloseProgress() -{ - ProgressDialog->MyClose(); - return S_OK; -} -*/ - - -HRESULT CUpdateCallbackGUI::Open_CheckBreak() -{ - return ProgressDialog->Sync.CheckStop(); -} - -HRESULT CUpdateCallbackGUI::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) -{ - // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) -{ - return ProgressDialog->Sync.CheckStop(); -} - -#ifndef Z7_NO_CRYPTO - -HRESULT CUpdateCallbackGUI::Open_CryptoGetTextPassword(BSTR *password) -{ - PasswordWasAsked = true; - return CryptoGetTextPassword2(NULL, password); -} - -/* -HRESULT CUpdateCallbackGUI::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) -{ - passwordIsDefined = PasswordIsDefined; - password = Password; - return S_OK; -} - -bool CUpdateCallbackGUI::Open_WasPasswordAsked() -{ - return PasswordWasAsked; -} - -void CUpdateCallbackGUI::Open_Clear_PasswordWasAsked_Flag() -{ - PasswordWasAsked = false; -} -*/ - -HRESULT CUpdateCallbackGUI::ShowDeleteFile(const wchar_t *name, bool isDir) -{ - return SetOperation_Base(NUpdateNotifyOp::kDelete, name, isDir); -} - -HRESULT CUpdateCallbackGUI::FinishDeletingAfterArchiving() -{ - // ClosePercents2(); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::DeletingAfterArchiving(const FString &path, bool isDir) -{ - return ProgressDialog->Sync.Set_Status2(_lang_Removing, fs2us(path), isDir); -} - -HRESULT CUpdateCallbackGUI::StartOpenArchive(const wchar_t * /* name */) -{ - return S_OK; -} - -HRESULT CUpdateCallbackGUI::ReadingFileError(const FString &path, DWORD systemError) -{ - FailedFiles.Add(path); - ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path)); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::WriteSfx(const wchar_t * /* name */, UInt64 /* size */) -{ - CProgressSync &sync = ProgressDialog->Sync; - sync.Set_Status(L"WriteSfx"); - return S_OK; -} - -HRESULT CUpdateCallbackGUI::Open_Finished() -{ - // ClosePercents(); - return S_OK; -} - -#endif +// UpdateCallbackGUI.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/PropVariant.h" + +#include "../FileManager/FormatUtils.h" +#include "../FileManager/LangUtils.h" + +#include "../FileManager/resourceGui.h" + +#include "resource2.h" + +#include "UpdateCallbackGUI.h" + +using namespace NWindows; + +// CUpdateCallbackGUI::~CUpdateCallbackGUI() {} + +void CUpdateCallbackGUI::Init() +{ + CUpdateCallbackGUI2::Init(); + FailedFiles.Clear(); +} + +void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result); + +HRESULT CUpdateCallbackGUI::OpenResult( + const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) +{ + UString s; + OpenResult_GUI(s, codecs, arcLink, name, result); + if (!s.IsEmpty()) + { + ProgressDialog->Sync.AddError_Message(s); + } + + return S_OK; +} + +HRESULT CUpdateCallbackGUI::StartScanning() +{ + CProgressSync &sync = ProgressDialog->Sync; + sync.Set_Status(LangString(IDS_SCANNING)); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::ScanError(const FString &path, DWORD systemError) +{ + FailedFiles.Add(path); + ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path)); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::FinishScanning(const CDirItemsStat &st) +{ + CProgressSync &sync = ProgressDialog->Sync; + RINOK(ProgressDialog->Sync.ScanProgress(st.NumFiles + st.NumAltStreams, + st.GetTotalBytes(), FString(), true)) + sync.Set_Status(L""); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::StartArchive(const wchar_t *name, bool /* updating */) +{ + CProgressSync &sync = ProgressDialog->Sync; + sync.Set_Status(LangString(IDS_PROGRESS_COMPRESSING)); + sync.Set_TitleFileName(name); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::FinishArchive(const CFinishArchiveStat & /* st */) +{ + CProgressSync &sync = ProgressDialog->Sync; + sync.Set_Status(L""); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::CheckBreak() +{ + return ProgressDialog->Sync.CheckStop(); +} + +HRESULT CUpdateCallbackGUI::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) +{ + return ProgressDialog->Sync.ScanProgress(st.NumFiles + st.NumAltStreams, + st.GetTotalBytes(), path, isDir); +} + +/* +HRESULT CUpdateCallbackGUI::Finalize() +{ + return S_OK; +} +*/ + +HRESULT CUpdateCallbackGUI::SetNumItems(const CArcToDoStat &stat) +{ + ProgressDialog->Sync.Set_NumFilesTotal(stat.Get_NumDataItems_Total()); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::SetTotal(UInt64 total) +{ + ProgressDialog->Sync.Set_NumBytesTotal(total); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::SetCompleted(const UInt64 *completed) +{ + return ProgressDialog->Sync.Set_NumBytesCur(completed); +} + +HRESULT CUpdateCallbackGUI::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + ProgressDialog->Sync.Set_Ratio(inSize, outSize); + return CheckBreak(); +} + +HRESULT CUpdateCallbackGUI::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode) +{ + return SetOperation_Base(mode, name, isDir); +} + +HRESULT CUpdateCallbackGUI::OpenFileError(const FString &path, DWORD systemError) +{ + FailedFiles.Add(path); + // if (systemError == ERROR_SHARING_VIOLATION) + { + ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path)); + return S_FALSE; + } + // return systemError; +} + +HRESULT CUpdateCallbackGUI::SetOperationResult(Int32 /* operationResult */) +{ + NumFiles++; + ProgressDialog->Sync.Set_NumFilesCur(NumFiles); + return S_OK; +} + +void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); + +HRESULT CUpdateCallbackGUI::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) +{ + if (opRes != NArchive::NExtract::NOperationResult::kOK) + { + UString s; + SetExtractErrorMessage(opRes, isEncrypted, name, s); + ProgressDialog->Sync.AddError_Message(s); + } + return S_OK; +} + +HRESULT CUpdateCallbackGUI::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) +{ + return SetOperation_Base(op, name, isDir); +} + +HRESULT CUpdateCallbackGUI::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) +{ + *password = NULL; + if (passwordIsDefined) + *passwordIsDefined = BoolToInt(PasswordIsDefined); + if (!PasswordIsDefined) + { + if (AskPassword) + { + RINOK(ShowAskPasswordDialog()) + } + } + if (passwordIsDefined) + *passwordIsDefined = BoolToInt(PasswordIsDefined); + return StringToBstr(Password, password); +} + +HRESULT CUpdateCallbackGUI::CryptoGetTextPassword(BSTR *password) +{ + return CryptoGetTextPassword2(NULL, password); +} + +/* +It doesn't work, since main stream waits Dialog +HRESULT CUpdateCallbackGUI::CloseProgress() +{ + ProgressDialog->MyClose(); + return S_OK; +} +*/ + + +HRESULT CUpdateCallbackGUI::Open_CheckBreak() +{ + return ProgressDialog->Sync.CheckStop(); +} + +HRESULT CUpdateCallbackGUI::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) +{ + // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) +{ + return ProgressDialog->Sync.CheckStop(); +} + +#ifndef Z7_NO_CRYPTO + +HRESULT CUpdateCallbackGUI::Open_CryptoGetTextPassword(BSTR *password) +{ + PasswordWasAsked = true; + return CryptoGetTextPassword2(NULL, password); +} + +/* +HRESULT CUpdateCallbackGUI::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) +{ + passwordIsDefined = PasswordIsDefined; + password = Password; + return S_OK; +} + +bool CUpdateCallbackGUI::Open_WasPasswordAsked() +{ + return PasswordWasAsked; +} + +void CUpdateCallbackGUI::Open_Clear_PasswordWasAsked_Flag() +{ + PasswordWasAsked = false; +} +*/ + +HRESULT CUpdateCallbackGUI::ShowDeleteFile(const wchar_t *name, bool isDir) +{ + return SetOperation_Base(NUpdateNotifyOp::kDelete, name, isDir); +} + +HRESULT CUpdateCallbackGUI::FinishDeletingAfterArchiving() +{ + // ClosePercents2(); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::DeletingAfterArchiving(const FString &path, bool isDir) +{ + return ProgressDialog->Sync.Set_Status2(_lang_Removing, fs2us(path), isDir); +} + + +HRESULT CUpdateCallbackGUI::MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 totalSize, Int32 updateMode) +{ + return MoveArc_Start_Base(srcTempPath, destFinalPath, totalSize, updateMode); +} +HRESULT CUpdateCallbackGUI::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize) +{ + return MoveArc_Progress_Base(totalSize, currentSize); +} +HRESULT CUpdateCallbackGUI::MoveArc_Finish() +{ + return MoveArc_Finish_Base(); +} + + +HRESULT CUpdateCallbackGUI::StartOpenArchive(const wchar_t * /* name */) +{ + return S_OK; +} + +HRESULT CUpdateCallbackGUI::ReadingFileError(const FString &path, DWORD systemError) +{ + FailedFiles.Add(path); + ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path)); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::WriteSfx(const wchar_t * /* name */, UInt64 /* size */) +{ + CProgressSync &sync = ProgressDialog->Sync; + sync.Set_Status(L"WriteSfx"); + return S_OK; +} + +HRESULT CUpdateCallbackGUI::Open_Finished() +{ + // ClosePercents(); + return S_OK; +} + +#endif diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h index aa6374548..998249a80 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI.h +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h @@ -1,31 +1,31 @@ -// UpdateCallbackGUI.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK_GUI_H -#define ZIP7_INC_UPDATE_CALLBACK_GUI_H - -#include "../Common/Update.h" -#include "../Common/ArchiveOpenCallback.h" - -#include "UpdateCallbackGUI2.h" - -class CUpdateCallbackGUI Z7_final: - public IOpenCallbackUI, - public IUpdateCallbackUI2, - public CUpdateCallbackGUI2 -{ - Z7_IFACE_IMP(IOpenCallbackUI) - Z7_IFACE_IMP(IUpdateCallbackUI) - Z7_IFACE_IMP(IDirItemsCallback) - Z7_IFACE_IMP(IUpdateCallbackUI2) - -public: - bool AskPassword; - FStringVector FailedFiles; - - CUpdateCallbackGUI(): - AskPassword(false) - {} - void Init(); -}; - -#endif +// UpdateCallbackGUI.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK_GUI_H +#define ZIP7_INC_UPDATE_CALLBACK_GUI_H + +#include "../Common/Update.h" +#include "../Common/ArchiveOpenCallback.h" + +#include "UpdateCallbackGUI2.h" + +class CUpdateCallbackGUI Z7_final: + public IOpenCallbackUI, + public IUpdateCallbackUI2, + public CUpdateCallbackGUI2 +{ + Z7_IFACE_IMP(IOpenCallbackUI) + Z7_IFACE_IMP(IUpdateCallbackUI) + Z7_IFACE_IMP(IDirItemsCallback) + Z7_IFACE_IMP(IUpdateCallbackUI2) + +public: + bool AskPassword; + FStringVector FailedFiles; + + CUpdateCallbackGUI(): + AskPassword(false) + {} + void Init(); +}; + +#endif diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp index e741a6221..53fed91ee 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp @@ -1,59 +1,130 @@ -// UpdateCallbackGUI2.cpp - -#include "StdAfx.h" - -#include "../FileManager/LangUtils.h" -#include "../FileManager/PasswordDialog.h" - -#include "resource2.h" -#include "resource3.h" -#include "ExtractRes.h" - -#include "UpdateCallbackGUI.h" - -using namespace NWindows; - -static const UINT k_UpdNotifyLangs[] = -{ - IDS_PROGRESS_ADD, - IDS_PROGRESS_UPDATE, - IDS_PROGRESS_ANALYZE, - IDS_PROGRESS_REPLICATE, - IDS_PROGRESS_REPACK, - IDS_PROGRESS_SKIPPING, - IDS_PROGRESS_DELETE, - IDS_PROGRESS_HEADER -}; - -void CUpdateCallbackGUI2::Init() -{ - NumFiles = 0; - - _lang_Removing = LangString(IDS_PROGRESS_REMOVE); - _lang_Ops.Clear(); - for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_UpdNotifyLangs); i++) - _lang_Ops.Add(LangString(k_UpdNotifyLangs[i])); -} - -HRESULT CUpdateCallbackGUI2::SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir) -{ - const UString *s = NULL; - if (notifyOp < _lang_Ops.Size()) - s = &(_lang_Ops[(unsigned)notifyOp]); - else - s = &_emptyString; - - return ProgressDialog->Sync.Set_Status2(*s, name, isDir); -} - - -HRESULT CUpdateCallbackGUI2::ShowAskPasswordDialog() -{ - CPasswordDialog dialog; - ProgressDialog->WaitCreating(); - if (dialog.Create(*ProgressDialog) != IDOK) - return E_ABORT; - Password = dialog.Password; - PasswordIsDefined = true; - return S_OK; -} +// UpdateCallbackGUI2.cpp + +#include "StdAfx.h" + +#include "../FileManager/LangUtils.h" +#include "../FileManager/PasswordDialog.h" + +#include "resource2.h" +#include "resource3.h" +#include "ExtractRes.h" +#include "../FileManager/resourceGui.h" + +#include "UpdateCallbackGUI.h" + +using namespace NWindows; + +static const UINT k_UpdNotifyLangs[] = +{ + IDS_PROGRESS_ADD, + IDS_PROGRESS_UPDATE, + IDS_PROGRESS_ANALYZE, + IDS_PROGRESS_REPLICATE, + IDS_PROGRESS_REPACK, + IDS_PROGRESS_SKIPPING, + IDS_PROGRESS_DELETE, + IDS_PROGRESS_HEADER +}; + +void CUpdateCallbackGUI2::Init() +{ + NumFiles = 0; + + LangString(IDS_PROGRESS_REMOVE, _lang_Removing); + LangString(IDS_MOVING, _lang_Moving); + _lang_Ops.Clear(); + for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_UpdNotifyLangs); i++) + _lang_Ops.Add(LangString(k_UpdNotifyLangs[i])); +} + +HRESULT CUpdateCallbackGUI2::SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir) +{ + const UString *s = NULL; + if (notifyOp < _lang_Ops.Size()) + s = &(_lang_Ops[(unsigned)notifyOp]); + else + s = &_emptyString; + + return ProgressDialog->Sync.Set_Status2(*s, name, isDir); +} + + +HRESULT CUpdateCallbackGUI2::ShowAskPasswordDialog() +{ + CPasswordDialog dialog; + ProgressDialog->WaitCreating(); + if (dialog.Create(*ProgressDialog) != IDOK) + return E_ABORT; + Password = dialog.Password; + PasswordIsDefined = true; + return S_OK; +} + + +HRESULT CUpdateCallbackGUI2::MoveArc_UpdateStatus() +{ + UString s; + s.Add_UInt64(_arcMoving_percents); + s.Add_Char('%'); + + const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1); + if (totalDefined || _arcMoving_current != 0) + { + s += " : "; + s.Add_UInt64(_arcMoving_current >> 20); + s += " MiB"; + } + if (totalDefined) + { + s += " / "; + s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20); + s += " MiB"; + } + + s += " : "; + s += _lang_Moving; + s += " : "; + // s.Add_Char('\"'); + s += _arcMoving_name1; + // s.Add_Char('\"'); + return ProgressDialog->Sync.Set_Status2(s, _arcMoving_name2, + false); // isDir +} + + +HRESULT CUpdateCallbackGUI2::MoveArc_Start_Base(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 totalSize, Int32 updateMode) +{ + _arcMoving_percents = 0; + _arcMoving_total = totalSize; + _arcMoving_current = 0; + _arcMoving_updateMode = updateMode; + _arcMoving_name1 = srcTempPath; + _arcMoving_name2 = destFinalPath; + return MoveArc_UpdateStatus(); +} + + +HRESULT CUpdateCallbackGUI2::MoveArc_Progress_Base(UInt64 totalSize, UInt64 currentSize) +{ + _arcMoving_total = totalSize; + _arcMoving_current = currentSize; + UInt64 percents = 0; + if (totalSize != 0) + { + if (totalSize < ((UInt64)1 << 57)) + percents = currentSize * 100 / totalSize; + else + percents = currentSize / (totalSize / 100); + } + if (percents == _arcMoving_percents) + return ProgressDialog->Sync.CheckStop(); + // Sleep(300); // for debug + _arcMoving_percents = percents; + return MoveArc_UpdateStatus(); +} + + +HRESULT CUpdateCallbackGUI2::MoveArc_Finish_Base() +{ + return ProgressDialog->Sync.Set_Status2(L"", L"", false); +} diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h index 3aa4a189d..56747ff02 100644 --- a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h +++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h @@ -1,34 +1,53 @@ -// UpdateCallbackGUI2.h - -#ifndef ZIP7_INC_UPDATE_CALLBACK_GUI2_H -#define ZIP7_INC_UPDATE_CALLBACK_GUI2_H - -#include "../FileManager/ProgressDialog2.h" - -class CUpdateCallbackGUI2 -{ - UStringVector _lang_Ops; - UString _emptyString; -public: - UString Password; - bool PasswordIsDefined; - bool PasswordWasAsked; - UInt64 NumFiles; - - UString _lang_Removing; - - CUpdateCallbackGUI2(): - PasswordIsDefined(false), - PasswordWasAsked(false), - NumFiles(0) - {} - - void Init(); - - CProgressDialog *ProgressDialog; - - HRESULT SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir); - HRESULT ShowAskPasswordDialog(); -}; - -#endif +// UpdateCallbackGUI2.h + +#ifndef ZIP7_INC_UPDATE_CALLBACK_GUI2_H +#define ZIP7_INC_UPDATE_CALLBACK_GUI2_H + +#include "../FileManager/ProgressDialog2.h" + +class CUpdateCallbackGUI2 +{ +public: + CProgressDialog *ProgressDialog; +protected: + UString _arcMoving_name1; + UString _arcMoving_name2; + UInt64 _arcMoving_percents; + UInt64 _arcMoving_total; + UInt64 _arcMoving_current; + Int32 _arcMoving_updateMode; +public: + bool PasswordIsDefined; + bool PasswordWasAsked; + UInt64 NumFiles; + UString Password; +protected: + UStringVector _lang_Ops; + UString _lang_Removing; + UString _lang_Moving; + UString _emptyString; + + HRESULT MoveArc_UpdateStatus(); + HRESULT MoveArc_Start_Base(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 /* totalSize */, Int32 updateMode); + HRESULT MoveArc_Progress_Base(UInt64 totalSize, UInt64 currentSize); + HRESULT MoveArc_Finish_Base(); + +public: + + CUpdateCallbackGUI2(): + _arcMoving_percents(0), + _arcMoving_total(0), + _arcMoving_current(0), + _arcMoving_updateMode(0), + PasswordIsDefined(false), + PasswordWasAsked(false), + NumFiles(0) + {} + + void Init(); + + HRESULT SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir); + HRESULT ShowAskPasswordDialog(); +}; + +#endif diff --git a/CPP/7zip/UI/GUI/UpdateGUI.cpp b/CPP/7zip/UI/GUI/UpdateGUI.cpp index ee5d6e4d7..a600a8bc1 100644 --- a/CPP/7zip/UI/GUI/UpdateGUI.cpp +++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp @@ -1,605 +1,605 @@ -// UpdateGUI.cpp - -#include "StdAfx.h" - -#include "../../../Common/IntToString.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/StringToInt.h" - -#include "../../../Windows/DLL.h" -#include "../../../Windows/FileDir.h" -#include "../../../Windows/FileName.h" -#include "../../../Windows/Thread.h" - -#include "../Common/WorkDir.h" - -#include "../Explorer/MyMessages.h" - -#include "../FileManager/LangUtils.h" -#include "../FileManager/StringUtils.h" -#include "../FileManager/resourceGui.h" - -#include "CompressDialog.h" -#include "UpdateGUI.h" - -#include "resource2.h" - -using namespace NWindows; -using namespace NFile; -using namespace NDir; - -static const char * const kDefaultSfxModule = "7z.sfx"; -static const char * const kSFXExtension = "exe"; - -extern void AddMessageToString(UString &dest, const UString &src); - -UString HResultToMessage(HRESULT errorCode); - -class CThreadUpdating: public CProgressThreadVirt -{ - HRESULT ProcessVirt() Z7_override; -public: - CCodecs *codecs; - const CObjectVector *formatIndices; - const UString *cmdArcPath; - CUpdateCallbackGUI *UpdateCallbackGUI; - NWildcard::CCensor *WildcardCensor; - CUpdateOptions *Options; - bool needSetPath; -}; - -HRESULT CThreadUpdating::ProcessVirt() -{ - CUpdateErrorInfo ei; - HRESULT res = UpdateArchive(codecs, *formatIndices, *cmdArcPath, - *WildcardCensor, *Options, - ei, UpdateCallbackGUI, UpdateCallbackGUI, needSetPath); - FinalMessage.ErrorMessage.Message = ei.Message.Ptr(); - ErrorPaths = ei.FileNames; - if (res != S_OK) - return res; - return HRESULT_FROM_WIN32(ei.SystemError); -} - - -// parse command line properties - -static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp) -{ - if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name)) - return false; - const UString rem = prop.Name.Ptr((unsigned)strlen(name)); - UString val = prop.Value; - if (!rem.IsEmpty()) - { - if (!val.IsEmpty()) - return true; - val = rem; - } - bool res; - if (StringToBool(val, res)) - { - bp.Val = res; - bp.Def = true; - } - return true; -} - -static void ParseProp( - const CProperty &prop, - NCompressDialog::CInfo &di) -{ - if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return; - if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return; - if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return; -} - -static void ParseProperties( - const CObjectVector &properties, - NCompressDialog::CInfo &di) -{ - FOR_VECTOR (i, properties) - { - ParseProp(properties[i], di); - } -} - - - - - -static void AddProp_UString(CObjectVector &properties, const char *name, const UString &value) -{ - CProperty prop; - prop.Name = name; - prop.Value = value; - properties.Add(prop); -} - -static void AddProp_UInt32(CObjectVector &properties, const char *name, UInt32 value) -{ - UString s; - s.Add_UInt32(value); - AddProp_UString(properties, name, s); -} - -static void AddProp_bool(CObjectVector &properties, const char *name, bool value) -{ - AddProp_UString(properties, name, UString(value ? "on": "off")); -} - - -static void AddProp_BoolPair(CObjectVector &properties, - const char *name, const CBoolPair &bp) -{ - if (bp.Def) - AddProp_bool(properties, name, bp.Val); -} - - - -static void SplitOptionsToStrings(const UString &src, UStringVector &strings) -{ - SplitString(src, strings); - FOR_VECTOR (i, strings) - { - UString &s = strings[i]; - if (s.Len() > 2 - && s[0] == '-' - && MyCharLower_Ascii(s[1]) == 'm') - s.DeleteFrontal(2); - } -} - -static bool IsThereMethodOverride(bool is7z, const UStringVector &strings) -{ - FOR_VECTOR (i, strings) - { - const UString &s = strings[i]; - if (is7z) - { - const wchar_t *end; - UInt64 n = ConvertStringToUInt64(s, &end); - if (n == 0 && *end == L'=') - return true; - } - else - { - if (s.Len() > 0) - if (s[0] == L'm' && s[1] == L'=') - return true; - } - } - return false; -} - -static void ParseAndAddPropertires(CObjectVector &properties, - const UStringVector &strings) -{ - FOR_VECTOR (i, strings) - { - const UString &s = strings[i]; - CProperty property; - const int index = s.Find(L'='); - if (index < 0) - property.Name = s; - else - { - property.Name.SetFrom(s, (unsigned)index); - property.Value = s.Ptr(index + 1); - } - properties.Add(property); - } -} - - -static void AddProp_Size(CObjectVector &properties, const char *name, const UInt64 size) -{ - UString s; - s.Add_UInt64(size); - s.Add_Char('b'); - AddProp_UString(properties, name, s); -} - - -static void SetOutProperties( - CObjectVector &properties, - const NCompressDialog::CInfo &di, - bool is7z, - bool setMethod) -{ - if (di.Level != (UInt32)(Int32)-1) - AddProp_UInt32(properties, "x", (UInt32)di.Level); - if (setMethod) - { - if (!di.Method.IsEmpty()) - AddProp_UString(properties, is7z ? "0": "m", di.Method); - if (di.Dict64 != (UInt64)(Int64)-1) - { - AString name; - if (is7z) - name = "0"; - name += (di.OrderMode ? "mem" : "d"); - AddProp_Size(properties, name, di.Dict64); - } - /* - if (di.Dict64_Chain != (UInt64)(Int64)-1) - { - AString name; - if (is7z) - name = "0"; - name += "dc"; - AddProp_Size(properties, name, di.Dict64_Chain); - } - */ - if (di.Order != (UInt32)(Int32)-1) - { - AString name; - if (is7z) - name = "0"; - name += (di.OrderMode ? "o" : "fb"); - AddProp_UInt32(properties, name, (UInt32)di.Order); - } - } - - if (!di.EncryptionMethod.IsEmpty()) - AddProp_UString(properties, "em", di.EncryptionMethod); - - if (di.EncryptHeadersIsAllowed) - AddProp_bool(properties, "he", di.EncryptHeaders); - - if (di.SolidIsSpecified) - AddProp_Size(properties, "s", di.SolidBlockSize); - - if ( - // di.MultiThreadIsAllowed && - di.NumThreads != (UInt32)(Int32)-1) - AddProp_UInt32(properties, "mt", di.NumThreads); - - const NCompression::CMemUse &memUse = di.MemUsage; - if (memUse.IsDefined) - { - const char *kMemUse = "memuse"; - if (memUse.IsPercent) - { - UString s; - // s += 'p'; // for debug: alternate percent method - s.Add_UInt64(memUse.Val); - s.Add_Char('%'); - AddProp_UString(properties, kMemUse, s); - } - else - AddProp_Size(properties, kMemUse, memUse.Val); - } - - AddProp_BoolPair(properties, "tm", di.MTime); - AddProp_BoolPair(properties, "tc", di.CTime); - AddProp_BoolPair(properties, "ta", di.ATime); - - if (di.TimePrec != (UInt32)(Int32)-1) - AddProp_UInt32(properties, "tp", di.TimePrec); -} - - -struct C_UpdateMode_ToAction_Pair -{ - NCompressDialog::NUpdateMode::EEnum UpdateMode; - const NUpdateArchive::CActionSet *ActionSet; -}; - -static const C_UpdateMode_ToAction_Pair g_UpdateMode_Pairs[] = -{ - { NCompressDialog::NUpdateMode::kAdd, &NUpdateArchive::k_ActionSet_Add }, - { NCompressDialog::NUpdateMode::kUpdate, &NUpdateArchive::k_ActionSet_Update }, - { NCompressDialog::NUpdateMode::kFresh, &NUpdateArchive::k_ActionSet_Fresh }, - { NCompressDialog::NUpdateMode::kSync, &NUpdateArchive::k_ActionSet_Sync } -}; - -static int FindActionSet(const NUpdateArchive::CActionSet &actionSet) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++) - if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet)) - return (int)i; - return -1; -} - -static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode) -{ - for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++) - if (mode == g_UpdateMode_Pairs[i].UpdateMode) - return (int)i; - return -1; -} - - -static HRESULT ShowDialog( - CCodecs *codecs, - const CObjectVector &censor, - CUpdateOptions &options, - CUpdateCallbackGUI *callback, HWND hwndParent) -{ - if (options.Commands.Size() != 1) - throw "It must be one command"; - /* - FString currentDirPrefix; - #ifndef UNDER_CE - { - if (!MyGetCurrentDirectory(currentDirPrefix)) - return E_FAIL; - NName::NormalizeDirPathPrefix(currentDirPrefix); - } - #endif - */ - - bool oneFile = false; - NFind::CFileInfo fileInfo; - UString name; - - /* - if (censor.Pairs.Size() > 0) - { - const NWildcard::CPair &pair = censor.Pairs[0]; - if (pair.Head.IncludeItems.Size() > 0) - { - const NWildcard::CItem &item = pair.Head.IncludeItems[0]; - if (item.ForFile) - { - name = pair.Prefix; - FOR_VECTOR (i, item.PathParts) - { - if (i > 0) - name.Add_PathSepar(); - name += item.PathParts[i]; - } - if (fileInfo.Find(us2fs(name))) - { - if (censor.Pairs.Size() == 1 && pair.Head.IncludeItems.Size() == 1) - oneFile = !fileInfo.IsDir(); - } - } - } - } - */ - if (censor.Size() > 0) - { - const NWildcard::CCensorPath &cp = censor[0]; - if (cp.Include) - { - { - if (fileInfo.Find(us2fs(cp.Path))) - { - if (censor.Size() == 1) - oneFile = !fileInfo.IsDir(); - } - } - } - } - - - /* - // v23: we restore current dir in dialog code - #if defined(_WIN32) && !defined(UNDER_CE) - CCurrentDirRestorer curDirRestorer; - #endif - */ - - CCompressDialog dialog; - NCompressDialog::CInfo &di = dialog.Info; - dialog.ArcFormats = &codecs->Formats; - { - CObjectVector userCodecs; - codecs->Get_CodecsInfoUser_Vector(userCodecs); - dialog.SetMethods(userCodecs); - } - - if (options.MethodMode.Type_Defined) - di.FormatIndex = options.MethodMode.Type.FormatIndex; - - FOR_VECTOR (i, codecs->Formats) - { - const CArcInfoEx &ai = codecs->Formats[i]; - if (!ai.UpdateEnabled) - continue; - if (!oneFile && ai.Flags_KeepName()) - continue; - if ((int)i != di.FormatIndex) - { - if (ai.Flags_HashHandler()) - continue; - if (ai.Name.IsEqualTo_Ascii_NoCase("swfc")) - if (!oneFile || name.Len() < 4 || !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".swf")) - continue; - } - dialog.ArcIndices.Add(i); - } - if (dialog.ArcIndices.IsEmpty()) - { - ShowErrorMessage(L"No Update Engines"); - return E_FAIL; - } - - // di.ArchiveName = options.ArchivePath.GetFinalPath(); - di.ArcPath = options.ArchivePath.GetPathWithoutExt(); - dialog.OriginalFileName = fs2us(fileInfo.Name); - - di.PathMode = options.PathMode; - - // di.CurrentDirPrefix = currentDirPrefix; - di.SFXMode = options.SfxMode; - di.OpenShareForWrite = options.OpenShareForWrite; - di.DeleteAfterCompressing = options.DeleteAfterCompressing; - - di.SymLinks = options.SymLinks; - di.HardLinks = options.HardLinks; - di.AltStreams = options.AltStreams; - di.NtSecurity = options.NtSecurity; - if (options.SetArcMTime) - di.SetArcMTime.SetTrueTrue(); - if (options.PreserveATime) - di.PreserveATime.SetTrueTrue(); - - if (callback->PasswordIsDefined) - di.Password = callback->Password; - - di.KeepName = !oneFile; - - NUpdateArchive::CActionSet &actionSet = options.Commands.Front().ActionSet; - - { - int index = FindActionSet(actionSet); - if (index < 0) - return E_NOTIMPL; - di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode; - } - - ParseProperties(options.MethodMode.Properties, di); - - if (dialog.Create(hwndParent) != IDOK) - return E_ABORT; - - options.DeleteAfterCompressing = di.DeleteAfterCompressing; - - options.SymLinks = di.SymLinks; - options.HardLinks = di.HardLinks; - options.AltStreams = di.AltStreams; - options.NtSecurity = di.NtSecurity; - options.SetArcMTime = di.SetArcMTime.Val; - if (di.PreserveATime.Def) - options.PreserveATime = di.PreserveATime.Val; - - /* - #if defined(_WIN32) && !defined(UNDER_CE) - curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged; - #endif - */ - - options.VolumesSizes = di.VolumeSizes; - /* - if (di.VolumeSizeIsDefined) - { - MyMessageBox(L"Splitting to volumes is not supported"); - return E_FAIL; - } - */ - - - { - int index = FindUpdateMode(di.UpdateMode); - if (index < 0) - return E_FAIL; - actionSet = *g_UpdateMode_Pairs[index].ActionSet; - } - - options.PathMode = di.PathMode; - - const CArcInfoEx &archiverInfo = codecs->Formats[di.FormatIndex]; - callback->PasswordIsDefined = (!di.Password.IsEmpty()); - if (callback->PasswordIsDefined) - callback->Password = di.Password; - - // we clear command line options, and fill options form Dialog - options.MethodMode.Properties.Clear(); - - const bool is7z = archiverInfo.Is_7z(); - - UStringVector optionStrings; - SplitOptionsToStrings(di.Options, optionStrings); - const bool methodOverride = IsThereMethodOverride(is7z, optionStrings); - - SetOutProperties(options.MethodMode.Properties, di, - is7z, - !methodOverride); // setMethod - - options.OpenShareForWrite = di.OpenShareForWrite; - ParseAndAddPropertires(options.MethodMode.Properties, optionStrings); - - if (di.SFXMode) - options.SfxMode = true; - options.MethodMode.Type = COpenType(); - options.MethodMode.Type_Defined = true; - options.MethodMode.Type.FormatIndex = di.FormatIndex; - - options.ArchivePath.VolExtension = archiverInfo.GetMainExt(); - if (di.SFXMode) - options.ArchivePath.BaseExtension = kSFXExtension; - else - options.ArchivePath.BaseExtension = options.ArchivePath.VolExtension; - options.ArchivePath.ParseFromPath(di.ArcPath, k_ArcNameMode_Smart); - - NWorkDir::CInfo workDirInfo; - workDirInfo.Load(); - options.WorkingDir.Empty(); - if (workDirInfo.Mode != NWorkDir::NMode::kCurrent) - { - FString fullPath; - MyGetFullPathName(us2fs(di.ArcPath), fullPath); - FString namePart; - options.WorkingDir = GetWorkDir(workDirInfo, fullPath, namePart); - CreateComplexDir(options.WorkingDir); - } - return S_OK; -} - -HRESULT UpdateGUI( - CCodecs *codecs, - const CObjectVector &formatIndices, - const UString &cmdArcPath, - NWildcard::CCensor &censor, - CUpdateOptions &options, - bool showDialog, - bool &messageWasDisplayed, - CUpdateCallbackGUI *callback, - HWND hwndParent) -{ - messageWasDisplayed = false; - bool needSetPath = true; - if (showDialog) - { - RINOK(ShowDialog(codecs, censor.CensorPaths, options, callback, hwndParent)) - needSetPath = false; - } - if (options.SfxMode && options.SfxModule.IsEmpty()) - { - options.SfxModule = NWindows::NDLL::GetModuleDirPrefix(); - options.SfxModule += kDefaultSfxModule; - } - - CThreadUpdating tu; - - tu.needSetPath = needSetPath; - - tu.codecs = codecs; - tu.formatIndices = &formatIndices; - tu.cmdArcPath = &cmdArcPath; - - tu.UpdateCallbackGUI = callback; - tu.UpdateCallbackGUI->ProgressDialog = &tu; - tu.UpdateCallbackGUI->Init(); - - UString title = LangString(IDS_PROGRESS_COMPRESSING); - if (!formatIndices.IsEmpty()) - { - const int fin = formatIndices[0].FormatIndex; - if (fin >= 0) - if (codecs->Formats[fin].Flags_HashHandler()) - title = LangString(IDS_CHECKSUM_CALCULATING); - } - - /* - if (hwndParent != 0) - { - tu.ProgressDialog.MainWindow = hwndParent; - // tu.ProgressDialog.MainTitle = fileName; - tu.ProgressDialog.MainAddTitle = title + L' '; - } - */ - - tu.WildcardCensor = &censor; - tu.Options = &options; - tu.IconID = IDI_ICON; - - RINOK(tu.Create(title, hwndParent)) - - messageWasDisplayed = tu.ThreadFinishedOK && tu.MessagesDisplayed; - return tu.Result; -} +// UpdateGUI.cpp + +#include "StdAfx.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/Thread.h" + +#include "../Common/WorkDir.h" + +#include "../Explorer/MyMessages.h" + +#include "../FileManager/LangUtils.h" +#include "../FileManager/StringUtils.h" +#include "../FileManager/resourceGui.h" + +#include "CompressDialog.h" +#include "UpdateGUI.h" + +#include "resource2.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDir; + +static const char * const kDefaultSfxModule = "7z.sfx"; +static const char * const kSFXExtension = "exe"; + +extern void AddMessageToString(UString &dest, const UString &src); + +UString HResultToMessage(HRESULT errorCode); + +class CThreadUpdating: public CProgressThreadVirt +{ + HRESULT ProcessVirt() Z7_override; +public: + CCodecs *codecs; + const CObjectVector *formatIndices; + const UString *cmdArcPath; + CUpdateCallbackGUI *UpdateCallbackGUI; + NWildcard::CCensor *WildcardCensor; + CUpdateOptions *Options; + bool needSetPath; +}; + +HRESULT CThreadUpdating::ProcessVirt() +{ + CUpdateErrorInfo ei; + HRESULT res = UpdateArchive(codecs, *formatIndices, *cmdArcPath, + *WildcardCensor, *Options, + ei, UpdateCallbackGUI, UpdateCallbackGUI, needSetPath); + FinalMessage.ErrorMessage.Message = ei.Message.Ptr(); + ErrorPaths = ei.FileNames; + if (res != S_OK) + return res; + return HRESULT_FROM_WIN32(ei.SystemError); +} + + +// parse command line properties + +static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp) +{ + if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name)) + return false; + const UString rem = prop.Name.Ptr((unsigned)strlen(name)); + UString val = prop.Value; + if (!rem.IsEmpty()) + { + if (!val.IsEmpty()) + return true; + val = rem; + } + bool res; + if (StringToBool(val, res)) + { + bp.Val = res; + bp.Def = true; + } + return true; +} + +static void ParseProp( + const CProperty &prop, + NCompressDialog::CInfo &di) +{ + if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return; + if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return; + if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return; +} + +static void ParseProperties( + const CObjectVector &properties, + NCompressDialog::CInfo &di) +{ + FOR_VECTOR (i, properties) + { + ParseProp(properties[i], di); + } +} + + + + + +static void AddProp_UString(CObjectVector &properties, const char *name, const UString &value) +{ + CProperty prop; + prop.Name = name; + prop.Value = value; + properties.Add(prop); +} + +static void AddProp_UInt32(CObjectVector &properties, const char *name, UInt32 value) +{ + UString s; + s.Add_UInt32(value); + AddProp_UString(properties, name, s); +} + +static void AddProp_bool(CObjectVector &properties, const char *name, bool value) +{ + AddProp_UString(properties, name, UString(value ? "on": "off")); +} + + +static void AddProp_BoolPair(CObjectVector &properties, + const char *name, const CBoolPair &bp) +{ + if (bp.Def) + AddProp_bool(properties, name, bp.Val); +} + + + +static void SplitOptionsToStrings(const UString &src, UStringVector &strings) +{ + SplitString(src, strings); + FOR_VECTOR (i, strings) + { + UString &s = strings[i]; + if (s.Len() > 2 + && s[0] == '-' + && MyCharLower_Ascii(s[1]) == 'm') + s.DeleteFrontal(2); + } +} + +static bool IsThereMethodOverride(bool is7z, const UStringVector &strings) +{ + FOR_VECTOR (i, strings) + { + const UString &s = strings[i]; + if (is7z) + { + const wchar_t *end; + UInt64 n = ConvertStringToUInt64(s, &end); + if (n == 0 && *end == L'=') + return true; + } + else + { + if (s.Len() > 0) + if (s[0] == L'm' && s[1] == L'=') + return true; + } + } + return false; +} + +static void ParseAndAddPropertires(CObjectVector &properties, + const UStringVector &strings) +{ + FOR_VECTOR (i, strings) + { + const UString &s = strings[i]; + CProperty property; + const int index = s.Find(L'='); + if (index < 0) + property.Name = s; + else + { + property.Name.SetFrom(s, (unsigned)index); + property.Value = s.Ptr(index + 1); + } + properties.Add(property); + } +} + + +static void AddProp_Size(CObjectVector &properties, const char *name, const UInt64 size) +{ + UString s; + s.Add_UInt64(size); + s.Add_Char('b'); + AddProp_UString(properties, name, s); +} + + +static void SetOutProperties( + CObjectVector &properties, + const NCompressDialog::CInfo &di, + bool is7z, + bool setMethod) +{ + if (di.Level != (UInt32)(Int32)-1) + AddProp_UInt32(properties, "x", (UInt32)di.Level); + if (setMethod) + { + if (!di.Method.IsEmpty()) + AddProp_UString(properties, is7z ? "0": "m", di.Method); + if (di.Dict64 != (UInt64)(Int64)-1) + { + AString name; + if (is7z) + name = "0"; + name += (di.OrderMode ? "mem" : "d"); + AddProp_Size(properties, name, di.Dict64); + } + /* + if (di.Dict64_Chain != (UInt64)(Int64)-1) + { + AString name; + if (is7z) + name = "0"; + name += "dc"; + AddProp_Size(properties, name, di.Dict64_Chain); + } + */ + if (di.Order != (UInt32)(Int32)-1) + { + AString name; + if (is7z) + name = "0"; + name += (di.OrderMode ? "o" : "fb"); + AddProp_UInt32(properties, name, (UInt32)di.Order); + } + } + + if (!di.EncryptionMethod.IsEmpty()) + AddProp_UString(properties, "em", di.EncryptionMethod); + + if (di.EncryptHeadersIsAllowed) + AddProp_bool(properties, "he", di.EncryptHeaders); + + if (di.SolidIsSpecified) + AddProp_Size(properties, "s", di.SolidBlockSize); + + if ( + // di.MultiThreadIsAllowed && + di.NumThreads != (UInt32)(Int32)-1) + AddProp_UInt32(properties, "mt", di.NumThreads); + + const NCompression::CMemUse &memUse = di.MemUsage; + if (memUse.IsDefined) + { + const char *kMemUse = "memuse"; + if (memUse.IsPercent) + { + UString s; + // s += 'p'; // for debug: alternate percent method + s.Add_UInt64(memUse.Val); + s.Add_Char('%'); + AddProp_UString(properties, kMemUse, s); + } + else + AddProp_Size(properties, kMemUse, memUse.Val); + } + + AddProp_BoolPair(properties, "tm", di.MTime); + AddProp_BoolPair(properties, "tc", di.CTime); + AddProp_BoolPair(properties, "ta", di.ATime); + + if (di.TimePrec != (UInt32)(Int32)-1) + AddProp_UInt32(properties, "tp", di.TimePrec); +} + + +struct C_UpdateMode_ToAction_Pair +{ + NCompressDialog::NUpdateMode::EEnum UpdateMode; + const NUpdateArchive::CActionSet *ActionSet; +}; + +static const C_UpdateMode_ToAction_Pair g_UpdateMode_Pairs[] = +{ + { NCompressDialog::NUpdateMode::kAdd, &NUpdateArchive::k_ActionSet_Add }, + { NCompressDialog::NUpdateMode::kUpdate, &NUpdateArchive::k_ActionSet_Update }, + { NCompressDialog::NUpdateMode::kFresh, &NUpdateArchive::k_ActionSet_Fresh }, + { NCompressDialog::NUpdateMode::kSync, &NUpdateArchive::k_ActionSet_Sync } +}; + +static int FindActionSet(const NUpdateArchive::CActionSet &actionSet) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++) + if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet)) + return (int)i; + return -1; +} + +static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode) +{ + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++) + if (mode == g_UpdateMode_Pairs[i].UpdateMode) + return (int)i; + return -1; +} + + +static HRESULT ShowDialog( + CCodecs *codecs, + const CObjectVector &censor, + CUpdateOptions &options, + CUpdateCallbackGUI *callback, HWND hwndParent) +{ + if (options.Commands.Size() != 1) + throw "It must be one command"; + /* + FString currentDirPrefix; + #ifndef UNDER_CE + { + if (!MyGetCurrentDirectory(currentDirPrefix)) + return E_FAIL; + NName::NormalizeDirPathPrefix(currentDirPrefix); + } + #endif + */ + + bool oneFile = false; + NFind::CFileInfo fileInfo; + UString name; + + /* + if (censor.Pairs.Size() > 0) + { + const NWildcard::CPair &pair = censor.Pairs[0]; + if (pair.Head.IncludeItems.Size() > 0) + { + const NWildcard::CItem &item = pair.Head.IncludeItems[0]; + if (item.ForFile) + { + name = pair.Prefix; + FOR_VECTOR (i, item.PathParts) + { + if (i > 0) + name.Add_PathSepar(); + name += item.PathParts[i]; + } + if (fileInfo.Find(us2fs(name))) + { + if (censor.Pairs.Size() == 1 && pair.Head.IncludeItems.Size() == 1) + oneFile = !fileInfo.IsDir(); + } + } + } + } + */ + if (censor.Size() > 0) + { + const NWildcard::CCensorPath &cp = censor[0]; + if (cp.Include) + { + { + if (fileInfo.Find(us2fs(cp.Path))) + { + if (censor.Size() == 1) + oneFile = !fileInfo.IsDir(); + } + } + } + } + + + /* + // v23: we restore current dir in dialog code + #if defined(_WIN32) && !defined(UNDER_CE) + CCurrentDirRestorer curDirRestorer; + #endif + */ + + CCompressDialog dialog; + NCompressDialog::CInfo &di = dialog.Info; + dialog.ArcFormats = &codecs->Formats; + { + CObjectVector userCodecs; + codecs->Get_CodecsInfoUser_Vector(userCodecs); + dialog.SetMethods(userCodecs); + } + + if (options.MethodMode.Type_Defined) + di.FormatIndex = options.MethodMode.Type.FormatIndex; + + FOR_VECTOR (i, codecs->Formats) + { + const CArcInfoEx &ai = codecs->Formats[i]; + if (!ai.UpdateEnabled) + continue; + if (!oneFile && ai.Flags_KeepName()) + continue; + if ((int)i != di.FormatIndex) + { + if (ai.Flags_HashHandler()) + continue; + if (ai.Name.IsEqualTo_Ascii_NoCase("swfc")) + if (!oneFile || name.Len() < 4 || !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".swf")) + continue; + } + dialog.ArcIndices.Add(i); + } + if (dialog.ArcIndices.IsEmpty()) + { + ShowErrorMessage(L"No Update Engines"); + return E_FAIL; + } + + // di.ArchiveName = options.ArchivePath.GetFinalPath(); + di.ArcPath = options.ArchivePath.GetPathWithoutExt(); + dialog.OriginalFileName = fs2us(fileInfo.Name); + + di.PathMode = options.PathMode; + + // di.CurrentDirPrefix = currentDirPrefix; + di.SFXMode = options.SfxMode; + di.OpenShareForWrite = options.OpenShareForWrite; + di.DeleteAfterCompressing = options.DeleteAfterCompressing; + + di.SymLinks = options.SymLinks; + di.HardLinks = options.HardLinks; + di.AltStreams = options.AltStreams; + di.NtSecurity = options.NtSecurity; + if (options.SetArcMTime) + di.SetArcMTime.SetTrueTrue(); + if (options.PreserveATime) + di.PreserveATime.SetTrueTrue(); + + if (callback->PasswordIsDefined) + di.Password = callback->Password; + + di.KeepName = !oneFile; + + NUpdateArchive::CActionSet &actionSet = options.Commands.Front().ActionSet; + + { + int index = FindActionSet(actionSet); + if (index < 0) + return E_NOTIMPL; + di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode; + } + + ParseProperties(options.MethodMode.Properties, di); + + if (dialog.Create(hwndParent) != IDOK) + return E_ABORT; + + options.DeleteAfterCompressing = di.DeleteAfterCompressing; + + options.SymLinks = di.SymLinks; + options.HardLinks = di.HardLinks; + options.AltStreams = di.AltStreams; + options.NtSecurity = di.NtSecurity; + options.SetArcMTime = di.SetArcMTime.Val; + if (di.PreserveATime.Def) + options.PreserveATime = di.PreserveATime.Val; + + /* + #if defined(_WIN32) && !defined(UNDER_CE) + curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged; + #endif + */ + + options.VolumesSizes = di.VolumeSizes; + /* + if (di.VolumeSizeIsDefined) + { + MyMessageBox(L"Splitting to volumes is not supported"); + return E_FAIL; + } + */ + + + { + int index = FindUpdateMode(di.UpdateMode); + if (index < 0) + return E_FAIL; + actionSet = *g_UpdateMode_Pairs[index].ActionSet; + } + + options.PathMode = di.PathMode; + + const CArcInfoEx &archiverInfo = codecs->Formats[di.FormatIndex]; + callback->PasswordIsDefined = (!di.Password.IsEmpty()); + if (callback->PasswordIsDefined) + callback->Password = di.Password; + + // we clear command line options, and fill options form Dialog + options.MethodMode.Properties.Clear(); + + const bool is7z = archiverInfo.Is_7z(); + + UStringVector optionStrings; + SplitOptionsToStrings(di.Options, optionStrings); + const bool methodOverride = IsThereMethodOverride(is7z, optionStrings); + + SetOutProperties(options.MethodMode.Properties, di, + is7z, + !methodOverride); // setMethod + + options.OpenShareForWrite = di.OpenShareForWrite; + ParseAndAddPropertires(options.MethodMode.Properties, optionStrings); + + if (di.SFXMode) + options.SfxMode = true; + options.MethodMode.Type = COpenType(); + options.MethodMode.Type_Defined = true; + options.MethodMode.Type.FormatIndex = di.FormatIndex; + + options.ArchivePath.VolExtension = archiverInfo.GetMainExt(); + if (di.SFXMode) + options.ArchivePath.BaseExtension = kSFXExtension; + else + options.ArchivePath.BaseExtension = options.ArchivePath.VolExtension; + options.ArchivePath.ParseFromPath(di.ArcPath, k_ArcNameMode_Smart); + + NWorkDir::CInfo workDirInfo; + workDirInfo.Load(); + options.WorkingDir.Empty(); + if (workDirInfo.Mode != NWorkDir::NMode::kCurrent) + { + FString fullPath; + MyGetFullPathName(us2fs(di.ArcPath), fullPath); + FString namePart; + options.WorkingDir = GetWorkDir(workDirInfo, fullPath, namePart); + CreateComplexDir(options.WorkingDir); + } + return S_OK; +} + +HRESULT UpdateGUI( + CCodecs *codecs, + const CObjectVector &formatIndices, + const UString &cmdArcPath, + NWildcard::CCensor &censor, + CUpdateOptions &options, + bool showDialog, + bool &messageWasDisplayed, + CUpdateCallbackGUI *callback, + HWND hwndParent) +{ + messageWasDisplayed = false; + bool needSetPath = true; + if (showDialog) + { + RINOK(ShowDialog(codecs, censor.CensorPaths, options, callback, hwndParent)) + needSetPath = false; + } + if (options.SfxMode && options.SfxModule.IsEmpty()) + { + options.SfxModule = NWindows::NDLL::GetModuleDirPrefix(); + options.SfxModule += kDefaultSfxModule; + } + + CThreadUpdating tu; + + tu.needSetPath = needSetPath; + + tu.codecs = codecs; + tu.formatIndices = &formatIndices; + tu.cmdArcPath = &cmdArcPath; + + tu.UpdateCallbackGUI = callback; + tu.UpdateCallbackGUI->ProgressDialog = &tu; + tu.UpdateCallbackGUI->Init(); + + UString title = LangString(IDS_PROGRESS_COMPRESSING); + if (!formatIndices.IsEmpty()) + { + const int fin = formatIndices[0].FormatIndex; + if (fin >= 0) + if (codecs->Formats[fin].Flags_HashHandler()) + title = LangString(IDS_CHECKSUM_CALCULATING); + } + + /* + if (hwndParent != 0) + { + tu.ProgressDialog.MainWindow = hwndParent; + // tu.ProgressDialog.MainTitle = fileName; + tu.ProgressDialog.MainAddTitle = title + L' '; + } + */ + + tu.WildcardCensor = &censor; + tu.Options = &options; + tu.IconID = IDI_ICON; + + RINOK(tu.Create(title, hwndParent)) + + messageWasDisplayed = tu.ThreadFinishedOK && tu.MessagesDisplayed; + return tu.Result; +} diff --git a/CPP/7zip/UI/GUI/UpdateGUI.h b/CPP/7zip/UI/GUI/UpdateGUI.h index 263e7dfb8..0c43a01b8 100644 --- a/CPP/7zip/UI/GUI/UpdateGUI.h +++ b/CPP/7zip/UI/GUI/UpdateGUI.h @@ -1,33 +1,33 @@ -// GUI/UpdateGUI.h - -#ifndef ZIP7_INC_UPDATE_GUI_H -#define ZIP7_INC_UPDATE_GUI_H - -#include "../Common/Update.h" - -#include "UpdateCallbackGUI.h" - -/* - callback->FailedFiles contains names of files for that there were problems. - RESULT can be S_OK, even if there are such warnings!!! - - RESULT = E_ABORT - user break. - RESULT != E_ABORT: - { - messageWasDisplayed = true - message was displayed already. - messageWasDisplayed = false - there was some internal error, so you must show error message. - } -*/ - -HRESULT UpdateGUI( - CCodecs *codecs, - const CObjectVector &formatIndices, - const UString &cmdArcPath2, - NWildcard::CCensor &censor, - CUpdateOptions &options, - bool showDialog, - bool &messageWasDisplayed, - CUpdateCallbackGUI *callback, - HWND hwndParent = NULL); - -#endif +// GUI/UpdateGUI.h + +#ifndef ZIP7_INC_UPDATE_GUI_H +#define ZIP7_INC_UPDATE_GUI_H + +#include "../Common/Update.h" + +#include "UpdateCallbackGUI.h" + +/* + callback->FailedFiles contains names of files for that there were problems. + RESULT can be S_OK, even if there are such warnings!!! + + RESULT = E_ABORT - user break. + RESULT != E_ABORT: + { + messageWasDisplayed = true - message was displayed already. + messageWasDisplayed = false - there was some internal error, so you must show error message. + } +*/ + +HRESULT UpdateGUI( + CCodecs *codecs, + const CObjectVector &formatIndices, + const UString &cmdArcPath2, + NWildcard::CCensor &censor, + CUpdateOptions &options, + bool showDialog, + bool &messageWasDisplayed, + CUpdateCallbackGUI *callback, + HWND hwndParent = NULL); + +#endif diff --git a/CPP/7zip/UI/GUI/makefile b/CPP/7zip/UI/GUI/makefile index 42d430278..22ae095aa 100644 --- a/CPP/7zip/UI/GUI/makefile +++ b/CPP/7zip/UI/GUI/makefile @@ -1,150 +1,150 @@ -PROG = 7zG.exe -CFLAGS = $(CFLAGS) \ - -DZ7_LANG \ - -DZ7_EXTERNAL_CODECS \ - -!IFDEF UNDER_CE -LIBS = $(LIBS) ceshell.lib Commctrl.lib -!ELSE -LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib gdi32.lib -CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE -# -DZ7_LONG_PATH -DZ7_LARGE_PAGES -!ENDIF - -GUI_OBJS = \ - $O\BenchmarkDialog.obj \ - $O\CompressDialog.obj \ - $O\ExtractDialog.obj \ - $O\ExtractGUI.obj \ - $O\GUI.obj \ - $O\HashGUI.obj \ - $O\UpdateCallbackGUI.obj \ - $O\UpdateCallbackGUI2.obj \ - $O\UpdateGUI.obj \ - -COMMON_OBJS = \ - $O\CommandLineParser.obj \ - $O\CRC.obj \ - $O\DynLimBuf.obj \ - $O\IntToString.obj \ - $O\Lang.obj \ - $O\ListFileUtils.obj \ - $O\MyString.obj \ - $O\MyVector.obj \ - $O\NewHandler.obj \ - $O\StringConvert.obj \ - $O\StringToInt.obj \ - $O\UTFConvert.obj \ - $O\Wildcard.obj \ - -WIN_OBJS = \ - $O\Clipboard.obj \ - $O\CommonDialog.obj \ - $O\DLL.obj \ - $O\ErrorMsg.obj \ - $O\FileDir.obj \ - $O\FileFind.obj \ - $O\FileIO.obj \ - $O\FileLink.obj \ - $O\FileName.obj \ - $O\FileSystem.obj \ - $O\MemoryGlobal.obj \ - $O\MemoryLock.obj \ - $O\PropVariant.obj \ - $O\PropVariantConv.obj \ - $O\Registry.obj \ - $O\ResourceString.obj \ - $O\Shell.obj \ - $O\Synchronization.obj \ - $O\System.obj \ - $O\SystemInfo.obj \ - $O\TimeUtils.obj \ - $O\Window.obj \ - -WIN_CTRL_OBJS = \ - $O\ComboBox.obj \ - $O\Dialog.obj \ - $O\ListView.obj \ - -7ZIP_COMMON_OBJS = \ - $O\CreateCoder.obj \ - $O\FilePathAutoRename.obj \ - $O\FileStreams.obj \ - $O\FilterCoder.obj \ - $O\LimitedStreams.obj \ - $O\MethodProps.obj \ - $O\MultiOutStream.obj \ - $O\ProgressUtils.obj \ - $O\PropId.obj \ - $O\StreamObjects.obj \ - $O\StreamUtils.obj \ - $O\UniqBlocks.obj \ - -UI_COMMON_OBJS = \ - $O\ArchiveCommandLine.obj \ - $O\ArchiveExtractCallback.obj \ - $O\ArchiveOpenCallback.obj \ - $O\Bench.obj \ - $O\DefaultName.obj \ - $O\EnumDirItems.obj \ - $O\Extract.obj \ - $O\ExtractingFilePath.obj \ - $O\HashCalc.obj \ - $O\LoadCodecs.obj \ - $O\OpenArchive.obj \ - $O\PropIDUtils.obj \ - $O\SetProperties.obj \ - $O\SortUtils.obj \ - $O\TempFiles.obj \ - $O\Update.obj \ - $O\UpdateAction.obj \ - $O\UpdateCallback.obj \ - $O\UpdatePair.obj \ - $O\UpdateProduce.obj \ - $O\WorkDir.obj \ - $O\ZipRegistry.obj \ - -AR_COMMON_OBJS = \ - $O\ItemNameUtils.obj \ - $O\OutStreamWithCRC.obj \ - -FM_OBJS = \ - $O\EditDialog.obj \ - $O\ExtractCallback.obj \ - $O\FormatUtils.obj \ - $O\HelpUtils.obj \ - $O\LangUtils.obj \ - $O\ListViewDialog.obj \ - $O\MemDialog.obj \ - $O\OpenCallback.obj \ - $O\ProgramLocation.obj \ - $O\PropertyName.obj \ - $O\RegistryUtils.obj \ - $O\SplitUtils.obj \ - $O\StringUtils.obj \ - $O\OverwriteDialog.obj \ - $O\PasswordDialog.obj \ - $O\ProgressDialog2.obj \ - -FM_OBJS = $(FM_OBJS) \ - $O\BrowseDialog.obj \ - $O\ComboDialog.obj \ - $O\SysIconUtils.obj \ - -EXPLORER_OBJS = \ - $O\MyMessages.obj \ - -COMPRESS_OBJS = \ - $O\CopyCoder.obj \ - -C_OBJS = \ - $O\Alloc.obj \ - $O\CpuArch.obj \ - $O\DllSecur.obj \ - $O\Sort.obj \ - $O\Threads.obj \ - -!include "../../Crc.mak" - - -!include "../../7zip.mak" +PROG = 7zG.exe +CFLAGS = $(CFLAGS) \ + -DZ7_LANG \ + -DZ7_EXTERNAL_CODECS \ + +!IFDEF UNDER_CE +LIBS = $(LIBS) ceshell.lib Commctrl.lib +!ELSE +LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib gdi32.lib +CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE +# -DZ7_LONG_PATH -DZ7_LARGE_PAGES +!ENDIF + +GUI_OBJS = \ + $O\BenchmarkDialog.obj \ + $O\CompressDialog.obj \ + $O\ExtractDialog.obj \ + $O\ExtractGUI.obj \ + $O\GUI.obj \ + $O\HashGUI.obj \ + $O\UpdateCallbackGUI.obj \ + $O\UpdateCallbackGUI2.obj \ + $O\UpdateGUI.obj \ + +COMMON_OBJS = \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\DynLimBuf.obj \ + $O\IntToString.obj \ + $O\Lang.obj \ + $O\ListFileUtils.obj \ + $O\MyString.obj \ + $O\MyVector.obj \ + $O\NewHandler.obj \ + $O\StringConvert.obj \ + $O\StringToInt.obj \ + $O\UTFConvert.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\Clipboard.obj \ + $O\CommonDialog.obj \ + $O\DLL.obj \ + $O\ErrorMsg.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileLink.obj \ + $O\FileName.obj \ + $O\FileSystem.obj \ + $O\MemoryGlobal.obj \ + $O\MemoryLock.obj \ + $O\PropVariant.obj \ + $O\PropVariantConv.obj \ + $O\Registry.obj \ + $O\ResourceString.obj \ + $O\Shell.obj \ + $O\Synchronization.obj \ + $O\System.obj \ + $O\SystemInfo.obj \ + $O\TimeUtils.obj \ + $O\Window.obj \ + +WIN_CTRL_OBJS = \ + $O\ComboBox.obj \ + $O\Dialog.obj \ + $O\ListView.obj \ + +7ZIP_COMMON_OBJS = \ + $O\CreateCoder.obj \ + $O\FilePathAutoRename.obj \ + $O\FileStreams.obj \ + $O\FilterCoder.obj \ + $O\LimitedStreams.obj \ + $O\MethodProps.obj \ + $O\MultiOutStream.obj \ + $O\ProgressUtils.obj \ + $O\PropId.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + $O\UniqBlocks.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveCommandLine.obj \ + $O\ArchiveExtractCallback.obj \ + $O\ArchiveOpenCallback.obj \ + $O\Bench.obj \ + $O\DefaultName.obj \ + $O\EnumDirItems.obj \ + $O\Extract.obj \ + $O\ExtractingFilePath.obj \ + $O\HashCalc.obj \ + $O\LoadCodecs.obj \ + $O\OpenArchive.obj \ + $O\PropIDUtils.obj \ + $O\SetProperties.obj \ + $O\SortUtils.obj \ + $O\TempFiles.obj \ + $O\Update.obj \ + $O\UpdateAction.obj \ + $O\UpdateCallback.obj \ + $O\UpdatePair.obj \ + $O\UpdateProduce.obj \ + $O\WorkDir.obj \ + $O\ZipRegistry.obj \ + +AR_COMMON_OBJS = \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + +FM_OBJS = \ + $O\EditDialog.obj \ + $O\ExtractCallback.obj \ + $O\FormatUtils.obj \ + $O\HelpUtils.obj \ + $O\LangUtils.obj \ + $O\ListViewDialog.obj \ + $O\MemDialog.obj \ + $O\OpenCallback.obj \ + $O\ProgramLocation.obj \ + $O\PropertyName.obj \ + $O\RegistryUtils.obj \ + $O\SplitUtils.obj \ + $O\StringUtils.obj \ + $O\OverwriteDialog.obj \ + $O\PasswordDialog.obj \ + $O\ProgressDialog2.obj \ + +FM_OBJS = $(FM_OBJS) \ + $O\BrowseDialog.obj \ + $O\ComboDialog.obj \ + $O\SysIconUtils.obj \ + +EXPLORER_OBJS = \ + $O\MyMessages.obj \ + +COMPRESS_OBJS = \ + $O\CopyCoder.obj \ + +C_OBJS = \ + $O\Alloc.obj \ + $O\CpuArch.obj \ + $O\DllSecur.obj \ + $O\Sort.obj \ + $O\Threads.obj \ + +!include "../../Crc.mak" + + +!include "../../7zip.mak" diff --git a/CPP/7zip/UI/GUI/resource.rc b/CPP/7zip/UI/GUI/resource.rc index 762061250..08ef00adf 100644 --- a/CPP/7zip/UI/GUI/resource.rc +++ b/CPP/7zip/UI/GUI/resource.rc @@ -1,26 +1,26 @@ -#include "../../MyVersionInfo.rc" -// #include - -#include "resource2.rc" -#include "resource3.rc" - -#include "../FileManager/resourceGui.rc" - -MY_VERSION_INFO(MY_VFT_APP, "7-Zip GUI", "7zg", "7zg.exe") - -IDI_ICON ICON "FM.ico" - -#ifndef UNDER_CE -1 24 MOVEABLE PURE "7zG.exe.manifest" -#endif - -#include "../FileManager/PropertyName.rc" -#include "../FileManager/MemDialog.rc" -#include "../FileManager/OverwriteDialog.rc" -#include "../FileManager/PasswordDialog.rc" -#include "../FileManager/ProgressDialog2.rc" -#include "Extract.rc" -#include "../FileManager/BrowseDialog.rc" -#include "../FileManager/ComboDialog.rc" -#include "../FileManager/EditDialog.rc" -#include "../FileManager/ListViewDialog.rc" +#include "../../MyVersionInfo.rc" +// #include + +#include "resource2.rc" +#include "resource3.rc" + +#include "../FileManager/resourceGui.rc" + +MY_VERSION_INFO(MY_VFT_APP, "7-Zip GUI", "7zg", "7zg.exe") + +IDI_ICON ICON "FM.ico" + +#ifndef UNDER_CE +1 24 MOVEABLE PURE "7zG.exe.manifest" +#endif + +#include "../FileManager/PropertyName.rc" +#include "../FileManager/MemDialog.rc" +#include "../FileManager/OverwriteDialog.rc" +#include "../FileManager/PasswordDialog.rc" +#include "../FileManager/ProgressDialog2.rc" +#include "Extract.rc" +#include "../FileManager/BrowseDialog.rc" +#include "../FileManager/ComboDialog.rc" +#include "../FileManager/EditDialog.rc" +#include "../FileManager/ListViewDialog.rc" diff --git a/CPP/7zip/UI/GUI/resource2.h b/CPP/7zip/UI/GUI/resource2.h index 152e71f8a..cd8829245 100644 --- a/CPP/7zip/UI/GUI/resource2.h +++ b/CPP/7zip/UI/GUI/resource2.h @@ -1,2 +1,2 @@ -#define IDS_PROGRESS_COMPRESSING 3301 -#define IDS_ARCHIVES_COLON 3907 +#define IDS_PROGRESS_COMPRESSING 3301 +#define IDS_ARCHIVES_COLON 3907 diff --git a/CPP/7zip/UI/GUI/resource2.rc b/CPP/7zip/UI/GUI/resource2.rc index 042154e62..49534f504 100644 --- a/CPP/7zip/UI/GUI/resource2.rc +++ b/CPP/7zip/UI/GUI/resource2.rc @@ -1,10 +1,10 @@ -#include "ExtractDialog.rc" -#include "CompressDialog.rc" -#include "BenchmarkDialog.rc" -#include "resource2.h" - -STRINGTABLE -BEGIN - IDS_PROGRESS_COMPRESSING "Compressing" - IDS_ARCHIVES_COLON "Archives:" -END +#include "ExtractDialog.rc" +#include "CompressDialog.rc" +#include "BenchmarkDialog.rc" +#include "resource2.h" + +STRINGTABLE +BEGIN + IDS_PROGRESS_COMPRESSING "Compressing" + IDS_ARCHIVES_COLON "Archives:" +END diff --git a/CPP/7zip/UI/GUI/resource3.h b/CPP/7zip/UI/GUI/resource3.h index 4c33bb92b..c25737fa1 100644 --- a/CPP/7zip/UI/GUI/resource3.h +++ b/CPP/7zip/UI/GUI/resource3.h @@ -1,10 +1,10 @@ -#define IDS_PROGRESS_REMOVE 3305 - -#define IDS_PROGRESS_ADD 3320 -#define IDS_PROGRESS_UPDATE 3321 -#define IDS_PROGRESS_ANALYZE 3322 -#define IDS_PROGRESS_REPLICATE 3323 -#define IDS_PROGRESS_REPACK 3324 - -#define IDS_PROGRESS_DELETE 3326 -#define IDS_PROGRESS_HEADER 3327 +#define IDS_PROGRESS_REMOVE 3305 + +#define IDS_PROGRESS_ADD 3320 +#define IDS_PROGRESS_UPDATE 3321 +#define IDS_PROGRESS_ANALYZE 3322 +#define IDS_PROGRESS_REPLICATE 3323 +#define IDS_PROGRESS_REPACK 3324 + +#define IDS_PROGRESS_DELETE 3326 +#define IDS_PROGRESS_HEADER 3327 diff --git a/CPP/7zip/UI/GUI/resource3.rc b/CPP/7zip/UI/GUI/resource3.rc index 9f533be72..cfc8bc35e 100644 --- a/CPP/7zip/UI/GUI/resource3.rc +++ b/CPP/7zip/UI/GUI/resource3.rc @@ -1,15 +1,15 @@ -#include "resource3.h" - -STRINGTABLE -BEGIN - IDS_PROGRESS_REMOVE "Removing" - - IDS_PROGRESS_ADD "Adding" - IDS_PROGRESS_UPDATE "Updating" - IDS_PROGRESS_ANALYZE "Analyzing" - IDS_PROGRESS_REPLICATE "Replicating" - IDS_PROGRESS_REPACK "Repacking" - - IDS_PROGRESS_DELETE "Deleting" - IDS_PROGRESS_HEADER "Header creating" -END +#include "resource3.h" + +STRINGTABLE +BEGIN + IDS_PROGRESS_REMOVE "Removing" + + IDS_PROGRESS_ADD "Adding" + IDS_PROGRESS_UPDATE "Updating" + IDS_PROGRESS_ANALYZE "Analyzing" + IDS_PROGRESS_REPLICATE "Replicating" + IDS_PROGRESS_REPACK "Repacking" + + IDS_PROGRESS_DELETE "Deleting" + IDS_PROGRESS_HEADER "Header creating" +END diff --git a/CPP/7zip/UI/makefile b/CPP/7zip/UI/makefile index 9d51814f3..1b0cdbe18 100644 --- a/CPP/7zip/UI/makefile +++ b/CPP/7zip/UI/makefile @@ -1,12 +1,12 @@ -DIRS = \ - Client7z\~ \ - Console\~ \ - Explorer\~ \ - Far\~ \ - FileManager\~ \ - GUI\~ \ - -all: $(DIRS) - -$(DIRS): -!include "../SubBuild.mak" +DIRS = \ + Client7z\~ \ + Console\~ \ + Explorer\~ \ + Far\~ \ + FileManager\~ \ + GUI\~ \ + +all: $(DIRS) + +$(DIRS): +!include "../SubBuild.mak" diff --git a/CPP/7zip/cmpl_clang.mak b/CPP/7zip/cmpl_clang.mak index 9e17022cc..e62e1e62f 100644 --- a/CPP/7zip/cmpl_clang.mak +++ b/CPP/7zip/cmpl_clang.mak @@ -1,3 +1,3 @@ -include ../../var_clang.mak -include ../../warn_clang.mak -include makefile.gcc +include ../../var_clang.mak +include ../../warn_clang.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_clang_arm64.mak b/CPP/7zip/cmpl_clang_arm64.mak index bc57d3372..3f6b02bfc 100644 --- a/CPP/7zip/cmpl_clang_arm64.mak +++ b/CPP/7zip/cmpl_clang_arm64.mak @@ -1,3 +1,3 @@ -include ../../var_clang_arm64.mak -include ../../warn_clang.mak -include makefile.gcc +include ../../var_clang_arm64.mak +include ../../warn_clang.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_clang_x64.mak b/CPP/7zip/cmpl_clang_x64.mak index 959042c2f..b61e2af66 100644 --- a/CPP/7zip/cmpl_clang_x64.mak +++ b/CPP/7zip/cmpl_clang_x64.mak @@ -1,3 +1,3 @@ -include ../../var_clang_x64.mak -include ../../warn_clang.mak -include makefile.gcc +include ../../var_clang_x64.mak +include ../../warn_clang.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_clang_x86.mak b/CPP/7zip/cmpl_clang_x86.mak index 9b9150005..0e5cb76c0 100644 --- a/CPP/7zip/cmpl_clang_x86.mak +++ b/CPP/7zip/cmpl_clang_x86.mak @@ -1,3 +1,3 @@ -include ../../var_clang_x86.mak -include ../../warn_clang.mak -include makefile.gcc +include ../../var_clang_x86.mak +include ../../warn_clang.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_gcc.mak b/CPP/7zip/cmpl_gcc.mak index ebfa1c606..7a1aef2e3 100644 --- a/CPP/7zip/cmpl_gcc.mak +++ b/CPP/7zip/cmpl_gcc.mak @@ -1,3 +1,3 @@ -include ../../var_gcc.mak -include ../../warn_gcc.mak -include makefile.gcc +include ../../var_gcc.mak +include ../../warn_gcc.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_gcc_arm.mak b/CPP/7zip/cmpl_gcc_arm.mak index 525f9b94e..6671d58d9 100644 --- a/CPP/7zip/cmpl_gcc_arm.mak +++ b/CPP/7zip/cmpl_gcc_arm.mak @@ -1,3 +1,3 @@ -include ../../var_gcc_arm.mak -include ../../warn_gcc.mak -include makefile.gcc +include ../../var_gcc_arm.mak +include ../../warn_gcc.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_gcc_arm64.mak b/CPP/7zip/cmpl_gcc_arm64.mak index ba89d46c7..53a858447 100644 --- a/CPP/7zip/cmpl_gcc_arm64.mak +++ b/CPP/7zip/cmpl_gcc_arm64.mak @@ -1,3 +1,3 @@ -include ../../var_gcc_arm64.mak -include ../../warn_gcc.mak -include makefile.gcc +include ../../var_gcc_arm64.mak +include ../../warn_gcc.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_gcc_x64.mak b/CPP/7zip/cmpl_gcc_x64.mak index 76ad1ea03..500c30e47 100644 --- a/CPP/7zip/cmpl_gcc_x64.mak +++ b/CPP/7zip/cmpl_gcc_x64.mak @@ -1,3 +1,3 @@ -include ../../var_gcc_x64.mak -include ../../warn_gcc.mak -include makefile.gcc +include ../../var_gcc_x64.mak +include ../../warn_gcc.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_gcc_x86.mak b/CPP/7zip/cmpl_gcc_x86.mak index a538ae62a..e76870707 100644 --- a/CPP/7zip/cmpl_gcc_x86.mak +++ b/CPP/7zip/cmpl_gcc_x86.mak @@ -1,3 +1,3 @@ -include ../../var_gcc_x86.mak -include ../../warn_gcc.mak -include makefile.gcc +include ../../var_gcc_x86.mak +include ../../warn_gcc.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_mac_arm64.mak b/CPP/7zip/cmpl_mac_arm64.mak index 60be4b609..941028e95 100644 --- a/CPP/7zip/cmpl_mac_arm64.mak +++ b/CPP/7zip/cmpl_mac_arm64.mak @@ -1,3 +1,3 @@ -include ../../var_mac_arm64.mak -include ../../warn_clang_mac.mak -include makefile.gcc +include ../../var_mac_arm64.mak +include ../../warn_clang_mac.mak +include makefile.gcc diff --git a/CPP/7zip/cmpl_mac_x64.mak b/CPP/7zip/cmpl_mac_x64.mak index 262e743ea..d3aa03967 100644 --- a/CPP/7zip/cmpl_mac_x64.mak +++ b/CPP/7zip/cmpl_mac_x64.mak @@ -1,3 +1,3 @@ -include ../../var_mac_x64.mak -include ../../warn_clang_mac.mak -include makefile.gcc +include ../../var_mac_x64.mak +include ../../warn_clang_mac.mak +include makefile.gcc diff --git a/CPP/7zip/makefile b/CPP/7zip/makefile index 422d2d25c..9d31e6bdc 100644 --- a/CPP/7zip/makefile +++ b/CPP/7zip/makefile @@ -1,10 +1,10 @@ -DIRS = \ - UI\~ \ - Bundles\~ \ - -all: $(DIRS) - -$(DIRS): - cd $(@D) - $(MAKE) -nologo - cd .. +DIRS = \ + UI\~ \ + Bundles\~ \ + +all: $(DIRS) + +$(DIRS): + cd $(@D) + $(MAKE) -nologo + cd .. diff --git a/CPP/7zip/var_clang.mak b/CPP/7zip/var_clang.mak index ee265698e..a6df26e77 100644 --- a/CPP/7zip/var_clang.mak +++ b/CPP/7zip/var_clang.mak @@ -1,11 +1,11 @@ -PLATFORM= -O=b/c -IS_X64= -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM= -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM= +O=b/c +IS_X64= +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM= +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/CPP/7zip/var_clang_arm64.mak b/CPP/7zip/var_clang_arm64.mak index ea170b858..ec81d2661 100644 --- a/CPP/7zip/var_clang_arm64.mak +++ b/CPP/7zip/var_clang_arm64.mak @@ -1,19 +1,19 @@ -PLATFORM=arm64 -O=b/c_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64=1 -CROSS_COMPILE= - -MY_ARCH=-march=armv8-a -MY_ARCH=-march=armv8-a+crypto+crc -MY_ARCH=-march=armv8.3-a+crypto+crc -MY_ARCH= - -USE_ASM= -USE_ASM=1 - -ASM_FLAGS=-Wno-unused-macros -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=arm64 +O=b/c_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64=1 +CROSS_COMPILE= + +MY_ARCH=-march=armv8-a +MY_ARCH=-march=armv8-a+crypto+crc +MY_ARCH=-march=armv8.3-a+crypto+crc +MY_ARCH= + +USE_ASM= +USE_ASM=1 + +ASM_FLAGS=-Wno-unused-macros +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/CPP/7zip/var_clang_x64.mak b/CPP/7zip/var_clang_x64.mak index b35f0cca4..34e1b49c5 100644 --- a/CPP/7zip/var_clang_x64.mak +++ b/CPP/7zip/var_clang_x64.mak @@ -1,11 +1,11 @@ -PLATFORM=x64 -O=b/c_$(PLATFORM) -IS_X64=1 -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM=1 -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=x64 +O=b/c_$(PLATFORM) +IS_X64=1 +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM=1 +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/CPP/7zip/var_clang_x86.mak b/CPP/7zip/var_clang_x86.mak index d18f0ae12..bd2317c29 100644 --- a/CPP/7zip/var_clang_x86.mak +++ b/CPP/7zip/var_clang_x86.mak @@ -1,11 +1,11 @@ -PLATFORM=x86 -O=b/c_$(PLATFORM) -IS_X64= -IS_X86=1 -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-m32 -USE_ASM=1 -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=x86 +O=b/c_$(PLATFORM) +IS_X64= +IS_X86=1 +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-m32 +USE_ASM=1 +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/CPP/7zip/var_gcc.mak b/CPP/7zip/var_gcc.mak index 803c8de9d..664491cf2 100644 --- a/CPP/7zip/var_gcc.mak +++ b/CPP/7zip/var_gcc.mak @@ -1,12 +1,12 @@ -PLATFORM= -O=b/g -IS_X64= -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH= -USE_ASM= -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ - -# -march=armv8-a+crc+crypto +PLATFORM= +O=b/g +IS_X64= +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH= +USE_ASM= +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ + +# -march=armv8-a+crc+crypto diff --git a/CPP/7zip/var_gcc_arm.mak b/CPP/7zip/var_gcc_arm.mak index f7696d9f5..7527e4077 100644 --- a/CPP/7zip/var_gcc_arm.mak +++ b/CPP/7zip/var_gcc_arm.mak @@ -1,34 +1,34 @@ -PLATFORM=arm -O=b/g_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64= - -CROSS_COMPILE_ABI= -CROSS_COMPILE_ABI=arm-linux-musleabi -CROSS_COMPILE_ABI=arm-linux-musleabihf -CROSS_COMPILE_ABI=aarch64-linux-musl -CROSS_COMPILE_ABI=arm-linux-gnueabi -CROSS_COMPILE_ABI=arm-linux-gnueabihf - -COMPILER_VER_POSTFIX=-12 -COMPILER_VER_POSTFIX= - -CROSS_COMPILE_PREFIX= - -CROSS_COMPILE=$(CROSS_COMPILE_PREFIX)$(CROSS_COMPILE_ABI)- -CROSS_COMPILE= - -MY_ARCH= -MY_ARCH=-mtune=cortex-a53 -march=armv7-a -MY_ARCH=-mtune=cortex-a53 -march=armv4 -MY_ARCH=-mtune=cortex-a53 - -USE_ASM= - -LDFLAGS_STATIC_3=-static -LDFLAGS_STATIC_3= - -CC=$(CROSS_COMPILE)gcc$(COMPILER_VER_POSTFIX) -CXX=$(CROSS_COMPILE)g++$(COMPILER_VER_POSTFIX) -# -marm -march=armv5t -march=armv6 -march=armv7-a -march=armv8-a -march=armv8-a+crc+crypto +PLATFORM=arm +O=b/g_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64= + +CROSS_COMPILE_ABI= +CROSS_COMPILE_ABI=arm-linux-musleabi +CROSS_COMPILE_ABI=arm-linux-musleabihf +CROSS_COMPILE_ABI=aarch64-linux-musl +CROSS_COMPILE_ABI=arm-linux-gnueabi +CROSS_COMPILE_ABI=arm-linux-gnueabihf + +COMPILER_VER_POSTFIX=-12 +COMPILER_VER_POSTFIX= + +CROSS_COMPILE_PREFIX= + +CROSS_COMPILE=$(CROSS_COMPILE_PREFIX)$(CROSS_COMPILE_ABI)- +CROSS_COMPILE= + +MY_ARCH= +MY_ARCH=-mtune=cortex-a53 -march=armv7-a +MY_ARCH=-mtune=cortex-a53 -march=armv4 +MY_ARCH=-mtune=cortex-a53 + +USE_ASM= + +LDFLAGS_STATIC_3=-static +LDFLAGS_STATIC_3= + +CC=$(CROSS_COMPILE)gcc$(COMPILER_VER_POSTFIX) +CXX=$(CROSS_COMPILE)g++$(COMPILER_VER_POSTFIX) +# -marm -march=armv5t -march=armv6 -march=armv7-a -march=armv8-a -march=armv8-a+crc+crypto diff --git a/CPP/7zip/var_gcc_arm64.mak b/CPP/7zip/var_gcc_arm64.mak index 562cfaa6d..4bbb687db 100644 --- a/CPP/7zip/var_gcc_arm64.mak +++ b/CPP/7zip/var_gcc_arm64.mak @@ -1,12 +1,12 @@ -PLATFORM=arm64 -O=b/g_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64=1 -CROSS_COMPILE= -MY_ARCH=-mtune=cortex-a53 -USE_ASM=1 -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ - -# -march=armv8-a+crc+crypto +PLATFORM=arm64 +O=b/g_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64=1 +CROSS_COMPILE= +MY_ARCH=-mtune=cortex-a53 +USE_ASM=1 +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ + +# -march=armv8-a+crc+crypto diff --git a/CPP/7zip/var_gcc_x64.mak b/CPP/7zip/var_gcc_x64.mak index 06e422805..aeea20346 100644 --- a/CPP/7zip/var_gcc_x64.mak +++ b/CPP/7zip/var_gcc_x64.mak @@ -1,11 +1,11 @@ -PLATFORM=x64 -O=b/g_$(PLATFORM) -IS_X64=1 -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-mavx512f -mavx512vl -MY_ARCH= -USE_ASM=1 -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ +PLATFORM=x64 +O=b/g_$(PLATFORM) +IS_X64=1 +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-mavx512f -mavx512vl +MY_ARCH= +USE_ASM=1 +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ diff --git a/CPP/7zip/var_gcc_x86.mak b/CPP/7zip/var_gcc_x86.mak index 3adf4a84a..f0718ec71 100644 --- a/CPP/7zip/var_gcc_x86.mak +++ b/CPP/7zip/var_gcc_x86.mak @@ -1,10 +1,10 @@ -PLATFORM=x86 -O=b/g_$(PLATFORM) -IS_X64= -IS_X86=1 -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-m32 -USE_ASM=1 -CC=$(CROSS_COMPILE)gcc -CXX=$(CROSS_COMPILE)g++ +PLATFORM=x86 +O=b/g_$(PLATFORM) +IS_X64= +IS_X86=1 +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-m32 +USE_ASM=1 +CC=$(CROSS_COMPILE)gcc +CXX=$(CROSS_COMPILE)g++ diff --git a/CPP/7zip/var_mac_arm64.mak b/CPP/7zip/var_mac_arm64.mak index 4a18c48d6..746e6db19 100644 --- a/CPP/7zip/var_mac_arm64.mak +++ b/CPP/7zip/var_mac_arm64.mak @@ -1,13 +1,13 @@ -PLATFORM=arm64 -O=b/m_$(PLATFORM) -IS_X64= -IS_X86= -IS_ARM64=1 -CROSS_COMPILE= -#use this code to reduce features -MY_ARCH=-arch arm64 -march=armv8-a -MY_ARCH=-arch arm64 -USE_ASM=1 -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=arm64 +O=b/m_$(PLATFORM) +IS_X64= +IS_X86= +IS_ARM64=1 +CROSS_COMPILE= +#use this code to reduce features +MY_ARCH=-arch arm64 -march=armv8-a +MY_ARCH=-arch arm64 +USE_ASM=1 +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/CPP/7zip/var_mac_x64.mak b/CPP/7zip/var_mac_x64.mak index 92b15c8b7..13d7aa7fe 100644 --- a/CPP/7zip/var_mac_x64.mak +++ b/CPP/7zip/var_mac_x64.mak @@ -1,11 +1,11 @@ -PLATFORM=x64 -O=b/m_$(PLATFORM) -IS_X64=1 -IS_X86= -IS_ARM64= -CROSS_COMPILE= -MY_ARCH=-arch x86_64 -USE_ASM= -CC=$(CROSS_COMPILE)clang -CXX=$(CROSS_COMPILE)clang++ -USE_CLANG=1 +PLATFORM=x64 +O=b/m_$(PLATFORM) +IS_X64=1 +IS_X86= +IS_ARM64= +CROSS_COMPILE= +MY_ARCH=-arch x86_64 +USE_ASM= +CC=$(CROSS_COMPILE)clang +CXX=$(CROSS_COMPILE)clang++ +USE_CLANG=1 diff --git a/CPP/7zip/warn_clang.mak b/CPP/7zip/warn_clang.mak index 01d3d8dda..0d0073070 100644 --- a/CPP/7zip/warn_clang.mak +++ b/CPP/7zip/warn_clang.mak @@ -1,3 +1,3 @@ -CFLAGS_WARN = -Weverything -Wfatal-errors -# CXX_STD_FLAGS = -std=c++11 -# CXX_STD_FLAGS = +CFLAGS_WARN = -Weverything -Wfatal-errors +# CXX_STD_FLAGS = -std=c++11 +# CXX_STD_FLAGS = diff --git a/CPP/7zip/warn_clang_mac.mak b/CPP/7zip/warn_clang_mac.mak index 3f229976a..ed936c588 100644 --- a/CPP/7zip/warn_clang_mac.mak +++ b/CPP/7zip/warn_clang_mac.mak @@ -1,9 +1,9 @@ -CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories -CXX_STD_FLAGS = -std=c++98 -CXX_STD_FLAGS = -std=c++11 -CXX_STD_FLAGS = -std=c++14 -CXX_STD_FLAGS = -std=c++17 -CXX_STD_FLAGS = -std=c++20 -CXX_STD_FLAGS = -std=c++23 - -CXX_STD_FLAGS = -std=c++11 +CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories +CXX_STD_FLAGS = -std=c++98 +CXX_STD_FLAGS = -std=c++11 +CXX_STD_FLAGS = -std=c++14 +CXX_STD_FLAGS = -std=c++17 +CXX_STD_FLAGS = -std=c++20 +CXX_STD_FLAGS = -std=c++23 + +CXX_STD_FLAGS = -std=c++11 diff --git a/CPP/7zip/warn_gcc.mak b/CPP/7zip/warn_gcc.mak index ec9e9ecd4..6152ab12d 100644 --- a/CPP/7zip/warn_gcc.mak +++ b/CPP/7zip/warn_gcc.mak @@ -1,46 +1,55 @@ -CFLAGS_WARN_GCC_4_8 = \ - -Waddress \ - -Waggressive-loop-optimizations \ - -Wattributes \ - -Wcast-align \ - -Wcomment \ - -Wdiv-by-zero \ - -Wformat-contains-nul \ - -Winit-self \ - -Wint-to-pointer-cast \ - -Wunused \ - -Wunused-macros \ - -CFLAGS_WARN_GCC_6 = $(CFLAGS_WARN_GCC_4_8)\ - -Wbool-compare \ - -Wduplicated-cond \ - -# -Wno-strict-aliasing - -CFLAGS_WARN_GCC_9 = $(CFLAGS_WARN_GCC_6)\ - -Waddress-of-packed-member \ - -Wbool-operation \ - -Wcast-align=strict \ - -Wconversion \ - -Wdangling-else \ - -Wduplicated-branches \ - -Wimplicit-fallthrough=5 \ - -Wint-in-bool-context \ - -Wmaybe-uninitialized \ - -Wmisleading-indentation \ - -Wmissing-attributes - -# In C: -Wsign-conversion enabled also by -Wconversion -# -Wno-sign-conversion \ - - -CFLAGS_WARN_GCC_PPMD_UNALIGNED = \ - -Wno-strict-aliasing \ - - -CFLAGS_WARN = $(CFLAGS_WARN_GCC_4_8) -CFLAGS_WARN = $(CFLAGS_WARN_GCC_6) -CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) - -# CXX_STD_FLAGS = -std=c++11 -# CXX_STD_FLAGS = +CFLAGS_WARN_GCC_4_8 = \ + -Waddress \ + -Waggressive-loop-optimizations \ + -Wattributes \ + -Wcast-align \ + -Wcomment \ + -Wdiv-by-zero \ + -Wformat-contains-nul \ + -Winit-self \ + -Wint-to-pointer-cast \ + -Wunused \ + -Wunused-macros \ + +CFLAGS_WARN_GCC_5 = $(CFLAGS_WARN_GCC_4_8)\ + -Wbool-compare \ + +CFLAGS_WARN_GCC_6 = $(CFLAGS_WARN_GCC_5)\ + -Wduplicated-cond \ + +# -Wno-strict-aliasing + +CFLAGS_WARN_GCC_7 = $(CFLAGS_WARN_GCC_6)\ + -Wbool-operation \ + -Wconversion \ + -Wdangling-else \ + -Wduplicated-branches \ + -Wimplicit-fallthrough=5 \ + -Wint-in-bool-context \ + -Wmaybe-uninitialized \ + -Wmisleading-indentation \ + +CFLAGS_WARN_GCC_8 = $(CFLAGS_WARN_GCC_7)\ + -Wcast-align=strict \ + -Wmissing-attributes + +CFLAGS_WARN_GCC_9 = $(CFLAGS_WARN_GCC_8)\ + -Waddress-of-packed-member \ + +# In C: -Wsign-conversion enabled also by -Wconversion +# -Wno-sign-conversion \ + + +CFLAGS_WARN_GCC_PPMD_UNALIGNED = \ + -Wno-strict-aliasing \ + + +CFLAGS_WARN = $(CFLAGS_WARN_GCC_4_8) +CFLAGS_WARN = $(CFLAGS_WARN_GCC_5) +CFLAGS_WARN = $(CFLAGS_WARN_GCC_6) +CFLAGS_WARN = $(CFLAGS_WARN_GCC_7) +CFLAGS_WARN = $(CFLAGS_WARN_GCC_8) +CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) + +# CXX_STD_FLAGS = -std=c++11 +# CXX_STD_FLAGS = diff --git a/CPP/Build.mak b/CPP/Build.mak index 81992d428..afb7ae877 100644 --- a/CPP/Build.mak +++ b/CPP/Build.mak @@ -1,246 +1,246 @@ -LIBS = $(LIBS) oleaut32.lib ole32.lib - -# CFLAGS = $(CFLAGS) -DZ7_NO_UNICODE -!IFNDEF MY_NO_UNICODE -# CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE -!ENDIF - -!IF "$(CC)" != "clang-cl" -# for link time code generation: -# CFLAGS = $(CFLAGS) -GL -!ENDIF - -!IFNDEF O -!IFDEF PLATFORM -O=$(PLATFORM) -!ELSE -O=o -!ENDIF -!ENDIF - -!IF "$(CC)" != "clang-cl" -# CFLAGS = $(CFLAGS) -FAsc -Fa$O/asm/ -!ENDIF - -# LFLAGS = $(LFLAGS) /guard:cf - - -!IF "$(PLATFORM)" == "x64" -MY_ML = ml64 -WX -#-Dx64 -!ELSEIF "$(PLATFORM)" == "arm64" -MY_ML = armasm64 -!ELSEIF "$(PLATFORM)" == "arm" -MY_ML = armasm -WX -!ELSE -MY_ML = ml -WX -# -DABI_CDECL -!ENDIF - -# MY_ML = "$(MY_ML) -Fl$O\asm\ - - -!IFDEF UNDER_CE -RFLAGS = $(RFLAGS) -dUNDER_CE -!IFDEF MY_CONSOLE -LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup -!ENDIF -!ELSE -!IFDEF OLD_COMPILER -LFLAGS = $(LFLAGS) -OPT:NOWIN98 -!ENDIF -!IF "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" -CFLAGS = $(CFLAGS) -Gr -!ENDIF -LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib -!ENDIF - -!IF "$(PLATFORM)" == "arm" -COMPL_ASM = $(MY_ML) $** $O/$(*B).obj -!ELSEIF "$(PLATFORM)" == "arm64" -COMPL_ASM = $(MY_ML) $** $O/$(*B).obj -!ELSE -COMPL_ASM = $(MY_ML) -c -Fo$O/ $** -!ENDIF - -!IFDEF OLD_COMPILER -CFLAGS_WARN_LEVEL = -W4 -!ELSE -CFLAGS_WARN_LEVEL = -Wall -!ENDIF - -CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF - -!IF "$(CC)" == "clang-cl" - -CFLAGS = $(CFLAGS) \ - -Werror \ - -Wall \ - -Wextra \ - -Weverything \ - -Wfatal-errors \ - -!ENDIF - -# !IFDEF MY_DYNAMIC_LINK -!IF "$(MY_DYNAMIC_LINK)" != "" -CFLAGS = $(CFLAGS) -MD -!ELSE -!IFNDEF MY_SINGLE_THREAD -CFLAGS = $(CFLAGS) -MT -!ENDIF -!ENDIF - - -CFLAGS = $(CFLAGS_COMMON) $(CFLAGS) - - -!IFNDEF OLD_COMPILER - -CFLAGS = $(CFLAGS) -GS- -Zc:wchar_t -!IFDEF VCTOOLSVERSION -!IF "$(VCTOOLSVERSION)" >= "14.00" -!IF "$(CC)" != "clang-cl" -CFLAGS = $(CFLAGS) -Zc:throwingNew -!ENDIF -!ENDIF -!ELSE -# -Zc:forScope is default in VS2010. so we need it only for older versions -CFLAGS = $(CFLAGS) -Zc:forScope -!ENDIF - -!IFNDEF UNDER_CE -!IF "$(CC)" != "clang-cl" -CFLAGS = $(CFLAGS) -MP4 -!ENDIF -!IFNDEF PLATFORM -# CFLAGS = $(CFLAGS) -arch:IA32 -!ENDIF -!ENDIF - -!ENDIF - - -!IFDEF MY_CONSOLE -CFLAGS = $(CFLAGS) -D_CONSOLE -!ENDIF - -!IFNDEF UNDER_CE -!IF "$(PLATFORM)" == "arm" -CFLAGS = $(CFLAGS) -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE -!ENDIF -!ENDIF - -!IF "$(PLATFORM)" == "x64" -CFLAGS_O1 = $(CFLAGS) -O1 -!ELSE -CFLAGS_O1 = $(CFLAGS) -O1 -!ENDIF -CFLAGS_O2 = $(CFLAGS) -O2 - -LFLAGS = $(LFLAGS) -nologo -OPT:REF -OPT:ICF -INCREMENTAL:NO - -!IFNDEF UNDER_CE -LFLAGS = $(LFLAGS) /LARGEADDRESSAWARE -!ENDIF - -!IFDEF DEF_FILE -LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE) -!ELSE -!IF defined(MY_FIXED) && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" -LFLAGS = $(LFLAGS) /FIXED -!ELSE -LFLAGS = $(LFLAGS) /FIXED:NO -!ENDIF -# /BASE:0x400000 -!ENDIF - -!IF "$(PLATFORM)" == "arm64" -# we can get better compression ratio with ARM64 filter if we change alignment to 4096 -# LFLAGS = $(LFLAGS) /FILEALIGN:4096 -!ENDIF - - - -# !IF "$(PLATFORM)" == "x64" - -!IFDEF SUB_SYS_VER - -MY_SUB_SYS_VER=5.02 - -!IFDEF MY_CONSOLE -LFLAGS = $(LFLAGS) /SUBSYSTEM:console,$(MY_SUB_SYS_VER) -!ELSE -LFLAGS = $(LFLAGS) /SUBSYSTEM:windows,$(MY_SUB_SYS_VER) -!ENDIF - -!ENDIF - - -!IF "$(PLATFORM)" == "arm64" -CLANG_FLAGS_TARGET = --target=arm64-pc-windows-msvc -!ENDIF - -COMPL_CLANG_SPEC=clang-cl $(CLANG_FLAGS_TARGET) -COMPL_ASM_CLANG = $(COMPL_CLANG_SPEC) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX $** -# COMPL_C_CLANG = $(COMPL_CLANG_SPEC) $(CFLAGS_O2) - - -PROGPATH = $O\$(PROG) - -COMPL_O1 = $(CC) $(CFLAGS_O1) $** -COMPL_O2 = $(CC) $(CFLAGS_O2) $** -COMPL_PCH = $(CC) $(CFLAGS_O1) -Yc"StdAfx.h" -Fp$O/a.pch $** -COMPL = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $** -COMPLB = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $< -COMPLB_O2 = $(CC) $(CFLAGS_O2) $< -# COMPLB_O2 = $(CC) $(CFLAGS_O2) -Yu"StdAfx.h" -Fp$O/a.pch $< - -CFLAGS_C_ALL = $(CFLAGS_O2) $(CFLAGS_C_SPEC) - -CCOMPL_PCH = $(CC) $(CFLAGS_C_ALL) -Yc"Precomp.h" -Fp$O/a.pch $** -CCOMPL_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $** -CCOMPLB_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $< -CCOMPL = $(CC) $(CFLAGS_C_ALL) $** -CCOMPLB = $(CC) $(CFLAGS_C_ALL) $< - -!IF "$(CC)" == "clang-cl" -COMPL = $(COMPL) -FI StdAfx.h -COMPLB = $(COMPLB) -FI StdAfx.h -CCOMPL_USE = $(CCOMPL_USE) -FI Precomp.h -CCOMPLB_USE = $(CCOMPLB_USE) -FI Precomp.h -!ENDIF - -all: $(PROGPATH) - -clean: - -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch $O\*.asm - -$O: - if not exist "$O" mkdir "$O" -$O/asm: - if not exist "$O/asm" mkdir "$O/asm" - -!IF "$(CC)" != "clang-cl" -# for link time code generation: -# LFLAGS = $(LFLAGS) -LTCG -!ENDIF - -$(PROGPATH): $O $O/asm $(OBJS) $(DEF_FILE) - link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS) - -!IFNDEF NO_DEFAULT_RES -$O\resource.res: $(*B).rc - rc $(RFLAGS) -fo$@ $** -!ENDIF -$O\StdAfx.obj: $(*B).cpp - $(COMPL_PCH) - -predef: empty.c - $(CCOMPL) /EP /Zc:preprocessor /PD -predef2: A.cpp - $(COMPL) -EP -Zc:preprocessor -PD -predef3: A.cpp - $(COMPL) -E -dM -predef4: A.cpp - $(COMPL_O2) -E +LIBS = $(LIBS) oleaut32.lib ole32.lib + +# CFLAGS = $(CFLAGS) -DZ7_NO_UNICODE +!IFNDEF MY_NO_UNICODE +# CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE +!ENDIF + +!IF "$(CC)" != "clang-cl" +# for link time code generation: +# CFLAGS = $(CFLAGS) -GL +!ENDIF + +!IFNDEF O +!IFDEF PLATFORM +O=$(PLATFORM) +!ELSE +O=o +!ENDIF +!ENDIF + +!IF "$(CC)" != "clang-cl" +# CFLAGS = $(CFLAGS) -FAsc -Fa$O/asm/ +!ENDIF + +# LFLAGS = $(LFLAGS) /guard:cf + + +!IF "$(PLATFORM)" == "x64" +MY_ML = ml64 -WX +#-Dx64 +!ELSEIF "$(PLATFORM)" == "arm64" +MY_ML = armasm64 +!ELSEIF "$(PLATFORM)" == "arm" +MY_ML = armasm -WX +!ELSE +MY_ML = ml -WX +# -DABI_CDECL +!ENDIF + +# MY_ML = "$(MY_ML) -Fl$O\asm\ + + +!IFDEF UNDER_CE +RFLAGS = $(RFLAGS) -dUNDER_CE +!IFDEF MY_CONSOLE +LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup +!ENDIF +!ELSE +!IFDEF OLD_COMPILER +LFLAGS = $(LFLAGS) -OPT:NOWIN98 +!ENDIF +!IF "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" +CFLAGS = $(CFLAGS) -Gr +!ENDIF +LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib +!ENDIF + +!IF "$(PLATFORM)" == "arm" +COMPL_ASM = $(MY_ML) $** $O/$(*B).obj +!ELSEIF "$(PLATFORM)" == "arm64" +COMPL_ASM = $(MY_ML) $** $O/$(*B).obj +!ELSE +COMPL_ASM = $(MY_ML) -c -Fo$O/ $** +!ENDIF + +!IFDEF OLD_COMPILER +CFLAGS_WARN_LEVEL = -W4 +!ELSE +CFLAGS_WARN_LEVEL = -Wall +!ENDIF + +CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF + +!IF "$(CC)" == "clang-cl" + +CFLAGS = $(CFLAGS) \ + -Werror \ + -Wall \ + -Wextra \ + -Weverything \ + -Wfatal-errors \ + +!ENDIF + +# !IFDEF MY_DYNAMIC_LINK +!IF "$(MY_DYNAMIC_LINK)" != "" +CFLAGS = $(CFLAGS) -MD +!ELSE +!IFNDEF MY_SINGLE_THREAD +CFLAGS = $(CFLAGS) -MT +!ENDIF +!ENDIF + + +CFLAGS = $(CFLAGS_COMMON) $(CFLAGS) + + +!IFNDEF OLD_COMPILER + +CFLAGS = $(CFLAGS) -GS- -Zc:wchar_t +!IFDEF VCTOOLSVERSION +!IF "$(VCTOOLSVERSION)" >= "14.00" +!IF "$(CC)" != "clang-cl" +CFLAGS = $(CFLAGS) -Zc:throwingNew +!ENDIF +!ENDIF +!ELSE +# -Zc:forScope is default in VS2010. so we need it only for older versions +CFLAGS = $(CFLAGS) -Zc:forScope +!ENDIF + +!IFNDEF UNDER_CE +!IF "$(CC)" != "clang-cl" +CFLAGS = $(CFLAGS) -MP4 +!ENDIF +!IFNDEF PLATFORM +# CFLAGS = $(CFLAGS) -arch:IA32 +!ENDIF +!ENDIF + +!ENDIF + + +!IFDEF MY_CONSOLE +CFLAGS = $(CFLAGS) -D_CONSOLE +!ENDIF + +!IFNDEF UNDER_CE +!IF "$(PLATFORM)" == "arm" +CFLAGS = $(CFLAGS) -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE +!ENDIF +!ENDIF + +!IF "$(PLATFORM)" == "x64" +CFLAGS_O1 = $(CFLAGS) -O1 +!ELSE +CFLAGS_O1 = $(CFLAGS) -O1 +!ENDIF +CFLAGS_O2 = $(CFLAGS) -O2 + +LFLAGS = $(LFLAGS) -nologo -OPT:REF -OPT:ICF -INCREMENTAL:NO + +!IFNDEF UNDER_CE +LFLAGS = $(LFLAGS) /LARGEADDRESSAWARE +!ENDIF + +!IFDEF DEF_FILE +LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE) +!ELSE +!IF defined(MY_FIXED) && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64" +LFLAGS = $(LFLAGS) /FIXED +!ELSE +LFLAGS = $(LFLAGS) /FIXED:NO +!ENDIF +# /BASE:0x400000 +!ENDIF + +!IF "$(PLATFORM)" == "arm64" +# we can get better compression ratio with ARM64 filter if we change alignment to 4096 +# LFLAGS = $(LFLAGS) /FILEALIGN:4096 +!ENDIF + + + +# !IF "$(PLATFORM)" == "x64" + +!IFDEF SUB_SYS_VER + +MY_SUB_SYS_VER=5.02 + +!IFDEF MY_CONSOLE +LFLAGS = $(LFLAGS) /SUBSYSTEM:console,$(MY_SUB_SYS_VER) +!ELSE +LFLAGS = $(LFLAGS) /SUBSYSTEM:windows,$(MY_SUB_SYS_VER) +!ENDIF + +!ENDIF + + +!IF "$(PLATFORM)" == "arm64" +CLANG_FLAGS_TARGET = --target=arm64-pc-windows-msvc +!ENDIF + +COMPL_CLANG_SPEC=clang-cl $(CLANG_FLAGS_TARGET) +COMPL_ASM_CLANG = $(COMPL_CLANG_SPEC) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX $** +# COMPL_C_CLANG = $(COMPL_CLANG_SPEC) $(CFLAGS_O2) + + +PROGPATH = $O\$(PROG) + +COMPL_O1 = $(CC) $(CFLAGS_O1) $** +COMPL_O2 = $(CC) $(CFLAGS_O2) $** +COMPL_PCH = $(CC) $(CFLAGS_O1) -Yc"StdAfx.h" -Fp$O/a.pch $** +COMPL = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $** +COMPLB = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $< +COMPLB_O2 = $(CC) $(CFLAGS_O2) $< +# COMPLB_O2 = $(CC) $(CFLAGS_O2) -Yu"StdAfx.h" -Fp$O/a.pch $< + +CFLAGS_C_ALL = $(CFLAGS_O2) $(CFLAGS_C_SPEC) + +CCOMPL_PCH = $(CC) $(CFLAGS_C_ALL) -Yc"Precomp.h" -Fp$O/a.pch $** +CCOMPL_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $** +CCOMPLB_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $< +CCOMPL = $(CC) $(CFLAGS_C_ALL) $** +CCOMPLB = $(CC) $(CFLAGS_C_ALL) $< + +!IF "$(CC)" == "clang-cl" +COMPL = $(COMPL) -FI StdAfx.h +COMPLB = $(COMPLB) -FI StdAfx.h +CCOMPL_USE = $(CCOMPL_USE) -FI Precomp.h +CCOMPLB_USE = $(CCOMPLB_USE) -FI Precomp.h +!ENDIF + +all: $(PROGPATH) + +clean: + -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch $O\*.asm + +$O: + if not exist "$O" mkdir "$O" +$O/asm: + if not exist "$O/asm" mkdir "$O/asm" + +!IF "$(CC)" != "clang-cl" +# for link time code generation: +# LFLAGS = $(LFLAGS) -LTCG +!ENDIF + +$(PROGPATH): $O $O/asm $(OBJS) $(DEF_FILE) + link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS) + +!IFNDEF NO_DEFAULT_RES +$O\resource.res: $(*B).rc + rc $(RFLAGS) -fo$@ $** +!ENDIF +$O\StdAfx.obj: $(*B).cpp + $(COMPL_PCH) + +predef: empty.c + $(CCOMPL) /EP /Zc:preprocessor /PD +predef2: A.cpp + $(COMPL) -EP -Zc:preprocessor -PD +predef3: A.cpp + $(COMPL) -E -dM +predef4: A.cpp + $(COMPL_O2) -E diff --git a/CPP/Common/AutoPtr.h b/CPP/Common/AutoPtr.h index f27b44f84..e3c576385 100644 --- a/CPP/Common/AutoPtr.h +++ b/CPP/Common/AutoPtr.h @@ -1,46 +1,46 @@ -// Common/AutoPtr.h - -#ifndef ZIP7_INC_COMMON_AUTOPTR_H -#define ZIP7_INC_COMMON_AUTOPTR_H - -template class CMyUniquePtr -// CMyAutoPtr -{ - T *_p; - - CMyUniquePtr(CMyUniquePtr& p); // : _p(p.release()) {} - CMyUniquePtr& operator=(T *p); - CMyUniquePtr& operator=(CMyUniquePtr& p); - /* - { - reset(p.release()); - return (*this); - } - */ - void reset(T* p = NULL) - { - if (p != _p) - delete _p; - _p = p; - } -public: - CMyUniquePtr(T *p = NULL) : _p(p) {} - ~CMyUniquePtr() { delete _p; } - T& operator*() const { return *_p; } - T* operator->() const { return _p; } - // operator bool() const { return _p != NULL; } - T* get() const { return _p; } - T* release() - { - T *tmp = _p; - _p = NULL; - return tmp; - } - void Create_if_Empty() - { - if (!_p) - _p = new T; - } -}; - -#endif +// Common/AutoPtr.h + +#ifndef ZIP7_INC_COMMON_AUTOPTR_H +#define ZIP7_INC_COMMON_AUTOPTR_H + +template class CMyUniquePtr +// CMyAutoPtr +{ + T *_p; + + CMyUniquePtr(CMyUniquePtr& p); // : _p(p.release()) {} + CMyUniquePtr& operator=(T *p); + CMyUniquePtr& operator=(CMyUniquePtr& p); + /* + { + reset(p.release()); + return (*this); + } + */ + void reset(T* p = NULL) + { + if (p != _p) + delete _p; + _p = p; + } +public: + CMyUniquePtr(T *p = NULL) : _p(p) {} + ~CMyUniquePtr() { delete _p; } + T& operator*() const { return *_p; } + T* operator->() const { return _p; } + // operator bool() const { return _p != NULL; } + T* get() const { return _p; } + T* release() + { + T *tmp = _p; + _p = NULL; + return tmp; + } + void Create_if_Empty() + { + if (!_p) + _p = new T; + } +}; + +#endif diff --git a/CPP/Common/CRC.cpp b/CPP/Common/CRC.cpp index ef7550ebf..c6b7d5e4a 100644 --- a/CPP/Common/CRC.cpp +++ b/CPP/Common/CRC.cpp @@ -1,7 +1,7 @@ -// Common/CRC.cpp - -#include "StdAfx.h" - -#include "../../C/7zCrc.h" - -static struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit; +// Common/CRC.cpp + +#include "StdAfx.h" + +#include "../../C/7zCrc.h" + +static struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit; diff --git a/CPP/Common/C_FileIO.cpp b/CPP/Common/C_FileIO.cpp index 82da3cf1c..4bd3fadc4 100644 --- a/CPP/Common/C_FileIO.cpp +++ b/CPP/Common/C_FileIO.cpp @@ -1,3 +1,3 @@ -// Common/C_FileIO.cpp - -#include "StdAfx.h" +// Common/C_FileIO.cpp + +#include "StdAfx.h" diff --git a/CPP/Common/C_FileIO.h b/CPP/Common/C_FileIO.h index c3388072e..12d943910 100644 --- a/CPP/Common/C_FileIO.h +++ b/CPP/Common/C_FileIO.h @@ -1,6 +1,6 @@ -// Common/C_FileIO.h - -#ifndef ZIP7_INC_COMMON_C_FILEIO_H -#define ZIP7_INC_COMMON_C_FILEIO_H - -#endif +// Common/C_FileIO.h + +#ifndef ZIP7_INC_COMMON_C_FILEIO_H +#define ZIP7_INC_COMMON_C_FILEIO_H + +#endif diff --git a/CPP/Common/CksumReg.cpp b/CPP/Common/CksumReg.cpp index 030147cff..8c9c44905 100644 --- a/CPP/Common/CksumReg.cpp +++ b/CPP/Common/CksumReg.cpp @@ -1,55 +1,55 @@ -// CksumReg.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" -#include "../7zip/Compress/BZip2Crc.h" - -Z7_CLASS_IMP_COM_1( - CCksumHasher - , IHasher -) - CBZip2Crc _crc; - UInt64 _size; -public: - // Byte _mtDummy[1 << 7]; - CCksumHasher() - { - _crc.Init(0); - _size = 0; - } -}; - -Z7_COM7F_IMF2(void, CCksumHasher::Init()) -{ - _crc.Init(0); - _size = 0; -} - -Z7_COM7F_IMF2(void, CCksumHasher::Update(const void *data, UInt32 size)) -{ - _size += size; - CBZip2Crc crc = _crc; - for (UInt32 i = 0; i < size; i++) - crc.UpdateByte(((const Byte *)data)[i]); - _crc = crc; -} - -Z7_COM7F_IMF2(void, CCksumHasher::Final(Byte *digest)) -{ - UInt64 size = _size; - CBZip2Crc crc = _crc; - while (size) - { - crc.UpdateByte((Byte)size); - size >>= 8; - } - const UInt32 val = crc.GetDigest(); - SetUi32(digest, val) -} - -REGISTER_HASHER(CCksumHasher, 0x203, "CKSUM", 4) +// CksumReg.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" +#include "../7zip/Compress/BZip2Crc.h" + +Z7_CLASS_IMP_COM_1( + CCksumHasher + , IHasher +) + CBZip2Crc _crc; + UInt64 _size; +public: + // Byte _mtDummy[1 << 7]; + CCksumHasher() + { + _crc.Init(0); + _size = 0; + } +}; + +Z7_COM7F_IMF2(void, CCksumHasher::Init()) +{ + _crc.Init(0); + _size = 0; +} + +Z7_COM7F_IMF2(void, CCksumHasher::Update(const void *data, UInt32 size)) +{ + _size += size; + CBZip2Crc crc = _crc; + for (UInt32 i = 0; i < size; i++) + crc.UpdateByte(((const Byte *)data)[i]); + _crc = crc; +} + +Z7_COM7F_IMF2(void, CCksumHasher::Final(Byte *digest)) +{ + UInt64 size = _size; + CBZip2Crc crc = _crc; + while (size) + { + crc.UpdateByte((Byte)size); + size >>= 8; + } + const UInt32 val = crc.GetDigest(); + SetUi32(digest, val) +} + +REGISTER_HASHER(CCksumHasher, 0x203, "CKSUM", 4) diff --git a/CPP/Common/ComTry.h b/CPP/Common/ComTry.h index 3457b36b7..84746a7d0 100644 --- a/CPP/Common/ComTry.h +++ b/CPP/Common/ComTry.h @@ -1,21 +1,21 @@ -// ComTry.h - -#ifndef ZIP7_INC_COM_TRY_H -#define ZIP7_INC_COM_TRY_H - -#include "MyWindows.h" -// #include "Exception.h" -// #include "NewHandler.h" - -#define COM_TRY_BEGIN try { -#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; } - -/* -#define COM_TRY_END } \ - catch(const CNewException &) { return E_OUTOFMEMORY; } \ - catch(...) { return HRESULT_FROM_WIN32(ERROR_NOACCESS); } \ -*/ - // catch(const CSystemException &e) { return e.ErrorCode; } - // catch(...) { return E_FAIL; } - -#endif +// ComTry.h + +#ifndef ZIP7_INC_COM_TRY_H +#define ZIP7_INC_COM_TRY_H + +#include "MyWindows.h" +// #include "Exception.h" +// #include "NewHandler.h" + +#define COM_TRY_BEGIN try { +#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; } + +/* +#define COM_TRY_END } \ + catch(const CNewException &) { return E_OUTOFMEMORY; } \ + catch(...) { return HRESULT_FROM_WIN32(ERROR_NOACCESS); } \ +*/ + // catch(const CSystemException &e) { return e.ErrorCode; } + // catch(...) { return E_FAIL; } + +#endif diff --git a/CPP/Common/CommandLineParser.cpp b/CPP/Common/CommandLineParser.cpp index 21e09f0ee..319f27fca 100644 --- a/CPP/Common/CommandLineParser.cpp +++ b/CPP/Common/CommandLineParser.cpp @@ -1,231 +1,231 @@ -// CommandLineParser.cpp - -#include "StdAfx.h" - -#include "CommandLineParser.h" - -namespace NCommandLineParser { - -#ifdef _WIN32 - -bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2) -{ - dest1.Empty(); - dest2.Empty(); - bool quoteMode = false; - unsigned i; - for (i = 0; i < src.Len(); i++) - { - const wchar_t c = src[i]; - if ((c == L' ' || c == L'\t') && !quoteMode) - { - dest2 = src.Ptr(i + 1); - return i != 0; - } - if (c == L'\"') - quoteMode = !quoteMode; - else - dest1 += c; - } - return i != 0; -} - -void SplitCommandLine(const UString &s, UStringVector &parts) -{ -#if 0 -/* we don't use CommandLineToArgvW() because - it can remove tail backslash: - "1\" - converted to - 1" -*/ - parts.Clear(); - { - int nArgs; - LPWSTR *szArgList = CommandLineToArgvW(s, &nArgs); - if (szArgList) - { - for (int i = 0; i < nArgs; i++) - { - // printf("%2d: |%S|\n", i, szArglist[i]); - parts.Add(szArgList[i]); - } - LocalFree(szArgList); - return; - } - } -#endif -/* -#ifdef _UNICODE - throw 20240406; -#else -*/ - UString sTemp (s); - sTemp.Trim(); - parts.Clear(); - for (;;) - { - UString s1, s2; - if (SplitCommandLine(sTemp, s1, s2)) - parts.Add(s1); - if (s2.IsEmpty()) - break; - sTemp = s2; - } -// #endif -} -#endif - - -static const char * const kStopSwitchParsing = "--"; - -static bool inline IsItSwitchChar(wchar_t c) -{ - return (c == '-'); -} - -CParser::CParser(): - _switches(NULL), - StopSwitchIndex(-1) -{ -} - -CParser::~CParser() -{ - delete []_switches; -} - - -// if (s) contains switch then function updates switch structures -// out: true, if (s) is a switch -bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches) -{ - if (s.IsEmpty() || !IsItSwitchChar(s[0])) - return false; - - unsigned pos = 1; - unsigned switchIndex = 0; - int maxLen = -1; - - for (unsigned i = 0; i < numSwitches; i++) - { - const char * const key = switchForms[i].Key; - const unsigned switchLen = MyStringLen(key); - if ((int)switchLen <= maxLen || pos + switchLen > s.Len()) - continue; - if (IsString1PrefixedByString2_NoCase_Ascii((const wchar_t *)s + pos, key)) - { - switchIndex = i; - maxLen = (int)switchLen; - } - } - - if (maxLen < 0) - { - ErrorMessage = "Unknown switch:"; - return false; - } - - pos += (unsigned)maxLen; - - CSwitchResult &sw = _switches[switchIndex]; - const CSwitchForm &form = switchForms[switchIndex]; - - if (!form.Multi && sw.ThereIs) - { - ErrorMessage = "Multiple instances for switch:"; - return false; - } - - sw.ThereIs = true; - - const unsigned rem = s.Len() - pos; - if (rem < form.MinLen) - { - ErrorMessage = "Too short switch:"; - return false; - } - - sw.WithMinus = false; - sw.PostCharIndex = -1; - - switch (form.Type) - { - case NSwitchType::kMinus: - if (rem == 1) - { - sw.WithMinus = (s[pos] == '-'); - if (sw.WithMinus) - return true; - ErrorMessage = "Incorrect switch postfix:"; - return false; - } - break; - - case NSwitchType::kChar: - if (rem == 1) - { - const wchar_t c = s[pos]; - if (c <= 0x7F) - { - sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c); - if (sw.PostCharIndex >= 0) - return true; - } - ErrorMessage = "Incorrect switch postfix:"; - return false; - } - break; - - case NSwitchType::kString: - { - sw.PostStrings.Add(s.Ptr(pos)); - return true; - } - // case NSwitchType::kSimple: - default: break; - } - - if (pos != s.Len()) - { - ErrorMessage = "Too long switch:"; - return false; - } - return true; -} - - -bool CParser::ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings) -{ - StopSwitchIndex = -1; - ErrorMessage.Empty(); - ErrorLine.Empty(); - NonSwitchStrings.Clear(); - delete []_switches; - _switches = NULL; - _switches = new CSwitchResult[numSwitches]; - - FOR_VECTOR (i, commandStrings) - { - const UString &s = commandStrings[i]; - if (StopSwitchIndex < 0) - { - if (s.IsEqualTo(kStopSwitchParsing)) - { - StopSwitchIndex = (int)NonSwitchStrings.Size(); - continue; - } - if (!s.IsEmpty() && IsItSwitchChar(s[0])) - { - if (ParseString(s, switchForms, numSwitches)) - continue; - ErrorLine = s; - return false; - } - } - NonSwitchStrings.Add(s); - } - return true; -} - -} +// CommandLineParser.cpp + +#include "StdAfx.h" + +#include "CommandLineParser.h" + +namespace NCommandLineParser { + +#ifdef _WIN32 + +bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2) +{ + dest1.Empty(); + dest2.Empty(); + bool quoteMode = false; + unsigned i; + for (i = 0; i < src.Len(); i++) + { + const wchar_t c = src[i]; + if ((c == L' ' || c == L'\t') && !quoteMode) + { + dest2 = src.Ptr(i + 1); + return i != 0; + } + if (c == L'\"') + quoteMode = !quoteMode; + else + dest1 += c; + } + return i != 0; +} + +void SplitCommandLine(const UString &s, UStringVector &parts) +{ +#if 0 +/* we don't use CommandLineToArgvW() because + it can remove tail backslash: + "1\" + converted to + 1" +*/ + parts.Clear(); + { + int nArgs; + LPWSTR *szArgList = CommandLineToArgvW(s, &nArgs); + if (szArgList) + { + for (int i = 0; i < nArgs; i++) + { + // printf("%2d: |%S|\n", i, szArglist[i]); + parts.Add(szArgList[i]); + } + LocalFree(szArgList); + return; + } + } +#endif +/* +#ifdef _UNICODE + throw 20240406; +#else +*/ + UString sTemp (s); + sTemp.Trim(); + parts.Clear(); + for (;;) + { + UString s1, s2; + if (SplitCommandLine(sTemp, s1, s2)) + parts.Add(s1); + if (s2.IsEmpty()) + break; + sTemp = s2; + } +// #endif +} +#endif + + +static const char * const kStopSwitchParsing = "--"; + +static bool inline IsItSwitchChar(wchar_t c) +{ + return (c == '-'); +} + +CParser::CParser(): + _switches(NULL), + StopSwitchIndex(-1) +{ +} + +CParser::~CParser() +{ + delete []_switches; +} + + +// if (s) contains switch then function updates switch structures +// out: true, if (s) is a switch +bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches) +{ + if (s.IsEmpty() || !IsItSwitchChar(s[0])) + return false; + + unsigned pos = 1; + unsigned switchIndex = 0; + int maxLen = -1; + + for (unsigned i = 0; i < numSwitches; i++) + { + const char * const key = switchForms[i].Key; + const unsigned switchLen = MyStringLen(key); + if ((int)switchLen <= maxLen || pos + switchLen > s.Len()) + continue; + if (IsString1PrefixedByString2_NoCase_Ascii((const wchar_t *)s + pos, key)) + { + switchIndex = i; + maxLen = (int)switchLen; + } + } + + if (maxLen < 0) + { + ErrorMessage = "Unknown switch:"; + return false; + } + + pos += (unsigned)maxLen; + + CSwitchResult &sw = _switches[switchIndex]; + const CSwitchForm &form = switchForms[switchIndex]; + + if (!form.Multi && sw.ThereIs) + { + ErrorMessage = "Multiple instances for switch:"; + return false; + } + + sw.ThereIs = true; + + const unsigned rem = s.Len() - pos; + if (rem < form.MinLen) + { + ErrorMessage = "Too short switch:"; + return false; + } + + sw.WithMinus = false; + sw.PostCharIndex = -1; + + switch (form.Type) + { + case NSwitchType::kMinus: + if (rem == 1) + { + sw.WithMinus = (s[pos] == '-'); + if (sw.WithMinus) + return true; + ErrorMessage = "Incorrect switch postfix:"; + return false; + } + break; + + case NSwitchType::kChar: + if (rem == 1) + { + const wchar_t c = s[pos]; + if (c <= 0x7F) + { + sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c); + if (sw.PostCharIndex >= 0) + return true; + } + ErrorMessage = "Incorrect switch postfix:"; + return false; + } + break; + + case NSwitchType::kString: + { + sw.PostStrings.Add(s.Ptr(pos)); + return true; + } + // case NSwitchType::kSimple: + default: break; + } + + if (pos != s.Len()) + { + ErrorMessage = "Too long switch:"; + return false; + } + return true; +} + + +bool CParser::ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings) +{ + StopSwitchIndex = -1; + ErrorMessage.Empty(); + ErrorLine.Empty(); + NonSwitchStrings.Clear(); + delete []_switches; + _switches = NULL; + _switches = new CSwitchResult[numSwitches]; + + FOR_VECTOR (i, commandStrings) + { + const UString &s = commandStrings[i]; + if (StopSwitchIndex < 0) + { + if (s.IsEqualTo(kStopSwitchParsing)) + { + StopSwitchIndex = (int)NonSwitchStrings.Size(); + continue; + } + if (!s.IsEmpty() && IsItSwitchChar(s[0])) + { + if (ParseString(s, switchForms, numSwitches)) + continue; + ErrorLine = s; + return false; + } + } + NonSwitchStrings.Add(s); + } + return true; +} + +} diff --git a/CPP/Common/CommandLineParser.h b/CPP/Common/CommandLineParser.h index edbba5eea..fc6f028e6 100644 --- a/CPP/Common/CommandLineParser.h +++ b/CPP/Common/CommandLineParser.h @@ -1,63 +1,63 @@ -// Common/CommandLineParser.h - -#ifndef ZIP7_INC_COMMON_COMMAND_LINE_PARSER_H -#define ZIP7_INC_COMMON_COMMAND_LINE_PARSER_H - -#include "MyString.h" - -namespace NCommandLineParser { - -bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2); -void SplitCommandLine(const UString &s, UStringVector &parts); - -namespace NSwitchType -{ - enum EEnum - { - kSimple, - kMinus, - kString, - kChar - }; -} - -struct CSwitchForm -{ - const char *Key; - Byte Type; - bool Multi; - Byte MinLen; - // int MaxLen; - const char *PostCharSet; -}; - -struct CSwitchResult -{ - bool ThereIs; - bool WithMinus; - int PostCharIndex; - UStringVector PostStrings; - - CSwitchResult(): ThereIs(false) {} -}; - -class CParser -{ - CSwitchResult *_switches; - - bool ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches); -public: - UStringVector NonSwitchStrings; - int StopSwitchIndex; // NonSwitchStrings[StopSwitchIndex+] are after "--" - AString ErrorMessage; - UString ErrorLine; - - CParser(); - ~CParser(); - bool ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings); - const CSwitchResult& operator[](unsigned index) const { return _switches[index]; } -}; - -} - -#endif +// Common/CommandLineParser.h + +#ifndef ZIP7_INC_COMMON_COMMAND_LINE_PARSER_H +#define ZIP7_INC_COMMON_COMMAND_LINE_PARSER_H + +#include "MyString.h" + +namespace NCommandLineParser { + +bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2); +void SplitCommandLine(const UString &s, UStringVector &parts); + +namespace NSwitchType +{ + enum EEnum + { + kSimple, + kMinus, + kString, + kChar + }; +} + +struct CSwitchForm +{ + const char *Key; + Byte Type; + bool Multi; + Byte MinLen; + // int MaxLen; + const char *PostCharSet; +}; + +struct CSwitchResult +{ + bool ThereIs; + bool WithMinus; + int PostCharIndex; + UStringVector PostStrings; + + CSwitchResult(): ThereIs(false) {} +}; + +class CParser +{ + CSwitchResult *_switches; + + bool ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches); +public: + UStringVector NonSwitchStrings; + int StopSwitchIndex; // NonSwitchStrings[StopSwitchIndex+] are after "--" + AString ErrorMessage; + UString ErrorLine; + + CParser(); + ~CParser(); + bool ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings); + const CSwitchResult& operator[](unsigned index) const { return _switches[index]; } +}; + +} + +#endif diff --git a/CPP/Common/Common.h b/CPP/Common/Common.h index ba175d93d..cde0c38af 100644 --- a/CPP/Common/Common.h +++ b/CPP/Common/Common.h @@ -1,28 +1,28 @@ -// Common.h - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#ifndef ZIP7_INC_COMMON_H -#define ZIP7_INC_COMMON_H - -#include "../../C/Precomp.h" -#include "Common0.h" -#include "MyWindows.h" - -/* -This file is included to all cpp files in 7-Zip. -Each folder contains StdAfx.h file that includes "Common.h". -So 7-Zip includes "Common.h" in both modes: - with precompiled StdAfx.h -and - without precompiled StdAfx.h - -include "Common.h" before other h files of 7-zip, - if you need predefined macros. -do not include "Common.h", if you need only interfaces, - and you don't need predefined macros. -*/ - -#endif +// Common.h + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#ifndef ZIP7_INC_COMMON_H +#define ZIP7_INC_COMMON_H + +#include "../../C/Precomp.h" +#include "Common0.h" +#include "MyWindows.h" + +/* +This file is included to all cpp files in 7-Zip. +Each folder contains StdAfx.h file that includes "Common.h". +So 7-Zip includes "Common.h" in both modes: + with precompiled StdAfx.h +and + without precompiled StdAfx.h + +include "Common.h" before other h files of 7-zip, + if you need predefined macros. +do not include "Common.h", if you need only interfaces, + and you don't need predefined macros. +*/ + +#endif diff --git a/CPP/Common/Common0.h b/CPP/Common/Common0.h index 920089018..55606cd61 100644 --- a/CPP/Common/Common0.h +++ b/CPP/Common/Common0.h @@ -1,330 +1,330 @@ -// Common0.h - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif - -#ifndef ZIP7_INC_COMMON0_H -#define ZIP7_INC_COMMON0_H - -#include "../../C/Compiler.h" - -/* -This file contains compiler related things for cpp files. -This file is included to all cpp files in 7-Zip via "Common.h". -Also this file is included in "IDecl.h" (that is included in interface files). -So external modules can use 7-Zip interfaces without -predefined macros defined in "Common.h". -*/ - -#ifdef _MSC_VER - #pragma warning(disable : 4710) // function not inlined - // 'CUncopyable::CUncopyable': - #pragma warning(disable : 4514) // unreferenced inline function has been removed - #if _MSC_VER < 1300 - #pragma warning(disable : 4702) // unreachable code - #pragma warning(disable : 4714) // function marked as __forceinline not inlined - #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information - #endif - #if _MSC_VER < 1400 - #pragma warning(disable : 4511) // copy constructor could not be generated // #pragma warning(disable : 4512) // assignment operator could not be generated - #pragma warning(disable : 4512) // assignment operator could not be generated - #endif - #if _MSC_VER > 1400 && _MSC_VER <= 1900 - // #pragma warning(disable : 4996) - // strcat: This function or variable may be unsafe - // GetVersion was declared deprecated - #endif - -#if _MSC_VER > 1200 -// -Wall warnings - -#if _MSC_VER <= 1600 -#pragma warning(disable : 4917) // 'OLE_HANDLE' : a GUID can only be associated with a class, interface or namespace -#endif - -// #pragma warning(disable : 4061) // enumerator '' in switch of enum '' is not explicitly handled by a case label -// #pragma warning(disable : 4266) // no override available for virtual member function from base ''; function is hidden -#pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted -#pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted -#if _MSC_VER >= 1600 && _MSC_VER < 1920 -#pragma warning(disable : 4571) // Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught -#endif -#if _MSC_VER >= 1600 -#pragma warning(disable : 4365) // 'initializing' : conversion from 'int' to 'unsigned int', signed / unsigned mismatch -#endif -#if _MSC_VER < 1800 -// we disable the warning, if we don't use 'final' in class -#pragma warning(disable : 4265) // class has virtual functions, but destructor is not virtual -#endif - -#if _MSC_VER >= 1900 -#pragma warning(disable : 5026) // move constructor was implicitly defined as deleted -#pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted -#endif -#if _MSC_VER >= 1912 -#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception. -#endif -#if _MSC_VER >= 1925 -// #pragma warning(disable : 5204) // 'ISequentialInStream' : class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly -#endif -#if _MSC_VER >= 1934 -// #pragma warning(disable : 5264) // const variable is not used -#endif - -#endif // _MSC_VER > 1200 -#endif // _MSC_VER - - -#if defined(_MSC_VER) // && !defined(__clang__) -#define Z7_DECLSPEC_NOTHROW __declspec(nothrow) -#elif defined(__clang__) || defined(__GNUC__) -#define Z7_DECLSPEC_NOTHROW __attribute__((nothrow)) -#else -#define Z7_DECLSPEC_NOTHROW -#endif - -/* -#if defined (_MSC_VER) && _MSC_VER >= 1900 \ - || defined(__clang__) && __clang_major__ >= 6 \ - || defined(__GNUC__) && __GNUC__ >= 6 - #define Z7_noexcept noexcept -#else - #define Z7_noexcept throw() -#endif -*/ - - -#if defined(__clang__) - -#if /* defined(_WIN32) && */ __clang_major__ >= 16 -#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" -#endif - -#if __clang_major__ >= 4 && __clang_major__ < 12 && !defined(_WIN32) -/* -if compiled with new GCC libstdc++, GCC libstdc++ can use: -13.2.0/include/c++/ - : #define _NEW - : #define _GLIBCXX_STDLIB_H 1 -*/ -#pragma GCC diagnostic ignored "-Wreserved-id-macro" -#endif - -// noexcept, final, = delete -#pragma GCC diagnostic ignored "-Wc++98-compat" -#if __clang_major__ >= 4 -// throw() dynamic exception specifications are deprecated -#pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" -#endif - -#if __clang_major__ <= 6 // check it -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - -#pragma GCC diagnostic ignored "-Wold-style-cast" -#pragma GCC diagnostic ignored "-Wglobal-constructors" -#pragma GCC diagnostic ignored "-Wexit-time-destructors" - -#if defined(Z7_LLVM_CLANG_VERSION) && __clang_major__ >= 18 // 18.1.0RC -#pragma GCC diagnostic ignored "-Wswitch-default" -#endif -// #pragma GCC diagnostic ignored "-Wunused-private-field" -// #pragma GCC diagnostic ignored "-Wnonportable-system-include-path" -// #pragma GCC diagnostic ignored "-Wsuggest-override" -// #pragma GCC diagnostic ignored "-Wsign-conversion" -// #pragma GCC diagnostic ignored "-Winconsistent-missing-override" -// #pragma GCC diagnostic ignored "-Wsuggest-destructor-override" -// #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -// #pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-dtor" -// #pragma GCC diagnostic ignored "-Wdeprecated-copy-dtor" -// #ifndef _WIN32 -// #pragma GCC diagnostic ignored "-Wweak-vtables" -// #endif -/* -#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \ - || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000) -// enumeration values not explicitly handled in switch -#pragma GCC diagnostic ignored "-Wswitch-enum" -#endif -*/ -#endif // __clang__ - - -#ifdef __GNUC__ -// #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -#endif - - -/* There is BUG in MSVC 6.0 compiler for operator new[]: - It doesn't check overflow, when it calculates size in bytes for allocated array. - So we can use Z7_ARRAY_NEW macro instead of new[] operator. */ - -#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64) - #define Z7_ARRAY_NEW(p, T, size) p = new T[((size) > 0xFFFFFFFFu / sizeof(T)) ? 0xFFFFFFFFu / sizeof(T) : (size)]; -#else - #define Z7_ARRAY_NEW(p, T, size) p = new T[size]; -#endif - -#if (defined(__GNUC__) && (__GNUC__ >= 8)) - #define Z7_ATTR_NORETURN __attribute__((noreturn)) -#elif (defined(__clang__) && (__clang_major__ >= 3)) - #if __has_feature(cxx_attributes) - #define Z7_ATTR_NORETURN [[noreturn]] - #else - #define Z7_ATTR_NORETURN __attribute__((noreturn)) - #endif -#elif (defined(_MSC_VER) && (_MSC_VER >= 1900)) - #define Z7_ATTR_NORETURN [[noreturn]] -#else - #define Z7_ATTR_NORETURN -#endif - - -// final in "GCC 4.7.0" -// In C++98 and C++03 code the alternative spelling __final can be used instead (this is a GCC extension.) - -#if defined (__cplusplus) && __cplusplus >= 201103L \ - || defined(_MSC_VER) && _MSC_VER >= 1800 \ - || defined(__clang__) && __clang_major__ >= 4 \ - /* || defined(__GNUC__) && __GNUC__ >= 9 */ - #define Z7_final final - #if defined(__clang__) && __cplusplus < 201103L - #pragma GCC diagnostic ignored "-Wc++11-extensions" - #endif -#elif defined (__cplusplus) && __cplusplus >= 199711L \ - && defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__) - #define Z7_final __final -#else - #define Z7_final - #if defined(__clang__) && __clang_major__ >= 4 \ - || defined(__GNUC__) && __GNUC__ >= 4 - #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" - #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" - #endif -#endif - -#define Z7_class_final(c) class c Z7_final - - -#if defined (__cplusplus) && __cplusplus >= 201103L \ - || (defined(_MSC_VER) && _MSC_VER >= 1800) - #define Z7_CPP_IS_SUPPORTED_default - #define Z7_eq_delete = delete - // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) c(const c& k) = default; -#else - #define Z7_eq_delete - // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) -#endif - - -#if defined(__cplusplus) && (__cplusplus >= 201103L) \ - || defined(_MSC_VER) && (_MSC_VER >= 1400) /* && (_MSC_VER != 1600) */ \ - || defined(__clang__) && __clang_major__ >= 4 - #if defined(_MSC_VER) && (_MSC_VER == 1600) /* && (_MSC_VER != 1600) */ - #pragma warning(disable : 4481) // nonstandard extension used: override specifier 'override' - #define Z7_DESTRUCTOR_override - #else - #define Z7_DESTRUCTOR_override override - #endif - #define Z7_override override -#else - #define Z7_override - #define Z7_DESTRUCTOR_override -#endif - - - -#define Z7_CLASS_NO_COPY(cls) \ - private: \ - cls(const cls &) Z7_eq_delete; \ - cls &operator=(const cls &) Z7_eq_delete; - -class CUncopyable -{ -protected: - CUncopyable() {} // allow constructor - // ~CUncopyable() {} - Z7_CLASS_NO_COPY(CUncopyable) -}; - -#define MY_UNCOPYABLE :private CUncopyable -// #define MY_UNCOPYABLE - - -// typedef void (*Z7_void_Function)(void); - -#if defined(__clang__) || defined(__GNUC__) -#define Z7_CAST_FUNC(t, e) reinterpret_cast(reinterpret_cast(e)) -#else -#define Z7_CAST_FUNC(t, e) reinterpret_cast(reinterpret_cast(e)) -// #define Z7_CAST_FUNC(t, e) reinterpret_cast(e) -#endif - -#define Z7_GET_PROC_ADDRESS(func_type, hmodule, func_name) \ - Z7_CAST_FUNC(func_type, GetProcAddress(hmodule, func_name)) - -// || defined(__clang__) -// || defined(__GNUC__) - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define Z7_DECLSPEC_NOVTABLE __declspec(novtable) -#else -#define Z7_DECLSPEC_NOVTABLE -#endif - -#ifdef __clang__ -#define Z7_PURE_INTERFACES_BEGIN \ -_Pragma("GCC diagnostic push") \ -_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") -_Pragma("GCC diagnostic ignored \"-Wweak-vtables\"") -#define Z7_PURE_INTERFACES_END \ -_Pragma("GCC diagnostic pop") -#else -#define Z7_PURE_INTERFACES_BEGIN -#define Z7_PURE_INTERFACES_END -#endif - -// NewHandler.h and NewHandler.cpp redefine operator new() to throw exceptions, if compiled with old MSVC compilers -#include "NewHandler.h" - -/* -// #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) Z7_ARRAY_SIZE(a) -#endif -*/ - -#endif // ZIP7_INC_COMMON0_H - - - -// #define Z7_REDEFINE_NULL - -#if defined(Z7_REDEFINE_NULL) /* && (!defined(__clang__) || defined(_MSC_VER)) */ - -// NULL is defined in -#include -#undef NULL - -#ifdef __cplusplus - #if defined (__cplusplus) && __cplusplus >= 201103L \ - || (defined(_MSC_VER) && _MSC_VER >= 1800) - #define NULL nullptr - #else - #define NULL 0 - #endif -#else - #define NULL ((void *)0) -#endif - -#else // Z7_REDEFINE_NULL - -#if defined(__clang__) && __clang_major__ >= 5 -#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" -#endif - -#endif // Z7_REDEFINE_NULL - -// for precompiler: -// #include "MyWindows.h" +// Common0.h + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#ifndef ZIP7_INC_COMMON0_H +#define ZIP7_INC_COMMON0_H + +#include "../../C/Compiler.h" + +/* +This file contains compiler related things for cpp files. +This file is included to all cpp files in 7-Zip via "Common.h". +Also this file is included in "IDecl.h" (that is included in interface files). +So external modules can use 7-Zip interfaces without +predefined macros defined in "Common.h". +*/ + +#ifdef _MSC_VER + #pragma warning(disable : 4710) // function not inlined + // 'CUncopyable::CUncopyable': + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #if _MSC_VER < 1300 + #pragma warning(disable : 4702) // unreachable code + #pragma warning(disable : 4714) // function marked as __forceinline not inlined + #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information + #endif + #if _MSC_VER < 1400 + #pragma warning(disable : 4511) // copy constructor could not be generated // #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4512) // assignment operator could not be generated + #endif + #if _MSC_VER > 1400 && _MSC_VER <= 1900 + // #pragma warning(disable : 4996) + // strcat: This function or variable may be unsafe + // GetVersion was declared deprecated + #endif + +#if _MSC_VER > 1200 +// -Wall warnings + +#if _MSC_VER <= 1600 +#pragma warning(disable : 4917) // 'OLE_HANDLE' : a GUID can only be associated with a class, interface or namespace +#endif + +// #pragma warning(disable : 4061) // enumerator '' in switch of enum '' is not explicitly handled by a case label +// #pragma warning(disable : 4266) // no override available for virtual member function from base ''; function is hidden +#pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted +#pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted +#if _MSC_VER >= 1600 && _MSC_VER < 1920 +#pragma warning(disable : 4571) // Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught +#endif +#if _MSC_VER >= 1600 +#pragma warning(disable : 4365) // 'initializing' : conversion from 'int' to 'unsigned int', signed / unsigned mismatch +#endif +#if _MSC_VER < 1800 +// we disable the warning, if we don't use 'final' in class +#pragma warning(disable : 4265) // class has virtual functions, but destructor is not virtual +#endif + +#if _MSC_VER >= 1900 +#pragma warning(disable : 5026) // move constructor was implicitly defined as deleted +#pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted +#endif +#if _MSC_VER >= 1912 +#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception. +#endif +#if _MSC_VER >= 1925 +// #pragma warning(disable : 5204) // 'ISequentialInStream' : class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly +#endif +#if _MSC_VER >= 1934 +// #pragma warning(disable : 5264) // const variable is not used +#endif + +#endif // _MSC_VER > 1200 +#endif // _MSC_VER + + +#if defined(_MSC_VER) // && !defined(__clang__) +#define Z7_DECLSPEC_NOTHROW __declspec(nothrow) +#elif defined(__clang__) || defined(__GNUC__) +#define Z7_DECLSPEC_NOTHROW __attribute__((nothrow)) +#else +#define Z7_DECLSPEC_NOTHROW +#endif + +/* +#if defined (_MSC_VER) && _MSC_VER >= 1900 \ + || defined(__clang__) && __clang_major__ >= 6 \ + || defined(__GNUC__) && __GNUC__ >= 6 + #define Z7_noexcept noexcept +#else + #define Z7_noexcept throw() +#endif +*/ + + +#if defined(__clang__) + +#if /* defined(_WIN32) && */ __clang_major__ >= 16 +#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#if __clang_major__ >= 4 && __clang_major__ < 12 && !defined(_WIN32) +/* +if compiled with new GCC libstdc++, GCC libstdc++ can use: +13.2.0/include/c++/ + : #define _NEW + : #define _GLIBCXX_STDLIB_H 1 +*/ +#pragma GCC diagnostic ignored "-Wreserved-id-macro" +#endif + +// noexcept, final, = delete +#pragma GCC diagnostic ignored "-Wc++98-compat" +#if __clang_major__ >= 4 +// throw() dynamic exception specifications are deprecated +#pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" +#endif + +#if __clang_major__ <= 6 // check it +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wglobal-constructors" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" + +#if defined(Z7_LLVM_CLANG_VERSION) && __clang_major__ >= 18 // 18.1.0RC +#pragma GCC diagnostic ignored "-Wswitch-default" +#endif +// #pragma GCC diagnostic ignored "-Wunused-private-field" +// #pragma GCC diagnostic ignored "-Wnonportable-system-include-path" +// #pragma GCC diagnostic ignored "-Wsuggest-override" +// #pragma GCC diagnostic ignored "-Wsign-conversion" +// #pragma GCC diagnostic ignored "-Winconsistent-missing-override" +// #pragma GCC diagnostic ignored "-Wsuggest-destructor-override" +// #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +// #pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-dtor" +// #pragma GCC diagnostic ignored "-Wdeprecated-copy-dtor" +// #ifndef _WIN32 +// #pragma GCC diagnostic ignored "-Wweak-vtables" +// #endif +/* +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \ + || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000) +// enumeration values not explicitly handled in switch +#pragma GCC diagnostic ignored "-Wswitch-enum" +#endif +*/ +#endif // __clang__ + + +#ifdef __GNUC__ +// #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#endif + + +/* There is BUG in MSVC 6.0 compiler for operator new[]: + It doesn't check overflow, when it calculates size in bytes for allocated array. + So we can use Z7_ARRAY_NEW macro instead of new[] operator. */ + +#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64) + #define Z7_ARRAY_NEW(p, T, size) p = new T[((size) > 0xFFFFFFFFu / sizeof(T)) ? 0xFFFFFFFFu / sizeof(T) : (size)]; +#else + #define Z7_ARRAY_NEW(p, T, size) p = new T[size]; +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 8)) + #define Z7_ATTR_NORETURN __attribute__((noreturn)) +#elif (defined(__clang__) && (__clang_major__ >= 3)) + #if __has_feature(cxx_attributes) + #define Z7_ATTR_NORETURN [[noreturn]] + #else + #define Z7_ATTR_NORETURN __attribute__((noreturn)) + #endif +#elif (defined(_MSC_VER) && (_MSC_VER >= 1900)) + #define Z7_ATTR_NORETURN [[noreturn]] +#else + #define Z7_ATTR_NORETURN +#endif + + +// final in "GCC 4.7.0" +// In C++98 and C++03 code the alternative spelling __final can be used instead (this is a GCC extension.) + +#if defined (__cplusplus) && __cplusplus >= 201103L \ + || defined(_MSC_VER) && _MSC_VER >= 1800 \ + || defined(__clang__) && __clang_major__ >= 4 \ + /* || defined(__GNUC__) && __GNUC__ >= 9 */ + #define Z7_final final + #if defined(__clang__) && __cplusplus < 201103L + #pragma GCC diagnostic ignored "-Wc++11-extensions" + #endif +#elif defined (__cplusplus) && __cplusplus >= 199711L \ + && defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__) + #define Z7_final __final +#else + #define Z7_final + #if defined(__clang__) && __clang_major__ >= 4 \ + || defined(__GNUC__) && __GNUC__ >= 4 + #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" + #endif +#endif + +#define Z7_class_final(c) class c Z7_final + + +#if defined (__cplusplus) && __cplusplus >= 201103L \ + || (defined(_MSC_VER) && _MSC_VER >= 1800) + #define Z7_CPP_IS_SUPPORTED_default + #define Z7_eq_delete = delete + // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) c(const c& k) = default; +#else + #define Z7_eq_delete + // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) +#endif + + +#if defined(__cplusplus) && (__cplusplus >= 201103L) \ + || defined(_MSC_VER) && (_MSC_VER >= 1400) /* && (_MSC_VER != 1600) */ \ + || defined(__clang__) && __clang_major__ >= 4 + #if defined(_MSC_VER) && (_MSC_VER == 1600) /* && (_MSC_VER != 1600) */ + #pragma warning(disable : 4481) // nonstandard extension used: override specifier 'override' + #define Z7_DESTRUCTOR_override + #else + #define Z7_DESTRUCTOR_override override + #endif + #define Z7_override override +#else + #define Z7_override + #define Z7_DESTRUCTOR_override +#endif + + + +#define Z7_CLASS_NO_COPY(cls) \ + private: \ + cls(const cls &) Z7_eq_delete; \ + cls &operator=(const cls &) Z7_eq_delete; + +class CUncopyable +{ +protected: + CUncopyable() {} // allow constructor + // ~CUncopyable() {} + Z7_CLASS_NO_COPY(CUncopyable) +}; + +#define MY_UNCOPYABLE :private CUncopyable +// #define MY_UNCOPYABLE + + +// typedef void (*Z7_void_Function)(void); + +#if defined(__clang__) || defined(__GNUC__) +#define Z7_CAST_FUNC(t, e) reinterpret_cast(reinterpret_cast(e)) +#else +#define Z7_CAST_FUNC(t, e) reinterpret_cast(reinterpret_cast(e)) +// #define Z7_CAST_FUNC(t, e) reinterpret_cast(e) +#endif + +#define Z7_GET_PROC_ADDRESS(func_type, hmodule, func_name) \ + Z7_CAST_FUNC(func_type, GetProcAddress(hmodule, func_name)) + +// || defined(__clang__) +// || defined(__GNUC__) + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define Z7_DECLSPEC_NOVTABLE __declspec(novtable) +#else +#define Z7_DECLSPEC_NOVTABLE +#endif + +#ifdef __clang__ +#define Z7_PURE_INTERFACES_BEGIN \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") +_Pragma("GCC diagnostic ignored \"-Wweak-vtables\"") +#define Z7_PURE_INTERFACES_END \ +_Pragma("GCC diagnostic pop") +#else +#define Z7_PURE_INTERFACES_BEGIN +#define Z7_PURE_INTERFACES_END +#endif + +// NewHandler.h and NewHandler.cpp redefine operator new() to throw exceptions, if compiled with old MSVC compilers +#include "NewHandler.h" + +/* +// #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) Z7_ARRAY_SIZE(a) +#endif +*/ + +#endif // ZIP7_INC_COMMON0_H + + + +// #define Z7_REDEFINE_NULL + +#if defined(Z7_REDEFINE_NULL) /* && (!defined(__clang__) || defined(_MSC_VER)) */ + +// NULL is defined in +#include +#undef NULL + +#ifdef __cplusplus + #if defined (__cplusplus) && __cplusplus >= 201103L \ + || (defined(_MSC_VER) && _MSC_VER >= 1800) + #define NULL nullptr + #else + #define NULL 0 + #endif +#else + #define NULL ((void *)0) +#endif + +#else // Z7_REDEFINE_NULL + +#if defined(__clang__) && __clang_major__ >= 5 +#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#endif // Z7_REDEFINE_NULL + +// for precompiler: +// #include "MyWindows.h" diff --git a/CPP/Common/CrcReg.cpp b/CPP/Common/CrcReg.cpp index a35b00a4e..cd5d3da0b 100644 --- a/CPP/Common/CrcReg.cpp +++ b/CPP/Common/CrcReg.cpp @@ -1,77 +1,77 @@ -// CrcReg.cpp - -#include "StdAfx.h" - -#include "../../C/7zCrc.h" -#include "../../C/CpuArch.h" - -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" - -EXTERN_C_BEGIN - -EXTERN_C_END - -Z7_CLASS_IMP_COM_2( - CCrcHasher - , IHasher - , ICompressSetCoderProperties -) - UInt32 _crc; - Z7_CRC_UPDATE_FUNC _updateFunc; - - Z7_CLASS_NO_COPY(CCrcHasher) - - bool SetFunctions(UInt32 tSize); -public: - Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field - - CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); } -}; - -bool CCrcHasher::SetFunctions(UInt32 tSize) -{ - const Z7_CRC_UPDATE_FUNC f = z7_GetFunc_CrcUpdate(tSize); - if (!f) - { - _updateFunc = CrcUpdate; - return false; - } - _updateFunc = f; - return true; -} - -Z7_COM7F_IMF(CCrcHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - for (UInt32 i = 0; i < numProps; i++) - { - if (propIDs[i] == NCoderPropID::kDefaultProp) - { - const PROPVARIANT &prop = coderProps[i]; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - if (!SetFunctions(prop.ulVal)) - return E_NOTIMPL; - } - } - return S_OK; -} - -Z7_COM7F_IMF2(void, CCrcHasher::Init()) -{ - _crc = CRC_INIT_VAL; -} - -Z7_COM7F_IMF2(void, CCrcHasher::Update(const void *data, UInt32 size)) -{ - _crc = _updateFunc(_crc, data, size); -} - -Z7_COM7F_IMF2(void, CCrcHasher::Final(Byte *digest)) -{ - const UInt32 val = CRC_GET_DIGEST(_crc); - SetUi32(digest, val) -} - -REGISTER_HASHER(CCrcHasher, 0x1, "CRC32", 4) +// CrcReg.cpp + +#include "StdAfx.h" + +#include "../../C/7zCrc.h" +#include "../../C/CpuArch.h" + +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +EXTERN_C_BEGIN + +EXTERN_C_END + +Z7_CLASS_IMP_COM_2( + CCrcHasher + , IHasher + , ICompressSetCoderProperties +) + UInt32 _crc; + Z7_CRC_UPDATE_FUNC _updateFunc; + + Z7_CLASS_NO_COPY(CCrcHasher) + + bool SetFunctions(UInt32 tSize); +public: + Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field + + CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); } +}; + +bool CCrcHasher::SetFunctions(UInt32 tSize) +{ + const Z7_CRC_UPDATE_FUNC f = z7_GetFunc_CrcUpdate(tSize); + if (!f) + { + _updateFunc = CrcUpdate; + return false; + } + _updateFunc = f; + return true; +} + +Z7_COM7F_IMF(CCrcHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + for (UInt32 i = 0; i < numProps; i++) + { + if (propIDs[i] == NCoderPropID::kDefaultProp) + { + const PROPVARIANT &prop = coderProps[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + if (!SetFunctions(prop.ulVal)) + return E_NOTIMPL; + } + } + return S_OK; +} + +Z7_COM7F_IMF2(void, CCrcHasher::Init()) +{ + _crc = CRC_INIT_VAL; +} + +Z7_COM7F_IMF2(void, CCrcHasher::Update(const void *data, UInt32 size)) +{ + _crc = _updateFunc(_crc, data, size); +} + +Z7_COM7F_IMF2(void, CCrcHasher::Final(Byte *digest)) +{ + const UInt32 val = CRC_GET_DIGEST(_crc); + SetUi32(digest, val) +} + +REGISTER_HASHER(CCrcHasher, 0x1, "CRC32", 4) diff --git a/CPP/Common/Defs.h b/CPP/Common/Defs.h index 6276b9fd5..e302f3587 100644 --- a/CPP/Common/Defs.h +++ b/CPP/Common/Defs.h @@ -1,16 +1,16 @@ -// Common/Defs.h - -#ifndef ZIP7_INC_COMMON_DEFS_H -#define ZIP7_INC_COMMON_DEFS_H - -template inline T MyMin(T a, T b) { return a < b ? a : b; } -template inline T MyMax(T a, T b) { return a > b ? a : b; } - -template inline int MyCompare(T a, T b) - { return a == b ? 0 : (a < b ? -1 : 1); } - -inline int BoolToInt(bool v) { return (v ? 1 : 0); } -inline unsigned BoolToUInt(bool v) { return (v ? 1u : 0u); } -inline bool IntToBool(int v) { return (v != 0); } - -#endif +// Common/Defs.h + +#ifndef ZIP7_INC_COMMON_DEFS_H +#define ZIP7_INC_COMMON_DEFS_H + +template inline T MyMin(T a, T b) { return a < b ? a : b; } +template inline T MyMax(T a, T b) { return a > b ? a : b; } + +template inline int MyCompare(T a, T b) + { return a == b ? 0 : (a < b ? -1 : 1); } + +inline int BoolToInt(bool v) { return (v ? 1 : 0); } +inline unsigned BoolToUInt(bool v) { return (v ? 1u : 0u); } +inline bool IntToBool(int v) { return (v != 0); } + +#endif diff --git a/CPP/Common/DynLimBuf.cpp b/CPP/Common/DynLimBuf.cpp index 37504d065..1d92af399 100644 --- a/CPP/Common/DynLimBuf.cpp +++ b/CPP/Common/DynLimBuf.cpp @@ -1,93 +1,93 @@ -// Common/DynLimBuf.cpp - -#include "StdAfx.h" - -#include "DynLimBuf.h" -#include "MyString.h" - -CDynLimBuf::CDynLimBuf(size_t limit) throw() -{ - _chars = NULL; - _pos = 0; - _size = 0; - _sizeLimit = limit; - _error = true; - unsigned size = 1 << 4; - if (size > limit) - size = (unsigned)limit; - _chars = (Byte *)MyAlloc(size); - if (_chars) - { - _size = size; - _error = false; - } -} - -CDynLimBuf & CDynLimBuf::operator+=(char c) throw() -{ - if (_error) - return *this; - if (_size == _pos) - { - size_t n = _sizeLimit - _size; - if (n == 0) - { - _error = true; - return *this; - } - if (n > _size) - n = _size; - - n += _pos; - - Byte *newBuf = (Byte *)MyAlloc(n); - if (!newBuf) - { - _error = true; - return *this; - } - memcpy(newBuf, _chars, _pos); - MyFree(_chars); - _chars = newBuf; - _size = n; - } - _chars[_pos++] = (Byte)c; - return *this; -} - -CDynLimBuf &CDynLimBuf::operator+=(const char *s) throw() -{ - if (_error) - return *this; - unsigned len = MyStringLen(s); - size_t rem = _sizeLimit - _pos; - if (rem < len) - { - len = (unsigned)rem; - _error = true; - } - if (_size - _pos < len) - { - size_t n = _pos + len; - if (n - _size < _size) - { - n = _sizeLimit; - if (n - _size > _size) - n = _size * 2; - } - - Byte *newBuf = (Byte *)MyAlloc(n); - if (!newBuf) - { - _error = true; - return *this; - } - memcpy(newBuf, _chars, _pos); - MyFree(_chars); - _chars = newBuf; - _size = n; - } - memcpy(_chars + _pos, s, len); - _pos += len; - return *this; -} +// Common/DynLimBuf.cpp + +#include "StdAfx.h" + +#include "DynLimBuf.h" +#include "MyString.h" + +CDynLimBuf::CDynLimBuf(size_t limit) throw() +{ + _chars = NULL; + _pos = 0; + _size = 0; + _sizeLimit = limit; + _error = true; + unsigned size = 1 << 4; + if (size > limit) + size = (unsigned)limit; + _chars = (Byte *)MyAlloc(size); + if (_chars) + { + _size = size; + _error = false; + } +} + +CDynLimBuf & CDynLimBuf::operator+=(char c) throw() +{ + if (_error) + return *this; + if (_size == _pos) + { + size_t n = _sizeLimit - _size; + if (n == 0) + { + _error = true; + return *this; + } + if (n > _size) + n = _size; + + n += _pos; + + Byte *newBuf = (Byte *)MyAlloc(n); + if (!newBuf) + { + _error = true; + return *this; + } + memcpy(newBuf, _chars, _pos); + MyFree(_chars); + _chars = newBuf; + _size = n; + } + _chars[_pos++] = (Byte)c; + return *this; +} + +CDynLimBuf &CDynLimBuf::operator+=(const char *s) throw() +{ + if (_error) + return *this; + unsigned len = MyStringLen(s); + size_t rem = _sizeLimit - _pos; + if (rem < len) + { + len = (unsigned)rem; + _error = true; + } + if (_size - _pos < len) + { + size_t n = _pos + len; + if (n - _size < _size) + { + n = _sizeLimit; + if (n - _size > _size) + n = _size * 2; + } + + Byte *newBuf = (Byte *)MyAlloc(n); + if (!newBuf) + { + _error = true; + return *this; + } + memcpy(newBuf, _chars, _pos); + MyFree(_chars); + _chars = newBuf; + _size = n; + } + memcpy(_chars + _pos, s, len); + _pos += len; + return *this; +} diff --git a/CPP/Common/DynLimBuf.h b/CPP/Common/DynLimBuf.h index 64bf5f92a..af22f0764 100644 --- a/CPP/Common/DynLimBuf.h +++ b/CPP/Common/DynLimBuf.h @@ -1,41 +1,41 @@ -// Common/DynLimBuf.h - -#ifndef ZIP7_INC_COMMON_DYN_LIM_BUF_H -#define ZIP7_INC_COMMON_DYN_LIM_BUF_H - -#include - -#include "../../C/Alloc.h" - -#include "MyString.h" - -class CDynLimBuf -{ - Byte *_chars; - size_t _pos; - size_t _size; - size_t _sizeLimit; - bool _error; - - CDynLimBuf(const CDynLimBuf &s); - - // ---------- forbidden functions ---------- - CDynLimBuf &operator+=(wchar_t c); - -public: - CDynLimBuf(size_t limit) throw(); - ~CDynLimBuf() { MyFree(_chars); } - - size_t Len() const { return _pos; } - bool IsError() const { return _error; } - void Empty() { _pos = 0; _error = false; } - - operator const Byte *() const { return _chars; } - // const char *Ptr() const { return _chars; } - - CDynLimBuf &operator+=(char c) throw(); - CDynLimBuf &operator+=(const char *s) throw(); -}; - - -#endif +// Common/DynLimBuf.h + +#ifndef ZIP7_INC_COMMON_DYN_LIM_BUF_H +#define ZIP7_INC_COMMON_DYN_LIM_BUF_H + +#include + +#include "../../C/Alloc.h" + +#include "MyString.h" + +class CDynLimBuf +{ + Byte *_chars; + size_t _pos; + size_t _size; + size_t _sizeLimit; + bool _error; + + CDynLimBuf(const CDynLimBuf &s); + + // ---------- forbidden functions ---------- + CDynLimBuf &operator+=(wchar_t c); + +public: + CDynLimBuf(size_t limit) throw(); + ~CDynLimBuf() { MyFree(_chars); } + + size_t Len() const { return _pos; } + bool IsError() const { return _error; } + void Empty() { _pos = 0; _error = false; } + + operator const Byte *() const { return _chars; } + // const char *Ptr() const { return _chars; } + + CDynLimBuf &operator+=(char c) throw(); + CDynLimBuf &operator+=(const char *s) throw(); +}; + + +#endif diff --git a/CPP/Common/DynamicBuffer.h b/CPP/Common/DynamicBuffer.h index f1543f771..b03d371cf 100644 --- a/CPP/Common/DynamicBuffer.h +++ b/CPP/Common/DynamicBuffer.h @@ -1,76 +1,76 @@ -// Common/DynamicBuffer.h - -#ifndef ZIP7_INC_COMMON_DYNAMIC_BUFFER_H -#define ZIP7_INC_COMMON_DYNAMIC_BUFFER_H - -#include - -#include "MyTypes.h" - -template class CDynamicBuffer -{ - T *_items; - size_t _size; - size_t _pos; - - CDynamicBuffer(const CDynamicBuffer &buffer); - void operator=(const CDynamicBuffer &buffer); - - void Grow(size_t size) - { - size_t delta = _size >= 64 ? _size : 64; - if (delta < size) - delta = size; - size_t newCap = _size + delta; - if (newCap < delta) - { - newCap = _size + size; - if (newCap < size) - throw 20120116; - } - - T *newBuffer = new T[newCap]; - if (_pos != 0) - memcpy(newBuffer, _items, _pos * sizeof(T)); - delete []_items; - _items = newBuffer; - _size = newCap; - } - -public: - CDynamicBuffer(): _items(NULL), _size(0), _pos(0) {} - // operator T *() { return _items; } - operator const T *() const { return _items; } - ~CDynamicBuffer() { delete []_items; } - - void Free() - { - delete []_items; - _items = NULL; - _size = 0; - _pos = 0; - } - - T *GetCurPtrAndGrow(size_t addSize) - { - size_t rem = _size - _pos; - if (rem < addSize) - Grow(addSize - rem); - T *res = _items + _pos; - _pos += addSize; - return res; - } - - void AddData(const T *data, size_t size) - { - memcpy(GetCurPtrAndGrow(size), data, size * sizeof(T)); - } - - size_t GetPos() const { return _pos; } - - // void Empty() { _pos = 0; } -}; - -typedef CDynamicBuffer CByteDynamicBuffer; - -#endif +// Common/DynamicBuffer.h + +#ifndef ZIP7_INC_COMMON_DYNAMIC_BUFFER_H +#define ZIP7_INC_COMMON_DYNAMIC_BUFFER_H + +#include + +#include "MyTypes.h" + +template class CDynamicBuffer +{ + T *_items; + size_t _size; + size_t _pos; + + CDynamicBuffer(const CDynamicBuffer &buffer); + void operator=(const CDynamicBuffer &buffer); + + void Grow(size_t size) + { + size_t delta = _size >= 64 ? _size : 64; + if (delta < size) + delta = size; + size_t newCap = _size + delta; + if (newCap < delta) + { + newCap = _size + size; + if (newCap < size) + throw 20120116; + } + + T *newBuffer = new T[newCap]; + if (_pos != 0) + memcpy(newBuffer, _items, _pos * sizeof(T)); + delete []_items; + _items = newBuffer; + _size = newCap; + } + +public: + CDynamicBuffer(): _items(NULL), _size(0), _pos(0) {} + // operator T *() { return _items; } + operator const T *() const { return _items; } + ~CDynamicBuffer() { delete []_items; } + + void Free() + { + delete []_items; + _items = NULL; + _size = 0; + _pos = 0; + } + + T *GetCurPtrAndGrow(size_t addSize) + { + size_t rem = _size - _pos; + if (rem < addSize) + Grow(addSize - rem); + T *res = _items + _pos; + _pos += addSize; + return res; + } + + void AddData(const T *data, size_t size) + { + memcpy(GetCurPtrAndGrow(size), data, size * sizeof(T)); + } + + size_t GetPos() const { return _pos; } + + // void Empty() { _pos = 0; } +}; + +typedef CDynamicBuffer CByteDynamicBuffer; + +#endif diff --git a/CPP/Common/IntToString.cpp b/CPP/Common/IntToString.cpp index 38374c56b..0a7cb3b1f 100644 --- a/CPP/Common/IntToString.cpp +++ b/CPP/Common/IntToString.cpp @@ -1,215 +1,215 @@ -// Common/IntToString.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#include "IntToString.h" - -#define CONVERT_INT_TO_STR(charType, tempSize) \ - if (val < 10) \ - *s++ = (charType)('0' + (unsigned)val); \ - else { \ - Byte temp[tempSize]; \ - size_t i = 0; \ - do { \ - temp[++i] = (Byte)('0' + (unsigned)(val % 10)); \ - val /= 10; } \ - while (val >= 10); \ - *s++ = (charType)('0' + (unsigned)val); \ - do { *s++ = (charType)temp[i]; } \ - while (--i); \ - } \ - *s = 0; \ - return s; - -char * ConvertUInt32ToString(UInt32 val, char *s) throw() -{ - CONVERT_INT_TO_STR(char, 16) -} - -char * ConvertUInt64ToString(UInt64 val, char *s) throw() -{ - if (val <= (UInt32)0xFFFFFFFF) - return ConvertUInt32ToString((UInt32)val, s); - CONVERT_INT_TO_STR(char, 24) -} - -wchar_t * ConvertUInt32ToString(UInt32 val, wchar_t *s) throw() -{ - CONVERT_INT_TO_STR(wchar_t, 16) -} - -wchar_t * ConvertUInt64ToString(UInt64 val, wchar_t *s) throw() -{ - if (val <= (UInt32)0xFFFFFFFF) - return ConvertUInt32ToString((UInt32)val, s); - CONVERT_INT_TO_STR(wchar_t, 24) -} - -void ConvertInt64ToString(Int64 val, char *s) throw() -{ - if (val < 0) - { - *s++ = '-'; - val = -val; - } - ConvertUInt64ToString((UInt64)val, s); -} - -void ConvertInt64ToString(Int64 val, wchar_t *s) throw() -{ - if (val < 0) - { - *s++ = L'-'; - val = -val; - } - ConvertUInt64ToString((UInt64)val, s); -} - - -void ConvertUInt64ToOct(UInt64 val, char *s) throw() -{ - { - UInt64 v = val; - do - s++; - while (v >>= 3); - } - *s = 0; - do - { - const unsigned t = (unsigned)val & 7; - *--s = (char)('0' + t); - } - while (val >>= 3); -} - -MY_ALIGN(16) const char k_Hex_Upper[16] = - { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; -MY_ALIGN(16) const char k_Hex_Lower[16] = - { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; - -void ConvertUInt32ToHex(UInt32 val, char *s) throw() -{ - { - UInt32 v = val; - do - s++; - while (v >>= 4); - } - *s = 0; - do - { - const unsigned t = (unsigned)val & 0xF; - *--s = GET_HEX_CHAR_UPPER(t); - } - while (val >>= 4); -} - -void ConvertUInt64ToHex(UInt64 val, char *s) throw() -{ - { - UInt64 v = val; - do - s++; - while (v >>= 4); - } - *s = 0; - do - { - const unsigned t = (unsigned)val & 0xF; - *--s = GET_HEX_CHAR_UPPER(t); - } - while (val >>= 4); -} - -void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw() -{ - s[8] = 0; - int i = 7; - do - { - { const unsigned t = (unsigned)val & 0xF; s[i--] = GET_HEX_CHAR_UPPER(t); } - { const unsigned t = (Byte)val >> 4; val >>= 8; s[i--] = GET_HEX_CHAR_UPPER(t); } - } - while (i >= 0); -} - -/* -void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s) -{ - s[8] = 0; - for (int i = 7; i >= 0; i--) - { - const unsigned t = (unsigned)val & 0xF; - val >>= 4; - s[i] = GET_HEX_CHAR(t); - } -} -*/ - - -MY_ALIGN(16) static const Byte k_Guid_Pos[] = - { 6,4,2,0, 11,9, 16,14, 19,21, 24,26,28,30,32,34 }; - -char *RawLeGuidToString(const Byte *g, char *s) throw() -{ - s[ 8] = '-'; - s[13] = '-'; - s[18] = '-'; - s[23] = '-'; - s[36] = 0; - for (unsigned i = 0; i < 16; i++) - { - char *s2 = s + k_Guid_Pos[i]; - const unsigned v = g[i]; - s2[0] = GET_HEX_CHAR_UPPER(v >> 4); - s2[1] = GET_HEX_CHAR_UPPER(v & 0xF); - } - return s + 36; -} - -char *RawLeGuidToString_Braced(const Byte *g, char *s) throw() -{ - *s++ = '{'; - s = RawLeGuidToString(g, s); - *s++ = '}'; - *s = 0; - return s; -} - - -void ConvertDataToHex_Lower(char *dest, const Byte *src, size_t size) throw() -{ - if (size) - { - const Byte *lim = src + size; - do - { - const unsigned b = *src++; - dest[0] = GET_HEX_CHAR_LOWER(b >> 4); - dest[1] = GET_HEX_CHAR_LOWER(b & 0xF); - dest += 2; - } - while (src != lim); - } - *dest = 0; -} - -void ConvertDataToHex_Upper(char *dest, const Byte *src, size_t size) throw() -{ - if (size) - { - const Byte *lim = src + size; - do - { - const unsigned b = *src++; - dest[0] = GET_HEX_CHAR_UPPER(b >> 4); - dest[1] = GET_HEX_CHAR_UPPER(b & 0xF); - dest += 2; - } - while (src != lim); - } - *dest = 0; -} +// Common/IntToString.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#include "IntToString.h" + +#define CONVERT_INT_TO_STR(charType, tempSize) \ + if (val < 10) \ + *s++ = (charType)('0' + (unsigned)val); \ + else { \ + Byte temp[tempSize]; \ + size_t i = 0; \ + do { \ + temp[++i] = (Byte)('0' + (unsigned)(val % 10)); \ + val /= 10; } \ + while (val >= 10); \ + *s++ = (charType)('0' + (unsigned)val); \ + do { *s++ = (charType)temp[i]; } \ + while (--i); \ + } \ + *s = 0; \ + return s; + +char * ConvertUInt32ToString(UInt32 val, char *s) throw() +{ + CONVERT_INT_TO_STR(char, 16) +} + +char * ConvertUInt64ToString(UInt64 val, char *s) throw() +{ + if (val <= (UInt32)0xFFFFFFFF) + return ConvertUInt32ToString((UInt32)val, s); + CONVERT_INT_TO_STR(char, 24) +} + +wchar_t * ConvertUInt32ToString(UInt32 val, wchar_t *s) throw() +{ + CONVERT_INT_TO_STR(wchar_t, 16) +} + +wchar_t * ConvertUInt64ToString(UInt64 val, wchar_t *s) throw() +{ + if (val <= (UInt32)0xFFFFFFFF) + return ConvertUInt32ToString((UInt32)val, s); + CONVERT_INT_TO_STR(wchar_t, 24) +} + +void ConvertInt64ToString(Int64 val, char *s) throw() +{ + if (val < 0) + { + *s++ = '-'; + val = -val; + } + ConvertUInt64ToString((UInt64)val, s); +} + +void ConvertInt64ToString(Int64 val, wchar_t *s) throw() +{ + if (val < 0) + { + *s++ = L'-'; + val = -val; + } + ConvertUInt64ToString((UInt64)val, s); +} + + +void ConvertUInt64ToOct(UInt64 val, char *s) throw() +{ + { + UInt64 v = val; + do + s++; + while (v >>= 3); + } + *s = 0; + do + { + const unsigned t = (unsigned)val & 7; + *--s = (char)('0' + t); + } + while (val >>= 3); +} + +MY_ALIGN(16) const char k_Hex_Upper[16] = + { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; +MY_ALIGN(16) const char k_Hex_Lower[16] = + { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; + +void ConvertUInt32ToHex(UInt32 val, char *s) throw() +{ + { + UInt32 v = val; + do + s++; + while (v >>= 4); + } + *s = 0; + do + { + const unsigned t = (unsigned)val & 0xF; + *--s = GET_HEX_CHAR_UPPER(t); + } + while (val >>= 4); +} + +void ConvertUInt64ToHex(UInt64 val, char *s) throw() +{ + { + UInt64 v = val; + do + s++; + while (v >>= 4); + } + *s = 0; + do + { + const unsigned t = (unsigned)val & 0xF; + *--s = GET_HEX_CHAR_UPPER(t); + } + while (val >>= 4); +} + +void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw() +{ + s[8] = 0; + int i = 7; + do + { + { const unsigned t = (unsigned)val & 0xF; s[i--] = GET_HEX_CHAR_UPPER(t); } + { const unsigned t = (Byte)val >> 4; val >>= 8; s[i--] = GET_HEX_CHAR_UPPER(t); } + } + while (i >= 0); +} + +/* +void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s) +{ + s[8] = 0; + for (int i = 7; i >= 0; i--) + { + const unsigned t = (unsigned)val & 0xF; + val >>= 4; + s[i] = GET_HEX_CHAR(t); + } +} +*/ + + +MY_ALIGN(16) static const Byte k_Guid_Pos[] = + { 6,4,2,0, 11,9, 16,14, 19,21, 24,26,28,30,32,34 }; + +char *RawLeGuidToString(const Byte *g, char *s) throw() +{ + s[ 8] = '-'; + s[13] = '-'; + s[18] = '-'; + s[23] = '-'; + s[36] = 0; + for (unsigned i = 0; i < 16; i++) + { + char *s2 = s + k_Guid_Pos[i]; + const unsigned v = g[i]; + s2[0] = GET_HEX_CHAR_UPPER(v >> 4); + s2[1] = GET_HEX_CHAR_UPPER(v & 0xF); + } + return s + 36; +} + +char *RawLeGuidToString_Braced(const Byte *g, char *s) throw() +{ + *s++ = '{'; + s = RawLeGuidToString(g, s); + *s++ = '}'; + *s = 0; + return s; +} + + +void ConvertDataToHex_Lower(char *dest, const Byte *src, size_t size) throw() +{ + if (size) + { + const Byte *lim = src + size; + do + { + const unsigned b = *src++; + dest[0] = GET_HEX_CHAR_LOWER(b >> 4); + dest[1] = GET_HEX_CHAR_LOWER(b & 0xF); + dest += 2; + } + while (src != lim); + } + *dest = 0; +} + +void ConvertDataToHex_Upper(char *dest, const Byte *src, size_t size) throw() +{ + if (size) + { + const Byte *lim = src + size; + do + { + const unsigned b = *src++; + dest[0] = GET_HEX_CHAR_UPPER(b >> 4); + dest[1] = GET_HEX_CHAR_UPPER(b & 0xF); + dest += 2; + } + while (src != lim); + } + *dest = 0; +} diff --git a/CPP/Common/IntToString.h b/CPP/Common/IntToString.h index 586651cfa..2f096d672 100644 --- a/CPP/Common/IntToString.h +++ b/CPP/Common/IntToString.h @@ -1,54 +1,54 @@ -// Common/IntToString.h - -#ifndef ZIP7_INC_COMMON_INT_TO_STRING_H -#define ZIP7_INC_COMMON_INT_TO_STRING_H - -#include "MyTypes.h" - -// return: the pointer to the "terminating" null character after written characters - -char * ConvertUInt32ToString(UInt32 value, char *s) throw(); -char * ConvertUInt64ToString(UInt64 value, char *s) throw(); - -wchar_t * ConvertUInt32ToString(UInt32 value, wchar_t *s) throw(); -wchar_t * ConvertUInt64ToString(UInt64 value, wchar_t *s) throw(); -void ConvertInt64ToString(Int64 value, char *s) throw(); -void ConvertInt64ToString(Int64 value, wchar_t *s) throw(); - -void ConvertUInt64ToOct(UInt64 value, char *s) throw(); - -extern const char k_Hex_Upper[16]; -extern const char k_Hex_Lower[16]; - -#define GET_HEX_CHAR_UPPER(t) (k_Hex_Upper[t]) -#define GET_HEX_CHAR_LOWER(t) (k_Hex_Lower[t]) -/* -// #define GET_HEX_CHAR_UPPER(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) -static inline unsigned GetHex_Lower(unsigned v) -{ - const unsigned v0 = v + '0'; - v += 'a' - 10; - if (v < 'a') - v = v0; - return v; -} -static inline char GetHex_Upper(unsigned v) -{ - return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10))); -} -*/ - - -void ConvertUInt32ToHex(UInt32 value, char *s) throw(); -void ConvertUInt64ToHex(UInt64 value, char *s) throw(); -void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw(); -// void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw(); - -// use RawLeGuid only for RAW bytes that contain stored GUID as Little-endian. -char *RawLeGuidToString(const Byte *guid, char *s) throw(); -char *RawLeGuidToString_Braced(const Byte *guid, char *s) throw(); - -void ConvertDataToHex_Lower(char *dest, const Byte *src, size_t size) throw(); -void ConvertDataToHex_Upper(char *dest, const Byte *src, size_t size) throw(); - -#endif +// Common/IntToString.h + +#ifndef ZIP7_INC_COMMON_INT_TO_STRING_H +#define ZIP7_INC_COMMON_INT_TO_STRING_H + +#include "MyTypes.h" + +// return: the pointer to the "terminating" null character after written characters + +char * ConvertUInt32ToString(UInt32 value, char *s) throw(); +char * ConvertUInt64ToString(UInt64 value, char *s) throw(); + +wchar_t * ConvertUInt32ToString(UInt32 value, wchar_t *s) throw(); +wchar_t * ConvertUInt64ToString(UInt64 value, wchar_t *s) throw(); +void ConvertInt64ToString(Int64 value, char *s) throw(); +void ConvertInt64ToString(Int64 value, wchar_t *s) throw(); + +void ConvertUInt64ToOct(UInt64 value, char *s) throw(); + +extern const char k_Hex_Upper[16]; +extern const char k_Hex_Lower[16]; + +#define GET_HEX_CHAR_UPPER(t) (k_Hex_Upper[t]) +#define GET_HEX_CHAR_LOWER(t) (k_Hex_Lower[t]) +/* +// #define GET_HEX_CHAR_UPPER(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) +static inline unsigned GetHex_Lower(unsigned v) +{ + const unsigned v0 = v + '0'; + v += 'a' - 10; + if (v < 'a') + v = v0; + return v; +} +static inline char GetHex_Upper(unsigned v) +{ + return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10))); +} +*/ + + +void ConvertUInt32ToHex(UInt32 value, char *s) throw(); +void ConvertUInt64ToHex(UInt64 value, char *s) throw(); +void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw(); +// void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw(); + +// use RawLeGuid only for RAW bytes that contain stored GUID as Little-endian. +char *RawLeGuidToString(const Byte *guid, char *s) throw(); +char *RawLeGuidToString_Braced(const Byte *guid, char *s) throw(); + +void ConvertDataToHex_Lower(char *dest, const Byte *src, size_t size) throw(); +void ConvertDataToHex_Upper(char *dest, const Byte *src, size_t size) throw(); + +#endif diff --git a/CPP/Common/Lang.cpp b/CPP/Common/Lang.cpp index e81b40faf..b0b4342b5 100644 --- a/CPP/Common/Lang.cpp +++ b/CPP/Common/Lang.cpp @@ -1,173 +1,173 @@ -// Common/Lang.cpp - -#include "StdAfx.h" - -#include "Lang.h" -#include "StringToInt.h" -#include "UTFConvert.h" - -#include "../Windows/FileIO.h" - -void CLang::Clear() throw() -{ - _ids.Clear(); - _offsets.Clear(); - Comments.Clear(); - delete []_text; - _text = NULL; -} - -static const char * const kLangSignature = ";!@Lang2@!UTF-8!\n"; - -bool CLang::OpenFromString(const AString &s2) -{ - UString su; - if (!ConvertUTF8ToUnicode(s2, su)) - return false; - if (su.IsEmpty()) - return false; - const wchar_t *s = su; - const wchar_t *sLim = s + su.Len(); - if (*s == 0xFEFF) - s++; - for (const char *p = kLangSignature;; s++) - { - const Byte c = (Byte)(*p++); - if (c == 0) - break; - if (*s != c) - return false; - } - - wchar_t *text = new wchar_t[(size_t)(sLim - s) + 1]; - _text = text; - - UString comment; - Int32 id = -1024; - unsigned pos = 0; - - while (s != sLim) - { - const unsigned start = pos; - do - { - wchar_t c = *s++; - if (c == '\n') - break; - if (c == '\\') - { - if (s == sLim) - return false; - c = *s++; - switch (c) - { - case '\n': return false; - case 'n': c = '\n'; break; - case 't': c = '\t'; break; - case '\\': /* c = '\\'; */ break; - default: text[pos++] = L'\\'; break; - } - } - text[pos++] = c; - } - while (s != sLim); - - { - unsigned j = start; - for (; j < pos; j++) - if (text[j] != ' ' && text[j] != '\t') - break; - if (j == pos) - { - id++; - pos = start; - continue; - } - } - - // start != pos - text[pos++] = 0; - - if (text[start] == ';') - { - comment = text + start; - comment.TrimRight(); - if (comment.Len() != 1) - Comments.Add(comment); - id++; - pos = start; - continue; - } - - const wchar_t *end; - const UInt32 id32 = ConvertStringToUInt32(text + start, &end); - if (*end == 0) - { - if (id32 > ((UInt32)1 << 30) || (Int32)id32 < id) - return false; - id = (Int32)id32; - pos = start; - continue; - } - - if (id < 0) - return false; - _ids.Add((UInt32)id++); - _offsets.Add(start); - } - - return true; -} - -bool CLang::Open(CFSTR fileName, const char *id) -{ - Clear(); - NWindows::NFile::NIO::CInFile file; - if (!file.Open(fileName)) - return false; - UInt64 length; - if (!file.GetLength(length)) - return false; - if (length > (1 << 20)) - return false; - - AString s; - const unsigned len = (unsigned)length; - char *p = s.GetBuf(len); - size_t processed; - if (!file.ReadFull(p, len, processed)) - return false; - file.Close(); - if (len != processed) - return false; - - char *p2 = p; - for (unsigned i = 0; i < len; i++) - { - const char c = p[i]; - if (c == 0) - break; - if (c != 0x0D) - *p2++ = c; - } - *p2 = 0; - s.ReleaseBuf_SetLen((unsigned)(p2 - p)); - - if (OpenFromString(s)) - { - const wchar_t *name = Get(0); - if (name && StringsAreEqual_Ascii(name, id)) - return true; - } - - Clear(); - return false; -} - -const wchar_t *CLang::Get(UInt32 id) const throw() -{ - const int index = _ids.FindInSorted(id); - if (index < 0) - return NULL; - return _text + (size_t)_offsets[(unsigned)index]; -} +// Common/Lang.cpp + +#include "StdAfx.h" + +#include "Lang.h" +#include "StringToInt.h" +#include "UTFConvert.h" + +#include "../Windows/FileIO.h" + +void CLang::Clear() throw() +{ + _ids.Clear(); + _offsets.Clear(); + Comments.Clear(); + delete []_text; + _text = NULL; +} + +static const char * const kLangSignature = ";!@Lang2@!UTF-8!\n"; + +bool CLang::OpenFromString(const AString &s2) +{ + UString su; + if (!ConvertUTF8ToUnicode(s2, su)) + return false; + if (su.IsEmpty()) + return false; + const wchar_t *s = su; + const wchar_t *sLim = s + su.Len(); + if (*s == 0xFEFF) + s++; + for (const char *p = kLangSignature;; s++) + { + const Byte c = (Byte)(*p++); + if (c == 0) + break; + if (*s != c) + return false; + } + + wchar_t *text = new wchar_t[(size_t)(sLim - s) + 1]; + _text = text; + + UString comment; + Int32 id = -1024; + unsigned pos = 0; + + while (s != sLim) + { + const unsigned start = pos; + do + { + wchar_t c = *s++; + if (c == '\n') + break; + if (c == '\\') + { + if (s == sLim) + return false; + c = *s++; + switch (c) + { + case '\n': return false; + case 'n': c = '\n'; break; + case 't': c = '\t'; break; + case '\\': /* c = '\\'; */ break; + default: text[pos++] = L'\\'; break; + } + } + text[pos++] = c; + } + while (s != sLim); + + { + unsigned j = start; + for (; j < pos; j++) + if (text[j] != ' ' && text[j] != '\t') + break; + if (j == pos) + { + id++; + pos = start; + continue; + } + } + + // start != pos + text[pos++] = 0; + + if (text[start] == ';') + { + comment = text + start; + comment.TrimRight(); + if (comment.Len() != 1) + Comments.Add(comment); + id++; + pos = start; + continue; + } + + const wchar_t *end; + const UInt32 id32 = ConvertStringToUInt32(text + start, &end); + if (*end == 0) + { + if (id32 > ((UInt32)1 << 30) || (Int32)id32 < id) + return false; + id = (Int32)id32; + pos = start; + continue; + } + + if (id < 0) + return false; + _ids.Add((UInt32)id++); + _offsets.Add(start); + } + + return true; +} + +bool CLang::Open(CFSTR fileName, const char *id) +{ + Clear(); + NWindows::NFile::NIO::CInFile file; + if (!file.Open(fileName)) + return false; + UInt64 length; + if (!file.GetLength(length)) + return false; + if (length > (1 << 20)) + return false; + + AString s; + const unsigned len = (unsigned)length; + char *p = s.GetBuf(len); + size_t processed; + if (!file.ReadFull(p, len, processed)) + return false; + file.Close(); + if (len != processed) + return false; + + char *p2 = p; + for (unsigned i = 0; i < len; i++) + { + const char c = p[i]; + if (c == 0) + break; + if (c != 0x0D) + *p2++ = c; + } + *p2 = 0; + s.ReleaseBuf_SetLen((unsigned)(p2 - p)); + + if (OpenFromString(s)) + { + const wchar_t *name = Get(0); + if (name && StringsAreEqual_Ascii(name, id)) + return true; + } + + Clear(); + return false; +} + +const wchar_t *CLang::Get(UInt32 id) const throw() +{ + const int index = _ids.FindInSorted(id); + if (index < 0) + return NULL; + return _text + (size_t)_offsets[(unsigned)index]; +} diff --git a/CPP/Common/Lang.h b/CPP/Common/Lang.h index fa58ed263..76d5418e6 100644 --- a/CPP/Common/Lang.h +++ b/CPP/Common/Lang.h @@ -1,30 +1,30 @@ -// Common/Lang.h - -#ifndef ZIP7_INC_COMMON_LANG_H -#define ZIP7_INC_COMMON_LANG_H - -#include "MyString.h" - -class CLang -{ - wchar_t *_text; - - bool OpenFromString(const AString &s); -public: - CRecordVector _ids; - CRecordVector _offsets; - UStringVector Comments; - - CLang(): _text(NULL) {} - ~CLang() { Clear(); } - bool Open(CFSTR fileName, const char *id); - void Clear() throw(); - bool IsEmpty() const { return _ids.IsEmpty(); } - const wchar_t *Get(UInt32 id) const throw(); - const wchar_t *Get_by_index(unsigned index) const throw() - { - return _text + (size_t)_offsets[index]; - } -}; - -#endif +// Common/Lang.h + +#ifndef ZIP7_INC_COMMON_LANG_H +#define ZIP7_INC_COMMON_LANG_H + +#include "MyString.h" + +class CLang +{ + wchar_t *_text; + + bool OpenFromString(const AString &s); +public: + CRecordVector _ids; + CRecordVector _offsets; + UStringVector Comments; + + CLang(): _text(NULL) {} + ~CLang() { Clear(); } + bool Open(CFSTR fileName, const char *id); + void Clear() throw(); + bool IsEmpty() const { return _ids.IsEmpty(); } + const wchar_t *Get(UInt32 id) const throw(); + const wchar_t *Get_by_index(unsigned index) const throw() + { + return _text + (size_t)_offsets[index]; + } +}; + +#endif diff --git a/CPP/Common/ListFileUtils.cpp b/CPP/Common/ListFileUtils.cpp index c979ca0f8..714b275d5 100644 --- a/CPP/Common/ListFileUtils.cpp +++ b/CPP/Common/ListFileUtils.cpp @@ -1,150 +1,150 @@ -// Common/ListFileUtils.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#include "ListFileUtils.h" -#include "MyBuffer.h" -#include "StringConvert.h" -#include "UTFConvert.h" - -#include "../Windows/FileIO.h" - -#define CSysInFile NWindows::NFile::NIO::CInFile -#define MY_GET_LAST_ERROR ::GetLastError() - - -#define kQuoteChar '\"' - - -static void AddName(UStringVector &strings, UString &s) -{ - s.Trim(); - if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar) - { - s.DeleteBack(); - s.Delete(0); - } - if (!s.IsEmpty()) - strings.Add(s); -} - - -static bool My_File_Read(CSysInFile &file, void *data, size_t size, DWORD &lastError) -{ - size_t processed; - if (!file.ReadFull(data, size, processed)) - { - lastError = MY_GET_LAST_ERROR; - return false; - } - if (processed != size) - { - lastError = 1; // error: size of listfile was changed - return false; - } - return true; -} - - -bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError) -{ - lastError = 0; - CSysInFile file; - if (!file.Open(fileName)) - { - lastError = MY_GET_LAST_ERROR; - return false; - } - UInt64 fileSize; - if (!file.GetLength(fileSize)) - { - lastError = MY_GET_LAST_ERROR; - return false; - } - if (fileSize >= ((UInt32)1 << 31) - 32) - return false; - UString u; - if (codePage == Z7_WIN_CP_UTF16 || codePage == Z7_WIN_CP_UTF16BE) - { - if ((fileSize & 1) != 0) - return false; - CByteArr buf((size_t)fileSize); - - if (!My_File_Read(file, buf, (size_t)fileSize, lastError)) - return false; - - file.Close(); - const size_t num = (size_t)fileSize / 2; - wchar_t *p = u.GetBuf((unsigned)num); - if (codePage == Z7_WIN_CP_UTF16) - for (size_t i = 0; i < num; i++) - { - const wchar_t c = GetUi16(buf.ConstData() + (size_t)i * 2); - if (c == 0) - return false; - p[i] = c; - } - else - for (size_t i = 0; i < num; i++) - { - const wchar_t c = (wchar_t)GetBe16(buf.ConstData() + (size_t)i * 2); - if (c == 0) - return false; - p[i] = c; - } - p[num] = 0; - u.ReleaseBuf_SetLen((unsigned)num); - } - else - { - AString s; - char *p = s.GetBuf((unsigned)fileSize); - - if (!My_File_Read(file, p, (size_t)fileSize, lastError)) - return false; - - file.Close(); - s.ReleaseBuf_CalcLen((unsigned)fileSize); - if (s.Len() != fileSize) - return false; - - // #ifdef CP_UTF8 - if (codePage == CP_UTF8) - { - // we must check UTF8 here, if convert function doesn't check - if (!CheckUTF8_AString(s)) - return false; - if (!ConvertUTF8ToUnicode(s, u)) - return false; - } - else - // #endif - MultiByteToUnicodeString2(u, s, codePage); - } - - const wchar_t kGoodBOM = 0xFEFF; - // const wchar_t kBadBOM = 0xFFFE; - - UString s; - unsigned i = 0; - for (; i < u.Len() && u[i] == kGoodBOM; i++); - for (; i < u.Len(); i++) - { - wchar_t c = u[i]; - /* - if (c == kGoodBOM || c == kBadBOM) - return false; - */ - if (c == '\n' || c == 0xD) - { - AddName(strings, s); - s.Empty(); - } - else - s += c; - } - AddName(strings, s); - return true; -} +// Common/ListFileUtils.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#include "ListFileUtils.h" +#include "MyBuffer.h" +#include "StringConvert.h" +#include "UTFConvert.h" + +#include "../Windows/FileIO.h" + +#define CSysInFile NWindows::NFile::NIO::CInFile +#define MY_GET_LAST_ERROR ::GetLastError() + + +#define kQuoteChar '\"' + + +static void AddName(UStringVector &strings, UString &s) +{ + s.Trim(); + if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar) + { + s.DeleteBack(); + s.Delete(0); + } + if (!s.IsEmpty()) + strings.Add(s); +} + + +static bool My_File_Read(CSysInFile &file, void *data, size_t size, DWORD &lastError) +{ + size_t processed; + if (!file.ReadFull(data, size, processed)) + { + lastError = MY_GET_LAST_ERROR; + return false; + } + if (processed != size) + { + lastError = 1; // error: size of listfile was changed + return false; + } + return true; +} + + +bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError) +{ + lastError = 0; + CSysInFile file; + if (!file.Open(fileName)) + { + lastError = MY_GET_LAST_ERROR; + return false; + } + UInt64 fileSize; + if (!file.GetLength(fileSize)) + { + lastError = MY_GET_LAST_ERROR; + return false; + } + if (fileSize >= ((UInt32)1 << 31) - 32) + return false; + UString u; + if (codePage == Z7_WIN_CP_UTF16 || codePage == Z7_WIN_CP_UTF16BE) + { + if ((fileSize & 1) != 0) + return false; + CByteArr buf((size_t)fileSize); + + if (!My_File_Read(file, buf, (size_t)fileSize, lastError)) + return false; + + file.Close(); + const size_t num = (size_t)fileSize / 2; + wchar_t *p = u.GetBuf((unsigned)num); + if (codePage == Z7_WIN_CP_UTF16) + for (size_t i = 0; i < num; i++) + { + const wchar_t c = GetUi16(buf.ConstData() + (size_t)i * 2); + if (c == 0) + return false; + p[i] = c; + } + else + for (size_t i = 0; i < num; i++) + { + const wchar_t c = (wchar_t)GetBe16(buf.ConstData() + (size_t)i * 2); + if (c == 0) + return false; + p[i] = c; + } + p[num] = 0; + u.ReleaseBuf_SetLen((unsigned)num); + } + else + { + AString s; + char *p = s.GetBuf((unsigned)fileSize); + + if (!My_File_Read(file, p, (size_t)fileSize, lastError)) + return false; + + file.Close(); + s.ReleaseBuf_CalcLen((unsigned)fileSize); + if (s.Len() != fileSize) + return false; + + // #ifdef CP_UTF8 + if (codePage == CP_UTF8) + { + // we must check UTF8 here, if convert function doesn't check + if (!CheckUTF8_AString(s)) + return false; + if (!ConvertUTF8ToUnicode(s, u)) + return false; + } + else + // #endif + MultiByteToUnicodeString2(u, s, codePage); + } + + const wchar_t kGoodBOM = 0xFEFF; + // const wchar_t kBadBOM = 0xFFFE; + + UString s; + unsigned i = 0; + for (; i < u.Len() && u[i] == kGoodBOM; i++); + for (; i < u.Len(); i++) + { + wchar_t c = u[i]; + /* + if (c == kGoodBOM || c == kBadBOM) + return false; + */ + if (c == '\n' || c == 0xD) + { + AddName(strings, s); + s.Empty(); + } + else + s += c; + } + AddName(strings, s); + return true; +} diff --git a/CPP/Common/ListFileUtils.h b/CPP/Common/ListFileUtils.h index f8111192d..d43cc378f 100644 --- a/CPP/Common/ListFileUtils.h +++ b/CPP/Common/ListFileUtils.h @@ -1,18 +1,18 @@ -// Common/ListFileUtils.h - -#ifndef ZIP7_INC_COMMON_LIST_FILE_UTILS_H -#define ZIP7_INC_COMMON_LIST_FILE_UTILS_H - -#include "MyString.h" -#include "MyTypes.h" - -#define Z7_WIN_CP_UTF16 1200 -#define Z7_WIN_CP_UTF16BE 1201 - -// bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP); - - // = CP_OEMCP -bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, - DWORD &lastError); - -#endif +// Common/ListFileUtils.h + +#ifndef ZIP7_INC_COMMON_LIST_FILE_UTILS_H +#define ZIP7_INC_COMMON_LIST_FILE_UTILS_H + +#include "MyString.h" +#include "MyTypes.h" + +#define Z7_WIN_CP_UTF16 1200 +#define Z7_WIN_CP_UTF16BE 1201 + +// bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP); + + // = CP_OEMCP +bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, + DWORD &lastError); + +#endif diff --git a/CPP/Common/LzFindPrepare.cpp b/CPP/Common/LzFindPrepare.cpp index 9cdbddcbd..8845e4a55 100644 --- a/CPP/Common/LzFindPrepare.cpp +++ b/CPP/Common/LzFindPrepare.cpp @@ -1,7 +1,7 @@ -// Sha256Prepare.cpp - -#include "StdAfx.h" - -#include "../../C/LzFind.h" - -static struct CLzFindPrepare { CLzFindPrepare() { LzFindPrepare(); } } g_CLzFindPrepare; +// Sha256Prepare.cpp + +#include "StdAfx.h" + +#include "../../C/LzFind.h" + +static struct CLzFindPrepare { CLzFindPrepare() { LzFindPrepare(); } } g_CLzFindPrepare; diff --git a/CPP/Common/Md5Reg.cpp b/CPP/Common/Md5Reg.cpp new file mode 100644 index 000000000..026fd411c --- /dev/null +++ b/CPP/Common/Md5Reg.cpp @@ -0,0 +1,44 @@ +// Md5Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Md5.h" + +#include "../Common/MyBuffer2.h" +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_1( + CMd5Hasher + , IHasher +) + CAlignedBuffer1 _buf; +public: + Byte _mtDummy[1 << 7]; + + CMd5 *Md5() { return (CMd5 *)(void *)(Byte *)_buf; } +public: + CMd5Hasher(): + _buf(sizeof(CMd5)) + { + Md5_Init(Md5()); + } +}; + +Z7_COM7F_IMF2(void, CMd5Hasher::Init()) +{ + Md5_Init(Md5()); +} + +Z7_COM7F_IMF2(void, CMd5Hasher::Update(const void *data, UInt32 size)) +{ + Md5_Update(Md5(), (const Byte *)data, size); +} + +Z7_COM7F_IMF2(void, CMd5Hasher::Final(Byte *digest)) +{ + Md5_Final(Md5(), digest); +} + +REGISTER_HASHER(CMd5Hasher, 0x208, "MD5", MD5_DIGEST_SIZE) diff --git a/CPP/Common/MyBuffer.h b/CPP/Common/MyBuffer.h index 31d619dba..80f0205dc 100644 --- a/CPP/Common/MyBuffer.h +++ b/CPP/Common/MyBuffer.h @@ -1,297 +1,297 @@ -// Common/MyBuffer.h - -#ifndef ZIP7_INC_COMMON_MY_BUFFER_H -#define ZIP7_INC_COMMON_MY_BUFFER_H - -#include - -#include "Defs.h" -#include "MyTypes.h" - -/* 7-Zip now uses CBuffer only as CByteBuffer. - So there is no need to use Z7_ARRAY_NEW macro in CBuffer code. */ - -template class CBuffer -{ - T *_items; - size_t _size; - -public: - void Free() - { - if (_items) - { - delete []_items; - _items = NULL; - } - _size = 0; - } - - CBuffer(): _items(NULL), _size(0) {} - CBuffer(size_t size): _items(NULL), _size(0) - { - if (size != 0) - { - _items = new T[size]; - _size = size; - } - } - CBuffer(const CBuffer &buffer): _items(NULL), _size(0) - { - const size_t size = buffer._size; - if (size != 0) - { - _items = new T[size]; - memcpy(_items, buffer._items, size * sizeof(T)); - _size = size; - } - } - - ~CBuffer() { delete []_items; } - - operator T *() { return _items; } - operator const T *() const { return _items; } - const T* ConstData() const { return _items; } - T* NonConstData() const { return _items; } - T* NonConstData() { return _items; } - // const T* Data() const { return _items; } - // T* Data() { return _items; } - - size_t Size() const { return _size; } - - void Alloc(size_t size) - { - if (size != _size) - { - Free(); - if (size != 0) - { - _items = new T[size]; - _size = size; - } - } - } - - void AllocAtLeast(size_t size) - { - if (size > _size) - { - Free(); - _items = new T[size]; - _size = size; - } - } - - void CopyFrom(const T *data, size_t size) - { - Alloc(size); - if (size != 0) - memcpy(_items, data, size * sizeof(T)); - } - - void ChangeSize_KeepData(size_t newSize, size_t keepSize) - { - if (newSize == _size) - return; - T *newBuffer = NULL; - if (newSize != 0) - { - newBuffer = new T[newSize]; - if (keepSize > _size) - keepSize = _size; - if (keepSize != 0) - memcpy(newBuffer, _items, MyMin(keepSize, newSize) * sizeof(T)); - } - delete []_items; - _items = newBuffer; - _size = newSize; - } - - void Wipe() - { - if (_size != 0) - memset(_items, 0, _size * sizeof(T)); - } - - CBuffer& operator=(const CBuffer &buffer) - { - if (&buffer != this) - CopyFrom(buffer, buffer._size); - return *this; - } -}; - -template -bool operator==(const CBuffer& b1, const CBuffer& b2) -{ - size_t size1 = b1.Size(); - if (size1 != b2.Size()) - return false; - if (size1 == 0) - return true; - return memcmp(b1, b2, size1 * sizeof(T)) == 0; -} - -template -bool operator!=(const CBuffer& b1, const CBuffer& b2) -{ - size_t size1 = b1.Size(); - if (size1 != b2.Size()) - return true; - if (size1 == 0) - return false; - return memcmp(b1, b2, size1 * sizeof(T)) != 0; -} - - -// typedef CBuffer CCharBuffer; -// typedef CBuffer CWCharBuffer; -typedef CBuffer CByteBuffer; - - -class CByteBuffer_Wipe: public CByteBuffer -{ - Z7_CLASS_NO_COPY(CByteBuffer_Wipe) -public: - // CByteBuffer_Wipe(): CBuffer() {} - CByteBuffer_Wipe(size_t size): CBuffer(size) {} - ~CByteBuffer_Wipe() { Wipe(); } -}; - - - -template class CObjArray -{ -protected: - T *_items; -private: - // we disable copy - CObjArray(const CObjArray &buffer); - void operator=(const CObjArray &buffer); -public: - void Free() - { - delete []_items; - _items = NULL; - } - CObjArray(size_t size): _items(NULL) - { - if (size != 0) - { - Z7_ARRAY_NEW(_items, T, size) - // _items = new T[size]; - } - } - CObjArray(): _items(NULL) {} - ~CObjArray() { delete []_items; } - - operator T *() { return _items; } - operator const T *() const { return _items; } - const T* ConstData() const { return _items; } - T* NonConstData() const { return _items; } - T* NonConstData() { return _items; } - // const T* Data() const { return _items; } - // T* Data() { return _items; } - - void Alloc(size_t newSize) - { - delete []_items; - _items = NULL; - Z7_ARRAY_NEW(_items, T, newSize) - // _items = new T[newSize]; - } -}; - -typedef CObjArray CByteArr; -typedef CObjArray CBoolArr; -typedef CObjArray CIntArr; -typedef CObjArray CUIntArr; - - -template class CObjArray2 -{ - T *_items; - unsigned _size; - - // we disable copy - CObjArray2(const CObjArray2 &buffer); - void operator=(const CObjArray2 &buffer); -public: - - void Free() - { - delete []_items; - _items = NULL; - _size = 0; - } - CObjArray2(): _items(NULL), _size(0) {} - /* - CObjArray2(const CObjArray2 &buffer): _items(NULL), _size(0) - { - size_t newSize = buffer._size; - if (newSize != 0) - { - T *newBuffer = new T[newSize];; - _items = newBuffer; - _size = newSize; - const T *src = buffer; - for (size_t i = 0; i < newSize; i++) - newBuffer[i] = src[i]; - } - } - */ - /* - CObjArray2(size_t size): _items(NULL), _size(0) - { - if (size != 0) - { - _items = new T[size]; - _size = size; - } - } - */ - - ~CObjArray2() { delete []_items; } - - operator T *() { return _items; } - operator const T *() const { return _items; } - - unsigned Size() const { return (unsigned)_size; } - bool IsEmpty() const { return _size == 0; } - - // SetSize doesn't keep old items. It allocates new array if size is not equal - void SetSize(unsigned size) - { - if (size == _size) - return; - T *newBuffer = NULL; - if (size != 0) - { - Z7_ARRAY_NEW(newBuffer, T, size) - // newBuffer = new T[size]; - } - delete []_items; - _items = newBuffer; - _size = size; - } - - /* - CObjArray2& operator=(const CObjArray2 &buffer) - { - Free(); - size_t newSize = buffer._size; - if (newSize != 0) - { - T *newBuffer = new T[newSize];; - _items = newBuffer; - _size = newSize; - const T *src = buffer; - for (size_t i = 0; i < newSize; i++) - newBuffer[i] = src[i]; - } - return *this; - } - */ -}; - -#endif +// Common/MyBuffer.h + +#ifndef ZIP7_INC_COMMON_MY_BUFFER_H +#define ZIP7_INC_COMMON_MY_BUFFER_H + +#include + +#include "Defs.h" +#include "MyTypes.h" + +/* 7-Zip now uses CBuffer only as CByteBuffer. + So there is no need to use Z7_ARRAY_NEW macro in CBuffer code. */ + +template class CBuffer +{ + T *_items; + size_t _size; + +public: + void Free() + { + if (_items) + { + delete []_items; + _items = NULL; + } + _size = 0; + } + + CBuffer(): _items(NULL), _size(0) {} + CBuffer(size_t size): _items(NULL), _size(0) + { + if (size != 0) + { + _items = new T[size]; + _size = size; + } + } + CBuffer(const CBuffer &buffer): _items(NULL), _size(0) + { + const size_t size = buffer._size; + if (size != 0) + { + _items = new T[size]; + memcpy(_items, buffer._items, size * sizeof(T)); + _size = size; + } + } + + ~CBuffer() { delete []_items; } + + operator T *() { return _items; } + operator const T *() const { return _items; } + const T* ConstData() const { return _items; } + T* NonConstData() const { return _items; } + T* NonConstData() { return _items; } + // const T* Data() const { return _items; } + // T* Data() { return _items; } + + size_t Size() const { return _size; } + + void Alloc(size_t size) + { + if (size != _size) + { + Free(); + if (size != 0) + { + _items = new T[size]; + _size = size; + } + } + } + + void AllocAtLeast(size_t size) + { + if (size > _size) + { + Free(); + _items = new T[size]; + _size = size; + } + } + + void CopyFrom(const T *data, size_t size) + { + Alloc(size); + if (size != 0) + memcpy(_items, data, size * sizeof(T)); + } + + void ChangeSize_KeepData(size_t newSize, size_t keepSize) + { + if (newSize == _size) + return; + T *newBuffer = NULL; + if (newSize != 0) + { + newBuffer = new T[newSize]; + if (keepSize > _size) + keepSize = _size; + if (keepSize != 0) + memcpy(newBuffer, _items, MyMin(keepSize, newSize) * sizeof(T)); + } + delete []_items; + _items = newBuffer; + _size = newSize; + } + + void Wipe() + { + if (_size != 0) + memset(_items, 0, _size * sizeof(T)); + } + + CBuffer& operator=(const CBuffer &buffer) + { + if (&buffer != this) + CopyFrom(buffer, buffer._size); + return *this; + } +}; + +template +bool operator==(const CBuffer& b1, const CBuffer& b2) +{ + size_t size1 = b1.Size(); + if (size1 != b2.Size()) + return false; + if (size1 == 0) + return true; + return memcmp(b1, b2, size1 * sizeof(T)) == 0; +} + +template +bool operator!=(const CBuffer& b1, const CBuffer& b2) +{ + size_t size1 = b1.Size(); + if (size1 != b2.Size()) + return true; + if (size1 == 0) + return false; + return memcmp(b1, b2, size1 * sizeof(T)) != 0; +} + + +// typedef CBuffer CCharBuffer; +// typedef CBuffer CWCharBuffer; +typedef CBuffer CByteBuffer; + + +class CByteBuffer_Wipe: public CByteBuffer +{ + Z7_CLASS_NO_COPY(CByteBuffer_Wipe) +public: + // CByteBuffer_Wipe(): CBuffer() {} + CByteBuffer_Wipe(size_t size): CBuffer(size) {} + ~CByteBuffer_Wipe() { Wipe(); } +}; + + + +template class CObjArray +{ +protected: + T *_items; +private: + // we disable copy + CObjArray(const CObjArray &buffer); + void operator=(const CObjArray &buffer); +public: + void Free() + { + delete []_items; + _items = NULL; + } + CObjArray(size_t size): _items(NULL) + { + if (size != 0) + { + Z7_ARRAY_NEW(_items, T, size) + // _items = new T[size]; + } + } + CObjArray(): _items(NULL) {} + ~CObjArray() { delete []_items; } + + operator T *() { return _items; } + operator const T *() const { return _items; } + const T* ConstData() const { return _items; } + T* NonConstData() const { return _items; } + T* NonConstData() { return _items; } + // const T* Data() const { return _items; } + // T* Data() { return _items; } + + void Alloc(size_t newSize) + { + delete []_items; + _items = NULL; + Z7_ARRAY_NEW(_items, T, newSize) + // _items = new T[newSize]; + } +}; + +typedef CObjArray CByteArr; +typedef CObjArray CBoolArr; +typedef CObjArray CIntArr; +typedef CObjArray CUIntArr; + + +template class CObjArray2 +{ + T *_items; + unsigned _size; + + // we disable copy + CObjArray2(const CObjArray2 &buffer); + void operator=(const CObjArray2 &buffer); +public: + + void Free() + { + delete []_items; + _items = NULL; + _size = 0; + } + CObjArray2(): _items(NULL), _size(0) {} + /* + CObjArray2(const CObjArray2 &buffer): _items(NULL), _size(0) + { + size_t newSize = buffer._size; + if (newSize != 0) + { + T *newBuffer = new T[newSize];; + _items = newBuffer; + _size = newSize; + const T *src = buffer; + for (size_t i = 0; i < newSize; i++) + newBuffer[i] = src[i]; + } + } + */ + /* + CObjArray2(size_t size): _items(NULL), _size(0) + { + if (size != 0) + { + _items = new T[size]; + _size = size; + } + } + */ + + ~CObjArray2() { delete []_items; } + + operator T *() { return _items; } + operator const T *() const { return _items; } + + unsigned Size() const { return (unsigned)_size; } + bool IsEmpty() const { return _size == 0; } + + // SetSize doesn't keep old items. It allocates new array if size is not equal + void SetSize(unsigned size) + { + if (size == _size) + return; + T *newBuffer = NULL; + if (size != 0) + { + Z7_ARRAY_NEW(newBuffer, T, size) + // newBuffer = new T[size]; + } + delete []_items; + _items = newBuffer; + _size = size; + } + + /* + CObjArray2& operator=(const CObjArray2 &buffer) + { + Free(); + size_t newSize = buffer._size; + if (newSize != 0) + { + T *newBuffer = new T[newSize];; + _items = newBuffer; + _size = newSize; + const T *src = buffer; + for (size_t i = 0; i < newSize; i++) + newBuffer[i] = src[i]; + } + return *this; + } + */ +}; + +#endif diff --git a/CPP/Common/MyBuffer2.h b/CPP/Common/MyBuffer2.h index 8db937f3a..1ec8ffb89 100644 --- a/CPP/Common/MyBuffer2.h +++ b/CPP/Common/MyBuffer2.h @@ -1,185 +1,185 @@ -// Common/MyBuffer2.h - -#ifndef ZIP7_INC_COMMON_MY_BUFFER2_H -#define ZIP7_INC_COMMON_MY_BUFFER2_H - -#include "../../C/Alloc.h" - -#include "MyTypes.h" - -class CMidBuffer -{ - Byte *_data; - size_t _size; - - Z7_CLASS_NO_COPY(CMidBuffer) - -public: - CMidBuffer(): _data(NULL), _size(0) {} - ~CMidBuffer() { ::MidFree(_data); } - - void Free() { ::MidFree(_data); _data = NULL; _size = 0; } - - bool IsAllocated() const { return _data != NULL; } - operator Byte *() { return _data; } - operator const Byte *() const { return _data; } - size_t Size() const { return _size; } - - void Alloc(size_t size) - { - if (!_data || size != _size) - { - ::MidFree(_data); - _size = 0; - _data = NULL; - _data = (Byte *)::MidAlloc(size); - if (_data) - _size = size; - } - } - - void AllocAtLeast(size_t size) - { - if (!_data || size > _size) - { - ::MidFree(_data); - const size_t kMinSize = (size_t)1 << 16; - if (size < kMinSize) - size = kMinSize; - _size = 0; - _data = NULL; - _data = (Byte *)::MidAlloc(size); - if (_data) - _size = size; - } - } -}; - - -class CAlignedBuffer1 -{ - Byte *_data; - - Z7_CLASS_NO_COPY(CAlignedBuffer1) - -public: - ~CAlignedBuffer1() - { - z7_AlignedFree(_data); - } - - CAlignedBuffer1(size_t size) - { - _data = NULL; - _data = (Byte *)z7_AlignedAlloc(size); - if (!_data) - throw 1; - } - - operator Byte *() { return _data; } - operator const Byte *() const { return _data; } -}; - - -class CAlignedBuffer -{ - Byte *_data; - size_t _size; - - Z7_CLASS_NO_COPY(CAlignedBuffer) - -public: - CAlignedBuffer(): _data(NULL), _size(0) {} - ~CAlignedBuffer() - { - z7_AlignedFree(_data); - } - - /* - CAlignedBuffer(size_t size): _size(0) - { - _data = NULL; - _data = (Byte *)z7_AlignedAlloc(size); - if (!_data) - throw 1; - _size = size; - } - */ - - void Free() - { - z7_AlignedFree(_data); - _data = NULL; - _size = 0; - } - - bool IsAllocated() const { return _data != NULL; } - operator Byte *() { return _data; } - operator const Byte *() const { return _data; } - size_t Size() const { return _size; } - - void Alloc(size_t size) - { - if (!_data || size != _size) - { - z7_AlignedFree(_data); - _size = 0; - _data = NULL; - _data = (Byte *)z7_AlignedAlloc(size); - if (_data) - _size = size; - } - } - - void AllocAtLeast(size_t size) - { - if (!_data || size > _size) - { - z7_AlignedFree(_data); - _size = 0; - _data = NULL; - _data = (Byte *)z7_AlignedAlloc(size); - if (_data) - _size = size; - } - } - - // (size <= size_max) - void AllocAtLeast_max(size_t size, size_t size_max) - { - if (!_data || size > _size) - { - z7_AlignedFree(_data); - _size = 0; - _data = NULL; - if (size_max < size) size_max = size; // optional check - const size_t delta = size / 2; - size += delta; - if (size < delta || size > size_max) - size = size_max; - _data = (Byte *)z7_AlignedAlloc(size); - if (_data) - _size = size; - } - } -}; - -/* - CMidAlignedBuffer must return aligned pointer. - - in Windows it uses CMidBuffer(): MidAlloc() : VirtualAlloc() - VirtualAlloc(): Memory allocated is automatically initialized to zero. - MidAlloc(0) returns NULL - - in non-Windows systems it uses g_AlignedAlloc. - g_AlignedAlloc::Alloc(size = 0) can return non NULL. -*/ - -typedef -#ifdef _WIN32 - CMidBuffer -#else - CAlignedBuffer -#endif - CMidAlignedBuffer; - - -#endif +// Common/MyBuffer2.h + +#ifndef ZIP7_INC_COMMON_MY_BUFFER2_H +#define ZIP7_INC_COMMON_MY_BUFFER2_H + +#include "../../C/Alloc.h" + +#include "MyTypes.h" + +class CMidBuffer +{ + Byte *_data; + size_t _size; + + Z7_CLASS_NO_COPY(CMidBuffer) + +public: + CMidBuffer(): _data(NULL), _size(0) {} + ~CMidBuffer() { ::MidFree(_data); } + + void Free() { ::MidFree(_data); _data = NULL; _size = 0; } + + bool IsAllocated() const { return _data != NULL; } + operator Byte *() { return _data; } + operator const Byte *() const { return _data; } + size_t Size() const { return _size; } + + void Alloc(size_t size) + { + if (!_data || size != _size) + { + ::MidFree(_data); + _size = 0; + _data = NULL; + _data = (Byte *)::MidAlloc(size); + if (_data) + _size = size; + } + } + + void AllocAtLeast(size_t size) + { + if (!_data || size > _size) + { + ::MidFree(_data); + const size_t kMinSize = (size_t)1 << 16; + if (size < kMinSize) + size = kMinSize; + _size = 0; + _data = NULL; + _data = (Byte *)::MidAlloc(size); + if (_data) + _size = size; + } + } +}; + + +class CAlignedBuffer1 +{ + Byte *_data; + + Z7_CLASS_NO_COPY(CAlignedBuffer1) + +public: + ~CAlignedBuffer1() + { + z7_AlignedFree(_data); + } + + CAlignedBuffer1(size_t size) + { + _data = NULL; + _data = (Byte *)z7_AlignedAlloc(size); + if (!_data) + throw 1; + } + + operator Byte *() { return _data; } + operator const Byte *() const { return _data; } +}; + + +class CAlignedBuffer +{ + Byte *_data; + size_t _size; + + Z7_CLASS_NO_COPY(CAlignedBuffer) + +public: + CAlignedBuffer(): _data(NULL), _size(0) {} + ~CAlignedBuffer() + { + z7_AlignedFree(_data); + } + + /* + CAlignedBuffer(size_t size): _size(0) + { + _data = NULL; + _data = (Byte *)z7_AlignedAlloc(size); + if (!_data) + throw 1; + _size = size; + } + */ + + void Free() + { + z7_AlignedFree(_data); + _data = NULL; + _size = 0; + } + + bool IsAllocated() const { return _data != NULL; } + operator Byte *() { return _data; } + operator const Byte *() const { return _data; } + size_t Size() const { return _size; } + + void Alloc(size_t size) + { + if (!_data || size != _size) + { + z7_AlignedFree(_data); + _size = 0; + _data = NULL; + _data = (Byte *)z7_AlignedAlloc(size); + if (_data) + _size = size; + } + } + + void AllocAtLeast(size_t size) + { + if (!_data || size > _size) + { + z7_AlignedFree(_data); + _size = 0; + _data = NULL; + _data = (Byte *)z7_AlignedAlloc(size); + if (_data) + _size = size; + } + } + + // (size <= size_max) + void AllocAtLeast_max(size_t size, size_t size_max) + { + if (!_data || size > _size) + { + z7_AlignedFree(_data); + _size = 0; + _data = NULL; + if (size_max < size) size_max = size; // optional check + const size_t delta = size / 2; + size += delta; + if (size < delta || size > size_max) + size = size_max; + _data = (Byte *)z7_AlignedAlloc(size); + if (_data) + _size = size; + } + } +}; + +/* + CMidAlignedBuffer must return aligned pointer. + - in Windows it uses CMidBuffer(): MidAlloc() : VirtualAlloc() + VirtualAlloc(): Memory allocated is automatically initialized to zero. + MidAlloc(0) returns NULL + - in non-Windows systems it uses g_AlignedAlloc. + g_AlignedAlloc::Alloc(size = 0) can return non NULL. +*/ + +typedef +#ifdef _WIN32 + CMidBuffer +#else + CAlignedBuffer +#endif + CMidAlignedBuffer; + + +#endif diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h index 2112b9cd0..7dc21baab 100644 --- a/CPP/Common/MyCom.h +++ b/CPP/Common/MyCom.h @@ -1,656 +1,693 @@ -// MyCom.h - -#ifndef ZIP7_INC_MY_COM_H -#define ZIP7_INC_MY_COM_H - -#include "MyWindows.h" -#include "MyTypes.h" - -template -class CMyComPtr -{ - T* _p; -public: - CMyComPtr(): _p(NULL) {} - CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } - CMyComPtr(const CMyComPtr& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); } - ~CMyComPtr() { if (_p) _p->Release(); } - void Release() { if (_p) { _p->Release(); _p = NULL; } } - operator T*() const { return (T*)_p; } - T* Interface() const { return (T*)_p; } - // T& operator*() const { return *_p; } - T** operator&() { return &_p; } - T* operator->() const { return _p; } - T* operator=(T* p) - { - if (p) - p->AddRef(); - if (_p) - _p->Release(); - _p = p; - return p; - } - T* operator=(const CMyComPtr& lp) { return (*this = lp._p); } - bool operator!() const { return (_p == NULL); } - // bool operator==(T* pT) const { return _p == pT; } - void Attach(T* p2) - { - Release(); - _p = p2; - } - T* Detach() - { - T* pt = _p; - _p = NULL; - return pt; - } - #ifdef _WIN32 - HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) - { - return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p); - } - #endif - /* - HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) - { - CLSID clsid; - HRESULT hr = CLSIDFromProgID(szProgID, &clsid); - ATLASSERT(_p == NULL); - if (SUCCEEDED(hr)) - hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p); - return hr; - } - */ - template - HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() - { - // if (*pp) throw 20220216; // for debug - return _p->QueryInterface(iid, (void**)pp); - } -}; - - -template -class CMyComPtr2 -{ - cls* _p; - - CMyComPtr2(const CMyComPtr2& lp); - CMyComPtr2(cls* p); - CMyComPtr2(iface* p); - iface* operator=(const CMyComPtr2& lp); - iface* operator=(cls* p); - iface* operator=(iface* p); -public: - CMyComPtr2(): _p(NULL) {} - ~CMyComPtr2() - { - if (_p) - { - iface *ip = _p; - ip->Release(); - } - } - // void Release() { if (_p) { (iface *)_p->Release(); _p = NULL; } } - cls* operator->() const { return _p; } - cls* ClsPtr() const { return _p; } - operator iface*() const - { - iface *ip = _p; - return ip; - } - iface* Interface() const - { - iface *ip = _p; - return ip; - } - // operator bool() const { return _p != NULL; } - bool IsDefined() const { return _p != NULL; } - void Create_if_Empty() - { - if (!_p) - { - _p = new cls; - iface *ip = _p; - ip->AddRef(); - } - } - iface* Detach() - { - iface *ip = _p; - _p = NULL; - return ip; - } - void SetFromCls(cls *src) - { - if (src) - { - iface *ip = src; - ip->AddRef(); - } - if (_p) - { - iface *ip = _p; - ip->Release(); - } - _p = src; - } -}; - - -template -class CMyComPtr2_Create -{ - cls* _p; - - CMyComPtr2_Create(const CMyComPtr2_Create& lp); - CMyComPtr2_Create(cls* p); - CMyComPtr2_Create(iface* p); - iface* operator=(const CMyComPtr2_Create& lp); - iface* operator=(cls* p); - iface* operator=(iface* p); -public: - CMyComPtr2_Create(): _p(new cls) - { - iface *ip = _p; - ip->AddRef(); - } - ~CMyComPtr2_Create() - { - iface *ip = _p; - ip->Release(); - } - cls* operator->() const { return _p; } - cls* ClsPtr() const { return _p; } - operator iface*() const - { - iface *ip = _p; - return ip; - } - iface* Interface() const - { - iface *ip = _p; - return ip; - } -}; - - -#define Z7_DECL_CMyComPtr_QI_FROM(i, v, unk) \ - CMyComPtr v; (unk)->QueryInterface(IID_ ## i, (void **)&v); - - -////////////////////////////////////////////////////////// - -inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr) -{ - *bstr = ::SysAllocString(src); - return (*bstr) ? S_OK : E_OUTOFMEMORY; -} - -class CMyComBSTR -{ - BSTR m_str; - Z7_CLASS_NO_COPY(CMyComBSTR) -public: - CMyComBSTR(): m_str(NULL) {} - ~CMyComBSTR() { ::SysFreeString(m_str); } - BSTR* operator&() { return &m_str; } - operator LPCOLESTR() const { return m_str; } - // operator bool() const { return m_str != NULL; } - // bool operator!() const { return m_str == NULL; } - - void Wipe_and_Free() - { - if (m_str) - { - memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str)); - Empty(); - } - } - -private: - // operator BSTR() const { return m_str; } - - CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); } - // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); } - // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); } - // CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); } - - /* - CMyComBSTR(REFGUID src) - { - LPOLESTR szGuid; - StringFromCLSID(src, &szGuid); - m_str = ::SysAllocString(szGuid); - CoTaskMemFree(szGuid); - } - */ - - /* - CMyComBSTR& operator=(const CMyComBSTR& src) - { - if (m_str != src.m_str) - { - if (m_str) - ::SysFreeString(m_str); - m_str = src.MyCopy(); - } - return *this; - } - */ - - CMyComBSTR& operator=(LPCOLESTR src) - { - ::SysFreeString(m_str); - m_str = ::SysAllocString(src); - return *this; - } - - unsigned Len() const { return ::SysStringLen(m_str); } - - BSTR MyCopy() const - { - // We don't support Byte BSTRs here - return ::SysAllocStringLen(m_str, ::SysStringLen(m_str)); - /* - UINT byteLen = ::SysStringByteLen(m_str); - BSTR res = ::SysAllocStringByteLen(NULL, byteLen); - if (res && byteLen != 0 && m_str) - memcpy(res, m_str, byteLen); - return res; - */ - } - - /* - void Attach(BSTR src) { m_str = src; } - BSTR Detach() - { - BSTR s = m_str; - m_str = NULL; - return s; - } - */ - - void Empty() - { - ::SysFreeString(m_str); - m_str = NULL; - } -}; - - -class CMyComBSTR_Wipe: public CMyComBSTR -{ - Z7_CLASS_NO_COPY(CMyComBSTR_Wipe) -public: - CMyComBSTR_Wipe(): CMyComBSTR() {} - ~CMyComBSTR_Wipe() { Wipe_and_Free(); } -}; - - - -/* - If CMyUnknownImp doesn't use virtual destructor, the code size is smaller. - But if some class_1 derived from CMyUnknownImp - uses Z7_COM_ADDREF_RELEASE and IUnknown::Release() - and some another class_2 is derived from class_1, - then class_1 must use virtual destructor: - virtual ~class_1(); - In that case, class_1::Release() calls correct destructor of class_2. - We can use virtual ~CMyUnknownImp() to disable warning - "class has virtual functions, but destructor is not virtual". - Also we can use virtual ~IUnknown() {} in MyWindows.h -*/ - -class CMyUnknownImp -{ - Z7_CLASS_NO_COPY(CMyUnknownImp) -protected: - ULONG _m_RefCount; - CMyUnknownImp(): _m_RefCount(0) {} - - #ifdef _WIN32 - #if defined(__GNUC__) || defined(__clang__) - // virtual ~CMyUnknownImp() {} // to disable GCC/CLANG varnings - #endif - #endif -}; - - - -#define Z7_COM_QI_BEGIN \ - private: STDMETHOD(QueryInterface) (REFGUID iid, void **outObject) throw() Z7_override Z7_final \ - { *outObject = NULL; - -#define Z7_COM_QI_ENTRY(i) \ - else if (iid == IID_ ## i) \ - { i *ti = this; *outObject = ti; } -// { *outObject = (void *)(i *)this; } - -#define Z7_COM_QI_ENTRY_UNKNOWN_0 \ - if (iid == IID_IUnknown) \ - { IUnknown *tu = this; *outObject = tu; } - -#define Z7_COM_QI_ENTRY_UNKNOWN(i) \ - if (iid == IID_IUnknown) \ - { i *ti = this; IUnknown *tu = ti; *outObject = tu; } -// { *outObject = (void *)(IUnknown *)(i *)this; } - -#define Z7_COM_QI_BEGIN2(i) \ - Z7_COM_QI_BEGIN \ - Z7_COM_QI_ENTRY_UNKNOWN(i) \ - Z7_COM_QI_ENTRY(i) - - -#define Z7_COM_ADDREF_RELEASE_MT \ - private: \ - STDMETHOD_(ULONG, AddRef)() Z7_override Z7_final \ - { return (ULONG)InterlockedIncrement((LONG *)&_m_RefCount); } \ - STDMETHOD_(ULONG, Release)() Z7_override Z7_final \ - { const LONG v = InterlockedDecrement((LONG *)&_m_RefCount); \ - if (v != 0) return (ULONG)v; \ - delete this; return 0; } - -#define Z7_COM_QI_END_MT \ - else return E_NOINTERFACE; \ - InterlockedIncrement((LONG *)&_m_RefCount); /* AddRef(); */ return S_OK; } - -// you can define Z7_COM_USE_ATOMIC, -// if you want to call Release() from different threads (for example, for .NET code) -// #define Z7_COM_USE_ATOMIC - -#if defined(Z7_COM_USE_ATOMIC) && !defined(Z7_ST) - -#ifndef _WIN32 -#if 0 -#include "../../C/Threads.h" -#else -EXTERN_C_BEGIN -LONG InterlockedIncrement(LONG volatile *addend); -LONG InterlockedDecrement(LONG volatile *addend); -EXTERN_C_END -#endif -#endif // _WIN32 - -#define Z7_COM_ADDREF_RELEASE Z7_COM_ADDREF_RELEASE_MT -#define Z7_COM_QI_END Z7_COM_QI_END_MT - -#else // !Z7_COM_USE_ATOMIC - -#define Z7_COM_ADDREF_RELEASE \ - private: \ - STDMETHOD_(ULONG, AddRef)() throw() Z7_override Z7_final \ - { return ++_m_RefCount; } \ - STDMETHOD_(ULONG, Release)() throw() Z7_override Z7_final \ - { if (--_m_RefCount != 0) return _m_RefCount; \ - delete this; return 0; } - -#define Z7_COM_QI_END \ - else return E_NOINTERFACE; \ - ++_m_RefCount; /* AddRef(); */ return S_OK; } - -#endif // !Z7_COM_USE_ATOMIC - - -#define Z7_COM_UNKNOWN_IMP_SPEC(i) \ - Z7_COM_QI_BEGIN \ - i \ - Z7_COM_QI_END \ - Z7_COM_ADDREF_RELEASE - - -#define Z7_COM_UNKNOWN_IMP_0 \ - Z7_COM_QI_BEGIN \ - Z7_COM_QI_ENTRY_UNKNOWN_0 \ - Z7_COM_QI_END \ - Z7_COM_ADDREF_RELEASE - -#define Z7_COM_UNKNOWN_IMP_1(i) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i) \ - Z7_COM_QI_ENTRY(i) \ - ) - -#define Z7_COM_UNKNOWN_IMP_2(i1, i2) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - ) - -#define Z7_COM_UNKNOWN_IMP_3(i1, i2, i3) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - ) - -#define Z7_COM_UNKNOWN_IMP_4(i1, i2, i3, i4) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - Z7_COM_QI_ENTRY(i4) \ - ) - -#define Z7_COM_UNKNOWN_IMP_5(i1, i2, i3, i4, i5) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - Z7_COM_QI_ENTRY(i4) \ - Z7_COM_QI_ENTRY(i5) \ - ) - -#define Z7_COM_UNKNOWN_IMP_6(i1, i2, i3, i4, i5, i6) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - Z7_COM_QI_ENTRY(i4) \ - Z7_COM_QI_ENTRY(i5) \ - Z7_COM_QI_ENTRY(i6) \ - ) - -#define Z7_COM_UNKNOWN_IMP_7(i1, i2, i3, i4, i5, i6, i7) \ - Z7_COM_UNKNOWN_IMP_SPEC( \ - Z7_COM_QI_ENTRY_UNKNOWN(i1) \ - Z7_COM_QI_ENTRY(i1) \ - Z7_COM_QI_ENTRY(i2) \ - Z7_COM_QI_ENTRY(i3) \ - Z7_COM_QI_ENTRY(i4) \ - Z7_COM_QI_ENTRY(i5) \ - Z7_COM_QI_ENTRY(i6) \ - Z7_COM_QI_ENTRY(i7) \ - ) - - -#define Z7_IFACES_IMP_UNK_1(i1) \ - Z7_COM_UNKNOWN_IMP_1(i1) \ - Z7_IFACE_COM7_IMP(i1) \ - -#define Z7_IFACES_IMP_UNK_2(i1, i2) \ - Z7_COM_UNKNOWN_IMP_2(i1, i2) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - -#define Z7_IFACES_IMP_UNK_3(i1, i2, i3) \ - Z7_COM_UNKNOWN_IMP_3(i1, i2, i3) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - -#define Z7_IFACES_IMP_UNK_4(i1, i2, i3, i4) \ - Z7_COM_UNKNOWN_IMP_4(i1, i2, i3, i4) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - Z7_IFACE_COM7_IMP(i4) \ - -#define Z7_IFACES_IMP_UNK_5(i1, i2, i3, i4, i5) \ - Z7_COM_UNKNOWN_IMP_5(i1, i2, i3, i4, i5) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - Z7_IFACE_COM7_IMP(i4) \ - Z7_IFACE_COM7_IMP(i5) \ - -#define Z7_IFACES_IMP_UNK_6(i1, i2, i3, i4, i5, i6) \ - Z7_COM_UNKNOWN_IMP_6(i1, i2, i3, i4, i5, i6) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - Z7_IFACE_COM7_IMP(i4) \ - Z7_IFACE_COM7_IMP(i5) \ - Z7_IFACE_COM7_IMP(i6) \ - - -#define Z7_CLASS_IMP_COM_0(c) \ - Z7_class_final(c) : \ - public IUnknown, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_0 \ - private: - -#define Z7_CLASS_IMP_COM_1(c, i1) \ - Z7_class_final(c) : \ - public i1, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_1(i1) \ - private: - -#define Z7_CLASS_IMP_COM_2(c, i1, i2) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_2(i1, i2) \ - private: - -#define Z7_CLASS_IMP_COM_3(c, i1, i2, i3) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_3(i1, i2, i3) \ - private: - -#define Z7_CLASS_IMP_COM_4(c, i1, i2, i3, i4) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public i4, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_4(i1, i2, i3, i4) \ - private: - -#define Z7_CLASS_IMP_COM_5(c, i1, i2, i3, i4, i5) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public i4, \ - public i5, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_5(i1, i2, i3, i4, i5) \ - private: - -#define Z7_CLASS_IMP_COM_6(c, i1, i2, i3, i4, i5, i6) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public i4, \ - public i5, \ - public i6, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_6(i1, i2, i3, i4, i5, i6) \ - private: - - -/* -#define Z7_CLASS_IMP_NOQIB_0(c) \ - Z7_class_final(c) : \ - public IUnknown, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_0 \ - private: -*/ - -#define Z7_CLASS_IMP_NOQIB_1(c, i1) \ - Z7_class_final(c) : \ - public i1, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_0 \ - Z7_IFACE_COM7_IMP(i1) \ - private: - -#define Z7_CLASS_IMP_NOQIB_2(c, i1, i2) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_1(i2) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - private: - -#define Z7_CLASS_IMP_NOQIB_3(c, i1, i2, i3) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_2(i2, i3) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - private: - -#define Z7_CLASS_IMP_NOQIB_4(c, i1, i2, i3, i4) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public i4, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_3(i2, i3, i4) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - Z7_IFACE_COM7_IMP(i4) \ - -/* -#define Z7_CLASS_IMP_NOQIB_5(c, i1, i2, i3, i4, i5) \ - Z7_class_final(c) : \ - public i1, \ - public i2, \ - public i3, \ - public i4, \ - public i5, \ - public CMyUnknownImp { \ - Z7_COM_UNKNOWN_IMP_4(i2, i3, i4, i5) \ - Z7_IFACE_COM7_IMP(i1) \ - Z7_IFACE_COM7_IMP(i2) \ - Z7_IFACE_COM7_IMP(i3) \ - Z7_IFACE_COM7_IMP(i4) \ - Z7_IFACE_COM7_IMP(i5) \ -*/ - - -#define Z7_CLASS_IMP_IInStream(c) \ - class c Z7_final : \ - public IInStream, \ - public CMyUnknownImp { \ - Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) \ - - -#define k_My_HRESULT_WritingWasCut 0x20000010 - -#endif +// MyCom.h + +#ifndef ZIP7_INC_MY_COM_H +#define ZIP7_INC_MY_COM_H + +#include "MyWindows.h" +#include "MyTypes.h" + +template +class CMyComPtr +{ + T* _p; +public: + CMyComPtr(): _p(NULL) {} + CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } + CMyComPtr(const CMyComPtr& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); } + ~CMyComPtr() { if (_p) _p->Release(); } + void Release() { if (_p) { _p->Release(); _p = NULL; } } + operator T*() const { return (T*)_p; } + T* Interface() const { return (T*)_p; } + // T& operator*() const { return *_p; } + T** operator&() { return &_p; } + T* operator->() const { return _p; } + T* operator=(T* p) + { + if (p) + p->AddRef(); + if (_p) + _p->Release(); + _p = p; + return p; + } + T* operator=(const CMyComPtr& lp) { return (*this = lp._p); } + bool operator!() const { return (_p == NULL); } + // bool operator==(T* pT) const { return _p == pT; } + void Attach(T* p2) + { + Release(); + _p = p2; + } + T* Detach() + { + T* pt = _p; + _p = NULL; + return pt; + } + #ifdef _WIN32 + HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) + { + return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p); + } + #endif + /* + HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) + { + CLSID clsid; + HRESULT hr = CLSIDFromProgID(szProgID, &clsid); + ATLASSERT(_p == NULL); + if (SUCCEEDED(hr)) + hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p); + return hr; + } + */ + template + HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() + { + // if (*pp) throw 20220216; // for debug + return _p->QueryInterface(iid, (void**)pp); + } +}; + + +template +class CMyComPtr2 +{ + cls* _p; + + CMyComPtr2(const CMyComPtr2& lp); + CMyComPtr2(cls* p); + CMyComPtr2(iface* p); + iface* operator=(const CMyComPtr2& lp); + iface* operator=(cls* p); + iface* operator=(iface* p); +public: + CMyComPtr2(): _p(NULL) {} + ~CMyComPtr2() + { + if (_p) + { + iface *ip = _p; + ip->Release(); + } + } + // void Release() { if (_p) { (iface *)_p->Release(); _p = NULL; } } + cls* operator->() const { return _p; } + cls* ClsPtr() const { return _p; } + operator iface*() const + { + iface *ip = _p; + return ip; + } + iface* Interface() const + { + iface *ip = _p; + return ip; + } + // operator bool() const { return _p != NULL; } + bool IsDefined() const { return _p != NULL; } + void Create_if_Empty() + { + if (!_p) + { + _p = new cls; + iface *ip = _p; + ip->AddRef(); + } + } + iface* Detach() + { + iface *ip = _p; + _p = NULL; + return ip; + } + void SetFromCls(cls *src) + { + if (src) + { + iface *ip = src; + ip->AddRef(); + } + if (_p) + { + iface *ip = _p; + ip->Release(); + } + _p = src; + } +}; + + +template +class CMyComPtr2_Create +{ + cls* _p; + + CMyComPtr2_Create(const CMyComPtr2_Create& lp); + CMyComPtr2_Create(cls* p); + CMyComPtr2_Create(iface* p); + iface* operator=(const CMyComPtr2_Create& lp); + iface* operator=(cls* p); + iface* operator=(iface* p); +public: + CMyComPtr2_Create(): _p(new cls) + { + iface *ip = _p; + ip->AddRef(); + } + ~CMyComPtr2_Create() + { + iface *ip = _p; + ip->Release(); + } + cls* operator->() const { return _p; } + cls* ClsPtr() const { return _p; } + operator iface*() const + { + iface *ip = _p; + return ip; + } + iface* Interface() const + { + iface *ip = _p; + return ip; + } +}; + + +#define Z7_DECL_CMyComPtr_QI_FROM(i, v, unk) \ + CMyComPtr v; (unk)->QueryInterface(IID_ ## i, (void **)&v); + + +////////////////////////////////////////////////////////// + +inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr) +{ + *bstr = ::SysAllocString(src); + return (*bstr) ? S_OK : E_OUTOFMEMORY; +} + +class CMyComBSTR +{ + BSTR m_str; + Z7_CLASS_NO_COPY(CMyComBSTR) +public: + CMyComBSTR(): m_str(NULL) {} + ~CMyComBSTR() { ::SysFreeString(m_str); } + BSTR* operator&() { return &m_str; } + operator LPCOLESTR() const { return m_str; } + // operator bool() const { return m_str != NULL; } + // bool operator!() const { return m_str == NULL; } + + void Wipe_and_Free() + { + if (m_str) + { + memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str)); + Empty(); + } + } + +private: + // operator BSTR() const { return m_str; } + + CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); } + // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); } + // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); } + // CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); } + + /* + CMyComBSTR(REFGUID src) + { + LPOLESTR szGuid; + StringFromCLSID(src, &szGuid); + m_str = ::SysAllocString(szGuid); + CoTaskMemFree(szGuid); + } + */ + + /* + CMyComBSTR& operator=(const CMyComBSTR& src) + { + if (m_str != src.m_str) + { + if (m_str) + ::SysFreeString(m_str); + m_str = src.MyCopy(); + } + return *this; + } + */ + + CMyComBSTR& operator=(LPCOLESTR src) + { + ::SysFreeString(m_str); + m_str = ::SysAllocString(src); + return *this; + } + + unsigned Len() const { return ::SysStringLen(m_str); } + + BSTR MyCopy() const + { + // We don't support Byte BSTRs here + return ::SysAllocStringLen(m_str, ::SysStringLen(m_str)); + /* + UINT byteLen = ::SysStringByteLen(m_str); + BSTR res = ::SysAllocStringByteLen(NULL, byteLen); + if (res && byteLen != 0 && m_str) + memcpy(res, m_str, byteLen); + return res; + */ + } + + /* + void Attach(BSTR src) { m_str = src; } + BSTR Detach() + { + BSTR s = m_str; + m_str = NULL; + return s; + } + */ + + void Empty() + { + ::SysFreeString(m_str); + m_str = NULL; + } +}; + + +class CMyComBSTR_Wipe: public CMyComBSTR +{ + Z7_CLASS_NO_COPY(CMyComBSTR_Wipe) +public: + CMyComBSTR_Wipe(): CMyComBSTR() {} + ~CMyComBSTR_Wipe() { Wipe_and_Free(); } +}; + + + +/* + If CMyUnknownImp doesn't use virtual destructor, the code size is smaller. + But if some class_1 derived from CMyUnknownImp + uses Z7_COM_ADDREF_RELEASE and IUnknown::Release() + and some another class_2 is derived from class_1, + then class_1 must use virtual destructor: + virtual ~class_1(); + In that case, class_1::Release() calls correct destructor of class_2. + We can use virtual ~CMyUnknownImp() to disable warning + "class has virtual functions, but destructor is not virtual". + Also we can use virtual ~IUnknown() {} in MyWindows.h +*/ + +class CMyUnknownImp +{ + Z7_CLASS_NO_COPY(CMyUnknownImp) +protected: + ULONG _m_RefCount; + CMyUnknownImp(): _m_RefCount(0) {} + + #ifdef _WIN32 + #if defined(__GNUC__) || defined(__clang__) + // virtual ~CMyUnknownImp() {} // to disable GCC/CLANG varnings + #endif + #endif +}; + + + +#define Z7_COM_QI_BEGIN \ + private: STDMETHOD(QueryInterface) (REFGUID iid, void **outObject) throw() Z7_override Z7_final \ + { *outObject = NULL; + +#define Z7_COM_QI_ENTRY(i) \ + else if (iid == IID_ ## i) \ + { i *ti = this; *outObject = ti; } +// { *outObject = (void *)(i *)this; } + +#define Z7_COM_QI_ENTRY_UNKNOWN_0 \ + if (iid == IID_IUnknown) \ + { IUnknown *tu = this; *outObject = tu; } + +#define Z7_COM_QI_ENTRY_UNKNOWN(i) \ + if (iid == IID_IUnknown) \ + { i *ti = this; IUnknown *tu = ti; *outObject = tu; } +// { *outObject = (void *)(IUnknown *)(i *)this; } + +#define Z7_COM_QI_BEGIN2(i) \ + Z7_COM_QI_BEGIN \ + Z7_COM_QI_ENTRY_UNKNOWN(i) \ + Z7_COM_QI_ENTRY(i) + + +#define Z7_COM_ADDREF_RELEASE_MT \ + private: \ + STDMETHOD_(ULONG, AddRef)() Z7_override Z7_final \ + { return (ULONG)InterlockedIncrement((LONG *)&_m_RefCount); } \ + STDMETHOD_(ULONG, Release)() Z7_override Z7_final \ + { const LONG v = InterlockedDecrement((LONG *)&_m_RefCount); \ + if (v != 0) return (ULONG)v; \ + delete this; return 0; } + +#define Z7_COM_QI_END_MT \ + else return E_NOINTERFACE; \ + InterlockedIncrement((LONG *)&_m_RefCount); /* AddRef(); */ return S_OK; } + +// you can define Z7_COM_USE_ATOMIC, +// if you want to call Release() from different threads (for example, for .NET code) +// #define Z7_COM_USE_ATOMIC + +#if defined(Z7_COM_USE_ATOMIC) && !defined(Z7_ST) + +#ifndef _WIN32 +#if 0 +#include "../../C/Threads.h" +#else +EXTERN_C_BEGIN +LONG InterlockedIncrement(LONG volatile *addend); +LONG InterlockedDecrement(LONG volatile *addend); +EXTERN_C_END +#endif +#endif // _WIN32 + +#define Z7_COM_ADDREF_RELEASE Z7_COM_ADDREF_RELEASE_MT +#define Z7_COM_QI_END Z7_COM_QI_END_MT + +#else // !Z7_COM_USE_ATOMIC + +#define Z7_COM_ADDREF_RELEASE \ + private: \ + STDMETHOD_(ULONG, AddRef)() throw() Z7_override Z7_final \ + { return ++_m_RefCount; } \ + STDMETHOD_(ULONG, Release)() throw() Z7_override Z7_final \ + { if (--_m_RefCount != 0) return _m_RefCount; \ + delete this; return 0; } + +#define Z7_COM_QI_END \ + else return E_NOINTERFACE; \ + ++_m_RefCount; /* AddRef(); */ return S_OK; } + +#endif // !Z7_COM_USE_ATOMIC + + +#define Z7_COM_UNKNOWN_IMP_SPEC(i) \ + Z7_COM_QI_BEGIN \ + i \ + Z7_COM_QI_END \ + Z7_COM_ADDREF_RELEASE + + +#define Z7_COM_UNKNOWN_IMP_0 \ + Z7_COM_QI_BEGIN \ + Z7_COM_QI_ENTRY_UNKNOWN_0 \ + Z7_COM_QI_END \ + Z7_COM_ADDREF_RELEASE + +#define Z7_COM_UNKNOWN_IMP_1(i) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i) \ + Z7_COM_QI_ENTRY(i) \ + ) + +#define Z7_COM_UNKNOWN_IMP_2(i1, i2) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + ) + +#define Z7_COM_UNKNOWN_IMP_3(i1, i2, i3) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + ) + +#define Z7_COM_UNKNOWN_IMP_4(i1, i2, i3, i4) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + Z7_COM_QI_ENTRY(i4) \ + ) + +#define Z7_COM_UNKNOWN_IMP_5(i1, i2, i3, i4, i5) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + Z7_COM_QI_ENTRY(i4) \ + Z7_COM_QI_ENTRY(i5) \ + ) + +#define Z7_COM_UNKNOWN_IMP_6(i1, i2, i3, i4, i5, i6) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + Z7_COM_QI_ENTRY(i4) \ + Z7_COM_QI_ENTRY(i5) \ + Z7_COM_QI_ENTRY(i6) \ + ) + +#define Z7_COM_UNKNOWN_IMP_7(i1, i2, i3, i4, i5, i6, i7) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + Z7_COM_QI_ENTRY(i4) \ + Z7_COM_QI_ENTRY(i5) \ + Z7_COM_QI_ENTRY(i6) \ + Z7_COM_QI_ENTRY(i7) \ + ) + +#define Z7_COM_UNKNOWN_IMP_8(i1, i2, i3, i4, i5, i6, i7, i8) \ + Z7_COM_UNKNOWN_IMP_SPEC( \ + Z7_COM_QI_ENTRY_UNKNOWN(i1) \ + Z7_COM_QI_ENTRY(i1) \ + Z7_COM_QI_ENTRY(i2) \ + Z7_COM_QI_ENTRY(i3) \ + Z7_COM_QI_ENTRY(i4) \ + Z7_COM_QI_ENTRY(i5) \ + Z7_COM_QI_ENTRY(i6) \ + Z7_COM_QI_ENTRY(i7) \ + Z7_COM_QI_ENTRY(i8) \ + ) + + +#define Z7_IFACES_IMP_UNK_1(i1) \ + Z7_COM_UNKNOWN_IMP_1(i1) \ + Z7_IFACE_COM7_IMP(i1) \ + +#define Z7_IFACES_IMP_UNK_2(i1, i2) \ + Z7_COM_UNKNOWN_IMP_2(i1, i2) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + +#define Z7_IFACES_IMP_UNK_3(i1, i2, i3) \ + Z7_COM_UNKNOWN_IMP_3(i1, i2, i3) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + +#define Z7_IFACES_IMP_UNK_4(i1, i2, i3, i4) \ + Z7_COM_UNKNOWN_IMP_4(i1, i2, i3, i4) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + Z7_IFACE_COM7_IMP(i4) \ + +#define Z7_IFACES_IMP_UNK_5(i1, i2, i3, i4, i5) \ + Z7_COM_UNKNOWN_IMP_5(i1, i2, i3, i4, i5) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + Z7_IFACE_COM7_IMP(i4) \ + Z7_IFACE_COM7_IMP(i5) \ + +#define Z7_IFACES_IMP_UNK_6(i1, i2, i3, i4, i5, i6) \ + Z7_COM_UNKNOWN_IMP_6(i1, i2, i3, i4, i5, i6) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + Z7_IFACE_COM7_IMP(i4) \ + Z7_IFACE_COM7_IMP(i5) \ + Z7_IFACE_COM7_IMP(i6) \ + +#define Z7_IFACES_IMP_UNK_7(i1, i2, i3, i4, i5, i6, i7) \ + Z7_COM_UNKNOWN_IMP_7(i1, i2, i3, i4, i5, i6, i7) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + Z7_IFACE_COM7_IMP(i4) \ + Z7_IFACE_COM7_IMP(i5) \ + Z7_IFACE_COM7_IMP(i6) \ + Z7_IFACE_COM7_IMP(i7) \ + + +#define Z7_CLASS_IMP_COM_0(c) \ + Z7_class_final(c) : \ + public IUnknown, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_0 \ + private: + +#define Z7_CLASS_IMP_COM_1(c, i1) \ + Z7_class_final(c) : \ + public i1, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_1(i1) \ + private: + +#define Z7_CLASS_IMP_COM_2(c, i1, i2) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_2(i1, i2) \ + private: + +#define Z7_CLASS_IMP_COM_3(c, i1, i2, i3) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_3(i1, i2, i3) \ + private: + +#define Z7_CLASS_IMP_COM_4(c, i1, i2, i3, i4) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public i4, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_4(i1, i2, i3, i4) \ + private: + +#define Z7_CLASS_IMP_COM_5(c, i1, i2, i3, i4, i5) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public i4, \ + public i5, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_5(i1, i2, i3, i4, i5) \ + private: + +#define Z7_CLASS_IMP_COM_6(c, i1, i2, i3, i4, i5, i6) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public i4, \ + public i5, \ + public i6, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_6(i1, i2, i3, i4, i5, i6) \ + private: + + +#define Z7_CLASS_IMP_COM_7(c, i1, i2, i3, i4, i5, i6, i7) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public i4, \ + public i5, \ + public i6, \ + public i7, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_7(i1, i2, i3, i4, i5, i6, i7) \ + private: + + +/* +#define Z7_CLASS_IMP_NOQIB_0(c) \ + Z7_class_final(c) : \ + public IUnknown, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_0 \ + private: +*/ + +#define Z7_CLASS_IMP_NOQIB_1(c, i1) \ + Z7_class_final(c) : \ + public i1, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_0 \ + Z7_IFACE_COM7_IMP(i1) \ + private: + +#define Z7_CLASS_IMP_NOQIB_2(c, i1, i2) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_1(i2) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + private: + +#define Z7_CLASS_IMP_NOQIB_3(c, i1, i2, i3) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_2(i2, i3) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + private: + +#define Z7_CLASS_IMP_NOQIB_4(c, i1, i2, i3, i4) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public i4, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_3(i2, i3, i4) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + Z7_IFACE_COM7_IMP(i4) \ + +/* +#define Z7_CLASS_IMP_NOQIB_5(c, i1, i2, i3, i4, i5) \ + Z7_class_final(c) : \ + public i1, \ + public i2, \ + public i3, \ + public i4, \ + public i5, \ + public CMyUnknownImp { \ + Z7_COM_UNKNOWN_IMP_4(i2, i3, i4, i5) \ + Z7_IFACE_COM7_IMP(i1) \ + Z7_IFACE_COM7_IMP(i2) \ + Z7_IFACE_COM7_IMP(i3) \ + Z7_IFACE_COM7_IMP(i4) \ + Z7_IFACE_COM7_IMP(i5) \ +*/ + + +#define Z7_CLASS_IMP_IInStream(c) \ + class c Z7_final : \ + public IInStream, \ + public CMyUnknownImp { \ + Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) \ + + +#define k_My_HRESULT_WritingWasCut 0x20000010 + +#endif diff --git a/CPP/Common/MyException.h b/CPP/Common/MyException.h index fa9847c8e..06fbdea15 100644 --- a/CPP/Common/MyException.h +++ b/CPP/Common/MyException.h @@ -1,14 +1,14 @@ -// Common/Exception.h - -#ifndef ZIP7_INC_COMMON_EXCEPTION_H -#define ZIP7_INC_COMMON_EXCEPTION_H - -#include "MyWindows.h" - -struct CSystemException -{ - HRESULT ErrorCode; - CSystemException(HRESULT errorCode): ErrorCode(errorCode) {} -}; - -#endif +// Common/Exception.h + +#ifndef ZIP7_INC_COMMON_EXCEPTION_H +#define ZIP7_INC_COMMON_EXCEPTION_H + +#include "MyWindows.h" + +struct CSystemException +{ + HRESULT ErrorCode; + CSystemException(HRESULT errorCode): ErrorCode(errorCode) {} +}; + +#endif diff --git a/CPP/Common/MyGuidDef.h b/CPP/Common/MyGuidDef.h index 32fc23cb8..3aa5266a5 100644 --- a/CPP/Common/MyGuidDef.h +++ b/CPP/Common/MyGuidDef.h @@ -1,63 +1,63 @@ -// Common/MyGuidDef.h - -// #pragma message "Common/MyGuidDef.h" - -#ifndef GUID_DEFINED -#define GUID_DEFINED - -// #pragma message "GUID_DEFINED" - -#include "MyTypes.h" - -typedef struct { - UInt32 Data1; - UInt16 Data2; - UInt16 Data3; - Byte Data4[8]; -} GUID; - -#ifdef __cplusplus -#define REFGUID const GUID & -#else -#define REFGUID const GUID * -#endif - -// typedef GUID IID; -typedef GUID CLSID; - -#define REFCLSID REFGUID -#define REFIID REFGUID - -#ifdef __cplusplus -inline int operator==(REFGUID g1, REFGUID g2) -{ - for (unsigned i = 0; i < sizeof(g1); i++) - if (((const Byte *)&g1)[i] != ((const Byte *)&g2)[i]) - return 0; - return 1; -} -inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); } -#endif - -#endif // GUID_DEFINED - -#ifndef EXTERN_C -#ifdef __cplusplus - #define EXTERN_C extern "C" -#else - #define EXTERN_C extern -#endif -#endif - -#ifdef DEFINE_GUID -#undef DEFINE_GUID -#endif - -#ifdef INITGUID - #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - EXTERN_C const GUID name; \ - EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -#else - #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - EXTERN_C const GUID name -#endif +// Common/MyGuidDef.h + +// #pragma message "Common/MyGuidDef.h" + +#ifndef GUID_DEFINED +#define GUID_DEFINED + +// #pragma message "GUID_DEFINED" + +#include "MyTypes.h" + +typedef struct { + UInt32 Data1; + UInt16 Data2; + UInt16 Data3; + Byte Data4[8]; +} GUID; + +#ifdef __cplusplus +#define REFGUID const GUID & +#else +#define REFGUID const GUID * +#endif + +// typedef GUID IID; +typedef GUID CLSID; + +#define REFCLSID REFGUID +#define REFIID REFGUID + +#ifdef __cplusplus +inline int operator==(REFGUID g1, REFGUID g2) +{ + for (unsigned i = 0; i < sizeof(g1); i++) + if (((const Byte *)&g1)[i] != ((const Byte *)&g2)[i]) + return 0; + return 1; +} +inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); } +#endif + +#endif // GUID_DEFINED + +#ifndef EXTERN_C +#ifdef __cplusplus + #define EXTERN_C extern "C" +#else + #define EXTERN_C extern +#endif +#endif + +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#endif + +#ifdef INITGUID + #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name; \ + EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else + #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name +#endif diff --git a/CPP/Common/MyInitGuid.h b/CPP/Common/MyInitGuid.h index 6cc50e950..3745c79a0 100644 --- a/CPP/Common/MyInitGuid.h +++ b/CPP/Common/MyInitGuid.h @@ -1,57 +1,57 @@ -// Common/MyInitGuid.h - -#ifndef ZIP7_INC_COMMON_MY_INITGUID_H -#define ZIP7_INC_COMMON_MY_INITGUID_H - -/* -This file must be included only to one C++ file in project before -declarations of COM interfaces with DEFINE_GUID macro. - -Each GUID must be initialized exactly once in project. -There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h): - - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name. - - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID. - -Also we need IID_IUnknown that is initialized in some file for linking: - MSVC: by default the linker uses some lib file that contains IID_IUnknown - MinGW: add -luuid switch for linker - WinCE: we define IID_IUnknown in this file - Other: we define IID_IUnknown in this file -*/ - -// #include "Common.h" -/* vc6 without sdk needs before , - but it doesn't work in new msvc. - So we include full "MyWindows.h" instead of */ -// #include -#include "MyWindows.h" - -#ifdef _WIN32 - -#ifdef __clang__ - // #pragma GCC diagnostic ignored "-Wmissing-variable-declarations" -#endif - -#ifdef UNDER_CE -#include -#endif - -// for vc6 without sdk we must define INITGUID here -#define INITGUID -#include - -#ifdef UNDER_CE -DEFINE_GUID(IID_IUnknown, -0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); -#endif - -#else // _WIN32 - -#define INITGUID -#include "MyGuidDef.h" -DEFINE_GUID(IID_IUnknown, -0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); - -#endif // _WIN32 - -#endif +// Common/MyInitGuid.h + +#ifndef ZIP7_INC_COMMON_MY_INITGUID_H +#define ZIP7_INC_COMMON_MY_INITGUID_H + +/* +This file must be included only to one C++ file in project before +declarations of COM interfaces with DEFINE_GUID macro. + +Each GUID must be initialized exactly once in project. +There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h): + - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name. + - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID. + +Also we need IID_IUnknown that is initialized in some file for linking: + MSVC: by default the linker uses some lib file that contains IID_IUnknown + MinGW: add -luuid switch for linker + WinCE: we define IID_IUnknown in this file + Other: we define IID_IUnknown in this file +*/ + +// #include "Common.h" +/* vc6 without sdk needs before , + but it doesn't work in new msvc. + So we include full "MyWindows.h" instead of */ +// #include +#include "MyWindows.h" + +#ifdef _WIN32 + +#ifdef __clang__ + // #pragma GCC diagnostic ignored "-Wmissing-variable-declarations" +#endif + +#ifdef UNDER_CE +#include +#endif + +// for vc6 without sdk we must define INITGUID here +#define INITGUID +#include + +#ifdef UNDER_CE +DEFINE_GUID(IID_IUnknown, +0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +#endif + +#else // _WIN32 + +#define INITGUID +#include "MyGuidDef.h" +DEFINE_GUID(IID_IUnknown, +0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + +#endif // _WIN32 + +#endif diff --git a/CPP/Common/MyLinux.h b/CPP/Common/MyLinux.h index 274defe2e..a8454d7f5 100644 --- a/CPP/Common/MyLinux.h +++ b/CPP/Common/MyLinux.h @@ -1,75 +1,75 @@ -// MyLinux.h - -#ifndef ZIP7_INC_COMMON_MY_LINUX_H -#define ZIP7_INC_COMMON_MY_LINUX_H - -// #include "../../C/7zTypes.h" - -#define MY_LIN_DT_UNKNOWN 0 -#define MY_LIN_DT_FIFO 1 -#define MY_LIN_DT_CHR 2 -#define MY_LIN_DT_DIR 4 -#define MY_LIN_DT_BLK 6 -#define MY_LIN_DT_REG 8 -#define MY_LIN_DT_LNK 10 -#define MY_LIN_DT_SOCK 12 -#define MY_LIN_DT_WHT 14 - -#define MY_LIN_S_IFMT 00170000 -#define MY_LIN_S_IFSOCK 0140000 -#define MY_LIN_S_IFLNK 0120000 -#define MY_LIN_S_IFREG 0100000 -#define MY_LIN_S_IFBLK 0060000 -#define MY_LIN_S_IFDIR 0040000 -#define MY_LIN_S_IFCHR 0020000 -#define MY_LIN_S_IFIFO 0010000 - -#define MY_LIN_S_ISLNK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFLNK) -#define MY_LIN_S_ISREG(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFREG) -#define MY_LIN_S_ISDIR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFDIR) -#define MY_LIN_S_ISCHR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFCHR) -#define MY_LIN_S_ISBLK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFBLK) -#define MY_LIN_S_ISFIFO(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFIFO) -#define MY_LIN_S_ISSOCK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFSOCK) - -#define MY_LIN_S_ISUID 0004000 -#define MY_LIN_S_ISGID 0002000 -#define MY_LIN_S_ISVTX 0001000 - -#define MY_LIN_S_IRWXU 00700 -#define MY_LIN_S_IRUSR 00400 -#define MY_LIN_S_IWUSR 00200 -#define MY_LIN_S_IXUSR 00100 - -#define MY_LIN_S_IRWXG 00070 -#define MY_LIN_S_IRGRP 00040 -#define MY_LIN_S_IWGRP 00020 -#define MY_LIN_S_IXGRP 00010 - -#define MY_LIN_S_IRWXO 00007 -#define MY_LIN_S_IROTH 00004 -#define MY_LIN_S_IWOTH 00002 -#define MY_LIN_S_IXOTH 00001 - -/* -// major/minor encoding for makedev(): MMMMMmmmmmmMMMmm: - -inline UInt32 MY_dev_major(UInt64 dev) -{ - return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff); -} - -inline UInt32 MY_dev_minor(UInt64 dev) -{ - return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~0xff); -} - -inline UInt64 MY_dev_makedev(UInt32 __major, UInt32 __minor) -{ - return (__minor & 0xff) | ((__major & 0xfff) << 8) - | ((UInt64) (__minor & ~0xff) << 12) - | ((UInt64) (__major & ~0xfff) << 32); -} -*/ - -#endif +// MyLinux.h + +#ifndef ZIP7_INC_COMMON_MY_LINUX_H +#define ZIP7_INC_COMMON_MY_LINUX_H + +// #include "../../C/7zTypes.h" + +#define MY_LIN_DT_UNKNOWN 0 +#define MY_LIN_DT_FIFO 1 +#define MY_LIN_DT_CHR 2 +#define MY_LIN_DT_DIR 4 +#define MY_LIN_DT_BLK 6 +#define MY_LIN_DT_REG 8 +#define MY_LIN_DT_LNK 10 +#define MY_LIN_DT_SOCK 12 +#define MY_LIN_DT_WHT 14 + +#define MY_LIN_S_IFMT 00170000 +#define MY_LIN_S_IFSOCK 0140000 +#define MY_LIN_S_IFLNK 0120000 +#define MY_LIN_S_IFREG 0100000 +#define MY_LIN_S_IFBLK 0060000 +#define MY_LIN_S_IFDIR 0040000 +#define MY_LIN_S_IFCHR 0020000 +#define MY_LIN_S_IFIFO 0010000 + +#define MY_LIN_S_ISLNK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFLNK) +#define MY_LIN_S_ISREG(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFREG) +#define MY_LIN_S_ISDIR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFDIR) +#define MY_LIN_S_ISCHR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFCHR) +#define MY_LIN_S_ISBLK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFBLK) +#define MY_LIN_S_ISFIFO(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFIFO) +#define MY_LIN_S_ISSOCK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFSOCK) + +#define MY_LIN_S_ISUID 0004000 +#define MY_LIN_S_ISGID 0002000 +#define MY_LIN_S_ISVTX 0001000 + +#define MY_LIN_S_IRWXU 00700 +#define MY_LIN_S_IRUSR 00400 +#define MY_LIN_S_IWUSR 00200 +#define MY_LIN_S_IXUSR 00100 + +#define MY_LIN_S_IRWXG 00070 +#define MY_LIN_S_IRGRP 00040 +#define MY_LIN_S_IWGRP 00020 +#define MY_LIN_S_IXGRP 00010 + +#define MY_LIN_S_IRWXO 00007 +#define MY_LIN_S_IROTH 00004 +#define MY_LIN_S_IWOTH 00002 +#define MY_LIN_S_IXOTH 00001 + +/* +// major/minor encoding for makedev(): MMMMMmmmmmmMMMmm: + +inline UInt32 MY_dev_major(UInt64 dev) +{ + return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff); +} + +inline UInt32 MY_dev_minor(UInt64 dev) +{ + return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~0xff); +} + +inline UInt64 MY_dev_makedev(UInt32 __major, UInt32 __minor) +{ + return (__minor & 0xff) | ((__major & 0xfff) << 8) + | ((UInt64) (__minor & ~0xff) << 12) + | ((UInt64) (__major & ~0xfff) << 32); +} +*/ + +#endif diff --git a/CPP/Common/MyMap.cpp b/CPP/Common/MyMap.cpp index f5d98bc47..d130aec70 100644 --- a/CPP/Common/MyMap.cpp +++ b/CPP/Common/MyMap.cpp @@ -1,140 +1,140 @@ -// MyMap.cpp - -#include "StdAfx.h" - -#include "MyMap.h" - -static const unsigned kNumBitsMax = sizeof(UInt32) * 8; - -static UInt32 GetSubBits(UInt32 value, unsigned startPos, unsigned numBits) throw() -{ - if (startPos == sizeof(value) * 8) - return 0; - value >>= startPos; - if (numBits == sizeof(value) * 8) - return value; - return value & (((UInt32)1 << numBits) - 1); -} - -static inline unsigned GetSubBit(UInt32 v, unsigned n) { return (unsigned)(v >> n) & 1; } - -bool CMap32::Find(UInt32 key, UInt32 &valueRes) const throw() -{ - valueRes = (UInt32)(Int32)-1; - if (Nodes.Size() == 0) - return false; - if (Nodes.Size() == 1) - { - const CNode &n = Nodes[0]; - if (n.Len == kNumBitsMax) - { - valueRes = n.Values[0]; - return (key == n.Key); - } - } - - unsigned cur = 0; - unsigned bitPos = kNumBitsMax; - for (;;) - { - const CNode &n = Nodes[cur]; - bitPos -= n.Len; - if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len)) - return false; - unsigned bit = GetSubBit(key, --bitPos); - if (n.IsLeaf[bit]) - { - valueRes = n.Values[bit]; - return (key == n.Keys[bit]); - } - cur = (unsigned)n.Keys[bit]; - } -} - -bool CMap32::Set(UInt32 key, UInt32 value) -{ - if (Nodes.Size() == 0) - { - CNode n; - n.Key = n.Keys[0] = n.Keys[1] = key; - n.Values[0] = n.Values[1] = value; - n.IsLeaf[0] = n.IsLeaf[1] = 1; - n.Len = kNumBitsMax; - Nodes.Add(n); - return false; - } - if (Nodes.Size() == 1) - { - CNode &n = Nodes[0]; - if (n.Len == kNumBitsMax) - { - if (key == n.Key) - { - n.Values[0] = n.Values[1] = value; - return true; - } - unsigned i = kNumBitsMax - 1; - for (; GetSubBit(key, i) == GetSubBit(n.Key, i); i--); - n.Len = (UInt16)(kNumBitsMax - (1 + i)); - const unsigned newBit = GetSubBit(key, i); - n.Values[newBit] = value; - n.Keys[newBit] = key; - return false; - } - } - - unsigned cur = 0; - unsigned bitPos = kNumBitsMax; - for (;;) - { - CNode &n = Nodes[cur]; - bitPos -= n.Len; - if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len)) - { - unsigned i = (unsigned)n.Len - 1; - for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--); - - CNode e2(n); - e2.Len = (UInt16)i; - - n.Len = (UInt16)(n.Len - (1 + i)); - unsigned newBit = GetSubBit(key, bitPos + i); - n.Values[newBit] = value; - n.IsLeaf[newBit] = 1; - n.IsLeaf[1 - newBit] = 0; - n.Keys[newBit] = key; - n.Keys[1 - newBit] = (UInt32)Nodes.Size(); - Nodes.Add(e2); - return false; - } - const unsigned bit = GetSubBit(key, --bitPos); - - if (n.IsLeaf[bit]) - { - if (key == n.Keys[bit]) - { - n.Values[bit] = value; - return true; - } - unsigned i = bitPos - 1; - for (; GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--); - - CNode e2; - - const unsigned newBit = GetSubBit(key, i); - e2.Values[newBit] = value; - e2.Values[1 - newBit] = n.Values[bit]; - e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1; - e2.Keys[newBit] = key; - e2.Keys[1 - newBit] = e2.Key = n.Keys[bit]; - e2.Len = (UInt16)(bitPos - (1 + i)); - - n.IsLeaf[bit] = 0; - n.Keys[bit] = (UInt32)Nodes.Size(); - - Nodes.Add(e2); - return false; - } - cur = (unsigned)n.Keys[bit]; - } -} +// MyMap.cpp + +#include "StdAfx.h" + +#include "MyMap.h" + +static const unsigned kNumBitsMax = sizeof(UInt32) * 8; + +static UInt32 GetSubBits(UInt32 value, unsigned startPos, unsigned numBits) throw() +{ + if (startPos == sizeof(value) * 8) + return 0; + value >>= startPos; + if (numBits == sizeof(value) * 8) + return value; + return value & (((UInt32)1 << numBits) - 1); +} + +static inline unsigned GetSubBit(UInt32 v, unsigned n) { return (unsigned)(v >> n) & 1; } + +bool CMap32::Find(UInt32 key, UInt32 &valueRes) const throw() +{ + valueRes = (UInt32)(Int32)-1; + if (Nodes.Size() == 0) + return false; + if (Nodes.Size() == 1) + { + const CNode &n = Nodes[0]; + if (n.Len == kNumBitsMax) + { + valueRes = n.Values[0]; + return (key == n.Key); + } + } + + unsigned cur = 0; + unsigned bitPos = kNumBitsMax; + for (;;) + { + const CNode &n = Nodes[cur]; + bitPos -= n.Len; + if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len)) + return false; + unsigned bit = GetSubBit(key, --bitPos); + if (n.IsLeaf[bit]) + { + valueRes = n.Values[bit]; + return (key == n.Keys[bit]); + } + cur = (unsigned)n.Keys[bit]; + } +} + +bool CMap32::Set(UInt32 key, UInt32 value) +{ + if (Nodes.Size() == 0) + { + CNode n; + n.Key = n.Keys[0] = n.Keys[1] = key; + n.Values[0] = n.Values[1] = value; + n.IsLeaf[0] = n.IsLeaf[1] = 1; + n.Len = kNumBitsMax; + Nodes.Add(n); + return false; + } + if (Nodes.Size() == 1) + { + CNode &n = Nodes[0]; + if (n.Len == kNumBitsMax) + { + if (key == n.Key) + { + n.Values[0] = n.Values[1] = value; + return true; + } + unsigned i = kNumBitsMax - 1; + for (; GetSubBit(key, i) == GetSubBit(n.Key, i); i--); + n.Len = (UInt16)(kNumBitsMax - (1 + i)); + const unsigned newBit = GetSubBit(key, i); + n.Values[newBit] = value; + n.Keys[newBit] = key; + return false; + } + } + + unsigned cur = 0; + unsigned bitPos = kNumBitsMax; + for (;;) + { + CNode &n = Nodes[cur]; + bitPos -= n.Len; + if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len)) + { + unsigned i = (unsigned)n.Len - 1; + for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--); + + CNode e2(n); + e2.Len = (UInt16)i; + + n.Len = (UInt16)(n.Len - (1 + i)); + unsigned newBit = GetSubBit(key, bitPos + i); + n.Values[newBit] = value; + n.IsLeaf[newBit] = 1; + n.IsLeaf[1 - newBit] = 0; + n.Keys[newBit] = key; + n.Keys[1 - newBit] = (UInt32)Nodes.Size(); + Nodes.Add(e2); + return false; + } + const unsigned bit = GetSubBit(key, --bitPos); + + if (n.IsLeaf[bit]) + { + if (key == n.Keys[bit]) + { + n.Values[bit] = value; + return true; + } + unsigned i = bitPos - 1; + for (; GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--); + + CNode e2; + + const unsigned newBit = GetSubBit(key, i); + e2.Values[newBit] = value; + e2.Values[1 - newBit] = n.Values[bit]; + e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1; + e2.Keys[newBit] = key; + e2.Keys[1 - newBit] = e2.Key = n.Keys[bit]; + e2.Len = (UInt16)(bitPos - (1 + i)); + + n.IsLeaf[bit] = 0; + n.Keys[bit] = (UInt32)Nodes.Size(); + + Nodes.Add(e2); + return false; + } + cur = (unsigned)n.Keys[bit]; + } +} diff --git a/CPP/Common/MyMap.h b/CPP/Common/MyMap.h index cab941518..9ca556683 100644 --- a/CPP/Common/MyMap.h +++ b/CPP/Common/MyMap.h @@ -1,28 +1,28 @@ -// MyMap.h - -#ifndef ZIP7_INC_COMMON_MY_MAP_H -#define ZIP7_INC_COMMON_MY_MAP_H - -#include "MyTypes.h" -#include "MyVector.h" - -class CMap32 -{ - struct CNode - { - UInt32 Key; - UInt32 Keys[2]; - UInt32 Values[2]; - UInt16 Len; - Byte IsLeaf[2]; - }; - CRecordVector Nodes; - -public: - - void Clear() { Nodes.Clear(); } - bool Find(UInt32 key, UInt32 &valueRes) const throw(); - bool Set(UInt32 key, UInt32 value); // returns true, if there is such key already -}; - -#endif +// MyMap.h + +#ifndef ZIP7_INC_COMMON_MY_MAP_H +#define ZIP7_INC_COMMON_MY_MAP_H + +#include "MyTypes.h" +#include "MyVector.h" + +class CMap32 +{ + struct CNode + { + UInt32 Key; + UInt32 Keys[2]; + UInt32 Values[2]; + UInt16 Len; + Byte IsLeaf[2]; + }; + CRecordVector Nodes; + +public: + + void Clear() { Nodes.Clear(); } + bool Find(UInt32 key, UInt32 &valueRes) const throw(); + bool Set(UInt32 key, UInt32 value); // returns true, if there is such key already +}; + +#endif diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp index e10472abd..b5f7e52f6 100644 --- a/CPP/Common/MyString.cpp +++ b/CPP/Common/MyString.cpp @@ -1,1871 +1,1871 @@ -// Common/MyString.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include -#else -#include -#endif - -#include "IntToString.h" - -#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING) -#include "StringConvert.h" -#endif - -#include "MyString.h" - -#define MY_STRING_NEW(_T_, _size_) new _T_[_size_] -// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_))) - -/* -inline const char* MyStringGetNextCharPointer(const char *p) throw() -{ - #if defined(_WIN32) && !defined(UNDER_CE) - return CharNextA(p); - #else - return p + 1; - #endif -} -*/ - -#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, (_size_)) -#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, (_size_)) - - -int FindCharPosInString(const char *s, char c) throw() -{ - for (const char *p = s;; p++) - { - if (*p == c) - return (int)(p - s); - if (*p == 0) - return -1; - // MyStringGetNextCharPointer(p); - } -} - -int FindCharPosInString(const wchar_t *s, wchar_t c) throw() -{ - for (const wchar_t *p = s;; p++) - { - if (*p == c) - return (int)(p - s); - if (*p == 0) - return -1; - } -} - -/* -void MyStringUpper_Ascii(char *s) throw() -{ - for (;;) - { - const char c = *s; - if (c == 0) - return; - *s++ = MyCharUpper_Ascii(c); - } -} - -void MyStringUpper_Ascii(wchar_t *s) throw() -{ - for (;;) - { - const wchar_t c = *s; - if (c == 0) - return; - *s++ = MyCharUpper_Ascii(c); - } -} -*/ - -void MyStringLower_Ascii(char *s) throw() -{ - for (;;) - { - const char c = *s; - if (c == 0) - return; - *s++ = MyCharLower_Ascii(c); - } -} - -void MyStringLower_Ascii(wchar_t *s) throw() -{ - for (;;) - { - const wchar_t c = *s; - if (c == 0) - return; - *s++ = MyCharLower_Ascii(c); - } -} - -#ifdef _WIN32 - -#ifdef _UNICODE - -// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } -// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } -// for WinCE - FString - char -// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; } - -#else - -// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); } -// char * MyStringUpper(char *s) { return CharUpperA(s); } -// char * MyStringLower(char *s) { return CharLowerA(s); } - -wchar_t MyCharUpper_WIN(wchar_t c) throw() -{ - wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); - if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - return (wchar_t)(unsigned)(UINT_PTR)res; - const int kBufSize = 4; - char s[kBufSize + 1]; - int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); - if (numChars == 0 || numChars > kBufSize) - return c; - s[numChars] = 0; - ::CharUpperA(s); - ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); - return c; -} - -/* -wchar_t MyCharLower_WIN(wchar_t c) -{ - wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); - if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - return (wchar_t)(unsigned)(UINT_PTR)res; - const int kBufSize = 4; - char s[kBufSize + 1]; - int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); - if (numChars == 0 || numChars > kBufSize) - return c; - s[numChars] = 0; - ::CharLowerA(s); - ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); - return c; -} -*/ - -/* -wchar_t * MyStringUpper(wchar_t *s) -{ - if (s == 0) - return 0; - wchar_t *res = CharUpperW(s); - if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - return res; - AString a = UnicodeStringToMultiByte(s); - a.MakeUpper(); - MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); - return s; -} -*/ - -/* -wchar_t * MyStringLower(wchar_t *s) -{ - if (s == 0) - return 0; - wchar_t *res = CharLowerW(s); - if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) - return res; - AString a = UnicodeStringToMultiByte(s); - a.MakeLower(); - MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); - return s; -} -*/ - -#endif - -#endif - -bool IsString1PrefixedByString2(const char *s1, const char *s2) throw() -{ - for (;;) - { - const char c2 = *s2++; if (c2 == 0) return true; - const char c1 = *s1++; if (c1 != c2) return false; - } -} - -bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - const wchar_t c1 = *s1++; - const wchar_t c2 = *s2++; - if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; - if (c1 == 0) return true; - } -} - -// ---------- ASCII ---------- - -bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() -{ - const char *s1 = _chars; - for (;;) - { - const char c2 = *s++; - if (c2 == 0) - return true; - const char c1 = *s1++; - if (MyCharLower_Ascii(c1) != - MyCharLower_Ascii(c2)) - return false; - } -} - -bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() -{ - const wchar_t *s1 = _chars; - for (;;) - { - const char c2 = *s++; - if (c2 == 0) - return true; - const wchar_t c1 = *s1++; - if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) - return false; - } -} - -bool StringsAreEqual_Ascii(const char *u, const char *a) throw() -{ - for (;;) - { - const char c = *a; - if (c != *u) - return false; - if (c == 0) - return true; - a++; - u++; - } -} - -bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw() -{ - for (;;) - { - const unsigned char c = (unsigned char)*a; - if (c != *u) - return false; - if (c == 0) - return true; - a++; - u++; - } -} - -bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw() -{ - for (;;) - { - const char c1 = *s1++; - const char c2 = *s2++; - if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) - return false; - if (c1 == 0) - return true; - } -} - -bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - const wchar_t c1 = *s1++; - const wchar_t c2 = *s2++; - if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) - return false; - if (c1 == 0) - return true; - } -} - -bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw() -{ - for (;;) - { - const wchar_t c1 = *s1++; - const char c2 = *s2++; - if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) - return false; - if (c1 == 0) - return true; - } -} - -bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - const wchar_t c2 = *s2++; if (c2 == 0) return true; - const wchar_t c1 = *s1++; if (c1 != c2) return false; - } -} - -bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw() -{ - for (;;) - { - const unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true; - const wchar_t c1 = *s1++; if (c1 != c2) return false; - } -} - -bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw() -{ - for (;;) - { - const char c2 = *s2++; if (c2 == 0) return true; - const char c1 = *s1++; - if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) - return false; - } -} - -bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2) throw() -{ - for (;;) - { - const char c2 = *s2++; if (c2 == 0) return true; - const wchar_t c1 = *s1++; - if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) - return false; - } -} - -bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - const wchar_t c2 = *s2++; if (c2 == 0) return true; - const wchar_t c1 = *s1++; - if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) - return false; - } -} - -// NTFS order: uses upper case -int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - const wchar_t c1 = *s1++; - const wchar_t c2 = *s2++; - if (c1 != c2) - { - const wchar_t u1 = MyCharUpper(c1); - const wchar_t u2 = MyCharUpper(c2); - if (u1 < u2) return -1; - if (u1 > u2) return 1; - } - if (c1 == 0) return 0; - } -} - -/* -int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) -{ - for (; num != 0; num--) - { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; - if (c1 != c2) - { - wchar_t u1 = MyCharUpper(c1); - wchar_t u2 = MyCharUpper(c2); - if (u1 < u2) return -1; - if (u1 > u2) return 1; - } - if (c1 == 0) return 0; - } - return 0; -} -*/ - -// ---------- AString ---------- - -void AString::InsertSpace(unsigned &index, unsigned size) -{ - Grow(size); - MoveItems(index + size, index); -} - -#define k_Alloc_Len_Limit (0x40000000 - 2) -// #define k_Alloc_Len_Limit (((unsigned)1 << (sizeof(unsigned) * 8 - 2)) - 2) - -void AString::ReAlloc(unsigned newLimit) -{ - // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, (size_t)_len + 1); - char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1); - memcpy(newBuf, _chars, (size_t)_len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = newLimit; -} - -#define THROW_STRING_ALLOC_EXCEPTION { throw 20130220; } - -#define CHECK_STRING_ALLOC_LEN(len) \ - { if ((len) > k_Alloc_Len_Limit) THROW_STRING_ALLOC_EXCEPTION } - -void AString::ReAlloc2(unsigned newLimit) -{ - CHECK_STRING_ALLOC_LEN(newLimit) - // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, 0); - char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1); - newBuf[0] = 0; - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = newLimit; - _len = 0; -} - -void AString::SetStartLen(unsigned len) -{ - _chars = NULL; - _chars = MY_STRING_NEW_char((size_t)len + 1); - _len = len; - _limit = len; -} - -Z7_NO_INLINE -void AString::Grow_1() -{ - unsigned next = _len; - next += next / 2; - next += 16; - next &= ~(unsigned)15; - next--; - if (next < _len || next > k_Alloc_Len_Limit) - next = k_Alloc_Len_Limit; - if (next <= _len) - THROW_STRING_ALLOC_EXCEPTION - ReAlloc(next); - // Grow(1); -} - -void AString::Grow(unsigned n) -{ - const unsigned freeSize = _limit - _len; - if (n <= freeSize) - return; - unsigned next = _len + n; - next += next / 2; - next += 16; - next &= ~(unsigned)15; - next--; - if (next < _len || next > k_Alloc_Len_Limit) - next = k_Alloc_Len_Limit; - if (next <= _len || next - _len < n) - THROW_STRING_ALLOC_EXCEPTION - ReAlloc(next); -} - -AString::AString(unsigned num, const char *s) -{ - unsigned len = MyStringLen(s); - if (num > len) - num = len; - SetStartLen(num); - memcpy(_chars, s, num); - _chars[num] = 0; -} - -AString::AString(unsigned num, const AString &s) -{ - if (num > s._len) - num = s._len; - SetStartLen(num); - memcpy(_chars, s._chars, num); - _chars[num] = 0; -} - -AString::AString(const AString &s, char c) -{ - SetStartLen(s.Len() + 1); - char *chars = _chars; - unsigned len = s.Len(); - memcpy(chars, s, len); - chars[len] = c; - chars[(size_t)len + 1] = 0; -} - -AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2) -{ - SetStartLen(num1 + num2); - char *chars = _chars; - memcpy(chars, s1, num1); - memcpy(chars + num1, s2, num2 + 1); -} - -AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); } -AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); } -AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); } - -static const unsigned kStartStringCapacity = 4; - -AString::AString() -{ - _chars = NULL; - _chars = MY_STRING_NEW_char(kStartStringCapacity); - _len = 0; - _limit = kStartStringCapacity - 1; - _chars[0] = 0; -} - -AString::AString(char c) -{ - SetStartLen(1); - char *chars = _chars; - chars[0] = c; - chars[1] = 0; -} - -AString::AString(const char *s) -{ - SetStartLen(MyStringLen(s)); - MyStringCopy(_chars, s); -} - -AString::AString(const AString &s) -{ - SetStartLen(s._len); - MyStringCopy(_chars, s._chars); -} - -AString &AString::operator=(char c) -{ - if (1 > _limit) - { - char *newBuf = MY_STRING_NEW_char(1 + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = 1; - } - _len = 1; - char *chars = _chars; - chars[0] = c; - chars[1] = 0; - return *this; -} - -AString &AString::operator=(const char *s) -{ - unsigned len = MyStringLen(s); - if (len > _limit) - { - char *newBuf = MY_STRING_NEW_char((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - MyStringCopy(_chars, s); - return *this; -} - -AString &AString::operator=(const AString &s) -{ - if (&s == this) - return *this; - unsigned len = s._len; - if (len > _limit) - { - char *newBuf = MY_STRING_NEW_char((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - MyStringCopy(_chars, s._chars); - return *this; -} - -void AString::SetFromWStr_if_Ascii(const wchar_t *s) -{ - unsigned len = 0; - { - for (;; len++) - { - wchar_t c = s[len]; - if (c == 0) - break; - if (c >= 0x80) - return; - } - } - if (len > _limit) - { - char *newBuf = MY_STRING_NEW_char((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - char *dest = _chars; - unsigned i; - for (i = 0; i < len; i++) - dest[i] = (char)s[i]; - dest[i] = 0; -} - -/* -void AString::SetFromBstr_if_Ascii(BSTR s) -{ - unsigned len = ::SysStringLen(s); - { - for (unsigned i = 0; i < len; i++) - if (s[i] <= 0 || s[i] >= 0x80) - return; - } - if (len > _limit) - { - char *newBuf = MY_STRING_NEW_char((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - char *dest = _chars; - unsigned i; - for (i = 0; i < len; i++) - dest[i] = (char)s[i]; - dest[i] = 0; -} -*/ - -void AString::Add_Char(char c) { operator+=(c); } -void AString::Add_Space() { operator+=(' '); } -void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } -void AString::Add_LF() { operator+=('\n'); } -void AString::Add_Slash() { operator+=('/'); } -void AString::Add_Dot() { operator+=('.'); } -void AString::Add_Minus() { operator+=('-'); } -void AString::Add_Colon() { operator+=(':'); } - -AString &AString::operator+=(const char *s) -{ - unsigned len = MyStringLen(s); - Grow(len); - MyStringCopy(_chars + _len, s); - _len += len; - return *this; -} - -void AString::Add_OptSpaced(const char *s) -{ - Add_Space_if_NotEmpty(); - (*this) += s; -} - -AString &AString::operator+=(const AString &s) -{ - Grow(s._len); - MyStringCopy(_chars + _len, s._chars); - _len += s._len; - return *this; -} - -void AString::Add_UInt32(UInt32 v) -{ - Grow(10); - _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars); -} - -void UString::Add_UInt64(UInt64 v) -{ - Grow(20); - _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); -} - -void AString::AddFrom(const char *s, unsigned len) // no check -{ - if (len != 0) - { - Grow(len); - memcpy(_chars + _len, s, len); - len += _len; - _chars[len] = 0; - _len = len; - } -} - -void AString::SetFrom(const char *s, unsigned len) // no check -{ - if (len > _limit) - { - CHECK_STRING_ALLOC_LEN(len) - char *newBuf = MY_STRING_NEW_char((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - if (len != 0) - memcpy(_chars, s, len); - _chars[len] = 0; - _len = len; -} - -void AString::SetFrom_Chars_SizeT(const char *s, size_t len) -{ - CHECK_STRING_ALLOC_LEN(len) - SetFrom(s, (unsigned)len); -} - -void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check -{ - unsigned i; - for (i = 0; i < len; i++) - if (s[i] == 0) - break; - SetFrom(s, i); -} - -int AString::Find(const char *s, unsigned startIndex) const throw() -{ - const char *fs = strstr(_chars + startIndex, s); - if (!fs) - return -1; - return (int)(fs - _chars); - - /* - if (s[0] == 0) - return startIndex; - unsigned len = MyStringLen(s); - const char *p = _chars + startIndex; - for (;; p++) - { - const char c = *p; - if (c != s[0]) - { - if (c == 0) - return -1; - continue; - } - unsigned i; - for (i = 1; i < len; i++) - if (p[i] != s[i]) - break; - if (i == len) - return (int)(p - _chars); - } - */ -} - -int AString::ReverseFind(char c) const throw() -{ - if (_len == 0) - return -1; - const char *p = _chars + _len - 1; - for (;;) - { - if (*p == c) - return (int)(p - _chars); - if (p == _chars) - return -1; - p--; // p = GetPrevCharPointer(_chars, p); - } -} - -int AString::ReverseFind_PathSepar() const throw() -{ - if (_len == 0) - return -1; - const char *p = _chars + _len - 1; - for (;;) - { - const char c = *p; - if (IS_PATH_SEPAR(c)) - return (int)(p - _chars); - if (p == _chars) - return -1; - p--; - } -} - -void AString::TrimLeft() throw() -{ - const char *p = _chars; - for (;; p++) - { - char c = *p; - if (c != ' ' && c != '\n' && c != '\t') - break; - } - unsigned pos = (unsigned)(p - _chars); - if (pos != 0) - { - MoveItems(0, pos); - _len -= pos; - } -} - -void AString::TrimRight() throw() -{ - const char *p = _chars; - unsigned i; - for (i = _len; i != 0; i--) - { - char c = p[(size_t)i - 1]; - if (c != ' ' && c != '\n' && c != '\t') - break; - } - if (i != _len) - { - _chars[i] = 0; - _len = i; - } -} - -void AString::InsertAtFront(char c) -{ - if (_limit == _len) - Grow_1(); - MoveItems(1, 0); - _chars[0] = c; - _len++; -} - -/* -void AString::Insert(unsigned index, char c) -{ - InsertSpace(index, 1); - _chars[index] = c; - _len++; -} -*/ - -void AString::Insert(unsigned index, const char *s) -{ - unsigned num = MyStringLen(s); - if (num != 0) - { - InsertSpace(index, num); - memcpy(_chars + index, s, num); - _len += num; - } -} - -void AString::Insert(unsigned index, const AString &s) -{ - unsigned num = s.Len(); - if (num != 0) - { - InsertSpace(index, num); - memcpy(_chars + index, s, num); - _len += num; - } -} - -void AString::RemoveChar(char ch) throw() -{ - char *src = _chars; - - for (;;) - { - char c = *src++; - if (c == 0) - return; - if (c == ch) - break; - } - - char *dest = src - 1; - - for (;;) - { - char c = *src++; - if (c == 0) - break; - if (c != ch) - *dest++ = c; - } - - *dest = 0; - _len = (unsigned)(dest - _chars); -} - -// !!!!!!!!!!!!!!! test it if newChar = '\0' -void AString::Replace(char oldChar, char newChar) throw() -{ - if (oldChar == newChar) - return; // 0; - // unsigned number = 0; - int pos = 0; - char *chars = _chars; - while ((unsigned)pos < _len) - { - pos = Find(oldChar, (unsigned)pos); - if (pos < 0) - break; - chars[(unsigned)pos] = newChar; - pos++; - // number++; - } - return; // number; -} - -void AString::Replace(const AString &oldString, const AString &newString) -{ - if (oldString.IsEmpty()) - return; // 0; - if (oldString == newString) - return; // 0; - const unsigned oldLen = oldString.Len(); - const unsigned newLen = newString.Len(); - // unsigned number = 0; - int pos = 0; - while ((unsigned)pos < _len) - { - pos = Find(oldString, (unsigned)pos); - if (pos < 0) - break; - Delete((unsigned)pos, oldLen); - Insert((unsigned)pos, newString); - pos += newLen; - // number++; - } - // return number; -} - -void AString::Delete(unsigned index) throw() -{ - MoveItems(index, index + 1); - _len--; -} - -void AString::Delete(unsigned index, unsigned count) throw() -{ - if (index + count > _len) - count = _len - index; - if (count > 0) - { - MoveItems(index, index + count); - _len -= count; - } -} - -void AString::DeleteFrontal(unsigned num) throw() -{ - if (num != 0) - { - MoveItems(0, num); - _len -= num; - } -} - -/* -AString operator+(const AString &s1, const AString &s2) -{ - AString result(s1); - result += s2; - return result; -} - -AString operator+(const AString &s, const char *chars) -{ - AString result(s); - result += chars; - return result; -} - -AString operator+(const char *chars, const AString &s) -{ - AString result(chars); - result += s; - return result; -} - -AString operator+(const AString &s, char c) -{ - AString result(s); - result += c; - return result; -} -*/ - -/* -AString operator+(char c, const AString &s) -{ - AString result(c); - result += s; - return result; -} -*/ - - - - -// ---------- UString ---------- - -void UString::InsertSpace(unsigned index, unsigned size) -{ - Grow(size); - MoveItems(index + size, index); -} - -void UString::ReAlloc(unsigned newLimit) -{ - // MY_STRING_REALLOC(_chars, wchar_t, (size_t)newLimit + 1, (size_t)_len + 1); - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); - wmemcpy(newBuf, _chars, _len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = newLimit; -} - -void UString::ReAlloc2(unsigned newLimit) -{ - CHECK_STRING_ALLOC_LEN(newLimit) - // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); - newBuf[0] = 0; - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = newLimit; - _len = 0; -} - -void UString::SetStartLen(unsigned len) -{ - _chars = NULL; - _chars = MY_STRING_NEW_wchar_t((size_t)len + 1); - _len = len; - _limit = len; -} - -Z7_NO_INLINE -void UString::Grow_1() -{ - unsigned next = _len; - next += next / 2; - next += 16; - next &= ~(unsigned)15; - next--; - if (next < _len || next > k_Alloc_Len_Limit) - next = k_Alloc_Len_Limit; - if (next <= _len) - THROW_STRING_ALLOC_EXCEPTION - ReAlloc(next); -} - -void UString::Grow(unsigned n) -{ - const unsigned freeSize = _limit - _len; - if (n <= freeSize) - return; - unsigned next = _len + n; - next += next / 2; - next += 16; - next &= ~(unsigned)15; - next--; - if (next < _len || next > k_Alloc_Len_Limit) - next = k_Alloc_Len_Limit; - if (next <= _len || next - _len < n) - THROW_STRING_ALLOC_EXCEPTION - ReAlloc(next - 1); -} - - -UString::UString(unsigned num, const wchar_t *s) -{ - unsigned len = MyStringLen(s); - if (num > len) - num = len; - SetStartLen(num); - wmemcpy(_chars, s, num); - _chars[num] = 0; -} - - -UString::UString(unsigned num, const UString &s) -{ - if (num > s._len) - num = s._len; - SetStartLen(num); - wmemcpy(_chars, s._chars, num); - _chars[num] = 0; -} - -UString::UString(const UString &s, wchar_t c) -{ - SetStartLen(s.Len() + 1); - wchar_t *chars = _chars; - unsigned len = s.Len(); - wmemcpy(chars, s, len); - chars[len] = c; - chars[(size_t)len + 1] = 0; -} - -UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2) -{ - SetStartLen(num1 + num2); - wchar_t *chars = _chars; - wmemcpy(chars, s1, num1); - wmemcpy(chars + num1, s2, num2 + 1); -} - -UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); } -UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); } -UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); } - -UString::UString() -{ - _chars = NULL; - _chars = MY_STRING_NEW_wchar_t(kStartStringCapacity); - _len = 0; - _limit = kStartStringCapacity - 1; - _chars[0] = 0; -} - -UString::UString(wchar_t c) -{ - SetStartLen(1); - wchar_t *chars = _chars; - chars[0] = c; - chars[1] = 0; -} - -UString::UString(char c) -{ - SetStartLen(1); - wchar_t *chars = _chars; - chars[0] = (unsigned char)c; - chars[1] = 0; -} - -UString::UString(const wchar_t *s) -{ - const unsigned len = MyStringLen(s); - SetStartLen(len); - wmemcpy(_chars, s, len + 1); -} - -UString::UString(const char *s) -{ - const unsigned len = MyStringLen(s); - SetStartLen(len); - wchar_t *chars = _chars; - for (unsigned i = 0; i < len; i++) - chars[i] = (unsigned char)s[i]; - chars[len] = 0; -} - -UString::UString(const AString &s) -{ - const unsigned len = s.Len(); - SetStartLen(len); - wchar_t *chars = _chars; - const char *s2 = s.Ptr(); - for (unsigned i = 0; i < len; i++) - chars[i] = (unsigned char)s2[i]; - chars[len] = 0; -} - -UString::UString(const UString &s) -{ - SetStartLen(s._len); - wmemcpy(_chars, s._chars, s._len + 1); -} - -UString &UString::operator=(wchar_t c) -{ - if (1 > _limit) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = 1; - } - _len = 1; - wchar_t *chars = _chars; - chars[0] = c; - chars[1] = 0; - return *this; -} - -UString &UString::operator=(const wchar_t *s) -{ - unsigned len = MyStringLen(s); - if (len > _limit) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - wmemcpy(_chars, s, len + 1); - return *this; -} - -UString &UString::operator=(const UString &s) -{ - if (&s == this) - return *this; - unsigned len = s._len; - if (len > _limit) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - wmemcpy(_chars, s._chars, len + 1); - return *this; -} - -void UString::SetFrom(const wchar_t *s, unsigned len) // no check -{ - if (len > _limit) - { - CHECK_STRING_ALLOC_LEN(len) - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - if (len != 0) - wmemcpy(_chars, s, len); - _chars[len] = 0; - _len = len; -} - -void UString::SetFromBstr(LPCOLESTR s) -{ - unsigned len = ::SysStringLen((BSTR)(void *)(s)); - - /* - #if WCHAR_MAX > 0xffff - size_t num_wchars = 0; - for (size_t i = 0; i < len;) - { - wchar_t c = s[i++]; - if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) - { - wchar_t c2 = s[i]; - if (c2 >= 0xdc00 && c2 < 0xe000) - { - c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); - i++; - } - } - num_wchars++; - } - len = num_wchars; - #endif - */ - - if (len > _limit) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - _len = len; - - /* - #if WCHAR_MAX > 0xffff - - wchar_t *chars = _chars; - for (size_t i = 0; i <= len; i++) - { - wchar_t c = *s++; - if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) - { - wchar_t c2 = *s; - if (c2 >= 0xdc00 && c2 < 0xe000) - { - s++; - c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); - } - } - chars[i] = c; - } - - #else - */ - - // if (s) - wmemcpy(_chars, s, len + 1); - - // #endif -} - -UString &UString::operator=(const char *s) -{ - unsigned len = MyStringLen(s); - if (len > _limit) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - MY_STRING_DELETE(_chars) - _chars = newBuf; - _limit = len; - } - wchar_t *chars = _chars; - for (unsigned i = 0; i < len; i++) - chars[i] = (unsigned char)s[i]; - chars[len] = 0; - _len = len; - return *this; -} - -void UString::Add_Char(char c) { operator+=((wchar_t)(unsigned char)c); } -// void UString::Add_WChar(wchar_t c) { operator+=(c); } -void UString::Add_Dot() { operator+=(L'.'); } -void UString::Add_Space() { operator+=(L' '); } -void UString::Add_Minus() { operator+=(L'-'); } -void UString::Add_Colon() { operator+=(L':'); } -void UString::Add_LF() { operator+=(L'\n'); } -void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } - -UString &UString::operator+=(const wchar_t *s) -{ - unsigned len = MyStringLen(s); - Grow(len); - wmemcpy(_chars + _len, s, len + 1); - _len += len; - return *this; -} - -UString &UString::operator+=(const UString &s) -{ - Grow(s._len); - wmemcpy(_chars + _len, s._chars, s._len + 1); - _len += s._len; - return *this; -} - -UString &UString::operator+=(const char *s) -{ - unsigned len = MyStringLen(s); - Grow(len); - wchar_t *chars = _chars + _len; - for (unsigned i = 0; i < len; i++) - chars[i] = (unsigned char)s[i]; - chars[len] = 0; - _len += len; - return *this; -} - - -void UString::Add_UInt32(UInt32 v) -{ - Grow(10); - _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars); -} - -void AString::Add_UInt64(UInt64 v) -{ - Grow(20); - _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); -} - - -int UString::Find(const wchar_t *s, unsigned startIndex) const throw() -{ - const wchar_t *fs = wcsstr(_chars + startIndex, s); - if (!fs) - return -1; - return (int)(fs - _chars); - - /* - if (s[0] == 0) - return startIndex; - unsigned len = MyStringLen(s); - const wchar_t *p = _chars + startIndex; - for (;; p++) - { - const wchar_t c = *p; - if (c != s[0]) - { - if (c == 0) - return -1; - continue; - } - unsigned i; - for (i = 1; i < len; i++) - if (p[i] != s[i]) - break; - if (i == len) - return (int)(p - _chars); - } - */ -} - -int UString::ReverseFind(wchar_t c) const throw() -{ - if (_len == 0) - return -1; - const wchar_t *p = _chars + _len; - do - { - if (*(--p) == c) - return (int)(p - _chars); - } - while (p != _chars); - return -1; -} - -int UString::ReverseFind_PathSepar() const throw() -{ - const wchar_t *p = _chars + _len; - while (p != _chars) - { - const wchar_t c = *(--p); - if (IS_PATH_SEPAR(c)) - return (int)(p - _chars); - } - return -1; -} - -void UString::TrimLeft() throw() -{ - const wchar_t *p = _chars; - for (;; p++) - { - wchar_t c = *p; - if (c != ' ' && c != '\n' && c != '\t') - break; - } - unsigned pos = (unsigned)(p - _chars); - if (pos != 0) - { - MoveItems(0, pos); - _len -= pos; - } -} - -void UString::TrimRight() throw() -{ - const wchar_t *p = _chars; - unsigned i; - for (i = _len; i != 0; i--) - { - wchar_t c = p[(size_t)i - 1]; - if (c != ' ' && c != '\n' && c != '\t') - break; - } - if (i != _len) - { - _chars[i] = 0; - _len = i; - } -} - -void UString::InsertAtFront(wchar_t c) -{ - if (_limit == _len) - Grow_1(); - MoveItems(1, 0); - _chars[0] = c; - _len++; -} - -/* -void UString::Insert_wchar_t(unsigned index, wchar_t c) -{ - InsertSpace(index, 1); - _chars[index] = c; - _len++; -} -*/ - -void UString::Insert(unsigned index, const wchar_t *s) -{ - unsigned num = MyStringLen(s); - if (num != 0) - { - InsertSpace(index, num); - wmemcpy(_chars + index, s, num); - _len += num; - } -} - -void UString::Insert(unsigned index, const UString &s) -{ - unsigned num = s.Len(); - if (num != 0) - { - InsertSpace(index, num); - wmemcpy(_chars + index, s, num); - _len += num; - } -} - -void UString::RemoveChar(wchar_t ch) throw() -{ - wchar_t *src = _chars; - - for (;;) - { - wchar_t c = *src++; - if (c == 0) - return; - if (c == ch) - break; - } - - wchar_t *dest = src - 1; - - for (;;) - { - wchar_t c = *src++; - if (c == 0) - break; - if (c != ch) - *dest++ = c; - } - - *dest = 0; - _len = (unsigned)(dest - _chars); -} - -// !!!!!!!!!!!!!!! test it if newChar = '\0' -void UString::Replace(wchar_t oldChar, wchar_t newChar) throw() -{ - if (oldChar == newChar) - return; // 0; - // unsigned number = 0; - int pos = 0; - wchar_t *chars = _chars; - while ((unsigned)pos < _len) - { - pos = Find(oldChar, (unsigned)pos); - if (pos < 0) - break; - chars[(unsigned)pos] = newChar; - pos++; - // number++; - } - return; // number; -} - -void UString::Replace(const UString &oldString, const UString &newString) -{ - if (oldString.IsEmpty()) - return; // 0; - if (oldString == newString) - return; // 0; - unsigned oldLen = oldString.Len(); - unsigned newLen = newString.Len(); - // unsigned number = 0; - int pos = 0; - while ((unsigned)pos < _len) - { - pos = Find(oldString, (unsigned)pos); - if (pos < 0) - break; - Delete((unsigned)pos, oldLen); - Insert((unsigned)pos, newString); - pos += newLen; - // number++; - } - // return number; -} - -void UString::Delete(unsigned index) throw() -{ - MoveItems(index, index + 1); - _len--; -} - -void UString::Delete(unsigned index, unsigned count) throw() -{ - if (index + count > _len) - count = _len - index; - if (count > 0) - { - MoveItems(index, index + count); - _len -= count; - } -} - -void UString::DeleteFrontal(unsigned num) throw() -{ - if (num != 0) - { - MoveItems(0, num); - _len -= num; - } -} - - -// ---------- UString2 ---------- - -void UString2::ReAlloc2(unsigned newLimit) -{ - // wrong (_len) is allowed after this function - CHECK_STRING_ALLOC_LEN(newLimit) - // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); - if (_chars) - { - MY_STRING_DELETE(_chars) - _chars = NULL; - // _len = 0; - } - _chars = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); - _chars[0] = 0; - // _len = newLimit; -} - -void UString2::SetStartLen(unsigned len) -{ - _chars = NULL; - _chars = MY_STRING_NEW_wchar_t((size_t)len + 1); - _len = len; -} - - -/* -UString2::UString2(wchar_t c) -{ - SetStartLen(1); - wchar_t *chars = _chars; - chars[0] = c; - chars[1] = 0; -} -*/ - -UString2::UString2(const wchar_t *s) -{ - const unsigned len = MyStringLen(s); - SetStartLen(len); - wmemcpy(_chars, s, len + 1); -} - -UString2::UString2(const UString2 &s): _chars(NULL), _len(0) -{ - if (s._chars) - { - SetStartLen(s._len); - wmemcpy(_chars, s._chars, s._len + 1); - } -} - -/* -UString2 &UString2::operator=(wchar_t c) -{ - if (1 > _len) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1); - if (_chars) - MY_STRING_DELETE(_chars) - _chars = newBuf; - } - _len = 1; - wchar_t *chars = _chars; - chars[0] = c; - chars[1] = 0; - return *this; -} -*/ - -UString2 &UString2::operator=(const wchar_t *s) -{ - unsigned len = MyStringLen(s); - if (len > _len) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - if (_chars) - MY_STRING_DELETE(_chars) - _chars = newBuf; - } - _len = len; - MyStringCopy(_chars, s); - return *this; -} - -void UString2::SetFromAscii(const char *s) -{ - unsigned len = MyStringLen(s); - if (len > _len) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - if (_chars) - MY_STRING_DELETE(_chars) - _chars = newBuf; - } - wchar_t *chars = _chars; - for (unsigned i = 0; i < len; i++) - chars[i] = (unsigned char)s[i]; - chars[len] = 0; - _len = len; -} - -UString2 &UString2::operator=(const UString2 &s) -{ - if (&s == this) - return *this; - unsigned len = s._len; - if (len > _len) - { - wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); - if (_chars) - MY_STRING_DELETE(_chars) - _chars = newBuf; - } - _len = len; - MyStringCopy(_chars, s._chars); - return *this; -} - -bool operator==(const UString2 &s1, const UString2 &s2) -{ - return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0); -} - -bool operator==(const UString2 &s1, const wchar_t *s2) -{ - if (s1.IsEmpty()) - return (*s2 == 0); - return wcscmp(s1.GetRawPtr(), s2) == 0; -} - -bool operator==(const wchar_t *s1, const UString2 &s2) -{ - if (s2.IsEmpty()) - return (*s1 == 0); - return wcscmp(s1, s2.GetRawPtr()) == 0; -} - - - -// ---------------------------------------- - -/* -int MyStringCompareNoCase(const char *s1, const char *s2) -{ - return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); -} -*/ - -#if !defined(USE_UNICODE_FSTRING) || !defined(_UNICODE) - -static inline UINT GetCurrentCodePage() -{ - #if defined(UNDER_CE) || !defined(_WIN32) - return CP_ACP; - #else - return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; - #endif -} - -#endif - -#ifdef USE_UNICODE_FSTRING - -#ifndef _UNICODE - -AString fs2fas(CFSTR s) -{ - return UnicodeStringToMultiByte(s, GetCurrentCodePage()); -} - -FString fas2fs(const char *s) -{ - return MultiByteToUnicodeString(s, GetCurrentCodePage()); -} - -FString fas2fs(const AString &s) -{ - return MultiByteToUnicodeString(s, GetCurrentCodePage()); -} - -#endif // _UNICODE - -#else // USE_UNICODE_FSTRING - -UString fs2us(const FChar *s) -{ - return MultiByteToUnicodeString(s, GetCurrentCodePage()); -} - -UString fs2us(const FString &s) -{ - return MultiByteToUnicodeString(s, GetCurrentCodePage()); -} - -FString us2fs(const wchar_t *s) -{ - return UnicodeStringToMultiByte(s, GetCurrentCodePage()); -} - -#endif // USE_UNICODE_FSTRING - - -bool CStringFinder::FindWord_In_LowCaseAsciiList_NoCase(const char *p, const wchar_t *str) -{ - _temp.Empty(); - for (;;) - { - const wchar_t c = *str++; - if (c == 0) - break; - if (c <= 0x20 || c > 0x7f) - return false; - _temp.Add_Char((char)MyCharLower_Ascii((char)c)); - } - - while (*p != 0) - { - const char *s2 = _temp.Ptr(); - char c, c2; - do - { - c = *p++; - c2 = *s2++; - } - while (c == c2); - - if (c == ' ') - { - if (c2 == 0) - return true; - continue; - } - - while (*p++ != ' '); - } - - return false; -} - - -void SplitString(const UString &srcString, UStringVector &destStrings) -{ - destStrings.Clear(); - unsigned len = srcString.Len(); - if (len == 0) - return; - UString s; - for (unsigned i = 0; i < len; i++) - { - const wchar_t c = srcString[i]; - if (c == ' ') - { - if (!s.IsEmpty()) - { - destStrings.Add(s); - s.Empty(); - } - } - else - s += c; - } - if (!s.IsEmpty()) - destStrings.Add(s); -} +// Common/MyString.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "IntToString.h" + +#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING) +#include "StringConvert.h" +#endif + +#include "MyString.h" + +#define MY_STRING_NEW(_T_, _size_) new _T_[_size_] +// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_))) + +/* +inline const char* MyStringGetNextCharPointer(const char *p) throw() +{ + #if defined(_WIN32) && !defined(UNDER_CE) + return CharNextA(p); + #else + return p + 1; + #endif +} +*/ + +#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, (_size_)) +#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, (_size_)) + + +int FindCharPosInString(const char *s, char c) throw() +{ + for (const char *p = s;; p++) + { + if (*p == c) + return (int)(p - s); + if (*p == 0) + return -1; + // MyStringGetNextCharPointer(p); + } +} + +int FindCharPosInString(const wchar_t *s, wchar_t c) throw() +{ + for (const wchar_t *p = s;; p++) + { + if (*p == c) + return (int)(p - s); + if (*p == 0) + return -1; + } +} + +/* +void MyStringUpper_Ascii(char *s) throw() +{ + for (;;) + { + const char c = *s; + if (c == 0) + return; + *s++ = MyCharUpper_Ascii(c); + } +} + +void MyStringUpper_Ascii(wchar_t *s) throw() +{ + for (;;) + { + const wchar_t c = *s; + if (c == 0) + return; + *s++ = MyCharUpper_Ascii(c); + } +} +*/ + +void MyStringLower_Ascii(char *s) throw() +{ + for (;;) + { + const char c = *s; + if (c == 0) + return; + *s++ = MyCharLower_Ascii(c); + } +} + +void MyStringLower_Ascii(wchar_t *s) throw() +{ + for (;;) + { + const wchar_t c = *s; + if (c == 0) + return; + *s++ = MyCharLower_Ascii(c); + } +} + +#ifdef _WIN32 + +#ifdef _UNICODE + +// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } +// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } +// for WinCE - FString - char +// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; } + +#else + +// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); } +// char * MyStringUpper(char *s) { return CharUpperA(s); } +// char * MyStringLower(char *s) { return CharLowerA(s); } + +wchar_t MyCharUpper_WIN(wchar_t c) throw() +{ + wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return (wchar_t)(unsigned)(UINT_PTR)res; + const int kBufSize = 4; + char s[kBufSize + 1]; + int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); + if (numChars == 0 || numChars > kBufSize) + return c; + s[numChars] = 0; + ::CharUpperA(s); + ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); + return c; +} + +/* +wchar_t MyCharLower_WIN(wchar_t c) +{ + wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return (wchar_t)(unsigned)(UINT_PTR)res; + const int kBufSize = 4; + char s[kBufSize + 1]; + int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); + if (numChars == 0 || numChars > kBufSize) + return c; + s[numChars] = 0; + ::CharLowerA(s); + ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); + return c; +} +*/ + +/* +wchar_t * MyStringUpper(wchar_t *s) +{ + if (s == 0) + return 0; + wchar_t *res = CharUpperW(s); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return res; + AString a = UnicodeStringToMultiByte(s); + a.MakeUpper(); + MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); + return s; +} +*/ + +/* +wchar_t * MyStringLower(wchar_t *s) +{ + if (s == 0) + return 0; + wchar_t *res = CharLowerW(s); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return res; + AString a = UnicodeStringToMultiByte(s); + a.MakeLower(); + MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); + return s; +} +*/ + +#endif + +#endif + +bool IsString1PrefixedByString2(const char *s1, const char *s2) throw() +{ + for (;;) + { + const char c2 = *s2++; if (c2 == 0) return true; + const char c1 = *s1++; if (c1 != c2) return false; + } +} + +bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + const wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; + if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; + if (c1 == 0) return true; + } +} + +// ---------- ASCII ---------- + +bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() +{ + const char *s1 = _chars; + for (;;) + { + const char c2 = *s++; + if (c2 == 0) + return true; + const char c1 = *s1++; + if (MyCharLower_Ascii(c1) != + MyCharLower_Ascii(c2)) + return false; + } +} + +bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() +{ + const wchar_t *s1 = _chars; + for (;;) + { + const char c2 = *s++; + if (c2 == 0) + return true; + const wchar_t c1 = *s1++; + if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) + return false; + } +} + +bool StringsAreEqual_Ascii(const char *u, const char *a) throw() +{ + for (;;) + { + const char c = *a; + if (c != *u) + return false; + if (c == 0) + return true; + a++; + u++; + } +} + +bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw() +{ + for (;;) + { + const unsigned char c = (unsigned char)*a; + if (c != *u) + return false; + if (c == 0) + return true; + a++; + u++; + } +} + +bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw() +{ + for (;;) + { + const char c1 = *s1++; + const char c2 = *s2++; + if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) + return false; + if (c1 == 0) + return true; + } +} + +bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + const wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; + if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) + return false; + if (c1 == 0) + return true; + } +} + +bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw() +{ + for (;;) + { + const wchar_t c1 = *s1++; + const char c2 = *s2++; + if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) + return false; + if (c1 == 0) + return true; + } +} + +bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + const wchar_t c2 = *s2++; if (c2 == 0) return true; + const wchar_t c1 = *s1++; if (c1 != c2) return false; + } +} + +bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw() +{ + for (;;) + { + const unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true; + const wchar_t c1 = *s1++; if (c1 != c2) return false; + } +} + +bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw() +{ + for (;;) + { + const char c2 = *s2++; if (c2 == 0) return true; + const char c1 = *s1++; + if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) + return false; + } +} + +bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2) throw() +{ + for (;;) + { + const char c2 = *s2++; if (c2 == 0) return true; + const wchar_t c1 = *s1++; + if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) + return false; + } +} + +bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + const wchar_t c2 = *s2++; if (c2 == 0) return true; + const wchar_t c1 = *s1++; + if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) + return false; + } +} + +// NTFS order: uses upper case +int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + const wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; + if (c1 != c2) + { + const wchar_t u1 = MyCharUpper(c1); + const wchar_t u2 = MyCharUpper(c2); + if (u1 < u2) return -1; + if (u1 > u2) return 1; + } + if (c1 == 0) return 0; + } +} + +/* +int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) +{ + for (; num != 0; num--) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + wchar_t u1 = MyCharUpper(c1); + wchar_t u2 = MyCharUpper(c2); + if (u1 < u2) return -1; + if (u1 > u2) return 1; + } + if (c1 == 0) return 0; + } + return 0; +} +*/ + +// ---------- AString ---------- + +void AString::InsertSpace(unsigned &index, unsigned size) +{ + Grow(size); + MoveItems(index + size, index); +} + +#define k_Alloc_Len_Limit (0x40000000 - 2) +// #define k_Alloc_Len_Limit (((unsigned)1 << (sizeof(unsigned) * 8 - 2)) - 2) + +void AString::ReAlloc(unsigned newLimit) +{ + // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, (size_t)_len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1); + memcpy(newBuf, _chars, (size_t)_len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = newLimit; +} + +#define THROW_STRING_ALLOC_EXCEPTION { throw 20130220; } + +#define CHECK_STRING_ALLOC_LEN(len) \ + { if ((len) > k_Alloc_Len_Limit) THROW_STRING_ALLOC_EXCEPTION } + +void AString::ReAlloc2(unsigned newLimit) +{ + CHECK_STRING_ALLOC_LEN(newLimit) + // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, 0); + char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1); + newBuf[0] = 0; + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = newLimit; + _len = 0; +} + +void AString::SetStartLen(unsigned len) +{ + _chars = NULL; + _chars = MY_STRING_NEW_char((size_t)len + 1); + _len = len; + _limit = len; +} + +Z7_NO_INLINE +void AString::Grow_1() +{ + unsigned next = _len; + next += next / 2; + next += 16; + next &= ~(unsigned)15; + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len) + THROW_STRING_ALLOC_EXCEPTION + ReAlloc(next); + // Grow(1); +} + +void AString::Grow(unsigned n) +{ + const unsigned freeSize = _limit - _len; + if (n <= freeSize) + return; + unsigned next = _len + n; + next += next / 2; + next += 16; + next &= ~(unsigned)15; + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len || next - _len < n) + THROW_STRING_ALLOC_EXCEPTION + ReAlloc(next); +} + +AString::AString(unsigned num, const char *s) +{ + unsigned len = MyStringLen(s); + if (num > len) + num = len; + SetStartLen(num); + memcpy(_chars, s, num); + _chars[num] = 0; +} + +AString::AString(unsigned num, const AString &s) +{ + if (num > s._len) + num = s._len; + SetStartLen(num); + memcpy(_chars, s._chars, num); + _chars[num] = 0; +} + +AString::AString(const AString &s, char c) +{ + SetStartLen(s.Len() + 1); + char *chars = _chars; + unsigned len = s.Len(); + memcpy(chars, s, len); + chars[len] = c; + chars[(size_t)len + 1] = 0; +} + +AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2) +{ + SetStartLen(num1 + num2); + char *chars = _chars; + memcpy(chars, s1, num1); + memcpy(chars + num1, s2, num2 + 1); +} + +AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); } +AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); } +AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); } + +static const unsigned kStartStringCapacity = 4; + +AString::AString() +{ + _chars = NULL; + _chars = MY_STRING_NEW_char(kStartStringCapacity); + _len = 0; + _limit = kStartStringCapacity - 1; + _chars[0] = 0; +} + +AString::AString(char c) +{ + SetStartLen(1); + char *chars = _chars; + chars[0] = c; + chars[1] = 0; +} + +AString::AString(const char *s) +{ + SetStartLen(MyStringLen(s)); + MyStringCopy(_chars, s); +} + +AString::AString(const AString &s) +{ + SetStartLen(s._len); + MyStringCopy(_chars, s._chars); +} + +AString &AString::operator=(char c) +{ + if (1 > _limit) + { + char *newBuf = MY_STRING_NEW_char(1 + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = 1; + } + _len = 1; + char *chars = _chars; + chars[0] = c; + chars[1] = 0; + return *this; +} + +AString &AString::operator=(const char *s) +{ + unsigned len = MyStringLen(s); + if (len > _limit) + { + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + MyStringCopy(_chars, s); + return *this; +} + +AString &AString::operator=(const AString &s) +{ + if (&s == this) + return *this; + unsigned len = s._len; + if (len > _limit) + { + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + MyStringCopy(_chars, s._chars); + return *this; +} + +void AString::SetFromWStr_if_Ascii(const wchar_t *s) +{ + unsigned len = 0; + { + for (;; len++) + { + wchar_t c = s[len]; + if (c == 0) + break; + if (c >= 0x80) + return; + } + } + if (len > _limit) + { + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + char *dest = _chars; + unsigned i; + for (i = 0; i < len; i++) + dest[i] = (char)s[i]; + dest[i] = 0; +} + +/* +void AString::SetFromBstr_if_Ascii(BSTR s) +{ + unsigned len = ::SysStringLen(s); + { + for (unsigned i = 0; i < len; i++) + if (s[i] <= 0 || s[i] >= 0x80) + return; + } + if (len > _limit) + { + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + char *dest = _chars; + unsigned i; + for (i = 0; i < len; i++) + dest[i] = (char)s[i]; + dest[i] = 0; +} +*/ + +void AString::Add_Char(char c) { operator+=(c); } +void AString::Add_Space() { operator+=(' '); } +void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } +void AString::Add_LF() { operator+=('\n'); } +void AString::Add_Slash() { operator+=('/'); } +void AString::Add_Dot() { operator+=('.'); } +void AString::Add_Minus() { operator+=('-'); } +void AString::Add_Colon() { operator+=(':'); } + +AString &AString::operator+=(const char *s) +{ + unsigned len = MyStringLen(s); + Grow(len); + MyStringCopy(_chars + _len, s); + _len += len; + return *this; +} + +void AString::Add_OptSpaced(const char *s) +{ + Add_Space_if_NotEmpty(); + (*this) += s; +} + +AString &AString::operator+=(const AString &s) +{ + Grow(s._len); + MyStringCopy(_chars + _len, s._chars); + _len += s._len; + return *this; +} + +void AString::Add_UInt32(UInt32 v) +{ + Grow(10); + _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars); +} + +void UString::Add_UInt64(UInt64 v) +{ + Grow(20); + _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); +} + +void AString::AddFrom(const char *s, unsigned len) // no check +{ + if (len != 0) + { + Grow(len); + memcpy(_chars + _len, s, len); + len += _len; + _chars[len] = 0; + _len = len; + } +} + +void AString::SetFrom(const char *s, unsigned len) // no check +{ + if (len > _limit) + { + CHECK_STRING_ALLOC_LEN(len) + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + if (len != 0) + memcpy(_chars, s, len); + _chars[len] = 0; + _len = len; +} + +void AString::SetFrom_Chars_SizeT(const char *s, size_t len) +{ + CHECK_STRING_ALLOC_LEN(len) + SetFrom(s, (unsigned)len); +} + +void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check +{ + unsigned i; + for (i = 0; i < len; i++) + if (s[i] == 0) + break; + SetFrom(s, i); +} + +int AString::Find(const char *s, unsigned startIndex) const throw() +{ + const char *fs = strstr(_chars + startIndex, s); + if (!fs) + return -1; + return (int)(fs - _chars); + + /* + if (s[0] == 0) + return startIndex; + unsigned len = MyStringLen(s); + const char *p = _chars + startIndex; + for (;; p++) + { + const char c = *p; + if (c != s[0]) + { + if (c == 0) + return -1; + continue; + } + unsigned i; + for (i = 1; i < len; i++) + if (p[i] != s[i]) + break; + if (i == len) + return (int)(p - _chars); + } + */ +} + +int AString::ReverseFind(char c) const throw() +{ + if (_len == 0) + return -1; + const char *p = _chars + _len - 1; + for (;;) + { + if (*p == c) + return (int)(p - _chars); + if (p == _chars) + return -1; + p--; // p = GetPrevCharPointer(_chars, p); + } +} + +int AString::ReverseFind_PathSepar() const throw() +{ + if (_len == 0) + return -1; + const char *p = _chars + _len - 1; + for (;;) + { + const char c = *p; + if (IS_PATH_SEPAR(c)) + return (int)(p - _chars); + if (p == _chars) + return -1; + p--; + } +} + +void AString::TrimLeft() throw() +{ + const char *p = _chars; + for (;; p++) + { + char c = *p; + if (c != ' ' && c != '\n' && c != '\t') + break; + } + unsigned pos = (unsigned)(p - _chars); + if (pos != 0) + { + MoveItems(0, pos); + _len -= pos; + } +} + +void AString::TrimRight() throw() +{ + const char *p = _chars; + unsigned i; + for (i = _len; i != 0; i--) + { + char c = p[(size_t)i - 1]; + if (c != ' ' && c != '\n' && c != '\t') + break; + } + if (i != _len) + { + _chars[i] = 0; + _len = i; + } +} + +void AString::InsertAtFront(char c) +{ + if (_limit == _len) + Grow_1(); + MoveItems(1, 0); + _chars[0] = c; + _len++; +} + +/* +void AString::Insert(unsigned index, char c) +{ + InsertSpace(index, 1); + _chars[index] = c; + _len++; +} +*/ + +void AString::Insert(unsigned index, const char *s) +{ + unsigned num = MyStringLen(s); + if (num != 0) + { + InsertSpace(index, num); + memcpy(_chars + index, s, num); + _len += num; + } +} + +void AString::Insert(unsigned index, const AString &s) +{ + unsigned num = s.Len(); + if (num != 0) + { + InsertSpace(index, num); + memcpy(_chars + index, s, num); + _len += num; + } +} + +void AString::RemoveChar(char ch) throw() +{ + char *src = _chars; + + for (;;) + { + char c = *src++; + if (c == 0) + return; + if (c == ch) + break; + } + + char *dest = src - 1; + + for (;;) + { + char c = *src++; + if (c == 0) + break; + if (c != ch) + *dest++ = c; + } + + *dest = 0; + _len = (unsigned)(dest - _chars); +} + +// !!!!!!!!!!!!!!! test it if newChar = '\0' +void AString::Replace(char oldChar, char newChar) throw() +{ + if (oldChar == newChar) + return; // 0; + // unsigned number = 0; + int pos = 0; + char *chars = _chars; + while ((unsigned)pos < _len) + { + pos = Find(oldChar, (unsigned)pos); + if (pos < 0) + break; + chars[(unsigned)pos] = newChar; + pos++; + // number++; + } + return; // number; +} + +void AString::Replace(const AString &oldString, const AString &newString) +{ + if (oldString.IsEmpty()) + return; // 0; + if (oldString == newString) + return; // 0; + const unsigned oldLen = oldString.Len(); + const unsigned newLen = newString.Len(); + // unsigned number = 0; + int pos = 0; + while ((unsigned)pos < _len) + { + pos = Find(oldString, (unsigned)pos); + if (pos < 0) + break; + Delete((unsigned)pos, oldLen); + Insert((unsigned)pos, newString); + pos += newLen; + // number++; + } + // return number; +} + +void AString::Delete(unsigned index) throw() +{ + MoveItems(index, index + 1); + _len--; +} + +void AString::Delete(unsigned index, unsigned count) throw() +{ + if (index + count > _len) + count = _len - index; + if (count > 0) + { + MoveItems(index, index + count); + _len -= count; + } +} + +void AString::DeleteFrontal(unsigned num) throw() +{ + if (num != 0) + { + MoveItems(0, num); + _len -= num; + } +} + +/* +AString operator+(const AString &s1, const AString &s2) +{ + AString result(s1); + result += s2; + return result; +} + +AString operator+(const AString &s, const char *chars) +{ + AString result(s); + result += chars; + return result; +} + +AString operator+(const char *chars, const AString &s) +{ + AString result(chars); + result += s; + return result; +} + +AString operator+(const AString &s, char c) +{ + AString result(s); + result += c; + return result; +} +*/ + +/* +AString operator+(char c, const AString &s) +{ + AString result(c); + result += s; + return result; +} +*/ + + + + +// ---------- UString ---------- + +void UString::InsertSpace(unsigned index, unsigned size) +{ + Grow(size); + MoveItems(index + size, index); +} + +void UString::ReAlloc(unsigned newLimit) +{ + // MY_STRING_REALLOC(_chars, wchar_t, (size_t)newLimit + 1, (size_t)_len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); + wmemcpy(newBuf, _chars, _len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = newLimit; +} + +void UString::ReAlloc2(unsigned newLimit) +{ + CHECK_STRING_ALLOC_LEN(newLimit) + // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); + newBuf[0] = 0; + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = newLimit; + _len = 0; +} + +void UString::SetStartLen(unsigned len) +{ + _chars = NULL; + _chars = MY_STRING_NEW_wchar_t((size_t)len + 1); + _len = len; + _limit = len; +} + +Z7_NO_INLINE +void UString::Grow_1() +{ + unsigned next = _len; + next += next / 2; + next += 16; + next &= ~(unsigned)15; + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len) + THROW_STRING_ALLOC_EXCEPTION + ReAlloc(next); +} + +void UString::Grow(unsigned n) +{ + const unsigned freeSize = _limit - _len; + if (n <= freeSize) + return; + unsigned next = _len + n; + next += next / 2; + next += 16; + next &= ~(unsigned)15; + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len || next - _len < n) + THROW_STRING_ALLOC_EXCEPTION + ReAlloc(next - 1); +} + + +UString::UString(unsigned num, const wchar_t *s) +{ + unsigned len = MyStringLen(s); + if (num > len) + num = len; + SetStartLen(num); + wmemcpy(_chars, s, num); + _chars[num] = 0; +} + + +UString::UString(unsigned num, const UString &s) +{ + if (num > s._len) + num = s._len; + SetStartLen(num); + wmemcpy(_chars, s._chars, num); + _chars[num] = 0; +} + +UString::UString(const UString &s, wchar_t c) +{ + SetStartLen(s.Len() + 1); + wchar_t *chars = _chars; + unsigned len = s.Len(); + wmemcpy(chars, s, len); + chars[len] = c; + chars[(size_t)len + 1] = 0; +} + +UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2) +{ + SetStartLen(num1 + num2); + wchar_t *chars = _chars; + wmemcpy(chars, s1, num1); + wmemcpy(chars + num1, s2, num2 + 1); +} + +UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); } +UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); } +UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); } + +UString::UString() +{ + _chars = NULL; + _chars = MY_STRING_NEW_wchar_t(kStartStringCapacity); + _len = 0; + _limit = kStartStringCapacity - 1; + _chars[0] = 0; +} + +UString::UString(wchar_t c) +{ + SetStartLen(1); + wchar_t *chars = _chars; + chars[0] = c; + chars[1] = 0; +} + +UString::UString(char c) +{ + SetStartLen(1); + wchar_t *chars = _chars; + chars[0] = (unsigned char)c; + chars[1] = 0; +} + +UString::UString(const wchar_t *s) +{ + const unsigned len = MyStringLen(s); + SetStartLen(len); + wmemcpy(_chars, s, len + 1); +} + +UString::UString(const char *s) +{ + const unsigned len = MyStringLen(s); + SetStartLen(len); + wchar_t *chars = _chars; + for (unsigned i = 0; i < len; i++) + chars[i] = (unsigned char)s[i]; + chars[len] = 0; +} + +UString::UString(const AString &s) +{ + const unsigned len = s.Len(); + SetStartLen(len); + wchar_t *chars = _chars; + const char *s2 = s.Ptr(); + for (unsigned i = 0; i < len; i++) + chars[i] = (unsigned char)s2[i]; + chars[len] = 0; +} + +UString::UString(const UString &s) +{ + SetStartLen(s._len); + wmemcpy(_chars, s._chars, s._len + 1); +} + +UString &UString::operator=(wchar_t c) +{ + if (1 > _limit) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = 1; + } + _len = 1; + wchar_t *chars = _chars; + chars[0] = c; + chars[1] = 0; + return *this; +} + +UString &UString::operator=(const wchar_t *s) +{ + unsigned len = MyStringLen(s); + if (len > _limit) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + wmemcpy(_chars, s, len + 1); + return *this; +} + +UString &UString::operator=(const UString &s) +{ + if (&s == this) + return *this; + unsigned len = s._len; + if (len > _limit) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + wmemcpy(_chars, s._chars, len + 1); + return *this; +} + +void UString::SetFrom(const wchar_t *s, unsigned len) // no check +{ + if (len > _limit) + { + CHECK_STRING_ALLOC_LEN(len) + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + if (len != 0) + wmemcpy(_chars, s, len); + _chars[len] = 0; + _len = len; +} + +void UString::SetFromBstr(LPCOLESTR s) +{ + unsigned len = ::SysStringLen((BSTR)(void *)(s)); + + /* + #if WCHAR_MAX > 0xffff + size_t num_wchars = 0; + for (size_t i = 0; i < len;) + { + wchar_t c = s[i++]; + if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) + { + wchar_t c2 = s[i]; + if (c2 >= 0xdc00 && c2 < 0xe000) + { + c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); + i++; + } + } + num_wchars++; + } + len = num_wchars; + #endif + */ + + if (len > _limit) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + _len = len; + + /* + #if WCHAR_MAX > 0xffff + + wchar_t *chars = _chars; + for (size_t i = 0; i <= len; i++) + { + wchar_t c = *s++; + if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) + { + wchar_t c2 = *s; + if (c2 >= 0xdc00 && c2 < 0xe000) + { + s++; + c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); + } + } + chars[i] = c; + } + + #else + */ + + // if (s) + wmemcpy(_chars, s, len + 1); + + // #endif +} + +UString &UString::operator=(const char *s) +{ + unsigned len = MyStringLen(s); + if (len > _limit) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + MY_STRING_DELETE(_chars) + _chars = newBuf; + _limit = len; + } + wchar_t *chars = _chars; + for (unsigned i = 0; i < len; i++) + chars[i] = (unsigned char)s[i]; + chars[len] = 0; + _len = len; + return *this; +} + +void UString::Add_Char(char c) { operator+=((wchar_t)(unsigned char)c); } +// void UString::Add_WChar(wchar_t c) { operator+=(c); } +void UString::Add_Dot() { operator+=(L'.'); } +void UString::Add_Space() { operator+=(L' '); } +void UString::Add_Minus() { operator+=(L'-'); } +void UString::Add_Colon() { operator+=(L':'); } +void UString::Add_LF() { operator+=(L'\n'); } +void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } + +UString &UString::operator+=(const wchar_t *s) +{ + unsigned len = MyStringLen(s); + Grow(len); + wmemcpy(_chars + _len, s, len + 1); + _len += len; + return *this; +} + +UString &UString::operator+=(const UString &s) +{ + Grow(s._len); + wmemcpy(_chars + _len, s._chars, s._len + 1); + _len += s._len; + return *this; +} + +UString &UString::operator+=(const char *s) +{ + unsigned len = MyStringLen(s); + Grow(len); + wchar_t *chars = _chars + _len; + for (unsigned i = 0; i < len; i++) + chars[i] = (unsigned char)s[i]; + chars[len] = 0; + _len += len; + return *this; +} + + +void UString::Add_UInt32(UInt32 v) +{ + Grow(10); + _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars); +} + +void AString::Add_UInt64(UInt64 v) +{ + Grow(20); + _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); +} + + +int UString::Find(const wchar_t *s, unsigned startIndex) const throw() +{ + const wchar_t *fs = wcsstr(_chars + startIndex, s); + if (!fs) + return -1; + return (int)(fs - _chars); + + /* + if (s[0] == 0) + return startIndex; + unsigned len = MyStringLen(s); + const wchar_t *p = _chars + startIndex; + for (;; p++) + { + const wchar_t c = *p; + if (c != s[0]) + { + if (c == 0) + return -1; + continue; + } + unsigned i; + for (i = 1; i < len; i++) + if (p[i] != s[i]) + break; + if (i == len) + return (int)(p - _chars); + } + */ +} + +int UString::ReverseFind(wchar_t c) const throw() +{ + if (_len == 0) + return -1; + const wchar_t *p = _chars + _len; + do + { + if (*(--p) == c) + return (int)(p - _chars); + } + while (p != _chars); + return -1; +} + +int UString::ReverseFind_PathSepar() const throw() +{ + const wchar_t *p = _chars + _len; + while (p != _chars) + { + const wchar_t c = *(--p); + if (IS_PATH_SEPAR(c)) + return (int)(p - _chars); + } + return -1; +} + +void UString::TrimLeft() throw() +{ + const wchar_t *p = _chars; + for (;; p++) + { + wchar_t c = *p; + if (c != ' ' && c != '\n' && c != '\t') + break; + } + unsigned pos = (unsigned)(p - _chars); + if (pos != 0) + { + MoveItems(0, pos); + _len -= pos; + } +} + +void UString::TrimRight() throw() +{ + const wchar_t *p = _chars; + unsigned i; + for (i = _len; i != 0; i--) + { + wchar_t c = p[(size_t)i - 1]; + if (c != ' ' && c != '\n' && c != '\t') + break; + } + if (i != _len) + { + _chars[i] = 0; + _len = i; + } +} + +void UString::InsertAtFront(wchar_t c) +{ + if (_limit == _len) + Grow_1(); + MoveItems(1, 0); + _chars[0] = c; + _len++; +} + +/* +void UString::Insert_wchar_t(unsigned index, wchar_t c) +{ + InsertSpace(index, 1); + _chars[index] = c; + _len++; +} +*/ + +void UString::Insert(unsigned index, const wchar_t *s) +{ + unsigned num = MyStringLen(s); + if (num != 0) + { + InsertSpace(index, num); + wmemcpy(_chars + index, s, num); + _len += num; + } +} + +void UString::Insert(unsigned index, const UString &s) +{ + unsigned num = s.Len(); + if (num != 0) + { + InsertSpace(index, num); + wmemcpy(_chars + index, s, num); + _len += num; + } +} + +void UString::RemoveChar(wchar_t ch) throw() +{ + wchar_t *src = _chars; + + for (;;) + { + wchar_t c = *src++; + if (c == 0) + return; + if (c == ch) + break; + } + + wchar_t *dest = src - 1; + + for (;;) + { + wchar_t c = *src++; + if (c == 0) + break; + if (c != ch) + *dest++ = c; + } + + *dest = 0; + _len = (unsigned)(dest - _chars); +} + +// !!!!!!!!!!!!!!! test it if newChar = '\0' +void UString::Replace(wchar_t oldChar, wchar_t newChar) throw() +{ + if (oldChar == newChar) + return; // 0; + // unsigned number = 0; + int pos = 0; + wchar_t *chars = _chars; + while ((unsigned)pos < _len) + { + pos = Find(oldChar, (unsigned)pos); + if (pos < 0) + break; + chars[(unsigned)pos] = newChar; + pos++; + // number++; + } + return; // number; +} + +void UString::Replace(const UString &oldString, const UString &newString) +{ + if (oldString.IsEmpty()) + return; // 0; + if (oldString == newString) + return; // 0; + unsigned oldLen = oldString.Len(); + unsigned newLen = newString.Len(); + // unsigned number = 0; + int pos = 0; + while ((unsigned)pos < _len) + { + pos = Find(oldString, (unsigned)pos); + if (pos < 0) + break; + Delete((unsigned)pos, oldLen); + Insert((unsigned)pos, newString); + pos += newLen; + // number++; + } + // return number; +} + +void UString::Delete(unsigned index) throw() +{ + MoveItems(index, index + 1); + _len--; +} + +void UString::Delete(unsigned index, unsigned count) throw() +{ + if (index + count > _len) + count = _len - index; + if (count > 0) + { + MoveItems(index, index + count); + _len -= count; + } +} + +void UString::DeleteFrontal(unsigned num) throw() +{ + if (num != 0) + { + MoveItems(0, num); + _len -= num; + } +} + + +// ---------- UString2 ---------- + +void UString2::ReAlloc2(unsigned newLimit) +{ + // wrong (_len) is allowed after this function + CHECK_STRING_ALLOC_LEN(newLimit) + // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); + if (_chars) + { + MY_STRING_DELETE(_chars) + _chars = NULL; + // _len = 0; + } + _chars = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); + _chars[0] = 0; + // _len = newLimit; +} + +void UString2::SetStartLen(unsigned len) +{ + _chars = NULL; + _chars = MY_STRING_NEW_wchar_t((size_t)len + 1); + _len = len; +} + + +/* +UString2::UString2(wchar_t c) +{ + SetStartLen(1); + wchar_t *chars = _chars; + chars[0] = c; + chars[1] = 0; +} +*/ + +UString2::UString2(const wchar_t *s) +{ + const unsigned len = MyStringLen(s); + SetStartLen(len); + wmemcpy(_chars, s, len + 1); +} + +UString2::UString2(const UString2 &s): _chars(NULL), _len(0) +{ + if (s._chars) + { + SetStartLen(s._len); + wmemcpy(_chars, s._chars, s._len + 1); + } +} + +/* +UString2 &UString2::operator=(wchar_t c) +{ + if (1 > _len) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1); + if (_chars) + MY_STRING_DELETE(_chars) + _chars = newBuf; + } + _len = 1; + wchar_t *chars = _chars; + chars[0] = c; + chars[1] = 0; + return *this; +} +*/ + +UString2 &UString2::operator=(const wchar_t *s) +{ + unsigned len = MyStringLen(s); + if (len > _len) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + if (_chars) + MY_STRING_DELETE(_chars) + _chars = newBuf; + } + _len = len; + MyStringCopy(_chars, s); + return *this; +} + +void UString2::SetFromAscii(const char *s) +{ + unsigned len = MyStringLen(s); + if (len > _len) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + if (_chars) + MY_STRING_DELETE(_chars) + _chars = newBuf; + } + wchar_t *chars = _chars; + for (unsigned i = 0; i < len; i++) + chars[i] = (unsigned char)s[i]; + chars[len] = 0; + _len = len; +} + +UString2 &UString2::operator=(const UString2 &s) +{ + if (&s == this) + return *this; + unsigned len = s._len; + if (len > _len) + { + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); + if (_chars) + MY_STRING_DELETE(_chars) + _chars = newBuf; + } + _len = len; + MyStringCopy(_chars, s._chars); + return *this; +} + +bool operator==(const UString2 &s1, const UString2 &s2) +{ + return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0); +} + +bool operator==(const UString2 &s1, const wchar_t *s2) +{ + if (s1.IsEmpty()) + return (*s2 == 0); + return wcscmp(s1.GetRawPtr(), s2) == 0; +} + +bool operator==(const wchar_t *s1, const UString2 &s2) +{ + if (s2.IsEmpty()) + return (*s1 == 0); + return wcscmp(s1, s2.GetRawPtr()) == 0; +} + + + +// ---------------------------------------- + +/* +int MyStringCompareNoCase(const char *s1, const char *s2) +{ + return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); +} +*/ + +#if !defined(USE_UNICODE_FSTRING) || !defined(_UNICODE) + +static inline UINT GetCurrentCodePage() +{ + #if defined(UNDER_CE) || !defined(_WIN32) + return CP_ACP; + #else + return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; + #endif +} + +#endif + +#ifdef USE_UNICODE_FSTRING + +#ifndef _UNICODE + +AString fs2fas(CFSTR s) +{ + return UnicodeStringToMultiByte(s, GetCurrentCodePage()); +} + +FString fas2fs(const char *s) +{ + return MultiByteToUnicodeString(s, GetCurrentCodePage()); +} + +FString fas2fs(const AString &s) +{ + return MultiByteToUnicodeString(s, GetCurrentCodePage()); +} + +#endif // _UNICODE + +#else // USE_UNICODE_FSTRING + +UString fs2us(const FChar *s) +{ + return MultiByteToUnicodeString(s, GetCurrentCodePage()); +} + +UString fs2us(const FString &s) +{ + return MultiByteToUnicodeString(s, GetCurrentCodePage()); +} + +FString us2fs(const wchar_t *s) +{ + return UnicodeStringToMultiByte(s, GetCurrentCodePage()); +} + +#endif // USE_UNICODE_FSTRING + + +bool CStringFinder::FindWord_In_LowCaseAsciiList_NoCase(const char *p, const wchar_t *str) +{ + _temp.Empty(); + for (;;) + { + const wchar_t c = *str++; + if (c == 0) + break; + if (c <= 0x20 || c > 0x7f) + return false; + _temp.Add_Char((char)MyCharLower_Ascii((char)c)); + } + + while (*p != 0) + { + const char *s2 = _temp.Ptr(); + char c, c2; + do + { + c = *p++; + c2 = *s2++; + } + while (c == c2); + + if (c == ' ') + { + if (c2 == 0) + return true; + continue; + } + + while (*p++ != ' '); + } + + return false; +} + + +void SplitString(const UString &srcString, UStringVector &destStrings) +{ + destStrings.Clear(); + unsigned len = srcString.Len(); + if (len == 0) + return; + UString s; + for (unsigned i = 0; i < len; i++) + { + const wchar_t c = srcString[i]; + if (c == ' ') + { + if (!s.IsEmpty()) + { + destStrings.Add(s); + s.Empty(); + } + } + else + s += c; + } + if (!s.IsEmpty()) + destStrings.Add(s); +} diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h index 5f41c7b97..ba9914e18 100644 --- a/CPP/Common/MyString.h +++ b/CPP/Common/MyString.h @@ -1,1078 +1,1078 @@ -// Common/MyString.h - -#ifndef ZIP7_INC_COMMON_MY_STRING_H -#define ZIP7_INC_COMMON_MY_STRING_H - -#include - -#ifndef _WIN32 -#include -#include -#endif - -#include "Common.h" -#include "MyWindows.h" -#include "MyTypes.h" -#include "MyVector.h" - - -/* if (DEBUG_FSTRING_INHERITS_ASTRING is defined), then - FString inherits from AString, so we can find bugs related to FString at compile time. - DON'T define DEBUG_FSTRING_INHERITS_ASTRING in release code */ - -// #define DEBUG_FSTRING_INHERITS_ASTRING - -#ifdef DEBUG_FSTRING_INHERITS_ASTRING -class FString; -#endif - - -#ifdef _MSC_VER - #ifdef _NATIVE_WCHAR_T_DEFINED - #define MY_NATIVE_WCHAR_T_DEFINED - #endif -#else - #define MY_NATIVE_WCHAR_T_DEFINED -#endif - -/* - native support for wchar_t: - _MSC_VER == 1600 : /Zc:wchar_t is not supported - _MSC_VER == 1310 (VS2003) - ? _MSC_VER == 1400 (VS2005) : wchar_t <- unsigned short - /Zc:wchar_t : wchar_t <- __wchar_t, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED - _MSC_VER > 1400 (VS2008+) - /Zc:wchar_t[-] - /Zc:wchar_t is on by default -*/ - -#ifdef _WIN32 -#define IS_PATH_SEPAR(c) ((c) == '\\' || (c) == '/') -#else -#define IS_PATH_SEPAR(c) ((c) == CHAR_PATH_SEPARATOR) -#endif - -inline bool IsPathSepar(char c) { return IS_PATH_SEPAR(c); } -inline bool IsPathSepar(wchar_t c) { return IS_PATH_SEPAR(c); } - -inline unsigned MyStringLen(const char *s) -{ - unsigned i; - for (i = 0; s[i] != 0; i++); - return i; -} - -inline void MyStringCopy(char *dest, const char *src) -{ - while ((*dest++ = *src++) != 0); -} - -inline char *MyStpCpy(char *dest, const char *src) -{ - for (;;) - { - const char c = *src; - *dest = c; - if (c == 0) - return dest; - src++; - dest++; - } -} - -inline void MyStringCat(char *dest, const char *src) -{ - for (; *dest != 0; dest++); - while ((*dest++ = *src++) != 0); - // MyStringCopy(dest + MyStringLen(dest), src); -} - -inline unsigned MyStringLen(const wchar_t *s) -{ - unsigned i; - for (i = 0; s[i] != 0; i++); - return i; -} - -inline void MyStringCopy(wchar_t *dest, const wchar_t *src) -{ - while ((*dest++ = *src++) != 0); -} - -inline void MyStringCat(wchar_t *dest, const wchar_t *src) -{ - for (; *dest != 0; dest++); - while ((*dest++ = *src++) != 0); - // MyStringCopy(dest + MyStringLen(dest), src); -} - - -/* -inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src) -{ - for (;;) - { - const wchar_t c = *src; - *dest = c; - if (c == 0) - return dest; - src++; - dest++; - } -} -*/ - -int FindCharPosInString(const char *s, char c) throw(); -int FindCharPosInString(const wchar_t *s, wchar_t c) throw(); - -#ifdef _WIN32 - #ifndef _UNICODE - #define STRING_UNICODE_THROW - #endif -#endif - -#ifndef STRING_UNICODE_THROW - #define STRING_UNICODE_THROW throw() -#endif - - -inline char MyCharUpper_Ascii(char c) -{ - if (c >= 'a' && c <= 'z') - return (char)((unsigned char)c - 0x20); - return c; -} - -/* -inline wchar_t MyCharUpper_Ascii(wchar_t c) -{ - if (c >= 'a' && c <= 'z') - return (wchar_t)(c - 0x20); - return c; -} -*/ - -inline char MyCharLower_Ascii(char c) -{ - if (c >= 'A' && c <= 'Z') - return (char)((unsigned char)c + 0x20); - return c; -} - -inline wchar_t MyCharLower_Ascii(wchar_t c) -{ - if (c >= 'A' && c <= 'Z') - return (wchar_t)(c + 0x20); - return c; -} - -wchar_t MyCharUpper_WIN(wchar_t c) throw(); - -inline wchar_t MyCharUpper(wchar_t c) throw() -{ - if (c < 'a') return c; - if (c <= 'z') return (wchar_t)(c - 0x20); - if (c <= 0x7F) return c; - #ifdef _WIN32 - #ifdef _UNICODE - return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); - #else - return (wchar_t)MyCharUpper_WIN(c); - #endif - #else - return (wchar_t)towupper((wint_t)c); - #endif -} - -/* -wchar_t MyCharLower_WIN(wchar_t c) throw(); - -inline wchar_t MyCharLower(wchar_t c) throw() -{ - if (c < 'A') return c; - if (c <= 'Z') return (wchar_t)(c + 0x20); - if (c <= 0x7F) return c; - #ifdef _WIN32 - #ifdef _UNICODE - return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); - #else - return (wchar_t)MyCharLower_WIN(c); - #endif - #else - return (wchar_t)tolower(c); - #endif -} -*/ - -// char *MyStringUpper(char *s) throw(); -// char *MyStringLower(char *s) throw(); - -// void MyStringUpper_Ascii(char *s) throw(); -// void MyStringUpper_Ascii(wchar_t *s) throw(); -void MyStringLower_Ascii(char *s) throw(); -void MyStringLower_Ascii(wchar_t *s) throw(); -// wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW; -// wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW; - -bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw(); - -bool IsString1PrefixedByString2(const char *s1, const char *s2) throw(); -bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw(); -bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw(); -bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw(); -bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *u, const char *a) throw(); -bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw(); - -#define MyStringCompare(s1, s2) wcscmp(s1, s2) -int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw(); -// int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw(); - -// ---------- ASCII ---------- -// char values in ASCII strings must be less then 128 -bool StringsAreEqual_Ascii(const char *u, const char *a) throw(); -bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw(); -bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw(); -bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw(); -bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw(); - -#define MY_STRING_DELETE(_p_) { delete [](_p_); } -// #define MY_STRING_DELETE(_p_) my_delete(_p_); - - -#define FORBID_STRING_OPS_2(cls, t) \ - void Find(t) const; \ - void Find(t, unsigned startIndex) const; \ - void ReverseFind(t) const; \ - void InsertAtFront(t); \ - void RemoveChar(t); \ - void Replace(t, t); \ - -#define FORBID_STRING_OPS(cls, t) \ - explicit cls(t); \ - explicit cls(const t *); \ - cls &operator=(t); \ - cls &operator=(const t *); \ - cls &operator+=(t); \ - cls &operator+=(const t *); \ - FORBID_STRING_OPS_2(cls, t) \ - -/* - cls &operator+(t); \ - cls &operator+(const t *); \ -*/ - -#define FORBID_STRING_OPS_AString(t) FORBID_STRING_OPS(AString, t) -#define FORBID_STRING_OPS_UString(t) FORBID_STRING_OPS(UString, t) -#define FORBID_STRING_OPS_UString2(t) FORBID_STRING_OPS(UString2, t) - -class AString -{ - char *_chars; - unsigned _len; - unsigned _limit; - - void MoveItems(unsigned dest, unsigned src) - { - memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char)); - } - - void InsertSpace(unsigned &index, unsigned size); - - void ReAlloc(unsigned newLimit); - void ReAlloc2(unsigned newLimit); - void SetStartLen(unsigned len); - - Z7_NO_INLINE - void Grow_1(); - void Grow(unsigned n); - - AString(unsigned num, const char *s); - AString(unsigned num, const AString &s); - AString(const AString &s, char c); // it's for String + char - AString(const char *s1, unsigned num1, const char *s2, unsigned num2); - - friend AString operator+(const AString &s, char c) { return AString(s, c); } - // friend AString operator+(char c, const AString &s); // is not supported - - friend AString operator+(const AString &s1, const AString &s2); - friend AString operator+(const AString &s1, const char *s2); - friend AString operator+(const char *s1, const AString &s2); - - // ---------- forbidden functions ---------- - - #ifdef MY_NATIVE_WCHAR_T_DEFINED - FORBID_STRING_OPS_AString(wchar_t) - #endif - - FORBID_STRING_OPS_AString(signed char) - FORBID_STRING_OPS_AString(unsigned char) - FORBID_STRING_OPS_AString(short) - FORBID_STRING_OPS_AString(unsigned short) - FORBID_STRING_OPS_AString(int) - FORBID_STRING_OPS_AString(unsigned) - FORBID_STRING_OPS_AString(long) - FORBID_STRING_OPS_AString(unsigned long) - - #ifdef DEBUG_FSTRING_INHERITS_ASTRING - AString(const FString &s); - AString &operator=(const FString &s); - AString &operator+=(const FString &s); - #endif - -public: - explicit AString(); - explicit AString(char c); - explicit AString(const char *s); - AString(const AString &s); - ~AString() { MY_STRING_DELETE(_chars) } - - unsigned Len() const { return _len; } - bool IsEmpty() const { return _len == 0; } - void Empty() { _len = 0; _chars[0] = 0; } - - operator const char *() const { return _chars; } - char *Ptr_non_const() const { return _chars; } - const char *Ptr() const { return _chars; } - const char *Ptr(unsigned pos) const { return _chars + pos; } - const char *Ptr(int pos) const { return _chars + (unsigned)pos; } - const char *RightPtr(unsigned num) const { return _chars + _len - num; } - char Back() const { return _chars[(size_t)_len - 1]; } - - void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; } - - char *GetBuf() { return _chars; } - /* GetBuf(minLen): provides the buffer that can store - at least (minLen) characters and additional null terminator. - 9.35: GetBuf doesn't preserve old characters and terminator */ - char *GetBuf(unsigned minLen) - { - if (minLen > _limit) - ReAlloc2(minLen); - return _chars; - } - char *GetBuf_SetEnd(unsigned minLen) - { - if (minLen > _limit) - ReAlloc2(minLen); - char *chars = _chars; - chars[minLen] = 0; - _len = minLen; - return chars; - } - - void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } - void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } - void ReleaseBuf_CalcLen(unsigned maxLen) - { - char *chars = _chars; - chars[maxLen] = 0; - _len = MyStringLen(chars); - } - - AString &operator=(char c); - AString &operator=(const char *s); - AString &operator=(const AString &s); - void SetFromWStr_if_Ascii(const wchar_t *s); - // void SetFromBstr_if_Ascii(BSTR s); - -// private: - Z7_FORCE_INLINE - AString &operator+=(char c) - { - if (_limit == _len) - Grow_1(); - unsigned len = _len; - char *chars = _chars; - chars[len++] = c; - chars[len] = 0; - _len = len; - return *this; - } -public: - void Add_Space(); - void Add_Space_if_NotEmpty(); - void Add_OptSpaced(const char *s); - void Add_Char(char c); - void Add_LF(); - void Add_Slash(); - void Add_Dot(); - void Add_Minus(); - void Add_Colon(); - void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); } - - AString &operator+=(const char *s); - AString &operator+=(const AString &s); - - void Add_UInt32(UInt32 v); - void Add_UInt64(UInt64 v); - - void AddFrom(const char *s, unsigned len); // no check - void SetFrom(const char *s, unsigned len); // no check - void SetFrom_Chars_SizeT(const char* s, size_t len); // no check - void SetFrom(const char* s, int len) // no check - { - SetFrom(s, (unsigned)len); // no check - } - void SetFrom_CalcLen(const char *s, unsigned len); - - AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } - AString Left(unsigned count) const { return AString(count, *this); } - // void MakeUpper() { MyStringUpper(_chars); } - // void MakeLower() { MyStringLower(_chars); } - void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } - - - bool IsEqualTo(const char *s) const { return strcmp(_chars, s) == 0; } - bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } - // int Compare(const char *s) const { return MyStringCompare(_chars, s); } - // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); } - // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } - // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } - bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } - bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); - - bool IsAscii() const - { - unsigned len = Len(); - const char *s = _chars; - for (unsigned i = 0; i < len; i++) - if ((unsigned char)s[i] >= 0x80) - return false; - return true; - } - int Find(char c) const { return FindCharPosInString(_chars, c); } - int Find(char c, unsigned startIndex) const - { - const int pos = FindCharPosInString(_chars + startIndex, c); - return pos < 0 ? -1 : (int)startIndex + pos; - } - int Find(char c, int startIndex) const - { - return Find(c, (unsigned)startIndex); - } - - int ReverseFind(char c) const throw(); - int ReverseFind_Dot() const throw() { return ReverseFind('.'); } - int ReverseFind_PathSepar() const throw(); - - int Find(const char *s) const { return Find(s, 0); } - int Find(const char *s, unsigned startIndex) const throw(); - - void TrimLeft() throw(); - void TrimRight() throw(); - void Trim() - { - TrimRight(); - TrimLeft(); - } - - void InsertAtFront(char c); - // void Insert(unsigned index, char c); - void Insert(unsigned index, const char *s); - void Insert(unsigned index, const AString &s); - - void RemoveChar(char ch) throw(); - - void Replace(char oldChar, char newChar) throw(); - void Replace(const AString &oldString, const AString &newString); - - void Delete(unsigned index) throw(); - void Delete(unsigned index, unsigned count) throw(); - void DeleteFrontal(unsigned num) throw(); - void DeleteBack() { _chars[--_len] = 0; } - void DeleteFrom(unsigned index) - { - if (index < _len) - { - _len = index; - _chars[index] = 0; - } - } - void DeleteFrom(int index) - { - DeleteFrom((unsigned)index); - } - - - void Wipe_and_Empty() - { - if (_chars) - { - memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); - _len = 0; - } - } -}; - - -class AString_Wipe: public AString -{ - Z7_CLASS_NO_COPY(AString_Wipe) -public: - AString_Wipe(): AString() {} - // AString_Wipe(const AString &s): AString(s) {} - // AString_Wipe &operator=(const AString &s) { AString::operator=(s); return *this; } - // AString_Wipe &operator=(const char *s) { AString::operator=(s); return *this; } - ~AString_Wipe() { Wipe_and_Empty(); } -}; - - -bool operator<(const AString &s1, const AString &s2); -bool operator>(const AString &s1, const AString &s2); - -/* -bool operator==(const AString &s1, const AString &s2); -bool operator==(const AString &s1, const char *s2); -bool operator==(const char *s1, const AString &s2); - -bool operator!=(const AString &s1, const AString &s2); -bool operator!=(const AString &s1, const char *s2); -bool operator!=(const char *s1, const AString &s2); -*/ - -inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; } -inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; } -inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; } - -inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; } -inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; } -inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; } - -// ---------- forbidden functions ---------- - -void operator==(char c1, const AString &s2); -void operator==(const AString &s1, char c2); - -void operator+(char c, const AString &s); // this function can be OK, but we don't use it - -void operator+(const AString &s, int c); -void operator+(const AString &s, unsigned c); -void operator+(int c, const AString &s); -void operator+(unsigned c, const AString &s); -void operator-(const AString &s, int c); -void operator-(const AString &s, unsigned c); - - -class UString -{ - wchar_t *_chars; - unsigned _len; - unsigned _limit; - - void MoveItems(unsigned dest, unsigned src) - { - memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t)); - } - - void InsertSpace(unsigned index, unsigned size); - - void ReAlloc(unsigned newLimit); - void ReAlloc2(unsigned newLimit); - void SetStartLen(unsigned len); - void Grow_1(); - void Grow(unsigned n); - - UString(unsigned num, const wchar_t *s); // for Mid - UString(unsigned num, const UString &s); // for Left - UString(const UString &s, wchar_t c); // it's for String + char - UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2); - - friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } - // friend UString operator+(wchar_t c, const UString &s); // is not supported - - friend UString operator+(const UString &s1, const UString &s2); - friend UString operator+(const UString &s1, const wchar_t *s2); - friend UString operator+(const wchar_t *s1, const UString &s2); - - // ---------- forbidden functions ---------- - - FORBID_STRING_OPS_UString(signed char) - FORBID_STRING_OPS_UString(unsigned char) - FORBID_STRING_OPS_UString(short) - - #ifdef MY_NATIVE_WCHAR_T_DEFINED - FORBID_STRING_OPS_UString(unsigned short) - #endif - - FORBID_STRING_OPS_UString(int) - FORBID_STRING_OPS_UString(unsigned) - FORBID_STRING_OPS_UString(long) - FORBID_STRING_OPS_UString(unsigned long) - - FORBID_STRING_OPS_2(UString, char) - - #ifdef DEBUG_FSTRING_INHERITS_ASTRING - UString(const FString &s); - UString &operator=(const FString &s); - UString &operator+=(const FString &s); - #endif - -public: - UString(); - explicit UString(wchar_t c); - explicit UString(char c); - explicit UString(const char *s); - explicit UString(const AString &s); - UString(const wchar_t *s); - UString(const UString &s); - ~UString() { MY_STRING_DELETE(_chars) } - - unsigned Len() const { return _len; } - bool IsEmpty() const { return _len == 0; } - void Empty() { _len = 0; _chars[0] = 0; } - - operator const wchar_t *() const { return _chars; } - wchar_t *Ptr_non_const() const { return _chars; } - const wchar_t *Ptr() const { return _chars; } - const wchar_t *Ptr(int pos) const { return _chars + (unsigned)pos; } - const wchar_t *Ptr(unsigned pos) const { return _chars + pos; } - const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; } - wchar_t Back() const { return _chars[(size_t)_len - 1]; } - - void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; } - - wchar_t *GetBuf() { return _chars; } - - /* - wchar_t *GetBuf_GetMaxAvail(unsigned &availBufLen) - { - availBufLen = _limit; - return _chars; - } - */ - - wchar_t *GetBuf(unsigned minLen) - { - if (minLen > _limit) - ReAlloc2(minLen); - return _chars; - } - wchar_t *GetBuf_SetEnd(unsigned minLen) - { - if (minLen > _limit) - ReAlloc2(minLen); - wchar_t *chars = _chars; - chars[minLen] = 0; - _len = minLen; - return chars; - } - - void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } - void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } - void ReleaseBuf_CalcLen(unsigned maxLen) - { - wchar_t *chars = _chars; - chars[maxLen] = 0; - _len = MyStringLen(chars); - } - - UString &operator=(wchar_t c); - UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); } - UString &operator=(const wchar_t *s); - UString &operator=(const UString &s); - void SetFrom(const wchar_t *s, unsigned len); // no check - void SetFromBstr(LPCOLESTR s); - UString &operator=(const char *s); - UString &operator=(const AString &s) { return operator=(s.Ptr()); } - -// private: - Z7_FORCE_INLINE - UString &operator+=(wchar_t c) - { - if (_limit == _len) - Grow_1(); - unsigned len = _len; - wchar_t *chars = _chars; - chars[len++] = c; - chars[len] = 0; - _len = len; - return *this; - } - -private: - UString &operator+=(char c); // { return (*this)+=((wchar_t)(unsigned char)c); } -public: - void Add_Char(char c); - // void Add_WChar(wchar_t c); - void Add_Space(); - void Add_Space_if_NotEmpty(); - void Add_LF(); - void Add_Dot(); - void Add_Minus(); - void Add_Colon(); - void Add_PathSepar() { operator+=(WCHAR_PATH_SEPARATOR); } - - UString &operator+=(const wchar_t *s); - UString &operator+=(const UString &s); - UString &operator+=(const char *s); - UString &operator+=(const AString &s) { return operator+=(s.Ptr()); } - - void Add_UInt32(UInt32 v); - void Add_UInt64(UInt64 v); - - UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); } - UString Left(unsigned count) const { return UString(count, *this); } - UString Left(int count) const { return Left((unsigned)count); } - - // void MakeUpper() { MyStringUpper(_chars); } - // void MakeUpper() { MyStringUpper_Ascii(_chars); } - // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); } - void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } - - bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); } - bool IsEqualTo_NoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); } - bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } - int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } - // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); } - // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } - // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } - bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } - bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } - bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); - - bool IsAscii() const - { - unsigned len = Len(); - const wchar_t *s = _chars; - for (unsigned i = 0; i < len; i++) - if (s[i] >= 0x80) - return false; - return true; - } - int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } - int Find(wchar_t c, unsigned startIndex) const - { - int pos = FindCharPosInString(_chars + startIndex, c); - return pos < 0 ? -1 : (int)startIndex + pos; - } - - int ReverseFind(wchar_t c) const throw(); - int ReverseFind_Dot() const throw() { return ReverseFind(L'.'); } - int ReverseFind_PathSepar() const throw(); - - int Find(const wchar_t *s) const { return Find(s, 0); } - int Find(const wchar_t *s, unsigned startIndex) const throw(); - - void TrimLeft() throw(); - void TrimRight() throw(); - void Trim() - { - TrimRight(); - TrimLeft(); - } - - void InsertAtFront(wchar_t c); - // void Insert_wchar_t(unsigned index, wchar_t c); - void Insert(unsigned index, const wchar_t *s); - void Insert(unsigned index, const UString &s); - - void RemoveChar(wchar_t ch) throw(); - - void Replace(wchar_t oldChar, wchar_t newChar) throw(); - void Replace(const UString &oldString, const UString &newString); - - void Delete(int index) throw() { Delete((unsigned)index); } - void Delete(unsigned index) throw(); - void Delete(unsigned index, unsigned count) throw(); - void DeleteFrontal(unsigned num) throw(); - void DeleteBack() { _chars[--_len] = 0; } - void DeleteFrom(int index) { DeleteFrom((unsigned)index); } - void DeleteFrom(unsigned index) - { - if (index < _len) - { - _len = index; - _chars[index] = 0; - } - } - - void Wipe_and_Empty() - { - if (_chars) - { - memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); - _len = 0; - } - } -}; - - -class UString_Wipe: public UString -{ - Z7_CLASS_NO_COPY(UString_Wipe) -public: - UString_Wipe(): UString() {} - // UString_Wipe(const UString &s): UString(s) {} - // UString_Wipe &operator=(const UString &s) { UString::operator=(s); return *this; } - // UString_Wipe &operator=(const wchar_t *s) { UString::operator=(s); return *this; } - ~UString_Wipe() { Wipe_and_Empty(); } -}; - - -bool operator<(const UString &s1, const UString &s2); -bool operator>(const UString &s1, const UString &s2); - -inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; } -inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; } -inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; } - -inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; } -inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; } -inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; } - - -// ---------- forbidden functions ---------- - -void operator==(wchar_t c1, const UString &s2); -void operator==(const UString &s1, wchar_t c2); - -void operator+(wchar_t c, const UString &s); // this function can be OK, but we don't use it - -void operator+(const AString &s1, const UString &s2); -void operator+(const UString &s1, const AString &s2); - -void operator+(const UString &s1, const char *s2); -void operator+(const char *s1, const UString &s2); - -void operator+(const UString &s, char c); -void operator+(const UString &s, unsigned char c); -void operator+(char c, const UString &s); -void operator+(unsigned char c, const UString &s); -void operator-(const UString &s1, wchar_t c); - -#ifdef _WIN32 -// can we forbid these functions, if wchar_t is 32-bit ? -void operator+(const UString &s, int c); -void operator+(const UString &s, unsigned c); -void operator+(int c, const UString &s); -void operator+(unsigned c, const UString &s); -void operator-(const UString &s1, int c); -void operator-(const UString &s1, unsigned c); -#endif - - - - - - - -class UString2 -{ - wchar_t *_chars; - unsigned _len; - - void ReAlloc2(unsigned newLimit); - void SetStartLen(unsigned len); - - // ---------- forbidden functions ---------- - - FORBID_STRING_OPS_UString2(char) - FORBID_STRING_OPS_UString2(signed char) - FORBID_STRING_OPS_UString2(unsigned char) - FORBID_STRING_OPS_UString2(short) - - UString2 &operator=(wchar_t c); - - UString2(const AString &s); - UString2 &operator=(const AString &s); - UString2 &operator+=(const AString &s); - - #ifdef DEBUG_FSTRING_INHERITS_ASTRING - UString2(const FString &s); - UString2 &operator=(const FString &s); - UString2 &operator+=(const FString &s); - #endif - -public: - UString2(): _chars(NULL), _len(0) {} - UString2(const wchar_t *s); - UString2(const UString2 &s); - ~UString2() { if (_chars) { MY_STRING_DELETE(_chars) } } - - unsigned Len() const { return _len; } - bool IsEmpty() const { return _len == 0; } - // void Empty() { _len = 0; _chars[0] = 0; } - - // operator const wchar_t *() const { return _chars; } - const wchar_t *GetRawPtr() const { return _chars; } - - int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } - - wchar_t *GetBuf(unsigned minLen) - { - if (!_chars || minLen > _len) - ReAlloc2(minLen); - return _chars; - } - void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } - - UString2 &operator=(const wchar_t *s); - UString2 &operator=(const UString2 &s); - void SetFromAscii(const char *s); -}; - -bool operator==(const UString2 &s1, const UString2 &s2); -bool operator==(const UString2 &s1, const wchar_t *s2); -bool operator==(const wchar_t *s1, const UString2 &s2); - -inline bool operator!=(const UString2 &s1, const UString2 &s2) { return !(s1 == s2); } -inline bool operator!=(const UString2 &s1, const wchar_t *s2) { return !(s1 == s2); } -inline bool operator!=(const wchar_t *s1, const UString2 &s2) { return !(s1 == s2); } - - -// ---------- forbidden functions ---------- - -void operator==(wchar_t c1, const UString2 &s2); -void operator==(const UString2 &s1, wchar_t c2); -bool operator<(const UString2 &s1, const UString2 &s2); -bool operator>(const UString2 &s1, const UString2 &s2); - -void operator+(const UString2 &s1, const UString2 &s2); -void operator+(const UString2 &s1, const wchar_t *s2); -void operator+(const wchar_t *s1, const UString2 &s2); -void operator+(wchar_t c, const UString2 &s); -void operator+(const UString2 &s, wchar_t c); -void operator+(const UString2 &s, char c); -void operator+(const UString2 &s, unsigned char c); -void operator+(char c, const UString2 &s); -void operator+(unsigned char c, const UString2 &s); -void operator-(const UString2 &s1, wchar_t c); - - - - - - -typedef CObjectVector AStringVector; -typedef CObjectVector UStringVector; - -#ifdef _UNICODE - typedef UString CSysString; -#else - typedef AString CSysString; -#endif - -typedef CObjectVector CSysStringVector; - - -// ---------- FString ---------- - -#ifndef DEBUG_FSTRING_INHERITS_ASTRING -#ifdef _WIN32 - #define USE_UNICODE_FSTRING -#endif -#endif - -#ifdef USE_UNICODE_FSTRING - - #define MY_FTEXT(quote) L##quote - - typedef wchar_t FChar; - typedef UString FString; - - #define fs2us(_x_) (_x_) - #define us2fs(_x_) (_x_) - FString fas2fs(const char *s); - FString fas2fs(const AString &s); - AString fs2fas(const FChar *s); - -#else // USE_UNICODE_FSTRING - - #define MY_FTEXT(quote) quote - - typedef char FChar; - - #ifdef DEBUG_FSTRING_INHERITS_ASTRING - - class FString: public AString - { - // FString &operator=(const char *s); - FString &operator=(const AString &s); - // FString &operator+=(const AString &s); - public: - FString(const AString &s): AString(s.Ptr()) {} - FString(const FString &s): AString(s.Ptr()) {} - FString(const char *s): AString(s) {} - FString() {} - FString &operator=(const FString &s) { AString::operator=((const AString &)s); return *this; } - FString &operator=(char c) { AString::operator=(c); return *this; } - FString &operator+=(char c) { AString::operator+=(c); return *this; } - FString &operator+=(const FString &s) { AString::operator+=((const AString &)s); return *this; } - FString Left(unsigned count) const { return FString(AString::Left(count)); } - }; - void operator+(const AString &s1, const FString &s2); - void operator+(const FString &s1, const AString &s2); - - inline FString operator+(const FString &s1, const FString &s2) - { - AString s =(const AString &)s1 + (const AString &)s2; - return FString(s.Ptr()); - // return FString((const AString &)s1 + (const AString &)s2); - } - inline FString operator+(const FString &s1, const FChar *s2) - { - return s1 + (FString)s2; - } - /* - inline FString operator+(const FChar *s1, const FString &s2) - { - return (FString)s1 + s2; - } - */ - - inline FString fas2fs(const char *s) { return FString(s); } - - #else // DEBUG_FSTRING_INHERITS_ASTRING - typedef AString FString; - #define fas2fs(_x_) (_x_) - #endif // DEBUG_FSTRING_INHERITS_ASTRING - - UString fs2us(const FChar *s); - UString fs2us(const FString &s); - FString us2fs(const wchar_t *s); - #define fs2fas(_x_) (_x_) - -#endif // USE_UNICODE_FSTRING - -#define FTEXT(quote) MY_FTEXT(quote) - -#define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR) -#define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR) - -// #define FCHAR_ANY_MASK FTEXT('*') -// #define FSTRING_ANY_MASK FTEXT("*") - -typedef const FChar *CFSTR; - -typedef CObjectVector FStringVector; - - -class CStringFinder -{ - AString _temp; -public: - // list - is list of low case Ascii strings separated by space " ". - // the function returns true, if it can find exact word (str) in (list). - bool FindWord_In_LowCaseAsciiList_NoCase(const char *list, const wchar_t *str); -}; - -void SplitString(const UString &srcString, UStringVector &destStrings); - -#endif - - - -#if defined(_WIN32) - // #include - // WCHAR_MAX is defined as ((wchar_t)-1) - #define Z7_WCHART_IS_16BIT 1 -#elif (defined(WCHAR_MAX) && (WCHAR_MAX <= 0xffff)) \ - || (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ == 2)) - #define Z7_WCHART_IS_16BIT 1 -#endif - -#if WCHAR_PATH_SEPARATOR == L'\\' -// WSL scheme -#define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT ((wchar_t)((unsigned)(0xF000) + (unsigned)'\\')) -// #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT '_' -#endif +// Common/MyString.h + +#ifndef ZIP7_INC_COMMON_MY_STRING_H +#define ZIP7_INC_COMMON_MY_STRING_H + +#include + +#ifndef _WIN32 +#include +#include +#endif + +#include "Common.h" +#include "MyWindows.h" +#include "MyTypes.h" +#include "MyVector.h" + + +/* if (DEBUG_FSTRING_INHERITS_ASTRING is defined), then + FString inherits from AString, so we can find bugs related to FString at compile time. + DON'T define DEBUG_FSTRING_INHERITS_ASTRING in release code */ + +// #define DEBUG_FSTRING_INHERITS_ASTRING + +#ifdef DEBUG_FSTRING_INHERITS_ASTRING +class FString; +#endif + + +#ifdef _MSC_VER + #ifdef _NATIVE_WCHAR_T_DEFINED + #define MY_NATIVE_WCHAR_T_DEFINED + #endif +#else + #define MY_NATIVE_WCHAR_T_DEFINED +#endif + +/* + native support for wchar_t: + _MSC_VER == 1600 : /Zc:wchar_t is not supported + _MSC_VER == 1310 (VS2003) + ? _MSC_VER == 1400 (VS2005) : wchar_t <- unsigned short + /Zc:wchar_t : wchar_t <- __wchar_t, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED + _MSC_VER > 1400 (VS2008+) + /Zc:wchar_t[-] + /Zc:wchar_t is on by default +*/ + +#ifdef _WIN32 +#define IS_PATH_SEPAR(c) ((c) == '\\' || (c) == '/') +#else +#define IS_PATH_SEPAR(c) ((c) == CHAR_PATH_SEPARATOR) +#endif + +inline bool IsPathSepar(char c) { return IS_PATH_SEPAR(c); } +inline bool IsPathSepar(wchar_t c) { return IS_PATH_SEPAR(c); } + +inline unsigned MyStringLen(const char *s) +{ + unsigned i; + for (i = 0; s[i] != 0; i++); + return i; +} + +inline void MyStringCopy(char *dest, const char *src) +{ + while ((*dest++ = *src++) != 0); +} + +inline char *MyStpCpy(char *dest, const char *src) +{ + for (;;) + { + const char c = *src; + *dest = c; + if (c == 0) + return dest; + src++; + dest++; + } +} + +inline void MyStringCat(char *dest, const char *src) +{ + for (; *dest != 0; dest++); + while ((*dest++ = *src++) != 0); + // MyStringCopy(dest + MyStringLen(dest), src); +} + +inline unsigned MyStringLen(const wchar_t *s) +{ + unsigned i; + for (i = 0; s[i] != 0; i++); + return i; +} + +inline void MyStringCopy(wchar_t *dest, const wchar_t *src) +{ + while ((*dest++ = *src++) != 0); +} + +inline void MyStringCat(wchar_t *dest, const wchar_t *src) +{ + for (; *dest != 0; dest++); + while ((*dest++ = *src++) != 0); + // MyStringCopy(dest + MyStringLen(dest), src); +} + + +/* +inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src) +{ + for (;;) + { + const wchar_t c = *src; + *dest = c; + if (c == 0) + return dest; + src++; + dest++; + } +} +*/ + +int FindCharPosInString(const char *s, char c) throw(); +int FindCharPosInString(const wchar_t *s, wchar_t c) throw(); + +#ifdef _WIN32 + #ifndef _UNICODE + #define STRING_UNICODE_THROW + #endif +#endif + +#ifndef STRING_UNICODE_THROW + #define STRING_UNICODE_THROW throw() +#endif + + +inline char MyCharUpper_Ascii(char c) +{ + if (c >= 'a' && c <= 'z') + return (char)((unsigned char)c - 0x20); + return c; +} + +/* +inline wchar_t MyCharUpper_Ascii(wchar_t c) +{ + if (c >= 'a' && c <= 'z') + return (wchar_t)(c - 0x20); + return c; +} +*/ + +inline char MyCharLower_Ascii(char c) +{ + if (c >= 'A' && c <= 'Z') + return (char)((unsigned char)c + 0x20); + return c; +} + +inline wchar_t MyCharLower_Ascii(wchar_t c) +{ + if (c >= 'A' && c <= 'Z') + return (wchar_t)(c + 0x20); + return c; +} + +wchar_t MyCharUpper_WIN(wchar_t c) throw(); + +inline wchar_t MyCharUpper(wchar_t c) throw() +{ + if (c < 'a') return c; + if (c <= 'z') return (wchar_t)(c - 0x20); + if (c <= 0x7F) return c; + #ifdef _WIN32 + #ifdef _UNICODE + return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); + #else + return (wchar_t)MyCharUpper_WIN(c); + #endif + #else + return (wchar_t)towupper((wint_t)c); + #endif +} + +/* +wchar_t MyCharLower_WIN(wchar_t c) throw(); + +inline wchar_t MyCharLower(wchar_t c) throw() +{ + if (c < 'A') return c; + if (c <= 'Z') return (wchar_t)(c + 0x20); + if (c <= 0x7F) return c; + #ifdef _WIN32 + #ifdef _UNICODE + return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); + #else + return (wchar_t)MyCharLower_WIN(c); + #endif + #else + return (wchar_t)tolower(c); + #endif +} +*/ + +// char *MyStringUpper(char *s) throw(); +// char *MyStringLower(char *s) throw(); + +// void MyStringUpper_Ascii(char *s) throw(); +// void MyStringUpper_Ascii(wchar_t *s) throw(); +void MyStringLower_Ascii(char *s) throw(); +void MyStringLower_Ascii(wchar_t *s) throw(); +// wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW; +// wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW; + +bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw(); + +bool IsString1PrefixedByString2(const char *s1, const char *s2) throw(); +bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw(); +bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw(); +bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw(); +bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *u, const char *a) throw(); +bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw(); + +#define MyStringCompare(s1, s2) wcscmp(s1, s2) +int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw(); +// int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw(); + +// ---------- ASCII ---------- +// char values in ASCII strings must be less then 128 +bool StringsAreEqual_Ascii(const char *u, const char *a) throw(); +bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw(); +bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw(); +bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw(); +bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw(); + +#define MY_STRING_DELETE(_p_) { delete [](_p_); } +// #define MY_STRING_DELETE(_p_) my_delete(_p_); + + +#define FORBID_STRING_OPS_2(cls, t) \ + void Find(t) const; \ + void Find(t, unsigned startIndex) const; \ + void ReverseFind(t) const; \ + void InsertAtFront(t); \ + void RemoveChar(t); \ + void Replace(t, t); \ + +#define FORBID_STRING_OPS(cls, t) \ + explicit cls(t); \ + explicit cls(const t *); \ + cls &operator=(t); \ + cls &operator=(const t *); \ + cls &operator+=(t); \ + cls &operator+=(const t *); \ + FORBID_STRING_OPS_2(cls, t) \ + +/* + cls &operator+(t); \ + cls &operator+(const t *); \ +*/ + +#define FORBID_STRING_OPS_AString(t) FORBID_STRING_OPS(AString, t) +#define FORBID_STRING_OPS_UString(t) FORBID_STRING_OPS(UString, t) +#define FORBID_STRING_OPS_UString2(t) FORBID_STRING_OPS(UString2, t) + +class AString +{ + char *_chars; + unsigned _len; + unsigned _limit; + + void MoveItems(unsigned dest, unsigned src) + { + memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char)); + } + + void InsertSpace(unsigned &index, unsigned size); + + void ReAlloc(unsigned newLimit); + void ReAlloc2(unsigned newLimit); + void SetStartLen(unsigned len); + + Z7_NO_INLINE + void Grow_1(); + void Grow(unsigned n); + + AString(unsigned num, const char *s); + AString(unsigned num, const AString &s); + AString(const AString &s, char c); // it's for String + char + AString(const char *s1, unsigned num1, const char *s2, unsigned num2); + + friend AString operator+(const AString &s, char c) { return AString(s, c); } + // friend AString operator+(char c, const AString &s); // is not supported + + friend AString operator+(const AString &s1, const AString &s2); + friend AString operator+(const AString &s1, const char *s2); + friend AString operator+(const char *s1, const AString &s2); + + // ---------- forbidden functions ---------- + + #ifdef MY_NATIVE_WCHAR_T_DEFINED + FORBID_STRING_OPS_AString(wchar_t) + #endif + + FORBID_STRING_OPS_AString(signed char) + FORBID_STRING_OPS_AString(unsigned char) + FORBID_STRING_OPS_AString(short) + FORBID_STRING_OPS_AString(unsigned short) + FORBID_STRING_OPS_AString(int) + FORBID_STRING_OPS_AString(unsigned) + FORBID_STRING_OPS_AString(long) + FORBID_STRING_OPS_AString(unsigned long) + + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + AString(const FString &s); + AString &operator=(const FString &s); + AString &operator+=(const FString &s); + #endif + +public: + explicit AString(); + explicit AString(char c); + explicit AString(const char *s); + AString(const AString &s); + ~AString() { MY_STRING_DELETE(_chars) } + + unsigned Len() const { return _len; } + bool IsEmpty() const { return _len == 0; } + void Empty() { _len = 0; _chars[0] = 0; } + + operator const char *() const { return _chars; } + char *Ptr_non_const() const { return _chars; } + const char *Ptr() const { return _chars; } + const char *Ptr(unsigned pos) const { return _chars + pos; } + const char *Ptr(int pos) const { return _chars + (unsigned)pos; } + const char *RightPtr(unsigned num) const { return _chars + _len - num; } + char Back() const { return _chars[(size_t)_len - 1]; } + + void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; } + + char *GetBuf() { return _chars; } + /* GetBuf(minLen): provides the buffer that can store + at least (minLen) characters and additional null terminator. + 9.35: GetBuf doesn't preserve old characters and terminator */ + char *GetBuf(unsigned minLen) + { + if (minLen > _limit) + ReAlloc2(minLen); + return _chars; + } + char *GetBuf_SetEnd(unsigned minLen) + { + if (minLen > _limit) + ReAlloc2(minLen); + char *chars = _chars; + chars[minLen] = 0; + _len = minLen; + return chars; + } + + void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } + void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } + void ReleaseBuf_CalcLen(unsigned maxLen) + { + char *chars = _chars; + chars[maxLen] = 0; + _len = MyStringLen(chars); + } + + AString &operator=(char c); + AString &operator=(const char *s); + AString &operator=(const AString &s); + void SetFromWStr_if_Ascii(const wchar_t *s); + // void SetFromBstr_if_Ascii(BSTR s); + +// private: + Z7_FORCE_INLINE + AString &operator+=(char c) + { + if (_limit == _len) + Grow_1(); + unsigned len = _len; + char *chars = _chars; + chars[len++] = c; + chars[len] = 0; + _len = len; + return *this; + } +public: + void Add_Space(); + void Add_Space_if_NotEmpty(); + void Add_OptSpaced(const char *s); + void Add_Char(char c); + void Add_LF(); + void Add_Slash(); + void Add_Dot(); + void Add_Minus(); + void Add_Colon(); + void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); } + + AString &operator+=(const char *s); + AString &operator+=(const AString &s); + + void Add_UInt32(UInt32 v); + void Add_UInt64(UInt64 v); + + void AddFrom(const char *s, unsigned len); // no check + void SetFrom(const char *s, unsigned len); // no check + void SetFrom_Chars_SizeT(const char* s, size_t len); // no check + void SetFrom(const char* s, int len) // no check + { + SetFrom(s, (unsigned)len); // no check + } + void SetFrom_CalcLen(const char *s, unsigned len); + + AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } + AString Left(unsigned count) const { return AString(count, *this); } + // void MakeUpper() { MyStringUpper(_chars); } + // void MakeLower() { MyStringLower(_chars); } + void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } + + + bool IsEqualTo(const char *s) const { return strcmp(_chars, s) == 0; } + bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } + // int Compare(const char *s) const { return MyStringCompare(_chars, s); } + // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); } + // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } + // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } + bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } + bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); + + bool IsAscii() const + { + unsigned len = Len(); + const char *s = _chars; + for (unsigned i = 0; i < len; i++) + if ((unsigned char)s[i] >= 0x80) + return false; + return true; + } + int Find(char c) const { return FindCharPosInString(_chars, c); } + int Find(char c, unsigned startIndex) const + { + const int pos = FindCharPosInString(_chars + startIndex, c); + return pos < 0 ? -1 : (int)startIndex + pos; + } + int Find(char c, int startIndex) const + { + return Find(c, (unsigned)startIndex); + } + + int ReverseFind(char c) const throw(); + int ReverseFind_Dot() const throw() { return ReverseFind('.'); } + int ReverseFind_PathSepar() const throw(); + + int Find(const char *s) const { return Find(s, 0); } + int Find(const char *s, unsigned startIndex) const throw(); + + void TrimLeft() throw(); + void TrimRight() throw(); + void Trim() + { + TrimRight(); + TrimLeft(); + } + + void InsertAtFront(char c); + // void Insert(unsigned index, char c); + void Insert(unsigned index, const char *s); + void Insert(unsigned index, const AString &s); + + void RemoveChar(char ch) throw(); + + void Replace(char oldChar, char newChar) throw(); + void Replace(const AString &oldString, const AString &newString); + + void Delete(unsigned index) throw(); + void Delete(unsigned index, unsigned count) throw(); + void DeleteFrontal(unsigned num) throw(); + void DeleteBack() { _chars[--_len] = 0; } + void DeleteFrom(unsigned index) + { + if (index < _len) + { + _len = index; + _chars[index] = 0; + } + } + void DeleteFrom(int index) + { + DeleteFrom((unsigned)index); + } + + + void Wipe_and_Empty() + { + if (_chars) + { + memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); + _len = 0; + } + } +}; + + +class AString_Wipe: public AString +{ + Z7_CLASS_NO_COPY(AString_Wipe) +public: + AString_Wipe(): AString() {} + // AString_Wipe(const AString &s): AString(s) {} + // AString_Wipe &operator=(const AString &s) { AString::operator=(s); return *this; } + // AString_Wipe &operator=(const char *s) { AString::operator=(s); return *this; } + ~AString_Wipe() { Wipe_and_Empty(); } +}; + + +bool operator<(const AString &s1, const AString &s2); +bool operator>(const AString &s1, const AString &s2); + +/* +bool operator==(const AString &s1, const AString &s2); +bool operator==(const AString &s1, const char *s2); +bool operator==(const char *s1, const AString &s2); + +bool operator!=(const AString &s1, const AString &s2); +bool operator!=(const AString &s1, const char *s2); +bool operator!=(const char *s1, const AString &s2); +*/ + +inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; } +inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; } +inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; } + +inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; } +inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; } +inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; } + +// ---------- forbidden functions ---------- + +void operator==(char c1, const AString &s2); +void operator==(const AString &s1, char c2); + +void operator+(char c, const AString &s); // this function can be OK, but we don't use it + +void operator+(const AString &s, int c); +void operator+(const AString &s, unsigned c); +void operator+(int c, const AString &s); +void operator+(unsigned c, const AString &s); +void operator-(const AString &s, int c); +void operator-(const AString &s, unsigned c); + + +class UString +{ + wchar_t *_chars; + unsigned _len; + unsigned _limit; + + void MoveItems(unsigned dest, unsigned src) + { + memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t)); + } + + void InsertSpace(unsigned index, unsigned size); + + void ReAlloc(unsigned newLimit); + void ReAlloc2(unsigned newLimit); + void SetStartLen(unsigned len); + void Grow_1(); + void Grow(unsigned n); + + UString(unsigned num, const wchar_t *s); // for Mid + UString(unsigned num, const UString &s); // for Left + UString(const UString &s, wchar_t c); // it's for String + char + UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2); + + friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } + // friend UString operator+(wchar_t c, const UString &s); // is not supported + + friend UString operator+(const UString &s1, const UString &s2); + friend UString operator+(const UString &s1, const wchar_t *s2); + friend UString operator+(const wchar_t *s1, const UString &s2); + + // ---------- forbidden functions ---------- + + FORBID_STRING_OPS_UString(signed char) + FORBID_STRING_OPS_UString(unsigned char) + FORBID_STRING_OPS_UString(short) + + #ifdef MY_NATIVE_WCHAR_T_DEFINED + FORBID_STRING_OPS_UString(unsigned short) + #endif + + FORBID_STRING_OPS_UString(int) + FORBID_STRING_OPS_UString(unsigned) + FORBID_STRING_OPS_UString(long) + FORBID_STRING_OPS_UString(unsigned long) + + FORBID_STRING_OPS_2(UString, char) + + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + UString(const FString &s); + UString &operator=(const FString &s); + UString &operator+=(const FString &s); + #endif + +public: + UString(); + explicit UString(wchar_t c); + explicit UString(char c); + explicit UString(const char *s); + explicit UString(const AString &s); + UString(const wchar_t *s); + UString(const UString &s); + ~UString() { MY_STRING_DELETE(_chars) } + + unsigned Len() const { return _len; } + bool IsEmpty() const { return _len == 0; } + void Empty() { _len = 0; _chars[0] = 0; } + + operator const wchar_t *() const { return _chars; } + wchar_t *Ptr_non_const() const { return _chars; } + const wchar_t *Ptr() const { return _chars; } + const wchar_t *Ptr(int pos) const { return _chars + (unsigned)pos; } + const wchar_t *Ptr(unsigned pos) const { return _chars + pos; } + const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; } + wchar_t Back() const { return _chars[(size_t)_len - 1]; } + + void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; } + + wchar_t *GetBuf() { return _chars; } + + /* + wchar_t *GetBuf_GetMaxAvail(unsigned &availBufLen) + { + availBufLen = _limit; + return _chars; + } + */ + + wchar_t *GetBuf(unsigned minLen) + { + if (minLen > _limit) + ReAlloc2(minLen); + return _chars; + } + wchar_t *GetBuf_SetEnd(unsigned minLen) + { + if (minLen > _limit) + ReAlloc2(minLen); + wchar_t *chars = _chars; + chars[minLen] = 0; + _len = minLen; + return chars; + } + + void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } + void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } + void ReleaseBuf_CalcLen(unsigned maxLen) + { + wchar_t *chars = _chars; + chars[maxLen] = 0; + _len = MyStringLen(chars); + } + + UString &operator=(wchar_t c); + UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); } + UString &operator=(const wchar_t *s); + UString &operator=(const UString &s); + void SetFrom(const wchar_t *s, unsigned len); // no check + void SetFromBstr(LPCOLESTR s); + UString &operator=(const char *s); + UString &operator=(const AString &s) { return operator=(s.Ptr()); } + +// private: + Z7_FORCE_INLINE + UString &operator+=(wchar_t c) + { + if (_limit == _len) + Grow_1(); + unsigned len = _len; + wchar_t *chars = _chars; + chars[len++] = c; + chars[len] = 0; + _len = len; + return *this; + } + +private: + UString &operator+=(char c); // { return (*this)+=((wchar_t)(unsigned char)c); } +public: + void Add_Char(char c); + // void Add_WChar(wchar_t c); + void Add_Space(); + void Add_Space_if_NotEmpty(); + void Add_LF(); + void Add_Dot(); + void Add_Minus(); + void Add_Colon(); + void Add_PathSepar() { operator+=(WCHAR_PATH_SEPARATOR); } + + UString &operator+=(const wchar_t *s); + UString &operator+=(const UString &s); + UString &operator+=(const char *s); + UString &operator+=(const AString &s) { return operator+=(s.Ptr()); } + + void Add_UInt32(UInt32 v); + void Add_UInt64(UInt64 v); + + UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); } + UString Left(unsigned count) const { return UString(count, *this); } + UString Left(int count) const { return Left((unsigned)count); } + + // void MakeUpper() { MyStringUpper(_chars); } + // void MakeUpper() { MyStringUpper_Ascii(_chars); } + // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); } + void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } + + bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); } + bool IsEqualTo_NoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); } + bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } + int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } + // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); } + // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } + // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } + bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } + bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } + bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); + + bool IsAscii() const + { + unsigned len = Len(); + const wchar_t *s = _chars; + for (unsigned i = 0; i < len; i++) + if (s[i] >= 0x80) + return false; + return true; + } + int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } + int Find(wchar_t c, unsigned startIndex) const + { + int pos = FindCharPosInString(_chars + startIndex, c); + return pos < 0 ? -1 : (int)startIndex + pos; + } + + int ReverseFind(wchar_t c) const throw(); + int ReverseFind_Dot() const throw() { return ReverseFind(L'.'); } + int ReverseFind_PathSepar() const throw(); + + int Find(const wchar_t *s) const { return Find(s, 0); } + int Find(const wchar_t *s, unsigned startIndex) const throw(); + + void TrimLeft() throw(); + void TrimRight() throw(); + void Trim() + { + TrimRight(); + TrimLeft(); + } + + void InsertAtFront(wchar_t c); + // void Insert_wchar_t(unsigned index, wchar_t c); + void Insert(unsigned index, const wchar_t *s); + void Insert(unsigned index, const UString &s); + + void RemoveChar(wchar_t ch) throw(); + + void Replace(wchar_t oldChar, wchar_t newChar) throw(); + void Replace(const UString &oldString, const UString &newString); + + void Delete(int index) throw() { Delete((unsigned)index); } + void Delete(unsigned index) throw(); + void Delete(unsigned index, unsigned count) throw(); + void DeleteFrontal(unsigned num) throw(); + void DeleteBack() { _chars[--_len] = 0; } + void DeleteFrom(int index) { DeleteFrom((unsigned)index); } + void DeleteFrom(unsigned index) + { + if (index < _len) + { + _len = index; + _chars[index] = 0; + } + } + + void Wipe_and_Empty() + { + if (_chars) + { + memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); + _len = 0; + } + } +}; + + +class UString_Wipe: public UString +{ + Z7_CLASS_NO_COPY(UString_Wipe) +public: + UString_Wipe(): UString() {} + // UString_Wipe(const UString &s): UString(s) {} + // UString_Wipe &operator=(const UString &s) { UString::operator=(s); return *this; } + // UString_Wipe &operator=(const wchar_t *s) { UString::operator=(s); return *this; } + ~UString_Wipe() { Wipe_and_Empty(); } +}; + + +bool operator<(const UString &s1, const UString &s2); +bool operator>(const UString &s1, const UString &s2); + +inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; } +inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; } +inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; } + +inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; } +inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; } +inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; } + + +// ---------- forbidden functions ---------- + +void operator==(wchar_t c1, const UString &s2); +void operator==(const UString &s1, wchar_t c2); + +void operator+(wchar_t c, const UString &s); // this function can be OK, but we don't use it + +void operator+(const AString &s1, const UString &s2); +void operator+(const UString &s1, const AString &s2); + +void operator+(const UString &s1, const char *s2); +void operator+(const char *s1, const UString &s2); + +void operator+(const UString &s, char c); +void operator+(const UString &s, unsigned char c); +void operator+(char c, const UString &s); +void operator+(unsigned char c, const UString &s); +void operator-(const UString &s1, wchar_t c); + +#ifdef _WIN32 +// can we forbid these functions, if wchar_t is 32-bit ? +void operator+(const UString &s, int c); +void operator+(const UString &s, unsigned c); +void operator+(int c, const UString &s); +void operator+(unsigned c, const UString &s); +void operator-(const UString &s1, int c); +void operator-(const UString &s1, unsigned c); +#endif + + + + + + + +class UString2 +{ + wchar_t *_chars; + unsigned _len; + + void ReAlloc2(unsigned newLimit); + void SetStartLen(unsigned len); + + // ---------- forbidden functions ---------- + + FORBID_STRING_OPS_UString2(char) + FORBID_STRING_OPS_UString2(signed char) + FORBID_STRING_OPS_UString2(unsigned char) + FORBID_STRING_OPS_UString2(short) + + UString2 &operator=(wchar_t c); + + UString2(const AString &s); + UString2 &operator=(const AString &s); + UString2 &operator+=(const AString &s); + + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + UString2(const FString &s); + UString2 &operator=(const FString &s); + UString2 &operator+=(const FString &s); + #endif + +public: + UString2(): _chars(NULL), _len(0) {} + UString2(const wchar_t *s); + UString2(const UString2 &s); + ~UString2() { if (_chars) { MY_STRING_DELETE(_chars) } } + + unsigned Len() const { return _len; } + bool IsEmpty() const { return _len == 0; } + // void Empty() { _len = 0; _chars[0] = 0; } + + // operator const wchar_t *() const { return _chars; } + const wchar_t *GetRawPtr() const { return _chars; } + + int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } + + wchar_t *GetBuf(unsigned minLen) + { + if (!_chars || minLen > _len) + ReAlloc2(minLen); + return _chars; + } + void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } + + UString2 &operator=(const wchar_t *s); + UString2 &operator=(const UString2 &s); + void SetFromAscii(const char *s); +}; + +bool operator==(const UString2 &s1, const UString2 &s2); +bool operator==(const UString2 &s1, const wchar_t *s2); +bool operator==(const wchar_t *s1, const UString2 &s2); + +inline bool operator!=(const UString2 &s1, const UString2 &s2) { return !(s1 == s2); } +inline bool operator!=(const UString2 &s1, const wchar_t *s2) { return !(s1 == s2); } +inline bool operator!=(const wchar_t *s1, const UString2 &s2) { return !(s1 == s2); } + + +// ---------- forbidden functions ---------- + +void operator==(wchar_t c1, const UString2 &s2); +void operator==(const UString2 &s1, wchar_t c2); +bool operator<(const UString2 &s1, const UString2 &s2); +bool operator>(const UString2 &s1, const UString2 &s2); + +void operator+(const UString2 &s1, const UString2 &s2); +void operator+(const UString2 &s1, const wchar_t *s2); +void operator+(const wchar_t *s1, const UString2 &s2); +void operator+(wchar_t c, const UString2 &s); +void operator+(const UString2 &s, wchar_t c); +void operator+(const UString2 &s, char c); +void operator+(const UString2 &s, unsigned char c); +void operator+(char c, const UString2 &s); +void operator+(unsigned char c, const UString2 &s); +void operator-(const UString2 &s1, wchar_t c); + + + + + + +typedef CObjectVector AStringVector; +typedef CObjectVector UStringVector; + +#ifdef _UNICODE + typedef UString CSysString; +#else + typedef AString CSysString; +#endif + +typedef CObjectVector CSysStringVector; + + +// ---------- FString ---------- + +#ifndef DEBUG_FSTRING_INHERITS_ASTRING +#ifdef _WIN32 + #define USE_UNICODE_FSTRING +#endif +#endif + +#ifdef USE_UNICODE_FSTRING + + #define MY_FTEXT(quote) L##quote + + typedef wchar_t FChar; + typedef UString FString; + + #define fs2us(_x_) (_x_) + #define us2fs(_x_) (_x_) + FString fas2fs(const char *s); + FString fas2fs(const AString &s); + AString fs2fas(const FChar *s); + +#else // USE_UNICODE_FSTRING + + #define MY_FTEXT(quote) quote + + typedef char FChar; + + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + + class FString: public AString + { + // FString &operator=(const char *s); + FString &operator=(const AString &s); + // FString &operator+=(const AString &s); + public: + FString(const AString &s): AString(s.Ptr()) {} + FString(const FString &s): AString(s.Ptr()) {} + FString(const char *s): AString(s) {} + FString() {} + FString &operator=(const FString &s) { AString::operator=((const AString &)s); return *this; } + FString &operator=(char c) { AString::operator=(c); return *this; } + FString &operator+=(char c) { AString::operator+=(c); return *this; } + FString &operator+=(const FString &s) { AString::operator+=((const AString &)s); return *this; } + FString Left(unsigned count) const { return FString(AString::Left(count)); } + }; + void operator+(const AString &s1, const FString &s2); + void operator+(const FString &s1, const AString &s2); + + inline FString operator+(const FString &s1, const FString &s2) + { + AString s =(const AString &)s1 + (const AString &)s2; + return FString(s.Ptr()); + // return FString((const AString &)s1 + (const AString &)s2); + } + inline FString operator+(const FString &s1, const FChar *s2) + { + return s1 + (FString)s2; + } + /* + inline FString operator+(const FChar *s1, const FString &s2) + { + return (FString)s1 + s2; + } + */ + + inline FString fas2fs(const char *s) { return FString(s); } + + #else // DEBUG_FSTRING_INHERITS_ASTRING + typedef AString FString; + #define fas2fs(_x_) (_x_) + #endif // DEBUG_FSTRING_INHERITS_ASTRING + + UString fs2us(const FChar *s); + UString fs2us(const FString &s); + FString us2fs(const wchar_t *s); + #define fs2fas(_x_) (_x_) + +#endif // USE_UNICODE_FSTRING + +#define FTEXT(quote) MY_FTEXT(quote) + +#define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR) +#define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR) + +// #define FCHAR_ANY_MASK FTEXT('*') +// #define FSTRING_ANY_MASK FTEXT("*") + +typedef const FChar *CFSTR; + +typedef CObjectVector FStringVector; + + +class CStringFinder +{ + AString _temp; +public: + // list - is list of low case Ascii strings separated by space " ". + // the function returns true, if it can find exact word (str) in (list). + bool FindWord_In_LowCaseAsciiList_NoCase(const char *list, const wchar_t *str); +}; + +void SplitString(const UString &srcString, UStringVector &destStrings); + +#endif + + + +#if defined(_WIN32) + // #include + // WCHAR_MAX is defined as ((wchar_t)-1) + #define Z7_WCHART_IS_16BIT 1 +#elif (defined(WCHAR_MAX) && (WCHAR_MAX <= 0xffff)) \ + || (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ == 2)) + #define Z7_WCHART_IS_16BIT 1 +#endif + +#if WCHAR_PATH_SEPARATOR == L'\\' +// WSL scheme +#define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT ((wchar_t)((unsigned)(0xF000) + (unsigned)'\\')) +// #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT '_' +#endif diff --git a/CPP/Common/MyTypes.h b/CPP/Common/MyTypes.h index a94d47509..eadc9a4d1 100644 --- a/CPP/Common/MyTypes.h +++ b/CPP/Common/MyTypes.h @@ -1,38 +1,38 @@ -// Common/MyTypes.h - -#ifndef ZIP7_INC_COMMON_MY_TYPES_H -#define ZIP7_INC_COMMON_MY_TYPES_H - -#include "Common0.h" -#include "../../C/7zTypes.h" - -// typedef int HRes; -// typedef HRESULT HRes; - -struct CBoolPair -{ - bool Val; - bool Def; - - CBoolPair(): Val(false), Def(false) {} - - void Init() - { - Val = false; - Def = false; - } - - void SetTrueTrue() - { - Val = true; - Def = true; - } - - void SetVal_as_Defined(bool val) - { - Val = val; - Def = true; - } -}; - -#endif +// Common/MyTypes.h + +#ifndef ZIP7_INC_COMMON_MY_TYPES_H +#define ZIP7_INC_COMMON_MY_TYPES_H + +#include "Common0.h" +#include "../../C/7zTypes.h" + +// typedef int HRes; +// typedef HRESULT HRes; + +struct CBoolPair +{ + bool Val; + bool Def; + + CBoolPair(): Val(false), Def(false) {} + + void Init() + { + Val = false; + Def = false; + } + + void SetTrueTrue() + { + Val = true; + Def = true; + } + + void SetVal_as_Defined(bool val) + { + Val = val; + Def = true; + } +}; + +#endif diff --git a/CPP/Common/MyUnknown.h b/CPP/Common/MyUnknown.h index af4165118..75ee96fa5 100644 --- a/CPP/Common/MyUnknown.h +++ b/CPP/Common/MyUnknown.h @@ -1,8 +1,8 @@ -// MyUnknown.h - -#ifndef ZIP7_INC_MY_UNKNOWN_H -#define ZIP7_INC_MY_UNKNOWN_H - -#include "MyWindows.h" - -#endif +// MyUnknown.h + +#ifndef ZIP7_INC_MY_UNKNOWN_H +#define ZIP7_INC_MY_UNKNOWN_H + +#include "MyWindows.h" + +#endif diff --git a/CPP/Common/MyVector.cpp b/CPP/Common/MyVector.cpp index 9a6d1d5ae..0b1baf45c 100644 --- a/CPP/Common/MyVector.cpp +++ b/CPP/Common/MyVector.cpp @@ -1,3 +1,3 @@ -// Common/MyVector.cpp - -#include "StdAfx.h" +// Common/MyVector.cpp + +#include "StdAfx.h" diff --git a/CPP/Common/MyVector.h b/CPP/Common/MyVector.h index f47a6ab63..a772785c8 100644 --- a/CPP/Common/MyVector.h +++ b/CPP/Common/MyVector.h @@ -1,724 +1,724 @@ -// Common/MyVector.h - -#ifndef ZIP7_INC_COMMON_MY_VECTOR_H -#define ZIP7_INC_COMMON_MY_VECTOR_H - -#include - -#include "Common.h" - -const unsigned k_VectorSizeMax = ((unsigned)1 << 31) - 1; - -template -class CRecordVector -{ - T *_items; - unsigned _size; - unsigned _capacity; - - void MoveItems(unsigned destIndex, unsigned srcIndex) - { - memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T)); - } - - void ReAllocForNewCapacity(const unsigned newCapacity) - { - T *p; - Z7_ARRAY_NEW(p, T, newCapacity) - // p = new T[newCapacity]; - if (_size != 0) - memcpy(p, _items, (size_t)_size * sizeof(T)); - delete []_items; - _items = p; - _capacity = newCapacity; - } - -public: - - void ReserveOnePosition() - { - if (_size != _capacity) - return; - if (_capacity >= k_VectorSizeMax) - throw 2021; - const unsigned rem = k_VectorSizeMax - _capacity; - unsigned add = (_capacity >> 2) + 1; - if (add > rem) - add = rem; - ReAllocForNewCapacity(_capacity + add); - } - - CRecordVector(): _items(NULL), _size(0), _capacity(0) {} - - CRecordVector(const CRecordVector &v): _items(NULL), _size(0), _capacity(0) - { - const unsigned size = v.Size(); - if (size != 0) - { - // Z7_ARRAY_NEW(_items, T, size) - _items = new T[size]; - _size = size; - _capacity = size; - memcpy(_items, v._items, (size_t)size * sizeof(T)); - } - } - - unsigned Size() const { return _size; } - bool IsEmpty() const { return _size == 0; } - - void ConstructReserve(unsigned size) - { - if (size != 0) - { - Z7_ARRAY_NEW(_items, T, size) - // _items = new T[size]; - _capacity = size; - } - } - - void Reserve(unsigned newCapacity) - { - if (newCapacity > _capacity) - { - if (newCapacity > k_VectorSizeMax) - throw 2021; - ReAllocForNewCapacity(newCapacity); - } - } - - void ChangeSize_KeepData(unsigned newSize) - { - Reserve(newSize); - _size = newSize; - } - - void ClearAndReserve(unsigned newCapacity) - { - Clear(); - if (newCapacity > _capacity) - { - if (newCapacity > k_VectorSizeMax) - throw 2021; - delete []_items; - _items = NULL; - _capacity = 0; - Z7_ARRAY_NEW(_items, T, newCapacity) - // _items = new T[newCapacity]; - _capacity = newCapacity; - } - } - - void ClearAndSetSize(unsigned newSize) - { - ClearAndReserve(newSize); - _size = newSize; - } - - void ReserveDown() - { - if (_size == _capacity) - return; - T *p = NULL; - if (_size != 0) - { - // Z7_ARRAY_NEW(p, T, _size) - p = new T[_size]; - memcpy(p, _items, (size_t)_size * sizeof(T)); - } - delete []_items; - _items = p; - _capacity = _size; - } - - ~CRecordVector() { delete []_items; } - - void ClearAndFree() - { - delete []_items; - _items = NULL; - _size = 0; - _capacity = 0; - } - - void Clear() { _size = 0; } - - void DeleteBack() { _size--; } - - void DeleteFrom(unsigned index) - { - // if (index <= _size) - _size = index; - } - - void DeleteFrontal(unsigned num) - { - if (num != 0) - { - MoveItems(0, num); - _size -= num; - } - } - - void Delete(unsigned index) - { - MoveItems(index, index + 1); - _size -= 1; - } - - /* - void Delete(unsigned index, unsigned num) - { - if (num > 0) - { - MoveItems(index, index + num); - _size -= num; - } - } - */ - - CRecordVector& operator=(const CRecordVector &v) - { - if (&v == this) - return *this; - const unsigned size = v.Size(); - if (size > _capacity) - { - delete []_items; - _capacity = 0; - _size = 0; - _items = NULL; - _items = new T[size]; - _capacity = size; - } - _size = size; - if (size != 0) - memcpy(_items, v._items, (size_t)size * sizeof(T)); - return *this; - } - - CRecordVector& operator+=(const CRecordVector &v) - { - const unsigned size = v.Size(); - if (size != 0) - { - if (_size >= k_VectorSizeMax || size > k_VectorSizeMax - _size) - throw 2021; - const unsigned newSize = _size + size; - Reserve(newSize); - memcpy(_items + _size, v._items, (size_t)size * sizeof(T)); - _size = newSize; - } - return *this; - } - - unsigned Add(const T item) - { - ReserveOnePosition(); - const unsigned size = _size; - _size = size + 1; - _items[size] = item; - return size; - } - - /* - unsigned Add2(const T &item) - { - ReserveOnePosition(); - const unsigned size = _size; - _size = size + 1; - _items[size] = item; - return size; - } - */ - - unsigned AddInReserved(const T item) - { - const unsigned size = _size; - _size = size + 1; - _items[size] = item; - return size; - } - - void Insert(unsigned index, const T item) - { - ReserveOnePosition(); - MoveItems(index + 1, index); - _items[index] = item; - _size++; - } - - void InsertInReserved(unsigned index, const T item) - { - MoveItems(index + 1, index); - _items[index] = item; - _size++; - } - - void MoveToFront(unsigned index) - { - if (index != 0) - { - const T temp = _items[index]; - memmove(_items + 1, _items, (size_t)index * sizeof(T)); - _items[0] = temp; - } - } - - const T& operator[](unsigned index) const { return _items[index]; } - T& operator[](unsigned index) { return _items[index]; } - const T& operator[](int index) const { return _items[(unsigned)index]; } - T& operator[](int index) { return _items[(unsigned)index]; } - - const T* ConstData() const { return _items; } - T* NonConstData() const { return _items; } - T* NonConstData() { return _items; } - - const T* Data() const { return _items; } - T* Data() { return _items; } - - const T& FrontItem() const { return _items[0]; } - T& FrontItem() { return _items[0]; } - /* - const T Front() const { return _items[0]; } - T Front() { return _items[0]; } - const T& Front() const { return _items[0]; } - T& Front() { return _items[0]; } - */ - const T& Back() const { return _items[(size_t)_size - 1]; } - T& Back() { return _items[(size_t)_size - 1]; } - - /* - void Swap(unsigned i, unsigned j) - { - const T temp = _items[i]; - _items[i] = _items[j]; - _items[j] = temp; - } - */ - - int FindInSorted(const T item, unsigned left, unsigned right) const - { - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T midVal = (*this)[mid]; - if (item == midVal) - return (int)mid; - if (item < midVal) - right = mid; - else - left = mid + 1; - } - return -1; - } - - int FindInSorted2(const T &item, unsigned left, unsigned right) const - { - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T& midVal = (*this)[mid]; - const int comp = item.Compare(midVal); - if (comp == 0) - return (int)mid; - if (comp < 0) - right = mid; - else - left = mid + 1; - } - return -1; - } - - int FindInSorted(const T item) const - { - return FindInSorted(item, 0, _size); - } - - int FindInSorted2(const T &item) const - { - return FindInSorted2(item, 0, _size); - } - - unsigned AddToUniqueSorted(const T item) - { - unsigned left = 0, right = _size; - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T midVal = (*this)[mid]; - if (item == midVal) - return mid; - if (item < midVal) - right = mid; - else - left = mid + 1; - } - Insert(right, item); - return right; - } - - unsigned AddToUniqueSorted2(const T &item) - { - unsigned left = 0, right = _size; - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T& midVal = (*this)[mid]; - const int comp = item.Compare(midVal); - if (comp == 0) - return mid; - if (comp < 0) - right = mid; - else - left = mid + 1; - } - Insert(right, item); - return right; - } - - static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param) - { - const T temp = p[k]; - for (;;) - { - unsigned s = (k << 1); - if (s > size) - break; - if (s < size && compare(p + s + 1, p + s, param) > 0) - s++; - if (compare(&temp, p + s, param) >= 0) - break; - p[k] = p[s]; - k = s; - } - p[k] = temp; - } - - void Sort(int (*compare)(const T*, const T*, void *), void *param) - { - unsigned size = _size; - if (size <= 1) - return; - T* p = _items - 1; - { - unsigned i = size >> 1; - do - SortRefDown(p, i, size, compare, param); - while (--i); - } - do - { - const T temp = p[size]; - p[size--] = p[1]; - p[1] = temp; - SortRefDown(p, 1, size, compare, param); - } - while (size > 1); - } - - static void SortRefDown2(T* p, unsigned k, unsigned size) - { - const T temp = p[k]; - for (;;) - { - unsigned s = (k << 1); - if (s > size) - break; - if (s < size && p[(size_t)s + 1].Compare(p[s]) > 0) - s++; - if (temp.Compare(p[s]) >= 0) - break; - p[k] = p[s]; - k = s; - } - p[k] = temp; - } - - void Sort2() - { - unsigned size = _size; - if (size <= 1) - return; - T* p = _items - 1; - { - unsigned i = size >> 1; - do - SortRefDown2(p, i, size); - while (--i); - } - do - { - const T temp = p[size]; - p[size--] = p[1]; - p[1] = temp; - SortRefDown2(p, 1, size); - } - while (size > 1); - } -}; - -typedef CRecordVector CIntVector; -typedef CRecordVector CUIntVector; -typedef CRecordVector CBoolVector; -typedef CRecordVector CByteVector; -typedef CRecordVector CPointerVector; - -template -class CObjectVector -{ - CPointerVector _v; -public: - unsigned Size() const { return _v.Size(); } - bool IsEmpty() const { return _v.IsEmpty(); } - void ReserveDown() { _v.ReserveDown(); } - // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); } - void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); } - - CObjectVector() {} - CObjectVector(const CObjectVector &v) - { - const unsigned size = v.Size(); - _v.ConstructReserve(size); - for (unsigned i = 0; i < size; i++) - AddInReserved(v[i]); - } - CObjectVector& operator=(const CObjectVector &v) - { - if (&v == this) - return *this; - Clear(); - const unsigned size = v.Size(); - _v.Reserve(size); - for (unsigned i = 0; i < size; i++) - AddInReserved(v[i]); - return *this; - } - - CObjectVector& operator+=(const CObjectVector &v) - { - const unsigned addSize = v.Size(); - if (addSize != 0) - { - const unsigned size = Size(); - if (size >= k_VectorSizeMax || addSize > k_VectorSizeMax - size) - throw 2021; - _v.Reserve(size + addSize); - for (unsigned i = 0; i < addSize; i++) - AddInReserved(v[i]); - } - return *this; - } - - const T& operator[](unsigned index) const { return *((T *)_v[index]); } - T& operator[](unsigned index) { return *((T *)_v[index]); } - const T& operator[](int index) const { return *((T *)_v[(unsigned)index]); } - T& operator[](int index) { return *((T *)_v[(unsigned)index]); } - const T& Front() const { return operator[](0); } - T& Front() { return operator[](0); } - const T& Back() const { return *(T *)_v.Back(); } - T& Back() { return *(T *)_v.Back(); } - - void MoveToFront(unsigned index) { _v.MoveToFront(index); } - - unsigned Add(const T& item) - { - _v.ReserveOnePosition(); - return AddInReserved(item); - } - - unsigned AddInReserved(const T& item) - { - return _v.AddInReserved(new T(item)); - } - - void ReserveOnePosition() - { - _v.ReserveOnePosition(); - } - - unsigned AddInReserved_Ptr_of_new(T *ptr) - { - return _v.AddInReserved(ptr); - } - - #define VECTOR_ADD_NEW_OBJECT(v, a) \ - (v).ReserveOnePosition(); \ - (v).AddInReserved_Ptr_of_new(new a); - - - T& AddNew() - { - _v.ReserveOnePosition(); - T *p = new T; - _v.AddInReserved(p); - return *p; - } - - T& AddNewInReserved() - { - T *p = new T; - _v.AddInReserved(p); - return *p; - } - - void Insert(unsigned index, const T& item) - { - _v.ReserveOnePosition(); - _v.InsertInReserved(index, new T(item)); - } - - T& InsertNew(unsigned index) - { - _v.ReserveOnePosition(); - T *p = new T; - _v.InsertInReserved(index, p); - return *p; - } - - ~CObjectVector() - { - for (unsigned i = _v.Size(); i != 0;) - delete (T *)_v[--i]; - } - - void ClearAndFree() - { - Clear(); - _v.ClearAndFree(); - } - - void Clear() - { - for (unsigned i = _v.Size(); i != 0;) - delete (T *)_v[--i]; - _v.Clear(); - } - - void DeleteFrom(unsigned index) - { - const unsigned size = _v.Size(); - for (unsigned i = index; i < size; i++) - delete (T *)_v[i]; - _v.DeleteFrom(index); - } - - void DeleteFrontal(unsigned num) - { - for (unsigned i = 0; i < num; i++) - delete (T *)_v[i]; - _v.DeleteFrontal(num); - } - - void DeleteBack() - { - delete (T *)_v.Back(); - _v.DeleteBack(); - } - - void Delete(unsigned index) - { - delete (T *)_v[index]; - _v.Delete(index); - } - // void Delete(int index) { Delete((unsigned)index); } - - /* - void Delete(unsigned index, unsigned num) - { - for (unsigned i = 0; i < num; i++) - delete (T *)_v[index + i]; - _v.Delete(index, num); - } - */ - - /* - int Find(const T& item) const - { - unsigned size = Size(); - for (unsigned i = 0; i < size; i++) - if (item == (*this)[i]) - return i; - return -1; - } - */ - - int FindInSorted(const T& item) const - { - unsigned left = 0, right = Size(); - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T& midVal = (*this)[mid]; - const int comp = item.Compare(midVal); - if (comp == 0) - return (int)mid; - if (comp < 0) - right = mid; - else - left = mid + 1; - } - return -1; - } - - unsigned AddToUniqueSorted(const T& item) - { - unsigned left = 0, right = Size(); - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T& midVal = (*this)[mid]; - const int comp = item.Compare(midVal); - if (comp == 0) - return mid; - if (comp < 0) - right = mid; - else - left = mid + 1; - } - Insert(right, item); - return right; - } - - /* - unsigned AddToSorted(const T& item) - { - unsigned left = 0, right = Size(); - while (left != right) - { - // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned mid = (left + right) / 2; - const T& midVal = (*this)[mid]; - const int comp = item.Compare(midVal); - if (comp == 0) - { - right = mid + 1; - break; - } - if (comp < 0) - right = mid; - else - left = mid + 1; - } - Insert(right, item); - return right; - } - */ - - void Sort(int (*compare)(void *const *, void *const *, void *), void *param) - { _v.Sort(compare, param); } - - static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */) - { return (*(*((const T *const *)a1))).Compare(*(*((const T *const *)a2))); } - - void Sort() { _v.Sort(CompareObjectItems, NULL); } -}; - -#define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++) - -#endif +// Common/MyVector.h + +#ifndef ZIP7_INC_COMMON_MY_VECTOR_H +#define ZIP7_INC_COMMON_MY_VECTOR_H + +#include + +#include "Common.h" + +const unsigned k_VectorSizeMax = ((unsigned)1 << 31) - 1; + +template +class CRecordVector +{ + T *_items; + unsigned _size; + unsigned _capacity; + + void MoveItems(unsigned destIndex, unsigned srcIndex) + { + memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T)); + } + + void ReAllocForNewCapacity(const unsigned newCapacity) + { + T *p; + Z7_ARRAY_NEW(p, T, newCapacity) + // p = new T[newCapacity]; + if (_size != 0) + memcpy(p, _items, (size_t)_size * sizeof(T)); + delete []_items; + _items = p; + _capacity = newCapacity; + } + +public: + + void ReserveOnePosition() + { + if (_size != _capacity) + return; + if (_capacity >= k_VectorSizeMax) + throw 2021; + const unsigned rem = k_VectorSizeMax - _capacity; + unsigned add = (_capacity >> 2) + 1; + if (add > rem) + add = rem; + ReAllocForNewCapacity(_capacity + add); + } + + CRecordVector(): _items(NULL), _size(0), _capacity(0) {} + + CRecordVector(const CRecordVector &v): _items(NULL), _size(0), _capacity(0) + { + const unsigned size = v.Size(); + if (size != 0) + { + // Z7_ARRAY_NEW(_items, T, size) + _items = new T[size]; + _size = size; + _capacity = size; + memcpy(_items, v._items, (size_t)size * sizeof(T)); + } + } + + unsigned Size() const { return _size; } + bool IsEmpty() const { return _size == 0; } + + void ConstructReserve(unsigned size) + { + if (size != 0) + { + Z7_ARRAY_NEW(_items, T, size) + // _items = new T[size]; + _capacity = size; + } + } + + void Reserve(unsigned newCapacity) + { + if (newCapacity > _capacity) + { + if (newCapacity > k_VectorSizeMax) + throw 2021; + ReAllocForNewCapacity(newCapacity); + } + } + + void ChangeSize_KeepData(unsigned newSize) + { + Reserve(newSize); + _size = newSize; + } + + void ClearAndReserve(unsigned newCapacity) + { + Clear(); + if (newCapacity > _capacity) + { + if (newCapacity > k_VectorSizeMax) + throw 2021; + delete []_items; + _items = NULL; + _capacity = 0; + Z7_ARRAY_NEW(_items, T, newCapacity) + // _items = new T[newCapacity]; + _capacity = newCapacity; + } + } + + void ClearAndSetSize(unsigned newSize) + { + ClearAndReserve(newSize); + _size = newSize; + } + + void ReserveDown() + { + if (_size == _capacity) + return; + T *p = NULL; + if (_size != 0) + { + // Z7_ARRAY_NEW(p, T, _size) + p = new T[_size]; + memcpy(p, _items, (size_t)_size * sizeof(T)); + } + delete []_items; + _items = p; + _capacity = _size; + } + + ~CRecordVector() { delete []_items; } + + void ClearAndFree() + { + delete []_items; + _items = NULL; + _size = 0; + _capacity = 0; + } + + void Clear() { _size = 0; } + + void DeleteBack() { _size--; } + + void DeleteFrom(unsigned index) + { + // if (index <= _size) + _size = index; + } + + void DeleteFrontal(unsigned num) + { + if (num != 0) + { + MoveItems(0, num); + _size -= num; + } + } + + void Delete(unsigned index) + { + MoveItems(index, index + 1); + _size -= 1; + } + + /* + void Delete(unsigned index, unsigned num) + { + if (num > 0) + { + MoveItems(index, index + num); + _size -= num; + } + } + */ + + CRecordVector& operator=(const CRecordVector &v) + { + if (&v == this) + return *this; + const unsigned size = v.Size(); + if (size > _capacity) + { + delete []_items; + _capacity = 0; + _size = 0; + _items = NULL; + _items = new T[size]; + _capacity = size; + } + _size = size; + if (size != 0) + memcpy(_items, v._items, (size_t)size * sizeof(T)); + return *this; + } + + CRecordVector& operator+=(const CRecordVector &v) + { + const unsigned size = v.Size(); + if (size != 0) + { + if (_size >= k_VectorSizeMax || size > k_VectorSizeMax - _size) + throw 2021; + const unsigned newSize = _size + size; + Reserve(newSize); + memcpy(_items + _size, v._items, (size_t)size * sizeof(T)); + _size = newSize; + } + return *this; + } + + unsigned Add(const T item) + { + ReserveOnePosition(); + const unsigned size = _size; + _size = size + 1; + _items[size] = item; + return size; + } + + /* + unsigned Add2(const T &item) + { + ReserveOnePosition(); + const unsigned size = _size; + _size = size + 1; + _items[size] = item; + return size; + } + */ + + unsigned AddInReserved(const T item) + { + const unsigned size = _size; + _size = size + 1; + _items[size] = item; + return size; + } + + void Insert(unsigned index, const T item) + { + ReserveOnePosition(); + MoveItems(index + 1, index); + _items[index] = item; + _size++; + } + + void InsertInReserved(unsigned index, const T item) + { + MoveItems(index + 1, index); + _items[index] = item; + _size++; + } + + void MoveToFront(unsigned index) + { + if (index != 0) + { + const T temp = _items[index]; + memmove(_items + 1, _items, (size_t)index * sizeof(T)); + _items[0] = temp; + } + } + + const T& operator[](unsigned index) const { return _items[index]; } + T& operator[](unsigned index) { return _items[index]; } + const T& operator[](int index) const { return _items[(unsigned)index]; } + T& operator[](int index) { return _items[(unsigned)index]; } + + const T* ConstData() const { return _items; } + T* NonConstData() const { return _items; } + T* NonConstData() { return _items; } + + const T* Data() const { return _items; } + T* Data() { return _items; } + + const T& FrontItem() const { return _items[0]; } + T& FrontItem() { return _items[0]; } + /* + const T Front() const { return _items[0]; } + T Front() { return _items[0]; } + const T& Front() const { return _items[0]; } + T& Front() { return _items[0]; } + */ + const T& Back() const { return _items[(size_t)_size - 1]; } + T& Back() { return _items[(size_t)_size - 1]; } + + /* + void Swap(unsigned i, unsigned j) + { + const T temp = _items[i]; + _items[i] = _items[j]; + _items[j] = temp; + } + */ + + int FindInSorted(const T item, unsigned left, unsigned right) const + { + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T midVal = (*this)[mid]; + if (item == midVal) + return (int)mid; + if (item < midVal) + right = mid; + else + left = mid + 1; + } + return -1; + } + + int FindInSorted2(const T &item, unsigned left, unsigned right) const + { + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T& midVal = (*this)[mid]; + const int comp = item.Compare(midVal); + if (comp == 0) + return (int)mid; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + return -1; + } + + int FindInSorted(const T item) const + { + return FindInSorted(item, 0, _size); + } + + int FindInSorted2(const T &item) const + { + return FindInSorted2(item, 0, _size); + } + + unsigned AddToUniqueSorted(const T item) + { + unsigned left = 0, right = _size; + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T midVal = (*this)[mid]; + if (item == midVal) + return mid; + if (item < midVal) + right = mid; + else + left = mid + 1; + } + Insert(right, item); + return right; + } + + unsigned AddToUniqueSorted2(const T &item) + { + unsigned left = 0, right = _size; + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T& midVal = (*this)[mid]; + const int comp = item.Compare(midVal); + if (comp == 0) + return mid; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + Insert(right, item); + return right; + } + + static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param) + { + const T temp = p[k]; + for (;;) + { + unsigned s = (k << 1); + if (s > size) + break; + if (s < size && compare(p + s + 1, p + s, param) > 0) + s++; + if (compare(&temp, p + s, param) >= 0) + break; + p[k] = p[s]; + k = s; + } + p[k] = temp; + } + + void Sort(int (*compare)(const T*, const T*, void *), void *param) + { + unsigned size = _size; + if (size <= 1) + return; + T* p = _items - 1; + { + unsigned i = size >> 1; + do + SortRefDown(p, i, size, compare, param); + while (--i); + } + do + { + const T temp = p[size]; + p[size--] = p[1]; + p[1] = temp; + SortRefDown(p, 1, size, compare, param); + } + while (size > 1); + } + + static void SortRefDown2(T* p, unsigned k, unsigned size) + { + const T temp = p[k]; + for (;;) + { + unsigned s = (k << 1); + if (s > size) + break; + if (s < size && p[(size_t)s + 1].Compare(p[s]) > 0) + s++; + if (temp.Compare(p[s]) >= 0) + break; + p[k] = p[s]; + k = s; + } + p[k] = temp; + } + + void Sort2() + { + unsigned size = _size; + if (size <= 1) + return; + T* p = _items - 1; + { + unsigned i = size >> 1; + do + SortRefDown2(p, i, size); + while (--i); + } + do + { + const T temp = p[size]; + p[size--] = p[1]; + p[1] = temp; + SortRefDown2(p, 1, size); + } + while (size > 1); + } +}; + +typedef CRecordVector CIntVector; +typedef CRecordVector CUIntVector; +typedef CRecordVector CBoolVector; +typedef CRecordVector CByteVector; +typedef CRecordVector CPointerVector; + +template +class CObjectVector +{ + CPointerVector _v; +public: + unsigned Size() const { return _v.Size(); } + bool IsEmpty() const { return _v.IsEmpty(); } + void ReserveDown() { _v.ReserveDown(); } + // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); } + void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); } + + CObjectVector() {} + CObjectVector(const CObjectVector &v) + { + const unsigned size = v.Size(); + _v.ConstructReserve(size); + for (unsigned i = 0; i < size; i++) + AddInReserved(v[i]); + } + CObjectVector& operator=(const CObjectVector &v) + { + if (&v == this) + return *this; + Clear(); + const unsigned size = v.Size(); + _v.Reserve(size); + for (unsigned i = 0; i < size; i++) + AddInReserved(v[i]); + return *this; + } + + CObjectVector& operator+=(const CObjectVector &v) + { + const unsigned addSize = v.Size(); + if (addSize != 0) + { + const unsigned size = Size(); + if (size >= k_VectorSizeMax || addSize > k_VectorSizeMax - size) + throw 2021; + _v.Reserve(size + addSize); + for (unsigned i = 0; i < addSize; i++) + AddInReserved(v[i]); + } + return *this; + } + + const T& operator[](unsigned index) const { return *((T *)_v[index]); } + T& operator[](unsigned index) { return *((T *)_v[index]); } + const T& operator[](int index) const { return *((T *)_v[(unsigned)index]); } + T& operator[](int index) { return *((T *)_v[(unsigned)index]); } + const T& Front() const { return operator[](0); } + T& Front() { return operator[](0); } + const T& Back() const { return *(T *)_v.Back(); } + T& Back() { return *(T *)_v.Back(); } + + void MoveToFront(unsigned index) { _v.MoveToFront(index); } + + unsigned Add(const T& item) + { + _v.ReserveOnePosition(); + return AddInReserved(item); + } + + unsigned AddInReserved(const T& item) + { + return _v.AddInReserved(new T(item)); + } + + void ReserveOnePosition() + { + _v.ReserveOnePosition(); + } + + unsigned AddInReserved_Ptr_of_new(T *ptr) + { + return _v.AddInReserved(ptr); + } + + #define VECTOR_ADD_NEW_OBJECT(v, a) \ + (v).ReserveOnePosition(); \ + (v).AddInReserved_Ptr_of_new(new a); + + + T& AddNew() + { + _v.ReserveOnePosition(); + T *p = new T; + _v.AddInReserved(p); + return *p; + } + + T& AddNewInReserved() + { + T *p = new T; + _v.AddInReserved(p); + return *p; + } + + void Insert(unsigned index, const T& item) + { + _v.ReserveOnePosition(); + _v.InsertInReserved(index, new T(item)); + } + + T& InsertNew(unsigned index) + { + _v.ReserveOnePosition(); + T *p = new T; + _v.InsertInReserved(index, p); + return *p; + } + + ~CObjectVector() + { + for (unsigned i = _v.Size(); i != 0;) + delete (T *)_v[--i]; + } + + void ClearAndFree() + { + Clear(); + _v.ClearAndFree(); + } + + void Clear() + { + for (unsigned i = _v.Size(); i != 0;) + delete (T *)_v[--i]; + _v.Clear(); + } + + void DeleteFrom(unsigned index) + { + const unsigned size = _v.Size(); + for (unsigned i = index; i < size; i++) + delete (T *)_v[i]; + _v.DeleteFrom(index); + } + + void DeleteFrontal(unsigned num) + { + for (unsigned i = 0; i < num; i++) + delete (T *)_v[i]; + _v.DeleteFrontal(num); + } + + void DeleteBack() + { + delete (T *)_v.Back(); + _v.DeleteBack(); + } + + void Delete(unsigned index) + { + delete (T *)_v[index]; + _v.Delete(index); + } + // void Delete(int index) { Delete((unsigned)index); } + + /* + void Delete(unsigned index, unsigned num) + { + for (unsigned i = 0; i < num; i++) + delete (T *)_v[index + i]; + _v.Delete(index, num); + } + */ + + /* + int Find(const T& item) const + { + unsigned size = Size(); + for (unsigned i = 0; i < size; i++) + if (item == (*this)[i]) + return i; + return -1; + } + */ + + int FindInSorted(const T& item) const + { + unsigned left = 0, right = Size(); + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T& midVal = (*this)[mid]; + const int comp = item.Compare(midVal); + if (comp == 0) + return (int)mid; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + return -1; + } + + unsigned AddToUniqueSorted(const T& item) + { + unsigned left = 0, right = Size(); + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T& midVal = (*this)[mid]; + const int comp = item.Compare(midVal); + if (comp == 0) + return mid; + if (comp < 0) + right = mid; + else + left = mid + 1; + } + Insert(right, item); + return right; + } + + /* + unsigned AddToSorted(const T& item) + { + unsigned left = 0, right = Size(); + while (left != right) + { + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; + const T& midVal = (*this)[mid]; + const int comp = item.Compare(midVal); + if (comp == 0) + { + right = mid + 1; + break; + } + if (comp < 0) + right = mid; + else + left = mid + 1; + } + Insert(right, item); + return right; + } + */ + + void Sort(int (*compare)(void *const *, void *const *, void *), void *param) + { _v.Sort(compare, param); } + + static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */) + { return (*(*((const T *const *)a1))).Compare(*(*((const T *const *)a2))); } + + void Sort() { _v.Sort(CompareObjectItems, NULL); } +}; + +#define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++) + +#endif diff --git a/CPP/Common/MyWindows.cpp b/CPP/Common/MyWindows.cpp index 6d52a944b..a1dfbefbf 100644 --- a/CPP/Common/MyWindows.cpp +++ b/CPP/Common/MyWindows.cpp @@ -1,292 +1,292 @@ -// MyWindows.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 - -#include -#include -#ifdef __GNUC__ -#include -#endif - -#include "MyWindows.h" - -static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } -static inline void FreeForBSTR(void *pv) { ::free(pv);} - -/* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string. - We must select CBstrSizeType for another systems (not Win32): - - if (CBstrSizeType is UINT32), - then we support only strings smaller than 4 GB. - Win32 version always has that limitation. - - if (CBstrSizeType is UINT), - (UINT can be 16/32/64-bit) - We can support strings larger than 4 GB (if UINT is 64-bit), - but sizeof(UINT) can be different in parts compiled by - different compilers/settings, - and we can't send such BSTR strings between such parts. -*/ - -typedef UINT32 CBstrSizeType; -// typedef UINT CBstrSizeType; - -#define k_BstrSize_Max 0xFFFFFFFF -// #define k_BstrSize_Max UINT_MAX -// #define k_BstrSize_Max ((UINT)(INT)-1) - -BSTR SysAllocStringByteLen(LPCSTR s, UINT len) -{ - /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end. - We provide also aligned null OLECHAR at the end. */ - - if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType))) - return NULL; - - UINT size = (len + (UINT)sizeof(OLECHAR) + (UINT)sizeof(OLECHAR) - 1) & ~((UINT)sizeof(OLECHAR) - 1); - void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType)); - if (!p) - return NULL; - *(CBstrSizeType *)p = (CBstrSizeType)len; - BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); - if (s) - memcpy(bstr, s, len); - for (; len < size; len++) - ((Byte *)bstr)[len] = 0; - return bstr; -} - -BSTR SysAllocStringLen(const OLECHAR *s, UINT len) -{ - if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType)) / (UINT)sizeof(OLECHAR)) - return NULL; - - UINT size = len * (UINT)sizeof(OLECHAR); - void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType) + (UINT)sizeof(OLECHAR)); - if (!p) - return NULL; - *(CBstrSizeType *)p = (CBstrSizeType)size; - BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); - if (s) - memcpy(bstr, s, size); - bstr[len] = 0; - return bstr; -} - -BSTR SysAllocString(const OLECHAR *s) -{ - if (!s) - return NULL; - const OLECHAR *s2 = s; - while (*s2 != 0) - s2++; - return SysAllocStringLen(s, (UINT)(s2 - s)); -} - -void SysFreeString(BSTR bstr) -{ - if (bstr) - FreeForBSTR((CBstrSizeType *)(void *)bstr - 1); -} - -UINT SysStringByteLen(BSTR bstr) -{ - if (!bstr) - return 0; - return *((CBstrSizeType *)(void *)bstr - 1); -} - -UINT SysStringLen(BSTR bstr) -{ - if (!bstr) - return 0; - return *((CBstrSizeType *)(void *)bstr - 1) / (UINT)sizeof(OLECHAR); -} - - -HRESULT VariantClear(VARIANTARG *prop) -{ - if (prop->vt == VT_BSTR) - SysFreeString(prop->bstrVal); - prop->vt = VT_EMPTY; - return S_OK; -} - -HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src) -{ - HRESULT res = ::VariantClear(dest); - if (res != S_OK) - return res; - if (src->vt == VT_BSTR) - { - dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, - SysStringByteLen(src->bstrVal)); - if (!dest->bstrVal) - return E_OUTOFMEMORY; - dest->vt = VT_BSTR; - } - else - *dest = *src; - return S_OK; -} - -LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) -{ - if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1; - if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1; - if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1; - if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1; - return 0; -} - -DWORD GetLastError() -{ - return (DWORD)errno; -} - -void SetLastError(DWORD dw) -{ - errno = (int)dw; -} - - -static LONG TIME_GetBias() -{ - time_t utc = time(NULL); - struct tm *ptm = localtime(&utc); - int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ - ptm = gmtime(&utc); - ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ - LONG bias = (int)(mktime(ptm)-utc); - return bias; -} - -#define TICKS_PER_SEC 10000000 -/* -#define SECS_PER_DAY (24 * 60 * 60) -#define SECS_1601_TO_1970 ((369 * 365 + 89) * (UInt64)SECS_PER_DAY) -#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKS_PER_SEC) -*/ - -#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) - -#define SET_FILETIME(ft, v64) \ - (ft)->dwLowDateTime = (DWORD)v64; \ - (ft)->dwHighDateTime = (DWORD)(v64 >> 32); - - -BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) -{ - UInt64 v = GET_TIME_64(fileTime); - v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); - SET_FILETIME(localFileTime, v) - return TRUE; -} - -BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime) -{ - UInt64 v = GET_TIME_64(localFileTime); - v = (UInt64)((Int64)v + (Int64)TIME_GetBias() * TICKS_PER_SEC); - SET_FILETIME(fileTime, v) - return TRUE; -} - -/* -VOID WINAPI GetSystemTimeAsFileTime(FILETIME *ft) -{ - UInt64 t = 0; - timeval tv; - if (gettimeofday(&tv, NULL) == 0) - { - t = tv.tv_sec * (UInt64)TICKS_PER_SEC + TICKS_1601_TO_1970; - t += tv.tv_usec * 10; - } - SET_FILETIME(ft, t) -} -*/ - -DWORD WINAPI GetTickCount(VOID) -{ - #ifndef _WIN32 - // gettimeofday() doesn't work in some MINGWs by unknown reason - timeval tv; - if (gettimeofday(&tv, NULL) == 0) - { - // tv_sec and tv_usec are (long) - return (DWORD)((UInt64)(Int64)tv.tv_sec * (UInt64)1000 + (UInt64)(Int64)tv.tv_usec / 1000); - } - #endif - return (DWORD)time(NULL) * 1000; -} - - -#define PERIOD_4 (4 * 365 + 1) -#define PERIOD_100 (PERIOD_4 * 25 - 1) -#define PERIOD_400 (PERIOD_100 * 4 + 1) - -BOOL WINAPI FileTimeToSystemTime(const FILETIME *ft, SYSTEMTIME *st) -{ - UInt32 v; - UInt64 v64 = GET_TIME_64(ft); - v64 /= 10000; - st->wMilliseconds = (WORD)(v64 % 1000); v64 /= 1000; - st->wSecond = (WORD)(v64 % 60); v64 /= 60; - st->wMinute = (WORD)(v64 % 60); v64 /= 60; - v = (UInt32)v64; - st->wHour = (WORD)(v % 24); v /= 24; - - // 1601-01-01 was Monday - st->wDayOfWeek = (WORD)((v + 1) % 7); - - UInt32 leaps, year, day, mon; - leaps = (3 * ((4 * v + (365 - 31 - 28) * 4 + 3) / PERIOD_400) + 3) / 4; - v += 28188 + leaps; - // leaps - the number of exceptions from PERIOD_4 rules starting from 1600-03-01 - // (1959 / 64) - converts day from 03-01 to month - year = (20 * v - 2442) / (5 * PERIOD_4); - day = v - (year * PERIOD_4) / 4; - mon = (64 * day) / 1959; - st->wDay = (WORD)(day - (1959 * mon) / 64); - mon -= 1; - year += 1524; - if (mon > 12) - { - mon -= 12; - year++; - } - st->wMonth = (WORD)mon; - st->wYear = (WORD)year; - - /* - unsigned year, mon; - unsigned char ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - unsigned t; - - year = (WORD)(1601 + v / PERIOD_400 * 400); - v %= PERIOD_400; - - t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; - t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; - t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; - - st->wYear = (WORD)year; - - if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) - ms[1] = 29; - for (mon = 0;; mon++) - { - unsigned d = ms[mon]; - if (v < d) - break; - v -= d; - } - st->wDay = (WORD)(v + 1); - st->wMonth = (WORD)(mon + 1); - */ - - return TRUE; -} - -#endif +// MyWindows.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 + +#include +#include +#ifdef __GNUC__ +#include +#endif + +#include "MyWindows.h" + +static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } +static inline void FreeForBSTR(void *pv) { ::free(pv);} + +/* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string. + We must select CBstrSizeType for another systems (not Win32): + + if (CBstrSizeType is UINT32), + then we support only strings smaller than 4 GB. + Win32 version always has that limitation. + + if (CBstrSizeType is UINT), + (UINT can be 16/32/64-bit) + We can support strings larger than 4 GB (if UINT is 64-bit), + but sizeof(UINT) can be different in parts compiled by + different compilers/settings, + and we can't send such BSTR strings between such parts. +*/ + +typedef UINT32 CBstrSizeType; +// typedef UINT CBstrSizeType; + +#define k_BstrSize_Max 0xFFFFFFFF +// #define k_BstrSize_Max UINT_MAX +// #define k_BstrSize_Max ((UINT)(INT)-1) + +BSTR SysAllocStringByteLen(LPCSTR s, UINT len) +{ + /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end. + We provide also aligned null OLECHAR at the end. */ + + if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType))) + return NULL; + + UINT size = (len + (UINT)sizeof(OLECHAR) + (UINT)sizeof(OLECHAR) - 1) & ~((UINT)sizeof(OLECHAR) - 1); + void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType)); + if (!p) + return NULL; + *(CBstrSizeType *)p = (CBstrSizeType)len; + BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); + if (s) + memcpy(bstr, s, len); + for (; len < size; len++) + ((Byte *)bstr)[len] = 0; + return bstr; +} + +BSTR SysAllocStringLen(const OLECHAR *s, UINT len) +{ + if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType)) / (UINT)sizeof(OLECHAR)) + return NULL; + + UINT size = len * (UINT)sizeof(OLECHAR); + void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType) + (UINT)sizeof(OLECHAR)); + if (!p) + return NULL; + *(CBstrSizeType *)p = (CBstrSizeType)size; + BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); + if (s) + memcpy(bstr, s, size); + bstr[len] = 0; + return bstr; +} + +BSTR SysAllocString(const OLECHAR *s) +{ + if (!s) + return NULL; + const OLECHAR *s2 = s; + while (*s2 != 0) + s2++; + return SysAllocStringLen(s, (UINT)(s2 - s)); +} + +void SysFreeString(BSTR bstr) +{ + if (bstr) + FreeForBSTR((CBstrSizeType *)(void *)bstr - 1); +} + +UINT SysStringByteLen(BSTR bstr) +{ + if (!bstr) + return 0; + return *((CBstrSizeType *)(void *)bstr - 1); +} + +UINT SysStringLen(BSTR bstr) +{ + if (!bstr) + return 0; + return *((CBstrSizeType *)(void *)bstr - 1) / (UINT)sizeof(OLECHAR); +} + + +HRESULT VariantClear(VARIANTARG *prop) +{ + if (prop->vt == VT_BSTR) + SysFreeString(prop->bstrVal); + prop->vt = VT_EMPTY; + return S_OK; +} + +HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src) +{ + HRESULT res = ::VariantClear(dest); + if (res != S_OK) + return res; + if (src->vt == VT_BSTR) + { + dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, + SysStringByteLen(src->bstrVal)); + if (!dest->bstrVal) + return E_OUTOFMEMORY; + dest->vt = VT_BSTR; + } + else + *dest = *src; + return S_OK; +} + +LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) +{ + if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1; + if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1; + if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1; + if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1; + return 0; +} + +DWORD GetLastError() +{ + return (DWORD)errno; +} + +void SetLastError(DWORD dw) +{ + errno = (int)dw; +} + + +static LONG TIME_GetBias() +{ + time_t utc = time(NULL); + struct tm *ptm = localtime(&utc); + int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ + ptm = gmtime(&utc); + ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ + LONG bias = (int)(mktime(ptm)-utc); + return bias; +} + +#define TICKS_PER_SEC 10000000 +/* +#define SECS_PER_DAY (24 * 60 * 60) +#define SECS_1601_TO_1970 ((369 * 365 + 89) * (UInt64)SECS_PER_DAY) +#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKS_PER_SEC) +*/ + +#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) + +#define SET_FILETIME(ft, v64) \ + (ft)->dwLowDateTime = (DWORD)v64; \ + (ft)->dwHighDateTime = (DWORD)(v64 >> 32); + + +BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) +{ + UInt64 v = GET_TIME_64(fileTime); + v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); + SET_FILETIME(localFileTime, v) + return TRUE; +} + +BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime) +{ + UInt64 v = GET_TIME_64(localFileTime); + v = (UInt64)((Int64)v + (Int64)TIME_GetBias() * TICKS_PER_SEC); + SET_FILETIME(fileTime, v) + return TRUE; +} + +/* +VOID WINAPI GetSystemTimeAsFileTime(FILETIME *ft) +{ + UInt64 t = 0; + timeval tv; + if (gettimeofday(&tv, NULL) == 0) + { + t = tv.tv_sec * (UInt64)TICKS_PER_SEC + TICKS_1601_TO_1970; + t += tv.tv_usec * 10; + } + SET_FILETIME(ft, t) +} +*/ + +DWORD WINAPI GetTickCount(VOID) +{ + #ifndef _WIN32 + // gettimeofday() doesn't work in some MINGWs by unknown reason + timeval tv; + if (gettimeofday(&tv, NULL) == 0) + { + // tv_sec and tv_usec are (long) + return (DWORD)((UInt64)(Int64)tv.tv_sec * (UInt64)1000 + (UInt64)(Int64)tv.tv_usec / 1000); + } + #endif + return (DWORD)time(NULL) * 1000; +} + + +#define PERIOD_4 (4 * 365 + 1) +#define PERIOD_100 (PERIOD_4 * 25 - 1) +#define PERIOD_400 (PERIOD_100 * 4 + 1) + +BOOL WINAPI FileTimeToSystemTime(const FILETIME *ft, SYSTEMTIME *st) +{ + UInt32 v; + UInt64 v64 = GET_TIME_64(ft); + v64 /= 10000; + st->wMilliseconds = (WORD)(v64 % 1000); v64 /= 1000; + st->wSecond = (WORD)(v64 % 60); v64 /= 60; + st->wMinute = (WORD)(v64 % 60); v64 /= 60; + v = (UInt32)v64; + st->wHour = (WORD)(v % 24); v /= 24; + + // 1601-01-01 was Monday + st->wDayOfWeek = (WORD)((v + 1) % 7); + + UInt32 leaps, year, day, mon; + leaps = (3 * ((4 * v + (365 - 31 - 28) * 4 + 3) / PERIOD_400) + 3) / 4; + v += 28188 + leaps; + // leaps - the number of exceptions from PERIOD_4 rules starting from 1600-03-01 + // (1959 / 64) - converts day from 03-01 to month + year = (20 * v - 2442) / (5 * PERIOD_4); + day = v - (year * PERIOD_4) / 4; + mon = (64 * day) / 1959; + st->wDay = (WORD)(day - (1959 * mon) / 64); + mon -= 1; + year += 1524; + if (mon > 12) + { + mon -= 12; + year++; + } + st->wMonth = (WORD)mon; + st->wYear = (WORD)year; + + /* + unsigned year, mon; + unsigned char ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + unsigned t; + + year = (WORD)(1601 + v / PERIOD_400 * 400); + v %= PERIOD_400; + + t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; + t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; + t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; + + st->wYear = (WORD)year; + + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + ms[1] = 29; + for (mon = 0;; mon++) + { + unsigned d = ms[mon]; + if (v < d) + break; + v -= d; + } + st->wDay = (WORD)(v + 1); + st->wMonth = (WORD)(mon + 1); + */ + + return TRUE; +} + +#endif diff --git a/CPP/Common/MyWindows.h b/CPP/Common/MyWindows.h index dad6106f5..da5370b09 100644 --- a/CPP/Common/MyWindows.h +++ b/CPP/Common/MyWindows.h @@ -1,325 +1,325 @@ -// MyWindows.h - -#ifdef Z7_DEFINE_GUID -#undef Z7_DEFINE_GUID -#endif - -#ifdef INITGUID - #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - EXTERN_C const GUID name; \ - EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -#else - #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - EXTERN_C const GUID name -#endif - - -#ifndef ZIP7_INC_MY_WINDOWS_H -#define ZIP7_INC_MY_WINDOWS_H - -#ifdef _WIN32 - -#include "../../C/7zWindows.h" - -#else // _WIN32 - -#include // for wchar_t -#include -// #include // for uintptr_t - -#include "../../C/7zTypes.h" -#include "MyGuidDef.h" - -// WINAPI is __stdcall in Windows-MSVC in windef.h -#define WINAPI - -typedef char CHAR; -typedef unsigned char UCHAR; - -#undef BYTE -typedef unsigned char BYTE; - -typedef short SHORT; -typedef unsigned short USHORT; - -#undef WORD -typedef unsigned short WORD; -typedef short VARIANT_BOOL; - -#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) -#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) - -// MS uses long for BOOL, but long is 32-bit in MS. So we use int. -// typedef long BOOL; -typedef int BOOL; - -#ifndef FALSE - #define FALSE 0 - #define TRUE 1 -#endif - -// typedef size_t ULONG_PTR; -// typedef size_t DWORD_PTR; -// typedef uintptr_t UINT_PTR; -// typedef ptrdiff_t UINT_PTR; - -typedef Int64 LONGLONG; -typedef UInt64 ULONGLONG; - -typedef struct { LONGLONG QuadPart; } LARGE_INTEGER; -typedef struct { ULONGLONG QuadPart; } ULARGE_INTEGER; - -typedef const CHAR *LPCSTR; -typedef CHAR TCHAR; -typedef const TCHAR *LPCTSTR; -typedef wchar_t WCHAR; -typedef WCHAR OLECHAR; -typedef const WCHAR *LPCWSTR; -typedef OLECHAR *BSTR; -typedef const OLECHAR *LPCOLESTR; -typedef OLECHAR *LPOLESTR; - -typedef struct -{ - DWORD dwLowDateTime; - DWORD dwHighDateTime; -} FILETIME; - -#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) -#define FAILED(hr) ((HRESULT)(hr) < 0) -typedef ULONG PROPID; -typedef LONG SCODE; - - -#define S_OK ((HRESULT)0x00000000L) -#define S_FALSE ((HRESULT)0x00000001L) -#define E_NOTIMPL ((HRESULT)0x80004001L) -#define E_NOINTERFACE ((HRESULT)0x80004002L) -#define E_ABORT ((HRESULT)0x80004004L) -#define E_FAIL ((HRESULT)0x80004005L) -#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) -#define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L) - - -#ifdef _MSC_VER -#define STDMETHODCALLTYPE __stdcall -#define STDAPICALLTYPE __stdcall -#else -// do we need __export here? -#define STDMETHODCALLTYPE -#define STDAPICALLTYPE -#endif - -#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE - -#ifndef DECLSPEC_NOTHROW -#define DECLSPEC_NOTHROW Z7_DECLSPEC_NOTHROW -#endif - -#ifndef DECLSPEC_NOVTABLE -#define DECLSPEC_NOVTABLE Z7_DECLSPEC_NOVTABLE -#endif - -#ifndef COM_DECLSPEC_NOTHROW -#ifdef COM_STDMETHOD_CAN_THROW - #define COM_DECLSPEC_NOTHROW -#else - #define COM_DECLSPEC_NOTHROW DECLSPEC_NOTHROW -#endif -#endif - -#define DECLARE_INTERFACE(iface) struct DECLSPEC_NOVTABLE iface -#define DECLARE_INTERFACE_(iface, baseiface) struct DECLSPEC_NOVTABLE iface : public baseiface - -#define STDMETHOD_(t, f) virtual COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE f -#define STDMETHOD(f) STDMETHOD_(HRESULT, f) -#define STDMETHODIMP_(t) COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE -#define STDMETHODIMP STDMETHODIMP_(HRESULT) - - -#define PURE = 0 - -// #define MIDL_INTERFACE(x) struct - - -#ifdef __cplusplus - -/* - p7zip and 7-Zip before v23 used virtual destructor in IUnknown, - if _WIN32 is not defined. - It used virtual destructor, because some compilers don't like virtual - interfaces without virtual destructor. - IUnknown in Windows (_WIN32) doesn't use virtual destructor in IUnknown. - We still can define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here, - if we want to be compatible with old plugin interface of p7zip and 7-Zip before v23. - -v23: - In new 7-Zip v23 we try to be more compatible with original IUnknown from _WIN32. - So we do not define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here, -*/ -// #define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN - -#ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN -#if defined(__clang__) -#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" -#endif -#endif - -Z7_PURE_INTERFACES_BEGIN - -DEFINE_GUID(IID_IUnknown, -0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); -struct IUnknown -{ - STDMETHOD(QueryInterface) (REFIID iid, void **outObject) =0; - STDMETHOD_(ULONG, AddRef)() =0; - STDMETHOD_(ULONG, Release)() =0; - #ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN - virtual ~IUnknown() {} - #endif -}; - -typedef IUnknown *LPUNKNOWN; - -Z7_PURE_INTERFACES_END - -#endif // __cplusplus - -#define VARIANT_TRUE ((VARIANT_BOOL)-1) -#define VARIANT_FALSE ((VARIANT_BOOL)0) - -enum VARENUM -{ - VT_EMPTY = 0, - VT_NULL = 1, - VT_I2 = 2, - VT_I4 = 3, - VT_R4 = 4, - VT_R8 = 5, - VT_CY = 6, - VT_DATE = 7, - VT_BSTR = 8, - VT_DISPATCH = 9, - VT_ERROR = 10, - VT_BOOL = 11, - VT_VARIANT = 12, - VT_UNKNOWN = 13, - VT_DECIMAL = 14, - - VT_I1 = 16, - VT_UI1 = 17, - VT_UI2 = 18, - VT_UI4 = 19, - VT_I8 = 20, - VT_UI8 = 21, - VT_INT = 22, - VT_UINT = 23, - VT_VOID = 24, - VT_HRESULT = 25, - VT_FILETIME = 64 -}; - -typedef unsigned short VARTYPE; -typedef WORD PROPVAR_PAD1; -typedef WORD PROPVAR_PAD2; -typedef WORD PROPVAR_PAD3; - -typedef struct tagPROPVARIANT -{ - VARTYPE vt; - PROPVAR_PAD1 wReserved1; - PROPVAR_PAD2 wReserved2; - PROPVAR_PAD3 wReserved3; - union - { - CHAR cVal; - UCHAR bVal; - SHORT iVal; - USHORT uiVal; - LONG lVal; - ULONG ulVal; - INT intVal; - UINT uintVal; - LARGE_INTEGER hVal; - ULARGE_INTEGER uhVal; - VARIANT_BOOL boolVal; - SCODE scode; - FILETIME filetime; - BSTR bstrVal; - }; -} PROPVARIANT; - -typedef PROPVARIANT tagVARIANT; -typedef tagVARIANT VARIANT; -typedef VARIANT VARIANTARG; - -EXTERN_C HRESULT VariantClear(VARIANTARG *prop); -EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src); - -typedef struct tagSTATPROPSTG -{ - LPOLESTR lpwstrName; - PROPID propid; - VARTYPE vt; -} STATPROPSTG; - -EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); -EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len); -EXTERN_C BSTR SysAllocString(const OLECHAR *sz); -EXTERN_C void SysFreeString(BSTR bstr); -EXTERN_C UINT SysStringByteLen(BSTR bstr); -EXTERN_C UINT SysStringLen(BSTR bstr); - -EXTERN_C DWORD GetLastError(); -EXTERN_C void SetLastError(DWORD dwCode); -EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); - -EXTERN_C DWORD GetCurrentThreadId(); -EXTERN_C DWORD GetCurrentProcessId(); - -#define MAX_PATH 1024 - -#define CP_ACP 0 -#define CP_OEMCP 1 -#define CP_UTF8 65001 - -typedef enum tagSTREAM_SEEK -{ - STREAM_SEEK_SET = 0, - STREAM_SEEK_CUR = 1, - STREAM_SEEK_END = 2 -} STREAM_SEEK; - - - -typedef struct -{ - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; -} SYSTEMTIME; - -BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime); -BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime); -BOOL WINAPI FileTimeToSystemTime(const FILETIME *fileTime, SYSTEMTIME *systemTime); -// VOID WINAPI GetSystemTimeAsFileTime(FILETIME *systemTimeAsFileTime); - -DWORD GetTickCount(); - - -/* -#define CREATE_NEW 1 -#define CREATE_ALWAYS 2 -#define OPEN_EXISTING 3 -#define OPEN_ALWAYS 4 -#define TRUNCATE_EXISTING 5 -*/ - -#endif // _WIN32 - -#endif +// MyWindows.h + +#ifdef Z7_DEFINE_GUID +#undef Z7_DEFINE_GUID +#endif + +#ifdef INITGUID + #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name; \ + EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else + #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name +#endif + + +#ifndef ZIP7_INC_MY_WINDOWS_H +#define ZIP7_INC_MY_WINDOWS_H + +#ifdef _WIN32 + +#include "../../C/7zWindows.h" + +#else // _WIN32 + +#include // for wchar_t +#include +// #include // for uintptr_t + +#include "../../C/7zTypes.h" +#include "MyGuidDef.h" + +// WINAPI is __stdcall in Windows-MSVC in windef.h +#define WINAPI + +typedef char CHAR; +typedef unsigned char UCHAR; + +#undef BYTE +typedef unsigned char BYTE; + +typedef short SHORT; +typedef unsigned short USHORT; + +#undef WORD +typedef unsigned short WORD; +typedef short VARIANT_BOOL; + +#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) +#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) + +// MS uses long for BOOL, but long is 32-bit in MS. So we use int. +// typedef long BOOL; +typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 + #define TRUE 1 +#endif + +// typedef size_t ULONG_PTR; +// typedef size_t DWORD_PTR; +// typedef uintptr_t UINT_PTR; +// typedef ptrdiff_t UINT_PTR; + +typedef Int64 LONGLONG; +typedef UInt64 ULONGLONG; + +typedef struct { LONGLONG QuadPart; } LARGE_INTEGER; +typedef struct { ULONGLONG QuadPart; } ULARGE_INTEGER; + +typedef const CHAR *LPCSTR; +typedef CHAR TCHAR; +typedef const TCHAR *LPCTSTR; +typedef wchar_t WCHAR; +typedef WCHAR OLECHAR; +typedef const WCHAR *LPCWSTR; +typedef OLECHAR *BSTR; +typedef const OLECHAR *LPCOLESTR; +typedef OLECHAR *LPOLESTR; + +typedef struct +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME; + +#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) +#define FAILED(hr) ((HRESULT)(hr) < 0) +typedef ULONG PROPID; +typedef LONG SCODE; + + +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define E_NOTIMPL ((HRESULT)0x80004001L) +#define E_NOINTERFACE ((HRESULT)0x80004002L) +#define E_ABORT ((HRESULT)0x80004004L) +#define E_FAIL ((HRESULT)0x80004005L) +#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) +#define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L) + + +#ifdef _MSC_VER +#define STDMETHODCALLTYPE __stdcall +#define STDAPICALLTYPE __stdcall +#else +// do we need __export here? +#define STDMETHODCALLTYPE +#define STDAPICALLTYPE +#endif + +#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE + +#ifndef DECLSPEC_NOTHROW +#define DECLSPEC_NOTHROW Z7_DECLSPEC_NOTHROW +#endif + +#ifndef DECLSPEC_NOVTABLE +#define DECLSPEC_NOVTABLE Z7_DECLSPEC_NOVTABLE +#endif + +#ifndef COM_DECLSPEC_NOTHROW +#ifdef COM_STDMETHOD_CAN_THROW + #define COM_DECLSPEC_NOTHROW +#else + #define COM_DECLSPEC_NOTHROW DECLSPEC_NOTHROW +#endif +#endif + +#define DECLARE_INTERFACE(iface) struct DECLSPEC_NOVTABLE iface +#define DECLARE_INTERFACE_(iface, baseiface) struct DECLSPEC_NOVTABLE iface : public baseiface + +#define STDMETHOD_(t, f) virtual COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE f +#define STDMETHOD(f) STDMETHOD_(HRESULT, f) +#define STDMETHODIMP_(t) COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE +#define STDMETHODIMP STDMETHODIMP_(HRESULT) + + +#define PURE = 0 + +// #define MIDL_INTERFACE(x) struct + + +#ifdef __cplusplus + +/* + p7zip and 7-Zip before v23 used virtual destructor in IUnknown, + if _WIN32 is not defined. + It used virtual destructor, because some compilers don't like virtual + interfaces without virtual destructor. + IUnknown in Windows (_WIN32) doesn't use virtual destructor in IUnknown. + We still can define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here, + if we want to be compatible with old plugin interface of p7zip and 7-Zip before v23. + +v23: + In new 7-Zip v23 we try to be more compatible with original IUnknown from _WIN32. + So we do not define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here, +*/ +// #define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN + +#ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" +#endif +#endif + +Z7_PURE_INTERFACES_BEGIN + +DEFINE_GUID(IID_IUnknown, +0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +struct IUnknown +{ + STDMETHOD(QueryInterface) (REFIID iid, void **outObject) =0; + STDMETHOD_(ULONG, AddRef)() =0; + STDMETHOD_(ULONG, Release)() =0; + #ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN + virtual ~IUnknown() {} + #endif +}; + +typedef IUnknown *LPUNKNOWN; + +Z7_PURE_INTERFACES_END + +#endif // __cplusplus + +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#define VARIANT_FALSE ((VARIANT_BOOL)0) + +enum VARENUM +{ + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_FILETIME = 64 +}; + +typedef unsigned short VARTYPE; +typedef WORD PROPVAR_PAD1; +typedef WORD PROPVAR_PAD2; +typedef WORD PROPVAR_PAD3; + +typedef struct tagPROPVARIANT +{ + VARTYPE vt; + PROPVAR_PAD1 wReserved1; + PROPVAR_PAD2 wReserved2; + PROPVAR_PAD3 wReserved3; + union + { + CHAR cVal; + UCHAR bVal; + SHORT iVal; + USHORT uiVal; + LONG lVal; + ULONG ulVal; + INT intVal; + UINT uintVal; + LARGE_INTEGER hVal; + ULARGE_INTEGER uhVal; + VARIANT_BOOL boolVal; + SCODE scode; + FILETIME filetime; + BSTR bstrVal; + }; +} PROPVARIANT; + +typedef PROPVARIANT tagVARIANT; +typedef tagVARIANT VARIANT; +typedef VARIANT VARIANTARG; + +EXTERN_C HRESULT VariantClear(VARIANTARG *prop); +EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src); + +typedef struct tagSTATPROPSTG +{ + LPOLESTR lpwstrName; + PROPID propid; + VARTYPE vt; +} STATPROPSTG; + +EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); +EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len); +EXTERN_C BSTR SysAllocString(const OLECHAR *sz); +EXTERN_C void SysFreeString(BSTR bstr); +EXTERN_C UINT SysStringByteLen(BSTR bstr); +EXTERN_C UINT SysStringLen(BSTR bstr); + +EXTERN_C DWORD GetLastError(); +EXTERN_C void SetLastError(DWORD dwCode); +EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); + +EXTERN_C DWORD GetCurrentThreadId(); +EXTERN_C DWORD GetCurrentProcessId(); + +#define MAX_PATH 1024 + +#define CP_ACP 0 +#define CP_OEMCP 1 +#define CP_UTF8 65001 + +typedef enum tagSTREAM_SEEK +{ + STREAM_SEEK_SET = 0, + STREAM_SEEK_CUR = 1, + STREAM_SEEK_END = 2 +} STREAM_SEEK; + + + +typedef struct +{ + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; +} SYSTEMTIME; + +BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime); +BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime); +BOOL WINAPI FileTimeToSystemTime(const FILETIME *fileTime, SYSTEMTIME *systemTime); +// VOID WINAPI GetSystemTimeAsFileTime(FILETIME *systemTimeAsFileTime); + +DWORD GetTickCount(); + + +/* +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 +*/ + +#endif // _WIN32 + +#endif diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp index e7c01da47..cc891fc6c 100644 --- a/CPP/Common/MyXml.cpp +++ b/CPP/Common/MyXml.cpp @@ -1,349 +1,349 @@ -// MyXml.cpp - -#include "StdAfx.h" - -#include "MyXml.h" -#include "StringToInt.h" - -static bool IsValidChar(char c) -{ - return - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '-'; -} - -static bool IsSpaceChar(char c) -{ - return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A); -} - -#define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++; - -int CXmlItem::FindProp(const char *propName) const throw() -{ - FOR_VECTOR (i, Props) - if (Props[i].Name == propName) - return (int)i; - return -1; -} - -AString CXmlItem::GetPropVal(const char *propName) const -{ - const int index = FindProp(propName); - if (index >= 0) - return Props[(unsigned)index].Value; - return AString(); -} - -bool CXmlItem::IsTagged(const char *tag) const throw() -{ - return (IsTag && Name == tag); -} - -int CXmlItem::FindSubTag(const char *tag) const throw() -{ - FOR_VECTOR (i, SubItems) - if (SubItems[i].IsTagged(tag)) - return (int)i; - return -1; -} - -const CXmlItem *CXmlItem::FindSubTag_GetPtr(const char *tag) const throw() -{ - FOR_VECTOR (i, SubItems) - { - const CXmlItem *p = &SubItems[i]; - if (p->IsTagged(tag)) - return p; - } - return NULL; -} - -AString CXmlItem::GetSubString() const -{ - if (SubItems.Size() == 1) - { - const CXmlItem &item = SubItems[0]; - if (!item.IsTag) - return item.Name; - } - return AString(); -} - -const AString * CXmlItem::GetSubStringPtr() const throw() -{ - if (SubItems.Size() == 1) - { - const CXmlItem &item = SubItems[0]; - if (!item.IsTag) - return &item.Name; - } - return NULL; -} - -AString CXmlItem::GetSubStringForTag(const char *tag) const -{ - const CXmlItem *item = FindSubTag_GetPtr(tag); - if (item) - return item->GetSubString(); - return AString(); -} - -const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels) -{ - SKIP_SPACES(s) - - const char *beg = s; - for (;;) - { - char c; - c = *s; if (c == 0 || c == '<') break; s++; - c = *s; if (c == 0 || c == '<') break; s++; - } - if (*s == 0) - return NULL; - { - const size_t num = (size_t)(s - beg); - if (num) - { - IsTag = false; - Name.SetFrom_Chars_SizeT(beg, num); - return s; - } - } - - IsTag = true; - - s++; - SKIP_SPACES(s) - - beg = s; - for (;; s++) - if (!IsValidChar(*s)) - break; - if (s == beg || *s == 0) - return NULL; - Name.SetFrom_Chars_SizeT(beg, (size_t)(s - beg)); - - for (;;) - { - beg = s; - SKIP_SPACES(s) - if (*s == '/') - { - s++; - // SKIP_SPACES(s) - if (*s != '>') - return NULL; - return s + 1; - } - if (*s == '>') - { - s++; - if (numAllowedLevels == 0) - return NULL; - SubItems.Clear(); - for (;;) - { - SKIP_SPACES(s) - if (s[0] == '<' && s[1] == '/') - break; - CXmlItem &item = SubItems.AddNew(); - s = item.ParseItem(s, numAllowedLevels - 1); - if (!s) - return NULL; - } - - s += 2; - const unsigned len = Name.Len(); - const char *name = Name.Ptr(); - for (unsigned i = 0; i < len; i++) - if (*s++ != *name++) - return NULL; - // s += len; - if (s[0] != '>') - return NULL; - return s + 1; - } - if (beg == s) - return NULL; - - // ReadProperty - CXmlProp &prop = Props.AddNew(); - - beg = s; - for (;; s++) - { - char c = *s; - if (!IsValidChar(c)) - break; - } - if (s == beg) - return NULL; - prop.Name.SetFrom_Chars_SizeT(beg, (size_t)(s - beg)); - - SKIP_SPACES(s) - if (*s != '=') - return NULL; - s++; - SKIP_SPACES(s) - if (*s != '\"') - return NULL; - s++; - - beg = s; - for (;;) - { - char c = *s; - if (c == 0) - return NULL; - if (c == '\"') - break; - s++; - } - prop.Value.SetFrom_Chars_SizeT(beg, (size_t)(s - beg)); - s++; - } -} - -static const char * SkipHeader(const char *s, const char *startString, const char *endString) -{ - SKIP_SPACES(s) - if (IsString1PrefixedByString2(s, startString)) - { - s = strstr(s, endString); - if (!s) - return NULL; - s += strlen(endString); - } - return s; -} - -void CXmlItem::AppendTo(AString &s) const -{ - if (IsTag) - s += '<'; - s += Name; - if (IsTag) - { - FOR_VECTOR (i, Props) - { - const CXmlProp &prop = Props[i]; - s.Add_Space(); - s += prop.Name; - s += '='; - s += '\"'; - s += prop.Value; - s += '\"'; - } - s += '>'; - } - FOR_VECTOR (i, SubItems) - { - const CXmlItem &item = SubItems[i]; - if (i != 0 && !SubItems[i - 1].IsTag) - s.Add_Space(); - item.AppendTo(s); - } - if (IsTag) - { - s += '<'; - s += '/'; - s += Name; - s += '>'; - } -} - -bool CXml::Parse(const char *s) -{ - s = SkipHeader(s, ""); if (!s) return false; - s = SkipHeader(s, ""); if (!s) return false; - - s = Root.ParseItem(s, 1000); - if (!s || !Root.IsTag) - return false; - SKIP_SPACES(s) - return *s == 0; -} - -/* -void CXml::AppendTo(AString &s) const -{ - Root.AppendTo(s); -} -*/ - - -void z7_xml_DecodeString(AString &temp) -{ - char * const beg = temp.GetBuf(); - char *dest = beg; - const char *p = beg; - for (;;) - { - char c = *p++; - if (c == 0) - break; - if (c == '&') - { - if (p[0] == '#') - { - const char *end; - const UInt32 number = ConvertStringToUInt32(p + 1, &end); - if (*end == ';' && number != 0 && number <= 127) - { - p = end + 1; - c = (char)number; - } - } - else if ( - p[0] == 'a' && - p[1] == 'm' && - p[2] == 'p' && - p[3] == ';') - { - p += 4; - } - else if ( - p[0] == 'l' && - p[1] == 't' && - p[2] == ';') - { - p += 3; - c = '<'; - } - else if ( - p[0] == 'g' && - p[1] == 't' && - p[2] == ';') - { - p += 3; - c = '>'; - } - else if ( - p[0] == 'a' && - p[1] == 'p' && - p[2] == 'o' && - p[3] == 's' && - p[4] == ';') - { - p += 5; - c = '\''; - } - else if ( - p[0] == 'q' && - p[1] == 'u' && - p[2] == 'o' && - p[3] == 't' && - p[4] == ';') - { - p += 5; - c = '\"'; - } - } - *dest++ = c; - } - temp.ReleaseBuf_SetEnd((unsigned)(dest - beg)); -} +// MyXml.cpp + +#include "StdAfx.h" + +#include "MyXml.h" +#include "StringToInt.h" + +static bool IsValidChar(char c) +{ + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-'; +} + +static bool IsSpaceChar(char c) +{ + return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A); +} + +#define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++; + +int CXmlItem::FindProp(const char *propName) const throw() +{ + FOR_VECTOR (i, Props) + if (Props[i].Name == propName) + return (int)i; + return -1; +} + +AString CXmlItem::GetPropVal(const char *propName) const +{ + const int index = FindProp(propName); + if (index >= 0) + return Props[(unsigned)index].Value; + return AString(); +} + +bool CXmlItem::IsTagged(const char *tag) const throw() +{ + return (IsTag && Name == tag); +} + +int CXmlItem::FindSubTag(const char *tag) const throw() +{ + FOR_VECTOR (i, SubItems) + if (SubItems[i].IsTagged(tag)) + return (int)i; + return -1; +} + +const CXmlItem *CXmlItem::FindSubTag_GetPtr(const char *tag) const throw() +{ + FOR_VECTOR (i, SubItems) + { + const CXmlItem *p = &SubItems[i]; + if (p->IsTagged(tag)) + return p; + } + return NULL; +} + +AString CXmlItem::GetSubString() const +{ + if (SubItems.Size() == 1) + { + const CXmlItem &item = SubItems[0]; + if (!item.IsTag) + return item.Name; + } + return AString(); +} + +const AString * CXmlItem::GetSubStringPtr() const throw() +{ + if (SubItems.Size() == 1) + { + const CXmlItem &item = SubItems[0]; + if (!item.IsTag) + return &item.Name; + } + return NULL; +} + +AString CXmlItem::GetSubStringForTag(const char *tag) const +{ + const CXmlItem *item = FindSubTag_GetPtr(tag); + if (item) + return item->GetSubString(); + return AString(); +} + +const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels) +{ + SKIP_SPACES(s) + + const char *beg = s; + for (;;) + { + char c; + c = *s; if (c == 0 || c == '<') break; s++; + c = *s; if (c == 0 || c == '<') break; s++; + } + if (*s == 0) + return NULL; + { + const size_t num = (size_t)(s - beg); + if (num) + { + IsTag = false; + Name.SetFrom_Chars_SizeT(beg, num); + return s; + } + } + + IsTag = true; + + s++; + SKIP_SPACES(s) + + beg = s; + for (;; s++) + if (!IsValidChar(*s)) + break; + if (s == beg || *s == 0) + return NULL; + Name.SetFrom_Chars_SizeT(beg, (size_t)(s - beg)); + + for (;;) + { + beg = s; + SKIP_SPACES(s) + if (*s == '/') + { + s++; + // SKIP_SPACES(s) + if (*s != '>') + return NULL; + return s + 1; + } + if (*s == '>') + { + s++; + if (numAllowedLevels == 0) + return NULL; + SubItems.Clear(); + for (;;) + { + SKIP_SPACES(s) + if (s[0] == '<' && s[1] == '/') + break; + CXmlItem &item = SubItems.AddNew(); + s = item.ParseItem(s, numAllowedLevels - 1); + if (!s) + return NULL; + } + + s += 2; + const unsigned len = Name.Len(); + const char *name = Name.Ptr(); + for (unsigned i = 0; i < len; i++) + if (*s++ != *name++) + return NULL; + // s += len; + if (s[0] != '>') + return NULL; + return s + 1; + } + if (beg == s) + return NULL; + + // ReadProperty + CXmlProp &prop = Props.AddNew(); + + beg = s; + for (;; s++) + { + char c = *s; + if (!IsValidChar(c)) + break; + } + if (s == beg) + return NULL; + prop.Name.SetFrom_Chars_SizeT(beg, (size_t)(s - beg)); + + SKIP_SPACES(s) + if (*s != '=') + return NULL; + s++; + SKIP_SPACES(s) + if (*s != '\"') + return NULL; + s++; + + beg = s; + for (;;) + { + char c = *s; + if (c == 0) + return NULL; + if (c == '\"') + break; + s++; + } + prop.Value.SetFrom_Chars_SizeT(beg, (size_t)(s - beg)); + s++; + } +} + +static const char * SkipHeader(const char *s, const char *startString, const char *endString) +{ + SKIP_SPACES(s) + if (IsString1PrefixedByString2(s, startString)) + { + s = strstr(s, endString); + if (!s) + return NULL; + s += strlen(endString); + } + return s; +} + +void CXmlItem::AppendTo(AString &s) const +{ + if (IsTag) + s += '<'; + s += Name; + if (IsTag) + { + FOR_VECTOR (i, Props) + { + const CXmlProp &prop = Props[i]; + s.Add_Space(); + s += prop.Name; + s += '='; + s += '\"'; + s += prop.Value; + s += '\"'; + } + s += '>'; + } + FOR_VECTOR (i, SubItems) + { + const CXmlItem &item = SubItems[i]; + if (i != 0 && !SubItems[i - 1].IsTag) + s.Add_Space(); + item.AppendTo(s); + } + if (IsTag) + { + s += '<'; + s += '/'; + s += Name; + s += '>'; + } +} + +bool CXml::Parse(const char *s) +{ + s = SkipHeader(s, ""); if (!s) return false; + s = SkipHeader(s, ""); if (!s) return false; + + s = Root.ParseItem(s, 1000); + if (!s || !Root.IsTag) + return false; + SKIP_SPACES(s) + return *s == 0; +} + +/* +void CXml::AppendTo(AString &s) const +{ + Root.AppendTo(s); +} +*/ + + +void z7_xml_DecodeString(AString &temp) +{ + char * const beg = temp.GetBuf(); + char *dest = beg; + const char *p = beg; + for (;;) + { + char c = *p++; + if (c == 0) + break; + if (c == '&') + { + if (p[0] == '#') + { + const char *end; + const UInt32 number = ConvertStringToUInt32(p + 1, &end); + if (*end == ';' && number != 0 && number <= 127) + { + p = end + 1; + c = (char)number; + } + } + else if ( + p[0] == 'a' && + p[1] == 'm' && + p[2] == 'p' && + p[3] == ';') + { + p += 4; + } + else if ( + p[0] == 'l' && + p[1] == 't' && + p[2] == ';') + { + p += 3; + c = '<'; + } + else if ( + p[0] == 'g' && + p[1] == 't' && + p[2] == ';') + { + p += 3; + c = '>'; + } + else if ( + p[0] == 'a' && + p[1] == 'p' && + p[2] == 'o' && + p[3] == 's' && + p[4] == ';') + { + p += 5; + c = '\''; + } + else if ( + p[0] == 'q' && + p[1] == 'u' && + p[2] == 'o' && + p[3] == 't' && + p[4] == ';') + { + p += 5; + c = '\"'; + } + } + *dest++ = c; + } + temp.ReleaseBuf_SetEnd((unsigned)(dest - beg)); +} diff --git a/CPP/Common/MyXml.h b/CPP/Common/MyXml.h index 1450692d3..b22d7e40b 100644 --- a/CPP/Common/MyXml.h +++ b/CPP/Common/MyXml.h @@ -1,45 +1,45 @@ -// MyXml.h - -#ifndef ZIP7_INC_MY_XML_H -#define ZIP7_INC_MY_XML_H - -#include "MyString.h" - -struct CXmlProp -{ - AString Name; - AString Value; -}; - -class CXmlItem -{ -public: - AString Name; - bool IsTag; - CObjectVector Props; - CObjectVector SubItems; - - const char * ParseItem(const char *s, int numAllowedLevels); - - bool IsTagged(const char *tag) const throw(); - int FindProp(const char *propName) const throw(); - AString GetPropVal(const char *propName) const; - AString GetSubString() const; - const AString * GetSubStringPtr() const throw(); - int FindSubTag(const char *tag) const throw(); - const CXmlItem *FindSubTag_GetPtr(const char *tag) const throw(); - AString GetSubStringForTag(const char *tag) const; - void AppendTo(AString &s) const; -}; - -struct CXml -{ - CXmlItem Root; - - bool Parse(const char *s); - // void AppendTo(AString &s) const; -}; - -void z7_xml_DecodeString(AString &s); - -#endif +// MyXml.h + +#ifndef ZIP7_INC_MY_XML_H +#define ZIP7_INC_MY_XML_H + +#include "MyString.h" + +struct CXmlProp +{ + AString Name; + AString Value; +}; + +class CXmlItem +{ +public: + AString Name; + bool IsTag; + CObjectVector Props; + CObjectVector SubItems; + + const char * ParseItem(const char *s, int numAllowedLevels); + + bool IsTagged(const char *tag) const throw(); + int FindProp(const char *propName) const throw(); + AString GetPropVal(const char *propName) const; + AString GetSubString() const; + const AString * GetSubStringPtr() const throw(); + int FindSubTag(const char *tag) const throw(); + const CXmlItem *FindSubTag_GetPtr(const char *tag) const throw(); + AString GetSubStringForTag(const char *tag) const; + void AppendTo(AString &s) const; +}; + +struct CXml +{ + CXmlItem Root; + + bool Parse(const char *s); + // void AppendTo(AString &s) const; +}; + +void z7_xml_DecodeString(AString &s); + +#endif diff --git a/CPP/Common/NewHandler.cpp b/CPP/Common/NewHandler.cpp index 984197d51..173b8ebeb 100644 --- a/CPP/Common/NewHandler.cpp +++ b/CPP/Common/NewHandler.cpp @@ -1,340 +1,340 @@ -// NewHandler.cpp - -#include "StdAfx.h" - -#include - -#include "NewHandler.h" - -// #define DEBUG_MEMORY_LEAK - -#ifndef DEBUG_MEMORY_LEAK - -#ifdef Z7_REDEFINE_OPERATOR_NEW - -/* -void * my_new(size_t size) -{ - // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); - if (size == 0) - size = 1; - void *p = ::malloc(size); - if (!p) - throw CNewException(); - return p; -} - -void my_delete(void *p) throw() -{ - // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p); - ::free(p); -} - -void * my_Realloc(void *p, size_t newSize, size_t oldSize) -{ - void *newBuf = my_new(newSize); - if (oldSize != 0) - memcpy(newBuf, p, oldSize); - my_delete(p); - return newBuf; -} -*/ - -void * -#ifdef _MSC_VER -__cdecl -#endif -operator new(size_t size) -{ - /* by C++ specification: - if (size == 0), operator new(size) returns non_NULL pointer. - If (operator new(0) returns NULL), it's out of specification. - but some calling code can work correctly even in this case too. */ - // if (size == 0) return NULL; // for debug only. don't use it - - /* malloc(0) returns non_NULL in main compilers, as we need here. - But specification also allows malloc(0) to return NULL. - So we change (size=0) to (size=1) here to get real non_NULL pointer */ - if (size == 0) - size = 1; - // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); - // void *p = ::MyAlloc(size); // note: MyAlloc(0) returns NULL - void *p = ::malloc(size); - if (!p) - throw CNewException(); - return p; -} - - -#if defined(_MSC_VER) && _MSC_VER == 1600 -// vs2010 has no throw() by default ? -#pragma warning(push) -#pragma warning(disable : 4986) // 'operator delete': exception specification does not match previous declaration -#endif - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p) throw() -{ - // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p); - // MyFree(p); - ::free(p); -} - -/* we define operator delete(void *p, size_t n) because - vs2022 compiler uses delete(void *p, size_t n), and - we want to mix files from different compilers: - - old vc6 linker - - old vc6 complier - - new vs2022 complier -*/ -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p, size_t n) throw() -{ - UNUSED_VAR(n) - ::free(p); -} - -#if defined(_MSC_VER) && _MSC_VER == 1600 -#pragma warning(pop) -#endif - -/* -void * -#ifdef _MSC_VER -__cdecl -#endif -operator new[](size_t size) -{ - // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); - if (size == 0) - size = 1; - void *p = ::malloc(size); - if (!p) - throw CNewException(); - return p; -} - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete[](void *p) throw() -{ - // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p); - ::free(p); -} -*/ - -#endif - -#else - -#include - -// #pragma init_seg(lib) -/* -const int kDebugSize = 1000000; -static void *a[kDebugSize]; -static int g_index = 0; - -class CC -{ -public: - CC() - { - for (int i = 0; i < kDebugSize; i++) - a[i] = 0; - } - ~CC() - { - printf("\nDestructor: %d\n", numAllocs); - for (int i = 0; i < kDebugSize; i++) - if (a[i] != 0) - return; - } -} g_CC; -*/ - -#ifdef _WIN32 -static bool wasInit = false; -static CRITICAL_SECTION cs; -#endif - -static int numAllocs = 0; - -void * -#ifdef _MSC_VER -__cdecl -#endif -operator new(size_t size) -{ - #ifdef _WIN32 - if (!wasInit) - { - InitializeCriticalSection(&cs); - wasInit = true; - } - EnterCriticalSection(&cs); - - numAllocs++; - int loc = numAllocs; - void *p = HeapAlloc(GetProcessHeap(), 0, size); - /* - if (g_index < kDebugSize) - { - a[g_index] = p; - g_index++; - } - */ - printf("Alloc %6d, size = %8u\n", loc, (unsigned)size); - LeaveCriticalSection(&cs); - if (!p) - throw CNewException(); - return p; - #else - numAllocs++; - int loc = numAllocs; - if (size == 0) - size = 1; - void *p = malloc(size); - /* - if (g_index < kDebugSize) - { - a[g_index] = p; - g_index++; - } - */ - printf("Alloc %6d, size = %8u\n", loc, (unsigned)size); - if (!p) - throw CNewException(); - return p; - #endif -} - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p) throw() -{ - if (!p) - return; - #ifdef _WIN32 - EnterCriticalSection(&cs); - /* - for (int i = 0; i < g_index; i++) - if (a[i] == p) - a[i] = 0; - */ - HeapFree(GetProcessHeap(), 0, p); - // if (numAllocs == 0) numAllocs = numAllocs; // ERROR - numAllocs--; - // if (numAllocs == 0) numAllocs = numAllocs; // OK: all objects were deleted - printf("Free %d\n", numAllocs); - LeaveCriticalSection(&cs); - #else - free(p); - numAllocs--; - printf("Free %d\n", numAllocs); - #endif -} - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p, size_t n) throw(); -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p, size_t n) throw() -{ - UNUSED_VAR(n) - printf("delete_WITH_SIZE=%u, ptr = %p\n", (unsigned)n, p); - operator delete(p); -} - -/* -void * -#ifdef _MSC_VER -__cdecl -#endif -operator new[](size_t size) -{ - printf("operator_new[] : "); - return operator new(size); -} - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p, size_t sz) throw(); - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p, size_t sz) throw() -{ - if (!p) - return; - printf("operator_delete_size : size=%d : ", (unsigned)sz); - operator delete(p); -} - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete[](void *p) throw() -{ - if (!p) - return; - printf("operator_delete[] : "); - operator delete(p); -} - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete[](void *p, size_t sz) throw(); - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete[](void *p, size_t sz) throw() -{ - if (!p) - return; - printf("operator_delete_size[] : size=%d : ", (unsigned)sz); - operator delete(p); -} -*/ - -#endif - -/* -int MemErrorVC(size_t) -{ - throw CNewException(); - // return 1; -} -CNewHandlerSetter::CNewHandlerSetter() -{ - // MemErrorOldVCFunction = _set_new_handler(MemErrorVC); -} -CNewHandlerSetter::~CNewHandlerSetter() -{ - // _set_new_handler(MemErrorOldVCFunction); -} -*/ +// NewHandler.cpp + +#include "StdAfx.h" + +#include + +#include "NewHandler.h" + +// #define DEBUG_MEMORY_LEAK + +#ifndef DEBUG_MEMORY_LEAK + +#ifdef Z7_REDEFINE_OPERATOR_NEW + +/* +void * my_new(size_t size) +{ + // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); + if (size == 0) + size = 1; + void *p = ::malloc(size); + if (!p) + throw CNewException(); + return p; +} + +void my_delete(void *p) throw() +{ + // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p); + ::free(p); +} + +void * my_Realloc(void *p, size_t newSize, size_t oldSize) +{ + void *newBuf = my_new(newSize); + if (oldSize != 0) + memcpy(newBuf, p, oldSize); + my_delete(p); + return newBuf; +} +*/ + +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new(size_t size) +{ + /* by C++ specification: + if (size == 0), operator new(size) returns non_NULL pointer. + If (operator new(0) returns NULL), it's out of specification. + but some calling code can work correctly even in this case too. */ + // if (size == 0) return NULL; // for debug only. don't use it + + /* malloc(0) returns non_NULL in main compilers, as we need here. + But specification also allows malloc(0) to return NULL. + So we change (size=0) to (size=1) here to get real non_NULL pointer */ + if (size == 0) + size = 1; + // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); + // void *p = ::MyAlloc(size); // note: MyAlloc(0) returns NULL + void *p = ::malloc(size); + if (!p) + throw CNewException(); + return p; +} + + +#if defined(_MSC_VER) && _MSC_VER == 1600 +// vs2010 has no throw() by default ? +#pragma warning(push) +#pragma warning(disable : 4986) // 'operator delete': exception specification does not match previous declaration +#endif + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p) throw() +{ + // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p); + // MyFree(p); + ::free(p); +} + +/* we define operator delete(void *p, size_t n) because + vs2022 compiler uses delete(void *p, size_t n), and + we want to mix files from different compilers: + - old vc6 linker + - old vc6 complier + - new vs2022 complier +*/ +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t n) throw() +{ + UNUSED_VAR(n) + ::free(p); +} + +#if defined(_MSC_VER) && _MSC_VER == 1600 +#pragma warning(pop) +#endif + +/* +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new[](size_t size) +{ + // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); + if (size == 0) + size = 1; + void *p = ::malloc(size); + if (!p) + throw CNewException(); + return p; +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete[](void *p) throw() +{ + // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p); + ::free(p); +} +*/ + +#endif + +#else + +#include + +// #pragma init_seg(lib) +/* +const int kDebugSize = 1000000; +static void *a[kDebugSize]; +static int g_index = 0; + +class CC +{ +public: + CC() + { + for (int i = 0; i < kDebugSize; i++) + a[i] = 0; + } + ~CC() + { + printf("\nDestructor: %d\n", numAllocs); + for (int i = 0; i < kDebugSize; i++) + if (a[i] != 0) + return; + } +} g_CC; +*/ + +#ifdef _WIN32 +static bool wasInit = false; +static CRITICAL_SECTION cs; +#endif + +static int numAllocs = 0; + +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new(size_t size) +{ + #ifdef _WIN32 + if (!wasInit) + { + InitializeCriticalSection(&cs); + wasInit = true; + } + EnterCriticalSection(&cs); + + numAllocs++; + int loc = numAllocs; + void *p = HeapAlloc(GetProcessHeap(), 0, size); + /* + if (g_index < kDebugSize) + { + a[g_index] = p; + g_index++; + } + */ + printf("Alloc %6d, size = %8u\n", loc, (unsigned)size); + LeaveCriticalSection(&cs); + if (!p) + throw CNewException(); + return p; + #else + numAllocs++; + int loc = numAllocs; + if (size == 0) + size = 1; + void *p = malloc(size); + /* + if (g_index < kDebugSize) + { + a[g_index] = p; + g_index++; + } + */ + printf("Alloc %6d, size = %8u\n", loc, (unsigned)size); + if (!p) + throw CNewException(); + return p; + #endif +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p) throw() +{ + if (!p) + return; + #ifdef _WIN32 + EnterCriticalSection(&cs); + /* + for (int i = 0; i < g_index; i++) + if (a[i] == p) + a[i] = 0; + */ + HeapFree(GetProcessHeap(), 0, p); + // if (numAllocs == 0) numAllocs = numAllocs; // ERROR + numAllocs--; + // if (numAllocs == 0) numAllocs = numAllocs; // OK: all objects were deleted + printf("Free %d\n", numAllocs); + LeaveCriticalSection(&cs); + #else + free(p); + numAllocs--; + printf("Free %d\n", numAllocs); + #endif +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t n) throw(); +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t n) throw() +{ + UNUSED_VAR(n) + printf("delete_WITH_SIZE=%u, ptr = %p\n", (unsigned)n, p); + operator delete(p); +} + +/* +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new[](size_t size) +{ + printf("operator_new[] : "); + return operator new(size); +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t sz) throw(); + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t sz) throw() +{ + if (!p) + return; + printf("operator_delete_size : size=%d : ", (unsigned)sz); + operator delete(p); +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete[](void *p) throw() +{ + if (!p) + return; + printf("operator_delete[] : "); + operator delete(p); +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete[](void *p, size_t sz) throw(); + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete[](void *p, size_t sz) throw() +{ + if (!p) + return; + printf("operator_delete_size[] : size=%d : ", (unsigned)sz); + operator delete(p); +} +*/ + +#endif + +/* +int MemErrorVC(size_t) +{ + throw CNewException(); + // return 1; +} +CNewHandlerSetter::CNewHandlerSetter() +{ + // MemErrorOldVCFunction = _set_new_handler(MemErrorVC); +} +CNewHandlerSetter::~CNewHandlerSetter() +{ + // _set_new_handler(MemErrorOldVCFunction); +} +*/ diff --git a/CPP/Common/NewHandler.h b/CPP/Common/NewHandler.h index 0a857f4c8..5ba64b7d4 100644 --- a/CPP/Common/NewHandler.h +++ b/CPP/Common/NewHandler.h @@ -1,121 +1,121 @@ -// Common/NewHandler.h - -#ifndef ZIP7_INC_COMMON_NEW_HANDLER_H -#define ZIP7_INC_COMMON_NEW_HANDLER_H - -/* -NewHandler.h and NewHandler.cpp allows to solve problem with compilers that -don't throw exception in operator new(). - -This file must be included before any code that uses operators new() or delete() -and you must compile and link "NewHandler.cpp", if you use some old MSVC compiler. - -DOCs: - Since ISO C++98, operator new throws std::bad_alloc when memory allocation fails. - MSVC 6.0 returned a null pointer on an allocation failure. - Beginning in VS2002, operator new conforms to the standard and throws on failure. - - By default, the compiler also generates defensive null checks to prevent - these older-style allocators from causing an immediate crash on failure. - The /Zc:throwingNew option tells the compiler to leave out these null checks, - on the assumption that all linked memory allocators conform to the standard. - -The operator new() in some MSVC versions doesn't throw exception std::bad_alloc. -MSVC 6.0 (_MSC_VER == 1200) doesn't throw exception. -The code produced by some another MSVC compilers also can be linked -to library that doesn't throw exception. -We suppose that code compiled with VS2015+ (_MSC_VER >= 1900) throws exception std::bad_alloc. -For older _MSC_VER versions we redefine operator new() and operator delete(). -Our version of operator new() throws CNewException() exception on failure. - -It's still allowed to use redefined version of operator new() from "NewHandler.cpp" -with any compiler. 7-Zip's code can work with std::bad_alloc and CNewException() exceptions. -But if you use some additional code (outside of 7-Zip's code), you must check -that redefined version of operator new() is not problem for your code. -*/ - -#include - -#ifdef _WIN32 -// We can compile my_new and my_delete with _fastcall -/* -void * my_new(size_t size); -void my_delete(void *p) throw(); -// void * my_Realloc(void *p, size_t newSize, size_t oldSize); -*/ -#endif - - -#if defined(_MSC_VER) && (_MSC_VER < 1600) - // If you want to use default operator new(), you can disable the following line - #define Z7_REDEFINE_OPERATOR_NEW -#endif - - -#ifdef Z7_REDEFINE_OPERATOR_NEW - -// std::bad_alloc can require additional DLL dependency. -// So we don't define CNewException as std::bad_alloc here. - -class CNewException {}; - -void * -#ifdef _MSC_VER -__cdecl -#endif -operator new(size_t size); - -/* -#if 0 && defined(_MSC_VER) && _MSC_VER == 1600 - #define Z7_OPERATOR_DELETE_SPEC_THROW0 -#else - #define Z7_OPERATOR_DELETE_SPEC_THROW0 throw() -#endif -*/ -#if defined(_MSC_VER) && _MSC_VER == 1600 -#pragma warning(push) -#pragma warning(disable : 4986) // 'operator delete': exception specification does not match previous declaration -#endif - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p) throw(); - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete(void *p, size_t n) throw(); - -#if defined(_MSC_VER) && _MSC_VER == 1600 -#pragma warning(pop) -#endif - - -#else - -#include - -#define CNewException std::bad_alloc - -#endif - -/* -#ifdef _WIN32 -void * -#ifdef _MSC_VER -__cdecl -#endif -operator new[](size_t size); - -void -#ifdef _MSC_VER -__cdecl -#endif -operator delete[](void *p) throw(); -#endif -*/ - -#endif +// Common/NewHandler.h + +#ifndef ZIP7_INC_COMMON_NEW_HANDLER_H +#define ZIP7_INC_COMMON_NEW_HANDLER_H + +/* +NewHandler.h and NewHandler.cpp allows to solve problem with compilers that +don't throw exception in operator new(). + +This file must be included before any code that uses operators new() or delete() +and you must compile and link "NewHandler.cpp", if you use some old MSVC compiler. + +DOCs: + Since ISO C++98, operator new throws std::bad_alloc when memory allocation fails. + MSVC 6.0 returned a null pointer on an allocation failure. + Beginning in VS2002, operator new conforms to the standard and throws on failure. + + By default, the compiler also generates defensive null checks to prevent + these older-style allocators from causing an immediate crash on failure. + The /Zc:throwingNew option tells the compiler to leave out these null checks, + on the assumption that all linked memory allocators conform to the standard. + +The operator new() in some MSVC versions doesn't throw exception std::bad_alloc. +MSVC 6.0 (_MSC_VER == 1200) doesn't throw exception. +The code produced by some another MSVC compilers also can be linked +to library that doesn't throw exception. +We suppose that code compiled with VS2015+ (_MSC_VER >= 1900) throws exception std::bad_alloc. +For older _MSC_VER versions we redefine operator new() and operator delete(). +Our version of operator new() throws CNewException() exception on failure. + +It's still allowed to use redefined version of operator new() from "NewHandler.cpp" +with any compiler. 7-Zip's code can work with std::bad_alloc and CNewException() exceptions. +But if you use some additional code (outside of 7-Zip's code), you must check +that redefined version of operator new() is not problem for your code. +*/ + +#include + +#ifdef _WIN32 +// We can compile my_new and my_delete with _fastcall +/* +void * my_new(size_t size); +void my_delete(void *p) throw(); +// void * my_Realloc(void *p, size_t newSize, size_t oldSize); +*/ +#endif + + +#if defined(_MSC_VER) && (_MSC_VER < 1600) + // If you want to use default operator new(), you can disable the following line + #define Z7_REDEFINE_OPERATOR_NEW +#endif + + +#ifdef Z7_REDEFINE_OPERATOR_NEW + +// std::bad_alloc can require additional DLL dependency. +// So we don't define CNewException as std::bad_alloc here. + +class CNewException {}; + +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new(size_t size); + +/* +#if 0 && defined(_MSC_VER) && _MSC_VER == 1600 + #define Z7_OPERATOR_DELETE_SPEC_THROW0 +#else + #define Z7_OPERATOR_DELETE_SPEC_THROW0 throw() +#endif +*/ +#if defined(_MSC_VER) && _MSC_VER == 1600 +#pragma warning(push) +#pragma warning(disable : 4986) // 'operator delete': exception specification does not match previous declaration +#endif + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p) throw(); + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t n) throw(); + +#if defined(_MSC_VER) && _MSC_VER == 1600 +#pragma warning(pop) +#endif + + +#else + +#include + +#define CNewException std::bad_alloc + +#endif + +/* +#ifdef _WIN32 +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new[](size_t size); + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete[](void *p) throw(); +#endif +*/ + +#endif diff --git a/CPP/Common/Random.cpp b/CPP/Common/Random.cpp index 598eba1b8..6ef9f1af5 100644 --- a/CPP/Common/Random.cpp +++ b/CPP/Common/Random.cpp @@ -1,28 +1,28 @@ -// Common/Random.cpp - -#include "StdAfx.h" - -#include - -#ifndef _WIN32 -#include -#else -#include "MyWindows.h" -#endif - -#include "Random.h" - -void CRandom::Init(unsigned seed) { srand(seed); } - -void CRandom::Init() -{ - Init((unsigned) - #ifdef _WIN32 - GetTickCount() - #else - time(NULL) - #endif - ); -} - -int CRandom::Generate() const { return rand(); } +// Common/Random.cpp + +#include "StdAfx.h" + +#include + +#ifndef _WIN32 +#include +#else +#include "MyWindows.h" +#endif + +#include "Random.h" + +void CRandom::Init(unsigned seed) { srand(seed); } + +void CRandom::Init() +{ + Init((unsigned) + #ifdef _WIN32 + GetTickCount() + #else + time(NULL) + #endif + ); +} + +int CRandom::Generate() const { return rand(); } diff --git a/CPP/Common/Random.h b/CPP/Common/Random.h index 9c2d9acdc..3fbb416a7 100644 --- a/CPP/Common/Random.h +++ b/CPP/Common/Random.h @@ -1,14 +1,14 @@ -// Common/Random.h - -#ifndef ZIP7_INC_COMMON_RANDOM_H -#define ZIP7_INC_COMMON_RANDOM_H - -class CRandom -{ -public: - void Init(); - void Init(unsigned seed); - int Generate() const; -}; - -#endif +// Common/Random.h + +#ifndef ZIP7_INC_COMMON_RANDOM_H +#define ZIP7_INC_COMMON_RANDOM_H + +class CRandom +{ +public: + void Init(); + void Init(unsigned seed); + int Generate() const; +}; + +#endif diff --git a/CPP/Common/Sha1Prepare.cpp b/CPP/Common/Sha1Prepare.cpp index 2adbfdeb1..2652f009b 100644 --- a/CPP/Common/Sha1Prepare.cpp +++ b/CPP/Common/Sha1Prepare.cpp @@ -1,7 +1,7 @@ -// Sha1Prepare.cpp - -#include "StdAfx.h" - -#include "../../C/Sha1.h" - -static struct CSha1Prepare { CSha1Prepare() { Sha1Prepare(); } } g_Sha1Prepare; +// Sha1Prepare.cpp + +#include "StdAfx.h" + +#include "../../C/Sha1.h" + +static struct CSha1Prepare { CSha1Prepare() { Sha1Prepare(); } } g_Sha1Prepare; diff --git a/CPP/Common/Sha1Reg.cpp b/CPP/Common/Sha1Reg.cpp index db16faf72..64eef34a9 100644 --- a/CPP/Common/Sha1Reg.cpp +++ b/CPP/Common/Sha1Reg.cpp @@ -1,67 +1,67 @@ -// Sha1Reg.cpp - -#include "StdAfx.h" - -#include "../../C/Sha1.h" - -#include "../Common/MyBuffer2.h" -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" - -Z7_CLASS_IMP_COM_2( - CSha1Hasher - , IHasher - , ICompressSetCoderProperties -) - CAlignedBuffer1 _buf; -public: - Byte _mtDummy[1 << 7]; - - CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_buf; } -public: - CSha1Hasher(): - _buf(sizeof(CSha1)) - { - Sha1_SetFunction(Sha(), 0); - Sha1_InitState(Sha()); - } -}; - -Z7_COM7F_IMF2(void, CSha1Hasher::Init()) -{ - Sha1_InitState(Sha()); -} - -Z7_COM7F_IMF2(void, CSha1Hasher::Update(const void *data, UInt32 size)) -{ - Sha1_Update(Sha(), (const Byte *)data, size); -} - -Z7_COM7F_IMF2(void, CSha1Hasher::Final(Byte *digest)) -{ - Sha1_Final(Sha(), digest); -} - - -Z7_COM7F_IMF(CSha1Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - unsigned algo = 0; - for (UInt32 i = 0; i < numProps; i++) - { - if (propIDs[i] == NCoderPropID::kDefaultProp) - { - const PROPVARIANT &prop = coderProps[i]; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - if (prop.ulVal > 2) - return E_NOTIMPL; - algo = (unsigned)prop.ulVal; - } - } - if (!Sha1_SetFunction(Sha(), algo)) - return E_NOTIMPL; - return S_OK; -} - -REGISTER_HASHER(CSha1Hasher, 0x201, "SHA1", SHA1_DIGEST_SIZE) +// Sha1Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Sha1.h" + +#include "../Common/MyBuffer2.h" +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_2( + CSha1Hasher + , IHasher + , ICompressSetCoderProperties +) + CAlignedBuffer1 _buf; +public: + Byte _mtDummy[1 << 7]; + + CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_buf; } +public: + CSha1Hasher(): + _buf(sizeof(CSha1)) + { + Sha1_SetFunction(Sha(), 0); + Sha1_InitState(Sha()); + } +}; + +Z7_COM7F_IMF2(void, CSha1Hasher::Init()) +{ + Sha1_InitState(Sha()); +} + +Z7_COM7F_IMF2(void, CSha1Hasher::Update(const void *data, UInt32 size)) +{ + Sha1_Update(Sha(), (const Byte *)data, size); +} + +Z7_COM7F_IMF2(void, CSha1Hasher::Final(Byte *digest)) +{ + Sha1_Final(Sha(), digest); +} + + +Z7_COM7F_IMF(CSha1Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + unsigned algo = 0; + for (UInt32 i = 0; i < numProps; i++) + { + if (propIDs[i] == NCoderPropID::kDefaultProp) + { + const PROPVARIANT &prop = coderProps[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + if (prop.ulVal > 2) + return E_NOTIMPL; + algo = (unsigned)prop.ulVal; + } + } + if (!Sha1_SetFunction(Sha(), algo)) + return E_NOTIMPL; + return S_OK; +} + +REGISTER_HASHER(CSha1Hasher, 0x201, "SHA1", SHA1_DIGEST_SIZE) diff --git a/CPP/Common/Sha256Prepare.cpp b/CPP/Common/Sha256Prepare.cpp index d670d8612..1ec242b57 100644 --- a/CPP/Common/Sha256Prepare.cpp +++ b/CPP/Common/Sha256Prepare.cpp @@ -1,7 +1,7 @@ -// Sha256Prepare.cpp - -#include "StdAfx.h" - -#include "../../C/Sha256.h" - -static struct CSha256Prepare { CSha256Prepare() { Sha256Prepare(); } } g_Sha256Prepare; +// Sha256Prepare.cpp + +#include "StdAfx.h" + +#include "../../C/Sha256.h" + +static struct CSha256Prepare { CSha256Prepare() { Sha256Prepare(); } } g_Sha256Prepare; diff --git a/CPP/Common/Sha256Reg.cpp b/CPP/Common/Sha256Reg.cpp index c0e88fed8..b5689c42d 100644 --- a/CPP/Common/Sha256Reg.cpp +++ b/CPP/Common/Sha256Reg.cpp @@ -1,67 +1,67 @@ -// Sha256Reg.cpp - -#include "StdAfx.h" - -#include "../../C/Sha256.h" - -#include "../Common/MyBuffer2.h" -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" - -Z7_CLASS_IMP_COM_2( - CSha256Hasher - , IHasher - , ICompressSetCoderProperties -) - CAlignedBuffer1 _buf; -public: - Byte _mtDummy[1 << 7]; - - CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_buf; } -public: - CSha256Hasher(): - _buf(sizeof(CSha256)) - { - Sha256_SetFunction(Sha(), 0); - Sha256_InitState(Sha()); - } -}; - -Z7_COM7F_IMF2(void, CSha256Hasher::Init()) -{ - Sha256_InitState(Sha()); -} - -Z7_COM7F_IMF2(void, CSha256Hasher::Update(const void *data, UInt32 size)) -{ - Sha256_Update(Sha(), (const Byte *)data, size); -} - -Z7_COM7F_IMF2(void, CSha256Hasher::Final(Byte *digest)) -{ - Sha256_Final(Sha(), digest); -} - - -Z7_COM7F_IMF(CSha256Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) -{ - unsigned algo = 0; - for (UInt32 i = 0; i < numProps; i++) - { - if (propIDs[i] == NCoderPropID::kDefaultProp) - { - const PROPVARIANT &prop = coderProps[i]; - if (prop.vt != VT_UI4) - return E_INVALIDARG; - if (prop.ulVal > 2) - return E_NOTIMPL; - algo = (unsigned)prop.ulVal; - } - } - if (!Sha256_SetFunction(Sha(), algo)) - return E_NOTIMPL; - return S_OK; -} - -REGISTER_HASHER(CSha256Hasher, 0xA, "SHA256", SHA256_DIGEST_SIZE) +// Sha256Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Sha256.h" + +#include "../Common/MyBuffer2.h" +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_2( + CSha256Hasher + , IHasher + , ICompressSetCoderProperties +) + CAlignedBuffer1 _buf; +public: + Byte _mtDummy[1 << 7]; + + CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_buf; } +public: + CSha256Hasher(): + _buf(sizeof(CSha256)) + { + Sha256_SetFunction(Sha(), 0); + Sha256_InitState(Sha()); + } +}; + +Z7_COM7F_IMF2(void, CSha256Hasher::Init()) +{ + Sha256_InitState(Sha()); +} + +Z7_COM7F_IMF2(void, CSha256Hasher::Update(const void *data, UInt32 size)) +{ + Sha256_Update(Sha(), (const Byte *)data, size); +} + +Z7_COM7F_IMF2(void, CSha256Hasher::Final(Byte *digest)) +{ + Sha256_Final(Sha(), digest); +} + + +Z7_COM7F_IMF(CSha256Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + unsigned algo = 0; + for (UInt32 i = 0; i < numProps; i++) + { + if (propIDs[i] == NCoderPropID::kDefaultProp) + { + const PROPVARIANT &prop = coderProps[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + if (prop.ulVal > 2) + return E_NOTIMPL; + algo = (unsigned)prop.ulVal; + } + } + if (!Sha256_SetFunction(Sha(), algo)) + return E_NOTIMPL; + return S_OK; +} + +REGISTER_HASHER(CSha256Hasher, 0xA, "SHA256", SHA256_DIGEST_SIZE) diff --git a/CPP/Common/Sha3Reg.cpp b/CPP/Common/Sha3Reg.cpp new file mode 100644 index 000000000..95db25e70 --- /dev/null +++ b/CPP/Common/Sha3Reg.cpp @@ -0,0 +1,76 @@ +// Sha3Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Sha3.h" + +#include "../Common/MyBuffer2.h" +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_1( + CSha3Hasher + , IHasher +) + unsigned _digestSize; + bool _isShake; + CAlignedBuffer1 _buf; +public: + Byte _mtDummy[1 << 7]; + + CSha3 *Sha() { return (CSha3 *)(void *)(Byte *)_buf; } +public: + CSha3Hasher(unsigned digestSize, bool isShake, unsigned blockSize): + _digestSize(digestSize), + _isShake(isShake), + _buf(sizeof(CSha3)) + { + CSha3 *p = Sha(); + Sha3_SET_blockSize(p, blockSize) + Sha3_Init(Sha()); + } +}; + +Z7_COM7F_IMF2(void, CSha3Hasher::Init()) +{ + Sha3_Init(Sha()); +} + +Z7_COM7F_IMF2(void, CSha3Hasher::Update(const void *data, UInt32 size)) +{ + Sha3_Update(Sha(), (const Byte *)data, size); +} + +Z7_COM7F_IMF2(void, CSha3Hasher::Final(Byte *digest)) +{ + Sha3_Final(Sha(), digest, _digestSize, _isShake); +} + +Z7_COM7F_IMF2(UInt32, CSha3Hasher::GetDigestSize()) +{ + return (UInt32)_digestSize; +} + + +#define REGISTER_SHA3_HASHER_2(cls, id, name, digestSize, isShake, digestSize_for_blockSize) \ + namespace N ## cls { \ + static IHasher *CreateHasherSpec() \ + { return new CSha3Hasher(digestSize / 8, isShake, \ + SHA3_BLOCK_SIZE_FROM_DIGEST_SIZE(digestSize_for_blockSize / 8)); } \ + static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, digestSize }; \ + struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ + static REGISTER_HASHER_NAME(cls) g_RegisterHasher; } + +#define REGISTER_SHA3_HASHER( cls, id, name, size, isShake) \ + REGISTER_SHA3_HASHER_2(cls, id, name, size, isShake, size) + +// REGISTER_SHA3_HASHER (Sha3_224_Hasher, 0x230, "SHA3-224", 224, false) +REGISTER_SHA3_HASHER (Sha3_256_Hasher, 0x231, "SHA3-256", 256, false) +// REGISTER_SHA3_HASHER (Sha3_386_Hasher, 0x232, "SHA3-384", 384, false) +// REGISTER_SHA3_HASHER (Sha3_512_Hasher, 0x233, "SHA3-512", 512, false) +// REGISTER_SHA3_HASHER (Shake128_Hasher, 0x240, "SHAKE128", 128, true) +// REGISTER_SHA3_HASHER (Shake256_Hasher, 0x241, "SHAKE256", 256, true) +// REGISTER_SHA3_HASHER_2 (Shake128_512_Hasher, 0x248, "SHAKE128-256", 256, true, 128) // -1344 (max) +// REGISTER_SHA3_HASHER_2 (Shake256_512_Hasher, 0x249, "SHAKE256-512", 512, true, 256) // -1088 (max) +// Shake supports different digestSize values for same blockSize diff --git a/CPP/Common/Sha512Prepare.cpp b/CPP/Common/Sha512Prepare.cpp new file mode 100644 index 000000000..e7beff518 --- /dev/null +++ b/CPP/Common/Sha512Prepare.cpp @@ -0,0 +1,7 @@ +// Sha512Prepare.cpp + +#include "StdAfx.h" + +#include "../../C/Sha512.h" + +static struct CSha512Prepare { CSha512Prepare() { Sha512Prepare(); } } g_Sha512Prepare; diff --git a/CPP/Common/Sha512Reg.cpp b/CPP/Common/Sha512Reg.cpp new file mode 100644 index 000000000..21df6baaa --- /dev/null +++ b/CPP/Common/Sha512Reg.cpp @@ -0,0 +1,83 @@ +// Sha512Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Sha512.h" + +#include "../Common/MyBuffer2.h" +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_2( + CSha512Hasher + , IHasher + , ICompressSetCoderProperties +) + unsigned _digestSize; + CAlignedBuffer1 _buf; +public: + Byte _mtDummy[1 << 7]; + + CSha512 *Sha() { return (CSha512 *)(void *)(Byte *)_buf; } +public: + CSha512Hasher(unsigned digestSize): + _digestSize(digestSize), + _buf(sizeof(CSha512)) + { + Sha512_SetFunction(Sha(), 0); + Sha512_InitState(Sha(), _digestSize); + } +}; + +Z7_COM7F_IMF2(void, CSha512Hasher::Init()) +{ + Sha512_InitState(Sha(), _digestSize); +} + +Z7_COM7F_IMF2(void, CSha512Hasher::Update(const void *data, UInt32 size)) +{ + Sha512_Update(Sha(), (const Byte *)data, size); +} + +Z7_COM7F_IMF2(void, CSha512Hasher::Final(Byte *digest)) +{ + Sha512_Final(Sha(), digest, _digestSize); +} + +Z7_COM7F_IMF2(UInt32, CSha512Hasher::GetDigestSize()) +{ + return (UInt32)_digestSize; +} + +Z7_COM7F_IMF(CSha512Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)) +{ + unsigned algo = 0; + for (UInt32 i = 0; i < numProps; i++) + { + if (propIDs[i] == NCoderPropID::kDefaultProp) + { + const PROPVARIANT &prop = coderProps[i]; + if (prop.vt != VT_UI4) + return E_INVALIDARG; + if (prop.ulVal > 2) + return E_NOTIMPL; + algo = (unsigned)prop.ulVal; + } + } + if (!Sha512_SetFunction(Sha(), algo)) + return E_NOTIMPL; + return S_OK; +} + +#define REGISTER_SHA512_HASHER(cls, id, name, size) \ + namespace N ## cls { \ + static IHasher *CreateHasherSpec() { return new CSha512Hasher(size); } \ + static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \ + struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \ + static REGISTER_HASHER_NAME(cls) g_RegisterHasher; } + +// REGISTER_SHA512_HASHER (Sha512_224_Hasher, 0x220, "SHA512-224", SHA512_224_DIGEST_SIZE) +// REGISTER_SHA512_HASHER (Sha512_256_Hasher, 0x221, "SHA512-256", SHA512_256_DIGEST_SIZE) +REGISTER_SHA512_HASHER (Sha384Hasher, 0x222, "SHA384", SHA512_384_DIGEST_SIZE) +REGISTER_SHA512_HASHER (Sha512Hasher, 0x223, "SHA512", SHA512_DIGEST_SIZE) diff --git a/CPP/Common/StdAfx.h b/CPP/Common/StdAfx.h index 4e27aa3d2..a5228b0a6 100644 --- a/CPP/Common/StdAfx.h +++ b/CPP/Common/StdAfx.h @@ -1,8 +1,8 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#include "Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#include "Common.h" + +#endif diff --git a/CPP/Common/StdInStream.cpp b/CPP/Common/StdInStream.cpp index c89e4c6fa..944be344d 100644 --- a/CPP/Common/StdInStream.cpp +++ b/CPP/Common/StdInStream.cpp @@ -1,98 +1,98 @@ -// Common/StdInStream.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include -#endif - -#include "StdInStream.h" -#include "StringConvert.h" -#include "UTFConvert.h" - -// #define kEOFMessage "Unexpected end of input stream" -// #define kReadErrorMessage "Error reading input stream" -// #define kIllegalCharMessage "Illegal zero character in input stream" - - -CStdInStream g_StdIn(stdin); - -/* -#define kFileOpenMode TEXT("r") - -bool CStdInStream::Open(LPCTSTR fileName) throw() -{ - Close(); - _stream = - #ifdef _WIN32 - _tfopen - #else - fopen - #endif - (fileName, kFileOpenMode); - _streamIsOpen = (_stream != 0); - return _streamIsOpen; -} - -bool CStdInStream::Close() throw() -{ - if (!_streamIsOpen) - return true; - _streamIsOpen = (fclose(_stream) != 0); - return !_streamIsOpen; -} -*/ - -bool CStdInStream::ScanAStringUntilNewLine(AString &s) -{ - s.Empty(); - for (;;) - { - const int intChar = GetChar(); - if (intChar == EOF) - return true; - const char c = (char)intChar; - if (c == 0) - return false; - if (c == '\n') - return true; - s.Add_Char(c); - } -} - -bool CStdInStream::ScanUStringUntilNewLine(UString &dest) -{ - dest.Empty(); - AString s; - const bool res = ScanAStringUntilNewLine(s); - int codePage = CodePage; - if (codePage == -1) - codePage = CP_OEMCP; - if ((unsigned)codePage == CP_UTF8) - ConvertUTF8ToUnicode(s, dest); - else - MultiByteToUnicodeString2(dest, s, (UINT)(unsigned)codePage); - return res; -} - -/* -bool CStdInStream::ReadToString(AString &resultString) -{ - resultString.Empty(); - for (;;) - { - int intChar = GetChar(); - if (intChar == EOF) - return !Error(); - char c = (char)intChar; - if (c == 0) - return false; - resultString += c; - } -} -*/ - -int CStdInStream::GetChar() -{ - return fgetc(_stream); // getc() doesn't work in BeOS? -} +// Common/StdInStream.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include +#endif + +#include "StdInStream.h" +#include "StringConvert.h" +#include "UTFConvert.h" + +// #define kEOFMessage "Unexpected end of input stream" +// #define kReadErrorMessage "Error reading input stream" +// #define kIllegalCharMessage "Illegal zero character in input stream" + + +CStdInStream g_StdIn(stdin); + +/* +#define kFileOpenMode TEXT("r") + +bool CStdInStream::Open(LPCTSTR fileName) throw() +{ + Close(); + _stream = + #ifdef _WIN32 + _tfopen + #else + fopen + #endif + (fileName, kFileOpenMode); + _streamIsOpen = (_stream != 0); + return _streamIsOpen; +} + +bool CStdInStream::Close() throw() +{ + if (!_streamIsOpen) + return true; + _streamIsOpen = (fclose(_stream) != 0); + return !_streamIsOpen; +} +*/ + +bool CStdInStream::ScanAStringUntilNewLine(AString &s) +{ + s.Empty(); + for (;;) + { + const int intChar = GetChar(); + if (intChar == EOF) + return true; + const char c = (char)intChar; + if (c == 0) + return false; + if (c == '\n') + return true; + s.Add_Char(c); + } +} + +bool CStdInStream::ScanUStringUntilNewLine(UString &dest) +{ + dest.Empty(); + AString s; + const bool res = ScanAStringUntilNewLine(s); + int codePage = CodePage; + if (codePage == -1) + codePage = CP_OEMCP; + if ((unsigned)codePage == CP_UTF8) + ConvertUTF8ToUnicode(s, dest); + else + MultiByteToUnicodeString2(dest, s, (UINT)(unsigned)codePage); + return res; +} + +/* +bool CStdInStream::ReadToString(AString &resultString) +{ + resultString.Empty(); + for (;;) + { + int intChar = GetChar(); + if (intChar == EOF) + return !Error(); + char c = (char)intChar; + if (c == 0) + return false; + resultString += c; + } +} +*/ + +int CStdInStream::GetChar() +{ + return fgetc(_stream); // getc() doesn't work in BeOS? +} diff --git a/CPP/Common/StdInStream.h b/CPP/Common/StdInStream.h index 2253c4312..81ca3bf6f 100644 --- a/CPP/Common/StdInStream.h +++ b/CPP/Common/StdInStream.h @@ -1,46 +1,46 @@ -// Common/StdInStream.h - -#ifndef ZIP7_INC_COMMON_STD_IN_STREAM_H -#define ZIP7_INC_COMMON_STD_IN_STREAM_H - -#include - -#include "MyString.h" -#include "MyTypes.h" - -class CStdInStream -{ - FILE *_stream; - // bool _streamIsOpen; -public: - int CodePage; - - CStdInStream(FILE *stream = NULL): - _stream(stream), - // _streamIsOpen(false), - CodePage(-1) - {} - - /* - ~CStdInStream() { Close(); } - - bool Open(LPCTSTR fileName) throw(); - bool Close() throw(); - */ - - // returns: - // false, if ZERO character in stream - // true, if EOF or '\n' - bool ScanAStringUntilNewLine(AString &s); - bool ScanUStringUntilNewLine(UString &s); - // bool ReadToString(AString &resultString); - - bool Eof() const throw() { return (feof(_stream) != 0); } - bool Error() const throw() { return (ferror(_stream) != 0); } - - int GetChar(); -}; - -extern CStdInStream g_StdIn; - -#endif +// Common/StdInStream.h + +#ifndef ZIP7_INC_COMMON_STD_IN_STREAM_H +#define ZIP7_INC_COMMON_STD_IN_STREAM_H + +#include + +#include "MyString.h" +#include "MyTypes.h" + +class CStdInStream +{ + FILE *_stream; + // bool _streamIsOpen; +public: + int CodePage; + + CStdInStream(FILE *stream = NULL): + _stream(stream), + // _streamIsOpen(false), + CodePage(-1) + {} + + /* + ~CStdInStream() { Close(); } + + bool Open(LPCTSTR fileName) throw(); + bool Close() throw(); + */ + + // returns: + // false, if ZERO character in stream + // true, if EOF or '\n' + bool ScanAStringUntilNewLine(AString &s); + bool ScanUStringUntilNewLine(UString &s); + // bool ReadToString(AString &resultString); + + bool Eof() const throw() { return (feof(_stream) != 0); } + bool Error() const throw() { return (ferror(_stream) != 0); } + + int GetChar(); +}; + +extern CStdInStream g_StdIn; + +#endif diff --git a/CPP/Common/StdOutStream.cpp b/CPP/Common/StdOutStream.cpp index 92753bded..ba179d967 100644 --- a/CPP/Common/StdOutStream.cpp +++ b/CPP/Common/StdOutStream.cpp @@ -1,248 +1,248 @@ -// Common/StdOutStream.cpp - -#include "StdAfx.h" - -#ifdef _WIN32 -#include -#endif - -#include "IntToString.h" -#include "StdOutStream.h" -#include "StringConvert.h" -#include "UTFConvert.h" - -CStdOutStream g_StdOut(stdout); -CStdOutStream g_StdErr(stderr); - -/* -// #define kFileOpenMode "wt" - -bool CStdOutStream::Open(const char *fileName) throw() -{ - Close(); - _stream = fopen(fileName, kFileOpenMode); - _streamIsOpen = (_stream != 0); - return _streamIsOpen; -} - -bool CStdOutStream::Close() throw() -{ - if (!_streamIsOpen) - return true; - if (fclose(_stream) != 0) - return false; - _stream = 0; - _streamIsOpen = false; - return true; -} -*/ - -bool CStdOutStream::Flush() throw() -{ - return (fflush(_stream) == 0); -} - -CStdOutStream & endl(CStdOutStream & outStream) throw() -{ - return outStream << '\n'; -} - -CStdOutStream & CStdOutStream::operator<<(const wchar_t *s) -{ - AString temp; - UString s2(s); - PrintUString(s2, temp); - return *this; -} - -void CStdOutStream::PrintUString(const UString &s, AString &temp) -{ - Convert_UString_to_AString(s, temp); - *this << (const char *)temp; -} - -void CStdOutStream::Convert_UString_to_AString(const UString &src, AString &dest) -{ - int codePage = CodePage; - if (codePage == -1) - codePage = CP_OEMCP; - if ((unsigned)codePage == CP_UTF8) - ConvertUnicodeToUTF8(src, dest); - else - UnicodeStringToMultiByte2(dest, src, (UINT)(unsigned)codePage); -} - - -static const wchar_t kReplaceChar = '_'; - -/* -void CStdOutStream::Normalize_UString_LF_Allowed(UString &s) -{ - if (!IsTerminalMode) - return; - - const unsigned len = s.Len(); - wchar_t *d = s.GetBuf(); - - for (unsigned i = 0; i < len; i++) - { - const wchar_t c = d[i]; - if (c == 0x1b || (c <= 13 && c >= 7 && c != '\n')) - d[i] = kReplaceChar; - } -} -*/ - -void CStdOutStream::Normalize_UString(UString &s) -{ - const unsigned len = s.Len(); - wchar_t *d = s.GetBuf(); - - if (IsTerminalMode) - for (unsigned i = 0; i < len; i++) - { - const wchar_t c = d[i]; - if ((c <= 13 && c >= 7) || c == 0x1b) - d[i] = kReplaceChar; - } - else - for (unsigned i = 0; i < len; i++) - { - const wchar_t c = d[i]; - if (c == '\n') - d[i] = kReplaceChar; - } -} - -void CStdOutStream::Normalize_UString_Path(UString &s) -{ - if (ListPathSeparatorSlash.Def) - { -#ifdef _WIN32 - if (ListPathSeparatorSlash.Val) - s.Replace(L'\\', L'/'); -#else - if (!ListPathSeparatorSlash.Val) - s.Replace(L'/', L'\\'); -#endif - } - Normalize_UString(s); -} - - -/* -void CStdOutStream::Normalize_UString(UString &src) -{ - const wchar_t *s = src.Ptr(); - const unsigned len = src.Len(); - unsigned i; - for (i = 0; i < len; i++) - { - const wchar_t c = s[i]; -#if 0 && !defined(_WIN32) - if (c == '\\') // IsTerminalMode && - break; -#endif - if ((unsigned)c < 0x20) - break; - } - if (i == len) - return; - - UString temp; - for (i = 0; i < len; i++) - { - wchar_t c = s[i]; -#if 0 && !defined(_WIN32) - if (c == '\\') - temp += (wchar_t)L'\\'; - else -#endif - if ((unsigned)c < 0x20) - { - if (c == '\n' - || (IsTerminalMode && (c == 0x1b || (c <= 13 && c >= 7)))) - { -#if 1 || defined(_WIN32) - c = (wchar_t)kReplaceChar; -#else - temp += (wchar_t)L'\\'; - if (c == '\n') c = L'n'; - else if (c == '\r') c = L'r'; - else if (c == '\a') c = L'a'; - else if (c == '\b') c = L'b'; - else if (c == '\t') c = L't'; - else if (c == '\v') c = L'v'; - else if (c == '\f') c = L'f'; - else - { - temp += (wchar_t)(L'0' + (unsigned)c / 64); - temp += (wchar_t)(L'0' + (unsigned)c / 8 % 8); - c = (wchar_t)(L'0' + (unsigned)c % 8); - } -#endif - } - } - temp += c; - } - src = temp; -} -*/ - -void CStdOutStream::NormalizePrint_UString_Path(const UString &s, UString &tempU, AString &tempA) -{ - tempU = s; - Normalize_UString_Path(tempU); - PrintUString(tempU, tempA); -} - -void CStdOutStream::NormalizePrint_UString_Path(const UString &s) -{ - UString tempU; - AString tempA; - NormalizePrint_UString_Path(s, tempU, tempA); -} - -void CStdOutStream::NormalizePrint_wstr_Path(const wchar_t *s) -{ - UString tempU = s; - Normalize_UString_Path(tempU); - AString tempA; - PrintUString(tempU, tempA); -} - -void CStdOutStream::NormalizePrint_UString(const UString &s) -{ - UString tempU = s; - Normalize_UString(tempU); - AString tempA; - PrintUString(tempU, tempA); -} - -CStdOutStream & CStdOutStream::operator<<(Int32 number) throw() -{ - char s[32]; - ConvertInt64ToString(number, s); - return operator<<(s); -} - -CStdOutStream & CStdOutStream::operator<<(Int64 number) throw() -{ - char s[32]; - ConvertInt64ToString(number, s); - return operator<<(s); -} - -CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw() -{ - char s[16]; - ConvertUInt32ToString(number, s); - return operator<<(s); -} - -CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw() -{ - char s[32]; - ConvertUInt64ToString(number, s); - return operator<<(s); -} +// Common/StdOutStream.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include +#endif + +#include "IntToString.h" +#include "StdOutStream.h" +#include "StringConvert.h" +#include "UTFConvert.h" + +CStdOutStream g_StdOut(stdout); +CStdOutStream g_StdErr(stderr); + +/* +// #define kFileOpenMode "wt" + +bool CStdOutStream::Open(const char *fileName) throw() +{ + Close(); + _stream = fopen(fileName, kFileOpenMode); + _streamIsOpen = (_stream != 0); + return _streamIsOpen; +} + +bool CStdOutStream::Close() throw() +{ + if (!_streamIsOpen) + return true; + if (fclose(_stream) != 0) + return false; + _stream = 0; + _streamIsOpen = false; + return true; +} +*/ + +bool CStdOutStream::Flush() throw() +{ + return (fflush(_stream) == 0); +} + +CStdOutStream & endl(CStdOutStream & outStream) throw() +{ + return outStream << '\n'; +} + +CStdOutStream & CStdOutStream::operator<<(const wchar_t *s) +{ + AString temp; + UString s2(s); + PrintUString(s2, temp); + return *this; +} + +void CStdOutStream::PrintUString(const UString &s, AString &temp) +{ + Convert_UString_to_AString(s, temp); + *this << (const char *)temp; +} + +void CStdOutStream::Convert_UString_to_AString(const UString &src, AString &dest) +{ + int codePage = CodePage; + if (codePage == -1) + codePage = CP_OEMCP; + if ((unsigned)codePage == CP_UTF8) + ConvertUnicodeToUTF8(src, dest); + else + UnicodeStringToMultiByte2(dest, src, (UINT)(unsigned)codePage); +} + + +static const wchar_t kReplaceChar = '_'; + +/* +void CStdOutStream::Normalize_UString_LF_Allowed(UString &s) +{ + if (!IsTerminalMode) + return; + + const unsigned len = s.Len(); + wchar_t *d = s.GetBuf(); + + for (unsigned i = 0; i < len; i++) + { + const wchar_t c = d[i]; + if (c == 0x1b || (c <= 13 && c >= 7 && c != '\n')) + d[i] = kReplaceChar; + } +} +*/ + +void CStdOutStream::Normalize_UString(UString &s) +{ + const unsigned len = s.Len(); + wchar_t *d = s.GetBuf(); + + if (IsTerminalMode) + for (unsigned i = 0; i < len; i++) + { + const wchar_t c = d[i]; + if ((c <= 13 && c >= 7) || c == 0x1b) + d[i] = kReplaceChar; + } + else + for (unsigned i = 0; i < len; i++) + { + const wchar_t c = d[i]; + if (c == '\n') + d[i] = kReplaceChar; + } +} + +void CStdOutStream::Normalize_UString_Path(UString &s) +{ + if (ListPathSeparatorSlash.Def) + { +#ifdef _WIN32 + if (ListPathSeparatorSlash.Val) + s.Replace(L'\\', L'/'); +#else + if (!ListPathSeparatorSlash.Val) + s.Replace(L'/', L'\\'); +#endif + } + Normalize_UString(s); +} + + +/* +void CStdOutStream::Normalize_UString(UString &src) +{ + const wchar_t *s = src.Ptr(); + const unsigned len = src.Len(); + unsigned i; + for (i = 0; i < len; i++) + { + const wchar_t c = s[i]; +#if 0 && !defined(_WIN32) + if (c == '\\') // IsTerminalMode && + break; +#endif + if ((unsigned)c < 0x20) + break; + } + if (i == len) + return; + + UString temp; + for (i = 0; i < len; i++) + { + wchar_t c = s[i]; +#if 0 && !defined(_WIN32) + if (c == '\\') + temp += (wchar_t)L'\\'; + else +#endif + if ((unsigned)c < 0x20) + { + if (c == '\n' + || (IsTerminalMode && (c == 0x1b || (c <= 13 && c >= 7)))) + { +#if 1 || defined(_WIN32) + c = (wchar_t)kReplaceChar; +#else + temp += (wchar_t)L'\\'; + if (c == '\n') c = L'n'; + else if (c == '\r') c = L'r'; + else if (c == '\a') c = L'a'; + else if (c == '\b') c = L'b'; + else if (c == '\t') c = L't'; + else if (c == '\v') c = L'v'; + else if (c == '\f') c = L'f'; + else + { + temp += (wchar_t)(L'0' + (unsigned)c / 64); + temp += (wchar_t)(L'0' + (unsigned)c / 8 % 8); + c = (wchar_t)(L'0' + (unsigned)c % 8); + } +#endif + } + } + temp += c; + } + src = temp; +} +*/ + +void CStdOutStream::NormalizePrint_UString_Path(const UString &s, UString &tempU, AString &tempA) +{ + tempU = s; + Normalize_UString_Path(tempU); + PrintUString(tempU, tempA); +} + +void CStdOutStream::NormalizePrint_UString_Path(const UString &s) +{ + UString tempU; + AString tempA; + NormalizePrint_UString_Path(s, tempU, tempA); +} + +void CStdOutStream::NormalizePrint_wstr_Path(const wchar_t *s) +{ + UString tempU = s; + Normalize_UString_Path(tempU); + AString tempA; + PrintUString(tempU, tempA); +} + +void CStdOutStream::NormalizePrint_UString(const UString &s) +{ + UString tempU = s; + Normalize_UString(tempU); + AString tempA; + PrintUString(tempU, tempA); +} + +CStdOutStream & CStdOutStream::operator<<(Int32 number) throw() +{ + char s[32]; + ConvertInt64ToString(number, s); + return operator<<(s); +} + +CStdOutStream & CStdOutStream::operator<<(Int64 number) throw() +{ + char s[32]; + ConvertInt64ToString(number, s); + return operator<<(s); +} + +CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw() +{ + char s[16]; + ConvertUInt32ToString(number, s); + return operator<<(s); +} + +CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw() +{ + char s[32]; + ConvertUInt64ToString(number, s); + return operator<<(s); +} diff --git a/CPP/Common/StdOutStream.h b/CPP/Common/StdOutStream.h index 19322d2f3..846b0db51 100644 --- a/CPP/Common/StdOutStream.h +++ b/CPP/Common/StdOutStream.h @@ -1,87 +1,87 @@ -// Common/StdOutStream.h - -#ifndef ZIP7_INC_COMMON_STD_OUT_STREAM_H -#define ZIP7_INC_COMMON_STD_OUT_STREAM_H - -#include - -#include "MyString.h" -#include "MyTypes.h" - -class CStdOutStream -{ - FILE *_stream; - // bool _streamIsOpen; -public: - bool IsTerminalMode; - CBoolPair ListPathSeparatorSlash; - int CodePage; - - CStdOutStream(FILE *stream = NULL): - _stream(stream), - // _streamIsOpen(false), - IsTerminalMode(false), - CodePage(-1) - { - ListPathSeparatorSlash.Val = -#ifdef _WIN32 - false; -#else - true; -#endif - } - - // ~CStdOutStream() { Close(); } - - // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; } - // bool IsDefined() const { return _stream != NULL; } - - operator FILE *() { return _stream; } - /* - bool Open(const char *fileName) throw(); - bool Close() throw(); - */ - bool Flush() throw(); - - CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &)) - { - (*func)(*this); - return *this; - } - - CStdOutStream & operator<<(const char *s) throw() - { - fputs(s, _stream); - return *this; - } - - CStdOutStream & operator<<(char c) throw() - { - fputc((unsigned char)c, _stream); - return *this; - } - - CStdOutStream & operator<<(Int32 number) throw(); - CStdOutStream & operator<<(Int64 number) throw(); - CStdOutStream & operator<<(UInt32 number) throw(); - CStdOutStream & operator<<(UInt64 number) throw(); - - CStdOutStream & operator<<(const wchar_t *s); - void PrintUString(const UString &s, AString &temp); - void Convert_UString_to_AString(const UString &src, AString &dest); - - void Normalize_UString(UString &s); - void Normalize_UString_Path(UString &s); - - void NormalizePrint_UString_Path(const UString &s, UString &tempU, AString &tempA); - void NormalizePrint_UString_Path(const UString &s); - void NormalizePrint_UString(const UString &s); - void NormalizePrint_wstr_Path(const wchar_t *s); -}; - -CStdOutStream & endl(CStdOutStream & outStream) throw(); - -extern CStdOutStream g_StdOut; -extern CStdOutStream g_StdErr; - -#endif +// Common/StdOutStream.h + +#ifndef ZIP7_INC_COMMON_STD_OUT_STREAM_H +#define ZIP7_INC_COMMON_STD_OUT_STREAM_H + +#include + +#include "MyString.h" +#include "MyTypes.h" + +class CStdOutStream +{ + FILE *_stream; + // bool _streamIsOpen; +public: + bool IsTerminalMode; + CBoolPair ListPathSeparatorSlash; + int CodePage; + + CStdOutStream(FILE *stream = NULL): + _stream(stream), + // _streamIsOpen(false), + IsTerminalMode(false), + CodePage(-1) + { + ListPathSeparatorSlash.Val = +#ifdef _WIN32 + false; +#else + true; +#endif + } + + // ~CStdOutStream() { Close(); } + + // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; } + // bool IsDefined() const { return _stream != NULL; } + + operator FILE *() { return _stream; } + /* + bool Open(const char *fileName) throw(); + bool Close() throw(); + */ + bool Flush() throw(); + + CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &)) + { + (*func)(*this); + return *this; + } + + CStdOutStream & operator<<(const char *s) throw() + { + fputs(s, _stream); + return *this; + } + + CStdOutStream & operator<<(char c) throw() + { + fputc((unsigned char)c, _stream); + return *this; + } + + CStdOutStream & operator<<(Int32 number) throw(); + CStdOutStream & operator<<(Int64 number) throw(); + CStdOutStream & operator<<(UInt32 number) throw(); + CStdOutStream & operator<<(UInt64 number) throw(); + + CStdOutStream & operator<<(const wchar_t *s); + void PrintUString(const UString &s, AString &temp); + void Convert_UString_to_AString(const UString &src, AString &dest); + + void Normalize_UString(UString &s); + void Normalize_UString_Path(UString &s); + + void NormalizePrint_UString_Path(const UString &s, UString &tempU, AString &tempA); + void NormalizePrint_UString_Path(const UString &s); + void NormalizePrint_UString(const UString &s); + void NormalizePrint_wstr_Path(const wchar_t *s); +}; + +CStdOutStream & endl(CStdOutStream & outStream) throw(); + +extern CStdOutStream g_StdOut; +extern CStdOutStream g_StdErr; + +#endif diff --git a/CPP/Common/StringConvert.cpp b/CPP/Common/StringConvert.cpp index 15aa5dfb9..79ff9e00f 100644 --- a/CPP/Common/StringConvert.cpp +++ b/CPP/Common/StringConvert.cpp @@ -1,762 +1,762 @@ -// Common/StringConvert.cpp - -#include "StdAfx.h" - -#include "StringConvert.h" - -#ifndef _WIN32 -// #include -#include -#endif - -#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) -#include "UTFConvert.h" -#endif - -#ifdef ENV_HAVE_LOCALE -#include -#endif - -static const char k_DefultChar = '_'; - -#ifdef _WIN32 - -/* -MultiByteToWideChar(CodePage, DWORD dwFlags, - LPCSTR lpMultiByteStr, int cbMultiByte, - LPWSTR lpWideCharStr, int cchWideChar) - - if (cbMultiByte == 0) - return: 0. ERR: ERROR_INVALID_PARAMETER - - if (cchWideChar == 0) - return: the required buffer size in characters. - - if (supplied buffer size was not large enough) - return: 0. ERR: ERROR_INSUFFICIENT_BUFFER - The number of filled characters in lpWideCharStr can be smaller than cchWideChar (if last character is complex) - - If there are illegal characters: - if MB_ERR_INVALID_CHARS is set in dwFlags: - - the function stops conversion on illegal character. - - Return: 0. ERR: ERROR_NO_UNICODE_TRANSLATION. - - if MB_ERR_INVALID_CHARS is NOT set in dwFlags: - before Vista: illegal character is dropped (skipped). WinXP-64: GetLastError() returns 0. - in Vista+: illegal character is not dropped (MSDN). Undocumented: illegal - character is converted to U+FFFD, which is REPLACEMENT CHARACTER. -*/ - - -void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage) -{ - dest.Empty(); - if (src.IsEmpty()) - return; - { - /* - wchar_t *d = dest.GetBuf(src.Len()); - const char *s = (const char *)src; - unsigned i; - - for (i = 0;;) - { - Byte c = (Byte)s[i]; - if (c >= 0x80 || c == 0) - break; - d[i++] = (wchar_t)c; - } - - if (i != src.Len()) - { - unsigned len = MultiByteToWideChar(codePage, 0, s + i, - src.Len() - i, d + i, - src.Len() + 1 - i); - if (len == 0) - throw 282228; - i += len; - } - - d[i] = 0; - dest.ReleaseBuf_SetLen(i); - */ - unsigned len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), NULL, 0); - if (len == 0) - { - if (GetLastError() != 0) - throw 282228; - } - else - { - len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), dest.GetBuf(len), (int)len); - if (len == 0) - throw 282228; - dest.ReleaseBuf_SetEnd(len); - } - } -} - -/* - int WideCharToMultiByte( - UINT CodePage, DWORD dwFlags, - LPCWSTR lpWideCharStr, int cchWideChar, - LPSTR lpMultiByteStr, int cbMultiByte, - LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); - -if (lpDefaultChar == NULL), - - it uses system default value. - -if (CodePage == CP_UTF7 || CodePage == CP_UTF8) - if (lpDefaultChar != NULL || lpUsedDefaultChar != NULL) - return: 0. ERR: ERROR_INVALID_PARAMETER. - -The function operates most efficiently, if (lpDefaultChar == NULL && lpUsedDefaultChar == NULL) - -*/ - -static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed) -{ - dest.Empty(); - defaultCharWasUsed = false; - if (src.IsEmpty()) - return; - { - /* - unsigned numRequiredBytes = src.Len() * 2; - char *d = dest.GetBuf(numRequiredBytes); - const wchar_t *s = (const wchar_t *)src; - unsigned i; - - for (i = 0;;) - { - wchar_t c = s[i]; - if (c >= 0x80 || c == 0) - break; - d[i++] = (char)c; - } - - if (i != src.Len()) - { - BOOL defUsed = FALSE; - defaultChar = defaultChar; - - bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7); - unsigned len = WideCharToMultiByte(codePage, 0, s + i, src.Len() - i, - d + i, numRequiredBytes + 1 - i, - (isUtf ? NULL : &defaultChar), - (isUtf ? NULL : &defUsed)); - defaultCharWasUsed = (defUsed != FALSE); - if (len == 0) - throw 282229; - i += len; - } - - d[i] = 0; - dest.ReleaseBuf_SetLen(i); - */ - - /* - if (codePage != CP_UTF7) - { - const wchar_t *s = (const wchar_t *)src; - unsigned i; - for (i = 0;; i++) - { - wchar_t c = s[i]; - if (c >= 0x80 || c == 0) - break; - } - - if (s[i] == 0) - { - char *d = dest.GetBuf(src.Len()); - for (i = 0;;) - { - wchar_t c = s[i]; - if (c == 0) - break; - d[i++] = (char)c; - } - d[i] = 0; - dest.ReleaseBuf_SetLen(i); - return; - } - } - */ - - unsigned len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), NULL, 0, NULL, NULL); - if (len == 0) - { - if (GetLastError() != 0) - throw 282228; - } - else - { - BOOL defUsed = FALSE; - bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7); - // defaultChar = defaultChar; - len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), - dest.GetBuf(len), (int)len, - (isUtf ? NULL : &defaultChar), - (isUtf ? NULL : &defUsed) - ); - if (!isUtf) - defaultCharWasUsed = (defUsed != FALSE); - if (len == 0) - throw 282228; - dest.ReleaseBuf_SetEnd(len); - } - } -} - -/* -#ifndef UNDER_CE -AString SystemStringToOemString(const CSysString &src) -{ - AString dest; - const unsigned len = src.Len() * 2; - CharToOem(src, dest.GetBuf(len)); - dest.ReleaseBuf_CalcLen(len); - return dest; -} -#endif -*/ - -#else // _WIN32 - -// #include -/* - if (wchar_t is 32-bit (#if WCHAR_MAX > 0xffff), - and utf-8 string contains big unicode character > 0xffff), - then we still use 16-bit surrogate pair in UString. - It simplifies another code where utf-16 encoding is used. - So we use surrogate-conversion code only in is file. -*/ - -/* - mbstowcs() returns error if there is error in utf-8 stream, - mbstowcs() returns error if there is single surrogates point (d800-dfff) in utf-8 stream -*/ - -/* -static void MultiByteToUnicodeString2_Native(UString &dest, const AString &src) -{ - dest.Empty(); - if (src.IsEmpty()) - return; - - const size_t limit = ((size_t)src.Len() + 1) * 2; - wchar_t *d = dest.GetBuf((unsigned)limit); - const size_t len = mbstowcs(d, src, limit); - if (len != (size_t)-1) - { - dest.ReleaseBuf_SetEnd((unsigned)len); - return; - } - dest.ReleaseBuf_SetEnd(0); -} -*/ - -bool g_ForceToUTF8 = true; // false; - -void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage) -{ - dest.Empty(); - if (src.IsEmpty()) - return; - - if (codePage == CP_UTF8 || g_ForceToUTF8) - { -#if 1 - ConvertUTF8ToUnicode(src, dest); - return; -#endif - } - - const size_t limit = ((size_t)src.Len() + 1) * 2; - wchar_t *d = dest.GetBuf((unsigned)limit); - const size_t len = mbstowcs(d, src, limit); - if (len != (size_t)-1) - { - dest.ReleaseBuf_SetEnd((unsigned)len); - -#if WCHAR_MAX > 0xffff - d = dest.GetBuf(); - for (size_t i = 0;; i++) - { - wchar_t c = d[i]; - // printf("\ni=%2d c = %4x\n", (unsigned)i, (unsigned)c); - if (c == 0) - break; - if (c >= 0x10000 && c < 0x110000) - { - UString tempString = d + i; - const wchar_t *t = tempString.Ptr(); - - for (;;) - { - wchar_t w = *t++; - // printf("\nchar=%x\n", w); - if (w == 0) - break; - if (i == limit) - break; // unexpected error - if (w >= 0x10000 && w < 0x110000) - { -#if 1 - if (i + 1 == limit) - break; // unexpected error - w -= 0x10000; - d[i++] = (unsigned)0xd800 + (((unsigned)w >> 10) & 0x3ff); - w = 0xdc00 + (w & 0x3ff); -#else - // w = '_'; // for debug -#endif - } - d[i++] = w; - } - dest.ReleaseBuf_SetEnd((unsigned)i); - break; - } - } - -#endif - - /* - printf("\nMultiByteToUnicodeString2 (%d) %s\n", (int)src.Len(), src.Ptr()); - printf("char: "); - for (unsigned i = 0; i < src.Len(); i++) - printf (" %02x", (int)(Byte)src[i]); - printf("\n"); - printf("\n-> (%d) %ls\n", (int)dest.Len(), dest.Ptr()); - printf("wchar_t: "); - for (unsigned i = 0; i < dest.Len(); i++) - { - printf (" %02x", (int)dest[i]); - } - printf("\n"); - */ - - return; - } - - /* if there is mbstowcs() error, we have two ways: - - 1) change 0x80+ characters to some character: '_' - in that case we lose data, but we have correct UString() - and that scheme can show errors to user in early stages, - when file converted back to mbs() cannot be found - - 2) transfer bad characters in some UTF-16 range. - it can be non-original Unicode character. - but later we still can restore original character. - */ - - - // printf("\nmbstowcs ERROR !!!!!! s=%s\n", src.Ptr()); - { - unsigned i; - const char *s = (const char *)src; - for (i = 0;;) - { - Byte c = (Byte)s[i]; - if (c == 0) - break; - // we can use ascii compatibilty character '_' - // if (c > 0x7F) c = '_'; // we replace "bad: character - d[i++] = (wchar_t)c; - } - d[i] = 0; - dest.ReleaseBuf_SetLen(i); - } -} - -static void UnicodeStringToMultiByte2_Native(AString &dest, const UString &src) -{ - dest.Empty(); - if (src.IsEmpty()) - return; - - const size_t limit = ((size_t)src.Len() + 1) * 6; - char *d = dest.GetBuf((unsigned)limit); - - const size_t len = wcstombs(d, src, limit); - - if (len != (size_t)-1) - { - dest.ReleaseBuf_SetEnd((unsigned)len); - return; - } - dest.ReleaseBuf_SetEnd(0); -} - - -static void UnicodeStringToMultiByte2(AString &dest, const UString &src2, UINT codePage, char defaultChar, bool &defaultCharWasUsed) -{ - // if (codePage == 1234567) // for debug purposes - if (codePage == CP_UTF8 || g_ForceToUTF8) - { -#if 1 - defaultCharWasUsed = false; - ConvertUnicodeToUTF8(src2, dest); - return; -#endif - } - - UString src = src2; -#if WCHAR_MAX > 0xffff - { - src.Empty(); - for (unsigned i = 0; i < src2.Len();) - { - wchar_t c = src2[i++]; - if (c >= 0xd800 && c < 0xdc00 && i != src2.Len()) - { - const wchar_t c2 = src2[i]; - if (c2 >= 0xdc00 && c2 < 0xe000) - { -#if 1 - // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2); - c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); - // printf("%4x\n", (int)c); - i++; -#else - // c = '_'; // for debug -#endif - } - } - src += c; - } - } -#endif - - dest.Empty(); - defaultCharWasUsed = false; - if (src.IsEmpty()) - return; - - const size_t len = wcstombs(NULL, src, 0); - - if (len != (size_t)-1) - { - const unsigned limit = ((unsigned)len); - if (limit == len) - { - char *d = dest.GetBuf(limit); - - /* - { - printf("\nwcstombs; len = %d %ls \n", (int)src.Len(), src.Ptr()); - for (unsigned i = 0; i < src.Len(); i++) - printf (" %02x", (int)src[i]); - printf("\n"); - printf("\ndest Limit = %d \n", limit); - } - */ - - const size_t len2 = wcstombs(d, src, len + 1); - - if (len2 != (size_t)-1 && len2 <= limit) - { - /* - printf("\nOK : destLen = %d : %s\n", (int)len, dest.Ptr()); - for (unsigned i = 0; i < len2; i++) - printf(" %02x", (int)(Byte)dest[i]); - printf("\n"); - */ - dest.ReleaseBuf_SetEnd((unsigned)len2); - return; - } - } - } - - { - const wchar_t *s = (const wchar_t *)src; - char *d = dest.GetBuf(src.Len()); - - unsigned i; - for (i = 0;;) - { - wchar_t c = s[i]; - if (c == 0) - break; - if (c >= - 0x100 - // 0x80 - ) - { - c = defaultChar; - defaultCharWasUsed = true; - } - - d[i++] = (char)c; - } - d[i] = 0; - dest.ReleaseBuf_SetLen(i); - /* - printf("\nUnicodeStringToMultiByte2; len = %d \n", (int)src.Len()); - printf("ERROR: %s\n", dest.Ptr()); - */ - } -} - -#endif // _WIN32 - - -UString MultiByteToUnicodeString(const AString &src, UINT codePage) -{ - UString dest; - MultiByteToUnicodeString2(dest, src, codePage); - return dest; -} - -UString MultiByteToUnicodeString(const char *src, UINT codePage) -{ - return MultiByteToUnicodeString(AString(src), codePage); -} - - -void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage) -{ - bool defaultCharWasUsed; - UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed); -} - -AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed) -{ - AString dest; - UnicodeStringToMultiByte2(dest, src, codePage, defaultChar, defaultCharWasUsed); - return dest; -} - -AString UnicodeStringToMultiByte(const UString &src, UINT codePage) -{ - AString dest; - bool defaultCharWasUsed; - UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed); - return dest; -} - - - - -#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) - -#ifdef _WIN32 -#define U_to_A(a, b, c) UnicodeStringToMultiByte2 -// #define A_to_U(a, b, c) MultiByteToUnicodeString2 -#else -// void MultiByteToUnicodeString2_Native(UString &dest, const AString &src); -#define U_to_A(a, b, c) UnicodeStringToMultiByte2_Native(a, b) -// #define A_to_U(a, b, c) MultiByteToUnicodeString2_Native(a, b) -#endif - -bool IsNativeUTF8() -{ - UString u; - AString a, a2; - // for (unsigned c = 0x80; c < (UInt32)0x10000; c += (c >> 9) + 1) - for (unsigned c = 0x80; c < (UInt32)0xD000; c += (c >> 2) + 1) - { - u.Empty(); - u += (wchar_t)c; - /* - if (Unicode_Is_There_Utf16SurrogateError(u)) - continue; - #ifndef _WIN32 - if (Unicode_Is_There_BmpEscape(u)) - continue; - #endif - */ - ConvertUnicodeToUTF8(u, a); - U_to_A(a2, u, CP_OEMCP); - if (a != a2) - return false; - } - return true; -} - -#endif - - -#ifdef ENV_HAVE_LOCALE - -const char *GetLocale(void) -{ - #ifdef ENV_HAVE_LOCALE - // printf("\n\nsetlocale(LC_CTYPE, NULL) : return : "); - const char *s = setlocale(LC_CTYPE, NULL); - if (!s) - { - // printf("[NULL]\n"); - s = "C"; - } - else - { - // ubuntu returns "C" after program start - // printf("\"%s\"\n", s); - } - return s; - #elif defined(LOCALE_IS_UTF8) - return "utf8"; - #else - return "C"; - #endif -} - -#ifdef _WIN32 - static void Set_ForceToUTF8(bool) {} -#else - static void Set_ForceToUTF8(bool val) { g_ForceToUTF8 = val; } -#endif - -static bool Is_Default_Basic_Locale(const char *locale) -{ - const AString a (locale); - if (a.IsEqualTo_Ascii_NoCase("") - || a.IsEqualTo_Ascii_NoCase("C") - || a.IsEqualTo_Ascii_NoCase("POSIX")) - return true; - return false; -} - -static bool Is_Default_Basic_Locale() -{ - return Is_Default_Basic_Locale(GetLocale()); -} - - -void MY_SetLocale() -{ - #ifdef ENV_HAVE_LOCALE - /* - { - const char *s = GetLocale(); - printf("\nGetLocale() : returned : \"%s\"\n", s); - } - */ - - unsigned start = 0; - // unsigned lim = 0; - unsigned lim = 3; - - /* - #define MY_SET_LOCALE_FLAGS__FROM_ENV 1 - #define MY_SET_LOCALE_FLAGS__TRY_UTF8 2 - - unsigned flags = - MY_SET_LOCALE_FLAGS__FROM_ENV | - MY_SET_LOCALE_FLAGS__TRY_UTF8 - - if (flags != 0) - { - if (flags & MY_SET_LOCALE_FLAGS__FROM_ENV) - lim = (flags & MY_SET_LOCALE_FLAGS__TRY_UTF8) ? 3 : 1; - else - { - start = 1; - lim = 2; - } - } - */ - - for (unsigned i = start; i < lim; i++) - { - /* - man7: "If locale is an empty string, "", each part of the locale that - should be modified is set according to the environment variables. - for glibc: glibc, first from the user's environment variables: - 1) the environment variable LC_ALL, - 2) environment variable with the same name as the category (see the - 3) the environment variable LANG - The locale "C" or "POSIX" is a portable locale; it exists on all conforming systems. - - for WIN32 : MSDN : - Sets the locale to the default, which is the user-default - ANSI code page obtained from the operating system. - The locale name is set to the value returned by GetUserDefaultLocaleName. - The code page is set to the value returned by GetACP - */ - const char *newLocale = ""; - - #ifdef __APPLE__ - - /* look also CFLocale - there is no C.UTF-8 in macos - macos has UTF-8 locale only with some language like en_US.UTF-8 - what is best way to set UTF-8 locale in macos? */ - if (i == 1) - newLocale = "en_US.UTF-8"; - - /* file open with non-utf8 sequencies return - #define EILSEQ 92 // "Illegal byte sequence" - */ -#else - // newLocale = "C"; - if (i == 1) - { - newLocale = "C.UTF-8"; // main UTF-8 locale in ubuntu - // newLocale = ".utf8"; // supported in new Windows 10 build 17134 (April 2018 Update), the Universal C Runtime - // newLocale = "en_US.utf8"; // supported by ubuntu ? - // newLocale = "en_US.UTF-8"; - /* setlocale() in ubuntu allows locales with minor chracter changes in strings - "en_US.UTF-8" / "en_US.utf8" */ - } - -#endif - - // printf("\nsetlocale(LC_ALL, \"%s\") : returned: ", newLocale); - - // const char *s = - setlocale(LC_ALL, newLocale); - - /* - if (!s) - printf("NULL: can't set locale"); - else - printf("\"%s\"\n", s); - */ - - // request curent locale of program - const char *locale = GetLocale(); - if (locale) - { - AString a (locale); - a.MakeLower_Ascii(); - // if (a.Find("utf") >= 0) - { - if (IsNativeUTF8()) - { - Set_ForceToUTF8(true); - return; - } - } - if (!Is_Default_Basic_Locale(locale)) - { - // if there is some non-default and non-utf locale, we want to use it - break; // comment it for debug - } - } - } - - if (IsNativeUTF8()) - { - Set_ForceToUTF8(true); - return; - } - - if (Is_Default_Basic_Locale()) - { - Set_ForceToUTF8(true); - return; - } - - Set_ForceToUTF8(false); - - #elif defined(LOCALE_IS_UTF8) - // assume LC_CTYPE="utf8" - #else - // assume LC_CTYPE="C" - #endif -} -#endif +// Common/StringConvert.cpp + +#include "StdAfx.h" + +#include "StringConvert.h" + +#ifndef _WIN32 +// #include +#include +#endif + +#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) +#include "UTFConvert.h" +#endif + +#ifdef ENV_HAVE_LOCALE +#include +#endif + +static const char k_DefultChar = '_'; + +#ifdef _WIN32 + +/* +MultiByteToWideChar(CodePage, DWORD dwFlags, + LPCSTR lpMultiByteStr, int cbMultiByte, + LPWSTR lpWideCharStr, int cchWideChar) + + if (cbMultiByte == 0) + return: 0. ERR: ERROR_INVALID_PARAMETER + + if (cchWideChar == 0) + return: the required buffer size in characters. + + if (supplied buffer size was not large enough) + return: 0. ERR: ERROR_INSUFFICIENT_BUFFER + The number of filled characters in lpWideCharStr can be smaller than cchWideChar (if last character is complex) + + If there are illegal characters: + if MB_ERR_INVALID_CHARS is set in dwFlags: + - the function stops conversion on illegal character. + - Return: 0. ERR: ERROR_NO_UNICODE_TRANSLATION. + + if MB_ERR_INVALID_CHARS is NOT set in dwFlags: + before Vista: illegal character is dropped (skipped). WinXP-64: GetLastError() returns 0. + in Vista+: illegal character is not dropped (MSDN). Undocumented: illegal + character is converted to U+FFFD, which is REPLACEMENT CHARACTER. +*/ + + +void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage) +{ + dest.Empty(); + if (src.IsEmpty()) + return; + { + /* + wchar_t *d = dest.GetBuf(src.Len()); + const char *s = (const char *)src; + unsigned i; + + for (i = 0;;) + { + Byte c = (Byte)s[i]; + if (c >= 0x80 || c == 0) + break; + d[i++] = (wchar_t)c; + } + + if (i != src.Len()) + { + unsigned len = MultiByteToWideChar(codePage, 0, s + i, + src.Len() - i, d + i, + src.Len() + 1 - i); + if (len == 0) + throw 282228; + i += len; + } + + d[i] = 0; + dest.ReleaseBuf_SetLen(i); + */ + unsigned len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), NULL, 0); + if (len == 0) + { + if (GetLastError() != 0) + throw 282228; + } + else + { + len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), dest.GetBuf(len), (int)len); + if (len == 0) + throw 282228; + dest.ReleaseBuf_SetEnd(len); + } + } +} + +/* + int WideCharToMultiByte( + UINT CodePage, DWORD dwFlags, + LPCWSTR lpWideCharStr, int cchWideChar, + LPSTR lpMultiByteStr, int cbMultiByte, + LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); + +if (lpDefaultChar == NULL), + - it uses system default value. + +if (CodePage == CP_UTF7 || CodePage == CP_UTF8) + if (lpDefaultChar != NULL || lpUsedDefaultChar != NULL) + return: 0. ERR: ERROR_INVALID_PARAMETER. + +The function operates most efficiently, if (lpDefaultChar == NULL && lpUsedDefaultChar == NULL) + +*/ + +static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed) +{ + dest.Empty(); + defaultCharWasUsed = false; + if (src.IsEmpty()) + return; + { + /* + unsigned numRequiredBytes = src.Len() * 2; + char *d = dest.GetBuf(numRequiredBytes); + const wchar_t *s = (const wchar_t *)src; + unsigned i; + + for (i = 0;;) + { + wchar_t c = s[i]; + if (c >= 0x80 || c == 0) + break; + d[i++] = (char)c; + } + + if (i != src.Len()) + { + BOOL defUsed = FALSE; + defaultChar = defaultChar; + + bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7); + unsigned len = WideCharToMultiByte(codePage, 0, s + i, src.Len() - i, + d + i, numRequiredBytes + 1 - i, + (isUtf ? NULL : &defaultChar), + (isUtf ? NULL : &defUsed)); + defaultCharWasUsed = (defUsed != FALSE); + if (len == 0) + throw 282229; + i += len; + } + + d[i] = 0; + dest.ReleaseBuf_SetLen(i); + */ + + /* + if (codePage != CP_UTF7) + { + const wchar_t *s = (const wchar_t *)src; + unsigned i; + for (i = 0;; i++) + { + wchar_t c = s[i]; + if (c >= 0x80 || c == 0) + break; + } + + if (s[i] == 0) + { + char *d = dest.GetBuf(src.Len()); + for (i = 0;;) + { + wchar_t c = s[i]; + if (c == 0) + break; + d[i++] = (char)c; + } + d[i] = 0; + dest.ReleaseBuf_SetLen(i); + return; + } + } + */ + + unsigned len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), NULL, 0, NULL, NULL); + if (len == 0) + { + if (GetLastError() != 0) + throw 282228; + } + else + { + BOOL defUsed = FALSE; + bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7); + // defaultChar = defaultChar; + len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), + dest.GetBuf(len), (int)len, + (isUtf ? NULL : &defaultChar), + (isUtf ? NULL : &defUsed) + ); + if (!isUtf) + defaultCharWasUsed = (defUsed != FALSE); + if (len == 0) + throw 282228; + dest.ReleaseBuf_SetEnd(len); + } + } +} + +/* +#ifndef UNDER_CE +AString SystemStringToOemString(const CSysString &src) +{ + AString dest; + const unsigned len = src.Len() * 2; + CharToOem(src, dest.GetBuf(len)); + dest.ReleaseBuf_CalcLen(len); + return dest; +} +#endif +*/ + +#else // _WIN32 + +// #include +/* + if (wchar_t is 32-bit (#if WCHAR_MAX > 0xffff), + and utf-8 string contains big unicode character > 0xffff), + then we still use 16-bit surrogate pair in UString. + It simplifies another code where utf-16 encoding is used. + So we use surrogate-conversion code only in is file. +*/ + +/* + mbstowcs() returns error if there is error in utf-8 stream, + mbstowcs() returns error if there is single surrogates point (d800-dfff) in utf-8 stream +*/ + +/* +static void MultiByteToUnicodeString2_Native(UString &dest, const AString &src) +{ + dest.Empty(); + if (src.IsEmpty()) + return; + + const size_t limit = ((size_t)src.Len() + 1) * 2; + wchar_t *d = dest.GetBuf((unsigned)limit); + const size_t len = mbstowcs(d, src, limit); + if (len != (size_t)-1) + { + dest.ReleaseBuf_SetEnd((unsigned)len); + return; + } + dest.ReleaseBuf_SetEnd(0); +} +*/ + +bool g_ForceToUTF8 = true; // false; + +void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage) +{ + dest.Empty(); + if (src.IsEmpty()) + return; + + if (codePage == CP_UTF8 || g_ForceToUTF8) + { +#if 1 + ConvertUTF8ToUnicode(src, dest); + return; +#endif + } + + const size_t limit = ((size_t)src.Len() + 1) * 2; + wchar_t *d = dest.GetBuf((unsigned)limit); + const size_t len = mbstowcs(d, src, limit); + if (len != (size_t)-1) + { + dest.ReleaseBuf_SetEnd((unsigned)len); + +#if WCHAR_MAX > 0xffff + d = dest.GetBuf(); + for (size_t i = 0;; i++) + { + wchar_t c = d[i]; + // printf("\ni=%2d c = %4x\n", (unsigned)i, (unsigned)c); + if (c == 0) + break; + if (c >= 0x10000 && c < 0x110000) + { + UString tempString = d + i; + const wchar_t *t = tempString.Ptr(); + + for (;;) + { + wchar_t w = *t++; + // printf("\nchar=%x\n", w); + if (w == 0) + break; + if (i == limit) + break; // unexpected error + if (w >= 0x10000 && w < 0x110000) + { +#if 1 + if (i + 1 == limit) + break; // unexpected error + w -= 0x10000; + d[i++] = (unsigned)0xd800 + (((unsigned)w >> 10) & 0x3ff); + w = 0xdc00 + (w & 0x3ff); +#else + // w = '_'; // for debug +#endif + } + d[i++] = w; + } + dest.ReleaseBuf_SetEnd((unsigned)i); + break; + } + } + +#endif + + /* + printf("\nMultiByteToUnicodeString2 (%d) %s\n", (int)src.Len(), src.Ptr()); + printf("char: "); + for (unsigned i = 0; i < src.Len(); i++) + printf (" %02x", (int)(Byte)src[i]); + printf("\n"); + printf("\n-> (%d) %ls\n", (int)dest.Len(), dest.Ptr()); + printf("wchar_t: "); + for (unsigned i = 0; i < dest.Len(); i++) + { + printf (" %02x", (int)dest[i]); + } + printf("\n"); + */ + + return; + } + + /* if there is mbstowcs() error, we have two ways: + + 1) change 0x80+ characters to some character: '_' + in that case we lose data, but we have correct UString() + and that scheme can show errors to user in early stages, + when file converted back to mbs() cannot be found + + 2) transfer bad characters in some UTF-16 range. + it can be non-original Unicode character. + but later we still can restore original character. + */ + + + // printf("\nmbstowcs ERROR !!!!!! s=%s\n", src.Ptr()); + { + unsigned i; + const char *s = (const char *)src; + for (i = 0;;) + { + Byte c = (Byte)s[i]; + if (c == 0) + break; + // we can use ascii compatibilty character '_' + // if (c > 0x7F) c = '_'; // we replace "bad: character + d[i++] = (wchar_t)c; + } + d[i] = 0; + dest.ReleaseBuf_SetLen(i); + } +} + +static void UnicodeStringToMultiByte2_Native(AString &dest, const UString &src) +{ + dest.Empty(); + if (src.IsEmpty()) + return; + + const size_t limit = ((size_t)src.Len() + 1) * 6; + char *d = dest.GetBuf((unsigned)limit); + + const size_t len = wcstombs(d, src, limit); + + if (len != (size_t)-1) + { + dest.ReleaseBuf_SetEnd((unsigned)len); + return; + } + dest.ReleaseBuf_SetEnd(0); +} + + +static void UnicodeStringToMultiByte2(AString &dest, const UString &src2, UINT codePage, char defaultChar, bool &defaultCharWasUsed) +{ + // if (codePage == 1234567) // for debug purposes + if (codePage == CP_UTF8 || g_ForceToUTF8) + { +#if 1 + defaultCharWasUsed = false; + ConvertUnicodeToUTF8(src2, dest); + return; +#endif + } + + UString src = src2; +#if WCHAR_MAX > 0xffff + { + src.Empty(); + for (unsigned i = 0; i < src2.Len();) + { + wchar_t c = src2[i++]; + if (c >= 0xd800 && c < 0xdc00 && i != src2.Len()) + { + const wchar_t c2 = src2[i]; + if (c2 >= 0xdc00 && c2 < 0xe000) + { +#if 1 + // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2); + c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); + // printf("%4x\n", (int)c); + i++; +#else + // c = '_'; // for debug +#endif + } + } + src += c; + } + } +#endif + + dest.Empty(); + defaultCharWasUsed = false; + if (src.IsEmpty()) + return; + + const size_t len = wcstombs(NULL, src, 0); + + if (len != (size_t)-1) + { + const unsigned limit = ((unsigned)len); + if (limit == len) + { + char *d = dest.GetBuf(limit); + + /* + { + printf("\nwcstombs; len = %d %ls \n", (int)src.Len(), src.Ptr()); + for (unsigned i = 0; i < src.Len(); i++) + printf (" %02x", (int)src[i]); + printf("\n"); + printf("\ndest Limit = %d \n", limit); + } + */ + + const size_t len2 = wcstombs(d, src, len + 1); + + if (len2 != (size_t)-1 && len2 <= limit) + { + /* + printf("\nOK : destLen = %d : %s\n", (int)len, dest.Ptr()); + for (unsigned i = 0; i < len2; i++) + printf(" %02x", (int)(Byte)dest[i]); + printf("\n"); + */ + dest.ReleaseBuf_SetEnd((unsigned)len2); + return; + } + } + } + + { + const wchar_t *s = (const wchar_t *)src; + char *d = dest.GetBuf(src.Len()); + + unsigned i; + for (i = 0;;) + { + wchar_t c = s[i]; + if (c == 0) + break; + if (c >= + 0x100 + // 0x80 + ) + { + c = defaultChar; + defaultCharWasUsed = true; + } + + d[i++] = (char)c; + } + d[i] = 0; + dest.ReleaseBuf_SetLen(i); + /* + printf("\nUnicodeStringToMultiByte2; len = %d \n", (int)src.Len()); + printf("ERROR: %s\n", dest.Ptr()); + */ + } +} + +#endif // _WIN32 + + +UString MultiByteToUnicodeString(const AString &src, UINT codePage) +{ + UString dest; + MultiByteToUnicodeString2(dest, src, codePage); + return dest; +} + +UString MultiByteToUnicodeString(const char *src, UINT codePage) +{ + return MultiByteToUnicodeString(AString(src), codePage); +} + + +void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage) +{ + bool defaultCharWasUsed; + UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed); +} + +AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed) +{ + AString dest; + UnicodeStringToMultiByte2(dest, src, codePage, defaultChar, defaultCharWasUsed); + return dest; +} + +AString UnicodeStringToMultiByte(const UString &src, UINT codePage) +{ + AString dest; + bool defaultCharWasUsed; + UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed); + return dest; +} + + + + +#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) + +#ifdef _WIN32 +#define U_to_A(a, b, c) UnicodeStringToMultiByte2 +// #define A_to_U(a, b, c) MultiByteToUnicodeString2 +#else +// void MultiByteToUnicodeString2_Native(UString &dest, const AString &src); +#define U_to_A(a, b, c) UnicodeStringToMultiByte2_Native(a, b) +// #define A_to_U(a, b, c) MultiByteToUnicodeString2_Native(a, b) +#endif + +bool IsNativeUTF8() +{ + UString u; + AString a, a2; + // for (unsigned c = 0x80; c < (UInt32)0x10000; c += (c >> 9) + 1) + for (unsigned c = 0x80; c < (UInt32)0xD000; c += (c >> 2) + 1) + { + u.Empty(); + u += (wchar_t)c; + /* + if (Unicode_Is_There_Utf16SurrogateError(u)) + continue; + #ifndef _WIN32 + if (Unicode_Is_There_BmpEscape(u)) + continue; + #endif + */ + ConvertUnicodeToUTF8(u, a); + U_to_A(a2, u, CP_OEMCP); + if (a != a2) + return false; + } + return true; +} + +#endif + + +#ifdef ENV_HAVE_LOCALE + +const char *GetLocale(void) +{ + #ifdef ENV_HAVE_LOCALE + // printf("\n\nsetlocale(LC_CTYPE, NULL) : return : "); + const char *s = setlocale(LC_CTYPE, NULL); + if (!s) + { + // printf("[NULL]\n"); + s = "C"; + } + else + { + // ubuntu returns "C" after program start + // printf("\"%s\"\n", s); + } + return s; + #elif defined(LOCALE_IS_UTF8) + return "utf8"; + #else + return "C"; + #endif +} + +#ifdef _WIN32 + static void Set_ForceToUTF8(bool) {} +#else + static void Set_ForceToUTF8(bool val) { g_ForceToUTF8 = val; } +#endif + +static bool Is_Default_Basic_Locale(const char *locale) +{ + const AString a (locale); + if (a.IsEqualTo_Ascii_NoCase("") + || a.IsEqualTo_Ascii_NoCase("C") + || a.IsEqualTo_Ascii_NoCase("POSIX")) + return true; + return false; +} + +static bool Is_Default_Basic_Locale() +{ + return Is_Default_Basic_Locale(GetLocale()); +} + + +void MY_SetLocale() +{ + #ifdef ENV_HAVE_LOCALE + /* + { + const char *s = GetLocale(); + printf("\nGetLocale() : returned : \"%s\"\n", s); + } + */ + + unsigned start = 0; + // unsigned lim = 0; + unsigned lim = 3; + + /* + #define MY_SET_LOCALE_FLAGS__FROM_ENV 1 + #define MY_SET_LOCALE_FLAGS__TRY_UTF8 2 + + unsigned flags = + MY_SET_LOCALE_FLAGS__FROM_ENV | + MY_SET_LOCALE_FLAGS__TRY_UTF8 + + if (flags != 0) + { + if (flags & MY_SET_LOCALE_FLAGS__FROM_ENV) + lim = (flags & MY_SET_LOCALE_FLAGS__TRY_UTF8) ? 3 : 1; + else + { + start = 1; + lim = 2; + } + } + */ + + for (unsigned i = start; i < lim; i++) + { + /* + man7: "If locale is an empty string, "", each part of the locale that + should be modified is set according to the environment variables. + for glibc: glibc, first from the user's environment variables: + 1) the environment variable LC_ALL, + 2) environment variable with the same name as the category (see the + 3) the environment variable LANG + The locale "C" or "POSIX" is a portable locale; it exists on all conforming systems. + + for WIN32 : MSDN : + Sets the locale to the default, which is the user-default + ANSI code page obtained from the operating system. + The locale name is set to the value returned by GetUserDefaultLocaleName. + The code page is set to the value returned by GetACP + */ + const char *newLocale = ""; + + #ifdef __APPLE__ + + /* look also CFLocale + there is no C.UTF-8 in macos + macos has UTF-8 locale only with some language like en_US.UTF-8 + what is best way to set UTF-8 locale in macos? */ + if (i == 1) + newLocale = "en_US.UTF-8"; + + /* file open with non-utf8 sequencies return + #define EILSEQ 92 // "Illegal byte sequence" + */ +#else + // newLocale = "C"; + if (i == 1) + { + newLocale = "C.UTF-8"; // main UTF-8 locale in ubuntu + // newLocale = ".utf8"; // supported in new Windows 10 build 17134 (April 2018 Update), the Universal C Runtime + // newLocale = "en_US.utf8"; // supported by ubuntu ? + // newLocale = "en_US.UTF-8"; + /* setlocale() in ubuntu allows locales with minor chracter changes in strings + "en_US.UTF-8" / "en_US.utf8" */ + } + +#endif + + // printf("\nsetlocale(LC_ALL, \"%s\") : returned: ", newLocale); + + // const char *s = + setlocale(LC_ALL, newLocale); + + /* + if (!s) + printf("NULL: can't set locale"); + else + printf("\"%s\"\n", s); + */ + + // request curent locale of program + const char *locale = GetLocale(); + if (locale) + { + AString a (locale); + a.MakeLower_Ascii(); + // if (a.Find("utf") >= 0) + { + if (IsNativeUTF8()) + { + Set_ForceToUTF8(true); + return; + } + } + if (!Is_Default_Basic_Locale(locale)) + { + // if there is some non-default and non-utf locale, we want to use it + break; // comment it for debug + } + } + } + + if (IsNativeUTF8()) + { + Set_ForceToUTF8(true); + return; + } + + if (Is_Default_Basic_Locale()) + { + Set_ForceToUTF8(true); + return; + } + + Set_ForceToUTF8(false); + + #elif defined(LOCALE_IS_UTF8) + // assume LC_CTYPE="utf8" + #else + // assume LC_CTYPE="C" + #endif +} +#endif diff --git a/CPP/Common/StringConvert.h b/CPP/Common/StringConvert.h index bbfe70e4c..2092a2da0 100644 --- a/CPP/Common/StringConvert.h +++ b/CPP/Common/StringConvert.h @@ -1,110 +1,110 @@ -// Common/StringConvert.h - -#ifndef ZIP7_INC_COMMON_STRING_CONVERT_H -#define ZIP7_INC_COMMON_STRING_CONVERT_H - -#include "MyString.h" -#include "MyWindows.h" - -UString MultiByteToUnicodeString(const AString &src, UINT codePage = CP_ACP); -UString MultiByteToUnicodeString(const char *src, UINT codePage = CP_ACP); - -// optimized versions that work faster for ASCII strings -void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage = CP_ACP); -// void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed); -void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage); - -AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed); -AString UnicodeStringToMultiByte(const UString &src, UINT codePage = CP_ACP); - -inline const wchar_t* GetUnicodeString(const wchar_t *u) { return u; } -inline const UString& GetUnicodeString(const UString &u) { return u; } - -inline UString GetUnicodeString(const AString &a) { return MultiByteToUnicodeString(a); } -inline UString GetUnicodeString(const char *a) { return MultiByteToUnicodeString(a); } - -inline UString GetUnicodeString(const AString &a, UINT codePage) - { return MultiByteToUnicodeString(a, codePage); } -inline UString GetUnicodeString(const char *a, UINT codePage) - { return MultiByteToUnicodeString(a, codePage); } - -inline const wchar_t* GetUnicodeString(const wchar_t *u, UINT) { return u; } -inline const UString& GetUnicodeString(const UString &u, UINT) { return u; } - -inline const char* GetAnsiString(const char *a) { return a; } -inline const AString& GetAnsiString(const AString &a) { return a; } - -inline AString GetAnsiString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); } -inline AString GetAnsiString(const UString &u) { return UnicodeStringToMultiByte(u); } - -/* -inline const char* GetOemString(const char* oem) - { return oem; } -inline const AString& GetOemString(const AString &oem) - { return oem; } -*/ -const char* GetOemString(const char* oem); -const AString& GetOemString(const AString &oem); -inline AString GetOemString(const UString &u) - { return UnicodeStringToMultiByte(u, CP_OEMCP); } - -#ifdef _UNICODE - inline const wchar_t* GetSystemString(const wchar_t *u) { return u;} - inline const UString& GetSystemString(const UString &u) { return u;} - inline const wchar_t* GetSystemString(const wchar_t *u, UINT /* codePage */) { return u;} - inline const UString& GetSystemString(const UString &u, UINT /* codePage */) { return u;} - - inline UString GetSystemString(const AString &a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); } - inline UString GetSystemString(const char *a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); } - inline UString GetSystemString(const AString &a) { return MultiByteToUnicodeString(a); } - inline UString GetSystemString(const char *a) { return MultiByteToUnicodeString(a); } -#else - inline const char* GetSystemString(const char *a) { return a; } - inline const AString& GetSystemString(const AString &a) { return a; } - inline const char* GetSystemString(const char *a, UINT) { return a; } - inline const AString& GetSystemString(const AString &a, UINT) { return a; } - - inline AString GetSystemString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); } - inline AString GetSystemString(const UString &u) { return UnicodeStringToMultiByte(u); } - inline AString GetSystemString(const UString &u, UINT codePage) { return UnicodeStringToMultiByte(u, codePage); } - - - - /* - inline AString GetSystemString(const wchar_t *u) - { - UString s; - s = u; - return UnicodeStringToMultiByte(s); - } - */ - -#endif - -#ifndef UNDER_CE -AString SystemStringToOemString(const CSysString &src); -#endif - - -#ifdef _WIN32 -/* we don't need locale functions in Windows - but we can define ENV_HAVE_LOCALE here for debug purposes */ -// #define ENV_HAVE_LOCALE -#else -#define ENV_HAVE_LOCALE -#endif - -#ifdef ENV_HAVE_LOCALE -void MY_SetLocale(); -const char *GetLocale(void); -#endif - -#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) -bool IsNativeUTF8(); -#endif - -#ifndef _WIN32 -extern bool g_ForceToUTF8; -#endif - -#endif +// Common/StringConvert.h + +#ifndef ZIP7_INC_COMMON_STRING_CONVERT_H +#define ZIP7_INC_COMMON_STRING_CONVERT_H + +#include "MyString.h" +#include "MyWindows.h" + +UString MultiByteToUnicodeString(const AString &src, UINT codePage = CP_ACP); +UString MultiByteToUnicodeString(const char *src, UINT codePage = CP_ACP); + +// optimized versions that work faster for ASCII strings +void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage = CP_ACP); +// void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed); +void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage); + +AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed); +AString UnicodeStringToMultiByte(const UString &src, UINT codePage = CP_ACP); + +inline const wchar_t* GetUnicodeString(const wchar_t *u) { return u; } +inline const UString& GetUnicodeString(const UString &u) { return u; } + +inline UString GetUnicodeString(const AString &a) { return MultiByteToUnicodeString(a); } +inline UString GetUnicodeString(const char *a) { return MultiByteToUnicodeString(a); } + +inline UString GetUnicodeString(const AString &a, UINT codePage) + { return MultiByteToUnicodeString(a, codePage); } +inline UString GetUnicodeString(const char *a, UINT codePage) + { return MultiByteToUnicodeString(a, codePage); } + +inline const wchar_t* GetUnicodeString(const wchar_t *u, UINT) { return u; } +inline const UString& GetUnicodeString(const UString &u, UINT) { return u; } + +inline const char* GetAnsiString(const char *a) { return a; } +inline const AString& GetAnsiString(const AString &a) { return a; } + +inline AString GetAnsiString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); } +inline AString GetAnsiString(const UString &u) { return UnicodeStringToMultiByte(u); } + +/* +inline const char* GetOemString(const char* oem) + { return oem; } +inline const AString& GetOemString(const AString &oem) + { return oem; } +*/ +const char* GetOemString(const char* oem); +const AString& GetOemString(const AString &oem); +inline AString GetOemString(const UString &u) + { return UnicodeStringToMultiByte(u, CP_OEMCP); } + +#ifdef _UNICODE + inline const wchar_t* GetSystemString(const wchar_t *u) { return u;} + inline const UString& GetSystemString(const UString &u) { return u;} + inline const wchar_t* GetSystemString(const wchar_t *u, UINT /* codePage */) { return u;} + inline const UString& GetSystemString(const UString &u, UINT /* codePage */) { return u;} + + inline UString GetSystemString(const AString &a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); } + inline UString GetSystemString(const char *a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); } + inline UString GetSystemString(const AString &a) { return MultiByteToUnicodeString(a); } + inline UString GetSystemString(const char *a) { return MultiByteToUnicodeString(a); } +#else + inline const char* GetSystemString(const char *a) { return a; } + inline const AString& GetSystemString(const AString &a) { return a; } + inline const char* GetSystemString(const char *a, UINT) { return a; } + inline const AString& GetSystemString(const AString &a, UINT) { return a; } + + inline AString GetSystemString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); } + inline AString GetSystemString(const UString &u) { return UnicodeStringToMultiByte(u); } + inline AString GetSystemString(const UString &u, UINT codePage) { return UnicodeStringToMultiByte(u, codePage); } + + + + /* + inline AString GetSystemString(const wchar_t *u) + { + UString s; + s = u; + return UnicodeStringToMultiByte(s); + } + */ + +#endif + +#ifndef UNDER_CE +AString SystemStringToOemString(const CSysString &src); +#endif + + +#ifdef _WIN32 +/* we don't need locale functions in Windows + but we can define ENV_HAVE_LOCALE here for debug purposes */ +// #define ENV_HAVE_LOCALE +#else +#define ENV_HAVE_LOCALE +#endif + +#ifdef ENV_HAVE_LOCALE +void MY_SetLocale(); +const char *GetLocale(void); +#endif + +#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) +bool IsNativeUTF8(); +#endif + +#ifndef _WIN32 +extern bool g_ForceToUTF8; +#endif + +#endif diff --git a/CPP/Common/StringToInt.cpp b/CPP/Common/StringToInt.cpp index 56091c437..ba8a81b38 100644 --- a/CPP/Common/StringToInt.cpp +++ b/CPP/Common/StringToInt.cpp @@ -1,154 +1,154 @@ -// Common/StringToInt.cpp - -#include "StdAfx.h" - -#include -#if defined(_MSC_VER) && (_MSC_VER >= 1600) -#include // for WCHAR_MAX in vs2022 -#endif - -#include "StringToInt.h" - -static const UInt32 k_UInt32_max = 0xFFFFFFFF; -static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF); -// static const UInt64 k_UInt64_max = (UInt64)(Int64)-1; - -#define DIGIT_TO_VALUE(charTypeUnsigned, digit) ((unsigned)(charTypeUnsigned)digit - '0') -// #define DIGIT_TO_VALUE(charTypeUnsigned, digit) ((unsigned)digit - '0') -// #define DIGIT_TO_VALUE(charTypeUnsigned, digit) ((unsigned)(digit - '0')) - -#define CONVERT_STRING_TO_UINT_FUNC(uintType, charType, charTypeUnsigned) \ -uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ - if (end) *end = s; \ - uintType res = 0; \ - for (;; s++) { \ - const unsigned v = DIGIT_TO_VALUE(charTypeUnsigned, *s); \ - if (v > 9) { if (end) *end = s; return res; } \ - if (res > (k_ ## uintType ## _max) / 10) return 0; \ - res *= 10; \ - if (res > (k_ ## uintType ## _max) - v) return 0; \ - res += v; }} - -// arm-linux-gnueabi GCC compilers give (WCHAR_MAX > UINT_MAX) by some unknown reason -// so we don't use this branch -#if 0 && WCHAR_MAX > UINT_MAX -/* - if (sizeof(wchar_t) > sizeof(unsigned) - we must use CONVERT_STRING_TO_UINT_FUNC_SLOW - But we just stop compiling instead. - We need some real cases to test this code. -*/ -#error Stop_Compiling_WCHAR_MAX_IS_LARGER_THAN_UINT_MAX -#define CONVERT_STRING_TO_UINT_FUNC_SLOW(uintType, charType, charTypeUnsigned) \ -uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ - if (end) *end = s; \ - uintType res = 0; \ - for (;; s++) { \ - const charTypeUnsigned c = (charTypeUnsigned)*s; \ - if (c < '0' || c > '9') { if (end) *end = s; return res; } \ - if (res > (k_ ## uintType ## _max) / 10) return 0; \ - res *= 10; \ - const unsigned v = (unsigned)(c - '0'); \ - if (res > (k_ ## uintType ## _max) - v) return 0; \ - res += v; }} -#endif - - -CONVERT_STRING_TO_UINT_FUNC(UInt32, char, Byte) -CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t) -CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte) -CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t) - -Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() -{ - if (end) - *end = s; - const wchar_t *s2 = s; - if (*s == '-') - s2++; - const wchar_t *end2; - UInt32 res = ConvertStringToUInt32(s2, &end2); - if (s2 == end2) - return 0; - if (s != s2) - { - if (res > (UInt32)1 << (32 - 1)) - return 0; - res = 0 - res; - } - else - { - if (res & (UInt32)1 << (32 - 1)) - return 0; - } - if (end) - *end = end2; - return (Int32)res; -} - - -#define CONVERT_OCT_STRING_TO_UINT_FUNC(uintType) \ -uintType ConvertOctStringTo ## uintType(const char *s, const char **end) throw() \ -{ \ - if (end) *end = s; \ - uintType res = 0; \ - for (;; s++) { \ - const unsigned c = (unsigned)(Byte)*s - '0'; \ - if (c > 7) { \ - if (end) \ - *end = s; \ - return res; \ - } \ - if (res & (uintType)7 << (sizeof(uintType) * 8 - 3)) \ - return 0; \ - res <<= 3; \ - res |= c; \ - } \ -} - -CONVERT_OCT_STRING_TO_UINT_FUNC(UInt32) -CONVERT_OCT_STRING_TO_UINT_FUNC(UInt64) - - -#define CONVERT_HEX_STRING_TO_UINT_FUNC(uintType) \ -uintType ConvertHexStringTo ## uintType(const char *s, const char **end) throw() \ -{ \ - if (end) *end = s; \ - uintType res = 0; \ - for (;; s++) { \ - unsigned c = (unsigned)(Byte)*s; \ - Z7_PARSE_HEX_DIGIT(c, { if (end) *end = s; return res; }) \ - if (res & (uintType)0xF << (sizeof(uintType) * 8 - 4)) \ - return 0; \ - res <<= 4; \ - res |= c; \ - } \ -} - -CONVERT_HEX_STRING_TO_UINT_FUNC(UInt32) -CONVERT_HEX_STRING_TO_UINT_FUNC(UInt64) - -const char *FindNonHexChar(const char *s) throw() -{ - for (;;) - { - unsigned c = (Byte)*s++; // pointer can go 1 byte after end - c -= '0'; - if (c <= 9) - continue; - c -= 'A' - '0'; - c &= ~0x20u; - if (c > 5) - return s - 1; - } -} - -Byte *ParseHexString(const char *s, Byte *dest) throw() -{ - for (;;) - { - unsigned v0 = (Byte)s[0]; Z7_PARSE_HEX_DIGIT(v0, return dest;) - unsigned v1 = (Byte)s[1]; s += 2; Z7_PARSE_HEX_DIGIT(v1, return dest;) - *dest++ = (Byte)(v1 | (v0 << 4)); - } -} +// Common/StringToInt.cpp + +#include "StdAfx.h" + +#include +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +#include // for WCHAR_MAX in vs2022 +#endif + +#include "StringToInt.h" + +static const UInt32 k_UInt32_max = 0xFFFFFFFF; +static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF); +// static const UInt64 k_UInt64_max = (UInt64)(Int64)-1; + +#define DIGIT_TO_VALUE(charTypeUnsigned, digit) ((unsigned)(charTypeUnsigned)digit - '0') +// #define DIGIT_TO_VALUE(charTypeUnsigned, digit) ((unsigned)digit - '0') +// #define DIGIT_TO_VALUE(charTypeUnsigned, digit) ((unsigned)(digit - '0')) + +#define CONVERT_STRING_TO_UINT_FUNC(uintType, charType, charTypeUnsigned) \ +uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ + if (end) *end = s; \ + uintType res = 0; \ + for (;; s++) { \ + const unsigned v = DIGIT_TO_VALUE(charTypeUnsigned, *s); \ + if (v > 9) { if (end) *end = s; return res; } \ + if (res > (k_ ## uintType ## _max) / 10) return 0; \ + res *= 10; \ + if (res > (k_ ## uintType ## _max) - v) return 0; \ + res += v; }} + +// arm-linux-gnueabi GCC compilers give (WCHAR_MAX > UINT_MAX) by some unknown reason +// so we don't use this branch +#if 0 && WCHAR_MAX > UINT_MAX +/* + if (sizeof(wchar_t) > sizeof(unsigned) + we must use CONVERT_STRING_TO_UINT_FUNC_SLOW + But we just stop compiling instead. + We need some real cases to test this code. +*/ +#error Stop_Compiling_WCHAR_MAX_IS_LARGER_THAN_UINT_MAX +#define CONVERT_STRING_TO_UINT_FUNC_SLOW(uintType, charType, charTypeUnsigned) \ +uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ + if (end) *end = s; \ + uintType res = 0; \ + for (;; s++) { \ + const charTypeUnsigned c = (charTypeUnsigned)*s; \ + if (c < '0' || c > '9') { if (end) *end = s; return res; } \ + if (res > (k_ ## uintType ## _max) / 10) return 0; \ + res *= 10; \ + const unsigned v = (unsigned)(c - '0'); \ + if (res > (k_ ## uintType ## _max) - v) return 0; \ + res += v; }} +#endif + + +CONVERT_STRING_TO_UINT_FUNC(UInt32, char, Byte) +CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t) +CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte) +CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t) + +Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() +{ + if (end) + *end = s; + const wchar_t *s2 = s; + if (*s == '-') + s2++; + const wchar_t *end2; + UInt32 res = ConvertStringToUInt32(s2, &end2); + if (s2 == end2) + return 0; + if (s != s2) + { + if (res > (UInt32)1 << (32 - 1)) + return 0; + res = 0 - res; + } + else + { + if (res & (UInt32)1 << (32 - 1)) + return 0; + } + if (end) + *end = end2; + return (Int32)res; +} + + +#define CONVERT_OCT_STRING_TO_UINT_FUNC(uintType) \ +uintType ConvertOctStringTo ## uintType(const char *s, const char **end) throw() \ +{ \ + if (end) *end = s; \ + uintType res = 0; \ + for (;; s++) { \ + const unsigned c = (unsigned)(Byte)*s - '0'; \ + if (c > 7) { \ + if (end) \ + *end = s; \ + return res; \ + } \ + if (res & (uintType)7 << (sizeof(uintType) * 8 - 3)) \ + return 0; \ + res <<= 3; \ + res |= c; \ + } \ +} + +CONVERT_OCT_STRING_TO_UINT_FUNC(UInt32) +CONVERT_OCT_STRING_TO_UINT_FUNC(UInt64) + + +#define CONVERT_HEX_STRING_TO_UINT_FUNC(uintType) \ +uintType ConvertHexStringTo ## uintType(const char *s, const char **end) throw() \ +{ \ + if (end) *end = s; \ + uintType res = 0; \ + for (;; s++) { \ + unsigned c = (unsigned)(Byte)*s; \ + Z7_PARSE_HEX_DIGIT(c, { if (end) *end = s; return res; }) \ + if (res & (uintType)0xF << (sizeof(uintType) * 8 - 4)) \ + return 0; \ + res <<= 4; \ + res |= c; \ + } \ +} + +CONVERT_HEX_STRING_TO_UINT_FUNC(UInt32) +CONVERT_HEX_STRING_TO_UINT_FUNC(UInt64) + +const char *FindNonHexChar(const char *s) throw() +{ + for (;;) + { + unsigned c = (Byte)*s++; // pointer can go 1 byte after end + c -= '0'; + if (c <= 9) + continue; + c -= 'A' - '0'; + c &= ~0x20u; + if (c > 5) + return s - 1; + } +} + +Byte *ParseHexString(const char *s, Byte *dest) throw() +{ + for (;;) + { + unsigned v0 = (Byte)s[0]; Z7_PARSE_HEX_DIGIT(v0, return dest;) + unsigned v1 = (Byte)s[1]; s += 2; Z7_PARSE_HEX_DIGIT(v1, return dest;) + *dest++ = (Byte)(v1 | (v0 << 4)); + } +} diff --git a/CPP/Common/StringToInt.h b/CPP/Common/StringToInt.h index 970041053..31ab2747d 100644 --- a/CPP/Common/StringToInt.h +++ b/CPP/Common/StringToInt.h @@ -1,38 +1,38 @@ -// Common/StringToInt.h - -#ifndef ZIP7_INC_COMMON_STRING_TO_INT_H -#define ZIP7_INC_COMMON_STRING_TO_INT_H - -#include "MyTypes.h" - -UInt32 ConvertStringToUInt32(const char *s, const char **end) throw(); -UInt64 ConvertStringToUInt64(const char *s, const char **end) throw(); -UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); -UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); - -// Int32 ConvertStringToInt32(const char *s, const char **end) throw(); -Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); - -UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); -UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw(); - -UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw(); -UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw(); - -#define Z7_PARSE_HEX_DIGIT(c, err_op) \ -{ c -= '0'; \ - if (c > 9) { \ - c -= 'A' - '0'; \ - c &= ~0x20u; \ - if (c > 5) { err_op } \ - c += 10; \ - } \ -} - -const char *FindNonHexChar(const char *s) throw(); - -// in: (dest != NULL) -// returns: pointer in dest array after last written byte -Byte *ParseHexString(const char *s, Byte *dest) throw(); - -#endif +// Common/StringToInt.h + +#ifndef ZIP7_INC_COMMON_STRING_TO_INT_H +#define ZIP7_INC_COMMON_STRING_TO_INT_H + +#include "MyTypes.h" + +UInt32 ConvertStringToUInt32(const char *s, const char **end) throw(); +UInt64 ConvertStringToUInt64(const char *s, const char **end) throw(); +UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); +UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); + +// Int32 ConvertStringToInt32(const char *s, const char **end) throw(); +Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); + +UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); +UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw(); + +UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw(); +UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw(); + +#define Z7_PARSE_HEX_DIGIT(c, err_op) \ +{ c -= '0'; \ + if (c > 9) { \ + c -= 'A' - '0'; \ + c &= ~0x20u; \ + if (c > 5) { err_op } \ + c += 10; \ + } \ +} + +const char *FindNonHexChar(const char *s) throw(); + +// in: (dest != NULL) +// returns: pointer in dest array after last written byte +Byte *ParseHexString(const char *s, Byte *dest) throw(); + +#endif diff --git a/CPP/Common/TextConfig.cpp b/CPP/Common/TextConfig.cpp index cd99e1ad2..5714e46c1 100644 --- a/CPP/Common/TextConfig.cpp +++ b/CPP/Common/TextConfig.cpp @@ -1,123 +1,123 @@ -// Common/TextConfig.cpp - -#include "StdAfx.h" - -#include "TextConfig.h" -#include "UTFConvert.h" - -static inline bool IsDelimitChar(char c) -{ - return (c == ' ' || c == 0x0A || c == 0x0D || c == '\0' || c == '\t'); -} - -static AString GetIDString(const char *s, unsigned &finishPos) -{ - AString result; - for (finishPos = 0; ; finishPos++) - { - const char c = s[finishPos]; - if (IsDelimitChar(c) || c == '=') - break; - result += c; - } - return result; -} - -static bool WaitNextLine(const AString &s, unsigned &pos) -{ - for (; pos < s.Len(); pos++) - if (s[pos] == 0x0A) - return true; - return false; -} - -static bool SkipSpaces(const AString &s, unsigned &pos) -{ - for (; pos < s.Len(); pos++) - { - const char c = s[pos]; - if (!IsDelimitChar(c)) - { - if (c != ';') - return true; - if (!WaitNextLine(s, pos)) - return false; - } - } - return false; -} - -bool GetTextConfig(const AString &s, CObjectVector &pairs) -{ - pairs.Clear(); - unsigned pos = 0; - - ///////////////////// - // read strings - - for (;;) - { - if (!SkipSpaces(s, pos)) - break; - CTextConfigPair pair; - unsigned finishPos; - const AString temp (GetIDString(((const char *)s) + pos, finishPos)); - if (!ConvertUTF8ToUnicode(temp, pair.ID)) - return false; - if (finishPos == 0) - return false; - pos += finishPos; - if (!SkipSpaces(s, pos)) - return false; - if (s[pos] != '=') - return false; - pos++; - if (!SkipSpaces(s, pos)) - return false; - if (s[pos] != '\"') - return false; - pos++; - AString message; - for (;;) - { - if (pos >= s.Len()) - return false; - char c = s[pos++]; - if (c == '\"') - break; - if (c == '\\') - { - c = s[pos++]; - switch (c) - { - case 'n': c = '\n'; break; - case 't': c = '\t'; break; - case '\\': break; - case '\"': break; - default: message += '\\'; break; - } - } - message += c; - } - if (!ConvertUTF8ToUnicode(message, pair.String)) - return false; - pairs.Add(pair); - } - return true; -} - -int FindTextConfigItem(const CObjectVector &pairs, const char *id) throw() -{ - FOR_VECTOR (i, pairs) - if (pairs[i].ID.IsEqualTo(id)) - return (int)i; - return -1; -} - -UString GetTextConfigValue(const CObjectVector &pairs, const char *id) -{ - const int index = FindTextConfigItem(pairs, id); - if (index < 0) - return UString(); - return pairs[index].String; -} +// Common/TextConfig.cpp + +#include "StdAfx.h" + +#include "TextConfig.h" +#include "UTFConvert.h" + +static inline bool IsDelimitChar(char c) +{ + return (c == ' ' || c == 0x0A || c == 0x0D || c == '\0' || c == '\t'); +} + +static AString GetIDString(const char *s, unsigned &finishPos) +{ + AString result; + for (finishPos = 0; ; finishPos++) + { + const char c = s[finishPos]; + if (IsDelimitChar(c) || c == '=') + break; + result += c; + } + return result; +} + +static bool WaitNextLine(const AString &s, unsigned &pos) +{ + for (; pos < s.Len(); pos++) + if (s[pos] == 0x0A) + return true; + return false; +} + +static bool SkipSpaces(const AString &s, unsigned &pos) +{ + for (; pos < s.Len(); pos++) + { + const char c = s[pos]; + if (!IsDelimitChar(c)) + { + if (c != ';') + return true; + if (!WaitNextLine(s, pos)) + return false; + } + } + return false; +} + +bool GetTextConfig(const AString &s, CObjectVector &pairs) +{ + pairs.Clear(); + unsigned pos = 0; + + ///////////////////// + // read strings + + for (;;) + { + if (!SkipSpaces(s, pos)) + break; + CTextConfigPair pair; + unsigned finishPos; + const AString temp (GetIDString(((const char *)s) + pos, finishPos)); + if (!ConvertUTF8ToUnicode(temp, pair.ID)) + return false; + if (finishPos == 0) + return false; + pos += finishPos; + if (!SkipSpaces(s, pos)) + return false; + if (s[pos] != '=') + return false; + pos++; + if (!SkipSpaces(s, pos)) + return false; + if (s[pos] != '\"') + return false; + pos++; + AString message; + for (;;) + { + if (pos >= s.Len()) + return false; + char c = s[pos++]; + if (c == '\"') + break; + if (c == '\\') + { + c = s[pos++]; + switch (c) + { + case 'n': c = '\n'; break; + case 't': c = '\t'; break; + case '\\': break; + case '\"': break; + default: message += '\\'; break; + } + } + message += c; + } + if (!ConvertUTF8ToUnicode(message, pair.String)) + return false; + pairs.Add(pair); + } + return true; +} + +int FindTextConfigItem(const CObjectVector &pairs, const char *id) throw() +{ + FOR_VECTOR (i, pairs) + if (pairs[i].ID.IsEqualTo(id)) + return (int)i; + return -1; +} + +UString GetTextConfigValue(const CObjectVector &pairs, const char *id) +{ + const int index = FindTextConfigItem(pairs, id); + if (index < 0) + return UString(); + return pairs[index].String; +} diff --git a/CPP/Common/TextConfig.h b/CPP/Common/TextConfig.h index 2dcb700d5..2263a4425 100644 --- a/CPP/Common/TextConfig.h +++ b/CPP/Common/TextConfig.h @@ -1,19 +1,19 @@ -// Common/TextConfig.h - -#ifndef ZIP7_INC_COMMON_TEXT_CONFIG_H -#define ZIP7_INC_COMMON_TEXT_CONFIG_H - -#include "MyString.h" - -struct CTextConfigPair -{ - UString ID; - UString String; -}; - -bool GetTextConfig(const AString &text, CObjectVector &pairs); - -int FindTextConfigItem(const CObjectVector &pairs, const char *id) throw(); -UString GetTextConfigValue(const CObjectVector &pairs, const char *id); - -#endif +// Common/TextConfig.h + +#ifndef ZIP7_INC_COMMON_TEXT_CONFIG_H +#define ZIP7_INC_COMMON_TEXT_CONFIG_H + +#include "MyString.h" + +struct CTextConfigPair +{ + UString ID; + UString String; +}; + +bool GetTextConfig(const AString &text, CObjectVector &pairs); + +int FindTextConfigItem(const CObjectVector &pairs, const char *id) throw(); +UString GetTextConfigValue(const CObjectVector &pairs, const char *id); + +#endif diff --git a/CPP/Common/UTFConvert.cpp b/CPP/Common/UTFConvert.cpp index e60c953a7..509de76f6 100644 --- a/CPP/Common/UTFConvert.cpp +++ b/CPP/Common/UTFConvert.cpp @@ -1,863 +1,863 @@ -// UTFConvert.cpp - -#include "StdAfx.h" - -// #include - -#include "MyTypes.h" -#include "UTFConvert.h" - - -#ifndef Z7_WCHART_IS_16BIT -#ifndef __APPLE__ - // we define it if the system supports files with non-utf8 symbols: - #define MY_UTF8_RAW_NON_UTF8_SUPPORTED -#endif -#endif - -/* - MY_UTF8_START(n) - is a base value for start byte (head), if there are (n) additional bytes after start byte - - n : MY_UTF8_START(n) : Bits of code point - - 0 : 0x80 : : unused - 1 : 0xC0 : 11 : - 2 : 0xE0 : 16 : Basic Multilingual Plane - 3 : 0xF0 : 21 : Unicode space - 4 : 0xF8 : 26 : - 5 : 0xFC : 31 : UCS-4 : wcstombs() in ubuntu is limited to that value - 6 : 0xFE : 36 : We can use it, if we want to encode any 32-bit value - 7 : 0xFF : -*/ - -#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n)))) - -#define MY_UTF8_HEAD_PARSE2(n) \ - if (c < MY_UTF8_START((n) + 1)) \ - { numBytes = (n); val -= MY_UTF8_START(n); } - -#ifndef Z7_WCHART_IS_16BIT - -/* - if (wchar_t is 32-bit), we can support large points in long UTF-8 sequence, - when we convert wchar_t strings to UTF-8: - (_UTF8_NUM_TAIL_BYTES_MAX == 3) : (21-bits points) - Unicode - (_UTF8_NUM_TAIL_BYTES_MAX == 5) : (31-bits points) - UCS-4 - (_UTF8_NUM_TAIL_BYTES_MAX == 6) : (36-bit hack) -*/ - -#define MY_UTF8_NUM_TAIL_BYTES_MAX 5 -#endif - -/* -#define MY_UTF8_HEAD_PARSE \ - UInt32 val = c; \ - MY_UTF8_HEAD_PARSE2(1) \ - else MY_UTF8_HEAD_PARSE2(2) \ - else MY_UTF8_HEAD_PARSE2(3) \ - else MY_UTF8_HEAD_PARSE2(4) \ - else MY_UTF8_HEAD_PARSE2(5) \ - #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6 - else MY_UTF8_HEAD_PARSE2(6) - #endif -*/ - -#define MY_UTF8_HEAD_PARSE_MAX_3_BYTES \ - UInt32 val = c; \ - MY_UTF8_HEAD_PARSE2(1) \ - else MY_UTF8_HEAD_PARSE2(2) \ - else { numBytes = 3; val -= MY_UTF8_START(3); } - - -#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) - - -#define START_POINT_FOR_SURROGATE 0x10000 - - -/* we use 128 bytes block in 16-bit BMP-PLANE to encode non-UTF-8 Escapes - Also we can use additional HIGH-PLANE (we use 21-bit points above 0x1f0000) - to simplify internal intermediate conversion in Linux: - RAW-UTF-8 <-> internal wchar_t utf-16 strings <-> RAW-UTF-UTF-8 -*/ - - -#if defined(Z7_WCHART_IS_16BIT) - -#define UTF_ESCAPE_PLANE 0 - -#else - -/* -we can place 128 ESCAPE chars to - ef 80 - ee be 80 (3-bytes utf-8) : similar to WSL - ef ff - ee bf bf - -1f ef 80 - f7 be be 80 (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode) -1f ef ff - f7 be bf bf (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode) -*/ - -// #define UTF_ESCAPE_PLANE_HIGH (0x1f << 16) -// #define UTF_ESCAPE_PLANE UTF_ESCAPE_PLANE_HIGH -#define UTF_ESCAPE_PLANE 0 - -/* - if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is set) - { - if (UTF_ESCAPE_PLANE is UTF_ESCAPE_PLANE_HIGH) - { - we can restore any 8-bit Escape from ESCAPE-PLANE-21 plane. - But ESCAPE-PLANE-21 point cannot be stored to utf-16 (7z archive) - So we still need a way to extract 8-bit Escapes and BMP-Escapes-8 - from same BMP-Escapes-16 stored in 7z. - And if we want to restore any 8-bit from 7z archive, - we still must use Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT for (utf-8 -> utf-16) - Also we need additional Conversions to tranform from utf-16 to utf-16-With-Escapes-21 - } - else (UTF_ESCAPE_PLANE == 0) - { - we must convert original 3-bytes utf-8 BMP-Escape point to sequence - of 3 BMP-Escape-16 points with Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT - so we can extract original RAW-UTF-8 from UTFD-16 later. - } - } -*/ - -#endif - - - -#define UTF_ESCAPE_BASE 0xef00 - - -#ifdef UTF_ESCAPE_BASE -#define IS_ESCAPE_POINT(v, plane) (((v) & (UInt32)0xffffff80) == (plane) + UTF_ESCAPE_BASE + 0x80) -#endif - -#define IS_SURROGATE_POINT(v) (((v) & (UInt32)0xfffff800) == 0xd800) -#define IS_LOW_SURROGATE_POINT(v) (((v) & (UInt32)0xfffffc00) == 0xdc00) - - -#define UTF_ERROR_UTF8_CHECK \ - { NonUtf = true; continue; } - -void CUtf8Check::Check_Buf(const char *src, size_t size) throw() -{ - Clear(); - // Byte maxByte = 0; - - for (;;) - { - if (size == 0) - break; - - const Byte c = (Byte)(*src++); - size--; - - if (c == 0) - { - ZeroChar = true; - continue; - } - - /* - if (c > maxByte) - maxByte = c; - */ - - if (c < 0x80) - continue; - - if (c < 0xc0 + 2) - UTF_ERROR_UTF8_CHECK - - unsigned numBytes; - UInt32 val = c; - MY_UTF8_HEAD_PARSE2(1) - else MY_UTF8_HEAD_PARSE2(2) - else MY_UTF8_HEAD_PARSE2(3) - else MY_UTF8_HEAD_PARSE2(4) - else MY_UTF8_HEAD_PARSE2(5) - else - { - UTF_ERROR_UTF8_CHECK - } - - unsigned pos = 0; - do - { - if (pos == size) - break; - unsigned c2 = (Byte)src[pos]; - c2 -= 0x80; - if (c2 >= 0x40) - break; - val <<= 6; - val |= c2; - if (pos == 0) - if (val < (((unsigned)1 << 7) >> numBytes)) - break; - pos++; - } - while (--numBytes); - - if (numBytes != 0) - { - if (pos == size) - Truncated = true; - else - UTF_ERROR_UTF8_CHECK - } - - #ifdef UTF_ESCAPE_BASE - if (IS_ESCAPE_POINT(val, 0)) - Escape = true; - #endif - - if (MaxHighPoint < val) - MaxHighPoint = val; - - if (IS_SURROGATE_POINT(val)) - SingleSurrogate = true; - - src += pos; - size -= pos; - } - - // MaxByte = maxByte; -} - -bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw() -{ - CUtf8Check check; - check.Check_Buf(src, size); - return check.IsOK(allowReduced); -} - -/* -bool CheckUTF8_chars(const char *src, bool allowReduced) throw() -{ - CUtf8Check check; - check.CheckBuf(src, strlen(src)); - return check.IsOK(allowReduced); -} -*/ - -bool CheckUTF8_AString(const AString &s) throw() -{ - CUtf8Check check; - check.Check_AString(s); - return check.IsOK(); -} - - -/* -bool CheckUTF8(const char *src, bool allowReduced) throw() -{ - // return Check_UTF8_Buf(src, strlen(src), allowReduced); - - for (;;) - { - const Byte c = (Byte)(*src++); - if (c == 0) - return true; - - if (c < 0x80) - continue; - if (c < 0xC0 + 2 || c >= 0xf5) - return false; - - unsigned numBytes; - MY_UTF8_HEAD_PARSE - else - return false; - - unsigned pos = 0; - - do - { - Byte c2 = (Byte)(*src++); - if (c2 < 0x80 || c2 >= 0xC0) - return allowReduced && c2 == 0; - val <<= 6; - val |= (c2 - 0x80); - pos++; - } - while (--numBytes); - - if (val < MY_UTF8_RANGE(pos - 1)) - return false; - - if (val >= 0x110000) - return false; - } -} -*/ - -// in case of UTF-8 error we have two ways: -// 21.01- : old : 0xfffd: REPLACEMENT CHARACTER : old version -// 21.02+ : new : 0xef00 + (c) : similar to WSL scheme for low symbols - -#define UTF_REPLACEMENT_CHAR 0xfffd - - - -#define UTF_ESCAPE(c) \ - ((flags & Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE) ? \ - UTF_ESCAPE_PLANE + UTF_ESCAPE_BASE + (c) : UTF_REPLACEMENT_CHAR) - -/* -#define UTF_HARD_ERROR_UTF8 - { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \ - destPos++; ok = false; continue; } -*/ - -// we ignore utf errors, and don't change (ok) variable! - -#define UTF_ERROR_UTF8 \ - { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \ - destPos++; continue; } - -// we store UTF-16 in wchar_t strings. So we use surrogates for big unicode points: - -// for debug puposes only we can store UTF-32 in wchar_t: -// #define START_POINT_FOR_SURROGATE ((UInt32)0 - 1) - - -/* - WIN32 MultiByteToWideChar(CP_UTF8) emits 0xfffd point, if utf-8 error was found. - Ant it can emit single 0xfffd from 2 src bytes. - It doesn't emit single 0xfffd from 3-4 src bytes. - We can - 1) emit Escape point for each incorrect byte. So we can data recover later - 2) emit 0xfffd for each incorrect byte. - That scheme is similar to Escape scheme, but we emit 0xfffd - instead of each Escape point. - 3) emit single 0xfffd from 1-2 incorrect bytes, as WIN32 MultiByteToWideChar scheme -*/ - -static bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, const char *srcLim, unsigned flags) throw() -{ - size_t destPos = 0; - bool ok = true; - - for (;;) - { - if (src == srcLim) - { - *destLen = destPos; - return ok; - } - - const Byte c = (Byte)(*src++); - - if (c < 0x80) - { - if (dest) - dest[destPos] = (wchar_t)c; - destPos++; - continue; - } - - if (c < 0xc0 + 2 - || c >= 0xf5) // it's limit for 0x140000 unicode codes : win32 compatibility - { - UTF_ERROR_UTF8 - } - - unsigned numBytes; - - MY_UTF8_HEAD_PARSE_MAX_3_BYTES - - unsigned pos = 0; - do - { - if (src + pos == srcLim) - break; - unsigned c2 = (Byte)src[pos]; - c2 -= 0x80; - if (c2 >= 0x40) - break; - val <<= 6; - val |= c2; - pos++; - if (pos == 1) - { - if (val < (((unsigned)1 << 7) >> numBytes)) - break; - if (numBytes == 2) - { - if (flags & Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) - if ((val & (0xF800 >> 6)) == (0xd800 >> 6)) - break; - } - else if (numBytes == 3 && val >= (0x110000 >> 12)) - break; - } - } - while (--numBytes); - - if (numBytes != 0) - { - if ((flags & Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE) == 0) - { - // the following code to emit the 0xfffd chars as win32 Utf8 function. - // disable the folling line, if you need 0xfffd for each incorrect byte as in Escape mode - src += pos; - } - UTF_ERROR_UTF8 - } - - /* - if (val < MY_UTF8_RANGE(pos - 1)) - UTF_ERROR_UTF8 - */ - - #ifdef UTF_ESCAPE_BASE - - if ((flags & Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT) - && IS_ESCAPE_POINT(val, 0)) - { - // We will emit 3 utf16-Escape-16-21 points from one Escape-16 point (3 bytes) - UTF_ERROR_UTF8 - } - - #endif - - /* - We don't expect virtual Escape-21 points in UTF-8 stream. - And we don't check for Escape-21. - So utf8-Escape-21 will be converted to another 3 utf16-Escape-21 points. - Maybe we could convert virtual utf8-Escape-21 to one utf16-Escape-21 point in some cases? - */ - - if (val < START_POINT_FOR_SURROGATE) - { - /* - if ((flags & Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) - && IS_SURROGATE_POINT(val)) - { - // We will emit 3 utf16-Escape-16-21 points from one Surrogate-16 point (3 bytes) - UTF_ERROR_UTF8 - } - */ - if (dest) - dest[destPos] = (wchar_t)val; - destPos++; - } - else - { - /* - if (val >= 0x110000) - { - // We will emit utf16-Escape-16-21 point from each source byte - UTF_ERROR_UTF8 - } - */ - if (dest) - { - dest[destPos + 0] = (wchar_t)(0xd800 - (0x10000 >> 10) + (val >> 10)); - dest[destPos + 1] = (wchar_t)(0xdc00 + (val & 0x3ff)); - } - destPos += 2; - } - src += pos; - } -} - - - -#define MY_UTF8_HEAD(n, val) ((char)(MY_UTF8_START(n) + (val >> (6 * (n))))) -#define MY_UTF8_CHAR(n, val) ((char)(0x80 + (((val) >> (6 * (n))) & 0x3F))) - -static size_t Utf16_To_Utf8_Calc(const wchar_t *src, const wchar_t *srcLim, unsigned flags) -{ - size_t size = (size_t)(srcLim - src); - for (;;) - { - if (src == srcLim) - return size; - - UInt32 val = (UInt32)(*src++); - - if (val < 0x80) - continue; - - if (val < MY_UTF8_RANGE(1)) - { - size++; - continue; - } - - #ifdef UTF_ESCAPE_BASE - - #if UTF_ESCAPE_PLANE != 0 - if (flags & Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE) - if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE)) - continue; - #endif - - if (flags & Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE) - if (IS_ESCAPE_POINT(val, 0)) - continue; - - #endif - - if (IS_SURROGATE_POINT(val)) - { - // it's hack to UTF-8 encoding - - if (val < 0xdc00 && src != srcLim) - { - const UInt32 c2 = (UInt32)*src; - if (c2 >= 0xdc00 && c2 < 0xe000) - src++; - } - size += 2; - continue; - } - - #ifdef Z7_WCHART_IS_16BIT - - size += 2; - - #else - - if (val < MY_UTF8_RANGE(2)) size += 2; - else if (val < MY_UTF8_RANGE(3)) size += 3; - else if (val < MY_UTF8_RANGE(4)) size += 4; - else if (val < MY_UTF8_RANGE(5)) size += 5; - else - #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6 - size += 6; - #else - size += 3; - #endif - - #endif - } -} - - -static char *Utf16_To_Utf8(char *dest, const wchar_t *src, const wchar_t *srcLim, unsigned flags) -{ - for (;;) - { - if (src == srcLim) - return dest; - - UInt32 val = (UInt32)*src++; - - if (val < 0x80) - { - *dest++ = (char)val; - continue; - } - - if (val < MY_UTF8_RANGE(1)) - { - dest[0] = MY_UTF8_HEAD(1, val); - dest[1] = MY_UTF8_CHAR(0, val); - dest += 2; - continue; - } - - #ifdef UTF_ESCAPE_BASE - - #if UTF_ESCAPE_PLANE != 0 - /* - if (wchar_t is 32-bit) - && (Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE is set) - && (point is virtual escape plane) - we extract 8-bit byte from virtual HIGH-ESCAPE PLANE. - */ - if (flags & Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE) - if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE)) - { - *dest++ = (char)(val); - continue; - } - #endif // UTF_ESCAPE_PLANE != 0 - - /* if (Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE is defined) - we extract 8-bit byte from BMP-ESCAPE PLANE. */ - - if (flags & Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE) - if (IS_ESCAPE_POINT(val, 0)) - { - *dest++ = (char)(val); - continue; - } - - #endif // UTF_ESCAPE_BASE - - if (IS_SURROGATE_POINT(val)) - { - // it's hack to UTF-8 encoding - if (val < 0xdc00 && src != srcLim) - { - const UInt32 c2 = (UInt32)*src; - if (IS_LOW_SURROGATE_POINT(c2)) - { - src++; - val = (((val - 0xd800) << 10) | (c2 - 0xdc00)) + 0x10000; - dest[0] = MY_UTF8_HEAD(3, val); - dest[1] = MY_UTF8_CHAR(2, val); - dest[2] = MY_UTF8_CHAR(1, val); - dest[3] = MY_UTF8_CHAR(0, val); - dest += 4; - continue; - } - } - if (flags & Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR) - val = UTF_REPLACEMENT_CHAR; // WIN32 function does it - } - - #ifndef Z7_WCHART_IS_16BIT - if (val < MY_UTF8_RANGE(2)) - #endif - { - dest[0] = MY_UTF8_HEAD(2, val); - dest[1] = MY_UTF8_CHAR(1, val); - dest[2] = MY_UTF8_CHAR(0, val); - dest += 3; - continue; - } - - #ifndef Z7_WCHART_IS_16BIT - - // we don't expect this case. so we can throw exception - // throw 20210407; - - char b; - unsigned numBits; - if (val < MY_UTF8_RANGE(3)) { numBits = 6 * 3; b = MY_UTF8_HEAD(3, val); } - else if (val < MY_UTF8_RANGE(4)) { numBits = 6 * 4; b = MY_UTF8_HEAD(4, val); } - else if (val < MY_UTF8_RANGE(5)) { numBits = 6 * 5; b = MY_UTF8_HEAD(5, val); } - #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6 - else { numBits = 6 * 6; b = (char)MY_UTF8_START(6); } - #else - else - { - val = UTF_REPLACEMENT_CHAR; - { numBits = 6 * 3; b = MY_UTF8_HEAD(3, val); } - } - #endif - - *dest++ = b; - - do - { - numBits -= 6; - *dest++ = (char)(0x80 + ((val >> numBits) & 0x3F)); - } - while (numBits != 0); - - #endif - } -} - -bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags) -{ - dest.Empty(); - size_t destLen = 0; - Utf8_To_Utf16(NULL, &destLen, src, src + srcSize, flags); - bool res = Utf8_To_Utf16(dest.GetBuf((unsigned)destLen), &destLen, src, src + srcSize, flags); - dest.ReleaseBuf_SetEnd((unsigned)destLen); - return res; -} - -bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags) -{ - return Convert_UTF8_Buf_To_Unicode(src, src.Len(), dest, flags); -} - - -static -unsigned g_UTF8_To_Unicode_Flags = - Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE - #ifndef Z7_WCHART_IS_16BIT - | Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR - #ifdef MY_UTF8_RAW_NON_UTF8_SUPPORTED - | Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT - #endif - #endif - ; - - -/* -bool ConvertUTF8ToUnicode_boolRes(const AString &src, UString &dest) -{ - return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags); -} -*/ - -bool ConvertUTF8ToUnicode(const AString &src, UString &dest) -{ - return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags); -} - -void Print_UString(const UString &a); - -void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags) -{ - /* - if (src.Len()== 24) - throw "202104"; - */ - dest.Empty(); - const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags); - char *destStart = dest.GetBuf((unsigned)destLen); - const char *destEnd = Utf16_To_Utf8(destStart, src, src.Ptr(src.Len()), flags); - dest.ReleaseBuf_SetEnd((unsigned)destLen); - // printf("\nlen = %d\n", src.Len()); - if (destLen != (size_t)(destEnd - destStart)) - { - /* - // dest.ReleaseBuf_SetEnd((unsigned)(destEnd - destStart)); - printf("\nlen = %d\n", (unsigned)destLen); - printf("\n(destEnd - destStart) = %d\n", (unsigned)(destEnd - destStart)); - printf("\n"); - // Print_UString(src); - printf("\n"); - // printf("\nlen = %d\n", destLen); - */ - throw 20210406; - } -} - - - -unsigned g_Unicode_To_UTF8_Flags = - // Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE - 0 - #ifndef _WIN32 - #ifdef MY_UTF8_RAW_NON_UTF8_SUPPORTED - | Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE - #else - | Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR - #endif - #endif - ; - -void ConvertUnicodeToUTF8(const UString &src, AString &dest) -{ - ConvertUnicodeToUTF8_Flags(src, dest, g_Unicode_To_UTF8_Flags); -} - -void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest) -{ - const unsigned flags = g_Unicode_To_UTF8_Flags; - dest.Free(); - const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags); - dest.Alloc(destLen); - const char *destEnd = Utf16_To_Utf8((char *)(void *)(Byte *)dest, src, src.Ptr(src.Len()), flags); - if (destLen != (size_t)(destEnd - (char *)(void *)(Byte *)dest)) - throw 202104; -} - -/* - -#ifndef _WIN32 -void Convert_UTF16_To_UTF32(const UString &src, UString &dest) -{ - dest.Empty(); - for (size_t i = 0; i < src.Len();) - { - wchar_t c = src[i++]; - if (c >= 0xd800 && c < 0xdc00 && i < src.Len()) - { - const wchar_t c2 = src[i]; - if (c2 >= 0xdc00 && c2 < 0xe000) - { - // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2); - c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); - // printf("%4x\n", (int)c); - i++; - } - } - dest += c; - } -} - -void Convert_UTF32_To_UTF16(const UString &src, UString &dest) -{ - dest.Empty(); - for (size_t i = 0; i < src.Len();) - { - wchar_t w = src[i++]; - if (w >= 0x10000 && w < 0x110000) - { - w -= 0x10000; - dest += (wchar_t)((unsigned)0xd800 + (((unsigned)w >> 10) & 0x3ff)); - w = 0xdc00 + (w & 0x3ff); - } - dest += w; - } -} - -bool UTF32_IsThere_BigPoint(const UString &src) -{ - for (size_t i = 0; i < src.Len();) - { - const UInt32 c = (UInt32)src[i++]; - if (c >= 0x110000) - return true; - } - return false; -} - -bool Unicode_IsThere_BmpEscape(const UString &src) -{ - for (size_t i = 0; i < src.Len();) - { - const UInt32 c = (UInt32)src[i++]; - if (IS_ESCAPE_POINT(c, 0)) - return true; - } - return false; -} - - -#endif - -bool Unicode_IsThere_Utf16SurrogateError(const UString &src) -{ - for (size_t i = 0; i < src.Len();) - { - const UInt32 val = (UInt32)src[i++]; - if (IS_SURROGATE_POINT(val)) - { - // it's hack to UTF-8 encoding - if (val >= 0xdc00 || i == src.Len()) - return true; - const UInt32 c2 = (UInt32)*src; - if (!IS_LOW_SURROGATE_POINT(c2)) - return true; - } - } - return false; -} -*/ - -#ifndef Z7_WCHART_IS_16BIT - -void Convert_UnicodeEsc16_To_UnicodeEscHigh -#if UTF_ESCAPE_PLANE == 0 - (UString &) {} -#else - (UString &s) -{ - const unsigned len = s.Len(); - for (unsigned i = 0; i < len; i++) - { - wchar_t c = s[i]; - if (IS_ESCAPE_POINT(c, 0)) - { - c += UTF_ESCAPE_PLANE; - s.ReplaceOneCharAtPos(i, c); - } - } -} -#endif -#endif +// UTFConvert.cpp + +#include "StdAfx.h" + +// #include + +#include "MyTypes.h" +#include "UTFConvert.h" + + +#ifndef Z7_WCHART_IS_16BIT +#ifndef __APPLE__ + // we define it if the system supports files with non-utf8 symbols: + #define MY_UTF8_RAW_NON_UTF8_SUPPORTED +#endif +#endif + +/* + MY_UTF8_START(n) - is a base value for start byte (head), if there are (n) additional bytes after start byte + + n : MY_UTF8_START(n) : Bits of code point + + 0 : 0x80 : : unused + 1 : 0xC0 : 11 : + 2 : 0xE0 : 16 : Basic Multilingual Plane + 3 : 0xF0 : 21 : Unicode space + 4 : 0xF8 : 26 : + 5 : 0xFC : 31 : UCS-4 : wcstombs() in ubuntu is limited to that value + 6 : 0xFE : 36 : We can use it, if we want to encode any 32-bit value + 7 : 0xFF : +*/ + +#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n)))) + +#define MY_UTF8_HEAD_PARSE2(n) \ + if (c < MY_UTF8_START((n) + 1)) \ + { numBytes = (n); val -= MY_UTF8_START(n); } + +#ifndef Z7_WCHART_IS_16BIT + +/* + if (wchar_t is 32-bit), we can support large points in long UTF-8 sequence, + when we convert wchar_t strings to UTF-8: + (_UTF8_NUM_TAIL_BYTES_MAX == 3) : (21-bits points) - Unicode + (_UTF8_NUM_TAIL_BYTES_MAX == 5) : (31-bits points) - UCS-4 + (_UTF8_NUM_TAIL_BYTES_MAX == 6) : (36-bit hack) +*/ + +#define MY_UTF8_NUM_TAIL_BYTES_MAX 5 +#endif + +/* +#define MY_UTF8_HEAD_PARSE \ + UInt32 val = c; \ + MY_UTF8_HEAD_PARSE2(1) \ + else MY_UTF8_HEAD_PARSE2(2) \ + else MY_UTF8_HEAD_PARSE2(3) \ + else MY_UTF8_HEAD_PARSE2(4) \ + else MY_UTF8_HEAD_PARSE2(5) \ + #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6 + else MY_UTF8_HEAD_PARSE2(6) + #endif +*/ + +#define MY_UTF8_HEAD_PARSE_MAX_3_BYTES \ + UInt32 val = c; \ + MY_UTF8_HEAD_PARSE2(1) \ + else MY_UTF8_HEAD_PARSE2(2) \ + else { numBytes = 3; val -= MY_UTF8_START(3); } + + +#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) + + +#define START_POINT_FOR_SURROGATE 0x10000 + + +/* we use 128 bytes block in 16-bit BMP-PLANE to encode non-UTF-8 Escapes + Also we can use additional HIGH-PLANE (we use 21-bit points above 0x1f0000) + to simplify internal intermediate conversion in Linux: + RAW-UTF-8 <-> internal wchar_t utf-16 strings <-> RAW-UTF-UTF-8 +*/ + + +#if defined(Z7_WCHART_IS_16BIT) + +#define UTF_ESCAPE_PLANE 0 + +#else + +/* +we can place 128 ESCAPE chars to + ef 80 - ee be 80 (3-bytes utf-8) : similar to WSL + ef ff - ee bf bf + +1f ef 80 - f7 be be 80 (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode) +1f ef ff - f7 be bf bf (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode) +*/ + +// #define UTF_ESCAPE_PLANE_HIGH (0x1f << 16) +// #define UTF_ESCAPE_PLANE UTF_ESCAPE_PLANE_HIGH +#define UTF_ESCAPE_PLANE 0 + +/* + if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is set) + { + if (UTF_ESCAPE_PLANE is UTF_ESCAPE_PLANE_HIGH) + { + we can restore any 8-bit Escape from ESCAPE-PLANE-21 plane. + But ESCAPE-PLANE-21 point cannot be stored to utf-16 (7z archive) + So we still need a way to extract 8-bit Escapes and BMP-Escapes-8 + from same BMP-Escapes-16 stored in 7z. + And if we want to restore any 8-bit from 7z archive, + we still must use Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT for (utf-8 -> utf-16) + Also we need additional Conversions to tranform from utf-16 to utf-16-With-Escapes-21 + } + else (UTF_ESCAPE_PLANE == 0) + { + we must convert original 3-bytes utf-8 BMP-Escape point to sequence + of 3 BMP-Escape-16 points with Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT + so we can extract original RAW-UTF-8 from UTFD-16 later. + } + } +*/ + +#endif + + + +#define UTF_ESCAPE_BASE 0xef00 + + +#ifdef UTF_ESCAPE_BASE +#define IS_ESCAPE_POINT(v, plane) (((v) & (UInt32)0xffffff80) == (plane) + UTF_ESCAPE_BASE + 0x80) +#endif + +#define IS_SURROGATE_POINT(v) (((v) & (UInt32)0xfffff800) == 0xd800) +#define IS_LOW_SURROGATE_POINT(v) (((v) & (UInt32)0xfffffc00) == 0xdc00) + + +#define UTF_ERROR_UTF8_CHECK \ + { NonUtf = true; continue; } + +void CUtf8Check::Check_Buf(const char *src, size_t size) throw() +{ + Clear(); + // Byte maxByte = 0; + + for (;;) + { + if (size == 0) + break; + + const Byte c = (Byte)(*src++); + size--; + + if (c == 0) + { + ZeroChar = true; + continue; + } + + /* + if (c > maxByte) + maxByte = c; + */ + + if (c < 0x80) + continue; + + if (c < 0xc0 + 2) + UTF_ERROR_UTF8_CHECK + + unsigned numBytes; + UInt32 val = c; + MY_UTF8_HEAD_PARSE2(1) + else MY_UTF8_HEAD_PARSE2(2) + else MY_UTF8_HEAD_PARSE2(3) + else MY_UTF8_HEAD_PARSE2(4) + else MY_UTF8_HEAD_PARSE2(5) + else + { + UTF_ERROR_UTF8_CHECK + } + + unsigned pos = 0; + do + { + if (pos == size) + break; + unsigned c2 = (Byte)src[pos]; + c2 -= 0x80; + if (c2 >= 0x40) + break; + val <<= 6; + val |= c2; + if (pos == 0) + if (val < (((unsigned)1 << 7) >> numBytes)) + break; + pos++; + } + while (--numBytes); + + if (numBytes != 0) + { + if (pos == size) + Truncated = true; + else + UTF_ERROR_UTF8_CHECK + } + + #ifdef UTF_ESCAPE_BASE + if (IS_ESCAPE_POINT(val, 0)) + Escape = true; + #endif + + if (MaxHighPoint < val) + MaxHighPoint = val; + + if (IS_SURROGATE_POINT(val)) + SingleSurrogate = true; + + src += pos; + size -= pos; + } + + // MaxByte = maxByte; +} + +bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw() +{ + CUtf8Check check; + check.Check_Buf(src, size); + return check.IsOK(allowReduced); +} + +/* +bool CheckUTF8_chars(const char *src, bool allowReduced) throw() +{ + CUtf8Check check; + check.CheckBuf(src, strlen(src)); + return check.IsOK(allowReduced); +} +*/ + +bool CheckUTF8_AString(const AString &s) throw() +{ + CUtf8Check check; + check.Check_AString(s); + return check.IsOK(); +} + + +/* +bool CheckUTF8(const char *src, bool allowReduced) throw() +{ + // return Check_UTF8_Buf(src, strlen(src), allowReduced); + + for (;;) + { + const Byte c = (Byte)(*src++); + if (c == 0) + return true; + + if (c < 0x80) + continue; + if (c < 0xC0 + 2 || c >= 0xf5) + return false; + + unsigned numBytes; + MY_UTF8_HEAD_PARSE + else + return false; + + unsigned pos = 0; + + do + { + Byte c2 = (Byte)(*src++); + if (c2 < 0x80 || c2 >= 0xC0) + return allowReduced && c2 == 0; + val <<= 6; + val |= (c2 - 0x80); + pos++; + } + while (--numBytes); + + if (val < MY_UTF8_RANGE(pos - 1)) + return false; + + if (val >= 0x110000) + return false; + } +} +*/ + +// in case of UTF-8 error we have two ways: +// 21.01- : old : 0xfffd: REPLACEMENT CHARACTER : old version +// 21.02+ : new : 0xef00 + (c) : similar to WSL scheme for low symbols + +#define UTF_REPLACEMENT_CHAR 0xfffd + + + +#define UTF_ESCAPE(c) \ + ((flags & Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE) ? \ + UTF_ESCAPE_PLANE + UTF_ESCAPE_BASE + (c) : UTF_REPLACEMENT_CHAR) + +/* +#define UTF_HARD_ERROR_UTF8 + { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \ + destPos++; ok = false; continue; } +*/ + +// we ignore utf errors, and don't change (ok) variable! + +#define UTF_ERROR_UTF8 \ + { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \ + destPos++; continue; } + +// we store UTF-16 in wchar_t strings. So we use surrogates for big unicode points: + +// for debug puposes only we can store UTF-32 in wchar_t: +// #define START_POINT_FOR_SURROGATE ((UInt32)0 - 1) + + +/* + WIN32 MultiByteToWideChar(CP_UTF8) emits 0xfffd point, if utf-8 error was found. + Ant it can emit single 0xfffd from 2 src bytes. + It doesn't emit single 0xfffd from 3-4 src bytes. + We can + 1) emit Escape point for each incorrect byte. So we can data recover later + 2) emit 0xfffd for each incorrect byte. + That scheme is similar to Escape scheme, but we emit 0xfffd + instead of each Escape point. + 3) emit single 0xfffd from 1-2 incorrect bytes, as WIN32 MultiByteToWideChar scheme +*/ + +static bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, const char *srcLim, unsigned flags) throw() +{ + size_t destPos = 0; + bool ok = true; + + for (;;) + { + if (src == srcLim) + { + *destLen = destPos; + return ok; + } + + const Byte c = (Byte)(*src++); + + if (c < 0x80) + { + if (dest) + dest[destPos] = (wchar_t)c; + destPos++; + continue; + } + + if (c < 0xc0 + 2 + || c >= 0xf5) // it's limit for 0x140000 unicode codes : win32 compatibility + { + UTF_ERROR_UTF8 + } + + unsigned numBytes; + + MY_UTF8_HEAD_PARSE_MAX_3_BYTES + + unsigned pos = 0; + do + { + if (src + pos == srcLim) + break; + unsigned c2 = (Byte)src[pos]; + c2 -= 0x80; + if (c2 >= 0x40) + break; + val <<= 6; + val |= c2; + pos++; + if (pos == 1) + { + if (val < (((unsigned)1 << 7) >> numBytes)) + break; + if (numBytes == 2) + { + if (flags & Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) + if ((val & (0xF800 >> 6)) == (0xd800 >> 6)) + break; + } + else if (numBytes == 3 && val >= (0x110000 >> 12)) + break; + } + } + while (--numBytes); + + if (numBytes != 0) + { + if ((flags & Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE) == 0) + { + // the following code to emit the 0xfffd chars as win32 Utf8 function. + // disable the folling line, if you need 0xfffd for each incorrect byte as in Escape mode + src += pos; + } + UTF_ERROR_UTF8 + } + + /* + if (val < MY_UTF8_RANGE(pos - 1)) + UTF_ERROR_UTF8 + */ + + #ifdef UTF_ESCAPE_BASE + + if ((flags & Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT) + && IS_ESCAPE_POINT(val, 0)) + { + // We will emit 3 utf16-Escape-16-21 points from one Escape-16 point (3 bytes) + UTF_ERROR_UTF8 + } + + #endif + + /* + We don't expect virtual Escape-21 points in UTF-8 stream. + And we don't check for Escape-21. + So utf8-Escape-21 will be converted to another 3 utf16-Escape-21 points. + Maybe we could convert virtual utf8-Escape-21 to one utf16-Escape-21 point in some cases? + */ + + if (val < START_POINT_FOR_SURROGATE) + { + /* + if ((flags & Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) + && IS_SURROGATE_POINT(val)) + { + // We will emit 3 utf16-Escape-16-21 points from one Surrogate-16 point (3 bytes) + UTF_ERROR_UTF8 + } + */ + if (dest) + dest[destPos] = (wchar_t)val; + destPos++; + } + else + { + /* + if (val >= 0x110000) + { + // We will emit utf16-Escape-16-21 point from each source byte + UTF_ERROR_UTF8 + } + */ + if (dest) + { + dest[destPos + 0] = (wchar_t)(0xd800 - (0x10000 >> 10) + (val >> 10)); + dest[destPos + 1] = (wchar_t)(0xdc00 + (val & 0x3ff)); + } + destPos += 2; + } + src += pos; + } +} + + + +#define MY_UTF8_HEAD(n, val) ((char)(MY_UTF8_START(n) + (val >> (6 * (n))))) +#define MY_UTF8_CHAR(n, val) ((char)(0x80 + (((val) >> (6 * (n))) & 0x3F))) + +static size_t Utf16_To_Utf8_Calc(const wchar_t *src, const wchar_t *srcLim, unsigned flags) +{ + size_t size = (size_t)(srcLim - src); + for (;;) + { + if (src == srcLim) + return size; + + UInt32 val = (UInt32)(*src++); + + if (val < 0x80) + continue; + + if (val < MY_UTF8_RANGE(1)) + { + size++; + continue; + } + + #ifdef UTF_ESCAPE_BASE + + #if UTF_ESCAPE_PLANE != 0 + if (flags & Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE) + if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE)) + continue; + #endif + + if (flags & Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE) + if (IS_ESCAPE_POINT(val, 0)) + continue; + + #endif + + if (IS_SURROGATE_POINT(val)) + { + // it's hack to UTF-8 encoding + + if (val < 0xdc00 && src != srcLim) + { + const UInt32 c2 = (UInt32)*src; + if (c2 >= 0xdc00 && c2 < 0xe000) + src++; + } + size += 2; + continue; + } + + #ifdef Z7_WCHART_IS_16BIT + + size += 2; + + #else + + if (val < MY_UTF8_RANGE(2)) size += 2; + else if (val < MY_UTF8_RANGE(3)) size += 3; + else if (val < MY_UTF8_RANGE(4)) size += 4; + else if (val < MY_UTF8_RANGE(5)) size += 5; + else + #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6 + size += 6; + #else + size += 3; + #endif + + #endif + } +} + + +static char *Utf16_To_Utf8(char *dest, const wchar_t *src, const wchar_t *srcLim, unsigned flags) +{ + for (;;) + { + if (src == srcLim) + return dest; + + UInt32 val = (UInt32)*src++; + + if (val < 0x80) + { + *dest++ = (char)val; + continue; + } + + if (val < MY_UTF8_RANGE(1)) + { + dest[0] = MY_UTF8_HEAD(1, val); + dest[1] = MY_UTF8_CHAR(0, val); + dest += 2; + continue; + } + + #ifdef UTF_ESCAPE_BASE + + #if UTF_ESCAPE_PLANE != 0 + /* + if (wchar_t is 32-bit) + && (Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE is set) + && (point is virtual escape plane) + we extract 8-bit byte from virtual HIGH-ESCAPE PLANE. + */ + if (flags & Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE) + if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE)) + { + *dest++ = (char)(val); + continue; + } + #endif // UTF_ESCAPE_PLANE != 0 + + /* if (Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE is defined) + we extract 8-bit byte from BMP-ESCAPE PLANE. */ + + if (flags & Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE) + if (IS_ESCAPE_POINT(val, 0)) + { + *dest++ = (char)(val); + continue; + } + + #endif // UTF_ESCAPE_BASE + + if (IS_SURROGATE_POINT(val)) + { + // it's hack to UTF-8 encoding + if (val < 0xdc00 && src != srcLim) + { + const UInt32 c2 = (UInt32)*src; + if (IS_LOW_SURROGATE_POINT(c2)) + { + src++; + val = (((val - 0xd800) << 10) | (c2 - 0xdc00)) + 0x10000; + dest[0] = MY_UTF8_HEAD(3, val); + dest[1] = MY_UTF8_CHAR(2, val); + dest[2] = MY_UTF8_CHAR(1, val); + dest[3] = MY_UTF8_CHAR(0, val); + dest += 4; + continue; + } + } + if (flags & Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR) + val = UTF_REPLACEMENT_CHAR; // WIN32 function does it + } + + #ifndef Z7_WCHART_IS_16BIT + if (val < MY_UTF8_RANGE(2)) + #endif + { + dest[0] = MY_UTF8_HEAD(2, val); + dest[1] = MY_UTF8_CHAR(1, val); + dest[2] = MY_UTF8_CHAR(0, val); + dest += 3; + continue; + } + + #ifndef Z7_WCHART_IS_16BIT + + // we don't expect this case. so we can throw exception + // throw 20210407; + + char b; + unsigned numBits; + if (val < MY_UTF8_RANGE(3)) { numBits = 6 * 3; b = MY_UTF8_HEAD(3, val); } + else if (val < MY_UTF8_RANGE(4)) { numBits = 6 * 4; b = MY_UTF8_HEAD(4, val); } + else if (val < MY_UTF8_RANGE(5)) { numBits = 6 * 5; b = MY_UTF8_HEAD(5, val); } + #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6 + else { numBits = 6 * 6; b = (char)MY_UTF8_START(6); } + #else + else + { + val = UTF_REPLACEMENT_CHAR; + { numBits = 6 * 3; b = MY_UTF8_HEAD(3, val); } + } + #endif + + *dest++ = b; + + do + { + numBits -= 6; + *dest++ = (char)(0x80 + ((val >> numBits) & 0x3F)); + } + while (numBits != 0); + + #endif + } +} + +bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags) +{ + dest.Empty(); + size_t destLen = 0; + Utf8_To_Utf16(NULL, &destLen, src, src + srcSize, flags); + bool res = Utf8_To_Utf16(dest.GetBuf((unsigned)destLen), &destLen, src, src + srcSize, flags); + dest.ReleaseBuf_SetEnd((unsigned)destLen); + return res; +} + +bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags) +{ + return Convert_UTF8_Buf_To_Unicode(src, src.Len(), dest, flags); +} + + +static +unsigned g_UTF8_To_Unicode_Flags = + Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE + #ifndef Z7_WCHART_IS_16BIT + | Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR + #ifdef MY_UTF8_RAW_NON_UTF8_SUPPORTED + | Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT + #endif + #endif + ; + + +/* +bool ConvertUTF8ToUnicode_boolRes(const AString &src, UString &dest) +{ + return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags); +} +*/ + +bool ConvertUTF8ToUnicode(const AString &src, UString &dest) +{ + return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags); +} + +void Print_UString(const UString &a); + +void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags) +{ + /* + if (src.Len()== 24) + throw "202104"; + */ + dest.Empty(); + const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags); + char *destStart = dest.GetBuf((unsigned)destLen); + const char *destEnd = Utf16_To_Utf8(destStart, src, src.Ptr(src.Len()), flags); + dest.ReleaseBuf_SetEnd((unsigned)destLen); + // printf("\nlen = %d\n", src.Len()); + if (destLen != (size_t)(destEnd - destStart)) + { + /* + // dest.ReleaseBuf_SetEnd((unsigned)(destEnd - destStart)); + printf("\nlen = %d\n", (unsigned)destLen); + printf("\n(destEnd - destStart) = %d\n", (unsigned)(destEnd - destStart)); + printf("\n"); + // Print_UString(src); + printf("\n"); + // printf("\nlen = %d\n", destLen); + */ + throw 20210406; + } +} + + + +unsigned g_Unicode_To_UTF8_Flags = + // Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE + 0 + #ifndef _WIN32 + #ifdef MY_UTF8_RAW_NON_UTF8_SUPPORTED + | Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE + #else + | Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR + #endif + #endif + ; + +void ConvertUnicodeToUTF8(const UString &src, AString &dest) +{ + ConvertUnicodeToUTF8_Flags(src, dest, g_Unicode_To_UTF8_Flags); +} + +void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest) +{ + const unsigned flags = g_Unicode_To_UTF8_Flags; + dest.Free(); + const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags); + dest.Alloc(destLen); + const char *destEnd = Utf16_To_Utf8((char *)(void *)(Byte *)dest, src, src.Ptr(src.Len()), flags); + if (destLen != (size_t)(destEnd - (char *)(void *)(Byte *)dest)) + throw 202104; +} + +/* + +#ifndef _WIN32 +void Convert_UTF16_To_UTF32(const UString &src, UString &dest) +{ + dest.Empty(); + for (size_t i = 0; i < src.Len();) + { + wchar_t c = src[i++]; + if (c >= 0xd800 && c < 0xdc00 && i < src.Len()) + { + const wchar_t c2 = src[i]; + if (c2 >= 0xdc00 && c2 < 0xe000) + { + // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2); + c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); + // printf("%4x\n", (int)c); + i++; + } + } + dest += c; + } +} + +void Convert_UTF32_To_UTF16(const UString &src, UString &dest) +{ + dest.Empty(); + for (size_t i = 0; i < src.Len();) + { + wchar_t w = src[i++]; + if (w >= 0x10000 && w < 0x110000) + { + w -= 0x10000; + dest += (wchar_t)((unsigned)0xd800 + (((unsigned)w >> 10) & 0x3ff)); + w = 0xdc00 + (w & 0x3ff); + } + dest += w; + } +} + +bool UTF32_IsThere_BigPoint(const UString &src) +{ + for (size_t i = 0; i < src.Len();) + { + const UInt32 c = (UInt32)src[i++]; + if (c >= 0x110000) + return true; + } + return false; +} + +bool Unicode_IsThere_BmpEscape(const UString &src) +{ + for (size_t i = 0; i < src.Len();) + { + const UInt32 c = (UInt32)src[i++]; + if (IS_ESCAPE_POINT(c, 0)) + return true; + } + return false; +} + + +#endif + +bool Unicode_IsThere_Utf16SurrogateError(const UString &src) +{ + for (size_t i = 0; i < src.Len();) + { + const UInt32 val = (UInt32)src[i++]; + if (IS_SURROGATE_POINT(val)) + { + // it's hack to UTF-8 encoding + if (val >= 0xdc00 || i == src.Len()) + return true; + const UInt32 c2 = (UInt32)*src; + if (!IS_LOW_SURROGATE_POINT(c2)) + return true; + } + } + return false; +} +*/ + +#ifndef Z7_WCHART_IS_16BIT + +void Convert_UnicodeEsc16_To_UnicodeEscHigh +#if UTF_ESCAPE_PLANE == 0 + (UString &) {} +#else + (UString &s) +{ + const unsigned len = s.Len(); + for (unsigned i = 0; i < len; i++) + { + wchar_t c = s[i]; + if (IS_ESCAPE_POINT(c, 0)) + { + c += UTF_ESCAPE_PLANE; + s.ReplaceOneCharAtPos(i, c); + } + } +} +#endif +#endif diff --git a/CPP/Common/UTFConvert.h b/CPP/Common/UTFConvert.h index 2fa33d549..94a8024fb 100644 --- a/CPP/Common/UTFConvert.h +++ b/CPP/Common/UTFConvert.h @@ -1,384 +1,384 @@ -// Common/UTFConvert.h - -#ifndef ZIP7_INC_COMMON_UTF_CONVERT_H -#define ZIP7_INC_COMMON_UTF_CONVERT_H - -#include "MyBuffer.h" -#include "MyString.h" - -struct CUtf8Check -{ - // Byte MaxByte; // in original src stream - bool NonUtf; - bool ZeroChar; - bool SingleSurrogate; - bool Escape; - bool Truncated; - UInt32 MaxHighPoint; // only for points >= 0x80 - - CUtf8Check() { Clear(); } - - void Clear() - { - // MaxByte = 0; - NonUtf = false; - ZeroChar = false; - SingleSurrogate = false; - Escape = false; - Truncated = false; - MaxHighPoint = 0; - } - - void Update(const CUtf8Check &c) - { - if (c.NonUtf) NonUtf = true; - if (c.ZeroChar) ZeroChar = true; - if (c.SingleSurrogate) SingleSurrogate = true; - if (c.Escape) Escape = true; - if (c.Truncated) Truncated = true; - if (MaxHighPoint < c.MaxHighPoint) MaxHighPoint = c.MaxHighPoint; - } - - void PrintStatus(AString &s) const - { - s.Empty(); - - // s.Add_OptSpaced("MaxByte="); - // s.Add_UInt32(MaxByte); - - if (NonUtf) s.Add_OptSpaced("non-UTF8"); - if (ZeroChar) s.Add_OptSpaced("ZeroChar"); - if (SingleSurrogate) s.Add_OptSpaced("SingleSurrogate"); - if (Escape) s.Add_OptSpaced("Escape"); - if (Truncated) s.Add_OptSpaced("Truncated"); - - if (MaxHighPoint != 0) - { - s.Add_OptSpaced("MaxUnicode="); - s.Add_UInt32(MaxHighPoint); - } - } - - - bool IsOK(bool allowReduced = false) const - { - if (NonUtf || SingleSurrogate || ZeroChar) - return false; - if (MaxHighPoint >= 0x110000) - return false; - if (Truncated && !allowReduced) - return false; - return true; - } - - // it checks full buffer as specified in (size) and it doesn't stop on zero char - void Check_Buf(const char *src, size_t size) throw(); - - void Check_AString(const AString &s) throw() - { - Check_Buf(s.Ptr(), s.Len()); - } -}; - -/* -if (allowReduced == false) - all UTF-8 character sequences must be finished. -if (allowReduced == true) - it allows truncated last character-Utf8-sequence -*/ - -bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw(); -bool CheckUTF8_AString(const AString &s) throw(); - -#define Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR (1 << 0) -#define Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE (1 << 1) -#define Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT (1 << 2) - -/* -Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR - - if (flag is NOT set) - { - it processes SINGLE-SURROGATE-8 as valid Unicode point. - it converts SINGLE-SURROGATE-8 to SINGLE-SURROGATE-16 - Note: some sequencies of two SINGLE-SURROGATE-8 points - will generate correct SURROGATE-16-PAIR, and - that SURROGATE-16-PAIR later will be converted to correct - UTF8-SURROGATE-21 point. So we don't restore original - STR-8 sequence in that case. - } - - if (flag is set) - { - if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is defined) - it generates ESCAPE for SINGLE-SURROGATE-8, - if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is not defined) - it generates U+fffd for SINGLE-SURROGATE-8, - } - - -Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE - - if (flag is NOT set) - it generates (U+fffd) code for non-UTF-8 (invalid) characters - - if (flag is set) - { - It generates (ESCAPE) codes for NON-UTF-8 (invalid) characters. - And later we can restore original UTF-8-RAW characters from (ESCAPE-16-21) codes. - } - -Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT - - if (flag is NOT set) - { - it process ESCAPE-8 points as another Unicode points. - In Linux: ESCAPE-16 will mean two different ESCAPE-8 seqences, - so we need HIGH-ESCAPE-PLANE-21 to restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW - } - - if (flag is set) - { - it generates ESCAPE-16-21 for ESCAPE-8 points - so we can restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW without HIGH-ESCAPE-PLANE-21. - } - - -Main USE CASES with UTF-8 <-> UTF-16 conversions: - - WIN32: UTF-16-RAW -> UTF-8 (Archive) -> UTF-16-RAW - { - set Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE - Do NOT set Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR - Do NOT set Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT - - So we restore original SINGLE-SURROGATE-16 from single SINGLE-SURROGATE-8. - } - - Linux: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW - { - we want restore original UTF-8-RAW sequence later from that ESCAPE-16. - Set the flags: - Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR - Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE - Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT - } - - MacOS: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW - { - we want to restore correct UTF-8 without any BMP processing: - Set the flags: - Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR - Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE - } - -*/ - -// zero char is not allowed in (src) buf -bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags = 0); - -bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags = 0); -bool ConvertUTF8ToUnicode(const AString &src, UString &dest); - -#define Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR (1 << 8) -#define Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE (1 << 9) -// #define Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE (1 << 10) - -/* -Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR - - if (flag is NOT set) - { - we extract SINGLE-SURROGATE as normal UTF-8 - - In Windows : for UTF-16-RAW <-> UTF-8 (archive) <-> UTF-16-RAW in . - - In Linux : - use-case-1: UTF-8 -> UTF-16 -> UTF-8 doesn't generate UTF-16 SINGLE-SURROGATE, - if (Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) is used. - use-case 2: UTF-16-7z (with SINGLE-SURROGATE from Windows) -> UTF-8 (Linux) - will generate SINGLE-SURROGATE-UTF-8 here. - } - - if (flag is set) - { - we generate UTF_REPLACEMENT_CHAR (0xfffd) for SINGLE_SURROGATE - it can be used for compatibility mode with WIN32 UTF function - or if we want UTF-8 stream without any errors - } - - -Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE - - if (flag is NOT set) it doesn't extract raw 8-bit symbol from Escape-Plane-16 - if (flag is set) it extracts raw 8-bit symbol from Escape-Plane-16 - - in Linux we need some way to extract NON-UTF8 RAW 8-bits from BMP (UTF-16 7z archive): - if (we use High-Escape-Plane), we can transfer BMP escapes to High-Escape-Plane. - if (we don't use High-Escape-Plane), we must use Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE. - - -Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE - // that flag affects the code only if (wchar_t is 32-bit) - // that mode with high-escape can be disabled now in UTFConvert.cpp - if (flag is NOT set) - it doesn't extract raw 8-bit symbol from High-Escape-Plane - if (flag is set) - it extracts raw 8-bit symbol from High-Escape-Plane - -Main use cases: - -WIN32 : UTF-16-RAW -> UTF-8 (archive) -> UTF-16-RAW - { - Do NOT set Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE. - Do NOT set Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR. - So we restore original UTF-16-RAW. - } - -Linix : UTF-8 with Escapes -> UTF-16 (7z archive) -> UTF-8 with Escapes - set Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE to extract non-UTF from 7z archive - set Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE for intermediate UTF-16. - Note: high esacape mode can be ignored now in UTFConvert.cpp - -macOS: - the system doesn't support incorrect UTF-8 in file names. - set Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR -*/ - -extern unsigned g_Unicode_To_UTF8_Flags; - -void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags = 0); -void ConvertUnicodeToUTF8(const UString &src, AString &dest); - -void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest); - -/* -#ifndef _WIN32 -void Convert_UTF16_To_UTF32(const UString &src, UString &dest); -void Convert_UTF32_To_UTF16(const UString &src, UString &dest); -bool UTF32_IsThere_BigPoint(const UString &src); -bool Unicode_IsThere_BmpEscape(const UString &src); -#endif - -bool Unicode_IsThere_Utf16SurrogateError(const UString &src); -*/ - -#ifdef Z7_WCHART_IS_16BIT -#define Convert_UnicodeEsc16_To_UnicodeEscHigh(s) -#else -void Convert_UnicodeEsc16_To_UnicodeEscHigh(UString &s); -#endif - -/* -// #include "../../C/CpuArch.h" - -// ---------- Utf16 Little endian functions ---------- - -// We store 16-bit surrogates even in 32-bit WCHARs in Linux. -// So now we don't use the following code: - -#if WCHAR_MAX > 0xffff - -// void *p : pointer to src bytes stream -// size_t len : num Utf16 characters : it can include or not include NULL character - -inline size_t Utf16LE__Get_Num_WCHARs(const void *p, size_t len) -{ - #if WCHAR_MAX > 0xffff - size_t num_wchars = 0; - for (size_t i = 0; i < len; i++) - { - wchar_t c = GetUi16(p); - p = (const void *)((const Byte *)p + 2); - if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) - { - wchar_t c2 = GetUi16(p); - if (c2 >= 0xdc00 && c2 < 0xe000) - { - c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); - p = (const void *)((const Byte *)p + 2); - i++; - } - } - num_wchars++; - } - return num_wchars; - #else - UNUSED_VAR(p) - return len; - #endif -} - -// #include - -inline wchar_t *Utf16LE__To_WCHARs_Sep(const void *p, size_t len, wchar_t *dest) -{ - for (size_t i = 0; i < len; i++) - { - wchar_t c = GetUi16(p); - p = (const void *)((const Byte *)p + 2); - - #if WCHAR_PATH_SEPARATOR != L'/' - if (c == L'/') - c = WCHAR_PATH_SEPARATOR; - #endif - - #if WCHAR_MAX > 0xffff - - if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) - { - wchar_t c2 = GetUi16(p); - if (c2 >= 0xdc00 && c2 < 0xe000) - { - // printf("\nSurragate : %4x %4x -> ", (int)c, (int)c2); - c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); - p = (const void *)((const Byte *)p + 2); - i++; - // printf("%4x\n", (int)c); - } - } - - #endif - - *dest++ = c; - } - return dest; -} - - -inline size_t Get_Num_Utf16_chars_from_wchar_string(const wchar_t *p) -{ - size_t num = 0; - for (;;) - { - wchar_t c = *p++; - if (c == 0) - return num; - num += ((c >= 0x10000 && c < 0x110000) ? 2 : 1); - } - return num; -} - -inline Byte *wchars_to_Utf16LE(const wchar_t *p, Byte *dest) -{ - for (;;) - { - wchar_t c = *p++; - if (c == 0) - return dest; - if (c >= 0x10000 && c < 0x110000) - { - SetUi16(dest , (UInt16)(0xd800 + ((c >> 10) & 0x3FF))); - SetUi16(dest + 2, (UInt16)(0xdc00 + ( c & 0x3FF))); - dest += 4; - } - else - { - SetUi16(dest, c); - dest += 2; - } - } -} - -#endif -*/ - -#endif +// Common/UTFConvert.h + +#ifndef ZIP7_INC_COMMON_UTF_CONVERT_H +#define ZIP7_INC_COMMON_UTF_CONVERT_H + +#include "MyBuffer.h" +#include "MyString.h" + +struct CUtf8Check +{ + // Byte MaxByte; // in original src stream + bool NonUtf; + bool ZeroChar; + bool SingleSurrogate; + bool Escape; + bool Truncated; + UInt32 MaxHighPoint; // only for points >= 0x80 + + CUtf8Check() { Clear(); } + + void Clear() + { + // MaxByte = 0; + NonUtf = false; + ZeroChar = false; + SingleSurrogate = false; + Escape = false; + Truncated = false; + MaxHighPoint = 0; + } + + void Update(const CUtf8Check &c) + { + if (c.NonUtf) NonUtf = true; + if (c.ZeroChar) ZeroChar = true; + if (c.SingleSurrogate) SingleSurrogate = true; + if (c.Escape) Escape = true; + if (c.Truncated) Truncated = true; + if (MaxHighPoint < c.MaxHighPoint) MaxHighPoint = c.MaxHighPoint; + } + + void PrintStatus(AString &s) const + { + s.Empty(); + + // s.Add_OptSpaced("MaxByte="); + // s.Add_UInt32(MaxByte); + + if (NonUtf) s.Add_OptSpaced("non-UTF8"); + if (ZeroChar) s.Add_OptSpaced("ZeroChar"); + if (SingleSurrogate) s.Add_OptSpaced("SingleSurrogate"); + if (Escape) s.Add_OptSpaced("Escape"); + if (Truncated) s.Add_OptSpaced("Truncated"); + + if (MaxHighPoint != 0) + { + s.Add_OptSpaced("MaxUnicode="); + s.Add_UInt32(MaxHighPoint); + } + } + + + bool IsOK(bool allowReduced = false) const + { + if (NonUtf || SingleSurrogate || ZeroChar) + return false; + if (MaxHighPoint >= 0x110000) + return false; + if (Truncated && !allowReduced) + return false; + return true; + } + + // it checks full buffer as specified in (size) and it doesn't stop on zero char + void Check_Buf(const char *src, size_t size) throw(); + + void Check_AString(const AString &s) throw() + { + Check_Buf(s.Ptr(), s.Len()); + } +}; + +/* +if (allowReduced == false) - all UTF-8 character sequences must be finished. +if (allowReduced == true) - it allows truncated last character-Utf8-sequence +*/ + +bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw(); +bool CheckUTF8_AString(const AString &s) throw(); + +#define Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR (1 << 0) +#define Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE (1 << 1) +#define Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT (1 << 2) + +/* +Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR + + if (flag is NOT set) + { + it processes SINGLE-SURROGATE-8 as valid Unicode point. + it converts SINGLE-SURROGATE-8 to SINGLE-SURROGATE-16 + Note: some sequencies of two SINGLE-SURROGATE-8 points + will generate correct SURROGATE-16-PAIR, and + that SURROGATE-16-PAIR later will be converted to correct + UTF8-SURROGATE-21 point. So we don't restore original + STR-8 sequence in that case. + } + + if (flag is set) + { + if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is defined) + it generates ESCAPE for SINGLE-SURROGATE-8, + if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is not defined) + it generates U+fffd for SINGLE-SURROGATE-8, + } + + +Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE + + if (flag is NOT set) + it generates (U+fffd) code for non-UTF-8 (invalid) characters + + if (flag is set) + { + It generates (ESCAPE) codes for NON-UTF-8 (invalid) characters. + And later we can restore original UTF-8-RAW characters from (ESCAPE-16-21) codes. + } + +Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT + + if (flag is NOT set) + { + it process ESCAPE-8 points as another Unicode points. + In Linux: ESCAPE-16 will mean two different ESCAPE-8 seqences, + so we need HIGH-ESCAPE-PLANE-21 to restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW + } + + if (flag is set) + { + it generates ESCAPE-16-21 for ESCAPE-8 points + so we can restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW without HIGH-ESCAPE-PLANE-21. + } + + +Main USE CASES with UTF-8 <-> UTF-16 conversions: + + WIN32: UTF-16-RAW -> UTF-8 (Archive) -> UTF-16-RAW + { + set Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE + Do NOT set Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR + Do NOT set Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT + + So we restore original SINGLE-SURROGATE-16 from single SINGLE-SURROGATE-8. + } + + Linux: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW + { + we want restore original UTF-8-RAW sequence later from that ESCAPE-16. + Set the flags: + Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR + Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE + Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT + } + + MacOS: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW + { + we want to restore correct UTF-8 without any BMP processing: + Set the flags: + Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR + Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE + } + +*/ + +// zero char is not allowed in (src) buf +bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags = 0); + +bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags = 0); +bool ConvertUTF8ToUnicode(const AString &src, UString &dest); + +#define Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR (1 << 8) +#define Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE (1 << 9) +// #define Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE (1 << 10) + +/* +Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR + + if (flag is NOT set) + { + we extract SINGLE-SURROGATE as normal UTF-8 + + In Windows : for UTF-16-RAW <-> UTF-8 (archive) <-> UTF-16-RAW in . + + In Linux : + use-case-1: UTF-8 -> UTF-16 -> UTF-8 doesn't generate UTF-16 SINGLE-SURROGATE, + if (Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) is used. + use-case 2: UTF-16-7z (with SINGLE-SURROGATE from Windows) -> UTF-8 (Linux) + will generate SINGLE-SURROGATE-UTF-8 here. + } + + if (flag is set) + { + we generate UTF_REPLACEMENT_CHAR (0xfffd) for SINGLE_SURROGATE + it can be used for compatibility mode with WIN32 UTF function + or if we want UTF-8 stream without any errors + } + + +Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE + + if (flag is NOT set) it doesn't extract raw 8-bit symbol from Escape-Plane-16 + if (flag is set) it extracts raw 8-bit symbol from Escape-Plane-16 + + in Linux we need some way to extract NON-UTF8 RAW 8-bits from BMP (UTF-16 7z archive): + if (we use High-Escape-Plane), we can transfer BMP escapes to High-Escape-Plane. + if (we don't use High-Escape-Plane), we must use Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE. + + +Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE + // that flag affects the code only if (wchar_t is 32-bit) + // that mode with high-escape can be disabled now in UTFConvert.cpp + if (flag is NOT set) + it doesn't extract raw 8-bit symbol from High-Escape-Plane + if (flag is set) + it extracts raw 8-bit symbol from High-Escape-Plane + +Main use cases: + +WIN32 : UTF-16-RAW -> UTF-8 (archive) -> UTF-16-RAW + { + Do NOT set Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE. + Do NOT set Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR. + So we restore original UTF-16-RAW. + } + +Linix : UTF-8 with Escapes -> UTF-16 (7z archive) -> UTF-8 with Escapes + set Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE to extract non-UTF from 7z archive + set Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE for intermediate UTF-16. + Note: high esacape mode can be ignored now in UTFConvert.cpp + +macOS: + the system doesn't support incorrect UTF-8 in file names. + set Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR +*/ + +extern unsigned g_Unicode_To_UTF8_Flags; + +void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags = 0); +void ConvertUnicodeToUTF8(const UString &src, AString &dest); + +void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest); + +/* +#ifndef _WIN32 +void Convert_UTF16_To_UTF32(const UString &src, UString &dest); +void Convert_UTF32_To_UTF16(const UString &src, UString &dest); +bool UTF32_IsThere_BigPoint(const UString &src); +bool Unicode_IsThere_BmpEscape(const UString &src); +#endif + +bool Unicode_IsThere_Utf16SurrogateError(const UString &src); +*/ + +#ifdef Z7_WCHART_IS_16BIT +#define Convert_UnicodeEsc16_To_UnicodeEscHigh(s) +#else +void Convert_UnicodeEsc16_To_UnicodeEscHigh(UString &s); +#endif + +/* +// #include "../../C/CpuArch.h" + +// ---------- Utf16 Little endian functions ---------- + +// We store 16-bit surrogates even in 32-bit WCHARs in Linux. +// So now we don't use the following code: + +#if WCHAR_MAX > 0xffff + +// void *p : pointer to src bytes stream +// size_t len : num Utf16 characters : it can include or not include NULL character + +inline size_t Utf16LE__Get_Num_WCHARs(const void *p, size_t len) +{ + #if WCHAR_MAX > 0xffff + size_t num_wchars = 0; + for (size_t i = 0; i < len; i++) + { + wchar_t c = GetUi16(p); + p = (const void *)((const Byte *)p + 2); + if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) + { + wchar_t c2 = GetUi16(p); + if (c2 >= 0xdc00 && c2 < 0xe000) + { + c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); + p = (const void *)((const Byte *)p + 2); + i++; + } + } + num_wchars++; + } + return num_wchars; + #else + UNUSED_VAR(p) + return len; + #endif +} + +// #include + +inline wchar_t *Utf16LE__To_WCHARs_Sep(const void *p, size_t len, wchar_t *dest) +{ + for (size_t i = 0; i < len; i++) + { + wchar_t c = GetUi16(p); + p = (const void *)((const Byte *)p + 2); + + #if WCHAR_PATH_SEPARATOR != L'/' + if (c == L'/') + c = WCHAR_PATH_SEPARATOR; + #endif + + #if WCHAR_MAX > 0xffff + + if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) + { + wchar_t c2 = GetUi16(p); + if (c2 >= 0xdc00 && c2 < 0xe000) + { + // printf("\nSurragate : %4x %4x -> ", (int)c, (int)c2); + c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); + p = (const void *)((const Byte *)p + 2); + i++; + // printf("%4x\n", (int)c); + } + } + + #endif + + *dest++ = c; + } + return dest; +} + + +inline size_t Get_Num_Utf16_chars_from_wchar_string(const wchar_t *p) +{ + size_t num = 0; + for (;;) + { + wchar_t c = *p++; + if (c == 0) + return num; + num += ((c >= 0x10000 && c < 0x110000) ? 2 : 1); + } + return num; +} + +inline Byte *wchars_to_Utf16LE(const wchar_t *p, Byte *dest) +{ + for (;;) + { + wchar_t c = *p++; + if (c == 0) + return dest; + if (c >= 0x10000 && c < 0x110000) + { + SetUi16(dest , (UInt16)(0xd800 + ((c >> 10) & 0x3FF))); + SetUi16(dest + 2, (UInt16)(0xdc00 + ( c & 0x3FF))); + dest += 4; + } + else + { + SetUi16(dest, c); + dest += 2; + } + } +} + +#endif +*/ + +#endif diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp index dc757c101..798cbd957 100644 --- a/CPP/Common/Wildcard.cpp +++ b/CPP/Common/Wildcard.cpp @@ -1,788 +1,788 @@ -// Common/Wildcard.cpp - -#include "StdAfx.h" - -#include "Wildcard.h" - -extern -bool g_CaseSensitive; -bool g_CaseSensitive = - #ifdef _WIN32 - false; - #elif defined (__APPLE__) - #ifdef TARGET_OS_IPHONE - true; - #else - false; - #endif - #else - true; - #endif - - -bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) -{ - if (g_CaseSensitive) - return IsString1PrefixedByString2(s1, s2); - return IsString1PrefixedByString2_NoCase(s1, s2); -} - -// #include - -/* -static int MyStringCompare_PathLinux(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; - if (c1 != c2) - { - if (c1 == 0) return -1; - if (c2 == 0) return 1; - if (c1 == '/') c1 = 0; - if (c2 == '/') c2 = 0; - if (c1 < c2) return -1; - if (c1 > c2) return 1; - continue; - } - if (c1 == 0) return 0; - } -} -*/ - -static int MyStringCompare_Path(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; - if (c1 != c2) - { - if (c1 == 0) return -1; - if (c2 == 0) return 1; - if (IS_PATH_SEPAR(c1)) c1 = 0; - if (IS_PATH_SEPAR(c2)) c2 = 0; - if (c1 < c2) return -1; - if (c1 > c2) return 1; - continue; - } - if (c1 == 0) return 0; - } -} - -static int MyStringCompareNoCase_Path(const wchar_t *s1, const wchar_t *s2) throw() -{ - for (;;) - { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; - if (c1 != c2) - { - if (c1 == 0) return -1; - if (c2 == 0) return 1; - if (IS_PATH_SEPAR(c1)) c1 = 0; - if (IS_PATH_SEPAR(c2)) c2 = 0; - c1 = MyCharUpper(c1); - c2 = MyCharUpper(c2); - if (c1 < c2) return -1; - if (c1 > c2) return 1; - continue; - } - if (c1 == 0) return 0; - } -} - -int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW -{ - /* - printf("\nCompareFileNames"); - printf("\n S1: %ls", s1); - printf("\n S2: %ls", s2); - printf("\n"); - */ - // 21.07 : we parse PATH_SEPARATOR so: 0 < PATH_SEPARATOR < 1 - if (g_CaseSensitive) - return MyStringCompare_Path(s1, s2); - return MyStringCompareNoCase_Path(s1, s2); -} - -#ifndef USE_UNICODE_FSTRING -int CompareFileNames(const char *s1, const char *s2) -{ - const UString u1 = fs2us(s1); - const UString u2 = fs2us(s2); - return CompareFileNames(u1, u2); -} -#endif - -// ----------------------------------------- -// this function compares name with mask -// ? - any char -// * - any char or empty - -static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name) -{ - for (;;) - { - const wchar_t m = *mask; - const wchar_t c = *name; - if (m == 0) - return (c == 0); - if (m == '*') - { - if (EnhancedMaskTest(mask + 1, name)) - return true; - if (c == 0) - return false; - } - else - { - if (m == '?') - { - if (c == 0) - return false; - } - else if (m != c) - if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c)) - return false; - mask++; - } - name++; - } -} - -// -------------------------------------------------- -// Splits path to strings - -void SplitPathToParts(const UString &path, UStringVector &pathParts) -{ - pathParts.Clear(); - unsigned len = path.Len(); - if (len == 0) - return; - UString name; - unsigned prev = 0; - for (unsigned i = 0; i < len; i++) - if (IsPathSepar(path[i])) - { - name.SetFrom(path.Ptr(prev), i - prev); - pathParts.Add(name); - prev = i + 1; - } - name.SetFrom(path.Ptr(prev), len - prev); - pathParts.Add(name); -} - -void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name) -{ - const wchar_t *start = path; - const wchar_t *p = start + path.Len(); - for (; p != start; p--) - if (IsPathSepar(*(p - 1))) - break; - dirPrefix.SetFrom(path, (unsigned)(p - start)); - name = p; -} - -void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name) -{ - const wchar_t *start = path; - const wchar_t *p = start + path.Len(); - if (p != start) - { - if (IsPathSepar(*(p - 1))) - p--; - for (; p != start; p--) - if (IsPathSepar(*(p - 1))) - break; - } - dirPrefix.SetFrom(path, (unsigned)(p - start)); - name = p; -} - -/* -UString ExtractDirPrefixFromPath(const UString &path) -{ - return path.Left(path.ReverseFind_PathSepar() + 1)); -} -*/ - -UString ExtractFileNameFromPath(const UString &path) -{ - return UString(path.Ptr((unsigned)(path.ReverseFind_PathSepar() + 1))); -} - - -bool DoesWildcardMatchName(const UString &mask, const UString &name) -{ - return EnhancedMaskTest(mask, name); -} - -bool DoesNameContainWildcard(const UString &path) -{ - for (unsigned i = 0; i < path.Len(); i++) - { - wchar_t c = path[i]; - if (c == '*' || c == '?') - return true; - } - return false; -} - - -// ----------------------------------------------------------' -// NWildcard - -namespace NWildcard { - -/* - -M = MaskParts.Size(); -N = TestNameParts.Size(); - - File Dir -ForFile rec M<=N [N-M, N) - -!ForDir nonrec M=N [0, M) - - -ForDir rec M &items = include ? IncludeItems : ExcludeItems; - items.Add(item); -} - -void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex) -{ - if (item.PathParts.Size() <= 1) - { - if (item.PathParts.Size() != 0 && item.WildcardMatching) - { - if (!DoesNameContainWildcard(item.PathParts.Front())) - item.WildcardMatching = false; - } - AddItemSimple(include, item); - return; - } - - const UString &front = item.PathParts.Front(); - - // WIN32 doesn't support wildcards in file names - if (item.WildcardMatching - && ignoreWildcardIndex != 0 - && DoesNameContainWildcard(front)) - { - AddItemSimple(include, item); - return; - } - CCensorNode &subNode = Find_SubNode_Or_Add_New(front); - item.PathParts.Delete(0); - subNode.AddItem(include, item, ignoreWildcardIndex - 1); -} - -/* -void CCensorNode::AddItem(bool include, const UString &path, const CCensorPathProps &props) -{ - CItem item; - SplitPathToParts(path, item.PathParts); - item.Recursive = props.Recursive; - item.ForFile = props.ForFile; - item.ForDir = props.ForDir; - item.WildcardMatching = props.WildcardMatching; - AddItem(include, item); -} -*/ - -bool CCensorNode::NeedCheckSubDirs() const -{ - FOR_VECTOR (i, IncludeItems) - { - const CItem &item = IncludeItems[i]; - if (item.Recursive || item.PathParts.Size() > 1) - return true; - } - return false; -} - -bool CCensorNode::AreThereIncludeItems() const -{ - if (IncludeItems.Size() > 0) - return true; - FOR_VECTOR (i, SubNodes) - if (SubNodes[i].AreThereIncludeItems()) - return true; - return false; -} - -bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const -{ - const CObjectVector &items = include ? IncludeItems : ExcludeItems; - FOR_VECTOR (i, items) - if (items[i].CheckPath(pathParts, isFile)) - return true; - return false; -} - -bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const -{ - if (CheckPathCurrent(false, pathParts, isFile)) - { - include = false; - return true; - } - if (pathParts.Size() > 1) - { - int index = FindSubNode(pathParts.Front()); - if (index >= 0) - { - UStringVector pathParts2 = pathParts; - pathParts2.Delete(0); - if (SubNodes[(unsigned)index].CheckPathVect(pathParts2, isFile, include)) - return true; - } - } - bool finded = CheckPathCurrent(true, pathParts, isFile); - include = finded; // if (!finded), then (true) is allowed also - return finded; -} - -/* -bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const -{ - UStringVector pathParts; - SplitPathToParts(path, pathParts); - if (CheckPathVect(pathParts, isFile, include)) - { - if (!include || !isAltStream) - return true; - } - if (isAltStream && !pathParts.IsEmpty()) - { - UString &back = pathParts.Back(); - int pos = back.Find(L':'); - if (pos > 0) - { - back.DeleteFrom(pos); - return CheckPathVect(pathParts, isFile, include); - } - } - return false; -} - -bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const -{ - bool include; - if (CheckPath2(isAltStream, path, isFile, include)) - return include; - return false; -} -*/ - -bool CCensorNode::CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const -{ - if (CheckPathCurrent(include, pathParts, isFile)) - return true; - if (!Parent) - return false; - pathParts.Insert(0, Name); - return Parent->CheckPathToRoot_Change(include, pathParts, isFile); -} - -bool CCensorNode::CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const -{ - if (CheckPathCurrent(include, pathParts, isFile)) - return true; - if (!Parent) - return false; - UStringVector pathParts2; - pathParts2.Add(Name); - pathParts2 += pathParts; - return Parent->CheckPathToRoot_Change(include, pathParts2, isFile); -} - -/* -bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const -{ - UStringVector pathParts; - SplitPathToParts(path, pathParts); - return CheckPathToRoot(include, pathParts, isFile); -} -*/ - -void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) -{ - ExcludeItems += fromNodes.ExcludeItems; - FOR_VECTOR (i, fromNodes.SubNodes) - { - const CCensorNode &node = fromNodes.SubNodes[i]; - Find_SubNode_Or_Add_New(node.Name).ExtendExclude(node); - } -} - -int CCensor::FindPairForPrefix(const UString &prefix) const -{ - FOR_VECTOR (i, Pairs) - if (CompareFileNames(Pairs[i].Prefix, prefix) == 0) - return (int)i; - return -1; -} - -#ifdef _WIN32 - -bool IsDriveColonName(const wchar_t *s) -{ - unsigned c = s[0]; - c |= 0x20; - c -= 'a'; - return c <= (unsigned)('z' - 'a') && s[1] == ':' && s[2] == 0; -} - -unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts) -{ - if (pathParts.IsEmpty()) - return 0; - - unsigned testIndex = 0; - if (pathParts[0].IsEmpty()) - { - if (pathParts.Size() < 4 - || !pathParts[1].IsEmpty() - || pathParts[2] != L"?") - return 0; - testIndex = 3; - } - if (NWildcard::IsDriveColonName(pathParts[testIndex])) - return testIndex + 1; - return 0; -} - -#endif - -static unsigned GetNumPrefixParts(const UStringVector &pathParts) -{ - if (pathParts.IsEmpty()) - return 0; - - /* empty last part could be removed already from (pathParts), - if there was tail path separator (slash) in original full path string. */ - - #ifdef _WIN32 - - if (IsDriveColonName(pathParts[0])) - return 1; - if (!pathParts[0].IsEmpty()) - return 0; - - if (pathParts.Size() == 1) - return 1; - if (!pathParts[1].IsEmpty()) - return 1; - if (pathParts.Size() == 2) - return 2; - if (pathParts[2] == L".") - return 3; - - unsigned networkParts = 2; - if (pathParts[2] == L"?") - { - if (pathParts.Size() == 3) - return 3; - if (IsDriveColonName(pathParts[3])) - return 4; - if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC")) - return 3; - networkParts = 4; - } - - networkParts += - // 2; // server/share - 1; // server - if (pathParts.Size() <= networkParts) - return pathParts.Size(); - return networkParts; - - #else - - return pathParts[0].IsEmpty() ? 1 : 0; - - #endif -} - -void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, - const CCensorPathProps &props) -{ - if (path.IsEmpty()) - throw "Empty file path"; - - UStringVector pathParts; - SplitPathToParts(path, pathParts); - - CCensorPathProps props2 = props; - - bool forFile = true; - bool forDir = true; - const UString &back = pathParts.Back(); - if (back.IsEmpty()) - { - // we have tail path separator. So it's directory. - // we delete tail path separator here even for "\" and "c:\" - forFile = false; - pathParts.DeleteBack(); - } - else - { - if (props.MarkMode == kMark_StrictFile - || (props.MarkMode == kMark_StrictFile_IfWildcard - && DoesNameContainWildcard(back))) - forDir = false; - } - - - UString prefix; - - int ignoreWildcardIndex = -1; - - // #ifdef _WIN32 - // we ignore "?" wildcard in "\\?\" prefix. - if (pathParts.Size() >= 3 - && pathParts[0].IsEmpty() - && pathParts[1].IsEmpty() - && pathParts[2] == L"?") - ignoreWildcardIndex = 2; - // #endif - - if (pathMode != k_AbsPath) - { - // detection of the number of Skip Parts for prefix - ignoreWildcardIndex = -1; - - const unsigned numPrefixParts = GetNumPrefixParts(pathParts); - unsigned numSkipParts = numPrefixParts; - - if (pathMode != k_FullPath) - { - // if absolute path, then all parts before last part will be in prefix - if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts) - numSkipParts = pathParts.Size() - 1; - } - { - int dotsIndex = -1; - for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) - { - const UString &part = pathParts[i]; - if (part == L".." || part == L".") - dotsIndex = (int)i; - } - - if (dotsIndex >= 0) - { - if (dotsIndex == (int)pathParts.Size() - 1) - numSkipParts = pathParts.Size(); - else - numSkipParts = pathParts.Size() - 1; - } - } - - // we split (pathParts) to (prefix) and (pathParts). - for (unsigned i = 0; i < numSkipParts; i++) - { - { - const UString &front = pathParts.Front(); - // WIN32 doesn't support wildcards in file names - if (props.WildcardMatching) - if (i >= numPrefixParts && DoesNameContainWildcard(front)) - break; - prefix += front; - prefix.Add_PathSepar(); - } - pathParts.Delete(0); - } - } - - int index = FindPairForPrefix(prefix); - if (index < 0) - { - index = (int)Pairs.Size(); - Pairs.AddNew().Prefix = prefix; - } - - if (pathMode != k_AbsPath) - { - if (pathParts.IsEmpty() || (pathParts.Size() == 1 && pathParts[0].IsEmpty())) - { - // we create universal item, if we skip all parts as prefix (like \ or L:\ ) - pathParts.Clear(); - pathParts.Add(UString("*")); - forFile = true; - forDir = true; - props2.WildcardMatching = true; - props2.Recursive = false; - } - } - - /* - // not possible now - if (!forDir && !forFile) - { - UString s ("file path was blocked for files and directories: "); - s += path; - throw s; - // return; // for debug : ignore item (don't create Item) - } - */ - - CItem item; - item.PathParts = pathParts; - item.ForDir = forDir; - item.ForFile = forFile; - item.Recursive = props2.Recursive; - item.WildcardMatching = props2.WildcardMatching; - Pairs[(unsigned)index].Head.AddItem(include, item, ignoreWildcardIndex); -} - -/* -bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const -{ - bool finded = false; - FOR_VECTOR (i, Pairs) - { - bool include; - if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include)) - { - if (!include) - return false; - finded = true; - } - } - return finded; -} -*/ - -void CCensor::ExtendExclude() -{ - unsigned i; - for (i = 0; i < Pairs.Size(); i++) - if (Pairs[i].Prefix.IsEmpty()) - break; - if (i == Pairs.Size()) - return; - unsigned index = i; - for (i = 0; i < Pairs.Size(); i++) - if (index != i) - Pairs[i].Head.ExtendExclude(Pairs[index].Head); -} - -void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) -{ - FOR_VECTOR(i, CensorPaths) - { - const CCensorPath &cp = CensorPaths[i]; - AddItem(censorPathMode, cp.Include, cp.Path, cp.Props); - } - CensorPaths.Clear(); -} - -void CCensor::AddPreItem(bool include, const UString &path, const CCensorPathProps &props) -{ - CCensorPath &cp = CensorPaths.AddNew(); - cp.Path = path; - cp.Include = include; - cp.Props = props; -} - -} +// Common/Wildcard.cpp + +#include "StdAfx.h" + +#include "Wildcard.h" + +extern +bool g_CaseSensitive; +bool g_CaseSensitive = + #ifdef _WIN32 + false; + #elif defined (__APPLE__) + #ifdef TARGET_OS_IPHONE + true; + #else + false; + #endif + #else + true; + #endif + + +bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) +{ + if (g_CaseSensitive) + return IsString1PrefixedByString2(s1, s2); + return IsString1PrefixedByString2_NoCase(s1, s2); +} + +// #include + +/* +static int MyStringCompare_PathLinux(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + if (c1 == 0) return -1; + if (c2 == 0) return 1; + if (c1 == '/') c1 = 0; + if (c2 == '/') c2 = 0; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + continue; + } + if (c1 == 0) return 0; + } +} +*/ + +static int MyStringCompare_Path(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + if (c1 == 0) return -1; + if (c2 == 0) return 1; + if (IS_PATH_SEPAR(c1)) c1 = 0; + if (IS_PATH_SEPAR(c2)) c2 = 0; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + continue; + } + if (c1 == 0) return 0; + } +} + +static int MyStringCompareNoCase_Path(const wchar_t *s1, const wchar_t *s2) throw() +{ + for (;;) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + if (c1 == 0) return -1; + if (c2 == 0) return 1; + if (IS_PATH_SEPAR(c1)) c1 = 0; + if (IS_PATH_SEPAR(c2)) c2 = 0; + c1 = MyCharUpper(c1); + c2 = MyCharUpper(c2); + if (c1 < c2) return -1; + if (c1 > c2) return 1; + continue; + } + if (c1 == 0) return 0; + } +} + +int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW +{ + /* + printf("\nCompareFileNames"); + printf("\n S1: %ls", s1); + printf("\n S2: %ls", s2); + printf("\n"); + */ + // 21.07 : we parse PATH_SEPARATOR so: 0 < PATH_SEPARATOR < 1 + if (g_CaseSensitive) + return MyStringCompare_Path(s1, s2); + return MyStringCompareNoCase_Path(s1, s2); +} + +#ifndef USE_UNICODE_FSTRING +int CompareFileNames(const char *s1, const char *s2) +{ + const UString u1 = fs2us(s1); + const UString u2 = fs2us(s2); + return CompareFileNames(u1, u2); +} +#endif + +// ----------------------------------------- +// this function compares name with mask +// ? - any char +// * - any char or empty + +static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name) +{ + for (;;) + { + const wchar_t m = *mask; + const wchar_t c = *name; + if (m == 0) + return (c == 0); + if (m == '*') + { + if (EnhancedMaskTest(mask + 1, name)) + return true; + if (c == 0) + return false; + } + else + { + if (m == '?') + { + if (c == 0) + return false; + } + else if (m != c) + if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c)) + return false; + mask++; + } + name++; + } +} + +// -------------------------------------------------- +// Splits path to strings + +void SplitPathToParts(const UString &path, UStringVector &pathParts) +{ + pathParts.Clear(); + unsigned len = path.Len(); + if (len == 0) + return; + UString name; + unsigned prev = 0; + for (unsigned i = 0; i < len; i++) + if (IsPathSepar(path[i])) + { + name.SetFrom(path.Ptr(prev), i - prev); + pathParts.Add(name); + prev = i + 1; + } + name.SetFrom(path.Ptr(prev), len - prev); + pathParts.Add(name); +} + +void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name) +{ + const wchar_t *start = path; + const wchar_t *p = start + path.Len(); + for (; p != start; p--) + if (IsPathSepar(*(p - 1))) + break; + dirPrefix.SetFrom(path, (unsigned)(p - start)); + name = p; +} + +void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name) +{ + const wchar_t *start = path; + const wchar_t *p = start + path.Len(); + if (p != start) + { + if (IsPathSepar(*(p - 1))) + p--; + for (; p != start; p--) + if (IsPathSepar(*(p - 1))) + break; + } + dirPrefix.SetFrom(path, (unsigned)(p - start)); + name = p; +} + +/* +UString ExtractDirPrefixFromPath(const UString &path) +{ + return path.Left(path.ReverseFind_PathSepar() + 1)); +} +*/ + +UString ExtractFileNameFromPath(const UString &path) +{ + return UString(path.Ptr((unsigned)(path.ReverseFind_PathSepar() + 1))); +} + + +bool DoesWildcardMatchName(const UString &mask, const UString &name) +{ + return EnhancedMaskTest(mask, name); +} + +bool DoesNameContainWildcard(const UString &path) +{ + for (unsigned i = 0; i < path.Len(); i++) + { + wchar_t c = path[i]; + if (c == '*' || c == '?') + return true; + } + return false; +} + + +// ----------------------------------------------------------' +// NWildcard + +namespace NWildcard { + +/* + +M = MaskParts.Size(); +N = TestNameParts.Size(); + + File Dir +ForFile rec M<=N [N-M, N) - +!ForDir nonrec M=N [0, M) - + +ForDir rec M &items = include ? IncludeItems : ExcludeItems; + items.Add(item); +} + +void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex) +{ + if (item.PathParts.Size() <= 1) + { + if (item.PathParts.Size() != 0 && item.WildcardMatching) + { + if (!DoesNameContainWildcard(item.PathParts.Front())) + item.WildcardMatching = false; + } + AddItemSimple(include, item); + return; + } + + const UString &front = item.PathParts.Front(); + + // WIN32 doesn't support wildcards in file names + if (item.WildcardMatching + && ignoreWildcardIndex != 0 + && DoesNameContainWildcard(front)) + { + AddItemSimple(include, item); + return; + } + CCensorNode &subNode = Find_SubNode_Or_Add_New(front); + item.PathParts.Delete(0); + subNode.AddItem(include, item, ignoreWildcardIndex - 1); +} + +/* +void CCensorNode::AddItem(bool include, const UString &path, const CCensorPathProps &props) +{ + CItem item; + SplitPathToParts(path, item.PathParts); + item.Recursive = props.Recursive; + item.ForFile = props.ForFile; + item.ForDir = props.ForDir; + item.WildcardMatching = props.WildcardMatching; + AddItem(include, item); +} +*/ + +bool CCensorNode::NeedCheckSubDirs() const +{ + FOR_VECTOR (i, IncludeItems) + { + const CItem &item = IncludeItems[i]; + if (item.Recursive || item.PathParts.Size() > 1) + return true; + } + return false; +} + +bool CCensorNode::AreThereIncludeItems() const +{ + if (IncludeItems.Size() > 0) + return true; + FOR_VECTOR (i, SubNodes) + if (SubNodes[i].AreThereIncludeItems()) + return true; + return false; +} + +bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const +{ + const CObjectVector &items = include ? IncludeItems : ExcludeItems; + FOR_VECTOR (i, items) + if (items[i].CheckPath(pathParts, isFile)) + return true; + return false; +} + +bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const +{ + if (CheckPathCurrent(false, pathParts, isFile)) + { + include = false; + return true; + } + if (pathParts.Size() > 1) + { + int index = FindSubNode(pathParts.Front()); + if (index >= 0) + { + UStringVector pathParts2 = pathParts; + pathParts2.Delete(0); + if (SubNodes[(unsigned)index].CheckPathVect(pathParts2, isFile, include)) + return true; + } + } + bool finded = CheckPathCurrent(true, pathParts, isFile); + include = finded; // if (!finded), then (true) is allowed also + return finded; +} + +/* +bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const +{ + UStringVector pathParts; + SplitPathToParts(path, pathParts); + if (CheckPathVect(pathParts, isFile, include)) + { + if (!include || !isAltStream) + return true; + } + if (isAltStream && !pathParts.IsEmpty()) + { + UString &back = pathParts.Back(); + int pos = back.Find(L':'); + if (pos > 0) + { + back.DeleteFrom(pos); + return CheckPathVect(pathParts, isFile, include); + } + } + return false; +} + +bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const +{ + bool include; + if (CheckPath2(isAltStream, path, isFile, include)) + return include; + return false; +} +*/ + +bool CCensorNode::CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const +{ + if (CheckPathCurrent(include, pathParts, isFile)) + return true; + if (!Parent) + return false; + pathParts.Insert(0, Name); + return Parent->CheckPathToRoot_Change(include, pathParts, isFile); +} + +bool CCensorNode::CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const +{ + if (CheckPathCurrent(include, pathParts, isFile)) + return true; + if (!Parent) + return false; + UStringVector pathParts2; + pathParts2.Add(Name); + pathParts2 += pathParts; + return Parent->CheckPathToRoot_Change(include, pathParts2, isFile); +} + +/* +bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const +{ + UStringVector pathParts; + SplitPathToParts(path, pathParts); + return CheckPathToRoot(include, pathParts, isFile); +} +*/ + +void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) +{ + ExcludeItems += fromNodes.ExcludeItems; + FOR_VECTOR (i, fromNodes.SubNodes) + { + const CCensorNode &node = fromNodes.SubNodes[i]; + Find_SubNode_Or_Add_New(node.Name).ExtendExclude(node); + } +} + +int CCensor::FindPairForPrefix(const UString &prefix) const +{ + FOR_VECTOR (i, Pairs) + if (CompareFileNames(Pairs[i].Prefix, prefix) == 0) + return (int)i; + return -1; +} + +#ifdef _WIN32 + +bool IsDriveColonName(const wchar_t *s) +{ + unsigned c = s[0]; + c |= 0x20; + c -= 'a'; + return c <= (unsigned)('z' - 'a') && s[1] == ':' && s[2] == 0; +} + +unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts) +{ + if (pathParts.IsEmpty()) + return 0; + + unsigned testIndex = 0; + if (pathParts[0].IsEmpty()) + { + if (pathParts.Size() < 4 + || !pathParts[1].IsEmpty() + || pathParts[2] != L"?") + return 0; + testIndex = 3; + } + if (NWildcard::IsDriveColonName(pathParts[testIndex])) + return testIndex + 1; + return 0; +} + +#endif + +static unsigned GetNumPrefixParts(const UStringVector &pathParts) +{ + if (pathParts.IsEmpty()) + return 0; + + /* empty last part could be removed already from (pathParts), + if there was tail path separator (slash) in original full path string. */ + + #ifdef _WIN32 + + if (IsDriveColonName(pathParts[0])) + return 1; + if (!pathParts[0].IsEmpty()) + return 0; + + if (pathParts.Size() == 1) + return 1; + if (!pathParts[1].IsEmpty()) + return 1; + if (pathParts.Size() == 2) + return 2; + if (pathParts[2] == L".") + return 3; + + unsigned networkParts = 2; + if (pathParts[2] == L"?") + { + if (pathParts.Size() == 3) + return 3; + if (IsDriveColonName(pathParts[3])) + return 4; + if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC")) + return 3; + networkParts = 4; + } + + networkParts += + // 2; // server/share + 1; // server + if (pathParts.Size() <= networkParts) + return pathParts.Size(); + return networkParts; + + #else + + return pathParts[0].IsEmpty() ? 1 : 0; + + #endif +} + +void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, + const CCensorPathProps &props) +{ + if (path.IsEmpty()) + throw "Empty file path"; + + UStringVector pathParts; + SplitPathToParts(path, pathParts); + + CCensorPathProps props2 = props; + + bool forFile = true; + bool forDir = true; + const UString &back = pathParts.Back(); + if (back.IsEmpty()) + { + // we have tail path separator. So it's directory. + // we delete tail path separator here even for "\" and "c:\" + forFile = false; + pathParts.DeleteBack(); + } + else + { + if (props.MarkMode == kMark_StrictFile + || (props.MarkMode == kMark_StrictFile_IfWildcard + && DoesNameContainWildcard(back))) + forDir = false; + } + + + UString prefix; + + int ignoreWildcardIndex = -1; + + // #ifdef _WIN32 + // we ignore "?" wildcard in "\\?\" prefix. + if (pathParts.Size() >= 3 + && pathParts[0].IsEmpty() + && pathParts[1].IsEmpty() + && pathParts[2] == L"?") + ignoreWildcardIndex = 2; + // #endif + + if (pathMode != k_AbsPath) + { + // detection of the number of Skip Parts for prefix + ignoreWildcardIndex = -1; + + const unsigned numPrefixParts = GetNumPrefixParts(pathParts); + unsigned numSkipParts = numPrefixParts; + + if (pathMode != k_FullPath) + { + // if absolute path, then all parts before last part will be in prefix + if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts) + numSkipParts = pathParts.Size() - 1; + } + { + int dotsIndex = -1; + for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) + { + const UString &part = pathParts[i]; + if (part == L".." || part == L".") + dotsIndex = (int)i; + } + + if (dotsIndex >= 0) + { + if (dotsIndex == (int)pathParts.Size() - 1) + numSkipParts = pathParts.Size(); + else + numSkipParts = pathParts.Size() - 1; + } + } + + // we split (pathParts) to (prefix) and (pathParts). + for (unsigned i = 0; i < numSkipParts; i++) + { + { + const UString &front = pathParts.Front(); + // WIN32 doesn't support wildcards in file names + if (props.WildcardMatching) + if (i >= numPrefixParts && DoesNameContainWildcard(front)) + break; + prefix += front; + prefix.Add_PathSepar(); + } + pathParts.Delete(0); + } + } + + int index = FindPairForPrefix(prefix); + if (index < 0) + { + index = (int)Pairs.Size(); + Pairs.AddNew().Prefix = prefix; + } + + if (pathMode != k_AbsPath) + { + if (pathParts.IsEmpty() || (pathParts.Size() == 1 && pathParts[0].IsEmpty())) + { + // we create universal item, if we skip all parts as prefix (like \ or L:\ ) + pathParts.Clear(); + pathParts.Add(UString("*")); + forFile = true; + forDir = true; + props2.WildcardMatching = true; + props2.Recursive = false; + } + } + + /* + // not possible now + if (!forDir && !forFile) + { + UString s ("file path was blocked for files and directories: "); + s += path; + throw s; + // return; // for debug : ignore item (don't create Item) + } + */ + + CItem item; + item.PathParts = pathParts; + item.ForDir = forDir; + item.ForFile = forFile; + item.Recursive = props2.Recursive; + item.WildcardMatching = props2.WildcardMatching; + Pairs[(unsigned)index].Head.AddItem(include, item, ignoreWildcardIndex); +} + +/* +bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const +{ + bool finded = false; + FOR_VECTOR (i, Pairs) + { + bool include; + if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include)) + { + if (!include) + return false; + finded = true; + } + } + return finded; +} +*/ + +void CCensor::ExtendExclude() +{ + unsigned i; + for (i = 0; i < Pairs.Size(); i++) + if (Pairs[i].Prefix.IsEmpty()) + break; + if (i == Pairs.Size()) + return; + unsigned index = i; + for (i = 0; i < Pairs.Size(); i++) + if (index != i) + Pairs[i].Head.ExtendExclude(Pairs[index].Head); +} + +void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) +{ + FOR_VECTOR(i, CensorPaths) + { + const CCensorPath &cp = CensorPaths[i]; + AddItem(censorPathMode, cp.Include, cp.Path, cp.Props); + } + CensorPaths.Clear(); +} + +void CCensor::AddPreItem(bool include, const UString &path, const CCensorPathProps &props) +{ + CCensorPath &cp = CensorPaths.AddNew(); + cp.Path = path; + cp.Include = include; + cp.Props = props; +} + +} diff --git a/CPP/Common/Wildcard.h b/CPP/Common/Wildcard.h index e175d17bd..4f81da923 100644 --- a/CPP/Common/Wildcard.h +++ b/CPP/Common/Wildcard.h @@ -1,231 +1,231 @@ -// Common/Wildcard.h - -#ifndef ZIP7_INC_COMMON_WILDCARD_H -#define ZIP7_INC_COMMON_WILDCARD_H - -#include "MyString.h" - -int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW; -#ifndef USE_UNICODE_FSTRING - int CompareFileNames(const char *s1, const char *s2); -#endif - -bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2); - -void SplitPathToParts(const UString &path, UStringVector &pathParts); -void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name); -void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path) - -UString ExtractDirPrefixFromPath(const UString &path); -UString ExtractFileNameFromPath(const UString &path); - -bool DoesNameContainWildcard(const UString &path); -bool DoesWildcardMatchName(const UString &mask, const UString &name); - -namespace NWildcard { - -#ifdef _WIN32 -// returns true, if name is like "a:", "c:", ... -bool IsDriveColonName(const wchar_t *s); -unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts); -#endif - -struct CItem -{ - UStringVector PathParts; - bool Recursive; - bool ForFile; - bool ForDir; - bool WildcardMatching; - - #ifdef _WIN32 - bool IsDriveItem() const - { - return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]); - } - #endif - - // CItem(): WildcardMatching(true) {} - - bool AreAllAllowed() const; - bool CheckPath(const UStringVector &pathParts, bool isFile) const; -}; - - - -const Byte kMark_FileOrDir = 0; -const Byte kMark_StrictFile = 1; -const Byte kMark_StrictFile_IfWildcard = 2; - -struct CCensorPathProps -{ - bool Recursive; - bool WildcardMatching; - Byte MarkMode; - - CCensorPathProps(): - Recursive(false), - WildcardMatching(true), - MarkMode(kMark_FileOrDir) - {} -}; - - -class CCensorNode MY_UNCOPYABLE -{ - CCensorNode *Parent; - - bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const; - void AddItemSimple(bool include, CItem &item); -public: - // bool ExcludeDirItems; - - CCensorNode(): - Parent(NULL) - // , ExcludeDirItems(false) - {} - - CCensorNode(const UString &name, CCensorNode *parent): - Parent(parent) - // , ExcludeDirItems(false) - , Name(name) - {} - - UString Name; // WIN32 doesn't support wildcards in file names - CObjectVector SubNodes; - CObjectVector IncludeItems; - CObjectVector ExcludeItems; - - CCensorNode &Find_SubNode_Or_Add_New(const UString &name) - { - int i = FindSubNode(name); - if (i >= 0) - return SubNodes[(unsigned)i]; - // return SubNodes.Add(CCensorNode(name, this)); - CCensorNode &node = SubNodes.AddNew(); - node.Parent = this; - node.Name = name; - return node; - } - - bool AreAllAllowed() const; - - int FindSubNode(const UString &path) const; - - void AddItem(bool include, CItem &item, int ignoreWildcardIndex = -1); - // void AddItem(bool include, const UString &path, const CCensorPathProps &props); - void Add_Wildcard() - { - CItem item; - item.PathParts.Add(L"*"); - item.Recursive = false; - item.ForFile = true; - item.ForDir = true; - item.WildcardMatching = true; - AddItem( - true // include - , item); - } - - // NeedCheckSubDirs() returns true, if there are IncludeItems rules that affect items in subdirs - bool NeedCheckSubDirs() const; - bool AreThereIncludeItems() const; - - /* - CheckPathVect() doesn't check path in Parent CCensorNode - so use CheckPathVect() for root CCensorNode - OUT: - returns (true) && (include = false) - file in exlude list - returns (true) && (include = true) - file in include list and is not in exlude list - returns (false) - file is not in (include/exlude) list - */ - bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const; - - // bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const; - // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; - - // CheckPathToRoot_Change() changes pathParts !!! - bool CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const; - bool CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const; - - // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const; - void ExtendExclude(const CCensorNode &fromNodes); -}; - - -struct CPair MY_UNCOPYABLE -{ - UString Prefix; - CCensorNode Head; - - // CPair(const UString &prefix): Prefix(prefix) { }; -}; - - -enum ECensorPathMode -{ - k_RelatPath, // absolute prefix as Prefix, remain path in Tree - k_FullPath, // drive prefix as Prefix, remain path in Tree - k_AbsPath // full path in Tree -}; - - -struct CCensorPath -{ - UString Path; - bool Include; - CCensorPathProps Props; - - CCensorPath(): - Include(true) - {} -}; - - -class CCensor MY_UNCOPYABLE -{ - int FindPairForPrefix(const UString &prefix) const; -public: - CObjectVector Pairs; - - bool ExcludeDirItems; - bool ExcludeFileItems; - - CCensor(): - ExcludeDirItems(false), - ExcludeFileItems(false) - {} - - CObjectVector CensorPaths; - - bool AllAreRelative() const - { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } - - void AddItem(ECensorPathMode pathMode, bool include, const UString &path, const CCensorPathProps &props); - // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; - void ExtendExclude(); - - void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode); - void AddPreItem(bool include, const UString &path, const CCensorPathProps &props); - - void AddPreItem_NoWildcard(const UString &path) - { - CCensorPathProps props; - props.WildcardMatching = false; - AddPreItem( - true, // include - path, props); - } - void AddPreItem_Wildcard() - { - CCensorPathProps props; - // props.WildcardMatching = true; - AddPreItem( - true, // include - UString("*"), props); - } -}; - -} - -#endif +// Common/Wildcard.h + +#ifndef ZIP7_INC_COMMON_WILDCARD_H +#define ZIP7_INC_COMMON_WILDCARD_H + +#include "MyString.h" + +int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW; +#ifndef USE_UNICODE_FSTRING + int CompareFileNames(const char *s1, const char *s2); +#endif + +bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2); + +void SplitPathToParts(const UString &path, UStringVector &pathParts); +void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name); +void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path) + +UString ExtractDirPrefixFromPath(const UString &path); +UString ExtractFileNameFromPath(const UString &path); + +bool DoesNameContainWildcard(const UString &path); +bool DoesWildcardMatchName(const UString &mask, const UString &name); + +namespace NWildcard { + +#ifdef _WIN32 +// returns true, if name is like "a:", "c:", ... +bool IsDriveColonName(const wchar_t *s); +unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts); +#endif + +struct CItem +{ + UStringVector PathParts; + bool Recursive; + bool ForFile; + bool ForDir; + bool WildcardMatching; + + #ifdef _WIN32 + bool IsDriveItem() const + { + return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]); + } + #endif + + // CItem(): WildcardMatching(true) {} + + bool AreAllAllowed() const; + bool CheckPath(const UStringVector &pathParts, bool isFile) const; +}; + + + +const Byte kMark_FileOrDir = 0; +const Byte kMark_StrictFile = 1; +const Byte kMark_StrictFile_IfWildcard = 2; + +struct CCensorPathProps +{ + bool Recursive; + bool WildcardMatching; + Byte MarkMode; + + CCensorPathProps(): + Recursive(false), + WildcardMatching(true), + MarkMode(kMark_FileOrDir) + {} +}; + + +class CCensorNode MY_UNCOPYABLE +{ + CCensorNode *Parent; + + bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const; + void AddItemSimple(bool include, CItem &item); +public: + // bool ExcludeDirItems; + + CCensorNode(): + Parent(NULL) + // , ExcludeDirItems(false) + {} + + CCensorNode(const UString &name, CCensorNode *parent): + Parent(parent) + // , ExcludeDirItems(false) + , Name(name) + {} + + UString Name; // WIN32 doesn't support wildcards in file names + CObjectVector SubNodes; + CObjectVector IncludeItems; + CObjectVector ExcludeItems; + + CCensorNode &Find_SubNode_Or_Add_New(const UString &name) + { + int i = FindSubNode(name); + if (i >= 0) + return SubNodes[(unsigned)i]; + // return SubNodes.Add(CCensorNode(name, this)); + CCensorNode &node = SubNodes.AddNew(); + node.Parent = this; + node.Name = name; + return node; + } + + bool AreAllAllowed() const; + + int FindSubNode(const UString &path) const; + + void AddItem(bool include, CItem &item, int ignoreWildcardIndex = -1); + // void AddItem(bool include, const UString &path, const CCensorPathProps &props); + void Add_Wildcard() + { + CItem item; + item.PathParts.Add(L"*"); + item.Recursive = false; + item.ForFile = true; + item.ForDir = true; + item.WildcardMatching = true; + AddItem( + true // include + , item); + } + + // NeedCheckSubDirs() returns true, if there are IncludeItems rules that affect items in subdirs + bool NeedCheckSubDirs() const; + bool AreThereIncludeItems() const; + + /* + CheckPathVect() doesn't check path in Parent CCensorNode + so use CheckPathVect() for root CCensorNode + OUT: + returns (true) && (include = false) - file in exlude list + returns (true) && (include = true) - file in include list and is not in exlude list + returns (false) - file is not in (include/exlude) list + */ + bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const; + + // bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const; + // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; + + // CheckPathToRoot_Change() changes pathParts !!! + bool CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const; + bool CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const; + + // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const; + void ExtendExclude(const CCensorNode &fromNodes); +}; + + +struct CPair MY_UNCOPYABLE +{ + UString Prefix; + CCensorNode Head; + + // CPair(const UString &prefix): Prefix(prefix) { }; +}; + + +enum ECensorPathMode +{ + k_RelatPath, // absolute prefix as Prefix, remain path in Tree + k_FullPath, // drive prefix as Prefix, remain path in Tree + k_AbsPath // full path in Tree +}; + + +struct CCensorPath +{ + UString Path; + bool Include; + CCensorPathProps Props; + + CCensorPath(): + Include(true) + {} +}; + + +class CCensor MY_UNCOPYABLE +{ + int FindPairForPrefix(const UString &prefix) const; +public: + CObjectVector Pairs; + + bool ExcludeDirItems; + bool ExcludeFileItems; + + CCensor(): + ExcludeDirItems(false), + ExcludeFileItems(false) + {} + + CObjectVector CensorPaths; + + bool AllAreRelative() const + { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } + + void AddItem(ECensorPathMode pathMode, bool include, const UString &path, const CCensorPathProps &props); + // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; + void ExtendExclude(); + + void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode); + void AddPreItem(bool include, const UString &path, const CCensorPathProps &props); + + void AddPreItem_NoWildcard(const UString &path) + { + CCensorPathProps props; + props.WildcardMatching = false; + AddPreItem( + true, // include + path, props); + } + void AddPreItem_Wildcard() + { + CCensorPathProps props; + // props.WildcardMatching = true; + AddPreItem( + true, // include + UString("*"), props); + } +}; + +} + +#endif diff --git a/CPP/Common/Xxh64Reg.cpp b/CPP/Common/Xxh64Reg.cpp index fc03da14a..8abd15ebf 100644 --- a/CPP/Common/Xxh64Reg.cpp +++ b/CPP/Common/Xxh64Reg.cpp @@ -1,97 +1,97 @@ -// Xxh64Reg.cpp - -#include "StdAfx.h" - -#include "../../C/Xxh64.h" -#include "../../C/CpuArch.h" - -// #define Z7_USE_HHX64_ORIGINAL -#ifdef Z7_USE_HHX64_ORIGINAL -#ifdef __clang__ -#include "../../C/zstd7z/7z_zstd_cmpl.h" -#pragma GCC diagnostic ignored "-Wlanguage-extension-token" -#endif -#define XXH_STATIC_LINKING_ONLY -#include "../../C/zstd7z/common/xxhash.h" -#endif - -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" - -Z7_CLASS_IMP_COM_1( - CXxh64Hasher - , IHasher -) - CXxh64 _state; -public: - Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field - CXxh64Hasher() { Init(); } -}; - -Z7_COM7F_IMF2(void, CXxh64Hasher::Init()) -{ - Xxh64_Init(&_state); -} - -Z7_COM7F_IMF2(void, CXxh64Hasher::Update(const void *data, UInt32 size)) -{ -#if 1 - Xxh64_Update(&_state, data, size); -#else // for debug: - for (;;) - { - if (size == 0) - return; - UInt32 size2 = (size * 0x85EBCA87) % size / 8; - if (size2 == 0) - size2 = 1; - Xxh64_Update(&_state, data, size2); - data = (const void *)((const Byte *)data + size2); - size -= size2; - } -#endif -} - -Z7_COM7F_IMF2(void, CXxh64Hasher::Final(Byte *digest)) -{ - const UInt64 val = Xxh64_Digest(&_state); - SetUi64(digest, val) -} - -REGISTER_HASHER(CXxh64Hasher, 0x211, "XXH64", 8) - - - -#ifdef Z7_USE_HHX64_ORIGINAL -namespace NOriginal -{ -Z7_CLASS_IMP_COM_1( - CXxh64Hasher - , IHasher -) - XXH64_state_t _state; -public: - Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field - CXxh64Hasher() { Init(); } -}; - -Z7_COM7F_IMF2(void, CXxh64Hasher::Init()) -{ - XXH64_reset(&_state, 0); -} - -Z7_COM7F_IMF2(void, CXxh64Hasher::Update(const void *data, UInt32 size)) -{ - XXH64_update(&_state, data, size); -} - -Z7_COM7F_IMF2(void, CXxh64Hasher::Final(Byte *digest)) -{ - const UInt64 val = XXH64_digest(&_state); - SetUi64(digest, val) -} - -REGISTER_HASHER(CXxh64Hasher, 0x212, "XXH64a", 8) -} -#endif +// Xxh64Reg.cpp + +#include "StdAfx.h" + +#include "../../C/Xxh64.h" +#include "../../C/CpuArch.h" + +// #define Z7_USE_HHX64_ORIGINAL +#ifdef Z7_USE_HHX64_ORIGINAL +#ifdef __clang__ +#include "../../C/zstd7z/7z_zstd_cmpl.h" +#pragma GCC diagnostic ignored "-Wlanguage-extension-token" +#endif +#define XXH_STATIC_LINKING_ONLY +#include "../../C/zstd7z/common/xxhash.h" +#endif + +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_1( + CXxh64Hasher + , IHasher +) + CXxh64 _state; +public: + Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field + CXxh64Hasher() { Init(); } +}; + +Z7_COM7F_IMF2(void, CXxh64Hasher::Init()) +{ + Xxh64_Init(&_state); +} + +Z7_COM7F_IMF2(void, CXxh64Hasher::Update(const void *data, UInt32 size)) +{ +#if 1 + Xxh64_Update(&_state, data, size); +#else // for debug: + for (;;) + { + if (size == 0) + return; + UInt32 size2 = (size * 0x85EBCA87) % size / 8; + if (size2 == 0) + size2 = 1; + Xxh64_Update(&_state, data, size2); + data = (const void *)((const Byte *)data + size2); + size -= size2; + } +#endif +} + +Z7_COM7F_IMF2(void, CXxh64Hasher::Final(Byte *digest)) +{ + const UInt64 val = Xxh64_Digest(&_state); + SetUi64(digest, val) +} + +REGISTER_HASHER(CXxh64Hasher, 0x211, "XXH64", 8) + + + +#ifdef Z7_USE_HHX64_ORIGINAL +namespace NOriginal +{ +Z7_CLASS_IMP_COM_1( + CXxh64Hasher + , IHasher +) + XXH64_state_t _state; +public: + Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field + CXxh64Hasher() { Init(); } +}; + +Z7_COM7F_IMF2(void, CXxh64Hasher::Init()) +{ + XXH64_reset(&_state, 0); +} + +Z7_COM7F_IMF2(void, CXxh64Hasher::Update(const void *data, UInt32 size)) +{ + XXH64_update(&_state, data, size); +} + +Z7_COM7F_IMF2(void, CXxh64Hasher::Final(Byte *digest)) +{ + const UInt64 val = XXH64_digest(&_state); + SetUi64(digest, val) +} + +REGISTER_HASHER(CXxh64Hasher, 0x212, "XXH64a", 8) +} +#endif diff --git a/CPP/Common/XzCrc64Init.cpp b/CPP/Common/XzCrc64Init.cpp index 1eae72ad9..5cb8e6744 100644 --- a/CPP/Common/XzCrc64Init.cpp +++ b/CPP/Common/XzCrc64Init.cpp @@ -1,7 +1,7 @@ -// XzCrc64Init.cpp - -#include "StdAfx.h" - -#include "../../C/XzCrc64.h" - -static struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; +// XzCrc64Init.cpp + +#include "StdAfx.h" + +#include "../../C/XzCrc64.h" + +static struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; diff --git a/CPP/Common/XzCrc64Reg.cpp b/CPP/Common/XzCrc64Reg.cpp index dfafa8d73..e9e67efcb 100644 --- a/CPP/Common/XzCrc64Reg.cpp +++ b/CPP/Common/XzCrc64Reg.cpp @@ -1,39 +1,39 @@ -// XzCrc64Reg.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" -#include "../../C/XzCrc64.h" - -#include "../Common/MyCom.h" - -#include "../7zip/Common/RegisterCodec.h" - -Z7_CLASS_IMP_COM_1( - CXzCrc64Hasher - , IHasher -) - UInt64 _crc; -public: - Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field - - CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {} -}; - -Z7_COM7F_IMF2(void, CXzCrc64Hasher::Init()) -{ - _crc = CRC64_INIT_VAL; -} - -Z7_COM7F_IMF2(void, CXzCrc64Hasher::Update(const void *data, UInt32 size)) -{ - _crc = Crc64Update(_crc, data, size); -} - -Z7_COM7F_IMF2(void, CXzCrc64Hasher::Final(Byte *digest)) -{ - const UInt64 val = CRC64_GET_DIGEST(_crc); - SetUi64(digest, val) -} - -REGISTER_HASHER(CXzCrc64Hasher, 0x4, "CRC64", 8) +// XzCrc64Reg.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" +#include "../../C/XzCrc64.h" + +#include "../Common/MyCom.h" + +#include "../7zip/Common/RegisterCodec.h" + +Z7_CLASS_IMP_COM_1( + CXzCrc64Hasher + , IHasher +) + UInt64 _crc; +public: + Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field + + CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {} +}; + +Z7_COM7F_IMF2(void, CXzCrc64Hasher::Init()) +{ + _crc = CRC64_INIT_VAL; +} + +Z7_COM7F_IMF2(void, CXzCrc64Hasher::Update(const void *data, UInt32 size)) +{ + _crc = Crc64Update(_crc, data, size); +} + +Z7_COM7F_IMF2(void, CXzCrc64Hasher::Final(Byte *digest)) +{ + const UInt64 val = CRC64_GET_DIGEST(_crc); + SetUi64(digest, val) +} + +REGISTER_HASHER(CXzCrc64Hasher, 0x4, "CRC64", 8) diff --git a/CPP/Windows/COM.cpp b/CPP/Windows/COM.cpp index b859326c1..d0cb32113 100644 --- a/CPP/Windows/COM.cpp +++ b/CPP/Windows/COM.cpp @@ -1,41 +1,41 @@ -// Windows/COM.cpp - -#include "StdAfx.h" - -/* - -#include "COM.h" -#include "../Common/StringConvert.h" - -namespace NWindows { -namespace NCOM { - -// CoInitialize (NULL); must be called! - -UString GUIDToStringW(REFGUID guid) -{ - UString s; - const unsigned kSize = 48; - StringFromGUID2(guid, s.GetBuf(kSize), kSize); - s.ReleaseBuf_CalcLen(kSize); - return s; -} - -AString GUIDToStringA(REFGUID guid) -{ - return UnicodeStringToMultiByte(GUIDToStringW(guid)); -} - -HRESULT StringToGUIDW(const wchar_t *string, GUID &classID) -{ - return CLSIDFromString((wchar_t *)string, &classID); -} - -HRESULT StringToGUIDA(const char *string, GUID &classID) -{ - return StringToGUIDW(MultiByteToUnicodeString(string), classID); -} - -}} - -*/ +// Windows/COM.cpp + +#include "StdAfx.h" + +/* + +#include "COM.h" +#include "../Common/StringConvert.h" + +namespace NWindows { +namespace NCOM { + +// CoInitialize (NULL); must be called! + +UString GUIDToStringW(REFGUID guid) +{ + UString s; + const unsigned kSize = 48; + StringFromGUID2(guid, s.GetBuf(kSize), kSize); + s.ReleaseBuf_CalcLen(kSize); + return s; +} + +AString GUIDToStringA(REFGUID guid) +{ + return UnicodeStringToMultiByte(GUIDToStringW(guid)); +} + +HRESULT StringToGUIDW(const wchar_t *string, GUID &classID) +{ + return CLSIDFromString((wchar_t *)string, &classID); +} + +HRESULT StringToGUIDA(const char *string, GUID &classID) +{ + return StringToGUIDW(MultiByteToUnicodeString(string), classID); +} + +}} + +*/ diff --git a/CPP/Windows/COM.h b/CPP/Windows/COM.h index ec30c096a..a8780cacb 100644 --- a/CPP/Windows/COM.h +++ b/CPP/Windows/COM.h @@ -1,86 +1,86 @@ -// Windows/COM.h - -#ifndef ZIP7_INC_WINDOWS_COM_H -#define ZIP7_INC_WINDOWS_COM_H - -// #include "../Common/MyString.h" - -namespace NWindows { -namespace NCOM { - -#ifdef _WIN32 - -class CComInitializer -{ -public: - CComInitializer() - { - #ifdef UNDER_CE - CoInitializeEx(NULL, COINIT_MULTITHREADED); - #else - // it's single thread. Do we need multithread? - CoInitialize(NULL); - #endif - } - ~CComInitializer() { CoUninitialize(); } -}; - -/* -class CStgMedium2 -{ - STGMEDIUM _object; - bool _mustBeReleased; -public: - CStgMedium2(): _mustBeReleased(false) {} - ~CStgMedium2() { Free(); } - void Free() - { - if (_mustBeReleased) - ReleaseStgMedium(&_object); - _mustBeReleased = false; - } - const STGMEDIUM* operator->() const { return &_object;} - STGMEDIUM* operator->() { return &_object;} - STGMEDIUM* operator&() { return &_object; } -}; -*/ - -struct CStgMedium: public STGMEDIUM -{ - CStgMedium() - { - tymed = TYMED_NULL; // 0 - hGlobal = NULL; - pUnkForRelease = NULL; - } - ~CStgMedium() - { - ReleaseStgMedium(this); - } -}; - -#endif - -/* -////////////////////////////////// -// GUID <--> String Conversions -UString GUIDToStringW(REFGUID guid); -AString GUIDToStringA(REFGUID guid); -#ifdef UNICODE - #define GUIDToString GUIDToStringW -#else - #define GUIDToString GUIDToStringA -#endif - -HRESULT StringToGUIDW(const wchar_t *string, GUID &classID); -HRESULT StringToGUIDA(const char *string, GUID &classID); -#ifdef UNICODE - #define StringToGUID StringToGUIDW -#else - #define StringToGUID StringToGUIDA -#endif -*/ - -}} - -#endif +// Windows/COM.h + +#ifndef ZIP7_INC_WINDOWS_COM_H +#define ZIP7_INC_WINDOWS_COM_H + +// #include "../Common/MyString.h" + +namespace NWindows { +namespace NCOM { + +#ifdef _WIN32 + +class CComInitializer +{ +public: + CComInitializer() + { + #ifdef UNDER_CE + CoInitializeEx(NULL, COINIT_MULTITHREADED); + #else + // it's single thread. Do we need multithread? + CoInitialize(NULL); + #endif + } + ~CComInitializer() { CoUninitialize(); } +}; + +/* +class CStgMedium2 +{ + STGMEDIUM _object; + bool _mustBeReleased; +public: + CStgMedium2(): _mustBeReleased(false) {} + ~CStgMedium2() { Free(); } + void Free() + { + if (_mustBeReleased) + ReleaseStgMedium(&_object); + _mustBeReleased = false; + } + const STGMEDIUM* operator->() const { return &_object;} + STGMEDIUM* operator->() { return &_object;} + STGMEDIUM* operator&() { return &_object; } +}; +*/ + +struct CStgMedium: public STGMEDIUM +{ + CStgMedium() + { + tymed = TYMED_NULL; // 0 + hGlobal = NULL; + pUnkForRelease = NULL; + } + ~CStgMedium() + { + ReleaseStgMedium(this); + } +}; + +#endif + +/* +////////////////////////////////// +// GUID <--> String Conversions +UString GUIDToStringW(REFGUID guid); +AString GUIDToStringA(REFGUID guid); +#ifdef UNICODE + #define GUIDToString GUIDToStringW +#else + #define GUIDToString GUIDToStringA +#endif + +HRESULT StringToGUIDW(const wchar_t *string, GUID &classID); +HRESULT StringToGUIDA(const char *string, GUID &classID); +#ifdef UNICODE + #define StringToGUID StringToGUIDW +#else + #define StringToGUID StringToGUIDA +#endif +*/ + +}} + +#endif diff --git a/CPP/Windows/Clipboard.cpp b/CPP/Windows/Clipboard.cpp index 90c486430..bc7e201dd 100644 --- a/CPP/Windows/Clipboard.cpp +++ b/CPP/Windows/Clipboard.cpp @@ -1,130 +1,130 @@ -// Windows/Clipboard.cpp - -#include "StdAfx.h" - -#ifdef UNDER_CE -#include -#endif - -#include "../Common/StringConvert.h" - -#include "Clipboard.h" -#include "Defs.h" -#include "MemoryGlobal.h" -#include "Shell.h" - -namespace NWindows { - -bool CClipboard::Open(HWND wndNewOwner) throw() -{ - m_Open = BOOLToBool(::OpenClipboard(wndNewOwner)); - return m_Open; -} - -bool CClipboard::Close() throw() -{ - if (!m_Open) - return true; - m_Open = !BOOLToBool(CloseClipboard()); - return !m_Open; -} - -bool ClipboardIsFormatAvailableHDROP() -{ - return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP)); -} - -/* -bool ClipboardGetTextString(AString &s) -{ - s.Empty(); - if (!IsClipboardFormatAvailable(CF_TEXT)) - return false; - CClipboard clipboard; - - if (!clipboard.Open(NULL)) - return false; - - HGLOBAL h = ::GetClipboardData(CF_TEXT); - if (h != NULL) - { - NMemory::CGlobalLock globalLock(h); - const char *p = (const char *)globalLock.GetPointer(); - if (p != NULL) - { - s = p; - return true; - } - } - return false; -} -*/ - -/* -bool ClipboardGetFileNames(UStringVector &names) -{ - names.Clear(); - if (!IsClipboardFormatAvailable(CF_HDROP)) - return false; - CClipboard clipboard; - - if (!clipboard.Open(NULL)) - return false; - - HGLOBAL h = ::GetClipboardData(CF_HDROP); - if (h != NULL) - { - NMemory::CGlobalLock globalLock(h); - void *p = (void *)globalLock.GetPointer(); - if (p != NULL) - { - NShell::CDrop drop(false); - drop.Attach((HDROP)p); - drop.QueryFileNames(names); - return true; - } - } - return false; -} -*/ - -static bool ClipboardSetData(UINT uFormat, const void *data, size_t size) throw() -{ - NMemory::CGlobal global; - if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size)) - return false; - { - NMemory::CGlobalLock globalLock(global); - LPVOID p = globalLock.GetPointer(); - if (!p) - return false; - memcpy(p, data, size); - } - if (::SetClipboardData(uFormat, global) == NULL) - return false; - global.Detach(); - return true; -} - -bool ClipboardSetText(HWND owner, const UString &s) -{ - CClipboard clipboard; - if (!clipboard.Open(owner)) - return false; - if (!::EmptyClipboard()) - return false; - - bool res; - res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Len() + 1) * sizeof(wchar_t)); - #ifndef _UNICODE - AString a (UnicodeStringToMultiByte(s, CP_ACP)); - if (ClipboardSetData(CF_TEXT, (const char *)a, (a.Len() + 1) * sizeof(char))) - res = true; - a = UnicodeStringToMultiByte(s, CP_OEMCP); - if (ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Len() + 1) * sizeof(char))) - res = true; - #endif - return res; -} - -} +// Windows/Clipboard.cpp + +#include "StdAfx.h" + +#ifdef UNDER_CE +#include +#endif + +#include "../Common/StringConvert.h" + +#include "Clipboard.h" +#include "Defs.h" +#include "MemoryGlobal.h" +#include "Shell.h" + +namespace NWindows { + +bool CClipboard::Open(HWND wndNewOwner) throw() +{ + m_Open = BOOLToBool(::OpenClipboard(wndNewOwner)); + return m_Open; +} + +bool CClipboard::Close() throw() +{ + if (!m_Open) + return true; + m_Open = !BOOLToBool(CloseClipboard()); + return !m_Open; +} + +bool ClipboardIsFormatAvailableHDROP() +{ + return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP)); +} + +/* +bool ClipboardGetTextString(AString &s) +{ + s.Empty(); + if (!IsClipboardFormatAvailable(CF_TEXT)) + return false; + CClipboard clipboard; + + if (!clipboard.Open(NULL)) + return false; + + HGLOBAL h = ::GetClipboardData(CF_TEXT); + if (h != NULL) + { + NMemory::CGlobalLock globalLock(h); + const char *p = (const char *)globalLock.GetPointer(); + if (p != NULL) + { + s = p; + return true; + } + } + return false; +} +*/ + +/* +bool ClipboardGetFileNames(UStringVector &names) +{ + names.Clear(); + if (!IsClipboardFormatAvailable(CF_HDROP)) + return false; + CClipboard clipboard; + + if (!clipboard.Open(NULL)) + return false; + + HGLOBAL h = ::GetClipboardData(CF_HDROP); + if (h != NULL) + { + NMemory::CGlobalLock globalLock(h); + void *p = (void *)globalLock.GetPointer(); + if (p != NULL) + { + NShell::CDrop drop(false); + drop.Attach((HDROP)p); + drop.QueryFileNames(names); + return true; + } + } + return false; +} +*/ + +static bool ClipboardSetData(UINT uFormat, const void *data, size_t size) throw() +{ + NMemory::CGlobal global; + if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size)) + return false; + { + NMemory::CGlobalLock globalLock(global); + LPVOID p = globalLock.GetPointer(); + if (!p) + return false; + memcpy(p, data, size); + } + if (::SetClipboardData(uFormat, global) == NULL) + return false; + global.Detach(); + return true; +} + +bool ClipboardSetText(HWND owner, const UString &s) +{ + CClipboard clipboard; + if (!clipboard.Open(owner)) + return false; + if (!::EmptyClipboard()) + return false; + + bool res; + res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Len() + 1) * sizeof(wchar_t)); + #ifndef _UNICODE + AString a (UnicodeStringToMultiByte(s, CP_ACP)); + if (ClipboardSetData(CF_TEXT, (const char *)a, (a.Len() + 1) * sizeof(char))) + res = true; + a = UnicodeStringToMultiByte(s, CP_OEMCP); + if (ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Len() + 1) * sizeof(char))) + res = true; + #endif + return res; +} + +} diff --git a/CPP/Windows/Clipboard.h b/CPP/Windows/Clipboard.h index 70fe6c48f..3b4f2fe5e 100644 --- a/CPP/Windows/Clipboard.h +++ b/CPP/Windows/Clipboard.h @@ -1,28 +1,28 @@ -// Windows/Clipboard.h - -#ifndef ZIP7_INC_CLIPBOARD_H -#define ZIP7_INC_CLIPBOARD_H - -#include "../Common/MyString.h" - -namespace NWindows { - -class CClipboard -{ - bool m_Open; -public: - CClipboard(): m_Open(false) {} - ~CClipboard() { Close(); } - bool Open(HWND wndNewOwner) throw(); - bool Close() throw(); -}; - -bool ClipboardIsFormatAvailableHDROP(); - -// bool ClipboardGetFileNames(UStringVector &names); -// bool ClipboardGetTextString(AString &s); -bool ClipboardSetText(HWND owner, const UString &s); - -} - -#endif +// Windows/Clipboard.h + +#ifndef ZIP7_INC_CLIPBOARD_H +#define ZIP7_INC_CLIPBOARD_H + +#include "../Common/MyString.h" + +namespace NWindows { + +class CClipboard +{ + bool m_Open; +public: + CClipboard(): m_Open(false) {} + ~CClipboard() { Close(); } + bool Open(HWND wndNewOwner) throw(); + bool Close() throw(); +}; + +bool ClipboardIsFormatAvailableHDROP(); + +// bool ClipboardGetFileNames(UStringVector &names); +// bool ClipboardGetTextString(AString &s); +bool ClipboardSetText(HWND owner, const UString &s); + +} + +#endif diff --git a/CPP/Windows/CommonDialog.cpp b/CPP/Windows/CommonDialog.cpp index 59d5b1bd9..7a92d5f9b 100644 --- a/CPP/Windows/CommonDialog.cpp +++ b/CPP/Windows/CommonDialog.cpp @@ -1,269 +1,269 @@ -// Windows/CommonDialog.cpp - -#include "StdAfx.h" - -#include "../Common/MyBuffer.h" - -#ifdef UNDER_CE -#include -#endif - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif - -#include "CommonDialog.h" -#include "Defs.h" -// #include "FileDir.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { - -/* - GetSaveFileName() - GetOpenFileName() - OPENFILENAME - -(lpstrInitialDir) : the initial directory. -DOCs: the algorithm for selecting the initial directory varies on different platforms: -{ - Win2000/XP/Vista: - 1. If lpstrFile contains a path, that path is the initial directory. - 2. Otherwise, lpstrInitialDir specifies the initial directory. - - Win7: - If lpstrInitialDir has the same value as was passed the first time - the application used an Open or Save As dialog box, the path - most recently selected by the user is used as the initial directory. -} - -Win10: - in: - function supports (lpstrInitialDir) path with super prefix "\\\\?\\" - function supports (lpstrInitialDir) path with long path - function doesn't support absolute (lpstrFile) path with super prefix "\\\\?\\" - function doesn't support absolute (lpstrFile) path with long path - out: the path with super prefix "\\\\?\\" will be returned, if selected path is long - -WinXP-64 and Win10: if no filters, the system shows all files. - but DOCs say: If all three members are zero or NULL, - the system does not use any filters and does not - show any files in the file list control of the dialog box. - -in Win7+: GetOpenFileName() and GetSaveFileName() - do not support pstrCustomFilter feature anymore -*/ - -#ifdef UNDER_CE -#define MY_OFN_PROJECT 0x00400000 -#define MY_OFN_SHOW_ALL 0x01000000 -#endif - - -/* -structures - OPENFILENAMEW - OPENFILENAMEA -contain additional members: -#if (_WIN32_WINNT >= 0x0500) - void *pvReserved; - DWORD dwReserved; - DWORD FlagsEx; -#endif - -If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions -will not work at NT 4.0, if we use sizeof(OPENFILENAME). -We try to use reduced structure OPENFILENAME_NT4. -*/ - -// #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500) -#if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK) - #ifndef _UNICODE - #define my_compatib_OPENFILENAMEA OPENFILENAMEA - #endif - #define my_compatib_OPENFILENAMEW OPENFILENAMEW - - // MinGW doesn't support some required macros. So we define them here: - #ifndef CDSIZEOF_STRUCT - #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) - #endif - #ifndef _UNICODE - #ifndef OPENFILENAME_SIZE_VERSION_400A - #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) - #endif - #endif - #ifndef OPENFILENAME_SIZE_VERSION_400W - #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) - #endif - - #ifndef _UNICODE - #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A - #endif - #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W -#else - #ifndef _UNICODE - #define my_compatib_OPENFILENAMEA OPENFILENAME_NT4A - #define my_compatib_OPENFILENAMEA_size sizeof(my_compatib_OPENFILENAMEA) - #endif - #define my_compatib_OPENFILENAMEW OPENFILENAME_NT4W - #define my_compatib_OPENFILENAMEW_size sizeof(my_compatib_OPENFILENAMEW) -#endif -/* -#elif defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500) -// || !defined(WINVER) - #ifndef _UNICODE - #define my_compatib_OPENFILENAMEA OPENFILENAMEA - #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA) - #endif - #define my_compatib_OPENFILENAMEW OPENFILENAMEW - #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW) -#else - -#endif -*/ - -#ifndef _UNICODE -#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; } -#endif - -bool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters) -{ - /* GetSaveFileName() and GetOpenFileName() could change current dir, - if OFN_NOCHANGEDIR is not used. - We can restore current dir manually, if it's required. - 22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */ - // NFile::NDir::CCurrentDirRestorer curDirRestorer; - -#ifndef _UNICODE - if (!g_IsNT) - { - AString tempPath; - AStringVector f; - unsigned i; - for (i = 0; i < filters.Size(); i++) - f.Add(GetSystemString(filters[i])); - unsigned size = f.Size() + 1; - for (i = 0; i < f.Size(); i++) - size += f[i].Len(); - CObjArray filterBuf(size); - // memset(filterBuf, 0, size * sizeof(char)); - { - char *dest = filterBuf; - for (i = 0; i < f.Size(); i++) - { - const AString &s = f[i]; - MyStringCopy(dest, s); - dest += s.Len() + 1; - } - *dest = 0; - } - my_compatib_OPENFILENAMEA p; - memset(&p, 0, sizeof(p)); - p.lStructSize = my_compatib_OPENFILENAMEA_size; - p.hwndOwner = hwndOwner; - if (size > 1) - { - p.lpstrFilter = filterBuf; - p.nFilterIndex = (DWORD)(FilterIndex + 1); - } - - CONV_U_To_A(p.lpstrInitialDir, lpstrInitialDir, initialDir_a) - CONV_U_To_A(p.lpstrTitle, lpstrTitle, title_a) - - const AString filePath_a = GetSystemString(FilePath); - const unsigned bufSize = MAX_PATH * 8 - + filePath_a.Len() - + initialDir_a.Len(); - p.nMaxFile = bufSize; - p.lpstrFile = tempPath.GetBuf(bufSize); - MyStringCopy(p.lpstrFile, filePath_a); - p.Flags = - OFN_EXPLORER - | OFN_HIDEREADONLY - | OFN_NOCHANGEDIR; - const BOOL b = SaveMode ? - ::GetSaveFileNameA((LPOPENFILENAMEA)(void *)&p) : - ::GetOpenFileNameA((LPOPENFILENAMEA)(void *)&p); - if (!b) - return false; - { - tempPath.ReleaseBuf_CalcLen(bufSize); - FilePath = GetUnicodeString(tempPath); - FilterIndex = (int)p.nFilterIndex - 1; - return true; - } - } - else -#endif - { - UString tempPath; - unsigned size = filters.Size() + 1; - unsigned i; - for (i = 0; i < filters.Size(); i++) - size += filters[i].Len(); - CObjArray filterBuf(size); - // memset(filterBuf, 0, size * sizeof(wchar_t)); - { - wchar_t *dest = filterBuf; - for (i = 0; i < filters.Size(); i++) - { - const UString &s = filters[i]; - MyStringCopy(dest, s); - dest += s.Len() + 1; - } - *dest = 0; - // if ((unsigned)(dest + 1 - filterBuf) != size) return false; - } - my_compatib_OPENFILENAMEW p; - memset(&p, 0, sizeof(p)); - p.lStructSize = my_compatib_OPENFILENAMEW_size; - p.hwndOwner = hwndOwner; - if (size > 1) - { - p.lpstrFilter = filterBuf; - p.nFilterIndex = (DWORD)(FilterIndex + 1); - } - unsigned bufSize = MAX_PATH * 8 + FilePath.Len(); - if (lpstrInitialDir) - { - p.lpstrInitialDir = lpstrInitialDir; - bufSize += MyStringLen(lpstrInitialDir); - } - p.nMaxFile = bufSize; - p.lpstrFile = tempPath.GetBuf(bufSize); - MyStringCopy(p.lpstrFile, FilePath); - p.lpstrTitle = lpstrTitle; - p.Flags = - OFN_EXPLORER - | OFN_HIDEREADONLY - | OFN_NOCHANGEDIR - // | OFN_FORCESHOWHIDDEN // Win10 shows hidden items even without this flag - // | OFN_PATHMUSTEXIST - #ifdef UNDER_CE - | (OpenFolderMode ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0) - #endif - ; - const BOOL b = SaveMode ? - ::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) : - ::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p); - /* DOCs: lpstrFile : - if the buffer is too small, then: - - the function returns FALSE - - the CommDlgExtendedError() returns FNERR_BUFFERTOOSMALL - - the first two bytes of the lpstrFile buffer contain the - required size, in bytes or characters. */ - if (!b) - return false; - { - tempPath.ReleaseBuf_CalcLen(bufSize); - FilePath = tempPath; - FilterIndex = (int)p.nFilterIndex - 1; - return true; - } - } -} - -} +// Windows/CommonDialog.cpp + +#include "StdAfx.h" + +#include "../Common/MyBuffer.h" + +#ifdef UNDER_CE +#include +#endif + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#include "CommonDialog.h" +#include "Defs.h" +// #include "FileDir.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +/* + GetSaveFileName() + GetOpenFileName() + OPENFILENAME + +(lpstrInitialDir) : the initial directory. +DOCs: the algorithm for selecting the initial directory varies on different platforms: +{ + Win2000/XP/Vista: + 1. If lpstrFile contains a path, that path is the initial directory. + 2. Otherwise, lpstrInitialDir specifies the initial directory. + + Win7: + If lpstrInitialDir has the same value as was passed the first time + the application used an Open or Save As dialog box, the path + most recently selected by the user is used as the initial directory. +} + +Win10: + in: + function supports (lpstrInitialDir) path with super prefix "\\\\?\\" + function supports (lpstrInitialDir) path with long path + function doesn't support absolute (lpstrFile) path with super prefix "\\\\?\\" + function doesn't support absolute (lpstrFile) path with long path + out: the path with super prefix "\\\\?\\" will be returned, if selected path is long + +WinXP-64 and Win10: if no filters, the system shows all files. + but DOCs say: If all three members are zero or NULL, + the system does not use any filters and does not + show any files in the file list control of the dialog box. + +in Win7+: GetOpenFileName() and GetSaveFileName() + do not support pstrCustomFilter feature anymore +*/ + +#ifdef UNDER_CE +#define MY_OFN_PROJECT 0x00400000 +#define MY_OFN_SHOW_ALL 0x01000000 +#endif + + +/* +structures + OPENFILENAMEW + OPENFILENAMEA +contain additional members: +#if (_WIN32_WINNT >= 0x0500) + void *pvReserved; + DWORD dwReserved; + DWORD FlagsEx; +#endif + +If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions +will not work at NT 4.0, if we use sizeof(OPENFILENAME). +We try to use reduced structure OPENFILENAME_NT4. +*/ + +// #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500) +#if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK) + #ifndef _UNICODE + #define my_compatib_OPENFILENAMEA OPENFILENAMEA + #endif + #define my_compatib_OPENFILENAMEW OPENFILENAMEW + + // MinGW doesn't support some required macros. So we define them here: + #ifndef CDSIZEOF_STRUCT + #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) + #endif + #ifndef _UNICODE + #ifndef OPENFILENAME_SIZE_VERSION_400A + #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) + #endif + #endif + #ifndef OPENFILENAME_SIZE_VERSION_400W + #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) + #endif + + #ifndef _UNICODE + #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A + #endif + #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W +#else + #ifndef _UNICODE + #define my_compatib_OPENFILENAMEA OPENFILENAME_NT4A + #define my_compatib_OPENFILENAMEA_size sizeof(my_compatib_OPENFILENAMEA) + #endif + #define my_compatib_OPENFILENAMEW OPENFILENAME_NT4W + #define my_compatib_OPENFILENAMEW_size sizeof(my_compatib_OPENFILENAMEW) +#endif +/* +#elif defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500) +// || !defined(WINVER) + #ifndef _UNICODE + #define my_compatib_OPENFILENAMEA OPENFILENAMEA + #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA) + #endif + #define my_compatib_OPENFILENAMEW OPENFILENAMEW + #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW) +#else + +#endif +*/ + +#ifndef _UNICODE +#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; } +#endif + +bool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters) +{ + /* GetSaveFileName() and GetOpenFileName() could change current dir, + if OFN_NOCHANGEDIR is not used. + We can restore current dir manually, if it's required. + 22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */ + // NFile::NDir::CCurrentDirRestorer curDirRestorer; + +#ifndef _UNICODE + if (!g_IsNT) + { + AString tempPath; + AStringVector f; + unsigned i; + for (i = 0; i < filters.Size(); i++) + f.Add(GetSystemString(filters[i])); + unsigned size = f.Size() + 1; + for (i = 0; i < f.Size(); i++) + size += f[i].Len(); + CObjArray filterBuf(size); + // memset(filterBuf, 0, size * sizeof(char)); + { + char *dest = filterBuf; + for (i = 0; i < f.Size(); i++) + { + const AString &s = f[i]; + MyStringCopy(dest, s); + dest += s.Len() + 1; + } + *dest = 0; + } + my_compatib_OPENFILENAMEA p; + memset(&p, 0, sizeof(p)); + p.lStructSize = my_compatib_OPENFILENAMEA_size; + p.hwndOwner = hwndOwner; + if (size > 1) + { + p.lpstrFilter = filterBuf; + p.nFilterIndex = (DWORD)(FilterIndex + 1); + } + + CONV_U_To_A(p.lpstrInitialDir, lpstrInitialDir, initialDir_a) + CONV_U_To_A(p.lpstrTitle, lpstrTitle, title_a) + + const AString filePath_a = GetSystemString(FilePath); + const unsigned bufSize = MAX_PATH * 8 + + filePath_a.Len() + + initialDir_a.Len(); + p.nMaxFile = bufSize; + p.lpstrFile = tempPath.GetBuf(bufSize); + MyStringCopy(p.lpstrFile, filePath_a); + p.Flags = + OFN_EXPLORER + | OFN_HIDEREADONLY + | OFN_NOCHANGEDIR; + const BOOL b = SaveMode ? + ::GetSaveFileNameA((LPOPENFILENAMEA)(void *)&p) : + ::GetOpenFileNameA((LPOPENFILENAMEA)(void *)&p); + if (!b) + return false; + { + tempPath.ReleaseBuf_CalcLen(bufSize); + FilePath = GetUnicodeString(tempPath); + FilterIndex = (int)p.nFilterIndex - 1; + return true; + } + } + else +#endif + { + UString tempPath; + unsigned size = filters.Size() + 1; + unsigned i; + for (i = 0; i < filters.Size(); i++) + size += filters[i].Len(); + CObjArray filterBuf(size); + // memset(filterBuf, 0, size * sizeof(wchar_t)); + { + wchar_t *dest = filterBuf; + for (i = 0; i < filters.Size(); i++) + { + const UString &s = filters[i]; + MyStringCopy(dest, s); + dest += s.Len() + 1; + } + *dest = 0; + // if ((unsigned)(dest + 1 - filterBuf) != size) return false; + } + my_compatib_OPENFILENAMEW p; + memset(&p, 0, sizeof(p)); + p.lStructSize = my_compatib_OPENFILENAMEW_size; + p.hwndOwner = hwndOwner; + if (size > 1) + { + p.lpstrFilter = filterBuf; + p.nFilterIndex = (DWORD)(FilterIndex + 1); + } + unsigned bufSize = MAX_PATH * 8 + FilePath.Len(); + if (lpstrInitialDir) + { + p.lpstrInitialDir = lpstrInitialDir; + bufSize += MyStringLen(lpstrInitialDir); + } + p.nMaxFile = bufSize; + p.lpstrFile = tempPath.GetBuf(bufSize); + MyStringCopy(p.lpstrFile, FilePath); + p.lpstrTitle = lpstrTitle; + p.Flags = + OFN_EXPLORER + | OFN_HIDEREADONLY + | OFN_NOCHANGEDIR + // | OFN_FORCESHOWHIDDEN // Win10 shows hidden items even without this flag + // | OFN_PATHMUSTEXIST + #ifdef UNDER_CE + | (OpenFolderMode ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0) + #endif + ; + const BOOL b = SaveMode ? + ::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) : + ::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p); + /* DOCs: lpstrFile : + if the buffer is too small, then: + - the function returns FALSE + - the CommDlgExtendedError() returns FNERR_BUFFERTOOSMALL + - the first two bytes of the lpstrFile buffer contain the + required size, in bytes or characters. */ + if (!b) + return false; + { + tempPath.ReleaseBuf_CalcLen(bufSize); + FilePath = tempPath; + FilterIndex = (int)p.nFilterIndex - 1; + return true; + } + } +} + +} diff --git a/CPP/Windows/CommonDialog.h b/CPP/Windows/CommonDialog.h index 1e94f133c..85b071f0c 100644 --- a/CPP/Windows/CommonDialog.h +++ b/CPP/Windows/CommonDialog.h @@ -1,43 +1,43 @@ -// Windows/CommonDialog.h - -#ifndef ZIP7_INC_WINDOWS_COMMON_DIALOG_H -#define ZIP7_INC_WINDOWS_COMMON_DIALOG_H - -#include "../Common/MyString.h" - -namespace NWindows { - -struct CCommonDialogInfo -{ - /* (FilterIndex == -1) means no selected filter. - and (-1) also is reserved for unsupported custom filter. - if (FilterIndex >= 0), then FilterIndex is index of filter */ - int FilterIndex; // [in / out] - bool SaveMode; - #ifdef UNDER_CE - bool OpenFolderMode; - #endif - HWND hwndOwner; - // LPCWSTR lpstrInitialDir; - LPCWSTR lpstrTitle; - UString FilePath; // [in / out] - - CCommonDialogInfo() - { - FilterIndex = -1; - SaveMode = false; - #ifdef UNDER_CE - OpenFolderMode = false; - #endif - hwndOwner = NULL; - // lpstrInitialDir = NULL; - lpstrTitle = NULL; - } - - /* (filters) : 2 sequential vector strings (Description, Masks) represent each filter */ - bool CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters); -}; - -} - -#endif +// Windows/CommonDialog.h + +#ifndef ZIP7_INC_WINDOWS_COMMON_DIALOG_H +#define ZIP7_INC_WINDOWS_COMMON_DIALOG_H + +#include "../Common/MyString.h" + +namespace NWindows { + +struct CCommonDialogInfo +{ + /* (FilterIndex == -1) means no selected filter. + and (-1) also is reserved for unsupported custom filter. + if (FilterIndex >= 0), then FilterIndex is index of filter */ + int FilterIndex; // [in / out] + bool SaveMode; + #ifdef UNDER_CE + bool OpenFolderMode; + #endif + HWND hwndOwner; + // LPCWSTR lpstrInitialDir; + LPCWSTR lpstrTitle; + UString FilePath; // [in / out] + + CCommonDialogInfo() + { + FilterIndex = -1; + SaveMode = false; + #ifdef UNDER_CE + OpenFolderMode = false; + #endif + hwndOwner = NULL; + // lpstrInitialDir = NULL; + lpstrTitle = NULL; + } + + /* (filters) : 2 sequential vector strings (Description, Masks) represent each filter */ + bool CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters); +}; + +} + +#endif diff --git a/CPP/Windows/Console.cpp b/CPP/Windows/Console.cpp index cb0c5d9c3..28ba1c47a 100644 --- a/CPP/Windows/Console.cpp +++ b/CPP/Windows/Console.cpp @@ -1,10 +1,10 @@ -// Windows/Console.cpp - -#include "StdAfx.h" - -#include "Console.h" - -namespace NWindows{ -namespace NConsole{ - -}} +// Windows/Console.cpp + +#include "StdAfx.h" + +#include "Console.h" + +namespace NWindows{ +namespace NConsole{ + +}} diff --git a/CPP/Windows/Console.h b/CPP/Windows/Console.h index f6a2399c8..818b8d430 100644 --- a/CPP/Windows/Console.h +++ b/CPP/Windows/Console.h @@ -1,52 +1,52 @@ -// Windows/Console.h - -#ifndef ZIP7_INC_WINDOWS_CONSOLE_H -#define ZIP7_INC_WINDOWS_CONSOLE_H - -#include "Defs.h" - -namespace NWindows { -namespace NConsole { - -class CBase -{ -protected: - HANDLE m_Object; -public: - void Attach(HANDLE handle) { m_Object = handle; } - bool GetMode(DWORD &mode) - { return BOOLToBool(::GetConsoleMode(m_Object, &mode)); } - bool SetMode(DWORD mode) - { return BOOLToBool(::SetConsoleMode(m_Object, mode)); } -}; - -class CIn: public CBase -{ -public: - bool PeekEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead) - { return BOOLToBool(::PeekConsoleInput(m_Object, events, numEvents, &numEventsRead)); } - bool PeekEvent(INPUT_RECORD &event, DWORD &numEventsRead) - { return PeekEvents(&event, 1, numEventsRead); } - bool ReadEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead) - { return BOOLToBool(::ReadConsoleInput(m_Object, events, numEvents, &numEventsRead)); } - bool ReadEvent(INPUT_RECORD &event, DWORD &numEventsRead) - { return ReadEvents(&event, 1, numEventsRead); } - bool GetNumberOfEvents(DWORD &numEvents) - { return BOOLToBool(::GetNumberOfConsoleInputEvents(m_Object, &numEvents)); } - - bool WriteEvents(const INPUT_RECORD *events, DWORD numEvents, DWORD &numEventsWritten) - { return BOOLToBool(::WriteConsoleInput(m_Object, events, numEvents, &numEventsWritten)); } - bool WriteEvent(const INPUT_RECORD &event, DWORD &numEventsWritten) - { return WriteEvents(&event, 1, numEventsWritten); } - - bool Read(LPVOID buffer, DWORD numChars, DWORD &numCharsRead) - { return BOOLToBool(::ReadConsole(m_Object, buffer, numChars, &numCharsRead, NULL)); } - - bool Flush() - { return BOOLToBool(::FlushConsoleInputBuffer(m_Object)); } - -}; - -}} - -#endif +// Windows/Console.h + +#ifndef ZIP7_INC_WINDOWS_CONSOLE_H +#define ZIP7_INC_WINDOWS_CONSOLE_H + +#include "Defs.h" + +namespace NWindows { +namespace NConsole { + +class CBase +{ +protected: + HANDLE m_Object; +public: + void Attach(HANDLE handle) { m_Object = handle; } + bool GetMode(DWORD &mode) + { return BOOLToBool(::GetConsoleMode(m_Object, &mode)); } + bool SetMode(DWORD mode) + { return BOOLToBool(::SetConsoleMode(m_Object, mode)); } +}; + +class CIn: public CBase +{ +public: + bool PeekEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead) + { return BOOLToBool(::PeekConsoleInput(m_Object, events, numEvents, &numEventsRead)); } + bool PeekEvent(INPUT_RECORD &event, DWORD &numEventsRead) + { return PeekEvents(&event, 1, numEventsRead); } + bool ReadEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead) + { return BOOLToBool(::ReadConsoleInput(m_Object, events, numEvents, &numEventsRead)); } + bool ReadEvent(INPUT_RECORD &event, DWORD &numEventsRead) + { return ReadEvents(&event, 1, numEventsRead); } + bool GetNumberOfEvents(DWORD &numEvents) + { return BOOLToBool(::GetNumberOfConsoleInputEvents(m_Object, &numEvents)); } + + bool WriteEvents(const INPUT_RECORD *events, DWORD numEvents, DWORD &numEventsWritten) + { return BOOLToBool(::WriteConsoleInput(m_Object, events, numEvents, &numEventsWritten)); } + bool WriteEvent(const INPUT_RECORD &event, DWORD &numEventsWritten) + { return WriteEvents(&event, 1, numEventsWritten); } + + bool Read(LPVOID buffer, DWORD numChars, DWORD &numCharsRead) + { return BOOLToBool(::ReadConsole(m_Object, buffer, numChars, &numCharsRead, NULL)); } + + bool Flush() + { return BOOLToBool(::FlushConsoleInputBuffer(m_Object)); } + +}; + +}} + +#endif diff --git a/CPP/Windows/Control/ComboBox.cpp b/CPP/Windows/Control/ComboBox.cpp index 36a2df251..8da487d49 100644 --- a/CPP/Windows/Control/ComboBox.cpp +++ b/CPP/Windows/Control/ComboBox.cpp @@ -1,66 +1,66 @@ -// Windows/Control/ComboBox.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../../Common/StringConvert.h" -#endif - -#include "ComboBox.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NControl { - -LRESULT CComboBox::GetLBText(int index, CSysString &s) -{ - s.Empty(); - LRESULT len = GetLBTextLen(index); // length, excluding the terminating null character - if (len == CB_ERR) - return len; - LRESULT len2 = GetLBText(index, s.GetBuf((unsigned)len)); - if (len2 == CB_ERR) - return len; - if (len > len2) - len = len2; - s.ReleaseBuf_CalcLen((unsigned)len); - return len; -} - -#ifndef _UNICODE -LRESULT CComboBox::AddString(LPCWSTR s) -{ - if (g_IsNT) - return SendMsgW(CB_ADDSTRING, 0, (LPARAM)s); - return AddString(GetSystemString(s)); -} - -LRESULT CComboBox::GetLBText(int index, UString &s) -{ - s.Empty(); - if (g_IsNT) - { - LRESULT len = SendMsgW(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0); - if (len == CB_ERR) - return len; - LRESULT len2 = SendMsgW(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s.GetBuf((unsigned)len)); - if (len2 == CB_ERR) - return len; - if (len > len2) - len = len2; - s.ReleaseBuf_CalcLen((unsigned)len); - return len; - } - AString sa; - const LRESULT len = GetLBText(index, sa); - if (len == CB_ERR) - return len; - s = GetUnicodeString(sa); - return (LRESULT)s.Len(); -} -#endif - -}} +// Windows/Control/ComboBox.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../../Common/StringConvert.h" +#endif + +#include "ComboBox.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NControl { + +LRESULT CComboBox::GetLBText(int index, CSysString &s) +{ + s.Empty(); + LRESULT len = GetLBTextLen(index); // length, excluding the terminating null character + if (len == CB_ERR) + return len; + LRESULT len2 = GetLBText(index, s.GetBuf((unsigned)len)); + if (len2 == CB_ERR) + return len; + if (len > len2) + len = len2; + s.ReleaseBuf_CalcLen((unsigned)len); + return len; +} + +#ifndef _UNICODE +LRESULT CComboBox::AddString(LPCWSTR s) +{ + if (g_IsNT) + return SendMsgW(CB_ADDSTRING, 0, (LPARAM)s); + return AddString(GetSystemString(s)); +} + +LRESULT CComboBox::GetLBText(int index, UString &s) +{ + s.Empty(); + if (g_IsNT) + { + LRESULT len = SendMsgW(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0); + if (len == CB_ERR) + return len; + LRESULT len2 = SendMsgW(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s.GetBuf((unsigned)len)); + if (len2 == CB_ERR) + return len; + if (len > len2) + len = len2; + s.ReleaseBuf_CalcLen((unsigned)len); + return len; + } + AString sa; + const LRESULT len = GetLBText(index, sa); + if (len == CB_ERR) + return len; + s = GetUnicodeString(sa); + return (LRESULT)s.Len(); +} +#endif + +}} diff --git a/CPP/Windows/Control/ComboBox.h b/CPP/Windows/Control/ComboBox.h index 535db69d3..2a60b8aac 100644 --- a/CPP/Windows/Control/ComboBox.h +++ b/CPP/Windows/Control/ComboBox.h @@ -1,77 +1,77 @@ -// Windows/Control/ComboBox.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H -#define ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H - -#include "../../Common/MyWindows.h" - -#include - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CComboBox: public CWindow -{ -public: - void ResetContent() { SendMsg(CB_RESETCONTENT, 0, 0); } - LRESULT AddString(LPCTSTR s) { return SendMsg(CB_ADDSTRING, 0, (LPARAM)s); } - #ifndef _UNICODE - LRESULT AddString(LPCWSTR s); - #endif - - /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/ - LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY_int_TO_WPARAM(index), 0); } - LRESULT SetCurSel(unsigned index) { return SendMsg(CB_SETCURSEL, index, 0); } - - /* If no item is selected, it returns CB_ERR (-1) */ - int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); } - - /* If an error occurs, it is CB_ERR (-1) */ - int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); } - - LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0); } - LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s); } - LRESULT GetLBText(int index, CSysString &s); - #ifndef _UNICODE - LRESULT GetLBText(int index, UString &s); - #endif - - LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, MY_int_TO_WPARAM(index), lParam); } - LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, MY_int_TO_WPARAM(index), 0); } - LRESULT GetItemData(unsigned index) { return SendMsg(CB_GETITEMDATA, index, 0); } - - LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); } - - void ShowDropDown(bool show = true) { SendMsg(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); } -}; - -#ifndef UNDER_CE - -class CComboBoxEx: public CComboBox -{ -public: - bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); } - - /* Returns: - an INT value that represents the number of items remaining in the control. - If (index) is invalid, the message returns CB_ERR. */ - LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, MY_int_TO_WPARAM(index), 0); } - - LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); } - #ifndef _UNICODE - LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); } - #endif - - LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_SETITEM, 0, (LPARAM)item); } - DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMsg(CBEM_SETEXTENDEDSTYLE, exMask, (LPARAM)exStyle); } - HWND GetEditControl() { return (HWND)SendMsg(CBEM_GETEDITCONTROL, 0, 0); } - HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMsg(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); } -}; - -#endif - -}} - -#endif +// Windows/Control/ComboBox.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H +#define ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H + +#include "../../Common/MyWindows.h" + +#include + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CComboBox: public CWindow +{ +public: + void ResetContent() { SendMsg(CB_RESETCONTENT, 0, 0); } + LRESULT AddString(LPCTSTR s) { return SendMsg(CB_ADDSTRING, 0, (LPARAM)s); } + #ifndef _UNICODE + LRESULT AddString(LPCWSTR s); + #endif + + /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/ + LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY_int_TO_WPARAM(index), 0); } + LRESULT SetCurSel(unsigned index) { return SendMsg(CB_SETCURSEL, index, 0); } + + /* If no item is selected, it returns CB_ERR (-1) */ + int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); } + + /* If an error occurs, it is CB_ERR (-1) */ + int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); } + + LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0); } + LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s); } + LRESULT GetLBText(int index, CSysString &s); + #ifndef _UNICODE + LRESULT GetLBText(int index, UString &s); + #endif + + LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, MY_int_TO_WPARAM(index), lParam); } + LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, MY_int_TO_WPARAM(index), 0); } + LRESULT GetItemData(unsigned index) { return SendMsg(CB_GETITEMDATA, index, 0); } + + LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); } + + void ShowDropDown(bool show = true) { SendMsg(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); } +}; + +#ifndef UNDER_CE + +class CComboBoxEx: public CComboBox +{ +public: + bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); } + + /* Returns: + an INT value that represents the number of items remaining in the control. + If (index) is invalid, the message returns CB_ERR. */ + LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, MY_int_TO_WPARAM(index), 0); } + + LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); } + #ifndef _UNICODE + LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); } + #endif + + LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_SETITEM, 0, (LPARAM)item); } + DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMsg(CBEM_SETEXTENDEDSTYLE, exMask, (LPARAM)exStyle); } + HWND GetEditControl() { return (HWND)SendMsg(CBEM_GETEDITCONTROL, 0, 0); } + HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMsg(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); } +}; + +#endif + +}} + +#endif diff --git a/CPP/Windows/Control/CommandBar.h b/CPP/Windows/Control/CommandBar.h index d69ac5dbe..d1b2f1786 100644 --- a/CPP/Windows/Control/CommandBar.h +++ b/CPP/Windows/Control/CommandBar.h @@ -1,52 +1,52 @@ -// Windows/Control/CommandBar.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H -#define ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H - -#ifdef UNDER_CE - -#include "../../Common/MyWindows.h" - -#include - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CCommandBar: public NWindows::CWindow -{ -public: - bool Create(HINSTANCE hInst, HWND hwndParent, int idCmdBar) - { - _window = ::CommandBar_Create(hInst, hwndParent, idCmdBar); - return (_window != NULL); - } - - // Macros - // void Destroy() { CommandBar_Destroy(_window); } - // bool AddButtons(UINT numButtons, LPTBBUTTON buttons) { return BOOLToBool(SendMsg(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); } - // bool InsertButton(unsigned iButton, LPTBBUTTON button) { return BOOLToBool(SendMsg(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); } - // BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMsg(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); } - void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); } - - // bool AddAdornments(DWORD dwFlags) { return BOOLToBool(::CommandBar_AddAdornments(_window, dwFlags, 0)); } - // int AddBitmap(HINSTANCE hInst, int idBitmap, int iNumImages, int iImageWidth, int iImageHeight) { return ::CommandBar_AddBitmap(_window, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight); } - bool DrawMenuBar(WORD iButton) { return BOOLToBool(::CommandBar_DrawMenuBar(_window, iButton)); } - HMENU GetMenu(WORD iButton) { return ::CommandBar_GetMenu(_window, iButton); } - int Height() { return CommandBar_Height(_window); } - HWND InsertComboBox(HINSTANCE hInst, int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton) { return ::CommandBar_InsertComboBox(_window, hInst, iWidth, dwStyle, idComboBox, iButton); } - bool InsertMenubar(HINSTANCE hInst, WORD idMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubar(_window, hInst, idMenu, iButton)); } - bool InsertMenubarEx(HINSTANCE hInst, LPTSTR pszMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubarEx(_window, hInst, pszMenu, iButton)); } - bool Show(bool cmdShow) { return BOOLToBool(::CommandBar_Show(_window, BoolToBOOL(cmdShow))); } - - - // CE 4.0 - void AlignAdornments() { CommandBar_AlignAdornments(_window); } -}; - -}} - -#endif - -#endif +// Windows/Control/CommandBar.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H +#define ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H + +#ifdef UNDER_CE + +#include "../../Common/MyWindows.h" + +#include + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CCommandBar: public NWindows::CWindow +{ +public: + bool Create(HINSTANCE hInst, HWND hwndParent, int idCmdBar) + { + _window = ::CommandBar_Create(hInst, hwndParent, idCmdBar); + return (_window != NULL); + } + + // Macros + // void Destroy() { CommandBar_Destroy(_window); } + // bool AddButtons(UINT numButtons, LPTBBUTTON buttons) { return BOOLToBool(SendMsg(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); } + // bool InsertButton(unsigned iButton, LPTBBUTTON button) { return BOOLToBool(SendMsg(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); } + // BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMsg(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); } + void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); } + + // bool AddAdornments(DWORD dwFlags) { return BOOLToBool(::CommandBar_AddAdornments(_window, dwFlags, 0)); } + // int AddBitmap(HINSTANCE hInst, int idBitmap, int iNumImages, int iImageWidth, int iImageHeight) { return ::CommandBar_AddBitmap(_window, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight); } + bool DrawMenuBar(WORD iButton) { return BOOLToBool(::CommandBar_DrawMenuBar(_window, iButton)); } + HMENU GetMenu(WORD iButton) { return ::CommandBar_GetMenu(_window, iButton); } + int Height() { return CommandBar_Height(_window); } + HWND InsertComboBox(HINSTANCE hInst, int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton) { return ::CommandBar_InsertComboBox(_window, hInst, iWidth, dwStyle, idComboBox, iButton); } + bool InsertMenubar(HINSTANCE hInst, WORD idMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubar(_window, hInst, idMenu, iButton)); } + bool InsertMenubarEx(HINSTANCE hInst, LPTSTR pszMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubarEx(_window, hInst, pszMenu, iButton)); } + bool Show(bool cmdShow) { return BOOLToBool(::CommandBar_Show(_window, BoolToBOOL(cmdShow))); } + + + // CE 4.0 + void AlignAdornments() { CommandBar_AlignAdornments(_window); } +}; + +}} + +#endif + +#endif diff --git a/CPP/Windows/Control/Dialog.cpp b/CPP/Windows/Control/Dialog.cpp index 547d50ab8..cbb000bb2 100644 --- a/CPP/Windows/Control/Dialog.cpp +++ b/CPP/Windows/Control/Dialog.cpp @@ -1,446 +1,446 @@ -// Windows/Control/Dialog.cpp - -#include "StdAfx.h" - -// #include "../../Windows/DLL.h" - -#ifndef _UNICODE -#include "../../Common/StringConvert.h" -#endif - -#include "Dialog.h" - -extern HINSTANCE g_hInstance; -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NControl { - -static -#ifdef Z7_OLD_WIN_SDK - BOOL -#else - INT_PTR -#endif -APIENTRY -DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) -{ - CWindow tempDialog(dialogHWND); - if (message == WM_INITDIALOG) - tempDialog.SetUserDataLongPtr(lParam); - CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr()); - if (dialog == NULL) - return FALSE; - if (message == WM_INITDIALOG) - dialog->Attach(dialogHWND); - - /* MSDN: The dialog box procedure should return - TRUE - if it processed the message - FALSE - if it did not process the message - If the dialog box procedure returns FALSE, - the dialog manager performs the default dialog operation in response to the message. - */ - - try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } - catch(...) { return TRUE; } -} - -bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: return OnInit(); - case WM_COMMAND: return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); - case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam); - case WM_TIMER: return OnTimer(wParam, lParam); - case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); - case WM_DESTROY: return OnDestroy(); - case WM_HELP: OnHelp(); return true; - /* - OnHelp( - #ifdef UNDER_CE - (void *) - #else - (LPHELPINFO) - #endif - lParam); - return true; - */ - default: return false; - } -} - -/* -bool CDialog::OnCommand2(WPARAM wParam, LPARAM lParam) -{ - return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); -} -*/ - -bool CDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) -{ - if (code == BN_CLICKED) - return OnButtonClicked(itemID, (HWND)lParam); - return false; -} - -bool CDialog::OnButtonClicked(unsigned buttonID, HWND /* buttonHWND */) -{ - switch (buttonID) - { - case IDOK: OnOK(); break; - case IDCANCEL: OnCancel(); break; - case IDCLOSE: OnClose(); break; - case IDCONTINUE: OnContinue(); break; - case IDHELP: OnHelp(); break; - default: return false; - } - return true; -} - -#ifndef UNDER_CE -/* in win2000/win98 : monitor functions are supported. - We need dynamic linking, if we want nt4/win95 support in program. - Even if we compile the code with low (WINVER) value, we still - want to use monitor functions. So we declare missing functions here */ -// #if (WINVER < 0x0500) -#ifndef MONITOR_DEFAULTTOPRIMARY -extern "C" { -DECLARE_HANDLE(HMONITOR); -#define MONITOR_DEFAULTTOPRIMARY 0x00000001 -typedef struct tagMONITORINFO -{ - DWORD cbSize; - RECT rcMonitor; - RECT rcWork; - DWORD dwFlags; -} MONITORINFO, *LPMONITORINFO; -WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd, DWORD dwFlags); -WINUSERAPI BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi); -} -#endif -#endif - -static bool GetWorkAreaRect(RECT *rect, HWND hwnd) -{ - if (hwnd) - { - #ifndef UNDER_CE - /* MonitorFromWindow() is supported in Win2000+ - MonitorFromWindow() : retrieves a handle to the display monitor that has the - largest area of intersection with the bounding rectangle of a specified window. - dwFlags: Determines the function's return value if the window does not intersect any display monitor. - MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window. - MONITOR_DEFAULTTONULL : Returns NULL. - MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor. - */ - const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); - if (hmon) - { - MONITORINFO mi; - memset(&mi, 0, sizeof(mi)); - mi.cbSize = sizeof(mi); - if (GetMonitorInfoA(hmon, &mi)) - { - *rect = mi.rcWork; - return true; - } - } - #endif - } - - /* Retrieves the size of the work area on the primary display monitor. - The work area is the portion of the screen not obscured - by the system taskbar or by application desktop toolbars. - Any DPI virtualization mode of the caller has no effect on this output. */ - - return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0)); -} - - -bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd) -{ - // it returns for system font. Real font uses another values - const LONG v = GetDialogBaseUnits(); - const int x = LOWORD(v); - const int y = HIWORD(v); - - RECT rect; - GetWorkAreaRect(&rect, hwnd); - const int wx = RECT_SIZE_X(rect); - const int wy = RECT_SIZE_Y(rect); - return - xSize / 4 * x <= wx && - ySize / 8 * y <= wy; -} - -bool CDialog::GetMargins(int margin, int &x, int &y) -{ - x = margin; - y = margin; - RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = margin; - rect.bottom = margin; - if (!MapRect(&rect)) - return false; - x = rect.right - rect.left; - y = rect.bottom - rect.top; - return true; -} - -int CDialog::Units_To_Pixels_X(int units) -{ - RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = units; - rect.bottom = units; - if (!MapRect(&rect)) - return units * 3 / 2; - return rect.right - rect.left; -} - -bool CDialog::GetItemSizes(unsigned id, int &x, int &y) -{ - RECT rect; - if (!::GetWindowRect(GetItem(id), &rect)) - return false; - x = RECT_SIZE_X(rect); - y = RECT_SIZE_Y(rect); - return true; -} - -void CDialog::GetClientRectOfItem(unsigned id, RECT &rect) -{ - ::GetWindowRect(GetItem(id), &rect); - ScreenToClient(&rect); -} - -bool CDialog::MoveItem(unsigned id, int x, int y, int width, int height, bool repaint) -{ - return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint))); -} - - -/* -typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)( - HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); - -static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect) -{ - // dll load and free is too slow : 300 calls in second. - NDLL::CLibrary dll; - if (!dll.Load(FTEXT("dwmapi.dll"))) - return false; - Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" ); - if (f) - { - #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9 - // 30000 per second - RECT r; - if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK) - { - *rect = r; - return true; - } - } - return false; -} -*/ - - -static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big) -{ - return sm.left >= big.left - && sm.right <= big.right - && sm.top >= big.top - && sm.bottom <= big.bottom; -} - - -static bool AreRectsOverlapped(const RECT &r1, const RECT &r2) -{ - return r1.left < r2.right - && r1.right > r2.left - && r1.top < r2.bottom - && r1.bottom > r2.top; -} - - -static bool AreRectsEqual(const RECT &r1, const RECT &r2) -{ - return r1.left == r2.left - && r1.right == r2.right - && r1.top == r2.top - && r1.bottom == r2.bottom; -} - - -void CDialog::NormalizeSize(bool fullNormalize) -{ - RECT workRect; - if (!GetWorkAreaRect(&workRect, *this)) - return; - RECT rect; - if (!GetWindowRect(&rect)) - return; - int xs = RECT_SIZE_X(rect); - int ys = RECT_SIZE_Y(rect); - - // we don't want to change size using workRect, if window is outside of WorkArea - if (!AreRectsOverlapped(rect, workRect)) - return; - - /* here rect and workRect are overlapped, but it can be false - overlapping of small shadow when window in another display. */ - - const int xsW = RECT_SIZE_X(workRect); - const int ysW = RECT_SIZE_Y(workRect); - if (xs <= xsW && ys <= ysW) - return; // size of window is OK - if (fullNormalize) - { - Show(SW_SHOWMAXIMIZED); - return; - } - int x = workRect.left; - int y = workRect.top; - if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW; - if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW; - Move(x, y, xs, ys, true); -} - - -void CDialog::NormalizePosition() -{ - RECT workRect; - if (!GetWorkAreaRect(&workRect, *this)) - return; - - RECT rect2 = workRect; - bool useWorkArea = true; - const HWND parentHWND = GetParent(); - - if (parentHWND) - { - RECT workRectParent; - if (!GetWorkAreaRect(&workRectParent, parentHWND)) - return; - - // if windows are in different monitors, we use only workArea of current window - - if (AreRectsEqual(workRectParent, workRect)) - { - // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {} - CWindow wnd(parentHWND); - if (wnd.GetWindowRect(&rect2)) - { - // it's same monitor. So we try to use parentHWND rect. - /* we don't want to change position, if parent window is not inside work area. - In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow. - In maximize mode : window is outside of workRect. - if parent window is inside workRect, we will use parent window instead of workRect */ - if (IsRect_Small_Inside_Big(rect2, workRect)) - useWorkArea = false; - } - } - } - - RECT rect; - if (!GetWindowRect(&rect)) - return; - - if (useWorkArea) - { - // we don't want to move window, if it's already inside. - if (IsRect_Small_Inside_Big(rect, workRect)) - return; - // we don't want to move window, if it's outside of workArea - if (!AreRectsOverlapped(rect, workRect)) - return; - rect2 = workRect; - } - - { - const int xs = RECT_SIZE_X(rect); - const int ys = RECT_SIZE_Y(rect); - const int xs2 = RECT_SIZE_X(rect2); - const int ys2 = RECT_SIZE_Y(rect2); - // we don't want to change position if parent is smaller. - if (xs <= xs2 && ys <= ys2) - { - const int x = rect2.left + (xs2 - xs) / 2; - const int y = rect2.top + (ys2 - ys) / 2; - - if (x != rect.left || y != rect.top) - Move(x, y, xs, ys, true); - // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); - return; - } - } -} - - - -bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow) -{ - const HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); - if (!aHWND) - return false; - Attach(aHWND); - return true; -} - -INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow) -{ - return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); -} - -#ifndef _UNICODE - -bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow) -{ - HWND aHWND; - if (g_IsNT) - aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); - else - { - AString name; - LPCSTR templateNameA; - if (IS_INTRESOURCE(templateName)) - templateNameA = (LPCSTR)templateName; - else - { - name = GetSystemString(templateName); - templateNameA = name; - } - aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); - } - if (aHWND == 0) - return false; - Attach(aHWND); - return true; -} - -INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow) -{ - if (g_IsNT) - return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); - AString name; - LPCSTR templateNameA; - if (IS_INTRESOURCE(templateName)) - templateNameA = (LPCSTR)templateName; - else - { - name = GetSystemString(templateName); - templateNameA = name; - } - return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); -} -#endif - -}} +// Windows/Control/Dialog.cpp + +#include "StdAfx.h" + +// #include "../../Windows/DLL.h" + +#ifndef _UNICODE +#include "../../Common/StringConvert.h" +#endif + +#include "Dialog.h" + +extern HINSTANCE g_hInstance; +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NControl { + +static +#ifdef Z7_OLD_WIN_SDK + BOOL +#else + INT_PTR +#endif +APIENTRY +DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) +{ + CWindow tempDialog(dialogHWND); + if (message == WM_INITDIALOG) + tempDialog.SetUserDataLongPtr(lParam); + CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr()); + if (dialog == NULL) + return FALSE; + if (message == WM_INITDIALOG) + dialog->Attach(dialogHWND); + + /* MSDN: The dialog box procedure should return + TRUE - if it processed the message + FALSE - if it did not process the message + If the dialog box procedure returns FALSE, + the dialog manager performs the default dialog operation in response to the message. + */ + + try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } + catch(...) { return TRUE; } +} + +bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: return OnInit(); + case WM_COMMAND: return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); + case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam); + case WM_TIMER: return OnTimer(wParam, lParam); + case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); + case WM_DESTROY: return OnDestroy(); + case WM_HELP: OnHelp(); return true; + /* + OnHelp( + #ifdef UNDER_CE + (void *) + #else + (LPHELPINFO) + #endif + lParam); + return true; + */ + default: return false; + } +} + +/* +bool CDialog::OnCommand2(WPARAM wParam, LPARAM lParam) +{ + return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); +} +*/ + +bool CDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) +{ + if (code == BN_CLICKED) + return OnButtonClicked(itemID, (HWND)lParam); + return false; +} + +bool CDialog::OnButtonClicked(unsigned buttonID, HWND /* buttonHWND */) +{ + switch (buttonID) + { + case IDOK: OnOK(); break; + case IDCANCEL: OnCancel(); break; + case IDCLOSE: OnClose(); break; + case IDCONTINUE: OnContinue(); break; + case IDHELP: OnHelp(); break; + default: return false; + } + return true; +} + +#ifndef UNDER_CE +/* in win2000/win98 : monitor functions are supported. + We need dynamic linking, if we want nt4/win95 support in program. + Even if we compile the code with low (WINVER) value, we still + want to use monitor functions. So we declare missing functions here */ +// #if (WINVER < 0x0500) +#ifndef MONITOR_DEFAULTTOPRIMARY +extern "C" { +DECLARE_HANDLE(HMONITOR); +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +typedef struct tagMONITORINFO +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; +WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd, DWORD dwFlags); +WINUSERAPI BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi); +} +#endif +#endif + +static bool GetWorkAreaRect(RECT *rect, HWND hwnd) +{ + if (hwnd) + { + #ifndef UNDER_CE + /* MonitorFromWindow() is supported in Win2000+ + MonitorFromWindow() : retrieves a handle to the display monitor that has the + largest area of intersection with the bounding rectangle of a specified window. + dwFlags: Determines the function's return value if the window does not intersect any display monitor. + MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window. + MONITOR_DEFAULTTONULL : Returns NULL. + MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor. + */ + const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + if (hmon) + { + MONITORINFO mi; + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + if (GetMonitorInfoA(hmon, &mi)) + { + *rect = mi.rcWork; + return true; + } + } + #endif + } + + /* Retrieves the size of the work area on the primary display monitor. + The work area is the portion of the screen not obscured + by the system taskbar or by application desktop toolbars. + Any DPI virtualization mode of the caller has no effect on this output. */ + + return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0)); +} + + +bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd) +{ + // it returns for system font. Real font uses another values + const LONG v = GetDialogBaseUnits(); + const int x = LOWORD(v); + const int y = HIWORD(v); + + RECT rect; + GetWorkAreaRect(&rect, hwnd); + const int wx = RECT_SIZE_X(rect); + const int wy = RECT_SIZE_Y(rect); + return + xSize / 4 * x <= wx && + ySize / 8 * y <= wy; +} + +bool CDialog::GetMargins(int margin, int &x, int &y) +{ + x = margin; + y = margin; + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = margin; + rect.bottom = margin; + if (!MapRect(&rect)) + return false; + x = rect.right - rect.left; + y = rect.bottom - rect.top; + return true; +} + +int CDialog::Units_To_Pixels_X(int units) +{ + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = units; + rect.bottom = units; + if (!MapRect(&rect)) + return units * 3 / 2; + return rect.right - rect.left; +} + +bool CDialog::GetItemSizes(unsigned id, int &x, int &y) +{ + RECT rect; + if (!::GetWindowRect(GetItem(id), &rect)) + return false; + x = RECT_SIZE_X(rect); + y = RECT_SIZE_Y(rect); + return true; +} + +void CDialog::GetClientRectOfItem(unsigned id, RECT &rect) +{ + ::GetWindowRect(GetItem(id), &rect); + ScreenToClient(&rect); +} + +bool CDialog::MoveItem(unsigned id, int x, int y, int width, int height, bool repaint) +{ + return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint))); +} + + +/* +typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)( + HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); + +static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect) +{ + // dll load and free is too slow : 300 calls in second. + NDLL::CLibrary dll; + if (!dll.Load(FTEXT("dwmapi.dll"))) + return false; + Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" ); + if (f) + { + #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9 + // 30000 per second + RECT r; + if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK) + { + *rect = r; + return true; + } + } + return false; +} +*/ + + +static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big) +{ + return sm.left >= big.left + && sm.right <= big.right + && sm.top >= big.top + && sm.bottom <= big.bottom; +} + + +static bool AreRectsOverlapped(const RECT &r1, const RECT &r2) +{ + return r1.left < r2.right + && r1.right > r2.left + && r1.top < r2.bottom + && r1.bottom > r2.top; +} + + +static bool AreRectsEqual(const RECT &r1, const RECT &r2) +{ + return r1.left == r2.left + && r1.right == r2.right + && r1.top == r2.top + && r1.bottom == r2.bottom; +} + + +void CDialog::NormalizeSize(bool fullNormalize) +{ + RECT workRect; + if (!GetWorkAreaRect(&workRect, *this)) + return; + RECT rect; + if (!GetWindowRect(&rect)) + return; + int xs = RECT_SIZE_X(rect); + int ys = RECT_SIZE_Y(rect); + + // we don't want to change size using workRect, if window is outside of WorkArea + if (!AreRectsOverlapped(rect, workRect)) + return; + + /* here rect and workRect are overlapped, but it can be false + overlapping of small shadow when window in another display. */ + + const int xsW = RECT_SIZE_X(workRect); + const int ysW = RECT_SIZE_Y(workRect); + if (xs <= xsW && ys <= ysW) + return; // size of window is OK + if (fullNormalize) + { + Show(SW_SHOWMAXIMIZED); + return; + } + int x = workRect.left; + int y = workRect.top; + if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW; + if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW; + Move(x, y, xs, ys, true); +} + + +void CDialog::NormalizePosition() +{ + RECT workRect; + if (!GetWorkAreaRect(&workRect, *this)) + return; + + RECT rect2 = workRect; + bool useWorkArea = true; + const HWND parentHWND = GetParent(); + + if (parentHWND) + { + RECT workRectParent; + if (!GetWorkAreaRect(&workRectParent, parentHWND)) + return; + + // if windows are in different monitors, we use only workArea of current window + + if (AreRectsEqual(workRectParent, workRect)) + { + // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {} + CWindow wnd(parentHWND); + if (wnd.GetWindowRect(&rect2)) + { + // it's same monitor. So we try to use parentHWND rect. + /* we don't want to change position, if parent window is not inside work area. + In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow. + In maximize mode : window is outside of workRect. + if parent window is inside workRect, we will use parent window instead of workRect */ + if (IsRect_Small_Inside_Big(rect2, workRect)) + useWorkArea = false; + } + } + } + + RECT rect; + if (!GetWindowRect(&rect)) + return; + + if (useWorkArea) + { + // we don't want to move window, if it's already inside. + if (IsRect_Small_Inside_Big(rect, workRect)) + return; + // we don't want to move window, if it's outside of workArea + if (!AreRectsOverlapped(rect, workRect)) + return; + rect2 = workRect; + } + + { + const int xs = RECT_SIZE_X(rect); + const int ys = RECT_SIZE_Y(rect); + const int xs2 = RECT_SIZE_X(rect2); + const int ys2 = RECT_SIZE_Y(rect2); + // we don't want to change position if parent is smaller. + if (xs <= xs2 && ys <= ys2) + { + const int x = rect2.left + (xs2 - xs) / 2; + const int y = rect2.top + (ys2 - ys) / 2; + + if (x != rect.left || y != rect.top) + Move(x, y, xs, ys, true); + // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); + return; + } + } +} + + + +bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow) +{ + const HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + if (!aHWND) + return false; + Attach(aHWND); + return true; +} + +INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow) +{ + return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); +} + +#ifndef _UNICODE + +bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow) +{ + HWND aHWND; + if (g_IsNT) + aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + else + { + AString name; + LPCSTR templateNameA; + if (IS_INTRESOURCE(templateName)) + templateNameA = (LPCSTR)templateName; + else + { + name = GetSystemString(templateName); + templateNameA = name; + } + aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); + } + if (aHWND == 0) + return false; + Attach(aHWND); + return true; +} + +INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow) +{ + if (g_IsNT) + return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + AString name; + LPCSTR templateNameA; + if (IS_INTRESOURCE(templateName)) + templateNameA = (LPCSTR)templateName; + else + { + name = GetSystemString(templateName); + templateNameA = name; + } + return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); +} +#endif + +}} diff --git a/CPP/Windows/Control/Dialog.h b/CPP/Windows/Control/Dialog.h index bafbf4f75..2510c8f15 100644 --- a/CPP/Windows/Control/Dialog.h +++ b/CPP/Windows/Control/Dialog.h @@ -1,213 +1,213 @@ -// Windows/Control/Dialog.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_DIALOG_H -#define ZIP7_INC_WINDOWS_CONTROL_DIALOG_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -#ifndef IDCONTINUE -#define IDCONTINUE 11 -#endif - -class CDialog: public CWindow -{ - // Z7_CLASS_NO_COPY(CDialog) -public: - CDialog(HWND wnd = NULL): CWindow(wnd) {} - virtual ~CDialog() {} - - HWND GetItem(unsigned itemID) const - { return GetDlgItem(_window, (int)itemID); } - - bool EnableItem(unsigned itemID, bool enable) const - { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); } - - bool ShowItem(unsigned itemID, int cmdShow) const - { return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); } - - bool ShowItem_Bool(unsigned itemID, bool show) const - { return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); } - - bool HideItem(unsigned itemID) const { return ShowItem(itemID, SW_HIDE); } - - bool SetItemText(unsigned itemID, LPCTSTR s) - { return BOOLToBool(SetDlgItemText(_window, (int)itemID, s)); } - - bool SetItemTextA(unsigned itemID, LPCSTR s) - { return BOOLToBool(SetDlgItemTextA(_window, (int)itemID, s)); } - - bool SetItemText_Empty(unsigned itemID) - { return SetItemText(itemID, TEXT("")); } - - #ifndef _UNICODE - bool SetItemText(unsigned itemID, LPCWSTR s) - { - CWindow window(GetItem(itemID)); - return window.SetText(s); - } - #endif - - UINT GetItemText(unsigned itemID, LPTSTR string, unsigned maxCount) - { return GetDlgItemText(_window, (int)itemID, string, (int)maxCount); } - #ifndef _UNICODE - /* - bool GetItemText(unsigned itemID, LPWSTR string, int maxCount) - { - CWindow window(GetItem(unsigned)); - return window.GetText(string, maxCount); - } - */ - #endif - - bool GetItemText(unsigned itemID, UString &s) - { - CWindow window(GetItem(itemID)); - return window.GetText(s); - } - -/* - bool SetItemInt(unsigned itemID, UINT value, bool isSigned) - { return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, BoolToBOOL(isSigned))); } -*/ - bool SetItemUInt(unsigned itemID, UINT value) - { return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, FALSE)); } -/* - bool GetItemInt(unsigned itemID, bool isSigned, UINT &value) - { - BOOL result; - value = GetDlgItemInt(_window, (int)itemID, &result, BoolToBOOL(isSigned)); - return BOOLToBool(result); - } -*/ - bool GetItemUInt(unsigned itemID, UINT &value) - { - BOOL result; - value = GetDlgItemInt(_window, (int)itemID, &result, FALSE); - return BOOLToBool(result); - } - - HWND GetNextGroupItem(HWND control, bool previous) - { return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); } - HWND GetNextTabItem(HWND control, bool previous) - { return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); } - - LRESULT SendMsg_NextDlgCtl(WPARAM wParam, LPARAM lParam) - { return SendMsg(WM_NEXTDLGCTL, wParam, lParam); } - LRESULT SendMsg_NextDlgCtl_HWND(HWND hwnd) { return SendMsg_NextDlgCtl((WPARAM)hwnd, TRUE); } - LRESULT SendMsg_NextDlgCtl_CtlId(unsigned id) { return SendMsg_NextDlgCtl_HWND(GetItem(id)); } - LRESULT SendMsg_NextDlgCtl_Next() { return SendMsg_NextDlgCtl(0, FALSE); } - LRESULT SendMsg_NextDlgCtl_Prev() { return SendMsg_NextDlgCtl(1, FALSE); } - - bool MapRect(LPRECT rect) - { return BOOLToBool(MapDialogRect(_window, rect)); } - - bool IsMessage(LPMSG message) - { return BOOLToBool(IsDialogMessage(_window, message)); } - - LRESULT SendItemMessage(unsigned itemID, UINT message, WPARAM wParam, LPARAM lParam) - { return SendDlgItemMessage(_window, (int)itemID, message, wParam, lParam); } - - bool CheckButton(unsigned buttonID, UINT checkState) - { return BOOLToBool(CheckDlgButton(_window, (int)buttonID, checkState)); } - bool CheckButton(unsigned buttonID, bool checkState) - { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); } - - UINT IsButtonChecked_BST(unsigned buttonID) const - { return IsDlgButtonChecked(_window, (int)buttonID); } - bool IsButtonCheckedBool(unsigned buttonID) const - { return (IsButtonChecked_BST(buttonID) == BST_CHECKED); } - - bool CheckRadioButton(unsigned firstButtonID, unsigned lastButtonID, unsigned checkButtonID) - { return BOOLToBool(::CheckRadioButton(_window, - (int)firstButtonID, (int)lastButtonID, (int)checkButtonID)); } - - virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam); - virtual bool OnInit() { return true; } - // virtual bool OnCommand2(WPARAM wParam, LPARAM lParam); - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam); - virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; } - virtual bool OnDestroy() { return false; } - - /* - #ifdef UNDER_CE - virtual void OnHelp(void *) { OnHelp(); } - #else - virtual void OnHelp(LPHELPINFO) { OnHelp(); } - #endif - */ - virtual void OnHelp() {} - - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND); - virtual void OnOK() {} - virtual void OnContinue() {} - virtual void OnCancel() {} - virtual void OnClose() {} - virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */) { return false; } - virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; } - - LONG_PTR SetMsgResult(LONG_PTR newLongPtr ) - { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } - LONG_PTR GetMsgResult() const - { return GetLongPtr(DWLP_MSGRESULT); } - - bool GetMargins(int margin, int &x, int &y); - int Units_To_Pixels_X(int units); - bool GetItemSizes(unsigned id, int &x, int &y); - void GetClientRectOfItem(unsigned id, RECT &rect); - bool MoveItem(unsigned id, int x, int y, int width, int height, bool repaint = true); - bool MoveItem_RECT(unsigned id, const RECT &r, bool repaint = true) - { return MoveItem(id, r.left, r.top, RECT_SIZE_X(r), RECT_SIZE_Y(r), repaint); } - - void NormalizeSize(bool fullNormalize = false); - void NormalizePosition(); -}; - -class CModelessDialog: public CDialog -{ -public: - bool Create(LPCTSTR templateName, HWND parentWindow); - bool Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); } - #ifndef _UNICODE - bool Create(LPCWSTR templateName, HWND parentWindow); - #endif - virtual void OnOK() Z7_override { Destroy(); } - virtual void OnContinue() Z7_override { Destroy(); } - virtual void OnCancel() Z7_override { Destroy(); } - virtual void OnClose() Z7_override { Destroy(); } -}; - -class CModalDialog: public CDialog -{ -public: - INT_PTR Create(LPCTSTR templateName, HWND parentWindow); - INT_PTR Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); } - #ifndef _UNICODE - INT_PTR Create(LPCWSTR templateName, HWND parentWindow); - #endif - - bool End(INT_PTR result) { return BOOLToBool(::EndDialog(_window, result)); } - virtual void OnOK() Z7_override { End(IDOK); } - virtual void OnContinue() Z7_override { End(IDCONTINUE); } - virtual void OnCancel() Z7_override { End(IDCANCEL); } - virtual void OnClose() Z7_override { End(IDCLOSE); } -}; - -class CDialogChildControl: public NWindows::CWindow -{ - // unsigned m_ID; -public: - void Init(const NWindows::NControl::CDialog &parentDialog, unsigned id) - { - // m_ID = id; - Attach(parentDialog.GetItem(id)); - } -}; - -bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd = NULL); - -}} - -#endif +// Windows/Control/Dialog.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_DIALOG_H +#define ZIP7_INC_WINDOWS_CONTROL_DIALOG_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +#ifndef IDCONTINUE +#define IDCONTINUE 11 +#endif + +class CDialog: public CWindow +{ + // Z7_CLASS_NO_COPY(CDialog) +public: + CDialog(HWND wnd = NULL): CWindow(wnd) {} + virtual ~CDialog() {} + + HWND GetItem(unsigned itemID) const + { return GetDlgItem(_window, (int)itemID); } + + bool EnableItem(unsigned itemID, bool enable) const + { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); } + + bool ShowItem(unsigned itemID, int cmdShow) const + { return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); } + + bool ShowItem_Bool(unsigned itemID, bool show) const + { return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); } + + bool HideItem(unsigned itemID) const { return ShowItem(itemID, SW_HIDE); } + + bool SetItemText(unsigned itemID, LPCTSTR s) + { return BOOLToBool(SetDlgItemText(_window, (int)itemID, s)); } + + bool SetItemTextA(unsigned itemID, LPCSTR s) + { return BOOLToBool(SetDlgItemTextA(_window, (int)itemID, s)); } + + bool SetItemText_Empty(unsigned itemID) + { return SetItemText(itemID, TEXT("")); } + + #ifndef _UNICODE + bool SetItemText(unsigned itemID, LPCWSTR s) + { + CWindow window(GetItem(itemID)); + return window.SetText(s); + } + #endif + + UINT GetItemText(unsigned itemID, LPTSTR string, unsigned maxCount) + { return GetDlgItemText(_window, (int)itemID, string, (int)maxCount); } + #ifndef _UNICODE + /* + bool GetItemText(unsigned itemID, LPWSTR string, int maxCount) + { + CWindow window(GetItem(unsigned)); + return window.GetText(string, maxCount); + } + */ + #endif + + bool GetItemText(unsigned itemID, UString &s) + { + CWindow window(GetItem(itemID)); + return window.GetText(s); + } + +/* + bool SetItemInt(unsigned itemID, UINT value, bool isSigned) + { return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, BoolToBOOL(isSigned))); } +*/ + bool SetItemUInt(unsigned itemID, UINT value) + { return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, FALSE)); } +/* + bool GetItemInt(unsigned itemID, bool isSigned, UINT &value) + { + BOOL result; + value = GetDlgItemInt(_window, (int)itemID, &result, BoolToBOOL(isSigned)); + return BOOLToBool(result); + } +*/ + bool GetItemUInt(unsigned itemID, UINT &value) + { + BOOL result; + value = GetDlgItemInt(_window, (int)itemID, &result, FALSE); + return BOOLToBool(result); + } + + HWND GetNextGroupItem(HWND control, bool previous) + { return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); } + HWND GetNextTabItem(HWND control, bool previous) + { return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); } + + LRESULT SendMsg_NextDlgCtl(WPARAM wParam, LPARAM lParam) + { return SendMsg(WM_NEXTDLGCTL, wParam, lParam); } + LRESULT SendMsg_NextDlgCtl_HWND(HWND hwnd) { return SendMsg_NextDlgCtl((WPARAM)hwnd, TRUE); } + LRESULT SendMsg_NextDlgCtl_CtlId(unsigned id) { return SendMsg_NextDlgCtl_HWND(GetItem(id)); } + LRESULT SendMsg_NextDlgCtl_Next() { return SendMsg_NextDlgCtl(0, FALSE); } + LRESULT SendMsg_NextDlgCtl_Prev() { return SendMsg_NextDlgCtl(1, FALSE); } + + bool MapRect(LPRECT rect) + { return BOOLToBool(MapDialogRect(_window, rect)); } + + bool IsMessage(LPMSG message) + { return BOOLToBool(IsDialogMessage(_window, message)); } + + LRESULT SendItemMessage(unsigned itemID, UINT message, WPARAM wParam, LPARAM lParam) + { return SendDlgItemMessage(_window, (int)itemID, message, wParam, lParam); } + + bool CheckButton(unsigned buttonID, UINT checkState) + { return BOOLToBool(CheckDlgButton(_window, (int)buttonID, checkState)); } + bool CheckButton(unsigned buttonID, bool checkState) + { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); } + + UINT IsButtonChecked_BST(unsigned buttonID) const + { return IsDlgButtonChecked(_window, (int)buttonID); } + bool IsButtonCheckedBool(unsigned buttonID) const + { return (IsButtonChecked_BST(buttonID) == BST_CHECKED); } + + bool CheckRadioButton(unsigned firstButtonID, unsigned lastButtonID, unsigned checkButtonID) + { return BOOLToBool(::CheckRadioButton(_window, + (int)firstButtonID, (int)lastButtonID, (int)checkButtonID)); } + + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + virtual bool OnInit() { return true; } + // virtual bool OnCommand2(WPARAM wParam, LPARAM lParam); + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam); + virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; } + virtual bool OnDestroy() { return false; } + + /* + #ifdef UNDER_CE + virtual void OnHelp(void *) { OnHelp(); } + #else + virtual void OnHelp(LPHELPINFO) { OnHelp(); } + #endif + */ + virtual void OnHelp() {} + + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND); + virtual void OnOK() {} + virtual void OnContinue() {} + virtual void OnCancel() {} + virtual void OnClose() {} + virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */) { return false; } + virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; } + + LONG_PTR SetMsgResult(LONG_PTR newLongPtr ) + { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } + LONG_PTR GetMsgResult() const + { return GetLongPtr(DWLP_MSGRESULT); } + + bool GetMargins(int margin, int &x, int &y); + int Units_To_Pixels_X(int units); + bool GetItemSizes(unsigned id, int &x, int &y); + void GetClientRectOfItem(unsigned id, RECT &rect); + bool MoveItem(unsigned id, int x, int y, int width, int height, bool repaint = true); + bool MoveItem_RECT(unsigned id, const RECT &r, bool repaint = true) + { return MoveItem(id, r.left, r.top, RECT_SIZE_X(r), RECT_SIZE_Y(r), repaint); } + + void NormalizeSize(bool fullNormalize = false); + void NormalizePosition(); +}; + +class CModelessDialog: public CDialog +{ +public: + bool Create(LPCTSTR templateName, HWND parentWindow); + bool Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); } + #ifndef _UNICODE + bool Create(LPCWSTR templateName, HWND parentWindow); + #endif + virtual void OnOK() Z7_override { Destroy(); } + virtual void OnContinue() Z7_override { Destroy(); } + virtual void OnCancel() Z7_override { Destroy(); } + virtual void OnClose() Z7_override { Destroy(); } +}; + +class CModalDialog: public CDialog +{ +public: + INT_PTR Create(LPCTSTR templateName, HWND parentWindow); + INT_PTR Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); } + #ifndef _UNICODE + INT_PTR Create(LPCWSTR templateName, HWND parentWindow); + #endif + + bool End(INT_PTR result) { return BOOLToBool(::EndDialog(_window, result)); } + virtual void OnOK() Z7_override { End(IDOK); } + virtual void OnContinue() Z7_override { End(IDCONTINUE); } + virtual void OnCancel() Z7_override { End(IDCANCEL); } + virtual void OnClose() Z7_override { End(IDCLOSE); } +}; + +class CDialogChildControl: public NWindows::CWindow +{ + // unsigned m_ID; +public: + void Init(const NWindows::NControl::CDialog &parentDialog, unsigned id) + { + // m_ID = id; + Attach(parentDialog.GetItem(id)); + } +}; + +bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd = NULL); + +}} + +#endif diff --git a/CPP/Windows/Control/Edit.h b/CPP/Windows/Control/Edit.h index 62e0a92a8..963470d78 100644 --- a/CPP/Windows/Control/Edit.h +++ b/CPP/Windows/Control/Edit.h @@ -1,19 +1,19 @@ -// Windows/Control/Edit.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_EDIT_H -#define ZIP7_INC_WINDOWS_CONTROL_EDIT_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CEdit: public CWindow -{ -public: - void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); } -}; - -}} - -#endif +// Windows/Control/Edit.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_EDIT_H +#define ZIP7_INC_WINDOWS_CONTROL_EDIT_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CEdit: public CWindow +{ +public: + void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); } +}; + +}} + +#endif diff --git a/CPP/Windows/Control/ImageList.cpp b/CPP/Windows/Control/ImageList.cpp index d201c8fd7..3e22b956e 100644 --- a/CPP/Windows/Control/ImageList.cpp +++ b/CPP/Windows/Control/ImageList.cpp @@ -1,10 +1,10 @@ -// Windows/Control/ImageList.cpp - -#include "StdAfx.h" - -#include "ImageList.h" - -namespace NWindows { -namespace NControl { - -}} +// Windows/Control/ImageList.cpp + +#include "StdAfx.h" + +#include "ImageList.h" + +namespace NWindows { +namespace NControl { + +}} diff --git a/CPP/Windows/Control/ImageList.h b/CPP/Windows/Control/ImageList.h index 4fa1d2208..688f1777c 100644 --- a/CPP/Windows/Control/ImageList.h +++ b/CPP/Windows/Control/ImageList.h @@ -1,87 +1,87 @@ -// Windows/Control/ImageList.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H -#define ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H - -#include - -#include "../Defs.h" - -namespace NWindows { -namespace NControl { - -class CImageList -{ - HIMAGELIST m_Object; -public: - operator HIMAGELIST() const {return m_Object; } - CImageList(): m_Object(NULL) {} - bool Attach(HIMAGELIST imageList) - { - if (imageList == NULL) - return false; - m_Object = imageList; - return true; - } - - HIMAGELIST Detach() - { - HIMAGELIST imageList = m_Object; - m_Object = NULL; - return imageList; - } - - bool Create(int width, int height, UINT flags, int initialNumber, int grow) - { - HIMAGELIST a = ImageList_Create(width, height, flags, - initialNumber, grow); - if (a == NULL) - return false; - return Attach(a); - } - - bool Destroy() // DeleteImageList() in MFC - { - if (m_Object == NULL) - return false; - return BOOLToBool(ImageList_Destroy(Detach())); - } - - ~CImageList() - { Destroy(); } - - int GetImageCount() const - { return ImageList_GetImageCount(m_Object); } - - bool GetImageInfo(int index, IMAGEINFO* imageInfo) const - { return BOOLToBool(ImageList_GetImageInfo(m_Object, index, imageInfo)); } - - int Add(HBITMAP hbmImage, HBITMAP hbmMask = NULL) - { return ImageList_Add(m_Object, hbmImage, hbmMask); } - int AddMasked(HBITMAP hbmImage, COLORREF mask) - { return ImageList_AddMasked(m_Object, hbmImage, mask); } - int AddIcon(HICON icon) - { return ImageList_AddIcon(m_Object, icon); } - int Replace(int index, HICON icon) - { return ImageList_ReplaceIcon(m_Object, index, icon); } - - // If index is -1, the function removes all images. - bool Remove(int index) - { return BOOLToBool(ImageList_Remove(m_Object, index)); } - bool RemoveAll() - { return BOOLToBool(ImageList_RemoveAll(m_Object)); } - - HICON ExtractIcon(int index) - { return ImageList_ExtractIcon(NULL, m_Object, index); } - HICON GetIcon(int index, UINT flags) - { return ImageList_GetIcon(m_Object, index, flags); } - - bool GetIconSize(int &width, int &height) const - { return BOOLToBool(ImageList_GetIconSize(m_Object, &width, &height)); } - bool SetIconSize(int width, int height) - { return BOOLToBool(ImageList_SetIconSize(m_Object, width, height)); } -}; - -}} - -#endif +// Windows/Control/ImageList.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H +#define ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H + +#include + +#include "../Defs.h" + +namespace NWindows { +namespace NControl { + +class CImageList +{ + HIMAGELIST m_Object; +public: + operator HIMAGELIST() const {return m_Object; } + CImageList(): m_Object(NULL) {} + bool Attach(HIMAGELIST imageList) + { + if (imageList == NULL) + return false; + m_Object = imageList; + return true; + } + + HIMAGELIST Detach() + { + HIMAGELIST imageList = m_Object; + m_Object = NULL; + return imageList; + } + + bool Create(int width, int height, UINT flags, int initialNumber, int grow) + { + HIMAGELIST a = ImageList_Create(width, height, flags, + initialNumber, grow); + if (a == NULL) + return false; + return Attach(a); + } + + bool Destroy() // DeleteImageList() in MFC + { + if (m_Object == NULL) + return false; + return BOOLToBool(ImageList_Destroy(Detach())); + } + + ~CImageList() + { Destroy(); } + + int GetImageCount() const + { return ImageList_GetImageCount(m_Object); } + + bool GetImageInfo(int index, IMAGEINFO* imageInfo) const + { return BOOLToBool(ImageList_GetImageInfo(m_Object, index, imageInfo)); } + + int Add(HBITMAP hbmImage, HBITMAP hbmMask = NULL) + { return ImageList_Add(m_Object, hbmImage, hbmMask); } + int AddMasked(HBITMAP hbmImage, COLORREF mask) + { return ImageList_AddMasked(m_Object, hbmImage, mask); } + int AddIcon(HICON icon) + { return ImageList_AddIcon(m_Object, icon); } + int Replace(int index, HICON icon) + { return ImageList_ReplaceIcon(m_Object, index, icon); } + + // If index is -1, the function removes all images. + bool Remove(int index) + { return BOOLToBool(ImageList_Remove(m_Object, index)); } + bool RemoveAll() + { return BOOLToBool(ImageList_RemoveAll(m_Object)); } + + HICON ExtractIcon(int index) + { return ImageList_ExtractIcon(NULL, m_Object, index); } + HICON GetIcon(int index, UINT flags) + { return ImageList_GetIcon(m_Object, index, flags); } + + bool GetIconSize(int &width, int &height) const + { return BOOLToBool(ImageList_GetIconSize(m_Object, &width, &height)); } + bool SetIconSize(int width, int height) + { return BOOLToBool(ImageList_SetIconSize(m_Object, width, height)); } +}; + +}} + +#endif diff --git a/CPP/Windows/Control/ListView.cpp b/CPP/Windows/Control/ListView.cpp index 7516d3cf4..3e8786a1d 100644 --- a/CPP/Windows/Control/ListView.cpp +++ b/CPP/Windows/Control/ListView.cpp @@ -1,162 +1,162 @@ -// Windows/Control/ListView.cpp - -#include "StdAfx.h" - -#include "ListView.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NControl { - -bool CListView::CreateEx(DWORD exStyle, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam) -{ - return CWindow::CreateEx(exStyle, WC_LISTVIEW, TEXT(""), style, x, y, width, - height, parentWindow, idOrHMenu, instance, createParam); -} - -/* note: LVITEM and LVCOLUMN structures contain optional fields - depending from preprocessor macros: - #if (_WIN32_IE >= 0x0300) - #if (_WIN32_WINNT >= 0x0501) - #if (_WIN32_WINNT >= 0x0600) -*/ - -bool CListView::GetItemParam(unsigned index, LPARAM ¶m) const -{ - LVITEM item; - item.iItem = (int)index; - item.iSubItem = 0; - item.mask = LVIF_PARAM; - const bool res = GetItem(&item); - param = item.lParam; - return res; -} - -int CListView::InsertColumn(unsigned columnIndex, LPCTSTR text, int width) -{ - LVCOLUMN ci; - ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - ci.pszText = (LPTSTR)(void *)text; - ci.iSubItem = (int)columnIndex; - ci.cx = width; - return InsertColumn(columnIndex, &ci); -} - -int CListView::InsertItem(unsigned index, LPCTSTR text) -{ - LVITEM item; - item.mask = LVIF_TEXT | LVIF_PARAM; - item.iItem = (int)index; - item.lParam = (LPARAM)index; - item.pszText = (LPTSTR)(void *)text; - item.iSubItem = 0; - return InsertItem(&item); -} - -int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text) -{ - LVITEM item; - item.mask = LVIF_TEXT; - item.iItem = (int)index; - item.pszText = (LPTSTR)(void *)text; - item.iSubItem = (int)subIndex; - return SetItem(&item); -} - -#ifndef _UNICODE - -int CListView::InsertColumn(unsigned columnIndex, LPCWSTR text, int width) -{ - LVCOLUMNW ci; - ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - ci.pszText = (LPWSTR)(void *)text; - ci.iSubItem = (int)columnIndex; - ci.cx = width; - return InsertColumn(columnIndex, &ci); -} - -int CListView::InsertItem(unsigned index, LPCWSTR text) -{ - LVITEMW item; - item.mask = LVIF_TEXT | LVIF_PARAM; - item.iItem = (int)index; - item.lParam = (LPARAM)index; - item.pszText = (LPWSTR)(void *)text; - item.iSubItem = 0; - return InsertItem(&item); -} - -int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text) -{ - LVITEMW item; - item.mask = LVIF_TEXT; - item.iItem = (int)index; - item.pszText = (LPWSTR)(void *)text; - item.iSubItem = (int)subIndex; - return SetItem(&item); -} - -#endif - -static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - CWindow window(hwnd); - CListView2 *w = (CListView2 *)(window.GetUserDataLongPtr()); - if (w == NULL) - return 0; - return w->OnMessage(message, wParam, lParam); -} - -LRESULT CListView2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - #ifndef _UNICODE - if (g_IsNT) - return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam); - else - #endif - return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); -} - -void CListView2::SetWindowProc() -{ - SetUserDataLongPtr((LONG_PTR)this); - #ifndef _UNICODE - if (g_IsNT) - _origWindowProc = (WNDPROC)SetLongPtrW(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc); - else - #endif - _origWindowProc = (WNDPROC)SetLongPtr(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc); -} - -/* -LRESULT CListView3::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT res = CListView2::OnMessage(message, wParam, lParam); - if (message == WM_GETDLGCODE) - { - // when user presses RETURN, windows sends default (first) button command to parent dialog. - // we disable this: - MSG *msg = (MSG *)lParam; - WPARAM key = wParam; - bool change = false; - if (msg) - { - if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN) - change = true; - } - else if (wParam == VK_RETURN) - change = true; - if (change) - res |= DLGC_WANTALLKEYS; - } - return res; -} -*/ - -}} +// Windows/Control/ListView.cpp + +#include "StdAfx.h" + +#include "ListView.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NControl { + +bool CListView::CreateEx(DWORD exStyle, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) +{ + return CWindow::CreateEx(exStyle, WC_LISTVIEW, TEXT(""), style, x, y, width, + height, parentWindow, idOrHMenu, instance, createParam); +} + +/* note: LVITEM and LVCOLUMN structures contain optional fields + depending from preprocessor macros: + #if (_WIN32_IE >= 0x0300) + #if (_WIN32_WINNT >= 0x0501) + #if (_WIN32_WINNT >= 0x0600) +*/ + +bool CListView::GetItemParam(unsigned index, LPARAM ¶m) const +{ + LVITEM item; + item.iItem = (int)index; + item.iSubItem = 0; + item.mask = LVIF_PARAM; + const bool res = GetItem(&item); + param = item.lParam; + return res; +} + +int CListView::InsertColumn(unsigned columnIndex, LPCTSTR text, int width) +{ + LVCOLUMN ci; + ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; + ci.pszText = (LPTSTR)(void *)text; + ci.iSubItem = (int)columnIndex; + ci.cx = width; + return InsertColumn(columnIndex, &ci); +} + +int CListView::InsertItem(unsigned index, LPCTSTR text) +{ + LVITEM item; + item.mask = LVIF_TEXT | LVIF_PARAM; + item.iItem = (int)index; + item.lParam = (LPARAM)index; + item.pszText = (LPTSTR)(void *)text; + item.iSubItem = 0; + return InsertItem(&item); +} + +int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text) +{ + LVITEM item; + item.mask = LVIF_TEXT; + item.iItem = (int)index; + item.pszText = (LPTSTR)(void *)text; + item.iSubItem = (int)subIndex; + return SetItem(&item); +} + +#ifndef _UNICODE + +int CListView::InsertColumn(unsigned columnIndex, LPCWSTR text, int width) +{ + LVCOLUMNW ci; + ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; + ci.pszText = (LPWSTR)(void *)text; + ci.iSubItem = (int)columnIndex; + ci.cx = width; + return InsertColumn(columnIndex, &ci); +} + +int CListView::InsertItem(unsigned index, LPCWSTR text) +{ + LVITEMW item; + item.mask = LVIF_TEXT | LVIF_PARAM; + item.iItem = (int)index; + item.lParam = (LPARAM)index; + item.pszText = (LPWSTR)(void *)text; + item.iSubItem = 0; + return InsertItem(&item); +} + +int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text) +{ + LVITEMW item; + item.mask = LVIF_TEXT; + item.iItem = (int)index; + item.pszText = (LPWSTR)(void *)text; + item.iSubItem = (int)subIndex; + return SetItem(&item); +} + +#endif + +static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + CWindow window(hwnd); + CListView2 *w = (CListView2 *)(window.GetUserDataLongPtr()); + if (w == NULL) + return 0; + return w->OnMessage(message, wParam, lParam); +} + +LRESULT CListView2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + #ifndef _UNICODE + if (g_IsNT) + return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam); + else + #endif + return CallWindowProc(_origWindowProc, *this, message, wParam, lParam); +} + +void CListView2::SetWindowProc() +{ + SetUserDataLongPtr((LONG_PTR)this); + #ifndef _UNICODE + if (g_IsNT) + _origWindowProc = (WNDPROC)SetLongPtrW(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc); + else + #endif + _origWindowProc = (WNDPROC)SetLongPtr(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc); +} + +/* +LRESULT CListView3::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT res = CListView2::OnMessage(message, wParam, lParam); + if (message == WM_GETDLGCODE) + { + // when user presses RETURN, windows sends default (first) button command to parent dialog. + // we disable this: + MSG *msg = (MSG *)lParam; + WPARAM key = wParam; + bool change = false; + if (msg) + { + if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN) + change = true; + } + else if (wParam == VK_RETURN) + change = true; + if (change) + res |= DLGC_WANTALLKEYS; + } + return res; +} +*/ + +}} diff --git a/CPP/Windows/Control/ListView.h b/CPP/Windows/Control/ListView.h index a31c1b97a..11a33a07d 100644 --- a/CPP/Windows/Control/ListView.h +++ b/CPP/Windows/Control/ListView.h @@ -1,156 +1,156 @@ -// Windows/Control/ListView.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H -#define ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H - -#include "../../Common/MyWindows.h" - -#include - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CListView: public NWindows::CWindow -{ -public: - bool CreateEx(DWORD exStyle, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam); - - void SetUnicodeFormat() - { - #ifndef UNDER_CE - ListView_SetUnicodeFormat(_window, TRUE); - #endif - } - - bool DeleteAllItems() { return BOOLToBool(ListView_DeleteAllItems(_window)); } - bool DeleteColumn(unsigned columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); } - - int InsertColumn(unsigned columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); } - int InsertColumn(unsigned columnIndex, LPCTSTR text, int width); - bool SetColumnOrderArray(unsigned count, const int *columns) - { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, (int *)(void *)columns)); } - - /* - int GetNumColumns() - { - HWND header = ListView_GetHeader(_window); - if (!header) - return -1; - return Header_GetItemCount(header); - } - */ - - int InsertItem(const LVITEM* item) { return ListView_InsertItem(_window, item); } - int InsertItem(unsigned index, LPCTSTR text); - bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); } - int SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text); - - #ifndef _UNICODE - - int InsertColumn(unsigned columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); } - int InsertColumn(unsigned columnIndex, LPCWSTR text, int width); - int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); } - int InsertItem(unsigned index, LPCWSTR text); - bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); } - int SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text); - - #endif - - bool DeleteItem(unsigned itemIndex) { return BOOLToBool(ListView_DeleteItem(_window, itemIndex)); } - - UINT GetSelectedCount() const { return ListView_GetSelectedCount(_window); } - int GetItemCount() const { return ListView_GetItemCount(_window); } - - INT GetSelectionMark() const { return ListView_GetSelectionMark(_window); } - - void SetItemCount(unsigned numItems) { ListView_SetItemCount(_window, numItems); } - void SetItemCountEx(unsigned numItems, DWORD flags) { ListView_SetItemCountEx(_window, numItems, flags); } - - /* startIndex : The index of the item with which to begin the search, - or -1 to find the first item that matches the specified flags. - The specified item itself is excluded from the search. */ - int GetNextItem(int startIndex, UINT flags) const { return ListView_GetNextItem(_window, startIndex, flags); } - int GetNextSelectedItem(int startIndex) const { return GetNextItem(startIndex, LVNI_SELECTED); } - int GetFocusedItem() const { return GetNextItem(-1, LVNI_FOCUSED); } - - bool GetItem(LVITEM* item) const { return BOOLToBool(ListView_GetItem(_window, item)); } - bool GetItemParam(unsigned itemIndex, LPARAM ¶m) const; - /* - void GetItemText(unsigned itemIndex, unsigned subItemIndex, LPTSTR text, unsigned textSizeMax) const - { ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax) } - */ - bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam) - { return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); } - - // If (index == -1), then the state change is applied to all items. - void SetItemState(int index, UINT state, UINT mask) { ListView_SetItemState(_window, index, state, mask) } - void SetItemState_Selected(int index, bool select) { SetItemState(index, select ? LVIS_SELECTED : 0, LVIS_SELECTED); } - void SetItemState_Selected(int index) { SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); } - void SelectAll() { SetItemState_Selected(-1); } - void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } - UINT GetItemState(int index, UINT mask) const { return ListView_GetItemState(_window, index, mask); } - bool IsItemSelected(int index) const { return GetItemState(index, LVIS_SELECTED) == LVIS_SELECTED; } - - bool GetColumn(unsigned columnIndex, LVCOLUMN* columnInfo) const - { return BOOLToBool(ListView_GetColumn(_window, columnIndex, columnInfo)); } - - HIMAGELIST SetImageList(HIMAGELIST imageList, int imageListType) - { return ListView_SetImageList(_window, imageList, imageListType); } - - // version 4.70: NT5 | (NT4 + ie3) | w98 | (w95 + ie3) - DWORD GetExtendedListViewStyle() { return ListView_GetExtendedListViewStyle(_window); } - void SetExtendedListViewStyle(DWORD exStyle) { ListView_SetExtendedListViewStyle(_window, exStyle); } - void SetExtendedListViewStyle(DWORD exMask, DWORD exStyle) { ListView_SetExtendedListViewStyleEx(_window, exMask, exStyle); } - - void SetCheckState(UINT index, bool checkState) { ListView_SetCheckState(_window, index, BoolToBOOL(checkState)) } - bool GetCheckState(UINT index) { return BOOLToBool(ListView_GetCheckState(_window, index)); } - - bool EnsureVisible(int index, bool partialOK) { return BOOLToBool(ListView_EnsureVisible(_window, index, BoolToBOOL(partialOK))); } - - bool GetItemRect(int index, RECT *rect, int code) { return BOOLToBool(ListView_GetItemRect(_window, index, rect, code)); } - - HWND GetEditControl() { return ListView_GetEditControl(_window) ; } - HWND EditLabel(int itemIndex) { return ListView_EditLabel(_window, itemIndex) ; } - - bool RedrawItems(int firstIndex, int lastIndex) { return BOOLToBool(ListView_RedrawItems(_window, firstIndex, lastIndex)); } - bool RedrawAllItems() - { - if (GetItemCount() > 0) - return RedrawItems(0, GetItemCount() - 1); - return true; - } - bool RedrawItem(int index) { return RedrawItems(index, index); } - - int HitTest(LPLVHITTESTINFO info) { return ListView_HitTest(_window, info); } - COLORREF GetBkColor() { return ListView_GetBkColor(_window); } - bool SetColumnWidth(int iCol, int cx) { return BOOLToBool(ListView_SetColumnWidth(_window, iCol, cx)); } - bool SetColumnWidthAuto(int iCol) { return SetColumnWidth(iCol, LVSCW_AUTOSIZE); } -}; - -class CListView2: public CListView -{ - WNDPROC _origWindowProc; - // ~CListView2() ZIP7_eq_delete; -public: - virtual ~CListView2() {} - CListView2() {} - void SetWindowProc(); - virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); -}; - -/* -class CListView3: public CListView2 -{ -public: - virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); -}; -*/ - -}} - -#endif +// Windows/Control/ListView.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H +#define ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H + +#include "../../Common/MyWindows.h" + +#include + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CListView: public NWindows::CWindow +{ +public: + bool CreateEx(DWORD exStyle, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam); + + void SetUnicodeFormat() + { + #ifndef UNDER_CE + ListView_SetUnicodeFormat(_window, TRUE); + #endif + } + + bool DeleteAllItems() { return BOOLToBool(ListView_DeleteAllItems(_window)); } + bool DeleteColumn(unsigned columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); } + + int InsertColumn(unsigned columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); } + int InsertColumn(unsigned columnIndex, LPCTSTR text, int width); + bool SetColumnOrderArray(unsigned count, const int *columns) + { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, (int *)(void *)columns)); } + + /* + int GetNumColumns() + { + HWND header = ListView_GetHeader(_window); + if (!header) + return -1; + return Header_GetItemCount(header); + } + */ + + int InsertItem(const LVITEM* item) { return ListView_InsertItem(_window, item); } + int InsertItem(unsigned index, LPCTSTR text); + bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); } + int SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text); + + #ifndef _UNICODE + + int InsertColumn(unsigned columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); } + int InsertColumn(unsigned columnIndex, LPCWSTR text, int width); + int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); } + int InsertItem(unsigned index, LPCWSTR text); + bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); } + int SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text); + + #endif + + bool DeleteItem(unsigned itemIndex) { return BOOLToBool(ListView_DeleteItem(_window, itemIndex)); } + + UINT GetSelectedCount() const { return ListView_GetSelectedCount(_window); } + int GetItemCount() const { return ListView_GetItemCount(_window); } + + INT GetSelectionMark() const { return ListView_GetSelectionMark(_window); } + + void SetItemCount(unsigned numItems) { ListView_SetItemCount(_window, numItems); } + void SetItemCountEx(unsigned numItems, DWORD flags) { ListView_SetItemCountEx(_window, numItems, flags); } + + /* startIndex : The index of the item with which to begin the search, + or -1 to find the first item that matches the specified flags. + The specified item itself is excluded from the search. */ + int GetNextItem(int startIndex, UINT flags) const { return ListView_GetNextItem(_window, startIndex, flags); } + int GetNextSelectedItem(int startIndex) const { return GetNextItem(startIndex, LVNI_SELECTED); } + int GetFocusedItem() const { return GetNextItem(-1, LVNI_FOCUSED); } + + bool GetItem(LVITEM* item) const { return BOOLToBool(ListView_GetItem(_window, item)); } + bool GetItemParam(unsigned itemIndex, LPARAM ¶m) const; + /* + void GetItemText(unsigned itemIndex, unsigned subItemIndex, LPTSTR text, unsigned textSizeMax) const + { ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax) } + */ + bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam) + { return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); } + + // If (index == -1), then the state change is applied to all items. + void SetItemState(int index, UINT state, UINT mask) { ListView_SetItemState(_window, index, state, mask) } + void SetItemState_Selected(int index, bool select) { SetItemState(index, select ? LVIS_SELECTED : 0, LVIS_SELECTED); } + void SetItemState_Selected(int index) { SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); } + void SelectAll() { SetItemState_Selected(-1); } + void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } + UINT GetItemState(int index, UINT mask) const { return ListView_GetItemState(_window, index, mask); } + bool IsItemSelected(int index) const { return GetItemState(index, LVIS_SELECTED) == LVIS_SELECTED; } + + bool GetColumn(unsigned columnIndex, LVCOLUMN* columnInfo) const + { return BOOLToBool(ListView_GetColumn(_window, columnIndex, columnInfo)); } + + HIMAGELIST SetImageList(HIMAGELIST imageList, int imageListType) + { return ListView_SetImageList(_window, imageList, imageListType); } + + // version 4.70: NT5 | (NT4 + ie3) | w98 | (w95 + ie3) + DWORD GetExtendedListViewStyle() { return ListView_GetExtendedListViewStyle(_window); } + void SetExtendedListViewStyle(DWORD exStyle) { ListView_SetExtendedListViewStyle(_window, exStyle); } + void SetExtendedListViewStyle(DWORD exMask, DWORD exStyle) { ListView_SetExtendedListViewStyleEx(_window, exMask, exStyle); } + + void SetCheckState(UINT index, bool checkState) { ListView_SetCheckState(_window, index, BoolToBOOL(checkState)) } + bool GetCheckState(UINT index) { return BOOLToBool(ListView_GetCheckState(_window, index)); } + + bool EnsureVisible(int index, bool partialOK) { return BOOLToBool(ListView_EnsureVisible(_window, index, BoolToBOOL(partialOK))); } + + bool GetItemRect(int index, RECT *rect, int code) { return BOOLToBool(ListView_GetItemRect(_window, index, rect, code)); } + + HWND GetEditControl() { return ListView_GetEditControl(_window) ; } + HWND EditLabel(int itemIndex) { return ListView_EditLabel(_window, itemIndex) ; } + + bool RedrawItems(int firstIndex, int lastIndex) { return BOOLToBool(ListView_RedrawItems(_window, firstIndex, lastIndex)); } + bool RedrawAllItems() + { + if (GetItemCount() > 0) + return RedrawItems(0, GetItemCount() - 1); + return true; + } + bool RedrawItem(int index) { return RedrawItems(index, index); } + + int HitTest(LPLVHITTESTINFO info) { return ListView_HitTest(_window, info); } + COLORREF GetBkColor() { return ListView_GetBkColor(_window); } + bool SetColumnWidth(int iCol, int cx) { return BOOLToBool(ListView_SetColumnWidth(_window, iCol, cx)); } + bool SetColumnWidthAuto(int iCol) { return SetColumnWidth(iCol, LVSCW_AUTOSIZE); } +}; + +class CListView2: public CListView +{ + WNDPROC _origWindowProc; + // ~CListView2() ZIP7_eq_delete; +public: + virtual ~CListView2() {} + CListView2() {} + void SetWindowProc(); + virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); +}; + +/* +class CListView3: public CListView2 +{ +public: + virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); +}; +*/ + +}} + +#endif diff --git a/CPP/Windows/Control/ProgressBar.h b/CPP/Windows/Control/ProgressBar.h index 827f38302..2256aa9e9 100644 --- a/CPP/Windows/Control/ProgressBar.h +++ b/CPP/Windows/Control/ProgressBar.h @@ -1,35 +1,35 @@ -// Windows/Control/ProgressBar.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H -#define ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H - -#include "../../Common/MyWindows.h" - -#include - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CProgressBar: public CWindow -{ -public: - LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, (unsigned)pos, 0); } - // LRESULT DeltaPos(int increment) { return SendMsg(PBM_DELTAPOS, increment, 0); } - // UINT GetPos() { return (UINT)SendMsg(PBM_GETPOS, 0, 0); } - // LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMsg(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); } - DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMsg(PBM_SETRANGE32, (unsigned)minValue, (LPARAM)(unsigned)maxValue); } - // int SetStep(int step) { return (int)SendMsg(PBM_SETSTEP, step, 0); } - // LRESULT StepIt() { return SendMsg(PBM_STEPIT, 0, 0); } - // INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMsg(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); } - - #ifndef UNDER_CE - COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBARCOLOR, 0, (LPARAM)color); } - COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, (LPARAM)color); } - #endif -}; - -}} - -#endif +// Windows/Control/ProgressBar.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H +#define ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H + +#include "../../Common/MyWindows.h" + +#include + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CProgressBar: public CWindow +{ +public: + LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, (unsigned)pos, 0); } + // LRESULT DeltaPos(int increment) { return SendMsg(PBM_DELTAPOS, increment, 0); } + // UINT GetPos() { return (UINT)SendMsg(PBM_GETPOS, 0, 0); } + // LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMsg(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); } + DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMsg(PBM_SETRANGE32, (unsigned)minValue, (LPARAM)(unsigned)maxValue); } + // int SetStep(int step) { return (int)SendMsg(PBM_SETSTEP, step, 0); } + // LRESULT StepIt() { return SendMsg(PBM_STEPIT, 0, 0); } + // INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMsg(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); } + + #ifndef UNDER_CE + COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBARCOLOR, 0, (LPARAM)color); } + COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, (LPARAM)color); } + #endif +}; + +}} + +#endif diff --git a/CPP/Windows/Control/PropertyPage.cpp b/CPP/Windows/Control/PropertyPage.cpp index 03f035557..9b36cbec8 100644 --- a/CPP/Windows/Control/PropertyPage.cpp +++ b/CPP/Windows/Control/PropertyPage.cpp @@ -1,165 +1,165 @@ -// Windows/Control/PropertyPage.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../../Common/StringConvert.h" -#endif - -#include "PropertyPage.h" - -extern HINSTANCE g_hInstance; -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NControl { - -static -#ifdef Z7_OLD_WIN_SDK - BOOL -#else - INT_PTR -#endif -APIENTRY MyProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) -{ - CWindow tempDialog(dialogHWND); - if (message == WM_INITDIALOG) - tempDialog.SetUserDataLongPtr(((PROPSHEETPAGE *)lParam)->lParam); - CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr()); - if (dialog == NULL) - return FALSE; - if (message == WM_INITDIALOG) - dialog->Attach(dialogHWND); - try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } - catch(...) { return TRUE; } -} - -bool CPropertyPage::OnNotify(UINT /* controlID */, LPNMHDR lParam) -{ - switch (lParam->code) - { - case PSN_APPLY: SetMsgResult(OnApply2(LPPSHNOTIFY(lParam))); break; - case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive2(LPPSHNOTIFY(lParam)))); break; - case PSN_SETACTIVE: SetMsgResult(OnSetActive2(LPPSHNOTIFY(lParam))); break; - case PSN_RESET: OnReset2(LPPSHNOTIFY(lParam)); break; - case PSN_HELP: OnNotifyHelp2(LPPSHNOTIFY(lParam)); break; - default: return false; - } - return true; -} - -/* -PROPSHEETPAGE fields depend from -#if (_WIN32_WINNT >= 0x0600) -#elif (_WIN32_WINNT >= 0x0501) -#elif (_WIN32_IE >= 0x0400) -PROPSHEETHEADER fields depend from -#if (_WIN32_IE >= 0x0400) -*/ -#if defined(PROPSHEETPAGEA_V1_SIZE) && !defined(Z7_OLD_WIN_SDK) -#ifndef _UNICODE -#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA_V1 -#endif -#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW_V1 -#else -// for old mingw: -#ifndef _UNICODE -#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA -#endif -#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW -#endif - -INT_PTR MyPropertySheet(const CObjectVector &pagesInfo, HWND hwndParent, const UString &title) -{ - unsigned i; - #ifndef _UNICODE - AStringVector titles; - for (i = 0; i < pagesInfo.Size(); i++) - titles.Add(GetSystemString(pagesInfo[i].Title)); - CRecordVector pagesA; - #endif - CRecordVector pagesW; - - for (i = 0; i < pagesInfo.Size(); i++) - { - const CPageInfo &pageInfo = pagesInfo[i]; - #ifndef _UNICODE - { - my_compatib_PROPSHEETPAGEA page; - memset(&page, 0, sizeof(page)); - page.dwSize = sizeof(page); - page.dwFlags = PSP_HASHELP; - page.hInstance = g_hInstance; - page.pszTemplate = MAKEINTRESOURCEA(pageInfo.ID); - // page.pszIcon = NULL; - page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure; - - if (!titles[i].IsEmpty()) - { - page.pszTitle = titles[i]; - page.dwFlags |= PSP_USETITLE; - } - // else page.pszTitle = NULL; - page.lParam = (LPARAM)pageInfo.Page; - // page.pfnCallback = NULL; - pagesA.Add(page); - } - #endif - { - my_compatib_PROPSHEETPAGEW page; - memset(&page, 0, sizeof(page)); - page.dwSize = sizeof(page); - page.dwFlags = PSP_HASHELP; - page.hInstance = g_hInstance; - page.pszTemplate = MAKEINTRESOURCEW(pageInfo.ID); - // page.pszIcon = NULL; - page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure; - - if (!pageInfo.Title.IsEmpty()) - { - page.pszTitle = pageInfo.Title; - page.dwFlags |= PSP_USETITLE; - } - // else page.pszTitle = NULL; - page.lParam = (LPARAM)pageInfo.Page; - // page.pfnCallback = NULL; - pagesW.Add(page); - } - } - - #ifndef _UNICODE - if (!g_IsNT) - { - PROPSHEETHEADERA sheet; - sheet.dwSize = sizeof(sheet); - sheet.dwFlags = PSH_PROPSHEETPAGE; - sheet.hwndParent = hwndParent; - sheet.hInstance = g_hInstance; - AString titleA (GetSystemString(title)); - sheet.pszCaption = titleA; - sheet.nPages = pagesA.Size(); - sheet.nStartPage = 0; - sheet.ppsp = (LPCPROPSHEETPAGEA)(const void *)pagesA.ConstData(); - sheet.pfnCallback = NULL; - return ::PropertySheetA(&sheet); - } - else - #endif - { - PROPSHEETHEADERW sheet; - sheet.dwSize = sizeof(sheet); - sheet.dwFlags = PSH_PROPSHEETPAGE; - sheet.hwndParent = hwndParent; - sheet.hInstance = g_hInstance; - sheet.pszCaption = title; - sheet.nPages = pagesW.Size(); - sheet.nStartPage = 0; - sheet.ppsp = (LPCPROPSHEETPAGEW)(const void *)pagesW.ConstData(); - sheet.pfnCallback = NULL; - return ::PropertySheetW(&sheet); - } -} - -}} +// Windows/Control/PropertyPage.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../../Common/StringConvert.h" +#endif + +#include "PropertyPage.h" + +extern HINSTANCE g_hInstance; +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NControl { + +static +#ifdef Z7_OLD_WIN_SDK + BOOL +#else + INT_PTR +#endif +APIENTRY MyProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) +{ + CWindow tempDialog(dialogHWND); + if (message == WM_INITDIALOG) + tempDialog.SetUserDataLongPtr(((PROPSHEETPAGE *)lParam)->lParam); + CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr()); + if (dialog == NULL) + return FALSE; + if (message == WM_INITDIALOG) + dialog->Attach(dialogHWND); + try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } + catch(...) { return TRUE; } +} + +bool CPropertyPage::OnNotify(UINT /* controlID */, LPNMHDR lParam) +{ + switch (lParam->code) + { + case PSN_APPLY: SetMsgResult(OnApply2(LPPSHNOTIFY(lParam))); break; + case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive2(LPPSHNOTIFY(lParam)))); break; + case PSN_SETACTIVE: SetMsgResult(OnSetActive2(LPPSHNOTIFY(lParam))); break; + case PSN_RESET: OnReset2(LPPSHNOTIFY(lParam)); break; + case PSN_HELP: OnNotifyHelp2(LPPSHNOTIFY(lParam)); break; + default: return false; + } + return true; +} + +/* +PROPSHEETPAGE fields depend from +#if (_WIN32_WINNT >= 0x0600) +#elif (_WIN32_WINNT >= 0x0501) +#elif (_WIN32_IE >= 0x0400) +PROPSHEETHEADER fields depend from +#if (_WIN32_IE >= 0x0400) +*/ +#if defined(PROPSHEETPAGEA_V1_SIZE) && !defined(Z7_OLD_WIN_SDK) +#ifndef _UNICODE +#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA_V1 +#endif +#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW_V1 +#else +// for old mingw: +#ifndef _UNICODE +#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA +#endif +#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW +#endif + +INT_PTR MyPropertySheet(const CObjectVector &pagesInfo, HWND hwndParent, const UString &title) +{ + unsigned i; + #ifndef _UNICODE + AStringVector titles; + for (i = 0; i < pagesInfo.Size(); i++) + titles.Add(GetSystemString(pagesInfo[i].Title)); + CRecordVector pagesA; + #endif + CRecordVector pagesW; + + for (i = 0; i < pagesInfo.Size(); i++) + { + const CPageInfo &pageInfo = pagesInfo[i]; + #ifndef _UNICODE + { + my_compatib_PROPSHEETPAGEA page; + memset(&page, 0, sizeof(page)); + page.dwSize = sizeof(page); + page.dwFlags = PSP_HASHELP; + page.hInstance = g_hInstance; + page.pszTemplate = MAKEINTRESOURCEA(pageInfo.ID); + // page.pszIcon = NULL; + page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure; + + if (!titles[i].IsEmpty()) + { + page.pszTitle = titles[i]; + page.dwFlags |= PSP_USETITLE; + } + // else page.pszTitle = NULL; + page.lParam = (LPARAM)pageInfo.Page; + // page.pfnCallback = NULL; + pagesA.Add(page); + } + #endif + { + my_compatib_PROPSHEETPAGEW page; + memset(&page, 0, sizeof(page)); + page.dwSize = sizeof(page); + page.dwFlags = PSP_HASHELP; + page.hInstance = g_hInstance; + page.pszTemplate = MAKEINTRESOURCEW(pageInfo.ID); + // page.pszIcon = NULL; + page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure; + + if (!pageInfo.Title.IsEmpty()) + { + page.pszTitle = pageInfo.Title; + page.dwFlags |= PSP_USETITLE; + } + // else page.pszTitle = NULL; + page.lParam = (LPARAM)pageInfo.Page; + // page.pfnCallback = NULL; + pagesW.Add(page); + } + } + + #ifndef _UNICODE + if (!g_IsNT) + { + PROPSHEETHEADERA sheet; + sheet.dwSize = sizeof(sheet); + sheet.dwFlags = PSH_PROPSHEETPAGE; + sheet.hwndParent = hwndParent; + sheet.hInstance = g_hInstance; + AString titleA (GetSystemString(title)); + sheet.pszCaption = titleA; + sheet.nPages = pagesA.Size(); + sheet.nStartPage = 0; + sheet.ppsp = (LPCPROPSHEETPAGEA)(const void *)pagesA.ConstData(); + sheet.pfnCallback = NULL; + return ::PropertySheetA(&sheet); + } + else + #endif + { + PROPSHEETHEADERW sheet; + sheet.dwSize = sizeof(sheet); + sheet.dwFlags = PSH_PROPSHEETPAGE; + sheet.hwndParent = hwndParent; + sheet.hInstance = g_hInstance; + sheet.pszCaption = title; + sheet.nPages = pagesW.Size(); + sheet.nStartPage = 0; + sheet.ppsp = (LPCPROPSHEETPAGEW)(const void *)pagesW.ConstData(); + sheet.pfnCallback = NULL; + return ::PropertySheetW(&sheet); + } +} + +}} diff --git a/CPP/Windows/Control/PropertyPage.h b/CPP/Windows/Control/PropertyPage.h index b917131be..264a5d29c 100644 --- a/CPP/Windows/Control/PropertyPage.h +++ b/CPP/Windows/Control/PropertyPage.h @@ -1,50 +1,50 @@ -// Windows/Control/PropertyPage.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H -#define ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H - -#include "../../Common/MyWindows.h" - -#include - -#include "Dialog.h" - -namespace NWindows { -namespace NControl { - -INT_PTR APIENTRY ProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam); - -class CPropertyPage: public CDialog -{ -public: - CPropertyPage(HWND window = NULL): CDialog(window) {} - - void Changed() { PropSheet_Changed(GetParent(), (HWND)*this); } - void UnChanged() { PropSheet_UnChanged(GetParent(), (HWND)*this); } - - virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override; - - virtual bool OnKillActive() { return false; } // false = OK - virtual bool OnKillActive2(const PSHNOTIFY *) { return OnKillActive(); } - virtual LONG OnSetActive() { return false; } // false = OK - virtual LONG OnSetActive2(const PSHNOTIFY *) { return OnSetActive(); } - virtual LONG OnApply() { return PSNRET_NOERROR; } - virtual LONG OnApply2(const PSHNOTIFY *) { return OnApply(); } - virtual void OnNotifyHelp() {} - virtual void OnNotifyHelp2(const PSHNOTIFY *) { OnNotifyHelp(); } - virtual void OnReset() {} - virtual void OnReset2(const PSHNOTIFY *) { OnReset(); } -}; - -struct CPageInfo -{ - CPropertyPage *Page; - UString Title; - UINT ID; -}; - -INT_PTR MyPropertySheet(const CObjectVector &pagesInfo, HWND hwndParent, const UString &title); - -}} - -#endif +// Windows/Control/PropertyPage.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H +#define ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H + +#include "../../Common/MyWindows.h" + +#include + +#include "Dialog.h" + +namespace NWindows { +namespace NControl { + +INT_PTR APIENTRY ProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam); + +class CPropertyPage: public CDialog +{ +public: + CPropertyPage(HWND window = NULL): CDialog(window) {} + + void Changed() { PropSheet_Changed(GetParent(), (HWND)*this); } + void UnChanged() { PropSheet_UnChanged(GetParent(), (HWND)*this); } + + virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override; + + virtual bool OnKillActive() { return false; } // false = OK + virtual bool OnKillActive2(const PSHNOTIFY *) { return OnKillActive(); } + virtual LONG OnSetActive() { return false; } // false = OK + virtual LONG OnSetActive2(const PSHNOTIFY *) { return OnSetActive(); } + virtual LONG OnApply() { return PSNRET_NOERROR; } + virtual LONG OnApply2(const PSHNOTIFY *) { return OnApply(); } + virtual void OnNotifyHelp() {} + virtual void OnNotifyHelp2(const PSHNOTIFY *) { OnNotifyHelp(); } + virtual void OnReset() {} + virtual void OnReset2(const PSHNOTIFY *) { OnReset(); } +}; + +struct CPageInfo +{ + CPropertyPage *Page; + UString Title; + UINT ID; +}; + +INT_PTR MyPropertySheet(const CObjectVector &pagesInfo, HWND hwndParent, const UString &title); + +}} + +#endif diff --git a/CPP/Windows/Control/ReBar.h b/CPP/Windows/Control/ReBar.h index 135388c5a..b56f018cb 100644 --- a/CPP/Windows/Control/ReBar.h +++ b/CPP/Windows/Control/ReBar.h @@ -1,34 +1,34 @@ -// Windows/Control/ReBar.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_REBAR_H -#define ZIP7_INC_WINDOWS_CONTROL_REBAR_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CReBar: public NWindows::CWindow -{ -public: - bool SetBarInfo(LPREBARINFO barInfo) - { return LRESULTToBool(SendMsg(RB_SETBARINFO, 0, (LPARAM)barInfo)); } - bool InsertBand(int index, LPREBARBANDINFO bandInfo) - { return LRESULTToBool(SendMsg(RB_INSERTBAND, MY_int_TO_WPARAM(index), (LPARAM)bandInfo)); } - bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo) - { return LRESULTToBool(SendMsg(RB_SETBANDINFO, index, (LPARAM)bandInfo)); } - void MaximizeBand(unsigned index, bool ideal) - { SendMsg(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); } - bool SizeToRect(LPRECT rect) - { return LRESULTToBool(SendMsg(RB_SIZETORECT, 0, (LPARAM)rect)); } - UINT GetHeight() - { return (UINT)SendMsg(RB_GETBARHEIGHT); } - UINT GetBandCount() - { return (UINT)SendMsg(RB_GETBANDCOUNT); } - bool DeleteBand(UINT index) - { return LRESULTToBool(SendMsg(RB_DELETEBAND, index)); } -}; - -}} - -#endif +// Windows/Control/ReBar.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_REBAR_H +#define ZIP7_INC_WINDOWS_CONTROL_REBAR_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CReBar: public NWindows::CWindow +{ +public: + bool SetBarInfo(LPREBARINFO barInfo) + { return LRESULTToBool(SendMsg(RB_SETBARINFO, 0, (LPARAM)barInfo)); } + bool InsertBand(int index, LPREBARBANDINFO bandInfo) + { return LRESULTToBool(SendMsg(RB_INSERTBAND, MY_int_TO_WPARAM(index), (LPARAM)bandInfo)); } + bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo) + { return LRESULTToBool(SendMsg(RB_SETBANDINFO, index, (LPARAM)bandInfo)); } + void MaximizeBand(unsigned index, bool ideal) + { SendMsg(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); } + bool SizeToRect(LPRECT rect) + { return LRESULTToBool(SendMsg(RB_SIZETORECT, 0, (LPARAM)rect)); } + UINT GetHeight() + { return (UINT)SendMsg(RB_GETBARHEIGHT); } + UINT GetBandCount() + { return (UINT)SendMsg(RB_GETBANDCOUNT); } + bool DeleteBand(UINT index) + { return LRESULTToBool(SendMsg(RB_DELETEBAND, index)); } +}; + +}} + +#endif diff --git a/CPP/Windows/Control/Static.h b/CPP/Windows/Control/Static.h index 42261d39e..ceeedf966 100644 --- a/CPP/Windows/Control/Static.h +++ b/CPP/Windows/Control/Static.h @@ -1,28 +1,28 @@ -// Windows/Control/Static.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_STATIC_H -#define ZIP7_INC_WINDOWS_CONTROL_STATIC_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CStatic: public CWindow -{ -public: - HANDLE SetImage(WPARAM imageType, HANDLE handle) { return (HANDLE)SendMsg(STM_SETIMAGE, imageType, (LPARAM)handle); } - HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMsg(STM_GETIMAGE, imageType, 0); } - - #ifdef UNDER_CE - HICON SetIcon(HICON icon) { return (HICON)SetImage(IMAGE_ICON, icon); } - HICON GetIcon() { return (HICON)GetImage(IMAGE_ICON); } - #else - HICON SetIcon(HICON icon) { return (HICON)SendMsg(STM_SETICON, (WPARAM)icon, 0); } - HICON GetIcon() { return (HICON)SendMsg(STM_GETICON, 0, 0); } - #endif -}; - -}} - -#endif +// Windows/Control/Static.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_STATIC_H +#define ZIP7_INC_WINDOWS_CONTROL_STATIC_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CStatic: public CWindow +{ +public: + HANDLE SetImage(WPARAM imageType, HANDLE handle) { return (HANDLE)SendMsg(STM_SETIMAGE, imageType, (LPARAM)handle); } + HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMsg(STM_GETIMAGE, imageType, 0); } + + #ifdef UNDER_CE + HICON SetIcon(HICON icon) { return (HICON)SetImage(IMAGE_ICON, icon); } + HICON GetIcon() { return (HICON)GetImage(IMAGE_ICON); } + #else + HICON SetIcon(HICON icon) { return (HICON)SendMsg(STM_SETICON, (WPARAM)icon, 0); } + HICON GetIcon() { return (HICON)SendMsg(STM_GETICON, 0, 0); } + #endif +}; + +}} + +#endif diff --git a/CPP/Windows/Control/StatusBar.h b/CPP/Windows/Control/StatusBar.h index fa34e2af3..38aca4788 100644 --- a/CPP/Windows/Control/StatusBar.h +++ b/CPP/Windows/Control/StatusBar.h @@ -1,42 +1,42 @@ -// Windows/Control/StatusBar.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H -#define ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CStatusBar: public NWindows::CWindow -{ -public: - bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id) - { return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != NULL; } - bool SetText(LPCTSTR text) - { return CWindow::SetText(text); } - bool SetText(unsigned index, LPCTSTR text, UINT type) - { return LRESULTToBool(SendMsg(SB_SETTEXT, index | type, (LPARAM)text)); } - bool SetText(unsigned index, LPCTSTR text) - { return SetText(index, text, 0); } - - #ifndef _UNICODE - bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id) - { return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != NULL; } - bool SetText(LPCWSTR text) - { return CWindow::SetText(text); } - bool SetText(unsigned index, LPCWSTR text, UINT type) - { return LRESULTToBool(SendMsg(SB_SETTEXTW, index | type, (LPARAM)text)); } - bool SetText(unsigned index, LPCWSTR text) - { return SetText(index, text, 0); } - #endif - - bool SetParts(unsigned numParts, const int *edgePostions) - { return LRESULTToBool(SendMsg(SB_SETPARTS, numParts, (LPARAM)edgePostions)); } - void Simple(bool simple) - { SendMsg(SB_SIMPLE, (WPARAM)BoolToBOOL(simple), 0); } -}; - -}} - -#endif +// Windows/Control/StatusBar.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H +#define ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CStatusBar: public NWindows::CWindow +{ +public: + bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id) + { return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != NULL; } + bool SetText(LPCTSTR text) + { return CWindow::SetText(text); } + bool SetText(unsigned index, LPCTSTR text, UINT type) + { return LRESULTToBool(SendMsg(SB_SETTEXT, index | type, (LPARAM)text)); } + bool SetText(unsigned index, LPCTSTR text) + { return SetText(index, text, 0); } + + #ifndef _UNICODE + bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id) + { return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != NULL; } + bool SetText(LPCWSTR text) + { return CWindow::SetText(text); } + bool SetText(unsigned index, LPCWSTR text, UINT type) + { return LRESULTToBool(SendMsg(SB_SETTEXTW, index | type, (LPARAM)text)); } + bool SetText(unsigned index, LPCWSTR text) + { return SetText(index, text, 0); } + #endif + + bool SetParts(unsigned numParts, const int *edgePostions) + { return LRESULTToBool(SendMsg(SB_SETPARTS, numParts, (LPARAM)edgePostions)); } + void Simple(bool simple) + { SendMsg(SB_SIMPLE, (WPARAM)BoolToBOOL(simple), 0); } +}; + +}} + +#endif diff --git a/CPP/Windows/Control/StdAfx.h b/CPP/Windows/Control/StdAfx.h index aa6fe0328..80866550d 100644 --- a/CPP/Windows/Control/StdAfx.h +++ b/CPP/Windows/Control/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../../Common/Common.h" + +#endif diff --git a/CPP/Windows/Control/ToolBar.h b/CPP/Windows/Control/ToolBar.h index 79c49e254..2bf20a592 100644 --- a/CPP/Windows/Control/ToolBar.h +++ b/CPP/Windows/Control/ToolBar.h @@ -1,43 +1,43 @@ -// Windows/Control/ToolBar.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H -#define ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CToolBar: public NWindows::CWindow -{ -public: - void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); } - DWORD GetButtonSize() { return (DWORD)SendMsg(TB_GETBUTTONSIZE, 0, 0); } - - bool GetMaxSize(LPSIZE size) - #ifdef UNDER_CE - { - // maybe it must be fixed for more than 1 buttons - const DWORD val = GetButtonSize(); - size->cx = LOWORD(val); - size->cy = HIWORD(val); - return true; - } - #else - { - return LRESULTToBool(SendMsg(TB_GETMAXSIZE, 0, (LPARAM)size)); - } - #endif - - bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMsg(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); } - void ButtonStructSize() { SendMsg(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); } - HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMsg(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); } - bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); } - #ifndef _UNICODE - bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); } - #endif -}; - -}} - -#endif +// Windows/Control/ToolBar.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H +#define ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CToolBar: public NWindows::CWindow +{ +public: + void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); } + DWORD GetButtonSize() { return (DWORD)SendMsg(TB_GETBUTTONSIZE, 0, 0); } + + bool GetMaxSize(LPSIZE size) + #ifdef UNDER_CE + { + // maybe it must be fixed for more than 1 buttons + const DWORD val = GetButtonSize(); + size->cx = LOWORD(val); + size->cy = HIWORD(val); + return true; + } + #else + { + return LRESULTToBool(SendMsg(TB_GETMAXSIZE, 0, (LPARAM)size)); + } + #endif + + bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMsg(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); } + void ButtonStructSize() { SendMsg(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); } + HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMsg(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); } + bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); } + #ifndef _UNICODE + bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); } + #endif +}; + +}} + +#endif diff --git a/CPP/Windows/Control/Trackbar.h b/CPP/Windows/Control/Trackbar.h index 86e3b303d..18d1b2918 100644 --- a/CPP/Windows/Control/Trackbar.h +++ b/CPP/Windows/Control/Trackbar.h @@ -1,27 +1,27 @@ -// Windows/Control/Trackbar.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H -#define ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CTrackbar: public CWindow -{ -public: - void SetRange(int minimum, int maximum, bool redraw = true) - { SendMsg(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); } - void SetPos(int pos, bool redraw = true) - { SendMsg(TBM_SETPOS, BoolToBOOL(redraw), pos); } - void SetTicFreq(int freq) - { SendMsg(TBM_SETTICFREQ, freq); } - - int GetPos() - { return (int)SendMsg(TBM_GETPOS); } -}; - -}} - -#endif +// Windows/Control/Trackbar.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H +#define ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CTrackbar: public CWindow +{ +public: + void SetRange(int minimum, int maximum, bool redraw = true) + { SendMsg(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); } + void SetPos(int pos, bool redraw = true) + { SendMsg(TBM_SETPOS, BoolToBOOL(redraw), pos); } + void SetTicFreq(int freq) + { SendMsg(TBM_SETTICFREQ, freq); } + + int GetPos() + { return (int)SendMsg(TBM_GETPOS); } +}; + +}} + +#endif diff --git a/CPP/Windows/Control/Window2.cpp b/CPP/Windows/Control/Window2.cpp index 639b1e2de..8fe908e08 100644 --- a/CPP/Windows/Control/Window2.cpp +++ b/CPP/Windows/Control/Window2.cpp @@ -1,202 +1,202 @@ -// Windows/Control/Window2.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../../Common/StringConvert.h" -#endif - -#include "Window2.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { - -#ifndef _UNICODE -ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); -#endif - -namespace NControl { - -#ifdef UNDER_CE -#define MY_START_WM_CREATE WM_CREATE -#else -#define MY_START_WM_CREATE WM_NCCREATE -#endif - -static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message, WPARAM wParam, LPARAM lParam) -{ - CWindow tempWindow(aHWND); - if (message == MY_START_WM_CREATE) - tempWindow.SetUserDataLongPtr((LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams)); - CWindow2 *window = (CWindow2 *)(tempWindow.GetUserDataLongPtr()); - if (window && message == MY_START_WM_CREATE) - window->Attach(aHWND); - if (!window) - { - #ifndef _UNICODE - if (g_IsNT) - return DefWindowProcW(aHWND, message, wParam, lParam); - else - #endif - return DefWindowProc(aHWND, message, wParam, lParam); - } - return window->OnMessage(message, wParam, lParam); -} - -bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName, - DWORD style, int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance) -{ - WNDCLASS wc; - if (!::GetClassInfo(instance, className, &wc)) - { - // wc.style = CS_HREDRAW | CS_VREDRAW; - wc.style = 0; - wc.lpfnWndProc = WindowProcedure; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = instance; - wc.hIcon = NULL; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wc.lpszMenuName = NULL; - wc.lpszClassName = className; - if (::RegisterClass(&wc) == 0) - return false; - } - return CWindow::CreateEx(exStyle, className, windowName, style, - x, y, width, height, parentWindow, idOrHMenu, instance, this); -} - -#ifndef _UNICODE - -bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, - DWORD style, int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance) -{ - bool needRegister; - if (g_IsNT) - { - WNDCLASSW wc; - needRegister = ::GetClassInfoW(instance, className, &wc) == 0; - } - else - { - WNDCLASSA windowClassA; - AString classNameA; - LPCSTR classNameP; - if (IS_INTRESOURCE(className)) - classNameP = (LPCSTR)className; - else - { - classNameA = GetSystemString(className); - classNameP = classNameA; - } - needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0; - } - if (needRegister) - { - WNDCLASSW wc; - // wc.style = CS_HREDRAW | CS_VREDRAW; - wc.style = 0; - wc.lpfnWndProc = WindowProcedure; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = instance; - wc.hIcon = NULL; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wc.lpszMenuName = NULL; - wc.lpszClassName = className; - if (MyRegisterClass(&wc) == 0) - return false; - } - return CWindow::CreateEx(exStyle, className, windowName, style, - x, y, width, height, parentWindow, idOrHMenu, instance, this); -} - -#endif - -LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam) -{ - #ifndef _UNICODE - if (g_IsNT) - return DefWindowProcW(_window, message, wParam, lParam); - else - #endif - return DefWindowProc(_window, message, wParam, lParam); -} - -LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) -{ - LRESULT result; - switch (message) - { - case WM_CREATE: - if (!OnCreate((CREATESTRUCT *)lParam)) - return -1; - break; - case WM_COMMAND: - if (OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result)) - return result; - break; - case WM_NOTIFY: - if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result)) - return result; - break; - case WM_DESTROY: - OnDestroy(); - break; - case WM_CLOSE: - OnClose(); - return 0; - case WM_SIZE: - if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam))) - return 0; - } - return DefProc(message, wParam, lParam); -} - -/* -bool CWindow2::OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result) -{ - return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result); -} -*/ - -bool CWindow2::OnCommand(unsigned /* code */, unsigned /* itemID */, LPARAM /* lParam */, LRESULT & /* result */) -{ - return false; - // return DefProc(message, wParam, lParam); - /* - if (code == BN_CLICKED) - return OnButtonClicked(itemID, (HWND)lParam); - */ -} - -/* -bool CDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) -{ - switch (buttonID) - { - case IDOK: - OnOK(); - break; - case IDCANCEL: - OnCancel(); - break; - case IDHELP: - OnHelp(); - break; - default: - return false; - } - return true; -} - -*/ - -}} +// Windows/Control/Window2.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../../Common/StringConvert.h" +#endif + +#include "Window2.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +#ifndef _UNICODE +ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); +#endif + +namespace NControl { + +#ifdef UNDER_CE +#define MY_START_WM_CREATE WM_CREATE +#else +#define MY_START_WM_CREATE WM_NCCREATE +#endif + +static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message, WPARAM wParam, LPARAM lParam) +{ + CWindow tempWindow(aHWND); + if (message == MY_START_WM_CREATE) + tempWindow.SetUserDataLongPtr((LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams)); + CWindow2 *window = (CWindow2 *)(tempWindow.GetUserDataLongPtr()); + if (window && message == MY_START_WM_CREATE) + window->Attach(aHWND); + if (!window) + { + #ifndef _UNICODE + if (g_IsNT) + return DefWindowProcW(aHWND, message, wParam, lParam); + else + #endif + return DefWindowProc(aHWND, message, wParam, lParam); + } + return window->OnMessage(message, wParam, lParam); +} + +bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName, + DWORD style, int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance) +{ + WNDCLASS wc; + if (!::GetClassInfo(instance, className, &wc)) + { + // wc.style = CS_HREDRAW | CS_VREDRAW; + wc.style = 0; + wc.lpfnWndProc = WindowProcedure; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = instance; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = className; + if (::RegisterClass(&wc) == 0) + return false; + } + return CWindow::CreateEx(exStyle, className, windowName, style, + x, y, width, height, parentWindow, idOrHMenu, instance, this); +} + +#ifndef _UNICODE + +bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, + DWORD style, int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance) +{ + bool needRegister; + if (g_IsNT) + { + WNDCLASSW wc; + needRegister = ::GetClassInfoW(instance, className, &wc) == 0; + } + else + { + WNDCLASSA windowClassA; + AString classNameA; + LPCSTR classNameP; + if (IS_INTRESOURCE(className)) + classNameP = (LPCSTR)className; + else + { + classNameA = GetSystemString(className); + classNameP = classNameA; + } + needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0; + } + if (needRegister) + { + WNDCLASSW wc; + // wc.style = CS_HREDRAW | CS_VREDRAW; + wc.style = 0; + wc.lpfnWndProc = WindowProcedure; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = instance; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = className; + if (MyRegisterClass(&wc) == 0) + return false; + } + return CWindow::CreateEx(exStyle, className, windowName, style, + x, y, width, height, parentWindow, idOrHMenu, instance, this); +} + +#endif + +LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + #ifndef _UNICODE + if (g_IsNT) + return DefWindowProcW(_window, message, wParam, lParam); + else + #endif + return DefWindowProc(_window, message, wParam, lParam); +} + +LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + switch (message) + { + case WM_CREATE: + if (!OnCreate((CREATESTRUCT *)lParam)) + return -1; + break; + case WM_COMMAND: + if (OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result)) + return result; + break; + case WM_NOTIFY: + if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result)) + return result; + break; + case WM_DESTROY: + OnDestroy(); + break; + case WM_CLOSE: + OnClose(); + return 0; + case WM_SIZE: + if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam))) + return 0; + } + return DefProc(message, wParam, lParam); +} + +/* +bool CWindow2::OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result) +{ + return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result); +} +*/ + +bool CWindow2::OnCommand(unsigned /* code */, unsigned /* itemID */, LPARAM /* lParam */, LRESULT & /* result */) +{ + return false; + // return DefProc(message, wParam, lParam); + /* + if (code == BN_CLICKED) + return OnButtonClicked(itemID, (HWND)lParam); + */ +} + +/* +bool CDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDOK: + OnOK(); + break; + case IDCANCEL: + OnCancel(); + break; + case IDHELP: + OnHelp(); + break; + default: + return false; + } + return true; +} + +*/ + +}} diff --git a/CPP/Windows/Control/Window2.h b/CPP/Windows/Control/Window2.h index 0cc1b2295..ebb597935 100644 --- a/CPP/Windows/Control/Window2.h +++ b/CPP/Windows/Control/Window2.h @@ -1,53 +1,53 @@ -// Windows/Control/Window2.h - -#ifndef ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H -#define ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H - -#include "../Window.h" - -namespace NWindows { -namespace NControl { - -class CWindow2: public CWindow -{ - // Z7_CLASS_NO_COPY(CWindow2) - - LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam); -public: - CWindow2(HWND newWindow = NULL): CWindow(newWindow) {} - virtual ~CWindow2() {} - - bool CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName, - DWORD style, int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance); - - #ifndef _UNICODE - bool CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, - DWORD style, int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance); - #endif - - virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); - virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; } - // virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam); - // bool OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result); - virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result); - virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; } - virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; } - virtual void OnDestroy() { PostQuitMessage(0); } - virtual void OnClose() { Destroy(); } - /* - virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); } - virtual LRESULT OnHelp() {}; - virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND); - virtual void OnOK() {}; - virtual void OnCancel() {}; - */ - - LONG_PTR SetMsgResult(LONG_PTR newLongPtr) { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } - LONG_PTR GetMsgResult() const { return GetLongPtr(DWLP_MSGRESULT); } -}; - -}} - -#endif +// Windows/Control/Window2.h + +#ifndef ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H +#define ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H + +#include "../Window.h" + +namespace NWindows { +namespace NControl { + +class CWindow2: public CWindow +{ + // Z7_CLASS_NO_COPY(CWindow2) + + LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam); +public: + CWindow2(HWND newWindow = NULL): CWindow(newWindow) {} + virtual ~CWindow2() {} + + bool CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName, + DWORD style, int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance); + + #ifndef _UNICODE + bool CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, + DWORD style, int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance); + #endif + + virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; } + // virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam); + // bool OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result); + virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result); + virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; } + virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; } + virtual void OnDestroy() { PostQuitMessage(0); } + virtual void OnClose() { Destroy(); } + /* + virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); } + virtual LRESULT OnHelp() {}; + virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND); + virtual void OnOK() {}; + virtual void OnCancel() {}; + */ + + LONG_PTR SetMsgResult(LONG_PTR newLongPtr) { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } + LONG_PTR GetMsgResult() const { return GetLongPtr(DWLP_MSGRESULT); } +}; + +}} + +#endif diff --git a/CPP/Windows/DLL.cpp b/CPP/Windows/DLL.cpp index a7dc65e1d..025df17bd 100644 --- a/CPP/Windows/DLL.cpp +++ b/CPP/Windows/DLL.cpp @@ -1,178 +1,178 @@ -// Windows/DLL.cpp - -#include "StdAfx.h" - -#include "DLL.h" - -#ifdef _WIN32 - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -extern HINSTANCE g_hInstance; - -namespace NWindows { -namespace NDLL { - -bool CLibrary::Free() throw() -{ - if (_module == NULL) - return true; - if (!::FreeLibrary(_module)) - return false; - _module = NULL; - return true; -} - -bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw() -{ - if (!Free()) - return false; - #ifndef _UNICODE - if (!g_IsNT) - { - _module = ::LoadLibraryEx(fs2fas(path), NULL, flags); - } - else - #endif - { - _module = ::LoadLibraryExW(fs2us(path), NULL, flags); - } - return (_module != NULL); -} - -bool CLibrary::Load(CFSTR path) throw() -{ - if (!Free()) - return false; - #ifndef _UNICODE - if (!g_IsNT) - { - _module = ::LoadLibrary(fs2fas(path)); - } - else - #endif - { - _module = ::LoadLibraryW(fs2us(path)); - } - return (_module != NULL); -} - -bool MyGetModuleFileName(FString &path) -{ - const HMODULE hModule = g_hInstance; - path.Empty(); - #ifndef _UNICODE - if (!g_IsNT) - { - TCHAR s[MAX_PATH + 2]; - s[0] = 0; - const DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1); - if (size <= MAX_PATH && size != 0) - { - path = fas2fs(s); - return true; - } - } - else - #endif - { - WCHAR s[MAX_PATH + 2]; - s[0] = 0; - const DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1); - if (size <= MAX_PATH && size != 0) - { - path = us2fs(s); - return true; - } - } - return false; -} - -#ifndef Z7_SFX - -FString GetModuleDirPrefix() -{ - FString s; - if (MyGetModuleFileName(s)) - { - const int pos = s.ReverseFind_PathSepar(); - if (pos >= 0) - s.DeleteFrom((unsigned)(pos + 1)); - } - if (s.IsEmpty()) - s = "." STRING_PATH_SEPARATOR; - return s; -} - -#endif - -}} - -#else // _WIN32 - -#include -#include - -// FARPROC -void *GetProcAddress(HMODULE module, LPCSTR procName) -{ - void *ptr = NULL; - if (module) - ptr = dlsym(module, procName); - return ptr; -} - -namespace NWindows { -namespace NDLL { - -bool CLibrary::Free() throw() -{ - if (!_module) - return true; - const int ret = dlclose(_module); - if (ret != 0) - return false; - _module = NULL; - return true; -} - -bool CLibrary::Load(CFSTR path) throw() -{ - if (!Free()) - return false; - - int options = 0; - - #ifdef RTLD_LOCAL - options |= RTLD_LOCAL; - #endif - - #ifdef RTLD_NOW - options |= RTLD_NOW; - #endif - - #ifdef RTLD_GROUP - #if ! (defined(hpux) || defined(__hpux)) - options |= RTLD_GROUP; // mainly for solaris but not for HPUX - #endif - #endif - - _module = dlopen(path, options); - return (_module != NULL); -} - -/* -// FARPROC -void * CLibrary::GetProc(LPCSTR procName) const -{ - // return My_GetProcAddress(_module, procName); - return local_GetProcAddress(_module, procName); - // return NULL; -} -*/ - -}} - -#endif +// Windows/DLL.cpp + +#include "StdAfx.h" + +#include "DLL.h" + +#ifdef _WIN32 + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +extern HINSTANCE g_hInstance; + +namespace NWindows { +namespace NDLL { + +bool CLibrary::Free() throw() +{ + if (_module == NULL) + return true; + if (!::FreeLibrary(_module)) + return false; + _module = NULL; + return true; +} + +bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw() +{ + if (!Free()) + return false; + #ifndef _UNICODE + if (!g_IsNT) + { + _module = ::LoadLibraryEx(fs2fas(path), NULL, flags); + } + else + #endif + { + _module = ::LoadLibraryExW(fs2us(path), NULL, flags); + } + return (_module != NULL); +} + +bool CLibrary::Load(CFSTR path) throw() +{ + if (!Free()) + return false; + #ifndef _UNICODE + if (!g_IsNT) + { + _module = ::LoadLibrary(fs2fas(path)); + } + else + #endif + { + _module = ::LoadLibraryW(fs2us(path)); + } + return (_module != NULL); +} + +bool MyGetModuleFileName(FString &path) +{ + const HMODULE hModule = g_hInstance; + path.Empty(); + #ifndef _UNICODE + if (!g_IsNT) + { + TCHAR s[MAX_PATH + 2]; + s[0] = 0; + const DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1); + if (size <= MAX_PATH && size != 0) + { + path = fas2fs(s); + return true; + } + } + else + #endif + { + WCHAR s[MAX_PATH + 2]; + s[0] = 0; + const DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1); + if (size <= MAX_PATH && size != 0) + { + path = us2fs(s); + return true; + } + } + return false; +} + +#ifndef Z7_SFX + +FString GetModuleDirPrefix() +{ + FString s; + if (MyGetModuleFileName(s)) + { + const int pos = s.ReverseFind_PathSepar(); + if (pos >= 0) + s.DeleteFrom((unsigned)(pos + 1)); + } + if (s.IsEmpty()) + s = "." STRING_PATH_SEPARATOR; + return s; +} + +#endif + +}} + +#else // _WIN32 + +#include +#include + +// FARPROC +void *GetProcAddress(HMODULE module, LPCSTR procName) +{ + void *ptr = NULL; + if (module) + ptr = dlsym(module, procName); + return ptr; +} + +namespace NWindows { +namespace NDLL { + +bool CLibrary::Free() throw() +{ + if (!_module) + return true; + const int ret = dlclose(_module); + if (ret != 0) + return false; + _module = NULL; + return true; +} + +bool CLibrary::Load(CFSTR path) throw() +{ + if (!Free()) + return false; + + int options = 0; + + #ifdef RTLD_LOCAL + options |= RTLD_LOCAL; + #endif + + #ifdef RTLD_NOW + options |= RTLD_NOW; + #endif + + #ifdef RTLD_GROUP + #if ! (defined(hpux) || defined(__hpux)) + options |= RTLD_GROUP; // mainly for solaris but not for HPUX + #endif + #endif + + _module = dlopen(path, options); + return (_module != NULL); +} + +/* +// FARPROC +void * CLibrary::GetProc(LPCSTR procName) const +{ + // return My_GetProcAddress(_module, procName); + return local_GetProcAddress(_module, procName); + // return NULL; +} +*/ + +}} + +#endif diff --git a/CPP/Windows/DLL.h b/CPP/Windows/DLL.h index b00678651..19a82b33b 100644 --- a/CPP/Windows/DLL.h +++ b/CPP/Windows/DLL.h @@ -1,103 +1,103 @@ -// Windows/DLL.h - -#ifndef ZIP7_INC_WINDOWS_DLL_H -#define ZIP7_INC_WINDOWS_DLL_H - -#include "../Common/MyString.h" - -#ifndef _WIN32 -typedef void * HMODULE; -// typedef int (*FARPROC)(); -// typedef void *FARPROC; -void *GetProcAddress(HMODULE module, LPCSTR procName); -#endif - -namespace NWindows { -namespace NDLL { - -#ifdef _WIN32 - -/* -#ifdef UNDER_CE -#define My_GetProcAddress(module, procName) (void *)::GetProcAddressA(module, procName) -#else -#define My_GetProcAddress(module, procName) (void *)::GetProcAddress(module, procName) -#endif -*/ - -/* Win32: Don't call CLibrary::Free() and FreeLibrary() from another - FreeLibrary() code: detaching code in DLL entry-point or in - destructors of global objects in DLL module. */ - -class CLibrary -{ - HMODULE _module; - - // Z7_CLASS_NO_COPY(CLibrary); - // copy constructor is required here -public: - CLibrary(): _module(NULL) {} - ~CLibrary() { Free(); } - - CLibrary(const CLibrary &c): _module(NULL) - { - if (c._module) - { - // we need non const to reference from original item - // c._module = NULL; - throw 20230102; - } - } - - HMODULE Get_HMODULE() const { return _module; } - // operator HMODULE() const { return _module; } - // HMODULE* operator&() { return &_module; } - bool IsLoaded() const { return (_module != NULL); } - - void Attach(HMODULE m) - { - Free(); - _module = m; - } - HMODULE Detach() - { - const HMODULE m = _module; - _module = NULL; - return m; - } - - bool Free() throw(); - bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw(); - bool Load(CFSTR path) throw(); - // FARPROC - // void *GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); } -}; - -#else - -class CLibrary -{ - HMODULE _module; - - // Z7_CLASS_NO_COPY(CLibrary); -public: - CLibrary(): _module(NULL) {} - ~CLibrary() { Free(); } - - HMODULE Get_HMODULE() const { return _module; } - - bool Free() throw(); - bool Load(CFSTR path) throw(); - // FARPROC - // void *GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); } -}; - -#endif - -bool MyGetModuleFileName(FString &path); - -FString GetModuleDirPrefix(); - -}} - -#endif +// Windows/DLL.h + +#ifndef ZIP7_INC_WINDOWS_DLL_H +#define ZIP7_INC_WINDOWS_DLL_H + +#include "../Common/MyString.h" + +#ifndef _WIN32 +typedef void * HMODULE; +// typedef int (*FARPROC)(); +// typedef void *FARPROC; +void *GetProcAddress(HMODULE module, LPCSTR procName); +#endif + +namespace NWindows { +namespace NDLL { + +#ifdef _WIN32 + +/* +#ifdef UNDER_CE +#define My_GetProcAddress(module, procName) (void *)::GetProcAddressA(module, procName) +#else +#define My_GetProcAddress(module, procName) (void *)::GetProcAddress(module, procName) +#endif +*/ + +/* Win32: Don't call CLibrary::Free() and FreeLibrary() from another + FreeLibrary() code: detaching code in DLL entry-point or in + destructors of global objects in DLL module. */ + +class CLibrary +{ + HMODULE _module; + + // Z7_CLASS_NO_COPY(CLibrary); + // copy constructor is required here +public: + CLibrary(): _module(NULL) {} + ~CLibrary() { Free(); } + + CLibrary(const CLibrary &c): _module(NULL) + { + if (c._module) + { + // we need non const to reference from original item + // c._module = NULL; + throw 20230102; + } + } + + HMODULE Get_HMODULE() const { return _module; } + // operator HMODULE() const { return _module; } + // HMODULE* operator&() { return &_module; } + bool IsLoaded() const { return (_module != NULL); } + + void Attach(HMODULE m) + { + Free(); + _module = m; + } + HMODULE Detach() + { + const HMODULE m = _module; + _module = NULL; + return m; + } + + bool Free() throw(); + bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw(); + bool Load(CFSTR path) throw(); + // FARPROC + // void *GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); } +}; + +#else + +class CLibrary +{ + HMODULE _module; + + // Z7_CLASS_NO_COPY(CLibrary); +public: + CLibrary(): _module(NULL) {} + ~CLibrary() { Free(); } + + HMODULE Get_HMODULE() const { return _module; } + + bool Free() throw(); + bool Load(CFSTR path) throw(); + // FARPROC + // void *GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); } +}; + +#endif + +bool MyGetModuleFileName(FString &path); + +FString GetModuleDirPrefix(); + +}} + +#endif diff --git a/CPP/Windows/Defs.h b/CPP/Windows/Defs.h index d682a33ef..8ab9cf5ea 100644 --- a/CPP/Windows/Defs.h +++ b/CPP/Windows/Defs.h @@ -1,17 +1,17 @@ -// Windows/Defs.h - -#ifndef ZIP7_INC_WINDOWS_DEFS_H -#define ZIP7_INC_WINDOWS_DEFS_H - -#include "../Common/MyWindows.h" - -#ifdef _WIN32 -inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } -#endif - -inline bool BOOLToBool(BOOL v) { return (v != FALSE); } - -inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } -inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } - -#endif +// Windows/Defs.h + +#ifndef ZIP7_INC_WINDOWS_DEFS_H +#define ZIP7_INC_WINDOWS_DEFS_H + +#include "../Common/MyWindows.h" + +#ifdef _WIN32 +inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } +#endif + +inline bool BOOLToBool(BOOL v) { return (v != FALSE); } + +inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } +inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } + +#endif diff --git a/CPP/Windows/ErrorMsg.cpp b/CPP/Windows/ErrorMsg.cpp index b947ca5e1..5acf3adb6 100644 --- a/CPP/Windows/ErrorMsg.cpp +++ b/CPP/Windows/ErrorMsg.cpp @@ -1,133 +1,133 @@ -// Windows/ErrorMsg.h - -#include "StdAfx.h" - -#if !defined(_UNICODE) || !defined(_WIN32) -#include "../Common/StringConvert.h" -#endif - -#include "ErrorMsg.h" - -#ifdef _WIN32 -#if !defined(_UNICODE) -extern bool g_IsNT; -#endif -#endif - -namespace NWindows { -namespace NError { - -static bool MyFormatMessage(DWORD errorCode, UString &message) -{ - #ifndef Z7_SFX - if ((HRESULT)errorCode == MY_HRES_ERROR_INTERNAL_ERROR) - { - message = "Internal Error: The failure in hardware (RAM or CPU), OS or program"; - return true; - } - #endif - - #ifdef _WIN32 - - LPVOID msgBuf; - #ifndef _UNICODE - if (!g_IsNT) - { - if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorCode, 0, (LPTSTR) &msgBuf, 0, NULL) == 0) - return false; - message = GetUnicodeString((LPCTSTR)msgBuf); - } - else - #endif - { - if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) - return false; - message = (LPCWSTR)msgBuf; - } - ::LocalFree(msgBuf); - return true; - - #else // _WIN32 - - AString m; - - const char *s = NULL; - - switch ((Int32)errorCode) - { - // case ERROR_NO_MORE_FILES : s = "No more files"; break; - // case ERROR_DIRECTORY : s = "Error Directory"; break; - case E_NOTIMPL : s = "E_NOTIMPL : Not implemented"; break; - case E_NOINTERFACE : s = "E_NOINTERFACE : No such interface supported"; break; - case E_ABORT : s = "E_ABORT : Operation aborted"; break; - case E_FAIL : s = "E_FAIL : Unspecified error"; break; - - case STG_E_INVALIDFUNCTION : s = "STG_E_INVALIDFUNCTION"; break; - case CLASS_E_CLASSNOTAVAILABLE : s = "CLASS_E_CLASSNOTAVAILABLE"; break; - - case E_OUTOFMEMORY : s = "E_OUTOFMEMORY : Can't allocate required memory"; break; - case E_INVALIDARG : s = "E_INVALIDARG : One or more arguments are invalid"; break; - - // case MY_E_ERROR_NEGATIVE_SEEK : s = "MY_E_ERROR_NEGATIVE_SEEK"; break; - default: - break; - } - - /* strerror() for unknown errors still shows message "Unknown error -12345678") - So we must transfer error codes before strerror() */ - if (!s) - { - if ((errorCode & 0xFFFF0000) == (UInt32)((MY_FACILITY_WRes << 16) | 0x80000000)) - errorCode &= 0xFFFF; - else if ((errorCode & ((UInt32)1 << 31))) - return false; // we will show hex error later for that case - - s = strerror((int)errorCode); - - // if (!s) - { - m += "errno="; - m.Add_UInt32(errorCode); - if (s) - m += " : "; - } - } - - if (s) - m += s; - - MultiByteToUnicodeString2(message, m); - return true; - - #endif -} - - -UString MyFormatMessage(DWORD errorCode) -{ - UString m; - if (!MyFormatMessage(errorCode, m) || m.IsEmpty()) - { - char s[16]; - for (int i = 0; i < 8; i++) - { - unsigned t = errorCode & 0xF; - errorCode >>= 4; - s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } - s[8] = 0; - m += "Error #"; - m += s; - } - else if (m.Len() >= 2 - && m[m.Len() - 1] == 0x0A - && m[m.Len() - 2] == 0x0D) - m.DeleteFrom(m.Len() - 2); - return m; -} - -}} +// Windows/ErrorMsg.h + +#include "StdAfx.h" + +#if !defined(_UNICODE) || !defined(_WIN32) +#include "../Common/StringConvert.h" +#endif + +#include "ErrorMsg.h" + +#ifdef _WIN32 +#if !defined(_UNICODE) +extern bool g_IsNT; +#endif +#endif + +namespace NWindows { +namespace NError { + +static bool MyFormatMessage(DWORD errorCode, UString &message) +{ + #ifndef Z7_SFX + if ((HRESULT)errorCode == MY_HRES_ERROR_INTERNAL_ERROR) + { + message = "Internal Error: The failure in hardware (RAM or CPU), OS or program"; + return true; + } + #endif + + #ifdef _WIN32 + + LPVOID msgBuf; + #ifndef _UNICODE + if (!g_IsNT) + { + if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorCode, 0, (LPTSTR) &msgBuf, 0, NULL) == 0) + return false; + message = GetUnicodeString((LPCTSTR)msgBuf); + } + else + #endif + { + if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) + return false; + message = (LPCWSTR)msgBuf; + } + ::LocalFree(msgBuf); + return true; + + #else // _WIN32 + + AString m; + + const char *s = NULL; + + switch ((Int32)errorCode) + { + // case ERROR_NO_MORE_FILES : s = "No more files"; break; + // case ERROR_DIRECTORY : s = "Error Directory"; break; + case E_NOTIMPL : s = "E_NOTIMPL : Not implemented"; break; + case E_NOINTERFACE : s = "E_NOINTERFACE : No such interface supported"; break; + case E_ABORT : s = "E_ABORT : Operation aborted"; break; + case E_FAIL : s = "E_FAIL : Unspecified error"; break; + + case STG_E_INVALIDFUNCTION : s = "STG_E_INVALIDFUNCTION"; break; + case CLASS_E_CLASSNOTAVAILABLE : s = "CLASS_E_CLASSNOTAVAILABLE"; break; + + case E_OUTOFMEMORY : s = "E_OUTOFMEMORY : Can't allocate required memory"; break; + case E_INVALIDARG : s = "E_INVALIDARG : One or more arguments are invalid"; break; + + // case MY_E_ERROR_NEGATIVE_SEEK : s = "MY_E_ERROR_NEGATIVE_SEEK"; break; + default: + break; + } + + /* strerror() for unknown errors still shows message "Unknown error -12345678") + So we must transfer error codes before strerror() */ + if (!s) + { + if ((errorCode & 0xFFFF0000) == (UInt32)((MY_FACILITY_WRes << 16) | 0x80000000)) + errorCode &= 0xFFFF; + else if ((errorCode & ((UInt32)1 << 31))) + return false; // we will show hex error later for that case + + s = strerror((int)errorCode); + + // if (!s) + { + m += "errno="; + m.Add_UInt32(errorCode); + if (s) + m += " : "; + } + } + + if (s) + m += s; + + MultiByteToUnicodeString2(message, m); + return true; + + #endif +} + + +UString MyFormatMessage(DWORD errorCode) +{ + UString m; + if (!MyFormatMessage(errorCode, m) || m.IsEmpty()) + { + char s[16]; + for (int i = 0; i < 8; i++) + { + unsigned t = errorCode & 0xF; + errorCode >>= 4; + s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } + s[8] = 0; + m += "Error #"; + m += s; + } + else if (m.Len() >= 2 + && m[m.Len() - 1] == 0x0A + && m[m.Len() - 2] == 0x0D) + m.DeleteFrom(m.Len() - 2); + return m; +} + +}} diff --git a/CPP/Windows/ErrorMsg.h b/CPP/Windows/ErrorMsg.h index 5a6db7950..6142b4ebe 100644 --- a/CPP/Windows/ErrorMsg.h +++ b/CPP/Windows/ErrorMsg.h @@ -1,16 +1,16 @@ -// Windows/ErrorMsg.h - -#ifndef ZIP7_INC_WINDOWS_ERROR_MSG_H -#define ZIP7_INC_WINDOWS_ERROR_MSG_H - -#include "../Common/MyString.h" - -namespace NWindows { -namespace NError { - -UString MyFormatMessage(DWORD errorCode); -inline UString MyFormatMessage(HRESULT errorCode) { return MyFormatMessage((DWORD)errorCode); } - -}} - -#endif +// Windows/ErrorMsg.h + +#ifndef ZIP7_INC_WINDOWS_ERROR_MSG_H +#define ZIP7_INC_WINDOWS_ERROR_MSG_H + +#include "../Common/MyString.h" + +namespace NWindows { +namespace NError { + +UString MyFormatMessage(DWORD errorCode); +inline UString MyFormatMessage(HRESULT errorCode) { return MyFormatMessage((DWORD)errorCode); } + +}} + +#endif diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index e54a8fb35..2cb83b252 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp @@ -1,1245 +1,1331 @@ -// Windows/FileDir.cpp - -#include "StdAfx.h" - - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../Common/StringConvert.h" -#include "../Common/C_FileIO.h" -#endif - -#include "FileDir.h" -#include "FileFind.h" -#include "FileName.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NName; - -#ifndef _WIN32 - -static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) -{ - if (ft) - { -#if defined(_AIX) - ts.tv_sec = ft->tv_sec; - ts.tv_nsec = ft->tv_nsec; -#else - ts = *ft; -#endif - return true; - } - // else - { - ts.tv_sec = 0; - ts.tv_nsec = - #ifdef UTIME_OMIT - UTIME_OMIT; // -2 keep old timesptamp - #else - // UTIME_NOW; -1 // set to the current time - 0; - #endif - return false; - } -} -#endif - -namespace NWindows { -namespace NFile { -namespace NDir { - -#ifdef _WIN32 - -#ifndef UNDER_CE - -bool GetWindowsDir(FString &path) -{ - const unsigned kBufSize = MAX_PATH + 16; - UINT len; - #ifndef _UNICODE - if (!g_IsNT) - { - TCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetWindowsDirectory(s, kBufSize); - path = fas2fs(s); - } - else - #endif - { - WCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetWindowsDirectoryW(s, kBufSize); - path = us2fs(s); - } - return (len != 0 && len < kBufSize); -} - - -/* -new DOCs for GetSystemDirectory: - returned path does not end with a backslash unless the - system directory is the root directory. -*/ - -bool GetSystemDir(FString &path) -{ - const unsigned kBufSize = MAX_PATH + 16; - UINT len; - #ifndef _UNICODE - if (!g_IsNT) - { - TCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetSystemDirectory(s, kBufSize); - path = fas2fs(s); - } - else - #endif - { - WCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetSystemDirectoryW(s, kBufSize); - path = us2fs(s); - } - return (len != 0 && len < kBufSize); -} -#endif // UNDER_CE - - -bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; - } - #endif - - HANDLE hDir = INVALID_HANDLE_VALUE; - IF_USE_MAIN_PATH - hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - #ifdef Z7_LONG_PATH - if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - } - #endif - - bool res = false; - if (hDir != INVALID_HANDLE_VALUE) - { - res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime)); - ::CloseHandle(hDir); - } - return res; -} - - - -bool SetFileAttrib(CFSTR path, DWORD attrib) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - if (::SetFileAttributes(fs2fas(path), attrib)) - return true; - } - else - #endif - { - IF_USE_MAIN_PATH - if (::SetFileAttributesW(fs2us(path), attrib)) - return true; - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - return BOOLToBool(::SetFileAttributesW(superPath, attrib)); - } - #endif - } - return false; -} - - -bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) -{ - #ifdef _WIN32 - if ((attrib & 0xF0000000) != 0) - attrib &= 0x3FFF; - #endif - return SetFileAttrib(path, attrib); -} - - -bool RemoveDir(CFSTR path) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - if (::RemoveDirectory(fs2fas(path))) - return true; - } - else - #endif - { - IF_USE_MAIN_PATH - if (::RemoveDirectoryW(fs2us(path))) - return true; - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - return BOOLToBool(::RemoveDirectoryW(superPath)); - } - #endif - } - return false; -} - - -bool MyMoveFile(CFSTR oldFile, CFSTR newFile) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - if (::MoveFile(fs2fas(oldFile), fs2fas(newFile))) - return true; - } - else - #endif - { - IF_USE_MAIN_PATH_2(oldFile, newFile) - { - if (::MoveFileW(fs2us(oldFile), fs2us(newFile))) - return true; - } - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH_2) - { - UString d1, d2; - if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) - return BOOLToBool(::MoveFileW(d1, d2)); - } - #endif - } - return false; -} - -#ifndef UNDER_CE -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 -#define Z7_USE_DYN_CreateHardLink -#endif - -#ifdef Z7_USE_DYN_CreateHardLink -EXTERN_C_BEGIN -typedef BOOL (WINAPI *Func_CreateHardLinkW)( - LPCWSTR lpFileName, - LPCWSTR lpExistingFileName, - LPSECURITY_ATTRIBUTES lpSecurityAttributes - ); -EXTERN_C_END -#endif -#endif // UNDER_CE - -bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; - /* - if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL)) - return true; - */ - } - else - #endif - { -#ifdef Z7_USE_DYN_CreateHardLink - const - Func_CreateHardLinkW - my_CreateHardLinkW = Z7_GET_PROC_ADDRESS( - Func_CreateHardLinkW, ::GetModuleHandleW(L"kernel32.dll"), - "CreateHardLinkW"); - if (!my_CreateHardLinkW) - return false; - #define MY_CreateHardLinkW my_CreateHardLinkW -#else - #define MY_CreateHardLinkW CreateHardLinkW -#endif - IF_USE_MAIN_PATH_2(newFileName, existFileName) - { - if (MY_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL)) - return true; - } - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH_2) - { - UString d1, d2; - if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2)) - return BOOLToBool(MY_CreateHardLinkW(d1, d2, NULL)); - } - #endif - } - return false; -} - - -/* -WinXP-64 CreateDir(): - "" - ERROR_PATH_NOT_FOUND - \ - ERROR_ACCESS_DENIED - C:\ - ERROR_ACCESS_DENIED, if there is such drive, - - D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive, - C:\nonExistent\folder - ERROR_PATH_NOT_FOUND - - C:\existFolder - ERROR_ALREADY_EXISTS - C:\existFolder\ - ERROR_ALREADY_EXISTS - - C:\folder - OK - C:\folder\ - OK - - \\Server\nonExistent - ERROR_BAD_NETPATH - \\Server\Share_Readonly - ERROR_ACCESS_DENIED - \\Server\Share - ERROR_ALREADY_EXISTS - - \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED - \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS -*/ - -bool CreateDir(CFSTR path) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - if (::CreateDirectory(fs2fas(path), NULL)) - return true; - } - else - #endif - { - IF_USE_MAIN_PATH - if (::CreateDirectoryW(fs2us(path), NULL)) - return true; - #ifdef Z7_LONG_PATH - if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - return BOOLToBool(::CreateDirectoryW(superPath, NULL)); - } - #endif - } - return false; -} - -/* - CreateDir2 returns true, if directory can contain files after the call (two cases): - 1) the directory already exists - 2) the directory was created - path must be WITHOUT trailing path separator. - - We need CreateDir2, since fileInfo.Find() for reserved names like "com8" - returns FILE instead of DIRECTORY. And we need to use SuperPath */ - -static bool CreateDir2(CFSTR path) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - if (::CreateDirectory(fs2fas(path), NULL)) - return true; - } - else - #endif - { - IF_USE_MAIN_PATH - if (::CreateDirectoryW(fs2us(path), NULL)) - return true; - #ifdef Z7_LONG_PATH - if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - { - if (::CreateDirectoryW(superPath, NULL)) - return true; - if (::GetLastError() != ERROR_ALREADY_EXISTS) - return false; - NFind::CFileInfo fi; - if (!fi.Find(us2fs(superPath))) - return false; - return fi.IsDir(); - } - } - #endif - } - if (::GetLastError() != ERROR_ALREADY_EXISTS) - return false; - NFind::CFileInfo fi; - if (!fi.Find(path)) - return false; - return fi.IsDir(); -} - -#endif // _WIN32 - -static bool CreateDir2(CFSTR path); - -bool CreateComplexDir(CFSTR _path) -{ - #ifdef _WIN32 - - { - const DWORD attrib = NFind::GetFileAttrib(_path); - if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) - return true; - } - - #ifndef UNDER_CE - - if (IsDriveRootPath_SuperAllowed(_path)) - return false; - - const unsigned prefixSize = GetRootPrefixSize(_path); - - #endif // UNDER_CE - - #else // _WIN32 - - // Posix - NFind::CFileInfo fi; - if (fi.Find(_path)) - { - if (fi.IsDir()) - return true; - } - - #endif // _WIN32 - - FString path (_path); - - int pos = path.ReverseFind_PathSepar(); - if (pos >= 0 && (unsigned)pos == path.Len() - 1) - { - if (path.Len() == 1) - return true; - path.DeleteBack(); - } - - const FString path2 (path); - pos = (int)path.Len(); - - for (;;) - { - if (CreateDir2(path)) - break; - if (::GetLastError() == ERROR_ALREADY_EXISTS) - return false; - pos = path.ReverseFind_PathSepar(); - if (pos < 0 || pos == 0) - return false; - - #if defined(_WIN32) && !defined(UNDER_CE) - if (pos == 1 && IS_PATH_SEPAR(path[0])) - return false; - if (prefixSize >= (unsigned)pos + 1) - return false; - #endif - - path.DeleteFrom((unsigned)pos); - } - - while (pos < (int)path2.Len()) - { - int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1)); - if (pos2 < 0) - pos = (int)path2.Len(); - else - pos += 1 + pos2; - path.SetFrom(path2, (unsigned)pos); - if (!CreateDir(path)) - return false; - } - - return true; -} - - -#ifdef _WIN32 - -bool DeleteFileAlways(CFSTR path) -{ - /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete. - SetFileAttrib("name:stream", ) changes attributes of main file. */ - { - DWORD attrib = NFind::GetFileAttrib(path); - if (attrib != INVALID_FILE_ATTRIBUTES - && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0 - && (attrib & FILE_ATTRIBUTE_READONLY) != 0) - { - if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY)) - return false; - } - } - - #ifndef _UNICODE - if (!g_IsNT) - { - if (::DeleteFile(fs2fas(path))) - return true; - } - else - #endif - { - /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")). - Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */ - IF_USE_MAIN_PATH - if (::DeleteFileW(fs2us(path))) - return true; - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - return BOOLToBool(::DeleteFileW(superPath)); - } - #endif - } - return false; -} - - - -bool RemoveDirWithSubItems(const FString &path) -{ - bool needRemoveSubItems = true; - { - NFind::CFileInfo fi; - if (!fi.Find(path)) - return false; - if (!fi.IsDir()) - { - ::SetLastError(ERROR_DIRECTORY); - return false; - } - if (fi.HasReparsePoint()) - needRemoveSubItems = false; - } - - if (needRemoveSubItems) - { - FString s (path); - s.Add_PathSepar(); - const unsigned prefixSize = s.Len(); - NFind::CEnumerator enumerator; - enumerator.SetDirPrefix(s); - NFind::CDirEntry fi; - bool isError = false; - DWORD lastError = 0; - while (enumerator.Next(fi)) - { - s.DeleteFrom(prefixSize); - s += fi.Name; - if (fi.IsDir()) - { - if (!RemoveDirWithSubItems(s)) - { - lastError = GetLastError(); - isError = true; - } - } - else if (!DeleteFileAlways(s)) - { - lastError = GetLastError(); - isError = false; - } - } - if (isError) - { - SetLastError(lastError); - return false; - } - } - - // we clear read-only attrib to remove read-only dir - if (!SetFileAttrib(path, 0)) - return false; - return RemoveDir(path); -} - -#endif // _WIN32 - -#ifdef UNDER_CE - -bool MyGetFullPathName(CFSTR path, FString &resFullPath) -{ - resFullPath = path; - return true; -} - -#else - -bool MyGetFullPathName(CFSTR path, FString &resFullPath) -{ - return GetFullPath(path, resFullPath); -} - -#ifdef _WIN32 - -/* Win10: SetCurrentDirectory() doesn't support long paths and - doesn't support super prefix "\\?\", if long path behavior is not - enabled in registry (LongPathsEnabled) and in manifest (longPathAware). */ - -bool SetCurrentDir(CFSTR path) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - return BOOLToBool(::SetCurrentDirectory(fs2fas(path))); - } - else - #endif - { - return BOOLToBool(::SetCurrentDirectoryW(fs2us(path))); - } -} - - -/* -we use system function GetCurrentDirectory() -new GetCurrentDirectory() DOCs: - - If the function fails, the return value is zero. - - If the function succeeds, the return value specifies - the number of characters that are written to the buffer, - not including the terminating null character. - - If the buffer is not large enough, the return value specifies - the required size of the buffer, in characters, - including the null-terminating character. - -GetCurrentDir() calls GetCurrentDirectory(). -GetCurrentDirectory() in win10 in tests: - the returned (path) does not end with a backslash, if - current directory is not root directory of drive. - But that behavior is not guarantied in specification docs. -*/ - -bool GetCurrentDir(FString &path) -{ - const unsigned kBufSize = MAX_PATH + 16; - path.Empty(); - - #ifndef _UNICODE - if (!g_IsNT) - { - TCHAR s[kBufSize + 1]; - s[0] = 0; - const DWORD len = ::GetCurrentDirectory(kBufSize, s); - if (len == 0 || len >= kBufSize) - return false; - s[kBufSize] = 0; // optional guard - path = fas2fs(s); - return true; - } - else - #endif - { - DWORD len; - { - WCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetCurrentDirectoryW(kBufSize, s); - if (len == 0) - return false; - if (len < kBufSize) - { - s[kBufSize] = 0; // optional guard - path = us2fs(s); - return true; - } - } - UString temp; - const DWORD len2 = ::GetCurrentDirectoryW(len, temp.GetBuf(len)); - if (len2 == 0) - return false; - temp.ReleaseBuf_CalcLen(len); - if (temp.Len() != len2 || len - 1 != len2) - { - /* it's unexpected case, if current dir of process - was changed between two function calls, - or some unexpected function implementation */ - // SetLastError((DWORD)E_FAIL); // we can set some error code - return false; - } - path = us2fs(temp); - return true; - } -} - -#endif // _WIN32 -#endif // UNDER_CE - - -bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) -{ - bool res = MyGetFullPathName(path, resDirPrefix); - if (!res) - resDirPrefix = path; - int pos = resDirPrefix.ReverseFind_PathSepar(); - pos++; - resFileName = resDirPrefix.Ptr((unsigned)pos); - resDirPrefix.DeleteFrom((unsigned)pos); - return res; -} - -bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) -{ - FString resFileName; - return GetFullPathAndSplit(path, resDirPrefix, resFileName); -} - - - -bool MyGetTempPath(FString &path) -{ - #ifdef _WIN32 - - /* - new DOCs for GetTempPathW(): - - The returned string ends with a backslash. - - The maximum possible return value is MAX_PATH+1 (261). - */ - - const unsigned kBufSize = MAX_PATH + 16; - DWORD len; - #ifndef _UNICODE - if (!g_IsNT) - { - TCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetTempPath(kBufSize, s); - path = fas2fs(s); - } - else - #endif - { - WCHAR s[kBufSize + 1]; - s[0] = 0; - len = ::GetTempPathW(kBufSize, s); - path = us2fs(s); - } - /* win10: GetTempPathW() doesn't set backslash at the end of path, - if (buffer_size == len_of(path_with_backslash)). - So we normalize path here: */ - NormalizeDirPathPrefix(path); - return (len != 0 && len < kBufSize); - - #else // !_WIN32 - - // FIXME: improve that code - path = STRING_PATH_SEPARATOR "tmp"; - const char *s; - if (NFind::DoesDirExist_FollowLink(path)) - s = STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR; - else - s = "." STRING_PATH_SEPARATOR; - path = s; - return true; - - #endif -} - - -bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile) -{ - UInt32 d = - #ifdef _WIN32 - (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); - #else - (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid()); - #endif - - for (unsigned i = 0; i < 100; i++) - { - postfix.Empty(); - if (addRandom) - { - char s[16]; - UInt32 val = d; - unsigned k; - for (k = 0; k < 8; k++) - { - const unsigned t = (unsigned)val & 0xF; - val >>= 4; - s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); - } - s[k] = '\0'; - if (outFile) - postfix.Add_Dot(); - postfix += s; - UInt32 step = GetTickCount() + 2; - if (step == 0) - step = 1; - d += step; - } - addRandom = true; - if (outFile) - postfix += ".tmp"; - FString path (prefix); - path += postfix; - if (NFind::DoesFileOrDirExist(path)) - { - SetLastError(ERROR_ALREADY_EXISTS); - continue; - } - if (outFile) - { - if (outFile->Create_NEW(path)) - return true; - } - else - { - if (CreateDir(path)) - return true; - } - const DWORD error = GetLastError(); - if (error != ERROR_FILE_EXISTS && - error != ERROR_ALREADY_EXISTS) - break; - } - postfix.Empty(); - return false; -} - -bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile) -{ - if (!Remove()) - return false; - _path.Empty(); - AString postfix; - if (!CreateTempFile2(prefix, false, postfix, outFile)) - return false; - _path = prefix; - _path += postfix; - _mustBeDeleted = true; - return true; -} - -bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile) -{ - if (!Remove()) - return false; - _path.Empty(); - FString tempPath; - if (!MyGetTempPath(tempPath)) - return false; - AString postfix; - tempPath += namePrefix; - if (!CreateTempFile2(tempPath, true, postfix, outFile)) - return false; - _path = tempPath; - _path += postfix; - _mustBeDeleted = true; - return true; -} - -bool CTempFile::Remove() -{ - if (!_mustBeDeleted) - return true; - _mustBeDeleted = !DeleteFileAlways(_path); - return !_mustBeDeleted; -} - -bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) -{ - // DWORD attrib = 0; - if (deleteDestBefore) - { - if (NFind::DoesFileExist_Raw(name)) - { - // attrib = NFind::GetFileAttrib(name); - if (!DeleteFileAlways(name)) - return false; - } - } - DisableDeleting(); - return MyMoveFile(_path, name); - - /* - if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) - { - DWORD attrib2 = NFind::GetFileAttrib(name); - if (attrib2 != INVALID_FILE_ATTRIBUTES) - SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY); - } - */ -} - -#ifdef _WIN32 -bool CTempDir::Create(CFSTR prefix) -{ - if (!Remove()) - return false; - _path.Empty(); - FString tempPath; - if (!MyGetTempPath(tempPath)) - return false; - tempPath += prefix; - AString postfix; - if (!CreateTempFile2(tempPath, true, postfix, NULL)) - return false; - _path = tempPath; - _path += postfix; - _mustBeDeleted = true; - return true; -} - -bool CTempDir::Remove() -{ - if (!_mustBeDeleted) - return true; - _mustBeDeleted = !RemoveDirWithSubItems(_path); - return !_mustBeDeleted; -} -#endif - - - -#ifndef _WIN32 - -bool RemoveDir(CFSTR path) -{ - return (rmdir(path) == 0); -} - - -static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) -{ - NWindows::NFile::NIO::COutFile outFile; - if (!outFile.Create_NEW(newFile)) - return FALSE; - - NWindows::NFile::NIO::CInFile inFile; - if (!inFile.Open(oldFile)) - return FALSE; - - char buf[1 << 14]; - - for (;;) - { - const ssize_t num = inFile.read_part(buf, sizeof(buf)); - if (num == 0) - return TRUE; - if (num < 0) - return FALSE; - size_t processed; - const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); - if (num2 != num || processed != (size_t)num) - return FALSE; - } -} - - -bool MyMoveFile(CFSTR oldFile, CFSTR newFile) -{ - int res = rename(oldFile, newFile); - if (res == 0) - return true; - if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) - return false; - - if (My_CopyFile(oldFile, newFile) == FALSE) - return false; - - struct stat info_file; - res = stat(oldFile, &info_file); - if (res != 0) - return false; - - /* - ret = chmod(dst,info_file.st_mode & g_umask.mask); - */ - return (unlink(oldFile) == 0); -} - - -bool CreateDir(CFSTR path) -{ - return (mkdir(path, 0777) == 0); // change it -} - -static bool CreateDir2(CFSTR path) -{ - return (mkdir(path, 0777) == 0); // change it -} - - -bool DeleteFileAlways(CFSTR path) -{ - return (remove(path) == 0); -} - -bool SetCurrentDir(CFSTR path) -{ - return (chdir(path) == 0); -} - - -bool GetCurrentDir(FString &path) -{ - path.Empty(); - - #define MY_PATH_MAX PATH_MAX - // #define MY_PATH_MAX 1024 - - char s[MY_PATH_MAX + 1]; - char *res = getcwd(s, MY_PATH_MAX); - if (res) - { - path = fas2fs(s); - return true; - } - { - // if (errno != ERANGE) return false; - #if defined(__GLIBC__) || defined(__APPLE__) - /* As an extension to the POSIX.1-2001 standard, glibc's getcwd() - allocates the buffer dynamically using malloc(3) if buf is NULL. */ - res = getcwd(NULL, 0); - if (res) - { - path = fas2fs(res); - ::free(res); - return true; - } - #endif - return false; - } -} - - - -// #undef UTIME_OMIT // to debug - -#ifndef UTIME_OMIT - /* we can define UTIME_OMIT for debian and another systems. - Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */ - // #define UTIME_OMIT -2 -#endif - - - - - -bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) -{ - // need testing - /* - struct utimbuf buf; - struct stat st; - UNUSED_VAR(cTime) - - printf("\nstat = %s\n", path); - int ret = stat(path, &st); - - if (ret == 0) - { - buf.actime = st.st_atime; - buf.modtime = st.st_mtime; - } - else - { - time_t cur_time = time(0); - buf.actime = cur_time; - buf.modtime = cur_time; - } - - if (aTime) - { - UInt32 ut; - if (NTime::FileTimeToUnixTime(*aTime, ut)) - buf.actime = ut; - } - - if (mTime) - { - UInt32 ut; - if (NTime::FileTimeToUnixTime(*mTime, ut)) - buf.modtime = ut; - } - - return utime(path, &buf) == 0; - */ - - // if (!aTime && !mTime) return true; - - struct timespec times[2]; - UNUSED_VAR(cTime) - - bool needChange; - needChange = FiTime_To_timespec(aTime, times[0]); - needChange |= FiTime_To_timespec(mTime, times[1]); - - /* - if (mTime) - { - printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); - } - */ - - if (!needChange) - return true; - const int flags = 0; // follow link - // = AT_SYMLINK_NOFOLLOW; // don't follow link - return utimensat(AT_FDCWD, path, times, flags) == 0; -} - - - -struct C_umask -{ - mode_t mask; - - C_umask() - { - /* by security reasons we restrict attributes according - with process's file mode creation mask (umask) */ - const mode_t um = umask(0); // octal :0022 is expected - mask = 0777 & (~um); // octal: 0755 is expected - umask(um); // restore the umask - // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); - - // mask = 0777; // debug we can disable the restriction: - } -}; - -static C_umask g_umask; - -// #define PRF(x) x; -#define PRF(x) - -#define TRACE_SetFileAttrib(msg) \ - PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg);) - -#define TRACE_chmod(s, mode) \ - PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode));) - -int my_chown(CFSTR path, uid_t owner, gid_t group) -{ - return chown(path, owner, group); -} - -bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) -{ - TRACE_SetFileAttrib("") - - struct stat st; - - bool use_lstat = true; - if (use_lstat) - { - if (lstat(path, &st) != 0) - { - TRACE_SetFileAttrib("bad lstat()") - return false; - } - // TRACE_chmod("lstat", st.st_mode); - } - else - { - if (stat(path, &st) != 0) - { - TRACE_SetFileAttrib("bad stat()") - return false; - } - } - - if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) - { - TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION") - st.st_mode = attrib >> 16; - if (S_ISDIR(st.st_mode)) - { - // user/7z must be able to create files in this directory - st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); - } - else if (!S_ISREG(st.st_mode)) - return true; - } - else if (S_ISLNK(st.st_mode)) - { - /* for most systems: permissions for symlinks are fixed to rwxrwxrwx. - so we don't need chmod() for symlinks. */ - return true; - // SetLastError(ENOSYS); - // return false; - } - else - { - TRACE_SetFileAttrib("Only Windows Attributes") - // Only Windows Attributes - if (S_ISDIR(st.st_mode) - || (attrib & FILE_ATTRIBUTE_READONLY) == 0) - return true; - st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions - } - - int res; - /* - if (S_ISLNK(st.st_mode)) - { - printf("\nfchmodat()\n"); - TRACE_chmod(path, (st.st_mode) & g_umask.mask) - // AT_SYMLINK_NOFOLLOW is not implemted still in Linux. - res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask, - S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0); - } - else - */ - { - TRACE_chmod(path, (st.st_mode) & g_umask.mask) - res = chmod(path, (st.st_mode) & g_umask.mask); - } - // TRACE_SetFileAttrib("End") - return (res == 0); -} - - -bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) -{ - PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName);) - return (link(existFileName, newFileName) == 0); -} - -#endif // !_WIN32 - -// #endif - -}}} +// Windows/FileDir.cpp + +#include "StdAfx.h" + + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Common/C_FileIO.h" +#include "../Common/MyBuffer2.h" +#include "../Common/StringConvert.h" +#endif + +#include "FileDir.h" +#include "FileFind.h" +#include "FileName.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +#ifndef _WIN32 + +static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) +{ + if (ft) + { +#if defined(_AIX) + ts.tv_sec = ft->tv_sec; + ts.tv_nsec = ft->tv_nsec; +#else + ts = *ft; +#endif + return true; + } + // else + { + ts.tv_sec = 0; + ts.tv_nsec = + #ifdef UTIME_OMIT + UTIME_OMIT; // -2 keep old timesptamp + #else + // UTIME_NOW; -1 // set to the current time + 0; + #endif + return false; + } +} +#endif + +namespace NWindows { +namespace NFile { +namespace NDir { + +#ifdef _WIN32 + +#ifndef UNDER_CE + +bool GetWindowsDir(FString &path) +{ + const unsigned kBufSize = MAX_PATH + 16; + UINT len; + #ifndef _UNICODE + if (!g_IsNT) + { + TCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetWindowsDirectory(s, kBufSize); + path = fas2fs(s); + } + else + #endif + { + WCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetWindowsDirectoryW(s, kBufSize); + path = us2fs(s); + } + return (len != 0 && len < kBufSize); +} + + +/* +new DOCs for GetSystemDirectory: + returned path does not end with a backslash unless the + system directory is the root directory. +*/ + +bool GetSystemDir(FString &path) +{ + const unsigned kBufSize = MAX_PATH + 16; + UINT len; + #ifndef _UNICODE + if (!g_IsNT) + { + TCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetSystemDirectory(s, kBufSize); + path = fas2fs(s); + } + else + #endif + { + WCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetSystemDirectoryW(s, kBufSize); + path = us2fs(s); + } + return (len != 0 && len < kBufSize); +} +#endif // UNDER_CE + + +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } + #endif + + HANDLE hDir = INVALID_HANDLE_VALUE; + IF_USE_MAIN_PATH + hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + #ifdef Z7_LONG_PATH + if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + } + #endif + + bool res = false; + if (hDir != INVALID_HANDLE_VALUE) + { + res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime)); + ::CloseHandle(hDir); + } + return res; +} + + + +bool SetFileAttrib(CFSTR path, DWORD attrib) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + if (::SetFileAttributes(fs2fas(path), attrib)) + return true; + } + else + #endif + { + IF_USE_MAIN_PATH + if (::SetFileAttributesW(fs2us(path), attrib)) + return true; + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + return BOOLToBool(::SetFileAttributesW(superPath, attrib)); + } + #endif + } + return false; +} + + +bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) +{ + #ifdef _WIN32 + if ((attrib & 0xF0000000) != 0) + attrib &= 0x3FFF; + #endif + return SetFileAttrib(path, attrib); +} + + +bool RemoveDir(CFSTR path) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + if (::RemoveDirectory(fs2fas(path))) + return true; + } + else + #endif + { + IF_USE_MAIN_PATH + if (::RemoveDirectoryW(fs2us(path))) + return true; + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + return BOOLToBool(::RemoveDirectoryW(superPath)); + } + #endif + } + return false; +} + + +// When moving a directory, oldFile and newFile must be on the same drive. + +bool MyMoveFile(CFSTR oldFile, CFSTR newFile) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + if (::MoveFile(fs2fas(oldFile), fs2fas(newFile))) + return true; + } + else + #endif + { + IF_USE_MAIN_PATH_2(oldFile, newFile) + { + if (::MoveFileW(fs2us(oldFile), fs2us(newFile))) + return true; + } + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH_2) + { + UString d1, d2; + if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) + return BOOLToBool(::MoveFileW(d1, d2)); + } + #endif + } + return false; +} + +#if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500 +static DWORD WINAPI CopyProgressRoutine_to_ICopyFileProgress( + LARGE_INTEGER TotalFileSize, // file size + LARGE_INTEGER TotalBytesTransferred, // bytes transferred + LARGE_INTEGER /* StreamSize */, // bytes in stream + LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream + DWORD /* dwStreamNumber */, // current stream + DWORD /* dwCallbackReason */, // callback reason + HANDLE /* hSourceFile */, // handle to source file + HANDLE /* hDestinationFile */, // handle to destination file + LPVOID lpData // from CopyFileEx +) +{ + return ((ICopyFileProgress *)lpData)->CopyFileProgress( + (UInt64)TotalFileSize.QuadPart, + (UInt64)TotalBytesTransferred.QuadPart); +} +#endif + +bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, + ICopyFileProgress *progress) +{ +#if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500 +#ifndef _UNICODE + if (g_IsNT) +#endif + if (progress) + { + IF_USE_MAIN_PATH_2(oldFile, newFile) + { + if (::MoveFileWithProgressW(fs2us(oldFile), fs2us(newFile), + CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED)) + return true; + if (::GetLastError() == ERROR_REQUEST_ABORTED) + return false; + } + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH_2) + { + UString d1, d2; + if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) + return BOOLToBool(::MoveFileWithProgressW(d1, d2, + CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED)); + } + #endif + return false; + } +#else + UNUSED_VAR(progress) +#endif + return MyMoveFile(oldFile, newFile); +} + +#ifndef UNDER_CE +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 +#define Z7_USE_DYN_CreateHardLink +#endif + +#ifdef Z7_USE_DYN_CreateHardLink +EXTERN_C_BEGIN +typedef BOOL (WINAPI *Func_CreateHardLinkW)( + LPCWSTR lpFileName, + LPCWSTR lpExistingFileName, + LPSECURITY_ATTRIBUTES lpSecurityAttributes + ); +EXTERN_C_END +#endif +#endif // UNDER_CE + +bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + /* + if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL)) + return true; + */ + } + else + #endif + { +#ifdef Z7_USE_DYN_CreateHardLink + const + Func_CreateHardLinkW + my_CreateHardLinkW = Z7_GET_PROC_ADDRESS( + Func_CreateHardLinkW, ::GetModuleHandleW(L"kernel32.dll"), + "CreateHardLinkW"); + if (!my_CreateHardLinkW) + return false; + #define MY_CreateHardLinkW my_CreateHardLinkW +#else + #define MY_CreateHardLinkW CreateHardLinkW +#endif + IF_USE_MAIN_PATH_2(newFileName, existFileName) + { + if (MY_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL)) + return true; + } + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH_2) + { + UString d1, d2; + if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2)) + return BOOLToBool(MY_CreateHardLinkW(d1, d2, NULL)); + } + #endif + } + return false; +} + + +/* +WinXP-64 CreateDir(): + "" - ERROR_PATH_NOT_FOUND + \ - ERROR_ACCESS_DENIED + C:\ - ERROR_ACCESS_DENIED, if there is such drive, + + D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive, + C:\nonExistent\folder - ERROR_PATH_NOT_FOUND + + C:\existFolder - ERROR_ALREADY_EXISTS + C:\existFolder\ - ERROR_ALREADY_EXISTS + + C:\folder - OK + C:\folder\ - OK + + \\Server\nonExistent - ERROR_BAD_NETPATH + \\Server\Share_Readonly - ERROR_ACCESS_DENIED + \\Server\Share - ERROR_ALREADY_EXISTS + + \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED + \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS +*/ + +bool CreateDir(CFSTR path) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + if (::CreateDirectory(fs2fas(path), NULL)) + return true; + } + else + #endif + { + IF_USE_MAIN_PATH + if (::CreateDirectoryW(fs2us(path), NULL)) + return true; + #ifdef Z7_LONG_PATH + if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + return BOOLToBool(::CreateDirectoryW(superPath, NULL)); + } + #endif + } + return false; +} + +/* + CreateDir2 returns true, if directory can contain files after the call (two cases): + 1) the directory already exists + 2) the directory was created + path must be WITHOUT trailing path separator. + + We need CreateDir2, since fileInfo.Find() for reserved names like "com8" + returns FILE instead of DIRECTORY. And we need to use SuperPath */ + +static bool CreateDir2(CFSTR path) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + if (::CreateDirectory(fs2fas(path), NULL)) + return true; + } + else + #endif + { + IF_USE_MAIN_PATH + if (::CreateDirectoryW(fs2us(path), NULL)) + return true; + #ifdef Z7_LONG_PATH + if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + { + if (::CreateDirectoryW(superPath, NULL)) + return true; + if (::GetLastError() != ERROR_ALREADY_EXISTS) + return false; + NFind::CFileInfo fi; + if (!fi.Find(us2fs(superPath))) + return false; + return fi.IsDir(); + } + } + #endif + } + if (::GetLastError() != ERROR_ALREADY_EXISTS) + return false; + NFind::CFileInfo fi; + if (!fi.Find(path)) + return false; + return fi.IsDir(); +} + +#endif // _WIN32 + +static bool CreateDir2(CFSTR path); + +bool CreateComplexDir(CFSTR _path) +{ + #ifdef _WIN32 + + { + const DWORD attrib = NFind::GetFileAttrib(_path); + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + return true; + } + + #ifndef UNDER_CE + + if (IsDriveRootPath_SuperAllowed(_path)) + return false; + + const unsigned prefixSize = GetRootPrefixSize(_path); + + #endif // UNDER_CE + + #else // _WIN32 + + // Posix + NFind::CFileInfo fi; + if (fi.Find(_path)) + { + if (fi.IsDir()) + return true; + } + + #endif // _WIN32 + + FString path (_path); + + int pos = path.ReverseFind_PathSepar(); + if (pos >= 0 && (unsigned)pos == path.Len() - 1) + { + if (path.Len() == 1) + return true; + path.DeleteBack(); + } + + const FString path2 (path); + pos = (int)path.Len(); + + for (;;) + { + if (CreateDir2(path)) + break; + if (::GetLastError() == ERROR_ALREADY_EXISTS) + return false; + pos = path.ReverseFind_PathSepar(); + if (pos < 0 || pos == 0) + return false; + + #if defined(_WIN32) && !defined(UNDER_CE) + if (pos == 1 && IS_PATH_SEPAR(path[0])) + return false; + if (prefixSize >= (unsigned)pos + 1) + return false; + #endif + + path.DeleteFrom((unsigned)pos); + } + + while (pos < (int)path2.Len()) + { + int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1)); + if (pos2 < 0) + pos = (int)path2.Len(); + else + pos += 1 + pos2; + path.SetFrom(path2, (unsigned)pos); + if (!CreateDir(path)) + return false; + } + + return true; +} + + +#ifdef _WIN32 + +bool DeleteFileAlways(CFSTR path) +{ + /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete. + SetFileAttrib("name:stream", ) changes attributes of main file. */ + { + DWORD attrib = NFind::GetFileAttrib(path); + if (attrib != INVALID_FILE_ATTRIBUTES + && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0 + && (attrib & FILE_ATTRIBUTE_READONLY) != 0) + { + if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY)) + return false; + } + } + + #ifndef _UNICODE + if (!g_IsNT) + { + if (::DeleteFile(fs2fas(path))) + return true; + } + else + #endif + { + /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")). + Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */ + IF_USE_MAIN_PATH + if (::DeleteFileW(fs2us(path))) + return true; + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + return BOOLToBool(::DeleteFileW(superPath)); + } + #endif + } + return false; +} + + + +bool RemoveDirWithSubItems(const FString &path) +{ + bool needRemoveSubItems = true; + { + NFind::CFileInfo fi; + if (!fi.Find(path)) + return false; + if (!fi.IsDir()) + { + ::SetLastError(ERROR_DIRECTORY); + return false; + } + if (fi.HasReparsePoint()) + needRemoveSubItems = false; + } + + if (needRemoveSubItems) + { + FString s (path); + s.Add_PathSepar(); + const unsigned prefixSize = s.Len(); + NFind::CEnumerator enumerator; + enumerator.SetDirPrefix(s); + NFind::CDirEntry fi; + bool isError = false; + DWORD lastError = 0; + while (enumerator.Next(fi)) + { + s.DeleteFrom(prefixSize); + s += fi.Name; + if (fi.IsDir()) + { + if (!RemoveDirWithSubItems(s)) + { + lastError = GetLastError(); + isError = true; + } + } + else if (!DeleteFileAlways(s)) + { + lastError = GetLastError(); + isError = false; + } + } + if (isError) + { + SetLastError(lastError); + return false; + } + } + + // we clear read-only attrib to remove read-only dir + if (!SetFileAttrib(path, 0)) + return false; + return RemoveDir(path); +} + +#endif // _WIN32 + +#ifdef UNDER_CE + +bool MyGetFullPathName(CFSTR path, FString &resFullPath) +{ + resFullPath = path; + return true; +} + +#else + +bool MyGetFullPathName(CFSTR path, FString &resFullPath) +{ + return GetFullPath(path, resFullPath); +} + +#ifdef _WIN32 + +/* Win10: SetCurrentDirectory() doesn't support long paths and + doesn't support super prefix "\\?\", if long path behavior is not + enabled in registry (LongPathsEnabled) and in manifest (longPathAware). */ + +bool SetCurrentDir(CFSTR path) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + return BOOLToBool(::SetCurrentDirectory(fs2fas(path))); + } + else + #endif + { + return BOOLToBool(::SetCurrentDirectoryW(fs2us(path))); + } +} + + +/* +we use system function GetCurrentDirectory() +new GetCurrentDirectory() DOCs: + - If the function fails, the return value is zero. + - If the function succeeds, the return value specifies + the number of characters that are written to the buffer, + not including the terminating null character. + - If the buffer is not large enough, the return value specifies + the required size of the buffer, in characters, + including the null-terminating character. + +GetCurrentDir() calls GetCurrentDirectory(). +GetCurrentDirectory() in win10 in tests: + the returned (path) does not end with a backslash, if + current directory is not root directory of drive. + But that behavior is not guarantied in specification docs. +*/ + +bool GetCurrentDir(FString &path) +{ + const unsigned kBufSize = MAX_PATH + 16; + path.Empty(); + + #ifndef _UNICODE + if (!g_IsNT) + { + TCHAR s[kBufSize + 1]; + s[0] = 0; + const DWORD len = ::GetCurrentDirectory(kBufSize, s); + if (len == 0 || len >= kBufSize) + return false; + s[kBufSize] = 0; // optional guard + path = fas2fs(s); + return true; + } + else + #endif + { + DWORD len; + { + WCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetCurrentDirectoryW(kBufSize, s); + if (len == 0) + return false; + if (len < kBufSize) + { + s[kBufSize] = 0; // optional guard + path = us2fs(s); + return true; + } + } + UString temp; + const DWORD len2 = ::GetCurrentDirectoryW(len, temp.GetBuf(len)); + if (len2 == 0) + return false; + temp.ReleaseBuf_CalcLen(len); + if (temp.Len() != len2 || len - 1 != len2) + { + /* it's unexpected case, if current dir of process + was changed between two function calls, + or some unexpected function implementation */ + // SetLastError((DWORD)E_FAIL); // we can set some error code + return false; + } + path = us2fs(temp); + return true; + } +} + +#endif // _WIN32 +#endif // UNDER_CE + + +bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) +{ + bool res = MyGetFullPathName(path, resDirPrefix); + if (!res) + resDirPrefix = path; + int pos = resDirPrefix.ReverseFind_PathSepar(); + pos++; + resFileName = resDirPrefix.Ptr((unsigned)pos); + resDirPrefix.DeleteFrom((unsigned)pos); + return res; +} + +bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) +{ + FString resFileName; + return GetFullPathAndSplit(path, resDirPrefix, resFileName); +} + + + +bool MyGetTempPath(FString &path) +{ + #ifdef _WIN32 + + /* + new DOCs for GetTempPathW(): + - The returned string ends with a backslash. + - The maximum possible return value is MAX_PATH+1 (261). + */ + + const unsigned kBufSize = MAX_PATH + 16; + DWORD len; + #ifndef _UNICODE + if (!g_IsNT) + { + TCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetTempPath(kBufSize, s); + path = fas2fs(s); + } + else + #endif + { + WCHAR s[kBufSize + 1]; + s[0] = 0; + len = ::GetTempPathW(kBufSize, s); + path = us2fs(s); + } + /* win10: GetTempPathW() doesn't set backslash at the end of path, + if (buffer_size == len_of(path_with_backslash)). + So we normalize path here: */ + NormalizeDirPathPrefix(path); + return (len != 0 && len < kBufSize); + + #else // !_WIN32 + + // FIXME: improve that code + path = STRING_PATH_SEPARATOR "tmp"; + const char *s; + if (NFind::DoesDirExist_FollowLink(path)) + s = STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR; + else + s = "." STRING_PATH_SEPARATOR; + path = s; + return true; + + #endif +} + + +bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile) +{ + UInt32 d = + #ifdef _WIN32 + (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + #else + (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid()); + #endif + + for (unsigned i = 0; i < 100; i++) + { + postfix.Empty(); + if (addRandom) + { + char s[16]; + UInt32 val = d; + unsigned k; + for (k = 0; k < 8; k++) + { + const unsigned t = (unsigned)val & 0xF; + val >>= 4; + s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + } + s[k] = '\0'; + if (outFile) + postfix.Add_Dot(); + postfix += s; + UInt32 step = GetTickCount() + 2; + if (step == 0) + step = 1; + d += step; + } + addRandom = true; + if (outFile) + postfix += ".tmp"; + FString path (prefix); + path += postfix; + if (NFind::DoesFileOrDirExist(path)) + { + SetLastError(ERROR_ALREADY_EXISTS); + continue; + } + if (outFile) + { + if (outFile->Create_NEW(path)) + return true; + } + else + { + if (CreateDir(path)) + return true; + } + const DWORD error = GetLastError(); + if (error != ERROR_FILE_EXISTS && + error != ERROR_ALREADY_EXISTS) + break; + } + postfix.Empty(); + return false; +} + +bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile) +{ + if (!Remove()) + return false; + _path.Empty(); + AString postfix; + if (!CreateTempFile2(prefix, false, postfix, outFile)) + return false; + _path = prefix; + _path += postfix; + _mustBeDeleted = true; + return true; +} + +bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile) +{ + if (!Remove()) + return false; + _path.Empty(); + FString tempPath; + if (!MyGetTempPath(tempPath)) + return false; + AString postfix; + tempPath += namePrefix; + if (!CreateTempFile2(tempPath, true, postfix, outFile)) + return false; + _path = tempPath; + _path += postfix; + _mustBeDeleted = true; + return true; +} + +bool CTempFile::Remove() +{ + if (!_mustBeDeleted) + return true; + _mustBeDeleted = !DeleteFileAlways(_path); + return !_mustBeDeleted; +} + +bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore, + ICopyFileProgress *progress) +{ + if (deleteDestBefore) + { + if (NFind::DoesFileExist_Raw(name)) + { + // attrib = NFind::GetFileAttrib(name); + if (!DeleteFileAlways(name)) + return false; + } + } + DisableDeleting(); + // if (!progress) return MyMoveFile(_path, name); + return MyMoveFile_with_Progress(_path, name, progress); + /* + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) + { + DWORD attrib2 = NFind::GetFileAttrib(name); + if (attrib2 != INVALID_FILE_ATTRIBUTES) + SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY); + } + */ +} + +#ifdef _WIN32 +bool CTempDir::Create(CFSTR prefix) +{ + if (!Remove()) + return false; + _path.Empty(); + FString tempPath; + if (!MyGetTempPath(tempPath)) + return false; + tempPath += prefix; + AString postfix; + if (!CreateTempFile2(tempPath, true, postfix, NULL)) + return false; + _path = tempPath; + _path += postfix; + _mustBeDeleted = true; + return true; +} + +bool CTempDir::Remove() +{ + if (!_mustBeDeleted) + return true; + _mustBeDeleted = !RemoveDirWithSubItems(_path); + return !_mustBeDeleted; +} +#endif + + + +#ifndef _WIN32 + +bool RemoveDir(CFSTR path) +{ + return (rmdir(path) == 0); +} + + +static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile, ICopyFileProgress *progress) +{ + { + NIO::COutFile outFile; + if (!outFile.Create_NEW(newFile)) + return FALSE; + NIO::CInFile inFile; + if (!inFile.Open(oldFile)) + return FALSE; + + const size_t k_BufSize = 1 << 16; + CAlignedBuffer1 buf(k_BufSize); + + UInt64 length = 0; + if (progress && !inFile.GetLength(length)) + length = 0; + UInt64 prev = 0; + UInt64 cur = 0; + for (;;) + { + const ssize_t num = inFile.read_part(buf, k_BufSize); + if (num == 0) + return TRUE; + if (num < 0) + break; + size_t processed; + const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); + if (num2 != num || processed != (size_t)num) + break; + cur += (size_t)num2; + if (progress && cur - prev >= (1u << 20)) + { + prev = cur; + if (progress->CopyFileProgress(length, cur) != PROGRESS_CONTINUE) + { + errno = EINTR; // instead of WIN32::ERROR_REQUEST_ABORTED + break; + } + } + } + } + // There is file IO error or process was interrupted by user. + // We close output file and delete it. + // DeleteFileAlways doesn't change errno (if successed), but we restore errno. + const int errno_save = errno; + DeleteFileAlways(newFile); + errno = errno_save; + return FALSE; +} + + +bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, + ICopyFileProgress *progress) +{ + int res = rename(oldFile, newFile); + if (res == 0) + return true; + if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) + return false; + + if (My_CopyFile(oldFile, newFile, progress) == FALSE) + return false; + + struct stat info_file; + res = stat(oldFile, &info_file); + if (res != 0) + return false; + + /* + ret = chmod(dst,info_file.st_mode & g_umask.mask); + */ + return (unlink(oldFile) == 0); +} + +bool MyMoveFile(CFSTR oldFile, CFSTR newFile) +{ + return MyMoveFile_with_Progress(oldFile, newFile, NULL); +} + + +bool CreateDir(CFSTR path) +{ + return (mkdir(path, 0777) == 0); // change it +} + +static bool CreateDir2(CFSTR path) +{ + return (mkdir(path, 0777) == 0); // change it +} + + +bool DeleteFileAlways(CFSTR path) +{ + return (remove(path) == 0); +} + +bool SetCurrentDir(CFSTR path) +{ + return (chdir(path) == 0); +} + + +bool GetCurrentDir(FString &path) +{ + path.Empty(); + + #define MY_PATH_MAX PATH_MAX + // #define MY_PATH_MAX 1024 + + char s[MY_PATH_MAX + 1]; + char *res = getcwd(s, MY_PATH_MAX); + if (res) + { + path = fas2fs(s); + return true; + } + { + // if (errno != ERANGE) return false; + #if defined(__GLIBC__) || defined(__APPLE__) + /* As an extension to the POSIX.1-2001 standard, glibc's getcwd() + allocates the buffer dynamically using malloc(3) if buf is NULL. */ + res = getcwd(NULL, 0); + if (res) + { + path = fas2fs(res); + ::free(res); + return true; + } + #endif + return false; + } +} + + + +// #undef UTIME_OMIT // to debug + +#ifndef UTIME_OMIT + /* we can define UTIME_OMIT for debian and another systems. + Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */ + // #define UTIME_OMIT -2 +#endif + + + + + +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) +{ + // need testing + /* + struct utimbuf buf; + struct stat st; + UNUSED_VAR(cTime) + + printf("\nstat = %s\n", path); + int ret = stat(path, &st); + + if (ret == 0) + { + buf.actime = st.st_atime; + buf.modtime = st.st_mtime; + } + else + { + time_t cur_time = time(0); + buf.actime = cur_time; + buf.modtime = cur_time; + } + + if (aTime) + { + UInt32 ut; + if (NTime::FileTimeToUnixTime(*aTime, ut)) + buf.actime = ut; + } + + if (mTime) + { + UInt32 ut; + if (NTime::FileTimeToUnixTime(*mTime, ut)) + buf.modtime = ut; + } + + return utime(path, &buf) == 0; + */ + + // if (!aTime && !mTime) return true; + + struct timespec times[2]; + UNUSED_VAR(cTime) + + bool needChange; + needChange = FiTime_To_timespec(aTime, times[0]); + needChange |= FiTime_To_timespec(mTime, times[1]); + + /* + if (mTime) + { + printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); + } + */ + + if (!needChange) + return true; + const int flags = 0; // follow link + // = AT_SYMLINK_NOFOLLOW; // don't follow link + return utimensat(AT_FDCWD, path, times, flags) == 0; +} + + + +struct C_umask +{ + mode_t mask; + + C_umask() + { + /* by security reasons we restrict attributes according + with process's file mode creation mask (umask) */ + const mode_t um = umask(0); // octal :0022 is expected + mask = 0777 & (~um); // octal: 0755 is expected + umask(um); // restore the umask + // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); + + // mask = 0777; // debug we can disable the restriction: + } +}; + +static C_umask g_umask; + +// #define PRF(x) x; +#define PRF(x) + +#define TRACE_SetFileAttrib(msg) \ + PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg);) + +#define TRACE_chmod(s, mode) \ + PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode));) + +int my_chown(CFSTR path, uid_t owner, gid_t group) +{ + return chown(path, owner, group); +} + +bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) +{ + TRACE_SetFileAttrib("") + + struct stat st; + + bool use_lstat = true; + if (use_lstat) + { + if (lstat(path, &st) != 0) + { + TRACE_SetFileAttrib("bad lstat()") + return false; + } + // TRACE_chmod("lstat", st.st_mode); + } + else + { + if (stat(path, &st) != 0) + { + TRACE_SetFileAttrib("bad stat()") + return false; + } + } + + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) + { + TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION") + st.st_mode = attrib >> 16; + if (S_ISDIR(st.st_mode)) + { + // user/7z must be able to create files in this directory + st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); + } + else if (!S_ISREG(st.st_mode)) + return true; + } + else if (S_ISLNK(st.st_mode)) + { + /* for most systems: permissions for symlinks are fixed to rwxrwxrwx. + so we don't need chmod() for symlinks. */ + return true; + // SetLastError(ENOSYS); + // return false; + } + else + { + TRACE_SetFileAttrib("Only Windows Attributes") + // Only Windows Attributes + if (S_ISDIR(st.st_mode) + || (attrib & FILE_ATTRIBUTE_READONLY) == 0) + return true; + st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions + } + + int res; + /* + if (S_ISLNK(st.st_mode)) + { + printf("\nfchmodat()\n"); + TRACE_chmod(path, (st.st_mode) & g_umask.mask) + // AT_SYMLINK_NOFOLLOW is not implemted still in Linux. + res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask, + S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0); + } + else + */ + { + TRACE_chmod(path, (st.st_mode) & g_umask.mask) + res = chmod(path, (st.st_mode) & g_umask.mask); + } + // TRACE_SetFileAttrib("End") + return (res == 0); +} + + +bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) +{ + PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName);) + return (link(existFileName, newFileName) == 0); +} + +#endif // !_WIN32 + +// #endif + +}}} diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 774fa898e..74675eea1 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h @@ -1,135 +1,156 @@ -// Windows/FileDir.h - -#ifndef ZIP7_INC_WINDOWS_FILE_DIR_H -#define ZIP7_INC_WINDOWS_FILE_DIR_H - -#include "../Common/MyString.h" - -#include "FileIO.h" - -namespace NWindows { -namespace NFile { -namespace NDir { - -bool GetWindowsDir(FString &path); -bool GetSystemDir(FString &path); - -/* -WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file -but linux : allows unix time = 0 in filesystem -*/ - -bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); - - -#ifdef _WIN32 - -bool SetFileAttrib(CFSTR path, DWORD attrib); - -/* - Some programs store posix attributes in high 16 bits of windows attributes field. - Also some programs use additional flag markers: 0x8000 or 0x4000. - SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute - bits that are related to current system only. -*/ -#else - -int my_chown(CFSTR path, uid_t owner, gid_t group); - -#endif - -bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); - - -bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); - -#ifndef UNDER_CE -bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); -#endif - -bool RemoveDir(CFSTR path); -bool CreateDir(CFSTR path); - -/* CreateComplexDir returns true, if directory can contain files after the call (two cases): - 1) the directory already exists (network shares and drive paths are supported) - 2) the directory was created - path can be WITH or WITHOUT trailing path separator. */ - -bool CreateComplexDir(CFSTR path); - -bool DeleteFileAlways(CFSTR name); -bool RemoveDirWithSubItems(const FString &path); - -bool MyGetFullPathName(CFSTR path, FString &resFullPath); -bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); -bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix); - -#ifndef UNDER_CE - -bool SetCurrentDir(CFSTR path); -bool GetCurrentDir(FString &resultPath); - -#endif - -bool MyGetTempPath(FString &resultPath); - -bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile); - -class CTempFile MY_UNCOPYABLE -{ - bool _mustBeDeleted; - FString _path; - void DisableDeleting() { _mustBeDeleted = false; } -public: - CTempFile(): _mustBeDeleted(false) {} - ~CTempFile() { Remove(); } - const FString &GetPath() const { return _path; } - bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix - bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); - bool Remove(); - bool MoveTo(CFSTR name, bool deleteDestBefore); -}; - - -#ifdef _WIN32 -class CTempDir MY_UNCOPYABLE -{ - bool _mustBeDeleted; - FString _path; -public: - CTempDir(): _mustBeDeleted(false) {} - ~CTempDir() { Remove(); } - const FString &GetPath() const { return _path; } - void DisableDeleting() { _mustBeDeleted = false; } - bool Create(CFSTR namePrefix) ; - bool Remove(); -}; -#endif - - -#if !defined(UNDER_CE) -class CCurrentDirRestorer MY_UNCOPYABLE -{ - FString _path; -public: - bool NeedRestore; - - CCurrentDirRestorer(): NeedRestore(true) - { - GetCurrentDir(_path); - } - ~CCurrentDirRestorer() - { - if (!NeedRestore) - return; - FString s; - if (GetCurrentDir(s)) - if (s != _path) - SetCurrentDir(_path); - } -}; -#endif - -}}} - -#endif +// Windows/FileDir.h + +#ifndef ZIP7_INC_WINDOWS_FILE_DIR_H +#define ZIP7_INC_WINDOWS_FILE_DIR_H + +#include "../Common/MyString.h" + +#include "FileIO.h" + +namespace NWindows { +namespace NFile { +namespace NDir { + +bool GetWindowsDir(FString &path); +bool GetSystemDir(FString &path); + +/* +WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file +but linux : allows unix time = 0 in filesystem +*/ + +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); + + +#ifdef _WIN32 + +bool SetFileAttrib(CFSTR path, DWORD attrib); + +/* + Some programs store posix attributes in high 16 bits of windows attributes field. + Also some programs use additional flag markers: 0x8000 or 0x4000. + SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute + bits that are related to current system only. +*/ +#else + +int my_chown(CFSTR path, uid_t owner, gid_t group); + +#endif + +bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); + + +#ifndef _WIN32 +#define PROGRESS_CONTINUE 0 +#define PROGRESS_CANCEL 1 +// #define PROGRESS_STOP 2 +// #define PROGRESS_QUIET 3 +#endif +Z7_PURE_INTERFACES_BEGIN +DECLARE_INTERFACE(ICopyFileProgress) +{ + // in: total, current: include all/processed alt streams. + // it returns PROGRESS_CONTINUE or PROGRESS_CANCEL. + virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) = 0; +}; +Z7_PURE_INTERFACES_END + +bool MyMoveFile(CFSTR existFileName, CFSTR newFileName); +// (progress == NULL) is allowed +bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, + ICopyFileProgress *progress); + + +#ifndef UNDER_CE +bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName); +#endif + +bool RemoveDir(CFSTR path); +bool CreateDir(CFSTR path); + +/* CreateComplexDir returns true, if directory can contain files after the call (two cases): + 1) the directory already exists (network shares and drive paths are supported) + 2) the directory was created + path can be WITH or WITHOUT trailing path separator. */ + +bool CreateComplexDir(CFSTR path); + +bool DeleteFileAlways(CFSTR name); +bool RemoveDirWithSubItems(const FString &path); + +bool MyGetFullPathName(CFSTR path, FString &resFullPath); +bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); +bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix); + +#ifndef UNDER_CE + +bool SetCurrentDir(CFSTR path); +bool GetCurrentDir(FString &resultPath); + +#endif + +bool MyGetTempPath(FString &resultPath); + +bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile); + +class CTempFile MY_UNCOPYABLE +{ + bool _mustBeDeleted; + FString _path; + void DisableDeleting() { _mustBeDeleted = false; } +public: + CTempFile(): _mustBeDeleted(false) {} + ~CTempFile() { Remove(); } + const FString &GetPath() const { return _path; } + bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix + bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile); + bool Remove(); + // bool MoveTo(CFSTR name, bool deleteDestBefore); + bool MoveTo(CFSTR name, bool deleteDestBefore, + ICopyFileProgress *progress); +}; + + +#ifdef _WIN32 +class CTempDir MY_UNCOPYABLE +{ + bool _mustBeDeleted; + FString _path; +public: + CTempDir(): _mustBeDeleted(false) {} + ~CTempDir() { Remove(); } + const FString &GetPath() const { return _path; } + void DisableDeleting() { _mustBeDeleted = false; } + bool Create(CFSTR namePrefix) ; + bool Remove(); +}; +#endif + + +#if !defined(UNDER_CE) +class CCurrentDirRestorer MY_UNCOPYABLE +{ + FString _path; +public: + bool NeedRestore; + + CCurrentDirRestorer(): NeedRestore(true) + { + GetCurrentDir(_path); + } + ~CCurrentDirRestorer() + { + if (!NeedRestore) + return; + FString s; + if (GetCurrentDir(s)) + if (s != _path) + SetCurrentDir(_path); + } +}; +#endif + +}}} + +#endif diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp index 54e4590ee..ca387f609 100644 --- a/CPP/Windows/FileFind.cpp +++ b/CPP/Windows/FileFind.cpp @@ -1,1442 +1,1442 @@ -// Windows/FileFind.cpp - -#include "StdAfx.h" - -// #include - -#ifndef _WIN32 -#include /* Definition of AT_* constants */ -#include "TimeUtils.h" -// for major -// #include -#endif - -#include "FileFind.h" -#include "FileIO.h" -#include "FileName.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NName; - -#if defined(_WIN32) && !defined(UNDER_CE) - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502 // Win2003 -#define Z7_USE_DYN_FindFirstStream -#endif - -#ifdef Z7_USE_DYN_FindFirstStream - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -EXTERN_C_BEGIN - -typedef enum -{ - My_FindStreamInfoStandard, - My_FindStreamInfoMaxInfoLevel -} MY_STREAM_INFO_LEVELS; - -typedef struct -{ - LARGE_INTEGER StreamSize; - WCHAR cStreamName[MAX_PATH + 36]; -} MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; - -typedef HANDLE (WINAPI *Func_FindFirstStreamW)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, - LPVOID findStreamData, DWORD flags); - -typedef BOOL (APIENTRY *Func_FindNextStreamW)(HANDLE findStream, LPVOID findStreamData); - -EXTERN_C_END - -#else - -#define MY_WIN32_FIND_STREAM_DATA WIN32_FIND_STREAM_DATA -#define My_FindStreamInfoStandard FindStreamInfoStandard - -#endif -#endif // defined(_WIN32) && !defined(UNDER_CE) - - -namespace NWindows { -namespace NFile { - - -#ifdef _WIN32 -#ifdef Z7_DEVICE_FILE -namespace NSystem -{ -bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); -} -#endif -#endif - -namespace NFind { - -/* -#ifdef _WIN32 -#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; -#else -#define MY_CLEAR_FILETIME(ft) ft.tv_sec = 0; ft.tv_nsec = 0; -#endif -*/ - -void CFileInfoBase::ClearBase() throw() -{ - Size = 0; - FiTime_Clear(CTime); - FiTime_Clear(ATime); - FiTime_Clear(MTime); - - #ifdef _WIN32 - Attrib = 0; - // ReparseTag = 0; - IsAltStream = false; - IsDevice = false; - #else - dev = 0; - ino = 0; - mode = 0; - nlink = 0; - uid = 0; - gid = 0; - rdev = 0; - #endif -} - - -bool CFileInfoBase::SetAs_StdInFile() -{ - ClearBase(); - Size = (UInt64)(Int64)-1; - NTime::GetCurUtc_FiTime(MTime); - CTime = ATime = MTime; - -#ifdef _WIN32 - - /* in GUI mode : GetStdHandle(STD_INPUT_HANDLE) returns NULL, - and it doesn't set LastError. */ -#if 1 - SetLastError(0); - const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); - if (!h || h == INVALID_HANDLE_VALUE) - { - if (GetLastError() == 0) - SetLastError(ERROR_INVALID_HANDLE); - return false; - } - BY_HANDLE_FILE_INFORMATION info; - if (GetFileInformationByHandle(h, &info) - && info.dwVolumeSerialNumber) - { - Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; - // FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; - // NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1; - Attrib = info.dwFileAttributes; - CTime = info.ftCreationTime; - ATime = info.ftLastAccessTime; - MTime = info.ftLastWriteTime; - } -#if 0 - printf( - "\ndwFileAttributes = %8x" - "\nftCreationTime = %8x" - "\nftLastAccessTime = %8x" - "\nftLastWriteTime = %8x" - "\ndwVolumeSerialNumber = %8x" - "\nnFileSizeHigh = %8x" - "\nnFileSizeLow = %8x" - "\nnNumberOfLinks = %8x" - "\nnFileIndexHigh = %8x" - "\nnFileIndexLow = %8x \n", - (unsigned)info.dwFileAttributes, - (unsigned)info.ftCreationTime.dwHighDateTime, - (unsigned)info.ftLastAccessTime.dwHighDateTime, - (unsigned)info.ftLastWriteTime.dwHighDateTime, - (unsigned)info.dwVolumeSerialNumber, - (unsigned)info.nFileSizeHigh, - (unsigned)info.nFileSizeLow, - (unsigned)info.nNumberOfLinks, - (unsigned)info.nFileIndexHigh, - (unsigned)info.nFileIndexLow); -#endif -#endif - -#else // non-Wiondow - - mode = S_IFIFO | 0777; // 0755 : 0775 : 0664 : 0644 : -#if 1 - struct stat st; - if (fstat(0, &st) == 0) - { - SetFrom_stat(st); - if (!S_ISREG(st.st_mode) - // S_ISFIFO(st->st_mode) - || st.st_size == 0) - { - Size = (UInt64)(Int64)-1; - // mode = S_IFIFO | 0777; - } - } -#endif -#endif - - return true; -} - -bool CFileInfo::IsDots() const throw() -{ - if (!IsDir() || Name.IsEmpty()) - return false; - if (Name[0] != '.') - return false; - return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.'); -} - - -#ifdef _WIN32 - - -#define WIN_FD_TO_MY_FI(fi, fd) \ - fi.Attrib = fd.dwFileAttributes; \ - fi.CTime = fd.ftCreationTime; \ - fi.ATime = fd.ftLastAccessTime; \ - fi.MTime = fd.ftLastWriteTime; \ - fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ - /* fi.ReparseTag = fd.dwReserved0; */ \ - fi.IsAltStream = false; \ - fi.IsDevice = false; - - /* - #ifdef UNDER_CE - fi.ObjectID = fd.dwOID; - #else - fi.ReparseTag = fd.dwReserved0; - #endif - */ - -static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi) -{ - WIN_FD_TO_MY_FI(fi, fd) - fi.Name = us2fs(fd.cFileName); - #if defined(_WIN32) && !defined(UNDER_CE) - // fi.ShortName = us2fs(fd.cAlternateFileName); - #endif -} - -#ifndef _UNICODE -static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) -{ - WIN_FD_TO_MY_FI(fi, fd) - fi.Name = fas2fs(fd.cFileName); - #if defined(_WIN32) && !defined(UNDER_CE) - // fi.ShortName = fas2fs(fd.cAlternateFileName); - #endif -} -#endif - -//////////////////////////////// -// CFindFile - -bool CFindFileBase::Close() throw() -{ - if (_handle == INVALID_HANDLE_VALUE) - return true; - if (!::FindClose(_handle)) - return false; - _handle = INVALID_HANDLE_VALUE; - return true; -} - -/* -WinXP-64 FindFirstFile(): - "" - ERROR_PATH_NOT_FOUND - folder\ - ERROR_FILE_NOT_FOUND - \ - ERROR_FILE_NOT_FOUND - c:\ - ERROR_FILE_NOT_FOUND - c: - ERROR_FILE_NOT_FOUND, if current dir is ROOT ( c:\ ) - c: - OK, if current dir is NOT ROOT ( c:\folder ) - folder - OK - - \\ - ERROR_INVALID_NAME - \\Server - ERROR_INVALID_NAME - \\Server\ - ERROR_INVALID_NAME - - \\Server\Share - ERROR_BAD_NETPATH - \\Server\Share - ERROR_BAD_NET_NAME (Win7). - !!! There is problem : Win7 makes some requests for "\\Server\Shar" (look in Procmon), - when we call it for "\\Server\Share" - - \\Server\Share\ - ERROR_FILE_NOT_FOUND - - \\?\UNC\Server\Share - ERROR_INVALID_NAME - \\?\UNC\Server\Share - ERROR_BAD_PATHNAME (Win7) - \\?\UNC\Server\Share\ - ERROR_FILE_NOT_FOUND - - \\Server\Share_RootDrive - ERROR_INVALID_NAME - \\Server\Share_RootDrive\ - ERROR_INVALID_NAME - - e:\* - ERROR_FILE_NOT_FOUND, if there are no items in that root folder - w:\* - ERROR_PATH_NOT_FOUND, if there is no such drive w: -*/ - -bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) -{ - if (!Close()) - return false; - #ifndef _UNICODE - if (!g_IsNT) - { - WIN32_FIND_DATAA fd; - _handle = ::FindFirstFileA(fs2fas(path), &fd); - if (_handle == INVALID_HANDLE_VALUE) - return false; - Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); - } - else - #endif - { - WIN32_FIND_DATAW fd; - - IF_USE_MAIN_PATH - _handle = ::FindFirstFileW(fs2us(path), &fd); - #ifdef Z7_LONG_PATH - if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - _handle = ::FindFirstFileW(superPath, &fd); - } - #endif - if (_handle == INVALID_HANDLE_VALUE) - return false; - Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); - } - return true; -} - -bool CFindFile::FindNext(CFileInfo &fi) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - WIN32_FIND_DATAA fd; - if (!::FindNextFileA(_handle, &fd)) - return false; - Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); - } - else - #endif - { - WIN32_FIND_DATAW fd; - if (!::FindNextFileW(_handle, &fd)) - return false; - Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); - } - return true; -} - -#if defined(_WIN32) && !defined(UNDER_CE) - -//////////////////////////////// -// AltStreams - -#ifdef Z7_USE_DYN_FindFirstStream -static Func_FindFirstStreamW g_FindFirstStreamW; -static Func_FindNextStreamW g_FindNextStreamW; -#define MY_FindFirstStreamW g_FindFirstStreamW -#define MY_FindNextStreamW g_FindNextStreamW -static struct CFindStreamLoader -{ - CFindStreamLoader() - { - const HMODULE hm = ::GetModuleHandleA("kernel32.dll"); - g_FindFirstStreamW = Z7_GET_PROC_ADDRESS( - Func_FindFirstStreamW, hm, - "FindFirstStreamW"); - g_FindNextStreamW = Z7_GET_PROC_ADDRESS( - Func_FindNextStreamW, hm, - "FindNextStreamW"); - } -} g_FindStreamLoader; -#else -#define MY_FindFirstStreamW FindFirstStreamW -#define MY_FindNextStreamW FindNextStreamW -#endif - - -bool CStreamInfo::IsMainStream() const throw() -{ - return StringsAreEqualNoCase_Ascii(Name, "::$DATA"); -} - -UString CStreamInfo::GetReducedName() const -{ - // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA" - UString s (Name); - if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA")) - s.DeleteFrom(s.Len() - 6); - return s; -} - -/* -UString CStreamInfo::GetReducedName2() const -{ - UString s = GetReducedName(); - if (!s.IsEmpty() && s[0] == ':') - s.Delete(0); - return s; -} -*/ - -static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) -{ - si.Size = (UInt64)sd.StreamSize.QuadPart; - si.Name = sd.cStreamName; -} - -/* - WinXP-64 FindFirstStream(): - "" - ERROR_PATH_NOT_FOUND - folder\ - OK - folder - OK - \ - OK - c:\ - OK - c: - OK, if current dir is ROOT ( c:\ ) - c: - OK, if current dir is NOT ROOT ( c:\folder ) - \\Server\Share - OK - \\Server\Share\ - OK - - \\ - ERROR_INVALID_NAME - \\Server - ERROR_INVALID_NAME - \\Server\ - ERROR_INVALID_NAME -*/ - -bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si) -{ - if (!Close()) - return false; -#ifdef Z7_USE_DYN_FindFirstStream - if (!g_FindFirstStreamW) - { - ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; - } -#endif - { - MY_WIN32_FIND_STREAM_DATA sd; - SetLastError(0); - IF_USE_MAIN_PATH - _handle = MY_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0); - if (_handle == INVALID_HANDLE_VALUE) - { - if (::GetLastError() == ERROR_HANDLE_EOF) - return false; - // long name can be tricky for path like ".\dirName". - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - _handle = MY_FindFirstStreamW(superPath, My_FindStreamInfoStandard, &sd, 0); - } - #endif - } - if (_handle == INVALID_HANDLE_VALUE) - return false; - Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); - } - return true; -} - -bool CFindStream::FindNext(CStreamInfo &si) -{ -#ifdef Z7_USE_DYN_FindFirstStream - if (!g_FindNextStreamW) - { - ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return false; - } -#endif - { - MY_WIN32_FIND_STREAM_DATA sd; - if (!MY_FindNextStreamW(_handle, &sd)) - return false; - Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); - } - return true; -} - -bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) -{ - bool res; - if (_find.IsHandleAllocated()) - res = _find.FindNext(si); - else - res = _find.FindFirst(_filePath, si); - if (res) - { - found = true; - return true; - } - found = false; - return (::GetLastError() == ERROR_HANDLE_EOF); -} - -#endif - - -/* -WinXP-64 GetFileAttributes(): - If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code - - \ - OK - C:\ - OK, if there is such drive, - D:\ - ERROR_PATH_NOT_FOUND, if there is no such drive, - - C:\folder - OK - C:\folder\ - OK - C:\folderBad - ERROR_FILE_NOT_FOUND - - \\Server\BadShare - ERROR_BAD_NETPATH - \\Server\Share - WORKS OK, but MSDN says: - GetFileAttributes for a network share, the function fails, and GetLastError - returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share. -*/ - -DWORD GetFileAttrib(CFSTR path) -{ - #ifndef _UNICODE - if (!g_IsNT) - return ::GetFileAttributes(fs2fas(path)); - else - #endif - { - IF_USE_MAIN_PATH - { - DWORD dw = ::GetFileAttributesW(fs2us(path)); - if (dw != INVALID_FILE_ATTRIBUTES) - return dw; - } - #ifdef Z7_LONG_PATH - if (USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - return ::GetFileAttributesW(superPath); - } - #endif - return INVALID_FILE_ATTRIBUTES; - } -} - -/* if path is "c:" or "c::" then CFileInfo::Find() returns name of current folder for that disk - so instead of absolute path we have relative path in Name. That is not good in some calls */ - -/* In CFileInfo::Find() we want to support same names for alt streams as in CreateFile(). */ - -/* CFileInfo::Find() -We alow the following paths (as FindFirstFile): - C:\folder - c: - if current dir is NOT ROOT ( c:\folder ) - -also we support paths that are not supported by FindFirstFile: - \ - \\.\c: - c:\ - Name will be without tail slash ( c: ) - \\?\c:\ - Name will be without tail slash ( c: ) - \\Server\Share - \\?\UNC\Server\Share - - c:\folder:stream - Name = folder:stream - c:\:stream - Name = :stream - c::stream - Name = c::stream -*/ - -bool CFileInfo::Find(CFSTR path, bool followLink) -{ - #ifdef Z7_DEVICE_FILE - - if (IS_PATH_SEPAR(path[0]) && - IS_PATH_SEPAR(path[1]) && - path[2] == '.' && - path[3] == 0) - { - // 22.00 : it's virtual directory for devices - // IsDevice = true; - ClearBase(); - Name = path + 2; - Attrib = FILE_ATTRIBUTE_DIRECTORY; - return true; - } - - if (IsDevicePath(path)) - { - ClearBase(); - Name = path + 4; - IsDevice = true; - - if (NName::IsDrivePath2(path + 4) && path[6] == 0) - { - FChar drive[4] = { path[4], ':', '\\', 0 }; - UInt64 clusterSize, totalSize, freeSize; - if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize)) - { - Size = totalSize; - return true; - } - } - - NIO::CInFile inFile; - // ::OutputDebugStringW(path); - if (!inFile.Open(path)) - return false; - // ::OutputDebugStringW(L"---"); - if (inFile.SizeDefined) - Size = inFile.Size; - return true; - } - #endif - - #if defined(_WIN32) && !defined(UNDER_CE) - - const int colonPos = FindAltStreamColon(path); - if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) - { - UString streamName = fs2us(path + (unsigned)colonPos); - FString filePath (path); - filePath.DeleteFrom((unsigned)colonPos); - /* we allow both cases: - name:stream - name:stream:$DATA - */ - const unsigned kPostfixSize = 6; - if (streamName.Len() <= kPostfixSize - || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA")) - streamName += ":$DATA"; - - bool isOk = true; - - if (IsDrivePath2(filePath) && - (colonPos == 2 || (colonPos == 3 && filePath[2] == '\\'))) - { - // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT) - ClearBase(); - Name.Empty(); - if (colonPos == 2) - Name = filePath; - } - else - isOk = Find(filePath, followLink); // check it (followLink) - - if (isOk) - { - Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); - Size = 0; - CStreamEnumerator enumerator(filePath); - for (;;) - { - CStreamInfo si; - bool found; - if (!enumerator.Next(si, found)) - return false; - if (!found) - { - ::SetLastError(ERROR_FILE_NOT_FOUND); - return false; - } - if (si.Name.IsEqualTo_NoCase(streamName)) - { - // we delete postfix, if alt stream name is not "::$DATA" - if (si.Name.Len() > kPostfixSize + 1) - si.Name.DeleteFrom(si.Name.Len() - kPostfixSize); - Name += us2fs(si.Name); - Size = si.Size; - IsAltStream = true; - return true; - } - } - } - } - - #endif - - CFindFile finder; - - #if defined(_WIN32) && !defined(UNDER_CE) - { - /* - DWORD lastError = GetLastError(); - if (lastError == ERROR_FILE_NOT_FOUND - || lastError == ERROR_BAD_NETPATH // XP64: "\\Server\Share" - || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share" - || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share" - || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share" - ) - */ - - unsigned rootSize = 0; - if (IsSuperPath(path)) - rootSize = kSuperPathPrefixSize; - - if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0) - { - DWORD attrib = GetFileAttrib(path); - if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) - { - ClearBase(); - Attrib = attrib; - Name = path + rootSize; - Name.DeleteFrom(2); - if (!Fill_From_ByHandleFileInfo(path)) - { - } - return true; - } - } - else if (IS_PATH_SEPAR(path[0])) - { - if (path[1] == 0) - { - DWORD attrib = GetFileAttrib(path); - if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) - { - ClearBase(); - Name.Empty(); - Attrib = attrib; - return true; - } - } - else - { - const unsigned prefixSize = GetNetworkServerPrefixSize(path); - if (prefixSize > 0 && path[prefixSize] != 0) - { - if (NName::FindSepar(path + prefixSize) < 0) - { - if (Fill_From_ByHandleFileInfo(path)) - { - Name = path + prefixSize; - return true; - } - - FString s (path); - s.Add_PathSepar(); - s.Add_Char('*'); // CHAR_ANY_MASK - bool isOK = false; - if (finder.FindFirst(s, *this)) - { - if (Name == FTEXT(".")) - { - Name = path + prefixSize; - return true; - } - isOK = true; - /* if "\\server\share" maps to root folder "d:\", there is no "." item. - But it's possible that there are another items */ - } - { - const DWORD attrib = GetFileAttrib(path); - if (isOK || (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)) - { - ClearBase(); - if (attrib != INVALID_FILE_ATTRIBUTES) - Attrib = attrib; - else - SetAsDir(); - Name = path + prefixSize; - return true; - } - } - // ::SetLastError(lastError); - } - } - } - } - } - #endif - - bool res = finder.FindFirst(path, *this); - if (!followLink - || !res - || !HasReparsePoint()) - return res; - - // return FollowReparse(path, IsDir()); - return Fill_From_ByHandleFileInfo(path); -} - -bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) -{ - BY_HANDLE_FILE_INFORMATION info; - if (!NIO::CFileBase::GetFileInformation(path, &info)) - return false; - { - Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; - CTime = info.ftCreationTime; - ATime = info.ftLastAccessTime; - MTime = info.ftLastWriteTime; - Attrib = info.dwFileAttributes; - return true; - } -} - -/* -bool CFileInfo::FollowReparse(CFSTR path, bool isDir) -{ - if (isDir) - { - FString prefix = path; - prefix.Add_PathSepar(); - - // "folder/." refers to folder itself. So we can't use that path - // we must use enumerator and search "." item - CEnumerator enumerator; - enumerator.SetDirPrefix(prefix); - for (;;) - { - CFileInfo fi; - if (!enumerator.NextAny(fi)) - break; - if (fi.Name.IsEqualTo_Ascii_NoCase(".")) - { - // we can copy preperies; - CTime = fi.CTime; - ATime = fi.ATime; - MTime = fi.MTime; - Attrib = fi.Attrib; - Size = fi.Size; - return true; - } - break; - } - // LastError(lastError); - return false; - } - - { - NIO::CInFile inFile; - if (inFile.Open(path)) - { - BY_HANDLE_FILE_INFORMATION info; - if (inFile.GetFileInformation(&info)) - { - ClearBase(); - Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; - CTime = info.ftCreationTime; - ATime = info.ftLastAccessTime; - MTime = info.ftLastWriteTime; - Attrib = info.dwFileAttributes; - return true; - } - } - return false; - } -} -*/ - -bool DoesFileExist_Raw(CFSTR name) -{ - CFileInfo fi; - return fi.Find(name) && !fi.IsDir(); -} - -bool DoesFileExist_FollowLink(CFSTR name) -{ - CFileInfo fi; - return fi.Find_FollowLink(name) && !fi.IsDir(); -} - -bool DoesDirExist(CFSTR name, bool followLink) -{ - CFileInfo fi; - return fi.Find(name, followLink) && fi.IsDir(); -} - -bool DoesFileOrDirExist(CFSTR name) -{ - CFileInfo fi; - return fi.Find(name); -} - - -void CEnumerator::SetDirPrefix(const FString &dirPrefix) -{ - _wildcard = dirPrefix; - _wildcard.Add_Char('*'); -} - -bool CEnumerator::NextAny(CFileInfo &fi) -{ - if (_findFile.IsHandleAllocated()) - return _findFile.FindNext(fi); - else - return _findFile.FindFirst(_wildcard, fi); -} - -bool CEnumerator::Next(CFileInfo &fi) -{ - for (;;) - { - if (!NextAny(fi)) - return false; - if (!fi.IsDots()) - return true; - } -} - -bool CEnumerator::Next(CFileInfo &fi, bool &found) -{ - /* - for (;;) - { - if (!NextAny(fi)) - break; - if (!fi.IsDots()) - { - found = true; - return true; - } - } - */ - - if (Next(fi)) - { - found = true; - return true; - } - - found = false; - DWORD lastError = ::GetLastError(); - if (_findFile.IsHandleAllocated()) - return (lastError == ERROR_NO_MORE_FILES); - // we support the case for empty root folder: FindFirstFile("c:\\*") returns ERROR_FILE_NOT_FOUND - if (lastError == ERROR_FILE_NOT_FOUND) - return true; - if (lastError == ERROR_ACCESS_DENIED) - { - // here we show inaccessible root system folder as empty folder to eliminate redundant user warnings - const char *s = "System Volume Information" STRING_PATH_SEPARATOR "*"; - const int len = (int)strlen(s); - const int delta = (int)_wildcard.Len() - len; - if (delta == 0 || (delta > 0 && IS_PATH_SEPAR(_wildcard[(unsigned)delta - 1]))) - if (StringsAreEqual_Ascii(_wildcard.Ptr((unsigned)delta), s)) - return true; - } - return false; -} - - -//////////////////////////////// -// CFindChangeNotification -// FindFirstChangeNotification can return 0. MSDN doesn't tell about it. - -bool CFindChangeNotification::Close() throw() -{ - if (!IsHandleAllocated()) - return true; - if (!::FindCloseChangeNotification(_handle)) - return false; - _handle = INVALID_HANDLE_VALUE; - return true; -} - -HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter) -{ - #ifndef _UNICODE - if (!g_IsNT) - _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter); - else - #endif - { - IF_USE_MAIN_PATH - _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter); - #ifdef Z7_LONG_PATH - if (!IsHandleAllocated()) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - _handle = ::FindFirstChangeNotificationW(superPath, BoolToBOOL(watchSubtree), notifyFilter); - } - #endif - } - return _handle; -} - -#ifndef UNDER_CE - -bool MyGetLogicalDriveStrings(CObjectVector &driveStrings) -{ - driveStrings.Clear(); - #ifndef _UNICODE - if (!g_IsNT) - { - driveStrings.Clear(); - UINT32 size = GetLogicalDriveStrings(0, NULL); - if (size == 0) - return false; - CObjArray buf(size); - UINT32 newSize = GetLogicalDriveStrings(size, buf); - if (newSize == 0 || newSize > size) - return false; - AString s; - UINT32 prev = 0; - for (UINT32 i = 0; i < newSize; i++) - { - if (buf[i] == 0) - { - s = buf + prev; - prev = i + 1; - driveStrings.Add(fas2fs(s)); - } - } - return prev == newSize; - } - else - #endif - { - UINT32 size = GetLogicalDriveStringsW(0, NULL); - if (size == 0) - return false; - CObjArray buf(size); - UINT32 newSize = GetLogicalDriveStringsW(size, buf); - if (newSize == 0 || newSize > size) - return false; - UString s; - UINT32 prev = 0; - for (UINT32 i = 0; i < newSize; i++) - { - if (buf[i] == 0) - { - s = buf + prev; - prev = i + 1; - driveStrings.Add(us2fs(s)); - } - } - return prev == newSize; - } -} - -#endif // UNDER_CE - - - -#else // _WIN32 - -// ---------- POSIX ---------- - -static int MY_lstat(CFSTR path, struct stat *st, bool followLink) -{ - memset(st, 0, sizeof(*st)); - int res; - // #ifdef ENV_HAVE_LSTAT - if (/* global_use_lstat && */ !followLink) - { - // printf("\nlstat\n"); - res = lstat(path, st); - } - else - // #endif - { - // printf("\nstat\n"); - res = stat(path, st); - } -#if 0 -#if defined(__clang__) && __clang_major__ >= 14 - #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" -#endif - - printf("\n st_dev = %lld", (long long)(st->st_dev)); - printf("\n st_ino = %lld", (long long)(st->st_ino)); - printf("\n st_mode = %llx", (long long)(st->st_mode)); - printf("\n st_nlink = %lld", (long long)(st->st_nlink)); - printf("\n st_uid = %lld", (long long)(st->st_uid)); - printf("\n st_gid = %lld", (long long)(st->st_gid)); - printf("\n st_size = %lld", (long long)(st->st_size)); - printf("\n st_blksize = %lld", (long long)(st->st_blksize)); - printf("\n st_blocks = %lld", (long long)(st->st_blocks)); - printf("\n st_ctim = %lld", (long long)(ST_CTIME((*st)).tv_sec)); - printf("\n st_mtim = %lld", (long long)(ST_MTIME((*st)).tv_sec)); - printf("\n st_atim = %lld", (long long)(ST_ATIME((*st)).tv_sec)); - printf(S_ISFIFO(st->st_mode) ? "\n FIFO" : "\n NO FIFO"); - printf("\n"); -#endif - - return res; -} - - -static const char *Get_Name_from_Path(CFSTR path) throw() -{ - size_t len = strlen(path); - if (len == 0) - return path; - const char *p = path + len - 1; - { - if (p == path) - return path; - p--; - } - for (;;) - { - char c = *p; - if (IS_PATH_SEPAR(c)) - return p + 1; - if (p == path) - return path; - p--; - } -} - - -UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) -{ - UInt32 attrib = S_ISDIR(mode) ? - FILE_ATTRIBUTE_DIRECTORY : - FILE_ATTRIBUTE_ARCHIVE; - if ((mode & 0222) == 0) // S_IWUSR in p7zip - attrib |= FILE_ATTRIBUTE_READONLY; - return attrib | FILE_ATTRIBUTE_UNIX_EXTENSION | ((mode & 0xFFFF) << 16); -} - -/* -UInt32 Get_WinAttrib_From_stat(const struct stat &st) -{ - UInt32 attrib = S_ISDIR(st.st_mode) ? - FILE_ATTRIBUTE_DIRECTORY : - FILE_ATTRIBUTE_ARCHIVE; - - if ((st.st_mode & 0222) == 0) // check it !!! - attrib |= FILE_ATTRIBUTE_READONLY; - - attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((st.st_mode & 0xFFFF) << 16); - return attrib; -} -*/ - -void CFileInfoBase::SetFrom_stat(const struct stat &st) -{ - // IsDevice = false; - - if (S_ISDIR(st.st_mode)) - { - Size = 0; - } - else - { - Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename - } - - // Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); - - // NTime::UnixTimeToFileTime(st.st_ctime, CTime); - // NTime::UnixTimeToFileTime(st.st_mtime, MTime); - // NTime::UnixTimeToFileTime(st.st_atime, ATime); - #ifdef __APPLE__ - // #ifdef _DARWIN_FEATURE_64_BIT_INODE - /* - here we can use birthtime instead of st_ctimespec. - but we use st_ctimespec for compatibility with previous versions and p7zip. - st_birthtimespec in OSX - st_birthtim : at FreeBSD, NetBSD - */ - // timespec_To_FILETIME(st.st_birthtimespec, CTime); - // #else - // timespec_To_FILETIME(st.st_ctimespec, CTime); - // #endif - // timespec_To_FILETIME(st.st_mtimespec, MTime); - // timespec_To_FILETIME(st.st_atimespec, ATime); - CTime = st.st_ctimespec; - MTime = st.st_mtimespec; - ATime = st.st_atimespec; - - #else - // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100); - // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100); - // timespec_To_FILETIME(st.st_atim, ATime, &ATime_ns100); - CTime = st.st_ctim; - MTime = st.st_mtim; - ATime = st.st_atim; - - #endif - - dev = st.st_dev; - ino = st.st_ino; - mode = st.st_mode; - nlink = st.st_nlink; - uid = st.st_uid; - gid = st.st_gid; - rdev = st.st_rdev; - - /* - printf("\n sizeof timespec = %d", (int)sizeof(timespec)); - printf("\n sizeof st_rdev = %d", (int)sizeof(rdev)); - printf("\n sizeof st_ino = %d", (int)sizeof(ino)); - printf("\n sizeof mode_t = %d", (int)sizeof(mode_t)); - printf("\n sizeof nlink_t = %d", (int)sizeof(nlink_t)); - printf("\n sizeof uid_t = %d", (int)sizeof(uid_t)); - printf("\n"); - */ - /* - printf("\n st_rdev = %llx", (long long)rdev); - printf("\n st_dev = %llx", (long long)dev); - printf("\n dev : major = %5x minor = %5x", (unsigned)major(dev), (unsigned)minor(dev)); - printf("\n st_ino = %lld", (long long)(ino)); - printf("\n rdev : major = %5x minor = %5x", (unsigned)major(rdev), (unsigned)minor(rdev)); - printf("\n size = %lld \n", (long long)(Size)); - printf("\n"); - */ -} - -/* -int Uid_To_Uname(uid_t uid, AString &name) -{ - name.Empty(); - struct passwd *passwd; - - if (uid != 0 && uid == cached_no_such_uid) - { - *uname = xstrdup (""); - return; - } - - if (!cached_uname || uid != cached_uid) - { - passwd = getpwuid (uid); - if (passwd) - { - cached_uid = uid; - assign_string (&cached_uname, passwd->pw_name); - } - else - { - cached_no_such_uid = uid; - *uname = xstrdup (""); - return; - } - } - *uname = xstrdup (cached_uname); -} -*/ - -bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) -{ - struct stat st; - if (MY_lstat(path, &st, followLink) != 0) - return false; - // printf("\nFind_DontFill_Name : name=%s\n", path); - SetFrom_stat(st); - return true; -} - - -bool CFileInfo::Find(CFSTR path, bool followLink) -{ - // printf("\nCEnumerator::Find() name = %s\n", path); - if (!Find_DontFill_Name(path, followLink)) - return false; - - // printf("\nOK\n"); - - Name = Get_Name_from_Path(path); - if (!Name.IsEmpty()) - { - char c = Name.Back(); - if (IS_PATH_SEPAR(c)) - Name.DeleteBack(); - } - return true; -} - - -bool DoesFileExist_Raw(CFSTR name) -{ - // FIXME for symbolic links. - struct stat st; - if (MY_lstat(name, &st, false) != 0) - return false; - return !S_ISDIR(st.st_mode); -} - -bool DoesFileExist_FollowLink(CFSTR name) -{ - // FIXME for symbolic links. - struct stat st; - if (MY_lstat(name, &st, true) != 0) - return false; - return !S_ISDIR(st.st_mode); -} - -bool DoesDirExist(CFSTR name, bool followLink) -{ - struct stat st; - if (MY_lstat(name, &st, followLink) != 0) - return false; - return S_ISDIR(st.st_mode); -} - -bool DoesFileOrDirExist(CFSTR name) -{ - struct stat st; - if (MY_lstat(name, &st, false) != 0) - return false; - return true; -} - - -CEnumerator::~CEnumerator() -{ - if (_dir) - closedir(_dir); -} - -void CEnumerator::SetDirPrefix(const FString &dirPrefix) -{ - _wildcard = dirPrefix; -} - -bool CDirEntry::IsDots() const throw() -{ - /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) - we can call fstatat() for that case, but we use only (Name) check here */ - -#if !defined(_AIX) && !defined(__sun) - if (Type != DT_DIR && Type != DT_UNKNOWN) - return false; -#endif - - return Name.Len() != 0 - && Name.Len() <= 2 - && Name[0] == '.' - && (Name.Len() == 1 || Name[1] == '.'); -} - - -bool CEnumerator::NextAny(CDirEntry &fi, bool &found) -{ - found = false; - - if (!_dir) - { - const char *w = "./"; - if (!_wildcard.IsEmpty()) - w = _wildcard.Ptr(); - _dir = ::opendir((const char *)w); - if (_dir == NULL) - return false; - } - - // To distinguish end of stream from an error, we must set errno to zero before readdir() - errno = 0; - - struct dirent *de = readdir(_dir); - if (!de) - { - if (errno == 0) - return true; // it's end of stream, and we report it with (found = false) - // it's real error - return false; - } - - fi.iNode = de->d_ino; - -#if !defined(_AIX) && !defined(__sun) - fi.Type = de->d_type; - /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) - we can set (Type) from fstatat() in that case. - But (Type) is not too important. So we don't set it here with slow fstatat() */ - /* - // fi.Type = DT_UNKNOWN; // for debug - if (fi.Type == DT_UNKNOWN) - { - struct stat st; - if (fstatat(dirfd(_dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) == 0) - if (S_ISDIR(st.st_mode)) - fi.Type = DT_DIR; - } - */ -#endif - - /* - if (de->d_type == DT_DIR) - fi.Attrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(S_IFDIR) << 16); - else if (de->d_type < 16) - fi.Attrib = FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(de->d_type) << (16 + 12)); - */ - fi.Name = de->d_name; - - /* - printf("\nCEnumerator::NextAny; len = %d %s \n", (int)fi.Name.Len(), fi.Name.Ptr()); - for (unsigned i = 0; i < fi.Name.Len(); i++) - printf (" %02x", (unsigned)(Byte)de->d_name[i]); - printf("\n"); - */ - - found = true; - return true; -} - - -bool CEnumerator::Next(CDirEntry &fi, bool &found) -{ - // printf("\nCEnumerator::Next()\n"); - // PrintName("Next", ""); - for (;;) - { - if (!NextAny(fi, found)) - return false; - if (!found) - return true; - if (!fi.IsDots()) - { - /* - if (!NeedFullStat) - return true; - // we silently skip error file here - it can be wrong link item - if (fi.Find_DontFill_Name(path)) - return true; - */ - return true; - } - } -} - -/* -bool CEnumerator::Next(CDirEntry &fileInfo, bool &found) -{ - bool found; - if (!Next(fi, found)) - return false; - return found; -} -*/ - -bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const -{ - // printf("\nCEnumerator::Fill_FileInfo()\n"); - struct stat st; - // probably it's OK to use fstatat() even if it changes file position dirfd(_dir) - int res = fstatat(dirfd(_dir), de.Name, &st, followLink ? 0 : AT_SYMLINK_NOFOLLOW); - // if fstatat() is not supported, we can use stat() / lstat() - - /* - const FString path = _wildcard + s; - int res = MY_lstat(path, &st, followLink); - */ - - if (res != 0) - return false; - // printf("\nname=%s\n", de.Name.Ptr()); - fileInfo.SetFrom_stat(st); - fileInfo.Name = de.Name; - return true; -} - -#endif // _WIN32 - -}}} +// Windows/FileFind.cpp + +#include "StdAfx.h" + +// #include + +#ifndef _WIN32 +#include /* Definition of AT_* constants */ +#include "TimeUtils.h" +// for major +// #include +#endif + +#include "FileFind.h" +#include "FileIO.h" +#include "FileName.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +#if defined(_WIN32) && !defined(UNDER_CE) + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0502 // Win2003 +#define Z7_USE_DYN_FindFirstStream +#endif + +#ifdef Z7_USE_DYN_FindFirstStream + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +EXTERN_C_BEGIN + +typedef enum +{ + My_FindStreamInfoStandard, + My_FindStreamInfoMaxInfoLevel +} MY_STREAM_INFO_LEVELS; + +typedef struct +{ + LARGE_INTEGER StreamSize; + WCHAR cStreamName[MAX_PATH + 36]; +} MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; + +typedef HANDLE (WINAPI *Func_FindFirstStreamW)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, + LPVOID findStreamData, DWORD flags); + +typedef BOOL (APIENTRY *Func_FindNextStreamW)(HANDLE findStream, LPVOID findStreamData); + +EXTERN_C_END + +#else + +#define MY_WIN32_FIND_STREAM_DATA WIN32_FIND_STREAM_DATA +#define My_FindStreamInfoStandard FindStreamInfoStandard + +#endif +#endif // defined(_WIN32) && !defined(UNDER_CE) + + +namespace NWindows { +namespace NFile { + + +#ifdef _WIN32 +#ifdef Z7_DEVICE_FILE +namespace NSystem +{ +bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); +} +#endif +#endif + +namespace NFind { + +/* +#ifdef _WIN32 +#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; +#else +#define MY_CLEAR_FILETIME(ft) ft.tv_sec = 0; ft.tv_nsec = 0; +#endif +*/ + +void CFileInfoBase::ClearBase() throw() +{ + Size = 0; + FiTime_Clear(CTime); + FiTime_Clear(ATime); + FiTime_Clear(MTime); + + #ifdef _WIN32 + Attrib = 0; + // ReparseTag = 0; + IsAltStream = false; + IsDevice = false; + #else + dev = 0; + ino = 0; + mode = 0; + nlink = 0; + uid = 0; + gid = 0; + rdev = 0; + #endif +} + + +bool CFileInfoBase::SetAs_StdInFile() +{ + ClearBase(); + Size = (UInt64)(Int64)-1; + NTime::GetCurUtc_FiTime(MTime); + CTime = ATime = MTime; + +#ifdef _WIN32 + + /* in GUI mode : GetStdHandle(STD_INPUT_HANDLE) returns NULL, + and it doesn't set LastError. */ +#if 1 + SetLastError(0); + const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + if (!h || h == INVALID_HANDLE_VALUE) + { + if (GetLastError() == 0) + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + BY_HANDLE_FILE_INFORMATION info; + if (GetFileInformationByHandle(h, &info) + && info.dwVolumeSerialNumber) + { + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + // FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; + // NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1; + Attrib = info.dwFileAttributes; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + } +#if 0 + printf( + "\ndwFileAttributes = %8x" + "\nftCreationTime = %8x" + "\nftLastAccessTime = %8x" + "\nftLastWriteTime = %8x" + "\ndwVolumeSerialNumber = %8x" + "\nnFileSizeHigh = %8x" + "\nnFileSizeLow = %8x" + "\nnNumberOfLinks = %8x" + "\nnFileIndexHigh = %8x" + "\nnFileIndexLow = %8x \n", + (unsigned)info.dwFileAttributes, + (unsigned)info.ftCreationTime.dwHighDateTime, + (unsigned)info.ftLastAccessTime.dwHighDateTime, + (unsigned)info.ftLastWriteTime.dwHighDateTime, + (unsigned)info.dwVolumeSerialNumber, + (unsigned)info.nFileSizeHigh, + (unsigned)info.nFileSizeLow, + (unsigned)info.nNumberOfLinks, + (unsigned)info.nFileIndexHigh, + (unsigned)info.nFileIndexLow); +#endif +#endif + +#else // non-Wiondow + + mode = S_IFIFO | 0777; // 0755 : 0775 : 0664 : 0644 : +#if 1 + struct stat st; + if (fstat(0, &st) == 0) + { + SetFrom_stat(st); + if (!S_ISREG(st.st_mode) + // S_ISFIFO(st->st_mode) + || st.st_size == 0) + { + Size = (UInt64)(Int64)-1; + // mode = S_IFIFO | 0777; + } + } +#endif +#endif + + return true; +} + +bool CFileInfo::IsDots() const throw() +{ + if (!IsDir() || Name.IsEmpty()) + return false; + if (Name[0] != '.') + return false; + return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.'); +} + + +#ifdef _WIN32 + + +#define WIN_FD_TO_MY_FI(fi, fd) \ + fi.Attrib = fd.dwFileAttributes; \ + fi.CTime = fd.ftCreationTime; \ + fi.ATime = fd.ftLastAccessTime; \ + fi.MTime = fd.ftLastWriteTime; \ + fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ + /* fi.ReparseTag = fd.dwReserved0; */ \ + fi.IsAltStream = false; \ + fi.IsDevice = false; + + /* + #ifdef UNDER_CE + fi.ObjectID = fd.dwOID; + #else + fi.ReparseTag = fd.dwReserved0; + #endif + */ + +static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi) +{ + WIN_FD_TO_MY_FI(fi, fd) + fi.Name = us2fs(fd.cFileName); + #if defined(_WIN32) && !defined(UNDER_CE) + // fi.ShortName = us2fs(fd.cAlternateFileName); + #endif +} + +#ifndef _UNICODE +static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) +{ + WIN_FD_TO_MY_FI(fi, fd) + fi.Name = fas2fs(fd.cFileName); + #if defined(_WIN32) && !defined(UNDER_CE) + // fi.ShortName = fas2fs(fd.cAlternateFileName); + #endif +} +#endif + +//////////////////////////////// +// CFindFile + +bool CFindFileBase::Close() throw() +{ + if (_handle == INVALID_HANDLE_VALUE) + return true; + if (!::FindClose(_handle)) + return false; + _handle = INVALID_HANDLE_VALUE; + return true; +} + +/* +WinXP-64 FindFirstFile(): + "" - ERROR_PATH_NOT_FOUND + folder\ - ERROR_FILE_NOT_FOUND + \ - ERROR_FILE_NOT_FOUND + c:\ - ERROR_FILE_NOT_FOUND + c: - ERROR_FILE_NOT_FOUND, if current dir is ROOT ( c:\ ) + c: - OK, if current dir is NOT ROOT ( c:\folder ) + folder - OK + + \\ - ERROR_INVALID_NAME + \\Server - ERROR_INVALID_NAME + \\Server\ - ERROR_INVALID_NAME + + \\Server\Share - ERROR_BAD_NETPATH + \\Server\Share - ERROR_BAD_NET_NAME (Win7). + !!! There is problem : Win7 makes some requests for "\\Server\Shar" (look in Procmon), + when we call it for "\\Server\Share" + + \\Server\Share\ - ERROR_FILE_NOT_FOUND + + \\?\UNC\Server\Share - ERROR_INVALID_NAME + \\?\UNC\Server\Share - ERROR_BAD_PATHNAME (Win7) + \\?\UNC\Server\Share\ - ERROR_FILE_NOT_FOUND + + \\Server\Share_RootDrive - ERROR_INVALID_NAME + \\Server\Share_RootDrive\ - ERROR_INVALID_NAME + + e:\* - ERROR_FILE_NOT_FOUND, if there are no items in that root folder + w:\* - ERROR_PATH_NOT_FOUND, if there is no such drive w: +*/ + +bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) +{ + if (!Close()) + return false; + #ifndef _UNICODE + if (!g_IsNT) + { + WIN32_FIND_DATAA fd; + _handle = ::FindFirstFileA(fs2fas(path), &fd); + if (_handle == INVALID_HANDLE_VALUE) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); + } + else + #endif + { + WIN32_FIND_DATAW fd; + + IF_USE_MAIN_PATH + _handle = ::FindFirstFileW(fs2us(path), &fd); + #ifdef Z7_LONG_PATH + if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + _handle = ::FindFirstFileW(superPath, &fd); + } + #endif + if (_handle == INVALID_HANDLE_VALUE) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); + } + return true; +} + +bool CFindFile::FindNext(CFileInfo &fi) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + WIN32_FIND_DATAA fd; + if (!::FindNextFileA(_handle, &fd)) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); + } + else + #endif + { + WIN32_FIND_DATAW fd; + if (!::FindNextFileW(_handle, &fd)) + return false; + Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi); + } + return true; +} + +#if defined(_WIN32) && !defined(UNDER_CE) + +//////////////////////////////// +// AltStreams + +#ifdef Z7_USE_DYN_FindFirstStream +static Func_FindFirstStreamW g_FindFirstStreamW; +static Func_FindNextStreamW g_FindNextStreamW; +#define MY_FindFirstStreamW g_FindFirstStreamW +#define MY_FindNextStreamW g_FindNextStreamW +static struct CFindStreamLoader +{ + CFindStreamLoader() + { + const HMODULE hm = ::GetModuleHandleA("kernel32.dll"); + g_FindFirstStreamW = Z7_GET_PROC_ADDRESS( + Func_FindFirstStreamW, hm, + "FindFirstStreamW"); + g_FindNextStreamW = Z7_GET_PROC_ADDRESS( + Func_FindNextStreamW, hm, + "FindNextStreamW"); + } +} g_FindStreamLoader; +#else +#define MY_FindFirstStreamW FindFirstStreamW +#define MY_FindNextStreamW FindNextStreamW +#endif + + +bool CStreamInfo::IsMainStream() const throw() +{ + return StringsAreEqualNoCase_Ascii(Name, "::$DATA"); +} + +UString CStreamInfo::GetReducedName() const +{ + // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA" + UString s (Name); + if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA")) + s.DeleteFrom(s.Len() - 6); + return s; +} + +/* +UString CStreamInfo::GetReducedName2() const +{ + UString s = GetReducedName(); + if (!s.IsEmpty() && s[0] == ':') + s.Delete(0); + return s; +} +*/ + +static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) +{ + si.Size = (UInt64)sd.StreamSize.QuadPart; + si.Name = sd.cStreamName; +} + +/* + WinXP-64 FindFirstStream(): + "" - ERROR_PATH_NOT_FOUND + folder\ - OK + folder - OK + \ - OK + c:\ - OK + c: - OK, if current dir is ROOT ( c:\ ) + c: - OK, if current dir is NOT ROOT ( c:\folder ) + \\Server\Share - OK + \\Server\Share\ - OK + + \\ - ERROR_INVALID_NAME + \\Server - ERROR_INVALID_NAME + \\Server\ - ERROR_INVALID_NAME +*/ + +bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si) +{ + if (!Close()) + return false; +#ifdef Z7_USE_DYN_FindFirstStream + if (!g_FindFirstStreamW) + { + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } +#endif + { + MY_WIN32_FIND_STREAM_DATA sd; + SetLastError(0); + IF_USE_MAIN_PATH + _handle = MY_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0); + if (_handle == INVALID_HANDLE_VALUE) + { + if (::GetLastError() == ERROR_HANDLE_EOF) + return false; + // long name can be tricky for path like ".\dirName". + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + _handle = MY_FindFirstStreamW(superPath, My_FindStreamInfoStandard, &sd, 0); + } + #endif + } + if (_handle == INVALID_HANDLE_VALUE) + return false; + Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); + } + return true; +} + +bool CFindStream::FindNext(CStreamInfo &si) +{ +#ifdef Z7_USE_DYN_FindFirstStream + if (!g_FindNextStreamW) + { + ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return false; + } +#endif + { + MY_WIN32_FIND_STREAM_DATA sd; + if (!MY_FindNextStreamW(_handle, &sd)) + return false; + Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si); + } + return true; +} + +bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) +{ + bool res; + if (_find.IsHandleAllocated()) + res = _find.FindNext(si); + else + res = _find.FindFirst(_filePath, si); + if (res) + { + found = true; + return true; + } + found = false; + return (::GetLastError() == ERROR_HANDLE_EOF); +} + +#endif + + +/* +WinXP-64 GetFileAttributes(): + If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code + + \ - OK + C:\ - OK, if there is such drive, + D:\ - ERROR_PATH_NOT_FOUND, if there is no such drive, + + C:\folder - OK + C:\folder\ - OK + C:\folderBad - ERROR_FILE_NOT_FOUND + + \\Server\BadShare - ERROR_BAD_NETPATH + \\Server\Share - WORKS OK, but MSDN says: + GetFileAttributes for a network share, the function fails, and GetLastError + returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share. +*/ + +DWORD GetFileAttrib(CFSTR path) +{ + #ifndef _UNICODE + if (!g_IsNT) + return ::GetFileAttributes(fs2fas(path)); + else + #endif + { + IF_USE_MAIN_PATH + { + DWORD dw = ::GetFileAttributesW(fs2us(path)); + if (dw != INVALID_FILE_ATTRIBUTES) + return dw; + } + #ifdef Z7_LONG_PATH + if (USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + return ::GetFileAttributesW(superPath); + } + #endif + return INVALID_FILE_ATTRIBUTES; + } +} + +/* if path is "c:" or "c::" then CFileInfo::Find() returns name of current folder for that disk + so instead of absolute path we have relative path in Name. That is not good in some calls */ + +/* In CFileInfo::Find() we want to support same names for alt streams as in CreateFile(). */ + +/* CFileInfo::Find() +We alow the following paths (as FindFirstFile): + C:\folder + c: - if current dir is NOT ROOT ( c:\folder ) + +also we support paths that are not supported by FindFirstFile: + \ + \\.\c: + c:\ - Name will be without tail slash ( c: ) + \\?\c:\ - Name will be without tail slash ( c: ) + \\Server\Share + \\?\UNC\Server\Share + + c:\folder:stream - Name = folder:stream + c:\:stream - Name = :stream + c::stream - Name = c::stream +*/ + +bool CFileInfo::Find(CFSTR path, bool followLink) +{ + #ifdef Z7_DEVICE_FILE + + if (IS_PATH_SEPAR(path[0]) && + IS_PATH_SEPAR(path[1]) && + path[2] == '.' && + path[3] == 0) + { + // 22.00 : it's virtual directory for devices + // IsDevice = true; + ClearBase(); + Name = path + 2; + Attrib = FILE_ATTRIBUTE_DIRECTORY; + return true; + } + + if (IsDevicePath(path)) + { + ClearBase(); + Name = path + 4; + IsDevice = true; + + if (NName::IsDrivePath2(path + 4) && path[6] == 0) + { + FChar drive[4] = { path[4], ':', '\\', 0 }; + UInt64 clusterSize, totalSize, freeSize; + if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize)) + { + Size = totalSize; + return true; + } + } + + NIO::CInFile inFile; + // ::OutputDebugStringW(path); + if (!inFile.Open(path)) + return false; + // ::OutputDebugStringW(L"---"); + if (inFile.SizeDefined) + Size = inFile.Size; + return true; + } + #endif + + #if defined(_WIN32) && !defined(UNDER_CE) + + const int colonPos = FindAltStreamColon(path); + if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) + { + UString streamName = fs2us(path + (unsigned)colonPos); + FString filePath (path); + filePath.DeleteFrom((unsigned)colonPos); + /* we allow both cases: + name:stream + name:stream:$DATA + */ + const unsigned kPostfixSize = 6; + if (streamName.Len() <= kPostfixSize + || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA")) + streamName += ":$DATA"; + + bool isOk = true; + + if (IsDrivePath2(filePath) && + (colonPos == 2 || (colonPos == 3 && filePath[2] == '\\'))) + { + // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT) + ClearBase(); + Name.Empty(); + if (colonPos == 2) + Name = filePath; + } + else + isOk = Find(filePath, followLink); // check it (followLink) + + if (isOk) + { + Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); + Size = 0; + CStreamEnumerator enumerator(filePath); + for (;;) + { + CStreamInfo si; + bool found; + if (!enumerator.Next(si, found)) + return false; + if (!found) + { + ::SetLastError(ERROR_FILE_NOT_FOUND); + return false; + } + if (si.Name.IsEqualTo_NoCase(streamName)) + { + // we delete postfix, if alt stream name is not "::$DATA" + if (si.Name.Len() > kPostfixSize + 1) + si.Name.DeleteFrom(si.Name.Len() - kPostfixSize); + Name += us2fs(si.Name); + Size = si.Size; + IsAltStream = true; + return true; + } + } + } + } + + #endif + + CFindFile finder; + + #if defined(_WIN32) && !defined(UNDER_CE) + { + /* + DWORD lastError = GetLastError(); + if (lastError == ERROR_FILE_NOT_FOUND + || lastError == ERROR_BAD_NETPATH // XP64: "\\Server\Share" + || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share" + || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share" + || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share" + ) + */ + + unsigned rootSize = 0; + if (IsSuperPath(path)) + rootSize = kSuperPathPrefixSize; + + if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0) + { + DWORD attrib = GetFileAttrib(path); + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + ClearBase(); + Attrib = attrib; + Name = path + rootSize; + Name.DeleteFrom(2); + if (!Fill_From_ByHandleFileInfo(path)) + { + } + return true; + } + } + else if (IS_PATH_SEPAR(path[0])) + { + if (path[1] == 0) + { + DWORD attrib = GetFileAttrib(path); + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + ClearBase(); + Name.Empty(); + Attrib = attrib; + return true; + } + } + else + { + const unsigned prefixSize = GetNetworkServerPrefixSize(path); + if (prefixSize > 0 && path[prefixSize] != 0) + { + if (NName::FindSepar(path + prefixSize) < 0) + { + if (Fill_From_ByHandleFileInfo(path)) + { + Name = path + prefixSize; + return true; + } + + FString s (path); + s.Add_PathSepar(); + s.Add_Char('*'); // CHAR_ANY_MASK + bool isOK = false; + if (finder.FindFirst(s, *this)) + { + if (Name == FTEXT(".")) + { + Name = path + prefixSize; + return true; + } + isOK = true; + /* if "\\server\share" maps to root folder "d:\", there is no "." item. + But it's possible that there are another items */ + } + { + const DWORD attrib = GetFileAttrib(path); + if (isOK || (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)) + { + ClearBase(); + if (attrib != INVALID_FILE_ATTRIBUTES) + Attrib = attrib; + else + SetAsDir(); + Name = path + prefixSize; + return true; + } + } + // ::SetLastError(lastError); + } + } + } + } + } + #endif + + bool res = finder.FindFirst(path, *this); + if (!followLink + || !res + || !HasReparsePoint()) + return res; + + // return FollowReparse(path, IsDir()); + return Fill_From_ByHandleFileInfo(path); +} + +bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) +{ + BY_HANDLE_FILE_INFORMATION info; + if (!NIO::CFileBase::GetFileInformation(path, &info)) + return false; + { + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + Attrib = info.dwFileAttributes; + return true; + } +} + +/* +bool CFileInfo::FollowReparse(CFSTR path, bool isDir) +{ + if (isDir) + { + FString prefix = path; + prefix.Add_PathSepar(); + + // "folder/." refers to folder itself. So we can't use that path + // we must use enumerator and search "." item + CEnumerator enumerator; + enumerator.SetDirPrefix(prefix); + for (;;) + { + CFileInfo fi; + if (!enumerator.NextAny(fi)) + break; + if (fi.Name.IsEqualTo_Ascii_NoCase(".")) + { + // we can copy preperies; + CTime = fi.CTime; + ATime = fi.ATime; + MTime = fi.MTime; + Attrib = fi.Attrib; + Size = fi.Size; + return true; + } + break; + } + // LastError(lastError); + return false; + } + + { + NIO::CInFile inFile; + if (inFile.Open(path)) + { + BY_HANDLE_FILE_INFORMATION info; + if (inFile.GetFileInformation(&info)) + { + ClearBase(); + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + Attrib = info.dwFileAttributes; + return true; + } + } + return false; + } +} +*/ + +bool DoesFileExist_Raw(CFSTR name) +{ + CFileInfo fi; + return fi.Find(name) && !fi.IsDir(); +} + +bool DoesFileExist_FollowLink(CFSTR name) +{ + CFileInfo fi; + return fi.Find_FollowLink(name) && !fi.IsDir(); +} + +bool DoesDirExist(CFSTR name, bool followLink) +{ + CFileInfo fi; + return fi.Find(name, followLink) && fi.IsDir(); +} + +bool DoesFileOrDirExist(CFSTR name) +{ + CFileInfo fi; + return fi.Find(name); +} + + +void CEnumerator::SetDirPrefix(const FString &dirPrefix) +{ + _wildcard = dirPrefix; + _wildcard.Add_Char('*'); +} + +bool CEnumerator::NextAny(CFileInfo &fi) +{ + if (_findFile.IsHandleAllocated()) + return _findFile.FindNext(fi); + else + return _findFile.FindFirst(_wildcard, fi); +} + +bool CEnumerator::Next(CFileInfo &fi) +{ + for (;;) + { + if (!NextAny(fi)) + return false; + if (!fi.IsDots()) + return true; + } +} + +bool CEnumerator::Next(CFileInfo &fi, bool &found) +{ + /* + for (;;) + { + if (!NextAny(fi)) + break; + if (!fi.IsDots()) + { + found = true; + return true; + } + } + */ + + if (Next(fi)) + { + found = true; + return true; + } + + found = false; + DWORD lastError = ::GetLastError(); + if (_findFile.IsHandleAllocated()) + return (lastError == ERROR_NO_MORE_FILES); + // we support the case for empty root folder: FindFirstFile("c:\\*") returns ERROR_FILE_NOT_FOUND + if (lastError == ERROR_FILE_NOT_FOUND) + return true; + if (lastError == ERROR_ACCESS_DENIED) + { + // here we show inaccessible root system folder as empty folder to eliminate redundant user warnings + const char *s = "System Volume Information" STRING_PATH_SEPARATOR "*"; + const int len = (int)strlen(s); + const int delta = (int)_wildcard.Len() - len; + if (delta == 0 || (delta > 0 && IS_PATH_SEPAR(_wildcard[(unsigned)delta - 1]))) + if (StringsAreEqual_Ascii(_wildcard.Ptr((unsigned)delta), s)) + return true; + } + return false; +} + + +//////////////////////////////// +// CFindChangeNotification +// FindFirstChangeNotification can return 0. MSDN doesn't tell about it. + +bool CFindChangeNotification::Close() throw() +{ + if (!IsHandleAllocated()) + return true; + if (!::FindCloseChangeNotification(_handle)) + return false; + _handle = INVALID_HANDLE_VALUE; + return true; +} + +HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter) +{ + #ifndef _UNICODE + if (!g_IsNT) + _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter); + else + #endif + { + IF_USE_MAIN_PATH + _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter); + #ifdef Z7_LONG_PATH + if (!IsHandleAllocated()) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + _handle = ::FindFirstChangeNotificationW(superPath, BoolToBOOL(watchSubtree), notifyFilter); + } + #endif + } + return _handle; +} + +#ifndef UNDER_CE + +bool MyGetLogicalDriveStrings(CObjectVector &driveStrings) +{ + driveStrings.Clear(); + #ifndef _UNICODE + if (!g_IsNT) + { + driveStrings.Clear(); + UINT32 size = GetLogicalDriveStrings(0, NULL); + if (size == 0) + return false; + CObjArray buf(size); + UINT32 newSize = GetLogicalDriveStrings(size, buf); + if (newSize == 0 || newSize > size) + return false; + AString s; + UINT32 prev = 0; + for (UINT32 i = 0; i < newSize; i++) + { + if (buf[i] == 0) + { + s = buf + prev; + prev = i + 1; + driveStrings.Add(fas2fs(s)); + } + } + return prev == newSize; + } + else + #endif + { + UINT32 size = GetLogicalDriveStringsW(0, NULL); + if (size == 0) + return false; + CObjArray buf(size); + UINT32 newSize = GetLogicalDriveStringsW(size, buf); + if (newSize == 0 || newSize > size) + return false; + UString s; + UINT32 prev = 0; + for (UINT32 i = 0; i < newSize; i++) + { + if (buf[i] == 0) + { + s = buf + prev; + prev = i + 1; + driveStrings.Add(us2fs(s)); + } + } + return prev == newSize; + } +} + +#endif // UNDER_CE + + + +#else // _WIN32 + +// ---------- POSIX ---------- + +static int MY_lstat(CFSTR path, struct stat *st, bool followLink) +{ + memset(st, 0, sizeof(*st)); + int res; + // #ifdef ENV_HAVE_LSTAT + if (/* global_use_lstat && */ !followLink) + { + // printf("\nlstat\n"); + res = lstat(path, st); + } + else + // #endif + { + // printf("\nstat\n"); + res = stat(path, st); + } +#if 0 +#if defined(__clang__) && __clang_major__ >= 14 + #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#endif + + printf("\n st_dev = %lld", (long long)(st->st_dev)); + printf("\n st_ino = %lld", (long long)(st->st_ino)); + printf("\n st_mode = %llx", (long long)(st->st_mode)); + printf("\n st_nlink = %lld", (long long)(st->st_nlink)); + printf("\n st_uid = %lld", (long long)(st->st_uid)); + printf("\n st_gid = %lld", (long long)(st->st_gid)); + printf("\n st_size = %lld", (long long)(st->st_size)); + printf("\n st_blksize = %lld", (long long)(st->st_blksize)); + printf("\n st_blocks = %lld", (long long)(st->st_blocks)); + printf("\n st_ctim = %lld", (long long)(ST_CTIME((*st)).tv_sec)); + printf("\n st_mtim = %lld", (long long)(ST_MTIME((*st)).tv_sec)); + printf("\n st_atim = %lld", (long long)(ST_ATIME((*st)).tv_sec)); + printf(S_ISFIFO(st->st_mode) ? "\n FIFO" : "\n NO FIFO"); + printf("\n"); +#endif + + return res; +} + + +static const char *Get_Name_from_Path(CFSTR path) throw() +{ + size_t len = strlen(path); + if (len == 0) + return path; + const char *p = path + len - 1; + { + if (p == path) + return path; + p--; + } + for (;;) + { + char c = *p; + if (IS_PATH_SEPAR(c)) + return p + 1; + if (p == path) + return path; + p--; + } +} + + +UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) +{ + UInt32 attrib = S_ISDIR(mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((mode & 0222) == 0) // S_IWUSR in p7zip + attrib |= FILE_ATTRIBUTE_READONLY; + return attrib | FILE_ATTRIBUTE_UNIX_EXTENSION | ((mode & 0xFFFF) << 16); +} + +/* +UInt32 Get_WinAttrib_From_stat(const struct stat &st) +{ + UInt32 attrib = S_ISDIR(st.st_mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + + if ((st.st_mode & 0222) == 0) // check it !!! + attrib |= FILE_ATTRIBUTE_READONLY; + + attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((st.st_mode & 0xFFFF) << 16); + return attrib; +} +*/ + +void CFileInfoBase::SetFrom_stat(const struct stat &st) +{ + // IsDevice = false; + + if (S_ISDIR(st.st_mode)) + { + Size = 0; + } + else + { + Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename + } + + // Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); + + // NTime::UnixTimeToFileTime(st.st_ctime, CTime); + // NTime::UnixTimeToFileTime(st.st_mtime, MTime); + // NTime::UnixTimeToFileTime(st.st_atime, ATime); + #ifdef __APPLE__ + // #ifdef _DARWIN_FEATURE_64_BIT_INODE + /* + here we can use birthtime instead of st_ctimespec. + but we use st_ctimespec for compatibility with previous versions and p7zip. + st_birthtimespec in OSX + st_birthtim : at FreeBSD, NetBSD + */ + // timespec_To_FILETIME(st.st_birthtimespec, CTime); + // #else + // timespec_To_FILETIME(st.st_ctimespec, CTime); + // #endif + // timespec_To_FILETIME(st.st_mtimespec, MTime); + // timespec_To_FILETIME(st.st_atimespec, ATime); + CTime = st.st_ctimespec; + MTime = st.st_mtimespec; + ATime = st.st_atimespec; + + #else + // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100); + // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100); + // timespec_To_FILETIME(st.st_atim, ATime, &ATime_ns100); + CTime = st.st_ctim; + MTime = st.st_mtim; + ATime = st.st_atim; + + #endif + + dev = st.st_dev; + ino = st.st_ino; + mode = st.st_mode; + nlink = st.st_nlink; + uid = st.st_uid; + gid = st.st_gid; + rdev = st.st_rdev; + + /* + printf("\n sizeof timespec = %d", (int)sizeof(timespec)); + printf("\n sizeof st_rdev = %d", (int)sizeof(rdev)); + printf("\n sizeof st_ino = %d", (int)sizeof(ino)); + printf("\n sizeof mode_t = %d", (int)sizeof(mode_t)); + printf("\n sizeof nlink_t = %d", (int)sizeof(nlink_t)); + printf("\n sizeof uid_t = %d", (int)sizeof(uid_t)); + printf("\n"); + */ + /* + printf("\n st_rdev = %llx", (long long)rdev); + printf("\n st_dev = %llx", (long long)dev); + printf("\n dev : major = %5x minor = %5x", (unsigned)major(dev), (unsigned)minor(dev)); + printf("\n st_ino = %lld", (long long)(ino)); + printf("\n rdev : major = %5x minor = %5x", (unsigned)major(rdev), (unsigned)minor(rdev)); + printf("\n size = %lld \n", (long long)(Size)); + printf("\n"); + */ +} + +/* +int Uid_To_Uname(uid_t uid, AString &name) +{ + name.Empty(); + struct passwd *passwd; + + if (uid != 0 && uid == cached_no_such_uid) + { + *uname = xstrdup (""); + return; + } + + if (!cached_uname || uid != cached_uid) + { + passwd = getpwuid (uid); + if (passwd) + { + cached_uid = uid; + assign_string (&cached_uname, passwd->pw_name); + } + else + { + cached_no_such_uid = uid; + *uname = xstrdup (""); + return; + } + } + *uname = xstrdup (cached_uname); +} +*/ + +bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) +{ + struct stat st; + if (MY_lstat(path, &st, followLink) != 0) + return false; + // printf("\nFind_DontFill_Name : name=%s\n", path); + SetFrom_stat(st); + return true; +} + + +bool CFileInfo::Find(CFSTR path, bool followLink) +{ + // printf("\nCEnumerator::Find() name = %s\n", path); + if (!Find_DontFill_Name(path, followLink)) + return false; + + // printf("\nOK\n"); + + Name = Get_Name_from_Path(path); + if (!Name.IsEmpty()) + { + char c = Name.Back(); + if (IS_PATH_SEPAR(c)) + Name.DeleteBack(); + } + return true; +} + + +bool DoesFileExist_Raw(CFSTR name) +{ + // FIXME for symbolic links. + struct stat st; + if (MY_lstat(name, &st, false) != 0) + return false; + return !S_ISDIR(st.st_mode); +} + +bool DoesFileExist_FollowLink(CFSTR name) +{ + // FIXME for symbolic links. + struct stat st; + if (MY_lstat(name, &st, true) != 0) + return false; + return !S_ISDIR(st.st_mode); +} + +bool DoesDirExist(CFSTR name, bool followLink) +{ + struct stat st; + if (MY_lstat(name, &st, followLink) != 0) + return false; + return S_ISDIR(st.st_mode); +} + +bool DoesFileOrDirExist(CFSTR name) +{ + struct stat st; + if (MY_lstat(name, &st, false) != 0) + return false; + return true; +} + + +CEnumerator::~CEnumerator() +{ + if (_dir) + closedir(_dir); +} + +void CEnumerator::SetDirPrefix(const FString &dirPrefix) +{ + _wildcard = dirPrefix; +} + +bool CDirEntry::IsDots() const throw() +{ + /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) + we can call fstatat() for that case, but we use only (Name) check here */ + +#if !defined(_AIX) && !defined(__sun) + if (Type != DT_DIR && Type != DT_UNKNOWN) + return false; +#endif + + return Name.Len() != 0 + && Name.Len() <= 2 + && Name[0] == '.' + && (Name.Len() == 1 || Name[1] == '.'); +} + + +bool CEnumerator::NextAny(CDirEntry &fi, bool &found) +{ + found = false; + + if (!_dir) + { + const char *w = "./"; + if (!_wildcard.IsEmpty()) + w = _wildcard.Ptr(); + _dir = ::opendir((const char *)w); + if (_dir == NULL) + return false; + } + + // To distinguish end of stream from an error, we must set errno to zero before readdir() + errno = 0; + + struct dirent *de = readdir(_dir); + if (!de) + { + if (errno == 0) + return true; // it's end of stream, and we report it with (found = false) + // it's real error + return false; + } + + fi.iNode = de->d_ino; + +#if !defined(_AIX) && !defined(__sun) + fi.Type = de->d_type; + /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN) + we can set (Type) from fstatat() in that case. + But (Type) is not too important. So we don't set it here with slow fstatat() */ + /* + // fi.Type = DT_UNKNOWN; // for debug + if (fi.Type == DT_UNKNOWN) + { + struct stat st; + if (fstatat(dirfd(_dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) == 0) + if (S_ISDIR(st.st_mode)) + fi.Type = DT_DIR; + } + */ +#endif + + /* + if (de->d_type == DT_DIR) + fi.Attrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(S_IFDIR) << 16); + else if (de->d_type < 16) + fi.Attrib = FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(de->d_type) << (16 + 12)); + */ + fi.Name = de->d_name; + + /* + printf("\nCEnumerator::NextAny; len = %d %s \n", (int)fi.Name.Len(), fi.Name.Ptr()); + for (unsigned i = 0; i < fi.Name.Len(); i++) + printf (" %02x", (unsigned)(Byte)de->d_name[i]); + printf("\n"); + */ + + found = true; + return true; +} + + +bool CEnumerator::Next(CDirEntry &fi, bool &found) +{ + // printf("\nCEnumerator::Next()\n"); + // PrintName("Next", ""); + for (;;) + { + if (!NextAny(fi, found)) + return false; + if (!found) + return true; + if (!fi.IsDots()) + { + /* + if (!NeedFullStat) + return true; + // we silently skip error file here - it can be wrong link item + if (fi.Find_DontFill_Name(path)) + return true; + */ + return true; + } + } +} + +/* +bool CEnumerator::Next(CDirEntry &fileInfo, bool &found) +{ + bool found; + if (!Next(fi, found)) + return false; + return found; +} +*/ + +bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const +{ + // printf("\nCEnumerator::Fill_FileInfo()\n"); + struct stat st; + // probably it's OK to use fstatat() even if it changes file position dirfd(_dir) + int res = fstatat(dirfd(_dir), de.Name, &st, followLink ? 0 : AT_SYMLINK_NOFOLLOW); + // if fstatat() is not supported, we can use stat() / lstat() + + /* + const FString path = _wildcard + s; + int res = MY_lstat(path, &st, followLink); + */ + + if (res != 0) + return false; + // printf("\nname=%s\n", de.Name.Ptr()); + fileInfo.SetFrom_stat(st); + fileInfo.Name = de.Name; + return true; +} + +#endif // _WIN32 + +}}} diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h index d67924581..f68673a17 100644 --- a/CPP/Windows/FileFind.h +++ b/CPP/Windows/FileFind.h @@ -1,347 +1,347 @@ -// Windows/FileFind.h - -#ifndef ZIP7_INC_WINDOWS_FILE_FIND_H -#define ZIP7_INC_WINDOWS_FILE_FIND_H - -#ifndef _WIN32 -#include -#include -#include -#endif - -#include "../Common/MyLinux.h" -#include "../Common/MyString.h" -#include "../Common/MyWindows.h" - -#include "Defs.h" - -#include "FileIO.h" - -namespace NWindows { -namespace NFile { -namespace NFind { - -// bool DoesFileExist(CFSTR name, bool followLink); -bool DoesFileExist_Raw(CFSTR name); -bool DoesFileExist_FollowLink(CFSTR name); -bool DoesDirExist(CFSTR name, bool followLink); - -inline bool DoesDirExist(CFSTR name) - { return DoesDirExist(name, false); } -inline bool DoesDirExist_FollowLink(CFSTR name) - { return DoesDirExist(name, true); } - -// it's always _Raw -bool DoesFileOrDirExist(CFSTR name); - -DWORD GetFileAttrib(CFSTR path); - -#ifdef _WIN32 - -namespace NAttributes -{ - inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; } - inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; } - inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; } - inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } - inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } - inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } - inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } - - inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib) - { - UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG; - /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY). - So extracting at Linux will be allowed to write files inside (0777) directories. */ - v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777); - return v; - } -} - -#else - -UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode); - -#endif - -class CFileInfoBase -{ - #ifdef _WIN32 - bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } - #endif -public: - UInt64 Size; - CFiTime CTime; - CFiTime ATime; - CFiTime MTime; - #ifdef _WIN32 - DWORD Attrib; - bool IsAltStream; - bool IsDevice; - - /* - #ifdef UNDER_CE - DWORD ObjectID; - #else - UINT32 ReparseTag; - #endif - */ - #else - dev_t dev; /* ID of device containing file */ - ino_t ino; - mode_t mode; - nlink_t nlink; - uid_t uid; /* user ID of owner */ - gid_t gid; /* group ID of owner */ - dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */ - // bool Use_lstat; - #endif - - CFileInfoBase() { ClearBase(); } - void ClearBase() throw(); - bool SetAs_StdInFile(); - - #ifdef _WIN32 - - bool Fill_From_ByHandleFileInfo(CFSTR path); - void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); - - bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } - bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } - bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } - bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } - bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } - bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } - bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } - bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } - bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } - bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } - bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } - bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } - - UInt32 GetWinAttrib() const { return Attrib; } - UInt32 GetPosixAttrib() const - { - return NAttributes::Get_PosixMode_From_WinAttrib(Attrib); - } - bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } - - #else - - UInt32 GetPosixAttrib() const { return mode; } - UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); } - - bool IsDir() const { return S_ISDIR(mode); } - void SetAsDir() { mode = S_IFDIR | 0777; } - void SetFrom_stat(const struct stat &st); - - bool IsReadOnly() const - { - // does linux support writing to ReadOnly files? - if ((mode & 0222) == 0) // S_IWUSR in p7zip - return true; - return false; - } - - bool IsPosixLink() const { return S_ISLNK(mode); } - - #endif - - bool IsOsSymLink() const - { - #ifdef _WIN32 - return HasReparsePoint(); - #else - return IsPosixLink(); - #endif - } -}; - -struct CFileInfo: public CFileInfoBase -{ - FString Name; - #if defined(_WIN32) && !defined(UNDER_CE) - // FString ShortName; - #endif - - bool IsDots() const throw(); - bool Find(CFSTR path, bool followLink = false); - bool Find_FollowLink(CFSTR path) { return Find(path, true); } - - #ifdef _WIN32 - // bool Fill_From_ByHandleFileInfo(CFSTR path); - // bool FollowReparse(CFSTR path, bool isDir); - #else - bool Find_DontFill_Name(CFSTR path, bool followLink = false); - #endif -}; - - -#ifdef _WIN32 - -class CFindFileBase MY_UNCOPYABLE -{ -protected: - HANDLE _handle; -public: - bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; } - CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {} - ~CFindFileBase() { Close(); } - bool Close() throw(); -}; - -class CFindFile: public CFindFileBase -{ -public: - bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo); - bool FindNext(CFileInfo &fileInfo); -}; - -#if defined(_WIN32) && !defined(UNDER_CE) - -struct CStreamInfo -{ - UString Name; - UInt64 Size; - - UString GetReducedName() const; // returns ":Name" - // UString GetReducedName2() const; // returns "Name" - bool IsMainStream() const throw(); -}; - -class CFindStream: public CFindFileBase -{ -public: - bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo); - bool FindNext(CStreamInfo &streamInfo); -}; - -class CStreamEnumerator MY_UNCOPYABLE -{ - CFindStream _find; - FString _filePath; - - bool NextAny(CFileInfo &fileInfo, bool &found); -public: - CStreamEnumerator(const FString &filePath): _filePath(filePath) {} - bool Next(CStreamInfo &streamInfo, bool &found); -}; - -#endif // defined(_WIN32) && !defined(UNDER_CE) - - -class CEnumerator MY_UNCOPYABLE -{ - CFindFile _findFile; - FString _wildcard; - - bool NextAny(CFileInfo &fileInfo); -public: - void SetDirPrefix(const FString &dirPrefix); - bool Next(CFileInfo &fileInfo); - bool Next(CFileInfo &fileInfo, bool &found); -}; - - -class CFindChangeNotification MY_UNCOPYABLE -{ - HANDLE _handle; -public: - operator HANDLE () { return _handle; } - bool IsHandleAllocated() const - { - /* at least on win2000/XP (undocumented): - if pathName is "" or NULL, - FindFirstChangeNotification() could return NULL. - So we check for INVALID_HANDLE_VALUE and NULL. - */ - return _handle != INVALID_HANDLE_VALUE && _handle != NULL; - } - CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {} - ~CFindChangeNotification() { Close(); } - bool Close() throw(); - HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter); - bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); } -}; - -#ifndef UNDER_CE -bool MyGetLogicalDriveStrings(CObjectVector &driveStrings); -#endif - -typedef CFileInfo CDirEntry; - - -#else // WIN32 - - -struct CDirEntry -{ - ino_t iNode; -#if !defined(_AIX) && !defined(__sun) - Byte Type; -#endif - FString Name; - - /* -#if !defined(_AIX) && !defined(__sun) - bool IsDir() const - { - // (Type == DT_UNKNOWN) on some systems - return Type == DT_DIR; - } -#endif - */ - - bool IsDots() const throw(); -}; - -class CEnumerator MY_UNCOPYABLE -{ - DIR *_dir; - FString _wildcard; - - bool NextAny(CDirEntry &fileInfo, bool &found); -public: - CEnumerator(): _dir(NULL) {} - ~CEnumerator(); - void SetDirPrefix(const FString &dirPrefix); - - bool Next(CDirEntry &fileInfo, bool &found); - bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const; - bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const - { -#if !defined(_AIX) && !defined(__sun) - if (de.Type == DT_DIR) - return true; - if (de.Type != DT_UNKNOWN) - return false; -#endif - CFileInfo fileInfo; - if (Fill_FileInfo(de, fileInfo, followLink)) - { - return fileInfo.IsDir(); - } - return false; // change it - } -}; - -/* -inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode) -{ - UInt32 attrib = S_ISDIR(mode) ? - FILE_ATTRIBUTE_DIRECTORY : - FILE_ATTRIBUTE_ARCHIVE; - if ((st.st_mode & 0222) == 0) // check it !!! - attrib |= FILE_ATTRIBUTE_READONLY; - return attrib; -} -*/ - -// UInt32 Get_WinAttrib_From_stat(const struct stat &st); - - -#endif // WIN32 - -}}} - -#endif +// Windows/FileFind.h + +#ifndef ZIP7_INC_WINDOWS_FILE_FIND_H +#define ZIP7_INC_WINDOWS_FILE_FIND_H + +#ifndef _WIN32 +#include +#include +#include +#endif + +#include "../Common/MyLinux.h" +#include "../Common/MyString.h" +#include "../Common/MyWindows.h" + +#include "Defs.h" + +#include "FileIO.h" + +namespace NWindows { +namespace NFile { +namespace NFind { + +// bool DoesFileExist(CFSTR name, bool followLink); +bool DoesFileExist_Raw(CFSTR name); +bool DoesFileExist_FollowLink(CFSTR name); +bool DoesDirExist(CFSTR name, bool followLink); + +inline bool DoesDirExist(CFSTR name) + { return DoesDirExist(name, false); } +inline bool DoesDirExist_FollowLink(CFSTR name) + { return DoesDirExist(name, true); } + +// it's always _Raw +bool DoesFileOrDirExist(CFSTR name); + +DWORD GetFileAttrib(CFSTR path); + +#ifdef _WIN32 + +namespace NAttributes +{ + inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; } + inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; } + inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; } + inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } + inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } + inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } + inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } + + inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib) + { + UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG; + /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY). + So extracting at Linux will be allowed to write files inside (0777) directories. */ + v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777); + return v; + } +} + +#else + +UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode); + +#endif + +class CFileInfoBase +{ + #ifdef _WIN32 + bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } + #endif +public: + UInt64 Size; + CFiTime CTime; + CFiTime ATime; + CFiTime MTime; + #ifdef _WIN32 + DWORD Attrib; + bool IsAltStream; + bool IsDevice; + + /* + #ifdef UNDER_CE + DWORD ObjectID; + #else + UINT32 ReparseTag; + #endif + */ + #else + dev_t dev; /* ID of device containing file */ + ino_t ino; + mode_t mode; + nlink_t nlink; + uid_t uid; /* user ID of owner */ + gid_t gid; /* group ID of owner */ + dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */ + // bool Use_lstat; + #endif + + CFileInfoBase() { ClearBase(); } + void ClearBase() throw(); + bool SetAs_StdInFile(); + + #ifdef _WIN32 + + bool Fill_From_ByHandleFileInfo(CFSTR path); + void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); + + bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } + bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } + bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } + bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } + bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } + bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } + bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } + bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } + bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } + bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } + bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } + bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } + + UInt32 GetWinAttrib() const { return Attrib; } + UInt32 GetPosixAttrib() const + { + return NAttributes::Get_PosixMode_From_WinAttrib(Attrib); + } + bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } + + #else + + UInt32 GetPosixAttrib() const { return mode; } + UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); } + + bool IsDir() const { return S_ISDIR(mode); } + void SetAsDir() { mode = S_IFDIR | 0777; } + void SetFrom_stat(const struct stat &st); + + bool IsReadOnly() const + { + // does linux support writing to ReadOnly files? + if ((mode & 0222) == 0) // S_IWUSR in p7zip + return true; + return false; + } + + bool IsPosixLink() const { return S_ISLNK(mode); } + + #endif + + bool IsOsSymLink() const + { + #ifdef _WIN32 + return HasReparsePoint(); + #else + return IsPosixLink(); + #endif + } +}; + +struct CFileInfo: public CFileInfoBase +{ + FString Name; + #if defined(_WIN32) && !defined(UNDER_CE) + // FString ShortName; + #endif + + bool IsDots() const throw(); + bool Find(CFSTR path, bool followLink = false); + bool Find_FollowLink(CFSTR path) { return Find(path, true); } + + #ifdef _WIN32 + // bool Fill_From_ByHandleFileInfo(CFSTR path); + // bool FollowReparse(CFSTR path, bool isDir); + #else + bool Find_DontFill_Name(CFSTR path, bool followLink = false); + #endif +}; + + +#ifdef _WIN32 + +class CFindFileBase MY_UNCOPYABLE +{ +protected: + HANDLE _handle; +public: + bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; } + CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {} + ~CFindFileBase() { Close(); } + bool Close() throw(); +}; + +class CFindFile: public CFindFileBase +{ +public: + bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo); + bool FindNext(CFileInfo &fileInfo); +}; + +#if defined(_WIN32) && !defined(UNDER_CE) + +struct CStreamInfo +{ + UString Name; + UInt64 Size; + + UString GetReducedName() const; // returns ":Name" + // UString GetReducedName2() const; // returns "Name" + bool IsMainStream() const throw(); +}; + +class CFindStream: public CFindFileBase +{ +public: + bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo); + bool FindNext(CStreamInfo &streamInfo); +}; + +class CStreamEnumerator MY_UNCOPYABLE +{ + CFindStream _find; + FString _filePath; + + bool NextAny(CFileInfo &fileInfo, bool &found); +public: + CStreamEnumerator(const FString &filePath): _filePath(filePath) {} + bool Next(CStreamInfo &streamInfo, bool &found); +}; + +#endif // defined(_WIN32) && !defined(UNDER_CE) + + +class CEnumerator MY_UNCOPYABLE +{ + CFindFile _findFile; + FString _wildcard; + + bool NextAny(CFileInfo &fileInfo); +public: + void SetDirPrefix(const FString &dirPrefix); + bool Next(CFileInfo &fileInfo); + bool Next(CFileInfo &fileInfo, bool &found); +}; + + +class CFindChangeNotification MY_UNCOPYABLE +{ + HANDLE _handle; +public: + operator HANDLE () { return _handle; } + bool IsHandleAllocated() const + { + /* at least on win2000/XP (undocumented): + if pathName is "" or NULL, + FindFirstChangeNotification() could return NULL. + So we check for INVALID_HANDLE_VALUE and NULL. + */ + return _handle != INVALID_HANDLE_VALUE && _handle != NULL; + } + CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {} + ~CFindChangeNotification() { Close(); } + bool Close() throw(); + HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter); + bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); } +}; + +#ifndef UNDER_CE +bool MyGetLogicalDriveStrings(CObjectVector &driveStrings); +#endif + +typedef CFileInfo CDirEntry; + + +#else // WIN32 + + +struct CDirEntry +{ + ino_t iNode; +#if !defined(_AIX) && !defined(__sun) + Byte Type; +#endif + FString Name; + + /* +#if !defined(_AIX) && !defined(__sun) + bool IsDir() const + { + // (Type == DT_UNKNOWN) on some systems + return Type == DT_DIR; + } +#endif + */ + + bool IsDots() const throw(); +}; + +class CEnumerator MY_UNCOPYABLE +{ + DIR *_dir; + FString _wildcard; + + bool NextAny(CDirEntry &fileInfo, bool &found); +public: + CEnumerator(): _dir(NULL) {} + ~CEnumerator(); + void SetDirPrefix(const FString &dirPrefix); + + bool Next(CDirEntry &fileInfo, bool &found); + bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const; + bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const + { +#if !defined(_AIX) && !defined(__sun) + if (de.Type == DT_DIR) + return true; + if (de.Type != DT_UNKNOWN) + return false; +#endif + CFileInfo fileInfo; + if (Fill_FileInfo(de, fileInfo, followLink)) + { + return fileInfo.IsDir(); + } + return false; // change it + } +}; + +/* +inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode) +{ + UInt32 attrib = S_ISDIR(mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((st.st_mode & 0222) == 0) // check it !!! + attrib |= FILE_ATTRIBUTE_READONLY; + return attrib; +} +*/ + +// UInt32 Get_WinAttrib_From_stat(const struct stat &st); + + +#endif // WIN32 + +}}} + +#endif diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp index bb7aef95e..dc4de14dc 100644 --- a/CPP/Windows/FileIO.cpp +++ b/CPP/Windows/FileIO.cpp @@ -1,954 +1,954 @@ -// Windows/FileIO.cpp - -#include "StdAfx.h" - -#ifdef Z7_DEVICE_FILE -#include "../../C/Alloc.h" -#endif - -// #include - -/* -#ifndef _WIN32 -// for ioctl BLKGETSIZE64 -#include -#include -#endif -*/ - -#include "FileIO.h" -#include "FileName.h" - -HRESULT GetLastError_noZero_HRESULT() -{ - const DWORD res = ::GetLastError(); - if (res == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(res); -} - -#ifdef _WIN32 - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -using namespace NWindows; -using namespace NFile; -using namespace NName; - -namespace NWindows { -namespace NFile { - -#ifdef Z7_DEVICE_FILE - -namespace NSystem -{ -bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); -} -#endif - -namespace NIO { - -/* -WinXP-64 CreateFile(): - "" - ERROR_PATH_NOT_FOUND - :stream - OK - .:stream - ERROR_PATH_NOT_FOUND - .\:stream - OK - - folder\:stream - ERROR_INVALID_NAME - folder:stream - OK - - c:\:stream - OK - - c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 ) - c::stream - OK, if current dir is ROOT ( c:\ ) -*/ - -bool CFileBase::Create(CFSTR path, DWORD desiredAccess, - DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) -{ - if (!Close()) - return false; - - #ifdef Z7_DEVICE_FILE - IsDeviceFile = false; - #endif - - #ifndef _UNICODE - if (!g_IsNT) - { - _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode, - (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); - } - else - #endif - { - IF_USE_MAIN_PATH - _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode, - (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); - #ifdef Z7_LONG_PATH - if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) - { - UString superPath; - if (GetSuperPath(path, superPath, USE_MAIN_PATH)) - _handle = ::CreateFileW(superPath, desiredAccess, shareMode, - (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); - } - #endif - } - - /* - #ifndef UNDER_CE - #ifndef Z7_SFX - if (_handle == INVALID_HANDLE_VALUE) - { - // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10 - DWORD lastError = GetLastError(); - if (lastError == ERROR_CANT_ACCESS_FILE) - { - CByteBuffer buf; - if (NIO::GetReparseData(path, buf, NULL)) - { - CReparseAttr attr; - if (attr.Parse(buf, buf.Size())) - { - FString dirPrefix, fileName; - if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName)) - { - FString fullPath; - if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath)) - { - // FIX IT: recursion levels must be restricted - return Create(fullPath, desiredAccess, - shareMode, creationDisposition, flagsAndAttributes); - } - } - } - } - SetLastError(lastError); - } - } - #endif - #endif - */ - - return (_handle != INVALID_HANDLE_VALUE); -} - -bool CFileBase::Close() throw() -{ - if (_handle == INVALID_HANDLE_VALUE) - return true; -#if 0 - if (!IsStdStream) -#endif - { - if (!::CloseHandle(_handle)) - return false; - } -#if 0 - IsStdStream = false; - IsStdPipeStream = false; -#endif - _handle = INVALID_HANDLE_VALUE; - return true; -} - -bool CFileBase::GetLength(UInt64 &length) const throw() -{ - #ifdef Z7_DEVICE_FILE - if (IsDeviceFile && SizeDefined) - { - length = Size; - return true; - } - #endif - - DWORD high = 0; - const DWORD low = ::GetFileSize(_handle, &high); - if (low == INVALID_FILE_SIZE) - if (::GetLastError() != NO_ERROR) - return false; - length = (((UInt64)high) << 32) + low; - return true; - - /* - LARGE_INTEGER fileSize; - // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+ - if (!GetFileSizeEx(_handle, &fileSize)) - return false; - length = (UInt64)fileSize.QuadPart; - return true; - */ -} - - -/* Specification for SetFilePointer(): - - If a new file pointer is a negative value, - { - the function fails, - the file pointer is not moved, - the code returned by GetLastError() is ERROR_NEGATIVE_SEEK. - } - - If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set - { - an application can move the file pointer only to sector-aligned positions. - A sector-aligned position is a position that is a whole number multiple of - the volume sector size. - An application can obtain a volume sector size by calling the GetDiskFreeSpace. - } - - It is not an error to set a file pointer to a position beyond the end of the file. - The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function. - - If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL, - an application must call GetLastError to determine whether or not the function has succeeded or failed. -*/ - -bool CFileBase::GetPosition(UInt64 &position) const throw() -{ - LONG high = 0; - const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT); - if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) - { - // for error case we can set (position) to (-1) or (0) or leave (position) unchanged. - // position = (UInt64)(Int64)-1; // for debug - position = 0; - return false; - } - position = (((UInt64)(UInt32)high) << 32) + low; - return true; - // we don't want recursed GetPosition() - // return Seek(0, FILE_CURRENT, position); -} - -bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw() -{ - #ifdef Z7_DEVICE_FILE - if (IsDeviceFile && SizeDefined && moveMethod == FILE_END) - { - distanceToMove += Size; - moveMethod = FILE_BEGIN; - } - #endif - - LONG high = (LONG)(distanceToMove >> 32); - const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod); - if (low == INVALID_SET_FILE_POINTER) - { - const DWORD lastError = ::GetLastError(); - if (lastError != NO_ERROR) - { - // 21.07: we set (newPosition) to real position even after error. - GetPosition(newPosition); - SetLastError(lastError); // restore LastError - return false; - } - } - newPosition = (((UInt64)(UInt32)high) << 32) + low; - return true; -} - -bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw() -{ - return Seek((Int64)position, FILE_BEGIN, newPosition); -} - -bool CFileBase::SeekToBegin() const throw() -{ - UInt64 newPosition = 0; - return Seek(0, newPosition) && (newPosition == 0); -} - -bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw() -{ - return Seek(0, FILE_END, newPosition); -} - -// ---------- CInFile --------- - -#ifdef Z7_DEVICE_FILE - -void CInFile::CorrectDeviceSize() -{ - // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail - const UInt32 kClusterSize = 1 << 14; - UInt64 pos = Size & ~(UInt64)(kClusterSize - 1); - UInt64 realNewPosition; - if (!Seek(pos, realNewPosition)) - return; - Byte *buf = (Byte *)MidAlloc(kClusterSize); - - bool needbackward = true; - - for (;;) - { - UInt32 processed = 0; - // up test is slow for "PhysicalDrive". - // processed size for latest block for "PhysicalDrive0" is 0. - if (!Read1(buf, kClusterSize, processed)) - break; - if (processed == 0) - break; - needbackward = false; - Size = pos + processed; - if (processed != kClusterSize) - break; - pos += kClusterSize; - } - - if (needbackward && pos != 0) - { - pos -= kClusterSize; - for (;;) - { - // break; - if (!Seek(pos, realNewPosition)) - break; - if (!buf) - { - buf = (Byte *)MidAlloc(kClusterSize); - if (!buf) - break; - } - UInt32 processed = 0; - // that code doesn't work for "PhysicalDrive0" - if (!Read1(buf, kClusterSize, processed)) - break; - if (processed != 0) - { - Size = pos + processed; - break; - } - if (pos == 0) - break; - pos -= kClusterSize; - } - } - MidFree(buf); -} - - -void CInFile::CalcDeviceSize(CFSTR s) -{ - SizeDefined = false; - Size = 0; - if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile) - return; - #ifdef UNDER_CE - - SizeDefined = true; - Size = 128 << 20; - - #else - - PARTITION_INFORMATION partInfo; - bool needCorrectSize = true; - - /* - WinXP 64-bit: - - HDD \\.\PhysicalDrive0 (MBR): - GetPartitionInfo == GeometryEx : corrrect size? (includes tail) - Geometry : smaller than GeometryEx (no tail, maybe correct too?) - MyGetDiskFreeSpace : FAIL - Size correction is slow and block size (kClusterSize) must be small? - - HDD partition \\.\N: (NTFS): - MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction - GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS - Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition) - - CD-ROM drive (ISO): - MyGetDiskFreeSpace : correct size. Same size can be calculated after correction - Geometry == CdRomGeometry : smaller than corrrect size - GetPartitionInfo == GeometryEx : larger than corrrect size - - Floppy \\.\a: (FAT): - Geometry : correct size. - CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL - correction works OK for FAT. - correction works OK for non-FAT, if kClusterSize = 512. - */ - - if (GetPartitionInfo(&partInfo)) - { - Size = (UInt64)partInfo.PartitionLength.QuadPart; - SizeDefined = true; - needCorrectSize = false; - if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0) - { - FChar path[4] = { s[4], ':', '\\', 0 }; - UInt64 clusterSize, totalSize, freeSize; - if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize)) - Size = totalSize; - else - needCorrectSize = true; - } - } - - if (!SizeDefined) - { - my_DISK_GEOMETRY_EX geomEx; - SizeDefined = GetGeometryEx(&geomEx); - if (SizeDefined) - Size = (UInt64)geomEx.DiskSize.QuadPart; - else - { - DISK_GEOMETRY geom; - SizeDefined = GetGeometry(&geom); - if (!SizeDefined) - SizeDefined = GetCdRomGeometry(&geom); - if (SizeDefined) - Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; - } - } - - if (needCorrectSize && SizeDefined && Size != 0) - { - CorrectDeviceSize(); - SeekToBegin(); - } - - // SeekToBegin(); - #endif -} - -// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 && - -#define MY_DEVICE_EXTRA_CODE \ - IsDeviceFile = IsDevicePath(fileName); \ - CalcDeviceSize(fileName); -#else -#define MY_DEVICE_EXTRA_CODE -#endif - -bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) -{ - DWORD desiredAccess = GENERIC_READ; - - #ifdef _WIN32 - if (PreserveATime) - desiredAccess |= FILE_WRITE_ATTRIBUTES; - #endif - - bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes); - - #ifdef _WIN32 - if (res && PreserveATime) - { - FILETIME ft; - ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF; - ::SetFileTime(_handle, NULL, &ft, NULL); - } - #endif - - MY_DEVICE_EXTRA_CODE - return res; -} - -bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite) -{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } - -bool CInFile::Open(CFSTR fileName) - { return OpenShared(fileName, false); } - -// ReadFile and WriteFile functions in Windows have BUG: -// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) -// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES -// (Insufficient system resources exist to complete the requested service). - -// Probably in some version of Windows there are problems with other sizes: -// for 32 MB (maybe also for 16 MB). -// And message can be "Network connection was lost" - -static const UInt32 kChunkSizeMax = 1 << 22; - -bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw() -{ - DWORD processedLoc = 0; - const bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); - processedSize = (UInt32)processedLoc; - return res; -} - -bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw() -{ -#if 0 - const UInt32 chunkSizeMax = (0 || IsStdStream) ? (1 << 20) : kChunkSizeMax; - if (size > chunkSizeMax) - size = chunkSizeMax; -#else - if (size > kChunkSizeMax) - size = kChunkSizeMax; -#endif - return Read1(data, size, processedSize); -} - -bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw() -{ - processedSize = 0; - do - { - UInt32 processedLoc = 0; - const bool res = ReadPart(data, size, processedLoc); - processedSize += processedLoc; - if (!res) - return false; - if (processedLoc == 0) - return true; - data = (void *)((Byte *)data + processedLoc); - size -= processedLoc; - } - while (size); - return true; -} - -bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw() -{ - processedSize = 0; - do - { - UInt32 processedLoc = 0; - const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size); - const bool res = Read1(data, sizeLoc, processedLoc); - processedSize += processedLoc; - if (!res) - return false; - if (processedLoc == 0) - return true; - data = (void *)((Byte *)data + processedLoc); - size -= processedLoc; - } - while (size); - return true; -} - -// ---------- COutFile --------- - -bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) - { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } - -bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition) - { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } - -bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) - { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); } - -bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() - { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } - -bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); } - -bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw() -{ - if (size > kChunkSizeMax) - size = kChunkSizeMax; - DWORD processedLoc = 0; - bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); - processedSize = (UInt32)processedLoc; - return res; -} - -bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw() -{ - processedSize = 0; - do - { - UInt32 processedLoc = 0; - const bool res = WritePart(data, size, processedLoc); - processedSize += processedLoc; - if (!res) - return false; - if (processedLoc == 0) - return true; - data = (const void *)((const Byte *)data + processedLoc); - size -= processedLoc; - } - while (size); - return true; -} - -bool COutFile::WriteFull(const void *data, size_t size) throw() -{ - do - { - UInt32 processedLoc = 0; - const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size); - if (!WritePart(data, sizeCur, processedLoc)) - return false; - if (processedLoc == 0) - return (size == 0); - data = (const void *)((const Byte *)data + processedLoc); - size -= processedLoc; - } - while (size); - return true; -} - -bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); } - -bool COutFile::SetLength(UInt64 length) throw() -{ - UInt64 newPosition; - if (!Seek(length, newPosition)) - return false; - if (newPosition != length) - return false; - return SetEndOfFile(); -} - -bool COutFile::SetLength_KeepPosition(UInt64 length) throw() -{ - UInt64 currentPos = 0; - if (!GetPosition(currentPos)) - return false; - DWORD lastError = 0; - const bool result = SetLength(length); - if (!result) - lastError = GetLastError(); - UInt64 currentPos2; - const bool result2 = Seek(currentPos, currentPos2); - if (lastError != 0) - SetLastError(lastError); - return (result && result2); -} - -}}} - -#else // _WIN32 - - -// POSIX - -#include -#include - -namespace NWindows { -namespace NFile { - -namespace NDir { -bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); -} - -namespace NIO { - -bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode) -{ - #ifdef O_BINARY - flags |= O_BINARY; - #endif - - Close(); - _handle = ::open(name, flags, mode); - return _handle != -1; - - /* - if (_handle == -1) - return false; - if (IsString1PrefixedByString2(name, "/dev/")) - { - // /dev/sda - // IsDeviceFile = true; // for debug - // SizeDefined = false; - // SizeDefined = (GetDeviceSize_InBytes(Size) == 0); - } - return true; - */ -} - -bool CFileBase::Close() -{ - if (_handle == -1) - return true; - if (close(_handle) != 0) - return false; - _handle = -1; - /* - IsDeviceFile = false; - SizeDefined = false; - */ - return true; -} - -bool CFileBase::GetLength(UInt64 &length) const -{ - length = 0; - // length = (UInt64)(Int64)-1; // for debug - const off_t curPos = seekToCur(); - if (curPos == -1) - return false; - const off_t lengthTemp = seek(0, SEEK_END); - seek(curPos, SEEK_SET); - length = (UInt64)lengthTemp; - - /* - // 22.00: - if (lengthTemp == 1) - if (IsDeviceFile && SizeDefined) - { - length = Size; - return true; - } - */ - - return (lengthTemp != -1); -} - -off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const -{ - /* - if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END) - { - printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove); - distanceToMove += Size; - moveMethod = SEEK_SET; - } - */ - - // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove); - // off_t res = ::lseek(_handle, distanceToMove, moveMethod); - // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove); - return ::lseek(_handle, distanceToMove, moveMethod); - // return res; -} - -off_t CFileBase::seekToBegin() const throw() -{ - return seek(0, SEEK_SET); -} - -off_t CFileBase::seekToCur() const throw() -{ - return seek(0, SEEK_CUR); -} - -/* -bool CFileBase::SeekToBegin() const throw() -{ - return (::seek(0, SEEK_SET) != -1); -} -*/ - - -///////////////////////// -// CInFile - -bool CInFile::Open(const char *name) -{ - return CFileBase::OpenBinary(name, O_RDONLY); -} - -bool CInFile::OpenShared(const char *name, bool) -{ - return Open(name); -} - - -/* -int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks) -{ - // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition - // #include - return ioctl(_handle, BLKGETSIZE64, numBlocks); - // in block size -} - -int CFileBase::GetDeviceSize_InBytes(UInt64 &size) -{ - size = 0; - unsigned long long numBlocks; - int res = my_ioctl_BLKGETSIZE64(&numBlocks); - if (res == 0) - size = numBlocks; // another blockSize s possible? - printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size); - return res; -} -*/ - -/* -On Linux (32-bit and 64-bit): -read(), write() (and similar system calls) will transfer at most -0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred. -*/ - -static const size_t kChunkSizeMax = ((size_t)1 << 22); - -ssize_t CInFile::read_part(void *data, size_t size) throw() -{ - if (size > kChunkSizeMax) - size = kChunkSizeMax; - return ::read(_handle, data, size); -} - -bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw() -{ - processed = 0; - do - { - const ssize_t res = read_part(data, size); - if (res < 0) - return false; - if (res == 0) - break; - data = (void *)((Byte *)data + (size_t)res); - processed += (size_t)res; - size -= (size_t)res; - } - while (size); - return true; -} - - -///////////////////////// -// COutFile - -bool COutFile::OpenBinary_forWrite_oflag(const char *name, int oflag) -{ - Path = name; // change it : set it only if open is success. - return OpenBinary(name, oflag, mode_for_Create); -} - - -/* - windows exist non-exist posix - CREATE_NEW Fail Create O_CREAT | O_EXCL - CREATE_ALWAYS Trunc Create O_CREAT | O_TRUNC - OPEN_ALWAYS Open Create O_CREAT - OPEN_EXISTING Open Fail 0 - TRUNCATE_EXISTING Trunc Fail O_TRUNC ??? - - // O_CREAT = If the file exists, this flag has no effect except as noted under O_EXCL below. - // If O_CREAT and O_EXCL are set, open() shall fail if the file exists. - // O_TRUNC : If the file exists and the file is successfully opened, its length shall be truncated to 0. -*/ -bool COutFile::Open_EXISTING(const char *name) - { return OpenBinary_forWrite_oflag(name, O_WRONLY); } -bool COutFile::Create_ALWAYS(const char *name) - { return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_TRUNC); } -bool COutFile::Create_NEW(const char *name) - { return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_EXCL); } -bool COutFile::Create_ALWAYS_or_Open_ALWAYS(const char *name, bool createAlways) -{ - return OpenBinary_forWrite_oflag(name, - createAlways ? - O_WRONLY | O_CREAT | O_TRUNC : - O_WRONLY | O_CREAT); -} -/* -bool COutFile::Create_ALWAYS_or_NEW(const char *name, bool createAlways) -{ - return OpenBinary_forWrite_oflag(name, - createAlways ? - O_WRONLY | O_CREAT | O_TRUNC : - O_WRONLY | O_CREAT | O_EXCL); -} -bool COutFile::Open_Disposition(const char *name, DWORD creationDisposition) -{ - int flag; - switch (creationDisposition) - { - case CREATE_NEW: flag = O_WRONLY | O_CREAT | O_EXCL; break; - case CREATE_ALWAYS: flag = O_WRONLY | O_CREAT | O_TRUNC; break; - case OPEN_ALWAYS: flag = O_WRONLY | O_CREAT; break; - case OPEN_EXISTING: flag = O_WRONLY; break; - case TRUNCATE_EXISTING: flag = O_WRONLY | O_TRUNC; break; - default: - SetLastError(EINVAL); - return false; - } - return OpenBinary_forWrite_oflag(name, flag); -} -*/ - -ssize_t COutFile::write_part(const void *data, size_t size) throw() -{ - if (size > kChunkSizeMax) - size = kChunkSizeMax; - return ::write(_handle, data, size); -} - -ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw() -{ - processed = 0; - do - { - const ssize_t res = write_part(data, size); - if (res < 0) - return res; - if (res == 0) - break; - data = (const void *)((const Byte *)data + (size_t)res); - processed += (size_t)res; - size -= (size_t)res; - } - while (size); - return (ssize_t)processed; -} - -bool COutFile::SetLength(UInt64 length) throw() -{ - const off_t len2 = (off_t)length; - if ((Int64)length != len2) - { - SetLastError(EFBIG); - return false; - } - // The value of the seek pointer shall not be modified by a call to ftruncate(). - const int iret = ftruncate(_handle, len2); - return (iret == 0); -} - -bool COutFile::Close() -{ - const bool res = CFileBase::Close(); - if (!res) - return res; - if (CTime_defined || ATime_defined || MTime_defined) - { - /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, - CTime_defined ? &CTime : NULL, - ATime_defined ? &ATime : NULL, - MTime_defined ? &MTime : NULL); - } - return res; -} - -bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw() -{ - // On some OS (cygwin, MacOSX ...), you must close the file before updating times - // return true; - - if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false; - if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false; - if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; - return true; - - /* - struct timespec times[2]; - UNUSED_VAR(cTime) - if (!aTime && !mTime) - return true; - bool needChange; - needChange = FiTime_To_timespec(aTime, times[0]); - needChange |= FiTime_To_timespec(mTime, times[1]); - if (!needChange) - return true; - return futimens(_handle, times) == 0; - */ -} - -bool COutFile::SetMTime(const CFiTime *mTime) throw() -{ - if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; - return true; -} - -}}} - - -#endif +// Windows/FileIO.cpp + +#include "StdAfx.h" + +#ifdef Z7_DEVICE_FILE +#include "../../C/Alloc.h" +#endif + +// #include + +/* +#ifndef _WIN32 +// for ioctl BLKGETSIZE64 +#include +#include +#endif +*/ + +#include "FileIO.h" +#include "FileName.h" + +HRESULT GetLastError_noZero_HRESULT() +{ + const DWORD res = ::GetLastError(); + if (res == 0) + return E_FAIL; + return HRESULT_FROM_WIN32(res); +} + +#ifdef _WIN32 + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +namespace NWindows { +namespace NFile { + +#ifdef Z7_DEVICE_FILE + +namespace NSystem +{ +bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); +} +#endif + +namespace NIO { + +/* +WinXP-64 CreateFile(): + "" - ERROR_PATH_NOT_FOUND + :stream - OK + .:stream - ERROR_PATH_NOT_FOUND + .\:stream - OK + + folder\:stream - ERROR_INVALID_NAME + folder:stream - OK + + c:\:stream - OK + + c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 ) + c::stream - OK, if current dir is ROOT ( c:\ ) +*/ + +bool CFileBase::Create(CFSTR path, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) +{ + if (!Close()) + return false; + + #ifdef Z7_DEVICE_FILE + IsDeviceFile = false; + #endif + + #ifndef _UNICODE + if (!g_IsNT) + { + _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode, + (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); + } + else + #endif + { + IF_USE_MAIN_PATH + _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode, + (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); + #ifdef Z7_LONG_PATH + if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH) + { + UString superPath; + if (GetSuperPath(path, superPath, USE_MAIN_PATH)) + _handle = ::CreateFileW(superPath, desiredAccess, shareMode, + (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL); + } + #endif + } + + /* + #ifndef UNDER_CE + #ifndef Z7_SFX + if (_handle == INVALID_HANDLE_VALUE) + { + // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10 + DWORD lastError = GetLastError(); + if (lastError == ERROR_CANT_ACCESS_FILE) + { + CByteBuffer buf; + if (NIO::GetReparseData(path, buf, NULL)) + { + CReparseAttr attr; + if (attr.Parse(buf, buf.Size())) + { + FString dirPrefix, fileName; + if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName)) + { + FString fullPath; + if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath)) + { + // FIX IT: recursion levels must be restricted + return Create(fullPath, desiredAccess, + shareMode, creationDisposition, flagsAndAttributes); + } + } + } + } + SetLastError(lastError); + } + } + #endif + #endif + */ + + return (_handle != INVALID_HANDLE_VALUE); +} + +bool CFileBase::Close() throw() +{ + if (_handle == INVALID_HANDLE_VALUE) + return true; +#if 0 + if (!IsStdStream) +#endif + { + if (!::CloseHandle(_handle)) + return false; + } +#if 0 + IsStdStream = false; + IsStdPipeStream = false; +#endif + _handle = INVALID_HANDLE_VALUE; + return true; +} + +bool CFileBase::GetLength(UInt64 &length) const throw() +{ + #ifdef Z7_DEVICE_FILE + if (IsDeviceFile && SizeDefined) + { + length = Size; + return true; + } + #endif + + DWORD high = 0; + const DWORD low = ::GetFileSize(_handle, &high); + if (low == INVALID_FILE_SIZE) + if (::GetLastError() != NO_ERROR) + return false; + length = (((UInt64)high) << 32) + low; + return true; + + /* + LARGE_INTEGER fileSize; + // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+ + if (!GetFileSizeEx(_handle, &fileSize)) + return false; + length = (UInt64)fileSize.QuadPart; + return true; + */ +} + + +/* Specification for SetFilePointer(): + + If a new file pointer is a negative value, + { + the function fails, + the file pointer is not moved, + the code returned by GetLastError() is ERROR_NEGATIVE_SEEK. + } + + If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set + { + an application can move the file pointer only to sector-aligned positions. + A sector-aligned position is a position that is a whole number multiple of + the volume sector size. + An application can obtain a volume sector size by calling the GetDiskFreeSpace. + } + + It is not an error to set a file pointer to a position beyond the end of the file. + The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function. + + If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL, + an application must call GetLastError to determine whether or not the function has succeeded or failed. +*/ + +bool CFileBase::GetPosition(UInt64 &position) const throw() +{ + LONG high = 0; + const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT); + if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + { + // for error case we can set (position) to (-1) or (0) or leave (position) unchanged. + // position = (UInt64)(Int64)-1; // for debug + position = 0; + return false; + } + position = (((UInt64)(UInt32)high) << 32) + low; + return true; + // we don't want recursed GetPosition() + // return Seek(0, FILE_CURRENT, position); +} + +bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw() +{ + #ifdef Z7_DEVICE_FILE + if (IsDeviceFile && SizeDefined && moveMethod == FILE_END) + { + distanceToMove += Size; + moveMethod = FILE_BEGIN; + } + #endif + + LONG high = (LONG)(distanceToMove >> 32); + const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod); + if (low == INVALID_SET_FILE_POINTER) + { + const DWORD lastError = ::GetLastError(); + if (lastError != NO_ERROR) + { + // 21.07: we set (newPosition) to real position even after error. + GetPosition(newPosition); + SetLastError(lastError); // restore LastError + return false; + } + } + newPosition = (((UInt64)(UInt32)high) << 32) + low; + return true; +} + +bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw() +{ + return Seek((Int64)position, FILE_BEGIN, newPosition); +} + +bool CFileBase::SeekToBegin() const throw() +{ + UInt64 newPosition = 0; + return Seek(0, newPosition) && (newPosition == 0); +} + +bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw() +{ + return Seek(0, FILE_END, newPosition); +} + +// ---------- CInFile --------- + +#ifdef Z7_DEVICE_FILE + +void CInFile::CorrectDeviceSize() +{ + // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail + const UInt32 kClusterSize = 1 << 14; + UInt64 pos = Size & ~(UInt64)(kClusterSize - 1); + UInt64 realNewPosition; + if (!Seek(pos, realNewPosition)) + return; + Byte *buf = (Byte *)MidAlloc(kClusterSize); + + bool needbackward = true; + + for (;;) + { + UInt32 processed = 0; + // up test is slow for "PhysicalDrive". + // processed size for latest block for "PhysicalDrive0" is 0. + if (!Read1(buf, kClusterSize, processed)) + break; + if (processed == 0) + break; + needbackward = false; + Size = pos + processed; + if (processed != kClusterSize) + break; + pos += kClusterSize; + } + + if (needbackward && pos != 0) + { + pos -= kClusterSize; + for (;;) + { + // break; + if (!Seek(pos, realNewPosition)) + break; + if (!buf) + { + buf = (Byte *)MidAlloc(kClusterSize); + if (!buf) + break; + } + UInt32 processed = 0; + // that code doesn't work for "PhysicalDrive0" + if (!Read1(buf, kClusterSize, processed)) + break; + if (processed != 0) + { + Size = pos + processed; + break; + } + if (pos == 0) + break; + pos -= kClusterSize; + } + } + MidFree(buf); +} + + +void CInFile::CalcDeviceSize(CFSTR s) +{ + SizeDefined = false; + Size = 0; + if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile) + return; + #ifdef UNDER_CE + + SizeDefined = true; + Size = 128 << 20; + + #else + + PARTITION_INFORMATION partInfo; + bool needCorrectSize = true; + + /* + WinXP 64-bit: + + HDD \\.\PhysicalDrive0 (MBR): + GetPartitionInfo == GeometryEx : corrrect size? (includes tail) + Geometry : smaller than GeometryEx (no tail, maybe correct too?) + MyGetDiskFreeSpace : FAIL + Size correction is slow and block size (kClusterSize) must be small? + + HDD partition \\.\N: (NTFS): + MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction + GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS + Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition) + + CD-ROM drive (ISO): + MyGetDiskFreeSpace : correct size. Same size can be calculated after correction + Geometry == CdRomGeometry : smaller than corrrect size + GetPartitionInfo == GeometryEx : larger than corrrect size + + Floppy \\.\a: (FAT): + Geometry : correct size. + CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL + correction works OK for FAT. + correction works OK for non-FAT, if kClusterSize = 512. + */ + + if (GetPartitionInfo(&partInfo)) + { + Size = (UInt64)partInfo.PartitionLength.QuadPart; + SizeDefined = true; + needCorrectSize = false; + if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0) + { + FChar path[4] = { s[4], ':', '\\', 0 }; + UInt64 clusterSize, totalSize, freeSize; + if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize)) + Size = totalSize; + else + needCorrectSize = true; + } + } + + if (!SizeDefined) + { + my_DISK_GEOMETRY_EX geomEx; + SizeDefined = GetGeometryEx(&geomEx); + if (SizeDefined) + Size = (UInt64)geomEx.DiskSize.QuadPart; + else + { + DISK_GEOMETRY geom; + SizeDefined = GetGeometry(&geom); + if (!SizeDefined) + SizeDefined = GetCdRomGeometry(&geom); + if (SizeDefined) + Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; + } + } + + if (needCorrectSize && SizeDefined && Size != 0) + { + CorrectDeviceSize(); + SeekToBegin(); + } + + // SeekToBegin(); + #endif +} + +// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 && + +#define MY_DEVICE_EXTRA_CODE \ + IsDeviceFile = IsDevicePath(fileName); \ + CalcDeviceSize(fileName); +#else +#define MY_DEVICE_EXTRA_CODE +#endif + +bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) +{ + DWORD desiredAccess = GENERIC_READ; + + #ifdef _WIN32 + if (PreserveATime) + desiredAccess |= FILE_WRITE_ATTRIBUTES; + #endif + + bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes); + + #ifdef _WIN32 + if (res && PreserveATime) + { + FILETIME ft; + ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF; + ::SetFileTime(_handle, NULL, &ft, NULL); + } + #endif + + MY_DEVICE_EXTRA_CODE + return res; +} + +bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite) +{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } + +bool CInFile::Open(CFSTR fileName) + { return OpenShared(fileName, false); } + +// ReadFile and WriteFile functions in Windows have BUG: +// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) +// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES +// (Insufficient system resources exist to complete the requested service). + +// Probably in some version of Windows there are problems with other sizes: +// for 32 MB (maybe also for 16 MB). +// And message can be "Network connection was lost" + +static const UInt32 kChunkSizeMax = 1 << 22; + +bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw() +{ + DWORD processedLoc = 0; + const bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); + processedSize = (UInt32)processedLoc; + return res; +} + +bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw() +{ +#if 0 + const UInt32 chunkSizeMax = (0 || IsStdStream) ? (1 << 20) : kChunkSizeMax; + if (size > chunkSizeMax) + size = chunkSizeMax; +#else + if (size > kChunkSizeMax) + size = kChunkSizeMax; +#endif + return Read1(data, size, processedSize); +} + +bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw() +{ + processedSize = 0; + do + { + UInt32 processedLoc = 0; + const bool res = ReadPart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (void *)((Byte *)data + processedLoc); + size -= processedLoc; + } + while (size); + return true; +} + +bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw() +{ + processedSize = 0; + do + { + UInt32 processedLoc = 0; + const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size); + const bool res = Read1(data, sizeLoc, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (void *)((Byte *)data + processedLoc); + size -= processedLoc; + } + while (size); + return true; +} + +// ---------- COutFile --------- + +bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) + { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } + +bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition) + { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } + +bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) + { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); } + +bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() + { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } + +bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); } + +bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw() +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + DWORD processedLoc = 0; + bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); + processedSize = (UInt32)processedLoc; + return res; +} + +bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw() +{ + processedSize = 0; + do + { + UInt32 processedLoc = 0; + const bool res = WritePart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (const void *)((const Byte *)data + processedLoc); + size -= processedLoc; + } + while (size); + return true; +} + +bool COutFile::WriteFull(const void *data, size_t size) throw() +{ + do + { + UInt32 processedLoc = 0; + const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size); + if (!WritePart(data, sizeCur, processedLoc)) + return false; + if (processedLoc == 0) + return (size == 0); + data = (const void *)((const Byte *)data + processedLoc); + size -= processedLoc; + } + while (size); + return true; +} + +bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); } + +bool COutFile::SetLength(UInt64 length) throw() +{ + UInt64 newPosition; + if (!Seek(length, newPosition)) + return false; + if (newPosition != length) + return false; + return SetEndOfFile(); +} + +bool COutFile::SetLength_KeepPosition(UInt64 length) throw() +{ + UInt64 currentPos = 0; + if (!GetPosition(currentPos)) + return false; + DWORD lastError = 0; + const bool result = SetLength(length); + if (!result) + lastError = GetLastError(); + UInt64 currentPos2; + const bool result2 = Seek(currentPos, currentPos2); + if (lastError != 0) + SetLastError(lastError); + return (result && result2); +} + +}}} + +#else // _WIN32 + + +// POSIX + +#include +#include + +namespace NWindows { +namespace NFile { + +namespace NDir { +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); +} + +namespace NIO { + +bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode) +{ + #ifdef O_BINARY + flags |= O_BINARY; + #endif + + Close(); + _handle = ::open(name, flags, mode); + return _handle != -1; + + /* + if (_handle == -1) + return false; + if (IsString1PrefixedByString2(name, "/dev/")) + { + // /dev/sda + // IsDeviceFile = true; // for debug + // SizeDefined = false; + // SizeDefined = (GetDeviceSize_InBytes(Size) == 0); + } + return true; + */ +} + +bool CFileBase::Close() +{ + if (_handle == -1) + return true; + if (close(_handle) != 0) + return false; + _handle = -1; + /* + IsDeviceFile = false; + SizeDefined = false; + */ + return true; +} + +bool CFileBase::GetLength(UInt64 &length) const +{ + length = 0; + // length = (UInt64)(Int64)-1; // for debug + const off_t curPos = seekToCur(); + if (curPos == -1) + return false; + const off_t lengthTemp = seek(0, SEEK_END); + seek(curPos, SEEK_SET); + length = (UInt64)lengthTemp; + + /* + // 22.00: + if (lengthTemp == 1) + if (IsDeviceFile && SizeDefined) + { + length = Size; + return true; + } + */ + + return (lengthTemp != -1); +} + +off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const +{ + /* + if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END) + { + printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove); + distanceToMove += Size; + moveMethod = SEEK_SET; + } + */ + + // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove); + // off_t res = ::lseek(_handle, distanceToMove, moveMethod); + // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove); + return ::lseek(_handle, distanceToMove, moveMethod); + // return res; +} + +off_t CFileBase::seekToBegin() const throw() +{ + return seek(0, SEEK_SET); +} + +off_t CFileBase::seekToCur() const throw() +{ + return seek(0, SEEK_CUR); +} + +/* +bool CFileBase::SeekToBegin() const throw() +{ + return (::seek(0, SEEK_SET) != -1); +} +*/ + + +///////////////////////// +// CInFile + +bool CInFile::Open(const char *name) +{ + return CFileBase::OpenBinary(name, O_RDONLY); +} + +bool CInFile::OpenShared(const char *name, bool) +{ + return Open(name); +} + + +/* +int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks) +{ + // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition + // #include + return ioctl(_handle, BLKGETSIZE64, numBlocks); + // in block size +} + +int CFileBase::GetDeviceSize_InBytes(UInt64 &size) +{ + size = 0; + unsigned long long numBlocks; + int res = my_ioctl_BLKGETSIZE64(&numBlocks); + if (res == 0) + size = numBlocks; // another blockSize s possible? + printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size); + return res; +} +*/ + +/* +On Linux (32-bit and 64-bit): +read(), write() (and similar system calls) will transfer at most +0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred. +*/ + +static const size_t kChunkSizeMax = ((size_t)1 << 22); + +ssize_t CInFile::read_part(void *data, size_t size) throw() +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + return ::read(_handle, data, size); +} + +bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw() +{ + processed = 0; + do + { + const ssize_t res = read_part(data, size); + if (res < 0) + return false; + if (res == 0) + break; + data = (void *)((Byte *)data + (size_t)res); + processed += (size_t)res; + size -= (size_t)res; + } + while (size); + return true; +} + + +///////////////////////// +// COutFile + +bool COutFile::OpenBinary_forWrite_oflag(const char *name, int oflag) +{ + Path = name; // change it : set it only if open is success. + return OpenBinary(name, oflag, mode_for_Create); +} + + +/* + windows exist non-exist posix + CREATE_NEW Fail Create O_CREAT | O_EXCL + CREATE_ALWAYS Trunc Create O_CREAT | O_TRUNC + OPEN_ALWAYS Open Create O_CREAT + OPEN_EXISTING Open Fail 0 + TRUNCATE_EXISTING Trunc Fail O_TRUNC ??? + + // O_CREAT = If the file exists, this flag has no effect except as noted under O_EXCL below. + // If O_CREAT and O_EXCL are set, open() shall fail if the file exists. + // O_TRUNC : If the file exists and the file is successfully opened, its length shall be truncated to 0. +*/ +bool COutFile::Open_EXISTING(const char *name) + { return OpenBinary_forWrite_oflag(name, O_WRONLY); } +bool COutFile::Create_ALWAYS(const char *name) + { return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_TRUNC); } +bool COutFile::Create_NEW(const char *name) + { return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_EXCL); } +bool COutFile::Create_ALWAYS_or_Open_ALWAYS(const char *name, bool createAlways) +{ + return OpenBinary_forWrite_oflag(name, + createAlways ? + O_WRONLY | O_CREAT | O_TRUNC : + O_WRONLY | O_CREAT); +} +/* +bool COutFile::Create_ALWAYS_or_NEW(const char *name, bool createAlways) +{ + return OpenBinary_forWrite_oflag(name, + createAlways ? + O_WRONLY | O_CREAT | O_TRUNC : + O_WRONLY | O_CREAT | O_EXCL); +} +bool COutFile::Open_Disposition(const char *name, DWORD creationDisposition) +{ + int flag; + switch (creationDisposition) + { + case CREATE_NEW: flag = O_WRONLY | O_CREAT | O_EXCL; break; + case CREATE_ALWAYS: flag = O_WRONLY | O_CREAT | O_TRUNC; break; + case OPEN_ALWAYS: flag = O_WRONLY | O_CREAT; break; + case OPEN_EXISTING: flag = O_WRONLY; break; + case TRUNCATE_EXISTING: flag = O_WRONLY | O_TRUNC; break; + default: + SetLastError(EINVAL); + return false; + } + return OpenBinary_forWrite_oflag(name, flag); +} +*/ + +ssize_t COutFile::write_part(const void *data, size_t size) throw() +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + return ::write(_handle, data, size); +} + +ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw() +{ + processed = 0; + do + { + const ssize_t res = write_part(data, size); + if (res < 0) + return res; + if (res == 0) + break; + data = (const void *)((const Byte *)data + (size_t)res); + processed += (size_t)res; + size -= (size_t)res; + } + while (size); + return (ssize_t)processed; +} + +bool COutFile::SetLength(UInt64 length) throw() +{ + const off_t len2 = (off_t)length; + if ((Int64)length != len2) + { + SetLastError(EFBIG); + return false; + } + // The value of the seek pointer shall not be modified by a call to ftruncate(). + const int iret = ftruncate(_handle, len2); + return (iret == 0); +} + +bool COutFile::Close() +{ + const bool res = CFileBase::Close(); + if (!res) + return res; + if (CTime_defined || ATime_defined || MTime_defined) + { + /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, + CTime_defined ? &CTime : NULL, + ATime_defined ? &ATime : NULL, + MTime_defined ? &MTime : NULL); + } + return res; +} + +bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw() +{ + // On some OS (cygwin, MacOSX ...), you must close the file before updating times + // return true; + + if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false; + if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false; + if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; + return true; + + /* + struct timespec times[2]; + UNUSED_VAR(cTime) + if (!aTime && !mTime) + return true; + bool needChange; + needChange = FiTime_To_timespec(aTime, times[0]); + needChange |= FiTime_To_timespec(mTime, times[1]); + if (!needChange) + return true; + return futimens(_handle, times) == 0; + */ +} + +bool COutFile::SetMTime(const CFiTime *mTime) throw() +{ + if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; + return true; +} + +}}} + + +#endif diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index af2b325f2..6ba40eb68 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h @@ -1,448 +1,448 @@ -// Windows/FileIO.h - -#ifndef ZIP7_INC_WINDOWS_FILE_IO_H -#define ZIP7_INC_WINDOWS_FILE_IO_H - -#include "../Common/MyWindows.h" - -#define Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) -#define Z7_WIN_IO_REPARSE_TAG_SYMLINK (0xA000000CL) -#define Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) - -#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 - -// what the meaning of that FLAG or field (2)? -#define Z7_WIN_LX_SYMLINK_FLAG 2 - -#ifdef _WIN32 - -#if defined(_WIN32) && !defined(UNDER_CE) -#include -#endif - -#else - -#include -#include - -#endif - -#include "../Common/MyString.h" -#include "../Common/MyBuffer.h" - -#include "../Windows/TimeUtils.h" - -#include "Defs.h" - -HRESULT GetLastError_noZero_HRESULT(); - -#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER -#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER -#define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER - -namespace NWindows { -namespace NFile { - -#if defined(_WIN32) && !defined(UNDER_CE) -bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); -#endif - -struct CReparseShortInfo -{ - unsigned Offset; - unsigned Size; - - bool Parse(const Byte *p, size_t size); -}; - -struct CReparseAttr -{ - UInt32 Tag; - UInt32 Flags; - UString SubsName; - UString PrintName; - - AString WslName; - - bool HeaderError; - bool TagIsUnknown; - bool MinorError; - DWORD ErrorCode; - - CReparseAttr(): Tag(0), Flags(0) {} - - // Parse() - // returns (true) and (ErrorCode = 0), if (it'a correct known link) - // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag - bool Parse(const Byte *p, size_t size); - - bool IsMountPoint() const { return Tag == Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction - bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } - bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } - - bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } - - bool IsRelative_WSL() const - { - if (WslName.IsEmpty()) - return true; - char c = WslName[0]; - return !IS_PATH_SEPAR(c); - } - - // bool IsVolume() const; - - bool IsOkNamePair() const; - UString GetPath() const; -}; - -#ifdef _WIN32 -#define CFiInfo BY_HANDLE_FILE_INFORMATION -#define ST_MTIME(st) (st).ftLastWriteTime -#else -#define CFiInfo stat -#endif - -#ifdef _WIN32 - -namespace NIO { - -bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); -bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); -bool DeleteReparseData(CFSTR path); - -class CFileBase MY_UNCOPYABLE -{ -protected: - HANDLE _handle; - - bool Create(CFSTR path, DWORD desiredAccess, - DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); - -public: - - bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize, - LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const - { - return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize, - outBuffer, outSize, bytesReturned, overlapped)); - } - - bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const - { - return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned); - } - - bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const - { - DWORD bytesReturned; - return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned); - } - -public: - bool PreserveATime; -#if 0 - bool IsStdStream; - bool IsStdPipeStream; -#endif -#ifdef Z7_DEVICE_FILE - bool IsDeviceFile; - bool SizeDefined; - UInt64 Size; // it can be larger than real available size -#endif - - CFileBase(): - _handle(INVALID_HANDLE_VALUE), - PreserveATime(false) -#if 0 - , IsStdStream(false), - , IsStdPipeStream(false) -#endif - {} - ~CFileBase() { Close(); } - - HANDLE GetHandle() const { return _handle; } - - // void Detach() { _handle = INVALID_HANDLE_VALUE; } - - bool Close() throw(); - - bool GetPosition(UInt64 &position) const throw(); - bool GetLength(UInt64 &length) const throw(); - - bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw(); - bool Seek(UInt64 position, UInt64 &newPosition) const throw(); - bool SeekToBegin() const throw(); - bool SeekToEnd(UInt64 &newPosition) const throw(); - - bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const - { return BOOLToBool(GetFileInformationByHandle(_handle, info)); } - - static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) - { - // probably it can work for complex paths: unsupported by another things - NIO::CFileBase file; - if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) - return false; - return file.GetFileInformation(info); - } -}; - -#ifndef UNDER_CE -#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM -#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) -// #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) - -// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP -#define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) - -struct my_DISK_GEOMETRY_EX -{ - DISK_GEOMETRY Geometry; - LARGE_INTEGER DiskSize; - BYTE Data[1]; -}; -#endif - -class CInFile: public CFileBase -{ - #ifdef Z7_DEVICE_FILE - - #ifndef UNDER_CE - - bool GetGeometry(DISK_GEOMETRY *res) const - { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } - - bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const - { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); } - - bool GetCdRomGeometry(DISK_GEOMETRY *res) const - { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } - - bool GetPartitionInfo(PARTITION_INFORMATION *res) - { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); } - - #endif - - void CorrectDeviceSize(); - void CalcDeviceSize(CFSTR name); - - #endif - -public: - bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); - bool OpenShared(CFSTR fileName, bool shareForWrite); - bool Open(CFSTR fileName); - -#if 0 - bool AttachStdIn() - { - IsDeviceFile = false; - const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); - if (h == INVALID_HANDLE_VALUE || !h) - return false; - IsStdStream = true; - IsStdPipeStream = true; - _handle = h; - return true; - } -#endif - - #ifndef UNDER_CE - - bool Open_for_ReadAttributes(CFSTR fileName) - { - return Create(fileName, FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS); - // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. - } - - bool Open_for_FileRenameInformation(CFSTR fileName) - { - return Create(fileName, DELETE | SYNCHRONIZE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); - // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. - } - - bool OpenReparse(CFSTR fileName) - { - // 17.02 fix: to support Windows XP compatibility junctions: - // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ - return - Create(fileName, 0, - // Open(fileName, - FILE_SHARE_READ, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); - } - - #endif - - bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); - bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); - bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); - bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); -}; - -class COutFile: public CFileBase -{ - bool Open_Disposition(CFSTR fileName, DWORD creationDisposition); -public: - bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); - bool Open_EXISTING(CFSTR fileName) - { return Open_Disposition(fileName, OPEN_EXISTING); } - bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways) - { return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : OPEN_ALWAYS); } - bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways) - { return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : CREATE_NEW); } - bool Create_ALWAYS(CFSTR fileName) - { return Open_Disposition(fileName, CREATE_ALWAYS); } - bool Create_NEW(CFSTR fileName) - { return Open_Disposition(fileName, CREATE_NEW); } - - bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes); - - bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); - bool SetMTime(const CFiTime *mTime) throw(); - bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); - bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); - bool WriteFull(const void *data, size_t size) throw(); - bool SetEndOfFile() throw(); - bool SetLength(UInt64 length) throw(); - bool SetLength_KeepPosition(UInt64 length) throw(); -}; - -} - - -#else // _WIN32 - -namespace NIO { - -bool GetReparseData(CFSTR path, CByteBuffer &reparseData); -// bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); - -// parameters are in reverse order of symlink() function !!! -bool SetSymLink(CFSTR from, CFSTR to); -bool SetSymLink_UString(CFSTR from, const UString &to); - - -class CFileBase -{ -protected: - int _handle; - - /* - bool IsDeviceFile; - bool SizeDefined; - UInt64 Size; // it can be larger than real available size - */ - - bool OpenBinary(const char *name, int flags, mode_t mode = 0666); -public: - bool PreserveATime; -#if 0 - bool IsStdStream; -#endif - - CFileBase(): _handle(-1), PreserveATime(false) -#if 0 - , IsStdStream(false) -#endif - {} - ~CFileBase() { Close(); } - // void Detach() { _handle = -1; } - bool Close(); - bool GetLength(UInt64 &length) const; - off_t seek(off_t distanceToMove, int moveMethod) const; - off_t seekToBegin() const throw(); - off_t seekToCur() const throw(); - // bool SeekToBegin() throw(); - int my_fstat(struct stat *st) const { return fstat(_handle, st); } - /* - int my_ioctl_BLKGETSIZE64(unsigned long long *val); - int GetDeviceSize_InBytes(UInt64 &size); - void CalcDeviceSize(CFSTR s); - */ -}; - -class CInFile: public CFileBase -{ -public: - bool Open(const char *name); - bool OpenShared(const char *name, bool shareForWrite); -#if 0 - bool AttachStdIn() - { - _handle = GetStdHandle(STD_INPUT_HANDLE); - if (_handle == INVALID_HANDLE_VALUE || !_handle) - return false; - IsStdStream = true; - } -#endif - ssize_t read_part(void *data, size_t size) throw(); - // ssize_t read_full(void *data, size_t size, size_t &processed); - bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); -}; - -class COutFile: public CFileBase -{ - bool CTime_defined; - bool ATime_defined; - bool MTime_defined; - CFiTime CTime; - CFiTime ATime; - CFiTime MTime; - - AString Path; - ssize_t write_part(const void *data, size_t size) throw(); - bool OpenBinary_forWrite_oflag(const char *name, int oflag); -public: - mode_t mode_for_Create; - - COutFile(): - CTime_defined(false), - ATime_defined(false), - MTime_defined(false), - mode_for_Create(0666) - {} - - bool Close(); - - bool Open_EXISTING(CFSTR fileName); - bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways); - bool Create_ALWAYS(CFSTR fileName); - bool Create_NEW(CFSTR fileName); - // bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways); - // bool Open_Disposition(const char *name, DWORD creationDisposition); - - ssize_t write_full(const void *data, size_t size, size_t &processed) throw(); - - bool WriteFull(const void *data, size_t size) throw() - { - size_t processed; - ssize_t res = write_full(data, size, processed); - if (res == -1) - return false; - return processed == size; - } - - bool SetLength(UInt64 length) throw(); - bool SetLength_KeepPosition(UInt64 length) throw() - { - return SetLength(length); - } - bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); - bool SetMTime(const CFiTime *mTime) throw(); -}; - -} - -#endif // _WIN32 - -}} - - -#endif +// Windows/FileIO.h + +#ifndef ZIP7_INC_WINDOWS_FILE_IO_H +#define ZIP7_INC_WINDOWS_FILE_IO_H + +#include "../Common/MyWindows.h" + +#define Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#define Z7_WIN_IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#define Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) + +#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 + +// what the meaning of that FLAG or field (2)? +#define Z7_WIN_LX_SYMLINK_FLAG 2 + +#ifdef _WIN32 + +#if defined(_WIN32) && !defined(UNDER_CE) +#include +#endif + +#else + +#include +#include + +#endif + +#include "../Common/MyString.h" +#include "../Common/MyBuffer.h" + +#include "../Windows/TimeUtils.h" + +#include "Defs.h" + +HRESULT GetLastError_noZero_HRESULT(); + +#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER +#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER +#define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER + +namespace NWindows { +namespace NFile { + +#if defined(_WIN32) && !defined(UNDER_CE) +bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); +#endif + +struct CReparseShortInfo +{ + unsigned Offset; + unsigned Size; + + bool Parse(const Byte *p, size_t size); +}; + +struct CReparseAttr +{ + UInt32 Tag; + UInt32 Flags; + UString SubsName; + UString PrintName; + + AString WslName; + + bool HeaderError; + bool TagIsUnknown; + bool MinorError; + DWORD ErrorCode; + + CReparseAttr(): Tag(0), Flags(0) {} + + // Parse() + // returns (true) and (ErrorCode = 0), if (it'a correct known link) + // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag + bool Parse(const Byte *p, size_t size); + + bool IsMountPoint() const { return Tag == Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction + bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } + bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } + + bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } + + bool IsRelative_WSL() const + { + if (WslName.IsEmpty()) + return true; + char c = WslName[0]; + return !IS_PATH_SEPAR(c); + } + + // bool IsVolume() const; + + bool IsOkNamePair() const; + UString GetPath() const; +}; + +#ifdef _WIN32 +#define CFiInfo BY_HANDLE_FILE_INFORMATION +#define ST_MTIME(st) (st).ftLastWriteTime +#else +#define CFiInfo stat +#endif + +#ifdef _WIN32 + +namespace NIO { + +bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); +bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); +bool DeleteReparseData(CFSTR path); + +class CFileBase MY_UNCOPYABLE +{ +protected: + HANDLE _handle; + + bool Create(CFSTR path, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + +public: + + bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize, + LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const + { + return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize, + outBuffer, outSize, bytesReturned, overlapped)); + } + + bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const + { + return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned); + } + + bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const + { + DWORD bytesReturned; + return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned); + } + +public: + bool PreserveATime; +#if 0 + bool IsStdStream; + bool IsStdPipeStream; +#endif +#ifdef Z7_DEVICE_FILE + bool IsDeviceFile; + bool SizeDefined; + UInt64 Size; // it can be larger than real available size +#endif + + CFileBase(): + _handle(INVALID_HANDLE_VALUE), + PreserveATime(false) +#if 0 + , IsStdStream(false), + , IsStdPipeStream(false) +#endif + {} + ~CFileBase() { Close(); } + + HANDLE GetHandle() const { return _handle; } + + // void Detach() { _handle = INVALID_HANDLE_VALUE; } + + bool Close() throw(); + + bool GetPosition(UInt64 &position) const throw(); + bool GetLength(UInt64 &length) const throw(); + + bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw(); + bool Seek(UInt64 position, UInt64 &newPosition) const throw(); + bool SeekToBegin() const throw(); + bool SeekToEnd(UInt64 &newPosition) const throw(); + + bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const + { return BOOLToBool(GetFileInformationByHandle(_handle, info)); } + + static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) + { + // probably it can work for complex paths: unsupported by another things + NIO::CFileBase file; + if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) + return false; + return file.GetFileInformation(info); + } +}; + +#ifndef UNDER_CE +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) +// #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) + +// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP +#define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) + +struct my_DISK_GEOMETRY_EX +{ + DISK_GEOMETRY Geometry; + LARGE_INTEGER DiskSize; + BYTE Data[1]; +}; +#endif + +class CInFile: public CFileBase +{ + #ifdef Z7_DEVICE_FILE + + #ifndef UNDER_CE + + bool GetGeometry(DISK_GEOMETRY *res) const + { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } + + bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const + { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); } + + bool GetCdRomGeometry(DISK_GEOMETRY *res) const + { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } + + bool GetPartitionInfo(PARTITION_INFORMATION *res) + { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); } + + #endif + + void CorrectDeviceSize(); + void CalcDeviceSize(CFSTR name); + + #endif + +public: + bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + bool OpenShared(CFSTR fileName, bool shareForWrite); + bool Open(CFSTR fileName); + +#if 0 + bool AttachStdIn() + { + IsDeviceFile = false; + const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + if (h == INVALID_HANDLE_VALUE || !h) + return false; + IsStdStream = true; + IsStdPipeStream = true; + _handle = h; + return true; + } +#endif + + #ifndef UNDER_CE + + bool Open_for_ReadAttributes(CFSTR fileName) + { + return Create(fileName, FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); + // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. + } + + bool Open_for_FileRenameInformation(CFSTR fileName) + { + return Create(fileName, DELETE | SYNCHRONIZE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); + // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. + } + + bool OpenReparse(CFSTR fileName) + { + // 17.02 fix: to support Windows XP compatibility junctions: + // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ + return + Create(fileName, 0, + // Open(fileName, + FILE_SHARE_READ, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); + } + + #endif + + bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); + bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); + bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); + bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); +}; + +class COutFile: public CFileBase +{ + bool Open_Disposition(CFSTR fileName, DWORD creationDisposition); +public: + bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + bool Open_EXISTING(CFSTR fileName) + { return Open_Disposition(fileName, OPEN_EXISTING); } + bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways) + { return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : OPEN_ALWAYS); } + bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways) + { return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : CREATE_NEW); } + bool Create_ALWAYS(CFSTR fileName) + { return Open_Disposition(fileName, CREATE_ALWAYS); } + bool Create_NEW(CFSTR fileName) + { return Open_Disposition(fileName, CREATE_NEW); } + + bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes); + + bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); + bool SetMTime(const CFiTime *mTime) throw(); + bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); + bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); + bool WriteFull(const void *data, size_t size) throw(); + bool SetEndOfFile() throw(); + bool SetLength(UInt64 length) throw(); + bool SetLength_KeepPosition(UInt64 length) throw(); +}; + +} + + +#else // _WIN32 + +namespace NIO { + +bool GetReparseData(CFSTR path, CByteBuffer &reparseData); +// bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); + +// parameters are in reverse order of symlink() function !!! +bool SetSymLink(CFSTR from, CFSTR to); +bool SetSymLink_UString(CFSTR from, const UString &to); + + +class CFileBase +{ +protected: + int _handle; + + /* + bool IsDeviceFile; + bool SizeDefined; + UInt64 Size; // it can be larger than real available size + */ + + bool OpenBinary(const char *name, int flags, mode_t mode = 0666); +public: + bool PreserveATime; +#if 0 + bool IsStdStream; +#endif + + CFileBase(): _handle(-1), PreserveATime(false) +#if 0 + , IsStdStream(false) +#endif + {} + ~CFileBase() { Close(); } + // void Detach() { _handle = -1; } + bool Close(); + bool GetLength(UInt64 &length) const; + off_t seek(off_t distanceToMove, int moveMethod) const; + off_t seekToBegin() const throw(); + off_t seekToCur() const throw(); + // bool SeekToBegin() throw(); + int my_fstat(struct stat *st) const { return fstat(_handle, st); } + /* + int my_ioctl_BLKGETSIZE64(unsigned long long *val); + int GetDeviceSize_InBytes(UInt64 &size); + void CalcDeviceSize(CFSTR s); + */ +}; + +class CInFile: public CFileBase +{ +public: + bool Open(const char *name); + bool OpenShared(const char *name, bool shareForWrite); +#if 0 + bool AttachStdIn() + { + _handle = GetStdHandle(STD_INPUT_HANDLE); + if (_handle == INVALID_HANDLE_VALUE || !_handle) + return false; + IsStdStream = true; + } +#endif + ssize_t read_part(void *data, size_t size) throw(); + // ssize_t read_full(void *data, size_t size, size_t &processed); + bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); +}; + +class COutFile: public CFileBase +{ + bool CTime_defined; + bool ATime_defined; + bool MTime_defined; + CFiTime CTime; + CFiTime ATime; + CFiTime MTime; + + AString Path; + ssize_t write_part(const void *data, size_t size) throw(); + bool OpenBinary_forWrite_oflag(const char *name, int oflag); +public: + mode_t mode_for_Create; + + COutFile(): + CTime_defined(false), + ATime_defined(false), + MTime_defined(false), + mode_for_Create(0666) + {} + + bool Close(); + + bool Open_EXISTING(CFSTR fileName); + bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways); + bool Create_ALWAYS(CFSTR fileName); + bool Create_NEW(CFSTR fileName); + // bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways); + // bool Open_Disposition(const char *name, DWORD creationDisposition); + + ssize_t write_full(const void *data, size_t size, size_t &processed) throw(); + + bool WriteFull(const void *data, size_t size) throw() + { + size_t processed; + ssize_t res = write_full(data, size, processed); + if (res == -1) + return false; + return processed == size; + } + + bool SetLength(UInt64 length) throw(); + bool SetLength_KeepPosition(UInt64 length) throw() + { + return SetLength(length); + } + bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); + bool SetMTime(const CFiTime *mTime) throw(); +}; + +} + +#endif // _WIN32 + +}} + + +#endif diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp index 78961d5fa..bb380eced 100644 --- a/CPP/Windows/FileLink.cpp +++ b/CPP/Windows/FileLink.cpp @@ -1,621 +1,621 @@ -// Windows/FileLink.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#ifndef _WIN32 -#include -#endif - -#ifdef Z7_DEVICE_FILE -#include "../../C/Alloc.h" -#endif - -#include "../Common/UTFConvert.h" -#include "../Common/StringConvert.h" - -#include "FileDir.h" -#include "FileFind.h" -#include "FileIO.h" -#include "FileName.h" - -#ifdef Z7_OLD_WIN_SDK -#ifndef ERROR_INVALID_REPARSE_DATA -#define ERROR_INVALID_REPARSE_DATA 4392L -#endif -#ifndef ERROR_REPARSE_TAG_INVALID -#define ERROR_REPARSE_TAG_INVALID 4393L -#endif -#endif - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NFile { - -using namespace NName; - -/* - Reparse Points (Junctions and Symbolic Links): - struct - { - UInt32 Tag; - UInt16 Size; // not including starting 8 bytes - UInt16 Reserved; // = 0 - - UInt16 SubstituteOffset; // offset in bytes from start of namesChars - UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL - UInt16 PrintOffset; // offset in bytes from start of namesChars - UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL - - [UInt32] Flags; // for Symbolic Links only. - - UInt16 namesChars[] - } - - MOUNT_POINT (Junction point): - 1) there is NUL wchar after path - 2) Default Order in table: - Substitute Path - Print Path - 3) pathnames can not contain dot directory names - - SYMLINK: - 1) there is no NUL wchar after path - 2) Default Order in table: - Print Path - Substitute Path -*/ - -/* -Win10 WSL2: -admin rights + sudo: it creates normal windows symbolic link. -in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point. -*/ - -/* -static const UInt32 kReparseFlags_Alias = (1 << 29); -static const UInt32 kReparseFlags_HighLatency = (1 << 30); -static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); - -#define Z7_WIN_IO_REPARSE_TAG_HSM (0xC0000004L) -#define Z7_WIN_IO_REPARSE_TAG_HSM2 (0x80000006L) -#define Z7_WIN_IO_REPARSE_TAG_SIS (0x80000007L) -#define Z7_WIN_IO_REPARSE_TAG_WIM (0x80000008L) -#define Z7_WIN_IO_REPARSE_TAG_CSV (0x80000009L) -#define Z7_WIN_IO_REPARSE_TAG_DFS (0x8000000AL) -#define Z7_WIN_IO_REPARSE_TAG_DFSR (0x80000012L) -*/ - -#define Get16(p) GetUi16(p) -#define Get32(p) GetUi32(p) - -static const wchar_t * const k_LinkPrefix = L"\\??\\"; -static const unsigned k_LinkPrefix_Size = 4; - -static bool IsLinkPrefix(const wchar_t *s) -{ - return IsString1PrefixedByString2(s, k_LinkPrefix); -} - -/* -static const wchar_t * const k_VolumePrefix = L"Volume{"; -static const bool IsVolumeName(const wchar_t *s) -{ - return IsString1PrefixedByString2(s, k_VolumePrefix); -} -*/ - -#if defined(_WIN32) && !defined(UNDER_CE) - -#define Set16(p, v) SetUi16(p, v) -#define Set32(p, v) SetUi32(p, v) - -static void WriteString(Byte *dest, const wchar_t *path) -{ - for (;;) - { - wchar_t c = *path++; - if (c == 0) - return; - Set16(dest, (UInt16)c) - dest += 2; - } -} - -bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) -{ - bool isAbs = IsAbsolutePath(path); - if (!isAbs && !isSymLink) - return false; - - if (isWSL) - { - // unsupported characters probably use Replacement Character UTF-16 0xFFFD - AString utf; - ConvertUnicodeToUTF8(path, utf); - const size_t size = 4 + utf.Len(); - if (size != (UInt16)size) - return false; - dest.Alloc(8 + size); - Byte *p = dest; - Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) - Set16(p + 4, (UInt16)(size)) - Set16(p + 6, 0) - Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG) - memcpy(p + 12, utf.Ptr(), utf.Len()); - return true; - } - - // usual symbolic LINK (NOT WSL) - - bool needPrintName = true; - - if (IsSuperPath(path)) - { - path += kSuperPathPrefixSize; - if (!IsDrivePath(path)) - needPrintName = false; - } - - const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; - - size_t len2 = (size_t)MyStringLen(path) * 2; - const size_t len1 = len2 + add_Prefix_Len * 2; - if (!needPrintName) - len2 = 0; - - size_t totalNamesSize = (len1 + len2); - - /* some WIM imagex software uses old scheme for symbolic links. - so we can old scheme for byte to byte compatibility */ - - bool newOrderScheme = isSymLink; - // newOrderScheme = false; - - if (!newOrderScheme) - totalNamesSize += 2 * 2; - - const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; - if (size != (UInt16)size) - return false; - dest.Alloc(size); - memset(dest, 0, size); - const UInt32 tag = isSymLink ? - Z7_WIN_IO_REPARSE_TAG_SYMLINK : - Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; - Byte *p = dest; - Set32(p, tag) - Set16(p + 4, (UInt16)(size - 8)) - Set16(p + 6, 0) - p += 8; - - unsigned subOffs = 0; - unsigned printOffs = 0; - if (newOrderScheme) - subOffs = (unsigned)len2; - else - printOffs = (unsigned)len1 + 2; - - Set16(p + 0, (UInt16)subOffs) - Set16(p + 2, (UInt16)len1) - Set16(p + 4, (UInt16)printOffs) - Set16(p + 6, (UInt16)len2) - - p += 8; - if (isSymLink) - { - UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE; - Set32(p, flags) - p += 4; - } - - if (add_Prefix_Len != 0) - WriteString(p + subOffs, k_LinkPrefix); - WriteString(p + subOffs + add_Prefix_Len * 2, path); - if (needPrintName) - WriteString(p + printOffs, path); - return true; -} - -#endif // defined(_WIN32) && !defined(UNDER_CE) - - -static void GetString(const Byte *p, unsigned len, UString &res) -{ - wchar_t *s = res.GetBuf(len); - unsigned i; - for (i = 0; i < len; i++) - { - wchar_t c = Get16(p + i * 2); - if (c == 0) - break; - s[i] = c; - } - s[i] = 0; - res.ReleaseBuf_SetLen(i); -} - -bool CReparseAttr::Parse(const Byte *p, size_t size) -{ - ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; - HeaderError = true; - TagIsUnknown = true; - MinorError = false; - - if (size < 8) - return false; - Tag = Get32(p); - if (Get16(p + 6) != 0) // padding - return false; - unsigned len = Get16(p + 4); - p += 8; - size -= 8; - if (len != size) - // if (len > size) - return false; - /* - if ((type & kReparseFlags_Alias) == 0 || - (type & kReparseFlags_Microsoft) == 0 || - (type & 0xFFFF) != 3) - */ - - - HeaderError = false; - - if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT - && Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK - && Tag != Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) - { - // for unsupported reparse points - ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH - // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID - return false; - } - - TagIsUnknown = false; - - if (Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) - { - if (len < 4) - return false; - Flags = Get32(p); // maybe it's not Flags - if (Flags != Z7_WIN_LX_SYMLINK_FLAG) - return false; - len -= 4; - p += 4; - char *s = WslName.GetBuf(len); - unsigned i; - for (i = 0; i < len; i++) - { - char c = (char)p[i]; - s[i] = c; - if (c == 0) - break; - } - WslName.ReleaseBuf_SetEnd(i); - MinorError = (i != len); - ErrorCode = 0; - return true; - } - - if (len < 8) - return false; - unsigned subOffs = Get16(p); - unsigned subLen = Get16(p + 2); - unsigned printOffs = Get16(p + 4); - unsigned printLen = Get16(p + 6); - len -= 8; - p += 8; - - Flags = 0; - if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK) - { - if (len < 4) - return false; - Flags = Get32(p); - len -= 4; - p += 4; - } - - if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) - return false; - if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) - return false; - GetString(p + subOffs, subLen >> 1, SubsName); - GetString(p + printOffs, printLen >> 1, PrintName); - - ErrorCode = 0; - return true; -} - - -bool CReparseShortInfo::Parse(const Byte *p, size_t size) -{ - const Byte *start = p; - Offset= 0; - Size = 0; - if (size < 8) - return false; - UInt32 Tag = Get32(p); - UInt32 len = Get16(p + 4); - if (len + 8 > size) - return false; - /* - if ((type & kReparseFlags_Alias) == 0 || - (type & kReparseFlags_Microsoft) == 0 || - (type & 0xFFFF) != 3) - */ - if (Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT && - Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK) - // return true; - return false; - - if (Get16(p + 6) != 0) // padding - return false; - - p += 8; - size -= 8; - - if (len != size) // do we need that check? - return false; - - if (len < 8) - return false; - unsigned subOffs = Get16(p); - unsigned subLen = Get16(p + 2); - unsigned printOffs = Get16(p + 4); - unsigned printLen = Get16(p + 6); - len -= 8; - p += 8; - - // UInt32 Flags = 0; - if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK) - { - if (len < 4) - return false; - // Flags = Get32(p); - len -= 4; - p += 4; - } - - if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) - return false; - if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) - return false; - - Offset = (unsigned)(p - start) + subOffs; - Size = subLen; - return true; -} - -bool CReparseAttr::IsOkNamePair() const -{ - if (IsLinkPrefix(SubsName)) - { - if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) - return PrintName.IsEmpty(); - if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) - return true; - } - return wcscmp(SubsName, PrintName) == 0; -} - -/* -bool CReparseAttr::IsVolume() const -{ - if (!IsLinkPrefix(SubsName)) - return false; - return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size)); -} -*/ - -UString CReparseAttr::GetPath() const -{ - if (IsSymLink_WSL()) - { - UString u; - // if (CheckUTF8(attr.WslName) - if (!ConvertUTF8ToUnicode(WslName, u)) - MultiByteToUnicodeString2(u, WslName); - return u; - } - - UString s (SubsName); - if (IsLinkPrefix(s)) - { - s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" - if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) - s.DeleteFrontal(k_LinkPrefix_Size); - } - return s; -} - -#ifdef Z7_DEVICE_FILE - -namespace NSystem -{ -bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); -} -#endif // Z7_DEVICE_FILE - -#if defined(_WIN32) && !defined(UNDER_CE) - -namespace NIO { - -bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo) -{ - reparseData.Free(); - CInFile file; - if (!file.OpenReparse(path)) - return false; - - if (fileInfo) - file.GetFileInformation(fileInfo); - - const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; - CByteArr buf(kBufSize); - DWORD returnedSize; - if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize)) - return false; - reparseData.CopyFrom(buf, returnedSize); - return true; -} - -static bool CreatePrefixDirOfFile(CFSTR path) -{ - FString path2 (path); - int pos = path2.ReverseFind_PathSepar(); - if (pos < 0) - return true; - #ifdef _WIN32 - if (pos == 2 && path2[1] == L':') - return true; // we don't create Disk folder; - #endif - path2.DeleteFrom((unsigned)pos); - return NDir::CreateComplexDir(path2); -} - - -static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size) -{ - COutFile file; - if (!file.Open(path, - FILE_SHARE_WRITE, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) - return false; - - DWORD returnedSize; - return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize); -} - - -// If there is Reparse data already, it still writes new Reparse data -bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) -{ - NFile::NFind::CFileInfo fi; - if (fi.Find(path)) - { - if (fi.IsDir() != isDir) - { - ::SetLastError(ERROR_DIRECTORY); - return false; - } - } - else - { - if (isDir) - { - if (!NDir::CreateComplexDir(path)) - return false; - } - else - { - CreatePrefixDirOfFile(path); - COutFile file; - if (!file.Create_NEW(path)) - return false; - } - } - - return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size); -} - - -bool DeleteReparseData(CFSTR path) -{ - CByteBuffer reparseData; - if (!GetReparseData(path, reparseData, NULL)) - return false; - /* MSDN: The tag specified in the ReparseTag member of this structure - must match the tag of the reparse point to be deleted, - and the ReparseDataLength member must be zero */ - #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8 - if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE) - { - SetLastError(ERROR_INVALID_REPARSE_DATA); - return false; - } - BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; - memset(buf, 0, sizeof(buf)); - memcpy(buf, reparseData, 4); // tag - return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); -} - -} - -#endif // defined(_WIN32) && !defined(UNDER_CE) - - -#ifndef _WIN32 - -namespace NIO { - -bool GetReparseData(CFSTR path, CByteBuffer &reparseData) -{ - reparseData.Free(); - - #define MAX_PATHNAME_LEN 1024 - char buf[MAX_PATHNAME_LEN + 2]; - const size_t request = sizeof(buf) - 1; - - // printf("\nreadlink() path = %s \n", path); - const ssize_t size = readlink(path, buf, request); - // there is no tail zero - - if (size < 0) - return false; - if ((size_t)size >= request) - { - SetLastError(EINVAL); // check it: ENAMETOOLONG - return false; - } - - // printf("\nreadlink() res = %s size = %d \n", buf, (int)size); - reparseData.CopyFrom((const Byte *)buf, (size_t)size); - return true; -} - - -/* -// If there is Reparse data already, it still writes new Reparse data -bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) -{ - // AString s; - // s.SetFrom_CalcLen(data, size); - // return (symlink(s, path) == 0); - UNUSED_VAR(path) - UNUSED_VAR(isDir) - UNUSED_VAR(data) - UNUSED_VAR(size) - SetLastError(ENOSYS); - return false; -} -*/ - -bool SetSymLink(CFSTR from, CFSTR to) -{ - // printf("\nsymlink() %s -> %s\n", from, to); - int ir; - // ir = unlink(path); - // if (ir == 0) - ir = symlink(to, from); - return (ir == 0); -} - -bool SetSymLink_UString(CFSTR from, const UString &to) -{ - AString utf; - ConvertUnicodeToUTF8(to, utf); - return SetSymLink(from, utf); -} - -} - -#endif // !_WIN32 - -}} +// Windows/FileLink.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#ifndef _WIN32 +#include +#endif + +#ifdef Z7_DEVICE_FILE +#include "../../C/Alloc.h" +#endif + +#include "../Common/UTFConvert.h" +#include "../Common/StringConvert.h" + +#include "FileDir.h" +#include "FileFind.h" +#include "FileIO.h" +#include "FileName.h" + +#ifdef Z7_OLD_WIN_SDK +#ifndef ERROR_INVALID_REPARSE_DATA +#define ERROR_INVALID_REPARSE_DATA 4392L +#endif +#ifndef ERROR_REPARSE_TAG_INVALID +#define ERROR_REPARSE_TAG_INVALID 4393L +#endif +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NFile { + +using namespace NName; + +/* + Reparse Points (Junctions and Symbolic Links): + struct + { + UInt32 Tag; + UInt16 Size; // not including starting 8 bytes + UInt16 Reserved; // = 0 + + UInt16 SubstituteOffset; // offset in bytes from start of namesChars + UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL + UInt16 PrintOffset; // offset in bytes from start of namesChars + UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL + + [UInt32] Flags; // for Symbolic Links only. + + UInt16 namesChars[] + } + + MOUNT_POINT (Junction point): + 1) there is NUL wchar after path + 2) Default Order in table: + Substitute Path + Print Path + 3) pathnames can not contain dot directory names + + SYMLINK: + 1) there is no NUL wchar after path + 2) Default Order in table: + Print Path + Substitute Path +*/ + +/* +Win10 WSL2: +admin rights + sudo: it creates normal windows symbolic link. +in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point. +*/ + +/* +static const UInt32 kReparseFlags_Alias = (1 << 29); +static const UInt32 kReparseFlags_HighLatency = (1 << 30); +static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); + +#define Z7_WIN_IO_REPARSE_TAG_HSM (0xC0000004L) +#define Z7_WIN_IO_REPARSE_TAG_HSM2 (0x80000006L) +#define Z7_WIN_IO_REPARSE_TAG_SIS (0x80000007L) +#define Z7_WIN_IO_REPARSE_TAG_WIM (0x80000008L) +#define Z7_WIN_IO_REPARSE_TAG_CSV (0x80000009L) +#define Z7_WIN_IO_REPARSE_TAG_DFS (0x8000000AL) +#define Z7_WIN_IO_REPARSE_TAG_DFSR (0x80000012L) +*/ + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +static const wchar_t * const k_LinkPrefix = L"\\??\\"; +static const unsigned k_LinkPrefix_Size = 4; + +static bool IsLinkPrefix(const wchar_t *s) +{ + return IsString1PrefixedByString2(s, k_LinkPrefix); +} + +/* +static const wchar_t * const k_VolumePrefix = L"Volume{"; +static const bool IsVolumeName(const wchar_t *s) +{ + return IsString1PrefixedByString2(s, k_VolumePrefix); +} +*/ + +#if defined(_WIN32) && !defined(UNDER_CE) + +#define Set16(p, v) SetUi16(p, v) +#define Set32(p, v) SetUi32(p, v) + +static void WriteString(Byte *dest, const wchar_t *path) +{ + for (;;) + { + wchar_t c = *path++; + if (c == 0) + return; + Set16(dest, (UInt16)c) + dest += 2; + } +} + +bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) +{ + bool isAbs = IsAbsolutePath(path); + if (!isAbs && !isSymLink) + return false; + + if (isWSL) + { + // unsupported characters probably use Replacement Character UTF-16 0xFFFD + AString utf; + ConvertUnicodeToUTF8(path, utf); + const size_t size = 4 + utf.Len(); + if (size != (UInt16)size) + return false; + dest.Alloc(8 + size); + Byte *p = dest; + Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) + Set16(p + 4, (UInt16)(size)) + Set16(p + 6, 0) + Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG) + memcpy(p + 12, utf.Ptr(), utf.Len()); + return true; + } + + // usual symbolic LINK (NOT WSL) + + bool needPrintName = true; + + if (IsSuperPath(path)) + { + path += kSuperPathPrefixSize; + if (!IsDrivePath(path)) + needPrintName = false; + } + + const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; + + size_t len2 = (size_t)MyStringLen(path) * 2; + const size_t len1 = len2 + add_Prefix_Len * 2; + if (!needPrintName) + len2 = 0; + + size_t totalNamesSize = (len1 + len2); + + /* some WIM imagex software uses old scheme for symbolic links. + so we can old scheme for byte to byte compatibility */ + + bool newOrderScheme = isSymLink; + // newOrderScheme = false; + + if (!newOrderScheme) + totalNamesSize += 2 * 2; + + const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; + if (size != (UInt16)size) + return false; + dest.Alloc(size); + memset(dest, 0, size); + const UInt32 tag = isSymLink ? + Z7_WIN_IO_REPARSE_TAG_SYMLINK : + Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; + Byte *p = dest; + Set32(p, tag) + Set16(p + 4, (UInt16)(size - 8)) + Set16(p + 6, 0) + p += 8; + + unsigned subOffs = 0; + unsigned printOffs = 0; + if (newOrderScheme) + subOffs = (unsigned)len2; + else + printOffs = (unsigned)len1 + 2; + + Set16(p + 0, (UInt16)subOffs) + Set16(p + 2, (UInt16)len1) + Set16(p + 4, (UInt16)printOffs) + Set16(p + 6, (UInt16)len2) + + p += 8; + if (isSymLink) + { + UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE; + Set32(p, flags) + p += 4; + } + + if (add_Prefix_Len != 0) + WriteString(p + subOffs, k_LinkPrefix); + WriteString(p + subOffs + add_Prefix_Len * 2, path); + if (needPrintName) + WriteString(p + printOffs, path); + return true; +} + +#endif // defined(_WIN32) && !defined(UNDER_CE) + + +static void GetString(const Byte *p, unsigned len, UString &res) +{ + wchar_t *s = res.GetBuf(len); + unsigned i; + for (i = 0; i < len; i++) + { + wchar_t c = Get16(p + i * 2); + if (c == 0) + break; + s[i] = c; + } + s[i] = 0; + res.ReleaseBuf_SetLen(i); +} + +bool CReparseAttr::Parse(const Byte *p, size_t size) +{ + ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; + HeaderError = true; + TagIsUnknown = true; + MinorError = false; + + if (size < 8) + return false; + Tag = Get32(p); + if (Get16(p + 6) != 0) // padding + return false; + unsigned len = Get16(p + 4); + p += 8; + size -= 8; + if (len != size) + // if (len > size) + return false; + /* + if ((type & kReparseFlags_Alias) == 0 || + (type & kReparseFlags_Microsoft) == 0 || + (type & 0xFFFF) != 3) + */ + + + HeaderError = false; + + if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT + && Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK + && Tag != Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) + { + // for unsupported reparse points + ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH + // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID + return false; + } + + TagIsUnknown = false; + + if (Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK) + { + if (len < 4) + return false; + Flags = Get32(p); // maybe it's not Flags + if (Flags != Z7_WIN_LX_SYMLINK_FLAG) + return false; + len -= 4; + p += 4; + char *s = WslName.GetBuf(len); + unsigned i; + for (i = 0; i < len; i++) + { + char c = (char)p[i]; + s[i] = c; + if (c == 0) + break; + } + WslName.ReleaseBuf_SetEnd(i); + MinorError = (i != len); + ErrorCode = 0; + return true; + } + + if (len < 8) + return false; + unsigned subOffs = Get16(p); + unsigned subLen = Get16(p + 2); + unsigned printOffs = Get16(p + 4); + unsigned printLen = Get16(p + 6); + len -= 8; + p += 8; + + Flags = 0; + if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK) + { + if (len < 4) + return false; + Flags = Get32(p); + len -= 4; + p += 4; + } + + if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) + return false; + if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) + return false; + GetString(p + subOffs, subLen >> 1, SubsName); + GetString(p + printOffs, printLen >> 1, PrintName); + + ErrorCode = 0; + return true; +} + + +bool CReparseShortInfo::Parse(const Byte *p, size_t size) +{ + const Byte *start = p; + Offset= 0; + Size = 0; + if (size < 8) + return false; + UInt32 Tag = Get32(p); + UInt32 len = Get16(p + 4); + if (len + 8 > size) + return false; + /* + if ((type & kReparseFlags_Alias) == 0 || + (type & kReparseFlags_Microsoft) == 0 || + (type & 0xFFFF) != 3) + */ + if (Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT && + Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK) + // return true; + return false; + + if (Get16(p + 6) != 0) // padding + return false; + + p += 8; + size -= 8; + + if (len != size) // do we need that check? + return false; + + if (len < 8) + return false; + unsigned subOffs = Get16(p); + unsigned subLen = Get16(p + 2); + unsigned printOffs = Get16(p + 4); + unsigned printLen = Get16(p + 6); + len -= 8; + p += 8; + + // UInt32 Flags = 0; + if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK) + { + if (len < 4) + return false; + // Flags = Get32(p); + len -= 4; + p += 4; + } + + if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) + return false; + if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) + return false; + + Offset = (unsigned)(p - start) + subOffs; + Size = subLen; + return true; +} + +bool CReparseAttr::IsOkNamePair() const +{ + if (IsLinkPrefix(SubsName)) + { + if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) + return PrintName.IsEmpty(); + if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) + return true; + } + return wcscmp(SubsName, PrintName) == 0; +} + +/* +bool CReparseAttr::IsVolume() const +{ + if (!IsLinkPrefix(SubsName)) + return false; + return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size)); +} +*/ + +UString CReparseAttr::GetPath() const +{ + if (IsSymLink_WSL()) + { + UString u; + // if (CheckUTF8(attr.WslName) + if (!ConvertUTF8ToUnicode(WslName, u)) + MultiByteToUnicodeString2(u, WslName); + return u; + } + + UString s (SubsName); + if (IsLinkPrefix(s)) + { + s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" + if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) + s.DeleteFrontal(k_LinkPrefix_Size); + } + return s; +} + +#ifdef Z7_DEVICE_FILE + +namespace NSystem +{ +bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); +} +#endif // Z7_DEVICE_FILE + +#if defined(_WIN32) && !defined(UNDER_CE) + +namespace NIO { + +bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo) +{ + reparseData.Free(); + CInFile file; + if (!file.OpenReparse(path)) + return false; + + if (fileInfo) + file.GetFileInformation(fileInfo); + + const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + CByteArr buf(kBufSize); + DWORD returnedSize; + if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize)) + return false; + reparseData.CopyFrom(buf, returnedSize); + return true; +} + +static bool CreatePrefixDirOfFile(CFSTR path) +{ + FString path2 (path); + int pos = path2.ReverseFind_PathSepar(); + if (pos < 0) + return true; + #ifdef _WIN32 + if (pos == 2 && path2[1] == L':') + return true; // we don't create Disk folder; + #endif + path2.DeleteFrom((unsigned)pos); + return NDir::CreateComplexDir(path2); +} + + +static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size) +{ + COutFile file; + if (!file.Open(path, + FILE_SHARE_WRITE, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) + return false; + + DWORD returnedSize; + return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize); +} + + +// If there is Reparse data already, it still writes new Reparse data +bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) +{ + NFile::NFind::CFileInfo fi; + if (fi.Find(path)) + { + if (fi.IsDir() != isDir) + { + ::SetLastError(ERROR_DIRECTORY); + return false; + } + } + else + { + if (isDir) + { + if (!NDir::CreateComplexDir(path)) + return false; + } + else + { + CreatePrefixDirOfFile(path); + COutFile file; + if (!file.Create_NEW(path)) + return false; + } + } + + return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size); +} + + +bool DeleteReparseData(CFSTR path) +{ + CByteBuffer reparseData; + if (!GetReparseData(path, reparseData, NULL)) + return false; + /* MSDN: The tag specified in the ReparseTag member of this structure + must match the tag of the reparse point to be deleted, + and the ReparseDataLength member must be zero */ + #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8 + if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE) + { + SetLastError(ERROR_INVALID_REPARSE_DATA); + return false; + } + BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; + memset(buf, 0, sizeof(buf)); + memcpy(buf, reparseData, 4); // tag + return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); +} + +} + +#endif // defined(_WIN32) && !defined(UNDER_CE) + + +#ifndef _WIN32 + +namespace NIO { + +bool GetReparseData(CFSTR path, CByteBuffer &reparseData) +{ + reparseData.Free(); + + #define MAX_PATHNAME_LEN 1024 + char buf[MAX_PATHNAME_LEN + 2]; + const size_t request = sizeof(buf) - 1; + + // printf("\nreadlink() path = %s \n", path); + const ssize_t size = readlink(path, buf, request); + // there is no tail zero + + if (size < 0) + return false; + if ((size_t)size >= request) + { + SetLastError(EINVAL); // check it: ENAMETOOLONG + return false; + } + + // printf("\nreadlink() res = %s size = %d \n", buf, (int)size); + reparseData.CopyFrom((const Byte *)buf, (size_t)size); + return true; +} + + +/* +// If there is Reparse data already, it still writes new Reparse data +bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) +{ + // AString s; + // s.SetFrom_CalcLen(data, size); + // return (symlink(s, path) == 0); + UNUSED_VAR(path) + UNUSED_VAR(isDir) + UNUSED_VAR(data) + UNUSED_VAR(size) + SetLastError(ENOSYS); + return false; +} +*/ + +bool SetSymLink(CFSTR from, CFSTR to) +{ + // printf("\nsymlink() %s -> %s\n", from, to); + int ir; + // ir = unlink(path); + // if (ir == 0) + ir = symlink(to, from); + return (ir == 0); +} + +bool SetSymLink_UString(CFSTR from, const UString &to) +{ + AString utf; + ConvertUnicodeToUTF8(to, utf); + return SetSymLink(from, utf); +} + +} + +#endif // !_WIN32 + +}} diff --git a/CPP/Windows/FileMapping.cpp b/CPP/Windows/FileMapping.cpp index 01c4a943d..1933f7c8b 100644 --- a/CPP/Windows/FileMapping.cpp +++ b/CPP/Windows/FileMapping.cpp @@ -1,12 +1,12 @@ -// Windows/FileMapping.cpp - -#include "StdAfx.h" - -#include "FileMapping.h" - -namespace NWindows { -namespace NFile { -namespace NMapping { - - -}}} +// Windows/FileMapping.cpp + +#include "StdAfx.h" + +#include "FileMapping.h" + +namespace NWindows { +namespace NFile { +namespace NMapping { + + +}}} diff --git a/CPP/Windows/FileMapping.h b/CPP/Windows/FileMapping.h index 7a2d360bd..caa7ea3ed 100644 --- a/CPP/Windows/FileMapping.h +++ b/CPP/Windows/FileMapping.h @@ -1,66 +1,66 @@ -// Windows/FileMapping.h - -#ifndef ZIP7_INC_WINDOWS_FILE_MAPPING_H -#define ZIP7_INC_WINDOWS_FILE_MAPPING_H - -#include "../Common/MyTypes.h" - -#include "Handle.h" - -namespace NWindows { - -class CFileMapping: public CHandle -{ -public: - WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name) - { - _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name); - return ::GetLastError(); - } - - WRes Open(DWORD - #ifndef UNDER_CE - desiredAccess - #endif - , LPCTSTR name) - { - #ifdef UNDER_CE - WRes res = Create(PAGE_READONLY, 0, name); - if (res == ERROR_ALREADY_EXISTS) - return 0; - Close(); - if (res == 0) - res = ERROR_FILE_NOT_FOUND; - return res; - #else - _handle = ::OpenFileMapping(desiredAccess, FALSE, name); - if (_handle != NULL) - return 0; - return ::GetLastError(); - #endif - } - - LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap) - { - return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap); - } - - #ifndef UNDER_CE - LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress) - { - return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress); - } - #endif -}; - -class CFileUnmapper -{ - const void *_data; -public: - CFileUnmapper(const void *data) : _data(data) {} - ~CFileUnmapper() { ::UnmapViewOfFile(_data); } -}; - -} - -#endif +// Windows/FileMapping.h + +#ifndef ZIP7_INC_WINDOWS_FILE_MAPPING_H +#define ZIP7_INC_WINDOWS_FILE_MAPPING_H + +#include "../Common/MyTypes.h" + +#include "Handle.h" + +namespace NWindows { + +class CFileMapping: public CHandle +{ +public: + WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name) + { + _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name); + return ::GetLastError(); + } + + WRes Open(DWORD + #ifndef UNDER_CE + desiredAccess + #endif + , LPCTSTR name) + { + #ifdef UNDER_CE + WRes res = Create(PAGE_READONLY, 0, name); + if (res == ERROR_ALREADY_EXISTS) + return 0; + Close(); + if (res == 0) + res = ERROR_FILE_NOT_FOUND; + return res; + #else + _handle = ::OpenFileMapping(desiredAccess, FALSE, name); + if (_handle != NULL) + return 0; + return ::GetLastError(); + #endif + } + + LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap) + { + return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap); + } + + #ifndef UNDER_CE + LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress) + { + return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress); + } + #endif +}; + +class CFileUnmapper +{ + const void *_data; +public: + CFileUnmapper(const void *data) : _data(data) {} + ~CFileUnmapper() { ::UnmapViewOfFile(_data); } +}; + +} + +#endif diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp index 11322af81..1f4a6da00 100644 --- a/CPP/Windows/FileName.cpp +++ b/CPP/Windows/FileName.cpp @@ -1,894 +1,896 @@ -// Windows/FileName.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 -#include -#include -#include "../Common/StringConvert.h" -#endif - -#include "FileDir.h" -#include "FileName.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NFile { -namespace NName { - -#define IS_SEPAR(c) IS_PATH_SEPAR(c) - -int FindSepar(const wchar_t *s) throw() -{ - for (const wchar_t *p = s;; p++) - { - const wchar_t c = *p; - if (c == 0) - return -1; - if (IS_SEPAR(c)) - return (int)(p - s); - } -} - -#ifndef USE_UNICODE_FSTRING -int FindSepar(const FChar *s) throw() -{ - for (const FChar *p = s;; p++) - { - const FChar c = *p; - if (c == 0) - return -1; - if (IS_SEPAR(c)) - return (int)(p - s); - } -} -#endif - -#ifndef USE_UNICODE_FSTRING -void NormalizeDirPathPrefix(FString &dirPath) -{ - if (dirPath.IsEmpty()) - return; - if (!IsPathSepar(dirPath.Back())) - dirPath.Add_PathSepar(); -} -#endif - -void NormalizeDirPathPrefix(UString &dirPath) -{ - if (dirPath.IsEmpty()) - return; - if (!IsPathSepar(dirPath.Back())) - dirPath.Add_PathSepar(); -} - -#ifdef _WIN32 - -#ifndef USE_UNICODE_FSTRING -#ifdef Z7_LONG_PATH -static void NormalizeDirSeparators(UString &s) -{ - const unsigned len = s.Len(); - for (unsigned i = 0; i < len; i++) - if (s[i] == '/') - s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR); -} -#endif -#endif - -void NormalizeDirSeparators(FString &s) -{ - const unsigned len = s.Len(); - for (unsigned i = 0; i < len; i++) - if (s[i] == '/') - s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); -} - -#endif - - -#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a'))) - -bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } - -bool IsAltPathPrefix(CFSTR s) throw() -{ - unsigned len = MyStringLen(s); - if (len == 0) - return false; - if (s[len - 1] != ':') - return false; - - #if defined(_WIN32) && !defined(UNDER_CE) - if (IsDevicePath(s)) - return false; - if (IsSuperPath(s)) - { - s += kSuperPathPrefixSize; - len -= kSuperPathPrefixSize; - } - if (len == 2 && IsDrivePath2(s)) - return false; - #endif - - return true; -} - -#if defined(_WIN32) && !defined(UNDER_CE) - -const char * const kSuperPathPrefix = "\\\\?\\"; -#ifdef Z7_LONG_PATH -static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; -#endif - -#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) -#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) -#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) - -#define IS_UNC_WITH_SLASH(s) ( \ - ((s)[0] == 'U' || (s)[0] == 'u') \ - && ((s)[1] == 'N' || (s)[1] == 'n') \ - && ((s)[2] == 'C' || (s)[2] == 'c') \ - && IS_SEPAR((s)[3])) - -bool IsDevicePath(CFSTR s) throw() -{ - #ifdef UNDER_CE - - s = s; - return false; - /* - // actually we don't know the way to open device file in WinCE. - unsigned len = MyStringLen(s); - if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK")) - return false; - if (s[4] != ':') - return false; - // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); - */ - - #else - - if (!IS_DEVICE_PATH(s)) - return false; - unsigned len = MyStringLen(s); - if (len == 6 && s[5] == ':') - return true; - if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) - return false; - for (unsigned i = 17; i < len; i++) - if (s[i] < '0' || s[i] > '9') - return false; - return true; - - #endif -} - -bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } -bool IsNetworkPath(CFSTR s) throw() -{ - if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) - return false; - if (IsSuperUncPath(s)) - return true; - FChar c = s[2]; - return (c != '.' && c != '?'); -} - -unsigned GetNetworkServerPrefixSize(CFSTR s) throw() -{ - if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) - return 0; - unsigned prefixSize = 2; - if (IsSuperUncPath(s)) - prefixSize = kSuperUncPathPrefixSize; - else - { - FChar c = s[2]; - if (c == '.' || c == '?') - return 0; - } - const int pos = FindSepar(s + prefixSize); - if (pos < 0) - return 0; - return prefixSize + (unsigned)(pos + 1); -} - -bool IsNetworkShareRootPath(CFSTR s) throw() -{ - const unsigned prefixSize = GetNetworkServerPrefixSize(s); - if (prefixSize == 0) - return false; - s += prefixSize; - const int pos = FindSepar(s); - if (pos < 0) - return true; - return s[(unsigned)pos + 1] == 0; -} - -static const unsigned kDrivePrefixSize = 3; /* c:\ */ - -bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } -// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } -bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } -bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } -// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } - -bool IsAltStreamPrefixWithColon(const UString &s) throw() -{ - if (s.IsEmpty()) - return false; - if (s.Back() != ':') - return false; - unsigned pos = 0; - if (IsSuperPath(s)) - pos = kSuperPathPrefixSize; - if (s.Len() - pos == 2 && IsDrivePath2(s.Ptr(pos))) - return false; - return true; -} - -bool If_IsSuperPath_RemoveSuperPrefix(UString &s) -{ - if (!IsSuperPath(s)) - return false; - unsigned start = 0; - unsigned count = kSuperPathPrefixSize; - const wchar_t *s2 = s.Ptr(kSuperPathPrefixSize); - if (IS_UNC_WITH_SLASH(s2)) - { - start = 2; - count = kSuperUncPathPrefixSize - 2; - } - s.Delete(start, count); - return true; -} - - -#ifndef USE_UNICODE_FSTRING -bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } -// bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } -bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } -bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } -bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } -#endif // USE_UNICODE_FSTRING - -bool IsDrivePath_SuperAllowed(CFSTR s) throw() -{ - if (IsSuperPath(s)) - s += kSuperPathPrefixSize; - return IsDrivePath(s); -} - -bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() -{ - if (IsSuperPath(s)) - s += kSuperPathPrefixSize; - return IsDrivePath(s) && s[kDrivePrefixSize] == 0; -} - -bool IsAbsolutePath(const wchar_t *s) throw() -{ - return IS_SEPAR(s[0]) || IsDrivePath2(s); -} - -int FindAltStreamColon(CFSTR path) throw() -{ - unsigned i = 0; - if (IsDrivePath2(path)) - i = 2; - int colonPos = -1; - for (;; i++) - { - FChar c = path[i]; - if (c == 0) - return colonPos; - if (c == ':') - { - if (colonPos < 0) - colonPos = (int)i; - continue; - } - if (IS_SEPAR(c)) - colonPos = -1; - } -} - -#ifndef USE_UNICODE_FSTRING - -static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) -{ - // Network path: we look "server\path\" as root prefix - const int pos = FindSepar(s); - if (pos < 0) - return 0; - const int pos2 = FindSepar(s + (unsigned)pos + 1); - if (pos2 < 0) - return 0; - return (unsigned)pos + (unsigned)pos2 + 2; -} - -static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) -{ - if (IsDrivePath(s)) - return kDrivePrefixSize; - if (!IS_SEPAR(s[0])) - return 0; - if (s[1] == 0 || !IS_SEPAR(s[1])) - return 1; - const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); - return (size == 0) ? 0 : 2 + size; -} - -static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) -{ - if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) - { - const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); - return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; - } - // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" - const int pos = FindSepar(s + kSuperPathPrefixSize); - if (pos < 0) - return 0; - return kSuperPathPrefixSize + (unsigned)pos + 1; -} - -unsigned GetRootPrefixSize(CFSTR s) throw() -{ - if (IS_DEVICE_PATH(s)) - return kDevicePathPrefixSize; - if (IsSuperPath(s)) - return GetRootPrefixSize_Of_SuperPath(s); - return GetRootPrefixSize_Of_SimplePath(s); -} - -#endif // USE_UNICODE_FSTRING - -static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() -{ - // Network path: we look "server\path\" as root prefix - int pos = FindSepar(s); - if (pos < 0) - return 0; - int pos2 = FindSepar(s + (unsigned)pos + 1); - if (pos2 < 0) - return 0; - return (unsigned)(pos + pos2 + 2); -} - -static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() -{ - if (IsDrivePath(s)) - return kDrivePrefixSize; - if (!IS_SEPAR(s[0])) - return 0; - if (s[1] == 0 || !IS_SEPAR(s[1])) - return 1; - unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); - return (size == 0) ? 0 : 2 + size; -} - -static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() -{ - if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) - { - unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); - return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; - } - // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" - int pos = FindSepar(s + kSuperPathPrefixSize); - if (pos < 0) - return 0; - return kSuperPathPrefixSize + (unsigned)(pos + 1); -} - -unsigned GetRootPrefixSize(const wchar_t *s) throw() -{ - if (IS_DEVICE_PATH(s)) - return kDevicePathPrefixSize; - if (IsSuperPath(s)) - return GetRootPrefixSize_Of_SuperPath(s); - return GetRootPrefixSize_Of_SimplePath(s); -} - -#else // _WIN32 - -bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } - -#ifndef USE_UNICODE_FSTRING -unsigned GetRootPrefixSize(CFSTR s) throw(); -unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } -#endif -unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } - -#endif // _WIN32 - - -#ifndef UNDER_CE - - -#ifdef USE_UNICODE_FSTRING - -#define GetCurDir NDir::GetCurrentDir - -#else - -static bool GetCurDir(UString &path) -{ - path.Empty(); - FString s; - if (!NDir::GetCurrentDir(s)) - return false; - path = fs2us(s); - return true; -} - -#endif - - -static bool ResolveDotsFolders(UString &s) -{ - #ifdef _WIN32 - // s.Replace(L'/', WCHAR_PATH_SEPARATOR); - #endif - - for (unsigned i = 0;;) - { - const wchar_t c = s[i]; - if (c == 0) - return true; - if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) - { - const wchar_t c1 = s[i + 1]; - if (c1 == '.') - { - const wchar_t c2 = s[i + 2]; - if (IS_SEPAR(c2) || c2 == 0) - { - if (i == 0) - return false; - int k = (int)i - 2; - i += 2; - - for (;; k--) - { - if (k < 0) - return false; - if (!IS_SEPAR(s[(unsigned)k])) - break; - } - - do - k--; - while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); - - unsigned num; - - if (k >= 0) - { - num = i - (unsigned)k; - i = (unsigned)k; - } - else - { - num = (c2 == 0 ? i : (i + 1)); - i = 0; - } - - s.Delete(i, num); - continue; - } - } - else if (IS_SEPAR(c1) || c1 == 0) - { - unsigned num = 2; - if (i != 0) - i--; - else if (c1 == 0) - num = 1; - s.Delete(i, num); - continue; - } - } - - i++; - } -} - -#endif // UNDER_CE - -#define LONG_PATH_DOTS_FOLDERS_PARSING - - -/* -Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ -To solve that problem we check such path: - - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper - - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain -*/ -#ifdef LONG_PATH_DOTS_FOLDERS_PARSING -#ifndef UNDER_CE -static bool AreThereDotsFolders(CFSTR s) -{ - for (unsigned i = 0;; i++) - { - FChar c = s[i]; - if (c == 0) - return false; - if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) - { - FChar c1 = s[i + 1]; - if (c1 == 0 || IS_SEPAR(c1) || - (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) - return true; - } - } -} -#endif -#endif // LONG_PATH_DOTS_FOLDERS_PARSING - -#ifdef Z7_LONG_PATH - -/* -Most of Windows versions have problems, if some file or dir name -contains '.' or ' ' at the end of name (Bad Path). -To solve that problem, we always use Super Path ("\\?\" prefix and full path) -in such cases. Note that "." and ".." are not bad names. - -There are 3 cases: - 1) If the path is already Super Path, we use that path - 2) If the path is not Super Path : - 2.1) Bad Path; we use only Super Path. - 2.2) Good Path; we use Main Path. If it fails, we use Super Path. - - NeedToUseOriginalPath returns: - kSuperPathType_UseOnlyMain : Super already - kSuperPathType_UseOnlySuper : not Super, Bad Path - kSuperPathType_UseMainAndSuper : not Super, Good Path -*/ - -int GetUseSuperPathType(CFSTR s) throw() -{ - if (IsSuperOrDevicePath(s)) - { - #ifdef LONG_PATH_DOTS_FOLDERS_PARSING - if ((s)[2] != '.') - if (AreThereDotsFolders(s + kSuperPathPrefixSize)) - return kSuperPathType_UseOnlySuper; - #endif - return kSuperPathType_UseOnlyMain; - } - - for (unsigned i = 0;; i++) - { - FChar c = s[i]; - if (c == 0) - return kSuperPathType_UseMainAndSuper; - if (c == '.' || c == ' ') - { - FChar c2 = s[i + 1]; - if (c2 == 0 || IS_SEPAR(c2)) - { - // if it's "." or "..", it's not bad name. - if (c == '.') - { - if (i == 0 || IS_SEPAR(s[i - 1])) - continue; - if (s[i - 1] == '.') - { - if (i - 1 == 0 || IS_SEPAR(s[i - 2])) - continue; - } - } - return kSuperPathType_UseOnlySuper; - } - } - } -} - - - -/* - returns false in two cases: - - if GetCurDir was used, and GetCurDir returned error. - - if we can't resolve ".." name. - if path is ".", "..", res is empty. - if it's Super Path already, res is empty. - for \**** , and if GetCurDir is not drive (c:\), res is empty - for absolute paths, returns true, res is Super path. -*/ - -static bool GetSuperPathBase(CFSTR s, UString &res) -{ - res.Empty(); - - FChar c = s[0]; - if (c == 0) - return true; - if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) - return true; - - if (IsSuperOrDevicePath(s)) - { - #ifdef LONG_PATH_DOTS_FOLDERS_PARSING - - if ((s)[2] == '.') - return true; - - // we will return true here, so we will try to use these problem paths. - - if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) - return true; - - UString temp = fs2us(s); - const unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); - if (fixedSize == 0) - return true; - - UString rem = temp.Ptr(fixedSize); - if (!ResolveDotsFolders(rem)) - return true; - - temp.DeleteFrom(fixedSize); - res += temp; - res += rem; - - #endif - - return true; - } - - if (IS_SEPAR(c)) - { - if (IS_SEPAR(s[1])) - { - UString temp = fs2us(s + 2); - const unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); - // we ignore that error to allow short network paths server\share? - /* - if (fixedSize == 0) - return false; - */ - UString rem = temp.Ptr(fixedSize); - if (!ResolveDotsFolders(rem)) - return false; - res += kSuperUncPrefix; - temp.DeleteFrom(fixedSize); - res += temp; - res += rem; - return true; - } - } - else - { - if (IsDrivePath2(s)) - { - UString temp = fs2us(s); - unsigned prefixSize = 2; - if (IsDrivePath(s)) - prefixSize = kDrivePrefixSize; - UString rem = temp.Ptr(prefixSize); - if (!ResolveDotsFolders(rem)) - return true; - res += kSuperPathPrefix; - temp.DeleteFrom(prefixSize); - res += temp; - res += rem; - return true; - } - } - - UString curDir; - if (!GetCurDir(curDir)) - return false; - NormalizeDirPathPrefix(curDir); - - unsigned fixedSizeStart = 0; - unsigned fixedSize = 0; - const char *superMarker = NULL; - if (IsSuperPath(curDir)) - { - fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); - if (fixedSize == 0) - return false; - } - else - { - if (IsDrivePath(curDir)) - { - superMarker = kSuperPathPrefix; - fixedSize = kDrivePrefixSize; - } - else - { - if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) - return false; - fixedSizeStart = 2; - fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); - if (fixedSize == 0) - return false; - superMarker = kSuperUncPrefix; - } - } - - UString temp; - if (IS_SEPAR(c)) - { - temp = fs2us(s + 1); - } - else - { - temp += &curDir[fixedSizeStart + fixedSize]; - temp += fs2us(s); - } - if (!ResolveDotsFolders(temp)) - return false; - if (superMarker) - res += superMarker; - res += curDir.Mid(fixedSizeStart, fixedSize); - res += temp; - return true; -} - - -/* - In that case if GetSuperPathBase doesn't return new path, we don't need - to use same path that was used as main path - - GetSuperPathBase superPath.IsEmpty() onlyIfNew - false * * GetCurDir Error - true false * use Super path - true true true don't use any path, we already used mainPath - true true false use main path as Super Path, we don't try mainMath - That case is possible now if GetCurDir returns unknown - type of path (not drive and not network) - - We can change that code if we want to try mainPath, if GetSuperPathBase returns error, - and we didn't try mainPath still. - If we want to work that way, we don't need to use GetSuperPathBase return code. -*/ - -bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) -{ - if (GetSuperPathBase(path, superPath)) - { - if (superPath.IsEmpty()) - { - // actually the only possible when onlyIfNew == true and superPath is empty - // is case when - - if (onlyIfNew) - return false; - superPath = fs2us(path); - } - - NormalizeDirSeparators(superPath); - return true; - } - return false; -} - -bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) -{ - if (!GetSuperPathBase(s1, d1) || - !GetSuperPathBase(s2, d2)) - return false; - - NormalizeDirSeparators(d1); - NormalizeDirSeparators(d2); - - if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) - return false; - if (d1.IsEmpty()) d1 = fs2us(s1); - if (d2.IsEmpty()) d2 = fs2us(s2); - return true; -} - - -/* -// returns true, if we need additional use with New Super path. -bool GetSuperPath(CFSTR path, UString &superPath) -{ - if (GetSuperPathBase(path, superPath)) - return !superPath.IsEmpty(); - return false; -} -*/ -#endif // Z7_LONG_PATH - -bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) -{ - res = s; - - #ifdef UNDER_CE - - if (!IS_SEPAR(s[0])) - { - if (!dirPrefix) - return false; - res = dirPrefix; - res += s; - } - - #else - - const unsigned prefixSize = GetRootPrefixSize(s); - if (prefixSize != 0) -#ifdef _WIN32 - if (prefixSize != 1) -#endif - { - if (!AreThereDotsFolders(s + prefixSize)) - return true; - - UString rem = fs2us(s + prefixSize); - if (!ResolveDotsFolders(rem)) - return true; // maybe false; - res.DeleteFrom(prefixSize); - res += us2fs(rem); - return true; - } - - UString curDir; - if (dirPrefix && prefixSize == 0) - curDir = fs2us(dirPrefix); // we use (dirPrefix), only if (s) path is relative - else - { - if (!GetCurDir(curDir)) - return false; - } - NormalizeDirPathPrefix(curDir); - - unsigned fixedSize = GetRootPrefixSize(curDir); - - UString temp; -#ifdef _WIN32 - if (prefixSize != 0) - { - /* (s) is absolute path, but only (prefixSize == 1) is possible here. - So for full resolving we need root of current folder and - relative part of (s). */ - s += prefixSize; - // (s) is relative part now - if (fixedSize == 0) - { - // (curDir) is not absolute. - // That case is unexpected, but we support it too. - curDir.Empty(); - curDir.Add_PathSepar(); - fixedSize = 1; - // (curDir) now is just Separ character. - // So final (res) path later also will have Separ prefix. - } - } - else -#endif // _WIN32 - { - // (s) is relative path - temp = curDir.Ptr(fixedSize); - // (temp) is relative_part_of(curDir) - } - temp += fs2us(s); - if (!ResolveDotsFolders(temp)) - return false; - curDir.DeleteFrom(fixedSize); - // (curDir) now contains only absolute prefix part - res = us2fs(curDir); - res += us2fs(temp); - - #endif // UNDER_CE - - return true; -} - - -bool GetFullPath(CFSTR path, FString &fullPath) -{ - return GetFullPath(NULL, path, fullPath); -} - -}}} +// Windows/FileName.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 +#include +#include +#include "../Common/StringConvert.h" +#endif + +#include "FileDir.h" +#include "FileName.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NFile { +namespace NName { + +#define IS_SEPAR(c) IS_PATH_SEPAR(c) + +int FindSepar(const wchar_t *s) throw() +{ + for (const wchar_t *p = s;; p++) + { + const wchar_t c = *p; + if (c == 0) + return -1; + if (IS_SEPAR(c)) + return (int)(p - s); + } +} + +#ifndef USE_UNICODE_FSTRING +int FindSepar(const FChar *s) throw() +{ + for (const FChar *p = s;; p++) + { + const FChar c = *p; + if (c == 0) + return -1; + if (IS_SEPAR(c)) + return (int)(p - s); + } +} +#endif + +#ifndef USE_UNICODE_FSTRING +void NormalizeDirPathPrefix(FString &dirPath) +{ + if (dirPath.IsEmpty()) + return; + if (!IsPathSepar(dirPath.Back())) + dirPath.Add_PathSepar(); +} +#endif + +void NormalizeDirPathPrefix(UString &dirPath) +{ + if (dirPath.IsEmpty()) + return; + if (!IsPathSepar(dirPath.Back())) + dirPath.Add_PathSepar(); +} + +#ifdef _WIN32 + +#ifndef USE_UNICODE_FSTRING +#ifdef Z7_LONG_PATH +static void NormalizeDirSeparators(UString &s) +{ + const unsigned len = s.Len(); + for (unsigned i = 0; i < len; i++) + if (s[i] == '/') + s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR); +} +#endif +#endif + +void NormalizeDirSeparators(FString &s) +{ + const unsigned len = s.Len(); + for (unsigned i = 0; i < len; i++) + if (s[i] == '/') + s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); +} + +#endif + + +#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a'))) + +bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } + +bool IsAltPathPrefix(CFSTR s) throw() +{ + unsigned len = MyStringLen(s); + if (len == 0) + return false; + if (s[len - 1] != ':') + return false; + + #if defined(_WIN32) && !defined(UNDER_CE) + if (IsDevicePath(s)) + return false; + if (IsSuperPath(s)) + { + s += kSuperPathPrefixSize; + len -= kSuperPathPrefixSize; + } + if (len == 2 && IsDrivePath2(s)) + return false; + #endif + + return true; +} + +#if defined(_WIN32) && !defined(UNDER_CE) + +const char * const kSuperPathPrefix = "\\\\?\\"; +#ifdef Z7_LONG_PATH +static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; +#endif + +#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) +#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) +#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3])) + +#define IS_UNC_WITH_SLASH(s) ( \ + ((s)[0] == 'U' || (s)[0] == 'u') \ + && ((s)[1] == 'N' || (s)[1] == 'n') \ + && ((s)[2] == 'C' || (s)[2] == 'c') \ + && IS_SEPAR((s)[3])) + +bool IsDevicePath(CFSTR s) throw() +{ + #ifdef UNDER_CE + + s = s; + return false; + /* + // actually we don't know the way to open device file in WinCE. + unsigned len = MyStringLen(s); + if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK")) + return false; + if (s[4] != ':') + return false; + // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); + */ + + #else + + if (!IS_DEVICE_PATH(s)) + return false; + unsigned len = MyStringLen(s); + if (len == 6 && s[5] == ':') + return true; + if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) + return false; + for (unsigned i = 17; i < len; i++) + if (s[i] < '0' || s[i] > '9') + return false; + return true; + + #endif +} + +bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } +bool IsNetworkPath(CFSTR s) throw() +{ + if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) + return false; + if (IsSuperUncPath(s)) + return true; + FChar c = s[2]; + return (c != '.' && c != '?'); +} + +unsigned GetNetworkServerPrefixSize(CFSTR s) throw() +{ + if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) + return 0; + unsigned prefixSize = 2; + if (IsSuperUncPath(s)) + prefixSize = kSuperUncPathPrefixSize; + else + { + FChar c = s[2]; + if (c == '.' || c == '?') + return 0; + } + const int pos = FindSepar(s + prefixSize); + if (pos < 0) + return 0; + return prefixSize + (unsigned)(pos + 1); +} + +bool IsNetworkShareRootPath(CFSTR s) throw() +{ + const unsigned prefixSize = GetNetworkServerPrefixSize(s); + if (prefixSize == 0) + return false; + s += prefixSize; + const int pos = FindSepar(s); + if (pos < 0) + return true; + return s[(unsigned)pos + 1] == 0; +} + +static const unsigned kDrivePrefixSize = 3; /* c:\ */ + +bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } +// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } +bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } +bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } +// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } + +bool IsAltStreamPrefixWithColon(const UString &s) throw() +{ + if (s.IsEmpty()) + return false; + if (s.Back() != ':') + return false; + unsigned pos = 0; + if (IsSuperPath(s)) + pos = kSuperPathPrefixSize; + if (s.Len() - pos == 2 && IsDrivePath2(s.Ptr(pos))) + return false; + return true; +} + +bool If_IsSuperPath_RemoveSuperPrefix(UString &s) +{ + if (!IsSuperPath(s)) + return false; + unsigned start = 0; + unsigned count = kSuperPathPrefixSize; + const wchar_t *s2 = s.Ptr(kSuperPathPrefixSize); + if (IS_UNC_WITH_SLASH(s2)) + { + start = 2; + count = kSuperUncPathPrefixSize - 2; + } + s.Delete(start, count); + return true; +} + + +#ifndef USE_UNICODE_FSTRING +bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } +// bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } +bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } +bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } +bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } +#endif // USE_UNICODE_FSTRING + +bool IsDrivePath_SuperAllowed(CFSTR s) throw() +{ + if (IsSuperPath(s)) + s += kSuperPathPrefixSize; + return IsDrivePath(s); +} + +bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() +{ + if (IsSuperPath(s)) + s += kSuperPathPrefixSize; + return IsDrivePath(s) && s[kDrivePrefixSize] == 0; +} + +bool IsAbsolutePath(const wchar_t *s) throw() +{ + return IS_SEPAR(s[0]) || IsDrivePath2(s); +} + +int FindAltStreamColon(CFSTR path) throw() +{ + unsigned i = 0; + if (IsSuperPath(path)) + i = kSuperPathPrefixSize; + if (IsDrivePath2(path + i)) + i += 2; + int colonPos = -1; + for (;; i++) + { + const FChar c = path[i]; + if (c == 0) + return colonPos; + if (c == ':') + { + if (colonPos < 0) + colonPos = (int)i; + continue; + } + if (IS_SEPAR(c)) + colonPos = -1; + } +} + +#ifndef USE_UNICODE_FSTRING + +static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) +{ + // Network path: we look "server\path\" as root prefix + const int pos = FindSepar(s); + if (pos < 0) + return 0; + const int pos2 = FindSepar(s + (unsigned)pos + 1); + if (pos2 < 0) + return 0; + return (unsigned)pos + (unsigned)pos2 + 2; +} + +static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) +{ + if (IsDrivePath(s)) + return kDrivePrefixSize; + if (!IS_SEPAR(s[0])) + return 0; + if (s[1] == 0 || !IS_SEPAR(s[1])) + return 1; + const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); + return (size == 0) ? 0 : 2 + size; +} + +static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) +{ + if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) + { + const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); + return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; + } + // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" + const int pos = FindSepar(s + kSuperPathPrefixSize); + if (pos < 0) + return 0; + return kSuperPathPrefixSize + (unsigned)pos + 1; +} + +unsigned GetRootPrefixSize(CFSTR s) throw() +{ + if (IS_DEVICE_PATH(s)) + return kDevicePathPrefixSize; + if (IsSuperPath(s)) + return GetRootPrefixSize_Of_SuperPath(s); + return GetRootPrefixSize_Of_SimplePath(s); +} + +#endif // USE_UNICODE_FSTRING + +static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() +{ + // Network path: we look "server\path\" as root prefix + int pos = FindSepar(s); + if (pos < 0) + return 0; + int pos2 = FindSepar(s + (unsigned)pos + 1); + if (pos2 < 0) + return 0; + return (unsigned)(pos + pos2 + 2); +} + +static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() +{ + if (IsDrivePath(s)) + return kDrivePrefixSize; + if (!IS_SEPAR(s[0])) + return 0; + if (s[1] == 0 || !IS_SEPAR(s[1])) + return 1; + unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); + return (size == 0) ? 0 : 2 + size; +} + +static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() +{ + if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) + { + unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); + return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; + } + // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" + int pos = FindSepar(s + kSuperPathPrefixSize); + if (pos < 0) + return 0; + return kSuperPathPrefixSize + (unsigned)(pos + 1); +} + +unsigned GetRootPrefixSize(const wchar_t *s) throw() +{ + if (IS_DEVICE_PATH(s)) + return kDevicePathPrefixSize; + if (IsSuperPath(s)) + return GetRootPrefixSize_Of_SuperPath(s); + return GetRootPrefixSize_Of_SimplePath(s); +} + +#else // _WIN32 + +bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } + +#ifndef USE_UNICODE_FSTRING +unsigned GetRootPrefixSize(CFSTR s) throw(); +unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } +#endif +unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } + +#endif // _WIN32 + + +#ifndef UNDER_CE + + +#ifdef USE_UNICODE_FSTRING + +#define GetCurDir NDir::GetCurrentDir + +#else + +static bool GetCurDir(UString &path) +{ + path.Empty(); + FString s; + if (!NDir::GetCurrentDir(s)) + return false; + path = fs2us(s); + return true; +} + +#endif + + +static bool ResolveDotsFolders(UString &s) +{ + #ifdef _WIN32 + // s.Replace(L'/', WCHAR_PATH_SEPARATOR); + #endif + + for (unsigned i = 0;;) + { + const wchar_t c = s[i]; + if (c == 0) + return true; + if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) + { + const wchar_t c1 = s[i + 1]; + if (c1 == '.') + { + const wchar_t c2 = s[i + 2]; + if (IS_SEPAR(c2) || c2 == 0) + { + if (i == 0) + return false; + int k = (int)i - 2; + i += 2; + + for (;; k--) + { + if (k < 0) + return false; + if (!IS_SEPAR(s[(unsigned)k])) + break; + } + + do + k--; + while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); + + unsigned num; + + if (k >= 0) + { + num = i - (unsigned)k; + i = (unsigned)k; + } + else + { + num = (c2 == 0 ? i : (i + 1)); + i = 0; + } + + s.Delete(i, num); + continue; + } + } + else if (IS_SEPAR(c1) || c1 == 0) + { + unsigned num = 2; + if (i != 0) + i--; + else if (c1 == 0) + num = 1; + s.Delete(i, num); + continue; + } + } + + i++; + } +} + +#endif // UNDER_CE + +#define LONG_PATH_DOTS_FOLDERS_PARSING + + +/* +Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ +To solve that problem we check such path: + - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper + - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain +*/ +#ifdef LONG_PATH_DOTS_FOLDERS_PARSING +#ifndef UNDER_CE +static bool AreThereDotsFolders(CFSTR s) +{ + for (unsigned i = 0;; i++) + { + FChar c = s[i]; + if (c == 0) + return false; + if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) + { + FChar c1 = s[i + 1]; + if (c1 == 0 || IS_SEPAR(c1) || + (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) + return true; + } + } +} +#endif +#endif // LONG_PATH_DOTS_FOLDERS_PARSING + +#ifdef Z7_LONG_PATH + +/* +Most of Windows versions have problems, if some file or dir name +contains '.' or ' ' at the end of name (Bad Path). +To solve that problem, we always use Super Path ("\\?\" prefix and full path) +in such cases. Note that "." and ".." are not bad names. + +There are 3 cases: + 1) If the path is already Super Path, we use that path + 2) If the path is not Super Path : + 2.1) Bad Path; we use only Super Path. + 2.2) Good Path; we use Main Path. If it fails, we use Super Path. + + NeedToUseOriginalPath returns: + kSuperPathType_UseOnlyMain : Super already + kSuperPathType_UseOnlySuper : not Super, Bad Path + kSuperPathType_UseMainAndSuper : not Super, Good Path +*/ + +int GetUseSuperPathType(CFSTR s) throw() +{ + if (IsSuperOrDevicePath(s)) + { + #ifdef LONG_PATH_DOTS_FOLDERS_PARSING + if ((s)[2] != '.') + if (AreThereDotsFolders(s + kSuperPathPrefixSize)) + return kSuperPathType_UseOnlySuper; + #endif + return kSuperPathType_UseOnlyMain; + } + + for (unsigned i = 0;; i++) + { + FChar c = s[i]; + if (c == 0) + return kSuperPathType_UseMainAndSuper; + if (c == '.' || c == ' ') + { + FChar c2 = s[i + 1]; + if (c2 == 0 || IS_SEPAR(c2)) + { + // if it's "." or "..", it's not bad name. + if (c == '.') + { + if (i == 0 || IS_SEPAR(s[i - 1])) + continue; + if (s[i - 1] == '.') + { + if (i - 1 == 0 || IS_SEPAR(s[i - 2])) + continue; + } + } + return kSuperPathType_UseOnlySuper; + } + } + } +} + + + +/* + returns false in two cases: + - if GetCurDir was used, and GetCurDir returned error. + - if we can't resolve ".." name. + if path is ".", "..", res is empty. + if it's Super Path already, res is empty. + for \**** , and if GetCurDir is not drive (c:\), res is empty + for absolute paths, returns true, res is Super path. +*/ + +static bool GetSuperPathBase(CFSTR s, UString &res) +{ + res.Empty(); + + FChar c = s[0]; + if (c == 0) + return true; + if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) + return true; + + if (IsSuperOrDevicePath(s)) + { + #ifdef LONG_PATH_DOTS_FOLDERS_PARSING + + if ((s)[2] == '.') + return true; + + // we will return true here, so we will try to use these problem paths. + + if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) + return true; + + UString temp = fs2us(s); + const unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); + if (fixedSize == 0) + return true; + + UString rem = temp.Ptr(fixedSize); + if (!ResolveDotsFolders(rem)) + return true; + + temp.DeleteFrom(fixedSize); + res += temp; + res += rem; + + #endif + + return true; + } + + if (IS_SEPAR(c)) + { + if (IS_SEPAR(s[1])) + { + UString temp = fs2us(s + 2); + const unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); + // we ignore that error to allow short network paths server\share? + /* + if (fixedSize == 0) + return false; + */ + UString rem = temp.Ptr(fixedSize); + if (!ResolveDotsFolders(rem)) + return false; + res += kSuperUncPrefix; + temp.DeleteFrom(fixedSize); + res += temp; + res += rem; + return true; + } + } + else + { + if (IsDrivePath2(s)) + { + UString temp = fs2us(s); + unsigned prefixSize = 2; + if (IsDrivePath(s)) + prefixSize = kDrivePrefixSize; + UString rem = temp.Ptr(prefixSize); + if (!ResolveDotsFolders(rem)) + return true; + res += kSuperPathPrefix; + temp.DeleteFrom(prefixSize); + res += temp; + res += rem; + return true; + } + } + + UString curDir; + if (!GetCurDir(curDir)) + return false; + NormalizeDirPathPrefix(curDir); + + unsigned fixedSizeStart = 0; + unsigned fixedSize = 0; + const char *superMarker = NULL; + if (IsSuperPath(curDir)) + { + fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); + if (fixedSize == 0) + return false; + } + else + { + if (IsDrivePath(curDir)) + { + superMarker = kSuperPathPrefix; + fixedSize = kDrivePrefixSize; + } + else + { + if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) + return false; + fixedSizeStart = 2; + fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); + if (fixedSize == 0) + return false; + superMarker = kSuperUncPrefix; + } + } + + UString temp; + if (IS_SEPAR(c)) + { + temp = fs2us(s + 1); + } + else + { + temp += &curDir[fixedSizeStart + fixedSize]; + temp += fs2us(s); + } + if (!ResolveDotsFolders(temp)) + return false; + if (superMarker) + res += superMarker; + res += curDir.Mid(fixedSizeStart, fixedSize); + res += temp; + return true; +} + + +/* + In that case if GetSuperPathBase doesn't return new path, we don't need + to use same path that was used as main path + + GetSuperPathBase superPath.IsEmpty() onlyIfNew + false * * GetCurDir Error + true false * use Super path + true true true don't use any path, we already used mainPath + true true false use main path as Super Path, we don't try mainMath + That case is possible now if GetCurDir returns unknown + type of path (not drive and not network) + + We can change that code if we want to try mainPath, if GetSuperPathBase returns error, + and we didn't try mainPath still. + If we want to work that way, we don't need to use GetSuperPathBase return code. +*/ + +bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) +{ + if (GetSuperPathBase(path, superPath)) + { + if (superPath.IsEmpty()) + { + // actually the only possible when onlyIfNew == true and superPath is empty + // is case when + + if (onlyIfNew) + return false; + superPath = fs2us(path); + } + + NormalizeDirSeparators(superPath); + return true; + } + return false; +} + +bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) +{ + if (!GetSuperPathBase(s1, d1) || + !GetSuperPathBase(s2, d2)) + return false; + + NormalizeDirSeparators(d1); + NormalizeDirSeparators(d2); + + if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) + return false; + if (d1.IsEmpty()) d1 = fs2us(s1); + if (d2.IsEmpty()) d2 = fs2us(s2); + return true; +} + + +/* +// returns true, if we need additional use with New Super path. +bool GetSuperPath(CFSTR path, UString &superPath) +{ + if (GetSuperPathBase(path, superPath)) + return !superPath.IsEmpty(); + return false; +} +*/ +#endif // Z7_LONG_PATH + +bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) +{ + res = s; + + #ifdef UNDER_CE + + if (!IS_SEPAR(s[0])) + { + if (!dirPrefix) + return false; + res = dirPrefix; + res += s; + } + + #else + + const unsigned prefixSize = GetRootPrefixSize(s); + if (prefixSize != 0) +#ifdef _WIN32 + if (prefixSize != 1) +#endif + { + if (!AreThereDotsFolders(s + prefixSize)) + return true; + + UString rem = fs2us(s + prefixSize); + if (!ResolveDotsFolders(rem)) + return true; // maybe false; + res.DeleteFrom(prefixSize); + res += us2fs(rem); + return true; + } + + UString curDir; + if (dirPrefix && prefixSize == 0) + curDir = fs2us(dirPrefix); // we use (dirPrefix), only if (s) path is relative + else + { + if (!GetCurDir(curDir)) + return false; + } + NormalizeDirPathPrefix(curDir); + + unsigned fixedSize = GetRootPrefixSize(curDir); + + UString temp; +#ifdef _WIN32 + if (prefixSize != 0) + { + /* (s) is absolute path, but only (prefixSize == 1) is possible here. + So for full resolving we need root of current folder and + relative part of (s). */ + s += prefixSize; + // (s) is relative part now + if (fixedSize == 0) + { + // (curDir) is not absolute. + // That case is unexpected, but we support it too. + curDir.Empty(); + curDir.Add_PathSepar(); + fixedSize = 1; + // (curDir) now is just Separ character. + // So final (res) path later also will have Separ prefix. + } + } + else +#endif // _WIN32 + { + // (s) is relative path + temp = curDir.Ptr(fixedSize); + // (temp) is relative_part_of(curDir) + } + temp += fs2us(s); + if (!ResolveDotsFolders(temp)) + return false; + curDir.DeleteFrom(fixedSize); + // (curDir) now contains only absolute prefix part + res = us2fs(curDir); + res += us2fs(temp); + + #endif // UNDER_CE + + return true; +} + + +bool GetFullPath(CFSTR path, FString &fullPath) +{ + return GetFullPath(NULL, path, fullPath); +} + +}}} diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h index d0e9dc47a..219b656b2 100644 --- a/CPP/Windows/FileName.h +++ b/CPP/Windows/FileName.h @@ -1,133 +1,133 @@ -// Windows/FileName.h - -#ifndef ZIP7_INC_WINDOWS_FILE_NAME_H -#define ZIP7_INC_WINDOWS_FILE_NAME_H - -#include "../Common/MyString.h" - -namespace NWindows { -namespace NFile { -namespace NName { - -int FindSepar(const wchar_t *s) throw(); -#ifndef USE_UNICODE_FSTRING -int FindSepar(const FChar *s) throw(); -#endif - -void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty -void NormalizeDirPathPrefix(UString &dirPath); - -#ifdef _WIN32 -void NormalizeDirSeparators(FString &s); -#endif - -bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\" - -bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ - -#if defined(_WIN32) && !defined(UNDER_CE) - -extern const char * const kSuperPathPrefix; /* \\?\ */ -const unsigned kDevicePathPrefixSize = 4; -const unsigned kSuperPathPrefixSize = 4; -const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; - -bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ -bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ -bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ - -/* GetNetworkServerPrefixSize() returns size of server prefix: - \\?\UNC\SERVER\ - \\SERVER\ - in another cases it returns 0 -*/ - -unsigned GetNetworkServerPrefixSize(CFSTR s) throw(); - -bool IsNetworkShareRootPath(CFSTR s) throw(); /* \\?\UNC\SERVER\share or \\SERVER\share or with slash */ - -bool IsDrivePath_SuperAllowed(CFSTR s) throw(); // first chars are drive chars like "a:\" or "\\?\a:\" -bool IsDriveRootPath_SuperAllowed(CFSTR s) throw(); // exact drive root path "a:\" or "\\?\a:\" - -bool IsDrivePath2(const wchar_t *s) throw(); // first 2 chars are drive chars like "a:" -// bool IsDriveName2(const wchar_t *s) throw(); // is drive name like "a:" -bool IsSuperPath(const wchar_t *s) throw(); -bool IsSuperOrDevicePath(const wchar_t *s) throw(); - -bool IsAltStreamPrefixWithColon(const UString &s) throw(); -// returns true, if super prefix was removed -bool If_IsSuperPath_RemoveSuperPrefix(UString &s); - -#ifndef USE_UNICODE_FSTRING -bool IsDrivePath2(CFSTR s) throw(); // first 2 chars are drive chars like "a:" -// bool IsDriveName2(CFSTR s) throw(); // is drive name like "a:" -bool IsDrivePath(CFSTR s) throw(); -bool IsSuperPath(CFSTR s) throw(); -bool IsSuperOrDevicePath(CFSTR s) throw(); - -/* GetRootPrefixSize() returns size of ROOT PREFIX for cases: - \ - \\.\ - C:\ - \\?\C:\ - \\?\UNC\SERVER\Shared\ - \\SERVER\Shared\ - in another cases it returns 0 -*/ - -unsigned GetRootPrefixSize(CFSTR s) throw(); - -#endif - -int FindAltStreamColon(CFSTR path) throw(); - -#endif // _WIN32 - -bool IsAbsolutePath(const wchar_t *s) throw(); -unsigned GetRootPrefixSize(const wchar_t *s) throw(); - -#ifdef Z7_LONG_PATH - -const int kSuperPathType_UseOnlyMain = 0; -const int kSuperPathType_UseOnlySuper = 1; -const int kSuperPathType_UseMainAndSuper = 2; - -int GetUseSuperPathType(CFSTR s) throw(); -bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew); -bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew); - -#define USE_MAIN_PATH (_useSuperPathType != kSuperPathType_UseOnlySuper) -#define USE_MAIN_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlySuper && _useSuperPathType2 != kSuperPathType_UseOnlySuper) - -#define USE_SUPER_PATH (_useSuperPathType != kSuperPathType_UseOnlyMain) -#define USE_SUPER_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlyMain || _useSuperPathType2 != kSuperPathType_UseOnlyMain) - -#define IF_USE_MAIN_PATH int _useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH) -#define IF_USE_MAIN_PATH_2(x1, x2) \ - int _useSuperPathType1 = GetUseSuperPathType(x1); \ - int _useSuperPathType2 = GetUseSuperPathType(x2); \ - if (USE_MAIN_PATH_2) - -#else - -#define IF_USE_MAIN_PATH -#define IF_USE_MAIN_PATH_2(x1, x2) - -#endif // Z7_LONG_PATH - -/* - if (dirPrefix != NULL && (path) is relative) - { - (dirPrefix) will be used - result (fullPath) will contain prefix part of (dirPrefix). - } - Current_Dir path can be used in 2 cases: - 1) if (path) is relative && dirPrefix == NULL - 2) for _WIN32: if (path) is absolute starting wuth "\" -*/ -bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath); -bool GetFullPath(CFSTR path, FString &fullPath); - -}}} - -#endif +// Windows/FileName.h + +#ifndef ZIP7_INC_WINDOWS_FILE_NAME_H +#define ZIP7_INC_WINDOWS_FILE_NAME_H + +#include "../Common/MyString.h" + +namespace NWindows { +namespace NFile { +namespace NName { + +int FindSepar(const wchar_t *s) throw(); +#ifndef USE_UNICODE_FSTRING +int FindSepar(const FChar *s) throw(); +#endif + +void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty +void NormalizeDirPathPrefix(UString &dirPath); + +#ifdef _WIN32 +void NormalizeDirSeparators(FString &s); +#endif + +bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\" + +bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ + +#if defined(_WIN32) && !defined(UNDER_CE) + +extern const char * const kSuperPathPrefix; /* \\?\ */ +const unsigned kDevicePathPrefixSize = 4; +const unsigned kSuperPathPrefixSize = 4; +const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; + +bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ +bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ +bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ + +/* GetNetworkServerPrefixSize() returns size of server prefix: + \\?\UNC\SERVER\ + \\SERVER\ + in another cases it returns 0 +*/ + +unsigned GetNetworkServerPrefixSize(CFSTR s) throw(); + +bool IsNetworkShareRootPath(CFSTR s) throw(); /* \\?\UNC\SERVER\share or \\SERVER\share or with slash */ + +bool IsDrivePath_SuperAllowed(CFSTR s) throw(); // first chars are drive chars like "a:\" or "\\?\a:\" +bool IsDriveRootPath_SuperAllowed(CFSTR s) throw(); // exact drive root path "a:\" or "\\?\a:\" + +bool IsDrivePath2(const wchar_t *s) throw(); // first 2 chars are drive chars like "a:" +// bool IsDriveName2(const wchar_t *s) throw(); // is drive name like "a:" +bool IsSuperPath(const wchar_t *s) throw(); +bool IsSuperOrDevicePath(const wchar_t *s) throw(); + +bool IsAltStreamPrefixWithColon(const UString &s) throw(); +// returns true, if super prefix was removed +bool If_IsSuperPath_RemoveSuperPrefix(UString &s); + +#ifndef USE_UNICODE_FSTRING +bool IsDrivePath2(CFSTR s) throw(); // first 2 chars are drive chars like "a:" +// bool IsDriveName2(CFSTR s) throw(); // is drive name like "a:" +bool IsDrivePath(CFSTR s) throw(); +bool IsSuperPath(CFSTR s) throw(); +bool IsSuperOrDevicePath(CFSTR s) throw(); + +/* GetRootPrefixSize() returns size of ROOT PREFIX for cases: + \ + \\.\ + C:\ + \\?\C:\ + \\?\UNC\SERVER\Shared\ + \\SERVER\Shared\ + in another cases it returns 0 +*/ + +unsigned GetRootPrefixSize(CFSTR s) throw(); + +#endif + +int FindAltStreamColon(CFSTR path) throw(); + +#endif // _WIN32 + +bool IsAbsolutePath(const wchar_t *s) throw(); +unsigned GetRootPrefixSize(const wchar_t *s) throw(); + +#ifdef Z7_LONG_PATH + +const int kSuperPathType_UseOnlyMain = 0; +const int kSuperPathType_UseOnlySuper = 1; +const int kSuperPathType_UseMainAndSuper = 2; + +int GetUseSuperPathType(CFSTR s) throw(); +bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew); +bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew); + +#define USE_MAIN_PATH (_useSuperPathType != kSuperPathType_UseOnlySuper) +#define USE_MAIN_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlySuper && _useSuperPathType2 != kSuperPathType_UseOnlySuper) + +#define USE_SUPER_PATH (_useSuperPathType != kSuperPathType_UseOnlyMain) +#define USE_SUPER_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlyMain || _useSuperPathType2 != kSuperPathType_UseOnlyMain) + +#define IF_USE_MAIN_PATH int _useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH) +#define IF_USE_MAIN_PATH_2(x1, x2) \ + int _useSuperPathType1 = GetUseSuperPathType(x1); \ + int _useSuperPathType2 = GetUseSuperPathType(x2); \ + if (USE_MAIN_PATH_2) + +#else + +#define IF_USE_MAIN_PATH +#define IF_USE_MAIN_PATH_2(x1, x2) + +#endif // Z7_LONG_PATH + +/* + if (dirPrefix != NULL && (path) is relative) + { + (dirPrefix) will be used + result (fullPath) will contain prefix part of (dirPrefix). + } + Current_Dir path can be used in 2 cases: + 1) if (path) is relative && dirPrefix == NULL + 2) for _WIN32: if (path) is absolute starting wuth "\" +*/ +bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath); +bool GetFullPath(CFSTR path, FString &fullPath); + +}}} + +#endif diff --git a/CPP/Windows/FileSystem.cpp b/CPP/Windows/FileSystem.cpp index 02faf627b..b40230607 100644 --- a/CPP/Windows/FileSystem.cpp +++ b/CPP/Windows/FileSystem.cpp @@ -1,187 +1,187 @@ -// Windows/FileSystem.cpp - -#include "StdAfx.h" - -#ifndef UNDER_CE - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif - -#include "FileSystem.h" -#include "Defs.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NFile { -namespace NSystem { - -#ifdef _WIN32 - -bool MyGetVolumeInformation( - CFSTR rootPath, - UString &volumeName, - LPDWORD volumeSerialNumber, - LPDWORD maximumComponentLength, - LPDWORD fileSystemFlags, - UString &fileSystemName) -{ - BOOL res; - #ifndef _UNICODE - if (!g_IsNT) - { - TCHAR v[MAX_PATH + 2]; v[0] = 0; - TCHAR f[MAX_PATH + 2]; f[0] = 0; - res = GetVolumeInformation(fs2fas(rootPath), - v, MAX_PATH, - volumeSerialNumber, maximumComponentLength, fileSystemFlags, - f, MAX_PATH); - volumeName = MultiByteToUnicodeString(v); - fileSystemName = MultiByteToUnicodeString(f); - } - else - #endif - { - WCHAR v[MAX_PATH + 2]; v[0] = 0; - WCHAR f[MAX_PATH + 2]; f[0] = 0; - res = GetVolumeInformationW(fs2us(rootPath), - v, MAX_PATH, - volumeSerialNumber, maximumComponentLength, fileSystemFlags, - f, MAX_PATH); - volumeName = v; - fileSystemName = f; - } - return BOOLToBool(res); -} - -UINT MyGetDriveType(CFSTR pathName) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - return GetDriveType(fs2fas(pathName)); - } - else - #endif - { - return GetDriveTypeW(fs2us(pathName)); - } -} - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0400 -// GetDiskFreeSpaceEx requires Windows95-OSR2, NT4 -#define Z7_USE_DYN_GetDiskFreeSpaceEx -#endif - -#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx -typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExA)( - LPCSTR lpDirectoryName, // directory name - PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller - PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk - PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk -); - -typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExW)( - LPCWSTR lpDirectoryName, // directory name - PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller - PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk - PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk -); -#endif - -bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize) -{ - DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters; - bool sizeIsDetected = false; - #ifndef _UNICODE - if (!g_IsNT) - { -#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx - const - Func_GetDiskFreeSpaceExA f = Z7_GET_PROC_ADDRESS( - Func_GetDiskFreeSpaceExA, GetModuleHandle(TEXT("kernel32.dll")), - "GetDiskFreeSpaceExA"); - if (f) -#endif - { - ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2; - sizeIsDetected = BOOLToBool( -#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx - f -#else - GetDiskFreeSpaceExA -#endif - (fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2)); - totalSize = totalSize2.QuadPart; - freeSize = freeSize2.QuadPart; - } - if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters)) - return false; - } - else - #endif - { -#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx - const - Func_GetDiskFreeSpaceExW f = Z7_GET_PROC_ADDRESS( - Func_GetDiskFreeSpaceExW, GetModuleHandle(TEXT("kernel32.dll")), - "GetDiskFreeSpaceExW"); - if (f) -#endif - { - ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2; - sizeIsDetected = BOOLToBool( -#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx - f -#else - GetDiskFreeSpaceExW -#endif - (fs2us(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2)); - totalSize = totalSize2.QuadPart; - freeSize = freeSize2.QuadPart; - } - if (!::GetDiskFreeSpaceW(fs2us(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters)) - return false; - } - clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster; - if (!sizeIsDetected) - { - totalSize = clusterSize * (UInt64)numClusters; - freeSize = clusterSize * (UInt64)numFreeClusters; - } - return true; -} - -#endif - -/* -bool Is_File_LimitedBy_4GB(CFSTR _path, bool &isFsDetected) -{ - isFsDetected = false; - FString path (_path); - path.DeleteFrom(NName::GetRootPrefixSize(path)); - // GetVolumeInformation supports super paths. - // NName::If_IsSuperPath_RemoveSuperPrefix(path); - if (!path.IsEmpty()) - { - DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags; - UString volName, fileSystemName; - if (MyGetVolumeInformation(path, volName, - &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags, - fileSystemName)) - { - isFsDetected = true; - if (fileSystemName.IsPrefixedBy_Ascii_NoCase("fat")) - return true; - } - } - return false; -} -*/ - -}}} - -#endif +// Windows/FileSystem.cpp + +#include "StdAfx.h" + +#ifndef UNDER_CE + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#include "FileSystem.h" +#include "Defs.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NFile { +namespace NSystem { + +#ifdef _WIN32 + +bool MyGetVolumeInformation( + CFSTR rootPath, + UString &volumeName, + LPDWORD volumeSerialNumber, + LPDWORD maximumComponentLength, + LPDWORD fileSystemFlags, + UString &fileSystemName) +{ + BOOL res; + #ifndef _UNICODE + if (!g_IsNT) + { + TCHAR v[MAX_PATH + 2]; v[0] = 0; + TCHAR f[MAX_PATH + 2]; f[0] = 0; + res = GetVolumeInformation(fs2fas(rootPath), + v, MAX_PATH, + volumeSerialNumber, maximumComponentLength, fileSystemFlags, + f, MAX_PATH); + volumeName = MultiByteToUnicodeString(v); + fileSystemName = MultiByteToUnicodeString(f); + } + else + #endif + { + WCHAR v[MAX_PATH + 2]; v[0] = 0; + WCHAR f[MAX_PATH + 2]; f[0] = 0; + res = GetVolumeInformationW(fs2us(rootPath), + v, MAX_PATH, + volumeSerialNumber, maximumComponentLength, fileSystemFlags, + f, MAX_PATH); + volumeName = v; + fileSystemName = f; + } + return BOOLToBool(res); +} + +UINT MyGetDriveType(CFSTR pathName) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + return GetDriveType(fs2fas(pathName)); + } + else + #endif + { + return GetDriveTypeW(fs2us(pathName)); + } +} + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0400 +// GetDiskFreeSpaceEx requires Windows95-OSR2, NT4 +#define Z7_USE_DYN_GetDiskFreeSpaceEx +#endif + +#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx +typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExA)( + LPCSTR lpDirectoryName, // directory name + PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller + PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk + PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk +); + +typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExW)( + LPCWSTR lpDirectoryName, // directory name + PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller + PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk + PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk +); +#endif + +bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize) +{ + DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters; + bool sizeIsDetected = false; + #ifndef _UNICODE + if (!g_IsNT) + { +#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx + const + Func_GetDiskFreeSpaceExA f = Z7_GET_PROC_ADDRESS( + Func_GetDiskFreeSpaceExA, GetModuleHandle(TEXT("kernel32.dll")), + "GetDiskFreeSpaceExA"); + if (f) +#endif + { + ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2; + sizeIsDetected = BOOLToBool( +#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx + f +#else + GetDiskFreeSpaceExA +#endif + (fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2)); + totalSize = totalSize2.QuadPart; + freeSize = freeSize2.QuadPart; + } + if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters)) + return false; + } + else + #endif + { +#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx + const + Func_GetDiskFreeSpaceExW f = Z7_GET_PROC_ADDRESS( + Func_GetDiskFreeSpaceExW, GetModuleHandle(TEXT("kernel32.dll")), + "GetDiskFreeSpaceExW"); + if (f) +#endif + { + ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2; + sizeIsDetected = BOOLToBool( +#ifdef Z7_USE_DYN_GetDiskFreeSpaceEx + f +#else + GetDiskFreeSpaceExW +#endif + (fs2us(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2)); + totalSize = totalSize2.QuadPart; + freeSize = freeSize2.QuadPart; + } + if (!::GetDiskFreeSpaceW(fs2us(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters)) + return false; + } + clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster; + if (!sizeIsDetected) + { + totalSize = clusterSize * (UInt64)numClusters; + freeSize = clusterSize * (UInt64)numFreeClusters; + } + return true; +} + +#endif + +/* +bool Is_File_LimitedBy_4GB(CFSTR _path, bool &isFsDetected) +{ + isFsDetected = false; + FString path (_path); + path.DeleteFrom(NName::GetRootPrefixSize(path)); + // GetVolumeInformation supports super paths. + // NName::If_IsSuperPath_RemoveSuperPrefix(path); + if (!path.IsEmpty()) + { + DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags; + UString volName, fileSystemName; + if (MyGetVolumeInformation(path, volName, + &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags, + fileSystemName)) + { + isFsDetected = true; + if (fileSystemName.IsPrefixedBy_Ascii_NoCase("fat")) + return true; + } + } + return false; +} +*/ + +}}} + +#endif diff --git a/CPP/Windows/FileSystem.h b/CPP/Windows/FileSystem.h index 3e404d6ef..9f9e399ce 100644 --- a/CPP/Windows/FileSystem.h +++ b/CPP/Windows/FileSystem.h @@ -1,31 +1,31 @@ -// Windows/FileSystem.h - -#ifndef ZIP7_INC_WINDOWS_FILE_SYSTEM_H -#define ZIP7_INC_WINDOWS_FILE_SYSTEM_H - -#include "../Common/MyString.h" -#include "../Common/MyTypes.h" - -namespace NWindows { -namespace NFile { -namespace NSystem { - -#ifdef _WIN32 - -bool MyGetVolumeInformation( - CFSTR rootPath , - UString &volumeName, - LPDWORD volumeSerialNumber, - LPDWORD maximumComponentLength, - LPDWORD fileSystemFlags, - UString &fileSystemName); - -UINT MyGetDriveType(CFSTR pathName); - -bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); - -#endif - -}}} - -#endif +// Windows/FileSystem.h + +#ifndef ZIP7_INC_WINDOWS_FILE_SYSTEM_H +#define ZIP7_INC_WINDOWS_FILE_SYSTEM_H + +#include "../Common/MyString.h" +#include "../Common/MyTypes.h" + +namespace NWindows { +namespace NFile { +namespace NSystem { + +#ifdef _WIN32 + +bool MyGetVolumeInformation( + CFSTR rootPath , + UString &volumeName, + LPDWORD volumeSerialNumber, + LPDWORD maximumComponentLength, + LPDWORD fileSystemFlags, + UString &fileSystemName); + +UINT MyGetDriveType(CFSTR pathName); + +bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); + +#endif + +}}} + +#endif diff --git a/CPP/Windows/Handle.h b/CPP/Windows/Handle.h index eeb83c211..6ae09ecf5 100644 --- a/CPP/Windows/Handle.h +++ b/CPP/Windows/Handle.h @@ -1,39 +1,39 @@ -// Windows/Handle.h - -#ifndef ZIP7_INC_WINDOWS_HANDLE_H -#define ZIP7_INC_WINDOWS_HANDLE_H - -#include "../Common/MyWindows.h" - -namespace NWindows { - -class CHandle MY_UNCOPYABLE -{ -protected: - HANDLE _handle; -public: - operator HANDLE() { return _handle; } - CHandle(): _handle(NULL) {} - ~CHandle() { Close(); } - bool IsCreated() const { return (_handle != NULL); } - bool Close() - { - if (_handle == NULL) - return true; - if (!::CloseHandle(_handle)) - return false; - _handle = NULL; - return true; - } - void Attach(HANDLE handle) { _handle = handle; } - HANDLE Detach() - { - const HANDLE handle = _handle; - _handle = NULL; - return handle; - } -}; - -} - -#endif +// Windows/Handle.h + +#ifndef ZIP7_INC_WINDOWS_HANDLE_H +#define ZIP7_INC_WINDOWS_HANDLE_H + +#include "../Common/MyWindows.h" + +namespace NWindows { + +class CHandle MY_UNCOPYABLE +{ +protected: + HANDLE _handle; +public: + operator HANDLE() { return _handle; } + CHandle(): _handle(NULL) {} + ~CHandle() { Close(); } + bool IsCreated() const { return (_handle != NULL); } + bool Close() + { + if (_handle == NULL) + return true; + if (!::CloseHandle(_handle)) + return false; + _handle = NULL; + return true; + } + void Attach(HANDLE handle) { _handle = handle; } + HANDLE Detach() + { + const HANDLE handle = _handle; + _handle = NULL; + return handle; + } +}; + +} + +#endif diff --git a/CPP/Windows/MemoryGlobal.cpp b/CPP/Windows/MemoryGlobal.cpp index 7e2d3de3a..2a22394b3 100644 --- a/CPP/Windows/MemoryGlobal.cpp +++ b/CPP/Windows/MemoryGlobal.cpp @@ -1,36 +1,36 @@ -// Windows/MemoryGlobal.cpp - -#include "StdAfx.h" - -#include "MemoryGlobal.h" - -namespace NWindows { -namespace NMemory { - -bool CGlobal::Alloc(UINT flags, SIZE_T size) throw() -{ - HGLOBAL newBlock = ::GlobalAlloc(flags, size); - if (newBlock == NULL) - return false; - _global = newBlock; - return true; -} - -bool CGlobal::Free() throw() -{ - if (_global == NULL) - return true; - _global = ::GlobalFree(_global); - return (_global == NULL); -} - -bool CGlobal::ReAlloc(SIZE_T size) throw() -{ - HGLOBAL newBlock = ::GlobalReAlloc(_global, size, GMEM_MOVEABLE); - if (newBlock == NULL) - return false; - _global = newBlock; - return true; -} - -}} +// Windows/MemoryGlobal.cpp + +#include "StdAfx.h" + +#include "MemoryGlobal.h" + +namespace NWindows { +namespace NMemory { + +bool CGlobal::Alloc(UINT flags, SIZE_T size) throw() +{ + HGLOBAL newBlock = ::GlobalAlloc(flags, size); + if (newBlock == NULL) + return false; + _global = newBlock; + return true; +} + +bool CGlobal::Free() throw() +{ + if (_global == NULL) + return true; + _global = ::GlobalFree(_global); + return (_global == NULL); +} + +bool CGlobal::ReAlloc(SIZE_T size) throw() +{ + HGLOBAL newBlock = ::GlobalReAlloc(_global, size, GMEM_MOVEABLE); + if (newBlock == NULL) + return false; + _global = newBlock; + return true; +} + +}} diff --git a/CPP/Windows/MemoryGlobal.h b/CPP/Windows/MemoryGlobal.h index f9544aa86..685259158 100644 --- a/CPP/Windows/MemoryGlobal.h +++ b/CPP/Windows/MemoryGlobal.h @@ -1,55 +1,55 @@ -// Windows/MemoryGlobal.h - -#ifndef ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H -#define ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H - -#include "../Common/MyWindows.h" - -namespace NWindows { -namespace NMemory { - -class CGlobal -{ - HGLOBAL _global; -public: - CGlobal(): _global(NULL) {} - ~CGlobal() { Free(); } - operator HGLOBAL() const { return _global; } - void Attach(HGLOBAL hGlobal) - { - Free(); - _global = hGlobal; - } - HGLOBAL Detach() - { - const HGLOBAL h = _global; - _global = NULL; - return h; - } - bool Alloc(UINT flags, SIZE_T size) throw(); - bool Free() throw(); - LPVOID Lock() const { return GlobalLock(_global); } - void Unlock() const { GlobalUnlock(_global); } - bool ReAlloc(SIZE_T size) throw(); -}; - -class CGlobalLock -{ - HGLOBAL _global; - LPVOID _ptr; -public: - LPVOID GetPointer() const { return _ptr; } - CGlobalLock(HGLOBAL hGlobal): _global(hGlobal) - { - _ptr = GlobalLock(hGlobal); - } - ~CGlobalLock() - { - if (_ptr) - GlobalUnlock(_global); - } -}; - -}} - -#endif +// Windows/MemoryGlobal.h + +#ifndef ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H +#define ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H + +#include "../Common/MyWindows.h" + +namespace NWindows { +namespace NMemory { + +class CGlobal +{ + HGLOBAL _global; +public: + CGlobal(): _global(NULL) {} + ~CGlobal() { Free(); } + operator HGLOBAL() const { return _global; } + void Attach(HGLOBAL hGlobal) + { + Free(); + _global = hGlobal; + } + HGLOBAL Detach() + { + const HGLOBAL h = _global; + _global = NULL; + return h; + } + bool Alloc(UINT flags, SIZE_T size) throw(); + bool Free() throw(); + LPVOID Lock() const { return GlobalLock(_global); } + void Unlock() const { GlobalUnlock(_global); } + bool ReAlloc(SIZE_T size) throw(); +}; + +class CGlobalLock +{ + HGLOBAL _global; + LPVOID _ptr; +public: + LPVOID GetPointer() const { return _ptr; } + CGlobalLock(HGLOBAL hGlobal): _global(hGlobal) + { + _ptr = GlobalLock(hGlobal); + } + ~CGlobalLock() + { + if (_ptr) + GlobalUnlock(_global); + } +}; + +}} + +#endif diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp index 7f504d17a..bc2d7c713 100644 --- a/CPP/Windows/MemoryLock.cpp +++ b/CPP/Windows/MemoryLock.cpp @@ -1,127 +1,127 @@ -// Windows/MemoryLock.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#include "MemoryLock.h" - -namespace NWindows { -namespace NSecurity { - -#ifndef UNDER_CE - -#ifdef _UNICODE -#define MY_FUNC_SELECT(f) :: f -#else -#define MY_FUNC_SELECT(f) my_ ## f -extern "C" { -typedef BOOL (WINAPI * Func_OpenProcessToken)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); -typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid); -typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges, - PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); -} - -#define GET_PROC_ADDR(fff, name) \ - const Func_ ## fff my_ ## fff = Z7_GET_PROC_ADDRESS( \ - Func_ ## fff, hModule, name); -#endif - -bool EnablePrivilege(LPCTSTR privilegeName, bool enable) -{ - bool res = false; - - #ifndef _UNICODE - - const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll")); - if (!hModule) - return false; - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - - GET_PROC_ADDR( - OpenProcessToken, - "OpenProcessToken") - GET_PROC_ADDR( - LookupPrivilegeValue, - "LookupPrivilegeValueA") - GET_PROC_ADDR( - AdjustTokenPrivileges, - "AdjustTokenPrivileges") - - if (my_OpenProcessToken && - my_AdjustTokenPrivileges && - my_LookupPrivilegeValue) - - #endif - - { - HANDLE token; - if (MY_FUNC_SELECT(OpenProcessToken)(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) - { - TOKEN_PRIVILEGES tp; - if (MY_FUNC_SELECT(LookupPrivilegeValue)(NULL, privilegeName, &(tp.Privileges[0].Luid))) - { - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0); - if (MY_FUNC_SELECT(AdjustTokenPrivileges)(token, FALSE, &tp, 0, NULL, NULL)) - res = (GetLastError() == ERROR_SUCCESS); - } - ::CloseHandle(token); - } - } - - #ifndef _UNICODE - - ::FreeLibrary(hModule); - - #endif - - return res; -} - - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); - -/* - We suppose that Window 10 works incorrectly with "Large Pages" at: - - Windows 10 1703 (15063) : incorrect allocating after VirtualFree() - - Windows 10 1709 (16299) : incorrect allocating after VirtualFree() - - Windows 10 1809 (17763) : the failures for blocks of 1 GiB and larger, - if CPU doesn't support 1 GB pages. - Windows 10 1903 (18362) probably works correctly. -*/ - -unsigned Get_LargePages_RiskLevel() -{ - OSVERSIONINFOEXW vi; - const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); - if (!ntdll) - return 0; - const - Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS( - Func_RtlGetVersion, ntdll, - "RtlGetVersion"); - if (!func) - return 0; - func(&vi); - if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) - return 0; - if (vi.dwMajorVersion + vi.dwMinorVersion != 10) - return 0; - if (vi.dwBuildNumber <= 16299) - return 1; - - #ifdef MY_CPU_X86_OR_AMD64 - if (vi.dwBuildNumber < 18362 && !CPU_IsSupported_PageGB()) - return 1; - #endif - - return 0; -} - -#endif - -}} +// Windows/MemoryLock.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#include "MemoryLock.h" + +namespace NWindows { +namespace NSecurity { + +#ifndef UNDER_CE + +#ifdef _UNICODE +#define MY_FUNC_SELECT(f) :: f +#else +#define MY_FUNC_SELECT(f) my_ ## f +extern "C" { +typedef BOOL (WINAPI * Func_OpenProcessToken)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); +typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid); +typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges, + PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); +} + +#define GET_PROC_ADDR(fff, name) \ + const Func_ ## fff my_ ## fff = Z7_GET_PROC_ADDRESS( \ + Func_ ## fff, hModule, name); +#endif + +bool EnablePrivilege(LPCTSTR privilegeName, bool enable) +{ + bool res = false; + + #ifndef _UNICODE + + const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll")); + if (!hModule) + return false; + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + + GET_PROC_ADDR( + OpenProcessToken, + "OpenProcessToken") + GET_PROC_ADDR( + LookupPrivilegeValue, + "LookupPrivilegeValueA") + GET_PROC_ADDR( + AdjustTokenPrivileges, + "AdjustTokenPrivileges") + + if (my_OpenProcessToken && + my_AdjustTokenPrivileges && + my_LookupPrivilegeValue) + + #endif + + { + HANDLE token; + if (MY_FUNC_SELECT(OpenProcessToken)(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) + { + TOKEN_PRIVILEGES tp; + if (MY_FUNC_SELECT(LookupPrivilegeValue)(NULL, privilegeName, &(tp.Privileges[0].Luid))) + { + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0); + if (MY_FUNC_SELECT(AdjustTokenPrivileges)(token, FALSE, &tp, 0, NULL, NULL)) + res = (GetLastError() == ERROR_SUCCESS); + } + ::CloseHandle(token); + } + } + + #ifndef _UNICODE + + ::FreeLibrary(hModule); + + #endif + + return res; +} + + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); + +/* + We suppose that Window 10 works incorrectly with "Large Pages" at: + - Windows 10 1703 (15063) : incorrect allocating after VirtualFree() + - Windows 10 1709 (16299) : incorrect allocating after VirtualFree() + - Windows 10 1809 (17763) : the failures for blocks of 1 GiB and larger, + if CPU doesn't support 1 GB pages. + Windows 10 1903 (18362) probably works correctly. +*/ + +unsigned Get_LargePages_RiskLevel() +{ + OSVERSIONINFOEXW vi; + const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); + if (!ntdll) + return 0; + const + Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS( + Func_RtlGetVersion, ntdll, + "RtlGetVersion"); + if (!func) + return 0; + func(&vi); + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) + return 0; + if (vi.dwMajorVersion + vi.dwMinorVersion != 10) + return 0; + if (vi.dwBuildNumber <= 16299) + return 1; + + #ifdef MY_CPU_X86_OR_AMD64 + if (vi.dwBuildNumber < 18362 && !CPU_IsSupported_PageGB()) + return 1; + #endif + + return 0; +} + +#endif + +}} diff --git a/CPP/Windows/MemoryLock.h b/CPP/Windows/MemoryLock.h index 49528f97a..2b850029f 100644 --- a/CPP/Windows/MemoryLock.h +++ b/CPP/Windows/MemoryLock.h @@ -1,40 +1,40 @@ -// Windows/MemoryLock.h - -#ifndef ZIP7_INC_WINDOWS_MEMORY_LOCK_H -#define ZIP7_INC_WINDOWS_MEMORY_LOCK_H - -#include "../Common/MyWindows.h" - -namespace NWindows { -namespace NSecurity { - -#ifndef UNDER_CE - -bool EnablePrivilege(LPCTSTR privilegeName, bool enable = true); - -inline bool EnablePrivilege_LockMemory(bool enable = true) -{ - return EnablePrivilege(SE_LOCK_MEMORY_NAME, enable); -} - -inline void EnablePrivilege_SymLink() -{ - /* Probably we do not to set any Privilege for junction points. - But we need them for Symbolic links */ - NSecurity::EnablePrivilege(SE_RESTORE_NAME); - - /* Probably we need only SE_RESTORE_NAME, but there is also - SE_CREATE_SYMBOLIC_LINK_NAME. So we set it also. Do we need it? */ - - NSecurity::EnablePrivilege(TEXT("SeCreateSymbolicLinkPrivilege")); // SE_CREATE_SYMBOLIC_LINK_NAME - - // Do we need to set SE_BACKUP_NAME ? -} - -unsigned Get_LargePages_RiskLevel(); - -#endif - -}} - -#endif +// Windows/MemoryLock.h + +#ifndef ZIP7_INC_WINDOWS_MEMORY_LOCK_H +#define ZIP7_INC_WINDOWS_MEMORY_LOCK_H + +#include "../Common/MyWindows.h" + +namespace NWindows { +namespace NSecurity { + +#ifndef UNDER_CE + +bool EnablePrivilege(LPCTSTR privilegeName, bool enable = true); + +inline bool EnablePrivilege_LockMemory(bool enable = true) +{ + return EnablePrivilege(SE_LOCK_MEMORY_NAME, enable); +} + +inline void EnablePrivilege_SymLink() +{ + /* Probably we do not to set any Privilege for junction points. + But we need them for Symbolic links */ + NSecurity::EnablePrivilege(SE_RESTORE_NAME); + + /* Probably we need only SE_RESTORE_NAME, but there is also + SE_CREATE_SYMBOLIC_LINK_NAME. So we set it also. Do we need it? */ + + NSecurity::EnablePrivilege(TEXT("SeCreateSymbolicLinkPrivilege")); // SE_CREATE_SYMBOLIC_LINK_NAME + + // Do we need to set SE_BACKUP_NAME ? +} + +unsigned Get_LargePages_RiskLevel(); + +#endif + +}} + +#endif diff --git a/CPP/Windows/Menu.cpp b/CPP/Windows/Menu.cpp index 600e32a84..af54c6687 100644 --- a/CPP/Windows/Menu.cpp +++ b/CPP/Windows/Menu.cpp @@ -1,265 +1,265 @@ -// Windows/Menu.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif -#include "Menu.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { - -/* -structures - MENUITEMINFOA - MENUITEMINFOW -contain additional member: - #if (WINVER >= 0x0500) - HBITMAP hbmpItem; - #endif -If we compile the source code with (WINVER >= 0x0500), some functions -will not work at NT4, if cbSize is set as sizeof(MENUITEMINFO). -So we use size of old version of structure in some conditions. -Win98 probably supports full structure including hbmpItem. - -We have 2 ways to get/set string in menu item: -win95/NT4: we must use MIIM_TYPE only. - MIIM_TYPE : Retrieves or sets the fType and dwTypeData members. -win98/win2000: there are new flags that can be used instead of MIIM_TYPE: - MIIM_FTYPE : Retrieves or sets the fType member. - MIIM_STRING : Retrieves or sets the dwTypeData member. - -Windows versions probably support MIIM_TYPE flag, if we set MENUITEMINFO::cbSize -as sizeof of old (small) MENUITEMINFO that doesn't include (hbmpItem) field. -But do all Windows versions support old MIIM_TYPE flag, if we use -MENUITEMINFO::cbSize as sizeof of new (big) MENUITEMINFO including (hbmpItem) field ? -win10 probably supports any combination of small/big (cbSize) and old/new MIIM_TYPE/MIIM_STRING. -*/ - -#if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) - #ifndef _UNICODE - #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA) - #endif - #define my_compatib_MENUITEMINFOW_size sizeof(MENUITEMINFOW) -#else - #define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0)) - #ifndef _UNICODE - #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) - #endif - #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) -#if defined(__clang__) && __clang_major__ >= 13 -// error : performing pointer subtraction with a null pointer may have undefined behavior -#pragma GCC diagnostic ignored "-Wnull-pointer-subtraction" -#endif -#endif - - -#define COPY_MENUITEM_field(d, s, name) \ - d.name = s.name; - -#define COPY_MENUITEM_fields(d, s) \ - COPY_MENUITEM_field(d, s, fMask) \ - COPY_MENUITEM_field(d, s, fType) \ - COPY_MENUITEM_field(d, s, fState) \ - COPY_MENUITEM_field(d, s, wID) \ - COPY_MENUITEM_field(d, s, hSubMenu) \ - COPY_MENUITEM_field(d, s, hbmpChecked) \ - COPY_MENUITEM_field(d, s, hbmpUnchecked) \ - COPY_MENUITEM_field(d, s, dwItemData) \ - -static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) -{ - ZeroMemory(&si, sizeof(si)); - si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); - COPY_MENUITEM_fields(si, item) -} - -#ifndef _UNICODE -static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si) -{ - ZeroMemory(&si, sizeof(si)); - si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); - COPY_MENUITEM_fields(si, item) -} -#endif - -static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) -{ - COPY_MENUITEM_fields(item, si) -} - -#ifndef _UNICODE -static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) -{ - COPY_MENUITEM_fields(item, si) -} -#endif - - -bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const -{ - item.StringValue.Empty(); - const unsigned kMaxSize = 512; - #ifndef _UNICODE - if (!g_IsNT) - { - MENUITEMINFOA si; - ConvertItemToSysForm(item, si); - const bool isString = item.IsString(); - unsigned bufSize = kMaxSize; - AString a; - if (isString) - { - si.cch = bufSize; - si.dwTypeData = a.GetBuf(bufSize); - } - bool res = GetItemInfo(itemIndex, byPosition, &si); - if (isString) - a.ReleaseBuf_CalcLen(bufSize); - if (!res) - return false; - { - if (isString && si.cch >= bufSize - 1) - { - si.dwTypeData = NULL; - res = GetItemInfo(itemIndex, byPosition, &si); - if (!res) - return false; - si.cch++; - bufSize = si.cch; - si.dwTypeData = a.GetBuf(bufSize); - res = GetItemInfo(itemIndex, byPosition, &si); - a.ReleaseBuf_CalcLen(bufSize); - if (!res) - return false; - } - ConvertItemToMyForm(si, item); - if (isString) - item.StringValue = GetUnicodeString(a); - return true; - } - } - else - #endif - { - wchar_t s[kMaxSize + 1]; - s[0] = 0; - MENUITEMINFOW si; - ConvertItemToSysForm(item, si); - const bool isString = item.IsString(); - unsigned bufSize = kMaxSize; - if (isString) - { - si.cch = bufSize; - si.dwTypeData = s; - } - bool res = GetItemInfo(itemIndex, byPosition, &si); - if (!res) - return false; - if (isString) - { - s[Z7_ARRAY_SIZE(s) - 1] = 0; - item.StringValue = s; - if (si.cch >= bufSize - 1) - { - si.dwTypeData = NULL; - res = GetItemInfo(itemIndex, byPosition, &si); - if (!res) - return false; - si.cch++; - bufSize = si.cch; - si.dwTypeData = item.StringValue.GetBuf(bufSize); - res = GetItemInfo(itemIndex, byPosition, &si); - item.StringValue.ReleaseBuf_CalcLen(bufSize); - if (!res) - return false; - } - // if (item.StringValue.Len() != si.cch) throw 123; // for debug - } - ConvertItemToMyForm(si, item); - return true; - } -} - - -bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - MENUITEMINFOA si; - ConvertItemToSysForm(item, si); - AString s; - if (item.IsString()) - { - s = GetSystemString(item.StringValue); - si.dwTypeData = s.Ptr_non_const(); - } - return SetItemInfo(itemIndex, byPosition, &si); - } - else - #endif - { - MENUITEMINFOW si; - ConvertItemToSysForm(item, si); - if (item.IsString()) - si.dwTypeData = item.StringValue.Ptr_non_const(); - return SetItemInfo(itemIndex, byPosition, &si); - } -} - - -bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - MENUITEMINFOA si; - ConvertItemToSysForm(item, si); - AString s; - if (item.IsString()) - { - s = GetSystemString(item.StringValue); - si.dwTypeData = s.Ptr_non_const(); - } - return InsertItem(itemIndex, byPosition, &si); - } - else - #endif - { - MENUITEMINFOW si; - ConvertItemToSysForm(item, si); - if (item.IsString()) - si.dwTypeData = item.StringValue.Ptr_non_const(); - #ifdef UNDER_CE - UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; - UINT_PTR id = item.wID; - if ((item.fMask & MIIM_SUBMENU) != 0) - { - flags |= MF_POPUP; - id = (UINT_PTR)item.hSubMenu; - } - if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) - return false; - return SetItemInfo(itemIndex, byPosition, &si); - #else - return InsertItem(itemIndex, byPosition, &si); - #endif - } -} - -#ifndef _UNICODE -bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem) -{ - if (g_IsNT) - return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem)); - else - return AppendItem(flags, newItemID, GetSystemString(newItem)); -} -#endif - -} +// Windows/Menu.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif +#include "Menu.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +/* +structures + MENUITEMINFOA + MENUITEMINFOW +contain additional member: + #if (WINVER >= 0x0500) + HBITMAP hbmpItem; + #endif +If we compile the source code with (WINVER >= 0x0500), some functions +will not work at NT4, if cbSize is set as sizeof(MENUITEMINFO). +So we use size of old version of structure in some conditions. +Win98 probably supports full structure including hbmpItem. + +We have 2 ways to get/set string in menu item: +win95/NT4: we must use MIIM_TYPE only. + MIIM_TYPE : Retrieves or sets the fType and dwTypeData members. +win98/win2000: there are new flags that can be used instead of MIIM_TYPE: + MIIM_FTYPE : Retrieves or sets the fType member. + MIIM_STRING : Retrieves or sets the dwTypeData member. + +Windows versions probably support MIIM_TYPE flag, if we set MENUITEMINFO::cbSize +as sizeof of old (small) MENUITEMINFO that doesn't include (hbmpItem) field. +But do all Windows versions support old MIIM_TYPE flag, if we use +MENUITEMINFO::cbSize as sizeof of new (big) MENUITEMINFO including (hbmpItem) field ? +win10 probably supports any combination of small/big (cbSize) and old/new MIIM_TYPE/MIIM_STRING. +*/ + +#if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) + #ifndef _UNICODE + #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA) + #endif + #define my_compatib_MENUITEMINFOW_size sizeof(MENUITEMINFOW) +#else + #define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0)) + #ifndef _UNICODE + #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) + #endif + #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) +#if defined(__clang__) && __clang_major__ >= 13 +// error : performing pointer subtraction with a null pointer may have undefined behavior +#pragma GCC diagnostic ignored "-Wnull-pointer-subtraction" +#endif +#endif + + +#define COPY_MENUITEM_field(d, s, name) \ + d.name = s.name; + +#define COPY_MENUITEM_fields(d, s) \ + COPY_MENUITEM_field(d, s, fMask) \ + COPY_MENUITEM_field(d, s, fType) \ + COPY_MENUITEM_field(d, s, fState) \ + COPY_MENUITEM_field(d, s, wID) \ + COPY_MENUITEM_field(d, s, hSubMenu) \ + COPY_MENUITEM_field(d, s, hbmpChecked) \ + COPY_MENUITEM_field(d, s, hbmpUnchecked) \ + COPY_MENUITEM_field(d, s, dwItemData) \ + +static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si) +{ + ZeroMemory(&si, sizeof(si)); + si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si); + COPY_MENUITEM_fields(si, item) +} + +#ifndef _UNICODE +static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si) +{ + ZeroMemory(&si, sizeof(si)); + si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si); + COPY_MENUITEM_fields(si, item) +} +#endif + +static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item) +{ + COPY_MENUITEM_fields(item, si) +} + +#ifndef _UNICODE +static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item) +{ + COPY_MENUITEM_fields(item, si) +} +#endif + + +bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const +{ + item.StringValue.Empty(); + const unsigned kMaxSize = 512; + #ifndef _UNICODE + if (!g_IsNT) + { + MENUITEMINFOA si; + ConvertItemToSysForm(item, si); + const bool isString = item.IsString(); + unsigned bufSize = kMaxSize; + AString a; + if (isString) + { + si.cch = bufSize; + si.dwTypeData = a.GetBuf(bufSize); + } + bool res = GetItemInfo(itemIndex, byPosition, &si); + if (isString) + a.ReleaseBuf_CalcLen(bufSize); + if (!res) + return false; + { + if (isString && si.cch >= bufSize - 1) + { + si.dwTypeData = NULL; + res = GetItemInfo(itemIndex, byPosition, &si); + if (!res) + return false; + si.cch++; + bufSize = si.cch; + si.dwTypeData = a.GetBuf(bufSize); + res = GetItemInfo(itemIndex, byPosition, &si); + a.ReleaseBuf_CalcLen(bufSize); + if (!res) + return false; + } + ConvertItemToMyForm(si, item); + if (isString) + item.StringValue = GetUnicodeString(a); + return true; + } + } + else + #endif + { + wchar_t s[kMaxSize + 1]; + s[0] = 0; + MENUITEMINFOW si; + ConvertItemToSysForm(item, si); + const bool isString = item.IsString(); + unsigned bufSize = kMaxSize; + if (isString) + { + si.cch = bufSize; + si.dwTypeData = s; + } + bool res = GetItemInfo(itemIndex, byPosition, &si); + if (!res) + return false; + if (isString) + { + s[Z7_ARRAY_SIZE(s) - 1] = 0; + item.StringValue = s; + if (si.cch >= bufSize - 1) + { + si.dwTypeData = NULL; + res = GetItemInfo(itemIndex, byPosition, &si); + if (!res) + return false; + si.cch++; + bufSize = si.cch; + si.dwTypeData = item.StringValue.GetBuf(bufSize); + res = GetItemInfo(itemIndex, byPosition, &si); + item.StringValue.ReleaseBuf_CalcLen(bufSize); + if (!res) + return false; + } + // if (item.StringValue.Len() != si.cch) throw 123; // for debug + } + ConvertItemToMyForm(si, item); + return true; + } +} + + +bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + MENUITEMINFOA si; + ConvertItemToSysForm(item, si); + AString s; + if (item.IsString()) + { + s = GetSystemString(item.StringValue); + si.dwTypeData = s.Ptr_non_const(); + } + return SetItemInfo(itemIndex, byPosition, &si); + } + else + #endif + { + MENUITEMINFOW si; + ConvertItemToSysForm(item, si); + if (item.IsString()) + si.dwTypeData = item.StringValue.Ptr_non_const(); + return SetItemInfo(itemIndex, byPosition, &si); + } +} + + +bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + MENUITEMINFOA si; + ConvertItemToSysForm(item, si); + AString s; + if (item.IsString()) + { + s = GetSystemString(item.StringValue); + si.dwTypeData = s.Ptr_non_const(); + } + return InsertItem(itemIndex, byPosition, &si); + } + else + #endif + { + MENUITEMINFOW si; + ConvertItemToSysForm(item, si); + if (item.IsString()) + si.dwTypeData = item.StringValue.Ptr_non_const(); + #ifdef UNDER_CE + UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; + UINT_PTR id = item.wID; + if ((item.fMask & MIIM_SUBMENU) != 0) + { + flags |= MF_POPUP; + id = (UINT_PTR)item.hSubMenu; + } + if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue)) + return false; + return SetItemInfo(itemIndex, byPosition, &si); + #else + return InsertItem(itemIndex, byPosition, &si); + #endif + } +} + +#ifndef _UNICODE +bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem) +{ + if (g_IsNT) + return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem)); + else + return AppendItem(flags, newItemID, GetSystemString(newItem)); +} +#endif + +} diff --git a/CPP/Windows/Menu.h b/CPP/Windows/Menu.h index 6f7ccd58c..e1de4c4b3 100644 --- a/CPP/Windows/Menu.h +++ b/CPP/Windows/Menu.h @@ -1,170 +1,170 @@ -// Windows/Menu.h - -#ifndef ZIP7_INC_WINDOWS_MENU_H -#define ZIP7_INC_WINDOWS_MENU_H - -#include "../Common/MyWindows.h" -#include "../Common/MyString.h" - -#include "Defs.h" - -namespace NWindows { - -#ifndef MIIM_STRING -#define MIIM_STRING 0x00000040 -#endif -/* -#ifndef MIIM_BITMAP -#define MIIM_BITMAP 0x00000080 -#endif -*/ -#ifndef MIIM_FTYPE -#define MIIM_FTYPE 0x00000100 -#endif - -struct CMenuItem -{ - UString StringValue; - UINT fMask; - UINT fType; - UINT fState; - UINT wID; - HMENU hSubMenu; - HBITMAP hbmpChecked; - HBITMAP hbmpUnchecked; - ULONG_PTR dwItemData; - // LPTSTR dwTypeData; - // UINT cch; - // HBITMAP hbmpItem; - bool IsString() const { return (fMask & (MIIM_TYPE | MIIM_STRING)) != 0; } - bool IsSeparator() const { return (fType == MFT_SEPARATOR); } - CMenuItem(): fMask(0), fType(0), fState(0), wID(0), - hSubMenu(NULL), hbmpChecked(NULL), hbmpUnchecked(NULL), dwItemData(0) {} -}; - -class CMenu -{ - HMENU _menu; -public: - CMenu(): _menu(NULL) {} - operator HMENU() const { return _menu; } - void Attach(HMENU menu) { _menu = menu; } - - HMENU Detach() - { - const HMENU menu = _menu; - _menu = NULL; - return menu; - } - - bool Create() - { - _menu = ::CreateMenu(); - return (_menu != NULL); - } - - bool CreatePopup() - { - _menu = ::CreatePopupMenu(); - return (_menu != NULL); - } - - bool Destroy() - { - if (!_menu) - return false; - return BOOLToBool(::DestroyMenu(Detach())); - } - - int GetItemCount() const - { - #ifdef UNDER_CE - for (unsigned i = 0;; i++) - { - CMenuItem item; - item.fMask = MIIM_STATE; - if (!GetItem(i, true, item)) - return (int)i; - } - #else - return GetMenuItemCount(_menu); - #endif - } - - HMENU GetSubMenu(int pos) const { return ::GetSubMenu(_menu, pos); } - #ifndef UNDER_CE - /* - bool GetItemString(UINT idItem, UINT flag, CSysString &result) - { - result.Empty(); - int len = ::GetMenuString(_menu, idItem, 0, 0, flag); - int len2 = ::GetMenuString(_menu, idItem, result.GetBuf(len + 2), len + 1, flag); - if (len > len2) - len = len2; - result.ReleaseBuf_CalcLen(len + 2); - return (len != 0); - } - */ - UINT GetItemID(int pos) const { return ::GetMenuItemID(_menu, pos); } - UINT GetItemState(UINT id, UINT flags) const { return ::GetMenuState(_menu, id, flags); } - #endif - - bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) const - { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) - { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - - bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem) - { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); } - - bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem) - { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); } - - #ifndef UNDER_CE - bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo) - { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - #endif - - bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); } - void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); } - void RemoveAllItems() { RemoveAllItemsFrom(0); } - - #ifndef _UNICODE - bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) const - { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) - { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) - { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } - bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem); - #endif - - bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const; - bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item); - bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item); - - int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); } - - bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags) - { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); } - - DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); } - DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); } - - BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); } -}; - -class CMenuDestroyer -{ - CMenu *_menu; -public: - CMenuDestroyer(CMenu &menu): _menu(&menu) {} - CMenuDestroyer(): _menu(NULL) {} - ~CMenuDestroyer() { if (_menu) _menu->Destroy(); } - void Attach(CMenu &menu) { _menu = &menu; } - void Disable() { _menu = NULL; } -}; - -} - -#endif +// Windows/Menu.h + +#ifndef ZIP7_INC_WINDOWS_MENU_H +#define ZIP7_INC_WINDOWS_MENU_H + +#include "../Common/MyWindows.h" +#include "../Common/MyString.h" + +#include "Defs.h" + +namespace NWindows { + +#ifndef MIIM_STRING +#define MIIM_STRING 0x00000040 +#endif +/* +#ifndef MIIM_BITMAP +#define MIIM_BITMAP 0x00000080 +#endif +*/ +#ifndef MIIM_FTYPE +#define MIIM_FTYPE 0x00000100 +#endif + +struct CMenuItem +{ + UString StringValue; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + HMENU hSubMenu; + HBITMAP hbmpChecked; + HBITMAP hbmpUnchecked; + ULONG_PTR dwItemData; + // LPTSTR dwTypeData; + // UINT cch; + // HBITMAP hbmpItem; + bool IsString() const { return (fMask & (MIIM_TYPE | MIIM_STRING)) != 0; } + bool IsSeparator() const { return (fType == MFT_SEPARATOR); } + CMenuItem(): fMask(0), fType(0), fState(0), wID(0), + hSubMenu(NULL), hbmpChecked(NULL), hbmpUnchecked(NULL), dwItemData(0) {} +}; + +class CMenu +{ + HMENU _menu; +public: + CMenu(): _menu(NULL) {} + operator HMENU() const { return _menu; } + void Attach(HMENU menu) { _menu = menu; } + + HMENU Detach() + { + const HMENU menu = _menu; + _menu = NULL; + return menu; + } + + bool Create() + { + _menu = ::CreateMenu(); + return (_menu != NULL); + } + + bool CreatePopup() + { + _menu = ::CreatePopupMenu(); + return (_menu != NULL); + } + + bool Destroy() + { + if (!_menu) + return false; + return BOOLToBool(::DestroyMenu(Detach())); + } + + int GetItemCount() const + { + #ifdef UNDER_CE + for (unsigned i = 0;; i++) + { + CMenuItem item; + item.fMask = MIIM_STATE; + if (!GetItem(i, true, item)) + return (int)i; + } + #else + return GetMenuItemCount(_menu); + #endif + } + + HMENU GetSubMenu(int pos) const { return ::GetSubMenu(_menu, pos); } + #ifndef UNDER_CE + /* + bool GetItemString(UINT idItem, UINT flag, CSysString &result) + { + result.Empty(); + int len = ::GetMenuString(_menu, idItem, 0, 0, flag); + int len2 = ::GetMenuString(_menu, idItem, result.GetBuf(len + 2), len + 1, flag); + if (len > len2) + len = len2; + result.ReleaseBuf_CalcLen(len + 2); + return (len != 0); + } + */ + UINT GetItemID(int pos) const { return ::GetMenuItemID(_menu, pos); } + UINT GetItemState(UINT id, UINT flags) const { return ::GetMenuState(_menu, id, flags); } + #endif + + bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) const + { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) + { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + + bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem) + { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); } + + bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem) + { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); } + + #ifndef UNDER_CE + bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo) + { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + #endif + + bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); } + void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); } + void RemoveAllItems() { RemoveAllItemsFrom(0); } + + #ifndef _UNICODE + bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) const + { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) + { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) + { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); } + bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem); + #endif + + bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const; + bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item); + bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item); + + int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); } + + bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags) + { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); } + + DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); } + DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); } + + BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); } +}; + +class CMenuDestroyer +{ + CMenu *_menu; +public: + CMenuDestroyer(CMenu &menu): _menu(&menu) {} + CMenuDestroyer(): _menu(NULL) {} + ~CMenuDestroyer() { if (_menu) _menu->Destroy(); } + void Attach(CMenu &menu) { _menu = &menu; } + void Disable() { _menu = NULL; } +}; + +} + +#endif diff --git a/CPP/Windows/NationalTime.cpp b/CPP/Windows/NationalTime.cpp index 75c3213de..d3c38de5c 100644 --- a/CPP/Windows/NationalTime.cpp +++ b/CPP/Windows/NationalTime.cpp @@ -1,37 +1,37 @@ -// Windows/NationalTime.cpp - -#include "StdAfx.h" - -#include "NationalTime.h" - -namespace NWindows { -namespace NNational { -namespace NTime { - -bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, - LPCTSTR format, CSysString &resultString) -{ - resultString.Empty(); - int numChars = ::GetTimeFormat(locale, flags, time, format, NULL, 0); - if (numChars == 0) - return false; - numChars = ::GetTimeFormat(locale, flags, time, format, - resultString.GetBuf((unsigned)numChars), numChars + 1); - resultString.ReleaseBuf_CalcLen((unsigned)numChars); - return (numChars != 0); -} - -bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, - LPCTSTR format, CSysString &resultString) -{ - resultString.Empty(); - int numChars = ::GetDateFormat(locale, flags, time, format, NULL, 0); - if (numChars == 0) - return false; - numChars = ::GetDateFormat(locale, flags, time, format, - resultString.GetBuf((unsigned)numChars), numChars + 1); - resultString.ReleaseBuf_CalcLen((unsigned)numChars); - return (numChars != 0); -} - -}}} +// Windows/NationalTime.cpp + +#include "StdAfx.h" + +#include "NationalTime.h" + +namespace NWindows { +namespace NNational { +namespace NTime { + +bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, + LPCTSTR format, CSysString &resultString) +{ + resultString.Empty(); + int numChars = ::GetTimeFormat(locale, flags, time, format, NULL, 0); + if (numChars == 0) + return false; + numChars = ::GetTimeFormat(locale, flags, time, format, + resultString.GetBuf((unsigned)numChars), numChars + 1); + resultString.ReleaseBuf_CalcLen((unsigned)numChars); + return (numChars != 0); +} + +bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, + LPCTSTR format, CSysString &resultString) +{ + resultString.Empty(); + int numChars = ::GetDateFormat(locale, flags, time, format, NULL, 0); + if (numChars == 0) + return false; + numChars = ::GetDateFormat(locale, flags, time, format, + resultString.GetBuf((unsigned)numChars), numChars + 1); + resultString.ReleaseBuf_CalcLen((unsigned)numChars); + return (numChars != 0); +} + +}}} diff --git a/CPP/Windows/NationalTime.h b/CPP/Windows/NationalTime.h index a5bdd3c0a..32ba479f2 100644 --- a/CPP/Windows/NationalTime.h +++ b/CPP/Windows/NationalTime.h @@ -1,20 +1,20 @@ -// Windows/NationalTime.h - -#ifndef ZIP7_INC_WINDOWS_NATIONAL_TIME_H -#define ZIP7_INC_WINDOWS_NATIONAL_TIME_H - -#include "../Common/MyString.h" - -namespace NWindows { -namespace NNational { -namespace NTime { - -bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, - LPCTSTR format, CSysString &resultString); - -bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, - LPCTSTR format, CSysString &resultString); - -}}} - -#endif +// Windows/NationalTime.h + +#ifndef ZIP7_INC_WINDOWS_NATIONAL_TIME_H +#define ZIP7_INC_WINDOWS_NATIONAL_TIME_H + +#include "../Common/MyString.h" + +namespace NWindows { +namespace NNational { +namespace NTime { + +bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, + LPCTSTR format, CSysString &resultString); + +bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time, + LPCTSTR format, CSysString &resultString); + +}}} + +#endif diff --git a/CPP/Windows/Net.cpp b/CPP/Windows/Net.cpp index 8ca3b6de6..0ac82d4ea 100644 --- a/CPP/Windows/Net.cpp +++ b/CPP/Windows/Net.cpp @@ -1,398 +1,398 @@ -// Windows/Net.cpp - -#include "StdAfx.h" - -#include "../Common/MyBuffer.h" - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif - -#include "Net.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -extern "C" -{ -#if !defined(WNetGetResourceParent) -// #if defined(Z7_OLD_WIN_SDK) -// #if (WINVER >= 0x0400) -DWORD APIENTRY WNetGetResourceParentA(IN LPNETRESOURCEA lpNetResource, - OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer); -DWORD APIENTRY WNetGetResourceParentW(IN LPNETRESOURCEW lpNetResource, - OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer); -#ifdef UNICODE -#define WNetGetResourceParent WNetGetResourceParentW -#else -#define WNetGetResourceParent WNetGetResourceParentA -#endif - -DWORD APIENTRY WNetGetResourceInformationA(IN LPNETRESOURCEA lpNetResource, - OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPSTR *lplpSystem); -DWORD APIENTRY WNetGetResourceInformationW(IN LPNETRESOURCEW lpNetResource, - OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPWSTR *lplpSystem); -#ifdef UNICODE -#define WNetGetResourceInformation WNetGetResourceInformationW -#else -#define WNetGetResourceInformation WNetGetResourceInformationA -#endif -// #endif // (WINVER >= 0x0400) -#endif -} - -namespace NWindows { -namespace NNet { - -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource) -{ - Close(); - const DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle); - _handleAllocated = (result == NO_ERROR); - return result; -} - -#ifndef _UNICODE -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource) -{ - Close(); - const DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle); - _handleAllocated = (result == NO_ERROR); - return result; -} -#endif - -static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srcString) -{ - defined = (srcString != NULL); - if (defined) - destString = srcString; - else - destString.Empty(); -} - -static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource) -{ - resource.Scope = netResource.dwScope; - resource.Type = netResource.dwType; - resource.DisplayType = netResource.dwDisplayType; - resource.Usage = netResource.dwUsage; - SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); - SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); - SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); - SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); -} - -static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString) -{ - if (defined) - *destString = srcString.Ptr_non_const(); - else - *destString = NULL; -} - -static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource) -{ - netResource.dwScope = resource.Scope; - netResource.dwType = resource.Type; - netResource.dwDisplayType = resource.DisplayType; - netResource.dwUsage = resource.Usage; - SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); - SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); - SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); - SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); -} - -#ifndef _UNICODE - -static void SetComplexString(bool &defined, UString &destString, LPCWSTR src) -{ - defined = (src != NULL); - if (defined) - destString = src; - else - destString.Empty(); -} - -static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource) -{ - resource.Scope = netResource.dwScope; - resource.Type = netResource.dwType; - resource.DisplayType = netResource.dwDisplayType; - resource.Usage = netResource.dwUsage; - SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); - SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); - SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); - SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); -} - -static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString) -{ - if (defined) - *destString = srcString.Ptr_non_const(); - else - *destString = NULL; -} - -static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource) -{ - netResource.dwScope = resource.Scope; - netResource.dwType = resource.Type; - netResource.dwDisplayType = resource.DisplayType; - netResource.dwUsage = resource.Usage; - SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); - SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); - SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); - SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); -} - -static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource) -{ - *(CResourceBase *)&resource = *(CResourceBase *)&resourceW; - resource.LocalName = GetSystemString(resourceW.LocalName); - resource.RemoteName = GetSystemString(resourceW.RemoteName); - resource.Comment = GetSystemString(resourceW.Comment); - resource.Provider = GetSystemString(resourceW.Provider); -} - -static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW) -{ - *(CResourceBase *)&resourceW = *(CResourceBase *)&resource; - resourceW.LocalName = GetUnicodeString(resource.LocalName); - resourceW.RemoteName = GetUnicodeString(resource.RemoteName); - resourceW.Comment = GetUnicodeString(resource.Comment); - resourceW.Provider = GetUnicodeString(resource.Provider); -} -#endif - -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource) -{ - NETRESOURCE netResource; - LPNETRESOURCE pointer = NULL; - if (resource) - { - ConvertCResourceToNETRESOURCE(*resource, netResource); - pointer = &netResource; - } - return Open(scope, type, usage, pointer); -} - -#ifndef _UNICODE -DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource) -{ - if (g_IsNT) - { - NETRESOURCEW netResource; - LPNETRESOURCEW pointer = NULL; - if (resource) - { - ConvertCResourceToNETRESOURCE(*resource, netResource); - pointer = &netResource; - } - return Open(scope, type, usage, pointer); - } - CResource resourceA; - CResource *pointer = NULL; - if (resource) - { - ConvertResourceWToResource(*resource, resourceA); - pointer = &resourceA; - } - return Open(scope, type, usage, pointer); -} -#endif - -DWORD CEnum::Close() -{ - if (!_handleAllocated) - return NO_ERROR; - const DWORD result = ::WNetCloseEnum(_handle); - _handleAllocated = (result != NO_ERROR); - return result; -} - -DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize); -} - -#ifndef _UNICODE -DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize); -} -#endif - -DWORD CEnum::Next(CResource &resource) -{ - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - DWORD numEntries = 1; - const DWORD result = Next(&numEntries, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - if (numEntries != 1) - return (DWORD)E_FAIL; - ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); - return result; -} - -#ifndef _UNICODE -DWORD CEnum::Next(CResourceW &resource) -{ - if (g_IsNT) - { - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - DWORD numEntries = 1; - const DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - if (numEntries != 1) - return (DWORD)E_FAIL; - ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); - return result; - } - CResource resourceA; - const DWORD result = Next(resourceA); - ConvertResourceToResourceW(resourceA, resource); - return result; -} -#endif - - -DWORD GetResourceParent(const CResource &resource, CResource &parentResource) -{ - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCE netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - const DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); - return result; -} - -#ifndef _UNICODE -DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource) -{ - if (g_IsNT) - { - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCEW netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - const DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize); - if (result != NO_ERROR) - return result; - ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); - return result; - } - CResource resourceA, parentResourceA; - ConvertResourceWToResource(resource, resourceA); - const DWORD result = GetResourceParent(resourceA, parentResourceA); - ConvertResourceToResourceW(parentResourceA, parentResource); - return result; -} -#endif - -DWORD GetResourceInformation(const CResource &resource, - CResource &destResource, CSysString &systemPathPart) -{ - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCE netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - LPTSTR lplpSystem; - const DWORD result = ::WNetGetResourceInformation(&netResource, - lpnrLocal, &bufferSize, &lplpSystem); - if (result != NO_ERROR) - return result; - if (lplpSystem != NULL) - systemPathPart = lplpSystem; - ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); - return result; -} - -#ifndef _UNICODE -DWORD GetResourceInformation(const CResourceW &resource, - CResourceW &destResource, UString &systemPathPart) -{ - if (g_IsNT) - { - const DWORD kBufferSize = 16384; - CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); - ZeroMemory(lpnrLocal, kBufferSize); - DWORD bufferSize = kBufferSize; - NETRESOURCEW netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - LPWSTR lplpSystem; - const DWORD result = ::WNetGetResourceInformationW(&netResource, - lpnrLocal, &bufferSize, &lplpSystem); - if (result != NO_ERROR) - return result; - if (lplpSystem != 0) - systemPathPart = lplpSystem; - ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); - return result; - } - CResource resourceA, destResourceA; - ConvertResourceWToResource(resource, resourceA); - AString systemPathPartA; - const DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA); - ConvertResourceToResourceW(destResourceA, destResource); - systemPathPart = GetUnicodeString(systemPathPartA); - return result; -} -#endif - -DWORD AddConnection2(const CResource &resource, - LPCTSTR password, LPCTSTR userName, DWORD flags) -{ - NETRESOURCE netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - return ::WNetAddConnection2(&netResource, - password, userName, flags); -} - -DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); - -#ifndef _UNICODE -DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags) -{ - if (g_IsNT) - { - NETRESOURCEW netResource; - ConvertCResourceToNETRESOURCE(resource, netResource); - return ::WNetAddConnection2W(&netResource,password, userName, flags); - } - CResource resourceA; - ConvertResourceWToResource(resource, resourceA); - const CSysString passwordA (GetSystemString(password)); - const CSysString userNameA (GetSystemString(userName)); - return AddConnection2(resourceA, - password ? (LPCTSTR)passwordA: 0, - userName ? (LPCTSTR)userNameA: 0, - flags); -} -#endif - -}} +// Windows/Net.cpp + +#include "StdAfx.h" + +#include "../Common/MyBuffer.h" + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#include "Net.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +extern "C" +{ +#if !defined(WNetGetResourceParent) +// #if defined(Z7_OLD_WIN_SDK) +// #if (WINVER >= 0x0400) +DWORD APIENTRY WNetGetResourceParentA(IN LPNETRESOURCEA lpNetResource, + OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer); +DWORD APIENTRY WNetGetResourceParentW(IN LPNETRESOURCEW lpNetResource, + OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer); +#ifdef UNICODE +#define WNetGetResourceParent WNetGetResourceParentW +#else +#define WNetGetResourceParent WNetGetResourceParentA +#endif + +DWORD APIENTRY WNetGetResourceInformationA(IN LPNETRESOURCEA lpNetResource, + OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPSTR *lplpSystem); +DWORD APIENTRY WNetGetResourceInformationW(IN LPNETRESOURCEW lpNetResource, + OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPWSTR *lplpSystem); +#ifdef UNICODE +#define WNetGetResourceInformation WNetGetResourceInformationW +#else +#define WNetGetResourceInformation WNetGetResourceInformationA +#endif +// #endif // (WINVER >= 0x0400) +#endif +} + +namespace NWindows { +namespace NNet { + +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource) +{ + Close(); + const DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle); + _handleAllocated = (result == NO_ERROR); + return result; +} + +#ifndef _UNICODE +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource) +{ + Close(); + const DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle); + _handleAllocated = (result == NO_ERROR); + return result; +} +#endif + +static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srcString) +{ + defined = (srcString != NULL); + if (defined) + destString = srcString; + else + destString.Empty(); +} + +static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource) +{ + resource.Scope = netResource.dwScope; + resource.Type = netResource.dwType; + resource.DisplayType = netResource.dwDisplayType; + resource.Usage = netResource.dwUsage; + SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); + SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); + SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); + SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); +} + +static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString) +{ + if (defined) + *destString = srcString.Ptr_non_const(); + else + *destString = NULL; +} + +static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource) +{ + netResource.dwScope = resource.Scope; + netResource.dwType = resource.Type; + netResource.dwDisplayType = resource.DisplayType; + netResource.dwUsage = resource.Usage; + SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); + SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); + SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); + SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); +} + +#ifndef _UNICODE + +static void SetComplexString(bool &defined, UString &destString, LPCWSTR src) +{ + defined = (src != NULL); + if (defined) + destString = src; + else + destString.Empty(); +} + +static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource) +{ + resource.Scope = netResource.dwScope; + resource.Type = netResource.dwType; + resource.DisplayType = netResource.dwDisplayType; + resource.Usage = netResource.dwUsage; + SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName); + SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName); + SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment); + SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider); +} + +static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString) +{ + if (defined) + *destString = srcString.Ptr_non_const(); + else + *destString = NULL; +} + +static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource) +{ + netResource.dwScope = resource.Scope; + netResource.dwType = resource.Type; + netResource.dwDisplayType = resource.DisplayType; + netResource.dwUsage = resource.Usage; + SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName); + SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName); + SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment); + SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider); +} + +static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource) +{ + *(CResourceBase *)&resource = *(CResourceBase *)&resourceW; + resource.LocalName = GetSystemString(resourceW.LocalName); + resource.RemoteName = GetSystemString(resourceW.RemoteName); + resource.Comment = GetSystemString(resourceW.Comment); + resource.Provider = GetSystemString(resourceW.Provider); +} + +static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW) +{ + *(CResourceBase *)&resourceW = *(CResourceBase *)&resource; + resourceW.LocalName = GetUnicodeString(resource.LocalName); + resourceW.RemoteName = GetUnicodeString(resource.RemoteName); + resourceW.Comment = GetUnicodeString(resource.Comment); + resourceW.Provider = GetUnicodeString(resource.Provider); +} +#endif + +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource) +{ + NETRESOURCE netResource; + LPNETRESOURCE pointer = NULL; + if (resource) + { + ConvertCResourceToNETRESOURCE(*resource, netResource); + pointer = &netResource; + } + return Open(scope, type, usage, pointer); +} + +#ifndef _UNICODE +DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource) +{ + if (g_IsNT) + { + NETRESOURCEW netResource; + LPNETRESOURCEW pointer = NULL; + if (resource) + { + ConvertCResourceToNETRESOURCE(*resource, netResource); + pointer = &netResource; + } + return Open(scope, type, usage, pointer); + } + CResource resourceA; + CResource *pointer = NULL; + if (resource) + { + ConvertResourceWToResource(*resource, resourceA); + pointer = &resourceA; + } + return Open(scope, type, usage, pointer); +} +#endif + +DWORD CEnum::Close() +{ + if (!_handleAllocated) + return NO_ERROR; + const DWORD result = ::WNetCloseEnum(_handle); + _handleAllocated = (result != NO_ERROR); + return result; +} + +DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize); +} + +#ifndef _UNICODE +DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize); +} +#endif + +DWORD CEnum::Next(CResource &resource) +{ + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + DWORD numEntries = 1; + const DWORD result = Next(&numEntries, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + if (numEntries != 1) + return (DWORD)E_FAIL; + ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); + return result; +} + +#ifndef _UNICODE +DWORD CEnum::Next(CResourceW &resource) +{ + if (g_IsNT) + { + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + DWORD numEntries = 1; + const DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + if (numEntries != 1) + return (DWORD)E_FAIL; + ConvertNETRESOURCEToCResource(lpnrLocal[0], resource); + return result; + } + CResource resourceA; + const DWORD result = Next(resourceA); + ConvertResourceToResourceW(resourceA, resource); + return result; +} +#endif + + +DWORD GetResourceParent(const CResource &resource, CResource &parentResource) +{ + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCE netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + const DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); + return result; +} + +#ifndef _UNICODE +DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource) +{ + if (g_IsNT) + { + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCEW netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + const DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize); + if (result != NO_ERROR) + return result; + ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource); + return result; + } + CResource resourceA, parentResourceA; + ConvertResourceWToResource(resource, resourceA); + const DWORD result = GetResourceParent(resourceA, parentResourceA); + ConvertResourceToResourceW(parentResourceA, parentResource); + return result; +} +#endif + +DWORD GetResourceInformation(const CResource &resource, + CResource &destResource, CSysString &systemPathPart) +{ + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCE netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + LPTSTR lplpSystem; + const DWORD result = ::WNetGetResourceInformation(&netResource, + lpnrLocal, &bufferSize, &lplpSystem); + if (result != NO_ERROR) + return result; + if (lplpSystem != NULL) + systemPathPart = lplpSystem; + ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); + return result; +} + +#ifndef _UNICODE +DWORD GetResourceInformation(const CResourceW &resource, + CResourceW &destResource, UString &systemPathPart) +{ + if (g_IsNT) + { + const DWORD kBufferSize = 16384; + CByteArr byteBuffer(kBufferSize); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); + ZeroMemory(lpnrLocal, kBufferSize); + DWORD bufferSize = kBufferSize; + NETRESOURCEW netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + LPWSTR lplpSystem; + const DWORD result = ::WNetGetResourceInformationW(&netResource, + lpnrLocal, &bufferSize, &lplpSystem); + if (result != NO_ERROR) + return result; + if (lplpSystem != 0) + systemPathPart = lplpSystem; + ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource); + return result; + } + CResource resourceA, destResourceA; + ConvertResourceWToResource(resource, resourceA); + AString systemPathPartA; + const DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA); + ConvertResourceToResourceW(destResourceA, destResource); + systemPathPart = GetUnicodeString(systemPathPartA); + return result; +} +#endif + +DWORD AddConnection2(const CResource &resource, + LPCTSTR password, LPCTSTR userName, DWORD flags) +{ + NETRESOURCE netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + return ::WNetAddConnection2(&netResource, + password, userName, flags); +} + +DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); + +#ifndef _UNICODE +DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags) +{ + if (g_IsNT) + { + NETRESOURCEW netResource; + ConvertCResourceToNETRESOURCE(resource, netResource); + return ::WNetAddConnection2W(&netResource,password, userName, flags); + } + CResource resourceA; + ConvertResourceWToResource(resource, resourceA); + const CSysString passwordA (GetSystemString(password)); + const CSysString userNameA (GetSystemString(userName)); + return AddConnection2(resourceA, + password ? (LPCTSTR)passwordA: 0, + userName ? (LPCTSTR)userNameA: 0, + flags); +} +#endif + +}} diff --git a/CPP/Windows/Net.h b/CPP/Windows/Net.h index 711760d36..a954bdb2c 100644 --- a/CPP/Windows/Net.h +++ b/CPP/Windows/Net.h @@ -1,87 +1,87 @@ -// Windows/Net.h - -#ifndef ZIP7_INC_WINDOWS_NET_H -#define ZIP7_INC_WINDOWS_NET_H - -#include "../Common/MyString.h" -#include "../Common/MyWindows.h" - -namespace NWindows { -namespace NNet { - -struct CResourceBase -{ - DWORD Scope; - DWORD Type; - DWORD DisplayType; - DWORD Usage; - bool LocalNameIsDefined; - bool RemoteNameIsDefined; - bool CommentIsDefined; - bool ProviderIsDefined; -}; - -struct CResource: public CResourceBase -{ - CSysString LocalName; - CSysString RemoteName; - CSysString Comment; - CSysString Provider; -}; - -#ifdef _UNICODE -typedef CResource CResourceW; -#else -struct CResourceW: public CResourceBase -{ - UString LocalName; - UString RemoteName; - UString Comment; - UString Provider; -}; -#endif - -class CEnum -{ - HANDLE _handle; - bool _handleAllocated; - DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource); - DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); - #ifndef _UNICODE - DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource); - DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); - #endif -protected: - bool IsHandleAllocated() const { return _handleAllocated; } -public: - CEnum(): _handleAllocated(false) {} - ~CEnum() { Close(); } - DWORD Close(); - DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource); - DWORD Next(CResource &resource); - #ifndef _UNICODE - DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource); - DWORD Next(CResourceW &resource); - #endif -}; - -DWORD GetResourceParent(const CResource &resource, CResource &parentResource); -#ifndef _UNICODE -DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource); -#endif - -DWORD GetResourceInformation(const CResource &resource, - CResource &destResource, CSysString &systemPathPart); -#ifndef _UNICODE -DWORD GetResourceInformation(const CResourceW &resource, - CResourceW &destResource, UString &systemPathPart); -#endif - -DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); -#ifndef _UNICODE -DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags); -#endif - -}} - -#endif +// Windows/Net.h + +#ifndef ZIP7_INC_WINDOWS_NET_H +#define ZIP7_INC_WINDOWS_NET_H + +#include "../Common/MyString.h" +#include "../Common/MyWindows.h" + +namespace NWindows { +namespace NNet { + +struct CResourceBase +{ + DWORD Scope; + DWORD Type; + DWORD DisplayType; + DWORD Usage; + bool LocalNameIsDefined; + bool RemoteNameIsDefined; + bool CommentIsDefined; + bool ProviderIsDefined; +}; + +struct CResource: public CResourceBase +{ + CSysString LocalName; + CSysString RemoteName; + CSysString Comment; + CSysString Provider; +}; + +#ifdef _UNICODE +typedef CResource CResourceW; +#else +struct CResourceW: public CResourceBase +{ + UString LocalName; + UString RemoteName; + UString Comment; + UString Provider; +}; +#endif + +class CEnum +{ + HANDLE _handle; + bool _handleAllocated; + DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource); + DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); + #ifndef _UNICODE + DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource); + DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize); + #endif +protected: + bool IsHandleAllocated() const { return _handleAllocated; } +public: + CEnum(): _handleAllocated(false) {} + ~CEnum() { Close(); } + DWORD Close(); + DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource); + DWORD Next(CResource &resource); + #ifndef _UNICODE + DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource); + DWORD Next(CResourceW &resource); + #endif +}; + +DWORD GetResourceParent(const CResource &resource, CResource &parentResource); +#ifndef _UNICODE +DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource); +#endif + +DWORD GetResourceInformation(const CResource &resource, + CResource &destResource, CSysString &systemPathPart); +#ifndef _UNICODE +DWORD GetResourceInformation(const CResourceW &resource, + CResourceW &destResource, UString &systemPathPart); +#endif + +DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags); +#ifndef _UNICODE +DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags); +#endif + +}} + +#endif diff --git a/CPP/Windows/NtCheck.h b/CPP/Windows/NtCheck.h index 3fc8c8d7f..362a05ad9 100644 --- a/CPP/Windows/NtCheck.h +++ b/CPP/Windows/NtCheck.h @@ -1,58 +1,58 @@ -// Windows/NtCheck.h - -#ifndef ZIP7_INC_WINDOWS_NT_CHECK_H -#define ZIP7_INC_WINDOWS_NT_CHECK_H - -#ifdef _WIN32 - -#include "../Common/MyWindows.h" - -#if !defined(_WIN64) && !defined(UNDER_CE) - -#if defined(_MSC_VER) && _MSC_VER >= 1900 -#pragma warning(push) -// GetVersionExW was declared deprecated -#pragma warning(disable : 4996) -#endif -static inline bool IsItWindowsNT() -{ - OSVERSIONINFO vi; - vi.dwOSVersionInfoSize = sizeof(vi); - return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT); -} -#if defined(_MSC_VER) && _MSC_VER >= 1900 -#pragma warning(pop) -#endif - -#endif - -#ifndef _UNICODE - extern - bool g_IsNT; - #if defined(_WIN64) || defined(UNDER_CE) - bool g_IsNT = true; - #define SET_IS_NT - #else - bool g_IsNT = false; - #define SET_IS_NT g_IsNT = IsItWindowsNT(); - #endif - #define NT_CHECK_ACTION - // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION } -#else - #if !defined(_WIN64) && !defined(UNDER_CE) - #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION } - #else - #define NT_CHECK_ACTION - #endif - #define SET_IS_NT -#endif - -#define NT_CHECK NT_CHECK_ACTION SET_IS_NT - -#else - -#define NT_CHECK - -#endif - -#endif +// Windows/NtCheck.h + +#ifndef ZIP7_INC_WINDOWS_NT_CHECK_H +#define ZIP7_INC_WINDOWS_NT_CHECK_H + +#ifdef _WIN32 + +#include "../Common/MyWindows.h" + +#if !defined(_WIN64) && !defined(UNDER_CE) + +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#pragma warning(push) +// GetVersionExW was declared deprecated +#pragma warning(disable : 4996) +#endif +static inline bool IsItWindowsNT() +{ + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT); +} +#if defined(_MSC_VER) && _MSC_VER >= 1900 +#pragma warning(pop) +#endif + +#endif + +#ifndef _UNICODE + extern + bool g_IsNT; + #if defined(_WIN64) || defined(UNDER_CE) + bool g_IsNT = true; + #define SET_IS_NT + #else + bool g_IsNT = false; + #define SET_IS_NT g_IsNT = IsItWindowsNT(); + #endif + #define NT_CHECK_ACTION + // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION } +#else + #if !defined(_WIN64) && !defined(UNDER_CE) + #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION } + #else + #define NT_CHECK_ACTION + #endif + #define SET_IS_NT +#endif + +#define NT_CHECK NT_CHECK_ACTION SET_IS_NT + +#else + +#define NT_CHECK + +#endif + +#endif diff --git a/CPP/Windows/ProcessMessages.cpp b/CPP/Windows/ProcessMessages.cpp index 439d3fdbb..0f48aee25 100644 --- a/CPP/Windows/ProcessMessages.cpp +++ b/CPP/Windows/ProcessMessages.cpp @@ -1,22 +1,22 @@ -// Windows/ProcessMessages.cpp - -#include "StdAfx.h" - -#include "ProcessMessages.h" - -namespace NWindows { - -void ProcessMessages(HWND window) -{ - MSG msg; - while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) - { - if (window == (HWND) NULL || !IsDialogMessage(window, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } -} - -} +// Windows/ProcessMessages.cpp + +#include "StdAfx.h" + +#include "ProcessMessages.h" + +namespace NWindows { + +void ProcessMessages(HWND window) +{ + MSG msg; + while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) + { + if (window == (HWND) NULL || !IsDialogMessage(window, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +} diff --git a/CPP/Windows/ProcessMessages.h b/CPP/Windows/ProcessMessages.h index 28813c13f..aa98bbb05 100644 --- a/CPP/Windows/ProcessMessages.h +++ b/CPP/Windows/ProcessMessages.h @@ -1,12 +1,12 @@ -// Windows/ProcessMessages.h - -#ifndef ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H -#define ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H - -namespace NWindows { - -void ProcessMessages(HWND window); - -} - -#endif +// Windows/ProcessMessages.h + +#ifndef ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H +#define ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H + +namespace NWindows { + +void ProcessMessages(HWND window); + +} + +#endif diff --git a/CPP/Windows/ProcessUtils.cpp b/CPP/Windows/ProcessUtils.cpp index 00b9156da..f5e156c23 100644 --- a/CPP/Windows/ProcessUtils.cpp +++ b/CPP/Windows/ProcessUtils.cpp @@ -1,102 +1,102 @@ -// ProcessUtils.cpp - -#include "StdAfx.h" - -#include "../Common/StringConvert.h" - -#include "ProcessUtils.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { - -#ifndef UNDER_CE -static UString GetQuotedString(const UString &s) -{ - UString s2 ('\"'); - s2 += s; - s2.Add_Char('\"'); - return s2; -} -#endif - -WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir) -{ - /* - OutputDebugStringW(L"CProcess::Create"); - OutputDebugStringW(imageName); - if (params) - { - OutputDebugStringW(L"params:"); - OutputDebugStringW(params); - } - if (curDir) - { - OutputDebugStringW(L"cur dir:"); - OutputDebugStringW(curDir); - } - */ - - Close(); - const UString params2 = - #ifndef UNDER_CE - GetQuotedString(imageName) + L' ' + - #endif - params; - #ifdef UNDER_CE - curDir = NULL; - #else - imageName = NULL; - #endif - PROCESS_INFORMATION pi; - BOOL result; - #ifndef _UNICODE - if (!g_IsNT) - { - STARTUPINFOA si; - si.cb = sizeof(si); - si.lpReserved = NULL; - si.lpDesktop = NULL; - si.lpTitle = NULL; - si.dwFlags = 0; - si.cbReserved2 = 0; - si.lpReserved2 = NULL; - - CSysString curDirA; - if (curDir != 0) - curDirA = GetSystemString(curDir); - const AString s = GetSystemString(params2); - result = ::CreateProcessA(NULL, s.Ptr_non_const(), - NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi); - } - else - #endif - { - STARTUPINFOW si; - si.cb = sizeof(si); - si.lpReserved = NULL; - si.lpDesktop = NULL; - si.lpTitle = NULL; - si.dwFlags = 0; - si.cbReserved2 = 0; - si.lpReserved2 = NULL; - - result = CreateProcessW(imageName, params2.Ptr_non_const(), - NULL, NULL, FALSE, 0, NULL, curDir, &si, &pi); - } - if (result == 0) - return ::GetLastError(); - ::CloseHandle(pi.hThread); - _handle = pi.hProcess; - return 0; -} - -WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms) -{ - CProcess process; - return process.Create(imageName, params, NULL); -} - -} +// ProcessUtils.cpp + +#include "StdAfx.h" + +#include "../Common/StringConvert.h" + +#include "ProcessUtils.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +#ifndef UNDER_CE +static UString GetQuotedString(const UString &s) +{ + UString s2 ('\"'); + s2 += s; + s2.Add_Char('\"'); + return s2; +} +#endif + +WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir) +{ + /* + OutputDebugStringW(L"CProcess::Create"); + OutputDebugStringW(imageName); + if (params) + { + OutputDebugStringW(L"params:"); + OutputDebugStringW(params); + } + if (curDir) + { + OutputDebugStringW(L"cur dir:"); + OutputDebugStringW(curDir); + } + */ + + Close(); + const UString params2 = + #ifndef UNDER_CE + GetQuotedString(imageName) + L' ' + + #endif + params; + #ifdef UNDER_CE + curDir = NULL; + #else + imageName = NULL; + #endif + PROCESS_INFORMATION pi; + BOOL result; + #ifndef _UNICODE + if (!g_IsNT) + { + STARTUPINFOA si; + si.cb = sizeof(si); + si.lpReserved = NULL; + si.lpDesktop = NULL; + si.lpTitle = NULL; + si.dwFlags = 0; + si.cbReserved2 = 0; + si.lpReserved2 = NULL; + + CSysString curDirA; + if (curDir != 0) + curDirA = GetSystemString(curDir); + const AString s = GetSystemString(params2); + result = ::CreateProcessA(NULL, s.Ptr_non_const(), + NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi); + } + else + #endif + { + STARTUPINFOW si; + si.cb = sizeof(si); + si.lpReserved = NULL; + si.lpDesktop = NULL; + si.lpTitle = NULL; + si.dwFlags = 0; + si.cbReserved2 = 0; + si.lpReserved2 = NULL; + + result = CreateProcessW(imageName, params2.Ptr_non_const(), + NULL, NULL, FALSE, 0, NULL, curDir, &si, &pi); + } + if (result == 0) + return ::GetLastError(); + ::CloseHandle(pi.hThread); + _handle = pi.hProcess; + return 0; +} + +WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms) +{ + CProcess process; + return process.Create(imageName, params, NULL); +} + +} diff --git a/CPP/Windows/ProcessUtils.h b/CPP/Windows/ProcessUtils.h index 8054eef0a..b1fce3ae5 100644 --- a/CPP/Windows/ProcessUtils.h +++ b/CPP/Windows/ProcessUtils.h @@ -1,138 +1,138 @@ -// Windows/ProcessUtils.h - -#ifndef ZIP7_INC_WINDOWS_PROCESS_UTILS_H -#define ZIP7_INC_WINDOWS_PROCESS_UTILS_H - -#include "../Common/MyWindows.h" - -#ifndef Z7_OLD_WIN_SDK - -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#else // Z7_OLD_WIN_SDK - -typedef struct _MODULEINFO { - LPVOID lpBaseOfDll; - DWORD SizeOfImage; - LPVOID EntryPoint; -} MODULEINFO, *LPMODULEINFO; - -typedef struct _PROCESS_MEMORY_COUNTERS { - DWORD cb; - DWORD PageFaultCount; - SIZE_T PeakWorkingSetSize; - SIZE_T WorkingSetSize; - SIZE_T QuotaPeakPagedPoolUsage; - SIZE_T QuotaPagedPoolUsage; - SIZE_T QuotaPeakNonPagedPoolUsage; - SIZE_T QuotaNonPagedPoolUsage; - SIZE_T PagefileUsage; - SIZE_T PeakPagefileUsage; -} PROCESS_MEMORY_COUNTERS; -typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; - -#endif // Z7_OLD_WIN_SDK - -#include "../Common/MyString.h" - -#include "Defs.h" -#include "Handle.h" - -namespace NWindows { - -class CProcess: public CHandle -{ -public: - bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId) - { - _handle = ::OpenProcess(desiredAccess, inheritHandle, processId); - return (_handle != NULL); - } - - #ifndef UNDER_CE - - bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); } - bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); } - #if (WINVER >= 0x0500) - DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); } - #endif - bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); } - DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); } - // bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); } - - bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime) - { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); } - - DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); } - - // Debug - - bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead) - { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); } - - bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten) - { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress, - #ifdef Z7_OLD_WIN_SDK - (LPVOID) - #endif - buffer, - size, numberOfBytesWritten)); } - - bool FlushInstructionCache(LPCVOID baseAddress = NULL, SIZE_T size = 0) - { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); } - - LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect) - { return VirtualAllocEx(_handle, address, size, allocationType, protect); } - - bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType) - { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); } - - // Process Status API (PSAPI) - - /* - bool EmptyWorkingSet() - { return BOOLToBool(::EmptyWorkingSet(_handle)); } - bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes) - { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); } - DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size) - { return ::GetModuleBaseName(_handle, hModule, baseName, size); } - bool MyGetModuleBaseName(HMODULE hModule, CSysString &name) - { - const unsigned len = MAX_PATH + 100; - const DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuf(len), len); - name.ReleaseBuf_CalcLen(len); - return (resultLen != 0); - } - - DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size) - { return ::GetModuleFileNameEx(_handle, hModule, baseName, size); } - bool MyGetModuleFileNameEx(HMODULE hModule, CSysString &name) - { - const unsigned len = MAX_PATH + 100; - const DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuf(len), len); - name.ReleaseBuf_CalcLen(len); - return (resultLen != 0); - } - - bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo) - { return BOOLToBool(::GetModuleInformation(_handle, hModule, moduleInfo, sizeof(MODULEINFO))); } - bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters) - { return BOOLToBool(::GetProcessMemoryInfo(_handle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); } - */ - - #endif - - WRes Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir); - - DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); } -}; - -WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms); - -} - -#endif +// Windows/ProcessUtils.h + +#ifndef ZIP7_INC_WINDOWS_PROCESS_UTILS_H +#define ZIP7_INC_WINDOWS_PROCESS_UTILS_H + +#include "../Common/MyWindows.h" + +#ifndef Z7_OLD_WIN_SDK + +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#else // Z7_OLD_WIN_SDK + +typedef struct _MODULEINFO { + LPVOID lpBaseOfDll; + DWORD SizeOfImage; + LPVOID EntryPoint; +} MODULEINFO, *LPMODULEINFO; + +typedef struct _PROCESS_MEMORY_COUNTERS { + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} PROCESS_MEMORY_COUNTERS; +typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; + +#endif // Z7_OLD_WIN_SDK + +#include "../Common/MyString.h" + +#include "Defs.h" +#include "Handle.h" + +namespace NWindows { + +class CProcess: public CHandle +{ +public: + bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId) + { + _handle = ::OpenProcess(desiredAccess, inheritHandle, processId); + return (_handle != NULL); + } + + #ifndef UNDER_CE + + bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); } + bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); } + #if (WINVER >= 0x0500) + DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); } + #endif + bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); } + DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); } + // bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); } + + bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime) + { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); } + + DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); } + + // Debug + + bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead) + { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); } + + bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten) + { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress, + #ifdef Z7_OLD_WIN_SDK + (LPVOID) + #endif + buffer, + size, numberOfBytesWritten)); } + + bool FlushInstructionCache(LPCVOID baseAddress = NULL, SIZE_T size = 0) + { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); } + + LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect) + { return VirtualAllocEx(_handle, address, size, allocationType, protect); } + + bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType) + { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); } + + // Process Status API (PSAPI) + + /* + bool EmptyWorkingSet() + { return BOOLToBool(::EmptyWorkingSet(_handle)); } + bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes) + { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); } + DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size) + { return ::GetModuleBaseName(_handle, hModule, baseName, size); } + bool MyGetModuleBaseName(HMODULE hModule, CSysString &name) + { + const unsigned len = MAX_PATH + 100; + const DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuf(len), len); + name.ReleaseBuf_CalcLen(len); + return (resultLen != 0); + } + + DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size) + { return ::GetModuleFileNameEx(_handle, hModule, baseName, size); } + bool MyGetModuleFileNameEx(HMODULE hModule, CSysString &name) + { + const unsigned len = MAX_PATH + 100; + const DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuf(len), len); + name.ReleaseBuf_CalcLen(len); + return (resultLen != 0); + } + + bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo) + { return BOOLToBool(::GetModuleInformation(_handle, hModule, moduleInfo, sizeof(MODULEINFO))); } + bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters) + { return BOOLToBool(::GetProcessMemoryInfo(_handle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); } + */ + + #endif + + WRes Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir); + + DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); } +}; + +WRes MyCreateProcess(LPCWSTR imageName, const UString ¶ms); + +} + +#endif diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp index 5242614b6..678f970e6 100644 --- a/CPP/Windows/PropVariant.cpp +++ b/CPP/Windows/PropVariant.cpp @@ -1,393 +1,393 @@ -// Windows/PropVariant.cpp - -#include "StdAfx.h" - -#include "../Common/Defs.h" - -#include "PropVariant.h" - -namespace NWindows { -namespace NCOM { - -BSTR AllocBstrFromAscii(const char *s) throw() -{ - if (!s) - return NULL; - UINT len = (UINT)strlen(s); - BSTR p = ::SysAllocStringLen(NULL, len); - if (p) - { - for (UINT i = 0; i <= len; i++) - p[i] = (Byte)s[i]; - } - return p; -} - -HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw() -{ - p->bstrVal = ::SysAllocStringLen(NULL, numChars); - if (!p->bstrVal) - { - p->vt = VT_ERROR; - p->scode = E_OUTOFMEMORY; - return E_OUTOFMEMORY; - } - p->vt = VT_BSTR; - return S_OK; -} - -HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw() -{ - p->bstrVal = AllocBstrFromAscii(s); - if (p->bstrVal) - { - p->vt = VT_BSTR; - return S_OK; - } - p->vt = VT_ERROR; - p->scode = E_OUTOFMEMORY; - return E_OUTOFMEMORY; -} - -CPropVariant::CPropVariant(const PROPVARIANT &varSrc) -{ - vt = VT_EMPTY; - InternalCopy(&varSrc); -} - -CPropVariant::CPropVariant(const CPropVariant &varSrc) -{ - vt = VT_EMPTY; - InternalCopy(&varSrc); -} - -CPropVariant::CPropVariant(BSTR bstrSrc) -{ - vt = VT_EMPTY; - *this = bstrSrc; -} - -CPropVariant::CPropVariant(LPCOLESTR lpszSrc) -{ - vt = VT_EMPTY; - *this = lpszSrc; -} - -CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) -{ - InternalCopy(&varSrc); - return *this; -} - -CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) -{ - InternalCopy(&varSrc); - return *this; -} - -CPropVariant& CPropVariant::operator=(BSTR bstrSrc) -{ - *this = (LPCOLESTR)bstrSrc; - return *this; -} - -static const char * const kMemException = "out of memory"; - -CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) -{ - InternalClear(); - vt = VT_BSTR; - wReserved1 = 0; - bstrVal = ::SysAllocString(lpszSrc); - if (!bstrVal && lpszSrc) - { - throw kMemException; - // vt = VT_ERROR; - // scode = E_OUTOFMEMORY; - } - return *this; -} - -CPropVariant& CPropVariant::operator=(const UString &s) -{ - InternalClear(); - vt = VT_BSTR; - wReserved1 = 0; - bstrVal = ::SysAllocStringLen(s, s.Len()); - if (!bstrVal) - throw kMemException; - return *this; -} - -CPropVariant& CPropVariant::operator=(const UString2 &s) -{ - /* - if (s.IsEmpty()) - *this = L""; - else - */ - { - InternalClear(); - vt = VT_BSTR; - wReserved1 = 0; - bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len()); - if (!bstrVal) - throw kMemException; - /* SysAllocStringLen probably appends a null-terminating character for NULL string. - But it doesn't specified in MSDN. - But we suppose that it works - - if (!s.GetRawPtr()) - { - *bstrVal = 0; - } - */ - - /* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL) - pointers to this function causes an unexpected termination of the application. - Is it safe? Maybe we must chamnge the code for that case ? */ - } - return *this; -} - -CPropVariant& CPropVariant::operator=(const char *s) -{ - InternalClear(); - vt = VT_BSTR; - wReserved1 = 0; - bstrVal = AllocBstrFromAscii(s); - if (!bstrVal) - { - throw kMemException; - // vt = VT_ERROR; - // scode = E_OUTOFMEMORY; - } - return *this; -} - -CPropVariant& CPropVariant::operator=(bool bSrc) throw() -{ - if (vt != VT_BOOL) - { - InternalClear(); - vt = VT_BOOL; - } - boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; - return *this; -} - -BSTR CPropVariant::AllocBstr(unsigned numChars) -{ - if (vt != VT_EMPTY) - InternalClear(); - vt = VT_BSTR; - wReserved1 = 0; - bstrVal = ::SysAllocStringLen(NULL, numChars); - if (!bstrVal) - { - throw kMemException; - // vt = VT_ERROR; - // scode = E_OUTOFMEMORY; - } - return bstrVal; -} - -#define SET_PROP_id_dest(id, dest) \ - if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0; - -void CPropVariant::Set_Int32(Int32 value) throw() -{ - SET_PROP_id_dest(VT_I4, lVal) -} - -void CPropVariant::Set_Int64(Int64 value) throw() -{ - SET_PROP_id_dest(VT_I8, hVal.QuadPart) -} - -#define SET_PROP_FUNC(type, id, dest) \ - CPropVariant& CPropVariant::operator=(type value) throw() \ - { SET_PROP_id_dest(id, dest) return *this; } - -SET_PROP_FUNC(Byte, VT_UI1, bVal) -// SET_PROP_FUNC(Int16, VT_I2, iVal) -// SET_PROP_FUNC(Int32, VT_I4, lVal) -SET_PROP_FUNC(UInt32, VT_UI4, ulVal) -SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) -// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) -SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) - -#define CASE_SIMPLE_VT_VALUES \ - case VT_EMPTY: \ - case VT_BOOL: \ - case VT_FILETIME: \ - case VT_UI8: \ - case VT_UI4: \ - case VT_UI2: \ - case VT_UI1: \ - case VT_I8: \ - case VT_I4: \ - case VT_I2: \ - case VT_I1: \ - case VT_UINT: \ - case VT_INT: \ - case VT_NULL: \ - case VT_ERROR: \ - case VT_R4: \ - case VT_R8: \ - case VT_CY: \ - case VT_DATE: \ - - -/* - ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME) - So we handle VT_FILETIME and another simple types directly - we call system functions for VT_BSTR and for unknown typed -*/ - -CPropVariant::~CPropVariant() throw() -{ - switch ((unsigned)vt) - { - CASE_SIMPLE_VT_VALUES - // vt = VT_EMPTY; // it's optional - return; - default: break; - } - ::VariantClear((tagVARIANT *)this); -} - -HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() -{ - switch ((unsigned)prop->vt) - { - CASE_SIMPLE_VT_VALUES - prop->vt = VT_EMPTY; - break; - default: - { - const HRESULT res = ::VariantClear((VARIANTARG *)prop); - if (res != S_OK || prop->vt != VT_EMPTY) - return res; - break; - } - } - prop->wReserved1 = 0; - prop->wReserved2 = 0; - prop->wReserved3 = 0; - prop->uhVal.QuadPart = 0; - return S_OK; -} - -HRESULT CPropVariant::Clear() throw() -{ - if (vt == VT_EMPTY) - { - wReserved1 = 0; - return S_OK; - } - return PropVariant_Clear(this); -} - -HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() -{ - Clear(); - switch ((unsigned)pSrc->vt) - { - CASE_SIMPLE_VT_VALUES - memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); - return S_OK; - default: break; - } - return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast(pSrc)); -} - - -HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() -{ - const HRESULT hr = Clear(); - if (FAILED(hr)) - return hr; - // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); - *(PROPVARIANT *)this = *pSrc; - pSrc->vt = VT_EMPTY; - pSrc->wReserved1 = 0; - return S_OK; -} - -HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() -{ - if (pDest->vt != VT_EMPTY) - { - const HRESULT hr = PropVariant_Clear(pDest); - if (FAILED(hr)) - return hr; - } - // memcpy(pDest, this, sizeof(PROPVARIANT)); - *pDest = *(PROPVARIANT *)this; - vt = VT_EMPTY; - wReserved1 = 0; - return S_OK; -} - -HRESULT CPropVariant::InternalClear() throw() -{ - if (vt == VT_EMPTY) - { - wReserved1 = 0; - return S_OK; - } - const HRESULT hr = Clear(); - if (FAILED(hr)) - { - vt = VT_ERROR; - scode = hr; - } - return hr; -} - -void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) -{ - const HRESULT hr = Copy(pSrc); - if (FAILED(hr)) - { - if (hr == E_OUTOFMEMORY) - throw kMemException; - vt = VT_ERROR; - scode = hr; - } -} - - -int CPropVariant::Compare(const CPropVariant &a) throw() -{ - if (vt != a.vt) - return MyCompare(vt, a.vt); - switch ((unsigned)vt) - { - case VT_EMPTY: return 0; - // case VT_I1: return MyCompare(cVal, a.cVal); - case VT_UI1: return MyCompare(bVal, a.bVal); - case VT_I2: return MyCompare(iVal, a.iVal); - case VT_UI2: return MyCompare(uiVal, a.uiVal); - case VT_I4: return MyCompare(lVal, a.lVal); - case VT_UI4: return MyCompare(ulVal, a.ulVal); - // case VT_UINT: return MyCompare(uintVal, a.uintVal); - case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); - case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); - case VT_BOOL: return -MyCompare(boolVal, a.boolVal); - case VT_FILETIME: - { - const int res = CompareFileTime(&filetime, &a.filetime); - if (res != 0) - return res; - const unsigned v1 = Get_Ns100(); - const unsigned v2 = a.Get_Ns100(); - return MyCompare(v1, v2); - } - case VT_BSTR: return 0; // Not implemented - default: return 0; - } -} - -}} +// Windows/PropVariant.cpp + +#include "StdAfx.h" + +#include "../Common/Defs.h" + +#include "PropVariant.h" + +namespace NWindows { +namespace NCOM { + +BSTR AllocBstrFromAscii(const char *s) throw() +{ + if (!s) + return NULL; + UINT len = (UINT)strlen(s); + BSTR p = ::SysAllocStringLen(NULL, len); + if (p) + { + for (UINT i = 0; i <= len; i++) + p[i] = (Byte)s[i]; + } + return p; +} + +HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw() +{ + p->bstrVal = ::SysAllocStringLen(NULL, numChars); + if (!p->bstrVal) + { + p->vt = VT_ERROR; + p->scode = E_OUTOFMEMORY; + return E_OUTOFMEMORY; + } + p->vt = VT_BSTR; + return S_OK; +} + +HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw() +{ + p->bstrVal = AllocBstrFromAscii(s); + if (p->bstrVal) + { + p->vt = VT_BSTR; + return S_OK; + } + p->vt = VT_ERROR; + p->scode = E_OUTOFMEMORY; + return E_OUTOFMEMORY; +} + +CPropVariant::CPropVariant(const PROPVARIANT &varSrc) +{ + vt = VT_EMPTY; + InternalCopy(&varSrc); +} + +CPropVariant::CPropVariant(const CPropVariant &varSrc) +{ + vt = VT_EMPTY; + InternalCopy(&varSrc); +} + +CPropVariant::CPropVariant(BSTR bstrSrc) +{ + vt = VT_EMPTY; + *this = bstrSrc; +} + +CPropVariant::CPropVariant(LPCOLESTR lpszSrc) +{ + vt = VT_EMPTY; + *this = lpszSrc; +} + +CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) +{ + InternalCopy(&varSrc); + return *this; +} + +CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) +{ + InternalCopy(&varSrc); + return *this; +} + +CPropVariant& CPropVariant::operator=(BSTR bstrSrc) +{ + *this = (LPCOLESTR)bstrSrc; + return *this; +} + +static const char * const kMemException = "out of memory"; + +CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) +{ + InternalClear(); + vt = VT_BSTR; + wReserved1 = 0; + bstrVal = ::SysAllocString(lpszSrc); + if (!bstrVal && lpszSrc) + { + throw kMemException; + // vt = VT_ERROR; + // scode = E_OUTOFMEMORY; + } + return *this; +} + +CPropVariant& CPropVariant::operator=(const UString &s) +{ + InternalClear(); + vt = VT_BSTR; + wReserved1 = 0; + bstrVal = ::SysAllocStringLen(s, s.Len()); + if (!bstrVal) + throw kMemException; + return *this; +} + +CPropVariant& CPropVariant::operator=(const UString2 &s) +{ + /* + if (s.IsEmpty()) + *this = L""; + else + */ + { + InternalClear(); + vt = VT_BSTR; + wReserved1 = 0; + bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len()); + if (!bstrVal) + throw kMemException; + /* SysAllocStringLen probably appends a null-terminating character for NULL string. + But it doesn't specified in MSDN. + But we suppose that it works + + if (!s.GetRawPtr()) + { + *bstrVal = 0; + } + */ + + /* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL) + pointers to this function causes an unexpected termination of the application. + Is it safe? Maybe we must chamnge the code for that case ? */ + } + return *this; +} + +CPropVariant& CPropVariant::operator=(const char *s) +{ + InternalClear(); + vt = VT_BSTR; + wReserved1 = 0; + bstrVal = AllocBstrFromAscii(s); + if (!bstrVal) + { + throw kMemException; + // vt = VT_ERROR; + // scode = E_OUTOFMEMORY; + } + return *this; +} + +CPropVariant& CPropVariant::operator=(bool bSrc) throw() +{ + if (vt != VT_BOOL) + { + InternalClear(); + vt = VT_BOOL; + } + boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; + return *this; +} + +BSTR CPropVariant::AllocBstr(unsigned numChars) +{ + if (vt != VT_EMPTY) + InternalClear(); + vt = VT_BSTR; + wReserved1 = 0; + bstrVal = ::SysAllocStringLen(NULL, numChars); + if (!bstrVal) + { + throw kMemException; + // vt = VT_ERROR; + // scode = E_OUTOFMEMORY; + } + return bstrVal; +} + +#define SET_PROP_id_dest(id, dest) \ + if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0; + +void CPropVariant::Set_Int32(Int32 value) throw() +{ + SET_PROP_id_dest(VT_I4, lVal) +} + +void CPropVariant::Set_Int64(Int64 value) throw() +{ + SET_PROP_id_dest(VT_I8, hVal.QuadPart) +} + +#define SET_PROP_FUNC(type, id, dest) \ + CPropVariant& CPropVariant::operator=(type value) throw() \ + { SET_PROP_id_dest(id, dest) return *this; } + +SET_PROP_FUNC(Byte, VT_UI1, bVal) +// SET_PROP_FUNC(Int16, VT_I2, iVal) +// SET_PROP_FUNC(Int32, VT_I4, lVal) +SET_PROP_FUNC(UInt32, VT_UI4, ulVal) +SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) +// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) +SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) + +#define CASE_SIMPLE_VT_VALUES \ + case VT_EMPTY: \ + case VT_BOOL: \ + case VT_FILETIME: \ + case VT_UI8: \ + case VT_UI4: \ + case VT_UI2: \ + case VT_UI1: \ + case VT_I8: \ + case VT_I4: \ + case VT_I2: \ + case VT_I1: \ + case VT_UINT: \ + case VT_INT: \ + case VT_NULL: \ + case VT_ERROR: \ + case VT_R4: \ + case VT_R8: \ + case VT_CY: \ + case VT_DATE: \ + + +/* + ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME) + So we handle VT_FILETIME and another simple types directly + we call system functions for VT_BSTR and for unknown typed +*/ + +CPropVariant::~CPropVariant() throw() +{ + switch ((unsigned)vt) + { + CASE_SIMPLE_VT_VALUES + // vt = VT_EMPTY; // it's optional + return; + default: break; + } + ::VariantClear((tagVARIANT *)this); +} + +HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() +{ + switch ((unsigned)prop->vt) + { + CASE_SIMPLE_VT_VALUES + prop->vt = VT_EMPTY; + break; + default: + { + const HRESULT res = ::VariantClear((VARIANTARG *)prop); + if (res != S_OK || prop->vt != VT_EMPTY) + return res; + break; + } + } + prop->wReserved1 = 0; + prop->wReserved2 = 0; + prop->wReserved3 = 0; + prop->uhVal.QuadPart = 0; + return S_OK; +} + +HRESULT CPropVariant::Clear() throw() +{ + if (vt == VT_EMPTY) + { + wReserved1 = 0; + return S_OK; + } + return PropVariant_Clear(this); +} + +HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() +{ + Clear(); + switch ((unsigned)pSrc->vt) + { + CASE_SIMPLE_VT_VALUES + memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); + return S_OK; + default: break; + } + return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast(pSrc)); +} + + +HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() +{ + const HRESULT hr = Clear(); + if (FAILED(hr)) + return hr; + // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); + *(PROPVARIANT *)this = *pSrc; + pSrc->vt = VT_EMPTY; + pSrc->wReserved1 = 0; + return S_OK; +} + +HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() +{ + if (pDest->vt != VT_EMPTY) + { + const HRESULT hr = PropVariant_Clear(pDest); + if (FAILED(hr)) + return hr; + } + // memcpy(pDest, this, sizeof(PROPVARIANT)); + *pDest = *(PROPVARIANT *)this; + vt = VT_EMPTY; + wReserved1 = 0; + return S_OK; +} + +HRESULT CPropVariant::InternalClear() throw() +{ + if (vt == VT_EMPTY) + { + wReserved1 = 0; + return S_OK; + } + const HRESULT hr = Clear(); + if (FAILED(hr)) + { + vt = VT_ERROR; + scode = hr; + } + return hr; +} + +void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) +{ + const HRESULT hr = Copy(pSrc); + if (FAILED(hr)) + { + if (hr == E_OUTOFMEMORY) + throw kMemException; + vt = VT_ERROR; + scode = hr; + } +} + + +int CPropVariant::Compare(const CPropVariant &a) throw() +{ + if (vt != a.vt) + return MyCompare(vt, a.vt); + switch ((unsigned)vt) + { + case VT_EMPTY: return 0; + // case VT_I1: return MyCompare(cVal, a.cVal); + case VT_UI1: return MyCompare(bVal, a.bVal); + case VT_I2: return MyCompare(iVal, a.iVal); + case VT_UI2: return MyCompare(uiVal, a.uiVal); + case VT_I4: return MyCompare(lVal, a.lVal); + case VT_UI4: return MyCompare(ulVal, a.ulVal); + // case VT_UINT: return MyCompare(uintVal, a.uintVal); + case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); + case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); + case VT_BOOL: return -MyCompare(boolVal, a.boolVal); + case VT_FILETIME: + { + const int res = CompareFileTime(&filetime, &a.filetime); + if (res != 0) + return res; + const unsigned v1 = Get_Ns100(); + const unsigned v2 = a.Get_Ns100(); + return MyCompare(v1, v2); + } + case VT_BSTR: return 0; // Not implemented + default: return 0; + } +} + +}} diff --git a/CPP/Windows/PropVariant.h b/CPP/Windows/PropVariant.h index 004190b17..f358fdea1 100644 --- a/CPP/Windows/PropVariant.h +++ b/CPP/Windows/PropVariant.h @@ -1,173 +1,173 @@ -// Windows/PropVariant.h - -#ifndef ZIP7_INC_WINDOWS_PROP_VARIANT_H -#define ZIP7_INC_WINDOWS_PROP_VARIANT_H - -#include "../Common/MyTypes.h" -#include "../Common/MyWindows.h" -#include "../Common/MyString.h" - -namespace NWindows { -namespace NCOM { - -BSTR AllocBstrFromAscii(const char *s) throw(); - -HRESULT PropVariant_Clear(PROPVARIANT *p) throw(); - -HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw(); -HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw(); - -inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw() -{ - p->vt = VT_UI4; - p->ulVal = v; -} - -inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw() -{ - p->vt = VT_UI8; - p->uhVal.QuadPart = v; -} - -inline void PropVarEm_Set_FileTime64_Prec(PROPVARIANT *p, UInt64 v, unsigned prec) throw() -{ - p->vt = VT_FILETIME; - p->filetime.dwLowDateTime = (DWORD)v; - p->filetime.dwHighDateTime = (DWORD)(v >> 32); - p->wReserved1 = (WORD)prec; - p->wReserved2 = 0; - p->wReserved3 = 0; -} - -inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() -{ - p->vt = VT_BOOL; - p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE); -} - - -class CPropVariant : public tagPROPVARIANT -{ - // ---------- forbidden functions ---------- - CPropVariant(const char *s); - // CPropVariant(const UString &s); - #ifdef DEBUG_FSTRING_INHERITS_ASTRING - CPropVariant(const FString &s); - CPropVariant& operator=(const FString &s); - #endif - -public: - CPropVariant() - { - vt = VT_EMPTY; - wReserved1 = 0; - // wReserved2 = 0; - // wReserved3 = 0; - // uhVal.QuadPart = 0; - bstrVal = NULL; - } - - - void Set_FtPrec(unsigned prec) - { - wReserved1 = (WORD)prec; - wReserved2 = 0; - wReserved3 = 0; - } - - void SetAsTimeFrom_FT_Prec(const FILETIME &ft, unsigned prec) - { - operator=(ft); - Set_FtPrec(prec); - } - - void SetAsTimeFrom_Ft64_Prec(UInt64 v, unsigned prec) - { - FILETIME ft; - ft.dwLowDateTime = (DWORD)(UInt32)v; - ft.dwHighDateTime = (DWORD)(UInt32)(v >> 32); - operator=(ft); - Set_FtPrec(prec); - } - - void SetAsTimeFrom_FT_Prec_Ns100(const FILETIME &ft, unsigned prec, unsigned ns100) - { - operator=(ft); - wReserved1 = (WORD)prec; - wReserved2 = (WORD)ns100; - wReserved3 = 0; - } - - unsigned Get_Ns100() const - { - const unsigned prec = wReserved1; - const unsigned ns100 = wReserved2; - if (prec == 0 - && prec <= k_PropVar_TimePrec_1ns - && ns100 < 100 - && wReserved3 == 0) - return ns100; - return 0; - } - - ~CPropVariant() throw(); - CPropVariant(const PROPVARIANT &varSrc); - CPropVariant(const CPropVariant &varSrc); - CPropVariant(BSTR bstrSrc); - CPropVariant(LPCOLESTR lpszSrc); - CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); } - CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; } - -private: - CPropVariant(UInt16 value); // { vt = VT_UI2; wReserved1 = 0; uiVal = value; } - CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; } - CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; } - CPropVariant(Int64 value); // { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } - -public: - CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; } - CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; } - CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; } - - CPropVariant& operator=(const CPropVariant &varSrc); - CPropVariant& operator=(const PROPVARIANT &varSrc); - CPropVariant& operator=(BSTR bstrSrc); - CPropVariant& operator=(LPCOLESTR lpszSrc); - CPropVariant& operator=(const UString &s); - CPropVariant& operator=(const UString2 &s); - CPropVariant& operator=(const char *s); - CPropVariant& operator=(const AString &s) - { return (*this)=(const char *)s; } - - CPropVariant& operator=(bool bSrc) throw(); - CPropVariant& operator=(Byte value) throw(); - -private: - CPropVariant& operator=(Int16 value) throw(); - CPropVariant& operator=(UInt16 value) throw(); - CPropVariant& operator=(Int32 value) throw(); - CPropVariant& operator=(Int64 value) throw(); - -public: - CPropVariant& operator=(UInt32 value) throw(); - CPropVariant& operator=(UInt64 value) throw(); - CPropVariant& operator=(const FILETIME &value) throw(); - - void Set_Int32(Int32 value) throw(); - void Set_Int64(Int64 value) throw(); - - BSTR AllocBstr(unsigned numChars); - - HRESULT Clear() throw(); - HRESULT Copy(const PROPVARIANT *pSrc) throw(); - HRESULT Attach(PROPVARIANT *pSrc) throw(); - HRESULT Detach(PROPVARIANT *pDest) throw(); - - HRESULT InternalClear() throw(); - void InternalCopy(const PROPVARIANT *pSrc); - int Compare(const CPropVariant &a) throw(); -}; - -}} - -#endif +// Windows/PropVariant.h + +#ifndef ZIP7_INC_WINDOWS_PROP_VARIANT_H +#define ZIP7_INC_WINDOWS_PROP_VARIANT_H + +#include "../Common/MyTypes.h" +#include "../Common/MyWindows.h" +#include "../Common/MyString.h" + +namespace NWindows { +namespace NCOM { + +BSTR AllocBstrFromAscii(const char *s) throw(); + +HRESULT PropVariant_Clear(PROPVARIANT *p) throw(); + +HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw(); +HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw(); + +inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw() +{ + p->vt = VT_UI4; + p->ulVal = v; +} + +inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw() +{ + p->vt = VT_UI8; + p->uhVal.QuadPart = v; +} + +inline void PropVarEm_Set_FileTime64_Prec(PROPVARIANT *p, UInt64 v, unsigned prec) throw() +{ + p->vt = VT_FILETIME; + p->filetime.dwLowDateTime = (DWORD)v; + p->filetime.dwHighDateTime = (DWORD)(v >> 32); + p->wReserved1 = (WORD)prec; + p->wReserved2 = 0; + p->wReserved3 = 0; +} + +inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() +{ + p->vt = VT_BOOL; + p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE); +} + + +class CPropVariant : public tagPROPVARIANT +{ + // ---------- forbidden functions ---------- + CPropVariant(const char *s); + // CPropVariant(const UString &s); + #ifdef DEBUG_FSTRING_INHERITS_ASTRING + CPropVariant(const FString &s); + CPropVariant& operator=(const FString &s); + #endif + +public: + CPropVariant() + { + vt = VT_EMPTY; + wReserved1 = 0; + // wReserved2 = 0; + // wReserved3 = 0; + // uhVal.QuadPart = 0; + bstrVal = NULL; + } + + + void Set_FtPrec(unsigned prec) + { + wReserved1 = (WORD)prec; + wReserved2 = 0; + wReserved3 = 0; + } + + void SetAsTimeFrom_FT_Prec(const FILETIME &ft, unsigned prec) + { + operator=(ft); + Set_FtPrec(prec); + } + + void SetAsTimeFrom_Ft64_Prec(UInt64 v, unsigned prec) + { + FILETIME ft; + ft.dwLowDateTime = (DWORD)(UInt32)v; + ft.dwHighDateTime = (DWORD)(UInt32)(v >> 32); + operator=(ft); + Set_FtPrec(prec); + } + + void SetAsTimeFrom_FT_Prec_Ns100(const FILETIME &ft, unsigned prec, unsigned ns100) + { + operator=(ft); + wReserved1 = (WORD)prec; + wReserved2 = (WORD)ns100; + wReserved3 = 0; + } + + unsigned Get_Ns100() const + { + const unsigned prec = wReserved1; + const unsigned ns100 = wReserved2; + if (prec == 0 + && prec <= k_PropVar_TimePrec_1ns + && ns100 < 100 + && wReserved3 == 0) + return ns100; + return 0; + } + + ~CPropVariant() throw(); + CPropVariant(const PROPVARIANT &varSrc); + CPropVariant(const CPropVariant &varSrc); + CPropVariant(BSTR bstrSrc); + CPropVariant(LPCOLESTR lpszSrc); + CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); } + CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; } + +private: + CPropVariant(UInt16 value); // { vt = VT_UI2; wReserved1 = 0; uiVal = value; } + CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; } + CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; } + CPropVariant(Int64 value); // { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; } + +public: + CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; } + CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; } + CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; } + + CPropVariant& operator=(const CPropVariant &varSrc); + CPropVariant& operator=(const PROPVARIANT &varSrc); + CPropVariant& operator=(BSTR bstrSrc); + CPropVariant& operator=(LPCOLESTR lpszSrc); + CPropVariant& operator=(const UString &s); + CPropVariant& operator=(const UString2 &s); + CPropVariant& operator=(const char *s); + CPropVariant& operator=(const AString &s) + { return (*this)=(const char *)s; } + + CPropVariant& operator=(bool bSrc) throw(); + CPropVariant& operator=(Byte value) throw(); + +private: + CPropVariant& operator=(Int16 value) throw(); + CPropVariant& operator=(UInt16 value) throw(); + CPropVariant& operator=(Int32 value) throw(); + CPropVariant& operator=(Int64 value) throw(); + +public: + CPropVariant& operator=(UInt32 value) throw(); + CPropVariant& operator=(UInt64 value) throw(); + CPropVariant& operator=(const FILETIME &value) throw(); + + void Set_Int32(Int32 value) throw(); + void Set_Int64(Int64 value) throw(); + + BSTR AllocBstr(unsigned numChars); + + HRESULT Clear() throw(); + HRESULT Copy(const PROPVARIANT *pSrc) throw(); + HRESULT Attach(PROPVARIANT *pSrc) throw(); + HRESULT Detach(PROPVARIANT *pDest) throw(); + + HRESULT InternalClear() throw(); + void InternalCopy(const PROPVARIANT *pSrc); + int Compare(const CPropVariant &a) throw(); +}; + +}} + +#endif diff --git a/CPP/Windows/PropVariantConv.cpp b/CPP/Windows/PropVariantConv.cpp index df7bd4759..21a7b4e3c 100644 --- a/CPP/Windows/PropVariantConv.cpp +++ b/CPP/Windows/PropVariantConv.cpp @@ -1,274 +1,274 @@ -// PropVariantConv.cpp - -#include "StdAfx.h" - -#include "../Common/IntToString.h" - -#include "Defs.h" -#include "PropVariantConv.h" - -#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } - -static const unsigned k_TimeStringBufferSize = 64; - -bool g_Timestamp_Show_UTC; -#if 0 -bool g_Timestamp_Show_DisableZ; -bool g_Timestamp_Show_TDelimeter; -bool g_Timestamp_Show_ZoneOffset; -#endif - -Z7_NO_INLINE -bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level, unsigned flags) throw() -{ - *s = 0; - FILETIME ft; - -#if 0 - Int64 bias64 = 0; -#endif - - const bool show_utc = - (flags & kTimestampPrintFlags_Force_UTC) ? true : - (flags & kTimestampPrintFlags_Force_LOCAL) ? false : - g_Timestamp_Show_UTC; - - if (show_utc) - ft = utc; - else - { - if (!FileTimeToLocalFileTime(&utc, &ft)) - return false; -#if 0 - if (g_Timestamp_Show_ZoneOffset) - { - const UInt64 utc64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; - const UInt64 loc64 = (((UInt64) ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - bias64 = (Int64)utc64 - (Int64)loc64; - } -#endif - } - - SYSTEMTIME st; - if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) - { - // win10 : that function doesn't work, if bit 63 of 64-bit FILETIME is set. - return false; - } - - { - unsigned val = st.wYear; - if (val >= 10000) - { - *s++ = (char)('0' + val / 10000); - val %= 10000; - } - s[3] = (char)('0' + val % 10); val /= 10; - s[2] = (char)('0' + val % 10); val /= 10; - s[1] = (char)('0' + val % 10); - s[0] = (char)('0' + val / 10); - s += 4; - } - UINT_TO_STR_2('-', st.wMonth) - UINT_TO_STR_2('-', st.wDay) - - if (level > kTimestampPrintLevel_DAY) - { - const char setChar = -#if 0 - g_Timestamp_Show_TDelimeter ? 'T' : // ISO 8601 -#endif - ' '; - UINT_TO_STR_2(setChar, st.wHour) - UINT_TO_STR_2(':', st.wMinute) - - if (level >= kTimestampPrintLevel_SEC) - { - UINT_TO_STR_2(':', st.wSecond) - - if (level > kTimestampPrintLevel_SEC) - { - *s++ = '.'; - /* - { - unsigned val = st.wMilliseconds; - s[2] = (char)('0' + val % 10); val /= 10; - s[1] = (char)('0' + val % 10); - s[0] = (char)('0' + val / 10); - s += 3; - } - *s++ = ' '; - */ - - { - unsigned numDigits = 7; - UInt32 val = (UInt32)((((UInt64)ft.dwHighDateTime << 32) + ft.dwLowDateTime) % 10000000); - for (unsigned i = numDigits; i != 0;) - { - i--; - s[i] = (char)('0' + val % 10); val /= 10; - } - if (numDigits > (unsigned)level) - numDigits = (unsigned)level; - s += numDigits; - } - if (level >= kTimestampPrintLevel_NTFS + 1) - { - *s++ = (char)('0' + (ns100 / 10)); - if (level >= kTimestampPrintLevel_NTFS + 2) - *s++ = (char)('0' + (ns100 % 10)); - } - } - } - } - - if (show_utc) - { - if ((flags & kTimestampPrintFlags_DisableZ) == 0 -#if 0 - && !g_Timestamp_Show_DisableZ -#endif - ) - *s++ = 'Z'; - } -#if 0 - else if (g_Timestamp_Show_ZoneOffset) - { -#if 1 - { - char c; - if (bias64 < 0) - { - bias64 = -bias64; - c = '+'; - } - else - c = '-'; - UInt32 bias = (UInt32)((UInt64)bias64 / (10000000 * 60)); -#else - TIME_ZONE_INFORMATION zi; - const DWORD dw = GetTimeZoneInformation(&zi); - if (dw <= TIME_ZONE_ID_DAYLIGHT) // == 2 - { - // UTC = LOCAL + Bias - Int32 bias = zi.Bias; - char c; - if (bias < 0) - { - bias = -bias; - c = '+'; - } - else - c = '-'; -#endif - const UInt32 hours = (UInt32)bias / 60; - const UInt32 mins = (UInt32)bias % 60; - UINT_TO_STR_2(c, hours) - UINT_TO_STR_2(':', mins) - } - } -#endif - *s = 0; - return true; -} - - -bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw() -{ - return ConvertUtcFileTimeToString2(utc, 0, s, level); -} - -bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *dest, int level) throw() -{ - char s[k_TimeStringBufferSize]; - const bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level); - for (unsigned i = 0;; i++) - { - const Byte c = (Byte)s[i]; - dest[i] = c; - if (c == 0) - break; - } - return res; -} - -bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw() -{ - char s[k_TimeStringBufferSize]; - const bool res = ConvertUtcFileTimeToString(ft, s, level); - for (unsigned i = 0;; i++) - { - const Byte c = (Byte)s[i]; - dest[i] = c; - if (c == 0) - break; - } - return res; -} - - -void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw() -{ - *dest = 0; - switch (prop.vt) - { - case VT_EMPTY: return; - case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; - case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; - case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; - case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; - case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; - case VT_FILETIME: - { - // const unsigned prec = prop.wReserved1; - int level = 0; - /* - if (prec == 0) - level = 7; - else if (prec > 16 && prec <= 16 + 9) - level = prec - 16; - */ - ConvertUtcFileTimeToString(prop.filetime, dest, level); - return; - } - // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; - case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; - case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; - case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; - case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; - default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2); - } -} - -void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw() -{ - *dest = 0; - switch (prop.vt) - { - case VT_EMPTY: return; - case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; - case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; - case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; - case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; - case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; - case VT_FILETIME: - { - // const unsigned prec = prop.wReserved1; - int level = 0; - /* - if (prec == 0) - level = 7; - else if (prec > 16 && prec <= 16 + 9) - level = prec - 16; - */ - ConvertUtcFileTimeToString(prop.filetime, dest, level); - return; - } - // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; - case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; - case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; - case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; - case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? (wchar_t)'+' : (wchar_t)'-'; dest[1] = 0; return; - default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2); - } -} +// PropVariantConv.cpp + +#include "StdAfx.h" + +#include "../Common/IntToString.h" + +#include "Defs.h" +#include "PropVariantConv.h" + +#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } + +static const unsigned k_TimeStringBufferSize = 64; + +bool g_Timestamp_Show_UTC; +#if 0 +bool g_Timestamp_Show_DisableZ; +bool g_Timestamp_Show_TDelimeter; +bool g_Timestamp_Show_ZoneOffset; +#endif + +Z7_NO_INLINE +bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level, unsigned flags) throw() +{ + *s = 0; + FILETIME ft; + +#if 0 + Int64 bias64 = 0; +#endif + + const bool show_utc = + (flags & kTimestampPrintFlags_Force_UTC) ? true : + (flags & kTimestampPrintFlags_Force_LOCAL) ? false : + g_Timestamp_Show_UTC; + + if (show_utc) + ft = utc; + else + { + if (!FileTimeToLocalFileTime(&utc, &ft)) + return false; +#if 0 + if (g_Timestamp_Show_ZoneOffset) + { + const UInt64 utc64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; + const UInt64 loc64 = (((UInt64) ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + bias64 = (Int64)utc64 - (Int64)loc64; + } +#endif + } + + SYSTEMTIME st; + if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) + { + // win10 : that function doesn't work, if bit 63 of 64-bit FILETIME is set. + return false; + } + + { + unsigned val = st.wYear; + if (val >= 10000) + { + *s++ = (char)('0' + val / 10000); + val %= 10000; + } + s[3] = (char)('0' + val % 10); val /= 10; + s[2] = (char)('0' + val % 10); val /= 10; + s[1] = (char)('0' + val % 10); + s[0] = (char)('0' + val / 10); + s += 4; + } + UINT_TO_STR_2('-', st.wMonth) + UINT_TO_STR_2('-', st.wDay) + + if (level > kTimestampPrintLevel_DAY) + { + const char setChar = +#if 0 + g_Timestamp_Show_TDelimeter ? 'T' : // ISO 8601 +#endif + ' '; + UINT_TO_STR_2(setChar, st.wHour) + UINT_TO_STR_2(':', st.wMinute) + + if (level >= kTimestampPrintLevel_SEC) + { + UINT_TO_STR_2(':', st.wSecond) + + if (level > kTimestampPrintLevel_SEC) + { + *s++ = '.'; + /* + { + unsigned val = st.wMilliseconds; + s[2] = (char)('0' + val % 10); val /= 10; + s[1] = (char)('0' + val % 10); + s[0] = (char)('0' + val / 10); + s += 3; + } + *s++ = ' '; + */ + + { + unsigned numDigits = 7; + UInt32 val = (UInt32)((((UInt64)ft.dwHighDateTime << 32) + ft.dwLowDateTime) % 10000000); + for (unsigned i = numDigits; i != 0;) + { + i--; + s[i] = (char)('0' + val % 10); val /= 10; + } + if (numDigits > (unsigned)level) + numDigits = (unsigned)level; + s += numDigits; + } + if (level >= kTimestampPrintLevel_NTFS + 1) + { + *s++ = (char)('0' + (ns100 / 10)); + if (level >= kTimestampPrintLevel_NTFS + 2) + *s++ = (char)('0' + (ns100 % 10)); + } + } + } + } + + if (show_utc) + { + if ((flags & kTimestampPrintFlags_DisableZ) == 0 +#if 0 + && !g_Timestamp_Show_DisableZ +#endif + ) + *s++ = 'Z'; + } +#if 0 + else if (g_Timestamp_Show_ZoneOffset) + { +#if 1 + { + char c; + if (bias64 < 0) + { + bias64 = -bias64; + c = '+'; + } + else + c = '-'; + UInt32 bias = (UInt32)((UInt64)bias64 / (10000000 * 60)); +#else + TIME_ZONE_INFORMATION zi; + const DWORD dw = GetTimeZoneInformation(&zi); + if (dw <= TIME_ZONE_ID_DAYLIGHT) // == 2 + { + // UTC = LOCAL + Bias + Int32 bias = zi.Bias; + char c; + if (bias < 0) + { + bias = -bias; + c = '+'; + } + else + c = '-'; +#endif + const UInt32 hours = (UInt32)bias / 60; + const UInt32 mins = (UInt32)bias % 60; + UINT_TO_STR_2(c, hours) + UINT_TO_STR_2(':', mins) + } + } +#endif + *s = 0; + return true; +} + + +bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw() +{ + return ConvertUtcFileTimeToString2(utc, 0, s, level); +} + +bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *dest, int level) throw() +{ + char s[k_TimeStringBufferSize]; + const bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level); + for (unsigned i = 0;; i++) + { + const Byte c = (Byte)s[i]; + dest[i] = c; + if (c == 0) + break; + } + return res; +} + +bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw() +{ + char s[k_TimeStringBufferSize]; + const bool res = ConvertUtcFileTimeToString(ft, s, level); + for (unsigned i = 0;; i++) + { + const Byte c = (Byte)s[i]; + dest[i] = c; + if (c == 0) + break; + } + return res; +} + + +void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw() +{ + *dest = 0; + switch (prop.vt) + { + case VT_EMPTY: return; + case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; + case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; + case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; + case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; + case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; + case VT_FILETIME: + { + // const unsigned prec = prop.wReserved1; + int level = 0; + /* + if (prec == 0) + level = 7; + else if (prec > 16 && prec <= 16 + 9) + level = prec - 16; + */ + ConvertUtcFileTimeToString(prop.filetime, dest, level); + return; + } + // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; + case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; + case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; + case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; + case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return; + default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2); + } +} + +void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw() +{ + *dest = 0; + switch (prop.vt) + { + case VT_EMPTY: return; + case VT_BSTR: dest[0] = '?'; dest[1] = 0; return; + case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return; + case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; + case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; + case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; + case VT_FILETIME: + { + // const unsigned prec = prop.wReserved1; + int level = 0; + /* + if (prec == 0) + level = 7; + else if (prec > 16 && prec <= 16 + 9) + level = prec - 16; + */ + ConvertUtcFileTimeToString(prop.filetime, dest, level); + return; + } + // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; + case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; + case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; + case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return; + case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? (wchar_t)'+' : (wchar_t)'-'; dest[1] = 0; return; + default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2); + } +} diff --git a/CPP/Windows/PropVariantConv.h b/CPP/Windows/PropVariantConv.h index ea53b1656..87825073d 100644 --- a/CPP/Windows/PropVariantConv.h +++ b/CPP/Windows/PropVariantConv.h @@ -1,47 +1,47 @@ -// Windows/PropVariantConv.h - -#ifndef ZIP7_INC_PROP_VARIANT_CONV_H -#define ZIP7_INC_PROP_VARIANT_CONV_H - -#include "../Common/MyTypes.h" - -// provide at least 32 bytes for buffer including zero-end - -extern bool g_Timestamp_Show_UTC; - -#define kTimestampPrintLevel_DAY -3 -// #define kTimestampPrintLevel_HOUR -2 -#define kTimestampPrintLevel_MIN -1 -#define kTimestampPrintLevel_SEC 0 -#define kTimestampPrintLevel_NTFS 7 -#define kTimestampPrintLevel_NS 9 - - -#define kTimestampPrintFlags_Force_UTC (1 << 0) -#define kTimestampPrintFlags_Force_LOCAL (1 << 1) -#define kTimestampPrintFlags_DisableZ (1 << 4) - -bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw(); -bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); -bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, char *s, int level = kTimestampPrintLevel_SEC, unsigned flags = 0) throw(); -bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); - -// provide at least 32 bytes for buffer including zero-end -// don't send VT_BSTR to these functions -void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw(); -void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw(); - -inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value) -{ - switch (prop.vt) - { - case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true; - case VT_UI4: value = prop.ulVal; return true; - case VT_UI2: value = prop.uiVal; return true; - case VT_UI1: value = prop.bVal; return true; - case VT_EMPTY: return false; - default: throw 151199; - } -} - -#endif +// Windows/PropVariantConv.h + +#ifndef ZIP7_INC_PROP_VARIANT_CONV_H +#define ZIP7_INC_PROP_VARIANT_CONV_H + +#include "../Common/MyTypes.h" + +// provide at least 32 bytes for buffer including zero-end + +extern bool g_Timestamp_Show_UTC; + +#define kTimestampPrintLevel_DAY -3 +// #define kTimestampPrintLevel_HOUR -2 +#define kTimestampPrintLevel_MIN -1 +#define kTimestampPrintLevel_SEC 0 +#define kTimestampPrintLevel_NTFS 7 +#define kTimestampPrintLevel_NS 9 + + +#define kTimestampPrintFlags_Force_UTC (1 << 0) +#define kTimestampPrintFlags_Force_LOCAL (1 << 1) +#define kTimestampPrintFlags_DisableZ (1 << 4) + +bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw(); +bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); +bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, char *s, int level = kTimestampPrintLevel_SEC, unsigned flags = 0) throw(); +bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); + +// provide at least 32 bytes for buffer including zero-end +// don't send VT_BSTR to these functions +void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw(); +void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw(); + +inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value) +{ + switch (prop.vt) + { + case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true; + case VT_UI4: value = prop.ulVal; return true; + case VT_UI2: value = prop.uiVal; return true; + case VT_UI1: value = prop.bVal; return true; + case VT_EMPTY: return false; + default: throw 151199; + } +} + +#endif diff --git a/CPP/Windows/PropVariantUtils.cpp b/CPP/Windows/PropVariantUtils.cpp index 660c326d9..6daee8397 100644 --- a/CPP/Windows/PropVariantUtils.cpp +++ b/CPP/Windows/PropVariantUtils.cpp @@ -1,161 +1,161 @@ -// PropVariantUtils.cpp - -#include "StdAfx.h" - -#include "../Common/IntToString.h" - -#include "PropVariantUtils.h" - -using namespace NWindows; - -static void AddHex(AString &s, UInt32 v) -{ - char sz[16]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt32ToHex(v, sz + 2); - s += sz; -} - - -AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) -{ - char sz[16]; - const char *p = NULL; - for (unsigned i = 0; i < num; i++) - { - const CUInt32PCharPair &pair = pairs[i]; - if (pair.Value == value) - p = pair.Name; - } - if (!p) - { - ConvertUInt32ToString(value, sz); - p = sz; - } - return (AString)p; -} - -void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop) -{ - prop = TypePairToString(pairs, num, value); -} - - -AString TypeToString(const char * const table[], unsigned num, UInt32 value) -{ - char sz[16]; - const char *p = NULL; - if (value < num) - p = table[value]; - if (!p) - { - ConvertUInt32ToString(value, sz); - p = sz; - } - return (AString)p; -} - -void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop) -{ - char sz[16]; - const char *p = NULL; - if (value < num) - p = table[value]; - if (!p) - { - ConvertUInt32ToString(value, sz); - p = sz; - } - prop = p; -} - - -AString FlagsToString(const char * const *names, unsigned num, UInt32 flags) -{ - AString s; - for (unsigned i = 0; i < num; i++) - { - UInt32 flag = (UInt32)1 << i; - if ((flags & flag) != 0) - { - const char *name = names[i]; - if (name && name[0] != 0) - { - s.Add_OptSpaced(name); - flags &= ~flag; - } - } - } - if (flags != 0) - { - s.Add_Space_if_NotEmpty(); - AddHex(s, flags); - } - return s; -} - -AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags) -{ - AString s; - for (unsigned i = 0; i < num; i++) - { - const CUInt32PCharPair &p = pairs[i]; - UInt32 flag = (UInt32)1 << (unsigned)p.Value; - if ((flags & flag) != 0) - { - if (p.Name[0] != 0) - s.Add_OptSpaced(p.Name); - } - flags &= ~flag; - } - if (flags != 0) - { - s.Add_Space_if_NotEmpty(); - AddHex(s, flags); - } - return s; -} - -void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NCOM::CPropVariant &prop) -{ - prop = FlagsToString(names, num, flags); -} - -void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop) -{ - prop = FlagsToString(pairs, num, flags); -} - - -static AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags) -{ - AString s; - for (unsigned i = 0; i < num; i++) - { - const CUInt32PCharPair &p = pairs[i]; - UInt64 flag = (UInt64)1 << (unsigned)p.Value; - if ((flags & flag) != 0) - { - if (p.Name[0] != 0) - s.Add_OptSpaced(p.Name); - } - flags &= ~flag; - } - if (flags != 0) - { - { - char sz[32]; - sz[0] = '0'; - sz[1] = 'x'; - ConvertUInt64ToHex(flags, sz + 2); - s.Add_OptSpaced(sz); - } - } - return s; -} - -void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NCOM::CPropVariant &prop) -{ - prop = Flags64ToString(pairs, num, flags); -} +// PropVariantUtils.cpp + +#include "StdAfx.h" + +#include "../Common/IntToString.h" + +#include "PropVariantUtils.h" + +using namespace NWindows; + +static void AddHex(AString &s, UInt32 v) +{ + char sz[16]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt32ToHex(v, sz + 2); + s += sz; +} + + +AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value) +{ + char sz[16]; + const char *p = NULL; + for (unsigned i = 0; i < num; i++) + { + const CUInt32PCharPair &pair = pairs[i]; + if (pair.Value == value) + p = pair.Name; + } + if (!p) + { + ConvertUInt32ToString(value, sz); + p = sz; + } + return (AString)p; +} + +void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop) +{ + prop = TypePairToString(pairs, num, value); +} + + +AString TypeToString(const char * const table[], unsigned num, UInt32 value) +{ + char sz[16]; + const char *p = NULL; + if (value < num) + p = table[value]; + if (!p) + { + ConvertUInt32ToString(value, sz); + p = sz; + } + return (AString)p; +} + +void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop) +{ + char sz[16]; + const char *p = NULL; + if (value < num) + p = table[value]; + if (!p) + { + ConvertUInt32ToString(value, sz); + p = sz; + } + prop = p; +} + + +AString FlagsToString(const char * const *names, unsigned num, UInt32 flags) +{ + AString s; + for (unsigned i = 0; i < num; i++) + { + UInt32 flag = (UInt32)1 << i; + if ((flags & flag) != 0) + { + const char *name = names[i]; + if (name && name[0] != 0) + { + s.Add_OptSpaced(name); + flags &= ~flag; + } + } + } + if (flags != 0) + { + s.Add_Space_if_NotEmpty(); + AddHex(s, flags); + } + return s; +} + +AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags) +{ + AString s; + for (unsigned i = 0; i < num; i++) + { + const CUInt32PCharPair &p = pairs[i]; + UInt32 flag = (UInt32)1 << (unsigned)p.Value; + if ((flags & flag) != 0) + { + if (p.Name[0] != 0) + s.Add_OptSpaced(p.Name); + } + flags &= ~flag; + } + if (flags != 0) + { + s.Add_Space_if_NotEmpty(); + AddHex(s, flags); + } + return s; +} + +void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NCOM::CPropVariant &prop) +{ + prop = FlagsToString(names, num, flags); +} + +void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop) +{ + prop = FlagsToString(pairs, num, flags); +} + + +static AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags) +{ + AString s; + for (unsigned i = 0; i < num; i++) + { + const CUInt32PCharPair &p = pairs[i]; + UInt64 flag = (UInt64)1 << (unsigned)p.Value; + if ((flags & flag) != 0) + { + if (p.Name[0] != 0) + s.Add_OptSpaced(p.Name); + } + flags &= ~flag; + } + if (flags != 0) + { + { + char sz[32]; + sz[0] = '0'; + sz[1] = 'x'; + ConvertUInt64ToHex(flags, sz + 2); + s.Add_OptSpaced(sz); + } + } + return s; +} + +void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NCOM::CPropVariant &prop) +{ + prop = Flags64ToString(pairs, num, flags); +} diff --git a/CPP/Windows/PropVariantUtils.h b/CPP/Windows/PropVariantUtils.h index 2c4840bbd..78adb50d3 100644 --- a/CPP/Windows/PropVariantUtils.h +++ b/CPP/Windows/PropVariantUtils.h @@ -1,34 +1,34 @@ -// Windows/PropVariantUtils.h - -#ifndef ZIP7_INC_PROP_VARIANT_UTILS_H -#define ZIP7_INC_PROP_VARIANT_UTILS_H - -#include "../Common/MyString.h" - -#include "PropVariant.h" - -struct CUInt32PCharPair -{ - UInt32 Value; - const char *Name; -}; - -AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value); -void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop); - -AString FlagsToString(const char * const *names, unsigned num, UInt32 flags); -AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags); -void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop); -void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop); - -AString TypeToString(const char * const table[], unsigned num, UInt32 value); -void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop); - -#define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop) -#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop) -#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, Z7_ARRAY_SIZE(table), value, prop) - -void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NWindows::NCOM::CPropVariant &prop); -#define FLAGS64_TO_PROP(pairs, value, prop) Flags64ToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop) - -#endif +// Windows/PropVariantUtils.h + +#ifndef ZIP7_INC_PROP_VARIANT_UTILS_H +#define ZIP7_INC_PROP_VARIANT_UTILS_H + +#include "../Common/MyString.h" + +#include "PropVariant.h" + +struct CUInt32PCharPair +{ + UInt32 Value; + const char *Name; +}; + +AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value); +void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop); + +AString FlagsToString(const char * const *names, unsigned num, UInt32 flags); +AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags); +void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop); +void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop); + +AString TypeToString(const char * const table[], unsigned num, UInt32 value); +void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop); + +#define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop) +#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop) +#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, Z7_ARRAY_SIZE(table), value, prop) + +void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NWindows::NCOM::CPropVariant &prop); +#define FLAGS64_TO_PROP(pairs, value, prop) Flags64ToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop) + +#endif diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp index c383ac5e3..a94a50f5d 100644 --- a/CPP/Windows/Registry.cpp +++ b/CPP/Windows/Registry.cpp @@ -1,403 +1,474 @@ -// Windows/Registry.cpp - -#include "StdAfx.h" - -#include -// #include - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif -#include "Registry.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { -namespace NRegistry { - -#define MYASSERT(expr) // _ASSERTE(expr) -#define MY_ASSUME(expr) - -/* -static void Error() -{ - #ifdef _CONSOLE - printf("\nregistry error\n"); - #else - MessageBoxW(0, L"registry error", L"", 0); - // exit(1); - #endif -} - -#define MY_ASSUME(expr) { if (!(expr)) Error(); } -*/ - -LONG CKey::Create(HKEY parentKey, LPCTSTR keyName, - LPTSTR keyClass, DWORD options, REGSAM accessMask, - LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw() -{ - MY_ASSUME(parentKey != NULL); - DWORD dispositionReal; - HKEY key = NULL; - LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass, - options, accessMask, securityAttributes, &key, &dispositionReal); - if (disposition != NULL) - *disposition = dispositionReal; - if (res == ERROR_SUCCESS) - { - res = Close(); - _object = key; - } - return res; -} - -LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw() -{ - MY_ASSUME(parentKey != NULL); - HKEY key = NULL; - LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key); - if (res == ERROR_SUCCESS) - { - res = Close(); - MYASSERT(res == ERROR_SUCCESS); - _object = key; - } - return res; -} - -LONG CKey::Close() throw() -{ - LONG res = ERROR_SUCCESS; - if (_object != NULL) - { - res = RegCloseKey(_object); - _object = NULL; - } - return res; -} - -// win95, win98: deletes sunkey and all its subkeys -// winNT to be deleted must not have subkeys -LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() -{ - MY_ASSUME(_object != NULL); - return RegDeleteKey(_object, subKeyName); -} - -LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() -{ - CKey key; - LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE); - if (res != ERROR_SUCCESS) - return res; - FILETIME fileTime; - const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL - DWORD size = kBufSize; - TCHAR buffer[kBufSize]; - while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS) - { - res = key.RecurseDeleteKey(buffer); - if (res != ERROR_SUCCESS) - return res; - size = kBufSize; - } - key.Close(); - return DeleteSubKey(subKeyName); -} - - -///////////////////////// -// Value Functions - -static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); } -static inline bool UINT32ToBool(UInt32 value) { return (value != 0); } - - -LONG CKey::DeleteValue(LPCTSTR name) throw() -{ - MY_ASSUME(_object != NULL); - return ::RegDeleteValue(_object, name); -} - -#ifndef _UNICODE -LONG CKey::DeleteValue(LPCWSTR name) -{ - MY_ASSUME(_object != NULL); - if (g_IsNT) - return ::RegDeleteValueW(_object, name); - return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name)); -} -#endif - -LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw() -{ - MY_ASSUME(_object != NULL); - return RegSetValueEx(_object, name, 0, REG_DWORD, - (const BYTE *)&value, sizeof(UInt32)); -} - -LONG CKey::SetValue(LPCTSTR name, bool value) throw() -{ - return SetValue(name, BoolToUINT32(value)); -} - -LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() -{ - MYASSERT(value != NULL); - MY_ASSUME(_object != NULL); - return RegSetValueEx(_object, name, 0, REG_SZ, - (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)); -} - -/* -LONG CKey::SetValue(LPCTSTR name, const CSysString &value) -{ - MYASSERT(value != NULL); - MY_ASSUME(_object != NULL); - return RegSetValueEx(_object, name, NULL, REG_SZ, - (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); -} -*/ - -#ifndef _UNICODE - -LONG CKey::SetValue(LPCWSTR name, LPCWSTR value) -{ - MYASSERT(value != NULL); - MY_ASSUME(_object != NULL); - if (g_IsNT) - return RegSetValueExW(_object, name, 0, REG_SZ, - (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t))); - return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), - value == 0 ? 0 : (LPCSTR)GetSystemString(value)); -} - -#endif - - -LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw() -{ - MYASSERT(value != NULL); - MY_ASSUME(_object != NULL); - return RegSetValueEx(_object, name, 0, REG_BINARY, - (const BYTE *)value, size); -} - -LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) -{ - MYASSERT(value != NULL); - CKey key; - LONG res = key.Create(parentKey, keyName); - if (res == ERROR_SUCCESS) - res = key.SetValue(valueName, value); - return res; -} - -LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw() -{ - MYASSERT(value != NULL); - CKey key; - LONG res = key.Create(_object, keyName); - if (res == ERROR_SUCCESS) - res = key.SetValue(valueName, value); - return res; -} - -LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw() -{ - DWORD type = 0; - DWORD count = sizeof(DWORD); - LONG res = RegQueryValueEx(_object, name, NULL, &type, - (LPBYTE)&value, &count); - MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD)); - MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32))); - return res; -} - -LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() -{ - UInt32 uintValue = BoolToUINT32(value); - LONG res = QueryValue(name, uintValue); - value = UINT32ToBool(uintValue); - return res; -} - -LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() -{ - UInt32 newVal; - LONG res = QueryValue(name, newVal); - if (res == ERROR_SUCCESS) - value = newVal; - return res; -} - -LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() -{ - bool newVal = false; - LONG res = QueryValue(name, newVal); - if (res == ERROR_SUCCESS) - value = newVal; - return res; -} - -LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() -{ - DWORD type = 0; - LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); - MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); - return res; -} - -LONG CKey::QueryValue(LPCTSTR name, CSysString &value) -{ - value.Empty(); - DWORD type = 0; - DWORD curSize = 0; - LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, &curSize); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) - return res; - UInt32 curSize2 = curSize; - res = QueryValue(name, value.GetBuf(curSize), curSize2); - if (curSize > curSize2) - curSize = curSize2; - value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR)); - return res; -} - - -#ifndef _UNICODE - -LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count) -{ - DWORD type = 0; - LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); - MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); - return res; -} - -LONG CKey::QueryValue(LPCWSTR name, UString &value) -{ - value.Empty(); - DWORD type = 0; - DWORD curSize = 0; - LONG res; - if (g_IsNT) - { - res = RegQueryValueExW(_object, name, NULL, &type, NULL, &curSize); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) - return res; - UInt32 curSize2 = curSize; - res = QueryValue(name, value.GetBuf(curSize), curSize2); - if (curSize > curSize2) - curSize = curSize2; - value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t)); - } - else - { - AString vTemp; - res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp); - value = GetUnicodeString(vTemp); - } - return res; -} - -#endif - - -LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() -{ - DWORD type = 0; - LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); - MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); - return res; -} - - -LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize) -{ - DWORD type = 0; - dataSize = 0; - LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) - return res; - value.Alloc(dataSize); - return QueryValue(name, (BYTE *)value, dataSize); -} - -LONG CKey::EnumKeys(CSysStringVector &keyNames) -{ - keyNames.Clear(); - CSysString keyName; - for (DWORD index = 0; ; index++) - { - const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL - FILETIME lastWriteTime; - UInt32 nameSize = kBufSize; - LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize), - (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime); - keyName.ReleaseBuf_CalcLen(kBufSize); - if (result == ERROR_NO_MORE_ITEMS) - break; - if (result != ERROR_SUCCESS) - return result; - keyNames.Add(keyName); - } - return ERROR_SUCCESS; -} - -LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) -{ - size_t numChars = 0; - - unsigned i; - - for (i = 0; i < strings.Size(); i++) - numChars += strings[i].Len() + 1; - - CObjArray buffer(numChars); - size_t pos = 0; - - for (i = 0; i < strings.Size(); i++) - { - const UString &s = strings[i]; - size_t size = s.Len() + 1; - wmemcpy(buffer + pos, s, size); - pos += size; - } - return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); -} - -LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) -{ - strings.Clear(); - CByteBuffer buffer; - UInt32 dataSize = 0; - const LONG res = QueryValue(valueName, buffer, dataSize); - if (res != ERROR_SUCCESS) - return res; - if (dataSize > buffer.Size()) - return E_FAIL; - if (dataSize % sizeof(wchar_t) != 0) - return E_FAIL; - - const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; - const size_t numChars = dataSize / sizeof(wchar_t); - size_t prev = 0; - UString s; - - for (size_t i = 0; i < numChars; i++) - { - if (data[i] == 0) - { - s = data + prev; - strings.Add(s); - prev = i + 1; - } - } - - return res; -} - -}} +// Windows/Registry.cpp + +#include "StdAfx.h" + +#include +// #include + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif +#include "Registry.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NRegistry { + +#define MYASSERT(expr) // _ASSERTE(expr) +#define MY_ASSUME(expr) + +/* +static void Error() +{ + #ifdef _CONSOLE + printf("\nregistry error\n"); + #else + MessageBoxW(0, L"registry error", L"", 0); + // exit(1); + #endif +} + +#define MY_ASSUME(expr) { if (!(expr)) Error(); } +*/ + +LONG CKey::Create(HKEY parentKey, LPCTSTR keyName, + LPTSTR keyClass, DWORD options, REGSAM accessMask, + LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw() +{ + MY_ASSUME(parentKey != NULL); + DWORD dispositionReal; + HKEY key = NULL; + LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass, + options, accessMask, securityAttributes, &key, &dispositionReal); + if (disposition != NULL) + *disposition = dispositionReal; + if (res == ERROR_SUCCESS) + { + res = Close(); + _object = key; + } + return res; +} + +LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw() +{ + MY_ASSUME(parentKey != NULL); + HKEY key = NULL; + LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key); + if (res == ERROR_SUCCESS) + { + res = Close(); + MYASSERT(res == ERROR_SUCCESS); + _object = key; + } + return res; +} + +LONG CKey::Close() throw() +{ + LONG res = ERROR_SUCCESS; + if (_object != NULL) + { + res = RegCloseKey(_object); + _object = NULL; + } + return res; +} + +// win95, win98: deletes subkey and all its subkeys +// winNT to be deleted must not have subkeys +LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() +{ + MY_ASSUME(_object != NULL); + return RegDeleteKey(_object, subKeyName); +} + +LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() +{ + { + CKey key; + LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE); + if (res != ERROR_SUCCESS) + return res; + FILETIME fileTime; + const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL + TCHAR buffer[kBufSize]; + // we use loop limit here for some unexpected code failure + for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++) + { + DWORD size = kBufSize; + // we always request starting item (index==0) in each iteration, + // because we remove starting item (index==0) in each loop iteration. + res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime); + if (res != ERROR_SUCCESS) + { + // possible return codes: + // ERROR_NO_MORE_ITEMS : are no more subkeys available + // ERROR_MORE_DATA : name buffer is too small + // we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error. + // if (res != ERROR_NO_MORE_ITEMS) return res; + break; + } + res = key.RecurseDeleteKey(buffer); + if (res != ERROR_SUCCESS) + return res; + } + // key.Close(); + } + return DeleteSubKey(subKeyName); +} + + +///////////////////////// +// Value Functions + +static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); } +static inline bool UINT32ToBool(UInt32 value) { return (value != 0); } + + +LONG CKey::DeleteValue(LPCTSTR name) throw() +{ + MY_ASSUME(_object != NULL); + return ::RegDeleteValue(_object, name); +} + +#ifndef _UNICODE +LONG CKey::DeleteValue(LPCWSTR name) +{ + MY_ASSUME(_object != NULL); + if (g_IsNT) + return ::RegDeleteValueW(_object, name); + return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name)); +} +#endif + +LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw() +{ + MY_ASSUME(_object != NULL); + return RegSetValueEx(_object, name, 0, REG_DWORD, + (const BYTE *)&value, sizeof(UInt32)); +} + +LONG CKey::SetValue(LPCTSTR name, bool value) throw() +{ + return SetValue(name, BoolToUINT32(value)); +} + + +// value must be string that is NULL terminated +LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() +{ + MYASSERT(value != NULL); + MY_ASSUME(_object != NULL); + // note: RegSetValueEx supports (value == NULL), if (cbData == 0) + return RegSetValueEx(_object, name, 0, REG_SZ, + (const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR))); +} + +/* +LONG CKey::SetValue(LPCTSTR name, const CSysString &value) +{ + MYASSERT(value != NULL); + MY_ASSUME(_object != NULL); + return RegSetValueEx(_object, name, 0, REG_SZ, + (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); +} +*/ + +#ifndef _UNICODE + +LONG CKey::SetValue(LPCWSTR name, LPCWSTR value) +{ + MYASSERT(value != NULL); + MY_ASSUME(_object != NULL); + if (g_IsNT) + return RegSetValueExW(_object, name, 0, REG_SZ, + (const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t))); + return SetValue(name == NULL ? NULL : + (LPCSTR)GetSystemString(name), + (LPCSTR)GetSystemString(value)); +} + +#endif + + +LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw() +{ + MYASSERT(value != NULL); + MY_ASSUME(_object != NULL); + return RegSetValueEx(_object, name, 0, REG_BINARY, + (const BYTE *)value, size); +} + +LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) +{ + MYASSERT(value != NULL); + CKey key; + LONG res = key.Create(parentKey, keyName); + if (res == ERROR_SUCCESS) + res = key.SetValue(valueName, value); + return res; +} + +LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw() +{ + MYASSERT(value != NULL); + CKey key; + LONG res = key.Create(_object, keyName); + if (res == ERROR_SUCCESS) + res = key.SetValue(valueName, value); + return res; +} + + +LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw() +{ + DWORD type = 0; + DWORD count = sizeof(value); + UInt32 value2; // = value; + const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count); + if (res == ERROR_SUCCESS) + { + // ERROR_UNSUPPORTED_TYPE + if (count != sizeof(value) || type != REG_DWORD) + return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA; + value = value2; + } + return res; +} + +LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw() +{ + DWORD type = 0; + DWORD count = sizeof(value); + UInt64 value2; // = value; + const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count); + if (res == ERROR_SUCCESS) + { + if (count != sizeof(value) || type != REG_QWORD) + return ERROR_UNSUPPORTED_TYPE; + value = value2; + } + return res; +} + +LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw() +{ + UInt32 uintValue; + const LONG res = GetValue_UInt32_IfOk(name, uintValue); + if (res == ERROR_SUCCESS) + value = UINT32ToBool(uintValue); + return res; +} + + + +LONG CKey::QueryValue(LPCTSTR name, CSysString &value) +{ + value.Empty(); + LONG res = ERROR_SUCCESS; + { + // if we don't want multiple calls here, + // we can use big value (264) here. + // 3 is default available length in new string. + DWORD size_prev = 3 * sizeof(TCHAR); + // at least 2 attempts are required. But we use more attempts for cases, + // where string can be changed by anothner process + for (unsigned i = 0; i < 2 + 2; i++) + { + DWORD type = 0; + DWORD size = size_prev; + { + LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR)); + res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size); + // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size. + } + if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) + { + if (type != REG_SZ && type != REG_EXPAND_SZ) + { + res = ERROR_UNSUPPORTED_TYPE; + size = 0; + } + } + else + size = 0; + if (size > size_prev) + { + size_prev = size; + size = 0; + res = ERROR_MORE_DATA; + } + value.ReleaseBuf_CalcLen(size / sizeof(TCHAR)); + if (res != ERROR_MORE_DATA) + return res; + } + } + return res; +} + + +#ifndef _UNICODE + +LONG CKey::QueryValue(LPCWSTR name, UString &value) +{ + value.Empty(); + LONG res = ERROR_SUCCESS; + if (g_IsNT) + { + DWORD size_prev = 3 * sizeof(wchar_t); + for (unsigned i = 0; i < 2 + 2; i++) + { + DWORD type = 0; + DWORD size = size_prev; + { + LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t)); + res = RegQueryValueExW(_object, name, NULL, &type, + size == 0 ? NULL : buf, &size); + } + if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) + { + if (type != REG_SZ && type != REG_EXPAND_SZ) + { + res = ERROR_UNSUPPORTED_TYPE; + size = 0; + } + } + else + size = 0; + if (size > size_prev) + { + size_prev = size; + size = 0; + res = ERROR_MORE_DATA; + } + value.ReleaseBuf_CalcLen(size / sizeof(wchar_t)); + if (res != ERROR_MORE_DATA) + return res; + } + } + else + { + AString vTemp; + res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp); + value = GetUnicodeString(vTemp); + } + return res; +} + +#endif + + +LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value) +{ + // value.Free(); + DWORD size_prev = 0; + LONG res = ERROR_SUCCESS; + for (unsigned i = 0; i < 2 + 2; i++) + { + DWORD type = 0; + DWORD size = size_prev; + value.Alloc(size_prev); + res = QueryValueEx(name, &type, value.NonConstData(), &size); + // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size. + if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) + { + if (type != REG_BINARY) + { + res = ERROR_UNSUPPORTED_TYPE; + size = 0; + } + } + else + size = 0; + if (size > size_prev) + { + size_prev = size; + size = 0; + res = ERROR_MORE_DATA; + } + if (size < value.Size()) + value.ChangeSize_KeepData(size, size); + if (res != ERROR_MORE_DATA) + return res; + } + return res; +} + + +LONG CKey::EnumKeys(CSysStringVector &keyNames) +{ + keyNames.Clear(); + CSysString keyName; + for (DWORD index = 0; ; index++) + { + const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL + FILETIME lastWriteTime; + DWORD nameSize = kBufSize; + const LONG res = ::RegEnumKeyEx(_object, index, + keyName.GetBuf(kBufSize), &nameSize, + NULL, NULL, NULL, &lastWriteTime); + keyName.ReleaseBuf_CalcLen(kBufSize); + if (res == ERROR_NO_MORE_ITEMS) + return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) + return res; + keyNames.Add(keyName); + } +} + + +LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) +{ + size_t numChars = 0; + unsigned i; + + for (i = 0; i < strings.Size(); i++) + numChars += strings[i].Len() + 1; + + CObjArray buffer(numChars); + size_t pos = 0; + + for (i = 0; i < strings.Size(); i++) + { + const UString &s = strings[i]; + const size_t size = s.Len() + 1; + wmemcpy(buffer + pos, s, size); + pos += size; + } + // if (pos != numChars) return E_FAIL; + return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); +} + +LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) +{ + strings.Clear(); + CByteBuffer buffer; + const LONG res = QueryValue_Binary(valueName, buffer); + if (res != ERROR_SUCCESS) + return res; + const size_t dataSize = buffer.Size(); + if (dataSize % sizeof(wchar_t)) + return ERROR_INVALID_DATA; + const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; + const size_t numChars = dataSize / sizeof(wchar_t); + // we can check that all names are finished + // if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA; + size_t prev = 0; + UString s; + for (size_t i = 0; i < numChars; i++) + { + if (data[i] == 0) + { + s = data + prev; + strings.Add(s); + prev = i + 1; + } + } + return res; +} + +}} diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h index c8be8e4f3..74ee91965 100644 --- a/CPP/Windows/Registry.h +++ b/CPP/Windows/Registry.h @@ -1,84 +1,96 @@ -// Windows/Registry.h - -#ifndef ZIP7_INC_WINDOWS_REGISTRY_H -#define ZIP7_INC_WINDOWS_REGISTRY_H - -#include "../Common/MyBuffer.h" -#include "../Common/MyString.h" - -namespace NWindows { -namespace NRegistry { - -LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value); - -class CKey -{ - HKEY _object; -public: - CKey(): _object(NULL) {} - ~CKey() { Close(); } - - operator HKEY() const { return _object; } - void Attach(HKEY key) { _object = key; } - HKEY Detach() - { - HKEY key = _object; - _object = NULL; - return key; - } - - LONG Create(HKEY parentKey, LPCTSTR keyName, - LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE, - REGSAM accessMask = KEY_ALL_ACCESS, - LPSECURITY_ATTRIBUTES securityAttributes = NULL, - LPDWORD disposition = NULL) throw(); - LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS) throw(); - - LONG Close() throw(); - - LONG DeleteSubKey(LPCTSTR subKeyName) throw(); - LONG RecurseDeleteKey(LPCTSTR subKeyName) throw(); - - LONG DeleteValue(LPCTSTR name) throw(); - #ifndef _UNICODE - LONG DeleteValue(LPCWSTR name); - #endif - - LONG SetValue(LPCTSTR valueName, UInt32 value) throw(); - LONG SetValue(LPCTSTR valueName, bool value) throw(); - LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw(); - // LONG SetValue(LPCTSTR valueName, const CSysString &value); - #ifndef _UNICODE - LONG SetValue(LPCWSTR name, LPCWSTR value); - // LONG SetValue(LPCWSTR name, const UString &value); - #endif - - LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw(); - - LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings); - LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings); - - LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(); - - LONG QueryValue(LPCTSTR name, UInt32 &value) throw(); - LONG QueryValue(LPCTSTR name, bool &value) throw(); - LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize) throw(); - LONG QueryValue(LPCTSTR name, CSysString &value); - - LONG GetValue_IfOk(LPCTSTR name, UInt32 &value) throw(); - LONG GetValue_IfOk(LPCTSTR name, bool &value) throw(); - - #ifndef _UNICODE - LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize); - LONG QueryValue(LPCWSTR name, UString &value); - #endif - - LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize) throw(); - LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize); - - LONG EnumKeys(CSysStringVector &keyNames); -}; - -}} - -#endif +// Windows/Registry.h + +#ifndef ZIP7_INC_WINDOWS_REGISTRY_H +#define ZIP7_INC_WINDOWS_REGISTRY_H + +#include "../Common/MyBuffer.h" +#include "../Common/MyString.h" + +namespace NWindows { +namespace NRegistry { + +LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value); + +class CKey +{ + HKEY _object; + + LONG QueryValueEx(LPCTSTR lpValueName, LPDWORD lpType, + LPBYTE lpData, LPDWORD lpcbData) + { + return RegQueryValueEx(_object, lpValueName, NULL, lpType, lpData, lpcbData); + } + +public: + CKey(): _object(NULL) {} + ~CKey() { Close(); } + + operator HKEY() const { return _object; } + void Attach(HKEY key) { _object = key; } + HKEY Detach() + { + const HKEY key = _object; + _object = NULL; + return key; + } + + LONG Create(HKEY parentKey, LPCTSTR keyName, + LPTSTR keyClass = REG_NONE, + DWORD options = REG_OPTION_NON_VOLATILE, + REGSAM accessMask = KEY_ALL_ACCESS, + LPSECURITY_ATTRIBUTES securityAttributes = NULL, + LPDWORD disposition = NULL) throw(); + LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS) throw(); + + LONG Close() throw(); + + LONG DeleteSubKey(LPCTSTR subKeyName) throw(); + LONG RecurseDeleteKey(LPCTSTR subKeyName) throw(); + + LONG DeleteValue(LPCTSTR name) throw(); +#ifndef _UNICODE + LONG DeleteValue(LPCWSTR name); +#endif + + LONG SetValue(LPCTSTR valueName, UInt32 value) throw(); + LONG SetValue(LPCTSTR valueName, bool value) throw(); + LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw(); + // LONG SetValue(LPCTSTR valueName, const CSysString &value); +#ifndef _UNICODE + LONG SetValue(LPCWSTR name, LPCWSTR value); + // LONG SetValue(LPCWSTR name, const UString &value); +#endif + + LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw(); + + LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings); + LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings); + + LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(); + + // GetValue_[type]_IfOk(): + // if (return_result == ERROR_SUCCESS), (value) variable was read from registry + // if (return_result != ERROR_SUCCESS), (value) variable was not changed + LONG GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw(); + LONG GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw(); + LONG GetValue_bool_IfOk(LPCTSTR name, bool &value) throw(); + + // QueryValue(): + // if (return_result == ERROR_SUCCESS), (value) string was read from registry + // if (return_result != ERROR_SUCCESS), (value) string was cleared + LONG QueryValue(LPCTSTR name, CSysString &value); +#ifndef _UNICODE + LONG QueryValue(LPCWSTR name, UString &value); +#endif + + // QueryValue_Binary(): + // if (return_result == ERROR_SUCCESS), (value) buffer was read from registry (BINARY data) + // if (return_result != ERROR_SUCCESS), (value) buffer was cleared + LONG QueryValue_Binary(LPCTSTR name, CByteBuffer &value); + + LONG EnumKeys(CSysStringVector &keyNames); +}; + +}} + +#endif diff --git a/CPP/Windows/ResourceString.cpp b/CPP/Windows/ResourceString.cpp index 099a884da..ae8182ed4 100644 --- a/CPP/Windows/ResourceString.cpp +++ b/CPP/Windows/ResourceString.cpp @@ -1,103 +1,103 @@ -// Windows/ResourceString.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif - -#include "ResourceString.h" - -extern HINSTANCE g_hInstance; -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { - -#ifndef _UNICODE - -static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID) -{ - CSysString s; - int size = 128; - int len; - do - { - size <<= 1; - len = ::LoadString(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); - } - while (size - len <= 1); - s.ReleaseBuf_CalcLen((unsigned)len); - return s; -} - -#endif - -static const int kStartSize = 256; - -static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s) -{ - int size = kStartSize; - int len; - do - { - size <<= 1; - len = ::LoadStringW(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); - } - while (size - len <= 1); - s.ReleaseBuf_CalcLen((unsigned)len); -} - -// NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it. - -UString MyLoadString(UINT resourceID) -{ - #ifndef _UNICODE - if (!g_IsNT) - return GetUnicodeString(MyLoadStringA(g_hInstance, resourceID)); - else - #endif - { - { - wchar_t s[kStartSize]; - s[0] = 0; - int len = ::LoadStringW(g_hInstance, resourceID, s, kStartSize); - if (kStartSize - len > 1) - return s; - } - UString dest; - MyLoadString2(g_hInstance, resourceID, dest); - return dest; - } -} - -void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest) -{ - dest.Empty(); - #ifndef _UNICODE - if (!g_IsNT) - MultiByteToUnicodeString2(dest, MyLoadStringA(hInstance, resourceID)); - else - #endif - { - { - wchar_t s[kStartSize]; - s[0] = 0; - int len = ::LoadStringW(hInstance, resourceID, s, kStartSize); - if (kStartSize - len > 1) - { - dest = s; - return; - } - } - MyLoadString2(hInstance, resourceID, dest); - } -} - -void MyLoadString(UINT resourceID, UString &dest) -{ - MyLoadString(g_hInstance, resourceID, dest); -} - -} +// Windows/ResourceString.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#include "ResourceString.h" + +extern HINSTANCE g_hInstance; +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +#ifndef _UNICODE + +static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID) +{ + CSysString s; + int size = 128; + int len; + do + { + size <<= 1; + len = ::LoadString(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); + } + while (size - len <= 1); + s.ReleaseBuf_CalcLen((unsigned)len); + return s; +} + +#endif + +static const int kStartSize = 256; + +static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s) +{ + int size = kStartSize; + int len; + do + { + size <<= 1; + len = ::LoadStringW(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); + } + while (size - len <= 1); + s.ReleaseBuf_CalcLen((unsigned)len); +} + +// NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it. + +UString MyLoadString(UINT resourceID) +{ + #ifndef _UNICODE + if (!g_IsNT) + return GetUnicodeString(MyLoadStringA(g_hInstance, resourceID)); + else + #endif + { + { + wchar_t s[kStartSize]; + s[0] = 0; + int len = ::LoadStringW(g_hInstance, resourceID, s, kStartSize); + if (kStartSize - len > 1) + return s; + } + UString dest; + MyLoadString2(g_hInstance, resourceID, dest); + return dest; + } +} + +void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest) +{ + dest.Empty(); + #ifndef _UNICODE + if (!g_IsNT) + MultiByteToUnicodeString2(dest, MyLoadStringA(hInstance, resourceID)); + else + #endif + { + { + wchar_t s[kStartSize]; + s[0] = 0; + int len = ::LoadStringW(hInstance, resourceID, s, kStartSize); + if (kStartSize - len > 1) + { + dest = s; + return; + } + } + MyLoadString2(hInstance, resourceID, dest); + } +} + +void MyLoadString(UINT resourceID, UString &dest) +{ + MyLoadString(g_hInstance, resourceID, dest); +} + +} diff --git a/CPP/Windows/ResourceString.h b/CPP/Windows/ResourceString.h index 0bb9f902c..773307b93 100644 --- a/CPP/Windows/ResourceString.h +++ b/CPP/Windows/ResourceString.h @@ -1,17 +1,17 @@ -// Windows/ResourceString.h - -#ifndef ZIP7_INC_WINDOWS_RESOURCE_STRING_H -#define ZIP7_INC_WINDOWS_RESOURCE_STRING_H - -#include "../Common/MyString.h" -#include "../Common/MyWindows.h" - -namespace NWindows { - -UString MyLoadString(UINT resourceID); -void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest); -void MyLoadString(UINT resourceID, UString &dest); - -} - -#endif +// Windows/ResourceString.h + +#ifndef ZIP7_INC_WINDOWS_RESOURCE_STRING_H +#define ZIP7_INC_WINDOWS_RESOURCE_STRING_H + +#include "../Common/MyString.h" +#include "../Common/MyWindows.h" + +namespace NWindows { + +UString MyLoadString(UINT resourceID); +void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest); +void MyLoadString(UINT resourceID, UString &dest); + +} + +#endif diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp index 112b7aa51..d4282d070 100644 --- a/CPP/Windows/SecurityUtils.cpp +++ b/CPP/Windows/SecurityUtils.cpp @@ -1,186 +1,186 @@ -// Windows/SecurityUtils.cpp - -#include "StdAfx.h" - -#include "SecurityUtils.h" - -namespace NWindows { -namespace NSecurity { - -/* -bool MyLookupAccountSid(LPCTSTR systemName, PSID sid, - CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse) -{ - DWORD accountNameSize = 0, domainNameSize = 0; - - if (!::LookupAccountSid(systemName, sid, - accountName.GetBuf(0), &accountNameSize, - domainName.GetBuf(0), &domainNameSize, sidNameUse)) - { - if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return false; - } - DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize; - bool result = BOOLToBool(::LookupAccountSid(systemName, sid, - accountName.GetBuf(accountNameSize), &accountNameSize2, - domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse)); - accountName.ReleaseBuf_CalcLen(accountNameSize); - domainName.ReleaseBuf_CalcLen(domainNameSize); - return result; -} -*/ - -static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest) -{ - const size_t len = (size_t)wcslen(src); - dest->Length = (USHORT)(len * sizeof(WCHAR)); - dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR)); - dest->Buffer = src; -} - -/* -static void MyLookupSids(CPolicy &policy, PSID ps) -{ - LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL; - LSA_TRANSLATED_NAME *names = NULL; - NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names); - int res = LsaNtStatusToWinError(nts); - LsaFreeMemory(referencedDomains); - LsaFreeMemory(names); -} -*/ - -extern "C" { - -#ifndef _UNICODE -typedef BOOL (WINAPI * Func_LookupAccountNameW)( - LPCWSTR lpSystemName, - LPCWSTR lpAccountName, - PSID Sid, - LPDWORD cbSid, - LPWSTR ReferencedDomainName, - LPDWORD cchReferencedDomainName, - PSID_NAME_USE peUse - ); -#endif - -} - -static PSID GetSid(LPWSTR accountName) -{ - #ifndef _UNICODE - const HMODULE hModule = GetModuleHandle(TEXT("advapi32.dll")); - if (!hModule) - return NULL; - const - Func_LookupAccountNameW lookupAccountNameW = Z7_GET_PROC_ADDRESS( - Func_LookupAccountNameW, hModule, - "LookupAccountNameW"); - if (!lookupAccountNameW) - return NULL; - #endif - - DWORD sidLen = 0, domainLen = 0; - SID_NAME_USE sidNameUse; - if (! - #ifdef _UNICODE - ::LookupAccountNameW - #else - lookupAccountNameW - #endif - (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse)) - { - if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - const PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen); - LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR)); - const BOOL res = - #ifdef _UNICODE - ::LookupAccountNameW - #else - lookupAccountNameW - #endif - (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse); - ::HeapFree(GetProcessHeap(), 0, domainName); - if (res) - return pSid; - } - } - return NULL; -} - -#define Z7_WIN_SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege" - -bool AddLockMemoryPrivilege() -{ - CPolicy policy; - LSA_OBJECT_ATTRIBUTES attr; - attr.Length = sizeof(attr); - attr.RootDirectory = NULL; - attr.ObjectName = NULL; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - if (policy.Open(NULL, &attr, - // GENERIC_WRITE) - POLICY_ALL_ACCESS) - // STANDARD_RIGHTS_REQUIRED, - // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES) - != 0) - return false; - LSA_UNICODE_STRING userRights; - wchar_t s[128] = Z7_WIN_SE_LOCK_MEMORY_NAME; - SetLsaString(s, &userRights); - WCHAR userName[256 + 2]; - DWORD size = 256; - if (!GetUserNameW(userName, &size)) - return false; - const PSID psid = GetSid(userName); - if (psid == NULL) - return false; - bool res = false; - - /* - PLSA_UNICODE_STRING userRightsArray; - ULONG countOfRights; - NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights); - if (status != 0) - return false; - bool finded = false; - for (ULONG i = 0; i < countOfRights; i++) - { - LSA_UNICODE_STRING &ur = userRightsArray[i]; - if (ur.Length != s.Length() * sizeof(WCHAR)) - continue; - if (wcsncmp(ur.Buffer, s, s.Length()) != 0) - continue; - finded = true; - res = true; - break; - } - if (!finded) - */ - { - /* - LSA_ENUMERATION_INFORMATION *enums; - ULONG countReturned; - NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned); - if (status == 0) - { - for (ULONG i = 0; i < countReturned; i++) - MyLookupSids(policy, enums[i].Sid); - if (enums) - ::LsaFreeMemory(enums); - res = true; - } - */ - const NTSTATUS status = policy.AddAccountRights(psid, &userRights); - if (status == 0) - res = true; - // ULONG res = LsaNtStatusToWinError(status); - } - HeapFree(GetProcessHeap(), 0, psid); - return res; -} - -}} +// Windows/SecurityUtils.cpp + +#include "StdAfx.h" + +#include "SecurityUtils.h" + +namespace NWindows { +namespace NSecurity { + +/* +bool MyLookupAccountSid(LPCTSTR systemName, PSID sid, + CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse) +{ + DWORD accountNameSize = 0, domainNameSize = 0; + + if (!::LookupAccountSid(systemName, sid, + accountName.GetBuf(0), &accountNameSize, + domainName.GetBuf(0), &domainNameSize, sidNameUse)) + { + if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return false; + } + DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize; + bool result = BOOLToBool(::LookupAccountSid(systemName, sid, + accountName.GetBuf(accountNameSize), &accountNameSize2, + domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse)); + accountName.ReleaseBuf_CalcLen(accountNameSize); + domainName.ReleaseBuf_CalcLen(domainNameSize); + return result; +} +*/ + +static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest) +{ + const size_t len = (size_t)wcslen(src); + dest->Length = (USHORT)(len * sizeof(WCHAR)); + dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR)); + dest->Buffer = src; +} + +/* +static void MyLookupSids(CPolicy &policy, PSID ps) +{ + LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL; + LSA_TRANSLATED_NAME *names = NULL; + NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names); + int res = LsaNtStatusToWinError(nts); + LsaFreeMemory(referencedDomains); + LsaFreeMemory(names); +} +*/ + +extern "C" { + +#ifndef _UNICODE +typedef BOOL (WINAPI * Func_LookupAccountNameW)( + LPCWSTR lpSystemName, + LPCWSTR lpAccountName, + PSID Sid, + LPDWORD cbSid, + LPWSTR ReferencedDomainName, + LPDWORD cchReferencedDomainName, + PSID_NAME_USE peUse + ); +#endif + +} + +static PSID GetSid(LPWSTR accountName) +{ + #ifndef _UNICODE + const HMODULE hModule = GetModuleHandle(TEXT("advapi32.dll")); + if (!hModule) + return NULL; + const + Func_LookupAccountNameW lookupAccountNameW = Z7_GET_PROC_ADDRESS( + Func_LookupAccountNameW, hModule, + "LookupAccountNameW"); + if (!lookupAccountNameW) + return NULL; + #endif + + DWORD sidLen = 0, domainLen = 0; + SID_NAME_USE sidNameUse; + if (! + #ifdef _UNICODE + ::LookupAccountNameW + #else + lookupAccountNameW + #endif + (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse)) + { + if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + const PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen); + LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR)); + const BOOL res = + #ifdef _UNICODE + ::LookupAccountNameW + #else + lookupAccountNameW + #endif + (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse); + ::HeapFree(GetProcessHeap(), 0, domainName); + if (res) + return pSid; + } + } + return NULL; +} + +#define Z7_WIN_SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege" + +bool AddLockMemoryPrivilege() +{ + CPolicy policy; + LSA_OBJECT_ATTRIBUTES attr; + attr.Length = sizeof(attr); + attr.RootDirectory = NULL; + attr.ObjectName = NULL; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + if (policy.Open(NULL, &attr, + // GENERIC_WRITE) + POLICY_ALL_ACCESS) + // STANDARD_RIGHTS_REQUIRED, + // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES) + != 0) + return false; + LSA_UNICODE_STRING userRights; + wchar_t s[128] = Z7_WIN_SE_LOCK_MEMORY_NAME; + SetLsaString(s, &userRights); + WCHAR userName[256 + 2]; + DWORD size = 256; + if (!GetUserNameW(userName, &size)) + return false; + const PSID psid = GetSid(userName); + if (psid == NULL) + return false; + bool res = false; + + /* + PLSA_UNICODE_STRING userRightsArray; + ULONG countOfRights; + NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights); + if (status != 0) + return false; + bool finded = false; + for (ULONG i = 0; i < countOfRights; i++) + { + LSA_UNICODE_STRING &ur = userRightsArray[i]; + if (ur.Length != s.Length() * sizeof(WCHAR)) + continue; + if (wcsncmp(ur.Buffer, s, s.Length()) != 0) + continue; + finded = true; + res = true; + break; + } + if (!finded) + */ + { + /* + LSA_ENUMERATION_INFORMATION *enums; + ULONG countReturned; + NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned); + if (status == 0) + { + for (ULONG i = 0; i < countReturned; i++) + MyLookupSids(policy, enums[i].Sid); + if (enums) + ::LsaFreeMemory(enums); + res = true; + } + */ + const NTSTATUS status = policy.AddAccountRights(psid, &userRights); + if (status == 0) + res = true; + // ULONG res = LsaNtStatusToWinError(status); + } + HeapFree(GetProcessHeap(), 0, psid); + return res; +} + +}} diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h index a59796e2a..7219f065f 100644 --- a/CPP/Windows/SecurityUtils.h +++ b/CPP/Windows/SecurityUtils.h @@ -1,150 +1,150 @@ -// Windows/SecurityUtils.h - -#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H -#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H - -#include - -#include "Defs.h" - -#ifndef _UNICODE - -extern "C" { -typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName, - PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); -typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle); -typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle, - PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); -#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) -} - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -#define POLICY_FUNC_CALL(fff, str) \ - if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \ - const Func_ ## fff v = Z7_GET_PROC_ADDRESS(Func_ ## fff, hModule, str); \ - if (!v) return MY_STATUS_NOT_IMPLEMENTED; \ - const NTSTATUS res = v - -#else - -#define POLICY_FUNC_CALL(fff, str) \ - const NTSTATUS res = ::fff - -#endif - - -namespace NWindows { -namespace NSecurity { - -class CAccessToken -{ - HANDLE _handle; -public: - CAccessToken(): _handle(NULL) {} - ~CAccessToken() { Close(); } - bool Close() - { - if (_handle == NULL) - return true; - bool res = BOOLToBool(::CloseHandle(_handle)); - if (res) - _handle = NULL; - return res; - } - - bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess) - { - Close(); - return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle)); - } - - /* - bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf) - { - Close(); - return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle)); - } - */ - - bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState, - DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength) - { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges), - newState, bufferLength, previousState, returnLength)); } - - bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState) - { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); } - - bool AdjustPrivileges(PTOKEN_PRIVILEGES newState) - { return AdjustPrivileges(false, newState); } - -}; - - - - -struct CPolicy -{ -protected: - LSA_HANDLE _handle; - #ifndef _UNICODE - HMODULE hModule; - #endif -public: - operator LSA_HANDLE() const { return _handle; } - CPolicy(): _handle(NULL) - { - #ifndef _UNICODE - hModule = GetModuleHandle(TEXT("advapi32.dll")); - #endif - } - ~CPolicy() { Close(); } - - NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, - ACCESS_MASK desiredAccess) - { - Close(); - POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy") - (systemName, objectAttributes, desiredAccess, &_handle); - return res; - } - - NTSTATUS Close() - { - if (_handle == NULL) - return 0; - POLICY_FUNC_CALL (LsaClose, "LsaClose") - (_handle); - _handle = NULL; - return res; - } - - NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights, - PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned) - { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); } - - NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights) - { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); } - - NTSTATUS LookupSids(ULONG count, PSID* sids, - PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names) - { return LsaLookupSids(_handle, count, sids, referencedDomains, names); } - - NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) - { - POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights") - (_handle, accountSid, userRights, countOfRights); - return res; - } - NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) - { return AddAccountRights(accountSid, userRights, 1); } - - NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights) - { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); } -}; - -bool AddLockMemoryPrivilege(); - -}} - -#endif +// Windows/SecurityUtils.h + +#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H +#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H + +#include + +#include "Defs.h" + +#ifndef _UNICODE + +extern "C" { +typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName, + PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); +typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle); +typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle, + PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); +#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +} + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +#define POLICY_FUNC_CALL(fff, str) \ + if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \ + const Func_ ## fff v = Z7_GET_PROC_ADDRESS(Func_ ## fff, hModule, str); \ + if (!v) return MY_STATUS_NOT_IMPLEMENTED; \ + const NTSTATUS res = v + +#else + +#define POLICY_FUNC_CALL(fff, str) \ + const NTSTATUS res = ::fff + +#endif + + +namespace NWindows { +namespace NSecurity { + +class CAccessToken +{ + HANDLE _handle; +public: + CAccessToken(): _handle(NULL) {} + ~CAccessToken() { Close(); } + bool Close() + { + if (_handle == NULL) + return true; + bool res = BOOLToBool(::CloseHandle(_handle)); + if (res) + _handle = NULL; + return res; + } + + bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess) + { + Close(); + return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle)); + } + + /* + bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf) + { + Close(); + return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle)); + } + */ + + bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState, + DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength) + { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges), + newState, bufferLength, previousState, returnLength)); } + + bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState) + { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); } + + bool AdjustPrivileges(PTOKEN_PRIVILEGES newState) + { return AdjustPrivileges(false, newState); } + +}; + + + + +struct CPolicy +{ +protected: + LSA_HANDLE _handle; + #ifndef _UNICODE + HMODULE hModule; + #endif +public: + operator LSA_HANDLE() const { return _handle; } + CPolicy(): _handle(NULL) + { + #ifndef _UNICODE + hModule = GetModuleHandle(TEXT("advapi32.dll")); + #endif + } + ~CPolicy() { Close(); } + + NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, + ACCESS_MASK desiredAccess) + { + Close(); + POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy") + (systemName, objectAttributes, desiredAccess, &_handle); + return res; + } + + NTSTATUS Close() + { + if (_handle == NULL) + return 0; + POLICY_FUNC_CALL (LsaClose, "LsaClose") + (_handle); + _handle = NULL; + return res; + } + + NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights, + PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned) + { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); } + + NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights) + { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); } + + NTSTATUS LookupSids(ULONG count, PSID* sids, + PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names) + { return LsaLookupSids(_handle, count, sids, referencedDomains, names); } + + NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) + { + POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights") + (_handle, accountSid, userRights, countOfRights); + return res; + } + NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) + { return AddAccountRights(accountSid, userRights, 1); } + + NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights) + { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); } +}; + +bool AddLockMemoryPrivilege(); + +}} + +#endif diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp index 4bd900052..01ceb2288 100644 --- a/CPP/Windows/Shell.cpp +++ b/CPP/Windows/Shell.cpp @@ -1,839 +1,839 @@ -// Windows/Shell.cpp - -#include "StdAfx.h" - -#include "../Common/MyCom.h" -#include "../Common/StringConvert.h" - -#include "COM.h" -#include "FileName.h" -#include "MemoryGlobal.h" -#include "Shell.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -// MSVC6 and old SDK don't support this function: -// #define LWSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE -// LWSTDAPI StrRetToStrW(STRRET *pstr, LPCITEMIDLIST pidl, LPWSTR *ppsz); - -// #define SHOW_DEBUG_SHELL - -#ifdef SHOW_DEBUG_SHELL - -#include "../Common/IntToString.h" - -static void Print_Number(UInt32 number, const char *s) -{ - AString s2; - s2.Add_UInt32(number); - s2.Add_Space(); - s2 += s; - OutputDebugStringA(s2); -} - -#define ODS(sz) { OutputDebugStringA(sz); } -#define ODS_U(s) { OutputDebugStringW(s); } -#define ODS_(op) { op; } - -#else - -#define ODS(sz) -#define ODS_U(s) -#define ODS_(op) - -#endif - - -namespace NWindows { -namespace NShell { - -#ifndef UNDER_CE - -// SHGetMalloc is unsupported in Windows Mobile? - -void CItemIDList::Free() -{ - if (!m_Object) - return; - /* DOCs: - SHGetMalloc was introduced in Windows 95 and Microsoft Windows NT 4.0, - but as of Windows 2000 it is no longer necessary. - In its place, programs can call the equivalent (and easier to use) CoTaskMemAlloc and CoTaskMemFree. - Description from oldnewthings: - shell functions could work without COM (if OLE32.DLL is not loaded), - but now if OLE32.DLL is loaded, then shell functions and com functions do same things. - 22.02: so we use OLE32.DLL function to free memory: - */ - /* - CMyComPtr shellMalloc; - if (::SHGetMalloc(&shellMalloc) != NOERROR) - throw 41099; - shellMalloc->Free(m_Object); - */ - CoTaskMemFree(m_Object); - m_Object = NULL; -} - -/* -CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL) - { *this = itemIDList; } -CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL) - { *this = itemIDList; } - -CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object) -{ - Free(); - if (object != 0) - { - UINT32 size = GetSize(object); - m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size); - if (m_Object != NULL) - MoveMemory(m_Object, object, size); - } - return *this; -} - -CItemIDList& CItemIDList::operator=(const CItemIDList &object) -{ - Free(); - if (object.m_Object != NULL) - { - UINT32 size = GetSize(object.m_Object); - m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size); - if (m_Object != NULL) - MoveMemory(m_Object, object.m_Object, size); - } - return *this; -} -*/ - - -static HRESULT ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names) -{ - names.Clear(); - const wchar_t *lim = p + size; - UString s; - /* - if (size == 0 || p[size - 1] != 0) - return E_INVALIDARG; - if (size == 1) - return S_OK; - if (p[size - 2] != 0) - return E_INVALIDARG; - */ - for (;;) - { - const wchar_t *start = p; - for (;;) - { - if (p == lim) return E_INVALIDARG; // S_FALSE - if (*p++ == 0) - break; - } - const size_t num = (size_t)(p - start); - if (num == 1) - { - if (p != lim) return E_INVALIDARG; // S_FALSE - return S_OK; - } - s.SetFrom(start, (unsigned)(num - 1)); - ODS_U(s) - names.Add(s); - // names.ReserveOnePosition(); - // names.AddInReserved_Ptr_of_new(new UString((unsigned)num - 1, start)); - } -} - - -static HRESULT ReadAnsiStrings(const char *p, size_t size, UStringVector &names) -{ - names.Clear(); - AString name; - for (; size != 0; size--) - { - const char c = *p++; - if (c == 0) - { - if (name.IsEmpty()) - return S_OK; - names.Add(GetUnicodeString(name)); - name.Empty(); - } - else - name.Add_Char(c); - } - return E_INVALIDARG; -} - - -#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } - -static HRESULT DataObject_GetData_HGLOBAL(IDataObject *dataObject, CLIPFORMAT cf, NCOM::CStgMedium &medium) -{ - FORMATETC etc = INIT_FORMATETC_HGLOBAL(cf); - RINOK(dataObject->GetData(&etc, &medium)) - if (medium.tymed != TYMED_HGLOBAL) - return E_INVALIDARG; - return S_OK; -} - -static HRESULT DataObject_GetData_HDROP_Names(IDataObject *dataObject, UStringVector &names) -{ - names.Clear(); - NCOM::CStgMedium medium; - - /* Win10 : if (dataObject) is from IContextMenu::Initialize() and - if (len_of_path >= MAX_PATH (260) for some file in data object) - { - GetData() returns HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - "The data area passed to a system call is too small", - Is there a way to fix this code for long paths? - } */ - - RINOK(DataObject_GetData_HGLOBAL(dataObject, CF_HDROP, medium)) - const size_t blockSize = GlobalSize(medium.hGlobal); - if (blockSize < sizeof(DROPFILES)) - return E_INVALIDARG; - NMemory::CGlobalLock dropLock(medium.hGlobal); - const DROPFILES *dropFiles = (const DROPFILES *)dropLock.GetPointer(); - if (!dropFiles) - return E_INVALIDARG; - if (blockSize < dropFiles->pFiles - || dropFiles->pFiles < sizeof(DROPFILES) - // || dropFiles->pFiles != sizeof(DROPFILES) - ) - return E_INVALIDARG; - const size_t size = blockSize - dropFiles->pFiles; - const void *namesData = (const Byte *)(const void *)dropFiles + dropFiles->pFiles; - HRESULT hres; - if (dropFiles->fWide) - { - if (size % sizeof(wchar_t) != 0) - return E_INVALIDARG; - hres = ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names); - } - else - hres = ReadAnsiStrings((const char *)namesData, size, names); - - ODS_(Print_Number(names.Size(), "DataObject_GetData_HDROP_Names")) - return hres; -} - - - -// CF_IDLIST: -#define MYWIN_CFSTR_SHELLIDLIST TEXT("Shell IDList Array") - -typedef struct -{ - UINT cidl; - UINT aoffset[1]; -} MYWIN_CIDA; -/* - cidl : number of PIDLs that are being transferred, not including the parent folder. - aoffset : An array of offsets, relative to the beginning of this structure. - aoffset[0] - fully qualified PIDL of a parent folder. - If this PIDL is empty, the parent folder is the desktop. - aoffset[1] ... aoffset[cidl] : offset to one of the PIDLs to be transferred. - All of these PIDLs are relative to the PIDL of the parent folder. -*/ - -static HRESULT DataObject_GetData_IDLIST(IDataObject *dataObject, UStringVector &names) -{ - names.Clear(); - NCOM::CStgMedium medium; - RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT) - RegisterClipboardFormat(MYWIN_CFSTR_SHELLIDLIST), medium)) - const size_t blockSize = GlobalSize(medium.hGlobal); - if (blockSize < sizeof(MYWIN_CIDA) || blockSize >= (UInt32)((UInt32)0 - 1)) - return E_INVALIDARG; - NMemory::CGlobalLock dropLock(medium.hGlobal); - const MYWIN_CIDA *cida = (const MYWIN_CIDA *)dropLock.GetPointer(); - if (!cida) - return E_INVALIDARG; - if (cida->cidl == 0) - { - // is it posssible to have no selected items? - // it's unexpected case. - return E_INVALIDARG; - } - if (cida->cidl >= (blockSize - (UInt32)sizeof(MYWIN_CIDA)) / sizeof(UINT)) - return E_INVALIDARG; - const UInt32 start = cida->cidl * (UInt32)sizeof(UINT) + (UInt32)sizeof(MYWIN_CIDA); - - STRRET strret; - CMyComPtr parentFolder; - { - const UINT offset = cida->aoffset[0]; - if (offset < start || offset >= blockSize - // || offset != start - ) - return E_INVALIDARG; - - CMyComPtr desktopFolder; - RINOK(::SHGetDesktopFolder(&desktopFolder)) - if (!desktopFolder) - return E_FAIL; - - LPCITEMIDLIST const lpcItem = (LPCITEMIDLIST)(const void *)((const Byte *)cida + offset); - - #ifdef SHOW_DEBUG_SHELL - { - const HRESULT res = desktopFolder->GetDisplayNameOf( - lpcItem, SHGDN_FORPARSING, &strret); - if (res == S_OK && strret.uType == STRRET_WSTR) - { - ODS_U(strret.pOleStr) - /* if lpcItem is empty, the path will be - "C:\Users\user_name\Desktop" - if lpcItem is "My Computer" folder, the path will be - "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" */ - CoTaskMemFree(strret.pOleStr); - } - } - #endif - - RINOK(desktopFolder->BindToObject(lpcItem, - NULL, IID_IShellFolder, (void **)&parentFolder)) - if (!parentFolder) - return E_FAIL; - } - - names.ClearAndReserve(cida->cidl); - UString path; - - // for (int y = 0; y < 1; y++) // for debug - for (unsigned i = 1; i <= cida->cidl; i++) - { - const UINT offset = cida->aoffset[i]; - if (offset < start || offset >= blockSize) - return E_INVALIDARG; - const void *p = (const Byte *)(const void *)cida + offset; - /* ITEMIDLIST of file can contain more than one SHITEMID item. - In win10 only SHGDN_FORPARSING returns path that contains - all path parts related to parts of ITEMIDLIST. - So we can use only SHGDN_FORPARSING here. - Don't use (SHGDN_INFOLDER) - Don't use (SHGDN_INFOLDER | SHGDN_FORPARSING) - */ - RINOK(parentFolder->GetDisplayNameOf((LPCITEMIDLIST)p, SHGDN_FORPARSING, &strret)) - - /* - // MSVC6 and old SDK do not support StrRetToStrW(). - LPWSTR lpstr; - RINOK (StrRetToStrW(&strret, NULL, &lpstr)) - ODS_U(lpstr) - path = lpstr; - CoTaskMemFree(lpstr); - */ - if (strret.uType != STRRET_WSTR) - return E_INVALIDARG; - ODS_U(strret.pOleStr) - path = strret.pOleStr; - // the path could have super path prefix "\\\\?\\" - // we can remove super path prefix here, if we don't need that prefix - #ifdef Z7_LONG_PATH - // we remove super prefix, if we can work without that prefix - NFile::NName::If_IsSuperPath_RemoveSuperPrefix(path); - #endif - names.AddInReserved(path); - CoTaskMemFree(strret.pOleStr); - } - - ODS_(Print_Number(cida->cidl, "CFSTR_SHELLIDLIST END")) - return S_OK; -} - - -HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &paths) -{ - ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names START") - HRESULT hres = NShell::DataObject_GetData_HDROP_Names(dataObject, paths); - // if (hres == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) - if (hres != S_OK) - { - ODS("-- DataObject_GetData_IDLIST START") - // for (int y = 0; y < 10000; y++) // for debug - hres = NShell::DataObject_GetData_IDLIST(dataObject, paths); - } - ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names END") - return hres; -} - - - -// #if (NTDDI_VERSION >= NTDDI_VISTA) -typedef struct -{ - UINT cItems; // number of items in rgdwFileAttributes array - DWORD dwSumFileAttributes; // all of the attributes ORed together - DWORD dwProductFileAttributes; // all of the attributes ANDed together - DWORD rgdwFileAttributes[1]; // array -} MYWIN_FILE_ATTRIBUTES_ARRAY; - -#define MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY TEXT("File Attributes Array") - -HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs) -{ - attribs.Clear(); - NCOM::CStgMedium medium; - RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT) - RegisterClipboardFormat(MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY), medium)) - const size_t blockSize = GlobalSize(medium.hGlobal); - if (blockSize < sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY)) - return E_INVALIDARG; - NMemory::CGlobalLock dropLock(medium.hGlobal); - const MYWIN_FILE_ATTRIBUTES_ARRAY *faa = (const MYWIN_FILE_ATTRIBUTES_ARRAY *)dropLock.GetPointer(); - if (!faa) - return E_INVALIDARG; - const unsigned numFiles = faa->cItems; - if (numFiles == 0) - { - // is it posssible to have empty array here? - return E_INVALIDARG; - } - if ((blockSize - (sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY) - sizeof(DWORD))) - / sizeof(DWORD) != numFiles) - return E_INVALIDARG; - // attribs.Sum = faa->dwSumFileAttributes; - // attribs.Product = faa->dwProductFileAttributes; - // attribs.Vals.SetFromArray(faa->rgdwFileAttributes, numFiles); - // attribs.IsDirVector.ClearAndSetSize(numFiles); - - if ((faa->dwSumFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) - { - /* in win10: if selected items are volumes (c:\, d:\ ..) in My Compter, - all items have FILE_ATTRIBUTE_DIRECTORY attribute - ntfs volume also have FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM - udf volume: FILE_ATTRIBUTE_READONLY - dvd-rom device: (-1) : all bits are set - */ - const DWORD *attr = faa->rgdwFileAttributes; - // DWORD product = (UInt32)0 - 1, sum = 0; - for (unsigned i = 0; i < numFiles; i++) - { - if (attr[i] & FILE_ATTRIBUTE_DIRECTORY) - { - // attribs.ThereAreDirs = true; - attribs.FirstDirIndex = (int)i; - break; - } - // attribs.IsDirVector[i] = (attr[i] & FILE_ATTRIBUTE_DIRECTORY) != 0; - // product &= v; - // sum |= v; - } - // ODS_(Print_Number(product, "Product calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) - // ODS_(Print_Number(sum, "Sum calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) - } - // ODS_(Print_Number(attribs.Product, "Product FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) - // ODS_(Print_Number(attribs.Sum, "Sum FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) - ODS_(Print_Number(numFiles, "FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) - return S_OK; -} - - -///////////////////////////// -// CDrop - -/* - win10: - DragQueryFile() implementation code is not effective because - there is no pointer inside DROP internal file list, so - DragQueryFile(fileIndex) runs all names in range [0, fileIndex]. - DragQueryFile(,, buf, bufSize) - if (buf == NULL) by spec - { - returns value is the required size - in characters, of the buffer, not including the terminating null character - tests show that if (bufSize == 0), then it also returns required size. - } - if (bufSize != NULL) - { - returns: the count of the characters copied, not including null character. - win10: null character is also copied at position buf[ret_count]; - } -*/ - -/* -void CDrop::Attach(HDROP object) -{ - Free(); - m_Object = object; - m_Assigned = true; -} - -void CDrop::Free() -{ - if (m_MustBeFinished && m_Assigned) - Finish(); - m_Assigned = false; -} - -UINT CDrop::QueryCountOfFiles() -{ - return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0); -} - -void CDrop::QueryFileName(UINT fileIndex, UString &fileName) -{ - #ifndef _UNICODE - if (!g_IsNT) - { - AString fileNameA; - const UINT len = QueryFile(fileIndex, (LPTSTR)NULL, 0); - const UINT numCopied = QueryFile(fileIndex, fileNameA.GetBuf(len + 2), len + 2); - fileNameA.ReleaseBuf_CalcLen(len); - if (numCopied != len) - throw 20221223; - fileName = GetUnicodeString(fileNameA); - } - else - #endif - { - // kReserve must be >= 3 for additional buffer size - // safety and for optimal performance - const unsigned kReserve = 3; - { - unsigned len = 0; - wchar_t *buf = fileName.GetBuf_GetMaxAvail(len); - if (len >= kReserve) - { - const UINT numCopied = QueryFile(fileIndex, buf, len); - if (numCopied < len - 1) - { - // (numCopied < len - 1) case means that it have copied full string. - fileName.ReleaseBuf_CalcLen(numCopied); - return; - } - } - } - const UINT len = QueryFile(fileIndex, (LPWSTR)NULL, 0); - const UINT numCopied = QueryFile(fileIndex, - fileName.GetBuf(len + kReserve), len + kReserve); - fileName.ReleaseBuf_CalcLen(len); - if (numCopied != len) - throw 20221223; - } -} - - -void CDrop::QueryFileNames(UStringVector &fileNames) -{ - UINT numFiles = QueryCountOfFiles(); - - Print_Number(numFiles, "\n====== CDrop::QueryFileNames START ===== \n"); - - fileNames.ClearAndReserve(numFiles); - UString s; - for (UINT i = 0; i < numFiles; i++) - { - QueryFileName(i, s); - if (!s.IsEmpty()) - fileNames.AddInReserved(s); - } - Print_Number(numFiles, "\n====== CDrop::QueryFileNames END ===== \n"); -} -*/ - - -// #if (NTDDI_VERSION >= NTDDI_VISTA) -// SHGetPathFromIDListEx returns a win32 file system path for the item in the name space. -typedef int Z7_WIN_GPFIDL_FLAGS; - -extern "C" { -#ifndef _UNICODE -typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath); // nt4 -#endif - -#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0600 // Vista -#define Z7_USE_DYN_SHGetPathFromIDListEx -#endif - -#ifdef Z7_USE_DYN_SHGetPathFromIDListEx -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION -typedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts); // vista -#endif -} - -#ifndef _UNICODE - -bool GetPathFromIDList(LPCITEMIDLIST itemIDList, AString &path) -{ - path.Empty(); - const unsigned len = MAX_PATH + 16; - const bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); - path.ReleaseBuf_CalcLen(len); - return result; -} - -#endif - -bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) -{ - path.Empty(); - unsigned len = MAX_PATH + 16; - -#ifdef _UNICODE - bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); -#else - const - Func_SHGetPathFromIDListW - shGetPathFromIDListW = Z7_GET_PROC_ADDRESS( - Func_SHGetPathFromIDListW, ::GetModuleHandleW(L"shell32.dll"), - "SHGetPathFromIDListW"); - if (!shGetPathFromIDListW) - return false; - bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); -#endif - - if (!result) - { - ODS("==== GetPathFromIDList() SHGetPathFromIDList() returned false") - /* for long path we need SHGetPathFromIDListEx(). - win10: SHGetPathFromIDListEx() for long path returns path with - with super path prefix "\\\\?\\". */ -#ifdef Z7_USE_DYN_SHGetPathFromIDListEx - const - Func_SHGetPathFromIDListEx - func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS( - Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"), - "SHGetPathFromIDListEx"); - if (func_SHGetPathFromIDListEx) -#endif - { - ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)") - do - { - len *= 4; - result = BOOLToBool( -#ifdef Z7_USE_DYN_SHGetPathFromIDListEx - func_SHGetPathFromIDListEx -#else - SHGetPathFromIDListEx -#endif - (itemIDList, path.GetBuf(len), len, 0)); - if (result) - break; - } - while (len <= (1 << 16)); - } - } - - path.ReleaseBuf_CalcLen(len); - return result; -} - -#endif - -#ifdef UNDER_CE - -bool BrowseForFolder(LPBROWSEINFO, CSysString) -{ - return false; -} - -bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &) -{ - return false; -} - -bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */, - LPCTSTR /* initialFolder */, CSysString & /* resultPath */) -{ - /* - // SHBrowseForFolder doesn't work before CE 6.0 ? - if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0) - MessageBoxW(0, L"no", L"", 0); - else - MessageBoxW(0, L"yes", L"", 0); - */ - /* - UString s = "all files"; - s += " (*.*)"; - return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true); - */ - return false; -} - -#else - -/* win10: SHBrowseForFolder() doesn't support long paths, - even if long path suppport is enabled in registry and in manifest. - and SHBrowseForFolder() doesn't support super path prefix "\\\\?\\". */ - -bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath) -{ - resultPath.Empty(); - NWindows::NCOM::CComInitializer comInitializer; - LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo); - if (!itemIDList) - return false; - CItemIDList itemIDListHolder; - itemIDListHolder.Attach(itemIDList); - return GetPathFromIDList(itemIDList, resultPath); -} - - -static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) -{ - #ifndef UNDER_CE - switch (uMsg) - { - case BFFM_INITIALIZED: - { - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data); - break; - } - /* - case BFFM_SELCHANGED: - { - TCHAR dir[MAX_PATH]; - if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir)) - SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir); - else - SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT("")); - break; - } - */ - default: - break; - } - #endif - return 0; -} - - -static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, - LPCTSTR initialFolder, CSysString &resultPath) -{ - CSysString displayName; - BROWSEINFO browseInfo; - browseInfo.hwndOwner = owner; - browseInfo.pidlRoot = NULL; - - // there are Unicode/Astring problems in some WinCE SDK ? - /* - #ifdef UNDER_CE - browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH); - browseInfo.lpszTitle = (LPCSTR)title; - #else - */ - browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); - browseInfo.lpszTitle = title; - // #endif - browseInfo.ulFlags = ulFlags; - browseInfo.lpfn = initialFolder ? BrowseCallbackProc : NULL; - browseInfo.lParam = (LPARAM)initialFolder; - return BrowseForFolder(&browseInfo, resultPath); -} - -#ifdef Z7_OLD_WIN_SDK -// ShlObj.h: -#ifndef BIF_NEWDIALOGSTYLE -#define BIF_NEWDIALOGSTYLE 0x0040 -#endif -#endif - -bool BrowseForFolder(HWND owner, LPCTSTR title, - LPCTSTR initialFolder, CSysString &resultPath) -{ - return BrowseForFolder(owner, title, - #ifndef UNDER_CE - BIF_NEWDIALOGSTYLE | - #endif - BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath); - // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0) -} - -#ifndef _UNICODE - -extern "C" { -typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi); -} - -static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) -{ - NWindows::NCOM::CComInitializer comInitializer; - const - Func_SHBrowseForFolderW - f_SHBrowseForFolderW = Z7_GET_PROC_ADDRESS( - Func_SHBrowseForFolderW, ::GetModuleHandleW(L"shell32.dll"), - "SHBrowseForFolderW"); - if (!f_SHBrowseForFolderW) - return false; - LPITEMIDLIST itemIDList = f_SHBrowseForFolderW(browseInfo); - if (!itemIDList) - return false; - CItemIDList itemIDListHolder; - itemIDListHolder.Attach(itemIDList); - return GetPathFromIDList(itemIDList, resultPath); -} - -static -int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) -{ - switch (uMsg) - { - case BFFM_INITIALIZED: - { - SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data); - break; - } - /* - case BFFM_SELCHANGED: - { - wchar_t dir[MAX_PATH * 2]; - - if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir)) - SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir); - else - SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L""); - break; - } - */ - default: - break; - } - return 0; -} - - -static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, - LPCWSTR initialFolder, UString &resultPath) -{ - UString displayName; - BROWSEINFOW browseInfo; - browseInfo.hwndOwner = owner; - browseInfo.pidlRoot = NULL; - browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); - browseInfo.lpszTitle = title; - browseInfo.ulFlags = ulFlags; - browseInfo.lpfn = initialFolder ? BrowseCallbackProc2 : NULL; - browseInfo.lParam = (LPARAM)initialFolder; - return BrowseForFolder(&browseInfo, resultPath); -} - -bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath) -{ - if (g_IsNT) - return BrowseForFolder(owner, title, - BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS - // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified. - , initialFolder, resultPath); - // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0) - CSysString s; - bool res = BrowseForFolder(owner, GetSystemString(title), - BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS - // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified. - , GetSystemString(initialFolder), s); - resultPath = GetUnicodeString(s); - return res; -} - -#endif - -#endif - -}} +// Windows/Shell.cpp + +#include "StdAfx.h" + +#include "../Common/MyCom.h" +#include "../Common/StringConvert.h" + +#include "COM.h" +#include "FileName.h" +#include "MemoryGlobal.h" +#include "Shell.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +// MSVC6 and old SDK don't support this function: +// #define LWSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE +// LWSTDAPI StrRetToStrW(STRRET *pstr, LPCITEMIDLIST pidl, LPWSTR *ppsz); + +// #define SHOW_DEBUG_SHELL + +#ifdef SHOW_DEBUG_SHELL + +#include "../Common/IntToString.h" + +static void Print_Number(UInt32 number, const char *s) +{ + AString s2; + s2.Add_UInt32(number); + s2.Add_Space(); + s2 += s; + OutputDebugStringA(s2); +} + +#define ODS(sz) { OutputDebugStringA(sz); } +#define ODS_U(s) { OutputDebugStringW(s); } +#define ODS_(op) { op; } + +#else + +#define ODS(sz) +#define ODS_U(s) +#define ODS_(op) + +#endif + + +namespace NWindows { +namespace NShell { + +#ifndef UNDER_CE + +// SHGetMalloc is unsupported in Windows Mobile? + +void CItemIDList::Free() +{ + if (!m_Object) + return; + /* DOCs: + SHGetMalloc was introduced in Windows 95 and Microsoft Windows NT 4.0, + but as of Windows 2000 it is no longer necessary. + In its place, programs can call the equivalent (and easier to use) CoTaskMemAlloc and CoTaskMemFree. + Description from oldnewthings: + shell functions could work without COM (if OLE32.DLL is not loaded), + but now if OLE32.DLL is loaded, then shell functions and com functions do same things. + 22.02: so we use OLE32.DLL function to free memory: + */ + /* + CMyComPtr shellMalloc; + if (::SHGetMalloc(&shellMalloc) != NOERROR) + throw 41099; + shellMalloc->Free(m_Object); + */ + CoTaskMemFree(m_Object); + m_Object = NULL; +} + +/* +CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL) + { *this = itemIDList; } +CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL) + { *this = itemIDList; } + +CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object) +{ + Free(); + if (object != 0) + { + UINT32 size = GetSize(object); + m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size); + if (m_Object != NULL) + MoveMemory(m_Object, object, size); + } + return *this; +} + +CItemIDList& CItemIDList::operator=(const CItemIDList &object) +{ + Free(); + if (object.m_Object != NULL) + { + UINT32 size = GetSize(object.m_Object); + m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size); + if (m_Object != NULL) + MoveMemory(m_Object, object.m_Object, size); + } + return *this; +} +*/ + + +static HRESULT ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names) +{ + names.Clear(); + const wchar_t *lim = p + size; + UString s; + /* + if (size == 0 || p[size - 1] != 0) + return E_INVALIDARG; + if (size == 1) + return S_OK; + if (p[size - 2] != 0) + return E_INVALIDARG; + */ + for (;;) + { + const wchar_t *start = p; + for (;;) + { + if (p == lim) return E_INVALIDARG; // S_FALSE + if (*p++ == 0) + break; + } + const size_t num = (size_t)(p - start); + if (num == 1) + { + if (p != lim) return E_INVALIDARG; // S_FALSE + return S_OK; + } + s.SetFrom(start, (unsigned)(num - 1)); + ODS_U(s) + names.Add(s); + // names.ReserveOnePosition(); + // names.AddInReserved_Ptr_of_new(new UString((unsigned)num - 1, start)); + } +} + + +static HRESULT ReadAnsiStrings(const char *p, size_t size, UStringVector &names) +{ + names.Clear(); + AString name; + for (; size != 0; size--) + { + const char c = *p++; + if (c == 0) + { + if (name.IsEmpty()) + return S_OK; + names.Add(GetUnicodeString(name)); + name.Empty(); + } + else + name.Add_Char(c); + } + return E_INVALIDARG; +} + + +#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } + +static HRESULT DataObject_GetData_HGLOBAL(IDataObject *dataObject, CLIPFORMAT cf, NCOM::CStgMedium &medium) +{ + FORMATETC etc = INIT_FORMATETC_HGLOBAL(cf); + RINOK(dataObject->GetData(&etc, &medium)) + if (medium.tymed != TYMED_HGLOBAL) + return E_INVALIDARG; + return S_OK; +} + +static HRESULT DataObject_GetData_HDROP_Names(IDataObject *dataObject, UStringVector &names) +{ + names.Clear(); + NCOM::CStgMedium medium; + + /* Win10 : if (dataObject) is from IContextMenu::Initialize() and + if (len_of_path >= MAX_PATH (260) for some file in data object) + { + GetData() returns HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) + "The data area passed to a system call is too small", + Is there a way to fix this code for long paths? + } */ + + RINOK(DataObject_GetData_HGLOBAL(dataObject, CF_HDROP, medium)) + const size_t blockSize = GlobalSize(medium.hGlobal); + if (blockSize < sizeof(DROPFILES)) + return E_INVALIDARG; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const DROPFILES *dropFiles = (const DROPFILES *)dropLock.GetPointer(); + if (!dropFiles) + return E_INVALIDARG; + if (blockSize < dropFiles->pFiles + || dropFiles->pFiles < sizeof(DROPFILES) + // || dropFiles->pFiles != sizeof(DROPFILES) + ) + return E_INVALIDARG; + const size_t size = blockSize - dropFiles->pFiles; + const void *namesData = (const Byte *)(const void *)dropFiles + dropFiles->pFiles; + HRESULT hres; + if (dropFiles->fWide) + { + if (size % sizeof(wchar_t) != 0) + return E_INVALIDARG; + hres = ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names); + } + else + hres = ReadAnsiStrings((const char *)namesData, size, names); + + ODS_(Print_Number(names.Size(), "DataObject_GetData_HDROP_Names")) + return hres; +} + + + +// CF_IDLIST: +#define MYWIN_CFSTR_SHELLIDLIST TEXT("Shell IDList Array") + +typedef struct +{ + UINT cidl; + UINT aoffset[1]; +} MYWIN_CIDA; +/* + cidl : number of PIDLs that are being transferred, not including the parent folder. + aoffset : An array of offsets, relative to the beginning of this structure. + aoffset[0] - fully qualified PIDL of a parent folder. + If this PIDL is empty, the parent folder is the desktop. + aoffset[1] ... aoffset[cidl] : offset to one of the PIDLs to be transferred. + All of these PIDLs are relative to the PIDL of the parent folder. +*/ + +static HRESULT DataObject_GetData_IDLIST(IDataObject *dataObject, UStringVector &names) +{ + names.Clear(); + NCOM::CStgMedium medium; + RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT) + RegisterClipboardFormat(MYWIN_CFSTR_SHELLIDLIST), medium)) + const size_t blockSize = GlobalSize(medium.hGlobal); + if (blockSize < sizeof(MYWIN_CIDA) || blockSize >= (UInt32)((UInt32)0 - 1)) + return E_INVALIDARG; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const MYWIN_CIDA *cida = (const MYWIN_CIDA *)dropLock.GetPointer(); + if (!cida) + return E_INVALIDARG; + if (cida->cidl == 0) + { + // is it posssible to have no selected items? + // it's unexpected case. + return E_INVALIDARG; + } + if (cida->cidl >= (blockSize - (UInt32)sizeof(MYWIN_CIDA)) / sizeof(UINT)) + return E_INVALIDARG; + const UInt32 start = cida->cidl * (UInt32)sizeof(UINT) + (UInt32)sizeof(MYWIN_CIDA); + + STRRET strret; + CMyComPtr parentFolder; + { + const UINT offset = cida->aoffset[0]; + if (offset < start || offset >= blockSize + // || offset != start + ) + return E_INVALIDARG; + + CMyComPtr desktopFolder; + RINOK(::SHGetDesktopFolder(&desktopFolder)) + if (!desktopFolder) + return E_FAIL; + + LPCITEMIDLIST const lpcItem = (LPCITEMIDLIST)(const void *)((const Byte *)cida + offset); + + #ifdef SHOW_DEBUG_SHELL + { + const HRESULT res = desktopFolder->GetDisplayNameOf( + lpcItem, SHGDN_FORPARSING, &strret); + if (res == S_OK && strret.uType == STRRET_WSTR) + { + ODS_U(strret.pOleStr) + /* if lpcItem is empty, the path will be + "C:\Users\user_name\Desktop" + if lpcItem is "My Computer" folder, the path will be + "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" */ + CoTaskMemFree(strret.pOleStr); + } + } + #endif + + RINOK(desktopFolder->BindToObject(lpcItem, + NULL, IID_IShellFolder, (void **)&parentFolder)) + if (!parentFolder) + return E_FAIL; + } + + names.ClearAndReserve(cida->cidl); + UString path; + + // for (int y = 0; y < 1; y++) // for debug + for (unsigned i = 1; i <= cida->cidl; i++) + { + const UINT offset = cida->aoffset[i]; + if (offset < start || offset >= blockSize) + return E_INVALIDARG; + const void *p = (const Byte *)(const void *)cida + offset; + /* ITEMIDLIST of file can contain more than one SHITEMID item. + In win10 only SHGDN_FORPARSING returns path that contains + all path parts related to parts of ITEMIDLIST. + So we can use only SHGDN_FORPARSING here. + Don't use (SHGDN_INFOLDER) + Don't use (SHGDN_INFOLDER | SHGDN_FORPARSING) + */ + RINOK(parentFolder->GetDisplayNameOf((LPCITEMIDLIST)p, SHGDN_FORPARSING, &strret)) + + /* + // MSVC6 and old SDK do not support StrRetToStrW(). + LPWSTR lpstr; + RINOK (StrRetToStrW(&strret, NULL, &lpstr)) + ODS_U(lpstr) + path = lpstr; + CoTaskMemFree(lpstr); + */ + if (strret.uType != STRRET_WSTR) + return E_INVALIDARG; + ODS_U(strret.pOleStr) + path = strret.pOleStr; + // the path could have super path prefix "\\\\?\\" + // we can remove super path prefix here, if we don't need that prefix + #ifdef Z7_LONG_PATH + // we remove super prefix, if we can work without that prefix + NFile::NName::If_IsSuperPath_RemoveSuperPrefix(path); + #endif + names.AddInReserved(path); + CoTaskMemFree(strret.pOleStr); + } + + ODS_(Print_Number(cida->cidl, "CFSTR_SHELLIDLIST END")) + return S_OK; +} + + +HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &paths) +{ + ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names START") + HRESULT hres = NShell::DataObject_GetData_HDROP_Names(dataObject, paths); + // if (hres == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) + if (hres != S_OK) + { + ODS("-- DataObject_GetData_IDLIST START") + // for (int y = 0; y < 10000; y++) // for debug + hres = NShell::DataObject_GetData_IDLIST(dataObject, paths); + } + ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names END") + return hres; +} + + + +// #if (NTDDI_VERSION >= NTDDI_VISTA) +typedef struct +{ + UINT cItems; // number of items in rgdwFileAttributes array + DWORD dwSumFileAttributes; // all of the attributes ORed together + DWORD dwProductFileAttributes; // all of the attributes ANDed together + DWORD rgdwFileAttributes[1]; // array +} MYWIN_FILE_ATTRIBUTES_ARRAY; + +#define MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY TEXT("File Attributes Array") + +HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs) +{ + attribs.Clear(); + NCOM::CStgMedium medium; + RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT) + RegisterClipboardFormat(MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY), medium)) + const size_t blockSize = GlobalSize(medium.hGlobal); + if (blockSize < sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY)) + return E_INVALIDARG; + NMemory::CGlobalLock dropLock(medium.hGlobal); + const MYWIN_FILE_ATTRIBUTES_ARRAY *faa = (const MYWIN_FILE_ATTRIBUTES_ARRAY *)dropLock.GetPointer(); + if (!faa) + return E_INVALIDARG; + const unsigned numFiles = faa->cItems; + if (numFiles == 0) + { + // is it posssible to have empty array here? + return E_INVALIDARG; + } + if ((blockSize - (sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY) - sizeof(DWORD))) + / sizeof(DWORD) != numFiles) + return E_INVALIDARG; + // attribs.Sum = faa->dwSumFileAttributes; + // attribs.Product = faa->dwProductFileAttributes; + // attribs.Vals.SetFromArray(faa->rgdwFileAttributes, numFiles); + // attribs.IsDirVector.ClearAndSetSize(numFiles); + + if ((faa->dwSumFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + { + /* in win10: if selected items are volumes (c:\, d:\ ..) in My Compter, + all items have FILE_ATTRIBUTE_DIRECTORY attribute + ntfs volume also have FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM + udf volume: FILE_ATTRIBUTE_READONLY + dvd-rom device: (-1) : all bits are set + */ + const DWORD *attr = faa->rgdwFileAttributes; + // DWORD product = (UInt32)0 - 1, sum = 0; + for (unsigned i = 0; i < numFiles; i++) + { + if (attr[i] & FILE_ATTRIBUTE_DIRECTORY) + { + // attribs.ThereAreDirs = true; + attribs.FirstDirIndex = (int)i; + break; + } + // attribs.IsDirVector[i] = (attr[i] & FILE_ATTRIBUTE_DIRECTORY) != 0; + // product &= v; + // sum |= v; + } + // ODS_(Print_Number(product, "Product calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + // ODS_(Print_Number(sum, "Sum calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + } + // ODS_(Print_Number(attribs.Product, "Product FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + // ODS_(Print_Number(attribs.Sum, "Sum FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + ODS_(Print_Number(numFiles, "FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names")) + return S_OK; +} + + +///////////////////////////// +// CDrop + +/* + win10: + DragQueryFile() implementation code is not effective because + there is no pointer inside DROP internal file list, so + DragQueryFile(fileIndex) runs all names in range [0, fileIndex]. + DragQueryFile(,, buf, bufSize) + if (buf == NULL) by spec + { + returns value is the required size + in characters, of the buffer, not including the terminating null character + tests show that if (bufSize == 0), then it also returns required size. + } + if (bufSize != NULL) + { + returns: the count of the characters copied, not including null character. + win10: null character is also copied at position buf[ret_count]; + } +*/ + +/* +void CDrop::Attach(HDROP object) +{ + Free(); + m_Object = object; + m_Assigned = true; +} + +void CDrop::Free() +{ + if (m_MustBeFinished && m_Assigned) + Finish(); + m_Assigned = false; +} + +UINT CDrop::QueryCountOfFiles() +{ + return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0); +} + +void CDrop::QueryFileName(UINT fileIndex, UString &fileName) +{ + #ifndef _UNICODE + if (!g_IsNT) + { + AString fileNameA; + const UINT len = QueryFile(fileIndex, (LPTSTR)NULL, 0); + const UINT numCopied = QueryFile(fileIndex, fileNameA.GetBuf(len + 2), len + 2); + fileNameA.ReleaseBuf_CalcLen(len); + if (numCopied != len) + throw 20221223; + fileName = GetUnicodeString(fileNameA); + } + else + #endif + { + // kReserve must be >= 3 for additional buffer size + // safety and for optimal performance + const unsigned kReserve = 3; + { + unsigned len = 0; + wchar_t *buf = fileName.GetBuf_GetMaxAvail(len); + if (len >= kReserve) + { + const UINT numCopied = QueryFile(fileIndex, buf, len); + if (numCopied < len - 1) + { + // (numCopied < len - 1) case means that it have copied full string. + fileName.ReleaseBuf_CalcLen(numCopied); + return; + } + } + } + const UINT len = QueryFile(fileIndex, (LPWSTR)NULL, 0); + const UINT numCopied = QueryFile(fileIndex, + fileName.GetBuf(len + kReserve), len + kReserve); + fileName.ReleaseBuf_CalcLen(len); + if (numCopied != len) + throw 20221223; + } +} + + +void CDrop::QueryFileNames(UStringVector &fileNames) +{ + UINT numFiles = QueryCountOfFiles(); + + Print_Number(numFiles, "\n====== CDrop::QueryFileNames START ===== \n"); + + fileNames.ClearAndReserve(numFiles); + UString s; + for (UINT i = 0; i < numFiles; i++) + { + QueryFileName(i, s); + if (!s.IsEmpty()) + fileNames.AddInReserved(s); + } + Print_Number(numFiles, "\n====== CDrop::QueryFileNames END ===== \n"); +} +*/ + + +// #if (NTDDI_VERSION >= NTDDI_VISTA) +// SHGetPathFromIDListEx returns a win32 file system path for the item in the name space. +typedef int Z7_WIN_GPFIDL_FLAGS; + +extern "C" { +#ifndef _UNICODE +typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath); // nt4 +#endif + +#if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0600 // Vista +#define Z7_USE_DYN_SHGetPathFromIDListEx +#endif + +#ifdef Z7_USE_DYN_SHGetPathFromIDListEx +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +typedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts); // vista +#endif +} + +#ifndef _UNICODE + +bool GetPathFromIDList(LPCITEMIDLIST itemIDList, AString &path) +{ + path.Empty(); + const unsigned len = MAX_PATH + 16; + const bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); + path.ReleaseBuf_CalcLen(len); + return result; +} + +#endif + +bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) +{ + path.Empty(); + unsigned len = MAX_PATH + 16; + +#ifdef _UNICODE + bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len))); +#else + const + Func_SHGetPathFromIDListW + shGetPathFromIDListW = Z7_GET_PROC_ADDRESS( + Func_SHGetPathFromIDListW, ::GetModuleHandleW(L"shell32.dll"), + "SHGetPathFromIDListW"); + if (!shGetPathFromIDListW) + return false; + bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); +#endif + + if (!result) + { + ODS("==== GetPathFromIDList() SHGetPathFromIDList() returned false") + /* for long path we need SHGetPathFromIDListEx(). + win10: SHGetPathFromIDListEx() for long path returns path with + with super path prefix "\\\\?\\". */ +#ifdef Z7_USE_DYN_SHGetPathFromIDListEx + const + Func_SHGetPathFromIDListEx + func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS( + Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"), + "SHGetPathFromIDListEx"); + if (func_SHGetPathFromIDListEx) +#endif + { + ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)") + do + { + len *= 4; + result = BOOLToBool( +#ifdef Z7_USE_DYN_SHGetPathFromIDListEx + func_SHGetPathFromIDListEx +#else + SHGetPathFromIDListEx +#endif + (itemIDList, path.GetBuf(len), len, 0)); + if (result) + break; + } + while (len <= (1 << 16)); + } + } + + path.ReleaseBuf_CalcLen(len); + return result; +} + +#endif + +#ifdef UNDER_CE + +bool BrowseForFolder(LPBROWSEINFO, CSysString) +{ + return false; +} + +bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &) +{ + return false; +} + +bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */, + LPCTSTR /* initialFolder */, CSysString & /* resultPath */) +{ + /* + // SHBrowseForFolder doesn't work before CE 6.0 ? + if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0) + MessageBoxW(0, L"no", L"", 0); + else + MessageBoxW(0, L"yes", L"", 0); + */ + /* + UString s = "all files"; + s += " (*.*)"; + return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true); + */ + return false; +} + +#else + +/* win10: SHBrowseForFolder() doesn't support long paths, + even if long path suppport is enabled in registry and in manifest. + and SHBrowseForFolder() doesn't support super path prefix "\\\\?\\". */ + +bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath) +{ + resultPath.Empty(); + NWindows::NCOM::CComInitializer comInitializer; + LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo); + if (!itemIDList) + return false; + CItemIDList itemIDListHolder; + itemIDListHolder.Attach(itemIDList); + return GetPathFromIDList(itemIDList, resultPath); +} + + +static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) +{ + #ifndef UNDER_CE + switch (uMsg) + { + case BFFM_INITIALIZED: + { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data); + break; + } + /* + case BFFM_SELCHANGED: + { + TCHAR dir[MAX_PATH]; + if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir)) + SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir); + else + SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT("")); + break; + } + */ + default: + break; + } + #endif + return 0; +} + + +static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, + LPCTSTR initialFolder, CSysString &resultPath) +{ + CSysString displayName; + BROWSEINFO browseInfo; + browseInfo.hwndOwner = owner; + browseInfo.pidlRoot = NULL; + + // there are Unicode/Astring problems in some WinCE SDK ? + /* + #ifdef UNDER_CE + browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH); + browseInfo.lpszTitle = (LPCSTR)title; + #else + */ + browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); + browseInfo.lpszTitle = title; + // #endif + browseInfo.ulFlags = ulFlags; + browseInfo.lpfn = initialFolder ? BrowseCallbackProc : NULL; + browseInfo.lParam = (LPARAM)initialFolder; + return BrowseForFolder(&browseInfo, resultPath); +} + +#ifdef Z7_OLD_WIN_SDK +// ShlObj.h: +#ifndef BIF_NEWDIALOGSTYLE +#define BIF_NEWDIALOGSTYLE 0x0040 +#endif +#endif + +bool BrowseForFolder(HWND owner, LPCTSTR title, + LPCTSTR initialFolder, CSysString &resultPath) +{ + return BrowseForFolder(owner, title, + #ifndef UNDER_CE + BIF_NEWDIALOGSTYLE | + #endif + BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath); + // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0) +} + +#ifndef _UNICODE + +extern "C" { +typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi); +} + +static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) +{ + NWindows::NCOM::CComInitializer comInitializer; + const + Func_SHBrowseForFolderW + f_SHBrowseForFolderW = Z7_GET_PROC_ADDRESS( + Func_SHBrowseForFolderW, ::GetModuleHandleW(L"shell32.dll"), + "SHBrowseForFolderW"); + if (!f_SHBrowseForFolderW) + return false; + LPITEMIDLIST itemIDList = f_SHBrowseForFolderW(browseInfo); + if (!itemIDList) + return false; + CItemIDList itemIDListHolder; + itemIDListHolder.Attach(itemIDList); + return GetPathFromIDList(itemIDList, resultPath); +} + +static +int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) +{ + switch (uMsg) + { + case BFFM_INITIALIZED: + { + SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data); + break; + } + /* + case BFFM_SELCHANGED: + { + wchar_t dir[MAX_PATH * 2]; + + if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir)) + SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir); + else + SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L""); + break; + } + */ + default: + break; + } + return 0; +} + + +static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags, + LPCWSTR initialFolder, UString &resultPath) +{ + UString displayName; + BROWSEINFOW browseInfo; + browseInfo.hwndOwner = owner; + browseInfo.pidlRoot = NULL; + browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH); + browseInfo.lpszTitle = title; + browseInfo.ulFlags = ulFlags; + browseInfo.lpfn = initialFolder ? BrowseCallbackProc2 : NULL; + browseInfo.lParam = (LPARAM)initialFolder; + return BrowseForFolder(&browseInfo, resultPath); +} + +bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath) +{ + if (g_IsNT) + return BrowseForFolder(owner, title, + BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS + // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified. + , initialFolder, resultPath); + // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0) + CSysString s; + bool res = BrowseForFolder(owner, GetSystemString(title), + BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS + // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified. + , GetSystemString(initialFolder), s); + resultPath = GetUnicodeString(s); + return res; +} + +#endif + +#endif + +}} diff --git a/CPP/Windows/Shell.h b/CPP/Windows/Shell.h index d0a9d1b73..9e58e25cc 100644 --- a/CPP/Windows/Shell.h +++ b/CPP/Windows/Shell.h @@ -1,129 +1,129 @@ -// Windows/Shell.h - -#ifndef ZIP7_WINDOWS_SHELL_H -#define ZIP7_WINDOWS_SHELL_H - -#include "../Common/MyWindows.h" -#if defined(__MINGW32__) || defined(__MINGW64__) -#include -#else -#include -#endif - -#include "../Common/MyString.h" - -#include "Defs.h" - -namespace NWindows { -namespace NShell { - -///////////////////////// -// CItemIDList -#ifndef UNDER_CE - -class CItemIDList -{ - LPITEMIDLIST m_Object; - Z7_CLASS_NO_COPY(CItemIDList) -public: - CItemIDList(): m_Object(NULL) {} - // CItemIDList(LPCITEMIDLIST itemIDList); - // CItemIDList(const CItemIDList& itemIDList); - ~CItemIDList() { Free(); } - void Free(); - void Attach(LPITEMIDLIST object) - { - Free(); - m_Object = object; - } - LPITEMIDLIST Detach() - { - LPITEMIDLIST object = m_Object; - m_Object = NULL; - return object; - } - operator LPITEMIDLIST() { return m_Object;} - operator LPCITEMIDLIST() const { return m_Object;} - LPITEMIDLIST* operator&() { return &m_Object; } - LPITEMIDLIST operator->() { return m_Object; } - - // CItemIDList& operator=(LPCITEMIDLIST object); - // CItemIDList& operator=(const CItemIDList &object); -}; - -///////////////////////////// -// CDrop - -/* -class CDrop -{ - HDROP m_Object; - bool m_MustBeFinished; - bool m_Assigned; - void Free(); -public: - CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {} - ~CDrop() { Free(); } - - void Attach(HDROP object); - operator HDROP() { return m_Object;} - bool QueryPoint(LPPOINT point) - { return BOOLToBool(::DragQueryPoint(m_Object, point)); } - void Finish() - { - ::DragFinish(m_Object); - } - UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT bufSize) - { return ::DragQueryFile(m_Object, fileIndex, fileName, bufSize); } - #ifndef _UNICODE - UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT bufSize) - { return ::DragQueryFileW(m_Object, fileIndex, fileName, bufSize); } - #endif - UINT QueryCountOfFiles(); - void QueryFileName(UINT fileIndex, UString &fileName); - void QueryFileNames(UStringVector &fileNames); -}; -*/ -#endif - -struct CFileAttribs -{ - int FirstDirIndex; - // DWORD Sum; - // DWORD Product; - // CRecordVector Vals; - // CRecordVector IsDirVector; - - CFileAttribs() - { - Clear(); - } - - void Clear() - { - FirstDirIndex = -1; - // Sum = 0; - // Product = 0; - // IsDirVector.Clear(); - } -}; - - -/* read pathnames from HDROP or SHELLIDLIST. - The parser can return E_INVALIDARG, if there is some unexpected data in dataObject */ -HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &names); - -HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs); - -bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path); -bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath); -bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath); - -#ifndef _UNICODE -bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path); -bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath); -bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath); -#endif -}} - -#endif +// Windows/Shell.h + +#ifndef ZIP7_WINDOWS_SHELL_H +#define ZIP7_WINDOWS_SHELL_H + +#include "../Common/MyWindows.h" +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else +#include +#endif + +#include "../Common/MyString.h" + +#include "Defs.h" + +namespace NWindows { +namespace NShell { + +///////////////////////// +// CItemIDList +#ifndef UNDER_CE + +class CItemIDList +{ + LPITEMIDLIST m_Object; + Z7_CLASS_NO_COPY(CItemIDList) +public: + CItemIDList(): m_Object(NULL) {} + // CItemIDList(LPCITEMIDLIST itemIDList); + // CItemIDList(const CItemIDList& itemIDList); + ~CItemIDList() { Free(); } + void Free(); + void Attach(LPITEMIDLIST object) + { + Free(); + m_Object = object; + } + LPITEMIDLIST Detach() + { + LPITEMIDLIST object = m_Object; + m_Object = NULL; + return object; + } + operator LPITEMIDLIST() { return m_Object;} + operator LPCITEMIDLIST() const { return m_Object;} + LPITEMIDLIST* operator&() { return &m_Object; } + LPITEMIDLIST operator->() { return m_Object; } + + // CItemIDList& operator=(LPCITEMIDLIST object); + // CItemIDList& operator=(const CItemIDList &object); +}; + +///////////////////////////// +// CDrop + +/* +class CDrop +{ + HDROP m_Object; + bool m_MustBeFinished; + bool m_Assigned; + void Free(); +public: + CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {} + ~CDrop() { Free(); } + + void Attach(HDROP object); + operator HDROP() { return m_Object;} + bool QueryPoint(LPPOINT point) + { return BOOLToBool(::DragQueryPoint(m_Object, point)); } + void Finish() + { + ::DragFinish(m_Object); + } + UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT bufSize) + { return ::DragQueryFile(m_Object, fileIndex, fileName, bufSize); } + #ifndef _UNICODE + UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT bufSize) + { return ::DragQueryFileW(m_Object, fileIndex, fileName, bufSize); } + #endif + UINT QueryCountOfFiles(); + void QueryFileName(UINT fileIndex, UString &fileName); + void QueryFileNames(UStringVector &fileNames); +}; +*/ +#endif + +struct CFileAttribs +{ + int FirstDirIndex; + // DWORD Sum; + // DWORD Product; + // CRecordVector Vals; + // CRecordVector IsDirVector; + + CFileAttribs() + { + Clear(); + } + + void Clear() + { + FirstDirIndex = -1; + // Sum = 0; + // Product = 0; + // IsDirVector.Clear(); + } +}; + + +/* read pathnames from HDROP or SHELLIDLIST. + The parser can return E_INVALIDARG, if there is some unexpected data in dataObject */ +HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &names); + +HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs); + +bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path); +bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath); +bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath); + +#ifndef _UNICODE +bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path); +bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath); +bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath); +#endif +}} + +#endif diff --git a/CPP/Windows/StdAfx.h b/CPP/Windows/StdAfx.h index f77dd9c08..4441a5f08 100644 --- a/CPP/Windows/StdAfx.h +++ b/CPP/Windows/StdAfx.h @@ -1,11 +1,11 @@ -// StdAfx.h - -#ifndef ZIP7_INC_STDAFX_H -#define ZIP7_INC_STDAFX_H - -#if defined(_MSC_VER) && _MSC_VER >= 1800 -#pragma warning(disable : 4464) // relative include path contains '..' -#endif -#include "../Common/Common.h" - -#endif +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif +#include "../Common/Common.h" + +#endif diff --git a/CPP/Windows/Synchronization.cpp b/CPP/Windows/Synchronization.cpp index 5154f1b01..d5542af48 100644 --- a/CPP/Windows/Synchronization.cpp +++ b/CPP/Windows/Synchronization.cpp @@ -1,87 +1,87 @@ -// Windows/Synchronization.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 - -#include "Synchronization.h" - -namespace NWindows { -namespace NSynchronization { - -/* -#define INFINITE 0xFFFFFFFF -#define MAXIMUM_WAIT_OBJECTS 64 -#define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L) -#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) -#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) -// WINAPI -DWORD WaitForMultipleObjects(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout); -*/ - -/* clang: we need to place some virtual functions in cpp file to rid off the warning: - 'CBaseHandle_WFMO' has no out-of-line virtual method definitions; - its vtable will be emitted in every translation unit */ -CBaseHandle_WFMO::~CBaseHandle_WFMO() -{ -} - -bool CBaseEvent_WFMO::IsSignaledAndUpdate() -{ - if (this->_state == false) - return false; - if (this->_manual_reset == false) - this->_state = false; - return true; -} - -bool CSemaphore_WFMO::IsSignaledAndUpdate() -{ - if (this->_count == 0) - return false; - this->_count--; - return true; -} - -DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) -{ - if (count < 1) - { - // abort(); - SetLastError(EINVAL); - return WAIT_FAILED; - } - - CSynchro *synchro = handles[0]->_sync; - synchro->Enter(); - - // #ifdef DEBUG_SYNCHRO - for (DWORD i = 1; i < count; i++) - { - if (synchro != handles[i]->_sync) - { - // abort(); - synchro->Leave(); - SetLastError(EINVAL); - return WAIT_FAILED; - } - } - // #endif - - for (;;) - { - for (DWORD i = 0; i < count; i++) - { - if (handles[i]->IsSignaledAndUpdate()) - { - synchro->Leave(); - return WAIT_OBJECT_0 + i; - } - } - synchro->WaitCond(); - } -} - -}} - -#endif +// Windows/Synchronization.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 + +#include "Synchronization.h" + +namespace NWindows { +namespace NSynchronization { + +/* +#define INFINITE 0xFFFFFFFF +#define MAXIMUM_WAIT_OBJECTS 64 +#define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L) +#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) +#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) +// WINAPI +DWORD WaitForMultipleObjects(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout); +*/ + +/* clang: we need to place some virtual functions in cpp file to rid off the warning: + 'CBaseHandle_WFMO' has no out-of-line virtual method definitions; + its vtable will be emitted in every translation unit */ +CBaseHandle_WFMO::~CBaseHandle_WFMO() +{ +} + +bool CBaseEvent_WFMO::IsSignaledAndUpdate() +{ + if (this->_state == false) + return false; + if (this->_manual_reset == false) + this->_state = false; + return true; +} + +bool CSemaphore_WFMO::IsSignaledAndUpdate() +{ + if (this->_count == 0) + return false; + this->_count--; + return true; +} + +DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) +{ + if (count < 1) + { + // abort(); + SetLastError(EINVAL); + return WAIT_FAILED; + } + + CSynchro *synchro = handles[0]->_sync; + synchro->Enter(); + + // #ifdef DEBUG_SYNCHRO + for (DWORD i = 1; i < count; i++) + { + if (synchro != handles[i]->_sync) + { + // abort(); + synchro->Leave(); + SetLastError(EINVAL); + return WAIT_FAILED; + } + } + // #endif + + for (;;) + { + for (DWORD i = 0; i < count; i++) + { + if (handles[i]->IsSignaledAndUpdate()) + { + synchro->Leave(); + return WAIT_OBJECT_0 + i; + } + } + synchro->WaitCond(); + } +} + +}} + +#endif diff --git a/CPP/Windows/Synchronization.h b/CPP/Windows/Synchronization.h index 84df13676..1df84d321 100644 --- a/CPP/Windows/Synchronization.h +++ b/CPP/Windows/Synchronization.h @@ -1,386 +1,386 @@ -// Windows/Synchronization.h - -#ifndef ZIP7_INC_WINDOWS_SYNCHRONIZATION_H -#define ZIP7_INC_WINDOWS_SYNCHRONIZATION_H - -#include "../../C/Threads.h" - -#include "../Common/MyTypes.h" - -#include "Defs.h" - -#ifdef _WIN32 -#include "Handle.h" -#endif - -namespace NWindows { -namespace NSynchronization { - -class CBaseEvent MY_UNCOPYABLE -{ -protected: - ::CEvent _object; -public: - bool IsCreated() { return Event_IsCreated(&_object) != 0; } - - CBaseEvent() { Event_Construct(&_object); } - ~CBaseEvent() { Close(); } - WRes Close() { return Event_Close(&_object); } - - #ifdef _WIN32 - operator HANDLE() { return _object; } - WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) - { - _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); - if (name == NULL && _object != NULL) - return 0; - return ::GetLastError(); - } - WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) - { - _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); - if (_object != NULL) - return 0; - return ::GetLastError(); - } - #endif - - WRes Set() { return Event_Set(&_object); } - // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } - WRes Reset() { return Event_Reset(&_object); } - WRes Lock() { return Event_Wait(&_object); } -}; - -class CManualResetEvent: public CBaseEvent -{ -public: - WRes Create(bool initiallyOwn = false) - { - return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); - } - WRes CreateIfNotCreated_Reset() - { - if (IsCreated()) - return Reset(); - return ManualResetEvent_CreateNotSignaled(&_object); - } - #ifdef _WIN32 - WRes CreateWithName(bool initiallyOwn, LPCTSTR name) - { - return CBaseEvent::Create(true, initiallyOwn, name); - } - #endif -}; - -class CAutoResetEvent: public CBaseEvent -{ -public: - WRes Create() - { - return AutoResetEvent_CreateNotSignaled(&_object); - } - WRes CreateIfNotCreated_Reset() - { - if (IsCreated()) - return Reset(); - return AutoResetEvent_CreateNotSignaled(&_object); - } -}; - - -/* -#ifdef _WIN32 - -class CObject: public CHandle -{ -public: - WRes Lock(DWORD timeoutInterval = INFINITE) - { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } -}; - -class CMutex: public CObject -{ -public: - WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) - { - _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name); - if (name == NULL && _handle != 0) - return 0; - return ::GetLastError(); - } - #ifndef UNDER_CE - WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) - { - _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); - if (_handle != 0) - return 0; - return ::GetLastError(); - } - #endif - WRes Release() - { - return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); - } -}; - -class CMutexLock MY_UNCOPYABLE -{ - CMutex *_object; -public: - CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } - ~CMutexLock() { _object->Release(); } -}; - -#endif // _WIN32 -*/ - - -class CSemaphore MY_UNCOPYABLE -{ - ::CSemaphore _object; -public: - CSemaphore() { Semaphore_Construct(&_object); } - ~CSemaphore() { Close(); } - WRes Close() { return Semaphore_Close(&_object); } - - #ifdef _WIN32 - operator HANDLE() { return _object; } - #endif - - // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; } - - WRes Create(UInt32 initCount, UInt32 maxCount) - { - return Semaphore_Create(&_object, initCount, maxCount); - } - WRes OptCreateInit(UInt32 initCount, UInt32 maxCount) - { - return Semaphore_OptCreateInit(&_object, initCount, maxCount); - } - WRes Release() { return Semaphore_Release1(&_object); } - WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } - WRes Lock() { return Semaphore_Wait(&_object); } -}; - -class CCriticalSection MY_UNCOPYABLE -{ - ::CCriticalSection _object; -public: - CCriticalSection() { CriticalSection_Init(&_object); } - ~CCriticalSection() { CriticalSection_Delete(&_object); } - void Enter() { CriticalSection_Enter(&_object); } - void Leave() { CriticalSection_Leave(&_object); } -}; - -class CCriticalSectionLock MY_UNCOPYABLE -{ - CCriticalSection *_object; - void Unlock() { _object->Leave(); } -public: - CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } - ~CCriticalSectionLock() { Unlock(); } -}; - - -#ifdef _WIN32 - -typedef HANDLE CHandle_WFMO; -typedef CSemaphore CSemaphore_WFMO; -typedef CAutoResetEvent CAutoResetEvent_WFMO; -typedef CManualResetEvent CManualResetEvent_WFMO; - -inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) -{ - return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); -} - -#define SYNC_OBJ_DECL(obj) -#define SYNC_WFMO(x) -#define SYNC_PARAM(x) -#define SYNC_PARAM_DECL(x) - -#else // _WIN32 - -// POSIX sync objects for WaitForMultipleObjects - -#define SYNC_WFMO(x) x -#define SYNC_PARAM(x) x, -#define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x -#define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x; - -class CSynchro MY_UNCOPYABLE -{ - pthread_mutex_t _mutex; - pthread_cond_t _cond; - bool _isValid; - -public: - CSynchro() { _isValid = false; } - ~CSynchro() - { - if (_isValid) - { - ::pthread_mutex_destroy(&_mutex); - ::pthread_cond_destroy(&_cond); - } - _isValid = false; - } - WRes Create() - { - RINOK(::pthread_mutex_init(&_mutex, NULL)) - const WRes ret = ::pthread_cond_init(&_cond, NULL); - _isValid = 1; - return ret; - } - WRes Enter() - { -#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \ - && defined(__FreeBSD__) - #pragma GCC diagnostic ignored "-Wthread-safety-negative" - #pragma GCC diagnostic ignored "-Wthread-safety-analysis" -#endif - return ::pthread_mutex_lock(&_mutex); - } - WRes Leave() - { - return ::pthread_mutex_unlock(&_mutex); - } - WRes WaitCond() - { - return ::pthread_cond_wait(&_cond, &_mutex); - } - WRes LeaveAndSignal() - { - const WRes res1 = ::pthread_cond_broadcast(&_cond); - const WRes res2 = ::pthread_mutex_unlock(&_mutex); - return (res2 ? res2 : res1); - } -}; - - -struct CBaseHandle_WFMO; -typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO; - -// these constants are from Windows -#define WAIT_OBJECT_0 0 -#define WAIT_FAILED ((DWORD)0xFFFFFFFF) - -DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles); - - -struct CBaseHandle_WFMO MY_UNCOPYABLE -{ - CSynchro *_sync; - - CBaseHandle_WFMO(): _sync(NULL) {} - virtual ~CBaseHandle_WFMO(); - - operator CHandle_WFMO() { return this; } - virtual bool IsSignaledAndUpdate() = 0; -}; - - -class CBaseEvent_WFMO : public CBaseHandle_WFMO -{ - bool _manual_reset; - bool _state; - -public: - - // bool IsCreated() { return (this->_sync != NULL); } - // CBaseEvent_WFMO() { ; } - // ~CBaseEvent_WFMO() Z7_override { Close(); } - - WRes Close() { this->_sync = NULL; return 0; } - - WRes Create( - CSynchro *sync, - bool manualReset, bool initiallyOwn) - { - this->_sync = sync; - this->_manual_reset = manualReset; - this->_state = initiallyOwn; - return 0; - } - - WRes Set() - { - RINOK(this->_sync->Enter()) - this->_state = true; - return this->_sync->LeaveAndSignal(); - } - - WRes Reset() - { - RINOK(this->_sync->Enter()) - this->_state = false; - return this->_sync->Leave(); - } - - virtual bool IsSignaledAndUpdate() Z7_override; -}; - - -class CManualResetEvent_WFMO Z7_final: public CBaseEvent_WFMO -{ -public: - WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); } -}; - - -class CAutoResetEvent_WFMO Z7_final: public CBaseEvent_WFMO -{ -public: - WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); } - WRes CreateIfNotCreated_Reset(CSynchro *sync) - { - return Create(sync); - } -}; - - -class CSemaphore_WFMO Z7_final: public CBaseHandle_WFMO -{ - UInt32 _count; - UInt32 _maxCount; - -public: - CSemaphore_WFMO() : _count(0), _maxCount(0) {} - - WRes Close() { this->_sync = NULL; return 0; } - - WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount) - { - if (initCount > maxCount || maxCount < 1) - return EINVAL; - this->_sync = sync; - this->_count = initCount; - this->_maxCount = maxCount; - return 0; - } - - WRes Release(UInt32 releaseCount = 1) - { - if (releaseCount < 1) - return EINVAL; - - RINOK(this->_sync->Enter()) - UInt32 newCount = this->_count + releaseCount; - if (newCount > this->_maxCount) - { - RINOK(this->_sync->Leave()) - return ERROR_TOO_MANY_POSTS; // EINVAL - } - this->_count = newCount; - - return this->_sync->LeaveAndSignal(); - } - - virtual bool IsSignaledAndUpdate() Z7_override; -}; - -#endif // _WIN32 - -}} - -#endif +// Windows/Synchronization.h + +#ifndef ZIP7_INC_WINDOWS_SYNCHRONIZATION_H +#define ZIP7_INC_WINDOWS_SYNCHRONIZATION_H + +#include "../../C/Threads.h" + +#include "../Common/MyTypes.h" + +#include "Defs.h" + +#ifdef _WIN32 +#include "Handle.h" +#endif + +namespace NWindows { +namespace NSynchronization { + +class CBaseEvent MY_UNCOPYABLE +{ +protected: + ::CEvent _object; +public: + bool IsCreated() { return Event_IsCreated(&_object) != 0; } + + CBaseEvent() { Event_Construct(&_object); } + ~CBaseEvent() { Close(); } + WRes Close() { return Event_Close(&_object); } + + #ifdef _WIN32 + operator HANDLE() { return _object; } + WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) + { + _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); + if (name == NULL && _object != NULL) + return 0; + return ::GetLastError(); + } + WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) + { + _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); + if (_object != NULL) + return 0; + return ::GetLastError(); + } + #endif + + WRes Set() { return Event_Set(&_object); } + // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } + WRes Reset() { return Event_Reset(&_object); } + WRes Lock() { return Event_Wait(&_object); } +}; + +class CManualResetEvent: public CBaseEvent +{ +public: + WRes Create(bool initiallyOwn = false) + { + return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); + } + WRes CreateIfNotCreated_Reset() + { + if (IsCreated()) + return Reset(); + return ManualResetEvent_CreateNotSignaled(&_object); + } + #ifdef _WIN32 + WRes CreateWithName(bool initiallyOwn, LPCTSTR name) + { + return CBaseEvent::Create(true, initiallyOwn, name); + } + #endif +}; + +class CAutoResetEvent: public CBaseEvent +{ +public: + WRes Create() + { + return AutoResetEvent_CreateNotSignaled(&_object); + } + WRes CreateIfNotCreated_Reset() + { + if (IsCreated()) + return Reset(); + return AutoResetEvent_CreateNotSignaled(&_object); + } +}; + + +/* +#ifdef _WIN32 + +class CObject: public CHandle +{ +public: + WRes Lock(DWORD timeoutInterval = INFINITE) + { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } +}; + +class CMutex: public CObject +{ +public: + WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) + { + _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name); + if (name == NULL && _handle != 0) + return 0; + return ::GetLastError(); + } + #ifndef UNDER_CE + WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) + { + _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); + if (_handle != 0) + return 0; + return ::GetLastError(); + } + #endif + WRes Release() + { + return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); + } +}; + +class CMutexLock MY_UNCOPYABLE +{ + CMutex *_object; +public: + CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } + ~CMutexLock() { _object->Release(); } +}; + +#endif // _WIN32 +*/ + + +class CSemaphore MY_UNCOPYABLE +{ + ::CSemaphore _object; +public: + CSemaphore() { Semaphore_Construct(&_object); } + ~CSemaphore() { Close(); } + WRes Close() { return Semaphore_Close(&_object); } + + #ifdef _WIN32 + operator HANDLE() { return _object; } + #endif + + // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; } + + WRes Create(UInt32 initCount, UInt32 maxCount) + { + return Semaphore_Create(&_object, initCount, maxCount); + } + WRes OptCreateInit(UInt32 initCount, UInt32 maxCount) + { + return Semaphore_OptCreateInit(&_object, initCount, maxCount); + } + WRes Release() { return Semaphore_Release1(&_object); } + WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } + WRes Lock() { return Semaphore_Wait(&_object); } +}; + +class CCriticalSection MY_UNCOPYABLE +{ + ::CCriticalSection _object; +public: + CCriticalSection() { CriticalSection_Init(&_object); } + ~CCriticalSection() { CriticalSection_Delete(&_object); } + void Enter() { CriticalSection_Enter(&_object); } + void Leave() { CriticalSection_Leave(&_object); } +}; + +class CCriticalSectionLock MY_UNCOPYABLE +{ + CCriticalSection *_object; + void Unlock() { _object->Leave(); } +public: + CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); } + ~CCriticalSectionLock() { Unlock(); } +}; + + +#ifdef _WIN32 + +typedef HANDLE CHandle_WFMO; +typedef CSemaphore CSemaphore_WFMO; +typedef CAutoResetEvent CAutoResetEvent_WFMO; +typedef CManualResetEvent CManualResetEvent_WFMO; + +inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) +{ + return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); +} + +#define SYNC_OBJ_DECL(obj) +#define SYNC_WFMO(x) +#define SYNC_PARAM(x) +#define SYNC_PARAM_DECL(x) + +#else // _WIN32 + +// POSIX sync objects for WaitForMultipleObjects + +#define SYNC_WFMO(x) x +#define SYNC_PARAM(x) x, +#define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x +#define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x; + +class CSynchro MY_UNCOPYABLE +{ + pthread_mutex_t _mutex; + pthread_cond_t _cond; + bool _isValid; + +public: + CSynchro() { _isValid = false; } + ~CSynchro() + { + if (_isValid) + { + ::pthread_mutex_destroy(&_mutex); + ::pthread_cond_destroy(&_cond); + } + _isValid = false; + } + WRes Create() + { + RINOK(::pthread_mutex_init(&_mutex, NULL)) + const WRes ret = ::pthread_cond_init(&_cond, NULL); + _isValid = 1; + return ret; + } + WRes Enter() + { +#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \ + && defined(__FreeBSD__) + #pragma GCC diagnostic ignored "-Wthread-safety-negative" + #pragma GCC diagnostic ignored "-Wthread-safety-analysis" +#endif + return ::pthread_mutex_lock(&_mutex); + } + WRes Leave() + { + return ::pthread_mutex_unlock(&_mutex); + } + WRes WaitCond() + { + return ::pthread_cond_wait(&_cond, &_mutex); + } + WRes LeaveAndSignal() + { + const WRes res1 = ::pthread_cond_broadcast(&_cond); + const WRes res2 = ::pthread_mutex_unlock(&_mutex); + return (res2 ? res2 : res1); + } +}; + + +struct CBaseHandle_WFMO; +typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO; + +// these constants are from Windows +#define WAIT_OBJECT_0 0 +#define WAIT_FAILED ((DWORD)0xFFFFFFFF) + +DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles); + + +struct CBaseHandle_WFMO MY_UNCOPYABLE +{ + CSynchro *_sync; + + CBaseHandle_WFMO(): _sync(NULL) {} + virtual ~CBaseHandle_WFMO(); + + operator CHandle_WFMO() { return this; } + virtual bool IsSignaledAndUpdate() = 0; +}; + + +class CBaseEvent_WFMO : public CBaseHandle_WFMO +{ + bool _manual_reset; + bool _state; + +public: + + // bool IsCreated() { return (this->_sync != NULL); } + // CBaseEvent_WFMO() { ; } + // ~CBaseEvent_WFMO() Z7_override { Close(); } + + WRes Close() { this->_sync = NULL; return 0; } + + WRes Create( + CSynchro *sync, + bool manualReset, bool initiallyOwn) + { + this->_sync = sync; + this->_manual_reset = manualReset; + this->_state = initiallyOwn; + return 0; + } + + WRes Set() + { + RINOK(this->_sync->Enter()) + this->_state = true; + return this->_sync->LeaveAndSignal(); + } + + WRes Reset() + { + RINOK(this->_sync->Enter()) + this->_state = false; + return this->_sync->Leave(); + } + + virtual bool IsSignaledAndUpdate() Z7_override; +}; + + +class CManualResetEvent_WFMO Z7_final: public CBaseEvent_WFMO +{ +public: + WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); } +}; + + +class CAutoResetEvent_WFMO Z7_final: public CBaseEvent_WFMO +{ +public: + WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); } + WRes CreateIfNotCreated_Reset(CSynchro *sync) + { + return Create(sync); + } +}; + + +class CSemaphore_WFMO Z7_final: public CBaseHandle_WFMO +{ + UInt32 _count; + UInt32 _maxCount; + +public: + CSemaphore_WFMO() : _count(0), _maxCount(0) {} + + WRes Close() { this->_sync = NULL; return 0; } + + WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount) + { + if (initCount > maxCount || maxCount < 1) + return EINVAL; + this->_sync = sync; + this->_count = initCount; + this->_maxCount = maxCount; + return 0; + } + + WRes Release(UInt32 releaseCount = 1) + { + if (releaseCount < 1) + return EINVAL; + + RINOK(this->_sync->Enter()) + UInt32 newCount = this->_count + releaseCount; + if (newCount > this->_maxCount) + { + RINOK(this->_sync->Leave()) + return ERROR_TOO_MANY_POSTS; // EINVAL + } + this->_count = newCount; + + return this->_sync->LeaveAndSignal(); + } + + virtual bool IsSignaledAndUpdate() Z7_override; +}; + +#endif // _WIN32 + +}} + +#endif diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp index 320cc18de..5fa87f386 100644 --- a/CPP/Windows/System.cpp +++ b/CPP/Windows/System.cpp @@ -1,314 +1,327 @@ -// Windows/System.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 -#include -#include -#if defined(__APPLE__) || defined(__DragonFly__) || \ - defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#else -#include -#endif -#endif - -#include "../Common/Defs.h" -// #include "../Common/MyWindows.h" - -// #include "../../C/CpuArch.h" - -#include "System.h" - -namespace NWindows { -namespace NSystem { - -#ifdef _WIN32 - -UInt32 CountAffinity(DWORD_PTR mask) -{ - UInt32 num = 0; - for (unsigned i = 0; i < sizeof(mask) * 8; i++) - { - num += (UInt32)(mask & 1); - mask >>= 1; - } - return num; -} - -BOOL CProcessAffinity::Get() -{ - #ifndef UNDER_CE - return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); - #else - return FALSE; - #endif -} - - -UInt32 GetNumberOfProcessors() -{ - // We need to know how many threads we can use. - // By default the process is assigned to one group. - // So we get the number of logical processors (threads) - // assigned to current process in the current group. - // Group size can be smaller than total number logical processors, for exammple, 2x36 - - CProcessAffinity pa; - - if (pa.Get() && pa.processAffinityMask != 0) - return pa.GetNumProcessThreads(); - - SYSTEM_INFO systemInfo; - GetSystemInfo(&systemInfo); - // the number of logical processors in the current group - return (UInt32)systemInfo.dwNumberOfProcessors; -} - -#else - - -BOOL CProcessAffinity::Get() -{ - numSysThreads = GetNumberOfProcessors(); - - /* - numSysThreads = 8; - for (unsigned i = 0; i < numSysThreads; i++) - CpuSet_Set(&cpu_set, i); - return TRUE; - */ - - #ifdef Z7_AFFINITY_SUPPORTED - - // numSysThreads = sysconf(_SC_NPROCESSORS_ONLN); // The number of processors currently online - if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0) - return FALSE; - return TRUE; - - #else - - // cpu_set = ((CCpuSet)1 << (numSysThreads)) - 1; - return TRUE; - // errno = ENOSYS; - // return FALSE; - - #endif -} - -UInt32 GetNumberOfProcessors() -{ - #ifndef Z7_ST - long n = sysconf(_SC_NPROCESSORS_CONF); // The number of processors configured - if (n < 1) - n = 1; - return (UInt32)n; - #else - return 1; - #endif -} - -#endif - - -#ifdef _WIN32 - -#ifndef UNDER_CE - -#if !defined(_WIN64) && \ - (defined(__MINGW32_VERSION) || defined(Z7_OLD_WIN_SDK)) - -typedef struct { - DWORD dwLength; - DWORD dwMemoryLoad; - DWORDLONG ullTotalPhys; - DWORDLONG ullAvailPhys; - DWORDLONG ullTotalPageFile; - DWORDLONG ullAvailPageFile; - DWORDLONG ullTotalVirtual; - DWORDLONG ullAvailVirtual; - DWORDLONG ullAvailExtendedVirtual; -} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX; - -#else - -#define MY_MEMORYSTATUSEX MEMORYSTATUSEX -#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX - -#endif - -typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer); - -#endif // !UNDER_CE - - -bool GetRamSize(UInt64 &size) -{ - size = (UInt64)(sizeof(size_t)) << 29; - - #ifndef UNDER_CE - MY_MEMORYSTATUSEX stat; - stat.dwLength = sizeof(stat); - #endif - - #ifdef _WIN64 - - if (!::GlobalMemoryStatusEx(&stat)) - return false; - size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); - return true; - - #else - - #ifndef UNDER_CE - const - Func_GlobalMemoryStatusEx fn = Z7_GET_PROC_ADDRESS( - Func_GlobalMemoryStatusEx, ::GetModuleHandleA("kernel32.dll"), - "GlobalMemoryStatusEx"); - if (fn && fn(&stat)) - { - size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); - return true; - } - #endif - - { - MEMORYSTATUS stat2; - stat2.dwLength = sizeof(stat2); - ::GlobalMemoryStatus(&stat2); - size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys); - return true; - } - #endif -} - -#else - -// POSIX -// #include - -bool GetRamSize(UInt64 &size) -{ - size = (UInt64)(sizeof(size_t)) << 29; - -#if defined(__APPLE__) || defined(__DragonFly__) || \ - defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - - uint64_t val = 0; - int mib[2]; - mib[0] = CTL_HW; - - #ifdef HW_MEMSIZE - mib[1] = HW_MEMSIZE; - // printf("\n sysctl HW_MEMSIZE"); - #elif defined(HW_PHYSMEM64) - mib[1] = HW_PHYSMEM64; - // printf("\n sysctl HW_PHYSMEM64"); - #else - mib[1] = HW_PHYSMEM; - // printf("\n sysctl HW_PHYSMEM"); - #endif - - size_t size_sys = sizeof(val); - int res = sysctl(mib, 2, &val, &size_sys, NULL, 0); - // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val, (int)size_sys, errno); - // we use strict check (size_sys == sizeof(val)) for returned value - // because big-endian encoding is possible: - if (res == 0 && size_sys == sizeof(val) && val) - size = val; - else - { - uint32_t val32 = 0; - size_sys = sizeof(val32); - res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); - // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); - if (res == 0 && size_sys == sizeof(val32) && val32) - size = val32; - } - - #elif defined(_AIX) - #if defined(_SC_AIX_REALMEM) // AIX - size = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; - #endif - #elif 0 || defined(__sun) - #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) - // FreeBSD, Linux, OpenBSD, and Solaris. - { - const long phys_pages = sysconf(_SC_PHYS_PAGES); - const long page_size = sysconf(_SC_PAGESIZE); - // #pragma message("GetRamSize : sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)") - // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); - // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); - if (phys_pages != -1 && page_size != -1) - size = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; - } - #endif - #elif defined(__gnu_hurd__) - // fixme - #elif defined(__FreeBSD_kernel__) && defined(__GLIBC__) - // GNU/kFreeBSD Debian - // fixme - #else - - struct sysinfo info; - if (::sysinfo(&info) != 0) - return false; - size = (UInt64)info.mem_unit * info.totalram; - /* - printf("\n mem_unit = %lld", (UInt64)info.mem_unit); - printf("\n totalram = %lld", (UInt64)info.totalram); - printf("\n freeram = %lld", (UInt64)info.freeram); - */ - - #endif - - const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1); - if (size > kLimit) - size = kLimit; - - return true; -} - -#endif - - -unsigned long Get_File_OPEN_MAX() -{ - #ifdef _WIN32 - return (1 << 24) - (1 << 16); // ~16M handles - #else - // some linux versions have default open file limit for user process of 1024 files. - long n = sysconf(_SC_OPEN_MAX); - // n = -1; // for debug - // n = 9; // for debug - if (n < 1) - { - // n = OPEN_MAX; // ??? - // n = FOPEN_MAX; // = 16 : - #ifdef _POSIX_OPEN_MAX - n = _POSIX_OPEN_MAX; // = 20 : - #else - n = 30; // our limit - #endif - } - return (unsigned long)n; - #endif -} - -unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks() -{ - unsigned long numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX(); - const unsigned delta = 10; // the reserve for another internal needs of process - if (numFiles_OPEN_MAX > delta) - numFiles_OPEN_MAX -= delta; - else - numFiles_OPEN_MAX = 1; - numFiles_OPEN_MAX /= 3; // we suppose that we have up to 3 tasks in total for multiple file processing - numFiles_OPEN_MAX = MyMax(numFiles_OPEN_MAX, (unsigned long)3); - unsigned n = (unsigned)(int)-1; - if (n > numFiles_OPEN_MAX) - n = (unsigned)numFiles_OPEN_MAX; - return n; -} - -}} +// Windows/System.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 +#include +#include +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include +#else +#include +#endif +#endif + +#include "../Common/Defs.h" +// #include "../Common/MyWindows.h" + +// #include "../../C/CpuArch.h" + +#include "System.h" + +namespace NWindows { +namespace NSystem { + +#ifdef _WIN32 + +UInt32 CountAffinity(DWORD_PTR mask) +{ + UInt32 num = 0; + for (unsigned i = 0; i < sizeof(mask) * 8; i++) + { + num += (UInt32)(mask & 1); + mask >>= 1; + } + return num; +} + +BOOL CProcessAffinity::Get() +{ + #ifndef UNDER_CE + return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); + #else + return FALSE; + #endif +} + + +UInt32 GetNumberOfProcessors() +{ + // We need to know how many threads we can use. + // By default the process is assigned to one group. + // So we get the number of logical processors (threads) + // assigned to current process in the current group. + // Group size can be smaller than total number logical processors, for exammple, 2x36 + + CProcessAffinity pa; + + if (pa.Get() && pa.processAffinityMask != 0) + return pa.GetNumProcessThreads(); + + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + // the number of logical processors in the current group + return (UInt32)systemInfo.dwNumberOfProcessors; +} + +#else + + +BOOL CProcessAffinity::Get() +{ + numSysThreads = GetNumberOfProcessors(); + + /* + numSysThreads = 8; + for (unsigned i = 0; i < numSysThreads; i++) + CpuSet_Set(&cpu_set, i); + return TRUE; + */ + + #ifdef Z7_AFFINITY_SUPPORTED + + // numSysThreads = sysconf(_SC_NPROCESSORS_ONLN); // The number of processors currently online + if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0) + return FALSE; + return TRUE; + + #else + + // cpu_set = ((CCpuSet)1 << (numSysThreads)) - 1; + return TRUE; + // errno = ENOSYS; + // return FALSE; + + #endif +} + +UInt32 GetNumberOfProcessors() +{ + #ifndef Z7_ST + long n = sysconf(_SC_NPROCESSORS_CONF); // The number of processors configured + if (n < 1) + n = 1; + return (UInt32)n; + #else + return 1; + #endif +} + +#endif + + +#ifdef _WIN32 + +#ifndef UNDER_CE + +#if !defined(_WIN64) && \ + (defined(__MINGW32_VERSION) || defined(Z7_OLD_WIN_SDK)) + +typedef struct { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; +} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX; + +#else + +#define MY_MEMORYSTATUSEX MEMORYSTATUSEX +#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX + +#endif + +typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer); + +#endif // !UNDER_CE + + +bool GetRamSize(size_t &size) +{ + size = (size_t)sizeof(size_t) << 29; + + #ifndef UNDER_CE + MY_MEMORYSTATUSEX stat; + stat.dwLength = sizeof(stat); + #endif + + #ifdef _WIN64 + + if (!::GlobalMemoryStatusEx(&stat)) + return false; + size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); + return true; + + #else + + #ifndef UNDER_CE + const + Func_GlobalMemoryStatusEx fn = Z7_GET_PROC_ADDRESS( + Func_GlobalMemoryStatusEx, ::GetModuleHandleA("kernel32.dll"), + "GlobalMemoryStatusEx"); + if (fn && fn(&stat)) + { + // (MY_MEMORYSTATUSEX::ullTotalVirtual) < 4 GiB in 32-bit mode + size_t size2 = (size_t)0 - 1; + if (size2 > stat.ullTotalPhys) + size2 = (size_t)stat.ullTotalPhys; + if (size2 > stat.ullTotalVirtual) + size2 = (size_t)stat.ullTotalVirtual; + size = size2; + return true; + } + #endif + + // On computers with more than 4 GB of memory: + // new docs : GlobalMemoryStatus can report (-1) value to indicate an overflow. + // some old docs : GlobalMemoryStatus can report (modulo 4 GiB) value. + // (for example, if 5 GB total memory, it could report 1 GB). + // We don't want to get (modulo 4 GiB) value. + // So we use GlobalMemoryStatusEx() instead. + { + MEMORYSTATUS stat2; + stat2.dwLength = sizeof(stat2); + ::GlobalMemoryStatus(&stat2); + size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys); + return true; + } + #endif +} + +#else + +// POSIX +// #include + +bool GetRamSize(size_t &size) +{ + UInt64 size64; + size = (size_t)sizeof(size_t) << 29; + size64 = size; + +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + + uint64_t val = 0; + int mib[2]; + mib[0] = CTL_HW; + + #ifdef HW_MEMSIZE + mib[1] = HW_MEMSIZE; + // printf("\n sysctl HW_MEMSIZE"); + #elif defined(HW_PHYSMEM64) + mib[1] = HW_PHYSMEM64; + // printf("\n sysctl HW_PHYSMEM64"); + #else + mib[1] = HW_PHYSMEM; + // printf("\n sysctl HW_PHYSMEM"); + #endif + + size_t size_sys = sizeof(val); + int res = sysctl(mib, 2, &val, &size_sys, NULL, 0); + // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val, (int)size_sys, errno); + // we use strict check (size_sys == sizeof(val)) for returned value + // because big-endian encoding is possible: + if (res == 0 && size_sys == sizeof(val) && val) + size64 = val; + else + { + uint32_t val32 = 0; + size_sys = sizeof(val32); + res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); + // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); + if (res == 0 && size_sys == sizeof(val32) && val32) + size64 = val32; + } + + #elif defined(_AIX) + #if defined(_SC_AIX_REALMEM) // AIX + size64 = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; + #endif + #elif 0 || defined(__sun) + #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) + // FreeBSD, Linux, OpenBSD, and Solaris. + { + const long phys_pages = sysconf(_SC_PHYS_PAGES); + const long page_size = sysconf(_SC_PAGESIZE); + // #pragma message("GetRamSize : sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)") + // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); + // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); + if (phys_pages != -1 && page_size != -1) + size64 = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; + } + #endif + #elif defined(__gnu_hurd__) + // fixme + #elif defined(__FreeBSD_kernel__) && defined(__GLIBC__) + // GNU/kFreeBSD Debian + // fixme + #else + + struct sysinfo info; + if (::sysinfo(&info) != 0) + return false; + size64 = (UInt64)info.mem_unit * info.totalram; + /* + printf("\n mem_unit = %lld", (UInt64)info.mem_unit); + printf("\n totalram = %lld", (UInt64)info.totalram); + printf("\n freeram = %lld", (UInt64)info.freeram); + */ + + #endif + + size = (size_t)1 << (sizeof(size_t) * 8 - 1); + if (size > size64) + size = (size_t)size64; + return true; +} + +#endif + + +unsigned long Get_File_OPEN_MAX() +{ + #ifdef _WIN32 + return (1 << 24) - (1 << 16); // ~16M handles + #else + // some linux versions have default open file limit for user process of 1024 files. + long n = sysconf(_SC_OPEN_MAX); + // n = -1; // for debug + // n = 9; // for debug + if (n < 1) + { + // n = OPEN_MAX; // ??? + // n = FOPEN_MAX; // = 16 : + #ifdef _POSIX_OPEN_MAX + n = _POSIX_OPEN_MAX; // = 20 : + #else + n = 30; // our limit + #endif + } + return (unsigned long)n; + #endif +} + +unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks() +{ + unsigned long numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX(); + const unsigned delta = 10; // the reserve for another internal needs of process + if (numFiles_OPEN_MAX > delta) + numFiles_OPEN_MAX -= delta; + else + numFiles_OPEN_MAX = 1; + numFiles_OPEN_MAX /= 3; // we suppose that we have up to 3 tasks in total for multiple file processing + numFiles_OPEN_MAX = MyMax(numFiles_OPEN_MAX, (unsigned long)3); + unsigned n = (unsigned)(int)-1; + if (n > numFiles_OPEN_MAX) + n = (unsigned)numFiles_OPEN_MAX; + return n; +} + +}} diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h index bf63521a5..9951b8bb0 100644 --- a/CPP/Windows/System.h +++ b/CPP/Windows/System.h @@ -1,132 +1,132 @@ -// Windows/System.h - -#ifndef ZIP7_INC_WINDOWS_SYSTEM_H -#define ZIP7_INC_WINDOWS_SYSTEM_H - -#ifndef _WIN32 -// #include -#include "../../C/Threads.h" -#endif - -#include "../Common/MyTypes.h" -#include "../Common/MyWindows.h" - -namespace NWindows { -namespace NSystem { - -#ifdef _WIN32 - -UInt32 CountAffinity(DWORD_PTR mask); - -struct CProcessAffinity -{ - // UInt32 numProcessThreads; - // UInt32 numSysThreads; - DWORD_PTR processAffinityMask; - DWORD_PTR systemAffinityMask; - - void InitST() - { - // numProcessThreads = 1; - // numSysThreads = 1; - processAffinityMask = 1; - systemAffinityMask = 1; - } - - void CpuZero() - { - processAffinityMask = 0; - } - - void CpuSet(unsigned cpuIndex) - { - processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); - } - - UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } - UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } - - BOOL Get(); - - BOOL SetProcAffinity() const - { - return SetProcessAffinityMask(GetCurrentProcess(), processAffinityMask); - } -}; - - -#else // WIN32 - -struct CProcessAffinity -{ - UInt32 numSysThreads; - - UInt32 GetNumSystemThreads() const { return (UInt32)numSysThreads; } - BOOL Get(); - - #ifdef Z7_AFFINITY_SUPPORTED - - CCpuSet cpu_set; - - void InitST() - { - numSysThreads = 1; - CpuSet_Zero(&cpu_set); - CpuSet_Set(&cpu_set, 0); - } - - UInt32 GetNumProcessThreads() const { return (UInt32)CPU_COUNT(&cpu_set); } - void CpuZero() { CpuSet_Zero(&cpu_set); } - void CpuSet(unsigned cpuIndex) { CpuSet_Set(&cpu_set, cpuIndex); } - int IsCpuSet(unsigned cpuIndex) const { return CpuSet_IsSet(&cpu_set, cpuIndex); } - // void CpuClr(int cpuIndex) { CPU_CLR(cpuIndex, &cpu_set); } - - BOOL SetProcAffinity() const - { - return sched_setaffinity(0, sizeof(cpu_set), &cpu_set) == 0; - } - - #else // Z7_AFFINITY_SUPPORTED - - void InitST() - { - numSysThreads = 1; - } - - UInt32 GetNumProcessThreads() const - { - return numSysThreads; - /* - UInt32 num = 0; - for (unsigned i = 0; i < sizeof(cpu_set) * 8; i++) - num += (UInt32)((cpu_set >> i) & 1); - return num; - */ - } - - void CpuZero() { } - void CpuSet(unsigned /* cpuIndex */) { /* UNUSED_VAR(cpuIndex) */ } - int IsCpuSet(unsigned cpuIndex) const { return (cpuIndex < numSysThreads) ? 1 : 0; } - - BOOL SetProcAffinity() const - { - errno = ENOSYS; - return FALSE; - } - - #endif // Z7_AFFINITY_SUPPORTED -}; - -#endif // _WIN32 - - -UInt32 GetNumberOfProcessors(); - -bool GetRamSize(UInt64 &size); // returns false, if unknown ram size - -unsigned long Get_File_OPEN_MAX(); -unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks(); - -}} - -#endif +// Windows/System.h + +#ifndef ZIP7_INC_WINDOWS_SYSTEM_H +#define ZIP7_INC_WINDOWS_SYSTEM_H + +#ifndef _WIN32 +// #include +#include "../../C/Threads.h" +#endif + +#include "../Common/MyTypes.h" +#include "../Common/MyWindows.h" + +namespace NWindows { +namespace NSystem { + +#ifdef _WIN32 + +UInt32 CountAffinity(DWORD_PTR mask); + +struct CProcessAffinity +{ + // UInt32 numProcessThreads; + // UInt32 numSysThreads; + DWORD_PTR processAffinityMask; + DWORD_PTR systemAffinityMask; + + void InitST() + { + // numProcessThreads = 1; + // numSysThreads = 1; + processAffinityMask = 1; + systemAffinityMask = 1; + } + + void CpuZero() + { + processAffinityMask = 0; + } + + void CpuSet(unsigned cpuIndex) + { + processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); + } + + UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } + UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } + + BOOL Get(); + + BOOL SetProcAffinity() const + { + return SetProcessAffinityMask(GetCurrentProcess(), processAffinityMask); + } +}; + + +#else // WIN32 + +struct CProcessAffinity +{ + UInt32 numSysThreads; + + UInt32 GetNumSystemThreads() const { return (UInt32)numSysThreads; } + BOOL Get(); + + #ifdef Z7_AFFINITY_SUPPORTED + + CCpuSet cpu_set; + + void InitST() + { + numSysThreads = 1; + CpuSet_Zero(&cpu_set); + CpuSet_Set(&cpu_set, 0); + } + + UInt32 GetNumProcessThreads() const { return (UInt32)CPU_COUNT(&cpu_set); } + void CpuZero() { CpuSet_Zero(&cpu_set); } + void CpuSet(unsigned cpuIndex) { CpuSet_Set(&cpu_set, cpuIndex); } + int IsCpuSet(unsigned cpuIndex) const { return CpuSet_IsSet(&cpu_set, cpuIndex); } + // void CpuClr(int cpuIndex) { CPU_CLR(cpuIndex, &cpu_set); } + + BOOL SetProcAffinity() const + { + return sched_setaffinity(0, sizeof(cpu_set), &cpu_set) == 0; + } + + #else // Z7_AFFINITY_SUPPORTED + + void InitST() + { + numSysThreads = 1; + } + + UInt32 GetNumProcessThreads() const + { + return numSysThreads; + /* + UInt32 num = 0; + for (unsigned i = 0; i < sizeof(cpu_set) * 8; i++) + num += (UInt32)((cpu_set >> i) & 1); + return num; + */ + } + + void CpuZero() { } + void CpuSet(unsigned /* cpuIndex */) { /* UNUSED_VAR(cpuIndex) */ } + int IsCpuSet(unsigned cpuIndex) const { return (cpuIndex < numSysThreads) ? 1 : 0; } + + BOOL SetProcAffinity() const + { + errno = ENOSYS; + return FALSE; + } + + #endif // Z7_AFFINITY_SUPPORTED +}; + +#endif // _WIN32 + + +UInt32 GetNumberOfProcessors(); + +bool GetRamSize(size_t &size); // returns false, if unknown ram size + +unsigned long Get_File_OPEN_MAX(); +unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks(); + +}} + +#endif diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp index 3f037cf04..35846e05d 100644 --- a/CPP/Windows/SystemInfo.cpp +++ b/CPP/Windows/SystemInfo.cpp @@ -1,1170 +1,1251 @@ -// Windows/SystemInfo.cpp - -#include "StdAfx.h" - -#include "../../C/CpuArch.h" - -#include "../Common/IntToString.h" -#include "../Common/StringConvert.h" - -#ifdef _WIN32 - -#include "Registry.h" - -#else - -#include -#include -#ifdef __APPLE__ -#include - -#elif !defined(_AIX) - -#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216) - #define Z7_GETAUXV_AVAILABLE -#else -// #pragma message("=== is not NEW GLIBC === ") - #if defined __has_include - #if __has_include () -// #pragma message("=== sys/auxv.h is avail=== ") - #define Z7_GETAUXV_AVAILABLE - #endif - #endif -#endif - -#ifdef Z7_GETAUXV_AVAILABLE -// #if defined __has_include -// #if __has_include () -#include -#define USE_HWCAP -// #endif -// #endif - -// #undef AT_HWCAP // to debug -// #undef AT_HWCAP2 // to debug - -/* the following patch for some debian systems. - Is it OK to define AT_HWCAP and AT_HWCAP2 here with these constant numbers? */ -/* -#if defined(__FreeBSD_kernel__) && defined(__GLIBC__) - #ifndef AT_HWCAP - #define AT_HWCAP 16 - #endif - #ifndef AT_HWCAP2 - #define AT_HWCAP2 26 - #endif -#endif -*/ - -#ifdef USE_HWCAP - -#if defined(__FreeBSD__) - -// #if (__FreeBSD__ >= 13) // (FreeBSD 12.01 is required for elf_aux_info() ???) -static unsigned long MY_getauxval(int aux) -{ - unsigned long val; - if (elf_aux_info(aux, &val, sizeof(val))) - return 0; - return val; -} - -#else // ! __FreeBSD__ - -#ifdef MY_CPU_ARM_OR_ARM64 - #if defined __has_include - #if __has_include () -#include - #endif - #endif -#endif - -#if defined(AT_HWCAP) || defined(AT_HWCAP2) -#define MY_getauxval getauxval -#endif - -#endif // ! __FreeBSD__ -#endif // USE_HWCAP -#endif // Z7_GETAUXV_AVAILABLE - -#endif // !defined(_AIX) - -#ifdef __linux__ -#include "../Windows/FileIO.h" -#endif - -#endif // WIN32 - -#include "SystemInfo.h" -#include "System.h" - -using namespace NWindows; - -#ifdef __linux__ - -static bool ReadFile_to_Buffer(CFSTR fileName, CByteBuffer &buf) -{ - NWindows::NFile::NIO::CInFile file; - if (!file.Open(fileName)) - return false; - /* - UInt64 size; - if (!file.GetLength(size)) - { - // GetLength() doesn't work "/proc/cpuinfo" - return false; - } - if (size >= ((UInt32)1 << 29)) - return false; - */ - size_t size = 0; - size_t addSize = (size_t)1 << 12; - for (;;) - { - // printf("\nsize = %d\n", (unsigned)size); - buf.ChangeSize_KeepData(size + addSize, size); - size_t processed; - if (!file.ReadFull(buf.NonConstData() + size, addSize, processed)) - return false; - if (processed == 0) - { - buf.ChangeSize_KeepData(size, size); - return true; - } - size += processed; - addSize *= 2; - } -} - -#endif - - -#if defined(_WIN32) || defined(AT_HWCAP) || defined(AT_HWCAP2) -static void PrintHex(AString &s, UInt64 v) -{ - char temp[32]; - ConvertUInt64ToHex(v, temp); - s += temp; -} -#endif - -#ifdef MY_CPU_X86_OR_AMD64 - -Z7_NO_INLINE -static void PrintCpuChars(AString &s, UInt32 v) -{ - for (unsigned j = 0; j < 4; j++) - { - const Byte b = (Byte)(v & 0xFF); - v >>= 8; - if (b == 0) - break; - if (b >= 0x20 && b <= 0x7f) - s.Add_Char((char)b); - else - { - s.Add_Char('['); - char temp[16]; - ConvertUInt32ToHex(b, temp); - s += temp; - s.Add_Char(']'); - } - } -} - - -static void x86cpuid_to_String(AString &s) -{ - s.Empty(); - - UInt32 a[4]; - // cpuid was called already. So we don't check for cpuid availability here - z7_x86_cpuid(a, 0x80000000); - - if (a[0] >= 0x80000004) // if (maxFunc2 >= hi+4) the full name is available - { - for (unsigned i = 0; i < 3; i++) - { - z7_x86_cpuid(a, (UInt32)(0x80000002 + i)); - for (unsigned j = 0; j < 4; j++) - PrintCpuChars(s, a[j]); - } - } - - s.Trim(); - - if (s.IsEmpty()) - { - z7_x86_cpuid(a, 0); - for (unsigned i = 1; i < 4; i++) - { - const unsigned j = (i ^ (i >> 1)); - PrintCpuChars(s, a[j]); - } - s.Trim(); - } -} - -/* -static void x86cpuid_all_to_String(AString &s) -{ - Cx86cpuid p; - if (!x86cpuid_CheckAndRead(&p)) - return; - s += "x86cpuid maxFunc = "; - s.Add_UInt32(p.maxFunc); - for (unsigned j = 0; j <= p.maxFunc; j++) - { - s.Add_LF(); - // s.Add_UInt32(j); // align - { - char temp[32]; - ConvertUInt32ToString(j, temp); - unsigned len = (unsigned)strlen(temp); - while (len < 8) - { - len++; - s.Add_Space(); - } - s += temp; - } - - s += ":"; - UInt32 d[4] = { 0 }; - MyCPUID(j, &d[0], &d[1], &d[2], &d[3]); - for (unsigned i = 0; i < 4; i++) - { - char temp[32]; - ConvertUInt32ToHex8Digits(d[i], temp); - s.Add_Space(); - s += temp; - } - } -} -*/ - -#endif - - - -#ifdef _WIN32 - -static const char * const k_PROCESSOR_ARCHITECTURE[] = -{ - "x86" // "INTEL" - , "MIPS" - , "ALPHA" - , "PPC" - , "SHX" - , "ARM" - , "IA64" - , "ALPHA64" - , "MSIL" - , "x64" // "AMD64" - , "IA32_ON_WIN64" - , "NEUTRAL" - , "ARM64" - , "ARM32_ON_WIN64" -}; - -#define Z7_WIN_PROCESSOR_ARCHITECTURE_INTEL 0 -#define Z7_WIN_PROCESSOR_ARCHITECTURE_AMD64 9 - - -#define Z7_WIN_PROCESSOR_INTEL_PENTIUM 586 -#define Z7_WIN_PROCESSOR_AMD_X8664 8664 - -/* -static const CUInt32PCharPair k_PROCESSOR[] = -{ - { 2200, "IA64" }, - { 8664, "x64" } -}; - -#define PROCESSOR_INTEL_386 386 -#define PROCESSOR_INTEL_486 486 -#define PROCESSOR_INTEL_PENTIUM 586 -#define PROCESSOR_INTEL_860 860 -#define PROCESSOR_INTEL_IA64 2200 -#define PROCESSOR_AMD_X8664 8664 -#define PROCESSOR_MIPS_R2000 2000 -#define PROCESSOR_MIPS_R3000 3000 -#define PROCESSOR_MIPS_R4000 4000 -#define PROCESSOR_ALPHA_21064 21064 -#define PROCESSOR_PPC_601 601 -#define PROCESSOR_PPC_603 603 -#define PROCESSOR_PPC_604 604 -#define PROCESSOR_PPC_620 620 -#define PROCESSOR_HITACHI_SH3 10003 -#define PROCESSOR_HITACHI_SH3E 10004 -#define PROCESSOR_HITACHI_SH4 10005 -#define PROCESSOR_MOTOROLA_821 821 -#define PROCESSOR_SHx_SH3 103 -#define PROCESSOR_SHx_SH4 104 -#define PROCESSOR_STRONGARM 2577 // 0xA11 -#define PROCESSOR_ARM720 1824 // 0x720 -#define PROCESSOR_ARM820 2080 // 0x820 -#define PROCESSOR_ARM920 2336 // 0x920 -#define PROCESSOR_ARM_7TDMI 70001 -#define PROCESSOR_OPTIL 18767 // 0x494f -*/ - - -/* -static const char * const k_PF[] = -{ - "FP_ERRATA" - , "FP_EMU" - , "CMPXCHG" - , "MMX" - , "PPC_MOVEMEM_64BIT" - , "ALPHA_BYTE" - , "SSE" - , "3DNOW" - , "RDTSC" - , "PAE" - , "SSE2" - , "SSE_DAZ" - , "NX" - , "SSE3" - , "CMPXCHG16B" - , "CMP8XCHG16" - , "CHANNELS" - , "XSAVE" - , "ARM_VFP_32" - , "ARM_NEON" - , "L2AT" - , "VIRT_FIRMWARE" - , "RDWRFSGSBASE" - , "FASTFAIL" - , "ARM_DIVIDE" - , "ARM_64BIT_LOADSTORE_ATOMIC" - , "ARM_EXTERNAL_CACHE" - , "ARM_FMAC" - , "RDRAND" - , "ARM_V8" - , "ARM_V8_CRYPTO" - , "ARM_V8_CRC32" - , "RDTSCP" - , "RDPID" - , "ARM_V81_ATOMIC" - , "MONITORX" -}; -*/ - -#endif - - -static void PrintPage(AString &s, UInt64 v) -{ - const char *t = "B"; - if ((v & 0x3ff) == 0) - { - v >>= 10; - t = "KB"; - } - s.Add_UInt64(v); - s += t; -} - -#ifdef _WIN32 - -static AString TypeToString2(const char * const table[], unsigned num, UInt32 value) -{ - char sz[16]; - const char *p = NULL; - if (value < num) - p = table[value]; - if (!p) - { - ConvertUInt32ToString(value, sz); - p = sz; - } - return (AString)p; -} - -// #if defined(Z7_LARGE_PAGES) || defined(_WIN32) -// #ifdef _WIN32 -void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v) -{ - char c = 0; - if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; - if ((v & 0x3FF) == 0) { v >>= 10; c = 'M'; - if ((v & 0x3FF) == 0) { v >>= 10; c = 'G'; - if ((v & 0x3FF) == 0) { v >>= 10; c = 'T'; - }}}} - else - { - // s += "0x"; - PrintHex(s, v); - return; - } - s.Add_UInt64(v); - if (c) - s.Add_Char(c); - s.Add_Char('B'); -} -// #endif -// #endif - -static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si) -{ - s += TypeToString2(k_PROCESSOR_ARCHITECTURE, Z7_ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture); - - if (!( (si.wProcessorArchitecture == Z7_WIN_PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == Z7_WIN_PROCESSOR_INTEL_PENTIUM) - || (si.wProcessorArchitecture == Z7_WIN_PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == Z7_WIN_PROCESSOR_AMD_X8664))) - { - s.Add_Space(); - // s += TypePairToString(k_PROCESSOR, Z7_ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType); - s.Add_UInt32(si.dwProcessorType); - } - s.Add_Space(); - PrintHex(s, si.wProcessorLevel); - s.Add_Dot(); - PrintHex(s, si.wProcessorRevision); - if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors)) - if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8) - { - s += " act:"; - PrintHex(s, si.dwActiveProcessorMask); - } - s += " threads:"; - s.Add_UInt32(si.dwNumberOfProcessors); - if (si.dwPageSize != 1 << 12) - { - s += " page:"; - PrintPage(s, si.dwPageSize); - } - if (si.dwAllocationGranularity != 1 << 16) - { - s += " gran:"; - PrintPage(s, si.dwAllocationGranularity); - } - s.Add_Space(); - - const DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress; - UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1; - const UInt32 kReserveSize = ((UInt32)1 << 16); - if (minAdd != kReserveSize) - { - PrintSize_KMGT_Or_Hex(s, minAdd); - s.Add_Minus(); - } - else - { - if ((maxSize & (kReserveSize - 1)) == 0) - maxSize += kReserveSize; - } - PrintSize_KMGT_Or_Hex(s, maxSize); -} - -#ifndef _WIN64 -EXTERN_C_BEGIN -typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo); -EXTERN_C_END -#endif - -#endif - -#ifdef __APPLE__ -#ifndef MY_CPU_X86_OR_AMD64 -static void Add_sysctlbyname_to_String(const char *name, AString &s) -{ - size_t bufSize = 256; - char buf[256]; - if (z7_sysctlbyname_Get(name, &buf, &bufSize) == 0) - s += buf; -} -#endif -#endif - -void GetSysInfo(AString &s1, AString &s2); -void GetSysInfo(AString &s1, AString &s2) -{ - s1.Empty(); - s2.Empty(); - - #ifdef _WIN32 - SYSTEM_INFO si; - GetSystemInfo(&si); - { - SysInfo_To_String(s1, si); - // s += " : "; - } - - #if !defined(_WIN64) && !defined(UNDER_CE) - const - Func_GetNativeSystemInfo fn = Z7_GET_PROC_ADDRESS( - Func_GetNativeSystemInfo, GetModuleHandleA("kernel32.dll"), - "GetNativeSystemInfo"); - if (fn) - { - SYSTEM_INFO si2; - fn(&si2); - // if (memcmp(&si, &si2, sizeof(si)) != 0) - { - // s += " - "; - SysInfo_To_String(s2, si2); - } - } - #endif - #endif -} - - -static void AddBracedString(AString &dest, AString &src) -{ - if (!src.IsEmpty()) - { - dest.Add_Space_if_NotEmpty(); - dest.Add_Char('('); - dest += src; - dest.Add_Char(')'); - } -} - -struct CCpuName -{ - AString CpuName; - AString Revision; - AString Microcode; - AString LargePages; - - void Fill(); - - void Get_Revision_Microcode_LargePages(AString &s) - { - s.Empty(); - AddBracedString(s, Revision); - AddBracedString(s, Microcode); - s.Add_OptSpaced(LargePages); - } -}; - -void CCpuName::Fill() -{ - CpuName.Empty(); - Revision.Empty(); - Microcode.Empty(); - LargePages.Empty(); - - AString &s = CpuName; - - #ifdef MY_CPU_X86_OR_AMD64 - { - #if !defined(MY_CPU_AMD64) - if (z7_x86_cpuid_GetMaxFunc()) - #endif - { - x86cpuid_to_String(s); - { - UInt32 a[4]; - z7_x86_cpuid(a, 1); - char temp[16]; - ConvertUInt32ToHex(a[0], temp); - Revision += temp; - } - } - } - #elif defined(__APPLE__) - { - Add_sysctlbyname_to_String("machdep.cpu.brand_string", s); - } - #elif defined(MY_CPU_E2K) && defined(Z7_MCST_LCC_VERSION) && (Z7_MCST_LCC_VERSION >= 12323) - { - s += "mcst "; - s += __builtin_cpu_name(); - s.Add_Space(); - s += __builtin_cpu_arch(); - } - #endif - - -#ifdef _WIN32 - { - NRegistry::CKey key; - if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) - { - // s.Empty(); // for debug - { - CSysString name; - if (s.IsEmpty()) - if (key.QueryValue(TEXT("ProcessorNameString"), name) == ERROR_SUCCESS) - { - s += GetAnsiString(name); - } - if (key.QueryValue(TEXT("Identifier"), name) == ERROR_SUCCESS) - { - if (!Revision.IsEmpty()) - Revision += " : "; - Revision += GetAnsiString(name); - } - } - LONG res[2]; - CByteBuffer bufs[2]; - { - for (unsigned i = 0; i < 2; i++) - { - UInt32 size = 0; - res[i] = key.QueryValue(i == 0 ? - TEXT("Previous Update Revision") : - TEXT("Update Revision"), - bufs[i], size); - if (res[i] == ERROR_SUCCESS) - if (size != bufs[i].Size()) - res[i] = ERROR_SUCCESS + 1; - } - } - if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) - { - for (unsigned i = 0; i < 2; i++) - { - if (i == 1) - Microcode += "->"; - if (res[i] != ERROR_SUCCESS) - continue; - const CByteBuffer &buf = bufs[i]; - if (buf.Size() == 8) - { - const UInt32 high = GetUi32(buf); - if (high != 0) - { - PrintHex(Microcode, high); - Microcode.Add_Dot(); - } - PrintHex(Microcode, GetUi32(buf + 4)); - } - } - } - } - } -#endif - - if (s.IsEmpty()) - { - #ifdef MY_CPU_NAME - s += MY_CPU_NAME; - #endif - } - - #ifdef __APPLE__ - { - AString s2; - UInt32 v = 0; - if (z7_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0) - { - s2.Add_UInt32(v); - s2.Add_Char('C'); - } - if (z7_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0) - { - s2.Add_UInt32(v); - s2.Add_Char('T'); - } - if (!s2.IsEmpty()) - { - s.Add_Space_if_NotEmpty(); - s += s2; - } - } - #endif - - #ifdef Z7_LARGE_PAGES - Add_LargePages_String(LargePages); - #endif -} - -void AddCpuFeatures(AString &s); -void AddCpuFeatures(AString &s) -{ - #ifdef _WIN32 - // const unsigned kNumFeatures_Extra = 32; // we check also for unknown features - // const unsigned kNumFeatures = Z7_ARRAY_SIZE(k_PF) + kNumFeatures_Extra; - const unsigned kNumFeatures = 64; - UInt64 flags = 0; - for (unsigned i = 0; i < kNumFeatures; i++) - { - if (IsProcessorFeaturePresent((DWORD)i)) - { - flags += (UInt64)1 << i; - // s.Add_Space_if_NotEmpty(); - // s += TypeToString2(k_PF, Z7_ARRAY_SIZE(k_PF), i); - } - } - s.Add_OptSpaced("f:"); - PrintHex(s, flags); - - #elif defined(__APPLE__) - { - UInt32 v = 0; - if (z7_sysctlbyname_Get_UInt32("hw.pagesize", &v) == 0) - { - s.Add_OptSpaced("PageSize:"); - PrintPage(s, v); - } - } - - #else - - const long v = sysconf(_SC_PAGESIZE); - if (v != -1) - { - s.Add_OptSpaced("PageSize:"); - PrintPage(s, (unsigned long)v); - } - - #if !defined(_AIX) - - #ifdef __linux__ - - CByteBuffer buf; - if (ReadFile_to_Buffer("/sys/kernel/mm/transparent_hugepage/enabled", buf)) - // if (ReadFile_to_Buffer("/proc/cpuinfo", buf)) - { - s.Add_OptSpaced("THP:"); - AString s2; - s2.SetFrom_CalcLen((const char *)(const void *)(const Byte *)buf, (unsigned)buf.Size()); - const int pos = s2.Find('['); - if (pos >= 0) - { - const int pos2 = s2.Find(']', (unsigned)pos + 1); - if (pos2 >= 0) - { - s2.DeleteFrom((unsigned)pos2); - s2.DeleteFrontal((unsigned)pos + 1); - } - } - s += s2; - } - // else throw CSystemException(MY_SRes_HRESULT_FROM_WRes(errno)); - - #endif - - - #ifdef AT_HWCAP - s.Add_OptSpaced("hwcap:"); - { - unsigned long h = MY_getauxval(AT_HWCAP); - PrintHex(s, h); - #ifdef MY_CPU_ARM64 - if (h & HWCAP_CRC32) s += ":CRC32"; - if (h & HWCAP_SHA1) s += ":SHA1"; - if (h & HWCAP_SHA2) s += ":SHA2"; - if (h & HWCAP_AES) s += ":AES"; - if (h & HWCAP_ASIMD) s += ":ASIMD"; - #elif defined(MY_CPU_ARM) - if (h & HWCAP_NEON) s += ":NEON"; - #endif - } - #endif // AT_HWCAP - - #ifdef AT_HWCAP2 - { - unsigned long h = MY_getauxval(AT_HWCAP2); - #ifndef MY_CPU_ARM - if (h != 0) - #endif - { - s += " hwcap2:"; - PrintHex(s, h); - #ifdef MY_CPU_ARM - if (h & HWCAP2_CRC32) s += ":CRC32"; - if (h & HWCAP2_SHA1) s += ":SHA1"; - if (h & HWCAP2_SHA2) s += ":SHA2"; - if (h & HWCAP2_AES) s += ":AES"; - #endif - } - } - #endif // AT_HWCAP2 - #endif // _AIX - #endif // _WIN32 -} - - -#ifdef _WIN32 -#ifndef UNDER_CE - -Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION - -EXTERN_C_BEGIN -typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); -EXTERN_C_END - -static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi) -{ - const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); - if (!ntdll) - return FALSE; - const - Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS( - Func_RtlGetVersion, ntdll, - "RtlGetVersion"); - if (!func) - return FALSE; - func(vi); - return TRUE; -} - -#endif -#endif - - -void GetOsInfoText(AString &sRes) -{ - sRes.Empty(); - AString s; - - #ifdef _WIN32 - #ifndef UNDER_CE - // OSVERSIONINFO vi; - OSVERSIONINFOEXW vi; - vi.dwOSVersionInfoSize = sizeof(vi); - // if (::GetVersionEx(&vi)) - if (My_RtlGetVersion(&vi)) - { - s += "Windows"; - if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) - s.Add_UInt32(vi.dwPlatformId); - s.Add_Space(); s.Add_UInt32(vi.dwMajorVersion); - s.Add_Dot(); s.Add_UInt32(vi.dwMinorVersion); - s.Add_Space(); s.Add_UInt32(vi.dwBuildNumber); - - if (vi.wServicePackMajor != 0 || vi.wServicePackMinor != 0) - { - s += " SP:"; s.Add_UInt32(vi.wServicePackMajor); - s.Add_Dot(); s.Add_UInt32(vi.wServicePackMinor); - } - // s += " Suite:"; PrintHex(s, vi.wSuiteMask); - // s += " Type:"; s.Add_UInt32(vi.wProductType); - // s.Add_Space(); s += GetOemString(vi.szCSDVersion); - } - /* - { - s += " OEMCP:"; s.Add_UInt32(GetOEMCP()); - s += " ACP:"; s.Add_UInt32(GetACP()); - } - */ - #endif - #else // _WIN32 - - if (!s.IsEmpty()) - s.Add_LF(); - struct utsname un; - if (uname(&un) == 0) - { - s += un.sysname; - // s += " : "; s += un.nodename; // we don't want to show name of computer - s += " : "; s += un.release; - s += " : "; s += un.version; - s += " : "; s += un.machine; - - #ifdef __APPLE__ - // Add_sysctlbyname_to_String("kern.version", s); - // it's same as "utsname.version" - #endif - } - #endif // _WIN32 - - sRes += s; - #ifdef MY_CPU_X86_OR_AMD64 - { - AString s2; - GetVirtCpuid(s2); - if (!s2.IsEmpty()) - { - sRes += " : "; - sRes += s2; - } - } - #endif -} - - - -void GetSystemInfoText(AString &sRes) -{ - GetOsInfoText(sRes); - sRes.Add_LF(); - - { - AString s, s1, s2; - GetSysInfo(s1, s2); - if (!s1.IsEmpty() || !s2.IsEmpty()) - { - s = s1; - if (s1 != s2 && !s2.IsEmpty()) - { - s += " - "; - s += s2; - } - } - { - AddCpuFeatures(s); - if (!s.IsEmpty()) - { - sRes += s; - sRes.Add_LF(); - } - } - } - { - AString s; - GetCpuName_MultiLine(s); - if (!s.IsEmpty()) - { - sRes += s; - sRes.Add_LF(); - } - } - /* - #ifdef MY_CPU_X86_OR_AMD64 - { - AString s; - x86cpuid_all_to_String(s); - if (!s.IsEmpty()) - { - printCallback->Print(s); - printCallback->NewLine(); - } - } - #endif - */ -} - - -void GetCpuName_MultiLine(AString &s); -void GetCpuName_MultiLine(AString &s) -{ - CCpuName cpuName; - cpuName.Fill(); - s = cpuName.CpuName; - AString s2; - cpuName.Get_Revision_Microcode_LargePages(s2); - if (!s2.IsEmpty()) - { - s.Add_LF(); - s += s2; - } -} - - -#ifdef MY_CPU_X86_OR_AMD64 - -void GetVirtCpuid(AString &s) -{ - const UInt32 kHv = 0x40000000; - - Z7_IF_X86_CPUID_SUPPORTED - { - UInt32 a[4]; - z7_x86_cpuid(a, kHv); - - if (a[0] < kHv || a[0] >= kHv + (1 << 16)) - return; - { - { - for (unsigned j = 1; j < 4; j++) - PrintCpuChars(s, a[j]); - } - } - if (a[0] >= kHv + 1) - { - UInt32 d[4]; - z7_x86_cpuid(d, kHv + 1); - s += " : "; - PrintCpuChars(s, d[0]); - if (a[0] >= kHv + 2) - { - z7_x86_cpuid(d, kHv + 2); - s += " : "; - s.Add_UInt32(d[1] >> 16); - s.Add_Dot(); s.Add_UInt32(d[1] & 0xffff); - s.Add_Dot(); s.Add_UInt32(d[0]); - s.Add_Dot(); s.Add_UInt32(d[2]); - s.Add_Dot(); s.Add_UInt32(d[3] >> 24); - s.Add_Dot(); s.Add_UInt32(d[3] & 0xffffff); - } - /* - if (a[0] >= kHv + 5) - { - z7_x86_cpuid(d, kHv + 5); - s += " : "; - s.Add_UInt32(d[0]); - s += "p"; - s.Add_UInt32(d[1]); - s += "t"; - } - */ - } - } -} - -#endif - - -void GetCompiler(AString &s) -{ - #ifdef __clang__ - s += " CLANG "; - s.Add_UInt32(__clang_major__); - s.Add_Dot(); - s.Add_UInt32(__clang_minor__); - s.Add_Dot(); - s.Add_UInt32(__clang_patchlevel__); - #endif - - #ifdef __xlC__ - s += " XLC "; - s.Add_UInt32(__xlC__ >> 8); - s.Add_Dot(); - s.Add_UInt32(__xlC__ & 0xFF); - #ifdef __xlC_ver__ - s.Add_Dot(); - s.Add_UInt32(__xlC_ver__ >> 8); - s.Add_Dot(); - s.Add_UInt32(__xlC_ver__ & 0xFF); - #endif - #endif - - // #define __LCC__ 126 - // #define __LCC_MINOR__ 20 - // #define __MCST__ 1 - #ifdef __MCST__ - s += " MCST"; - #endif - #ifdef __LCC__ - s += " LCC "; - s.Add_UInt32(__LCC__ / 100); - s.Add_Dot(); - s.Add_UInt32(__LCC__ % 100 / 10); - s.Add_UInt32(__LCC__ % 10); - #ifdef __LCC_MINOR__ - s.Add_Dot(); - s.Add_UInt32(__LCC_MINOR__ / 10); - s.Add_UInt32(__LCC_MINOR__ % 10); - #endif - #endif - - // #define __EDG_VERSION__ 602 - #ifdef __EDG_VERSION__ - s += " EDG "; - s.Add_UInt32(__EDG_VERSION__ / 100); - s.Add_Dot(); - s.Add_UInt32(__EDG_VERSION__ % 100 / 10); - s.Add_UInt32(__EDG_VERSION__ % 10); - #endif - - #ifdef __VERSION__ - s.Add_Space(); - s += "ver:"; - s += __VERSION__; - #endif - - #ifdef __GNUC__ - s += " GCC "; - s.Add_UInt32(__GNUC__); - s.Add_Dot(); - s.Add_UInt32(__GNUC_MINOR__); - s.Add_Dot(); - s.Add_UInt32(__GNUC_PATCHLEVEL__); - #endif - - - #ifdef _MSC_VER - s += " MSC "; - s.Add_UInt32(_MSC_VER); - #ifdef _MSC_FULL_VER - s.Add_Dot(); - s.Add_UInt32(_MSC_FULL_VER); - #endif - - #endif - - #if defined(__AVX512F__) - #if defined(__AVX512VL__) - #define MY_CPU_COMPILE_ISA "AVX512VL" - #else - #define MY_CPU_COMPILE_ISA "AVX512F" - #endif - #elif defined(__AVX2__) - #define MY_CPU_COMPILE_ISA "AVX2" - #elif defined(__AVX__) - #define MY_CPU_COMPILE_ISA "AVX" - #elif defined(__SSE2__) - #define MY_CPU_COMPILE_ISA "SSE2" - #elif defined(_M_IX86_FP) && (_M_IX86_FP >= 2) - #define MY_CPU_COMPILE_ISA "SSE2" - #elif defined(__SSE__) - #define MY_CPU_COMPILE_ISA "SSE" - #elif defined(_M_IX86_FP) && (_M_IX86_FP >= 1) - #define MY_CPU_COMPILE_ISA "SSE" - #elif defined(__i686__) - #define MY_CPU_COMPILE_ISA "i686" - #elif defined(__i586__) - #define MY_CPU_COMPILE_ISA "i586" - #elif defined(__i486__) - #define MY_CPU_COMPILE_ISA "i486" - #elif defined(__i386__) - #define MY_CPU_COMPILE_ISA "i386" - #elif defined(_M_IX86_FP) - #define MY_CPU_COMPILE_ISA "IA32" - #endif - - AString s2; - - #ifdef MY_CPU_COMPILE_ISA - s2.Add_OptSpaced(MY_CPU_COMPILE_ISA); - #endif - -#ifndef MY_CPU_ARM64 - #ifdef __ARM_FP - s2.Add_OptSpaced("FP"); - #endif - #ifdef __ARM_NEON - s2.Add_OptSpaced("NEON"); - #endif - #ifdef __NEON__ - s2.Add_OptSpaced("__NEON__"); - #endif - #ifdef __ARM_FEATURE_SIMD32 - s2.Add_OptSpaced("SIMD32"); - #endif -#endif - - #ifdef __ARM_FEATURE_CRYPTO - s2.Add_OptSpaced("CRYPTO"); - #endif - - #ifdef __ARM_FEATURE_SHA2 - s2.Add_OptSpaced("SHA2"); - #endif - - #ifdef __ARM_FEATURE_AES - s2.Add_OptSpaced("AES"); - #endif - - #ifdef __ARM_FEATURE_CRC32 - s2.Add_OptSpaced("CRC32"); - #endif - - #ifdef __ARM_FEATURE_UNALIGNED - s2.Add_OptSpaced("UNALIGNED"); - #endif - - - #ifdef MY_CPU_BE - s2.Add_OptSpaced("BE"); - #endif - - #if defined(MY_CPU_LE_UNALIGN) \ - && !defined(MY_CPU_X86_OR_AMD64) \ - && !defined(MY_CPU_ARM64) - s2.Add_OptSpaced("LE-unaligned"); - #endif - - if (!s2.IsEmpty()) - { - s.Add_OptSpaced(": "); - s += s2; - } -} +// Windows/SystemInfo.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#include "../Common/IntToString.h" +#include "../Common/StringConvert.h" + +#ifdef _WIN32 + +#include "Registry.h" + +#else + +#include +#include +#ifdef __APPLE__ +#include + +#elif !defined(_AIX) + +#if defined(__GLIBC__) && (__GLIBC__ * 100 + __GLIBC_MINOR__ >= 216) + #define Z7_GETAUXV_AVAILABLE +#else +// #pragma message("=== is not NEW GLIBC === ") + #if defined __has_include + #if __has_include () +// #pragma message("=== sys/auxv.h is avail=== ") + #define Z7_GETAUXV_AVAILABLE + #endif + #endif +#endif + +#ifdef Z7_GETAUXV_AVAILABLE +// #if defined __has_include +// #if __has_include () +#include +#define USE_HWCAP +// #endif +// #endif + +// #undef AT_HWCAP // to debug +// #undef AT_HWCAP2 // to debug + +/* the following patch for some debian systems. + Is it OK to define AT_HWCAP and AT_HWCAP2 here with these constant numbers? */ +/* +#if defined(__FreeBSD_kernel__) && defined(__GLIBC__) + #ifndef AT_HWCAP + #define AT_HWCAP 16 + #endif + #ifndef AT_HWCAP2 + #define AT_HWCAP2 26 + #endif +#endif +*/ + +#ifdef USE_HWCAP + +#if defined(__FreeBSD__) + +// #if (__FreeBSD__ >= 13) // (FreeBSD 12.01 is required for elf_aux_info() ???) +static unsigned long MY_getauxval(int aux) +{ + unsigned long val; + if (elf_aux_info(aux, &val, sizeof(val))) + return 0; + return val; +} + +#else // ! __FreeBSD__ + +#ifdef MY_CPU_ARM_OR_ARM64 + #if defined __has_include + #if __has_include () +#include + #endif + #endif +#endif + +#if defined(AT_HWCAP) || defined(AT_HWCAP2) +#define MY_getauxval getauxval +#endif + +#endif // ! __FreeBSD__ +#endif // USE_HWCAP +#endif // Z7_GETAUXV_AVAILABLE + +#endif // !defined(_AIX) + +#ifdef __linux__ +#include "../Windows/FileIO.h" +#endif + +#endif // WIN32 + +#include "SystemInfo.h" +#include "System.h" + +using namespace NWindows; + +#ifdef __linux__ + +static bool ReadFile_to_Buffer(CFSTR fileName, CByteBuffer &buf) +{ + NWindows::NFile::NIO::CInFile file; + if (!file.Open(fileName)) + return false; + /* + UInt64 size; + if (!file.GetLength(size)) + { + // GetLength() doesn't work "/proc/cpuinfo" + return false; + } + if (size >= ((UInt32)1 << 29)) + return false; + */ + size_t size = 0; + size_t addSize = (size_t)1 << 12; + for (;;) + { + // printf("\nsize = %d\n", (unsigned)size); + buf.ChangeSize_KeepData(size + addSize, size); + size_t processed; + if (!file.ReadFull(buf.NonConstData() + size, addSize, processed)) + return false; + if (processed == 0) + { + buf.ChangeSize_KeepData(size, size); + return true; + } + size += processed; + addSize *= 2; + } +} + +#endif + + +#if defined(_WIN32) || defined(AT_HWCAP) || defined(AT_HWCAP2) +static void PrintHex(AString &s, UInt64 v) +{ + char temp[32]; + ConvertUInt64ToHex(v, temp); + s += temp; +} +#endif + +#ifdef MY_CPU_X86_OR_AMD64 + +Z7_NO_INLINE +static void PrintCpuChars(AString &s, UInt32 v) +{ + for (unsigned j = 0; j < 4; j++) + { + const Byte b = (Byte)(v & 0xFF); + v >>= 8; + if (b == 0) + break; + if (b >= 0x20 && b <= 0x7f) + s.Add_Char((char)b); + else + { + s.Add_Char('['); + char temp[16]; + ConvertUInt32ToHex(b, temp); + s += temp; + s.Add_Char(']'); + } + } +} + + +static void x86cpuid_to_String(AString &s) +{ + s.Empty(); + + UInt32 a[4]; + // cpuid was called already. So we don't check for cpuid availability here + z7_x86_cpuid(a, 0x80000000); + + if (a[0] >= 0x80000004) // if (maxFunc2 >= hi+4) the full name is available + { + for (unsigned i = 0; i < 3; i++) + { + z7_x86_cpuid(a, (UInt32)(0x80000002 + i)); + for (unsigned j = 0; j < 4; j++) + PrintCpuChars(s, a[j]); + } + } + + s.Trim(); + + if (s.IsEmpty()) + { + z7_x86_cpuid(a, 0); + for (unsigned i = 1; i < 4; i++) + { + const unsigned j = (i ^ (i >> 1)); + PrintCpuChars(s, a[j]); + } + s.Trim(); + } +} + +/* +static void x86cpuid_all_to_String(AString &s) +{ + Cx86cpuid p; + if (!x86cpuid_CheckAndRead(&p)) + return; + s += "x86cpuid maxFunc = "; + s.Add_UInt32(p.maxFunc); + for (unsigned j = 0; j <= p.maxFunc; j++) + { + s.Add_LF(); + // s.Add_UInt32(j); // align + { + char temp[32]; + ConvertUInt32ToString(j, temp); + unsigned len = (unsigned)strlen(temp); + while (len < 8) + { + len++; + s.Add_Space(); + } + s += temp; + } + + s += ":"; + UInt32 d[4] = { 0 }; + MyCPUID(j, &d[0], &d[1], &d[2], &d[3]); + for (unsigned i = 0; i < 4; i++) + { + char temp[32]; + ConvertUInt32ToHex8Digits(d[i], temp); + s.Add_Space(); + s += temp; + } + } +} +*/ + +#endif + + + +#ifdef _WIN32 + +static const char * const k_PROCESSOR_ARCHITECTURE[] = +{ + "x86" // "INTEL" + , "MIPS" + , "ALPHA" + , "PPC" + , "SHX" + , "ARM" + , "IA64" + , "ALPHA64" + , "MSIL" + , "x64" // "AMD64" + , "IA32_ON_WIN64" + , "NEUTRAL" + , "ARM64" + , "ARM32_ON_WIN64" +}; + +#define Z7_WIN_PROCESSOR_ARCHITECTURE_INTEL 0 +#define Z7_WIN_PROCESSOR_ARCHITECTURE_AMD64 9 + + +#define Z7_WIN_PROCESSOR_INTEL_PENTIUM 586 +#define Z7_WIN_PROCESSOR_AMD_X8664 8664 + +/* +static const CUInt32PCharPair k_PROCESSOR[] = +{ + { 2200, "IA64" }, + { 8664, "x64" } +}; + +#define PROCESSOR_INTEL_386 386 +#define PROCESSOR_INTEL_486 486 +#define PROCESSOR_INTEL_PENTIUM 586 +#define PROCESSOR_INTEL_860 860 +#define PROCESSOR_INTEL_IA64 2200 +#define PROCESSOR_AMD_X8664 8664 +#define PROCESSOR_MIPS_R2000 2000 +#define PROCESSOR_MIPS_R3000 3000 +#define PROCESSOR_MIPS_R4000 4000 +#define PROCESSOR_ALPHA_21064 21064 +#define PROCESSOR_PPC_601 601 +#define PROCESSOR_PPC_603 603 +#define PROCESSOR_PPC_604 604 +#define PROCESSOR_PPC_620 620 +#define PROCESSOR_HITACHI_SH3 10003 +#define PROCESSOR_HITACHI_SH3E 10004 +#define PROCESSOR_HITACHI_SH4 10005 +#define PROCESSOR_MOTOROLA_821 821 +#define PROCESSOR_SHx_SH3 103 +#define PROCESSOR_SHx_SH4 104 +#define PROCESSOR_STRONGARM 2577 // 0xA11 +#define PROCESSOR_ARM720 1824 // 0x720 +#define PROCESSOR_ARM820 2080 // 0x820 +#define PROCESSOR_ARM920 2336 // 0x920 +#define PROCESSOR_ARM_7TDMI 70001 +#define PROCESSOR_OPTIL 18767 // 0x494f +*/ + + +/* +static const char * const k_PF[] = +{ + "FP_ERRATA" + , "FP_EMU" + , "CMPXCHG" + , "MMX" + , "PPC_MOVEMEM_64BIT" + , "ALPHA_BYTE" + , "SSE" + , "3DNOW" + , "RDTSC" + , "PAE" + , "SSE2" + , "SSE_DAZ" + , "NX" + , "SSE3" + , "CMPXCHG16B" + , "CMP8XCHG16" + , "CHANNELS" + , "XSAVE" + , "ARM_VFP_32" + , "ARM_NEON" + , "L2AT" + , "VIRT_FIRMWARE" + , "RDWRFSGSBASE" + , "FASTFAIL" + , "ARM_DIVIDE" + , "ARM_64BIT_LOADSTORE_ATOMIC" + , "ARM_EXTERNAL_CACHE" + , "ARM_FMAC" + , "RDRAND" + , "ARM_V8" + , "ARM_V8_CRYPTO" + , "ARM_V8_CRC32" + , "RDTSCP" + , "RDPID" + , "ARM_V81_ATOMIC" + , "MONITORX" +}; +*/ + +#endif + + +static void PrintPage(AString &s, UInt64 v) +{ + const char *t = "B"; + if ((v & 0x3ff) == 0) + { + v >>= 10; + t = "KB"; + } + s.Add_UInt64(v); + s += t; +} + +#ifdef _WIN32 + +static AString TypeToString2(const char * const table[], unsigned num, UInt32 value) +{ + char sz[16]; + const char *p = NULL; + if (value < num) + p = table[value]; + if (!p) + { + ConvertUInt32ToString(value, sz); + p = sz; + } + return (AString)p; +} + +// #if defined(Z7_LARGE_PAGES) || defined(_WIN32) +// #ifdef _WIN32 +void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v) +{ + char c = 0; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'M'; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'G'; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'T'; + }}}} + else + { + // s += "0x"; + PrintHex(s, v); + return; + } + s.Add_UInt64(v); + if (c) + s.Add_Char(c); + s.Add_Char('B'); +} +// #endif +// #endif + +static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si) +{ + s += TypeToString2(k_PROCESSOR_ARCHITECTURE, Z7_ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture); + + if (!( (si.wProcessorArchitecture == Z7_WIN_PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == Z7_WIN_PROCESSOR_INTEL_PENTIUM) + || (si.wProcessorArchitecture == Z7_WIN_PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == Z7_WIN_PROCESSOR_AMD_X8664))) + { + s.Add_Space(); + // s += TypePairToString(k_PROCESSOR, Z7_ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType); + s.Add_UInt32(si.dwProcessorType); + } + s.Add_Space(); + PrintHex(s, si.wProcessorLevel); + s.Add_Dot(); + PrintHex(s, si.wProcessorRevision); + if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors)) + if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8) + { + s += " act:"; + PrintHex(s, si.dwActiveProcessorMask); + } + s += " threads:"; + s.Add_UInt32(si.dwNumberOfProcessors); + if (si.dwPageSize != 1 << 12) + { + s += " page:"; + PrintPage(s, si.dwPageSize); + } + if (si.dwAllocationGranularity != 1 << 16) + { + s += " gran:"; + PrintPage(s, si.dwAllocationGranularity); + } + s.Add_Space(); + + const DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress; + UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1; + const UInt32 kReserveSize = ((UInt32)1 << 16); + if (minAdd != kReserveSize) + { + PrintSize_KMGT_Or_Hex(s, minAdd); + s.Add_Minus(); + } + else + { + if ((maxSize & (kReserveSize - 1)) == 0) + maxSize += kReserveSize; + } + PrintSize_KMGT_Or_Hex(s, maxSize); +} + +#ifndef _WIN64 +EXTERN_C_BEGIN +typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo); +EXTERN_C_END +#endif + +#endif + +#ifdef __APPLE__ +#ifndef MY_CPU_X86_OR_AMD64 +static void Add_sysctlbyname_to_String(const char *name, AString &s) +{ + size_t bufSize = 256; + char buf[256]; + if (z7_sysctlbyname_Get(name, &buf, &bufSize) == 0) + s += buf; +} +#endif +#endif + +void GetSysInfo(AString &s1, AString &s2); +void GetSysInfo(AString &s1, AString &s2) +{ + s1.Empty(); + s2.Empty(); + + #ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + { + SysInfo_To_String(s1, si); + // s += " : "; + } + + #if !defined(_WIN64) && !defined(UNDER_CE) + const + Func_GetNativeSystemInfo fn = Z7_GET_PROC_ADDRESS( + Func_GetNativeSystemInfo, GetModuleHandleA("kernel32.dll"), + "GetNativeSystemInfo"); + if (fn) + { + SYSTEM_INFO si2; + fn(&si2); + // if (memcmp(&si, &si2, sizeof(si)) != 0) + { + // s += " - "; + SysInfo_To_String(s2, si2); + } + } + #endif + #endif +} + + +static void AddBracedString(AString &dest, AString &src) +{ + if (!src.IsEmpty()) + { + dest.Add_Space_if_NotEmpty(); + dest.Add_Char('('); + dest += src; + dest.Add_Char(')'); + } +} + +struct CCpuName +{ + AString CpuName; + AString Revision; + AString Microcode; + AString LargePages; + +#ifdef _WIN32 + UInt32 MHz; + +#ifdef MY_CPU_ARM64 +#define Z7_SYS_INFO_SHOW_ARM64_REGS +#endif +#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS + bool Arm64_ISAR0_EL1_Defined; + UInt64 Arm64_ISAR0_EL1; +#endif +#endif + +#ifdef _WIN32 + CCpuName(): + MHz(0) +#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS + , Arm64_ISAR0_EL1_Defined(false) + , Arm64_ISAR0_EL1(0) +#endif + {} +#endif + + void Fill(); + + void Get_Revision_Microcode_LargePages(AString &s) + { + s.Empty(); + AddBracedString(s, Revision); + AddBracedString(s, Microcode); +#ifdef _WIN32 + if (MHz != 0) + { + s.Add_Space_if_NotEmpty(); + s.Add_UInt32(MHz); + s += " MHz"; + } +#endif + if (!LargePages.IsEmpty()) + s.Add_OptSpaced(LargePages); + } + +#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS + void Get_Registers(AString &s) + { + if (Arm64_ISAR0_EL1_Defined) + { + // ID_AA64ISAR0_EL1 + s.Add_OptSpaced("cp4030:"); + PrintHex(s, Arm64_ISAR0_EL1); + { + const unsigned sha2 = ((unsigned)(Arm64_ISAR0_EL1 >> 12) & 0xf) - 1; + if (sha2 < 2) + { + s += ":SHA256"; + if (sha2) + s += ":SHA512"; + } + } + } + } +#endif +}; + +void CCpuName::Fill() +{ + // CpuName.Empty(); + // Revision.Empty(); + // Microcode.Empty(); + // LargePages.Empty(); + + AString &s = CpuName; + + #ifdef MY_CPU_X86_OR_AMD64 + { + #if !defined(MY_CPU_AMD64) + if (z7_x86_cpuid_GetMaxFunc()) + #endif + { + x86cpuid_to_String(s); + { + UInt32 a[4]; + z7_x86_cpuid(a, 1); + char temp[16]; + ConvertUInt32ToHex(a[0], temp); + Revision += temp; + } + } + } + #elif defined(__APPLE__) + { + Add_sysctlbyname_to_String("machdep.cpu.brand_string", s); + } + #elif defined(MY_CPU_E2K) && defined(Z7_MCST_LCC_VERSION) && (Z7_MCST_LCC_VERSION >= 12323) + { + s += "mcst "; + s += __builtin_cpu_name(); + s.Add_Space(); + s += __builtin_cpu_arch(); + } + #endif + + +#ifdef _WIN32 + { + NRegistry::CKey key; + if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) + { + // s.Empty(); // for debug + { + CSysString name; + if (s.IsEmpty()) + if (key.QueryValue(TEXT("ProcessorNameString"), name) == ERROR_SUCCESS) + { + s += GetAnsiString(name); + } + if (key.QueryValue(TEXT("Identifier"), name) == ERROR_SUCCESS) + { + if (!Revision.IsEmpty()) + Revision += " : "; + Revision += GetAnsiString(name); + } + } +#ifdef _WIN32 + key.GetValue_UInt32_IfOk(TEXT("~MHz"), MHz); +#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS +/* +mapping arm64 registers to Windows registry: +CP 4000: MIDR_EL1 +CP 4020: ID_AA64PFR0_EL1 +CP 4021: ID_AA64PFR1_EL1 +CP 4028: ID_AA64DFR0_EL1 +CP 4029: ID_AA64DFR1_EL1 +CP 402C: ID_AA64AFR0_EL1 +CP 402D: ID_AA64AFR1_EL1 +CP 4030: ID_AA64ISAR0_EL1 +CP 4031: ID_AA64ISAR1_EL1 +CP 4038: ID_AA64MMFR0_EL1 +CP 4039: ID_AA64MMFR1_EL1 +CP 403A: ID_AA64MMFR2_EL1 +*/ + if (key.GetValue_UInt64_IfOk(TEXT("CP 4030"), Arm64_ISAR0_EL1) == ERROR_SUCCESS) + Arm64_ISAR0_EL1_Defined = true; +#endif +#endif + LONG res[2]; + CByteBuffer bufs[2]; + res[0] = key.QueryValue_Binary(TEXT("Previous Update Revision"), bufs[0]); + res[1] = key.QueryValue_Binary(TEXT("Update Revision"), bufs[1]); + if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) + { + for (unsigned i = 0; i < 2; i++) + { + if (i == 1) + Microcode += "->"; + if (res[i] != ERROR_SUCCESS) + continue; + const CByteBuffer &buf = bufs[i]; + if (buf.Size() == 8) + { + const UInt32 high = GetUi32(buf); + if (high != 0) + { + PrintHex(Microcode, high); + Microcode.Add_Dot(); + } + PrintHex(Microcode, GetUi32(buf + 4)); + } + } + } + } + } +#endif + + if (s.IsEmpty()) + { + #ifdef MY_CPU_NAME + s += MY_CPU_NAME; + #endif + } + + #ifdef __APPLE__ + { + AString s2; + UInt32 v = 0; + if (z7_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0) + { + s2.Add_UInt32(v); + s2.Add_Char('C'); + } + if (z7_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0) + { + s2.Add_UInt32(v); + s2.Add_Char('T'); + } + if (!s2.IsEmpty()) + { + s.Add_Space_if_NotEmpty(); + s += s2; + } + } + #endif + + #ifdef Z7_LARGE_PAGES + Add_LargePages_String(LargePages); + #endif +} + +void AddCpuFeatures(AString &s); +void AddCpuFeatures(AString &s) +{ + #ifdef _WIN32 + // const unsigned kNumFeatures_Extra = 32; // we check also for unknown features + // const unsigned kNumFeatures = Z7_ARRAY_SIZE(k_PF) + kNumFeatures_Extra; + const unsigned kNumFeatures = 64; + UInt64 flags = 0; + for (unsigned i = 0; i < kNumFeatures; i++) + { + if (IsProcessorFeaturePresent((DWORD)i)) + { + flags += (UInt64)1 << i; + // s.Add_Space_if_NotEmpty(); + // s += TypeToString2(k_PF, Z7_ARRAY_SIZE(k_PF), i); + } + } + s.Add_OptSpaced("f:"); + PrintHex(s, flags); + + #elif defined(__APPLE__) + { + UInt32 v = 0; + if (z7_sysctlbyname_Get_UInt32("hw.pagesize", &v) == 0) + { + s.Add_OptSpaced("PageSize:"); + PrintPage(s, v); + } + } + + #else + + const long v = sysconf(_SC_PAGESIZE); + if (v != -1) + { + s.Add_OptSpaced("PageSize:"); + PrintPage(s, (unsigned long)v); + } + + #if !defined(_AIX) + + #ifdef __linux__ + + CByteBuffer buf; + if (ReadFile_to_Buffer("/sys/kernel/mm/transparent_hugepage/enabled", buf)) + // if (ReadFile_to_Buffer("/proc/cpuinfo", buf)) + { + s.Add_OptSpaced("THP:"); + AString s2; + s2.SetFrom_CalcLen((const char *)(const void *)(const Byte *)buf, (unsigned)buf.Size()); + const int pos = s2.Find('['); + if (pos >= 0) + { + const int pos2 = s2.Find(']', (unsigned)pos + 1); + if (pos2 >= 0) + { + s2.DeleteFrom((unsigned)pos2); + s2.DeleteFrontal((unsigned)pos + 1); + } + } + s += s2; + } + // else throw CSystemException(MY_SRes_HRESULT_FROM_WRes(errno)); + + #endif + + + #ifdef AT_HWCAP + s.Add_OptSpaced("hwcap:"); + { + unsigned long h = MY_getauxval(AT_HWCAP); + PrintHex(s, h); + #ifdef MY_CPU_ARM64 +#ifndef HWCAP_SHA3 +#define HWCAP_SHA3 (1 << 17) +#endif +#ifndef HWCAP_SHA512 +#define HWCAP_SHA512 (1 << 21) +// #pragma message("=== HWCAP_SHA512 define === ") +#endif + if (h & HWCAP_CRC32) s += ":CRC32"; + if (h & HWCAP_SHA1) s += ":SHA1"; + if (h & HWCAP_SHA2) s += ":SHA2"; + if (h & HWCAP_SHA3) s += ":SHA3"; + if (h & HWCAP_SHA512) s += ":SHA512"; + if (h & HWCAP_AES) s += ":AES"; + if (h & HWCAP_ASIMD) s += ":ASIMD"; + #elif defined(MY_CPU_ARM) + if (h & HWCAP_NEON) s += ":NEON"; + #endif + } + #endif // AT_HWCAP + + #ifdef AT_HWCAP2 + { + unsigned long h = MY_getauxval(AT_HWCAP2); + #ifndef MY_CPU_ARM + if (h != 0) + #endif + { + s += " hwcap2:"; + PrintHex(s, h); + #ifdef MY_CPU_ARM + if (h & HWCAP2_CRC32) s += ":CRC32"; + if (h & HWCAP2_SHA1) s += ":SHA1"; + if (h & HWCAP2_SHA2) s += ":SHA2"; + if (h & HWCAP2_AES) s += ":AES"; + #endif + } + } + #endif // AT_HWCAP2 + #endif // _AIX + #endif // _WIN32 +} + + +#ifdef _WIN32 +#ifndef UNDER_CE + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION + +EXTERN_C_BEGIN +typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); +EXTERN_C_END + +static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi) +{ + const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); + if (!ntdll) + return FALSE; + const + Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS( + Func_RtlGetVersion, ntdll, + "RtlGetVersion"); + if (!func) + return FALSE; + func(vi); + return TRUE; +} + +#endif +#endif + + +void GetOsInfoText(AString &sRes) +{ + sRes.Empty(); + AString s; + + #ifdef _WIN32 + #ifndef UNDER_CE + // OSVERSIONINFO vi; + OSVERSIONINFOEXW vi; + vi.dwOSVersionInfoSize = sizeof(vi); + // if (::GetVersionEx(&vi)) + if (My_RtlGetVersion(&vi)) + { + s += "Windows"; + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) + s.Add_UInt32(vi.dwPlatformId); + s.Add_Space(); s.Add_UInt32(vi.dwMajorVersion); + s.Add_Dot(); s.Add_UInt32(vi.dwMinorVersion); + s.Add_Space(); s.Add_UInt32(vi.dwBuildNumber); + + if (vi.wServicePackMajor != 0 || vi.wServicePackMinor != 0) + { + s += " SP:"; s.Add_UInt32(vi.wServicePackMajor); + s.Add_Dot(); s.Add_UInt32(vi.wServicePackMinor); + } + // s += " Suite:"; PrintHex(s, vi.wSuiteMask); + // s += " Type:"; s.Add_UInt32(vi.wProductType); + // s.Add_Space(); s += GetOemString(vi.szCSDVersion); + } + /* + { + s += " OEMCP:"; s.Add_UInt32(GetOEMCP()); + s += " ACP:"; s.Add_UInt32(GetACP()); + } + */ + #endif + #else // _WIN32 + + if (!s.IsEmpty()) + s.Add_LF(); + struct utsname un; + if (uname(&un) == 0) + { + s += un.sysname; + // s += " : "; s += un.nodename; // we don't want to show name of computer + s += " : "; s += un.release; + s += " : "; s += un.version; + s += " : "; s += un.machine; + + #ifdef __APPLE__ + // Add_sysctlbyname_to_String("kern.version", s); + // it's same as "utsname.version" + #endif + } + #endif // _WIN32 + + sRes += s; + #ifdef MY_CPU_X86_OR_AMD64 + { + AString s2; + GetVirtCpuid(s2); + if (!s2.IsEmpty()) + { + sRes += " : "; + sRes += s2; + } + } + #endif +} + + + +void GetSystemInfoText(AString &sRes) +{ + GetOsInfoText(sRes); + sRes.Add_LF(); + + { + AString s, s1, s2; + GetSysInfo(s1, s2); + if (!s1.IsEmpty() || !s2.IsEmpty()) + { + s = s1; + if (s1 != s2 && !s2.IsEmpty()) + { + s += " - "; + s += s2; + } + } + { + AddCpuFeatures(s); + if (!s.IsEmpty()) + { + sRes += s; + sRes.Add_LF(); + } + } + } + { + AString s, registers; + GetCpuName_MultiLine(s, registers); + if (!s.IsEmpty()) + { + sRes += s; + sRes.Add_LF(); + } + if (!registers.IsEmpty()) + { + sRes += registers; + sRes.Add_LF(); + } + } + /* + #ifdef MY_CPU_X86_OR_AMD64 + { + AString s; + x86cpuid_all_to_String(s); + if (!s.IsEmpty()) + { + printCallback->Print(s); + printCallback->NewLine(); + } + } + #endif + */ +} + + +void GetCpuName_MultiLine(AString &s, AString ®isters); +void GetCpuName_MultiLine(AString &s, AString ®isters) +{ + CCpuName cpuName; + cpuName.Fill(); + s = cpuName.CpuName; + AString s2; + cpuName.Get_Revision_Microcode_LargePages(s2); + if (!s2.IsEmpty()) + { + s.Add_LF(); + s += s2; + } + registers.Empty(); +#ifdef Z7_SYS_INFO_SHOW_ARM64_REGS + cpuName.Get_Registers(registers); +#endif +} + + +#ifdef MY_CPU_X86_OR_AMD64 + +void GetVirtCpuid(AString &s) +{ + const UInt32 kHv = 0x40000000; + + Z7_IF_X86_CPUID_SUPPORTED + { + UInt32 a[4]; + z7_x86_cpuid(a, kHv); + + if (a[0] < kHv || a[0] >= kHv + (1 << 16)) + return; + { + { + for (unsigned j = 1; j < 4; j++) + PrintCpuChars(s, a[j]); + } + } + if (a[0] >= kHv + 1) + { + UInt32 d[4]; + z7_x86_cpuid(d, kHv + 1); + s += " : "; + PrintCpuChars(s, d[0]); + if (a[0] >= kHv + 2) + { + z7_x86_cpuid(d, kHv + 2); + s += " : "; + s.Add_UInt32(d[1] >> 16); + s.Add_Dot(); s.Add_UInt32(d[1] & 0xffff); + s.Add_Dot(); s.Add_UInt32(d[0]); + s.Add_Dot(); s.Add_UInt32(d[2]); + s.Add_Dot(); s.Add_UInt32(d[3] >> 24); + s.Add_Dot(); s.Add_UInt32(d[3] & 0xffffff); + } + /* + if (a[0] >= kHv + 5) + { + z7_x86_cpuid(d, kHv + 5); + s += " : "; + s.Add_UInt32(d[0]); + s += "p"; + s.Add_UInt32(d[1]); + s += "t"; + } + */ + } + } +} + +#endif + + +void GetCompiler(AString &s) +{ + #ifdef __clang__ + s += " CLANG "; + s.Add_UInt32(__clang_major__); + s.Add_Dot(); + s.Add_UInt32(__clang_minor__); + s.Add_Dot(); + s.Add_UInt32(__clang_patchlevel__); + #endif + + #ifdef __xlC__ + s += " XLC "; + s.Add_UInt32(__xlC__ >> 8); + s.Add_Dot(); + s.Add_UInt32(__xlC__ & 0xFF); + #ifdef __xlC_ver__ + s.Add_Dot(); + s.Add_UInt32(__xlC_ver__ >> 8); + s.Add_Dot(); + s.Add_UInt32(__xlC_ver__ & 0xFF); + #endif + #endif + + // #define __LCC__ 126 + // #define __LCC_MINOR__ 20 + // #define __MCST__ 1 + #ifdef __MCST__ + s += " MCST"; + #endif + #ifdef __LCC__ + s += " LCC "; + s.Add_UInt32(__LCC__ / 100); + s.Add_Dot(); + s.Add_UInt32(__LCC__ % 100 / 10); + s.Add_UInt32(__LCC__ % 10); + #ifdef __LCC_MINOR__ + s.Add_Dot(); + s.Add_UInt32(__LCC_MINOR__ / 10); + s.Add_UInt32(__LCC_MINOR__ % 10); + #endif + #endif + + // #define __EDG_VERSION__ 602 + #ifdef __EDG_VERSION__ + s += " EDG "; + s.Add_UInt32(__EDG_VERSION__ / 100); + s.Add_Dot(); + s.Add_UInt32(__EDG_VERSION__ % 100 / 10); + s.Add_UInt32(__EDG_VERSION__ % 10); + #endif + + #ifdef __VERSION__ + s.Add_Space(); + s += "ver:"; + s += __VERSION__; + #endif + + #ifdef __GNUC__ + s += " GCC "; + s.Add_UInt32(__GNUC__); + s.Add_Dot(); + s.Add_UInt32(__GNUC_MINOR__); + s.Add_Dot(); + s.Add_UInt32(__GNUC_PATCHLEVEL__); + #endif + + + #ifdef _MSC_VER + s += " MSC "; + s.Add_UInt32(_MSC_VER); + #ifdef _MSC_FULL_VER + s.Add_Dot(); + s.Add_UInt32(_MSC_FULL_VER); + #endif + + #endif + + #if defined(__AVX512F__) + #if defined(__AVX512VL__) + #define MY_CPU_COMPILE_ISA "AVX512VL" + #else + #define MY_CPU_COMPILE_ISA "AVX512F" + #endif + #elif defined(__AVX2__) + #define MY_CPU_COMPILE_ISA "AVX2" + #elif defined(__AVX__) + #define MY_CPU_COMPILE_ISA "AVX" + #elif defined(__SSE2__) + #define MY_CPU_COMPILE_ISA "SSE2" + #elif defined(_M_IX86_FP) && (_M_IX86_FP >= 2) + #define MY_CPU_COMPILE_ISA "SSE2" + #elif defined(__SSE__) + #define MY_CPU_COMPILE_ISA "SSE" + #elif defined(_M_IX86_FP) && (_M_IX86_FP >= 1) + #define MY_CPU_COMPILE_ISA "SSE" + #elif defined(__i686__) + #define MY_CPU_COMPILE_ISA "i686" + #elif defined(__i586__) + #define MY_CPU_COMPILE_ISA "i586" + #elif defined(__i486__) + #define MY_CPU_COMPILE_ISA "i486" + #elif defined(__i386__) + #define MY_CPU_COMPILE_ISA "i386" + #elif defined(_M_IX86_FP) + #define MY_CPU_COMPILE_ISA "IA32" + #endif + + AString s2; + + #ifdef MY_CPU_COMPILE_ISA + s2.Add_OptSpaced(MY_CPU_COMPILE_ISA); + #endif + +#ifndef MY_CPU_ARM64 + #ifdef __ARM_FP + s2.Add_OptSpaced("FP"); + #endif + #ifdef __ARM_NEON + s2.Add_OptSpaced("NEON"); + #endif + #ifdef __NEON__ + s2.Add_OptSpaced("__NEON__"); + #endif + #ifdef __ARM_FEATURE_SIMD32 + s2.Add_OptSpaced("SIMD32"); + #endif +#endif + + #ifdef __ARM_FEATURE_CRYPTO + s2.Add_OptSpaced("CRYPTO"); + #endif + + #ifdef __ARM_FEATURE_SHA2 + s2.Add_OptSpaced("SHA2"); + #endif + + #ifdef __ARM_FEATURE_AES + s2.Add_OptSpaced("AES"); + #endif + + #ifdef __ARM_FEATURE_CRC32 + s2.Add_OptSpaced("CRC32"); + #endif + + #ifdef __ARM_FEATURE_UNALIGNED + s2.Add_OptSpaced("UNALIGNED"); + #endif + + + #ifdef MY_CPU_BE + s2.Add_OptSpaced("BE"); + #endif + + #if defined(MY_CPU_LE_UNALIGN) \ + && !defined(MY_CPU_X86_OR_AMD64) \ + && !defined(MY_CPU_ARM64) + s2.Add_OptSpaced("LE-unaligned"); + #endif + + if (!s2.IsEmpty()) + { + s.Add_OptSpaced(": "); + s += s2; + } +} diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h index 143bf9aaf..4601685e7 100644 --- a/CPP/Windows/SystemInfo.h +++ b/CPP/Windows/SystemInfo.h @@ -1,19 +1,19 @@ -// Windows/SystemInfo.h - -#ifndef ZIP7_INC_WINDOWS_SYSTEM_INFO_H -#define ZIP7_INC_WINDOWS_SYSTEM_INFO_H - -#include "../Common/MyString.h" - - -void GetCpuName_MultiLine(AString &s); - -void GetOsInfoText(AString &sRes); -void GetSystemInfoText(AString &s); -void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v); -void Add_LargePages_String(AString &s); - -void GetCompiler(AString &s); -void GetVirtCpuid(AString &s); - -#endif +// Windows/SystemInfo.h + +#ifndef ZIP7_INC_WINDOWS_SYSTEM_INFO_H +#define ZIP7_INC_WINDOWS_SYSTEM_INFO_H + +#include "../Common/MyString.h" + + +void GetCpuName_MultiLine(AString &s, AString ®isters); + +void GetOsInfoText(AString &sRes); +void GetSystemInfoText(AString &s); +void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v); +void Add_LargePages_String(AString &s); + +void GetCompiler(AString &s); +void GetVirtCpuid(AString &s); + +#endif diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h index 013e5fd13..d72f64c47 100644 --- a/CPP/Windows/Thread.h +++ b/CPP/Windows/Thread.h @@ -1,44 +1,44 @@ -// Windows/Thread.h - -#ifndef ZIP7_INC_WINDOWS_THREAD_H -#define ZIP7_INC_WINDOWS_THREAD_H - -#include "../../C/Threads.h" - -#include "Defs.h" - -namespace NWindows { - -class CThread MY_UNCOPYABLE -{ - ::CThread thread; -public: - CThread() { Thread_CONSTRUCT(&thread) } - ~CThread() { Close(); } - bool IsCreated() { return Thread_WasCreated(&thread) != 0; } - WRes Close() { return Thread_Close(&thread); } - // WRes Wait() { return Thread_Wait(&thread); } - WRes Wait_Close() { return Thread_Wait_Close(&thread); } - - WRes Create(THREAD_FUNC_TYPE startAddress, LPVOID param) - { return Thread_Create(&thread, startAddress, param); } - WRes Create_With_Affinity(THREAD_FUNC_TYPE startAddress, LPVOID param, CAffinityMask affinity) - { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } - WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) - { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } - - #ifdef _WIN32 - operator HANDLE() { return thread; } - void Attach(HANDLE handle) { thread = handle; } - HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } - DWORD Resume() { return ::ResumeThread(thread); } - DWORD Suspend() { return ::SuspendThread(thread); } - bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } - int GetPriority() { return ::GetThreadPriority(thread); } - bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } - #endif -}; - -} - -#endif +// Windows/Thread.h + +#ifndef ZIP7_INC_WINDOWS_THREAD_H +#define ZIP7_INC_WINDOWS_THREAD_H + +#include "../../C/Threads.h" + +#include "Defs.h" + +namespace NWindows { + +class CThread MY_UNCOPYABLE +{ + ::CThread thread; +public: + CThread() { Thread_CONSTRUCT(&thread) } + ~CThread() { Close(); } + bool IsCreated() { return Thread_WasCreated(&thread) != 0; } + WRes Close() { return Thread_Close(&thread); } + // WRes Wait() { return Thread_Wait(&thread); } + WRes Wait_Close() { return Thread_Wait_Close(&thread); } + + WRes Create(THREAD_FUNC_TYPE startAddress, LPVOID param) + { return Thread_Create(&thread, startAddress, param); } + WRes Create_With_Affinity(THREAD_FUNC_TYPE startAddress, LPVOID param, CAffinityMask affinity) + { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } + WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) + { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } + + #ifdef _WIN32 + operator HANDLE() { return thread; } + void Attach(HANDLE handle) { thread = handle; } + HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } + DWORD Resume() { return ::ResumeThread(thread); } + DWORD Suspend() { return ::SuspendThread(thread); } + bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } + int GetPriority() { return ::GetThreadPriority(thread); } + bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } + #endif +}; + +} + +#endif diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp index 04b230f81..bbd79baf3 100644 --- a/CPP/Windows/TimeUtils.cpp +++ b/CPP/Windows/TimeUtils.cpp @@ -1,466 +1,466 @@ -// Windows/TimeUtils.cpp - -#include "StdAfx.h" - -#ifndef _WIN32 -#include -#include -#endif - -#include "Defs.h" -#include "TimeUtils.h" - -namespace NWindows { -namespace NTime { - -static const UInt32 kNumTimeQuantumsInSecond = 10000000; -static const unsigned kFileTimeStartYear = 1601; -#if !defined(_WIN32) || defined(UNDER_CE) -static const unsigned kDosTimeStartYear = 1980; -#endif -static const unsigned kUnixTimeStartYear = 1970; -static const UInt64 kUnixTimeOffset = - (UInt64)60 * 60 * 24 * (89 + 365 * (UInt32)(kUnixTimeStartYear - kFileTimeStartYear)); -static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; - -bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw() -{ - #if defined(_WIN32) && !defined(UNDER_CE) - return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); - #else - ft.dwLowDateTime = 0; - ft.dwHighDateTime = 0; - UInt64 res; - if (!GetSecondsSince1601( - kDosTimeStartYear + (unsigned)(dosTime >> 25), - (unsigned)((dosTime >> 21) & 0xF), - (unsigned)((dosTime >> 16) & 0x1F), - (unsigned)((dosTime >> 11) & 0x1F), - (unsigned)((dosTime >> 5) & 0x3F), - (unsigned)((dosTime & 0x1F)) * 2, - res)) - return false; - res *= kNumTimeQuantumsInSecond; - ft.dwLowDateTime = (UInt32)res; - ft.dwHighDateTime = (UInt32)(res >> 32); - return true; - #endif -} - -static const UInt32 kHighDosTime = 0xFF9FBF7D; -static const UInt32 kLowDosTime = 0x210000; - -bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw() -{ - #if defined(_WIN32) && !defined(UNDER_CE) - - WORD datePart, timePart; - if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart)) - { - dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime; - return false; - } - dosTime = (((UInt32)datePart) << 16) + timePart; - - #else - -#define PERIOD_4 (4 * 365 + 1) -#define PERIOD_100 (PERIOD_4 * 25 - 1) -#define PERIOD_400 (PERIOD_100 * 4 + 1) - - unsigned year, mon, day, hour, min, sec; - UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); - Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - unsigned temp; - UInt32 v; - v64 += (kNumTimeQuantumsInSecond * 2 - 1); - v64 /= kNumTimeQuantumsInSecond; - sec = (unsigned)(v64 % 60); - v64 /= 60; - min = (unsigned)(v64 % 60); - v64 /= 60; - hour = (unsigned)(v64 % 24); - v64 /= 24; - - v = (UInt32)v64; - - year = kFileTimeStartYear + (unsigned)(v / PERIOD_400 * 400); - v %= PERIOD_400; - - temp = (unsigned)(v / PERIOD_100); - if (temp == 4) - temp = 3; - year += temp * 100; - v -= temp * PERIOD_100; - - temp = v / PERIOD_4; - if (temp == 25) - temp = 24; - year += temp * 4; - v -= temp * PERIOD_4; - - temp = v / 365; - if (temp == 4) - temp = 3; - year += temp; - v -= temp * 365; - - if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) - ms[1] = 29; - for (mon = 1; mon <= 12; mon++) - { - unsigned s = ms[mon - 1]; - if (v < s) - break; - v -= s; - } - day = (unsigned)v + 1; - - dosTime = kLowDosTime; - if (year < kDosTimeStartYear) - return false; - year -= kDosTimeStartYear; - dosTime = kHighDosTime; - if (year >= 128) - return false; - dosTime = - ((UInt32)year << 25) - | ((UInt32)mon << 21) - | ((UInt32)day << 16) - | ((UInt32)hour << 11) - | ((UInt32)min << 5) - | ((UInt32)sec >> 1); - #endif - return true; -} - - -bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw() -{ - FILETIME loc = { 0, 0 }; - const UInt64 u1 = FILETIME_To_UInt64(utc); - const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec. - if (u1 >= kDelta) - { - if (!FileTimeToLocalFileTime(&utc, &loc)) - loc = utc; - else - { - const UInt64 u2 = FILETIME_To_UInt64(loc); - const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2); - if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time - loc = utc; - } - } - return FileTime_To_DosTime(loc, dosTime); -} - -UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw() -{ - return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; -} - -void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw() -{ - const UInt64 v = UnixTime_To_FileTime64(unixTime); - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - -UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw() -{ - return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; -} - - -bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw() -{ - if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset)) - { - fileTime = (UInt64)(Int64)-1; - return false; - } - if (unixTime < -(Int64)kUnixTimeOffset) - { - fileTime = 0; - return false; - } - fileTime = UnixTime64_To_FileTime64(unixTime); - return true; -} - - -bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw() -{ - UInt64 v; - const bool res = UnixTime64_To_FileTime64(unixTime, v); - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); - return res; -} - - -Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw() -{ - const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; -} - -Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw() -{ - const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond); - return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; -} - -bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw() -{ - UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - winTime /= kNumTimeQuantumsInSecond; - if (winTime < kUnixTimeOffset) - { - unixTime = 0; - return false; - } - winTime -= kUnixTimeOffset; - if (winTime > (UInt32)0xFFFFFFFF) - { - unixTime = (UInt32)0xFFFFFFFF; - return false; - } - unixTime = (UInt32)winTime; - return true; -} - -bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, - unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw() -{ - resSeconds = 0; - if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 || - day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) - return false; - const unsigned numYears = year - kFileTimeStartYear; - UInt32 numDays = (UInt32)((UInt32)numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400); - Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) - ms[1] = 29; - month--; - for (unsigned i = 0; i < month; i++) - numDays += ms[i]; - numDays += (UInt32)(day - 1); - resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec; - return true; -} - - -/* docs: TIME_UTC is not defined on many platforms: - glibc 2.15, macOS 10.13 - FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, - Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, - Cygwin 2.9, mingw, MSVC 14, Android 9.0. -*/ -#if defined(TIME_UTC) -#define ZIP7_USE_timespec_get -// #pragma message("ZIP7_USE_timespec_get") -#elif defined(CLOCK_REALTIME) -#define ZIP7_USE_clock_gettime -// #pragma message("ZIP7_USE_clock_gettime") -#endif - -void GetCurUtc_FiTime(CFiTime &ft) throw() -{ - #ifdef _WIN32 - - // Both variants provide same low resolution on WinXP: about 15 ms. - // But GetSystemTimeAsFileTime is much faster. - #ifdef UNDER_CE - SYSTEMTIME st; - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - #else - GetSystemTimeAsFileTime(&ft); - #endif - - #else - - FiTime_Clear(ft); -#ifdef ZIP7_USE_timespec_get - timespec_get(&ft, TIME_UTC); -#elif defined ZIP7_USE_clock_gettime - -#if defined(_AIX) - { - timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ft.tv_sec = ts.tv_sec; - ft.tv_nsec = ts.tv_nsec; - } -#else - clock_gettime(CLOCK_REALTIME, &ft); -#endif - -#else - struct timeval now; - if (gettimeofday(&now, NULL) == 0) - { - ft.tv_sec = now.tv_sec; - // timeval::tv_usec can be 64-bit signed in some cases - // timespec::tv_nsec can be 32-bit signed in some cases - ft.tv_nsec = - (Int32) // to eliminate compiler conversion error - (now.tv_usec * 1000); - } -#endif - - #endif -} - -#ifndef _WIN32 -void GetCurUtcFileTime(FILETIME &ft) throw() -{ - UInt64 v = 0; -#if defined(ZIP7_USE_timespec_get) || \ - defined(ZIP7_USE_clock_gettime) - timespec ts; -#if defined(ZIP7_USE_timespec_get) - if (timespec_get(&ts, TIME_UTC)) -#else - if (clock_gettime(CLOCK_REALTIME, &ts) == 0) -#endif - { - v = ((UInt64)ts.tv_sec + kUnixTimeOffset) * - kNumTimeQuantumsInSecond + (UInt64)ts.tv_nsec / 100; - } -#else - struct timeval now; - if (gettimeofday(&now, NULL) == 0) - { - v = ((UInt64)now.tv_sec + kUnixTimeOffset) * - kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10; - } -#endif - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} -#endif - - -}} - - -#ifdef _WIN32 - -/* -void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) -{ - if (prec == k_PropVar_TimePrec_0 - || prec == k_PropVar_TimePrec_HighPrec - || prec >= k_PropVar_TimePrec_100ns) - return; - UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; - - int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; - UInt32 d; - if (prec == k_PropVar_TimePrec_DOS) - { - // we round up as windows DosDateTimeToFileTime() - v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1; - d = NWindows::NTime::kNumTimeQuantumsInSecond * 2; - } - else - { - if (prec == k_PropVar_TimePrec_Unix) - numDigits = 0; - else if (numDigits < 0) - return; - d = 1; - for (unsigned k = numDigits; k < 7; k++) - d *= 10; - } - v /= d; - v *= d; - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} -*/ - -#else - -/* -void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) -{ - if (prec >= k_PropVar_TimePrec_1ns - || prec == k_PropVar_TimePrec_HighPrec) - return; - - int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; - UInt32 d; - if (prec == k_PropVar_TimePrec_Unix || - prec == (int)k_PropVar_TimePrec_Base) - { - ft.tv_nsec = 0; - return; - } - if (prec == k_PropVar_TimePrec_DOS) - { - // we round up as windows DosDateTimeToFileTime() - const unsigned sec1 = (ft.tv_sec & 1); - if (ft.tv_nsec == 0 && sec1 == 0) - return; - ft.tv_nsec = 0; - ft.tv_sec += 2 - sec1; - return; - } - { - if (prec == k_PropVar_TimePrec_0 - || numDigits < 0) - numDigits = 7; - d = 1; - for (unsigned k = numDigits; k < 9; k++) - d *= 10; - ft.tv_nsec /= d; - ft.tv_nsec *= d; - } -} -*/ - -int Compare_FiTime(const CFiTime *a1, const CFiTime *a2) -{ - if (a1->tv_sec < a2->tv_sec) return -1; - if (a1->tv_sec > a2->tv_sec) return 1; - if (a1->tv_nsec < a2->tv_nsec) return -1; - if (a1->tv_nsec > a2->tv_nsec) return 1; - return 0; -} - -bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts) -{ - UInt32 quantums; - const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums); - // time_t is long - const time_t sec2 = (time_t)sec; - if (sec2 == sec) - { - ts.tv_sec = sec2; - ts.tv_nsec = (Int32)(quantums * 100); - return true; - } - return false; -} - -void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100) -{ - const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); - ns100 = (unsigned)((UInt64)ts.tv_nsec % 100); - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - -void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) -{ - const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - -#endif +// Windows/TimeUtils.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 +#include +#include +#endif + +#include "Defs.h" +#include "TimeUtils.h" + +namespace NWindows { +namespace NTime { + +static const UInt32 kNumTimeQuantumsInSecond = 10000000; +static const unsigned kFileTimeStartYear = 1601; +#if !defined(_WIN32) || defined(UNDER_CE) +static const unsigned kDosTimeStartYear = 1980; +#endif +static const unsigned kUnixTimeStartYear = 1970; +static const UInt64 kUnixTimeOffset = + (UInt64)60 * 60 * 24 * (89 + 365 * (UInt32)(kUnixTimeStartYear - kFileTimeStartYear)); +static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; + +bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw() +{ + #if defined(_WIN32) && !defined(UNDER_CE) + return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); + #else + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; + UInt64 res; + if (!GetSecondsSince1601( + kDosTimeStartYear + (unsigned)(dosTime >> 25), + (unsigned)((dosTime >> 21) & 0xF), + (unsigned)((dosTime >> 16) & 0x1F), + (unsigned)((dosTime >> 11) & 0x1F), + (unsigned)((dosTime >> 5) & 0x3F), + (unsigned)((dosTime & 0x1F)) * 2, + res)) + return false; + res *= kNumTimeQuantumsInSecond; + ft.dwLowDateTime = (UInt32)res; + ft.dwHighDateTime = (UInt32)(res >> 32); + return true; + #endif +} + +static const UInt32 kHighDosTime = 0xFF9FBF7D; +static const UInt32 kLowDosTime = 0x210000; + +bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw() +{ + #if defined(_WIN32) && !defined(UNDER_CE) + + WORD datePart, timePart; + if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart)) + { + dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime; + return false; + } + dosTime = (((UInt32)datePart) << 16) + timePart; + + #else + +#define PERIOD_4 (4 * 365 + 1) +#define PERIOD_100 (PERIOD_4 * 25 - 1) +#define PERIOD_400 (PERIOD_100 * 4 + 1) + + unsigned year, mon, day, hour, min, sec; + UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); + Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + unsigned temp; + UInt32 v; + v64 += (kNumTimeQuantumsInSecond * 2 - 1); + v64 /= kNumTimeQuantumsInSecond; + sec = (unsigned)(v64 % 60); + v64 /= 60; + min = (unsigned)(v64 % 60); + v64 /= 60; + hour = (unsigned)(v64 % 24); + v64 /= 24; + + v = (UInt32)v64; + + year = kFileTimeStartYear + (unsigned)(v / PERIOD_400 * 400); + v %= PERIOD_400; + + temp = (unsigned)(v / PERIOD_100); + if (temp == 4) + temp = 3; + year += temp * 100; + v -= temp * PERIOD_100; + + temp = v / PERIOD_4; + if (temp == 25) + temp = 24; + year += temp * 4; + v -= temp * PERIOD_4; + + temp = v / 365; + if (temp == 4) + temp = 3; + year += temp; + v -= temp * 365; + + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + ms[1] = 29; + for (mon = 1; mon <= 12; mon++) + { + unsigned s = ms[mon - 1]; + if (v < s) + break; + v -= s; + } + day = (unsigned)v + 1; + + dosTime = kLowDosTime; + if (year < kDosTimeStartYear) + return false; + year -= kDosTimeStartYear; + dosTime = kHighDosTime; + if (year >= 128) + return false; + dosTime = + ((UInt32)year << 25) + | ((UInt32)mon << 21) + | ((UInt32)day << 16) + | ((UInt32)hour << 11) + | ((UInt32)min << 5) + | ((UInt32)sec >> 1); + #endif + return true; +} + + +bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw() +{ + FILETIME loc = { 0, 0 }; + const UInt64 u1 = FILETIME_To_UInt64(utc); + const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec. + if (u1 >= kDelta) + { + if (!FileTimeToLocalFileTime(&utc, &loc)) + loc = utc; + else + { + const UInt64 u2 = FILETIME_To_UInt64(loc); + const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2); + if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time + loc = utc; + } + } + return FileTime_To_DosTime(loc, dosTime); +} + +UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw() +{ + return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; +} + +void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw() +{ + const UInt64 v = UnixTime_To_FileTime64(unixTime); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw() +{ + return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; +} + + +bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw() +{ + if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset)) + { + fileTime = (UInt64)(Int64)-1; + return false; + } + if (unixTime < -(Int64)kUnixTimeOffset) + { + fileTime = 0; + return false; + } + fileTime = UnixTime64_To_FileTime64(unixTime); + return true; +} + + +bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw() +{ + UInt64 v; + const bool res = UnixTime64_To_FileTime64(unixTime, v); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + return res; +} + + +Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw() +{ + const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; +} + +Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw() +{ + const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond); + return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; +} + +bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw() +{ + UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + winTime /= kNumTimeQuantumsInSecond; + if (winTime < kUnixTimeOffset) + { + unixTime = 0; + return false; + } + winTime -= kUnixTimeOffset; + if (winTime > (UInt32)0xFFFFFFFF) + { + unixTime = (UInt32)0xFFFFFFFF; + return false; + } + unixTime = (UInt32)winTime; + return true; +} + +bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, + unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw() +{ + resSeconds = 0; + if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 || + day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) + return false; + const unsigned numYears = year - kFileTimeStartYear; + UInt32 numDays = (UInt32)((UInt32)numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400); + Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + ms[1] = 29; + month--; + for (unsigned i = 0; i < month; i++) + numDays += ms[i]; + numDays += (UInt32)(day - 1); + resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec; + return true; +} + + +/* docs: TIME_UTC is not defined on many platforms: + glibc 2.15, macOS 10.13 + FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, + Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, + Cygwin 2.9, mingw, MSVC 14, Android 9.0. +*/ +#if defined(TIME_UTC) +#define ZIP7_USE_timespec_get +// #pragma message("ZIP7_USE_timespec_get") +#elif defined(CLOCK_REALTIME) +#define ZIP7_USE_clock_gettime +// #pragma message("ZIP7_USE_clock_gettime") +#endif + +void GetCurUtc_FiTime(CFiTime &ft) throw() +{ + #ifdef _WIN32 + + // Both variants provide same low resolution on WinXP: about 15 ms. + // But GetSystemTimeAsFileTime is much faster. + #ifdef UNDER_CE + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + #else + GetSystemTimeAsFileTime(&ft); + #endif + + #else + + FiTime_Clear(ft); +#ifdef ZIP7_USE_timespec_get + timespec_get(&ft, TIME_UTC); +#elif defined ZIP7_USE_clock_gettime + +#if defined(_AIX) + { + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ft.tv_sec = ts.tv_sec; + ft.tv_nsec = ts.tv_nsec; + } +#else + clock_gettime(CLOCK_REALTIME, &ft); +#endif + +#else + struct timeval now; + if (gettimeofday(&now, NULL) == 0) + { + ft.tv_sec = now.tv_sec; + // timeval::tv_usec can be 64-bit signed in some cases + // timespec::tv_nsec can be 32-bit signed in some cases + ft.tv_nsec = + (Int32) // to eliminate compiler conversion error + (now.tv_usec * 1000); + } +#endif + + #endif +} + +#ifndef _WIN32 +void GetCurUtcFileTime(FILETIME &ft) throw() +{ + UInt64 v = 0; +#if defined(ZIP7_USE_timespec_get) || \ + defined(ZIP7_USE_clock_gettime) + timespec ts; +#if defined(ZIP7_USE_timespec_get) + if (timespec_get(&ts, TIME_UTC)) +#else + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) +#endif + { + v = ((UInt64)ts.tv_sec + kUnixTimeOffset) * + kNumTimeQuantumsInSecond + (UInt64)ts.tv_nsec / 100; + } +#else + struct timeval now; + if (gettimeofday(&now, NULL) == 0) + { + v = ((UInt64)now.tv_sec + kUnixTimeOffset) * + kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10; + } +#endif + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} +#endif + + +}} + + +#ifdef _WIN32 + +/* +void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) +{ + if (prec == k_PropVar_TimePrec_0 + || prec == k_PropVar_TimePrec_HighPrec + || prec >= k_PropVar_TimePrec_100ns) + return; + UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + + int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; + UInt32 d; + if (prec == k_PropVar_TimePrec_DOS) + { + // we round up as windows DosDateTimeToFileTime() + v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1; + d = NWindows::NTime::kNumTimeQuantumsInSecond * 2; + } + else + { + if (prec == k_PropVar_TimePrec_Unix) + numDigits = 0; + else if (numDigits < 0) + return; + d = 1; + for (unsigned k = numDigits; k < 7; k++) + d *= 10; + } + v /= d; + v *= d; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} +*/ + +#else + +/* +void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) +{ + if (prec >= k_PropVar_TimePrec_1ns + || prec == k_PropVar_TimePrec_HighPrec) + return; + + int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; + UInt32 d; + if (prec == k_PropVar_TimePrec_Unix || + prec == (int)k_PropVar_TimePrec_Base) + { + ft.tv_nsec = 0; + return; + } + if (prec == k_PropVar_TimePrec_DOS) + { + // we round up as windows DosDateTimeToFileTime() + const unsigned sec1 = (ft.tv_sec & 1); + if (ft.tv_nsec == 0 && sec1 == 0) + return; + ft.tv_nsec = 0; + ft.tv_sec += 2 - sec1; + return; + } + { + if (prec == k_PropVar_TimePrec_0 + || numDigits < 0) + numDigits = 7; + d = 1; + for (unsigned k = numDigits; k < 9; k++) + d *= 10; + ft.tv_nsec /= d; + ft.tv_nsec *= d; + } +} +*/ + +int Compare_FiTime(const CFiTime *a1, const CFiTime *a2) +{ + if (a1->tv_sec < a2->tv_sec) return -1; + if (a1->tv_sec > a2->tv_sec) return 1; + if (a1->tv_nsec < a2->tv_nsec) return -1; + if (a1->tv_nsec > a2->tv_nsec) return 1; + return 0; +} + +bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts) +{ + UInt32 quantums; + const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums); + // time_t is long + const time_t sec2 = (time_t)sec; + if (sec2 == sec) + { + ts.tv_sec = sec2; + ts.tv_nsec = (Int32)(quantums * 100); + return true; + } + return false; +} + +void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100) +{ + const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); + ns100 = (unsigned)((UInt64)ts.tv_nsec % 100); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) +{ + const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +#endif diff --git a/CPP/Windows/TimeUtils.h b/CPP/Windows/TimeUtils.h index a4ce8465d..4a9d0f2fa 100644 --- a/CPP/Windows/TimeUtils.h +++ b/CPP/Windows/TimeUtils.h @@ -1,146 +1,146 @@ -// Windows/TimeUtils.h - -#ifndef ZIP7_INC_WINDOWS_TIME_UTILS_H -#define ZIP7_INC_WINDOWS_TIME_UTILS_H - -#include "../Common/MyTypes.h" -#include "../Common/MyWindows.h" -#include "PropVariant.h" - -inline UInt64 FILETIME_To_UInt64(const FILETIME &ft) -{ - return (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; -} - -inline void FILETIME_Clear(FILETIME &ft) -{ - ft.dwLowDateTime = 0; - ft.dwHighDateTime = 0; -} - -inline bool FILETIME_IsZero(const FILETIME &ft) -{ - return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); -} - - -#ifdef _WIN32 - #define CFiTime FILETIME - #define Compare_FiTime ::CompareFileTime - inline void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) - { - ft = ts; - } - /* - inline void FILETIME_To_FiTime(const FILETIME &ft, CFiTime &ts) - { - ts = ft; - } - */ - inline void FiTime_Clear(CFiTime &ft) - { - ft.dwLowDateTime = 0; - ft.dwHighDateTime = 0; - } -#else - - #include - - #if defined(_AIX) - #define CFiTime st_timespec - #else - #define CFiTime timespec - #endif - int Compare_FiTime(const CFiTime *a1, const CFiTime *a2); - bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts); - void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft); - void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100); - inline void FiTime_Clear(CFiTime &ft) - { - ft.tv_sec = 0; - ft.tv_nsec = 0; - } - - #ifdef __APPLE__ - #define ST_MTIME(st) st.st_mtimespec - #define ST_ATIME(st) st.st_atimespec - #define ST_CTIME(st) st.st_ctimespec - #else - #define ST_MTIME(st) st.st_mtim - #define ST_ATIME(st) st.st_atim - #define ST_CTIME(st) st.st_ctim - #endif - -#endif - -// void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec); - -namespace NWindows { -namespace NTime { - -bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &fileTime) throw(); -bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw(); -bool FileTime_To_DosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); - -// UInt32 Unix Time : for dates 1970-2106 -UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw(); -void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &fileTime) throw(); - -// Int64 Unix Time : negative values for dates before 1970 -UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw(); // no check -bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw(); -bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &fileTime) throw(); - -Int64 FileTime64_To_UnixTime64(UInt64 ft64) throw(); -bool FileTime_To_UnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); -Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw(); -Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw(); - -bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, - unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); - -void GetCurUtc_FiTime(CFiTime &ft) throw(); -#ifdef _WIN32 -#define GetCurUtcFileTime GetCurUtc_FiTime -#else -void GetCurUtcFileTime(FILETIME &ft) throw(); -#endif - -}} - -inline void PropVariant_SetFrom_UnixTime(NWindows::NCOM::CPropVariant &prop, UInt32 unixTime) -{ - FILETIME ft; - NWindows::NTime::UnixTime_To_FileTime(unixTime, ft); - prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix); -} - -inline void PropVariant_SetFrom_NtfsTime(NWindows::NCOM::CPropVariant &prop, const FILETIME &ft) -{ - prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_100ns); -} - -inline void PropVariant_SetFrom_FiTime(NWindows::NCOM::CPropVariant &prop, const CFiTime &fts) -{ - #ifdef _WIN32 - PropVariant_SetFrom_NtfsTime(prop, fts); - #else - unsigned ns100; - FILETIME ft; - FiTime_To_FILETIME_ns100(fts, ft, ns100); - prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); - #endif -} - -inline bool PropVariant_SetFrom_DosTime(NWindows::NCOM::CPropVariant &prop, UInt32 dosTime) -{ - FILETIME localFileTime, utc; - if (!NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime)) - return false; - if (!LocalFileTimeToFileTime(&localFileTime, &utc)) - return false; - prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_DOS); - return true; -} - -#endif +// Windows/TimeUtils.h + +#ifndef ZIP7_INC_WINDOWS_TIME_UTILS_H +#define ZIP7_INC_WINDOWS_TIME_UTILS_H + +#include "../Common/MyTypes.h" +#include "../Common/MyWindows.h" +#include "PropVariant.h" + +inline UInt64 FILETIME_To_UInt64(const FILETIME &ft) +{ + return (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; +} + +inline void FILETIME_Clear(FILETIME &ft) +{ + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; +} + +inline bool FILETIME_IsZero(const FILETIME &ft) +{ + return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); +} + + +#ifdef _WIN32 + #define CFiTime FILETIME + #define Compare_FiTime ::CompareFileTime + inline void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) + { + ft = ts; + } + /* + inline void FILETIME_To_FiTime(const FILETIME &ft, CFiTime &ts) + { + ts = ft; + } + */ + inline void FiTime_Clear(CFiTime &ft) + { + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; + } +#else + + #include + + #if defined(_AIX) + #define CFiTime st_timespec + #else + #define CFiTime timespec + #endif + int Compare_FiTime(const CFiTime *a1, const CFiTime *a2); + bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts); + void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft); + void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100); + inline void FiTime_Clear(CFiTime &ft) + { + ft.tv_sec = 0; + ft.tv_nsec = 0; + } + + #ifdef __APPLE__ + #define ST_MTIME(st) st.st_mtimespec + #define ST_ATIME(st) st.st_atimespec + #define ST_CTIME(st) st.st_ctimespec + #else + #define ST_MTIME(st) st.st_mtim + #define ST_ATIME(st) st.st_atim + #define ST_CTIME(st) st.st_ctim + #endif + +#endif + +// void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec); + +namespace NWindows { +namespace NTime { + +bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &fileTime) throw(); +bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw(); +bool FileTime_To_DosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); + +// UInt32 Unix Time : for dates 1970-2106 +UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw(); +void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &fileTime) throw(); + +// Int64 Unix Time : negative values for dates before 1970 +UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw(); // no check +bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw(); +bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &fileTime) throw(); + +Int64 FileTime64_To_UnixTime64(UInt64 ft64) throw(); +bool FileTime_To_UnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); +Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw(); +Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw(); + +bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, + unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); + +void GetCurUtc_FiTime(CFiTime &ft) throw(); +#ifdef _WIN32 +#define GetCurUtcFileTime GetCurUtc_FiTime +#else +void GetCurUtcFileTime(FILETIME &ft) throw(); +#endif + +}} + +inline void PropVariant_SetFrom_UnixTime(NWindows::NCOM::CPropVariant &prop, UInt32 unixTime) +{ + FILETIME ft; + NWindows::NTime::UnixTime_To_FileTime(unixTime, ft); + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix); +} + +inline void PropVariant_SetFrom_NtfsTime(NWindows::NCOM::CPropVariant &prop, const FILETIME &ft) +{ + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_100ns); +} + +inline void PropVariant_SetFrom_FiTime(NWindows::NCOM::CPropVariant &prop, const CFiTime &fts) +{ + #ifdef _WIN32 + PropVariant_SetFrom_NtfsTime(prop, fts); + #else + unsigned ns100; + FILETIME ft; + FiTime_To_FILETIME_ns100(fts, ft, ns100); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); + #endif +} + +inline bool PropVariant_SetFrom_DosTime(NWindows::NCOM::CPropVariant &prop, UInt32 dosTime) +{ + FILETIME localFileTime, utc; + if (!NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime)) + return false; + if (!LocalFileTimeToFileTime(&localFileTime, &utc)) + return false; + prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_DOS); + return true; +} + +#endif diff --git a/CPP/Windows/Window.cpp b/CPP/Windows/Window.cpp index ab763d58e..102c503a5 100644 --- a/CPP/Windows/Window.cpp +++ b/CPP/Windows/Window.cpp @@ -1,179 +1,179 @@ -// Windows/Window.cpp - -#include "StdAfx.h" - -#ifndef _UNICODE -#include "../Common/StringConvert.h" -#endif -#include "Window.h" - -#ifndef _UNICODE -extern bool g_IsNT; -#endif - -namespace NWindows { - -#ifndef _UNICODE -ATOM MyRegisterClass(CONST WNDCLASSW *wndClass) -{ - if (g_IsNT) - return RegisterClassW(wndClass); - WNDCLASSA wndClassA; - wndClassA.style = wndClass->style; - wndClassA.lpfnWndProc = wndClass->lpfnWndProc; - wndClassA.cbClsExtra = wndClass->cbClsExtra; - wndClassA.cbWndExtra = wndClass->cbWndExtra; - wndClassA.hInstance = wndClass->hInstance; - wndClassA.hIcon = wndClass->hIcon; - wndClassA.hCursor = wndClass->hCursor; - wndClassA.hbrBackground = wndClass->hbrBackground; - AString menuName; - AString className; - if (IS_INTRESOURCE(wndClass->lpszMenuName)) - wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName; - else - { - menuName = GetSystemString(wndClass->lpszMenuName); - wndClassA.lpszMenuName = menuName; - } - if (IS_INTRESOURCE(wndClass->lpszClassName)) - wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName; - else - { - className = GetSystemString(wndClass->lpszClassName); - wndClassA.lpszClassName = className; - } - return RegisterClassA(&wndClassA); -} - -bool CWindow::Create(LPCWSTR className, - LPCWSTR windowName, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam) -{ - if (g_IsNT) - { - _window = ::CreateWindowW(className, windowName, - style, x, y, width, height, parentWindow, - idOrHMenu, instance, createParam); - return (_window != NULL); - } - return Create(GetSystemString(className), GetSystemString(windowName), - style, x, y, width, height, parentWindow, - idOrHMenu, instance, createParam); -} - -bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className, - LPCWSTR windowName, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam) -{ - if (g_IsNT) - { - _window = ::CreateWindowExW(exStyle, className, windowName, - style, x, y, width, height, parentWindow, - idOrHMenu, instance, createParam); - return (_window != NULL); - } - AString classNameA; - LPCSTR classNameP; - if (IS_INTRESOURCE(className)) - classNameP = (LPCSTR)className; - else - { - classNameA = GetSystemString(className); - classNameP = classNameA; - } - AString windowNameA; - LPCSTR windowNameP; - if (IS_INTRESOURCE(windowName)) - windowNameP = (LPCSTR)windowName; - else - { - windowNameA = GetSystemString(windowName); - windowNameP = windowNameA; - } - return CreateEx(exStyle, classNameP, windowNameP, - style, x, y, width, height, parentWindow, - idOrHMenu, instance, createParam); -} - -#endif - -#ifndef _UNICODE -bool MySetWindowText(HWND wnd, LPCWSTR s) -{ - if (g_IsNT) - return BOOLToBool(::SetWindowTextW(wnd, s)); - return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s))); -} -#endif - -bool CWindow::GetText(CSysString &s) const -{ - s.Empty(); - unsigned len = (unsigned)GetTextLength(); - if (len == 0) - return (::GetLastError() == ERROR_SUCCESS); - TCHAR *p = s.GetBuf(len); - { - const unsigned len2 = (unsigned)GetText(p, (int)(len + 1)); - if (len > len2) - len = len2; - } - s.ReleaseBuf_CalcLen(len); - if (len == 0) - return (::GetLastError() == ERROR_SUCCESS); - return true; -} - -#ifndef _UNICODE -bool CWindow::GetText(UString &s) const -{ - if (g_IsNT) - { - s.Empty(); - unsigned len = (unsigned)GetWindowTextLengthW(_window); - if (len == 0) - return (::GetLastError() == ERROR_SUCCESS); - wchar_t *p = s.GetBuf(len); - { - const unsigned len2 = (unsigned)GetWindowTextW(_window, p, (int)(len + 1)); - if (len > len2) - len = len2; - } - s.ReleaseBuf_CalcLen(len); - if (len == 0) - return (::GetLastError() == ERROR_SUCCESS); - return true; - } - CSysString sysString; - const bool result = GetText(sysString); - MultiByteToUnicodeString2(s, sysString); - return result; -} -#endif - - -/* -bool CWindow::ModifyStyleBase(int styleOffset, - DWORD remove, DWORD add, UINT flags) -{ - DWORD style = GetWindowLong(styleOffset); - DWORD newStyle = (style & ~remove) | add; - if (style == newStyle) - return false; // it is not good - - SetWindowLong(styleOffset, newStyle); - if (flags != 0) - { - ::SetWindowPos(_window, NULL, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags); - } - return TRUE; -} -*/ - -} +// Windows/Window.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif +#include "Window.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +#ifndef _UNICODE +ATOM MyRegisterClass(CONST WNDCLASSW *wndClass) +{ + if (g_IsNT) + return RegisterClassW(wndClass); + WNDCLASSA wndClassA; + wndClassA.style = wndClass->style; + wndClassA.lpfnWndProc = wndClass->lpfnWndProc; + wndClassA.cbClsExtra = wndClass->cbClsExtra; + wndClassA.cbWndExtra = wndClass->cbWndExtra; + wndClassA.hInstance = wndClass->hInstance; + wndClassA.hIcon = wndClass->hIcon; + wndClassA.hCursor = wndClass->hCursor; + wndClassA.hbrBackground = wndClass->hbrBackground; + AString menuName; + AString className; + if (IS_INTRESOURCE(wndClass->lpszMenuName)) + wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName; + else + { + menuName = GetSystemString(wndClass->lpszMenuName); + wndClassA.lpszMenuName = menuName; + } + if (IS_INTRESOURCE(wndClass->lpszClassName)) + wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName; + else + { + className = GetSystemString(wndClass->lpszClassName); + wndClassA.lpszClassName = className; + } + return RegisterClassA(&wndClassA); +} + +bool CWindow::Create(LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) +{ + if (g_IsNT) + { + _window = ::CreateWindowW(className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + return Create(GetSystemString(className), GetSystemString(windowName), + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); +} + +bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) +{ + if (g_IsNT) + { + _window = ::CreateWindowExW(exStyle, className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + AString classNameA; + LPCSTR classNameP; + if (IS_INTRESOURCE(className)) + classNameP = (LPCSTR)className; + else + { + classNameA = GetSystemString(className); + classNameP = classNameA; + } + AString windowNameA; + LPCSTR windowNameP; + if (IS_INTRESOURCE(windowName)) + windowNameP = (LPCSTR)windowName; + else + { + windowNameA = GetSystemString(windowName); + windowNameP = windowNameA; + } + return CreateEx(exStyle, classNameP, windowNameP, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); +} + +#endif + +#ifndef _UNICODE +bool MySetWindowText(HWND wnd, LPCWSTR s) +{ + if (g_IsNT) + return BOOLToBool(::SetWindowTextW(wnd, s)); + return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s))); +} +#endif + +bool CWindow::GetText(CSysString &s) const +{ + s.Empty(); + unsigned len = (unsigned)GetTextLength(); + if (len == 0) + return (::GetLastError() == ERROR_SUCCESS); + TCHAR *p = s.GetBuf(len); + { + const unsigned len2 = (unsigned)GetText(p, (int)(len + 1)); + if (len > len2) + len = len2; + } + s.ReleaseBuf_CalcLen(len); + if (len == 0) + return (::GetLastError() == ERROR_SUCCESS); + return true; +} + +#ifndef _UNICODE +bool CWindow::GetText(UString &s) const +{ + if (g_IsNT) + { + s.Empty(); + unsigned len = (unsigned)GetWindowTextLengthW(_window); + if (len == 0) + return (::GetLastError() == ERROR_SUCCESS); + wchar_t *p = s.GetBuf(len); + { + const unsigned len2 = (unsigned)GetWindowTextW(_window, p, (int)(len + 1)); + if (len > len2) + len = len2; + } + s.ReleaseBuf_CalcLen(len); + if (len == 0) + return (::GetLastError() == ERROR_SUCCESS); + return true; + } + CSysString sysString; + const bool result = GetText(sysString); + MultiByteToUnicodeString2(s, sysString); + return result; +} +#endif + + +/* +bool CWindow::ModifyStyleBase(int styleOffset, + DWORD remove, DWORD add, UINT flags) +{ + DWORD style = GetWindowLong(styleOffset); + DWORD newStyle = (style & ~remove) | add; + if (style == newStyle) + return false; // it is not good + + SetWindowLong(styleOffset, newStyle); + if (flags != 0) + { + ::SetWindowPos(_window, NULL, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags); + } + return TRUE; +} +*/ + +} diff --git a/CPP/Windows/Window.h b/CPP/Windows/Window.h index 9510ff113..a99143bd1 100644 --- a/CPP/Windows/Window.h +++ b/CPP/Windows/Window.h @@ -1,363 +1,363 @@ -// Windows/Window.h - -#ifndef ZIP7_INC_WINDOWS_WINDOW_H -#define ZIP7_INC_WINDOWS_WINDOW_H - -#include "../Common/MyWindows.h" -#include "../Common/MyString.h" - -#include "Defs.h" - -#ifndef UNDER_CE -#ifdef WM_CHANGEUISTATE -#define Z7_WIN_WM_CHANGEUISTATE WM_CHANGEUISTATE -#define Z7_WIN_WM_UPDATEUISTATE WM_UPDATEUISTATE -#define Z7_WIN_WM_QUERYUISTATE WM_QUERYUISTATE -#else -// these are defined for (_WIN32_WINNT >= 0x0500): -#define Z7_WIN_WM_CHANGEUISTATE 0x0127 -#define Z7_WIN_WM_UPDATEUISTATE 0x0128 -#define Z7_WIN_WM_QUERYUISTATE 0x0129 -#endif - -#ifdef UIS_SET - -#define Z7_WIN_UIS_SET UIS_SET -#define Z7_WIN_UIS_CLEAR UIS_CLEAR -#define Z7_WIN_UIS_INITIALIZE UIS_INITIALIZE - -#define Z7_WIN_UISF_HIDEFOCUS UISF_HIDEFOCUS -#define Z7_WIN_UISF_HIDEACCEL UISF_HIDEACCEL - -#else -// these are defined for (_WIN32_WINNT >= 0x0500): -// LOWORD(wParam) values in WM_*UISTATE -#define Z7_WIN_UIS_SET 1 -#define Z7_WIN_UIS_CLEAR 2 -#define Z7_WIN_UIS_INITIALIZE 3 - -// HIWORD(wParam) values in WM_*UISTATE -#define Z7_WIN_UISF_HIDEFOCUS 0x1 -#define Z7_WIN_UISF_HIDEACCEL 0x2 -// defined for for (_WIN32_WINNT >= 0x0501): -// #define Z7_WIN_UISF_ACTIVE 0x4 - -#endif - -#endif // UNDER_CE - - -#ifdef Z7_OLD_WIN_SDK - -// #define VK_OEM_1 0xBA // ';:' for US -#define VK_OEM_PLUS 0xBB // '+' any country -// #define VK_OEM_COMMA 0xBC // ',' any country -#define VK_OEM_MINUS 0xBD // '-' any country -// #define VK_OEM_PERIOD 0xBE // '.' any country -// #define VK_OEM_2 0xBF // '/?' for US -// #define VK_OEM_3 0xC0 // '`~' for US - -// #ifndef GWLP_USERDATA -#define GWLP_WNDPROC (-4) -#define GWLP_USERDATA (-21) -// #endif -#define DWLP_MSGRESULT 0 -// #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) -// #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) - -#define BTNS_BUTTON TBSTYLE_BUTTON // 0x0000 - -/* -vc6 defines INT_PTR via long: - typedef long INT_PTR, *PINT_PTR; - typedef unsigned long UINT_PTR, *PUINT_PTR; -but newer sdk (sdk2003+) defines INT_PTR via int: - typedef _W64 int INT_PTR, *PINT_PTR; - typedef _W64 unsigned int UINT_PTR, *PUINT_PTR; -*/ - -#define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0) - -#define GetWindowLongPtrA GetWindowLongA -#define GetWindowLongPtrW GetWindowLongW -#ifdef UNICODE -#define GetWindowLongPtr GetWindowLongPtrW -#else -#define GetWindowLongPtr GetWindowLongPtrA -#endif // !UNICODE - -#define SetWindowLongPtrA SetWindowLongA -#define SetWindowLongPtrW SetWindowLongW -#ifdef UNICODE -#define SetWindowLongPtr SetWindowLongPtrW -#else -#define SetWindowLongPtr SetWindowLongPtrA -#endif // !UNICODE - -#define ListView_SetCheckState(hwndLV, i, fCheck) \ - ListView_SetItemState(hwndLV, i, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), LVIS_STATEIMAGEMASK) - -#endif // Z7_OLD_WIN_SDK - -inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } - -#define MY_int_TO_WPARAM(i) ((WPARAM)(INT_PTR)(i)) - -namespace NWindows { - -inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass) - { return ::RegisterClass(wndClass); } - -#ifndef _UNICODE -ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); -#endif - -#ifdef _UNICODE -inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); } -#else -bool MySetWindowText(HWND wnd, LPCWSTR s); -#endif - - -#ifdef UNDER_CE -#define GWLP_USERDATA GWL_USERDATA -#define GWLP_WNDPROC GWL_WNDPROC -#define BTNS_BUTTON TBSTYLE_BUTTON -#define WC_COMBOBOXW L"ComboBox" -#define DWLP_MSGRESULT DWL_MSGRESULT -#endif - -class CWindow -{ - Z7_CLASS_NO_COPY(CWindow) -private: - // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags); -protected: - HWND _window; -public: - CWindow(HWND newWindow = NULL): _window(newWindow) {} - CWindow& operator=(HWND newWindow) - { - _window = newWindow; - return *this; - } - operator HWND() const { return _window; } - void Attach(HWND newWindow) { _window = newWindow; } - HWND Detach() - { - HWND window = _window; - _window = NULL; - return window; - } - - bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); } - - HWND GetParent() const { return ::GetParent(_window); } - bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); } - #ifndef UNDER_CE - bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); } - #endif - bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); } - bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); } - - bool CreateEx(DWORD exStyle, LPCTSTR className, - LPCTSTR windowName, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam) - { - _window = ::CreateWindowEx(exStyle, className, windowName, - style, x, y, width, height, parentWindow, - idOrHMenu, instance, createParam); - return (_window != NULL); - } - - bool Create(LPCTSTR className, - LPCTSTR windowName, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam) - { - _window = ::CreateWindow(className, windowName, - style, x, y, width, height, parentWindow, - idOrHMenu, instance, createParam); - return (_window != NULL); - } - - #ifndef _UNICODE - bool Create(LPCWSTR className, - LPCWSTR windowName, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam); - bool CreateEx(DWORD exStyle, LPCWSTR className, - LPCWSTR windowName, DWORD style, - int x, int y, int width, int height, - HWND parentWindow, HMENU idOrHMenu, - HINSTANCE instance, LPVOID createParam); - #endif - - - bool Destroy() - { - if (_window == NULL) - return true; - bool result = BOOLToBool(::DestroyWindow(_window)); - if (result) - _window = NULL; - return result; - } - bool IsWindow() { return BOOLToBool(::IsWindow(_window)); } - bool Move(int x, int y, int width, int height, bool repaint = true) - { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); } - - bool ChangeSubWindowSizeX(HWND hwnd, int xSize) - { - RECT rect; - ::GetWindowRect(hwnd, &rect); - POINT p1; - p1.x = rect.left; - p1.y = rect.top; - ScreenToClient(&p1); - return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE)); - } - - void ScreenToClient(RECT *rect) - { - POINT p1, p2; - p1.x = rect->left; - p1.y = rect->top; - p2.x = rect->right; - p2.y = rect->bottom; - ScreenToClient(&p1); - ScreenToClient(&p2); - - rect->left = p1.x; - rect->top = p1.y; - rect->right = p2.x; - rect->bottom = p2.y; - } - - bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); } - bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); } - bool Show_Bool(bool show) { return Show(show ? SW_SHOW: SW_HIDE); } - - #ifndef UNDER_CE - bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); } - bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); } - #endif - bool Update() { return BOOLToBool(::UpdateWindow(_window)); } - bool InvalidateRect(LPCRECT rect, bool backgroundErase = true) - { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); } - void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, (WPARAM)BoolToBOOL(redraw), 0); } - - LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); } - // LONG_PTR SetStyle(DWORD style) { return SetLongPtr(GWL_STYLE, (LONG_PTR)style); } - LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); } - // bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); } - - LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); } - LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); } - LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); } - LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); } - - - #ifdef UNDER_CE - - LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); } - LONG_PTR GetLongPtr(int index) const { return GetLong(index); } - - LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); } - LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); } - - #else - - LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) - { return ::SetWindowLongPtr(_window, index, - #ifndef _WIN64 - (LONG) - #endif - newLongPtr); } - #ifndef _UNICODE - LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr) - { return ::SetWindowLongPtrW(_window, index, - #ifndef _WIN64 - (LONG) - #endif - newLongPtr); } - #endif - - LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); } - LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); } - LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); } - - #endif - - /* - bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) - { return ModifyStyleBase(GWL_STYLE, remove, add, flags); } - bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) - { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); } - */ - - HWND SetFocus() { return ::SetFocus(_window); } - - LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) - { return ::SendMessage(_window, message, wParam, lParam); } - #ifndef _UNICODE - LRESULT SendMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) - { return ::SendMessageW(_window, message, wParam, lParam); } - #endif - - bool PostMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) - { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)); } - #ifndef _UNICODE - bool PostMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) - { return BOOLToBool(::PostMessageW(_window, message, wParam, lParam)); } - #endif - - bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); } - #ifndef _UNICODE - bool SetText(LPCWSTR s) { return MySetWindowText(_window, s); } - #endif - - int GetTextLength() const - { return GetWindowTextLength(_window); } - int GetText(LPTSTR string, int maxCount) const - { return GetWindowText(_window, string, maxCount); } - bool GetText(CSysString &s) const; - #ifndef _UNICODE - /* - UINT GetText(LPWSTR string, int maxCount) const - { return GetWindowTextW(_window, string, maxCount); } - */ - bool GetText(UString &s) const; - #endif - - bool Enable(bool enable) - { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); } - - bool IsEnabled() const - { return BOOLToBool(::IsWindowEnabled(_window)); } - - #ifndef UNDER_CE - HMENU GetSystemMenu(bool revert) - { return ::GetSystemMenu(_window, BoolToBOOL(revert)); } - #endif - - UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = NULL) - { return ::SetTimer(_window, idEvent, elapse, timerFunc); } - bool KillTimer(UINT_PTR idEvent) - {return BOOLToBool(::KillTimer(_window, idEvent)); } - - HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMsg(WM_SETICON, sizeType, (LPARAM)icon); } -}; - -#define RECT_SIZE_X(r) ((r).right - (r).left) -#define RECT_SIZE_Y(r) ((r).bottom - (r).top) - -inline bool IsKeyDown(int virtKey) { return (::GetKeyState(virtKey) & 0x8000) != 0; } - -} - -#endif +// Windows/Window.h + +#ifndef ZIP7_INC_WINDOWS_WINDOW_H +#define ZIP7_INC_WINDOWS_WINDOW_H + +#include "../Common/MyWindows.h" +#include "../Common/MyString.h" + +#include "Defs.h" + +#ifndef UNDER_CE +#ifdef WM_CHANGEUISTATE +#define Z7_WIN_WM_CHANGEUISTATE WM_CHANGEUISTATE +#define Z7_WIN_WM_UPDATEUISTATE WM_UPDATEUISTATE +#define Z7_WIN_WM_QUERYUISTATE WM_QUERYUISTATE +#else +// these are defined for (_WIN32_WINNT >= 0x0500): +#define Z7_WIN_WM_CHANGEUISTATE 0x0127 +#define Z7_WIN_WM_UPDATEUISTATE 0x0128 +#define Z7_WIN_WM_QUERYUISTATE 0x0129 +#endif + +#ifdef UIS_SET + +#define Z7_WIN_UIS_SET UIS_SET +#define Z7_WIN_UIS_CLEAR UIS_CLEAR +#define Z7_WIN_UIS_INITIALIZE UIS_INITIALIZE + +#define Z7_WIN_UISF_HIDEFOCUS UISF_HIDEFOCUS +#define Z7_WIN_UISF_HIDEACCEL UISF_HIDEACCEL + +#else +// these are defined for (_WIN32_WINNT >= 0x0500): +// LOWORD(wParam) values in WM_*UISTATE +#define Z7_WIN_UIS_SET 1 +#define Z7_WIN_UIS_CLEAR 2 +#define Z7_WIN_UIS_INITIALIZE 3 + +// HIWORD(wParam) values in WM_*UISTATE +#define Z7_WIN_UISF_HIDEFOCUS 0x1 +#define Z7_WIN_UISF_HIDEACCEL 0x2 +// defined for for (_WIN32_WINNT >= 0x0501): +// #define Z7_WIN_UISF_ACTIVE 0x4 + +#endif + +#endif // UNDER_CE + + +#ifdef Z7_OLD_WIN_SDK + +// #define VK_OEM_1 0xBA // ';:' for US +#define VK_OEM_PLUS 0xBB // '+' any country +// #define VK_OEM_COMMA 0xBC // ',' any country +#define VK_OEM_MINUS 0xBD // '-' any country +// #define VK_OEM_PERIOD 0xBE // '.' any country +// #define VK_OEM_2 0xBF // '/?' for US +// #define VK_OEM_3 0xC0 // '`~' for US + +// #ifndef GWLP_USERDATA +#define GWLP_WNDPROC (-4) +#define GWLP_USERDATA (-21) +// #endif +#define DWLP_MSGRESULT 0 +// #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT) +// #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC) + +#define BTNS_BUTTON TBSTYLE_BUTTON // 0x0000 + +/* +vc6 defines INT_PTR via long: + typedef long INT_PTR, *PINT_PTR; + typedef unsigned long UINT_PTR, *PUINT_PTR; +but newer sdk (sdk2003+) defines INT_PTR via int: + typedef _W64 int INT_PTR, *PINT_PTR; + typedef _W64 unsigned int UINT_PTR, *PUINT_PTR; +*/ + +#define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0) + +#define GetWindowLongPtrA GetWindowLongA +#define GetWindowLongPtrW GetWindowLongW +#ifdef UNICODE +#define GetWindowLongPtr GetWindowLongPtrW +#else +#define GetWindowLongPtr GetWindowLongPtrA +#endif // !UNICODE + +#define SetWindowLongPtrA SetWindowLongA +#define SetWindowLongPtrW SetWindowLongW +#ifdef UNICODE +#define SetWindowLongPtr SetWindowLongPtrW +#else +#define SetWindowLongPtr SetWindowLongPtrA +#endif // !UNICODE + +#define ListView_SetCheckState(hwndLV, i, fCheck) \ + ListView_SetItemState(hwndLV, i, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), LVIS_STATEIMAGEMASK) + +#endif // Z7_OLD_WIN_SDK + +inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } + +#define MY_int_TO_WPARAM(i) ((WPARAM)(INT_PTR)(i)) + +namespace NWindows { + +inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass) + { return ::RegisterClass(wndClass); } + +#ifndef _UNICODE +ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); +#endif + +#ifdef _UNICODE +inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); } +#else +bool MySetWindowText(HWND wnd, LPCWSTR s); +#endif + + +#ifdef UNDER_CE +#define GWLP_USERDATA GWL_USERDATA +#define GWLP_WNDPROC GWL_WNDPROC +#define BTNS_BUTTON TBSTYLE_BUTTON +#define WC_COMBOBOXW L"ComboBox" +#define DWLP_MSGRESULT DWL_MSGRESULT +#endif + +class CWindow +{ + Z7_CLASS_NO_COPY(CWindow) +private: + // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags); +protected: + HWND _window; +public: + CWindow(HWND newWindow = NULL): _window(newWindow) {} + CWindow& operator=(HWND newWindow) + { + _window = newWindow; + return *this; + } + operator HWND() const { return _window; } + void Attach(HWND newWindow) { _window = newWindow; } + HWND Detach() + { + HWND window = _window; + _window = NULL; + return window; + } + + bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); } + + HWND GetParent() const { return ::GetParent(_window); } + bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); } + #ifndef UNDER_CE + bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); } + #endif + bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); } + bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); } + + bool CreateEx(DWORD exStyle, LPCTSTR className, + LPCTSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) + { + _window = ::CreateWindowEx(exStyle, className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + + bool Create(LPCTSTR className, + LPCTSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) + { + _window = ::CreateWindow(className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + + #ifndef _UNICODE + bool Create(LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam); + bool CreateEx(DWORD exStyle, LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam); + #endif + + + bool Destroy() + { + if (_window == NULL) + return true; + bool result = BOOLToBool(::DestroyWindow(_window)); + if (result) + _window = NULL; + return result; + } + bool IsWindow() { return BOOLToBool(::IsWindow(_window)); } + bool Move(int x, int y, int width, int height, bool repaint = true) + { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); } + + bool ChangeSubWindowSizeX(HWND hwnd, int xSize) + { + RECT rect; + ::GetWindowRect(hwnd, &rect); + POINT p1; + p1.x = rect.left; + p1.y = rect.top; + ScreenToClient(&p1); + return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE)); + } + + void ScreenToClient(RECT *rect) + { + POINT p1, p2; + p1.x = rect->left; + p1.y = rect->top; + p2.x = rect->right; + p2.y = rect->bottom; + ScreenToClient(&p1); + ScreenToClient(&p2); + + rect->left = p1.x; + rect->top = p1.y; + rect->right = p2.x; + rect->bottom = p2.y; + } + + bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); } + bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); } + bool Show_Bool(bool show) { return Show(show ? SW_SHOW: SW_HIDE); } + + #ifndef UNDER_CE + bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); } + bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); } + #endif + bool Update() { return BOOLToBool(::UpdateWindow(_window)); } + bool InvalidateRect(LPCRECT rect, bool backgroundErase = true) + { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); } + void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, (WPARAM)BoolToBOOL(redraw), 0); } + + LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); } + // LONG_PTR SetStyle(DWORD style) { return SetLongPtr(GWL_STYLE, (LONG_PTR)style); } + LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); } + // bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); } + + LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); } + LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); } + LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); } + LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); } + + + #ifdef UNDER_CE + + LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); } + LONG_PTR GetLongPtr(int index) const { return GetLong(index); } + + LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); } + LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); } + + #else + + LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) + { return ::SetWindowLongPtr(_window, index, + #ifndef _WIN64 + (LONG) + #endif + newLongPtr); } + #ifndef _UNICODE + LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr) + { return ::SetWindowLongPtrW(_window, index, + #ifndef _WIN64 + (LONG) + #endif + newLongPtr); } + #endif + + LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); } + LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); } + LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); } + + #endif + + /* + bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) + { return ModifyStyleBase(GWL_STYLE, remove, add, flags); } + bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) + { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); } + */ + + HWND SetFocus() { return ::SetFocus(_window); } + + LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return ::SendMessage(_window, message, wParam, lParam); } + #ifndef _UNICODE + LRESULT SendMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return ::SendMessageW(_window, message, wParam, lParam); } + #endif + + bool PostMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)); } + #ifndef _UNICODE + bool PostMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return BOOLToBool(::PostMessageW(_window, message, wParam, lParam)); } + #endif + + bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); } + #ifndef _UNICODE + bool SetText(LPCWSTR s) { return MySetWindowText(_window, s); } + #endif + + int GetTextLength() const + { return GetWindowTextLength(_window); } + int GetText(LPTSTR string, int maxCount) const + { return GetWindowText(_window, string, maxCount); } + bool GetText(CSysString &s) const; + #ifndef _UNICODE + /* + UINT GetText(LPWSTR string, int maxCount) const + { return GetWindowTextW(_window, string, maxCount); } + */ + bool GetText(UString &s) const; + #endif + + bool Enable(bool enable) + { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); } + + bool IsEnabled() const + { return BOOLToBool(::IsWindowEnabled(_window)); } + + #ifndef UNDER_CE + HMENU GetSystemMenu(bool revert) + { return ::GetSystemMenu(_window, BoolToBOOL(revert)); } + #endif + + UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = NULL) + { return ::SetTimer(_window, idEvent, elapse, timerFunc); } + bool KillTimer(UINT_PTR idEvent) + {return BOOLToBool(::KillTimer(_window, idEvent)); } + + HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMsg(WM_SETICON, sizeType, (LPARAM)icon); } +}; + +#define RECT_SIZE_X(r) ((r).right - (r).left) +#define RECT_SIZE_Y(r) ((r).bottom - (r).top) + +inline bool IsKeyDown(int virtKey) { return (::GetKeyState(virtKey) & 0x8000) != 0; } + +} + +#endif diff --git a/DOC/7zC.txt b/DOC/7zC.txt index 49276787f..939b720f9 100644 --- a/DOC/7zC.txt +++ b/DOC/7zC.txt @@ -1,187 +1,187 @@ -7z ANSI-C Decoder 9.35 ----------------------- - -7z ANSI-C provides 7z/LZMA decoding. -7z ANSI-C version is simplified version ported from C++ code. - -LZMA is default and general compression method of 7z format -in 7-Zip compression program (www.7-zip.org). LZMA provides high -compression ratio and very fast decompression. - - -LICENSE -------- - -7z ANSI-C Decoder is part of the LZMA SDK. -LZMA SDK is written and placed in the public domain by Igor Pavlov. - -Files ---------------------- - -7zDecode.* - Low level 7z decoding -7zExtract.* - High level 7z decoding -7zHeader.* - .7z format constants -7zIn.* - .7z archive opening -7zItem.* - .7z structures -7zMain.c - Test application - - -How To Use ----------- - -You can create .7z archive with 7z.exe, 7za.exe or 7zr.exe: - - 7z.exe a archive.7z *.htm -r -mx -m0fb=255 - -If you have big number of files in archive, and you need fast extracting, -you can use partly-solid archives: - - 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K - -In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only -512KB for extracting one file from such archive. - - -Limitations of current version of 7z ANSI-C Decoder ---------------------------------------------------- - - - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive. - - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters. - - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. - -These limitations will be fixed in future versions. - - -Using 7z ANSI-C Decoder Test application: ------------------------------------------ - -Usage: 7zDec - -: - e: Extract files from archive - l: List contents of archive - t: Test integrity of archive - -Example: - - 7zDec l archive.7z - -lists contents of archive.7z - - 7zDec e archive.7z - -extracts files from archive.7z to current folder. - - -How to use .7z Decoder ----------------------- - -Memory allocation -~~~~~~~~~~~~~~~~~ - -7z Decoder uses two memory pools: -1) Temporary pool -2) Main pool -Such scheme can allow you to avoid fragmentation of allocated blocks. - - -Steps for using 7z decoder --------------------------- - -Use code at 7zMain.c as example. - -1) Declare variables: - inStream /* implements ILookInStream interface */ - CSzArEx db; /* 7z archive database structure */ - ISzAlloc allocImp; /* memory functions for main pool */ - ISzAlloc allocTempImp; /* memory functions for temporary pool */ - -2) call CrcGenerateTable(); function to initialize CRC structures. - -3) call SzArEx_Init(&db); function to initialize db structures. - -4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive - -This function opens archive "inStream" and reads headers to "db". -All items in "db" will be allocated with "allocMain" functions. -SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions. - -5) List items or Extract items - - Listing code: - ~~~~~~~~~~~~~ - - Use SzArEx_GetFileNameUtf16 function. Look example code in C\Util\7z\7zMain.c file. - - - Extracting code: - ~~~~~~~~~~~~~~~~ - - SZ_RESULT SzAr_Extract( - CArchiveDatabaseEx *db, - ILookInStream *inStream, - UInt32 fileIndex, /* index of file */ - UInt32 *blockIndex, /* index of solid block */ - Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ - size_t *outBufferSize, /* buffer size for output buffer */ - size_t *offset, /* offset of stream for required file in *outBuffer */ - size_t *outSizeProcessed, /* size of file in *outBuffer */ - ISzAlloc *allocMain, - ISzAlloc *allocTemp); - - If you need to decompress more than one file, you can send these values from previous call: - blockIndex, - outBuffer, - outBufferSize, - You can consider "outBuffer" as cache of solid block. If your archive is solid, - it will increase decompression speed. - - After decompressing you must free "outBuffer": - allocImp.Free(outBuffer); - -6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db". - - - - -Memory requirements for .7z decoding ------------------------------------- - -Memory usage for Archive opening: - - Temporary pool: - - Memory for uncompressed .7z headers - - some other temporary blocks - - Main pool: - - Memory for database: - Estimated size of one file structures in solid archive: - - Size (4 or 8 Bytes) - - CRC32 (4 bytes) - - LastWriteTime (8 bytes) - - Some file information (4 bytes) - - File Name (variable length) + pointer + allocation structures - -Memory usage for archive Decompressing: - - Temporary pool: - - Memory for LZMA decompressing structures - - Main pool: - - Memory for decompressed solid block - - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these - temprorary buffers can be about 15% of solid block size. - - -7z Decoder doesn't allocate memory for compressed blocks. -Instead of this, you must allocate buffer with desired -size before calling 7z Decoder. Use 7zMain.c as example. - - -Defines -------- - -_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. - - ---- - -http://www.7-zip.org -http://www.7-zip.org/sdk.html -http://www.7-zip.org/support.html +7z ANSI-C Decoder 9.35 +---------------------- + +7z ANSI-C provides 7z/LZMA decoding. +7z ANSI-C version is simplified version ported from C++ code. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + + +LICENSE +------- + +7z ANSI-C Decoder is part of the LZMA SDK. +LZMA SDK is written and placed in the public domain by Igor Pavlov. + +Files +--------------------- + +7zDecode.* - Low level 7z decoding +7zExtract.* - High level 7z decoding +7zHeader.* - .7z format constants +7zIn.* - .7z archive opening +7zItem.* - .7z structures +7zMain.c - Test application + + +How To Use +---------- + +You can create .7z archive with 7z.exe, 7za.exe or 7zr.exe: + + 7z.exe a archive.7z *.htm -r -mx -m0fb=255 + +If you have big number of files in archive, and you need fast extracting, +you can use partly-solid archives: + + 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K + +In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only +512KB for extracting one file from such archive. + + +Limitations of current version of 7z ANSI-C Decoder +--------------------------------------------------- + + - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive. + - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters. + - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. + +These limitations will be fixed in future versions. + + +Using 7z ANSI-C Decoder Test application: +----------------------------------------- + +Usage: 7zDec + +: + e: Extract files from archive + l: List contents of archive + t: Test integrity of archive + +Example: + + 7zDec l archive.7z + +lists contents of archive.7z + + 7zDec e archive.7z + +extracts files from archive.7z to current folder. + + +How to use .7z Decoder +---------------------- + +Memory allocation +~~~~~~~~~~~~~~~~~ + +7z Decoder uses two memory pools: +1) Temporary pool +2) Main pool +Such scheme can allow you to avoid fragmentation of allocated blocks. + + +Steps for using 7z decoder +-------------------------- + +Use code at 7zMain.c as example. + +1) Declare variables: + inStream /* implements ILookInStream interface */ + CSzArEx db; /* 7z archive database structure */ + ISzAlloc allocImp; /* memory functions for main pool */ + ISzAlloc allocTempImp; /* memory functions for temporary pool */ + +2) call CrcGenerateTable(); function to initialize CRC structures. + +3) call SzArEx_Init(&db); function to initialize db structures. + +4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive + +This function opens archive "inStream" and reads headers to "db". +All items in "db" will be allocated with "allocMain" functions. +SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions. + +5) List items or Extract items + + Listing code: + ~~~~~~~~~~~~~ + + Use SzArEx_GetFileNameUtf16 function. Look example code in C\Util\7z\7zMain.c file. + + + Extracting code: + ~~~~~~~~~~~~~~~~ + + SZ_RESULT SzAr_Extract( + CArchiveDatabaseEx *db, + ILookInStream *inStream, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + + If you need to decompress more than one file, you can send these values from previous call: + blockIndex, + outBuffer, + outBufferSize, + You can consider "outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + After decompressing you must free "outBuffer": + allocImp.Free(outBuffer); + +6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db". + + + + +Memory requirements for .7z decoding +------------------------------------ + +Memory usage for Archive opening: + - Temporary pool: + - Memory for uncompressed .7z headers + - some other temporary blocks + - Main pool: + - Memory for database: + Estimated size of one file structures in solid archive: + - Size (4 or 8 Bytes) + - CRC32 (4 bytes) + - LastWriteTime (8 bytes) + - Some file information (4 bytes) + - File Name (variable length) + pointer + allocation structures + +Memory usage for archive Decompressing: + - Temporary pool: + - Memory for LZMA decompressing structures + - Main pool: + - Memory for decompressed solid block + - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these + temprorary buffers can be about 15% of solid block size. + + +7z Decoder doesn't allocate memory for compressed blocks. +Instead of this, you must allocate buffer with desired +size before calling 7z Decoder. Use 7zMain.c as example. + + +Defines +------- + +_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. + + +--- + +http://www.7-zip.org +http://www.7-zip.org/sdk.html +http://www.7-zip.org/support.html diff --git a/DOC/7zFormat.txt b/DOC/7zFormat.txt index 9239e9355..74cdfa418 100644 --- a/DOC/7zFormat.txt +++ b/DOC/7zFormat.txt @@ -1,469 +1,469 @@ -7z Format description (18.06) ----------------------------- - -This file contains description of 7z archive format. -7z archive can contain files compressed with any method. -See "Methods.txt" for description for defined compressing methods. - - -Format structure Overview -------------------------- - -Some fields can be optional. - -Archive structure -~~~~~~~~~~~~~~~~~ -SignatureHeader -[PackedStreams] -[PackedStreamsForHeaders] -[ - Header - or - { - Packed Header - HeaderInfo - } -] - - - -Header structure -~~~~~~~~~~~~~~~~ -{ - ArchiveProperties - AdditionalStreams - { - PackInfo - { - PackPos - NumPackStreams - Sizes[NumPackStreams] - CRCs[NumPackStreams] - } - CodersInfo - { - NumFolders - Folders[NumFolders] - { - NumCoders - CodersInfo[NumCoders] - { - ID - NumInStreams; - NumOutStreams; - PropertiesSize - Properties[PropertiesSize] - } - NumBindPairs - BindPairsInfo[NumBindPairs] - { - InIndex; - OutIndex; - } - PackedIndices - } - UnPackSize[Folders][Folders.NumOutstreams] - CRCs[NumFolders] - } - SubStreamsInfo - { - NumUnPackStreamsInFolders[NumFolders]; - UnPackSizes[] - CRCs[] - } - } - MainStreamsInfo - { - (Same as in AdditionalStreams) - } - FilesInfo - { - NumFiles - Properties[] - { - ID - Size - Data - } - } -} - -HeaderInfo structure -~~~~~~~~~~~~~~~~~~~~ -{ - (Same as in AdditionalStreams) -} - - - -Notes about Notation and encoding ---------------------------------- - -7z uses little endian encoding. - -7z archive format has optional headers that are marked as -[] -Header -[] - -REAL_UINT64 means real UINT64. - -UINT64 means real UINT64 encoded with the following scheme: - - Size of encoding sequence depends from first byte: - First_Byte Extra_Bytes Value - (binary) - 0xxxxxxx : ( xxxxxxx ) - 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y - 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y - ... - 1111110x BYTE y[6] : ( x << (8 * 6)) + y - 11111110 BYTE y[7] : y - 11111111 BYTE y[8] : y - - - -Property IDs ------------- - -0x00 = kEnd - -0x01 = kHeader - -0x02 = kArchiveProperties - -0x03 = kAdditionalStreamsInfo -0x04 = kMainStreamsInfo -0x05 = kFilesInfo - -0x06 = kPackInfo -0x07 = kUnPackInfo -0x08 = kSubStreamsInfo - -0x09 = kSize -0x0A = kCRC - -0x0B = kFolder - -0x0C = kCodersUnPackSize -0x0D = kNumUnPackStream - -0x0E = kEmptyStream -0x0F = kEmptyFile -0x10 = kAnti - -0x11 = kName -0x12 = kCTime -0x13 = kATime -0x14 = kMTime -0x15 = kWinAttributes -0x16 = kComment - -0x17 = kEncodedHeader - -0x18 = kStartPos -0x19 = kDummy - - -7z format headers ------------------ - -SignatureHeader -~~~~~~~~~~~~~~~ - BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - - ArchiveVersion - { - BYTE Major; // now = 0 - BYTE Minor; // now = 4 - }; - - UINT32 StartHeaderCRC; - - StartHeader - { - REAL_UINT64 NextHeaderOffset - REAL_UINT64 NextHeaderSize - UINT32 NextHeaderCRC - } - - -........................... - - -ArchiveProperties -~~~~~~~~~~~~~~~~~ -BYTE NID::kArchiveProperties (0x02) -for (;;) -{ - BYTE PropertyType; - if (aType == 0) - break; - UINT64 PropertySize; - BYTE PropertyData[PropertySize]; -} - - -Digests (NumStreams) -~~~~~~~~~~~~~~~~~~~~~ - BYTE AllAreDefined - if (AllAreDefined == 0) - { - for(NumStreams) - BIT Defined - } - UINT32 CRCs[NumDefined] - - -PackInfo -~~~~~~~~~~~~ - BYTE NID::kPackInfo (0x06) - UINT64 PackPos - UINT64 NumPackStreams - - [] - BYTE NID::kSize (0x09) - UINT64 PackSizes[NumPackStreams] - [] - - [] - BYTE NID::kCRC (0x0A) - PackStreamDigests[NumPackStreams] - [] - - BYTE NID::kEnd - - -Folder -~~~~~~ - UINT64 NumCoders; - for (NumCoders) - { - BYTE - { - 0:3 CodecIdSize - 4: Is Complex Coder - 5: There Are Attributes - 6: Reserved - 7: There are more alternative methods. (Not used anymore, must be 0). - } - BYTE CodecId[CodecIdSize] - if (Is Complex Coder) - { - UINT64 NumInStreams; - UINT64 NumOutStreams; - } - if (There Are Attributes) - { - UINT64 PropertiesSize - BYTE Properties[PropertiesSize] - } - } - - NumBindPairs = NumOutStreamsTotal - 1; - - for (NumBindPairs) - { - UINT64 InIndex; - UINT64 OutIndex; - } - - NumPackedStreams = NumInStreamsTotal - NumBindPairs; - if (NumPackedStreams > 1) - for(NumPackedStreams) - { - UINT64 Index; - }; - - - - -Coders Info -~~~~~~~~~~~ - - BYTE NID::kUnPackInfo (0x07) - - - BYTE NID::kFolder (0x0B) - UINT64 NumFolders - BYTE External - switch(External) - { - case 0: - Folders[NumFolders] - case 1: - UINT64 DataStreamIndex - } - - - BYTE ID::kCodersUnPackSize (0x0C) - for(Folders) - for(Folder.NumOutStreams) - UINT64 UnPackSize; - - - [] - BYTE NID::kCRC (0x0A) - UnPackDigests[NumFolders] - [] - - - - BYTE NID::kEnd - - - -SubStreams Info -~~~~~~~~~~~~~~ - BYTE NID::kSubStreamsInfo; (0x08) - - [] - BYTE NID::kNumUnPackStream; (0x0D) - UINT64 NumUnPackStreamsInFolders[NumFolders]; - [] - - - [] - BYTE NID::kSize (0x09) - UINT64 UnPackSizes[] - [] - - - [] - BYTE NID::kCRC (0x0A) - Digests[Number of streams with unknown CRC] - [] - - - BYTE NID::kEnd - - -Streams Info -~~~~~~~~~~~~ - - [] - PackInfo - [] - - - [] - CodersInfo - [] - - - [] - SubStreamsInfo - [] - - BYTE NID::kEnd - - -FilesInfo -~~~~~~~~~ - BYTE NID::kFilesInfo; (0x05) - UINT64 NumFiles - - for (;;) - { - BYTE PropertyType; - if (aType == 0) - break; - - UINT64 Size; - - switch(PropertyType) - { - kEmptyStream: (0x0E) - for(NumFiles) - BIT IsEmptyStream - - kEmptyFile: (0x0F) - for(EmptyStreams) - BIT IsEmptyFile - - kAnti: (0x10) - for(EmptyStreams) - BIT IsAntiFile - - case kCTime: (0x12) - case kATime: (0x13) - case kMTime: (0x14) - BYTE AllAreDefined - if (AllAreDefined == 0) - { - for(NumFiles) - BIT TimeDefined - } - BYTE External; - if(External != 0) - UINT64 DataIndex - [] - for(Definded Items) - REAL_UINT64 Time - [] - - kNames: (0x11) - BYTE External; - if(External != 0) - UINT64 DataIndex - [] - for(Files) - { - wchar_t Names[NameSize]; - wchar_t 0; - } - [] - - kAttributes: (0x15) - BYTE AllAreDefined - if (AllAreDefined == 0) - { - for(NumFiles) - BIT AttributesAreDefined - } - BYTE External; - if(External != 0) - UINT64 DataIndex - [] - for(Definded Attributes) - UINT32 Attributes - [] - } - } - - -Header -~~~~~~ - BYTE NID::kHeader (0x01) - - [] - ArchiveProperties - [] - - [] - BYTE NID::kAdditionalStreamsInfo; (0x03) - StreamsInfo - [] - - [] - BYTE NID::kMainStreamsInfo; (0x04) - StreamsInfo - [] - - [] - FilesInfo - [] - - BYTE NID::kEnd - - -HeaderInfo -~~~~~~~~~~ - [] - BYTE NID::kEncodedHeader; (0x17) - StreamsInfo for Encoded Header - [] - - ---- -End of document +7z Format description (18.06) +---------------------------- + +This file contains description of 7z archive format. +7z archive can contain files compressed with any method. +See "Methods.txt" for description for defined compressing methods. + + +Format structure Overview +------------------------- + +Some fields can be optional. + +Archive structure +~~~~~~~~~~~~~~~~~ +SignatureHeader +[PackedStreams] +[PackedStreamsForHeaders] +[ + Header + or + { + Packed Header + HeaderInfo + } +] + + + +Header structure +~~~~~~~~~~~~~~~~ +{ + ArchiveProperties + AdditionalStreams + { + PackInfo + { + PackPos + NumPackStreams + Sizes[NumPackStreams] + CRCs[NumPackStreams] + } + CodersInfo + { + NumFolders + Folders[NumFolders] + { + NumCoders + CodersInfo[NumCoders] + { + ID + NumInStreams; + NumOutStreams; + PropertiesSize + Properties[PropertiesSize] + } + NumBindPairs + BindPairsInfo[NumBindPairs] + { + InIndex; + OutIndex; + } + PackedIndices + } + UnPackSize[Folders][Folders.NumOutstreams] + CRCs[NumFolders] + } + SubStreamsInfo + { + NumUnPackStreamsInFolders[NumFolders]; + UnPackSizes[] + CRCs[] + } + } + MainStreamsInfo + { + (Same as in AdditionalStreams) + } + FilesInfo + { + NumFiles + Properties[] + { + ID + Size + Data + } + } +} + +HeaderInfo structure +~~~~~~~~~~~~~~~~~~~~ +{ + (Same as in AdditionalStreams) +} + + + +Notes about Notation and encoding +--------------------------------- + +7z uses little endian encoding. + +7z archive format has optional headers that are marked as +[] +Header +[] + +REAL_UINT64 means real UINT64. + +UINT64 means real UINT64 encoded with the following scheme: + + Size of encoding sequence depends from first byte: + First_Byte Extra_Bytes Value + (binary) + 0xxxxxxx : ( xxxxxxx ) + 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y + 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y + ... + 1111110x BYTE y[6] : ( x << (8 * 6)) + y + 11111110 BYTE y[7] : y + 11111111 BYTE y[8] : y + + + +Property IDs +------------ + +0x00 = kEnd + +0x01 = kHeader + +0x02 = kArchiveProperties + +0x03 = kAdditionalStreamsInfo +0x04 = kMainStreamsInfo +0x05 = kFilesInfo + +0x06 = kPackInfo +0x07 = kUnPackInfo +0x08 = kSubStreamsInfo + +0x09 = kSize +0x0A = kCRC + +0x0B = kFolder + +0x0C = kCodersUnPackSize +0x0D = kNumUnPackStream + +0x0E = kEmptyStream +0x0F = kEmptyFile +0x10 = kAnti + +0x11 = kName +0x12 = kCTime +0x13 = kATime +0x14 = kMTime +0x15 = kWinAttributes +0x16 = kComment + +0x17 = kEncodedHeader + +0x18 = kStartPos +0x19 = kDummy + + +7z format headers +----------------- + +SignatureHeader +~~~~~~~~~~~~~~~ + BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; + + ArchiveVersion + { + BYTE Major; // now = 0 + BYTE Minor; // now = 4 + }; + + UINT32 StartHeaderCRC; + + StartHeader + { + REAL_UINT64 NextHeaderOffset + REAL_UINT64 NextHeaderSize + UINT32 NextHeaderCRC + } + + +........................... + + +ArchiveProperties +~~~~~~~~~~~~~~~~~ +BYTE NID::kArchiveProperties (0x02) +for (;;) +{ + BYTE PropertyType; + if (aType == 0) + break; + UINT64 PropertySize; + BYTE PropertyData[PropertySize]; +} + + +Digests (NumStreams) +~~~~~~~~~~~~~~~~~~~~~ + BYTE AllAreDefined + if (AllAreDefined == 0) + { + for(NumStreams) + BIT Defined + } + UINT32 CRCs[NumDefined] + + +PackInfo +~~~~~~~~~~~~ + BYTE NID::kPackInfo (0x06) + UINT64 PackPos + UINT64 NumPackStreams + + [] + BYTE NID::kSize (0x09) + UINT64 PackSizes[NumPackStreams] + [] + + [] + BYTE NID::kCRC (0x0A) + PackStreamDigests[NumPackStreams] + [] + + BYTE NID::kEnd + + +Folder +~~~~~~ + UINT64 NumCoders; + for (NumCoders) + { + BYTE + { + 0:3 CodecIdSize + 4: Is Complex Coder + 5: There Are Attributes + 6: Reserved + 7: There are more alternative methods. (Not used anymore, must be 0). + } + BYTE CodecId[CodecIdSize] + if (Is Complex Coder) + { + UINT64 NumInStreams; + UINT64 NumOutStreams; + } + if (There Are Attributes) + { + UINT64 PropertiesSize + BYTE Properties[PropertiesSize] + } + } + + NumBindPairs = NumOutStreamsTotal - 1; + + for (NumBindPairs) + { + UINT64 InIndex; + UINT64 OutIndex; + } + + NumPackedStreams = NumInStreamsTotal - NumBindPairs; + if (NumPackedStreams > 1) + for(NumPackedStreams) + { + UINT64 Index; + }; + + + + +Coders Info +~~~~~~~~~~~ + + BYTE NID::kUnPackInfo (0x07) + + + BYTE NID::kFolder (0x0B) + UINT64 NumFolders + BYTE External + switch(External) + { + case 0: + Folders[NumFolders] + case 1: + UINT64 DataStreamIndex + } + + + BYTE ID::kCodersUnPackSize (0x0C) + for(Folders) + for(Folder.NumOutStreams) + UINT64 UnPackSize; + + + [] + BYTE NID::kCRC (0x0A) + UnPackDigests[NumFolders] + [] + + + + BYTE NID::kEnd + + + +SubStreams Info +~~~~~~~~~~~~~~ + BYTE NID::kSubStreamsInfo; (0x08) + + [] + BYTE NID::kNumUnPackStream; (0x0D) + UINT64 NumUnPackStreamsInFolders[NumFolders]; + [] + + + [] + BYTE NID::kSize (0x09) + UINT64 UnPackSizes[] + [] + + + [] + BYTE NID::kCRC (0x0A) + Digests[Number of streams with unknown CRC] + [] + + + BYTE NID::kEnd + + +Streams Info +~~~~~~~~~~~~ + + [] + PackInfo + [] + + + [] + CodersInfo + [] + + + [] + SubStreamsInfo + [] + + BYTE NID::kEnd + + +FilesInfo +~~~~~~~~~ + BYTE NID::kFilesInfo; (0x05) + UINT64 NumFiles + + for (;;) + { + BYTE PropertyType; + if (aType == 0) + break; + + UINT64 Size; + + switch(PropertyType) + { + kEmptyStream: (0x0E) + for(NumFiles) + BIT IsEmptyStream + + kEmptyFile: (0x0F) + for(EmptyStreams) + BIT IsEmptyFile + + kAnti: (0x10) + for(EmptyStreams) + BIT IsAntiFile + + case kCTime: (0x12) + case kATime: (0x13) + case kMTime: (0x14) + BYTE AllAreDefined + if (AllAreDefined == 0) + { + for(NumFiles) + BIT TimeDefined + } + BYTE External; + if(External != 0) + UINT64 DataIndex + [] + for(Definded Items) + REAL_UINT64 Time + [] + + kNames: (0x11) + BYTE External; + if(External != 0) + UINT64 DataIndex + [] + for(Files) + { + wchar_t Names[NameSize]; + wchar_t 0; + } + [] + + kAttributes: (0x15) + BYTE AllAreDefined + if (AllAreDefined == 0) + { + for(NumFiles) + BIT AttributesAreDefined + } + BYTE External; + if(External != 0) + UINT64 DataIndex + [] + for(Definded Attributes) + UINT32 Attributes + [] + } + } + + +Header +~~~~~~ + BYTE NID::kHeader (0x01) + + [] + ArchiveProperties + [] + + [] + BYTE NID::kAdditionalStreamsInfo; (0x03) + StreamsInfo + [] + + [] + BYTE NID::kMainStreamsInfo; (0x04) + StreamsInfo + [] + + [] + FilesInfo + [] + + BYTE NID::kEnd + + +HeaderInfo +~~~~~~~~~~ + [] + BYTE NID::kEncodedHeader; (0x17) + StreamsInfo for Encoded Header + [] + + +--- +End of document diff --git a/DOC/7zip.hhp b/DOC/7zip.hhp index 18a2774b4..58fbd1f9b 100644 --- a/DOC/7zip.hhp +++ b/DOC/7zip.hhp @@ -1,84 +1,84 @@ -[OPTIONS] -Compatibility=1.1 or later -Compiled file=7-zip.chm -Contents file=7zip.hhc -Default topic=start.htm -Display compile progress=No -Full-text search=Yes -Index file=7zip.hhk -Language=0x409 English (United States) - - -[FILES] -start.htm -general\thanks.htm -general\faq.htm -general\formats.htm -general\index.htm -general\license.htm -general\performance.htm -general\7z.htm -cmdline\index.htm -cmdline\syntax.htm -cmdline\exit_codes.htm -cmdline\commands\add.htm -cmdline\commands\bench.htm -cmdline\commands\delete.htm -cmdline\commands\extract.htm -cmdline\commands\extract_full.htm -cmdline\commands\update.htm -cmdline\commands\hash.htm -cmdline\commands\index.htm -cmdline\commands\list.htm -cmdline\commands\rename.htm -cmdline\commands\test.htm -cmdline\switches\index.htm -cmdline\switches\yes.htm -cmdline\switches\include.htm -cmdline\switches\method.htm -cmdline\switches\ar_include.htm -cmdline\switches\ar_exclude.htm -cmdline\switches\ar_no.htm -cmdline\switches\bb.htm -cmdline\switches\bs.htm -cmdline\switches\charset.htm -cmdline\switches\email.htm -cmdline\switches\list_tech.htm -cmdline\switches\large_pages.htm -cmdline\switches\output_dir.htm -cmdline\switches\overwrite.htm -cmdline\switches\password.htm -cmdline\switches\recurse.htm -cmdline\switches\sa.htm -cmdline\switches\scc.htm -cmdline\switches\scrc.htm -cmdline\switches\sdel.htm -cmdline\switches\sfx.htm -cmdline\switches\shared.htm -cmdline\switches\sni.htm -cmdline\switches\sns.htm -cmdline\switches\spf.htm -cmdline\switches\spm.htm -cmdline\switches\ssc.htm -cmdline\switches\stdin.htm -cmdline\switches\stdout.htm -cmdline\switches\stl.htm -cmdline\switches\stop_switch.htm -cmdline\switches\stx.htm -cmdline\switches\type.htm -cmdline\switches\update.htm -cmdline\switches\working_dir.htm -cmdline\switches\exclude.htm -fm\options.htm -fm\benchmark.htm -fm\temp.htm -fm\index.htm -fm\menu.htm -fm\about.htm -fm\plugins\index.htm -fm\plugins\7-zip\extract.htm -fm\plugins\7-zip\index.htm -fm\plugins\7-zip\add.htm - -[INFOTYPES] - +[OPTIONS] +Compatibility=1.1 or later +Compiled file=7-zip.chm +Contents file=7zip.hhc +Default topic=start.htm +Display compile progress=No +Full-text search=Yes +Index file=7zip.hhk +Language=0x409 English (United States) + + +[FILES] +start.htm +general\thanks.htm +general\faq.htm +general\formats.htm +general\index.htm +general\license.htm +general\performance.htm +general\7z.htm +cmdline\index.htm +cmdline\syntax.htm +cmdline\exit_codes.htm +cmdline\commands\add.htm +cmdline\commands\bench.htm +cmdline\commands\delete.htm +cmdline\commands\extract.htm +cmdline\commands\extract_full.htm +cmdline\commands\update.htm +cmdline\commands\hash.htm +cmdline\commands\index.htm +cmdline\commands\list.htm +cmdline\commands\rename.htm +cmdline\commands\test.htm +cmdline\switches\index.htm +cmdline\switches\yes.htm +cmdline\switches\include.htm +cmdline\switches\method.htm +cmdline\switches\ar_include.htm +cmdline\switches\ar_exclude.htm +cmdline\switches\ar_no.htm +cmdline\switches\bb.htm +cmdline\switches\bs.htm +cmdline\switches\charset.htm +cmdline\switches\email.htm +cmdline\switches\list_tech.htm +cmdline\switches\large_pages.htm +cmdline\switches\output_dir.htm +cmdline\switches\overwrite.htm +cmdline\switches\password.htm +cmdline\switches\recurse.htm +cmdline\switches\sa.htm +cmdline\switches\scc.htm +cmdline\switches\scrc.htm +cmdline\switches\sdel.htm +cmdline\switches\sfx.htm +cmdline\switches\shared.htm +cmdline\switches\sni.htm +cmdline\switches\sns.htm +cmdline\switches\spf.htm +cmdline\switches\spm.htm +cmdline\switches\ssc.htm +cmdline\switches\stdin.htm +cmdline\switches\stdout.htm +cmdline\switches\stl.htm +cmdline\switches\stop_switch.htm +cmdline\switches\stx.htm +cmdline\switches\type.htm +cmdline\switches\update.htm +cmdline\switches\working_dir.htm +cmdline\switches\exclude.htm +fm\options.htm +fm\benchmark.htm +fm\temp.htm +fm\index.htm +fm\menu.htm +fm\about.htm +fm\plugins\index.htm +fm\plugins\7-zip\extract.htm +fm\plugins\7-zip\index.htm +fm\plugins\7-zip\add.htm + +[INFOTYPES] + diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index 25e53b07c..867e3d1b2 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs @@ -1,403 +1,403 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - - 1 - - - - - - - - - - - - - - - - Privileged - - - - - - - - - - - - - - - - - - - - - - - - - - - Privileged - - - - - - Privileged - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + 1 + + + + + + + + + + + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + Privileged + + + + + + Privileged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DOC/License.txt b/DOC/License.txt index 6406093a6..8917dfc68 100644 --- a/DOC/License.txt +++ b/DOC/License.txt @@ -1,151 +1,151 @@ - 7-Zip source code - ~~~~~~~~~~~~~~~~~ - License for use and distribution - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - 7-Zip Copyright (C) 1999-2024 Igor Pavlov. - - The licenses for files are: - - - CPP/7zip/Compress/Rar* files: the "GNU LGPL" with "unRAR license restriction" - - CPP/7zip/Compress/LzfseDecoder.cpp: the "BSD 3-clause License" - - C/ZstdDec.c: the "BSD 3-clause License" - - C/Xxh64.c: the "BSD 2-clause License" - - Some files are "public domain" files, if "public domain" status is stated in source file. - - the "GNU LGPL" for all other files. If there is no license information in - some source file, that file is under the "GNU LGPL". - - The "GNU LGPL" with "unRAR license restriction" means that you must follow both - "GNU LGPL" rules and "unRAR license restriction" rules. - - - - -GNU LGPL information --------------------- - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, - you can get a copy of the GNU Lesser General Public License from - http://www.gnu.org/ - - - - -BSD 3-clause License in 7-Zip code ----------------------------------- - - The "BSD 3-clause License" is used for the following code in 7z.dll - 1) LZFSE data decompression. - CPP/7zip/Compress/LzfseDecoder.cpp. - That code was derived from the code in the "LZFSE compression library" developed by Apple Inc, - that also uses the "BSD 3-clause License". - 2) ZSTD data decompression. - C/ZstdDec.c - that code was developed using original zstd decoder code as reference code. - The original zstd decoder code was developed by Facebook Inc, - that also uses the "BSD 3-clause License". - - Copyright (c) 2015-2016, Apple Inc. All rights reserved. - Copyright (c) Facebook, Inc. All rights reserved. - Copyright (c) 2023-2024 Igor Pavlov. - -Text of the "BSD 3-clause License" ----------------------------------- - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---- - - - - -BSD 2-clause License in 7-Zip code ----------------------------------- - - The "BSD 2-clause License" is used for the XXH64 code in 7-Zip. - C/Xxh64.c - - XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet. - - Copyright (c) 2012-2021 Yann Collet. - Copyright (c) 2023-2024 Igor Pavlov. - -Text of the "BSD 2-clause License" ----------------------------------- - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---- - - - - -unRAR license restriction -------------------------- - -The decompression engine for RAR archives was developed using source -code of unRAR program. -All copyrights to original unRAR code are owned by Alexander Roshal. - -The license for original unRAR code has the following restriction: - - The unRAR sources cannot be used to re-create the RAR compression algorithm, - which is proprietary. Distribution of modified unRAR sources in separate form - or as a part of other software is permitted, provided that it is clearly - stated in the documentation and source comments that the code may - not be used to develop a RAR (WinRAR) compatible archiver. - --- + 7-Zip source code + ~~~~~~~~~~~~~~~~~ + License for use and distribution + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 7-Zip Copyright (C) 1999-2024 Igor Pavlov. + + The licenses for files are: + + - CPP/7zip/Compress/Rar* files: the "GNU LGPL" with "unRAR license restriction" + - CPP/7zip/Compress/LzfseDecoder.cpp: the "BSD 3-clause License" + - C/ZstdDec.c: the "BSD 3-clause License" + - C/Xxh64.c: the "BSD 2-clause License" + - Some files are "public domain" files, if "public domain" status is stated in source file. + - the "GNU LGPL" for all other files. If there is no license information in + some source file, that file is under the "GNU LGPL". + + The "GNU LGPL" with "unRAR license restriction" means that you must follow both + "GNU LGPL" rules and "unRAR license restriction" rules. + + + + +GNU LGPL information +-------------------- + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, + you can get a copy of the GNU Lesser General Public License from + http://www.gnu.org/ + + + + +BSD 3-clause License in 7-Zip code +---------------------------------- + + The "BSD 3-clause License" is used for the following code in 7z.dll + 1) LZFSE data decompression. + CPP/7zip/Compress/LzfseDecoder.cpp. + That code was derived from the code in the "LZFSE compression library" developed by Apple Inc, + that also uses the "BSD 3-clause License". + 2) ZSTD data decompression. + C/ZstdDec.c + that code was developed using original zstd decoder code as reference code. + The original zstd decoder code was developed by Facebook Inc, + that also uses the "BSD 3-clause License". + + Copyright (c) 2015-2016, Apple Inc. All rights reserved. + Copyright (c) Facebook, Inc. All rights reserved. + Copyright (c) 2023-2024 Igor Pavlov. + +Text of the "BSD 3-clause License" +---------------------------------- + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + + + + +BSD 2-clause License in 7-Zip code +---------------------------------- + + The "BSD 2-clause License" is used for the XXH64 code in 7-Zip. + C/Xxh64.c + + XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet. + + Copyright (c) 2012-2021 Yann Collet. + Copyright (c) 2023-2024 Igor Pavlov. + +Text of the "BSD 2-clause License" +---------------------------------- + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + + + + +unRAR license restriction +------------------------- + +The decompression engine for RAR archives was developed using source +code of unRAR program. +All copyrights to original unRAR code are owned by Alexander Roshal. + +The license for original unRAR code has the following restriction: + + The unRAR sources cannot be used to re-create the RAR compression algorithm, + which is proprietary. Distribution of modified unRAR sources in separate form + or as a part of other software is permitted, provided that it is clearly + stated in the documentation and source comments that the code may + not be used to develop a RAR (WinRAR) compatible archiver. + +-- diff --git a/DOC/Methods.txt b/DOC/Methods.txt index b840b55d2..3e5707c73 100644 --- a/DOC/Methods.txt +++ b/DOC/Methods.txt @@ -1,177 +1,177 @@ -7-Zip method IDs for 7z and xz archives ---------------------------------------- - -Version: 24.02 -Date: 2024-03-22 - -Each compression or crypto method in 7z is associated with unique binary value (ID). -The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes). - -xz and 7z formats use same ID map. - -If you want to add some new ID, you have two ways: - 1) Write request for allocating IDs to 7-Zip developers. - 2) Generate 8-bytes ID: - - 3F ZZ ZZ ZZ ZZ ZZ MM MM - - 3F - Prefix for random IDs (1 byte) - ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes. - - MM MM - Method ID (2 bytes) - - You can notify 7-Zip developers about your Developer ID / Method ID. - - Note: Use new ID, if old codec can not decode data encoded with new version. - - -List of defined IDs -------------------- - -00 - Copy - -03 - Delta -04 - BCJ (x86) -05 - PPC (big-endian) -06 - IA64 -07 - ARM (little-endian) -08 - ARMT (little-endian) -09 - SPARC -0A - ARM64 -0B - RISCV - -21 - LZMA2 - -02.. - Common - 03 [Swap] - - 2 Swap2 - - 4 Swap4 - -03.. - 7z - 01 - - 01 - LZMA - - 03 - [Branch Codecs] - 01 - [x86 Codecs] - 03 - BCJ - 1B - BCJ2 (4 packed streams) - 02 - - 05 - PPC (big-endian) - 03 - - 01 - Alpha - 04 - - 01 - IA64 - 05 - - 01 - ARM (little-endian) - 06 - - 05 - M68 (big-endian) - 07 - - 01 - ARMT (little-endian) - 08 - - 05 - SPARC - - 04 - - 01 - PPMD - - 7F - - 01 - experimental method. - - -04.. - Misc codecs - - 00 - Reserved - - 01 - [Zip] - 00 - Copy (not used. Use {00} instead) - 01 - Shrink - 06 - Implode - 08 - Deflate - 09 - Deflate64 - 0A - Imploding - 0C - BZip2 (not used. Use {040202} instead) - 0E - LZMA (LZMA-zip) - - 5D - ZSTD - 5F - xz - 60 - Jpeg - 61 - WavPack - 62 - PPMd (PPMd-zip) - 63 - wzAES - - 02 - - 02 - BZip2 - - 03 - [Rar] - 01 - Rar1 - 02 - Rar2 - 03 - Rar3 - 05 - Rar5 - - 04 - [Arj] - 01 - Arj(1,2,3) - 02 - Arj4 - - 05 - [Z] - - 06 - [Lzh] - - 07 - Reserved for 7z - - 08 - [Cab] - - 09 - [NSIS] - 01 - DeflateNSIS - 02 - BZip2NSIS - - F7 - External codecs (that are not included to 7-Zip) - - 0x xx - reserved - - 10 xx - reserved (LZHAM) - 01 - LZHAM - - 11 xx - reserved (Tino Reichardt) - 01 - ZSTD - 02 - BROTLI - 04 - LZ4 - 05 - LZ5 - 06 - LIZARD - - 12 xx - reserverd (Denis Anisimov) - - 01 - WavPack2 - FE - eSplitter - FF - RawSplitter - - -06.. - Crypto - - F0 - Ciphers without hashing algo - - 01 - [AES] - 0x - AES-128 - 4x - AES-192 - 8x - AES-256 - Cx - AES - - x0 - ECB - x1 - CBC - x2 - CFB - x3 - OFB - x4 - CTR - - F1 - Combine Ciphers - - 01 - [Zip] - 01 - ZipCrypto (Main Zip crypto algo) - - 03 - [RAR] - 02 - - 03 - Rar29AES (AES-128 + modified SHA-1) - - 07 - [7z] - 01 - 7zAES (AES-256 + SHA-256) - - ---- -End of document +7-Zip method IDs for 7z and xz archives +--------------------------------------- + +Version: 24.02 +Date: 2024-03-22 + +Each compression or crypto method in 7z is associated with unique binary value (ID). +The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes). + +xz and 7z formats use same ID map. + +If you want to add some new ID, you have two ways: + 1) Write request for allocating IDs to 7-Zip developers. + 2) Generate 8-bytes ID: + + 3F ZZ ZZ ZZ ZZ ZZ MM MM + + 3F - Prefix for random IDs (1 byte) + ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes. + + MM MM - Method ID (2 bytes) + + You can notify 7-Zip developers about your Developer ID / Method ID. + + Note: Use new ID, if old codec can not decode data encoded with new version. + + +List of defined IDs +------------------- + +00 - Copy + +03 - Delta +04 - BCJ (x86) +05 - PPC (big-endian) +06 - IA64 +07 - ARM (little-endian) +08 - ARMT (little-endian) +09 - SPARC +0A - ARM64 +0B - RISCV + +21 - LZMA2 + +02.. - Common + 03 [Swap] + - 2 Swap2 + - 4 Swap4 + +03.. - 7z + 01 - + 01 - LZMA + + 03 - [Branch Codecs] + 01 - [x86 Codecs] + 03 - BCJ + 1B - BCJ2 (4 packed streams) + 02 - + 05 - PPC (big-endian) + 03 - + 01 - Alpha + 04 - + 01 - IA64 + 05 - + 01 - ARM (little-endian) + 06 - + 05 - M68 (big-endian) + 07 - + 01 - ARMT (little-endian) + 08 - + 05 - SPARC + + 04 - + 01 - PPMD + + 7F - + 01 - experimental method. + + +04.. - Misc codecs + + 00 - Reserved + + 01 - [Zip] + 00 - Copy (not used. Use {00} instead) + 01 - Shrink + 06 - Implode + 08 - Deflate + 09 - Deflate64 + 0A - Imploding + 0C - BZip2 (not used. Use {040202} instead) + 0E - LZMA (LZMA-zip) + + 5D - ZSTD + 5F - xz + 60 - Jpeg + 61 - WavPack + 62 - PPMd (PPMd-zip) + 63 - wzAES + + 02 - + 02 - BZip2 + + 03 - [Rar] + 01 - Rar1 + 02 - Rar2 + 03 - Rar3 + 05 - Rar5 + + 04 - [Arj] + 01 - Arj(1,2,3) + 02 - Arj4 + + 05 - [Z] + + 06 - [Lzh] + + 07 - Reserved for 7z + + 08 - [Cab] + + 09 - [NSIS] + 01 - DeflateNSIS + 02 - BZip2NSIS + + F7 - External codecs (that are not included to 7-Zip) + + 0x xx - reserved + + 10 xx - reserved (LZHAM) + 01 - LZHAM + + 11 xx - reserved (Tino Reichardt) + 01 - ZSTD + 02 - BROTLI + 04 - LZ4 + 05 - LZ5 + 06 - LIZARD + + 12 xx - reserverd (Denis Anisimov) + + 01 - WavPack2 + FE - eSplitter + FF - RawSplitter + + +06.. - Crypto + + F0 - Ciphers without hashing algo + + 01 - [AES] + 0x - AES-128 + 4x - AES-192 + 8x - AES-256 + Cx - AES + + x0 - ECB + x1 - CBC + x2 - CFB + x3 - OFB + x4 - CTR + + F1 - Combine Ciphers + + 01 - [Zip] + 01 - ZipCrypto (Main Zip crypto algo) + + 03 - [RAR] + 02 - + 03 - Rar29AES (AES-128 + modified SHA-1) + + 07 - [7z] + 01 - 7zAES (AES-256 + SHA-256) + + +--- +End of document diff --git a/DOC/copying.txt b/DOC/copying.txt index 3394995ab..4362b4915 100644 --- a/DOC/copying.txt +++ b/DOC/copying.txt @@ -1,502 +1,502 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/DOC/lzma.txt b/DOC/lzma.txt index 62cf09455..166bc3b59 100644 --- a/DOC/lzma.txt +++ b/DOC/lzma.txt @@ -1,345 +1,345 @@ -LZMA compression ----------------- -Version: 24.07 - -This file describes LZMA encoding and decoding functions written in C language. - -LZMA is an improved version of famous LZ77 compression algorithm. -It was improved in way of maximum increasing of compression ratio, -keeping high decompression speed and low memory requirements for -decompressing. - -Note: you can read also LZMA Specification (lzma-specification.txt from LZMA SDK) - -Also you can look source code for LZMA encoding and decoding: - C/Util/Lzma/LzmaUtil.c - - -LZMA compressed file format ---------------------------- -Offset Size Description - 0 1 Special LZMA properties (lc,lp, pb in encoded form) - 1 4 Dictionary size (little endian) - 5 8 Uncompressed size (little endian). -1 means unknown size - 13 Compressed data - - - -ANSI-C LZMA Decoder -~~~~~~~~~~~~~~~~~~~ - -Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. -If you want to use old interfaces you can download previous version of LZMA SDK -from sourceforge.net site. - -To use ANSI-C LZMA Decoder you need the following files: -1) LzmaDec.h + LzmaDec.c + 7zTypes.h + Precomp.h + Compiler.h - -Look example code: - C/Util/Lzma/LzmaUtil.c - - -Memory requirements for LZMA decoding -------------------------------------- - -Stack usage of LZMA decoding function for local variables is not -larger than 200-400 bytes. - -LZMA Decoder uses dictionary buffer and internal state structure. -Internal state structure consumes - state_size = (4 + (1.5 << (lc + lp))) KB -by default (lc=3, lp=0), state_size = 16 KB. - - -How To decompress data ----------------------- - -LZMA Decoder (ANSI-C version) now supports 2 interfaces: -1) Single-call Decompressing -2) Multi-call State Decompressing (zlib-like interface) - -You must use external allocator: -Example: -void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } -void SzFree(void *p, void *address) { p = p; free(address); } -ISzAlloc alloc = { SzAlloc, SzFree }; - -You can use p = p; operator to disable compiler warnings. - - -Single-call Decompressing -------------------------- -When to use: RAM->RAM decompressing -Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h -Compile defines: no defines -Memory Requirements: - - Input buffer: compressed size - - Output buffer: uncompressed size - - LZMA Internal Structures: state_size (16 KB for default settings) - -Interface: - int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, - const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, - ELzmaStatus *status, ISzAlloc *alloc); - In: - dest - output data - destLen - output data size - src - input data - srcLen - input data size - propData - LZMA properties (5 bytes) - propSize - size of propData buffer (5 bytes) - finishMode - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). - You can use LZMA_FINISH_END, when you know that - current output buffer covers last bytes of stream. - alloc - Memory allocator. - - Out: - destLen - processed output size - srcLen - processed input size - - Output: - SZ_OK - status: - LZMA_STATUS_FINISHED_WITH_MARK - LZMA_STATUS_NOT_FINISHED - LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK - SZ_ERROR_DATA - Data error - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_UNSUPPORTED - Unsupported properties - SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). - - If LZMA decoder sees end_marker before reaching output limit, it returns OK result, - and output value of destLen will be less than output buffer size limit. - - You can use multiple checks to test data integrity after full decompression: - 1) Check Result and "status" variable. - 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. - 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. - You must use correct finish mode in that case. */ - - -Multi-call State Decompressing (zlib-like interface) ----------------------------------------------------- - -When to use: file->file decompressing -Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h - -Memory Requirements: - - Buffer for input stream: any size (for example, 16 KB) - - Buffer for output stream: any size (for example, 16 KB) - - LZMA Internal Structures: state_size (16 KB for default settings) - - LZMA dictionary (dictionary size is encoded in LZMA properties header) - -1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: - unsigned char header[LZMA_PROPS_SIZE + 8]; - ReadFile(inFile, header, sizeof(header) - -2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties - - CLzmaDec state; - LzmaDec_Constr(&state); - res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); - if (res != SZ_OK) - return res; - -3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop - - LzmaDec_Init(&state); - for (;;) - { - ... - int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); - ... - } - - -4) Free all allocated structures - LzmaDec_Free(&state, &g_Alloc); - -Look example code: - C/Util/Lzma/LzmaUtil.c - - -How To compress data --------------------- - -Compile files: - 7zTypes.h - Threads.h - Threads.c - LzmaEnc.h - LzmaEnc.c - LzFind.h - LzFind.c - LzFindMt.h - LzFindMt.c - LzFindOpt.c - LzHash.h - -Memory Requirements: - - (dictSize * 11.5 + 6 MB) + state_size - -Lzma Encoder can use two memory allocators: -1) alloc - for small arrays. -2) allocBig - for big arrays. - -For example, you can use Large RAM Pages (2 MB) in allocBig allocator for -better compression speed. Note that Windows has bad implementation for -Large RAM Pages. -It's OK to use same allocator for alloc and allocBig. - - -Single-call Compression with callbacks --------------------------------------- - -Look example code: - C/Util/Lzma/LzmaUtil.c - -When to use: file->file compressing - -1) you must implement callback structures for interfaces: -ISeqInStream -ISeqOutStream -ICompressProgress -ISzAlloc - -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - - CFileSeqInStream inStream; - CFileSeqOutStream outStream; - - inStream.funcTable.Read = MyRead; - inStream.file = inFile; - outStream.funcTable.Write = MyWrite; - outStream.file = outFile; - - -2) Create CLzmaEncHandle object; - - CLzmaEncHandle enc; - - enc = LzmaEnc_Create(&g_Alloc); - if (enc == 0) - return SZ_ERROR_MEM; - - -3) initialize CLzmaEncProps properties; - - LzmaEncProps_Init(&props); - - Then you can change some properties in that structure. - -4) Send LZMA properties to LZMA Encoder - - res = LzmaEnc_SetProps(enc, &props); - -5) Write encoded properties to header - - Byte header[LZMA_PROPS_SIZE + 8]; - size_t headerSize = LZMA_PROPS_SIZE; - UInt64 fileSize; - int i; - - res = LzmaEnc_WriteProperties(enc, header, &headerSize); - fileSize = MyGetFileLength(inFile); - for (i = 0; i < 8; i++) - header[headerSize++] = (Byte)(fileSize >> (8 * i)); - MyWriteFileAndCheck(outFile, header, headerSize) - -6) Call encoding function: - res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, - NULL, &g_Alloc, &g_Alloc); - -7) Destroy LZMA Encoder Object - LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); - - -If callback function return some error code, LzmaEnc_Encode also returns that code -or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. - - -Single-call RAM->RAM Compression --------------------------------- - -Single-call RAM->RAM Compression is similar to Compression with callbacks, -but you provide pointers to buffers instead of pointers to stream callbacks: - -SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, - const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, - ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); - -Return code: - SZ_OK - OK - SZ_ERROR_MEM - Memory allocation error - SZ_ERROR_PARAM - Incorrect paramater - SZ_ERROR_OUTPUT_EOF - output buffer overflow - SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) - - - -Defines -------- - -Z7_LZMA_SIZE_OPT - Enable some code size optimizations in LZMA Decoder to get smaller executable code. - -Z7_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for - some structures will be doubled in that case. - -Z7_DECL_Int32_AS_long - Define it if int is 16-bit on your compiler and long is 32-bit. - -Z7_DECL_SizeT_AS_unsigned_int - Define it if you don't want to use size_t type. - - -Defines for 7z decoder written in C ------------------------------------ -These defines are for 7zDec.c only (the decoder in C). -C++ 7z decoder doesn't uses these macros. - -Z7_PPMD_SUPPORT - define it if you need PPMD method support. -Z7_NO_METHODS_FILTERS - do not use filters (except of BCJ2 filter). -Z7_USE_NATIVE_BRANCH_FILTER - use filter for native ISA: - use x86 filter, if compiled to x86 executable, - use arm64 filter, if compiled to arm64 executable. - - -C++ LZMA Encoder/Decoder -~~~~~~~~~~~~~~~~~~~~~~~~ -C++ LZMA code use COM-like interfaces. So if you want to use it, -you can study basics of COM/OLE. -C++ LZMA code is just wrapper over ANSI-C code. - - -C++ Notes -~~~~~~~~~~~~~~~~~~~~~~~~ -If you use some C++ code folders in 7-Zip (for example, C++ code for 7z archive handling), -you must check that you correctly work with "new" operator. -7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. -So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator, -if compiled by old MSVC compilers (MSVC before version VS 2010): - -operator new(size_t size) -{ - void *p = ::malloc(size); - if (!p) - throw CNewException(); - return p; -} - -If the compiler is VS 2010 or newer, NewHandler.cpp doesn't redefine "new" operator. -Sp if you use new compiler (VS 2010 or newer), you still can include "NewHandler.cpp" -to compilation, and it will not redefine operator new. -Also you can compile without "NewHandler.cpp" with new compilers. -If 7-zip doesn't redefine operator "new", standard exception will be used instead of CNewException. -Some code of 7-Zip catches any exception in internal code and converts it to HRESULT code. -So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. - ---- - -http://www.7-zip.org -http://www.7-zip.org/sdk.html -http://www.7-zip.org/support.html +LZMA compression +---------------- +Version: 24.07 + +This file describes LZMA encoding and decoding functions written in C language. + +LZMA is an improved version of famous LZ77 compression algorithm. +It was improved in way of maximum increasing of compression ratio, +keeping high decompression speed and low memory requirements for +decompressing. + +Note: you can read also LZMA Specification (lzma-specification.txt from LZMA SDK) + +Also you can look source code for LZMA encoding and decoding: + C/Util/Lzma/LzmaUtil.c + + +LZMA compressed file format +--------------------------- +Offset Size Description + 0 1 Special LZMA properties (lc,lp, pb in encoded form) + 1 4 Dictionary size (little endian) + 5 8 Uncompressed size (little endian). -1 means unknown size + 13 Compressed data + + + +ANSI-C LZMA Decoder +~~~~~~~~~~~~~~~~~~~ + +Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58. +If you want to use old interfaces you can download previous version of LZMA SDK +from sourceforge.net site. + +To use ANSI-C LZMA Decoder you need the following files: +1) LzmaDec.h + LzmaDec.c + 7zTypes.h + Precomp.h + Compiler.h + +Look example code: + C/Util/Lzma/LzmaUtil.c + + +Memory requirements for LZMA decoding +------------------------------------- + +Stack usage of LZMA decoding function for local variables is not +larger than 200-400 bytes. + +LZMA Decoder uses dictionary buffer and internal state structure. +Internal state structure consumes + state_size = (4 + (1.5 << (lc + lp))) KB +by default (lc=3, lp=0), state_size = 16 KB. + + +How To decompress data +---------------------- + +LZMA Decoder (ANSI-C version) now supports 2 interfaces: +1) Single-call Decompressing +2) Multi-call State Decompressing (zlib-like interface) + +You must use external allocator: +Example: +void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); } +void SzFree(void *p, void *address) { p = p; free(address); } +ISzAlloc alloc = { SzAlloc, SzFree }; + +You can use p = p; operator to disable compiler warnings. + + +Single-call Decompressing +------------------------- +When to use: RAM->RAM decompressing +Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h +Compile defines: no defines +Memory Requirements: + - Input buffer: compressed size + - Output buffer: uncompressed size + - LZMA Internal Structures: state_size (16 KB for default settings) + +Interface: + int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size + propData - LZMA properties (5 bytes) + propSize - size of propData buffer (5 bytes) + finishMode - It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + You can use LZMA_FINISH_END, when you know that + current output buffer covers last bytes of stream. + alloc - Memory allocator. + + Out: + destLen - processed output size + srcLen - processed input size + + Output: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). + + If LZMA decoder sees end_marker before reaching output limit, it returns OK result, + and output value of destLen will be less than output buffer size limit. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + + +Multi-call State Decompressing (zlib-like interface) +---------------------------------------------------- + +When to use: file->file decompressing +Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h + +Memory Requirements: + - Buffer for input stream: any size (for example, 16 KB) + - Buffer for output stream: any size (for example, 16 KB) + - LZMA Internal Structures: state_size (16 KB for default settings) + - LZMA dictionary (dictionary size is encoded in LZMA properties header) + +1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header: + unsigned char header[LZMA_PROPS_SIZE + 8]; + ReadFile(inFile, header, sizeof(header) + +2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties + + CLzmaDec state; + LzmaDec_Constr(&state); + res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc); + if (res != SZ_OK) + return res; + +3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop + + LzmaDec_Init(&state); + for (;;) + { + ... + int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); + ... + } + + +4) Free all allocated structures + LzmaDec_Free(&state, &g_Alloc); + +Look example code: + C/Util/Lzma/LzmaUtil.c + + +How To compress data +-------------------- + +Compile files: + 7zTypes.h + Threads.h + Threads.c + LzmaEnc.h + LzmaEnc.c + LzFind.h + LzFind.c + LzFindMt.h + LzFindMt.c + LzFindOpt.c + LzHash.h + +Memory Requirements: + - (dictSize * 11.5 + 6 MB) + state_size + +Lzma Encoder can use two memory allocators: +1) alloc - for small arrays. +2) allocBig - for big arrays. + +For example, you can use Large RAM Pages (2 MB) in allocBig allocator for +better compression speed. Note that Windows has bad implementation for +Large RAM Pages. +It's OK to use same allocator for alloc and allocBig. + + +Single-call Compression with callbacks +-------------------------------------- + +Look example code: + C/Util/Lzma/LzmaUtil.c + +When to use: file->file compressing + +1) you must implement callback structures for interfaces: +ISeqInStream +ISeqOutStream +ICompressProgress +ISzAlloc + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + + CFileSeqInStream inStream; + CFileSeqOutStream outStream; + + inStream.funcTable.Read = MyRead; + inStream.file = inFile; + outStream.funcTable.Write = MyWrite; + outStream.file = outFile; + + +2) Create CLzmaEncHandle object; + + CLzmaEncHandle enc; + + enc = LzmaEnc_Create(&g_Alloc); + if (enc == 0) + return SZ_ERROR_MEM; + + +3) initialize CLzmaEncProps properties; + + LzmaEncProps_Init(&props); + + Then you can change some properties in that structure. + +4) Send LZMA properties to LZMA Encoder + + res = LzmaEnc_SetProps(enc, &props); + +5) Write encoded properties to header + + Byte header[LZMA_PROPS_SIZE + 8]; + size_t headerSize = LZMA_PROPS_SIZE; + UInt64 fileSize; + int i; + + res = LzmaEnc_WriteProperties(enc, header, &headerSize); + fileSize = MyGetFileLength(inFile); + for (i = 0; i < 8; i++) + header[headerSize++] = (Byte)(fileSize >> (8 * i)); + MyWriteFileAndCheck(outFile, header, headerSize) + +6) Call encoding function: + res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, + NULL, &g_Alloc, &g_Alloc); + +7) Destroy LZMA Encoder Object + LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); + + +If callback function return some error code, LzmaEnc_Encode also returns that code +or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. + + +Single-call RAM->RAM Compression +-------------------------------- + +Single-call RAM->RAM Compression is similar to Compression with callbacks, +but you provide pointers to buffers instead of pointers to stream callbacks: + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) + + + +Defines +------- + +Z7_LZMA_SIZE_OPT - Enable some code size optimizations in LZMA Decoder to get smaller executable code. + +Z7_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for + some structures will be doubled in that case. + +Z7_DECL_Int32_AS_long - Define it if int is 16-bit on your compiler and long is 32-bit. + +Z7_DECL_SizeT_AS_unsigned_int - Define it if you don't want to use size_t type. + + +Defines for 7z decoder written in C +----------------------------------- +These defines are for 7zDec.c only (the decoder in C). +C++ 7z decoder doesn't uses these macros. + +Z7_PPMD_SUPPORT - define it if you need PPMD method support. +Z7_NO_METHODS_FILTERS - do not use filters (except of BCJ2 filter). +Z7_USE_NATIVE_BRANCH_FILTER - use filter for native ISA: + use x86 filter, if compiled to x86 executable, + use arm64 filter, if compiled to arm64 executable. + + +C++ LZMA Encoder/Decoder +~~~~~~~~~~~~~~~~~~~~~~~~ +C++ LZMA code use COM-like interfaces. So if you want to use it, +you can study basics of COM/OLE. +C++ LZMA code is just wrapper over ANSI-C code. + + +C++ Notes +~~~~~~~~~~~~~~~~~~~~~~~~ +If you use some C++ code folders in 7-Zip (for example, C++ code for 7z archive handling), +you must check that you correctly work with "new" operator. +7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator. +So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator, +if compiled by old MSVC compilers (MSVC before version VS 2010): + +operator new(size_t size) +{ + void *p = ::malloc(size); + if (!p) + throw CNewException(); + return p; +} + +If the compiler is VS 2010 or newer, NewHandler.cpp doesn't redefine "new" operator. +Sp if you use new compiler (VS 2010 or newer), you still can include "NewHandler.cpp" +to compilation, and it will not redefine operator new. +Also you can compile without "NewHandler.cpp" with new compilers. +If 7-zip doesn't redefine operator "new", standard exception will be used instead of CNewException. +Some code of 7-Zip catches any exception in internal code and converts it to HRESULT code. +So you don't need to catch CNewException, if you call COM interfaces of 7-Zip. + +--- + +http://www.7-zip.org +http://www.7-zip.org/sdk.html +http://www.7-zip.org/support.html diff --git a/DOC/readme.txt b/DOC/readme.txt index 866d6102c..ad1d84234 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt @@ -1,273 +1,282 @@ -7-Zip 24.07 Sources -------------------- - -7-Zip is a file archiver for Windows. - -7-Zip Copyright (C) 1999-2024 Igor Pavlov. - - -License Info ------------- - -7-Zip is free software distributed under the GNU LGPL -(except for unRar code). Also some code -is licensed under the "BSD 3-clause License". -Read "License.txt" for more infomation about license. - -Notes about unRAR license: - -Please check main restriction from unRar license: - - 2. The unRAR sources may be used in any software to handle RAR - archives without limitations free of charge, but cannot be used - to re-create the RAR compression algorithm, which is proprietary. - Distribution of modified unRAR sources in separate form or as a - part of other software is permitted, provided that it is clearly - stated in the documentation and source comments that the code may - not be used to develop a RAR (WinRAR) compatible archiver. - -In brief it means: -1) You can compile and use compiled files under GNU LGPL rules, since - unRAR license almost has no restrictions for compiled files. - You can link these compiled files to LGPL programs. -2) You can fix bugs in source code and use compiled fixed version. -3) You can not use unRAR sources to re-create the RAR compression algorithm. - - -LZMA SDK --------- - -This package also contains some files from LZMA SDK -You can download LZMA SDK from: - http://www.7-zip.org/sdk.html -LZMA SDK is written and placed in the public domain by Igor Pavlov. - - -How to compile in Windows -------------------------- - -To compile the sources to Windows binaries you need Visual Studio compiler and/or Windows SDK. -You can use latest Windows Studio 2017/2019/2022 to compile binaries for x86, x64, arm64 and arm platforms. -Also you can use old compilers for some platforms: - x86 : Visual C++ 6.0 with Platform SDK - x64 : Windows Server 2003 R2 Platform SDK - ia64 (itanium) : Windows Server 2003 R2 Platform SDK - arm for Windows CE : Standard SDK for Windows CE 5.0 - -If you use MSVC6, specify also Platform SDK directories at top of directories lists: -Tools / Options / Directories - - Include files - - Library files - -Also you need Microsoft Macro Assembler: - - ml.exe for x86 - - ml64.exe for x64 -You can use ml.exe from Windows SDK for Windows Vista or some later versions. - -There are two ways to compile 7-Zip binaries: -1) via makefile in command line. -2) via dsp file in Visual Studio. - -The dsp file compiling can be used for development and debug purposes. -All final 7-Zip binaries are compiled via makefiles, that provide best -optimization options. - - -How to compile with makefile ----------------------------- - -Some macronames can be defined for compiling with makefile: - -PLATFORM - with possible values: x64, x86, arm64, arm, ia64 - -OLD_COMPILER - for old VC compiler, like MSCV 6.0. - -MY_DYNAMIC_LINK - for dynamic linking to the run-time library (msvcrt.dll). - The default makefile option is static linking to the run-time library. - - - -Compiling 7-Zip for Unix/Linux ------------------------------- - -There are several options to compile 7-Zip with different compilers: gcc and clang. -Also 7-Zip code contains two versions for some parts of code: in C and in Assembeler. -So if you compile the version with Assembeler code, you will get faster 7-Zip binary. - -7-Zip's assembler code uses the following syntax for different platforms: - -1) x86 and x86-64 (AMD64): MASM syntax. - There are 2 programs that supports MASM syntax in Linux. -' 'Asmc Macro Assembler and JWasm. But JWasm now doesn't support some - cpu instructions used in 7-Zip. - So you must install Asmc Macro Assembler in Linux, if you want to compile fastest version - of 7-Zip x86 and x86-64: - https://github.com/nidud/asmc - -2) arm64: GNU assembler for ARM64 with preprocessor. - That systax is supported by GCC and CLANG for ARM64. - -There are different binaries that can be compiled from 7-Zip source. -There are 2 main files in folder for compiling: - makefile - that can be used for compiling Windows version of 7-Zip with nmake command - makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip or Windows version - with MINGW (GCC) with make command. - -At first you must change the current folder to folder that contains `makefile.gcc`: - - cd CPP/7zip/Bundles/Alone2 - -Then you can compile `makefile.gcc` with the command: - - make -j -f makefile.gcc - -Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile -7-Zip binaries with optimized code and optimzing options. - -To compile with GCC without assembler: - cd CPP/7zip/Bundles/Alone2 - make -j -f ../../cmpl_gcc.mak - -To compile with CLANG without assembler: - make -j -f ../../cmpl_clang.mak - -To compile 7-Zip for x86-64 with asmc assembler: - make -j -f ../../cmpl_gcc_x64.mak - -To compile 7-Zip for arm64 with assembler: - make -j -f ../../cmpl_gcc_arm64.mak - -To compile 7-Zip for arm64 for macOS: - make -j -f ../../cmpl_mac_arm64.mak - -Also you can change some compiler options in the "mak" files: - cmpl_gcc.mak - var_gcc.mak - warn_gcc.mak - -makefile.gcc supports some variables that can change compile options - -USE_JWASM=1 - use JWasm assembler instead of Asmc. - Note that JWasm doesn't support AES instructions. So AES code from C version AesOpt.c - will be used instead of assembler code from AesOpt.asm. - -DISABLE_RAR=1 - removes whole RAR related code from compilation. - -DISABLE_RAR_COMPRESS=1 - removes "not fully free" code of RAR decompression codecs from compilation. - -RAR decompression codecs in 7-Zip code has some additional license restrictions, -that can be treated as not fully compatible with free-software licenses. -DISABLE_RAR_COMPRESS=1 allows to exclude such "not-fully-free" RAR code from compilation. -if DISABLE_RAR_COMPRESS=1 is specified, 7-zip will not be able to decompress files -from rar archives, but 7-zip still will be able to open rar archives to get list of -files or to extract files that are stored without compression. -if DISABLE_RAR=1 is specified, 7-zip will not be able to work with RAR archives. - - - -7-Zip and p7zip -=============== -Now there are two different ports of 7-Zip for Linux/macOS: - -1) p7zip - another port of 7-Zip for Linux, made by an independent developer. - The latest version of p7zip now is 16.02, and that p7zip 16.02 is outdated now. - http://sourceforge.net/projects/p7zip/ - -2) 7-Zip for Linux/macOS - this package - it's new code with all changes from latest 7-Zip for Windows. - -These two ports are not identical. -Note also that some Linux specific things can be implemented better in p7zip than in new 7-Zip for Linux. - - - - -Notes: ------- -7-Zip consists of COM modules (DLL files). -But 7-Zip doesn't use standard COM interfaces for creating objects. -Look at -7zip\UI\Client7z folder for example of using DLL files of 7-Zip. -Some DLL files can use other DLL files from 7-Zip. -If you don't like it, you must use standalone version of DLL. -To compile standalone version of DLL you must include all used parts -to project and define some defs. -For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll -that works with 7z format. So you can use such DLL in your project -without additional DLL files. - - -Description of 7-Zip sources package -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -DOC Documentation ---- - readme.txt - Readme file - src-history.txt - Sources history - 7zC.txt - 7z ANSI-C Decoder description - 7zFormat.txt - 7z format description - Methods.txt - Compression method IDs - lzma.txt - LZMA compression description - License.txt - license information - copying.txt - GNU LGPL license - unRarLicense.txt - License for unRAR part of source code - 7zip.wxs - installer script for WIX - 7zip.hhp - html help project file - -Asm - Source code in Assembler : optimized code for CRC, SHA, AES, LZMA decoding. - -C - Source code in C - -CPP - Source code in C++ - -Common common files for C++ projects - -Windows common files for Windows related code - -7zip - - Common Common modules for 7-zip - - Archive files related to archiving - - Bundle Modules that are bundles of other modules (files) - - Alone 7za.exe: Standalone version of 7-Zip console that supports only 7z/xz/cab/zip/gzip/bzip2/tar. - Alone2 7zz.exe: Standalone version of 7-Zip console that supports all formats. - Alone7z 7zr.exe: Standalone version of 7-Zip console that supports only 7z (reduced version) - Fm Standalone version of 7-Zip File Manager - Format7z 7za.dll: .7z support - Format7zExtract 7zxa.dll: .7z support, extracting only - Format7zR 7zr.dll: .7z support, reduced version - Format7zExtractR 7zxr.dll: .7z support, reduced version, extracting only - Format7zF 7z.dll: all formats - LzmaCon lzma.exe: LZMA compression/decompression - SFXCon 7zCon.sfx: Console 7z SFX module - SFXWin 7z.sfx: Windows 7z SFX module - SFXSetup 7zS.sfx: Windows 7z SFX module for Installers - - Compress files for compression / decompression - - Crypto files for encryption / decryption - - UI - - Agent Intermediary modules for FAR plugin and Explorer plugin - Client7z Test application for 7za.dll - Common Common UI files - Console 7z.exe : Console version - Explorer 7-zip.dll: 7-Zip Shell extension - Far plugin for Far Manager - FileManager 7zFM.exe: 7-Zip File Manager - GUI 7zG.exe: 7-Zip GUI version - - - ---- -Igor Pavlov -http://www.7-zip.org +7-Zip 24.09 Sources +------------------- + +7-Zip is a file archiver for Windows. + +7-Zip Copyright (C) 1999-2024 Igor Pavlov. + + +License Info +------------ + +7-Zip is free software distributed under the GNU LGPL +(except for unRar code). Also some code +is licensed under the "BSD 3-clause License". +Read "License.txt" for more infomation about license. + +Notes about unRAR license: + +Please check main restriction from unRar license: + + 2. The unRAR sources may be used in any software to handle RAR + archives without limitations free of charge, but cannot be used + to re-create the RAR compression algorithm, which is proprietary. + Distribution of modified unRAR sources in separate form or as a + part of other software is permitted, provided that it is clearly + stated in the documentation and source comments that the code may + not be used to develop a RAR (WinRAR) compatible archiver. + +In brief it means: +1) You can compile and use compiled files under GNU LGPL rules, since + unRAR license almost has no restrictions for compiled files. + You can link these compiled files to LGPL programs. +2) You can fix bugs in source code and use compiled fixed version. +3) You can not use unRAR sources to re-create the RAR compression algorithm. + + +LZMA SDK +-------- + +This package also contains some files from LZMA SDK +You can download LZMA SDK from: + http://www.7-zip.org/sdk.html +LZMA SDK is written and placed in the public domain by Igor Pavlov. + + +How to compile in Windows +------------------------- + +To compile the sources to Windows binaries you need Visual Studio compiler and/or Windows SDK. +You can use latest Windows Studio 2017/2019/2022 to compile binaries for x86, x64, arm64 and arm platforms. +Also you can use old compilers for some platforms: + x86 : Visual C++ 6.0 with Platform SDK + x64 : Windows Server 2003 R2 Platform SDK + ia64 (itanium) : Windows Server 2003 R2 Platform SDK + arm for Windows CE : Standard SDK for Windows CE 5.0 + +If you use MSVC6, specify also Platform SDK directories at top of directories lists: +Tools / Options / Directories + - Include files + - Library files + +Also you need Microsoft Macro Assembler: + - ml.exe for x86 + - ml64.exe for x64 +You can use ml.exe from Windows SDK for Windows Vista or some later versions. + +There are two ways to compile 7-Zip binaries: +1) via makefile in command line. +2) via dsp file in Visual Studio. + +The dsp file compiling can be used for development and debug purposes. +All final 7-Zip binaries are compiled via makefiles, that provide best +optimization options. + + +How to compile with makefile +---------------------------- + +Some macronames can be defined for compiling with makefile: + +PLATFORM + with possible values: x64, x86, arm64, arm, ia64 + +OLD_COMPILER + for old VC compiler, like MSCV 6.0. + +MY_DYNAMIC_LINK + for dynamic linking to the run-time library (msvcrt.dll). + The default makefile option is static linking to the run-time library. + + + +Compiling 7-Zip for Unix/Linux +------------------------------ + +There are several options to compile 7-Zip with different compilers: gcc and clang. +Also 7-Zip code contains two versions for some parts of code: in C and in Assembeler. +So if you compile the version with Assembeler code, you will get faster 7-Zip binary. + +7-Zip's assembler code uses the following syntax for different platforms: + +1) x86 and x86-64 (AMD64): MASM syntax. + Now there are 3 programs that supports MASM syntax in Linux. +' 'Asmc Macro Assembler, JWasm, and UASM. Note that JWasm now doesn't support some + cpu instructions used in 7-Zip. + So you must install Asmc Macro Assembler in Linux or UASM, if you want to compile + fastest version of 7-Zip x86 and x86-64: + https://github.com/nidud/asmc + https://github.com/Terraspace/UASM + + +2) arm64: GNU assembler for ARM64 with preprocessor. + That systax is supported by GCC and CLANG for ARM64. + +There are different binaries that can be compiled from 7-Zip source. +There are 2 main files in folder for compiling: + makefile - that can be used for compiling Windows version of 7-Zip with nmake command + makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip or Windows version + with MINGW (GCC) with make command. + +At first you must change the current folder to folder that contains `makefile.gcc`: + + cd CPP/7zip/Bundles/Alone2 + +Then you can compile `makefile.gcc` with the command: + + make -j -f makefile.gcc + +Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile +7-Zip binaries with optimized code and optimzing options. + +To compile with GCC without assembler: + cd CPP/7zip/Bundles/Alone2 + make -j -f ../../cmpl_gcc.mak + +To compile with CLANG without assembler: + make -j -f ../../cmpl_clang.mak + +To compile 7-Zip for x86-64 with asmc assembler: + make -j -f ../../cmpl_gcc_x64.mak + +To compile 7-Zip for arm64 with assembler: + make -j -f ../../cmpl_gcc_arm64.mak + +To compile 7-Zip for arm64 for macOS: + make -j -f ../../cmpl_mac_arm64.mak + +Also you can change some compiler options in the "mak" files: + cmpl_gcc.mak + var_gcc.mak + warn_gcc.mak + +makefile.gcc supports some variables that can change compile options + +USE_JWASM=1 + use JWasm assembler instead of Asmc. + Note that JWasm doesn't support AES instructions. So AES code from C version AesOpt.c + will be used instead of assembler code from AesOpt.asm. + +If you want to use UASM for x86-64 compiling, you can change 7zip_gcc.mak, +or send IS_X64=1 USE_ASM=1 MY_ASM="$UASM" to make command calling: + UASM="$PWD/GccUnixR/uasm" + cd "7zip-src/CPP/7zip/Bundles/Alone2" + make -f makefile.gcc -j IS_X64=1 USE_ASM=1 MY_ASM="$UASM" + + +DISABLE_RAR=1 + removes whole RAR related code from compilation. + +DISABLE_RAR_COMPRESS=1 + removes "not fully free" code of RAR decompression codecs from compilation. + +RAR decompression codecs in 7-Zip code has some additional license restrictions, +that can be treated as not fully compatible with free-software licenses. +DISABLE_RAR_COMPRESS=1 allows to exclude such "not-fully-free" RAR code from compilation. +if DISABLE_RAR_COMPRESS=1 is specified, 7-zip will not be able to decompress files +from rar archives, but 7-zip still will be able to open rar archives to get list of +files or to extract files that are stored without compression. +if DISABLE_RAR=1 is specified, 7-zip will not be able to work with RAR archives. + + + +7-Zip and p7zip +=============== +Now there are two different ports of 7-Zip for Linux/macOS: + +1) p7zip - another port of 7-Zip for Linux, made by an independent developer. + The latest version of p7zip now is 16.02, and that p7zip 16.02 is outdated now. + http://sourceforge.net/projects/p7zip/ + +2) 7-Zip for Linux/macOS - this package - it's new code with all changes from latest 7-Zip for Windows. + +These two ports are not identical. +Note also that some Linux specific things can be implemented better in p7zip than in new 7-Zip for Linux. + + + + +Notes: +------ +7-Zip consists of COM modules (DLL files). +But 7-Zip doesn't use standard COM interfaces for creating objects. +Look at +7zip\UI\Client7z folder for example of using DLL files of 7-Zip. +Some DLL files can use other DLL files from 7-Zip. +If you don't like it, you must use standalone version of DLL. +To compile standalone version of DLL you must include all used parts +to project and define some defs. +For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll +that works with 7z format. So you can use such DLL in your project +without additional DLL files. + + +Description of 7-Zip sources package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DOC Documentation +--- + readme.txt - Readme file + src-history.txt - Sources history + 7zC.txt - 7z ANSI-C Decoder description + 7zFormat.txt - 7z format description + Methods.txt - Compression method IDs + lzma.txt - LZMA compression description + License.txt - license information + copying.txt - GNU LGPL license + unRarLicense.txt - License for unRAR part of source code + 7zip.wxs - installer script for WIX + 7zip.hhp - html help project file + +Asm - Source code in Assembler : optimized code for CRC, SHA, AES, LZMA decoding. + +C - Source code in C + +CPP - Source code in C++ + +Common common files for C++ projects + +Windows common files for Windows related code + +7zip + + Common Common modules for 7-zip + + Archive files related to archiving + + Bundle Modules that are bundles of other modules (files) + + Alone 7za.exe: Standalone version of 7-Zip console that supports only 7z/xz/cab/zip/gzip/bzip2/tar. + Alone2 7zz.exe: Standalone version of 7-Zip console that supports all formats. + Alone7z 7zr.exe: Standalone version of 7-Zip console that supports only 7z (reduced version) + Fm Standalone version of 7-Zip File Manager + Format7z 7za.dll: .7z support + Format7zExtract 7zxa.dll: .7z support, extracting only + Format7zR 7zr.dll: .7z support, reduced version + Format7zExtractR 7zxr.dll: .7z support, reduced version, extracting only + Format7zF 7z.dll: all formats + LzmaCon lzma.exe: LZMA compression/decompression + SFXCon 7zCon.sfx: Console 7z SFX module + SFXWin 7z.sfx: Windows 7z SFX module + SFXSetup 7zS.sfx: Windows 7z SFX module for Installers + + Compress files for compression / decompression + + Crypto files for encryption / decryption + + UI + + Agent Intermediary modules for FAR plugin and Explorer plugin + Client7z Test application for 7za.dll + Common Common UI files + Console 7z.exe : Console version + Explorer 7-zip.dll: 7-Zip Shell extension + Far plugin for Far Manager + FileManager 7zFM.exe: 7-Zip File Manager + GUI 7zG.exe: 7-Zip GUI version + + + +--- +Igor Pavlov +http://www.7-zip.org diff --git a/DOC/src-history.txt b/DOC/src-history.txt index 10b2931b7..6b576942a 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt @@ -1,781 +1,804 @@ -HISTORY of the 7-Zip source code --------------------------------- - -24.08 2024-08-11 -------------------------- -- The bug in 7-Zip 24.00-24.07 was fixed: - For creating a zip archive: 7-Zip could write extra zero bytes after the end of the archive, - if a file included to archive cannot be compressed to a size smaller than original. - The created zip archive is correct except for the useless zero bytes after the end of the archive. - When unpacking such a zip archive, 7-Zip displays a warning: - "WARNING: There are data after the end of archive". -- Some bugs were fixed. - - -24.07 2024-06-19 -------------------------- -- Changes in files: - Asm/x86/Sha256Opt.asm - Asm/x86/Sha1Opt.asm - Now it uses "READONLY" flag for constant array segment. - It fixes an issue where ".rodata" section in 7-Zip for x86/x64 Linux had a "WRITE" attribute. -- The bug was fixed: 7-Zip could crash for some incorrect ZSTD archives. - - -24.06 2024-05-26 -------------------------- -- The bug was fixed: 7-Zip could not unpack some ZSTD archives. - - -24.05 2024-05-14 -------------------------- -- New switch -myv={MMNN} to set decoder compatibility version for 7z archive creating. - {MMNN} is 4-digit number that represents the version of 7-Zip without a dot. - If -myv={MMNN} switch is specified, 7-Zip will only use compression methods that can - be decoded by the specified version {MMNN} of 7-Zip and newer versions. - If -myv={MMNN} switch is not specified, -myv=2300 is used, and 7-Zip will only - use compression methods that can be decoded by 7-Zip 23.00 and newer versions. -- New switch -myfa={FilterID} to allow 7-Zip to use the specified filter method for 7z archive creating. -- New switch -myfd={FilterID} to disallow 7-Zip to use the specified filter method for 7z archive creating. - - -24.03 2024-03-23 -------------------------- -- 7-Zip now can use new RISCV filter for compression to 7z and xz archives. - RISCV filter can increase compression ratio for data containing executable - files compiled for RISC-V architecture. -- The speed for LZMA and LZMA2 decompression in ARM64 version for Windows - was increased by 20%-60%. - It uses arm64 assembler code, and clang-cl is required for arm64 assembler code compiling. -- Some bugs were fixed. - - -24.01 2024-01-31 -------------------------- -- 7-Zip uses file C/Precomp.h that is included to all c and c++ files. - CPP/Common/Common.h also includes C/Precomp.h. - C/Precomp.h defines the following macros (if _WIN32 is defined): - Z7_LARGE_PAGES 1 - Z7_LONG_PATH 1 - Z7_WIN32_WINNT_MIN 0x0500 (or higher) - _WIN32_WINNT 0x0500 (or higher) - WINVER _WIN32_WINNT - UNICODE 1 - _UNICODE 1 - if _WIN32_WINNT is defined already, C/Precomp.h doesn't redefine it. - -- 7-Zip now can unpack ZSTD archives (.zst extension). -- 7-Zip now can unpack ZIP and SquashFS archives that use ZSTD compression method. -- 7-Zip now supports fast hash algorithm XXH64 that is used in ZSTD. -- Speed optimizations for archive unpacking: rar, zip, gz, wim, cab. -- Speed optimizations for hash caclulation: CRC-32, CRC-64, Blake2sp. -- The bug was fixed: 7-Zip for Linux could fail for multivolume creation in some cases. -- Some bugs were fixed. - - -23.01 2023-06-20 -------------------------- -- All external macros for compiling C/C++ code of 7-Zip now have Z7_ prefix. -- 7-Zip COM interfaces now use new macros that allow to declare and implement COM interface. -- The code has been modified to compile with the maximum diagnostic warning level: - -Wall in MSVC and -Weverything in CLANG. - And some warning types are disabled in 2 files: - - C/Compiler.h for C/C++ code warnings. - - CPP/Common/Common.h for C++ code warnings. -- Linux/macOS versions of 7-Zip: IUnknown interface in new code doesn't use - virtual destructor that was used in previous 7-Zip and p7zip: - // virtual ~IUnknown() {} - So 7-Zip's dynamically linked shared libraries (codecs) are not compatible - between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip). -- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers. -- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp - files in system's TEMP folder. 7-Zip uses temp file for additional compressed - data stream, if size of such compressed stream is larger than predefined limit: - 16 MiB in 32-bit version, 4 GiB in 64-bit version. -- Some bugs were fixed. - - -22.00 2022-06-16 -------------------------- -- 7-Zip interfaces now support high precision (1 ns) timestamps with reserved - fields of tagPROPVARIANT (VT_FILETIME). - - -21.07 2021-12-26 -------------------------- -- The sorting order of files in archives was slightly changed to be more consistent - for cases where the name of some directory is the same as the prefix part of the name - of another directory or file. -- TAR archives created by 7-Zip now are more consistent with archives created by GNU TAR program. - - -21.06 2021-11-24 -------------------------- -- Bug in LZMA encoder in file LzmaEnc.c was fixed: - LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly, - if size value for output buffer is smaller than size required for all compressed data. - LzmaEnc_Encode() could work incorrectly, - if callback ISeqOutStream::Write() doesn't write all compressed data. - NCompress::NLzma::CEncoder::Code() could work incorrectly, - if callback ISequentialOutStream::Write() returns error code. -- Bug in versions 21.00-21.05 was fixed: - 7-Zip didn't set attributes of directories during archive extracting. - - -21.04 beta 2021-11-02 -------------------------- -- 7-Zip now reduces the number of working CPU threads for compression, - if RAM size is not enough for compression with big LZMA2 dictionary. -- 7-Zip now can create and check "file.sha256" and "file.sha1" text files - that contain the list of file names and SHA-1 / SHA-256 checksums in format - compatible with sha1sum/sha256sum programs. - - -21.03 beta 2021-07-20 -------------------------- -- The maximum dictionary size for LZMA/LZMA2 compressing was increased to 4 GB (3840 MiB). -- Minor speed optimizations in LZMA/LZMA2 compressing. - - -21.02 alpha 2021-05-06 -------------------------- -- 7-Zip now writes additional field for filename in UTF-8 encoding to zip archives. - It allows to extract correct file name from zip archives on different systems. -- The command line version of 7-Zip for macOS was released. -- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux - was increased by 20%-60%. -- Some changes and improvements in ZIP, TAR and NSIS code. - - -21.01 alpha 2021-03-09 -------------------------- -- The command line version of 7-Zip for Linux was released. -- The improvements for speed of ARM64 version using hardware CPU instructions - for AES, CRC-32, SHA-1 and SHA-256. -- The bug in versions 18.02 - 21.00 was fixed: - 7-Zip could not correctly extract some ZIP archives created with xz compression method. -- Some bugs were fixed. - - -20.02 alpha 2020-08-08 -------------------------- -- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64. - It allows to increase the compression speed for big 7z archives, if there is a big number - of CPU cores and threads. -- The speed of PPMd compressing/decompressing was increased for 7z/ZIP/RAR archives. -- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system - to modify "Last Access Time" property of source files for archiving and hashing operations. -- Some bugs were fixed. - - -20.00 alpha 2020-02-06 -------------------------- -- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5, - that can work faster than bt4 and hc4 match finders for the data with big redundancy. -- The compression ratio was improved for Fast and Fastest compression levels with the - following default settings: - - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary. - - Fast level (-mx3) : hc5 match finder with 4 MB dictionary. -- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra - compression levels. -- bzip2 decoding code was updated to support bzip2 archives, created by lbzip2 program. - - -19.02 2019-09-05 -------------------------- -- Support for SHA-1/SHA-256 optimized code in - Sha1Opt.c, Sha256Opt.c, Sha256Opt.asm, Sha1Opt.asm. - - -19.00 2019-02-21 -------------------------- -- Encryption strength for 7z archives was increased: - the size of random initialization vector was increased from 64-bit to 128-bit, - and the pseudo-random number generator was improved. -- Some bugs were fixed. - - -18.06 2018-12-30 -------------------------- -- The speed for LZMA/LZMA2 compressing was increased by 3-10%, - and there are minor changes in compression ratio. -- Some bugs were fixed. -- The bug in 7-Zip 18.02-18.05 was fixed: - There was memory leak in multithreading xz decoder - XzDecMt_Decode(), - if xz stream contains only one block. -- 7-Zip 18.02-18.05 used only one CPU thread for bz2 archive creation. -- The changes for MSVS compiler makefiles: - - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64) - instead of "CPU" macroname with values (AMD64, ARM64). - - the makefiles by default now use static version of the run-time library. - - -18.05 2018-04-30 -------------------------- -- The speed for LZMA/LZMA2 compressing was increased - by 8% for fastest/fast compression levels and - by 3% for normal/maximum compression levels. -- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in - Windows 10 because of some BUG with "Large Pages" in Windows 10. - Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299). - - -18.03 beta 2018-03-04 -------------------------- -- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm - for x64 with about 30% higher speed than main version of LZMA decoder written in C. -- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%. -- 7-Zip now can use multi-threading for 7z/LZMA2 decoding, - if there are multiple independent data chunks in LZMA2 stream. -- 7-Zip now can use multi-threading for xz decoding, - if there are multiple blocks in xz stream. - - -17.00 beta 2017-04-29 -------------------------- -- NewHandler.h / NewHandler.cpp: - now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900). -- C/7zTypes.h : the names of variables in interface structures were changed (vt). -- Some bugs were fixed. 7-Zip could crash in some cases. -- Some internal changes in code. - - -16.02 2016-05-21 -------------------------- -- The BUG in 16.00 - 16.01 was fixed: - Split Handler (SplitHandler.cpp) returned incorrect - total size value (kpidSize) for split archives. - - -16.01 2016-05-19 -------------------------- -- Some bugs were fixed, -- Some internal changes to reduce the number of compiler warnings. - - -16.00 2016-05-10 -------------------------- -- 7-Zip now can extract multivolume ZIP archives (z01, z02, ... , zip). -- Some bugs were fixed, - - -15.12 2015-11-19 -------------------------- -- The BUG in C version of 7z decoder was fixed: - 7zDec.c : SzDecodeLzma2() - 7z decoder could mistakenly report about decoding error for some 7z archives - that use LZMA2 compression method. - The probability to get that mistaken decoding error report was about - one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size). -- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed: - 7zArcIn.c : SzReadHeader2() - 7z decoder worked incorrectly for 7z archives that contain - empty solid blocks, that can be placed to 7z archive, if some file is - unavailable for reading during archive creation. - - -15.09 beta 2015-10-16 -------------------------- -- The BUG in LZMA / LZMA2 encoding code was fixed. - The BUG in LzFind.c::MatchFinder_ReadBlock() function. - If input data size is larger than (4 GiB - dictionary_size), - the following code worked incorrectly: - - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions - for compressing from memory to memory. - That BUG is not related to LZMA encoder version that works via streams. - - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if - default value of chunk size (CLzma2EncProps::blockSize) is changed - to value larger than (4 GiB - dictionary_size). - - -9.38 beta 2015-01-03 -------------------------- -- The BUG in 9.31-9.37 was fixed: - IArchiveGetRawProps interface was disabled for 7z archives. -- The BUG in 9.26-9.36 was fixed: - Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows. - - -9.36 beta 2014-12-26 -------------------------- -- The BUG in command line version was fixed: - 7-Zip created temporary archive in current folder during update archive - operation, if -w{Path} switch was not specified. - The fixed 7-Zip creates temporary archive in folder that contains updated archive. -- The BUG in 9.33-9.35 was fixed: - 7-Zip silently ignored file reading errors during 7z or gz archive creation, - and the created archive contained only part of file that was read before error. - The fixed 7-Zip stops archive creation and it reports about error. - - -9.31 2012-10-31 -------------------------- -- InBuffer.h : CInBuffer uses ISequentialInStream *_stream; instead of CMyComPtr - OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr - - -9.26 2011-04-11 -------------------------- -- The BUG was fixed: multi-threaded ZIP stored file size that was at scan stage, - So if the file was changed after scan, the Unpack Size field was incorrect - - -9.21 2011-04-11 -------------------------- -- New class FString for file names at file systems. -- Speed optimization in CRC code for big-endian CPUs. - - -9.18 2010-11-02 -------------------------- -- New small SFX module for installers (C/Util/SfxSetup). - - -9.17 2010-10-04 -------------------------- -- IStream.h::IOutStream:: - STDMETHOD(SetSize)(Int64 newSize) PURE; - was changed to - STDMETHOD(SetSize)(UInt64 newSize) PURE; - - -9.09 2009-12-12 -------------------------- -- The bug was fixed: - Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c - incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8. - - -9.05 2009-07-05 -------------------------- -- FileMapping.h::CFileMapping now returns WRes - - -9.04 2009-05-30 -------------------------- -- ICoder.h: NCoderPropID::EEnum values were changed - - -9.02 2009-04-23 -------------------------- -- Bug was fixed: if swap2 filter was requests at compression, - 7-zip used swap4 filter instead (but id was swap2), so archives were incorrect. - -4.61 2008-11-23 -------------------------- -- Bug in ver. 4.58+ was fixed: - 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives. -- Bug in .CAB code was fixed. 7-Zip didn't show some empty files, - if .CAB archive contains more than one empty file. - - -4.59 2008-07-27 -------------------------- -- Bug was fixed: - LZMA Encoder in fast compression mode could access memory outside of - allocated range in some rare cases. - - -4.59 alpha 2008-05-30 -------------------------- -- BUGS was fixed: - 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases. - 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties. - -4.58 alpha 9 2008-04-29 -------------------------- -- BUG was fixed: 7-Zip showed incorrect timestamps in ISO files. - - -4.58 alpha 8 2008-04-15 -------------------------- -- BUG in 4.58 alpha 5/6/7 was fixed: - LZMA encoder worked incorrectly, if lp != 0. -- Unicode (UTF-8) support for filenames in .ZIP archives. Now there are 3 modes: - 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols. - 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols. - 3) -mcl switch: 7-Zip uses local code page. -- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on - - -4.58 alpha 7 2008-04-08 -------------------------- -- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without - creating, when BZip2 code was called with one thread (with -mmt1 switch or with - default switches on single thread CPU). -- .lzma support. -- RPM and NSIS support was improved. -- LZMA now stores only (2 << n) or (3 << n) dictionary size value to LZMA properties. - - -4.58 alpha 6 2008-03-27 -------------------------- -- NTFS time extra in ZIP. -- New item property - kpidTimeType - VT_UI4 (0 - NTFS, 1 - Unix, 2 - DOS). -- Static CRC table is not required now for Lzma Encoder (in Lz MatchFinder). - - -4.58 alpha 5 2008-03-19 -------------------------- -- Creation time (-mtc switch) for .7z archives -- LZMA encoder was converted to ANSI-C - - -4.58 alpha 3 2008-02-25 -------------------------- -- Speed optimizations for LZMA decoding. Now it uses C code instead of C++. -- 7-Zip now has 128 MB dictionary limit for 32-bit version: - It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2; -- TAR: 'D' link flag support. -- 7-Zip now can unpack multivolume RAR archives created with - "old style volume names" scheme (-vn switch) and names *.001, *.002, ... -- Fixed bugs: - - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\ - In case of move it removed original files. - - SFX-WIN: if there are errors, it still could return 0. - - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF. - - ZIP name updating: - If zip file contains extra field and you try to change properties of files, - 7-zip tries to delete all extra fileds (except for WzAES). - And that code could hang. - - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run. - - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp - as modification time stamp. - -4.58 alpha 2 2007-12-31 -------------------------- -- Small changes in Deflate and LZMA compression. -- Some speed optimizations. - - -4.57 ----- -- Bug was fixed: - Anti item is created for wrong file: - http://sourceforge.net/forum/forum.php?thread_id=1880366&forum_id=45798 - - -4.52 beta 2007-07-32 -------------------------- -- 7-Zip could not decompress some cab files -- "." dir creating at FAT was fixed / long names - - -4.50 beta 2007-07-24 -------------------------- -- 7-Zip now replaces unsupported filenames (like "nul", "com1") during extracting. -- New switch for command line version: - -ssc[-] enables/disables case-sensitive mode. -- 7z.exe l shows archive comment for zip archives -- Some bugs were fixed: long paths names shorter than 4. -- Speed optimizations for AES encryption. - - - -4.56 beta 2007-09-13 -------------------------- -- some fixes in LZ encoder (LZMA and Deflate) code. - size_t was replaces to ptrdiff_t. - size_t version worked incorrectly with some compilers. - - -4.46 beta 2007-05-25 -------------------------- -- CPP Synchronization objects now return HRes (error code) instead of bool. - - -4.45 beta 2007-04-16 -------------------------- -- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at - stratup code, or you must add CPP/Common/CRC.cpp to your project. -- Method ID in .7z now is 63-bit integer (UInt64). -- Open error messages -- unRar 1.5 fixed -- unShrink fixed -- BUG of 4.43 beta and 4.44 beta was fixed. - 7-Zip compressing to .zip in multi-threading mode didn't work in some cases. - - -4.44 beta 2007-01-20 -------------------------- - -- Bug was fixed: LZMAEncoder.cpp::CEncoder::GetOptimumFast - it was: - data++ - fixed version: - data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1; - It could lead to very small cpmpression ratio decreasing when block needs move. - - -4.30 beta 2005-11-18 -------------------------- -- Security.h::AddLockMemoryPrivilege - installs "Large pages" feature -- MemoryLock.h::EnableLockMemoryPrivilege - enables "Large pages" feature -- Alloc.h::SetLargePageSize - sets optimal LargePageSize size - - -4.27 2005-09-21 -------------------------- -- Some GUIDs/interfaces were changed. - IStream.h: - ISequentialInStream::Read now works as old ReadPart - ISequentialOutStream::Write now works as old WritePart - - -4.26 beta 2005-08-05 -------------------------- -- MyAlloc(0)/BigAlloc(0) now return 0 - - -4.25 beta 2005-07-31 -------------------------- -- More 64-bit compatibilty - - -4.24 beta 2005-07-06 -------------------------- -- Common\NewHandler.h: using throw() for code size optimization. - - -4.23 2005-06-29 -------------------------- -- Bug was fixed: memory leak in Cab decoder. - - -4.19 beta 2005-05-21 -------------------------- -- BZip2 code was rewritten. Now 7-Zip doesn't use original BZip2 code. - Old (original) version was moved to folder 7zip/Compress/BZip2Original/ - - -4.14 beta 2005-01-11 -------------------------- -- STL using was reduced -- 7za now supports Split(001) archves - - -4.10 beta 2004-10-21 -------------------------- -- Codecs now use new interface: ICompressSetDecoderProperties2 - - -4.07 beta 2004-10-03 -------------------------- -- some interfaces were changed slightly to support - -stdin -stdout mode. -- FilterCoder for simple filters -- Wildcard censor class was changed. -- Bug was fixed: when encrypted stream was multiple 16, - it used additional 16 empty bytes. - - -3.11 2003-10-06 -------------------------- - File functions support unicode strings even - on Windows 95/98/ME. - - -3.08.02 2003-09-20 -------------------------- - More compatible with GCC. - - -3.08.02 beta 2003-08-20 -------------------------- - Extracting bug in 7zExtract.cpp was fixed. - - -3.08 beta 2003-08-19 -------------------------- - Big source code reconstruction. - - -2.30 Beta 32 2003-05-15 -------------------------- - Small changes in Deflate decoder. - - -2.30 Beta 31 2003-04-29 -------------------------- - Common/NewHandler.cpp - HeapAlloc in (included to beta 30) was changed to malloc. - HeapAlloc worked slower in Win95/98/Me. - - -2.30 Beta 30 2003-04-21 -------------------------- - new file: Common/String.cpp - Common/NewHandler.* were changed - - -2.30 Beta 29 2003-04-07 -------------------------- - Small changes in LZMA code. - - -2.30 Beta 28 2003-02-16 -------------------------- - Processing anti-files was corrected. - - -2.30 Beta 27 2003-01-24 -------------------------- - Project/Archiver/Format/Common/ArchiveInterface.h: - new IArchiveOpenVolumeCallback interface. - - -2.30 Beta 26 2003-01-12 -------------------------- - SDK/Interface/PropID.h: - kpidComment now is kpidCommented - - -2.30 Beta 25 2003-01-02 -------------------------- - Main archive interfaces were changed. - - -2.30 Beta 24 2002-11-01 -------------------------- - SDK/Windows/Synchronization.h - SDK/Windows/Synchronization.cpp - - some changes. - - -2.30 Beta 23 2002-09-07 -------------------------- - Project/FileManager folder was added. - Notation of some source files was changed. - - -2.30 Beta 22 2002-08-28 -------------------------- - Project/FileManager folder was added. - Notation of some source files was changed. - - - -2.30 Beta 21 2002-07-08 -------------------------- - Project/Compress/LZ/MatchFinder/BinTree/BinTree.h - Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h - Project/Compress/LZ/MatchFinder/BinTree/HC.h - Project/Compress/LZ/MatchFinder/BinTree/HCMain.h - - RAM requirements for LZMA (7z) compression were reduced. - - -2.30 Beta 20 2002-07-01 -------------------------- -- SDK/Stream/WindowOut.h - now it uses only required memory (dictionary size). -- Project/Archiver/Resource - contains common resurces - - -2.30 Beta 19 2002-04-11 -------------------------- -- SDK/Archive/Rar/Handler.cpp - supporting RAR29 - -2.30 Beta 18 2002-03-25 -------------------------- -- SDK/Archive/Cab/MSZipDecoder.cpp - SDK/Archive/Cab/LZXDecoder.cpp: - bug with corrupted archives was fixed -- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h -- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h - some speed optimization (using prefetching) - - -2.30 Beta 17 2002-03-03 -------------------------- -- ARJ suppport. - - -2.30 Beta 16 2002-02-24 -------------------------- -- Project/Compress/LZ/LZMA/Decoder.cpp: - Bug was fixed: LZMA could not extract more than 4 GB. -- RPM and CPIO formats. -- Project/Compress/LZ/LZMA/Encoder.* - Project/Archiver/Format/7z/OutHandler.cpp - New fast compression mode for LZMA: -m0a=0. -- New match finders for LZMA: bt4b, hc3, hc4. - - -2.30 Beta 15 2002-02-17 -------------------------- -- Compression ratio in LZMA was slightly improved: - Project/Compress/LZ/LZMA/Encoder.* - Project/Archiver/Format/7z/OutHandler.cpp - - -2.30 Beta 14 2002-02-10 -------------------------- -- Supporting multithreading for LZMA: - Project/Compress/LZ/MatchFinder/MT -- Common/String.h: - CStringBase::Replace function was fixed. - - -2.30 Beta 13 2002-01-27 -------------------------- -- Compress/LZ/MatchFinder/BinTree3.h: - method -- Compress/LZ/MatchFinder/BinTreemain.h: - - one VirtualAlloc array was splitted to - the for 3 arrays. - - Hash-functions were changed. - - - -2.30 Beta 12 2002-01-16 -------------------------- -- Compress/LZ/MatchFinder/BinTreemain.h: - Compress/LZ/MatchFinder/Patricia.h: - Compress/PPM/PPMd/SubAlloc.h: - Beta 11 bugs were fixed: - - VirtualFree was used incorrectly - - checking WIN32 instead _WINDOWS. - Compress/LZ/MatchFinder/Patricia.h: - Beta 11 bug with deleting m_Hash2Descendants was fixed. - - -2.30 Beta 11 2002-01-15 -------------------------- -- Compress/LZ/MatchFinder/BinTreemain.h: - Compress/LZ/MatchFinder/Patricia.h: - Compress/PPM/PPMd/SubAlloc.h: - using VirtualAlloc for memory allocating -- Exlorer/ContextMenu.cpp: - Testing supporting. - CreateProcess instead WinExec -- Format/Common/IArchiveHandler.h: - Exlorer/ProxyHandler.cpp: - FAR/Plugin.cpp: - New properties names: Method, HostOS. -- Exlorer/OverwriteDialog.cpp: - FAR/OverwriteDialog.cpp: - Windows/PropVariantConversions.h - Using National time format was eliminated. - - - -2.30 Beta 10 2002-01-11 -------------------------- -- Exlorer/ContextMenu.cpp: bug with context menu on - Windows NT4 in Unicode version was fixed. -- Format/7z/UpdateArchiveEngine.cpp: bug was fixed - - Updating in Beta 8 and 9 didn't work. -- Exlorer/CCompressDialog.cpp: history growing bug was fixed. - - -2.30 Beta 9 2002-01-08 -------------------------- -- SDK/Common/Vector.h: sopporting sorted object vectors . -- Lang features. -- Two new match finders: pat3h and pat4h. -- SDK/Archive/Zip/InEngine.cpp: bug was fixed. -- SDK/Windows/FileDir.cpp: function CreateComplexDirectory - was changed. - +HISTORY of the 7-Zip source code +-------------------------------- + +24.09 2024-11-29 +------------------------- +- The default dictionary size values for LZMA/LZMA2 compression methods were increased: + dictionary size compression level + v24.08 v24.09 v24.09 + 32-bit 64-bit + 8 MB 16 MB 16 MB -mx4 + 16 MB 32 MB 32 MB -mx5 : Normal + 32 MB 64 MB 64 MB -mx6 + 32 MB 64 MB 128 MB -mx7 : Maximum + 64 MB 64 MB 256 MB -mx8 + 64 MB 64 MB 256 MB -mx9 : Ultra + The default dictionary size values for 32-bit versions of LZMA/LZMA2 don't exceed 64 MB. +- 7-Zip now can calculate the following hash checksums: SHA-512, SHA-384, SHA3-256 and MD5. +- APM and HFS support was improved. +- If an archive update operation uses a temporary archive folder and + the archive is moved to the destination folder, 7-Zip shows the progress of moving + the archive file, as this operation can take a long time if the archive is large. +- The bug was fixed: 7-Zip File Manager didn't propagate Zone.Identifier stream + for extacted files from nested archives (if there is open archive inside another open archive). +- Some bugs were fixed. + + +24.08 2024-08-11 +------------------------- +- The bug in 7-Zip 24.00-24.07 was fixed: + For creating a zip archive: 7-Zip could write extra zero bytes after the end of the archive, + if a file included to archive cannot be compressed to a size smaller than original. + The created zip archive is correct except for the useless zero bytes after the end of the archive. + When unpacking such a zip archive, 7-Zip displays a warning: + "WARNING: There are data after the end of archive". +- Some bugs were fixed. + + +24.07 2024-06-19 +------------------------- +- Changes in files: + Asm/x86/Sha256Opt.asm + Asm/x86/Sha1Opt.asm + Now it uses "READONLY" flag for constant array segment. + It fixes an issue where ".rodata" section in 7-Zip for x86/x64 Linux had a "WRITE" attribute. +- The bug was fixed: 7-Zip could crash for some incorrect ZSTD archives. + + +24.06 2024-05-26 +------------------------- +- The bug was fixed: 7-Zip could not unpack some ZSTD archives. + + +24.05 2024-05-14 +------------------------- +- New switch -myv={MMNN} to set decoder compatibility version for 7z archive creating. + {MMNN} is 4-digit number that represents the version of 7-Zip without a dot. + If -myv={MMNN} switch is specified, 7-Zip will only use compression methods that can + be decoded by the specified version {MMNN} of 7-Zip and newer versions. + If -myv={MMNN} switch is not specified, -myv=2300 is used, and 7-Zip will only + use compression methods that can be decoded by 7-Zip 23.00 and newer versions. +- New switch -myfa={FilterID} to allow 7-Zip to use the specified filter method for 7z archive creating. +- New switch -myfd={FilterID} to disallow 7-Zip to use the specified filter method for 7z archive creating. + + +24.03 2024-03-23 +------------------------- +- 7-Zip now can use new RISCV filter for compression to 7z and xz archives. + RISCV filter can increase compression ratio for data containing executable + files compiled for RISC-V architecture. +- The speed for LZMA and LZMA2 decompression in ARM64 version for Windows + was increased by 20%-60%. + It uses arm64 assembler code, and clang-cl is required for arm64 assembler code compiling. +- Some bugs were fixed. + + +24.01 2024-01-31 +------------------------- +- 7-Zip uses file C/Precomp.h that is included to all c and c++ files. + CPP/Common/Common.h also includes C/Precomp.h. + C/Precomp.h defines the following macros (if _WIN32 is defined): + Z7_LARGE_PAGES 1 + Z7_LONG_PATH 1 + Z7_WIN32_WINNT_MIN 0x0500 (or higher) + _WIN32_WINNT 0x0500 (or higher) + WINVER _WIN32_WINNT + UNICODE 1 + _UNICODE 1 + if _WIN32_WINNT is defined already, C/Precomp.h doesn't redefine it. + +- 7-Zip now can unpack ZSTD archives (.zst extension). +- 7-Zip now can unpack ZIP and SquashFS archives that use ZSTD compression method. +- 7-Zip now supports fast hash algorithm XXH64 that is used in ZSTD. +- Speed optimizations for archive unpacking: rar, zip, gz, wim, cab. +- Speed optimizations for hash caclulation: CRC-32, CRC-64, Blake2sp. +- The bug was fixed: 7-Zip for Linux could fail for multivolume creation in some cases. +- Some bugs were fixed. + + +23.01 2023-06-20 +------------------------- +- All external macros for compiling C/C++ code of 7-Zip now have Z7_ prefix. +- 7-Zip COM interfaces now use new macros that allow to declare and implement COM interface. +- The code has been modified to compile with the maximum diagnostic warning level: + -Wall in MSVC and -Weverything in CLANG. + And some warning types are disabled in 2 files: + - C/Compiler.h for C/C++ code warnings. + - CPP/Common/Common.h for C++ code warnings. +- Linux/macOS versions of 7-Zip: IUnknown interface in new code doesn't use + virtual destructor that was used in previous 7-Zip and p7zip: + // virtual ~IUnknown() {} + So 7-Zip's dynamically linked shared libraries (codecs) are not compatible + between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip). +- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers. +- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp + files in system's TEMP folder. 7-Zip uses temp file for additional compressed + data stream, if size of such compressed stream is larger than predefined limit: + 16 MiB in 32-bit version, 4 GiB in 64-bit version. +- Some bugs were fixed. + + +22.00 2022-06-16 +------------------------- +- 7-Zip interfaces now support high precision (1 ns) timestamps with reserved + fields of tagPROPVARIANT (VT_FILETIME). + + +21.07 2021-12-26 +------------------------- +- The sorting order of files in archives was slightly changed to be more consistent + for cases where the name of some directory is the same as the prefix part of the name + of another directory or file. +- TAR archives created by 7-Zip now are more consistent with archives created by GNU TAR program. + + +21.06 2021-11-24 +------------------------- +- Bug in LZMA encoder in file LzmaEnc.c was fixed: + LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly, + if size value for output buffer is smaller than size required for all compressed data. + LzmaEnc_Encode() could work incorrectly, + if callback ISeqOutStream::Write() doesn't write all compressed data. + NCompress::NLzma::CEncoder::Code() could work incorrectly, + if callback ISequentialOutStream::Write() returns error code. +- Bug in versions 21.00-21.05 was fixed: + 7-Zip didn't set attributes of directories during archive extracting. + + +21.04 beta 2021-11-02 +------------------------- +- 7-Zip now reduces the number of working CPU threads for compression, + if RAM size is not enough for compression with big LZMA2 dictionary. +- 7-Zip now can create and check "file.sha256" and "file.sha1" text files + that contain the list of file names and SHA-1 / SHA-256 checksums in format + compatible with sha1sum/sha256sum programs. + + +21.03 beta 2021-07-20 +------------------------- +- The maximum dictionary size for LZMA/LZMA2 compressing was increased to 4 GB (3840 MiB). +- Minor speed optimizations in LZMA/LZMA2 compressing. + + +21.02 alpha 2021-05-06 +------------------------- +- 7-Zip now writes additional field for filename in UTF-8 encoding to zip archives. + It allows to extract correct file name from zip archives on different systems. +- The command line version of 7-Zip for macOS was released. +- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux + was increased by 20%-60%. +- Some changes and improvements in ZIP, TAR and NSIS code. + + +21.01 alpha 2021-03-09 +------------------------- +- The command line version of 7-Zip for Linux was released. +- The improvements for speed of ARM64 version using hardware CPU instructions + for AES, CRC-32, SHA-1 and SHA-256. +- The bug in versions 18.02 - 21.00 was fixed: + 7-Zip could not correctly extract some ZIP archives created with xz compression method. +- Some bugs were fixed. + + +20.02 alpha 2020-08-08 +------------------------- +- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64. + It allows to increase the compression speed for big 7z archives, if there is a big number + of CPU cores and threads. +- The speed of PPMd compressing/decompressing was increased for 7z/ZIP/RAR archives. +- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system + to modify "Last Access Time" property of source files for archiving and hashing operations. +- Some bugs were fixed. + + +20.00 alpha 2020-02-06 +------------------------- +- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5, + that can work faster than bt4 and hc4 match finders for the data with big redundancy. +- The compression ratio was improved for Fast and Fastest compression levels with the + following default settings: + - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary. + - Fast level (-mx3) : hc5 match finder with 4 MB dictionary. +- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra + compression levels. +- bzip2 decoding code was updated to support bzip2 archives, created by lbzip2 program. + + +19.02 2019-09-05 +------------------------- +- Support for SHA-1/SHA-256 optimized code in + Sha1Opt.c, Sha256Opt.c, Sha256Opt.asm, Sha1Opt.asm. + + +19.00 2019-02-21 +------------------------- +- Encryption strength for 7z archives was increased: + the size of random initialization vector was increased from 64-bit to 128-bit, + and the pseudo-random number generator was improved. +- Some bugs were fixed. + + +18.06 2018-12-30 +------------------------- +- The speed for LZMA/LZMA2 compressing was increased by 3-10%, + and there are minor changes in compression ratio. +- Some bugs were fixed. +- The bug in 7-Zip 18.02-18.05 was fixed: + There was memory leak in multithreading xz decoder - XzDecMt_Decode(), + if xz stream contains only one block. +- 7-Zip 18.02-18.05 used only one CPU thread for bz2 archive creation. +- The changes for MSVS compiler makefiles: + - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64) + instead of "CPU" macroname with values (AMD64, ARM64). + - the makefiles by default now use static version of the run-time library. + + +18.05 2018-04-30 +------------------------- +- The speed for LZMA/LZMA2 compressing was increased + by 8% for fastest/fast compression levels and + by 3% for normal/maximum compression levels. +- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in + Windows 10 because of some BUG with "Large Pages" in Windows 10. + Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299). + + +18.03 beta 2018-03-04 +------------------------- +- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm + for x64 with about 30% higher speed than main version of LZMA decoder written in C. +- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%. +- 7-Zip now can use multi-threading for 7z/LZMA2 decoding, + if there are multiple independent data chunks in LZMA2 stream. +- 7-Zip now can use multi-threading for xz decoding, + if there are multiple blocks in xz stream. + + +17.00 beta 2017-04-29 +------------------------- +- NewHandler.h / NewHandler.cpp: + now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900). +- C/7zTypes.h : the names of variables in interface structures were changed (vt). +- Some bugs were fixed. 7-Zip could crash in some cases. +- Some internal changes in code. + + +16.02 2016-05-21 +------------------------- +- The BUG in 16.00 - 16.01 was fixed: + Split Handler (SplitHandler.cpp) returned incorrect + total size value (kpidSize) for split archives. + + +16.01 2016-05-19 +------------------------- +- Some bugs were fixed, +- Some internal changes to reduce the number of compiler warnings. + + +16.00 2016-05-10 +------------------------- +- 7-Zip now can extract multivolume ZIP archives (z01, z02, ... , zip). +- Some bugs were fixed, + + +15.12 2015-11-19 +------------------------- +- The BUG in C version of 7z decoder was fixed: + 7zDec.c : SzDecodeLzma2() + 7z decoder could mistakenly report about decoding error for some 7z archives + that use LZMA2 compression method. + The probability to get that mistaken decoding error report was about + one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size). +- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed: + 7zArcIn.c : SzReadHeader2() + 7z decoder worked incorrectly for 7z archives that contain + empty solid blocks, that can be placed to 7z archive, if some file is + unavailable for reading during archive creation. + + +15.09 beta 2015-10-16 +------------------------- +- The BUG in LZMA / LZMA2 encoding code was fixed. + The BUG in LzFind.c::MatchFinder_ReadBlock() function. + If input data size is larger than (4 GiB - dictionary_size), + the following code worked incorrectly: + - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions + for compressing from memory to memory. + That BUG is not related to LZMA encoder version that works via streams. + - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if + default value of chunk size (CLzma2EncProps::blockSize) is changed + to value larger than (4 GiB - dictionary_size). + + +9.38 beta 2015-01-03 +------------------------- +- The BUG in 9.31-9.37 was fixed: + IArchiveGetRawProps interface was disabled for 7z archives. +- The BUG in 9.26-9.36 was fixed: + Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows. + + +9.36 beta 2014-12-26 +------------------------- +- The BUG in command line version was fixed: + 7-Zip created temporary archive in current folder during update archive + operation, if -w{Path} switch was not specified. + The fixed 7-Zip creates temporary archive in folder that contains updated archive. +- The BUG in 9.33-9.35 was fixed: + 7-Zip silently ignored file reading errors during 7z or gz archive creation, + and the created archive contained only part of file that was read before error. + The fixed 7-Zip stops archive creation and it reports about error. + + +9.31 2012-10-31 +------------------------- +- InBuffer.h : CInBuffer uses ISequentialInStream *_stream; instead of CMyComPtr + OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr + + +9.26 2011-04-11 +------------------------- +- The BUG was fixed: multi-threaded ZIP stored file size that was at scan stage, + So if the file was changed after scan, the Unpack Size field was incorrect + + +9.21 2011-04-11 +------------------------- +- New class FString for file names at file systems. +- Speed optimization in CRC code for big-endian CPUs. + + +9.18 2010-11-02 +------------------------- +- New small SFX module for installers (C/Util/SfxSetup). + + +9.17 2010-10-04 +------------------------- +- IStream.h::IOutStream:: + STDMETHOD(SetSize)(Int64 newSize) PURE; + was changed to + STDMETHOD(SetSize)(UInt64 newSize) PURE; + + +9.09 2009-12-12 +------------------------- +- The bug was fixed: + Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c + incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8. + + +9.05 2009-07-05 +------------------------- +- FileMapping.h::CFileMapping now returns WRes + + +9.04 2009-05-30 +------------------------- +- ICoder.h: NCoderPropID::EEnum values were changed + + +9.02 2009-04-23 +------------------------- +- Bug was fixed: if swap2 filter was requests at compression, + 7-zip used swap4 filter instead (but id was swap2), so archives were incorrect. + +4.61 2008-11-23 +------------------------- +- Bug in ver. 4.58+ was fixed: + 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives. +- Bug in .CAB code was fixed. 7-Zip didn't show some empty files, + if .CAB archive contains more than one empty file. + + +4.59 2008-07-27 +------------------------- +- Bug was fixed: + LZMA Encoder in fast compression mode could access memory outside of + allocated range in some rare cases. + + +4.59 alpha 2008-05-30 +------------------------- +- BUGS was fixed: + 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases. + 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties. + +4.58 alpha 9 2008-04-29 +------------------------- +- BUG was fixed: 7-Zip showed incorrect timestamps in ISO files. + + +4.58 alpha 8 2008-04-15 +------------------------- +- BUG in 4.58 alpha 5/6/7 was fixed: + LZMA encoder worked incorrectly, if lp != 0. +- Unicode (UTF-8) support for filenames in .ZIP archives. Now there are 3 modes: + 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols. + 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols. + 3) -mcl switch: 7-Zip uses local code page. +- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on + + +4.58 alpha 7 2008-04-08 +------------------------- +- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without + creating, when BZip2 code was called with one thread (with -mmt1 switch or with + default switches on single thread CPU). +- .lzma support. +- RPM and NSIS support was improved. +- LZMA now stores only (2 << n) or (3 << n) dictionary size value to LZMA properties. + + +4.58 alpha 6 2008-03-27 +------------------------- +- NTFS time extra in ZIP. +- New item property - kpidTimeType - VT_UI4 (0 - NTFS, 1 - Unix, 2 - DOS). +- Static CRC table is not required now for Lzma Encoder (in Lz MatchFinder). + + +4.58 alpha 5 2008-03-19 +------------------------- +- Creation time (-mtc switch) for .7z archives +- LZMA encoder was converted to ANSI-C + + +4.58 alpha 3 2008-02-25 +------------------------- +- Speed optimizations for LZMA decoding. Now it uses C code instead of C++. +- 7-Zip now has 128 MB dictionary limit for 32-bit version: + It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2; +- TAR: 'D' link flag support. +- 7-Zip now can unpack multivolume RAR archives created with + "old style volume names" scheme (-vn switch) and names *.001, *.002, ... +- Fixed bugs: + - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\ + In case of move it removed original files. + - SFX-WIN: if there are errors, it still could return 0. + - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF. + - ZIP name updating: + If zip file contains extra field and you try to change properties of files, + 7-zip tries to delete all extra fileds (except for WzAES). + And that code could hang. + - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run. + - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp + as modification time stamp. + +4.58 alpha 2 2007-12-31 +------------------------- +- Small changes in Deflate and LZMA compression. +- Some speed optimizations. + + +4.57 +---- +- Bug was fixed: + Anti item is created for wrong file: + http://sourceforge.net/forum/forum.php?thread_id=1880366&forum_id=45798 + + +4.52 beta 2007-07-32 +------------------------- +- 7-Zip could not decompress some cab files +- "." dir creating at FAT was fixed / long names + + +4.50 beta 2007-07-24 +------------------------- +- 7-Zip now replaces unsupported filenames (like "nul", "com1") during extracting. +- New switch for command line version: + -ssc[-] enables/disables case-sensitive mode. +- 7z.exe l shows archive comment for zip archives +- Some bugs were fixed: long paths names shorter than 4. +- Speed optimizations for AES encryption. + + + +4.56 beta 2007-09-13 +------------------------- +- some fixes in LZ encoder (LZMA and Deflate) code. + size_t was replaces to ptrdiff_t. + size_t version worked incorrectly with some compilers. + + +4.46 beta 2007-05-25 +------------------------- +- CPP Synchronization objects now return HRes (error code) instead of bool. + + +4.45 beta 2007-04-16 +------------------------- +- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at + stratup code, or you must add CPP/Common/CRC.cpp to your project. +- Method ID in .7z now is 63-bit integer (UInt64). +- Open error messages +- unRar 1.5 fixed +- unShrink fixed +- BUG of 4.43 beta and 4.44 beta was fixed. + 7-Zip compressing to .zip in multi-threading mode didn't work in some cases. + + +4.44 beta 2007-01-20 +------------------------- + +- Bug was fixed: LZMAEncoder.cpp::CEncoder::GetOptimumFast + it was: + data++ + fixed version: + data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1; + It could lead to very small cpmpression ratio decreasing when block needs move. + + +4.30 beta 2005-11-18 +------------------------- +- Security.h::AddLockMemoryPrivilege - installs "Large pages" feature +- MemoryLock.h::EnableLockMemoryPrivilege - enables "Large pages" feature +- Alloc.h::SetLargePageSize - sets optimal LargePageSize size + + +4.27 2005-09-21 +------------------------- +- Some GUIDs/interfaces were changed. + IStream.h: + ISequentialInStream::Read now works as old ReadPart + ISequentialOutStream::Write now works as old WritePart + + +4.26 beta 2005-08-05 +------------------------- +- MyAlloc(0)/BigAlloc(0) now return 0 + + +4.25 beta 2005-07-31 +------------------------- +- More 64-bit compatibilty + + +4.24 beta 2005-07-06 +------------------------- +- Common\NewHandler.h: using throw() for code size optimization. + + +4.23 2005-06-29 +------------------------- +- Bug was fixed: memory leak in Cab decoder. + + +4.19 beta 2005-05-21 +------------------------- +- BZip2 code was rewritten. Now 7-Zip doesn't use original BZip2 code. + Old (original) version was moved to folder 7zip/Compress/BZip2Original/ + + +4.14 beta 2005-01-11 +------------------------- +- STL using was reduced +- 7za now supports Split(001) archves + + +4.10 beta 2004-10-21 +------------------------- +- Codecs now use new interface: ICompressSetDecoderProperties2 + + +4.07 beta 2004-10-03 +------------------------- +- some interfaces were changed slightly to support + -stdin -stdout mode. +- FilterCoder for simple filters +- Wildcard censor class was changed. +- Bug was fixed: when encrypted stream was multiple 16, + it used additional 16 empty bytes. + + +3.11 2003-10-06 +------------------------- + File functions support unicode strings even + on Windows 95/98/ME. + + +3.08.02 2003-09-20 +------------------------- + More compatible with GCC. + + +3.08.02 beta 2003-08-20 +------------------------- + Extracting bug in 7zExtract.cpp was fixed. + + +3.08 beta 2003-08-19 +------------------------- + Big source code reconstruction. + + +2.30 Beta 32 2003-05-15 +------------------------- + Small changes in Deflate decoder. + + +2.30 Beta 31 2003-04-29 +------------------------- + Common/NewHandler.cpp + HeapAlloc in (included to beta 30) was changed to malloc. + HeapAlloc worked slower in Win95/98/Me. + + +2.30 Beta 30 2003-04-21 +------------------------- + new file: Common/String.cpp + Common/NewHandler.* were changed + + +2.30 Beta 29 2003-04-07 +------------------------- + Small changes in LZMA code. + + +2.30 Beta 28 2003-02-16 +------------------------- + Processing anti-files was corrected. + + +2.30 Beta 27 2003-01-24 +------------------------- + Project/Archiver/Format/Common/ArchiveInterface.h: + new IArchiveOpenVolumeCallback interface. + + +2.30 Beta 26 2003-01-12 +------------------------- + SDK/Interface/PropID.h: + kpidComment now is kpidCommented + + +2.30 Beta 25 2003-01-02 +------------------------- + Main archive interfaces were changed. + + +2.30 Beta 24 2002-11-01 +------------------------- + SDK/Windows/Synchronization.h + SDK/Windows/Synchronization.cpp + - some changes. + + +2.30 Beta 23 2002-09-07 +------------------------- + Project/FileManager folder was added. + Notation of some source files was changed. + + +2.30 Beta 22 2002-08-28 +------------------------- + Project/FileManager folder was added. + Notation of some source files was changed. + + + +2.30 Beta 21 2002-07-08 +------------------------- + Project/Compress/LZ/MatchFinder/BinTree/BinTree.h + Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h + Project/Compress/LZ/MatchFinder/BinTree/HC.h + Project/Compress/LZ/MatchFinder/BinTree/HCMain.h + - RAM requirements for LZMA (7z) compression were reduced. + + +2.30 Beta 20 2002-07-01 +------------------------- +- SDK/Stream/WindowOut.h + now it uses only required memory (dictionary size). +- Project/Archiver/Resource + contains common resurces + + +2.30 Beta 19 2002-04-11 +------------------------- +- SDK/Archive/Rar/Handler.cpp + supporting RAR29 + +2.30 Beta 18 2002-03-25 +------------------------- +- SDK/Archive/Cab/MSZipDecoder.cpp + SDK/Archive/Cab/LZXDecoder.cpp: + bug with corrupted archives was fixed +- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h +- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h + some speed optimization (using prefetching) + + +2.30 Beta 17 2002-03-03 +------------------------- +- ARJ suppport. + + +2.30 Beta 16 2002-02-24 +------------------------- +- Project/Compress/LZ/LZMA/Decoder.cpp: + Bug was fixed: LZMA could not extract more than 4 GB. +- RPM and CPIO formats. +- Project/Compress/LZ/LZMA/Encoder.* + Project/Archiver/Format/7z/OutHandler.cpp + New fast compression mode for LZMA: -m0a=0. +- New match finders for LZMA: bt4b, hc3, hc4. + + +2.30 Beta 15 2002-02-17 +------------------------- +- Compression ratio in LZMA was slightly improved: + Project/Compress/LZ/LZMA/Encoder.* + Project/Archiver/Format/7z/OutHandler.cpp + + +2.30 Beta 14 2002-02-10 +------------------------- +- Supporting multithreading for LZMA: + Project/Compress/LZ/MatchFinder/MT +- Common/String.h: + CStringBase::Replace function was fixed. + + +2.30 Beta 13 2002-01-27 +------------------------- +- Compress/LZ/MatchFinder/BinTree3.h: + method +- Compress/LZ/MatchFinder/BinTreemain.h: + - one VirtualAlloc array was splitted to + the for 3 arrays. + - Hash-functions were changed. + + + +2.30 Beta 12 2002-01-16 +------------------------- +- Compress/LZ/MatchFinder/BinTreemain.h: + Compress/LZ/MatchFinder/Patricia.h: + Compress/PPM/PPMd/SubAlloc.h: + Beta 11 bugs were fixed: + - VirtualFree was used incorrectly + - checking WIN32 instead _WINDOWS. + Compress/LZ/MatchFinder/Patricia.h: + Beta 11 bug with deleting m_Hash2Descendants was fixed. + + +2.30 Beta 11 2002-01-15 +------------------------- +- Compress/LZ/MatchFinder/BinTreemain.h: + Compress/LZ/MatchFinder/Patricia.h: + Compress/PPM/PPMd/SubAlloc.h: + using VirtualAlloc for memory allocating +- Exlorer/ContextMenu.cpp: + Testing supporting. + CreateProcess instead WinExec +- Format/Common/IArchiveHandler.h: + Exlorer/ProxyHandler.cpp: + FAR/Plugin.cpp: + New properties names: Method, HostOS. +- Exlorer/OverwriteDialog.cpp: + FAR/OverwriteDialog.cpp: + Windows/PropVariantConversions.h + Using National time format was eliminated. + + + +2.30 Beta 10 2002-01-11 +------------------------- +- Exlorer/ContextMenu.cpp: bug with context menu on + Windows NT4 in Unicode version was fixed. +- Format/7z/UpdateArchiveEngine.cpp: bug was fixed - + Updating in Beta 8 and 9 didn't work. +- Exlorer/CCompressDialog.cpp: history growing bug was fixed. + + +2.30 Beta 9 2002-01-08 +------------------------- +- SDK/Common/Vector.h: sopporting sorted object vectors . +- Lang features. +- Two new match finders: pat3h and pat4h. +- SDK/Archive/Zip/InEngine.cpp: bug was fixed. +- SDK/Windows/FileDir.cpp: function CreateComplexDirectory + was changed. +